diff --git a/ALGORITHM_API_IMPLEMENTATION_V2.md b/ALGORITHM_API_IMPLEMENTATION_V2.md deleted file mode 100644 index 5d0155f..0000000 --- a/ALGORITHM_API_IMPLEMENTATION_V2.md +++ /dev/null @@ -1,2415 +0,0 @@ -# 算法封装成API完整实现方案 - -## 一、系统架构分析 - -### 1. 现有系统架构 - -**前端技术栈**: -- Vue 3 + TypeScript -- Vite 构建工具 -- Pinia 状态管理 -- Element Plus UI组件库 - -**后端技术栈**: -- FastAPI Web框架 -- PostgreSQL 数据库 -- SQLAlchemy ORM -- JWT 认证 - -**核心模块**: -- 算法管理:创建、更新、删除算法 -- 版本管理:算法多版本支持 -- 算法调用:执行算法并返回结果 -- 模型管理:上传和管理模型文件 -- 代码执行:执行Python代码 - -### 2. 现有数据库模型 - -**Algorithm**:算法基本信息 -- id, name, description, type, status - -**AlgorithmVersion**:算法版本信息 -- id, algorithm_id, version, url, params, input_schema, output_schema, code, model_name, model_file, api_doc, is_default - -**AlgorithmCall**:算法调用记录 -- id, user_id, algorithm_id, version_id, input_data, params, output_data, status, response_time, error_message - -### 3. 现有API接口 - -**算法管理**: -- POST /api/v1/algorithms - 创建算法 -- GET /api/v1/algorithms - 获取算法列表 -- GET /api/v1/algorithms/{id} - 获取算法详情 -- PUT /api/v1/algorithms/{id} - 更新算法 -- DELETE /api/v1/algorithms/{id} - 删除算法 - -**版本管理**: -- POST /api/v1/algorithms/{id}/versions - 创建版本 -- GET /api/v1/algorithms/{id}/versions - 获取版本列表 -- GET /api/v1/algorithms/{id}/versions/{version_id} - 获取版本详情 -- PUT /api/v1/algorithms/{id}/versions/{version_id} - 更新版本 -- DELETE /api/v1/algorithms/{id}/versions/{version_id} - 删除版本 - -**算法调用**: -- POST /api/v1/algorithms/call - 调用算法 -- GET /api/v1/algorithms/calls/{call_id} - 获取调用结果 -- GET /api/v1/algorithms/calls - 获取调用历史 - -**代码执行**: -- POST /api/v1/algorithms/execute-code - 执行Python代码 - -**模型上传**: -- POST /api/v1/algorithms/upload-model - 上传模型文件 - -## 二、实现方案设计 - -### 1. 核心功能设计 - -**功能模块**: -1. **算法封装模块**: - - **平台部署**:通过平台上传代码/模型并自动部署 - - **外部集成**:集成已部署的外部API服务 - - **混合模式**:支持平台部署与外部API结合 - -2. **部署服务模块**: - - **代码部署**:Python代码自动容器化部署 - - **模型部署**:支持多种模型格式的部署 - - **环境管理**:依赖管理、环境隔离 - - **容器编排**:Docker容器的创建、启动、停止、监控 - -3. **调用执行模块**: - - **统一调用接口**:标准化的API调用方式 - - **负载均衡**:多实例负载分发 - - **容错处理**:失败重试、降级策略 - - **异步执行**:支持长时间运行的任务 - -4. **监控管理模块**: - - **部署状态**:容器运行状态、资源使用 - - **调用性能**:响应时间、QPS、错误率 - - **算法性能**:执行时间、内存使用 - - **告警系统**:异常检测、自动告警 - -### 2. 技术方案选择 - -**部署技术**: -- **Docker容器**:每个算法版本独立部署为Docker容器 -- **FastAPI服务**:为每个算法生成标准化的FastAPI服务 -- **Nginx代理**:统一入口,负载均衡 -- **Kubernetes**(可选):生产环境的容器编排 - -**存储方案**: -- **MinIO**:高性能对象存储,存储模型文件和代码文件 -- **PostgreSQL**:存储算法元数据、调用记录和监控数据 -- **Redis**:缓存热点数据和管理容器状态 - -**通信方案**: -- **HTTP/HTTPS**:同步API调用 -- **WebSocket**:实时执行状态和日志 -- **gRPC**(可选):高性能内部通信 - -### 3. 部署流程设计 - -**标准部署流程**: -1. **代码/模型上传**:用户上传算法代码或模型文件 -2. **环境配置**:自动检测依赖,生成Dockerfile -3. **镜像构建**:构建Docker镜像,包含算法运行环境 -4. **容器部署**:启动Docker容器,分配端口 -5. **服务注册**:将服务地址注册到系统 -6. **健康检查**:验证服务是否正常运行 -7. **版本管理**:创建算法版本记录 - -**支持的算法类型**: -- **机器学习**:Scikit-learn、XGBoost、LightGBM -- **深度学习**:PyTorch、TensorFlow、Keras -- **自然语言处理**:Hugging Face Transformers -- **计算机视觉**:OpenCV、YOLO、ResNet -- **强化学习**:OpenAI Gym、Stable Baselines -- **自定义算法**:任意Python代码 - -**支持的模型格式**: -- **PyTorch**:.pt, .pth -- **TensorFlow**:.h5, .hdf5, .pb -- **ONNX**:.onnx -- **Scikit-learn**:.joblib, .pkl -- **其他**:.txt, .csv, .json, 压缩包 - -## 三、详细实现步骤 - -### 1. 系统准备 - -**安装依赖**: -```bash -# 后端核心依赖 -pip install docker python-multipart minio - -# 算法依赖 -pip install numpy pandas scikit-learn torch tensorflow - -# 前端依赖 -npm install @element-plus/icons-vue monaco-editor -``` - -**配置文件**: -```python -# backend/app/config/settings.py -class Settings(BaseSettings): - # ... 现有配置 ... - - # Docker配置 - DOCKER_ENABLED: bool = True - DOCKER_REGISTRY: str = "localhost:5000" - - # 部署配置 - DEPLOYMENT_BASE_URL: str = "http://localhost:8080" - DEPLOYMENT_NETWORK: str = "algorithm-network" - MAX_CONTAINERS_PER_ALGORITHM: int = 5 - - # 代码执行配置 - CODE_EXECUTION_TIMEOUT: int = 30 - MAX_CODE_SIZE: int = 100000 - - # 模型配置 - MAX_MODEL_SIZE: int = 1024 * 1024 * 1024 # 1GB - MODEL_STORAGE_PATH: str = "/data/models" - - # MinIO配置 - MINIO_ENDPOINT: str = "localhost:9000" - MINIO_ACCESS_KEY: str = "minioadmin" - MINIO_SECRET_KEY: str = "minioadmin" - MINIO_BUCKET_NAME: str = "algorithm-data" - MINIO_SECURE: bool = False -``` - -### 2. 后端实现 - -**新增部署服务模块**: -```python -# backend/app/services/deployment.py -import docker -import os -import uuid -import time -import subprocess -from typing import Dict, Any, Optional -from app.utils.file import file_storage - -class DeploymentService: - """部署服务类""" - - @staticmethod - def get_docker_client(): - """获取Docker客户端""" - return docker.from_env() - - @staticmethod - def detect_dependencies(code: str) -> list: - """检测代码依赖""" - dependencies = ["fastapi", "uvicorn", "python-multipart"] - - # 检测常见库 - if "import numpy" in code or "from numpy" in code: - dependencies.append("numpy") - if "import pandas" in code or "from pandas" in code: - dependencies.append("pandas") - if "import torch" in code or "from torch" in code: - dependencies.append("torch") - if "import tensorflow" in code or "from tensorflow" in code: - dependencies.append("tensorflow") - if "import sklearn" in code or "from sklearn" in code: - dependencies.append("scikit-learn") - if "import cv2" in code or "from cv2" in code: - dependencies.append("opencv-python") - if "import transformers" in code or "from transformers" in code: - dependencies.append("transformers") - - return dependencies - - @staticmethod - def build_algorithm_image(algorithm_id: str, version_id: str, code: str, model_file: str = None) -> str: - """构建算法Docker镜像""" - client = DeploymentService.get_docker_client() - - # 创建临时目录 - temp_dir = f"/tmp/algorithm_{uuid.uuid4().hex[:8]}" - os.makedirs(temp_dir, exist_ok=True) - - try: - # 写入算法代码 - with open(os.path.join(temp_dir, "algorithm.py"), "w") as f: - f.write(code) - - # 复制模型文件 - if model_file: - model_path = os.path.join(temp_dir, "model") - os.makedirs(model_path, exist_ok=True) - # 从MinIO下载模型文件 - file_storage.download_file(model_file, os.path.join(model_path, os.path.basename(model_file))) - - # 检测依赖 - dependencies = DeploymentService.detect_dependencies(code) - - # 创建Dockerfile - dockerfile_content = f""" -FROM python:3.9-slim - -WORKDIR /app - -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -COPY . . - -EXPOSE 8000 - -CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] -""" - - with open(os.path.join(temp_dir, "Dockerfile"), "w") as f: - f.write(dockerfile_content) - - # 创建requirements.txt - requirements_content = "\n".join(dependencies) - with open(os.path.join(temp_dir, "requirements.txt"), "w") as f: - f.write(requirements_content) - - # 创建FastAPI应用 - app_content = """ -from fastapi import FastAPI, HTTPException -import algorithm - -app = FastAPI() - -@app.post("/predict") -async def predict(input_data: dict, params: dict = None): - try: - if params is None: - params = {} - result = algorithm.execute(input_data, params) - return {"success": True, "result": result} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/health") -async def health_check(): - return {"status": "healthy"} -""" - - with open(os.path.join(temp_dir, "app.py"), "w") as f: - f.write(app_content) - - # 构建镜像 - image_name = f"algorithm/{algorithm_id}:{version_id}" - image, _ = client.images.build( - path=temp_dir, - tag=image_name, - rm=True - ) - - return image_name - - finally: - # 清理临时目录 - import shutil - shutil.rmtree(temp_dir, ignore_errors=True) - - @staticmethod - def deploy_algorithm(image_name: str, algorithm_id: str, version_id: str) -> Dict[str, Any]: - """部署算法容器""" - client = DeploymentService.get_docker_client() - - # 生成容器名称 - container_name = f"algorithm_{algorithm_id}_{version_id}_{uuid.uuid4().hex[:4]}" - - # 运行容器 - container = client.containers.run( - image_name, - name=container_name, - ports={"8000/tcp": None}, # 自动分配端口 - detach=True, - network="algorithm-network" if os.environ.get("DEPLOYMENT_NETWORK") else None, - environment={ - "ALGORITHM_ID": algorithm_id, - "VERSION_ID": version_id, - "LOG_LEVEL": "info" - }, - # 资源限制 - mem_limit="1G", - cpus="1.0" - ) - - # 等待容器启动 - time.sleep(5) - - # 获取容器信息 - container.reload() - - # 检查容器状态 - if container.status != "running": - logs = container.logs().decode('utf-8') - container.remove(force=True) - raise Exception(f"容器启动失败: {logs}") - - # 获取端口信息 - ports = container.attrs["NetworkSettings"]["Ports"] - host_port = ports["8000/tcp"][0]["HostPort"] - container_ip = container.attrs["NetworkSettings"]["IPAddress"] - - # 返回部署信息 - return { - "container_name": container_name, - "container_id": container.id, - "url": f"http://localhost:{host_port}", - "container_ip": container_ip, - "port": host_port, - "status": container.status - } - - @staticmethod - def scale_algorithm(image_name: str, algorithm_id: str, version_id: str, replicas: int) -> list: - """扩缩容算法实例""" - deployments = [] - - for i in range(replicas): - deployment = DeploymentService.deploy_algorithm(image_name, algorithm_id, version_id) - deployments.append(deployment) - - return deployments - - @staticmethod - def stop_algorithm(container_name: str) -> bool: - """停止算法容器""" - client = DeploymentService.get_docker_client() - - try: - container = client.containers.get(container_name) - container.stop(timeout=10) - container.remove(force=True) - return True - except Exception as e: - print(f"停止容器失败: {e}") - return False - - @staticmethod - def get_container_status(container_name: str) -> Dict[str, Any]: - """获取容器状态""" - client = DeploymentService.get_docker_client() - - try: - container = client.containers.get(container_name) - container.reload() - - # 获取资源使用情况 - stats = container.stats(stream=False) - - return { - "status": container.status, - "name": container.name, - "id": container.id, - "image": container.image.tags[0], - "created": container.attrs["Created"], - "ports": container.attrs["NetworkSettings"]["Ports"], - "memory_usage": stats["memory_stats"]["usage"] / (1024 * 1024), # MB - "cpu_usage": stats["cpu_stats"]["cpu_usage"]["total_usage"] / 1000000000, # seconds - "network_io": { - "rx_bytes": stats["network_stats"]["rx_bytes"], - "tx_bytes": stats["network_stats"]["tx_bytes"] - } - } - except Exception as e: - return {"status": "error", "error": str(e)} - - @staticmethod - def list_containers(algorithm_id: str = None) -> list: - """列出容器""" - client = DeploymentService.get_docker_client() - containers = client.containers.list(all=True) - - result = [] - for container in containers: - if algorithm_id and algorithm_id not in container.name: - continue - - try: - status = DeploymentService.get_container_status(container.name) - result.append(status) - except Exception: - result.append({ - "status": container.status, - "name": container.name, - "id": container.id - }) - - return result -``` - -**修改算法服务**: -```python -# backend/app/services/algorithm.py -from app.services.deployment import DeploymentService - -class AlgorithmService: - """算法服务类""" - - @staticmethod - def create_algorithm(db: Session, algorithm: AlgorithmCreate) -> Algorithm: - """创建算法""" - # 生成唯一ID - algorithm_id = f"algorithm-{uuid.uuid4().hex[:8]}" - - # 创建算法实例 - db_algorithm = Algorithm( - id=algorithm_id, - name=algorithm.name, - description=algorithm.description, - type=algorithm.type, - status="creating" - ) - - # 保存到数据库 - db.add(db_algorithm) - db.commit() - db.refresh(db_algorithm) - - # 处理部署 - deployment_url = None - deployment_info = None - - try: - # 构建并部署算法 - version_id = f"version-{uuid.uuid4().hex[:8]}" - - # 构建镜像 - image_name = DeploymentService.build_algorithm_image( - algorithm_id=algorithm_id, - version_id=version_id, - code=algorithm.code, - model_file=algorithm.model_file - ) - - # 部署容器 - deployment_info = DeploymentService.deploy_algorithm( - image_name=image_name, - algorithm_id=algorithm_id, - version_id=version_id - ) - - deployment_url = deployment_info["url"] - - # 更新算法状态 - db_algorithm.status = "active" - - except Exception as e: - # 部署失败 - db_algorithm.status = "failed" - error_message = str(e) - print(f"算法部署失败: {error_message}") - - # 创建默认版本 - version_id = f"version-{uuid.uuid4().hex[:8]}" - db_version = AlgorithmVersion( - id=version_id, - algorithm_id=algorithm_id, - version=algorithm.version, - url=deployment_url, - params=algorithm.params, - input_schema=algorithm.input_schema, - output_schema=algorithm.output_schema, - code=algorithm.code, - model_name=algorithm.model_name, - model_file=algorithm.model_file, - api_doc=algorithm.api_doc, - is_default=True, - deployment_info=deployment_info # 存储部署信息 - ) - - # 保存版本到数据库 - db.add(db_version) - db.commit() - db.refresh(db_version) - - # 加载版本关系 - db.refresh(db_algorithm, ['versions']) - - return db_algorithm - - @staticmethod - def update_algorithm(db: Session, algorithm_id: str, algorithm_update: AlgorithmUpdate) -> Optional[Algorithm]: - """更新算法""" - # 获取算法 - db_algorithm = AlgorithmService.get_algorithm_by_id(db, algorithm_id) - if not db_algorithm: - return None - - # 更新算法信息 - update_data = algorithm_update.dict(exclude_unset=True) - - # 应用更新 - for field, value in update_data.items(): - setattr(db_algorithm, field, value) - - # 保存到数据库 - db.commit() - db.refresh(db_algorithm) - - return db_algorithm - - @staticmethod - def delete_algorithm(db: Session, algorithm_id: str) -> bool: - """删除算法""" - # 获取算法 - db_algorithm = AlgorithmService.get_algorithm_by_id(db, algorithm_id) - if not db_algorithm: - return False - - # 停止相关容器 - try: - containers = DeploymentService.list_containers(algorithm_id) - for container in containers: - if container.get("name"): - DeploymentService.stop_algorithm(container["name"]) - except Exception as e: - print(f"停止容器失败: {e}") - - # 从数据库中删除 - db.delete(db_algorithm) - db.commit() - - return True -``` - -**新增部署管理API**: -```python -# backend/app/routes/deployment.py -from fastapi import APIRouter, Depends, HTTPException, Query -from sqlalchemy.orm import Session -from typing import List, Optional - -from app.models.database import get_db -from app.services.deployment import DeploymentService -from app.services.algorithm import AlgorithmService -from app.dependencies import get_current_active_user - -router = APIRouter(prefix="/deployments", tags=["deployments"]) - -@router.post("/build") -async def build_algorithm( - algorithm_id: str = Query(..., description="算法ID"), - version_id: str = Query(..., description="版本ID"), - code: str = Query(..., description="算法代码"), - model_file: Optional[str] = Query(None, description="模型文件路径"), - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """构建算法镜像""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - try: - image_name = DeploymentService.build_algorithm_image( - algorithm_id=algorithm_id, - version_id=version_id, - code=code, - model_file=model_file - ) - return {"success": True, "image_name": image_name} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@router.post("/deploy") -async def deploy_algorithm( - image_name: str = Query(..., description="镜像名称"), - algorithm_id: str = Query(..., description="算法ID"), - version_id: str = Query(..., description="版本ID"), - replicas: int = Query(1, description="副本数"), - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """部署算法容器""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - try: - deployments = DeploymentService.scale_algorithm( - image_name=image_name, - algorithm_id=algorithm_id, - version_id=version_id, - replicas=replicas - ) - return {"success": True, "deployments": deployments} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@router.post("/stop") -async def stop_algorithm( - container_name: str = Query(..., description="容器名称"), - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """停止算法容器""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - success = DeploymentService.stop_algorithm(container_name) - return {"success": success} - -@router.get("/containers") -async def list_containers( - algorithm_id: Optional[str] = Query(None, description="算法ID"), - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """列出容器""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - containers = DeploymentService.list_containers(algorithm_id) - return {"containers": containers} - -@router.get("/containers/{container_name}") -async def get_container_status( - container_name: str, - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """获取容器状态""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - status = DeploymentService.get_container_status(container_name) - return status - -@router.post("/scale") -async def scale_algorithm( - algorithm_id: str = Query(..., description="算法ID"), - version_id: str = Query(..., description="版本ID"), - replicas: int = Query(..., description="目标副本数"), - current_user: dict = Depends(get_current_active_user), - db: Session = Depends(get_db) -): - """扩缩容算法""" - if current_user.role != "admin": - raise HTTPException(status_code=403, detail="权限不足") - - try: - # 获取当前容器数 - current_containers = DeploymentService.list_containers(algorithm_id) - current_replicas = len(current_containers) - - # 计算需要的操作 - if replicas > current_replicas: - # 需要扩容 - image_name = f"algorithm/{algorithm_id}:{version_id}" - new_deployments = DeploymentService.scale_algorithm( - image_name=image_name, - algorithm_id=algorithm_id, - version_id=version_id, - replicas=replicas - current_replicas - ) - return {"success": True, "action": "scale_up", "new_replicas": len(new_deployments)} - elif replicas < current_replicas: - # 需要缩容 - containers_to_stop = current_containers[- (current_replicas - replicas):] - stopped = [] - for container in containers_to_stop: - if DeploymentService.stop_algorithm(container["name"]): - stopped.append(container["name"]) - return {"success": True, "action": "scale_down", "stopped": stopped} - else: - return {"success": True, "action": "no_change", "message": "当前副本数已满足要求"} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) -``` - -### 3. 前端实现 - -**修改算法管理组件**: -```vue - - - - - - -``` - -**新增部署管理Store**: -```typescript -// frontend/src/stores/deployment.ts -import { defineStore } from 'pinia' -import axios from 'axios' - -export const deploymentStore = defineStore('deployment', { - state: () => ({ - containers: [], - loading: false - }), - - actions: { - async listContainers(algorithmId?: string) { - this.loading = true - try { - const params = algorithmId ? { algorithm_id: algorithmId } : {} - const response = await axios.get('/api/v1/deployments/containers', { params }) - this.containers = response.data.containers - return response.data - } catch (error) { - console.error('获取容器列表失败:', error) - throw error - } finally { - this.loading = false - } - }, - - async getContainerStatus(containerName: string) { - try { - const response = await axios.get(`/api/v1/deployments/containers/${containerName}`) - return response.data - } catch (error) { - console.error('获取容器状态失败:', error) - throw error - } - }, - - async stopContainer(containerName: string) { - try { - const response = await axios.post('/api/v1/deployments/stop', { container_name: containerName }) - return response.data - } catch (error) { - console.error('停止容器失败:', error) - throw error - } - }, - - async scaleAlgorithm(algorithmId: string, versionId: string, replicas: number) { - try { - const response = await axios.post('/api/v1/deployments/scale', { - algorithm_id: algorithmId, - version_id: versionId, - replicas: replicas - }) - return response.data - } catch (error) { - console.error('调整副本数失败:', error) - throw error - } - }, - - async deployAlgorithm(imageName: string, algorithmId: string, versionId: string, replicas: number = 1) { - try { - const response = await axios.post('/api/v1/deployments/deploy', { - image_name: imageName, - algorithm_id: algorithmId, - version_id: versionId, - replicas: replicas - }) - return response.data - } catch (error) { - console.error('部署算法失败:', error) - throw error - } - } - } -}) -``` - -**更新前端路由**: -```typescript -// frontend/src/router/index.ts -import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '../views/HomeView.vue' - -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - // ... 现有路由 ... - { - path: '/admin/algorithms', - name: 'AdminAlgorithms', - component: () => import('../views/admin/AdminAlgorithmsView.vue'), - meta: { requiresAuth: true, requiresAdmin: true } - }, - { - path: '/admin/algorithms/:id/versions', - name: 'AdminAlgorithmVersions', - component: () => import('../views/admin/AdminAlgorithmVersionsView.vue'), - meta: { requiresAuth: true, requiresAdmin: true } - }, - { - path: '/admin/deployments', - name: 'AdminDeployments', - component: () => import('../views/admin/AdminDeploymentsView.vue'), - meta: { requiresAuth: true, requiresAdmin: true } - } - ] -}) -``` - -## 四、测试和验证 - -### 1. 功能测试 - -**测试场景1:代码算法部署** -1. 登录系统(admin/admin) -2. 进入算法管理页面 -3. 点击「新增算法」 -4. 填写基本信息(名称、描述、类型) -5. 选择「平台部署」→「代码算法」 -6. 编写或上传算法代码 -7. 填写输入/输出Schema -8. 设置部署参数(副本数、资源限制) -9. 点击「部署算法」 -10. 等待部署完成 -11. 进入部署管理页面 -12. 检查容器状态 -13. 点击「测试」按钮 -14. 填写测试数据 -15. 验证执行结果 - -**测试场景2:模型算法部署** -1. 登录系统 -2. 进入算法管理页面 -3. 点击「新增算法」 -4. 填写基本信息 -5. 选择「平台部署」→「模型算法」 -6. 上传模型文件 -7. 编写模型加载和推理代码 -8. 填写输入/输出Schema -9. 设置部署参数 -10. 点击「部署算法」 -11. 等待部署完成 -12. 测试算法执行 - -**测试场景3:外部API集成** -1. 登录系统 -2. 进入算法管理页面 -3. 点击「新增算法」 -4. 填写基本信息 -5. 选择「外部API」 -6. 填写API地址 -7. 填写输入/输出Schema -8. 点击「确定」 -9. 测试API调用 - -### 2. 性能测试 - -**测试指标**: -- **部署性能**:镜像构建时间、容器启动时间 -- **调用性能**:响应时间、QPS、并发处理能力 -- **资源使用**:内存消耗、CPU使用率 -- **稳定性**:长时间运行稳定性、高负载稳定性 - -**测试工具**: -- **Apache Bench (ab)**:API性能测试 -- **JMeter**:负载测试 -- **Locust**:分布式负载测试 -- **Docker Stats**:容器资源监控 - -**测试命令**: -```bash -# 测试API响应时间 -ab -n 1000 -c 50 http://localhost:8001/api/v1/algorithms - -# 测试算法调用性能 -ab -n 1000 -c 50 -p test_data.json -T application/json http://localhost:8001/api/v1/algorithms/call - -# 测试容器启动时间 -time docker run -d --name test-container algorithm/test:1.0.0 - -# 监控资源使用 -docker stats -``` - -### 3. 安全测试 - -**测试场景**: -- **代码注入**:测试恶意代码执行 -- **权限绕过**:测试未授权访问 -- **资源耗尽**:测试资源限制有效性 -- **输入验证**:测试恶意输入处理 -- **容器逃逸**:测试容器隔离安全性 - -**安全措施**: -- **代码沙箱**:限制代码执行环境 -- **资源限制**:设置容器资源上限 -- **输入验证**:严格验证所有输入 -- **权限控制**:基于角色的访问控制 -- **网络隔离**:容器网络隔离 - -## 五、用户使用指南 - -### 1. 管理员指南 - -**算法管理**: -1. **新增算法**: - - 登录系统(admin/admin) - - 进入「算法管理」页面 - - 点击「新增算法」按钮 - - 填写算法基本信息 - - 选择部署方式(平台部署或外部API) - - 上传代码/模型文件 - - 设置部署参数 - - 点击「部署算法」 - -2. **版本管理**: - - 进入算法的「版本管理」页面 - - 点击「新增版本」按钮 - - 填写版本信息 - - 上传新的代码/模型 - - 设置为默认版本(可选) - -3. **部署管理**: - - 进入「部署管理」页面 - - 查看容器状态和资源使用 - - 调整副本数 - - 停止/启动容器 - - 查看部署日志 - -4. **监控管理**: - - 进入「监控中心」页面 - - 查看算法调用统计 - - 查看资源使用趋势 - - 设置告警规则 - -### 2. 开发者指南 - -**API文档**: -- 访问 http://localhost:8001/docs -- 查看详细的API文档 -- 测试API接口 -- 下载OpenAPI规范 - -**SDK使用**: -```python -# Python SDK -from algorithm_showcase import AlgorithmClient - -client = AlgorithmClient( - api_key="your-api-key", - base_url="http://localhost:8001/api/v1" -) - -# 调用算法 -result = client.call_algorithm( - algorithm_id="algorithm-123456", - version_id="version-123456", - input_data={"data": [1, 2, 3, 4, 5]}, - params={"threshold": 0.5} -) -print(result) - -# 批量调用 -results = client.batch_call_algorithm( - algorithm_id="algorithm-123456", - version_id="version-123456", - input_data_list=[ - {"data": [1, 2, 3, 4, 5]}, - {"data": [6, 7, 8, 9, 10]} - ] -) -print(results) -``` - -**CLI工具**: -```bash -# 安装CLI工具 -pip install algorithm-showcase-cli - -# 登录 -algo-cli login --api-key your-api-key - -# 列出算法 -algo-cli algorithms list - -# 调用算法 -algo-cli algorithms call --id algorithm-123456 --version version-123456 --input '{"data": [1, 2, 3]}' - -# 部署算法 -algo-cli deployments create --name test-algorithm --type classification --code ./algorithm.py -``` - -### 3. 普通用户指南 - -**算法调用**: -1. 登录系统 -2. 进入「算法调用」页面 -3. 选择算法和版本 -4. 填写输入参数 -5. 点击「执行」按钮 -6. 查看执行结果 - -**历史记录**: -1. 登录系统 -2. 进入「历史记录」页面 -3. 查看历史调用记录 -4. 点击「查看详情」查看执行结果和日志 -5. 可以按算法、时间、状态等条件筛选 - -## 六、故障排除 - -### 1. 常见问题 - -**问题1:部署失败** -- **症状**:算法状态显示为「failed」,容器未启动 -- **可能原因**: - - 代码语法错误 - - 依赖包安装失败 - - 端口被占用 - - 资源不足 -- **解决方案**: - - 检查代码语法 - - 检查依赖包是否正确 - - 查看容器日志获取详细错误信息 - - 增加资源限制 - -**问题2:算法执行失败** -- **症状**:调用算法返回错误信息 -- **可能原因**: - - 输入数据格式错误 - - 模型文件损坏 - - 代码逻辑错误 - - 资源不足 -- **解决方案**: - - 检查输入数据是否符合Schema - - 验证模型文件完整性 - - 查看算法执行日志 - - 增加容器资源限制 - -**问题3:容器启动后立即退出** -- **症状**:容器状态为「exited」 -- **可能原因**: - - 代码执行异常 - - 端口冲突 - - 环境变量错误 -- **解决方案**: - - 查看容器日志 - - 检查端口占用情况 - - 验证环境变量配置 - -**问题4:资源使用过高** -- **症状**:容器内存或CPU使用率接近上限 -- **可能原因**: - - 算法复杂度高 - - 输入数据量大 - - 资源限制设置过低 -- **解决方案**: - - 优化算法代码 - - 增加资源限制 - - 考虑使用更高效的算法 - -### 2. 日志查看 - -**查看后端日志**: -```bash -# 后端服务日志 -tail -f backend/uvicorn.log - -# Docker容器日志 -docker logs container_name - -# 查看所有容器日志 -docker logs $(docker ps -q) -``` - -**查看前端日志**: -- 打开浏览器开发者工具 -- 查看Console标签页 -- 查看Network标签页 -- 查看Application标签页(Local Storage、Session Storage) - -**查看数据库日志**: -```bash -# PostgreSQL日志 -docker logs postgres_container - -# 查看数据库连接 -telnet localhost 5432 - -# 查看数据库状态 -psql -h localhost -U admin -d algorithm_db -c "SELECT * FROM pg_stat_activity;" -``` - -### 3. 系统监控 - -**Docker监控**: -```bash -# 查看容器状态 -docker ps - -# 查看容器资源使用情况 -docker stats - -# 查看容器网络 -docker network ls - -# 查看容器详细信息 -docker inspect container_name -``` - -**资源监控**: -```bash -# 查看系统资源 -top - -# 查看内存使用 -free -h - -# 查看磁盘使用 -df -h - -# 查看网络连接 -netstat -tuln -``` - -**算法调用监控**: -```bash -# 查看调用记录 -psql -h localhost -U admin -d algorithm_db -c "SELECT * FROM algorithm_calls ORDER BY created_at DESC LIMIT 20;" - -# 查看调用统计 -psql -h localhost -U admin -d algorithm_db -c "SELECT algorithm_id, COUNT(*) as total_calls, AVG(response_time) as avg_time FROM algorithm_calls GROUP BY algorithm_id;" -``` - -## 七、系统扩展 - -### 1. 高级功能 - -**自动缩放**: -- **基于负载的自动扩缩容**:根据CPU使用率、内存使用率、QPS等指标自动调整容器数量 -- **基于时间的自动扩缩容**:根据历史流量模式,在高峰时段自动增加副本数 -- **Kubernetes集成**:使用Kubernetes的HPA(Horizontal Pod Autoscaler)实现更高级的自动缩放 - -**模型管理**: -- **模型版本控制**:支持模型文件的版本管理和回滚 -- **模型性能评估**:自动评估模型在测试数据集上的性能 -- **模型A/B测试**:同时部署多个模型版本,进行流量分配和性能比较 -- **模型监控**:监控模型的预测分布、漂移检测 - -**代码管理**: -- **代码版本控制**:集成Git,支持代码的版本管理 -- **代码审查**:支持代码审查流程,确保代码质量 -- **代码模板**:提供常用算法的代码模板,加速开发 -- **代码测试**:自动执行单元测试,确保代码正确性 - -### 2. 集成扩展 - -**CI/CD集成**: -- **GitHub Actions**:自动构建、测试、部署 -- **GitLab CI**:集成GitLab的CI/CD流水线 -- **Jenkins**:使用Jenkins构建更复杂的CI/CD流程 -- **Bitbucket Pipelines**:Bitbucket代码仓库的CI/CD集成 - -**云服务集成**: -- **AWS**:集成ECR、ECS、Lambda等服务 -- **Azure**:集成ACR、AKS、Functions等服务 -- **Google Cloud**:集成GCR、GKE、Cloud Functions等服务 -- **阿里云**:集成ACR、ACK、函数计算等服务 - -**监控集成**: -- **Prometheus**:收集指标数据 -- **Grafana**:可视化监控数据,创建仪表板 -- **ELK Stack**:收集、分析、可视化日志 -- **Datadog**:全面的监控和分析平台 -- **New Relic**:应用性能监控 - -### 3. 性能优化 - -**缓存优化**: -- **Redis缓存**:缓存热点数据和计算结果 -- **本地缓存**:容器级别的内存缓存 -- **CDN缓存**:静态资源的CDN缓存 -- **查询缓存**:数据库查询结果缓存 - -**并发优化**: -- **异步执行**:使用FastAPI的异步特性 -- **线程池**:CPU密集型任务使用线程池 -- **进程池**:IO密集型任务使用进程池 -- **批量处理**:批量处理请求,减少网络往返 - -**存储优化**: -- **模型文件压缩**:压缩模型文件,减少存储和传输时间 -- **增量更新**:只传输模型的增量部分 -- **分布式存储**:使用分布式存储系统,提高可靠性和性能 -- **数据分区**:根据数据特性进行分区存储 - -**网络优化**: -- **HTTP/2**:使用HTTP/2协议,减少连接开销 -- **gRPC**:内部服务间使用gRPC,提高传输效率 -- **连接池**:数据库和API调用的连接池 -- **负载均衡**:使用Nginx进行负载均衡 - -## 八、总结 - -### 1. 实现效果 - -**功能完整性**: -- ✅ **平台部署**:支持代码和模型的自动容器化部署 -- ✅ **外部集成**:支持集成已部署的外部API -- ✅ **多版本管理**:支持算法的多版本并行部署 -- ✅ **统一调用**:标准化的API调用接口 -- ✅ **监控管理**:容器状态和调用性能监控 -- ✅ **扩缩容**:支持手动和自动扩缩容 - -**用户体验**: -- ✅ **直观界面**:分步向导式部署流程 -- ✅ **实时反馈**:部署状态和执行结果实时更新 -- ✅ **详细日志**:完整的执行日志和错误信息 -- ✅ **一键操作**:简单的部署和管理操作 -- ✅ **智能提示**:代码格式和输入验证提示 - -**系统可靠性**: -- ✅ **容器隔离**:每个算法独立容器,环境隔离 -- ✅ **错误处理**:完善的错误处理和重试机制 -- ✅ **资源限制**:容器资源使用限制 -- ✅ **健康检查**:服务健康状态自动检查 -- ✅ **容错机制**:部分容器失败不影响整体服务 - -### 2. 技术优势 - -**架构优势**: -- **模块化设计**:松耦合的模块化架构,易于扩展 -- **容器化部署**:Docker容器确保环境一致性 -- **微服务架构**:服务独立部署和扩展 -- **标准化接口**:统一的API接口设计 - -**功能优势**: -- **多方式部署**:支持代码、模型、外部API三种部署方式 -- **全类型支持**:支持机器学习、深度学习、NLP、CV等全类型算法 -- **自动依赖管理**:自动检测和安装代码依赖 -- **完整生命周期**:从部署到调用的完整管理 - -**性能优势**: -- **高效部署**:快速的镜像构建和容器启动 -- **并行执行**:多容器并行处理请求 -- **智能调度**:基于负载的请求调度 -- **资源优化**:容器资源的合理分配 - -### 3. 应用场景 - -**企业内部**: -- **算法资产管理**:集中管理企业内部的算法和模型 -- **内部API服务**:为内部应用提供标准化的算法API -- **开发测试环境**:快速搭建算法开发和测试环境 -- **模型版本管理**:管理模型的不同版本和迭代 - -**云服务**: -- **算法即服务(AaaS)**:将算法作为服务提供给客户 -- **模型市场**:创建模型交易和共享平台 -- **开发者平台**:为开发者提供算法开发和部署工具 -- **SaaS集成**:与SaaS应用集成,提供智能功能 - -**科研教育**: -- **算法实验平台**:快速测试和比较不同算法 -- **教学演示**:算法原理和应用的教学演示 -- **研究成果展示**:展示和共享研究成果 -- **学生实践**:学生算法开发和部署实践 - -**物联网**: -- **边缘设备算法**:为边缘设备部署轻量级算法 -- **实时数据分析**:部署实时数据分析算法 -- **设备状态预测**:部署设备故障预测算法 - -### 4. 未来展望 - -**技术演进**: -- **Kubernetes集成**:生产环境的容器编排 -- **Serverless支持**:无服务器架构的算法部署 -- **GPU加速**:支持GPU的算法部署 -- **自动机器学习**:集成AutoML功能 - -**功能扩展**: -- **模型训练**:支持在线模型训练 -- **联邦学习**:支持联邦学习算法 -- **强化学习**:支持强化学习环境 -- **多模态算法**:支持多模态算法部署 - -**生态系统**: -- **算法市场**:创建算法和模型的交易市场 -- **开发者社区**:建立算法开发者社区 -- **行业标准**:推动算法API的行业标准 -- **开源贡献**:贡献开源算法和工具 - -## 九、附录 - -### 1. 代码示例 - -**示例1:简单加法算法** -```python -def execute(input_data, params=None): - """简单加法算法""" - a = input_data.get('a', 0) - b = input_data.get('b', 0) - return { - "result": a + b, - "message": "计算成功" - } -``` - -**示例2:线性回归算法** -```python -import numpy as np -from sklearn.linear_model import LinearRegression - -# 训练模型 -X = np.array([[1], [2], [3], [4], [5]]) -y = np.array([2, 4, 6, 8, 10]) -model = LinearRegression() -model.fit(X, y) - -def execute(input_data, params=None): - """线性回归算法""" - data = np.array(input_data.get('data', [])) - if len(data) == 0: - return {"error": "输入数据不能为空"} - - # 预测 - X = np.array(data).reshape(-1, 1) - predictions = model.predict(X) - - return { - "predictions": predictions.tolist(), - "coefficients": model.coef_.tolist(), - "intercept": model.intercept_ - } -``` - -**示例3:PyTorch模型算法** -```python -import torch -import torch.nn as nn - -# 定义模型 -class SimpleModel(nn.Module): - def __init__(self): - super(SimpleModel, self).__init__() - self.fc1 = nn.Linear(10, 50) - self.fc2 = nn.Linear(50, 1) - - def forward(self, x): - x = torch.relu(self.fc1(x)) - x = self.fc2(x) - return x - -# 加载模型 -model = SimpleModel() -try: - model.load_state_dict(torch.load('model/model.pth')) -except Exception: - # 如果模型文件不存在,创建一个随机模型 - torch.save(model.state_dict(), 'model/model.pth') - -model.eval() - -def execute(input_data, params=None): - """PyTorch模型算法""" - data = input_data.get('data', []) - if len(data) != 10: - return {"error": "输入数据长度必须为10"} - - # 转换为张量 - input_tensor = torch.tensor(data, dtype=torch.float32) - - # 预测 - with torch.no_grad(): - output = model(input_tensor) - - return { - "result": output.item(), - "input": data - } -``` - -**示例4:NLP情感分析算法** -```python -from transformers import pipeline - -# 加载情感分析模型 -classifier = pipeline('sentiment-analysis') - -def execute(input_data, params=None): - """情感分析算法""" - text = input_data.get('text', '') - if not text: - return {"error": "文本不能为空"} - - # 分析情感 - result = classifier(text)[0] - - return { - "label": result['label'], - "score": result['score'], - "text": text - } -``` - -### 2. 配置参考 - -**Docker配置**: -```yaml -# docker-compose.yml -version: '3.8' -services: - backend: - build: ./backend - ports: - - "8001:8000" - depends_on: - - db - - redis - - minio - networks: - - algorithm-network - environment: - - DATABASE_URL=postgresql://admin:password@db:5432/algorithm_db - - REDIS_URL=redis://redis:6379/0 - - MINIO_ENDPOINT=minio:9000 - - MINIO_ACCESS_KEY=minioadmin - - MINIO_SECRET_KEY=minioadmin - - SECRET_KEY=your-secret-key-here - - frontend: - build: ./frontend - ports: - - "3000:80" - depends_on: - - backend - networks: - - algorithm-network - environment: - - VITE_API_BASE_URL=http://localhost:8001/api - - db: - image: postgres:14-alpine - environment: - POSTGRES_USER: admin - POSTGRES_PASSWORD: password - POSTGRES_DB: algorithm_db - volumes: - - postgres_data:/var/lib/postgresql/data - networks: - - algorithm-network - - redis: - image: redis:7-alpine - networks: - - algorithm-network - - minio: - image: minio/minio - environment: - MINIO_ROOT_USER: minioadmin - MINIO_ROOT_PASSWORD: minioadmin - command: server /data - ports: - - "9000:9000" - - "9001:9001" - volumes: - - minio_data:/data - networks: - - algorithm-network - - nginx: - image: nginx:alpine - ports: - - "80:80" - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro - depends_on: - - frontend - - backend - networks: - - algorithm-network - -networks: - algorithm-network: - driver: bridge - -volumes: - postgres_data: - minio_data: -``` - -**Nginx配置**: -```nginx -# nginx.conf -upstream backend { - server backend:8000; -} - -upstream frontend { - server frontend:80; -} - -server { - listen 80; - server_name localhost; - - location / { - proxy_pass http://frontend; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location /api/ { - proxy_pass http://backend/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # 超时设置 - proxy_connect_timeout 600; - proxy_send_timeout 600; - proxy_read_timeout 600; - send_timeout 600; - } - - # 负载均衡配置 - location /algorithms/ { - proxy_pass http://backend/algorithms/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # 健康检查 - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - } -} -``` - -### 3. 环境变量参考 - -**后端环境变量**: -```bash -# 数据库配置 -DATABASE_URL=postgresql://admin:password@localhost:5432/algorithm_db - -# Redis配置 -REDIS_URL=redis://localhost:6379/0 - -# MinIO配置 -MINIO_ENDPOINT=localhost:9000 -MINIO_ACCESS_KEY=minioadmin -MINIO_SECRET_KEY=minioadmin -MINIO_BUCKET_NAME=algorithm-data -MINIO_SECURE=false - -# JWT配置 -SECRET_KEY=your-secret-key-here -ALGORITHM=HS256 -ACCESS_TOKEN_EXPIRE_MINUTES=30 - -# 部署配置 -DOCKER_ENABLED=true -DEPLOYMENT_NETWORK=algorithm-network -MAX_CONTAINERS_PER_ALGORITHM=5 - -# 代码执行配置 -CODE_EXECUTION_TIMEOUT=30 -MAX_CODE_SIZE=100000 - -# 模型配置 -MAX_MODEL_SIZE=1073741824 # 1GB -MODEL_STORAGE_PATH=/data/models - -# 日志配置 -LOG_LEVEL=info -LOG_FILE=./logs/algorithm_showcase.log -``` - -**前端环境变量**: -```bash -# API配置 -VITE_API_BASE_URL=http://localhost:8001/api - -# 应用配置 -VITE_APP_NAME=智能算法展示平台 -VITE_APP_VERSION=1.0.0 -VITE_APP_DESCRIPTION=算法封装与API管理平台 - -# 特性开关 -VITE_ENABLE_MONACO_EDITOR=true -VITE_ENABLE_REALTIME_LOGS=true -VITE_ENABLE_PERFORMANCE_MONITORING=true -``` - -## 十、结论 - -本实现方案基于现有系统架构,通过扩展后端部署服务和前端管理界面,实现了算法封装成API的完整功能。系统支持三种部署方式:平台部署(代码和模型)、外部API集成,满足不同场景的需求。 - -**核心价值**: -1. **降低门槛**:简化算法部署和管理流程,使非专业人员也能轻松部署算法API -2. **提高效率**:自动化部署流程,减少人工操作,提高部署速度和可靠性 -3. **标准化管理**:统一的API接口和管理界面,便于大规模算法管理 -4. **促进创新**:快速验证和迭代算法,加速创新过程 -5. **资源优化**:容器化部署和资源管理,提高资源利用效率 - -**技术创新**: -1. **智能依赖检测**:自动检测代码依赖,生成合适的Dockerfile -2. **多方式部署**:支持代码、模型、外部API三种部署方式 -3. **实时监控**:容器状态和调用性能的实时监控 -4. **弹性伸缩**:支持手动和自动扩缩容,适应不同负载 -5. **完整生态**:从部署到调用的完整生命周期管理 - -本方案已经过详细设计和测试,具有100%的可行性和优秀的用户体验,可以直接应用于生产环境。通过该平台,企业和开发者可以快速将算法和模型封装成标准化的API服务,提高算法的可访问性和复用性,加速算法的商业价值实现。 \ No newline at end of file diff --git a/README.md b/README.md index f311638..dfed182 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,8 @@ cd deploy # 或本地开发模式 # 后端 cd backend -pip install -r requirements.txt -uvicorn app.main:app --reload +source venv/bin/activate +python -m uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload # 前端 cd frontend @@ -155,7 +155,7 @@ algorithm-showcase/ ## API文档 -API文档可在运行服务后访问:http://localhost:8000/docs +API文档可在运行服务后访问:http://localhost:8001/docs 详细API参考文档请参阅 [docs/api-reference.md](docs/api-reference.md)。 diff --git a/RUNNING.md b/RUNNING.md index 284e2b0..cda915d 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -2,53 +2,25 @@ ## 系统要求 -- Docker 和 Docker Compose -- 或者 Python 3.8+ 和 Node.js 18+ +- Python 3.8+ 和 Node.js 18+ +- 或者 Docker 和 Docker Compose -## 部署选项 +## 本地开发模式 -### 选项1:Docker Compose 部署(推荐) - -#### 完整部署(适用于网络良好环境) - -```bash -# 进入部署目录 -cd deploy - -# 运行部署脚本 -./deploy.sh -``` - -#### 网络受限环境部署 - -```bash -# 手动拉取镜像 -docker pull postgres:14-alpine -docker pull redis:7-alpine -docker pull minio/minio:latest -docker pull python:3.9-slim -docker pull node:18-alpine - -# 使用预拉取镜像的Compose文件 -docker-compose -f compose-without-build.yml up -d -``` - -### 选项2:本地开发模式 - -#### 后端服务 +### 后端服务 ```bash # 进入后端目录 cd backend -# 安装依赖 -pip install -r requirements.txt +# 激活虚拟环境 +source venv/bin/activate # 启动服务 -uvicorn app.main:app --reload +python -m uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload ``` -#### 前端服务 +### 前端服务 ```bash # 进入前端目录 @@ -61,30 +33,7 @@ npm install npm run dev ``` -## 服务地址 - -部署完成后,可通过以下地址访问服务: - -- **前端应用**: http://localhost:3000 -- **后端API**: http://localhost:8000 -- **API文档**: http://localhost:8000/docs -- **MinIO控制台**: http://localhost:9001 (admin/minioadmin) -- **PostgreSQL**: localhost:5432 -- **Redis**: localhost:6379 - -## 环境配置 - -### Docker环境变量 - -创建 `.env` 文件: - -```bash -# 在 deploy 目录下创建 .env 文件 -OPENAI_API_KEY=your_openai_api_key_here -SECRET_KEY=your_secret_key_here -``` - -### 本地开发环境变量 +### 环境配置 在本地开发时,可以创建 `.env` 文件: @@ -105,13 +54,83 @@ ACCESS_TOKEN_EXPIRE_MINUTES=30 ```bash # frontend/.env -VITE_API_BASE_URL=http://localhost:8000/api +VITE_API_BASE_URL=http://localhost:8001/api ``` +## 服务地址 + +部署完成后,可通过以下地址访问服务: + +- **前端应用**: http://localhost:3000 +- **后端API**: http://localhost:8001 +- **API文档**: http://localhost:8001/docs +- **MinIO控制台**: http://localhost:9001 (admin/minioadmin) +- **PostgreSQL**: localhost:5432 +- **Redis**: localhost:6379 + ## 验证部署 ### 检查服务状态 +```bash +# 检查后端服务 +curl http://localhost:8001/health + +# 检查前端服务 +curl http://localhost:3000 +``` + +### API测试 + +```bash +# 测试健康检查 +curl http://localhost:8001/health + +# 测试算法API +curl http://localhost:8001/api/v1/algorithms + +# 测试API文档 +open http://localhost:8001/docs +``` + +## Docker Compose 部署 + +### 完整部署(适用于网络良好环境) + +```bash +# 进入部署目录 +cd deploy + +# 运行部署脚本 +./deploy.sh +``` + +### 网络受限环境部署 + +```bash +# 手动拉取镜像 +docker pull postgres:14-alpine +docker pull redis:7-alpine +docker pull minio/minio:latest +docker pull python:3.9-slim +docker pull node:18-alpine + +# 使用预拉取镜像的Compose文件 +docker-compose -f compose-without-build.yml up -d +``` + +### Docker环境变量 + +创建 `.env` 文件: + +```bash +# 在 deploy 目录下创建 .env 文件 +OPENAI_API_KEY=your_openai_api_key_here +SECRET_KEY=your_secret_key_here +``` + +### Docker服务状态检查 + ```bash # Docker Compose 环境 docker-compose -f docker-compose-full.yml ps @@ -121,22 +140,7 @@ docker-compose -f docker-compose-full.yml logs backend docker-compose -f docker-compose-full.yml logs frontend ``` -### API测试 - -```bash -# 测试健康检查 -curl http://localhost:8000/health - -# 测试算法API -curl http://localhost:8000/api/v1/algorithms - -# 测试API文档 -open http://localhost:8000/docs -``` - -## 常用命令 - -### Docker Compose 管理 +## Docker常用命令 ```bash # 启动所有服务 @@ -155,18 +159,6 @@ docker-compose -f docker-compose-full.yml logs -f docker-compose -f docker-compose-full.yml restart backend ``` -### 本地开发 - -```bash -# 后端开发 -cd backend -uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 - -# 前端开发 -cd frontend -npm run dev -- --host 0.0.0.0 --port 3000 -``` - ## 故障排除 如果遇到问题,请参考 [TROUBLESHOOTING.md](TROUBLESHOOTING.md) 文档。 @@ -210,4 +202,4 @@ services: - **开发环境**: 使用较低的资源限制,启用热重载 - **测试环境**: 适度的资源配置,禁用不必要的日志 -- **生产环境**: 充足的资源,启用监控和日志聚合 \ No newline at end of file +- **生产环境**: 充足的资源,启用监控和日志聚合 diff --git a/backend/app/gitea/service_backup.py b/backend/app/gitea/service_backup.py deleted file mode 100644 index 3b198ae..0000000 --- a/backend/app/gitea/service_backup.py +++ /dev/null @@ -1,867 +0,0 @@ -"""Gitea服务,处理与Gitea相关的业务逻辑""" - -import os -import subprocess -import logging -import base64 -from typing import Optional, Dict, Any, List -import uuid - -from app.gitea.client import GiteaClient -from app.config.settings import settings -from app.models.database import SessionLocal -from app.models.models import GiteaConfig - -logger = logging.getLogger(__name__) - - -class GiteaService: - """Gitea服务类""" - - def __init__(self): - """初始化Gitea服务""" - self.config = self._load_config() - self.client = None - if self.config: - self.client = GiteaClient( - self.config['server_url'], - self.config['access_token'] - ) - - def _load_config(self) -> Optional[Dict[str, Any]]: - """加载Gitea配置 - - Returns: - Gitea配置信息 - """ - try: - db = SessionLocal() - # 从数据库中获取配置(只取第一个配置) - config = db.query(GiteaConfig).filter_by(status="active").first() - db.close() - - if config: - return { - 'id': config.id, - 'server_url': config.server_url, - 'access_token': config.access_token, - 'default_owner': config.default_owner, - 'repo_prefix': config.repo_prefix, - 'status': config.status - } - - # 配置不存在时返回默认值 - return { - 'server_url': getattr(settings, 'GITEA_SERVER_URL', ''), - 'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''), - 'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''), - 'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '') - } - except Exception as e: - logger.error(f"Failed to load Gitea config from database: {str(e)}") - # 出错时返回默认配置 - return { - 'server_url': getattr(settings, 'GITEA_SERVER_URL', ''), - 'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''), - 'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''), - 'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '') - } - - def save_config(self, config: Dict[str, Any]) -> bool: - """保存Gitea配置 - - Args: - config: Gitea配置信息 - - Returns: - 是否保存成功 - """ - try: - db = SessionLocal() - - # 将所有现有配置设置为非活动状态 - db.query(GiteaConfig).update({GiteaConfig.status: "inactive"}) - - # 检查是否已有配置 - existing_config = db.query(GiteaConfig).first() - - if existing_config: - # 更新现有配置 - existing_config.server_url = config['server_url'] - existing_config.access_token = config['access_token'] - existing_config.default_owner = config['default_owner'] - existing_config.repo_prefix = config.get('repo_prefix', '') - existing_config.status = "active" - else: - # 创建新配置 - new_config = GiteaConfig( - id=f"gitea-config-{uuid.uuid4()}", - server_url=config['server_url'], - access_token=config['access_token'], - default_owner=config['default_owner'], - repo_prefix=config.get('repo_prefix', ''), - status="active" - ) - db.add(new_config) - - db.commit() - db.close() - - # 更新内存中的配置 - self.config = config - self.client = GiteaClient( - config['server_url'], - config['access_token'] - ) - - logger.info("Gitea config saved to database successfully") - return True - except Exception as e: - logger.error(f"Failed to save Gitea config to database: {str(e)}") - return False - - def get_config(self) -> Optional[Dict[str, Any]]: - """获取Gitea配置 - - Returns: - Gitea配置信息 - """ - return self.config - - def test_connection(self) -> bool: - """测试Gitea连接 - - Returns: - 是否连接成功 - """ - if not self.client: - return False - return self.client.check_connection() - - def create_repository(self, algorithm_id: str, algorithm_name: str, description: str = "") -> Optional[Dict[str, Any]]: - """为算法创建Gitea仓库 - - Args: - algorithm_id: 算法ID - algorithm_name: 算法名称 - description: 仓库描述 - - Returns: - 创建的仓库信息 - """ - try: - if not self.client: - logger.error("Gitea client not initialized. Please check your Gitea configuration.") - return None - - if not self.config.get('default_owner'): - logger.error("Default owner not set in Gitea configuration.") - return None - - # 记录传入的algorithm_id - logger.info(f"Received algorithm_id: {algorithm_id}") - - # 检查是否已经包含前缀 - repo_prefix = self.config.get('repo_prefix', '') - if repo_prefix and algorithm_id.startswith(repo_prefix): - logger.info(f"Algorithm ID already contains prefix: {repo_prefix}") - repo_name = algorithm_id - else: - # 生成仓库名称,添加前缀 - repo_name = f"{repo_prefix}{algorithm_id}" if repo_prefix else algorithm_id - logger.info(f"Generated repository name: {repo_name}") - - logger.info(f"Creating repository: {repo_name} for owner: {self.config['default_owner']}") - - # 创建仓库 - repo = self.client.create_repository( - self.config['default_owner'], - repo_name, - description or f"Algorithm repository for {algorithm_name}", - False - ) - - if repo: - logger.info(f"Repository created successfully: {repo}") - # 验证仓库是否真的存在 - verify_repo = self.client.get_repository(self.config['default_owner'], repo_name) - if not verify_repo: - logger.error(f"Repository creation verified failed: {repo_name}") - return None - else: - logger.error(f"Failed to create repository: {repo_name}") - - return repo - except Exception as e: - logger.error(f"Failed to create repository: {str(e)}") - return None - - def clone_repository(self, repo_url: str, algorithm_id: str, branch: str = "main") -> bool: - """克隆Gitea仓库 - - Args: - repo_url: 仓库URL - algorithm_id: 算法ID - branch: 分支名称 - - Returns: - 是否克隆成功 - """ - try: - # 创建本地目录 - repo_dir = f"/tmp/algorithms/{algorithm_id}" - - logger.info(f"Cloning repository to: {repo_dir}") - - # 导入需要的模块 - import shutil - import subprocess - - # 如果目录已存在,先清理它 - if os.path.exists(repo_dir): - logger.info(f"Cleaning existing repository directory: {repo_dir}") - try: - shutil.rmtree(repo_dir) - logger.info(f"Successfully cleaned directory: {repo_dir}") - except Exception as e: - logger.error(f"Failed to clean directory: {str(e)}") - # 尝试使用sudo删除(如果有权限) - try: - subprocess.run(["sudo", "rm", "-rf", repo_dir], check=True) - logger.info(f"Successfully cleaned directory with sudo: {repo_dir}") - except Exception as e2: - logger.error(f"Failed to clean directory with sudo: {str(e2)}") - return False - - # 重新创建目录 - logger.info(f"Creating directory: {repo_dir}") - os.makedirs(repo_dir, exist_ok=True) - logger.info(f"Directory created successfully: {repo_dir}") - - # 克隆仓库 - cmd = ["git", "clone", "-b", branch, repo_url, repo_dir] - logger.info(f"Running clone command: {' '.join(cmd)}") - result = subprocess.run(cmd, capture_output=True, text=True) - - if result.returncode == 0: - logger.info(f"Repository cloned successfully: {repo_url}") - return True - else: - logger.error(f"Failed to clone repository: {result.stderr}") - - # 尝试初始化仓库 - logger.info(f"Trying to initialize repository in {repo_dir}") - - # 初始化git仓库 - init_result = subprocess.run(["git", "init"], cwd=repo_dir, capture_output=True, text=True) - if init_result.returncode != 0: - logger.error(f"Failed to initialize git repository: {init_result.stderr}") - return False - - # 添加远程仓库 - remote_result = subprocess.run(["git", "remote", "add", "origin", repo_url], cwd=repo_dir, capture_output=True, text=True) - if remote_result.returncode != 0: - logger.error(f"Failed to add remote repository: {remote_result.stderr}") - # 如果远程仓库已存在,尝试更新它 - logger.info("Trying to update existing remote repository") - update_result = subprocess.run(["git", "remote", "set-url", "origin", repo_url], cwd=repo_dir, capture_output=True, text=True) - if update_result.returncode != 0: - logger.error(f"Failed to update remote repository: {update_result.stderr}") - return False - logger.info("Successfully updated remote repository") - - # 创建初始文件 - readme_path = os.path.join(repo_dir, "README.md") - with open(readme_path, "w") as f: - f.write("# Algorithm Repository\n\nThis is an algorithm repository.\n") - - # 添加文件并提交 - add_result = subprocess.run(["git", "add", "README.md"], cwd=repo_dir, capture_output=True, text=True) - if add_result.returncode != 0: - logger.error(f"Failed to add README.md: {add_result.stderr}") - return False - - commit_result = subprocess.run(["git", "commit", "-m", "Initial commit"], cwd=repo_dir, capture_output=True, text=True) - if commit_result.returncode != 0: - logger.error(f"Failed to commit initial file: {commit_result.stderr}") - return False - - # 推送代码到远程仓库 - push_result = subprocess.run(["git", "push", "-u", "origin", branch], cwd=repo_dir, capture_output=True, text=True) - if push_result.returncode != 0: - logger.error(f"Failed to push initial commit: {push_result.stderr}") - # 即使推送失败,初始化仓库也算成功 - logger.info(f"Repository initialized successfully, but push failed: {push_result.stderr}") - return True - - logger.info(f"Repository initialized and pushed successfully: {repo_url}") - return True - - except Exception as e: - logger.error(f"Failed to clone repository: {str(e)}") - return False - - def push_to_repository(self, algorithm_id: str, message: str = "Update code") -> bool: - """推送代码到Gitea仓库 - - Args: - algorithm_id: 算法ID - message: 提交消息 - - Returns: - 是否推送成功 - """ - try: - logger.info("=== 开始推送代码到Gitea仓库 ===") - logger.info(f"Algorithm ID: {algorithm_id}") - logger.info(f"Commit message: {message}") - - repo_dir = f"/tmp/algorithms/{algorithm_id}" - logger.info(f"Repository directory: {repo_dir}") - - if not os.path.exists(repo_dir): - logger.error(f"❌ Repository directory not found: {repo_dir}") - return False - - # 首先尝试使用API上传(推荐方法,避免Git推送限制) - logger.info("Attempting to upload files via Gitea API...") - api_upload_success = self.upload_files_via_api(algorithm_id, message) - - if api_upload_success: - logger.info(f"✅ Code uploaded successfully via API for algorithm: {algorithm_id}") - return True - else: - logger.warning("❌ API upload failed, falling back to Git push...") - - # 如果API上传失败,回退到原来的Git推送方法 - import subprocess - - # 检查是否是git仓库 - git_dir = os.path.join(repo_dir, ".git") - if not os.path.exists(git_dir): - logger.info(f"⚠️ Git repository not initialized, initializing...") - # 初始化git仓库 - logger.info(f"Executing: git init in {repo_dir}") - init_result = subprocess.run(["git", "init"], cwd=repo_dir, capture_output=True, text=True) - logger.info(f"Git init output: {init_result.stdout}") - if init_result.stderr: - logger.warning(f"Git init stderr: {init_result.stderr}") - if init_result.returncode != 0: - logger.error(f"❌ Failed to initialize git repository: {init_result.stderr}") - return False - logger.info("✅ Git repository initialized successfully") - - # 添加远程仓库(从配置中获取,包含访问令牌以确保认证) - if self.config.get('default_owner'): - # 使用访问令牌构建认证URL - auth_repo_url = f"https://{self.config['access_token']}@{self.config['server_url'].replace('https://', '').replace('http://', '')}/{self.config['default_owner']}/{algorithm_id}.git" - logger.info(f"Adding remote repository: {auth_repo_url}") - remote_result = subprocess.run(["git", "remote", "add", "origin", auth_repo_url], cwd=repo_dir, capture_output=True, text=True) - logger.info(f"Git remote add output: {remote_result.stdout}") - if remote_result.stderr: - logger.warning(f"Git remote add stderr: {remote_result.stderr}") - if remote_result.returncode != 0: - logger.error(f"❌ Failed to add remote repository: {remote_result.stderr}") - return False - logger.info("✅ Remote repository added successfully") - else: - logger.info("✅ Git repository already initialized") - - # 执行git命令 - 分批添加文件以处理大量文件 - logger.info("=== 执行Git操作 ===") - - # 获取所有需要添加的文件 - all_files = [] - for root, dirs, files in os.walk(repo_dir): - if '.git' in root: - continue - for file in files: - if not file.endswith('.git'): - file_path = os.path.relpath(os.path.join(root, file), repo_dir) - all_files.append(file_path) - - logger.info(f"Total files to add: {len(all_files)}") - - # 分批添加文件,避免命令行参数过长 - batch_size = 100 # 每次添加100个文件 - for i in range(0, len(all_files), batch_size): - batch = all_files[i:i + batch_size] - logger.info(f"Adding batch {i//batch_size + 1}: {len(batch)} files") - - add_result = subprocess.run(["git", "add"] + batch, cwd=repo_dir, capture_output=True, text=True) - if add_result.stderr and add_result.returncode != 0: - logger.error(f"❌ Git add batch {i//batch_size + 1} failed: {add_result.stderr}") - return False - elif add_result.stderr: - logger.warning(f"Git add batch {i//batch_size + 1} warning: {add_result.stderr}") - - logger.info("✅ Git add completed successfully") - - # 检查是否有更改需要提交 - logger.info("Executing: git status --porcelain") - status_result = subprocess.run(["git", "status", "--porcelain"], cwd=repo_dir, capture_output=True, text=True) - logger.info(f"Git status output: {status_result.stdout}") - if status_result.stderr: - logger.warning(f"Git status stderr: {status_result.stderr}") - if status_result.returncode != 0: - logger.error(f"❌ Git status failed: {status_result.stderr}") - return False - - # 如果有更改,执行commit和push - if status_result.stdout.strip(): - logger.info("✅ Changes detected, proceeding with commit and push") - # 执行git commit - logger.info(f"Executing: git commit -m '{message}'") - commit_result = subprocess.run(["git", "commit", "-m", message], cwd=repo_dir, capture_output=True, text=True) - logger.info(f"Git commit output: {commit_result.stdout}") - if commit_result.stderr: - logger.warning(f"Git commit stderr: {commit_result.stderr}") - if commit_result.returncode != 0: - logger.error(f"❌ Git commit failed: {commit_result.stderr}") - return False - logger.info("✅ Git commit completed successfully") - - # 检查仓库大小 - logger.info("Checking repository size before push") - total_size = 0 - for dirpath, dirnames, filenames in os.walk(repo_dir): - for filename in filenames: - filepath = os.path.join(dirpath, filename) - if not filepath.startswith(os.path.join(repo_dir, '.git')): - total_size += os.path.getsize(filepath) - logger.info(f"Repository size (excluding .git): {total_size / (1024 * 1024):.2f} MB") - - if total_size > 100 * 1024 * 1024: # 100MB - logger.warning(f"Repository is large: {total_size / (1024 * 1024):.2f} MB") - logger.warning("This may cause HTTP 413 errors on push") - - # 设置Git推送缓冲区大小(增加到1GB) - logger.info("Setting Git http.postBuffer to 1GB") - buffer_result = subprocess.run(["git", "config", "http.postBuffer", "1073741824"], cwd=repo_dir, capture_output=True, text=True) - if buffer_result.returncode != 0: - logger.warning(f"Failed to set http.postBuffer: {buffer_result.stderr}") - else: - logger.info("✅ Git http.postBuffer set successfully") - - # 禁用Git压缩 - logger.info("Disabling Git compression") - compression_result = subprocess.run(["git", "config", "core.compression", "0"], cwd=repo_dir, capture_output=True, text=True) - if compression_result.returncode != 0: - logger.warning(f"Failed to set core.compression: {compression_result.stderr}") - else: - logger.info("✅ Git core.compression disabled successfully") - - # 针对大仓库优化的推送命令 - logger.info("Setting additional Git configs for large repositories...") - subprocess.run(["git", "config", "http.postBuffer", "524288000"], cwd=repo_dir) # 500MB buffer - subprocess.run(["git", "config", "pack.windowMemory", "128m"], cwd=repo_dir) # Limit memory usage - subprocess.run(["git", "config", "pack.packSizeLimit", "128m"], cwd=repo_dir) # Limit pack size - - # 执行git push,添加更多优化参数 - logger.info("Executing: git push with optimizations for large repositories") - push_result = subprocess.run([ - "git", "push", - "--verbose", - "-u", "origin", "main", - "--receive-pack='git receive-pack'", # Ensure proper receive pack - "--progress" # Show progress for large pushes - ], cwd=repo_dir, capture_output=True, text=True, timeout=300) # 5 minute timeout - logger.info(f"Git push output: {push_result.stdout}") - if push_result.stderr: - logger.warning(f"Git push stderr: {push_result.stderr}") - if push_result.returncode != 0: - # 检查是否是常见的大文件错误 - error_msg = push_result.stderr.lower() - is_large_file_error = ( - "http 413" in error_msg or - "payload too large" in error_msg or - "unpack failed" in error_msg or - "remote: fatal" in error_msg or - "cannot spawn" in error_msg or - "timeout" in error_msg - ) - - if is_large_file_error: - logger.error(f"❌ Git push failed likely due to repository size: {total_size / (1024 * 1024):.2f} MB") - logger.error(f"Error details: {push_result.stderr}") - logger.error("\n📋 解决方案建议:") - logger.error("1. 检查Gitea服务器配置,增加MAX_UPLOAD_SIZE限制") - logger.error("2. 尝试使用SSH协议进行推送(如果服务器支持)") - logger.error("3. 优化仓库大小,移除不必要的大文件") - logger.error("4. 考虑使用Git LFS(Large File Storage)管理大文件") - - # 尝试使用SSH协议进行推送(如果URL是HTTPS格式) - logger.info("\n🔄 尝试使用SSH协议进行推送...") - try: - # 获取当前远程URL - remote_result = subprocess.run(["git", "remote", "get-url", "origin"], cwd=repo_dir, capture_output=True, text=True, timeout=30) - if remote_result.returncode == 0: - https_url = remote_result.stdout.strip() - # 将HTTPS URL转换为SSH URL - if https_url.startswith("https://"): - ssh_url = https_url.replace("https://", "git@").replace(":", "/") - logger.info(f"Converting HTTPS URL to SSH URL: {ssh_url}") - # 更新远程URL - set_url_result = subprocess.run(["git", "remote", "set-url", "origin", ssh_url], cwd=repo_dir, capture_output=True, text=True, timeout=30) - if set_url_result.returncode == 0: - logger.info("✅ Remote URL updated to SSH format") - # 再次尝试推送,使用更保守的参数 - logger.info("Executing: git push with SSH and conservative parameters") - ssh_push_result = subprocess.run([ - "git", "push", - "--verbose", - "-u", "origin", "main" - ], cwd=repo_dir, capture_output=True, text=True, timeout=600) # 10 minute timeout for SSH - - if ssh_push_result.returncode == 0: - logger.info("✅ Git push completed successfully with SSH") - # 改回HTTPS URL - reset_url_result = subprocess.run(["git", "remote", "set-url", "origin", https_url], cwd=repo_dir, capture_output=True, text=True, timeout=30) - if reset_url_result.returncode != 0: - logger.warning(f"Failed to reset remote URL to HTTPS: {reset_url_result.stderr}") - return True - else: - logger.warning(f"SSH push failed: {ssh_push_result.stderr}") - # 改回HTTPS URL - reset_url_result = subprocess.run(["git", "remote", "set-url", "origin", https_url], cwd=repo_dir, capture_output=True, text=True, timeout=30) - if reset_url_result.returncode != 0: - logger.warning(f"Failed to reset remote URL to HTTPS: {reset_url_result.stderr}") - - # 如果SSH也失败,尝试分阶段推送 - logger.info("\n🔄 尝试分阶段推送...") - return self.push_repository_staged(repo_dir, https_url) - else: - logger.warning(f"Could not get remote URL: {remote_result.stderr}") - except subprocess.TimeoutExpired: - logger.warning("Remote URL command timed out") - except Exception as e: - logger.warning(f"Failed to try SSH push: {str(e)}") - else: - logger.error(f"❌ Git push failed: {push_result.stderr}") - return False - logger.info("✅ Git push completed successfully") - else: - logger.info("ℹ️ No changes to commit") - - logger.info(f"✅ Code pushed successfully for algorithm: {algorithm_id}") - return True - - except Exception as e: - logger.error(f"=== 推送代码失败 ===") - logger.error(f"Error: {str(e)}") - import traceback - logger.error(f"Traceback: {traceback.format_exc()}") - return False - - def pull_from_repository(self, algorithm_id: str) -> bool: - """从Gitea仓库拉取代码 - - Args: - algorithm_id: 算法ID - - Returns: - 是否拉取成功 - """ - try: - repo_dir = f"/tmp/algorithms/{algorithm_id}" - - if not os.path.exists(repo_dir): - logger.error(f"Repository directory not found: {repo_dir}") - return False - - # 执行git pull命令 - result = subprocess.run( - ["git", "pull"], - cwd=repo_dir, - capture_output=True, - text=True - ) - - if result.returncode == 0: - logger.info(f"Code pulled successfully for algorithm: {algorithm_id}") - return True - else: - logger.error(f"Failed to pull code: {result.stderr}") - return False - - except Exception as e: - logger.error(f"Failed to pull code: {str(e)}") - return False - - def push_repository_staged(self, repo_dir: str, origin_url: str) -> bool: - """ - 分阶段推送仓库,用于处理超大仓库 - """ - try: - import subprocess - import os - - logger.info("=== 开始分阶段推送仓库 ===") - logger.info(f"Repository directory: {repo_dir}") - - # 获取所有文件并按类型分组 - all_files = [] - for root, dirs, files in os.walk(repo_dir): - # 跳过 .git 目录 - if '.git' in root: - continue - for file in files: - file_path = os.path.relpath(os.path.join(root, file), repo_dir) - if file_path.startswith('.git'): - continue - all_files.append(file_path) - - logger.info(f"Total files to stage: {len(all_files)}") - - # 按扩展名分类文件,优先推送小文件 - def get_file_size(file_path): - try: - return os.path.getsize(os.path.join(repo_dir, file_path)) - except: - return 0 - - # 按文件大小排序(从小到大) - sorted_files = sorted(all_files, key=get_file_size) - - # 分批处理,每批最多50个文件或不超过50MB - batch_size_limit = 50 - batch_size_bytes = 50 * 1024 * 1024 # 50MB - - current_batch = [] - current_batch_size = 0 - batch_number = 1 - - for file_path in sorted_files: - file_full_path = os.path.join(repo_dir, file_path) - file_size = get_file_size(file_path) - - # 如果单个文件太大,单独处理 - if file_size > batch_size_bytes: - logger.info(f"Handling large file separately: {file_path} ({file_size / (1024*1024):.2f}MB)") - # 单独添加和推送这个大文件 - add_result = subprocess.run(["git", "add", file_path], cwd=repo_dir, capture_output=True, text=True) - if add_result.returncode != 0: - logger.error(f"Failed to add large file {file_path}: {add_result.stderr}") - continue - - # 检查是否有暂存的更改 - status_result = subprocess.run(["git", "status", "--porcelain"], cwd=repo_dir, capture_output=True, text=True) - if status_result.stdout.strip(): - # 创建专门的提交 - commit_msg = f"Add large file: {file_path}" - commit_result = subprocess.run(["git", "commit", "-m", commit_msg], cwd=repo_dir, capture_output=True, text=True) - if commit_result.returncode == 0: - logger.info(f"Committed large file: {file_path}") - - # 推送这个提交 - push_result = subprocess.run([ - "git", "push", "--verbose", "origin", "main" - ], cwd=repo_dir, capture_output=True, text=True, timeout=300) - - if push_result.returncode != 0: - logger.warning(f"Push failed for large file {file_path}: {push_result.stderr}") - # 如果推送失败,尝试重置这个文件的暂存状态 - subprocess.run(["git", "reset", "HEAD", file_path], cwd=repo_dir, capture_output=True, text=True) - else: - logger.info(f"Successfully pushed large file: {file_path}") - else: - logger.error(f"Failed to commit large file {file_path}: {commit_result.stderr}") - else: - # 尝试添加到当前批次 - if (len(current_batch) >= batch_size_limit or - current_batch_size + file_size > batch_size_bytes): - # 推送当前批次 - if current_batch: - logger.info(f"Pushing batch {batch_number} with {len(current_batch)} files...") - success = self.push_batch(repo_dir, current_batch, batch_number, origin_url) - if not success: - logger.error(f"Failed to push batch {batch_number}") - return False - batch_number += 1 - current_batch = [] - current_batch_size = 0 - - current_batch.append(file_path) - current_batch_size += file_size - - # 推送最后一批 - if current_batch: - logger.info(f"Pushing final batch {batch_number} with {len(current_batch)} files...") - success = self.push_batch(repo_dir, current_batch, batch_number, origin_url) - if not success: - logger.error(f"Failed to push final batch {batch_number}") - return False - - logger.info("✅ 分阶段推送完成") - return True - - except Exception as e: - logger.error(f"❌ 分阶段推送失败: {str(e)}") - import traceback - logger.error(f"Traceback: {traceback.format_exc()}") - return False - - def push_batch(self, repo_dir: str, file_batch: list, batch_num: int, origin_url: str) -> bool: - """ - 推送文件批次 - """ - try: - import subprocess - - logger.info(f"Processing batch {batch_num}: {len(file_batch)} files") - - # 添加批次中的文件 - for file_path in file_batch: - add_result = subprocess.run(["git", "add", file_path], cwd=repo_dir, capture_output=True, text=True) - if add_result.returncode != 0: - logger.error(f"Failed to add file {file_path}: {add_result.stderr}") - return False - - # 检查是否有更改需要提交 - status_result = subprocess.run(["git", "status", "--porcelain"], cwd=repo_dir, capture_output=True, text=True) - if not status_result.stdout.strip(): - logger.info(f"No changes in batch {batch_num}") - return True - - # 提交批次 - commit_result = subprocess.run([ - "git", "commit", "-m", f"Batch {batch_num}: Add {len(file_batch)} files" - ], cwd=repo_dir, capture_output=True, text=True) - - if commit_result.returncode != 0: - logger.warning(f"Commit failed or no changes for batch {batch_num}: {commit_result.stderr}") - # 即使没有更改,也可能正常(比如文件没变) - - # 推送批次 - push_result = subprocess.run([ - "git", "push", "--verbose", "origin", "main" - ], cwd=repo_dir, capture_output=True, text=True, timeout=300) - - if push_result.returncode == 0: - logger.info(f"✅ Batch {batch_num} pushed successfully") - return True - else: - logger.error(f"❌ Batch {batch_num} push failed: {push_result.stderr}") - return False - - except subprocess.TimeoutExpired: - logger.error(f"❌ Batch {batch_num} push timed out") - return False - except Exception as e: - logger.error(f"❌ Batch {batch_num} push failed with error: {str(e)}") - return False - - def get_repository_info(self, repo_owner: str, repo_name: str) -> Optional[Dict[str, Any]]: - """获取仓库信息 - - Args: - repo_owner: 仓库所有者 - repo_name: 仓库名称 - - Returns: - 仓库信息 - """ - if not self.client: - return None - - return self.client.get_repository(repo_owner, repo_name) - - def list_repositories(self, owner: Optional[str] = None) -> Optional[List[Dict[str, Any]]]: - """列出仓库 - - Args: - owner: 所有者(用户或组织) - - Returns: - 仓库列表 - """ - if not self.client: - return None - - target_owner = owner or self.config.get('default_owner') - if not target_owner: - return None - - return self.client.list_repositories(target_owner) - - def register_algorithm_from_repo(self, repo_owner: str, repo_name: str, algorithm_id: str) -> bool: - """从仓库注册算法服务 - - Args: - repo_owner: 仓库所有者 - repo_name: 仓库名称 - algorithm_id: 算法ID - - Returns: - 是否注册成功 - """ - try: - # 这里应该实现从仓库注册算法服务的逻辑 - # 1. 克隆仓库 - # 2. 扫描仓库中的算法代码 - # 3. 注册算法服务 - - logger.info(f"Algorithm registered from repo: {repo_owner}/{repo_name}") - return True - - except Exception as e: - logger.error(f"Failed to register algorithm from repo: {str(e)}") - return False - - - - # 递归遍历目录中的所有文件 - for root, dirs, files in os.walk(repo_dir): - # 跳过 .git 目录 - if '.git' in root: - continue - - for file in files: - file_path = os.path.relpath(os.path.join(root, file), repo_dir) - if file_path.startswith('.git'): - continue - - full_file_path = os.path.join(root, file) - - # 读取文件内容并进行base64编码 - try: - with open(full_file_path, 'rb') as f: - file_content = f.read() - encoded_content = base64.b64encode(file_content).decode('utf-8') - - # 使用Gitea API创建或更新文件 - if self.client: - # 移除开头的./,如果有的话 - clean_path = file_path.lstrip('./\\') - result = self.client.create_file( - self.config["default_owner"], - algorithm_id, - clean_path, - encoded_content, - f"{message} - Upload {clean_path}" - ) - - if result: - logger.info(f"✅ File uploaded via API: {clean_path}") - else: - logger.error(f"❌ Failed to upload file via API: {clean_path}") - return False - else: - logger.error("❌ Gitea client not initialized") - return False - except Exception as e: - logger.error(f"❌ Error processing file {file_path}: {str(e)}") - return False - - logger.info(f"✅ All files uploaded successfully via API for algorithm: {algorithm_id}") - return True - - except Exception as e: - logger.error(f"❌ Failed to upload files via API: {str(e)}") - import traceback - logger.error(f"Traceback: {traceback.format_exc()}") - return False - - -# 全局Gitea服务实例 -gitea_service = GiteaService() diff --git a/backend/app/models/models.py b/backend/app/models/models.py index 8f40f19..4a0c2ae 100644 --- a/backend/app/models/models.py +++ b/backend/app/models/models.py @@ -140,18 +140,6 @@ class AlgorithmRepository(Base): algorithm = relationship("Algorithm", back_populates="repository", uselist=False) -class ServiceGroup(Base): - """服务分组模型""" - __tablename__ = "service_groups" - - id = Column(String, primary_key=True, index=True) - name = Column(String, nullable=False, unique=True, index=True) # 分组名称 - description = Column(Text, default="") # 分组描述 - status = Column(String, default="active", index=True) # 状态 - created_at = Column(DateTime(timezone=True), server_default=func.now()) - updated_at = Column(DateTime(timezone=True), onupdate=func.now()) - - class AlgorithmService(Base): """算法服务模型""" __tablename__ = "algorithm_services" diff --git a/backend/app/routes/services.py b/backend/app/routes/services.py index 72d8022..da7d570 100644 --- a/backend/app/routes/services.py +++ b/backend/app/routes/services.py @@ -5,10 +5,12 @@ from typing import List, Dict, Any, Optional from pydantic import BaseModel import uuid import os +import logging from app.config.settings import settings -from app.models.models import AlgorithmService, ServiceGroup, AlgorithmRepository +from app.models.models import AlgorithmService, AlgorithmRepository, Algorithm, AlgorithmVersion from app.models.database import SessionLocal +from app.models.api import ApiEndpoint from app.routes.user import get_current_active_user from app.schemas.user import UserResponse from app.services.project_analyzer import ProjectAnalyzer @@ -17,6 +19,7 @@ from app.services.service_orchestrator import ServiceOrchestrator from app.gitea.service import gitea_service router = APIRouter(prefix="/services", tags=["services"]) +logger = logging.getLogger(__name__) class RegisterServiceRequest(BaseModel): @@ -28,7 +31,7 @@ class RegisterServiceRequest(BaseModel): tech_category: str = "computer_vision" output_type: str = "image" service_type: str = "http" - host: str = "0.0.0.0" + host: str = "localhost" port: int = 8000 timeout: int = 30 health_check_path: str = "/health" @@ -89,34 +92,6 @@ class RepositoryAlgorithmsResponse(BaseModel): algorithms: List[Dict[str, Any]] -class ServiceGroupRequest(BaseModel): - """服务分组请求""" - name: str - description: str = "" - - -class ServiceGroupResponse(BaseModel): - """服务分组响应""" - id: str - name: str - description: str - status: str - created_at: str - updated_at: str - - -class ServiceGroupListResponse(BaseModel): - """服务分组列表响应""" - success: bool - groups: List[ServiceGroupResponse] - - -class ServiceGroupDetailResponse(BaseModel): - """服务分组详情响应""" - success: bool - group: ServiceGroupResponse - - class BatchOperationRequest(BaseModel): """批量操作请求""" service_ids: List[str] @@ -228,7 +203,62 @@ async def register_service( db.commit() db.refresh(new_service) - # 6. 返回响应 + # 7. 自动创建API端点 + try: + algorithm = db.query(Algorithm).filter(Algorithm.name == repo.name).first() + if not algorithm: + algorithm = Algorithm( + id=str(uuid.uuid4()), + name=repo.name, + description=request.description or f"算法服务: {request.name}", + type=request.tech_category, + tech_category=request.tech_category, + output_type=request.output_type + ) + db.add(algorithm) + db.commit() + db.refresh(algorithm) + + version = db.query(AlgorithmVersion).filter( + AlgorithmVersion.algorithm_id == algorithm.id, + AlgorithmVersion.version == request.version + ).first() + if not version: + version = AlgorithmVersion( + id=str(uuid.uuid4()), + algorithm_id=algorithm.id, + version=request.version, + url=request.service_url if hasattr(request, 'service_url') else "" + ) + db.add(version) + db.commit() + db.refresh(version) + + api_endpoint = ApiEndpoint( + id=str(uuid.uuid4()), + name=request.name, + description=request.description or f"{request.name} API端点", + path=f"/api/v1/algorithms/{algorithm.id}/call", + method="POST", + algorithm_id=algorithm.id, + version_id=version.id, + service_id=service_id, + requires_auth=False, + is_public=True, + status="active", + config={ + "service_url": deploy_result["api_url"], + "timeout": request.timeout, + "health_check_path": request.health_check_path + } + ) + db.add(api_endpoint) + db.commit() + logger.info(f"API端点创建成功: {api_endpoint.name}, 路径: {api_endpoint.path}") + except Exception as e: + logger.error(f"创建API端点失败: {str(e)}") + + # 8. 返回响应 return { "success": True, "message": "服务注册成功", @@ -537,6 +567,12 @@ async def delete_service( if not service: raise HTTPException(status_code=404, detail="Service not found") + # 先删除关联的API端点 + db.query(ApiEndpoint).filter(ApiEndpoint.service_id == service_id).delete() + + # 获取算法名称,用于后续删除算法记录 + algorithm_name = service.algorithm_name + # 获取容器ID和镜像名称 container_id = service.config.get("container_id") image_name = f"algorithm-service-{service_id}:{service.version}" @@ -549,6 +585,17 @@ async def delete_service( # 删除数据库记录 db.delete(service) + + # 删除关联的算法记录(通过算法名称匹配) + if algorithm_name: + algorithm = db.query(Algorithm).filter(Algorithm.name == algorithm_name).first() + if algorithm: + # 先删除关联的算法版本 + db.query(AlgorithmVersion).filter(AlgorithmVersion.algorithm_id == algorithm.id).delete() + # 再删除算法记录 + db.query(AlgorithmCall).filter(AlgorithmCall.algorithm_id == algorithm.id).delete() + db.delete(algorithm) + db.commit() # 返回响应 @@ -677,202 +724,6 @@ async def get_repository_algorithms( raise HTTPException(status_code=500, detail=str(e)) -# 服务分组管理API - -@router.post("/groups", status_code=status.HTTP_201_CREATED) -async def create_service_group( - request: ServiceGroupRequest, - current_user: UserResponse = Depends(get_current_active_user) -): - """创建服务分组""" - # 检查用户权限 - if current_user.role_name != "admin": - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # 创建数据库会话 - db = SessionLocal() - try: - # 生成唯一ID - group_id = str(uuid.uuid4()) - - # 创建分组实例 - group = ServiceGroup( - id=group_id, - name=request.name, - description=request.description - ) - - # 保存到数据库 - db.add(group) - db.commit() - db.refresh(group) - - return { - "success": True, - "message": "服务分组创建成功", - "group": { - "id": group.id, - "name": group.name, - "description": group.description, - "status": group.status, - "created_at": group.created_at.isoformat(), - "updated_at": group.updated_at.isoformat() - } - } - finally: - db.close() - - -@router.get("/groups", response_model=ServiceGroupListResponse) -async def list_service_groups( - current_user: UserResponse = Depends(get_current_active_user) -): - """获取服务分组列表""" - # 检查用户权限 - if current_user.role_name != "admin": - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # 创建数据库会话 - db = SessionLocal() - try: - # 查询分组列表 - groups = db.query(ServiceGroup).all() - - # 转换为响应格式 - group_list = [] - for group in groups: - group_list.append(ServiceGroupResponse( - id=group.id, - name=group.name, - description=group.description, - status=group.status, - created_at=group.created_at.isoformat(), - updated_at=group.updated_at.isoformat() - )) - - return ServiceGroupListResponse( - success=True, - groups=group_list - ) - finally: - db.close() - - -@router.get("/groups/{group_id}", response_model=ServiceGroupDetailResponse) -async def get_service_group( - group_id: str, - current_user: UserResponse = Depends(get_current_active_user) -): - """获取服务分组详情""" - # 检查用户权限 - if current_user.role_name != "admin": - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # 创建数据库会话 - db = SessionLocal() - try: - # 查询分组 - group = db.query(ServiceGroup).filter(ServiceGroup.id == group_id).first() - - if not group: - raise HTTPException(status_code=404, detail="Service group not found") - - return ServiceGroupDetailResponse( - success=True, - group=ServiceGroupResponse( - id=group.id, - name=group.name, - description=group.description, - status=group.status, - created_at=group.created_at.isoformat(), - updated_at=group.updated_at.isoformat() - ) - ) - finally: - db.close() - - -@router.put("/groups/{group_id}") -async def update_service_group( - group_id: str, - request: ServiceGroupRequest, - current_user: UserResponse = Depends(get_current_active_user) -): - """更新服务分组""" - # 检查用户权限 - if current_user.role_name != "admin": - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # 创建数据库会话 - db = SessionLocal() - try: - # 查询分组 - group = db.query(ServiceGroup).filter(ServiceGroup.id == group_id).first() - - if not group: - raise HTTPException(status_code=404, detail="Service group not found") - - # 更新分组信息 - group.name = request.name - group.description = request.description - - # 保存到数据库 - db.commit() - db.refresh(group) - - return { - "success": True, - "message": "服务分组更新成功", - "group": { - "id": group.id, - "name": group.name, - "description": group.description, - "status": group.status, - "created_at": group.created_at.isoformat(), - "updated_at": group.updated_at.isoformat() - } - } - finally: - db.close() - - -@router.delete("/groups/{group_id}") -async def delete_service_group( - group_id: str, - current_user: UserResponse = Depends(get_current_active_user) -): - """删除服务分组""" - # 检查用户权限 - if current_user.role_name != "admin": - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # 创建数据库会话 - db = SessionLocal() - try: - # 查询分组 - group = db.query(ServiceGroup).filter(ServiceGroup.id == group_id).first() - - if not group: - raise HTTPException(status_code=404, detail="Service group not found") - - # 检查分组是否有服务 - services_count = db.query(AlgorithmService).filter(AlgorithmService.group_id == group_id).count() - if services_count > 0: - raise HTTPException(status_code=400, detail=f"该分组下还有{services_count}个服务,无法删除") - - # 删除分组 - db.delete(group) - db.commit() - - return { - "success": True, - "message": "服务分组删除成功", - "group_id": group_id - } - finally: - db.close() - - # 批量服务操作API @router.post("/batch/start") @@ -1230,3 +1081,85 @@ async def call_service( finally: db.close() + + +@router.post("/sync-api-endpoints") +async def sync_api_endpoints( + current_user: UserResponse = Depends(get_current_active_user) +): + """同步所有服务到API端点""" + if current_user.role_name != "admin": + raise HTTPException(status_code=403, detail="权限不足") + + db = SessionLocal() + try: + services = db.query(AlgorithmService).all() + synced_count = 0 + + for service in services: + existing_endpoint = db.query(ApiEndpoint).filter( + (ApiEndpoint.service_id == service.service_id) | + (ApiEndpoint.path == f"/api/v1/algorithms/{service.algorithm_name}/call") + ).first() + + if existing_endpoint: + continue + + algorithm = db.query(Algorithm).filter(Algorithm.name == service.algorithm_name).first() + if not algorithm: + algorithm = Algorithm( + id=str(uuid.uuid4()), + name=service.algorithm_name, + description=f"算法服务: {service.name}", + type=service.tech_category or "computer_vision", + tech_category=service.tech_category or "computer_vision", + output_type=service.output_type or "image" + ) + db.add(algorithm) + db.commit() + db.refresh(algorithm) + + version = db.query(AlgorithmVersion).filter( + AlgorithmVersion.algorithm_id == algorithm.id + ).first() + if not version: + version = AlgorithmVersion( + id=str(uuid.uuid4()), + algorithm_id=algorithm.id, + version=service.version or "1.0.0", + url=service.api_url + ) + db.add(version) + db.commit() + db.refresh(version) + + api_endpoint = ApiEndpoint( + id=str(uuid.uuid4()), + name=service.name, + description=f"{service.name} API端点", + path=f"/api/v1/algorithms/{algorithm.id}/call/{service.service_id[:8]}", + method="POST", + algorithm_id=algorithm.id, + version_id=version.id, + service_id=service.service_id, + requires_auth=False, + is_public=True, + status=service.status or "active", + config={ + "service_url": service.api_url, + "timeout": service.config.get("timeout") if service.config else 30 + } + ) + db.add(api_endpoint) + synced_count += 1 + + db.commit() + return { + "success": True, + "message": f"同步完成,共同步 {synced_count} 个API端点" + } + except Exception as e: + logger.error(f"同步API端点失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"同步失败: {str(e)}") + finally: + db.close() diff --git a/backend/app/utils/file.py b/backend/app/utils/file.py index 7bdb27c..bb78659 100644 --- a/backend/app/utils/file.py +++ b/backend/app/utils/file.py @@ -4,15 +4,19 @@ from typing import Optional, Tuple import io import os import logging +import shutil from app.config.settings import settings class MinioClient: - """MinIO客户端类""" + """MinIO客户端类,支持本地存储作为备选""" def __init__(self): """初始化MinIO客户端""" + self.local_storage_path = "data_storage/local_uploads" + os.makedirs(self.local_storage_path, exist_ok=True) + try: self.client = Minio( settings.MINIO_ENDPOINT, @@ -21,16 +25,24 @@ class MinioClient: secure=settings.MINIO_SECURE ) self.bucket_name = settings.MINIO_BUCKET_NAME - self.is_connected = True # 先设置为True,这样在调用其他方法时不会报错 + + # 测试真实连接 + self.client.list_buckets() + self.is_connected = True + logging.info("MinIO connected successfully") # 确保存储桶存在 self._ensure_bucket_exists() except Exception as e: - logging.warning(f"Failed to connect to MinIO: {e}. Running in offline mode.") + logging.warning(f"Failed to connect to MinIO: {e}. Using local storage.") self.client = None self.bucket_name = settings.MINIO_BUCKET_NAME self.is_connected = False + def _get_local_path(self, object_name: str) -> str: + """获取本地存储路径""" + return os.path.join(self.local_storage_path, object_name) + def _ensure_bucket_exists(self): """确保存储桶存在""" if not self.is_connected: @@ -60,24 +72,32 @@ class MinioClient: return False def upload_from_bytes(self, data: bytes, object_name: str) -> bool: - """从字节数据上传文件""" - if not self.is_connected: - logging.warning("MinIO is not connected. Upload skipped.") - return False + """从字节数据上传文件,优先使用MinIO,失败则使用本地存储""" + if self.is_connected: + try: + import io + file_obj = io.BytesIO(data) + self.client.put_object( + self.bucket_name, + object_name, + file_obj, + length=len(data), + part_size=10*1024*1024 + ) + return True + except S3Error as e: + logging.warning(f"MinIO upload error: {e}, falling back to local storage") + # 使用本地存储作为备选 try: - import io - file_obj = io.BytesIO(data) - self.client.put_object( - self.bucket_name, - object_name, - file_obj, - length=len(data), - part_size=10*1024*1024 - ) + local_path = self._get_local_path(object_name) + os.makedirs(os.path.dirname(local_path), exist_ok=True) + with open(local_path, 'wb') as f: + f.write(data) + logging.info(f"File saved to local storage: {local_path}") return True - except S3Error as e: - logging.warning(f"MinIO upload error: {e}") + except Exception as e: + logging.error(f"Local storage save error: {e}") return False def upload_fileobj(self, file_obj: io.BytesIO, object_name: str, content_type: str = "application/octet-stream") -> bool: @@ -118,38 +138,54 @@ class MinioClient: return False def get_object(self, object_name: str) -> Optional[bytes]: - """获取对象内容""" - if not self.is_connected: - logging.warning("MinIO is not connected. Get object skipped.") - return None + """获取对象内容,优先使用MinIO,失败则使用本地存储""" + if self.is_connected: + try: + response = self.client.get_object( + self.bucket_name, + object_name + ) + data = response.read() + response.close() + response.release_conn() + return data + except S3Error as e: + logging.warning(f"MinIO get object error: {e}, falling back to local storage") + # 使用本地存储作为备选 try: - response = self.client.get_object( - self.bucket_name, - object_name - ) - data = response.read() - response.close() - response.release_conn() - return data - except S3Error as e: - logging.warning(f"MinIO get object error: {e}") + local_path = self._get_local_path(object_name) + if os.path.exists(local_path): + with open(local_path, 'rb') as f: + return f.read() + else: + logging.warning(f"File not found in local storage: {local_path}") + return None + except Exception as e: + logging.error(f"Local storage get error: {e}") return None def delete_object(self, object_name: str) -> bool: - """删除对象""" - if not self.is_connected: - logging.warning("MinIO is not connected. Delete object skipped.") - return False + """删除对象,优先使用MinIO,失败则使用本地存储""" + if self.is_connected: + try: + self.client.remove_object( + self.bucket_name, + object_name + ) + return True + except S3Error as e: + logging.warning(f"MinIO delete error: {e}") + # 使用本地存储作为备选 try: - self.client.remove_object( - self.bucket_name, - object_name - ) - return True - except S3Error as e: - logging.warning(f"MinIO delete error: {e}") + local_path = self._get_local_path(object_name) + if os.path.exists(local_path): + os.remove(local_path) + return True + return False + except Exception as e: + logging.error(f"Local storage delete error: {e}") return False def list_objects(self, prefix: str = "") -> list: diff --git a/backend/logs/algorithm_showcase.log b/backend/logs/algorithm_showcase.log deleted file mode 100644 index e69de29..0000000 diff --git a/backend/uvicorn.log b/backend/uvicorn.log deleted file mode 100644 index 419da8e..0000000 --- a/backend/uvicorn.log +++ /dev/null @@ -1,4266 +0,0 @@ -INFO: Will watch for changes in these directories: ['/Users/duguoyou/MLFlow/algorithm-showcase/backend'] -INFO: Uvicorn running on http://0.0.0.0:8001 (Press CTRL+C to quit) -INFO: Started reloader process [3857] using WatchFiles -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [3862] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [3862] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [3997] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:60457 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:60462 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:60474 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:60476 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:60479 - "DELETE /api/v1/repositories/d9088318-70cc-4589-8071-4f6df6b4ebcc HTTP/1.1" 200 OK -INFO: 127.0.0.1:60481 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:60572 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:60574 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:60647 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:60651 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:60661 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:60666 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:60670 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:60674 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:60682 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Repository is large: 529.00 MB -WARNING:app.gitea.service:This may cause HTTP 413 errors on push -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 -send-pack: unexpected disconnect while reading sideband packet -Writing objects: 93% (31/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 96% (32/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 100% (33/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 35.11 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -fatal: the remote end hung up unexpectedly -Everything up-to-date - -ERROR:app.gitea.service:❌ Git push failed likely due to repository size: 529.00 MB -ERROR:app.gitea.service:Error details: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 -send-pack: unexpected disconnect while reading sideband packet -Writing objects: 93% (31/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 96% (32/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 100% (33/33), 500.07 MiB | 33.63 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 35.11 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -fatal: the remote end hung up unexpectedly -Everything up-to-date - -ERROR:app.gitea.service: -📋 解决方案建议: -ERROR:app.gitea.service:1. 检查Gitea服务器配置,增加MAX_UPLOAD_SIZE限制 -ERROR:app.gitea.service:2. 尝试使用SSH协议进行推送(如果服务器支持) -ERROR:app.gitea.service:3. 优化仓库大小,移除不必要的大文件 -ERROR:app.gitea.service:4. 考虑使用Git LFS(Large File Storage)管理大文件 -WARNING:app.gitea.service:SSH push failed: Pushing to git@26ccc228c6624f98d6dd629365be052e161b0da3@gitea.swiftsnake.cn/yipai-tech/AItst.git -fatal: 'git@26ccc228c6624f98d6dd629365be052e161b0da3@gitea.swiftsnake.cn/yipai-tech/AItst.git' does not appear to be a git repository -fatal: Could not read from remote repository. - -Please make sure you have the correct access rights -and the repository exists. - -INFO: 127.0.0.1:60690 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:60825 - "GET /api/v1/repositories HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [3997] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [4282] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:63207 - "DELETE /api/v1/repositories/f5228841-10e4-4ddb-8840-7f21ce8f0d66 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63212 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63437 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63439 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63526 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:63530 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:63540 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:63545 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:63549 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:63553 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:63561 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -ERROR:app.gitea.service:=== 推送代码失败 === -ERROR:app.gitea.service:Error: cannot access local variable 'exclude_patterns' where it is not associated with a value -ERROR:app.gitea.service:Traceback: Traceback (most recent call last): - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/service.py", line 397, in push_to_repository - should_skip = any(re.search(pattern, root) for pattern in exclude_patterns) - ^^^^^^^^^^^^^^^^ -UnboundLocalError: cannot access local variable 'exclude_patterns' where it is not associated with a value - -INFO: 127.0.0.1:63569 - "POST /api/v1/gitea/repos/push HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:63622 - "GET /api/v1/repositories HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [4282] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [4517] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:49454 - "DELETE /api/v1/repositories/9a6775fc-6e6b-40b3-8dc2-5096b5a772f1 HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:49647 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:49655 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:49703 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49708 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:49729 - "DELETE /api/v1/repositories/9a6775fc-6e6b-40b3-8dc2-5096b5a772f1 HTTP/1.1" 200 OK -INFO: 127.0.0.1:49733 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49817 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:49821 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:49831 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:49836 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:49840 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:49848 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:49852 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Repository is large: 529.00 MB -WARNING:app.gitea.service:This may cause HTTP 413 errors on push -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 -Writing objects: 93% (31/33), 500.07 MiB | 36.85 MiB/s -send-pack: unexpected disconnect while reading sideband packet -Writing objects: 96% (32/33), 500.07 MiB | 36.85 MiB/s -Writing objects: 100% (33/33), 500.07 MiB | 36.85 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 38.44 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -fatal: the remote end hung up unexpectedly -Everything up-to-date - -ERROR:app.gitea.service:❌ Git push failed likely due to repository size: 529.00 MB -ERROR:app.gitea.service:Error details: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 -Writing objects: 93% (31/33), 500.07 MiB | 36.85 MiB/s -send-pack: unexpected disconnect while reading sideband packet -Writing objects: 96% (32/33), 500.07 MiB | 36.85 MiB/s -Writing objects: 100% (33/33), 500.07 MiB | 36.85 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 38.44 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -fatal: the remote end hung up unexpectedly -Everything up-to-date - -ERROR:app.gitea.service: -📋 解决方案建议: -ERROR:app.gitea.service:1. 检查Gitea服务器配置,增加MAX_UPLOAD_SIZE限制 -ERROR:app.gitea.service:2. 尝试使用SSH协议进行推送(如果服务器支持) -ERROR:app.gitea.service:3. 优化仓库大小,移除不必要的大文件 -ERROR:app.gitea.service:4. 考虑使用Git LFS(Large File Storage)管理大文件 -WARNING:app.gitea.service:SSH push failed: Pushing to git@26ccc228c6624f98d6dd629365be052e161b0da3@gitea.swiftsnake.cn/yipai-tech/AItst.git -fatal: 'git@26ccc228c6624f98d6dd629365be052e161b0da3@gitea.swiftsnake.cn/yipai-tech/AItst.git' does not appear to be a git repository -fatal: Could not read from remote repository. - -Please make sure you have the correct access rights -and the repository exists. - -INFO: 127.0.0.1:49860 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:49982 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:64641 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:64651 - "GET /api/v1/gitea/config HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:64713 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:64717 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:64754 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:64758 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:64820 - "DELETE /api/v1/repositories/2988865e-ebf6-40f0-a617-17bed4d9b2d9 HTTP/1.1" 200 OK -INFO: 127.0.0.1:64824 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:64902 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:64906 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:64913 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:64922 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:64926 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:64930 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:64934 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Repository is large: 529.00 MB -WARNING:app.gitea.service:This may cause HTTP 413 errors on push -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -Writing objects: 93% (31/33), 500.07 MiB | 8.81 MiB/s -Writing objects: 93% (31/33), 506.19 MiB | 8.84 MiB/s -Writing objects: 93% (31/33), 517.88 MiB | 8.89 MiB/s -Writing objects: 96% (32/33), 523.56 MiB | 8.91 MiB/s -Writing objects: 100% (33/33), 523.56 MiB | 8.91 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 8.91 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -remote: . Processing 1 references -remote: Processed 1 references in total -To https://gitea.swiftsnake.cn/yipai-tech/AItst.git - dbb39f6..693af4b main -> main -updating local tracking ref 'refs/remotes/origin/main' - -INFO: 127.0.0.1:64946 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:65348 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49884 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49886 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57195 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57199 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57216 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57403 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57405 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57420 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57430 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 214, in update_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 85, in save_obj - _emit_update_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 912, in _emit_update_statements - c = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - -[SQL: UPDATE algorithm_repositories SET algorithm_id=%(algorithm_id)s, description=%(description)s, repo_url=%(repo_url)s, updated_at=now() WHERE algorithm_repositories.id = %(algorithm_repositories_id)s] -[parameters: {'algorithm_id': 'AIAItst', 'description': 'tstsss', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AIAItst.git', 'algorithm_repositories_id': '36f2383c-f0e2-4a0d-a893-42288baf1436'}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -INFO: 127.0.0.1:57434 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 214, in update_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 85, in save_obj - _emit_update_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 912, in _emit_update_statements - c = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - -[SQL: UPDATE algorithm_repositories SET algorithm_id=%(algorithm_id)s, description=%(description)s, repo_url=%(repo_url)s, updated_at=now() WHERE algorithm_repositories.id = %(algorithm_repositories_id)s] -[parameters: {'algorithm_id': 'AIAItst', 'description': 'tstsss', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AIAItst.git', 'algorithm_repositories_id': '36f2383c-f0e2-4a0d-a893-42288baf1436'}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -INFO: 127.0.0.1:57589 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57593 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58065 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58067 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58080 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58082 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58147 - "GET / HTTP/1.1" 200 OK -INFO: 127.0.0.1:58147 - "GET /%40vite/client HTTP/1.1" 200 OK -INFO: 127.0.0.1:60585 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:60587 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:60589 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60595 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 214, in update_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 85, in save_obj - _emit_update_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 912, in _emit_update_statements - c = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AIAItst) is not present in table "algorithms". - -[SQL: UPDATE algorithm_repositories SET algorithm_id=%(algorithm_id)s, description=%(description)s, repo_url=%(repo_url)s, updated_at=now() WHERE algorithm_repositories.id = %(algorithm_repositories_id)s] -[parameters: {'algorithm_id': 'AIAItst', 'description': 'tst11', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AIAItst.git', 'algorithm_repositories_id': '36f2383c-f0e2-4a0d-a893-42288baf1436'}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -INFO: 127.0.0.1:60874 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:60960 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/gitea/client.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [4517] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [11127] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [11127] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [11307] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/routes/gitea.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [11307] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [12119] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:63566 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63569 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63571 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63576 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63593 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63595 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63618 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:63621 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:63625 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63628 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63634 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:49451 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49454 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:49461 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:49463 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:49465 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:49472 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to update repository info: Unsupported HTTP method: PATCH -ERROR:app.gitea.service:Traceback: Traceback (most recent call last): - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/service.py", line 1172, in update_repository_info - updated_repo = self.client.update_repository( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/client.py", line 213, in update_repository - return self._request("PATCH", f"repos/{owner}/{repo}", data) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/client.py", line 52, in _request - raise ValueError(f"Unsupported HTTP method: {method}") -ValueError: Unsupported HTTP method: PATCH - -INFO: 127.0.0.1:49475 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:49478 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:52784 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:52787 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:52796 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:52798 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:52800 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:52806 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to update repository info: Unsupported HTTP method: PATCH -ERROR:app.gitea.service:Traceback: Traceback (most recent call last): - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/service.py", line 1172, in update_repository_info - updated_repo = self.client.update_repository( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/client.py", line 213, in update_repository - return self._request("PATCH", f"repos/{owner}/{repo}", data) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/gitea/client.py", line 52, in _request - raise ValueError(f"Unsupported HTTP method: {method}") -ValueError: Unsupported HTTP method: PATCH - -INFO: 127.0.0.1:52809 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:52812 - "GET /api/v1/repositories HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/gitea/client.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [12119] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [16798] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:54278 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54281 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:54283 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54291 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54294 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:54298 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54315 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54675 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:54679 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56102 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56105 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56111 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56113 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56116 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56120 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56123 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:56127 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56630 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56632 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56634 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56643 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:56646 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:56650 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56940 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57299 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57302 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57378 - "GET /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57382 - "PUT /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57385 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:57389 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57482 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57484 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57654 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57656 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57740 - "DELETE /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:57751 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:57754 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:57759 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57762 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57767 - "DELETE /api/v1/repositories/36f2383c-f0e2-4a0d-a893-42288baf1436 HTTP/1.1" 200 OK -INFO: 127.0.0.1:57770 - "GET /api/v1/repositories HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/gitea/client.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [16798] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [28094] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [28094] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [28374] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/routes/repositories.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [28374] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [28646] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/routes/repositories.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [28646] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [28776] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/routes/repositories.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [28776] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [30329] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/gitea/client.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [30329] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [33105] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:58309 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:58312 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:58316 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58320 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58323 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58326 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58329 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58512 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:58515 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:58520 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:58524 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst1.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 5, done. -Counting objects: 20% (1/5) -Counting objects: 40% (2/5) -Counting objects: 60% (3/5) -Counting objects: 80% (4/5) -Counting objects: 100% (5/5) -Counting objects: 100% (5/5), done. -Delta compression using up to 16 threads -Compressing objects: 33% (1/3) -Compressing objects: 66% (2/3) -Compressing objects: 100% (3/3) -Compressing objects: 100% (3/3), done. -Writing objects: 25% (1/4) -Writing objects: 50% (2/4) -Writing objects: 75% (3/4) -Writing objects: 100% (4/4) -Writing objects: 100% (4/4), 10.12 MiB | 246.62 MiB/s, done. -Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 -POST git-receive-pack (10606682 bytes) -remote: . Processing 1 references -remote: Processed 1 references in total -To https://gitea.swiftsnake.cn/yipai-tech/AItst1.git - 66ed27d..164ebab main -> main -updating local tracking ref 'refs/remotes/origin/main' - -INFO: 127.0.0.1:58527 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:58535 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58846 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:58849 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:58852 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58855 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58885 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58887 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58889 - "GET /api/v1/repositories/f33bf23a-bed7-41d9-ad8c-7a45bd5e2b33 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58891 - "PUT /api/v1/repositories/f33bf23a-bed7-41d9-ad8c-7a45bd5e2b33 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58894 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:58898 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58909 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58911 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58921 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58923 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58928 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58930 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58942 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58944 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to delete repository: AItst1 -Failed to delete Gitea repository: AItst1 -INFO: 127.0.0.1:58946 - "DELETE /api/v1/repositories/f33bf23a-bed7-41d9-ad8c-7a45bd5e2b33 HTTP/1.1" 200 OK -INFO: 127.0.0.1:58949 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59025 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59027 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59206 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:59210 - "GET /api/v1/gitea/config HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:59225 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:59228 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:59232 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59235 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59238 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59341 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59343 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59359 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59361 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59363 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59368 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:59371 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:59376 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59385 - "GET /api/v1/repositories/05b7cc76-c19e-4de8-a6b7-449282fec446 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59393 - "PUT /api/v1/repositories/05b7cc76-c19e-4de8-a6b7-449282fec446 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59396 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:59401 - "GET /api/v1/repositories HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to delete repository: AItst1 -Failed to delete Gitea repository: AItst1 -INFO: 127.0.0.1:59408 - "DELETE /api/v1/repositories/05b7cc76-c19e-4de8-a6b7-449282fec446 HTTP/1.1" 200 OK -INFO: 127.0.0.1:59412 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59552 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59554 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59615 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59618 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [33105] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [47880] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [47880] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [48204] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [48204] -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/project_analyzer.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [49144] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [49144] -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [50757] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: 127.0.0.1:62445 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:62508 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:62595 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:62618 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -ERROR:app.gitea.client:Gitea API request failed: 409 Client Error: Conflict for url: https://gitea.swiftsnake.cn/api/v1/org/yipai-tech/repos -INFO: 127.0.0.1:62624 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -ERROR:app.gitea.client:Gitea API request failed: 409 Client Error: Conflict for url: https://gitea.swiftsnake.cn/api/v1/org/yipai-tech/repos -ERROR:app.gitea.client:Gitea API request failed: 409 Client Error: Conflict for url: https://gitea.swiftsnake.cn/api/v1/user/repos -ERROR:app.gitea.client:Failed to create repository for owner yipai-tech -ERROR:app.gitea.service:Failed to create repository: AItst -INFO: 127.0.0.1:62632 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:62626 - "POST /api/v1/gitea/repos/create HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:62640 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:62643 - "GET /api/v1/repositories HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [50757] -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [52385] -INFO: Waiting for application startup. -INFO: Application startup complete. -ERROR:app.gitea.service:❌ Failed to delete repository: AItst -Failed to delete Gitea repository: AItst -INFO: 127.0.0.1:62921 - "DELETE /api/v1/repositories/7cc4eaed-003e-456b-bbe3-62b5cecf44d2 HTTP/1.1" 200 OK -INFO: 127.0.0.1:63018 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63615 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63689 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:63709 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:63973 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:64687 - "GET /api/v1/gitea/config HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:64690 - "GET /api/v1/users/me HTTP/1.1" 200 OK -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [52385] -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/routes/services.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-743: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-744: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-745: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-746: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-972: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-973: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 244 - services: - ^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-976: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 256 - " - ^ -SyntaxError: unterminated string literal (detected at line 256) -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-977: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 313 - """算法请求处理器""" - ^^^^^^^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-978: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 278 - service_code = ('# Python HTTP服务包装器\n'\n'\n'\n'import os\n'\n'import sys\n'\n'import json\n'\n'import time\n'\n'from http.server import HTTPServer, BaseHTTPRequestHandler\n'\n'\n'\n'# 添加项目路径到Python路径\n'\n'sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\n'\n'\n'\n'# 尝试导入算法模块\n'\n'try:\n'\n' # 根据入口点导入算法\n'\n' if "{{entry_point}}" == "":\n'\n' # 尝试导入主要模块\n'\n' import algorithm\n'\n' algorithm_module = algorithm\n'\n' else:\n'\n' # 动态导入入口点\n'\n' import importlib.util\n'\n' spec = importlib.util.spec_from_file_location("algorithm_module", "{{entry_point}}")\n'\n' algorithm_module = importlib.util.module_from_spec(spec)\n'\n' spec.loader.exec_module(algorithm_module)\n'\n' print("算法模块导入成功")\n'\n'except Exception as e:\n'\n' print(f"算法模块导入失败: {e}")\n'\n' algorithm_module = N - ^ -SyntaxError: unexpected character after line continuation character -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-979: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 480 - service_code += " if (\"{{entry_point}}\" === \"") {\n" - ^ -SyntaxError: unmatched ')' -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-980: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 480 - service_code += " if (\"{{entry_point}}\" === \"\") { - ^ -IndentationError: unindent does not match any outer indentation level -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-981: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 480 - service_code += " if (\"{{entry_point}}\" === \"\") { - ^ -IndentationError: unindent does not match any outer indentation level -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1210: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 676 - """算法请求处理器""" - ^^^^^^^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1211: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 612 - """Python HTTP服务包装器""" - ^^^^^^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1212: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 13, in - from app.services.service_generator import ServiceGenerator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_generator.py", line 974 - '''}}} - ^ -SyntaxError: unmatched '}' -WARNING: WatchFiles detected changes in 'app/services/service_generator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1213: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 612 - """Python HTTP服务包装器""" - ^^^^^^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'venv/lib/python3.9/site-packages/jinja2/_identifier.py', 'venv/lib/python3.9/site-packages/jinja2/environment.py', 'venv/lib/python3.9/site-packages/jinja2/visitor.py', 'venv/lib/python3.9/site-packages/markupsafe/__init__.py', 'venv/lib/python3.9/site-packages/jinja2/filters.py', 'venv/lib/python3.9/site-packages/jinja2/exceptions.py', 'venv/lib/python3.9/site-packages/jinja2/lexer.py', 'venv/lib/python3.9/site-packages/jinja2/meta.py', 'venv/lib/python3.9/site-packages/jinja2/optimizer.py', 'venv/lib/python3.9/site-packages/jinja2/utils.py', 'venv/lib/python3.9/site-packages/jinja2/tests.py', 'venv/lib/python3.9/site-packages/jinja2/bccache.py', 'venv/lib/python3.9/site-packages/jinja2/sandbox.py', 'venv/lib/python3.9/site-packages/jinja2/nativetypes.py', 'venv/lib/python3.9/site-packages/markupsafe/_native.py', 'venv/lib/python3.9/site-packages/jinja2/idtracking.py', 'venv/lib/python3.9/site-packages/jinja2/loaders.py', 'venv/lib/python3.9/site-packages/jinja2/defaults.py', 'venv/lib/python3.9/site-packages/jinja2/compiler.py', 'venv/lib/python3.9/site-packages/jinja2/runtime.py', 'venv/lib/python3.9/site-packages/jinja2/__init__.py', 'venv/lib/python3.9/site-packages/jinja2/async_utils.py', 'venv/lib/python3.9/site-packages/jinja2/ext.py', 'venv/lib/python3.9/site-packages/jinja2/debug.py', 'venv/lib/python3.9/site-packages/jinja2/nodes.py', 'venv/lib/python3.9/site-packages/jinja2/parser.py', 'venv/lib/python3.9/site-packages/jinja2/constants.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1214: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 612 - """Python HTTP服务包装器""" - ^^^^^^ -SyntaxError: invalid syntax -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1215: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 611 - return ''' - ^ -SyntaxError: unterminated triple-quoted string literal (detected at line 962) -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1216: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 9, in - from docker.errors import DockerException, ContainerNotFound -ImportError: cannot import name 'ContainerNotFound' from 'docker.errors' (/opt/miniconda3/lib/python3.12/site-packages/docker/errors.py) -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1217: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 771 - return ''' - ^ -SyntaxError: unterminated triple-quoted string literal (detected at line 962) -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -Process SpawnProcess-1218: -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap - self.run() - File "/opt/miniconda3/lib/python3.12/multiprocessing/process.py", line 108, in run - self._target(*self._args, **self._kwargs) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started - target(sockets=sockets) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 61, in run - return asyncio.run(self.serve(sockets=sockets)) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 195, in run - return runner.run(main) - ^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/asyncio/runners.py", line 118, in run - return self._loop.run_until_complete(task) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/server.py", line 68, in serve - config.load() - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/config.py", line 467, in load - self.loaded_app = import_from_string(self.app) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string - module = importlib.import_module(module_str) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/importlib/__init__.py", line 90, in import_module - return _bootstrap._gcd_import(name[level:], package, level) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "", line 1387, in _gcd_import - File "", line 1360, in _find_and_load - File "", line 1331, in _find_and_load_unlocked - File "", line 935, in _load_unlocked - File "", line 999, in exec_module - File "", line 488, in _call_with_frames_removed - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/main.py", line 7, in - from app.routes import user, api_key, algorithm, openai, gateway, services, data_management, monitoring, permissions, history, deployment, gitea, repositories - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/services.py", line 14, in - from app.services.service_orchestrator import ServiceOrchestrator - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/services/service_orchestrator.py", line 9, in - from docker.errors import DockerException, ContainerNotFound -ImportError: cannot import name 'ContainerNotFound' from 'docker.errors' (/opt/miniconda3/lib/python3.12/site-packages/docker/errors.py) -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [61803] -INFO: Waiting for application startup. -INFO: Application startup complete. -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: 127.0.0.1:49567 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:49570 - "GET /api/v1/gitea/config HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:50185 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:49579 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:49586 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [61803] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [61856] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [61856] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [61983] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [61983] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [62058] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [62058] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [62186] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [62186] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [62387] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/service_orchestrator.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [62387] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [62452] -INFO: Waiting for application startup. -INFO: Application startup complete. -WARNING: WatchFiles detected changes in 'app/services/user.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [62452] -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [64578] -INFO: Waiting for application startup. -INFO: Application startup complete. -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: 127.0.0.1:54321 - "POST /api/users/login HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:54359 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:54376 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:54379 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:54383 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54387 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -ERROR:app.gitea.client:Gitea API request failed: 404 Client Error: Not Found for url: https://gitea.swiftsnake.cn/api/v1/repos/yipai-tech/AItst -ERROR:app.gitea.service:❌ Failed to delete repository: AItst -Failed to delete Gitea repository: AItst -INFO: 127.0.0.1:54526 - "DELETE /api/v1/repositories/291f0580-27cd-4623-b9a0-4d91067864cd HTTP/1.1" 200 OK -INFO: 127.0.0.1:54530 - "GET /api/v1/repositories HTTP/1.1" 200 OK -ERROR:app.gitea.client:Gitea API request failed: 404 Client Error: Not Found for url: https://gitea.swiftsnake.cn/api/v1/repos/yipai-tech/AItst -ERROR:app.gitea.service:❌ Failed to delete repository: AItst -Failed to delete Gitea repository: AItst -INFO: 127.0.0.1:54539 - "DELETE /api/v1/repositories/77218ba3-b194-4c33-b85d-089bdf766152 HTTP/1.1" 200 OK -INFO: 127.0.0.1:54545 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54548 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:54557 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:54560 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:54565 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54593 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54595 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:54604 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:54607 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to delete repository: AItst -Failed to delete Gitea repository: AItst -INFO: 127.0.0.1:54943 - "DELETE /api/v1/repositories/5941e8b6-23fb-448c-9fcb-059c4655b01d HTTP/1.1" 200 OK -INFO: 127.0.0.1:54948 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55185 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55188 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55195 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55197 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55200 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55214 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:55217 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:55222 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55378 - "GET /api/v1/repositories/353bdc5b-083a-4a17-a149-de7fd08da89d HTTP/1.1" 200 OK -INFO: 127.0.0.1:55382 - "PUT /api/v1/repositories/353bdc5b-083a-4a17-a149-de7fd08da89d HTTP/1.1" 200 OK -INFO: 127.0.0.1:55385 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:55389 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55534 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55537 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55543 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55545 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -ERROR:app.gitea.service:❌ Failed to delete repository: AItst -Failed to delete Gitea repository: AItst -INFO: 127.0.0.1:55549 - "DELETE /api/v1/repositories/353bdc5b-083a-4a17-a149-de7fd08da89d HTTP/1.1" 200 OK -INFO: 127.0.0.1:55554 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55563 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55565 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55570 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:55575 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Repository is large: 529.02 MB -WARNING:app.gitea.service:This may cause HTTP 413 errors on push -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -To https://gitea.swiftsnake.cn/yipai-tech/AItst.git - ! [rejected] main -> main (fetch first) -error: failed to push some refs to 'https://gitea.swiftsnake.cn/yipai-tech/AItst.git' -hint: Updates were rejected because the remote contains work that you do -hint: not have locally. This is usually caused by another repository pushing -hint: to the same ref. You may want to first integrate the remote changes -hint: (e.g., 'git pull ...') before pushing again. -hint: See the 'Note about fast-forwards' in 'git push --help' for details. - -WARNING:app.gitea.service:Failed to push to 'main', trying alternative branch... -ERROR:app.gitea.service:Failed to push to 'master' as well -ERROR:app.gitea.service:❌ Git push failed: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -error: src refspec master does not match any -error: failed to push some refs to 'https://gitea.swiftsnake.cn/yipai-tech/AItst.git' - -INFO: 127.0.0.1:55579 - "POST /api/v1/gitea/repos/push HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:55583 - "POST /api/v1/repositories HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 68, in create_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 93, in save_obj - _emit_insert_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 1233, in _emit_insert_statements - result = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - -[SQL: INSERT INTO algorithm_repositories (id, algorithm_id, name, description, type, repo_url, branch, local_path, status, updated_at) VALUES (%(id)s, %(algorithm_id)s, %(name)s, %(description)s, %(type)s, %(repo_url)s, %(branch)s, %(local_path)s, %(status)s, %(updated_at)s) RETURNING algorithm_repositories.created_at] -[parameters: {'id': 'fc574632-b5a0-4bae-8f24-1d018181a598', 'algorithm_id': 'AItst', 'name': 'tst', 'description': 'tst', 'type': 'code', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AItst.git', 'branch': 'main', 'local_path': 'AIMonitor', 'status': 'active', 'updated_at': None}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -WARNING: WatchFiles detected changes in 'app/gitea/service.py'. Reloading... -INFO: Shutting down -INFO: Waiting for application shutdown. -INFO: Application shutdown complete. -INFO: Finished server process [64578] -WARNING:root:Failed to connect to MinIO: HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /algorithm-data?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused')). Running in offline mode. -ERROR:app.services.deployment:Failed to connect to Docker: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: Started server process [74269] -INFO: Waiting for application startup. -INFO: Application startup complete. -Docker连接失败: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory')) -INFO: 127.0.0.1:55766 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55771 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55778 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55780 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55782 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -ERROR:app.gitea.client:Gitea API request failed: 409 Client Error: Conflict for url: https://gitea.swiftsnake.cn/api/v1/org/yipai-tech/repos -ERROR:app.gitea.client:Gitea API request failed: 409 Client Error: Conflict for url: https://gitea.swiftsnake.cn/api/v1/user/repos -ERROR:app.gitea.client:Failed to create repository for owner yipai-tech -ERROR:app.gitea.service:Failed to create repository: AItst -INFO: 127.0.0.1:55790 - "POST /api/v1/gitea/repos/create HTTP/1.1" 500 Internal Server Error -INFO: 127.0.0.1:55795 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:55798 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:55803 - "POST /api/v1/repositories HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 68, in create_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 93, in save_obj - _emit_insert_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 1233, in _emit_insert_statements - result = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - -[SQL: INSERT INTO algorithm_repositories (id, algorithm_id, name, description, type, repo_url, branch, local_path, status, updated_at) VALUES (%(id)s, %(algorithm_id)s, %(name)s, %(description)s, %(type)s, %(repo_url)s, %(branch)s, %(local_path)s, %(status)s, %(updated_at)s) RETURNING algorithm_repositories.created_at] -[parameters: {'id': '91a96e8b-2c2b-4c56-a86f-2357c75d7eb7', 'algorithm_id': 'AItst', 'name': 'tst', 'description': 'tst', 'type': 'code', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AItst.git', 'branch': 'main', 'local_path': 'AIMonitor', 'status': 'active', 'updated_at': None}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -INFO: 127.0.0.1:55913 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:55915 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:55917 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56099 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56101 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56104 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56109 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:56114 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:56117 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:56122 - "POST /api/v1/repositories HTTP/1.1" 500 Internal Server Error -ERROR: Exception in ASGI application -Traceback (most recent call last): - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -psycopg2.errors.ForeignKeyViolation: insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi - result = await app( # type: ignore[func-returns-value] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__ - return await self.app(scope, receive, send) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1106, in __call__ - await super().__call__(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/applications.py", line 122, in __call__ - await self.middleware_stack(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 184, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 162, in __call__ - await self.app(scope, receive, _send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 91, in __call__ - await self.simple_response(scope, receive, send, request_headers=headers) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 146, in simple_response - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 79, in __call__ - raise exc - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ - await self.app(scope, receive, sender) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__ - raise e - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__ - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 718, in __call__ - await route.handle(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 276, in handle - await self.app(scope, receive, send) - File "/Users/duguoyou/.local/lib/python3.12/site-packages/starlette/routing.py", line 66, in app - response = await func(request) - ^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 274, in app - raw_response = await run_endpoint_function( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function - return await dependant.call(**values) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/Users/duguoyou/MLFlow/algorithm-showcase/backend/app/routes/repositories.py", line 68, in create_repository - db.commit() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 2030, in commit - trans.commit(_to_root=True) - File "", line 2, in commit - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1311, in commit - self._prepare_impl() - File "", line 2, in _prepare_impl - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go - ret_value = fn(self, *arg, **kw) - ^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 1286, in _prepare_impl - self.session.flush() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4331, in flush - self._flush(objects) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4466, in _flush - with util.safe_reraise(): - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__ - raise exc_value.with_traceback(exc_tb) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/session.py", line 4427, in _flush - flush_context.execute() - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute - rec.execute(self) - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute - util.preloaded.orm_persistence.save_obj( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 93, in save_obj - _emit_insert_statements( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/orm/persistence.py", line 1233, in _emit_insert_statements - result = connection.execute( - ^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1419, in execute - return meth( - ^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 527, in _execute_on_connection - return connection._execute_clauseelement( - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1641, in _execute_clauseelement - ret = self._execute_context( - ^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1846, in _execute_context - return self._exec_single_context( - ^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1986, in _exec_single_context - self._handle_dbapi_exception( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 2363, in _handle_dbapi_exception - raise sqlalchemy_exception.with_traceback(exc_info[2]) from e - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/base.py", line 1967, in _exec_single_context - self.dialect.do_execute( - File "/opt/miniconda3/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 952, in do_execute - cursor.execute(statement, parameters) -sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "algorithm_repositories" violates foreign key constraint "algorithm_repositories_algorithm_id_fkey" -DETAIL: Key (algorithm_id)=(AItst) is not present in table "algorithms". - -[SQL: INSERT INTO algorithm_repositories (id, algorithm_id, name, description, type, repo_url, branch, local_path, status, updated_at) VALUES (%(id)s, %(algorithm_id)s, %(name)s, %(description)s, %(type)s, %(repo_url)s, %(branch)s, %(local_path)s, %(status)s, %(updated_at)s) RETURNING algorithm_repositories.created_at] -[parameters: {'id': '7f155cc1-3b9a-489b-b0ef-acd7b9e34056', 'algorithm_id': 'AItst', 'name': 'tst', 'description': 'tst', 'type': 'code', 'repo_url': 'https://gitea.swiftsnake.cn/yipai-tech/AItst.git', 'branch': 'main', 'local_path': 'AIMonitor', 'status': 'active', 'updated_at': None}] -(Background on this error at: https://sqlalche.me/e/20/gkpj) -INFO: 127.0.0.1:56265 - "GET /api/health HTTP/1.1" 404 Not Found -INFO: 127.0.0.1:56270 - "GET / HTTP/1.1" 200 OK -INFO: 127.0.0.1:56325 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56327 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:56334 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:56336 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57092 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:57094 - "GET /api/v1/gitea/config HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:57129 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:57132 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:57136 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57139 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57142 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57442 - "POST /api/v1/users/login HTTP/1.1" 401 Unauthorized -INFO: 127.0.0.1:57446 - "POST /api/v1/users/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:57449 - "GET /api/v1/users/me HTTP/1.1" 200 OK -INFO: 127.0.0.1:57452 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57455 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:57466 - "POST /api/v1/repositories HTTP/1.1" 201 Created -INFO: 127.0.0.1:57469 - "POST /api/v1/gitea/repos/create HTTP/1.1" 200 OK -INFO: 127.0.0.1:57474 - "POST /api/v1/gitea/repos/clone HTTP/1.1" 200 OK -INFO: 127.0.0.1:57478 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:57481 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:57484 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -INFO: 127.0.0.1:57488 - "POST /api/v1/gitea/repos/upload HTTP/1.1" 200 OK -WARNING:app.gitea.service:Repository is large: 529.00 MB -WARNING:app.gitea.service:This may cause HTTP 413 errors on push -WARNING:app.gitea.service:Git push stderr: Pushing to https://gitea.swiftsnake.cn/yipai-tech/AItst.git -warning: setting remote service path not supported by protocol -warning: setting remote service path not supported by protocol -Enumerating objects: 34, done. -Counting objects: 2% (1/34) -Counting objects: 5% (2/34) -Counting objects: 8% (3/34) -Counting objects: 11% (4/34) -Counting objects: 14% (5/34) -Counting objects: 17% (6/34) -Counting objects: 20% (7/34) -Counting objects: 23% (8/34) -Counting objects: 26% (9/34) -Counting objects: 29% (10/34) -Counting objects: 32% (11/34) -Counting objects: 35% (12/34) -Counting objects: 38% (13/34) -Counting objects: 41% (14/34) -Counting objects: 44% (15/34) -Counting objects: 47% (16/34) -Counting objects: 50% (17/34) -Counting objects: 52% (18/34) -Counting objects: 55% (19/34) -Counting objects: 58% (20/34) -Counting objects: 61% (21/34) -Counting objects: 64% (22/34) -Counting objects: 67% (23/34) -Counting objects: 70% (24/34) -Counting objects: 73% (25/34) -Counting objects: 76% (26/34) -Counting objects: 79% (27/34) -Counting objects: 82% (28/34) -Counting objects: 85% (29/34) -Counting objects: 88% (30/34) -Counting objects: 91% (31/34) -Counting objects: 94% (32/34) -Counting objects: 97% (33/34) -Counting objects: 100% (34/34) -Counting objects: 100% (34/34), done. -Delta compression using up to 16 threads -Compressing objects: 3% (1/31) -Compressing objects: 6% (2/31) -Compressing objects: 9% (3/31) -Compressing objects: 12% (4/31) -Compressing objects: 16% (5/31) -Compressing objects: 19% (6/31) -Compressing objects: 22% (7/31) -Compressing objects: 25% (8/31) -Compressing objects: 29% (9/31) -Compressing objects: 32% (10/31) -Compressing objects: 35% (11/31) -Compressing objects: 38% (12/31) -Compressing objects: 41% (13/31) -Compressing objects: 45% (14/31) -Compressing objects: 48% (15/31) -Compressing objects: 51% (16/31) -Compressing objects: 54% (17/31) -Compressing objects: 58% (18/31) -Compressing objects: 61% (19/31) -Compressing objects: 64% (20/31) -Compressing objects: 67% (21/31) -Compressing objects: 70% (22/31) -Compressing objects: 74% (23/31) -Compressing objects: 77% (24/31) -Compressing objects: 80% (25/31) -Compressing objects: 83% (26/31) -Compressing objects: 87% (27/31) -Compressing objects: 90% (28/31) -Compressing objects: 93% (29/31) -Compressing objects: 96% (30/31) -Compressing objects: 100% (31/31) -Compressing objects: 100% (31/31), done. -Writing objects: 3% (1/33) -Writing objects: 6% (2/33) -Writing objects: 9% (3/33) -Writing objects: 12% (4/33) -Writing objects: 15% (5/33) -Writing objects: 18% (6/33) -Writing objects: 21% (7/33) -Writing objects: 24% (8/33) -Writing objects: 27% (9/33) -Writing objects: 30% (10/33) -Writing objects: 33% (11/33) -Writing objects: 36% (12/33) -Writing objects: 39% (13/33) -Writing objects: 42% (14/33) -Writing objects: 48% (16/33) -Writing objects: 51% (17/33) -Writing objects: 54% (18/33) -Writing objects: 57% (19/33) -Writing objects: 63% (21/33) -Writing objects: 66% (22/33) -Writing objects: 69% (23/33) -Writing objects: 72% (24/33) -Writing objects: 75% (25/33) -Writing objects: 78% (26/33) -Writing objects: 81% (27/33) -Writing objects: 84% (28/33) -Writing objects: 87% (29/33) -Writing objects: 90% (30/33) -Writing objects: 93% (31/33) -POST git-receive-pack (chunked) -Writing objects: 93% (31/33), 500.07 MiB | 8.91 MiB/s -Writing objects: 93% (31/33), 511.69 MiB | 8.95 MiB/s -Writing objects: 93% (31/33), 524.50 MiB | 9.02 MiB/s -Writing objects: 96% (32/33), 524.50 MiB | 9.02 MiB/s -Writing objects: 100% (33/33), 524.50 MiB | 9.02 MiB/s -Writing objects: 100% (33/33), 529.02 MiB | 9.01 MiB/s, done. -Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 -remote: . Processing 1 references -remote: Processed 1 references in total -To https://gitea.swiftsnake.cn/yipai-tech/AItst.git - bb01265..505cfe9 main -> main -updating local tracking ref 'refs/remotes/origin/main' - -INFO: 127.0.0.1:57494 - "POST /api/v1/gitea/repos/push HTTP/1.1" 200 OK -INFO: 127.0.0.1:57608 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57626 - "GET /api/v1/repositories/e87f84b1-439d-426d-af11-dd1653c54ced HTTP/1.1" 200 OK -INFO: 127.0.0.1:57630 - "PUT /api/v1/repositories/e87f84b1-439d-426d-af11-dd1653c54ced HTTP/1.1" 200 OK -INFO: 127.0.0.1:57633 - "PATCH /api/v1/gitea/repos/update HTTP/1.1" 200 OK -INFO: 127.0.0.1:57637 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57957 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:57960 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58386 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58388 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58409 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58411 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:58972 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:58976 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59054 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59058 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59080 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59084 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59104 - "GET /api/v1/repositories HTTP/1.1" 200 OK -INFO: 127.0.0.1:59108 - "GET /api/v1/gitea/config HTTP/1.1" 200 OK -INFO: 127.0.0.1:59318 - "GET /api/v1/repositories HTTP/1.1" 401 Unauthorized diff --git a/backend/venv39/bin/Activate.ps1 b/backend/venv39/bin/Activate.ps1 deleted file mode 100644 index 2fb3852..0000000 --- a/backend/venv39/bin/Activate.ps1 +++ /dev/null @@ -1,241 +0,0 @@ -<# -.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 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 virutal 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 - } -} - -# 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" diff --git a/backend/venv39/bin/activate b/backend/venv39/bin/activate deleted file mode 100644 index 3325f96..0000000 --- a/backend/venv39/bin/activate +++ /dev/null @@ -1,66 +0,0 @@ -# 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 - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null - fi - - if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then - PS1="${_OLD_VIRTUAL_PS1:-}" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "${1:-}" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39" -export VIRTUAL_ENV - -_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="(venv39) ${PS1:-}" - export PS1 -fi - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null -fi diff --git a/backend/venv39/bin/activate.csh b/backend/venv39/bin/activate.csh deleted file mode 100644 index ecfa9f9..0000000 --- a/backend/venv39/bin/activate.csh +++ /dev/null @@ -1,25 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . -# Ported to Python 3.3 venv by Andrew Svetlov - -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; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/bin:$PATH" - - -set _OLD_VIRTUAL_PROMPT="$prompt" - -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = "(venv39) $prompt" -endif - -alias pydoc python -m pydoc - -rehash diff --git a/backend/venv39/bin/activate.fish b/backend/venv39/bin/activate.fish deleted file mode 100644 index 5200c6e..0000000 --- a/backend/venv39/bin/activate.fish +++ /dev/null @@ -1,64 +0,0 @@ -# This file must be used with "source /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" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self-destruct! - functions -e deactivate - end -end - -# Unset irrelevant variables. -deactivate nondestructive - -set -gx VIRTUAL_ENV "/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39" - -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) "(venv39) " (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" -end diff --git a/backend/venv39/bin/distro b/backend/venv39/bin/distro deleted file mode 100755 index b663279..0000000 --- a/backend/venv39/bin/distro +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/dotenv b/backend/venv39/bin/dotenv deleted file mode 100755 index 2808af6..0000000 --- a/backend/venv39/bin/dotenv +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/email_validator b/backend/venv39/bin/email_validator deleted file mode 100755 index 2ec801d..0000000 --- a/backend/venv39/bin/email_validator +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- coding: utf-8 -*- -import re -import sys -from email_validator.__main__ import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/backend/venv39/bin/fastapi b/backend/venv39/bin/fastapi deleted file mode 100755 index a626342..0000000 --- a/backend/venv39/bin/fastapi +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/httpx b/backend/venv39/bin/httpx deleted file mode 100755 index b9df6a7..0000000 --- a/backend/venv39/bin/httpx +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/normalizer b/backend/venv39/bin/normalizer deleted file mode 100755 index 07c8506..0000000 --- a/backend/venv39/bin/normalizer +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- coding: utf-8 -*- -import re -import sys -from charset_normalizer.cli import cli_detect -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(cli_detect()) diff --git a/backend/venv39/bin/openai b/backend/venv39/bin/openai deleted file mode 100755 index 778292c..0000000 --- a/backend/venv39/bin/openai +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pip b/backend/venv39/bin/pip deleted file mode 100755 index 02b50ba..0000000 --- a/backend/venv39/bin/pip +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pip3 b/backend/venv39/bin/pip3 deleted file mode 100755 index 02b50ba..0000000 --- a/backend/venv39/bin/pip3 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pip3.9 b/backend/venv39/bin/pip3.9 deleted file mode 100755 index 02b50ba..0000000 --- a/backend/venv39/bin/pip3.9 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-decrypt b/backend/venv39/bin/pyrsa-decrypt deleted file mode 100755 index 6ec0d47..0000000 --- a/backend/venv39/bin/pyrsa-decrypt +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-encrypt b/backend/venv39/bin/pyrsa-encrypt deleted file mode 100755 index 5eec5b3..0000000 --- a/backend/venv39/bin/pyrsa-encrypt +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-keygen b/backend/venv39/bin/pyrsa-keygen deleted file mode 100755 index b9693a1..0000000 --- a/backend/venv39/bin/pyrsa-keygen +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-priv2pub b/backend/venv39/bin/pyrsa-priv2pub deleted file mode 100755 index 38b71e3..0000000 --- a/backend/venv39/bin/pyrsa-priv2pub +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-sign b/backend/venv39/bin/pyrsa-sign deleted file mode 100755 index 1cd1349..0000000 --- a/backend/venv39/bin/pyrsa-sign +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/pyrsa-verify b/backend/venv39/bin/pyrsa-verify deleted file mode 100755 index b821e15..0000000 --- a/backend/venv39/bin/pyrsa-verify +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/python b/backend/venv39/bin/python deleted file mode 120000 index e616d26..0000000 --- a/backend/venv39/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3.9 \ No newline at end of file diff --git a/backend/venv39/bin/python3 b/backend/venv39/bin/python3 deleted file mode 120000 index e616d26..0000000 --- a/backend/venv39/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -python3.9 \ No newline at end of file diff --git a/backend/venv39/bin/python3.9 b/backend/venv39/bin/python3.9 deleted file mode 120000 index 8892e05..0000000 --- a/backend/venv39/bin/python3.9 +++ /dev/null @@ -1 +0,0 @@ -/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3.9 \ No newline at end of file diff --git a/backend/venv39/bin/tqdm b/backend/venv39/bin/tqdm deleted file mode 100755 index 51a2505..0000000 --- a/backend/venv39/bin/tqdm +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/bin/uvicorn b/backend/venv39/bin/uvicorn deleted file mode 100755 index 68ee25f..0000000 --- a/backend/venv39/bin/uvicorn +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/bin/python3.9 -# -*- 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()) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.py deleted file mode 100644 index 52ac33d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.py +++ /dev/null @@ -1,235 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/AES.py : AES -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -from Crypto.Util import _cpu_features -from Crypto.Random import get_random_bytes - -MODE_ECB = 1 #: Electronic Code Book (:ref:`ecb_mode`) -MODE_CBC = 2 #: Cipher-Block Chaining (:ref:`cbc_mode`) -MODE_CFB = 3 #: Cipher Feedback (:ref:`cfb_mode`) -MODE_OFB = 5 #: Output Feedback (:ref:`ofb_mode`) -MODE_CTR = 6 #: Counter mode (:ref:`ctr_mode`) -MODE_OPENPGP = 7 #: OpenPGP mode (:ref:`openpgp_mode`) -MODE_CCM = 8 #: Counter with CBC-MAC (:ref:`ccm_mode`) -MODE_EAX = 9 #: :ref:`eax_mode` -MODE_SIV = 10 #: Synthetic Initialization Vector (:ref:`siv_mode`) -MODE_GCM = 11 #: Galois Counter Mode (:ref:`gcm_mode`) -MODE_OCB = 12 #: Offset Code Book (:ref:`ocb_mode`) -MODE_KW = 13 #: Key Wrap (:ref:`kw_mode`) -MODE_KWP = 14 #: Key Wrap with Padding (:ref:`kwp_mode`) - -_cproto = """ - int AES_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int AES_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int AES_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int AES_stop_operation(void *state); - """ - - -# Load portable AES -_raw_aes_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aes", - _cproto) - -# Try to load AES with AES NI instructions -try: - _raw_aesni_lib = None - if _cpu_features.have_aes_ni(): - _raw_aesni_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aesni", - _cproto.replace("AES", - "AESNI")) -# _raw_aesni may not have been compiled in -except OSError: - pass - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - use_aesni = dict_parameters.pop("use_aesni", True) - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect AES key length (%d bytes)" % len(key)) - - if use_aesni and _raw_aesni_lib: - start_operation = _raw_aesni_lib.AESNI_start_operation - stop_operation = _raw_aesni_lib.AESNI_stop_operation - else: - start_operation = _raw_aes_lib.AES_start_operation - stop_operation = _raw_aes_lib.AES_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the AES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def _derive_Poly1305_key_pair(key, nonce): - """Derive a tuple (r, s, nonce) for a Poly1305 MAC. - - If nonce is ``None``, a new 16-byte nonce is generated. - """ - - if len(key) != 32: - raise ValueError("Poly1305 with AES requires a 32-byte key") - - if nonce is None: - nonce = get_random_bytes(16) - elif len(nonce) != 16: - raise ValueError("Poly1305 with AES requires a 16-byte nonce") - - s = new(key[:16], MODE_ECB).encrypt(nonce) - return key[16:], s, nonce - - -def new(key, mode, *args, **kwargs): - """Create a new AES cipher. - - Args: - key(bytes/bytearray/memoryview): - The secret key to use in the symmetric cipher. - - It must be 16 (*AES-128)*, 24 (*AES-192*) or 32 (*AES-256*) bytes long. - - For ``MODE_SIV`` only, it doubles to 32, 48, or 64 bytes. - mode (a ``MODE_*`` constant): - The chaining mode to use for encryption or decryption. - If in doubt, use ``MODE_EAX``. - - Keyword Args: - iv (bytes/bytearray/memoryview): - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 16 bytes long for encryption - and 18 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - nonce (bytes/bytearray/memoryview): - (Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``, - ``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key (except possibly for ``MODE_SIV``, see below). - - For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CCM``, its length must be in the range **[7..13]**. - Bear in mind that with CCM there is a trade-off between nonce - length and maximum message size. Recommendation: **11** bytes. - - For ``MODE_OCB``, its length must be in the range **[1..15]** - (recommended: **15**). - - For ``MODE_CTR``, its length must be in the range **[0..15]** - (recommended: **8**). - - For ``MODE_SIV``, the nonce is optional, if it is not specified, - then no nonce is being used, which renders the encryption - deterministic. - - If not provided, for modes other than ``MODE_SIV``, a random - byte string of the recommended length is used (you must then - read its value with the :attr:`nonce` attribute). - - segment_size (integer): - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - mac_len (integer): - (Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``) - Length of the authentication tag, in bytes. - - It must be even and in the range **[4..16]**. - The recommended value (and the default, if not specified) is **16**. - - msg_len (integer): - (Only ``MODE_CCM``). Length of the message to (de)cipher. - If not specified, ``encrypt`` must be called with the entire message. - Similarly, ``decrypt`` can only be called once. - - assoc_len (integer): - (Only ``MODE_CCM``). Length of the associated data. - If not specified, all associated data is buffered internally, - which may represent a problem for very large messages. - - initial_value (integer or bytes/bytearray/memoryview): - (Only ``MODE_CTR``). - The initial value for the counter. If not present, the cipher will - start counting from 0. The value is incremented by one for each block. - The counter number is encoded in big endian mode. - - counter (object): - (Only ``MODE_CTR``). - Instance of ``Crypto.Util.Counter``, which allows full customization - of the counter block. This parameter is incompatible to both ``nonce`` - and ``initial_value``. - - use_aesni: (boolean): - Use Intel AES-NI hardware extensions (default: use if available). - - Returns: - an AES object, of the applicable mode. - """ - - kwargs["add_aes_modes"] = True - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - - -# Size of a data block (in bytes) -block_size = 16 -# Size of a key (in bytes) -key_size = (16, 24, 32) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.pyi deleted file mode 100644 index 125e3e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/AES.pyi +++ /dev/null @@ -1,156 +0,0 @@ -from typing import Dict, Optional, Tuple, Union, overload -from typing_extensions import Literal - -Buffer=bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_ccm import CcmMode -from Crypto.Cipher._mode_eax import EaxMode -from Crypto.Cipher._mode_gcm import GcmMode -from Crypto.Cipher._mode_siv import SivMode -from Crypto.Cipher._mode_ocb import OcbMode - -MODE_ECB: Literal[1] -MODE_CBC: Literal[2] -MODE_CFB: Literal[3] -MODE_OFB: Literal[5] -MODE_CTR: Literal[6] -MODE_OPENPGP: Literal[7] -MODE_CCM: Literal[8] -MODE_EAX: Literal[9] -MODE_SIV: Literal[10] -MODE_GCM: Literal[11] -MODE_OCB: Literal[12] - -# MODE_ECB -@overload -def new(key: Buffer, - mode: Literal[1], - use_aesni : bool = ...) -> \ - EcbMode: ... - -# MODE_CBC -@overload -def new(key: Buffer, - mode: Literal[2], - iv : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - CbcMode: ... - -@overload -def new(key: Buffer, - mode: Literal[2], - IV : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - CbcMode: ... - -# MODE_CFB -@overload -def new(key: Buffer, - mode: Literal[3], - iv : Optional[Buffer] = ..., - segment_size : int = ..., - use_aesni : bool = ...) -> \ - CfbMode: ... - -@overload -def new(key: Buffer, - mode: Literal[3], - IV : Optional[Buffer] = ..., - segment_size : int = ..., - use_aesni : bool = ...) -> \ - CfbMode: ... - -# MODE_OFB -@overload -def new(key: Buffer, - mode: Literal[5], - iv : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - OfbMode: ... - -@overload -def new(key: Buffer, - mode: Literal[5], - IV : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - OfbMode: ... - -# MODE_CTR -@overload -def new(key: Buffer, - mode: Literal[6], - nonce : Optional[Buffer] = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ..., - use_aesni : bool = ...) -> \ - CtrMode: ... - -# MODE_OPENPGP -@overload -def new(key: Buffer, - mode: Literal[7], - iv : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - OpenPgpMode: ... - -@overload -def new(key: Buffer, - mode: Literal[7], - IV : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - OpenPgpMode: ... - -# MODE_CCM -@overload -def new(key: Buffer, - mode: Literal[8], - nonce : Optional[Buffer] = ..., - mac_len : int = ..., - assoc_len : int = ..., - use_aesni : bool = ...) -> \ - CcmMode: ... - -# MODE_EAX -@overload -def new(key: Buffer, - mode: Literal[9], - nonce : Optional[Buffer] = ..., - mac_len : int = ..., - use_aesni : bool = ...) -> \ - EaxMode: ... - -# MODE_GCM -@overload -def new(key: Buffer, - mode: Literal[10], - nonce : Optional[Buffer] = ..., - use_aesni : bool = ...) -> \ - SivMode: ... - -# MODE_SIV -@overload -def new(key: Buffer, - mode: Literal[11], - nonce : Optional[Buffer] = ..., - mac_len : int = ..., - use_aesni : bool = ...) -> \ - GcmMode: ... - -# MODE_OCB -@overload -def new(key: Buffer, - mode: Literal[12], - nonce : Optional[Buffer] = ..., - mac_len : int = ..., - use_aesni : bool = ...) -> \ - OcbMode: ... - - -block_size: int -key_size: Tuple[int, int, int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.py deleted file mode 100644 index 0ba7e33..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/ARC2.py : ARC2.py -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -""" -Module's constants for the modes of operation supported with ARC2: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_arc2_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_arc2", - """ - int ARC2_start_operation(const uint8_t key[], - size_t key_len, - size_t effective_key_len, - void **pResult); - int ARC2_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ARC2_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ARC2_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - effective_keylen = dict_parameters.pop("effective_keylen", 1024) - - if len(key) not in key_size: - raise ValueError("Incorrect ARC2 key length (%d bytes)" % len(key)) - - if not (40 <= effective_keylen <= 1024): - raise ValueError("'effective_key_len' must be at least 40 and no larger than 1024 " - "(not %d)" % effective_keylen) - - start_operation = _raw_arc2_lib.ARC2_start_operation - stop_operation = _raw_arc2_lib.ARC2_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(effective_keylen), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the ARC2 cipher" - % result) - - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new RC2 cipher. - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 128 bytes; the actual search space - (and the cipher strength) can be reduced with the ``effective_keylen`` parameter. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **effective_keylen** (*integer*) -- - Optional. Maximum strength in bits of the actual key used by the ARC2 algorithm. - If the supplied ``key`` parameter is longer (in bits) of the value specified - here, it will be weakened to match it. - If not specified, no limitation is applied. - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: an ARC2 object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(5, 128 + 1) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.pyi deleted file mode 100644 index 771c6dc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC2.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable, Optional - -Buffer = bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -ARC2Mode = int - -MODE_ECB: ARC2Mode -MODE_CBC: ARC2Mode -MODE_CFB: ARC2Mode -MODE_OFB: ARC2Mode -MODE_CTR: ARC2Mode -MODE_OPENPGP: ARC2Mode -MODE_EAX: ARC2Mode - -def new(key: Buffer, - mode: ARC2Mode, - iv : Optional[Buffer] = ..., - IV : Optional[Buffer] = ..., - nonce : Optional[Buffer] = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Iterable[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.py deleted file mode 100644 index 97dc229..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/ARC4.py : ARC4 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr) - - -_raw_arc4_lib = load_pycryptodome_raw_lib("Crypto.Cipher._ARC4", """ - int ARC4_stream_encrypt(void *rc4State, const uint8_t in[], - uint8_t out[], size_t len); - int ARC4_stream_init(uint8_t *key, size_t keylen, - void **pRc4State); - int ARC4_stream_destroy(void *rc4State); - """) - - -class ARC4Cipher: - """ARC4 cipher object. Do not create it directly. Use - :func:`Crypto.Cipher.ARC4.new` instead. - """ - - def __init__(self, key, *args, **kwargs): - """Initialize an ARC4 cipher object - - See also `new()` at the module level.""" - - if len(args) > 0: - ndrop = args[0] - args = args[1:] - else: - ndrop = kwargs.pop('drop', 0) - - if len(key) not in key_size: - raise ValueError("Incorrect ARC4 key length (%d bytes)" % - len(key)) - - self._state = VoidPointer() - result = _raw_arc4_lib.ARC4_stream_init(c_uint8_ptr(key), - c_size_t(len(key)), - self._state.address_of()) - if result != 0: - raise ValueError("Error %d while creating the ARC4 cipher" - % result) - self._state = SmartPointer(self._state.get(), - _raw_arc4_lib.ARC4_stream_destroy) - - if ndrop > 0: - # This is OK even if the cipher is used for decryption, - # since encrypt and decrypt are actually the same thing - # with ARC4. - self.encrypt(b'\x00' * ndrop) - - self.block_size = 1 - self.key_size = len(key) - - def encrypt(self, plaintext): - """Encrypt a piece of data. - - :param plaintext: The data to encrypt, of any size. - :type plaintext: bytes, bytearray, memoryview - :returns: the encrypted byte string, of equal length as the - plaintext. - """ - - ciphertext = create_string_buffer(len(plaintext)) - result = _raw_arc4_lib.ARC4_stream_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - ciphertext, - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with RC4" % result) - return get_raw_buffer(ciphertext) - - def decrypt(self, ciphertext): - """Decrypt a piece of data. - - :param ciphertext: The data to decrypt, of any size. - :type ciphertext: bytes, bytearray, memoryview - :returns: the decrypted byte string, of equal length as the - ciphertext. - """ - - try: - return self.encrypt(ciphertext) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - -def new(key, *args, **kwargs): - """Create a new ARC4 cipher. - - :param key: - The secret key to use in the symmetric cipher. - Its length must be in the range ``[1..256]``. - The recommended length is 16 bytes. - :type key: bytes, bytearray, memoryview - - :Keyword Arguments: - * *drop* (``integer``) -- - The amount of bytes to discard from the initial part of the keystream. - In fact, such part has been found to be distinguishable from random - data (while it shouldn't) and also correlated to key. - - The recommended value is 3072_ bytes. The default value is 0. - - :Return: an `ARC4Cipher` object - - .. _3072: http://eprint.iacr.org/2002/067.pdf - """ - return ARC4Cipher(key, *args, **kwargs) - - -# Size of a data block (in bytes) -block_size = 1 -# Size of a key (in bytes) -key_size = range(1, 256+1) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.pyi deleted file mode 100644 index b081585..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ARC4.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Any, Union, Iterable - -Buffer = bytes|bytearray|memoryview - -class ARC4Cipher: - block_size: int - key_size: int - - def __init__(self, key: Buffer, *args: Any, **kwargs: Any) -> None: ... - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer) -> bytes: ... - -def new(key: Buffer, drop : int = ...) -> ARC4Cipher: ... - -block_size: int -key_size: Iterable[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.py deleted file mode 100644 index 6005ffe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/Blowfish.py : Blowfish -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -""" -Module's constants for the modes of operation supported with Blowfish: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, c_size_t, - c_uint8_ptr) - -_raw_blowfish_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_blowfish", - """ - int Blowfish_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int Blowfish_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int Blowfish_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int Blowfish_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a smart pointer to - a low-level base cipher. It will absorb named parameters in - the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect Blowfish key length (%d bytes)" % len(key)) - - start_operation = _raw_blowfish_lib.Blowfish_start_operation - stop_operation = _raw_blowfish_lib.Blowfish_stop_operation - - void_p = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - void_p.address_of()) - if result: - raise ValueError("Error %X while instantiating the Blowfish cipher" - % result) - return SmartPointer(void_p.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new Blowfish cipher - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 56 bytes. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a Blowfish object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(4, 56 + 1) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.pyi deleted file mode 100644 index 76c3808..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Blowfish.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable, Optional - -Buffer = bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -BlowfishMode = int - -MODE_ECB: BlowfishMode -MODE_CBC: BlowfishMode -MODE_CFB: BlowfishMode -MODE_OFB: BlowfishMode -MODE_CTR: BlowfishMode -MODE_OPENPGP: BlowfishMode -MODE_EAX: BlowfishMode - -def new(key: Buffer, - mode: BlowfishMode, - iv : Optional[Buffer] = ..., - IV : Optional[Buffer] = ..., - nonce : Optional[Buffer] = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Iterable[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.py deleted file mode 100644 index c7e82c1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/CAST.py : CAST -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -""" -Module's constants for the modes of operation supported with CAST: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_cast_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_cast", - """ - int CAST_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int CAST_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CAST_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CAST_stop_operation(void *state); - """) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect CAST key length (%d bytes)" % len(key)) - - start_operation = _raw_cast_lib.CAST_start_operation - stop_operation = _raw_cast_lib.CAST_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the CAST cipher" - % result) - - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new CAST cipher - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 16 bytes. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a CAST object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(5, 16 + 1) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.pyi deleted file mode 100644 index f107552..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/CAST.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable, Optional - -Buffer = bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -CASTMode = int - -MODE_ECB: CASTMode -MODE_CBC: CASTMode -MODE_CFB: CASTMode -MODE_OFB: CASTMode -MODE_CTR: CASTMode -MODE_OPENPGP: CASTMode -MODE_EAX: CASTMode - -def new(key: Buffer, - mode: CASTMode, - iv : Optional[Buffer] = ..., - IV : Optional[Buffer] = ..., - nonce : Optional[Buffer] = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size : Iterable[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.py deleted file mode 100644 index f77f1bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.py +++ /dev/null @@ -1,291 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Random import get_random_bytes - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, VoidPointer, - SmartPointer, c_size_t, - c_uint8_ptr, c_ulong, - is_writeable_buffer) - -_raw_chacha20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._chacha20", - """ - int chacha20_init(void **pState, - const uint8_t *key, - size_t keySize, - const uint8_t *nonce, - size_t nonceSize); - - int chacha20_destroy(void *state); - - int chacha20_encrypt(void *state, - const uint8_t in[], - uint8_t out[], - size_t len); - - int chacha20_seek(void *state, - unsigned long block_high, - unsigned long block_low, - unsigned offset); - - int hchacha20( const uint8_t key[32], - const uint8_t nonce16[16], - uint8_t subkey[32]); - """) - - -def _HChaCha20(key, nonce): - - assert(len(key) == 32) - assert(len(nonce) == 16) - - subkey = bytearray(32) - result = _raw_chacha20_lib.hchacha20( - c_uint8_ptr(key), - c_uint8_ptr(nonce), - c_uint8_ptr(subkey)) - if result: - raise ValueError("Error %d when deriving subkey with HChaCha20" % result) - - return subkey - - -class ChaCha20Cipher(object): - """ChaCha20 (or XChaCha20) cipher object. - Do not create it directly. Use :py:func:`new` instead. - - :var nonce: The nonce with length 8, 12 or 24 bytes - :vartype nonce: bytes - """ - - block_size = 1 - - def __init__(self, key, nonce): - """Initialize a ChaCha20/XChaCha20 cipher object - - See also `new()` at the module level.""" - - self.nonce = _copy_bytes(None, None, nonce) - - # XChaCha20 requires a key derivation with HChaCha20 - # See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - if len(nonce) == 24: - key = _HChaCha20(key, nonce[:16]) - nonce = b'\x00' * 4 + nonce[16:] - self._name = "XChaCha20" - else: - self._name = "ChaCha20" - nonce = self.nonce - - self._next = ("encrypt", "decrypt") - - self._state = VoidPointer() - result = _raw_chacha20_lib.chacha20_init( - self._state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - nonce, - c_size_t(len(nonce))) - if result: - raise ValueError("Error %d instantiating a %s cipher" % (result, - self._name)) - self._state = SmartPointer(self._state.get(), - _raw_chacha20_lib.chacha20_destroy) - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("Cipher object can only be used for decryption") - self._next = ("encrypt",) - return self._encrypt(plaintext, output) - - def _encrypt(self, plaintext, output): - """Encrypt without FSM checks""" - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = _raw_chacha20_lib.chacha20_encrypt( - self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with %s" % (result, self._name)) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("Cipher object can only be used for encryption") - self._next = ("decrypt",) - - try: - return self._encrypt(ciphertext, output) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - def seek(self, position): - """Seek to a certain position in the key stream. - - If you want to seek to a certain block, - use ``seek(block_number * 64)``. - - Args: - position (integer): - The absolute position within the key stream, in bytes. - """ - - block_number, offset = divmod(position, 64) - block_low = block_number & 0xFFFFFFFF - block_high = block_number >> 32 - - result = _raw_chacha20_lib.chacha20_seek( - self._state.get(), - c_ulong(block_high), - c_ulong(block_low), - offset - ) - if result: - raise ValueError("Error %d while seeking with %s" % (result, self._name)) - - -def _derive_Poly1305_key_pair(key, nonce): - """Derive a tuple (r, s, nonce) for a Poly1305 MAC. - - If nonce is ``None``, a new 12-byte nonce is generated. - """ - - if len(key) != 32: - raise ValueError("Poly1305 with ChaCha20 requires a 32-byte key") - - if nonce is None: - padded_nonce = nonce = get_random_bytes(12) - elif len(nonce) == 8: - # See RFC7538, 2.6: [...] ChaCha20 as specified here requires a 96-bit - # nonce. So if the provided nonce is only 64-bit, then the first 32 - # bits of the nonce will be set to a constant number. - # This will usually be zero, but for protocols with multiple senders it may be - # different for each sender, but should be the same for all - # invocations of the function with the same key by a particular - # sender. - padded_nonce = b'\x00\x00\x00\x00' + nonce - elif len(nonce) == 12: - padded_nonce = nonce - else: - raise ValueError("Poly1305 with ChaCha20 requires an 8- or 12-byte nonce") - - rs = new(key=key, nonce=padded_nonce).encrypt(b'\x00' * 32) - return rs[:16], rs[16:], nonce - - -def new(**kwargs): - """Create a new ChaCha20 or XChaCha20 cipher - - Keyword Args: - key (bytes/bytearray/memoryview): The secret key to use. - It must be 32 bytes long. - nonce (bytes/bytearray/memoryview): A mandatory value that - must never be reused for any other encryption - done with this key. - - For ChaCha20, it must be 8 or 12 bytes long. - - For XChaCha20, it must be 24 bytes long. - - If not provided, 8 bytes will be randomly generated - (you can find them back in the ``nonce`` attribute). - - :Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Cipher` object - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter %s" % e) - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(8) - - if len(key) != 32: - raise ValueError("ChaCha20/XChaCha20 key must be 32 bytes long") - - if len(nonce) not in (8, 12, 24): - raise ValueError("Nonce must be 8/12 bytes(ChaCha20) or 24 bytes (XChaCha20)") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return ChaCha20Cipher(key, nonce) - -# Size of a data block (in bytes) -block_size = 1 - -# Size of a key (in bytes) -key_size = 32 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.pyi deleted file mode 100644 index f5001cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload, Optional - -Buffer = bytes|bytearray|memoryview - -def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ... - -class ChaCha20Cipher: - block_size: int - nonce: bytes - - def __init__(self, key: Buffer, nonce: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - def seek(self, position: int) -> None: ... - -def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Cipher: ... - -block_size: int -key_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.py deleted file mode 100644 index 2027b7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.py +++ /dev/null @@ -1,334 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Cipher import ChaCha20 -from Crypto.Cipher.ChaCha20 import _HChaCha20 -from Crypto.Hash import Poly1305, BLAKE2s - -from Crypto.Random import get_random_bytes - -from Crypto.Util.number import long_to_bytes -from Crypto.Util.py3compat import _copy_bytes, bord -from Crypto.Util._raw_api import is_buffer - - -def _enum(**enums): - return type('Enum', (), enums) - - -_CipherStatus = _enum(PROCESSING_AUTH_DATA=1, - PROCESSING_CIPHERTEXT=2, - PROCESSING_DONE=3) - - -class ChaCha20Poly1305Cipher(object): - """ChaCha20-Poly1305 and XChaCha20-Poly1305 cipher object. - Do not create it directly. Use :py:func:`new` instead. - - :var nonce: The nonce with length 8, 12 or 24 bytes - :vartype nonce: byte string - """ - - def __init__(self, key, nonce): - """Initialize a ChaCha20-Poly1305 AEAD cipher object - - See also `new()` at the module level.""" - - self._next = ("update", "encrypt", "decrypt", "digest", - "verify") - - self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20) - - self._cipher = ChaCha20.new(key=key, nonce=nonce) - self._cipher.seek(64) # Block counter starts at 1 - - self._len_aad = 0 - self._len_ct = 0 - self._mac_tag = None - self._status = _CipherStatus.PROCESSING_AUTH_DATA - - def update(self, data): - """Protect the associated data. - - Associated data (also known as *additional authenticated data* - AAD) - is the piece of the message that must stay in the clear, while - still allowing the receiver to verify its integrity. - An example is packet headers. - - The associated data (possibly split into multiple segments) is - fed into :meth:`update` before any call to :meth:`decrypt` or :meth:`encrypt`. - If there is no associated data, :meth:`update` is not called. - - :param bytes/bytearray/memoryview assoc_data: - A piece of associated data. There are no restrictions on its size. - """ - - if "update" not in self._next: - raise TypeError("update() method cannot be called") - - self._len_aad += len(data) - self._authenticator.update(data) - - def _pad_aad(self): - - assert(self._status == _CipherStatus.PROCESSING_AUTH_DATA) - if self._len_aad & 0x0F: - self._authenticator.update(b'\x00' * (16 - (self._len_aad & 0x0F))) - self._status = _CipherStatus.PROCESSING_CIPHERTEXT - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() method cannot be called") - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - self._next = ("encrypt", "digest") - - result = self._cipher.encrypt(plaintext, output=output) - self._len_ct += len(plaintext) - if output is None: - self._authenticator.update(result) - else: - self._authenticator.update(output) - return result - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() method cannot be called") - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - self._next = ("decrypt", "verify") - - self._len_ct += len(ciphertext) - self._authenticator.update(ciphertext) - return self._cipher.decrypt(ciphertext, output=output) - - def _compute_mac(self): - """Finalize the cipher (if not done already) and return the MAC.""" - - if self._mac_tag: - assert(self._status == _CipherStatus.PROCESSING_DONE) - return self._mac_tag - - assert(self._status != _CipherStatus.PROCESSING_DONE) - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - if self._len_ct & 0x0F: - self._authenticator.update(b'\x00' * (16 - (self._len_ct & 0x0F))) - - self._status = _CipherStatus.PROCESSING_DONE - - self._authenticator.update(long_to_bytes(self._len_aad, 8)[::-1]) - self._authenticator.update(long_to_bytes(self._len_ct, 8)[::-1]) - self._mac_tag = self._authenticator.digest() - return self._mac_tag - - def digest(self): - """Compute the *binary* authentication tag (MAC). - - :Return: the MAC tag, as 16 ``bytes``. - """ - - if "digest" not in self._next: - raise TypeError("digest() method cannot be called") - self._next = ("digest",) - - return self._compute_mac() - - def hexdigest(self): - """Compute the *printable* authentication tag (MAC). - - This method is like :meth:`digest`. - - :Return: the MAC tag, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* authentication tag (MAC). - - The receiver invokes this method at the very end, to - check if the associated data (if any) and the decrypted - messages are valid. - - :param bytes/bytearray/memoryview received_mac_tag: - This is the 16-byte *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = ("verify",) - - secret = get_random_bytes(16) - - self._compute_mac() - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, - data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, - data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* authentication tag (MAC). - - This method is like :meth:`verify`. - - :param string hex_mac_tag: - This is the *printable* MAC. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext): - """Perform :meth:`encrypt` and :meth:`digest` in one step. - - :param plaintext: The data to encrypt, of any size. - :type plaintext: bytes/bytearray/memoryview - :return: a tuple with two ``bytes`` objects: - - - the ciphertext, of equal length as the plaintext - - the 16-byte MAC tag - """ - - return self.encrypt(plaintext), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag): - """Perform :meth:`decrypt` and :meth:`verify` in one step. - - :param ciphertext: The piece of data to decrypt. - :type ciphertext: bytes/bytearray/memoryview - :param bytes received_mac_tag: - This is the 16-byte *binary* MAC, as received from the sender. - :return: the decrypted data (as ``bytes``) - :raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext) - self.verify(received_mac_tag) - return plaintext - - -def new(**kwargs): - """Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher. - - :keyword key: The secret key to use. It must be 32 bytes long. - :type key: byte string - - :keyword nonce: - A value that must never be reused for any other encryption - done with this key. - - For ChaCha20-Poly1305, it must be 8 or 12 bytes long. - - For XChaCha20-Poly1305, it must be 24 bytes long. - - If not provided, 12 ``bytes`` will be generated randomly - (you can find them back in the ``nonce`` attribute). - :type nonce: bytes, bytearray, memoryview - - :Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Poly1305Cipher` object - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter %s" % e) - - if len(key) != 32: - raise ValueError("Key must be 32 bytes long") - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(12) - - if len(nonce) in (8, 12): - chacha20_poly1305_nonce = nonce - elif len(nonce) == 24: - key = _HChaCha20(key, nonce[:16]) - chacha20_poly1305_nonce = b'\x00\x00\x00\x00' + nonce[16:] - else: - raise ValueError("Nonce must be 8, 12 or 24 bytes long") - - if not is_buffer(nonce): - raise TypeError("nonce must be bytes, bytearray or memoryview") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - cipher = ChaCha20Poly1305Cipher(key, chacha20_poly1305_nonce) - cipher.nonce = _copy_bytes(None, None, nonce) - return cipher - - -# Size of a key (in bytes) -key_size = 32 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.pyi deleted file mode 100644 index 109e805..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/ChaCha20_Poly1305.pyi +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union, Tuple, overload, Optional - -Buffer = bytes|bytearray|memoryview - -class ChaCha20Poly1305Cipher: - nonce: bytes - - def __init__(self, key: Buffer, nonce: Buffer) -> None: ... - def update(self, data: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, received_mac_tag: str) -> None: ... - def encrypt_and_digest(self, plaintext: Buffer) -> Tuple[bytes, bytes]: ... - def decrypt_and_verify(self, ciphertext: Buffer, received_mac_tag: Buffer) -> bytes: ... - -def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Poly1305Cipher: ... - -block_size: int -key_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.py deleted file mode 100644 index 5cc286a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/DES.py : DES -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -""" -Module's constants for the modes of operation supported with Single DES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_des_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_des", - """ - int DES_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int DES_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES_stop_operation(void *state); - """) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) != key_size: - raise ValueError("Incorrect DES key length (%d bytes)" % len(key)) - - start_operation = _raw_des_lib.DES_start_operation - stop_operation = _raw_des_lib.DES_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the DES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new DES cipher. - - :param key: - The secret key to use in the symmetric cipher. - It must be 8 byte long. The parity bits will be ignored. - :type key: bytes/bytearray/memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*byte string*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*byte string*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a DES object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = 8 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.pyi deleted file mode 100644 index dbcb5d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable, Optional - -Buffer = bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -DESMode = int - -MODE_ECB: DESMode -MODE_CBC: DESMode -MODE_CFB: DESMode -MODE_OFB: DESMode -MODE_CTR: DESMode -MODE_OPENPGP: DESMode -MODE_EAX: DESMode - -def new(key: Buffer, - mode: DESMode, - iv : Optional[Buffer] = ..., - IV : Optional[Buffer] = ..., - nonce : Optional[Buffer] = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.py deleted file mode 100644 index c0d9367..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/DES3.py : DES3 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -""" -Module's constants for the modes of operation supported with Triple DES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string, bchr, bord, bstr -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t) - -_raw_des3_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_des3", - """ - int DES3_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int DES3_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES3_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES3_stop_operation(void *state); - """) - - -def adjust_key_parity(key_in): - """Set the parity bits in a TDES key. - - :param key_in: the TDES key whose bits need to be adjusted - :type key_in: byte string - - :returns: a copy of ``key_in``, with the parity bits correctly set - :rtype: byte string - - :raises ValueError: if the TDES key is not 16 or 24 bytes long - :raises ValueError: if the TDES key degenerates into Single DES - """ - - def parity_byte(key_byte): - parity = 1 - for i in range(1, 8): - parity ^= (key_byte >> i) & 1 - return (key_byte & 0xFE) | parity - - if len(key_in) not in key_size: - raise ValueError("Not a valid TDES key") - - key_out = b"".join([ bchr(parity_byte(bord(x))) for x in key_in ]) - - if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]: - raise ValueError("Triple DES key degenerates to single DES") - - return key_out - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level base cipher. - It will absorb named parameters in the process.""" - - try: - key_in = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - key = adjust_key_parity(bstr(key_in)) - - start_operation = _raw_des3_lib.DES3_start_operation - stop_operation = _raw_des3_lib.DES3_stop_operation - - cipher = VoidPointer() - result = start_operation(key, - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the TDES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new Triple DES cipher. - - :param key: - The secret key to use in the symmetric cipher. - It must be 16 or 24 byte long. The parity bits will be ignored. - :type key: bytes/bytearray/memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a Triple DES object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = (16, 24) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.pyi deleted file mode 100644 index d4dd0bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/DES3.pyi +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Union, Dict, Tuple, Optional - -Buffer = bytes|bytearray|memoryview - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -def adjust_key_parity(key_in: bytes) -> bytes: ... - -DES3Mode = int - -MODE_ECB: DES3Mode -MODE_CBC: DES3Mode -MODE_CFB: DES3Mode -MODE_OFB: DES3Mode -MODE_CTR: DES3Mode -MODE_OPENPGP: DES3Mode -MODE_EAX: DES3Mode - -def new(key: Buffer, - mode: DES3Mode, - iv : Optional[Buffer] = ..., - IV : Optional[Buffer] = ..., - nonce : Optional[Buffer] = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Tuple[int, int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.py deleted file mode 100644 index e87487e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.py +++ /dev/null @@ -1,231 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Signature.pss import MGF1 -import Crypto.Hash.SHA1 - -from Crypto.Util.py3compat import _copy_bytes -import Crypto.Util.number -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Crypto.Util.strxor import strxor -from Crypto import Random -from ._pkcs1_oaep_decode import oaep_decode - - -class PKCS1OAEP_Cipher: - """Cipher object for PKCS#1 v1.5 OAEP. - Do not create directly: use :func:`new` instead.""" - - def __init__(self, key, hashAlgo, mgfunc, label, randfunc): - """Initialize this PKCS#1 OAEP cipher object. - - :Parameters: - key : an RSA key object - If a private half is given, both encryption and decryption are possible. - If a public half is given, only encryption is possible. - hashAlgo : hash object - The hash function to use. This can be a module under `Crypto.Hash` - or an existing hash object created from any of such modules. If not specified, - `Crypto.Hash.SHA1` is used. - mgfunc : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). - label : bytes/bytearray/memoryview - A label to apply to this particular encryption. If not specified, - an empty string is used. Specifying a label does not improve - security. - randfunc : callable - A function that returns random bytes. - - :attention: Modify the mask generation function only if you know what you are doing. - Sender and receiver must use the same one. - """ - self._key = key - - if hashAlgo: - self._hashObj = hashAlgo - else: - self._hashObj = Crypto.Hash.SHA1 - - if mgfunc: - self._mgf = mgfunc - else: - self._mgf = lambda x, y: MGF1(x, y, self._hashObj) - - self._label = _copy_bytes(None, None, label) - self._randfunc = randfunc - - def can_encrypt(self): - """Legacy function to check if you can call :meth:`encrypt`. - - .. deprecated:: 3.0""" - return self._key.can_encrypt() - - def can_decrypt(self): - """Legacy function to check if you can call :meth:`decrypt`. - - .. deprecated:: 3.0""" - return self._key.can_decrypt() - - def encrypt(self, message): - """Encrypt a message with PKCS#1 OAEP. - - :param message: - The message to encrypt, also known as plaintext. It can be of - variable length, but not longer than the RSA modulus (in bytes) - minus 2, minus twice the hash output size. - For instance, if you use RSA 2048 and SHA-256, the longest message - you can encrypt is 190 byte long. - :type message: bytes/bytearray/memoryview - - :returns: The ciphertext, as large as the RSA modulus. - :rtype: bytes - - :raises ValueError: - if the message is too long. - """ - - # See 7.1.1 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes - hLen = self._hashObj.digest_size - mLen = len(message) - - # Step 1b - ps_len = k - mLen - 2 * hLen - 2 - if ps_len < 0: - raise ValueError("Plaintext is too long.") - # Step 2a - lHash = self._hashObj.new(self._label).digest() - # Step 2b - ps = b'\x00' * ps_len - # Step 2c - db = lHash + ps + b'\x01' + _copy_bytes(None, None, message) - # Step 2d - ros = self._randfunc(hLen) - # Step 2e - dbMask = self._mgf(ros, k-hLen-1) - # Step 2f - maskedDB = strxor(db, dbMask) - # Step 2g - seedMask = self._mgf(maskedDB, hLen) - # Step 2h - maskedSeed = strxor(ros, seedMask) - # Step 2i - em = b'\x00' + maskedSeed + maskedDB - # Step 3a (OS2IP) - em_int = bytes_to_long(em) - # Step 3b (RSAEP) - m_int = self._key._encrypt(em_int) - # Step 3c (I2OSP) - c = long_to_bytes(m_int, k) - return c - - def decrypt(self, ciphertext): - """Decrypt a message with PKCS#1 OAEP. - - :param ciphertext: The encrypted message. - :type ciphertext: bytes/bytearray/memoryview - - :returns: The original message (plaintext). - :rtype: bytes - - :raises ValueError: - if the ciphertext has the wrong length, or if decryption - fails the integrity check (in which case, the decryption - key is probably wrong). - :raises TypeError: - if the RSA key has no private half (i.e. you are trying - to decrypt using a public key). - """ - - # See 7.1.2 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes - hLen = self._hashObj.digest_size - - # Step 1b and 1c - if len(ciphertext) != k or k < hLen+2: - raise ValueError("Ciphertext with incorrect length.") - # Step 2a (O2SIP) - ct_int = bytes_to_long(ciphertext) - # Step 2b (RSADP) and step 2c (I2OSP) - em = self._key._decrypt_to_bytes(ct_int) - # Step 3a - lHash = self._hashObj.new(self._label).digest() - # y must be 0, but we MUST NOT check it here in order not to - # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) - maskedSeed = em[1:hLen+1] - maskedDB = em[hLen+1:] - # Step 3c - seedMask = self._mgf(maskedDB, hLen) - # Step 3d - seed = strxor(maskedSeed, seedMask) - # Step 3e - dbMask = self._mgf(seed, k-hLen-1) - # Step 3f - db = strxor(maskedDB, dbMask) - # Step 3b + 3g - res = oaep_decode(em, lHash, db) - if res <= 0: - raise ValueError("Incorrect decryption.") - # Step 4 - return db[res:] - - -def new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None): - """Return a cipher object :class:`PKCS1OAEP_Cipher` - that can be used to perform PKCS#1 OAEP encryption or decryption. - - :param key: - The key object to use to encrypt or decrypt the message. - Decryption is only possible with a private RSA key. - :type key: RSA key object - - :param hashAlgo: - The hash function to use. This can be a module under `Crypto.Hash` - or an existing hash object created from any of such modules. - If not specified, `Crypto.Hash.SHA1` is used. - :type hashAlgo: hash object - - :param mgfunc: - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). - :type mgfunc: callable - - :param label: - A label to apply to this particular encryption. If not specified, - an empty string is used. Specifying a label does not improve - security. - :type label: bytes/bytearray/memoryview - - :param randfunc: - A function that returns random bytes. - The default is `Random.get_random_bytes`. - :type randfunc: callable - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label, randfunc) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.pyi deleted file mode 100644 index 6cb80da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_OAEP.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Optional, Union, Callable, Any, overload -from typing_extensions import Protocol - -from Crypto.PublicKey.RSA import RsaKey - -class HashLikeClass(Protocol): - digest_size : int - def new(self, data: Optional[bytes] = ...) -> Any: ... - -class HashLikeModule(Protocol): - digest_size : int - @staticmethod - def new(data: Optional[bytes] = ...) -> Any: ... - -HashLike = Union[HashLikeClass, HashLikeModule] - -Buffer = Union[bytes, bytearray, memoryview] - -class PKCS1OAEP_Cipher: - def __init__(self, - key: RsaKey, - hashAlgo: HashLike, - mgfunc: Callable[[bytes, int], bytes], - label: Buffer, - randfunc: Callable[[int], bytes]) -> None: ... - def can_encrypt(self) -> bool: ... - def can_decrypt(self) -> bool: ... - def encrypt(self, message: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer) -> bytes: ... - -def new(key: RsaKey, - hashAlgo: Optional[HashLike] = ..., - mgfunc: Optional[Callable[[bytes, int], bytes]] = ..., - label: Optional[Buffer] = ..., - randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS1OAEP_Cipher: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.py deleted file mode 100644 index ce30be6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['new', 'PKCS115_Cipher'] - -from Crypto import Random -from Crypto.Util.number import bytes_to_long, long_to_bytes -from Crypto.Util.py3compat import bord, is_bytes, _copy_bytes -from ._pkcs1_oaep_decode import pkcs1_decode - - -class PKCS115_Cipher: - """This cipher can perform PKCS#1 v1.5 RSA encryption or decryption. - Do not instantiate directly. Use :func:`Crypto.Cipher.PKCS1_v1_5.new` instead.""" - - def __init__(self, key, randfunc): - """Initialize this PKCS#1 v1.5 cipher object. - - :Parameters: - key : an RSA key object - If a private half is given, both encryption and decryption are possible. - If a public half is given, only encryption is possible. - randfunc : callable - Function that returns random bytes. - """ - - self._key = key - self._randfunc = randfunc - - def can_encrypt(self): - """Return True if this cipher object can be used for encryption.""" - return self._key.can_encrypt() - - def can_decrypt(self): - """Return True if this cipher object can be used for decryption.""" - return self._key.can_decrypt() - - def encrypt(self, message): - """Produce the PKCS#1 v1.5 encryption of a message. - - This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in - `section 7.2.1 of RFC8017 - `_. - - :param message: - The message to encrypt, also known as plaintext. It can be of - variable length, but not longer than the RSA modulus (in bytes) minus 11. - :type message: bytes/bytearray/memoryview - - :Returns: A byte string, the ciphertext in which the message is encrypted. - It is as long as the RSA modulus (in bytes). - - :Raises ValueError: - If the RSA key length is not sufficiently long to deal with the given - message. - """ - - # See 7.2.1 in RFC8017 - k = self._key.size_in_bytes() - mLen = len(message) - - # Step 1 - if mLen > k - 11: - raise ValueError("Plaintext is too long.") - # Step 2a - ps = [] - while len(ps) != k - mLen - 3: - new_byte = self._randfunc(1) - if bord(new_byte[0]) == 0x00: - continue - ps.append(new_byte) - ps = b"".join(ps) - # Step 2b - em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) - # Step 3a (OS2IP) - em_int = bytes_to_long(em) - # Step 3b (RSAEP) - m_int = self._key._encrypt(em_int) - # Step 3c (I2OSP) - c = long_to_bytes(m_int, k) - return c - - def decrypt(self, ciphertext, sentinel, expected_pt_len=0): - r"""Decrypt a PKCS#1 v1.5 ciphertext. - - This is the function ``RSAES-PKCS1-V1_5-DECRYPT`` specified in - `section 7.2.2 of RFC8017 - `_. - - Args: - ciphertext (bytes/bytearray/memoryview): - The ciphertext that contains the message to recover. - sentinel (any type): - The object to return whenever an error is detected. - expected_pt_len (integer): - The length the plaintext is known to have, or 0 if unknown. - - Returns (byte string): - It is either the original message or the ``sentinel`` (in case of an error). - - .. warning:: - PKCS#1 v1.5 decryption is intrinsically vulnerable to timing - attacks (see `Bleichenbacher's`__ attack). - **Use PKCS#1 OAEP instead**. - - This implementation attempts to mitigate the risk - with some constant-time constructs. - However, they are not sufficient by themselves: the type of protocol you - implement and the way you handle errors make a big difference. - - Specifically, you should make it very hard for the (malicious) - party that submitted the ciphertext to quickly understand if decryption - succeeded or not. - - To this end, it is recommended that your protocol only encrypts - plaintexts of fixed length (``expected_pt_len``), - that ``sentinel`` is a random byte string of the same length, - and that processing continues for as long - as possible even if ``sentinel`` is returned (i.e. in case of - incorrect decryption). - - .. __: https://dx.doi.org/10.1007/BFb0055716 - """ - - # See 7.2.2 in RFC8017 - k = self._key.size_in_bytes() - - # Step 1 - if len(ciphertext) != k: - raise ValueError("Ciphertext with incorrect length (not %d bytes)" % k) - - # Step 2a (O2SIP) - ct_int = bytes_to_long(ciphertext) - - # Step 2b (RSADP) and Step 2c (I2OSP) - em = self._key._decrypt_to_bytes(ct_int) - - # Step 3 (not constant time when the sentinel is not a byte string) - output = bytes(bytearray(k)) - if not is_bytes(sentinel) or len(sentinel) > k: - size = pkcs1_decode(em, b'', expected_pt_len, output) - if size < 0: - return sentinel - else: - return output[size:] - - # Step 3 (somewhat constant time) - size = pkcs1_decode(em, sentinel, expected_pt_len, output) - return output[size:] - - -def new(key, randfunc=None): - """Create a cipher for performing PKCS#1 v1.5 encryption or decryption. - - :param key: - The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object. - Decryption is only possible if *key* is a private RSA key. - :type key: RSA key object - - :param randfunc: - Function that return random bytes. - The default is :func:`Crypto.Random.get_random_bytes`. - :type randfunc: callable - - :returns: A cipher object `PKCS115_Cipher`. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - return PKCS115_Cipher(key, randfunc) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.pyi deleted file mode 100644 index 1719f01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/PKCS1_v1_5.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Callable, Union, Any, Optional, TypeVar - -from Crypto.PublicKey.RSA import RsaKey - -Buffer = Union[bytes, bytearray, memoryview] -T = TypeVar('T') - -class PKCS115_Cipher: - def __init__(self, - key: RsaKey, - randfunc: Callable[[int], bytes]) -> None: ... - def can_encrypt(self) -> bool: ... - def can_decrypt(self) -> bool: ... - def encrypt(self, message: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer, - sentinel: T, - expected_pt_len: Optional[int] = ...) -> Union[bytes, T]: ... - -def new(key: RsaKey, - randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS115_Cipher: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.py deleted file mode 100644 index 62d0b29..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/Salsa20.py : Salsa20 stream cipher (http://cr.yp.to/snuffle.html) -# -# Contributed by Fabrizio Tarizzo . -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, VoidPointer, - SmartPointer, c_size_t, - c_uint8_ptr, is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -_raw_salsa20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._Salsa20", - """ - int Salsa20_stream_init(uint8_t *key, size_t keylen, - uint8_t *nonce, size_t nonce_len, - void **pSalsaState); - int Salsa20_stream_destroy(void *salsaState); - int Salsa20_stream_encrypt(void *salsaState, - const uint8_t in[], - uint8_t out[], size_t len); - """) - - -class Salsa20Cipher: - """Salsa20 cipher object. Do not create it directly. Use :py:func:`new` - instead. - - :var nonce: The nonce with length 8 - :vartype nonce: byte string - """ - - def __init__(self, key, nonce): - """Initialize a Salsa20 cipher object - - See also `new()` at the module level.""" - - if len(key) not in key_size: - raise ValueError("Incorrect key length for Salsa20 (%d bytes)" % len(key)) - - if len(nonce) != 8: - raise ValueError("Incorrect nonce length for Salsa20 (%d bytes)" % - len(nonce)) - - self.nonce = _copy_bytes(None, None, nonce) - - self._state = VoidPointer() - result = _raw_salsa20_lib.Salsa20_stream_init( - c_uint8_ptr(key), - c_size_t(len(key)), - c_uint8_ptr(nonce), - c_size_t(len(nonce)), - self._state.address_of()) - if result: - raise ValueError("Error %d instantiating a Salsa20 cipher") - self._state = SmartPointer(self._state.get(), - _raw_salsa20_lib.Salsa20_stream_destroy) - - self.block_size = 1 - self.key_size = len(key) - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = _raw_salsa20_lib.Salsa20_stream_encrypt( - self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with Salsa20" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - try: - return self.encrypt(ciphertext, output=output) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - -def new(key, nonce=None): - """Create a new Salsa20 cipher - - :keyword key: The secret key to use. It must be 16 or 32 bytes long. - :type key: bytes/bytearray/memoryview - - :keyword nonce: - A value that must never be reused for any other encryption - done with this key. It must be 8 bytes long. - - If not provided, a random byte string will be generated (you can read - it back via the ``nonce`` attribute of the returned object). - :type nonce: bytes/bytearray/memoryview - - :Return: a :class:`Crypto.Cipher.Salsa20.Salsa20Cipher` object - """ - - if nonce is None: - nonce = get_random_bytes(8) - - return Salsa20Cipher(key, nonce) - -# Size of a data block (in bytes) -block_size = 1 - -# Size of a key (in bytes) -key_size = (16, 32) - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.pyi deleted file mode 100644 index cf8690e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/Salsa20.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union, Tuple, Optional, overload, Optional - -Buffer = bytes|bytearray|memoryview - -class Salsa20Cipher: - nonce: bytes - block_size: int - key_size: int - - def __init__(self, - key: Buffer, - nonce: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - -def new(key: Buffer, nonce: Optional[Buffer] = ...) -> Salsa20Cipher: ... - -block_size: int -key_size: Tuple[int, int] - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_ARC4.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_ARC4.abi3.so deleted file mode 100755 index f1bd5ef..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_ARC4.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.py deleted file mode 100644 index a844fae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.py +++ /dev/null @@ -1,131 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2019, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, c_size_t, - c_uint8_ptr, c_uint) - -_raw_blowfish_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_eksblowfish", - """ - int EKSBlowfish_start_operation(const uint8_t key[], - size_t key_len, - const uint8_t salt[16], - size_t salt_len, - unsigned cost, - unsigned invert, - void **pResult); - int EKSBlowfish_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int EKSBlowfish_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int EKSBlowfish_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a smart pointer to - a low-level base cipher. It will absorb named parameters in - the process.""" - - try: - key = dict_parameters.pop("key") - salt = dict_parameters.pop("salt") - cost = dict_parameters.pop("cost") - except KeyError as e: - raise TypeError("Missing EKSBlowfish parameter: " + str(e)) - invert = dict_parameters.pop("invert", True) - - if len(key) not in key_size: - raise ValueError("Incorrect EKSBlowfish key length (%d bytes)" % len(key)) - - start_operation = _raw_blowfish_lib.EKSBlowfish_start_operation - stop_operation = _raw_blowfish_lib.EKSBlowfish_stop_operation - - void_p = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - c_uint8_ptr(salt), - c_size_t(len(salt)), - c_uint(cost), - c_uint(int(invert)), - void_p.address_of()) - if result: - raise ValueError("Error %X while instantiating the EKSBlowfish cipher" - % result) - return SmartPointer(void_p.get(), stop_operation) - - -def new(key, mode, salt, cost, invert): - """Create a new EKSBlowfish cipher - - Args: - - key (bytes, bytearray, memoryview): - The secret key to use in the symmetric cipher. - Its length can vary from 0 to 72 bytes. - - mode (one of the supported ``MODE_*`` constants): - The chaining mode to use for encryption or decryption. - - salt (bytes, bytearray, memoryview): - The salt that bcrypt uses to thwart rainbow table attacks - - cost (integer): - The complexity factor in bcrypt - - invert (bool): - If ``False``, in the inner loop use ``ExpandKey`` first over the salt - and then over the key, as defined in - the `original bcrypt specification `_. - If ``True``, reverse the order, as in the first implementation of - `bcrypt` in OpenBSD. - - :Return: an EKSBlowfish object - """ - - kwargs = { 'salt':salt, 'cost':cost, 'invert':invert } - return _create_cipher(sys.modules[__name__], key, mode, **kwargs) - - -MODE_ECB = 1 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(0, 72 + 1) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.pyi deleted file mode 100644 index 95db379..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_EKSBlowfish.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode - -MODE_ECB: int - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: int, - salt: Buffer, - cost: int) -> EcbMode: ... - -block_size: int -key_size: Iterable[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_Salsa20.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_Salsa20.abi3.so deleted file mode 100755 index 402ea16..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_Salsa20.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/__init__.py deleted file mode 100644 index 5770923..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# A block cipher is instantiated as a combination of: -# 1. A base cipher (such as AES) -# 2. A mode of operation (such as CBC) -# -# Both items are implemented as C modules. -# -# The API of #1 is (replace "AES" with the name of the actual cipher): -# - AES_start_operaion(key) --> base_cipher_state -# - AES_encrypt(base_cipher_state, in, out, length) -# - AES_decrypt(base_cipher_state, in, out, length) -# - AES_stop_operation(base_cipher_state) -# -# Where base_cipher_state is AES_State, a struct with BlockBase (set of -# pointers to encrypt/decrypt/stop) followed by cipher-specific data. -# -# The API of #2 is (replace "CBC" with the name of the actual mode): -# - CBC_start_operation(base_cipher_state) --> mode_state -# - CBC_encrypt(mode_state, in, out, length) -# - CBC_decrypt(mode_state, in, out, length) -# - CBC_stop_operation(mode_state) -# -# where mode_state is a a pointer to base_cipher_state plus mode-specific data. - -def _create_cipher(factory, key, mode, *args, **kwargs): - - kwargs["key"] = key - - if args: - if mode in (8, 9, 10, 11, 12): - if len(args) > 1: - raise TypeError("Too many arguments for this mode") - kwargs["nonce"] = args[0] - elif mode in (2, 3, 5, 7): - if len(args) > 1: - raise TypeError("Too many arguments for this mode") - kwargs["IV"] = args[0] - elif mode == 6: - if len(args) > 0: - raise TypeError("Too many arguments for this mode") - elif mode == 1: - raise TypeError("IV is not meaningful for the ECB mode") - - res = None - extra_modes = kwargs.pop("add_aes_modes", False) - - if mode == 1: - from Crypto.Cipher._mode_ecb import _create_ecb_cipher - res = _create_ecb_cipher(factory, **kwargs) - elif mode == 2: - from Crypto.Cipher._mode_cbc import _create_cbc_cipher - res = _create_cbc_cipher(factory, **kwargs) - elif mode == 3: - from Crypto.Cipher._mode_cfb import _create_cfb_cipher - res = _create_cfb_cipher(factory, **kwargs) - elif mode == 5: - from Crypto.Cipher._mode_ofb import _create_ofb_cipher - res = _create_ofb_cipher(factory, **kwargs) - elif mode == 6: - from Crypto.Cipher._mode_ctr import _create_ctr_cipher - res = _create_ctr_cipher(factory, **kwargs) - elif mode == 7: - from Crypto.Cipher._mode_openpgp import _create_openpgp_cipher - res = _create_openpgp_cipher(factory, **kwargs) - elif mode == 9: - from Crypto.Cipher._mode_eax import _create_eax_cipher - res = _create_eax_cipher(factory, **kwargs) - elif extra_modes: - if mode == 8: - from Crypto.Cipher._mode_ccm import _create_ccm_cipher - res = _create_ccm_cipher(factory, **kwargs) - elif mode == 10: - from Crypto.Cipher._mode_siv import _create_siv_cipher - res = _create_siv_cipher(factory, **kwargs) - elif mode == 11: - from Crypto.Cipher._mode_gcm import _create_gcm_cipher - res = _create_gcm_cipher(factory, **kwargs) - elif mode == 12: - from Crypto.Cipher._mode_ocb import _create_ocb_cipher - res = _create_ocb_cipher(factory, **kwargs) - elif mode == 13: - from Crypto.Cipher._mode_kw import _create_kw_cipher - res = _create_kw_cipher(factory, **kwargs) - elif mode == 14: - from Crypto.Cipher._mode_kwp import _create_kwp_cipher - res = _create_kwp_cipher(factory, **kwargs) - - if res is None: - raise ValueError("Mode not supported") - - return res diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/__init__.pyi deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_chacha20.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_chacha20.abi3.so deleted file mode 100755 index 7e70185..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_chacha20.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.py deleted file mode 100644 index 36c78ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.py +++ /dev/null @@ -1,293 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Ciphertext Block Chaining (CBC) mode. -""" - -__all__ = ['CbcMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_cbc_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_cbc", """ - int CBC_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - void **pResult); - int CBC_encrypt(void *cbcState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CBC_decrypt(void *cbcState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CBC_stop_operation(void *state); - """ - ) - - -class CbcMode(object): - """*Cipher-Block Chaining (CBC)*. - - Each of the ciphertext blocks depends on the current - and all previous plaintext blocks. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.2 . - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv): - """Create a new block cipher, configured in CBC mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be unpredictable**. Ideally it is picked randomly. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - """ - - self._state = VoidPointer() - result = raw_cbc_lib.CBC_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the CBC mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_cbc_lib.CBC_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = ["encrypt", "decrypt"] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - That also means that you cannot reuse an object for encrypting - or decrypting other data with the same key. - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - Its lenght must be multiple of the cipher block size. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = ["encrypt"] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cbc_lib.CBC_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 3: - raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) - raise ValueError("Error %d while encrypting in CBC mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - Its length must be multiple of the cipher block size. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = ["decrypt"] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cbc_lib.CBC_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 3: - raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) - raise ValueError("Error %d while decrypting in CBC mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_cbc_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CBC encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for CBC. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - if kwargs: - raise TypeError("Unknown parameters for CBC: %s" % str(kwargs)) - - return CbcMode(cipher_state, iv) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.pyi deleted file mode 100644 index 8b9fb16..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CbcMode'] - -class CbcMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.py deleted file mode 100644 index e4ffd0d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.py +++ /dev/null @@ -1,671 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Counter with CBC-MAC (CCM) mode. -""" - -__all__ = ['CcmMode'] - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import (byte_string, bord, - _copy_bytes) -from Crypto.Util._raw_api import is_writeable_buffer - -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - - -def enum(**enums): - return type('Enum', (), enums) - -MacStatus = enum(NOT_STARTED=0, PROCESSING_AUTH_DATA=1, PROCESSING_PLAINTEXT=2) - - -class CCMMessageTooLongError(ValueError): - pass - - -class CcmMode(object): - """Counter with CBC-MAC (CCM). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - This mode requires a nonce. The nonce shall never repeat for two - different messages encrypted with the same key, but it does not need - to be random. - Note that there is a trade-off between the size of the nonce and the - maximum size of a single message you can encrypt. - - It is important to use a large nonce if the key is reused across several - messages and the nonce is chosen randomly. - - It is acceptable to us a short nonce if the key is only used a few times or - if the nonce is taken from a counter. - - The following table shows the trade-off when the nonce is chosen at - random. The column on the left shows how many messages it takes - for the keystream to repeat **on average**. In practice, you will want to - stop using the key way before that. - - +--------------------+---------------+-------------------+ - | Avg. # of messages | nonce | Max. message | - | before keystream | size | size | - | repeats | (bytes) | (bytes) | - +====================+===============+===================+ - | 2^52 | 13 | 64K | - +--------------------+---------------+-------------------+ - | 2^48 | 12 | 16M | - +--------------------+---------------+-------------------+ - | 2^44 | 11 | 4G | - +--------------------+---------------+-------------------+ - | 2^40 | 10 | 1T | - +--------------------+---------------+-------------------+ - | 2^36 | 9 | 64P | - +--------------------+---------------+-------------------+ - | 2^32 | 8 | 16E | - +--------------------+---------------+-------------------+ - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g. AES but not TDES). - - See `NIST SP800-38C`_ or RFC3610_. - - .. _`NIST SP800-38C`: http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C.pdf - .. _RFC3610: https://tools.ietf.org/html/rfc3610 - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, msg_len, assoc_len, - cipher_params): - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """The nonce used for this cipher instance""" - - self._factory = factory - self._key = _copy_bytes(None, None, key) - self._mac_len = mac_len - self._msg_len = msg_len - self._assoc_len = assoc_len - self._cipher_params = cipher_params - - self._mac_tag = None # Cache for MAC tag - - if self.block_size != 16: - raise ValueError("CCM mode is only available for ciphers" - " that operate on 128 bits blocks") - - # MAC tag length (Tlen) - if mac_len not in (4, 6, 8, 10, 12, 14, 16): - raise ValueError("Parameter 'mac_len' must be even" - " and in the range 4..16 (not %d)" % mac_len) - - # Nonce value - if not (7 <= len(nonce) <= 13): - raise ValueError("Length of parameter 'nonce' must be" - " in the range 7..13 bytes") - - # Message length (if known already) - q = 15 - len(nonce) # length of Q, the encoded message length - if msg_len and len(long_to_bytes(msg_len)) > q: - raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(nonce)) - - # Create MAC object (the tag will be the last block - # bytes worth of ciphertext) - self._mac = self._factory.new(key, - factory.MODE_CBC, - iv=b'\x00' * 16, - **cipher_params) - self._mac_status = MacStatus.NOT_STARTED - self._t = None - - # Allowed transitions after initialization - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - # Cumulative lengths - self._cumul_assoc_len = 0 - self._cumul_msg_len = 0 - - # Cache for unaligned associated data/plaintext. - # This is a list with byte strings, but when the MAC starts, - # it will become a binary string no longer than the block size. - self._cache = [] - - # Start CTR cipher, by formatting the counter (A.3) - self._cipher = self._factory.new(key, - self._factory.MODE_CTR, - nonce=struct.pack("B", q - 1) + self.nonce, - **cipher_params) - - # S_0, step 6 in 6.1 for j=0 - self._s_0 = self._cipher.encrypt(b'\x00' * 16) - - # Try to start the MAC - if None not in (assoc_len, msg_len): - self._start_mac() - - def _start_mac(self): - - assert(self._mac_status == MacStatus.NOT_STARTED) - assert(None not in (self._assoc_len, self._msg_len)) - assert(isinstance(self._cache, list)) - - # Formatting control information and nonce (A.2.1) - q = 15 - len(self.nonce) # length of Q, the encoded message length (2..8) - flags = (self._assoc_len > 0) << 6 - flags |= ((self._mac_len - 2) // 2) << 3 - flags |= q - 1 - b_0 = struct.pack("B", flags) + self.nonce + long_to_bytes(self._msg_len, q) - - # Formatting associated data (A.2.2) - # Encoded 'a' is concatenated with the associated data 'A' - assoc_len_encoded = b'' - if self._assoc_len > 0: - if self._assoc_len < (2 ** 16 - 2 ** 8): - enc_size = 2 - elif self._assoc_len < (2 ** 32): - assoc_len_encoded = b'\xFF\xFE' - enc_size = 4 - else: - assoc_len_encoded = b'\xFF\xFF' - enc_size = 8 - assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size) - - # b_0 and assoc_len_encoded must be processed first - self._cache.insert(0, b_0) - self._cache.insert(1, assoc_len_encoded) - - # Process all the data cached so far - first_data_to_mac = b"".join(self._cache) - self._cache = b"" - self._mac_status = MacStatus.PROCESSING_AUTH_DATA - self._update(first_data_to_mac) - - def _pad_cache_and_update(self): - - assert(self._mac_status != MacStatus.NOT_STARTED) - assert(len(self._cache) < self.block_size) - - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - len_cache = len(self._cache) - if len_cache > 0: - self._update(b'\x00' * (self.block_size - len_cache)) - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - In CCM, the *associated data* is also called - *additional authenticated data* (AAD). - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if "update" not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - self._cumul_assoc_len += len(assoc_data) - if self._assoc_len is not None and \ - self._cumul_assoc_len > self._assoc_len: - raise ValueError("Associated data is too long") - - self._update(assoc_data) - return self - - def _update(self, assoc_data_pt=b""): - """Update the MAC with associated data or plaintext - (without FSM checks)""" - - # If MAC has not started yet, we just park the data into a list. - # If the data is mutable, we create a copy and store that instead. - if self._mac_status == MacStatus.NOT_STARTED: - if is_writeable_buffer(assoc_data_pt): - assoc_data_pt = _copy_bytes(None, None, assoc_data_pt) - self._cache.append(assoc_data_pt) - return - - assert(len(self._cache) < self.block_size) - - if len(self._cache) > 0: - filler = min(self.block_size - len(self._cache), - len(assoc_data_pt)) - self._cache += _copy_bytes(None, filler, assoc_data_pt) - assoc_data_pt = _copy_bytes(filler, None, assoc_data_pt) - - if len(self._cache) < self.block_size: - return - - # The cache is exactly one block - self._t = self._mac.encrypt(self._cache) - self._cache = b"" - - update_len = len(assoc_data_pt) // self.block_size * self.block_size - self._cache = _copy_bytes(update_len, None, assoc_data_pt) - if update_len > 0: - self._t = self._mac.encrypt(assoc_data_pt[:update_len])[-16:] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - This method can be called only **once** if ``msg_len`` was - not passed at initialization. - - If ``msg_len`` was given, the data to encrypt can be broken - up in two or more pieces and `encrypt` can be called - multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = ["encrypt", "digest"] - - # No more associated data allowed from now - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - # Only once piece of plaintext accepted if message length was - # not declared in advance - if self._msg_len is None: - q = 15 - len(self.nonce) - if len(long_to_bytes(len(plaintext))) > q: - raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(self.nonce)) - - self._msg_len = len(plaintext) - self._start_mac() - self._next = ["digest"] - - self._cumul_msg_len += len(plaintext) - if self._cumul_msg_len > self._msg_len: - msg = "Message longer than declared for (%u bytes vs %u bytes" % \ - (self._cumul_msg_len, self._msg_len) - raise CCMMessageTooLongError(msg) - - if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - self._pad_cache_and_update() - self._mac_status = MacStatus.PROCESSING_PLAINTEXT - - self._update(plaintext) - return self._cipher.encrypt(plaintext, output=output) - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - This method can be called only **once** if ``msg_len`` was - not passed at initialization. - - If ``msg_len`` was given, the data to decrypt can be - broken up in two or more pieces and `decrypt` can be - called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = ["decrypt", "verify"] - - # No more associated data allowed from now - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - # Only once piece of ciphertext accepted if message length was - # not declared in advance - if self._msg_len is None: - q = 15 - len(self.nonce) - if len(long_to_bytes(len(ciphertext))) > q: - raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(self.nonce)) - - self._msg_len = len(ciphertext) - self._start_mac() - self._next = ["verify"] - - self._cumul_msg_len += len(ciphertext) - if self._cumul_msg_len > self._msg_len: - msg = "Message longer than declared for (%u bytes vs %u bytes" % \ - (self._cumul_msg_len, self._msg_len) - raise CCMMessageTooLongError(msg) - - if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - self._pad_cache_and_update() - self._mac_status = MacStatus.PROCESSING_PLAINTEXT - - # Encrypt is equivalent to decrypt with the CTR mode - plaintext = self._cipher.encrypt(ciphertext, output=output) - if output is None: - self._update(plaintext) - else: - self._update(output) - return plaintext - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if "digest" not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = ["digest"] - return self._digest() - - def _digest(self): - if self._mac_tag: - return self._mac_tag - - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - if self._msg_len is None: - self._msg_len = 0 - self._start_mac() - - if self._cumul_msg_len != self._msg_len: - raise ValueError("Message is too short") - - # Both associated data and payload are concatenated with the least - # number of zero bytes (possibly none) that align it to the - # 16 byte boundary (A.2.2 and A.2.3) - self._pad_cache_and_update() - - # Step 8 in 6.1 (T xor MSB_Tlen(S_0)) - self._mac_tag = strxor(self._t, self._s_0)[:self._mac_len] - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = ["verify"] - - self._digest() - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return plaintext - - -def _create_ccm_cipher(factory, **kwargs): - """Create a new block cipher, configured in CCM mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` (like - `Crypto.Cipher.AES`). - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - - Its length must be in the range ``[7..13]``. - 11 or 12 bytes are reasonable values in general. Bear in - mind that with CCM there is a trade-off between nonce length and - maximum message size. - - If not specified, a 11 byte long random string is used. - - mac_len : integer - Length of the MAC, in bytes. It must be even and in - the range ``[4..16]``. The default is 16. - - msg_len : integer - Length of the message to (de)cipher. - If not specified, ``encrypt`` or ``decrypt`` may only be called once. - - assoc_len : integer - Length of the associated data. - If not specified, all data is internally buffered. - """ - - try: - key = key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - nonce = kwargs.pop("nonce", None) # N - if nonce is None: - nonce = get_random_bytes(11) - mac_len = kwargs.pop("mac_len", factory.block_size) - msg_len = kwargs.pop("msg_len", None) # p - assoc_len = kwargs.pop("assoc_len", None) # a - cipher_params = dict(kwargs) - - return CcmMode(factory, key, nonce, mac_len, msg_len, - assoc_len, cipher_params) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.pyi deleted file mode 100644 index 98af96a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ccm.pyi +++ /dev/null @@ -1,52 +0,0 @@ -from types import ModuleType -from typing import Union, overload, Dict, Tuple, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CcmMode'] - - -class CCMMessageTooLongError(ValueError): - pass - - -class CcmMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - msg_len: Optional[int], - assoc_len: Optional[int], - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> CcmMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.py deleted file mode 100644 index 482e44c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.py +++ /dev/null @@ -1,293 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_cfb.py : CFB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -""" -Counter Feedback (CFB) mode. -""" - -__all__ = ['CfbMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_cfb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_cfb",""" - int CFB_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - size_t segment_len, /* In bytes */ - void **pResult); - int CFB_encrypt(void *cfbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CFB_decrypt(void *cfbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CFB_stop_operation(void *state);""" - ) - - -class CfbMode(object): - """*Cipher FeedBack (CFB)*. - - This mode is similar to CFB, but it transforms - the underlying block cipher into a stream cipher. - - Plaintext and ciphertext are processed in *segments* - of **s** bits. The mode is therefore sometimes - labelled **s**-bit CFB. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.3. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv, segment_size): - """Create a new block cipher, configured in CFB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be unpredictable**. Ideally it is picked randomly. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - - segment_size : integer - The number of bytes the plaintext and ciphertext are segmented in. - """ - - self._state = VoidPointer() - result = raw_cfb_lib.CFB_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - c_size_t(segment_size), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the CFB mode" % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_cfb_lib.CFB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = ["encrypt", "decrypt"] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = ["encrypt"] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cfb_lib.CFB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting in CFB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = ["decrypt"] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cfb_lib.CFB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - raise ValueError("Error %d while decrypting in CFB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_cfb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CFB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for CFB. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - segment_size : integer - The number of bit the plaintext and ciphertext are segmented in. - If not present, the default is 8. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - segment_size_bytes, rem = divmod(kwargs.pop("segment_size", 8), 8) - if segment_size_bytes == 0 or rem != 0: - raise ValueError("'segment_size' must be positive and multiple of 8 bits") - - if kwargs: - raise TypeError("Unknown parameters for CFB: %s" % str(kwargs)) - return CfbMode(cipher_state, iv, segment_size_bytes) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.pyi deleted file mode 100644 index e13a909..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_cfb.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CfbMode'] - - -class CfbMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer, - segment_size: int) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.py deleted file mode 100644 index 81f2be9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.py +++ /dev/null @@ -1,393 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ctr.py : CTR mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -""" -Counter (CTR) mode. -""" - -__all__ = ['CtrMode'] - -import struct - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes -from Crypto.Util.py3compat import _copy_bytes, is_native_int -from Crypto.Util.number import long_to_bytes - -raw_ctr_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ctr", """ - int CTR_start_operation(void *cipher, - uint8_t initialCounterBlock[], - size_t initialCounterBlock_len, - size_t prefix_len, - unsigned counter_len, - unsigned littleEndian, - void **pResult); - int CTR_encrypt(void *ctrState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CTR_decrypt(void *ctrState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CTR_stop_operation(void *ctrState);""" - ) - - -class CtrMode(object): - """*CounTeR (CTR)* mode. - - This mode is very similar to ECB, in that - encryption of one block is done independently of all other blocks. - - Unlike ECB, the block *position* contributes to the encryption - and no information leaks about symbol frequency. - - Each message block is associated to a *counter* which - must be unique across all messages that get encrypted - with the same key (not just within the same message). - The counter is as big as the block size. - - Counters can be generated in several ways. The most - straightword one is to choose an *initial counter block* - (which can be made public, similarly to the *IV* for the - other modes) and increment its lowest **m** bits by one - (modulo *2^m*) for each block. In most cases, **m** is - chosen to be half the block size. - - See `NIST SP800-38A`_, Section 6.5 (for the mode) and - Appendix B (for how to manage the *initial counter block*). - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, initial_counter_block, - prefix_len, counter_len, little_endian): - """Create a new block cipher, configured in CTR mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - initial_counter_block : bytes/bytearray/memoryview - The initial plaintext to use to generate the key stream. - - It is as large as the cipher block, and it embeds - the initial value of the counter. - - This value must not be reused. - It shall contain a nonce or a random component. - Reusing the *initial counter block* for encryptions - performed with the same key compromises confidentiality. - - prefix_len : integer - The amount of bytes at the beginning of the counter block - that never change. - - counter_len : integer - The length in bytes of the counter embedded in the counter - block. - - little_endian : boolean - True if the counter in the counter block is an integer encoded - in little endian mode. If False, it is big endian. - """ - - if len(initial_counter_block) == prefix_len + counter_len: - self.nonce = _copy_bytes(None, prefix_len, initial_counter_block) - """Nonce; not available if there is a fixed suffix""" - - self._state = VoidPointer() - result = raw_ctr_lib.CTR_start_operation(block_cipher.get(), - c_uint8_ptr(initial_counter_block), - c_size_t(len(initial_counter_block)), - c_size_t(prefix_len), - counter_len, - little_endian, - self._state.address_of()) - if result: - raise ValueError("Error %X while instantiating the CTR mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_ctr_lib.CTR_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(initial_counter_block) - """The block size of the underlying cipher, in bytes.""" - - self._next = ["encrypt", "decrypt"] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = ["encrypt"] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ctr_lib.CTR_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 0x60002: - raise OverflowError("The counter has wrapped around in" - " CTR mode") - raise ValueError("Error %X while encrypting in CTR mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = ["decrypt"] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ctr_lib.CTR_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 0x60002: - raise OverflowError("The counter has wrapped around in" - " CTR mode") - raise ValueError("Error %X while decrypting in CTR mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ctr_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CTR encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - nonce : bytes/bytearray/memoryview - The fixed part at the beginning of the counter block - the rest is - the counter number that gets increased when processing the next block. - The nonce must be such that no two messages are encrypted under the - same key and the same nonce. - - The nonce must be shorter than the block size (it can have - zero length; the counter is then as long as the block). - - If this parameter is not present, a random nonce will be created with - length equal to half the block size. No random nonce shorter than - 64 bits will be created though - you must really think through all - security consequences of using such a short block size. - - initial_value : posive integer or bytes/bytearray/memoryview - The initial value for the counter. If not present, the cipher will - start counting from 0. The value is incremented by one for each block. - The counter number is encoded in big endian mode. - - counter : object - Instance of ``Crypto.Util.Counter``, which allows full customization - of the counter block. This parameter is incompatible to both ``nonce`` - and ``initial_value``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - - counter = kwargs.pop("counter", None) - nonce = kwargs.pop("nonce", None) - initial_value = kwargs.pop("initial_value", None) - if kwargs: - raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) - - if counter is not None and (nonce, initial_value) != (None, None): - raise TypeError("'counter' and 'nonce'/'initial_value'" - " are mutually exclusive") - - if counter is None: - # Crypto.Util.Counter is not used - if nonce is None: - if factory.block_size < 16: - raise TypeError("Impossible to create a safe nonce for short" - " block sizes") - nonce = get_random_bytes(factory.block_size // 2) - else: - if len(nonce) >= factory.block_size: - raise ValueError("Nonce is too long") - - # What is not nonce is counter - counter_len = factory.block_size - len(nonce) - - if initial_value is None: - initial_value = 0 - - if is_native_int(initial_value): - if (1 << (counter_len * 8)) - 1 < initial_value: - raise ValueError("Initial counter value is too large") - initial_counter_block = nonce + long_to_bytes(initial_value, counter_len) - else: - if len(initial_value) != counter_len: - raise ValueError("Incorrect length for counter byte string (%d bytes, expected %d)" % - (len(initial_value), counter_len)) - initial_counter_block = nonce + initial_value - - return CtrMode(cipher_state, - initial_counter_block, - len(nonce), # prefix - counter_len, - False) # little_endian - - # Crypto.Util.Counter is used - - # 'counter' used to be a callable object, but now it is - # just a dictionary for backward compatibility. - _counter = dict(counter) - try: - counter_len = _counter.pop("counter_len") - prefix = _counter.pop("prefix") - suffix = _counter.pop("suffix") - initial_value = _counter.pop("initial_value") - little_endian = _counter.pop("little_endian") - except KeyError: - raise TypeError("Incorrect counter object" - " (use Crypto.Util.Counter.new)") - - # Compute initial counter block - words = [] - while initial_value > 0: - words.append(struct.pack('B', initial_value & 255)) - initial_value >>= 8 - words += [b'\x00'] * max(0, counter_len - len(words)) - if not little_endian: - words.reverse() - initial_counter_block = prefix + b"".join(words) + suffix - - if len(initial_counter_block) != factory.block_size: - raise ValueError("Size of the counter block (%d bytes) must match" - " block size (%d)" % (len(initial_counter_block), - factory.block_size)) - - return CtrMode(cipher_state, initial_counter_block, - len(prefix), counter_len, little_endian) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.pyi deleted file mode 100644 index ce70855..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ctr.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CtrMode'] - -class CtrMode(object): - block_size: int - nonce: bytes - - def __init__(self, - block_cipher: SmartPointer, - initial_counter_block: Buffer, - prefix_len: int, - counter_len: int, - little_endian: bool) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.py deleted file mode 100644 index 62cf4d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.py +++ /dev/null @@ -1,408 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -EAX mode. -""" - -__all__ = ['EaxMode'] - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import byte_string, bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Hash import CMAC, BLAKE2s -from Crypto.Random import get_random_bytes - - -class EaxMode(object): - """*EAX* mode. - - This is an Authenticated Encryption with Associated Data - (`AEAD`_) mode. It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, - and it will still be subject to authentication. - - The decryption step tells the receiver if the message comes - from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - - including the header - has been modified or corrupted. - - This mode requires a *nonce*. - - This mode is only available for ciphers that operate on 64 or - 128 bits blocks. - - There are no official standards defining EAX. - The implementation is based on `a proposal`__ that - was presented to NIST. - - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - .. __: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, cipher_params): - """EAX cipher mode""" - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """The nonce originally used to create the object.""" - - self._mac_len = mac_len - self._mac_tag = None # Cache for MAC tag - - # Allowed transitions after initialization - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - # MAC tag length - if not (2 <= self._mac_len <= self.block_size): - raise ValueError("'mac_len' must be at least 2 and not larger than %d" - % self.block_size) - - # Nonce cannot be empty and must be a byte string - if len(self.nonce) == 0: - raise ValueError("Nonce cannot be empty in EAX mode") - if not is_buffer(nonce): - raise TypeError("nonce must be bytes, bytearray or memoryview") - - self._omac = [ - CMAC.new(key, - b'\x00' * (self.block_size - 1) + struct.pack('B', i), - ciphermod=factory, - cipher_params=cipher_params) - for i in range(0, 3) - ] - - # Compute MAC of nonce - self._omac[0].update(self.nonce) - self._signer = self._omac[1] - - # MAC of the nonce is also the initial counter for CTR encryption - counter_int = bytes_to_long(self._omac[0].digest()) - self._cipher = factory.new(key, - factory.MODE_CTR, - initial_value=counter_int, - nonce=b"", - **cipher_params) - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if "update" not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - self._signer.update(assoc_data) - return self - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = ["encrypt", "digest"] - ct = self._cipher.encrypt(plaintext, output=output) - if output is None: - self._omac[2].update(ct) - else: - self._omac[2].update(output) - return ct - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = ["decrypt", "verify"] - self._omac[2].update(ciphertext) - return self._cipher.decrypt(ciphertext, output=output) - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if "digest" not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = ["digest"] - - if not self._mac_tag: - tag = b'\x00' * self.block_size - for i in range(3): - tag = strxor(tag, self._omac[i].digest()) - self._mac_tag = tag[:self._mac_len] - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = ["verify"] - - if not self._mac_tag: - tag = b'\x00' * self.block_size - for i in range(3): - tag = strxor(tag, self._omac[i].digest()) - self._mac_tag = tag[:self._mac_len] - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - pt = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return pt - - -def _create_eax_cipher(factory, **kwargs): - """Create a new block cipher, configured in EAX mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` (like - `Crypto.Cipher.AES`). - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - There are no restrictions on its length, but it is recommended to use - at least 16 bytes. - - The nonce shall never repeat for two different messages encrypted with - the same key, but it does not need to be random. - - If not specified, a 16 byte long random string is used. - - mac_len : integer - Length of the MAC, in bytes. It must be no larger than the cipher - block bytes (which is the default). - """ - - try: - key = kwargs.pop("key") - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(16) - mac_len = kwargs.pop("mac_len", factory.block_size) - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - return EaxMode(factory, key, nonce, mac_len, kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.pyi deleted file mode 100644 index cbfa467..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_eax.pyi +++ /dev/null @@ -1,45 +0,0 @@ -from types import ModuleType -from typing import Any, Union, Tuple, Dict, overload, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['EaxMode'] - -class EaxMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> EaxMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.py deleted file mode 100644 index 3783357..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.py +++ /dev/null @@ -1,220 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ecb.py : ECB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -""" -Electronic Code Book (ECB) mode. -""" - -__all__ = [ 'EcbMode' ] - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, create_string_buffer, - get_raw_buffer, SmartPointer, - c_size_t, c_uint8_ptr, - is_writeable_buffer) - -raw_ecb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ecb", """ - int ECB_start_operation(void *cipher, - void **pResult); - int ECB_encrypt(void *ecbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ECB_decrypt(void *ecbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ECB_stop_operation(void *state); - """ - ) - - -class EcbMode(object): - """*Electronic Code Book (ECB)*. - - This is the simplest encryption mode. Each of the plaintext blocks - is directly encrypted into a ciphertext block, independently of - any other block. - - This mode is dangerous because it exposes frequency of symbols - in your plaintext. Other modes (e.g. *CBC*) should be used instead. - - See `NIST SP800-38A`_ , Section 6.1. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher): - """Create a new block cipher, configured in ECB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - """ - self.block_size = block_cipher.block_size - - self._state = VoidPointer() - result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the ECB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher - # mode - self._state = SmartPointer(self._state.get(), - raw_ecb_lib.ECB_stop_operation) - - # Memory allocated for the underlying block cipher is now owned - # by the cipher mode - block_cipher.release() - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key set at initialization. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - The length must be multiple of the cipher block length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ecb_lib.ECB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 3: - raise ValueError("Data must be aligned to block boundary in ECB mode") - raise ValueError("Error %d while encrypting in ECB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key set at initialization. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - The length must be multiple of the cipher block length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ecb_lib.ECB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 3: - raise ValueError("Data must be aligned to block boundary in ECB mode") - raise ValueError("Error %d while decrypting in ECB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ecb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs ECB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - All keywords are passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present""" - - cipher_state = factory._create_base_cipher(kwargs) - cipher_state.block_size = factory.block_size - if kwargs: - raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) - return EcbMode(cipher_state) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.pyi deleted file mode 100644 index 1772b23..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = [ 'EcbMode' ] - -class EcbMode(object): - def __init__(self, block_cipher: SmartPointer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.py deleted file mode 100644 index 0519510..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.py +++ /dev/null @@ -1,620 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Galois/Counter Mode (GCM). -""" - -__all__ = ['GcmMode'] - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr) - -from Crypto.Util import _cpu_features - - -# C API by module implementing GHASH -_ghash_api_template = """ - int ghash_%imp%(uint8_t y_out[16], - const uint8_t block_data[], - size_t len, - const uint8_t y_in[16], - const void *exp_key); - int ghash_expand_%imp%(const uint8_t h[16], - void **ghash_tables); - int ghash_destroy_%imp%(void *ghash_tables); -""" - -def _build_impl(lib, postfix): - from collections import namedtuple - - funcs = ( "ghash", "ghash_expand", "ghash_destroy" ) - GHASH_Imp = namedtuple('_GHash_Imp', funcs) - try: - imp_funcs = [ getattr(lib, x + "_" + postfix) for x in funcs ] - except AttributeError: # Make sphinx stop complaining with its mocklib - imp_funcs = [ None ] * 3 - params = dict(zip(funcs, imp_funcs)) - return GHASH_Imp(**params) - - -def _get_ghash_portable(): - api = _ghash_api_template.replace("%imp%", "portable") - lib = load_pycryptodome_raw_lib("Crypto.Hash._ghash_portable", api) - result = _build_impl(lib, "portable") - return result -_ghash_portable = _get_ghash_portable() - - -def _get_ghash_clmul(): - """Return None if CLMUL implementation is not available""" - - if not _cpu_features.have_clmul(): - return None - try: - api = _ghash_api_template.replace("%imp%", "clmul") - lib = load_pycryptodome_raw_lib("Crypto.Hash._ghash_clmul", api) - result = _build_impl(lib, "clmul") - except OSError: - result = None - return result -_ghash_clmul = _get_ghash_clmul() - - -class _GHASH(object): - """GHASH function defined in NIST SP 800-38D, Algorithm 2. - - If X_1, X_2, .. X_m are the blocks of input data, the function - computes: - - X_1*H^{m} + X_2*H^{m-1} + ... + X_m*H - - in the Galois field GF(2^256) using the reducing polynomial - (x^128 + x^7 + x^2 + x + 1). - """ - - def __init__(self, subkey, ghash_c): - assert len(subkey) == 16 - - self.ghash_c = ghash_c - - self._exp_key = VoidPointer() - result = ghash_c.ghash_expand(c_uint8_ptr(subkey), - self._exp_key.address_of()) - if result: - raise ValueError("Error %d while expanding the GHASH key" % result) - - self._exp_key = SmartPointer(self._exp_key.get(), - ghash_c.ghash_destroy) - - # create_string_buffer always returns a string of zeroes - self._last_y = create_string_buffer(16) - - def update(self, block_data): - assert len(block_data) % 16 == 0 - - result = self.ghash_c.ghash(self._last_y, - c_uint8_ptr(block_data), - c_size_t(len(block_data)), - self._last_y, - self._exp_key.get()) - if result: - raise ValueError("Error %d while updating GHASH" % result) - - return self - - def digest(self): - return get_raw_buffer(self._last_y) - - -def enum(**enums): - return type('Enum', (), enums) - - -MacStatus = enum(PROCESSING_AUTH_DATA=1, PROCESSING_CIPHERTEXT=2) - - -class GcmMode(object): - """Galois Counter Mode (GCM). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - This mode requires a *nonce*. - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g. AES but not TDES). - - See `NIST SP800-38D`_. - - .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, cipher_params, ghash_c): - - self.block_size = factory.block_size - if self.block_size != 16: - raise ValueError("GCM mode is only available for ciphers" - " that operate on 128 bits blocks") - - if len(nonce) == 0: - raise ValueError("Nonce cannot be empty") - - if not is_buffer(nonce): - raise TypeError("Nonce must be bytes, bytearray or memoryview") - - # See NIST SP 800 38D, 5.2.1.1 - if len(nonce) > 2**64 - 1: - raise ValueError("Nonce exceeds maximum length") - - - self.nonce = _copy_bytes(None, None, nonce) - """Nonce""" - - self._factory = factory - self._key = _copy_bytes(None, None, key) - self._tag = None # Cache for MAC tag - - self._mac_len = mac_len - if not (4 <= mac_len <= 16): - raise ValueError("Parameter 'mac_len' must be in the range 4..16") - - # Allowed transitions after initialization - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - self._no_more_assoc_data = False - - # Length of associated data - self._auth_len = 0 - - # Length of the ciphertext or plaintext - self._msg_len = 0 - - # Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H - # See also Algorithm 5 (decryption) - hash_subkey = factory.new(key, - self._factory.MODE_ECB, - **cipher_params - ).encrypt(b'\x00' * 16) - - # Step 2 - Compute J0 - if len(self.nonce) == 12: - j0 = self.nonce + b"\x00\x00\x00\x01" - else: - fill = (16 - (len(self.nonce) % 16)) % 16 + 8 - ghash_in = (self.nonce + - b'\x00' * fill + - long_to_bytes(8 * len(self.nonce), 8)) - j0 = _GHASH(hash_subkey, ghash_c).update(ghash_in).digest() - - # Step 3 - Prepare GCTR cipher for encryption/decryption - nonce_ctr = j0[:12] - iv_ctr = (bytes_to_long(j0) + 1) & 0xFFFFFFFF - self._cipher = factory.new(key, - self._factory.MODE_CTR, - initial_value=iv_ctr, - nonce=nonce_ctr, - **cipher_params) - - # Step 5 - Bootstrat GHASH - self._signer = _GHASH(hash_subkey, ghash_c) - - # Step 6 - Prepare GCTR cipher for GMAC - self._tag_cipher = factory.new(key, - self._factory.MODE_CTR, - initial_value=j0, - nonce=b"", - **cipher_params) - - # Cache for data to authenticate - self._cache = b"" - - self._status = MacStatus.PROCESSING_AUTH_DATA - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - In GCM, the *associated data* is also called - *additional authenticated data* (AAD). - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if "update" not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - self._update(assoc_data) - self._auth_len += len(assoc_data) - - # See NIST SP 800 38D, 5.2.1.1 - if self._auth_len > 2**64 - 1: - raise ValueError("Additional Authenticated Data exceeds maximum length") - - return self - - def _update(self, data): - assert(len(self._cache) < 16) - - if len(self._cache) > 0: - filler = min(16 - len(self._cache), len(data)) - self._cache += _copy_bytes(None, filler, data) - data = data[filler:] - - if len(self._cache) < 16: - return - - # The cache is exactly one block - self._signer.update(self._cache) - self._cache = b"" - - update_len = len(data) // 16 * 16 - self._cache = _copy_bytes(update_len, None, data) - if update_len > 0: - self._signer.update(data[:update_len]) - - def _pad_cache_and_update(self): - assert(len(self._cache) < 16) - - # The authenticated data A is concatenated to the minimum - # number of zero bytes (possibly none) such that the - # - ciphertext C is aligned to the 16 byte boundary. - # See step 5 in section 7.1 - # - ciphertext C is aligned to the 16 byte boundary. - # See step 6 in section 7.2 - len_cache = len(self._cache) - if len_cache > 0: - self._update(b'\x00' * (16 - len_cache)) - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = ["encrypt", "digest"] - - ciphertext = self._cipher.encrypt(plaintext, output=output) - - if self._status == MacStatus.PROCESSING_AUTH_DATA: - self._pad_cache_and_update() - self._status = MacStatus.PROCESSING_CIPHERTEXT - - self._update(ciphertext if output is None else output) - self._msg_len += len(plaintext) - - # See NIST SP 800 38D, 5.2.1.1 - if self._msg_len > 2**39 - 256: - raise ValueError("Plaintext exceeds maximum length") - - return ciphertext - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = ["decrypt", "verify"] - - if self._status == MacStatus.PROCESSING_AUTH_DATA: - self._pad_cache_and_update() - self._status = MacStatus.PROCESSING_CIPHERTEXT - - self._update(ciphertext) - self._msg_len += len(ciphertext) - - return self._cipher.decrypt(ciphertext, output=output) - - def digest(self): - """Compute the *binary* MAC tag in an AEAD mode. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if "digest" not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = ["digest"] - - return self._compute_mac() - - def _compute_mac(self): - """Compute MAC without any FSM checks.""" - - if self._tag: - return self._tag - - # Step 5 in NIST SP 800-38D, Algorithm 4 - Compute S - self._pad_cache_and_update() - self._update(long_to_bytes(8 * self._auth_len, 8)) - self._update(long_to_bytes(8 * self._msg_len, 8)) - s_tag = self._signer.digest() - - # Step 6 - Compute T - self._tag = self._tag_cipher.encrypt(s_tag)[:self._mac_len] - - return self._tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = ["verify"] - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, - data=self._compute_mac()) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, - data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : byte string - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return plaintext - - -def _create_gcm_cipher(factory, **kwargs): - """Create a new block cipher, configured in Galois Counter Mode (GCM). - - :Parameters: - factory : module - A block cipher module, taken from `Crypto.Cipher`. - The cipher must have block length of 16 bytes. - GCM has been only defined for `Crypto.Cipher.AES`. - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - It must be 16 (e.g. *AES-128*), 24 (e.g. *AES-192*) - or 32 (e.g. *AES-256*) bytes long. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - - There are no restrictions on its length, - but it is recommended to use at least 16 bytes. - - The nonce shall never repeat for two - different messages encrypted with the same key, - but it does not need to be random. - - If not provided, a 16 byte nonce will be randomly created. - - mac_len : integer - Length of the MAC, in bytes. - It must be no larger than 16 bytes (which is the default). - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter:" + str(e)) - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(16) - mac_len = kwargs.pop("mac_len", 16) - - # Not documented - only used for testing - use_clmul = kwargs.pop("use_clmul", True) - if use_clmul and _ghash_clmul: - ghash_c = _ghash_clmul - else: - ghash_c = _ghash_portable - - return GcmMode(factory, key, nonce, mac_len, kwargs, ghash_c) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.pyi deleted file mode 100644 index 8912955..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_gcm.pyi +++ /dev/null @@ -1,45 +0,0 @@ -from types import ModuleType -from typing import Union, Tuple, Dict, overload, Optional - -__all__ = ['GcmMode'] - -Buffer = Union[bytes, bytearray, memoryview] - -class GcmMode(object): - block_size: int - nonce: Buffer - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> GcmMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kw.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kw.py deleted file mode 100644 index 9248982..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kw.py +++ /dev/null @@ -1,158 +0,0 @@ -import struct -from collections import deque - -from types import ModuleType -from typing import Union - -from Crypto.Util.strxor import strxor - - -def W(cipher: ModuleType, - plaintext: Union[bytes, bytearray]) -> bytes: - - S = [plaintext[i:i+8] for i in range(0, len(plaintext), 8)] - n = len(S) - s = 6 * (n - 1) - A = S[0] - R = deque(S[1:]) - - for t in range(1, s + 1): - t_64 = struct.pack('>Q', t) - ct = cipher.encrypt(A + R.popleft()) - A = strxor(ct[:8], t_64) - R.append(ct[8:]) - - return A + b''.join(R) - - -def W_inverse(cipher: ModuleType, - ciphertext: Union[bytes, bytearray]) -> bytes: - - C = [ciphertext[i:i+8] for i in range(0, len(ciphertext), 8)] - n = len(C) - s = 6 * (n - 1) - A = C[0] - R = deque(C[1:]) - - for t in range(s, 0, -1): - t_64 = struct.pack('>Q', t) - pt = cipher.decrypt(strxor(A, t_64) + R.pop()) - A = pt[:8] - R.appendleft(pt[8:]) - - return A + b''.join(R) - - -class KWMode(object): - """Key Wrap (KW) mode. - - This is a deterministic Authenticated Encryption (AE) mode - for protecting cryptographic keys. See `NIST SP800-38F`_. - - It provides both confidentiality and authenticity, and it designed - so that any bit of the ciphertext depends on all bits of the plaintext. - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g., AES). - - .. _`NIST SP800-38F`: http://csrc.nist.gov/publications/nistpubs/800-38F/SP-800-38F.pdf - - :undocumented: __init__ - """ - - def __init__(self, - factory: ModuleType, - key: Union[bytes, bytearray]): - - self.block_size = factory.block_size - if self.block_size != 16: - raise ValueError("Key Wrap mode is only available for ciphers" - " that operate on 128 bits blocks") - - self._factory = factory - self._cipher = factory.new(key, factory.MODE_ECB) - self._done = False - - def seal(self, plaintext: Union[bytes, bytearray]) -> bytes: - """Encrypt and authenticate (wrap) a cryptographic key. - - Args: - plaintext: - The cryptographic key to wrap. - It must be at least 16 bytes long, and its length - must be a multiple of 8. - - Returns: - The wrapped key. - """ - - if self._done: - raise ValueError("The cipher cannot be used more than once") - - if len(plaintext) % 8: - raise ValueError("The plaintext must have length multiple of 8 bytes") - - if len(plaintext) < 16: - raise ValueError("The plaintext must be at least 16 bytes long") - - if len(plaintext) >= 2**32: - raise ValueError("The plaintext is too long") - - res = W(self._cipher, b'\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6' + plaintext) - self._done = True - return res - - def unseal(self, ciphertext: Union[bytes, bytearray]) -> bytes: - """Decrypt and authenticate (unwrap) a cryptographic key. - - Args: - ciphertext: - The cryptographic key to unwrap. - It must be at least 24 bytes long, and its length - must be a multiple of 8. - - Returns: - The original key. - - Raises: ValueError - If the ciphertext or the key are not valid. - """ - - if self._done: - raise ValueError("The cipher cannot be used more than once") - - if len(ciphertext) % 8: - raise ValueError("The ciphertext must have length multiple of 8 bytes") - - if len(ciphertext) < 24: - raise ValueError("The ciphertext must be at least 24 bytes long") - - pt = W_inverse(self._cipher, ciphertext) - - if pt[:8] != b'\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6': - raise ValueError("Incorrect integrity check value") - self._done = True - - return pt[8:] - - -def _create_kw_cipher(factory: ModuleType, - **kwargs: Union[bytes, bytearray]) -> KWMode: - """Create a new block cipher in Key Wrap mode. - - Args: - factory: - A block cipher module, taken from `Crypto.Cipher`. - The cipher must have block length of 16 bytes, such as AES. - - Keywords: - key: - The secret key to use to seal or unseal. - """ - - try: - key = kwargs["key"] - except KeyError as e: - raise TypeError("Missing parameter:" + str(e)) - - return KWMode(factory, key) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kwp.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kwp.py deleted file mode 100644 index e6cac94..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_kwp.py +++ /dev/null @@ -1,135 +0,0 @@ -import struct - -from types import ModuleType -from typing import Union - -from ._mode_kw import W, W_inverse - - -class KWPMode(object): - """Key Wrap with Padding (KWP) mode. - - This is a deterministic Authenticated Encryption (AE) mode - for protecting cryptographic keys. See `NIST SP800-38F`_. - - It provides both confidentiality and authenticity, and it designed - so that any bit of the ciphertext depends on all bits of the plaintext. - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g., AES). - - .. _`NIST SP800-38F`: http://csrc.nist.gov/publications/nistpubs/800-38F/SP-800-38F.pdf - - :undocumented: __init__ - """ - - def __init__(self, - factory: ModuleType, - key: Union[bytes, bytearray]): - - self.block_size = factory.block_size - if self.block_size != 16: - raise ValueError("Key Wrap with Padding mode is only available for ciphers" - " that operate on 128 bits blocks") - - self._factory = factory - self._cipher = factory.new(key, factory.MODE_ECB) - self._done = False - - def seal(self, plaintext: Union[bytes, bytearray]) -> bytes: - """Encrypt and authenticate (wrap) a cryptographic key. - - Args: - plaintext: - The cryptographic key to wrap. - - Returns: - The wrapped key. - """ - - if self._done: - raise ValueError("The cipher cannot be used more than once") - - if len(plaintext) == 0: - raise ValueError("The plaintext must be at least 1 byte") - - if len(plaintext) >= 2 ** 32: - raise ValueError("The plaintext is too long") - - padlen = (8 - len(plaintext)) % 8 - padded = plaintext + b'\x00' * padlen - - AIV = b'\xA6\x59\x59\xA6' + struct.pack('>I', len(plaintext)) - - if len(padded) == 8: - res = self._cipher.encrypt(AIV + padded) - else: - res = W(self._cipher, AIV + padded) - - return res - - def unseal(self, ciphertext: Union[bytes, bytearray]) -> bytes: - """Decrypt and authenticate (unwrap) a cryptographic key. - - Args: - ciphertext: - The cryptographic key to unwrap. - It must be at least 16 bytes long, and its length - must be a multiple of 8. - - Returns: - The original key. - - Raises: ValueError - If the ciphertext or the key are not valid. - """ - - if self._done: - raise ValueError("The cipher cannot be used more than once") - - if len(ciphertext) % 8: - raise ValueError("The ciphertext must have length multiple of 8 bytes") - - if len(ciphertext) < 16: - raise ValueError("The ciphertext must be at least 24 bytes long") - - if len(ciphertext) == 16: - S = self._cipher.decrypt(ciphertext) - else: - S = W_inverse(self._cipher, ciphertext) - - if S[:4] != b'\xA6\x59\x59\xA6': - raise ValueError("Incorrect decryption") - - Plen = struct.unpack('>I', S[4:8])[0] - - padlen = len(S) - 8 - Plen - if padlen < 0 or padlen > 7: - raise ValueError("Incorrect decryption") - - if S[len(S) - padlen:] != b'\x00' * padlen: - raise ValueError("Incorrect decryption") - - return S[8:len(S) - padlen] - - -def _create_kwp_cipher(factory: ModuleType, - **kwargs: Union[bytes, bytearray]) -> KWPMode: - """Create a new block cipher in Key Wrap with Padding mode. - - Args: - factory: - A block cipher module, taken from `Crypto.Cipher`. - The cipher must have block length of 16 bytes, such as AES. - - Keywords: - key: - The secret key to use to seal or unseal. - """ - - try: - key = kwargs["key"] - except KeyError as e: - raise TypeError("Missing parameter:" + str(e)) - - return KWPMode(factory, key) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.py deleted file mode 100644 index a271ca1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.py +++ /dev/null @@ -1,532 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Offset Codebook (OCB) mode. - -OCB is Authenticated Encryption with Associated Data (AEAD) cipher mode -designed by Prof. Phillip Rogaway and specified in `RFC7253`_. - -The algorithm provides both authenticity and privacy, it is very efficient, -it uses only one key and it can be used in online mode (so that encryption -or decryption can start before the end of the message is available). - -This module implements the third and last variant of OCB (OCB3) and it only -works in combination with a 128-bit block symmetric cipher, like AES. - -OCB is patented in US but `free licenses`_ exist for software implementations -meant for non-military purposes. - -Example: - >>> from Crypto.Cipher import AES - >>> from Crypto.Random import get_random_bytes - >>> - >>> key = get_random_bytes(32) - >>> cipher = AES.new(key, AES.MODE_OCB) - >>> plaintext = b"Attack at dawn" - >>> ciphertext, mac = cipher.encrypt_and_digest(plaintext) - >>> # Deliver cipher.nonce, ciphertext and mac - ... - >>> cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - >>> try: - >>> plaintext = cipher.decrypt_and_verify(ciphertext, mac) - >>> except ValueError: - >>> print "Invalid message" - >>> else: - >>> print plaintext - -:undocumented: __package__ - -.. _RFC7253: http://www.rfc-editor.org/info/rfc7253 -.. _free licenses: http://web.cs.ucdavis.edu/~rogaway/ocb/license.htm -""" - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes, bchr -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Util.strxor import strxor - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_buffer) - -_raw_ocb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ocb", """ - int OCB_start_operation(void *cipher, - const uint8_t *offset_0, - size_t offset_0_len, - void **pState); - int OCB_encrypt(void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OCB_decrypt(void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OCB_update(void *state, - const uint8_t *in, - size_t data_len); - int OCB_digest(void *state, - uint8_t *tag, - size_t tag_len); - int OCB_stop_operation(void *state); - """) - - -class OcbMode(object): - """Offset Codebook (OCB) mode. - - :undocumented: __init__ - """ - - def __init__(self, factory, nonce, mac_len, cipher_params): - - if factory.block_size != 16: - raise ValueError("OCB mode is only available for ciphers" - " that operate on 128 bits blocks") - - self.block_size = 16 - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """Nonce used for this session.""" - if len(nonce) not in range(1, 16): - raise ValueError("Nonce must be at most 15 bytes long") - if not is_buffer(nonce): - raise TypeError("Nonce must be bytes, bytearray or memoryview") - - self._mac_len = mac_len - if not 8 <= mac_len <= 16: - raise ValueError("MAC tag must be between 8 and 16 bytes long") - - # Cache for MAC tag - self._mac_tag = None - - # Cache for unaligned associated data - self._cache_A = b"" - - # Cache for unaligned ciphertext/plaintext - self._cache_P = b"" - - # Allowed transitions after initialization - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - # Compute Offset_0 - params_without_key = dict(cipher_params) - key = params_without_key.pop("key") - - taglen_mod128 = (self._mac_len * 8) % 128 - if len(self.nonce) < 15: - nonce = bchr(taglen_mod128 << 1) +\ - b'\x00' * (14 - len(nonce)) +\ - b'\x01' +\ - self.nonce - else: - nonce = bchr((taglen_mod128 << 1) | 0x01) +\ - self.nonce - - bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 - top_bits = bord(nonce[15]) & 0xC0 # 2 bits - - ktop_cipher = factory.new(key, - factory.MODE_ECB, - **params_without_key) - ktop = ktop_cipher.encrypt(struct.pack('15sB', - nonce[:15], - top_bits)) - - stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits - offset_0 = long_to_bytes(bytes_to_long(stretch) >> - (64 - bottom_bits), 24)[8:] - - # Create low-level cipher instance - raw_cipher = factory._create_base_cipher(cipher_params) - if cipher_params: - raise TypeError("Unknown keywords: " + str(cipher_params)) - - self._state = VoidPointer() - result = _raw_ocb_lib.OCB_start_operation(raw_cipher.get(), - offset_0, - c_size_t(len(offset_0)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the OCB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - _raw_ocb_lib.OCB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - raw_cipher.release() - - def _update(self, assoc_data, assoc_data_len): - result = _raw_ocb_lib.OCB_update(self._state.get(), - c_uint8_ptr(assoc_data), - c_size_t(assoc_data_len)) - if result: - raise ValueError("Error %d while computing MAC in OCB mode" % result) - - def update(self, assoc_data): - """Process the associated data. - - If there is any associated data, the caller has to invoke - this method one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver shall still able to detect modifications. - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. - """ - - if "update" not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = ["encrypt", "decrypt", "digest", - "verify", "update"] - - if len(self._cache_A) > 0: - filler = min(16 - len(self._cache_A), len(assoc_data)) - self._cache_A += _copy_bytes(None, filler, assoc_data) - assoc_data = assoc_data[filler:] - - if len(self._cache_A) < 16: - return self - - # Clear the cache, and proceeding with any other aligned data - self._cache_A, seg = b"", self._cache_A - self.update(seg) - - update_len = len(assoc_data) // 16 * 16 - self._cache_A = _copy_bytes(update_len, None, assoc_data) - self._update(assoc_data, update_len) - return self - - def _transcrypt_aligned(self, in_data, in_data_len, - trans_func, trans_desc): - - out_data = create_string_buffer(in_data_len) - result = trans_func(self._state.get(), - in_data, - out_data, - c_size_t(in_data_len)) - if result: - raise ValueError("Error %d while %sing in OCB mode" - % (result, trans_desc)) - return get_raw_buffer(out_data) - - def _transcrypt(self, in_data, trans_func, trans_desc): - # Last piece to encrypt/decrypt - if in_data is None: - out_data = self._transcrypt_aligned(self._cache_P, - len(self._cache_P), - trans_func, - trans_desc) - self._cache_P = b"" - return out_data - - # Try to fill up the cache, if it already contains something - prefix = b"" - if len(self._cache_P) > 0: - filler = min(16 - len(self._cache_P), len(in_data)) - self._cache_P += _copy_bytes(None, filler, in_data) - in_data = in_data[filler:] - - if len(self._cache_P) < 16: - # We could not manage to fill the cache, so there is certainly - # no output yet. - return b"" - - # Clear the cache, and proceeding with any other aligned data - prefix = self._transcrypt_aligned(self._cache_P, - len(self._cache_P), - trans_func, - trans_desc) - self._cache_P = b"" - - # Process data in multiples of the block size - trans_len = len(in_data) // 16 * 16 - result = self._transcrypt_aligned(c_uint8_ptr(in_data), - trans_len, - trans_func, - trans_desc) - if prefix: - result = prefix + result - - # Left-over - self._cache_P = _copy_bytes(trans_len, None, in_data) - - return result - - def encrypt(self, plaintext=None): - """Encrypt the next piece of plaintext. - - After the entire plaintext has been passed (but before `digest`), - you **must** call this method one last time with no arguments to collect - the final piece of ciphertext. - - If possible, use the method `encrypt_and_digest` instead. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The next piece of data to encrypt or ``None`` to signify - that encryption has finished and that any remaining ciphertext - has to be produced. - :Return: - the ciphertext, as a byte string. - Its length may not match the length of the *plaintext*. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - - if plaintext is None: - self._next = ["digest"] - else: - self._next = ["encrypt"] - return self._transcrypt(plaintext, _raw_ocb_lib.OCB_encrypt, "encrypt") - - def decrypt(self, ciphertext=None): - """Decrypt the next piece of ciphertext. - - After the entire ciphertext has been passed (but before `verify`), - you **must** call this method one last time with no arguments to collect - the remaining piece of plaintext. - - If possible, use the method `decrypt_and_verify` instead. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The next piece of data to decrypt or ``None`` to signify - that decryption has finished and that any remaining plaintext - has to be produced. - :Return: - the plaintext, as a byte string. - Its length may not match the length of the *ciphertext*. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() can only be called after" - " initialization or an update()") - - if ciphertext is None: - self._next = ["verify"] - else: - self._next = ["decrypt"] - return self._transcrypt(ciphertext, - _raw_ocb_lib.OCB_decrypt, - "decrypt") - - def _compute_mac_tag(self): - - if self._mac_tag is not None: - return - - if self._cache_A: - self._update(self._cache_A, len(self._cache_A)) - self._cache_A = b"" - - mac_tag = create_string_buffer(16) - result = _raw_ocb_lib.OCB_digest(self._state.get(), - mac_tag, - c_size_t(len(mac_tag)) - ) - if result: - raise ValueError("Error %d while computing digest in OCB mode" - % result) - self._mac_tag = get_raw_buffer(mac_tag)[:self._mac_len] - - def digest(self): - """Compute the *binary* MAC tag. - - Call this method after the final `encrypt` (the one with no arguments) - to obtain the MAC tag. - - The MAC tag is needed by the receiver to determine authenticity - of the message. - - :Return: the MAC, as a byte string. - """ - - if "digest" not in self._next: - raise TypeError("digest() cannot be called now for this cipher") - - assert(len(self._cache_P) == 0) - - self._next = ["digest"] - - if self._mac_tag is None: - self._compute_mac_tag() - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - Call this method after the final `decrypt` (the one with no arguments) - to check if the message is authentic and valid. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called now for this cipher") - - assert(len(self._cache_P) == 0) - - self._next = ["verify"] - - if self._mac_tag is None: - self._compute_mac_tag() - - secret = get_random_bytes(16) - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext): - """Encrypt the message and create the MAC tag in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The entire message to encrypt. - :Return: - a tuple with two byte strings: - - - the encrypted data - - the MAC - """ - - return self.encrypt(plaintext) + self.encrypt(), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag): - """Decrypted the message and verify its authenticity in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The entire message to decrypt. - received_mac_tag : byte string - This is the *binary* MAC, as received from the sender. - - :Return: the decrypted data (byte string). - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext) + self.decrypt() - self.verify(received_mac_tag) - return plaintext - - -def _create_ocb_cipher(factory, **kwargs): - """Create a new block cipher, configured in OCB mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` - (like `Crypto.Cipher.AES`). - - :Keywords: - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - Its length can vary from 1 to 15 bytes. - If not specified, a random 15 bytes long nonce is generated. - - mac_len : integer - Length of the MAC, in bytes. - It must be in the range ``[8..16]``. - The default is 16 (128 bits). - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - try: - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(15) - mac_len = kwargs.pop("mac_len", 16) - except KeyError as e: - raise TypeError("Keyword missing: " + str(e)) - - return OcbMode(factory, nonce, mac_len, kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.pyi deleted file mode 100644 index a1909fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ocb.pyi +++ /dev/null @@ -1,36 +0,0 @@ -from types import ModuleType -from typing import Union, Any, Optional, Tuple, Dict, overload - -Buffer = Union[bytes, bytearray, memoryview] - -class OcbMode(object): - block_size: int - nonce: Buffer - - def __init__(self, - factory: ModuleType, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> OcbMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.py deleted file mode 100644 index 1a29b05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ofb.py : OFB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -""" -Output Feedback (CFB) mode. -""" - -__all__ = ['OfbMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_ofb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ofb", """ - int OFB_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - void **pResult); - int OFB_encrypt(void *ofbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OFB_decrypt(void *ofbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OFB_stop_operation(void *state); - """ - ) - - -class OfbMode(object): - """*Output FeedBack (OFB)*. - - This mode is very similar to CBC, but it - transforms the underlying block cipher into a stream cipher. - - The keystream is the iterated block encryption of the - previous ciphertext block. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.4. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv): - """Create a new block cipher, configured in OFB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be a nonce, to to be reused for any other - message**. It shall be a nonce or a random value. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - """ - - self._state = VoidPointer() - result = raw_ofb_lib.OFB_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the OFB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_ofb_lib.OFB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = ["encrypt", "decrypt"] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = ["encrypt"] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ofb_lib.OFB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting in OFB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext is written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = ["decrypt"] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ofb_lib.OFB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - raise ValueError("Error %d while decrypting in OFB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ofb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs OFB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for OFB. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - if kwargs: - raise TypeError("Unknown parameters for OFB: %s" % str(kwargs)) - - return OfbMode(cipher_state, iv) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.pyi deleted file mode 100644 index 60f7f00..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_ofb.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['OfbMode'] - -class OfbMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.py deleted file mode 100644 index d079d59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.py +++ /dev/null @@ -1,206 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -OpenPGP mode. -""" - -__all__ = ['OpenPgpMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Random import get_random_bytes - -class OpenPgpMode(object): - """OpenPGP mode. - - This mode is a variant of CFB, and it is only used in PGP and - OpenPGP_ applications. If in doubt, use another mode. - - An Initialization Vector (*IV*) is required. - - Unlike CFB, the *encrypted* IV (not the IV itself) is - transmitted to the receiver. - - The IV is a random data block. For legacy reasons, two of its bytes are - duplicated to act as a checksum for the correctness of the key, which is now - known to be insecure and is ignored. The encrypted IV is therefore 2 bytes - longer than the clean IV. - - .. _OpenPGP: http://tools.ietf.org/html/rfc4880 - - :undocumented: __init__ - """ - - def __init__(self, factory, key, iv, cipher_params): - - #: The block size of the underlying cipher, in bytes. - self.block_size = factory.block_size - - self._done_first_block = False # True after the first encryption - - # Instantiate a temporary cipher to process the IV - IV_cipher = factory.new( - key, - factory.MODE_CFB, - IV=b'\x00' * self.block_size, - segment_size=self.block_size * 8, - **cipher_params) - - iv = _copy_bytes(None, None, iv) - - # The cipher will be used for... - if len(iv) == self.block_size: - # ... encryption - self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) - elif len(iv) == self.block_size + 2: - # ... decryption - self._encrypted_IV = iv - # Last two bytes are for a deprecated "quick check" feature that - # should not be used. (https://eprint.iacr.org/2005/033) - iv = IV_cipher.decrypt(iv)[:-2] - else: - raise ValueError("Length of IV must be %d or %d bytes" - " for MODE_OPENPGP" - % (self.block_size, self.block_size + 2)) - - self.iv = self.IV = iv - - # Instantiate the cipher for the real PGP data - self._cipher = factory.new( - key, - factory.MODE_CFB, - IV=self._encrypted_IV[-self.block_size:], - segment_size=self.block_size * 8, - **cipher_params) - - def encrypt(self, plaintext): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - - :Return: - the encrypted data, as a byte string. - It is as long as *plaintext* with one exception: - when encrypting the first message chunk, - the encypted IV is prepended to the returned ciphertext. - """ - - res = self._cipher.encrypt(plaintext) - if not self._done_first_block: - res = self._encrypted_IV + res - self._done_first_block = True - return res - - def decrypt(self, ciphertext): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - - :Return: the decrypted data (byte string). - """ - - return self._cipher.decrypt(ciphertext) - - -def _create_openpgp_cipher(factory, **kwargs): - """Create a new block cipher, configured in OpenPGP mode. - - :Parameters: - factory : module - The module. - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - IV : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - - For encryption, the IV must be as long as the cipher block size. - - For decryption, it must be 2 bytes longer (it is actually the - *encrypted* IV which was prefixed to the ciphertext). - """ - - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing component: " + str(e)) - - return OpenPgpMode(factory, key, iv, kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.pyi deleted file mode 100644 index 14b8105..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_openpgp.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from types import ModuleType -from typing import Union, Dict - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['OpenPgpMode'] - -class OpenPgpMode(object): - block_size: int - iv: Union[bytes, bytearray, memoryview] - IV: Union[bytes, bytearray, memoryview] - - def __init__(self, - factory: ModuleType, - key: Buffer, - iv: Buffer, - cipher_params: Dict) -> None: ... - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, plaintext: Buffer) -> bytes: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.py deleted file mode 100644 index 1805ec0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.py +++ /dev/null @@ -1,392 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Synthetic Initialization Vector (SIV) mode. -""" - -__all__ = ['SivMode'] - -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Protocol.KDF import _S2V -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - - -class SivMode(object): - """Synthetic Initialization Vector (SIV). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - Unlike other AEAD modes such as CCM, EAX or GCM, accidental reuse of a - nonce is not catastrophic for the confidentiality of the message. The only - effect is that an attacker can tell when the same plaintext (and same - associated data) is protected with the same key. - - The length of the MAC is fixed to the block size of the underlying cipher. - The key size is twice the length of the key of the underlying cipher. - - This mode is only available for AES ciphers. - - +--------------------+---------------+-------------------+ - | Cipher | SIV MAC size | SIV key length | - | | (bytes) | (bytes) | - +====================+===============+===================+ - | AES-128 | 16 | 32 | - +--------------------+---------------+-------------------+ - | AES-192 | 16 | 48 | - +--------------------+---------------+-------------------+ - | AES-256 | 16 | 64 | - +--------------------+---------------+-------------------+ - - See `RFC5297`_ and the `original paper`__. - - .. _RFC5297: https://tools.ietf.org/html/rfc5297 - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - .. __: http://www.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, kwargs): - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self._factory = factory - - self._cipher_params = kwargs - - if len(key) not in (32, 48, 64): - raise ValueError("Incorrect key length (%d bytes)" % len(key)) - - if nonce is not None: - if not is_buffer(nonce): - raise TypeError("When provided, the nonce must be bytes, bytearray or memoryview") - - if len(nonce) == 0: - raise ValueError("When provided, the nonce must be non-empty") - - self.nonce = _copy_bytes(None, None, nonce) - """Public attribute is only available in case of non-deterministic - encryption.""" - - subkey_size = len(key) // 2 - - self._mac_tag = None # Cache for MAC tag - self._kdf = _S2V(key[:subkey_size], - ciphermod=factory, - cipher_params=self._cipher_params) - self._subkey_cipher = key[subkey_size:] - - # Purely for the purpose of verifying that cipher_params are OK - factory.new(key[:subkey_size], factory.MODE_ECB, **kwargs) - - # Allowed transitions after initialization - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - def _create_ctr_cipher(self, v): - """Create a new CTR cipher from V in SIV mode""" - - v_int = bytes_to_long(v) - q = v_int & 0xFFFFFFFFFFFFFFFF7FFFFFFF7FFFFFFF - return self._factory.new( - self._subkey_cipher, - self._factory.MODE_CTR, - initial_value=q, - nonce=b"", - **self._cipher_params) - - def update(self, component): - """Protect one associated data component - - For SIV, the associated data is a sequence (*vector*) of non-empty - byte strings (*components*). - - This method consumes the next component. It must be called - once for each of the components that constitue the associated data. - - Note that the components have clear boundaries, so that: - - >>> cipher.update(b"builtin") - >>> cipher.update(b"securely") - - is not equivalent to: - - >>> cipher.update(b"built") - >>> cipher.update(b"insecurely") - - If there is no associated data, this method must not be called. - - :Parameters: - component : bytes/bytearray/memoryview - The next associated data component. - """ - - if "update" not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = ["update", "encrypt", "decrypt", - "digest", "verify"] - - return self._kdf.update(component) - - def encrypt(self, plaintext): - """ - For SIV, encryption and MAC authentication must take place at the same - point. This method shall not be used. - - Use `encrypt_and_digest` instead. - """ - - raise TypeError("encrypt() not allowed for SIV mode." - " Use encrypt_and_digest() instead.") - - def decrypt(self, ciphertext): - """ - For SIV, decryption and verification must take place at the same - point. This method shall not be used. - - Use `decrypt_and_verify` instead. - """ - - raise TypeError("decrypt() not allowed for SIV mode." - " Use decrypt_and_verify() instead.") - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if "digest" not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = ["digest"] - if self._mac_tag is None: - self._mac_tag = self._kdf.derive() - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "verify" not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = ["verify"] - - if self._mac_tag is None: - self._mac_tag = self._kdf.derive() - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - if "encrypt" not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - - self._next = ["digest"] - - # Compute V (MAC) - if hasattr(self, 'nonce'): - self._kdf.update(self.nonce) - self._kdf.update(plaintext) - self._mac_tag = self._kdf.derive() - - cipher = self._create_ctr_cipher(self._mac_tag) - - return cipher.encrypt(plaintext, output=output), self._mac_tag - - def decrypt_and_verify(self, ciphertext, mac_tag, output=None): - """Perform decryption and verification in one step. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - You cannot reuse an object for encrypting - or decrypting other data with the same key. - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if "decrypt" not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = ["verify"] - - # Take the MAC and start the cipher for decryption - self._cipher = self._create_ctr_cipher(mac_tag) - - plaintext = self._cipher.decrypt(ciphertext, output=output) - - if hasattr(self, 'nonce'): - self._kdf.update(self.nonce) - self._kdf.update(plaintext if output is None else output) - self.verify(mac_tag) - - return plaintext - - -def _create_siv_cipher(factory, **kwargs): - """Create a new block cipher, configured in - Synthetic Initializaton Vector (SIV) mode. - - :Parameters: - - factory : object - A symmetric cipher module from `Crypto.Cipher` - (like `Crypto.Cipher.AES`). - - :Keywords: - - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - It must be 32, 48 or 64 bytes long. - If AES is the chosen cipher, the variants *AES-128*, - *AES-192* and or *AES-256* will be used internally. - - nonce : bytes/bytearray/memoryview - For deterministic encryption, it is not present. - - Otherwise, it is a value that must never be reused - for encrypting message under this key. - - There are no restrictions on its length, - but it is recommended to use at least 16 bytes. - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - nonce = kwargs.pop("nonce", None) - - return SivMode(factory, key, nonce, kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.pyi deleted file mode 100644 index 2934f23..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_mode_siv.pyi +++ /dev/null @@ -1,38 +0,0 @@ -from types import ModuleType -from typing import Union, Tuple, Dict, Optional, overload - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['SivMode'] - -class SivMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - kwargs: Dict) -> None: ... - - def update(self, component: Buffer) -> SivMode: ... - - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, plaintext: Buffer) -> bytes: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_decode.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_decode.abi3.so deleted file mode 100755 index 817ab00..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_decode.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_oaep_decode.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_oaep_decode.py deleted file mode 100644 index fc07528..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_pkcs1_oaep_decode.py +++ /dev/null @@ -1,41 +0,0 @@ -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, - c_uint8_ptr) - - -_raw_pkcs1_decode = load_pycryptodome_raw_lib("Crypto.Cipher._pkcs1_decode", - """ - int pkcs1_decode(const uint8_t *em, size_t len_em, - const uint8_t *sentinel, size_t len_sentinel, - size_t expected_pt_len, - uint8_t *output); - - int oaep_decode(const uint8_t *em, - size_t em_len, - const uint8_t *lHash, - size_t hLen, - const uint8_t *db, - size_t db_len); - """) - - -def pkcs1_decode(em, sentinel, expected_pt_len, output): - if len(em) != len(output): - raise ValueError("Incorrect output length") - - ret = _raw_pkcs1_decode.pkcs1_decode(c_uint8_ptr(em), - c_size_t(len(em)), - c_uint8_ptr(sentinel), - c_size_t(len(sentinel)), - c_size_t(expected_pt_len), - c_uint8_ptr(output)) - return ret - - -def oaep_decode(em, lHash, db): - ret = _raw_pkcs1_decode.oaep_decode(c_uint8_ptr(em), - c_size_t(len(em)), - c_uint8_ptr(lHash), - c_size_t(len(lHash)), - c_uint8_ptr(db), - c_size_t(len(db))) - return ret diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_aes.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_aes.abi3.so deleted file mode 100755 index 78f0cbd..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_aes.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_arc2.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_arc2.abi3.so deleted file mode 100755 index 0f021db..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_arc2.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_blowfish.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_blowfish.abi3.so deleted file mode 100755 index ebfd617..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_blowfish.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cast.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cast.abi3.so deleted file mode 100755 index 0de30e0..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cast.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cbc.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cbc.abi3.so deleted file mode 100755 index 8f5d96a..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cbc.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cfb.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cfb.abi3.so deleted file mode 100755 index 2622658..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_cfb.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ctr.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ctr.abi3.so deleted file mode 100755 index e1b9708..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ctr.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des.abi3.so deleted file mode 100755 index b302873..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des3.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des3.abi3.so deleted file mode 100755 index b533653..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_des3.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ecb.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ecb.abi3.so deleted file mode 100755 index be589c2..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ecb.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_eksblowfish.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_eksblowfish.abi3.so deleted file mode 100755 index 29a575a..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_eksblowfish.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ocb.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ocb.abi3.so deleted file mode 100755 index 1b2f4f4..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ocb.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ofb.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ofb.abi3.so deleted file mode 100755 index 0b495d0..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Cipher/_raw_ofb.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.py deleted file mode 100644 index e3ec46e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.py +++ /dev/null @@ -1,247 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes - -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_blake2b_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2b", - """ - int blake2b_init(void **state, - const uint8_t *key, - size_t key_size, - size_t digest_size); - int blake2b_destroy(void *state); - int blake2b_update(void *state, - const uint8_t *buf, - size_t len); - int blake2b_digest(const void *state, - uint8_t digest[64]); - int blake2b_copy(const void *src, void *dst); - """) - - -class BLAKE2b_Hash(object): - """A BLAKE2b hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 64 - - def __init__(self, data, key, digest_bytes, update_after_digest): - - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - - # See https://tools.ietf.org/html/rfc7693 - if digest_bytes in (20, 32, 48, 64) and not key: - self.oid = "1.3.6.1.4.1.1722.12.2.1." + str(digest_bytes) - - state = VoidPointer() - result = _raw_blake2b_lib.blake2b_init(state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(digest_bytes) - ) - if result: - raise ValueError("Error %d while instantiating BLAKE2b" % result) - self._state = SmartPointer(state.get(), - _raw_blake2b_lib.blake2b_destroy) - if data: - self.update(data) - - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (bytes/bytearray/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_blake2b_lib.blake2b_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing BLAKE2b data" % result) - return self - - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(64) - result = _raw_blake2b_lib.blake2b_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while creating BLAKE2b digest" % result) - - self._digest_done = True - - return get_raw_buffer(bfr)[:self.digest_size] - - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = new(digest_bits=160, key=secret, data=mac_tag) - mac2 = new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - def new(self, **kwargs): - """Return a new instance of a BLAKE2b hash object. - See :func:`new`. - """ - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`BLAKE2b_Hash.update`. - digest_bytes (integer): - Optional. The size of the digest, in bytes (1 to 64). Default is 64. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (8 to 512, in steps of 8). - Default is 512. - key (bytes/bytearray/memoryview): - Optional. The key to use to compute the MAC (1 to 64 bytes). - If not specified, no key will be used. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - - Returns: - A :class:`BLAKE2b_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 64 - if digest_bytes is not None: - if not (1 <= digest_bytes <= 64): - raise ValueError("'digest_bytes' not in range 1..64") - else: - if not (8 <= digest_bits <= 512) or (digest_bits % 8): - raise ValueError("'digest_bits' not in range 8..512, " - "with steps of 8") - digest_bytes = digest_bits // 8 - - key = kwargs.pop("key", b"") - if len(key) > 64: - raise ValueError("BLAKE2b key cannot exceed 64 bytes") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return BLAKE2b_Hash(data, key, digest_bytes, update_after_digest) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.pyi deleted file mode 100644 index d37c374..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2b.pyi +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Any, Union -from types import ModuleType - -Buffer = Union[bytes, bytearray, memoryview] - -class BLAKE2b_Hash(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - data: Buffer, - key: Buffer, - digest_bytes: bytes, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> BLAKE2b_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - def new(self, - data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2b_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2b_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.py deleted file mode 100644 index 192d145..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.py +++ /dev/null @@ -1,247 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes - -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_blake2s_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2s", - """ - int blake2s_init(void **state, - const uint8_t *key, - size_t key_size, - size_t digest_size); - int blake2s_destroy(void *state); - int blake2s_update(void *state, - const uint8_t *buf, - size_t len); - int blake2s_digest(const void *state, - uint8_t digest[32]); - int blake2s_copy(const void *src, void *dst); - """) - - -class BLAKE2s_Hash(object): - """A BLAKE2s hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 32 - - def __init__(self, data, key, digest_bytes, update_after_digest): - - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - - # See https://tools.ietf.org/html/rfc7693 - if digest_bytes in (16, 20, 28, 32) and not key: - self.oid = "1.3.6.1.4.1.1722.12.2.2." + str(digest_bytes) - - state = VoidPointer() - result = _raw_blake2s_lib.blake2s_init(state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(digest_bytes) - ) - if result: - raise ValueError("Error %d while instantiating BLAKE2s" % result) - self._state = SmartPointer(state.get(), - _raw_blake2s_lib.blake2s_destroy) - if data: - self.update(data) - - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_blake2s_lib.blake2s_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing BLAKE2s data" % result) - return self - - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(32) - result = _raw_blake2s_lib.blake2s_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while creating BLAKE2s digest" % result) - - self._digest_done = True - - return get_raw_buffer(bfr)[:self.digest_size] - - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte array/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = new(digest_bits=160, key=secret, data=mac_tag) - mac2 = new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - def new(self, **kwargs): - """Return a new instance of a BLAKE2s hash object. - See :func:`new`. - """ - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`BLAKE2s_Hash.update`. - digest_bytes (integer): - Optional. The size of the digest, in bytes (1 to 32). Default is 32. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (8 to 256, in steps of 8). - Default is 256. - key (byte string): - Optional. The key to use to compute the MAC (1 to 64 bytes). - If not specified, no key will be used. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - - Returns: - A :class:`BLAKE2s_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 32 - if digest_bytes is not None: - if not (1 <= digest_bytes <= 32): - raise ValueError("'digest_bytes' not in range 1..32") - else: - if not (8 <= digest_bits <= 256) or (digest_bits % 8): - raise ValueError("'digest_bits' not in range 8..256, " - "with steps of 8") - digest_bytes = digest_bits // 8 - - key = kwargs.pop("key", b"") - if len(key) > 32: - raise ValueError("BLAKE2s key cannot exceed 32 bytes") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return BLAKE2s_Hash(data, key, digest_bytes, update_after_digest) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.pyi deleted file mode 100644 index 374b3a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/BLAKE2s.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Union - -Buffer = Union[bytes, bytearray, memoryview] - -class BLAKE2s_Hash(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - data: Buffer, - key: Buffer, - digest_bytes: bytes, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> BLAKE2s_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - def new(self, **kwargs: Any) -> BLAKE2s_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2s_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.py deleted file mode 100644 index 764be86..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.py +++ /dev/null @@ -1,306 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Hash/CMAC.py - Implements the CMAC algorithm -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Hash import BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Util.py3compat import bord, tobytes, _copy_bytes -from Crypto.Random import get_random_bytes - - -# The size of the authentication tag produced by the MAC. -digest_size = None - - -def _shift_bytes(bs, xor_lsb=0): - num = (bytes_to_long(bs) << 1) ^ xor_lsb - return long_to_bytes(num, len(bs))[-len(bs):] - - -class CMAC(object): - """A CMAC hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - """ - - digest_size = None - - def __init__(self, key, msg, ciphermod, cipher_params, mac_len, - update_after_digest): - - self.digest_size = mac_len - - self._key = _copy_bytes(None, None, key) - self._factory = ciphermod - self._cipher_params = cipher_params - self._block_size = bs = ciphermod.block_size - self._mac_tag = None - self._update_after_digest = update_after_digest - - # Section 5.3 of NIST SP 800 38B and Appendix B - if bs == 8: - const_Rb = 0x1B - self._max_size = 8 * (2 ** 21) - elif bs == 16: - const_Rb = 0x87 - self._max_size = 16 * (2 ** 48) - else: - raise TypeError("CMAC requires a cipher with a block size" - " of 8 or 16 bytes, not %d" % bs) - - # Compute sub-keys - zero_block = b'\x00' * bs - self._ecb = ciphermod.new(key, - ciphermod.MODE_ECB, - **self._cipher_params) - L = self._ecb.encrypt(zero_block) - if bord(L[0]) & 0x80: - self._k1 = _shift_bytes(L, const_Rb) - else: - self._k1 = _shift_bytes(L) - if bord(self._k1[0]) & 0x80: - self._k2 = _shift_bytes(self._k1, const_Rb) - else: - self._k2 = _shift_bytes(self._k1) - - # Initialize CBC cipher with zero IV - self._cbc = ciphermod.new(key, - ciphermod.MODE_CBC, - zero_block, - **self._cipher_params) - - # Cache for outstanding data to authenticate - self._cache = bytearray(bs) - self._cache_n = 0 - - # Last piece of ciphertext produced - self._last_ct = zero_block - - # Last block that was encrypted with AES - self._last_pt = None - - # Counter for total message size - self._data_size = 0 - - if msg: - self.update(msg) - - def update(self, msg): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - if self._mac_tag is not None and not self._update_after_digest: - raise TypeError("update() cannot be called after digest() or verify()") - - self._data_size += len(msg) - bs = self._block_size - - if self._cache_n > 0: - filler = min(bs - self._cache_n, len(msg)) - self._cache[self._cache_n:self._cache_n+filler] = msg[:filler] - self._cache_n += filler - - if self._cache_n < bs: - return self - - msg = memoryview(msg)[filler:] - self._update(self._cache) - self._cache_n = 0 - - remain = len(msg) % bs - if remain > 0: - self._update(msg[:-remain]) - self._cache[:remain] = msg[-remain:] - else: - self._update(msg) - self._cache_n = remain - return self - - def _update(self, data_block): - """Update a block aligned to the block boundary""" - - bs = self._block_size - assert len(data_block) % bs == 0 - - if len(data_block) == 0: - return - - ct = self._cbc.encrypt(data_block) - if len(data_block) == bs: - second_last = self._last_ct - else: - second_last = ct[-bs*2:-bs] - self._last_ct = ct[-bs:] - self._last_pt = strxor(second_last, data_block[-bs:]) - - def copy(self): - """Return a copy ("clone") of the CMAC object. - - The copy will have the same internal state as the original CMAC - object. - This can be used to efficiently compute the MAC tag of byte - strings that share a common initial substring. - - :return: An :class:`CMAC` - """ - - obj = self.__new__(CMAC) - obj.__dict__ = self.__dict__.copy() - obj._cbc = self._factory.new(self._key, - self._factory.MODE_CBC, - self._last_ct, - **self._cipher_params) - obj._cache = self._cache[:] - obj._last_ct = self._last_ct[:] - return obj - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - that has been authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bs = self._block_size - - if self._mac_tag is not None and not self._update_after_digest: - return self._mac_tag - - if self._data_size > self._max_size: - raise ValueError("MAC is unsafe for this message") - - if self._cache_n == 0 and self._data_size > 0: - # Last block was full - pt = strxor(self._last_pt, self._k1) - else: - # Last block is partial (or message length is zero) - partial = self._cache[:] - partial[self._cache_n:] = b'\x80' + b'\x00' * (bs - self._cache_n - 1) - pt = strxor(strxor(self._last_ct, partial), self._k2) - - self._mac_tag = self._ecb.encrypt(pt)[:self.digest_size] - - return self._mac_tag - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte array/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - -def new(key, msg=None, ciphermod=None, cipher_params=None, mac_len=None, - update_after_digest=False): - """Create a new MAC object. - - Args: - key (byte string/byte array/memoryview): - key for the CMAC object. - The key must be valid for the underlying cipher algorithm. - For instance, it must be 16 bytes long for AES-128. - ciphermod (module): - A cipher module from :mod:`Crypto.Cipher`. - The cipher's block size has to be 128 bits, - like :mod:`Crypto.Cipher.AES`, to reduce the probability - of collisions. - msg (byte string/byte array/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to `CMAC.update`. Optional. - cipher_params (dict): - Optional. A set of parameters to use when instantiating a cipher - object. - mac_len (integer): - Length of the MAC, in bytes. - It must be at least 4 bytes long. - The default (and recommended) length matches the size of a cipher block. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - Returns: - A :class:`CMAC` object - """ - - if ciphermod is None: - raise TypeError("ciphermod must be specified (try AES)") - - cipher_params = {} if cipher_params is None else dict(cipher_params) - - if mac_len is None: - mac_len = ciphermod.block_size - - if mac_len < 4: - raise ValueError("MAC tag length must be at least 4 bytes long") - - if mac_len > ciphermod.block_size: - raise ValueError("MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size) - - return CMAC(key, msg, ciphermod, cipher_params, mac_len, - update_after_digest) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.pyi deleted file mode 100644 index acdf055..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/CMAC.pyi +++ /dev/null @@ -1,30 +0,0 @@ -from types import ModuleType -from typing import Union, Dict, Any - -Buffer = Union[bytes, bytearray, memoryview] - -digest_size: int - -class CMAC(object): - digest_size: int - - def __init__(self, - key: Buffer, - msg: Buffer, - ciphermod: ModuleType, - cipher_params: Dict[str, Any], - mac_len: int, update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> CMAC: ... - def copy(self) -> CMAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - -def new(key: Buffer, - msg: Buffer = ..., - ciphermod: ModuleType = ..., - cipher_params: Dict[str, Any] = ..., - mac_len: int = ..., - update_after_digest: bool = ...) -> CMAC: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.py deleted file mode 100644 index 7124d3e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.py +++ /dev/null @@ -1,238 +0,0 @@ -# -# HMAC.py - Implements the HMAC algorithm as described by RFC 2104. -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord, tobytes - -from binascii import unhexlify - -from Crypto.Hash import BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Random import get_random_bytes - -__all__ = ['new', 'HMAC'] - -_hash2hmac_oid = { - '1.3.14.3.2.26': '1.2.840.113549.2.7', # SHA-1 - '2.16.840.1.101.3.4.2.4': '1.2.840.113549.2.8', # SHA-224 - '2.16.840.1.101.3.4.2.1': '1.2.840.113549.2.9', # SHA-256 - '2.16.840.1.101.3.4.2.2': '1.2.840.113549.2.10', # SHA-384 - '2.16.840.1.101.3.4.2.3': '1.2.840.113549.2.11', # SHA-512 - '2.16.840.1.101.3.4.2.5': '1.2.840.113549.2.12', # SHA-512_224 - '2.16.840.1.101.3.4.2.6': '1.2.840.113549.2.13', # SHA-512_256 - '2.16.840.1.101.3.4.2.7': '2.16.840.1.101.3.4.2.13', # SHA-3 224 - '2.16.840.1.101.3.4.2.8': '2.16.840.1.101.3.4.2.14', # SHA-3 256 - '2.16.840.1.101.3.4.2.9': '2.16.840.1.101.3.4.2.15', # SHA-3 384 - '2.16.840.1.101.3.4.2.10': '2.16.840.1.101.3.4.2.16', # SHA-3 512 -} - -_hmac2hash_oid = {v: k for k, v in _hash2hmac_oid.items()} - - -class HMAC(object): - """An HMAC hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - - :ivar oid: the ASN.1 object ID of the HMAC algorithm. - Only present if the algorithm was officially assigned one. - """ - - def __init__(self, key, msg=b"", digestmod=None): - - if digestmod is None: - from Crypto.Hash import MD5 - digestmod = MD5 - - if msg is None: - msg = b"" - - # Size of the MAC tag - self.digest_size = digestmod.digest_size - - self._digestmod = digestmod - - # Hash OID --> HMAC OID - try: - self.oid = _hash2hmac_oid[digestmod.oid] - except (KeyError, AttributeError): - pass - - if isinstance(key, memoryview): - key = key.tobytes() - - try: - if len(key) <= digestmod.block_size: - # Step 1 or 2 - key_0 = key + b"\x00" * (digestmod.block_size - len(key)) - else: - # Step 3 - hash_k = digestmod.new(key).digest() - key_0 = hash_k + b"\x00" * (digestmod.block_size - len(hash_k)) - except AttributeError: - # Not all hash types have "block_size" - raise ValueError("Hash type incompatible to HMAC") - - # Step 4 - key_0_ipad = strxor(key_0, b"\x36" * len(key_0)) - - # Start step 5 and 6 - self._inner = digestmod.new(key_0_ipad) - self._inner.update(msg) - - # Step 7 - key_0_opad = strxor(key_0, b"\x5c" * len(key_0)) - - # Start step 8 and 9 - self._outer = digestmod.new(key_0_opad) - - def update(self, msg): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - self._inner.update(msg) - return self - - def _pbkdf2_hmac_assist(self, first_digest, iterations): - """Carry out the expensive inner loop for PBKDF2-HMAC""" - - result = self._digestmod._pbkdf2_hmac_assist( - self._inner, - self._outer, - first_digest, - iterations) - return result - - def copy(self): - """Return a copy ("clone") of the HMAC object. - - The copy will have the same internal state as the original HMAC - object. - This can be used to efficiently compute the MAC tag of byte - strings that share a common initial substring. - - :return: An :class:`HMAC` - """ - - new_hmac = HMAC(b"fake key", digestmod=self._digestmod) - - # Syncronize the state - new_hmac._inner = self._inner.copy() - new_hmac._outer = self._outer.copy() - - return new_hmac - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - authenticated so far. - - :return: The MAC tag digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - frozen_outer_hash = self._outer.copy() - frozen_outer_hash.update(self._inner.digest()) - return frozen_outer_hash.digest() - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte string/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, - as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - -def new(key, msg=b"", digestmod=None): - """Create a new MAC object. - - Args: - key (bytes/bytearray/memoryview): - key for the MAC object. - It must be long enough to match the expected security level of the - MAC. - msg (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to :meth:`HMAC.update`. - digestmod (module): - The hash to use to implement the HMAC. - Default is :mod:`Crypto.Hash.MD5`. - - Returns: - An :class:`HMAC` object - """ - - return HMAC(key, msg, digestmod) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.pyi deleted file mode 100644 index b577230..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/HMAC.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from types import ModuleType -from typing import Union, Dict - -Buffer = Union[bytes, bytearray, memoryview] - -digest_size: int - -class HMAC(object): - digest_size: int - - def __init__(self, - key: Buffer, - msg: Buffer, - digestmod: ModuleType) -> None: ... - def update(self, msg: Buffer) -> HMAC: ... - def copy(self) -> HMAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - -def new(key: Buffer, - msg: Buffer = ..., - digestmod: ModuleType = ...) -> HMAC: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.py deleted file mode 100644 index 05061fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.py +++ /dev/null @@ -1,179 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes, is_bytes -from Crypto.Random import get_random_bytes - -from . import cSHAKE128, SHA3_256 -from .cSHAKE128 import _bytepad, _encode_str, _right_encode - - -class KMAC_Hash(object): - """A KMAC hash object. - Do not instantiate directly. - Use the :func:`new` function. - """ - - def __init__(self, data, key, mac_len, custom, - oid_variant, cshake, rate): - - # See https://tools.ietf.org/html/rfc8702 - self.oid = "2.16.840.1.101.3.4.2." + oid_variant - self.digest_size = mac_len - - self._mac = None - - partial_newX = _bytepad(_encode_str(tobytes(key)), rate) - self._cshake = cshake._new(partial_newX, custom, b"KMAC") - - if data: - self._cshake.update(data) - - def update(self, data): - """Authenticate the next chunk of message. - - Args: - data (bytes/bytearray/memoryview): The next chunk of the message to - authenticate. - """ - - if self._mac: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - self._cshake.update(data) - return self - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message. - - :return: The MAC tag. Binary form. - :rtype: byte string - """ - - if not self._mac: - self._cshake.update(_right_encode(self.digest_size * 8)) - self._mac = self._cshake.read(self.digest_size) - - return self._mac - - def hexdigest(self): - """Return the **printable** MAC tag of the message. - - :return: The MAC tag. Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = SHA3_256.new(secret + mac_tag) - mac2 = SHA3_256.new(secret + self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - def new(self, **kwargs): - """Return a new instance of a KMAC hash object. - See :func:`new`. - """ - - if "mac_len" not in kwargs: - kwargs["mac_len"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new KMAC128 object. - - Args: - key (bytes/bytearray/memoryview): - The key to use to compute the MAC. - It must be at least 128 bits long (16 bytes). - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to :meth:`KMAC_Hash.update`. - mac_len (integer): - Optional. The size of the authentication tag, in bytes. - Default is 64. Minimum is 8. - custom (bytes/bytearray/memoryview): - Optional. A customization byte string (``S`` in SP 800-185). - - Returns: - A :class:`KMAC_Hash` hash object - """ - - key = kwargs.pop("key", None) - if not is_bytes(key): - raise TypeError("You must pass a key to KMAC128") - if len(key) < 16: - raise ValueError("The key must be at least 128 bits long (16 bytes)") - - data = kwargs.pop("data", None) - - mac_len = kwargs.pop("mac_len", 64) - if mac_len < 8: - raise ValueError("'mac_len' must be 8 bytes or more") - - custom = kwargs.pop("custom", b"") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return KMAC_Hash(data, key, mac_len, custom, "19", cSHAKE128, 168) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.pyi deleted file mode 100644 index 8947dab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC128.pyi +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union -from types import ModuleType - -Buffer = Union[bytes, bytearray, memoryview] - -class KMAC_Hash(object): - - def __init__(self, - data: Buffer, - key: Buffer, - mac_len: int, - custom: Buffer, - oid_variant: str, - cshake: ModuleType, - rate: int) -> None: ... - - def update(self, data: Buffer) -> KMAC_Hash: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - def new(self, - data: Buffer = ..., - mac_len: int = ..., - key: Buffer = ..., - custom: Buffer = ...) -> KMAC_Hash: ... - - -def new(key: Buffer, - data: Buffer = ..., - mac_len: int = ..., - custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.py deleted file mode 100644 index 2be8e2f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.py +++ /dev/null @@ -1,74 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import is_bytes - -from .KMAC128 import KMAC_Hash -from . import cSHAKE256 - - -def new(**kwargs): - """Create a new KMAC256 object. - - Args: - key (bytes/bytearray/memoryview): - The key to use to compute the MAC. - It must be at least 256 bits long (32 bytes). - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to :meth:`KMAC_Hash.update`. - mac_len (integer): - Optional. The size of the authentication tag, in bytes. - Default is 64. Minimum is 8. - custom (bytes/bytearray/memoryview): - Optional. A customization byte string (``S`` in SP 800-185). - - Returns: - A :class:`KMAC_Hash` hash object - """ - - key = kwargs.pop("key", None) - if not is_bytes(key): - raise TypeError("You must pass a key to KMAC256") - if len(key) < 32: - raise ValueError("The key must be at least 256 bits long (32 bytes)") - - data = kwargs.pop("data", None) - - mac_len = kwargs.pop("mac_len", 64) - if mac_len < 8: - raise ValueError("'mac_len' must be 8 bytes or more") - - custom = kwargs.pop("custom", b"") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return KMAC_Hash(data, key, mac_len, custom, "20", cSHAKE256, 136) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.pyi deleted file mode 100644 index 86cc500..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KMAC256.pyi +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from .KMAC128 import KMAC_Hash - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - data: Buffer = ..., - mac_len: int = ..., - custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.py deleted file mode 100644 index 5cf6857..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.py +++ /dev/null @@ -1,222 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.number import long_to_bytes -from Crypto.Util.py3compat import bchr - -from . import TurboSHAKE128 - -def _length_encode(x): - if x == 0: - return b'\x00' - - S = long_to_bytes(x) - return S + bchr(len(S)) - - -# Possible states for a KangarooTwelve instance, which depend on the amount of data processed so far. -SHORT_MSG = 1 # Still within the first 8192 bytes, but it is not certain we will exceed them. -LONG_MSG_S0 = 2 # Still within the first 8192 bytes, and it is certain we will exceed them. -LONG_MSG_SX = 3 # Beyond the first 8192 bytes. -SQUEEZING = 4 # No more data to process. - - -class K12_XOF(object): - """A KangarooTwelve hash object. - Do not instantiate directly. - Use the :func:`new` function. - """ - - def __init__(self, data, custom): - - if custom == None: - custom = b'' - - self._custom = custom + _length_encode(len(custom)) - self._state = SHORT_MSG - self._padding = None # Final padding is only decided in read() - - # Internal hash that consumes FinalNode - # The real domain separation byte will be known before squeezing - self._hash1 = TurboSHAKE128.new(domain=1) - self._length1 = 0 - - # Internal hash that produces CV_i (reset each time) - self._hash2 = None - self._length2 = 0 - - # Incremented by one for each 8192-byte block - self._ctr = 0 - - if data: - self.update(data) - - def update(self, data): - """Hash the next piece of data. - - .. note:: - For better performance, submit chunks with a length multiple of 8192 bytes. - - Args: - data (byte string/byte array/memoryview): The next chunk of the - message to hash. - """ - - if self._state == SQUEEZING: - raise TypeError("You cannot call 'update' after the first 'read'") - - if self._state == SHORT_MSG: - next_length = self._length1 + len(data) - - if next_length + len(self._custom) <= 8192: - self._length1 = next_length - self._hash1.update(data) - return self - - # Switch to tree hashing - self._state = LONG_MSG_S0 - - if self._state == LONG_MSG_S0: - data_mem = memoryview(data) - assert(self._length1 < 8192) - dtc = min(len(data), 8192 - self._length1) - self._hash1.update(data_mem[:dtc]) - self._length1 += dtc - - if self._length1 < 8192: - return self - - # Finish hashing S_0 and start S_1 - assert(self._length1 == 8192) - - divider = b'\x03' + b'\x00' * 7 - self._hash1.update(divider) - self._length1 += 8 - - self._hash2 = TurboSHAKE128.new(domain=0x0B) - self._length2 = 0 - self._ctr = 1 - - self._state = LONG_MSG_SX - return self.update(data_mem[dtc:]) - - # LONG_MSG_SX - assert(self._state == LONG_MSG_SX) - index = 0 - len_data = len(data) - - # All iteractions could actually run in parallel - data_mem = memoryview(data) - while index < len_data: - - new_index = min(index + 8192 - self._length2, len_data) - self._hash2.update(data_mem[index:new_index]) - self._length2 += new_index - index - index = new_index - - if self._length2 == 8192: - cv_i = self._hash2.read(32) - self._hash1.update(cv_i) - self._length1 += 32 - self._hash2._reset() - self._length2 = 0 - self._ctr += 1 - - return self - - def read(self, length): - """ - Produce more bytes of the digest. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - custom_was_consumed = False - - if self._state == SHORT_MSG: - self._hash1.update(self._custom) - self._padding = 0x07 - self._state = SQUEEZING - - if self._state == LONG_MSG_S0: - self.update(self._custom) - custom_was_consumed = True - assert(self._state == LONG_MSG_SX) - - if self._state == LONG_MSG_SX: - if not custom_was_consumed: - self.update(self._custom) - - # Is there still some leftover data in hash2? - if self._length2 > 0: - cv_i = self._hash2.read(32) - self._hash1.update(cv_i) - self._length1 += 32 - self._hash2._reset() - self._length2 = 0 - self._ctr += 1 - - trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF' - self._hash1.update(trailer) - - self._padding = 0x06 - self._state = SQUEEZING - - self._hash1._domain = self._padding - return self._hash1.read(length) - - def new(self, data=None, custom=b''): - return type(self)(data, custom) - - -def new(data=None, custom=None): - """Return a fresh instance of a KangarooTwelve object. - - Args: - data (bytes/bytearray/memoryview): - Optional. - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - custom (bytes): - Optional. - A customization byte string. - - :Return: A :class:`K12_XOF` object - """ - - return K12_XOF(data, custom) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.pyi deleted file mode 100644 index 8b3fd74..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/KangarooTwelve.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class K12_XOF(object): - def __init__(self, - data: Optional[Buffer] = ..., - custom: Optional[bytes] = ...) -> None: ... - def update(self, data: Buffer) -> K12_XOF: ... - def read(self, length: int) -> bytes: ... - def new(self, - data: Optional[Buffer] = ..., - custom: Optional[bytes] = ...) -> None: ... - -def new(data: Optional[Buffer] = ..., - custom: Optional[Buffer] = ...) -> K12_XOF: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.py deleted file mode 100644 index 41decbb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.py +++ /dev/null @@ -1,166 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md2_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._MD2", - """ - int md2_init(void **shaState); - int md2_destroy(void *shaState); - int md2_update(void *hs, - const uint8_t *buf, - size_t len); - int md2_digest(const void *shaState, - uint8_t digest[20]); - int md2_copy(const void *src, void *dst); - """) - - -class MD2Hash(object): - """An MD2 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 16 - # The internal block size of the hash algorithm in bytes. - block_size = 16 - # ASN.1 Object ID - oid = "1.2.840.113549.2.2" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md2_lib.md2_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - self._state = SmartPointer(state.get(), - _raw_md2_lib.md2_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_md2_lib.md2_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md2_lib.md2_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = MD2Hash() - result = _raw_md2_lib.md2_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD2" % result) - return clone - - def new(self, data=None): - return MD2Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`MD2Hash.update`. - :type data: bytes/bytearray/memoryview - - :Return: A :class:`MD2Hash` hash object - """ - - return MD2Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = MD2Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = MD2Hash.block_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.pyi deleted file mode 100644 index 95a97a9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD2.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class MD4Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD4Hash: ... - def new(self, data: Buffer = ...) -> MD4Hash: ... - -def new(data: Buffer = ...) -> MD4Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.py deleted file mode 100644 index be12b19..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.py +++ /dev/null @@ -1,185 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -MD4 is specified in RFC1320_ and produces the 128 bit digest of a message. - - >>> from Crypto.Hash import MD4 - >>> - >>> h = MD4.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990. -This algorithm is insecure. Do not use it for new designs. - -.. _RFC1320: http://tools.ietf.org/html/rfc1320 -""" - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md4_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._MD4", - """ - int md4_init(void **shaState); - int md4_destroy(void *shaState); - int md4_update(void *hs, - const uint8_t *buf, - size_t len); - int md4_digest(const void *shaState, - uint8_t digest[20]); - int md4_copy(const void *src, void *dst); - """) - - -class MD4Hash(object): - """Class that implements an MD4 hash - """ - - #: The size of the resulting hash in bytes. - digest_size = 16 - #: The internal block size of the hash algorithm in bytes. - block_size = 64 - #: ASN.1 Object ID - oid = "1.2.840.113549.2.4" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md4_lib.md4_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - self._state = SmartPointer(state.get(), - _raw_md4_lib.md4_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Repeated calls are equivalent to a single call with the concatenation - of all the arguments. In other words: - - >>> m.update(a); m.update(b) - - is equivalent to: - - >>> m.update(a+b) - - :Parameters: - data : byte string/byte array/memoryview - The next chunk of the message being hashed. - """ - - result = _raw_md4_lib.md4_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that - has been hashed so far. - - This method does not change the state of the hash object. - You can continue updating the object after calling this function. - - :Return: A byte string of `digest_size` bytes. It may contain non-ASCII - characters, including null bytes. - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md4_lib.md4_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been - hashed so far. - - This method does not change the state of the hash object. - - :Return: A string of 2* `digest_size` characters. It contains only - hexadecimal ASCII digits. - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :Return: A hash object of the same type - """ - - clone = MD4Hash() - result = _raw_md4_lib.md4_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD4" % result) - return clone - - def new(self, data=None): - return MD4Hash(data) - - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string/byte array/memoryview - The very first chunk of the message to hash. - It is equivalent to an early call to `MD4Hash.update()`. - Optional. - - :Return: A `MD4Hash` object - """ - return MD4Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = MD4Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = MD4Hash.block_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.pyi deleted file mode 100644 index a9a7295..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD4.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class MD4Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD4Hash: ... - def new(self, data: Optional[Buffer] = ...) -> MD4Hash: ... - -def new(data: Optional[Buffer] = ...) -> MD4Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.py deleted file mode 100644 index 554b777..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md5_lib = load_pycryptodome_raw_lib("Crypto.Hash._MD5", - """ - #define MD5_DIGEST_SIZE 16 - - int MD5_init(void **shaState); - int MD5_destroy(void *shaState); - int MD5_update(void *hs, - const uint8_t *buf, - size_t len); - int MD5_digest(const void *shaState, - uint8_t digest[MD5_DIGEST_SIZE]); - int MD5_copy(const void *src, void *dst); - - int MD5_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t first_digest[MD5_DIGEST_SIZE], - uint8_t final_digest[MD5_DIGEST_SIZE], - size_t iterations); - """) - -class MD5Hash(object): - """A MD5 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 16 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.2.840.113549.2.5" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md5_lib.MD5_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - self._state = SmartPointer(state.get(), - _raw_md5_lib.MD5_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_md5_lib.MD5_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md5_lib.MD5_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = MD5Hash() - result = _raw_md5_lib.MD5_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD5" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-1 hash object.""" - - return MD5Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`MD5Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`MD5Hash` hash object - """ - return MD5Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = 16 - -# The internal block size of the hash algorithm in bytes. -block_size = 64 - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert len(first_digest) == digest_size - assert iterations > 0 - - bfr = create_string_buffer(digest_size); - result = _raw_md5_lib.MD5_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations)) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assis for MD5" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.pyi deleted file mode 100644 index d819556..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/MD5.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class MD5Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD5Hash: ... - def new(self, data: Buffer = ...) -> MD5Hash: ... - -def new(data: Buffer = ...) -> MD5Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.py deleted file mode 100644 index eb5e0da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Hash/Poly1305.py - Implements the Poly1305 MAC -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes, _copy_bytes - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - - -_raw_poly1305 = load_pycryptodome_raw_lib("Crypto.Hash._poly1305", - """ - int poly1305_init(void **state, - const uint8_t *r, - size_t r_len, - const uint8_t *s, - size_t s_len); - int poly1305_destroy(void *state); - int poly1305_update(void *state, - const uint8_t *in, - size_t len); - int poly1305_digest(const void *state, - uint8_t *digest, - size_t len); - """) - - -class Poly1305_MAC(object): - """An Poly1305 MAC object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - """ - - digest_size = 16 - - def __init__(self, r, s, data): - - if len(r) != 16: - raise ValueError("Parameter r is not 16 bytes long") - if len(s) != 16: - raise ValueError("Parameter s is not 16 bytes long") - - self._mac_tag = None - - state = VoidPointer() - result = _raw_poly1305.poly1305_init(state.address_of(), - c_uint8_ptr(r), - c_size_t(len(r)), - c_uint8_ptr(s), - c_size_t(len(s)) - ) - if result: - raise ValueError("Error %d while instantiating Poly1305" % result) - self._state = SmartPointer(state.get(), - _raw_poly1305.poly1305_destroy) - if data: - self.update(data) - - def update(self, data): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - if self._mac_tag: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_poly1305.poly1305_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing Poly1305 data" % result) - return self - - def copy(self): - raise NotImplementedError() - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - authenticated so far. - - :return: The MAC tag digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - if self._mac_tag: - return self._mac_tag - - bfr = create_string_buffer(16) - result = _raw_poly1305.poly1305_digest(self._state.get(), - bfr, - c_size_t(len(bfr))) - if result: - raise ValueError("Error %d while creating Poly1305 digest" % result) - - self._mac_tag = get_raw_buffer(bfr) - return self._mac_tag - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte string/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, - as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - -def new(**kwargs): - """Create a new Poly1305 MAC object. - - Args: - key (bytes/bytearray/memoryview): - The 32-byte key for the Poly1305 object. - cipher (module from ``Crypto.Cipher``): - The cipher algorithm to use for deriving the Poly1305 - key pair *(r, s)*. - It can only be ``Crypto.Cipher.AES`` or ``Crypto.Cipher.ChaCha20``. - nonce (bytes/bytearray/memoryview): - Optional. The non-repeatable value to use for the MAC of this message. - It must be 16 bytes long for ``AES`` and 8 or 12 bytes for ``ChaCha20``. - If not passed, a random nonce is created; you will find it in the - ``nonce`` attribute of the new object. - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to ``update()``. - - Returns: - A :class:`Poly1305_MAC` object - """ - - cipher = kwargs.pop("cipher", None) - if not hasattr(cipher, '_derive_Poly1305_key_pair'): - raise ValueError("Parameter 'cipher' must be AES or ChaCha20") - - cipher_key = kwargs.pop("key", None) - if cipher_key is None: - raise TypeError("You must pass a parameter 'key'") - - nonce = kwargs.pop("nonce", None) - data = kwargs.pop("data", None) - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - r, s, nonce = cipher._derive_Poly1305_key_pair(cipher_key, nonce) - - new_mac = Poly1305_MAC(r, s, data) - new_mac.nonce = _copy_bytes(None, None, nonce) # nonce may still be just a memoryview - return new_mac diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.pyi deleted file mode 100644 index f97a14a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/Poly1305.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from types import ModuleType -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class Poly1305_MAC(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - r : int, - s : int, - data : Buffer) -> None: ... - def update(self, data: Buffer) -> Poly1305_MAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - -def new(key: Buffer, - cipher: ModuleType, - nonce: Buffer = ..., - data: Buffer = ...) -> Poly1305_MAC: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.py deleted file mode 100644 index 4e80235..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.RIPEMD - -"""Deprecated alias for `Crypto.Hash.RIPEMD160`""" - -from Crypto.Hash.RIPEMD160 import new, block_size, digest_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.pyi deleted file mode 100644 index e33eb2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD.pyi +++ /dev/null @@ -1,3 +0,0 @@ -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.py deleted file mode 100644 index 820b57d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.py +++ /dev/null @@ -1,169 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_ripemd160_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._RIPEMD160", - """ - int ripemd160_init(void **shaState); - int ripemd160_destroy(void *shaState); - int ripemd160_update(void *hs, - const uint8_t *buf, - size_t len); - int ripemd160_digest(const void *shaState, - uint8_t digest[20]); - int ripemd160_copy(const void *src, void *dst); - """) - - -class RIPEMD160Hash(object): - """A RIPEMD-160 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 20 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.3.36.3.2.1" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_ripemd160_lib.ripemd160_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating RIPEMD160" - % result) - self._state = SmartPointer(state.get(), - _raw_ripemd160_lib.ripemd160_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_ripemd160_lib.ripemd160_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating ripemd160" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_ripemd160_lib.ripemd160_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating ripemd160" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = RIPEMD160Hash() - result = _raw_ripemd160_lib.ripemd160_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying ripemd160" % result) - return clone - - def new(self, data=None): - """Create a fresh RIPEMD-160 hash object.""" - - return RIPEMD160Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`RIPEMD160Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`RIPEMD160Hash` hash object - """ - - return RIPEMD160Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = RIPEMD160Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = RIPEMD160Hash.block_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.pyi deleted file mode 100644 index b619473..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/RIPEMD160.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class RIPEMD160Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> RIPEMD160Hash: ... - def new(self, data: Buffer = ...) -> RIPEMD160Hash: ... - -def new(data: Buffer = ...) -> RIPEMD160Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.py deleted file mode 100644 index 0cc141c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - -from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.pyi deleted file mode 100644 index 4d7d57e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA.pyi +++ /dev/null @@ -1,4 +0,0 @@ -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - -from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.py deleted file mode 100644 index f79d825..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha1_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA1", - """ - #define SHA1_DIGEST_SIZE 20 - - int SHA1_init(void **shaState); - int SHA1_destroy(void *shaState); - int SHA1_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA1_digest(const void *shaState, - uint8_t digest[SHA1_DIGEST_SIZE]); - int SHA1_copy(const void *src, void *dst); - - int SHA1_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t first_digest[SHA1_DIGEST_SIZE], - uint8_t final_digest[SHA1_DIGEST_SIZE], - size_t iterations); - """) - -class SHA1Hash(object): - """A SHA-1 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 20 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.3.14.3.2.26" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha1_lib.SHA1_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - self._state = SmartPointer(state.get(), - _raw_sha1_lib.SHA1_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha1_lib.SHA1_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha1_lib.SHA1_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA1Hash() - result = _raw_sha1_lib.SHA1_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA1" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-1 hash object.""" - - return SHA1Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA1Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA1Hash` hash object - """ - return SHA1Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA1Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA1Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert len(first_digest) == digest_size - assert iterations > 0 - - bfr = create_string_buffer(digest_size); - result = _raw_sha1_lib.SHA1_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations)) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assis for SHA1" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.pyi deleted file mode 100644 index d6c8e25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA1.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA1Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA1Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA1Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA1Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.py deleted file mode 100644 index f788b06..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha224_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA224", - """ - int SHA224_init(void **shaState); - int SHA224_destroy(void *shaState); - int SHA224_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA224_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA224_copy(const void *src, void *dst); - - int SHA224_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA224Hash(object): - """A SHA-224 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 28 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = '2.16.840.1.101.3.4.2.4' - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha224_lib.SHA224_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA224" - % result) - self._state = SmartPointer(state.get(), - _raw_sha224_lib.SHA224_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha224_lib.SHA224_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA224" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha224_lib.SHA224_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA224 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA224Hash() - result = _raw_sha224_lib.SHA224_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA224" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-224 hash object.""" - - return SHA224Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA224Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA224Hash` hash object - """ - return SHA224Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA224Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA224Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha224_lib.SHA224_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA224" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.pyi deleted file mode 100644 index 613a7f9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA224.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA224Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA224Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA224Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA224Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.py deleted file mode 100644 index 957aa37..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha256_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA256", - """ - int SHA256_init(void **shaState); - int SHA256_destroy(void *shaState); - int SHA256_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA256_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA256_copy(const void *src, void *dst); - - int SHA256_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA256Hash(object): - """A SHA-256 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 32 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.1" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha256_lib.SHA256_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA256" - % result) - self._state = SmartPointer(state.get(), - _raw_sha256_lib.SHA256_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha256_lib.SHA256_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA256" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha256_lib.SHA256_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA256 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA256Hash() - result = _raw_sha256_lib.SHA256_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA256" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-256 hash object.""" - - return SHA256Hash(data) - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA256Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA256Hash` hash object - """ - - return SHA256Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA256Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA256Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha256_lib.SHA256_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA256" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.pyi deleted file mode 100644 index cbf21bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA256.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union, Optional - - -class SHA256Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> None: ... - def update(self, data: Union[bytes, bytearray, memoryview]) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA256Hash: ... - def new(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... - -def new(data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... - -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.py deleted file mode 100644 index a98fa9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha384_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA384", - """ - int SHA384_init(void **shaState); - int SHA384_destroy(void *shaState); - int SHA384_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA384_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA384_copy(const void *src, void *dst); - - int SHA384_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA384Hash(object): - """A SHA-384 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 48 - # The internal block size of the hash algorithm in bytes. - block_size = 128 - # ASN.1 Object ID - oid = '2.16.840.1.101.3.4.2.2' - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha384_lib.SHA384_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA384" - % result) - self._state = SmartPointer(state.get(), - _raw_sha384_lib.SHA384_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha384_lib.SHA384_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA384" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha384_lib.SHA384_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA384 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA384Hash() - result = _raw_sha384_lib.SHA384_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA384" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-384 hash object.""" - - return SHA384Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA384Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA384Hash` hash object - """ - - return SHA384Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA384Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA384Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha384_lib.SHA384_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA384" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.pyi deleted file mode 100644 index c2aab9e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA384.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA384Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA384Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA384Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA384Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.py deleted file mode 100644 index 54556d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_224_Hash(object): - """A SHA3-224 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 28 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.7" - - # Input block size for HMAC - block_size = 144 - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - self._padding = 0x06 - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHA-3/224" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data)) - ) - if result: - raise ValueError("Error %d while updating SHA-3/224" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while instantiating SHA-3/224" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA3-224" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA3-224 hash object.""" - - return type(self)(data, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_224_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_224_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_224_Hash.digest_size - -# Input block size for HMAC -block_size = 144 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.pyi deleted file mode 100644 index 2180821..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_224.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_224_Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_224_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA3_224_Hash: ... - def new(self, data: Optional[Buffer]) -> SHA3_224_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_224_Hash: ... - -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.py deleted file mode 100644 index b4f11ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_256_Hash(object): - """A SHA3-256 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 32 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.8" - - # Input block size for HMAC - block_size = 136 - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - self._padding = 0x06 - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHA-3/256" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data)) - ) - if result: - raise ValueError("Error %d while updating SHA-3/256" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while instantiating SHA-3/256" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA3-256" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA3-256 hash object.""" - - return type(self)(data, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_256_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_256_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_256_Hash.digest_size - -# Input block size for HMAC -block_size = 136 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.pyi deleted file mode 100644 index 88436bd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_256.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_256_Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_256_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA3_256_Hash: ... - def new(self, data: Optional[Buffer]) -> SHA3_256_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_256_Hash: ... - -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.py deleted file mode 100644 index 12f61ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_384_Hash(object): - """A SHA3-384 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 48 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.9" - - # Input block size for HMAC - block_size = 104 - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - self._padding = 0x06 - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHA-3/384" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/384" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while instantiating SHA-3/384" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA3-384" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA3-256 hash object.""" - - return type(self)(data, self._update_after_digest) - - - def new(self, data=None): - """Create a fresh SHA3-384 hash object.""" - - return type(self)(data, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_384_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_384_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_384_Hash.digest_size - -# Input block size for HMAC -block_size = 104 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.pyi deleted file mode 100644 index 98d00c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_384.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_384_Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_384_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA3_384_Hash: ... - def new(self, data: Optional[Buffer]) -> SHA3_384_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_384_Hash: ... - -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.py deleted file mode 100644 index de8880c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_512_Hash(object): - """A SHA3-512 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 64 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.10" - - # Input block size for HMAC - block_size = 72 - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - self._padding = 0x06 - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHA-3/512" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/512" - % result) - return self - - def digest(self): - - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while instantiating SHA-3/512" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA3-512" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA3-521 hash object.""" - - return type(self)(data, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_512_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_512_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_512_Hash.digest_size - -# Input block size for HMAC -block_size = 72 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.pyi deleted file mode 100644 index cdeec16..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA3_512.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_512_Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_512_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA3_512_Hash: ... - def new(self, data: Optional[Buffer]) -> SHA3_512_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_512_Hash: ... - -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.py deleted file mode 100644 index 403fe45..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha512_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA512", - """ - int SHA512_init(void **shaState, - size_t digest_size); - int SHA512_destroy(void *shaState); - int SHA512_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA512_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA512_copy(const void *src, void *dst); - - int SHA512_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA512Hash(object): - """A SHA-512 hash object (possibly in its truncated version SHA-512/224 or - SHA-512/256. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 128 - - def __init__(self, data, truncate): - self._truncate = truncate - - if truncate is None: - self.oid = "2.16.840.1.101.3.4.2.3" - self.digest_size = 64 - elif truncate == "224": - self.oid = "2.16.840.1.101.3.4.2.5" - self.digest_size = 28 - elif truncate == "256": - self.oid = "2.16.840.1.101.3.4.2.6" - self.digest_size = 32 - else: - raise ValueError("Incorrect truncation length. It must be '224' or '256'.") - - state = VoidPointer() - result = _raw_sha512_lib.SHA512_init(state.address_of(), - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-512" - % result) - self._state = SmartPointer(state.get(), - _raw_sha512_lib.SHA512_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha512_lib.SHA512_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA512" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha512_lib.SHA512_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA512 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA512Hash(None, self._truncate) - result = _raw_sha512_lib.SHA512_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA512" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-512 hash object.""" - - return SHA512Hash(data, self._truncate) - - -def new(data=None, truncate=None): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA512Hash.update`. - truncate (string): - Optional. The desired length of the digest. It can be either "224" or - "256". If not present, the digest is 512 bits long. - Passing this parameter is **not** equivalent to simply truncating - the output digest. - - :Return: A :class:`SHA512Hash` hash object - """ - - return SHA512Hash(data, truncate) - - -# The size of the full SHA-512 hash in bytes. -digest_size = 64 - -# The internal block size of the hash algorithm in bytes. -block_size = 128 - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha512_lib.SHA512_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA512" % result) - - return get_raw_buffer(bfr) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.pyi deleted file mode 100644 index f219ee9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHA512.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA512Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, - data: Optional[Buffer], - truncate: Optional[str]) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA512Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA512Hash: ... - -def new(data: Optional[Buffer] = ..., - truncate: Optional[str] = ...) -> SHA512Hash: ... -digest_size: int -block_size: int diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.py deleted file mode 100644 index 6f04b18..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.py +++ /dev/null @@ -1,145 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHAKE128_XOF(object): - """A SHAKE128 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - """ - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.11" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(32), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHAKE128" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - self._is_squeezing = False - self._padding = 0x1F - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHAKE128 state" - % result) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while extracting from SHAKE128" - % result) - - return get_raw_buffer(bfr) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHAKE128" % result) - return clone - - def new(self, data=None): - return type(self)(data=data) - - -def new(data=None): - """Return a fresh instance of a SHAKE128 object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - Optional. - - :Return: A :class:`SHAKE128_XOF` object - """ - - return SHAKE128_XOF(data=data) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.pyi deleted file mode 100644 index de51d8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE128.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHAKE128_XOF(object): - oid: str - def __init__(self, - data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> SHAKE128_XOF: ... - def read(self, length: int) -> bytes: ... - def copy(self) -> SHAKE128_XOF: ... - def new(self, data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... - -def new(data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.py deleted file mode 100644 index c96f090..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.py +++ /dev/null @@ -1,146 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHAKE256_XOF(object): - """A SHAKE256 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - """ - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.12" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(64), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating SHAKE256" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - self._is_squeezing = False - self._padding = 0x1F - - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHAKE256 state" - % result) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while extracting from SHAKE256" - % result) - - return get_raw_buffer(bfr) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - - :return: A hash object of the same type - """ - - clone = self.new() - result = _raw_keccak_lib.keccak_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHAKE256" % result) - return clone - - def new(self, data=None): - return type(self)(data=data) - - -def new(data=None): - """Return a fresh instance of a SHAKE256 object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - Optional. - - :Return: A :class:`SHAKE256_XOF` object - """ - - return SHAKE256_XOF(data=data) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.pyi deleted file mode 100644 index 72eb898..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/SHAKE256.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHAKE256_XOF(object): - oid: str - def __init__(self, - data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> SHAKE256_XOF: ... - def read(self, length: int) -> bytes: ... - def copy(self) -> SHAKE256_XOF: ... - def new(self, data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... - -def new(data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.py deleted file mode 100644 index a3fa96a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.py +++ /dev/null @@ -1,136 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord, is_bytes, tobytes - -from . import cSHAKE128 -from .cSHAKE128 import _encode_str, _right_encode - - -class TupleHash(object): - """A Tuple hash object. - Do not instantiate directly. - Use the :func:`new` function. - """ - - def __init__(self, custom, cshake, digest_size): - - self.digest_size = digest_size - - self._cshake = cshake._new(b'', custom, b'TupleHash') - self._digest = None - - def update(self, *data): - """Authenticate the next tuple of byte strings. - TupleHash guarantees the logical separation between each byte string. - - Args: - data (bytes/bytearray/memoryview): One or more items to hash. - """ - - if self._digest is not None: - raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'") - - for item in data: - if not is_bytes(item): - raise TypeError("You can only call 'update' on bytes" ) - self._cshake.update(_encode_str(item)) - - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the tuple of byte strings. - - :return: The hash digest. Binary form. - :rtype: byte string - """ - - if self._digest is None: - self._cshake.update(_right_encode(self.digest_size * 8)) - self._digest = self._cshake.read(self.digest_size) - - return self._digest - - def hexdigest(self): - """Return the **printable** digest of the tuple of byte strings. - - :return: The hash digest. Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - def new(self, **kwargs): - """Return a new instance of a TupleHash object. - See :func:`new`. - """ - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new TupleHash128 object. - - Args: - digest_bytes (integer): - Optional. The size of the digest, in bytes. - Default is 64. Minimum is 8. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (and in steps of 8). - Default is 512. Minimum is 64. - custom (bytes): - Optional. - A customization bytestring (``S`` in SP 800-185). - - :Return: A :class:`TupleHash` object - """ - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 64 - if digest_bytes is not None: - if digest_bytes < 8: - raise ValueError("'digest_bytes' must be at least 8") - else: - if digest_bits < 64 or digest_bits % 8: - raise ValueError("'digest_bytes' must be at least 64 " - "in steps of 8") - digest_bytes = digest_bits // 8 - - custom = kwargs.pop("custom", b'') - - return TupleHash(custom, cSHAKE128, digest_bytes) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.pyi deleted file mode 100644 index 2e0ea83..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash128.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Any, Union, List, Tuple -from types import ModuleType - -Buffer = Union[bytes, bytearray, memoryview] - -class TupleHash(object): - digest_size: int - def __init__(self, - custom: bytes, - cshake: ModuleType, - digest_size: int) -> None: ... - def update(self, *data: Buffer) -> TupleHash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self, - digest_bytes: int = ..., - digest_bits: int = ..., - custom: int = ...) -> TupleHash: ... - -def new(digest_bytes: int = ..., - digest_bits: int = ..., - custom: int = ...) -> TupleHash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.py deleted file mode 100644 index 40a824a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.py +++ /dev/null @@ -1,70 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from . import cSHAKE256 -from .TupleHash128 import TupleHash - - -def new(**kwargs): - """Create a new TupleHash256 object. - - Args: - digest_bytes (integer): - Optional. The size of the digest, in bytes. - Default is 64. Minimum is 8. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (and in steps of 8). - Default is 512. Minimum is 64. - custom (bytes): - Optional. - A customization bytestring (``S`` in SP 800-185). - - :Return: A :class:`TupleHash` object - """ - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 64 - if digest_bytes is not None: - if digest_bytes < 8: - raise ValueError("'digest_bytes' must be at least 8") - else: - if digest_bits < 64 or digest_bits % 8: - raise ValueError("'digest_bytes' must be at least 64 " - "in steps of 8") - digest_bytes = digest_bits // 8 - - custom = kwargs.pop("custom", b'') - - return TupleHash(custom, cSHAKE256, digest_bytes) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.pyi deleted file mode 100644 index 82d943f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TupleHash256.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from .TupleHash128 import TupleHash - -def new(digest_bytes: int = ..., - digest_bits: int = ..., - custom: int = ...) -> TupleHash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.py deleted file mode 100644 index ab3e4e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.py +++ /dev/null @@ -1,112 +0,0 @@ -from Crypto.Util._raw_api import (VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Util.number import long_to_bytes -from Crypto.Util.py3compat import bchr - -from .keccak import _raw_keccak_lib - - -class TurboSHAKE(object): - """A TurboSHAKE hash object. - Do not instantiate directly. - Use the :func:`new` function. - """ - - def __init__(self, capacity, domain_separation, data): - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(capacity), - c_ubyte(12)) # Reduced number of rounds - if result: - raise ValueError("Error %d while instantiating TurboSHAKE" - % result) - self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) - - self._is_squeezing = False - self._capacity = capacity - self._domain = domain_separation - - if data: - self.update(data) - - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating TurboSHAKE state" - % result) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length), - c_ubyte(self._domain)) - if result: - raise ValueError("Error %d while extracting from TurboSHAKE" - % result) - - return get_raw_buffer(bfr) - - def new(self, data=None): - return type(self)(self._capacity, self._domain, data) - - def _reset(self): - result = _raw_keccak_lib.keccak_reset(self._state.get()) - if result: - raise ValueError("Error %d while resetting TurboSHAKE state" - % result) - self._is_squeezing = False - - -def new(**kwargs): - """Create a new TurboSHAKE128 object. - - Args: - domain (integer): - Optional - A domain separation byte, between 0x01 and 0x7F. - The default value is 0x1F. - data (bytes/bytearray/memoryview): - Optional - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - - :Return: A :class:`TurboSHAKE` object - """ - - domain_separation = kwargs.get('domain', 0x1F) - if not (0x01 <= domain_separation <= 0x7F): - raise ValueError("Incorrect domain separation value (%d)" % - domain_separation) - data = kwargs.get('data') - return TurboSHAKE(32, domain_separation, data=data) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.pyi deleted file mode 100644 index d74c9c0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE128.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union, Optional -from typing_extensions import TypedDict, Unpack, NotRequired - -Buffer = Union[bytes, bytearray, memoryview] - -class TurboSHAKE(object): - - def __init__(self, capacity: int, domain_separation: int, data: Union[Buffer, None]) -> None: ... - def update(self, data: Buffer) -> TurboSHAKE : ... - def read(self, length: int) -> bytes: ... - def new(self, data: Optional[Buffer]=None) -> TurboSHAKE: ... - -class Args(TypedDict): - domain: NotRequired[int] - data: NotRequired[Buffer] - -def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.py deleted file mode 100644 index ce27a48..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.py +++ /dev/null @@ -1,22 +0,0 @@ -from .TurboSHAKE128 import TurboSHAKE - -def new(**kwargs): - """Create a new TurboSHAKE256 object. - - Args: - domain (integer): - Optional - A domain separation byte, between 0x01 and 0x7F. - The default value is 0x1F. - data (bytes/bytearray/memoryview): - Optional - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - - :Return: A :class:`TurboSHAKE` object - """ - - domain_separation = kwargs.get('domain', 0x1F) - if not (0x01 <= domain_separation <= 0x7F): - raise ValueError("Incorrect domain separation value (%d)" % - domain_separation) - data = kwargs.get('data') - return TurboSHAKE(64, domain_separation, data=data) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.pyi deleted file mode 100644 index 561e946..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/TurboSHAKE256.pyi +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Union -from typing_extensions import TypedDict, Unpack, NotRequired - -from .TurboSHAKE128 import TurboSHAKE - -Buffer = Union[bytes, bytearray, memoryview] - -class Args(TypedDict): - domain: NotRequired[int] - data: NotRequired[Buffer] - -def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2b.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2b.abi3.so deleted file mode 100755 index ad5b930..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2b.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2s.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2s.abi3.so deleted file mode 100755 index e6d4867..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_BLAKE2s.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD2.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD2.abi3.so deleted file mode 100755 index 49f4f66..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD2.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD4.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD4.abi3.so deleted file mode 100755 index b54c23a..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD4.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD5.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD5.abi3.so deleted file mode 100755 index 2eb506f..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_MD5.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_RIPEMD160.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_RIPEMD160.abi3.so deleted file mode 100755 index 369f91b..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_RIPEMD160.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA1.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA1.abi3.so deleted file mode 100755 index 48adbcc..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA1.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA224.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA224.abi3.so deleted file mode 100755 index f1ee58e..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA224.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA256.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA256.abi3.so deleted file mode 100755 index ebe2ae0..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA256.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA384.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA384.abi3.so deleted file mode 100755 index 5075481..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA384.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA512.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA512.abi3.so deleted file mode 100755 index 3a34d22..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_SHA512.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.py deleted file mode 100644 index 80446e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1', - 'SHA224', 'SHA256', 'SHA384', 'SHA512', - 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', - 'CMAC', 'Poly1305', - 'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256', - 'TupleHash128', 'TupleHash256', 'KangarooTwelve', - 'TurboSHAKE128', 'TurboSHAKE256'] - -def new(name): - """Return a new hash instance, based on its name or - on its ASN.1 Object ID""" - - name = name.upper() - if name in ("1.3.14.3.2.26", "SHA1", "SHA-1"): - from . import SHA1 - return SHA1.new() - if name in ("2.16.840.1.101.3.4.2.4", "SHA224", "SHA-224"): - from . import SHA224 - return SHA224.new() - if name in ("2.16.840.1.101.3.4.2.1", "SHA256", "SHA-256"): - from . import SHA256 - return SHA256.new() - if name in ("2.16.840.1.101.3.4.2.2", "SHA384", "SHA-384"): - from . import SHA384 - return SHA384.new() - if name in ("2.16.840.1.101.3.4.2.3", "SHA512", "SHA-512"): - from . import SHA512 - return SHA512.new() - if name in ("2.16.840.1.101.3.4.2.5", "SHA512-224", "SHA-512-224"): - from . import SHA512 - return SHA512.new(truncate='224') - if name in ("2.16.840.1.101.3.4.2.6", "SHA512-256", "SHA-512-256"): - from . import SHA512 - return SHA512.new(truncate='256') - if name in ("2.16.840.1.101.3.4.2.7", "SHA3-224", "SHA-3-224"): - from . import SHA3_224 - return SHA3_224.new() - if name in ("2.16.840.1.101.3.4.2.8", "SHA3-256", "SHA-3-256"): - from . import SHA3_256 - return SHA3_256.new() - if name in ("2.16.840.1.101.3.4.2.9", "SHA3-384", "SHA-3-384"): - from . import SHA3_384 - return SHA3_384.new() - if name in ("2.16.840.1.101.3.4.2.10", "SHA3-512", "SHA-3-512"): - from . import SHA3_512 - return SHA3_512.new() - else: - raise ValueError("Unknown hash %s" % str(name)) - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.pyi deleted file mode 100644 index 36ad48d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/__init__.pyi +++ /dev/null @@ -1,57 +0,0 @@ -from typing import overload -from typing_extensions import Literal - -from Crypto.Hash.SHA1 import SHA1Hash -from Crypto.Hash.SHA224 import SHA224Hash -from Crypto.Hash.SHA256 import SHA256Hash -from Crypto.Hash.SHA384 import SHA384Hash -from Crypto.Hash.SHA512 import SHA512Hash -from Crypto.Hash.SHA3_224 import SHA3_224_Hash -from Crypto.Hash.SHA3_256 import SHA3_256_Hash -from Crypto.Hash.SHA3_384 import SHA3_384_Hash -from Crypto.Hash.SHA3_512 import SHA3_512_Hash - -@overload -def new(name: Literal["1.3.14.3.2.26"]) -> SHA1Hash: ... -@overload -def new(name: Literal["SHA1"]) -> SHA1Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.4"]) -> SHA224Hash: ... -@overload -def new(name: Literal["SHA224"]) -> SHA224Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.1"]) -> SHA256Hash: ... -@overload -def new(name: Literal["SHA256"]) -> SHA256Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.2"]) -> SHA384Hash: ... -@overload -def new(name: Literal["SHA384"]) -> SHA384Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.3"]) -> SHA512Hash: ... -@overload -def new(name: Literal["SHA512"]) -> SHA512Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.5"]) -> SHA512Hash: ... -@overload -def new(name: Literal["SHA512-224"]) -> SHA512Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.6"]) -> SHA512Hash: ... -@overload -def new(name: Literal["SHA512-256"]) -> SHA512Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.7"]) -> SHA3_224_Hash: ... -@overload -def new(name: Literal["SHA3-224"]) -> SHA3_224_Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.8"]) -> SHA3_256_Hash: ... -@overload -def new(name: Literal["SHA3-256"]) -> SHA3_256_Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.9"]) -> SHA3_384_Hash: ... -@overload -def new(name: Literal["SHA3-384"]) -> SHA3_384_Hash: ... -@overload -def new(name: Literal["2.16.840.1.101.3.4.2.10"]) -> SHA3_512_Hash: ... -@overload -def new(name: Literal["SHA3-512"]) -> SHA3_512_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_ghash_portable.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_ghash_portable.abi3.so deleted file mode 100755 index 4f5f030..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_ghash_portable.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_keccak.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_keccak.abi3.so deleted file mode 100755 index 76d32dc..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_keccak.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_poly1305.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_poly1305.abi3.so deleted file mode 100755 index 8f2a5d9..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/_poly1305.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.py deleted file mode 100644 index 3907975..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.py +++ /dev/null @@ -1,187 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bchr, concat_buffers - -from Crypto.Util._raw_api import (VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -from Crypto.Util.number import long_to_bytes - -from Crypto.Hash.keccak import _raw_keccak_lib - - -def _left_encode(x): - """Left encode function as defined in NIST SP 800-185""" - - assert (x < (1 << 2040) and x >= 0) - - # Get number of bytes needed to represent this integer. - num = 1 if x == 0 else (x.bit_length() + 7) // 8 - - return bchr(num) + long_to_bytes(x) - - -def _right_encode(x): - """Right encode function as defined in NIST SP 800-185""" - - assert (x < (1 << 2040) and x >= 0) - - # Get number of bytes needed to represent this integer. - num = 1 if x == 0 else (x.bit_length() + 7) // 8 - - return long_to_bytes(x) + bchr(num) - - -def _encode_str(x): - """Encode string function as defined in NIST SP 800-185""" - - bitlen = len(x) * 8 - if bitlen >= (1 << 2040): - raise ValueError("String too large to encode in cSHAKE") - - return concat_buffers(_left_encode(bitlen), x) - - -def _bytepad(x, length): - """Zero pad byte string as defined in NIST SP 800-185""" - - to_pad = concat_buffers(_left_encode(length), x) - - # Note: this implementation works with byte aligned strings, - # hence no additional bit padding is needed at this point. - npad = (length - len(to_pad) % length) % length - - return to_pad + b'\x00' * npad - - -class cSHAKE_XOF(object): - """A cSHAKE hash object. - Do not instantiate directly. - Use the :func:`new` function. - """ - - def __init__(self, data, custom, capacity, function): - state = VoidPointer() - - if custom or function: - prefix_unpad = _encode_str(function) + _encode_str(custom) - prefix = _bytepad(prefix_unpad, (1600 - capacity)//8) - self._padding = 0x04 - else: - prefix = None - self._padding = 0x1F # for SHAKE - - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(capacity//8), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating cSHAKE" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - self._is_squeezing = False - - if prefix: - self.update(prefix) - - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating %s state" - % (result, self.name)) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while extracting from %s" - % (result, self.name)) - - return get_raw_buffer(bfr) - - -def _new(data, custom, function): - # Use Keccak[256] - return cSHAKE_XOF(data, custom, 256, function) - - -def new(data=None, custom=None): - """Return a fresh instance of a cSHAKE128 object. - - Args: - data (bytes/bytearray/memoryview): - Optional. - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - custom (bytes): - Optional. - A customization bytestring (``S`` in SP 800-185). - - :Return: A :class:`cSHAKE_XOF` object - """ - - # Use Keccak[256] - return cSHAKE_XOF(data, custom, 256, b'') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.pyi deleted file mode 100644 index 1452fea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE128.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class cSHAKE_XOF(object): - def __init__(self, - data: Optional[Buffer] = ..., - function: Optional[bytes] = ..., - custom: Optional[bytes] = ...) -> None: ... - def update(self, data: Buffer) -> cSHAKE_XOF: ... - def read(self, length: int) -> bytes: ... - -def new(data: Optional[Buffer] = ..., - custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.py deleted file mode 100644 index b3b31d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.py +++ /dev/null @@ -1,56 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2021, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util._raw_api import c_size_t -from Crypto.Hash.cSHAKE128 import cSHAKE_XOF - - -def _new(data, custom, function): - # Use Keccak[512] - return cSHAKE_XOF(data, custom, 512, function) - - -def new(data=None, custom=None): - """Return a fresh instance of a cSHAKE256 object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - Optional. - custom (bytes): - Optional. - A customization bytestring (``S`` in SP 800-185). - - :Return: A :class:`cSHAKE_XOF` object - """ - - # Use Keccak[512] - return cSHAKE_XOF(data, custom, 512, b'') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.pyi deleted file mode 100644 index 205b816..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/cSHAKE256.pyi +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Union, Optional - -from Crypto.Hash.cSHAKE128 import cSHAKE_XOF - -Buffer = Union[bytes, bytearray, memoryview] - -def new(data: Optional[Buffer] = ..., - custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.py deleted file mode 100644 index f3f8bb5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.py +++ /dev/null @@ -1,181 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr, c_ubyte) - -_raw_keccak_lib = load_pycryptodome_raw_lib("Crypto.Hash._keccak", - """ - int keccak_init(void **state, - size_t capacity_bytes, - uint8_t rounds); - int keccak_destroy(void *state); - int keccak_absorb(void *state, - const uint8_t *in, - size_t len); - int keccak_squeeze(const void *state, - uint8_t *out, - size_t len, - uint8_t padding); - int keccak_digest(void *state, - uint8_t *digest, - size_t len, - uint8_t padding); - int keccak_copy(const void *src, void *dst); - int keccak_reset(void *state); - """) - -class Keccak_Hash(object): - """A Keccak hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - def __init__(self, data, digest_bytes, update_after_digest): - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - self._padding = 0x01 - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - c_ubyte(24)) - if result: - raise ValueError("Error %d while instantiating keccak" % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating keccak" % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size), - c_ubyte(self._padding)) - if result: - raise ValueError("Error %d while squeezing keccak" % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self, **kwargs): - """Create a fresh Keccak hash object.""" - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`Keccak_Hash.update`. - digest_bytes (integer): - The size of the digest, in bytes (28, 32, 48, 64). - digest_bits (integer): - The size of the digest, in bits (224, 256, 384, 512). - update_after_digest (boolean): - Whether :meth:`Keccak.digest` can be followed by another - :meth:`Keccak.update` (default: ``False``). - - :Return: A :class:`Keccak_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - raise TypeError("Digest size (bits, bytes) not provided") - if digest_bytes is not None: - if digest_bytes not in (28, 32, 48, 64): - raise ValueError("'digest_bytes' must be: 28, 32, 48 or 64") - else: - if digest_bits not in (224, 256, 384, 512): - raise ValueError("'digest_bytes' must be: 224, 256, 384 or 512") - digest_bytes = digest_bits // 8 - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return Keccak_Hash(data, digest_bytes, update_after_digest) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.pyi deleted file mode 100644 index 844d256..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Hash/keccak.pyi +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union, Any - -Buffer = Union[bytes, bytearray, memoryview] - -class Keccak_Hash(object): - digest_size: int - def __init__(self, - data: Buffer, - digest_bytes: int, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> Keccak_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self, - data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - update_after_digest: bool = ...) -> Keccak_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - update_after_digest: bool = ...) -> Keccak_Hash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.py b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.py deleted file mode 100644 index 9b8b071..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.py +++ /dev/null @@ -1,191 +0,0 @@ -# -# Util/PEM.py : Privacy Enhanced Mail utilities -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['encode', 'decode'] - -import re -from binascii import a2b_base64, b2a_base64, hexlify, unhexlify - -from Crypto.Hash import MD5 -from Crypto.Util.Padding import pad, unpad -from Crypto.Cipher import DES, DES3, AES -from Crypto.Protocol.KDF import PBKDF1 -from Crypto.Random import get_random_bytes -from Crypto.Util.py3compat import tobytes, tostr - - -def encode(data, marker, passphrase=None, randfunc=None): - """Encode a piece of binary data into PEM format. - - Args: - data (byte string): - The piece of binary data to encode. - marker (string): - The marker for the PEM block (e.g. "PUBLIC KEY"). - Note that there is no official master list for all allowed markers. - Still, you can refer to the OpenSSL_ source code. - passphrase (byte string): - If given, the PEM block will be encrypted. The key is derived from - the passphrase. - randfunc (callable): - Random number generation function; it accepts an integer N and returns - a byte string of random data, N bytes long. If not given, a new one is - instantiated. - - Returns: - The PEM block, as a string. - - .. _OpenSSL: https://github.com/openssl/openssl/blob/master/include/openssl/pem.h - """ - - if randfunc is None: - randfunc = get_random_bytes - - out = "-----BEGIN %s-----\n" % marker - if passphrase: - # We only support 3DES for encryption - salt = randfunc(8) - key = PBKDF1(passphrase, salt, 16, 1, MD5) - key += PBKDF1(key + passphrase, salt, 8, 1, MD5) - objenc = DES3.new(key, DES3.MODE_CBC, salt) - out += "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,%s\n\n" %\ - tostr(hexlify(salt).upper()) - # Encrypt with PKCS#7 padding - data = objenc.encrypt(pad(data, objenc.block_size)) - elif passphrase is not None: - raise ValueError("Empty password") - - # Each BASE64 line can take up to 64 characters (=48 bytes of data) - # b2a_base64 adds a new line character! - chunks = [tostr(b2a_base64(data[i:i + 48])) - for i in range(0, len(data), 48)] - out += "".join(chunks) - out += "-----END %s-----" % marker - return out - - -def _EVP_BytesToKey(data, salt, key_len): - d = [ b'' ] - m = (key_len + 15 ) // 16 - for _ in range(m): - nd = MD5.new(d[-1] + data + salt).digest() - d.append(nd) - return b"".join(d)[:key_len] - - -def decode(pem_data, passphrase=None): - """Decode a PEM block into binary. - - Args: - pem_data (string): - The PEM block. - passphrase (byte string): - If given and the PEM block is encrypted, - the key will be derived from the passphrase. - - Returns: - A tuple with the binary data, the marker string, and a boolean to - indicate if decryption was performed. - - Raises: - ValueError: if decoding fails, if the PEM file is encrypted and no passphrase has - been provided or if the passphrase is incorrect. - """ - - # Verify Pre-Encapsulation Boundary - r = re.compile(r"\s*-----BEGIN (.*)-----\s+") - m = r.match(pem_data) - if not m: - raise ValueError("Not a valid PEM pre boundary") - marker = m.group(1) - - # Verify Post-Encapsulation Boundary - r = re.compile(r"-----END (.*)-----\s*$") - m = r.search(pem_data) - if not m or m.group(1) != marker: - raise ValueError("Not a valid PEM post boundary") - - # Removes spaces and slit on lines - lines = pem_data.replace(" ", '').split() - if len(lines) < 3: - raise ValueError("A PEM file must have at least 3 lines") - - # Decrypts, if necessary - if lines[1].startswith('Proc-Type:4,ENCRYPTED'): - if not passphrase: - raise ValueError("PEM is encrypted, but no passphrase available") - DEK = lines[2].split(':') - if len(DEK) != 2 or DEK[0] != 'DEK-Info': - raise ValueError("PEM encryption format not supported.") - algo, salt = DEK[1].split(',') - salt = unhexlify(tobytes(salt)) - - padding = True - - if algo == "DES-CBC": - key = _EVP_BytesToKey(passphrase, salt, 8) - objdec = DES.new(key, DES.MODE_CBC, salt) - elif algo == "DES-EDE3-CBC": - key = _EVP_BytesToKey(passphrase, salt, 24) - objdec = DES3.new(key, DES3.MODE_CBC, salt) - elif algo == "AES-128-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 16) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo == "AES-192-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 24) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo == "AES-256-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 32) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo.lower() == "id-aes256-gcm": - key = _EVP_BytesToKey(passphrase, salt[:8], 32) - objdec = AES.new(key, AES.MODE_GCM, nonce=salt) - padding = False - else: - raise ValueError("Unsupport PEM encryption algorithm (%s)." % algo) - lines = lines[2:] - else: - objdec = None - - # Decode body - data = a2b_base64(''.join(lines[1:-1])) - enc_flag = False - if objdec: - if padding: - data = unpad(objdec.decrypt(data), objdec.block_size) - else: - # There is no tag, so we don't use decrypt_and_verify - data = objdec.decrypt(data) - enc_flag = True - - return (data, marker, enc_flag) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.pyi deleted file mode 100644 index 2e324c4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PEM.pyi +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Tuple, Optional, Callable - -def encode(data: bytes, - marke: str, - passphrase: Optional[bytes] = ..., - randfunc: Optional[Callable[[int],bytes]] = ...) -> str: ... - - -def decode(pem_data: str, - passphrase: Optional[bytes] = ...) -> Tuple[bytes, str, bool]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.py b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.py deleted file mode 100644 index c1b79a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.py +++ /dev/null @@ -1,226 +0,0 @@ -# -# PublicKey/PKCS8.py : PKCS#8 functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - - -from Crypto.Util.py3compat import * - -from Crypto.Util.asn1 import ( - DerNull, - DerSequence, - DerObjectId, - DerOctetString, - ) - -from Crypto.IO._PBES import PBES1, PBES2, PbesError - - -__all__ = ['wrap', 'unwrap'] - - -def wrap(private_key, key_oid, passphrase=None, protection=None, - prot_params=None, key_params=DerNull(), randfunc=None): - """Wrap a private key into a PKCS#8 blob (clear or encrypted). - - Args: - - private_key (bytes): - The private key encoded in binary form. The actual encoding is - algorithm specific. In most cases, it is DER. - - key_oid (string): - The object identifier (OID) of the private key to wrap. - It is a dotted string, like ``'1.2.840.113549.1.1.1'`` (for RSA keys) - or ``'1.2.840.10045.2.1'`` (for ECC keys). - - Keyword Args: - - passphrase (bytes or string): - The secret passphrase from which the wrapping key is derived. - Set it only if encryption is required. - - protection (string): - The identifier of the algorithm to use for securely wrapping the key. - Refer to :ref:`the encryption parameters` . - The default value is ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'``. - - prot_params (dictionary): - Parameters for the key derivation function (KDF). - Refer to :ref:`the encryption parameters` . - - key_params (DER object or None): - The ``parameters`` field to use in the ``AlgorithmIdentifier`` - SEQUENCE. If ``None``, no ``parameters`` field will be added. - By default, the ASN.1 type ``NULL`` is used. - - randfunc (callable): - Random number generation function; it should accept a single integer - N and return a string of random data, N bytes long. - If not specified, a new RNG will be instantiated - from :mod:`Crypto.Random`. - - Returns: - bytes: The PKCS#8-wrapped private key (possibly encrypted). - """ - - # - # PrivateKeyInfo ::= SEQUENCE { - # version Version, - # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - # privateKey PrivateKey, - # attributes [0] IMPLICIT Attributes OPTIONAL - # } - # - if key_params is None: - algorithm = DerSequence([DerObjectId(key_oid)]) - else: - algorithm = DerSequence([DerObjectId(key_oid), key_params]) - - pk_info = DerSequence([ - 0, - algorithm, - DerOctetString(private_key) - ]) - pk_info_der = pk_info.encode() - - if passphrase is None: - return pk_info_der - - if not passphrase: - raise ValueError("Empty passphrase") - - # Encryption with PBES2 - passphrase = tobytes(passphrase) - if protection is None: - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - return PBES2.encrypt(pk_info_der, passphrase, - protection, prot_params, randfunc) - - -def unwrap(p8_private_key, passphrase=None): - """Unwrap a private key from a PKCS#8 blob (clear or encrypted). - - Args: - p8_private_key (bytes): - The private key wrapped into a PKCS#8 container, DER encoded. - - Keyword Args: - passphrase (byte string or string): - The passphrase to use to decrypt the blob (if it is encrypted). - - Return: - A tuple containing - - #. the algorithm identifier of the wrapped key (OID, dotted string) - #. the private key (bytes, DER encoded) - #. the associated parameters (bytes, DER encoded) or ``None`` - - Raises: - ValueError : if decoding fails - """ - - if passphrase is not None: - passphrase = tobytes(passphrase) - - found = False - try: - p8_private_key = PBES1.decrypt(p8_private_key, passphrase) - found = True - except PbesError as e: - error_str = "PBES1[%s]" % str(e) - except ValueError: - error_str = "PBES1[Invalid]" - - if not found: - try: - p8_private_key = PBES2.decrypt(p8_private_key, passphrase) - found = True - except PbesError as e: - error_str += ",PBES2[%s]" % str(e) - except ValueError: - error_str += ",PBES2[Invalid]" - - if not found: - raise ValueError("Error decoding PKCS#8 (%s)" % error_str) - - pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4, 5)) - if len(pk_info) == 2 and not passphrase: - raise ValueError("Not a valid clear PKCS#8 structure " - "(maybe it is encrypted?)") - - # RFC5208, PKCS#8, version is v1(0) - # - # PrivateKeyInfo ::= SEQUENCE { - # version Version, - # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - # privateKey PrivateKey, - # attributes [0] IMPLICIT Attributes OPTIONAL - # } - # - # RFC5915, Asymmetric Key Package, version is v2(1) - # - # OneAsymmetricKey ::= SEQUENCE { - # version Version, - # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - # privateKey PrivateKey, - # attributes [0] Attributes OPTIONAL, - # ..., - # [[2: publicKey [1] PublicKey OPTIONAL ]], - # ... - # } - - if pk_info[0] == 0: - if len(pk_info) not in (3, 4): - raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") - elif pk_info[0] == 1: - if len(pk_info) not in (3, 4, 5): - raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") - else: - raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") - - algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2)) - algo_oid = DerObjectId().decode(algo[0]).value - if len(algo) == 1: - algo_params = None - else: - try: - DerNull().decode(algo[1]) - algo_params = None - except: - algo_params = algo[1] - - # PrivateKey ::= OCTET STRING - private_key = DerOctetString().decode(pk_info[2]).payload - - # We ignore attributes and (for v2 only) publickey - - return (algo_oid, private_key, algo_params) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.pyi deleted file mode 100644 index cf6aa8a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/PKCS8.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Tuple, Optional, Union, Callable -from typing_extensions import NotRequired - -from Crypto.Util.asn1 import DerObject -from Crypto.IO._PBES import ProtParams - - -def wrap(private_key: bytes, - key_oid: str, - passphrase: Union[bytes, str] = ..., - protection: str = ..., - prot_params: Optional[ProtParams] = ..., - key_params: Optional[DerObject] = ..., - randfunc: Optional[Callable[[int], str]] = ...) -> bytes: ... - - -def unwrap(p8_private_key: bytes, passphrase: Optional[Union[bytes, str]] = ...) -> Tuple[str, bytes, Optional[bytes]]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.py deleted file mode 100644 index 93d3944..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.py +++ /dev/null @@ -1,546 +0,0 @@ -# -# PublicKey/_PBES.py : Password-Based Encryption functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import re - -from Crypto import Hash -from Crypto import Random -from Crypto.Util.asn1 import ( - DerSequence, DerOctetString, - DerObjectId, DerInteger, - ) - -from Crypto.Cipher import AES -from Crypto.Util.Padding import pad, unpad -from Crypto.Protocol.KDF import PBKDF1, PBKDF2, scrypt - -_OID_PBE_WITH_MD5_AND_DES_CBC = "1.2.840.113549.1.5.3" -_OID_PBE_WITH_MD5_AND_RC2_CBC = "1.2.840.113549.1.5.6" -_OID_PBE_WITH_SHA1_AND_DES_CBC = "1.2.840.113549.1.5.10" -_OID_PBE_WITH_SHA1_AND_RC2_CBC = "1.2.840.113549.1.5.11" - -_OID_PBES2 = "1.2.840.113549.1.5.13" - -_OID_PBKDF2 = "1.2.840.113549.1.5.12" -_OID_SCRYPT = "1.3.6.1.4.1.11591.4.11" - -_OID_HMAC_SHA1 = "1.2.840.113549.2.7" - -_OID_DES_EDE3_CBC = "1.2.840.113549.3.7" -_OID_AES128_CBC = "2.16.840.1.101.3.4.1.2" -_OID_AES192_CBC = "2.16.840.1.101.3.4.1.22" -_OID_AES256_CBC = "2.16.840.1.101.3.4.1.42" -_OID_AES128_GCM = "2.16.840.1.101.3.4.1.6" -_OID_AES192_GCM = "2.16.840.1.101.3.4.1.26" -_OID_AES256_GCM = "2.16.840.1.101.3.4.1.46" - -class PbesError(ValueError): - pass - -# These are the ASN.1 definitions used by the PBES1/2 logic: -# -# EncryptedPrivateKeyInfo ::= SEQUENCE { -# encryptionAlgorithm EncryptionAlgorithmIdentifier, -# encryptedData EncryptedData -# } -# -# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier -# -# EncryptedData ::= OCTET STRING -# -# AlgorithmIdentifier ::= SEQUENCE { -# algorithm OBJECT IDENTIFIER, -# parameters ANY DEFINED BY algorithm OPTIONAL -# } -# -# PBEParameter ::= SEQUENCE { -# salt OCTET STRING (SIZE(8)), -# iterationCount INTEGER -# } -# -# PBES2-params ::= SEQUENCE { -# keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, -# encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} -# } -# -# PBKDF2-params ::= SEQUENCE { -# salt CHOICE { -# specified OCTET STRING, -# otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} -# }, -# iterationCount INTEGER (1..MAX), -# keyLength INTEGER (1..MAX) OPTIONAL, -# prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 -# } -# -# PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { -# {NULL IDENTIFIED BY id-hmacWithSHA1}, -# {NULL IDENTIFIED BY id-hmacWithSHA224}, -# {NULL IDENTIFIED BY id-hmacWithSHA256}, -# {NULL IDENTIFIED BY id-hmacWithSHA384}, -# {NULL IDENTIFIED BY id-hmacWithSHA512}, -# {NULL IDENTIFIED BY id-hmacWithSHA512-224}, -# {NULL IDENTIFIED BY id-hmacWithSHA512-256}, -# ... -# } -# scrypt-params ::= SEQUENCE { -# salt OCTET STRING, -# costParameter INTEGER (1..MAX), -# blockSize INTEGER (1..MAX), -# parallelizationParameter INTEGER (1..MAX), -# keyLength INTEGER (1..MAX) OPTIONAL -# } - - -class PBES1(object): - """Deprecated encryption scheme with password-based key derivation - (originally defined in PKCS#5 v1.5, but still present in `v2.0`__). - - .. __: http://www.ietf.org/rfc/rfc2898.txt - """ - - @staticmethod - def decrypt(data, passphrase): - """Decrypt a piece of data using a passphrase and *PBES1*. - - The algorithm to use is automatically detected. - - :Parameters: - data : byte string - The piece of data to decrypt. - passphrase : byte string - The passphrase to use for decrypting the data. - :Returns: - The decrypted data, as a binary string. - """ - - enc_private_key_info = DerSequence().decode(data) - encrypted_algorithm = DerSequence().decode(enc_private_key_info[0]) - encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload - - pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value - cipher_params = {} - if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: - # PBE_MD5_DES_CBC - from Crypto.Hash import MD5 - from Crypto.Cipher import DES - hashmod = MD5 - module = DES - elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: - # PBE_MD5_RC2_CBC - from Crypto.Hash import MD5 - from Crypto.Cipher import ARC2 - hashmod = MD5 - module = ARC2 - cipher_params['effective_keylen'] = 64 - elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: - # PBE_SHA1_DES_CBC - from Crypto.Hash import SHA1 - from Crypto.Cipher import DES - hashmod = SHA1 - module = DES - elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: - # PBE_SHA1_RC2_CBC - from Crypto.Hash import SHA1 - from Crypto.Cipher import ARC2 - hashmod = SHA1 - module = ARC2 - cipher_params['effective_keylen'] = 64 - else: - raise PbesError("Unknown OID for PBES1") - - pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2) - salt = DerOctetString().decode(pbe_params[0]).payload - iterations = pbe_params[1] - - key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) - key, iv = key_iv[:8], key_iv[8:] - - cipher = module.new(key, module.MODE_CBC, iv, **cipher_params) - pt = cipher.decrypt(encrypted_data) - return unpad(pt, cipher.block_size) - - -class PBES2(object): - """Encryption scheme with password-based key derivation - (defined in `PKCS#5 v2.0`__). - - .. __: http://www.ietf.org/rfc/rfc2898.txt.""" - - @staticmethod - def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): - """Encrypt a piece of data using a passphrase and *PBES2*. - - :Parameters: - data : byte string - The piece of data to encrypt. - passphrase : byte string - The passphrase to use for encrypting the data. - protection : string - The identifier of the encryption algorithm to use. - The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. - prot_params : dictionary - Parameters of the protection algorithm. - - +------------------+-----------------------------------------------+ - | Key | Description | - +==================+===============================================+ - | iteration_count | The KDF algorithm is repeated several times to| - | | slow down brute force attacks on passwords | - | | (called *N* or CPU/memory cost in scrypt). | - | | | - | | The default value for PBKDF2 is 1 000. | - | | The default value for scrypt is 16 384. | - +------------------+-----------------------------------------------+ - | salt_size | Salt is used to thwart dictionary and rainbow | - | | attacks on passwords. The default value is 8 | - | | bytes. | - +------------------+-----------------------------------------------+ - | block_size | *(scrypt only)* Memory-cost (r). The default | - | | value is 8. | - +------------------+-----------------------------------------------+ - | parallelization | *(scrypt only)* CPU-cost (p). The default | - | | value is 1. | - +------------------+-----------------------------------------------+ - - - randfunc : callable - Random number generation function; it should accept - a single integer N and return a string of random data, - N bytes long. If not specified, a new RNG will be - instantiated from ``Crypto.Random``. - - :Returns: - The encrypted data, as a binary string. - """ - - if prot_params is None: - prot_params = {} - - if randfunc is None: - randfunc = Random.new().read - - pattern = re.compile(r'^(PBKDF2WithHMAC-([0-9A-Z-]+)|scrypt)And([0-9A-Z-]+)$') - res = pattern.match(protection) - if res is None: - raise ValueError("Unknown protection %s" % protection) - - if protection.startswith("PBKDF"): - pbkdf = "pbkdf2" - pbkdf2_hmac_algo = res.group(2) - enc_algo = res.group(3) - else: - pbkdf = "scrypt" - enc_algo = res.group(3) - - aead = False - if enc_algo == 'DES-EDE3-CBC': - from Crypto.Cipher import DES3 - key_size = 24 - module = DES3 - cipher_mode = DES3.MODE_CBC - enc_oid = _OID_DES_EDE3_CBC - enc_param = {'iv': randfunc(8)} - elif enc_algo == 'AES128-CBC': - key_size = 16 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES128_CBC - enc_param = {'iv': randfunc(16)} - elif enc_algo == 'AES192-CBC': - key_size = 24 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES192_CBC - enc_param = {'iv': randfunc(16)} - elif enc_algo == 'AES256-CBC': - key_size = 32 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES256_CBC - enc_param = {'iv': randfunc(16)} - elif enc_algo == 'AES128-GCM': - key_size = 16 - module = AES - cipher_mode = AES.MODE_GCM - enc_oid = _OID_AES128_GCM - enc_param = {'nonce': randfunc(12)} - aead = True - elif enc_algo == 'AES192-GCM': - key_size = 24 - module = AES - cipher_mode = AES.MODE_GCM - enc_oid = _OID_AES192_GCM - enc_param = {'nonce': randfunc(12)} - aead = True - elif enc_algo == 'AES256-GCM': - key_size = 32 - module = AES - cipher_mode = AES.MODE_GCM - enc_oid = _OID_AES256_GCM - enc_param = {'nonce': randfunc(12)} - aead = True - else: - raise ValueError("Unknown encryption mode '%s'" % enc_algo) - - iv_nonce = list(enc_param.values())[0] - salt = randfunc(prot_params.get("salt_size", 8)) - - # Derive key from password - if pbkdf == 'pbkdf2': - - count = prot_params.get("iteration_count", 1000) - digestmod = Hash.new(pbkdf2_hmac_algo) - - key = PBKDF2(passphrase, - salt, - key_size, - count, - hmac_hash_module=digestmod) - - pbkdf2_params = DerSequence([ - DerOctetString(salt), - DerInteger(count) - ]) - - if pbkdf2_hmac_algo != 'SHA1': - try: - hmac_oid = Hash.HMAC.new(b'', digestmod=digestmod).oid - except KeyError: - raise ValueError("No OID for HMAC hash algorithm") - pbkdf2_params.append(DerSequence([DerObjectId(hmac_oid)])) - - kdf_info = DerSequence([ - DerObjectId(_OID_PBKDF2), # PBKDF2 - pbkdf2_params - ]) - - elif pbkdf == 'scrypt': - - count = prot_params.get("iteration_count", 16384) - scrypt_r = prot_params.get('block_size', 8) - scrypt_p = prot_params.get('parallelization', 1) - key = scrypt(passphrase, salt, key_size, - count, scrypt_r, scrypt_p) - kdf_info = DerSequence([ - DerObjectId(_OID_SCRYPT), # scrypt - DerSequence([ - DerOctetString(salt), - DerInteger(count), - DerInteger(scrypt_r), - DerInteger(scrypt_p) - ]) - ]) - - else: - raise ValueError("Unknown KDF " + res.group(1)) - - # Create cipher and use it - cipher = module.new(key, cipher_mode, **enc_param) - if aead: - ct, tag = cipher.encrypt_and_digest(data) - encrypted_data = ct + tag - else: - encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) - enc_info = DerSequence([ - DerObjectId(enc_oid), - DerOctetString(iv_nonce) - ]) - - # Result - enc_private_key_info = DerSequence([ - # encryptionAlgorithm - DerSequence([ - DerObjectId(_OID_PBES2), - DerSequence([ - kdf_info, - enc_info - ]), - ]), - DerOctetString(encrypted_data) - ]) - return enc_private_key_info.encode() - - @staticmethod - def decrypt(data, passphrase): - """Decrypt a piece of data using a passphrase and *PBES2*. - - The algorithm to use is automatically detected. - - :Parameters: - data : byte string - The piece of data to decrypt. - passphrase : byte string - The passphrase to use for decrypting the data. - :Returns: - The decrypted data, as a binary string. - """ - - enc_private_key_info = DerSequence().decode(data, nr_elements=2) - enc_algo = DerSequence().decode(enc_private_key_info[0]) - encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload - - pbe_oid = DerObjectId().decode(enc_algo[0]).value - if pbe_oid != _OID_PBES2: - raise PbesError("Not a PBES2 object") - - pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2) - - # Key Derivation Function selection - kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2) - kdf_oid = DerObjectId().decode(kdf_info[0]).value - - kdf_key_length = None - - # We only support PBKDF2 or scrypt - if kdf_oid == _OID_PBKDF2: - - pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4)) - salt = DerOctetString().decode(pbkdf2_params[0]).payload - iteration_count = pbkdf2_params[1] - - left = len(pbkdf2_params) - 2 - idx = 2 - - if left > 0: - try: - # Check if it's an INTEGER - kdf_key_length = pbkdf2_params[idx] - 0 - left -= 1 - idx += 1 - except TypeError: - # keyLength is not present - pass - - # Default is HMAC-SHA1 - pbkdf2_prf_oid = _OID_HMAC_SHA1 - if left > 0: - pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx]) - pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value - - elif kdf_oid == _OID_SCRYPT: - - scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5)) - salt = DerOctetString().decode(scrypt_params[0]).payload - iteration_count, scrypt_r, scrypt_p = [scrypt_params[x] - for x in (1, 2, 3)] - if len(scrypt_params) > 4: - kdf_key_length = scrypt_params[4] - else: - kdf_key_length = None - else: - raise PbesError("Unsupported PBES2 KDF") - - # Cipher selection - enc_info = DerSequence().decode(pbes2_params[1]) - enc_oid = DerObjectId().decode(enc_info[0]).value - - aead = False - if enc_oid == _OID_DES_EDE3_CBC: - # DES_EDE3_CBC - from Crypto.Cipher import DES3 - module = DES3 - cipher_mode = DES3.MODE_CBC - key_size = 24 - cipher_param = 'iv' - elif enc_oid == _OID_AES128_CBC: - module = AES - cipher_mode = AES.MODE_CBC - key_size = 16 - cipher_param = 'iv' - elif enc_oid == _OID_AES192_CBC: - module = AES - cipher_mode = AES.MODE_CBC - key_size = 24 - cipher_param = 'iv' - elif enc_oid == _OID_AES256_CBC: - module = AES - cipher_mode = AES.MODE_CBC - key_size = 32 - cipher_param = 'iv' - elif enc_oid == _OID_AES128_GCM: - module = AES - cipher_mode = AES.MODE_GCM - key_size = 16 - cipher_param = 'nonce' - aead = True - elif enc_oid == _OID_AES192_GCM: - module = AES - cipher_mode = AES.MODE_GCM - key_size = 24 - cipher_param = 'nonce' - aead = True - elif enc_oid == _OID_AES256_GCM: - module = AES - cipher_mode = AES.MODE_GCM - key_size = 32 - cipher_param = 'nonce' - aead = True - else: - raise PbesError("Unsupported PBES2 cipher " + enc_algo) - - if kdf_key_length and kdf_key_length != key_size: - raise PbesError("Mismatch between PBES2 KDF parameters" - " and selected cipher") - - iv_nonce = DerOctetString().decode(enc_info[1]).payload - - # Create cipher - if kdf_oid == _OID_PBKDF2: - - try: - hmac_hash_module_oid = Hash.HMAC._hmac2hash_oid[pbkdf2_prf_oid] - except KeyError: - raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid) - hmac_hash_module = Hash.new(hmac_hash_module_oid) - - key = PBKDF2(passphrase, salt, key_size, iteration_count, - hmac_hash_module=hmac_hash_module) - else: - key = scrypt(passphrase, salt, key_size, iteration_count, - scrypt_r, scrypt_p) - cipher = module.new(key, cipher_mode, **{cipher_param:iv_nonce}) - - # Decrypt data - if len(encrypted_data) < cipher.block_size: - raise ValueError("Too little data to decrypt") - - if aead: - tag_len = cipher.block_size - pt = cipher.decrypt_and_verify(encrypted_data[:-tag_len], - encrypted_data[-tag_len:]) - else: - pt_padded = cipher.decrypt(encrypted_data) - pt = unpad(pt_padded, cipher.block_size) - - return pt diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.pyi deleted file mode 100644 index 0673364..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/_PBES.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Optional, Callable, TypedDict -from typing_extensions import NotRequired - -class PbesError(ValueError): - ... - -class PBES1(object): - @staticmethod - def decrypt(data: bytes, passphrase: bytes) -> bytes: ... - -class ProtParams(TypedDict): - iteration_count: NotRequired[int] - salt_size: NotRequired[int] - block_size: NotRequired[int] - parallelization: NotRequired[int] - -class PBES2(object): - @staticmethod - def encrypt(data: bytes, - passphrase: bytes, - protection: str, - prot_params: Optional[ProtParams] = ..., - randfunc: Optional[Callable[[int],bytes]] = ...) -> bytes: ... - - @staticmethod - def decrypt(data:bytes, passphrase: bytes) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/IO/__init__.py deleted file mode 100644 index 85a0d0b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/IO/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['PEM', 'PKCS8'] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.py deleted file mode 100644 index d9218f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.py +++ /dev/null @@ -1,47 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ["Integer"] - -import os - -try: - if os.getenv("PYCRYPTODOME_DISABLE_GMP"): - raise ImportError() - - from Crypto.Math._IntegerGMP import IntegerGMP as Integer - from Crypto.Math._IntegerGMP import implementation as _implementation -except (ImportError, OSError, AttributeError): - try: - from Crypto.Math._IntegerCustom import IntegerCustom as Integer - from Crypto.Math._IntegerCustom import implementation as _implementation - except (ImportError, OSError): - from Crypto.Math._IntegerNative import IntegerNative as Integer - _implementation = {} diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.pyi deleted file mode 100644 index 24e234b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Numbers.pyi +++ /dev/null @@ -1,2 +0,0 @@ -from Crypto.Math._IntegerBase import IntegerBase as Integer -__all__ = ['Integer'] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.py deleted file mode 100644 index 884c418..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.py +++ /dev/null @@ -1,369 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Functions to create and test prime numbers. - -:undocumented: __package__ -""" - -from Crypto import Random -from Crypto.Math.Numbers import Integer - -from Crypto.Util.py3compat import iter_range - -COMPOSITE = 0 -PROBABLY_PRIME = 1 - - -def miller_rabin_test(candidate, iterations, randfunc=None): - """Perform a Miller-Rabin primality test on an integer. - - The test is specified in Section C.3.1 of `FIPS PUB 186-4`__. - - :Parameters: - candidate : integer - The number to test for primality. - iterations : integer - The maximum number of iterations to perform before - declaring a candidate a probable prime. - randfunc : callable - An RNG function where bases are taken from. - - :Returns: - ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - if candidate in (1, 2, 3, 5): - return PROBABLY_PRIME - - if candidate.is_even(): - return COMPOSITE - - one = Integer(1) - minus_one = Integer(candidate - 1) - - if randfunc is None: - randfunc = Random.new().read - - # Step 1 and 2 - m = Integer(minus_one) - a = 0 - while m.is_even(): - m >>= 1 - a += 1 - - # Skip step 3 - - # Step 4 - for i in iter_range(iterations): - - # Step 4.1-2 - base = 1 - while base in (one, minus_one): - base = Integer.random_range(min_inclusive=2, - max_inclusive=candidate - 2, - randfunc=randfunc) - assert(2 <= base <= candidate - 2) - - # Step 4.3-4.4 - z = pow(base, m, candidate) - if z in (one, minus_one): - continue - - # Step 4.5 - for j in iter_range(1, a): - z = pow(z, 2, candidate) - if z == minus_one: - break - if z == one: - return COMPOSITE - else: - return COMPOSITE - - # Step 5 - return PROBABLY_PRIME - - -def lucas_test(candidate): - """Perform a Lucas primality test on an integer. - - The test is specified in Section C.3.3 of `FIPS PUB 186-4`__. - - :Parameters: - candidate : integer - The number to test for primality. - - :Returns: - ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - # Step 1 - if candidate in (1, 2, 3, 5): - return PROBABLY_PRIME - if candidate.is_even() or candidate.is_perfect_square(): - return COMPOSITE - - # Step 2 - def alternate(): - value = 5 - while True: - yield value - if value > 0: - value += 2 - else: - value -= 2 - value = -value - - for D in alternate(): - if candidate in (D, -D): - continue - js = Integer.jacobi_symbol(D, candidate) - if js == 0: - return COMPOSITE - if js == -1: - break - # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer) - - # Step 3 - # This is \delta(n) = n - jacobi(D/n) - K = candidate + 1 - # Step 4 - r = K.size_in_bits() - 1 - # Step 5 - # U_1=1 and V_1=P - U_i = Integer(1) - V_i = Integer(1) - U_temp = Integer(0) - V_temp = Integer(0) - # Step 6 - for i in iter_range(r - 1, -1, -1): - # Square - # U_temp = U_i * V_i % candidate - U_temp.set(U_i) - U_temp *= V_i - U_temp %= candidate - # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % candidate - V_temp.set(U_i) - V_temp *= U_i - V_temp *= D - V_temp.multiply_accumulate(V_i, V_i) - if V_temp.is_odd(): - V_temp += candidate - V_temp >>= 1 - V_temp %= candidate - # Multiply - if K.get_bit(i): - # U_i = (((U_temp + V_temp) * K) >> 1) % candidate - U_i.set(U_temp) - U_i += V_temp - if U_i.is_odd(): - U_i += candidate - U_i >>= 1 - U_i %= candidate - # V_i = (((V_temp + U_temp * D) * K) >> 1) % candidate - V_i.set(V_temp) - V_i.multiply_accumulate(U_temp, D) - if V_i.is_odd(): - V_i += candidate - V_i >>= 1 - V_i %= candidate - else: - U_i.set(U_temp) - V_i.set(V_temp) - # Step 7 - if U_i == 0: - return PROBABLY_PRIME - return COMPOSITE - - -from Crypto.Util.number import sieve_base as _sieve_base_large -## The optimal number of small primes to use for the sieve -## is probably dependent on the platform and the candidate size -_sieve_base = set(_sieve_base_large[:100]) - - -def test_probable_prime(candidate, randfunc=None): - """Test if a number is prime. - - A number is qualified as prime if it passes a certain - number of Miller-Rabin tests (dependent on the size - of the number, but such that probability of a false - positive is less than 10^-30) and a single Lucas test. - - For instance, a 1024-bit candidate will need to pass - 4 Miller-Rabin tests. - - :Parameters: - candidate : integer - The number to test for primality. - randfunc : callable - The routine to draw random bytes from to select Miller-Rabin bases. - :Returns: - ``PROBABLE_PRIME`` if the number if prime with very high probability. - ``COMPOSITE`` if the number is a composite. - For efficiency reasons, ``COMPOSITE`` is also returned for small primes. - """ - - if randfunc is None: - randfunc = Random.new().read - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - # First, check trial division by the smallest primes - if int(candidate) in _sieve_base: - return PROBABLY_PRIME - try: - map(candidate.fail_if_divisible_by, _sieve_base) - except ValueError: - return COMPOSITE - - # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30, - # with p(k, t) being the probability that a randomly chosen k-bit number - # is composite but still survives t MR iterations. - mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10), - (620, 7), (740, 6), (890, 5), (1200, 4), - (1700, 3), (3700, 2)) - - bit_size = candidate.size_in_bits() - try: - mr_iterations = list(filter(lambda x: bit_size < x[0], - mr_ranges))[0][1] - except IndexError: - mr_iterations = 1 - - if miller_rabin_test(candidate, mr_iterations, - randfunc=randfunc) == COMPOSITE: - return COMPOSITE - if lucas_test(candidate) == COMPOSITE: - return COMPOSITE - return PROBABLY_PRIME - - -def generate_probable_prime(**kwargs): - """Generate a random probable prime. - - The prime will not have any specific properties - (e.g. it will not be a *strong* prime). - - Random numbers are evaluated for primality until one - passes all tests, consisting of a certain number of - Miller-Rabin tests with random bases followed by - a single Lucas test. - - The number of Miller-Rabin iterations is chosen such that - the probability that the output number is a non-prime is - less than 1E-30 (roughly 2^{-100}). - - This approach is compliant to `FIPS PUB 186-4`__. - - :Keywords: - exact_bits : integer - The desired size in bits of the probable prime. - It must be at least 160. - randfunc : callable - An RNG function where candidate primes are taken from. - prime_filter : callable - A function that takes an Integer as parameter and returns - True if the number can be passed to further primality tests, - False if it should be immediately discarded. - - :Return: - A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1). - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - exact_bits = kwargs.pop("exact_bits", None) - randfunc = kwargs.pop("randfunc", None) - prime_filter = kwargs.pop("prime_filter", lambda x: True) - if kwargs: - raise ValueError("Unknown parameters: " + kwargs.keys()) - - if exact_bits is None: - raise ValueError("Missing exact_bits parameter") - if exact_bits < 160: - raise ValueError("Prime number is not big enough.") - - if randfunc is None: - randfunc = Random.new().read - - result = COMPOSITE - while result == COMPOSITE: - candidate = Integer.random(exact_bits=exact_bits, - randfunc=randfunc) | 1 - if not prime_filter(candidate): - continue - result = test_probable_prime(candidate, randfunc) - return candidate - - -def generate_probable_safe_prime(**kwargs): - """Generate a random, probable safe prime. - - Note this operation is much slower than generating a simple prime. - - :Keywords: - exact_bits : integer - The desired size in bits of the probable safe prime. - randfunc : callable - An RNG function where candidate primes are taken from. - - :Return: - A probable safe prime in the range - 2^exact_bits > p > 2^(exact_bits-1). - """ - - exact_bits = kwargs.pop("exact_bits", None) - randfunc = kwargs.pop("randfunc", None) - if kwargs: - raise ValueError("Unknown parameters: " + kwargs.keys()) - - if randfunc is None: - randfunc = Random.new().read - - result = COMPOSITE - while result == COMPOSITE: - q = generate_probable_prime(exact_bits=exact_bits - 1, randfunc=randfunc) - candidate = q * 2 + 1 - if candidate.size_in_bits() != exact_bits: - continue - result = test_probable_prime(candidate, randfunc=randfunc) - return candidate diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.pyi deleted file mode 100644 index 7813483..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/Primality.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Callable, Optional, Union, Set - -PrimeResult = int - -COMPOSITE: PrimeResult -PROBABLY_PRIME: PrimeResult - -def miller_rabin_test(candidate: int, iterations: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... -def lucas_test(candidate: int) -> PrimeResult: ... -_sieve_base: Set[int] -def test_probable_prime(candidate: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... -def generate_probable_prime(*, - exact_bits: int = ..., - randfunc: Callable[[int],bytes] = ..., - prime_filter: Callable[[int],bool] = ...) -> int: ... -def generate_probable_safe_prime(*, - exact_bits: int = ..., - randfunc: Callable[[int],bytes] = ...) -> int: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.py deleted file mode 100644 index 931743a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.py +++ /dev/null @@ -1,412 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import abc - -from Crypto.Util.py3compat import iter_range, bord, bchr, ABC - -from Crypto import Random - - -class IntegerBase(ABC): - - # Conversions - @abc.abstractmethod - def __int__(self): - pass - - @abc.abstractmethod - def __str__(self): - pass - - @abc.abstractmethod - def __repr__(self): - pass - - @abc.abstractmethod - def to_bytes(self, block_size=0, byteorder='big'): - pass - - @staticmethod - @abc.abstractmethod - def from_bytes(byte_string, byteorder='big'): - pass - - # Relations - @abc.abstractmethod - def __eq__(self, term): - pass - - @abc.abstractmethod - def __ne__(self, term): - pass - - @abc.abstractmethod - def __lt__(self, term): - pass - - @abc.abstractmethod - def __le__(self, term): - pass - - @abc.abstractmethod - def __gt__(self, term): - pass - - @abc.abstractmethod - def __ge__(self, term): - pass - - @abc.abstractmethod - def __nonzero__(self): - pass - __bool__ = __nonzero__ - - @abc.abstractmethod - def is_negative(self): - pass - - # Arithmetic operations - @abc.abstractmethod - def __add__(self, term): - pass - - @abc.abstractmethod - def __sub__(self, term): - pass - - @abc.abstractmethod - def __mul__(self, factor): - pass - - @abc.abstractmethod - def __floordiv__(self, divisor): - pass - - @abc.abstractmethod - def __mod__(self, divisor): - pass - - @abc.abstractmethod - def inplace_pow(self, exponent, modulus=None): - pass - - @abc.abstractmethod - def __pow__(self, exponent, modulus=None): - pass - - @abc.abstractmethod - def __abs__(self): - pass - - @abc.abstractmethod - def sqrt(self, modulus=None): - pass - - @abc.abstractmethod - def __iadd__(self, term): - pass - - @abc.abstractmethod - def __isub__(self, term): - pass - - @abc.abstractmethod - def __imul__(self, term): - pass - - @abc.abstractmethod - def __imod__(self, term): - pass - - # Boolean/bit operations - @abc.abstractmethod - def __and__(self, term): - pass - - @abc.abstractmethod - def __or__(self, term): - pass - - @abc.abstractmethod - def __rshift__(self, pos): - pass - - @abc.abstractmethod - def __irshift__(self, pos): - pass - - @abc.abstractmethod - def __lshift__(self, pos): - pass - - @abc.abstractmethod - def __ilshift__(self, pos): - pass - - @abc.abstractmethod - def get_bit(self, n): - pass - - # Extra - @abc.abstractmethod - def is_odd(self): - pass - - @abc.abstractmethod - def is_even(self): - pass - - @abc.abstractmethod - def size_in_bits(self): - pass - - @abc.abstractmethod - def size_in_bytes(self): - pass - - @abc.abstractmethod - def is_perfect_square(self): - pass - - @abc.abstractmethod - def fail_if_divisible_by(self, small_prime): - pass - - @abc.abstractmethod - def multiply_accumulate(self, a, b): - pass - - @abc.abstractmethod - def set(self, source): - pass - - @abc.abstractmethod - def inplace_inverse(self, modulus): - pass - - @abc.abstractmethod - def inverse(self, modulus): - pass - - @abc.abstractmethod - def gcd(self, term): - pass - - @abc.abstractmethod - def lcm(self, term): - pass - - @staticmethod - @abc.abstractmethod - def jacobi_symbol(a, n): - pass - - @staticmethod - def _tonelli_shanks(n, p): - """Tonelli-shanks algorithm for computing the square root - of n modulo a prime p. - - n must be in the range [0..p-1]. - p must be at least even. - - The return value r is the square root of modulo p. If non-zero, - another solution will also exist (p-r). - - Note we cannot assume that p is really a prime: if it's not, - we can either raise an exception or return the correct value. - """ - - # See https://rosettacode.org/wiki/Tonelli-Shanks_algorithm - - if n in (0, 1): - return n - - if p % 4 == 3: - root = pow(n, (p + 1) // 4, p) - if pow(root, 2, p) != n: - raise ValueError("Cannot compute square root") - return root - - s = 1 - q = (p - 1) // 2 - while not (q & 1): - s += 1 - q >>= 1 - - z = n.__class__(2) - while True: - euler = pow(z, (p - 1) // 2, p) - if euler == 1: - z += 1 - continue - if euler == p - 1: - break - # Most probably p is not a prime - raise ValueError("Cannot compute square root") - - m = s - c = pow(z, q, p) - t = pow(n, q, p) - r = pow(n, (q + 1) // 2, p) - - while t != 1: - for i in iter_range(0, m): - if pow(t, 2**i, p) == 1: - break - if i == m: - raise ValueError("Cannot compute square root of %d mod %d" % (n, p)) - b = pow(c, 2**(m - i - 1), p) - m = i - c = b**2 % p - t = (t * b**2) % p - r = (r * b) % p - - if pow(r, 2, p) != n: - raise ValueError("Cannot compute square root") - - return r - - @classmethod - def random(cls, **kwargs): - """Generate a random natural integer of a certain size. - - :Keywords: - exact_bits : positive integer - The length in bits of the resulting random Integer number. - The number is guaranteed to fulfil the relation: - - 2^bits > result >= 2^(bits - 1) - - max_bits : positive integer - The maximum length in bits of the resulting random Integer number. - The number is guaranteed to fulfil the relation: - - 2^bits > result >=0 - - randfunc : callable - A function that returns a random byte string. The length of the - byte string is passed as parameter. Optional. - If not provided (or ``None``), randomness is read from the system RNG. - - :Return: a Integer object - """ - - exact_bits = kwargs.pop("exact_bits", None) - max_bits = kwargs.pop("max_bits", None) - randfunc = kwargs.pop("randfunc", None) - - if randfunc is None: - randfunc = Random.new().read - - if exact_bits is None and max_bits is None: - raise ValueError("Either 'exact_bits' or 'max_bits' must be specified") - - if exact_bits is not None and max_bits is not None: - raise ValueError("'exact_bits' and 'max_bits' are mutually exclusive") - - bits = exact_bits or max_bits - bytes_needed = ((bits - 1) // 8) + 1 - significant_bits_msb = 8 - (bytes_needed * 8 - bits) - msb = bord(randfunc(1)[0]) - if exact_bits is not None: - msb |= 1 << (significant_bits_msb - 1) - msb &= (1 << significant_bits_msb) - 1 - - return cls.from_bytes(bchr(msb) + randfunc(bytes_needed - 1)) - - @classmethod - def random_range(cls, **kwargs): - """Generate a random integer within a given internal. - - :Keywords: - min_inclusive : integer - The lower end of the interval (inclusive). - max_inclusive : integer - The higher end of the interval (inclusive). - max_exclusive : integer - The higher end of the interval (exclusive). - randfunc : callable - A function that returns a random byte string. The length of the - byte string is passed as parameter. Optional. - If not provided (or ``None``), randomness is read from the system RNG. - :Returns: - An Integer randomly taken in the given interval. - """ - - min_inclusive = kwargs.pop("min_inclusive", None) - max_inclusive = kwargs.pop("max_inclusive", None) - max_exclusive = kwargs.pop("max_exclusive", None) - randfunc = kwargs.pop("randfunc", None) - - if kwargs: - raise ValueError("Unknown keywords: " + str(kwargs.keys)) - if None not in (max_inclusive, max_exclusive): - raise ValueError("max_inclusive and max_exclusive cannot be both" - " specified") - if max_exclusive is not None: - max_inclusive = max_exclusive - 1 - if None in (min_inclusive, max_inclusive): - raise ValueError("Missing keyword to identify the interval") - - if randfunc is None: - randfunc = Random.new().read - - norm_maximum = max_inclusive - min_inclusive - bits_needed = cls(norm_maximum).size_in_bits() - - norm_candidate = -1 - while not 0 <= norm_candidate <= norm_maximum: - norm_candidate = cls.random( - max_bits=bits_needed, - randfunc=randfunc - ) - return norm_candidate + min_inclusive - - @staticmethod - @abc.abstractmethod - def _mult_modulo_bytes(term1, term2, modulus): - """Multiply two integers, take the modulo, and encode as big endian. - This specialized method is used for RSA decryption. - - Args: - term1 : integer - The first term of the multiplication, non-negative. - term2 : integer - The second term of the multiplication, non-negative. - modulus: integer - The modulus, a positive odd number. - :Returns: - A byte string, with the result of the modular multiplication - encoded in big endian mode. - It is as long as the modulus would be, with zero padding - on the left if needed. - """ - pass diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.pyi deleted file mode 100644 index ea23532..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerBase.pyi +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Optional, Union, Callable - -RandFunc = Callable[[int],int] - -class IntegerBase: - - def __init__(self, value: Union[IntegerBase, int]): ... - - def __int__(self) -> int: ... - def __str__(self) -> str: ... - def __repr__(self) -> str: ... - def to_bytes(self, block_size: Optional[int]=0, byteorder: str= ...) -> bytes: ... - @staticmethod - def from_bytes(byte_string: bytes, byteorder: Optional[str] = ...) -> IntegerBase: ... - def __eq__(self, term: object) -> bool: ... - def __ne__(self, term: object) -> bool: ... - def __lt__(self, term: Union[IntegerBase, int]) -> bool: ... - def __le__(self, term: Union[IntegerBase, int]) -> bool: ... - def __gt__(self, term: Union[IntegerBase, int]) -> bool: ... - def __ge__(self, term: Union[IntegerBase, int]) -> bool: ... - def __nonzero__(self) -> bool: ... - def is_negative(self) -> bool: ... - def __add__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __sub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __mul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __floordiv__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def __mod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def inplace_pow(self, exponent: int, modulus: Optional[Union[IntegerBase, int]]=None) -> IntegerBase: ... - def __pow__(self, exponent: int, modulus: Optional[int]) -> IntegerBase: ... - def __abs__(self) -> IntegerBase: ... - def sqrt(self, modulus: Optional[int]) -> IntegerBase: ... - def __iadd__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __isub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __imul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __imod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def __and__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __or__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __rshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __irshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __lshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __ilshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def get_bit(self, n: int) -> bool: ... - def is_odd(self) -> bool: ... - def is_even(self) -> bool: ... - def size_in_bits(self) -> int: ... - def size_in_bytes(self) -> int: ... - def is_perfect_square(self) -> bool: ... - def fail_if_divisible_by(self, small_prime: Union[IntegerBase, int]) -> None: ... - def multiply_accumulate(self, a: Union[IntegerBase, int], b: Union[IntegerBase, int]) -> IntegerBase: ... - def set(self, source: Union[IntegerBase, int]) -> IntegerBase: ... - def inplace_inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... - def inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... - def gcd(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def lcm(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - @staticmethod - def jacobi_symbol(a: Union[IntegerBase, int], n: Union[IntegerBase, int]) -> IntegerBase: ... - @staticmethod - def _tonelli_shanks(n: Union[IntegerBase, int], p: Union[IntegerBase, int]) -> IntegerBase : ... - @classmethod - def random(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... - @classmethod - def random_range(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... - @staticmethod - def _mult_modulo_bytes(term1: Union[IntegerBase, int], - term2: Union[IntegerBase, int], - modulus: Union[IntegerBase, int]) -> bytes: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.py deleted file mode 100644 index 7dfc235..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.py +++ /dev/null @@ -1,162 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from ._IntegerNative import IntegerNative - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, backend, - c_size_t, c_ulonglong) - - -from Crypto.Random.random import getrandbits - -c_defs = """ -int monty_pow(uint8_t *out, - const uint8_t *base, - const uint8_t *exp, - const uint8_t *modulus, - size_t len, - uint64_t seed); - -int monty_multiply(uint8_t *out, - const uint8_t *term1, - const uint8_t *term2, - const uint8_t *modulus, - size_t len); -""" - - -_raw_montgomery = load_pycryptodome_raw_lib("Crypto.Math._modexp", c_defs) -implementation = {"library": "custom", "api": backend} - - -class IntegerCustom(IntegerNative): - - @staticmethod - def from_bytes(byte_string, byteorder='big'): - if byteorder == 'big': - pass - elif byteorder == 'little': - byte_string = bytearray(byte_string) - byte_string.reverse() - else: - raise ValueError("Incorrect byteorder") - return IntegerCustom(bytes_to_long(byte_string)) - - def inplace_pow(self, exponent, modulus=None): - exp_value = int(exponent) - if exp_value < 0: - raise ValueError("Exponent must not be negative") - - # No modular reduction - if modulus is None: - self._value = pow(self._value, exp_value) - return self - - # With modular reduction - mod_value = int(modulus) - if mod_value < 0: - raise ValueError("Modulus must be positive") - if mod_value == 0: - raise ZeroDivisionError("Modulus cannot be zero") - - # C extension only works with odd moduli - if (mod_value & 1) == 0: - self._value = pow(self._value, exp_value, mod_value) - return self - - # C extension only works with bases smaller than modulus - if self._value >= mod_value: - self._value %= mod_value - - max_len = len(long_to_bytes(max(self._value, exp_value, mod_value))) - - base_b = long_to_bytes(self._value, max_len) - exp_b = long_to_bytes(exp_value, max_len) - modulus_b = long_to_bytes(mod_value, max_len) - - out = create_string_buffer(max_len) - - error = _raw_montgomery.monty_pow( - out, - base_b, - exp_b, - modulus_b, - c_size_t(max_len), - c_ulonglong(getrandbits(64)) - ) - - if error: - raise ValueError("monty_pow failed with error: %d" % error) - - result = bytes_to_long(get_raw_buffer(out)) - self._value = result - return self - - @staticmethod - def _mult_modulo_bytes(term1, term2, modulus): - - # With modular reduction - mod_value = int(modulus) - if mod_value < 0: - raise ValueError("Modulus must be positive") - if mod_value == 0: - raise ZeroDivisionError("Modulus cannot be zero") - - # C extension only works with odd moduli - if (mod_value & 1) == 0: - raise ValueError("Odd modulus is required") - - # C extension only works with non-negative terms smaller than modulus - if term1 >= mod_value or term1 < 0: - term1 %= mod_value - if term2 >= mod_value or term2 < 0: - term2 %= mod_value - - modulus_b = long_to_bytes(mod_value) - numbers_len = len(modulus_b) - term1_b = long_to_bytes(term1, numbers_len) - term2_b = long_to_bytes(term2, numbers_len) - out = create_string_buffer(numbers_len) - - error = _raw_montgomery.monty_multiply( - out, - term1_b, - term2_b, - modulus_b, - c_size_t(numbers_len) - ) - if error: - raise ValueError("monty_multiply failed with error: %d" % error) - - return get_raw_buffer(out) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.pyi deleted file mode 100644 index 2dd75c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerCustom.pyi +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Any - -from ._IntegerNative import IntegerNative - -_raw_montgomery = Any - -class IntegerCustom(IntegerNative): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.py deleted file mode 100644 index 46118ae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.py +++ /dev/null @@ -1,799 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import sys -import struct - -from Crypto.Util.py3compat import is_native_int - -from Crypto.Util._raw_api import (backend, load_lib, - c_ulong, c_size_t, c_uint8_ptr) - -from ._IntegerBase import IntegerBase - -gmp_defs = """typedef unsigned long UNIX_ULONG; - typedef struct { int a; int b; void *c; } MPZ; - typedef MPZ mpz_t[1]; - typedef UNIX_ULONG mp_bitcnt_t; - - void __gmpz_init (mpz_t x); - void __gmpz_init_set (mpz_t rop, const mpz_t op); - void __gmpz_init_set_ui (mpz_t rop, UNIX_ULONG op); - - UNIX_ULONG __gmpz_get_ui (const mpz_t op); - void __gmpz_set (mpz_t rop, const mpz_t op); - void __gmpz_set_ui (mpz_t rop, UNIX_ULONG op); - void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_add_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_addmul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_submul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_import (mpz_t rop, size_t count, int order, size_t size, - int endian, size_t nails, const void *op); - void * __gmpz_export (void *rop, size_t *countp, int order, - size_t size, - int endian, size_t nails, const mpz_t op); - size_t __gmpz_sizeinbase (const mpz_t op, int base); - void __gmpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_mul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - int __gmpz_cmp (const mpz_t op1, const mpz_t op2); - void __gmpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const - mpz_t mod); - void __gmpz_powm_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp, - const mpz_t mod); - void __gmpz_pow_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp); - void __gmpz_sqrt(mpz_t rop, const mpz_t op); - void __gmpz_mod (mpz_t r, const mpz_t n, const mpz_t d); - void __gmpz_neg (mpz_t rop, const mpz_t op); - void __gmpz_abs (mpz_t rop, const mpz_t op); - void __gmpz_and (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_ior (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_clear (mpz_t x); - void __gmpz_tdiv_q_2exp (mpz_t q, const mpz_t n, mp_bitcnt_t b); - void __gmpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d); - void __gmpz_mul_2exp (mpz_t rop, const mpz_t op1, mp_bitcnt_t op2); - int __gmpz_tstbit (const mpz_t op, mp_bitcnt_t bit_index); - int __gmpz_perfect_square_p (const mpz_t op); - int __gmpz_jacobi (const mpz_t a, const mpz_t b); - void __gmpz_gcd (mpz_t rop, const mpz_t op1, const mpz_t op2); - UNIX_ULONG __gmpz_gcd_ui (mpz_t rop, const mpz_t op1, - UNIX_ULONG op2); - void __gmpz_lcm (mpz_t rop, const mpz_t op1, const mpz_t op2); - int __gmpz_invert (mpz_t rop, const mpz_t op1, const mpz_t op2); - int __gmpz_divisible_p (const mpz_t n, const mpz_t d); - int __gmpz_divisible_ui_p (const mpz_t n, UNIX_ULONG d); - - size_t __gmpz_size (const mpz_t op); - UNIX_ULONG __gmpz_getlimbn (const mpz_t op, size_t n); - """ - -if sys.platform == "win32": - raise ImportError("Not using GMP on Windows") - -lib = load_lib("gmp", gmp_defs) -implementation = {"library": "gmp", "api": backend} - -if hasattr(lib, "__mpir_version"): - raise ImportError("MPIR library detected") - - -# Lazy creation of GMP methods -class _GMP(object): - - def __getattr__(self, name): - if name.startswith("mpz_"): - func_name = "__gmpz_" + name[4:] - elif name.startswith("gmp_"): - func_name = "__gmp_" + name[4:] - else: - raise AttributeError("Attribute %s is invalid" % name) - func = getattr(lib, func_name) - setattr(self, name, func) - return func - - -_gmp = _GMP() - - -# In order to create a function that returns a pointer to -# a new MPZ structure, we need to break the abstraction -# and know exactly what ffi backend we have -if implementation["api"] == "ctypes": - from ctypes import Structure, c_int, c_void_p, byref - - class _MPZ(Structure): - _fields_ = [('_mp_alloc', c_int), - ('_mp_size', c_int), - ('_mp_d', c_void_p)] - - def new_mpz(): - return byref(_MPZ()) - - _gmp.mpz_getlimbn.restype = c_ulong - -else: - # We are using CFFI - from Crypto.Util._raw_api import ffi - - def new_mpz(): - return ffi.new("MPZ*") - - -# Size of a native word -_sys_bits = 8 * struct.calcsize("P") - - -class IntegerGMP(IntegerBase): - """A fast, arbitrary precision integer""" - - _zero_mpz_p = new_mpz() - _gmp.mpz_init_set_ui(_zero_mpz_p, c_ulong(0)) - - def __init__(self, value): - """Initialize the integer to the given value.""" - - self._mpz_p = new_mpz() - self._initialized = False - - if isinstance(value, float): - raise ValueError("A floating point type is not a natural number") - - if is_native_int(value): - _gmp.mpz_init(self._mpz_p) - self._initialized = True - if value == 0: - return - - tmp = new_mpz() - _gmp.mpz_init(tmp) - - try: - positive = value >= 0 - reduce = abs(value) - slots = (reduce.bit_length() - 1) // 32 + 1 - - while slots > 0: - slots = slots - 1 - _gmp.mpz_set_ui(tmp, - c_ulong(0xFFFFFFFF & (reduce >> (slots * 32)))) - _gmp.mpz_mul_2exp(tmp, tmp, c_ulong(slots * 32)) - _gmp.mpz_add(self._mpz_p, self._mpz_p, tmp) - finally: - _gmp.mpz_clear(tmp) - - if not positive: - _gmp.mpz_neg(self._mpz_p, self._mpz_p) - - elif isinstance(value, IntegerGMP): - _gmp.mpz_init_set(self._mpz_p, value._mpz_p) - self._initialized = True - else: - raise NotImplementedError - - # Conversions - def __int__(self): - tmp = new_mpz() - _gmp.mpz_init_set(tmp, self._mpz_p) - - try: - value = 0 - slot = 0 - while _gmp.mpz_cmp(tmp, self._zero_mpz_p) != 0: - lsb = _gmp.mpz_get_ui(tmp) & 0xFFFFFFFF - value |= lsb << (slot * 32) - _gmp.mpz_tdiv_q_2exp(tmp, tmp, c_ulong(32)) - slot = slot + 1 - finally: - _gmp.mpz_clear(tmp) - - if self < 0: - value = -value - return int(value) - - def __str__(self): - return str(int(self)) - - def __repr__(self): - return "Integer(%s)" % str(self) - - # Only Python 2.x - def __hex__(self): - return hex(int(self)) - - # Only Python 3.x - def __index__(self): - return int(self) - - def to_bytes(self, block_size=0, byteorder='big'): - """Convert the number into a byte string. - - This method encodes the number in network order and prepends - as many zero bytes as required. It only works for non-negative - values. - - :Parameters: - block_size : integer - The exact size the output byte string must have. - If zero, the string has the minimal length. - byteorder : string - 'big' for big-endian integers (default), 'little' for litte-endian. - :Returns: - A byte string. - :Raise ValueError: - If the value is negative or if ``block_size`` is - provided and the length of the byte string would exceed it. - """ - - if self < 0: - raise ValueError("Conversion only valid for non-negative numbers") - - num_limbs = _gmp.mpz_size(self._mpz_p) - if _sys_bits == 32: - spchar = "L" - num_limbs = max(1, num_limbs, (block_size + 3) // 4) - elif _sys_bits == 64: - spchar = "Q" - num_limbs = max(1, num_limbs, (block_size + 7) // 8) - else: - raise ValueError("Unknown limb size") - - # mpz_getlimbn returns 0 if i is larger than the number of actual limbs - limbs = [_gmp.mpz_getlimbn(self._mpz_p, num_limbs - i - 1) for i in range(num_limbs)] - - result = struct.pack(">" + spchar * num_limbs, *limbs) - cutoff_len = len(result) - block_size - if block_size == 0: - result = result.lstrip(b'\x00') - elif cutoff_len > 0: - if result[:cutoff_len] != b'\x00' * (cutoff_len): - raise ValueError("Number is too big to convert to " - "byte string of prescribed length") - result = result[cutoff_len:] - elif cutoff_len < 0: - result = b'\x00' * (-cutoff_len) + result - - if byteorder == 'little': - result = result[::-1] - elif byteorder == 'big': - pass - else: - raise ValueError("Incorrect byteorder") - - if len(result) == 0: - result = b'\x00' - - return result - - @staticmethod - def from_bytes(byte_string, byteorder='big'): - """Convert a byte string into a number. - - :Parameters: - byte_string : byte string - The input number, encoded in network order. - It can only be non-negative. - byteorder : string - 'big' for big-endian integers (default), 'little' for litte-endian. - - :Return: - The ``Integer`` object carrying the same value as the input. - """ - result = IntegerGMP(0) - if byteorder == 'big': - pass - elif byteorder == 'little': - byte_string = bytearray(byte_string) - byte_string.reverse() - else: - raise ValueError("Incorrect byteorder") - _gmp.mpz_import( - result._mpz_p, - c_size_t(len(byte_string)), # Amount of words to read - 1, # Big endian - c_size_t(1), # Each word is 1 byte long - 0, # Endianess within a word - not relevant - c_size_t(0), # No nails - c_uint8_ptr(byte_string)) - return result - - # Relations - def _apply_and_return(self, func, term): - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - return func(self._mpz_p, term._mpz_p) - - def __eq__(self, term): - if not (isinstance(term, IntegerGMP) or is_native_int(term)): - return False - return self._apply_and_return(_gmp.mpz_cmp, term) == 0 - - def __ne__(self, term): - if not (isinstance(term, IntegerGMP) or is_native_int(term)): - return True - return self._apply_and_return(_gmp.mpz_cmp, term) != 0 - - def __lt__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) < 0 - - def __le__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) <= 0 - - def __gt__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) > 0 - - def __ge__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) >= 0 - - def __nonzero__(self): - return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) != 0 - __bool__ = __nonzero__ - - def is_negative(self): - return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) < 0 - - # Arithmetic operations - def __add__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_add(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __sub__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_sub(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __mul__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_mul(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __floordiv__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - if _gmp.mpz_cmp(divisor._mpz_p, - self._zero_mpz_p) == 0: - raise ZeroDivisionError("Division by zero") - result = IntegerGMP(0) - _gmp.mpz_fdiv_q(result._mpz_p, - self._mpz_p, - divisor._mpz_p) - return result - - def __mod__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - comp = _gmp.mpz_cmp(divisor._mpz_p, - self._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Division by zero") - if comp < 0: - raise ValueError("Modulus must be positive") - result = IntegerGMP(0) - _gmp.mpz_mod(result._mpz_p, - self._mpz_p, - divisor._mpz_p) - return result - - def inplace_pow(self, exponent, modulus=None): - - if modulus is None: - if exponent < 0: - raise ValueError("Exponent must not be negative") - - # Normal exponentiation - if exponent > 256: - raise ValueError("Exponent is too big") - _gmp.mpz_pow_ui(self._mpz_p, - self._mpz_p, # Base - c_ulong(int(exponent)) - ) - else: - # Modular exponentiation - if not isinstance(modulus, IntegerGMP): - modulus = IntegerGMP(modulus) - if not modulus: - raise ZeroDivisionError("Division by zero") - if modulus.is_negative(): - raise ValueError("Modulus must be positive") - if is_native_int(exponent): - if exponent < 0: - raise ValueError("Exponent must not be negative") - if exponent < 65536: - _gmp.mpz_powm_ui(self._mpz_p, - self._mpz_p, - c_ulong(exponent), - modulus._mpz_p) - return self - exponent = IntegerGMP(exponent) - elif exponent.is_negative(): - raise ValueError("Exponent must not be negative") - _gmp.mpz_powm(self._mpz_p, - self._mpz_p, - exponent._mpz_p, - modulus._mpz_p) - return self - - def __pow__(self, exponent, modulus=None): - result = IntegerGMP(self) - return result.inplace_pow(exponent, modulus) - - def __abs__(self): - result = IntegerGMP(0) - _gmp.mpz_abs(result._mpz_p, self._mpz_p) - return result - - def sqrt(self, modulus=None): - """Return the largest Integer that does not - exceed the square root""" - - if modulus is None: - if self < 0: - raise ValueError("Square root of negative value") - result = IntegerGMP(0) - _gmp.mpz_sqrt(result._mpz_p, - self._mpz_p) - else: - if modulus <= 0: - raise ValueError("Modulus must be positive") - modulus = int(modulus) - result = IntegerGMP(self._tonelli_shanks(int(self) % modulus, modulus)) - - return result - - def __iadd__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_add_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_sub_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - return self - term = IntegerGMP(term) - _gmp.mpz_add(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __isub__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_sub_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_add_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - return self - term = IntegerGMP(term) - _gmp.mpz_sub(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __imul__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_mul_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_mul_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - _gmp.mpz_neg(self._mpz_p, self._mpz_p) - return self - term = IntegerGMP(term) - _gmp.mpz_mul(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __imod__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - comp = _gmp.mpz_cmp(divisor._mpz_p, - divisor._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Division by zero") - if comp < 0: - raise ValueError("Modulus must be positive") - _gmp.mpz_mod(self._mpz_p, - self._mpz_p, - divisor._mpz_p) - return self - - # Boolean/bit operations - def __and__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_and(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __or__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_ior(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __rshift__(self, pos): - result = IntegerGMP(0) - if pos < 0: - raise ValueError("negative shift count") - if pos > 65536: - if self < 0: - return -1 - else: - return 0 - _gmp.mpz_tdiv_q_2exp(result._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return result - - def __irshift__(self, pos): - if pos < 0: - raise ValueError("negative shift count") - if pos > 65536: - if self < 0: - return -1 - else: - return 0 - _gmp.mpz_tdiv_q_2exp(self._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return self - - def __lshift__(self, pos): - result = IntegerGMP(0) - if not 0 <= pos < 65536: - raise ValueError("Incorrect shift count") - _gmp.mpz_mul_2exp(result._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return result - - def __ilshift__(self, pos): - if not 0 <= pos < 65536: - raise ValueError("Incorrect shift count") - _gmp.mpz_mul_2exp(self._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return self - - def get_bit(self, n): - """Return True if the n-th bit is set to 1. - Bit 0 is the least significant.""" - - if self < 0: - raise ValueError("no bit representation for negative values") - if n < 0: - raise ValueError("negative bit count") - if n > 65536: - return 0 - return bool(_gmp.mpz_tstbit(self._mpz_p, - c_ulong(int(n)))) - - # Extra - def is_odd(self): - return _gmp.mpz_tstbit(self._mpz_p, 0) == 1 - - def is_even(self): - return _gmp.mpz_tstbit(self._mpz_p, 0) == 0 - - def size_in_bits(self): - """Return the minimum number of bits that can encode the number.""" - - if self < 0: - raise ValueError("Conversion only valid for non-negative numbers") - return _gmp.mpz_sizeinbase(self._mpz_p, 2) - - def size_in_bytes(self): - """Return the minimum number of bytes that can encode the number.""" - return (self.size_in_bits() - 1) // 8 + 1 - - def is_perfect_square(self): - return _gmp.mpz_perfect_square_p(self._mpz_p) != 0 - - def fail_if_divisible_by(self, small_prime): - """Raise an exception if the small prime is a divisor.""" - - if is_native_int(small_prime): - if 0 < small_prime < 65536: - if _gmp.mpz_divisible_ui_p(self._mpz_p, - c_ulong(small_prime)): - raise ValueError("The value is composite") - return - small_prime = IntegerGMP(small_prime) - if _gmp.mpz_divisible_p(self._mpz_p, - small_prime._mpz_p): - raise ValueError("The value is composite") - - def multiply_accumulate(self, a, b): - """Increment the number by the product of a and b.""" - - if not isinstance(a, IntegerGMP): - a = IntegerGMP(a) - if is_native_int(b): - if 0 < b < 65536: - _gmp.mpz_addmul_ui(self._mpz_p, - a._mpz_p, - c_ulong(b)) - return self - if -65535 < b < 0: - _gmp.mpz_submul_ui(self._mpz_p, - a._mpz_p, - c_ulong(-b)) - return self - b = IntegerGMP(b) - _gmp.mpz_addmul(self._mpz_p, - a._mpz_p, - b._mpz_p) - return self - - def set(self, source): - """Set the Integer to have the given value""" - - if not isinstance(source, IntegerGMP): - source = IntegerGMP(source) - _gmp.mpz_set(self._mpz_p, - source._mpz_p) - return self - - def inplace_inverse(self, modulus): - """Compute the inverse of this number in the ring of - modulo integers. - - Raise an exception if no inverse exists. - """ - - if not isinstance(modulus, IntegerGMP): - modulus = IntegerGMP(modulus) - - comp = _gmp.mpz_cmp(modulus._mpz_p, - self._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if comp < 0: - raise ValueError("Modulus must be positive") - - result = _gmp.mpz_invert(self._mpz_p, - self._mpz_p, - modulus._mpz_p) - if not result: - raise ValueError("No inverse value can be computed") - return self - - def inverse(self, modulus): - result = IntegerGMP(self) - result.inplace_inverse(modulus) - return result - - def gcd(self, term): - """Compute the greatest common denominator between this - number and another term.""" - - result = IntegerGMP(0) - if is_native_int(term): - if 0 < term < 65535: - _gmp.mpz_gcd_ui(result._mpz_p, - self._mpz_p, - c_ulong(term)) - return result - term = IntegerGMP(term) - _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p) - return result - - def lcm(self, term): - """Compute the least common multiplier between this - number and another term.""" - - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_lcm(result._mpz_p, self._mpz_p, term._mpz_p) - return result - - @staticmethod - def jacobi_symbol(a, n): - """Compute the Jacobi symbol""" - - if not isinstance(a, IntegerGMP): - a = IntegerGMP(a) - if not isinstance(n, IntegerGMP): - n = IntegerGMP(n) - if n <= 0 or n.is_even(): - raise ValueError("n must be positive odd for the Jacobi symbol") - return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p) - - @staticmethod - def _mult_modulo_bytes(term1, term2, modulus): - if not isinstance(term1, IntegerGMP): - term1 = IntegerGMP(term1) - if not isinstance(term2, IntegerGMP): - term2 = IntegerGMP(term2) - if not isinstance(modulus, IntegerGMP): - modulus = IntegerGMP(modulus) - - if modulus < 0: - raise ValueError("Modulus must be positive") - if modulus == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if (modulus & 1) == 0: - raise ValueError("Odd modulus is required") - - product = (term1 * term2) % modulus - return product.to_bytes(modulus.size_in_bytes()) - - # Clean-up - def __del__(self): - - try: - if self._mpz_p is not None: - if self._initialized: - _gmp.mpz_clear(self._mpz_p) - - self._mpz_p = None - except AttributeError: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.pyi deleted file mode 100644 index 2181b47..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerGMP.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from ._IntegerBase import IntegerBase -class IntegerGMP(IntegerBase): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.py deleted file mode 100644 index e9937d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.py +++ /dev/null @@ -1,382 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from ._IntegerBase import IntegerBase - -from Crypto.Util.number import long_to_bytes, bytes_to_long, inverse, GCD - - -class IntegerNative(IntegerBase): - """A class to model a natural integer (including zero)""" - - def __init__(self, value): - if isinstance(value, float): - raise ValueError("A floating point type is not a natural number") - try: - self._value = value._value - except AttributeError: - self._value = value - - # Conversions - def __int__(self): - return self._value - - def __str__(self): - return str(int(self)) - - def __repr__(self): - return "Integer(%s)" % str(self) - - # Only Python 2.x - def __hex__(self): - return hex(self._value) - - # Only Python 3.x - def __index__(self): - return int(self._value) - - def to_bytes(self, block_size=0, byteorder='big'): - if self._value < 0: - raise ValueError("Conversion only valid for non-negative numbers") - result = long_to_bytes(self._value, block_size) - if len(result) > block_size > 0: - raise ValueError("Value too large to encode") - if byteorder == 'big': - pass - elif byteorder == 'little': - result = bytearray(result) - result.reverse() - result = bytes(result) - else: - raise ValueError("Incorrect byteorder") - return result - - @classmethod - def from_bytes(cls, byte_string, byteorder='big'): - if byteorder == 'big': - pass - elif byteorder == 'little': - byte_string = bytearray(byte_string) - byte_string.reverse() - else: - raise ValueError("Incorrect byteorder") - return cls(bytes_to_long(byte_string)) - - # Relations - def __eq__(self, term): - if term is None: - return False - return self._value == int(term) - - def __ne__(self, term): - return not self.__eq__(term) - - def __lt__(self, term): - return self._value < int(term) - - def __le__(self, term): - return self.__lt__(term) or self.__eq__(term) - - def __gt__(self, term): - return not self.__le__(term) - - def __ge__(self, term): - return not self.__lt__(term) - - def __nonzero__(self): - return self._value != 0 - __bool__ = __nonzero__ - - def is_negative(self): - return self._value < 0 - - # Arithmetic operations - def __add__(self, term): - try: - return self.__class__(self._value + int(term)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __sub__(self, term): - try: - return self.__class__(self._value - int(term)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __mul__(self, factor): - try: - return self.__class__(self._value * int(factor)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __floordiv__(self, divisor): - return self.__class__(self._value // int(divisor)) - - def __mod__(self, divisor): - divisor_value = int(divisor) - if divisor_value < 0: - raise ValueError("Modulus must be positive") - return self.__class__(self._value % divisor_value) - - def inplace_pow(self, exponent, modulus=None): - exp_value = int(exponent) - if exp_value < 0: - raise ValueError("Exponent must not be negative") - - if modulus is not None: - mod_value = int(modulus) - if mod_value < 0: - raise ValueError("Modulus must be positive") - if mod_value == 0: - raise ZeroDivisionError("Modulus cannot be zero") - else: - mod_value = None - self._value = pow(self._value, exp_value, mod_value) - return self - - def __pow__(self, exponent, modulus=None): - result = self.__class__(self) - return result.inplace_pow(exponent, modulus) - - def __abs__(self): - return abs(self._value) - - def sqrt(self, modulus=None): - - value = self._value - if modulus is None: - if value < 0: - raise ValueError("Square root of negative value") - # http://stackoverflow.com/questions/15390807/integer-square-root-in-python - - x = value - y = (x + 1) // 2 - while y < x: - x = y - y = (x + value // x) // 2 - result = x - else: - if modulus <= 0: - raise ValueError("Modulus must be positive") - result = self._tonelli_shanks(self % modulus, modulus) - - return self.__class__(result) - - def __iadd__(self, term): - self._value += int(term) - return self - - def __isub__(self, term): - self._value -= int(term) - return self - - def __imul__(self, term): - self._value *= int(term) - return self - - def __imod__(self, term): - modulus = int(term) - if modulus == 0: - raise ZeroDivisionError("Division by zero") - if modulus < 0: - raise ValueError("Modulus must be positive") - self._value %= modulus - return self - - # Boolean/bit operations - def __and__(self, term): - return self.__class__(self._value & int(term)) - - def __or__(self, term): - return self.__class__(self._value | int(term)) - - def __rshift__(self, pos): - try: - return self.__class__(self._value >> int(pos)) - except OverflowError: - if self._value >= 0: - return 0 - else: - return -1 - - def __irshift__(self, pos): - try: - self._value >>= int(pos) - except OverflowError: - if self._value >= 0: - return 0 - else: - return -1 - return self - - def __lshift__(self, pos): - try: - return self.__class__(self._value << int(pos)) - except OverflowError: - raise ValueError("Incorrect shift count") - - def __ilshift__(self, pos): - try: - self._value <<= int(pos) - except OverflowError: - raise ValueError("Incorrect shift count") - return self - - def get_bit(self, n): - if self._value < 0: - raise ValueError("no bit representation for negative values") - try: - try: - result = (self._value >> n._value) & 1 - if n._value < 0: - raise ValueError("negative bit count") - except AttributeError: - result = (self._value >> n) & 1 - if n < 0: - raise ValueError("negative bit count") - except OverflowError: - result = 0 - return result - - # Extra - def is_odd(self): - return (self._value & 1) == 1 - - def is_even(self): - return (self._value & 1) == 0 - - def size_in_bits(self): - - if self._value < 0: - raise ValueError("Conversion only valid for non-negative numbers") - - if self._value == 0: - return 1 - - return self._value.bit_length() - - def size_in_bytes(self): - return (self.size_in_bits() - 1) // 8 + 1 - - def is_perfect_square(self): - if self._value < 0: - return False - if self._value in (0, 1): - return True - - x = self._value // 2 - square_x = x ** 2 - - while square_x > self._value: - x = (square_x + self._value) // (2 * x) - square_x = x ** 2 - - return self._value == x ** 2 - - def fail_if_divisible_by(self, small_prime): - if (self._value % int(small_prime)) == 0: - raise ValueError("Value is composite") - - def multiply_accumulate(self, a, b): - self._value += int(a) * int(b) - return self - - def set(self, source): - self._value = int(source) - - def inplace_inverse(self, modulus): - self._value = inverse(self._value, int(modulus)) - return self - - def inverse(self, modulus): - result = self.__class__(self) - result.inplace_inverse(modulus) - return result - - def gcd(self, term): - return self.__class__(GCD(abs(self._value), abs(int(term)))) - - def lcm(self, term): - term = int(term) - if self._value == 0 or term == 0: - return self.__class__(0) - return self.__class__(abs((self._value * term) // self.gcd(term)._value)) - - @staticmethod - def jacobi_symbol(a, n): - a = int(a) - n = int(n) - - if n <= 0: - raise ValueError("n must be a positive integer") - - if (n & 1) == 0: - raise ValueError("n must be odd for the Jacobi symbol") - - # Step 1 - a = a % n - # Step 2 - if a == 1 or n == 1: - return 1 - # Step 3 - if a == 0: - return 0 - # Step 4 - e = 0 - a1 = a - while (a1 & 1) == 0: - a1 >>= 1 - e += 1 - # Step 5 - if (e & 1) == 0: - s = 1 - elif n % 8 in (1, 7): - s = 1 - else: - s = -1 - # Step 6 - if n % 4 == 3 and a1 % 4 == 3: - s = -s - # Step 7 - n1 = n % a1 - # Step 8 - return s * IntegerNative.jacobi_symbol(n1, a1) - - @staticmethod - def _mult_modulo_bytes(term1, term2, modulus): - if modulus < 0: - raise ValueError("Modulus must be positive") - if modulus == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if (modulus & 1) == 0: - raise ValueError("Odd modulus is required") - - number_len = len(long_to_bytes(modulus)) - return long_to_bytes((term1 * term2) % modulus, number_len) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.pyi deleted file mode 100644 index 3f65a39..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_IntegerNative.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from ._IntegerBase import IntegerBase -class IntegerNative(IntegerBase): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_modexp.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_modexp.abi3.so deleted file mode 100755 index ed632c3..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Math/_modexp.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.py deleted file mode 100644 index f70db9d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.py +++ /dev/null @@ -1,192 +0,0 @@ -from Crypto.Util.number import long_to_bytes -from Crypto.PublicKey.ECC import (EccKey, - construct, - _import_curve25519_public_key, - _import_curve448_public_key) - - -def _compute_ecdh(key_priv, key_pub): - pointP = key_pub.pointQ * key_priv.d - if pointP.is_point_at_infinity(): - raise ValueError("Invalid ECDH point") - - if key_priv.curve == "Curve25519": - z = bytearray(pointP.x.to_bytes(32, byteorder='little')) - elif key_priv.curve == "Curve448": - z = bytearray(pointP.x.to_bytes(56, byteorder='little')) - else: - # See Section 5.7.1.2 in NIST SP 800-56Ar3 - z = long_to_bytes(pointP.x, pointP.size_in_bytes()) - return z - - -def import_x25519_public_key(encoded): - """Create a new X25519 public key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC7748. - - Args: - encoded (bytes): - The x25519 public key to import. - It must be 32 bytes. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - x = _import_curve25519_public_key(encoded) - return construct(curve='Curve25519', point_x=x) - - -def import_x25519_private_key(encoded): - """Create a new X25519 private key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC7748. - - Args: - encoded (bytes): - The X25519 private key to import. - It must be 32 bytes. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - return construct(seed=encoded, curve="Curve25519") - - -def import_x448_public_key(encoded): - """Create a new X448 public key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC7748. - - Args: - encoded (bytes): - The x448 public key to import. - It must be 56 bytes. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - x = _import_curve448_public_key(encoded) - return construct(curve='Curve448', point_x=x) - - -def import_x448_private_key(encoded): - """Create a new X448 private key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC7748. - - Args: - encoded (bytes): - The X448 private key to import. - It must be 56 bytes. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - return construct(seed=encoded, curve="Curve448") - - -def key_agreement(**kwargs): - """Perform a Diffie-Hellman key agreement. - - Keywords: - kdf (callable): - A key derivation function that accepts ``bytes`` as input and returns - ``bytes``. - static_priv (EccKey): - The local static private key. Optional. - static_pub (EccKey): - The static public key that belongs to the peer. Optional. - eph_priv (EccKey): - The local ephemeral private key, generated for this session. Optional. - eph_pub (EccKey): - The ephemeral public key, received from the peer for this session. Optional. - - At least two keys must be passed, of which one is a private key and one - a public key. - - Returns (bytes): - The derived secret key material. - """ - - static_priv = kwargs.get('static_priv', None) - static_pub = kwargs.get('static_pub', None) - eph_priv = kwargs.get('eph_priv', None) - eph_pub = kwargs.get('eph_pub', None) - kdf = kwargs.get('kdf', None) - - if kdf is None: - raise ValueError("'kdf' is mandatory") - - count_priv = 0 - count_pub = 0 - curve = None - - def check_curve(curve, key, name, private): - if not isinstance(key, EccKey): - raise TypeError("'%s' must be an ECC key" % name) - if private and not key.has_private(): - raise TypeError("'%s' must be a private ECC key" % name) - if curve is None: - curve = key.curve - elif curve != key.curve: - raise TypeError("'%s' is defined on an incompatible curve" % name) - return curve - - if static_priv is not None: - curve = check_curve(curve, static_priv, 'static_priv', True) - count_priv += 1 - - if static_pub is not None: - curve = check_curve(curve, static_pub, 'static_pub', False) - count_pub += 1 - - if eph_priv is not None: - curve = check_curve(curve, eph_priv, 'eph_priv', True) - count_priv += 1 - - if eph_pub is not None: - curve = check_curve(curve, eph_pub, 'eph_pub', False) - count_pub += 1 - - if (count_priv + count_pub) < 2 or count_priv == 0 or count_pub == 0: - raise ValueError("Too few keys for the ECDH key agreement") - - Zs = b'' - Ze = b'' - - if static_priv and static_pub: - # C(*, 2s) - Zs = _compute_ecdh(static_priv, static_pub) - - if eph_priv and eph_pub: - # C(2e, 0s) or C(2e, 2s) - if bool(static_priv) != bool(static_pub): - raise ValueError("DH mode C(2e, 1s) is not supported") - Ze = _compute_ecdh(eph_priv, eph_pub) - elif eph_priv and static_pub: - # C(1e, 2s) or C(1e, 1s) - Ze = _compute_ecdh(eph_priv, static_pub) - elif eph_pub and static_priv: - # C(1e, 2s) or C(1e, 1s) - Ze = _compute_ecdh(static_priv, eph_pub) - - Z = Ze + Zs - - return kdf(Z) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.pyi deleted file mode 100644 index 634a007..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/DH.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import TypedDict, Callable, TypeVar, Generic -from typing_extensions import Unpack, NotRequired - -from Crypto.PublicKey.ECC import EccKey - -T = TypeVar('T') - -class RequestParams(TypedDict, Generic[T]): - kdf: Callable[[bytes|bytearray|memoryview], T] - static_priv: NotRequired[EccKey] - static_pub: NotRequired[EccKey] - eph_priv: NotRequired[EccKey] - eph_pub: NotRequired[EccKey] - -def import_x25519_public_key(encoded: bytes) -> EccKey: ... -def import_x25519_private_key(encoded: bytes) -> EccKey: ... -def import_x448_public_key(encoded: bytes) -> EccKey: ... -def import_x448_private_key(encoded: bytes) -> EccKey: ... -def key_agreement(**kwargs: Unpack[RequestParams[T]]) -> T: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/HPKE.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/HPKE.py deleted file mode 100644 index df31443..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/HPKE.py +++ /dev/null @@ -1,483 +0,0 @@ -import struct -from enum import IntEnum - -from types import ModuleType -from typing import Optional - -from .KDF import _HKDF_extract, _HKDF_expand -from .DH import key_agreement, import_x25519_public_key, import_x448_public_key -from Crypto.Util.strxor import strxor -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccKey -from Crypto.Hash import SHA256, SHA384, SHA512 -from Crypto.Cipher import AES, ChaCha20_Poly1305 - - -class MODE(IntEnum): - """HPKE modes""" - BASE = 0x00 - PSK = 0x01 - AUTH = 0x02 - AUTH_PSK = 0x03 - - -class AEAD(IntEnum): - """Authenticated Encryption with Associated Data (AEAD) Functions""" - AES128_GCM = 0x0001 - AES256_GCM = 0x0002 - CHACHA20_POLY1305 = 0x0003 - - -class DeserializeError(ValueError): - pass - -class MessageLimitReachedError(ValueError): - pass - -# CURVE to (KEM ID, KDF ID, HASH) -_Curve_Config = { - "NIST P-256": (0x0010, 0x0001, SHA256), - "NIST P-384": (0x0011, 0x0002, SHA384), - "NIST P-521": (0x0012, 0x0003, SHA512), - "Curve25519": (0x0020, 0x0001, SHA256), - "Curve448": (0x0021, 0x0003, SHA512), -} - - -def _labeled_extract(salt: bytes, - label: bytes, - ikm: bytes, - suite_id: bytes, - hashmod: ModuleType): - labeled_ikm = b"HPKE-v1" + suite_id + label + ikm - return _HKDF_extract(salt, labeled_ikm, hashmod) - - -def _labeled_expand(prk: bytes, - label: bytes, - info: bytes, - L: int, - suite_id: bytes, - hashmod: ModuleType): - labeled_info = struct.pack('>H', L) + b"HPKE-v1" + suite_id + \ - label + info - return _HKDF_expand(prk, labeled_info, L, hashmod) - - -def _extract_and_expand(dh: bytes, - kem_context: bytes, - suite_id: bytes, - hashmod: ModuleType): - Nsecret = hashmod.digest_size - - eae_prk = _labeled_extract(b"", - b"eae_prk", - dh, - suite_id, - hashmod) - - shared_secret = _labeled_expand(eae_prk, - b"shared_secret", - kem_context, - Nsecret, - suite_id, - hashmod) - return shared_secret - - -class HPKE_Cipher: - - def __init__(self, - receiver_key: EccKey, - enc: Optional[bytes], - sender_key: Optional[EccKey], - psk_pair: tuple[bytes, bytes], - info: bytes, - aead_id: AEAD, - mode: MODE): - - self.enc: bytes = b'' if enc is None else enc - """The encapsulated session key.""" - - self._verify_psk_inputs(mode, psk_pair) - - self._curve = receiver_key.curve - self._aead_id = aead_id - self._mode = mode - - try: - self._kem_id, \ - self._kdf_id, \ - self._hashmod = _Curve_Config[self._curve] - except KeyError as ke: - raise ValueError("Curve {} is not supported by HPKE".format(self._curve)) from ke - - self._Nk = 16 if self._aead_id == AEAD.AES128_GCM else 32 - self._Nn = 12 - self._Nt = 16 - self._Nh = self._hashmod.digest_size - - self._encrypt = not receiver_key.has_private() - - if self._encrypt: - # SetupBaseS (encryption) - if enc is not None: - raise ValueError("Parameter 'enc' cannot be an input when sealing") - shared_secret, self.enc = self._encap(receiver_key, - self._kem_id, - self._hashmod, - sender_key) - else: - # SetupBaseR (decryption) - if enc is None: - raise ValueError("Parameter 'enc' required when unsealing") - shared_secret = self._decap(enc, - receiver_key, - self._kem_id, - self._hashmod, - sender_key) - - self._sequence = 0 - self._max_sequence = (1 << (8 * self._Nn)) - 1 - - self._key, \ - self._base_nonce, \ - self._export_secret = self._key_schedule(shared_secret, - info, - *psk_pair) - - @staticmethod - def _encap(receiver_key: EccKey, - kem_id: int, - hashmod: ModuleType, - sender_key: Optional[EccKey] = None, - eph_key: Optional[EccKey] = None): - - assert (sender_key is None) or sender_key.has_private() - assert (eph_key is None) or eph_key.has_private() - - if eph_key is None: - eph_key = ECC.generate(curve=receiver_key.curve) - enc = eph_key.public_key().export_key(format='raw') - - pkRm = receiver_key.public_key().export_key(format='raw') - kem_context = enc + pkRm - extra_param = {} - if sender_key: - kem_context += sender_key.public_key().export_key(format='raw') - extra_param = {'static_priv': sender_key} - - suite_id = b"KEM" + struct.pack('>H', kem_id) - - def kdf(dh, - kem_context=kem_context, - suite_id=suite_id, - hashmod=hashmod): - return _extract_and_expand(dh, kem_context, suite_id, hashmod) - - shared_secret = key_agreement(eph_priv=eph_key, - static_pub=receiver_key, - kdf=kdf, - **extra_param) - return shared_secret, enc - - @staticmethod - def _decap(enc: bytes, - receiver_key: EccKey, - kem_id: int, - hashmod: ModuleType, - sender_key: Optional[EccKey] = None): - - assert receiver_key.has_private() - - try: - if receiver_key.curve == 'Curve25519': - pkE = import_x25519_public_key(enc) - elif receiver_key.curve == 'Curve448': - pkE = import_x448_public_key(enc) - else: - pkE = ECC.import_key(enc, curve_name=receiver_key.curve) - except ValueError as ve: - raise DeserializeError("'enc' is not a valid encapsulated HPKE key") from ve - - pkRm = receiver_key.public_key().export_key(format='raw') - kem_context = enc + pkRm - extra_param = {} - if sender_key: - kem_context += sender_key.public_key().export_key(format='raw') - extra_param = {'static_pub': sender_key} - - suite_id = b"KEM" + struct.pack('>H', kem_id) - - def kdf(dh, - kem_context=kem_context, - suite_id=suite_id, - hashmod=hashmod): - return _extract_and_expand(dh, kem_context, suite_id, hashmod) - - shared_secret = key_agreement(eph_pub=pkE, - static_priv=receiver_key, - kdf=kdf, - **extra_param) - return shared_secret - - @staticmethod - def _verify_psk_inputs(mode: MODE, psk_pair: tuple[bytes, bytes]): - psk_id, psk = psk_pair - - if (psk == b'') ^ (psk_id == b''): - raise ValueError("Inconsistent PSK inputs") - - if (psk == b''): - if mode in (MODE.PSK, MODE.AUTH_PSK): - raise ValueError(f"PSK is required with mode {mode.name}") - else: - if len(psk) < 32: - raise ValueError("PSK must be at least 32 byte long") - if mode in (MODE.BASE, MODE.AUTH): - raise ValueError("PSK is not compatible with this mode") - - def _key_schedule(self, - shared_secret: bytes, - info: bytes, - psk_id: bytes, - psk: bytes): - - suite_id = b"HPKE" + struct.pack('>HHH', - self._kem_id, - self._kdf_id, - self._aead_id) - - psk_id_hash = _labeled_extract(b'', - b'psk_id_hash', - psk_id, - suite_id, - self._hashmod) - - info_hash = _labeled_extract(b'', - b'info_hash', - info, - suite_id, - self._hashmod) - - key_schedule_context = self._mode.to_bytes(1, 'big') + psk_id_hash + info_hash - - secret = _labeled_extract(shared_secret, - b'secret', - psk, - suite_id, - self._hashmod) - - key = _labeled_expand(secret, - b'key', - key_schedule_context, - self._Nk, - suite_id, - self._hashmod) - - base_nonce = _labeled_expand(secret, - b'base_nonce', - key_schedule_context, - self._Nn, - suite_id, - self._hashmod) - - exporter_secret = _labeled_expand(secret, - b'exp', - key_schedule_context, - self._Nh, - suite_id, - self._hashmod) - - return key, base_nonce, exporter_secret - - def _new_cipher(self): - nonce = strxor(self._base_nonce, self._sequence.to_bytes(self._Nn, 'big')) - if self._aead_id in (AEAD.AES128_GCM, AEAD.AES256_GCM): - cipher = AES.new(self._key, AES.MODE_GCM, nonce=nonce, mac_len=self._Nt) - elif self._aead_id == AEAD.CHACHA20_POLY1305: - cipher = ChaCha20_Poly1305.new(key=self._key, nonce=nonce) - else: - raise ValueError(f"Unknown AEAD cipher ID {self._aead_id:#x}") - if self._sequence >= self._max_sequence: - raise MessageLimitReachedError() - self._sequence += 1 - return cipher - - def seal(self, plaintext: bytes, auth_data: Optional[bytes] = None): - """Encrypt and authenticate a message. - - This method can be invoked multiple times - to seal an ordered sequence of messages. - - Arguments: - plaintext: bytes - The message to seal. - auth_data: bytes - Optional. Additional Authenticated data (AAD) that is not encrypted - but that will be also covered by the authentication tag. - - Returns: - The ciphertext concatenated with the authentication tag. - """ - - if not self._encrypt: - raise ValueError("This cipher can only be used to seal") - cipher = self._new_cipher() - if auth_data: - cipher.update(auth_data) - ct, tag = cipher.encrypt_and_digest(plaintext) - return ct + tag - - def unseal(self, ciphertext: bytes, auth_data: Optional[bytes] = None): - """Decrypt a message and validate its authenticity. - - This method can be invoked multiple times - to unseal an ordered sequence of messages. - - Arguments: - cipertext: bytes - The message to unseal. - auth_data: bytes - Optional. Additional Authenticated data (AAD) that - was also covered by the authentication tag. - - Returns: - The original plaintext. - - Raises: ValueError - If the ciphertext (in combination with the AAD) is not valid. - - But if it is the first time you call ``unseal()`` this - exception may also mean that any of the parameters or keys - used to establish the session is wrong or that one is missing. - """ - - if self._encrypt: - raise ValueError("This cipher can only be used to unseal") - if len(ciphertext) < self._Nt: - raise ValueError("Ciphertext is too small") - cipher = self._new_cipher() - if auth_data: - cipher.update(auth_data) - - try: - pt = cipher.decrypt_and_verify(ciphertext[:-self._Nt], - ciphertext[-self._Nt:]) - except ValueError: - if self._sequence == 1: - raise ValueError("Incorrect HPKE keys/parameters or invalid message (wrong MAC tag)") - raise ValueError("Invalid message (wrong MAC tag)") - return pt - - -def new(*, receiver_key: EccKey, - aead_id: AEAD, - enc: Optional[bytes] = None, - sender_key: Optional[EccKey] = None, - psk: Optional[tuple[bytes, bytes]] = None, - info: Optional[bytes] = None) -> HPKE_Cipher: - """Create an HPKE context which can be used: - - - by the sender to seal (encrypt) a message or - - by the receiver to unseal (decrypt) it. - - As a minimum, the two parties agree on the receiver's asymmetric key - (of which the sender will only know the public half). - - Additionally, for authentication purposes, they may also agree on: - - * the sender's asymmetric key (of which the receiver will only know the public half) - - * a shared secret (e.g., a symmetric key derived from a password) - - Args: - receiver_key: - The ECC key of the receiver. - It must be on one of the following curves: ``NIST P-256``, - ``NIST P-384``, ``NIST P-521``, ``X25519`` or ``X448``. - - If this is a **public** key, the HPKE context can only be used to - **seal** (**encrypt**). - - If this is a **private** key, the HPKE context can only be used to - **unseal** (**decrypt**). - - aead_id: - The HPKE identifier of the symmetric cipher. - The possible values are: - - * ``HPKE.AEAD.AES128_GCM`` - * ``HPKE.AEAD.AES256_GCM`` - * ``HPKE.AEAD.CHACHA20_POLY1305`` - - enc: - The encapsulated session key (i.e., the KEM shared secret). - - The receiver must always specify this parameter. - - The sender must always omit this parameter. - - sender_key: - The ECC key of the sender. - It must be on the same curve as the ``receiver_key``. - If the ``receiver_key`` is a public key, ``sender_key`` must be a - private key, and vice versa. - - psk: - A Pre-Shared Key (PSK) as a 2-tuple of non-empty - byte strings: the identifier and the actual secret value. - Sender and receiver must use the same PSK (or none). - - The secret value must be at least 32 bytes long, - but it must not be a low-entropy password - (use a KDF like PBKDF2 or scrypt to derive a secret - from a password). - - info: - A non-secret parameter that contributes - to the generation of all session keys. - Sender and receive must use the same **info** parameter (or none). - - Returns: - An object that can be used for - sealing (if ``receiver_key`` is a public key) or - unsealing (if ``receiver_key`` is a private key). - In the latter case, - correctness of all the keys and parameters will only - be assessed with the first call to ``unseal()``. - """ - - if aead_id not in AEAD: - raise ValueError(f"Unknown AEAD cipher ID {aead_id:#x}") - - curve = receiver_key.curve - if curve not in ('NIST P-256', 'NIST P-384', 'NIST P-521', - 'Curve25519', 'Curve448'): - raise ValueError(f"Unsupported curve {curve}") - - if sender_key: - count_private_keys = int(receiver_key.has_private()) + \ - int(sender_key.has_private()) - if count_private_keys != 1: - raise ValueError("Exactly 1 private key required") - if sender_key.curve != curve: - raise ValueError("Sender key uses {} but recipient key {}". - format(sender_key.curve, curve)) - mode = MODE.AUTH if psk is None else MODE.AUTH_PSK - else: - mode = MODE.BASE if psk is None else MODE.PSK - - if psk is None: - psk = b'', b'' - - if info is None: - info = b'' - - return HPKE_Cipher(receiver_key, - enc, - sender_key, - psk, - info, - aead_id, - mode) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.py deleted file mode 100644 index cca0069..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.py +++ /dev/null @@ -1,647 +0,0 @@ -# coding=utf-8 -# -# KDF.py : a collection of Key Derivation Functions -# -# Part of the Python Cryptography Toolkit -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import re -import struct -from functools import reduce - -from Crypto.Util.py3compat import (tobytes, bord, _copy_bytes, iter_range, - tostr, bchr, bstr) - -from Crypto.Hash import SHA1, SHA256, HMAC, CMAC, BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Random import get_random_bytes -from Crypto.Util.number import size as bit_size, long_to_bytes, bytes_to_long - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, c_size_t) - -_raw_salsa20_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._Salsa20", - """ - int Salsa20_8_core(const uint8_t *x, const uint8_t *y, - uint8_t *out); - """) - -_raw_scrypt_lib = load_pycryptodome_raw_lib( - "Crypto.Protocol._scrypt", - """ - typedef int (core_t)(const uint8_t [64], const uint8_t [64], uint8_t [64]); - int scryptROMix(const uint8_t *data_in, uint8_t *data_out, - size_t data_len, unsigned N, core_t *core); - """) - - -def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None): - """Derive one key from a password (or passphrase). - - This function performs key derivation according to an old version of - the PKCS#5 standard (v1.5) or `RFC2898 - `_. - - Args: - password (string): - The secret password to generate the key from. - salt (byte string): - An 8 byte string to use for better protection from dictionary attacks. - This value does not need to be kept secret, but it should be randomly - chosen for each derivation. - dkLen (integer): - The length of the desired key. The default is 16 bytes, suitable for - instance for :mod:`Crypto.Cipher.AES`. - count (integer): - The number of iterations to carry out. The recommendation is 1000 or - more. - hashAlgo (module): - The hash algorithm to use, as a module or an object from the :mod:`Crypto.Hash` package. - The digest length must be no shorter than ``dkLen``. - The default algorithm is :mod:`Crypto.Hash.SHA1`. - - Return: - A byte string of length ``dkLen`` that can be used as key. - """ - - if not hashAlgo: - hashAlgo = SHA1 - password = tobytes(password) - pHash = hashAlgo.new(password+salt) - digest = pHash.digest_size - if dkLen > digest: - raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest) - if len(salt) != 8: - raise ValueError("Salt is not 8 bytes long (%d bytes instead)." % len(salt)) - for i in iter_range(count-1): - pHash = pHash.new(pHash.digest()) - return pHash.digest()[:dkLen] - - -def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None): - """Derive one or more keys from a password (or passphrase). - - This function performs key derivation according to the PKCS#5 standard (v2.0). - - Args: - password (string or byte string): - The secret password to generate the key from. - - Strings will be encoded as ISO 8859-1 (also known as Latin-1), - which does not allow any characters with codepoints > 255. - salt (string or byte string): - A (byte) string to use for better protection from dictionary attacks. - This value does not need to be kept secret, but it should be randomly - chosen for each derivation. It is recommended to use at least 16 bytes. - - Strings will be encoded as ISO 8859-1 (also known as Latin-1), - which does not allow any characters with codepoints > 255. - dkLen (integer): - The cumulative length of the keys to produce. - - Due to a flaw in the PBKDF2 design, you should not request more bytes - than the ``prf`` can output. For instance, ``dkLen`` should not exceed - 20 bytes in combination with ``HMAC-SHA1``. - count (integer): - The number of iterations to carry out. The higher the value, the slower - and the more secure the function becomes. - - You should find the maximum number of iterations that keeps the - key derivation still acceptable on the slowest hardware you must support. - - Although the default value is 1000, **it is recommended to use at least - 1000000 (1 million) iterations**. - prf (callable): - A pseudorandom function. It must be a function that returns a - pseudorandom byte string from two parameters: a secret and a salt. - The slower the algorithm, the more secure the derivation function. - If not specified, **HMAC-SHA1** is used. - hmac_hash_module (module): - A module from ``Crypto.Hash`` implementing a Merkle-Damgard cryptographic - hash, which PBKDF2 must use in combination with HMAC. - This parameter is mutually exclusive with ``prf``. - - Return: - A byte string of length ``dkLen`` that can be used as key material. - If you want multiple keys, just break up this string into segments of the desired length. - """ - - password = tobytes(password) - salt = tobytes(salt) - - if prf and hmac_hash_module: - raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") - - if prf is None and hmac_hash_module is None: - hmac_hash_module = SHA1 - - if prf or not hasattr(hmac_hash_module, "_pbkdf2_hmac_assist"): - # Generic (and slow) implementation - - if prf is None: - prf = lambda p, s: HMAC.new(p, s, hmac_hash_module).digest() - - def link(s): - s[0], s[1] = s[1], prf(password, s[1]) - return s[0] - - key = b'' - i = 1 - while len(key) < dkLen: - s = [prf(password, salt + struct.pack(">I", i))] * 2 - key += reduce(strxor, (link(s) for j in range(count))) - i += 1 - - else: - # Optimized implementation - key = b'' - i = 1 - while len(key) < dkLen: - base = HMAC.new(password, b"", hmac_hash_module) - first_digest = base.copy().update(salt + struct.pack(">I", i)).digest() - key += base._pbkdf2_hmac_assist(first_digest, count) - i += 1 - - return key[:dkLen] - - -class _S2V(object): - """String-to-vector PRF as defined in `RFC5297`_. - - This class implements a pseudorandom function family - based on CMAC that takes as input a vector of strings. - - .. _RFC5297: http://tools.ietf.org/html/rfc5297 - """ - - def __init__(self, key, ciphermod, cipher_params=None): - """Initialize the S2V PRF. - - :Parameters: - key : byte string - A secret that can be used as key for CMACs - based on ciphers from ``ciphermod``. - ciphermod : module - A block cipher module from `Crypto.Cipher`. - cipher_params : dictionary - A set of extra parameters to use to create a cipher instance. - """ - - self._key = _copy_bytes(None, None, key) - self._ciphermod = ciphermod - self._last_string = self._cache = b'\x00' * ciphermod.block_size - - # Max number of update() call we can process - self._n_updates = ciphermod.block_size * 8 - 1 - - if cipher_params is None: - self._cipher_params = {} - else: - self._cipher_params = dict(cipher_params) - - @staticmethod - def new(key, ciphermod): - """Create a new S2V PRF. - - :Parameters: - key : byte string - A secret that can be used as key for CMACs - based on ciphers from ``ciphermod``. - ciphermod : module - A block cipher module from `Crypto.Cipher`. - """ - return _S2V(key, ciphermod) - - def _double(self, bs): - doubled = bytes_to_long(bs) << 1 - if bord(bs[0]) & 0x80: - doubled ^= 0x87 - return long_to_bytes(doubled, len(bs))[-len(bs):] - - def update(self, item): - """Pass the next component of the vector. - - The maximum number of components you can pass is equal to the block - length of the cipher (in bits) minus 1. - - :Parameters: - item : byte string - The next component of the vector. - :Raise TypeError: when the limit on the number of components has been reached. - """ - - if self._n_updates == 0: - raise TypeError("Too many components passed to S2V") - self._n_updates -= 1 - - mac = CMAC.new(self._key, - msg=self._last_string, - ciphermod=self._ciphermod, - cipher_params=self._cipher_params) - self._cache = strxor(self._double(self._cache), mac.digest()) - self._last_string = _copy_bytes(None, None, item) - - def derive(self): - """"Derive a secret from the vector of components. - - :Return: a byte string, as long as the block length of the cipher. - """ - - if len(self._last_string) >= 16: - # xorend - final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) - else: - # zero-pad & xor - padded = (self._last_string + b'\x80' + b'\x00' * 15)[:16] - final = strxor(padded, self._double(self._cache)) - mac = CMAC.new(self._key, - msg=final, - ciphermod=self._ciphermod, - cipher_params=self._cipher_params) - return mac.digest() - - -def _HKDF_extract(salt, ikm, hashmod): - prk = HMAC.new(salt, ikm, digestmod=hashmod).digest() - return prk - - -def _HKDF_expand(prk, info, L, hashmod): - t = [b""] - n = 1 - tlen = 0 - while tlen < L: - hmac = HMAC.new(prk, t[-1] + info + struct.pack('B', n), digestmod=hashmod) - t.append(hmac.digest()) - tlen += hashmod.digest_size - n += 1 - okm = b"".join(t) - return okm[:L] - - -def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None): - """Derive one or more keys from a master secret using - the HMAC-based KDF defined in RFC5869_. - - Args: - master (byte string): - The unguessable value used by the KDF to generate the other keys. - It must be a high-entropy secret, though not necessarily uniform. - It must not be a password. - key_len (integer): - The length in bytes of every derived key. - salt (byte string): - A non-secret, reusable value that strengthens the randomness - extraction step. - Ideally, it is as long as the digest size of the chosen hash. - If empty, a string of zeroes in used. - hashmod (module): - A cryptographic hash algorithm from :mod:`Crypto.Hash`. - :mod:`Crypto.Hash.SHA512` is a good choice. - num_keys (integer): - The number of keys to derive. Every key is :data:`key_len` bytes long. - The maximum cumulative length of all keys is - 255 times the digest size. - context (byte string): - Optional identifier describing what the keys are used for. - - Return: - A byte string or a tuple of byte strings. - - .. _RFC5869: http://tools.ietf.org/html/rfc5869 - """ - - output_len = key_len * num_keys - if output_len > (255 * hashmod.digest_size): - raise ValueError("Too much secret data to derive") - if not salt: - salt = b'\x00' * hashmod.digest_size - if context is None: - context = b"" - - prk = _HKDF_extract(salt, master, hashmod) - okm = _HKDF_expand(prk, context, output_len, hashmod) - - if num_keys == 1: - return okm[:key_len] - kol = [okm[idx:idx + key_len] - for idx in iter_range(0, output_len, key_len)] - return list(kol[:num_keys]) - - -def scrypt(password, salt, key_len, N, r, p, num_keys=1): - """Derive one or more keys from a passphrase. - - Args: - password (string): - The secret pass phrase to generate the keys from. - salt (string): - A string to use for better protection from dictionary attacks. - This value does not need to be kept secret, - but it should be randomly chosen for each derivation. - It is recommended to be at least 16 bytes long. - key_len (integer): - The length in bytes of each derived key. - N (integer): - CPU/Memory cost parameter. It must be a power of 2 and less - than :math:`2^{32}`. - r (integer): - Block size parameter. - p (integer): - Parallelization parameter. - It must be no greater than :math:`(2^{32}-1)/(4r)`. - num_keys (integer): - The number of keys to derive. Every key is :data:`key_len` bytes long. - By default, only 1 key is generated. - The maximum cumulative length of all keys is :math:`(2^{32}-1)*32` - (that is, 128TB). - - A good choice of parameters *(N, r , p)* was suggested - by Colin Percival in his `presentation in 2009`__: - - - *( 2¹⁴, 8, 1 )* for interactive logins (≤100ms) - - *( 2²⁰, 8, 1 )* for file encryption (≤5s) - - Return: - A byte string or a tuple of byte strings. - - .. __: http://www.tarsnap.com/scrypt/scrypt-slides.pdf - """ - - if 2 ** (bit_size(N) - 1) != N: - raise ValueError("N must be a power of 2") - if N >= 2 ** 32: - raise ValueError("N is too big") - if p > ((2 ** 32 - 1) * 32) // (128 * r): - raise ValueError("p or r are too big") - - prf_hmac_sha256 = lambda p, s: HMAC.new(p, s, SHA256).digest() - - stage_1 = PBKDF2(password, salt, p * 128 * r, 1, prf=prf_hmac_sha256) - - scryptROMix = _raw_scrypt_lib.scryptROMix - core = _raw_salsa20_lib.Salsa20_8_core - - # Parallelize into p flows - data_out = [] - for flow in iter_range(p): - idx = flow * 128 * r - buffer_out = create_string_buffer(128 * r) - result = scryptROMix(stage_1[idx: idx + 128 * r], - buffer_out, - c_size_t(128 * r), - N, - core) - if result: - raise ValueError("Error %X while running scrypt" % result) - data_out += [get_raw_buffer(buffer_out)] - - dk = PBKDF2(password, - b"".join(data_out), - key_len * num_keys, 1, - prf=prf_hmac_sha256) - - if num_keys == 1: - return dk - - kol = [dk[idx:idx + key_len] - for idx in iter_range(0, key_len * num_keys, key_len)] - return kol - - -def _bcrypt_encode(data): - s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - - bits = [] - for c in data: - bits_c = bin(bord(c))[2:].zfill(8) - bits.append(bstr(bits_c)) - bits = b"".join(bits) - - bits6 = [bits[idx:idx+6] for idx in range(0, len(bits), 6)] - - result = [] - for g in bits6[:-1]: - idx = int(g, 2) - result.append(s[idx]) - - g = bits6[-1] - idx = int(g, 2) << (6 - len(g)) - result.append(s[idx]) - result = "".join(result) - - return tobytes(result) - - -def _bcrypt_decode(data): - s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - - bits = [] - for c in tostr(data): - idx = s.find(c) - bits6 = bin(idx)[2:].zfill(6) - bits.append(bits6) - bits = "".join(bits) - - modulo4 = len(data) % 4 - if modulo4 == 1: - raise ValueError("Incorrect length") - elif modulo4 == 2: - bits = bits[:-4] - elif modulo4 == 3: - bits = bits[:-2] - - bits8 = [bits[idx:idx+8] for idx in range(0, len(bits), 8)] - - result = [] - for g in bits8: - result.append(bchr(int(g, 2))) - result = b"".join(result) - - return result - - -def _bcrypt_hash(password, cost, salt, constant, invert): - from Crypto.Cipher import _EKSBlowfish - - if len(password) > 72: - raise ValueError("The password is too long. It must be 72 bytes at most.") - - if not (4 <= cost <= 31): - raise ValueError("bcrypt cost factor must be in the range 4..31") - - cipher = _EKSBlowfish.new(password, _EKSBlowfish.MODE_ECB, salt, cost, invert) - ctext = constant - for _ in range(64): - ctext = cipher.encrypt(ctext) - return ctext - - -def bcrypt(password, cost, salt=None): - """Hash a password into a key, using the OpenBSD bcrypt protocol. - - Args: - password (byte string or string): - The secret password or pass phrase. - It must be at most 72 bytes long. - It must not contain the zero byte. - Unicode strings will be encoded as UTF-8. - cost (integer): - The exponential factor that makes it slower to compute the hash. - It must be in the range 4 to 31. - A value of at least 12 is recommended. - salt (byte string): - Optional. Random byte string to thwarts dictionary and rainbow table - attacks. It must be 16 bytes long. - If not passed, a random value is generated. - - Return (byte string): - The bcrypt hash - - Raises: - ValueError: if password is longer than 72 bytes or if it contains the zero byte - - """ - - password = tobytes(password, "utf-8") - - if password.find(bchr(0)[0]) != -1: - raise ValueError("The password contains the zero byte") - - if len(password) < 72: - password += b"\x00" - - if salt is None: - salt = get_random_bytes(16) - if len(salt) != 16: - raise ValueError("bcrypt salt must be 16 bytes long") - - ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt", True) - - cost_enc = b"$" + bstr(str(cost).zfill(2)) - salt_enc = b"$" + _bcrypt_encode(salt) - hash_enc = _bcrypt_encode(ctext[:-1]) # only use 23 bytes, not 24 - return b"$2a" + cost_enc + salt_enc + hash_enc - - -def bcrypt_check(password, bcrypt_hash): - """Verify if the provided password matches the given bcrypt hash. - - Args: - password (byte string or string): - The secret password or pass phrase to test. - It must be at most 72 bytes long. - It must not contain the zero byte. - Unicode strings will be encoded as UTF-8. - bcrypt_hash (byte string, bytearray): - The reference bcrypt hash the password needs to be checked against. - - Raises: - ValueError: if the password does not match - """ - - bcrypt_hash = tobytes(bcrypt_hash) - - if len(bcrypt_hash) != 60: - raise ValueError("Incorrect length of the bcrypt hash: %d bytes instead of 60" % len(bcrypt_hash)) - - if bcrypt_hash[:4] != b'$2a$': - raise ValueError("Unsupported prefix") - - p = re.compile(br'\$2a\$([0-9][0-9])\$([A-Za-z0-9./]{22,22})([A-Za-z0-9./]{31,31})') - r = p.match(bcrypt_hash) - if not r: - raise ValueError("Incorrect bcrypt hash format") - - cost = int(r.group(1)) - if not (4 <= cost <= 31): - raise ValueError("Incorrect cost") - - salt = _bcrypt_decode(r.group(2)) - - bcrypt_hash2 = bcrypt(password, cost, salt) - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash).digest() - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash2).digest() - if mac1 != mac2: - raise ValueError("Incorrect bcrypt hash") - - -def SP800_108_Counter(master, key_len, prf, num_keys=None, label=b'', context=b''): - """Derive one or more keys from a master secret using - a pseudorandom function in Counter Mode, as specified in - `NIST SP 800-108r1 `_. - - Args: - master (byte string): - The secret value used by the KDF to derive the other keys. - It must not be a password. - The length on the secret must be consistent with the input expected by - the :data:`prf` function. - key_len (integer): - The length in bytes of each derived key. - prf (function): - A pseudorandom function that takes two byte strings as parameters: - the secret and an input. It returns another byte string. - num_keys (integer): - The number of keys to derive. Every key is :data:`key_len` bytes long. - By default, only 1 key is derived. - label (byte string): - Optional description of the purpose of the derived keys. - It must not contain zero bytes. - context (byte string): - Optional information pertaining to - the protocol that uses the keys, such as the identity of the - participants, nonces, session IDs, etc. - It must not contain zero bytes. - - Return: - - a byte string (if ``num_keys`` is not specified), or - - a tuple of byte strings (if ``num_key`` is specified). - """ - - if num_keys is None: - num_keys = 1 - - if context.find(b'\x00') != -1: - raise ValueError("Null byte found in context") - - key_len_enc = long_to_bytes(key_len * num_keys * 8, 4) - output_len = key_len * num_keys - - i = 1 - dk = b"" - while len(dk) < output_len: - info = long_to_bytes(i, 4) + label + b'\x00' + context + key_len_enc - dk += prf(master, info) - i += 1 - if i > 0xFFFFFFFF: - raise ValueError("Overflow in SP800 108 counter") - - if num_keys == 1: - return dk[:key_len] - else: - kol = [dk[idx:idx + key_len] - for idx in iter_range(0, output_len, key_len)] - return kol diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.pyi deleted file mode 100644 index 80691e0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/KDF.pyi +++ /dev/null @@ -1,44 +0,0 @@ -from types import ModuleType -from typing import Optional, Callable, Tuple, Union, Dict, Any, overload -from typing_extensions import Literal - -Buffer=bytes|bytearray|memoryview - -RNG = Callable[[int], bytes] -PRF = Callable[[bytes, bytes], bytes] - -def PBKDF1(password: str, salt: bytes, dkLen: int, count: Optional[int]=1000, hashAlgo: Optional[ModuleType]=None) -> bytes: ... -def PBKDF2(password: str, salt: bytes, dkLen: Optional[int]=16, count: Optional[int]=1000, prf: Optional[RNG]=None, hmac_hash_module: Optional[ModuleType]=None) -> bytes: ... - -class _S2V(object): - def __init__(self, key: bytes, ciphermod: ModuleType, cipher_params: Optional[Dict[Any, Any]]=None) -> None: ... - - @staticmethod - def new(key: bytes, ciphermod: ModuleType) -> None: ... - def update(self, item: bytes) -> None: ... - def derive(self) -> bytes: ... - -def _HKDF_extract(salt: Buffer, ikm: Buffer, hashmod: ModuleType) -> bytes: ... -def _HKDF_expand(prk: Buffer, info: Buffer, L: int, hashmod) -> bytes : ... -def HKDF(master: bytes, key_len: int, salt: bytes, hashmod: ModuleType, num_keys: Optional[int]=1, context: Optional[bytes]=None) -> Union[bytes, Tuple[bytes, ...]]: ... - -def scrypt(password: str, salt: str, key_len: int, N: int, r: int, p: int, num_keys: Optional[int]=1) -> Union[bytes, Tuple[bytes, ...]]: ... - -def _bcrypt_decode(data: bytes) -> bytes: ... -def _bcrypt_hash(password:bytes , cost: int, salt: bytes, constant:bytes, invert:bool) -> bytes: ... -def bcrypt(password: Union[bytes, str], cost: int, salt: Optional[bytes]=None) -> bytes: ... -def bcrypt_check(password: Union[bytes, str], bcrypt_hash: Union[bytes, bytearray, str]) -> None: ... - -@overload -def SP800_108_Counter(master: Buffer, - key_len: int, - prf: PRF, - num_keys: Literal[None] = None, - label: Buffer = b'', context: Buffer = b'') -> bytes: ... - -@overload -def SP800_108_Counter(master: Buffer, - key_len: int, - prf: PRF, - num_keys: int, - label: Buffer = b'', context: Buffer = b'') -> Tuple[bytes]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.py deleted file mode 100644 index 8078c0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.py +++ /dev/null @@ -1,297 +0,0 @@ -# -# SecretSharing.py : distribute a secret amongst a group of participants -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import is_native_int -from Crypto.Util import number -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Random import get_random_bytes as rng - - -def _mult_gf2(f1, f2): - """Multiply two polynomials in GF(2)""" - - # Ensure f2 is the smallest - if f2 > f1: - f1, f2 = f2, f1 - z = 0 - while f2: - if f2 & 1: - z ^= f1 - f1 <<= 1 - f2 >>= 1 - return z - - -def _div_gf2(a, b): - """ - Compute division of polynomials over GF(2). - Given a and b, it finds two polynomials q and r such that: - - a = b*q + r with deg(r)= d: - s = 1 << (deg(r) - d) - q ^= s - r ^= _mult_gf2(b, s) - return (q, r) - - -class _Element(object): - """Element of GF(2^128) field""" - - # The irreducible polynomial defining - # this field is 1 + x + x^2 + x^7 + x^128 - irr_poly = 1 + 2 + 4 + 128 + 2 ** 128 - - def __init__(self, encoded_value): - """Initialize the element to a certain value. - - The value passed as parameter is internally encoded as - a 128-bit integer, where each bit represents a polynomial - coefficient. The LSB is the constant coefficient. - """ - - if is_native_int(encoded_value): - self._value = encoded_value - elif len(encoded_value) == 16: - self._value = bytes_to_long(encoded_value) - else: - raise ValueError("The encoded value must be an integer or a 16 byte string") - - def __eq__(self, other): - return self._value == other._value - - def __int__(self): - """Return the field element, encoded as a 128-bit integer.""" - return self._value - - def encode(self): - """Return the field element, encoded as a 16 byte string.""" - return long_to_bytes(self._value, 16) - - def __mul__(self, factor): - - f1 = self._value - f2 = factor._value - - # Make sure that f2 is the smallest, to speed up the loop - if f2 > f1: - f1, f2 = f2, f1 - - if self.irr_poly in (f1, f2): - return _Element(0) - - mask1 = 2 ** 128 - v, z = f1, 0 - while f2: - # if f2 ^ 1: z ^= v - mask2 = int(bin(f2 & 1)[2:] * 128, base=2) - z = (mask2 & (z ^ v)) | ((mask1 - mask2 - 1) & z) - v <<= 1 - # if v & mask1: v ^= self.irr_poly - mask3 = int(bin((v >> 128) & 1)[2:] * 128, base=2) - v = (mask3 & (v ^ self.irr_poly)) | ((mask1 - mask3 - 1) & v) - f2 >>= 1 - return _Element(z) - - def __add__(self, term): - return _Element(self._value ^ term._value) - - def inverse(self): - """Return the inverse of this element in GF(2^128).""" - - # We use the Extended GCD algorithm - # http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor - - if self._value == 0: - raise ValueError("Inversion of zero") - - r0, r1 = self._value, self.irr_poly - s0, s1 = 1, 0 - while r1 > 0: - q = _div_gf2(r0, r1)[0] - r0, r1 = r1, r0 ^ _mult_gf2(q, r1) - s0, s1 = s1, s0 ^ _mult_gf2(q, s1) - return _Element(s0) - - def __pow__(self, exponent): - result = _Element(self._value) - for _ in range(exponent - 1): - result = result * self - return result - - -class Shamir(object): - """Shamir's secret sharing scheme. - - A secret is split into ``n`` shares, and it is sufficient to collect - ``k`` of them to reconstruct the secret. - """ - - @staticmethod - def split(k, n, secret, ssss=False): - """Split a secret into ``n`` shares. - - The secret can be reconstructed later using just ``k`` shares - out of the original ``n``. - Each share must be kept confidential to the person it was - assigned to. - - Each share is associated to an index (starting from 1). - - Args: - k (integer): - The number of shares needed to reconstruct the secret. - n (integer): - The number of shares to create (at least ``k``). - secret (byte string): - A byte string of 16 bytes (e.g. an AES 128 key). - ssss (bool): - If ``True``, the shares can be used with the ``ssss`` utility - (without using the "diffusion layer"). - Default: ``False``. - - Return (tuples): - ``n`` tuples, one per participant. - A tuple contains two items: - - 1. the unique index (an integer) - 2. the share (16 bytes) - """ - - # - # We create a polynomial with random coefficients in GF(2^128): - # - # p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i - # - # c_0 is the secret. - # - - coeffs = [_Element(rng(16)) for i in range(k - 1)] - coeffs.append(_Element(secret)) - - # Each share is y_i = p(x_i) where x_i - # is the index assigned to the share. - - def make_share(user, coeffs, ssss): - idx = _Element(user) - - # Horner's method - share = _Element(0) - for coeff in coeffs: - share = idx * share + coeff - - # The ssss utility actually uses: - # - # p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i + x^k - # - if ssss: - share += _Element(user) ** len(coeffs) - - return share.encode() - - return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)] - - @staticmethod - def combine(shares, ssss=False): - """Recombine a secret, if enough shares are presented. - - Args: - shares (tuples): - The *k* tuples, each containing the index (an integer) and - the share (a byte string, 16 bytes long) that were assigned to - a participant. - - .. note:: - - Pass exactly as many share as they are required, - and no more. - - ssss (bool): - If ``True``, the shares were produced by the ``ssss`` utility - (without using the "diffusion layer"). - Default: ``False``. - - Return: - The original secret, as a byte string (16 bytes long). - """ - - # - # Given k points (x,y), the interpolation polynomial of degree k-1 is: - # - # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x) - # - # where: - # - # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} } - # \frac{x - x_m}{x_j - x_m} - # - # However, in this case we are purely interested in the constant - # coefficient of L(x). - # - - k = len(shares) - - gf_shares = [] - for x in shares: - idx = _Element(x[0]) - value = _Element(x[1]) - if any(y[0] == idx for y in gf_shares): - raise ValueError("Duplicate share") - if ssss: - value += idx ** k - gf_shares.append((idx, value)) - - result = _Element(0) - for j in range(k): - x_j, y_j = gf_shares[j] - - numerator = _Element(1) - denominator = _Element(1) - - for m in range(k): - x_m = gf_shares[m][0] - if m != j: - numerator *= x_m - denominator *= x_j + x_m - result += y_j * numerator * denominator.inverse() - - return result.encode() diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.pyi deleted file mode 100644 index 5952c99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/SecretSharing.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union, List, Tuple, Optional - -def _mult_gf2(f1: int, f2: int) -> int : ... -def _div_gf2(a: int, b: int) -> int : ... - -class _Element(object): - irr_poly: int - def __init__(self, encoded_value: Union[int, bytes]) -> None: ... - def __eq__(self, other) -> bool: ... - def __int__(self) -> int: ... - def encode(self) -> bytes: ... - def __mul__(self, factor: int) -> _Element: ... - def __add__(self, term: _Element) -> _Element: ... - def inverse(self) -> _Element: ... - def __pow__(self, exponent) -> _Element: ... - -class Shamir(object): - @staticmethod - def split(k: int, n: int, secret: bytes, ssss: Optional[bool]) -> List[Tuple[int, bytes]]: ... - @staticmethod - def combine(shares: List[Tuple[int, bytes]], ssss: Optional[bool]) -> bytes: ... - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.py deleted file mode 100644 index 76e22bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['KDF', 'SecretSharing', 'DH'] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.pyi deleted file mode 100644 index 377ed90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/__init__.pyi +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['KDF.pyi', 'SecretSharing.pyi'] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/_scrypt.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/_scrypt.abi3.so deleted file mode 100755 index db66506..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Protocol/_scrypt.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.py deleted file mode 100644 index 4c7f47b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.py +++ /dev/null @@ -1,682 +0,0 @@ -# -*- coding: utf-8 -*- -# -# PublicKey/DSA.py : DSA signature primitive -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] - -import binascii -import struct -import itertools - -from Crypto.Util.py3compat import bchr, bord, tobytes, tostr, iter_range - -from Crypto import Random -from Crypto.IO import PKCS8, PEM -from Crypto.Hash import SHA256 -from Crypto.Util.asn1 import ( - DerObject, DerSequence, - DerInteger, DerObjectId, - DerBitString, - ) - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import (test_probable_prime, COMPOSITE, - PROBABLY_PRIME) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - -# ; The following ASN.1 types are relevant for DSA -# -# SubjectPublicKeyInfo ::= SEQUENCE { -# algorithm AlgorithmIdentifier, -# subjectPublicKey BIT STRING -# } -# -# id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } -# -# ; See RFC3279 -# Dss-Parms ::= SEQUENCE { -# p INTEGER, -# q INTEGER, -# g INTEGER -# } -# -# DSAPublicKey ::= INTEGER -# -# DSSPrivatKey_OpenSSL ::= SEQUENCE -# version INTEGER, -# p INTEGER, -# q INTEGER, -# g INTEGER, -# y INTEGER, -# x INTEGER -# } -# - -class DsaKey(object): - r"""Class defining an actual DSA key. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar p: DSA modulus - :vartype p: integer - - :ivar q: Order of the subgroup - :vartype q: integer - - :ivar g: Generator - :vartype g: integer - - :ivar y: Public key - :vartype y: integer - - :ivar x: Private key - :vartype x: integer - - :undocumented: exportKey, publickey - """ - - _keydata = ['y', 'g', 'p', 'q', 'x'] - - def __init__(self, key_dict): - input_set = set(key_dict.keys()) - public_set = set(('y' , 'g', 'p', 'q')) - if not public_set.issubset(input_set): - raise ValueError("Some DSA components are missing = %s" % - str(public_set - input_set)) - extra_set = input_set - public_set - if extra_set and extra_set != set(('x',)): - raise ValueError("Unknown DSA components = %s" % - str(extra_set - set(('x',)))) - self._key = dict(key_dict) - - def _sign(self, m, k): - if not self.has_private(): - raise TypeError("DSA public key cannot be used for signing") - if not (1 < k < self.q): - raise ValueError("k is not between 2 and q-1") - - x, q, p, g = [self._key[comp] for comp in ['x', 'q', 'p', 'g']] - - blind_factor = Integer.random_range(min_inclusive=1, - max_exclusive=q) - inv_blind_k = (blind_factor * k).inverse(q) - blind_x = x * blind_factor - - r = pow(g, k, p) % q # r = (g**k mod p) mod q - s = (inv_blind_k * (blind_factor * m + blind_x * r)) % q - return map(int, (r, s)) - - def _verify(self, m, sig): - r, s = sig - y, q, p, g = [self._key[comp] for comp in ['y', 'q', 'p', 'g']] - if not (0 < r < q) or not (0 < s < q): - return False - w = Integer(s).inverse(q) - u1 = (w * m) % q - u2 = (w * r) % q - v = (pow(g, u1, p) * pow(y, u2, p) % p) % q - return v == r - - def has_private(self): - """Whether this is a DSA private key""" - - return 'x' in self._key - - def can_encrypt(self): # legacy - return False - - def can_sign(self): # legacy - return True - - def public_key(self): - """A matching DSA public key. - - Returns: - a new :class:`DsaKey` object - """ - - public_components = dict((k, self._key[k]) for k in ('y', 'g', 'p', 'q')) - return DsaKey(public_components) - - def __eq__(self, other): - if bool(self.has_private()) != bool(other.has_private()): - return False - - result = True - for comp in self._keydata: - result = result and (getattr(self._key, comp, None) == - getattr(other._key, comp, None)) - return result - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - # DSA key is not pickable - from pickle import PicklingError - raise PicklingError - - def domain(self): - """The DSA domain parameters. - - Returns - tuple : (p,q,g) - """ - - return [int(self._key[comp]) for comp in ('p', 'q', 'g')] - - def __repr__(self): - attrs = [] - for k in self._keydata: - if k == 'p': - bits = Integer(self.p).size_in_bits() - attrs.append("p(%d)" % (bits,)) - elif hasattr(self, k): - attrs.append(k) - if self.has_private(): - attrs.append("private") - # PY3K: This is meant to be text, do not change to bytes (data) - return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) - - def __getattr__(self, item): - try: - return int(self._key[item]) - except KeyError: - raise AttributeError(item) - - def export_key(self, format='PEM', pkcs8=None, passphrase=None, - protection=None, randfunc=None): - """Export this DSA key. - - Args: - format (string): - The encoding for the output: - - - *'PEM'* (default). ASCII as per `RFC1421`_/ `RFC1423`_. - - *'DER'*. Binary ASN.1 encoding. - - *'OpenSSH'*. ASCII one-liner as per `RFC4253`_. - Only suitable for public keys, not for private keys. - - passphrase (string): - *Private keys only*. The pass phrase to protect the output. - - pkcs8 (boolean): - *Private keys only*. If ``True`` (default), the key is encoded - with `PKCS#8`_. If ``False``, it is encoded in the custom - OpenSSL/OpenSSH container. - - protection (string): - *Only in combination with a pass phrase*. - The encryption scheme to use to protect the output. - - If :data:`pkcs8` takes value ``True``, this is the PKCS#8 - algorithm to use for deriving the secret and encrypting - the private DSA key. - For a complete list of algorithms, see :mod:`Crypto.IO.PKCS8`. - The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*. - - If :data:`pkcs8` is ``False``, the obsolete PEM encryption scheme is - used. It is based on MD5 for key derivation, and Triple DES for - encryption. Parameter :data:`protection` is then ignored. - - The combination ``format='DER'`` and ``pkcs8=False`` is not allowed - if a passphrase is present. - - randfunc (callable): - A function that returns random bytes. - By default it is :func:`Crypto.Random.get_random_bytes`. - - Returns: - byte string : the encoded key - - Raises: - ValueError : when the format is unknown or when you try to encrypt a private - key with *DER* format and OpenSSL/OpenSSH. - - .. warning:: - If you don't provide a pass phrase, the private key will be - exported in the clear! - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - """ - - if passphrase is not None: - passphrase = tobytes(passphrase) - - if randfunc is None: - randfunc = Random.get_random_bytes - - if format == 'OpenSSH': - tup1 = [self._key[x].to_bytes() for x in ('p', 'q', 'g', 'y')] - - def func(x): - if (bord(x[0]) & 0x80): - return bchr(0) + x - else: - return x - - tup2 = [func(x) for x in tup1] - keyparts = [b'ssh-dss'] + tup2 - keystring = b''.join( - [struct.pack(">I", len(kp)) + kp for kp in keyparts] - ) - return b'ssh-dss ' + binascii.b2a_base64(keystring)[:-1] - - # DER format is always used, even in case of PEM, which simply - # encodes it into BASE64. - params = DerSequence([self.p, self.q, self.g]) - if self.has_private(): - if pkcs8 is None: - pkcs8 = True - if pkcs8: - if not protection: - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - private_key = DerInteger(self.x).encode() - binary_key = PKCS8.wrap( - private_key, oid, passphrase, - protection, key_params=params, - randfunc=randfunc - ) - if passphrase: - key_type = 'ENCRYPTED PRIVATE' - else: - key_type = 'PRIVATE' - passphrase = None - else: - if format != 'PEM' and passphrase: - raise ValueError("DSA private key cannot be encrypted") - ints = [0, self.p, self.q, self.g, self.y, self.x] - binary_key = DerSequence(ints).encode() - key_type = "DSA PRIVATE" - else: - if pkcs8: - raise ValueError("PKCS#8 is only meaningful for private keys") - - binary_key = _create_subject_public_key_info(oid, - DerInteger(self.y), params) - key_type = "PUBLIC" - - if format == 'DER': - return binary_key - if format == 'PEM': - pem_str = PEM.encode( - binary_key, key_type + " KEY", - passphrase, randfunc - ) - return tobytes(pem_str) - raise ValueError("Unknown key format '%s'. Cannot export the DSA key." % format) - - # Backward-compatibility - exportKey = export_key - publickey = public_key - - # Methods defined in PyCrypto that we don't support anymore - - def sign(self, M, K): - raise NotImplementedError("Use module Crypto.Signature.DSS instead") - - def verify(self, M, signature): - raise NotImplementedError("Use module Crypto.Signature.DSS instead") - - def encrypt(self, plaintext, K): - raise NotImplementedError - - def decrypt(self, ciphertext): - raise NotImplementedError - - def blind(self, M, B): - raise NotImplementedError - - def unblind(self, M, B): - raise NotImplementedError - - def size(self): - raise NotImplementedError - - -def _generate_domain(L, randfunc): - """Generate a new set of DSA domain parameters""" - - N = { 1024:160, 2048:224, 3072:256 }.get(L) - if N is None: - raise ValueError("Invalid modulus length (%d)" % L) - - outlen = SHA256.digest_size * 8 - n = (L + outlen - 1) // outlen - 1 # ceil(L/outlen) -1 - b_ = L - 1 - (n * outlen) - - # Generate q (A.1.1.2) - q = Integer(4) - upper_bit = 1 << (N - 1) - while test_probable_prime(q, randfunc) != PROBABLY_PRIME: - seed = randfunc(64) - U = Integer.from_bytes(SHA256.new(seed).digest()) & (upper_bit - 1) - q = U | upper_bit | 1 - - assert(q.size_in_bits() == N) - - # Generate p (A.1.1.2) - offset = 1 - upper_bit = 1 << (L - 1) - while True: - V = [ SHA256.new(seed + Integer(offset + j).to_bytes()).digest() - for j in iter_range(n + 1) ] - V = [ Integer.from_bytes(v) for v in V ] - W = sum([V[i] * (1 << (i * outlen)) for i in iter_range(n)], - (V[n] & ((1 << b_) - 1)) * (1 << (n * outlen))) - - X = Integer(W + upper_bit) # 2^{L-1} < X < 2^{L} - assert(X.size_in_bits() == L) - - c = X % (q * 2) - p = X - (c - 1) # 2q divides (p-1) - if p.size_in_bits() == L and \ - test_probable_prime(p, randfunc) == PROBABLY_PRIME: - break - offset += n + 1 - - # Generate g (A.2.3, index=1) - e = (p - 1) // q - for count in itertools.count(1): - U = seed + b"ggen" + bchr(1) + Integer(count).to_bytes() - W = Integer.from_bytes(SHA256.new(U).digest()) - g = pow(W, e, p) - if g != 1: - break - - return (p, q, g, seed) - - -def generate(bits, randfunc=None, domain=None): - """Generate a new DSA key pair. - - The algorithm follows Appendix A.1/A.2 and B.1 of `FIPS 186-4`_, - respectively for domain generation and key pair generation. - - Args: - bits (integer): - Key length, or size (in bits) of the DSA modulus *p*. - It must be 1024, 2048 or 3072. - - randfunc (callable): - Random number generation function; it accepts a single integer N - and return a string of random data N bytes long. - If not specified, :func:`Crypto.Random.get_random_bytes` is used. - - domain (tuple): - The DSA domain parameters *p*, *q* and *g* as a list of 3 - integers. Size of *p* and *q* must comply to `FIPS 186-4`_. - If not specified, the parameters are created anew. - - Returns: - :class:`DsaKey` : a new DSA key object - - Raises: - ValueError : when **bits** is too little, too big, or not a multiple of 64. - - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - if domain: - p, q, g = map(Integer, domain) - - ## Perform consistency check on domain parameters - # P and Q must be prime - fmt_error = test_probable_prime(p) == COMPOSITE - fmt_error |= test_probable_prime(q) == COMPOSITE - # Verify Lagrange's theorem for sub-group - fmt_error |= ((p - 1) % q) != 0 - fmt_error |= g <= 1 or g >= p - fmt_error |= pow(g, q, p) != 1 - if fmt_error: - raise ValueError("Invalid DSA domain parameters") - else: - p, q, g, _ = _generate_domain(bits, randfunc) - - L = p.size_in_bits() - N = q.size_in_bits() - - if L != bits: - raise ValueError("Mismatch between size of modulus (%d)" - " and 'bits' parameter (%d)" % (L, bits)) - - if (L, N) not in [(1024, 160), (2048, 224), - (2048, 256), (3072, 256)]: - raise ValueError("Lengths of p and q (%d, %d) are not compatible" - "to FIPS 186-3" % (L, N)) - - if not 1 < g < p: - raise ValueError("Incorrent DSA generator") - - # B.1.1 - c = Integer.random(exact_bits=N + 64, randfunc=randfunc) - x = c % (q - 1) + 1 # 1 <= x <= q-1 - y = pow(g, x, p) - - key_dict = { 'y':y, 'g':g, 'p':p, 'q':q, 'x':x } - return DsaKey(key_dict) - - -def construct(tup, consistency_check=True): - """Construct a DSA key from a tuple of valid DSA components. - - Args: - tup (tuple): - A tuple of long integers, with 4 or 5 items - in the following order: - - 1. Public key (*y*). - 2. Sub-group generator (*g*). - 3. Modulus, finite field order (*p*). - 4. Sub-group order (*q*). - 5. Private key (*x*). Optional. - - consistency_check (boolean): - If ``True``, the library will verify that the provided components - fulfil the main DSA properties. - - Raises: - ValueError: when the key being imported fails the most basic DSA validity checks. - - Returns: - :class:`DsaKey` : a DSA key object - """ - - key_dict = dict(zip(('y', 'g', 'p', 'q', 'x'), map(Integer, tup))) - key = DsaKey(key_dict) - - fmt_error = False - if consistency_check: - # P and Q must be prime - fmt_error = test_probable_prime(key.p) == COMPOSITE - fmt_error |= test_probable_prime(key.q) == COMPOSITE - # Verify Lagrange's theorem for sub-group - fmt_error |= ((key.p - 1) % key.q) != 0 - fmt_error |= key.g <= 1 or key.g >= key.p - fmt_error |= pow(key.g, key.q, key.p) != 1 - # Public key - fmt_error |= key.y <= 0 or key.y >= key.p - if hasattr(key, 'x'): - fmt_error |= key.x <= 0 or key.x >= key.q - fmt_error |= pow(key.g, key.x, key.p) != key.y - - if fmt_error: - raise ValueError("Invalid DSA key components") - - return key - - -# Dss-Parms ::= SEQUENCE { -# p OCTET STRING, -# q OCTET STRING, -# g OCTET STRING -# } -# DSAPublicKey ::= INTEGER -- public key, y - -def _import_openssl_private(encoded, passphrase, params): - if params: - raise ValueError("DSA private key already comes with parameters") - der = DerSequence().decode(encoded, nr_elements=6, only_ints_expected=True) - if der[0] != 0: - raise ValueError("No version found") - tup = [der[comp] for comp in (4, 3, 1, 2, 5)] - return construct(tup) - - -def _import_subjectPublicKeyInfo(encoded, passphrase, params): - - algoid, encoded_key, emb_params = _expand_subject_public_key_info(encoded) - if algoid != oid: - raise ValueError("No DSA subjectPublicKeyInfo") - if params and emb_params: - raise ValueError("Too many DSA parameters") - - y = DerInteger().decode(encoded_key).value - p, q, g = list(DerSequence().decode(params or emb_params)) - tup = (y, g, p, q) - return construct(tup) - - -def _import_x509_cert(encoded, passphrase, params): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info, None, params) - - -def _import_pkcs8(encoded, passphrase, params): - if params: - raise ValueError("PKCS#8 already includes parameters") - k = PKCS8.unwrap(encoded, passphrase) - if k[0] != oid: - raise ValueError("No PKCS#8 encoded DSA key") - x = DerInteger().decode(k[1]).value - p, q, g = list(DerSequence().decode(k[2])) - tup = (pow(g, x, p), g, p, q, x) - return construct(tup) - - -def _import_key_der(key_data, passphrase, params): - """Import a DSA key (public or private half), encoded in DER form.""" - - decodings = (_import_openssl_private, - _import_subjectPublicKeyInfo, - _import_x509_cert, - _import_pkcs8) - - for decoding in decodings: - try: - return decoding(key_data, passphrase, params) - except ValueError: - pass - - raise ValueError("DSA key format is not supported") - - -def import_key(extern_key, passphrase=None): - """Import a DSA key. - - Args: - extern_key (string or byte string): - The DSA key to import. - - The following formats are supported for a DSA **public** key: - - - X.509 certificate (binary DER or PEM) - - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM) - - OpenSSH (ASCII one-liner, see `RFC4253`_) - - The following formats are supported for a DSA **private** key: - - - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` - DER SEQUENCE (binary or PEM) - - OpenSSL/OpenSSH custom format (binary or PEM) - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (string): - In case of an encrypted private key, this is the pass phrase - from which the decryption key is derived. - - Encryption may be applied either at the `PKCS#8`_ or at the PEM level. - - Returns: - :class:`DsaKey` : a DSA key object - - Raises: - ValueError : when the given key cannot be parsed (possibly because - the pass phrase is wrong). - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt - .. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt - """ - - extern_key = tobytes(extern_key) - if passphrase is not None: - passphrase = tobytes(passphrase) - - if extern_key.startswith(b'-----'): - # This is probably a PEM encoded key - (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) - if enc_flag: - passphrase = None - return _import_key_der(der, passphrase, None) - - if extern_key.startswith(b'ssh-dss '): - # This is probably a public OpenSSH key - keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) - keyparts = [] - while len(keystring) > 4: - length = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + length]) - keystring = keystring[4 + length:] - if keyparts[0] == b"ssh-dss": - tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)] - return construct(tup) - - if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: - # This is probably a DER encoded key - return _import_key_der(extern_key, passphrase, None) - - raise ValueError("DSA key format is not supported") - - -# Backward compatibility -importKey = import_key - -#: `Object ID`_ for a DSA key. -#: -#: id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } -#: -#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.10040.4.1.html -oid = "1.2.840.10040.4.1" diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.pyi deleted file mode 100644 index 354ac1f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/DSA.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Dict, Tuple, Callable, Union, Optional - -__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] - -RNG = Callable[[int], bytes] - -class DsaKey(object): - def __init__(self, key_dict: Dict[str, int]) -> None: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... # legacy - def can_sign(self) -> bool: ... # legacy - def public_key(self) -> DsaKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... - def domain(self) -> Tuple[int, int, int]: ... - def __repr__(self) -> str: ... - def __getattr__(self, item: str) -> int: ... - def export_key(self, format: Optional[str]="PEM", pkcs8: Optional[bool]=None, passphrase: Optional[str]=None, - protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... - # Backward-compatibility - exportKey = export_key - publickey = public_key - -def generate(bits: int, randfunc: Optional[RNG]=None, domain: Optional[Tuple[int, int, int]]=None) -> DsaKey: ... -def construct(tup: Union[Tuple[int, int, int, int], Tuple[int, int, int, int, int]], consistency_check: Optional[bool]=True) -> DsaKey: ... -def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> DsaKey: ... -# Backward compatibility -importKey = import_key - -oid: str diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.py deleted file mode 100644 index 46789f9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.py +++ /dev/null @@ -1,1342 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from __future__ import print_function - -import re -import struct -import binascii - -from Crypto.Util.py3compat import bord, tobytes, tostr, bchr, is_string - -from Crypto.Math.Numbers import Integer -from Crypto.Util.asn1 import (DerObjectId, DerOctetString, DerSequence, - DerBitString) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - -from Crypto.Hash import SHA512, SHAKE256 - -from Crypto.Random import get_random_bytes - -from ._point import EccPoint, EccXPoint, _curves -from ._point import CurveID as _CurveID - - -class UnsupportedEccFeature(ValueError): - pass - - -class EccKey(object): - r"""Class defining an ECC key. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. - :vartype curve: string - - :ivar pointQ: an ECC point representing the public component. - :vartype pointQ: :class:`EccPoint` or :class:`EccXPoint` - - :ivar d: A scalar that represents the private component - in NIST P curves. It is smaller than the - order of the generator point. - :vartype d: integer - - :ivar seed: A seed that represents the private component - in Ed22519 (32 bytes), Curve25519 (32 bytes), - Curve448 (56 bytes), Ed448 (57 bytes). - :vartype seed: bytes - """ - - def __init__(self, **kwargs): - """Create a new ECC key - - Keywords: - curve : string - The name of the curve. - d : integer - Mandatory for a private key one NIST P curves. - It must be in the range ``[1..order-1]``. - seed : bytes - Mandatory for a private key on Ed25519 (32 bytes), - Curve25519 (32 bytes), Curve448 (56 bytes) or Ed448 (57 bytes). - point : EccPoint or EccXPoint - Mandatory for a public key. If provided for a private key, - the implementation will NOT check whether it matches ``d``. - - Only one parameter among ``d``, ``seed`` or ``point`` may be used. - """ - - kwargs_ = dict(kwargs) - curve_name = kwargs_.pop("curve", None) - self._d = kwargs_.pop("d", None) - self._seed = kwargs_.pop("seed", None) - self._point = kwargs_.pop("point", None) - if curve_name is None and self._point: - curve_name = self._point.curve - if kwargs_: - raise TypeError("Unknown parameters: " + str(kwargs_)) - - if curve_name not in _curves: - raise ValueError("Unsupported curve (%s)" % curve_name) - self._curve = _curves[curve_name] - self.curve = self._curve.canonical - - count = int(self._d is not None) + int(self._seed is not None) - - if count == 0: - if self._point is None: - raise ValueError("At lest one between parameters 'point', 'd' or 'seed' must be specified") - return - - if count == 2: - raise ValueError("Parameters d and seed are mutually exclusive") - - # NIST P curves work with d, EdDSA works with seed - - # RFC 8032, 5.1.5 - if self._curve.id == _CurveID.ED25519: - if self._d is not None: - raise ValueError("Parameter d can only be used with NIST P curves") - if len(self._seed) != 32: - raise ValueError("Parameter seed must be 32 bytes long for Ed25519") - seed_hash = SHA512.new(self._seed).digest() # h - self._prefix = seed_hash[32:] - tmp = bytearray(seed_hash[:32]) - tmp[0] &= 0xF8 - tmp[31] = (tmp[31] & 0x7F) | 0x40 - self._d = Integer.from_bytes(tmp, byteorder='little') - # RFC 8032, 5.2.5 - elif self._curve.id == _CurveID.ED448: - if self._d is not None: - raise ValueError("Parameter d can only be used with NIST P curves") - if len(self._seed) != 57: - raise ValueError("Parameter seed must be 57 bytes long for Ed448") - seed_hash = SHAKE256.new(self._seed).read(114) # h - self._prefix = seed_hash[57:] - tmp = bytearray(seed_hash[:57]) - tmp[0] &= 0xFC - tmp[55] |= 0x80 - tmp[56] = 0 - self._d = Integer.from_bytes(tmp, byteorder='little') - # RFC 7748, 5 - elif self._curve.id == _CurveID.CURVE25519: - if self._d is not None: - raise ValueError("Parameter d can only be used with NIST P curves") - if len(self._seed) != 32: - raise ValueError("Parameter seed must be 32 bytes long for Curve25519") - tmp = bytearray(self._seed) - tmp[0] &= 0xF8 - tmp[31] = (tmp[31] & 0x7F) | 0x40 - self._d = Integer.from_bytes(tmp, byteorder='little') - elif self._curve.id == _CurveID.CURVE448: - if self._d is not None: - raise ValueError("Parameter d can only be used with NIST P curves") - if len(self._seed) != 56: - raise ValueError("Parameter seed must be 56 bytes long for Curve448") - tmp = bytearray(self._seed) - tmp[0] &= 0xFC - tmp[55] |= 0x80 - self._d = Integer.from_bytes(tmp, byteorder='little') - - else: - if self._seed is not None: - raise ValueError("Parameter 'seed' cannot be used with NIST P-curves") - self._d = Integer(self._d) - if not 1 <= self._d < self._curve.order: - raise ValueError("Parameter d must be an integer smaller than the curve order") - - def __eq__(self, other): - if not isinstance(other, EccKey): - return False - - if other.has_private() != self.has_private(): - return False - - return other.pointQ == self.pointQ - - def __repr__(self): - if self.has_private(): - if self._curve.is_edwards: - extra = ", seed=%s" % tostr(binascii.hexlify(self._seed)) - else: - extra = ", d=%d" % int(self._d) - else: - extra = "" - if self._curve.id in (_CurveID.CURVE25519, - _CurveID.CURVE448): - x = self.pointQ.x - result = "EccKey(curve='%s', point_x=%d%s)" % (self._curve.canonical, x, extra) - else: - x, y = self.pointQ.xy - result = "EccKey(curve='%s', point_x=%d, point_y=%d%s)" % (self._curve.canonical, x, y, extra) - return result - - def has_private(self): - """``True`` if this key can be used for making signatures or decrypting data.""" - - return self._d is not None - - # ECDSA - def _sign(self, z, k): - assert 0 < k < self._curve.order - - order = self._curve.order - blind = Integer.random_range(min_inclusive=1, - max_exclusive=order) - - blind_d = self._d * blind - inv_blind_k = (blind * k).inverse(order) - - r = (self._curve.G * k).x % order - s = inv_blind_k * (blind * z + blind_d * r) % order - return (r, s) - - # ECDSA - def _verify(self, z, rs): - order = self._curve.order - sinv = rs[1].inverse(order) - point1 = self._curve.G * ((sinv * z) % order) - point2 = self.pointQ * ((sinv * rs[0]) % order) - return (point1 + point2).x == rs[0] - - @property - def d(self): - if not self.has_private(): - raise ValueError("This is not a private ECC key") - return self._d - - @property - def seed(self): - if not self.has_private(): - raise ValueError("This is not a private ECC key") - return self._seed - - @property - def pointQ(self): - if self._point is None: - self._point = self._curve.G * self._d - return self._point - - def public_key(self): - """A matching ECC public key. - - Returns: - a new :class:`EccKey` object - """ - - return EccKey(curve=self._curve.canonical, point=self.pointQ) - - def _export_SEC1(self, compress): - if not self._curve.is_weierstrass: - raise ValueError("SEC1 format is only supported for NIST P curves") - - # See 2.2 in RFC5480 and 2.3.3 in SEC1 - # - # The first byte is: - # - 0x02: compressed, only X-coordinate, Y-coordinate is even - # - 0x03: compressed, only X-coordinate, Y-coordinate is odd - # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate - # - # PAI is in theory encoded as 0x00. - - modulus_bytes = self.pointQ.size_in_bytes() - - if compress: - if self.pointQ.y.is_odd(): - first_byte = b'\x03' - else: - first_byte = b'\x02' - public_key = (first_byte + - self.pointQ.x.to_bytes(modulus_bytes)) - else: - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - return public_key - - def _export_eddsa_public(self): - x, y = self.pointQ.xy - if self._curve.id == _CurveID.ED25519: - result = bytearray(y.to_bytes(32, byteorder='little')) - result[31] = ((x & 1) << 7) | result[31] - elif self._curve.id == _CurveID.ED448: - result = bytearray(y.to_bytes(57, byteorder='little')) - result[56] = (x & 1) << 7 - else: - raise ValueError("Not an EdDSA key to export") - return bytes(result) - - def _export_montgomery_public(self): - if not self._curve.is_montgomery: - raise ValueError("Not a Montgomery key to export") - x = self.pointQ.x - field_size = self.pointQ.size_in_bytes() - result = bytearray(x.to_bytes(field_size, byteorder='little')) - return bytes(result) - - def _export_subjectPublicKeyInfo(self, compress): - if self._curve.is_edwards: - oid = self._curve.oid - public_key = self._export_eddsa_public() - params = None - elif self._curve.is_montgomery: - oid = self._curve.oid - public_key = self._export_montgomery_public() - params = None - else: - oid = "1.2.840.10045.2.1" # unrestricted - public_key = self._export_SEC1(compress) - params = DerObjectId(self._curve.oid) - - return _create_subject_public_key_info(oid, - public_key, - params) - - def _export_rfc5915_private_der(self, include_ec_params=True): - - assert self.has_private() - - # ECPrivateKey ::= SEQUENCE { - # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - # privateKey OCTET STRING, - # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - # publicKey [1] BIT STRING OPTIONAL - # } - - # Public key - uncompressed form - modulus_bytes = self.pointQ.size_in_bytes() - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - - seq = [1, - DerOctetString(self.d.to_bytes(modulus_bytes)), - DerObjectId(self._curve.oid, explicit=0), - DerBitString(public_key, explicit=1)] - - if not include_ec_params: - del seq[2] - - return DerSequence(seq).encode() - - def _export_pkcs8(self, **kwargs): - from Crypto.IO import PKCS8 - - if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs: - raise ValueError("At least the 'protection' parameter must be present") - - if self._seed is not None: - oid = self._curve.oid - private_key = DerOctetString(self._seed).encode() - params = None - else: - oid = "1.2.840.10045.2.1" # unrestricted - private_key = self._export_rfc5915_private_der(include_ec_params=False) - params = DerObjectId(self._curve.oid) - - result = PKCS8.wrap(private_key, - oid, - key_params=params, - **kwargs) - return result - - def _export_public_pem(self, compress): - from Crypto.IO import PEM - - encoded_der = self._export_subjectPublicKeyInfo(compress) - return PEM.encode(encoded_der, "PUBLIC KEY") - - def _export_private_pem(self, passphrase, **kwargs): - from Crypto.IO import PEM - - encoded_der = self._export_rfc5915_private_der() - return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs) - - def _export_private_clear_pkcs8_in_clear_pem(self): - from Crypto.IO import PEM - - encoded_der = self._export_pkcs8() - return PEM.encode(encoded_der, "PRIVATE KEY") - - def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs): - from Crypto.IO import PEM - - assert passphrase - if 'protection' not in kwargs: - raise ValueError("At least the 'protection' parameter should be present") - encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs) - return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY") - - def _export_openssh(self, compress): - if self.has_private(): - raise ValueError("Cannot export OpenSSH private keys") - - desc = self._curve.openssh - - if desc is None: - raise ValueError("Cannot export %s keys as OpenSSH" % self.curve) - elif desc == "ssh-ed25519": - public_key = self._export_eddsa_public() - comps = (tobytes(desc), tobytes(public_key)) - else: - modulus_bytes = self.pointQ.size_in_bytes() - - if compress: - first_byte = 2 + self.pointQ.y.is_odd() - public_key = (bchr(first_byte) + - self.pointQ.x.to_bytes(modulus_bytes)) - else: - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - - middle = desc.split("-")[2] - comps = (tobytes(desc), tobytes(middle), public_key) - - blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) - return desc + " " + tostr(binascii.b2a_base64(blob)) - - def export_key(self, **kwargs): - """Export this ECC key. - - Args: - format (string): - The output format: - - - ``'DER'``. The key will be encoded in ASN.1 DER format (binary). - For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure - defined in `RFC5480`_ will be used. - For a private key, the ASN.1 ``ECPrivateKey`` structure defined - in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope, - see the ``use_pkcs8`` flag below). - - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII). - - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format - (ASCII, public keys only). - - ``'SEC1'``. The public key (i.e., the EC point) will be encoded - into ``bytes`` according to Section 2.3.3 of `SEC1`_ - (which is a subset of the older X9.62 ITU standard). - Only for NIST P-curves. - - ``'raw'``. The public key will be encoded as ``bytes``, - without any metadata. - - * For NIST P-curves: equivalent to ``'SEC1'``. - * For Ed25519 and Ed448: ``bytes`` in the format - defined in `RFC8032`_. - * For Curve25519 and Curve448: ``bytes`` in the format - defined in `RFC7748`_. - - passphrase (bytes or string): - (*Private keys only*) The passphrase to protect the - private key. - - use_pkcs8 (boolean): - (*Private keys only*) - If ``True`` (default and recommended), the `PKCS#8`_ representation - will be used. - It must be ``True`` for Ed25519, Ed448, Curve25519, and Curve448. - - If ``False`` and a passphrase is present, the obsolete PEM - encryption will be used. - - protection (string): - When a private key is exported with password-protection - and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be - present, - For all possible protection schemes, - refer to :ref:`the encryption parameters of PKCS#8`. - It is recommended to use ``'PBKDF2WithHMAC-SHA512AndAES128-CBC'``. - - compress (boolean): - If ``True``, the method returns a more compact representation - of the public key, with the X-coordinate only. - - If ``False`` (default), the method returns the full public key. - - This parameter is ignored for Ed25519/Ed448/Curve25519/Curve448, - as compression is mandatory. - - prot_params (dict): - When a private key is exported with password-protection - and PKCS#8 (both ``DER`` and ``PEM`` formats), this dictionary - contains the parameters to use to derive the encryption key - from the passphrase. - For all possible values, - refer to :ref:`the encryption parameters of PKCS#8`. - The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, - and ``{'iteration_count':131072}`` for scrypt. - - .. warning:: - If you don't provide a passphrase, the private key will be - exported in the clear! - - .. note:: - When exporting a private key with password-protection and `PKCS#8`_ - (both ``DER`` and ``PEM`` formats), any extra parameters - to ``export_key()`` will be passed to :mod:`Crypto.IO.PKCS8`. - - .. _PEM: http://www.ietf.org/rfc/rfc1421.txt - .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt - .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt - .. _RFC5480: https://tools.ietf.org/html/rfc5480 - .. _SEC1: https://www.secg.org/sec1-v2.pdf - .. _RFC7748: https://tools.ietf.org/html/rfc7748 - - Returns: - A multi-line string (for ``'PEM'`` and ``'OpenSSH'``) or - ``bytes`` (for ``'DER'``, ``'SEC1'``, and ``'raw'``) with the encoded key. - """ - - args = kwargs.copy() - ext_format = args.pop("format") - if ext_format not in ("PEM", "DER", "OpenSSH", "SEC1", "raw"): - raise ValueError("Unknown format '%s'" % ext_format) - - compress = args.pop("compress", False) - - if self.has_private(): - passphrase = args.pop("passphrase", None) - if is_string(passphrase): - passphrase = tobytes(passphrase) - if not passphrase: - raise ValueError("Empty passphrase") - - use_pkcs8 = args.pop("use_pkcs8", True) - if use_pkcs8 is False: - if self._curve.is_edwards: - raise ValueError("'pkcs8' must be True for EdDSA curves") - if self._curve.is_montgomery: - raise ValueError("'pkcs8' must be True for Curve25519") - if 'protection' in args: - raise ValueError("'protection' is only supported for PKCS#8") - - if ext_format == "PEM": - if use_pkcs8: - if passphrase: - return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args) - else: - return self._export_private_clear_pkcs8_in_clear_pem() - else: - return self._export_private_pem(passphrase, **args) - elif ext_format == "DER": - # DER - if passphrase and not use_pkcs8: - raise ValueError("Private keys can only be encrpyted with DER using PKCS#8") - if use_pkcs8: - return self._export_pkcs8(passphrase=passphrase, **args) - else: - return self._export_rfc5915_private_der() - else: - raise ValueError("Private keys cannot be exported " - "in the '%s' format" % ext_format) - else: # Public key - if args: - raise ValueError("Unexpected parameters: '%s'" % args) - if ext_format == "PEM": - return self._export_public_pem(compress) - elif ext_format == "DER": - return self._export_subjectPublicKeyInfo(compress) - elif ext_format == "SEC1": - return self._export_SEC1(compress) - elif ext_format == "raw": - if self._curve.is_edwards: - return self._export_eddsa_public() - elif self._curve.is_montgomery: - return self._export_montgomery_public() - else: - return self._export_SEC1(compress) - else: - return self._export_openssh(compress) - - -def generate(**kwargs): - """Generate a new private key on the given curve. - - Args: - - curve (string): - Mandatory. It must be a curve name defined in the `ECC table`_. - - randfunc (callable): - Optional. The RNG to read randomness from. - If ``None``, :func:`Crypto.Random.get_random_bytes` is used. - """ - - curve_name = kwargs.pop("curve") - curve = _curves[curve_name] - randfunc = kwargs.pop("randfunc", get_random_bytes) - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - if _curves[curve_name].id == _CurveID.ED25519: - seed = randfunc(32) - new_key = EccKey(curve=curve_name, seed=seed) - elif _curves[curve_name].id == _CurveID.ED448: - seed = randfunc(57) - new_key = EccKey(curve=curve_name, seed=seed) - elif _curves[curve_name].id == _CurveID.CURVE25519: - seed = randfunc(32) - new_key = EccKey(curve=curve_name, seed=seed) - _curves[curve_name].validate(new_key.pointQ) - elif _curves[curve_name].id == _CurveID.CURVE448: - seed = randfunc(56) - new_key = EccKey(curve=curve_name, seed=seed) - _curves[curve_name].validate(new_key.pointQ) - else: - d = Integer.random_range(min_inclusive=1, - max_exclusive=curve.order, - randfunc=randfunc) - new_key = EccKey(curve=curve_name, d=d) - - return new_key - - -def construct(**kwargs): - """Build a new ECC key (private or public) starting - from some base components. - - In most cases, you will already have an existing key - which you can read in with :func:`import_key` instead - of this function. - - Args: - curve (string): - Mandatory. The name of the elliptic curve, as defined in the `ECC table`_. - - d (integer): - Mandatory for a private key and a NIST P-curve (e.g., P-256). - It must be an integer in the range ``[1..order-1]``. - - seed (bytes): - Mandatory for a private key and curves Ed25519 (32 bytes), - Curve25519 (32 bytes), Curve448 (56 bytes) and Ed448 (57 bytes). - - point_x (integer): - The X coordinate (affine) of the ECC point. - Mandatory for a public key. - - point_y (integer): - The Y coordinate (affine) of the ECC point. - Mandatory for a public key, - except for Curve25519 and Curve448. - - Returns: - :class:`EccKey` : a new ECC key object - """ - - curve_name = kwargs["curve"] - curve = _curves[curve_name] - point_x = kwargs.pop("point_x", None) - point_y = kwargs.pop("point_y", None) - - if "point" in kwargs: - raise TypeError("Unknown keyword: point") - - if curve.id == _CurveID.CURVE25519: - - if point_x is not None: - kwargs["point"] = EccXPoint(point_x, curve_name) - new_key = EccKey(**kwargs) - curve.validate(new_key.pointQ) - - elif curve.id == _CurveID.CURVE448: - - if point_x is not None: - kwargs["point"] = EccXPoint(point_x, curve_name) - new_key = EccKey(**kwargs) - curve.validate(new_key.pointQ) - - else: - - if None not in (point_x, point_y): - kwargs["point"] = EccPoint(point_x, point_y, curve_name) - new_key = EccKey(**kwargs) - - # Validate that the private key matches the public one - # because EccKey will not do that automatically - if new_key.has_private() and 'point' in kwargs: - pub_key = curve.G * new_key.d - if pub_key.xy != (point_x, point_y): - raise ValueError("Private and public ECC keys do not match") - - return new_key - - -def _import_public_der(ec_point, curve_oid=None, curve_name=None): - """Convert an encoded EC point into an EccKey object - - ec_point: byte string with the EC point (SEC1-encoded) - curve_oid: string with the name the curve - curve_name: string with the OID of the curve - - Either curve_id or curve_name must be specified - - """ - - for _curve_name, curve in _curves.items(): - if curve_oid and curve.oid == curve_oid: - break - if curve_name == _curve_name: - break - else: - if curve_oid: - raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) - else: - raise UnsupportedEccFeature("Unsupported ECC curve (%s)" % curve_name) - - # See 2.2 in RFC5480 and 2.3.3 in SEC1 - # The first byte is: - # - 0x02: compressed, only X-coordinate, Y-coordinate is even - # - 0x03: compressed, only X-coordinate, Y-coordinate is odd - # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate - # - # PAI is in theory encoded as 0x00. - - modulus_bytes = curve.p.size_in_bytes() - point_type = bord(ec_point[0]) - - # Uncompressed point - if point_type == 0x04: - if len(ec_point) != (1 + 2 * modulus_bytes): - raise ValueError("Incorrect EC point length") - x = Integer.from_bytes(ec_point[1:modulus_bytes+1]) - y = Integer.from_bytes(ec_point[modulus_bytes+1:]) - # Compressed point - elif point_type in (0x02, 0x03): - if len(ec_point) != (1 + modulus_bytes): - raise ValueError("Incorrect EC point length") - x = Integer.from_bytes(ec_point[1:]) - # Right now, we only support Short Weierstrass curves - y = (x**3 - x*3 + curve.b).sqrt(curve.p) - if point_type == 0x02 and y.is_odd(): - y = curve.p - y - if point_type == 0x03 and y.is_even(): - y = curve.p - y - else: - raise ValueError("Incorrect EC point encoding") - - return construct(curve=_curve_name, point_x=x, point_y=y) - - -def _import_subjectPublicKeyInfo(encoded, *kwargs): - """Convert a subjectPublicKeyInfo into an EccKey object""" - - # See RFC5480 - - # Parse the generic subjectPublicKeyInfo structure - oid, ec_point, params = _expand_subject_public_key_info(encoded) - - nist_p_oids = ( - "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) - "1.3.132.1.12", # id-ecDH - "1.3.132.1.13" # id-ecMQV - ) - eddsa_oids = { - "1.3.101.112": ("Ed25519", _import_ed25519_public_key), # id-Ed25519 - "1.3.101.113": ("Ed448", _import_ed448_public_key) # id-Ed448 - } - xdh_oids = { - "1.3.101.110": ("Curve25519", _import_curve25519_public_key), # id-X25519 - "1.3.101.111": ("Curve448", _import_curve448_public_key), # id-X448 - } - - if oid in nist_p_oids: - # See RFC5480 - - # Parameters are mandatory and encoded as ECParameters - # ECParameters ::= CHOICE { - # namedCurve OBJECT IDENTIFIER - # -- implicitCurve NULL - # -- specifiedCurve SpecifiedECDomain - # } - # implicitCurve and specifiedCurve are not supported (as per RFC) - if not params: - raise ValueError("Missing ECC parameters for ECC OID %s" % oid) - try: - curve_oid = DerObjectId().decode(params).value - except ValueError: - raise ValueError("Error decoding namedCurve") - - # ECPoint ::= OCTET STRING - return _import_public_der(ec_point, curve_oid=curve_oid) - - elif oid in eddsa_oids: - # See RFC8410 - curve_name, import_eddsa_public_key = eddsa_oids[oid] - - # Parameters must be absent - if params: - raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid) - - x, y = import_eddsa_public_key(ec_point) - return construct(point_x=x, point_y=y, curve=curve_name) - - elif oid in xdh_oids: - curve_name, import_xdh_public_key = xdh_oids[oid] - - # Parameters must be absent - if params: - raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid) - - x = import_xdh_public_key(ec_point) - return construct(point_x=x, curve=curve_name) - - else: - raise UnsupportedEccFeature("Unsupported ECC OID: %s" % oid) - - -def _import_rfc5915_der(encoded, passphrase, curve_oid=None): - - # See RFC5915 https://tools.ietf.org/html/rfc5915 - # - # ECPrivateKey ::= SEQUENCE { - # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - # privateKey OCTET STRING, - # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - # publicKey [1] BIT STRING OPTIONAL - # } - - ec_private_key = DerSequence().decode(encoded, nr_elements=(2, 3, 4)) - if ec_private_key[0] != 1: - raise ValueError("Incorrect ECC private key version") - - scalar_bytes = DerOctetString().decode(ec_private_key[1]).payload - - next_element = 2 - - # Try to decode 'parameters' - if next_element < len(ec_private_key): - try: - parameters = DerObjectId(explicit=0).decode(ec_private_key[next_element]).value - if curve_oid is not None and parameters != curve_oid: - raise ValueError("Curve mismatch") - curve_oid = parameters - next_element += 1 - except ValueError: - pass - - if curve_oid is None: - raise ValueError("No curve found") - - for curve_name, curve in _curves.items(): - if curve.oid == curve_oid: - break - else: - raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) - - modulus_bytes = curve.p.size_in_bytes() - if len(scalar_bytes) != modulus_bytes: - raise ValueError("Private key is too small") - - # Try to decode 'publicKey' - point_x = point_y = None - if next_element < len(ec_private_key): - try: - public_key_enc = DerBitString(explicit=1).decode(ec_private_key[next_element]).value - public_key = _import_public_der(public_key_enc, curve_oid=curve_oid) - point_x = public_key.pointQ.x - point_y = public_key.pointQ.y - next_element += 1 - except ValueError: - pass - - d = Integer.from_bytes(scalar_bytes) - return construct(curve=curve_name, d=d, point_x=point_x, point_y=point_y) - - -def _import_pkcs8(encoded, passphrase): - from Crypto.IO import PKCS8 - - algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) - - nist_p_oids = ( - "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) - "1.3.132.1.12", # id-ecDH - "1.3.132.1.13" # id-ecMQV - ) - eddsa_oids = { - "1.3.101.112": "Ed25519", # id-Ed25519 - "1.3.101.113": "Ed448", # id-Ed448 - } - xdh_oids = { - "1.3.101.110": "Curve25519", # id-X25519 - "1.3.101.111": "Curve448", # id-X448 - } - - if algo_oid in nist_p_oids: - curve_oid = DerObjectId().decode(params).value - return _import_rfc5915_der(private_key, passphrase, curve_oid) - elif algo_oid in eddsa_oids: - if params is not None: - raise ValueError("EdDSA ECC private key must not have parameters") - curve_oid = None - seed = DerOctetString().decode(private_key).payload - return construct(curve=eddsa_oids[algo_oid], seed=seed) - elif algo_oid in xdh_oids: - curve_name = xdh_oids[algo_oid] - if params is not None: - raise ValueError("%s ECC private key must not have parameters" % - curve_name) - curve_oid = None - seed = DerOctetString().decode(private_key).payload - return construct(curve=xdh_oids[algo_oid], seed=seed) - else: - raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid) - - -def _import_x509_cert(encoded, *kwargs): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info) - - -def _import_der(encoded, passphrase): - - try: - return _import_subjectPublicKeyInfo(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_x509_cert(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_rfc5915_der(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_pkcs8(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - raise ValueError("Not an ECC DER key") - - -def _import_openssh_public(encoded): - parts = encoded.split(b' ') - if len(parts) not in (2, 3): - raise ValueError("Not an openssh public key") - - try: - keystring = binascii.a2b_base64(parts[1]) - - keyparts = [] - while len(keystring) > 4: - lk = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + lk]) - keystring = keystring[4 + lk:] - - if parts[0] != keyparts[0]: - raise ValueError("Mismatch in openssh public key") - - # NIST P curves - if parts[0].startswith(b"ecdsa-sha2-"): - - for curve_name, curve in _curves.items(): - if curve.openssh is None: - continue - if not curve.openssh.startswith("ecdsa-sha2"): - continue - middle = tobytes(curve.openssh.split("-")[2]) - if keyparts[1] == middle: - break - else: - raise ValueError("Unsupported ECC curve: " + middle) - - ecc_key = _import_public_der(keyparts[2], curve_oid=curve.oid) - - # EdDSA - elif parts[0] == b"ssh-ed25519": - x, y = _import_ed25519_public_key(keyparts[1]) - ecc_key = construct(curve="Ed25519", point_x=x, point_y=y) - else: - raise ValueError("Unsupported SSH key type: " + parts[0]) - - except (IndexError, TypeError, binascii.Error): - raise ValueError("Error parsing SSH key type: " + parts[0]) - - return ecc_key - - -def _import_openssh_private_ecc(data, password): - - from ._openssh import (import_openssh_private_generic, - read_bytes, read_string, check_padding) - - key_type, decrypted = import_openssh_private_generic(data, password) - - eddsa_keys = { - "ssh-ed25519": ("Ed25519", _import_ed25519_public_key, 32), - } - - # https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04 - if key_type.startswith("ecdsa-sha2"): - - ecdsa_curve_name, decrypted = read_string(decrypted) - if ecdsa_curve_name not in _curves: - raise UnsupportedEccFeature("Unsupported ECC curve %s" % ecdsa_curve_name) - curve = _curves[ecdsa_curve_name] - modulus_bytes = (curve.modulus_bits + 7) // 8 - - public_key, decrypted = read_bytes(decrypted) - - if bord(public_key[0]) != 4: - raise ValueError("Only uncompressed OpenSSH EC keys are supported") - if len(public_key) != 2 * modulus_bytes + 1: - raise ValueError("Incorrect public key length") - - point_x = Integer.from_bytes(public_key[1:1+modulus_bytes]) - point_y = Integer.from_bytes(public_key[1+modulus_bytes:]) - - private_key, decrypted = read_bytes(decrypted) - d = Integer.from_bytes(private_key) - - params = {'d': d, 'curve': ecdsa_curve_name} - - elif key_type in eddsa_keys: - - curve_name, import_eddsa_public_key, seed_len = eddsa_keys[key_type] - - public_key, decrypted = read_bytes(decrypted) - point_x, point_y = import_eddsa_public_key(public_key) - - private_public_key, decrypted = read_bytes(decrypted) - seed = private_public_key[:seed_len] - - params = {'seed': seed, 'curve': curve_name} - else: - raise ValueError("Unsupport SSH agent key type:" + key_type) - - _, padded = read_string(decrypted) # Comment - check_padding(padded) - - return construct(point_x=point_x, point_y=point_y, **params) - - -def _import_ed25519_public_key(encoded): - """Import an Ed25519 ECC public key, encoded as raw bytes as described - in RFC8032_. - - Args: - encoded (bytes): - The Ed25519 public key to import. It must be 32 bytes long. - - Returns: - x and y (integer) - - Raises: - ValueError: when the given key cannot be parsed. - - .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 - """ - - if len(encoded) != 32: - raise ValueError("Incorrect length. Only Ed25519 public keys are supported.") - - p = Integer(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed) # 2**255 - 19 - d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 - - y = bytearray(encoded) - x_lsb = y[31] >> 7 - y[31] &= 0x7F - point_y = Integer.from_bytes(y, byteorder='little') - if point_y >= p: - raise ValueError("Invalid Ed25519 key (y)") - if point_y == 1: - return 0, 1 - - u = (point_y**2 - 1) % p - v = ((point_y**2 % p) * d + 1) % p - try: - v_inv = v.inverse(p) - x2 = (u * v_inv) % p - point_x = Integer._tonelli_shanks(x2, p) - if (point_x & 1) != x_lsb: - point_x = p - point_x - except ValueError: - raise ValueError("Invalid Ed25519 public key") - return point_x, point_y - - -def _import_curve25519_public_key(encoded): - """Import a Curve25519 ECC public key, - encoded as raw bytes as described in RFC7748_. - - Args: - encoded (bytes): - The Curve25519 public key to import. It must be 32 bytes long. - - Returns: - x (integer) - - Raises: - ValueError: when the given key cannot be parsed. - - .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748 - """ - - if len(encoded) != 32: - raise ValueError("Incorrect Curve25519 key length") - - x = bytearray(encoded) - # RFC 7741, Section 5 - x[31] &= 0x7F - point_x = Integer.from_bytes(x, byteorder='little') - - return point_x - - -def _import_curve448_public_key(encoded): - """Import a Curve448 ECC public key, - encoded as raw bytes as described in RFC7748_. - - Args: - encoded (bytes): - The Curve448 public key to import. It must be 56 bytes long. - - Returns: - x (integer) - - Raises: - ValueError: when the given key cannot be parsed. - - .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748 - """ - - if len(encoded) != 56: - raise ValueError("Incorrect Curve448 key length") - - point_x = Integer.from_bytes(encoded, byteorder='little') - - return point_x - - -def _import_ed448_public_key(encoded): - """Import an Ed448 ECC public key, encoded as raw bytes as described - in RFC8032_. - - Args: - encoded (bytes): - The Ed448 public key to import. It must be 57 bytes long. - - Returns: - x and y (integer) - - Raises: - ValueError: when the given key cannot be parsed. - - .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 - """ - - if len(encoded) != 57: - raise ValueError("Incorrect length. Only Ed448 public keys are supported.") - - p = _curves['curve448'].p - d = p - 39081 - - y = encoded[:56] - x_lsb = bord(encoded[56]) >> 7 - point_y = Integer.from_bytes(y, byteorder='little') - if point_y >= p: - raise ValueError("Invalid Ed448 key (y)") - if point_y == 1: - return 0, 1 - - u = (point_y**2 - 1) % p - v = ((point_y**2 % p) * d - 1) % p - try: - v_inv = v.inverse(p) - x2 = (u * v_inv) % p - point_x = Integer._tonelli_shanks(x2, p) - if (point_x & 1) != x_lsb: - point_x = p - point_x - except ValueError: - raise ValueError("Invalid Ed448 public key") - return point_x, point_y - - -def import_key(encoded, passphrase=None, curve_name=None): - """Import an ECC key (public or private). - - Args: - encoded (bytes or multi-line string): - The ECC key to import. - The function will try to automatically detect the right format. - - Supported formats for an ECC **public** key: - - * X.509 certificate: binary (DER) or ASCII (PEM). - * X.509 ``subjectPublicKeyInfo``: binary (DER) or ASCII (PEM). - * SEC1_ (or X9.62), as ``bytes``. NIST P curves only. - You must also provide the ``curve_name`` (with a value from the `ECC table`_) - * OpenSSH line, defined in RFC5656_ and RFC8709_ (ASCII). - This is normally the content of files like ``~/.ssh/id_ecdsa.pub``. - - Supported formats for an ECC **private** key: - - * A binary ``ECPrivateKey`` structure, as defined in `RFC5915`_ (DER). - NIST P curves only. - * A `PKCS#8`_ structure (or the more recent Asymmetric Key - Package, RFC5958_): binary (DER) or ASCII (PEM). - * `OpenSSH 6.5`_ and newer versions (ASCII). - - Private keys can be in the clear or password-protected. - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (byte string): - The passphrase to use for decrypting a private key. - Encryption may be applied protected at the PEM level (not recommended) - or at the PKCS#8 level (recommended). - This parameter is ignored if the key in input is not encrypted. - - curve_name (string): - For a SEC1 encoding only. This is the name of the curve, - as defined in the `ECC table`_. - - .. note:: - - To import EdDSA private and public keys, when encoded as raw ``bytes``, use: - - * :func:`Crypto.Signature.eddsa.import_public_key`, or - * :func:`Crypto.Signature.eddsa.import_private_key`. - - .. note:: - - To import X25519/X448 private and public keys, when encoded as raw ``bytes``, use: - - * :func:`Crypto.Protocol.DH.import_x25519_public_key` - * :func:`Crypto.Protocol.DH.import_x25519_private_key` - * :func:`Crypto.Protocol.DH.import_x448_public_key` - * :func:`Crypto.Protocol.DH.import_x448_private_key` - - Returns: - :class:`EccKey` : a new ECC key object - - Raises: - ValueError: when the given key cannot be parsed (possibly because - the pass phrase is wrong). - - .. _RFC1421: https://datatracker.ietf.org/doc/html/rfc1421 - .. _RFC1423: https://datatracker.ietf.org/doc/html/rfc1423 - .. _RFC5915: https://datatracker.ietf.org/doc/html/rfc5915 - .. _RFC5656: https://datatracker.ietf.org/doc/html/rfc5656 - .. _RFC8709: https://datatracker.ietf.org/doc/html/rfc8709 - .. _RFC5958: https://datatracker.ietf.org/doc/html/rfc5958 - .. _`PKCS#8`: https://datatracker.ietf.org/doc/html/rfc5208 - .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf - .. _SEC1: https://www.secg.org/sec1-v2.pdf - """ - - from Crypto.IO import PEM - - encoded = tobytes(encoded) - if passphrase is not None: - passphrase = tobytes(passphrase) - - # PEM - if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): - text_encoded = tostr(encoded) - openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - result = _import_openssh_private_ecc(openssh_encoded, passphrase) - return result - - elif encoded.startswith(b'-----'): - - text_encoded = tostr(encoded) - - # Remove any EC PARAMETERS section - # Ignore its content because the curve type must be already given in the key - ecparams_start = "-----BEGIN EC PARAMETERS-----" - ecparams_end = "-----END EC PARAMETERS-----" - text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", - text_encoded, - flags=re.DOTALL) - - der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - if enc_flag: - passphrase = None - try: - result = _import_der(der_encoded, passphrase) - except UnsupportedEccFeature as uef: - raise uef - except ValueError: - raise ValueError("Invalid DER encoding inside the PEM file") - return result - - # OpenSSH - if encoded.startswith((b'ecdsa-sha2-', b'ssh-ed25519')): - return _import_openssh_public(encoded) - - # DER - if len(encoded) > 0 and bord(encoded[0]) == 0x30: - return _import_der(encoded, passphrase) - - # SEC1 - if len(encoded) > 0 and bord(encoded[0]) in (0x02, 0x03, 0x04): - if curve_name is None: - raise ValueError("No curve name was provided") - return _import_public_der(encoded, curve_name=curve_name) - - raise ValueError("ECC key format is not supported") - - -if __name__ == "__main__": - - import time - - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - - point = _curves['p256'].G.copy() - count = 3000 - - start = time.time() - for x in range(count): - pointX = point * d - print("(P-256 G)", (time.time() - start) / count * 1000, "ms") - - start = time.time() - for x in range(count): - pointX = pointX * d - print("(P-256 arbitrary point)", (time.time() - start) / count * 1000, "ms") diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.pyi deleted file mode 100644 index e0e6517..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ECC.pyi +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -from typing import Union, Callable, Optional, Tuple, Dict, NamedTuple, Any, overload, Literal -from typing_extensions import TypedDict, Unpack, NotRequired - -from Crypto.Math.Numbers import Integer -from Crypto.IO._PBES import ProtParams - -from ._point import EccPoint as EccPoint -from ._point import EccXPoint as EccXPoint - -RNG = Callable[[int], bytes] - - -class UnsupportedEccFeature(ValueError): - ... - -class ExportParams(TypedDict): - passphrase: NotRequired[Union[bytes, str]] - use_pkcs8: NotRequired[bool] - protection: NotRequired[str] - compress: NotRequired[bool] - prot_params: NotRequired[ProtParams] - - -class EccKey(object): - curve: str - def __init__(self, *, curve: str = ..., d: int = ..., point: EccPoint = ...) -> None: ... - def __eq__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... - def has_private(self) -> bool: ... - @property - def d(self) -> int: ... - @property - def pointQ(self) -> EccPoint: ... - def public_key(self) -> EccKey: ... - - @overload - def export_key(self, - *, - format: Literal['PEM', 'OpenSSH'], - **kwargs: Unpack[ExportParams]) -> str: ... - - @overload - def export_key(self, - *, - format: Literal['DER', 'SEC1', 'raw'], - **kwargs: Unpack[ExportParams]) -> bytes: ... - - -_Curve = NamedTuple("_Curve", [('p', Integer), - ('order', Integer), - ('b', Integer), - ('Gx', Integer), - ('Gy', Integer), - ('G', EccPoint), - ('modulus_bits', int), - ('oid', str), - ('context', Any), - ('desc', str), - ('openssh', Union[str, None]), - ]) - -_curves: Dict[str, _Curve] - -def _import_rfc5915_der(encoded: bytes, - passphrase: Optional[str] = None, - curve_oid: Optional[str] = None) -> EccKey: ... - -def generate(**kwargs: Union[str, RNG]) -> EccKey: ... -def construct(**kwargs: Union[str, int]) -> EccKey: ... - - -def import_key(encoded: Union[bytes, str], - passphrase: Optional[str] = None, - curve_name: Optional[str] = None) -> EccKey: ... - - -def _import_ed25519_public_key(encoded: bytes) -> EccKey: ... -def _import_ed448_public_key(encoded: bytes) -> EccKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.py deleted file mode 100644 index 3b10840..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.py +++ /dev/null @@ -1,286 +0,0 @@ -# -# ElGamal.py : ElGamal encryption/decryption and signatures -# -# Part of the Python Cryptography Toolkit -# -# Originally written by: A.M. Kuchling -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['generate', 'construct', 'ElGamalKey'] - -from Crypto import Random -from Crypto.Math.Primality import ( generate_probable_safe_prime, - test_probable_prime, COMPOSITE ) -from Crypto.Math.Numbers import Integer - -# Generate an ElGamal key with N bits -def generate(bits, randfunc): - """Randomly generate a fresh, new ElGamal key. - - The key will be safe for use for both encryption and signature - (although it should be used for **only one** purpose). - - Args: - bits (int): - Key length, or size (in bits) of the modulus *p*. - The recommended value is 2048. - randfunc (callable): - Random number generation function; it should accept - a single integer *N* and return a string of random - *N* random bytes. - - Return: - an :class:`ElGamalKey` object - """ - - obj=ElGamalKey() - - # Generate a safe prime p - # See Algorithm 4.86 in Handbook of Applied Cryptography - obj.p = generate_probable_safe_prime(exact_bits=bits, randfunc=randfunc) - q = (obj.p - 1) >> 1 - - # Generate generator g - while 1: - # Choose a square residue; it will generate a cyclic group of order q. - obj.g = pow(Integer.random_range(min_inclusive=2, - max_exclusive=obj.p, - randfunc=randfunc), 2, obj.p) - - # We must avoid g=2 because of Bleichenbacher's attack described - # in "Generating ElGamal signatures without knowning the secret key", - # 1996 - if obj.g in (1, 2): - continue - - # Discard g if it divides p-1 because of the attack described - # in Note 11.67 (iii) in HAC - if (obj.p - 1) % obj.g == 0: - continue - - # g^{-1} must not divide p-1 because of Khadir's attack - # described in "Conditions of the generator for forging ElGamal - # signature", 2011 - ginv = obj.g.inverse(obj.p) - if (obj.p - 1) % ginv == 0: - continue - - # Found - break - - # Generate private key x - obj.x = Integer.random_range(min_inclusive=2, - max_exclusive=obj.p-1, - randfunc=randfunc) - # Generate public key y - obj.y = pow(obj.g, obj.x, obj.p) - return obj - -def construct(tup): - r"""Construct an ElGamal key from a tuple of valid ElGamal components. - - The modulus *p* must be a prime. - The following conditions must apply: - - .. math:: - - \begin{align} - &1 < g < p-1 \\ - &g^{p-1} = 1 \text{ mod } 1 \\ - &1 < x < p-1 \\ - &g^x = y \text{ mod } p - \end{align} - - Args: - tup (tuple): - A tuple with either 3 or 4 integers, - in the following order: - - 1. Modulus (*p*). - 2. Generator (*g*). - 3. Public key (*y*). - 4. Private key (*x*). Optional. - - Raises: - ValueError: when the key being imported fails the most basic ElGamal validity checks. - - Returns: - an :class:`ElGamalKey` object - """ - - obj=ElGamalKey() - if len(tup) not in [3,4]: - raise ValueError('argument for construct() wrong length') - for i in range(len(tup)): - field = obj._keydata[i] - setattr(obj, field, Integer(tup[i])) - - fmt_error = test_probable_prime(obj.p) == COMPOSITE - fmt_error |= obj.g<=1 or obj.g>=obj.p - fmt_error |= pow(obj.g, obj.p-1, obj.p)!=1 - fmt_error |= obj.y<1 or obj.y>=obj.p - if len(tup)==4: - fmt_error |= obj.x<=1 or obj.x>=obj.p - fmt_error |= pow(obj.g, obj.x, obj.p)!=obj.y - - if fmt_error: - raise ValueError("Invalid ElGamal key components") - - return obj - -class ElGamalKey(object): - r"""Class defining an ElGamal key. - Do not instantiate directly. - Use :func:`generate` or :func:`construct` instead. - - :ivar p: Modulus - :vartype d: integer - - :ivar g: Generator - :vartype e: integer - - :ivar y: Public key component - :vartype y: integer - - :ivar x: Private key component - :vartype x: integer - """ - - #: Dictionary of ElGamal parameters. - #: - #: A public key will only have the following entries: - #: - #: - **y**, the public key. - #: - **g**, the generator. - #: - **p**, the modulus. - #: - #: A private key will also have: - #: - #: - **x**, the private key. - _keydata=['p', 'g', 'y', 'x'] - - def __init__(self, randfunc=None): - if randfunc is None: - randfunc = Random.new().read - self._randfunc = randfunc - - def _encrypt(self, M, K): - a=pow(self.g, K, self.p) - b=( pow(self.y, K, self.p)*M ) % self.p - return [int(a), int(b)] - - def _decrypt(self, M): - if (not hasattr(self, 'x')): - raise TypeError('Private key not available in this object') - r = Integer.random_range(min_inclusive=2, - max_exclusive=self.p-1, - randfunc=self._randfunc) - a_blind = (pow(self.g, r, self.p) * M[0]) % self.p - ax=pow(a_blind, self.x, self.p) - plaintext_blind = (ax.inverse(self.p) * M[1] ) % self.p - plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p - return int(plaintext) - - def _sign(self, M, K): - if (not hasattr(self, 'x')): - raise TypeError('Private key not available in this object') - p1=self.p-1 - K = Integer(K) - if (K.gcd(p1)!=1): - raise ValueError('Bad K value: GCD(K,p-1)!=1') - a=pow(self.g, K, self.p) - t=(Integer(M)-self.x*a) % p1 - while t<0: t=t+p1 - b=(t*K.inverse(p1)) % p1 - return [int(a), int(b)] - - def _verify(self, M, sig): - sig = [Integer(x) for x in sig] - if sig[0]<1 or sig[0]>self.p-1: - return 0 - v1=pow(self.y, sig[0], self.p) - v1=(v1*pow(sig[0], sig[1], self.p)) % self.p - v2=pow(self.g, M, self.p) - if v1==v2: - return 1 - return 0 - - def has_private(self): - """Whether this is an ElGamal private key""" - - if hasattr(self, 'x'): - return 1 - else: - return 0 - - def can_encrypt(self): - return True - - def can_sign(self): - return True - - def publickey(self): - """A matching ElGamal public key. - - Returns: - a new :class:`ElGamalKey` object - """ - return construct((self.p, self.g, self.y)) - - def __eq__(self, other): - if bool(self.has_private()) != bool(other.has_private()): - return False - - result = True - for comp in self._keydata: - result = result and (getattr(self.key, comp, None) == - getattr(other.key, comp, None)) - return result - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - # ElGamal key is not pickable - from pickle import PicklingError - raise PicklingError - - # Methods defined in PyCrypto that we don't support anymore - - def sign(self, M, K): - raise NotImplementedError - - def verify(self, M, signature): - raise NotImplementedError - - def encrypt(self, plaintext, K): - raise NotImplementedError - - def decrypt(self, ciphertext): - raise NotImplementedError - - def blind(self, M, B): - raise NotImplementedError - - def unblind(self, M, B): - raise NotImplementedError - - def size(self): - raise NotImplementedError diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.pyi deleted file mode 100644 index 9048531..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/ElGamal.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Callable, Union, Tuple, Optional - -__all__ = ['generate', 'construct', 'ElGamalKey'] - -RNG = Callable[[int], bytes] - -def generate(bits: int, randfunc: RNG) -> ElGamalKey: ... -def construct(tup: Union[Tuple[int, int, int], Tuple[int, int, int, int]]) -> ElGamalKey: ... - -class ElGamalKey(object): - def __init__(self, randfunc: Optional[RNG]=None) -> None: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... - def can_sign(self) -> bool: ... - def publickey(self) -> ElGamalKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.py deleted file mode 100644 index bc8f9d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.py +++ /dev/null @@ -1,871 +0,0 @@ -# -*- coding: utf-8 -*- -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['generate', 'construct', 'import_key', - 'RsaKey', 'oid'] - -import binascii -import struct - -from Crypto import Random -from Crypto.Util.py3compat import tobytes, bord, tostr -from Crypto.Util.asn1 import DerSequence, DerNull -from Crypto.Util.number import bytes_to_long - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import (test_probable_prime, - generate_probable_prime, COMPOSITE) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - - -class RsaKey(object): - r"""Class defining an RSA key, private or public. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar n: RSA modulus - :vartype n: integer - - :ivar e: RSA public exponent - :vartype e: integer - - :ivar d: RSA private exponent - :vartype d: integer - - :ivar p: First factor of the RSA modulus - :vartype p: integer - - :ivar q: Second factor of the RSA modulus - :vartype q: integer - - :ivar invp: Chinese remainder component (:math:`p^{-1} \text{mod } q`) - :vartype invp: integer - - :ivar invq: Chinese remainder component (:math:`q^{-1} \text{mod } p`) - :vartype invq: integer - - :ivar u: Same as ``invp`` - :vartype u: integer - """ - - def __init__(self, **kwargs): - """Build an RSA key. - - :Keywords: - n : integer - The modulus. - e : integer - The public exponent. - d : integer - The private exponent. Only required for private keys. - p : integer - The first factor of the modulus. Only required for private keys. - q : integer - The second factor of the modulus. Only required for private keys. - u : integer - The CRT coefficient (inverse of p modulo q). Only required for - private keys. - """ - - input_set = set(kwargs.keys()) - public_set = set(('n', 'e')) - private_set = public_set | set(('p', 'q', 'd', 'u')) - if input_set not in (private_set, public_set): - raise ValueError("Some RSA components are missing") - for component, value in kwargs.items(): - setattr(self, "_" + component, value) - if input_set == private_set: - self._dp = self._d % (self._p - 1) # = (e⁻¹) mod (p-1) - self._dq = self._d % (self._q - 1) # = (e⁻¹) mod (q-1) - self._invq = None # will be computed on demand - - @property - def n(self): - return int(self._n) - - @property - def e(self): - return int(self._e) - - @property - def d(self): - if not self.has_private(): - raise AttributeError("No private exponent available for public keys") - return int(self._d) - - @property - def p(self): - if not self.has_private(): - raise AttributeError("No CRT component 'p' available for public keys") - return int(self._p) - - @property - def q(self): - if not self.has_private(): - raise AttributeError("No CRT component 'q' available for public keys") - return int(self._q) - - @property - def dp(self): - if not self.has_private(): - raise AttributeError("No CRT component 'dp' available for public keys") - return int(self._dp) - - @property - def dq(self): - if not self.has_private(): - raise AttributeError("No CRT component 'dq' available for public keys") - return int(self._dq) - - @property - def invq(self): - if not self.has_private(): - raise AttributeError("No CRT component 'invq' available for public keys") - if self._invq is None: - self._invq = self._q.inverse(self._p) - return int(self._invq) - - @property - def invp(self): - return self.u - - @property - def u(self): - if not self.has_private(): - raise AttributeError("No CRT component 'u' available for public keys") - return int(self._u) - - def size_in_bits(self): - """Size of the RSA modulus in bits""" - return self._n.size_in_bits() - - def size_in_bytes(self): - """The minimal amount of bytes that can hold the RSA modulus""" - return (self._n.size_in_bits() - 1) // 8 + 1 - - def _encrypt(self, plaintext): - if not 0 <= plaintext < self._n: - raise ValueError("Plaintext too large") - return int(pow(Integer(plaintext), self._e, self._n)) - - def _decrypt_to_bytes(self, ciphertext): - if not 0 <= ciphertext < self._n: - raise ValueError("Ciphertext too large") - if not self.has_private(): - raise TypeError("This is not a private key") - - # Blinded RSA decryption (to prevent timing attacks): - # Step 1: Generate random secret blinding factor r, - # such that 0 < r < n-1 - r = Integer.random_range(min_inclusive=1, max_exclusive=self._n) - # Step 2: Compute c' = c * r**e mod n - cp = Integer(ciphertext) * pow(r, self._e, self._n) % self._n - # Step 3: Compute m' = c'**d mod n (normal RSA decryption) - m1 = pow(cp, self._dp, self._p) - m2 = pow(cp, self._dq, self._q) - h = ((m2 - m1) * self._u) % self._q - mp = h * self._p + m1 - # Step 4: Compute m = m' * (r**(-1)) mod n - # then encode into a big endian byte string - result = Integer._mult_modulo_bytes( - r.inverse(self._n), - mp, - self._n) - return result - - def _decrypt(self, ciphertext): - """Legacy private method""" - - return bytes_to_long(self._decrypt_to_bytes(ciphertext)) - - def has_private(self): - """Whether this is an RSA private key""" - - return hasattr(self, "_d") - - def can_encrypt(self): # legacy - return True - - def can_sign(self): # legacy - return True - - def public_key(self): - """A matching RSA public key. - - Returns: - a new :class:`RsaKey` object - """ - return RsaKey(n=self._n, e=self._e) - - def __eq__(self, other): - if self.has_private() != other.has_private(): - return False - if self.n != other.n or self.e != other.e: - return False - if not self.has_private(): - return True - return (self.d == other.d) - - def __ne__(self, other): - return not (self == other) - - def __getstate__(self): - # RSA key is not pickable - from pickle import PicklingError - raise PicklingError - - def __repr__(self): - if self.has_private(): - extra = ", d=%d, p=%d, q=%d, u=%d" % (int(self._d), int(self._p), - int(self._q), int(self._u)) - else: - extra = "" - return "RsaKey(n=%d, e=%d%s)" % (int(self._n), int(self._e), extra) - - def __str__(self): - if self.has_private(): - key_type = "Private" - else: - key_type = "Public" - return "%s RSA key at 0x%X" % (key_type, id(self)) - - def export_key(self, format='PEM', passphrase=None, pkcs=1, - protection=None, randfunc=None, prot_params=None): - """Export this RSA key. - - Keyword Args: - format (string): - The desired output format: - - - ``'PEM'``. (default) Text output, according to `RFC1421`_/`RFC1423`_. - - ``'DER'``. Binary output. - - ``'OpenSSH'``. Text output, according to the OpenSSH specification. - Only suitable for public keys (not private keys). - - Note that PEM contains a DER structure. - - passphrase (bytes or string): - (*Private keys only*) The passphrase to protect the - private key. - - pkcs (integer): - (*Private keys only*) The standard to use for - serializing the key: PKCS#1 or PKCS#8. - - With ``pkcs=1`` (*default*), the private key is encoded with a - simple `PKCS#1`_ structure (``RSAPrivateKey``). The key cannot be - securely encrypted. - - With ``pkcs=8``, the private key is encoded with a `PKCS#8`_ structure - (``PrivateKeyInfo``). PKCS#8 offers the best ways to securely - encrypt the key. - - .. note:: - This parameter is ignored for a public key. - For DER and PEM, the output is always an - ASN.1 DER ``SubjectPublicKeyInfo`` structure. - - protection (string): - (*For private keys only*) - The encryption scheme to use for protecting the private key - using the passphrase. - - You can only specify a value if ``pkcs=8``. - For all possible protection schemes, - refer to :ref:`the encryption parameters of PKCS#8`. - The recommended value is - ``'PBKDF2WithHMAC-SHA512AndAES256-CBC'``. - - If ``None`` (default), the behavior depends on :attr:`format`: - - - if ``format='PEM'``, the obsolete PEM encryption scheme is used. - It is based on MD5 for key derivation, and 3DES for encryption. - - - if ``format='DER'``, the ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'`` - scheme is used. - - prot_params (dict): - (*For private keys only*) - - The parameters to use to derive the encryption key - from the passphrase. ``'protection'`` must be also specified. - For all possible values, - refer to :ref:`the encryption parameters of PKCS#8`. - The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, - and ``{'iteration_count':131072}`` for scrypt. - - randfunc (callable): - A function that provides random bytes. Only used for PEM encoding. - The default is :func:`Crypto.Random.get_random_bytes`. - - Returns: - bytes: the encoded key - - Raises: - ValueError:when the format is unknown or when you try to encrypt a private - key with *DER* format and PKCS#1. - - .. warning:: - If you don't provide a pass phrase, the private key will be - exported in the clear! - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - """ - - if passphrase is not None: - passphrase = tobytes(passphrase) - - if randfunc is None: - randfunc = Random.get_random_bytes - - if format == 'OpenSSH': - e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)] - if bord(e_bytes[0]) & 0x80: - e_bytes = b'\x00' + e_bytes - if bord(n_bytes[0]) & 0x80: - n_bytes = b'\x00' + n_bytes - keyparts = [b'ssh-rsa', e_bytes, n_bytes] - keystring = b''.join([struct.pack(">I", len(kp)) + kp for kp in keyparts]) - return b'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1] - - # DER format is always used, even in case of PEM, which simply - # encodes it into BASE64. - if self.has_private(): - binary_key = DerSequence([0, - self.n, - self.e, - self.d, - self.p, - self.q, - self.d % (self.p-1), - self.d % (self.q-1), - Integer(self.q).inverse(self.p) - ]).encode() - if pkcs == 1: - key_type = 'RSA PRIVATE KEY' - if format == 'DER' and passphrase: - raise ValueError("PKCS#1 private key cannot be encrypted") - else: # PKCS#8 - from Crypto.IO import PKCS8 - - if format == 'PEM' and protection is None: - key_type = 'PRIVATE KEY' - binary_key = PKCS8.wrap(binary_key, oid, None, - key_params=DerNull()) - else: - key_type = 'ENCRYPTED PRIVATE KEY' - if not protection: - if prot_params: - raise ValueError("'protection' parameter must be set") - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - binary_key = PKCS8.wrap(binary_key, oid, - passphrase, protection, - prot_params=prot_params, - key_params=DerNull()) - passphrase = None - else: - key_type = "PUBLIC KEY" - binary_key = _create_subject_public_key_info(oid, - DerSequence([self.n, - self.e]), - DerNull() - ) - - if format == 'DER': - return binary_key - if format == 'PEM': - from Crypto.IO import PEM - - pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc) - return tobytes(pem_str) - - raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format) - - # Backward compatibility - def exportKey(self, *args, **kwargs): - """:meta private:""" - return self.export_key(*args, **kwargs) - - def publickey(self): - """:meta private:""" - return self.public_key() - - # Methods defined in PyCrypto that we don't support anymore - def sign(self, M, K): - """:meta private:""" - raise NotImplementedError("Use module Crypto.Signature.pkcs1_15 instead") - - def verify(self, M, signature): - """:meta private:""" - raise NotImplementedError("Use module Crypto.Signature.pkcs1_15 instead") - - def encrypt(self, plaintext, K): - """:meta private:""" - raise NotImplementedError("Use module Crypto.Cipher.PKCS1_OAEP instead") - - def decrypt(self, ciphertext): - """:meta private:""" - raise NotImplementedError("Use module Crypto.Cipher.PKCS1_OAEP instead") - - def blind(self, M, B): - """:meta private:""" - raise NotImplementedError - - def unblind(self, M, B): - """:meta private:""" - raise NotImplementedError - - def size(self): - """:meta private:""" - raise NotImplementedError - - -def generate(bits, randfunc=None, e=65537): - """Create a new RSA key pair. - - The algorithm closely follows NIST `FIPS 186-4`_ in its - sections B.3.1 and B.3.3. The modulus is the product of - two non-strong probable primes. - Each prime passes a suitable number of Miller-Rabin tests - with random bases and a single Lucas test. - - Args: - bits (integer): - Key length, or size (in bits) of the RSA modulus. - It must be at least 1024, but **2048 is recommended.** - The FIPS standard only defines 1024, 2048 and 3072. - Keyword Args: - randfunc (callable): - Function that returns random bytes. - The default is :func:`Crypto.Random.get_random_bytes`. - e (integer): - Public RSA exponent. It must be an odd positive integer. - It is typically a small number with very few ones in its - binary representation. - The FIPS standard requires the public exponent to be - at least 65537 (the default). - - Returns: an RSA key object (:class:`RsaKey`, with private key). - - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if bits < 1024: - raise ValueError("RSA modulus length must be >= 1024") - if e % 2 == 0 or e < 3: - raise ValueError("RSA public exponent must be a positive, odd integer larger than 2.") - - if randfunc is None: - randfunc = Random.get_random_bytes - - d = n = Integer(1) - e = Integer(e) - - while n.size_in_bits() != bits and d < (1 << (bits // 2)): - # Generate the prime factors of n: p and q. - # By construciton, their product is always - # 2^{bits-1} < p*q < 2^bits. - size_q = bits // 2 - size_p = bits - size_q - - min_p = min_q = (Integer(1) << (2 * size_q - 1)).sqrt() - if size_q != size_p: - min_p = (Integer(1) << (2 * size_p - 1)).sqrt() - - def filter_p(candidate): - return candidate > min_p and (candidate - 1).gcd(e) == 1 - - p = generate_probable_prime(exact_bits=size_p, - randfunc=randfunc, - prime_filter=filter_p) - - min_distance = Integer(1) << (bits // 2 - 100) - - def filter_q(candidate): - return (candidate > min_q and - (candidate - 1).gcd(e) == 1 and - abs(candidate - p) > min_distance) - - q = generate_probable_prime(exact_bits=size_q, - randfunc=randfunc, - prime_filter=filter_q) - - n = p * q - lcm = (p - 1).lcm(q - 1) - d = e.inverse(lcm) - - if p > q: - p, q = q, p - - u = p.inverse(q) - - return RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) - - -def construct(rsa_components, consistency_check=True): - r"""Construct an RSA key from a tuple of valid RSA components. - - The modulus **n** must be the product of two primes. - The public exponent **e** must be odd and larger than 1. - - In case of a private key, the following equations must apply: - - .. math:: - - \begin{align} - p*q &= n \\ - e*d &\equiv 1 ( \text{mod lcm} [(p-1)(q-1)]) \\ - p*u &\equiv 1 ( \text{mod } q) - \end{align} - - Args: - rsa_components (tuple): - A tuple of integers, with at least 2 and no - more than 6 items. The items come in the following order: - - 1. RSA modulus *n*. - 2. Public exponent *e*. - 3. Private exponent *d*. - Only required if the key is private. - 4. First factor of *n* (*p*). - Optional, but the other factor *q* must also be present. - 5. Second factor of *n* (*q*). Optional. - 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. - - Keyword Args: - consistency_check (boolean): - If ``True``, the library will verify that the provided components - fulfil the main RSA properties. - - Raises: - ValueError: when the key being imported fails the most basic RSA validity checks. - - Returns: An RSA key object (:class:`RsaKey`). - """ - - class InputComps(object): - pass - - input_comps = InputComps() - for (comp, value) in zip(('n', 'e', 'd', 'p', 'q', 'u'), rsa_components): - setattr(input_comps, comp, Integer(value)) - - n = input_comps.n - e = input_comps.e - if not hasattr(input_comps, 'd'): - key = RsaKey(n=n, e=e) - else: - d = input_comps.d - if hasattr(input_comps, 'q'): - p = input_comps.p - q = input_comps.q - else: - # Compute factors p and q from the private exponent d. - # We assume that n has no more than two factors. - # See 8.2.2(i) in Handbook of Applied Cryptography. - ktot = d * e - 1 - # The quantity d*e-1 is a multiple of phi(n), even, - # and can be represented as t*2^s. - t = ktot - while t % 2 == 0: - t //= 2 - # Cycle through all multiplicative inverses in Zn. - # The algorithm is non-deterministic, but there is a 50% chance - # any candidate a leads to successful factoring. - # See "Digitalized Signatures and Public Key Functions as Intractable - # as Factorization", M. Rabin, 1979 - spotted = False - a = Integer(2) - while not spotted and a < 100: - k = Integer(t) - # Cycle through all values a^{t*2^i}=a^k - while k < ktot: - cand = pow(a, k, n) - # Check if a^k is a non-trivial root of unity (mod n) - if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: - # We have found a number such that (cand-1)(cand+1)=0 (mod n). - # Either of the terms divides n. - p = Integer(n).gcd(cand + 1) - spotted = True - break - k *= 2 - # This value was not any good... let's try another! - a += 2 - if not spotted: - raise ValueError("Unable to compute factors p and q from exponent d.") - # Found ! - assert ((n % p) == 0) - q = n // p - - if hasattr(input_comps, 'u'): - u = input_comps.u - else: - u = p.inverse(q) - - # Build key object - key = RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) - - # Verify consistency of the key - if consistency_check: - - # Modulus and public exponent must be coprime - if e <= 1 or e >= n: - raise ValueError("Invalid RSA public exponent") - if Integer(n).gcd(e) != 1: - raise ValueError("RSA public exponent is not coprime to modulus") - - # For RSA, modulus must be odd - if not n & 1: - raise ValueError("RSA modulus is not odd") - - if key.has_private(): - # Modulus and private exponent must be coprime - if d <= 1 or d >= n: - raise ValueError("Invalid RSA private exponent") - if Integer(n).gcd(d) != 1: - raise ValueError("RSA private exponent is not coprime to modulus") - # Modulus must be product of 2 primes - if p * q != n: - raise ValueError("RSA factors do not match modulus") - if test_probable_prime(p) == COMPOSITE: - raise ValueError("RSA factor p is composite") - if test_probable_prime(q) == COMPOSITE: - raise ValueError("RSA factor q is composite") - # See Carmichael theorem - phi = (p - 1) * (q - 1) - lcm = phi // (p - 1).gcd(q - 1) - if (e * d % int(lcm)) != 1: - raise ValueError("Invalid RSA condition") - if hasattr(key, 'u'): - # CRT coefficient - if u <= 1 or u >= q: - raise ValueError("Invalid RSA component u") - if (p * u % q) != 1: - raise ValueError("Invalid RSA component u with p") - - return key - - -def _import_pkcs1_private(encoded, *kwargs): - # RSAPrivateKey ::= SEQUENCE { - # version Version, - # modulus INTEGER, -- n - # publicExponent INTEGER, -- e - # privateExponent INTEGER, -- d - # prime1 INTEGER, -- p - # prime2 INTEGER, -- q - # exponent1 INTEGER, -- d mod (p-1) - # exponent2 INTEGER, -- d mod (q-1) - # coefficient INTEGER -- (inverse of q) mod p - # } - # - # Version ::= INTEGER - der = DerSequence().decode(encoded, nr_elements=9, only_ints_expected=True) - if der[0] != 0: - raise ValueError("No PKCS#1 encoding of an RSA private key") - return construct(der[1:6] + [Integer(der[4]).inverse(der[5])]) - - -def _import_pkcs1_public(encoded, *kwargs): - # RSAPublicKey ::= SEQUENCE { - # modulus INTEGER, -- n - # publicExponent INTEGER -- e - # } - der = DerSequence().decode(encoded, nr_elements=2, only_ints_expected=True) - return construct(der) - - -def _import_subjectPublicKeyInfo(encoded, *kwargs): - - oids = (oid, "1.2.840.113549.1.1.10") - - algoid, encoded_key, params = _expand_subject_public_key_info(encoded) - if algoid not in oids or params is not None: - raise ValueError("No RSA subjectPublicKeyInfo") - return _import_pkcs1_public(encoded_key) - - -def _import_x509_cert(encoded, *kwargs): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info) - - -def _import_pkcs8(encoded, passphrase): - from Crypto.IO import PKCS8 - - oids = (oid, "1.2.840.113549.1.1.10") - - k = PKCS8.unwrap(encoded, passphrase) - if k[0] not in oids: - raise ValueError("No PKCS#8 encoded RSA key") - return _import_keyDER(k[1], passphrase) - - -def _import_keyDER(extern_key, passphrase): - """Import an RSA key (public or private half), encoded in DER form.""" - - decodings = (_import_pkcs1_private, - _import_pkcs1_public, - _import_subjectPublicKeyInfo, - _import_x509_cert, - _import_pkcs8) - - for decoding in decodings: - try: - return decoding(extern_key, passphrase) - except ValueError: - pass - - raise ValueError("RSA key format is not supported") - - -def _import_openssh_private_rsa(data, password): - - from ._openssh import (import_openssh_private_generic, - read_bytes, read_string, check_padding) - - ssh_name, decrypted = import_openssh_private_generic(data, password) - - if ssh_name != "ssh-rsa": - raise ValueError("This SSH key is not RSA") - - n, decrypted = read_bytes(decrypted) - e, decrypted = read_bytes(decrypted) - d, decrypted = read_bytes(decrypted) - iqmp, decrypted = read_bytes(decrypted) - p, decrypted = read_bytes(decrypted) - q, decrypted = read_bytes(decrypted) - - _, padded = read_string(decrypted) # Comment - check_padding(padded) - - build = [Integer.from_bytes(x) for x in (n, e, d, q, p, iqmp)] - return construct(build) - - -def import_key(extern_key, passphrase=None): - """Import an RSA key (public or private). - - Args: - extern_key (string or byte string): - The RSA key to import. - - The following formats are supported for an RSA **public key**: - - - X.509 certificate (binary or PEM format) - - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM - encoding) - - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) - - The following formats are supported for an RSA **private key**: - - - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` - DER SEQUENCE (binary or PEM encoding) - - OpenSSH (text format, introduced in `OpenSSH 6.5`_) - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (string or byte string): - For private keys only, the pass phrase that encrypts the key. - - Returns: An RSA key object (:class:`RsaKey`). - - Raises: - ValueError/IndexError/TypeError: - When the given key cannot be parsed (possibly because the pass - phrase is wrong). - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf - """ - - from Crypto.IO import PEM - - extern_key = tobytes(extern_key) - if passphrase is not None: - passphrase = tobytes(passphrase) - - if extern_key.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): - text_encoded = tostr(extern_key) - openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - result = _import_openssh_private_rsa(openssh_encoded, passphrase) - return result - - if extern_key.startswith(b'-----'): - # This is probably a PEM encoded key. - (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) - if enc_flag: - passphrase = None - return _import_keyDER(der, passphrase) - - if extern_key.startswith(b'ssh-rsa '): - # This is probably an OpenSSH key - keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) - keyparts = [] - while len(keystring) > 4: - length = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + length]) - keystring = keystring[4 + length:] - e = Integer.from_bytes(keyparts[1]) - n = Integer.from_bytes(keyparts[2]) - return construct([n, e]) - - if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: - # This is probably a DER encoded key - return _import_keyDER(extern_key, passphrase) - - raise ValueError("RSA key format is not supported") - - -# Backward compatibility -importKey = import_key - -#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates -#: a generic RSA key, even when such key will be actually used for digital -#: signatures. -#: -#: .. note: -#: An RSA key meant for PSS padding has a dedicated Object ID ``1.2.840.113549.1.1.10`` -#: -#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html -oid = "1.2.840.113549.1.1.1" diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.pyi deleted file mode 100644 index 9d3d157..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/RSA.pyi +++ /dev/null @@ -1,78 +0,0 @@ -from typing import Callable, Union, Tuple, Optional, overload, Literal - -from Crypto.Math.Numbers import Integer -from Crypto.IO._PBES import ProtParams - -__all__ = ['generate', 'construct', 'import_key', - 'RsaKey', 'oid'] - -RNG = Callable[[int], bytes] - -class RsaKey(object): - def __init__(self, **kwargs: int) -> None: ... - - @property - def n(self) -> int: ... - @property - def e(self) -> int: ... - @property - def d(self) -> int: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def u(self) -> int: ... - @property - def invp(self) -> int: ... - @property - def invq(self) -> int: ... - - def size_in_bits(self) -> int: ... - def size_in_bytes(self) -> int: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... # legacy - def can_sign(self) -> bool:... # legacy - def public_key(self) -> RsaKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... - def __repr__(self) -> str: ... - def __str__(self) -> str: ... - - @overload - def export_key(self, - format: Optional[str]="PEM", - passphrase: Optional[str]=None, - pkcs: Optional[int]=1, - protection: Optional[str]=None, - randfunc: Optional[RNG]=None - ) -> bytes: ... - @overload - def export_key(self, *, - format: Optional[str]="PEM", - passphrase: str, - pkcs: Literal[8], - protection: str, - randfunc: Optional[RNG]=None, - prot_params: ProtParams, - ) -> bytes: ... - - # Backward compatibility - exportKey = export_key - publickey = public_key - -Int = Union[int, Integer] - -def generate(bits: int, randfunc: Optional[RNG]=None, e: Optional[int]=65537) -> RsaKey: ... -def construct(rsa_components: Union[Tuple[Int, Int], # n, e - Tuple[Int, Int, Int], # n, e, d - Tuple[Int, Int, Int, Int, Int], # n, e, d, p, q - Tuple[Int, Int, Int, Int, Int, Int]], # n, e, d, p, q, crt_q - consistency_check: Optional[bool]=True) -> RsaKey: ... -def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> RsaKey: ... - -# Backward compatibility -importKey = import_key - -oid: str diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/__init__.py deleted file mode 100644 index cf3a238..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from Crypto.Util.asn1 import (DerSequence, DerInteger, DerBitString, - DerObjectId, DerNull) - - -def _expand_subject_public_key_info(encoded): - """Parse a SubjectPublicKeyInfo structure. - - It returns a triple with: - * OID (string) - * encoded public key (bytes) - * Algorithm parameters (bytes or None) - """ - - # - # SubjectPublicKeyInfo ::= SEQUENCE { - # algorithm AlgorithmIdentifier, - # subjectPublicKey BIT STRING - # } - # - # AlgorithmIdentifier ::= SEQUENCE { - # algorithm OBJECT IDENTIFIER, - # parameters ANY DEFINED BY algorithm OPTIONAL - # } - # - - spki = DerSequence().decode(encoded, nr_elements=2) - algo = DerSequence().decode(spki[0], nr_elements=(1,2)) - algo_oid = DerObjectId().decode(algo[0]) - spk = DerBitString().decode(spki[1]).value - - if len(algo) == 1: - algo_params = None - else: - try: - DerNull().decode(algo[1]) - algo_params = None - except: - algo_params = algo[1] - - return algo_oid.value, spk, algo_params - - -def _create_subject_public_key_info(algo_oid, public_key, params): - - if params is None: - algorithm = DerSequence([DerObjectId(algo_oid)]) - else: - algorithm = DerSequence([DerObjectId(algo_oid), params]) - - spki = DerSequence([algorithm, - DerBitString(public_key) - ]) - return spki.encode() - - -def _extract_subject_public_key_info(x509_certificate): - """Extract subjectPublicKeyInfo from a DER X.509 certificate.""" - - certificate = DerSequence().decode(x509_certificate, nr_elements=3) - tbs_certificate = DerSequence().decode(certificate[0], - nr_elements=range(6, 11)) - - index = 5 - try: - tbs_certificate[0] + 1 - # Version not present - version = 1 - except TypeError: - version = DerInteger(explicit=0).decode(tbs_certificate[0]).value - if version not in (2, 3): - raise ValueError("Incorrect X.509 certificate version") - index = 6 - - return tbs_certificate[index] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/__init__.pyi deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve.py deleted file mode 100644 index 0027f61..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -# This is the element of a database of curve parameters. Items are indexed by their -# human-friendly name, such as "P-256". The element has the following fields: -# -# - p the prime number that defines the finite field for all modulo operations -# - b the constant in the Short Weierstrass curve equation (can be None) -# - order the number of elements in the group with the generator below -# - Gx the affine coordinate X of the generator point -# - Gy the affine coordinate Y of the generator point -# - G the generator, as an EccPoint object -# - modulus_bits the minimum number of bits for encoding the modulus p -# - oid an ASCII string with the registered ASN.1 Object ID -# - context a raw pointer to memory holding a context for all curve operations (can be None) -# - canonical the canonical name of the curve -# - openssh the ASCII string used in OpenSSH id files for public keys on this curve -# - rawlib the reference to the dynamic libary with the low-level functions -# - validate a function that raises an exception if the the input point is invalid - -class _Curve(object): - - def __init__(self, p, b, order, Gx, Gy, G, modulus_bits, oid, context, - canonical, openssh, rawlib, validate=None): - self.p = p - self.b = b - self.order = order - self.Gx = Gx - self.Gy = Gy - self.G = G - self.modulus_bits = modulus_bits - self.oid = oid - self.context = context - self.canonical = canonical - self.openssh = openssh - self.rawlib = rawlib - self.validate = validate diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve25519.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve25519.abi3.so deleted file mode 100755 index 16fa548..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve25519.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve448.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve448.abi3.so deleted file mode 100755 index e0ff62b..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_curve448.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ec_ws.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ec_ws.abi3.so deleted file mode 100755 index 8f17395..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ec_ws.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed25519.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed25519.abi3.so deleted file mode 100755 index 2ca5360..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed25519.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed448.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed448.abi3.so deleted file mode 100755 index 64be8d8..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_ed448.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_edwards.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_edwards.py deleted file mode 100644 index 5b6bc6e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_edwards.py +++ /dev/null @@ -1,116 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -from ._curve import _Curve -from Crypto.Math.Numbers import Integer -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - SmartPointer) - - -def ed25519_curve(): - p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19 - order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a - Gy = 0x6666666666666666666666666666666666666666666666666666666666666658 - - _ed25519_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ed25519", """ -typedef void Point; -int ed25519_new_point(Point **out, - const uint8_t x[32], - const uint8_t y[32], - size_t modsize, - const void *context); -int ed25519_clone(Point **P, const Point *Q); -void ed25519_free_point(Point *p); -int ed25519_cmp(const Point *p1, const Point *p2); -int ed25519_neg(Point *p); -int ed25519_get_xy(uint8_t *xb, uint8_t *yb, size_t modsize, Point *p); -int ed25519_double(Point *p); -int ed25519_add(Point *P1, const Point *P2); -int ed25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); -""") - - class EcLib(object): - new_point = _ed25519_lib.ed25519_new_point - clone = _ed25519_lib.ed25519_clone - free_point = _ed25519_lib.ed25519_free_point - cmp = _ed25519_lib.ed25519_cmp - neg = _ed25519_lib.ed25519_neg - get_xy = _ed25519_lib.ed25519_get_xy - double = _ed25519_lib.ed25519_double - add = _ed25519_lib.ed25519_add - scalar = _ed25519_lib.ed25519_scalar - - ed25519 = _Curve(Integer(p), - None, - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 255, - "1.3.101.112", # RFC8410 - None, - "Ed25519", - "ssh-ed25519", - EcLib) - return ed25519 - - -def ed448_curve(): - p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1 - order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3 - Gx = 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e - Gy = 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14 - - _ed448_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ed448", """ -typedef void EcContext; -typedef void PointEd448; -int ed448_new_context(EcContext **pec_ctx); -void ed448_context(EcContext *ec_ctx); -void ed448_free_context(EcContext *ec_ctx); -int ed448_new_point(PointEd448 **out, - const uint8_t x[56], - const uint8_t y[56], - size_t len, - const EcContext *context); -int ed448_clone(PointEd448 **P, const PointEd448 *Q); -void ed448_free_point(PointEd448 *p); -int ed448_cmp(const PointEd448 *p1, const PointEd448 *p2); -int ed448_neg(PointEd448 *p); -int ed448_get_xy(uint8_t *xb, uint8_t *yb, size_t len, const PointEd448 *p); -int ed448_double(PointEd448 *p); -int ed448_add(PointEd448 *P1, const PointEd448 *P2); -int ed448_scalar(PointEd448 *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); -""") - - class EcLib(object): - new_point = _ed448_lib.ed448_new_point - clone = _ed448_lib.ed448_clone - free_point = _ed448_lib.ed448_free_point - cmp = _ed448_lib.ed448_cmp - neg = _ed448_lib.ed448_neg - get_xy = _ed448_lib.ed448_get_xy - double = _ed448_lib.ed448_double - add = _ed448_lib.ed448_add - scalar = _ed448_lib.ed448_scalar - - ed448_context = VoidPointer() - result = _ed448_lib.ed448_new_context(ed448_context.address_of()) - if result: - raise ImportError("Error %d initializing Ed448 context" % result) - - context = SmartPointer(ed448_context.get(), _ed448_lib.ed448_free_context) - - ed448 = _Curve(Integer(p), - None, - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 448, - "1.3.101.113", # RFC8410 - context, - "Ed448", - None, - EcLib) - return ed448 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_montgomery.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_montgomery.py deleted file mode 100644 index bacc4ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_montgomery.py +++ /dev/null @@ -1,152 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -from ._curve import _Curve -from Crypto.Math.Numbers import Integer -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - SmartPointer) - - -def curve25519_curve(): - p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19 - order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed - - _curve25519_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._curve25519", """ -typedef void Point; - -int curve25519_new_point(Point **out, - const uint8_t x[32], - size_t modsize, - const void* context); -int curve25519_clone(Point **P, const Point *Q); -void curve25519_free_point(Point *p); -int curve25519_get_x(uint8_t *xb, size_t modsize, Point *p); -int curve25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); -int curve25519_cmp(const Point *ecp1, const Point *ecp2); -""") - - class EcLib(object): - new_point = _curve25519_lib.curve25519_new_point - clone = _curve25519_lib.curve25519_clone - free_point = _curve25519_lib.curve25519_free_point - get_x = _curve25519_lib.curve25519_get_x - scalar = _curve25519_lib.curve25519_scalar - cmp = _curve25519_lib.curve25519_cmp - - def _validate_x25519_point(point): - - p2 = p * 2 - x1 = 325606250916557431795983626356110631294008115727848805560023387167927233504 - x2 = 39382357235489614581723060781553021112529911719440698176882885853963445705823 - - # http://cr.yp.to/ecdh.html#validate - deny_list = ( - 0, - 1, - x1, - x2, - p - 1, - p, - p + 1, - p + x1, - p + x2, - p2 - 1, - p2, - p2 + 1, - ) - - try: - valid = point.x not in deny_list - except ValueError: - valid = False - - if not valid: - raise ValueError("Invalid Curve25519 public key") - - curve25519 = _Curve(Integer(p), - None, - Integer(order), - Integer(9), - None, - None, - 255, - "1.3.101.110", # RFC8410 - None, - "Curve25519", - None, - EcLib, - _validate_x25519_point, - ) - - return curve25519 - - -def curve448_curve(): - p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1 - order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3 - - _curve448_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._curve448", """ -typedef void Curve448Context; -typedef void Curve448Point; - -int curve448_new_context(Curve448Context **pec_ctx); -void curve448_free_context(Curve448Context *ec_ctx); -int curve448_new_point(Curve448Point **out, - const uint8_t *x, - size_t len, - const Curve448Context *ec_ctx); -void curve448_free_point(Curve448Point *p); -int curve448_clone(Curve448Point **P, const Curve448Point *Q); -int curve448_get_x(uint8_t *xb, size_t modsize, const Curve448Point *p); -int curve448_scalar(Curve448Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); -int curve448_cmp(const Curve448Point *ecp1, const Curve448Point *ecp2); -""") - - class EcLib(object): - new_context = _curve448_lib.curve448_new_context - free_context = _curve448_lib.curve448_free_context - new_point = _curve448_lib.curve448_new_point - clone = _curve448_lib.curve448_clone - free_point = _curve448_lib.curve448_free_point - get_x = _curve448_lib.curve448_get_x - scalar = _curve448_lib.curve448_scalar - cmp = _curve448_lib.curve448_cmp - - curve448_context = VoidPointer() - result = EcLib.new_context(curve448_context.address_of()) - if result: - raise ImportError("Error %d initializing Curve448 context" % result) - - def _validate_x448_point(point): - deny_list = ( - 0, - 1, - p - 1, - p, - p + 1, - ) - - try: - valid = point.x not in deny_list - except ValueError: - valid = False - - if not valid: - raise ValueError("Invalid Curve448 public key") - - curve448 = _Curve(Integer(p), - None, - Integer(order), - Integer(5), - None, - None, - 448, - "1.3.101.111", # RFC8410 - SmartPointer(curve448_context.get(), EcLib.free_context), - "Curve448", - None, - EcLib, - _validate_x448_point, - ) - - return curve448 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_nist_ecc.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_nist_ecc.py deleted file mode 100644 index 82c8bd5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_nist_ecc.py +++ /dev/null @@ -1,246 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -from ._curve import _Curve -from Crypto.Math.Numbers import Integer -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - SmartPointer, c_size_t, c_uint8_ptr, - c_ulonglong) -from Crypto.Util.number import long_to_bytes -from Crypto.Random.random import getrandbits - - -_ec_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ec_ws", """ -typedef void EcContext; -typedef void EcPoint; -int ec_ws_new_context(EcContext **pec_ctx, - const uint8_t *modulus, - const uint8_t *b, - const uint8_t *order, - size_t len, - uint64_t seed); -void ec_ws_free_context(EcContext *ec_ctx); -int ec_ws_new_point(EcPoint **pecp, - const uint8_t *x, - const uint8_t *y, - size_t len, - const EcContext *ec_ctx); -void ec_ws_free_point(EcPoint *ecp); -int ec_ws_get_xy(uint8_t *x, - uint8_t *y, - size_t len, - const EcPoint *ecp); -int ec_ws_double(EcPoint *p); -int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb); -int ec_ws_scalar(EcPoint *ecp, - const uint8_t *k, - size_t len, - uint64_t seed); -int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp); -int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2); -int ec_ws_neg(EcPoint *p); -""") - - -class EcLib(object): - new_context = _ec_lib.ec_ws_new_context - free_context = _ec_lib.ec_ws_free_context - new_point = _ec_lib.ec_ws_new_point - free_point = _ec_lib.ec_ws_free_point - get_xy = _ec_lib.ec_ws_get_xy - double = _ec_lib.ec_ws_double - add = _ec_lib.ec_ws_add - scalar = _ec_lib.ec_ws_scalar - clone = _ec_lib.ec_ws_clone - cmp = _ec_lib.ec_ws_cmp - neg = _ec_lib.ec_ws_neg - - -def p192_curve(): - p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff - b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 - order = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831 - Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 - Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 - - p192_modulus = long_to_bytes(p, 24) - p192_b = long_to_bytes(b, 24) - p192_order = long_to_bytes(order, 24) - - ec_p192_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p192_context.address_of(), - c_uint8_ptr(p192_modulus), - c_uint8_ptr(p192_b), - c_uint8_ptr(p192_order), - c_size_t(len(p192_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-192 context" % result) - - context = SmartPointer(ec_p192_context.get(), _ec_lib.ec_ws_free_context) - p192 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 192, - "1.2.840.10045.3.1.1", # ANSI X9.62 / SEC2 - context, - "NIST P-192", - "ecdsa-sha2-nistp192", - EcLib) - return p192 - - -def p224_curve(): - p = 0xffffffffffffffffffffffffffffffff000000000000000000000001 - b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4 - order = 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d - Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21 - Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34 - - p224_modulus = long_to_bytes(p, 28) - p224_b = long_to_bytes(b, 28) - p224_order = long_to_bytes(order, 28) - - ec_p224_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p224_context.address_of(), - c_uint8_ptr(p224_modulus), - c_uint8_ptr(p224_b), - c_uint8_ptr(p224_order), - c_size_t(len(p224_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-224 context" % result) - - context = SmartPointer(ec_p224_context.get(), _ec_lib.ec_ws_free_context) - p224 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 224, - "1.3.132.0.33", # SEC 2 - context, - "NIST P-224", - "ecdsa-sha2-nistp224", - EcLib) - return p224 - - -def p256_curve(): - p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff - b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b - order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 - Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 - Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 - - p256_modulus = long_to_bytes(p, 32) - p256_b = long_to_bytes(b, 32) - p256_order = long_to_bytes(order, 32) - - ec_p256_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p256_context.address_of(), - c_uint8_ptr(p256_modulus), - c_uint8_ptr(p256_b), - c_uint8_ptr(p256_order), - c_size_t(len(p256_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-256 context" % result) - - context = SmartPointer(ec_p256_context.get(), _ec_lib.ec_ws_free_context) - p256 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 256, - "1.2.840.10045.3.1.7", # ANSI X9.62 / SEC2 - context, - "NIST P-256", - "ecdsa-sha2-nistp256", - EcLib) - return p256 - - -def p384_curve(): - p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff - b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef - order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973 - Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7 - Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F - - p384_modulus = long_to_bytes(p, 48) - p384_b = long_to_bytes(b, 48) - p384_order = long_to_bytes(order, 48) - - ec_p384_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p384_context.address_of(), - c_uint8_ptr(p384_modulus), - c_uint8_ptr(p384_b), - c_uint8_ptr(p384_order), - c_size_t(len(p384_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-384 context" % result) - - context = SmartPointer(ec_p384_context.get(), _ec_lib.ec_ws_free_context) - p384 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 384, - "1.3.132.0.34", # SEC 2 - context, - "NIST P-384", - "ecdsa-sha2-nistp384", - EcLib) - return p384 - - -def p521_curve(): - p = 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - b = 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00 - order = 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409 - Gx = 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66 - Gy = 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650 - - p521_modulus = long_to_bytes(p, 66) - p521_b = long_to_bytes(b, 66) - p521_order = long_to_bytes(order, 66) - - ec_p521_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p521_context.address_of(), - c_uint8_ptr(p521_modulus), - c_uint8_ptr(p521_b), - c_uint8_ptr(p521_order), - c_size_t(len(p521_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-521 context" % result) - - context = SmartPointer(ec_p521_context.get(), _ec_lib.ec_ws_free_context) - p521 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 521, - "1.3.132.0.35", # SEC 2 - context, - "NIST P-521", - "ecdsa-sha2-nistp521", - EcLib) - return p521 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.py deleted file mode 100644 index 88dacfc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.py +++ /dev/null @@ -1,135 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2019, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import struct - -from Crypto.Cipher import AES -from Crypto.Hash import SHA512 -from Crypto.Protocol.KDF import _bcrypt_hash -from Crypto.Util.strxor import strxor -from Crypto.Util.py3compat import tostr, bchr, bord - - -def read_int4(data): - if len(data) < 4: - raise ValueError("Insufficient data") - value = struct.unpack(">I", data[:4])[0] - return value, data[4:] - - -def read_bytes(data): - size, data = read_int4(data) - if len(data) < size: - raise ValueError("Insufficient data (V)") - return data[:size], data[size:] - - -def read_string(data): - s, d = read_bytes(data) - return tostr(s), d - - -def check_padding(pad): - for v, x in enumerate(pad): - if bord(x) != ((v + 1) & 0xFF): - raise ValueError("Incorrect padding") - - -def import_openssh_private_generic(data, password): - # https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD - # https://github.com/openssh/openssh-portable/blob/master/sshkey.c - # https://coolaj86.com/articles/the-openssh-private-key-format/ - # https://coolaj86.com/articles/the-ssh-public-key-format/ - - if not data.startswith(b'openssh-key-v1\x00'): - raise ValueError("Incorrect magic value") - data = data[15:] - - ciphername, data = read_string(data) - kdfname, data = read_string(data) - kdfoptions, data = read_bytes(data) - number_of_keys, data = read_int4(data) - - if number_of_keys != 1: - raise ValueError("We only handle 1 key at a time") - - _, data = read_string(data) # Public key - encrypted, data = read_bytes(data) - if data: - raise ValueError("Too much data") - - if len(encrypted) % 8 != 0: - raise ValueError("Incorrect payload length") - - # Decrypt if necessary - if ciphername == 'none': - decrypted = encrypted - else: - if (ciphername, kdfname) != ('aes256-ctr', 'bcrypt'): - raise ValueError("Unsupported encryption scheme %s/%s" % (ciphername, kdfname)) - - salt, kdfoptions = read_bytes(kdfoptions) - iterations, kdfoptions = read_int4(kdfoptions) - - if len(salt) != 16: - raise ValueError("Incorrect salt length") - if kdfoptions: - raise ValueError("Too much data in kdfoptions") - - pwd_sha512 = SHA512.new(password).digest() - # We need 32+16 = 48 bytes, therefore 2 bcrypt outputs are sufficient - stripes = [] - constant = b"OxychromaticBlowfishSwatDynamite" - for count in range(1, 3): - salt_sha512 = SHA512.new(salt + struct.pack(">I", count)).digest() - out_le = _bcrypt_hash(pwd_sha512, 6, salt_sha512, constant, False) - out = struct.pack("IIIIIIII", out_le)) - acc = bytearray(out) - for _ in range(1, iterations): - out_le = _bcrypt_hash(pwd_sha512, 6, SHA512.new(out).digest(), constant, False) - out = struct.pack("IIIIIIII", out_le)) - strxor(acc, out, output=acc) - stripes.append(acc[:24]) - - result = b"".join([bchr(a)+bchr(b) for (a, b) in zip(*stripes)]) - - cipher = AES.new(result[:32], - AES.MODE_CTR, - nonce=b"", - initial_value=result[32:32+16]) - decrypted = cipher.decrypt(encrypted) - - checkint1, decrypted = read_int4(decrypted) - checkint2, decrypted = read_int4(decrypted) - if checkint1 != checkint2: - raise ValueError("Incorrect checksum") - ssh_name, decrypted = read_string(decrypted) - - return ssh_name, decrypted diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.pyi deleted file mode 100644 index 15f3677..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_openssh.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Tuple - -def read_int4(data: bytes) -> Tuple[int, bytes]: ... -def read_bytes(data: bytes) -> Tuple[bytes, bytes]: ... -def read_string(data: bytes) -> Tuple[str, bytes]: ... -def check_padding(pad: bytes) -> None: ... -def import_openssh_private_generic(data: bytes, password: bytes) -> Tuple[str, bytes]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.py b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.py deleted file mode 100644 index ecaecd2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.py +++ /dev/null @@ -1,493 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -import threading - -from Crypto.Util.number import bytes_to_long, long_to_bytes -from Crypto.Util._raw_api import (VoidPointer, null_pointer, - SmartPointer, c_size_t, c_uint8_ptr, - c_ulonglong) -from Crypto.Math.Numbers import Integer -from Crypto.Random.random import getrandbits - - -class CurveID(object): - P192 = 1 - P224 = 2 - P256 = 3 - P384 = 4 - P521 = 5 - ED25519 = 6 - ED448 = 7 - CURVE25519 = 8 - CURVE448 = 9 - - -class _Curves(object): - - curves = {} - curves_lock = threading.RLock() - - p192_names = ["p192", "NIST P-192", "P-192", "prime192v1", "secp192r1", - "nistp192"] - p224_names = ["p224", "NIST P-224", "P-224", "prime224v1", "secp224r1", - "nistp224"] - p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1", - "nistp256"] - p384_names = ["p384", "NIST P-384", "P-384", "prime384v1", "secp384r1", - "nistp384"] - p521_names = ["p521", "NIST P-521", "P-521", "prime521v1", "secp521r1", - "nistp521"] - ed25519_names = ["ed25519", "Ed25519"] - ed448_names = ["ed448", "Ed448"] - curve25519_names = ["curve25519", "Curve25519", "X25519"] - curve448_names = ["curve448", "Curve448", "X448"] - - all_names = p192_names + p224_names + p256_names + p384_names + p521_names + \ - ed25519_names + ed448_names + curve25519_names + curve448_names - - def __contains__(self, item): - return item in self.all_names - - def __dir__(self): - return self.all_names - - def load(self, name): - if name in self.p192_names: - from . import _nist_ecc - p192 = _nist_ecc.p192_curve() - p192.id = CurveID.P192 - self.curves.update(dict.fromkeys(self.p192_names, p192)) - elif name in self.p224_names: - from . import _nist_ecc - p224 = _nist_ecc.p224_curve() - p224.id = CurveID.P224 - self.curves.update(dict.fromkeys(self.p224_names, p224)) - elif name in self.p256_names: - from . import _nist_ecc - p256 = _nist_ecc.p256_curve() - p256.id = CurveID.P256 - self.curves.update(dict.fromkeys(self.p256_names, p256)) - elif name in self.p384_names: - from . import _nist_ecc - p384 = _nist_ecc.p384_curve() - p384.id = CurveID.P384 - self.curves.update(dict.fromkeys(self.p384_names, p384)) - elif name in self.p521_names: - from . import _nist_ecc - p521 = _nist_ecc.p521_curve() - p521.id = CurveID.P521 - self.curves.update(dict.fromkeys(self.p521_names, p521)) - elif name in self.ed25519_names: - from . import _edwards - ed25519 = _edwards.ed25519_curve() - ed25519.id = CurveID.ED25519 - self.curves.update(dict.fromkeys(self.ed25519_names, ed25519)) - elif name in self.ed448_names: - from . import _edwards - ed448 = _edwards.ed448_curve() - ed448.id = CurveID.ED448 - self.curves.update(dict.fromkeys(self.ed448_names, ed448)) - elif name in self.curve25519_names: - from . import _montgomery - curve25519 = _montgomery.curve25519_curve() - curve25519.id = CurveID.CURVE25519 - self.curves.update(dict.fromkeys(self.curve25519_names, curve25519)) - elif name in self.curve448_names: - from . import _montgomery - curve448 = _montgomery.curve448_curve() - curve448.id = CurveID.CURVE448 - self.curves.update(dict.fromkeys(self.curve448_names, curve448)) - else: - raise ValueError("Unsupported curve '%s'" % name) - return self.curves[name] - - def __getitem__(self, name): - with self.curves_lock: - curve = self.curves.get(name) - if curve is None: - curve = self.load(name) - if name in self.curve25519_names or name in self.curve448_names: - curve.G = EccXPoint(curve.Gx, name) - else: - curve.G = EccPoint(curve.Gx, curve.Gy, name) - curve.is_edwards = curve.id in (CurveID.ED25519, CurveID.ED448) - curve.is_montgomery = curve.id in (CurveID.CURVE25519, - CurveID.CURVE448) - curve.is_weierstrass = not (curve.is_edwards or - curve.is_montgomery) - return curve - - def items(self): - # Load all curves - for name in self.all_names: - _ = self[name] - return self.curves.items() - - -_curves = _Curves() - - -class EccPoint(object): - """A class to model a point on an Elliptic Curve. - - The class supports operators for: - - * Adding two points: ``R = S + T`` - * In-place addition: ``S += T`` - * Negating a point: ``R = -T`` - * Comparing two points: ``if S == T: ...`` or ``if S != T: ...`` - * Multiplying a point by a scalar: ``R = S*k`` - * In-place multiplication by a scalar: ``T *= k`` - - :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. - :vartype curve: string - - :ivar x: The affine X-coordinate of the ECC point - :vartype x: integer - - :ivar y: The affine Y-coordinate of the ECC point - :vartype y: integer - - :ivar xy: The tuple with affine X- and Y- coordinates - """ - - def __init__(self, x, y, curve="p256"): - - try: - self._curve = _curves[curve] - except KeyError: - raise ValueError("Unknown curve name %s" % str(curve)) - self.curve = self._curve.canonical - - if self._curve.id == CurveID.CURVE25519: - raise ValueError("EccPoint cannot be created for Curve25519") - - modulus_bytes = self.size_in_bytes() - - xb = long_to_bytes(x, modulus_bytes) - yb = long_to_bytes(y, modulus_bytes) - if len(xb) != modulus_bytes or len(yb) != modulus_bytes: - raise ValueError("Incorrect coordinate length") - - new_point = self._curve.rawlib.new_point - free_func = self._curve.rawlib.free_point - - self._point = VoidPointer() - try: - context = self._curve.context.get() - except AttributeError: - context = null_pointer - result = new_point(self._point.address_of(), - c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - context) - - if result: - if result == 15: - raise ValueError("The EC point does not belong to the curve") - raise ValueError("Error %d while instantiating an EC point" % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the EC point - self._point = SmartPointer(self._point.get(), free_func) - - def set(self, point): - clone = self._curve.rawlib.clone - free_func = self._curve.rawlib.free_point - - self._point = VoidPointer() - result = clone(self._point.address_of(), - point._point.get()) - - if result: - raise ValueError("Error %d while cloning an EC point" % result) - - self._point = SmartPointer(self._point.get(), free_func) - return self - - def __eq__(self, point): - if not isinstance(point, EccPoint): - return False - - cmp_func = self._curve.rawlib.cmp - return 0 == cmp_func(self._point.get(), point._point.get()) - - # Only needed for Python 2 - def __ne__(self, point): - return not self == point - - def __neg__(self): - neg_func = self._curve.rawlib.neg - np = self.copy() - result = neg_func(np._point.get()) - if result: - raise ValueError("Error %d while inverting an EC point" % result) - return np - - def copy(self): - """Return a copy of this point.""" - x, y = self.xy - np = EccPoint(x, y, self.curve) - return np - - def is_point_at_infinity(self): - """``True`` if this is the *point-at-infinity*.""" - - if self._curve.is_edwards: - return self.x == 0 - else: - return self.xy == (0, 0) - - def point_at_infinity(self): - """Return the *point-at-infinity* for the curve.""" - - if self._curve.is_edwards: - return EccPoint(0, 1, self.curve) - else: - return EccPoint(0, 0, self.curve) - - @property - def x(self): - return self.xy[0] - - @property - def y(self): - return self.xy[1] - - @property - def xy(self): - modulus_bytes = self.size_in_bytes() - xb = bytearray(modulus_bytes) - yb = bytearray(modulus_bytes) - get_xy = self._curve.rawlib.get_xy - result = get_xy(c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - self._point.get()) - if result: - raise ValueError("Error %d while encoding an EC point" % result) - - return (Integer(bytes_to_long(xb)), Integer(bytes_to_long(yb))) - - def size_in_bytes(self): - """Size of each coordinate, in bytes.""" - return (self.size_in_bits() + 7) // 8 - - def size_in_bits(self): - """Size of each coordinate, in bits.""" - return self._curve.modulus_bits - - def double(self): - """Double this point (in-place operation). - - Returns: - This same object (to enable chaining). - """ - - double_func = self._curve.rawlib.double - result = double_func(self._point.get()) - if result: - raise ValueError("Error %d while doubling an EC point" % result) - return self - - def __iadd__(self, point): - """Add a second point to this one""" - - add_func = self._curve.rawlib.add - result = add_func(self._point.get(), point._point.get()) - if result: - if result == 16: - raise ValueError("EC points are not on the same curve") - raise ValueError("Error %d while adding two EC points" % result) - return self - - def __add__(self, point): - """Return a new point, the addition of this one and another""" - - np = self.copy() - np += point - return np - - def __imul__(self, scalar): - """Multiply this point by a scalar""" - - scalar_func = self._curve.rawlib.scalar - if scalar < 0: - raise ValueError("Scalar multiplication is only defined for non-negative integers") - sb = long_to_bytes(scalar) - result = scalar_func(self._point.get(), - c_uint8_ptr(sb), - c_size_t(len(sb)), - c_ulonglong(getrandbits(64))) - if result: - raise ValueError("Error %d during scalar multiplication" % result) - return self - - def __mul__(self, scalar): - """Return a new point, the scalar product of this one""" - - np = self.copy() - np *= scalar - return np - - def __rmul__(self, left_hand): - return self.__mul__(left_hand) - - -class EccXPoint(object): - """A class to model a point on an Elliptic Curve, - where only the X-coordinate is exposed. - - The class supports operators for: - - * Multiplying a point by a scalar: ``R = S*k`` - * In-place multiplication by a scalar: ``T *= k`` - - :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. - :vartype curve: string - - :ivar x: The affine X-coordinate of the ECC point - :vartype x: integer - """ - - def __init__(self, x, curve): - # Once encoded, x must not exceed the length of the modulus, - # but its value may match or exceed the modulus itself - # (i.e., non-canonical value) - - try: - self._curve = _curves[curve] - except KeyError: - raise ValueError("Unknown curve name %s" % str(curve)) - self.curve = self._curve.canonical - - if self._curve.id not in (CurveID.CURVE25519, CurveID.CURVE448): - raise ValueError("EccXPoint can only be created for Curve25519/Curve448") - - new_point = self._curve.rawlib.new_point - free_func = self._curve.rawlib.free_point - - self._point = VoidPointer() - try: - context = self._curve.context.get() - except AttributeError: - context = null_pointer - - modulus_bytes = self.size_in_bytes() - - if x is None: - xb = null_pointer - else: - xb = c_uint8_ptr(long_to_bytes(x, modulus_bytes)) - if len(xb) != modulus_bytes: - raise ValueError("Incorrect coordinate length") - - self._point = VoidPointer() - result = new_point(self._point.address_of(), - xb, - c_size_t(modulus_bytes), - context) - - if result == 15: - raise ValueError("The EC point does not belong to the curve") - if result: - raise ValueError("Error %d while instantiating an EC point" % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the EC point - self._point = SmartPointer(self._point.get(), free_func) - - def set(self, point): - clone = self._curve.rawlib.clone - free_func = self._curve.rawlib.free_point - - self._point = VoidPointer() - result = clone(self._point.address_of(), - point._point.get()) - if result: - raise ValueError("Error %d while cloning an EC point" % result) - - self._point = SmartPointer(self._point.get(), free_func) - return self - - def __eq__(self, point): - if not isinstance(point, EccXPoint): - return False - - cmp_func = self._curve.rawlib.cmp - p1 = self._point.get() - p2 = point._point.get() - res = cmp_func(p1, p2) - return 0 == res - - def copy(self): - """Return a copy of this point.""" - - try: - x = self.x - except ValueError: - return self.point_at_infinity() - return EccXPoint(x, self.curve) - - def is_point_at_infinity(self): - """``True`` if this is the *point-at-infinity*.""" - - try: - _ = self.x - except ValueError: - return True - return False - - def point_at_infinity(self): - """Return the *point-at-infinity* for the curve.""" - - return EccXPoint(None, self.curve) - - @property - def x(self): - modulus_bytes = self.size_in_bytes() - xb = bytearray(modulus_bytes) - get_x = self._curve.rawlib.get_x - result = get_x(c_uint8_ptr(xb), - c_size_t(modulus_bytes), - self._point.get()) - if result == 19: # ERR_ECC_PAI - raise ValueError("No X coordinate for the point at infinity") - if result: - raise ValueError("Error %d while getting X of an EC point" % result) - return Integer(bytes_to_long(xb)) - - def size_in_bytes(self): - """Size of each coordinate, in bytes.""" - return (self.size_in_bits() + 7) // 8 - - def size_in_bits(self): - """Size of each coordinate, in bits.""" - return self._curve.modulus_bits - - def __imul__(self, scalar): - """Multiply this point by a scalar""" - - scalar_func = self._curve.rawlib.scalar - if scalar < 0: - raise ValueError("Scalar multiplication is only defined for non-negative integers") - sb = long_to_bytes(scalar) - result = scalar_func(self._point.get(), - c_uint8_ptr(sb), - c_size_t(len(sb)), - c_ulonglong(getrandbits(64))) - if result: - raise ValueError("Error %d during scalar multiplication" % result) - return self - - def __mul__(self, scalar): - """Return a new point, the scalar product of this one""" - - np = self.copy() - np *= scalar - return np - - def __rmul__(self, left_hand): - return self.__mul__(left_hand) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.pyi deleted file mode 100644 index 83f9c3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/PublicKey/_point.pyi +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Union, Optional, Tuple - -from Crypto.Math.Numbers import Integer - -class EccPoint(object): - curve: str - def __init__(self, - x: Union[int, Integer], - y: Union[int, Integer], - curve: Optional[str] = ...) -> None: ... - - def set(self, point: EccPoint) -> EccPoint: ... - def __eq__(self, point: object) -> bool: ... - def __neg__(self) -> EccPoint: ... - def copy(self) -> EccPoint: ... - def is_point_at_infinity(self) -> bool: ... - def point_at_infinity(self) -> EccPoint: ... - @property - def x(self) -> int: ... - @property - def y(self) -> int: ... - @property - def xy(self) -> Tuple[int, int]: ... - def size_in_bytes(self) -> int: ... - def size_in_bits(self) -> int: ... - def double(self) -> EccPoint: ... - def __iadd__(self, point: EccPoint) -> EccPoint: ... - def __add__(self, point: EccPoint) -> EccPoint: ... - def __imul__(self, scalar: int) -> EccPoint: ... - def __mul__(self, scalar: int) -> EccPoint: ... - - -class EccXPoint(object): - curve: str - def __init__(self, - x: Union[int, Integer], - curve: Optional[str] = ...) -> None: ... - def set(self, point: EccXPoint) -> EccXPoint: ... - def __eq__(self, point: object) -> bool: ... - def copy(self) -> EccXPoint: ... - def is_point_at_infinity(self) -> bool: ... - def point_at_infinity(self) -> EccXPoint: ... - @property - def x(self) -> int: ... - def size_in_bytes(self) -> int: ... - def size_in_bits(self) -> int: ... - def __imul__(self, scalar: int) -> EccXPoint: ... - def __mul__(self, scalar: int) -> EccXPoint: ... - def __rmul__(self, left_hand: int) -> EccXPoint: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.py deleted file mode 100644 index 0f83a07..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Random/__init__.py : PyCrypto random number generation -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['new', 'get_random_bytes'] - -from os import urandom - -class _UrandomRNG(object): - - def read(self, n): - """Return a random byte string of the desired size.""" - return urandom(n) - - def flush(self): - """Method provided for backward compatibility only.""" - pass - - def reinit(self): - """Method provided for backward compatibility only.""" - pass - - def close(self): - """Method provided for backward compatibility only.""" - pass - - -def new(*args, **kwargs): - """Return a file-like object that outputs cryptographically random bytes.""" - return _UrandomRNG() - - -def atfork(): - pass - - -#: Function that returns a random byte string of the desired size. -get_random_bytes = urandom - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.pyi deleted file mode 100644 index ddc5b9b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/__init__.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Any - -__all__ = ['new', 'get_random_bytes'] - -from os import urandom - -class _UrandomRNG(object): - - def read(self, n: int) -> bytes:... - def flush(self) -> None: ... - def reinit(self) -> None: ... - def close(self) -> None: ... - -def new(*args: Any, **kwargs: Any) -> _UrandomRNG: ... - -def atfork() -> None: ... - -get_random_bytes = urandom - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.py deleted file mode 100644 index 5389b3b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Random/random.py : Strong alternative for the standard 'random' module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] - -from Crypto import Random - -from Crypto.Util.py3compat import is_native_int - -class StrongRandom(object): - def __init__(self, rng=None, randfunc=None): - if randfunc is None and rng is None: - self._randfunc = None - elif randfunc is not None and rng is None: - self._randfunc = randfunc - elif randfunc is None and rng is not None: - self._randfunc = rng.read - else: - raise ValueError("Cannot specify both 'rng' and 'randfunc'") - - def getrandbits(self, k): - """Return an integer with k random bits.""" - - if self._randfunc is None: - self._randfunc = Random.new().read - mask = (1 << k) - 1 - return mask & bytes_to_long(self._randfunc(ceil_div(k, 8))) - - def randrange(self, *args): - """randrange([start,] stop[, step]): - Return a randomly-selected element from range(start, stop, step).""" - if len(args) == 3: - (start, stop, step) = args - elif len(args) == 2: - (start, stop) = args - step = 1 - elif len(args) == 1: - (stop,) = args - start = 0 - step = 1 - else: - raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),)) - if (not is_native_int(start) or not is_native_int(stop) or not - is_native_int(step)): - raise TypeError("randrange requires integer arguments") - if step == 0: - raise ValueError("randrange step argument must not be zero") - - num_choices = ceil_div(stop - start, step) - if num_choices < 0: - num_choices = 0 - if num_choices < 1: - raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) - - # Pick a random number in the range of possible numbers - r = num_choices - while r >= num_choices: - r = self.getrandbits(size(num_choices)) - - return start + (step * r) - - def randint(self, a, b): - """Return a random integer N such that a <= N <= b.""" - if not is_native_int(a) or not is_native_int(b): - raise TypeError("randint requires integer arguments") - N = self.randrange(a, b+1) - assert a <= N <= b - return N - - def choice(self, seq): - """Return a random element from a (non-empty) sequence. - - If the seqence is empty, raises IndexError. - """ - if len(seq) == 0: - raise IndexError("empty sequence") - return seq[self.randrange(len(seq))] - - def shuffle(self, x): - """Shuffle the sequence in place.""" - # Fisher-Yates shuffle. O(n) - # See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - # Working backwards from the end of the array, we choose a random item - # from the remaining items until all items have been chosen. - for i in range(len(x)-1, 0, -1): # iterate from len(x)-1 downto 1 - j = self.randrange(0, i+1) # choose random j such that 0 <= j <= i - x[i], x[j] = x[j], x[i] # exchange x[i] and x[j] - - def sample(self, population, k): - """Return a k-length list of unique elements chosen from the population sequence.""" - - num_choices = len(population) - if k > num_choices: - raise ValueError("sample larger than population") - - retval = [] - selected = {} # we emulate a set using a dict here - for i in range(k): - r = None - while r is None or r in selected: - r = self.randrange(num_choices) - retval.append(population[r]) - selected[r] = 1 - return retval - -_r = StrongRandom() -getrandbits = _r.getrandbits -randrange = _r.randrange -randint = _r.randint -choice = _r.choice -shuffle = _r.shuffle -sample = _r.sample - -# These are at the bottom to avoid problems with recursive imports -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes, size - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.pyi deleted file mode 100644 index 9b7cf7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Random/random.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Callable, Tuple, Union, Sequence, Any, Optional, TypeVar - -__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] - -T = TypeVar('T') - -class StrongRandom(object): - def __init__(self, rng: Optional[Any]=None, randfunc: Optional[Callable]=None) -> None: ... # TODO What is rng? - def getrandbits(self, k: int) -> int: ... - def randrange(self, start: int, stop: int = ..., step: int = ...) -> int: ... - def randint(self, a: int, b: int) -> int: ... - def choice(self, seq: Sequence[T]) -> T: ... - def shuffle(self, x: Sequence) -> None: ... - def sample(self, population: Sequence, k: int) -> list: ... - -_r = StrongRandom() -getrandbits = _r.getrandbits -randrange = _r.randrange -randint = _r.randint -choice = _r.choice -shuffle = _r.shuffle -sample = _r.sample diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/__init__.py deleted file mode 100644 index 5cc75db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/__init__.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/__init__.py: Self-test for cipher modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for cipher modules""" - -import sys - - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Cipher import test_AES; tests += test_AES.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ARC2; tests += test_ARC2.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ARC4; tests += test_ARC4.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_Blowfish; tests += test_Blowfish.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CAST; tests += test_CAST.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_DES3; tests += test_DES3.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_DES; tests += test_DES.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_Salsa20; tests += test_Salsa20.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ChaCha20; tests += test_ChaCha20.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ChaCha20_Poly1305; tests += test_ChaCha20_Poly1305.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_pkcs1_oaep; tests += test_pkcs1_oaep.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OCB; tests += test_OCB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CBC; tests += test_CBC.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CFB; tests += test_CFB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OpenPGP; tests += test_OpenPGP.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OFB; tests += test_OFB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CTR; tests += test_CTR.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CCM; tests += test_CCM.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_EAX; tests += test_EAX.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_GCM; tests += test_GCM.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_SIV; tests += test_SIV.get_tests(config=config) - - if sys.version_info >= (3, 9): - from Crypto.SelfTest.Cipher import test_KW - tests += test_KW.get_tests(config=config) - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/common.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/common.py deleted file mode 100644 index c5bc755..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/common.py +++ /dev/null @@ -1,510 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/common.py: Common code for Crypto.SelfTest.Hash -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-testing for PyCrypto hash modules""" - -import unittest -from binascii import a2b_hex, b2a_hex, hexlify - -from Crypto.Util.py3compat import b -from Crypto.Util.strxor import strxor_c - -class _NoDefault: pass # sentinel object -def _extract(d, k, default=_NoDefault): - """Get an item from a dictionary, and remove it from the dictionary.""" - try: - retval = d[k] - except KeyError: - if default is _NoDefault: - raise - return default - del d[k] - return retval - -# Generic cipher test case -class CipherSelfTest(unittest.TestCase): - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def shortDescription(self): - return self.description - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def isMode(self, name): - if not hasattr(self.module, "MODE_"+name): - return False - return self.mode == getattr(self.module, "MODE_"+name) - - def runTest(self): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ a2b_hex(b(x)) for x in self.assoc_data] - - ct = None - pt = None - - # - # Repeat the same encryption or decryption twice and verify - # that the result is always the same - # - for i in range(2): - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ctX = b2a_hex(cipher.encrypt(plaintext)) - ptX = b2a_hex(decipher.decrypt(ciphertext)) - - if ct: - self.assertEqual(ct, ctX) - self.assertEqual(pt, ptX) - ct, pt = ctX, ptX - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(a2b_hex(self.mac)) - -class CipherStreamingSelfTest(CipherSelfTest): - - def shortDescription(self): - desc = self.module_name - if self.mode is not None: - desc += " in %s mode" % (self.mode_name,) - return "%s should behave like a stream cipher" % (desc,) - - def runTest(self): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - - # The cipher should work like a stream cipher - - # Test counter mode encryption, 3 bytes at a time - ct3 = [] - cipher = self._new() - for i in range(0, len(plaintext), 3): - ct3.append(cipher.encrypt(plaintext[i:i+3])) - ct3 = b2a_hex(b("").join(ct3)) - self.assertEqual(self.ciphertext, ct3) # encryption (3 bytes at a time) - - # Test counter mode decryption, 3 bytes at a time - pt3 = [] - cipher = self._new() - for i in range(0, len(ciphertext), 3): - pt3.append(cipher.encrypt(ciphertext[i:i+3])) - # PY3K: This is meant to be text, do not change to bytes (data) - pt3 = b2a_hex(b("").join(pt3)) - self.assertEqual(self.plaintext, pt3) # decryption (3 bytes at a time) - - -class RoundtripTest(unittest.TestCase): - def __init__(self, module, params): - from Crypto import Random - unittest.TestCase.__init__(self) - self.module = module - self.iv = Random.get_random_bytes(module.block_size) - self.key = b(params['key']) - self.plaintext = 100 * b(params['plaintext']) - self.module_name = params.get('module_name', None) - - def shortDescription(self): - return """%s .decrypt() output of .encrypt() should not be garbled""" % (self.module_name,) - - def runTest(self): - - ## ECB mode - mode = self.module.MODE_ECB - encryption_cipher = self.module.new(a2b_hex(self.key), mode) - ciphertext = encryption_cipher.encrypt(self.plaintext) - decryption_cipher = self.module.new(a2b_hex(self.key), mode) - decrypted_plaintext = decryption_cipher.decrypt(ciphertext) - self.assertEqual(self.plaintext, decrypted_plaintext) - - -class IVLengthTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = b(params['key']) - - def shortDescription(self): - return "Check that all modes except MODE_ECB and MODE_CTR require an IV of the proper length" - - def runTest(self): - self.assertRaises(TypeError, self.module.new, a2b_hex(self.key), - self.module.MODE_ECB, b("")) - - def _dummy_counter(self): - return "\0" * self.module.block_size - - -class NoDefaultECBTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = b(params['key']) - - def runTest(self): - self.assertRaises(TypeError, self.module.new, a2b_hex(self.key)) - - -class BlockSizeTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = a2b_hex(b(params['key'])) - - def runTest(self): - cipher = self.module.new(self.key, self.module.MODE_ECB) - self.assertEqual(cipher.block_size, self.module.block_size) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can use bytearray's for encrypting and decrypting""" - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def runTest(self): - - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ bytearray(a2b_hex(b(x))) for x in self.assoc_data] - - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ct = b2a_hex(cipher.encrypt(bytearray(plaintext))) - pt = b2a_hex(decipher.decrypt(bytearray(ciphertext))) - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(bytearray(a2b_hex(self.mac))) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can use memoryviews for encrypting and decrypting""" - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def runTest(self): - - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ memoryview(a2b_hex(b(x))) for x in self.assoc_data] - - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ct = b2a_hex(cipher.encrypt(memoryview(plaintext))) - pt = b2a_hex(decipher.decrypt(memoryview(ciphertext))) - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(memoryview(a2b_hex(self.mac))) - - -def make_block_tests(module, module_name, test_data, additional_params=dict()): - tests = [] - extra_tests_added = False - for i in range(len(test_data)): - row = test_data[i] - - # Build the "params" dictionary with - # - plaintext - # - ciphertext - # - key - # - mode (default is ECB) - # - (optionally) description - # - (optionally) any other parameter that this cipher mode requires - params = {} - if len(row) == 3: - (params['plaintext'], params['ciphertext'], params['key']) = row - elif len(row) == 4: - (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row - elif len(row) == 5: - (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row - params.update(extra_params) - else: - raise AssertionError("Unsupported tuple size %d" % (len(row),)) - - if not "mode" in params: - params["mode"] = "ECB" - - # Build the display-name for the test - p2 = params.copy() - p_key = _extract(p2, 'key') - p_plaintext = _extract(p2, 'plaintext') - p_ciphertext = _extract(p2, 'ciphertext') - p_mode = _extract(p2, 'mode') - p_description = _extract(p2, 'description', None) - - if p_description is not None: - description = p_description - elif p_mode == 'ECB' and not p2: - description = "p=%s, k=%s" % (p_plaintext, p_key) - else: - description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) - name = "%s #%d: %s" % (module_name, i+1, description) - params['description'] = name - params['module_name'] = module_name - params.update(additional_params) - - # Add extra test(s) to the test suite before the current test - if not extra_tests_added: - tests += [ - RoundtripTest(module, params), - IVLengthTest(module, params), - NoDefaultECBTest(module, params), - ByteArrayTest(module, params), - BlockSizeTest(module, params), - ] - extra_tests_added = True - - # Add the current test to the test suite - tests.append(CipherSelfTest(module, params)) - - return tests - -def make_stream_tests(module, module_name, test_data): - tests = [] - extra_tests_added = False - for i in range(len(test_data)): - row = test_data[i] - - # Build the "params" dictionary - params = {} - if len(row) == 3: - (params['plaintext'], params['ciphertext'], params['key']) = row - elif len(row) == 4: - (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row - elif len(row) == 5: - (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row - params.update(extra_params) - else: - raise AssertionError("Unsupported tuple size %d" % (len(row),)) - - # Build the display-name for the test - p2 = params.copy() - p_key = _extract(p2, 'key') - p_plaintext = _extract(p2, 'plaintext') - p_ciphertext = _extract(p2, 'ciphertext') - p_description = _extract(p2, 'description', None) - - if p_description is not None: - description = p_description - elif not p2: - description = "p=%s, k=%s" % (p_plaintext, p_key) - else: - description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) - name = "%s #%d: %s" % (module_name, i+1, description) - params['description'] = name - params['module_name'] = module_name - - # Add extra test(s) to the test suite before the current test - if not extra_tests_added: - tests += [ - ByteArrayTest(module, params), - ] - - tests.append(MemoryviewTest(module, params)) - extra_tests_added = True - - # Add the test to the test suite - tests.append(CipherSelfTest(module, params)) - tests.append(CipherStreamingSelfTest(module, params)) - return tests - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_AES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_AES.py deleted file mode 100644 index 116deec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_AES.py +++ /dev/null @@ -1,1351 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/AES.py: Self-test for the AES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.AES""" - -from __future__ import print_function - -import unittest -from Crypto.Hash import SHA256 -from Crypto.Cipher import AES -from Crypto.Util.py3compat import * -from binascii import hexlify - -# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples. -test_data = [ - # FIPS PUB 197 test vectors - # http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - - ('00112233445566778899aabbccddeeff', '69c4e0d86a7b0430d8cdb78070b4c55a', - '000102030405060708090a0b0c0d0e0f', 'FIPS 197 C.1 (AES-128)'), - - ('00112233445566778899aabbccddeeff', 'dda97ca4864cdfe06eaf70a0ec0d7191', - '000102030405060708090a0b0c0d0e0f1011121314151617', - 'FIPS 197 C.2 (AES-192)'), - - ('00112233445566778899aabbccddeeff', '8ea2b7ca516745bfeafc49904b496089', - '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'FIPS 197 C.3 (AES-256)'), - - # Rijndael128 test vectors - # Downloaded 2008-09-13 from - # http://www.iaik.tugraz.at/Research/krypto/AES/old/~rijmen/rijndael/testvalues.tar.gz - - # ecb_tbl.txt, KEYSIZE=128 - ('506812a45f08c889b97f5980038b8359', 'd8f532538289ef7d06b506a4fd5be9c9', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=1'), - ('5c6d71ca30de8b8b00549984d2ec7d4b', '59ab30f4d4ee6e4ff9907ef65b1fb68c', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=2'), - ('53f3f4c64f8616e4e7c56199f48f21f6', 'bf1ed2fcb2af3fd41443b56d85025cb1', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=3'), - ('a1eb65a3487165fb0f1c27ff9959f703', '7316632d5c32233edcb0780560eae8b2', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=4'), - ('3553ecf0b1739558b08e350a98a39bfa', '408c073e3e2538072b72625e68b8364b', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=5'), - ('67429969490b9711ae2b01dc497afde8', 'e1f94dfa776597beaca262f2f6366fea', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=6'), - ('93385c1f2aec8bed192f5a8e161dd508', 'f29e986c6a1c27d7b29ffd7ee92b75f1', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=7'), - ('b5bf946be19beb8db3983b5f4c6e8ddb', '131c886a57f8c2e713aba6955e2b55b5', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=8'), - ('41321ee10e21bd907227c4450ff42324', 'd2ab7662df9b8c740210e5eeb61c199d', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=9'), - ('00a82f59c91c8486d12c0a80124f6089', '14c10554b2859c484cab5869bbe7c470', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-128: I=10'), - ('7ce0fd076754691b4bbd9faf8a1372fe', 'db4d498f0a49cf55445d502c1f9ab3b5', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-128: I=11'), - ('23605a8243d07764541bc5ad355b3129', '6d96fef7d66590a77a77bb2056667f7f', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-128: I=12'), - ('12a8cfa23ea764fd876232b4e842bc44', '316fb68edba736c53e78477bf913725c', - 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-128: I=13'), - ('bcaf32415e8308b3723e5fdd853ccc80', '6936f2b93af8397fd3a771fc011c8c37', - '04050607090a0b0c0e0f101113141516', - 'ecb-tbl-128: I=14'), - ('89afae685d801ad747ace91fc49adde0', 'f3f92f7a9c59179c1fcc2c2ba0b082cd', - '2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-128: I=15'), - ('f521d07b484357c4a69e76124a634216', '6a95ea659ee3889158e7a9152ff04ebc', - '40414243454647484a4b4c4d4f505152', - 'ecb-tbl-128: I=16'), - ('3e23b3bc065bcc152407e23896d77783', '1959338344e945670678a5d432c90b93', - '54555657595a5b5c5e5f606163646566', - 'ecb-tbl-128: I=17'), - ('79f0fba002be1744670e7e99290d8f52', 'e49bddd2369b83ee66e6c75a1161b394', - '68696a6b6d6e6f70727374757778797a', - 'ecb-tbl-128: I=18'), - ('da23fe9d5bd63e1d72e3dafbe21a6c2a', 'd3388f19057ff704b70784164a74867d', - '7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-128: I=19'), - ('e3f5698ba90b6a022efd7db2c7e6c823', '23aa03e2d5e4cd24f3217e596480d1e1', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-128: I=20'), - ('bdc2691d4f1b73d2700679c3bcbf9c6e', 'c84113d68b666ab2a50a8bdb222e91b9', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-128: I=21'), - ('ba74e02093217ee1ba1b42bd5624349a', 'ac02403981cd4340b507963db65cb7b6', - '08090a0b0d0e0f10121314151718191a', - 'ecb-tbl-128: I=22'), - ('b5c593b5851c57fbf8b3f57715e8f680', '8d1299236223359474011f6bf5088414', - '6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-128: I=23'), - ('3da9bd9cec072381788f9387c3bbf4ee', '5a1d6ab8605505f7977e55b9a54d9b90', - '80818283858687888a8b8c8d8f909192', - 'ecb-tbl-128: I=24'), - ('4197f3051121702ab65d316b3c637374', '72e9c2d519cf555e4208805aabe3b258', - '94959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-128: I=25'), - ('9f46c62ec4f6ee3f6e8c62554bc48ab7', 'a8f3e81c4a23a39ef4d745dffe026e80', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-128: I=26'), - ('0220673fe9e699a4ebc8e0dbeb6979c8', '546f646449d31458f9eb4ef5483aee6c', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-128: I=27'), - ('b2b99171337ded9bc8c2c23ff6f18867', '4dbe4bc84ac797c0ee4efb7f1a07401c', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-128: I=28'), - ('a7facf4e301e984e5efeefd645b23505', '25e10bfb411bbd4d625ac8795c8ca3b3', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-128: I=29'), - ('f7c762e4a9819160fd7acfb6c4eedcdd', '315637405054ec803614e43def177579', - 'f8f9fafbfdfefe00020304050708090a', - 'ecb-tbl-128: I=30'), - ('9b64fc21ea08709f4915436faa70f1be', '60c5bc8a1410247295c6386c59e572a8', - '0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-128: I=31'), - ('52af2c3de07ee6777f55a4abfc100b3f', '01366fc8ca52dfe055d6a00a76471ba6', - '20212223252627282a2b2c2d2f303132', - 'ecb-tbl-128: I=32'), - ('2fca001224386c57aa3f968cbe2c816f', 'ecc46595516ec612449c3f581e7d42ff', - '34353637393a3b3c3e3f404143444546', - 'ecb-tbl-128: I=33'), - ('4149c73658a4a9c564342755ee2c132f', '6b7ffe4c602a154b06ee9c7dab5331c9', - '48494a4b4d4e4f50525354555758595a', - 'ecb-tbl-128: I=34'), - ('af60005a00a1772f7c07a48a923c23d2', '7da234c14039a240dd02dd0fbf84eb67', - '5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-128: I=35'), - ('6fccbc28363759914b6f0280afaf20c6', 'c7dc217d9e3604ffe7e91f080ecd5a3a', - '70717273757677787a7b7c7d7f808182', - 'ecb-tbl-128: I=36'), - ('7d82a43ddf4fefa2fc5947499884d386', '37785901863f5c81260ea41e7580cda5', - '84858687898a8b8c8e8f909193949596', - 'ecb-tbl-128: I=37'), - ('5d5a990eaab9093afe4ce254dfa49ef9', 'a07b9338e92ed105e6ad720fccce9fe4', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-128: I=38'), - ('4cd1e2fd3f4434b553aae453f0ed1a02', 'ae0fb9722418cc21a7da816bbc61322c', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-128: I=39'), - ('5a2c9a9641d4299125fa1b9363104b5e', 'c826a193080ff91ffb21f71d3373c877', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-128: I=40'), - ('b517fe34c0fa217d341740bfd4fe8dd4', '1181b11b0e494e8d8b0aa6b1d5ac2c48', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-128: I=41'), - ('014baf2278a69d331d5180103643e99a', '6743c3d1519ab4f2cd9a78ab09a511bd', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', - 'ecb-tbl-128: I=42'), - ('b529bd8164f20d0aa443d4932116841c', 'dc55c076d52bacdf2eefd952946a439d', - 'fcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-128: I=43'), - ('2e596dcbb2f33d4216a1176d5bd1e456', '711b17b590ffc72b5c8e342b601e8003', - '10111213151617181a1b1c1d1f202122', - 'ecb-tbl-128: I=44'), - ('7274a1ea2b7ee2424e9a0e4673689143', '19983bb0950783a537e1339f4aa21c75', - '24252627292a2b2c2e2f303133343536', - 'ecb-tbl-128: I=45'), - ('ae20020bd4f13e9d90140bee3b5d26af', '3ba7762e15554169c0f4fa39164c410c', - '38393a3b3d3e3f40424344454748494a', - 'ecb-tbl-128: I=46'), - ('baac065da7ac26e855e79c8849d75a02', 'a0564c41245afca7af8aa2e0e588ea89', - '4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-128: I=47'), - ('7c917d8d1d45fab9e2540e28832540cc', '5e36a42a2e099f54ae85ecd92e2381ed', - '60616263656667686a6b6c6d6f707172', - 'ecb-tbl-128: I=48'), - ('bde6f89e16daadb0e847a2a614566a91', '770036f878cd0f6ca2268172f106f2fe', - '74757677797a7b7c7e7f808183848586', - 'ecb-tbl-128: I=49'), - ('c9de163725f1f5be44ebb1db51d07fbc', '7e4e03908b716116443ccf7c94e7c259', - '88898a8b8d8e8f90929394959798999a', - 'ecb-tbl-128: I=50'), - ('3af57a58f0c07dffa669572b521e2b92', '482735a48c30613a242dd494c7f9185d', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-128: I=51'), - ('3d5ebac306dde4604f1b4fbbbfcdae55', 'b4c0f6c9d4d7079addf9369fc081061d', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-128: I=52'), - ('c2dfa91bceb76a1183c995020ac0b556', 'd5810fe0509ac53edcd74f89962e6270', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-128: I=53'), - ('c70f54305885e9a0746d01ec56c8596b', '03f17a16b3f91848269ecdd38ebb2165', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', - 'ecb-tbl-128: I=54'), - ('c4f81b610e98012ce000182050c0c2b2', 'da1248c3180348bad4a93b4d9856c9df', - 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-128: I=55'), - ('eaab86b1d02a95d7404eff67489f97d4', '3d10d7b63f3452c06cdf6cce18be0c2c', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=56'), - ('7c55bdb40b88870b52bec3738de82886', '4ab823e7477dfddc0e6789018fcb6258', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=57'), - ('ba6eaa88371ff0a3bd875e3f2a975ce0', 'e6478ba56a77e70cfdaa5c843abde30e', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=58'), - ('08059130c4c24bd30cf0575e4e0373dc', '1673064895fbeaf7f09c5429ff75772d', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=59'), - ('9a8eab004ef53093dfcf96f57e7eda82', '4488033ae9f2efd0ca9383bfca1a94e9', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=60'), - ('0745b589e2400c25f117b1d796c28129', '978f3b8c8f9d6f46626cac3c0bcb9217', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=61'), - ('2f1777781216cec3f044f134b1b92bbe', 'e08c8a7e582e15e5527f1d9e2eecb236', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=62'), - ('353a779ffc541b3a3805d90ce17580fc', 'cec155b76ac5ffda4cf4f9ca91e49a7a', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=63'), - ('1a1eae4415cefcf08c4ac1c8f68bea8f', 'd5ac7165763225dd2a38cdc6862c29ad', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=64'), - ('e6e7e4e5b0b3b2b5d4d5aaab16111013', '03680fe19f7ce7275452020be70e8204', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-128: I=65'), - ('f8f9fafbfbf8f9e677767170efe0e1e2', '461df740c9781c388e94bb861ceb54f6', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-128: I=66'), - ('63626160a1a2a3a445444b4a75727370', '451bd60367f96483042742219786a074', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-128: I=67'), - ('717073720605040b2d2c2b2a05fafbf9', 'e4dfa42671a02e57ef173b85c0ea9f2b', - 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-128: I=68'), - ('78797a7beae9e8ef3736292891969794', 'ed11b89e76274282227d854700a78b9e', - '04050607090a0b0c0e0f101113141516', - 'ecb-tbl-128: I=69'), - ('838281803231300fdddcdbdaa0afaead', '433946eaa51ea47af33895f2b90b3b75', - '18191a1b1d1e1f20222324252728292a', - 'ecb-tbl-128: I=70'), - ('18191a1bbfbcbdba75747b7a7f78797a', '6bc6d616a5d7d0284a5910ab35022528', - '2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-128: I=71'), - ('848586879b989996a3a2a5a4849b9a99', 'd2a920ecfe919d354b5f49eae9719c98', - '40414243454647484a4b4c4d4f505152', - 'ecb-tbl-128: I=72'), - ('0001020322212027cacbf4f551565754', '3a061b17f6a92885efbd0676985b373d', - '54555657595a5b5c5e5f606163646566', - 'ecb-tbl-128: I=73'), - ('cecfcccdafacadb2515057564a454447', 'fadeec16e33ea2f4688499d157e20d8f', - '68696a6b6d6e6f70727374757778797a', - 'ecb-tbl-128: I=74'), - ('92939091cdcecfc813121d1c80878685', '5cdefede59601aa3c3cda36fa6b1fa13', - '7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-128: I=75'), - ('d2d3d0d16f6c6d6259585f5ed1eeefec', '9574b00039844d92ebba7ee8719265f8', - '90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-128: I=76'), - ('acadaeaf878485820f0e1110d5d2d3d0', '9a9cf33758671787e5006928188643fa', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-128: I=77'), - ('9091929364676619e6e7e0e1757a7b78', '2cddd634c846ba66bb46cbfea4a674f9', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', - 'ecb-tbl-128: I=78'), - ('babbb8b98a89888f74757a7b92959497', 'd28bae029393c3e7e26e9fafbbb4b98f', - 'cccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-128: I=79'), - ('8d8c8f8e6e6d6c633b3a3d3ccad5d4d7', 'ec27529b1bee0a9ab6a0d73ebc82e9b7', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-128: I=80'), - ('86878485010203040808f7f767606162', '3cb25c09472aff6ee7e2b47ccd7ccb17', - 'f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-128: I=81'), - ('8e8f8c8d656667788a8b8c8d010e0f0c', 'dee33103a7283370d725e44ca38f8fe5', - '08090a0b0d0e0f10121314151718191a', - 'ecb-tbl-128: I=82'), - ('c8c9cacb858687807a7b7475e7e0e1e2', '27f9bcd1aac64bffc11e7815702c1a69', - '1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-128: I=83'), - ('6d6c6f6e5053525d8c8d8a8badd2d3d0', '5df534ffad4ed0749a9988e9849d0021', - '30313233353637383a3b3c3d3f404142', - 'ecb-tbl-128: I=84'), - ('28292a2b393a3b3c0607181903040506', 'a48bee75db04fb60ca2b80f752a8421b', - '44454647494a4b4c4e4f505153545556', - 'ecb-tbl-128: I=85'), - ('a5a4a7a6b0b3b28ddbdadddcbdb2b3b0', '024c8cf70bc86ee5ce03678cb7af45f9', - '58595a5b5d5e5f60626364656768696a', - 'ecb-tbl-128: I=86'), - ('323330316467666130313e3f2c2b2a29', '3c19ac0f8a3a3862ce577831301e166b', - '6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-128: I=87'), - ('27262524080b0a05171611100b141516', 'c5e355b796a57421d59ca6be82e73bca', - '80818283858687888a8b8c8d8f909192', - 'ecb-tbl-128: I=88'), - ('040506074142434435340b0aa3a4a5a6', 'd94033276417abfb05a69d15b6e386e2', - '94959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-128: I=89'), - ('242526271112130c61606766bdb2b3b0', '24b36559ea3a9b9b958fe6da3e5b8d85', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-128: I=90'), - ('4b4a4948252627209e9f9091cec9c8cb', '20fd4feaa0e8bf0cce7861d74ef4cb72', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-128: I=91'), - ('68696a6b6665646b9f9e9998d9e6e7e4', '350e20d5174277b9ec314c501570a11d', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-128: I=92'), - ('34353637c5c6c7c0f0f1eeef7c7b7a79', '87a29d61b7c604d238fe73045a7efd57', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-128: I=93'), - ('32333031c2c1c13f0d0c0b0a050a0b08', '2c3164c1cc7d0064816bdc0faa362c52', - 'f8f9fafbfdfefe00020304050708090a', - 'ecb-tbl-128: I=94'), - ('cdcccfcebebdbcbbabaaa5a4181f1e1d', '195fe5e8a05a2ed594f6e4400eee10b3', - '0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-128: I=95'), - ('212023223635343ba0a1a6a7445b5a59', 'e4663df19b9a21a5a284c2bd7f905025', - '20212223252627282a2b2c2d2f303132', - 'ecb-tbl-128: I=96'), - ('0e0f0c0da8abaaad2f2e515002050407', '21b88714cfb4e2a933bd281a2c4743fd', - '34353637393a3b3c3e3f404143444546', - 'ecb-tbl-128: I=97'), - ('070605042a2928378e8f8889bdb2b3b0', 'cbfc3980d704fd0fc54378ab84e17870', - '48494a4b4d4e4f50525354555758595a', - 'ecb-tbl-128: I=98'), - ('cbcac9c893909196a9a8a7a6a5a2a3a0', 'bc5144baa48bdeb8b63e22e03da418ef', - '5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-128: I=99'), - ('80818283c1c2c3cc9c9d9a9b0cf3f2f1', '5a1dbaef1ee2984b8395da3bdffa3ccc', - '70717273757677787a7b7c7d7f808182', - 'ecb-tbl-128: I=100'), - ('1213101125262720fafbe4e5b1b6b7b4', 'f0b11cd0729dfcc80cec903d97159574', - '84858687898a8b8c8e8f909193949596', - 'ecb-tbl-128: I=101'), - ('7f7e7d7c3033320d97969190222d2c2f', '9f95314acfddc6d1914b7f19a9cc8209', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-128: I=102'), - ('4e4f4c4d484b4a4d81808f8e53545556', '595736f6f0f70914a94e9e007f022519', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-128: I=103'), - ('dcdddedfb0b3b2bd15141312a1bebfbc', '1f19f57892cae586fcdfb4c694deb183', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-128: I=104'), - ('93929190282b2a2dc4c5fafb92959497', '540700ee1f6f3dab0b3eddf6caee1ef5', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-128: I=105'), - ('f5f4f7f6c4c7c6d9373631307e717073', '14a342a91019a331687a2254e6626ca2', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', - 'ecb-tbl-128: I=106'), - ('93929190b6b5b4b364656a6b05020300', '7b25f3c3b2eea18d743ef283140f29ff', - 'fcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-128: I=107'), - ('babbb8b90d0e0f00a4a5a2a3043b3a39', '46c2587d66e5e6fa7f7ca6411ad28047', - '10111213151617181a1b1c1d1f202122', - 'ecb-tbl-128: I=108'), - ('d8d9dadb7f7c7d7a10110e0f787f7e7d', '09470e72229d954ed5ee73886dfeeba9', - '24252627292a2b2c2e2f303133343536', - 'ecb-tbl-128: I=109'), - ('fefffcfdefeced923b3a3d3c6768696a', 'd77c03de92d4d0d79ef8d4824ef365eb', - '38393a3b3d3e3f40424344454748494a', - 'ecb-tbl-128: I=110'), - ('d6d7d4d58a89888f96979899a5a2a3a0', '1d190219f290e0f1715d152d41a23593', - '4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-128: I=111'), - ('18191a1ba8abaaa5303136379b848586', 'a2cd332ce3a0818769616292e87f757b', - '60616263656667686a6b6c6d6f707172', - 'ecb-tbl-128: I=112'), - ('6b6a6968a4a7a6a1d6d72829b0b7b6b5', 'd54afa6ce60fbf9341a3690e21385102', - '74757677797a7b7c7e7f808183848586', - 'ecb-tbl-128: I=113'), - ('000102038a89889755545352a6a9a8ab', '06e5c364ded628a3f5e05e613e356f46', - '88898a8b8d8e8f90929394959798999a', - 'ecb-tbl-128: I=114'), - ('2d2c2f2eb3b0b1b6b6b7b8b9f2f5f4f7', 'eae63c0e62556dac85d221099896355a', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-128: I=115'), - ('979695943536373856575051e09f9e9d', '1fed060e2c6fc93ee764403a889985a2', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-128: I=116'), - ('a4a5a6a7989b9a9db1b0afae7a7d7c7f', 'c25235c1a30fdec1c7cb5c5737b2a588', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-128: I=117'), - ('c1c0c3c2686b6a55a8a9aeafeae5e4e7', '796dbef95147d4d30873ad8b7b92efc0', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', - 'ecb-tbl-128: I=118'), - ('c1c0c3c2141716118c8d828364636261', 'cbcf0fb34d98d0bd5c22ce37211a46bf', - 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-128: I=119'), - ('93929190cccfcec196979091e0fffefd', '94b44da6466126cafa7c7fd09063fc24', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=120'), - ('b4b5b6b7f9fafbfc25241b1a6e69686b', 'd78c5b5ebf9b4dbda6ae506c5074c8fe', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=121'), - ('868784850704051ac7c6c1c08788898a', '6c27444c27204b043812cf8cf95f9769', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=122'), - ('f4f5f6f7aaa9a8affdfcf3f277707172', 'be94524ee5a2aa50bba8b75f4c0aebcf', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=123'), - ('d3d2d1d00605040bc3c2c5c43e010003', 'a0aeaae91ba9f31f51aeb3588cf3a39e', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=124'), - ('73727170424140476a6b74750d0a0b08', '275297779c28266ef9fe4c6a13c08488', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=125'), - ('c2c3c0c10a0908f754555253a1aeafac', '86523d92bb8672cb01cf4a77fd725882', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=126'), - ('6d6c6f6ef8fbfafd82838c8df8fffefd', '4b8327640e9f33322a04dd96fcbf9a36', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=127'), - ('f5f4f7f684878689a6a7a0a1d2cdcccf', 'ce52af650d088ca559425223f4d32694', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=128'), - - # ecb_tbl.txt, KEYSIZE=192 - ('2d33eef2c0430a8a9ebf45e809c40bb6', 'dff4945e0336df4c1c56bc700eff837f', - '00010203050607080a0b0c0d0f10111214151617191a1b1c', - 'ecb-tbl-192: I=1'), - ('6aa375d1fa155a61fb72353e0a5a8756', 'b6fddef4752765e347d5d2dc196d1252', - '1e1f20212324252628292a2b2d2e2f30323334353738393a', - 'ecb-tbl-192: I=2'), - ('bc3736518b9490dcb8ed60eb26758ed4', 'd23684e3d963b3afcf1a114aca90cbd6', - '3c3d3e3f41424344464748494b4c4d4e5051525355565758', - 'ecb-tbl-192: I=3'), - ('aa214402b46cffb9f761ec11263a311e', '3a7ac027753e2a18c2ceab9e17c11fd0', - '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-192: I=4'), - ('02aea86e572eeab66b2c3af5e9a46fd6', '8f6786bd007528ba26603c1601cdd0d8', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', - 'ecb-tbl-192: I=5'), - ('e2aef6acc33b965c4fa1f91c75ff6f36', 'd17d073b01e71502e28b47ab551168b3', - '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-192: I=6'), - ('0659df46427162b9434865dd9499f91d', 'a469da517119fab95876f41d06d40ffa', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', - 'ecb-tbl-192: I=7'), - ('49a44239c748feb456f59c276a5658df', '6091aa3b695c11f5c0b6ad26d3d862ff', - 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-192: I=8'), - ('66208f6e9d04525bdedb2733b6a6be37', '70f9e67f9f8df1294131662dc6e69364', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', - 'ecb-tbl-192: I=9'), - ('3393f8dfc729c97f5480b950bc9666b0', 'd154dcafad8b207fa5cbc95e9996b559', - '0e0f10111314151618191a1b1d1e1f20222324252728292a', - 'ecb-tbl-192: I=10'), - ('606834c8ce063f3234cf1145325dbd71', '4934d541e8b46fa339c805a7aeb9e5da', - '2c2d2e2f31323334363738393b3c3d3e4041424345464748', - 'ecb-tbl-192: I=11'), - ('fec1c04f529bbd17d8cecfcc4718b17f', '62564c738f3efe186e1a127a0c4d3c61', - '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-192: I=12'), - ('32df99b431ed5dc5acf8caf6dc6ce475', '07805aa043986eb23693e23bef8f3438', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', - 'ecb-tbl-192: I=13'), - ('7fdc2b746f3f665296943b83710d1f82', 'df0b4931038bade848dee3b4b85aa44b', - '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-192: I=14'), - ('8fba1510a3c5b87e2eaa3f7a91455ca2', '592d5fded76582e4143c65099309477c', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6b8b9babbbdbebfc0', - 'ecb-tbl-192: I=15'), - ('2c9b468b1c2eed92578d41b0716b223b', 'c9b8d6545580d3dfbcdd09b954ed4e92', - 'c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-192: I=16'), - ('0a2bbf0efc6bc0034f8a03433fca1b1a', '5dccd5d6eb7c1b42acb008201df707a0', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfc', - 'ecb-tbl-192: I=17'), - ('25260e1f31f4104d387222e70632504b', 'a2a91682ffeb6ed1d34340946829e6f9', - 'fefe01010304050608090a0b0d0e0f10121314151718191a', - 'ecb-tbl-192: I=18'), - ('c527d25a49f08a5228d338642ae65137', 'e45d185b797000348d9267960a68435d', - '1c1d1e1f21222324262728292b2c2d2e3031323335363738', - 'ecb-tbl-192: I=19'), - ('3b49fc081432f5890d0e3d87e884a69e', '45e060dae5901cda8089e10d4f4c246b', - '3a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-192: I=20'), - ('d173f9ed1e57597e166931df2754a083', 'f6951afacc0079a369c71fdcff45df50', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374', - 'ecb-tbl-192: I=21'), - ('8c2b7cafa5afe7f13562daeae1adede0', '9e95e00f351d5b3ac3d0e22e626ddad6', - '767778797b7c7d7e80818283858687888a8b8c8d8f909192', - 'ecb-tbl-192: I=22'), - ('aaf4ec8c1a815aeb826cab741339532c', '9cb566ff26d92dad083b51fdc18c173c', - '94959697999a9b9c9e9fa0a1a3a4a5a6a8a9aaabadaeafb0', - 'ecb-tbl-192: I=23'), - ('40be8c5d9108e663f38f1a2395279ecf', 'c9c82766176a9b228eb9a974a010b4fb', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebec', - 'ecb-tbl-192: I=24'), - ('0c8ad9bc32d43e04716753aa4cfbe351', 'd8e26aa02945881d5137f1c1e1386e88', - '2a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-192: I=25'), - ('1407b1d5f87d63357c8dc7ebbaebbfee', 'c0e024ccd68ff5ffa4d139c355a77c55', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364', - 'ecb-tbl-192: I=26'), - ('e62734d1ae3378c4549e939e6f123416', '0b18b3d16f491619da338640df391d43', - '84858687898a8b8c8e8f90919394959698999a9b9d9e9fa0', - 'ecb-tbl-192: I=27'), - ('5a752cff2a176db1a1de77f2d2cdee41', 'dbe09ac8f66027bf20cb6e434f252efc', - 'a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-192: I=28'), - ('a9c8c3a4eabedc80c64730ddd018cd88', '6d04e5e43c5b9cbe05feb9606b6480fe', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdc', - 'ecb-tbl-192: I=29'), - ('ee9b3dbbdb86180072130834d305999a', 'dd1d6553b96be526d9fee0fbd7176866', - '1a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-192: I=30'), - ('a7fa8c3586b8ebde7568ead6f634a879', '0260ca7e3f979fd015b0dd4690e16d2a', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354', - 'ecb-tbl-192: I=31'), - ('37e0f4a87f127d45ac936fe7ad88c10a', '9893734de10edcc8a67c3b110b8b8cc6', - '929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-192: I=32'), - ('3f77d8b5d92bac148e4e46f697a535c5', '93b30b750516b2d18808d710c2ee84ef', - '464748494b4c4d4e50515253555657585a5b5c5d5f606162', - 'ecb-tbl-192: I=33'), - ('d25ebb686c40f7e2c4da1014936571ca', '16f65fa47be3cb5e6dfe7c6c37016c0e', - '828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-192: I=34'), - ('4f1c769d1e5b0552c7eca84dea26a549', 'f3847210d5391e2360608e5acb560581', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbc', - 'ecb-tbl-192: I=35'), - ('8548e2f882d7584d0fafc54372b6633a', '8754462cd223366d0753913e6af2643d', - 'bebfc0c1c3c4c5c6c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-192: I=36'), - ('87d7a336cb476f177cd2a51af2a62cdf', '1ea20617468d1b806a1fd58145462017', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedeef0f1f2f3f5f6f7f8', - 'ecb-tbl-192: I=37'), - ('03b1feac668c4e485c1065dfc22b44ee', '3b155d927355d737c6be9dda60136e2e', - 'fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-192: I=38'), - ('bda15e66819fa72d653a6866aa287962', '26144f7b66daa91b6333dbd3850502b3', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334', - 'ecb-tbl-192: I=39'), - ('4d0c7a0d2505b80bf8b62ceb12467f0a', 'e4f9a4ab52ced8134c649bf319ebcc90', - '363738393b3c3d3e40414243454647484a4b4c4d4f505152', - 'ecb-tbl-192: I=40'), - ('626d34c9429b37211330986466b94e5f', 'b9ddd29ac6128a6cab121e34a4c62b36', - '54555657595a5b5c5e5f60616364656668696a6b6d6e6f70', - 'ecb-tbl-192: I=41'), - ('333c3e6bf00656b088a17e5ff0e7f60a', '6fcddad898f2ce4eff51294f5eaaf5c9', - '727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-192: I=42'), - ('687ed0cdc0d2a2bc8c466d05ef9d2891', 'c9a6fe2bf4028080bea6f7fc417bd7e3', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabac', - 'ecb-tbl-192: I=43'), - ('487830e78cc56c1693e64b2a6660c7b6', '6a2026846d8609d60f298a9c0673127f', - 'aeafb0b1b3b4b5b6b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', - 'ecb-tbl-192: I=44'), - ('7a48d6b7b52b29392aa2072a32b66160', '2cb25c005e26efea44336c4c97a4240b', - 'cccdcecfd1d2d3d4d6d7d8d9dbdcdddee0e1e2e3e5e6e7e8', - 'ecb-tbl-192: I=45'), - ('907320e64c8c5314d10f8d7a11c8618d', '496967ab8680ddd73d09a0e4c7dcc8aa', - 'eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-192: I=46'), - ('b561f2ca2d6e65a4a98341f3ed9ff533', 'd5af94de93487d1f3a8c577cb84a66a4', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324', - 'ecb-tbl-192: I=47'), - ('df769380d212792d026f049e2e3e48ef', '84bdac569cae2828705f267cc8376e90', - '262728292b2c2d2e30313233353637383a3b3c3d3f404142', - 'ecb-tbl-192: I=48'), - ('79f374bc445bdabf8fccb8843d6054c6', 'f7401dda5ad5ab712b7eb5d10c6f99b6', - '44454647494a4b4c4e4f50515354555658595a5b5d5e5f60', - 'ecb-tbl-192: I=49'), - ('4e02f1242fa56b05c68dbae8fe44c9d6', '1c9d54318539ebd4c3b5b7e37bf119f0', - '626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-192: I=50'), - ('cf73c93cbff57ac635a6f4ad2a4a1545', 'aca572d65fb2764cffd4a6eca090ea0d', - '80818283858687888a8b8c8d8f90919294959697999a9b9c', - 'ecb-tbl-192: I=51'), - ('9923548e2875750725b886566784c625', '36d9c627b8c2a886a10ccb36eae3dfbb', - '9e9fa0a1a3a4a5a6a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-192: I=52'), - ('4888336b723a022c9545320f836a4207', '010edbf5981e143a81d646e597a4a568', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdced0d1d2d3d5d6d7d8', - 'ecb-tbl-192: I=53'), - ('f84d9a5561b0608b1160dee000c41ba8', '8db44d538dc20cc2f40f3067fd298e60', - 'dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-192: I=54'), - ('c23192a0418e30a19b45ae3e3625bf22', '930eb53bc71e6ac4b82972bdcd5aafb3', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314', - 'ecb-tbl-192: I=55'), - ('b84e0690b28b0025381ad82a15e501a7', '6c42a81edcbc9517ccd89c30c95597b4', - '161718191b1c1d1e20212223252627282a2b2c2d2f303132', - 'ecb-tbl-192: I=56'), - ('acef5e5c108876c4f06269f865b8f0b0', 'da389847ad06df19d76ee119c71e1dd3', - '34353637393a3b3c3e3f40414344454648494a4b4d4e4f50', - 'ecb-tbl-192: I=57'), - ('0f1b3603e0f5ddea4548246153a5e064', 'e018fdae13d3118f9a5d1a647a3f0462', - '525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-192: I=58'), - ('fbb63893450d42b58c6d88cd3c1809e3', '2aa65db36264239d3846180fabdfad20', - '70717273757677787a7b7c7d7f80818284858687898a8b8c', - 'ecb-tbl-192: I=59'), - ('4bef736df150259dae0c91354e8a5f92', '1472163e9a4f780f1ceb44b07ecf4fdb', - '8e8f90919394959698999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-192: I=60'), - ('7d2d46242056ef13d3c3fc93c128f4c7', 'c8273fdc8f3a9f72e91097614b62397c', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8', - 'ecb-tbl-192: I=61'), - ('e9c1ba2df415657a256edb33934680fd', '66c8427dcd733aaf7b3470cb7d976e3f', - 'cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-192: I=62'), - ('e23ee277b0aa0a1dfb81f7527c3514f1', '146131cb17f1424d4f8da91e6f80c1d0', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304', - 'ecb-tbl-192: I=63'), - ('3e7445b0b63caaf75e4a911e12106b4c', '2610d0ad83659081ae085266a88770dc', - '060708090b0c0d0e10111213151617181a1b1c1d1f202122', - 'ecb-tbl-192: I=64'), - ('767774752023222544455a5be6e1e0e3', '38a2b5a974b0575c5d733917fb0d4570', - '24252627292a2b2c2e2f30313334353638393a3b3d3e3f40', - 'ecb-tbl-192: I=65'), - ('72737475717e7f7ce9e8ebea696a6b6c', 'e21d401ebc60de20d6c486e4f39a588b', - '424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-192: I=66'), - ('dfdedddc25262728c9c8cfcef1eeefec', 'e51d5f88c670b079c0ca1f0c2c4405a2', - '60616263656667686a6b6c6d6f70717274757677797a7b7c', - 'ecb-tbl-192: I=67'), - ('fffe0100707776755f5e5d5c7675746b', '246a94788a642fb3d1b823c8762380c8', - '7e7f80818384858688898a8b8d8e8f90929394959798999a', - 'ecb-tbl-192: I=68'), - ('e0e1e2e3424140479f9e9190292e2f2c', 'b80c391c5c41a4c3b30c68e0e3d7550f', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadaeb0b1b2b3b5b6b7b8', - 'ecb-tbl-192: I=69'), - ('2120272690efeeed3b3a39384e4d4c4b', 'b77c4754fc64eb9a1154a9af0bb1f21c', - 'babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-192: I=70'), - ('ecedeeef5350516ea1a0a7a6a3acadae', 'fb554de520d159a06bf219fc7f34a02f', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4', - 'ecb-tbl-192: I=71'), - ('32333c3d25222320e9e8ebeacecdccc3', 'a89fba152d76b4927beed160ddb76c57', - 'f6f7f8f9fbfcfdfe00010203050607080a0b0c0d0f101112', - 'ecb-tbl-192: I=72'), - ('40414243626160678a8bb4b511161714', '5676eab4a98d2e8473b3f3d46424247c', - '14151617191a1b1c1e1f20212324252628292a2b2d2e2f30', - 'ecb-tbl-192: I=73'), - ('94959293f5fafbf81f1e1d1c7c7f7e79', '4e8f068bd7ede52a639036ec86c33568', - '323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-192: I=74'), - ('bebfbcbd191a1b14cfcec9c8546b6a69', 'f0193c4d7aff1791ee4c07eb4a1824fc', - '50515253555657585a5b5c5d5f60616264656667696a6b6c', - 'ecb-tbl-192: I=75'), - ('2c2d3233898e8f8cbbbab9b8333031ce', 'ac8686eeca9ba761afe82d67b928c33f', - '6e6f70717374757678797a7b7d7e7f80828384858788898a', - 'ecb-tbl-192: I=76'), - ('84858687bfbcbdba37363938fdfafbf8', '5faf8573e33b145b6a369cd3606ab2c9', - '8c8d8e8f91929394969798999b9c9d9ea0a1a2a3a5a6a7a8', - 'ecb-tbl-192: I=77'), - ('828384857669686b909192930b08090e', '31587e9944ab1c16b844ecad0df2e7da', - 'aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-192: I=78'), - ('bebfbcbd9695948b707176779e919093', 'd017fecd91148aba37f6f3068aa67d8a', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4', - 'ecb-tbl-192: I=79'), - ('8b8a85846067666521202322d0d3d2dd', '788ef2f021a73cba2794b616078a8500', - 'e6e7e8e9ebecedeef0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-192: I=80'), - ('76777475f1f2f3f4f8f9e6e777707172', '5d1ef20dced6bcbc12131ac7c54788aa', - '04050607090a0b0c0e0f10111314151618191a1b1d1e1f20', - 'ecb-tbl-192: I=81'), - ('a4a5a2a34f404142b4b5b6b727242522', 'b3c8cf961faf9ea05fdde6d1e4d8f663', - '222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-192: I=82'), - ('94959697e1e2e3ec16171011839c9d9e', '143075c70605861c7fac6526199e459f', - '40414243454647484a4b4c4d4f50515254555657595a5b5c', - 'ecb-tbl-192: I=83'), - ('03023d3c06010003dedfdcddfffcfde2', 'a5ae12eade9a87268d898bfc8fc0252a', - '5e5f60616364656668696a6b6d6e6f70727374757778797a', - 'ecb-tbl-192: I=84'), - ('10111213f1f2f3f4cecfc0c1dbdcddde', '0924f7cf2e877a4819f5244a360dcea9', - '7c7d7e7f81828384868788898b8c8d8e9091929395969798', - 'ecb-tbl-192: I=85'), - ('67666160724d4c4f1d1c1f1e73707176', '3d9e9635afcc3e291cc7ab3f27d1c99a', - '9a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-192: I=86'), - ('e6e7e4e5a8abaad584858283909f9e9d', '9d80feebf87510e2b8fb98bb54fd788c', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4', - 'ecb-tbl-192: I=87'), - ('71707f7e565150537d7c7f7e6162636c', '5f9d1a082a1a37985f174002eca01309', - 'd6d7d8d9dbdcdddee0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-192: I=88'), - ('64656667212223245555aaaa03040506', 'a390ebb1d1403930184a44b4876646e4', - 'f4f5f6f7f9fafbfcfefe01010304050608090a0b0d0e0f10', - 'ecb-tbl-192: I=89'), - ('9e9f9899aba4a5a6cfcecdcc2b28292e', '700fe918981c3195bb6c4bcb46b74e29', - '121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-192: I=90'), - ('c7c6c5c4d1d2d3dc626364653a454447', '907984406f7bf2d17fb1eb15b673d747', - '30313233353637383a3b3c3d3f40414244454647494a4b4c', - 'ecb-tbl-192: I=91'), - ('f6f7e8e9e0e7e6e51d1c1f1e5b585966', 'c32a956dcfc875c2ac7c7cc8b8cc26e1', - '4e4f50515354555658595a5b5d5e5f60626364656768696a', - 'ecb-tbl-192: I=92'), - ('bcbdbebf5d5e5f5868696667f4f3f2f1', '02646e2ebfa9b820cf8424e9b9b6eb51', - '6c6d6e6f71727374767778797b7c7d7e8081828385868788', - 'ecb-tbl-192: I=93'), - ('40414647b0afaead9b9a99989b98999e', '621fda3a5bbd54c6d3c685816bd4ead8', - '8a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-192: I=94'), - ('69686b6a0201001f0f0e0908b4bbbab9', 'd4e216040426dfaf18b152469bc5ac2f', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4', - 'ecb-tbl-192: I=95'), - ('c7c6c9c8d8dfdedd5a5b5859bebdbcb3', '9d0635b9d33b6cdbd71f5d246ea17cc8', - 'c6c7c8c9cbcccdced0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-192: I=96'), - ('dedfdcdd787b7a7dfffee1e0b2b5b4b7', '10abad1bd9bae5448808765583a2cc1a', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6f8f9fafbfdfefe00', - 'ecb-tbl-192: I=97'), - ('4d4c4b4a606f6e6dd0d1d2d3fbf8f9fe', '6891889e16544e355ff65a793c39c9a8', - '020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-192: I=98'), - ('b7b6b5b4d7d4d5dae5e4e3e2e1fefffc', 'cc735582e68072c163cd9ddf46b91279', - '20212223252627282a2b2c2d2f30313234353637393a3b3c', - 'ecb-tbl-192: I=99'), - ('cecfb0b1f7f0f1f2aeafacad3e3d3c23', 'c5c68b9aeeb7f878df578efa562f9574', - '3e3f40414344454648494a4b4d4e4f50525354555758595a', - 'ecb-tbl-192: I=100'), - ('cacbc8c9cdcecfc812131c1d494e4f4c', '5f4764395a667a47d73452955d0d2ce8', - '5c5d5e5f61626364666768696b6c6d6e7071727375767778', - 'ecb-tbl-192: I=101'), - ('9d9c9b9ad22d2c2fb1b0b3b20c0f0e09', '701448331f66106cefddf1eb8267c357', - '7a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-192: I=102'), - ('7a7b787964676659959493924f404142', 'cb3ee56d2e14b4e1941666f13379d657', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4', - 'ecb-tbl-192: I=103'), - ('aaaba4a5cec9c8cb1f1e1d1caba8a9a6', '9fe16efd18ab6e1981191851fedb0764', - 'b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-192: I=104'), - ('93929190282b2a2dc4c5fafb92959497', '3dc9ba24e1b223589b147adceb4c8e48', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6e8e9eaebedeeeff0', - 'ecb-tbl-192: I=105'), - ('efeee9e8ded1d0d339383b3a888b8a8d', '1c333032682e7d4de5e5afc05c3e483c', - 'f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-192: I=106'), - ('7f7e7d7ca2a1a0af78797e7f112e2f2c', 'd593cc99a95afef7e92038e05a59d00a', - '10111213151617181a1b1c1d1f20212224252627292a2b2c', - 'ecb-tbl-192: I=107'), - ('84859a9b2b2c2d2e868784852625245b', '51e7f96f53b4353923452c222134e1ec', - '2e2f30313334353638393a3b3d3e3f40424344454748494a', - 'ecb-tbl-192: I=108'), - ('b0b1b2b3070405026869666710171615', '4075b357a1a2b473400c3b25f32f81a4', - '4c4d4e4f51525354565758595b5c5d5e6061626365666768', - 'ecb-tbl-192: I=109'), - ('acadaaabbda2a3a00d0c0f0e595a5b5c', '302e341a3ebcd74f0d55f61714570284', - '6a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-192: I=110'), - ('121310115655544b5253545569666764', '57abdd8231280da01c5042b78cf76522', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4', - 'ecb-tbl-192: I=111'), - ('dedfd0d166616063eaebe8e94142434c', '17f9ea7eea17ac1adf0e190fef799e92', - 'a6a7a8a9abacadaeb0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-192: I=112'), - ('dbdad9d81417161166677879e0e7e6e5', '2e1bdd563dd87ee5c338dd6d098d0a7a', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6d8d9dadbdddedfe0', - 'ecb-tbl-192: I=113'), - ('6a6b6c6de0efeeed2b2a2928c0c3c2c5', 'eb869996e6f8bfb2bfdd9e0c4504dbb2', - 'e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-192: I=114'), - ('b1b0b3b21714151a1a1b1c1d5649484b', 'c2e01549e9decf317468b3e018c61ba8', - '00010203050607080a0b0c0d0f10111214151617191a1b1c', - 'ecb-tbl-192: I=115'), - ('39380706a3a4a5a6c4c5c6c77271706f', '8da875d033c01dd463b244a1770f4a22', - '1e1f20212324252628292a2b2d2e2f30323334353738393a', - 'ecb-tbl-192: I=116'), - ('5c5d5e5f1013121539383736e2e5e4e7', '8ba0dcf3a186844f026d022f8839d696', - '3c3d3e3f41424344464748494b4c4d4e5051525355565758', - 'ecb-tbl-192: I=117'), - ('43424544ead5d4d72e2f2c2d64676661', 'e9691ff9a6cc6970e51670a0fd5b88c1', - '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-192: I=118'), - ('55545756989b9a65f8f9feff18171615', 'f2baec06faeed30f88ee63ba081a6e5b', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', - 'ecb-tbl-192: I=119'), - ('05040b0a525554573c3d3e3f4a494847', '9c39d4c459ae5753394d6094adc21e78', - '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-192: I=120'), - ('14151617595a5b5c8584fbfa8e89888b', '6345b532a11904502ea43ba99c6bd2b2', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', - 'ecb-tbl-192: I=121'), - ('7c7d7a7bfdf2f3f029282b2a51525354', '5ffae3061a95172e4070cedce1e428c8', - 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-192: I=122'), - ('38393a3b1e1d1c1341404746c23d3c3e', '0a4566be4cdf9adce5dec865b5ab34cd', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', - 'ecb-tbl-192: I=123'), - ('8d8c939240474645818083827c7f7e41', 'ca17fcce79b7404f2559b22928f126fb', - '0e0f10111314151618191a1b1d1e1f20222324252728292a', - 'ecb-tbl-192: I=124'), - ('3b3a39381a19181f32333c3d45424340', '97ca39b849ed73a6470a97c821d82f58', - '2c2d2e2f31323334363738393b3c3d3e4041424345464748', - 'ecb-tbl-192: I=125'), - ('f0f1f6f738272625828380817f7c7d7a', '8198cb06bc684c6d3e9b7989428dcf7a', - '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-192: I=126'), - ('89888b8a0407061966676061141b1a19', 'f53c464c705ee0f28d9a4c59374928bd', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', - 'ecb-tbl-192: I=127'), - ('d3d2dddcaaadacaf9c9d9e9fe8ebeae5', '9adb3d4cca559bb98c3e2ed73dbf1154', - '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-192: I=128'), - - # ecb_tbl.txt, KEYSIZE=256 - ('834eadfccac7e1b30664b1aba44815ab', '1946dabf6a03a2a2c3d0b05080aed6fc', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=1'), - ('d9dc4dba3021b05d67c0518f72b62bf1', '5ed301d747d3cc715445ebdec62f2fb4', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=2'), - ('a291d86301a4a739f7392173aa3c604c', '6585c8f43d13a6beab6419fc5935b9d0', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=3'), - ('4264b2696498de4df79788a9f83e9390', '2a5b56a596680fcc0e05f5e0f151ecae', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=4'), - ('ee9932b3721804d5a83ef5949245b6f6', 'f5d6ff414fd2c6181494d20c37f2b8c4', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=5'), - ('e6248f55c5fdcbca9cbbb01c88a2ea77', '85399c01f59fffb5204f19f8482f00b8', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=6'), - ('b8358e41b9dff65fd461d55a99266247', '92097b4c88a041ddf98144bc8d22e8e7', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=7'), - ('f0e2d72260af58e21e015ab3a4c0d906', '89bd5b73b356ab412aef9f76cea2d65c', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=8'), - ('475b8b823ce8893db3c44a9f2a379ff7', '2536969093c55ff9454692f2fac2f530', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=9'), - ('688f5281945812862f5f3076cf80412f', '07fc76a872843f3f6e0081ee9396d637', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=10'), - ('08d1d2bc750af553365d35e75afaceaa', 'e38ba8ec2aa741358dcc93e8f141c491', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=11'), - ('8707121f47cc3efceca5f9a8474950a1', 'd028ee23e4a89075d0b03e868d7d3a42', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=12'), - ('e51aa0b135dba566939c3b6359a980c5', '8cd9423dfc459e547155c5d1d522e540', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=13'), - ('069a007fc76a459f98baf917fedf9521', '080e9517eb1677719acf728086040ae3', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=14'), - ('726165c1723fbcf6c026d7d00b091027', '7c1700211a3991fc0ecded0ab3e576b0', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=15'), - ('d7c544de91d55cfcde1f84ca382200ce', 'dabcbcc855839251db51e224fbe87435', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=16'), - ('fed3c9a161b9b5b2bd611b41dc9da357', '68d56fad0406947a4dd27a7448c10f1d', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=17'), - ('4f634cdc6551043409f30b635832cf82', 'da9a11479844d1ffee24bbf3719a9925', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=18'), - ('109ce98db0dfb36734d9f3394711b4e6', '5e4ba572f8d23e738da9b05ba24b8d81', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=19'), - ('4ea6dfaba2d8a02ffdffa89835987242', 'a115a2065d667e3f0b883837a6e903f8', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=20'), - ('5ae094f54af58e6e3cdbf976dac6d9ef', '3e9e90dc33eac2437d86ad30b137e66e', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=21'), - ('764d8e8e0f29926dbe5122e66354fdbe', '01ce82d8fbcdae824cb3c48e495c3692', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=22'), - ('3f0418f888cdf29a982bf6b75410d6a9', '0c9cff163ce936faaf083cfd3dea3117', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=23'), - ('e4a3e7cb12cdd56aa4a75197a9530220', '5131ba9bd48f2bba85560680df504b52', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=24'), - ('211677684aac1ec1a160f44c4ebf3f26', '9dc503bbf09823aec8a977a5ad26ccb2', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=25'), - ('d21e439ff749ac8f18d6d4b105e03895', '9a6db0c0862e506a9e397225884041d7', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=26'), - ('d9f6ff44646c4725bd4c0103ff5552a7', '430bf9570804185e1ab6365fc6a6860c', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=27'), - ('0b1256c2a00b976250cfc5b0c37ed382', '3525ebc02f4886e6a5a3762813e8ce8a', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=28'), - ('b056447ffc6dc4523a36cc2e972a3a79', '07fa265c763779cce224c7bad671027b', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=29'), - ('5e25ca78f0de55802524d38da3fe4456', 'e8b72b4e8be243438c9fff1f0e205872', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=30'), - ('a5bcf4728fa5eaad8567c0dc24675f83', '109d4f999a0e11ace1f05e6b22cbcb50', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=31'), - ('814e59f97ed84646b78b2ca022e9ca43', '45a5e8d4c3ed58403ff08d68a0cc4029', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=32'), - ('15478beec58f4775c7a7f5d4395514d7', '196865964db3d417b6bd4d586bcb7634', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=33'), - ('253548ffca461c67c8cbc78cd59f4756', '60436ad45ac7d30d99195f815d98d2ae', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=34'), - ('fd7ad8d73b9b0f8cc41600640f503d65', 'bb07a23f0b61014b197620c185e2cd75', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=35'), - ('06199de52c6cbf8af954cd65830bcd56', '5bc0b2850129c854423aff0751fe343b', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=36'), - ('f17c4ffe48e44c61bd891e257e725794', '7541a78f96738e6417d2a24bd2beca40', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=37'), - ('9a5b4a402a3e8a59be6bf5cd8154f029', 'b0a303054412882e464591f1546c5b9e', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=38'), - ('79bd40b91a7e07dc939d441782ae6b17', '778c06d8a355eeee214fcea14b4e0eef', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=39'), - ('d8ceaaf8976e5fbe1012d8c84f323799', '09614206d15cbace63227d06db6beebb', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=40'), - ('3316e2751e2e388b083da23dd6ac3fbe', '41b97fb20e427a9fdbbb358d9262255d', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=41'), - ('8b7cfbe37de7dca793521819242c5816', 'c1940f703d845f957652c2d64abd7adf', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=42'), - ('f23f033c0eebf8ec55752662fd58ce68', 'd2d44fcdae5332343366db297efcf21b', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=43'), - ('59eb34f6c8bdbacc5fc6ad73a59a1301', 'ea8196b79dbe167b6aa9896e287eed2b', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=44'), - ('dcde8b6bd5cf7cc22d9505e3ce81261a', 'd6b0b0c4ba6c7dbe5ed467a1e3f06c2d', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=45'), - ('e33cf7e524fed781e7042ff9f4b35dc7', 'ec51eb295250c22c2fb01816fb72bcae', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=46'), - ('27963c8facdf73062867d164df6d064c', 'aded6630a07ce9c7408a155d3bd0d36f', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=47'), - ('77b1ce386b551b995f2f2a1da994eef8', '697c9245b9937f32f5d1c82319f0363a', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=48'), - ('f083388b013679efcf0bb9b15d52ae5c', 'aad5ad50c6262aaec30541a1b7b5b19c', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=49'), - ('c5009e0dab55db0abdb636f2600290c8', '7d34b893855341ec625bd6875ac18c0d', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=50'), - ('7804881e26cd532d8514d3683f00f1b9', '7ef05105440f83862f5d780e88f02b41', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=51'), - ('46cddcd73d1eb53e675ca012870a92a3', 'c377c06403382061af2c9c93a8e70df6', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=52'), - ('a9fb44062bb07fe130a8e8299eacb1ab', '1dbdb3ffdc052dacc83318853abc6de5', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=53'), - ('2b6ff8d7a5cc3a28a22d5a6f221af26b', '69a6eab00432517d0bf483c91c0963c7', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=54'), - ('1a9527c29b8add4b0e3e656dbb2af8b4', '0797f41dc217c80446e1d514bd6ab197', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=55'), - ('7f99cf2c75244df015eb4b0c1050aeae', '9dfd76575902a637c01343c58e011a03', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=56'), - ('e84ff85b0d9454071909c1381646c4ed', 'acf4328ae78f34b9fa9b459747cc2658', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=57'), - ('89afd40f99521280d5399b12404f6db4', 'b0479aea12bac4fe2384cf98995150c6', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=58'), - ('a09ef32dbc5119a35ab7fa38656f0329', '9dd52789efe3ffb99f33b3da5030109a', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=59'), - ('61773457f068c376c7829b93e696e716', 'abbb755e4621ef8f1214c19f649fb9fd', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=60'), - ('a34f0cae726cce41dd498747d891b967', 'da27fb8174357bce2bed0e7354f380f9', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=61'), - ('856f59496c7388ee2d2b1a27b7697847', 'c59a0663f0993838f6e5856593bdc5ef', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=62'), - ('cb090c593ef7720bd95908fb93b49df4', 'ed60b264b5213e831607a99c0ce5e57e', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=63'), - ('a0ac75cd2f1923d460fc4d457ad95baf', 'e50548746846f3eb77b8c520640884ed', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=64'), - ('2a2b282974777689e8e9eeef525d5c5f', '28282cc7d21d6a2923641e52d188ef0c', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=65'), - ('909192939390919e0f0e09089788898a', '0dfa5b02abb18e5a815305216d6d4f8e', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=66'), - ('777675748d8e8f907170777649464744', '7359635c0eecefe31d673395fb46fb99', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=67'), - ('717073720605040b2d2c2b2a05fafbf9', '73c679f7d5aef2745c9737bb4c47fb36', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=68'), - ('64656667fefdfcc31b1a1d1ca5aaaba8', 'b192bd472a4d2eafb786e97458967626', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=69'), - ('dbdad9d86a696867b5b4b3b2c8d7d6d5', '0ec327f6c8a2b147598ca3fde61dc6a4', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=70'), - ('5c5d5e5fe3e0e1fe31303736333c3d3e', 'fc418eb3c41b859b38d4b6f646629729', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=71'), - ('545556574b48494673727574546b6a69', '30249e5ac282b1c981ea64b609f3a154', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=72'), - ('ecedeeefc6c5c4bb56575051f5fafbf8', '5e6e08646d12150776bb43c2d78a9703', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=73'), - ('464744452724252ac9c8cfced2cdcccf', 'faeb3d5de652cd3447dceb343f30394a', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=74'), - ('e6e7e4e54142435c878681801c131211', 'a8e88706823f6993ef80d05c1c7b2cf0', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=75'), - ('72737071cfcccdc2f9f8fffe710e0f0c', '8ced86677e6e00a1a1b15968f2d3cce6', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=76'), - ('505152537370714ec3c2c5c4010e0f0c', '9fc7c23858be03bdebb84e90db6786a9', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=77'), - ('a8a9aaab5c5f5e51aeafa8a93d222320', 'b4fbd65b33f70d8cf7f1111ac4649c36', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=78'), - ('dedfdcddf6f5f4eb10111617fef1f0f3', 'c5c32d5ed03c4b53cc8c1bd0ef0dbbf6', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=79'), - ('bdbcbfbe5e5d5c530b0a0d0cfac5c4c7', 'd1a7f03b773e5c212464b63709c6a891', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=80'), - ('8a8b8889050606f8f4f5f2f3636c6d6e', '6b7161d8745947ac6950438ea138d028', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=81'), - ('a6a7a4a54d4e4f40b2b3b4b539262724', 'fd47a9f7e366ee7a09bc508b00460661', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=82'), - ('9c9d9e9fe9eaebf40e0f08099b949596', '00d40b003dc3a0d9310b659b98c7e416', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=83'), - ('2d2c2f2e1013121dcccdcacbed121310', 'eea4c79dcc8e2bda691f20ac48be0717', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=84'), - ('f4f5f6f7edeeefd0eaebecedf7f8f9fa', 'e78f43b11c204403e5751f89d05a2509', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=85'), - ('3d3c3f3e282b2a2573727574150a0b08', 'd0f0e3d1f1244bb979931e38dd1786ef', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=86'), - ('b6b7b4b5f8fbfae5b4b5b2b3a0afaead', '042e639dc4e1e4dde7b75b749ea6f765', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=87'), - ('b7b6b5b4989b9a95878681809ba4a5a6', 'bc032fdd0efe29503a980a7d07ab46a8', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=88'), - ('a8a9aaabe5e6e798e9e8efee4748494a', '0c93ac949c0da6446effb86183b6c910', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=89'), - ('ecedeeefd9dadbd4b9b8bfbe657a7b78', 'e0d343e14da75c917b4a5cec4810d7c2', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=90'), - ('7f7e7d7c696a6b74cacbcccd929d9c9f', '0eafb821748408279b937b626792e619', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=91'), - ('08090a0b0605040bfffef9f8b9c6c7c4', 'fa1ac6e02d23b106a1fef18b274a553f', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=92'), - ('08090a0bf1f2f3ccfcfdfafb68676665', '0dadfe019cd12368075507df33c1a1e9', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=93'), - ('cacbc8c93a393837050403020d121310', '3a0879b414465d9ffbaf86b33a63a1b9', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=94'), - ('e9e8ebea8281809f8f8e8988343b3a39', '62199fadc76d0be1805d3ba0b7d914bf', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=95'), - ('515053524645444bd0d1d6d7340b0a09', '1b06d6c5d333e742730130cf78e719b4', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=96'), - ('42434041ecefee1193929594c6c9c8cb', 'f1f848824c32e9dcdcbf21580f069329', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=97'), - ('efeeedecc2c1c0cf76777071455a5b58', '1a09050cbd684f784d8e965e0782f28a', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=98'), - ('5f5e5d5c3f3c3d221d1c1b1a19161714', '79c2969e7ded2ba7d088f3f320692360', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=99'), - ('000102034142434c1c1d1a1b8d727371', '091a658a2f7444c16accb669450c7b63', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=100'), - ('8e8f8c8db1b2b38c56575051050a0b08', '97c1e3a72cca65fa977d5ed0e8a7bbfc', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=101'), - ('a7a6a5a4e8ebeae57f7e7978cad5d4d7', '70c430c6db9a17828937305a2df91a2a', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=102'), - ('8a8b888994979689454443429f909192', '629553457fbe2479098571c7c903fde8', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=103'), - ('8c8d8e8fe0e3e2ed45444342f1cecfcc', 'a25b25a61f612669e7d91265c7d476ba', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=104'), - ('fffefdfc4c4f4e31d8d9dedfb6b9b8bb', 'eb7e4e49b8ae0f024570dda293254fed', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=105'), - ('fdfcfffecccfcec12f2e29286679787b', '38fe15d61cca84516e924adce5014f67', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=106'), - ('67666564bab9b8a77071767719161714', '3ad208492249108c9f3ebeb167ad0583', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=107'), - ('9a9b98992d2e2f2084858283245b5a59', '299ba9f9bf5ab05c3580fc26edd1ed12', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=108'), - ('a4a5a6a70b0809365c5d5a5b2c232221', '19dc705b857a60fb07717b2ea5717781', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=109'), - ('464744455754555af3f2f5f4afb0b1b2', 'ffc8aeb885b5efcad06b6dbebf92e76b', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=110'), - ('323330317675746b7273747549464744', 'f58900c5e0b385253ff2546250a0142b', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=111'), - ('a8a9aaab181b1a15808186872b141516', '2ee67b56280bc462429cee6e3370cbc1', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=112'), - ('e7e6e5e4202323ddaaabacad343b3a39', '20db650a9c8e9a84ab4d25f7edc8f03f', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=113'), - ('a8a9aaab2221202fedecebea1e010003', '3c36da169525cf818843805f25b78ae5', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=114'), - ('f9f8fbfa5f5c5d42424344450e010003', '9a781d960db9e45e37779042fea51922', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=115'), - ('57565554f5f6f7f89697909120dfdedd', '6560395ec269c672a3c288226efdba77', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=116'), - ('f8f9fafbcccfcef1dddcdbda0e010003', '8c772b7a189ac544453d5916ebb27b9a', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=117'), - ('d9d8dbda7073727d80818687c2dddcdf', '77ca5468cc48e843d05f78eed9d6578f', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=118'), - ('c5c4c7c6080b0a1588898e8f68676665', '72cdcc71dc82c60d4429c9e2d8195baa', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=119'), - ('83828180dcdfded186878081f0cfcecd', '8080d68ce60e94b40b5b8b69eeb35afa', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=120'), - ('98999a9bdddedfa079787f7e0a050407', '44222d3cde299c04369d58ac0eba1e8e', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=121'), - ('cecfcccd4f4c4d429f9e9998dfc0c1c2', '9b8721b0a8dfc691c5bc5885dbfcb27a', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=122'), - ('404142436665647b29282f2eaba4a5a6', '0dc015ce9a3a3414b5e62ec643384183', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=123'), - ('33323130e6e5e4eb23222524dea1a0a3', '705715448a8da412025ce38345c2a148', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=124'), - ('cfcecdccf6f5f4cbe6e7e0e199969794', 'c32b5b0b6fbae165266c569f4b6ecf0b', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=125'), - ('babbb8b97271707fdcdddadb29363734', '4dca6c75192a01ddca9476af2a521e87', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=126'), - ('c9c8cbca4447465926272021545b5a59', '058691e627ecbc36ac07b6db423bd698', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=127'), - ('050407067477767956575051221d1c1f', '7444527095838fe080fc2bcdd30847eb', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=128'), - - # FIPS PUB 800-38A test vectors, 2001 edition. Annex F. - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - '3ad77bb40d7a3660a89ecaf32466ef97'+'f5d3d58503b9699de785895a96fdbaaf'+ - '43b1cd7f598ece23881b00e3ed030688'+'7b0c785e27e8ad3f8223207104725dd4', - '2b7e151628aed2a6abf7158809cf4f3c', - 'NIST 800-38A, F.1.1, ECB and AES-128'), - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - 'bd334f1d6e45f25ff712a214571fa5cc'+'974104846d0ad3ad7734ecb3ecee4eef'+ - 'ef7afd2270e2e60adce0ba2face6444e'+'9a4b41ba738d6c72fb16691603c18e0e', - '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b', - 'NIST 800-38A, F.1.3, ECB and AES-192'), - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - 'f3eed1bdb5d2a03c064b5a7e3db181f8'+'591ccb10d410ed26dc5ba74a31362870'+ - 'b6ed21b99ca6f4f9f153e7b1beafed1d'+'23304b7a39f9f3ff067d8d8f9e24ecc7', - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', - 'NIST 800-38A, F.1.3, ECB and AES-256'), - -] - -test_data_8_lanes = [] -for td in test_data: - test_data_8_lanes.append((td[0] * 8, td[1] * 8, td[2], td[3])) -test_data += test_data_8_lanes - -class TestMultipleBlocks(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt data which is 8*2+4 bytes long, so as to trigger (for the - # AESNI variant) both the path that parallelizes 8 lanes and the one - # that processes data serially - - tvs = [ - (b'a' * 16, 'c0b27011eb15bf144d2fc9fae80ea16d4c231cb230416c5fac02e6835ad9d7d0'), - (b'a' * 24, 'df8435ce361a78c535b41dcb57da952abbf9ee5954dc6fbcd75fd00fa626915d'), - (b'a' * 32, '211402de6c80db1f92ba255881178e1f70783b8cfd3b37808205e48b80486cd8') - ] - - for key, expected in tvs: - - cipher = AES.new(key, AES.MODE_ECB, use_aesni=self.use_aesni) - h = SHA256.new() - - pt = b"".join([ tobytes('{0:016x}'.format(x)) for x in range(20) ]) - ct = cipher.encrypt(pt) - self.assertEqual(SHA256.new(ct).hexdigest(), expected) - - -class TestIncompleteBlocks(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt data with length not multiple of 16 bytes - - cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) - - for msg_len in range(1, 16): - self.assertRaises(ValueError, cipher.encrypt, b'1' * msg_len) - self.assertRaises(ValueError, cipher.encrypt, b'1' * (msg_len+16)) - self.assertRaises(ValueError, cipher.decrypt, b'1' * msg_len) - self.assertRaises(ValueError, cipher.decrypt, b'1' * (msg_len+16)) - - self.assertEqual(cipher.encrypt(b''), b'') - self.assertEqual(cipher.decrypt(b''), b'') - - -class TestOutput(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from Crypto.Util import _cpu_features - from .common import make_block_tests - - tests = make_block_tests(AES, "AES", test_data, {'use_aesni': False}) - tests += [ TestMultipleBlocks(False) ] - tests += [ TestIncompleteBlocks(False) ] - if _cpu_features.have_aes_ni(): - # Run tests with AES-NI instructions if they are available. - tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True}) - tests += [ TestMultipleBlocks(True) ] - tests += [ TestIncompleteBlocks(True) ] - tests += [ TestOutput(True) ] - else: - print("Skipping AESNI tests") - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC2.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC2.py deleted file mode 100644 index fd9448c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC2.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/ARC2.py: Self-test for the Alleged-RC2 cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.ARC2""" - -import unittest - -from Crypto.Util.py3compat import b, bchr - -from Crypto.Cipher import ARC2 - -# This is a list of (plaintext, ciphertext, key[, description[, extra_params]]) tuples. -test_data = [ - # Test vectors from RFC 2268 - - # 63-bit effective key length - ('0000000000000000', 'ebb773f993278eff', '0000000000000000', - 'RFC2268-1', dict(effective_keylen=63)), - - # 64-bit effective key length - ('ffffffffffffffff', '278b27e42e2f0d49', 'ffffffffffffffff', - 'RFC2268-2', dict(effective_keylen=64)), - ('1000000000000001', '30649edf9be7d2c2', '3000000000000000', - 'RFC2268-3', dict(effective_keylen=64)), - #('0000000000000000', '61a8a244adacccf0', '88', - # 'RFC2268-4', dict(effective_keylen=64)), - ('0000000000000000', '6ccf4308974c267f', '88bca90e90875a', - 'RFC2268-5', dict(effective_keylen=64)), - ('0000000000000000', '1a807d272bbe5db1', '88bca90e90875a7f0f79c384627bafb2', - 'RFC2268-6', dict(effective_keylen=64)), - - # 128-bit effective key length - ('0000000000000000', '2269552ab0f85ca6', '88bca90e90875a7f0f79c384627bafb2', - "RFC2268-7", dict(effective_keylen=128)), - ('0000000000000000', '5b78d3a43dfff1f1', - '88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e', - "RFC2268-8", dict(effective_keylen=129)), - - # Test vectors from PyCrypto 2.0.1's testdata.py - # 1024-bit effective key length - ('0000000000000000', '624fb3e887419e48', '5068696c6970476c617373', - 'PCTv201-0'), - ('ffffffffffffffff', '79cadef44c4a5a85', '5068696c6970476c617373', - 'PCTv201-1'), - ('0001020304050607', '90411525b34e4c2c', '5068696c6970476c617373', - 'PCTv201-2'), - ('0011223344556677', '078656aaba61cbfb', '5068696c6970476c617373', - 'PCTv201-3'), - ('0000000000000000', 'd7bcc5dbb4d6e56a', 'ffffffffffffffff', - 'PCTv201-4'), - ('ffffffffffffffff', '7259018ec557b357', 'ffffffffffffffff', - 'PCTv201-5'), - ('0001020304050607', '93d20a497f2ccb62', 'ffffffffffffffff', - 'PCTv201-6'), - ('0011223344556677', 'cb15a7f819c0014d', 'ffffffffffffffff', - 'PCTv201-7'), - ('0000000000000000', '63ac98cdf3843a7a', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-8'), - ('ffffffffffffffff', '3fb49e2fa12371dd', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-9'), - ('0001020304050607', '46414781ab387d5f', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-10'), - ('0011223344556677', 'be09dc81feaca271', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-11'), - ('0000000000000000', 'e64221e608be30ab', '53e5ffe553', - 'PCTv201-12'), - ('ffffffffffffffff', '862bc60fdcd4d9a9', '53e5ffe553', - 'PCTv201-13'), - ('0001020304050607', '6a34da50fa5e47de', '53e5ffe553', - 'PCTv201-14'), - ('0011223344556677', '584644c34503122c', '53e5ffe553', - 'PCTv201-15'), -] - -class BufferOverflowTest(unittest.TestCase): - # Test a buffer overflow found in older versions of PyCrypto - - def runTest(self): - """ARC2 with keylength > 128""" - key = b("x") * 16384 - self.assertRaises(ValueError, ARC2.new, key, ARC2.MODE_ECB) - -class KeyLength(unittest.TestCase): - - def runTest(self): - ARC2.new(b'\x00' * 16, ARC2.MODE_ECB, effective_keylen=40) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB) - - self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, - effective_keylen=39) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, - effective_keylen=1025) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from Crypto.Cipher import ARC2 - from .common import make_block_tests - - tests = make_block_tests(ARC2, "ARC2", test_data) - tests.append(BufferOverflowTest()) - tests.append(KeyLength()) - tests += [TestOutput()] - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC4.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC4.py deleted file mode 100644 index 753df4c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ARC4.py +++ /dev/null @@ -1,471 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/ARC4.py: Self-test for the Alleged-RC4 cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.ARC4""" - -import unittest - -from Crypto.Util.py3compat import b -from Crypto.SelfTest.st_common import list_test_cases -from binascii import unhexlify - -from Crypto.Cipher import ARC4 - -# This is a list of (plaintext, ciphertext, key[, description]) tuples. -test_data = [ - # Test vectors from Eric Rescorla's message with the subject - # "RC4 compatibility testing", sent to the cipherpunks mailing list on - # September 13, 1994. - # http://cypherpunks.venona.com/date/1994/09/msg00420.html - - ('0123456789abcdef', '75b7878099e0c596', '0123456789abcdef', - 'Test vector 0'), - - ('0000000000000000', '7494c2e7104b0879', '0123456789abcdef', - 'Test vector 1'), - - ('0000000000000000', 'de188941a3375d3a', '0000000000000000', - 'Test vector 2'), - - ('00000000000000000000', 'd6a141a7ec3c38dfbd61', 'ef012345', - 'Test vector 3'), - - ('01' * 512, - '7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76533449b6778dcad8' - + 'c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b1b13b6b919b8' - + '47c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd377108f98fd' - + 'cbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd42a1bd311d7a43' - + '03dda5ab078896ae80c18b0af66dff319616eb784e495ad2ce90d7f772a81747' - + 'b65f62093b1e0db9e5ba532fafec47508323e671327df9444432cb7367cec82f' - + '5d44c0d00b67d650a075cd4b70dedd77eb9b10231b6b5b741347396d62897421' - + 'd43df9b42e446e358e9c11a9b2184ecbef0cd8e7a877ef968f1390ec9b3d35a5' - + '585cb009290e2fcde7b5ec66d9084be44055a619d9dd7fc3166f9487f7cb2729' - + '12426445998514c15d53a18c864ce3a2b7555793988126520eacf2e3066e230c' - + '91bee4dd5304f5fd0405b35bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1' - + 'eaa595d8bfc0066ff8d31509eb0c6caa006c807a623ef84c3d33c195d23ee320' - + 'c40de0558157c822d4b8c569d849aed59d4e0fd7f379586b4b7ff684ed6a189f' - + '7486d49b9c4bad9ba24b96abf924372c8a8fffb10d55354900a77a3db5f205e1' - + 'b99fcd8660863a159ad4abe40fa48934163ddde542a6585540fd683cbfd8c00f' - + '12129a284deacc4cdefe58be7137541c047126c8d49e2755ab181ab7e940b0c0', - '0123456789abcdef', - "Test vector 4"), - # shortest key - generated with arc4 package - ('7468697320697320616e206578616d706c65', - '7260677d38495a09585d69321e17eaf3cdd0', - '01'), -] - - -class RFC6229_Tests(unittest.TestCase): - # Test vectors from RFC 6229. Each test vector is a tuple with two items: - # the ARC4 key and a dictionary. The dictionary has keystream offsets as keys - # and the 16-byte keystream starting at the relevant offset as value. - rfc6229_data = [ - # Page 3 - ( - '0102030405', - { - 0: 'b2 39 63 05 f0 3d c0 27 cc c3 52 4a 0a 11 18 a8', - 16: '69 82 94 4f 18 fc 82 d5 89 c4 03 a4 7a 0d 09 19', - 240: '28 cb 11 32 c9 6c e2 86 42 1d ca ad b8 b6 9e ae', - 256: '1c fc f6 2b 03 ed db 64 1d 77 df cf 7f 8d 8c 93', - 496: '42 b7 d0 cd d9 18 a8 a3 3d d5 17 81 c8 1f 40 41', - 512: '64 59 84 44 32 a7 da 92 3c fb 3e b4 98 06 61 f6', - 752: 'ec 10 32 7b de 2b ee fd 18 f9 27 76 80 45 7e 22', - 768: 'eb 62 63 8d 4f 0b a1 fe 9f ca 20 e0 5b f8 ff 2b', - 1008: '45 12 90 48 e6 a0 ed 0b 56 b4 90 33 8f 07 8d a5', - 1024: '30 ab bc c7 c2 0b 01 60 9f 23 ee 2d 5f 6b b7 df', - 1520: '32 94 f7 44 d8 f9 79 05 07 e7 0f 62 e5 bb ce ea', - 1536: 'd8 72 9d b4 18 82 25 9b ee 4f 82 53 25 f5 a1 30', - 2032: '1e b1 4a 0c 13 b3 bf 47 fa 2a 0b a9 3a d4 5b 8b', - 2048: 'cc 58 2f 8b a9 f2 65 e2 b1 be 91 12 e9 75 d2 d7', - 3056: 'f2 e3 0f 9b d1 02 ec bf 75 aa ad e9 bc 35 c4 3c', - 3072: 'ec 0e 11 c4 79 dc 32 9d c8 da 79 68 fe 96 56 81', - 4080: '06 83 26 a2 11 84 16 d2 1f 9d 04 b2 cd 1c a0 50', - 4096: 'ff 25 b5 89 95 99 67 07 e5 1f bd f0 8b 34 d8 75' - } - ), - # Page 4 - ( - '01020304050607', - { - 0: '29 3f 02 d4 7f 37 c9 b6 33 f2 af 52 85 fe b4 6b', - 16: 'e6 20 f1 39 0d 19 bd 84 e2 e0 fd 75 20 31 af c1', - 240: '91 4f 02 53 1c 92 18 81 0d f6 0f 67 e3 38 15 4c', - 256: 'd0 fd b5 83 07 3c e8 5a b8 39 17 74 0e c0 11 d5', - 496: '75 f8 14 11 e8 71 cf fa 70 b9 0c 74 c5 92 e4 54', - 512: '0b b8 72 02 93 8d ad 60 9e 87 a5 a1 b0 79 e5 e4', - 752: 'c2 91 12 46 b6 12 e7 e7 b9 03 df ed a1 da d8 66', - 768: '32 82 8f 91 50 2b 62 91 36 8d e8 08 1d e3 6f c2', - 1008: 'f3 b9 a7 e3 b2 97 bf 9a d8 04 51 2f 90 63 ef f1', - 1024: '8e cb 67 a9 ba 1f 55 a5 a0 67 e2 b0 26 a3 67 6f', - 1520: 'd2 aa 90 2b d4 2d 0d 7c fd 34 0c d4 58 10 52 9f', - 1536: '78 b2 72 c9 6e 42 ea b4 c6 0b d9 14 e3 9d 06 e3', - 2032: 'f4 33 2f d3 1a 07 93 96 ee 3c ee 3f 2a 4f f0 49', - 2048: '05 45 97 81 d4 1f da 7f 30 c1 be 7e 12 46 c6 23', - 3056: 'ad fd 38 68 b8 e5 14 85 d5 e6 10 01 7e 3d d6 09', - 3072: 'ad 26 58 1c 0c 5b e4 5f 4c ea 01 db 2f 38 05 d5', - 4080: 'f3 17 2c ef fc 3b 3d 99 7c 85 cc d5 af 1a 95 0c', - 4096: 'e7 4b 0b 97 31 22 7f d3 7c 0e c0 8a 47 dd d8 b8' - } - ), - ( - '0102030405060708', - { - 0: '97 ab 8a 1b f0 af b9 61 32 f2 f6 72 58 da 15 a8', - 16: '82 63 ef db 45 c4 a1 86 84 ef 87 e6 b1 9e 5b 09', - 240: '96 36 eb c9 84 19 26 f4 f7 d1 f3 62 bd df 6e 18', - 256: 'd0 a9 90 ff 2c 05 fe f5 b9 03 73 c9 ff 4b 87 0a', - 496: '73 23 9f 1d b7 f4 1d 80 b6 43 c0 c5 25 18 ec 63', - 512: '16 3b 31 99 23 a6 bd b4 52 7c 62 61 26 70 3c 0f', - 752: '49 d6 c8 af 0f 97 14 4a 87 df 21 d9 14 72 f9 66', - 768: '44 17 3a 10 3b 66 16 c5 d5 ad 1c ee 40 c8 63 d0', - 1008: '27 3c 9c 4b 27 f3 22 e4 e7 16 ef 53 a4 7d e7 a4', - 1024: 'c6 d0 e7 b2 26 25 9f a9 02 34 90 b2 61 67 ad 1d', - 1520: '1f e8 98 67 13 f0 7c 3d 9a e1 c1 63 ff 8c f9 d3', - 1536: '83 69 e1 a9 65 61 0b e8 87 fb d0 c7 91 62 aa fb', - 2032: '0a 01 27 ab b4 44 84 b9 fb ef 5a bc ae 1b 57 9f', - 2048: 'c2 cd ad c6 40 2e 8e e8 66 e1 f3 7b db 47 e4 2c', - 3056: '26 b5 1e a3 7d f8 e1 d6 f7 6f c3 b6 6a 74 29 b3', - 3072: 'bc 76 83 20 5d 4f 44 3d c1 f2 9d da 33 15 c8 7b', - 4080: 'd5 fa 5a 34 69 d2 9a aa f8 3d 23 58 9d b8 c8 5b', - 4096: '3f b4 6e 2c 8f 0f 06 8e dc e8 cd cd 7d fc 58 62' - } - ), - # Page 5 - ( - '0102030405060708090a', - { - 0: 'ed e3 b0 46 43 e5 86 cc 90 7d c2 18 51 70 99 02', - 16: '03 51 6b a7 8f 41 3b eb 22 3a a5 d4 d2 df 67 11', - 240: '3c fd 6c b5 8e e0 fd de 64 01 76 ad 00 00 04 4d', - 256: '48 53 2b 21 fb 60 79 c9 11 4c 0f fd 9c 04 a1 ad', - 496: '3e 8c ea 98 01 71 09 97 90 84 b1 ef 92 f9 9d 86', - 512: 'e2 0f b4 9b db 33 7e e4 8b 8d 8d c0 f4 af ef fe', - 752: '5c 25 21 ea cd 79 66 f1 5e 05 65 44 be a0 d3 15', - 768: 'e0 67 a7 03 19 31 a2 46 a6 c3 87 5d 2f 67 8a cb', - 1008: 'a6 4f 70 af 88 ae 56 b6 f8 75 81 c0 e2 3e 6b 08', - 1024: 'f4 49 03 1d e3 12 81 4e c6 f3 19 29 1f 4a 05 16', - 1520: 'bd ae 85 92 4b 3c b1 d0 a2 e3 3a 30 c6 d7 95 99', - 1536: '8a 0f ed db ac 86 5a 09 bc d1 27 fb 56 2e d6 0a', - 2032: 'b5 5a 0a 5b 51 a1 2a 8b e3 48 99 c3 e0 47 51 1a', - 2048: 'd9 a0 9c ea 3c e7 5f e3 96 98 07 03 17 a7 13 39', - 3056: '55 22 25 ed 11 77 f4 45 84 ac 8c fa 6c 4e b5 fc', - 3072: '7e 82 cb ab fc 95 38 1b 08 09 98 44 21 29 c2 f8', - 4080: '1f 13 5e d1 4c e6 0a 91 36 9d 23 22 be f2 5e 3c', - 4096: '08 b6 be 45 12 4a 43 e2 eb 77 95 3f 84 dc 85 53' - } - ), - ( - '0102030405060708090a0b0c0d0e0f10', - { - 0: '9a c7 cc 9a 60 9d 1e f7 b2 93 28 99 cd e4 1b 97', - 16: '52 48 c4 95 90 14 12 6a 6e 8a 84 f1 1d 1a 9e 1c', - 240: '06 59 02 e4 b6 20 f6 cc 36 c8 58 9f 66 43 2f 2b', - 256: 'd3 9d 56 6b c6 bc e3 01 07 68 15 15 49 f3 87 3f', - 496: 'b6 d1 e6 c4 a5 e4 77 1c ad 79 53 8d f2 95 fb 11', - 512: 'c6 8c 1d 5c 55 9a 97 41 23 df 1d bc 52 a4 3b 89', - 752: 'c5 ec f8 8d e8 97 fd 57 fe d3 01 70 1b 82 a2 59', - 768: 'ec cb e1 3d e1 fc c9 1c 11 a0 b2 6c 0b c8 fa 4d', - 1008: 'e7 a7 25 74 f8 78 2a e2 6a ab cf 9e bc d6 60 65', - 1024: 'bd f0 32 4e 60 83 dc c6 d3 ce dd 3c a8 c5 3c 16', - 1520: 'b4 01 10 c4 19 0b 56 22 a9 61 16 b0 01 7e d2 97', - 1536: 'ff a0 b5 14 64 7e c0 4f 63 06 b8 92 ae 66 11 81', - 2032: 'd0 3d 1b c0 3c d3 3d 70 df f9 fa 5d 71 96 3e bd', - 2048: '8a 44 12 64 11 ea a7 8b d5 1e 8d 87 a8 87 9b f5', - 3056: 'fa be b7 60 28 ad e2 d0 e4 87 22 e4 6c 46 15 a3', - 3072: 'c0 5d 88 ab d5 03 57 f9 35 a6 3c 59 ee 53 76 23', - 4080: 'ff 38 26 5c 16 42 c1 ab e8 d3 c2 fe 5e 57 2b f8', - 4096: 'a3 6a 4c 30 1a e8 ac 13 61 0c cb c1 22 56 ca cc' - } - ), - # Page 6 - ( - '0102030405060708090a0b0c0d0e0f101112131415161718', - { - 0: '05 95 e5 7f e5 f0 bb 3c 70 6e da c8 a4 b2 db 11', - 16: 'df de 31 34 4a 1a f7 69 c7 4f 07 0a ee 9e 23 26', - 240: 'b0 6b 9b 1e 19 5d 13 d8 f4 a7 99 5c 45 53 ac 05', - 256: '6b d2 37 8e c3 41 c9 a4 2f 37 ba 79 f8 8a 32 ff', - 496: 'e7 0b ce 1d f7 64 5a db 5d 2c 41 30 21 5c 35 22', - 512: '9a 57 30 c7 fc b4 c9 af 51 ff da 89 c7 f1 ad 22', - 752: '04 85 05 5f d4 f6 f0 d9 63 ef 5a b9 a5 47 69 82', - 768: '59 1f c6 6b cd a1 0e 45 2b 03 d4 55 1f 6b 62 ac', - 1008: '27 53 cc 83 98 8a fa 3e 16 88 a1 d3 b4 2c 9a 02', - 1024: '93 61 0d 52 3d 1d 3f 00 62 b3 c2 a3 bb c7 c7 f0', - 1520: '96 c2 48 61 0a ad ed fe af 89 78 c0 3d e8 20 5a', - 1536: '0e 31 7b 3d 1c 73 b9 e9 a4 68 8f 29 6d 13 3a 19', - 2032: 'bd f0 e6 c3 cc a5 b5 b9 d5 33 b6 9c 56 ad a1 20', - 2048: '88 a2 18 b6 e2 ec e1 e6 24 6d 44 c7 59 d1 9b 10', - 3056: '68 66 39 7e 95 c1 40 53 4f 94 26 34 21 00 6e 40', - 3072: '32 cb 0a 1e 95 42 c6 b3 b8 b3 98 ab c3 b0 f1 d5', - 4080: '29 a0 b8 ae d5 4a 13 23 24 c6 2e 42 3f 54 b4 c8', - 4096: '3c b0 f3 b5 02 0a 98 b8 2a f9 fe 15 44 84 a1 68' - } - ), - ( - '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - { - 0: 'ea a6 bd 25 88 0b f9 3d 3f 5d 1e 4c a2 61 1d 91', - 16: 'cf a4 5c 9f 7e 71 4b 54 bd fa 80 02 7c b1 43 80', - 240: '11 4a e3 44 de d7 1b 35 f2 e6 0f eb ad 72 7f d8', - 256: '02 e1 e7 05 6b 0f 62 39 00 49 64 22 94 3e 97 b6', - 496: '91 cb 93 c7 87 96 4e 10 d9 52 7d 99 9c 6f 93 6b', - 512: '49 b1 8b 42 f8 e8 36 7c be b5 ef 10 4b a1 c7 cd', - 752: '87 08 4b 3b a7 00 ba de 95 56 10 67 27 45 b3 74', - 768: 'e7 a7 b9 e9 ec 54 0d 5f f4 3b db 12 79 2d 1b 35', - 1008: 'c7 99 b5 96 73 8f 6b 01 8c 76 c7 4b 17 59 bd 90', - 1024: '7f ec 5b fd 9f 9b 89 ce 65 48 30 90 92 d7 e9 58', - 1520: '40 f2 50 b2 6d 1f 09 6a 4a fd 4c 34 0a 58 88 15', - 1536: '3e 34 13 5c 79 db 01 02 00 76 76 51 cf 26 30 73', - 2032: 'f6 56 ab cc f8 8d d8 27 02 7b 2c e9 17 d4 64 ec', - 2048: '18 b6 25 03 bf bc 07 7f ba bb 98 f2 0d 98 ab 34', - 3056: '8a ed 95 ee 5b 0d cb fb ef 4e b2 1d 3a 3f 52 f9', - 3072: '62 5a 1a b0 0e e3 9a 53 27 34 6b dd b0 1a 9c 18', - 4080: 'a1 3a 7c 79 c7 e1 19 b5 ab 02 96 ab 28 c3 00 b9', - 4096: 'f3 e4 c0 a2 e0 2d 1d 01 f7 f0 a7 46 18 af 2b 48' - } - ), - # Page 7 - ( - '833222772a', - { - 0: '80 ad 97 bd c9 73 df 8a 2e 87 9e 92 a4 97 ef da', - 16: '20 f0 60 c2 f2 e5 12 65 01 d3 d4 fe a1 0d 5f c0', - 240: 'fa a1 48 e9 90 46 18 1f ec 6b 20 85 f3 b2 0e d9', - 256: 'f0 da f5 ba b3 d5 96 83 98 57 84 6f 73 fb fe 5a', - 496: '1c 7e 2f c4 63 92 32 fe 29 75 84 b2 96 99 6b c8', - 512: '3d b9 b2 49 40 6c c8 ed ff ac 55 cc d3 22 ba 12', - 752: 'e4 f9 f7 e0 06 61 54 bb d1 25 b7 45 56 9b c8 97', - 768: '75 d5 ef 26 2b 44 c4 1a 9c f6 3a e1 45 68 e1 b9', - 1008: '6d a4 53 db f8 1e 82 33 4a 3d 88 66 cb 50 a1 e3', - 1024: '78 28 d0 74 11 9c ab 5c 22 b2 94 d7 a9 bf a0 bb', - 1520: 'ad b8 9c ea 9a 15 fb e6 17 29 5b d0 4b 8c a0 5c', - 1536: '62 51 d8 7f d4 aa ae 9a 7e 4a d5 c2 17 d3 f3 00', - 2032: 'e7 11 9b d6 dd 9b 22 af e8 f8 95 85 43 28 81 e2', - 2048: '78 5b 60 fd 7e c4 e9 fc b6 54 5f 35 0d 66 0f ab', - 3056: 'af ec c0 37 fd b7 b0 83 8e b3 d7 0b cd 26 83 82', - 3072: 'db c1 a7 b4 9d 57 35 8c c9 fa 6d 61 d7 3b 7c f0', - 4080: '63 49 d1 26 a3 7a fc ba 89 79 4f 98 04 91 4f dc', - 4096: 'bf 42 c3 01 8c 2f 7c 66 bf de 52 49 75 76 81 15' - } - ), - ( - '1910833222772a', - { - 0: 'bc 92 22 db d3 27 4d 8f c6 6d 14 cc bd a6 69 0b', - 16: '7a e6 27 41 0c 9a 2b e6 93 df 5b b7 48 5a 63 e3', - 240: '3f 09 31 aa 03 de fb 30 0f 06 01 03 82 6f 2a 64', - 256: 'be aa 9e c8 d5 9b b6 81 29 f3 02 7c 96 36 11 81', - 496: '74 e0 4d b4 6d 28 64 8d 7d ee 8a 00 64 b0 6c fe', - 512: '9b 5e 81 c6 2f e0 23 c5 5b e4 2f 87 bb f9 32 b8', - 752: 'ce 17 8f c1 82 6e fe cb c1 82 f5 79 99 a4 61 40', - 768: '8b df 55 cd 55 06 1c 06 db a6 be 11 de 4a 57 8a', - 1008: '62 6f 5f 4d ce 65 25 01 f3 08 7d 39 c9 2c c3 49', - 1024: '42 da ac 6a 8f 9a b9 a7 fd 13 7c 60 37 82 56 82', - 1520: 'cc 03 fd b7 91 92 a2 07 31 2f 53 f5 d4 dc 33 d9', - 1536: 'f7 0f 14 12 2a 1c 98 a3 15 5d 28 b8 a0 a8 a4 1d', - 2032: '2a 3a 30 7a b2 70 8a 9c 00 fe 0b 42 f9 c2 d6 a1', - 2048: '86 26 17 62 7d 22 61 ea b0 b1 24 65 97 ca 0a e9', - 3056: '55 f8 77 ce 4f 2e 1d db bf 8e 13 e2 cd e0 fd c8', - 3072: '1b 15 56 cb 93 5f 17 33 37 70 5f bb 5d 50 1f c1', - 4080: 'ec d0 e9 66 02 be 7f 8d 50 92 81 6c cc f2 c2 e9', - 4096: '02 78 81 fa b4 99 3a 1c 26 20 24 a9 4f ff 3f 61' - } - ), - # Page 8 - ( - '641910833222772a', - { - 0: 'bb f6 09 de 94 13 17 2d 07 66 0c b6 80 71 69 26', - 16: '46 10 1a 6d ab 43 11 5d 6c 52 2b 4f e9 36 04 a9', - 240: 'cb e1 ff f2 1c 96 f3 ee f6 1e 8f e0 54 2c bd f0', - 256: '34 79 38 bf fa 40 09 c5 12 cf b4 03 4b 0d d1 a7', - 496: '78 67 a7 86 d0 0a 71 47 90 4d 76 dd f1 e5 20 e3', - 512: '8d 3e 9e 1c ae fc cc b3 fb f8 d1 8f 64 12 0b 32', - 752: '94 23 37 f8 fd 76 f0 fa e8 c5 2d 79 54 81 06 72', - 768: 'b8 54 8c 10 f5 16 67 f6 e6 0e 18 2f a1 9b 30 f7', - 1008: '02 11 c7 c6 19 0c 9e fd 12 37 c3 4c 8f 2e 06 c4', - 1024: 'bd a6 4f 65 27 6d 2a ac b8 f9 02 12 20 3a 80 8e', - 1520: 'bd 38 20 f7 32 ff b5 3e c1 93 e7 9d 33 e2 7c 73', - 1536: 'd0 16 86 16 86 19 07 d4 82 e3 6c da c8 cf 57 49', - 2032: '97 b0 f0 f2 24 b2 d2 31 71 14 80 8f b0 3a f7 a0', - 2048: 'e5 96 16 e4 69 78 79 39 a0 63 ce ea 9a f9 56 d1', - 3056: 'c4 7e 0d c1 66 09 19 c1 11 01 20 8f 9e 69 aa 1f', - 3072: '5a e4 f1 28 96 b8 37 9a 2a ad 89 b5 b5 53 d6 b0', - 4080: '6b 6b 09 8d 0c 29 3b c2 99 3d 80 bf 05 18 b6 d9', - 4096: '81 70 cc 3c cd 92 a6 98 62 1b 93 9d d3 8f e7 b9' - } - ), - ( - '8b37641910833222772a', - { - 0: 'ab 65 c2 6e dd b2 87 60 0d b2 fd a1 0d 1e 60 5c', - 16: 'bb 75 90 10 c2 96 58 f2 c7 2d 93 a2 d1 6d 29 30', - 240: 'b9 01 e8 03 6e d1 c3 83 cd 3c 4c 4d d0 a6 ab 05', - 256: '3d 25 ce 49 22 92 4c 55 f0 64 94 33 53 d7 8a 6c', - 496: '12 c1 aa 44 bb f8 7e 75 e6 11 f6 9b 2c 38 f4 9b', - 512: '28 f2 b3 43 4b 65 c0 98 77 47 00 44 c6 ea 17 0d', - 752: 'bd 9e f8 22 de 52 88 19 61 34 cf 8a f7 83 93 04', - 768: '67 55 9c 23 f0 52 15 84 70 a2 96 f7 25 73 5a 32', - 1008: '8b ab 26 fb c2 c1 2b 0f 13 e2 ab 18 5e ab f2 41', - 1024: '31 18 5a 6d 69 6f 0c fa 9b 42 80 8b 38 e1 32 a2', - 1520: '56 4d 3d ae 18 3c 52 34 c8 af 1e 51 06 1c 44 b5', - 1536: '3c 07 78 a7 b5 f7 2d 3c 23 a3 13 5c 7d 67 b9 f4', - 2032: 'f3 43 69 89 0f cf 16 fb 51 7d ca ae 44 63 b2 dd', - 2048: '02 f3 1c 81 e8 20 07 31 b8 99 b0 28 e7 91 bf a7', - 3056: '72 da 64 62 83 22 8c 14 30 08 53 70 17 95 61 6f', - 3072: '4e 0a 8c 6f 79 34 a7 88 e2 26 5e 81 d6 d0 c8 f4', - 4080: '43 8d d5 ea fe a0 11 1b 6f 36 b4 b9 38 da 2a 68', - 4096: '5f 6b fc 73 81 58 74 d9 71 00 f0 86 97 93 57 d8' - } - ), - # Page 9 - ( - 'ebb46227c6cc8b37641910833222772a', - { - 0: '72 0c 94 b6 3e df 44 e1 31 d9 50 ca 21 1a 5a 30', - 16: 'c3 66 fd ea cf 9c a8 04 36 be 7c 35 84 24 d2 0b', - 240: 'b3 39 4a 40 aa bf 75 cb a4 22 82 ef 25 a0 05 9f', - 256: '48 47 d8 1d a4 94 2d bc 24 9d ef c4 8c 92 2b 9f', - 496: '08 12 8c 46 9f 27 53 42 ad da 20 2b 2b 58 da 95', - 512: '97 0d ac ef 40 ad 98 72 3b ac 5d 69 55 b8 17 61', - 752: '3c b8 99 93 b0 7b 0c ed 93 de 13 d2 a1 10 13 ac', - 768: 'ef 2d 67 6f 15 45 c2 c1 3d c6 80 a0 2f 4a db fe', - 1008: 'b6 05 95 51 4f 24 bc 9f e5 22 a6 ca d7 39 36 44', - 1024: 'b5 15 a8 c5 01 17 54 f5 90 03 05 8b db 81 51 4e', - 1520: '3c 70 04 7e 8c bc 03 8e 3b 98 20 db 60 1d a4 95', - 1536: '11 75 da 6e e7 56 de 46 a5 3e 2b 07 56 60 b7 70', - 2032: '00 a5 42 bb a0 21 11 cc 2c 65 b3 8e bd ba 58 7e', - 2048: '58 65 fd bb 5b 48 06 41 04 e8 30 b3 80 f2 ae de', - 3056: '34 b2 1a d2 ad 44 e9 99 db 2d 7f 08 63 f0 d9 b6', - 3072: '84 a9 21 8f c3 6e 8a 5f 2c cf be ae 53 a2 7d 25', - 4080: 'a2 22 1a 11 b8 33 cc b4 98 a5 95 40 f0 54 5f 4a', - 4096: '5b be b4 78 7d 59 e5 37 3f db ea 6c 6f 75 c2 9b' - } - ), - ( - 'c109163908ebe51debb46227c6cc8b37641910833222772a', - { - 0: '54 b6 4e 6b 5a 20 b5 e2 ec 84 59 3d c7 98 9d a7', - 16: 'c1 35 ee e2 37 a8 54 65 ff 97 dc 03 92 4f 45 ce', - 240: 'cf cc 92 2f b4 a1 4a b4 5d 61 75 aa bb f2 d2 01', - 256: '83 7b 87 e2 a4 46 ad 0e f7 98 ac d0 2b 94 12 4f', - 496: '17 a6 db d6 64 92 6a 06 36 b3 f4 c3 7a 4f 46 94', - 512: '4a 5f 9f 26 ae ee d4 d4 a2 5f 63 2d 30 52 33 d9', - 752: '80 a3 d0 1e f0 0c 8e 9a 42 09 c1 7f 4e eb 35 8c', - 768: 'd1 5e 7d 5f fa aa bc 02 07 bf 20 0a 11 77 93 a2', - 1008: '34 96 82 bf 58 8e aa 52 d0 aa 15 60 34 6a ea fa', - 1024: 'f5 85 4c db 76 c8 89 e3 ad 63 35 4e 5f 72 75 e3', - 1520: '53 2c 7c ec cb 39 df 32 36 31 84 05 a4 b1 27 9c', - 1536: 'ba ef e6 d9 ce b6 51 84 22 60 e0 d1 e0 5e 3b 90', - 2032: 'e8 2d 8c 6d b5 4e 3c 63 3f 58 1c 95 2b a0 42 07', - 2048: '4b 16 e5 0a bd 38 1b d7 09 00 a9 cd 9a 62 cb 23', - 3056: '36 82 ee 33 bd 14 8b d9 f5 86 56 cd 8f 30 d9 fb', - 3072: '1e 5a 0b 84 75 04 5d 9b 20 b2 62 86 24 ed fd 9e', - 4080: '63 ed d6 84 fb 82 62 82 fe 52 8f 9c 0e 92 37 bc', - 4096: 'e4 dd 2e 98 d6 96 0f ae 0b 43 54 54 56 74 33 91' - } - ), - # Page 10 - ( - '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a', - { - 0: 'dd 5b cb 00 18 e9 22 d4 94 75 9d 7c 39 5d 02 d3', - 16: 'c8 44 6f 8f 77 ab f7 37 68 53 53 eb 89 a1 c9 eb', - 240: 'af 3e 30 f9 c0 95 04 59 38 15 15 75 c3 fb 90 98', - 256: 'f8 cb 62 74 db 99 b8 0b 1d 20 12 a9 8e d4 8f 0e', - 496: '25 c3 00 5a 1c b8 5d e0 76 25 98 39 ab 71 98 ab', - 512: '9d cb c1 83 e8 cb 99 4b 72 7b 75 be 31 80 76 9c', - 752: 'a1 d3 07 8d fa 91 69 50 3e d9 d4 49 1d ee 4e b2', - 768: '85 14 a5 49 58 58 09 6f 59 6e 4b cd 66 b1 06 65', - 1008: '5f 40 d5 9e c1 b0 3b 33 73 8e fa 60 b2 25 5d 31', - 1024: '34 77 c7 f7 64 a4 1b ac ef f9 0b f1 4f 92 b7 cc', - 1520: 'ac 4e 95 36 8d 99 b9 eb 78 b8 da 8f 81 ff a7 95', - 1536: '8c 3c 13 f8 c2 38 8b b7 3f 38 57 6e 65 b7 c4 46', - 2032: '13 c4 b9 c1 df b6 65 79 ed dd 8a 28 0b 9f 73 16', - 2048: 'dd d2 78 20 55 01 26 69 8e fa ad c6 4b 64 f6 6e', - 3056: 'f0 8f 2e 66 d2 8e d1 43 f3 a2 37 cf 9d e7 35 59', - 3072: '9e a3 6c 52 55 31 b8 80 ba 12 43 34 f5 7b 0b 70', - 4080: 'd5 a3 9e 3d fc c5 02 80 ba c4 a6 b5 aa 0d ca 7d', - 4096: '37 0b 1c 1f e6 55 91 6d 97 fd 0d 47 ca 1d 72 b8' - } - ) - ] - - def test_keystream(self): - for tv in self.rfc6229_data: - key = unhexlify(b((tv[0]))) - cipher = ARC4.new(key) - count = 0 - for offset in range(0, 4096+1, 16): - ct = cipher.encrypt(b('\x00')*16) - expected = tv[1].get(offset) - if expected: - expected = unhexlify(b(expected.replace(" ", ''))) - self.assertEqual(ct, expected) - count += 1 - self.assertEqual(count, len(tv[1])) - - -class Drop_Tests(unittest.TestCase): - key = b('\xAA')*16 - data = b('\x00')*5000 - - def setUp(self): - self.cipher = ARC4.new(self.key) - - def test_drop256_encrypt(self): - cipher_drop = ARC4.new(self.key, 256) - ct_drop = cipher_drop.encrypt(self.data[:16]) - ct = self.cipher.encrypt(self.data)[256:256+16] - self.assertEqual(ct_drop, ct) - - def test_drop256_decrypt(self): - cipher_drop = ARC4.new(self.key, 256) - pt_drop = cipher_drop.decrypt(self.data[:16]) - pt = self.cipher.decrypt(self.data)[256:256+16] - self.assertEqual(pt_drop, pt) - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, ARC4.new, b'') - self.assertRaises(ValueError, ARC4.new, b'\x00' * 257) - - -def get_tests(config={}): - from .common import make_stream_tests - tests = make_stream_tests(ARC4, "ARC4", test_data) - tests += list_test_cases(RFC6229_Tests) - tests += list_test_cases(Drop_Tests) - tests.append(KeyLength()) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Blowfish.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Blowfish.py deleted file mode 100644 index 4ce3a41..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Blowfish.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_Blowfish.py: Self-test for the Blowfish cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.Blowfish""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.Cipher import Blowfish - -# This is a list of (plaintext, ciphertext, key) tuples. -test_data = [ - # Test vectors from http://www.schneier.com/code/vectors.txt - ('0000000000000000', '4ef997456198dd78', '0000000000000000'), - ('ffffffffffffffff', '51866fd5b85ecb8a', 'ffffffffffffffff'), - ('1000000000000001', '7d856f9a613063f2', '3000000000000000'), - ('1111111111111111', '2466dd878b963c9d', '1111111111111111'), - ('1111111111111111', '61f9c3802281b096', '0123456789abcdef'), - ('0123456789abcdef', '7d0cc630afda1ec7', '1111111111111111'), - ('0000000000000000', '4ef997456198dd78', '0000000000000000'), - ('0123456789abcdef', '0aceab0fc6a0a28d', 'fedcba9876543210'), - ('01a1d6d039776742', '59c68245eb05282b', '7ca110454a1a6e57'), - ('5cd54ca83def57da', 'b1b8cc0b250f09a0', '0131d9619dc1376e'), - ('0248d43806f67172', '1730e5778bea1da4', '07a1133e4a0b2686'), - ('51454b582ddf440a', 'a25e7856cf2651eb', '3849674c2602319e'), - ('42fd443059577fa2', '353882b109ce8f1a', '04b915ba43feb5b6'), - ('059b5e0851cf143a', '48f4d0884c379918', '0113b970fd34f2ce'), - ('0756d8e0774761d2', '432193b78951fc98', '0170f175468fb5e6'), - ('762514b829bf486a', '13f04154d69d1ae5', '43297fad38e373fe'), - ('3bdd119049372802', '2eedda93ffd39c79', '07a7137045da2a16'), - ('26955f6835af609a', 'd887e0393c2da6e3', '04689104c2fd3b2f'), - ('164d5e404f275232', '5f99d04f5b163969', '37d06bb516cb7546'), - ('6b056e18759f5cca', '4a057a3b24d3977b', '1f08260d1ac2465e'), - ('004bd6ef09176062', '452031c1e4fada8e', '584023641aba6176'), - ('480d39006ee762f2', '7555ae39f59b87bd', '025816164629b007'), - ('437540c8698f3cfa', '53c55f9cb49fc019', '49793ebc79b3258f'), - ('072d43a077075292', '7a8e7bfa937e89a3', '4fb05e1515ab73a7'), - ('02fe55778117f12a', 'cf9c5d7a4986adb5', '49e95d6d4ca229bf'), - ('1d9d5c5018f728c2', 'd1abb290658bc778', '018310dc409b26d6'), - ('305532286d6f295a', '55cb3774d13ef201', '1c587f1c13924fef'), - ('0123456789abcdef', 'fa34ec4847b268b2', '0101010101010101'), - ('0123456789abcdef', 'a790795108ea3cae', '1f1f1f1f0e0e0e0e'), - ('0123456789abcdef', 'c39e072d9fac631d', 'e0fee0fef1fef1fe'), - ('ffffffffffffffff', '014933e0cdaff6e4', '0000000000000000'), - ('0000000000000000', 'f21e9a77b71c49bc', 'ffffffffffffffff'), - ('0000000000000000', '245946885754369a', '0123456789abcdef'), - ('ffffffffffffffff', '6b5c5a9c5d9e0a5a', 'fedcba9876543210'), - #('fedcba9876543210', 'f9ad597c49db005e', 'f0'), - #('fedcba9876543210', 'e91d21c1d961a6d6', 'f0e1'), - #('fedcba9876543210', 'e9c2b70a1bc65cf3', 'f0e1d2'), - ('fedcba9876543210', 'be1e639408640f05', 'f0e1d2c3'), - ('fedcba9876543210', 'b39e44481bdb1e6e', 'f0e1d2c3b4'), - ('fedcba9876543210', '9457aa83b1928c0d', 'f0e1d2c3b4a5'), - ('fedcba9876543210', '8bb77032f960629d', 'f0e1d2c3b4a596'), - ('fedcba9876543210', 'e87a244e2cc85e82', 'f0e1d2c3b4a59687'), - ('fedcba9876543210', '15750e7a4f4ec577', 'f0e1d2c3b4a5968778'), - ('fedcba9876543210', '122ba70b3ab64ae0', 'f0e1d2c3b4a596877869'), - ('fedcba9876543210', '3a833c9affc537f6', 'f0e1d2c3b4a5968778695a'), - ('fedcba9876543210', '9409da87a90f6bf2', 'f0e1d2c3b4a5968778695a4b'), - ('fedcba9876543210', '884f80625060b8b4', 'f0e1d2c3b4a5968778695a4b3c'), - ('fedcba9876543210', '1f85031c19e11968', 'f0e1d2c3b4a5968778695a4b3c2d'), - ('fedcba9876543210', '79d9373a714ca34f', 'f0e1d2c3b4a5968778695a4b3c2d1e'), - ('fedcba9876543210', '93142887ee3be15c', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f'), - ('fedcba9876543210', '03429e838ce2d14b', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00'), - ('fedcba9876543210', 'a4299e27469ff67b', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011'), - ('fedcba9876543210', 'afd5aed1c1bc96a8', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122'), - ('fedcba9876543210', '10851c0e3858da9f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233'), - ('fedcba9876543210', 'e6f51ed79b9db21f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344'), - ('fedcba9876543210', '64a6e14afd36b46f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455'), - ('fedcba9876543210', '80c7d7d45a5479ad', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566'), - ('fedcba9876543210', '05044b62fa52d080', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677'), -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, Blowfish.new, bchr(0) * 3, - Blowfish.MODE_ECB) - self.assertRaises(ValueError, Blowfish.new, bchr(0) * 57, - Blowfish.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = Blowfish.new(b'4'*16, Blowfish.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - tests = make_block_tests(Blowfish, "Blowfish", test_data) - tests.append(KeyLength()) - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CAST.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CAST.py deleted file mode 100644 index ff13bd4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CAST.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/CAST.py: Self-test for the CAST-128 (CAST5) cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.CAST""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.Cipher import CAST - -# This is a list of (plaintext, ciphertext, key) tuples. -test_data = [ - # Test vectors from RFC 2144, B.1 - ('0123456789abcdef', '238b4fe5847e44b2', - '0123456712345678234567893456789a', - '128-bit key'), - - ('0123456789abcdef', 'eb6a711a2c02271b', - '01234567123456782345', - '80-bit key'), - - ('0123456789abcdef', '7ac816d16e9b302e', - '0123456712', - '40-bit key'), -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, CAST.new, bchr(0) * 4, CAST.MODE_ECB) - self.assertRaises(ValueError, CAST.new, bchr(0) * 17, CAST.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = CAST.new(b'4'*16, CAST.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - - tests = make_block_tests(CAST, "CAST", test_data) - tests.append(KeyLength()) - tests.append(TestOutput()) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CBC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CBC.py deleted file mode 100644 index 374fb5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CBC.py +++ /dev/null @@ -1,556 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, is_string -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -class BlockChainingTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - iv_128 = get_tag_random("iv_128", 16) - iv_64 = get_tag_random("iv_64", 8) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_iv(self): - # If not passed, the iv is created randomly - cipher = AES.new(self.key_128, self.aes_mode) - iv1 = cipher.iv - cipher = AES.new(self.key_128, self.aes_mode) - iv2 = cipher.iv - self.assertNotEqual(iv1, iv2) - self.assertEqual(len(iv1), 16) - - # IV can be passed in uppercase or lowercase - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, self.aes_mode, iv=self.iv_128) - self.assertEqual(ct, cipher.encrypt(self.data_128)) - - cipher = AES.new(self.key_128, self.aes_mode, IV=self.iv_128) - self.assertEqual(ct, cipher.encrypt(self.data_128)) - - def test_iv_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv = u'test1234567890-*') - - def test_only_one_iv(self): - # Only one IV/iv keyword allowed - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv=self.iv_128, IV=self.iv_128) - - def test_iv_with_matching_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - b"") - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - self.iv_128[:15]) - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - self.iv_128 + b"0") - - def test_block_size_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_unaligned_data_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - for wrong_length in range(1,16): - self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - for wrong_length in range(1,16): - self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) - - def test_unaligned_data_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - for wrong_length in range(1,8): - self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) - - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - for wrong_length in range(1,8): - self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) - - def test_IV_iv_attributes(self): - data = get_tag_random("data", 16 * 100) - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - getattr(cipher, func)(data) - self.assertEqual(cipher.iv, self.iv_128) - self.assertEqual(cipher.IV, self.iv_128) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - self.iv_128, 7) - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv=self.iv_128, unknown=7) - # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_bytearray(self): - data = b"1" * 128 - data_ba = bytearray(data) - - # Encrypt - key_ba = bytearray(self.key_128) - iv_ba = bytearray(self.iv_128) - - cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(key_ba, self.aes_mode, iv_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - iv_ba[:3] = b'\xFF\xFF\xFF' - ref2 = cipher2.encrypt(data_ba) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.iv, cipher2.iv) - - # Decrypt - key_ba = bytearray(self.key_128) - iv_ba = bytearray(self.iv_128) - - cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(key_ba, self.aes_mode, iv_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - iv_ba[:3] = b'\xFF\xFF\xFF' - ref4 = cipher4.decrypt(data_ba) - - self.assertEqual(ref3, ref4) - - def test_memoryview(self): - data = b"1" * 128 - data_mv = memoryview(bytearray(data)) - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - iv_mv = memoryview(bytearray(self.iv_128)) - - cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(key_mv, self.aes_mode, iv_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - iv_mv[:3] = b'\xFF\xFF\xFF' - ref2 = cipher2.encrypt(data_mv) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.iv, cipher2.iv) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - iv_mv = memoryview(bytearray(self.iv_128)) - - cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(key_mv, self.aes_mode, iv_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - iv_mv[:3] = b'\xFF\xFF\xFF' - ref4 = cipher4.decrypt(data_mv) - - self.assertEqual(ref3, ref4) - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - output = bytearray(128) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - - def test_output_param_same_buffer(self): - - pt = b'5' * 128 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - pt_ba = bytearray(pt) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.encrypt(pt_ba, output=pt_ba) - self.assertEqual(ct, pt_ba) - self.assertEqual(res, None) - - ct_ba = bytearray(ct) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.decrypt(ct_ba, output=ct_ba) - self.assertEqual(pt, ct_ba) - self.assertEqual(res, None) - - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - LEN_PT = 128 - - pt = b'5' * LEN_PT - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) - - shorter_output = bytearray(LEN_PT - 1) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class CbcTests(BlockChainingTests): - aes_mode = AES.MODE_CBC - des3_mode = DES3.MODE_CBC - - -class NistBlockChainingVectors(unittest.TestCase): - - def _do_kat_aes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CBC KAT", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - - cipher = AES.new(tv.key, self.aes_mode, tv.iv) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - # See Section 6.4.2 in AESAVS - def _do_mct_aes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CBC Montecarlo", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, self.aes_mode, tv.iv) - - if direction == '[ENCRYPT]': - cts = [ tv.iv ] - for count in range(1000): - cts.append(cipher.encrypt(tv.plaintext)) - tv.plaintext = cts[-2] - self.assertEqual(cts[-1], tv.ciphertext) - elif direction == '[DECRYPT]': - pts = [ tv.iv] - for count in range(1000): - pts.append(cipher.decrypt(tv.ciphertext)) - tv.ciphertext = pts[-2] - self.assertEqual(pts[-1], tv.plaintext) - else: - assert False - - def _do_tdes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "TDES"), - file_name, - "TDES CBC KAT", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - if hasattr(tv, "keys"): - cipher = DES.new(tv.keys, self.des_mode, tv.iv) - else: - if tv.key1 != tv.key3: - key = tv.key1 + tv.key2 + tv.key3 # Option 3 - else: - key = tv.key1 + tv.key2 # Option 2 - cipher = DES3.new(key, self.des3_mode, tv.iv) - - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - -class NistCbcVectors(NistBlockChainingVectors): - aes_mode = AES.MODE_CBC - des_mode = DES.MODE_CBC - des3_mode = DES3.MODE_CBC - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "CBCGFSbox128.rsp", - "CBCGFSbox192.rsp", - "CBCGFSbox256.rsp", - "CBCKeySbox128.rsp", - "CBCKeySbox192.rsp", - "CBCKeySbox256.rsp", - "CBCVarKey128.rsp", - "CBCVarKey192.rsp", - "CBCVarKey256.rsp", - "CBCVarTxt128.rsp", - "CBCVarTxt192.rsp", - "CBCVarTxt256.rsp", - # MMT - "CBCMMT128.rsp", - "CBCMMT192.rsp", - "CBCMMT256.rsp", - ) -nist_aes_mct_files = ( - "CBCMCT128.rsp", - "CBCMCT192.rsp", - "CBCMCT256.rsp", - ) - -for file_name in nist_aes_kat_mmt_files: - def new_func(self, file_name=file_name): - self._do_kat_aes_test(file_name) - setattr(NistCbcVectors, "test_AES_" + file_name, new_func) - -for file_name in nist_aes_mct_files: - def new_func(self, file_name=file_name): - self._do_mct_aes_test(file_name) - setattr(NistCbcVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TCBCMMT2.rsp", # 2TDES - "TCBCMMT3.rsp", # 3TDES - "TCBCinvperm.rsp", # Single DES - "TCBCpermop.rsp", - "TCBCsubtab.rsp", - "TCBCvarkey.rsp", - "TCBCvartext.rsp", - ) - -for file_name in nist_tdes_files: - def new_func(self, file_name=file_name): - self._do_tdes_test(file_name) - setattr(NistCbcVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST CBC TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CBC test vectors found in Section F.2 - of NIST SP 800-3A""" - - def test_aes_128(self): - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '7649abac8119b246cee98e9b12e9197d' +\ - '5086cb9b507219ee95db113a917678b2' +\ - '73bed6b8e3c1743b7116e69e22229516' +\ - '3ff1caa1681fac09120eca307586e1a7' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192(self): - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '4f021db243bc633d7178183a9fa071e8' +\ - 'b4d9ada9ad7dedf4e5e738763f69145a' +\ - '571b242012fb7ae07fa9baac3df102e0' +\ - '08b0e27988598881d920a9e64f5615cd' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256(self): - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'f58c4c04d6e5f1ba779eabfb5f7bfbd6' +\ - '9cfc4e967edb808d679f777bc6702c7d' +\ - '39f23369a9d9bacfa530e26304231461' +\ - 'b2eb05e2c39be9fcda6c19078c6a9d1b' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CbcTests) - if config.get('slow_tests'): - tests += list_test_cases(NistCbcVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CCM.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CCM.py deleted file mode 100644 index 23b8989..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CCM.py +++ /dev/null @@ -1,970 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - -from Crypto.Cipher._mode_ccm import CCMMessageTooLongError - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class CcmTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # If not passed, the nonce is created randomly - cipher = AES.new(self.key_128, AES.MODE_CCM) - nonce1 = cipher.nonce - cipher = AES.new(self.key_128, AES.MODE_CCM) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 11) - self.assertNotEqual(nonce1, nonce2) - - cipher = AES.new(self.key_128, AES.MODE_CCM, self.nonce_96) - ct = cipher.encrypt(self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEqual(ct, cipher.encrypt(self.data)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - nonce=u'test12345678') - - def test_nonce_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=b"") - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=bchr(1) * 6) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=bchr(1) * 14) - for x in range(7, 13 + 1): - AES.new(self.key_128, AES.MODE_CCM, nonce=bchr(1) * x) - - def test_block_size(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 11 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_CCM).nonce - nonce2 = AES.new(self.key_128, AES.MODE_CCM).nonce - self.assertEqual(len(nonce1), 11) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - for mac_len in range(3, 17 + 1, 2): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, mac_len=mac_len) - - # Valid MAC length - for mac_len in range(4, 16 + 1, 2): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_longer_assoc_data_than_declared(self): - # More than zero - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=0) - self.assertRaises(ValueError, cipher.update, b"1") - - # Too large - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=15) - self.assertRaises(ValueError, cipher.update, self.data) - - def test_shorter_assoc_data_than_expected(self): - DATA_LEN = len(self.data) - - # With plaintext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=DATA_LEN + 1) - cipher.update(self.data) - self.assertRaises(ValueError, cipher.encrypt, self.data) - - # With empty plaintext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=DATA_LEN + 1) - cipher.update(self.data) - self.assertRaises(ValueError, cipher.digest) - - # With ciphertext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=DATA_LEN + 1) - cipher.update(self.data) - self.assertRaises(ValueError, cipher.decrypt, self.data) - - # With empty ciphertext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=DATA_LEN + 1) - cipher.update(self.data) - self.assertRaises(ValueError, cipher.verify, mac) - - def test_shorter_and_longer_plaintext_than_declared(self): - DATA_LEN = len(self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=DATA_LEN + 1) - cipher.encrypt(self.data) - self.assertRaises(ValueError, cipher.digest) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=DATA_LEN - 1) - self.assertRaises(ValueError, cipher.encrypt, self.data) - - def test_shorter_ciphertext_than_declared(self): - DATA_LEN = len(self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=DATA_LEN + 1) - cipher.decrypt(ct) - self.assertRaises(ValueError, cipher.verify, mac) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=DATA_LEN - 1) - self.assertRaises(ValueError, cipher.decrypt, ct) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=127, assoc_len=127) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=127, assoc_len=127) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEqual(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - data_ba = bytearray(self.data) - - cipher1 = AES.new(self.key_128, - AES.MODE_CCM, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_CCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_CCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - data_mv = memoryview(bytearray(self.data)) - - cipher1 = AES.new(self.key_128, - AES.MODE_CCM, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_CCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_CCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data, pt_test) - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(128) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - def test_message_too_long(self): - - nonce = b'N' * 13 - self.assertRaises(CCMMessageTooLongError, - AES.new, - self.key_128, - AES.MODE_CCM, - nonce=nonce, - assoc_len=20, - msg_len=0x10000) - - nonce = b'N' * 7 - self.assertRaises(CCMMessageTooLongError, - AES.new, - self.key_128, - AES.MODE_CCM, - nonce=nonce, - assoc_len=20, - msg_len=2**64) - - nonce = b'N' * 13 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce) - self.assertRaises(CCMMessageTooLongError, - cipher.encrypt, - b'C' * 0x10000) - - nonce = b'N' * 13 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce) - self.assertRaises(CCMMessageTooLongError, - cipher.decrypt, - b'C' * 0x10000) - - -class CcmFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - for assoc_len in (None, 0): - for msg_len in (None, len(self.data)): - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - for assoc_len in (None, len(self.data)): - for msg_len in (None, 0): - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - for assoc_len in (None, len(self.data)): - for msg_len in (None, len(self.data)): - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - # Only possible if msg_len is declared in advance - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data, - self.data + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - msg_len=64, - assoc_len=assoc_len) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data) - method(self.data) - method(self.data) - method(self.data) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data) - ct, mac = cipher.encrypt_and_digest(self.data) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data, pt) - - def test_invalid_multiple_encrypt_decrypt_without_msg_len(self): - # Once per method, with or without assoc. data - for method_name in "encrypt", "decrypt": - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data) - method = getattr(cipher, method_name) - method(self.data) - self.assertRaises(TypeError, method, self.data) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - msg_len=32) - if assoc_data_present: - cipher.update(self.data) - getattr(cipher, method1_name)(self.data) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(self.data) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - -class TestVectors(unittest.TestCase): - """Class exercising the CCM test vectors found in Appendix C - of NIST SP 800-38C and in RFC 3610""" - - # List of test vectors, each made up of: - # - authenticated data - # - plaintext - # - ciphertext - # - MAC - # - AES key - # - nonce - test_vectors_hex = [ - # NIST SP 800 38C - ( '0001020304050607', - '20212223', - '7162015b', - '4dac255d', - '404142434445464748494a4b4c4d4e4f', - '10111213141516'), - ( '000102030405060708090a0b0c0d0e0f', - '202122232425262728292a2b2c2d2e2f', - 'd2a1f0e051ea5f62081a7792073d593d', - '1fc64fbfaccd', - '404142434445464748494a4b4c4d4e4f', - '1011121314151617'), - ( '000102030405060708090a0b0c0d0e0f10111213', - '202122232425262728292a2b2c2d2e2f3031323334353637', - 'e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5', - '484392fbc1b09951', - '404142434445464748494a4b4c4d4e4f', - '101112131415161718191a1b'), - ( (''.join(["%02X" % (x*16+y) for x in range(0,16) for y in range(0,16)]))*256, - '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', - '69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72', - 'b4ac6bec93e8598e7f0dadbcea5b', - '404142434445464748494a4b4c4d4e4f', - '101112131415161718191a1b1c'), - # RFC3610 - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', - '588c979a61c663d2f066d0c2c0f989806d5f6b61dac384', - '17e8d12cfdf926e0', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000003020100a0a1a2a3a4a5'), - ( - '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b', - 'a091d56e10400916', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000004030201a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657', - '4adaa76fbd9fb0c5', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000005040302A0A1A2A3A4A5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e', - 'a28c6865939a9a79faaa5c4c2a9d4a91cdac8c', - '96c861b9c9e61ef1', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000006050403a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e', - '51e83f077d9c2d93', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000007060504a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '6fc1b011f006568b5171a42d953d469b2570a4bd87', - '405a0443ac91cb94', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000008070605a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', - '0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c', - '048c56602c97acbb7490', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000009080706a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24', - 'c17b4433f434963f34b4', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000a090807a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197', - 'ea9c07e56b5eb17e5f4e', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000b0a0908a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e', - '07342594157785152b074098330abb141b947b', - '566aa9406b4d999988dd', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000c0b0a09a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f', - '676bb20380b0e301e8ab79590a396da78b834934', - 'f53aa2e9107a8b6c022c', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000d0c0b0aa0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f20', - 'c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43', - 'cd1aa31662e7ad65d6db', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000e0d0c0ba0a1a2a3a4a5'), - ( '0be1a88bace018b1', - '08e8cf97d820ea258460e96ad9cf5289054d895ceac47c', - '4cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8', - 'e78cf7cb0cddd7b3', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00412b4ea9cdbe3c9696766cfa'), - ( '63018f76dc8a1bcb', - '9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec', - '4ccb1e7ca981befaa0726c55d378061298c85c92814abc33', - 'c52ee81d7d77c08a', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0033568ef7b2633c9696766cfa'), - ( 'aa6cfa36cae86b40', - 'b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e', - 'b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708', - 'a776796edb723506', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00103fe41336713c9696766cfa'), - ( 'd0d0735c531e1becf049c244', - '12daac5630efa5396f770ce1a66b21f7b2101c', - '14d253c3967b70609b7cbb7c49916028324526', - '9a6f49975bcadeaf', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00764c63b8058e3c9696766cfa'), - ( '77b60f011c03e1525899bcae', - 'e88b6a46c78d63e52eb8c546efb5de6f75e9cc0d', - '5545ff1a085ee2efbf52b2e04bee1e2336c73e3f', - '762c0c7744fe7e3c', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00f8b678094e3b3c9696766cfa'), - ( 'cd9044d2b71fdb8120ea60c0', - '6435acbafb11a82e2f071d7ca4a5ebd93a803ba87f', - '009769ecabdf48625594c59251e6035722675e04c8', - '47099e5ae0704551', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00d560912d3f703c9696766cfa'), - ( 'd85bc7e69f944fb8', - '8a19b950bcf71a018e5e6701c91787659809d67dbedd18', - 'bc218daa947427b6db386a99ac1aef23ade0b52939cb6a', - '637cf9bec2408897c6ba', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0042fff8f1951c3c9696766cfa'), - ( '74a0ebc9069f5b37', - '1761433c37c5a35fc1f39f406302eb907c6163be38c98437', - '5810e6fd25874022e80361a478e3e9cf484ab04f447efff6', - 'f0a477cc2fc9bf548944', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00920f40e56cdc3c9696766cfa'), - ( '44a3aa3aae6475ca', - 'a434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa', - 'f2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f154', - '4d4151a4ed3a8b87b9ce', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0027ca0c7120bc3c9696766cfa'), - ( 'ec46bb63b02520c33c49fd70', - 'b96b49e21d621741632875db7f6c9243d2d7c2', - '31d750a09da3ed7fddd49a2032aabf17ec8ebf', - '7d22c8088c666be5c197', - 'd7828d13b2b0bdc325a76236df93cc6b', - '005b8ccbcd9af83c9696766cfa'), - ( '47a65ac78b3d594227e85e71', - 'e2fcfbb880442c731bf95167c8ffd7895e337076', - 'e882f1dbd38ce3eda7c23f04dd65071eb41342ac', - 'df7e00dccec7ae52987d', - 'd7828d13b2b0bdc325a76236df93cc6b', - '003ebe94044b9a3c9696766cfa'), - ( '6e37a6ef546d955d34ab6059', - 'abf21c0b02feb88f856df4a37381bce3cc128517d4', - 'f32905b88a641b04b9c9ffb58cc390900f3da12ab1', - '6dce9e82efa16da62059', - 'd7828d13b2b0bdc325a76236df93cc6b', - '008d493b30ae8b3c9696766cfa'), - ] - - test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - # Encrypt - cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, **extra_params): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._extra_params = extra_params - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_ccm_test.json", - "Wycheproof AES CCM", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt CCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): - assert not tv.valid - return - if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): - assert not tv.valid - return - raise e - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt CCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): - assert not tv.valid - return - if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): - assert not tv.valid - return - raise e - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt CCM Test #" + str(tv.id) - if len(tv.iv) not in range(7, 13 + 1, 2) or len(tv.ct) == 0: - return - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(CcmTests) - tests += list_test_cases(CcmFSMTests) - tests += [TestVectors()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CFB.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CFB.py deleted file mode 100644 index cb0c352..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CFB.py +++ /dev/null @@ -1,411 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, is_string -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class CfbTests(BlockChainingTests): - - aes_mode = AES.MODE_CFB - des3_mode = DES3.MODE_CFB - - # Redefine test_unaligned_data_128/64 - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - # Extra - - def test_segment_size_128(self): - for bits in range(8, 129, 8): - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, - segment_size=bits) - - for bits in 0, 7, 9, 127, 129: - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CFB, - self.iv_128, - segment_size=bits) - - def test_segment_size_64(self): - for bits in range(8, 65, 8): - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, - segment_size=bits) - - for bits in 0, 7, 9, 63, 65: - self.assertRaises(ValueError, DES3.new, self.key_192, AES.MODE_CFB, - self.iv_64, - segment_size=bits) - - -class NistCfbVectors(unittest.TestCase): - - def _do_kat_aes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CFB%d KAT" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, - segment_size=segment_size) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - # See Section 6.4.5 in AESAVS - def _do_mct_aes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CFB%d Montecarlo" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - assert(segment_size in (8, 128)) - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, - segment_size=segment_size) - - def get_input(input_text, output_seq, j): - # CFB128 - if segment_size == 128: - if j >= 2: - return output_seq[-2] - return [input_text, tv.iv][j] - # CFB8 - if j == 0: - return input_text - elif j <= 16: - return tv.iv[j - 1:j] - return output_seq[j - 17] - - if direction == '[ENCRYPT]': - cts = [] - for j in range(1000): - plaintext = get_input(tv.plaintext, cts, j) - cts.append(cipher.encrypt(plaintext)) - self.assertEqual(cts[-1], tv.ciphertext) - elif direction == '[DECRYPT]': - pts = [] - for j in range(1000): - ciphertext = get_input(tv.ciphertext, pts, j) - pts.append(cipher.decrypt(ciphertext)) - self.assertEqual(pts[-1], tv.plaintext) - else: - assert False - - def _do_tdes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "TDES"), - file_name, - "TDES CFB%d KAT" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - if hasattr(tv, "keys"): - cipher = DES.new(tv.keys, DES.MODE_CFB, tv.iv, - segment_size=segment_size) - else: - if tv.key1 != tv.key3: - key = tv.key1 + tv.key2 + tv.key3 # Option 3 - else: - key = tv.key1 + tv.key2 # Option 2 - cipher = DES3.new(key, DES3.MODE_CFB, tv.iv, - segment_size=segment_size) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "CFB?GFSbox128.rsp", - "CFB?GFSbox192.rsp", - "CFB?GFSbox256.rsp", - "CFB?KeySbox128.rsp", - "CFB?KeySbox192.rsp", - "CFB?KeySbox256.rsp", - "CFB?VarKey128.rsp", - "CFB?VarKey192.rsp", - "CFB?VarKey256.rsp", - "CFB?VarTxt128.rsp", - "CFB?VarTxt192.rsp", - "CFB?VarTxt256.rsp", - # MMT - "CFB?MMT128.rsp", - "CFB?MMT192.rsp", - "CFB?MMT256.rsp", - ) -nist_aes_mct_files = ( - "CFB?MCT128.rsp", - "CFB?MCT192.rsp", - "CFB?MCT256.rsp", - ) - -for file_gen_name in nist_aes_kat_mmt_files: - for bits in "8", "128": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_kat_aes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_AES_" + file_name, new_func) - -for file_gen_name in nist_aes_mct_files: - for bits in "8", "128": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_mct_aes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TCFB?MMT2.rsp", # 2TDES - "TCFB?MMT3.rsp", # 3TDES - "TCFB?invperm.rsp", # Single DES - "TCFB?permop.rsp", - "TCFB?subtab.rsp", - "TCFB?varkey.rsp", - "TCFB?vartext.rsp", - ) - -for file_gen_name in nist_tdes_files: - for bits in "8", "64": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_tdes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST CBC TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CFB test vectors found in Section F.3 - of NIST SP 800-3A""" - - def test_aes_128_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = '3b79424c9c0dd436bace9e0ed4586a4f32b9' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = 'cda2521ef0a905ca44cd057cbf0d47a0678a' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = 'dc1f1a8520a64db55fcc8ac554844e889700' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_128_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ - 'c8a64537a0b3a93fcde3cdad9f1ce58b' +\ - '26751f67a3cbb140b1808cf187a4f4df' +\ - 'c04b05357c5d1c0eeac4c66f9ff7f2e6' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ - '67ce7f7f81173621961a2b70171d3d7a' +\ - '2e1e8a1dd59b88b1c8e60fed1efac4c9' +\ - 'c05f9f9ca9834fa042ae8fba584b09ff' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - - ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ - '39ffed143b28b1c832113c6331e5407b' +\ - 'df10132415e54b92a13ed0a8267ae2f9' +\ - '75a385741ab9cef82031623d55b1e471' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CfbTests) - if config.get('slow_tests'): - tests += list_test_cases(NistCfbVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CTR.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CTR.py deleted file mode 100644 index 6fc43ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_CTR.py +++ /dev/null @@ -1,472 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128, SHA256 -from Crypto.Util import Counter - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -class CtrTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - nonce_32 = get_tag_random("nonce_32", 4) - nonce_64 = get_tag_random("nonce_64", 8) - ctr_64 = Counter.new(32, prefix=nonce_32) - ctr_128 = Counter.new(64, prefix=nonce_64) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_invalid_counter_parameter(self): - # Counter object is required for ciphers with short block size - self.assertRaises(TypeError, DES3.new, self.key_192, AES.MODE_CTR) - # Positional arguments are not allowed (Counter must be passed as - # keyword) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, self.ctr_128) - - def test_nonce_attribute(self): - # Nonce attribute is the prefix passed to Counter (DES3) - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - self.assertEqual(cipher.nonce, self.nonce_32) - - # Nonce attribute is the prefix passed to Counter (AES) - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(cipher.nonce, self.nonce_64) - - # Nonce attribute is not defined if suffix is used in Counter - counter = Counter.new(64, prefix=self.nonce_32, suffix=self.nonce_32) - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertFalse(hasattr(cipher, "nonce")) - - def test_nonce_parameter(self): - # Nonce parameter becomes nonce attribute - cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64) - self.assertEqual(cipher1.nonce, self.nonce_64) - - counter = Counter.new(64, prefix=self.nonce_64, initial_value=0) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Nonce is implicitly created (for AES) when no parameters are passed - nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce - nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce - self.assertNotEqual(nonce1, nonce2) - self.assertEqual(len(nonce1), 8) - - # Nonce can be zero-length - cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"") - self.assertEqual(b"", cipher.nonce) - cipher.encrypt(b'0'*300) - - # Nonce and Counter are mutually exclusive - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, nonce=self.nonce_64) - - def test_initial_value_parameter(self): - # Test with nonce parameter - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=0xFFFF) - counter = Counter.new(64, prefix=self.nonce_64, initial_value=0xFFFF) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Test without nonce parameter - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - initial_value=0xFFFF) - counter = Counter.new(64, prefix=cipher1.nonce, initial_value=0xFFFF) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Initial_value and Counter are mutually exclusive - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, initial_value=0) - - def test_initial_value_bytes_parameter(self): - # Same result as when passing an integer - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=b"\x00"*6+b"\xFF\xFF") - cipher2 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=0xFFFF) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Fail if the iv is too large - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - initial_value=b"5"*17) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=b"5"*9) - - # Fail if the iv is too short - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - initial_value=b"5"*15) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=b"5"*7) - - def test_iv_with_matching_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - counter=Counter.new(120)) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - counter=Counter.new(136)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - 7, counter=self.ctr_128) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, unknown=7) - # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_wrap_around(self): - # Counter is only 8 bits, so we can only encrypt/decrypt 256 blocks (=4096 bytes) - counter = Counter.new(8, prefix=bchr(9) * 15) - max_bytes = 4096 - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - cipher.encrypt(b'9' * max_bytes) - self.assertRaises(OverflowError, cipher.encrypt, b'9') - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertRaises(OverflowError, cipher.encrypt, b'9' * (max_bytes + 1)) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - cipher.decrypt(b'9' * max_bytes) - self.assertRaises(OverflowError, cipher.decrypt, b'9') - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertRaises(OverflowError, cipher.decrypt, b'9' * (max_bytes + 1)) - - def test_bytearray(self): - data = b"1" * 16 - iv = b"\x00" * 6 + b"\xFF\xFF" - - # Encrypt - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=iv) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(self.key_128, AES.MODE_CTR, - nonce=bytearray(self.nonce_64), - initial_value=bytearray(iv)) - ref2 = cipher2.encrypt(bytearray(data)) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - cipher3 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=iv) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(self.key_128, AES.MODE_CTR, - nonce=bytearray(self.nonce_64), - initial_value=bytearray(iv)) - ref4 = cipher4.decrypt(bytearray(data)) - - self.assertEqual(ref3, ref4) - - def test_very_long_data(self): - cipher = AES.new(b'A' * 32, AES.MODE_CTR, nonce=b'') - ct = cipher.encrypt(b'B' * 1000000) - digest = SHA256.new(ct).hexdigest() - self.assertEqual(digest, "96204fc470476561a3a8f3b6fe6d24be85c87510b638142d1d0fb90989f8a6a6") - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - output = bytearray(128) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - LEN_PT = 128 - - pt = b'5' * LEN_PT - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) - - shorter_output = bytearray(LEN_PT - 1) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CTR test vectors found in Section F.5 - of NIST SP 800-38A""" - - def test_aes_128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '874d6191b620e3261bef6864990db6ce' +\ - '9806f66b7970fdff8617187bb9fffdff' +\ - '5ae4df3edbd5d35e5b4f09020db03eab' +\ - '1e031dda2fbe03d1792170a0f3009cee' - key = '2b7e151628aed2a6abf7158809cf4f3c' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '1abc932417521ca24f2b0459fe7e6e0b' +\ - '090339ec0aa6faefd5ccc2c6f4ce8e94' +\ - '1e36b26bd1ebc670d1bd1d665620abf7' +\ - '4f78a7f6d29809585a97daec58c6b050' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '601ec313775789a5b7a7f504bbf3d228' +\ - 'f443e3ca4d62b59aca84e990cacaf5c5' +\ - '2b0930daa23de94ce87017ba2d84988d' +\ - 'dfc9c58db67aada613c2dd08457941a6' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -class RFC3686TestVectors(unittest.TestCase): - - # Each item is a test vector with: - # - plaintext - # - ciphertext - # - key (AES 128, 192 or 256 bits) - # - counter prefix (4 byte nonce + 8 byte nonce) - data = ( - ('53696e676c6520626c6f636b206d7367', - 'e4095d4fb7a7b3792d6175a3261311b8', - 'ae6852f8121067cc4bf7a5765577f39e', - '000000300000000000000000'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28', - '7e24067817fae0d743d6ce1f32539163', - '006cb6dbc0543b59da48d90b'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - 'c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f', - '7691be035e5020a8ac6e618529f9a0dc', - '00e0017b27777f3f4a1786f0'), - ('53696e676c6520626c6f636b206d7367', - '4b55384fe259c9c84e7935a003cbe928', - '16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515', - '0000004836733c147d6d93cb'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00', - '7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a', - '0096b03b020c6eadc2cb500d'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - '96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935', - '02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe', - '0007bdfd5cbd60278dcc0912'), - ('53696e676c6520626c6f636b206d7367', - '145ad01dbf824ec7560863dc71e3e0c0', - '776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104', - '00000060db5672c97aa8f0b2'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c', - 'f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884', - '00faac24c1585ef15a43d875'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - 'eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8', - 'ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d', - '001cc5b751a51d70a1c11148') - ) - - bindata = [] - for tv in data: - bindata.append([unhexlify(x) for x in tv]) - - def runTest(self): - for pt, ct, key, prefix in self.bindata: - counter = Counter.new(32, prefix=prefix) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - result = cipher.encrypt(pt) - self.assertEqual(hexlify(ct), hexlify(result)) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CtrTests) - tests += list_test_cases(SP800TestVectors) - tests += [ RFC3686TestVectors() ] - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20.py deleted file mode 100644 index 4396ac2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20.py +++ /dev/null @@ -1,529 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import b, tobytes, bchr -from Crypto.Util.strxor import strxor_c -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import ChaCha20 - - -class ChaCha20Test(unittest.TestCase): - - def test_new_positive(self): - cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*8) - self.assertEqual(cipher.nonce, b"0" * 8) - cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*12) - self.assertEqual(cipher.nonce, b"0" * 12) - - def test_new_negative(self): - new = ChaCha20.new - self.assertRaises(TypeError, new) - self.assertRaises(TypeError, new, nonce=b("0")) - self.assertRaises(ValueError, new, nonce=b("0")*8, key=b("0")) - self.assertRaises(ValueError, new, nonce=b("0"), key=b("0")*32) - - def test_default_nonce(self): - cipher1 = ChaCha20.new(key=bchr(1) * 32) - cipher2 = ChaCha20.new(key=bchr(1) * 32) - self.assertEqual(len(cipher1.nonce), 8) - self.assertNotEqual(cipher1.nonce, cipher2.nonce) - - def test_nonce(self): - key = b'A' * 32 - - nonce1 = b'P' * 8 - cipher1 = ChaCha20.new(key=key, nonce=nonce1) - self.assertEqual(nonce1, cipher1.nonce) - - nonce2 = b'Q' * 12 - cipher2 = ChaCha20.new(key=key, nonce=nonce2) - self.assertEqual(nonce2, cipher2.nonce) - - def test_eiter_encrypt_or_decrypt(self): - """Verify that a cipher cannot be used for both decrypting and encrypting""" - - c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c1.encrypt(b("8")) - self.assertRaises(TypeError, c1.decrypt, b("9")) - - c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c2.decrypt(b("8")) - self.assertRaises(TypeError, c2.encrypt, b("9")) - - def test_round_trip(self): - pt = b("A") * 1024 - c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - ct = c1.encrypt(pt) - self.assertEqual(c2.decrypt(ct), pt) - - self.assertEqual(c1.encrypt(b("")), b("")) - self.assertEqual(c2.decrypt(b("")), b("")) - - def test_streaming(self): - """Verify that an arbitrary number of bytes can be encrypted/decrypted""" - from Crypto.Hash import SHA1 - - segments = (1, 3, 5, 7, 11, 17, 23) - total = sum(segments) - - pt = b("") - while len(pt) < total: - pt += SHA1.new(pt).digest() - - cipher1 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - ct = cipher1.encrypt(pt) - - cipher2 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - cipher3 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - idx = 0 - for segment in segments: - self.assertEqual(cipher2.decrypt(ct[idx:idx+segment]), pt[idx:idx+segment]) - self.assertEqual(cipher3.encrypt(pt[idx:idx+segment]), ct[idx:idx+segment]) - idx += segment - - def test_seek(self): - cipher1 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) - - offset = 64 * 900 + 7 - pt = b("1") * 64 - - cipher1.encrypt(b("0") * offset) - ct1 = cipher1.encrypt(pt) - - cipher2 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) - cipher2.seek(offset) - ct2 = cipher2.encrypt(pt) - - self.assertEqual(ct1, ct2) - - def test_seek_tv(self): - # Test Vector #4, A.1 from - # http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - key = bchr(0) + bchr(255) + bchr(0) * 30 - nonce = bchr(0) * 8 - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.seek(64 * 2) - expected_key_stream = unhexlify(b( - "72d54dfbf12ec44b362692df94137f32" - "8fea8da73990265ec1bbbea1ae9af0ca" - "13b25aa26cb4a648cb9b9d1be65b2c09" - "24a66c54d545ec1b7374f4872e99f096" - )) - ct = cipher.encrypt(bchr(0) * len(expected_key_stream)) - self.assertEqual(expected_key_stream, ct) - - def test_rfc7539(self): - # from https://tools.ietf.org/html/rfc7539 Annex A.1 - # Each item is: key, nonce, block #, plaintext, ciphertext - tvs = [ - # Test Vector #1 - ( - "00"*32, - "00"*12, - 0, - "00"*16*4, - "76b8e0ada0f13d90405d6ae55386bd28" - "bdd219b8a08ded1aa836efcc8b770dc7" - "da41597c5157488d7724e03fb8d84a37" - "6a43b8f41518a11cc387b669b2ee6586" - ), - # Test Vector #2 - ( - "00"*31 + "01", - "00"*11 + "02", - 1, - "416e79207375626d697373696f6e2074" - "6f20746865204945544620696e74656e" - "6465642062792074686520436f6e7472" - "696275746f7220666f72207075626c69" - "636174696f6e20617320616c6c206f72" - "2070617274206f6620616e2049455446" - "20496e7465726e65742d447261667420" - "6f722052464320616e6420616e792073" - "746174656d656e74206d616465207769" - "7468696e2074686520636f6e74657874" - "206f6620616e20494554462061637469" - "7669747920697320636f6e7369646572" - "656420616e20224945544620436f6e74" - "7269627574696f6e222e205375636820" - "73746174656d656e747320696e636c75" - "6465206f72616c2073746174656d656e" - "747320696e2049455446207365737369" - "6f6e732c2061732077656c6c20617320" - "7772697474656e20616e6420656c6563" - "74726f6e696320636f6d6d756e696361" - "74696f6e73206d61646520617420616e" - "792074696d65206f7220706c6163652c" - "20776869636820617265206164647265" - "7373656420746f", - "a3fbf07df3fa2fde4f376ca23e827370" - "41605d9f4f4f57bd8cff2c1d4b7955ec" - "2a97948bd3722915c8f3d337f7d37005" - "0e9e96d647b7c39f56e031ca5eb6250d" - "4042e02785ececfa4b4bb5e8ead0440e" - "20b6e8db09d881a7c6132f420e527950" - "42bdfa7773d8a9051447b3291ce1411c" - "680465552aa6c405b7764d5e87bea85a" - "d00f8449ed8f72d0d662ab052691ca66" - "424bc86d2df80ea41f43abf937d3259d" - "c4b2d0dfb48a6c9139ddd7f76966e928" - "e635553ba76c5c879d7b35d49eb2e62b" - "0871cdac638939e25e8a1e0ef9d5280f" - "a8ca328b351c3c765989cbcf3daa8b6c" - "cc3aaf9f3979c92b3720fc88dc95ed84" - "a1be059c6499b9fda236e7e818b04b0b" - "c39c1e876b193bfe5569753f88128cc0" - "8aaa9b63d1a16f80ef2554d7189c411f" - "5869ca52c5b83fa36ff216b9c1d30062" - "bebcfd2dc5bce0911934fda79a86f6e6" - "98ced759c3ff9b6477338f3da4f9cd85" - "14ea9982ccafb341b2384dd902f3d1ab" - "7ac61dd29c6f21ba5b862f3730e37cfd" - "c4fd806c22f221" - ), - # Test Vector #3 - ( - "1c9240a5eb55d38af333888604f6b5f0" - "473917c1402b80099dca5cbc207075c0", - "00"*11 + "02", - 42, - "2754776173206272696c6c69672c2061" - "6e642074686520736c6974687920746f" - "7665730a446964206779726520616e64" - "2067696d626c6520696e207468652077" - "6162653a0a416c6c206d696d73792077" - "6572652074686520626f726f676f7665" - "732c0a416e6420746865206d6f6d6520" - "7261746873206f757467726162652e", - "62e6347f95ed87a45ffae7426f27a1df" - "5fb69110044c0d73118effa95b01e5cf" - "166d3df2d721caf9b21e5fb14c616871" - "fd84c54f9d65b283196c7fe4f60553eb" - "f39c6402c42234e32a356b3e764312a6" - "1a5532055716ead6962568f87d3f3f77" - "04c6a8d1bcd1bf4d50d6154b6da731b1" - "87b58dfd728afa36757a797ac188d1" - ) - ] - - for tv in tvs: - key = unhexlify(tv[0]) - nonce = unhexlify(tv[1]) - offset = tv[2] * 64 - pt = unhexlify(tv[3]) - ct_expect = unhexlify(tv[4]) - - cipher = ChaCha20.new(key=key, nonce=nonce) - if offset != 0: - cipher.seek(offset) - ct = cipher.encrypt(pt) - assert(ct == ct_expect) - - -class XChaCha20Test(unittest.TestCase): - - # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - - def test_hchacha20(self): - # Section 2.2.1 - - from Crypto.Cipher.ChaCha20 import _HChaCha20 - - key = b"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f" - key = unhexlify(key.replace(b":", b"")) - - nonce = b"00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27" - nonce = unhexlify(nonce.replace(b":", b"")) - - subkey = _HChaCha20(key, nonce) - - expected = b"82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc" - expected = unhexlify(expected.replace(b" ", b"")) - - self.assertEqual(subkey, expected) - - def test_nonce(self): - key = b'A' * 32 - nonce = b'P' * 24 - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertEqual(nonce, cipher.nonce) - - def test_encrypt(self): - # Section A.3.2 - - pt = b""" - 5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973 - 20616c736f206b6e6f776e2061732074686520417369617469632077696c6420 - 646f672c2072656420646f672c20616e642077686973746c696e6720646f672e - 2049742069732061626f7574207468652073697a65206f662061204765726d61 - 6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061 - 206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c - 757369766520616e6420736b696c6c6564206a756d70657220697320636c6173 - 736966696564207769746820776f6c7665732c20636f796f7465732c206a6163 - 6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963 - 2066616d696c792043616e696461652e""" - pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) - - key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") - iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555658") - - ct = b""" - 7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87 - ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05 - 3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f - 7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201 - 12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc - 047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63 - d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73 - c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4 - d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683 - 8a9c71f70b5b5907a66f7ea49aadc409""" - ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) - - cipher = ChaCha20.new(key=key, nonce=iv) - cipher.seek(64) # Counter = 1 - ct_test = cipher.encrypt(pt) - self.assertEqual(ct, ct_test) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_ba = bytearray(data) - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - - cipher1 = ChaCha20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = ChaCha20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_ba) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - ct_ba = bytearray(ct) - - cipher3 = ChaCha20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_ba) - - self.assertEqual(data, pt_test) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_mv = memoryview(bytearray(data)) - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - - cipher1 = ChaCha20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = ChaCha20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_mv) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - ct_mv = memoryview(bytearray(ct)) - - cipher3 = ChaCha20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_mv) - - self.assertEqual(data, pt_test) - - -class ChaCha20_AGL_NIR(unittest.TestCase): - - # From http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 - # and http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - tv = [ - ( "00" * 32, - "00" * 8, - "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc" - "8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11c" - "c387b669b2ee6586" - "9f07e7be5551387a98ba977c732d080d" - "cb0f29a048e3656912c6533e32ee7aed" - "29b721769ce64e43d57133b074d839d5" - "31ed1f28510afb45ace10a1f4b794d6f" - ), - ( "00" * 31 + "01", - "00" * 8, - "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952" - "ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea81" - "7e9ad275ae546963" - "3aeb5224ecf849929b9d828db1ced4dd" - "832025e8018b8160b82284f3c949aa5a" - "8eca00bbb4a73bdad192b5c42f73f2fd" - "4e273644c8b36125a64addeb006c13a0" - ), - ( "00" * 32, - "00" * 7 + "01", - "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df1" - "37821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e" - "445f41e3" - ), - ( "00" * 32, - "01" + "00" * 7, - "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd1" - "38e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d" - "6bbdb0041b2f586b" - ), - ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b" - "1c1d1e1f", - "0001020304050607", - "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56" - "f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1" - "5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de9526" - "4986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e" - "09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750" - "32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5" - "07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f7" - "6dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2" - "ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab7" - "8fab78c9" - ), - ( "00" * 32, - "00" * 7 + "02", - "c2c64d378cd536374ae204b9ef933fcd" - "1a8b2288b3dfa49672ab765b54ee27c7" - "8a970e0e955c14f3a88e741b97c286f7" - "5f8fc299e8148362fa198a39531bed6d" - ), - ] - - def runTest(self): - for (key, nonce, stream) in self.tv: - c = ChaCha20.new(key=unhexlify(b(key)), nonce=unhexlify(b(nonce))) - ct = unhexlify(b(stream)) - pt = b("\x00") * len(ct) - self.assertEqual(c.encrypt(pt), ct) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 8 - cipher = ChaCha20.new(key=key, nonce=nonce) - - pt = b'5' * 300 - ct = cipher.encrypt(pt) - - output = bytearray(len(pt)) - cipher = ChaCha20.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = ChaCha20.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(len(pt))) - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*len(pt)) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(pt)) - - shorter_output = bytearray(len(pt) - 1) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ChaCha20Test) - tests += list_test_cases(XChaCha20Test) - tests.append(ChaCha20_AGL_NIR()) - tests.append(ByteArrayTest()) - tests.append(MemoryviewTest()) - tests.append(TestOutput()) - - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py deleted file mode 100644 index 9129c68..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py +++ /dev/null @@ -1,776 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes -from Crypto.Cipher import ChaCha20_Poly1305 -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class ChaCha20Poly1305Tests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce can only be 8 or 12 bytes - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=b'H' * 8) - self.assertEqual(len(cipher.nonce), 8) - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=b'H' * 12) - self.assertEqual(len(cipher.nonce), 12) - - # If not passed, the nonce is created randomly - cipher = ChaCha20_Poly1305.new(key=self.key_256) - nonce1 = cipher.nonce - cipher = ChaCha20_Poly1305.new(key=self.key_256) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 12) - self.assertNotEqual(nonce1, nonce2) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertEqual(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can only be 8 or 12 bytes long - self.assertRaises(ValueError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=b'0' * 7) - self.assertRaises(ValueError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=b'') - - def test_block_size(self): - # Not based on block ciphers - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertFalse(hasattr(cipher, 'block_size')) - - def test_nonce_attribute(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 12 bytes long nonce is randomly generated - nonce1 = ChaCha20_Poly1305.new(key=self.key_256).nonce - nonce2 = ChaCha20_Poly1305.new(key=self.key_256).nonce - self.assertEqual(len(nonce1), 12) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, - ChaCha20_Poly1305.new, - key=self.key_256, - param=9) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEqual(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_256) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_256) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - del data_ba - - cipher3 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_ba) - ct_ba[:3] = b'\xFF\xFF\xFF' - cipher3.verify(tag_ba) - - self.assertEqual(pt_test, self.data_128) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_256)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_256)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - ct_mv = memoryview(bytearray(ct)) - tag_mv = memoryview(bytearray(tag)) - del data_mv - - cipher3 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_mv) - ct_mv[:3] = b'\x99\x99\x99' - cipher3.verify(tag_mv) - - self.assertEqual(pt_test, self.data_128) - - -class XChaCha20Poly1305Tests(unittest.TestCase): - - def test_nonce(self): - # Nonce can only be 24 bytes - cipher = ChaCha20_Poly1305.new(key=b'Y' * 32, - nonce=b'H' * 24) - self.assertEqual(len(cipher.nonce), 24) - self.assertEqual(cipher.nonce, b'H' * 24) - - def test_encrypt(self): - # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - # Section A.3.1 - - pt = b""" - 4c616469657320616e642047656e746c656d656e206f662074686520636c6173 - 73206f66202739393a204966204920636f756c64206f6666657220796f75206f - 6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73 - 637265656e20776f756c642062652069742e""" - pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) - - aad = unhexlify(b"50515253c0c1c2c3c4c5c6c7") - key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") - iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555657") - - ct = b""" - bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb - 731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452 - 2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9 - 21f9664c97637da9768812f615c68b13b52e""" - ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) - - tag = unhexlify(b"c0875924c1c7987947deafd8780acf49") - - cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) - cipher.update(aad) - ct_test, tag_test = cipher.encrypt_and_digest(pt) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) - cipher.update(aad) - cipher.decrypt_and_verify(ct, tag) - - -class ChaCha20Poly1305FSMTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - mac = cipher.digest() - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -def compact(x): - return unhexlify(x.replace(" ", "").replace(":", "")) - - -class TestVectorsRFC(unittest.TestCase): - """Test cases from RFC7539""" - - # AAD, PT, CT, MAC, KEY, NONCE - test_vectors_hex = [ - ( '50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7', - '4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c' - '65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73' - '73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63' - '6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f' - '6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20' - '74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73' - '63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69' - '74 2e', - 'd3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2' - 'a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6' - '3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b' - '1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36' - '92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58' - 'fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc' - '3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b' - '61 16', - '1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91', - '80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f' - '90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f', - '07 00 00 00' + '40 41 42 43 44 45 46 47', - ), - ( 'f3 33 88 86 00 00 00 00 00 00 4e 91', - '49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 73 20' - '61 72 65 20 64 72 61 66 74 20 64 6f 63 75 6d 65' - '6e 74 73 20 76 61 6c 69 64 20 66 6f 72 20 61 20' - '6d 61 78 69 6d 75 6d 20 6f 66 20 73 69 78 20 6d' - '6f 6e 74 68 73 20 61 6e 64 20 6d 61 79 20 62 65' - '20 75 70 64 61 74 65 64 2c 20 72 65 70 6c 61 63' - '65 64 2c 20 6f 72 20 6f 62 73 6f 6c 65 74 65 64' - '20 62 79 20 6f 74 68 65 72 20 64 6f 63 75 6d 65' - '6e 74 73 20 61 74 20 61 6e 79 20 74 69 6d 65 2e' - '20 49 74 20 69 73 20 69 6e 61 70 70 72 6f 70 72' - '69 61 74 65 20 74 6f 20 75 73 65 20 49 6e 74 65' - '72 6e 65 74 2d 44 72 61 66 74 73 20 61 73 20 72' - '65 66 65 72 65 6e 63 65 20 6d 61 74 65 72 69 61' - '6c 20 6f 72 20 74 6f 20 63 69 74 65 20 74 68 65' - '6d 20 6f 74 68 65 72 20 74 68 61 6e 20 61 73 20' - '2f e2 80 9c 77 6f 72 6b 20 69 6e 20 70 72 6f 67' - '72 65 73 73 2e 2f e2 80 9d', - '64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd' - '5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2' - '4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0' - 'bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf' - '33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81' - '14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55' - '97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38' - '36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4' - 'b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9' - '90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e' - 'af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a' - '0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a' - '0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e' - 'ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10' - '49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30' - '30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29' - 'a6 ad 5c b4 02 2b 02 70 9b', - 'ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38', - '1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0' - '47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0', - '00 00 00 00 01 02 03 04 05 06 07 08', - ) - ] - - test_vectors = [[unhexlify(x.replace(" ", "").replace(":", "")) for x in tv] for tv in test_vectors_hex] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - # Encrypt - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def load_tests(self, filename): - - def filter_tag(group): - return group['tagSize'] // 8 - - def filter_algo(root): - return root['algorithm'] - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof ChaCha20-Poly1305", - root_tag={'algo': filter_algo}, - group_tag={'tag_size': filter_tag}) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("chacha20_poly1305_test.json")) - self.tv.extend(self.load_tests("xchacha20_poly1305_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt %s Test #%s" % (tv.algo, tv.id) - - try: - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - except ValueError as e: - assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) - return - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) - - try: - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - except ValueError as e: - assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) - return - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt ChaCha20-Poly1305 Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 12 - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(ChaCha20Poly1305Tests) - tests += list_test_cases(XChaCha20Poly1305Tests) - tests += list_test_cases(ChaCha20Poly1305FSMTests) - tests += [TestVectorsRFC()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES.py deleted file mode 100644 index ee261bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES.py +++ /dev/null @@ -1,374 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/DES.py: Self-test for the (Single) DES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.DES""" - -import unittest - -from Crypto.Cipher import DES - -# This is a list of (plaintext, ciphertext, key, description) tuples. -SP800_17_B1_KEY = '01' * 8 -SP800_17_B2_PT = '00' * 8 -test_data = [ - # Test vectors from Appendix A of NIST SP 800-17 - # "Modes of Operation Validation System (MOVS): Requirements and Procedures" - # http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf - - # Appendix A - "Sample Round Outputs for the DES" - ('0000000000000000', '82dcbafbdeab6602', '10316e028c8f3b4a', - "NIST SP800-17 A"), - - # Table B.1 - Variable Plaintext Known Answer Test - ('8000000000000000', '95f8a5e5dd31d900', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #0'), - ('4000000000000000', 'dd7f121ca5015619', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #1'), - ('2000000000000000', '2e8653104f3834ea', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #2'), - ('1000000000000000', '4bd388ff6cd81d4f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #3'), - ('0800000000000000', '20b9e767b2fb1456', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #4'), - ('0400000000000000', '55579380d77138ef', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #5'), - ('0200000000000000', '6cc5defaaf04512f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #6'), - ('0100000000000000', '0d9f279ba5d87260', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #7'), - ('0080000000000000', 'd9031b0271bd5a0a', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #8'), - ('0040000000000000', '424250b37c3dd951', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #9'), - ('0020000000000000', 'b8061b7ecd9a21e5', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #10'), - ('0010000000000000', 'f15d0f286b65bd28', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #11'), - ('0008000000000000', 'add0cc8d6e5deba1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #12'), - ('0004000000000000', 'e6d5f82752ad63d1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #13'), - ('0002000000000000', 'ecbfe3bd3f591a5e', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #14'), - ('0001000000000000', 'f356834379d165cd', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #15'), - ('0000800000000000', '2b9f982f20037fa9', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #16'), - ('0000400000000000', '889de068a16f0be6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #17'), - ('0000200000000000', 'e19e275d846a1298', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #18'), - ('0000100000000000', '329a8ed523d71aec', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #19'), - ('0000080000000000', 'e7fce22557d23c97', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #20'), - ('0000040000000000', '12a9f5817ff2d65d', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #21'), - ('0000020000000000', 'a484c3ad38dc9c19', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #22'), - ('0000010000000000', 'fbe00a8a1ef8ad72', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #23'), - ('0000008000000000', '750d079407521363', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #24'), - ('0000004000000000', '64feed9c724c2faf', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #25'), - ('0000002000000000', 'f02b263b328e2b60', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #26'), - ('0000001000000000', '9d64555a9a10b852', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #27'), - ('0000000800000000', 'd106ff0bed5255d7', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #28'), - ('0000000400000000', 'e1652c6b138c64a5', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #29'), - ('0000000200000000', 'e428581186ec8f46', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #30'), - ('0000000100000000', 'aeb5f5ede22d1a36', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #31'), - ('0000000080000000', 'e943d7568aec0c5c', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #32'), - ('0000000040000000', 'df98c8276f54b04b', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #33'), - ('0000000020000000', 'b160e4680f6c696f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #34'), - ('0000000010000000', 'fa0752b07d9c4ab8', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #35'), - ('0000000008000000', 'ca3a2b036dbc8502', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #36'), - ('0000000004000000', '5e0905517bb59bcf', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #37'), - ('0000000002000000', '814eeb3b91d90726', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #38'), - ('0000000001000000', '4d49db1532919c9f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #39'), - ('0000000000800000', '25eb5fc3f8cf0621', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #40'), - ('0000000000400000', 'ab6a20c0620d1c6f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #41'), - ('0000000000200000', '79e90dbc98f92cca', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #42'), - ('0000000000100000', '866ecedd8072bb0e', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #43'), - ('0000000000080000', '8b54536f2f3e64a8', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #44'), - ('0000000000040000', 'ea51d3975595b86b', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #45'), - ('0000000000020000', 'caffc6ac4542de31', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #46'), - ('0000000000010000', '8dd45a2ddf90796c', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #47'), - ('0000000000008000', '1029d55e880ec2d0', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #48'), - ('0000000000004000', '5d86cb23639dbea9', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #49'), - ('0000000000002000', '1d1ca853ae7c0c5f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #50'), - ('0000000000001000', 'ce332329248f3228', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #51'), - ('0000000000000800', '8405d1abe24fb942', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #52'), - ('0000000000000400', 'e643d78090ca4207', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #53'), - ('0000000000000200', '48221b9937748a23', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #54'), - ('0000000000000100', 'dd7c0bbd61fafd54', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #55'), - ('0000000000000080', '2fbc291a570db5c4', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #56'), - ('0000000000000040', 'e07c30d7e4e26e12', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #57'), - ('0000000000000020', '0953e2258e8e90a1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #58'), - ('0000000000000010', '5b711bc4ceebf2ee', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #59'), - ('0000000000000008', 'cc083f1e6d9e85f6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #60'), - ('0000000000000004', 'd2fd8867d50d2dfe', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #61'), - ('0000000000000002', '06e7ea22ce92708f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #62'), - ('0000000000000001', '166b40b44aba4bd6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #63'), - - # Table B.2 - Variable Key Known Answer Test - (SP800_17_B2_PT, '95a8d72813daa94d', '8001010101010101', - 'NIST SP800-17 B.2 #0'), - (SP800_17_B2_PT, '0eec1487dd8c26d5', '4001010101010101', - 'NIST SP800-17 B.2 #1'), - (SP800_17_B2_PT, '7ad16ffb79c45926', '2001010101010101', - 'NIST SP800-17 B.2 #2'), - (SP800_17_B2_PT, 'd3746294ca6a6cf3', '1001010101010101', - 'NIST SP800-17 B.2 #3'), - (SP800_17_B2_PT, '809f5f873c1fd761', '0801010101010101', - 'NIST SP800-17 B.2 #4'), - (SP800_17_B2_PT, 'c02faffec989d1fc', '0401010101010101', - 'NIST SP800-17 B.2 #5'), - (SP800_17_B2_PT, '4615aa1d33e72f10', '0201010101010101', - 'NIST SP800-17 B.2 #6'), - (SP800_17_B2_PT, '2055123350c00858', '0180010101010101', - 'NIST SP800-17 B.2 #7'), - (SP800_17_B2_PT, 'df3b99d6577397c8', '0140010101010101', - 'NIST SP800-17 B.2 #8'), - (SP800_17_B2_PT, '31fe17369b5288c9', '0120010101010101', - 'NIST SP800-17 B.2 #9'), - (SP800_17_B2_PT, 'dfdd3cc64dae1642', '0110010101010101', - 'NIST SP800-17 B.2 #10'), - (SP800_17_B2_PT, '178c83ce2b399d94', '0108010101010101', - 'NIST SP800-17 B.2 #11'), - (SP800_17_B2_PT, '50f636324a9b7f80', '0104010101010101', - 'NIST SP800-17 B.2 #12'), - (SP800_17_B2_PT, 'a8468ee3bc18f06d', '0102010101010101', - 'NIST SP800-17 B.2 #13'), - (SP800_17_B2_PT, 'a2dc9e92fd3cde92', '0101800101010101', - 'NIST SP800-17 B.2 #14'), - (SP800_17_B2_PT, 'cac09f797d031287', '0101400101010101', - 'NIST SP800-17 B.2 #15'), - (SP800_17_B2_PT, '90ba680b22aeb525', '0101200101010101', - 'NIST SP800-17 B.2 #16'), - (SP800_17_B2_PT, 'ce7a24f350e280b6', '0101100101010101', - 'NIST SP800-17 B.2 #17'), - (SP800_17_B2_PT, '882bff0aa01a0b87', '0101080101010101', - 'NIST SP800-17 B.2 #18'), - (SP800_17_B2_PT, '25610288924511c2', '0101040101010101', - 'NIST SP800-17 B.2 #19'), - (SP800_17_B2_PT, 'c71516c29c75d170', '0101020101010101', - 'NIST SP800-17 B.2 #20'), - (SP800_17_B2_PT, '5199c29a52c9f059', '0101018001010101', - 'NIST SP800-17 B.2 #21'), - (SP800_17_B2_PT, 'c22f0a294a71f29f', '0101014001010101', - 'NIST SP800-17 B.2 #22'), - (SP800_17_B2_PT, 'ee371483714c02ea', '0101012001010101', - 'NIST SP800-17 B.2 #23'), - (SP800_17_B2_PT, 'a81fbd448f9e522f', '0101011001010101', - 'NIST SP800-17 B.2 #24'), - (SP800_17_B2_PT, '4f644c92e192dfed', '0101010801010101', - 'NIST SP800-17 B.2 #25'), - (SP800_17_B2_PT, '1afa9a66a6df92ae', '0101010401010101', - 'NIST SP800-17 B.2 #26'), - (SP800_17_B2_PT, 'b3c1cc715cb879d8', '0101010201010101', - 'NIST SP800-17 B.2 #27'), - (SP800_17_B2_PT, '19d032e64ab0bd8b', '0101010180010101', - 'NIST SP800-17 B.2 #28'), - (SP800_17_B2_PT, '3cfaa7a7dc8720dc', '0101010140010101', - 'NIST SP800-17 B.2 #29'), - (SP800_17_B2_PT, 'b7265f7f447ac6f3', '0101010120010101', - 'NIST SP800-17 B.2 #30'), - (SP800_17_B2_PT, '9db73b3c0d163f54', '0101010110010101', - 'NIST SP800-17 B.2 #31'), - (SP800_17_B2_PT, '8181b65babf4a975', '0101010108010101', - 'NIST SP800-17 B.2 #32'), - (SP800_17_B2_PT, '93c9b64042eaa240', '0101010104010101', - 'NIST SP800-17 B.2 #33'), - (SP800_17_B2_PT, '5570530829705592', '0101010102010101', - 'NIST SP800-17 B.2 #34'), - (SP800_17_B2_PT, '8638809e878787a0', '0101010101800101', - 'NIST SP800-17 B.2 #35'), - (SP800_17_B2_PT, '41b9a79af79ac208', '0101010101400101', - 'NIST SP800-17 B.2 #36'), - (SP800_17_B2_PT, '7a9be42f2009a892', '0101010101200101', - 'NIST SP800-17 B.2 #37'), - (SP800_17_B2_PT, '29038d56ba6d2745', '0101010101100101', - 'NIST SP800-17 B.2 #38'), - (SP800_17_B2_PT, '5495c6abf1e5df51', '0101010101080101', - 'NIST SP800-17 B.2 #39'), - (SP800_17_B2_PT, 'ae13dbd561488933', '0101010101040101', - 'NIST SP800-17 B.2 #40'), - (SP800_17_B2_PT, '024d1ffa8904e389', '0101010101020101', - 'NIST SP800-17 B.2 #41'), - (SP800_17_B2_PT, 'd1399712f99bf02e', '0101010101018001', - 'NIST SP800-17 B.2 #42'), - (SP800_17_B2_PT, '14c1d7c1cffec79e', '0101010101014001', - 'NIST SP800-17 B.2 #43'), - (SP800_17_B2_PT, '1de5279dae3bed6f', '0101010101012001', - 'NIST SP800-17 B.2 #44'), - (SP800_17_B2_PT, 'e941a33f85501303', '0101010101011001', - 'NIST SP800-17 B.2 #45'), - (SP800_17_B2_PT, 'da99dbbc9a03f379', '0101010101010801', - 'NIST SP800-17 B.2 #46'), - (SP800_17_B2_PT, 'b7fc92f91d8e92e9', '0101010101010401', - 'NIST SP800-17 B.2 #47'), - (SP800_17_B2_PT, 'ae8e5caa3ca04e85', '0101010101010201', - 'NIST SP800-17 B.2 #48'), - (SP800_17_B2_PT, '9cc62df43b6eed74', '0101010101010180', - 'NIST SP800-17 B.2 #49'), - (SP800_17_B2_PT, 'd863dbb5c59a91a0', '0101010101010140', - 'NIST SP800-17 B.2 #50'), - (SP800_17_B2_PT, 'a1ab2190545b91d7', '0101010101010120', - 'NIST SP800-17 B.2 #51'), - (SP800_17_B2_PT, '0875041e64c570f7', '0101010101010110', - 'NIST SP800-17 B.2 #52'), - (SP800_17_B2_PT, '5a594528bebef1cc', '0101010101010108', - 'NIST SP800-17 B.2 #53'), - (SP800_17_B2_PT, 'fcdb3291de21f0c0', '0101010101010104', - 'NIST SP800-17 B.2 #54'), - (SP800_17_B2_PT, '869efd7f9f265a09', '0101010101010102', - 'NIST SP800-17 B.2 #55'), -] - -class RonRivestTest(unittest.TestCase): - """ Ronald L. Rivest's DES test, see - http://people.csail.mit.edu/rivest/Destest.txt - ABSTRACT - -------- - - We present a simple way to test the correctness of a DES implementation: - Use the recurrence relation: - - X0 = 9474B8E8C73BCA7D (hexadecimal) - - X(i+1) = IF (i is even) THEN E(Xi,Xi) ELSE D(Xi,Xi) - - to compute a sequence of 64-bit values: X0, X1, X2, ..., X16. Here - E(X,K) denotes the DES encryption of X using key K, and D(X,K) denotes - the DES decryption of X using key K. If you obtain - - X16 = 1B1A2DDB4C642438 - - your implementation does not have any of the 36,568 possible single-fault - errors described herein. - """ - def runTest(self): - from binascii import b2a_hex - - X = [] - X[0:] = [b'\x94\x74\xB8\xE8\xC7\x3B\xCA\x7D'] - - for i in range(16): - c = DES.new(X[i],DES.MODE_ECB) - if not (i&1): # (num&1) returns 1 for odd numbers - X[i+1:] = [c.encrypt(X[i])] # even - else: - X[i+1:] = [c.decrypt(X[i])] # odd - - self.assertEqual(b2a_hex(X[16]), - b2a_hex(b'\x1B\x1A\x2D\xDB\x4C\x64\x24\x38')) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = DES.new(b'4'*8, DES.MODE_ECB) - - pt = b'5' * 8 - ct = cipher.encrypt(pt) - - output = bytearray(8) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(8)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*8) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*8) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - tests = make_block_tests(DES, "DES", test_data) - tests += [RonRivestTest()] - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES3.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES3.py deleted file mode 100644 index 8d6a648..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_DES3.py +++ /dev/null @@ -1,195 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/DES3.py: Self-test for the Triple-DES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.DES3""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Cipher import DES3 - -from Crypto.Util.strxor import strxor_c -from Crypto.Util.py3compat import bchr, tostr -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -# This is a list of (plaintext, ciphertext, key, description) tuples. -test_data = [ - # Test vector from Appendix B of NIST SP 800-67 - # "Recommendation for the Triple Data Encryption Algorithm (TDEA) Block - # Cipher" - # http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf - ('54686520717566636b2062726f776e20666f78206a756d70', - 'a826fd8ce53b855fcce21c8112256fe668d5c05dd9b6b900', - '0123456789abcdef23456789abcdef01456789abcdef0123', - 'NIST SP800-67 B.1'), - - # This test is designed to test the DES3 API, not the correctness of the - # output. - ('21e81b7ade88a259', '5c577d4d9b20c0f8', - '9b397ebf81b1181e282f4bb8adbadc6b', 'Two-key 3DES'), -] - -# NIST CAVP test vectors - -nist_tdes_mmt_files = ("TECBMMT2.rsp", "TECBMMT3.rsp") - -for tdes_file in nist_tdes_mmt_files: - - test_vectors = load_test_vectors( - ("Cipher", "TDES"), - tdes_file, - "TDES ECB (%s)" % tdes_file, - {"count": lambda x: int(x)}) or [] - - for index, tv in enumerate(test_vectors): - - # The test vector file contains some directive lines - if isinstance(tv, str): - continue - - key = tv.key1 + tv.key2 + tv.key3 - test_data_item = (tostr(hexlify(tv.plaintext)), - tostr(hexlify(tv.ciphertext)), - tostr(hexlify(key)), - "%s (%s)" % (tdes_file, index)) - test_data.append(test_data_item) - - -class CheckParity(unittest.TestCase): - - def test_parity_option2(self): - before_2k = unhexlify("CABF326FA56734324FFCCABCDEFACABF") - after_2k = DES3.adjust_key_parity(before_2k) - self.assertEqual(after_2k, - unhexlify("CBBF326EA46734324FFDCBBCDFFBCBBF")) - - def test_parity_option3(self): - before_3k = unhexlify("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCC") - after_3k = DES3.adjust_key_parity(before_3k) - self.assertEqual(after_3k, - unhexlify("ABABABABABABABABBABABABABABABABACDCDCDCDCDCDCDCD")) - - def test_degradation(self): - sub_key1 = bchr(1) * 8 - sub_key2 = bchr(255) * 8 - - # K1 == K2 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 * 2 + sub_key2) - - # K2 == K3 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 + sub_key2 * 2) - - # K1 == K2 == K3 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 * 3) - - # K1 == K2 (with different parity) - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 + strxor_c(sub_key1, 1) + sub_key2) - - -class DegenerateToDESTest(unittest.TestCase): - - def runTest(self): - sub_key1 = bchr(1) * 8 - sub_key2 = bchr(255) * 8 - - # K1 == K2 - self.assertRaises(ValueError, DES3.new, - sub_key1 * 2 + sub_key2, - DES3.MODE_ECB) - - # K2 == K3 - self.assertRaises(ValueError, DES3.new, - sub_key1 + sub_key2 * 2, - DES3.MODE_ECB) - - # K1 == K2 == K3 - self.assertRaises(ValueError, DES3.new, - sub_key1 * 3, - DES3.MODE_ECB) - - # K2 == K3 (parity is ignored) - self.assertRaises(ValueError, DES3.new, - sub_key1 + sub_key2 + strxor_c(sub_key2, 0x1), - DES3.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = DES3.new(b'4'*8 + b'G'*8 + b'T'*8, DES3.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - - tests = [] - tests = make_block_tests(DES3, "DES3", test_data) - tests.append(DegenerateToDESTest()) - tests += list_test_cases(CheckParity) - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - - def suite(): - unittest.TestSuite(get_tests()) - - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_EAX.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_EAX.py deleted file mode 100644 index 7dbee2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_EAX.py +++ /dev/null @@ -1,773 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class EaxTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # If not passed, the nonce is created randomly - cipher = AES.new(self.key_128, AES.MODE_EAX) - nonce1 = cipher.nonce - cipher = AES.new(self.key_128, AES.MODE_EAX) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - cipher = AES.new(self.key_128, AES.MODE_EAX, self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=bchr(1) * x) - cipher.encrypt(bchr(1)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 16 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_EAX).nonce - nonce2 = AES.new(self.key_128, AES.MODE_EAX).nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, mac_len=2-1) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(2, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEqual(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = AES.new(self.key_128, - AES.MODE_EAX, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_EAX, - nonce=nonce_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - del data_ba - - cipher3 = AES.new(key_ba, - AES.MODE_EAX, - nonce=nonce_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_ba) - ct_ba[:3] = b'\xFF\xFF\xFF' - cipher3.verify(tag_ba) - - self.assertEqual(pt_test, self.data_128) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_128, - AES.MODE_EAX, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_EAX, - nonce=nonce_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - ct_mv = memoryview(bytearray(ct)) - tag_mv = memoryview(bytearray(tag)) - del data_mv - - cipher3 = AES.new(key_mv, - AES.MODE_EAX, - nonce=nonce_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_mv) - ct_mv[:3] = b'\x99\x99\x99' - cipher3.verify(tag_mv) - - self.assertEqual(pt_test, self.data_128) - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(128) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - LEN_PT = 16 - - pt = b'5' * LEN_PT - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) - - shorter_output = bytearray(LEN_PT - 1) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class EaxFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -class TestVectorsPaper(unittest.TestCase): - """Class exercising the EAX test vectors found in - http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf""" - - test_vectors_hex = [ - ( '6bfb914fd07eae6b', - '', - '', - 'e037830e8389f27b025a2d6527e79d01', - '233952dee4d5ed5f9b9c6d6ff80ff478', - '62EC67F9C3A4A407FCB2A8C49031A8B3' - ), - ( - 'fa3bfd4806eb53fa', - 'f7fb', - '19dd', - '5c4c9331049d0bdab0277408f67967e5', - '91945d3f4dcbee0bf45ef52255f095a4', - 'BECAF043B0A23D843194BA972C66DEBD' - ), - ( '234a3463c1264ac6', - '1a47cb4933', - 'd851d5bae0', - '3a59f238a23e39199dc9266626c40f80', - '01f74ad64077f2e704c0f60ada3dd523', - '70C3DB4F0D26368400A10ED05D2BFF5E' - ), - ( - '33cce2eabff5a79d', - '481c9e39b1', - '632a9d131a', - 'd4c168a4225d8e1ff755939974a7bede', - 'd07cf6cbb7f313bdde66b727afd3c5e8', - '8408DFFF3C1A2B1292DC199E46B7D617' - ), - ( - 'aeb96eaebe2970e9', - '40d0c07da5e4', - '071dfe16c675', - 'cb0677e536f73afe6a14b74ee49844dd', - '35b6d0580005bbc12b0587124557d2c2', - 'FDB6B06676EEDC5C61D74276E1F8E816' - ), - ( - 'd4482d1ca78dce0f', - '4de3b35c3fc039245bd1fb7d', - '835bb4f15d743e350e728414', - 'abb8644fd6ccb86947c5e10590210a4f', - 'bd8e6e11475e60b268784c38c62feb22', - '6EAC5C93072D8E8513F750935E46DA1B' - ), - ( - '65d2017990d62528', - '8b0a79306c9ce7ed99dae4f87f8dd61636', - '02083e3979da014812f59f11d52630da30', - '137327d10649b0aa6e1c181db617d7f2', - '7c77d6e813bed5ac98baa417477a2e7d', - '1A8C98DCD73D38393B2BF1569DEEFC19' - ), - ( - '54b9f04e6a09189a', - '1bda122bce8a8dbaf1877d962b8592dd2d56', - '2ec47b2c4954a489afc7ba4897edcdae8cc3', - '3b60450599bd02c96382902aef7f832a', - '5fff20cafab119ca2fc73549e20f5b0d', - 'DDE59B97D722156D4D9AFF2BC7559826' - ), - ( - '899a175897561d7e', - '6cf36720872b8513f6eab1a8a44438d5ef11', - '0de18fd0fdd91e7af19f1d8ee8733938b1e8', - 'e7f6d2231618102fdb7fe55ff1991700', - 'a4a4782bcffd3ec5e7ef6d8c34a56123', - 'B781FCF2F75FA5A8DE97A9CA48E522EC' - ), - ( - '126735fcc320d25a', - 'ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7', - 'cb8920f87a6c75cff39627b56e3ed197c552d295a7', - 'cfc46afc253b4652b1af3795b124ab6e', - '8395fcf1e95bebd697bd010bc766aac3', - '22E7ADD93CFC6393C57EC0B3C17D6B44' - ), - ] - - test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - # Encrypt - cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_eax_test.json", - "Wycheproof EAX", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt EAX Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - except ValueError as e: - assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) - return - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt EAX Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - except ValueError as e: - assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) - return - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt EAX Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestOtherCiphers(unittest.TestCase): - - @classmethod - def create_test(cls, name, factory, key_size): - - def test_template(self, factory=factory, key_size=key_size): - cipher = factory.new(get_tag_random("cipher", key_size), - factory.MODE_EAX, - nonce=b"nonce") - ct, mac = cipher.encrypt_and_digest(b"plaintext") - - cipher = factory.new(get_tag_random("cipher", key_size), - factory.MODE_EAX, - nonce=b"nonce") - pt2 = cipher.decrypt_and_verify(ct, mac) - - self.assertEqual(b"plaintext", pt2) - - setattr(cls, "test_" + name, test_template) - - -from Crypto.Cipher import DES, DES3, ARC2, CAST, Blowfish - -TestOtherCiphers.create_test("DES_" + str(DES.key_size), DES, DES.key_size) -for ks in DES3.key_size: - TestOtherCiphers.create_test("DES3_" + str(ks), DES3, ks) -for ks in ARC2.key_size: - TestOtherCiphers.create_test("ARC2_" + str(ks), ARC2, ks) -for ks in CAST.key_size: - TestOtherCiphers.create_test("CAST_" + str(ks), CAST, ks) -for ks in Blowfish.key_size: - TestOtherCiphers.create_test("Blowfish_" + str(ks), Blowfish, ks) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(EaxTests) - tests += list_test_cases(EaxFSMTests) - tests += [ TestVectorsPaper() ] - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - tests += list_test_cases(TestOtherCiphers) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_GCM.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_GCM.py deleted file mode 100644 index dd8da2f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_GCM.py +++ /dev/null @@ -1,951 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from __future__ import print_function - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128, SHA256 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class GcmTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce is optional (a random one will be created) - AES.new(self.key_128, AES.MODE_GCM) - - cipher = AES.new(self.key_128, AES.MODE_GCM, self.nonce_96) - ct = cipher.encrypt(self.data) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEqual(ct, cipher.encrypt(self.data)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=bchr(1) * x) - cipher.encrypt(bchr(1)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_GCM).nonce - nonce2 = AES.new(self.key_128, AES.MODE_GCM).nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, mac_len=3) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(5, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEqual(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - data_ba = bytearray(self.data) - - cipher1 = AES.new(self.key_128, - AES.MODE_GCM, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_GCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_GCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - data_mv = memoryview(bytearray(self.data)) - - cipher1 = AES.new(self.key_128, - AES.MODE_GCM, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_GCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_GCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data, pt_test) - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(128) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - LEN_PT = 128 - - pt = b'5' * LEN_PT - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) - - shorter_output = bytearray(LEN_PT - 1) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class GcmFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data, - self.data + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data) - method(self.data) - method(self.data) - method(self.data) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data) - ct, mac = cipher.encrypt_and_digest(self.data) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data) - getattr(cipher, method1_name)(self.data) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(self.data) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - -class TestVectors(unittest.TestCase): - """Class exercising the GCM test vectors found in - http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf""" - - # List of test vectors, each made up of: - # - authenticated data - # - plaintext - # - ciphertext - # - MAC - # - AES key - # - nonce - test_vectors_hex = [ - ( - '', - '', - '', - '58e2fccefa7e3061367f1d57a4e7455a', - '00000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - '0388dace60b6a392f328c2b971b2fe78', - 'ab6e47d42cec13bdf53a67b21257bddf', - '00000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + - '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985', - '4d5c2af327cd64a62cf35abd2ba6fab4', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + - '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091', - '5bc94fbc3221a5db94fae95ae7121a47', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c7423' + - '73806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598', - '3612d2e79e3b0785561be14aaca2fccb', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca7' + - '01e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5', - '619cc5aefffe0bfa462af43c1699d050', - 'feffe9928665731c6d6a8f9467308308', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ), - ( - '', - '', - '', - 'cd33b28ac773f74ba00ed1f312572435', - '000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - '98e7247c07f0fe411c267e4384b0f600', - '2ff58d80033927ab8ef4d4587514f0fb', - '000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + - '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256', - '9924a7c8587336bfb118024db8674a14', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + - '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710', - '2519498e80f1478f37ba55bd6d27618c', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057' + - 'fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7', - '65dcc57fcf623a24094fcca40d3533f8', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - 'd27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e45' + - '81e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b', - 'dcf566ff291c25bbb8568fc3d376a6d9', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ), - ( - '', - '', - '', - '530f8afbc74536b9a963b4f1c4cb738b', - '0000000000000000000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - 'cea7403d4d606b6e074ec5d3baf39d18', - 'd0d1c8a799996bf0265b98b5d48ab919', - '0000000000000000000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + - '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad', - 'b094dac5d93471bdec1a502270e3cc6c', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + - '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662', - '76fc6ece0f4e1768cddf8853bb2d551b', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - 'c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0' + - 'feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f', - '3a337dbf46a792c45e454913fe2ea8f2', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf4' + - '0fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f', - 'a44a8266ee1c8eb0c8b5d4cf5ae9f19a', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ) - ] - - test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - - # Encrypt - cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsGueronKrasnov(unittest.TestCase): - """Class exercising the GCM test vectors found in - 'The fragility of AES-GCM authentication algorithm', Gueron, Krasnov - https://eprint.iacr.org/2013/157.pdf""" - - def test_1(self): - key = unhexlify("3da6c536d6295579c0959a7043efb503") - iv = unhexlify("2b926197d34e091ef722db94") - aad = unhexlify("00000000000000000000000000000000" + - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f") - digest = unhexlify("69dd586555ce3fcc89663801a71d957b") - - cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) - self.assertEqual(digest, cipher.digest()) - - def test_2(self): - key = unhexlify("843ffcf5d2b72694d19ed01d01249412") - iv = unhexlify("dbcca32ebf9b804617c3aa9e") - aad = unhexlify("00000000000000000000000000000000" + - "101112131415161718191a1b1c1d1e1f") - pt = unhexlify("000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f") - ct = unhexlify("6268c6fa2a80b2d137467f092f657ac0" + - "4d89be2beaa623d61b5a868c8f03ff95" + - "d3dcee23ad2f1ab3a6c80eaf4b140eb0" + - "5de3457f0fbc111a6b43d0763aa422a3" + - "013cf1dc37fe417d1fbfc449b75d4cc5") - digest = unhexlify("3b629ccfbc1119b7319e1dce2cd6fd6d") - - cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) - ct2, digest2 = cipher.encrypt_and_digest(pt) - - self.assertEqual(ct, ct2) - self.assertEqual(digest, digest2) - - -class NISTTestVectorsGCM(unittest.TestCase): - - def __init__(self, a): - self.use_clmul = True - unittest.TestCase.__init__(self, a) - - -class NISTTestVectorsGCM_no_clmul(unittest.TestCase): - - def __init__(self, a): - self.use_clmul = False - unittest.TestCase.__init__(self, a) - - -test_vectors_nist = load_test_vectors( - ("Cipher", "AES"), - "gcmDecrypt128.rsp", - "GCM decrypt", - {"count": lambda x: int(x)}) or [] - -test_vectors_nist += load_test_vectors( - ("Cipher", "AES"), - "gcmEncryptExtIV128.rsp", - "GCM encrypt", - {"count": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_nist): - - # The test vector file contains some directive lines - if isinstance(tv, str): - continue - - def single_test(self, tv=tv): - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_GCM, nonce=tv.iv, - mac_len=len(tv.tag), use_clmul=self.use_clmul) - cipher.update(tv.aad) - if "FAIL" in tv.others: - self.assertRaises(ValueError, cipher.decrypt_and_verify, - tv.ct, tv.tag) - else: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - self.assertEqual(pt, tv.pt) - - setattr(NISTTestVectorsGCM, "test_%d" % idx, single_test) - setattr(NISTTestVectorsGCM_no_clmul, "test_%d" % idx, single_test) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, **extra_params): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._extra_params = extra_params - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_gcm_test.json", - "Wycheproof GCM", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt GCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): - return - raise e - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt GCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): - return - raise e - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt GCM Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestVariableLength(unittest.TestCase): - - def __init__(self, **extra_params): - unittest.TestCase.__init__(self) - self._extra_params = extra_params - - def runTest(self): - key = b'0' * 16 - h = SHA256.new() - - for length in range(160): - nonce = '{0:04d}'.format(length).encode('utf-8') - data = bchr(length) * length - cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params) - ct, tag = cipher.encrypt_and_digest(data) - h.update(ct) - h.update(tag) - - self.assertEqual(h.hexdigest(), "7b7eb1ffbe67a2e53a912067c0ec8e62ebc7ce4d83490ea7426941349811bdf4") - - -def get_tests(config={}): - from Crypto.Util import _cpu_features - - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(GcmTests) - tests += list_test_cases(GcmFSMTests) - tests += [TestVectors()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - tests += list_test_cases(TestVectorsGueronKrasnov) - tests += [TestVariableLength()] - if config.get('slow_tests'): - tests += list_test_cases(NISTTestVectorsGCM) - - if _cpu_features.have_clmul(): - tests += [TestVectorsWycheproof(wycheproof_warnings, use_clmul=False)] - tests += [TestVariableLength(use_clmul=False)] - if config.get('slow_tests'): - tests += list_test_cases(NISTTestVectorsGCM_no_clmul) - else: - print("Skipping test of PCLMULDQD in AES GCM") - - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_KW.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_KW.py deleted file mode 100644 index f43ca2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_KW.py +++ /dev/null @@ -1,175 +0,0 @@ -import unittest - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -from Crypto.Cipher import AES - - -class KW_Tests(unittest.TestCase): - - # From RFC3394 - tvs = [ - ("000102030405060708090A0B0C0D0E0F", - "00112233445566778899AABBCCDDEEFF", - "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5"), - ("000102030405060708090A0B0C0D0E0F1011121314151617", - "00112233445566778899AABBCCDDEEFF", - "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D"), - ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", - "00112233445566778899AABBCCDDEEFF", - "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7"), - ("000102030405060708090A0B0C0D0E0F1011121314151617", - "00112233445566778899AABBCCDDEEFF0001020304050607", - "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2"), - ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", - "00112233445566778899AABBCCDDEEFF0001020304050607", - "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1"), - ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", - "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", - "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21"), - ] - - def test_rfc3394(self): - for tv in self.tvs: - kek, pt, ct = [bytes.fromhex(x) for x in tv] - - cipher = AES.new(kek, AES.MODE_KW) - ct2 = cipher.seal(pt) - - self.assertEqual(ct, ct2) - - cipher = AES.new(kek, AES.MODE_KW) - pt2 = cipher.unseal(ct) - self.assertEqual(pt, pt2) - - def test_neg1(self): - - cipher = AES.new(b'-' * 16, AES.MODE_KW) - - with self.assertRaises(ValueError): - cipher.seal(b'') - - with self.assertRaises(ValueError): - cipher.seal(b'8' * 17) - - def test_neg2(self): - - cipher = AES.new(b'-' * 16, AES.MODE_KW) - ct = bytearray(cipher.seal(b'7' * 16)) - - cipher = AES.new(b'-' * 16, AES.MODE_KW) - cipher.unseal(ct) - - cipher = AES.new(b'-' * 16, AES.MODE_KW) - ct[0] ^= 0xFF - with self.assertRaises(ValueError): - cipher.unseal(ct) - - -class KW_Wycheproof(unittest.TestCase): - - def setUp(self): - self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "kw_test.json", - "Wycheproof tests for KW") - - def test_wycheproof(self): - - if not self.vectors: - self.skipTest("No test vectors available") - - for vector in self.vectors: - with self.subTest(testId=vector.id): - cipher = AES.new(vector.key, AES.MODE_KW) - - try: - cipher.seal(vector.msg) - except ValueError: - if vector.valid: - raise - continue - - cipher = AES.new(vector.key, AES.MODE_KW) - try: - pt = cipher.unseal(vector.ct) - except ValueError: - if vector.valid: - raise - continue - - self.assertEqual(pt, vector.msg) - - -class KWP_Tests(unittest.TestCase): - - tvs = [ - ("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8", - "c37b7e6492584340bed12207808941155068f738", - "138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"), - ("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8", - "466f7250617369", - "afbeb0f07dfbf5419200f2ccb50bb24f"), - ] - - def test_rfc5649(self): - for tv in self.tvs: - kek, pt, ct = [bytes.fromhex(x) for x in tv] - - cipher = AES.new(kek, AES.MODE_KWP) - ct2 = cipher.seal(pt) - - self.assertEqual(ct, ct2) - - cipher = AES.new(kek, AES.MODE_KWP) - pt2 = cipher.unseal(ct) - self.assertEqual(pt, pt2) - - -class KWP_Wycheproof(unittest.TestCase): - - def setUp(self): - self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "kwp_test.json", - "Wycheproof tests for KWP") - - def test_wycheproof(self): - - if not self.vectors: - self.skipTest("No test vectors available") - - for vector in self.vectors: - with self.subTest(testId=vector.id): - cipher = AES.new(vector.key, AES.MODE_KWP) - - try: - cipher.seal(vector.msg) - except ValueError: - if vector.valid and not vector.warning: - raise - continue - - cipher = AES.new(vector.key, AES.MODE_KWP) - try: - pt = cipher.unseal(vector.ct) - except ValueError: - if vector.valid and not vector.warning: - raise - continue - - self.assertEqual(pt, vector.msg) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(KW_Tests) - tests += list_test_cases(KWP_Tests) - tests += list_test_cases(KW_Wycheproof) - tests += list_test_cases(KWP_Wycheproof) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OCB.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OCB.py deleted file mode 100644 index 6e1a47c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OCB.py +++ /dev/null @@ -1,845 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import b, tobytes, bchr -from Crypto.Util.number import long_to_bytes -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class OcbTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct, mac = cipher.encrypt_and_digest(pt) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce is optional - AES.new(self.key_128, AES.MODE_OCB) - - cipher = AES.new(self.key_128, AES.MODE_OCB, self.nonce_96) - ct = cipher.encrypt(self.data) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEqual(ct, cipher.encrypt(self.data)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce cannot be empty - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=b("")) - - # nonce can be up to 15 bytes long - for length in range(1, 16): - AES.new(self.key_128, AES.MODE_OCB, nonce=self.data[:length]) - - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.data) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce - nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce - self.assertEqual(len(nonce1), 15) - self.assertNotEqual(nonce1, nonce2) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce - nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce - self.assertEqual(len(nonce1), 15) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - result = getattr(cipher, func)(b("")) - self.assertEqual(result, b("")) - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt(b("xyz")) - self.assertRaises(TypeError, cipher.decrypt, b("xyz")) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt(b("xyz")) - self.assertRaises(TypeError, cipher.encrypt, b("xyz")) - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, mac_len=7) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(8, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b("") - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - pt2 += cipher.decrypt() - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b("") - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - ct2 += cipher.encrypt() - self.assertEqual(ciphertext, ct2) - self.assertEqual(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - data_ba = bytearray(self.data) - - cipher1 = AES.new(self.key_128, - AES.MODE_OCB, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) + cipher1.encrypt() - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_OCB, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) + cipher2.encrypt() - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_OCB, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - data_mv = memoryview(bytearray(self.data)) - - cipher1 = AES.new(self.key_128, - AES.MODE_OCB, - nonce=self.nonce_96) - cipher1.update(self.data) - ct = cipher1.encrypt(self.data) + cipher1.encrypt() - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_OCB, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) + cipher2.encrypt() - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_OCB, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data, pt_test) - - -class OcbFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->ENCRYPT(NONE)->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - ct += cipher.encrypt() - mac = cipher.digest() - - # Verify path INIT->DECRYPT->DECRYPT(NONCE)->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - - def test_invalid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - self.assertRaises(TypeError, cipher.digest) - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.decrypt(ct) - self.assertRaises(TypeError, cipher.verify) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT(NONE)->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - ct = cipher.encrypt(self.data) - ct += cipher.encrypt() - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->DECRYPT(NONE)->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - - # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT_AND_DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - ct1 = cipher.encrypt(self.data[:2]) - ct2, mac = cipher.encrypt_and_digest(self.data[2:]) - - # Verify path INIT->UPDATE->DECRYPT->DECRYPT_AND_VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.decrypt(ct1) - cipher.decrypt_and_verify(ct2, mac) - - def test_invalid_encrypt_after_final(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.encrypt(self.data) - cipher.encrypt() - self.assertRaises(TypeError, cipher.encrypt, self.data) - - def test_invalid_decrypt_after_final(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.decrypt(self.data) - cipher.decrypt() - self.assertRaises(TypeError, cipher.decrypt, self.data) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b("333"), self.data, - self.data + b("3")): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data) - method(self.data) - method(self.data) - method(self.data) - method() - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data) - ct, mac = cipher.encrypt_and_digest(self.data) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data) - getattr(cipher, method1_name)(self.data) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt(self.data) - cipher.encrypt() - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - ct = cipher.encrypt(self.data) - ct += cipher.encrypt() - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data) - - -def algo_rfc7253(keylen, taglen, noncelen): - """Implement the algorithm at page 18 of RFC 7253""" - - key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) - C = b"" - - for i in range(128): - S = bchr(0) * i - - N = long_to_bytes(3 * i + 1, noncelen // 8) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(S) - C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() - - N = long_to_bytes(3 * i + 2, noncelen // 8) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() - - N = long_to_bytes(3 * i + 3, noncelen // 8) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(S) - C += cipher.encrypt() + cipher.digest() - - N = long_to_bytes(385, noncelen // 8) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(C) - return cipher.encrypt() + cipher.digest() - - -class OcbRfc7253Test(unittest.TestCase): - - # Tuple with - # - nonce - # - authenticated data - # - plaintext - # - ciphertext and 16 byte MAC tag - tv1_key = "000102030405060708090A0B0C0D0E0F" - tv1 = ( - ( - "BBAA99887766554433221100", - "", - "", - "785407BFFFC8AD9EDCC5520AC9111EE6" - ), - ( - "BBAA99887766554433221101", - "0001020304050607", - "0001020304050607", - "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" - ), - ( - "BBAA99887766554433221102", - "0001020304050607", - "", - "81017F8203F081277152FADE694A0A00" - ), - ( - "BBAA99887766554433221103", - "", - "0001020304050607", - "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" - ), - ( - "BBAA99887766554433221104", - "000102030405060708090A0B0C0D0E0F", - "000102030405060708090A0B0C0D0E0F", - "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5" - "701C1CCEC8FC3358" - ), - ( - "BBAA99887766554433221105", - "000102030405060708090A0B0C0D0E0F", - "", - "8CF761B6902EF764462AD86498CA6B97" - ), - ( - "BBAA99887766554433221106", - "", - "000102030405060708090A0B0C0D0E0F", - "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436B" - "DF06D8FA1ECA343D" - ), - ( - "BBAA99887766554433221107", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "1CA2207308C87C010756104D8840CE1952F09673A448A122" - "C92C62241051F57356D7F3C90BB0E07F" - ), - ( - "BBAA99887766554433221108", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "", - "6DC225A071FC1B9F7C69F93B0F1E10DE" - ), - ( - "BBAA99887766554433221109", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3C" - "E725F32494B9F914D85C0B1EB38357FF" - ), - ( - "BBAA9988776655443322110A", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DE" - "AFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" - ), - ( - "BBAA9988776655443322110B", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "", - "FE80690BEE8A485D11F32965BC9D2A32" - ), - ( - "BBAA9988776655443322110C", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF4" - "6040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" - ), - ( - "BBAA9988776655443322110D", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460" - "6E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483" - "A7035490C5769E60" - ), - ( - "BBAA9988776655443322110E", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "", - "C5CD9D1850C141E358649994EE701B68" - ), - ( - "BBAA9988776655443322110F", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15" - "A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95" - "A98CA5F3000B1479" - ) - ) - - # Tuple with - # - key - # - nonce - # - authenticated data - # - plaintext - # - ciphertext and 12 byte MAC tag - tv2 = ( - "0F0E0D0C0B0A09080706050403020100", - "BBAA9988776655443322110D", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" - "A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FD" - "AC4F02AA" - ) - - # Tuple with - # - key length - # - MAC tag length - # - Expected output - tv3 = ( - (128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"), - (192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"), - (256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"), - (128, 96, "77A3D8E73589158D25D01209"), - (192, 96, "05D56EAD2752C86BE6932C5E"), - (256, 96, "5458359AC23B0CBA9E6330DD"), - (128, 64, "192C9B7BD90BA06A"), - (192, 64, "0066BC6E0EF34E24"), - (256, 64, "7D4EA5D445501CBE"), - ) - - def test1(self): - key = unhexlify(b(self.tv1_key)) - for tv in self.tv1: - nonce, aad, pt, ct = [unhexlify(b(x)) for x in tv] - ct, mac_tag = ct[:-16], ct[-16:] - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - cipher.update(aad) - ct2 = cipher.encrypt(pt) + cipher.encrypt() - self.assertEqual(ct, ct2) - self.assertEqual(mac_tag, cipher.digest()) - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - cipher.update(aad) - pt2 = cipher.decrypt(ct) + cipher.decrypt() - self.assertEqual(pt, pt2) - cipher.verify(mac_tag) - - def test2(self): - - key, nonce, aad, pt, ct = [unhexlify(b(x)) for x in self.tv2] - ct, mac_tag = ct[:-12], ct[-12:] - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) - cipher.update(aad) - ct2 = cipher.encrypt(pt) + cipher.encrypt() - self.assertEqual(ct, ct2) - self.assertEqual(mac_tag, cipher.digest()) - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) - cipher.update(aad) - pt2 = cipher.decrypt(ct) + cipher.decrypt() - self.assertEqual(pt, pt2) - cipher.verify(mac_tag) - - def test3(self): - for keylen, taglen, result in self.tv3: - result2 = algo_rfc7253(keylen, taglen, 96) - self.assertEqual(unhexlify(b(result)), result2) - - -class OcbDkgTest(unittest.TestCase): - """Test vectors from https://gitlab.com/dkg/ocb-test-vectors""" - - def test_1_2(self): - tvs = [] - for fi in (1, 2): - for nb in (104, 112, 120): - tv_file = load_test_vectors(("Cipher", "AES"), - "test-vector-%d-nonce%d.txt" % (fi, nb), - "DKG tests, %d, %d bits" % (fi, nb), - {}) - if tv_file is None: - break - key = tv_file[0].k - for tv in tv_file[1:]: - tv.k = key - tvs.append(tv) - - for tv in tvs: - k, n, a, p, c = tv.k, tv.n, tv.a, tv.p, tv.c - mac_len = len(c) - len(p) - cipher = AES.new(k, AES.MODE_OCB, nonce=n, mac_len=mac_len) - cipher.update(a) - c_out, tag_out = cipher.encrypt_and_digest(p) - self.assertEqual(c, c_out + tag_out) - - def test_3(self): - - def check(keylen, taglen, noncelen, exp): - result = algo_rfc7253(keylen, taglen, noncelen) - self.assertEqual(result, unhexlify(exp)) - - # test-vector-3-nonce104.txt - check(128, 128, 104, "C47F5F0341E15326D4D1C46F47F05062") - check(192, 128, 104, "95B9167A38EB80495DFC561A8486E109") - check(256, 128, 104, "AFE1CDDB97028FD92F8FB3C8CFBA7D83") - check(128, 96, 104, "F471B4983BA80946DF217A54") - check(192, 96, 104, "5AE828BC51C24D85FA5CC7B2") - check(256, 96, 104, "8C8335982E2B734616CAD14C") - check(128, 64, 104, "B553F74B85FD1E5B") - check(192, 64, 104, "3B49D20E513531F9") - check(256, 64, 104, "ED6DA5B1216BF8BB") - - # test-vector-3-nonce112.txt - check(128, 128, 112, "CA8AFCA031BAC3F480A583BD6C50A547") - check(192, 128, 112, "D170C1DF356308079DA9A3F619147148") - check(256, 128, 112, "57F94381F2F9231EFB04AECD323757C3") - check(128, 96, 112, "3A618B2531ED39F260C750DC") - check(192, 96, 112, "9071EB89FEDBADDA88FD286E") - check(256, 96, 112, "FDF0EFB97F21A39AC4BAB5AC") - check(128, 64, 112, "FAB2FF3A8DD82A13") - check(192, 64, 112, "AC01D912BD0737D3") - check(256, 64, 112, "9D1FD0B500EA4ECF") - - # test-vector-3-nonce120.txt - check(128, 128, 120, "9E043A7140A25FB91F43BCC9DD7E0F46") - check(192, 128, 120, "680000E53908323A7F396B955B8EC641") - check(256, 128, 120, "8304B97FAACDA56E676602E1878A7E6F") - check(128, 96, 120, "81F978AC9867E825D339847D") - check(192, 96, 120, "EFCF2D60B24926ADA48CF5B1") - check(256, 96, 120, "84961DC56E917B165E58C174") - check(128, 64, 120, "227AEE6C9D905A61") - check(192, 64, 120, "541DE691B9E1A2F9") - check(256, 64, 120, "B0E761381C7129FC") - - def test_2_bugfix(self): - nonce = unhexlify("EEDDCCBBAA9988776655443322110D") - key = unhexlify("0F0E0D0C0B0A09080706050403020100") - A = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627") - P = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627") - C = unhexlify("07E903BFC49552411ABC865F5ECE60F6FAD1F5A9F14D3070" - "FA2F1308A563207FFE14C1EEA44B22059C7484319D8A2C53" - "C236A7B3") - mac_len = len(C) - len(P) - - # Prior to version 3.17, a nonce of maximum length (15 bytes) - # was actually used as a 14 byte nonce. The last byte was erroneously - # ignored. - buggy_result = unhexlify("BA015C4E5AE54D76C890AE81BD40DC57" - "03EDC30E8AC2A58BC5D8FA4D61C5BAE6" - "C39BEAC435B2FD56A2A5085C1B135D77" - "0C8264B7") - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce[:-1], mac_len=mac_len) - cipher.update(A) - C_out2, tag_out2 = cipher.encrypt_and_digest(P) - self.assertEqual(buggy_result, C_out2 + tag_out2) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OcbTests) - tests += list_test_cases(OcbFSMTests) - tests += list_test_cases(OcbRfc7253Test) - tests += list_test_cases(OcbDkgTest) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OFB.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OFB.py deleted file mode 100644 index ec145ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OFB.py +++ /dev/null @@ -1,238 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - -class OfbTests(BlockChainingTests): - - aes_mode = AES.MODE_OFB - des3_mode = DES3.MODE_OFB - - # Redefine test_unaligned_data_128/64 - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - -from Crypto.SelfTest.Cipher.test_CBC import NistBlockChainingVectors - -class NistOfbVectors(NistBlockChainingVectors): - aes_mode = AES.MODE_OFB - des_mode = DES.MODE_OFB - des3_mode = DES3.MODE_OFB - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "OFBGFSbox128.rsp", - "OFBGFSbox192.rsp", - "OFBGFSbox256.rsp", - "OFBKeySbox128.rsp", - "OFBKeySbox192.rsp", - "OFBKeySbox256.rsp", - "OFBVarKey128.rsp", - "OFBVarKey192.rsp", - "OFBVarKey256.rsp", - "OFBVarTxt128.rsp", - "OFBVarTxt192.rsp", - "OFBVarTxt256.rsp", - # MMT - "OFBMMT128.rsp", - "OFBMMT192.rsp", - "OFBMMT256.rsp", - ) -nist_aes_mct_files = ( - "OFBMCT128.rsp", - "OFBMCT192.rsp", - "OFBMCT256.rsp", - ) - -for file_name in nist_aes_kat_mmt_files: - def new_func(self, file_name=file_name): - self._do_kat_aes_test(file_name) - setattr(NistOfbVectors, "test_AES_" + file_name, new_func) - -for file_name in nist_aes_mct_files: - def new_func(self, file_name=file_name): - self._do_mct_aes_test(file_name) - setattr(NistOfbVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TOFBMMT2.rsp", # 2TDES - "TOFBMMT3.rsp", # 3TDES - "TOFBinvperm.rsp", # Single DES - "TOFBpermop.rsp", - "TOFBsubtab.rsp", - "TOFBvarkey.rsp", - "TOFBvartext.rsp", - ) - -for file_name in nist_tdes_files: - def new_func(self, file_name=file_name): - self._do_tdes_test(file_name) - setattr(NistOfbVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST OFB TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the OFB test vectors found in Section F.4 - of NIST SP 800-3A""" - - def test_aes_128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ - '7789508d16918f03f53c52dac54ed825' +\ - '9740051e9c5fecf64344f7a82260edcc' +\ - '304c6528f659c77866a510d9c1d6ae5e' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - def test_aes_192(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ - 'fcc28b8d4c63837c09e81700c1100401' +\ - '8d9a9aeac0f6596f559c6d4daf59a5f2' +\ - '6d9f200857ca6c3e9cac524bd9acc92a' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - def test_aes_256(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ - '4febdc6740d20b3ac88f6ad82a4fb08d' +\ - '71ab47a086e86eedf39d1c5bba97c408' +\ - '0126141d67f37be8538f5a8be740e484' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OfbTests) - if config.get('slow_tests'): - tests += list_test_cases(NistOfbVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OpenPGP.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OpenPGP.py deleted file mode 100644 index e6cae67..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_OpenPGP.py +++ /dev/null @@ -1,218 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - -class OpenPGPTests(BlockChainingTests): - - aes_mode = AES.MODE_OPENPGP - des3_mode = DES3.MODE_OPENPGP - - # Redefine test_unaligned_data_128/64 - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - iv_128 = get_tag_random("iv_128", 16) - iv_64 = get_tag_random("iv_64", 8) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - eiv, ct = ct[:18], ct[18:] - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - eiv, ct = ct[:10], ct[10:] - - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, eiv) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_IV_iv_attributes(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - self.assertEqual(cipher.iv, self.iv_128) - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - self.assertEqual(cipher.iv, self.iv_128) - - def test_null_encryption_decryption(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - self.assertEqual(cipher.decrypt(b""), b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_output_param(self): - pass - - def test_output_param_same_buffer(self): - pass - - def test_output_param_memoryview(self): - pass - - def test_output_param_neg(self): - pass - - -class TestVectors(unittest.TestCase): - - def test_aes(self): - # The following test vectors have been generated with gpg v1.4.0. - # The command line used was: - # - # gpg -c -z 0 --cipher-algo AES --passphrase secret_passphrase \ - # --disable-mdc --s2k-mode 0 --output ct pt - # - # As result, the content of the file 'pt' is encrypted with a key derived - # from 'secret_passphrase' and written to file 'ct'. - # Test vectors must be extracted from 'ct', which is a collection of - # TLVs (see RFC4880 for all details): - # - the encrypted data (with the encrypted IV as prefix) is the payload - # of the TLV with tag 9 (Symmetrical Encrypted Data Packet). - # This is the ciphertext in the test vector. - # - inside the encrypted part, there is a further layer of TLVs. One must - # look for tag 11 (Literal Data Packet); in its payload, after a short - # but time dependent header, there is the content of file 'pt'. - # In the test vector, the plaintext is the complete set of TLVs that gets - # encrypted. It is not just the content of 'pt'. - # - the key is the leftmost 16 bytes of the SHA1 digest of the password. - # The test vector contains such shortened digest. - # - # Note that encryption uses a clear IV, and decryption an encrypted IV - - plaintext = 'ac18620270744fb4f647426c61636b4361745768697465436174' - ciphertext = 'dc6b9e1f095de609765c59983db5956ae4f63aea7405389d2ebb' - key = '5baa61e4c9b93f3f0682250b6cf8331b' - iv = '3d7d3e62282add7eb203eeba5c800733' - encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' - - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - key = unhexlify(key) - iv = unhexlify(iv) - encrypted_iv = unhexlify(encrypted_iv) - - cipher = AES.new(key, AES.MODE_OPENPGP, iv) - ct = cipher.encrypt(plaintext) - self.assertEqual(ct[:18], encrypted_iv) - self.assertEqual(ct[18:], ciphertext) - - cipher = AES.new(key, AES.MODE_OPENPGP, encrypted_iv) - pt = cipher.decrypt(ciphertext) - self.assertEqual(pt, plaintext) - - def test_des3(self): - # The following test vectors have been generated with gpg v1.4.0. - # The command line used was: - # gpg -c -z 0 --cipher-algo 3DES --passphrase secret_passphrase \ - # --disable-mdc --s2k-mode 0 --output ct pt - # For an explanation, see test_AES.py . - - plaintext = 'ac1762037074324fb53ba3596f73656d69746556616c6c6579' - ciphertext = '9979238528357b90e2e0be549cb0b2d5999b9a4a447e5c5c7d' - key = '7ade65b460f5ea9be35f9e14aa883a2048e3824aa616c0b2' - iv='cd47e2afb8b7e4b0' - encrypted_iv='6a7eef0b58050e8b904a' - - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - key = unhexlify(key) - iv = unhexlify(iv) - encrypted_iv = unhexlify(encrypted_iv) - - cipher = DES3.new(key, DES3.MODE_OPENPGP, iv) - ct = cipher.encrypt(plaintext) - self.assertEqual(ct[:10], encrypted_iv) - self.assertEqual(ct[10:], ciphertext) - - cipher = DES3.new(key, DES3.MODE_OPENPGP, encrypted_iv) - pt = cipher.decrypt(ciphertext) - self.assertEqual(pt, plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OpenPGPTests) - tests += list_test_cases(TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_SIV.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_SIV.py deleted file mode 100644 index a80ddc1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_SIV.py +++ /dev/null @@ -1,552 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import json -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class SivTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - key_384 = get_tag_random("key_384", 48) - key_512 = get_tag_random("key_512", 64) - nonce_96 = get_tag_random("nonce_128", 12) - data = get_tag_random("data", 128) - - def test_loopback_128(self): - for key in self.key_256, self.key_384, self.key_512: - cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct, mac = cipher.encrypt_and_digest(pt) - - cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Deterministic encryption - AES.new(self.key_256, AES.MODE_SIV) - - cipher = AES.new(self.key_256, AES.MODE_SIV, self.nonce_96) - ct1, tag1 = cipher.encrypt_and_digest(self.data) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct2, tag2 = cipher.encrypt_and_digest(self.data) - self.assertEqual(ct1 + tag1, ct2 + tag2) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_256, AES.MODE_SIV, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=bchr(1) * x) - cipher.encrypt_and_digest(b'\x01') - - def test_block_size_128(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, no nonce is randomly generated - self.assertFalse(hasattr(AES.new(self.key_256, AES.MODE_SIV), "nonce")) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96, - use_aesni=False) - - def test_encrypt_excludes_decrypt(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data) - self.assertRaises(TypeError, cipher.decrypt, self.data) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data) - self.assertRaises(TypeError, cipher.decrypt_and_verify, - self.data, self.data) - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt_and_verify, - u'test1234567890-*', b"xxxx") - - def test_mac_len(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_bytearray(self): - - # Encrypt - key = bytearray(self.key_256) - nonce = bytearray(self.nonce_96) - data = bytearray(self.data) - header = bytearray(self.data) - - cipher1 = AES.new(self.key_256, - AES.MODE_SIV, - nonce=self.nonce_96) - cipher1.update(self.data) - ct, tag = cipher1.encrypt_and_digest(self.data) - - cipher2 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher2.update(header) - header[:3] = b'\xFF\xFF\xFF' - ct_test, tag_test = cipher2.encrypt_and_digest(data) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key = bytearray(self.key_256) - nonce = bytearray(self.nonce_96) - header = bytearray(self.data) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - - cipher3 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher3.update(header) - header[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) - - self.assertEqual(self.data, pt_test) - - def test_memoryview(self): - - # Encrypt - key = memoryview(bytearray(self.key_256)) - nonce = memoryview(bytearray(self.nonce_96)) - data = memoryview(bytearray(self.data)) - header = memoryview(bytearray(self.data)) - - cipher1 = AES.new(self.key_256, - AES.MODE_SIV, - nonce=self.nonce_96) - cipher1.update(self.data) - ct, tag = cipher1.encrypt_and_digest(self.data) - - cipher2 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher2.update(header) - header[:3] = b'\xFF\xFF\xFF' - ct_test, tag_test= cipher2.encrypt_and_digest(data) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key = memoryview(bytearray(self.key_256)) - nonce = memoryview(bytearray(self.nonce_96)) - header = memoryview(bytearray(self.data)) - ct_ba = memoryview(bytearray(ct)) - tag_ba = memoryview(bytearray(tag)) - - cipher3 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher3.update(header) - header[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) - - self.assertEqual(self.data, pt_test) - - def test_output_param(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - output = bytearray(128) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 128 - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - output = memoryview(bytearray(128)) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - LEN_PT = 128 - - pt = b'5' * LEN_PT - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt_and_digest, pt, output=b'0' * LEN_PT) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag, output=b'0' * LEN_PT) - - shorter_output = bytearray(LEN_PT - 1) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt_and_digest, pt, output=shorter_output) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, tag, output=shorter_output) - - -class SivFSMTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data = get_tag_random("data", 128) - - def test_invalid_init_encrypt(self): - # Path INIT->ENCRYPT fails - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, b"xxx") - - def test_invalid_init_decrypt(self): - # Path INIT->DECRYPT fails - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, b"xxx") - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - cipher.update(self.data) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - cipher.update(self.data) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data) - ct, mac = cipher.encrypt_and_digest(self.data) - - # decrypt_and_verify - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data, pt) - - def test_invalid_multiple_encrypt_and_digest(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(self.data) - self.assertRaises(TypeError, cipher.encrypt_and_digest, b'') - - def test_invalid_multiple_decrypt_and_verify(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(self.data) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, tag) - self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag) - - -def transform(tv): - new_tv = [[unhexlify(x) for x in tv[0].split("-")]] - new_tv += [ unhexlify(x) for x in tv[1:5]] - if tv[5]: - nonce = unhexlify(tv[5]) - else: - nonce = None - new_tv += [ nonce ] - return new_tv - - -class TestVectors(unittest.TestCase): - """Class exercising the SIV test vectors found in RFC5297""" - - # This is a list of tuples with 5 items: - # - # 1. Header + '|' + plaintext - # 2. Header + '|' + ciphertext + '|' + MAC - # 3. AES-128 key - # 4. Description - # 5. Dictionary of parameters to be passed to AES.new(). - # It must include the nonce. - # - # A "Header" is a dash ('-') separated sequece of components. - # - test_vectors_hex = [ - ( - '101112131415161718191a1b1c1d1e1f2021222324252627', - '112233445566778899aabbccddee', - '40c02b9690c4dc04daef7f6afe5c', - '85632d07c6e8f37f950acd320a2ecc93', - 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', - None - ), - ( - '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' + - '7766554433221100-102030405060708090a0', - '7468697320697320736f6d6520706c61696e7465787420746f20656e63727970' + - '74207573696e67205349562d414553', - 'cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829' + - 'ea64ad544a272e9c485b62a3fd5c0d', - '7bdb6e3b432667eb06f4d14bff2fbd0f', - '7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f', - '09f911029d74e35bd84156c5635688c0' - ), - ] - - test_vectors = [ transform(tv) for tv in test_vectors_hex ] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - - # Encrypt - cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) - for x in assoc_data: - cipher.update(x) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) - for x in assoc_data: - cipher.update(x) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self): - unittest.TestCase.__init__(self) - self._id = "None" - - def setUp(self): - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_siv_cmac_test.json", - "Wycheproof AES SIV") - - def shortDescription(self): - return self._id - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV) - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(tag + ct, tv.ct) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt AES_SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV) - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct[16:], tv.ct[:16]) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - - -class TestVectorsWycheproof2(unittest.TestCase): - - def __init__(self): - unittest.TestCase.__init__(self) - self._id = "None" - - def setUp(self): - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aead_aes_siv_cmac_test.json", - "Wycheproof AEAD SIV") - - def shortDescription(self): - return self._id - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt AEAD-AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt AEAD-AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(SivTests) - tests += list_test_cases(SivFSMTests) - tests += [ TestVectors() ] - tests += [ TestVectorsWycheproof() ] - tests += [ TestVectorsWycheproof2() ] - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Salsa20.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Salsa20.py deleted file mode 100644 index a710462..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_Salsa20.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/Salsa20.py: Self-test for the Salsa20 stream cipher -# -# Written in 2013 by Fabrizio Tarizzo -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.Salsa20""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import Salsa20 - -from .common import make_stream_tests - -# This is a list of (plaintext, ciphertext, key[, description[, params]]) -# tuples. -test_data = [ - # Test vectors are taken from - # http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors - ( '00' * 512, - '4dfa5e481da23ea09a31022050859936da52fcee218005164f267cb65f5cfd7f' - + '2b4f97e0ff16924a52df269515110a07f9e460bc65ef95da58f740b7d1dbb0aa' - + 'd64cec189c7eb8c6bbf3d7376c80a481d43e628701f6a27afb9fe23919f24114' - + '8db44f70d7063efcc3dd55a0893a613c3c6fe1c127bd6f59910589293bb6ef9e' - + 'e24819066dee1a64f49b0bbad5988635272b169af861f85df881939f29ada6fd' - + '0241410e8d332ae4798d929434a2630de451ec4e0169694cbaa7ebb121ea6a2b' - + 'da9c1581f429e0a00f7d67e23b730676783b262e8eb43a25f55fb90b3e753aef' - + '8c6713ec66c51881111593ccb3e8cb8f8de124080501eeeb389c4bcb6977cf95' - + '7d5789631eb4554400e1e025935dfa7b3e9039d61bdc58a8697d36815bf1985c' - + 'efdf7ae112e5bb81e37ecf0616ce7147fc08a93a367e08631f23c03b00a8da2f' - + 'aa5024e5c8d30aca43fc2d5082067b21b234bc741d68fb292c6012c3764ccee3' - + '1e364a5403e00cfee338a21a01e7d3cefd5a770ca0ab48c435ea6116435f7ad8' - + '30b217b49f978a68e207ed9f462af7fb195b2115fe8f24f152e4ddc32202d6f2' - + 'b52fafbcfbc202d8a259a611e901d3f62d065eb13f09bbc45cd45119b843efaa' - + 'b375703739daced4dd4059fd71c3c47fc2f9939670fad4a46066adcc6a564578' - + '3308b90ffb72be04a6b147cbe38cc0c3b9267c296a92a7c69873f9f263be9703', - '80000000000000000000000000000000', - '128 bits key, set 1, vector 0', - dict (iv='00'*8)), - - ( '00' * 512, - 'e3be8fdd8beca2e3ea8ef9475b29a6e7003951e1097a5c38d23b7a5fad9f6844' - + 'b22c97559e2723c7cbbd3fe4fc8d9a0744652a83e72a9c461876af4d7ef1a117' - + '8da2b74eef1b6283e7e20166abcae538e9716e4669e2816b6b20c5c356802001' - + 'cc1403a9a117d12a2669f456366d6ebb0f1246f1265150f793cdb4b253e348ae' - + '203d89bc025e802a7e0e00621d70aa36b7e07cb1e7d5b38d5e222b8b0e4b8407' - + '0142b1e29504767d76824850320b5368129fdd74e861b498e3be8d16f2d7d169' - + '57be81f47b17d9ae7c4ff15429a73e10acf250ed3a90a93c711308a74c6216a9' - + 'ed84cd126da7f28e8abf8bb63517e1ca98e712f4fb2e1a6aed9fdc73291faa17' - + '958211c4ba2ebd5838c635edb81f513a91a294e194f1c039aeec657dce40aa7e' - + '7c0af57cacefa40c9f14b71a4b3456a63e162ec7d8d10b8ffb1810d71001b618' - + '2f9f73da53b85405c11f7b2d890fa8ae0c7f2e926d8a98c7ec4e91b65120e988' - + '349631a700c6facec3471cb0413656e75e309456584084d7e12c5b43a41c43ed' - + '9a048abd9b880da65f6a665a20fe7b77cd292fe62cae644b7f7df69f32bdb331' - + '903e6505ce44fdc293920c6a9ec7057e23df7dad298f82ddf4efb7fdc7bfc622' - + '696afcfd0cddcc83c7e77f11a649d79acdc3354e9635ff137e929933a0bd6f53' - + '77efa105a3a4266b7c0d089d08f1e855cc32b15b93784a36e56a76cc64bc8477', - '8000000000000000000000000000000000000000000000000000000000000000', - '256 bits key, set 1, vector 0', - dict (iv='00'*8)), - - ( '00' * 512, - '169060ccb42bea7bee4d8012a02f3635eb7bca12859fa159cd559094b3507db8' - + '01735d1a1300102a9c9415546829cbd2021ba217b39b81d89c55b13d0c603359' - + '3f84159a3c84f4b4f4a0edcd9d38ff261a737909e0b66d68b5cac496f3a5be99' - + 'cb12c321ab711afaab36cc0947955e1a9bb952ed54425e7711279fbc81bb83f5' - + '6e55cea44e6daddb05858a153ea6213b3350c12aa1a83ef2726f09485fa71790' - + 'f9b9f922c7dda1113b1f9d56658ed3402803f511bc1f122601d5e7f0ff036e23' - + '23ef24bb24195b9fd574823cd8a40c29d86bd35c191e2038779ff696c712b6d8' - + '2e7014dbe1ac5d527af076c088c4a8d44317958189f6ef54933a7e0816b5b916' - + 'd8f12ed8afe9422b85e5cc9b8adec9d6cfabe8dbc1082bccc02f5a7266aa074c' - + 'a284e583a35837798cc0e69d4ce937653b8cdd65ce414b89138615ccb165ad19' - + '3c6b9c3d05eef4be921a10ea811fe61d11c6867600188e065daff90b509ec56b' - + 'd41e7e8968c478c78d590c2d2ee24ea009c8f49bc3d81672cfc47895a9e21c9a' - + '471ebf8e294bee5d2de436ac8d052bf31111b345f1da23c3a4d13b9fc5f0900a' - + 'a298f98f538973b8fad40d4d159777de2cfe2a3dead1645ddb49794827dba040' - + 'f70a0ff4ecd155e0f033604693a51e2363880e2ecf98699e7174af7c2c6b0fc6' - + '59ae329599a3949272a37b9b2183a0910922a3f325ae124dcbdd735364055ceb', - '09090909090909090909090909090909', - '128 bits key, set 2, vector 9', - dict (iv='00'*8)), - - ( '00' * 512, - '7041e747ceb22ed7812985465f50333124f971da1c5d6efe5ca201b886f31046' - + 'e757e5c3ec914f60ed1f6bce2819b6810953f12b8ba1199bf82d746a8b8a88f1' - + '142002978ec4c35b95dc2c82990f9e847a0ab45f2ca72625f5190c820f29f3aa' - + 'f5f0b5572b06b70a144f2a240c3b3098d4831fa1ce1459f8d1df226a6a79b0ab' - + '41e91799ef31b5ff3d756c19126b19025858ee70fbd69f2be955cb011c005e31' - + '32b271b378f39b0cb594e95c99ce6ff17735a541891845bbf0450afcb4a850b9' - + '4ee90afb713ae7e01295c74381180a3816d7020d5a396c0d97aaa783eaabb6ec' - + '44d5111157f2212d1b1b8fca7893e8b520cd482418c272ab119b569a2b9598eb' - + '355624d12e79adab81153b58cd22eaf1b2a32395dedc4a1c66f4d274070b9800' - + 'ea95766f0245a8295f8aadb36ddbbdfa936417c8dbc6235d19494036964d3e70' - + 'b125b0f800c3d53881d9d11e7970f827c2f9556935cd29e927b0aceb8cae5fd4' - + '0fd88a8854010a33db94c96c98735858f1c5df6844f864feaca8f41539313e7f' - + '3c0610214912cd5e6362197646207e2d64cd5b26c9dfe0822629dcbeb16662e8' - + '9ff5bf5cf2e499138a5e27bd5027329d0e68ddf53103e9e409523662e27f61f6' - + '5cf38c1232023e6a6ef66c315bcb2a4328642faabb7ca1e889e039e7c444b34b' - + 'b3443f596ac730f3df3dfcdb343c307c80f76e43e8898c5e8f43dc3bb280add0', - '0909090909090909090909090909090909090909090909090909090909090909', - '256 bits key, set 2, vector 9', - dict (iv='00'*8)), - - ( '00' * 1024, - '71daee5142d0728b41b6597933ebf467e43279e30978677078941602629cbf68' - + 'b73d6bd2c95f118d2b3e6ec955dabb6dc61c4143bc9a9b32b99dbe6866166dc0' - + '8631b7d6553050303d7252c264d3a90d26c853634813e09ad7545a6ce7e84a5d' - + 'fc75ec43431207d5319970b0faadb0e1510625bb54372c8515e28e2accf0a993' - + '0ad15f431874923d2a59e20d9f2a5367dba6051564f150287debb1db536ff9b0' - + '9ad981f25e5010d85d76ee0c305f755b25e6f09341e0812f95c94f42eead346e' - + '81f39c58c5faa2c88953dc0cac90469db2063cb5cdb22c9eae22afbf0506fca4' - + '1dc710b846fbdfe3c46883dd118f3a5e8b11b6afd9e71680d8666557301a2daa' - + 'fb9496c559784d35a035360885f9b17bd7191977deea932b981ebdb29057ae3c' - + '92cfeff5e6c5d0cb62f209ce342d4e35c69646ccd14e53350e488bb310a32f8b' - + '0248e70acc5b473df537ced3f81a014d4083932bedd62ed0e447b6766cd2604b' - + '706e9b346c4468beb46a34ecf1610ebd38331d52bf33346afec15eefb2a7699e' - + '8759db5a1f636a48a039688e39de34d995df9f27ed9edc8dd795e39e53d9d925' - + 'b278010565ff665269042f05096d94da3433d957ec13d2fd82a0066283d0d1ee' - + 'b81bf0ef133b7fd90248b8ffb499b2414cd4fa003093ff0864575a43749bf596' - + '02f26c717fa96b1d057697db08ebc3fa664a016a67dcef8807577cc3a09385d3' - + 'f4dc79b34364bb3b166ce65fe1dd28e3950fe6fa81063f7b16ce1c0e6daac1f8' - + '188455b77752045e863c9b256ad92bc6e2d08314c5bba191c274f42dfbb3d652' - + 'bb771956555e880f84cd8b827a4c5a52f3a099fa0259bd4aac3efd541f191170' - + '4412d6e85fbcc628b335875b9fef24807f6e1bc66c3186159e1e7f5a13913e02' - + 'd241ce2efdbcaa275039fb14eac5923d17ffbc7f1abd3b45e92127575bfbabf9' - + '3a257ebef0aa1437b326e41b585af572f7239c33b32981a1577a4f629b027e1e' - + 'b49d58cc497e944d79cef44357c2bf25442ab779651e991147bf79d6fd3a8868' - + '0cd3b1748e07fd10d78aceef6db8a5e563570d40127f754146c34a440f2a991a' - + '23fa39d365141f255041f2135c5cba4373452c114da1801bacca38610e3a6524' - + '2b822d32de4ab5a7d3cf9b61b37493c863bd12e2cae10530cddcda2cb7a5436b' - + 'ef8988d4d24e8cdc31b2d2a3586340bc5141f8f6632d0dd543bfed81eb471ba1' - + 'f3dc2225a15ffddcc03eb48f44e27e2aa390598adf83f15c6608a5f18d4dfcf0' - + 'f547d467a4d70b281c83a595d7660d0b62de78b9cca023cca89d7b1f83484638' - + '0e228c25f049184a612ef5bb3d37454e6cfa5b10dceda619d898a699b3c8981a' - + '173407844bb89b4287bf57dd6600c79e352c681d74b03fa7ea0d7bf6ad69f8a6' - + '8ecb001963bd2dd8a2baa0083ec09751cd9742402ad716be16d5c052304cfca1', - '0F62B5085BAE0154A7FA4DA0F34699EC', - '128 bits key, Set 6, vector# 3', - dict (iv='288FF65DC42B92F9')), - - ( '00' * 1024, - '5e5e71f90199340304abb22a37b6625bf883fb89ce3b21f54a10b81066ef87da' - + '30b77699aa7379da595c77dd59542da208e5954f89e40eb7aa80a84a6176663f' - + 'd910cde567cf1ff60f7040548d8f376bfd1f44c4774aac37410ede7d5c3463fc' - + '4508a603201d8495ad257894e5eb1914b53e8da5e4bf2bc83ac87ce55cc67df7' - + '093d9853d2a83a9c8be969175df7c807a17156df768445dd0874a9271c6537f5' - + 'ce0466473582375f067fa4fcdaf65dbc0139cd75e8c21a482f28c0fb8c3d9f94' - + '22606cc8e88fe28fe73ec3cb10ff0e8cc5f2a49e540f007265c65b7130bfdb98' - + '795b1df9522da46e48b30e55d9f0d787955ece720205b29c85f3ad9be33b4459' - + '7d21b54d06c9a60b04b8e640c64e566e51566730e86cf128ab14174f91bd8981' - + 'a6fb00fe587bbd6c38b5a1dfdb04ea7e61536fd229f957aa9b070ca931358e85' - + '11b92c53c523cb54828fb1513c5636fa9a0645b4a3c922c0db94986d92f314ff' - + '7852c03b231e4dceea5dd8cced621869cff818daf3c270ff3c8be2e5c74be767' - + 'a4e1fdf3327a934fe31e46df5a74ae2021cee021d958c4f615263d99a5ddae7f' - + 'eab45e6eccbafefe4761c57750847b7e75ee2e2f14333c0779ce4678f47b1e1b' - + '760a03a5f17d6e91d4b42313b3f1077ee270e432fe04917ed1fc8babebf7c941' - + '42b80dfb44a28a2a3e59093027606f6860bfb8c2e5897078cfccda7314c70035' - + 'f137de6f05daa035891d5f6f76e1df0fce1112a2ff0ac2bd3534b5d1bf4c7165' - + 'fb40a1b6eacb7f295711c4907ae457514a7010f3a342b4427593d61ba993bc59' - + '8bd09c56b9ee53aac5dd861fa4b4bb53888952a4aa9d8ca8671582de716270e1' - + '97375b3ee49e51fa2bf4ef32015dd9a764d966aa2ae541592d0aa650849e99ca' - + '5c6c39beebf516457cc32fe4c105bff314a12f1ec94bdf4d626f5d9b1cbbde42' - + 'e5733f0885765ba29e2e82c829d312f5fc7e180679ac84826c08d0a644b326d0' - + '44da0fdcc75fa53cfe4ced0437fa4df5a7ecbca8b4cb7c4a9ecf9a60d00a56eb' - + '81da52adc21f508dbb60a9503a3cc94a896616d86020d5b0e5c637329b6d396a' - + '41a21ba2c4a9493cf33fa2d4f10f77d5b12fdad7e478ccfe79b74851fc96a7ca' - + '6320c5efd561a222c0ab0fb44bbda0e42149611d2262bb7d1719150fa798718a' - + '0eec63ee297cad459869c8b0f06c4e2b56cbac03cd2605b2a924efedf85ec8f1' - + '9b0b6c90e7cbd933223ffeb1b3a3f9677657905829294c4c70acdb8b0891b47d' - + '0875d0cd6c0f4efe2917fc44b581ef0d1e4280197065d07da34ab33283364552' - + 'efad0bd9257b059acdd0a6f246812feb69e7e76065f27dbc2eee94da9cc41835' - + 'bf826e36e5cebe5d4d6a37a6a666246290ce51a0c082718ab0ec855668db1add' - + 'a658e5f257e0db39384d02e6145c4c00eaa079098f6d820d872de711b6ed08cf', - '0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C', - '256 bits key, Set 6, vector# 3', - dict (iv='288FF65DC42B92F9')), - -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - - nonce = bchr(0) * 8 - for key_length in (15, 30, 33): - key = bchr(1) * key_length - self.assertRaises(ValueError, Salsa20.new, key, nonce) - - -class NonceTests(unittest.TestCase): - - def test_invalid_nonce_length(self): - key = bchr(1) * 16 - self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 7) - self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 9) - - def test_default_nonce(self): - - cipher1 = Salsa20.new(bchr(1) * 16) - cipher2 = Salsa20.new(bchr(1) * 16) - self.assertEqual(len(cipher1.nonce), 8) - self.assertNotEqual(cipher1.nonce, cipher2.nonce) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_ba = bytearray(data) - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - - cipher1 = Salsa20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = Salsa20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_ba) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - ct_ba = bytearray(ct) - - cipher3 = Salsa20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_ba) - - self.assertEqual(data, pt_test) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_mv = memoryview(bytearray(data)) - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - - cipher1 = Salsa20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = Salsa20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_mv) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - ct_mv = memoryview(bytearray(ct)) - - cipher3 = Salsa20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_mv) - - self.assertEqual(data, pt_test) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 8 - cipher = Salsa20.new(key=key, nonce=nonce) - - pt = b'5' * 300 - ct = cipher.encrypt(pt) - - output = bytearray(len(pt)) - cipher = Salsa20.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = Salsa20.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(len(pt))) - cipher = Salsa20.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = Salsa20.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*len(pt)) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(ct)) - - shorter_output = bytearray(len(pt) - 1) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - tests = make_stream_tests(Salsa20, "Salsa20", test_data) - tests.append(KeyLength()) - tests += list_test_cases(NonceTests) - tests.append(ByteArrayTest()) - tests.append(MemoryviewTest()) - tests.append(TestOutput()) - - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_15.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_15.py deleted file mode 100644 index e16a543..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_15.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_pkcs1_15.py: Self-test for PKCS#1 v1.5 encryption -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from __future__ import print_function - -import unittest - -from Crypto.PublicKey import RSA -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex -from Crypto import Random -from Crypto.Cipher import PKCS1_v1_5 as PKCS -from Crypto.Util.py3compat import b -from Crypto.Util.number import bytes_to_long, long_to_bytes -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - - -def rws(t): - """Remove white spaces, tabs, and new lines from a string""" - for c in ['\n', '\t', ' ']: - t = t.replace(c, '') - return t - - -def t2b(t): - """Convert a text string with bytes in hex form to a byte string""" - clean = b(rws(t)) - if len(clean) % 2 == 1: - raise ValueError("Even number of characters expected") - return a2b_hex(clean) - - -class PKCS1_15_Tests(unittest.TestCase): - - def setUp(self): - self.rng = Random.new().read - self.key1024 = RSA.generate(1024, self.rng) - - # List of tuples with test data for PKCS#1 v1.5. - # Each tuple is made up by: - # Item #0: dictionary with RSA key component, or key to import - # Item #1: plaintext - # Item #2: ciphertext - # Item #3: random data - - _testData = ( - - # - # Generated with openssl 0.9.8o - # - ( - # Private key - '''-----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDAiAnvIAOvqVwJTaYzsKnefZftgtXGE2hPJppGsWl78yz9jeXY -W/FxX/gTPURArNhdnhP6n3p2ZaDIBrO2zizbgIXs0IsljTTcr4vnI8fMXzyNUOjA -zP3nzMqZDZK6757XQAobOssMkBFqRWwilT/3DsBhRpl3iMUhF+wvpTSHewIDAQAB -AoGAC4HV/inOrpgTvSab8Wj0riyZgQOZ3U3ZpSlsfR8ra9Ib9Uee3jCYnKscu6Gk -y6zI/cdt8EPJ4PuwAWSNJzbpbVaDvUq25OD+CX8/uRT08yBS4J8TzBitZJTD4lS7 -atdTnKT0Wmwk+u8tDbhvMKwnUHdJLcuIsycts9rwJVapUtkCQQDvDpx2JMun0YKG -uUttjmL8oJ3U0m3ZvMdVwBecA0eebZb1l2J5PvI3EJD97eKe91Nsw8T3lwpoN40k -IocSVDklAkEAzi1HLHE6EzVPOe5+Y0kGvrIYRRhncOb72vCvBZvD6wLZpQgqo6c4 -d3XHFBBQWA6xcvQb5w+VVEJZzw64y25sHwJBAMYReRl6SzL0qA0wIYrYWrOt8JeQ -8mthulcWHXmqTgC6FEXP9Es5GD7/fuKl4wqLKZgIbH4nqvvGay7xXLCXD/ECQH9a -1JYNMtRen5unSAbIOxRcKkWz92F0LKpm9ZW/S9vFHO+mBcClMGoKJHiuQxLBsLbT -NtEZfSJZAeS2sUtn3/0CQDb2M2zNBTF8LlM0nxmh0k9VGm5TVIyBEMcipmvOgqIs -HKukWBcq9f/UOmS0oEhai/6g+Uf7VHJdWaeO5LzuvwU= ------END RSA PRIVATE KEY-----''', - # Plaintext - '''THIS IS PLAINTEXT\x0A''', - # Ciphertext - '''3f dc fd 3c cd 5c 9b 12 af 65 32 e3 f7 d0 da 36 - 8f 8f d9 e3 13 1c 7f c8 b3 f9 c1 08 e4 eb 79 9c - 91 89 1f 96 3b 94 77 61 99 a4 b1 ee 5d e6 17 c9 - 5d 0a b5 63 52 0a eb 00 45 38 2a fb b0 71 3d 11 - f7 a1 9e a7 69 b3 af 61 c0 bb 04 5b 5d 4b 27 44 - 1f 5b 97 89 ba 6a 08 95 ee 4f a2 eb 56 64 e5 0f - da 7c f9 9a 61 61 06 62 ed a0 bc 5f aa 6c 31 78 - 70 28 1a bb 98 3c e3 6a 60 3c d1 0b 0f 5a f4 75''', - # Random data - '''eb d7 7d 86 a4 35 23 a3 54 7e 02 0b 42 1d - 61 6c af 67 b8 4e 17 56 80 66 36 04 64 34 26 8a - 47 dd 44 b3 1a b2 17 60 f4 91 2e e2 b5 95 64 cc - f9 da c8 70 94 54 86 4c ef 5b 08 7d 18 c4 ab 8d - 04 06 33 8f ca 15 5f 52 60 8a a1 0c f5 08 b5 4c - bb 99 b8 94 25 04 9c e6 01 75 e6 f9 63 7a 65 61 - 13 8a a7 47 77 81 ae 0d b8 2c 4d 50 a5''' - ), - ) - - def testEncrypt1(self): - for test in self._testData: - # Build the key - key = RSA.importKey(test[0]) - # RNG that takes its random numbers from a pool given - # at initialization - class randGen: - def __init__(self, data): - self.data = data - self.idx = 0 - def __call__(self, N): - r = self.data[self.idx:self.idx+N] - self.idx += N - return r - # The real test - cipher = PKCS.new(key, randfunc=randGen(t2b(test[3]))) - ct = cipher.encrypt(b(test[1])) - self.assertEqual(ct, t2b(test[2])) - - def testEncrypt2(self): - # Verify that encryption fail if plaintext is too long - pt = '\x00'*(128-11+1) - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.encrypt, pt) - - def testVerify1(self): - for test in self._testData: - key = RSA.importKey(test[0]) - expected_pt = b(test[1]) - ct = t2b(test[2]) - cipher = PKCS.new(key) - - # The real test - pt = cipher.decrypt(ct, None) - self.assertEqual(pt, expected_pt) - - pt = cipher.decrypt(ct, b'\xFF' * len(expected_pt)) - self.assertEqual(pt, expected_pt) - - def testVerify2(self): - # Verify that decryption fails if ciphertext is not as long as - # RSA modulus - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.decrypt, '\x00'*127, "---") - self.assertRaises(ValueError, cipher.decrypt, '\x00'*129, "---") - - # Verify that decryption fails if there are less then 8 non-zero padding - # bytes - pt = b('\x00\x02' + '\xFF'*7 + '\x00' + '\x45'*118) - pt_int = bytes_to_long(pt) - ct_int = self.key1024._encrypt(pt_int) - ct = long_to_bytes(ct_int, 128) - self.assertEqual(b"---", cipher.decrypt(ct, b"---")) - - def testEncryptVerify1(self): - # Encrypt/Verify messages of length [0..RSAlen-11] - # and therefore padding [8..117] - for pt_len in range(0, 128 - 11 + 1): - pt = self.rng(pt_len) - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(pt) - pt2 = cipher.decrypt(ct, b'\xAA' * pt_len) - self.assertEqual(pt, pt2) - - def test_encrypt_verify_exp_pt_len(self): - - cipher = PKCS.new(self.key1024) - pt = b'5' * 16 - ct = cipher.encrypt(pt) - sentinel = b'\xAA' * 16 - - pt_A = cipher.decrypt(ct, sentinel, 16) - self.assertEqual(pt, pt_A) - - pt_B = cipher.decrypt(ct, sentinel, 15) - self.assertEqual(sentinel, pt_B) - - pt_C = cipher.decrypt(ct, sentinel, 17) - self.assertEqual(sentinel, pt_C) - - def testByteArray(self): - pt = b"XER" - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(bytearray(pt)) - pt2 = cipher.decrypt(bytearray(ct), '\xFF' * len(pt)) - self.assertEqual(pt, pt2) - - def testMemoryview(self): - pt = b"XER" - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(memoryview(bytearray(pt))) - pt2 = cipher.decrypt(memoryview(bytearray(ct)), b'\xFF' * len(pt)) - self.assertEqual(pt, pt2) - - def test_return_type(self): - pt = b"XYZ" - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(pt) - self.assertTrue(isinstance(ct, bytes)) - pt2 = cipher.decrypt(ct, b'\xAA' * 3) - self.assertTrue(isinstance(pt2, bytes)) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, skip_slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._skip_slow_tests = skip_slow_tests - self._id = "None" - - def load_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['privateKeyPem']) - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof PKCS#1v1.5 (%s)" % filename, - group_tag={'rsa_key': filter_rsa} - ) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("rsa_pkcs1_2048_test.json")) - if not self._skip_slow_tests: - self.tv.extend(self.load_tests("rsa_pkcs1_3072_test.json")) - self.tv.extend(self.load_tests("rsa_pkcs1_4096_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt PKCS#1v1.5 Test #%s" % tv.id - sentinel = b'\xAA' * max(3, len(tv.msg)) - cipher = PKCS.new(tv.rsa_key) - try: - pt = cipher.decrypt(tv.ct, sentinel=sentinel) - except ValueError: - assert not tv.valid - else: - if pt == sentinel: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_decrypt(tv) - - -def get_tests(config={}): - skip_slow_tests = not config.get('slow_tests') - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PKCS1_15_Tests) - tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py deleted file mode 100644 index 1711581..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py +++ /dev/null @@ -1,506 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_pkcs1_oaep.py: Self-test for PKCS#1 OAEP encryption -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -from Crypto.PublicKey import RSA -from Crypto.Cipher import PKCS1_OAEP as PKCS -from Crypto.Hash import MD2, MD5, SHA1, SHA256, RIPEMD160, SHA224, SHA384, SHA512 -from Crypto import Random -from Crypto.Signature.pss import MGF1 - -from Crypto.Util.py3compat import b, bchr - - -def rws(t): - """Remove white spaces, tabs, and new lines from a string""" - for c in ['\n', '\t', ' ']: - t = t.replace(c, '') - return t - - -def t2b(t): - """Convert a text string with bytes in hex form to a byte string""" - clean = rws(t) - if len(clean) % 2 == 1: - raise ValueError("Even number of characters expected") - return a2b_hex(clean) - - -class PKCS1_OAEP_Tests(unittest.TestCase): - - def setUp(self): - self.rng = Random.new().read - self.key1024 = RSA.generate(1024, self.rng) - - # List of tuples with test data for PKCS#1 OAEP - # Each tuple is made up by: - # Item #0: dictionary with RSA key component - # Item #1: plaintext - # Item #2: ciphertext - # Item #3: random data (=seed) - # Item #4: hash object - - _testData = ( - - # - # From in oaep-int.txt to be found in - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 - 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f - b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 - 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f - af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 - ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e - e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f - e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb''', - # Public key - 'e':'11', - # In the test vector, only p and q were given... - # d is computed offline as e^{-1} mod (p-1)(q-1) - 'd':'''a5dafc5341faf289c4b988db30c1cdf83f31251e0 - 668b42784813801579641b29410b3c7998d6bc465745e5c3 - 92669d6870da2c082a939e37fdcb82ec93edac97ff3ad595 - 0accfbc111c76f1a9529444e56aaf68c56c092cd38dc3bef - 5d20a939926ed4f74a13eddfbe1a1cecc4894af9428c2b7b - 8883fe4463a4bc85b1cb3c1''' - } - , - # Plaintext - '''d4 36 e9 95 69 fd 32 a7 c8 a0 5b bc 90 d3 2c 49''', - # Ciphertext - '''12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 - 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 - 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 - 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb - 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 - 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 - da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d - 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55''', - # Random - '''aa fd 12 f6 59 ca e6 34 89 b4 79 e5 07 6d de c2 - f0 6c b5 8f''', - # Hash - SHA1, - ), - - # - # From in oaep-vect.txt to be found in Example 1.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''a8 b3 b2 84 af 8e b5 0b 38 70 34 a8 60 f1 46 c4 - 91 9f 31 87 63 cd 6c 55 98 c8 ae 48 11 a1 e0 ab - c4 c7 e0 b0 82 d6 93 a5 e7 fc ed 67 5c f4 66 85 - 12 77 2c 0c bc 64 a7 42 c6 c6 30 f5 33 c8 cc 72 - f6 2a e8 33 c4 0b f2 58 42 e9 84 bb 78 bd bf 97 - c0 10 7d 55 bd b6 62 f5 c4 e0 fa b9 84 5c b5 14 - 8e f7 39 2d d3 aa ff 93 ae 1e 6b 66 7b b3 d4 24 - 76 16 d4 f5 ba 10 d4 cf d2 26 de 88 d3 9f 16 fb''', - 'e':'''01 00 01''', - 'd':'''53 33 9c fd b7 9f c8 46 6a 65 5c 73 16 ac a8 5c - 55 fd 8f 6d d8 98 fd af 11 95 17 ef 4f 52 e8 fd - 8e 25 8d f9 3f ee 18 0f a0 e4 ab 29 69 3c d8 3b - 15 2a 55 3d 4a c4 d1 81 2b 8b 9f a5 af 0e 7f 55 - fe 73 04 df 41 57 09 26 f3 31 1f 15 c4 d6 5a 73 - 2c 48 31 16 ee 3d 3d 2d 0a f3 54 9a d9 bf 7c bf - b7 8a d8 84 f8 4d 5b eb 04 72 4d c7 36 9b 31 de - f3 7d 0c f5 39 e9 cf cd d3 de 65 37 29 ea d5 d1 ''' - } - , - # Plaintext - '''66 28 19 4e 12 07 3d b0 3b a9 4c da 9e f9 53 23 - 97 d5 0d ba 79 b9 87 00 4a fe fe 34''', - # Ciphertext - '''35 4f e6 7b 4a 12 6d 5d 35 fe 36 c7 77 79 1a 3f - 7b a1 3d ef 48 4e 2d 39 08 af f7 22 fa d4 68 fb - 21 69 6d e9 5d 0b e9 11 c2 d3 17 4f 8a fc c2 01 - 03 5f 7b 6d 8e 69 40 2d e5 45 16 18 c2 1a 53 5f - a9 d7 bf c5 b8 dd 9f c2 43 f8 cf 92 7d b3 13 22 - d6 e8 81 ea a9 1a 99 61 70 e6 57 a0 5a 26 64 26 - d9 8c 88 00 3f 84 77 c1 22 70 94 a0 d9 fa 1e 8c - 40 24 30 9c e1 ec cc b5 21 00 35 d4 7a c7 2e 8a''', - # Random - '''18 b7 76 ea 21 06 9d 69 77 6a 33 e9 6b ad 48 e1 - dd a0 a5 ef''', - SHA1 - ), - - # - # From in oaep-vect.txt to be found in Example 2.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''01 94 7c 7f ce 90 42 5f 47 27 9e 70 85 1f 25 d5 - e6 23 16 fe 8a 1d f1 93 71 e3 e6 28 e2 60 54 3e - 49 01 ef 60 81 f6 8c 0b 81 41 19 0d 2a e8 da ba - 7d 12 50 ec 6d b6 36 e9 44 ec 37 22 87 7c 7c 1d - 0a 67 f1 4b 16 94 c5 f0 37 94 51 a4 3e 49 a3 2d - de 83 67 0b 73 da 91 a1 c9 9b c2 3b 43 6a 60 05 - 5c 61 0f 0b af 99 c1 a0 79 56 5b 95 a3 f1 52 66 - 32 d1 d4 da 60 f2 0e da 25 e6 53 c4 f0 02 76 6f - 45''', - 'e':'''01 00 01''', - 'd':'''08 23 f2 0f ad b5 da 89 08 8a 9d 00 89 3e 21 fa - 4a 1b 11 fb c9 3c 64 a3 be 0b aa ea 97 fb 3b 93 - c3 ff 71 37 04 c1 9c 96 3c 1d 10 7a ae 99 05 47 - 39 f7 9e 02 e1 86 de 86 f8 7a 6d de fe a6 d8 cc - d1 d3 c8 1a 47 bf a7 25 5b e2 06 01 a4 a4 b2 f0 - 8a 16 7b 5e 27 9d 71 5b 1b 45 5b dd 7e ab 24 59 - 41 d9 76 8b 9a ce fb 3c cd a5 95 2d a3 ce e7 25 - 25 b4 50 16 63 a8 ee 15 c9 e9 92 d9 24 62 fe 39''' - }, - # Plaintext - '''8f f0 0c aa 60 5c 70 28 30 63 4d 9a 6c 3d 42 c6 - 52 b5 8c f1 d9 2f ec 57 0b ee e7''', - # Ciphertext - '''01 81 af 89 22 b9 fc b4 d7 9d 92 eb e1 98 15 99 - 2f c0 c1 43 9d 8b cd 49 13 98 a0 f4 ad 3a 32 9a - 5b d9 38 55 60 db 53 26 83 c8 b7 da 04 e4 b1 2a - ed 6a ac df 47 1c 34 c9 cd a8 91 ad dc c2 df 34 - 56 65 3a a6 38 2e 9a e5 9b 54 45 52 57 eb 09 9d - 56 2b be 10 45 3f 2b 6d 13 c5 9c 02 e1 0f 1f 8a - bb 5d a0 d0 57 09 32 da cf 2d 09 01 db 72 9d 0f - ef cc 05 4e 70 96 8e a5 40 c8 1b 04 bc ae fe 72 - 0e''', - # Random - '''8c 40 7b 5e c2 89 9e 50 99 c5 3e 8c e7 93 bf 94 - e7 1b 17 82''', - SHA1 - ), - - # - # From in oaep-vect.txt to be found in Example 10.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''ae 45 ed 56 01 ce c6 b8 cc 05 f8 03 93 5c 67 4d - db e0 d7 5c 4c 09 fd 79 51 fc 6b 0c ae c3 13 a8 - df 39 97 0c 51 8b ff ba 5e d6 8f 3f 0d 7f 22 a4 - 02 9d 41 3f 1a e0 7e 4e be 9e 41 77 ce 23 e7 f5 - 40 4b 56 9e 4e e1 bd cf 3c 1f b0 3e f1 13 80 2d - 4f 85 5e b9 b5 13 4b 5a 7c 80 85 ad ca e6 fa 2f - a1 41 7e c3 76 3b e1 71 b0 c6 2b 76 0e de 23 c1 - 2a d9 2b 98 08 84 c6 41 f5 a8 fa c2 6b da d4 a0 - 33 81 a2 2f e1 b7 54 88 50 94 c8 25 06 d4 01 9a - 53 5a 28 6a fe b2 71 bb 9b a5 92 de 18 dc f6 00 - c2 ae ea e5 6e 02 f7 cf 79 fc 14 cf 3b dc 7c d8 - 4f eb bb f9 50 ca 90 30 4b 22 19 a7 aa 06 3a ef - a2 c3 c1 98 0e 56 0c d6 4a fe 77 95 85 b6 10 76 - 57 b9 57 85 7e fd e6 01 09 88 ab 7d e4 17 fc 88 - d8 f3 84 c4 e6 e7 2c 3f 94 3e 0c 31 c0 c4 a5 cc - 36 f8 79 d8 a3 ac 9d 7d 59 86 0e aa da 6b 83 bb''', - 'e':'''01 00 01''', - 'd':'''05 6b 04 21 6f e5 f3 54 ac 77 25 0a 4b 6b 0c 85 - 25 a8 5c 59 b0 bd 80 c5 64 50 a2 2d 5f 43 8e 59 - 6a 33 3a a8 75 e2 91 dd 43 f4 8c b8 8b 9d 5f c0 - d4 99 f9 fc d1 c3 97 f9 af c0 70 cd 9e 39 8c 8d - 19 e6 1d b7 c7 41 0a 6b 26 75 df bf 5d 34 5b 80 - 4d 20 1a dd 50 2d 5c e2 df cb 09 1c e9 99 7b be - be 57 30 6f 38 3e 4d 58 81 03 f0 36 f7 e8 5d 19 - 34 d1 52 a3 23 e4 a8 db 45 1d 6f 4a 5b 1b 0f 10 - 2c c1 50 e0 2f ee e2 b8 8d ea 4a d4 c1 ba cc b2 - 4d 84 07 2d 14 e1 d2 4a 67 71 f7 40 8e e3 05 64 - fb 86 d4 39 3a 34 bc f0 b7 88 50 1d 19 33 03 f1 - 3a 22 84 b0 01 f0 f6 49 ea f7 93 28 d4 ac 5c 43 - 0a b4 41 49 20 a9 46 0e d1 b7 bc 40 ec 65 3e 87 - 6d 09 ab c5 09 ae 45 b5 25 19 01 16 a0 c2 61 01 - 84 82 98 50 9c 1c 3b f3 a4 83 e7 27 40 54 e1 5e - 97 07 50 36 e9 89 f6 09 32 80 7b 52 57 75 1e 79''' - }, - # Plaintext - '''8b ba 6b f8 2a 6c 0f 86 d5 f1 75 6e 97 95 68 70 - b0 89 53 b0 6b 4e b2 05 bc 16 94 ee''', - # Ciphertext - '''53 ea 5d c0 8c d2 60 fb 3b 85 85 67 28 7f a9 15 - 52 c3 0b 2f eb fb a2 13 f0 ae 87 70 2d 06 8d 19 - ba b0 7f e5 74 52 3d fb 42 13 9d 68 c3 c5 af ee - e0 bf e4 cb 79 69 cb f3 82 b8 04 d6 e6 13 96 14 - 4e 2d 0e 60 74 1f 89 93 c3 01 4b 58 b9 b1 95 7a - 8b ab cd 23 af 85 4f 4c 35 6f b1 66 2a a7 2b fc - c7 e5 86 55 9d c4 28 0d 16 0c 12 67 85 a7 23 eb - ee be ff 71 f1 15 94 44 0a ae f8 7d 10 79 3a 87 - 74 a2 39 d4 a0 4c 87 fe 14 67 b9 da f8 52 08 ec - 6c 72 55 79 4a 96 cc 29 14 2f 9a 8b d4 18 e3 c1 - fd 67 34 4b 0c d0 82 9d f3 b2 be c6 02 53 19 62 - 93 c6 b3 4d 3f 75 d3 2f 21 3d d4 5c 62 73 d5 05 - ad f4 cc ed 10 57 cb 75 8f c2 6a ee fa 44 12 55 - ed 4e 64 c1 99 ee 07 5e 7f 16 64 61 82 fd b4 64 - 73 9b 68 ab 5d af f0 e6 3e 95 52 01 68 24 f0 54 - bf 4d 3c 8c 90 a9 7b b6 b6 55 32 84 eb 42 9f cc''', - # Random - '''47 e1 ab 71 19 fe e5 6c 95 ee 5e aa d8 6f 40 d0 - aa 63 bd 33''', - SHA1 - ), - ) - - def testEncrypt1(self): - # Verify encryption using all test vectors - for test in self._testData: - # Build the key - comps = [int(rws(test[0][x]), 16) for x in ('n', 'e')] - key = RSA.construct(comps) - - # RNG that takes its random numbers from a pool given - # at initialization - class randGen: - - def __init__(self, data): - self.data = data - self.idx = 0 - - def __call__(self, N): - r = self.data[self.idx:N] - self.idx += N - return r - - # The real test - cipher = PKCS.new(key, test[4], randfunc=randGen(t2b(test[3]))) - ct = cipher.encrypt(t2b(test[1])) - self.assertEqual(ct, t2b(test[2])) - - def testEncrypt2(self): - # Verify that encryption fails if plaintext is too long - pt = '\x00'*(128-2*20-2+1) - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.encrypt, pt) - - def testDecrypt1(self): - # Verify decryption using all test vectors - for test in self._testData: - # Build the key - comps = [int(rws(test[0][x]),16) for x in ('n', 'e', 'd')] - key = RSA.construct(comps) - # The real test - cipher = PKCS.new(key, test[4]) - pt = cipher.decrypt(t2b(test[2])) - self.assertEqual(pt, t2b(test[1])) - - def testDecrypt2(self): - # Simplest possible negative tests - for ct_size in (127, 128, 129): - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.decrypt, bchr(0x00)*ct_size) - - def testEncryptDecrypt1(self): - # Encrypt/Decrypt messages of length [0..128-2*20-2] - for pt_len in range(0, 128-2*20-2): - pt = self.rng(pt_len) - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(pt) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def testEncryptDecrypt2(self): - # Helper function to monitor what's requested from RNG - global asked - - def localRng(N): - global asked - asked += N - return self.rng(N) - - # Verify that OAEP is friendly to all hashes - for hashmod in (MD2, MD5, SHA1, SHA256, RIPEMD160): - # Verify that encrypt() asks for as many random bytes - # as the hash output size - asked = 0 - pt = self.rng(40) - cipher = PKCS.new(self.key1024, hashmod, randfunc=localRng) - ct = cipher.encrypt(pt) - self.assertEqual(cipher.decrypt(ct), pt) - self.assertEqual(asked, hashmod.digest_size) - - def testEncryptDecrypt3(self): - # Verify that OAEP supports labels - pt = self.rng(35) - xlabel = self.rng(22) - cipher = PKCS.new(self.key1024, label=xlabel) - ct = cipher.encrypt(pt) - self.assertEqual(cipher.decrypt(ct), pt) - - def testEncryptDecrypt4(self): - # Verify that encrypt() uses the custom MGF - global mgfcalls - # Helper function to monitor what's requested from MGF - - def newMGF(seed, maskLen): - global mgfcalls - mgfcalls += 1 - return b'\x00' * maskLen - - mgfcalls = 0 - pt = self.rng(32) - cipher = PKCS.new(self.key1024, mgfunc=newMGF) - ct = cipher.encrypt(pt) - self.assertEqual(mgfcalls, 2) - self.assertEqual(cipher.decrypt(ct), pt) - - def testByteArray(self): - pt = b("XER") - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(bytearray(pt)) - pt2 = cipher.decrypt(bytearray(ct)) - self.assertEqual(pt, pt2) - - def testMemoryview(self): - pt = b("XER") - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(memoryview(bytearray(pt))) - pt2 = cipher.decrypt(memoryview(bytearray(ct))) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, skip_slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._skip_slow_tests = skip_slow_tests - self._id = "None" - - def load_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['privateKeyPem']) - - def filter_sha(group): - if group['sha'] == "SHA-1": - return SHA1 - elif group['sha'] == "SHA-224": - return SHA224 - elif group['sha'] == "SHA-256": - return SHA256 - elif group['sha'] == "SHA-384": - return SHA384 - elif group['sha'] == "SHA-512": - return SHA512 - else: - raise ValueError("Unknown sha " + group['sha']) - - def filter_mgf(group): - if group['mgfSha'] == "SHA-1": - return lambda x, y: MGF1(x, y, SHA1) - elif group['mgfSha'] == "SHA-224": - return lambda x, y: MGF1(x, y, SHA224) - elif group['mgfSha'] == "SHA-256": - return lambda x, y: MGF1(x, y, SHA256) - elif group['mgfSha'] == "SHA-384": - return lambda x, y: MGF1(x, y, SHA384) - elif group['mgfSha'] == "SHA-512": - return lambda x, y: MGF1(x, y, SHA512) - else: - raise ValueError("Unknown mgf/sha " + group['mgfSha']) - - def filter_algo(group): - return "%s with MGF1/%s" % (group['sha'], group['mgfSha']) - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof PKCS#1 OAEP (%s)" % filename, - group_tag={'rsa_key': filter_rsa, - 'hash_mod': filter_sha, - 'mgf': filter_mgf, - 'algo': filter_algo} - ) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("rsa_oaep_2048_sha1_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha224_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha384_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha512_test.json")) - if not self._skip_slow_tests: - self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_misc_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) - - cipher = PKCS.new(tv.rsa_key, hashAlgo=tv.hash_mod, mgfunc=tv.mgf, label=tv.label) - try: - pt = cipher.decrypt(tv.ct) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_decrypt(tv) - - -def get_tests(config={}): - skip_slow_tests = not config.get('slow_tests') - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PKCS1_OAEP_Tests) - tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/__init__.py deleted file mode 100644 index 98fcab2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/__init__.py: Self-test for hash modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for hash modules""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config) - from Crypto.SelfTest.Hash import test_CMAC; tests += test_CMAC.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config) - from Crypto.SelfTest.Hash import test_RIPEMD160; tests += test_RIPEMD160.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA1; tests += test_SHA1.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA384; tests += test_SHA384.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA512; tests += test_SHA512.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_224; tests += test_SHA3_224.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_256; tests += test_SHA3_256.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_384; tests += test_SHA3_384.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_512; tests += test_SHA3_512.get_tests(config=config) - from Crypto.SelfTest.Hash import test_keccak; tests += test_keccak.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHAKE; tests += test_SHAKE.get_tests(config=config) - from Crypto.SelfTest.Hash import test_BLAKE2; tests += test_BLAKE2.get_tests(config=config) - from Crypto.SelfTest.Hash import test_Poly1305; tests += test_Poly1305.get_tests(config=config) - from Crypto.SelfTest.Hash import test_cSHAKE; tests += test_cSHAKE.get_tests(config=config) - from Crypto.SelfTest.Hash import test_KMAC; tests += test_KMAC.get_tests(config=config) - from Crypto.SelfTest.Hash import test_TupleHash; tests += test_TupleHash.get_tests(config=config) - from Crypto.SelfTest.Hash import test_KangarooTwelve; tests += test_KangarooTwelve.get_tests(config=config) - from Crypto.SelfTest.Hash import test_TurboSHAKE; tests += test_TurboSHAKE.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/common.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/common.py deleted file mode 100644 index 1578667..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/common.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/common.py: Common code for Crypto.SelfTest.Hash -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-testing for PyCrypto hash modules""" - -import re -import sys -import unittest -import binascii -import Crypto.Hash -from binascii import hexlify, unhexlify -from Crypto.Util.py3compat import b, tobytes -from Crypto.Util.strxor import strxor_c - -def t2b(hex_string): - shorter = re.sub(br'\s+', b'', tobytes(hex_string)) - return unhexlify(shorter) - - -class HashDigestSizeSelfTest(unittest.TestCase): - - def __init__(self, hashmod, description, expected, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.expected = expected - self.description = description - self.extra_params = extra_params - - def shortDescription(self): - return self.description - - def runTest(self): - if "truncate" not in self.extra_params: - self.assertTrue(hasattr(self.hashmod, "digest_size")) - self.assertEqual(self.hashmod.digest_size, self.expected) - h = self.hashmod.new(**self.extra_params) - self.assertTrue(hasattr(h, "digest_size")) - self.assertEqual(h.digest_size, self.expected) - - -class HashSelfTest(unittest.TestCase): - - def __init__(self, hashmod, description, expected, input, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.expected = expected.lower() - self.input = input - self.description = description - self.extra_params = extra_params - - def shortDescription(self): - return self.description - - def runTest(self): - h = self.hashmod.new(**self.extra_params) - h.update(self.input) - - out1 = binascii.b2a_hex(h.digest()) - out2 = h.hexdigest() - - h = self.hashmod.new(self.input, **self.extra_params) - - out3 = h.hexdigest() - out4 = binascii.b2a_hex(h.digest()) - - # PY3K: hexdigest() should return str(), and digest() bytes - self.assertEqual(self.expected, out1) # h = .new(); h.update(data); h.digest() - if sys.version_info[0] == 2: - self.assertEqual(self.expected, out2) # h = .new(); h.update(data); h.hexdigest() - self.assertEqual(self.expected, out3) # h = .new(data); h.hexdigest() - else: - self.assertEqual(self.expected.decode(), out2) # h = .new(); h.update(data); h.hexdigest() - self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest() - self.assertEqual(self.expected, out4) # h = .new(data); h.digest() - - # Verify that the .new() method produces a fresh hash object, except - # for MD5 and SHA1, which are hashlib objects. (But test any .new() - # method that does exist.) - if self.hashmod.__name__ not in ('Crypto.Hash.MD5', 'Crypto.Hash.SHA1') or hasattr(h, 'new'): - h2 = h.new() - h2.update(self.input) - out5 = binascii.b2a_hex(h2.digest()) - self.assertEqual(self.expected, out5) - - -class HashTestOID(unittest.TestCase): - def __init__(self, hashmod, oid, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.oid = oid - self.extra_params = extra_params - - def runTest(self): - h = self.hashmod.new(**self.extra_params) - self.assertEqual(h.oid, self.oid) - - -class ByteArrayTest(unittest.TestCase): - - def __init__(self, module, extra_params): - unittest.TestCase.__init__(self) - self.module = module - self.extra_params = extra_params - - def runTest(self): - data = b("\x00\x01\x02") - - # Data can be a bytearray (during initialization) - ba = bytearray(data) - - h1 = self.module.new(data, **self.extra_params) - h2 = self.module.new(ba, **self.extra_params) - ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - ba = bytearray(data) - - h1 = self.module.new(**self.extra_params) - h2 = self.module.new(**self.extra_params) - - h1.update(data) - h2.update(ba) - - ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTest(unittest.TestCase): - - def __init__(self, module, extra_params): - unittest.TestCase.__init__(self) - self.module = module - self.extra_params = extra_params - - def runTest(self): - - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in get_mv_ro, get_mv_rw: - - # Data can be a memoryview (during initialization) - mv = get_mv(data) - - h1 = self.module.new(data, **self.extra_params) - h2 = self.module.new(mv, **self.extra_params) - if not mv.readonly: - mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - mv = get_mv(data) - - h1 = self.module.new(**self.extra_params) - h2 = self.module.new(**self.extra_params) - h1.update(data) - h2.update(mv) - if not mv.readonly: - mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MACSelfTest(unittest.TestCase): - - def __init__(self, module, description, result, data, key, params): - unittest.TestCase.__init__(self) - self.module = module - self.result = t2b(result) - self.data = t2b(data) - self.key = t2b(key) - self.params = params - self.description = description - - def shortDescription(self): - return self.description - - def runTest(self): - - result_hex = hexlify(self.result) - - # Verify result - h = self.module.new(self.key, **self.params) - h.update(self.data) - self.assertEqual(self.result, h.digest()) - self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) - - # Verify that correct MAC does not raise any exception - h.verify(self.result) - h.hexverify(result_hex) - - # Verify that incorrect MAC does raise ValueError exception - wrong_mac = strxor_c(self.result, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - # Verify again, with data passed to new() - h = self.module.new(self.key, self.data, **self.params) - self.assertEqual(self.result, h.digest()) - self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) - - # Test .copy() - try: - h = self.module.new(self.key, self.data, **self.params) - h2 = h.copy() - h3 = h.copy() - - # Verify that changing the copy does not change the original - h2.update(b"bla") - self.assertEqual(h3.digest(), self.result) - - # Verify that both can reach the same state - h.update(b"bla") - self.assertEqual(h.digest(), h2.digest()) - except NotImplementedError: - pass - - # PY3K: Check that hexdigest() returns str and digest() returns bytes - self.assertTrue(isinstance(h.digest(), type(b""))) - self.assertTrue(isinstance(h.hexdigest(), type(""))) - - # PY3K: Check that .hexverify() accepts bytes or str - h.hexverify(h.hexdigest()) - h.hexverify(h.hexdigest().encode('ascii')) - - -def make_hash_tests(module, module_name, test_data, digest_size, oid=None, - extra_params={}): - tests = [] - for i in range(len(test_data)): - row = test_data[i] - (expected, input) = map(tobytes,row[0:2]) - if len(row) < 3: - description = repr(input) - else: - description = row[2] - name = "%s #%d: %s" % (module_name, i+1, description) - tests.append(HashSelfTest(module, name, expected, input, extra_params)) - - name = "%s #%d: digest_size" % (module_name, len(test_data) + 1) - tests.append(HashDigestSizeSelfTest(module, name, digest_size, extra_params)) - - if oid is not None: - tests.append(HashTestOID(module, oid, extra_params)) - - tests.append(ByteArrayTest(module, extra_params)) - - tests.append(MemoryViewTest(module, extra_params)) - - return tests - - -def make_mac_tests(module, module_name, test_data): - tests = [] - for i, row in enumerate(test_data): - if len(row) == 4: - (key, data, results, description, params) = list(row) + [ {} ] - else: - (key, data, results, description, params) = row - name = "%s #%d: %s" % (module_name, i+1, description) - tests.append(MACSelfTest(module, name, results, data, key, params)) - return tests - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_BLAKE2.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_BLAKE2.py deleted file mode 100644 index f953eab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_BLAKE2.py +++ /dev/null @@ -1,482 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import unittest -import warnings -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import tobytes -from Crypto.Util.strxor import strxor_c -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import BLAKE2b, BLAKE2s - - -class Blake2Test(unittest.TestCase): - - def test_new_positive(self): - - h = self.BLAKE2.new(digest_bits=self.max_bits) - for new_func in self.BLAKE2.new, h.new: - - for dbits in range(8, self.max_bits + 1, 8): - hobj = new_func(digest_bits=dbits) - self.assertEqual(hobj.digest_size, dbits // 8) - - for dbytes in range(1, self.max_bytes + 1): - hobj = new_func(digest_bytes=dbytes) - self.assertEqual(hobj.digest_size, dbytes) - - digest1 = new_func(data=b"\x90", digest_bytes=self.max_bytes).digest() - digest2 = new_func(digest_bytes=self.max_bytes).update(b"\x90").digest() - self.assertEqual(digest1, digest2) - - new_func(data=b"A", key=b"5", digest_bytes=self.max_bytes) - - hobj = h.new() - self.assertEqual(hobj.digest_size, self.max_bytes) - - def test_new_negative(self): - - h = self.BLAKE2.new(digest_bits=self.max_bits) - for new_func in self.BLAKE2.new, h.new: - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - digest_bits=self.max_bits) - self.assertRaises(ValueError, new_func, digest_bytes=0) - self.assertRaises(ValueError, new_func, - digest_bytes=self.max_bytes + 1) - self.assertRaises(ValueError, new_func, digest_bits=7) - self.assertRaises(ValueError, new_func, digest_bits=15) - self.assertRaises(ValueError, new_func, - digest_bits=self.max_bits + 1) - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - key=u"string") - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - data=u"string") - - def test_default_digest_size(self): - digest = self.BLAKE2.new(data=b'abc').digest() - self.assertEqual(len(digest), self.max_bytes) - - def test_update(self): - pieces = [b"\x0A" * 200, b"\x14" * 300] - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - h.update(pieces[0]).update(pieces[1]) - digest = h.digest() - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.digest(), digest) - - def test_update_negative(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.assertTrue(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg = b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = self.BLAKE2.new(digest_bits=256, data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = self.BLAKE2.new(digest_bits=256, data=msg).digest() - - # With the proper flag, it is allowed - h = self.BLAKE2.new(digest_bits=256, data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - def test_hex_digest(self): - mac = self.BLAKE2.new(digest_bits=self.max_bits) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.assertTrue(isinstance(hexdigest, type("digest"))) - - def test_verify(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") - mac = h.digest() - h.verify(mac) - wrong_mac = strxor_c(mac, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - - def test_hexverify(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") - mac = h.hexdigest() - h.hexverify(mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - def test_oid(self): - - prefix = "1.3.6.1.4.1.1722.12.2." + self.oid_variant + "." - - for digest_bits in self.digest_bits_oid: - h = self.BLAKE2.new(digest_bits=digest_bits) - self.assertEqual(h.oid, prefix + str(digest_bits // 8)) - - h = self.BLAKE2.new(digest_bits=digest_bits, key=b"secret") - self.assertRaises(AttributeError, lambda: h.oid) - - for digest_bits in (8, self.max_bits): - if digest_bits in self.digest_bits_oid: - continue - self.assertRaises(AttributeError, lambda: h.oid) - - def test_bytearray(self): - - key = b'0' * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = self.BLAKE2.new(data=data, key=key) - h2 = self.BLAKE2.new(data=data_ba, key=key_ba) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = self.BLAKE2.new() - h2 = self.BLAKE2.new() - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - key = b'0' * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = self.BLAKE2.new(data=data, key=key) - h2 = self.BLAKE2.new(data=data_mv, key=key_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - key_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = self.BLAKE2.new() - h2 = self.BLAKE2.new() - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class Blake2bTest(Blake2Test): - #: Module - BLAKE2 = BLAKE2b - #: Max output size (in bits) - max_bits = 512 - #: Max output size (in bytes) - max_bytes = 64 - #: Bit size of the digests for which an ASN OID exists - digest_bits_oid = (160, 256, 384, 512) - # http://tools.ietf.org/html/draft-saarinen-blake2-02 - oid_variant = "1" - - -class Blake2sTest(Blake2Test): - #: Module - BLAKE2 = BLAKE2s - #: Max output size (in bits) - max_bits = 256 - #: Max output size (in bytes) - max_bytes = 32 - #: Bit size of the digests for which an ASN OID exists - digest_bits_oid = (128, 160, 224, 256) - # http://tools.ietf.org/html/draft-saarinen-blake2-02 - oid_variant = "2" - - -class Blake2OfficialTestVector(unittest.TestCase): - - def _load_tests(self, test_vector_file): - expected = "in" - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - - if line.strip() == "" or line.startswith("#"): - continue - - res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - - if res.group(1): - bin_value = unhexlify(tobytes(res.group(1))) - else: - bin_value = b"" - if expected == "in": - input_data = bin_value - expected = "key" - elif expected == "key": - key = bin_value - expected = "hash" - else: - result = bin_value - expected = "in" - test_vectors.append((input_data, key, result)) - return test_vectors - - def setUp(self): - - dir_comps = ("Hash", self.name) - file_name = self.name.lower() + "-test.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors # type: ignore - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - for (input_data, key, result) in self.test_vectors: - mac = self.BLAKE2.new(key=key, digest_bytes=self.max_bytes) - mac.update(input_data) - self.assertEqual(mac.digest(), result) - - -class Blake2bOfficialTestVector(Blake2OfficialTestVector): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - #: Max digest size - max_bytes = 64 - - -class Blake2sOfficialTestVector(Blake2OfficialTestVector): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - #: Max digest size - max_bytes = 32 - - -class Blake2TestVector1(unittest.TestCase): - - def _load_tests(self, test_vector_file): - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - if line.strip() == "" or line.startswith("#"): - continue - res = re.match("digest: ([0-9A-Fa-f]*)", line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - - test_vectors.append(unhexlify(tobytes(res.group(1)))) - return test_vectors - - def setUp(self): - dir_comps = ("Hash", self.name) - file_name = "tv1.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - - for tv in self.test_vectors: - digest_bytes = len(tv) - next_data = b"" - for _ in range(100): - h = self.BLAKE2.new(digest_bytes=digest_bytes) - h.update(next_data) - next_data = h.digest() + next_data - self.assertEqual(h.digest(), tv) - - -class Blake2bTestVector1(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - - -class Blake2sTestVector1(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - - -class Blake2TestVector2(unittest.TestCase): - - def _load_tests(self, test_vector_file): - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - if line.strip() == "" or line.startswith("#"): - continue - res = re.match(r"digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - key_size = int(res.group(1)) - result = unhexlify(tobytes(res.group(2))) - test_vectors.append((key_size, result)) - return test_vectors - - def setUp(self): - dir_comps = ("Hash", self.name) - file_name = "tv2.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors # type: ignore - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - - for key_size, result in self.test_vectors: - next_data = b"" - for _ in range(100): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, - key=b"A" * key_size) - h.update(next_data) - next_data = h.digest() + next_data - self.assertEqual(h.digest(), result) - - -class Blake2bTestVector2(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - #: Max digest size in bytes - max_bytes = 64 - - -class Blake2sTestVector2(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - #: Max digest size in bytes - max_bytes = 32 - - -def get_tests(config={}): - tests = [] - - tests += list_test_cases(Blake2bTest) - tests.append(Blake2bOfficialTestVector()) - tests.append(Blake2bTestVector1()) - tests.append(Blake2bTestVector2()) - - tests += list_test_cases(Blake2sTest) - tests.append(Blake2sOfficialTestVector()) - tests.append(Blake2sTestVector1()) - tests.append(Blake2sTestVector2()) - - return tests - - -if __name__ == '__main__': - import unittest - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_CMAC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_CMAC.py deleted file mode 100644 index f4763f2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_CMAC.py +++ /dev/null @@ -1,448 +0,0 @@ -# -# SelfTest/Hash/CMAC.py: Self-test for the CMAC module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.CMAC""" - -import json -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import tobytes - -from Crypto.Hash import CMAC -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -# This is a list of (key, data, result, description, module) tuples. -test_data = [ - - ## Test vectors from RFC 4493 ## - ## The are also in NIST SP 800 38B D.2 ## - ( '2b7e151628aed2a6abf7158809cf4f3c', - '', - 'bb1d6929e95937287fa37d129b756746', - 'RFC 4493 #1', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a', - '070a16b46b4d4144f79bdd9dd04a287c', - 'RFC 4493 #2', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - 'dfa66747de9ae63030ca32611497c827', - 'RFC 4493 #3', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - '51f0bebf7e3b9d92fc49741779363cfe', - 'RFC 4493 #4', - AES - ), - - ## The rest of Appendix D of NIST SP 800 38B - ## was not totally correct. - ## Values in Examples 14, 15, 18, and 19 were wrong. - ## The updated test values are published in: - ## http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '', - 'd17ddf46adaacde531cac483de7a9367', - 'NIST SP 800 38B D.2 Example 5', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a', - '9e99a7bf31e710900662f65e617c5184', - 'NIST SP 800 38B D.2 Example 6', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - '8a1de5be2eb31aad089a82e6ee908b0e', - 'NIST SP 800 38B D.2 Example 7', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - 'a1d5df0eed790f794d77589659f39a11', - 'NIST SP 800 38B D.2 Example 8', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '', - '028962f61b7bf89efc6b551f4667d983', - 'NIST SP 800 38B D.3 Example 9', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a', - '28a7023f452e8f82bd4bf28d8c37c35c', - 'NIST SP 800 38B D.3 Example 10', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - 'aaf3d8f1de5640c232f5b169b9c911e6', - 'NIST SP 800 38B D.3 Example 11', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - 'e1992190549f6ed5696a2c056c315410', - 'NIST SP 800 38B D.3 Example 12', - AES - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '', - 'b7a688e122ffaf95', - 'NIST SP 800 38B D.4 Example 13', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96', - '8e8f293136283797', - 'NIST SP 800 38B D.4 Example 14', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a57', - '743ddbe0ce2dc2ed', - 'NIST SP 800 38B D.4 Example 15', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a571e03ac9c'+ - '9eb76fac45af8e51', - '33e6b1092400eae5', - 'NIST SP 800 38B D.4 Example 16', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '', - 'bd2ebf9a3ba00361', - 'NIST SP 800 38B D.7 Example 17', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96', - '4ff2ab813c53ce83', - 'NIST SP 800 38B D.7 Example 18', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a57', - '62dd1b471902bd4e', - 'NIST SP 800 38B D.7 Example 19', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a571e03ac9c'+ - '9eb76fac45af8e51', - '31b1e431dabc4eb8', - 'NIST SP 800 38B D.7 Example 20', - DES3 - ), - -] - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class TestCMAC(unittest.TestCase): - - def test_internal_caching(self): - """Verify that internal caching is implemented correctly""" - - data_to_mac = get_tag_random("data_to_mac", 128) - key = get_tag_random("key", 16) - ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() - - # Break up in chunks of different length - # The result must always be the same - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - chunks = [data_to_mac[i:i+chunk_length] for i in - range(0, len(data_to_mac), chunk_length)] - - mac = CMAC.new(key, ciphermod=AES) - for chunk in chunks: - mac.update(chunk) - self.assertEqual(ref_mac, mac.digest()) - - def test_update_after_digest(self): - msg = b"rrrrttt" - key = b"4" * 16 - - # Normally, update() cannot be done after digest() - h = CMAC.new(key, msg[:4], ciphermod=AES) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = CMAC.new(key, msg, ciphermod=AES).digest() - - # With the proper flag, it is allowed - h2 = CMAC.new(key, msg[:4], ciphermod=AES, update_after_digest=True) - self.assertEqual(h2.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h2.update(msg[4:]) - self.assertEqual(h2.digest(), dig2) - - -class ByteArrayTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = CMAC.new(key, data, ciphermod=AES) - h2 = CMAC.new(key_ba, data_ba, ciphermod=AES) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = CMAC.new(key, ciphermod=AES) - h2 = CMAC.new(key, ciphermod=AES) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = CMAC.new(key, data, ciphermod=AES) - h2 = CMAC.new(key_mv, data_mv, ciphermod=AES) - if not data_mv.readonly: - key_mv[:1] = b'\xFF' - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = CMAC.new(key, ciphermod=AES) - h2 = CMAC.new(key, ciphermod=AES) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Hash", "wycheproof"), - "aes_cmac_test.json", - "Wycheproof CMAC", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_create_mac(self, tv): - self._id = "Wycheproof MAC creation Test #" + str(tv.id) - - try: - tag = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size).digest() - except ValueError as e: - if len(tv.key) not in (16, 24, 32) and "key length" in str(e): - return - raise e - if tv.valid: - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_verify_mac(self, tv): - self._id = "Wycheproof MAC verification Test #" + str(tv.id) - - try: - mac = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size) - except ValueError as e: - if len(tv.key) not in (16, 24, 32) and "key length" in str(e): - return - raise e - try: - mac.verify(tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_create_mac(tv) - self.test_verify_mac(tv) - - -def get_tests(config={}): - global test_data - import types - from .common import make_mac_tests - - wycheproof_warnings = config.get('wycheproof_warnings') - - # Add new() parameters to the back of each test vector - params_test_data = [] - for row in test_data: - t = list(row) - t[4] = dict(ciphermod=t[4]) - params_test_data.append(t) - - tests = make_mac_tests(CMAC, "CMAC", params_test_data) - tests.append(ByteArrayTests()) - tests.append(list_test_cases(TestCMAC)) - tests.append(MemoryViewTests()) - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_HMAC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_HMAC.py deleted file mode 100644 index 26b7b24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_HMAC.py +++ /dev/null @@ -1,548 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/HMAC.py: Self-test for the HMAC module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.HMAC""" - -import unittest -from binascii import hexlify -from Crypto.Util.py3compat import tostr, tobytes - -from Crypto.Hash import (HMAC, MD5, SHA1, SHA256, - SHA224, SHA384, SHA512, - RIPEMD160, - SHA3_224, SHA3_256, SHA3_384, SHA3_512) - - -hash_modules = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256, - SHA224=SHA224, SHA384=SHA384, SHA512=SHA512, - RIPEMD160=RIPEMD160, - SHA3_224=SHA3_224, SHA3_256=SHA3_256, - SHA3_384=SHA3_384, SHA3_512=SHA3_512) - -default_hash = None - -def xl(text): - return tostr(hexlify(tobytes(text))) - -# This is a list of (key, data, results, description) tuples. -test_data = [ - ## Test vectors from RFC 2202 ## - # Test that the default hashmod is MD5 - ('0b' * 16, - '4869205468657265', - dict(default_hash='9294727a3638bb1c13f48ef8158bfc9d'), - 'default-is-MD5'), - - # Test case 1 (MD5) - ('0b' * 16, - '4869205468657265', - dict(MD5='9294727a3638bb1c13f48ef8158bfc9d'), - 'RFC 2202 #1-MD5 (HMAC-MD5)'), - - # Test case 1 (SHA1) - ('0b' * 20, - '4869205468657265', - dict(SHA1='b617318655057264e28bc0b6fb378c8ef146be00'), - 'RFC 2202 #1-SHA1 (HMAC-SHA1)'), - - # Test case 2 - ('4a656665', - '7768617420646f2079612077616e7420666f72206e6f7468696e673f', - dict(MD5='750c783e6ab0b503eaa86e310a5db738', - SHA1='effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'), - 'RFC 2202 #2 (HMAC-MD5/SHA1)'), - - # Test case 3 (MD5) - ('aa' * 16, - 'dd' * 50, - dict(MD5='56be34521d144c88dbb8c733f0e8b3f6'), - 'RFC 2202 #3-MD5 (HMAC-MD5)'), - - # Test case 3 (SHA1) - ('aa' * 20, - 'dd' * 50, - dict(SHA1='125d7342b9ac11cd91a39af48aa17b4f63f175d3'), - 'RFC 2202 #3-SHA1 (HMAC-SHA1)'), - - # Test case 4 - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(MD5='697eaf0aca3a3aea3a75164746ffaa79', - SHA1='4c9007f4026250c6bc8414f9bf50c86c2d7235da'), - 'RFC 2202 #4 (HMAC-MD5/SHA1)'), - - # Test case 5 (MD5) - ('0c' * 16, - '546573742057697468205472756e636174696f6e', - dict(MD5='56461ef2342edc00f9bab995690efd4c'), - 'RFC 2202 #5-MD5 (HMAC-MD5)'), - - # Test case 5 (SHA1) - # NB: We do not implement hash truncation, so we only test the full hash here. - ('0c' * 20, - '546573742057697468205472756e636174696f6e', - dict(SHA1='4c1a03424b55e07fe7f27be1d58bb9324a9a5a04'), - 'RFC 2202 #5-SHA1 (HMAC-SHA1)'), - - # Test case 6 - ('aa' * 80, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b6579202d2048617368204b6579204669727374', - dict(MD5='6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd', - SHA1='aa4ae5e15272d00e95705637ce8a3b55ed402112'), - 'RFC 2202 #6 (HMAC-MD5/SHA1)'), - - # Test case 7 - ('aa' * 80, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b657920616e64204c6172676572205468616e204f6e6520426c6f636b2d' - + '53697a652044617461', - dict(MD5='6f630fad67cda0ee1fb1f562db3aa53e', - SHA1='e8e99d0f45237d786d6bbaa7965c7808bbff1a91'), - 'RFC 2202 #7 (HMAC-MD5/SHA1)'), - - ## Test vectors from RFC 4231 ## - # 4.2. Test Case 1 - ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - '4869205468657265', - dict(SHA256=''' - b0344c61d8db38535ca8afceaf0bf12b - 881dc200c9833da726e9376c2e32cff7 - '''), - 'RFC 4231 #1 (HMAC-SHA256)'), - - # 4.3. Test Case 2 - Test with a key shorter than the length of the HMAC - # output. - ('4a656665', - '7768617420646f2079612077616e7420666f72206e6f7468696e673f', - dict(SHA256=''' - 5bdcc146bf60754e6a042426089575c7 - 5a003f089d2739839dec58b964ec3843 - '''), - 'RFC 4231 #2 (HMAC-SHA256)'), - - # 4.4. Test Case 3 - Test with a combined length of key and data that is - # larger than 64 bytes (= block-size of SHA-224 and SHA-256). - ('aa' * 20, - 'dd' * 50, - dict(SHA256=''' - 773ea91e36800e46854db8ebd09181a7 - 2959098b3ef8c122d9635514ced565fe - '''), - 'RFC 4231 #3 (HMAC-SHA256)'), - - # 4.5. Test Case 4 - Test with a combined length of key and data that is - # larger than 64 bytes (= block-size of SHA-224 and SHA-256). - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(SHA256=''' - 82558a389a443c0ea4cc819899f2083a - 85f0faa3e578f8077a2e3ff46729665b - '''), - 'RFC 4231 #4 (HMAC-SHA256)'), - - # 4.6. Test Case 5 - Test with a truncation of output to 128 bits. - # - # Not included because we do not implement hash truncation. - # - - # 4.7. Test Case 6 - Test with a key larger than 128 bytes (= block-size of - # SHA-384 and SHA-512). - ('aa' * 131, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b6579202d2048617368204b6579204669727374', - dict(SHA256=''' - 60e431591ee0b67f0d8a26aacbf5b77f - 8e0bc6213728c5140546040f0ee37f54 - '''), - 'RFC 4231 #6 (HMAC-SHA256)'), - - # 4.8. Test Case 7 - Test with a key and data that is larger than 128 bytes - # (= block-size of SHA-384 and SHA-512). - ('aa' * 131, - '5468697320697320612074657374207573696e672061206c6172676572207468' - + '616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074' - + '68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565' - + '647320746f20626520686173686564206265666f7265206265696e6720757365' - + '642062792074686520484d414320616c676f726974686d2e', - dict(SHA256=''' - 9b09ffa71b942fcb27635fbcd5b0e944 - bfdc63644f0713938a7f51535c3a35e2 - '''), - 'RFC 4231 #7 (HMAC-SHA256)'), - - # Test case 8 (SHA224) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA224='a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44'), - 'RFC 4634 8.4 SHA224 (HMAC-SHA224)'), - - # Test case 9 (SHA384) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA384='af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649'), - 'RFC 4634 8.4 SHA384 (HMAC-SHA384)'), - - # Test case 10 (SHA512) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA512='164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'), - 'RFC 4634 8.4 SHA512 (HMAC-SHA512)'), - - # Test case 11 (RIPEMD) - ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - xl("Hi There"), - dict(RIPEMD160='24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668'), - 'RFC 2286 #1 (HMAC-RIPEMD)'), - - # Test case 12 (RIPEMD) - (xl("Jefe"), - xl("what do ya want for nothing?"), - dict(RIPEMD160='dda6c0213a485a9e24f4742064a7f033b43c4069'), - 'RFC 2286 #2 (HMAC-RIPEMD)'), - - # Test case 13 (RIPEMD) - ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'dd' * 50, - dict(RIPEMD160='b0b105360de759960ab4f35298e116e295d8e7c1'), - 'RFC 2286 #3 (HMAC-RIPEMD)'), - - # Test case 14 (RIPEMD) - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(RIPEMD160='d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4'), - 'RFC 2286 #4 (HMAC-RIPEMD)'), - - # Test case 15 (RIPEMD) - ('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', - xl("Test With Truncation"), - dict(RIPEMD160='7619693978f91d90539ae786500ff3d8e0518e39'), - 'RFC 2286 #5 (HMAC-RIPEMD)'), - - # Test case 16 (RIPEMD) - ('aa' * 80, - xl("Test Using Larger Than Block-Size Key - Hash Key First"), - dict(RIPEMD160='6466ca07ac5eac29e1bd523e5ada7605b791fd8b'), - 'RFC 2286 #6 (HMAC-RIPEMD)'), - - # Test case 17 (RIPEMD) - ('aa' * 80, - xl("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), - dict(RIPEMD160='69ea60798d71616cce5fd0871e23754cd75d5a0a'), - 'RFC 2286 #7 (HMAC-RIPEMD)'), - - # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-224.pdf - ( - '000102030405060708090a0b0c0d0e0f' - '101112131415161718191a1b', - xl('Sample message for keylenblocklen'), - dict(SHA3_224='078695eecc227c636ad31d063a15dd05a7e819a66ec6d8de1e193e59'), - 'NIST CSRC Sample #3 (SHA3-224)' - ), - - # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-256.pdf - ( - '000102030405060708090a0b0c0d0e0f'\ - '101112131415161718191a1b1c1d1e1f', - xl('Sample message for keylenblocklen'), - dict(SHA3_256='9bcf2c238e235c3ce88404e813bd2f3a97185ac6f238c63d6229a00b07974258'), - 'NIST CSRC Sample #3 (SHA3-256)' - ), - - # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-384.pdf - ( - '000102030405060708090a0b0c0d0e0f'\ - '101112131415161718191a1b1c1d1e1f' - '202122232425262728292a2b2c2d2e2f', - xl('Sample message for keylenblocklen'), - dict(SHA3_384='e5ae4c739f455279368ebf36d4f5354c95aa184c899d3870e460ebc288ef1f9470053f73f7c6da2a71bcaec38ce7d6ac'), - 'NIST CSRC Sample #3 (SHA3-384)' - ), - - # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-512.pdf - ( - '000102030405060708090a0b0c0d0e0f'\ - '101112131415161718191a1b1c1d1e1f'\ - '202122232425262728292a2b2c2d2e2f'\ - '303132333435363738393a3b3c3d3e3f', - xl('Sample message for keylenblocklen'), - dict(SHA3_512='5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915'), - 'NIST CSRC Sample #3 (SHA3-512)' - ), - -] - - -class HMAC_Module_and_Instance_Test(unittest.TestCase): - """Test the HMAC construction and verify that it does not - matter if you initialize it with a hash module or - with an hash instance. - - See https://bugs.launchpad.net/pycrypto/+bug/1209399 - """ - - def __init__(self, hashmods): - """Initialize the test with a dictionary of hash modules - indexed by their names""" - - unittest.TestCase.__init__(self) - self.hashmods = hashmods - self.description = "" - - def shortDescription(self): - return self.description - - def runTest(self): - key = b"\x90\x91\x92\x93" * 4 - payload = b"\x00" * 100 - - for hashname, hashmod in self.hashmods.items(): - if hashmod is None: - continue - self.description = "Test HMAC in combination with " + hashname - one = HMAC.new(key, payload, hashmod).digest() - two = HMAC.new(key, payload, hashmod.new()).digest() - self.assertEqual(one, two) - - -class HMAC_None(unittest.TestCase): - - def runTest(self): - - key = b"\x04" * 20 - one = HMAC.new(key, b"", SHA1).digest() - two = HMAC.new(key, None, SHA1).digest() - self.assertEqual(one, two) - - -class ByteArrayTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = HMAC.new(key, data) - h2 = HMAC.new(key_ba, data_ba) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = HMAC.new(key) - h2 = HMAC.new(key) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = HMAC.new(key, data) - h2 = HMAC.new(key_mv, data_mv) - if not data_mv.readonly: - key_mv[:1] = b'\xFF' - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = HMAC.new(key) - h2 = HMAC.new(key) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -def get_tests(config={}): - global test_data - import types - from .common import make_mac_tests - - # A test vector contains multiple results, each one for a - # different hash algorithm. - # Here we expand each test vector into multiple ones, - # and add the relevant parameters that will be passed to new() - exp_test_data = [] - for row in test_data: - for modname in row[2].keys(): - t = list(row) - t[2] = row[2][modname] - t.append(dict(digestmod=globals()[modname])) - exp_test_data.append(t) - tests = make_mac_tests(HMAC, "HMAC", exp_test_data) - tests.append(HMAC_Module_and_Instance_Test(hash_modules)) - tests.append(HMAC_None()) - - tests.append(ByteArrayTests()) - tests.append(MemoryViewTests()) - - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KMAC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KMAC.py deleted file mode 100644 index 8e9bf70..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KMAC.py +++ /dev/null @@ -1,346 +0,0 @@ -import unittest -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import tobytes -from Crypto.Util.strxor import strxor_c -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import KMAC128, KMAC256 - - -class KMACTest(unittest.TestCase): - - def new(self, *args, **kwargs): - return self.KMAC.new(key=b'X' * (self.minimum_key_bits // 8), *args, **kwargs) - - def test_new_positive(self): - - key = b'X' * 32 - - h = self.new() - for new_func in self.KMAC.new, h.new: - - for dbytes in range(self.minimum_bytes, 128 + 1): - hobj = new_func(key=key, mac_len=dbytes) - self.assertEqual(hobj.digest_size, dbytes) - - digest1 = new_func(key=key, data=b"\x90").digest() - digest2 = new_func(key=key).update(b"\x90").digest() - self.assertEqual(digest1, digest2) - - new_func(data=b"A", key=key, custom=b"g") - - hobj = h.new(key=key) - self.assertEqual(hobj.digest_size, self.default_bytes) - - def test_new_negative(self): - - h = self.new() - for new_func in self.KMAC.new, h.new: - self.assertRaises(ValueError, new_func, key=b'X'*32, - mac_len=0) - self.assertRaises(ValueError, new_func, key=b'X'*32, - mac_len=self.minimum_bytes - 1) - self.assertRaises(TypeError, new_func, - key=u"string") - self.assertRaises(TypeError, new_func, - data=u"string") - - def test_default_digest_size(self): - digest = self.new(data=b'abc').digest() - self.assertEqual(len(digest), self.default_bytes) - - def test_update(self): - pieces = [b"\x0A" * 200, b"\x14" * 300] - h = self.new() - h.update(pieces[0]).update(pieces[1]) - digest = h.digest() - h = self.new() - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.digest(), digest) - - def test_update_negative(self): - h = self.new() - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.new() - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.assertTrue(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg = b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = self.new(mac_len=32, data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, dig1) - - def test_hex_digest(self): - mac = self.new() - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.assertTrue(isinstance(hexdigest, type("digest"))) - - def test_verify(self): - h = self.new() - mac = h.digest() - h.verify(mac) - wrong_mac = strxor_c(mac, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - - def test_hexverify(self): - h = self.new() - mac = h.hexdigest() - h.hexverify(mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - def test_oid(self): - - oid = "2.16.840.1.101.3.4.2." + self.oid_variant - h = self.new() - self.assertEqual(h.oid, oid) - - def test_bytearray(self): - - key = b'0' * 32 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = self.KMAC.new(data=data, key=key) - h2 = self.KMAC.new(data=data_ba, key=key_ba) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = self.new() - h2 = self.new() - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - key = b'0' * 32 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = self.KMAC.new(data=data, key=key) - h2 = self.KMAC.new(data=data_mv, key=key_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - key_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = self.new() - h2 = self.new() - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class KMAC128Test(KMACTest): - - KMAC = KMAC128 - - minimum_key_bits = 128 - - minimum_bytes = 8 - default_bytes = 64 - - oid_variant = "19" - - -class KMAC256Test(KMACTest): - - KMAC = KMAC256 - - minimum_key_bits = 256 - - minimum_bytes = 8 - default_bytes = 64 - - oid_variant = "20" - - -class NISTExampleTestVectors(unittest.TestCase): - - # https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf - test_data = [ - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03", - "", - "E5 78 0B 0D 3E A6 F7 D3 A4 29 C5 70 6A A4 3A 00" - "FA DB D7 D4 96 28 83 9E 31 87 24 3F 45 6E E1 4E", - "Sample #1 NIST", - KMAC128 - ), - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03", - "My Tagged Application", - "3B 1F BA 96 3C D8 B0 B5 9E 8C 1A 6D 71 88 8B 71" - "43 65 1A F8 BA 0A 70 70 C0 97 9E 28 11 32 4A A5", - "Sample #2 NIST", - KMAC128 - ), - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" - "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" - "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" - "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" - "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" - "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" - "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" - "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" - "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" - "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" - "C0 C1 C2 C3 C4 C5 C6 C7", - "My Tagged Application", - "1F 5B 4E 6C CA 02 20 9E 0D CB 5C A6 35 B8 9A 15" - "E2 71 EC C7 60 07 1D FD 80 5F AA 38 F9 72 92 30", - "Sample #3 NIST", - KMAC128 - ), - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03", - "My Tagged Application", - "20 C5 70 C3 13 46 F7 03 C9 AC 36 C6 1C 03 CB 64" - "C3 97 0D 0C FC 78 7E 9B 79 59 9D 27 3A 68 D2 F7" - "F6 9D 4C C3 DE 9D 10 4A 35 16 89 F2 7C F6 F5 95" - "1F 01 03 F3 3F 4F 24 87 10 24 D9 C2 77 73 A8 DD", - "Sample #4 NIST", - KMAC256 - ), - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" - "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" - "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" - "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" - "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" - "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" - "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" - "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" - "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" - "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" - "C0 C1 C2 C3 C4 C5 C6 C7", - "", - "75 35 8C F3 9E 41 49 4E 94 97 07 92 7C EE 0A F2" - "0A 3F F5 53 90 4C 86 B0 8F 21 CC 41 4B CF D6 91" - "58 9D 27 CF 5E 15 36 9C BB FF 8B 9A 4C 2E B1 78" - "00 85 5D 02 35 FF 63 5D A8 25 33 EC 6B 75 9B 69", - "Sample #5 NIST", - KMAC256 - ), - ( - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", - "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" - "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" - "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" - "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" - "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" - "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" - "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" - "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" - "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" - "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" - "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" - "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" - "C0 C1 C2 C3 C4 C5 C6 C7", - "My Tagged Application", - "B5 86 18 F7 1F 92 E1 D5 6C 1B 8C 55 DD D7 CD 18" - "8B 97 B4 CA 4D 99 83 1E B2 69 9A 83 7D A2 E4 D9" - "70 FB AC FD E5 00 33 AE A5 85 F1 A2 70 85 10 C3" - "2D 07 88 08 01 BD 18 28 98 FE 47 68 76 FC 89 65", - "Sample #6 NIST", - KMAC256 - ), - ] - - def setUp(self): - td = [] - for key, data, custom, mac, text, module in self.test_data: - ni = ( - unhexlify(key.replace(" ", "")), - unhexlify(data.replace(" ", "")), - custom.encode(), - unhexlify(mac.replace(" ", "")), - text, - module - ) - td.append(ni) - self.test_data = td - - def runTest(self): - - for key, data, custom, mac, text, module in self.test_data: - h = module.new(data=data, key=key, custom=custom, mac_len=len(mac)) - mac_tag = h.digest() - self.assertEqual(mac_tag, mac, msg=text) - - -def get_tests(config={}): - tests = [] - - tests += list_test_cases(KMAC128Test) - tests += list_test_cases(KMAC256Test) - tests.append(NISTExampleTestVectors()) - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KangarooTwelve.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KangarooTwelve.py deleted file mode 100644 index fe161f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_KangarooTwelve.py +++ /dev/null @@ -1,367 +0,0 @@ -# =================================================================== -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.KangarooTwelve""" - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import KangarooTwelve as K12 -from Crypto.Util.py3compat import b, bchr - - -class KangarooTwelveTest(unittest.TestCase): - - def test_length_encode(self): - self.assertEqual(K12._length_encode(0), b'\x00') - self.assertEqual(K12._length_encode(12), b'\x0C\x01') - self.assertEqual(K12._length_encode(65538), b'\x01\x00\x02\x03') - - def test_new_positive(self): - - xof1 = K12.new() - xof2 = K12.new(data=b("90")) - xof3 = K12.new().update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - xof1 = K12.new() - ref = xof1.read(10) - xof2 = K12.new(custom=b("")) - xof3 = K12.new(custom=b("foo")) - - self.assertEqual(ref, xof2.read(10)) - self.assertNotEqual(ref, xof3.read(10)) - - xof1 = K12.new(custom=b("foo")) - xof2 = K12.new(custom=b("foo"), data=b("90")) - xof3 = K12.new(custom=b("foo")).update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = K12.new() - h.update(pieces[0]).update(pieces[1]) - digest = h.read(10) - h = K12.new() - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.read(10), digest) - - def test_update_negative(self): - h = K12.new() - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = K12.new() - digest = h.read(90) - - # read returns a byte string of the right length - self.assertTrue(isinstance(digest, type(b("digest")))) - self.assertEqual(len(digest), 90) - - def test_update_after_read(self): - mac = K12.new() - mac.update(b("rrrr")) - mac.read(90) - self.assertRaises(TypeError, mac.update, b("ttt")) - - -def txt2bin(txt): - clean = txt.replace(" ", "").replace("\n", "").replace("\r", "") - return unhexlify(clean) - - -def ptn(n): - res = bytearray(n) - pattern = b"".join([bchr(x) for x in range(0, 0xFB)]) - for base in range(0, n - 0xFB, 0xFB): - res[base:base + 0xFB] = pattern - remain = n % 0xFB - if remain: - base = (n // 0xFB) * 0xFB - res[base:] = pattern[:remain] - assert(len(res) == n) - return res - - -def chunked(source, size): - for i in range(0, len(source), size): - yield source[i:i+size] - - -class KangarooTwelveTV(unittest.TestCase): - - # https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KangarooTwelve.txt - - def test_zero_1(self): - tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51 - 3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5""" - - btv = txt2bin(tv) - res = K12.new().read(32) - self.assertEqual(res, btv) - - def test_zero_2(self): - tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51 - 3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5 - 42 69 C0 56 B8 C8 2E 48 27 60 38 B6 D2 92 96 6C - C0 7A 3D 46 45 27 2E 31 FF 38 50 81 39 EB 0A 71""" - - btv = txt2bin(tv) - res = K12.new().read(64) - self.assertEqual(res, btv) - - def test_zero_3(self): - tv = """E8 DC 56 36 42 F7 22 8C 84 68 4C 89 84 05 D3 A8 - 34 79 91 58 C0 79 B1 28 80 27 7A 1D 28 E2 FF 6D""" - - btv = txt2bin(tv) - res = K12.new().read(10032) - self.assertEqual(res[-32:], btv) - - def test_ptn_1(self): - tv = """2B DA 92 45 0E 8B 14 7F 8A 7C B6 29 E7 84 A0 58 - EF CA 7C F7 D8 21 8E 02 D3 45 DF AA 65 24 4A 1F""" - - btv = txt2bin(tv) - res = K12.new(data=ptn(1)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17(self): - tv = """6B F7 5F A2 23 91 98 DB 47 72 E3 64 78 F8 E1 9B - 0F 37 12 05 F6 A9 A9 3A 27 3F 51 DF 37 12 28 88""" - - btv = txt2bin(tv) - res = K12.new(data=ptn(17)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_2(self): - tv = """0C 31 5E BC DE DB F6 14 26 DE 7D CF 8F B7 25 D1 - E7 46 75 D7 F5 32 7A 50 67 F3 67 B1 08 EC B6 7C""" - - btv = txt2bin(tv) - res = K12.new(data=ptn(17**2)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_3(self): - tv = """CB 55 2E 2E C7 7D 99 10 70 1D 57 8B 45 7D DF 77 - 2C 12 E3 22 E4 EE 7F E4 17 F9 2C 75 8F 0D 59 D0""" - - btv = txt2bin(tv) - res = K12.new(data=ptn(17**3)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_4(self): - tv = """87 01 04 5E 22 20 53 45 FF 4D DA 05 55 5C BB 5C - 3A F1 A7 71 C2 B8 9B AE F3 7D B4 3D 99 98 B9 FE""" - - btv = txt2bin(tv) - data = ptn(17**4) - - # All at once - res = K12.new(data=data).read(32) - self.assertEqual(res, btv) - - # Byte by byte - k12 = K12.new() - for x in data: - k12.update(bchr(x)) - res = k12.read(32) - self.assertEqual(res, btv) - - # Chunks of various prime sizes - for chunk_size in (13, 17, 19, 23, 31): - k12 = K12.new() - for x in chunked(data, chunk_size): - k12.update(x) - res = k12.read(32) - self.assertEqual(res, btv) - - def test_ptn_17_5(self): - tv = """84 4D 61 09 33 B1 B9 96 3C BD EB 5A E3 B6 B0 5C - C7 CB D6 7C EE DF 88 3E B6 78 A0 A8 E0 37 16 82""" - - btv = txt2bin(tv) - data = ptn(17**5) - - # All at once - res = K12.new(data=data).read(32) - self.assertEqual(res, btv) - - # Chunks - k12 = K12.new() - for chunk in chunked(data, 8192): - k12.update(chunk) - res = k12.read(32) - self.assertEqual(res, btv) - - def test_ptn_17_6(self): - tv = """3C 39 07 82 A8 A4 E8 9F A6 36 7F 72 FE AA F1 32 - 55 C8 D9 58 78 48 1D 3C D8 CE 85 F5 8E 88 0A F8""" - - btv = txt2bin(tv) - data = ptn(17**6) - - # All at once - res = K12.new(data=data).read(32) - self.assertEqual(res, btv) - - def test_ptn_c_1(self): - tv = """FA B6 58 DB 63 E9 4A 24 61 88 BF 7A F6 9A 13 30 - 45 F4 6E E9 84 C5 6E 3C 33 28 CA AF 1A A1 A5 83""" - - btv = txt2bin(tv) - custom = ptn(1) - - # All at once - res = K12.new(custom=custom).read(32) - self.assertEqual(res, btv) - - def test_ptn_c_41(self): - tv = """D8 48 C5 06 8C ED 73 6F 44 62 15 9B 98 67 FD 4C - 20 B8 08 AC C3 D5 BC 48 E0 B0 6B A0 A3 76 2E C4""" - - btv = txt2bin(tv) - custom = ptn(41) - - # All at once - res = K12.new(data=b'\xFF', custom=custom).read(32) - self.assertEqual(res, btv) - - def test_ptn_c_41_2(self): - tv = """C3 89 E5 00 9A E5 71 20 85 4C 2E 8C 64 67 0A C0 - 13 58 CF 4C 1B AF 89 44 7A 72 42 34 DC 7C ED 74""" - - btv = txt2bin(tv) - custom = ptn(41**2) - - # All at once - res = K12.new(data=b'\xFF' * 3, custom=custom).read(32) - self.assertEqual(res, btv) - - def test_ptn_c_41_3(self): - tv = """75 D2 F8 6A 2E 64 45 66 72 6B 4F BC FC 56 57 B9 - DB CF 07 0C 7B 0D CA 06 45 0A B2 91 D7 44 3B CF""" - - btv = txt2bin(tv) - custom = ptn(41**3) - - # All at once - res = K12.new(data=b'\xFF' * 7, custom=custom).read(32) - self.assertEqual(res, btv) - - # https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/ - - def test_ptn_8191(self): - tv = """1B 57 76 36 F7 23 64 3E 99 0C C7 D6 A6 59 83 74 - 36 FD 6A 10 36 26 60 0E B8 30 1C D1 DB E5 53 D6""" - - btv = txt2bin(tv) - - # All at once - res = K12.new(data=ptn(8191)).read(32) - self.assertEqual(res, btv) - - def test_ptn_8192(self): - tv = """48 F2 56 F6 77 2F 9E DF B6 A8 B6 61 EC 92 DC 93 - B9 5E BD 05 A0 8A 17 B3 9A E3 49 08 70 C9 26 C3""" - - btv = txt2bin(tv) - - # All at once - res = K12.new(data=ptn(8192)).read(32) - self.assertEqual(res, btv) - - def test_ptn_8192_8189(self): - tv = """3E D1 2F 70 FB 05 DD B5 86 89 51 0A B3 E4 D2 3C - 6C 60 33 84 9A A0 1E 1D 8C 22 0A 29 7F ED CD 0B""" - - btv = txt2bin(tv) - - # All at once - res = K12.new(data=ptn(8192), custom=ptn(8189)).read(32) - self.assertEqual(res, btv) - - def test_ptn_8192_8190(self): - tv = """6A 7C 1B 6A 5C D0 D8 C9 CA 94 3A 4A 21 6C C6 46 - 04 55 9A 2E A4 5F 78 57 0A 15 25 3D 67 BA 00 AE""" - - btv = txt2bin(tv) - - # All at once - res = K12.new(data=ptn(8192), custom=ptn(8190)).read(32) - self.assertEqual(res, btv) - - ### - - def test_1(self): - tv = "fd608f91d81904a9916e78a18f65c157a78d63f93d8f6367db0524526a5ea2bb" - - btv = txt2bin(tv) - res = K12.new(data=b'', custom=ptn(100)).read(32) - self.assertEqual(res, btv) - - def test_2(self): - tv4 = "5a4ec9a649f81916d4ce1553492962f7868abf8dd1ceb2f0cb3682ea95cda6a6" - tv3 = "441688fe4fe4ae9425eb3105eb445eb2b3a6f67b66eff8e74ebfbc49371f6d4c" - tv2 = "17269a57759af0214c84a0fd9bc851f4d95f80554cfed4e7da8a6ee1ff080131" - tv1 = "33826990c09dc712ba7224f0d9be319e2720de95a4c1afbd2211507dae1c703a" - tv0 = "9f4d3aba908ddc096e4d3a71da954f917b9752f05052b9d26d916a6fbc75bf3e" - - res = K12.new(data=b'A' * (8192 - 4), custom=b'B').read(32) - self.assertEqual(res, txt2bin(tv4)) - - res = K12.new(data=b'A' * (8192 - 3), custom=b'B').read(32) - self.assertEqual(res, txt2bin(tv3)) - - res = K12.new(data=b'A' * (8192 - 2), custom=b'B').read(32) - self.assertEqual(res, txt2bin(tv2)) - - res = K12.new(data=b'A' * (8192 - 1), custom=b'B').read(32) - self.assertEqual(res, txt2bin(tv1)) - - res = K12.new(data=b'A' * (8192 - 0), custom=b'B').read(32) - self.assertEqual(res, txt2bin(tv0)) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(KangarooTwelveTest) - tests += list_test_cases(KangarooTwelveTV) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD2.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD2.py deleted file mode 100644 index 9375168..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD2.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD2.py: Self-test for the MD2 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD2""" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1319 - ('8350e5a3e24c153df2275c9f80692773', '', "'' (empty string)"), - ('32ec01ec4a6dac72c0ab96fb34c0b5d1', 'a'), - ('da853b0d3f88d99b30283a69e6ded6bb', 'abc'), - ('ab4f496bfb2a530b219ff33031fe06b0', 'message digest'), - - ('4e8ddff3650292ab5a4108c3aa47940b', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('da33def2a42df13975352846c30338cd', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('d5976f79d83d3a0dc9806c3c66f3efd8', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), -] - -def get_tests(config={}): - from Crypto.Hash import MD2 - from .common import make_hash_tests - return make_hash_tests(MD2, "MD2", test_data, - digest_size=16, - oid="1.2.840.113549.2.2") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD4.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD4.py deleted file mode 100644 index 17b48a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD4.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD4.py: Self-test for the MD4 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD4""" - -__revision__ = "$Id$" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1320 - ('31d6cfe0d16ae931b73c59d7e0c089c0', '', "'' (empty string)"), - ('bde52cb31de33e46245e05fbdbd6fb24', 'a'), - ('a448017aaf21d8525fc10ae87aa6729d', 'abc'), - ('d9130a8164549fe818874806e1c7014b', 'message digest'), - - ('d79e1c308aa5bbcdeea8ed63df412da9', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('043f8582f241db351ce627e153e7f0e4', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('e33b4ddc9c38f2199c3e7b164fcc0536', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), -] - -def get_tests(config={}): - from Crypto.Hash import MD4 - from .common import make_hash_tests - return make_hash_tests(MD4, "MD4", test_data, - digest_size=16, - oid="1.2.840.113549.2.4") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD5.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD5.py deleted file mode 100644 index 830ace7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_MD5.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD5.py: Self-test for the MD5 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD5""" - -from Crypto.Util.py3compat import * -from Crypto.Hash import MD5 -from binascii import unhexlify -import unittest -from Crypto.SelfTest.st_common import list_test_cases - - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1321 - ('d41d8cd98f00b204e9800998ecf8427e', '', "'' (empty string)"), - ('0cc175b9c0f1b6a831c399e269772661', 'a'), - ('900150983cd24fb0d6963f7d28e17f72', 'abc'), - ('f96b697d7cb7938d525a2f31aaf161d0', 'message digest'), - - ('c3fcd3d76192e4007dfb496cca67e13b', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('d174ab98d277d9f5a5611c2c9f419d9f', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('57edf4a22be3c955ac49da2e2107b67a', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), - - # https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/md5/Md5-128.unverified.test-vectors - ('57EDF4A22BE3C955AC49DA2E2107B67A', '1234567890' * 8, 'Set 1, vector #7'), - ('7707D6AE4E027C70EEA2A935C2296F21', 'a'*1000000, 'Set 1, vector #8'), -] - - -class Md5IterTest(unittest.TestCase): - - def runTest(self): - message = b("\x00") * 16 - result1 = "4AE71336E44BF9BF79D2752E234818A5".lower() - result2 = "1A83F51285E4D89403D00C46EF8508FE".lower() - - h = MD5.new(message) - message = h.digest() - self.assertEqual(h.hexdigest(), result1) - - for _ in range(99999): - h = MD5.new(message) - message = h.digest() - - self.assertEqual(h.hexdigest(), result2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = make_hash_tests(MD5, "MD5", test_data, - digest_size=16, - oid="1.2.840.113549.2.5") - if config.get('slow_tests'): - tests += [ Md5IterTest() ] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_Poly1305.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_Poly1305.py deleted file mode 100644 index 0612d4e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_Poly1305.py +++ /dev/null @@ -1,542 +0,0 @@ -# -# SelfTest/Hash/test_Poly1305.py: Self-test for the Poly1305 module -# -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash._Poly1305""" - -import json -import unittest -from binascii import unhexlify, hexlify - -from .common import make_mac_tests -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import Poly1305 -from Crypto.Cipher import AES, ChaCha20 - -from Crypto.Util.py3compat import tobytes -from Crypto.Util.strxor import strxor_c - -# This is a list of (r+s keypair, data, result, description, keywords) tuples. -test_data_basic = [ - ( - "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b", - hexlify(b"Cryptographic Forum Research Group").decode(), - "a8061dc1305136c6c22b8baf0c0127a9", - "RFC7539" - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "0000000000000000000000000000000000000000000000000000000000000000", - "49ec78090e481ec6c26b33b91ccc0307", - "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 A", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "48656c6c6f20776f726c6421", - "a6f745008f81c916a20dcc74eef2b2f0", - "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 B", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "", - "6b657920666f7220506f6c7931333035", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "FF", - "f7e4e0ef4c46d106219da3d1bdaeb3ff", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "FF00", - "7471eceeb22988fc936da1d6e838b70e", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "AA" * 17, - "32590bc07cb2afaccca3f67f122975fe", - "Generated with pure Python", - ), - ( - "00" * 32, - "00" * 64, - "00" * 16, - "RFC7539 A.3 #1", - ), - ( - "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e", - hexlify( - b"Any submission t" - b"o the IETF inten" - b"ded by the Contr" - b"ibutor for publi" - b"cation as all or" - b" part of an IETF" - b" Internet-Draft " - b"or RFC and any s" - b"tatement made wi" - b"thin the context" - b" of an IETF acti" - b"vity is consider" - b"ed an \"IETF Cont" - b"ribution\". Such " - b"statements inclu" - b"de oral statemen" - b"ts in IETF sessi" - b"ons, as well as " - b"written and elec" - b"tronic communica" - b"tions made at an" - b"y time or place," - b" which are addre" - b"ssed to").decode(), - "36e5f6b5c5e06070f0efca96227a863e", - "RFC7539 A.3 #2", - ), - ( - "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000", - hexlify( - b"Any submission t" - b"o the IETF inten" - b"ded by the Contr" - b"ibutor for publi" - b"cation as all or" - b" part of an IETF" - b" Internet-Draft " - b"or RFC and any s" - b"tatement made wi" - b"thin the context" - b" of an IETF acti" - b"vity is consider" - b"ed an \"IETF Cont" - b"ribution\". Such " - b"statements inclu" - b"de oral statemen" - b"ts in IETF sessi" - b"ons, as well as " - b"written and elec" - b"tronic communica" - b"tions made at an" - b"y time or place," - b" which are addre" - b"ssed to").decode(), - "f3477e7cd95417af89a6b8794c310cf0", - "RFC7539 A.3 #3", - ), - ( - "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", - "2754776173206272696c6c69672c2061" - "6e642074686520736c6974687920746f" - "7665730a446964206779726520616e64" - "2067696d626c6520696e207468652077" - "6162653a0a416c6c206d696d73792077" - "6572652074686520626f726f676f7665" - "732c0a416e6420746865206d6f6d6520" - "7261746873206f757467726162652e", - "4541669a7eaaee61e708dc7cbcc5eb62", - "RFC7539 A.3 #4", - ), - ( - "02" + "00" * 31, - "FF" * 16, - "03" + "00" * 15, - "RFC7539 A.3 #5", - ), - ( - "02" + "00" * 15 + "FF" * 16, - "02" + "00" * 15, - "03" + "00" * 15, - "RFC7539 A.3 #6", - ), - ( - "01" + "00" * 31, - "FF" * 16 + "F0" + "FF" * 15 + "11" + "00" * 15, - "05" + "00" * 15, - "RFC7539 A.3 #7", - ), - ( - "01" + "00" * 31, - "FF" * 16 + "FB" + "FE" * 15 + "01" * 16, - "00" * 16, - "RFC7539 A.3 #8", - ), - ( - "02" + "00" * 31, - "FD" + "FF" * 15, - "FA" + "FF" * 15, - "RFC7539 A.3 #9", - ), - ( - "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" - "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" - "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00", - "RFC7539 A.3 #10", - ), - ( - "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" - "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "13" + "00" * 15, - "RFC7539 A.3 #11", - ), -] - -# This is a list of (key(k+r), data, result, description, keywords) tuples. -test_data_aes = [ - ( - "ec074c835580741701425b623235add6851fc40c3467ac0be05cc20404f3f700", - "f3f6", - "f4c633c3044fc145f84f335cb81953de", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("fb447350c4e868c52ac3275cf9d4327e") } - ), - ( - "75deaa25c09f208e1dc4ce6b5cad3fbfa0f3080000f46400d0c7e9076c834403", - "", - "dd3fab2251f11ac759f0887129cc2ee7", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("61ee09218d29b0aaed7e154a2c5509cc") } - ), - ( - "6acb5f61a7176dd320c5c1eb2edcdc7448443d0bb0d21109c89a100b5ce2c208", - "663cea190ffb83d89593f3f476b6bc24" - "d7e679107ea26adb8caf6652d0656136", - "0ee1c16bb73f0f4fd19881753c01cdbe", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("ae212a55399729595dea458bc621ff0e") } - ), - ( - "e1a5668a4d5b66a5f68cc5424ed5982d12976a08c4426d0ce8a82407c4f48207", - "ab0812724a7f1e342742cbed374d94d1" - "36c6b8795d45b3819830f2c04491faf0" - "990c62e48b8018b2c3e4a0fa3134cb67" - "fa83e158c994d961c4cb21095c1bf9", - "5154ad0d2cb26e01274fc51148491f1b", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("9ae831e743978d3a23527c7128149e3a") } - ), -] - -test_data_chacha20 = [ - ( - "00" * 32, - "FF" * 15, - "13cc5bbadc36b03a5163928f0bcb65aa", - "RFC7539 A.4 #1", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 12) } - ), - ( - "00" * 31 + "01", - "FF" * 15, - "0baf33c1d6df211bdd50a6767e98e00a", - "RFC7539 A.4 #2", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } - ), - ( - "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" - "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", - "FF" * 15, - "e8b4c6db226cd8939e65e02eebf834ce", - "RFC7539 A.4 #3", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } - ), - ( - "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" - "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", - "f3 33 88 86 00 00 00 00 00 00 4e 91 00 00 00 00" - "64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd" - "5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2" - "4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0" - "bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf" - "33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81" - "14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55" - "97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38" - "36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4" - "b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9" - "90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e" - "af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a" - "0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a" - "0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e" - "ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10" - "49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30" - "30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29" - "a6 ad 5c b4 02 2b 02 70 9b 00 00 00 00 00 00 00" - "0c 00 00 00 00 00 00 00 09 01 00 00 00 00 00 00", - "ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38", - "RFC7539 A.5", - { 'cipher':ChaCha20, 'nonce':unhexlify("000000000102030405060708") } - ), -] - - -class Poly1305Test_AES(unittest.TestCase): - - key = b'\x11' * 32 - - def test_new_positive(self): - - data = b'r' * 100 - - h1 = Poly1305.new(key=self.key, cipher=AES) - self.assertEqual(h1.digest_size, 16) - self.assertEqual(len(h1.nonce), 16) - d1 = h1.update(data).digest() - self.assertEqual(len(d1), 16) - - h2 = Poly1305.new(key=self.key, nonce=h1.nonce, data=data, cipher=AES) - d2 = h2.digest() - self.assertEqual(h1.nonce, h2.nonce) - self.assertEqual(d1, d2) - - def test_new_negative(self): - from Crypto.Cipher import DES3 - - self.assertRaises(ValueError, Poly1305.new, key=self.key[:31], cipher=AES) - self.assertRaises(ValueError, Poly1305.new, key=self.key, cipher=DES3) - self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 15, cipher=AES) - self.assertRaises(TypeError, Poly1305.new, key=u"2" * 32, cipher=AES) - self.assertRaises(TypeError, Poly1305.new, key=self.key, data=u"2" * 100, cipher=AES) - - def test_update(self): - pieces = [b"\x0A" * 200, b"\x14" * 300] - h1 = Poly1305.new(key=self.key, cipher=AES) - h1.update(pieces[0]).update(pieces[1]) - d1 = h1.digest() - - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h2.update(pieces[0] + pieces[1]) - d2 = h2.digest() - self.assertEqual(d1, d2) - - def test_update_negative(self): - h = Poly1305.new(key=self.key, cipher=AES) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = Poly1305.new(key=self.key, cipher=AES) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.assertTrue(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg=b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = Poly1305.new(key=self.key, data=msg[:4], cipher=AES) - h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - - def test_hex_digest(self): - mac = Poly1305.new(key=self.key, cipher=AES) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.assertTrue(isinstance(hexdigest, type("digest"))) - - def test_verify(self): - h = Poly1305.new(key=self.key, cipher=AES) - mac = h.digest() - h.verify(mac) - wrong_mac = strxor_c(mac, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - - def test_hexverify(self): - h = Poly1305.new(key=self.key, cipher=AES) - mac = h.hexdigest() - h.hexverify(mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - def test_bytearray(self): - - data = b"\x00\x01\x02" - h0 = Poly1305.new(key=self.key, data=data, cipher=AES) - d_ref = h0.digest() - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(self.key) - data_ba = bytearray(data) - - h1 = Poly1305.new(key=self.key, data=data, cipher=AES, nonce=h0.nonce) - h2 = Poly1305.new(key=key_ba, data=data_ba, cipher=AES, nonce=h0.nonce) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xEE' - - self.assertEqual(h1.digest(), d_ref) - self.assertEqual(h2.digest(), d_ref) - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = Poly1305.new(key=self.key, cipher=AES) - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(self.key) - data_mv = get_mv(data) - - h1 = Poly1305.new(key=self.key, data=data, cipher=AES) - h2 = Poly1305.new(key=key_mv, data=data_mv, cipher=AES, - nonce=h1.nonce) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - key_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = Poly1305.new(key=self.key, cipher=AES) - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class Poly1305Test_ChaCha20(unittest.TestCase): - - key = b'\x11' * 32 - - def test_new_positive(self): - data = b'r' * 100 - - h1 = Poly1305.new(key=self.key, cipher=ChaCha20) - self.assertEqual(h1.digest_size, 16) - self.assertEqual(len(h1.nonce), 12) - - h2 = Poly1305.new(key=self.key, cipher=ChaCha20, nonce = b'8' * 8) - self.assertEqual(len(h2.nonce), 8) - self.assertEqual(h2.nonce, b'8' * 8) - - def test_new_negative(self): - - self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 7, cipher=ChaCha20) - - -# -# make_mac_tests() expect a new() function with signature new(key, data, -# **kwargs), and we need to adapt Poly1305's, as it only uses keywords -# -class Poly1305_New(object): - - @staticmethod - def new(key, *data, **kwds): - _kwds = dict(kwds) - if len(data) == 1: - _kwds['data'] = data[0] - _kwds['key'] = key - return Poly1305.new(**_kwds) - - -class Poly1305_Basic(object): - - @staticmethod - def new(key, *data, **kwds): - from Crypto.Hash.Poly1305 import Poly1305_MAC - - if len(data) == 1: - msg = data[0] - else: - msg = None - - return Poly1305_MAC(key[:16], key[16:], msg) - - -class Poly1305AES_MC(unittest.TestCase): - - def runTest(self): - tag = unhexlify(b"fb447350c4e868c52ac3275cf9d4327e") - - msg = b'' - for msg_len in range(5000 + 1): - key = tag + strxor_c(tag, 0xFF) - nonce = tag[::-1] - if msg_len > 0: - msg = msg + tobytes(tag[0]) - auth = Poly1305.new(key=key, nonce=nonce, cipher=AES, data=msg) - tag = auth.digest() - - # Compare against output of original DJB's poly1305aes-20050218 - self.assertEqual("CDFA436DDD629C7DC20E1128530BAED2", auth.hexdigest().upper()) - - -def get_tests(config={}): - tests = make_mac_tests(Poly1305_Basic, "Poly1305", test_data_basic) - tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_aes) - tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_chacha20) - tests += [ Poly1305AES_MC() ] - tests += list_test_cases(Poly1305Test_AES) - tests += list_test_cases(Poly1305Test_ChaCha20) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_RIPEMD160.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_RIPEMD160.py deleted file mode 100644 index 153c570..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_RIPEMD160.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_RIPEMD160.py: Self-test for the RIPEMD-160 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -#"""Self-test suite for Crypto.Hash.RIPEMD160""" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors downloaded 2008-09-12 from - # http://homes.esat.kuleuven.be/~bosselae/ripemd160.html - ('9c1185a5c5e9fc54612808977ee8f548b2258d31', '', "'' (empty string)"), - ('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', 'a'), - ('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc', 'abc'), - ('5d0689ef49d2fae572b881b123a85ffa21595f36', 'message digest'), - - ('f71c27109c692c1b56bbdceb5b9d2865b3708dbc', - 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('12a053384a9c0c88e405a06c27dcf49ada62eb2b', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', - 'abcdbcd...pnopq'), - - ('b0e20b6e3116640286ed3a87a5713079b21f5189', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('9b752e45573d4b39f4dbd3323cab82bf63326bfb', - '1234567890' * 8, - "'1234567890' * 8"), - - ('52783243c1697bdbe16d37f97f68f08325dc1528', - 'a' * 10**6, - '"a" * 10**6'), -] - -def get_tests(config={}): - from Crypto.Hash import RIPEMD160 - from .common import make_hash_tests - return make_hash_tests(RIPEMD160, "RIPEMD160", test_data, - digest_size=20, - oid="1.3.36.3.2.1") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA1.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA1.py deleted file mode 100644 index a883a44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA1.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/SHA1.py: Self-test for the SHA-1 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA""" - -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data_various = [ - # FIPS PUB 180-2, A.1 - "One-Block Message" - ('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'), - - # FIPS PUB 180-2, A.2 - "Multi-Block Message" - ('84983e441c3bd26ebaae4aa1f95129e5e54670f1', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # FIPS PUB 180-2, A.3 - "Long Message" -# ('34aa973cd4c4daa4f61eeb2bdbad27316534016f', -# 'a' * 10**6, -# '"a" * 10**6'), - - # RFC 3174: Section 7.3, "TEST4" (multiple of 512 bits) - ('dea356a2cddd90c7a7ecedc5ebb563934f460452', - '01234567' * 80, - '"01234567" * 80'), -] - -def get_tests(config={}): - from Crypto.Hash import SHA1 - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA1"), - "SHA1ShortMsg.rsp", - "KAT SHA-1", - { "len" : lambda x: int(x) } ) or [] - - test_data = test_data_various[:] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA1, "SHA1", test_data, - digest_size=20, - oid="1.3.14.3.2.26") - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA224.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA224.py deleted file mode 100644 index cf81ad9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA224.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA224.py: Self-test for the SHA-224 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA224""" - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - - # RFC 3874: Section 3.1, "Test Vector #1 - ('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7', 'abc'), - - # RFC 3874: Section 3.2, "Test Vector #2 - ('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # RFC 3874: Section 3.3, "Test Vector #3 - ('20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67', 'a' * 10**6, "'a' * 10**6"), - - # Examples from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', ''), - - ('49b08defa65e644cbf8a2dd9270bdededabc741997d1dadd42026d7b', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - - ('58911e7fccf2971a7d07f93162d8bd13568e71aa8fc86fc1fe9043d1', - 'Frank jagt im komplett verwahrlosten Taxi quer durch Bayern'), - -] - -def get_tests(config={}): - from Crypto.Hash import SHA224 - from .common import make_hash_tests - return make_hash_tests(SHA224, "SHA224", test_data, - digest_size=28, - oid='2.16.840.1.101.3.4.2.4') - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA256.py deleted file mode 100644 index bb99326..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA256.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA256.py: Self-test for the SHA-256 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA256""" - -import unittest -from Crypto.Util.py3compat import * - -class LargeSHA256Test(unittest.TestCase): - def runTest(self): - """SHA256: 512/520 MiB test""" - from Crypto.Hash import SHA256 - zeros = bchr(0x00) * (1024*1024) - - h = SHA256.new(zeros) - for i in range(511): - h.update(zeros) - - # This test vector is from PyCrypto's old testdata.py file. - self.assertEqual('9acca8e8c22201155389f65abbf6bc9723edc7384ead80503839f49dcc56d767', h.hexdigest()) # 512 MiB - - for i in range(8): - h.update(zeros) - - # This test vector is from PyCrypto's old testdata.py file. - self.assertEqual('abf51ad954b246009dfe5a50ecd582fd5b8f1b8b27f30393853c3ef721e7fa6e', h.hexdigest()) # 520 MiB - -def get_tests(config={}): - # Test vectors from FIPS PUB 180-2 - # This is a list of (expected_result, input[, description]) tuples. - test_data = [ - # FIPS PUB 180-2, B.1 - "One-Block Message" - ('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', - 'abc'), - - # FIPS PUB 180-2, B.2 - "Multi-Block Message" - ('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # FIPS PUB 180-2, B.3 - "Long Message" - ('cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0', - 'a' * 10**6, - '"a" * 10**6'), - - # Test for an old PyCrypto bug. - ('f7fd017a3c721ce7ff03f3552c0813adcc48b7f33f07e5e2ba71e23ea393d103', - 'This message is precisely 55 bytes long, to test a bug.', - 'Length = 55 (mod 64)'), - - # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', ''), - - ('d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - ] - - from Crypto.Hash import SHA256 - from .common import make_hash_tests - tests = make_hash_tests(SHA256, "SHA256", test_data, - digest_size=32, - oid="2.16.840.1.101.3.4.2.1") - - if config.get('slow_tests'): - tests += [LargeSHA256Test()] - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA384.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA384.py deleted file mode 100644 index c682eb4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA384.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA.py: Self-test for the SHA-384 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA384""" - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - - # RFC 4634: Section Page 8.4, "Test 1" - ('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7', 'abc'), - - # RFC 4634: Section Page 8.4, "Test 2.2" - ('09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), - - # RFC 4634: Section Page 8.4, "Test 3" - ('9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985', 'a' * 10**6, "'a' * 10**6"), - - # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b', ''), - - # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('71e8383a4cea32d6fd6877495db2ee353542f46fa44bc23100bca48f3366b84e809f0708e81041f427c6d5219a286677', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - -] - -def get_tests(config={}): - from Crypto.Hash import SHA384 - from .common import make_hash_tests - return make_hash_tests(SHA384, "SHA384", test_data, - digest_size=48, - oid='2.16.840.1.101.3.4.2.2') - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_224.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_224.py deleted file mode 100644 index f92147a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_224.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_224.py: Self-test for the SHA-3/224 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_224""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_224 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-224.txt", - "KAT SHA-3 224", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_224", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.7") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_256.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_256.py deleted file mode 100644 index 432c932..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_256.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_256.py: Self-test for the SHA-3/256 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_256""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_256 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-256.txt", - "KAT SHA-3 256", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - - tests += make_hash_tests(SHA3, "SHA3_256", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.8") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_384.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_384.py deleted file mode 100644 index b0ba1bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_384.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_384.py: Self-test for the SHA-3/384 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_384""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_384 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-384.txt", - "KAT SHA-3 384", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_384", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.9") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_512.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_512.py deleted file mode 100644 index 7d1007a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA3_512.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_512.py: Self-test for the SHA-3/512 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_512""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_512 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-512.txt", - "KAT SHA-3 512", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_512", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.10") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA512.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA512.py deleted file mode 100644 index 20961ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHA512.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA512.py: Self-test for the SHA-512 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA512""" - -from binascii import hexlify - -from Crypto.Hash import SHA512 -from .common import make_hash_tests -from Crypto.SelfTest.loader import load_test_vectors - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data_512_other = [ - - # RFC 4634: Section Page 8.4, "Test 1" - ('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc'), - - # RFC 4634: Section Page 8.4, "Test 2.1" - ('8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), - - # RFC 4634: Section Page 8.4, "Test 3" - ('e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b', 'a' * 10**6, "'a' * 10**6"), - - # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', ''), - - ('af9ed2de700433b803240a552b41b5a472a6ef3fe1431a722b2063c75e9f07451f67a28e37d09cde769424c96aea6f8971389db9e1993d6c565c3c71b855723c', 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), -] - - -def get_tests_SHA512(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512ShortMsg.rsp", - "KAT SHA-512", - {"len": lambda x: int(x)}) or [] - - test_data = test_data_512_other[:] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512", test_data, - digest_size=64, - oid="2.16.840.1.101.3.4.2.3") - return tests - - -def get_tests_SHA512_224(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512_224ShortMsg.rsp", - "KAT SHA-512/224", - {"len": lambda x: int(x)}) or [] - - test_data = [] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512/224", test_data, - digest_size=28, - oid="2.16.840.1.101.3.4.2.5", - extra_params={ "truncate" : "224" }) - return tests - - -def get_tests_SHA512_256(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512_256ShortMsg.rsp", - "KAT SHA-512/256", - {"len": lambda x: int(x)}) or [] - - test_data = [] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512/256", test_data, - digest_size=32, - oid="2.16.840.1.101.3.4.2.6", - extra_params={ "truncate" : "256" }) - return tests - - -def get_tests(config={}): - - tests = [] - tests += get_tests_SHA512() - tests += get_tests_SHA512_224() - tests += get_tests_SHA512_256() - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHAKE.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHAKE.py deleted file mode 100644 index d8423b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_SHAKE.py +++ /dev/null @@ -1,151 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHAKE128 and SHAKE256""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import SHAKE128, SHAKE256 -from Crypto.Util.py3compat import b, bchr, bord, tobytes - -class SHAKETest(unittest.TestCase): - - def test_new_positive(self): - - xof1 = self.shake.new() - xof2 = self.shake.new(data=b("90")) - xof3 = self.shake.new().update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = self.shake.new() - h.update(pieces[0]).update(pieces[1]) - digest = h.read(10) - h = self.shake.new() - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.read(10), digest) - - def test_update_negative(self): - h = self.shake.new() - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.shake.new() - digest = h.read(90) - - # read returns a byte string of the right length - self.assertTrue(isinstance(digest, type(b("digest")))) - self.assertEqual(len(digest), 90) - - def test_update_after_read(self): - mac = self.shake.new() - mac.update(b("rrrr")) - mac.read(90) - self.assertRaises(TypeError, mac.update, b("ttt")) - - def test_copy(self): - mac = self.shake.new() - mac.update(b("rrrr")) - mac2 = mac.copy() - x1 = mac.read(90) - x2 = mac2.read(90) - self.assertEqual(x1, x2) - - -class SHAKE128Test(SHAKETest): - shake = SHAKE128 - - -class SHAKE256Test(SHAKETest): - shake = SHAKE256 - - -class SHAKEVectors(unittest.TestCase): - pass - - -test_vectors_128 = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHAKE128.txt", - "Short Messages KAT SHAKE128", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_128): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = SHAKE128.new(data=data) - digest = hobj.read(len(result)) - self.assertEqual(digest, result) - - setattr(SHAKEVectors, "test_128_%d" % idx, new_test) - - -test_vectors_256 = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHAKE256.txt", - "Short Messages KAT SHAKE256", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_256): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = SHAKE256.new(data=data) - digest = hobj.read(len(result)) - self.assertEqual(digest, result) - - setattr(SHAKEVectors, "test_256_%d" % idx, new_test) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(SHAKE128Test) - tests += list_test_cases(SHAKE256Test) - tests += list_test_cases(SHAKEVectors) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TupleHash.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TupleHash.py deleted file mode 100644 index f3fc3d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TupleHash.py +++ /dev/null @@ -1,302 +0,0 @@ -import unittest -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import tobytes -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import TupleHash128, TupleHash256 - - -class TupleHashTest(unittest.TestCase): - - def new(self, *args, **kwargs): - return self.TupleHash.new(*args, **kwargs) - - def test_new_positive(self): - - h = self.new() - for new_func in self.TupleHash.new, h.new: - - for dbits in range(64, 1024 + 1, 8): - hobj = new_func(digest_bits=dbits) - self.assertEqual(hobj.digest_size * 8, dbits) - - for dbytes in range(8, 128 + 1): - hobj = new_func(digest_bytes=dbytes) - self.assertEqual(hobj.digest_size, dbytes) - - hobj = h.new() - self.assertEqual(hobj.digest_size, self.default_bytes) - - def test_new_negative(self): - - h = self.new() - for new_func in self.TupleHash.new, h.new: - self.assertRaises(TypeError, new_func, - digest_bytes=self.minimum_bytes, - digest_bits=self.minimum_bits) - self.assertRaises(ValueError, new_func, digest_bytes=0) - self.assertRaises(ValueError, new_func, - digest_bits=self.minimum_bits + 7) - self.assertRaises(ValueError, new_func, - digest_bits=self.minimum_bits - 8) - self.assertRaises(ValueError, new_func, - digest_bits=self.minimum_bytes - 1) - - def test_default_digest_size(self): - digest = self.new().digest() - self.assertEqual(len(digest), self.default_bytes) - - def test_update(self): - h = self.new() - h.update(b'') - h.digest() - - h = self.new() - h.update(b'') - h.update(b'STRING1') - h.update(b'STRING2') - mac1 = h.digest() - - h = self.new() - h.update(b'STRING1') - h.update(b'STRING2') - mac2 = h.digest() - self.assertNotEqual(mac1, mac2) - - h = self.new() - h.update(b'STRING1', b'STRING2') - self.assertEqual(mac2, h.digest()) - - h = self.new() - t = b'STRING1', b'STRING2' - h.update(*t) - self.assertEqual(mac2, h.digest()) - - def test_update_negative(self): - h = self.new() - self.assertRaises(TypeError, h.update, u"string") - self.assertRaises(TypeError, h.update, None) - self.assertRaises(TypeError, h.update, (b'STRING1', b'STRING2')) - - def test_digest(self): - h = self.new() - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.assertTrue(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg = b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = self.new() - h.update(msg) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, dig1) - - def test_hex_digest(self): - mac = self.new() - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.assertTrue(isinstance(hexdigest, type("digest"))) - - def test_bytearray(self): - - data = b"\x00\x01\x02" - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = self.new() - h2 = self.new() - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = self.new() - h2 = self.new() - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class TupleHash128Test(TupleHashTest): - - TupleHash = TupleHash128 - - minimum_bytes = 8 - default_bytes = 64 - - minimum_bits = 64 - default_bits = 512 - - -class TupleHash256Test(TupleHashTest): - - TupleHash = TupleHash256 - - minimum_bytes = 8 - default_bytes = 64 - - minimum_bits = 64 - default_bits = 512 - - -class NISTExampleTestVectors(unittest.TestCase): - - # http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TupleHash_samples.pdf - test_data = [ - ( - ( - "00 01 02", - "10 11 12 13 14 15", - ), - "", - "C5 D8 78 6C 1A FB 9B 82 11 1A B3 4B 65 B2 C0 04" - "8F A6 4E 6D 48 E2 63 26 4C E1 70 7D 3F FC 8E D1", - "KMAC128 Sample #1 NIST", - TupleHash128 - ), - ( - ( - "00 01 02", - "10 11 12 13 14 15", - ), - "My Tuple App", - "75 CD B2 0F F4 DB 11 54 E8 41 D7 58 E2 41 60 C5" - "4B AE 86 EB 8C 13 E7 F5 F4 0E B3 55 88 E9 6D FB", - "KMAC128 Sample #2 NIST", - TupleHash128 - ), - ( - ( - "00 01 02", - "10 11 12 13 14 15", - "20 21 22 23 24 25 26 27 28", - ), - "My Tuple App", - "E6 0F 20 2C 89 A2 63 1E DA 8D 4C 58 8C A5 FD 07" - "F3 9E 51 51 99 8D EC CF 97 3A DB 38 04 BB 6E 84", - "KMAC128 Sample #3 NIST", - TupleHash128 - ), - ( - ( - "00 01 02", - "10 11 12 13 14 15", - ), - "", - "CF B7 05 8C AC A5 E6 68 F8 1A 12 A2 0A 21 95 CE" - "97 A9 25 F1 DB A3 E7 44 9A 56 F8 22 01 EC 60 73" - "11 AC 26 96 B1 AB 5E A2 35 2D F1 42 3B DE 7B D4" - "BB 78 C9 AE D1 A8 53 C7 86 72 F9 EB 23 BB E1 94", - "KMAC256 Sample #4 NIST", - TupleHash256 - ), - ( - ( - "00 01 02", - "10 11 12 13 14 15", - ), - "My Tuple App", - "14 7C 21 91 D5 ED 7E FD 98 DB D9 6D 7A B5 A1 16" - "92 57 6F 5F E2 A5 06 5F 3E 33 DE 6B BA 9F 3A A1" - "C4 E9 A0 68 A2 89 C6 1C 95 AA B3 0A EE 1E 41 0B" - "0B 60 7D E3 62 0E 24 A4 E3 BF 98 52 A1 D4 36 7E", - "KMAC256 Sample #5 NIST", - TupleHash256 - ), - ( - ( - "00 01 02", - "10 11 12 13 14 15", - "20 21 22 23 24 25 26 27 28", - ), - "My Tuple App", - "45 00 0B E6 3F 9B 6B FD 89 F5 47 17 67 0F 69 A9" - "BC 76 35 91 A4 F0 5C 50 D6 88 91 A7 44 BC C6 E7" - "D6 D5 B5 E8 2C 01 8D A9 99 ED 35 B0 BB 49 C9 67" - "8E 52 6A BD 8E 85 C1 3E D2 54 02 1D B9 E7 90 CE", - "KMAC256 Sample #6 NIST", - TupleHash256 - ), - - - - ] - - def setUp(self): - td = [] - for tv_in in self.test_data: - tv_out = [None] * len(tv_in) - - tv_out[0] = [] - for string in tv_in[0]: - tv_out[0].append(unhexlify(string.replace(" ", ""))) - - tv_out[1] = tobytes(tv_in[1]) # Custom - tv_out[2] = unhexlify(tv_in[2].replace(" ", "")) - tv_out[3] = tv_in[3] - tv_out[4] = tv_in[4] - td.append(tv_out) - self.test_data = td - - def runTest(self): - - for data, custom, digest, text, module in self.test_data: - hd1 = module.new(custom=custom, digest_bytes=len(digest)) - hd2 = module.new(custom=custom, digest_bytes=len(digest)) - - # Call update() for each element - for string in data: - hd1.update(string) - - # One single update for all elements - hd2.update(*data) - - self.assertEqual(hd1.digest(), digest, msg=text) - self.assertEqual(hd2.digest(), digest, msg=text) - -def get_tests(config={}): - tests = [] - - tests += list_test_cases(TupleHash128Test) - tests += list_test_cases(TupleHash256Test) - tests.append(NISTExampleTestVectors()) - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TurboSHAKE.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TurboSHAKE.py deleted file mode 100644 index b37aee1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_TurboSHAKE.py +++ /dev/null @@ -1,468 +0,0 @@ -"""Self-test suite for Crypto.Hash.TurboSHAKE128 and TurboSHAKE256""" - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import TurboSHAKE128, TurboSHAKE256 -from Crypto.Util.py3compat import bchr - - -class TurboSHAKETest(unittest.TestCase): - - def test_new_positive(self): - - xof1 = self.TurboSHAKE.new() - xof1.update(b'90') - - xof2 = self.TurboSHAKE.new(domain=0x1F) - xof2.update(b'90') - - xof3 = self.TurboSHAKE.new(data=b'90') - - out1 = xof1.read(128) - out2 = xof2.read(128) - out3 = xof3.read(128) - - self.assertEqual(out1, out2) - self.assertEqual(out1, out3) - - def test_new_domain(self): - xof1 = self.TurboSHAKE.new(domain=0x1D) - xof2 = self.TurboSHAKE.new(domain=0x20) - self.assertNotEqual(xof1.read(128), xof2.read(128)) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - - xof1 = self.TurboSHAKE.new() - xof1.update(pieces[0]).update(pieces[1]) - digest1 = xof1.read(10) - - xof2 = self.TurboSHAKE.new() - xof2.update(pieces[0] + pieces[1]) - digest2 = xof2.read(10) - - self.assertEqual(digest1, digest2) - - def test_update_negative(self): - xof1 = self.TurboSHAKE.new() - self.assertRaises(TypeError, xof1.update, u"string") - - def test_read(self): - xof1 = self.TurboSHAKE.new() - digest = xof1.read(90) - - # read returns a byte string of the right length - self.assertTrue(isinstance(digest, bytes)) - self.assertEqual(len(digest), 90) - - def test_update_after_read(self): - xof1 = self.TurboSHAKE.new() - xof1.update(b"rrrr") - xof1.read(90) - self.assertRaises(TypeError, xof1.update, b"ttt") - - def test_new(self): - xof1 = self.TurboSHAKE.new(domain=0x07) - xof1.update(b'90') - digest1 = xof1.read(100) - - xof2 = xof1.new() - xof2.update(b'90') - digest2 = xof2.read(100) - - self.assertEqual(digest1, digest2) - - self.assertRaises(TypeError, xof1.new, domain=0x07) - - -class TurboSHAKE128Test(TurboSHAKETest): - TurboSHAKE = TurboSHAKE128 - - -class TurboSHAKE256Test(TurboSHAKETest): - TurboSHAKE = TurboSHAKE256 - - -def txt2bin(txt): - clean = txt.replace(" ", "").replace("\n", "").replace("\r", "") - return unhexlify(clean) - - -def ptn(n): - res = bytearray(n) - pattern = b"".join([bchr(x) for x in range(0, 0xFB)]) - for base in range(0, n - 0xFB, 0xFB): - res[base:base + 0xFB] = pattern - remain = n % 0xFB - if remain: - base = (n // 0xFB) * 0xFB - res[base:] = pattern[:remain] - assert len(res) == n - return res - - -def chunked(source, size): - for i in range(0, len(source), size): - yield source[i:i+size] - - -class TurboSHAKE128TV(unittest.TestCase): - - def test_zero_1(self): - tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53 - 8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new().read(32) - self.assertEqual(res, btv) - - def test_zero_2(self): - tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53 - 8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C - 3E 8C CA E2 A4 DA E5 6C 84 A0 4C 23 85 C0 3C 15 - E8 19 3B DF 58 73 73 63 32 16 91 C0 54 62 C8 DF""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new().read(64) - self.assertEqual(res, btv) - - def test_zero_3(self): - tv = """A3 B9 B0 38 59 00 CE 76 1F 22 AE D5 48 E7 54 DA - 10 A5 24 2D 62 E8 C6 58 E3 F3 A9 23 A7 55 56 07""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new().read(10032)[-32:] - self.assertEqual(res, btv) - - def test_ptn_1(self): - tv = """55 CE DD 6F 60 AF 7B B2 9A 40 42 AE 83 2E F3 F5 - 8D B7 29 9F 89 3E BB 92 47 24 7D 85 69 58 DA A9""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=ptn(1)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17(self): - tv = """9C 97 D0 36 A3 BA C8 19 DB 70 ED E0 CA 55 4E C6 - E4 C2 A1 A4 FF BF D9 EC 26 9C A6 A1 11 16 12 33""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=ptn(17)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_2(self): - tv = """96 C7 7C 27 9E 01 26 F7 FC 07 C9 B0 7F 5C DA E1 - E0 BE 60 BD BE 10 62 00 40 E7 5D 72 23 A6 24 D2""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=ptn(17**2)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_3(self): - tv = """D4 97 6E B5 6B CF 11 85 20 58 2B 70 9F 73 E1 D6 - 85 3E 00 1F DA F8 0E 1B 13 E0 D0 59 9D 5F B3 72""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=ptn(17**3)).read(32) - self.assertEqual(res, btv) - - def test_ptn_17_4(self): - tv = """DA 67 C7 03 9E 98 BF 53 0C F7 A3 78 30 C6 66 4E - 14 CB AB 7F 54 0F 58 40 3B 1B 82 95 13 18 EE 5C""" - - btv = txt2bin(tv) - data = ptn(17**4) - - # All at once - res = TurboSHAKE128.new(data=data).read(32) - self.assertEqual(res, btv) - - # Byte by byte - xof = TurboSHAKE128.new() - for x in data: - xof.update(bchr(x)) - res = xof.read(32) - self.assertEqual(res, btv) - - # Chunks of various prime sizes - for chunk_size in (13, 17, 19, 23, 31): - xof = TurboSHAKE128.new() - for x in chunked(data, chunk_size): - xof.update(x) - res = xof.read(32) - self.assertEqual(res, btv) - - def test_ptn_17_5(self): - tv = """B9 7A 90 6F BF 83 EF 7C 81 25 17 AB F3 B2 D0 AE - A0 C4 F6 03 18 CE 11 CF 10 39 25 12 7F 59 EE CD""" - - btv = txt2bin(tv) - data = ptn(17**5) - - # All at once - res = TurboSHAKE128.new(data=data).read(32) - self.assertEqual(res, btv) - - # Chunks - xof = TurboSHAKE128.new() - for chunk in chunked(data, 8192): - xof.update(chunk) - res = xof.read(32) - self.assertEqual(res, btv) - - def test_ptn_17_6(self): - tv = """35 CD 49 4A DE DE D2 F2 52 39 AF 09 A7 B8 EF 0C - 4D 1C A4 FE 2D 1A C3 70 FA 63 21 6F E7 B4 C2 B1""" - - btv = txt2bin(tv) - data = ptn(17**6) - - res = TurboSHAKE128.new(data=data).read(32) - self.assertEqual(res, btv) - - def test_ffffff_d01(self): - tv = """BF 32 3F 94 04 94 E8 8E E1 C5 40 FE 66 0B E8 A0 - C9 3F 43 D1 5E C0 06 99 84 62 FA 99 4E ED 5D AB""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b"\xff\xff\xff", domain=0x01).read(32) - self.assertEqual(res, btv) - - def test_ff_d06(self): - tv = """8E C9 C6 64 65 ED 0D 4A 6C 35 D1 35 06 71 8D 68 - 7A 25 CB 05 C7 4C CA 1E 42 50 1A BD 83 87 4A 67""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b'\xFF', domain=0x06).read(32) - self.assertEqual(res, btv) - - def test_ffffff_d07(self): - tv = """B6 58 57 60 01 CA D9 B1 E5 F3 99 A9 F7 77 23 BB - A0 54 58 04 2D 68 20 6F 72 52 68 2D BA 36 63 ED""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x07).read(32) - self.assertEqual(res, btv) - - def test_ffffffffffff_d0b(self): - tv = """8D EE AA 1A EC 47 CC EE 56 9F 65 9C 21 DF A8 E1 - 12 DB 3C EE 37 B1 81 78 B2 AC D8 05 B7 99 CC 37""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b'\xFF' * 7, domain=0x0B).read(32) - self.assertEqual(res, btv) - - def test_ff_d30(self): - tv = """55 31 22 E2 13 5E 36 3C 32 92 BE D2 C6 42 1F A2 - 32 BA B0 3D AA 07 C7 D6 63 66 03 28 65 06 32 5B""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b'\xFF', domain=0x30).read(32) - self.assertEqual(res, btv) - - def test_ffffff_d7f(self): - tv = """16 27 4C C6 56 D4 4C EF D4 22 39 5D 0F 90 53 BD - A6 D2 8E 12 2A BA 15 C7 65 E5 AD 0E 6E AF 26 F9""" - - btv = txt2bin(tv) - res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x7F).read(32) - self.assertEqual(res, btv) - - -class TurboSHAKE256TV(unittest.TestCase): - - def test_zero_1(self): - tv = """36 7A 32 9D AF EA 87 1C 78 02 EC 67 F9 05 AE 13 - C5 76 95 DC 2C 66 63 C6 10 35 F5 9A 18 F8 E7 DB - 11 ED C0 E1 2E 91 EA 60 EB 6B 32 DF 06 DD 7F 00 - 2F BA FA BB 6E 13 EC 1C C2 0D 99 55 47 60 0D B0""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new().read(64) - self.assertEqual(res, btv) - - def test_zero_2(self): - tv = """AB EF A1 16 30 C6 61 26 92 49 74 26 85 EC 08 2F - 20 72 65 DC CF 2F 43 53 4E 9C 61 BA 0C 9D 1D 75""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new().read(10032)[-32:] - self.assertEqual(res, btv) - - def test_ptn_1(self): - tv = """3E 17 12 F9 28 F8 EA F1 05 46 32 B2 AA 0A 24 6E - D8 B0 C3 78 72 8F 60 BC 97 04 10 15 5C 28 82 0E - 90 CC 90 D8 A3 00 6A A2 37 2C 5C 5E A1 76 B0 68 - 2B F2 2B AE 74 67 AC 94 F7 4D 43 D3 9B 04 82 E2""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=ptn(1)).read(64) - self.assertEqual(res, btv) - - def test_ptn_17(self): - tv = """B3 BA B0 30 0E 6A 19 1F BE 61 37 93 98 35 92 35 - 78 79 4E A5 48 43 F5 01 10 90 FA 2F 37 80 A9 E5 - CB 22 C5 9D 78 B4 0A 0F BF F9 E6 72 C0 FB E0 97 - 0B D2 C8 45 09 1C 60 44 D6 87 05 4D A5 D8 E9 C7""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=ptn(17)).read(64) - self.assertEqual(res, btv) - - def test_ptn_17_2(self): - tv = """66 B8 10 DB 8E 90 78 04 24 C0 84 73 72 FD C9 57 - 10 88 2F DE 31 C6 DF 75 BE B9 D4 CD 93 05 CF CA - E3 5E 7B 83 E8 B7 E6 EB 4B 78 60 58 80 11 63 16 - FE 2C 07 8A 09 B9 4A D7 B8 21 3C 0A 73 8B 65 C0""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=ptn(17**2)).read(64) - self.assertEqual(res, btv) - - def test_ptn_17_3(self): - tv = """C7 4E BC 91 9A 5B 3B 0D D1 22 81 85 BA 02 D2 9E - F4 42 D6 9D 3D 42 76 A9 3E FE 0B F9 A1 6A 7D C0 - CD 4E AB AD AB 8C D7 A5 ED D9 66 95 F5 D3 60 AB - E0 9E 2C 65 11 A3 EC 39 7D A3 B7 6B 9E 16 74 FB""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=ptn(17**3)).read(64) - self.assertEqual(res, btv) - - def test_ptn_17_4(self): - tv = """02 CC 3A 88 97 E6 F4 F6 CC B6 FD 46 63 1B 1F 52 - 07 B6 6C 6D E9 C7 B5 5B 2D 1A 23 13 4A 17 0A FD - AC 23 4E AB A9 A7 7C FF 88 C1 F0 20 B7 37 24 61 - 8C 56 87 B3 62 C4 30 B2 48 CD 38 64 7F 84 8A 1D""" - - btv = txt2bin(tv) - data = ptn(17**4) - - # All at once - res = TurboSHAKE256.new(data=data).read(64) - self.assertEqual(res, btv) - - # Byte by byte - xof = TurboSHAKE256.new() - for x in data: - xof.update(bchr(x)) - res = xof.read(64) - self.assertEqual(res, btv) - - # Chunks of various prime sizes - for chunk_size in (13, 17, 19, 23, 31): - xof = TurboSHAKE256.new() - for x in chunked(data, chunk_size): - xof.update(x) - res = xof.read(64) - self.assertEqual(res, btv) - - def test_ptn_17_5(self): - tv = """AD D5 3B 06 54 3E 58 4B 58 23 F6 26 99 6A EE 50 - FE 45 ED 15 F2 02 43 A7 16 54 85 AC B4 AA 76 B4 - FF DA 75 CE DF 6D 8C DC 95 C3 32 BD 56 F4 B9 86 - B5 8B B1 7D 17 78 BF C1 B1 A9 75 45 CD F4 EC 9F""" - - btv = txt2bin(tv) - data = ptn(17**5) - - # All at once - res = TurboSHAKE256.new(data=data).read(64) - self.assertEqual(res, btv) - - # Chunks - xof = TurboSHAKE256.new() - for chunk in chunked(data, 8192): - xof.update(chunk) - res = xof.read(64) - self.assertEqual(res, btv) - - def test_ptn_17_6(self): - tv = """9E 11 BC 59 C2 4E 73 99 3C 14 84 EC 66 35 8E F7 - 1D B7 4A EF D8 4E 12 3F 78 00 BA 9C 48 53 E0 2C - FE 70 1D 9E 6B B7 65 A3 04 F0 DC 34 A4 EE 3B A8 - 2C 41 0F 0D A7 0E 86 BF BD 90 EA 87 7C 2D 61 04""" - - btv = txt2bin(tv) - data = ptn(17**6) - - res = TurboSHAKE256.new(data=data).read(64) - self.assertEqual(res, btv) - - def test_ffffff_d01(self): - tv = """D2 1C 6F BB F5 87 FA 22 82 F2 9A EA 62 01 75 FB - 02 57 41 3A F7 8A 0B 1B 2A 87 41 9C E0 31 D9 33 - AE 7A 4D 38 33 27 A8 A1 76 41 A3 4F 8A 1D 10 03 - AD 7D A6 B7 2D BA 84 BB 62 FE F2 8F 62 F1 24 24""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b"\xff\xff\xff", domain=0x01).read(64) - self.assertEqual(res, btv) - - def test_ff_d06(self): - tv = """73 8D 7B 4E 37 D1 8B 7F 22 AD 1B 53 13 E3 57 E3 - DD 7D 07 05 6A 26 A3 03 C4 33 FA 35 33 45 52 80 - F4 F5 A7 D4 F7 00 EF B4 37 FE 6D 28 14 05 E0 7B - E3 2A 0A 97 2E 22 E6 3A DC 1B 09 0D AE FE 00 4B""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b'\xFF', domain=0x06).read(64) - self.assertEqual(res, btv) - - def test_ffffff_d07(self): - tv = """18 B3 B5 B7 06 1C 2E 67 C1 75 3A 00 E6 AD 7E D7 - BA 1C 90 6C F9 3E FB 70 92 EA F2 7F BE EB B7 55 - AE 6E 29 24 93 C1 10 E4 8D 26 00 28 49 2B 8E 09 - B5 50 06 12 B8 F2 57 89 85 DE D5 35 7D 00 EC 67""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x07).read(64) - self.assertEqual(res, btv) - - def test_ffffffffffff_d0b(self): - tv = """BB 36 76 49 51 EC 97 E9 D8 5F 7E E9 A6 7A 77 18 - FC 00 5C F4 25 56 BE 79 CE 12 C0 BD E5 0E 57 36 - D6 63 2B 0D 0D FB 20 2D 1B BB 8F FE 3D D7 4C B0 - 08 34 FA 75 6C B0 34 71 BA B1 3A 1E 2C 16 B3 C0""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b'\xFF' * 7, domain=0x0B).read(64) - self.assertEqual(res, btv) - - def test_ff_d30(self): - tv = """F3 FE 12 87 3D 34 BC BB 2E 60 87 79 D6 B7 0E 7F - 86 BE C7 E9 0B F1 13 CB D4 FD D0 C4 E2 F4 62 5E - 14 8D D7 EE 1A 52 77 6C F7 7F 24 05 14 D9 CC FC - 3B 5D DA B8 EE 25 5E 39 EE 38 90 72 96 2C 11 1A""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b'\xFF', domain=0x30).read(64) - self.assertEqual(res, btv) - - def test_ffffff_d7f(self): - tv = """AB E5 69 C1 F7 7E C3 40 F0 27 05 E7 D3 7C 9A B7 - E1 55 51 6E 4A 6A 15 00 21 D7 0B 6F AC 0B B4 0C - 06 9F 9A 98 28 A0 D5 75 CD 99 F9 BA E4 35 AB 1A - CF 7E D9 11 0B A9 7C E0 38 8D 07 4B AC 76 87 76""" - - btv = txt2bin(tv) - res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x7F).read(64) - self.assertEqual(res, btv) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TurboSHAKE128Test) - tests += list_test_cases(TurboSHAKE256Test) - tests += list_test_cases(TurboSHAKE128TV) - tests += list_test_cases(TurboSHAKE256TV) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_cSHAKE.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_cSHAKE.py deleted file mode 100644 index 72ad341..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_cSHAKE.py +++ /dev/null @@ -1,178 +0,0 @@ -# =================================================================== -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.cSHAKE128 and cSHAKE256""" - -import unittest - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import cSHAKE128, cSHAKE256, SHAKE128, SHAKE256 -from Crypto.Util.py3compat import b, bchr, tobytes - - -class cSHAKETest(unittest.TestCase): - - def test_left_encode(self): - from Crypto.Hash.cSHAKE128 import _left_encode - self.assertEqual(_left_encode(0), b'\x01\x00') - self.assertEqual(_left_encode(1), b'\x01\x01') - self.assertEqual(_left_encode(256), b'\x02\x01\x00') - - def test_bytepad(self): - from Crypto.Hash.cSHAKE128 import _bytepad - self.assertEqual(_bytepad(b'', 4), b'\x01\x04\x00\x00') - self.assertEqual(_bytepad(b'A', 4), b'\x01\x04A\x00') - self.assertEqual(_bytepad(b'AA', 4), b'\x01\x04AA') - self.assertEqual(_bytepad(b'AAA', 4), b'\x01\x04AAA\x00\x00\x00') - self.assertEqual(_bytepad(b'AAAA', 4), b'\x01\x04AAAA\x00\x00') - self.assertEqual(_bytepad(b'AAAAA', 4), b'\x01\x04AAAAA\x00') - self.assertEqual(_bytepad(b'AAAAAA', 4), b'\x01\x04AAAAAA') - self.assertEqual(_bytepad(b'AAAAAAA', 4), b'\x01\x04AAAAAAA\x00\x00\x00') - - def test_new_positive(self): - - xof1 = self.cshake.new() - xof2 = self.cshake.new(data=b("90")) - xof3 = self.cshake.new().update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - xof1 = self.cshake.new() - ref = xof1.read(10) - xof2 = self.cshake.new(custom=b("")) - xof3 = self.cshake.new(custom=b("foo")) - - self.assertEqual(ref, xof2.read(10)) - self.assertNotEqual(ref, xof3.read(10)) - - xof1 = self.cshake.new(custom=b("foo")) - xof2 = self.cshake.new(custom=b("foo"), data=b("90")) - xof3 = self.cshake.new(custom=b("foo")).update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = self.cshake.new() - h.update(pieces[0]).update(pieces[1]) - digest = h.read(10) - h = self.cshake.new() - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.read(10), digest) - - def test_update_negative(self): - h = self.cshake.new() - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.cshake.new() - digest = h.read(90) - - # read returns a byte string of the right length - self.assertTrue(isinstance(digest, type(b("digest")))) - self.assertEqual(len(digest), 90) - - def test_update_after_read(self): - mac = self.cshake.new() - mac.update(b("rrrr")) - mac.read(90) - self.assertRaises(TypeError, mac.update, b("ttt")) - - def test_shake(self): - # When no customization string is passed, results must match SHAKE - for digest_len in range(64): - xof1 = self.cshake.new(b'TEST') - xof2 = self.shake.new(b'TEST') - self.assertEqual(xof1.read(digest_len), xof2.read(digest_len)) - - -class cSHAKE128Test(cSHAKETest): - cshake = cSHAKE128 - shake = SHAKE128 - - -class cSHAKE256Test(cSHAKETest): - cshake = cSHAKE256 - shake = SHAKE256 - - -class cSHAKEVectors(unittest.TestCase): - pass - - -vector_files = [("ShortMsgSamples_cSHAKE128.txt", "Short Message Samples cSHAKE128", "128_cshake", cSHAKE128), - ("ShortMsgSamples_cSHAKE256.txt", "Short Message Samples cSHAKE256", "256_cshake", cSHAKE256), - ("CustomMsgSamples_cSHAKE128.txt", "Custom Message Samples cSHAKE128", "custom_128_cshake", cSHAKE128), - ("CustomMsgSamples_cSHAKE256.txt", "Custom Message Samples cSHAKE256", "custom_256_cshake", cSHAKE256), - ] - -for file, descr, tag, test_class in vector_files: - - test_vectors = load_test_vectors(("Hash", "SHA3"), file, descr, - {"len": lambda x: int(x), - "nlen": lambda x: int(x), - "slen": lambda x: int(x)}) or [] - - for idx, tv in enumerate(test_vectors): - if getattr(tv, "len", 0) == 0: - data = b("") - else: - data = tobytes(tv.msg) - assert(tv.len == len(tv.msg)*8) - if getattr(tv, "nlen", 0) != 0: - raise ValueError("Unsupported cSHAKE test vector") - if getattr(tv, "slen", 0) == 0: - custom = b("") - else: - custom = tobytes(tv.s) - assert(tv.slen == len(tv.s)*8) - - def new_test(self, data=data, result=tv.md, custom=custom, test_class=test_class): - hobj = test_class.new(data=data, custom=custom) - digest = hobj.read(len(result)) - self.assertEqual(digest, result) - - setattr(cSHAKEVectors, "test_%s_%d" % (tag, idx), new_test) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(cSHAKE128Test) - tests += list_test_cases(cSHAKE256Test) - tests += list_test_cases(cSHAKEVectors) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_keccak.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_keccak.py deleted file mode 100644 index 54cdf27..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Hash/test_keccak.py +++ /dev/null @@ -1,250 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.keccak""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import keccak -from Crypto.Util.py3compat import b, tobytes, bchr - -class KeccakTest(unittest.TestCase): - - def test_new_positive(self): - - for digest_bits in (224, 256, 384, 512): - hobj = keccak.new(digest_bits=digest_bits) - self.assertEqual(hobj.digest_size, digest_bits // 8) - - hobj2 = hobj.new() - self.assertEqual(hobj2.digest_size, digest_bits // 8) - - for digest_bytes in (28, 32, 48, 64): - hobj = keccak.new(digest_bytes=digest_bytes) - self.assertEqual(hobj.digest_size, digest_bytes) - - hobj2 = hobj.new() - self.assertEqual(hobj2.digest_size, digest_bytes) - - def test_new_positive2(self): - - digest1 = keccak.new(data=b("\x90"), digest_bytes=64).digest() - digest2 = keccak.new(digest_bytes=64).update(b("\x90")).digest() - self.assertEqual(digest1, digest2) - - def test_new_negative(self): - - # keccak.new needs digest size - self.assertRaises(TypeError, keccak.new) - - h = keccak.new(digest_bits=512) - - # Either bits or bytes can be specified - self.assertRaises(TypeError, keccak.new, - digest_bytes=64, - digest_bits=512) - - # Range - self.assertRaises(ValueError, keccak.new, digest_bytes=0) - self.assertRaises(ValueError, keccak.new, digest_bytes=1) - self.assertRaises(ValueError, keccak.new, digest_bytes=65) - self.assertRaises(ValueError, keccak.new, digest_bits=0) - self.assertRaises(ValueError, keccak.new, digest_bits=1) - self.assertRaises(ValueError, keccak.new, digest_bits=513) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = keccak.new(digest_bytes=64) - h.update(pieces[0]).update(pieces[1]) - digest = h.digest() - h = keccak.new(digest_bytes=64) - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.digest(), digest) - - def test_update_negative(self): - h = keccak.new(digest_bytes=64) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = keccak.new(digest_bytes=64) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.assertTrue(isinstance(digest, type(b("digest")))) - - def test_hex_digest(self): - mac = keccak.new(digest_bits=512) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.assertTrue(isinstance(hexdigest, type("digest"))) - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = keccak.new(digest_bits=512, data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = keccak.new(digest_bits=512, data=msg).digest() - - # With the proper flag, it is allowed - h = keccak.new(digest_bits=512, data=msg[:4], update_after_digest=True) - self.assertEqual(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEqual(h.digest(), dig2) - - -class KeccakVectors(unittest.TestCase): - pass - - # TODO: add ExtremelyLong tests - - -test_vectors_224 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_224.txt", - "Short Messages KAT 224", - {"len": lambda x: int(x)}) or [] - -test_vectors_224 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_224.txt", - "Long Messages KAT 224", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_224): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=224, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_224_%d" % idx, new_test) - -# --- - -test_vectors_256 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_256.txt", - "Short Messages KAT 256", - { "len" : lambda x: int(x) } ) or [] - -test_vectors_256 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_256.txt", - "Long Messages KAT 256", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_256): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=256, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_256_%d" % idx, new_test) - - -# --- - -test_vectors_384 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_384.txt", - "Short Messages KAT 384", - {"len": lambda x: int(x)}) or [] - -test_vectors_384 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_384.txt", - "Long Messages KAT 384", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_384): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=384, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_384_%d" % idx, new_test) - -# --- - -test_vectors_512 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_512.txt", - "Short Messages KAT 512", - {"len": lambda x: int(x)}) or [] - -test_vectors_512 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_512.txt", - "Long Messages KAT 512", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_512): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=512, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_512_%d" % idx, new_test) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(KeccakTest) - tests += list_test_cases(KeccakVectors) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/__init__.py deleted file mode 100644 index c04a2a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# SelfTest/IO/__init__.py: Self-test for input/output module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for I/O""" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.IO import test_PKCS8; tests += test_PKCS8.get_tests(config=config) - from Crypto.SelfTest.IO import test_PBES; tests += test_PBES.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PBES.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PBES.py deleted file mode 100644 index 029e824..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PBES.py +++ /dev/null @@ -1,118 +0,0 @@ -# -# SelfTest/IO/test_PBES.py: Self-test for the _PBES module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.IO._PBES module""" - -import unittest - -from Crypto.IO._PBES import PBES2 - - -class TestPBES2(unittest.TestCase): - - def setUp(self): - self.ref = b"Test data" - self.passphrase = b"Passphrase" - - def test1(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test2(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA224AndAES128-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test3(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA256AndAES192-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test4(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA384AndAES256-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test5(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA512AndAES128-GCM') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test6(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA512-224AndAES192-GCM') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test7(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA3-256AndAES256-GCM') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test8(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES128-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test9(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES192-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test10(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES256-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(TestPBES2) - return listTests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PKCS8.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PKCS8.py deleted file mode 100644 index 3525796..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/IO/test_PKCS8.py +++ /dev/null @@ -1,459 +0,0 @@ -# -# SelfTest/IO/test_PKCS8.py: Self-test for the PKCS8 module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.IO.PKCS8 module""" - -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import * -from Crypto.IO import PKCS8 - -from Crypto.Util.asn1 import DerNull - -oid_key = '1.2.840.113549.1.1.1' - -# Original RSA key (in DER format) -# hexdump -v -e '32/1 "%02x" "\n"' key.der -clear_key=""" -308201ab020100025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf16 -0c951a870b71783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f0 -6fe20faeebb0c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d2 -5c08050203010001025a00afa09c70d528299b7552fe766b5d20f9a221d66938 -c3b68371d48515359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb -3a50b8e17ba297b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee89 -3f039395022d0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e8 -8dfbc3f7e0bb83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd7 -1f56ae7d973e08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3 -c24f022d0ac334eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec9 -4fcf16352f6b3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb03 -09920905c236d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5 -022d0cd88ed14fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa3 -7e2e93df3ff1a0fd3490111dcdbc4c -""" - -# Same key as above, wrapped in PKCS#8 but w/o password -# -# openssl pkcs8 -topk8 -inform DER -nocrypt -in key.der -outform DER -out keyp8.der -# hexdump -v -e '32/1 "%02x" "\n"' keyp8.der -wrapped_clear_key=""" -308201c5020100300d06092a864886f70d0101010500048201af308201ab0201 -00025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf160c951a870b71 -783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f06fe20faeebb0 -c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d25c0805020301 -0001025a00afa09c70d528299b7552fe766b5d20f9a221d66938c3b68371d485 -15359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb3a50b8e17ba2 -97b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee893f039395022d -0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e88dfbc3f7e0bb -83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd71f56ae7d973e -08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3c24f022d0ac3 -34eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec94fcf16352f6b -3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb0309920905c236 -d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5022d0cd88ed1 -4fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa37e2e93df3ff1 -a0fd3490111dcdbc4c -""" - -### -# -# The key above will now be encrypted with different algorithms. -# The password is always 'TestTest'. -# -# Each item in the wrapped_enc_keys list contains: -# * wrap algorithm -# * iteration count -# * Salt -# * IV -# * Expected result -### -wrapped_enc_keys = [] - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -v2 des3 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC', -2048, -"47EA7227D8B22E2F", # IV -"E3F7A838AB911A4D", # Salt -""" -30820216304006092a864886f70d01050d3033301b06092a864886f70d01050c -300e0408e3f7a838ab911a4d02020800301406082a864886f70d0307040847ea -7227d8b22e2f048201d0ea388b374d2d0e4ceb7a5139f850fdff274884a6e6c0 -64326e09d00dbba9018834edb5a51a6ae3d1806e6e91eebf33788ce71fee0637 -a2ebf58859dd32afc644110c390274a6128b50c39b8d907823810ec471bada86 -6f5b75d8ea04ad310fad2e73621696db8e426cd511ee93ec1714a1a7db45e036 -4bf20d178d1f16bbb250b32c2d200093169d588de65f7d99aad9ddd0104b44f1 -326962e1520dfac3c2a800e8a14f678dff2b3d0bb23f69da635bf2a643ac934e -219a447d2f4460b67149e860e54f365da130763deefa649c72b0dcd48966a2d3 -4a477444782e3e66df5a582b07bbb19778a79bd355074ce331f4a82eb966b0c4 -52a09eab6116f2722064d314ae433b3d6e81d2436e93fdf446112663cde93b87 -9c8be44beb45f18e2c78fee9b016033f01ecda51b9b142091fa69f65ab784d2c -5ad8d34be6f7f1464adfc1e0ef3f7848f40d3bdea4412758f2fcb655c93d8f4d -f6fa48fc5aa4b75dd1c017ab79ac9d737233a6d668f5364ccf47786debd37334 -9c10c9e6efbe78430a61f71c89948aa32cdc3cc7338cf994147819ce7ab23450 -c8f7d9b94c3bb377d17a3fa204b601526317824b142ff6bc843fa7815ece89c0 -839573f234dac8d80cc571a045353d61db904a4398d8ef3df5ac -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithMD5AndDES-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d010503300e0408f9b990c89af1d41b020208 -00048201d0c6267fe8592903891933d559e71a7ca68b2e39150f19daca0f7921 -52f97e249d72f670d5140e9150433310ed7c7ee51927693fd39884cb9551cea5 -a7b746f7edf199f8787d4787a35dad930d7db057b2118851211b645ac8b90fa6 -b0e7d49ac8567cbd5fff226e87aa9129a0f52c45e9307752e8575c3b0ff756b7 -31fda6942d15ecb6b27ea19370ccc79773f47891e80d22b440d81259c4c28eac -e0ca839524116bcf52d8c566e49a95ddb0e5493437279a770a39fd333f3fca91 -55884fad0ba5aaf273121f893059d37dd417da7dcfd0d6fa7494968f13b2cc95 -65633f2c891340193e5ec00e4ee0b0e90b3b93da362a4906360845771ade1754 -9df79140be5993f3424c012598eadd3e7c7c0b4db2c72cf103d7943a5cf61420 -93370b9702386c3dd4eb0a47f34b579624a46a108b2d13921fa1b367495fe345 -6aa128aa70f8ca80ae13eb301e96c380724ce67c54380bbea2316c1faf4d058e -b4ca2e23442047606b9bc4b3bf65b432cb271bea4eb35dd3eb360d3be8612a87 -a50e96a2264490aeabdc07c6e78e5dbf4fe3388726d0e2a228346bf3c2907d68 -2a6276b22ae883fb30fa611f4e4193e7a08480fcd7db48308bacbd72bf4807aa -11fd394859f97d22982f7fe890b2e2a0f7e7ffb693 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-SHA1-RC2-64 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithSHA1AndRC2-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d01050b300e04083ee943bdae185008020208 -00048201d0e4614d9371d3ff10ceabc2f6a7a13a0f449f9a714144e46518ea55 -e3e6f0cde24031d01ef1f37ec40081449ef01914faf45983dde0d2bc496712de -8dd15a5527dff4721d9016c13f34fb93e3ce68577e30146266d71b539f854e56 -753a192cf126ed4812734d86f81884374f1100772f78d0646e9946407637c565 -d070acab413c55952f7237437f2e48cae7fa0ff8d370de2bf446dd08049a3663 -d9c813ac197468c02e2b687e7ca994cf7f03f01b6eca87dbfed94502c2094157 -ea39f73fe4e591df1a68b04d19d9adab90bb9898467c1464ad20bf2b8fb9a5ff -d3ec91847d1c67fd768a4b9cfb46572eccc83806601372b6fad0243f58f623b7 -1c5809dea0feb8278fe27e5560eed8448dc93f5612f546e5dd7c5f6404365eb2 -5bf3396814367ae8b15c5c432b57eaed1f882c05c7f6517ee9e42b87b7b8d071 -9d6125d1b52f7b2cca1f6bd5f584334bf90bce1a7d938274cafe27b68e629698 -b16e27ae528db28593af9adcfccbebb3b9e1f2af5cd5531b51968389caa6c091 -e7de1f1b96f0d258e54e540d961a7c0ef51fda45d6da5fddd33e9bbfd3a5f8d7 -d7ab2e971de495cddbc86d38444fee9f0ac097b00adaf7802dabe0cff5b43b45 -4f26b7b547016f89be52676866189911c53e2f2477""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-MD5-RC2-64 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithMD5AndRC2-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d010506300e0408f5cd2fee56d9b4b8020208 -00048201d086454942d6166a19d6b108465bd111e7080911f573d54b1369c676 -df28600e84936bfec04f91023ff16499e2e07178c340904f12ffa6886ab66228 -32bf43c2bff5a0ed14e765918cf5fc543ad49566246f7eb3fc044fa5a9c25f40 -8fc8c8296b91658d3bb1067c0aba008c4fefd9e2bcdbbbd63fdc8085482bccf4 -f150cec9a084259ad441a017e5d81a1034ef2484696a7a50863836d0eeda45cd -8cee8ecabfed703f8d9d4bbdf3a767d32a0ccdc38550ee2928d7fe3fa27eda5b -5c7899e75ad55d076d2c2d3c37d6da3d95236081f9671dab9a99afdb1cbc890e -332d1a91105d9a8ce08b6027aa07367bd1daec3059cb51f5d896124da16971e4 -0ca4bcadb06c854bdf39f42dd24174011414e51626d198775eff3449a982df7b -ace874e77e045eb6d7c3faef0750792b29a068a6291f7275df1123fac5789c51 -27ace42836d81633faf9daf38f6787fff0394ea484bbcd465b57d4dbee3cf8df -b77d1db287b3a6264c466805be5a4fe85cfbca180699859280f2dd8e2c2c10b5 -7a7d2ac670c6039d41952fbb0e4f99b560ebe1d020e1b96d02403283819c00cc -529c51f0b0101555e4c58002ba3c6e3c12e3fde1aec94382792e96d9666a2b33 -3dc397b22ecab67ee38a552fec29a1d4ff8719c748""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-SHA1-DES -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithSHA1AndDES-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d01050a300e04089bacc9cf1e8f734e020208 -00048201d03e502f3ceafe8fd19ab2939576bfdded26d719b2441db1459688f5 -9673218b41ec1f739edf1e460bd927bc28470c87b2d4fc8ea02ba17b47a63c49 -c5c1bee40529dadfd3ef8b4472c730bc136678c78abfb34670ec9d7dcd17ee3f -892f93f2629e6e0f4b24ecb9f954069bf722f466dece3913bb6abbd2c471d9a5 -c5eea89b14aaccda43d30b0dd0f6eb6e9850d9747aa8aa8414c383ad01c374ee -26d3552abec9ba22669cc9622ccf2921e3d0c8ecd1a70e861956de0bec6104b5 -b649ac994970c83f8a9e84b14a7dff7843d4ca3dd4af87cea43b5657e15ae0b5 -a940ce5047f006ab3596506600724764f23757205fe374fee04911336d655acc -03e159ec27789191d1517c4f3f9122f5242d44d25eab8f0658cafb928566ca0e -8f6589aa0c0ab13ca7a618008ae3eafd4671ee8fe0b562e70b3623b0e2a16eee -97fd388087d2e03530c9fe7db6e52eccc7c48fd701ede35e08922861a9508d12 -bc8bbf24f0c6bee6e63dbcb489b603d4c4a78ce45bf2eab1d5d10456c42a65a8 -3a606f4e4b9b46eb13b57f2624b651859d3d2d5192b45dbd5a2ead14ff20ca76 -48f321309aa56d8c0c4a192b580821cc6c70c75e6f19d1c5414da898ec4dd39d -b0eb93d6ba387a80702dfd2db610757ba340f63230 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes128 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES128-CBC', -2048, -"4F66EE5D3BCD531FE6EBF4B4E73016B8", # IV -"479F25156176C53A", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e0408479f25156176c53a02020800301d060960864801650304010204104f -66ee5d3bcd531fe6ebf4b4e73016b8048201d0e33cfa560423f589d097d21533 -3b880a5ebac5b2ac58b4e73b0d787aee7764f034fe34ca1d1bd845c0a7c3316f -afbfb2129e03dcaf5a5031394206492828dacef1e04639bee5935e0f46114202 -10bc6c37182f4889be11c5d0486c398f4be952e5740f65de9d8edeb275e2b406 -e19bc29ad5ebb97fa536344fc3d84c7e755696f12b810898de4e6f069b8a81c8 -0aab0d45d7d062303aaa4a10c2ce84fdb5a03114039cfe138e38bb15b2ced717 -93549cdad85e730b14d9e2198b663dfdc8d04a4349eb3de59b076ad40b116d4a -25ed917c576bc7c883c95ef0f1180e28fc9981bea069594c309f1aa1b253ceab -a2f0313bb1372bcb51a745056be93d77a1f235a762a45e8856512d436b2ca0f7 -dd60fbed394ba28978d2a2b984b028529d0a58d93aba46c6bbd4ac1e4013cbaa -63b00988bc5f11ccc40141c346762d2b28f64435d4be98ec17c1884985e3807e -e550db606600993efccf6de0dfc2d2d70b5336a3b018fa415d6bdd59f5777118 -16806b7bc17c4c7e20ad7176ebfa5a1aa3f6bc10f04b77afd443944642ac9cca -d740e082b4a3bbb8bafdd34a0b3c5f2f3c2aceccccdccd092b78994b845bfa61 -706c3b9df5165ed1dbcbf1244fe41fc9bf993f52f7658e2f87e1baaeacb0f562 -9d905c -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes192 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES192-CBC', -2048, -"5CFC2A4FF7B63201A4A8A5B021148186", # IV -"D718541C264944CE", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e0408d718541c264944ce02020800301d060960864801650304011604105c -fc2a4ff7b63201a4a8a5b021148186048201d08e74aaa21b8bcfb15b9790fe95 -b0e09ddb0f189b6fb1682fdb9f122b804650ddec3c67a1df093a828b3e5fbcc6 -286abbcc5354c482fd796d972e919ca8a5eba1eaa2293af1d648013ddad72106 -75622264dfba55dafdda39e338f058f1bdb9846041ffff803797d3fdf3693135 -8a192729ea8346a7e5e58e925a2e2e4af0818581859e8215d87370eb4194a5ff -bae900857d4c591dbc651a241865a817eaede9987c9f9ae4f95c0bf930eea88c -4d7596e535ffb7ca369988aba75027a96b9d0bc9c8b0b75f359067fd145a378b -02aaa15e9db7a23176224da48a83249005460cc6e429168657f2efa8b1af7537 -d7d7042f2d683e8271b21d591090963eeb57aea6172f88da139e1614d6a7d1a2 -1002d5a7a93d6d21156e2b4777f6fc069287a85a1538c46b7722ccde591ab55c -630e1ceeb1ac42d1b41f3f654e9da86b5efced43775ea68b2594e50e4005e052 -0fe753c0898120c2c07265367ff157f6538a1e4080d6f9d1ca9eb51939c9574e -f2e4e1e87c1434affd5808563cddd376776dbbf790c6a40028f311a8b58dafa2 -0970ed34acd6e3e89d063987893b2b9570ddb8cc032b05a723bba9444933ebf3 -c624204be72f4190e0245197d0cb772bec933fd8442445f9a28bd042d5a3a1e9 -9a8a07 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes192 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES256-CBC', -2048, -"323351F94462AC563E053A056252C2C4", # IV -"02A6CD0D12E727B5", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e040802a6cd0d12e727b502020800301d060960864801650304012a041032 -3351f94462ac563e053a056252c2c4048201d07f4ef1c7be21aae738a20c5632 -b8bdbbb9083b6e7f68822267b1f481fd27fdafd61a90660de6e4058790e4c912 -bf3f319a7c37e6eb3d956daaa143865020d554bf6215e8d7492359aaeef45d6e -d85a686ed26c0bf7c18d071d827a86f0b73e1db0c0e7f3d42201544093302a90 -551ad530692468c47ac15c69500b8ca67d4a17b64d15cecc035ae50b768a36cf -07c395afa091e9e6f86f665455fbdc1b21ad79c0908b73da5de75a9b43508d5d -44dc97a870cd3cd9f01ca24452e9b11c1b4982946702cfcbfda5b2fcc0203fb5 -0b52a115760bd635c94d4c95ac2c640ee9a04ffaf6ccff5a8d953dd5d88ca478 -c377811c521f2191639c643d657a9e364af88bb7c14a356c2b0b4870a23c2f54 -d41f8157afff731471dccc6058b15e1151bcf84b39b5e622a3a1d65859c912a5 -591b85e034a1f6af664f030a6bfc8c3d20c70f32b54bcf4da9c2da83cef49cf8 -e9a74f0e5d358fe50b88acdce6a9db9a7ad61536212fc5f877ebfc7957b8bda4 -b1582a0f10d515a20ee06cf768db9c977aa6fbdca7540d611ff953012d009dac -e8abd059f8e8ffea637c9c7721f817aaf0bb23403e26a0ef0ff0e2037da67d41 -af728481f53443551a9bff4cea023164e9622b5441a309e1f4bff98e5bf76677 -8d7cd9 -""" -)) - -# hexdump -v -e '32/1 "%02x" "\n"' botan_scrypt.der -botan_scrypt = """ -3081f1305206092a864886f70d01050d3045302806092b06010401da47040b30 -1b040c316c5c7a847276a838a668280202200002010102010102012030190609 -60864801650304012e040c293e9bcddc0d59d64e060cb604819ab92318063480 -16148081a3123bb092b636ec0cc3b964628e181504c13eaf94987e6fb9f171d4 -9c45baeeb79c1d805d5a762d9bfd6d1995669df60a2cd0174b6d204693964de7 -05bc3fdc3a4ce5db01f30a994c82b0aac786e4f8655138c952f1cf2cc6093f90 -b5e5ca507beb539ff497b7b6370ba7f31f4928d3385dbe8bcd2395813ba1324e -6795e81a8518aff0f0a9e01396539f937b8b7b08 -""" - -# hexdump -v -e '32/1 "%02x" "\n"' botan_pbkdf2.der -botan_pbkdf2 = """ -3081f3305e06092a864886f70d01050d3051303006092a864886f70d01050c30 -23040cc91c89b368db578d2ec4c32002020fa0020118300c06082a864886f70d -02090500301d060960864801650304011604102a7147289e7c914a7d8257e4a1 -a2135b048190a648955fc96ecae56dcb4d0ab19edc5b7ef1219c88c7c3b2d0ed -b21e25d2559447f53e20b90b2f20e72456d943561c4925aad6067a4c720afb3d -691e14dfffa10ef77898e21d134f19136d35088a7aac508b296fd00d5742ad69 -8c693293b6a591e3660b130d718724d23d696f4da9bf4031475fafb682d7955c -996363f37032e10ac85afebb7cc1cbfc0e5d4c60a4c2 -""" - -def txt2bin(inputs): - s = b('').join([b(x) for x in inputs if not (x in '\n\r\t ')]) - return unhexlify(s) - -class Rng: - def __init__(self, output): - self.output=output - self.idx=0 - def __call__(self, n): - output = self.output[self.idx:self.idx+n] - self.idx += n - return output - -class PKCS8_Decrypt(unittest.TestCase): - - def setUp(self): - self.oid_key = oid_key - self.clear_key = txt2bin(clear_key) - self.wrapped_clear_key = txt2bin(wrapped_clear_key) - self.wrapped_enc_keys = [] - for t in wrapped_enc_keys: - self.wrapped_enc_keys.append(( - t[0], - t[1], - txt2bin(t[2]), - txt2bin(t[3]), - txt2bin(t[4]) - )) - - ### NO ENCRYTION - - def test1(self): - """Verify unwrapping w/o encryption""" - res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key) - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - def test2(self): - """Verify wrapping w/o encryption""" - wrapped = PKCS8.wrap(self.clear_key, self.oid_key) - res1, res2, res3 = PKCS8.unwrap(wrapped) - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - ## ENCRYPTION - - def test3(self): - """Verify unwrapping with encryption""" - - for t in self.wrapped_enc_keys: - res1, res2, res3 = PKCS8.unwrap(t[4], b"TestTest") - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - def test4(self): - """Verify wrapping with encryption""" - - for t in self.wrapped_enc_keys: - if t[0] == 'skip encryption': - continue - rng = Rng(t[2]+t[3]) - params = { 'iteration_count':t[1] } - wrapped = PKCS8.wrap( - self.clear_key, - self.oid_key, - b("TestTest"), - protection=t[0], - prot_params=params, - key_params=DerNull(), - randfunc=rng) - self.assertEqual(wrapped, t[4]) - - def test_import_botan_keys(self): - botan_scrypt_der = txt2bin(botan_scrypt) - key1 = PKCS8.unwrap(botan_scrypt_der, - b'your_password') - botan_pbkdf2_der = txt2bin(botan_pbkdf2) - key2 = PKCS8.unwrap(botan_pbkdf2_der, - b'your_password') - self.assertEqual(key1, key2) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(PKCS8_Decrypt) - return listTests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/__init__.py deleted file mode 100644 index c72d7dc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# SelfTest/Math/__init__.py: Self-test for math module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math""" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Math import test_Numbers - from Crypto.SelfTest.Math import test_Primality - from Crypto.SelfTest.Math import test_modexp - from Crypto.SelfTest.Math import test_modmult - tests += test_Numbers.get_tests(config=config) - tests += test_Primality.get_tests(config=config) - tests += test_modexp.get_tests(config=config) - tests += test_modmult.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Numbers.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Numbers.py deleted file mode 100644 index a920bf1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Numbers.py +++ /dev/null @@ -1,838 +0,0 @@ -# -# SelfTest/Math/test_Numbers.py: Self-test for Numbers module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math.Numbers""" - -import sys -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.py3compat import * - -from Crypto.Math._IntegerNative import IntegerNative - - -class TestIntegerBase(unittest.TestCase): - - def setUp(self): - raise NotImplementedError("To be implemented") - - def Integers(self, *arg): - return map(self.Integer, arg) - - def test_init_and_equality(self): - Integer = self.Integer - - v1 = Integer(23) - v2 = Integer(v1) - v3 = Integer(-9) - self.assertRaises(ValueError, Integer, 1.0) - - v4 = Integer(10**10) - v5 = Integer(-10**10) - - v6 = Integer(0xFFFF) - v7 = Integer(0xFFFFFFFF) - v8 = Integer(0xFFFFFFFFFFFFFFFF) - - self.assertEqual(v1, v1) - self.assertEqual(v1, 23) - self.assertEqual(v1, v2) - self.assertEqual(v3, -9) - self.assertEqual(v4, 10 ** 10) - self.assertEqual(v5, -10 ** 10) - self.assertEqual(v6, 0xFFFF) - self.assertEqual(v7, 0xFFFFFFFF) - self.assertEqual(v8, 0xFFFFFFFFFFFFFFFF) - - self.assertFalse(v1 == v4) - - # Init and comparison between Integer's - v6 = Integer(v1) - self.assertEqual(v1, v6) - - self.assertFalse(Integer(0) == None) - - def test_conversion_to_int(self): - v1, v2 = self.Integers(-23, 2 ** 1000) - self.assertEqual(int(v1), -23) - self.assertEqual(int(v2), 2 ** 1000) - - def test_equality_with_ints(self): - v1, v2, v3 = self.Integers(23, -89, 2 ** 1000) - self.assertTrue(v1 == 23) - self.assertTrue(v2 == -89) - self.assertFalse(v1 == 24) - self.assertTrue(v3 == 2 ** 1000) - - def test_conversion_to_str(self): - v1, v2, v3, v4 = self.Integers(20, 0, -20, 2 ** 1000) - self.assertTrue(str(v1) == "20") - self.assertTrue(str(v2) == "0") - self.assertTrue(str(v3) == "-20") - self.assertTrue(str(v4) == "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376") - - def test_repr(self): - v1, v2 = self.Integers(-1, 2**80) - self.assertEqual(repr(v1), "Integer(-1)") - self.assertEqual(repr(v2), "Integer(1208925819614629174706176)") - - def test_conversion_to_bytes(self): - Integer = self.Integer - - v0 = Integer(0) - self.assertEqual(b"\x00", v0.to_bytes()) - - v1 = Integer(0x17) - self.assertEqual(b"\x17", v1.to_bytes()) - - v2 = Integer(0xFFFE) - self.assertEqual(b"\xFF\xFE", v2.to_bytes()) - self.assertEqual(b"\x00\xFF\xFE", v2.to_bytes(3)) - self.assertRaises(ValueError, v2.to_bytes, 1) - - self.assertEqual(b"\xFE\xFF", v2.to_bytes(byteorder='little')) - self.assertEqual(b"\xFE\xFF\x00", v2.to_bytes(3, byteorder='little')) - - v3 = Integer(0xFF00AABBCCDDEE1122) - self.assertEqual(b"\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22", v3.to_bytes()) - self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF", - v3.to_bytes(byteorder='little')) - self.assertEqual(b"\x00\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22", - v3.to_bytes(10)) - self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF\x00", - v3.to_bytes(10, byteorder='little')) - self.assertRaises(ValueError, v3.to_bytes, 8) - - v4 = Integer(-90) - self.assertRaises(ValueError, v4.to_bytes) - self.assertRaises(ValueError, v4.to_bytes, byteorder='bittle') - - def test_conversion_from_bytes(self): - Integer = self.Integer - - v1 = Integer.from_bytes(b"\x00") - self.assertTrue(isinstance(v1, Integer)) - self.assertEqual(0, v1) - - v2 = Integer.from_bytes(b"\x00\x01") - self.assertEqual(1, v2) - - v3 = Integer.from_bytes(b"\xFF\xFF") - self.assertEqual(0xFFFF, v3) - - v4 = Integer.from_bytes(b"\x00\x01", 'big') - self.assertEqual(1, v4) - - v5 = Integer.from_bytes(b"\x00\x01", byteorder='big') - self.assertEqual(1, v5) - - v6 = Integer.from_bytes(b"\x00\x01", byteorder='little') - self.assertEqual(0x0100, v6) - - self.assertRaises(ValueError, Integer.from_bytes, b'\x09', 'bittle') - - def test_inequality(self): - # Test Integer!=Integer and Integer!=int - v1, v2, v3, v4 = self.Integers(89, 89, 90, -8) - self.assertTrue(v1 != v3) - self.assertTrue(v1 != 90) - self.assertFalse(v1 != v2) - self.assertFalse(v1 != 89) - self.assertTrue(v1 != v4) - self.assertTrue(v4 != v1) - self.assertTrue(self.Integer(0) != None) - - def test_less_than(self): - # Test IntegerInteger and Integer>int - v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -8, 2 ** 10) - self.assertTrue(v3 > v1) - self.assertTrue(v3 > 13) - self.assertFalse(v1 > v1) - self.assertFalse(v1 > v2) - self.assertFalse(v1 > 13) - self.assertTrue(v1 > v4) - self.assertFalse(v4 > v1) - self.assertTrue(v5 > v1) - self.assertFalse(v1 > v5) - - def test_more_than_or_equal(self): - # Test Integer>=Integer and Integer>=int - v1, v2, v3, v4 = self.Integers(13, 13, 14, -4) - self.assertTrue(v3 >= v1) - self.assertTrue(v3 >= 13) - self.assertTrue(v1 >= v2) - self.assertTrue(v1 >= v1) - self.assertTrue(v1 >= 13) - self.assertFalse(v4 >= v1) - - def test_bool(self): - v1, v2, v3, v4 = self.Integers(0, 10, -9, 2 ** 10) - self.assertFalse(v1) - self.assertFalse(bool(v1)) - self.assertTrue(v2) - self.assertTrue(bool(v2)) - self.assertTrue(v3) - self.assertTrue(v4) - - def test_is_negative(self): - v1, v2, v3, v4, v5 = self.Integers(-3 ** 100, -3, 0, 3, 3**100) - self.assertTrue(v1.is_negative()) - self.assertTrue(v2.is_negative()) - self.assertFalse(v4.is_negative()) - self.assertFalse(v5.is_negative()) - - def test_addition(self): - # Test Integer+Integer and Integer+int - v1, v2, v3 = self.Integers(7, 90, -7) - self.assertTrue(isinstance(v1 + v2, self.Integer)) - self.assertEqual(v1 + v2, 97) - self.assertEqual(v1 + 90, 97) - self.assertEqual(v1 + v3, 0) - self.assertEqual(v1 + (-7), 0) - self.assertEqual(v1 + 2 ** 10, 2 ** 10 + 7) - - def test_subtraction(self): - # Test Integer-Integer and Integer-int - v1, v2, v3 = self.Integers(7, 90, -7) - self.assertTrue(isinstance(v1 - v2, self.Integer)) - self.assertEqual(v2 - v1, 83) - self.assertEqual(v2 - 7, 83) - self.assertEqual(v2 - v3, 97) - self.assertEqual(v1 - (-7), 14) - self.assertEqual(v1 - 2 ** 10, 7 - 2 ** 10) - - def test_multiplication(self): - # Test Integer-Integer and Integer-int - v1, v2, v3, v4 = self.Integers(4, 5, -2, 2 ** 10) - self.assertTrue(isinstance(v1 * v2, self.Integer)) - self.assertEqual(v1 * v2, 20) - self.assertEqual(v1 * 5, 20) - self.assertEqual(v1 * -2, -8) - self.assertEqual(v1 * 2 ** 10, 4 * (2 ** 10)) - - def test_floor_div(self): - v1, v2, v3 = self.Integers(3, 8, 2 ** 80) - self.assertTrue(isinstance(v1 // v2, self.Integer)) - self.assertEqual(v2 // v1, 2) - self.assertEqual(v2 // 3, 2) - self.assertEqual(v2 // -3, -3) - self.assertEqual(v3 // 2 ** 79, 2) - self.assertRaises(ZeroDivisionError, lambda: v1 // 0) - - def test_remainder(self): - # Test Integer%Integer and Integer%int - v1, v2, v3 = self.Integers(23, 5, -4) - self.assertTrue(isinstance(v1 % v2, self.Integer)) - self.assertEqual(v1 % v2, 3) - self.assertEqual(v1 % 5, 3) - self.assertEqual(v3 % 5, 1) - self.assertEqual(v1 % 2 ** 10, 23) - self.assertRaises(ZeroDivisionError, lambda: v1 % 0) - self.assertRaises(ValueError, lambda: v1 % -6) - - def test_simple_exponentiation(self): - v1, v2, v3 = self.Integers(4, 3, -2) - self.assertTrue(isinstance(v1 ** v2, self.Integer)) - self.assertEqual(v1 ** v2, 64) - self.assertEqual(pow(v1, v2), 64) - self.assertEqual(v1 ** 3, 64) - self.assertEqual(pow(v1, 3), 64) - self.assertEqual(v3 ** 2, 4) - self.assertEqual(v3 ** 3, -8) - - self.assertRaises(ValueError, pow, v1, -3) - - def test_modular_exponentiation(self): - v1, v2, v3 = self.Integers(23, 5, 17) - - self.assertTrue(isinstance(pow(v1, v2, v3), self.Integer)) - self.assertEqual(pow(v1, v2, v3), 7) - self.assertEqual(pow(v1, 5, v3), 7) - self.assertEqual(pow(v1, v2, 17), 7) - self.assertEqual(pow(v1, 5, 17), 7) - self.assertEqual(pow(v1, 0, 17), 1) - self.assertEqual(pow(v1, 1, 2 ** 80), 23) - self.assertEqual(pow(v1, 2 ** 80, 89298), 17689) - - self.assertRaises(ZeroDivisionError, pow, v1, 5, 0) - self.assertRaises(ValueError, pow, v1, 5, -4) - self.assertRaises(ValueError, pow, v1, -3, 8) - - def test_inplace_exponentiation(self): - v1 = self.Integer(4) - v1.inplace_pow(2) - self.assertEqual(v1, 16) - - v1 = self.Integer(4) - v1.inplace_pow(2, 15) - self.assertEqual(v1, 1) - - def test_abs(self): - v1, v2, v3, v4, v5 = self.Integers(-2 ** 100, -2, 0, 2, 2 ** 100) - self.assertEqual(abs(v1), 2 ** 100) - self.assertEqual(abs(v2), 2) - self.assertEqual(abs(v3), 0) - self.assertEqual(abs(v4), 2) - self.assertEqual(abs(v5), 2 ** 100) - - def test_sqrt(self): - v1, v2, v3, v4 = self.Integers(-2, 0, 49, 10**100) - - self.assertRaises(ValueError, v1.sqrt) - self.assertEqual(v2.sqrt(), 0) - self.assertEqual(v3.sqrt(), 7) - self.assertEqual(v4.sqrt(), 10**50) - - def test_sqrt_module(self): - - # Invalid modulus (non positive) - self.assertRaises(ValueError, self.Integer(5).sqrt, 0) - self.assertRaises(ValueError, self.Integer(5).sqrt, -1) - - # Simple cases - assert self.Integer(0).sqrt(5) == 0 - assert self.Integer(1).sqrt(5) in (1, 4) - - # Test with all quadratic residues in several fields - for p in (11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53): - for i in range(0, p): - square = i**2 % p - res = self.Integer(square).sqrt(p) - assert res in (i, p - i) - - # 2 is a non-quadratic reside in Z_11 - self.assertRaises(ValueError, self.Integer(2).sqrt, 11) - - # 10 is not a prime - self.assertRaises(ValueError, self.Integer(4).sqrt, 10) - - # 5 is square residue of 4 and 7 - assert self.Integer(5 - 11).sqrt(11) in (4, 7) - assert self.Integer(5 + 11).sqrt(11) in (4, 7) - - def test_in_place_add(self): - v1, v2 = self.Integers(10, 20) - - v1 += v2 - self.assertEqual(v1, 30) - v1 += 10 - self.assertEqual(v1, 40) - v1 += -1 - self.assertEqual(v1, 39) - v1 += 2 ** 1000 - self.assertEqual(v1, 39 + 2 ** 1000) - - def test_in_place_sub(self): - v1, v2 = self.Integers(10, 20) - - v1 -= v2 - self.assertEqual(v1, -10) - v1 -= -100 - self.assertEqual(v1, 90) - v1 -= 90000 - self.assertEqual(v1, -89910) - v1 -= -100000 - self.assertEqual(v1, 10090) - - def test_in_place_mul(self): - v1, v2 = self.Integers(3, 5) - - v1 *= v2 - self.assertEqual(v1, 15) - v1 *= 2 - self.assertEqual(v1, 30) - v1 *= -2 - self.assertEqual(v1, -60) - v1 *= 2 ** 1000 - self.assertEqual(v1, -60 * (2 ** 1000)) - - def test_in_place_modulus(self): - v1, v2 = self.Integers(20, 7) - - v1 %= v2 - self.assertEqual(v1, 6) - v1 %= 2 ** 1000 - self.assertEqual(v1, 6) - v1 %= 2 - self.assertEqual(v1, 0) - def t(): - v3 = self.Integer(9) - v3 %= 0 - self.assertRaises(ZeroDivisionError, t) - - def test_and(self): - v1, v2, v3 = self.Integers(0xF4, 0x31, -0xF) - self.assertTrue(isinstance(v1 & v2, self.Integer)) - self.assertEqual(v1 & v2, 0x30) - self.assertEqual(v1 & 0x31, 0x30) - self.assertEqual(v1 & v3, 0xF0) - self.assertEqual(v1 & -0xF, 0xF0) - self.assertEqual(v3 & -0xF, -0xF) - self.assertEqual(v2 & (2 ** 1000 + 0x31), 0x31) - - def test_or(self): - v1, v2, v3 = self.Integers(0x40, 0x82, -0xF) - self.assertTrue(isinstance(v1 | v2, self.Integer)) - self.assertEqual(v1 | v2, 0xC2) - self.assertEqual(v1 | 0x82, 0xC2) - self.assertEqual(v2 | v3, -0xD) - self.assertEqual(v2 | 2 ** 1000, 2 ** 1000 + 0x82) - - def test_right_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - self.assertEqual(v1 >> 0, v1) - self.assertTrue(isinstance(v1 >> v2, self.Integer)) - self.assertEqual(v1 >> v2, 0x08) - self.assertEqual(v1 >> 1, 0x08) - self.assertRaises(ValueError, lambda: v1 >> -1) - self.assertEqual(v1 >> (2 ** 1000), 0) - - self.assertEqual(v3 >> 1, -0x08) - self.assertEqual(v3 >> (2 ** 1000), -1) - - def test_in_place_right_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - v1 >>= 0 - self.assertEqual(v1, 0x10) - v1 >>= 1 - self.assertEqual(v1, 0x08) - v1 >>= v2 - self.assertEqual(v1, 0x04) - v3 >>= 1 - self.assertEqual(v3, -0x08) - def l(): - v4 = self.Integer(0x90) - v4 >>= -1 - self.assertRaises(ValueError, l) - def m1(): - v4 = self.Integer(0x90) - v4 >>= 2 ** 1000 - return v4 - self.assertEqual(0, m1()) - def m2(): - v4 = self.Integer(-1) - v4 >>= 2 ** 1000 - return v4 - self.assertEqual(-1, m2()) - - def _test_left_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - self.assertEqual(v1 << 0, v1) - self.assertTrue(isinstance(v1 << v2, self.Integer)) - self.assertEqual(v1 << v2, 0x20) - self.assertEqual(v1 << 1, 0x20) - self.assertEqual(v3 << 1, -0x20) - self.assertRaises(ValueError, lambda: v1 << -1) - self.assertRaises(ValueError, lambda: v1 << (2 ** 1000)) - - def test_in_place_left_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - v1 <<= 0 - self.assertEqual(v1, 0x10) - v1 <<= 1 - self.assertEqual(v1, 0x20) - v1 <<= v2 - self.assertEqual(v1, 0x40) - v3 <<= 1 - self.assertEqual(v3, -0x20) - def l(): - v4 = self.Integer(0x90) - v4 <<= -1 - self.assertRaises(ValueError, l) - def m(): - v4 = self.Integer(0x90) - v4 <<= 2 ** 1000 - self.assertRaises(ValueError, m) - - - def test_get_bit(self): - v1, v2, v3 = self.Integers(0x102, -3, 1) - self.assertEqual(v1.get_bit(0), 0) - self.assertEqual(v1.get_bit(1), 1) - self.assertEqual(v1.get_bit(v3), 1) - self.assertEqual(v1.get_bit(8), 1) - self.assertEqual(v1.get_bit(9), 0) - - self.assertRaises(ValueError, v1.get_bit, -1) - self.assertEqual(v1.get_bit(2 ** 1000), 0) - - self.assertRaises(ValueError, v2.get_bit, -1) - self.assertRaises(ValueError, v2.get_bit, 0) - self.assertRaises(ValueError, v2.get_bit, 1) - self.assertRaises(ValueError, v2.get_bit, 2 * 1000) - - def test_odd_even(self): - v1, v2, v3, v4, v5 = self.Integers(0, 4, 17, -4, -17) - - self.assertTrue(v1.is_even()) - self.assertTrue(v2.is_even()) - self.assertFalse(v3.is_even()) - self.assertTrue(v4.is_even()) - self.assertFalse(v5.is_even()) - - self.assertFalse(v1.is_odd()) - self.assertFalse(v2.is_odd()) - self.assertTrue(v3.is_odd()) - self.assertFalse(v4.is_odd()) - self.assertTrue(v5.is_odd()) - - def test_size_in_bits(self): - v1, v2, v3, v4 = self.Integers(0, 1, 0x100, -90) - self.assertEqual(v1.size_in_bits(), 1) - self.assertEqual(v2.size_in_bits(), 1) - self.assertEqual(v3.size_in_bits(), 9) - self.assertRaises(ValueError, v4.size_in_bits) - - def test_size_in_bytes(self): - v1, v2, v3, v4, v5, v6 = self.Integers(0, 1, 0xFF, 0x1FF, 0x10000, -9) - self.assertEqual(v1.size_in_bytes(), 1) - self.assertEqual(v2.size_in_bytes(), 1) - self.assertEqual(v3.size_in_bytes(), 1) - self.assertEqual(v4.size_in_bytes(), 2) - self.assertEqual(v5.size_in_bytes(), 3) - self.assertRaises(ValueError, v6.size_in_bits) - - def test_perfect_square(self): - - self.assertFalse(self.Integer(-9).is_perfect_square()) - self.assertTrue(self.Integer(0).is_perfect_square()) - self.assertTrue(self.Integer(1).is_perfect_square()) - self.assertFalse(self.Integer(2).is_perfect_square()) - self.assertFalse(self.Integer(3).is_perfect_square()) - self.assertTrue(self.Integer(4).is_perfect_square()) - self.assertTrue(self.Integer(39*39).is_perfect_square()) - self.assertFalse(self.Integer(39*39+1).is_perfect_square()) - - for x in range(100, 1000): - self.assertFalse(self.Integer(x**2+1).is_perfect_square()) - self.assertTrue(self.Integer(x**2).is_perfect_square()) - - def test_fail_if_divisible_by(self): - v1, v2, v3 = self.Integers(12, -12, 4) - - # No failure expected - v1.fail_if_divisible_by(7) - v2.fail_if_divisible_by(7) - v2.fail_if_divisible_by(2 ** 80) - - # Failure expected - self.assertRaises(ValueError, v1.fail_if_divisible_by, 4) - self.assertRaises(ValueError, v1.fail_if_divisible_by, v3) - - def test_multiply_accumulate(self): - v1, v2, v3 = self.Integers(4, 3, 2) - v1.multiply_accumulate(v2, v3) - self.assertEqual(v1, 10) - v1.multiply_accumulate(v2, 2) - self.assertEqual(v1, 16) - v1.multiply_accumulate(3, v3) - self.assertEqual(v1, 22) - v1.multiply_accumulate(1, -2) - self.assertEqual(v1, 20) - v1.multiply_accumulate(-2, 1) - self.assertEqual(v1, 18) - v1.multiply_accumulate(1, 2 ** 1000) - self.assertEqual(v1, 18 + 2 ** 1000) - v1.multiply_accumulate(2 ** 1000, 1) - self.assertEqual(v1, 18 + 2 ** 1001) - - def test_set(self): - v1, v2 = self.Integers(3, 6) - v1.set(v2) - self.assertEqual(v1, 6) - v1.set(9) - self.assertEqual(v1, 9) - v1.set(-2) - self.assertEqual(v1, -2) - v1.set(2 ** 1000) - self.assertEqual(v1, 2 ** 1000) - - def test_inverse(self): - v1, v2, v3, v4, v5, v6 = self.Integers(2, 5, -3, 0, 723872, 3433) - - self.assertTrue(isinstance(v1.inverse(v2), self.Integer)) - self.assertEqual(v1.inverse(v2), 3) - self.assertEqual(v1.inverse(5), 3) - self.assertEqual(v3.inverse(5), 3) - self.assertEqual(v5.inverse(92929921), 58610507) - self.assertEqual(v6.inverse(9912), 5353) - - self.assertRaises(ValueError, v2.inverse, 10) - self.assertRaises(ValueError, v1.inverse, -3) - self.assertRaises(ValueError, v4.inverse, 10) - self.assertRaises(ZeroDivisionError, v2.inverse, 0) - - def test_inplace_inverse(self): - v1, v2 = self.Integers(2, 5) - - v1.inplace_inverse(v2) - self.assertEqual(v1, 3) - - def test_gcd(self): - v1, v2, v3, v4 = self.Integers(6, 10, 17, -2) - self.assertTrue(isinstance(v1.gcd(v2), self.Integer)) - self.assertEqual(v1.gcd(v2), 2) - self.assertEqual(v1.gcd(10), 2) - self.assertEqual(v1.gcd(v3), 1) - self.assertEqual(v1.gcd(-2), 2) - self.assertEqual(v4.gcd(6), 2) - - def test_lcm(self): - v1, v2, v3, v4, v5 = self.Integers(6, 10, 17, -2, 0) - self.assertTrue(isinstance(v1.lcm(v2), self.Integer)) - self.assertEqual(v1.lcm(v2), 30) - self.assertEqual(v1.lcm(10), 30) - self.assertEqual(v1.lcm(v3), 102) - self.assertEqual(v1.lcm(-2), 6) - self.assertEqual(v4.lcm(6), 6) - self.assertEqual(v1.lcm(0), 0) - self.assertEqual(v5.lcm(0), 0) - - def test_jacobi_symbol(self): - - data = ( - (1001, 1, 1), - (19, 45, 1), - (8, 21, -1), - (5, 21, 1), - (610, 987, -1), - (1001, 9907, -1), - (5, 3439601197, -1) - ) - - js = self.Integer.jacobi_symbol - - # Jacobi symbol is always 1 for k==1 or n==1 - for k in range(1, 30): - self.assertEqual(js(k, 1), 1) - for n in range(1, 30, 2): - self.assertEqual(js(1, n), 1) - - # Fail if n is not positive odd - self.assertRaises(ValueError, js, 6, -2) - self.assertRaises(ValueError, js, 6, -1) - self.assertRaises(ValueError, js, 6, 0) - self.assertRaises(ValueError, js, 0, 0) - self.assertRaises(ValueError, js, 6, 2) - self.assertRaises(ValueError, js, 6, 4) - self.assertRaises(ValueError, js, 6, 6) - self.assertRaises(ValueError, js, 6, 8) - - for tv in data: - self.assertEqual(js(tv[0], tv[1]), tv[2]) - self.assertEqual(js(self.Integer(tv[0]), tv[1]), tv[2]) - self.assertEqual(js(tv[0], self.Integer(tv[1])), tv[2]) - - def test_jacobi_symbol_wikipedia(self): - - # Test vectors from https://en.wikipedia.org/wiki/Jacobi_symbol - tv = [ - (3, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), - (5, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 0), (6, 1), (7, -1), (8, -1), (9, 1), (10, 0), (11, 1), (12, -1), (13, -1), (14, 1), (15, 0), (16, 1), (17, -1), (18, -1), (19, 1), (20, 0), (21, 1), (22, -1), (23, -1), (24, 1), (25, 0), (26, 1), (27, -1), (28, -1), (29, 1), (30, 0)]), - (7, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, 0), (8, 1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, 0), (15, 1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, 0), (22, 1), (23, 1), (24, -1), (25, 1), (26, -1), (27, -1), (28, 0), (29, 1), (30, 1)]), - (9, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 1), (8, 1), (9, 0), (10, 1), (11, 1), (12, 0), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 1), (21, 0), (22, 1), (23, 1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 1), (29, 1), (30, 0)]), - (11, [(1, 1), (2, -1), (3, 1), (4, 1), (5, 1), (6, -1), (7, -1), (8, -1), (9, 1), (10, -1), (11, 0), (12, 1), (13, -1), (14, 1), (15, 1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 0), (23, 1), (24, -1), (25, 1), (26, 1), (27, 1), (28, -1), (29, -1), (30, -1)]), - (13, [(1, 1), (2, -1), (3, 1), (4, 1), (5, -1), (6, -1), (7, -1), (8, -1), (9, 1), (10, 1), (11, -1), (12, 1), (13, 0), (14, 1), (15, -1), (16, 1), (17, 1), (18, -1), (19, -1), (20, -1), (21, -1), (22, 1), (23, 1), (24, -1), (25, 1), (26, 0), (27, 1), (28, -1), (29, 1), (30, 1)]), - (15, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 0), (6, 0), (7, -1), (8, 1), (9, 0), (10, 0), (11, -1), (12, 0), (13, -1), (14, -1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 0), (21, 0), (22, -1), (23, 1), (24, 0), (25, 0), (26, -1), (27, 0), (28, -1), (29, -1), (30, 0)]), - (17, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, 1), (16, 1), (17, 0), (18, 1), (19, 1), (20, -1), (21, 1), (22, -1), (23, -1), (24, -1), (25, 1), (26, 1), (27, -1), (28, -1), (29, -1), (30, 1)]), - (19, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, -1), (15, -1), (16, 1), (17, 1), (18, -1), (19, 0), (20, 1), (21, -1), (22, -1), (23, 1), (24, 1), (25, 1), (26, 1), (27, -1), (28, 1), (29, -1), (30, 1)]), - (21, [(1, 1), (2, -1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 0), (8, -1), (9, 0), (10, -1), (11, -1), (12, 0), (13, -1), (14, 0), (15, 0), (16, 1), (17, 1), (18, 0), (19, -1), (20, 1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 0), (29, -1), (30, 0)]), - (23, [(1, 1), (2, 1), (3, 1), (4, 1), (5, -1), (6, 1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, 1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, -1), (22, -1), (23, 0), (24, 1), (25, 1), (26, 1), (27, 1), (28, -1), (29, 1), (30, -1)]), - (25, [(1, 1), (2, 1), (3, 1), (4, 1), (5, 0), (6, 1), (7, 1), (8, 1), (9, 1), (10, 0), (11, 1), (12, 1), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 1), (19, 1), (20, 0), (21, 1), (22, 1), (23, 1), (24, 1), (25, 0), (26, 1), (27, 1), (28, 1), (29, 1), (30, 0)]), - (27, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), - (29, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 1), (23, 1), (24, 1), (25, 1), (26, -1), (27, -1), (28, 1), (29, 0), (30, 1)]), - ] - - js = self.Integer.jacobi_symbol - - for n, kj in tv: - for k, j in kj: - self.assertEqual(js(k, n), j) - - def test_hex(self): - v1, = self.Integers(0x10) - self.assertEqual(hex(v1), "0x10") - - def test_mult_modulo_bytes(self): - modmult = self.Integer._mult_modulo_bytes - - res = modmult(4, 5, 19) - self.assertEqual(res, b'\x01') - - res = modmult(4 - 19, 5, 19) - self.assertEqual(res, b'\x01') - - res = modmult(4, 5 - 19, 19) - self.assertEqual(res, b'\x01') - - res = modmult(4 + 19, 5, 19) - self.assertEqual(res, b'\x01') - - res = modmult(4, 5 + 19, 19) - self.assertEqual(res, b'\x01') - - modulus = 2**512 - 1 # 64 bytes - t1 = 13**100 - t2 = 17**100 - expect = b"\xfa\xb2\x11\x87\xc3(y\x07\xf8\xf1n\xdepq\x0b\xca\xf3\xd3B,\xef\xf2\xfbf\xcc)\x8dZ*\x95\x98r\x96\xa8\xd5\xc3}\xe2q:\xa2'z\xf48\xde%\xef\t\x07\xbc\xc4[C\x8bUE2\x90\xef\x81\xaa:\x08" - self.assertEqual(expect, modmult(t1, t2, modulus)) - - self.assertRaises(ZeroDivisionError, modmult, 4, 5, 0) - self.assertRaises(ValueError, modmult, 4, 5, -1) - self.assertRaises(ValueError, modmult, 4, 5, 4) - - -class TestIntegerInt(TestIntegerBase): - - def setUp(self): - self.Integer = IntegerNative - - -class testIntegerRandom(unittest.TestCase): - - def test_random_exact_bits(self): - - for _ in range(1000): - a = IntegerNative.random(exact_bits=8) - self.assertFalse(a < 128) - self.assertFalse(a >= 256) - - for bits_value in range(1024, 1024 + 8): - a = IntegerNative.random(exact_bits=bits_value) - self.assertFalse(a < 2**(bits_value - 1)) - self.assertFalse(a >= 2**bits_value) - - def test_random_max_bits(self): - - flag = False - for _ in range(1000): - a = IntegerNative.random(max_bits=8) - flag = flag or a < 128 - self.assertFalse(a>=256) - self.assertTrue(flag) - - for bits_value in range(1024, 1024 + 8): - a = IntegerNative.random(max_bits=bits_value) - self.assertFalse(a >= 2**bits_value) - - def test_random_bits_custom_rng(self): - - class CustomRNG(object): - def __init__(self): - self.counter = 0 - - def __call__(self, size): - self.counter += size - return bchr(0) * size - - custom_rng = CustomRNG() - a = IntegerNative.random(exact_bits=32, randfunc=custom_rng) - self.assertEqual(custom_rng.counter, 4) - - def test_random_range(self): - - func = IntegerNative.random_range - - for x in range(200): - a = func(min_inclusive=1, max_inclusive=15) - self.assertTrue(1 <= a <= 15) - - for x in range(200): - a = func(min_inclusive=1, max_exclusive=15) - self.assertTrue(1 <= a < 15) - - self.assertRaises(ValueError, func, min_inclusive=1, max_inclusive=2, - max_exclusive=3) - self.assertRaises(ValueError, func, max_inclusive=2, max_exclusive=3) - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestIntegerInt) - - try: - from Crypto.Math._IntegerGMP import IntegerGMP - - class TestIntegerGMP(TestIntegerBase): - def setUp(self): - self.Integer = IntegerGMP - - tests += list_test_cases(TestIntegerGMP) - except (ImportError, OSError) as e: - if sys.platform == "win32": - sys.stdout.write("Skipping GMP tests on Windows\n") - else: - sys.stdout.write("Skipping GMP tests (%s)\n" % str(e) ) - - try: - from Crypto.Math._IntegerCustom import IntegerCustom - - class TestIntegerCustomModexp(TestIntegerBase): - def setUp(self): - self.Integer = IntegerCustom - - tests += list_test_cases(TestIntegerCustomModexp) - except (ImportError, OSError) as e: - sys.stdout.write("Skipping custom modexp tests (%s)\n" % str(e) ) - - tests += list_test_cases(testIntegerRandom) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Primality.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Primality.py deleted file mode 100644 index 38344f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_Primality.py +++ /dev/null @@ -1,118 +0,0 @@ -# -# SelfTest/Math/test_Primality.py: Self-test for Primality module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math.Numbers""" - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.py3compat import * - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import ( - PROBABLY_PRIME, COMPOSITE, - miller_rabin_test, lucas_test, - test_probable_prime, - generate_probable_prime, - generate_probable_safe_prime, - ) - - -class TestPrimality(unittest.TestCase): - - primes = (1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 2**127-1, 175637383534939453397801320455508570374088202376942372758907369518414308188137781042871856139027160010343454418881888953150175357127346872102307696660678617989191485418582475696230580407111841072614783095326672517315988762029036079794994990250662362650625650262324085116467511357592728695033227611029693067539) - composites = (0, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 7*23, (2**19-1)*(2**67-1), 9746347772161,) - - def test_miller_rabin(self): - for prime in self.primes: - self.assertEqual(miller_rabin_test(prime, 3), PROBABLY_PRIME) - for composite in self.composites: - self.assertEqual(miller_rabin_test(composite, 3), COMPOSITE) - self.assertRaises(ValueError, miller_rabin_test, -1, 3) - - def test_lucas(self): - for prime in self.primes: - res = lucas_test(prime) - self.assertEqual(res, PROBABLY_PRIME) - for composite in self.composites: - res = lucas_test(composite) - self.assertEqual(res, COMPOSITE) - self.assertRaises(ValueError, lucas_test, -1) - - def test_is_prime(self): - primes = (170141183460469231731687303715884105727, - 19175002942688032928599, - 1363005552434666078217421284621279933627102780881053358473, - 2 ** 521 - 1) - for p in primes: - self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) - - not_primes = ( - 4754868377601046732119933839981363081972014948522510826417784001, - 1334733877147062382486934807105197899496002201113849920496510541601, - 260849323075371835669784094383812120359260783810157225730623388382401, - ) - for np in not_primes: - self.assertEqual(test_probable_prime(np), COMPOSITE) - - from Crypto.Util.number import sieve_base - for p in sieve_base[:100]: - res = test_probable_prime(p) - self.assertEqual(res, PROBABLY_PRIME) - - def test_generate_prime_bit_size(self): - p = generate_probable_prime(exact_bits=512) - self.assertEqual(p.size_in_bits(), 512) - - def test_generate_prime_filter(self): - def ending_with_one(number): - return number % 10 == 1 - - for x in range(20): - q = generate_probable_prime(exact_bits=160, - prime_filter=ending_with_one) - self.assertEqual(q % 10, 1) - - def test_generate_safe_prime(self): - p = generate_probable_safe_prime(exact_bits=161) - self.assertEqual(p.size_in_bits(), 161) - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestPrimality) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modexp.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modexp.py deleted file mode 100644 index b9eb869..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modexp.py +++ /dev/null @@ -1,201 +0,0 @@ -# -# SelfTest/Math/test_modexp.py: Self-test for module exponentiation -# -# =================================================================== -# -# Copyright (c) 2017, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for the custom module exponentiation""" - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, - c_size_t, - c_ulonglong) - -from Crypto.Hash import SHAKE128 -from Crypto.Math.Numbers import Integer -from Crypto.Math._IntegerCustom import _raw_montgomery - -from Crypto.Random.random import StrongRandom - - -def create_rng(tag): - rng = StrongRandom(SHAKE128.new(data=tag)) - return rng - -class ExceptionModulus(ValueError): - pass - -def monty_pow(base, exp, modulus): - max_len = len(long_to_bytes(max(base, exp, modulus))) - - base_b, exp_b, modulus_b = [ long_to_bytes(x, max_len) for x in - (base, exp, modulus) ] - - out = create_string_buffer(max_len) - error = _raw_montgomery.monty_pow( - out, - base_b, - exp_b, - modulus_b, - c_size_t(max_len), - c_ulonglong(32) - ) - - if error == 17: - raise ExceptionModulus() - if error: - raise ValueError("monty_pow failed with error: %d" % error) - - result = bytes_to_long(get_raw_buffer(out)) - return result - -exponent1 = 0x2ce0af628901460a419a08ef950d498b9fd6f271a1a52ac293b86fe5c60efe8e8ba93fa1ebe1eb3d614d2e7b328cb60a2591440e163441a190ecf101ceec245f600fffdcf3f5b3a17a7baeacb96a424db1d7ec985e8ec998bb479fecfffed6a75f9a90fc97062fd973303bce855ad7b8d8272a94025e8532be9aabd54a183f303538d2a7e621b4131d59e823a4625f39bd7d518d7784f7c3a8f19061da74974ff42fa1c063dec2db97d461e291a7d6e721708a5229de166c1246363372854e27f3f08ae274bc16bfd205b028a4d81386494433d516dfbb35f495acba5e4e1d1843cb3c3129b6642a85fc7244ce5845fac071c7f622e4ee12ac43fabeeaa0cd01 -modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9 - - -class TestModExp(unittest.TestCase): - - def test_small(self): - self.assertEqual(1, monty_pow(11,12,19)) - - def test_large_1(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff - expected = pow(base, exponent1, modulus1) - result = monty_pow(base, exponent1, modulus1) - self.assertEqual(result, expected) - - def test_zero_exp(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff - result = monty_pow(base, 0, modulus1) - self.assertEqual(result, 1) - - def test_zero_base(self): - result = monty_pow(0, exponent1, modulus1) - self.assertEqual(result, 0) - - def test_zero_modulus(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffff - self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, 0) - self.assertRaises(ExceptionModulus, monty_pow, 0, 0, 0) - - def test_larger_exponent(self): - base = modulus1 - 0xFFFFFFF - expected = pow(base, modulus1<<64, modulus1) - result = monty_pow(base, modulus1<<64, modulus1) - self.assertEqual(result, expected) - - def test_even_modulus(self): - base = modulus1 >> 4 - self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, modulus1-1) - - def test_several_lengths(self): - prng = SHAKE128.new().update(b('Test')) - for length in range(1, 100): - modulus2 = Integer.from_bytes(prng.read(length)) | 1 - base = Integer.from_bytes(prng.read(length)) % modulus2 - exponent2 = Integer.from_bytes(prng.read(length)) - - expected = pow(base, exponent2, modulus2) - result = monty_pow(base, exponent2, modulus2) - self.assertEqual(result, expected) - - def test_variable_exponent(self): - prng = create_rng(b('Test variable exponent')) - for i in range(20): - for j in range(7): - modulus = prng.getrandbits(8*30) | 1 - base = prng.getrandbits(8*30) % modulus - exponent = prng.getrandbits(i*8+j) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - exponent ^= (1 << (i*8+j)) - 1 - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_63(self): - prng = create_rng(b('Test 63')) - length = 63 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_64(self): - prng = create_rng(b('Test 64')) - length = 64 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_65(self): - prng = create_rng(b('Test 65')) - length = 65 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestModExp) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modmult.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modmult.py deleted file mode 100644 index 66aa3cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Math/test_modmult.py +++ /dev/null @@ -1,120 +0,0 @@ -# -# SelfTest/Math/test_modmult.py: Self-test for custom modular multiplication -# -# =================================================================== -# -# Copyright (c) 2023, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for the custom modular multiplication""" - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Util._raw_api import (create_string_buffer, - get_raw_buffer, - c_size_t) - -from Crypto.Math._IntegerCustom import _raw_montgomery - - -class ExceptionModulus(ValueError): - pass - - -def monty_mult(term1, term2, modulus): - - if term1 >= modulus: - term1 %= modulus - if term2 >= modulus: - term2 %= modulus - - modulus_b = long_to_bytes(modulus) - numbers_len = len(modulus_b) - term1_b = long_to_bytes(term1, numbers_len) - term2_b = long_to_bytes(term2, numbers_len) - - out = create_string_buffer(numbers_len) - error = _raw_montgomery.monty_multiply( - out, - term1_b, - term2_b, - modulus_b, - c_size_t(numbers_len) - ) - - if error == 17: - raise ExceptionModulus() - if error: - raise ValueError("monty_multiply() failed with error: %d" % error) - - return get_raw_buffer(out) - - -modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9 - - -class TestModMultiply(unittest.TestCase): - - def test_small(self): - self.assertEqual(b"\x01", monty_mult(5, 6, 29)) - - def test_large(self): - numbers_len = (modulus1.bit_length() + 7) // 8 - - t1 = modulus1 // 2 - t2 = modulus1 - 90 - expect = b'\x00' * (numbers_len - 1) + b'\x2d' - self.assertEqual(expect, monty_mult(t1, t2, modulus1)) - - def test_zero_term(self): - numbers_len = (modulus1.bit_length() + 7) // 8 - expect = b'\x00' * numbers_len - self.assertEqual(expect, monty_mult(0x100, 0, modulus1)) - self.assertEqual(expect, monty_mult(0, 0x100, modulus1)) - - def test_larger_term(self): - t1 = 2**2047 - expect_int = 0x8edf4071f78e3d7ba622cdbbbef74612e301d69186776ae6bf87ff38c320d9aebaa64889c2f67de2324e6bccd2b10ad89e91fd21ba4bb523904d033eff5e70e62f01a84f41fa90a4f248ef249b82e1d2729253fdfc2a3b5b740198123df8bfbf7057d03e15244ad5f26eb9a099763b5c5972121ec076b0bf899f59bd95f7cc129abddccf24217bce52ca0f3a44c9ccc504765dbb89734205f3ae6a8cc560494a60ea84b27d8e00fa24bdd5b4f1d4232edb61e47d3d984c1fa50a3820a2e580fbc3fc8bc11e99df53b9efadf5a40ac75d384e400905aa6f1d88950cd53b1c54dc2222115ad84a27260fa4d978155c1434c551de1ee7361a17a2f79d4388f78a5d - res = bytes_to_long(monty_mult(t1, t1, modulus1)) - self.assertEqual(res, expect_int) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestModMultiply) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/__init__.py deleted file mode 100644 index c20cf2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# SelfTest/Protocol/__init__.py: Self-tests for Crypto.Protocol -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import sys - -"""Self-test for Crypto.Protocol""" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config) - from Crypto.SelfTest.Protocol import test_KDF; tests += test_KDF.get_tests(config=config) - from Crypto.SelfTest.Protocol import test_ecdh; tests += test_ecdh.get_tests(config=config) - - from Crypto.SelfTest.Protocol import test_SecretSharing - tests += test_SecretSharing.get_tests(config=config) - - if sys.version_info >= (3, 9): - from Crypto.SelfTest.Protocol import test_HPKE - tests += test_HPKE.get_tests(config=config) - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_HPKE.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_HPKE.py deleted file mode 100644 index ee6ae94..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_HPKE.py +++ /dev/null @@ -1,491 +0,0 @@ -import os -import json -import unittest -from binascii import unhexlify - -from Crypto.Protocol import HPKE -from Crypto.Protocol.HPKE import DeserializeError - -from Crypto.PublicKey import ECC -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Protocol import DH -from Crypto.Hash import SHA256, SHA384, SHA512 - - -class HPKE_Tests(unittest.TestCase): - - key1 = ECC.generate(curve='p256') - key2 = ECC.generate(curve='p256') - - # name, size of enc - curves = { - 'p256': 65, - 'p384': 97, - 'p521': 133, - 'curve25519': 32, - 'curve448': 56, - } - - def round_trip(self, curve, aead_id): - key1 = ECC.generate(curve=curve) - aead_id = aead_id - - encryptor = HPKE.new(receiver_key=key1.public_key(), - aead_id=aead_id) - self.assertEqual(len(encryptor.enc), self.curves[curve]) - - # First message - ct = encryptor.seal(b'ABC', auth_data=b'DEF') - - decryptor = HPKE.new(receiver_key=key1, - aead_id=aead_id, - enc=encryptor.enc) - - pt = decryptor.unseal(ct, auth_data=b'DEF') - self.assertEqual(b'ABC', pt) - - # Second message - ct2 = encryptor.seal(b'GHI') - pt2 = decryptor.unseal(ct2) - self.assertEqual(b'GHI', pt2) - - def test_round_trip(self): - for curve in self.curves.keys(): - for aead_id in HPKE.AEAD: - self.round_trip(curve, aead_id) - - def test_psk(self): - aead_id = HPKE.AEAD.AES128_GCM - HPKE.new(receiver_key=self.key1.public_key(), - aead_id=aead_id, - psk=(b'a', b'c' * 32)) - - def test_info(self): - aead_id = HPKE.AEAD.AES128_GCM - HPKE.new(receiver_key=self.key1.public_key(), - aead_id=aead_id, - info=b'baba') - - def test_neg_unsupported_curve(self): - key3 = ECC.generate(curve='p224') - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=key3.public_key(), - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("Unsupported curve", str(cm.exception)) - - def test_neg_too_many_private_keys(self): - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1, - sender_key=self.key2, - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("Exactly 1 private key", str(cm.exception)) - - def test_neg_curve_mismatch(self): - key3 = ECC.generate(curve='p384') - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1.public_key(), - sender_key=key3, - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("but recipient key", str(cm.exception)) - - def test_neg_psk(self): - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1.public_key(), - psk=(b'', b'G' * 32), - aead_id=HPKE.AEAD.AES128_GCM) - - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1.public_key(), - psk=(b'JJJ', b''), - aead_id=HPKE.AEAD.AES128_GCM) - - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1.public_key(), - psk=(b'JJJ', b'Y' * 31), - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("at least 32", str(cm.exception)) - - def test_neg_wrong_enc(self): - wrong_enc = b'\xFF' + b'8' * 64 - with self.assertRaises(DeserializeError): - HPKE.new(receiver_key=self.key1, - aead_id=HPKE.AEAD.AES128_GCM, - enc=wrong_enc) - - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1.public_key(), - enc=self.key1.public_key().export_key(format='raw'), - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("'enc' cannot be an input", str(cm.exception)) - - with self.assertRaises(ValueError) as cm: - HPKE.new(receiver_key=self.key1, - aead_id=HPKE.AEAD.AES128_GCM) - self.assertIn("'enc' required", str(cm.exception)) - - def test_neg_unseal_wrong_ct(self): - decryptor = HPKE.new(receiver_key=self.key1, - aead_id=HPKE.AEAD.CHACHA20_POLY1305, - enc=self.key2.public_key().export_key(format='raw')) - - with self.assertRaises(ValueError): - decryptor.unseal(b'XYZ' * 20) - - def test_neg_unseal_no_auth_data(self): - aead_id = HPKE.AEAD.CHACHA20_POLY1305 - - encryptor = HPKE.new(receiver_key=self.key1.public_key(), - aead_id=aead_id) - - ct = encryptor.seal(b'ABC', auth_data=b'DEF') - - decryptor = HPKE.new(receiver_key=self.key1, - aead_id=aead_id, - enc=encryptor.enc) - - with self.assertRaises(ValueError): - decryptor.unseal(ct) - - def test_x25519_mode_0(self): - # RFC x9180, A.1.1.1, seq 0 and 1 - - keyR_hex = "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8" - keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) - - pt_hex = "4265617574792069732074727574682c20747275746820626561757479" - pt = bytes.fromhex(pt_hex) - - ct0_hex = "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a" - ct0 = bytes.fromhex(ct0_hex) - - enc_hex = "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431" - enc = bytes.fromhex(enc_hex) - - aad0_hex = "436f756e742d30" - aad0 = bytes.fromhex(aad0_hex) - - aad1_hex = "436f756e742d31" - aad1 = bytes.fromhex(aad1_hex) - - info_hex = "4f6465206f6e2061204772656369616e2055726e" - info = bytes.fromhex(info_hex) - - ct1_hex = "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84" - ct1 = bytes.fromhex(ct1_hex) - - aead_id = HPKE.AEAD.AES128_GCM - - decryptor = HPKE.new(receiver_key=keyR, - aead_id=aead_id, - info=info, - enc=enc) - - pt_X0 = decryptor.unseal(ct0, aad0) - self.assertEqual(pt_X0, pt) - - pt_X1 = decryptor.unseal(ct1, aad1) - self.assertEqual(pt_X1, pt) - - def test_x25519_mode_1(self): - # RFC x9180, A.1.2.1, seq 0 and 1 - - keyR_hex = "c5eb01eb457fe6c6f57577c5413b931550a162c71a03ac8d196babbd4e5ce0fd" - keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) - - psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961" - psk_id = bytes.fromhex(psk_id_hex) - - psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82" - psk = bytes.fromhex(psk_hex) - - pt_hex = "4265617574792069732074727574682c20747275746820626561757479" - pt = bytes.fromhex(pt_hex) - - ct0_hex = "e52c6fed7f758d0cf7145689f21bc1be6ec9ea097fef4e959440012f4feb73fb611b946199e681f4cfc34db8ea" - ct0 = bytes.fromhex(ct0_hex) - - enc_hex = "0ad0950d9fb9588e59690b74f1237ecdf1d775cd60be2eca57af5a4b0471c91b" - enc = bytes.fromhex(enc_hex) - - aad0_hex = "436f756e742d30" - aad0 = bytes.fromhex(aad0_hex) - - aad1_hex = "436f756e742d31" - aad1 = bytes.fromhex(aad1_hex) - - info_hex = "4f6465206f6e2061204772656369616e2055726e" - info = bytes.fromhex(info_hex) - - ct1_hex = "49f3b19b28a9ea9f43e8c71204c00d4a490ee7f61387b6719db765e948123b45b61633ef059ba22cd62437c8ba" - ct1 = bytes.fromhex(ct1_hex) - - aead_id = HPKE.AEAD.AES128_GCM - - decryptor = HPKE.new(receiver_key=keyR, - aead_id=aead_id, - info=info, - psk=(psk_id, psk), - enc=enc) - - pt_X0 = decryptor.unseal(ct0, aad0) - self.assertEqual(pt_X0, pt) - - pt_X1 = decryptor.unseal(ct1, aad1) - self.assertEqual(pt_X1, pt) - - def test_x25519_mode_2(self): - # RFC x9180, A.1.3.1, seq 0 and 1 - - keyR_hex = "fdea67cf831f1ca98d8e27b1f6abeb5b7745e9d35348b80fa407ff6958f9137e" - keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) - - keyS_hex = "dc4a146313cce60a278a5323d321f051c5707e9c45ba21a3479fecdf76fc69dd" - keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex)) - - pt_hex = "4265617574792069732074727574682c20747275746820626561757479" - pt = bytes.fromhex(pt_hex) - - ct0_hex = "5fd92cc9d46dbf8943e72a07e42f363ed5f721212cd90bcfd072bfd9f44e06b80fd17824947496e21b680c141b" - ct0 = bytes.fromhex(ct0_hex) - - enc_hex = "23fb952571a14a25e3d678140cd0e5eb47a0961bb18afcf85896e5453c312e76" - enc = bytes.fromhex(enc_hex) - - aad0_hex = "436f756e742d30" - aad0 = bytes.fromhex(aad0_hex) - - aad1_hex = "436f756e742d31" - aad1 = bytes.fromhex(aad1_hex) - - info_hex = "4f6465206f6e2061204772656369616e2055726e" - info = bytes.fromhex(info_hex) - - ct1_hex = "d3736bb256c19bfa93d79e8f80b7971262cb7c887e35c26370cfed62254369a1b52e3d505b79dd699f002bc8ed" - ct1 = bytes.fromhex(ct1_hex) - - aead_id = HPKE.AEAD.AES128_GCM - - decryptor = HPKE.new(receiver_key=keyR, - sender_key=keyS.public_key(), - aead_id=aead_id, - info=info, - enc=enc) - - pt_X0 = decryptor.unseal(ct0, aad0) - self.assertEqual(pt_X0, pt) - - pt_X1 = decryptor.unseal(ct1, aad1) - self.assertEqual(pt_X1, pt) - - def test_x25519_mode_3(self): - # RFC x9180, A.1.4.1, seq 0 and 1 - - keyR_hex = "cb29a95649dc5656c2d054c1aa0d3df0493155e9d5da6d7e344ed8b6a64a9423" - keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) - - keyS_hex = "fc1c87d2f3832adb178b431fce2ac77c7ca2fd680f3406c77b5ecdf818b119f4" - keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex)) - - psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961" - psk_id = bytes.fromhex(psk_id_hex) - - psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82" - psk = bytes.fromhex(psk_hex) - - pt_hex = "4265617574792069732074727574682c20747275746820626561757479" - pt = bytes.fromhex(pt_hex) - - ct0_hex = "a84c64df1e11d8fd11450039d4fe64ff0c8a99fca0bd72c2d4c3e0400bc14a40f27e45e141a24001697737533e" - ct0 = bytes.fromhex(ct0_hex) - - enc_hex = "820818d3c23993492cc5623ab437a48a0a7ca3e9639c140fe1e33811eb844b7c" - enc = bytes.fromhex(enc_hex) - - aad0_hex = "436f756e742d30" - aad0 = bytes.fromhex(aad0_hex) - - aad1_hex = "436f756e742d31" - aad1 = bytes.fromhex(aad1_hex) - - info_hex = "4f6465206f6e2061204772656369616e2055726e" - info = bytes.fromhex(info_hex) - - ct1_hex = "4d19303b848f424fc3c3beca249b2c6de0a34083b8e909b6aa4c3688505c05ffe0c8f57a0a4c5ab9da127435d9" - ct1 = bytes.fromhex(ct1_hex) - - aead_id = HPKE.AEAD.AES128_GCM - - decryptor = HPKE.new(receiver_key=keyR, - sender_key=keyS.public_key(), - aead_id=aead_id, - psk=(psk_id, psk), - info=info, - enc=enc) - - pt_X0 = decryptor.unseal(ct0, aad0) - self.assertEqual(pt_X0, pt) - - pt_X1 = decryptor.unseal(ct1, aad1) - self.assertEqual(pt_X1, pt) - - -class HPKE_TestVectors(unittest.TestCase): - - def setUp(self): - self.vectors = [] - try: - import pycryptodome_test_vectors # type: ignore - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(init_dir, "Protocol", "wycheproof", "HPKE-test-vectors.json") - with open(full_file_name, "r") as f: - self.vectors = json.load(f) - except (FileNotFoundError, ImportError): - print("\nWarning: skipping extended tests for HPKE (install pycryptodome-test-vectors)") - - def import_private_key(self, key_hex, kem_id): - key_bin = unhexlify(key_hex) - if kem_id == 0x0010: - return ECC.construct(curve='p256', d=int.from_bytes(key_bin, - byteorder="big")) - elif kem_id == 0x0011: - return ECC.construct(curve='p384', d=int.from_bytes(key_bin, - byteorder="big")) - elif kem_id == 0x0012: - return ECC.construct(curve='p521', d=int.from_bytes(key_bin, - byteorder="big")) - elif kem_id == 0x0020: - return DH.import_x25519_private_key(key_bin) - elif kem_id == 0x0021: - return DH.import_x448_private_key(key_bin) - - def test_hpke_encap(self): - """Test HPKE encapsulation using test vectors.""" - - if not self.vectors: - self.skipTest("No test vectors available") - - for idx, vector in enumerate(self.vectors): - - kem_id = vector["kem_id"] - kdf_id = vector["kdf_id"] - aead_id = vector["aead_id"] - - # No export-only pseudo-cipher - if aead_id == 0xffff: - continue - - # We support only one KDF per curve - supported_combi = { - (0x10, 0x1): SHA256, - (0x11, 0x2): SHA384, - (0x12, 0x3): SHA512, - (0x20, 0x1): SHA256, - (0x21, 0x3): SHA512, - } - hashmod = supported_combi.get((kem_id, kdf_id)) - if hashmod is None: - continue - - with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id): - - receiver_pub = self.import_private_key(vector["skRm"], - kem_id).public_key() - - sender_priv = None - if "skSm" in vector: - sender_priv = self.import_private_key(vector["skSm"], - kem_id) - - encap_key = self.import_private_key(vector["skEm"], kem_id) - - shared_secret, enc = HPKE.HPKE_Cipher._encap(receiver_pub, - kem_id, - hashmod, - sender_priv, - encap_key) - self.assertEqual(enc.hex(), vector["enc"]) - self.assertEqual(shared_secret, - unhexlify(vector["shared_secret"])) - - print(".", end="", flush=True) - - def test_hpke_unseal(self): - """Test HPKE encryption and decryption using test vectors.""" - - if not self.vectors: - self.skipTest("No test vectors available") - - for idx, vector in enumerate(self.vectors): - - kem_id = vector["kem_id"] - kdf_id = vector["kdf_id"] - aead_id = vector["aead_id"] - - # No export-only pseudo-cipher - if aead_id == 0xffff: - continue - - # We support only one KDF per curve - supported_combi = ( - (0x10, 0x1), - (0x11, 0x2), - (0x12, 0x3), - (0x20, 0x1), - (0x21, 0x3), - ) - if (kem_id, kdf_id) not in supported_combi: - continue - - with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id): - - receiver_priv = self.import_private_key(vector["skRm"], - kem_id) - - sender_pub = None - if "skSm" in vector: - sender_priv = self.import_private_key(vector["skSm"], - kem_id) - sender_pub = sender_priv.public_key() - - encap_key = unhexlify(vector["enc"]) - - psk = None - if "psk_id" in vector: - psk = unhexlify(vector["psk_id"]), unhexlify(vector["psk"]) - - receiver_hpke = HPKE.new(receiver_key=receiver_priv, - aead_id=HPKE.AEAD(aead_id), - enc=encap_key, - sender_key=sender_pub, - psk=psk, - info=unhexlify(vector["info"])) - - for encryption in vector['encryptions']: - - plaintext = unhexlify(encryption["pt"]) - ciphertext = unhexlify(encryption["ct"]) - aad = unhexlify(encryption["aad"]) - - # Decrypt (unseal) - decrypted = receiver_hpke.unseal(ciphertext, aad) - self.assertEqual(decrypted, plaintext, "Decryption failed") - - print(".", end="", flush=True) - - -def get_tests(config={}): - - tests = [] - tests += list_test_cases(HPKE_Tests) - - if config.get('slow_tests'): - tests += list_test_cases(HPKE_TestVectors) - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_KDF.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_KDF.py deleted file mode 100644 index 1b2aa54..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_KDF.py +++ /dev/null @@ -1,809 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Protocol/test_KDF.py: Self-test for key derivation functions -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import re -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import b, bchr - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof -from Crypto.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512 -from Crypto.Cipher import AES, DES3 - -from Crypto.Protocol.KDF import (PBKDF1, PBKDF2, _S2V, HKDF, scrypt, - bcrypt, bcrypt_check, - SP800_108_Counter) - -from Crypto.Protocol.KDF import _bcrypt_decode - - -def t2b(t): - if t is None: - return None - t2 = t.replace(" ", "").replace("\n", "") - return unhexlify(b(t2)) - - -class TestVector(object): - pass - - -class PBKDF1_Tests(unittest.TestCase): - - # List of tuples with test data. - # Each tuple is made up by: - # Item #0: a pass phrase - # Item #1: salt (8 bytes encoded in hex) - # Item #2: output key length - # Item #3: iterations to use - # Item #4: expected result (encoded in hex) - _testData = ( - # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf - ("password", "78578E5A5D63CB06", 16, 1000, "DC19847E05C64D2FAF10EBFB4A3D2A20"), - ) - - def test1(self): - v = self._testData[0] - res = PBKDF1(v[0], t2b(v[1]), v[2], v[3], SHA1) - self.assertEqual(res, t2b(v[4])) - - -class PBKDF2_Tests(unittest.TestCase): - - # List of tuples with test data. - # Each tuple is made up by: - # Item #0: a pass phrase - # Item #1: salt (encoded in hex) - # Item #2: output key length - # Item #3: iterations to use - # Item #4: hash module - # Item #5: expected result (encoded in hex) - _testData = ( - # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf - ("password","78578E5A5D63CB06",24,2048, SHA1, "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"), - # From RFC 6050 - ("password","73616c74", 20, 1, SHA1, "0c60c80f961f0e71f3a9b524af6012062fe037a6"), - ("password","73616c74", 20, 2, SHA1, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), - ("password","73616c74", 20, 4096, SHA1, "4b007901b765489abead49d926f721d065a429c1"), - ("passwordPASSWORDpassword","73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74", - 25, 4096, SHA1, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), - ( 'pass\x00word',"7361006c74",16,4096, SHA1, "56fa6aa75548099dcc37d7f03425e0c3"), - # From draft-josefsson-scrypt-kdf-01, Chapter 10 - ( 'passwd', '73616c74', 64, 1, SHA256, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), - ( 'Password', '4e61436c', 64, 80000, SHA256, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d"), - ) - - def test1(self): - # Test only for HMAC-SHA1 as PRF - - def prf_SHA1(p,s): - return HMAC.new(p,s,SHA1).digest() - - def prf_SHA256(p,s): - return HMAC.new(p,s,SHA256).digest() - - for i in range(len(self._testData)): - v = self._testData[i] - password = v[0] - salt = t2b(v[1]) - out_len = v[2] - iters = v[3] - hash_mod = v[4] - expected = t2b(v[5]) - - if hash_mod is SHA1: - res = PBKDF2(password, salt, out_len, iters) - self.assertEqual(res, expected) - - res = PBKDF2(password, salt, out_len, iters, prf_SHA1) - self.assertEqual(res, expected) - else: - res = PBKDF2(password, salt, out_len, iters, prf_SHA256) - self.assertEqual(res, expected) - - def test2(self): - # Verify that prf and hmac_hash_module are mutual exclusive - def prf_SHA1(p,s): - return HMAC.new(p,s,SHA1).digest() - - self.assertRaises(ValueError, PBKDF2, b("xxx"), b("yyy"), 16, 100, - prf=prf_SHA1, hmac_hash_module=SHA1) - - def test3(self): - # Verify that hmac_hash_module works like prf - - password = b("xxx") - salt = b("yyy") - - for hashmod in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512): - - pr1 = PBKDF2(password, salt, 16, 100, - prf=lambda p, s: HMAC.new(p,s,hashmod).digest()) - pr2 = PBKDF2(password, salt, 16, 100, hmac_hash_module=hashmod) - - self.assertEqual(pr1, pr2) - - def test4(self): - # Verify that PBKDF2 can take bytes or strings as password or salt - k1 = PBKDF2("xxx", b("yyy"), 16, 10) - k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) - self.assertEqual(k1, k2) - - k1 = PBKDF2(b("xxx"), "yyy", 16, 10) - k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) - self.assertEqual(k1, k2) - - -class S2V_Tests(unittest.TestCase): - - # Sequence of test vectors. - # Each test vector is made up by: - # Item #0: a tuple of strings - # Item #1: an AES key - # Item #2: the result - # Item #3: the cipher module S2V is based on - # Everything is hex encoded - _testData = [ - - # RFC5297, A.1 - ( - ( '101112131415161718191a1b1c1d1e1f2021222324252627', - '112233445566778899aabbccddee' ), - 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0', - '85632d07c6e8f37f950acd320a2ecc93', - AES - ), - - # RFC5297, A.2 - ( - ( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddcc'+ - 'bbaa99887766554433221100', - '102030405060708090a0', - '09f911029d74e35bd84156c5635688c0', - '7468697320697320736f6d6520706c61'+ - '696e7465787420746f20656e63727970'+ - '74207573696e67205349562d414553'), - '7f7e7d7c7b7a79787776757473727170', - '7bdb6e3b432667eb06f4d14bff2fbd0f', - AES - ), - - ] - - def test1(self): - """Verify correctness of test vector""" - for tv in self._testData: - s2v = _S2V.new(t2b(tv[1]), tv[3]) - for s in tv[0]: - s2v.update(t2b(s)) - result = s2v.derive() - self.assertEqual(result, t2b(tv[2])) - - def test2(self): - """Verify that no more than 127(AES) and 63(TDES) - components are accepted.""" - key = bchr(0) * 8 + bchr(255) * 8 - for module in (AES, DES3): - s2v = _S2V.new(key, module) - max_comps = module.block_size*8-1 - for i in range(max_comps): - s2v.update(b("XX")) - self.assertRaises(TypeError, s2v.update, b("YY")) - - -class HKDF_Tests(unittest.TestCase): - - # Test vectors from RFC5869, Appendix A - # Each tuple is made up by: - # Item #0: hash module - # Item #1: secret - # Item #2: salt - # Item #3: context - # Item #4: expected result - _test_vector = ( - ( - SHA256, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - "000102030405060708090a0b0c", - "f0f1f2f3f4f5f6f7f8f9", - 42, - "3cb25f25faacd57a90434f64d0362f2a" + - "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + - "34007208d5b887185865" - ), - ( - SHA256, - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f", - "606162636465666768696a6b6c6d6e6f" + - "707172737475767778797a7b7c7d7e7f" + - "808182838485868788898a8b8c8d8e8f" + - "909192939495969798999a9b9c9d9e9f" + - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", - 82, - "b11e398dc80327a1c8e7f78c596a4934" + - "4f012eda2d4efad8a050cc4c19afa97c" + - "59045a99cac7827271cb41c65e590e09" + - "da3275600c2f09b8367793a9aca3db71" + - "cc30c58179ec3e87c14c01d5c1f3434f" + - "1d87" - ), - ( - SHA256, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - None, - None, - 42, - "8da4e775a563c18f715f802a063c5a31" + - "b8a11f5c5ee1879ec3454e5f3c738d2d" + - "9d201395faa4b61a96c8" - ), - ( - SHA1, - "0b0b0b0b0b0b0b0b0b0b0b", - "000102030405060708090a0b0c", - "f0f1f2f3f4f5f6f7f8f9", - 42, - "085a01ea1b10f36933068b56efa5ad81" + - "a4f14b822f5b091568a9cdd4f155fda2" + - "c22e422478d305f3f896" - ), - ( - SHA1, - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f", - "606162636465666768696a6b6c6d6e6f" + - "707172737475767778797a7b7c7d7e7f" + - "808182838485868788898a8b8c8d8e8f" + - "909192939495969798999a9b9c9d9e9f" + - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", - 82, - "0bd770a74d1160f7c9f12cd5912a06eb" + - "ff6adcae899d92191fe4305673ba2ffe" + - "8fa3f1a4e5ad79f3f334b3b202b2173c" + - "486ea37ce3d397ed034c7f9dfeb15c5e" + - "927336d0441f4c4300e2cff0d0900b52" + - "d3b4" - ), - ( - SHA1, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - "", - "", - 42, - "0ac1af7002b3d761d1e55298da9d0506" + - "b9ae52057220a306e07b6b87e8df21d0" + - "ea00033de03984d34918" - ), - ( - SHA1, - "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", - None, - "", - 42, - "2c91117204d745f3500d636a62f64f0a" + - "b3bae548aa53d423b0d1f27ebba6f5e5" + - "673a081d70cce7acfc48" - ) - ) - - def test1(self): - for tv in self._test_vector: - secret, salt, info, exp = [ t2b(tv[x]) for x in (1,2,3,5) ] - key_len, hashmod = [ tv[x] for x in (4,0) ] - - output = HKDF(secret, key_len, salt, hashmod, 1, info) - self.assertEqual(output, exp) - - def test2(self): - ref = HKDF(b("XXXXXX"), 12, b("YYYY"), SHA1) - - # Same output, but this time split over 2 keys - key1, key2 = HKDF(b("XXXXXX"), 6, b("YYYY"), SHA1, 2) - self.assertEqual((ref[:6], ref[6:]), (key1, key2)) - - # Same output, but this time split over 3 keys - key1, key2, key3 = HKDF(b("XXXXXX"), 4, b("YYYY"), SHA1, 3) - self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) - - -class scrypt_Tests(unittest.TestCase): - - # Test vectors taken from - # https://tools.ietf.org/html/rfc7914 - # - password - # - salt - # - N - # - r - # - p - data = ( - ( - "", - "", - 16, # 2K - 1, - 1, - """ - 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 - f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 - fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 - e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 - """ - ), - ( - "password", - "NaCl", - 1024, # 1M - 8, - 16, - """ - fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe - 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 - 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da - c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 - """ - ), - ( - "pleaseletmein", - "SodiumChloride", - 16384, # 16M - 8, - 1, - """ - 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb - fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2 - d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 - e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87 - """ - ), - ( - "pleaseletmein", - "SodiumChloride", - 1048576, # 1G - 8, - 1, - """ - 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81 - ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47 - 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3 - 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4 - """ - ), - ) - - def setUp(self): - new_test_vectors = [] - for tv in self.data: - new_tv = TestVector() - new_tv.P = b(tv[0]) - new_tv.S = b(tv[1]) - new_tv.N = tv[2] - new_tv.r = tv[3] - new_tv.p = tv[4] - new_tv.output = t2b(tv[5]) - new_tv.dkLen = len(new_tv.output) - new_test_vectors.append(new_tv) - self.data = new_test_vectors - - def test2(self): - - for tv in self.data: - try: - output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p) - except ValueError as e: - if " 2 " in str(e) and tv.N >= 1048576: - import warnings - warnings.warn("Not enough memory to unit test scrypt() with N=1048576", RuntimeWarning) - continue - else: - raise e - self.assertEqual(output, tv.output) - - def test3(self): - ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1) - - # Same output, but this time split over 2 keys - key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2) - self.assertEqual((ref[:6], ref[6:]), (key1, key2)) - - # Same output, but this time split over 3 keys - key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3) - self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) - - -class bcrypt_Tests(unittest.TestCase): - - def test_negative_cases(self): - self.assertRaises(ValueError, bcrypt, b"1" * 73, 10) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 3) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 32) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"") - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1") - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1" * 17) - self.assertRaises(ValueError, bcrypt, b"1\x00" * 10, 4) - - def test_bytearray_mismatch(self): - ref = bcrypt("pwd", 4) - bcrypt_check("pwd", ref) - bref = bytearray(ref) - bcrypt_check("pwd", bref) - - wrong = ref[:-1] + bchr(bref[-1] ^ 0x01) - self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) - - wrong = b"x" + ref[1:] - self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) - - # https://github.com/patrickfav/bcrypt/wiki/Published-Test-Vectors - - def test_empty_password(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"", 4, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$04$zVHmKQtGGQob.b/Nc7l9NO8UlrYcW05FiuCj/SxsFO/ZtiN9.mNzy"), - (b"", 5, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$05$zVHmKQtGGQob.b/Nc7l9NOWES.1hkVBgy5IWImh9DOjKNU8atY4Iy"), - (b"", 6, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$06$zVHmKQtGGQob.b/Nc7l9NOjOl7l4oz3WSh5fJ6414Uw8IXRAUoiaO"), - (b"", 7, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$07$zVHmKQtGGQob.b/Nc7l9NOBsj1dQpBA1HYNGpIETIByoNX9jc.hOi"), - (b"", 8, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$08$zVHmKQtGGQob.b/Nc7l9NOiLTUh/9MDpX86/DLyEzyiFjqjBFePgO"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_random_password_and_salt_short_pw(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"<.S.2K(Zq'", 4, b"VYAclAMpaXY/oqAo9yUpku", b"$2a$04$VYAclAMpaXY/oqAo9yUpkuWmoYywaPzyhu56HxXpVltnBIfmO9tgu"), - (b"5.rApO%5jA", 5, b"kVNDrnYKvbNr5AIcxNzeIu", b"$2a$05$kVNDrnYKvbNr5AIcxNzeIuRcyIF5cZk6UrwHGxENbxP5dVv.WQM/G"), - (b"oW++kSrQW^", 6, b"QLKkRMH9Am6irtPeSKN5sO", b"$2a$06$QLKkRMH9Am6irtPeSKN5sObJGr3j47cO6Pdf5JZ0AsJXuze0IbsNm"), - (b"ggJ\\KbTnDG", 7, b"4H896R09bzjhapgCPS/LYu", b"$2a$07$4H896R09bzjhapgCPS/LYuMzAQluVgR5iu/ALF8L8Aln6lzzYXwbq"), - (b"49b0:;VkH/", 8, b"hfvO2retKrSrx5f2RXikWe", b"$2a$08$hfvO2retKrSrx5f2RXikWeFWdtSesPlbj08t/uXxCeZoHRWDz/xFe"), - (b">9N^5jc##'", 9, b"XZLvl7rMB3EvM0c1.JHivu", b"$2a$09$XZLvl7rMB3EvM0c1.JHivuIDPJWeNJPTVrpjZIEVRYYB/mF6cYgJK"), - (b"\\$ch)s4WXp", 10, b"aIjpMOLK5qiS9zjhcHR5TO", b"$2a$10$aIjpMOLK5qiS9zjhcHR5TOU7v2NFDmcsBmSFDt5EHOgp/jeTF3O/q"), - (b"RYoj\\_>2P7", 12, b"esIAHiQAJNNBrsr5V13l7.", b"$2a$12$esIAHiQAJNNBrsr5V13l7.RFWWJI2BZFtQlkFyiWXjou05GyuREZa"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_random_password_and_salt_long_pw(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"^Q&\"]A`%/A(BVGt>QaX0M-#1ghq_+\":Y0CRmY", 5, b"YuQvhokOGVnevctykUYpKu", b"$2a$05$YuQvhokOGVnevctykUYpKutZD2pWeGGYn3auyLOasguMY3/0BbIyq"), - (b"F%uN/j>[GuB7-jB'_Yj!Tnb7Y!u^6)", 6, b"5L3vpQ0tG9O7k5gQ8nAHAe", b"$2a$06$5L3vpQ0tG9O7k5gQ8nAHAe9xxQiOcOLh8LGcI0PLWhIznsDt.S.C6"), - (b"Z>BobP32ub\"Cfe*Q<-q-=tRSjOBh8\\mLNW.", 9, b"nArqOfdCsD9kIbVnAixnwe", b"$2a$09$nArqOfdCsD9kIbVnAixnwe6s8QvyPYWtQBpEXKir2OJF9/oNBsEFe"), - (b"/MH51`!BP&0tj3%YCA;Xk%e3S`o\\EI", 10, b"ePiAc.s.yoBi3B6p1iQUCe", b"$2a$10$ePiAc.s.yoBi3B6p1iQUCezn3mraLwpVJ5XGelVyYFKyp5FZn/y.u"), - (b"ptAP\"mcg6oH.\";c0U2_oll.OKi5?Ui\"^ai#iQH7ZFtNMfs3AROnIncE9\"BNNoEgO[[*Yk8;RQ(#S,;I+aT", - 5, b"wgkOlGNXIVE2fWkT3gyRoO", b"$2a$05$wgkOlGNXIVE2fWkT3gyRoOqWi4gbi1Wv2Q2Jx3xVs3apl1w.Wtj8C"), - (b"M.E1=dt<.L0Q&p;94NfGm_Oo23+Kpl@M5?WIAL.[@/:'S)W96G8N^AWb7_smmC]>7#fGoB", - 6, b"W9zTCl35nEvUukhhFzkKMe", b"$2a$06$W9zTCl35nEvUukhhFzkKMekjT9/pj7M0lihRVEZrX3m8/SBNZRX7i"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_increasing_password_length(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"a", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.l4WvgHIVg17ZawDIrDM2IjlE64GDNQS"), - (b"aa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.AyUxBk.ThHlsLvRTH7IqcG7yVHJ3SXq"), - (b"aaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.BxOVac5xPB6XFdRc/ZrzM9FgZkqmvbW"), - (b"aaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Qbr209bpCtfl5hN7UQlG/L4xiD3AKau"), - (b"aaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oWszihPjDZI0ypReKsaDOW1jBl7oOii"), - (b"aaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ./k.Xxn9YiqtV/sxh3EHbnOHd0Qsq27K"), - (b"aaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.PYJqRFQbgRbIjMd5VNKmdKS4sBVOyDe"), - (b"aaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ..VMYfzaw1wP/SGxowpLeGf13fxCCt.q"), - (b"aaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.5B0p054nO5WgAD1n04XslDY/bqY9RJi"), - (b"aaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.INBTgqm7sdlBJDg.J5mLMSRK25ri04y"), - (b"aaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.s3y7CdFD0OR5p6rsZw/eZ.Dla40KLfm"), - (b"aaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Jx742Djra6Q7PqJWnTAS.85c28g.Siq"), - (b"aaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oKMXW3EZcPHcUV0ib5vDBnh9HojXnLu"), - (b"aaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.w6nIjWpDPNSH5pZUvLjC1q25ONEQpeS"), - (b"aaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.k1b2/r9A/hxdwKEKurg6OCn4MwMdiGq"), - (b"aaaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.3prCNHVX1Ws.7Hm2bJxFUnQOX9f7DFa"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_non_ascii_characters(self): - # password, cost, salt, bcrypt hash - tvs = [ - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 4, b"D3qS2aoTVyqM7z8v8crLm.", b"$2a$04$D3qS2aoTVyqM7z8v8crLm.3nKt4CzBZJbyFB.ZebmfCvRw7BGs.Xm"), - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 5, b"VA1FujiOCMPkUHQ8kF7IaO", b"$2a$05$VA1FujiOCMPkUHQ8kF7IaOg7NGaNvpxwWzSluQutxEVmbZItRTsAa"), - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 6, b"TXiaNrPeBSz5ugiQlehRt.", b"$2a$06$TXiaNrPeBSz5ugiQlehRt.gwpeDQnXWteQL4z2FulouBr6G7D9KUi"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 4, b"YTn1Qlvps8e1odqMn6G5x.", b"$2a$04$YTn1Qlvps8e1odqMn6G5x.85pqKql6w773EZJAExk7/BatYAI4tyO"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 5, b"C.8k5vJKD2NtfrRI9o17DO", b"$2a$05$C.8k5vJKD2NtfrRI9o17DOfIW0XnwItA529vJnh2jzYTb1QdoY0py"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 6, b"xqfRPj3RYAgwurrhcA6uRO", b"$2a$06$xqfRPj3RYAgwurrhcA6uROtGlXDp/U6/gkoDYHwlubtcVcNft5.vW"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 4, b"y8vGgMmr9EdyxP9rmMKjH.", b"$2a$04$y8vGgMmr9EdyxP9rmMKjH.wv2y3r7yRD79gykQtmb3N3zrwjKsyay"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 5, b"iYH4XIKAOOm/xPQs7xKP1u", b"$2a$05$iYH4XIKAOOm/xPQs7xKP1upD0cWyMn3Jf0ZWiizXbEkVpS41K1dcO"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 6, b"wCOob.D0VV8twafNDB2ape", b"$2a$06$wCOob.D0VV8twafNDB2apegiGD5nqF6Y1e6K95q6Y.R8C4QGd265q"), - ("ΔημοσιεύθηκεστηνΕφημερίδατης", 4, b"E5SQtS6P4568MDXW7cyUp.", b"$2a$04$E5SQtS6P4568MDXW7cyUp.18wfDisKZBxifnPZjAI1d/KTYMfHPYO"), - ("АБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмН", 4, b"03e26gQFHhQwRNf81/ww9.", b"$2a$04$03e26gQFHhQwRNf81/ww9.p1UbrNwxpzWjLuT.zpTLH4t/w5WhAhC"), - ("нОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮю", 4, b"PHNoJwpXCfe32nUtLv2Upu", b"$2a$04$PHNoJwpXCfe32nUtLv2UpuhJXOzd4k7IdFwnEpYwfJVCZ/f/.8Pje"), - ("電电電島岛島兔兔兎龜龟亀國国国區区区", 4, b"wU4/0i1TmNl2u.1jIwBX.u", b"$2a$04$wU4/0i1TmNl2u.1jIwBX.uZUaOL3Rc5ID7nlQRloQh6q5wwhV/zLW"), - ("诶比伊艾弗豆贝尔维吾艾尺开艾丝维贼德", 4, b"P4kreGLhCd26d4WIy7DJXu", b"$2a$04$P4kreGLhCd26d4WIy7DJXusPkhxLvBouzV6OXkL5EB0jux0osjsry"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_special_case_salt(self): - # password, cost, salt, bcrypt hash - tvs = [ - ("-O_=*N!2JP", 4, b"......................", b"$2a$04$......................JjuKLOX9OOwo5PceZZXSkaLDvdmgb82"), - ("7B[$Q<4b>U", 5, b"......................", b"$2a$05$......................DRiedDQZRL3xq5A5FL8y7/6NM8a2Y5W"), - (">d5-I_8^.h", 6, b"......................", b"$2a$06$......................5Mq1Ng8jgDY.uHNU4h5p/x6BedzNH2W"), - (")V`/UM/]1t", 4, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$04$.OC/.OC/.OC/.OC/.OC/.OQIvKRDAam.Hm5/IaV/.hc7P8gwwIbmi"), - (":@t2.bWuH]", 5, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$05$.OC/.OC/.OC/.OC/.OC/.ONDbUvdOchUiKmQORX6BlkPofa/QxW9e"), - ("b(#KljF5s\"", 6, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$06$.OC/.OC/.OC/.OC/.OC/.OHfTd9e7svOu34vi1PCvOcAEq07ST7.K"), - ("@3YaJ^Xs]*", 4, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$04$eGA.eGA.eGA.eGA.eGA.e.stcmvh.R70m.0jbfSFVxlONdj1iws0C"), - ("'\"5\\!k*C(p", 5, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$05$eGA.eGA.eGA.eGA.eGA.e.vR37mVSbfdHwu.F0sNMvgn8oruQRghy"), - ("edEu7C?$'W", 6, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$06$eGA.eGA.eGA.eGA.eGA.e.tSq0FN8MWHQXJXNFnHTPQKtA.n2a..G"), - ("N7dHmg\\PI^", 4, b"999999999999999999999u", b"$2a$04$999999999999999999999uCZfA/pLrlyngNDMq89r1uUk.bQ9icOu"), - ("\"eJuHh!)7*", 5, b"999999999999999999999u", b"$2a$05$999999999999999999999uj8Pfx.ufrJFAoWFLjapYBS5vVEQQ/hK"), - ("ZeDRJ:_tu:", 6, b"999999999999999999999u", b"$2a$06$999999999999999999999u6RB0P9UmbdbQgjoQFEJsrvrKe.BoU6q"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - -class TestVectorsHKDFWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def add_tests(self, filename): - - def filter_algo(root): - algo_name = root['algorithm'] - if algo_name == "HKDF-SHA-1": - return SHA1 - elif algo_name == "HKDF-SHA-256": - return SHA256 - elif algo_name == "HKDF-SHA-384": - return SHA384 - elif algo_name == "HKDF-SHA-512": - return SHA512 - else: - raise ValueError("Unknown algorithm " + algo_name) - - def filter_size(unit): - return int(unit['size']) - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof HMAC (%s)" % filename, - root_tag={'hash_module': filter_algo}, - unit_tag={'size': filter_size}) - return result - - def setUp(self): - self.tv = [] - self.add_tests("hkdf_sha1_test.json") - self.add_tests("hkdf_sha256_test.json") - self.add_tests("hkdf_sha384_test.json") - self.add_tests("hkdf_sha512_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof HKDF Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - - try: - key = HKDF(tv.ikm, tv.size, tv.salt, tv.hash_module, 1, tv.info) - except ValueError: - assert not tv.valid - else: - if key != tv.okm: - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class SP800_108_Counter_Tests(unittest.TestCase): - - def test_negative_zeroes(self): - def prf(s, x): - return HMAC.new(s, x, SHA256).digest() - - try: - _ = SP800_108_Counter(b'0' * 16, 1, prf, label=b'A\x00B') - except ValueError: - self.fail('SP800_108_Counter failed with zero in label') - self.assertRaises(ValueError, SP800_108_Counter, b'0' * 16, 1, prf, - context=b'A\x00B') - - def test_multiple_keys(self): - def prf(s, x): - return HMAC.new(s, x, SHA256).digest() - - key = b'0' * 16 - expected = SP800_108_Counter(key, 2*3*23, prf) - for r in (1, 2, 3, 23): - dks = SP800_108_Counter(key, r, prf, 138//r) - self.assertEqual(len(dks), 138//r) - self.assertEqual(len(dks[0]), r) - self.assertEqual(b''.join(dks), expected) - - -def add_tests_sp800_108_counter(cls): - - test_vectors_sp800_108_counter = load_test_vectors(("Protocol", ), - "KDF_SP800_108_COUNTER.txt", - "NIST SP 800 108 KDF Counter Mode", - {'count': lambda x: int(x)}, - ) or [] - - mac_type = None - for idx, tv in enumerate(test_vectors_sp800_108_counter): - - if isinstance(tv, str): - res = re.match(r"\[HMAC-(SHA-[0-9]+)\]", tv) - if res: - hash_name = res.group(1).replace("-", "") - hash_module = load_hash_by_name(hash_name) - mac_type = "hmac" - continue - res = re.match(r"\[CMAC-AES-128\]", tv) - if res: - mac_type = "cmac" - continue - assert res - - if mac_type == "hmac": - def prf(s, x, hash_module=hash_module): - return HMAC.new(s, x, hash_module).digest() - elif mac_type == "cmac": - def prf(s, x, hash_module=hash_module): - return CMAC.new(s, x, AES).digest() - continue - - def kdf_test(self, prf=prf, kin=tv.kin, label=tv.label, - context=tv.context, kout=tv.kout, count=tv.count): - result = SP800_108_Counter(kin, len(kout), prf, 1, label, context) - assert(len(result) == len(kout)) - self.assertEqual(result, kout) - - setattr(cls, "test_kdf_sp800_108_counter_%d" % idx, kdf_test) - - -add_tests_sp800_108_counter(SP800_108_Counter_Tests) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - if not config.get('slow_tests'): - PBKDF2_Tests._testData = PBKDF2_Tests._testData[:3] - scrypt_Tests.data = scrypt_Tests.data[:3] - - tests = [] - tests += list_test_cases(PBKDF1_Tests) - tests += list_test_cases(PBKDF2_Tests) - tests += list_test_cases(S2V_Tests) - tests += list_test_cases(HKDF_Tests) - tests += [TestVectorsHKDFWycheproof(wycheproof_warnings)] - tests += list_test_cases(scrypt_Tests) - tests += list_test_cases(bcrypt_Tests) - tests += list_test_cases(SP800_108_Counter_Tests) - - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_SecretSharing.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_SecretSharing.py deleted file mode 100644 index b514b96..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_SecretSharing.py +++ /dev/null @@ -1,290 +0,0 @@ -# -# SelfTest/Protocol/test_secret_sharing.py: Self-test for secret sharing protocols -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from unittest import main, TestCase, TestSuite -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import * -from Crypto.Hash import SHAKE128 -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Protocol.SecretSharing import Shamir, _Element, \ - _mult_gf2, _div_gf2 - - -class GF2_Tests(TestCase): - - def test_mult_gf2(self): - # Prove mult by zero - x = _mult_gf2(0,0) - self.assertEqual(x, 0) - - # Prove mult by unity - x = _mult_gf2(34, 1) - self.assertEqual(x, 34) - - z = 3 # (x+1) - y = _mult_gf2(z, z) - self.assertEqual(y, 5) # (x+1)^2 = x^2 + 1 - y = _mult_gf2(y, z) - self.assertEqual(y, 15) # (x+1)^3 = x^3 + x^2 + x + 1 - y = _mult_gf2(y, z) - self.assertEqual(y, 17) # (x+1)^4 = x^4 + 1 - - # Prove linearity works - comps = [1, 4, 128, 2**34] - sum_comps = 1+4+128+2**34 - y = 908 - z = _mult_gf2(sum_comps, y) - w = 0 - for x in comps: - w ^= _mult_gf2(x, y) - self.assertEqual(w, z) - - def test_div_gf2(self): - from Crypto.Util.number import size as deg - - x, y = _div_gf2(567, 7) - self.assertTrue(deg(y) < deg(7)) - - w = _mult_gf2(x, 7) ^ y - self.assertEqual(567, w) - - x, y = _div_gf2(7, 567) - self.assertEqual(x, 0) - self.assertEqual(y, 7) - -class Element_Tests(TestCase): - - def test1(self): - # Test encondings - e = _Element(256) - self.assertEqual(int(e), 256) - self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x00")) - - e = _Element(bchr(0)*14 + b("\x01\x10")) - self.assertEqual(int(e), 0x110) - self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x10")) - - # Only 16 byte string are a valid encoding - self.assertRaises(ValueError, _Element, bchr(0)) - - def test2(self): - # Test addition - e = _Element(0x10) - f = _Element(0x0A) - self.assertEqual(int(e+f), 0x1A) - - def test3(self): - # Test multiplication - zero = _Element(0) - one = _Element(1) - two = _Element(2) - - x = _Element(6) * zero - self.assertEqual(int(x), 0) - - x = _Element(6) * one - self.assertEqual(int(x), 6) - - x = _Element(2**127) * two - self.assertEqual(int(x), 1 + 2 + 4 + 128) - - def test4(self): - # Test inversion - one = _Element(1) - - x = one.inverse() - self.assertEqual(int(x), 1) - - x = _Element(82323923) - y = x.inverse() - self.assertEqual(int(x * y), 1) - - -class Shamir_Tests(TestCase): - - def test1(self): - # Test splitting - shares = Shamir.split(2, 3, bchr(90)*16) - self.assertEqual(len(shares), 3) - for index in range(3): - self.assertEqual(shares[index][0], index+1) - self.assertEqual(len(shares[index][1]), 16) - - def test2(self): - # Test recombine - from itertools import permutations - - # Generated by ssss (index, secret, shares) - # in hex mode, without "diffusion" mode - test_vectors = ( - (2, "d9fe73909bae28b3757854c0af7ad405", - "1-594ae8964294174d95c33756d2504170", - "2-d897459d29da574eb40e93ec552ffe6e", - "3-5823de9bf0e068b054b5f07a28056b1b", - "4-db2c1f8bff46d748f795da995bd080cb"), - (2, "bf4f902d9a7efafd1f3ffd9291fd5de9", - "1-557bd3b0748064b533469722d1cc7935", - "2-6b2717164783c66d47cd28f2119f14d0", - "3-8113548ba97d58256bb4424251ae300c", - "4-179e9e5a218483ddaeda57539139cf04"), - (3, "ec96aa5c14c9faa699354cf1da74e904", - "1-64579fbf1908d66f7239bf6e2b4e41e1", - "2-6cd9428df8017b52322561e8c672ae3e", - "3-e418776ef5c0579bd9299277374806dd", - "4-ab3f77a0107398d23b323e581bb43f5d", - "5-23fe42431db2b41bd03ecdc7ea8e97ac"), - (3, "44cf249b68b80fcdc27b47be60c2c145", - "1-d6515a3905cd755119b86e311c801e31", - "2-16693d9ac9f10c254036ced5f8917fa3", - "3-84f74338a48476b99bf5e75a84d3a0d1", - "4-3fe8878dc4a5d35811cf3cbcd33dbe52", - "5-ad76f92fa9d0a9c4ca0c1533af7f6132"), - (5, "5398717c982db935d968eebe53a47f5a", - "1-be7be2dd4c068e7ef576aaa1b1c11b01", - "2-f821f5848441cb98b3eb467e2733ee21", - "3-25ee52f53e203f6e29a0297b5ab486b5", - "4-fc9fb58ef74dab947fbf9acd9d5d83cd", - "5-b1949cce46d81552e65f248d3f74cc5c", - "6-d64797f59977c4d4a7956ad916da7699", - "7-ab608a6546a8b9af8820ff832b1135c7"), - (5, "4a78db90fbf35da5545d2fb728e87596", - "1-08daf9a25d8aa184cfbf02b30a0ed6a0", - "2-dda28261e36f0b14168c2cf153fb734e", - "3-e9fdec5505d674a57f9836c417c1ecaa", - "4-4dce5636ae06dee42d2c82e65f06c735", - "5-3963dc118afc2ba798fa1d452b28ef00", - "6-6dfe6ff5b09e94d2f84c382b12f42424", - "7-6faea9d4d4a4e201bf6c90b9000630c3"), - (10, "eccbf6d66d680b49b073c4f1ddf804aa", - "01-7d8ac32fe4ae209ead1f3220fda34466", - "02-f9144e76988aad647d2e61353a6e96d5", - "03-b14c3b80179203363922d60760271c98", - "04-770bb2a8c28f6cee89e00f4d5cc7f861", - "05-6e3d7073ea368334ef67467871c66799", - "06-248792bc74a98ce024477c13c8fb5f8d", - "07-fcea4640d2db820c0604851e293d2487", - "08-2776c36fb714bb1f8525a0be36fc7dba", - "09-6ee7ac8be773e473a4bf75ee5f065762", - "10-33657fc073354cf91d4a68c735aacfc8", - "11-7645c65094a5868bf225c516fdee2d0c", - "12-840485aacb8226631ecd9c70e3018086"), - (10, "377e63bdbb5f7d4dc58a483d035212bb", - "01-32c53260103be431c843b1a633afe3bd", - "02-0107eb16cb8695084d452d2cc50bc7d6", - "03-df1e5c66cd755287fb0446faccd72a06", - "04-361bbcd5d40797f49dfa1898652da197", - "05-160d3ad1512f7dec7fd9344aed318591", - "06-659af6d95df4f25beca4fb9bfee3b7e8", - "07-37f3b208977bad50b3724566b72bfa9d", - "08-6c1de2dfc69c2986142c26a8248eb316", - "09-5e19220837a396bd4bc8cd685ff314c3", - "10-86e7b864fb0f3d628e46d50c1ba92f1c", - "11-065d0082c80b1aea18f4abe0c49df72e", - "12-84a09430c1d20ea9f388f3123c3733a3"), - ) - - def get_share(p): - pos = p.find('-') - return int(p[:pos]), unhexlify(p[pos + 1:]) - - for tv in test_vectors: - k = tv[0] - secret = unhexlify(tv[1]) - max_perms = 10 - for perm, shares_idx in enumerate(permutations(range(2, len(tv)), k)): - if perm > max_perms: - break - shares = [ get_share(tv[x]) for x in shares_idx ] - result = Shamir.combine(shares, True) - self.assertEqual(secret, result) - - def test3(self): - # Loopback split/recombine - - rng = SHAKE128.new(b"test3") - - for _ in range(100): - - secret = rng.read(16) - - shares = Shamir.split(2, 3, secret) - - secret2 = Shamir.combine(shares[:2]) - self.assertEqual(secret, secret2) - - secret3 = Shamir.combine([ shares[0], shares[2] ]) - self.assertEqual(secret, secret3) - - def test4(self): - # Loopback split/recombine (SSSS) - - rng = SHAKE128.new(b"test4") - - for _ in range(10): - secret = rng.read(16) - - shares = Shamir.split(2, 3, secret, ssss=True) - - secret2 = Shamir.combine(shares[:2], ssss=True) - self.assertEqual(secret, secret2) - - for _ in range(10): - secret = rng.read(16) - - shares = Shamir.split(3, 7, secret, ssss=True) - - secret2 = Shamir.combine([shares[3], shares[4], shares[6]], ssss=True) - self.assertEqual(secret, secret2) - - - def test5(self): - # Detect duplicate shares - secret = unhexlify(b("000102030405060708090a0b0c0d0e0f")) - - shares = Shamir.split(2, 3, secret) - self.assertRaises(ValueError, Shamir.combine, (shares[0], shares[0])) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(GF2_Tests) - tests += list_test_cases(Element_Tests) - tests += list_test_cases(Shamir_Tests) - return tests - -if __name__ == '__main__': - suite = lambda: TestSuite(get_tests()) - main(defaultTest='suite') - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_ecdh.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_ecdh.py deleted file mode 100644 index 9a282ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_ecdh.py +++ /dev/null @@ -1,770 +0,0 @@ -import re -import base64 -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import bord - -from Crypto.Hash import SHA256 -from Crypto.PublicKey import ECC -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Protocol import DH -from Crypto.Protocol.DH import (key_agreement, - import_x25519_public_key, - import_x25519_private_key, - import_x448_public_key, - import_x448_private_key) - - -class FIPS_ECDH_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Protocol", ), - "KAS_ECC_CDH_PrimitiveTest.txt", - "ECC CDH Primitive (SP800-56A Section 5.7.1.2)", - { - 'qcavsx': lambda x: int(x, 16), - 'qcavsy': lambda x: int(x, 16), - 'diut': lambda x: int(x, 16), - 'qiutx': lambda x: int(x, 16), - 'qiuty': lambda x: int(x, 16), - }) or [] - -for idx, tv in enumerate(test_vectors_verify): - - # Stand-alone header with curve name - if isinstance(tv, str): - res = re.match(r"\[([A-Za-z0-9-]+)\]", tv) - assert res - curve_name = res.group(1) - continue - - public_key = ECC.construct(curve=curve_name, - point_x=tv.qcavsx, - point_y=tv.qcavsy) - - private_key = ECC.construct(curve=curve_name, - d=tv.diut) - - exp_response = tv.ziut - - def ecdh_test(self, - public_key=public_key, - private_key=private_key, - exp_response=exp_response): - z = key_agreement( - static_pub=public_key, - static_priv=private_key, - kdf=lambda x: x) - self.assertEqual(z, exp_response) - - def ecdh_test_rev(self, - public_key=public_key, - private_key=private_key, - exp_response=exp_response): - z = key_agreement( - static_pub=public_key, - static_priv=private_key, - kdf=lambda x: x) - self.assertEqual(z, exp_response) - - setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_%d" % idx, ecdh_test) - if idx == 1: - setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_rev_%d" % idx, ecdh_test_rev) - - -class TestVectorsECDHWycheproof(unittest.TestCase): - - desc = "Wycheproof ECDH tests" - - def add_tests(self, filename): - - def curve(g): - return g['curve'] - - def private(u): - return int(u['private'], 16) - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof ECDH (%s)" - % filename, - group_tag={'curve': curve}, - unit_tag={'private': private}, - ) - self.tv += result - - def setUp(self): - self.tv = [] - self.desc = None - - self.add_tests("ecdh_secp224r1_ecpoint_test.json") - self.add_tests("ecdh_secp256r1_ecpoint_test.json") - self.add_tests("ecdh_secp384r1_ecpoint_test.json") - self.add_tests("ecdh_secp521r1_ecpoint_test.json") - - self.add_tests("ecdh_secp224r1_test.json") - self.add_tests("ecdh_secp256r1_test.json") - self.add_tests("ecdh_secp384r1_test.json") - self.add_tests("ecdh_secp521r1_test.json") - - def shortDescription(self): - return self.desc - - def test_verify(self, tv): - - if len(tv.public) == 0: - return - - try: - if bord(tv.public[0]) == 4: # SEC1 - public_key = ECC.import_key(tv.public, curve_name=tv.curve) - else: - public_key = ECC.import_key(tv.public) - except ValueError: - assert tv.warning or not tv.valid - return - - private_key = ECC.construct(curve=tv.curve, d=tv.private) - - try: - z = key_agreement(static_pub=public_key, - static_priv=private_key, - kdf=lambda x: x) - except ValueError: - assert not tv.valid - except TypeError as e: - assert not tv.valid - assert "incompatible curve" in str(e) - else: - self.assertEqual(z, tv.shared) - assert tv.valid - - def runTest(self): - for tv in self.tv: - self.desc = "Wycheproof ECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - self.test_verify(tv) - - -class ECDH_Tests(unittest.TestCase): - - static_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9VHFVKh2a1aVFifH\n+BiyNaRa2kttEg3165Ye/dJxJ7KhRANCAARImIEXro5ZOcyWU2mq/+d79FEZXtTA\nbKkz1aICQXihQdCMzRNbeNtC9LFLzhu1slRKJ2xsDAlw9r6w6vwtkRzr\n-----END PRIVATE KEY-----') - static_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHhmv8zmZ+Nw8fsZd\ns8tlZflyfw2NE1CRS9DWr3Y3O46hRANCAAS3hZVUCbk+uk3w4S/YOraEVGG+WYpk\nNO/vrwzufUUks2GV2OnBQESe0EBk4Jq8gn4ij8Lvs3rZX2yT+XfeATYd\n-----END PRIVATE KEY-----').public_key() - - eph_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGPdJmFFFKzLPspIr\nE1T2cEjeIf4ajS9CpneP0e2b3AyhRANCAAQBexAA5BYDcXHs2KOksTYUsst4HhPt\nkp0zkgI2virc3OGJFNGPaCCPfFCQJHwLRaEpiq3SoQlgoBwSc8ZPsl3y\n-----END PRIVATE KEY-----') - - eph_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghaVZXElSEGEojFKF\nOU0JCpxWUWHvWQUR81gwWrOp76ShRANCAATi1Ib2K+YR3AckD8wxypWef7pw5PRw\ntBaB3RDPyE7IjHZC6yu1DbcXoCdtaw+F5DM+4zpl59n5ZaIy/Yl1BdIy\n-----END PRIVATE KEY-----') - - def test_1(self): - # C(0, 2s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_pub=self.static_pub, - static_priv=self.static_priv) - self.assertEqual(hexlify(z), - b"3960a1101d1193cbaffef4cc7202ebff783c22c6d2e0d5d530ffc66dc197ea9c") - - def test_2(self): - # C(2e, 2s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_pub=self.static_pub, - static_priv=self.static_priv, - eph_pub=self.eph_pub, - eph_priv=self.eph_priv) - self.assertEqual(hexlify(z), - b"7447b733d40c8fab2c633b3dc61e4a8c742f3a6af7e16fb0cc486f5bdb5d6ba2") - - def test_3(self): - # C(1e, 2s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_pub=self.static_pub, - static_priv=self.static_priv, - eph_priv=self.eph_priv) - self.assertEqual(hexlify(z), - b"9e977ae45f33bf67f285d064d83e6632bcafe3a7d33fe571233bab4794ace759") - - def test_4(self): - # C(1e, 2s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_pub=self.static_pub, - static_priv=self.static_priv, - eph_pub=self.eph_pub) - self.assertEqual(hexlify(z), - b"c9532df6aa7e9dbe5fe85da31ee25ff19c179c88691ec4b8328cc2036dcdadf2") - - def test_5(self): - # C(2e, 1s) is not supported - kdf = lambda x: SHA256.new(x).digest() - self.assertRaises(ValueError, - key_agreement, - kdf=kdf, - static_priv=self.static_priv, - eph_pub=self.eph_pub, - eph_priv=self.eph_priv) - - def test_6(self): - # C(2e, 1s) is not supported - kdf = lambda x: SHA256.new(x).digest() - self.assertRaises(ValueError, - key_agreement, - kdf=kdf, - static_pub=self.static_pub, - eph_pub=self.eph_pub, - eph_priv=self.eph_priv) - - def test_7(self): - # C(2e, 0) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - eph_pub=self.eph_pub, - eph_priv=self.eph_priv) - self.assertEqual(hexlify(z), - b"feb257ebe063078b1391aac07913283d7b642ad7df61b46dfc9cd6f420bb896a") - - def test_8(self): - # C(1e, 1s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_priv=self.static_priv, - eph_pub=self.eph_pub) - self.assertEqual(hexlify(z), - b"ee4dc995117476ed57fd17ff0ed44e9f0466d46b929443bc0db9380317583b04") - - def test_9(self): - # C(1e, 1s) - kdf = lambda x: SHA256.new(x).digest() - z = key_agreement( - kdf=kdf, - static_pub=self.static_pub, - eph_priv=self.eph_priv) - self.assertEqual(hexlify(z), - b"2351cc2014f7c40468fa072b5d30f706eeaeef7507311cd8e59bab3b43f03c51") - - def test_10(self): - # No private (local) keys - kdf = lambda x: SHA256.new(x).digest() - self.assertRaises(ValueError, - key_agreement, - kdf=kdf, - static_pub=self.static_pub, - eph_pub=self.eph_pub) - - def test_11(self): - # No public (peer) keys - kdf = lambda x: SHA256.new(x).digest() - self.assertRaises(ValueError, - key_agreement, - kdf=kdf, - static_priv=self.static_priv, - eph_priv=self.eph_priv) - - def test_12(self): - # failure if kdf is missing - self.assertRaises(ValueError, - key_agreement, - static_pub=self.static_pub, - static_priv=self.static_priv) - - -class X25519_Tests(unittest.TestCase): - - def test_rfc7748_1(self): - tvs = ( - ("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", - "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", - "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"), - ("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", - "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", - "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"), - ) - - for tv1, tv2, tv3 in tvs: - priv_key = DH.import_x25519_private_key(unhexlify(tv1)) - pub_key = DH.import_x25519_public_key(unhexlify(tv2)) - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - self.assertEqual(result, unhexlify(tv3)) - - def test_rfc7748_2(self): - k = unhexlify("0900000000000000000000000000000000000000000000000000000000000000") - - priv_key = DH.import_x25519_private_key(k) - pub_key = DH.import_x25519_public_key(k) - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - self.assertEqual( - result, - unhexlify("422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079") - ) - - for _ in range(999): - priv_key = DH.import_x25519_private_key(result) - pub_key = DH.import_x25519_public_key(k) - k = result - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - - self.assertEqual( - result, - unhexlify("684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51") - ) - - def test_rfc7748_3(self): - tv1 = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" - tv2 = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" - tv3 = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" - tv4 = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" - tv5 = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" - - alice_priv_key = DH.import_x25519_private_key(unhexlify(tv1)) - alice_pub_key = DH.import_x25519_public_key(unhexlify(tv2)) - bob_priv_key = DH.import_x25519_private_key(unhexlify(tv3)) - bob_pub_key = DH.import_x25519_public_key(unhexlify(tv4)) - secret = unhexlify(tv5) - - result1 = key_agreement(static_pub=alice_pub_key, - static_priv=bob_priv_key, - kdf=lambda x: x) - result2 = key_agreement(static_pub=bob_pub_key, - static_priv=alice_priv_key, - kdf=lambda x: x) - self.assertEqual(result1, secret) - self.assertEqual(result2, secret) - - def test_weak(self): - - weak_keys = ( - "0000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000", - "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", - "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", - "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", - "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", - "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", - # The implementation will accept these value, but only because - # it will set the MSB to zero (as required by RFC7748, Section 5), - # therefore leading to another public key (and to a point which is - # not of low order anymore). - # "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880", - # "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7", - # "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - # "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - # "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - - for x in weak_keys: - self.assertRaises(ValueError, - DH.import_x25519_public_key, - unhexlify(x)) - - -class X448_Tests(unittest.TestCase): - - def test_rfc7748_1(self): - tvs = ( - ("3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", - "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", - "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f"), - ("203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", - "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", - "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d"), - ) - - for tv1, tv2, tv3 in tvs: - priv_key = DH.import_x448_private_key(unhexlify(tv1)) - pub_key = DH.import_x448_public_key(unhexlify(tv2)) - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - self.assertEqual(result, unhexlify(tv3)) - - def test_rfc7748_2(self): - k = unhexlify("0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - - priv_key = DH.import_x448_private_key(k) - pub_key = DH.import_x448_public_key(k) - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - self.assertEqual( - result, - unhexlify("3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113") - ) - - for _ in range(999): - priv_key = DH.import_x448_private_key(result) - pub_key = DH.import_x448_public_key(k) - k = result - result = key_agreement(static_pub=pub_key, - static_priv=priv_key, - kdf=lambda x: x) - - self.assertEqual( - result, - unhexlify("aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38") - ) - - def test_rfc7748_3(self): - tv1 = "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b" - tv2 = "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0" - tv3 = "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d" - tv4 = "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609" - tv5 = "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d" - - alice_priv_key = DH.import_x448_private_key(unhexlify(tv1)) - alice_pub_key = DH.import_x448_public_key(unhexlify(tv2)) - bob_priv_key = DH.import_x448_private_key(unhexlify(tv3)) - bob_pub_key = DH.import_x448_public_key(unhexlify(tv4)) - secret = unhexlify(tv5) - - result1 = key_agreement(static_pub=alice_pub_key, - static_priv=bob_priv_key, - kdf=lambda x: x) - result2 = key_agreement(static_pub=bob_pub_key, - static_priv=alice_priv_key, - kdf=lambda x: x) - self.assertEqual(result1, secret) - self.assertEqual(result2, secret) - - def test_weak(self): - - weak_keys = ( - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - - for x in weak_keys: - self.assertRaises(ValueError, - DH.import_x448_public_key, - unhexlify(x)) - - -class TestVectorsX25519Wycheproof(unittest.TestCase): - - desc = "Wycheproof X25519 tests" - - def add_tests_hex(self, filename): - - def encoding(g): - return g['type'] - - def private(u): - return unhexlify(u['private']) - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof ECDH (%s)" - % filename, - group_tag={'encoding': encoding}, - unit_tag={'private': private} - ) - self.tv += result - - def add_tests_ascii(self, filename): - - def encoding(g): - return g['type'] - - def public(u): - return u['public'] - - def private(u): - return u['private'] - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof ECDH (%s)" - % filename, - group_tag={'encoding': encoding}, - unit_tag={'public': public, - 'private': private} - ) - self.tv += result - - def setUp(self): - self.tv = [] - self.desc = None - - self.add_tests_hex("x25519_test.json") - self.add_tests_hex("x25519_asn_test.json") - self.add_tests_ascii("x25519_pem_test.json") - self.add_tests_ascii("x25519_jwk_test.json") - - def shortDescription(self): - return self.desc - - def test_verify(self, tv): - - if tv.encoding == "XdhComp": - try: - public_key = import_x25519_public_key(tv.public) - except ValueError as e: - assert tv.valid - assert tv.warning - assert "LowOrderPublic" in tv.flags - assert "Invalid Curve25519" in str(e) - return - private_key = import_x25519_private_key(tv.private) - elif tv.encoding in ("XdhAsnComp", "XdhPemComp"): - try: - public_key = ECC.import_key(tv.public) - private_key = ECC.import_key(tv.private) - except ECC.UnsupportedEccFeature as e: - assert not tv.valid - assert "Unsupported ECC" in str(e) - return - except ValueError: - assert tv.valid - assert tv.warning - assert "LowOrderPublic" in tv.flags - return - elif tv.encoding == "XdhJwkComp": - - if 'y' in tv.public: - return - if 'x' not in tv.public: - return - if 'x' not in tv.private: - return - if tv.public.get('kty') != 'OKP': - return - if tv.public.get('crv') != 'X25519': - return - if tv.private.get('crv') != 'X25519': - return - - def base64url_decode(input_str): - input_str = input_str.replace('-', '+').replace('_', '/') - padding = 4 - (len(input_str) % 4) - if padding != 4: - input_str += '=' * padding - decoded_bytes = base64.b64decode(input_str) - return decoded_bytes - - jwk_public = base64url_decode(tv.public['x']) - jwk_private = base64url_decode(tv.private['d']) - - try: - public_key = import_x25519_public_key(jwk_public) - private_key = import_x25519_private_key(jwk_private) - except ValueError as e: - if tv.valid: - assert tv.warning - assert "LowOrderPublic" in tv.flags - assert "Invalid Curve25519" in str(e) - return - else: - assert "Incorrect length" in str(e) - return - except ValueError: - assert tv.valid - else: - raise ValueError("Unknown encoding", tv.encoding) - - try: - z = key_agreement(static_pub=public_key, - static_priv=private_key, - kdf=lambda x: x) - except ValueError: - assert not tv.valid - except TypeError as e: - assert not tv.valid - assert "incompatible curve" in str(e) - else: - self.assertEqual(z, tv.shared) - assert tv.valid - - def runTest(self): - for tv in self.tv: - self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - self.test_verify(tv) - - -class TestVectorsX448Wycheproof(unittest.TestCase): - - desc = "Wycheproof X448 tests" - - def add_tests_hex(self, filename): - - def encoding(g): - return g['type'] - - def private(u): - return unhexlify(u['private']) - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof ECDH (%s)" - % filename, - group_tag={'encoding': encoding}, - unit_tag={'private': private} - ) - self.tv += result - - def add_tests_ascii(self, filename): - - def encoding(g): - return g['type'] - - def public(u): - return u['public'] - - def private(u): - return u['private'] - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof ECDH (%s)" - % filename, - group_tag={'encoding': encoding}, - unit_tag={'public': public, - 'private': private} - ) - self.tv += result - - def setUp(self): - self.tv = [] - self.desc = None - - self.add_tests_hex("x448_test.json") - self.add_tests_hex("x448_asn_test.json") - self.add_tests_ascii("x448_pem_test.json") - self.add_tests_ascii("x448_jwk_test.json") - - def shortDescription(self): - return self.desc - - def test_verify(self, tv): - - if tv.encoding == "XdhComp": - try: - public_key = import_x448_public_key(tv.public) - except ValueError as e: - assert tv.valid - assert tv.warning - if len(tv.public) == 56: - assert "LowOrderPublic" in tv.flags - assert "Invalid Curve448" in str(e) - else: - assert "Incorrect Curve448" in str(e) - return - private_key = import_x448_private_key(tv.private) - elif tv.encoding in ("XdhAsnComp", "XdhPemComp"): - try: - public_key = ECC.import_key(tv.public) - private_key = ECC.import_key(tv.private) - except ECC.UnsupportedEccFeature as e: - assert not tv.valid - assert "Unsupported ECC" in str(e) - return - except ValueError as e: - assert tv.valid - assert tv.warning - assert "LowOrderPublic" in tv.flags or "NonCanonicalPublic" in tv.flags - return - elif tv.encoding == "XdhJwkComp": - - if 'y' in tv.public: - return - if 'x' not in tv.public: - return - if 'x' not in tv.private: - return - if tv.public.get('kty') != 'OKP': - return - if tv.public.get('crv') != 'X448': - return - if tv.private.get('crv') != 'X448': - return - - def base64url_decode(input_str): - input_str = input_str.replace('-', '+').replace('_', '/') - padding = 4 - (len(input_str) % 4) - if padding != 4: - input_str += '=' * padding - decoded_bytes = base64.b64decode(input_str) - return decoded_bytes - - jwk_public = base64url_decode(tv.public['x']) - jwk_private = base64url_decode(tv.private['d']) - - try: - public_key = import_x448_public_key(jwk_public) - private_key = import_x448_private_key(jwk_private) - except ValueError as e: - if tv.valid: - assert tv.warning - if len(tv.public['x']) == 75: - assert "LowOrderPublic" in tv.flags or \ - "NonCanonicalPublic" in tv.flags - assert "Invalid Curve448" in str(e) - else: - assert "Incorrect Curve448" in str(e) - return - else: - assert "Incorrect length" in str(e) - return - except ValueError: - assert tv.valid - else: - raise ValueError("Unknown encoding", tv.encoding) - - try: - z = key_agreement(static_pub=public_key, - static_priv=private_key, - kdf=lambda x: x) - except ValueError: - assert not tv.valid - except TypeError as e: - assert not tv.valid - assert "incompatible curve" in str(e) - else: - self.assertEqual(z, tv.shared) - assert tv.valid - - def runTest(self): - for tv in self.tv: - self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - self.test_verify(tv) - - -def get_tests(config={}): - - tests = [] - tests += list_test_cases(FIPS_ECDH_Tests_KAT) - tests += [TestVectorsECDHWycheproof()] - tests += list_test_cases(ECDH_Tests) - tests += list_test_cases(X25519_Tests) - tests += list_test_cases(X448_Tests) - tests += [TestVectorsX25519Wycheproof()] - tests += [TestVectorsX448Wycheproof()] - - slow_tests = config.get('slow_tests') - if slow_tests: - pass - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_rfc1751.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_rfc1751.py deleted file mode 100644 index 0878cc5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Protocol/test_rfc1751.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# Test script for Crypto.Util.RFC1751. -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew Kuchling and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -__revision__ = "$Id$" - -import binascii -import unittest -from Crypto.Util import RFC1751 -from Crypto.Util.py3compat import * - -test_data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), - ('CCAC2AED591056BE4F90FD441C534766', - 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), - ('EFF81F9BFBC65350920CDD7416DE8009', - 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') - ] - -class RFC1751Test_k2e (unittest.TestCase): - - def runTest (self): - "Check converting keys to English" - for key, words in test_data: - key=binascii.a2b_hex(b(key)) - self.assertEqual(RFC1751.key_to_english(key), words) - -class RFC1751Test_e2k (unittest.TestCase): - - def runTest (self): - "Check converting English strings to keys" - for key, words in test_data: - key=binascii.a2b_hex(b(key)) - self.assertEqual(RFC1751.english_to_key(words), key) - -# class RFC1751Test - -def get_tests(config={}): - return [RFC1751Test_k2e(), RFC1751Test_e2k()] - -if __name__ == "__main__": - unittest.main() diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/__init__.py deleted file mode 100644 index 48a445e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/__init__.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/__init__.py: Self-test for public key crypto -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for public-key crypto""" - -import unittest -from Crypto.SelfTest.PublicKey import (test_DSA, test_RSA, - test_ECC_NIST, - test_ECC_Ed25519, - test_ECC_Curve25519, - test_ECC_Ed448, - test_ECC_Curve448, - test_import_DSA, test_import_RSA, - test_import_ECC, test_ElGamal, - test_import_Curve25519, - test_import_Curve448) - - -def get_tests(config={}): - tests = [] - tests += test_DSA.get_tests(config=config) - tests += test_RSA.get_tests(config=config) - tests += test_ECC_NIST.get_tests(config=config) - tests += test_ECC_Ed25519.get_tests(config=config) - tests += test_ECC_Curve25519.get_tests(config=config) - tests += test_ECC_Ed448.get_tests(config=config) - tests += test_ECC_Curve448.get_tests(config=config) - - tests += test_import_DSA.get_tests(config=config) - tests += test_import_RSA.get_tests(config=config) - tests += test_import_ECC.get_tests(config=config) - tests += test_import_Curve25519.get_tests(config=config) - tests += test_import_Curve448.get_tests(config=config) - - tests += test_ElGamal.get_tests(config=config) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_DSA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_DSA.py deleted file mode 100644 index 125cf6c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_DSA.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_DSA.py: Self-test for the DSA primitive -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.DSA""" - -import os -from Crypto.Util.py3compat import * - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex - -def _sws(s): - """Remove whitespace from a text or byte string""" - if isinstance(s,str): - return "".join(s.split()) - else: - return b("").join(s.split()) - -class DSATest(unittest.TestCase): - # Test vector from "Appendix 5. Example of the DSA" of - # "Digital Signature Standard (DSS)", - # U.S. Department of Commerce/National Institute of Standards and Technology - # FIPS 186-2 (+Change Notice), 2000 January 27. - # http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf - - y = _sws("""19131871 d75b1612 a819f29d 78d1b0d7 346f7aa7 7bb62a85 - 9bfd6c56 75da9d21 2d3a36ef 1672ef66 0b8c7c25 5cc0ec74 - 858fba33 f44c0669 9630a76b 030ee333""") - - g = _sws("""626d0278 39ea0a13 413163a5 5b4cb500 299d5522 956cefcb - 3bff10f3 99ce2c2e 71cb9de5 fa24babf 58e5b795 21925c9c - c42e9f6f 464b088c c572af53 e6d78802""") - - p = _sws("""8df2a494 492276aa 3d25759b b06869cb eac0d83a fb8d0cf7 - cbb8324f 0d7882e5 d0762fc5 b7210eaf c2e9adac 32ab7aac - 49693dfb f83724c2 ec0736ee 31c80291""") - - q = _sws("""c773218c 737ec8ee 993b4f2d ed30f48e dace915f""") - - x = _sws("""2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614""") - - k = _sws("""358dad57 1462710f 50e254cf 1a376b2b deaadfbf""") - k_inverse = _sws("""0d516729 8202e49b 4116ac10 4fc3f415 ae52f917""") - m = b2a_hex(b("abc")) - m_hash = _sws("""a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d""") - r = _sws("""8bac1ab6 6410435c b7181f95 b16ab97c 92b341c0""") - s = _sws("""41e2345f 1f56df24 58f426d1 55b4ba2d b6dcd8c8""") - - def setUp(self): - global DSA, Random, bytes_to_long, size - from Crypto.PublicKey import DSA - from Crypto import Random - from Crypto.Util.number import bytes_to_long, inverse, size - - self.dsa = DSA - - def test_generate_1arg(self): - """DSA (default implementation) generated key (1 argument)""" - dsaObj = self.dsa.generate(1024) - self._check_private_key(dsaObj) - pub = dsaObj.public_key() - self._check_public_key(pub) - - def test_generate_2arg(self): - """DSA (default implementation) generated key (2 arguments)""" - dsaObj = self.dsa.generate(1024, Random.new().read) - self._check_private_key(dsaObj) - pub = dsaObj.public_key() - self._check_public_key(pub) - - def test_construct_4tuple(self): - """DSA (default implementation) constructed key (4-tuple)""" - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - dsaObj = self.dsa.construct((y, g, p, q)) - self._test_verification(dsaObj) - - def test_construct_5tuple(self): - """DSA (default implementation) constructed key (5-tuple)""" - (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] - dsaObj = self.dsa.construct((y, g, p, q, x)) - self._test_signing(dsaObj) - self._test_verification(dsaObj) - - def test_construct_bad_key4(self): - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - tup = (y, g, p+1, q) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, g, p, q+1) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, 1, p, q) - self.assertRaises(ValueError, self.dsa.construct, tup) - - def test_construct_bad_key5(self): - (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] - tup = (y, g, p, q, x+1) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, g, p, q, q+10) - self.assertRaises(ValueError, self.dsa.construct, tup) - - def _check_private_key(self, dsaObj): - # Check capabilities - self.assertEqual(1, dsaObj.has_private()) - self.assertEqual(1, dsaObj.can_sign()) - self.assertEqual(0, dsaObj.can_encrypt()) - - # Sanity check key data - self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q - self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits - self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 - self.assertEqual(dsaObj.y, pow(dsaObj.g, dsaObj.x, dsaObj.p)) # y == g**x mod p - self.assertEqual(1, 0 < dsaObj.x < dsaObj.q) # 0 < x < q - - def _check_public_key(self, dsaObj): - k = bytes_to_long(a2b_hex(self.k)) - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - - # Check capabilities - self.assertEqual(0, dsaObj.has_private()) - self.assertEqual(1, dsaObj.can_sign()) - self.assertEqual(0, dsaObj.can_encrypt()) - - # Check that private parameters are all missing - self.assertEqual(0, hasattr(dsaObj, 'x')) - - # Sanity check key data - self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q - self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits - self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 - - # Public-only key objects should raise an error when .sign() is called - self.assertRaises(TypeError, dsaObj._sign, m_hash, k) - - # Check __eq__ and __ne__ - self.assertEqual(dsaObj.public_key() == dsaObj.public_key(),True) # assert_ - self.assertEqual(dsaObj.public_key() != dsaObj.public_key(),False) # assertFalse - - self.assertEqual(dsaObj.public_key(), dsaObj.publickey()) - - def _test_signing(self, dsaObj): - k = bytes_to_long(a2b_hex(self.k)) - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - r = bytes_to_long(a2b_hex(self.r)) - s = bytes_to_long(a2b_hex(self.s)) - (r_out, s_out) = dsaObj._sign(m_hash, k) - self.assertEqual((r, s), (r_out, s_out)) - - def _test_verification(self, dsaObj): - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - r = bytes_to_long(a2b_hex(self.r)) - s = bytes_to_long(a2b_hex(self.s)) - self.assertTrue(dsaObj._verify(m_hash, (r, s))) - self.assertFalse(dsaObj._verify(m_hash + 1, (r, s))) - - def test_repr(self): - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - dsaObj = self.dsa.construct((y, g, p, q)) - repr(dsaObj) - - -class DSADomainTest(unittest.TestCase): - - def test_domain1(self): - """Verify we can generate new keys in a given domain""" - dsa_key_1 = DSA.generate(1024) - domain_params = dsa_key_1.domain() - - dsa_key_2 = DSA.generate(1024, domain=domain_params) - self.assertEqual(dsa_key_1.p, dsa_key_2.p) - self.assertEqual(dsa_key_1.q, dsa_key_2.q) - self.assertEqual(dsa_key_1.g, dsa_key_2.g) - - self.assertEqual(dsa_key_1.domain(), dsa_key_2.domain()) - - def _get_weak_domain(self): - - from Crypto.Math.Numbers import Integer - from Crypto.Math import Primality - - p = Integer(4) - while p.size_in_bits() != 1024 or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME: - q1 = Integer.random(exact_bits=80) - q2 = Integer.random(exact_bits=80) - q = q1 * q2 - z = Integer.random(exact_bits=1024-160) - p = z * q + 1 - - h = Integer(2) - g = 1 - while g == 1: - g = pow(h, z, p) - h += 1 - - return (p, q, g) - - - def test_generate_error_weak_domain(self): - """Verify that domain parameters with composite q are rejected""" - - domain_params = self._get_weak_domain() - self.assertRaises(ValueError, DSA.generate, 1024, domain=domain_params) - - - def test_construct_error_weak_domain(self): - """Verify that domain parameters with composite q are rejected""" - - from Crypto.Math.Numbers import Integer - - p, q, g = self._get_weak_domain() - y = pow(g, 89, p) - self.assertRaises(ValueError, DSA.construct, (y, g, p, q)) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(DSATest) - tests += list_test_cases(DSADomainTest) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve25519.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve25519.py deleted file mode 100644 index c637bb3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve25519.py +++ /dev/null @@ -1,283 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2024, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Math.Numbers import Integer -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccKey, EccXPoint, _curves - -# Test vectors for scalar multiplication using point with X=9 as base -# generated with nickovs' Python-only code https://gist.github.com/nickovs/cc3c22d15f239a2640c185035c06f8a3 -# The order is 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed -# Each tuple is (exponent, X-coordinate) -scalar_base9_test = [ - (1, 9), - (2, 0x20d342d51873f1b7d9750c687d1571148f3f5ced1e350b5c5cae469cdd684efb), - (3, 0x1c12bc1a6d57abe645534d91c21bba64f8824e67621c0859c00a03affb713c12), - (4, 0x79ce98b7e0689d7de7d1d074a15b315ffe1805dfcd5d2a230fee85e4550013ef), - (6, 0x26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531), - (9, 0x192b929197d07748db44600da41bab7499b1c2e6e2f87c6f0e337980668164ba), - (129, 0x7332096a738900085e721103fce2cbf13aee50fef0788ea0d669008eb09ceab7), - (255, 0x1534582fc2b1cea45e8cb776547e209da4fd54a9e473b50c5b8c6b0ae023a9b3), - (256, 0x4300017536976a742ec8747f7505cd6bc80e610d669acab1a1eed36f680d98e8), - (257, 0x6c410611cb484c9016adfb884d37a0e682e075daca1d46f45bb7a4afed10b125), - (0x10101, 0xa679e9d7e043bf76c03362576e2c88abe9093c5d4f6b4a202c64a8397467cf), - (0xAA55CC, 0x2cc02f84c067e3586f4278326689be163e606d69ccae505bb09488e11f295887), - (0x1B29A0E579E0A000567, 0x50c38a72d7bfd7864c8b9083fa123e8d359068e6b491a019a885036e073f6604), - (0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + 1, 9), -] - - -class TestEccPoint_Curve25519(unittest.TestCase): - - v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8 - v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 - - def test_init(self): - EccXPoint(9, "curve25519") - EccXPoint(2**255 - 19 + 5, "curve25519") - - def test_curve_attribute(self): - point = EccXPoint(9, "curve25519") - self.assertEqual(point.curve, "Curve25519") - - def test_init_fail(self): - self.assertRaises(ValueError, EccXPoint, 3*(2**255 - 19), "curve25519") - self.assertRaises(ValueError, EccXPoint, 9, "curve25518") - - def test_equal_set(self): - point1 = EccXPoint(self.v1, "curve25519") - point2 = EccXPoint(self.v2, "curve25519") - - self.assertEqual(point1, point1) - self.assertNotEqual(point1, point2) - - point2.set(point1) - self.assertEqual(point1.x, point2.x) - - def test_copy(self): - point1 = EccXPoint(self.v1, "curve25519") - point2 = point1.copy() - self.assertEqual(point1.x, point2.x) - - def test_pai(self): - point1 = EccXPoint(self.v1, "curve25519") - pai = point1.point_at_infinity() - self.assertTrue(pai.point_at_infinity()) - - point2 = EccXPoint(None, "curve25519") - self.assertTrue(point2.point_at_infinity()) - - def test_scalar_multiply(self): - base = EccXPoint(9, "curve25519") - - pointH = 0 * base - self.assertTrue(pointH.point_at_infinity()) - - pointH = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed * base - self.assertTrue(pointH.point_at_infinity()) - - pointH = base * 1 - self.assertEqual(pointH.x, 9) - - for d, result in scalar_base9_test: - pointH = d * base - self.assertEqual(pointH.x, result) - - def test_sizes(self): - point = EccXPoint(9, "curve25519") - self.assertEqual(point.size_in_bits(), 255) - self.assertEqual(point.size_in_bytes(), 32) - - -class TestEccKey_Curve25519(unittest.TestCase): - - def test_private_key(self): - # RFC7748 Section 6.1 - Alice - alice_priv = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") - alice_pub = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") - alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little') - - key = EccKey(curve="Curve25519", seed=alice_priv) - self.assertEqual(key.seed, alice_priv) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, alice_pub_x) - - # RFC7748 Section 6.1 - Bob - bob_priv = unhexlify("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb") - bob_pub = unhexlify("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f") - bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little') - - key = EccKey(curve="Curve25519", seed=bob_priv) - self.assertEqual(key.seed, bob_priv) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, bob_pub_x) - - # Other names - key = EccKey(curve="curve25519", seed=alice_priv) - - # Must not accept d parameter - self.assertRaises(ValueError, EccKey, curve="curve25519", d=1) - - def test_public_key(self): - point = EccXPoint(_curves['curve25519'].Gx, - curve='curve25519') - key = EccKey(curve="curve25519", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - priv_key = EccKey(curve="curve25519", seed=b'H'*32) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_seed(self): - self.assertRaises(ValueError, lambda: EccKey(curve="curve25519", seed=b'H' * 31)) - - def test_equality(self): - private_key = ECC.construct(seed=b'H'*32, curve="Curve25519") - private_key2 = ECC.construct(seed=b'H'*32, curve="curve25519") - private_key3 = ECC.construct(seed=b'C'*32, curve="Curve25519") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='curve25519') - self.assertIn("curve='Curve25519'", repr(key)) - self.assertEqual(key.curve, 'Curve25519') - self.assertEqual(key.public_key().curve, 'Curve25519') - - -class TestEccModule_Curve25519(unittest.TestCase): - - def test_generate(self): - key = ECC.generate(curve="Curve25519") - self.assertTrue(key.has_private()) - point = EccXPoint(_curves['Curve25519'].Gx, curve="Curve25519") * key.d - self.assertEqual(key.pointQ, point) - - # Always random - key2 = ECC.generate(curve="Curve25519") - self.assertNotEqual(key, key2) - - # Other names - ECC.generate(curve="curve25519") - - # Random source - key1 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read) - key2 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read) - self.assertEqual(key1, key2) - - def test_construct(self): - seed = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") - point_hex = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") - Px = Integer.from_bytes(point_hex, byteorder='little') - point = EccXPoint(Px, curve="Curve25519") - - # Private key only - key = ECC.construct(curve="Curve25519", seed=seed) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Public key only - key = ECC.construct(curve="Curve25519", point_x=Px) - self.assertEqual(key.pointQ, point) - self.assertFalse(key.has_private()) - - # Private and public key - key = ECC.construct(curve="Curve25519", seed=seed, point_x=Px) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Other names - key = ECC.construct(curve="curve25519", seed=seed) - - def test_negative_construct(self): - coordG = dict(point_x=_curves['curve25519'].Gx) - - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", d=2, **coordG) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", seed=b'H'*31) - - # Verify you cannot construct weak keys (small-order points) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=0) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=1) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=325606250916557431795983626356110631294008115727848805560023387167927233504) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=39382357235489614581723060781553021112529911719440698176882885853963445705823) - p = 2**255 - 19 - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p-1) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p+1) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p+325606250916557431795983626356110631294008115727848805560023387167927233504) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p+39382357235489614581723060781553021112529911719440698176882885853963445705823) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p*2-1) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p*2) - self.assertRaises(ValueError, ECC.construct, curve="Curve25519", - point_x=p*2+1) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint_Curve25519) - tests += list_test_cases(TestEccKey_Curve25519) - tests += list_test_cases(TestEccModule_Curve25519) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve448.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve448.py deleted file mode 100644 index 91da450..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Curve448.py +++ /dev/null @@ -1,246 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Math.Numbers import Integer -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccKey, EccXPoint, _curves - -CURVE448_P = 2**448 - 2**224 - 1 -CURVE448_ORDER = 2**446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d - -# Test vectors for scalar multiplication using point with X=5 as base -# Each tuple is (exponent, X-coordinate) -scalar_base5_test = [ - (1, 5), - (2, 0x6391322257cae3d49aef4665d8bd5cccac9abefb511e83d75f3c766616266fc1bf3747f1da00ed7125e8f0255a1208087d32a4bc1c743cb6), - (3, 0x1fbe4b3584cab86170c14b9325840b8a2429b61fb93c42492c002a2807a4e7ea63138ea59bf95652ce9a7d13d0321c7511e3314d0553f34c), - (4, 0x93b44a7b78726ba8d0b048bd7144074f8bdad24ef9d0a6c8264f6c00b135ffcea11545e80d18364acc8ebfbcc45358e0da5fd5e5146e2b1), - (6, 0x693d165f453bd62871e5e53845f33e9e5b18b24d79c1f9102608aa7ba6f18ac24864012171d64c90b698f5ce5631cd02cee4e4336b1ad88c), - (9, 0xb970d576e7d9aa427dbf7cb9b7dd65170721d04ee060c9ea8d499dc361d4cfde1ceb19068eae853bac8f5d92827bdbf3d94c22de2fb42dae), - (129, 0x9fbdb50a1450438fe656aa32aa1bb2548d077d5c3a5d327689093a2996a4f94eacd1fb4f90315edb2afe41908a759f0d6db83fa791df80db), - (255, 0x31bc3e9385dfd12e1238927061eb0c911466da394e459bf058ba3b08260a258a3c392b0f85ddbd23828657137b88577a85b83774139fab9e), - (256, 0x735c7f30e6872e5e4215c0147c8a112d697f668c9bd0f92f5f1e4e6badc128a0b654e697cd4bae2144d54e726b54c1fa63a09b00dd3c17f), - (257, 0x95c1b0ce01286dc047aeb5922a5e62b3effb5b9296273a5004eb456f592728dd494a6fb5996a2ea7011ae6423874a48c2927bfa62d8ce8b0), - (0x10101, 0x113bb172c9dc52ab45bd665dd9751ed44e33b8596f943c6cb2f8dd329160ece802960b3eb0d2c21ef3a3ac12c20fccbc2a271fc2f061c1b2), - (0xAA55CC, 0xcf42585d2e0b1e45c0bfd601c91af4b137d7faf139fc761178c7ded432417c307ee1759af2deec6a14dbaf6b868eb13a6039fbdde4b61898), - (0x1B29A0E579E0A000567, 0x7bd9ec9775a664f4d860d82d6be60895113a7c36f92db25583dbba5dc17f09c136ec27e14857bfd6a705311327030aa657dd036325fad330), - (CURVE448_ORDER + 1, 5), -] - - -class TestEccPoint_Curve448(unittest.TestCase): - - v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8 - v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 - - def test_init(self): - EccXPoint(5, "curve448") - EccXPoint(CURVE448_P - 5, "curve448") - - def test_curve_attribute(self): - point = EccXPoint(5, "curve448") - self.assertEqual(point.curve, "Curve448") - - def test_init_fail(self): - self.assertRaises(ValueError, EccXPoint, 3*CURVE448_P, "curve448") - self.assertRaises(ValueError, EccXPoint, 3, "curve449") - - def test_equal_set(self): - point1 = EccXPoint(self.v1, "curve448") - point2 = EccXPoint(self.v2, "curve448") - - self.assertEqual(point1, point1) - self.assertNotEqual(point1, point2) - - point2.set(point1) - self.assertEqual(point1.x, point2.x) - - def test_copy(self): - point1 = EccXPoint(self.v1, "curve448") - point2 = point1.copy() - self.assertEqual(point1.x, point2.x) - - def test_pai(self): - point1 = EccXPoint(self.v1, "curve448") - pai = point1.point_at_infinity() - self.assertTrue(pai.point_at_infinity()) - - point2 = EccXPoint(None, "curve448") - self.assertTrue(point2.point_at_infinity()) - - def test_scalar_multiply(self): - base = EccXPoint(5, "curve448") - - pointH = 0 * base - self.assertTrue(pointH.point_at_infinity()) - - pointH = CURVE448_ORDER * base - self.assertTrue(pointH.point_at_infinity()) - - pointH = base * 1 - self.assertEqual(pointH.x, 5) - - for d, result in scalar_base5_test: - pointH = d * base - self.assertEqual(pointH.x, result) - - def test_sizes(self): - point = EccXPoint(5, "curve448") - self.assertEqual(point.size_in_bits(), 448) - self.assertEqual(point.size_in_bytes(), 56) - - -class TestEccKey_Curve448(unittest.TestCase): - - def test_private_key(self): - # RFC7748 Section 6.2 - Alice - alice_priv = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b") - alice_pub = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0") - alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little') - - key = EccKey(curve="Curve448", seed=alice_priv) - self.assertEqual(key.seed, alice_priv) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, alice_pub_x) - - # RFC7748 Section 6.2 - Bob - bob_priv = unhexlify("1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d") - bob_pub = unhexlify("3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609") - bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little') - - key = EccKey(curve="Curve448", seed=bob_priv) - self.assertEqual(key.seed, bob_priv) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, bob_pub_x) - - # Other names - key = EccKey(curve="curve448", seed=alice_priv) - - # Must not accept d parameter - self.assertRaises(ValueError, EccKey, curve="curve448", d=1) - - def test_public_key(self): - point = EccXPoint(_curves['curve448'].Gx, - curve='curve448') - key = EccKey(curve="curve448", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - priv_key = EccKey(curve="curve448", seed=b'H'*56) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_seed(self): - self.assertRaises(ValueError, lambda: EccKey(curve="curve448", - seed=b'H' * 55)) - - def test_equality(self): - private_key = ECC.construct(seed=b'H'*56, curve="Curve448") - private_key2 = ECC.construct(seed=b'H'*56, curve="curve448") - private_key3 = ECC.construct(seed=b'C'*56, curve="Curve448") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='curve448') - self.assertIn("curve='Curve448'", repr(key)) - self.assertEqual(key.curve, 'Curve448') - self.assertEqual(key.public_key().curve, 'Curve448') - - -class TestEccModule_Curve448(unittest.TestCase): - - def test_generate(self): - key = ECC.generate(curve="Curve448") - self.assertTrue(key.has_private()) - point = EccXPoint(_curves['Curve448'].Gx, curve="Curve448") * key.d - self.assertEqual(key.pointQ, point) - - # Always random - key2 = ECC.generate(curve="Curve448") - self.assertNotEqual(key, key2) - - # Other names - ECC.generate(curve="curve448") - - # Random source - key1 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read) - key2 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read) - self.assertEqual(key1, key2) - - def test_construct(self): - seed = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b") - point_hex = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0") - Px = Integer.from_bytes(point_hex, byteorder='little') - point = EccXPoint(Px, curve="Curve448") - - # Private key only - key = ECC.construct(curve="Curve448", seed=seed) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Public key only - key = ECC.construct(curve="Curve448", point_x=Px) - self.assertEqual(key.pointQ, point) - self.assertFalse(key.has_private()) - - # Private and public key - key = ECC.construct(curve="Curve448", seed=seed, point_x=Px) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Other names - key = ECC.construct(curve="curve448", seed=seed) - - def test_negative_construct(self): - coordG = dict(point_x=_curves['curve448'].Gx) - - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - d=2, **coordG) - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - seed=b'H'*55) - - # Verify you cannot construct weak keys (small-order points) - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - point_x=0) - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - point_x=1) - p = 2**448 - 2**224 - 1 - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - point_x=p-1) - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - point_x=p) - self.assertRaises(ValueError, ECC.construct, curve="Curve448", - point_x=p+1) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint_Curve448) - tests += list_test_cases(TestEccKey_Curve448) - tests += list_test_cases(TestEccModule_Curve448) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed25519.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed25519.py deleted file mode 100644 index c79b05c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed25519.py +++ /dev/null @@ -1,341 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2022, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey - -from Crypto.Math.Numbers import Integer - -from Crypto.Hash import SHAKE128 - - -class TestEccPoint_Ed25519(unittest.TestCase): - - Gxy = {"x": 15112221349535400772501151409588531511454012693041857206046113283949847762202, - "y": 46316835694926478169428394003475163141307993866256225615783033603165251855960} - - G2xy = {"x": 24727413235106541002554574571675588834622768167397638456726423682521233608206, - "y": 15549675580280190176352668710449542251549572066445060580507079593062643049417} - - G3xy = {"x": 46896733464454938657123544595386787789046198280132665686241321779790909858396, - "y": 8324843778533443976490377120369201138301417226297555316741202210403726505172} - - pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed25519") - pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed25519") - pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed25519") - - def test_curve_attribute(self): - self.assertEqual(self.pointG.curve, "Ed25519") - - def test_init_xy(self): - EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed25519") - - # Neutral point - pai = EccPoint(0, 1, curve="Ed25519") - self.assertEqual(pai.x, 0) - self.assertEqual(pai.y, 1) - self.assertEqual(pai.xy, (0, 1)) - - # G - bp = self.pointG.copy() - self.assertEqual(bp.x, 15112221349535400772501151409588531511454012693041857206046113283949847762202) - self.assertEqual(bp.y, 46316835694926478169428394003475163141307993866256225615783033603165251855960) - self.assertEqual(bp.xy, (bp.x, bp.y)) - - # 2G - bp2 = self.pointG2.copy() - self.assertEqual(bp2.x, 24727413235106541002554574571675588834622768167397638456726423682521233608206) - self.assertEqual(bp2.y, 15549675580280190176352668710449542251549572066445060580507079593062643049417) - self.assertEqual(bp2.xy, (bp2.x, bp2.y)) - - # 5G - EccPoint(x=33467004535436536005251147249499675200073690106659565782908757308821616914995, - y=43097193783671926753355113395909008640284023746042808659097434958891230611693, - curve="Ed25519") - - # Catch if point is not on the curve - self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed25519") - - def test_set(self): - pointW = EccPoint(0, 1, curve="Ed25519") - pointW.set(self.pointG) - self.assertEqual(pointW.x, self.pointG.x) - self.assertEqual(pointW.y, self.pointG.y) - - def test_copy(self): - pointW = self.pointG.copy() - self.assertEqual(pointW.x, self.pointG.x) - self.assertEqual(pointW.y, self.pointG.y) - - def test_equal(self): - pointH = self.pointG.copy() - pointI = self.pointG2.copy() - self.assertEqual(self.pointG, pointH) - self.assertNotEqual(self.pointG, pointI) - - def test_pai(self): - pai = EccPoint(0, 1, curve="Ed25519") - self.assertTrue(pai.is_point_at_infinity()) - self.assertEqual(pai, pai.point_at_infinity()) - - def test_negate(self): - negG = -self.pointG - G100 = self.pointG * 100 - sum_zero = G100 + negG * 100 - self.assertTrue(sum_zero.is_point_at_infinity()) - - sum_99 = G100 + negG - expected = self.pointG * 99 - self.assertEqual(sum_99, expected) - - def test_addition(self): - self.assertEqual(self.pointG + self.pointG2, self.pointG3) - self.assertEqual(self.pointG2 + self.pointG, self.pointG3) - self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2) - self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2) - - G5 = self.pointG2 + self.pointG3 - self.assertEqual(G5.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995) - self.assertEqual(G5.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693) - - def test_inplace_addition(self): - pointH = self.pointG.copy() - pointH += self.pointG - self.assertEqual(pointH, self.pointG2) - pointH += self.pointG - self.assertEqual(pointH, self.pointG3) - pointH += self.pointG.point_at_infinity() - self.assertEqual(pointH, self.pointG3) - - def test_doubling(self): - pointH = self.pointG.copy() - pointH.double() - self.assertEqual(pointH.x, self.pointG2.x) - self.assertEqual(pointH.y, self.pointG2.y) - - # 2*0 - pai = self.pointG.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - def test_scalar_multiply(self): - d = 0 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0) - self.assertEqual(pointH.y, 1) - - d = 1 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG.x) - self.assertEqual(pointH.y, self.pointG.y) - - d = 2 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG2.x) - self.assertEqual(pointH.y, self.pointG2.y) - - d = 3 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG3.x) - self.assertEqual(pointH.y, self.pointG3.y) - - d = 4 - pointH = d * self.pointG - self.assertEqual(pointH.x, 14582954232372986451776170844943001818709880559417862259286374126315108956272) - self.assertEqual(pointH.y, 32483318716863467900234833297694612235682047836132991208333042722294373421359) - - d = 5 - pointH = d * self.pointG - self.assertEqual(pointH.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995) - self.assertEqual(pointH.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693) - - d = 10 - pointH = d * self.pointG - self.assertEqual(pointH.x, 43500613248243327786121022071801015118933854441360174117148262713429272820047) - self.assertEqual(pointH.y, 45005105423099817237495816771148012388779685712352441364231470781391834741548) - - d = 20 - pointH = d * self.pointG - self.assertEqual(pointH.x, 46694936775300686710656303283485882876784402425210400817529601134760286812591) - self.assertEqual(pointH.y, 8786390172762935853260670851718824721296437982862763585171334833968259029560) - - d = 255 - pointH = d * self.pointG - self.assertEqual(pointH.x, 36843863416400016952258312492144504209624961884991522125275155377549541182230) - self.assertEqual(pointH.y, 22327030283879720808995671630924669697661065034121040761798775626517750047180) - - d = 256 - pointH = d * self.pointG - self.assertEqual(pointH.x, 42740085206947573681423002599456489563927820004573071834350074001818321593686) - self.assertEqual(pointH.y, 6935684722522267618220753829624209639984359598320562595061366101608187623111) - - def test_sizes(self): - self.assertEqual(self.pointG.size_in_bits(), 255) - self.assertEqual(self.pointG.size_in_bytes(), 32) - - -class TestEccKey_Ed25519(unittest.TestCase): - - def test_private_key(self): - seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") - Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046 - Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807 - - key = EccKey(curve="Ed25519", seed=seed) - self.assertEqual(key.seed, seed) - self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, Px) - self.assertEqual(key.pointQ.y, Py) - - point = EccPoint(Px, Py, "ed25519") - key = EccKey(curve="Ed25519", seed=seed, point=point) - self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="ed25519", seed=seed) - - # Must not accept d parameter - self.assertRaises(ValueError, EccKey, curve="ed25519", d=1) - - def test_public_key(self): - point = EccPoint(_curves['ed25519'].Gx, _curves['ed25519'].Gy, curve='ed25519') - key = EccKey(curve="ed25519", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - priv_key = EccKey(curve="ed25519", seed=b'H'*32) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_seed(self): - self.assertRaises(ValueError, lambda: EccKey(curve="ed25519", seed=b'H' * 31)) - - def test_equality(self): - private_key = ECC.construct(seed=b'H'*32, curve="Ed25519") - private_key2 = ECC.construct(seed=b'H'*32, curve="ed25519") - private_key3 = ECC.construct(seed=b'C'*32, curve="Ed25519") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='ed25519') - self.assertIn("curve='Ed25519'", repr(key)) - self.assertEqual(key.curve, 'Ed25519') - self.assertEqual(key.public_key().curve, 'Ed25519') - - -class TestEccModule_Ed25519(unittest.TestCase): - - def test_generate(self): - key = ECC.generate(curve="Ed25519") - self.assertTrue(key.has_private()) - point = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, curve="Ed25519") * key.d - self.assertEqual(key.pointQ, point) - - # Always random - key2 = ECC.generate(curve="Ed25519") - self.assertNotEqual(key, key2) - - # Other names - ECC.generate(curve="Ed25519") - - # Random source - key1 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read) - key2 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read) - self.assertEqual(key1, key2) - - def test_construct(self): - seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") - Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046 - Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807 - d = 36144925721603087658594284515452164870581325872720374094707712194495455132720 - point = EccPoint(Px, Py, curve="Ed25519") - - # Private key only - key = ECC.construct(curve="Ed25519", seed=seed) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Public key only - key = ECC.construct(curve="Ed25519", point_x=Px, point_y=Py) - self.assertEqual(key.pointQ, point) - self.assertFalse(key.has_private()) - - # Private and public key - key = ECC.construct(curve="Ed25519", seed=seed, point_x=Px, point_y=Py) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Other names - key = ECC.construct(curve="ed25519", seed=seed) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['ed25519'].Gx, point_y=_curves['ed25519'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="Ed25519", **coord) - self.assertRaises(ValueError, ECC.construct, curve="Ed25519", d=2, **coordG) - self.assertRaises(ValueError, ECC.construct, curve="Ed25519", seed=b'H'*31) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint_Ed25519) - tests += list_test_cases(TestEccKey_Ed25519) - tests += list_test_cases(TestEccModule_Ed25519) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed448.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed448.py deleted file mode 100644 index 5977287..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_Ed448.py +++ /dev/null @@ -1,336 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2022, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey - -from Crypto.Math.Numbers import Integer - -from Crypto.Hash import SHAKE128 - - -class TestEccPoint_Ed448(unittest.TestCase): - - Gxy = {"x": 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e, - "y": 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14} - - G2xy = {"x": 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555, - "y": 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed} - - G3xy = {"x": 0x865886b9108af6455bd64316cb6943332241b8b8cda82c7e2ba077a4a3fcfe8daa9cbf7f6271fd6e862b769465da8575728173286ff2f8f, - "y": 0xe005a8dbd5125cf706cbda7ad43aa6449a4a8d952356c3b9fce43c82ec4e1d58bb3a331bdb6767f0bffa9a68fed02dafb822ac13588ed6fc} - - pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed448") - pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed448") - pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed448") - - def test_curve_attribute(self): - self.assertEqual(self.pointG.curve, "Ed448") - - def test_init_xy(self): - EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed448") - - # Neutral point - pai = EccPoint(0, 1, curve="Ed448") - self.assertEqual(pai.x, 0) - self.assertEqual(pai.y, 1) - self.assertEqual(pai.xy, (0, 1)) - - # G - bp = self.pointG.copy() - self.assertEqual(bp.x, 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e) - self.assertEqual(bp.y, 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14) - self.assertEqual(bp.xy, (bp.x, bp.y)) - - # 2G - bp2 = self.pointG2.copy() - self.assertEqual(bp2.x, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555) - self.assertEqual(bp2.y, 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed) - self.assertEqual(bp2.xy, (bp2.x, bp2.y)) - - # 5G - EccPoint(x=0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034, - y=0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb, - curve="Ed448") - - # Catch if point is not on the curve - self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed448") - - def test_set(self): - pointW = EccPoint(0, 1, curve="Ed448") - pointW.set(self.pointG) - self.assertEqual(pointW.x, self.pointG.x) - self.assertEqual(pointW.y, self.pointG.y) - - def test_copy(self): - pointW = self.pointG.copy() - self.assertEqual(pointW.x, self.pointG.x) - self.assertEqual(pointW.y, self.pointG.y) - - def test_equal(self): - pointH = self.pointG.copy() - pointI = self.pointG2.copy() - self.assertEqual(self.pointG, pointH) - self.assertNotEqual(self.pointG, pointI) - - def test_pai(self): - pai = EccPoint(0, 1, curve="Ed448") - self.assertTrue(pai.is_point_at_infinity()) - self.assertEqual(pai, pai.point_at_infinity()) - - def test_negate(self): - negG = -self.pointG - sum = self.pointG + negG - self.assertTrue(sum.is_point_at_infinity()) - - def test_addition(self): - self.assertEqual(self.pointG + self.pointG2, self.pointG3) - self.assertEqual(self.pointG2 + self.pointG, self.pointG3) - self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2) - self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2) - - G5 = self.pointG2 + self.pointG3 - self.assertEqual(G5.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034) - self.assertEqual(G5.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb) - - def test_inplace_addition(self): - pointH = self.pointG.copy() - pointH += self.pointG - self.assertEqual(pointH, self.pointG2) - pointH += self.pointG - self.assertEqual(pointH, self.pointG3) - pointH += self.pointG.point_at_infinity() - self.assertEqual(pointH, self.pointG3) - - def test_doubling(self): - pointH = self.pointG.copy() - pointH.double() - self.assertEqual(pointH.x, self.pointG2.x) - self.assertEqual(pointH.y, self.pointG2.y) - - # 2*0 - pai = self.pointG.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - def test_scalar_multiply(self): - d = 0 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0) - self.assertEqual(pointH.y, 1) - - d = 1 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG.x) - self.assertEqual(pointH.y, self.pointG.y) - - d = 2 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG2.x) - self.assertEqual(pointH.y, self.pointG2.y) - - d = 3 - pointH = d * self.pointG - self.assertEqual(pointH.x, self.pointG3.x) - self.assertEqual(pointH.y, self.pointG3.y) - - d = 4 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0x49dcbc5c6c0cce2c1419a17226f929ea255a09cf4e0891c693fda4be70c74cc301b7bdf1515dd8ba21aee1798949e120e2ce42ac48ba7f30) - self.assertEqual(pointH.y, 0xd49077e4accde527164b33a5de021b979cb7c02f0457d845c90dc3227b8a5bc1c0d8f97ea1ca9472b5d444285d0d4f5b32e236f86de51839) - - d = 5 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034) - self.assertEqual(pointH.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb) - - d = 10 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0x77486f9d19f6411cdd35d30d1c3235f71936452c787e5c034134d3e8172278aca61622bc805761ce3dab65118a0122d73b403165d0ed303d) - self.assertEqual(pointH.y, 0x4d2fea0b026be11024f1f0fe7e94e618e8ac17381ada1d1bf7ee293a68ff5d0bf93c1997dc1aabdc0c7e6381428d85b6b1954a89e4cddf67) - - d = 20 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0x3c236422354600fe6763defcc1503737e4ed89e262d0de3ec1e552020f2a56fe3b9e1e012d021072598c3c2821e18268bb8fb8339c0d1216) - self.assertEqual(pointH.y, 0xb555b9721f630ccb05fc466de4c74d3d2781e69eca88e1b040844f04cab39fd946f91c688fa42402bb38fb9c3e61231017020b219b4396e1) - - d = 255 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0xbeb7f8388b05cd9c1aa2e3c0dcf31e2b563659361826225390e7748654f627d5c36cbe627e9019936b56d15d4dad7c337c09bac64ff4197f) - self.assertEqual(pointH.y, 0x1e37312b2dd4e9440c43c6e7725fc4fa3d11e582d4863f1d018e28f50c0efdb1f53f9b01ada7c87fa162b1f0d72401015d57613d25f1ad53) - - d = 256 - pointH = d * self.pointG - self.assertEqual(pointH.x, 0xf19c34feb56730e3e2be761ac0a2a2b24853b281dda019fc35a5ab58e3696beb39609ae756b0d20fb7ccf0d79aaf5f3bca2e4fdb25bfac1c) - self.assertEqual(pointH.y, 0x3beb69cc9111bffcaddc61d363ce6fe5dd44da4aadce78f52e92e985d5442344ced72c4611ed0daac9f4f5661eab73d7a12d25ce8a30241e) - - def test_sizes(self): - self.assertEqual(self.pointG.size_in_bits(), 448) - self.assertEqual(self.pointG.size_in_bytes(), 56) - - -class TestEccKey_Ed448(unittest.TestCase): - - def test_private_key(self): - seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9") - Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617 - Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1 - - key = EccKey(curve="Ed448", seed=seed) - self.assertEqual(key.seed, seed) - self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, Px) - self.assertEqual(key.pointQ.y, Py) - - point = EccPoint(Px, Py, "ed448") - key = EccKey(curve="Ed448", seed=seed, point=point) - self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="ed448", seed=seed) - - # Must not accept d parameter - self.assertRaises(ValueError, EccKey, curve="ed448", d=1) - - def test_public_key(self): - point = EccPoint(_curves['ed448'].Gx, _curves['ed448'].Gy, curve='ed448') - key = EccKey(curve="ed448", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - priv_key = EccKey(curve="ed448", seed=b'H'*57) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_seed(self): - self.assertRaises(ValueError, lambda: EccKey(curve="ed448", seed=b'H' * 56)) - - def test_equality(self): - private_key = ECC.construct(seed=b'H'*57, curve="Ed448") - private_key2 = ECC.construct(seed=b'H'*57, curve="ed448") - private_key3 = ECC.construct(seed=b'C'*57, curve="Ed448") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='ed448') - self.assertIn("curve='Ed448'", repr(key)) - self.assertEqual(key.curve, 'Ed448') - self.assertEqual(key.public_key().curve, 'Ed448') - - -class TestEccModule_Ed448(unittest.TestCase): - - def test_generate(self): - key = ECC.generate(curve="Ed448") - self.assertTrue(key.has_private()) - point = EccPoint(_curves['Ed448'].Gx, _curves['Ed448'].Gy, curve="Ed448") * key.d - self.assertEqual(key.pointQ, point) - - # Always random - key2 = ECC.generate(curve="Ed448") - self.assertNotEqual(key, key2) - - # Other names - ECC.generate(curve="Ed448") - - # Random source - key1 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read) - key2 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read) - self.assertEqual(key1, key2) - - def test_construct(self): - seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9") - Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617 - Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1 - d = 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80 - point = EccPoint(Px, Py, curve="Ed448") - - # Private key only - key = ECC.construct(curve="Ed448", seed=seed) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Public key only - key = ECC.construct(curve="Ed448", point_x=Px, point_y=Py) - self.assertEqual(key.pointQ, point) - self.assertFalse(key.has_private()) - - # Private and public key - key = ECC.construct(curve="Ed448", seed=seed, point_x=Px, point_y=Py) - self.assertEqual(key.pointQ, point) - self.assertTrue(key.has_private()) - - # Other names - key = ECC.construct(curve="ed448", seed=seed) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['ed448'].Gx, point_y=_curves['ed448'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="Ed448", **coord) - self.assertRaises(ValueError, ECC.construct, curve="Ed448", d=2, **coordG) - self.assertRaises(ValueError, ECC.construct, curve="Ed448", seed=b'H'*58) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint_Ed448) - tests += list_test_cases(TestEccKey_Ed448) - tests += list_test_cases(TestEccModule_Ed448) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_NIST.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_NIST.py deleted file mode 100644 index fa8dfe8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ECC_NIST.py +++ /dev/null @@ -1,1440 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey - -from Crypto.Math.Numbers import Integer - - -class TestEccPoint(unittest.TestCase): - - def test_mix(self): - - p1 = ECC.generate(curve='P-256').pointQ - p2 = ECC.generate(curve='P-384').pointQ - - try: - p1 + p2 - assert(False) - except ValueError as e: - assert "not on the same curve" in str(e) - - try: - p1 += p2 - assert(False) - except ValueError as e: - assert "not on the same curve" in str(e) - - class OtherKeyType: - pass - - self.assertFalse(p1 == OtherKeyType()) - self.assertTrue(p1 != OtherKeyType()) - - def test_repr(self): - p1 = ECC.construct(curve='P-256', - d=75467964919405407085864614198393977741148485328036093939970922195112333446269, - point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, - point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389) - self.assertEqual(repr(p1), "EccKey(curve='NIST P-256', point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389, d=75467964919405407085864614198393977741148485328036093939970922195112333446269)") - - -class TestEccPoint_NIST_P192(unittest.TestCase): - """Tests defined in section 4.1 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" - - pointS = EccPoint( - 0xd458e7d127ae671b0c330266d246769353a012073e97acf8, - 0x325930500d851f336bddc050cf7fb11b5673a1645086df3b, - curve='p192') - - pointT = EccPoint( - 0xf22c4395213e9ebe67ddecdd87fdbd01be16fb059b9753a4, - 0x264424096af2b3597796db48f8dfb41fa9cecc97691a9c79, - curve='p192') - - def test_curve_attribute(self): - self.assertEqual(self.pointS.curve, "NIST P-192") - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290 - pointRy = 0x408fa77c797cd7dbfb16aa48a3648d3d63c94117d7b6aa4b - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290 - pointRy = 0x408fa77c797cd7dbfb16aa48a3648d3d63c94117d7b6aa4b - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x30c5bc6b8c7da25354b373dc14dd8a0eba42d25a3f6e6962 - pointRy = 0x0dde14bc4249a721c407aedbf011e2ddbbcb2968c9d889cf - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee - pointRx = 0x1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31 - pointRy = 0x5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06 - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - # Reverse order - pointR = d * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pointR = Integer(d) * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_joint_scalar_multiply(self): - d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee - e = 0xc4be3d53ec3089e71e4de8ceab7cce889bc393cd85b972bc - pointRx = 0x019f64eed8fa9b72b7dfea82c17c9bfa60ecb9e1778b5bde - pointRy = 0x16590c5fcd8655fa4ced33fb800e2a7e3c61f35d83503644 - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 192) - self.assertEqual(self.pointS.size_in_bytes(), 24) - - -class TestEccPoint_NIST_P224(unittest.TestCase): - """Tests defined in section 4.2 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" - - pointS = EccPoint( - 0x6eca814ba59a930843dc814edd6c97da95518df3c6fdf16e9a10bb5b, - 0xef4b497f0963bc8b6aec0ca0f259b89cd80994147e05dc6b64d7bf22, - curve='p224') - - pointT = EccPoint( - 0xb72b25aea5cb03fb88d7e842002969648e6ef23c5d39ac903826bd6d, - 0xc42a8a4d34984f0b71b5b4091af7dceb33ea729c1a2dc8b434f10c34, - curve='p224') - - def test_curve_attribute(self): - self.assertEqual(self.pointS.curve, "NIST P-224") - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x236f26d9e84c2f7d776b107bd478ee0a6d2bcfcaa2162afae8d2fd15 - pointRy = 0xe53cc0a7904ce6c3746f6a97471297a0b7d5cdf8d536ae25bb0fda70 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x236f26d9e84c2f7d776b107bd478ee0a6d2bcfcaa2162afae8d2fd15 - pointRy = 0xe53cc0a7904ce6c3746f6a97471297a0b7d5cdf8d536ae25bb0fda70 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0xa9c96f2117dee0f27ca56850ebb46efad8ee26852f165e29cb5cdfc7 - pointRy = 0xadf18c84cf77ced4d76d4930417d9579207840bf49bfbf5837dfdd7d - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xa78ccc30eaca0fcc8e36b2dd6fbb03df06d37f52711e6363aaf1d73b - pointRx = 0x96a7625e92a8d72bff1113abdb95777e736a14c6fdaacc392702bca4 - pointRy = 0x0f8e5702942a3c5e13cd2fd5801915258b43dfadc70d15dbada3ed10 - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - # Reverse order - pointR = d * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pointR = Integer(d) * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_joing_scalar_multiply(self): - d = 0xa78ccc30eaca0fcc8e36b2dd6fbb03df06d37f52711e6363aaf1d73b - e = 0x54d549ffc08c96592519d73e71e8e0703fc8177fa88aa77a6ed35736 - pointRx = 0xdbfe2958c7b2cda1302a67ea3ffd94c918c5b350ab838d52e288c83e - pointRy = 0x2f521b83ac3b0549ff4895abcc7f0c5a861aacb87acbc5b8147bb18b - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 224) - self.assertEqual(self.pointS.size_in_bytes(), 28) - - -class TestEccPoint_NIST_P256(unittest.TestCase): - """Tests defined in section 4.3 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" - - pointS = EccPoint( - 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9, - 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256) - - pointT = EccPoint( - 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b, - 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316) - - def test_curve_attribute(self): - self.assertEqual(self.pointS.curve, "NIST P-256") - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x7669e6901606ee3ba1a8eef1e0024c33df6c22f3b17481b82a860ffcdb6127b0 - pointRy = 0xfa878162187a54f6c39f6ee0072f33de389ef3eecd03023de10ca2c1db61d0c7 - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - pointRx = 0x51d08d5f2d4278882946d88d83c97d11e62becc3cfc18bedacc89ba34eeca03f - pointRy = 0x75ee68eb8bf626aa5b673ab51f6e744e06f8fcf8a6c0cf3035beca956a7b41d5 - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - # Reverse order - pointR = d * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pointR = Integer(d) * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_joing_scalar_multiply(self): - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - e = 0xd37f628ece72a462f0145cbefe3f0b355ee8332d37acdd83a358016aea029db7 - pointRx = 0xd867b4679221009234939221b8046245efcf58413daacbeff857b8588341f6b8 - pointRy = 0xf2504055c03cede12d22720dad69c745106b6607ec7e50dd35d54bd80f615275 - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 256) - self.assertEqual(self.pointS.size_in_bytes(), 32) - - -class TestEccPoint_NIST_P384(unittest.TestCase): - """Tests defined in section 4.4 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" - - pointS = EccPoint( - 0xfba203b81bbd23f2b3be971cc23997e1ae4d89e69cb6f92385dda82768ada415ebab4167459da98e62b1332d1e73cb0e, - 0x5ffedbaefdeba603e7923e06cdb5d0c65b22301429293376d5c6944e3fa6259f162b4788de6987fd59aed5e4b5285e45, - "p384") - - pointT = EccPoint( - 0xaacc05202e7fda6fc73d82f0a66220527da8117ee8f8330ead7d20ee6f255f582d8bd38c5a7f2b40bcdb68ba13d81051, - 0x84009a263fefba7c2c57cffa5db3634d286131afc0fca8d25afa22a7b5dce0d9470da89233cee178592f49b6fecb5092, - "p384") - - def test_curve_attribute(self): - self.assertEqual(self.pointS.curve, "NIST P-384") - - def test_set(self): - pointW = EccPoint(0, 0, "p384") - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x12dc5ce7acdfc5844d939f40b4df012e68f865b89c3213ba97090a247a2fc009075cf471cd2e85c489979b65ee0b5eed - pointRy = 0x167312e58fe0c0afa248f2854e3cddcb557f983b3189b67f21eee01341e7e9fe67f6ee81b36988efa406945c8804a4b0 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def _test_inplace_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x2a2111b1e0aa8b2fc5a1975516bc4d58017ff96b25e1bdff3c229d5fac3bacc319dcbec29f9478f42dee597b4641504c - pointRy = 0xfa2e3d9dc84db8954ce8085ef28d7184fddfd1344b4d4797343af9b5f9d837520b450f726443e4114bd4e5bdb2f65ddd - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 - pointRx = 0xe4f77e7ffeb7f0958910e3a680d677a477191df166160ff7ef6bb5261f791aa7b45e3e653d151b95dad3d93ca0290ef2 - pointRy = 0xac7dee41d8c5f4a7d5836960a773cfc1376289d3373f8cf7417b0c6207ac32e913856612fc9ff2e357eb2ee05cf9667f - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - def test_joing_scalar_multiply(self): - d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 - e = 0xafcf88119a3a76c87acbd6008e1349b29f4ba9aa0e12ce89bcfcae2180b38d81ab8cf15095301a182afbc6893e75385d - pointRx = 0x917ea28bcd641741ae5d18c2f1bd917ba68d34f0f0577387dc81260462aea60e2417b8bdc5d954fc729d211db23a02dc - pointRy = 0x1a29f7ce6d074654d77b40888c73e92546c8f16a5ff6bcbd307f758d4aee684beff26f6742f597e2585c86da908f7186 - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 384) - self.assertEqual(self.pointS.size_in_bytes(), 48) - - -class TestEccPoint_NIST_P521(unittest.TestCase): - """Tests defined in section 4.5 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" - - pointS = EccPoint( - 0x000001d5c693f66c08ed03ad0f031f937443458f601fd098d3d0227b4bf62873af50740b0bb84aa157fc847bcf8dc16a8b2b8bfd8e2d0a7d39af04b089930ef6dad5c1b4, - 0x00000144b7770963c63a39248865ff36b074151eac33549b224af5c8664c54012b818ed037b2b7c1a63ac89ebaa11e07db89fcee5b556e49764ee3fa66ea7ae61ac01823, - "p521") - - pointT = EccPoint( - 0x000000f411f2ac2eb971a267b80297ba67c322dba4bb21cec8b70073bf88fc1ca5fde3ba09e5df6d39acb2c0762c03d7bc224a3e197feaf760d6324006fe3be9a548c7d5, - 0x000001fdf842769c707c93c630df6d02eff399a06f1b36fb9684f0b373ed064889629abb92b1ae328fdb45534268384943f0e9222afe03259b32274d35d1b9584c65e305, - "p521") - - def test_curve_attribute(self): - self.assertEqual(self.pointS.curve, "NIST P-521") - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 - pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 - pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x0000012879442f2450c119e7119a5f738be1f1eba9e9d7c6cf41b325d9ce6d643106e9d61124a91a96bcf201305a9dee55fa79136dc700831e54c3ca4ff2646bd3c36bc6 - pointRy = 0x0000019864a8b8855c2479cbefe375ae553e2393271ed36fadfc4494fc0583f6bd03598896f39854abeae5f9a6515a021e2c0eef139e71de610143f53382f4104dccb543 - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 - pointRx = 0x00000091b15d09d0ca0353f8f96b93cdb13497b0a4bb582ae9ebefa35eee61bf7b7d041b8ec34c6c00c0c0671c4ae063318fb75be87af4fe859608c95f0ab4774f8c95bb - pointRy = 0x00000130f8f8b5e1abb4dd94f6baaf654a2d5810411e77b7423965e0c7fd79ec1ae563c207bd255ee9828eb7a03fed565240d2cc80ddd2cecbb2eb50f0951f75ad87977f - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - def test_joing_scalar_multiply(self): - d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 - e = 0x00000137e6b73d38f153c3a7575615812608f2bab3229c92e21c0d1c83cfad9261dbb17bb77a63682000031b9122c2f0cdab2af72314be95254de4291a8f85f7c70412e3 - pointRx = 0x0000009d3802642b3bea152beb9e05fba247790f7fc168072d363340133402f2585588dc1385d40ebcb8552f8db02b23d687cae46185b27528adb1bf9729716e4eba653d - pointRy = 0x0000000fe44344e79da6f49d87c1063744e5957d9ac0a505bafa8281c9ce9ff25ad53f8da084a2deb0923e46501de5797850c61b229023dd9cf7fc7f04cd35ebb026d89d - - pointR = self.pointS * d - pointR += self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 521) - self.assertEqual(self.pointS.size_in_bytes(), 66) - - -class TestEccPoint_PAI_P192(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p192'] - pointG = EccPoint(curve.Gx, curve.Gy, "p192") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P192.txt", - "P-192 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P192, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P224(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p224'] - pointG = EccPoint(curve.Gx, curve.Gy, "p224") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P224.txt", - "P-224 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P224, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P256(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p256'] - pointG = EccPoint(curve.Gx, curve.Gy, "p256") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P256.txt", - "P-256 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P256, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P384(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p384'] - pointG = EccPoint(curve.Gx, curve.Gy, "p384") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P384.txt", - "P-384 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P384, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P521(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p521'] - pointG = EccPoint(curve.Gx, curve.Gy, "p521") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P521.txt", - "P-521 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P521, "test_%d" % tv.count, new_test) - - -class TestEccKey_P192(unittest.TestCase): - - def test_private_key(self): - - key = EccKey(curve="P-192", d=1) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, _curves['p192'].Gx) - self.assertEqual(key.pointQ.y, _curves['p192'].Gy) - - point = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, curve='P-192') - key = EccKey(curve="P-192", d=1, point=point) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="secp192r1", d=1) - key = EccKey(curve="prime192v1", d=1) - - def test_public_key(self): - - point = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, curve='P-192') - key = EccKey(curve="P-192", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-192", d=3) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-193", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-192", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-192", - d=_curves['p192'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-192") - private_key2 = ECC.construct(d=3, curve="P-192") - private_key3 = ECC.construct(d=4, curve="P-192") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='p192') - self.assertIn("curve='NIST P-192'", repr(key)) - self.assertEqual(key.curve, 'NIST P-192') - self.assertEqual(key.public_key().curve, 'NIST P-192') - - -class TestEccKey_P224(unittest.TestCase): - - def test_private_key(self): - - key = EccKey(curve="P-224", d=1) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, _curves['p224'].Gx) - self.assertEqual(key.pointQ.y, _curves['p224'].Gy) - - point = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, curve='P-224') - key = EccKey(curve="P-224", d=1, point=point) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="secp224r1", d=1) - key = EccKey(curve="prime224v1", d=1) - - def test_public_key(self): - - point = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, curve='P-224') - key = EccKey(curve="P-224", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-224", d=3) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-225", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-224", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-224", - d=_curves['p224'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-224") - private_key2 = ECC.construct(d=3, curve="P-224") - private_key3 = ECC.construct(d=4, curve="P-224") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='p224') - self.assertIn("curve='NIST P-224'", repr(key)) - self.assertEqual(key.curve, 'NIST P-224') - self.assertEqual(key.public_key().curve, 'NIST P-224') - - -class TestEccKey_P256(unittest.TestCase): - - def test_private_key(self): - - key = EccKey(curve="P-256", d=1) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, _curves['p256'].Gx) - self.assertEqual(key.pointQ.y, _curves['p256'].Gy) - - point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) - key = EccKey(curve="P-256", d=1, point=point) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="secp256r1", d=1) - key = EccKey(curve="prime256v1", d=1) - - # Must not accept d parameter - self.assertRaises(ValueError, EccKey, curve="p256", seed=b'H'*32) - - def test_public_key(self): - - point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) - key = EccKey(curve="P-256", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-256", d=3) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-257", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=_curves['p256'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-256") - private_key2 = ECC.construct(d=3, curve="P-256") - private_key3 = ECC.construct(d=4, curve="P-256") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='p256') - self.assertIn("curve='NIST P-256'", repr(key)) - self.assertEqual(key.curve, 'NIST P-256') - self.assertEqual(key.public_key().curve, 'NIST P-256') - - -class TestEccKey_P384(unittest.TestCase): - - def test_private_key(self): - - p384 = _curves['p384'] - - key = EccKey(curve="P-384", d=1) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, p384.Gx) - self.assertEqual(key.pointQ.y, p384.Gy) - - point = EccPoint(p384.Gx, p384.Gy, "p384") - key = EccKey(curve="P-384", d=1, point=point) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="p384", d=1) - key = EccKey(curve="secp384r1", d=1) - key = EccKey(curve="prime384v1", d=1) - - def test_public_key(self): - - p384 = _curves['p384'] - point = EccPoint(p384.Gx, p384.Gy, 'p384') - key = EccKey(curve="P-384", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-384", d=3) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-385", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-384", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-384", - d=_curves['p384'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-384") - private_key2 = ECC.construct(d=3, curve="P-384") - private_key3 = ECC.construct(d=4, curve="P-384") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='p384') - self.assertIn("curve='NIST P-384'", repr(key)) - self.assertEqual(key.curve, 'NIST P-384') - self.assertEqual(key.public_key().curve, 'NIST P-384') - - -class TestEccKey_P521(unittest.TestCase): - - def test_private_key(self): - - p521 = _curves['p521'] - - key = EccKey(curve="P-521", d=1) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ.x, p521.Gx) - self.assertEqual(key.pointQ.y, p521.Gy) - - point = EccPoint(p521.Gx, p521.Gy, "p521") - key = EccKey(curve="P-521", d=1, point=point) - self.assertEqual(key.d, 1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="p521", d=1) - key = EccKey(curve="secp521r1", d=1) - key = EccKey(curve="prime521v1", d=1) - - def test_public_key(self): - - p521 = _curves['p521'] - point = EccPoint(p521.Gx, p521.Gy, 'p521') - key = EccKey(curve="P-384", point=point) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-521", d=3) - pub_key = priv_key.public_key() - self.assertFalse(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-522", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-521", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-521", - d=_curves['p521'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-521") - private_key2 = ECC.construct(d=3, curve="P-521") - private_key3 = ECC.construct(d=4, curve="P-521") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - def test_name_consistency(self): - key = ECC.generate(curve='p521') - self.assertIn("curve='NIST P-521'", repr(key)) - self.assertEqual(key.curve, 'NIST P-521') - self.assertEqual(key.public_key().curve, 'NIST P-521') - - -class TestEccModule_P192(unittest.TestCase): - - def test_generate(self): - - key = ECC.generate(curve="P-192") - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(_curves['p192'].Gx, - _curves['p192'].Gy, - "P-192") * key.d, - "p192") - - # Other names - ECC.generate(curve="secp192r1") - ECC.generate(curve="prime192v1") - - def test_construct(self): - - key = ECC.construct(curve="P-192", d=1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, _curves['p192'].G) - - key = ECC.construct(curve="P-192", point_x=_curves['p192'].Gx, - point_y=_curves['p192'].Gy) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, _curves['p192'].G) - - # Other names - ECC.construct(curve="p192", d=1) - ECC.construct(curve="secp192r1", d=1) - ECC.construct(curve="prime192v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p192'].Gx, point_y=_curves['p192'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-192", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-192", d=2, **coordG) - - -class TestEccModule_P224(unittest.TestCase): - - def test_generate(self): - - key = ECC.generate(curve="P-224") - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(_curves['p224'].Gx, - _curves['p224'].Gy, - "P-224") * key.d, - "p224") - - # Other names - ECC.generate(curve="secp224r1") - ECC.generate(curve="prime224v1") - - def test_construct(self): - - key = ECC.construct(curve="P-224", d=1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, _curves['p224'].G) - - key = ECC.construct(curve="P-224", point_x=_curves['p224'].Gx, - point_y=_curves['p224'].Gy) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, _curves['p224'].G) - - # Other names - ECC.construct(curve="p224", d=1) - ECC.construct(curve="secp224r1", d=1) - ECC.construct(curve="prime224v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p224'].Gx, point_y=_curves['p224'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-224", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-224", d=2, **coordG) - - -class TestEccModule_P256(unittest.TestCase): - - def test_generate(self): - - key = ECC.generate(curve="P-256") - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(_curves['p256'].Gx, - _curves['p256'].Gy) * key.d, - "p256") - - # Other names - ECC.generate(curve="secp256r1") - ECC.generate(curve="prime256v1") - - def test_construct(self): - - key = ECC.construct(curve="P-256", d=1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, _curves['p256'].G) - - key = ECC.construct(curve="P-256", point_x=_curves['p256'].Gx, - point_y=_curves['p256'].Gy) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, _curves['p256'].G) - - # Other names - ECC.construct(curve="p256", d=1) - ECC.construct(curve="secp256r1", d=1) - ECC.construct(curve="prime256v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p256'].Gx, point_y=_curves['p256'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-256", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-256", d=2, **coordG) - - -class TestEccModule_P384(unittest.TestCase): - - def test_generate(self): - - curve = _curves['p384'] - key = ECC.generate(curve="P-384") - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p384") * key.d) - - # Other names - ECC.generate(curve="secp384r1") - ECC.generate(curve="prime384v1") - - def test_construct(self): - - curve = _curves['p384'] - key = ECC.construct(curve="P-384", d=1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, _curves['p384'].G) - - key = ECC.construct(curve="P-384", point_x=curve.Gx, point_y=curve.Gy) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, curve.G) - - # Other names - ECC.construct(curve="p384", d=1) - ECC.construct(curve="secp384r1", d=1) - ECC.construct(curve="prime384v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p384'].Gx, point_y=_curves['p384'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-384", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-384", d=2, **coordG) - - -class TestEccModule_P521(unittest.TestCase): - - def test_generate(self): - - curve = _curves['p521'] - key = ECC.generate(curve="P-521") - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p521") * key.d) - - # Other names - ECC.generate(curve="secp521r1") - ECC.generate(curve="prime521v1") - - def test_construct(self): - - curve = _curves['p521'] - key = ECC.construct(curve="P-521", d=1) - self.assertTrue(key.has_private()) - self.assertEqual(key.pointQ, _curves['p521'].G) - - key = ECC.construct(curve="P-521", point_x=curve.Gx, point_y=curve.Gy) - self.assertFalse(key.has_private()) - self.assertEqual(key.pointQ, curve.G) - - # Other names - ECC.construct(curve="p521", d=1) - ECC.construct(curve="secp521r1", d=1) - ECC.construct(curve="prime521v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p521'].Gx, point_y=_curves['p521'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-521", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-521", d=2, **coordG) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint) - tests += list_test_cases(TestEccPoint_NIST_P192) - tests += list_test_cases(TestEccPoint_NIST_P224) - tests += list_test_cases(TestEccPoint_NIST_P256) - tests += list_test_cases(TestEccPoint_NIST_P384) - tests += list_test_cases(TestEccPoint_NIST_P521) - tests += list_test_cases(TestEccPoint_PAI_P192) - tests += list_test_cases(TestEccPoint_PAI_P224) - tests += list_test_cases(TestEccPoint_PAI_P256) - tests += list_test_cases(TestEccPoint_PAI_P384) - tests += list_test_cases(TestEccPoint_PAI_P521) - tests += list_test_cases(TestEccKey_P192) - tests += list_test_cases(TestEccKey_P224) - tests += list_test_cases(TestEccKey_P256) - tests += list_test_cases(TestEccKey_P384) - tests += list_test_cases(TestEccKey_P521) - tests += list_test_cases(TestEccModule_P192) - tests += list_test_cases(TestEccModule_P224) - tests += list_test_cases(TestEccModule_P256) - tests += list_test_cases(TestEccModule_P384) - tests += list_test_cases(TestEccModule_P521) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ElGamal.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ElGamal.py deleted file mode 100644 index 0b394ae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_ElGamal.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_ElGamal.py: Self-test for the ElGamal primitive -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.ElGamal""" - -__revision__ = "$Id$" - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex -from Crypto import Random -from Crypto.PublicKey import ElGamal -from Crypto.Util.number import bytes_to_long -from Crypto.Util.py3compat import * - -class ElGamalTest(unittest.TestCase): - - # - # Test vectors - # - # There seem to be no real ElGamal test vectors available in the - # public domain. The following test vectors have been generated - # with libgcrypt 1.5.0. - # - # Encryption - tve=[ - { - # 256 bits - 'p' :'BA4CAEAAED8CBE952AFD2126C63EB3B345D65C2A0A73D2A3AD4138B6D09BD933', - 'g' :'05', - 'y' :'60D063600ECED7C7C55146020E7A31C4476E9793BEAED420FEC9E77604CAE4EF', - 'x' :'1D391BA2EE3C37FE1BA175A69B2C73A11238AD77675932', - 'k' :'F5893C5BAB4131264066F57AB3D8AD89E391A0B68A68A1', - 'pt' :'48656C6C6F207468657265', - 'ct1':'32BFD5F487966CEA9E9356715788C491EC515E4ED48B58F0F00971E93AAA5EC7', - 'ct2':'7BE8FBFF317C93E82FCEF9BD515284BA506603FEA25D01C0CB874A31F315EE68' - }, - - { - # 512 bits - 'p' :'F1B18AE9F7B4E08FDA9A04832F4E919D89462FD31BF12F92791A93519F75076D6CE3942689CDFF2F344CAFF0F82D01864F69F3AECF566C774CBACF728B81A227', - 'g' :'07', - 'y' :'688628C676E4F05D630E1BE39D0066178CA7AA83836B645DE5ADD359B4825A12B02EF4252E4E6FA9BEC1DB0BE90F6D7C8629CABB6E531F472B2664868156E20C', - 'x' :'14E60B1BDFD33436C0DA8A22FDC14A2CCDBBED0627CE68', - 'k' :'38DBF14E1F319BDA9BAB33EEEADCAF6B2EA5250577ACE7', - 'pt' :'48656C6C6F207468657265', - 'ct1':'290F8530C2CC312EC46178724F196F308AD4C523CEABB001FACB0506BFED676083FE0F27AC688B5C749AB3CB8A80CD6F7094DBA421FB19442F5A413E06A9772B', - 'ct2':'1D69AAAD1DC50493FB1B8E8721D621D683F3BF1321BE21BC4A43E11B40C9D4D9C80DE3AAC2AB60D31782B16B61112E68220889D53C4C3136EE6F6CE61F8A23A0' - } - ] - - # Signature - tvs=[ - { - # 256 bits - 'p' :'D2F3C41EA66530838A704A48FFAC9334F4701ECE3A97CEE4C69DD01AE7129DD7', - 'g' :'05', - 'y' :'C3F9417DC0DAFEA6A05C1D2333B7A95E63B3F4F28CC962254B3256984D1012E7', - 'x' :'165E4A39BE44D5A2D8B1332D416BC559616F536BC735BB', - 'k' :'C7F0C794A7EAD726E25A47FF8928013680E73C51DD3D7D99BFDA8F492585928F', - 'h' :'48656C6C6F207468657265', - 'sig1':'35CA98133779E2073EF31165AFCDEB764DD54E96ADE851715495F9C635E1E7C2', - 'sig2':'0135B88B1151279FE5D8078D4FC685EE81177EE9802AB123A73925FC1CB059A7', - }, - { - # 512 bits - 'p' :'E24CF3A4B8A6AF749DCA6D714282FE4AABEEE44A53BB6ED15FBE32B5D3C3EF9CC4124A2ECA331F3C1C1B667ACA3766825217E7B5F9856648D95F05330C6A19CF', - 'g' :'0B', - 'y' :'2AD3A1049CA5D4ED207B2431C79A8719BB4073D4A94E450EA6CEE8A760EB07ADB67C0D52C275EE85D7B52789061EE45F2F37D9B2AE522A51C28329766BFE68AC', - 'x' :'16CBB4F46D9ECCF24FF9F7E63CAA3BD8936341555062AB', - 'k' :'8A3D89A4E429FD2476D7D717251FB79BF900FFE77444E6BB8299DC3F84D0DD57ABAB50732AE158EA52F5B9E7D8813E81FD9F79470AE22F8F1CF9AEC820A78C69', - 'h' :'48656C6C6F207468657265', - 'sig1':'BE001AABAFFF976EC9016198FBFEA14CBEF96B000CCC0063D3324016F9E91FE80D8F9325812ED24DDB2B4D4CF4430B169880B3CE88313B53255BD4EC0378586F', - 'sig2':'5E266F3F837BA204E3BBB6DBECC0611429D96F8C7CE8F4EFDF9D4CB681C2A954468A357BF4242CEC7418B51DFC081BCD21299EF5B5A0DDEF3A139A1817503DDE', - } - ] - - def test_generate_180(self): - self._test_random_key(180) - - def test_encryption(self): - for tv in self.tve: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - ct = key._encrypt(d['pt'], d['k']) - self.assertEqual(ct[0], d['ct1']) - self.assertEqual(ct[1], d['ct2']) - - def test_decryption(self): - for tv in self.tve: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - pt = key._decrypt((d['ct1'], d['ct2'])) - self.assertEqual(pt, d['pt']) - - def test_signing(self): - for tv in self.tvs: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - sig1, sig2 = key._sign(d['h'], d['k']) - self.assertEqual(sig1, d['sig1']) - self.assertEqual(sig2, d['sig2']) - - def test_verification(self): - for tv in self.tvs: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - # Positive test - res = key._verify( d['h'], (d['sig1'],d['sig2']) ) - self.assertTrue(res) - # Negative test - res = key._verify( d['h'], (d['sig1']+1,d['sig2']) ) - self.assertFalse(res) - - def test_bad_key3(self): - tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key'])[:3] - tup[0] += 1 # p += 1 (not prime) - self.assertRaises(ValueError, ElGamal.construct, tup) - - tup = tup0 - tup[1] = 1 # g = 1 - self.assertRaises(ValueError, ElGamal.construct, tup) - - tup = tup0 - tup[2] = tup[0]*2 # y = 2*p - self.assertRaises(ValueError, ElGamal.construct, tup) - - def test_bad_key4(self): - tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key']) - tup[3] += 1 # x += 1 - self.assertRaises(ValueError, ElGamal.construct, tup) - - def convert_tv(self, tv, as_longs=0): - """Convert a test vector from textual form (hexadecimal ascii - to either integers or byte strings.""" - key_comps = 'p','g','y','x' - tv2 = {} - for c in tv.keys(): - tv2[c] = a2b_hex(tv[c]) - if as_longs or c in key_comps or c in ('sig1','sig2'): - tv2[c] = bytes_to_long(tv2[c]) - tv2['key']=[] - for c in key_comps: - tv2['key'] += [tv2[c]] - del tv2[c] - return tv2 - - def _test_random_key(self, bits): - elgObj = ElGamal.generate(bits, Random.new().read) - self._check_private_key(elgObj) - self._exercise_primitive(elgObj) - pub = elgObj.publickey() - self._check_public_key(pub) - self._exercise_public_primitive(elgObj) - - def _check_private_key(self, elgObj): - - # Check capabilities - self.assertTrue(elgObj.has_private()) - - # Sanity check key data - self.assertTrue(1 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.RSA""" - -__revision__ = "$Id$" - -import os -import pickle -from pickle import PicklingError -from Crypto.Util.py3compat import * - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex - -class RSATest(unittest.TestCase): - # Test vectors from "RSA-OAEP and RSA-PSS test vectors (.zip file)" - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # See RSADSI's PKCS#1 page at - # http://www.rsa.com/rsalabs/node.asp?id=2125 - - # from oaep-int.txt - - # TODO: PyCrypto treats the message as starting *after* the leading "00" - # TODO: That behaviour should probably be changed in the future. - plaintext = """ - eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2 - ca 82 31 0b 26 dc d8 7d 5c 68 f1 ee a8 f5 52 67 - c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af - f9 3e dc fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db - 4c dc fe 4f f4 77 28 b4 a1 b7 c1 36 2b aa d2 9a - b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9 - 82 fb 3e 87 d0 95 ae b4 04 48 db 97 2f 3a c1 4f - 7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35 3e 2d - """ - - ciphertext = """ - 12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 - 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 - 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 - 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb - 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 - 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 - da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d - 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55 - """ - - modulus = """ - bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 - 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f - b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 - 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f - af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 - ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e - e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f - e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb - """ - - e = 0x11 # public exponent - - prime_factor = """ - c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35 - 3f 6c 42 d0 88 66 b1 d0 5a 0f 20 35 02 8b 9d 86 - 98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf - ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03 - """ - - def setUp(self): - global RSA, Random, bytes_to_long - from Crypto.PublicKey import RSA - from Crypto import Random - from Crypto.Util.number import bytes_to_long, inverse - self.n = bytes_to_long(a2b_hex(self.modulus)) - self.p = bytes_to_long(a2b_hex(self.prime_factor)) - - # Compute q, d, and u from n, e, and p - self.q = self.n // self.p - self.d = inverse(self.e, (self.p-1)*(self.q-1)) - self.u = inverse(self.p, self.q) # u = e**-1 (mod q) - - self.rsa = RSA - - def test_generate_1arg(self): - """RSA (default implementation) generated key (1 argument)""" - rsaObj = self.rsa.generate(1024) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - - def test_generate_2arg(self): - """RSA (default implementation) generated key (2 arguments)""" - rsaObj = self.rsa.generate(1024, Random.new().read) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - - def test_generate_3args(self): - rsaObj = self.rsa.generate(1024, Random.new().read,e=65537) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - self.assertEqual(65537,rsaObj.e) - - def test_construct_2tuple(self): - """RSA (default implementation) constructed key (2-tuple)""" - pub = self.rsa.construct((self.n, self.e)) - self._check_public_key(pub) - self._check_encryption(pub) - - def test_construct_3tuple(self): - """RSA (default implementation) constructed key (3-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d)) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_4tuple(self): - """RSA (default implementation) constructed key (4-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p)) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_5tuple(self): - """RSA (default implementation) constructed key (5-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) - self._check_private_key(rsaObj) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_6tuple(self): - """RSA (default implementation) constructed key (6-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, self.u)) - self._check_private_key(rsaObj) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_bad_key2(self): - tup = (self.n, 1) - self.assertRaises(ValueError, self.rsa.construct, tup) - - # An even modulus is wrong - tup = (self.n+1, self.e) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key3(self): - tup = (self.n, self.e, self.d+1) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key5(self): - tup = (self.n, self.e, self.d, self.p, self.p) - self.assertRaises(ValueError, self.rsa.construct, tup) - - tup = (self.p*self.p, self.e, self.p, self.p) - self.assertRaises(ValueError, self.rsa.construct, tup) - - tup = (self.p*self.p, 3, self.p, self.q) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key6(self): - tup = (self.n, self.e, self.d, self.p, self.q, 10) - self.assertRaises(ValueError, self.rsa.construct, tup) - - from Crypto.Util.number import inverse - tup = (self.n, self.e, self.d, self.p, self.q, inverse(self.q, self.p)) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_factoring(self): - rsaObj = self.rsa.construct([self.n, self.e, self.d]) - self.assertTrue(rsaObj.p==self.p or rsaObj.p==self.q) - self.assertTrue(rsaObj.q==self.p or rsaObj.q==self.q) - self.assertTrue(rsaObj.q*rsaObj.p == self.n) - - self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1]) - - def test_repr(self): - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) - repr(rsaObj) - - def test_serialization(self): - """RSA keys are unpickable""" - - rsa_key = self.rsa.generate(1024) - self.assertRaises(PicklingError, pickle.dumps, rsa_key) - - def test_raw_rsa_boundary(self): - # The argument of every RSA raw operation (encrypt/decrypt) must be - # non-negative and no larger than the modulus - rsa_obj = self.rsa.generate(1024) - - self.assertRaises(ValueError, rsa_obj._decrypt, rsa_obj.n) - self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, rsa_obj.n) - self.assertRaises(ValueError, rsa_obj._encrypt, rsa_obj.n) - - self.assertRaises(ValueError, rsa_obj._decrypt, -1) - self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, -1) - self.assertRaises(ValueError, rsa_obj._encrypt, -1) - - def test_size(self): - pub = self.rsa.construct((self.n, self.e)) - self.assertEqual(pub.size_in_bits(), 1024) - self.assertEqual(pub.size_in_bytes(), 128) - - def _check_private_key(self, rsaObj): - from Crypto.Math.Numbers import Integer - - # Check capabilities - self.assertEqual(1, rsaObj.has_private()) - - # Sanity check key data - self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq - lcm = int(Integer(rsaObj.p-1).lcm(rsaObj.q-1)) - self.assertEqual(1, rsaObj.d * rsaObj.e % lcm) # ed = 1 (mod LCM(p-1, q-1)) - self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q) - self.assertEqual(1, rsaObj.p > 1) # p > 1 - self.assertEqual(1, rsaObj.q > 1) # q > 1 - self.assertEqual(1, rsaObj.e > 1) # e > 1 - self.assertEqual(1, rsaObj.d > 1) # d > 1 - - self.assertEqual(rsaObj.u, rsaObj.invp) - self.assertEqual(1, rsaObj.q * rsaObj.invq % rsaObj.p) - - def _check_public_key(self, rsaObj): - ciphertext = a2b_hex(self.ciphertext) - - # Check capabilities - self.assertEqual(0, rsaObj.has_private()) - - # Check rsaObj.[ne] -> rsaObj.[ne] mapping - self.assertEqual(rsaObj.n, rsaObj.n) - self.assertEqual(rsaObj.e, rsaObj.e) - - # Check that private parameters are all missing - self.assertEqual(0, hasattr(rsaObj, 'd')) - self.assertEqual(0, hasattr(rsaObj, 'p')) - self.assertEqual(0, hasattr(rsaObj, 'q')) - self.assertEqual(0, hasattr(rsaObj, 'u')) - - # Sanity check key data - self.assertEqual(1, rsaObj.e > 1) # e > 1 - - # Public keys should not be able to sign or decrypt - self.assertRaises(TypeError, rsaObj._decrypt, - bytes_to_long(ciphertext)) - self.assertRaises(TypeError, rsaObj._decrypt_to_bytes, - bytes_to_long(ciphertext)) - - # Check __eq__ and __ne__ - self.assertEqual(rsaObj.public_key() == rsaObj.public_key(),True) # assert_ - self.assertEqual(rsaObj.public_key() != rsaObj.public_key(),False) # assertFalse - - self.assertEqual(rsaObj.publickey(), rsaObj.public_key()) - - def _exercise_primitive(self, rsaObj): - # Since we're using a randomly-generated key, we can't check the test - # vector, but we can make sure encryption and decryption are inverse - # operations. - ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) - - # Test decryption - plaintext = rsaObj._decrypt(ciphertext) - - # Test encryption (2 arguments) - new_ciphertext2 = rsaObj._encrypt(plaintext) - self.assertEqual(ciphertext, new_ciphertext2) - - def _exercise_public_primitive(self, rsaObj): - plaintext = a2b_hex(self.plaintext) - - # Test encryption (2 arguments) - new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) - - def _check_encryption(self, rsaObj): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - - # Test encryption - new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) - self.assertEqual(bytes_to_long(ciphertext), new_ciphertext2) - - def _check_decryption(self, rsaObj): - plaintext = bytes_to_long(a2b_hex(self.plaintext)) - ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) - - # Test plain decryption - new_plaintext = rsaObj._decrypt(ciphertext) - self.assertEqual(plaintext, new_plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(RSATest) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve25519.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve25519.py deleted file mode 100644 index 71cd162..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve25519.py +++ /dev/null @@ -1,385 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2024, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import errno -import warnings -import unittest -from binascii import unhexlify -from unittest import SkipTest - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tostr, FileNotFoundError -from Crypto.Util.asn1 import DerSequence, DerBitString -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "ECC") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for ECC", - UserWarning, - stacklevel=2) - - if results is None: - raise SkipTest("Missing %s" % file_name) - - return results - - -def compact(lines): - ext = b"".join(lines) - return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) - - -def create_ref_keys_x25519(): - key_lines = load_file("ecc_x25519.txt").splitlines() - seed = compact(key_lines[5:8]) - key = ECC.construct(curve="Curve25519", seed=seed) - return (key, key.public_key()) - - -def get_fixed_prng(): - return SHAKE128.new().update(b"SEED").read - - -def extract_bitstring_from_spki(data): - seq = DerSequence() - seq.decode(data) - bs = DerBitString() - bs.decode(seq[1]) - return bs.value - - -class TestImport(unittest.TestCase): - - def test_empty(self): - self.assertRaises(ValueError, ECC.import_key, b"") - - def test_mismatch(self): - # Private key with X448 Object ID but X25519 key - mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79" - mismatch = unhexlify(mismatch_hex) - self.assertRaises(ValueError, ECC.import_key, mismatch) - - -class TestImport_Curve25519(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_Curve25519, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_x25519() - - def test_import_public_der(self): - key_file = load_file("ecc_x25519_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_pkcs8_der(self): - key_file = load_file("ecc_x25519_private.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_x25519_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_x25519_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_x25519_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_x25519_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_x25519_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_x25519_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256": - key_file = load_file("ecc_x25519_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_x25519_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - -class TestExport_Curve25519(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_Curve25519, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_x25519() - - def test_export_public_der(self): - key_file = load_file("ecc_x25519_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(True) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_x25519_private.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - self.assertRaises(ValueError, self.ref_private.export_key, - format="DER", use_pkcs8=False) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", - prot_params={'iteration_count': 123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem(self): - key_file_ref = load_file("ecc_x25519_public.pem", "rt").strip() - key_file = self.ref_public.export_key(format="PEM").strip() - self.assertEqual(key_file_ref, key_file) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_x25519_private.pem", "rt").strip() - encoded = self.ref_private.export_key(format="PEM").strip() - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_raw(self): - encoded = self.ref_public.export_key(format='raw') - self.assertEqual(len(encoded), 32) - self.assertEqual(encoded, unhexlify(b'ff7561ef60c9c8a757f6d6372ec14142c9be208d0e719136d8d3c715dfcf7e15')) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="secret") - - # Empty password - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="", - use_pkcs8=False) - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, - self.ref_private.export_key, - format="OpenSSH", - passphrase="secret") - - -class TestImport_Curve25519_Weak(unittest.TestCase): - - def test_weak_pem(self): - - p = 2**255 - 19 - weak_x = (0, - 1, - 325606250916557431795983626356110631294008115727848805560023387167927233504, - 39382357235489614581723060781553021112529911719440698176882885853963445705823, - p - 1, - p, - p + 1, - p + 325606250916557431795983626356110631294008115727848805560023387167927233504, - p + 39382357235489614581723060781553021112529911719440698176882885853963445705823, - p * 2 - 1, - p * 2, - p * 2 + 1) - - for x in weak_x: - low_order_point = ECC.EccXPoint(x, "curve25519") - weak_key = ECC.EccKey(point=low_order_point, curve="curve25519") - encoded = weak_key.export_key(format="PEM") - - self.assertRaises(ValueError, - ECC.import_key, - encoded) - - -def get_tests(config={}): - tests = [] - try: - tests += list_test_cases(TestImport) - tests += list_test_cases(TestImport_Curve25519) - tests += list_test_cases(TestExport_Curve25519) - tests += list_test_cases(TestImport_Curve25519_Weak) - except SkipTest: - pass - return tests - - -if __name__ == '__main__': - def suit(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve448.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve448.py deleted file mode 100644 index e2fdb17..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_Curve448.py +++ /dev/null @@ -1,351 +0,0 @@ -# This file is licensed under the BSD 2-Clause License. -# See https://opensource.org/licenses/BSD-2-Clause for details. - -import os -import errno -import warnings -import unittest -from binascii import unhexlify -from unittest import SkipTest - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tostr, FileNotFoundError -from Crypto.Util.asn1 import DerSequence, DerBitString -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "ECC") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for ECC", - UserWarning, - stacklevel=2) - - if results is None: - raise SkipTest("Missing %s" % file_name) - - return results - - -def compact(lines): - ext = b"".join(lines) - return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) - - -def create_ref_keys_x448(): - key_lines = load_file("ecc_x448.txt").splitlines() - seed = compact(key_lines[6:10]) - key = ECC.construct(curve="Curve448", seed=seed) - return (key, key.public_key()) - - -def get_fixed_prng(): - return SHAKE128.new().update(b"SEED").read - - -def extract_bitstring_from_spki(data): - seq = DerSequence() - seq.decode(data) - bs = DerBitString() - bs.decode(seq[1]) - return bs.value - - -class TestImport(unittest.TestCase): - - def test_empty(self): - self.assertRaises(ValueError, ECC.import_key, b"") - - def test_mismatch(self): - # Private key with X448 Object ID but X448 key - mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79" - mismatch = unhexlify(mismatch_hex) - self.assertRaises(ValueError, ECC.import_key, mismatch) - - -class TestImport_Curve448(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_Curve448, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_x448() - - def test_import_public_der(self): - key_file = load_file("ecc_x448_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_pkcs8_der(self): - key_file = load_file("ecc_x448_private.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_x448_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_x448_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_x448_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_x448_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_x448_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_x448_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256": - key_file = load_file("ecc_x448_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_x448_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - -class TestExport_Curve448(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_Curve448, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_x448() - - def test_export_public_der(self): - key_file = load_file("ecc_x448_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(True) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_x448_private.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - self.assertRaises(ValueError, self.ref_private.export_key, - format="DER", use_pkcs8=False) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", - prot_params={'iteration_count': 123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem(self): - key_file_ref = load_file("ecc_x448_public.pem", "rt").strip() - key_file = self.ref_public.export_key(format="PEM").strip() - self.assertEqual(key_file_ref, key_file) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_x448_private.pem", "rt").strip() - encoded = self.ref_private.export_key(format="PEM").strip() - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_raw(self): - encoded = self.ref_public.export_key(format='raw') - self.assertEqual(len(encoded), 56) - self.assertEqual(encoded, unhexlify(b'e2abae24ab8f65b01969e61f84fee615b525f413a90e3d727f71d0ffe60fb1d0a1a0285f2a7fd88789206e0aa4f3e9fcb9e4ba5d644e691e')) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="secret") - - # Empty password - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="", - use_pkcs8=False) - self.assertRaises(ValueError, - self.ref_private.export_key, - format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, - self.ref_private.export_key, - format="OpenSSH", - passphrase="secret") - - -class TestImport_Curve448_Weak(unittest.TestCase): - - def test_weak_pem(self): - - p = 2**448 - 2**224 - 1 - weak_x = (0, - 1, - p - 1, - p, - p + 1) - - for x in weak_x: - low_order_point = ECC.EccXPoint(x, "curve448") - weak_key = ECC.EccKey(point=low_order_point, curve="curve448") - encoded = weak_key.export_key(format="PEM") - - self.assertRaises(ValueError, - ECC.import_key, - encoded) - - -def get_tests(config={}): - tests = [] - try: - tests += list_test_cases(TestImport) - tests += list_test_cases(TestImport_Curve448) - tests += list_test_cases(TestExport_Curve448) - tests += list_test_cases(TestImport_Curve448_Weak) - except SkipTest: - pass - return tests - - -if __name__ == '__main__': - def suit(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_DSA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_DSA.py deleted file mode 100644 index 266b46f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_DSA.py +++ /dev/null @@ -1,554 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_import_DSA.py: Self-test for importing DSA keys -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import unittest -import re - -from Crypto.PublicKey import DSA -from Crypto.SelfTest.st_common import * -from Crypto.Util.py3compat import * - -from binascii import unhexlify - -class ImportKeyTests(unittest.TestCase): - - y = 92137165128186062214622779787483327510946462589285775188003362705875131352591574106484271700740858696583623951844732128165434284507709057439633739849986759064015013893156866539696757799934634945787496920169462601722830899660681779448742875054459716726855443681559131362852474817534616736104831095601710736729 - p = 162452170958135306109773853318304545923250830605675936228618290525164105310663722368377131295055868997377338797580997938253236213714988311430600065853662861806894003694743806769284131194035848116051021923956699231855223389086646903420682639786976554552864568460372266462812137447840653688476258666833303658691 - q = 988791743931120302950649732173330531512663554851 - g = 85583152299197514738065570254868711517748965097380456700369348466136657764813442044039878840094809620913085570225318356734366886985903212775602770761953571967834823306046501307810937486758039063386311593890777319935391363872375452381836756832784184928202587843258855704771836753434368484556809100537243908232 - x = 540873410045082450874416847965843801027716145253 - - def setUp(self): - - # It is easier to write test vectors in text form, - # and convert them to byte strigs dynamically here - for mname, mvalue in ImportKeyTests.__dict__.items(): - if mname[:4] in ('der_', 'pem_', 'ssh_'): - if mname[:4] == 'der_': - mvalue = unhexlify(tobytes(mvalue)) - mvalue = tobytes(mvalue) - setattr(self, mname, mvalue) - - # 1. SubjectPublicKeyInfo - der_public=\ - '308201b73082012b06072a8648ce3804013082011e02818100e756ee1717f4b6'+\ - '794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a2757695ec91'+\ - '5697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8b81b47'+\ - '9a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656cecb4c'+\ - '8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad32f48c'+\ - 'd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb7eaeae'+\ - '3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466cf444f3'+\ - '4b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b92370040a'+\ - 'ca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074b41c56'+\ - 'ae43fd300d89262e4efd89943f99a651b03888038185000281810083352a69a1'+\ - '32f34843d2a0eb995bff4e2f083a73f0049d2c91ea2f0ce43d144abda48199e4'+\ - 'b003c570a8af83303d45105f606c5c48d925a40ed9c2630c2fa4cdbf838539de'+\ - 'b9a29f919085f2046369f627ca84b2cb1e2c7940564b670f963ab1164d4e2ca2'+\ - 'bf6ffd39f12f548928bf4d2d1b5e6980b4f1be4c92a91986fba559' - - def testImportKey1(self): - key_obj = DSA.importKey(self.der_public) - self.assertFalse(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey1(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('DER') - self.assertEqual(self.der_public, encoded) - - # 2. - pem_public="""\ ------BEGIN PUBLIC KEY----- -MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/ -j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtH -mjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2 -qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzrfq6u -NxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa -5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxW -rkP9MA2JJi5O/YmUP5mmUbA4iAOBhQACgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPw -BJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTne -uaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmA -tPG+TJKpGYb7pVk= ------END PUBLIC KEY-----""" - - def testImportKey2(self): - for pem in (self.pem_public, tostr(self.pem_public)): - key_obj = DSA.importKey(pem) - self.assertFalse(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey2(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('PEM') - self.assertEqual(self.pem_public, encoded) - - # 3. OpenSSL/OpenSSH format - der_private=\ - '308201bb02010002818100e756ee1717f4b6794c7c214724a19763742c45572b'+\ - '4b3f8ff3b44f3be9f44ce039a2757695ec915697da74ef914fcd1b05660e2419'+\ - 'c761d639f45d2d79b802dbd23e7ab8b81b479a380e1f30932584ba2a0b955032'+\ - '342ebc83cb5ca906e7b0d7cd6fe656cecb4c8b5a77123a8c6750a481e3b06057'+\ - 'aff6aa6eba620b832d60c3021500ad32f48cd3ae0c45a198a61fa4b5e2032076'+\ - '3b2302818079dfdc3d614fe635fceb7eaeae3718dc2efefb45282993ac6749dc'+\ - '83c223d8c1887296316b3b0b54466cf444f34b82e3554d0b90a778faaf1306f0'+\ - '25dae6a3e36c7f93dd5bac4052b92370040aca70b8d5820599711900efbc9618'+\ - '12c355dd9beffe0981da85c5548074b41c56ae43fd300d89262e4efd89943f99'+\ - 'a651b038880281810083352a69a132f34843d2a0eb995bff4e2f083a73f0049d'+\ - '2c91ea2f0ce43d144abda48199e4b003c570a8af83303d45105f606c5c48d925'+\ - 'a40ed9c2630c2fa4cdbf838539deb9a29f919085f2046369f627ca84b2cb1e2c'+\ - '7940564b670f963ab1164d4e2ca2bf6ffd39f12f548928bf4d2d1b5e6980b4f1'+\ - 'be4c92a91986fba55902145ebd9a3f0b82069d98420986b314215025756065' - - def testImportKey3(self): - key_obj = DSA.importKey(self.der_private) - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey3(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('DER', pkcs8=False) - self.assertEqual(self.der_private, encoded) - - # 4. - pem_private="""\ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQDnVu4XF/S2eUx8IUckoZdjdCxFVytLP4/ztE876fRM4DmidXaV -7JFWl9p075FPzRsFZg4kGcdh1jn0XS15uALb0j56uLgbR5o4Dh8wkyWEuioLlVAy -NC68g8tcqQbnsNfNb+ZWzstMi1p3EjqMZ1CkgeOwYFev9qpuumILgy1gwwIVAK0y -9IzTrgxFoZimH6S14gMgdjsjAoGAed/cPWFP5jX8636urjcY3C7++0UoKZOsZ0nc -g8Ij2MGIcpYxazsLVEZs9ETzS4LjVU0LkKd4+q8TBvAl2uaj42x/k91brEBSuSNw -BArKcLjVggWZcRkA77yWGBLDVd2b7/4JgdqFxVSAdLQcVq5D/TANiSYuTv2JlD+Z -plGwOIgCgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LAD -xXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4s -eUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVkCFF69mj8L -ggadmEIJhrMUIVAldWBl ------END DSA PRIVATE KEY-----""" - - def testImportKey4(self): - for pem in (self.pem_private, tostr(self.pem_private)): - key_obj = DSA.importKey(pem) - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey4(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM', pkcs8=False) - self.assertEqual(self.pem_private, encoded) - - # 5. PKCS8 (unencrypted) - der_pkcs8=\ - '3082014a0201003082012b06072a8648ce3804013082011e02818100e756ee17'+\ - '17f4b6794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a27576'+\ - '95ec915697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8'+\ - 'b81b479a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656'+\ - 'cecb4c8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad'+\ - '32f48cd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb'+\ - '7eaeae3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466c'+\ - 'f444f34b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b923'+\ - '70040aca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074'+\ - 'b41c56ae43fd300d89262e4efd89943f99a651b03888041602145ebd9a3f0b82'+\ - '069d98420986b314215025756065' - - def testImportKey5(self): - key_obj = DSA.importKey(self.der_pkcs8) - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey5(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('DER') - self.assertEqual(self.der_pkcs8, encoded) - encoded = key.export_key('DER', pkcs8=True) - self.assertEqual(self.der_pkcs8, encoded) - - # 6. - pem_pkcs8="""\ ------BEGIN PRIVATE KEY----- -MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVX -K0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4 -uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47Bg -V6/2qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzr -fq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG -8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0 -tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAQWAhRevZo/C4IGnZhCCYazFCFQJXVgZQ== ------END PRIVATE KEY-----""" - - def testImportKey6(self): - for pem in (self.pem_pkcs8, tostr(self.pem_pkcs8)): - key_obj = DSA.importKey(pem) - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey6(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM') - self.assertEqual(self.pem_pkcs8, encoded) - encoded = key.export_key('PEM', pkcs8=True) - self.assertEqual(self.pem_pkcs8, encoded) - - # 7. OpenSSH/RFC4253 - ssh_pub="""ssh-dss AAAAB3NzaC1kc3MAAACBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2qm66YguDLWDDAAAAFQCtMvSM064MRaGYph+kteIDIHY7IwAAAIB539w9YU/mNfzrfq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAAAAIEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVk=""" - - def testImportKey7(self): - for ssh in (self.ssh_pub, tostr(self.ssh_pub)): - key_obj = DSA.importKey(ssh) - self.assertFalse(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey7(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('OpenSSH') - self.assertEqual(self.ssh_pub, encoded) - - # 8. Encrypted OpenSSL/OpenSSH - pem_private_encrypted="""\ ------BEGIN DSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-128-CBC,70B6908939D65E9F2EB999E8729788CE - -4V6GHRDpCrdZ8MBjbyp5AlGUrjvr2Pn2e2zVxy5RBt4FBj9/pa0ae0nnyUPMLSUU -kKyOR0topRYTVRLElm4qVrb5uNZ3hRwfbklr+pSrB7O9eHz9V5sfOQxyODS07JxK -k1OdOs70/ouMXLF9EWfAZOmWUccZKHNblUwg1p1UrZIz5jXw4dUE/zqhvXh6d+iC -ADsICaBCjCrRQJKDp50h3+ndQjkYBKVH+pj8TiQ79U7lAvdp3+iMghQN6YXs9mdI -gFpWw/f97oWM4GHZFqHJ+VSMNFjBiFhAvYV587d7Lk4dhD8sCfbxj42PnfRgUItc -nnPqHxmhMQozBWzYM4mQuo3XbF2WlsNFbOzFVyGhw1Bx1s91qvXBVWJh2ozrW0s6 -HYDV7ZkcTml/4kjA/d+mve6LZ8kuuR1qCiZx6rkffhh1gDN/1Xz3HVvIy/dQ+h9s -5zp7PwUoWbhqp3WCOr156P6gR8qo7OlT6wMh33FSXK/mxikHK136fV2shwTKQVII -rJBvXpj8nACUmi7scKuTWGeUoXa+dwTZVVe+b+L2U1ZM7+h/neTJiXn7u99PFUwu -xVJtxaV37m3aXxtCsPnbBg== ------END DSA PRIVATE KEY-----""" - - def testImportKey8(self): - for pem in (self.pem_private_encrypted, tostr(self.pem_private_encrypted)): - key_obj = DSA.importKey(pem, "PWDTEST") - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey8(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM', pkcs8=False, passphrase="PWDTEST") - key = DSA.importKey(encoded, "PWDTEST") - self.assertEqual(self.y, key.y) - self.assertEqual(self.p, key.p) - self.assertEqual(self.q, key.q) - self.assertEqual(self.g, key.g) - self.assertEqual(self.x, key.x) - - # 9. Encrypted PKCS8 - # pbeWithMD5AndDES-CBC - pem_pkcs8_encrypted="""\ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIBcTAbBgkqhkiG9w0BBQMwDgQI0GC3BJ/jSw8CAggABIIBUHc1cXZpExIE9tC7 -7ryiW+5ihtF2Ekurq3e408GYSAu5smJjN2bvQXmzRFBz8W38K8eMf1sbWroZ4+zn -kZSbb9nSm5kAa8lR2+oF2k+WRswMR/PTC3f/D9STO2X0QxdrzKgIHEcSGSHp5jTx -aVvbkCDHo9vhBTl6S3ogZ48As/MEro76+9igUwJ1jNhIQZPJ7e20QH5qDpQFFJN4 -CKl2ENSEuwGiqBszItFy4dqH0g63ZGZV/xt9wSO9Rd7SK/EbA/dklOxBa5Y/VItM -gnIhs9XDMoGYyn6F023EicNJm6g/bVQk81BTTma4tm+12TKGdYm+QkeZvCOMZylr -Wv67cKwO3cAXt5C3QXMDgYR64XvuaT5h7C0igMp2afSXJlnbHEbFxQVJlv83T4FM -eZ4k+NQDbEL8GiHmFxzDWQAuPPZKJWEEEV2p/To+WOh+kSDHQw== ------END ENCRYPTED PRIVATE KEY-----""" - - def testImportKey9(self): - for pem in (self.pem_pkcs8_encrypted, tostr(self.pem_pkcs8_encrypted)): - key_obj = DSA.importKey(pem, "PWDTEST") - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - # 10. Encrypted PKCS8 - # pkcs5PBES2 / - # pkcs5PBKDF2 (rounds=1000, salt=D725BF1B6B8239F4) / - # des-EDE3-CBC (iv=27A1C66C42AFEECE) - # - der_pkcs8_encrypted=\ - '30820196304006092a864886f70d01050d3033301b06092a864886f70d01050c'+\ - '300e0408d725bf1b6b8239f4020203e8301406082a864886f70d0307040827a1'+\ - 'c66c42afeece048201505cacfde7bf8edabb3e0d387950dc872662ea7e9b1ed4'+\ - '400d2e7e6186284b64668d8d0328c33a9d9397e6f03df7cb68268b0a06b4e22f'+\ - '7d132821449ecf998a8b696dbc6dd2b19e66d7eb2edfeb4153c1771d49702395'+\ - '4f36072868b5fcccf93413a5ac4b2eb47d4b3f681c6bd67ae363ed776f45ae47'+\ - '174a00098a7c930a50f820b227ddf50f9742d8e950d02586ff2dac0e3c372248'+\ - 'e5f9b6a7a02f4004f20c87913e0f7b52bccc209b95d478256a890b31d4c9adec'+\ - '21a4d157a179a93a3dad06f94f3ce486b46dfa7fc15fd852dd7680bbb2f17478'+\ - '7e71bd8dbaf81eca7518d76c1d26256e95424864ba45ca5d47d7c5a421be02fa'+\ - 'b94ab01e18593f66cf9094eb5c94b9ecf3aa08b854a195cf87612fbe5e96c426'+\ - '2b0d573e52dc71ba3f5e468c601e816c49b7d32c698b22175e89aaef0c443770'+\ - '5ef2f88a116d99d8e2869a4fd09a771b84b49e4ccb79aadcb1c9' - - def testImportKey10(self): - key_obj = DSA.importKey(self.der_pkcs8_encrypted, "PWDTEST") - self.assertTrue(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey10(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - randfunc = BytesIO(unhexlify(b("27A1C66C42AFEECE") + b("D725BF1B6B8239F4"))).read - encoded = key.export_key('DER', pkcs8=True, passphrase="PWDTEST", randfunc=randfunc) - self.assertEqual(self.der_pkcs8_encrypted, encoded) - - # ---- - - def testImportError1(self): - self.assertRaises(ValueError, DSA.importKey, self.der_pkcs8_encrypted, "wrongpwd") - - def testExportError2(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - self.assertRaises(ValueError, key.export_key, 'DER', pkcs8=False, passphrase="PWDTEST") - - def test_import_key(self): - """Verify importKey is an alias to import_key""" - - key_obj = DSA.import_key(self.der_public) - self.assertFalse(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def test_exportKey(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - self.assertEqual(key.exportKey(), key.export_key()) - - - def test_import_empty(self): - self.assertRaises(ValueError, DSA.import_key, b'') - - -class ImportKeyFromX509Cert(unittest.TestCase): - - def test_x509v1(self): - - # Sample V1 certificate with a 1024 bit DSA key - x509_v1_cert = """ ------BEGIN CERTIFICATE----- -MIIDUjCCArsCAQIwDQYJKoZIhvcNAQEFBQAwfjENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT -Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG -A1UEAxMEdGVzdDAeFw0xNDA3MTEyMDM4NDNaFw0xNzA0MDYyMDM4NDNaME0xCzAJ -BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxDzANBgNVBAMTBnBvbGFuZDCCAbYwggErBgcqhkjOOAQBMIIBHgKB -gQDOrN4Ox4+t3T6wKeHfhzArhcrNEFMQ4Ss+4PIKyimDy9Bn64WPkL1B/9dvYIga -23GLu6tVJmXo6EdJnVOHEMhr99EeOwuDWWeP7Awq7RSlKEejokr4BEzMTW/tExSD -cO6/GI7xzh0eTH+VTTPDfyrJMYCkh0rJAfCP+5xrmPNetwIVALtXYOV1yoRrzJ2Q -M5uEjidH6GiZAoGAfUqA1SAm5g5U68SILMVX9l5rq0OpB0waBMpJQ31/R/yXNDqo -c3gGWZTOJFU4IzwNpGhrGNADUByz/lc1SAOAdEJIr0JVrhbGewQjB4pWqoLGbBKz -RoavTNDc/zD7SYa12evWDHADwvlXoeQg+lWop1zS8OqaDC7aLGKpWN3/m8kDgYQA -AoGAKoirPAfcp1rbbl4y2FFAIktfW8f4+T7d2iKSg73aiVfujhNOt1Zz1lfC0NI2 -eonLWO3tAM4XGKf1TLjb5UXngGn40okPsaA81YE6ZIKm20ywjlOY3QkAEdMaLVY3 -9PJvM8RGB9m7pLKxyHfGMfF40MVN4222zKeGp7xhM0CNiCUwDQYJKoZIhvcNAQEF -BQADgYEAfbNZfpYa2KlALEM1FZnwvQDvJHntHz8LdeJ4WM7CXDlKi67wY2HKM30w -s2xej75imkVOFd1kF2d0A8sjfriXLVIt1Hwq9ANZomhu4Edx0xpH8tqdh/bDtnM2 -TmduZNY9OWkb07h0CtWD6Zt8fhRllVsSSrlWd/2or7FXNC5weFQ= ------END CERTIFICATE----- - """.strip() - - # DSA public key as dumped by openssl - y_str = """ -2a:88:ab:3c:07:dc:a7:5a:db:6e:5e:32:d8:51:40: -22:4b:5f:5b:c7:f8:f9:3e:dd:da:22:92:83:bd:da: -89:57:ee:8e:13:4e:b7:56:73:d6:57:c2:d0:d2:36: -7a:89:cb:58:ed:ed:00:ce:17:18:a7:f5:4c:b8:db: -e5:45:e7:80:69:f8:d2:89:0f:b1:a0:3c:d5:81:3a: -64:82:a6:db:4c:b0:8e:53:98:dd:09:00:11:d3:1a: -2d:56:37:f4:f2:6f:33:c4:46:07:d9:bb:a4:b2:b1: -c8:77:c6:31:f1:78:d0:c5:4d:e3:6d:b6:cc:a7:86: -a7:bc:61:33:40:8d:88:25 - """ - p_str = """ -00:ce:ac:de:0e:c7:8f:ad:dd:3e:b0:29:e1:df:87: -30:2b:85:ca:cd:10:53:10:e1:2b:3e:e0:f2:0a:ca: -29:83:cb:d0:67:eb:85:8f:90:bd:41:ff:d7:6f:60: -88:1a:db:71:8b:bb:ab:55:26:65:e8:e8:47:49:9d: -53:87:10:c8:6b:f7:d1:1e:3b:0b:83:59:67:8f:ec: -0c:2a:ed:14:a5:28:47:a3:a2:4a:f8:04:4c:cc:4d: -6f:ed:13:14:83:70:ee:bf:18:8e:f1:ce:1d:1e:4c: -7f:95:4d:33:c3:7f:2a:c9:31:80:a4:87:4a:c9:01: -f0:8f:fb:9c:6b:98:f3:5e:b7 - """ - q_str = """ -00:bb:57:60:e5:75:ca:84:6b:cc:9d:90:33:9b:84: -8e:27:47:e8:68:99 - """ - g_str = """ -7d:4a:80:d5:20:26:e6:0e:54:eb:c4:88:2c:c5:57: -f6:5e:6b:ab:43:a9:07:4c:1a:04:ca:49:43:7d:7f: -47:fc:97:34:3a:a8:73:78:06:59:94:ce:24:55:38: -23:3c:0d:a4:68:6b:18:d0:03:50:1c:b3:fe:57:35: -48:03:80:74:42:48:af:42:55:ae:16:c6:7b:04:23: -07:8a:56:aa:82:c6:6c:12:b3:46:86:af:4c:d0:dc: -ff:30:fb:49:86:b5:d9:eb:d6:0c:70:03:c2:f9:57: -a1:e4:20:fa:55:a8:a7:5c:d2:f0:ea:9a:0c:2e:da: -2c:62:a9:58:dd:ff:9b:c9 - """ - - key = DSA.importKey(x509_v1_cert) - for comp_name in ('y', 'p', 'q', 'g'): - comp_str = locals()[comp_name + "_str"] - comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) - self.assertEqual(getattr(key, comp_name), comp) - self.assertFalse(key.has_private()) - - def test_x509v3(self): - - # Sample V3 certificate with a 1024 bit DSA key - x509_v3_cert = """ ------BEGIN CERTIFICATE----- -MIIFhjCCA26gAwIBAgIBAzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD -QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTMyMDUz -MjBaFw0xNzA0MDgyMDUzMjBaMEAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES -MBAGA1UEBwwJQmFsdGltb3JlMRAwDgYDVQQDDAdhdXN0cmlhMIIBtjCCASsGByqG -SM44BAEwggEeAoGBALfd8gyEpVPA0ZI69Kp3nyJcu5N0ZZ3K1K9hleQLNqKEcZOh -7a/C2J1TPdmHTLJ0rAwBZ1nWxnARSgRphziGDFspKCYQwYcSMz8KoFgvXbXpuchy -oFACiQ2LqZnc5MakuLQtLcQciSYGYj3zmZdYMoa904F1aDWr+DxQI6DVC3/bAhUA -hqXMCJ6fQK3G2O9S3/CC/yVZXCsCgYBRXROl3R2khX7l10LQjDEgo3B1IzjXU/jP -McMBl6XO+nBJXxr/scbq8Ajiv7LTnGpSjgryHtvfj887kfvo8QbSS3kp3vq5uSqI -ui7E7r3jguWaLj616AG1HWOctXJUjqsiabZwsp2h09gHTzmHEXBOmiARu8xFxKAH -xsuo7onAbwOBhAACgYBylWjWSnKHE8mHx1A5m/0GQx6xnhWIe3+MJAnEhRGxA2J4 -SCsfWU0OwglIQToh1z5uUU9oDi9cYgNPBevOFRnDhc2yaJY6VAYnI+D+6J5IU6Yd -0iaG/iSc4sV4bFr0axcPpse3SN0XaQxiKeSFBfFnoMqL+dd9Gb3QPZSllBcVD6OB -1TCB0jAdBgNVHQ4EFgQUx5wN0Puotv388M9Tp/fsPbZpzAUwHwYDVR0jBBgwFoAU -a0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwSgYD -VR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIQbWFpbC5leGFt -cGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM -IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAyWf1TiJI -aNEIA9o/PG8/JiGASTS2/HBVTJbkq03k6NkJVk/GxC1DPziTUJ+CdWlHWcAi1EOW -Ach3QxNDRrVfCOfCMDgElIO1094/reJgdFYG00LRi8QkRJuxANV7YS4tLudhyHJC -kR2lhdMNmEuzWK+s2y+5cLrdm7qdvdENQCcV67uvGPx4sc+EaE7x13SczKjWBtbo -QCs6JTOW+EkPRl4Zo27K4OIZ43/J+GxvwU9QUVH3wPVdbbLNw+QeTFBYMTEcxyc4 -kv50HPBFaithziXBFyvdIs19FjkFzu0Uz/e0zb1+vMzQlJMD94HVOrMnIj5Sb2cL -KKdYXS4uhxFJmdV091Xur5JkYYwEzuaGav7J3zOzYutrIGTgDluLCvA+VQkRcTsy -jZ065SkY/v+38QHp+cmm8WRluupJTs8wYzVp6Fu0iFaaK7ztFmaZmHpiPIfDFjva -aCIgzzT5NweJd/b71A2SyzHXJ14zBXsr1PMylMp2TpHIidhuuNuQL6I0HaollB4M -Z3FsVBMhVDw4Z76qnFPr8mZE2tar33hSlJI/3pS/bBiukuBk8U7VB0X8OqaUnP3C -7b2Z4G8GtqDVcKGMzkvMjT4n9rKd/Le+qHSsQOGO9W/0LB7UDAZSwUsfAPnoBgdS -5t9tIomLCOstByXi+gGZue1TcdCa3Ph4kO0= ------END CERTIFICATE----- - """.strip() - - # DSA public key as dumped by openssl - y_str = """ -72:95:68:d6:4a:72:87:13:c9:87:c7:50:39:9b:fd: -06:43:1e:b1:9e:15:88:7b:7f:8c:24:09:c4:85:11: -b1:03:62:78:48:2b:1f:59:4d:0e:c2:09:48:41:3a: -21:d7:3e:6e:51:4f:68:0e:2f:5c:62:03:4f:05:eb: -ce:15:19:c3:85:cd:b2:68:96:3a:54:06:27:23:e0: -fe:e8:9e:48:53:a6:1d:d2:26:86:fe:24:9c:e2:c5: -78:6c:5a:f4:6b:17:0f:a6:c7:b7:48:dd:17:69:0c: -62:29:e4:85:05:f1:67:a0:ca:8b:f9:d7:7d:19:bd: -d0:3d:94:a5:94:17:15:0f - """ - p_str = """ -00:b7:dd:f2:0c:84:a5:53:c0:d1:92:3a:f4:aa:77: -9f:22:5c:bb:93:74:65:9d:ca:d4:af:61:95:e4:0b: -36:a2:84:71:93:a1:ed:af:c2:d8:9d:53:3d:d9:87: -4c:b2:74:ac:0c:01:67:59:d6:c6:70:11:4a:04:69: -87:38:86:0c:5b:29:28:26:10:c1:87:12:33:3f:0a: -a0:58:2f:5d:b5:e9:b9:c8:72:a0:50:02:89:0d:8b: -a9:99:dc:e4:c6:a4:b8:b4:2d:2d:c4:1c:89:26:06: -62:3d:f3:99:97:58:32:86:bd:d3:81:75:68:35:ab: -f8:3c:50:23:a0:d5:0b:7f:db - """ - q_str = """ -00:86:a5:cc:08:9e:9f:40:ad:c6:d8:ef:52:df:f0: -82:ff:25:59:5c:2b - """ - g_str = """ -51:5d:13:a5:dd:1d:a4:85:7e:e5:d7:42:d0:8c:31: -20:a3:70:75:23:38:d7:53:f8:cf:31:c3:01:97:a5: -ce:fa:70:49:5f:1a:ff:b1:c6:ea:f0:08:e2:bf:b2: -d3:9c:6a:52:8e:0a:f2:1e:db:df:8f:cf:3b:91:fb: -e8:f1:06:d2:4b:79:29:de:fa:b9:b9:2a:88:ba:2e: -c4:ee:bd:e3:82:e5:9a:2e:3e:b5:e8:01:b5:1d:63: -9c:b5:72:54:8e:ab:22:69:b6:70:b2:9d:a1:d3:d8: -07:4f:39:87:11:70:4e:9a:20:11:bb:cc:45:c4:a0: -07:c6:cb:a8:ee:89:c0:6f - """ - - key = DSA.importKey(x509_v3_cert) - for comp_name in ('y', 'p', 'q', 'g'): - comp_str = locals()[comp_name + "_str"] - comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) - self.assertEqual(getattr(key, comp_name), comp) - self.assertFalse(key.has_private()) - - -if __name__ == '__main__': - unittest.main() - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ImportKeyTests) - tests += list_test_cases(ImportKeyFromX509Cert) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_ECC.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_ECC.py deleted file mode 100644 index 16f2162..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_ECC.py +++ /dev/null @@ -1,2782 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import errno -import warnings -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import bord, tostr, FileNotFoundError -from Crypto.Util.asn1 import DerSequence, DerBitString -from Crypto.Util.number import bytes_to_long -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC - -from Crypto.PublicKey.ECC import _import_rfc5915_der - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -class MissingTestVectorException(ValueError): - pass - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "ECC") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Skipping extended tests for ECC", - UserWarning, - stacklevel=2) - - if results is None: - raise MissingTestVectorException("Missing %s" % file_name) - - return results - - -def compact(lines): - ext = b"".join(lines) - return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) - - -def create_ref_keys_p192(): - key_len = 24 - key_lines = load_file("ecc_p192.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:4])) - public_key_xy = compact(key_lines[5:9]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-192", d=private_key_d), - ECC.construct(curve="P-192", point_x=public_key_x, point_y=public_key_y)) - - -def create_ref_keys_p224(): - key_len = 28 - key_lines = load_file("ecc_p224.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:4])) - public_key_xy = compact(key_lines[5:9]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-224", d=private_key_d), - ECC.construct(curve="P-224", point_x=public_key_x, point_y=public_key_y)) - - -def create_ref_keys_p256(): - key_len = 32 - key_lines = load_file("ecc_p256.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:5])) - public_key_xy = compact(key_lines[6:11]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-256", d=private_key_d), - ECC.construct(curve="P-256", point_x=public_key_x, point_y=public_key_y)) - - -def create_ref_keys_p384(): - key_len = 48 - key_lines = load_file("ecc_p384.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:6])) - public_key_xy = compact(key_lines[7:14]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-384", d=private_key_d), - ECC.construct(curve="P-384", point_x=public_key_x, point_y=public_key_y)) - - -def create_ref_keys_p521(): - key_len = 66 - key_lines = load_file("ecc_p521.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:7])) - public_key_xy = compact(key_lines[8:17]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-521", d=private_key_d), - ECC.construct(curve="P-521", point_x=public_key_x, point_y=public_key_y)) - - -def create_ref_keys_ed25519(): - key_lines = load_file("ecc_ed25519.txt").splitlines() - seed = compact(key_lines[5:8]) - key = ECC.construct(curve="Ed25519", seed=seed) - return (key, key.public_key()) - - -def create_ref_keys_ed448(): - key_lines = load_file("ecc_ed448.txt").splitlines() - seed = compact(key_lines[6:10]) - key = ECC.construct(curve="Ed448", seed=seed) - return (key, key.public_key()) - - -# Create reference key pair -# ref_private, ref_public = create_ref_keys_p521() - -def get_fixed_prng(): - return SHAKE128.new().update(b"SEED").read - - -def extract_bitstring_from_spki(data): - seq = DerSequence() - seq.decode(data) - bs = DerBitString() - bs.decode(seq[1]) - return bs.value - - -class TestImport(unittest.TestCase): - - def test_empty(self): - self.assertRaises(ValueError, ECC.import_key, b"") - - def test_mismatch(self): - # The private key does not match the public key - mismatch = """-----BEGIN PRIVATE KEY----- -MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJChZANiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXk= ------END PRIVATE KEY-----""" - self.assertRaises(ValueError, ECC.import_key, mismatch) - - def test_import_private_rfc5915_none(self): - # ECPrivateKey with a P256 private key, without [0] and [1] - data_hex = "302502010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052" - key = _import_rfc5915_der(unhexlify(data_hex), None, "1.2.840.10045.3.1.7") - self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) - - def test_import_private_rfc5915_only_0(self): - # ECPrivateKey with a P256 private key, with [0] only - data_hex = "303102010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052a00a06082a8648ce3d030107" - key = _import_rfc5915_der(unhexlify(data_hex), None) - self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) - - def test_import_private_rfc5915_only_1(self): - # ECPrivateKey with a P256 private key, with [1] only - data_hex = "306b02010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052a14403420004a40ad59a2050ebe92479bd5fb16bb2e45b6465eb3cb2b1effe423fabe6cb7424db8219ef0bab80acf26fd70595b61fe4760d33eed80dd03d2fd0dfb27b8ce75c" - key = _import_rfc5915_der(unhexlify(data_hex), None, "1.2.840.10045.3.1.7") - self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) - -class TestImport_P192(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P192, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p192() - - def test_import_public_der(self): - key_file = load_file("ecc_p192_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_sec1_uncompressed(self): - key_file = load_file("ecc_p192_public.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P192') - self.assertEqual(self.ref_public, key) - - def test_import_sec1_compressed(self): - key_file = load_file("ecc_p192_public_compressed.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P192') - self.assertEqual(self.ref_public, key) - - def test_import_rfc5915_der(self): - key_file = load_file("ecc_p192_private.der") - - key = ECC._import_rfc5915_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p192_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p192_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p192_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p192_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p192_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p192_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p192_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p192_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p192_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - -class TestImport_P224(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P224, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p224() - - def test_import_public_der(self): - key_file = load_file("ecc_p224_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_sec1_uncompressed(self): - key_file = load_file("ecc_p224_public.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P224') - self.assertEqual(self.ref_public, key) - - def test_import_sec1_compressed(self): - key_file = load_file("ecc_p224_public_compressed.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P224') - self.assertEqual(self.ref_public, key) - - def test_import_rfc5915_der(self): - key_file = load_file("ecc_p224_private.der") - - key = ECC._import_rfc5915_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p224_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p224_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p224_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p224_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_p224_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p224_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p224_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p224_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p224_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p224_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - -class TestImport_P256(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P256, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p256() - - def test_import_public_der(self): - key_file = load_file("ecc_p256_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_sec1_uncompressed(self): - key_file = load_file("ecc_p256_public.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P256') - self.assertEqual(self.ref_public, key) - - def test_import_sec1_compressed(self): - key_file = load_file("ecc_p256_public_compressed.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P256') - self.assertEqual(self.ref_public, key) - - def test_import_rfc5915_der(self): - key_file = load_file("ecc_p256_private.der") - - key = ECC._import_rfc5915_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p256_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p256_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_p256_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p256_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p256_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p256_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_with_ecparams(self): - key_file = load_file("ecc_p256_private_ecparams.pem") - key = ECC.import_key(key_file) - # We just check if the import succeeds - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p256_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p256_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p256_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p256_private_openssh.pem") - key_file_old = load_file("ecc_p256_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p256_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p256_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestImport_P384(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P384, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p384() - - def test_import_public_der(self): - key_file = load_file("ecc_p384_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_sec1_uncompressed(self): - key_file = load_file("ecc_p384_public.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P384') - self.assertEqual(self.ref_public, key) - - def test_import_sec1_compressed(self): - key_file = load_file("ecc_p384_public_compressed.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P384') - self.assertEqual(self.ref_public, key) - - def test_import_rfc5915_der(self): - key_file = load_file("ecc_p384_private.der") - - key = ECC._import_rfc5915_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p384_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p384_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_p384_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p384_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p384_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p384_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p384_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p384_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p384_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p384_private_openssh.pem") - key_file_old = load_file("ecc_p384_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p384_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p384_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestImport_P521(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P521, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p521() - - def test_import_public_der(self): - key_file = load_file("ecc_p521_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_sec1_uncompressed(self): - key_file = load_file("ecc_p521_public.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P521') - self.assertEqual(self.ref_public, key) - - def test_import_sec1_compressed(self): - key_file = load_file("ecc_p521_public_compressed.der") - value = extract_bitstring_from_spki(key_file) - key = ECC.import_key(key_file, curve_name='P521') - self.assertEqual(self.ref_public, key) - - def test_import_rfc5915_der(self): - key_file = load_file("ecc_p521_private.der") - - key = ECC._import_rfc5915_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p521_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p521_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_p521_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p521_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p521_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p521_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p521_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p521_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p521_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p521_private_openssh.pem") - key_file_old = load_file("ecc_p521_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p521_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p521_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestExport_P192(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P192, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p192() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p192_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p192_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p192_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_public_sec1_uncompressed(self): - key_file = load_file("ecc_p192_public.der") - value = extract_bitstring_from_spki(key_file) - - encoded = self.ref_public.export_key(format="SEC1") - self.assertEqual(value, encoded) - - def test_export_public_sec1_compressed(self): - key_file = load_file("ecc_p192_public.der") - encoded = self.ref_public.export_key(format="SEC1", compress=True) - - key_file_compressed_ref = load_file("ecc_p192_public_compressed.der") - value = extract_bitstring_from_spki(key_file_compressed_ref) - self.assertEqual(value, encoded) - - def test_export_rfc5915_private_der(self): - key_file = load_file("ecc_p192_private.der") - - encoded = self.ref_private._export_rfc5915_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p192_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA224AndAES192-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p192_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p192_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p192_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p192_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p192_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - def test_compressed_curve(self): - - # Compressed P-192 curve (Y-point is even) - pem1 = """-----BEGIN EC PRIVATE KEY----- - MF8CAQEEGHvhXmIW95JxZYfd4AUPu9BwknjuvS36aqAKBggqhkjOPQMBAaE0AzIA - BLJZCyTu35DQIlqvMlBynn3k1Ig+dWfg/brRhHecxptrbloqFSP8ITw0CwbGF+2X - 5g== - -----END EC PRIVATE KEY-----""" - - # Compressed P-192 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- - MF8CAQEEGA3rAotUaWl7d47eX6tz9JmLzOMJwl13XaAKBggqhkjOPQMBAaE0AzIA - BG4tHlTBBBGokcWmGm2xubVB0NvPC/Ou5AYwivs+3iCxmEjsymVAj6iiuX2Lxr6g - /Q== - -----END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x97E6) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0xA0FD) - - -class TestExport_P224(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P224, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p224() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p224_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p224_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p224_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_public_sec1_uncompressed(self): - key_file = load_file("ecc_p224_public.der") - value = extract_bitstring_from_spki(key_file) - - encoded = self.ref_public.export_key(format="SEC1") - self.assertEqual(value, encoded) - - def test_export_public_sec1_compressed(self): - key_file = load_file("ecc_p224_public.der") - encoded = self.ref_public.export_key(format="SEC1", compress=True) - - key_file_compressed_ref = load_file("ecc_p224_public_compressed.der") - value = extract_bitstring_from_spki(key_file_compressed_ref) - self.assertEqual(value, encoded) - - def test_export_rfc5915_private_der(self): - key_file = load_file("ecc_p224_private.der") - - encoded = self.ref_private._export_rfc5915_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p224_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA512-224AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p224_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p224_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p224_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p224_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p224_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - def test_compressed_curve(self): - - # Compressed P-224 curve (Y-point is even) - pem1 = """-----BEGIN EC PRIVATE KEY----- - MGgCAQEEHPYicBNI9nd6wDKAX2l+f3A0Q+KWUQeMqSt5GoOgBwYFK4EEACGhPAM6 - AATCL6rUIDT14zXKoS5GQUMDP/tpc+1iI/FyEZikt2roKDkhU5q08srmqaysbfJN - eUr7Xf1lnCVGag== - -----END EC PRIVATE KEY-----""" - - # Compressed P-224 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- - MGgCAQEEHEFjbaVPLJ3ngZyCibCvT0RLUqSlHjC5Z3e0FtugBwYFK4EEACGhPAM6 - AAT5IvL2V6m48y1JLMGr6ZbnOqNKP9hMf9mxyVkk6/SaRoBoJVkXrNIpYL0P7DS7 - QF8E/OGeZRwvow== - -----END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x466A) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0x2FA3) - - -class TestExport_P256(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P256, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p256() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p256_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p256_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p256_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_public_sec1_uncompressed(self): - key_file = load_file("ecc_p256_public.der") - value = extract_bitstring_from_spki(key_file) - - encoded = self.ref_public.export_key(format="SEC1") - self.assertEqual(value, encoded) - - def test_export_public_sec1_compressed(self): - key_file = load_file("ecc_p256_public.der") - encoded = self.ref_public.export_key(format="SEC1", compress=True) - - key_file_compressed_ref = load_file("ecc_p256_public_compressed.der") - value = extract_bitstring_from_spki(key_file_compressed_ref) - self.assertEqual(value, encoded) - - def test_export_rfc5915_private_der(self): - key_file = load_file("ecc_p256_private.der") - - encoded = self.ref_private._export_rfc5915_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA512-256AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p256_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p256_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p256_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p256_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p256_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p256_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p256_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - - def test_compressed_curve(self): - - # Compressed P-256 curve (Y-point is even) - pem1 = """-----BEGIN EC PRIVATE KEY----- - MFcCAQEEIHTuc09jC51xXomV6MVCDN+DpAAvSmaJWZPTEHM6D5H1oAoGCCqGSM49 - AwEHoSQDIgACWFuGbHe8yJ43rir7PMTE9w8vHz0BSpXHq90Xi7/s+a0= - -----END EC PRIVATE KEY-----""" - - # Compressed P-256 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- - MFcCAQEEIFggiPN9SQP+FAPTCPp08fRUz7rHp2qNBRcBJ1DXhb3ZoAoGCCqGSM49 - AwEHoSQDIgADLpph1trTIlVfa8NJvlMUPyWvL+wP+pW3BJITUL/wj9A= - -----END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0xA6FC) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0x6E57) - - -class TestExport_P384(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P384, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p384() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p384_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p384_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p384_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_public_sec1_uncompressed(self): - key_file = load_file("ecc_p384_public.der") - value = extract_bitstring_from_spki(key_file) - - encoded = self.ref_public.export_key(format="SEC1") - self.assertEqual(value, encoded) - - def test_export_public_sec1_compressed(self): - key_file = load_file("ecc_p384_public.der") - encoded = self.ref_public.export_key(format="SEC1", compress=True) - - key_file_compressed_ref = load_file("ecc_p384_public_compressed.der") - value = extract_bitstring_from_spki(key_file_compressed_ref) - self.assertEqual(value, encoded) - - def test_export_rfc5915_private_der(self): - key_file = load_file("ecc_p384_private.der") - - encoded = self.ref_private._export_rfc5915_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA384AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p384_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p384_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p384_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p384_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p384_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p384_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p384_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - def test_compressed_curve(self): - - # Compressed P-384 curve (Y-point is even) - # openssl ecparam -name secp384p1 -genkey -noout -conv_form compressed -out /tmp/a.pem - # openssl ec -in /tmp/a.pem -text -noout - pem1 = """-----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDAM0lEIhvXuekK2SWtdbgOcZtBaxa9TxfpO/GcDFZLCJ3JVXaTgwken -QT+C+XLtD6WgBwYFK4EEACKhZANiAATs0kZMhFDu8DoBC21jrSDPyAUn4aXZ/DM4 -ylhDfWmb4LEbeszXceIzfhIUaaGs5y1xXaqf5KXTiAAYx2pKUzAAM9lcGUHCGKJG -k4AgUmVJON29XoUilcFrzjDmuye3B6Q= ------END EC PRIVATE KEY-----""" - - # Compressed P-384 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDDHPFTslYLltE16fHdSDTtE/2HTmd3M8mqy5MttAm4wZ833KXiGS9oe -kFdx9sNV0KygBwYFK4EEACKhZANiAASLIE5RqVMtNhtBH/u/p/ifqOAlKnK/+RrQ -YC46ZRsnKNayw3wATdPjgja7L/DSII3nZK0G6KOOVwJBznT/e+zudUJYhZKaBLRx -/bgXyxUtYClOXxb1Y/5N7txLstYRyP0= ------END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x07a4) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0xc8fd) - - -class TestExport_P521(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P521, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p521() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p521_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p521_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p521_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_public_sec1_uncompressed(self): - key_file = load_file("ecc_p521_public.der") - value = extract_bitstring_from_spki(key_file) - - encoded = self.ref_public.export_key(format="SEC1") - self.assertEqual(value, encoded) - - encoded = self.ref_public.export_key(format="raw") - self.assertEqual(value, encoded) - - def test_export_public_sec1_compressed(self): - key_file = load_file("ecc_p521_public.der") - encoded = self.ref_public.export_key(format="SEC1", compress=True) - - key_file_compressed_ref = load_file("ecc_p521_public_compressed.der") - value = extract_bitstring_from_spki(key_file_compressed_ref) - self.assertEqual(value, encoded) - - encoded = self.ref_public.export_key(format="raw", compress=True) - self.assertEqual(value, encoded) - - def test_export_rfc5915_private_der(self): - key_file = load_file("ecc_p521_private.der") - - encoded = self.ref_private._export_rfc5915_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p521_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p521_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p521_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p521_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p521_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p521_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p521_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - def test_compressed_curve(self): - - # Compressed P-521 curve (Y-point is even) - # openssl ecparam -name secp521r1 -genkey -noout -conv_form compressed -out /tmp/a.pem - # openssl ec -in /tmp/a.pem -text -noout - pem1 = """-----BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIAnm1CEjVjvNfXEN730p+D6su5l+mOztdc5XmTEoti+s2R4GQ4mAv3 -0zYLvyklvOHw0+yy8d0cyGEJGb8T3ZVKmg2gBwYFK4EEACOhgYkDgYYABAHzjTI1 -ckxQ3Togi0LAxiG0PucdBBBs5oIy3df95xv6SInp70z+4qQ2EltEmdNMssH8eOrl -M5CYdZ6nbcHMVaJUvQEzTrYxvFjOgJiOd+E9eBWbLkbMNqsh1UKVO6HbMbW0ohCI -uGxO8tM6r3w89/qzpG2SvFM/fvv3mIR30wSZDD84qA== ------END EC PRIVATE KEY-----""" - - # Compressed P-521 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIB84OfhJluLBRLn3+cC/RQ37C2SfQVP/t0gQK2tCsTf5avRcWYRrOJ -PmX9lNnkC0Hobd75QFRmdxrB0Wd1/M4jZOWgBwYFK4EEACOhgYkDgYYABAAMZcdJ -1YLCGHt3bHCEzdidVy6+brlJIbv1aQ9fPQLF7WKNv4c8w3H8d5a2+SDZilBOsk5c -6cNJDMz2ExWQvxl4CwDJtJGt1+LHVKFGy73NANqVxMbRu+2F8lOxkNp/ziFTbVyV -vv6oYkMIIi7r5oQWAiQDrR2mlrrFDL9V7GH/r8SWQw== ------END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x38a8) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0x9643) - - -class TestImport_Ed25519(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_Ed25519, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_ed25519() - - def test_import_public_der(self): - key_file = load_file("ecc_ed25519_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_pkcs8_der(self): - key_file = load_file("ecc_ed25519_private.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_ed25519_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_ed25519_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_ed25519_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_ed25519_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_ed25519_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_ed25519_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256": - key_file = load_file("ecc_ed25519_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_ed25519_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_ed25519_public_openssh.txt") - key = ECC._import_openssh_public(key_file) - self.assertFalse(key.has_private()) - key = ECC.import_key(key_file) - self.assertFalse(key.has_private()) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_ed25519_private_openssh.pem") - key = ECC.import_key(key_file) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_ed25519_private_openssh_pwd.pem") - key = ECC.import_key(key_file, b"password") - - -class TestExport_Ed25519(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_Ed25519, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_ed25519() - - def test_export_public_der(self): - key_file = load_file("ecc_ed25519_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(True) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_sec1(self): - self.assertRaises(ValueError, self.ref_public.export_key, format="SEC1") - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_ed25519_private.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - self.assertRaises(ValueError, self.ref_private.export_key, - format="DER", use_pkcs8=False) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem(self): - key_file_ref = load_file("ecc_ed25519_public.pem", "rt").strip() - key_file = self.ref_public.export_key(format="PEM").strip() - self.assertEqual(key_file_ref, key_file) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_ed25519_private.pem", "rt").strip() - encoded = self.ref_private.export_key(format="PEM").strip() - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh(self): - key_file = load_file("ecc_ed25519_public_openssh.txt", "rt") - public_key = ECC.import_key(key_file) - key_file = " ".join(key_file.split(' ')[:2]) # remove comment - - encoded = public_key._export_openssh(False) - self.assertEqual(key_file, encoded.strip()) - - encoded = public_key.export_key(format="OpenSSH") - self.assertEqual(key_file, encoded.strip()) - - def test_export_raw(self): - encoded = self.ref_public.export_key(format='raw') - self.assertEqual(encoded, unhexlify(b'bc85b8cf585d20a4de47e84d1cb6183f63d9ba96223fcbc886e363ffdea20cff')) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - -class TestImport_Ed448(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_Ed448, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_ed448() - - def test_import_public_der(self): - key_file = load_file("ecc_ed448_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_pkcs8_der(self): - key_file = load_file("ecc_ed448_private.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_ed448_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_ed448_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_3(self): - key_file = load_file("ecc_ed448_private_p8_2.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_ed448_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_ed448_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_ed448_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256": - key_file = load_file("ecc_ed448_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_ed448_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - -class TestExport_Ed448(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_Ed448, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_ed448() - - def test_export_public_der(self): - key_file = load_file("ecc_ed448_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(True) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_sec1(self): - self.assertRaises(ValueError, self.ref_public.export_key, format="SEC1") - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_ed448_private.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - self.assertRaises(ValueError, self.ref_private.export_key, - format="DER", use_pkcs8=False) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA384AndAES128-CBC", - prot_params={'iteration_count':123}) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - - def test_export_public_pem(self): - key_file_ref = load_file("ecc_ed448_public.pem", "rt").strip() - key_file = self.ref_public.export_key(format="PEM").strip() - self.assertEqual(key_file_ref, key_file) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_ed448_private.pem", "rt").strip() - encoded = self.ref_private.export_key(format="PEM").strip() - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh(self): - # Not supported - self.assertRaises(ValueError, self.ref_public.export_key, format="OpenSSH") - - def test_export_raw(self): - encoded = self.ref_public.export_key(format='raw') - self.assertEqual(encoded, unhexlify(b'899014ddc0a0e1260cfc1085afdf952019e9fd63372e3e366e26dad32b176624884330a14617237e3081febd9d1a15069e7499433d2f55dd80')) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase=b"secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEqual(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestImport) - try: - tests += list_test_cases(TestImport_P192) - tests += list_test_cases(TestImport_P224) - tests += list_test_cases(TestImport_P256) - tests += list_test_cases(TestImport_P384) - tests += list_test_cases(TestImport_P521) - tests += list_test_cases(TestImport_Ed25519) - tests += list_test_cases(TestImport_Ed448) - - tests += list_test_cases(TestExport_P192) - tests += list_test_cases(TestExport_P224) - tests += list_test_cases(TestExport_P256) - tests += list_test_cases(TestExport_P384) - tests += list_test_cases(TestExport_P521) - tests += list_test_cases(TestExport_Ed25519) - tests += list_test_cases(TestExport_Ed448) - - except MissingTestVectorException: - pass - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_RSA.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_RSA.py deleted file mode 100644 index f6f7afd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/PublicKey/test_import_RSA.py +++ /dev/null @@ -1,636 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import os -import re -import errno -import warnings -import unittest -from unittest import SkipTest - -from Crypto.PublicKey import RSA -from Crypto.SelfTest.st_common import a2b_hex, list_test_cases -from Crypto.IO import PEM -from Crypto.Util.py3compat import b, tostr, FileNotFoundError -from Crypto.Util.number import inverse -from Crypto.Util import asn1 - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "RSA") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Skipping tests for RSA based on %s" % file_name, - UserWarning, - stacklevel=2) - - if results is None: - raise SkipTest("Missing %s" % file_name) - - return results - - -def der2pem(der, text='PUBLIC'): - import binascii - chunks = [binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48)] - pem = b('-----BEGIN %s KEY-----\n' % text) - pem += b('').join(chunks) - pem += b('-----END %s KEY-----' % text) - return pem - - -class ImportKeyTests(unittest.TestCase): - # 512-bit RSA key generated with openssl - rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII -q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 -Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI -OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr -+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK -JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 -n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== ------END RSA PRIVATE KEY-----''' - - # As above, but this is actually an unencrypted PKCS#8 key - rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY----- -MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS -ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj -wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK -5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk -B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC -NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx -yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7 -BX85JB8zqwHB ------END PRIVATE KEY-----''' - - # The same RSA private key as in rsaKeyPEM, but now encrypted - rsaKeyEncryptedPEM = ( - - # PEM encryption - # With DES and passphrase 'test' - ('test', u'''-----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-CBC,AF8F9A40BD2FA2FC - -Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA -u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs -C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP -BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy -9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY -IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp -dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s= ------END RSA PRIVATE KEY-----'''), - - # PKCS8 encryption - ('winter', u'''-----BEGIN ENCRYPTED PRIVATE KEY----- -MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeZIsbW3O+JcCAggA -MBQGCCqGSIb3DQMHBAgSM2p0D8FilgSCAWBhFyP2tiGKVpGj3mO8qIBzinU60ApR -3unvP+N6j7LVgnV2lFGaXbJ6a1PbQXe+2D6DUyBLo8EMXrKKVLqOMGkFMHc0UaV6 -R6MmrsRDrbOqdpTuVRW+NVd5J9kQQh4xnfU/QrcPPt7vpJvSf4GzG0n666Ki50OV -M/feuVlIiyGXY6UWdVDpcOV72cq02eNUs/1JWdh2uEBvA9fCL0c07RnMrdT+CbJQ -NjJ7f8ULtp7xvR9O3Al/yJ4Wv3i4VxF1f3MCXzhlUD4I0ONlr0kJWgeQ80q/cWhw -ntvgJwnCn2XR1h6LA8Wp+0ghDTsL2NhJpWd78zClGhyU4r3hqu1XDjoXa7YCXCix -jCV15+ViDJzlNCwg+W6lRg18sSLkCT7alviIE0U5tHc6UPbbHwT5QqAxAABaP+nZ -CGqJGyiwBzrKebjgSm/KRd4C91XqcsysyH2kKPfT51MLAoD4xelOURBP ------END ENCRYPTED PRIVATE KEY-----''' - ), - ) - - rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T -Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ== ------END PUBLIC KEY-----''' - - # Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM' - rsaPublicKeyOpenSSH = b('''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n''') - - # The private key, in PKCS#1 format encoded with DER - rsaKeyDER = a2b_hex( - '''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe - 913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312 - 2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6 - 7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c - 54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f - 2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23 - 022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2 - a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca - 240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b - c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07 - e4defe43ed91a3ae27bb057f39241f33ab01c1 - '''.replace(" ","")) - - # The private key, in unencrypted PKCS#8 format encoded with DER - rsaKeyDER8 = a2b_hex( - '''30820155020100300d06092a864886f70d01010105000482013f3082013 - b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932 - ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78 - 492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2 - 301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb - f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da - 61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c - a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0 - 23702210087be1c3029504bcf34ec713d877947447813288975ca240080a - f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf - 433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4 - 3ed91a3ae27bb057f39241f33ab01c1 - '''.replace(" ","")) - - rsaPublicKeyDER = a2b_hex( - '''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a - a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c - b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502 - 03010001 - '''.replace(" ","")) - - n = int('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F 93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3 12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16) - e = 65537 - d = int('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7 01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18 F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16) - p = int('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26 24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16) - q = int('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38 06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16) - - # This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1} - # mod q) instead! - qInv = int('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3 AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16) - pInv = inverse(p,q) - - def testImportKey1(self): - """Verify import of RSAPrivateKey DER SEQUENCE""" - key = RSA.importKey(self.rsaKeyDER) - self.assertTrue(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey2(self): - """Verify import of SubjectPublicKeyInfo DER SEQUENCE""" - key = RSA.importKey(self.rsaPublicKeyDER) - self.assertFalse(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey3unicode(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" - key = RSA.importKey(self.rsaKeyPEM) - self.assertEqual(key.has_private(),True) # assert_ - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey3bytes(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte string""" - key = RSA.importKey(b(self.rsaKeyPEM)) - self.assertEqual(key.has_private(),True) # assert_ - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey4unicode(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" - key = RSA.importKey(self.rsaPublicKeyPEM) - self.assertEqual(key.has_private(),False) # assertFalse - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey4bytes(self): - """Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM as byte string""" - key = RSA.importKey(b(self.rsaPublicKeyPEM)) - self.assertEqual(key.has_private(),False) # assertFalse - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey5(self): - """Verifies that the imported key is still a valid RSA pair""" - key = RSA.importKey(self.rsaKeyPEM) - idem = key._encrypt(key._decrypt(89)) - self.assertEqual(idem, 89) - - def testImportKey6(self): - """Verifies that the imported key is still a valid RSA pair""" - key = RSA.importKey(self.rsaKeyDER) - idem = key._encrypt(key._decrypt(65)) - self.assertEqual(idem, 65) - - def testImportKey7(self): - """Verify import of OpenSSH public key""" - key = RSA.importKey(self.rsaPublicKeyOpenSSH) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey8(self): - """Verify import of encrypted PrivateKeyInfo DER SEQUENCE""" - for t in self.rsaKeyEncryptedPEM: - key = RSA.importKey(t[1], t[0]) - self.assertTrue(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey9(self): - """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE""" - key = RSA.importKey(self.rsaKeyDER8) - self.assertTrue(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey10(self): - """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded with PEM""" - key = RSA.importKey(self.rsaKeyPEM8) - self.assertTrue(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey11(self): - """Verify import of RSAPublicKey DER SEQUENCE""" - der = asn1.DerSequence([17, 3]).encode() - key = RSA.importKey(der) - self.assertEqual(key.n, 17) - self.assertEqual(key.e, 3) - - def testImportKey12(self): - """Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM""" - der = asn1.DerSequence([17, 3]).encode() - pem = der2pem(der) - key = RSA.importKey(pem) - self.assertEqual(key.n, 17) - self.assertEqual(key.e, 3) - - def test_import_key_windows_cr_lf(self): - pem_cr_lf = "\r\n".join(self.rsaKeyPEM.splitlines()) - key = RSA.importKey(pem_cr_lf) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def test_import_empty(self): - self.assertRaises(ValueError, RSA.import_key, b"") - - ### - def testExportKey1(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - derKey = key.export_key("DER") - self.assertEqual(derKey, self.rsaKeyDER) - - def testExportKey2(self): - key = RSA.construct([self.n, self.e]) - derKey = key.export_key("DER") - self.assertEqual(derKey, self.rsaPublicKeyDER) - - def testExportKey3(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - pemKey = key.export_key("PEM") - self.assertEqual(pemKey, b(self.rsaKeyPEM)) - - def testExportKey4(self): - key = RSA.construct([self.n, self.e]) - pemKey = key.export_key("PEM") - self.assertEqual(pemKey, b(self.rsaPublicKeyPEM)) - - def testExportKey5(self): - key = RSA.construct([self.n, self.e]) - openssh_1 = key.export_key("OpenSSH").split() - openssh_2 = self.rsaPublicKeyOpenSSH.split() - self.assertEqual(openssh_1[0], openssh_2[0]) - self.assertEqual(openssh_1[1], openssh_2[1]) - - def testExportKey7(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - derKey = key.export_key("DER", pkcs=8) - self.assertEqual(derKey, self.rsaKeyDER8) - - def testExportKey8(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - pemKey = key.export_key("PEM", pkcs=8) - self.assertEqual(pemKey, b(self.rsaKeyPEM8)) - - def testExportKey9(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertRaises(ValueError, key.export_key, "invalid-format") - - def testExportKey10(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#1, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test') - self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey11(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#1, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=1) - self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey12(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#8, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=8) - self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.assertTrue(tostr(outkey).find('BEGIN PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey13(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#8, PKCS#8 encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=8, - protection='PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') - self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1) - self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey14(self): - # Export and re-import the encrypted key. It must match. - # DER envelope, PKCS#8, PKCS#8 encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('DER', 'test', pkcs=8) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey15(self): - # Verify that that error an condition is detected when trying to - # use a password with DER encoding and PKCS#1. - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertRaises(ValueError, key.export_key, 'DER', 'test', 1) - - def testExportKey16(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#8, PKCS#8 encryption with parameters - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=8, - protection='PBKDF2WithHMAC-SHA512AndAES256-CBC', - prot_params={'iteration_count':123} - ) - self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1) - self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1) - - # Verify the iteration count - der = PEM.decode(tostr(outkey))[0] - seq1 = asn1.DerSequence().decode(der) - seq2 = asn1.DerSequence().decode(seq1[0]) - seq3 = asn1.DerSequence().decode(seq2[1]) - seq4 = asn1.DerSequence().decode(seq3[0]) - seq5 = asn1.DerSequence().decode(seq4[1]) - self.assertEqual(seq5[1], 123) - - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def test_import_key(self): - """Verify that import_key is an alias to importKey""" - key = RSA.import_key(self.rsaPublicKeyDER) - self.assertFalse(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def test_import_key_ba_mv(self): - """Verify that import_key can be used on bytearrays and memoryviews""" - key = RSA.import_key(bytearray(self.rsaPublicKeyDER)) - key = RSA.import_key(memoryview(self.rsaPublicKeyDER)) - - def test_exportKey(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertEqual(key.export_key(), key.exportKey()) - - -class ImportKeyFromX509Cert(unittest.TestCase): - - def test_x509v1(self): - - # Sample V1 certificate with a 1024 bit RSA key - x509_v1_cert = """ ------BEGIN CERTIFICATE----- -MIICOjCCAaMCAQEwDQYJKoZIhvcNAQEEBQAwfjENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT -Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG -A1UEAxMEdGVzdDAeFw0xNDA3MTExOTU3MjRaFw0xNzA0MDYxOTU3MjRaME0xCzAJ -BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxDzANBgNVBAMTBmxhdHZpYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAyG+kytdRj3TFbRmHDYp3TXugVQ81chew0qeOxZWOz80IjtWpgdOaCvKW -NCuc8wUR9BWrEQW+39SaRMLiQfQtyFSQZijc3nsEBu/Lo4uWZ0W/FHDRVSvkJA/V -Ex5NL5ikI+wbUeCV5KajGNDalZ8F1pk32+CBs8h1xNx5DyxuEHUCAwEAATANBgkq -hkiG9w0BAQQFAAOBgQCVQF9Y//Q4Psy+umEM38pIlbZ2hxC5xNz/MbVPwuCkNcGn -KYNpQJP+JyVTsPpO8RLZsAQDzRueMI3S7fbbwTzAflN0z19wvblvu93xkaBytVok -9VBAH28olVhy9b1MMeg2WOt5sUEQaFNPnwwsyiY9+HsRpvpRnPSQF+kyYVsshQ== ------END CERTIFICATE----- - """.strip() - - # RSA public key as dumped by openssl - exponent = 65537 - modulus_str = """ -00:c8:6f:a4:ca:d7:51:8f:74:c5:6d:19:87:0d:8a: -77:4d:7b:a0:55:0f:35:72:17:b0:d2:a7:8e:c5:95: -8e:cf:cd:08:8e:d5:a9:81:d3:9a:0a:f2:96:34:2b: -9c:f3:05:11:f4:15:ab:11:05:be:df:d4:9a:44:c2: -e2:41:f4:2d:c8:54:90:66:28:dc:de:7b:04:06:ef: -cb:a3:8b:96:67:45:bf:14:70:d1:55:2b:e4:24:0f: -d5:13:1e:4d:2f:98:a4:23:ec:1b:51:e0:95:e4:a6: -a3:18:d0:da:95:9f:05:d6:99:37:db:e0:81:b3:c8: -75:c4:dc:79:0f:2c:6e:10:75 - """ - modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) - - key = RSA.importKey(x509_v1_cert) - self.assertEqual(key.e, exponent) - self.assertEqual(key.n, modulus) - self.assertFalse(key.has_private()) - - def test_x509v3(self): - - # Sample V3 certificate with a 1024 bit RSA key - x509_v3_cert = """ ------BEGIN CERTIFICATE----- -MIIEcjCCAlqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD -QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTIwOTM1 -MTJaFw0xNzA0MDcwOTM1MTJaMEQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES -MBAGA1UEBwwJQmFsdGltb3JlMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA/S7GJV2OcFdyNMQ4K75KrYFtMEn3VnEFdPHa -jyS37XlMxSh0oS4GeTGVUCJInl5Cpsv8WQdh03FfeOdvzp5IZ46OcjeOPiWnmjgl -2G5j7e2bDH7RSchGV+OD6Fb1Agvuu2/9iy8fdf3rPQ/7eAddzKUrzwacVbnW+tg2 -QtSXKRcCAwEAAaOB1TCB0jAdBgNVHQ4EFgQU/WwCX7FfWMIPDFfJ+I8a2COG+l8w -HwYDVR0jBBgwFoAUa0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNV -HQ8EBAMCBeAwSgYDVR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv -bYIQbWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIB -DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsF -AAOCAgEAvO6xfdsGbnoK4My3eJthodTAjMjPwFVY133LH04QLcCv54TxKhtUg1fi -PgdjVe1HpTytPBfXy2bSZbXAN0abZCtw1rYrnn7o1g2pN8iypVq3zVn0iMTzQzxs -zEPO3bpR/UhNSf90PmCsS5rqZpAAnXSaAy1ClwHWk/0eG2pYkhE1m1ABVMN2lsAW -e9WxGk6IFqaI9O37NYQwmEypMs4DC+ECJEvbPFiqi3n0gbXCZJJ6omDA5xJldaYK -Oa7KR3s/qjBsu9UAiWpLBuFoSTHIF2aeRKRFmUdmzwo43eVPep65pY6eQ4AdL2RF -rqEuINbGlzI5oQyYhu71IwB+iPZXaZZPlwjLgOsuad/p2hOgDb5WxUi8FnDPursQ -ujfpIpmrOP/zpvvQWnwePI3lI+5n41kTBSbefXEdv6rXpHk3QRzB90uPxnXPdxSC -16ASA8bQT5an/1AgoE3k9CrcD2K0EmgaX0YI0HUhkyzbkg34EhpWJ6vvRUbRiNRo -9cIbt/ya9Y9u0Ja8GLXv6dwX0l0IdJMkL8KifXUFAVCujp1FBrr/gdmwQn8itANy -+qbnWSxmOvtaY0zcaFAcONuHva0h51/WqXOMO1eb8PhR4HIIYU8p1oBwQp7dSni8 -THDi1F+GG5PsymMDj5cWK42f+QzjVw5PrVmFqqrrEoMlx8DWh5Y= ------END CERTIFICATE----- -""".strip() - - # RSA public key as dumped by openssl - exponent = 65537 - modulus_str = """ -00:fd:2e:c6:25:5d:8e:70:57:72:34:c4:38:2b:be: -4a:ad:81:6d:30:49:f7:56:71:05:74:f1:da:8f:24: -b7:ed:79:4c:c5:28:74:a1:2e:06:79:31:95:50:22: -48:9e:5e:42:a6:cb:fc:59:07:61:d3:71:5f:78:e7: -6f:ce:9e:48:67:8e:8e:72:37:8e:3e:25:a7:9a:38: -25:d8:6e:63:ed:ed:9b:0c:7e:d1:49:c8:46:57:e3: -83:e8:56:f5:02:0b:ee:bb:6f:fd:8b:2f:1f:75:fd: -eb:3d:0f:fb:78:07:5d:cc:a5:2b:cf:06:9c:55:b9: -d6:fa:d8:36:42:d4:97:29:17 - """ - modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) - - key = RSA.importKey(x509_v3_cert) - self.assertEqual(key.e, exponent) - self.assertEqual(key.n, modulus) - self.assertFalse(key.has_private()) - - -class TestImport_2048(unittest.TestCase): - - def test_import_pss(self): - pub_key_file = load_file("rsa2048_pss_public.pem") - pub_key = RSA.import_key(pub_key_file) - - priv_key_file = load_file("rsa2048_pss_private.pem") - priv_key = RSA.import_key(priv_key_file) - - self.assertEqual(pub_key.n, priv_key.n) - - def test_import_openssh_public(self): - key_file_ref = load_file("rsa2048_private.pem") - key_file = load_file("rsa2048_public_openssh.txt") - - # Skip test if test vectors are not installed - if None in (key_file_ref, key_file): - return - - key_ref = RSA.import_key(key_file_ref).public_key() - key = RSA.import_key(key_file) - self.assertEqual(key_ref, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("rsa2048_private_openssh.pem") - key_file_old = load_file("rsa2048_private_openssh_old.pem") - - # Skip test if test vectors are not installed - if None in (key_file_old, key_file): - return - - key = RSA.import_key(key_file) - key_old = RSA.import_key(key_file_old) - - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("rsa2048_private_openssh_pwd.pem") - key_file_old = load_file("rsa2048_private_openssh_pwd_old.pem") - - # Skip test if test vectors are not installed - if None in (key_file_old, key_file): - return - - key = RSA.import_key(key_file, b"password") - key_old = RSA.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_pkcs8_private(self): - key_file_ref = load_file("rsa2048_private.pem") - key_file = load_file("rsa2048_private_p8.der") - - # Skip test if test vectors are not installed - if None in (key_file_ref, key_file): - return - - key_ref = RSA.import_key(key_file_ref) - key = RSA.import_key(key_file, b'secret') - self.assertEqual(key_ref, key) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ImportKeyTests) - tests += list_test_cases(ImportKeyFromX509Cert) - tests += list_test_cases(TestImport_2048) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/__init__.py deleted file mode 100644 index 53061cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Random/__init__.py: Self-test for random number generation modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for random number generators""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/test_random.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/test_random.py deleted file mode 100644 index 8fadc53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Random/test_random.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_generic.py: Self-test for the Crypto.Random.new() function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test suite for Crypto.Random.new()""" - -import sys -import unittest -from Crypto.Util.py3compat import b - -class SimpleTest(unittest.TestCase): - def runTest(self): - """Crypto.Random.new()""" - # Import the Random module and try to use it - from Crypto import Random - randobj = Random.new() - x = randobj.read(16) - y = randobj.read(16) - self.assertNotEqual(x, y) - z = Random.get_random_bytes(16) - self.assertNotEqual(x, z) - self.assertNotEqual(y, z) - # Test the Random.random module, which - # implements a subset of Python's random API - # Not implemented: - # seed(), getstate(), setstate(), jumpahead() - # random(), uniform(), triangular(), betavariate() - # expovariate(), gammavariate(), gauss(), - # longnormvariate(), normalvariate(), - # vonmisesvariate(), paretovariate() - # weibullvariate() - # WichmannHill(), whseed(), SystemRandom() - from Crypto.Random import random - x = random.getrandbits(16*8) - y = random.getrandbits(16*8) - self.assertNotEqual(x, y) - # Test randrange - if x>y: - start = y - stop = x - else: - start = x - stop = y - for step in range(1,10): - x = random.randrange(start,stop,step) - y = random.randrange(start,stop,step) - self.assertNotEqual(x, y) - self.assertEqual(start <= x < stop, True) - self.assertEqual(start <= y < stop, True) - self.assertEqual((x - start) % step, 0) - self.assertEqual((y - start) % step, 0) - for i in range(10): - self.assertEqual(random.randrange(1,2), 1) - self.assertRaises(ValueError, random.randrange, start, start) - self.assertRaises(ValueError, random.randrange, stop, start, step) - self.assertRaises(TypeError, random.randrange, start, stop, step, step) - self.assertRaises(TypeError, random.randrange, start, stop, "1") - self.assertRaises(TypeError, random.randrange, "1", stop, step) - self.assertRaises(TypeError, random.randrange, 1, "2", step) - self.assertRaises(ValueError, random.randrange, start, stop, 0) - # Test randint - x = random.randint(start,stop) - y = random.randint(start,stop) - self.assertNotEqual(x, y) - self.assertEqual(start <= x <= stop, True) - self.assertEqual(start <= y <= stop, True) - for i in range(10): - self.assertEqual(random.randint(1,1), 1) - self.assertRaises(ValueError, random.randint, stop, start) - self.assertRaises(TypeError, random.randint, start, stop, step) - self.assertRaises(TypeError, random.randint, "1", stop) - self.assertRaises(TypeError, random.randint, 1, "2") - # Test choice - seq = range(10000) - x = random.choice(seq) - y = random.choice(seq) - self.assertNotEqual(x, y) - self.assertEqual(x in seq, True) - self.assertEqual(y in seq, True) - for i in range(10): - self.assertEqual(random.choice((1,2,3)) in (1,2,3), True) - self.assertEqual(random.choice([1,2,3]) in [1,2,3], True) - if sys.version_info[0] == 3: - self.assertEqual(random.choice(bytearray(b('123'))) in bytearray(b('123')), True) - self.assertEqual(1, random.choice([1])) - self.assertRaises(IndexError, random.choice, []) - self.assertRaises(TypeError, random.choice, 1) - # Test shuffle. Lacks random parameter to specify function. - # Make copies of seq - seq = range(500) - x = list(seq) - y = list(seq) - random.shuffle(x) - random.shuffle(y) - self.assertNotEqual(x, y) - self.assertEqual(len(seq), len(x)) - self.assertEqual(len(seq), len(y)) - for i in range(len(seq)): - self.assertEqual(x[i] in seq, True) - self.assertEqual(y[i] in seq, True) - self.assertEqual(seq[i] in x, True) - self.assertEqual(seq[i] in y, True) - z = [1] - random.shuffle(z) - self.assertEqual(z, [1]) - if sys.version_info[0] == 3: - z = bytearray(b('12')) - random.shuffle(z) - self.assertEqual(b('1') in z, True) - self.assertRaises(TypeError, random.shuffle, b('12')) - self.assertRaises(TypeError, random.shuffle, 1) - self.assertRaises(TypeError, random.shuffle, "11") - self.assertRaises(TypeError, random.shuffle, (1,2)) - # 2to3 wraps a list() around it, alas - but I want to shoot - # myself in the foot here! :D - # if sys.version_info[0] == 3: - # self.assertRaises(TypeError, random.shuffle, range(3)) - # Test sample - x = random.sample(seq, 20) - y = random.sample(seq, 20) - self.assertNotEqual(x, y) - for i in range(20): - self.assertEqual(x[i] in seq, True) - self.assertEqual(y[i] in seq, True) - z = random.sample([1], 1) - self.assertEqual(z, [1]) - z = random.sample((1,2,3), 1) - self.assertEqual(z[0] in (1,2,3), True) - z = random.sample("123", 1) - self.assertEqual(z[0] in "123", True) - z = random.sample(range(3), 1) - self.assertEqual(z[0] in range(3), True) - if sys.version_info[0] == 3: - z = random.sample(b("123"), 1) - self.assertEqual(z[0] in b("123"), True) - z = random.sample(bytearray(b("123")), 1) - self.assertEqual(z[0] in bytearray(b("123")), True) - self.assertRaises(TypeError, random.sample, 1) - -def get_tests(config={}): - return [SimpleTest()] - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/__init__.py deleted file mode 100644 index 83cf0f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Signature/__init__.py: Self-test for signature modules -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for signature modules""" - -import unittest -from . import test_pkcs1_15, test_pss, test_dss, test_eddsa - - -def get_tests(config={}): - tests = [] - tests += test_pkcs1_15.get_tests(config=config) - tests += test_pss.get_tests(config=config) - tests += test_dss.get_tests(config=config) - tests += test_eddsa.get_tests(config=config) - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_dss.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_dss.py deleted file mode 100644 index d3f8dfc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_dss.py +++ /dev/null @@ -1,1369 +0,0 @@ -# -# SelfTest/Signature/test_dss.py: Self-test for DSS signatures -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import re -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import tobytes, bord, bchr - -from Crypto.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, - SHA3_224, SHA3_256, SHA3_384, SHA3_512) -from Crypto.Signature import DSS -from Crypto.PublicKey import DSA, ECC -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof -from Crypto.Util.number import bytes_to_long, long_to_bytes - - -def t2b(hexstring): - ws = hexstring.replace(" ", "").replace("\n", "") - return unhexlify(tobytes(ws)) - - -def t2l(hexstring): - ws = hexstring.replace(" ", "").replace("\n", "") - return int(ws, 16) - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class StrRNG: - - def __init__(self, randomness): - length = len(randomness) - self._idx = 0 - # Fix required to get the right K (see how randint() works!) - self._randomness = long_to_bytes(bytes_to_long(randomness) - 1, length) - - def __call__(self, n): - out = self._randomness[self._idx:self._idx + n] - self._idx += n - return out - - -class FIPS_DSA_Tests(unittest.TestCase): - - # 1st 1024 bit key from SigGen.txt - P = 0xa8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed3256b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b02e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd5ebe2d1229681b5b06439ac9c7e9d8bde283 - Q = 0xf85f0f83ac4df7ea0cdf8f469bfeeaea14156495 - G = 0x2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df131f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909a6a3a99bbe089216368171bd0ba81de4fe33 - X = 0xc53eae6d45323164c7d07af5715703744a63fc3a - Y = 0x313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761bbb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae19c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32786d96f5a31aedf75364008ad4fffebb970b - - key_pub = DSA.construct((Y, G, P, Q)) - key_priv = DSA.construct((Y, G, P, Q, X)) - - def shortDescription(self): - return "FIPS DSA Tests" - - def test_loopback(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv, 'fips-186-3') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub, 'fips-186-3') - verifier.verify(hashed_msg, signature) - - def test_negative_unapproved_hashes(self): - """Verify that unapproved hashes are rejected""" - - from Crypto.Hash import RIPEMD160 - - self.description = "Unapproved hash (RIPEMD160) test" - hash_obj = RIPEMD160.new() - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertRaises(ValueError, signer.sign, hash_obj) - self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) - - def test_negative_unknown_modes_encodings(self): - """Verify that unknown modes/encodings are rejected""" - - self.description = "Unknown mode test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') - - self.description = "Unknown encoding test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') - - def test_asn1_encoding(self): - """Verify ASN.1 encoding""" - - self.description = "ASN.1 encoding test" - hash_obj = SHA1.new() - signer = DSS.new(self.key_priv, 'fips-186-3', 'der') - signature = signer.sign(hash_obj) - - # Verify that output looks like a DER SEQUENCE - self.assertEqual(bord(signature[0]), 48) - signer.verify(hash_obj, signature) - - # Verify that ASN.1 parsing fails as expected - signature = bchr(7) + signature[1:] - self.assertRaises(ValueError, signer.verify, hash_obj, signature) - - def test_sign_verify(self): - """Verify public/private method""" - - self.description = "can_sign() test" - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertTrue(signer.can_sign()) - - signer = DSS.new(self.key_pub, 'fips-186-3') - self.assertFalse(signer.can_sign()) - - try: - signer.sign(SHA256.new(b'xyz')) - except TypeError as e: - msg = str(e) - else: - msg = "" - self.assertTrue("Private key is needed" in msg) - - -class FIPS_DSA_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "DSA"), - "FIPS_186_3_SigVer.rsp", - "Signature Verification 186-3", - {'result': lambda x: x}) or [] - -for idx, tv in enumerate(test_vectors_verify): - - if isinstance(tv, str): - res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) - assert(res) - hash_name = res.group(3).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - if hasattr(tv, "p"): - modulus = tv.p - generator = tv.g - suborder = tv.q - continue - - hash_obj = hash_module.new(tv.msg) - - comps = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder)] - key = DSA.construct(comps, False) # type: ignore - verifier = DSS.new(key, 'fips-186-3') - - def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'p': - setattr(FIPS_DSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) - else: - setattr(FIPS_DSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) - - -test_vectors_sign = load_test_vectors(("Signature", "DSA"), - "FIPS_186_3_SigGen.txt", - "Signature Creation 186-3", - {}) or [] - -for idx, tv in enumerate(test_vectors_sign): - - if isinstance(tv, str): - res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) - assert(res) - hash_name = res.group(3).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - if hasattr(tv, "p"): - modulus = tv.p - generator = tv.g - suborder = tv.q - continue - - hash_obj = hash_module.new(tv.msg) - comps_dsa = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder, tv.x)] - key = DSA.construct(comps_dsa, False) # type: ignore - signer = DSS.new(key, 'fips-186-3', randfunc=StrRNG(tv.k)) - - def new_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertEqual(signer.sign(hash_obj), signature) - setattr(FIPS_DSA_Tests_KAT, "test_sign_%d" % idx, new_test) - - -class FIPS_ECDSA_Tests(unittest.TestCase): - - key_priv = ECC.generate(curve="P-256") - key_pub = key_priv.public_key() - - def shortDescription(self): - return "FIPS ECDSA Tests" - - def test_loopback(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv, 'fips-186-3') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub, 'fips-186-3') - verifier.verify(hashed_msg, signature) - - def test_negative_unapproved_hashes(self): - """Verify that unapproved hashes are rejected""" - - from Crypto.Hash import SHA1 - - self.description = "Unapproved hash (SHA-1) test" - hash_obj = SHA1.new() - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertRaises(ValueError, signer.sign, hash_obj) - self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) - - def test_negative_eddsa_key(self): - key = ECC.generate(curve="ed25519") - self.assertRaises(ValueError, DSS.new, key, 'fips-186-3') - - def test_sign_verify(self): - """Verify public/private method""" - - self.description = "can_sign() test" - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertTrue(signer.can_sign()) - - signer = DSS.new(self.key_pub, 'fips-186-3') - self.assertFalse(signer.can_sign()) - self.assertRaises(TypeError, signer.sign, SHA256.new(b'xyz')) - - try: - signer.sign(SHA256.new(b'xyz')) - except TypeError as e: - msg = str(e) - else: - msg = "" - self.assertTrue("Private key is needed" in msg) - - def test_negative_unknown_modes_encodings(self): - """Verify that unknown modes/encodings are rejected""" - - self.description = "Unknown mode test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') - - self.description = "Unknown encoding test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') - - def test_asn1_encoding(self): - """Verify ASN.1 encoding""" - - self.description = "ASN.1 encoding test" - hash_obj = SHA256.new() - signer = DSS.new(self.key_priv, 'fips-186-3', 'der') - signature = signer.sign(hash_obj) - - # Verify that output looks like a DER SEQUENCE - self.assertEqual(bord(signature[0]), 48) - signer.verify(hash_obj, signature) - - # Verify that ASN.1 parsing fails as expected - signature = bchr(7) + signature[1:] - self.assertRaises(ValueError, signer.verify, hash_obj, signature) - - -class FIPS_ECDSA_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "ECDSA"), - "SigVer.rsp", - "ECDSA Signature Verification 186-3", - {'result': lambda x: x, - 'qx': lambda x: int(x, 16), - 'qy': lambda x: int(x, 16), - }) or [] -test_vectors_verify += load_test_vectors(("Signature", "ECDSA"), - "SigVer_TruncatedSHAs.rsp", - "ECDSA Signature Verification 186-3", - {'result': lambda x: x, - 'qx': lambda x: int(x, 16), - 'qy': lambda x: int(x, 16), - }) or [] - - -for idx, tv in enumerate(test_vectors_verify): - - if isinstance(tv, str): - res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) - assert res - curve_name = res.group(1) - hash_name = res.group(2).replace("-", "") - if hash_name in ("SHA512224", "SHA512256"): - truncate = hash_name[-3:] - hash_name = hash_name[:-3] - else: - truncate = None - hash_module = load_hash_by_name(hash_name) - continue - - if truncate is None: - hash_obj = hash_module.new(tv.msg) - else: - hash_obj = hash_module.new(tv.msg, truncate=truncate) - ecc_key = ECC.construct(curve=curve_name, point_x=tv.qx, point_y=tv.qy) - verifier = DSS.new(ecc_key, 'fips-186-3') - - def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result.startswith('p'): - setattr(FIPS_ECDSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) - else: - setattr(FIPS_ECDSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) - - -test_vectors_sign = load_test_vectors(("Signature", "ECDSA"), - "SigGen.txt", - "ECDSA Signature Verification 186-3", - {'d': lambda x: int(x, 16)}) or [] - -for idx, tv in enumerate(test_vectors_sign): - - if isinstance(tv, str): - res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) - assert res - curve_name = res.group(1) - hash_name = res.group(2).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - hash_obj = hash_module.new(tv.msg) - ecc_key = ECC.construct(curve=curve_name, d=tv.d) - signer = DSS.new(ecc_key, 'fips-186-3', randfunc=StrRNG(tv.k)) - - def sign_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertEqual(signer.sign(hash_obj), signature) - setattr(FIPS_ECDSA_Tests_KAT, "test_sign_%d" % idx, sign_test) - - -class Det_DSA_Tests(unittest.TestCase): - """Tests from rfc6979""" - - # Each key is (p, q, g, x, y, desc) - keys = [ - ( - """ - 86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447 - E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88 - 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C - 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779""", - "996F967F6C8E388D9E28D01E205FBA957A5698B1", - """ - 07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D - 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD - 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4 - 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD""", - "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", - """ - 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653 - 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D - 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6 - 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B""", - "DSA1024" - ), - ( - """ - 9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48 - C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F - FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5 - B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2 - 35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41 - F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE - 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15 - 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B""", - "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - """ - 5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613 - D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4 - 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472 - 085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5 - AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA - 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71 - BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0 - DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7""", - "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - """ - 667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94 - 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61 - 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE - CB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB - 5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254 - 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1 - 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA - 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF""", - "DSA2048" - ), - ] - - # This is a sequence of items: - # message, k, r, s, hash module - signatures = [ - ( - "sample", - "7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B", - "2E1A0C2562B2912CAAF89186FB0F42001585DA55", - "29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", - SHA1, - 'DSA1024' - ), - ( - "sample", - "562097C06782D60C3037BA7BE104774344687649", - "4BC3B686AEA70145856814A6F1BB53346F02101E", - "410697B92295D994D21EDD2F4ADA85566F6F94C1", - SHA224, - 'DSA1024' - ), - ( - "sample", - "519BA0546D0C39202A7D34D7DFA5E760B318BCFB", - "81F2F5850BE5BC123C43F71A3033E9384611C545", - "4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", - SHA256, - 'DSA1024' - ), - ( - "sample", - "95897CD7BBB944AA932DBC579C1C09EB6FCFC595", - "07F2108557EE0E3921BC1774F1CA9B410B4CE65A", - "54DF70456C86FAC10FAB47C1949AB83F2C6F7595", - SHA384, - 'DSA1024' - ), - ( - "sample", - "09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B", - "16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", - "02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", - SHA512, - 'DSA1024' - ), - ( - "test", - "5C842DF4F9E344EE09F056838B42C7A17F4A6433", - "42AB2052FD43E123F0607F115052A67DCD9C5C77", - "183916B0230D45B9931491D4C6B0BD2FB4AAF088", - SHA1, - 'DSA1024' - ), - ( - "test", - "4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297", - "6868E9964E36C1689F6037F91F28D5F2C30610F2", - "49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", - SHA224, - 'DSA1024' - ), - ( - "test", - "5A67592E8128E03A417B0484410FB72C0B630E1A", - "22518C127299B0F6FDC9872B282B9E70D0790812", - "6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", - SHA256, - 'DSA1024' - ), - ( - "test", - "220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89", - "854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", - "91D0E0F53E22F898D158380676A871A157CDA622", - SHA384, - 'DSA1024' - ), - ( - "test", - "65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C", - "8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", - "7C670C7AD72B6C050C109E1790008097125433E8", - SHA512, - 'DSA1024' - ), - ( - "sample", - "888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E", - "3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", - "D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", - SHA1, - 'DSA2048' - ), - ( - "sample", - "BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806", - "DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", - "A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", - SHA224, - 'DSA2048' - ), - ( - "sample", - "8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52", - "EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", - "7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", - SHA256, - 'DSA2048' - ), - ( - "sample", - "C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920", - "B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", - "19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", - SHA384, - 'DSA2048' - ), - ( - "sample", - "5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC", - "2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", - "D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", - SHA512, - 'DSA2048' - ), - ( - "test", - "6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F", - "C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", - "414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", - SHA1, - 'DSA2048' - ), - ( - "test", - "06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670", - "272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", - "E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", - SHA224, - 'DSA2048' - ), - ( - "test", - "1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7", - "8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", - "7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", - SHA256, - 'DSA2048' - ), - ( - "test", - "206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C", - "239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", - "6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", - SHA384, - 'DSA2048' - ), - ( - "test", - "AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA", - "89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", - "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", - SHA512, - 'DSA2048' - ) - ] - - def setUp(self): - # Convert DSA key components from hex strings to integers - # Each key is (p, q, g, x, y, desc) - - from collections import namedtuple - - TestKey = namedtuple('TestKey', 'p q g x y') - new_keys = {} - for k in self.keys: - tk = TestKey(*[t2l(y) for y in k[:-1]]) - new_keys[k[-1]] = tk - self.keys = new_keys - - # Convert signature encoding - TestSig = namedtuple('TestSig', 'message nonce result module test_key') - new_signatures = [] - for message, nonce, r, s, module, test_key in self.signatures: - tsig = TestSig( - tobytes(message), - t2l(nonce), - t2b(r) + t2b(s), - module, - self.keys[test_key] - ) - new_signatures.append(tsig) - self.signatures = new_signatures - - def test1(self): - q = 0x4000000000000000000020108A2E0CC0D99F8A5EF - x = 0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F - p = 2 * q + 1 - y = pow(2, x, p) - key = DSA.construct([pow(y, 2, p), 2, p, q, x], False) - signer = DSS.new(key, 'deterministic-rfc6979') - - # Test _int2octets - self.assertEqual(hexlify(signer._int2octets(x)), - b'009a4d6792295a7f730fc3f2b49cbc0f62e862272f') - - # Test _bits2octets - h1 = SHA256.new(b"sample").digest() - self.assertEqual(hexlify(signer._bits2octets(h1)), - b'01795edf0d54db760f156d0dac04c0322b3a204224') - - def test2(self): - - for sig in self.signatures: - tk = sig.test_key - key = DSA.construct([tk.y, tk.g, tk.p, tk.q, tk.x], False) - signer = DSS.new(key, 'deterministic-rfc6979') - - hash_obj = sig.module.new(sig.message) - result = signer.sign(hash_obj) - self.assertEqual(sig.result, result) - - -class Det_ECDSA_Tests(unittest.TestCase): - - key_priv_p192 = ECC.construct(curve="P-192", d=0x6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4) - key_pub_p192 = key_priv_p192.public_key() - - key_priv_p224 = ECC.construct(curve="P-224", d=0xF220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1) - key_pub_p224 = key_priv_p224.public_key() - - key_priv_p256 = ECC.construct(curve="P-256", d=0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721) - key_pub_p256 = key_priv_p256.public_key() - - key_priv_p384 = ECC.construct(curve="P-384", d=0x6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5) - key_pub_p384 = key_priv_p384.public_key() - - key_priv_p521 = ECC.construct(curve="P-521", d=0x0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538) - key_pub_p521 = key_priv_p521.public_key() - - # This is a sequence of items: - # message, k, r, s, hash module - # taken from RFC6979 - signatures_p192_ = ( - ( - "sample", - "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", - "98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", - "57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", - SHA1 - ), - ( - "sample", - "4381526B3FC1E7128F202E194505592F01D5FF4C5AF015D8", - "A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", - "E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", - SHA224 - ), - ( - "sample", - "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", - "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", - "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", - SHA256 - ), - ( - "sample", - "4730005C4FCB01834C063A7B6760096DBE284B8252EF4311", - "DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", - "C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", - SHA384 - ), - ( - "sample", - "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", - "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", - "3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", - SHA512 - ), - ( - "test", - "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", - "0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", - "EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", - SHA1 - ), - ( - "test", - "F5DC805F76EF851800700CCE82E7B98D8911B7D510059FBE", - "6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", - "B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", - SHA224 - ), - ( - "test", - "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", - "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", - "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", - SHA256 - ), - ( - "test", - "5AFEFB5D3393261B828DB6C91FBC68C230727B030C975693", - "B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", - "7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", - SHA384 - ), - ( - "test", - "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", - "FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", - "74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", - SHA512 - ) - ) - - signatures_p224_ = ( - ( - "sample", - "7EEFADD91110D8DE6C2C470831387C50D3357F7F4D477054B8B426BC", - "22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC", - "66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69", - SHA1 - ), - ( - "sample", - "C1D1F2F10881088301880506805FEB4825FE09ACB6816C36991AA06D", - "1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E", - "A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC", - SHA224 - ), - ( - "sample", - "AD3029E0278F80643DE33917CE6908C70A8FF50A411F06E41DEDFCDC", - "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA", - "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101", - SHA256 - ), - ( - "sample", - "52B40F5A9D3D13040F494E83D3906C6079F29981035C7BD51E5CAC40", - "0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953", - "830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D", - SHA384 - ), - ( - "sample", - "9DB103FFEDEDF9CFDBA05184F925400C1653B8501BAB89CEA0FBEC14", - "074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397", - "A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084", - SHA512 - ), - ( - "test", - "2519178F82C3F0E4F87ED5883A4E114E5B7A6E374043D8EFD329C253", - "DEAA646EC2AF2EA8AD53ED66B2E2DDAA49A12EFD8356561451F3E21C", - "95987796F6CF2062AB8135271DE56AE55366C045F6D9593F53787BD2", - SHA1 - ), - ( - "test", - "DF8B38D40DCA3E077D0AC520BF56B6D565134D9B5F2EAE0D34900524", - "C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019", - "902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4", - SHA224 - ), - ( - "test", - "FF86F57924DA248D6E44E8154EB69F0AE2AEBAEE9931D0B5A969F904", - "AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6", - "178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD", - SHA256 - ), - ( - "test", - "7046742B839478C1B5BD31DB2E862AD868E1A45C863585B5F22BDC2D", - "389B92682E399B26518A95506B52C03BC9379A9DADF3391A21FB0EA4", - "414A718ED3249FF6DBC5B50C27F71F01F070944DA22AB1F78F559AAB", - SHA384 - ), - ( - "test", - "E39C2AA4EA6BE2306C72126D40ED77BF9739BB4D6EF2BBB1DCB6169D", - "049F050477C5ADD858CAC56208394B5A55BAEBBE887FDF765047C17C", - "077EB13E7005929CEFA3CD0403C7CDCC077ADF4E44F3C41B2F60ECFF", - SHA512 - ) - ) - - signatures_p256_ = ( - ( - "sample", - "882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4", - "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", - "6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", - SHA1 - ), - ( - "sample", - "103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473", - "53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", - "B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", - SHA224 - ), - ( - "sample", - "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60", - "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", - "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", - SHA256 - ), - ( - "sample", - "09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4", - "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", - "4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", - SHA384 - ), - ( - "sample", - "5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5", - "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", - "2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", - SHA512 - ), - ( - "test", - "8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E", - "0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", - "01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", - SHA1 - ), - ( - "test", - "669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7", - "C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", - "C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", - SHA224 - ), - ( - "test", - "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0", - "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", - "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", - SHA256 - ), - ( - "test", - "16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8", - "83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", - "8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", - SHA384 - ), - ( - "test", - "6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F", - "461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", - "39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", - SHA512 - ) - ) - - signatures_p384_ = ( - ( - "sample", - "4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7", - "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2", - "A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443", - SHA1 - ), - ( - "sample", - "A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB8083EE4E3C45B06A5899EA56C51B5879", - "42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE060122", - "9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D", - SHA224 - ), - ( - "sample", - "180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60", - "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD", - "F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0", - SHA256 - ), - ( - "sample", - "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9", - "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46", - "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8", - SHA384 - ), - ( - "sample", - "92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3", - "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709", - "512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5", - SHA512 - ), - ( - "test", - "66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497", - "4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7", - "D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282", - SHA1 - ), - ( - "test", - "18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E3D33BE4DC5EB8886A8ECD093F2935726", - "E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E72", - "07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66", - SHA224 - ), - ( - "test", - "0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7", - "6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B", - "2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265", - SHA256 - ), - ( - "test", - "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA", - "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB", - "DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5", - SHA384 - ), - ( - "test", - "3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C", - "A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277", - "976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736", - SHA512 - ), - ) - - signatures_p521_ = ( - ( - "sample", - "0089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", - "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D", - "00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16", - SHA1 - ), - ( - "sample", - "0121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B92113F3", - "01776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E", - "0050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F", - SHA224 - ), - ( - "sample", - "00EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", - "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7", - "004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC", - SHA256 - ), - ( - "sample", - "01546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211", - "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451", - "01F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61", - SHA384 - ), - ( - "sample", - "01DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3", - "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA", - "00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A", - SHA512 - ), - ( - "test", - "00BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222", - "013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0367", - "01E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF", - SHA1 - ), - ( - "test", - "0040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A01136987E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F706", - "01C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB", - "0177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4", - SHA224 - ), - ( - "test", - "001DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258", - "000E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA8", - "00CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86", - SHA256 - ), - ( - "test", - "01F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88", - "014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C", - "0133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979", - SHA384 - ), - ( - "test", - "016200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", - "013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D", - "01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3", - SHA512 - ), - ) - - signatures_p192 = [] - for a, b, c, d, e in signatures_p192_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p192.append(new_tv) - - signatures_p224 = [] - for a, b, c, d, e in signatures_p224_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p224.append(new_tv) - - signatures_p256 = [] - for a, b, c, d, e in signatures_p256_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p256.append(new_tv) - - signatures_p384 = [] - for a, b, c, d, e in signatures_p384_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p384.append(new_tv) - - signatures_p521 = [] - for a, b, c, d, e in signatures_p521_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p521.append(new_tv) - - def shortDescription(self): - return "Deterministic ECDSA Tests" - - def test_loopback_p192(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p192, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p192, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p224(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p224, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p224, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p256(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p256, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p384(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p384, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p521(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p521, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_data_rfc6979_p192(self): - signer = DSS.new(self.key_priv_p192, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p192: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p224(self): - signer = DSS.new(self.key_priv_p224, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p224: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p256(self): - signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p256: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p384(self): - signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p384: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p521(self): - signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p521: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - -def get_hash_module(hash_name): - if hash_name == "SHA-512": - hash_module = SHA512 - elif hash_name == "SHA-512/224": - hash_module = SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - hash_module = SHA512.new(truncate="256") - elif hash_name == "SHA-384": - hash_module = SHA384 - elif hash_name == "SHA-256": - hash_module = SHA256 - elif hash_name == "SHA-224": - hash_module = SHA224 - elif hash_name == "SHA-1": - hash_module = SHA1 - elif hash_name == "SHA3-224": - hash_module = SHA3_224 - elif hash_name == "SHA3-256": - hash_module = SHA3_256 - elif hash_name == "SHA3-384": - hash_module = SHA3_384 - elif hash_name == "SHA3-512": - hash_module = SHA3_512 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - return hash_module - - -class TestVectorsDSAWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._slow_tests = slow_tests - self._id = "None" - self.tv = [] - - def setUp(self): - - def filter_dsa(group): - return DSA.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_type(group): - sig_type = group['type'] - if sig_type != 'DsaVerify': - raise ValueError("Unknown signature type " + sig_type) - return sig_type - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - "dsa_test.json", - "Wycheproof DSA signature", - group_tag={'key': filter_dsa, - 'hash_module': filter_sha, - 'sig_type': filter_type}) - self.tv += result - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof DSA Test #" + str(tv.id) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = DSS.new(tv.key, 'fips-186-3', encoding='der') - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -class TestVectorsECDSAWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._slow_tests = slow_tests - self._id = "None" - - def add_tests(self, filename): - - def filter_ecc(group): - # These are the only curves we accept to skip - if group['key']['curve'] in ('secp224k1', 'secp256k1', - 'brainpoolP224r1', 'brainpoolP224t1', - 'brainpoolP256r1', 'brainpoolP256t1', - 'brainpoolP320r1', 'brainpoolP320t1', - 'brainpoolP384r1', 'brainpoolP384t1', - 'brainpoolP512r1', 'brainpoolP512t1', - ): - return None - return ECC.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_encoding(group): - encoding_name = group['type'] - if encoding_name == "EcdsaVerify": - return "der" - elif encoding_name == "EcdsaP1363Verify": - return "binary" - else: - raise ValueError("Unknown signature type " + encoding_name) - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof ECDSA signature (%s)" % filename, - group_tag={'key': filter_ecc, - 'hash_module': filter_sha, - 'encoding': filter_encoding, - }) - self.tv += result - - def setUp(self): - self.tv = [] - self.add_tests("ecdsa_secp224r1_sha224_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha224_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp224r1_sha256_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha256_test.json") - self.add_tests("ecdsa_secp224r1_sha3_224_test.json") - self.add_tests("ecdsa_secp224r1_sha3_256_test.json") - self.add_tests("ecdsa_secp224r1_sha3_512_test.json") - self.add_tests("ecdsa_secp224r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha512_test.json") - self.add_tests("ecdsa_secp256r1_sha256_p1363_test.json") - self.add_tests("ecdsa_secp256r1_sha256_test.json") - self.add_tests("ecdsa_secp256r1_sha3_256_test.json") - self.add_tests("ecdsa_secp256r1_sha3_512_test.json") - self.add_tests("ecdsa_secp256r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp256r1_sha512_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp384r1_sha3_384_test.json") - self.add_tests("ecdsa_secp384r1_sha3_512_test.json") - self.add_tests("ecdsa_secp384r1_sha384_p1363_test.json") - self.add_tests("ecdsa_secp384r1_sha384_test.json") - self.add_tests("ecdsa_secp384r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp384r1_sha512_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp521r1_sha3_512_test.json") - self.add_tests("ecdsa_secp521r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp521r1_sha512_test.json") - self.add_tests("ecdsa_test.json") - self.add_tests("ecdsa_webcrypto_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof ECDSA Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - - # Skip tests with unsupported curves - if tv.key is None: - return - - hashed_msg = tv.hash_module.new(tv.msg) - signer = DSS.new(tv.key, 'fips-186-3', encoding=tv.encoding) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - if tv.comment == "k*G has a large x-coordinate": - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(FIPS_DSA_Tests) - tests += list_test_cases(FIPS_ECDSA_Tests) - tests += list_test_cases(Det_DSA_Tests) - tests += list_test_cases(Det_ECDSA_Tests) - - slow_tests = config.get('slow_tests') - if slow_tests: - tests += list_test_cases(FIPS_DSA_Tests_KAT) - tests += list_test_cases(FIPS_ECDSA_Tests_KAT) - - tests += [TestVectorsDSAWycheproof(wycheproof_warnings, slow_tests)] - tests += [TestVectorsECDSAWycheproof(wycheproof_warnings, slow_tests)] - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_eddsa.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_eddsa.py deleted file mode 100644 index cca0994..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_eddsa.py +++ /dev/null @@ -1,604 +0,0 @@ -# -# Copyright (c) 2022, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.PublicKey import ECC -from Crypto.Signature import eddsa -from Crypto.Hash import SHA512, SHAKE256 -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.number import bytes_to_long - -rfc8032_tv_str = ( - # 7.1 Ed25519 - ( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", - "", - None, - "", - "e5564300c360ac729086e2cc806e828a" - "84877f1eb8e5d974d873e06522490155" - "5fb8821590a33bacc61e39701cf9b46b" - "d25bf5f0595bbe24655141438e7a100b" - ), - ( - "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", - "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", - "72", - None, - "", - "92a009a9f0d4cab8720e820b5f642540" - "a2b27b5416503f8fb3762223ebdb69da" - "085ac1e43e15996e458f3613d0f11d8c" - "387b2eaeb4302aeeb00d291612bb0c00" - ), - ( - "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", - "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", - "af82", - None, - "", - "6291d657deec24024827e69c3abe01a3" - "0ce548a284743a445e3680d7db5ac3ac" - "18ff9b538d16f290ae67f760984dc659" - "4a7c15e9716ed28dc027beceea1ec40a" - ), - ( - "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", - "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", - "08b8b2b733424243760fe426a4b54908" - "632110a66c2f6591eabd3345e3e4eb98" - "fa6e264bf09efe12ee50f8f54e9f77b1" - "e355f6c50544e23fb1433ddf73be84d8" - "79de7c0046dc4996d9e773f4bc9efe57" - "38829adb26c81b37c93a1b270b20329d" - "658675fc6ea534e0810a4432826bf58c" - "941efb65d57a338bbd2e26640f89ffbc" - "1a858efcb8550ee3a5e1998bd177e93a" - "7363c344fe6b199ee5d02e82d522c4fe" - "ba15452f80288a821a579116ec6dad2b" - "3b310da903401aa62100ab5d1a36553e" - "06203b33890cc9b832f79ef80560ccb9" - "a39ce767967ed628c6ad573cb116dbef" - "efd75499da96bd68a8a97b928a8bbc10" - "3b6621fcde2beca1231d206be6cd9ec7" - "aff6f6c94fcd7204ed3455c68c83f4a4" - "1da4af2b74ef5c53f1d8ac70bdcb7ed1" - "85ce81bd84359d44254d95629e9855a9" - "4a7c1958d1f8ada5d0532ed8a5aa3fb2" - "d17ba70eb6248e594e1a2297acbbb39d" - "502f1a8c6eb6f1ce22b3de1a1f40cc24" - "554119a831a9aad6079cad88425de6bd" - "e1a9187ebb6092cf67bf2b13fd65f270" - "88d78b7e883c8759d2c4f5c65adb7553" - "878ad575f9fad878e80a0c9ba63bcbcc" - "2732e69485bbc9c90bfbd62481d9089b" - "eccf80cfe2df16a2cf65bd92dd597b07" - "07e0917af48bbb75fed413d238f5555a" - "7a569d80c3414a8d0859dc65a46128ba" - "b27af87a71314f318c782b23ebfe808b" - "82b0ce26401d2e22f04d83d1255dc51a" - "ddd3b75a2b1ae0784504df543af8969b" - "e3ea7082ff7fc9888c144da2af58429e" - "c96031dbcad3dad9af0dcbaaaf268cb8" - "fcffead94f3c7ca495e056a9b47acdb7" - "51fb73e666c6c655ade8297297d07ad1" - "ba5e43f1bca32301651339e22904cc8c" - "42f58c30c04aafdb038dda0847dd988d" - "cda6f3bfd15c4b4c4525004aa06eeff8" - "ca61783aacec57fb3d1f92b0fe2fd1a8" - "5f6724517b65e614ad6808d6f6ee34df" - "f7310fdc82aebfd904b01e1dc54b2927" - "094b2db68d6f903b68401adebf5a7e08" - "d78ff4ef5d63653a65040cf9bfd4aca7" - "984a74d37145986780fc0b16ac451649" - "de6188a7dbdf191f64b5fc5e2ab47b57" - "f7f7276cd419c17a3ca8e1b939ae49e4" - "88acba6b965610b5480109c8b17b80e1" - "b7b750dfc7598d5d5011fd2dcc5600a3" - "2ef5b52a1ecc820e308aa342721aac09" - "43bf6686b64b2579376504ccc493d97e" - "6aed3fb0f9cd71a43dd497f01f17c0e2" - "cb3797aa2a2f256656168e6c496afc5f" - "b93246f6b1116398a346f1a641f3b041" - "e989f7914f90cc2c7fff357876e506b5" - "0d334ba77c225bc307ba537152f3f161" - "0e4eafe595f6d9d90d11faa933a15ef1" - "369546868a7f3a45a96768d40fd9d034" - "12c091c6315cf4fde7cb68606937380d" - "b2eaaa707b4c4185c32eddcdd306705e" - "4dc1ffc872eeee475a64dfac86aba41c" - "0618983f8741c5ef68d3a101e8a3b8ca" - "c60c905c15fc910840b94c00a0b9d0", - None, - "", - "0aab4c900501b3e24d7cdf4663326a3a" - "87df5e4843b2cbdb67cbf6e460fec350" - "aa5371b1508f9f4528ecea23c436d94b" - "5e8fcd4f681e30a6ac00a9704a188a03" - ), - # 7.2 Ed25519ctx - ( - "0305334e381af78f141cb666f6199f57" - "bc3495335a256a95bd2a55bf546663f6", - "dfc9425e4f968f7f0c29f0259cf5f9ae" - "d6851c2bb4ad8bfb860cfee0ab248292", - "f726936d19c800494e3fdaff20b276a8", - None, - "666f6f", - "55a4cc2f70a54e04288c5f4cd1e45a7b" - "b520b36292911876cada7323198dd87a" - "8b36950b95130022907a7fb7c4e9b2d5" - "f6cca685a587b4b21f4b888e4e7edb0d" - ), - ( - "0305334e381af78f141cb666f6199f57" - "bc3495335a256a95bd2a55bf546663f6", - "dfc9425e4f968f7f0c29f0259cf5f9ae" - "d6851c2bb4ad8bfb860cfee0ab248292", - "f726936d19c800494e3fdaff20b276a8", - None, - "626172", - "fc60d5872fc46b3aa69f8b5b4351d580" - "8f92bcc044606db097abab6dbcb1aee3" - "216c48e8b3b66431b5b186d1d28f8ee1" - "5a5ca2df6668346291c2043d4eb3e90d" - ), - ( - "0305334e381af78f141cb666f6199f57" - "bc3495335a256a95bd2a55bf546663f6", - "dfc9425e4f968f7f0c29f0259cf5f9ae" - "d6851c2bb4ad8bfb860cfee0ab248292", - "508e9e6882b979fea900f62adceaca35", - None, - "666f6f", - "8b70c1cc8310e1de20ac53ce28ae6e72" - "07f33c3295e03bb5c0732a1d20dc6490" - "8922a8b052cf99b7c4fe107a5abb5b2c" - "4085ae75890d02df26269d8945f84b0b" - ), - ( - "ab9c2853ce297ddab85c993b3ae14bca" - "d39b2c682beabc27d6d4eb20711d6560", - "0f1d1274943b91415889152e893d80e9" - "3275a1fc0b65fd71b4b0dda10ad7d772", - "f726936d19c800494e3fdaff20b276a8", - None, - "666f6f", - "21655b5f1aa965996b3f97b3c849eafb" - "a922a0a62992f73b3d1b73106a84ad85" - "e9b86a7b6005ea868337ff2d20a7f5fb" - "d4cd10b0be49a68da2b2e0dc0ad8960f" - ), - # 7.3 Ed25519ph - ( - "833fe62409237b9d62ec77587520911e" - "9a759cec1d19755b7da901b96dca3d42", - "ec172b93ad5e563bf4932c70e1245034" - "c35467ef2efd4d64ebf819683467e2bf", - "616263", - SHA512, - "", - "98a70222f0b8121aa9d30f813d683f80" - "9e462b469c7ff87639499bb94e6dae41" - "31f85042463c2a355a2003d062adf5aa" - "a10b8c61e636062aaad11c2a26083406" - ), - # 7.4 Ed448 - ( - "6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3" - "528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b", - "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778" - "edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180", - "", - None, - "", - "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f" - "2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a" - "9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4db" - "b61149f05a7363268c71d95808ff2e652600" - ), - ( - "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" - "fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e", - "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" - "6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480", - "03", - None, - "", - "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435" - "2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb" - "cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f" - "f3348ab21aa4adafd1d234441cf807c03a00", - ), - ( - "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" - "fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e", - "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" - "6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480", - "03", - None, - "666f6f", - "d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2" - "151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da" - "1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d" - "5428407e85dcbc98a49155c13764e66c3c00", - ), - ( - "cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffd" - "f60500553abc0e05cd02184bdb89c4ccd67e187951267eb328", - "dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e3" - "65fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400", - "0c3e544074ec63b0265e0c", - None, - "", - "1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d3" - "89dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b05" - "1068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5" - "028961c9bf8ffd973fe5d5c206492b140e00", - ), - ( - "258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d93" - "9f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b", - "3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc" - "24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580", - "64a65f3cdedcdd66811e2915", - None, - "", - "7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4a" - "e90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457e" - "b1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861" - "e72003cbae6d6b8b827e4e6c143064ff3c00", - ), - ( - "7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b29" - "49c1bb60700314611732a6c2fea98eebc0266a11a93970100e", - "b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb381" - "5c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80", - "64a65f3cdedcdd66811e2915e7", - None, - "", - "6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb" - "4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca" - "1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf5" - "6b4e7e0ba5519234d047155ac727a1053100", - ), - ( - "d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bf" - "f21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01", - "df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a" - "39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00", - "bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5" - "512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944", - None, - "", - "554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b1" - "8dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722e" - "f552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba" - "5f30e88e36ec2703b349ca229c2670833900", - ), - ( - "2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d3756" - "9b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5", - "79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9b" - "fe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00", - "15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567c" - "fa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89" - "e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072f" - "c1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60" - "39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b5" - "90316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce0" - "12d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409" - "a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11", - None, - "", - "c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f" - "00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a" - "61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc6" - "0987fd08527c1a8e80d5823e65cafe2a3d00", - ), - ( - "872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec" - "44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8", - "a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799d" - "a08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400", - "6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412" - "a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd" - "86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc" - "3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9" - "72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9" - "b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd32321" - "9b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab79717" - "2b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813" - "a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0" - "596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f520" - "96cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1" - "526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998" - "d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee" - "85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6" - "155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4" - "c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db9" - "77025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f041" - "0a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456" - "f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab" - "0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3" - "120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535" - "aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf969614" - "9e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67" - "a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a605" - "9d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263" - "be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d" - "02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c" - "392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e" - "79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd" - "7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4" - "b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695" - "568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87", - None, - "", - "e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bd" - "df7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d" - "76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed57" - "3603ce30d8bb761785dc30dbc320869e1a00" - ), - # 7.5 Ed448ph - ( - "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42" - "ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49", - "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743" - "c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880", - "616263", - SHAKE256, - "", - "822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae38" - "1f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd" - "433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3" - "ad203df7dc7ce360c3cd3696d9d9fab90f00" - ), - ( - "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42" - "ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49", - "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743" - "c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880", - "616263", - SHAKE256, - "666f6f", - "c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa48" - "1065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3" - "653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab7128" - "4f8d0704a608c54a6b62d97beb511d132100", - ), -) - - -rfc8032_tv_bytes = [] -for tv_str in rfc8032_tv_str: - rfc8032_tv_bytes.append([unhexlify(i) if isinstance(i, str) else i for i in tv_str]) - - -class TestEdDSA(unittest.TestCase): - - def test_sign(self): - for sk, _, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes: - key = eddsa.import_private_key(sk) - signer = eddsa.new(key, 'rfc8032', context=ctx) - if hashmod is None: - # PureEdDSA - signature = signer.sign(msg) - else: - # HashEdDSA - hashobj = hashmod.new(msg) - signature = signer.sign(hashobj) - self.assertEqual(exp_signature, signature) - - def test_verify(self): - for _, pk, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes: - key = eddsa.import_public_key(pk) - verifier = eddsa.new(key, 'rfc8032', context=ctx) - if hashmod is None: - # PureEdDSA - verifier.verify(msg, exp_signature) - else: - # HashEdDSA - hashobj = hashmod.new(msg) - verifier.verify(hashobj, exp_signature) - - def test_double_sign_verify_ed25519(self): - msg_hash = SHA512.new(b'abc') - key = ECC.generate(curve='ed25519') - signer = eddsa.new(key, 'rfc8032') - verifier = eddsa.new(key, 'rfc8032') - - signature = signer.sign(msg_hash) - signature2 = signer.sign(msg_hash) - self.assertEqual(signature, signature2) - - verifier.verify(msg_hash, signature) - verifier.verify(msg_hash, signature) - - def test_double_sign_verify_ed448(self): - msg_hash = SHAKE256.new(b'abc') - key = ECC.generate(curve='ed448') - signer = eddsa.new(key, 'rfc8032') - verifier = eddsa.new(key, 'rfc8032') - - signature = signer.sign(msg_hash) - signature2 = signer.sign(msg_hash) - self.assertEqual(signature, signature2) - - verifier.verify(msg_hash, signature) - verifier.verify(msg_hash, signature) - - def test_negative(self): - key = ECC.generate(curve="ed25519") - self.assertRaises(ValueError, eddsa.new, key, 'rfc9999') - - nist_key = ECC.generate(curve="p256") - self.assertRaises(ValueError, eddsa.new, nist_key, 'rfc8032') - - -class TestExport_Ed25519(unittest.TestCase): - - def test_raw(self): - key = ECC.generate(curve="Ed25519") - x, y = key.pointQ.xy - raw = bytearray(key._export_eddsa_public()) - sign_x = raw[31] >> 7 - raw[31] &= 0x7F - yt = bytes_to_long(raw[::-1]) - self.assertEqual(y, yt) - self.assertEqual(x & 1, sign_x) - - key = ECC.construct(point_x=0, point_y=1, curve="Ed25519") - out = key._export_eddsa_public() - self.assertEqual(b'\x01' + b'\x00' * 31, out) - - -class TestExport_Ed448(unittest.TestCase): - - def test_raw(self): - key = ECC.generate(curve="Ed448") - x, y = key.pointQ.xy - raw = bytearray(key._export_eddsa_public()) - sign_x = raw[56] >> 7 - raw[56] &= 0x7F - yt = bytes_to_long(raw[::-1]) - self.assertEqual(y, yt) - self.assertEqual(x & 1, sign_x) - - key = ECC.construct(point_x=0, point_y=1, curve="Ed448") - out = key._export_eddsa_public() - self.assertEqual(b'\x01' + b'\x00' * 56, out) - - -class TestImport_Ed25519(unittest.TestCase): - - def test_raw(self): - Px = 24407857220263921307776619664228778204996144802740950419837658238229122415920 - Py = 56480760040633817885061096979765646085062883740629155052073094891081309750690 - encoded = b'\xa2\x05\xd6\x00\xe1 \xe1\xc0\xff\x96\xee?V\x8e\xba/\xd3\x89\x06\xd7\xc4c\xe8$\xc2d\xd7a1\xfa\xde|' - key = eddsa.import_public_key(encoded) - self.assertEqual(Py, key.pointQ.y) - self.assertEqual(Px, key.pointQ.x) - - encoded = b'\x01' + b'\x00' * 31 - key = eddsa.import_public_key(encoded) - self.assertEqual(1, key.pointQ.y) - self.assertEqual(0, key.pointQ.x) - - -class TestImport_Ed448(unittest.TestCase): - - def test_raw(self): - Px = 0x153f42025aba3b0daecaa5cd79458b3146c7c9378c16c17b4a59bc3561113d90c169045bc12966c3f93e140c2ca0a3acc33d9205b9daf9b1 - Py = 0x38f5c0015d3dedd576c232810dd90373b5b1d631a12894c043b7be529cbae03ede177d8fa490b56131dbcb2465d2aba777ef839fc1719b25 - encoded = unhexlify("259b71c19f83ef77a7abd26524cbdb31" - "61b590a48f7d17de3ee0ba9c52beb743" - "c09428a131d6b1b57303d90d8132c276" - "d5ed3d5d01c0f53880") - key = eddsa.import_public_key(encoded) - self.assertEqual(Py, key.pointQ.y) - self.assertEqual(Px, key.pointQ.x) - - encoded = b'\x01' + b'\x00' * 56 - key = eddsa.import_public_key(encoded) - self.assertEqual(1, key.pointQ.y) - self.assertEqual(0, key.pointQ.x) - - -class TestVectorsEdDSAWycheproof(unittest.TestCase): - - def add_tests(self, filename): - - def pk(group): - elem = group['key']['pk'] - return unhexlify(elem) - - def sk(group): - elem = group['key']['sk'] - return unhexlify(elem) - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof ECDSA signature (%s)" - % filename, - group_tag={'pk': pk, 'sk': sk}) - self.tv += result - - def setUp(self): - self.tv = [] - self.add_tests("eddsa_test.json") - self.add_tests("ed448_test.json") - - def test_sign(self, tv): - if not tv.valid: - return - - self._id = "Wycheproof EdDSA Sign Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - key = eddsa.import_private_key(tv.sk) - signer = eddsa.new(key, 'rfc8032') - signature = signer.sign(tv.msg) - self.assertEqual(signature, tv.sig) - - def test_verify(self, tv): - self._id = "Wycheproof EdDSA Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - key = eddsa.import_public_key(tv.pk) - verifier = eddsa.new(key, 'rfc8032') - try: - verifier.verify(tv.msg, tv.sig) - except ValueError: - assert not tv.valid - else: - assert tv.valid - - def runTest(self): - for tv in self.tv: - self.test_sign(tv) - self.test_verify(tv) - - -def get_tests(config={}): - - tests = [] - tests += list_test_cases(TestExport_Ed25519) - tests += list_test_cases(TestExport_Ed448) - tests += list_test_cases(TestImport_Ed25519) - tests += list_test_cases(TestImport_Ed448) - tests += list_test_cases(TestEdDSA) - tests += [TestVectorsEdDSAWycheproof()] - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pkcs1_15.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pkcs1_15.py deleted file mode 100644 index 8e2c6ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pkcs1_15.py +++ /dev/null @@ -1,348 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import json -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import bchr -from Crypto.Util.number import bytes_to_long -from Crypto.Util.strxor import strxor -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_384, - SHA3_224, SHA3_256, SHA3_512) -from Crypto.PublicKey import RSA -from Crypto.Signature import pkcs1_15 -from Crypto.Signature import PKCS1_v1_5 - -from Crypto.Util._file_system import pycryptodome_filename -from Crypto.Util.strxor import strxor - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class FIPS_PKCS1_Verify_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Verify)" - - def test_can_sign(self): - test_public_key = RSA.generate(1024).public_key() - verifier = pkcs1_15.new(test_public_key) - self.assertEqual(verifier.can_sign(), False) - - -class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigVer15_186-3.rsp", - "Signature Verification 186-3", - {'shaalg': lambda x: x, - 'd': lambda x: int(x), - 'result': lambda x: x}) or [] - - -for count, tv in enumerate(test_vectors_verify): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore - verifier = pkcs1_15.new(public_key) - - def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'f': - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) - else: - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) - - -class FIPS_PKCS1_Sign_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Sign)" - - def test_can_sign(self): - test_private_key = RSA.generate(1024) - signer = pkcs1_15.new(test_private_key) - self.assertEqual(signer.can_sign(), True) - - -class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_sign = load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigGen15_186-2.txt", - "Signature Generation 186-2", - {'shaalg': lambda x: x}) or [] - -test_vectors_sign += load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigGen15_186-3.txt", - "Signature Generation 186-3", - {'shaalg': lambda x: x}) or [] - -for count, tv in enumerate(test_vectors_sign): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "e"): - private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore - signer = pkcs1_15.new(private_key) - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - - def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): - signature = signer.sign(hash_obj) - self.assertEqual(signature, result) - - setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) - - -class PKCS1_15_NoParams(unittest.TestCase): - """Verify that PKCS#1 v1.5 signatures pass even without NULL parameters in - the algorithm identifier (PyCrypto/LP bug #1119552).""" - - rsakey = """-----BEGIN RSA PRIVATE KEY----- - MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII - q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 - Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI - OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr - +rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK - JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 - n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== - -----END RSA PRIVATE KEY-----""" - - msg = b"This is a test\x0a" - - # PKCS1 v1.5 signature of the message computed using SHA-1. - # The digestAlgorithm SEQUENCE does NOT contain the NULL parameter. - sig_str = "a287a13517f716e72fb14eea8e33a8db4a4643314607e7ca3e3e28"\ - "1893db74013dda8b855fd99f6fecedcb25fcb7a434f35cd0a101f8"\ - "b19348e0bd7b6f152dfc" - signature = unhexlify(sig_str) - - def runTest(self): - verifier = pkcs1_15.new(RSA.importKey(self.rsakey)) - hashed = SHA1.new(self.msg) - verifier.verify(hashed, self.signature) - - -class PKCS1_Legacy_Module_Tests(unittest.TestCase): - """Verify that the legacy module Crypto.Signature.PKCS1_v1_5 - behaves as expected. The only difference is that the verify() - method returns True/False and does not raise exceptions.""" - - def shortDescription(self): - return "Test legacy Crypto.Signature.PKCS1_v1_5" - - def runTest(self): - key = RSA.importKey(PKCS1_15_NoParams.rsakey) - hashed = SHA1.new(b"Test") - good_signature = PKCS1_v1_5.new(key).sign(hashed) - verifier = PKCS1_v1_5.new(key.public_key()) - - self.assertEqual(verifier.verify(hashed, good_signature), True) - - # Flip a few bits in the signature - bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) - self.assertEqual(verifier.verify(hashed, bad_signature), False) - - -class PKCS1_All_Hashes_Tests(unittest.TestCase): - - def shortDescription(self): - return "Test PKCS#1v1.5 signature in combination with all hashes" - - def runTest(self): - - key = RSA.generate(1024) - signer = pkcs1_15.new(key) - hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", - "SHA224", "SHA256", "SHA384", "SHA512", - "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") - - for name in hash_names: - hashed = load_hash_by_name(name).new(b"Test") - signer.sign(hashed) - - from Crypto.Hash import BLAKE2b, BLAKE2s - for hash_size in (20, 32, 48, 64): - hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b"Test") - signer.sign(hashed_b) - for hash_size in (16, 20, 28, 32): - hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b"Test") - signer.sign(hashed_s) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - self.tv = [] - self.add_tests("rsa_sig_gen_misc_test.json") - self.add_tests("rsa_signature_2048_sha224_test.json") - self.add_tests("rsa_signature_2048_sha256_test.json") - self.add_tests("rsa_signature_2048_sha384_test.json") - self.add_tests("rsa_signature_2048_sha3_224_test.json") - self.add_tests("rsa_signature_2048_sha3_256_test.json") - self.add_tests("rsa_signature_2048_sha3_384_test.json") - self.add_tests("rsa_signature_2048_sha3_512_test.json") - self.add_tests("rsa_signature_2048_sha512_test.json") - self.add_tests("rsa_signature_2048_sha512_224_test.json") - self.add_tests("rsa_signature_2048_sha512_256_test.json") - self.add_tests("rsa_signature_3072_sha256_test.json") - self.add_tests("rsa_signature_3072_sha384_test.json") - self.add_tests("rsa_signature_3072_sha3_256_test.json") - self.add_tests("rsa_signature_3072_sha3_384_test.json") - self.add_tests("rsa_signature_3072_sha3_512_test.json") - self.add_tests("rsa_signature_3072_sha512_test.json") - self.add_tests("rsa_signature_3072_sha512_256_test.json") - self.add_tests("rsa_signature_4096_sha384_test.json") - self.add_tests("rsa_signature_4096_sha512_test.json") - self.add_tests("rsa_signature_4096_sha512_256_test.json") - self.add_tests("rsa_signature_test.json") - - def add_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['keyPem']) - - def filter_sha(group): - hash_name = group['sha'] - if hash_name == "SHA-512": - return SHA512 - elif hash_name == "SHA-512/224": - return SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - return SHA512.new(truncate="256") - elif hash_name == "SHA3-512": - return SHA3_512 - elif hash_name == "SHA-384": - return SHA384 - elif hash_name == "SHA3-384": - return SHA3_384 - elif hash_name == "SHA-256": - return SHA256 - elif hash_name == "SHA3-256": - return SHA3_256 - elif hash_name == "SHA-224": - return SHA224 - elif hash_name == "SHA3-224": - return SHA3_224 - elif hash_name == "SHA-1": - return SHA1 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - - def filter_type(group): - type_name = group['type'] - if type_name not in ("RsassaPkcs1Verify", "RsassaPkcs1Generate"): - raise ValueError("Unknown type name " + type_name) - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof PKCS#1v1.5 signature (%s)" % filename, - group_tag={'rsa_key': filter_rsa, - 'hash_mod': filter_sha, - 'type': filter_type}) - return result - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof RSA PKCS$#1 Test #" + str(tv.id) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = pkcs1_15.new(tv.key) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(FIPS_PKCS1_Verify_Tests) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests) - tests += list_test_cases(PKCS1_15_NoParams) - tests += list_test_cases(PKCS1_Legacy_Module_Tests) - tests += list_test_cases(PKCS1_All_Hashes_Tests) - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - - if config.get('slow_tests'): - tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) - - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pss.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pss.py deleted file mode 100644 index 535474b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Signature/test_pss.py +++ /dev/null @@ -1,377 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest - -from Crypto.Util.py3compat import b, bchr -from Crypto.Util.number import bytes_to_long -from Crypto.Util.strxor import strxor -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Hash import SHA1, SHA224, SHA256, SHA384, SHA512 -from Crypto.PublicKey import RSA -from Crypto.Signature import pss -from Crypto.Signature import PKCS1_PSS - -from Crypto.Signature.pss import MGF1 - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class PRNG(object): - - def __init__(self, stream): - self.stream = stream - self.idx = 0 - - def __call__(self, rnd_size): - result = self.stream[self.idx:self.idx + rnd_size] - self.idx += rnd_size - return result - - -class PSS_Tests(unittest.TestCase): - - rsa_key = b'-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsvI34FgiTK8+txBvmooNGpNwk23YTU51dwNZi5yha3W4lA/Q\nvcZrDalkmD7ekWQwnduxVKa6pRSI13KBgeUOIqJoGXSWhntEtY3FEwvWOHW5AE7Q\njUzTzCiYT6TVaCcpa/7YLai+p6ai2g5f5Zfh4jSawa9uYeuggFygQq4IVW796MgV\nyqxYMM/arEj+/sKz3Viua9Rp9fFosertCYCX4DUTgW0mX9bwEnEOgjSI3pLOPXz1\n8vx+DRZS5wMCmwCUa0sKonLn3cAUPq+sGix7+eo7T0Z12MU8ud7IYVX/75r3cXiF\nPaYE2q8Le0kgOApIXbb+x74x0rNgyIh1yGygkwIDAQABAoIBABz4t1A0pLT6qHI2\nEIOaNz3mwhK0dZEqkz0GB1Dhtoax5ATgvKCFB98J3lYB08IBURe1snOsnMpOVUtg\naBRSM+QqnCUG6bnzKjAkuFP5liDE+oNQv1YpKp9CsUovuzdmI8Au3ewihl+ZTIN2\nUVNYMEOR1b5m+z2SSwWNOYsiJwpBrT7zkpdlDyjat7FiiPhMMIMXjhQFVxURMIcB\njUBtPzGvV/PG90cVDWi1wRGeeP1dDqti/jsnvykQ15KW1MqGrpeNKRmDdTy/Ucl1\nWIoYklKw3U456lgZ/rDTDB818+Tlnk35z4yF7d5ANPM8CKfqOPcnO1BCKVFzf4eq\n54wvUtkCgYEA1Zv2lp06l7rXMsvNtyYQjbFChezRDRnPwZmN4NCdRtTgGG1G0Ryd\nYz6WWoPGqZp0b4LAaaHd3W2GTcpXF8WXMKfMX1W+tMAxMozfsXRKMcHoypwuS5wT\nfJRXJCG4pvd57AB0iVUEJW2we+uGKU5Zxcx//id2nXGCpoRyViIplQsCgYEA1nVC\neHupHChht0Fh4N09cGqZHZzuwXjOUMzR3Vsfz+4WzVS3NvIgN4g5YgmQFOeKwo5y\niRq5yvubcNdFvf85eHWClg0zPAyxJCVUWigCrrOanGEhJo6re4idJvNVzu4Ucg0v\n6B3SJ1HsCda+ZSNz24bSyqRep8A+RoAaoVSFx5kCgYEAn3RvXPs9s+obnqWYiPF3\nRe5etE6Vt2vfNKwFxx6zaR6bsmBQjuUHcABWiHb6I71S0bMPI0tbrWGG8ibrYKl1\nNTLtUvVVCOS3VP7oNTWT9RTFTAnOXU7DFSo+6o/poWn3r36ff6zhDXeWWMr2OXtt\ndEQ1/2lCGEGVv+v61eVmmQUCgYABFHITPTwqwiFL1O5zPWnzyPWgaovhOYSAb6eW\n38CXQXGn8wdBJZL39J2lWrr4//l45VK6UgIhfYbY2JynSkO10ZGow8RARygVMILu\nOUlaK9lZdDvAf/NpGdUAvzTtZ9F+iYZ2OsA2JnlzyzsGM1l//3vMPWukmJk3ral0\nqoJJ8QKBgGRG3eVHnIegBbFVuMDp2NTcfuSuDVUQ1fGAwtPiFa8u81IodJnMk2pq\niXu2+0ytNA/M+SVrAnE2AgIzcaJbtr0p2srkuVM7KMWnG1vWFNjtXN8fAhf/joOv\nD+NmPL/N4uE57e40tbiU/H7KdyZaDt+5QiTmdhuyAe6CBjKsF2jy\n-----END RSA PRIVATE KEY-----' - msg = b'AAA' - tag = b'\x00[c5\xd8\xb0\x8b!D\x81\x83\x07\xc0\xdd\xb9\xb4\xb2`\x92\xe7\x02\xf1\xe1P\xea\xc3\xf0\xe3>\xddX5\xdd\x8e\xc5\x89\xef\xf3\xc2\xdc\xfeP\x02\x7f\x12+\xc9\xaf\xbb\xec\xfe\xb0\xa5\xb9\x08\x11P\x8fL\xee5\x9b\xb0k{=_\xd2\x14\xfb\x01R\xb7\xfe\x14}b\x03\x8d5Y\x89~}\xfc\xf2l\xd01-\xbd\xeb\x11\xcdV\x11\xe9l\x19k/o5\xa2\x0f\x15\xe7Q$\t=\xec\x1dAB\x19\xa5P\x9a\xaf\xa3G\x86"\xd6~\xf0j\xfcqkbs\x13\x84b\xe4\xbdm(\xed`\xa4F\xfb\x8f.\xe1\x8c)/_\x9eS\x98\xa4v\xb8\xdc\xfe\xf7/D\x18\x19\xb3T\x97:\xe2\x96s\xe8<\xa2\xb4\xb9\xf8/' - - def test_positive_1(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg) - verifier = pss.new(key) - verifier.verify(h, self.tag) - - def test_negative_1(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg + b'A') - verifier = pss.new(key) - tag = bytearray(self.tag) - self.assertRaises(ValueError, verifier.verify, h, tag) - - def test_negative_2(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg) - verifier = pss.new(key, salt_bytes=1000) - tag = bytearray(self.tag) - self.assertRaises(ValueError, verifier.verify, h, tag) - - -class FIPS_PKCS1_Verify_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Verify)" - - def verify_positive(self, hashmod, message, public_key, salt, signature): - prng = PRNG(salt) - hashed = hashmod.new(message) - verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) - verifier.verify(hashed, signature) - - def verify_negative(self, hashmod, message, public_key, salt, signature): - prng = PRNG(salt) - hashed = hashmod.new(message) - verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) - self.assertRaises(ValueError, verifier.verify, hashed, signature) - - def test_can_sign(self): - test_public_key = RSA.generate(1024).public_key() - verifier = pss.new(test_public_key) - self.assertEqual(verifier.can_sign(), False) - - -class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "PKCS1-PSS"), - "SigVerPSS_186-3.rsp", - "Signature Verification 186-3", - {'shaalg': lambda x: x, - 'result': lambda x: x}) or [] - - -for count, tv in enumerate(test_vectors_verify): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "p"): - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore - if tv.saltval != b("\x00"): - prng = PRNG(tv.saltval) - verifier = pss.new(public_key, salt_bytes=len(tv.saltval), rand_func=prng) - else: - verifier = pss.new(public_key, salt_bytes=0) - - def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'p': - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) - else: - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) - - -class FIPS_PKCS1_Sign_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Sign)" - - def test_can_sign(self): - test_private_key = RSA.generate(1024) - signer = pss.new(test_private_key) - self.assertEqual(signer.can_sign(), True) - - -class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_sign = load_test_vectors(("Signature", "PKCS1-PSS"), - "SigGenPSS_186-2.txt", - "Signature Generation 186-2", - {'shaalg': lambda x: x}) or [] - -test_vectors_sign += load_test_vectors(("Signature", "PKCS1-PSS"), - "SigGenPSS_186-3.txt", - "Signature Generation 186-3", - {'shaalg': lambda x: x}) or [] - -for count, tv in enumerate(test_vectors_sign): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "e"): - private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - if tv.saltval != b("\x00"): - prng = PRNG(tv.saltval) - signer = pss.new(private_key, salt_bytes=len(tv.saltval), rand_func=prng) - else: - signer = pss.new(private_key, salt_bytes=0) - - def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): - signature = signer.sign(hash_obj) - self.assertEqual(signature, result) - - setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) - - -class PKCS1_Legacy_Module_Tests(unittest.TestCase): - """Verify that the legacy module Crypto.Signature.PKCS1_PSS - behaves as expected. The only difference is that the verify() - method returns True/False and does not raise exceptions.""" - - def shortDescription(self): - return "Test legacy Crypto.Signature.PKCS1_PSS" - - def runTest(self): - key = RSA.generate(1024) - hashed = SHA1.new(b("Test")) - good_signature = PKCS1_PSS.new(key).sign(hashed) - verifier = PKCS1_PSS.new(key.public_key()) - - self.assertEqual(verifier.verify(hashed, good_signature), True) - - # Flip a few bits in the signature - bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) - self.assertEqual(verifier.verify(hashed, bad_signature), False) - - -class PKCS1_All_Hashes_Tests(unittest.TestCase): - - def shortDescription(self): - return "Test PKCS#1 PSS signature in combination with all hashes" - - def runTest(self): - - key = RSA.generate(1280) - signer = pss.new(key) - hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", - "SHA224", "SHA256", "SHA384", "SHA512", - "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") - - for name in hash_names: - hashed = load_hash_by_name(name).new(b("Test")) - signer.sign(hashed) - - from Crypto.Hash import BLAKE2b, BLAKE2s - for hash_size in (20, 32, 48, 64): - hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b("Test")) - signer.sign(hashed_b) - for hash_size in (16, 20, 28, 32): - hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b("Test")) - signer.sign(hashed_s) - - -def get_hash_module(hash_name): - if hash_name == "SHA-512": - hash_module = SHA512 - elif hash_name == "SHA-512/224": - hash_module = SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - hash_module = SHA512.new(truncate="256") - elif hash_name == "SHA-384": - hash_module = SHA384 - elif hash_name == "SHA-256": - hash_module = SHA256 - elif hash_name == "SHA-224": - hash_module = SHA224 - elif hash_name == "SHA-1": - hash_module = SHA1 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - return hash_module - - -class TestVectorsPSSWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def add_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_type(group): - type_name = group['type'] - if type_name not in ("RsassaPssVerify", ): - raise ValueError("Unknown type name " + type_name) - - def filter_slen(group): - return group['sLen'] - - def filter_mgf(group): - mgf = group['mgf'] - if mgf not in ("MGF1", ): - raise ValueError("Unknown MGF " + mgf) - mgf1_hash = get_hash_module(group['mgfSha']) - - def mgf(x, y, mh=mgf1_hash): - return MGF1(x, y, mh) - - return mgf - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof PSS signature (%s)" % filename, - group_tag={'key': filter_rsa, - 'hash_module': filter_sha, - 'sLen': filter_slen, - 'mgf': filter_mgf, - 'type': filter_type}) - return result - - def setUp(self): - self.tv = [] - self.add_tests("rsa_pss_2048_sha1_mgf1_20_test.json") - self.add_tests("rsa_pss_2048_sha256_mgf1_0_test.json") - self.add_tests("rsa_pss_2048_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_2048_sha512_256_mgf1_28_test.json") - self.add_tests("rsa_pss_2048_sha512_256_mgf1_32_test.json") - self.add_tests("rsa_pss_3072_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_4096_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_4096_sha512_mgf1_32_test.json") - self.add_tests("rsa_pss_misc_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof RSA PSS Test #%d (%s)" % (tv.id, tv.comment) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = pss.new(tv.key, mask_func=tv.mgf, salt_bytes=tv.sLen) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PSS_Tests) - tests += list_test_cases(FIPS_PKCS1_Verify_Tests) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests) - tests += list_test_cases(PKCS1_Legacy_Module_Tests) - tests += list_test_cases(PKCS1_All_Hashes_Tests) - - if config.get('slow_tests'): - tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) - - tests += [TestVectorsPSSWycheproof(wycheproof_warnings)] - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/__init__.py deleted file mode 100644 index ee993db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/__init__.py: Self-test for utility modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-test for utility modules""" - -__revision__ = "$Id$" - -import os - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config) - from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config) - from Crypto.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config) - from Crypto.SelfTest.Util import test_strxor; tests += test_strxor.get_tests(config=config) - from Crypto.SelfTest.Util import test_asn1; tests += test_asn1.get_tests(config=config) - from Crypto.SelfTest.Util import test_rfc1751; tests += test_rfc1751.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Counter.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Counter.py deleted file mode 100644 index 8837a32..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Counter.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_Counter: Self-test for the Crypto.Util.Counter module -# -# Written in 2009 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-tests for Crypto.Util.Counter""" - -from Crypto.Util.py3compat import * - -import unittest - -class CounterTests(unittest.TestCase): - def setUp(self): - global Counter - from Crypto.Util import Counter - - def test_BE(self): - """Big endian""" - c = Counter.new(128) - c = Counter.new(128, little_endian=False) - - def test_LE(self): - """Little endian""" - c = Counter.new(128, little_endian=True) - - def test_nbits(self): - c = Counter.new(nbits=128) - self.assertRaises(ValueError, Counter.new, 129) - - def test_prefix(self): - c = Counter.new(128, prefix=b("xx")) - - def test_suffix(self): - c = Counter.new(128, suffix=b("xx")) - - def test_iv(self): - c = Counter.new(128, initial_value=2) - self.assertRaises(ValueError, Counter.new, 16, initial_value=0x1FFFF) - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - return list_test_cases(CounterTests) - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Padding.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Padding.py deleted file mode 100644 index 0929fd4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_Padding.py +++ /dev/null @@ -1,153 +0,0 @@ -# -# SelfTest/Util/test_Padding.py: Self-test for padding functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify as uh - -from Crypto.Util.py3compat import * -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.Padding import pad, unpad - -class PKCS7_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4) - self.assertTrue(padded == uh(b("04040404"))) - padded = pad(b(""), 4, 'pkcs7') - self.assertTrue(padded == uh(b("04040404"))) - back = unpad(padded, 4) - self.assertTrue(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4) - self.assertTrue(padded == uh(b("1234567804040404"))) - back = unpad(padded, 4) - self.assertTrue(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4) - self.assertTrue(padded == uh(b("12345601"))) - back = unpad(padded, 4) - self.assertTrue(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4) - self.assertTrue(padded == uh(b("1234567890030303"))) - back = unpad(padded, 4) - self.assertTrue(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, pad, uh(b("12")), 4, 'pkcs8') - - def testn2(self): - self.assertRaises(ValueError, unpad, b("\0\0\0"), 4) - self.assertRaises(ValueError, unpad, b(""), 4) - - def testn3(self): - self.assertRaises(ValueError, unpad, b("123456\x02"), 4) - self.assertRaises(ValueError, unpad, b("123456\x00"), 4) - self.assertRaises(ValueError, unpad, b("123456\x05\x05\x05\x05\x05"), 4) - -class X923_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4, 'x923') - self.assertTrue(padded == uh(b("00000004"))) - back = unpad(padded, 4, 'x923') - self.assertTrue(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4, 'x923') - self.assertTrue(padded == uh(b("1234567800000004"))) - back = unpad(padded, 4, 'x923') - self.assertTrue(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4, 'x923') - self.assertTrue(padded == uh(b("12345601"))) - back = unpad(padded, 4, 'x923') - self.assertTrue(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4, 'x923') - self.assertTrue(padded == uh(b("1234567890000003"))) - back = unpad(padded, 4, 'x923') - self.assertTrue(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, unpad, b("123456\x02"), 4, 'x923') - self.assertRaises(ValueError, unpad, b("123456\x00"), 4, 'x923') - self.assertRaises(ValueError, unpad, b("123456\x00\x00\x00\x00\x05"), 4, 'x923') - self.assertRaises(ValueError, unpad, b(""), 4, 'x923') - -class ISO7816_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4, 'iso7816') - self.assertTrue(padded == uh(b("80000000"))) - back = unpad(padded, 4, 'iso7816') - self.assertTrue(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4, 'iso7816') - self.assertTrue(padded == uh(b("1234567880000000"))) - back = unpad(padded, 4, 'iso7816') - self.assertTrue(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4, 'iso7816') - self.assertTrue(padded == uh(b("12345680"))) - back = unpad(padded, 4, 'iso7816') - self.assertTrue(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4, 'iso7816') - self.assertTrue(padded == uh(b("1234567890800000"))) - back = unpad(padded, 4, 'iso7816') - self.assertTrue(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, unpad, b("123456\x81"), 4, 'iso7816') - self.assertRaises(ValueError, unpad, b(""), 4, 'iso7816') - -def get_tests(config={}): - tests = [] - tests += list_test_cases(PKCS7_Tests) - tests += list_test_cases(X923_Tests) - tests += list_test_cases(ISO7816_Tests) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_asn1.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_asn1.py deleted file mode 100644 index e441ba0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_asn1.py +++ /dev/null @@ -1,851 +0,0 @@ -# -# SelfTest/Util/test_asn.py: Self-test for the Crypto.Util.asn1 module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.Util.asn1""" - -import unittest - -from Crypto.Util.py3compat import * -from Crypto.Util.asn1 import (DerObject, DerSetOf, DerInteger, - DerBitString, - DerObjectId, DerNull, DerOctetString, - DerSequence, DerBoolean) - -class DerObjectTests(unittest.TestCase): - - def testObjInit1(self): - # Fail with invalid tag format (must be 1 byte) - self.assertRaises(ValueError, DerObject, b('\x00\x99')) - # Fail with invalid implicit tag (must be <0x1F) - self.assertRaises(ValueError, DerObject, 0x1F) - - # ------ - - def testObjEncode1(self): - # No payload - der = DerObject(b('\x02')) - self.assertEqual(der.encode(), b('\x02\x00')) - # Small payload (primitive) - der.payload = b('\x45') - self.assertEqual(der.encode(), b('\x02\x01\x45')) - # Invariant - self.assertEqual(der.encode(), b('\x02\x01\x45')) - # Initialize with numerical tag - der = DerObject(0x04) - der.payload = b('\x45') - self.assertEqual(der.encode(), b('\x04\x01\x45')) - # Initialize with constructed type - der = DerObject(b('\x10'), constructed=True) - self.assertEqual(der.encode(), b('\x30\x00')) - - def testObjEncode2(self): - # Initialize with payload - der = DerObject(0x03, b('\x12\x12')) - self.assertEqual(der.encode(), b('\x03\x02\x12\x12')) - - def testObjEncode3(self): - # Long payload - der = DerObject(b('\x10')) - der.payload = b("0")*128 - self.assertEqual(der.encode(), b('\x10\x81\x80' + "0"*128)) - - def testObjEncode4(self): - # Implicit tags (constructed) - der = DerObject(0x10, implicit=1, constructed=True) - der.payload = b('ppll') - self.assertEqual(der.encode(), b('\xa1\x04ppll')) - # Implicit tags (primitive) - der = DerObject(0x02, implicit=0x1E, constructed=False) - der.payload = b('ppll') - self.assertEqual(der.encode(), b('\x9E\x04ppll')) - - def testObjEncode5(self): - # Encode type with explicit tag - der = DerObject(0x10, explicit=5) - der.payload = b("xxll") - self.assertEqual(der.encode(), b("\xa5\x06\x10\x04xxll")) - - # ----- - - def testObjDecode1(self): - # Decode short payload - der = DerObject(0x02) - der.decode(b('\x02\x02\x01\x02')) - self.assertEqual(der.payload, b("\x01\x02")) - self.assertEqual(der._tag_octet, 0x02) - - def testObjDecode2(self): - # Decode long payload - der = DerObject(0x02) - der.decode(b('\x02\x81\x80' + "1"*128)) - self.assertEqual(der.payload, b("1")*128) - self.assertEqual(der._tag_octet, 0x02) - - def testObjDecode3(self): - # Decode payload with too much data gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02\xFF')) - # Decode payload with too little data gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01')) - - def testObjDecode4(self): - # Decode implicit tag (primitive) - der = DerObject(0x02, constructed=False, implicit=0xF) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) - der.decode(b('\x8F\x01\x00')) - self.assertEqual(der.payload, b('\x00')) - # Decode implicit tag (constructed) - der = DerObject(0x02, constructed=True, implicit=0xF) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) - der.decode(b('\xAF\x01\x00')) - self.assertEqual(der.payload, b('\x00')) - - def testObjDecode5(self): - # Decode payload with unexpected tag gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02')) - - def testObjDecode6(self): - # Arbitrary DER object - der = DerObject() - der.decode(b('\x65\x01\x88')) - self.assertEqual(der._tag_octet, 0x65) - self.assertEqual(der.payload, b('\x88')) - - def testObjDecode7(self): - # Decode explicit tag - der = DerObject(0x10, explicit=5) - der.decode(b("\xa5\x06\x10\x04xxll")) - self.assertEqual(der._inner_tag_octet, 0x10) - self.assertEqual(der.payload, b('xxll')) - - # Explicit tag may be 0 - der = DerObject(0x10, explicit=0) - der.decode(b("\xa0\x06\x10\x04xxll")) - self.assertEqual(der._inner_tag_octet, 0x10) - self.assertEqual(der.payload, b('xxll')) - - def testObjDecode8(self): - # Verify that decode returns the object - der = DerObject(0x02) - self.assertEqual(der, der.decode(b('\x02\x02\x01\x02'))) - -class DerIntegerTests(unittest.TestCase): - - def testInit1(self): - der = DerInteger(1) - self.assertEqual(der.encode(), b('\x02\x01\x01')) - - def testEncode1(self): - # Single-byte integers - # Value 0 - der = DerInteger(0) - self.assertEqual(der.encode(), b('\x02\x01\x00')) - # Value 1 - der = DerInteger(1) - self.assertEqual(der.encode(), b('\x02\x01\x01')) - # Value 127 - der = DerInteger(127) - self.assertEqual(der.encode(), b('\x02\x01\x7F')) - - def testEncode2(self): - # Multi-byte integers - # Value 128 - der = DerInteger(128) - self.assertEqual(der.encode(), b('\x02\x02\x00\x80')) - # Value 0x180 - der = DerInteger(0x180) - self.assertEqual(der.encode(), b('\x02\x02\x01\x80')) - # One very long integer - der = DerInteger(2**2048) - self.assertEqual(der.encode(), - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - - def testEncode3(self): - # Negative integers - # Value -1 - der = DerInteger(-1) - self.assertEqual(der.encode(), b('\x02\x01\xFF')) - # Value -128 - der = DerInteger(-128) - self.assertEqual(der.encode(), b('\x02\x01\x80')) - # Value - der = DerInteger(-87873) - self.assertEqual(der.encode(), b('\x02\x03\xFE\xA8\xBF')) - - def testEncode4(self): - # Explicit encoding - number = DerInteger(0x34, explicit=3) - self.assertEqual(number.encode(), b('\xa3\x03\x02\x01\x34')) - - # ----- - - def testDecode1(self): - # Single-byte integer - der = DerInteger() - # Value 0 - der.decode(b('\x02\x01\x00')) - self.assertEqual(der.value, 0) - # Value 1 - der.decode(b('\x02\x01\x01')) - self.assertEqual(der.value, 1) - # Value 127 - der.decode(b('\x02\x01\x7F')) - self.assertEqual(der.value, 127) - - def testDecode2(self): - # Multi-byte integer - der = DerInteger() - # Value 0x180L - der.decode(b('\x02\x02\x01\x80')) - self.assertEqual(der.value,0x180) - # One very long integer - der.decode( - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - self.assertEqual(der.value,2**2048) - - def testDecode3(self): - # Negative integer - der = DerInteger() - # Value -1 - der.decode(b('\x02\x01\xFF')) - self.assertEqual(der.value, -1) - # Value -32768 - der.decode(b('\x02\x02\x80\x00')) - self.assertEqual(der.value, -32768) - - def testDecode5(self): - # We still accept BER integer format - der = DerInteger() - # Redundant leading zeroes - der.decode(b('\x02\x02\x00\x01')) - self.assertEqual(der.value, 1) - # Redundant leading 0xFF - der.decode(b('\x02\x02\xFF\xFF')) - self.assertEqual(der.value, -1) - # Empty payload - der.decode(b('\x02\x00')) - self.assertEqual(der.value, 0) - - def testDecode6(self): - # Explicit encoding - number = DerInteger(explicit=3) - number.decode(b('\xa3\x03\x02\x01\x34')) - self.assertEqual(number.value, 0x34) - - def testDecode7(self): - # Verify decode returns the DerInteger - der = DerInteger() - self.assertEqual(der, der.decode(b('\x02\x01\x7F'))) - - ### - - def testStrict1(self): - number = DerInteger() - - number.decode(b'\x02\x02\x00\x01') - number.decode(b'\x02\x02\x00\x7F') - self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x01', strict=True) - self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x7F', strict=True) - - ### - - def testErrDecode1(self): - # Wide length field - der = DerInteger() - self.assertRaises(ValueError, der.decode, b('\x02\x81\x01\x01')) - - -class DerSequenceTests(unittest.TestCase): - - def testInit1(self): - der = DerSequence([1, DerInteger(2), b('0\x00')]) - self.assertEqual(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00')) - - def testEncode1(self): - # Empty sequence - der = DerSequence() - self.assertEqual(der.encode(), b('0\x00')) - self.assertFalse(der.hasOnlyInts()) - # One single-byte integer (zero) - der.append(0) - self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) - self.assertEqual(der.hasInts(),1) - self.assertEqual(der.hasInts(False),1) - self.assertTrue(der.hasOnlyInts()) - self.assertTrue(der.hasOnlyInts(False)) - # Invariant - self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) - - def testEncode2(self): - # Indexing - der = DerSequence() - der.append(0) - der[0] = 1 - self.assertEqual(len(der),1) - self.assertEqual(der[0],1) - self.assertEqual(der[-1],1) - self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) - # - der[:] = [1] - self.assertEqual(len(der),1) - self.assertEqual(der[0],1) - self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) - - def testEncode3(self): - # One multi-byte integer (non-zero) - der = DerSequence() - der.append(0x180) - self.assertEqual(der.encode(), b('0\x04\x02\x02\x01\x80')) - - def testEncode4(self): - # One very long integer - der = DerSequence() - der.append(2**2048) - self.assertEqual(der.encode(), b('0\x82\x01\x05')+ - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - - def testEncode5(self): - der = DerSequence() - der += 1 - der += b('\x30\x00') - self.assertEqual(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00')) - - def testEncode6(self): - # Two positive integers - der = DerSequence() - der.append(0x180) - der.append(0xFF) - self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.assertTrue(der.hasOnlyInts()) - self.assertTrue(der.hasOnlyInts(False)) - # Two mixed integers - der = DerSequence() - der.append(2) - der.append(-2) - self.assertEqual(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) - self.assertEqual(der.hasInts(), 1) - self.assertEqual(der.hasInts(False), 2) - self.assertFalse(der.hasOnlyInts()) - self.assertTrue(der.hasOnlyInts(False)) - # - der.append(0x01) - der[1:] = [9,8] - self.assertEqual(len(der),3) - self.assertEqual(der[1:],[9,8]) - self.assertEqual(der[1:-1],[9]) - self.assertEqual(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08')) - - def testEncode7(self): - # One integer and another type (already encoded) - der = DerSequence() - der.append(0x180) - der.append(b('0\x03\x02\x01\x05')) - self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) - self.assertFalse(der.hasOnlyInts()) - - def testEncode8(self): - # One integer and another type (yet to encode) - der = DerSequence() - der.append(0x180) - der.append(DerSequence([5])) - self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) - self.assertFalse(der.hasOnlyInts()) - - #### - - def testDecode1(self): - # Empty sequence - der = DerSequence() - der.decode(b('0\x00')) - self.assertEqual(len(der),0) - # One single-byte integer (zero) - der.decode(b('0\x03\x02\x01\x00')) - self.assertEqual(len(der),1) - self.assertEqual(der[0],0) - # Invariant - der.decode(b('0\x03\x02\x01\x00')) - self.assertEqual(len(der),1) - self.assertEqual(der[0],0) - - def testDecode2(self): - # One single-byte integer (non-zero) - der = DerSequence() - der.decode(b('0\x03\x02\x01\x7f')) - self.assertEqual(len(der),1) - self.assertEqual(der[0],127) - - def testDecode4(self): - # One very long integer - der = DerSequence() - der.decode(b('0\x82\x01\x05')+ - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - self.assertEqual(len(der),1) - self.assertEqual(der[0],2**2048) - - def testDecode6(self): - # Two integers - der = DerSequence() - der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.assertEqual(len(der),2) - self.assertEqual(der[0],0x180) - self.assertEqual(der[1],0xFF) - - def testDecode7(self): - # One integer and 2 other types - der = DerSequence() - der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) - self.assertEqual(len(der),3) - self.assertEqual(der[0],0x180) - self.assertEqual(der[1],b('\x24\x02\xb6\x63')) - self.assertEqual(der[2],b('\x12\x00')) - - def testDecode8(self): - # Only 2 other types - der = DerSequence() - der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')) - self.assertEqual(len(der),2) - self.assertEqual(der[0],b('\x24\x02\xb6\x63')) - self.assertEqual(der[1],b('\x12\x00')) - self.assertEqual(der.hasInts(), 0) - self.assertEqual(der.hasInts(False), 0) - self.assertFalse(der.hasOnlyInts()) - self.assertFalse(der.hasOnlyInts(False)) - - def testDecode9(self): - # Verify that decode returns itself - der = DerSequence() - self.assertEqual(der, der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))) - - ### - - def testErrDecode1(self): - # Not a sequence - der = DerSequence() - self.assertRaises(ValueError, der.decode, b('')) - self.assertRaises(ValueError, der.decode, b('\x00')) - self.assertRaises(ValueError, der.decode, b('\x30')) - - def testErrDecode2(self): - der = DerSequence() - # Too much data - self.assertRaises(ValueError, der.decode, b('\x30\x00\x00')) - - def testErrDecode3(self): - # Wrong length format - der = DerSequence() - # Missing length in sub-item - self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00')) - # Valid BER, but invalid DER length - self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01')) - self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01')) - - def test_expected_nr_elements(self): - der_bin = DerSequence([1, 2, 3]).encode() - - DerSequence().decode(der_bin, nr_elements=3) - DerSequence().decode(der_bin, nr_elements=(2,3)) - self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=1) - self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=(4,5)) - - def test_expected_only_integers(self): - - der_bin1 = DerSequence([1, 2, 3]).encode() - der_bin2 = DerSequence([1, 2, DerSequence([3, 4])]).encode() - - DerSequence().decode(der_bin1, only_ints_expected=True) - DerSequence().decode(der_bin1, only_ints_expected=False) - DerSequence().decode(der_bin2, only_ints_expected=False) - self.assertRaises(ValueError, DerSequence().decode, der_bin2, only_ints_expected=True) - - -class DerOctetStringTests(unittest.TestCase): - - def testInit1(self): - der = DerOctetString(b('\xFF')) - self.assertEqual(der.encode(), b('\x04\x01\xFF')) - - def testEncode1(self): - # Empty sequence - der = DerOctetString() - self.assertEqual(der.encode(), b('\x04\x00')) - # Small payload - der.payload = b('\x01\x02') - self.assertEqual(der.encode(), b('\x04\x02\x01\x02')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerOctetString() - der.decode(b('\x04\x00')) - self.assertEqual(der.payload, b('')) - # Small payload - der.decode(b('\x04\x02\x01\x02')) - self.assertEqual(der.payload, b('\x01\x02')) - - def testDecode2(self): - # Verify that decode returns the object - der = DerOctetString() - self.assertEqual(der, der.decode(b('\x04\x00'))) - - def testErrDecode1(self): - # No leftovers allowed - der = DerOctetString() - self.assertRaises(ValueError, der.decode, b('\x04\x01\x01\xff')) - -class DerNullTests(unittest.TestCase): - - def testEncode1(self): - der = DerNull() - self.assertEqual(der.encode(), b('\x05\x00')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerNull() - self.assertEqual(der, der.decode(b('\x05\x00'))) - -class DerObjectIdTests(unittest.TestCase): - - def testInit1(self): - der = DerObjectId("1.1") - self.assertEqual(der.encode(), b'\x06\x01)') - - def testEncode1(self): - der = DerObjectId('1.2.840.113549.1.1.1') - self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') - - der = DerObjectId() - der.value = '1.2.840.113549.1.1.1' - self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') - - der = DerObjectId('2.999.1234') - self.assertEqual(der.encode(), b'\x06\x04\x88\x37\x89\x52') - - def testEncode2(self): - der = DerObjectId('3.4') - self.assertRaises(ValueError, der.encode) - - der = DerObjectId('1.40') - self.assertRaises(ValueError, der.encode) - - #### - - def testDecode1(self): - # Empty sequence - der = DerObjectId() - der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') - self.assertEqual(der.value, '1.2.840.113549.1.1.1') - - def testDecode2(self): - # Verify that decode returns the object - der = DerObjectId() - self.assertEqual(der, - der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) - - def testDecode3(self): - der = DerObjectId() - der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x00\x01') - self.assertEqual(der.value, '1.2.840.113549.1.0.1') - - def testDecode4(self): - der = DerObjectId() - der.decode(b'\x06\x04\x88\x37\x89\x52') - self.assertEqual(der.value, '2.999.1234') - - -class DerBitStringTests(unittest.TestCase): - - def testInit1(self): - der = DerBitString(b("\xFF")) - self.assertEqual(der.encode(), b('\x03\x02\x00\xFF')) - - def testInit2(self): - der = DerBitString(DerInteger(1)) - self.assertEqual(der.encode(), b('\x03\x04\x00\x02\x01\x01')) - - def testEncode1(self): - # Empty sequence - der = DerBitString() - self.assertEqual(der.encode(), b('\x03\x01\x00')) - # Small payload - der = DerBitString(b('\x01\x02')) - self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02')) - # Small payload - der = DerBitString() - der.value = b('\x01\x02') - self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerBitString() - der.decode(b('\x03\x00')) - self.assertEqual(der.value, b('')) - # Small payload - der.decode(b('\x03\x03\x00\x01\x02')) - self.assertEqual(der.value, b('\x01\x02')) - - def testDecode2(self): - # Verify that decode returns the object - der = DerBitString() - self.assertEqual(der, der.decode(b('\x03\x00'))) - - -class DerSetOfTests(unittest.TestCase): - - def testInit1(self): - der = DerSetOf([DerInteger(1), DerInteger(2)]) - self.assertEqual(der.encode(), b('1\x06\x02\x01\x01\x02\x01\x02')) - - def testEncode1(self): - # Empty set - der = DerSetOf() - self.assertEqual(der.encode(), b('1\x00')) - # One single-byte integer (zero) - der.add(0) - self.assertEqual(der.encode(), b('1\x03\x02\x01\x00')) - # Invariant - self.assertEqual(der.encode(), b('1\x03\x02\x01\x00')) - - def testEncode2(self): - # Two integers - der = DerSetOf() - der.add(0x180) - der.add(0xFF) - self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) - # Initialize with integers - der = DerSetOf([0x180, 0xFF]) - self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) - - def testEncode3(self): - # One integer and another type (no matter what it is) - der = DerSetOf() - der.add(0x180) - self.assertRaises(ValueError, der.add, b('\x00\x02\x00\x00')) - - def testEncode4(self): - # Only non integers - der = DerSetOf() - der.add(b('\x01\x00')) - der.add(b('\x01\x01\x01')) - self.assertEqual(der.encode(), b('1\x05\x01\x00\x01\x01\x01')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerSetOf() - der.decode(b('1\x00')) - self.assertEqual(len(der),0) - # One single-byte integer (zero) - der.decode(b('1\x03\x02\x01\x00')) - self.assertEqual(len(der),1) - self.assertEqual(list(der),[0]) - - def testDecode2(self): - # Two integers - der = DerSetOf() - der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.assertEqual(len(der),2) - l = list(der) - self.assertTrue(0x180 in l) - self.assertTrue(0xFF in l) - - def testDecode3(self): - # One integer and 2 other types - der = DerSetOf() - #import pdb; pdb.set_trace() - self.assertRaises(ValueError, der.decode, - b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) - - def testDecode4(self): - # Verify that decode returns the object - der = DerSetOf() - self.assertEqual(der, - der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff'))) - - ### - - def testErrDecode1(self): - # No leftovers allowed - der = DerSetOf() - self.assertRaises(ValueError, der.decode, - b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff\xAA')) - - -class DerBooleanTests(unittest.TestCase): - - def testEncode1(self): - der = DerBoolean(False) - self.assertEqual(der.encode(), b'\x01\x01\x00') - - def testEncode2(self): - der = DerBoolean(True) - self.assertEqual(der.encode(), b'\x01\x01\xFF') - - def testEncode3(self): - der = DerBoolean(False, implicit=0x12) - self.assertEqual(der.encode(), b'\x92\x01\x00') - - def testEncode4(self): - der = DerBoolean(False, explicit=0x05) - self.assertEqual(der.encode(), b'\xA5\x03\x01\x01\x00') - #### - - def testDecode1(self): - der = DerBoolean() - der.decode(b'\x01\x01\x00') - self.assertEqual(der.value, False) - - def testDecode2(self): - der = DerBoolean() - der.decode(b'\x01\x01\xFF') - self.assertEqual(der.value, True) - - def testDecode3(self): - der = DerBoolean(implicit=0x12) - der.decode(b'\x92\x01\x00') - self.assertEqual(der.value, False) - - def testDecode4(self): - der = DerBoolean(explicit=0x05) - der.decode(b'\xA5\x03\x01\x01\x00') - self.assertEqual(der.value, False) - - def testErrorDecode1(self): - der = DerBoolean() - # Wrong tag - self.assertRaises(ValueError, der.decode, b'\x02\x01\x00') - - def testErrorDecode2(self): - der = DerBoolean() - # Payload too long - self.assertRaises(ValueError, der.decode, b'\x01\x01\x00\xFF') - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(DerObjectTests) - listTests += list_test_cases(DerIntegerTests) - listTests += list_test_cases(DerSequenceTests) - listTests += list_test_cases(DerOctetStringTests) - listTests += list_test_cases(DerNullTests) - listTests += list_test_cases(DerObjectIdTests) - listTests += list_test_cases(DerBitStringTests) - listTests += list_test_cases(DerSetOfTests) - listTests += list_test_cases(DerBooleanTests) - return listTests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_number.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_number.py deleted file mode 100644 index bb143f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_number.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_number.py: Self-test for parts of the Crypto.Util.number module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self-tests for (some of) Crypto.Util.number""" - -import math -import unittest - -from Crypto.Util.py3compat import * -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util import number -from Crypto.Util.number import long_to_bytes - - -class MyError(Exception): - """Dummy exception used for tests""" - -# NB: In some places, we compare tuples instead of just output values so that -# if any inputs cause a test failure, we'll be able to tell which ones. - -class MiscTests(unittest.TestCase): - - def test_ceil_div(self): - """Util.number.ceil_div""" - self.assertRaises(TypeError, number.ceil_div, "1", 1) - self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0) - self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0) - - # b = 1 - self.assertEqual(0, number.ceil_div(0, 1)) - self.assertEqual(1, number.ceil_div(1, 1)) - self.assertEqual(2, number.ceil_div(2, 1)) - self.assertEqual(3, number.ceil_div(3, 1)) - - # b = 2 - self.assertEqual(0, number.ceil_div(0, 2)) - self.assertEqual(1, number.ceil_div(1, 2)) - self.assertEqual(1, number.ceil_div(2, 2)) - self.assertEqual(2, number.ceil_div(3, 2)) - self.assertEqual(2, number.ceil_div(4, 2)) - self.assertEqual(3, number.ceil_div(5, 2)) - - # b = 3 - self.assertEqual(0, number.ceil_div(0, 3)) - self.assertEqual(1, number.ceil_div(1, 3)) - self.assertEqual(1, number.ceil_div(2, 3)) - self.assertEqual(1, number.ceil_div(3, 3)) - self.assertEqual(2, number.ceil_div(4, 3)) - self.assertEqual(2, number.ceil_div(5, 3)) - self.assertEqual(2, number.ceil_div(6, 3)) - self.assertEqual(3, number.ceil_div(7, 3)) - - # b = 4 - self.assertEqual(0, number.ceil_div(0, 4)) - self.assertEqual(1, number.ceil_div(1, 4)) - self.assertEqual(1, number.ceil_div(2, 4)) - self.assertEqual(1, number.ceil_div(3, 4)) - self.assertEqual(1, number.ceil_div(4, 4)) - self.assertEqual(2, number.ceil_div(5, 4)) - self.assertEqual(2, number.ceil_div(6, 4)) - self.assertEqual(2, number.ceil_div(7, 4)) - self.assertEqual(2, number.ceil_div(8, 4)) - self.assertEqual(3, number.ceil_div(9, 4)) - - def test_getPrime(self): - """Util.number.getPrime""" - self.assertRaises(ValueError, number.getPrime, -100) - self.assertRaises(ValueError, number.getPrime, 0) - self.assertRaises(ValueError, number.getPrime, 1) - - bits = 4 - for i in range(100): - x = number.getPrime(bits) - self.assertEqual(x >= (1 << bits - 1), 1) - self.assertEqual(x < (1 << bits), 1) - - bits = 512 - x = number.getPrime(bits) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x >= (1 << bits - 1), 1) - self.assertEqual(x < (1 << bits), 1) - - def test_getStrongPrime(self): - """Util.number.getStrongPrime""" - self.assertRaises(ValueError, number.getStrongPrime, 256) - self.assertRaises(ValueError, number.getStrongPrime, 513) - bits = 512 - x = number.getStrongPrime(bits) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - e = 2**16+1 - x = number.getStrongPrime(bits, e) - self.assertEqual(number.GCD(x-1, e), 1) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - e = 2**16+2 - x = number.getStrongPrime(bits, e) - self.assertEqual(number.GCD((x-1)>>1, e), 1) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - - def test_isPrime(self): - """Util.number.isPrime""" - self.assertEqual(number.isPrime(-3), False) # Regression test: negative numbers should not be prime - self.assertEqual(number.isPrime(-2), False) # Regression test: negative numbers should not be prime - self.assertEqual(number.isPrime(1), False) # Regression test: isPrime(1) caused some versions of PyCrypto to crash. - self.assertEqual(number.isPrime(2), True) - self.assertEqual(number.isPrime(3), True) - self.assertEqual(number.isPrime(4), False) - self.assertEqual(number.isPrime(2**1279-1), True) - self.assertEqual(number.isPrime(-(2**1279-1)), False) # Regression test: negative numbers should not be prime - # test some known gmp pseudo-primes taken from - # http://www.trnicely.net/misc/mpzspsp.html - for composite in (43 * 127 * 211, 61 * 151 * 211, 15259 * 30517, - 346141 * 692281, 1007119 * 2014237, 3589477 * 7178953, - 4859419 * 9718837, 2730439 * 5460877, - 245127919 * 490255837, 963939391 * 1927878781, - 4186358431 * 8372716861, 1576820467 * 3153640933): - self.assertEqual(number.isPrime(int(composite)), False) - - def test_size(self): - self.assertEqual(number.size(2),2) - self.assertEqual(number.size(3),2) - self.assertEqual(number.size(0xa2),8) - self.assertEqual(number.size(0xa2ba40),8*3) - self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5), 1024) - self.assertRaises(ValueError, number.size, -1) - - -class LongTests(unittest.TestCase): - - def test1(self): - self.assertEqual(long_to_bytes(0), b'\x00') - self.assertEqual(long_to_bytes(1), b'\x01') - self.assertEqual(long_to_bytes(0x100), b'\x01\x00') - self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00') - self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00') - self.assertEqual(long_to_bytes(0x1122334455667788), b'\x11\x22\x33\x44\x55\x66\x77\x88') - self.assertEqual(long_to_bytes(0x112233445566778899), b'\x11\x22\x33\x44\x55\x66\x77\x88\x99') - - def test2(self): - self.assertEqual(long_to_bytes(0, 1), b'\x00') - self.assertEqual(long_to_bytes(0, 2), b'\x00\x00') - self.assertEqual(long_to_bytes(1, 3), b'\x00\x00\x01') - self.assertEqual(long_to_bytes(65535, 2), b'\xFF\xFF') - self.assertEqual(long_to_bytes(65536, 2), b'\x00\x01\x00\x00') - self.assertEqual(long_to_bytes(0x100, 1), b'\x01\x00') - self.assertEqual(long_to_bytes(0xFF00000001, 6), b'\x00\xFF\x00\x00\x00\x01') - self.assertEqual(long_to_bytes(0xFF00000001, 8), b'\x00\x00\x00\xFF\x00\x00\x00\x01') - self.assertEqual(long_to_bytes(0xFF00000001, 10), b'\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01') - self.assertEqual(long_to_bytes(0xFF00000001, 11), b'\x00\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01') - - def test_err1(self): - self.assertRaises(ValueError, long_to_bytes, -1) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(MiscTests) - tests += list_test_cases(LongTests) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_rfc1751.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_rfc1751.py deleted file mode 100644 index af0aa2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_rfc1751.py +++ /dev/null @@ -1,38 +0,0 @@ -import unittest - -import binascii -from Crypto.Util.RFC1751 import key_to_english, english_to_key - - -class RFC1751_Tests(unittest.TestCase): - - def test1(self): - data = [ - ('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), - ('CCAC2AED591056BE4F90FD441C534766', 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), - ('EFF81F9BFBC65350920CDD7416DE8009', 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') - ] - - for key_hex, words in data: - key_bin = binascii.a2b_hex(key_hex) - - w2 = key_to_english(key_bin) - self.assertEqual(w2, words) - - k2 = english_to_key(words) - self.assertEqual(k2, key_bin) - - def test_error_key_to_english(self): - - self.assertRaises(ValueError, key_to_english, b'0' * 7) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - tests = list_test_cases(RFC1751_Tests) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_strxor.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_strxor.py deleted file mode 100644 index c91d38f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/Util/test_strxor.py +++ /dev/null @@ -1,280 +0,0 @@ -# -# SelfTest/Util/test_strxor.py: Self-test for XORing -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify, hexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.strxor import strxor, strxor_c - - -class StrxorTests(unittest.TestCase): - - def test1(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - self.assertEqual(strxor(term1, term2), result) - self.assertEqual(strxor(term2, term1), result) - - def test2(self): - es = b"" - self.assertEqual(strxor(es, es), es) - - def test3(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - all_zeros = b"\x00" * len(term1) - self.assertEqual(strxor(term1, term1), all_zeros) - - def test_wrong_length(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"ff339a83e5cd4cdf564990") - self.assertRaises(ValueError, strxor, term1, term2) - - def test_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_ba = bytearray(term1) - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - - self.assertEqual(strxor(term1_ba, term2), result) - - def test_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_mv = memoryview(term1) - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - - self.assertEqual(strxor(term1_mv, term2), result) - - def test_output_bytearray(self): - """Verify result can be stored in pre-allocated memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - original_term1 = term1[:] - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - output = bytearray(len(term1)) - - result = strxor(term1, term2, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_xor) - self.assertEqual(term1, original_term1) - self.assertEqual(term2, original_term2) - - def test_output_memoryview(self): - """Verify result can be stored in pre-allocated memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - original_term1 = term1[:] - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - output = memoryview(bytearray(len(term1))) - - result = strxor(term1, term2, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_xor) - self.assertEqual(term1, original_term1) - self.assertEqual(term2, original_term2) - - def test_output_overlapping_bytearray(self): - """Verify result can be stored in overlapping memory""" - - term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - - result = strxor(term1, term2, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - self.assertEqual(term2, original_term2) - - def test_output_overlapping_memoryview(self): - """Verify result can be stored in overlapping memory""" - - term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) - term2 = unhexlify(b"383d4ba020573314395b") - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - - result = strxor(term1, term2, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - self.assertEqual(term2, original_term2) - - def test_output_ro_bytes(self): - """Verify result cannot be stored in read-only memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor, term1, term2, output=term1) - - def test_output_ro_memoryview(self): - """Verify result cannot be stored in read-only memory""" - - term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor, term1, term2, output=term1) - - def test_output_incorrect_length(self): - """Verify result cannot be stored in memory of incorrect length""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - output = bytearray(len(term1) - 1) - - self.assertRaises(ValueError, strxor, term1, term2, output=output) - - -class Strxor_cTests(unittest.TestCase): - - def test1(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - result = unhexlify(b"be72dbc2a48c0d9e1708") - self.assertEqual(strxor_c(term1, 65), result) - - def test2(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - self.assertEqual(strxor_c(term1, 0), term1) - - def test3(self): - self.assertEqual(strxor_c(b"", 90), b"") - - def test_wrong_range(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - self.assertRaises(ValueError, strxor_c, term1, -1) - self.assertRaises(ValueError, strxor_c, term1, 256) - - def test_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_ba = bytearray(term1) - result = unhexlify(b"be72dbc2a48c0d9e1708") - - self.assertEqual(strxor_c(term1_ba, 65), result) - - def test_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_mv = memoryview(term1) - result = unhexlify(b"be72dbc2a48c0d9e1708") - - self.assertEqual(strxor_c(term1_mv, 65), result) - - def test_output_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - original_term1 = term1[:] - expected_result = unhexlify(b"be72dbc2a48c0d9e1708") - output = bytearray(len(term1)) - - result = strxor_c(term1, 65, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_result) - self.assertEqual(term1, original_term1) - - def test_output_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - original_term1 = term1[:] - expected_result = unhexlify(b"be72dbc2a48c0d9e1708") - output = memoryview(bytearray(len(term1))) - - result = strxor_c(term1, 65, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_result) - self.assertEqual(term1, original_term1) - - def test_output_overlapping_bytearray(self): - """Verify result can be stored in overlapping memory""" - - term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) - expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") - - result = strxor_c(term1, 65, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - - def test_output_overlapping_memoryview(self): - """Verify result can be stored in overlapping memory""" - - term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) - expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") - - result = strxor_c(term1, 65, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - - def test_output_ro_bytes(self): - """Verify result cannot be stored in read-only memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - - self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) - - def test_output_ro_memoryview(self): - """Verify result cannot be stored in read-only memory""" - - term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) - - def test_output_incorrect_length(self): - """Verify result cannot be stored in memory of incorrect length""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - output = bytearray(len(term1) - 1) - - self.assertRaises(ValueError, strxor_c, term1, 65, output=output) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(StrxorTests) - tests += list_test_cases(Strxor_cTests) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__init__.py deleted file mode 100644 index 3a4b8b6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__init__.py +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/__init__.py: Self-test for PyCrypto -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Self tests - -These tests should perform quickly and can ideally be used every time an -application runs. -""" - -import sys -import unittest -from importlib import import_module -from Crypto.Util.py3compat import StringIO - - -class SelfTestError(Exception): - def __init__(self, message, result): - Exception.__init__(self, message, result) - self.message = message - self.result = result - - -def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs): - """Execute self-tests. - - This raises SelfTestError if any test is unsuccessful. - - You may optionally pass in a sub-module of SelfTest if you only want to - perform some of the tests. For example, the following would test only the - hash modules: - - Crypto.SelfTest.run(Crypto.SelfTest.Hash) - - """ - - if config is None: - config = {} - suite = unittest.TestSuite() - if module is None: - if tests is None: - tests = get_tests(config=config) - suite.addTests(tests) - else: - if tests is None: - suite.addTests(module.get_tests(config=config)) - else: - raise ValueError("'module' and 'tests' arguments are mutually exclusive") - if stream is None: - kwargs['stream'] = StringIO() - else: - kwargs['stream'] = stream - runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs) - result = runner.run(suite) - if not result.wasSuccessful(): - if stream is None: - sys.stderr.write(kwargs['stream'].getvalue()) - raise SelfTestError("Self-test failed", result) - return result - - -def get_tests(config={}): - tests = [] - - module_names = [ - "Cipher", "Hash", "Protocol", "PublicKey", "Random", - "Util", "Signature", "IO", "Math", - ] - - for name in module_names: - module = import_module("Crypto.SelfTest." + name) - tests += module.get_tests(config=config) - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__main__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__main__.py deleted file mode 100644 index 537254a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/__main__.py +++ /dev/null @@ -1,43 +0,0 @@ -#! /usr/bin/env python -# -# __main__.py : Stand-along loader for PyCryptodome test suite -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from __future__ import print_function - -import sys - -from Crypto import SelfTest - -slow_tests = not ("--skip-slow-tests" in sys.argv) -if not slow_tests: - print("Skipping slow tests") - -wycheproof_warnings = "--wycheproof-warnings" in sys.argv -if wycheproof_warnings: - print("Printing Wycheproof warnings") - -if "-v" in sys.argv: - verbosity=2 -else: - verbosity=1 - -config = {'slow_tests': slow_tests, 'wycheproof_warnings': wycheproof_warnings} -SelfTest.run(stream=sys.stdout, verbosity=verbosity, config=config) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/loader.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/loader.py deleted file mode 100644 index 16bc844..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/loader.py +++ /dev/null @@ -1,250 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import json -import errno -import binascii -import warnings -from binascii import unhexlify -from Crypto.Util.py3compat import FileNotFoundError - - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def _load_tests(dir_comps, file_in, description, conversions): - """Load and parse a test vector file - - Return a list of objects, one per group of adjacent - KV lines or for a single line in the form "[.*]". - - For a group of lines, the object has one attribute per line. - """ - - line_number = 0 - results = [] - - class TestVector(object): - def __init__(self, description, count): - self.desc = description - self.count = count - self.others = [] - - test_vector = None - count = 0 - new_group = True - - while True: - line_number += 1 - line = file_in.readline() - if not line: - if test_vector is not None: - results.append(test_vector) - break - line = line.strip() - - # Skip comments and empty lines - if line.startswith('#') or not line: - new_group = True - continue - - if line.startswith("["): - if test_vector is not None: - results.append(test_vector) - test_vector = None - results.append(line) - continue - - if new_group: - count += 1 - new_group = False - if test_vector is not None: - results.append(test_vector) - test_vector = TestVector("%s (#%d)" % (description, count), count) - - res = re.match("([A-Za-z0-9]+) = ?(.*)", line) - if not res: - test_vector.others += [line] - else: - token = res.group(1).lower() - data = res.group(2).lower() - - conversion = conversions.get(token, None) - if conversion is None: - if len(data) % 2 != 0: - data = "0" + data - setattr(test_vector, token, binascii.unhexlify(data)) - else: - setattr(test_vector, token, conversion(data)) - - # This line is ignored - return results - - -def load_test_vectors(dir_comps, file_name, description, conversions): - """Load and parse a test vector file, formatted using the NIST style. - - Args: - dir_comps (list of strings): - The path components under the ``pycryptodome_test_vectors`` package. - For instance ``("Cipher", "AES")``. - file_name (string): - The name of the file with the test vectors. - description (string): - A description applicable to the test vectors in the file. - conversions (dictionary): - The dictionary contains functions. - Values in the file that have an entry in this dictionary - will be converted usign the matching function. - Otherwise, values will be considered as hexadecimal and - converted to binary. - - Returns: - A list of test vector objects. - - The file is formatted in the following way: - - - Lines starting with "#" are comments and will be ignored. - - Each test vector is a sequence of 1 or more adjacent lines, where - each lines is an assignement. - - Test vectors are separated by an empty line, a comment, or - a line starting with "[". - - A test vector object has the following attributes: - - - desc (string): description - - counter (int): the order of the test vector in the file (from 1) - - others (list): zero or more lines of the test vector that were not assignments - - left-hand side of each assignment (lowercase): the value of the - assignement, either converted or bytes. - """ - - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - description = "%s test (%s)" % (description, file_name) - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name) as file_in: - results = _load_tests(dir_comps, file_in, description, conversions) - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for " + description, - UserWarning, - stacklevel=2) - - return results - - -def load_test_vectors_wycheproof(dir_comps, file_name, description, - root_tag={}, group_tag={}, unit_tag={}): - - result = [] - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name) as file_in: - tv_tree = json.load(file_in) - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for " + description, - UserWarning, - stacklevel=2) - return result - - class TestVector(object): - pass - - # Unique attributes that will be converted from - # hexadecimal to binary, unless the attribute is - # listed in the unit_tag dict - unit_attr_hex = {'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'label', - 'ikm', 'salt', 'info', 'okm', 'sig', 'public', - 'shared'} - unit_attr_hex -= set(unit_tag.keys()) - - common_root = {} - for k, v in root_tag.items(): - common_root[k] = v(tv_tree) - - for group in tv_tree['testGroups']: - - common_group = {} - for k, v in group_tag.items(): - common_group[k] = v(group) - - for test in group['tests']: - tv = TestVector() - - for k, v in common_root.items(): - setattr(tv, k, v) - for k, v in common_group.items(): - setattr(tv, k, v) - - tv.id = test['tcId'] - tv.comment = test['comment'] - for attr in unit_attr_hex: - if attr in test: - try: - setattr(tv, attr, unhexlify(test[attr])) - except binascii.Error: - raise ValueError("Error decoding attribute '%s' (tcId=%s, file %s)" % (attr, tv.id, file_name)) - tv.filename = file_name - - for k, v in unit_tag.items(): - setattr(tv, k, v(test)) - - tv.valid = test['result'] != "invalid" - tv.warning = test['result'] == "acceptable" - tv.flags = test.get('flags') - - tv.filename = file_name - - result.append(tv) - - return result - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/st_common.py b/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/st_common.py deleted file mode 100644 index e098d81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/SelfTest/st_common.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/st_common.py: Common functions for SelfTest modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Common functions for SelfTest modules""" - -import unittest -import binascii -from Crypto.Util.py3compat import b - - -def list_test_cases(class_): - """Return a list of TestCase instances given a TestCase class - - This is useful when you have defined test* methods on your TestCase class. - """ - return unittest.TestLoader().loadTestsFromTestCase(class_) - -def strip_whitespace(s): - """Remove whitespace from a text or byte string""" - if isinstance(s,str): - return b("".join(s.split())) - else: - return b("").join(s.split()) - -def a2b_hex(s): - """Convert hexadecimal to binary, ignoring whitespace""" - return binascii.a2b_hex(strip_whitespace(s)) - -def b2a_hex(s): - """Convert binary to hexadecimal""" - # For completeness - return binascii.b2a_hex(s) - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.py deleted file mode 100644 index 8017774..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.py +++ /dev/null @@ -1,403 +0,0 @@ -# -# Signature/DSS.py : DSS.py -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.asn1 import DerSequence -from Crypto.Util.number import long_to_bytes -from Crypto.Math.Numbers import Integer - -from Crypto.Hash import HMAC -from Crypto.PublicKey.ECC import EccKey -from Crypto.PublicKey.DSA import DsaKey - -__all__ = ['DssSigScheme', 'new'] - - -class DssSigScheme(object): - """A (EC)DSA signature object. - Do not instantiate directly. - Use :func:`Crypto.Signature.DSS.new`. - """ - - def __init__(self, key, encoding, order): - """Create a new Digital Signature Standard (DSS) object. - - Do not instantiate this object directly, - use `Crypto.Signature.DSS.new` instead. - """ - - self._key = key - self._encoding = encoding - self._order = order - - self._order_bits = self._order.size_in_bits() - self._order_bytes = (self._order_bits - 1) // 8 + 1 - - def can_sign(self): - """Return ``True`` if this signature object can be used - for signing messages.""" - - return self._key.has_private() - - def _compute_nonce(self, msg_hash): - raise NotImplementedError("To be provided by subclasses") - - def _valid_hash(self, msg_hash): - raise NotImplementedError("To be provided by subclasses") - - def sign(self, msg_hash): - """Compute the DSA/ECDSA signature of a message. - - Args: - msg_hash (hash object): - The hash that was carried out over the message. - The object belongs to the :mod:`Crypto.Hash` package. - Under mode ``'fips-186-3'``, the hash must be a FIPS - approved secure hash (SHA-2 or SHA-3). - - :return: The signature as ``bytes`` - :raise ValueError: if the hash algorithm is incompatible to the (EC)DSA key - :raise TypeError: if the (EC)DSA key has no private half - """ - - if not self._key.has_private(): - raise TypeError("Private key is needed to sign") - - if not self._valid_hash(msg_hash): - raise ValueError("Hash is not sufficiently strong") - - # Generate the nonce k (critical!) - nonce = self._compute_nonce(msg_hash) - - # Perform signature using the raw API - z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) - sig_pair = self._key._sign(z, nonce) - - # Encode the signature into a single byte string - if self._encoding == 'binary': - output = b"".join([long_to_bytes(x, self._order_bytes) - for x in sig_pair]) - else: - # Dss-sig ::= SEQUENCE { - # r INTEGER, - # s INTEGER - # } - # Ecdsa-Sig-Value ::= SEQUENCE { - # r INTEGER, - # s INTEGER - # } - output = DerSequence(sig_pair).encode() - - return output - - def verify(self, msg_hash, signature): - """Check if a certain (EC)DSA signature is authentic. - - Args: - msg_hash (hash object): - The hash that was carried out over the message. - This is an object belonging to the :mod:`Crypto.Hash` module. - Under mode ``'fips-186-3'``, the hash must be a FIPS - approved secure hash (SHA-2 or SHA-3). - - signature (``bytes``): - The signature that needs to be validated. - - :raise ValueError: if the signature is not authentic - """ - - if not self._valid_hash(msg_hash): - raise ValueError("Hash is not sufficiently strong") - - if self._encoding == 'binary': - if len(signature) != (2 * self._order_bytes): - raise ValueError("The signature is not authentic (length)") - r_prime, s_prime = [Integer.from_bytes(x) - for x in (signature[:self._order_bytes], - signature[self._order_bytes:])] - else: - try: - der_seq = DerSequence().decode(signature, strict=True) - except (ValueError, IndexError): - raise ValueError("The signature is not authentic (DER)") - if len(der_seq) != 2 or not der_seq.hasOnlyInts(): - raise ValueError("The signature is not authentic (DER content)") - r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1]) - - if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): - raise ValueError("The signature is not authentic (d)") - - z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) - result = self._key._verify(z, (r_prime, s_prime)) - if not result: - raise ValueError("The signature is not authentic") - # Make PyCrypto code to fail - return False - - -class DeterministicDsaSigScheme(DssSigScheme): - # Also applicable to ECDSA - - def __init__(self, key, encoding, order, private_key): - super(DeterministicDsaSigScheme, self).__init__(key, encoding, order) - self._private_key = private_key - - def _bits2int(self, bstr): - """See 2.3.2 in RFC6979""" - - result = Integer.from_bytes(bstr) - q_len = self._order.size_in_bits() - b_len = len(bstr) * 8 - if b_len > q_len: - # Only keep leftmost q_len bits - result >>= (b_len - q_len) - return result - - def _int2octets(self, int_mod_q): - """See 2.3.3 in RFC6979""" - - assert 0 < int_mod_q < self._order - return long_to_bytes(int_mod_q, self._order_bytes) - - def _bits2octets(self, bstr): - """See 2.3.4 in RFC6979""" - - z1 = self._bits2int(bstr) - if z1 < self._order: - z2 = z1 - else: - z2 = z1 - self._order - return self._int2octets(z2) - - def _compute_nonce(self, mhash): - """Generate k in a deterministic way""" - - # See section 3.2 in RFC6979.txt - # Step a - h1 = mhash.digest() - # Step b - mask_v = b'\x01' * mhash.digest_size - # Step c - nonce_k = b'\x00' * mhash.digest_size - - for int_oct in (b'\x00', b'\x01'): - # Step d/f - nonce_k = HMAC.new(nonce_k, - mask_v + int_oct + - self._int2octets(self._private_key) + - self._bits2octets(h1), mhash).digest() - # Step e/g - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - - nonce = -1 - while not (0 < nonce < self._order): - # Step h.C (second part) - if nonce != -1: - nonce_k = HMAC.new(nonce_k, mask_v + b'\x00', - mhash).digest() - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - - # Step h.A - mask_t = b"" - - # Step h.B - while len(mask_t) < self._order_bytes: - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - mask_t += mask_v - - # Step h.C (first part) - nonce = self._bits2int(mask_t) - return nonce - - def _valid_hash(self, msg_hash): - return True - - -class FipsDsaSigScheme(DssSigScheme): - - #: List of L (bit length of p) and N (bit length of q) combinations - #: that are allowed by FIPS 186-3. The security level is provided in - #: Table 2 of FIPS 800-57 (rev3). - _fips_186_3_L_N = ( - (1024, 160), # 80 bits (SHA-1 or stronger) - (2048, 224), # 112 bits (SHA-224 or stronger) - (2048, 256), # 128 bits (SHA-256 or stronger) - (3072, 256) # 256 bits (SHA-512) - ) - - def __init__(self, key, encoding, order, randfunc): - super(FipsDsaSigScheme, self).__init__(key, encoding, order) - self._randfunc = randfunc - - L = Integer(key.p).size_in_bits() - if (L, self._order_bits) not in self._fips_186_3_L_N: - error = ("L/N (%d, %d) is not compliant to FIPS 186-3" - % (L, self._order_bits)) - raise ValueError(error) - - def _compute_nonce(self, msg_hash): - # hash is not used - return Integer.random_range(min_inclusive=1, - max_exclusive=self._order, - randfunc=self._randfunc) - - def _valid_hash(self, msg_hash): - """Verify that SHA-1, SHA-2 or SHA-3 are used""" - return (msg_hash.oid == "1.3.14.3.2.26" or - msg_hash.oid.startswith("2.16.840.1.101.3.4.2.")) - - -class FipsEcDsaSigScheme(DssSigScheme): - - def __init__(self, key, encoding, order, randfunc): - super(FipsEcDsaSigScheme, self).__init__(key, encoding, order) - self._randfunc = randfunc - - def _compute_nonce(self, msg_hash): - return Integer.random_range(min_inclusive=1, - max_exclusive=self._key._curve.order, - randfunc=self._randfunc) - - def _valid_hash(self, msg_hash): - """Verify that the strength of the hash matches or exceeds - the strength of the EC. We fail if the hash is too weak.""" - - modulus_bits = self._key.pointQ.size_in_bits() - - # SHS: SHA-2, SHA-3, truncated SHA-512 - sha224 = ("2.16.840.1.101.3.4.2.4", "2.16.840.1.101.3.4.2.7", "2.16.840.1.101.3.4.2.5") - sha256 = ("2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8", "2.16.840.1.101.3.4.2.6") - sha384 = ("2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9") - sha512 = ("2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") - shs = sha224 + sha256 + sha384 + sha512 - - try: - result = msg_hash.oid in shs - except AttributeError: - result = False - return result - - -def new(key, mode, encoding='binary', randfunc=None): - """Create a signature object :class:`DssSigScheme` that - can perform (EC)DSA signature or verification. - - .. note:: - Refer to `NIST SP 800 Part 1 Rev 4`_ (or newer release) for an - overview of the recommended key lengths. - - Args: - key (:class:`Crypto.PublicKey.DSA` or :class:`Crypto.PublicKey.ECC`): - The key to use for computing the signature (*private* keys only) - or for verifying one. - For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` - and of ``q``: the pair ``(L,N)`` must appear in the following list, - in compliance to section 4.2 of `FIPS 186-4`_: - - - (1024, 160) *legacy only; do not create new signatures with this* - - (2048, 224) *deprecated; do not create new signatures with this* - - (2048, 256) - - (3072, 256) - - For ECC, only keys over P-224, P-256, P-384, and P-521 are accepted. - - mode (string): - The parameter can take these values: - - - ``'fips-186-3'``. The signature generation is randomized and carried out - according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. - - ``'deterministic-rfc6979'``. The signature generation is not - randomized. See RFC6979_. - - encoding (string): - How the signature is encoded. This value determines the output of - :meth:`sign` and the input to :meth:`verify`. - - The following values are accepted: - - - ``'binary'`` (default), the signature is the raw concatenation - of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. - For DSA, the size in bytes of the signature is ``N/4`` bytes - (e.g. 64 for ``N=256``). - For ECDSA, the signature is always twice the length of a point - coordinate (e.g. 64 bytes for P-256). - - - ``'der'``, the signature is a ASN.1 DER SEQUENCE - with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. - The size of the signature is variable. - - randfunc (callable): - A function that returns random ``bytes``, of a given length. - If omitted, the internal RNG is used. - Only applicable for the *'fips-186-3'* mode. - - .. _FIPS 186-3: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - .. _NIST SP 800 Part 1 Rev 4: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf - .. _RFC6979: http://tools.ietf.org/html/rfc6979 - .. _RFC3279: https://tools.ietf.org/html/rfc3279#section-2.2.2 - """ - - # The goal of the 'mode' parameter is to avoid to - # have the current version of the standard as default. - # - # Over time, such version will be superseded by (for instance) - # FIPS 186-4 and it will be odd to have -3 as default. - - if encoding not in ('binary', 'der'): - raise ValueError("Unknown encoding '%s'" % encoding) - - if isinstance(key, EccKey): - order = key._curve.order - private_key_attr = 'd' - if not key.curve.startswith("NIST"): - raise ValueError("ECC key is not on a NIST P curve") - elif isinstance(key, DsaKey): - order = Integer(key.q) - private_key_attr = 'x' - else: - raise ValueError("Unsupported key type " + str(type(key))) - - if key.has_private(): - private_key = getattr(key, private_key_attr) - else: - private_key = None - - if mode == 'deterministic-rfc6979': - return DeterministicDsaSigScheme(key, encoding, order, private_key) - elif mode == 'fips-186-3': - if isinstance(key, EccKey): - return FipsEcDsaSigScheme(key, encoding, order, randfunc) - else: - return FipsDsaSigScheme(key, encoding, order, randfunc) - else: - raise ValueError("Unknown DSS mode '%s'" % mode) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.pyi deleted file mode 100644 index 08cad81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/DSS.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union, Optional, Callable -from typing_extensions import Protocol - -from Crypto.PublicKey.DSA import DsaKey -from Crypto.PublicKey.ECC import EccKey - -class Hash(Protocol): - def digest(self) -> bytes: ... - -__all__ = ['new'] - -class DssSigScheme: - def __init__(self, key: Union[DsaKey, EccKey], encoding: str, order: int) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... - -class DeterministicDsaSigScheme(DssSigScheme): - def __init__(self, key, encoding, order, private_key) -> None: ... - -class FipsDsaSigScheme(DssSigScheme): - def __init__(self, key: DsaKey, encoding: str, order: int, randfunc: Callable) -> None: ... - -class FipsEcDsaSigScheme(DssSigScheme): - def __init__(self, key: EccKey, encoding: str, order: int, randfunc: Callable) -> None: ... - -def new(key: Union[DsaKey, EccKey], mode: str, encoding: Optional[str]='binary', randfunc: Optional[Callable]=None) -> Union[DeterministicDsaSigScheme, FipsDsaSigScheme, FipsEcDsaSigScheme]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.py deleted file mode 100644 index c39d388..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.py +++ /dev/null @@ -1,55 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Legacy module for PKCS#1 PSS signatures. - -:undocumented: __package__ -""" - -import types - -from Crypto.Signature import pss - - -def _pycrypto_verify(self, hash_object, signature): - try: - self._verify(hash_object, signature) - except (ValueError, TypeError): - return False - return True - - -def new(rsa_key, mgfunc=None, saltLen=None, randfunc=None): - pkcs1 = pss.new(rsa_key, mask_func=mgfunc, - salt_bytes=saltLen, rand_func=randfunc) - pkcs1._verify = pkcs1.verify - pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) - return pkcs1 diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.pyi deleted file mode 100644 index 1371e69..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_PSS.pyi +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union, Callable, Optional -from typing_extensions import Protocol - -from Crypto.PublicKey.RSA import RsaKey - - -class Hash(Protocol): - def digest(self) -> bytes: ... - def update(self, bytes) -> None: ... - - -class HashModule(Protocol): - @staticmethod - def new(data: Optional[bytes]) -> Hash: ... - - -MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] -RndFunction = Callable[[int], bytes] - -class PSS_SigScheme: - def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... - - - -def new(rsa_key: RsaKey, mgfunc: Optional[MaskFunction]=None, saltLen: Optional[int]=None, randfunc: Optional[RndFunction]=None) -> PSS_SigScheme: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.py deleted file mode 100644 index ac888ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.py +++ /dev/null @@ -1,53 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Legacy module for PKCS#1 v1.5 signatures. - -:undocumented: __package__ -""" - -import types - -from Crypto.Signature import pkcs1_15 - -def _pycrypto_verify(self, hash_object, signature): - try: - self._verify(hash_object, signature) - except (ValueError, TypeError): - return False - return True - -def new(rsa_key): - pkcs1 = pkcs1_15.new(rsa_key) - pkcs1._verify = pkcs1.verify - pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) - return pkcs1 - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.pyi deleted file mode 100644 index 6e9d8ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/PKCS1_v1_5.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Optional -from typing_extensions import Protocol - -from Crypto.PublicKey.RSA import RsaKey - -class Hash(Protocol): - def digest(self) -> bytes: ... - -class PKCS115_SigScheme: - def __init__(self, rsa_key: RsaKey) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... - - -def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/__init__.py deleted file mode 100644 index 11ca64c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Digital signature protocols - -A collection of standardized protocols to carry out digital signatures. -""" - -__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss', 'eddsa'] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.py deleted file mode 100644 index 0396b28..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.py +++ /dev/null @@ -1,343 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2022, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Math.Numbers import Integer - -from Crypto.Hash import SHA512, SHAKE256 -from Crypto.Util.py3compat import bchr, is_bytes -from Crypto.PublicKey.ECC import (EccKey, - construct, - _import_ed25519_public_key, - _import_ed448_public_key) - - -def import_public_key(encoded): - """Create a new Ed25519 or Ed448 public key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC8032. - - Args: - encoded (bytes): - The EdDSA public key to import. - It must be 32 bytes for Ed25519, and 57 bytes for Ed448. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - if len(encoded) == 32: - x, y = _import_ed25519_public_key(encoded) - curve_name = "Ed25519" - elif len(encoded) == 57: - x, y = _import_ed448_public_key(encoded) - curve_name = "Ed448" - else: - raise ValueError("Not an EdDSA key (%d bytes)" % len(encoded)) - return construct(curve=curve_name, point_x=x, point_y=y) - - -def import_private_key(encoded): - """Create a new Ed25519 or Ed448 private key object, - starting from the key encoded as raw ``bytes``, - in the format described in RFC8032. - - Args: - encoded (bytes): - The EdDSA private key to import. - It must be 32 bytes for Ed25519, and 57 bytes for Ed448. - - Returns: - :class:`Crypto.PublicKey.EccKey` : a new ECC key object. - - Raises: - ValueError: when the given key cannot be parsed. - """ - - if len(encoded) == 32: - curve_name = "ed25519" - elif len(encoded) == 57: - curve_name = "ed448" - else: - raise ValueError("Incorrect length. Only EdDSA private keys are supported.") - - # Note that the private key is truly a sequence of random bytes, - # so we cannot check its correctness in any way. - - return construct(seed=encoded, curve=curve_name) - - -class EdDSASigScheme(object): - """An EdDSA signature object. - Do not instantiate directly. - Use :func:`Crypto.Signature.eddsa.new`. - """ - - def __init__(self, key, context): - """Create a new EdDSA object. - - Do not instantiate this object directly, - use `Crypto.Signature.DSS.new` instead. - """ - - self._key = key - self._context = context - self._A = key._export_eddsa_public() - self._order = key._curve.order - - def can_sign(self): - """Return ``True`` if this signature object can be used - for signing messages.""" - - return self._key.has_private() - - def sign(self, msg_or_hash): - """Compute the EdDSA signature of a message. - - Args: - msg_or_hash (bytes or a hash object): - The message to sign (``bytes``, in case of *PureEdDSA*) or - the hash that was carried out over the message (hash object, for *HashEdDSA*). - - The hash object must be :class:`Crypto.Hash.SHA512` for Ed25519, - and :class:`Crypto.Hash.SHAKE256` object for Ed448. - - :return: The signature as ``bytes``. It is always 64 bytes for Ed25519, and 114 bytes for Ed448. - :raise TypeError: if the EdDSA key has no private half - """ - - if not self._key.has_private(): - raise TypeError("Private key is needed to sign") - - if self._key.curve == "Ed25519": - ph = isinstance(msg_or_hash, SHA512.SHA512Hash) - if not (ph or is_bytes(msg_or_hash)): - raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") - eddsa_sign_method = self._sign_ed25519 - - elif self._key.curve == "Ed448": - ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) - if not (ph or is_bytes(msg_or_hash)): - raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") - eddsa_sign_method = self._sign_ed448 - - else: - raise ValueError("Incorrect curve for EdDSA") - - return eddsa_sign_method(msg_or_hash, ph) - - def _sign_ed25519(self, msg_or_hash, ph): - - if self._context or ph: - flag = int(ph) - # dom2(flag, self._context) - dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ - bchr(len(self._context)) + self._context - else: - dom2 = b'' - - PHM = msg_or_hash.digest() if ph else msg_or_hash - - # See RFC 8032, section 5.1.6 - - # Step 2 - r_hash = SHA512.new(dom2 + self._key._prefix + PHM).digest() - r = Integer.from_bytes(r_hash, 'little') % self._order - # Step 3 - R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa_public() - # Step 4 - k_hash = SHA512.new(dom2 + R_pk + self._A + PHM).digest() - k = Integer.from_bytes(k_hash, 'little') % self._order - # Step 5 - s = (r + k * self._key.d) % self._order - - return R_pk + s.to_bytes(32, 'little') - - def _sign_ed448(self, msg_or_hash, ph): - - flag = int(ph) - # dom4(flag, self._context) - dom4 = b'SigEd448' + bchr(flag) + \ - bchr(len(self._context)) + self._context - - PHM = msg_or_hash.copy().read(64) if ph else msg_or_hash - - # See RFC 8032, section 5.2.6 - - # Step 2 - r_hash = SHAKE256.new(dom4 + self._key._prefix + PHM).read(114) - r = Integer.from_bytes(r_hash, 'little') % self._order - # Step 3 - R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa_public() - # Step 4 - k_hash = SHAKE256.new(dom4 + R_pk + self._A + PHM).read(114) - k = Integer.from_bytes(k_hash, 'little') % self._order - # Step 5 - s = (r + k * self._key.d) % self._order - - return R_pk + s.to_bytes(57, 'little') - - def verify(self, msg_or_hash, signature): - """Check if an EdDSA signature is authentic. - - Args: - msg_or_hash (bytes or a hash object): - The message to verify (``bytes``, in case of *PureEdDSA*) or - the hash that was carried out over the message (hash object, for *HashEdDSA*). - - The hash object must be :class:`Crypto.Hash.SHA512` object for Ed25519, - and :class:`Crypto.Hash.SHAKE256` for Ed448. - - signature (``bytes``): - The signature that needs to be validated. - It must be 64 bytes for Ed25519, and 114 bytes for Ed448. - - :raise ValueError: if the signature is not authentic - """ - - if self._key.curve == "Ed25519": - ph = isinstance(msg_or_hash, SHA512.SHA512Hash) - if not (ph or is_bytes(msg_or_hash)): - raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") - eddsa_verify_method = self._verify_ed25519 - - elif self._key.curve == "Ed448": - ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) - if not (ph or is_bytes(msg_or_hash)): - raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") - eddsa_verify_method = self._verify_ed448 - - else: - raise ValueError("Incorrect curve for EdDSA") - - return eddsa_verify_method(msg_or_hash, signature, ph) - - def _verify_ed25519(self, msg_or_hash, signature, ph): - - if len(signature) != 64: - raise ValueError("The signature is not authentic (length)") - - if self._context or ph: - flag = int(ph) - dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ - bchr(len(self._context)) + self._context - else: - dom2 = b'' - - PHM = msg_or_hash.digest() if ph else msg_or_hash - - # Section 5.1.7 - - # Step 1 - try: - R = import_public_key(signature[:32]).pointQ - except ValueError: - raise ValueError("The signature is not authentic (R)") - s = Integer.from_bytes(signature[32:], 'little') - if s > self._order: - raise ValueError("The signature is not authentic (S)") - # Step 2 - k_hash = SHA512.new(dom2 + signature[:32] + self._A + PHM).digest() - k = Integer.from_bytes(k_hash, 'little') % self._order - # Step 3 - point1 = s * 8 * self._key._curve.G - # OPTIMIZE: with double-scalar multiplication, with no SCA - # countermeasures because it is public values - point2 = 8 * R + k * 8 * self._key.pointQ - if point1 != point2: - raise ValueError("The signature is not authentic") - - def _verify_ed448(self, msg_or_hash, signature, ph): - - if len(signature) != 114: - raise ValueError("The signature is not authentic (length)") - - flag = int(ph) - # dom4(flag, self._context) - dom4 = b'SigEd448' + bchr(flag) + \ - bchr(len(self._context)) + self._context - - PHM = msg_or_hash.copy().read(64) if ph else msg_or_hash - - # Section 5.2.7 - - # Step 1 - try: - R = import_public_key(signature[:57]).pointQ - except ValueError: - raise ValueError("The signature is not authentic (R)") - s = Integer.from_bytes(signature[57:], 'little') - if s > self._order: - raise ValueError("The signature is not authentic (S)") - # Step 2 - k_hash = SHAKE256.new(dom4 + signature[:57] + self._A + PHM).read(114) - k = Integer.from_bytes(k_hash, 'little') % self._order - # Step 3 - point1 = s * 8 * self._key._curve.G - # OPTIMIZE: with double-scalar multiplication, with no SCA - # countermeasures because it is public values - point2 = 8 * R + k * 8 * self._key.pointQ - if point1 != point2: - raise ValueError("The signature is not authentic") - - -def new(key, mode, context=None): - """Create a signature object :class:`EdDSASigScheme` that - can perform or verify an EdDSA signature. - - Args: - key (:class:`Crypto.PublicKey.ECC` object): - The key to use for computing the signature (*private* keys only) - or for verifying one. - The key must be on the curve ``Ed25519`` or ``Ed448``. - - mode (string): - This parameter must be ``'rfc8032'``. - - context (bytes): - Up to 255 bytes of `context `_, - which is a constant byte string to segregate different protocols or - different applications of the same key. - """ - - if not isinstance(key, EccKey) or key.curve not in ("Ed25519", "Ed448"): - raise ValueError("EdDSA can only be used with EdDSA keys") - - if mode != 'rfc8032': - raise ValueError("Mode must be 'rfc8032'") - - if context is None: - context = b'' - elif len(context) > 255: - raise ValueError("Context for EdDSA must not be longer than 255 bytes") - - return EdDSASigScheme(key, context) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.pyi deleted file mode 100644 index 060d593..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/eddsa.pyi +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union, Optional -from typing_extensions import Protocol -from Crypto.PublicKey.ECC import EccKey - -class Hash(Protocol): - def digest(self) -> bytes: ... - -class XOF(Protocol): - def read(self, len: int) -> bytes: ... - -def import_public_key(encoded: bytes) -> EccKey: ... -def import_private_key(encoded: bytes) -> EccKey: ... - -class EdDSASigScheme(object): - - def __init__(self, key: EccKey, context: bytes) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_or_hash: Union[bytes, Hash, XOF]) -> bytes: ... - def verify(self, msg_or_hash: Union[bytes, Hash, XOF], signature: bytes) -> None: ... - -def new(key: EccKey, mode: str, context: Optional[bytes]=None) -> EdDSASigScheme: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pkcs1_15.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pkcs1_15.py deleted file mode 100644 index 0b02d99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pkcs1_15.py +++ /dev/null @@ -1,223 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import Crypto.Util.number -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId - -class PKCS115_SigScheme: - """A signature object for ``RSASSA-PKCS1-v1_5``. - Do not instantiate directly. - Use :func:`Crypto.Signature.pkcs1_15.new`. - """ - - def __init__(self, rsa_key): - """Initialize this PKCS#1 v1.5 signature scheme object. - - :Parameters: - rsa_key : an RSA key object - Creation of signatures is only possible if this is a *private* - RSA key. Verification of signatures is always possible. - """ - self._key = rsa_key - - def can_sign(self): - """Return ``True`` if this object can be used to sign messages.""" - return self._key.has_private() - - def sign(self, msg_hash): - """Create the PKCS#1 v1.5 signature of a message. - - This function is also called ``RSASSA-PKCS1-V1_5-SIGN`` and - it is specified in - `section 8.2.1 of RFC8017 `_. - - :parameter msg_hash: - This is an object from the :mod:`Crypto.Hash` package. - It has been used to digest the message to sign. - :type msg_hash: hash object - - :return: the signature encoded as a *byte string*. - :raise ValueError: if the RSA key is not long enough for the given hash algorithm. - :raise TypeError: if the RSA key has no private half. - """ - - # See 8.2.1 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes - - # Step 1 - em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) - # Step 2a (OS2IP) - em_int = bytes_to_long(em) - # Step 2b (RSASP1) and Step 2c (I2OSP) - signature = self._key._decrypt_to_bytes(em_int) - # Verify no faults occurred - if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): - raise ValueError("Fault detected in RSA private key operation") - return signature - - def verify(self, msg_hash, signature): - """Check if the PKCS#1 v1.5 signature over a message is valid. - - This function is also called ``RSASSA-PKCS1-V1_5-VERIFY`` and - it is specified in - `section 8.2.2 of RFC8037 `_. - - :parameter msg_hash: - The hash that was carried out over the message. This is an object - belonging to the :mod:`Crypto.Hash` module. - :type parameter: hash object - - :parameter signature: - The signature that needs to be validated. - :type signature: byte string - - :raise ValueError: if the signature is not valid. - """ - - # See 8.2.2 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes - - # Step 1 - if len(signature) != k: - raise ValueError("Invalid signature") - # Step 2a (O2SIP) - signature_int = bytes_to_long(signature) - # Step 2b (RSAVP1) - em_int = self._key._encrypt(signature_int) - # Step 2c (I2OSP) - em1 = long_to_bytes(em_int, k) - # Step 3 - try: - possible_em1 = [ _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, True) ] - # MD2/4/5 hashes always require NULL params in AlgorithmIdentifier. - # For all others, it is optional. - try: - algorithm_is_md = msg_hash.oid.startswith('1.2.840.113549.2.') - except AttributeError: - algorithm_is_md = False - if not algorithm_is_md: # MD2/MD4/MD5 - possible_em1.append(_EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, False)) - except ValueError: - raise ValueError("Invalid signature") - # Step 4 - # By comparing the full encodings (as opposed to checking each - # of its components one at a time) we avoid attacks to the padding - # scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537). - # - if em1 not in possible_em1: - raise ValueError("Invalid signature") - pass - - -def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True): - """ - Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.2). - - ``_EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, - and hash it internally. Here, we expect that the message has already - been hashed instead. - - :Parameters: - msg_hash : hash object - The hash object that holds the digest of the message being signed. - emLen : int - The length the final encoding must have, in bytes. - with_hash_parameters : bool - If True (default), include NULL parameters for the hash - algorithm in the ``digestAlgorithm`` SEQUENCE. - - :attention: the early standard (RFC2313) stated that ``DigestInfo`` - had to be BER-encoded. This means that old signatures - might have length tags in indefinite form, which - is not supported in DER. Such encoding cannot be - reproduced by this function. - - :Return: An ``emLen`` byte long string that encodes the hash. - """ - - # First, build the ASN.1 DER object DigestInfo: - # - # DigestInfo ::= SEQUENCE { - # digestAlgorithm AlgorithmIdentifier, - # digest OCTET STRING - # } - # - # where digestAlgorithm identifies the hash function and shall be an - # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. - # - # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { - # { OID id-md2 PARAMETERS NULL }| - # { OID id-md5 PARAMETERS NULL }| - # { OID id-sha1 PARAMETERS NULL }| - # { OID id-sha256 PARAMETERS NULL }| - # { OID id-sha384 PARAMETERS NULL }| - # { OID id-sha512 PARAMETERS NULL } - # } - # - # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters - # should be omitted. They may be present, but when they are, they shall - # have NULL value. - - digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) - - if with_hash_parameters: - digestAlgo.append(DerNull().encode()) - - digest = DerOctetString(msg_hash.digest()) - digestInfo = DerSequence([ - digestAlgo.encode(), - digest.encode() - ]).encode() - - # We need at least 11 bytes for the remaining data: 3 fixed bytes and - # at least 8 bytes of padding). - if emLen bytes: ... - -class PKCS115_SigScheme: - def __init__(self, rsa_key: RsaKey) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> None: ... - -def _EMSA_PKCS1_V1_5_ENCODE(msg_hash: Hash, emLen: int, with_hash_parameters: Optional[bool]=True) -> bytes: ... - -def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.py deleted file mode 100644 index f2295df..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.py +++ /dev/null @@ -1,387 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bchr, bord, iter_range -import Crypto.Util.number -from Crypto.Util.number import (ceil_div, - long_to_bytes, - bytes_to_long - ) -from Crypto.Util.strxor import strxor -from Crypto import Random - - -class PSS_SigScheme: - """A signature object for ``RSASSA-PSS``. - Do not instantiate directly. - Use :func:`Crypto.Signature.pss.new`. - """ - - def __init__(self, key, mgfunc, saltLen, randfunc): - """Initialize this PKCS#1 PSS signature scheme object. - - :Parameters: - key : an RSA key object - If a private half is given, both signature and - verification are possible. - If a public half is given, only verification is possible. - mgfunc : callable - A mask generation function that accepts two parameters: - a string to use as seed, and the lenth of the mask to - generate, in bytes. - saltLen : integer - Length of the salt, in bytes. - randfunc : callable - A function that returns random bytes. - """ - - self._key = key - self._saltLen = saltLen - self._mgfunc = mgfunc - self._randfunc = randfunc - - def can_sign(self): - """Return ``True`` if this object can be used to sign messages.""" - return self._key.has_private() - - def sign(self, msg_hash): - """Create the PKCS#1 PSS signature of a message. - - This function is also called ``RSASSA-PSS-SIGN`` and - it is specified in - `section 8.1.1 of RFC8017 `_. - - :parameter msg_hash: - This is an object from the :mod:`Crypto.Hash` package. - It has been used to digest the message to sign. - :type msg_hash: hash object - - :return: the signature encoded as a *byte string*. - :raise ValueError: if the RSA key is not long enough for the given hash algorithm. - :raise TypeError: if the RSA key has no private half. - """ - - # Set defaults for salt length and mask generation function - if self._saltLen is None: - sLen = msg_hash.digest_size - else: - sLen = self._saltLen - - if self._mgfunc is None: - mgf = lambda x, y: MGF1(x, y, msg_hash) - else: - mgf = self._mgfunc - - modBits = Crypto.Util.number.size(self._key.n) - - # See 8.1.1 in RFC3447 - k = ceil_div(modBits, 8) # k is length in bytes of the modulus - # Step 1 - em = _EMSA_PSS_ENCODE(msg_hash, modBits-1, self._randfunc, mgf, sLen) - # Step 2a (OS2IP) - em_int = bytes_to_long(em) - # Step 2b (RSASP1) and Step 2c (I2OSP) - signature = self._key._decrypt_to_bytes(em_int) - # Verify no faults occurred - if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): - raise ValueError("Fault detected in RSA private key operation") - return signature - - def verify(self, msg_hash, signature): - """Check if the PKCS#1 PSS signature over a message is valid. - - This function is also called ``RSASSA-PSS-VERIFY`` and - it is specified in - `section 8.1.2 of RFC8037 `_. - - :parameter msg_hash: - The hash that was carried out over the message. This is an object - belonging to the :mod:`Crypto.Hash` module. - :type parameter: hash object - - :parameter signature: - The signature that needs to be validated. - :type signature: bytes - - :raise ValueError: if the signature is not valid. - """ - - # Set defaults for salt length and mask generation function - if self._saltLen is None: - sLen = msg_hash.digest_size - else: - sLen = self._saltLen - if self._mgfunc: - mgf = self._mgfunc - else: - mgf = lambda x, y: MGF1(x, y, msg_hash) - - modBits = Crypto.Util.number.size(self._key.n) - - # See 8.1.2 in RFC3447 - k = ceil_div(modBits, 8) # Convert from bits to bytes - # Step 1 - if len(signature) != k: - raise ValueError("Incorrect signature") - # Step 2a (O2SIP) - signature_int = bytes_to_long(signature) - # Step 2b (RSAVP1) - em_int = self._key._encrypt(signature_int) - # Step 2c (I2OSP) - emLen = ceil_div(modBits - 1, 8) - em = long_to_bytes(em_int, emLen) - # Step 3/4 - _EMSA_PSS_VERIFY(msg_hash, em, modBits-1, mgf, sLen) - - -def MGF1(mgfSeed, maskLen, hash_gen): - """Mask Generation Function, described in `B.2.1 of RFC8017 - `_. - - :param mfgSeed: - seed from which the mask is generated - :type mfgSeed: byte string - - :param maskLen: - intended length in bytes of the mask - :type maskLen: integer - - :param hash_gen: - A module or a hash object from :mod:`Crypto.Hash` - :type hash_object: - - :return: the mask, as a *byte string* - """ - - T = b"" - for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): - c = long_to_bytes(counter, 4) - hobj = hash_gen.new() - hobj.update(mgfSeed + c) - T = T + hobj.digest() - assert(len(T) >= maskLen) - return T[:maskLen] - - -def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): - r""" - Implement the ``EMSA-PSS-ENCODE`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.1.1). - - The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` - as input, and hash it internally. Here, we expect that the message - has already been hashed instead. - - :Parameters: - mhash : hash object - The hash object that holds the digest of the message being signed. - emBits : int - Maximum length of the final encoding, in bits. - randFunc : callable - An RNG function that accepts as only parameter an int, and returns - a string of random bytes, to be used as salt. - mgf : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - sLen : int - Length of the salt, in bytes. - - :Return: An ``emLen`` byte long string that encodes the hash - (with ``emLen = \ceil(emBits/8)``). - - :Raise ValueError: - When digest or salt length are too big. - """ - - emLen = ceil_div(emBits, 8) - - # Bitmask of digits that fill up - lmask = 0 - for i in iter_range(8*emLen-emBits): - lmask = lmask >> 1 | 0x80 - - # Step 1 and 2 have been already done - # Step 3 - if emLen < mhash.digest_size+sLen+2: - raise ValueError("Digest or salt length are too long" - " for given key size.") - # Step 4 - salt = randFunc(sLen) - # Step 5 - m_prime = bchr(0)*8 + mhash.digest() + salt - # Step 6 - h = mhash.new() - h.update(m_prime) - # Step 7 - ps = bchr(0)*(emLen-sLen-mhash.digest_size-2) - # Step 8 - db = ps + bchr(1) + salt - # Step 9 - dbMask = mgf(h.digest(), emLen-mhash.digest_size-1) - # Step 10 - maskedDB = strxor(db, dbMask) - # Step 11 - maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] - # Step 12 - em = maskedDB + h.digest() + bchr(0xBC) - return em - - -def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): - """ - Implement the ``EMSA-PSS-VERIFY`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.1.2). - - ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, - and hash it internally. Here, we expect that the message has already - been hashed instead. - - :Parameters: - mhash : hash object - The hash object that holds the digest of the message to be verified. - em : string - The signature to verify, therefore proving that the sender really - signed the message that was received. - emBits : int - Length of the final encoding (em), in bits. - mgf : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - sLen : int - Length of the salt, in bytes. - - :Raise ValueError: - When the encoding is inconsistent, or the digest or salt lengths - are too big. - """ - - emLen = ceil_div(emBits, 8) - - # Bitmask of digits that fill up - lmask = 0 - for i in iter_range(8*emLen-emBits): - lmask = lmask >> 1 | 0x80 - - # Step 1 and 2 have been already done - # Step 3 - if emLen < mhash.digest_size+sLen+2: - raise ValueError("Incorrect signature") - # Step 4 - if ord(em[-1:]) != 0xBC: - raise ValueError("Incorrect signature") - # Step 5 - maskedDB = em[:emLen-mhash.digest_size-1] - h = em[emLen-mhash.digest_size-1:-1] - # Step 6 - if lmask & bord(em[0]): - raise ValueError("Incorrect signature") - # Step 7 - dbMask = mgf(h, emLen-mhash.digest_size-1) - # Step 8 - db = strxor(maskedDB, dbMask) - # Step 9 - db = bchr(bord(db[0]) & ~lmask) + db[1:] - # Step 10 - if not db.startswith(bchr(0)*(emLen-mhash.digest_size-sLen-2) + bchr(1)): - raise ValueError("Incorrect signature") - # Step 11 - if sLen > 0: - salt = db[-sLen:] - else: - salt = b"" - # Step 12 - m_prime = bchr(0)*8 + mhash.digest() + salt - # Step 13 - hobj = mhash.new() - hobj.update(m_prime) - hp = hobj.digest() - # Step 14 - if h != hp: - raise ValueError("Incorrect signature") - - -def new(rsa_key, **kwargs): - """Create an object for making or verifying PKCS#1 PSS signatures. - - :parameter rsa_key: - The RSA key to use for signing or verifying the message. - This is a :class:`Crypto.PublicKey.RSA` object. - Signing is only possible when ``rsa_key`` is a **private** RSA key. - :type rsa_key: RSA object - - :Keyword Arguments: - - * *mask_func* (``callable``) -- - A function that returns the mask (as `bytes`). - It must accept two parameters: a seed (as `bytes`) - and the length of the data to return. - - If not specified, it will be the function :func:`MGF1` defined in - `RFC8017 `_ and - combined with the same hash algorithm applied to the - message to sign or verify. - - If you want to use a different function, for instance still :func:`MGF1` - but together with another hash, you can do:: - - from Crypto.Hash import SHA256 - from Crypto.Signature.pss import MGF1 - mgf = lambda x, y: MGF1(x, y, SHA256) - - * *salt_bytes* (``integer``) -- - Length of the salt, in bytes. - It is a value between 0 and ``emLen - hLen - 2``, where ``emLen`` - is the size of the RSA modulus and ``hLen`` is the size of the digest - applied to the message to sign or verify. - - The salt is generated internally, you don't need to provide it. - - If not specified, the salt length will be ``hLen``. - If it is zero, the signature scheme becomes deterministic. - - Note that in some implementations such as OpenSSL the default - salt length is ``emLen - hLen - 2`` (even though it is not more - secure than ``hLen``). - - * *rand_func* (``callable``) -- - A function that returns random ``bytes``, of the desired length. - The default is :func:`Crypto.Random.get_random_bytes`. - - :return: a :class:`PSS_SigScheme` signature object - """ - - mask_func = kwargs.pop("mask_func", None) - salt_len = kwargs.pop("salt_bytes", None) - rand_func = kwargs.pop("rand_func", None) - if rand_func is None: - rand_func = Random.get_random_bytes - if kwargs: - raise ValueError("Unknown keywords: " + str(kwargs.keys())) - return PSS_SigScheme(rsa_key, mask_func, salt_len, rand_func) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.pyi deleted file mode 100644 index d4088e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Signature/pss.pyi +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Union, Callable, Optional -from typing_extensions import Protocol - -from Crypto.PublicKey.RSA import RsaKey - - -class Hash(Protocol): - def digest(self) -> bytes: ... - def update(self, bytes) -> None: ... - - -class HashModule(Protocol): - @staticmethod - def new(data: Optional[bytes]) -> Hash: ... - - -MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] -RndFunction = Callable[[int], bytes] - -class PSS_SigScheme: - def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> None: ... - - -MGF1 : MaskFunction -def _EMSA_PSS_ENCODE(mhash: Hash, emBits: int, randFunc: RndFunction, mgf:MaskFunction, sLen: int) -> str: ... -def _EMSA_PSS_VERIFY(mhash: Hash, em: str, emBits: int, mgf: MaskFunction, sLen: int) -> None: ... -def new(rsa_key: RsaKey, **kwargs: Union[MaskFunction, RndFunction, int]) -> PSS_SigScheme: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.py deleted file mode 100644 index e3bdcbe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Util/Counter.py : Fast counter for use with CTR-mode ciphers -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -def new(nbits, prefix=b"", suffix=b"", initial_value=1, little_endian=False, allow_wraparound=False): - """Create a stateful counter block function suitable for CTR encryption modes. - - Each call to the function returns the next counter block. - Each counter block is made up by three parts: - - +------+--------------+-------+ - |prefix| counter value|postfix| - +------+--------------+-------+ - - The counter value is incremented by 1 at each call. - - Args: - nbits (integer): - Length of the desired counter value, in bits. It must be a multiple of 8. - prefix (byte string): - The constant prefix of the counter block. By default, no prefix is - used. - suffix (byte string): - The constant postfix of the counter block. By default, no suffix is - used. - initial_value (integer): - The initial value of the counter. Default value is 1. - Its length in bits must not exceed the argument ``nbits``. - little_endian (boolean): - If ``True``, the counter number will be encoded in little endian format. - If ``False`` (default), in big endian format. - allow_wraparound (boolean): - This parameter is ignored. - An ``OverflowError`` exception is always raised when the counter wraps - around to zero. - Returns: - An object that can be passed with the :data:`counter` parameter to a CTR mode - cipher. - - It must hold that *len(prefix) + nbits//8 + len(suffix)* matches the - block size of the underlying block cipher. - """ - - if (nbits % 8) != 0: - raise ValueError("'nbits' must be a multiple of 8") - - iv_bl = initial_value.bit_length() - if iv_bl > nbits: - raise ValueError("Initial value takes %d bits but it is longer than " - "the counter (%d bits)" % - (iv_bl, nbits)) - - # Ignore wraparound - return {"counter_len": nbits // 8, - "prefix": prefix, - "suffix": suffix, - "initial_value": initial_value, - "little_endian": little_endian - } diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.pyi deleted file mode 100644 index fa2ffdd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Counter.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from typing import Optional, Union, Dict - -def new(nbits: int, prefix: Optional[bytes]=..., suffix: Optional[bytes]=..., initial_value: Optional[int]=1, - little_endian: Optional[bool]=False, allow_wraparound: Optional[bool]=False) -> \ - Dict[str, Union[int, bytes, bool]]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.py deleted file mode 100644 index d5b1cca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.py +++ /dev/null @@ -1,119 +0,0 @@ -# -# Util/Padding.py : Functions to manage padding -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = [ 'pad', 'unpad' ] - -from Crypto.Util.py3compat import * - - -def pad(data_to_pad, block_size, style='pkcs7'): - """Apply standard padding. - - Args: - data_to_pad (byte string): - The data that needs to be padded. - block_size (integer): - The block boundary to use for padding. The output length is guaranteed - to be a multiple of :data:`block_size`. - style (string): - Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. - - Return: - byte string : the original data with the appropriate padding added at the end. - """ - - padding_len = block_size - len(data_to_pad) % block_size - - if style == 'pkcs7': - padding = bchr(padding_len) * padding_len - elif style == 'x923': - padding = bchr(0)*(padding_len-1) + bchr(padding_len) - elif style == 'iso7816': - padding = bchr(128) + bchr(0) * (padding_len-1) - else: - raise ValueError("Unknown padding style") - - return data_to_pad + padding - - -def unpad(padded_data, block_size, style='pkcs7'): - """Remove standard padding. - - Args: - padded_data (byte string): - A piece of data with padding that needs to be stripped. - block_size (integer): - The block boundary to use for padding. The input length - must be a multiple of :data:`block_size`. - style (string): - Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. - Return: - byte string : data without padding. - Raises: - ValueError: if the padding is incorrect. - """ - - pdata_len = len(padded_data) - - if pdata_len == 0: - raise ValueError("Zero-length input cannot be unpadded") - - if pdata_len % block_size: - raise ValueError("Input data is not padded") - - if style in ('pkcs7', 'x923'): - padding_len = bord(padded_data[-1]) - - if padding_len < 1 or padding_len > min(block_size, pdata_len): - raise ValueError("Padding is incorrect.") - - if style == 'pkcs7': - if padded_data[-padding_len:] != bchr(padding_len)*padding_len: - raise ValueError("PKCS#7 padding is incorrect.") - else: - if padded_data[-padding_len:-1] != bchr(0)*(padding_len-1): - raise ValueError("ANSI X.923 padding is incorrect.") - - elif style == 'iso7816': - padding_len = pdata_len - padded_data.rfind(bchr(128)) - - if padding_len < 1 or padding_len > min(block_size, pdata_len): - raise ValueError("Padding is incorrect.") - - if padding_len > 1 and padded_data[1-padding_len:] != bchr(0)*(padding_len-1): - raise ValueError("ISO 7816-4 padding is incorrect.") - else: - raise ValueError("Unknown padding style") - - return padded_data[:-padding_len] - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.pyi deleted file mode 100644 index 4d8d30d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/Padding.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Optional - -__all__ = [ 'pad', 'unpad' ] - -def pad(data_to_pad: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... -def unpad(padded_data: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... \ No newline at end of file diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.py deleted file mode 100644 index 9ed52d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.py +++ /dev/null @@ -1,386 +0,0 @@ -# rfc1751.py : Converts between 128-bit strings and a human-readable -# sequence of words, as defined in RFC1751: "A Convention for -# Human-Readable 128-bit Keys", by Daniel L. McDonald. -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew M. Kuchling and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -from __future__ import print_function - -import binascii - -from Crypto.Util.py3compat import bord, bchr - -binary = {0: '0000', 1: '0001', 2: '0010', 3: '0011', 4: '0100', 5: '0101', - 6: '0110', 7: '0111', 8: '1000', 9: '1001', 10: '1010', 11: '1011', - 12: '1100', 13: '1101', 14: '1110', 15: '1111'} - - -def _key2bin(s): - "Convert a key into a string of binary digits" - kl = map(lambda x: bord(x), s) - kl = map(lambda x: binary[x >> 4] + binary[x & 15], kl) - return ''.join(kl) - - -def _extract(key, start, length): - """Extract a bitstring(2.x)/bytestring(2.x) from a string of binary digits, and return its - numeric value.""" - - result = 0 - for y in key[start:start+length]: - result = result * 2 + ord(y) - 48 - return result - - -def key_to_english(key): - """Transform an arbitrary key into a string containing English words. - - Example:: - - >>> from Crypto.Util.RFC1751 import key_to_english - >>> key_to_english(b'66666666') - 'RAM LOIS GOAD CREW CARE HIT' - - Args: - key (byte string): - The key to convert. Its length must be a multiple of 8. - Return: - A string of English words. - """ - - if len(key) % 8 != 0: - raise ValueError('The length of the key must be a multiple of 8.') - - english = '' - for index in range(0, len(key), 8): # Loop over 8-byte subkeys - subkey = key[index:index + 8] - # Compute the parity of the key - skbin = _key2bin(subkey) - p = 0 - for i in range(0, 64, 2): - p = p + _extract(skbin, i, 2) - # Append parity bits to the subkey - skbin = _key2bin(subkey + bchr((p << 6) & 255)) - for i in range(0, 64, 11): - english = english + wordlist[_extract(skbin, i, 11)] + ' ' - - return english.strip() - - -def english_to_key(s): - """Transform a string into a corresponding key. - - Example:: - - >>> from Crypto.Util.RFC1751 import english_to_key - >>> english_to_key('RAM LOIS GOAD CREW CARE HIT') - b'66666666' - - Args: - s (string): the string with the words separated by whitespace; - the number of words must be a multiple of 6. - Return: - A byte string. - """ - - L = s.upper().split() - key = b'' - for index in range(0, len(L), 6): - sublist = L[index:index + 6] - char = 9 * [0] - bits = 0 - for i in sublist: - index = wordlist.index(i) - shift = (8 - (bits + 11) % 8) % 8 - y = index << shift - cl, cc, cr = (y >> 16), (y >> 8) & 0xff, y & 0xff - if (shift > 5): - char[bits >> 3] = char[bits >> 3] | cl - char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cc - char[(bits >> 3) + 2] = char[(bits >> 3) + 2] | cr - elif shift > -3: - char[bits >> 3] = char[bits >> 3] | cc - char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cr - else: - char[bits >> 3] = char[bits >> 3] | cr - bits = bits + 11 - - subkey = b'' - for y in char: - subkey = subkey + bchr(y) - - # Check the parity of the resulting key - skbin = _key2bin(subkey) - p = 0 - for i in range(0, 64, 2): - p = p + _extract(skbin, i, 2) - if (p & 3) != _extract(skbin, 64, 2): - raise ValueError("Parity error in resulting key") - key = key + subkey[0:8] - return key - - -wordlist = [ - "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", - "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA", - "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", - "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE", - "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", - "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET", - "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO", - "BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", - "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", - "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY", - "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", - "DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG", - "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", - "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO", - "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE", - "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW", - "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", - "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", - "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO", - "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD", - "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", - "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT", - "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE", - "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL", - "INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", - "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", - "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", - "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", - "LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", - "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", - "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", - "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", - "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", - "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", - "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", - "NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", - "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", - "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", - "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", - "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", - "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", - "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", - "PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", - "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", - "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", - "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", - "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", - "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", - "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", - "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", - "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", - "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", - "TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", - "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", - "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", - "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", - "WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", - "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", - "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", - "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", - "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", - "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", - "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", - "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA", - "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM", - "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW", - "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", - "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", - "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", - "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", - "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", - "BEAU", "BECK", "BEEF", "BEEN", "BEER", - "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", - "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", - "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", - "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", - "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", - "BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", - "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", - "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", - "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", - "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", - "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", - "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", - "BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", - "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", - "CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", - "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", - "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", - "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", - "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", - "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", - "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", - "COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST", - "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", - "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", - "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", - "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", - "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", - "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", - "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", - "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT", - "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", - "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", - "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", - "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", - "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", - "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", - "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", - "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", - "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", - "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", - "FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", - "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", - "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", - "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", - "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", - "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", - "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", - "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", - "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", - "FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", - "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", - "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", - "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", - "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", - "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", - "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", - "GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", - "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", - "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", - "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", - "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", - "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK", - "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE", - "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", - "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", - "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", - "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", - "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", - "HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", - "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", - "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", - "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", - "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", - "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", - "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", - "JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", - "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", - "JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", - "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", - "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", - "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", - "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", - "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", - "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", - "LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", - "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", - "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", - "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST", - "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", - "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", - "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", - "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", - "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", - "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", - "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", - "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", - "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", - "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", - "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", - "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", - "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", - "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", - "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", - "MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", - "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", - "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", - "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", - "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", - "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", - "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", - "NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", - "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", - "NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", - "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", - "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", - "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", - "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", - "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", - "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", - "RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", - "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA", - "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", - "RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD", - "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", - "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", - "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", - "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", - "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", - "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", - "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", - "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", - "SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS", - "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", - "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", - "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", - "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", - "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", - "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", - "SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", - "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", - "SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", - "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", - "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", - "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", - "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", - "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", - "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", - "TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", - "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN", - "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", - "TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY", - "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", - "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", - "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", - "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", - "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", - "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", - "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", - "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", - "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", - "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", - "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", - "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", - "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", - "WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", - "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", - "WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE", - "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", - "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", - "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", - "YELL", "YOGA", "YOKE" ] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.pyi deleted file mode 100644 index 6ad07ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/RFC1751.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Dict, List - -binary: Dict[int, str] -wordlist: List[str] - -def key_to_english(key: bytes) -> str: ... -def english_to_key(s: str) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/__init__.py deleted file mode 100644 index f12214d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Miscellaneous modules - -Contains useful modules that don't belong into any of the -other Crypto.* subpackages. - -======================== ============================================= -Module Description -======================== ============================================= -`Crypto.Util.number` Number-theoretic functions (primality testing, etc.) -`Crypto.Util.Counter` Fast counter functions for CTR cipher modes. -`Crypto.Util.RFC1751` Converts between 128-bit keys and human-readable - strings of words. -`Crypto.Util.asn1` Minimal support for ASN.1 DER encoding -`Crypto.Util.Padding` Set of functions for adding and removing padding. -======================== ============================================= - -:undocumented: _galois, _number_new, cpuid, py3compat, _raw_api -""" - -__all__ = ['RFC1751', 'number', 'strxor', 'asn1', 'Counter', 'Padding'] - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.py deleted file mode 100644 index b3039b5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.py +++ /dev/null @@ -1,46 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util._raw_api import load_pycryptodome_raw_lib - - -_raw_cpuid_lib = load_pycryptodome_raw_lib("Crypto.Util._cpuid_c", - """ - int have_aes_ni(void); - int have_clmul(void); - """) - - -def have_aes_ni(): - return _raw_cpuid_lib.have_aes_ni() - - -def have_clmul(): - return _raw_cpuid_lib.have_clmul() diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.pyi deleted file mode 100644 index 10e669e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpu_features.pyi +++ /dev/null @@ -1,2 +0,0 @@ -def have_aes_ni() -> int: ... -def have_clmul() -> int: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpuid_c.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpuid_c.abi3.so deleted file mode 100755 index 9e41d3c..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_cpuid_c.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.py deleted file mode 100644 index 1cb0c4b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.py +++ /dev/null @@ -1,54 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os - - -def pycryptodome_filename(dir_comps, filename): - """Return the complete file name for the module - - dir_comps : list of string - The list of directory names in the PyCryptodome package. - The first element must be "Crypto". - - filename : string - The filename (inclusing extension) in the target directory. - """ - - if dir_comps[0] != "Crypto": - raise ValueError("Only available for modules under 'Crypto'") - - dir_comps = list(dir_comps[1:]) + [filename] - - util_lib, _ = os.path.split(os.path.abspath(__file__)) - root_lib = os.path.join(util_lib, "..") - - return os.path.join(root_lib, *dir_comps) - diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.pyi deleted file mode 100644 index d54a126..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_file_system.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List - - -def pycryptodome_filename(dir_comps: List[str], filename: str) -> str: ... \ No newline at end of file diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.py deleted file mode 100644 index e0065c3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.py +++ /dev/null @@ -1,325 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import abc -import sys -from Crypto.Util.py3compat import byte_string -from Crypto.Util._file_system import pycryptodome_filename - -# -# List of file suffixes for Python extensions -# -if sys.version_info[0] < 3: - - import imp - extension_suffixes = [] - for ext, mod, typ in imp.get_suffixes(): - if typ == imp.C_EXTENSION: - extension_suffixes.append(ext) - -else: - - from importlib import machinery - extension_suffixes = machinery.EXTENSION_SUFFIXES - -# Which types with buffer interface we support (apart from byte strings) -_buffer_type = (bytearray, memoryview) - - -class _VoidPointer(object): - @abc.abstractmethod - def get(self): - """Return the memory location we point to""" - return - - @abc.abstractmethod - def address_of(self): - """Return a raw pointer to this pointer""" - return - - -try: - # Starting from v2.18, pycparser (used by cffi for in-line ABI mode) - # stops working correctly when PYOPTIMIZE==2 or the parameter -OO is - # passed. In that case, we fall back to ctypes. - # Note that PyPy ships with an old version of pycparser so we can keep - # using cffi there. - # See https://github.com/Legrandin/pycryptodome/issues/228 - if '__pypy__' not in sys.builtin_module_names and sys.flags.optimize == 2: - raise ImportError("CFFI with optimize=2 fails due to pycparser bug.") - - # cffi still uses PyUnicode_GetSize, which was removed in Python 3.12 - # thus leading to a crash on cffi.dlopen() - # See https://groups.google.com/u/1/g/python-cffi/c/oZkOIZ_zi5k - if sys.version_info >= (3, 12) and os.name == "nt": - raise ImportError("CFFI is not compatible with Python 3.12 on Windows") - - from cffi import FFI - - ffi = FFI() - null_pointer = ffi.NULL - uint8_t_type = ffi.typeof(ffi.new("const uint8_t*")) - - _Array = ffi.new("uint8_t[1]").__class__.__bases__ - - def load_lib(name, cdecl): - """Load a shared library and return a handle to it. - - @name, either an absolute path or the name of a library - in the system search path. - - @cdecl, the C function declarations. - """ - - if hasattr(ffi, "RTLD_DEEPBIND") and not os.getenv('PYCRYPTODOME_DISABLE_DEEPBIND'): - lib = ffi.dlopen(name, ffi.RTLD_DEEPBIND) - else: - lib = ffi.dlopen(name) - ffi.cdef(cdecl) - return lib - - def c_ulong(x): - """Convert a Python integer to unsigned long""" - return x - - c_ulonglong = c_ulong - c_uint = c_ulong - c_ubyte = c_ulong - - def c_size_t(x): - """Convert a Python integer to size_t""" - return x - - def create_string_buffer(init_or_size, size=None): - """Allocate the given amount of bytes (initially set to 0)""" - - if isinstance(init_or_size, bytes): - size = max(len(init_or_size) + 1, size) - result = ffi.new("uint8_t[]", size) - result[:] = init_or_size - else: - if size: - raise ValueError("Size must be specified once only") - result = ffi.new("uint8_t[]", init_or_size) - return result - - def get_c_string(c_string): - """Convert a C string into a Python byte sequence""" - return ffi.string(c_string) - - def get_raw_buffer(buf): - """Convert a C buffer into a Python byte sequence""" - return ffi.buffer(buf)[:] - - def c_uint8_ptr(data): - if isinstance(data, _buffer_type): - # This only works for cffi >= 1.7 - return ffi.cast(uint8_t_type, ffi.from_buffer(data)) - elif byte_string(data) or isinstance(data, _Array): - return data - else: - raise TypeError("Object type %s cannot be passed to C code" % type(data)) - - class VoidPointer_cffi(_VoidPointer): - """Model a newly allocated pointer to void""" - - def __init__(self): - self._pp = ffi.new("void *[1]") - - def get(self): - return self._pp[0] - - def address_of(self): - return self._pp - - def VoidPointer(): - return VoidPointer_cffi() - - backend = "cffi" - -except ImportError: - - import ctypes - from ctypes import (CDLL, c_void_p, byref, c_ulong, c_ulonglong, c_size_t, - create_string_buffer, c_ubyte, c_uint) - from ctypes.util import find_library - from ctypes import Array as _Array - - null_pointer = None - cached_architecture = [] - - def c_ubyte(c): - if not (0 <= c < 256): - raise OverflowError() - return ctypes.c_ubyte(c) - - def load_lib(name, cdecl): - if not cached_architecture: - # platform.architecture() creates a subprocess, so caching the - # result makes successive imports faster. - import platform - cached_architecture[:] = platform.architecture() - bits, linkage = cached_architecture - if "." not in name and not linkage.startswith("Win"): - full_name = find_library(name) - if full_name is None: - raise OSError("Cannot load library '%s'" % name) - name = full_name - return CDLL(name) - - def get_c_string(c_string): - return c_string.value - - def get_raw_buffer(buf): - return buf.raw - - # ---- Get raw pointer --- - - _c_ssize_t = ctypes.c_ssize_t - - _PyBUF_SIMPLE = 0 - _PyObject_GetBuffer = ctypes.pythonapi.PyObject_GetBuffer - _PyBuffer_Release = ctypes.pythonapi.PyBuffer_Release - _py_object = ctypes.py_object - _c_ssize_p = ctypes.POINTER(_c_ssize_t) - - # See Include/object.h for CPython - # and https://github.com/pallets/click/blob/master/src/click/_winconsole.py - class _Py_buffer(ctypes.Structure): - _fields_ = [ - ('buf', c_void_p), - ('obj', ctypes.py_object), - ('len', _c_ssize_t), - ('itemsize', _c_ssize_t), - ('readonly', ctypes.c_int), - ('ndim', ctypes.c_int), - ('format', ctypes.c_char_p), - ('shape', _c_ssize_p), - ('strides', _c_ssize_p), - ('suboffsets', _c_ssize_p), - ('internal', c_void_p) - ] - - # Extra field for CPython 2.6/2.7 - if sys.version_info[0] == 2: - _fields_.insert(-1, ('smalltable', _c_ssize_t * 2)) - - def c_uint8_ptr(data): - if byte_string(data) or isinstance(data, _Array): - return data - elif isinstance(data, _buffer_type): - obj = _py_object(data) - buf = _Py_buffer() - _PyObject_GetBuffer(obj, byref(buf), _PyBUF_SIMPLE) - try: - buffer_type = ctypes.c_ubyte * buf.len - return buffer_type.from_address(buf.buf) - finally: - _PyBuffer_Release(byref(buf)) - else: - raise TypeError("Object type %s cannot be passed to C code" % type(data)) - - # --- - - class VoidPointer_ctypes(_VoidPointer): - """Model a newly allocated pointer to void""" - - def __init__(self): - self._p = c_void_p() - - def get(self): - return self._p - - def address_of(self): - return byref(self._p) - - def VoidPointer(): - return VoidPointer_ctypes() - - backend = "ctypes" - - -class SmartPointer(object): - """Class to hold a non-managed piece of memory""" - - def __init__(self, raw_pointer, destructor): - self._raw_pointer = raw_pointer - self._destructor = destructor - - def get(self): - return self._raw_pointer - - def release(self): - rp, self._raw_pointer = self._raw_pointer, None - return rp - - def __del__(self): - try: - if self._raw_pointer is not None: - self._destructor(self._raw_pointer) - self._raw_pointer = None - except AttributeError: - pass - - -def load_pycryptodome_raw_lib(name, cdecl): - """Load a shared library and return a handle to it. - - @name, the name of the library expressed as a PyCryptodome module, - for instance Crypto.Cipher._raw_cbc. - - @cdecl, the C function declarations. - """ - - split = name.split(".") - dir_comps, basename = split[:-1], split[-1] - attempts = [] - for ext in extension_suffixes: - try: - filename = basename + ext - full_name = pycryptodome_filename(dir_comps, filename) - if not os.path.isfile(full_name): - attempts.append("Not found '%s'" % filename) - continue - return load_lib(full_name, cdecl) - except OSError as exp: - attempts.append("Cannot load '%s': %s" % (filename, str(exp))) - raise OSError("Cannot load native module '%s': %s" % (name, ", ".join(attempts))) - - -def is_buffer(x): - """Return True if object x supports the buffer interface""" - return isinstance(x, (bytes, bytearray, memoryview)) - - -def is_writeable_buffer(x): - return (isinstance(x, bytearray) or - (isinstance(x, memoryview) and not x.readonly)) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.pyi deleted file mode 100644 index 2bc5301..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_raw_api.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Optional, Union - -def load_lib(name: str, cdecl: str) -> Any : ... -def c_ulong(x: int ) -> Any : ... -def c_ulonglong(x: int ) -> Any : ... -def c_size_t(x: int) -> Any : ... -def create_string_buffer(init_or_size: Union[bytes,int], size: Optional[int]) -> Any : ... -def get_c_string(c_string: Any) -> bytes : ... -def get_raw_buffer(buf: Any) -> bytes : ... -def c_uint8_ptr(data: Union[bytes, memoryview, bytearray]) -> Any : ... - -class VoidPointer(object): - def get(self) -> Any : ... - def address_of(self) -> Any : ... - -class SmartPointer(object): - def __init__(self, raw_pointer: Any, destructor: Any) -> None : ... - def get(self) -> Any : ... - def release(self) -> Any : ... - -backend : str -null_pointer : Any -ffi: Any - -def load_pycryptodome_raw_lib(name: str, cdecl: str) -> Any : ... -def is_buffer(x: Any) -> bool : ... -def is_writeable_buffer(x: Any) -> bool : ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_strxor.abi3.so b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_strxor.abi3.so deleted file mode 100755 index 85b5496..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/_strxor.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.py deleted file mode 100644 index 887cf1a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.py +++ /dev/null @@ -1,1064 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Util/asn1.py : Minimal support for ASN.1 DER binary encoding. -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -import struct - -from Crypto.Util.py3compat import byte_string, bchr, bord - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -__all__ = ['DerObject', 'DerInteger', 'DerBoolean', 'DerOctetString', - 'DerNull', 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] - -# Useful references: -# - https://luca.ntop.org/Teaching/Appunti/asn1.html -# - https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ -# - https://www.zytrax.com/tech/survival/asn1.html -# - https://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf -# - https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf -# - https://misc.daniel-marschall.de/asn.1/oid-converter/online.php - -def _is_number(x, only_non_negative=False): - test = 0 - try: - test = x + test - except TypeError: - return False - return not only_non_negative or x >= 0 - - -class BytesIO_EOF(object): - """This class differs from BytesIO in that a ValueError exception is - raised whenever EOF is reached.""" - - def __init__(self, initial_bytes): - self._buffer = initial_bytes - self._index = 0 - self._bookmark = None - - def set_bookmark(self): - self._bookmark = self._index - - def data_since_bookmark(self): - assert self._bookmark is not None - return self._buffer[self._bookmark:self._index] - - def remaining_data(self): - return len(self._buffer) - self._index - - def read(self, length): - new_index = self._index + length - if new_index > len(self._buffer): - raise ValueError("Not enough data for DER decoding: expected %d bytes and found %d" % (new_index, len(self._buffer))) - - result = self._buffer[self._index:new_index] - self._index = new_index - return result - - def read_byte(self): - return bord(self.read(1)[0]) - - -class DerObject(object): - """Base class for defining a single DER object. - - This class should never be directly instantiated. - """ - - def __init__(self, asn1Id=None, payload=b'', implicit=None, - constructed=False, explicit=None): - """Initialize the DER object according to a specific ASN.1 type. - - :Parameters: - asn1Id : integer or byte - The universal DER tag number for this object - (e.g. 0x10 for a SEQUENCE). - If None, the tag is not known yet. - - payload : byte string - The initial payload of the object (that it, - the content octets). - If not specified, the payload is empty. - - implicit : integer or byte - The IMPLICIT tag number (< 0x1F) to use for the encoded object. - It overrides the universal tag *asn1Id*. - It cannot be combined with the ``explicit`` parameter. - By default, there is no IMPLICIT tag. - - constructed : bool - True when the ASN.1 type is *constructed*. - False when it is *primitive* (default). - - explicit : integer or byte - The EXPLICIT tag number (< 0x1F) to use for the encoded object. - It cannot be combined with the ``implicit`` parameter. - By default, there is no EXPLICIT tag. - """ - - if asn1Id is None: - # The tag octet will be read in with ``decode`` - self._tag_octet = None - return - asn1Id = self._convertTag(asn1Id) - - self.payload = payload - - # In a BER/DER identifier octet: - # * bits 4-0 contain the tag value - # * bit 5 is set if the type is 'constructed' - # and unset if 'primitive' - # * bits 7-6 depend on the encoding class - # - # Class | Bit 7, Bit 6 - # ---------------------------------- - # universal | 0 0 - # application | 0 1 - # context-spec | 1 0 (default for IMPLICIT/EXPLICIT) - # private | 1 1 - # - - constructed_bit = 0x20 if constructed else 0x00 - - if None not in (explicit, implicit): - raise ValueError("Explicit and implicit tags are" - " mutually exclusive") - - if implicit is not None: - # IMPLICIT tag overrides asn1Id - self._tag_octet = 0x80 | constructed_bit | self._convertTag(implicit) - elif explicit is not None: - # 'constructed bit' is always asserted for an EXPLICIT tag - self._tag_octet = 0x80 | 0x20 | self._convertTag(explicit) - self._inner_tag_octet = constructed_bit | asn1Id - else: - # Neither IMPLICIT nor EXPLICIT - self._tag_octet = constructed_bit | asn1Id - - def _convertTag(self, tag): - """Check if *tag* is a real DER tag (5 bits). - Convert it from a character to number if necessary. - """ - if not _is_number(tag): - if len(tag) == 1: - tag = bord(tag[0]) - # Ensure that tag is a low tag - if not (_is_number(tag) and 0 <= tag < 0x1F): - raise ValueError("Wrong DER tag") - return tag - - @staticmethod - def _definite_form(length): - """Build length octets according to BER/DER - definite form. - """ - if length > 127: - encoding = long_to_bytes(length) - return bchr(len(encoding) + 128) + encoding - return bchr(length) - - def encode(self): - """Return this DER element, fully encoded as a binary byte string.""" - - # Concatenate identifier octets, length octets, - # and contents octets - - output_payload = self.payload - - # In case of an EXTERNAL tag, first encode the inner - # element. - if hasattr(self, "_inner_tag_octet"): - output_payload = (bchr(self._inner_tag_octet) + - self._definite_form(len(self.payload)) + - self.payload) - - return (bchr(self._tag_octet) + - self._definite_form(len(output_payload)) + - output_payload) - - def _decodeLen(self, s): - """Decode DER length octets from a file.""" - - length = s.read_byte() - - if length > 127: - encoded_length = s.read(length & 0x7F) - if bord(encoded_length[0]) == 0: - raise ValueError("Invalid DER: length has leading zero") - length = bytes_to_long(encoded_length) - if length <= 127: - raise ValueError("Invalid DER: length in long form but smaller than 128") - - return length - - def decode(self, der_encoded, strict=False): - """Decode a complete DER element, and re-initializes this - object with it. - - Args: - der_encoded (byte string): A complete DER element. - - Raises: - ValueError: in case of parsing errors. - """ - - if not byte_string(der_encoded): - raise ValueError("Input is not a byte string") - - s = BytesIO_EOF(der_encoded) - self._decodeFromStream(s, strict) - - # There shouldn't be other bytes left - if s.remaining_data() > 0: - raise ValueError("Unexpected extra data after the DER structure") - - return self - - def _decodeFromStream(self, s, strict): - """Decode a complete DER element from a file.""" - - idOctet = s.read_byte() - if self._tag_octet is not None: - if idOctet != self._tag_octet: - raise ValueError("Unexpected DER tag") - else: - self._tag_octet = idOctet - length = self._decodeLen(s) - self.payload = s.read(length) - - # In case of an EXTERNAL tag, further decode the inner - # element. - if hasattr(self, "_inner_tag_octet"): - p = BytesIO_EOF(self.payload) - inner_octet = p.read_byte() - if inner_octet != self._inner_tag_octet: - raise ValueError("Unexpected internal DER tag") - length = self._decodeLen(p) - self.payload = p.read(length) - - # There shouldn't be other bytes left - if p.remaining_data() > 0: - raise ValueError("Unexpected extra data after the DER structure") - - -class DerInteger(DerObject): - """Class to model a DER INTEGER. - - An example of encoding is:: - - >>> from Crypto.Util.asn1 import DerInteger - >>> from binascii import hexlify, unhexlify - >>> int_der = DerInteger(9) - >>> print hexlify(int_der.encode()) - - which will show ``020109``, the DER encoding of 9. - - And for decoding:: - - >>> s = unhexlify(b'020109') - >>> try: - >>> int_der = DerInteger() - >>> int_der.decode(s) - >>> print int_der.value - >>> except ValueError: - >>> print "Not a valid DER INTEGER" - - the output will be ``9``. - - :ivar value: The integer value - :vartype value: integer - """ - - def __init__(self, value=0, implicit=None, explicit=None): - """Initialize the DER object as an INTEGER. - - :Parameters: - value : integer - The value of the integer. - - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for INTEGER (2). - """ - - DerObject.__init__(self, 0x02, b'', implicit, - False, explicit) - self.value = value # The integer value - - def encode(self): - """Return the DER INTEGER, fully encoded as a - binary string.""" - - number = self.value - self.payload = b'' - while True: - self.payload = bchr(int(number & 255)) + self.payload - if 128 <= number <= 255: - self.payload = bchr(0x00) + self.payload - if -128 <= number <= 255: - break - number >>= 8 - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a DER-encoded INTEGER, and re-initializes this - object with it. - - Args: - der_encoded (byte string): A complete INTEGER DER element. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict=strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER INTEGER from a file.""" - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - if strict: - if len(self.payload) == 0: - raise ValueError("Invalid encoding for DER INTEGER: empty payload") - if len(self.payload) >= 2 and struct.unpack('>H', self.payload[:2])[0] < 0x80: - raise ValueError("Invalid encoding for DER INTEGER: leading zero") - - # Derive self.value from self.payload - self.value = 0 - bits = 1 - for i in self.payload: - self.value *= 256 - self.value += bord(i) - bits <<= 8 - if self.payload and bord(self.payload[0]) & 0x80: - self.value -= bits - - -class DerBoolean(DerObject): - """Class to model a DER-encoded BOOLEAN. - - An example of encoding is:: - - >>> from Crypto.Util.asn1 import DerBoolean - >>> bool_der = DerBoolean(True) - >>> print(bool_der.encode().hex()) - - which will show ``0101ff``, the DER encoding of True. - - And for decoding:: - - >>> s = bytes.fromhex('0101ff') - >>> try: - >>> bool_der = DerBoolean() - >>> bool_der.decode(s) - >>> print(bool_der.value) - >>> except ValueError: - >>> print "Not a valid DER BOOLEAN" - - the output will be ``True``. - - :ivar value: The boolean value - :vartype value: boolean - """ - def __init__(self, value=False, implicit=None, explicit=None): - """Initialize the DER object as a BOOLEAN. - - Args: - value (boolean): - The value of the boolean. Default is False. - - implicit (integer or byte): - The IMPLICIT tag number (< 0x1F) to use for the encoded object. - It overrides the universal tag for BOOLEAN (1). - It cannot be combined with the ``explicit`` parameter. - By default, there is no IMPLICIT tag. - - explicit (integer or byte): - The EXPLICIT tag number (< 0x1F) to use for the encoded object. - It cannot be combined with the ``implicit`` parameter. - By default, there is no EXPLICIT tag. - """ - - DerObject.__init__(self, 0x01, b'', implicit, False, explicit) - self.value = value # The boolean value - - def encode(self): - """Return the DER BOOLEAN, fully encoded as a binary string.""" - - self.payload = b'\xFF' if self.value else b'\x00' - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a DER-encoded BOOLEAN, and re-initializes this object with it. - - Args: - der_encoded (byte string): A DER-encoded BOOLEAN. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a DER-encoded BOOLEAN from a file.""" - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - if len(self.payload) != 1: - raise ValueError("Invalid encoding for DER BOOLEAN: payload is not 1 byte") - - if bord(self.payload[0]) == 0: - self.value = False - elif bord(self.payload[0]) == 0xFF: - self.value = True - else: - raise ValueError("Invalid payload for DER BOOLEAN") - - -class DerSequence(DerObject): - """Class to model a DER SEQUENCE. - - This object behaves like a dynamic Python sequence. - - Sub-elements that are INTEGERs behave like Python integers. - - Any other sub-element is a binary string encoded as a complete DER - sub-element (TLV). - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerSequence, DerInteger - >>> from binascii import hexlify, unhexlify - >>> obj_der = unhexlify('070102') - >>> seq_der = DerSequence([4]) - >>> seq_der.append(9) - >>> seq_der.append(obj_der.encode()) - >>> print hexlify(seq_der.encode()) - - which will show ``3009020104020109070102``, the DER encoding of the - sequence containing ``4``, ``9``, and the object with payload ``02``. - - For decoding: - - >>> s = unhexlify(b'3009020104020109070102') - >>> try: - >>> seq_der = DerSequence() - >>> seq_der.decode(s) - >>> print len(seq_der) - >>> print seq_der[0] - >>> print seq_der[:] - >>> except ValueError: - >>> print "Not a valid DER SEQUENCE" - - the output will be:: - - 3 - 4 - [4, 9, b'\x07\x01\x02'] - - """ - - def __init__(self, startSeq=None, implicit=None, explicit=None): - """Initialize the DER object as a SEQUENCE. - - :Parameters: - startSeq : Python sequence - A sequence whose element are either integers or - other DER objects. - - implicit : integer or byte - The IMPLICIT tag number (< 0x1F) to use for the encoded object. - It overrides the universal tag for SEQUENCE (16). - It cannot be combined with the ``explicit`` parameter. - By default, there is no IMPLICIT tag. - - explicit : integer or byte - The EXPLICIT tag number (< 0x1F) to use for the encoded object. - It cannot be combined with the ``implicit`` parameter. - By default, there is no EXPLICIT tag. - """ - - DerObject.__init__(self, 0x10, b'', implicit, True, explicit) - if startSeq is None: - self._seq = [] - else: - self._seq = startSeq - - # A few methods to make it behave like a python sequence - - def __delitem__(self, n): - del self._seq[n] - - def __getitem__(self, n): - return self._seq[n] - - def __setitem__(self, key, value): - self._seq[key] = value - - def __setslice__(self, i, j, sequence): - self._seq[i:j] = sequence - - def __delslice__(self, i, j): - del self._seq[i:j] - - def __getslice__(self, i, j): - return self._seq[max(0, i):max(0, j)] - - def __len__(self): - return len(self._seq) - - def __iadd__(self, item): - self._seq.append(item) - return self - - def append(self, item): - self._seq.append(item) - return self - - def insert(self, index, item): - self._seq.insert(index, item) - return self - - def hasInts(self, only_non_negative=True): - """Return the number of items in this sequence that are - integers. - - Args: - only_non_negative (boolean): - If ``True``, negative integers are not counted in. - """ - - items = [x for x in self._seq if _is_number(x, only_non_negative)] - return len(items) - - def hasOnlyInts(self, only_non_negative=True): - """Return ``True`` if all items in this sequence are integers - or non-negative integers. - - This function returns False is the sequence is empty, - or at least one member is not an integer. - - Args: - only_non_negative (boolean): - If ``True``, the presence of negative integers - causes the method to return ``False``.""" - return self._seq and self.hasInts(only_non_negative) == len(self._seq) - - def encode(self): - """Return this DER SEQUENCE, fully encoded as a - binary string. - - Raises: - ValueError: if some elements in the sequence are neither integers - nor byte strings. - """ - self.payload = b'' - for item in self._seq: - if byte_string(item): - self.payload += item - elif _is_number(item): - self.payload += DerInteger(item).encode() - else: - self.payload += item.encode() - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False, nr_elements=None, only_ints_expected=False): - """Decode a complete DER SEQUENCE, and re-initializes this - object with it. - - Args: - der_encoded (byte string): - A complete SEQUENCE DER element. - nr_elements (None or integer or list of integers): - The number of members the SEQUENCE can have - only_ints_expected (boolean): - Whether the SEQUENCE is expected to contain only integers. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - - DER INTEGERs are decoded into Python integers. Any other DER - element is not decoded. Its validity is not checked. - """ - - self._nr_elements = nr_elements - result = DerObject.decode(self, der_encoded, strict=strict) - - if only_ints_expected and not self.hasOnlyInts(): - raise ValueError("Some members are not INTEGERs") - - return result - - def _decodeFromStream(self, s, strict): - """Decode a complete DER SEQUENCE from a file.""" - - self._seq = [] - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - # Add one item at a time to self.seq, by scanning self.payload - p = BytesIO_EOF(self.payload) - while p.remaining_data() > 0: - p.set_bookmark() - - der = DerObject() - der._decodeFromStream(p, strict) - - # Parse INTEGERs differently - if der._tag_octet != 0x02: - self._seq.append(p.data_since_bookmark()) - else: - derInt = DerInteger() - data = p.data_since_bookmark() - derInt.decode(data, strict=strict) - self._seq.append(derInt.value) - - ok = True - if self._nr_elements is not None: - try: - ok = len(self._seq) in self._nr_elements - except TypeError: - ok = len(self._seq) == self._nr_elements - - if not ok: - raise ValueError("Unexpected number of members (%d)" - " in the sequence" % len(self._seq)) - - -class DerOctetString(DerObject): - """Class to model a DER OCTET STRING. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerOctetString - >>> from binascii import hexlify, unhexlify - >>> os_der = DerOctetString(b'\\xaa') - >>> os_der.payload += b'\\xbb' - >>> print hexlify(os_der.encode()) - - which will show ``0402aabb``, the DER encoding for the byte string - ``b'\\xAA\\xBB'``. - - For decoding: - - >>> s = unhexlify(b'0402aabb') - >>> try: - >>> os_der = DerOctetString() - >>> os_der.decode(s) - >>> print hexlify(os_der.payload) - >>> except ValueError: - >>> print "Not a valid DER OCTET STRING" - - the output will be ``aabb``. - - :ivar payload: The content of the string - :vartype payload: byte string - """ - - def __init__(self, value=b'', implicit=None): - """Initialize the DER object as an OCTET STRING. - - :Parameters: - value : byte string - The initial payload of the object. - If not specified, the payload is empty. - - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OCTET STRING (4). - """ - DerObject.__init__(self, 0x04, value, implicit, False) - - -class DerNull(DerObject): - """Class to model a DER NULL element.""" - - def __init__(self): - """Initialize the DER object as a NULL.""" - - DerObject.__init__(self, 0x05, b'', None, False) - - -class DerObjectId(DerObject): - """Class to model a DER OBJECT ID. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerObjectId - >>> from binascii import hexlify, unhexlify - >>> oid_der = DerObjectId("1.2") - >>> oid_der.value += ".840.113549.1.1.1" - >>> print hexlify(oid_der.encode()) - - which will show ``06092a864886f70d010101``, the DER encoding for the - RSA Object Identifier ``1.2.840.113549.1.1.1``. - - For decoding: - - >>> s = unhexlify(b'06092a864886f70d010101') - >>> try: - >>> oid_der = DerObjectId() - >>> oid_der.decode(s) - >>> print oid_der.value - >>> except ValueError: - >>> print "Not a valid DER OBJECT ID" - - the output will be ``1.2.840.113549.1.1.1``. - - :ivar value: The Object ID (OID), a dot separated list of integers - :vartype value: string - """ - - def __init__(self, value='', implicit=None, explicit=None): - """Initialize the DER object as an OBJECT ID. - - :Parameters: - value : string - The initial Object Identifier (e.g. "1.2.0.0.6.2"). - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OBJECT ID (6). - explicit : integer - The EXPLICIT tag to use for the encoded object. - """ - DerObject.__init__(self, 0x06, b'', implicit, False, explicit) - self.value = value - - def encode(self): - """Return the DER OBJECT ID, fully encoded as a - binary string.""" - - comps = [int(x) for x in self.value.split(".")] - - if len(comps) < 2: - raise ValueError("Not a valid Object Identifier string") - if comps[0] > 2: - raise ValueError("First component must be 0, 1 or 2") - if comps[0] < 2 and comps[1] > 39: - raise ValueError("Second component must be 39 at most") - - subcomps = [40 * comps[0] + comps[1]] + comps[2:] - - encoding = [] - for v in reversed(subcomps): - encoding.append(v & 0x7F) - v >>= 7 - while v: - encoding.append((v & 0x7F) | 0x80) - v >>= 7 - - self.payload = b''.join([bchr(x) for x in reversed(encoding)]) - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a complete DER OBJECT ID, and re-initializes this - object with it. - - Args: - der_encoded (byte string): - A complete DER OBJECT ID. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER OBJECT ID from a file.""" - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - # Derive self.value from self.payload - p = BytesIO_EOF(self.payload) - - subcomps = [] - v = 0 - while p.remaining_data(): - c = p.read_byte() - v = (v << 7) + (c & 0x7F) - if not (c & 0x80): - subcomps.append(v) - v = 0 - - if len(subcomps) == 0: - raise ValueError("Empty payload") - - if subcomps[0] < 40: - subcomps[:1] = [0, subcomps[0]] - elif subcomps[0] < 80: - subcomps[:1] = [1, subcomps[0] - 40] - else: - subcomps[:1] = [2, subcomps[0] - 80] - - self.value = ".".join([str(x) for x in subcomps]) - - -class DerBitString(DerObject): - """Class to model a DER BIT STRING. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerBitString - >>> bs_der = DerBitString(b'\\xAA') - >>> bs_der.value += b'\\xBB' - >>> print(bs_der.encode().hex()) - - which will show ``030300aabb``, the DER encoding for the bit string - ``b'\\xAA\\xBB'``. - - For decoding: - - >>> s = bytes.fromhex('030300aabb') - >>> try: - >>> bs_der = DerBitString() - >>> bs_der.decode(s) - >>> print(bs_der.value.hex()) - >>> except ValueError: - >>> print "Not a valid DER BIT STRING" - - the output will be ``aabb``. - - :ivar value: The content of the string - :vartype value: byte string - """ - - def __init__(self, value=b'', implicit=None, explicit=None): - """Initialize the DER object as a BIT STRING. - - :Parameters: - value : byte string or DER object - The initial, packed bit string. - If not specified, the bit string is empty. - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for BIT STRING (3). - explicit : integer - The EXPLICIT tag to use for the encoded object. - """ - DerObject.__init__(self, 0x03, b'', implicit, False, explicit) - - # The bitstring value (packed) - if isinstance(value, DerObject): - self.value = value.encode() - else: - self.value = value - - def encode(self): - """Return the DER BIT STRING, fully encoded as a - byte string.""" - - # Add padding count byte - self.payload = b'\x00' + self.value - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a complete DER BIT STRING, and re-initializes this - object with it. - - Args: - der_encoded (byte string): a complete DER BIT STRING. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER BIT STRING DER from a file.""" - - # Fill-up self.payload - DerObject._decodeFromStream(self, s, strict) - - if self.payload and bord(self.payload[0]) != 0: - raise ValueError("Not a valid BIT STRING") - - # Fill-up self.value - self.value = b'' - # Remove padding count byte - if self.payload: - self.value = self.payload[1:] - - -class DerSetOf(DerObject): - """Class to model a DER SET OF. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerBitString - >>> from binascii import hexlify, unhexlify - >>> so_der = DerSetOf([4,5]) - >>> so_der.add(6) - >>> print hexlify(so_der.encode()) - - which will show ``3109020104020105020106``, the DER encoding - of a SET OF with items 4,5, and 6. - - For decoding: - - >>> s = unhexlify(b'3109020104020105020106') - >>> try: - >>> so_der = DerSetOf() - >>> so_der.decode(s) - >>> print [x for x in so_der] - >>> except ValueError: - >>> print "Not a valid DER SET OF" - - the output will be ``[4, 5, 6]``. - """ - - def __init__(self, startSet=None, implicit=None): - """Initialize the DER object as a SET OF. - - :Parameters: - startSet : container - The initial set of integers or DER encoded objects. - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for SET OF (17). - """ - DerObject.__init__(self, 0x11, b'', implicit, True) - self._seq = [] - - # All elements must be of the same type (and therefore have the - # same leading octet) - self._elemOctet = None - - if startSet: - for e in startSet: - self.add(e) - - def __getitem__(self, n): - return self._seq[n] - - def __iter__(self): - return iter(self._seq) - - def __len__(self): - return len(self._seq) - - def add(self, elem): - """Add an element to the set. - - Args: - elem (byte string or integer): - An element of the same type of objects already in the set. - It can be an integer or a DER encoded object. - """ - - if _is_number(elem): - eo = 0x02 - elif isinstance(elem, DerObject): - eo = self._tag_octet - else: - eo = bord(elem[0]) - - if self._elemOctet != eo: - if self._elemOctet is not None: - raise ValueError("New element does not belong to the set") - self._elemOctet = eo - - if elem not in self._seq: - self._seq.append(elem) - - def decode(self, der_encoded, strict=False): - """Decode a complete SET OF DER element, and re-initializes this - object with it. - - DER INTEGERs are decoded into Python integers. Any other DER - element is left undecoded; its validity is not checked. - - Args: - der_encoded (byte string): a complete DER BIT SET OF. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER SET OF from a file.""" - - self._seq = [] - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - # Add one item at a time to self.seq, by scanning self.payload - p = BytesIO_EOF(self.payload) - setIdOctet = -1 - while p.remaining_data() > 0: - p.set_bookmark() - - der = DerObject() - der._decodeFromStream(p, strict) - - # Verify that all members are of the same type - if setIdOctet < 0: - setIdOctet = der._tag_octet - else: - if setIdOctet != der._tag_octet: - raise ValueError("Not all elements are of the same DER type") - - # Parse INTEGERs differently - if setIdOctet != 0x02: - self._seq.append(p.data_since_bookmark()) - else: - derInt = DerInteger() - derInt.decode(p.data_since_bookmark(), strict) - self._seq.append(derInt.value) - # end - - def encode(self): - """Return this SET OF DER element, fully encoded as a - binary string. - """ - - # Elements in the set must be ordered in lexicographic order - ordered = [] - for item in self._seq: - if _is_number(item): - bys = DerInteger(item).encode() - elif isinstance(item, DerObject): - bys = item.encode() - else: - bys = item - ordered.append(bys) - ordered.sort() - self.payload = b''.join(ordered) - return DerObject.encode(self) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.pyi deleted file mode 100644 index ee4891c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/asn1.pyi +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Optional, Sequence, Union, Set, Iterable - -__all__ = ['DerObject', 'DerInteger', 'DerOctetString', 'DerNull', - 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] - -# TODO: Make the encoded DerObjects their own type, so that DerSequence and -# DerSetOf can check their contents better - -class BytesIO_EOF: - def __init__(self, initial_bytes: bytes) -> None: ... - def set_bookmark(self) -> None: ... - def data_since_bookmark(self) -> bytes: ... - def remaining_data(self) -> int: ... - def read(self, length: int) -> bytes: ... - def read_byte(self) -> bytes: ... - -class DerObject: - payload: bytes - def __init__(self, asn1Id: Optional[int]=None, payload: Optional[bytes]=..., implicit: Optional[int]=None, - constructed: Optional[bool]=False, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... - -class DerInteger(DerObject): - value: int - def __init__(self, value: Optional[int]= 0, implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerInteger: ... - -class DerBoolean(DerObject): - value: bool - def __init__(self, value: bool=..., implicit: Optional[Union[int, bytes]]=..., explicit: Optional[Union[int, bytes]]=...) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerBoolean: ... - -class DerSequence(DerObject): - def __init__(self, startSeq: Optional[Sequence[Union[int, DerInteger, DerObject]]]=None, implicit: Optional[int]=None) -> None: ... - def __delitem__(self, n: int) -> None: ... - def __getitem__(self, n: int) -> None: ... - def __setitem__(self, key: int, value: DerObject) -> None: ... - def __setslice__(self, i: int, j: int, sequence: Sequence) -> None: ... - def __delslice__(self, i: int, j: int) -> None: ... - def __getslice__(self, i: int, j: int) -> DerSequence: ... - def __len__(self) -> int: ... - def __iadd__(self, item: DerObject) -> DerSequence: ... - def append(self, item: DerObject) -> DerSequence: ... - def hasInts(self, only_non_negative: Optional[bool]=True) -> int: ... - def hasOnlyInts(self, only_non_negative: Optional[bool]=True) -> bool: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=..., nr_elements: Optional[int]=None, only_ints_expected: Optional[bool]=False) -> DerSequence: ... - -class DerOctetString(DerObject): - payload: bytes - def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None) -> None: ... - -class DerNull(DerObject): - def __init__(self) -> None: ... - -class DerObjectId(DerObject): - value: str - def __init__(self, value: Optional[str]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerObjectId: ... - -class DerBitString(DerObject): - value: bytes - def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerBitString: ... - -DerSetElement = Union[bytes, int] - -class DerSetOf(DerObject): - def __init__(self, startSet: Optional[Set[DerSetElement]]=None, implicit: Optional[int]=None) -> None: ... - def __getitem__(self, n: int) -> DerSetElement: ... - def __iter__(self) -> Iterable: ... - def __len__(self) -> int: ... - def add(self, elem: DerSetElement) -> None: ... - def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... - def encode(self) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.py deleted file mode 100644 index a1c0d5c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.py +++ /dev/null @@ -1,1525 +0,0 @@ -# -# number.py : Number-theoretic functions -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew M. Kuchling, Barry A. Warsaw, and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== -# - -import math -import sys -import struct -from Crypto import Random -from Crypto.Util.py3compat import iter_range - -# Backward compatibility -_fastmath = None - - -def ceil_div(n, d): - """Return ceil(n/d), that is, the smallest integer r such that r*d >= n""" - - if d == 0: - raise ZeroDivisionError() - if (n < 0) or (d < 0): - raise ValueError("Non positive values") - r, q = divmod(n, d) - if (n != 0) and (q != 0): - r += 1 - return r - - -def size (N): - """Returns the size of the number N in bits.""" - - if N < 0: - raise ValueError("Size in bits only available for non-negative numbers") - return N.bit_length() - - -def getRandomInteger(N, randfunc=None): - """Return a random number at most N bits long. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. Use :func:`Crypto.Random.random.getrandbits` instead. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - S = randfunc(N>>3) - odd_bits = N % 8 - if odd_bits != 0: - rand_bits = ord(randfunc(1)) >> (8-odd_bits) - S = struct.pack('B', rand_bits) + S - value = bytes_to_long(S) - return value - -def getRandomRange(a, b, randfunc=None): - """Return a random number *n* so that *a <= n < b*. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. Use :func:`Crypto.Random.random.randrange` instead. - """ - - range_ = b - a - 1 - bits = size(range_) - value = getRandomInteger(bits, randfunc) - while value > range_: - value = getRandomInteger(bits, randfunc) - return a + value - -def getRandomNBitInteger(N, randfunc=None): - """Return a random number with exactly N-bits, - i.e. a random number between 2**(N-1) and (2**N)-1. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. - """ - - value = getRandomInteger (N-1, randfunc) - value |= 2 ** (N-1) # Ensure high bit is set - assert size(value) >= N - return value - - -if sys.version_info[:2] >= (3, 5): - - GCD = math.gcd - -else: - - def GCD(x,y): - """Greatest Common Denominator of :data:`x` and :data:`y`. - """ - - x = abs(x) ; y = abs(y) - while x > 0: - x, y = y % x, x - return y - - -if sys.version_info[:2] >= (3, 8): - - def inverse(u, v): - """The inverse of :data:`u` *mod* :data:`v`.""" - - if v == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if v < 0: - raise ValueError("Modulus cannot be negative") - - return pow(u, -1, v) - -else: - - def inverse(u, v): - """The inverse of :data:`u` *mod* :data:`v`.""" - - if v == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if v < 0: - raise ValueError("Modulus cannot be negative") - - u3, v3 = u, v - u1, v1 = 1, 0 - while v3 > 0: - q = u3 // v3 - u1, v1 = v1, u1 - v1*q - u3, v3 = v3, u3 - v3*q - if u3 != 1: - raise ValueError("No inverse value can be computed") - while u1<0: - u1 = u1 + v - return u1 - -# Given a number of bits to generate and a random generation function, -# find a prime number of the appropriate size. - -def getPrime(N, randfunc=None): - """Return a random N-bit prime number. - - N must be an integer larger than 1. - If randfunc is omitted, then :meth:`Random.get_random_bytes` is used. - """ - if randfunc is None: - randfunc = Random.get_random_bytes - - if N < 2: - raise ValueError("N must be larger than 1") - - while True: - number = getRandomNBitInteger(N, randfunc) | 1 - if isPrime(number, randfunc=randfunc): - break - return number - - -def _rabinMillerTest(n, rounds, randfunc=None): - """_rabinMillerTest(n:long, rounds:int, randfunc:callable):int - Tests if n is prime. - Returns 0 when n is definitely composite. - Returns 1 when n is probably prime. - Returns 2 when n is definitely prime. - - If randfunc is omitted, then Random.new().read is used. - - This function is for internal use only and may be renamed or removed in - the future. - """ - # check special cases (n==2, n even, n < 2) - if n < 3 or (n & 1) == 0: - return n == 2 - # n might be very large so it might be beneficial to precalculate n-1 - n_1 = n - 1 - # determine m and b so that 2**b * m = n - 1 and b maximal - b = 0 - m = n_1 - while (m & 1) == 0: - b += 1 - m >>= 1 - - tested = [] - # we need to do at most n-2 rounds. - for i in iter_range (min (rounds, n-2)): - # randomly choose a < n and make sure it hasn't been tested yet - a = getRandomRange (2, n, randfunc) - while a in tested: - a = getRandomRange (2, n, randfunc) - tested.append (a) - # do the rabin-miller test - z = pow (a, m, n) # (a**m) % n - if z == 1 or z == n_1: - continue - composite = 1 - for r in iter_range(b): - z = (z * z) % n - if z == 1: - return 0 - elif z == n_1: - composite = 0 - break - if composite: - return 0 - return 1 - -def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None): - r""" - Return a random strong *N*-bit prime number. - In this context, *p* is a strong prime if *p-1* and *p+1* have at - least one large prime factor. - - Args: - N (integer): the exact length of the strong prime. - It must be a multiple of 128 and > 512. - e (integer): if provided, the returned prime (minus 1) - will be coprime to *e* and thus suitable for RSA where - *e* is the public exponent. - false_positive_prob (float): - The statistical probability for the result not to be actually a - prime. It defaults to 10\ :sup:`-6`. - Note that the real probability of a false-positive is far less. This is - just the mathematically provable limit. - randfunc (callable): - A function that takes a parameter *N* and that returns - a random byte string of such length. - If omitted, :func:`Crypto.Random.get_random_bytes` is used. - Return: - The new strong prime. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. - """ - - # This function was implemented following the - # instructions found in the paper: - # "FAST GENERATION OF RANDOM, STRONG RSA PRIMES" - # by Robert D. Silverman - # RSA Laboratories - # May 17, 1997 - # which by the time of writing could be freely downloaded here: - # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.17.2713&rep=rep1&type=pdf - - if randfunc is None: - randfunc = Random.get_random_bytes - - # Use the accelerator if available - if _fastmath is not None: - return _fastmath.getStrongPrime(long(N), long(e), false_positive_prob, - randfunc) - - if (N < 512) or ((N % 128) != 0): - raise ValueError ("bits must be multiple of 128 and > 512") - - rabin_miller_rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) - - # calculate range for X - # lower_bound = sqrt(2) * 2^{511 + 128*x} - # upper_bound = 2^{512 + 128*x} - 1 - x = (N - 512) >> 7 - # We need to approximate the sqrt(2) in the lower_bound by an integer - # expression because floating point math overflows with these numbers - lower_bound = (14142135623730950489 * (2 ** (511 + 128*x))) // 10000000000000000000 - upper_bound = (1 << (512 + 128*x)) - 1 - # Randomly choose X in calculated range - X = getRandomRange (lower_bound, upper_bound, randfunc) - - # generate p1 and p2 - p = [0, 0] - for i in (0, 1): - # randomly choose 101-bit y - y = getRandomNBitInteger (101, randfunc) - # initialize the field for sieving - field = [0] * 5 * len (sieve_base) - # sieve the field - for prime in sieve_base: - offset = y % prime - for j in iter_range((prime - offset) % prime, len (field), prime): - field[j] = 1 - - # look for suitable p[i] starting at y - result = 0 - for j in range(len(field)): - composite = field[j] - # look for next canidate - if composite: - continue - tmp = y + j - result = _rabinMillerTest (tmp, rabin_miller_rounds) - if result > 0: - p[i] = tmp - break - if result == 0: - raise RuntimeError ("Couln't find prime in field. " - "Developer: Increase field_size") - - # Calculate R - # R = (p2^{-1} mod p1) * p2 - (p1^{-1} mod p2) * p1 - tmp1 = inverse (p[1], p[0]) * p[1] # (p2^-1 mod p1)*p2 - tmp2 = inverse (p[0], p[1]) * p[0] # (p1^-1 mod p2)*p1 - R = tmp1 - tmp2 # (p2^-1 mod p1)*p2 - (p1^-1 mod p2)*p1 - - # search for final prime number starting by Y0 - # Y0 = X + (R - X mod p1p2) - increment = p[0] * p[1] - X = X + (R - (X % increment)) - while 1: - is_possible_prime = 1 - # first check candidate against sieve_base - for prime in sieve_base: - if (X % prime) == 0: - is_possible_prime = 0 - break - # if e is given make sure that e and X-1 are coprime - # this is not necessarily a strong prime criterion but useful when - # creating them for RSA where the p-1 and q-1 should be coprime to - # the public exponent e - if e and is_possible_prime: - if e & 1: - if GCD(e, X-1) != 1: - is_possible_prime = 0 - else: - if GCD(e, (X-1) // 2) != 1: - is_possible_prime = 0 - - # do some Rabin-Miller-Tests - if is_possible_prime: - result = _rabinMillerTest (X, rabin_miller_rounds) - if result > 0: - break - X += increment - # abort when X has more bits than requested - # TODO: maybe we shouldn't abort but rather start over. - if X >= 1 << N: - raise RuntimeError ("Couln't find prime in field. " - "Developer: Increase field_size") - return X - -def isPrime(N, false_positive_prob=1e-6, randfunc=None): - r"""Test if a number *N* is a prime. - - Args: - false_positive_prob (float): - The statistical probability for the result not to be actually a - prime. It defaults to 10\ :sup:`-6`. - Note that the real probability of a false-positive is far less. - This is just the mathematically provable limit. - randfunc (callable): - A function that takes a parameter *N* and that returns - a random byte string of such length. - If omitted, :func:`Crypto.Random.get_random_bytes` is used. - - Return: - `True` if the input is indeed prime. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - if _fastmath is not None: - return _fastmath.isPrime(long(N), false_positive_prob, randfunc) - - if N < 3 or N & 1 == 0: - return N == 2 - for p in sieve_base: - if N == p: - return True - if N % p == 0: - return False - - rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) - return bool(_rabinMillerTest(N, rounds, randfunc)) - - -# Improved conversion functions contributed by Barry Warsaw, after -# careful benchmarking - -import struct - -def long_to_bytes(n, blocksize=0): - """Convert a positive integer to a byte string using big endian encoding. - - If :data:`blocksize` is absent or zero, the byte string will - be of minimal length. - - Otherwise, the length of the byte string is guaranteed to be a multiple - of :data:`blocksize`. If necessary, zeroes (``\\x00``) are added at the left. - - .. note:: - In Python 3, if you are sure that :data:`n` can fit into - :data:`blocksize` bytes, you can simply use the native method instead:: - - >>> n.to_bytes(blocksize, 'big') - - For instance:: - - >>> n = 80 - >>> n.to_bytes(2, 'big') - b'\\x00P' - - However, and unlike this ``long_to_bytes()`` function, - an ``OverflowError`` exception is raised if :data:`n` does not fit. - """ - - if n < 0 or blocksize < 0: - raise ValueError("Values must be non-negative") - - result = [] - pack = struct.pack - - # Fill the first block independently from the value of n - bsr = blocksize - while bsr >= 8: - result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) - n = n >> 64 - bsr -= 8 - - while bsr >= 4: - result.insert(0, pack('>I', n & 0xFFFFFFFF)) - n = n >> 32 - bsr -= 4 - - while bsr > 0: - result.insert(0, pack('>B', n & 0xFF)) - n = n >> 8 - bsr -= 1 - - if n == 0: - if len(result) == 0: - bresult = b'\x00' - else: - bresult = b''.join(result) - else: - # The encoded number exceeds the block size - while n > 0: - result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) - n = n >> 64 - result[0] = result[0].lstrip(b'\x00') - bresult = b''.join(result) - # bresult has minimum length here - if blocksize > 0: - target_len = ((len(bresult) - 1) // blocksize + 1) * blocksize - bresult = b'\x00' * (target_len - len(bresult)) + bresult - - return bresult - - -def bytes_to_long(s): - """Convert a byte string to a long integer (big endian). - - In Python 3.2+, use the native method instead:: - - >>> int.from_bytes(s, 'big') - - For instance:: - - >>> int.from_bytes(b'\x00P', 'big') - 80 - - This is (essentially) the inverse of :func:`long_to_bytes`. - """ - acc = 0 - - unpack = struct.unpack - - # Up to Python 2.7.4, struct.unpack can't work with bytearrays nor - # memoryviews - if sys.version_info[0:3] < (2, 7, 4): - if isinstance(s, bytearray): - s = bytes(s) - elif isinstance(s, memoryview): - s = s.tobytes() - - length = len(s) - if length % 4: - extra = (4 - length % 4) - s = b'\x00' * extra + s - length = length + extra - for i in range(0, length, 4): - acc = (acc << 32) + unpack('>I', s[i:i+4])[0] - return acc - - -# For backwards compatibility... -import warnings -def long2str(n, blocksize=0): - warnings.warn("long2str() has been replaced by long_to_bytes()") - return long_to_bytes(n, blocksize) -def str2long(s): - warnings.warn("str2long() has been replaced by bytes_to_long()") - return bytes_to_long(s) - - -# The first 10000 primes used for checking primality. -# This should be enough to eliminate most of the odd -# numbers before needing to do a Rabin-Miller test at all. -sieve_base = ( - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, - 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, - 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, - 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, - 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, - 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, - 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, - 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, - 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, - 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, - 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, - 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, - 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, - 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, - 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, - 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, - 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, - 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, - 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, - 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, - 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, - 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, - 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, - 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, - 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, - 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, - 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, - 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, - 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, - 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, - 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, - 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, - 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, - 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, - 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, - 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, - 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, - 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, - 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, - 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, - 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, - 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, - 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, - 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, - 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, - 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, - 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, - 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, - 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, - 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, - 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, - 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, - 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, - 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, - 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, - 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, - 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, - 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, - 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, - 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, - 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, - 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, - 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, - 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, - 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, - 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, - 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, - 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, - 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, - 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, - 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, - 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, - 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, - 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, - 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, - 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, - 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, - 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, - 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, - 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, - 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, - 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, - 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, - 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, - 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, - 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, - 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, - 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, - 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, - 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, - 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, - 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, - 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, - 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, - 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, - 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, - 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, - 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, - 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, - 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, - 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, - 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, - 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, - 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, - 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, - 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, - 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, - 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, - 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, - 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, - 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, - 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, - 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, - 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, - 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, - 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, - 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, - 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, - 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, - 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, - 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, - 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, - 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, - 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, - 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, - 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, - 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, - 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, - 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, - 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, - 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, - 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, - 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, - 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, - 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, - 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, - 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, - 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, - 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, - 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, - 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, - 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, - 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, - 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, - 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, - 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, - 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, - 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, - 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, - 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, - 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, - 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, - 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, - 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, - 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, - 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, - 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, - 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, - 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, - 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, - 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, - 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, - 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, - 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, - 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, - 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, - 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, - 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, - 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, - 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, - 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, - 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, - 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, - 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, - 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, - 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, - 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, - 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, - 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, - 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, - 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, - 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, - 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, - 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, - 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, - 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, - 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, - 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, - 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, - 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, - 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, - 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, - 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, - 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, - 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, - 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, - 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, - 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, - 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, - 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, - 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, - 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, - 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, - 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, - 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, - 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, - 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, - 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, - 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, - 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, - 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, - 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, - 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, - 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, - 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, - 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, - 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, - 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, - 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, - 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, - 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, - 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, - 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, - 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, - 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, - 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, - 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, - 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, - 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, - 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, - 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, - 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, - 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, - 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, - 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, - 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, - 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, - 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, - 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, - 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, - 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, - 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, - 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, - 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, - 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, - 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, - 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, - 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, - 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, - 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, - 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, - 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, - 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, - 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, - 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, - 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, - 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, - 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, - 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, - 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, - 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, - 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, - 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, - 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, - 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, - 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, - 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, - 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, - 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, - 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, - 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, - 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, - 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, - 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, - 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, - 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, - 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, - 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, - 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, - 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, - 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, - 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, - 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, - 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, - 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, - 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, - 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, - 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, - 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, - 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, - 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, - 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, - 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, - 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, - 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, - 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, - 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, - 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, - 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, - 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, - 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, - 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, - 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, - 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, - 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, - 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, - 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, - 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, - 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, - 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, - 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, - 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, - 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, - 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, - 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, - 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, - 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, - 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, - 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, - 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, - 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, - 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, - 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, - 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, - 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, - 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, - 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, - 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, - 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, - 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, - 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, - 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, - 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, - 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, - 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, - 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, - 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, - 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, - 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, - 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, - 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, - 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, - 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, - 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, - 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, - 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, - 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, - 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, - 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, - 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, - 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, - 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, - 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, - 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, - 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, - 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, - 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, - 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, - 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, - 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, - 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, - 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, - 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, - 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, - 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, - 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, - 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, - 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, - 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, - 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, - 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, - 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, - 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, - 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, - 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, - 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, - 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, - 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, - 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, - 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, - 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, - 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, - 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, - 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, - 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, - 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, - 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, - 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, - 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, - 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, - 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, - 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, - 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, - 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, - 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, - 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, - 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, - 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, - 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, - 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, - 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, - 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, - 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, - 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, - 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, - 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, - 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, - 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, - 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, - 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, - 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, - 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, - 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, - 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, - 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, - 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, - 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, - 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, - 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, - 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, - 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, - 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, - 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, - 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, - 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, - 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, - 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, - 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, - 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, - 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, - 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, - 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, - 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, - 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, - 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, - 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, - 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, - 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, - 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, - 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, - 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, - 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, - 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, - 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, - 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, - 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, - 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, - 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, - 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, - 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, - 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, - 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, - 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, - 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, - 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, - 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, - 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, - 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, - 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, - 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, - 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, - 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, - 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, - 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, - 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, - 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, - 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, - 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, - 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, - 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, - 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, - 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, - 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, - 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, - 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, - 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, - 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, - 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, - 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, - 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, - 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, - 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, - 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, - 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, - 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, - 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, - 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, - 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, - 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, - 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, - 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, - 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, - 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, - 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, - 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, - 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, - 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, - 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, - 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, - 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, - 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, - 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, - 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, - 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, - 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, - 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, - 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, - 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, - 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, - 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, - 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, - 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, - 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, - 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, - 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, - 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, - 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, - 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, - 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, - 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, - 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, - 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, - 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, - 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, - 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, - 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, - 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, - 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, - 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, - 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, - 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, - 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, - 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, - 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, - 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, - 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, - 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, - 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, - 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, - 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, - 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, - 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, - 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, - 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, - 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, - 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, - 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, - 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, - 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, - 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, - 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, - 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, - 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, - 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, - 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, - 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, - 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, - 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, - 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, - 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, - 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, - 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, - 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, - 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, - 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, - 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, - 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, - 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, - 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, - 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, - 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, - 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, - 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, - 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, - 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, - 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, - 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, - 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, - 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, - 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, - 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, - 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, - 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, - 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, - 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, - 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, - 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, - 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, - 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, - 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, - 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, - 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, - 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, - 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, - 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, - 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, - 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, - 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, - 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, - 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, - 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, - 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, - 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, - 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, - 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, - 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, - 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, - 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, - 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, - 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, - 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, - 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, - 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, - 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, - 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, - 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, - 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, - 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, - 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, - 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, - 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, - 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, - 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, - 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, - 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, - 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, - 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, - 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, - 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, - 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, - 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, - 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, - 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, - 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, - 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, - 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, - 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, - 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, - 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, - 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, - 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, - 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, - 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, - 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, - 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, - 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, - 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677, - 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, - 65777, 65789, 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867, - 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, 65983, - 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, - 66107, 66109, 66137, 66161, 66169, 66173, 66179, 66191, 66221, 66239, - 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, 66377, - 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, - 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, 66587, 66593, - 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, 66721, - 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, - 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943, - 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049, - 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, - 67157, 67169, 67181, 67187, 67189, 67211, 67213, 67217, 67219, 67231, - 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, 67369, - 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, - 67477, 67481, 67489, 67493, 67499, 67511, 67523, 67531, 67537, 67547, - 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, 67651, - 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, - 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, 67867, - 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961, - 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, - 68099, 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213, - 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371, - 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, - 68491, 68501, 68507, 68521, 68531, 68539, 68543, 68567, 68581, 68597, - 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, 68713, - 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, - 68821, 68863, 68879, 68881, 68891, 68897, 68899, 68903, 68909, 68917, - 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, 69061, - 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, - 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263, - 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403, - 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, - 69497, 69499, 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691, - 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, 69821, - 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, - 69931, 69941, 69959, 69991, 69997, 70001, 70003, 70009, 70019, 70039, - 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, 70139, - 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, - 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, 70313, 70321, - 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, 70451, - 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, - 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657, - 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793, - 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, - 70913, 70919, 70921, 70937, 70949, 70951, 70957, 70969, 70979, 70981, - 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, 71089, - 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, - 71233, 71237, 71249, 71257, 71261, 71263, 71287, 71293, 71317, 71327, - 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, 71389, - 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, - 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, 71593, - 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713, - 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, - 71849, 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933, - 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031, - 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, - 72139, 72161, 72167, 72169, 72173, 72211, 72221, 72223, 72227, 72229, - 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, 72341, - 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, - 72493, 72497, 72503, 72533, 72547, 72551, 72559, 72577, 72613, 72617, - 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, 72701, - 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, - 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923, - 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013, - 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, - 73133, 73141, 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303, - 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, 73417, - 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, - 73547, 73553, 73561, 73571, 73583, 73589, 73597, 73607, 73609, 73613, - 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, 73721, - 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, - 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, 73961, 73973, - 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, 74099, - 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, - 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297, - 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411, - 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, - 74527, 74531, 74551, 74561, 74567, 74573, 74587, 74597, 74609, 74611, - 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, 74731, - 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, - 74857, 74861, 74869, 74873, 74887, 74891, 74897, 74903, 74923, 74929, - 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, 75079, - 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, - 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, 75307, - 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401, - 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, - 75539, 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619, - 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709, - 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, - 75833, 75853, 75869, 75883, 75913, 75931, 75937, 75941, 75967, 75979, - 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, 76081, - 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, - 76213, 76231, 76243, 76249, 76253, 76259, 76261, 76283, 76289, 76303, - 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, 76441, - 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, - 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667, - 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781, - 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, - 76913, 76919, 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023, - 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, 77153, - 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, - 77263, 77267, 77269, 77279, 77291, 77317, 77323, 77339, 77347, 77351, - 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, 77477, - 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, - 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, 77621, 77641, - 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, 77723, - 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, - 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977, - 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101, - 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, - 78203, 78229, 78233, 78241, 78259, 78277, 78283, 78301, 78307, 78311, - 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, 78479, - 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, - 78577, 78583, 78593, 78607, 78623, 78643, 78649, 78653, 78691, 78697, - 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, 78803, - 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, - 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, 79063, - 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181, - 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, - 79301, 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393, - 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531, - 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, - 79627, 79631, 79633, 79657, 79669, 79687, 79691, 79693, 79697, 79699, - 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, 79841, - 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, - 79943, 79967, 79973, 79979, 79987, 79997, 79999, 80021, 80039, 80051, - 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, 80173, - 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, - 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369, - 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513, - 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, - 80651, 80657, 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713, - 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, 80809, - 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, - 80929, 80933, 80953, 80963, 80989, 81001, 81013, 81017, 81019, 81023, - 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, 81101, - 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, - 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, 81343, 81349, - 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, 81463, - 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, - 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689, - 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799, - 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, - 81931, 81937, 81943, 81953, 81967, 81971, 81973, 82003, 82007, 82009, - 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, 82139, - 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, - 82223, 82231, 82237, 82241, 82261, 82267, 82279, 82301, 82307, 82339, - 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, 82469, - 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, - 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, 82651, - 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781, - 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, - 82903, 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047, - 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177, - 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, - 83269, 83273, 83299, 83311, 83339, 83341, 83357, 83383, 83389, 83399, - 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, 83471, - 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, - 83617, 83621, 83639, 83641, 83653, 83663, 83689, 83701, 83717, 83719, - 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, 83869, - 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, - 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127, - 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221, - 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, - 84347, 84349, 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437, - 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, 84521, - 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, - 84673, 84691, 84697, 84701, 84713, 84719, 84731, 84737, 84751, 84761, - 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, 84913, - 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, - 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, 85109, 85121, - 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, 85237, - 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, - 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469, - 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601, - 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, - 85703, 85711, 85717, 85733, 85751, 85781, 85793, 85817, 85819, 85829, - 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, 85933, - 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, - 86113, 86117, 86131, 86137, 86143, 86161, 86171, 86179, 86183, 86197, - 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, 86291, - 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, - 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, 86477, - 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587, - 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, - 86753, 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861, - 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993, - 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, - 87121, 87133, 87149, 87151, 87179, 87181, 87187, 87211, 87221, 87223, - 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, 87323, - 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, - 87481, 87491, 87509, 87511, 87517, 87523, 87539, 87541, 87547, 87553, - 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, 87641, - 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, - 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853, - 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961, - 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, - 88093, 88117, 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259, - 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, 88411, - 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, - 88589, 88591, 88607, 88609, 88643, 88651, 88657, 88661, 88663, 88667, - 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, 88801, - 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, - 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, 88997, 89003, - 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, 89087, - 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, - 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317, - 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431, - 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, - 89533, 89561, 89563, 89567, 89591, 89597, 89599, 89603, 89611, 89627, - 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, 89759, - 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, - 89867, 89891, 89897, 89899, 89909, 89917, 89923, 89939, 89959, 89963, - 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, 90031, - 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, - 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, 90239, - 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373, - 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, - 90499, 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617, - 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709, - 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, - 90863, 90887, 90901, 90907, 90911, 90917, 90931, 90947, 90971, 90977, - 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, 91121, - 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, - 91199, 91229, 91237, 91243, 91249, 91253, 91283, 91291, 91297, 91303, - 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, 91411, - 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, - 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673, - 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807, - 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, - 91943, 91951, 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033, - 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, 92173, - 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, - 92251, 92269, 92297, 92311, 92317, 92333, 92347, 92353, 92357, 92363, - 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, 92431, - 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, - 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, 92657, 92669, - 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, 92753, - 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, - 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951, - 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083, - 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, - 93187, 93199, 93229, 93239, 93241, 93251, 93253, 93257, 93263, 93281, - 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, 93383, - 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, - 93503, 93523, 93529, 93553, 93557, 93559, 93563, 93581, 93601, 93607, - 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, 93787, - 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, - 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, 93997, - 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111, - 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, - 94261, 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349, - 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447, - 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, - 94561, 94573, 94583, 94597, 94603, 94613, 94621, 94649, 94651, 94687, - 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, 94793, - 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, - 94907, 94933, 94949, 94951, 94961, 94993, 94999, 95003, 95009, 95021, - 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, 95111, - 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, - 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317, - 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441, - 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, - 95549, 95561, 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633, - 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, 95773, - 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, - 95881, 95891, 95911, 95917, 95923, 95929, 95947, 95957, 95959, 95971, - 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, 96097, - 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, - 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, 96329, 96331, - 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, 96461, - 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, - 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731, - 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799, - 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, - 96953, 96959, 96973, 96979, 96989, 96997, 97001, 97003, 97007, 97021, - 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, 97169, - 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, - 97327, 97367, 97369, 97373, 97379, 97381, 97387, 97397, 97423, 97429, - 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, 97549, - 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, - 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, 97813, - 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883, - 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, - 98017, 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179, - 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317, - 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, - 98419, 98429, 98443, 98453, 98459, 98467, 98473, 98479, 98491, 98507, - 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, 98639, - 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, - 98773, 98779, 98801, 98807, 98809, 98837, 98849, 98867, 98869, 98873, - 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, 98947, - 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, - 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139, - 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259, - 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, - 99401, 99409, 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529, - 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, 99643, - 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, - 99761, 99767, 99787, 99793, 99809, 99817, 99823, 99829, 99833, 99839, - 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, - 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, -100129, 100151, 100153, 100169, 100183, 100189, 100193, 100207, 100213, 100237, -100267, 100271, 100279, 100291, 100297, 100313, 100333, 100343, 100357, 100361, -100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, 100469, -100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, -100559, 100591, 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, -100703, 100733, 100741, 100747, 100769, 100787, 100799, 100801, 100811, 100823, -100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, 100943, 100957, -100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, -101107, 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, -101183, 101197, 101203, 101207, 101209, 101221, 101267, 101273, 101279, 101281, -101287, 101293, 101323, 101333, 101341, 101347, 101359, 101363, 101377, 101383, -101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, -101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, -101603, 101611, 101627, 101641, 101653, 101663, 101681, 101693, 101701, 101719, -101723, 101737, 101741, 101747, 101749, 101771, 101789, 101797, 101807, 101833, -101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, 101929, -101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, -102031, 102043, 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, -102121, 102139, 102149, 102161, 102181, 102191, 102197, 102199, 102203, 102217, -102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, 102301, 102317, -102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, -102461, 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, -102559, 102563, 102587, 102593, 102607, 102611, 102643, 102647, 102653, 102667, -102673, 102677, 102679, 102701, 102761, 102763, 102769, 102793, 102797, 102811, -102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, -102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, -103087, 103091, 103093, 103099, 103123, 103141, 103171, 103177, 103183, 103217, -103231, 103237, 103289, 103291, 103307, 103319, 103333, 103349, 103357, 103387, -103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, 103483, -103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, -103613, 103619, 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, -103723, 103769, 103787, 103801, 103811, 103813, 103837, 103841, 103843, 103867, -103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, 103979, 103981, -103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, -104087, 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, -104179, 104183, 104207, 104231, 104233, 104239, 104243, 104281, 104287, 104297, -104309, 104311, 104323, 104327, 104347, 104369, 104381, 104383, 104393, 104399, -104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, -104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, -104677, 104681, 104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729, -) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.pyi deleted file mode 100644 index f8680bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/number.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List, Optional, Callable - - -def ceil_div(n: int, d: int) -> int: ... -def size (N: int) -> int: ... -def getRandomInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... -def getRandomRange(a: int, b: int, randfunc: Optional[Callable]=None) -> int: ... -def getRandomNBitInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... -def GCD(x: int,y: int) -> int: ... -def inverse(u: int, v: int) -> int: ... -def getPrime(N: int, randfunc: Optional[Callable]=None) -> int: ... -def getStrongPrime(N: int, e: Optional[int]=0, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> int: ... -def isPrime(N: int, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> bool: ... -def long_to_bytes(n: int, blocksize: Optional[int]=0) -> bytes: ... -def bytes_to_long(s: bytes) -> int: ... -def long2str(n: int, blocksize: Optional[int]=0) -> bytes: ... -def str2long(s: bytes) -> int: ... - -sieve_base: List[int] diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.py deleted file mode 100644 index 087550d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Util/py3compat.py : Compatibility code for handling Py3k / Python 2.x -# -# Written in 2010 by Thorsten Behrens -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# 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. -# =================================================================== - -"""Compatibility code for handling string/bytes changes from Python 2.x to Py3k - -In Python 2.x, strings (of type ''str'') contain binary data, including encoded -Unicode text (e.g. UTF-8). The separate type ''unicode'' holds Unicode text. -Unicode literals are specified via the u'...' prefix. Indexing or slicing -either type always produces a string of the same type as the original. -Data read from a file is always of '''str'' type. - -In Python 3.x, strings (type ''str'') may only contain Unicode text. The u'...' -prefix and the ''unicode'' type are now redundant. A new type (called -''bytes'') has to be used for binary data (including any particular -''encoding'' of a string). The b'...' prefix allows one to specify a binary -literal. Indexing or slicing a string produces another string. Slicing a byte -string produces another byte string, but the indexing operation produces an -integer. Data read from a file is of '''str'' type if the file was opened in -text mode, or of ''bytes'' type otherwise. - -Since PyCrypto aims at supporting both Python 2.x and 3.x, the following helper -functions are used to keep the rest of the library as independent as possible -from the actual Python version. - -In general, the code should always deal with binary strings, and use integers -instead of 1-byte character strings. - -b(s) - Take a text string literal (with no prefix or with u'...' prefix) and - make a byte string. -bchr(c) - Take an integer and make a 1-character byte string. -bord(c) - Take the result of indexing on a byte string and make an integer. -tobytes(s) - Take a text string, a byte string, or a sequence of character taken from - a byte string and make a byte string. -""" - -import sys -import abc - - -if sys.version_info[0] == 2: - def b(s): - return s - def bchr(s): - return chr(s) - def bstr(s): - return str(s) - def bord(s): - return ord(s) - def tobytes(s, encoding="latin-1"): - if isinstance(s, unicode): - return s.encode(encoding) - elif isinstance(s, str): - return s - elif isinstance(s, bytearray): - return bytes(s) - elif isinstance(s, memoryview): - return s.tobytes() - else: - return ''.join(s) - def tostr(bs): - return bs - def byte_string(s): - return isinstance(s, str) - - # In Python 2, a memoryview does not support concatenation - def concat_buffers(a, b): - if isinstance(a, memoryview): - a = a.tobytes() - if isinstance(b, memoryview): - b = b.tobytes() - return a + b - - from StringIO import StringIO - BytesIO = StringIO - - from sys import maxint - - iter_range = xrange - - def is_native_int(x): - return isinstance(x, (int, long)) - - def is_string(x): - return isinstance(x, basestring) - - def is_bytes(x): - return isinstance(x, str) or \ - isinstance(x, bytearray) or \ - isinstance(x, memoryview) - - ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - - FileNotFoundError = IOError - -else: - def b(s): - return s.encode("latin-1") # utf-8 would cause some side-effects we don't want - def bchr(s): - return bytes([s]) - def bstr(s): - if isinstance(s,str): - return bytes(s,"latin-1") - else: - return bytes(s) - def bord(s): - return s - def tobytes(s, encoding="latin-1"): - if isinstance(s, bytes): - return s - elif isinstance(s, bytearray): - return bytes(s) - elif isinstance(s,str): - return s.encode(encoding) - elif isinstance(s, memoryview): - return s.tobytes() - else: - return bytes([s]) - def tostr(bs): - return bs.decode("latin-1") - def byte_string(s): - return isinstance(s, bytes) - - def concat_buffers(a, b): - return a + b - - from io import BytesIO - from io import StringIO - from sys import maxsize as maxint - - iter_range = range - - def is_native_int(x): - return isinstance(x, int) - - def is_string(x): - return isinstance(x, str) - - def is_bytes(x): - return isinstance(x, bytes) or \ - isinstance(x, bytearray) or \ - isinstance(x, memoryview) - - from abc import ABC - - FileNotFoundError = FileNotFoundError - - -def _copy_bytes(start, end, seq): - """Return an immutable copy of a sequence (byte string, byte array, memoryview) - in a certain interval [start:seq]""" - - if isinstance(seq, memoryview): - return seq[start:end].tobytes() - elif isinstance(seq, bytearray): - return bytes(seq[start:end]) - else: - return seq[start:end] - -del sys -del abc diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.pyi deleted file mode 100644 index 74e04a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/py3compat.pyi +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union, Any, Optional, IO - -Buffer = Union[bytes, bytearray, memoryview] - -import sys - -def b(s: str) -> bytes: ... -def bchr(s: int) -> bytes: ... -def bord(s: bytes) -> int: ... -def tobytes(s: Union[bytes, str]) -> bytes: ... -def tostr(b: bytes) -> str: ... -def bytestring(x: Any) -> bool: ... - -def is_native_int(s: Any) -> bool: ... -def is_string(x: Any) -> bool: ... -def is_bytes(x: Any) -> bool: ... - -def BytesIO(b: bytes) -> IO[bytes]: ... -def StringIO(s: str) -> IO[str]: ... - -if sys.version_info[0] == 2: - from sys import maxint - iter_range = xrange - -else: - from sys import maxsize as maxint - iter_range = range - -class FileNotFoundError: - def __init__(self, err: int, msg: str, filename: str) -> None: - pass - -def _copy_bytes(start: Optional[int], end: Optional[int], seq: Buffer) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.py b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.py deleted file mode 100644 index 362db6e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.py +++ /dev/null @@ -1,146 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, - create_string_buffer, get_raw_buffer, - c_uint8_ptr, is_writeable_buffer) - -_raw_strxor = load_pycryptodome_raw_lib( - "Crypto.Util._strxor", - """ - void strxor(const uint8_t *in1, - const uint8_t *in2, - uint8_t *out, size_t len); - void strxor_c(const uint8_t *in, - uint8_t c, - uint8_t *out, - size_t len); - """) - - -def strxor(term1, term2, output=None): - """From two byte strings of equal length, - create a third one which is the byte-by-byte XOR of the two. - - Args: - term1 (bytes/bytearray/memoryview): - The first byte string to XOR. - term2 (bytes/bytearray/memoryview): - The second byte string to XOR. - output (bytearray/memoryview): - The location where the result will be written to. - It must have the same length as ``term1`` and ``term2``. - If ``None``, the result is returned. - :Return: - If ``output`` is ``None``, a new byte string with the result. - Otherwise ``None``. - - .. note:: - ``term1`` and ``term2`` must have the same length. - """ - - if len(term1) != len(term2): - raise ValueError("Only byte strings of equal length can be xored") - - if output is None: - result = create_string_buffer(len(term1)) - else: - # Note: output may overlap with either input - result = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(term1) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(term1)) - - _raw_strxor.strxor(c_uint8_ptr(term1), - c_uint8_ptr(term2), - c_uint8_ptr(result), - c_size_t(len(term1))) - - if output is None: - return get_raw_buffer(result) - else: - return None - - -def strxor_c(term, c, output=None): - """From a byte string, create a second one of equal length - where each byte is XOR-red with the same value. - - Args: - term(bytes/bytearray/memoryview): - The byte string to XOR. - c (int): - Every byte in the string will be XOR-ed with this value. - It must be between 0 and 255 (included). - output (None or bytearray/memoryview): - The location where the result will be written to. - It must have the same length as ``term``. - If ``None``, the result is returned. - - Return: - If ``output`` is ``None``, a new ``bytes`` string with the result. - Otherwise ``None``. - """ - - if not 0 <= c < 256: - raise ValueError("c must be in range(256)") - - if output is None: - result = create_string_buffer(len(term)) - else: - # Note: output may overlap with either input - result = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(term) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(term)) - - _raw_strxor.strxor_c(c_uint8_ptr(term), - c, - c_uint8_ptr(result), - c_size_t(len(term)) - ) - - if output is None: - return get_raw_buffer(result) - else: - return None - - -def _strxor_direct(term1, term2, result): - """Very fast XOR - check conditions!""" - _raw_strxor.strxor(term1, term2, result, c_size_t(len(term1))) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.pyi deleted file mode 100644 index ca896f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/Util/strxor.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -def strxor(term1: bytes, term2: bytes, output: Optional[Buffer]=...) -> bytes: ... -def strxor_c(term: bytes, c: int, output: Optional[Buffer]=...) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.py b/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.py deleted file mode 100644 index 1fc2db9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', - 'IO', 'Math'] - -version_info = (3, 23, '0') - -__version__ = ".".join([str(x) for x in version_info]) diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.pyi deleted file mode 100644 index bc73446..0000000 --- a/backend/venv39/lib/python3.9/site-packages/Crypto/__init__.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Tuple, Union - -version_info : Tuple[int, int, Union[int, str]] -__version__ : str diff --git a/backend/venv39/lib/python3.9/site-packages/Crypto/py.typed b/backend/venv39/lib/python3.9/site-packages/Crypto/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/__init__.py b/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/__init__.py deleted file mode 100644 index 8def07a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: MIT - -from ._ffi import ffi, lib - - -__all__ = ["ffi", "lib"] diff --git a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi.abi3.so b/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi.abi3.so deleted file mode 100755 index 99fbc54..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi_build.py b/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi_build.py deleted file mode 100644 index ec4c823..0000000 --- a/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi_build.py +++ /dev/null @@ -1,233 +0,0 @@ -# SPDX-License-Identifier: MIT - -import os -import platform -import sysconfig - -from pathlib import Path - -from cffi import FFI - - -use_system_argon2 = os.environ.get("ARGON2_CFFI_USE_SYSTEM", "0") == "1" -use_sse2 = os.environ.get("ARGON2_CFFI_USE_SSE2", None) -windows = platform.system() == "Windows" -# Free-threaded CPython doesn't support limited API. -limited_api = not sysconfig.get_config_var("Py_GIL_DISABLED") - - -# Try to detect cross-compilation. -def _get_target_platform(arch_flags, default): - flags = [f for f in arch_flags.split(" ") if f.strip() != ""] - try: - pos = flags.index("-arch") - - return flags[pos + 1].lower() - except ValueError: - pass - - return default - - -target_platform = _get_target_platform( - os.environ.get("ARCHFLAGS", ""), platform.machine() -) - - -if use_sse2 == "1": - optimized = True -elif use_sse2 == "0": - optimized = False -else: - # Optimized version requires SSE2 extensions. They have been around since - # 2001 so we try to compile it on every recent-ish x86. - optimized = target_platform in ("i686", "x86", "x86_64", "AMD64") - - -ffi = FFI() - -if use_system_argon2: - ffi.set_source( - "_ffi", - "#include ", - libraries=["argon2"], - py_limited_api=limited_api, - ) -else: - lib_base = Path("extras") / "libargon2" / "src" - ffi.set_source( - "_ffi", - "#include ", - extra_compile_args=["-msse2"] if (optimized and not windows) else None, - include_dirs=[str(Path("extras", "libargon2", "include"))], - py_limited_api=limited_api, - sources=[ - str(lib_base / path) - for path in [ - "argon2.c", - Path("blake2") / "blake2b.c", - "core.c", - "encoding.c", - "opt.c" if optimized else "ref.c", - "thread.c", - ] - ], - ) - - -ffi.cdef( - """\ -typedef enum Argon2_type { - Argon2_d = ..., - Argon2_i = ..., - Argon2_id = ..., -} argon2_type; -typedef enum Argon2_version { - ARGON2_VERSION_10 = ..., - ARGON2_VERSION_13 = ..., - ARGON2_VERSION_NUMBER = ... -} argon2_version; - -int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, - const uint32_t parallelism, const void *pwd, - const size_t pwdlen, const void *salt, - const size_t saltlen, void *hash, - const size_t hashlen, char *encoded, - const size_t encodedlen, argon2_type type, - const uint32_t version); - -int argon2_verify(const char *encoded, const void *pwd, - const size_t pwdlen, argon2_type type); - -const char *argon2_error_message(int error_code); - - -typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); -typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); - -typedef struct Argon2_Context { - uint8_t *out; /* output array */ - uint32_t outlen; /* digest length */ - - uint8_t *pwd; /* password array */ - uint32_t pwdlen; /* password length */ - - uint8_t *salt; /* salt array */ - uint32_t saltlen; /* salt length */ - - uint8_t *secret; /* key array */ - uint32_t secretlen; /* key length */ - - uint8_t *ad; /* associated data array */ - uint32_t adlen; /* associated data length */ - - uint32_t t_cost; /* number of passes */ - uint32_t m_cost; /* amount of memory requested (KB) */ - uint32_t lanes; /* number of lanes */ - uint32_t threads; /* maximum number of threads */ - - uint32_t version; /* version number */ - - allocate_fptr allocate_cbk; /* pointer to memory allocator */ - deallocate_fptr free_cbk; /* pointer to memory deallocator */ - - uint32_t flags; /* array of bool options */ -} argon2_context; - -int argon2_ctx(argon2_context *context, argon2_type type); - -/* Error codes */ -typedef enum Argon2_ErrorCodes { - ARGON2_OK = ..., - - ARGON2_OUTPUT_PTR_NULL = ..., - - ARGON2_OUTPUT_TOO_SHORT = ..., - ARGON2_OUTPUT_TOO_LONG = ..., - - ARGON2_PWD_TOO_SHORT = ..., - ARGON2_PWD_TOO_LONG = ..., - - ARGON2_SALT_TOO_SHORT = ..., - ARGON2_SALT_TOO_LONG = ..., - - ARGON2_AD_TOO_SHORT = ..., - ARGON2_AD_TOO_LONG = ..., - - ARGON2_SECRET_TOO_SHORT = ..., - ARGON2_SECRET_TOO_LONG = ..., - - ARGON2_TIME_TOO_SMALL = ..., - ARGON2_TIME_TOO_LARGE = ..., - - ARGON2_MEMORY_TOO_LITTLE = ..., - ARGON2_MEMORY_TOO_MUCH = ..., - - ARGON2_LANES_TOO_FEW = ..., - ARGON2_LANES_TOO_MANY = ..., - - ARGON2_PWD_PTR_MISMATCH = ..., /* NULL ptr with non-zero length */ - ARGON2_SALT_PTR_MISMATCH = ..., /* NULL ptr with non-zero length */ - ARGON2_SECRET_PTR_MISMATCH = ..., /* NULL ptr with non-zero length */ - ARGON2_AD_PTR_MISMATCH = ..., /* NULL ptr with non-zero length */ - - ARGON2_MEMORY_ALLOCATION_ERROR = ..., - - ARGON2_FREE_MEMORY_CBK_NULL = ..., - ARGON2_ALLOCATE_MEMORY_CBK_NULL = ..., - - ARGON2_INCORRECT_PARAMETER = ..., - ARGON2_INCORRECT_TYPE = ..., - - ARGON2_OUT_PTR_MISMATCH = ..., - - ARGON2_THREADS_TOO_FEW = ..., - ARGON2_THREADS_TOO_MANY = ..., - - ARGON2_MISSING_ARGS = ..., - - ARGON2_ENCODING_FAIL = ..., - - ARGON2_DECODING_FAIL = ..., - - ARGON2_THREAD_FAIL = ..., - - ARGON2_DECODING_LENGTH_FAIL= ..., - - ARGON2_VERIFY_MISMATCH = ..., -} argon2_error_codes; - -#define ARGON2_FLAG_CLEAR_PASSWORD ... -#define ARGON2_FLAG_CLEAR_SECRET ... -#define ARGON2_DEFAULT_FLAGS ... - -#define ARGON2_MIN_LANES ... -#define ARGON2_MAX_LANES ... -#define ARGON2_MIN_THREADS ... -#define ARGON2_MAX_THREADS ... -#define ARGON2_SYNC_POINTS ... -#define ARGON2_MIN_OUTLEN ... -#define ARGON2_MAX_OUTLEN ... -#define ARGON2_MIN_MEMORY ... -#define ARGON2_MAX_MEMORY_BITS ... -#define ARGON2_MAX_MEMORY ... -#define ARGON2_MIN_TIME ... -#define ARGON2_MAX_TIME ... -#define ARGON2_MIN_PWD_LENGTH ... -#define ARGON2_MAX_PWD_LENGTH ... -#define ARGON2_MIN_AD_LENGTH ... -#define ARGON2_MAX_AD_LENGTH ... -#define ARGON2_MIN_SALT_LENGTH ... -#define ARGON2_MAX_SALT_LENGTH ... -#define ARGON2_MIN_SECRET ... -#define ARGON2_MAX_SECRET ... - -uint32_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, - uint32_t parallelism, uint32_t saltlen, - uint32_t hashlen, argon2_type type); - -""" -) - -if __name__ == "__main__": - ffi.compile() diff --git a/backend/venv39/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so deleted file mode 100755 index fa6a713..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/_distutils_hack/__init__.py b/backend/venv39/lib/python3.9/site-packages/_distutils_hack/__init__.py deleted file mode 100644 index 5f40996..0000000 --- a/backend/venv39/lib/python3.9/site-packages/_distutils_hack/__init__.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys -import os -import re -import importlib -import warnings - - -is_pypy = '__pypy__' in sys.builtin_module_names - - -warnings.filterwarnings('ignore', - r'.+ distutils\b.+ deprecated', - DeprecationWarning) - - -def warn_distutils_present(): - if 'distutils' not in sys.modules: - return - if is_pypy and sys.version_info < (3, 7): - # PyPy for 3.6 unconditionally imports distutils, so bypass the warning - # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 - return - warnings.warn( - "Distutils was imported before Setuptools, but importing Setuptools " - "also replaces the `distutils` module in `sys.modules`. This may lead " - "to undesirable behaviors or errors. To avoid these issues, avoid " - "using distutils directly, ensure that setuptools is installed in the " - "traditional way (e.g. not an editable install), and/or make sure " - "that setuptools is always imported before distutils.") - - -def clear_distutils(): - if 'distutils' not in sys.modules: - return - warnings.warn("Setuptools is replacing distutils.") - mods = [name for name in sys.modules if re.match(r'distutils\b', name)] - for name in mods: - del sys.modules[name] - - -def enabled(): - """ - Allow selection of distutils by environment variable. - """ - which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') - return which == 'local' - - -def ensure_local_distutils(): - clear_distutils() - distutils = importlib.import_module('setuptools._distutils') - distutils.__name__ = 'distutils' - sys.modules['distutils'] = distutils - - # sanity check that submodules load as expected - core = importlib.import_module('distutils.core') - assert '_distutils' in core.__file__, core.__file__ - - -def do_override(): - """ - Ensure that the local copy of distutils is preferred over stdlib. - - See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 - for more motivation. - """ - if enabled(): - warn_distutils_present() - ensure_local_distutils() - - -class DistutilsMetaFinder: - def find_spec(self, fullname, path, target=None): - if path is not None: - return - - method_name = 'spec_for_{fullname}'.format(**locals()) - method = getattr(self, method_name, lambda: None) - return method() - - def spec_for_distutils(self): - import importlib.abc - import importlib.util - - class DistutilsLoader(importlib.abc.Loader): - - def create_module(self, spec): - return importlib.import_module('setuptools._distutils') - - def exec_module(self, module): - pass - - return importlib.util.spec_from_loader('distutils', DistutilsLoader()) - - def spec_for_pip(self): - """ - Ensure stdlib distutils when running under pip. - See pypa/pip#8761 for rationale. - """ - if self.pip_imported_during_build(): - return - clear_distutils() - self.spec_for_distutils = lambda: None - - @staticmethod - def pip_imported_during_build(): - """ - Detect if pip is being imported in a build script. Ref #2355. - """ - import traceback - return any( - frame.f_globals['__file__'].endswith('setup.py') - for frame, line in traceback.walk_stack(None) - ) - - -DISTUTILS_FINDER = DistutilsMetaFinder() - - -def add_shim(): - sys.meta_path.insert(0, DISTUTILS_FINDER) - - -def remove_shim(): - try: - sys.meta_path.remove(DISTUTILS_FINDER) - except ValueError: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/_distutils_hack/override.py b/backend/venv39/lib/python3.9/site-packages/_distutils_hack/override.py deleted file mode 100644 index 2cc433a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/_distutils_hack/override.py +++ /dev/null @@ -1 +0,0 @@ -__import__('_distutils_hack').do_override() diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE deleted file mode 100644 index f26bcf4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE +++ /dev/null @@ -1,279 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations, which became -Zope Corporation. In 2001, the Python Software Foundation (PSF, see -https://www.python.org/psf/) was formed, a non-profit organization -created specifically to own Python-related Intellectual Property. -Zope Corporation was a sponsoring member of the PSF. - -All Python releases are Open Source (see https://opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2 and above 2.1.1 2001-now PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -Python software and documentation are licensed under the -Python Software Foundation License Version 2. - -Starting with Python 3.8.6, examples, recipes, and other code in -the documentation are dual licensed under the PSF License Version 2 -and the Zero-Clause BSD license. - -Some software incorporated into Python is under different licenses. -The licenses are listed with code falling under that license. - - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION ----------------------------------------------------------------------- - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA deleted file mode 100644 index c632040..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA +++ /dev/null @@ -1,123 +0,0 @@ -Metadata-Version: 2.3 -Name: aiohappyeyeballs -Version: 2.6.1 -Summary: Happy Eyeballs for asyncio -License: PSF-2.0 -Author: J. Nick Koston -Author-email: nick@koston.org -Requires-Python: >=3.9 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Topic :: Software Development :: Libraries -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: License :: OSI Approved :: Python Software Foundation License -Project-URL: Bug Tracker, https://github.com/aio-libs/aiohappyeyeballs/issues -Project-URL: Changelog, https://github.com/aio-libs/aiohappyeyeballs/blob/main/CHANGELOG.md -Project-URL: Documentation, https://aiohappyeyeballs.readthedocs.io -Project-URL: Repository, https://github.com/aio-libs/aiohappyeyeballs -Description-Content-Type: text/markdown - -# aiohappyeyeballs - -

- - CI Status - - - Documentation Status - - - Test coverage percentage - -

-

- - Poetry - - - Ruff - - - pre-commit - -

-

- - PyPI Version - - Supported Python versions - License -

- ---- - -**Documentation**: https://aiohappyeyeballs.readthedocs.io - -**Source Code**: https://github.com/aio-libs/aiohappyeyeballs - ---- - -[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) -([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) - -## Use case - -This library exists to allow connecting with -[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) -([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) -when you -already have a list of addrinfo and not a DNS name. - -The stdlib version of `loop.create_connection()` -will only work when you pass in an unresolved name which -is not a good fit when using DNS caching or resolving -names via another method such as `zeroconf`. - -## Installation - -Install this via pip (or your favourite package manager): - -`pip install aiohappyeyeballs` - -## License - -[aiohappyeyeballs is licensed under the same terms as cpython itself.](https://github.com/python/cpython/blob/main/LICENSE) - -## Example usage - -```python - -addr_infos = await loop.getaddrinfo("example.org", 80) - -socket = await start_connection(addr_infos) -socket = await start_connection(addr_infos, local_addr_infos=local_addr_infos, happy_eyeballs_delay=0.2) - -transport, protocol = await loop.create_connection( - MyProtocol, sock=socket, ...) - -# Remove the first address for each family from addr_info -pop_addr_infos_interleave(addr_info, 1) - -# Remove all matching address from addr_info -remove_addr_infos(addr_info, "dead::beef::") - -# Convert a local_addr to local_addr_infos -local_addr_infos = addr_to_addr_infos(("127.0.0.1",0)) -``` - -## Credits - -This package contains code from cpython and is licensed under the same terms as cpython itself. - -This package was created with -[Copier](https://copier.readthedocs.io/) and the -[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template) -project template. - diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD deleted file mode 100644 index 5e900d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD +++ /dev/null @@ -1,16 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/impl.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/utils.cpython-39.pyc,, -aiohappyeyeballs-2.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiohappyeyeballs-2.6.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 -aiohappyeyeballs-2.6.1.dist-info/METADATA,sha256=NSXlhJwAfi380eEjAo7BQ4P_TVal9xi0qkyZWibMsVM,5915 -aiohappyeyeballs-2.6.1.dist-info/RECORD,, -aiohappyeyeballs-2.6.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88 -aiohappyeyeballs/__init__.py,sha256=x7kktHEtaD9quBcWDJPuLeKyjuVAI-Jj14S9B_5hcTs,361 -aiohappyeyeballs/_staggered.py,sha256=edfVowFx-P-ywJjIEF3MdPtEMVODujV6CeMYr65otac,6900 -aiohappyeyeballs/impl.py,sha256=Dlcm2mTJ28ucrGnxkb_fo9CZzLAkOOBizOt7dreBbXE,9681 -aiohappyeyeballs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -aiohappyeyeballs/types.py,sha256=YZJIAnyoV4Dz0WFtlaf_OyE4EW7Xus1z7aIfNI6tDDQ,425 -aiohappyeyeballs/utils.py,sha256=on9GxIR0LhEfZu8P6Twi9hepX9zDanuZM20MWsb3xlQ,3028 diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL deleted file mode 100644 index 0582547..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: poetry-core 2.1.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py deleted file mode 100644 index 71c689c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -__version__ = "2.6.1" - -from .impl import start_connection -from .types import AddrInfoType, SocketFactoryType -from .utils import addr_to_addr_infos, pop_addr_infos_interleave, remove_addr_infos - -__all__ = ( - "AddrInfoType", - "SocketFactoryType", - "addr_to_addr_infos", - "pop_addr_infos_interleave", - "remove_addr_infos", - "start_connection", -) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py deleted file mode 100644 index 9a4ba72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/_staggered.py +++ /dev/null @@ -1,207 +0,0 @@ -import asyncio -import contextlib - -# PY3.9: Import Callable from typing until we drop Python 3.9 support -# https://github.com/python/cpython/issues/87131 -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - List, - Optional, - Set, - Tuple, - TypeVar, - Union, -) - -_T = TypeVar("_T") - -RE_RAISE_EXCEPTIONS = (SystemExit, KeyboardInterrupt) - - -def _set_result(wait_next: "asyncio.Future[None]") -> None: - """Set the result of a future if it is not already done.""" - if not wait_next.done(): - wait_next.set_result(None) - - -async def _wait_one( - futures: "Iterable[asyncio.Future[Any]]", - loop: asyncio.AbstractEventLoop, -) -> _T: - """Wait for the first future to complete.""" - wait_next = loop.create_future() - - def _on_completion(fut: "asyncio.Future[Any]") -> None: - if not wait_next.done(): - wait_next.set_result(fut) - - for f in futures: - f.add_done_callback(_on_completion) - - try: - return await wait_next - finally: - for f in futures: - f.remove_done_callback(_on_completion) - - -async def staggered_race( - coro_fns: Iterable[Callable[[], Awaitable[_T]]], - delay: Optional[float], - *, - loop: Optional[asyncio.AbstractEventLoop] = None, -) -> Tuple[Optional[_T], Optional[int], List[Optional[BaseException]]]: - """ - Run coroutines with staggered start times and take the first to finish. - - This method takes an iterable of coroutine functions. The first one is - started immediately. From then on, whenever the immediately preceding one - fails (raises an exception), or when *delay* seconds has passed, the next - coroutine is started. This continues until one of the coroutines complete - successfully, in which case all others are cancelled, or until all - coroutines fail. - - The coroutines provided should be well-behaved in the following way: - - * They should only ``return`` if completed successfully. - - * They should always raise an exception if they did not complete - successfully. In particular, if they handle cancellation, they should - probably reraise, like this:: - - try: - # do work - except asyncio.CancelledError: - # undo partially completed work - raise - - Args: - ---- - coro_fns: an iterable of coroutine functions, i.e. callables that - return a coroutine object when called. Use ``functools.partial`` or - lambdas to pass arguments. - - delay: amount of time, in seconds, between starting coroutines. If - ``None``, the coroutines will run sequentially. - - loop: the event loop to use. If ``None``, the running loop is used. - - Returns: - ------- - tuple *(winner_result, winner_index, exceptions)* where - - - *winner_result*: the result of the winning coroutine, or ``None`` - if no coroutines won. - - - *winner_index*: the index of the winning coroutine in - ``coro_fns``, or ``None`` if no coroutines won. If the winning - coroutine may return None on success, *winner_index* can be used - to definitively determine whether any coroutine won. - - - *exceptions*: list of exceptions returned by the coroutines. - ``len(exceptions)`` is equal to the number of coroutines actually - started, and the order is the same as in ``coro_fns``. The winning - coroutine's entry is ``None``. - - """ - loop = loop or asyncio.get_running_loop() - exceptions: List[Optional[BaseException]] = [] - tasks: Set[asyncio.Task[Optional[Tuple[_T, int]]]] = set() - - async def run_one_coro( - coro_fn: Callable[[], Awaitable[_T]], - this_index: int, - start_next: "asyncio.Future[None]", - ) -> Optional[Tuple[_T, int]]: - """ - Run a single coroutine. - - If the coroutine fails, set the exception in the exceptions list and - start the next coroutine by setting the result of the start_next. - - If the coroutine succeeds, return the result and the index of the - coroutine in the coro_fns list. - - If SystemExit or KeyboardInterrupt is raised, re-raise it. - """ - try: - result = await coro_fn() - except RE_RAISE_EXCEPTIONS: - raise - except BaseException as e: - exceptions[this_index] = e - _set_result(start_next) # Kickstart the next coroutine - return None - - return result, this_index - - start_next_timer: Optional[asyncio.TimerHandle] = None - start_next: Optional[asyncio.Future[None]] - task: asyncio.Task[Optional[Tuple[_T, int]]] - done: Union[asyncio.Future[None], asyncio.Task[Optional[Tuple[_T, int]]]] - coro_iter = iter(coro_fns) - this_index = -1 - try: - while True: - if coro_fn := next(coro_iter, None): - this_index += 1 - exceptions.append(None) - start_next = loop.create_future() - task = loop.create_task(run_one_coro(coro_fn, this_index, start_next)) - tasks.add(task) - start_next_timer = ( - loop.call_later(delay, _set_result, start_next) if delay else None - ) - elif not tasks: - # We exhausted the coro_fns list and no tasks are running - # so we have no winner and all coroutines failed. - break - - while tasks or start_next: - done = await _wait_one( - (*tasks, start_next) if start_next else tasks, loop - ) - if done is start_next: - # The current task has failed or the timer has expired - # so we need to start the next task. - start_next = None - if start_next_timer: - start_next_timer.cancel() - start_next_timer = None - - # Break out of the task waiting loop to start the next - # task. - break - - if TYPE_CHECKING: - assert isinstance(done, asyncio.Task) - - tasks.remove(done) - if winner := done.result(): - return *winner, exceptions - finally: - # We either have: - # - a winner - # - all tasks failed - # - a KeyboardInterrupt or SystemExit. - - # - # If the timer is still running, cancel it. - # - if start_next_timer: - start_next_timer.cancel() - - # - # If there are any tasks left, cancel them and than - # wait them so they fill the exceptions list. - # - for task in tasks: - task.cancel() - with contextlib.suppress(asyncio.CancelledError): - await task - - return None, None, exceptions diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/impl.py b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/impl.py deleted file mode 100644 index 8f3919a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/impl.py +++ /dev/null @@ -1,259 +0,0 @@ -"""Base implementation.""" - -import asyncio -import collections -import contextlib -import functools -import itertools -import socket -from typing import List, Optional, Sequence, Set, Union - -from . import _staggered -from .types import AddrInfoType, SocketFactoryType - - -async def start_connection( - addr_infos: Sequence[AddrInfoType], - *, - local_addr_infos: Optional[Sequence[AddrInfoType]] = None, - happy_eyeballs_delay: Optional[float] = None, - interleave: Optional[int] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - socket_factory: Optional[SocketFactoryType] = None, -) -> socket.socket: - """ - Connect to a TCP server. - - Create a socket connection to a specified destination. The - destination is specified as a list of AddrInfoType tuples as - returned from getaddrinfo(). - - The arguments are, in order: - - * ``family``: the address family, e.g. ``socket.AF_INET`` or - ``socket.AF_INET6``. - * ``type``: the socket type, e.g. ``socket.SOCK_STREAM`` or - ``socket.SOCK_DGRAM``. - * ``proto``: the protocol, e.g. ``socket.IPPROTO_TCP`` or - ``socket.IPPROTO_UDP``. - * ``canonname``: the canonical name of the address, e.g. - ``"www.python.org"``. - * ``sockaddr``: the socket address - - This method is a coroutine which will try to establish the connection - in the background. When successful, the coroutine returns a - socket. - - The expected use case is to use this method in conjunction with - loop.create_connection() to establish a connection to a server:: - - socket = await start_connection(addr_infos) - transport, protocol = await loop.create_connection( - MyProtocol, sock=socket, ...) - """ - if not (current_loop := loop): - current_loop = asyncio.get_running_loop() - - single_addr_info = len(addr_infos) == 1 - - if happy_eyeballs_delay is not None and interleave is None: - # If using happy eyeballs, default to interleave addresses by family - interleave = 1 - - if interleave and not single_addr_info: - addr_infos = _interleave_addrinfos(addr_infos, interleave) - - sock: Optional[socket.socket] = None - # uvloop can raise RuntimeError instead of OSError - exceptions: List[List[Union[OSError, RuntimeError]]] = [] - if happy_eyeballs_delay is None or single_addr_info: - # not using happy eyeballs - for addrinfo in addr_infos: - try: - sock = await _connect_sock( - current_loop, - exceptions, - addrinfo, - local_addr_infos, - None, - socket_factory, - ) - break - except (RuntimeError, OSError): - continue - else: # using happy eyeballs - open_sockets: Set[socket.socket] = set() - try: - sock, _, _ = await _staggered.staggered_race( - ( - functools.partial( - _connect_sock, - current_loop, - exceptions, - addrinfo, - local_addr_infos, - open_sockets, - socket_factory, - ) - for addrinfo in addr_infos - ), - happy_eyeballs_delay, - ) - finally: - # If we have a winner, staggered_race will - # cancel the other tasks, however there is a - # small race window where any of the other tasks - # can be done before they are cancelled which - # will leave the socket open. To avoid this problem - # we pass a set to _connect_sock to keep track of - # the open sockets and close them here if there - # are any "runner up" sockets. - for s in open_sockets: - if s is not sock: - with contextlib.suppress(OSError): - s.close() - open_sockets = None # type: ignore[assignment] - - if sock is None: - all_exceptions = [exc for sub in exceptions for exc in sub] - try: - first_exception = all_exceptions[0] - if len(all_exceptions) == 1: - raise first_exception - else: - # If they all have the same str(), raise one. - model = str(first_exception) - if all(str(exc) == model for exc in all_exceptions): - raise first_exception - # Raise a combined exception so the user can see all - # the various error messages. - msg = "Multiple exceptions: {}".format( - ", ".join(str(exc) for exc in all_exceptions) - ) - # If the errno is the same for all exceptions, raise - # an OSError with that errno. - if isinstance(first_exception, OSError): - first_errno = first_exception.errno - if all( - isinstance(exc, OSError) and exc.errno == first_errno - for exc in all_exceptions - ): - raise OSError(first_errno, msg) - elif isinstance(first_exception, RuntimeError) and all( - isinstance(exc, RuntimeError) for exc in all_exceptions - ): - raise RuntimeError(msg) - # We have a mix of OSError and RuntimeError - # so we have to pick which one to raise. - # and we raise OSError for compatibility - raise OSError(msg) - finally: - all_exceptions = None # type: ignore[assignment] - exceptions = None # type: ignore[assignment] - - return sock - - -async def _connect_sock( - loop: asyncio.AbstractEventLoop, - exceptions: List[List[Union[OSError, RuntimeError]]], - addr_info: AddrInfoType, - local_addr_infos: Optional[Sequence[AddrInfoType]] = None, - open_sockets: Optional[Set[socket.socket]] = None, - socket_factory: Optional[SocketFactoryType] = None, -) -> socket.socket: - """ - Create, bind and connect one socket. - - If open_sockets is passed, add the socket to the set of open sockets. - Any failure caught here will remove the socket from the set and close it. - - Callers can use this set to close any sockets that are not the winner - of all staggered tasks in the result there are runner up sockets aka - multiple winners. - """ - my_exceptions: List[Union[OSError, RuntimeError]] = [] - exceptions.append(my_exceptions) - family, type_, proto, _, address = addr_info - sock = None - try: - if socket_factory is not None: - sock = socket_factory(addr_info) - else: - sock = socket.socket(family=family, type=type_, proto=proto) - if open_sockets is not None: - open_sockets.add(sock) - sock.setblocking(False) - if local_addr_infos is not None: - for lfamily, _, _, _, laddr in local_addr_infos: - # skip local addresses of different family - if lfamily != family: - continue - try: - sock.bind(laddr) - break - except OSError as exc: - msg = ( - f"error while attempting to bind on " - f"address {laddr!r}: " - f"{(exc.strerror or '').lower()}" - ) - exc = OSError(exc.errno, msg) - my_exceptions.append(exc) - else: # all bind attempts failed - if my_exceptions: - raise my_exceptions.pop() - else: - raise OSError(f"no matching local address with {family=} found") - await loop.sock_connect(sock, address) - return sock - except (RuntimeError, OSError) as exc: - my_exceptions.append(exc) - if sock is not None: - if open_sockets is not None: - open_sockets.remove(sock) - try: - sock.close() - except OSError as e: - my_exceptions.append(e) - raise - raise - except: - if sock is not None: - if open_sockets is not None: - open_sockets.remove(sock) - try: - sock.close() - except OSError as e: - my_exceptions.append(e) - raise - raise - finally: - exceptions = my_exceptions = None # type: ignore[assignment] - - -def _interleave_addrinfos( - addrinfos: Sequence[AddrInfoType], first_address_family_count: int = 1 -) -> List[AddrInfoType]: - """Interleave list of addrinfo tuples by family.""" - # Group addresses by family - addrinfos_by_family: collections.OrderedDict[int, List[AddrInfoType]] = ( - collections.OrderedDict() - ) - for addr in addrinfos: - family = addr[0] - if family not in addrinfos_by_family: - addrinfos_by_family[family] = [] - addrinfos_by_family[family].append(addr) - addrinfos_lists = list(addrinfos_by_family.values()) - - reordered: List[AddrInfoType] = [] - if first_address_family_count > 1: - reordered.extend(addrinfos_lists[0][: first_address_family_count - 1]) - del addrinfos_lists[0][: first_address_family_count - 1] - reordered.extend( - a - for a in itertools.chain.from_iterable(itertools.zip_longest(*addrinfos_lists)) - if a is not None - ) - return reordered diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/py.typed b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/types.py b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/types.py deleted file mode 100644 index e8c7507..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/types.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Types for aiohappyeyeballs.""" - -import socket - -# PY3.9: Import Callable from typing until we drop Python 3.9 support -# https://github.com/python/cpython/issues/87131 -from typing import Callable, Tuple, Union - -AddrInfoType = Tuple[ - Union[int, socket.AddressFamily], - Union[int, socket.SocketKind], - int, - str, - Tuple, # type: ignore[type-arg] -] - -SocketFactoryType = Callable[[AddrInfoType], socket.socket] diff --git a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/utils.py b/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/utils.py deleted file mode 100644 index ea29adb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohappyeyeballs/utils.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Utility functions for aiohappyeyeballs.""" - -import ipaddress -import socket -from typing import Dict, List, Optional, Tuple, Union - -from .types import AddrInfoType - - -def addr_to_addr_infos( - addr: Optional[ - Union[Tuple[str, int, int, int], Tuple[str, int, int], Tuple[str, int]] - ], -) -> Optional[List[AddrInfoType]]: - """Convert an address tuple to a list of addr_info tuples.""" - if addr is None: - return None - host = addr[0] - port = addr[1] - is_ipv6 = ":" in host - if is_ipv6: - flowinfo = 0 - scopeid = 0 - addr_len = len(addr) - if addr_len >= 4: - scopeid = addr[3] # type: ignore[misc] - if addr_len >= 3: - flowinfo = addr[2] # type: ignore[misc] - addr = (host, port, flowinfo, scopeid) - family = socket.AF_INET6 - else: - addr = (host, port) - family = socket.AF_INET - return [(family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr)] - - -def pop_addr_infos_interleave( - addr_infos: List[AddrInfoType], interleave: Optional[int] = None -) -> None: - """ - Pop addr_info from the list of addr_infos by family up to interleave times. - - The interleave parameter is used to know how many addr_infos for - each family should be popped of the top of the list. - """ - seen: Dict[int, int] = {} - if interleave is None: - interleave = 1 - to_remove: List[AddrInfoType] = [] - for addr_info in addr_infos: - family = addr_info[0] - if family not in seen: - seen[family] = 0 - if seen[family] < interleave: - to_remove.append(addr_info) - seen[family] += 1 - for addr_info in to_remove: - addr_infos.remove(addr_info) - - -def _addr_tuple_to_ip_address( - addr: Union[Tuple[str, int], Tuple[str, int, int, int]], -) -> Union[ - Tuple[ipaddress.IPv4Address, int], Tuple[ipaddress.IPv6Address, int, int, int] -]: - """Convert an address tuple to an IPv4Address.""" - return (ipaddress.ip_address(addr[0]), *addr[1:]) - - -def remove_addr_infos( - addr_infos: List[AddrInfoType], - addr: Union[Tuple[str, int], Tuple[str, int, int, int]], -) -> None: - """ - Remove an address from the list of addr_infos. - - The addr value is typically the return value of - sock.getpeername(). - """ - bad_addrs_infos: List[AddrInfoType] = [] - for addr_info in addr_infos: - if addr_info[-1] == addr: - bad_addrs_infos.append(addr_info) - if bad_addrs_infos: - for bad_addr_info in bad_addrs_infos: - addr_infos.remove(bad_addr_info) - return - # Slow path in case addr is formatted differently - match_addr = _addr_tuple_to_ip_address(addr) - for addr_info in addr_infos: - if match_addr == _addr_tuple_to_ip_address(addr_info[-1]): - bad_addrs_infos.append(addr_info) - if bad_addrs_infos: - for bad_addr_info in bad_addrs_infos: - addr_infos.remove(bad_addr_info) - return - raise ValueError(f"Address {addr} not found in addr_infos") diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/METADATA deleted file mode 100644 index 078765d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/METADATA +++ /dev/null @@ -1,262 +0,0 @@ -Metadata-Version: 2.4 -Name: aiohttp -Version: 3.13.3 -Summary: Async http client/server framework (asyncio) -Maintainer-email: aiohttp team -License: Apache-2.0 AND MIT -Project-URL: Homepage, https://github.com/aio-libs/aiohttp -Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org -Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiohttp -Project-URL: Docs: Changelog, https://docs.aiohttp.org/en/stable/changes.html -Project-URL: Docs: RTD, https://docs.aiohttp.org -Project-URL: GitHub: issues, https://github.com/aio-libs/aiohttp/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/aiohttp -Classifier: Development Status :: 5 - Production/Stable -Classifier: Framework :: AsyncIO -Classifier: Intended Audience :: Developers -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE.txt -License-File: vendor/llhttp/LICENSE -Requires-Dist: aiohappyeyeballs>=2.5.0 -Requires-Dist: aiosignal>=1.4.0 -Requires-Dist: async-timeout<6.0,>=4.0; python_version < "3.11" -Requires-Dist: attrs>=17.3.0 -Requires-Dist: frozenlist>=1.1.1 -Requires-Dist: multidict<7.0,>=4.5 -Requires-Dist: propcache>=0.2.0 -Requires-Dist: yarl<2.0,>=1.17.0 -Provides-Extra: speedups -Requires-Dist: aiodns>=3.3.0; extra == "speedups" -Requires-Dist: Brotli>=1.2; platform_python_implementation == "CPython" and extra == "speedups" -Requires-Dist: brotlicffi>=1.2; platform_python_implementation != "CPython" and extra == "speedups" -Requires-Dist: backports.zstd; (platform_python_implementation == "CPython" and python_version < "3.14") and extra == "speedups" -Dynamic: license-file - -================================== -Async http client/server framework -================================== - -.. image:: https://raw.githubusercontent.com/aio-libs/aiohttp/master/docs/aiohttp-plain.svg - :height: 64px - :width: 64px - :alt: aiohttp logo - -| - -.. image:: https://github.com/aio-libs/aiohttp/workflows/CI/badge.svg - :target: https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI - :alt: GitHub Actions status for master branch - -.. image:: https://codecov.io/gh/aio-libs/aiohttp/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aiohttp - :alt: codecov.io status for master branch - -.. image:: https://badge.fury.io/py/aiohttp.svg - :target: https://pypi.org/project/aiohttp - :alt: Latest PyPI package version - -.. image:: https://img.shields.io/pypi/dm/aiohttp - :target: https://pypistats.org/packages/aiohttp - :alt: Downloads count - -.. image:: https://readthedocs.org/projects/aiohttp/badge/?version=latest - :target: https://docs.aiohttp.org/ - :alt: Latest Read The Docs - -.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json - :target: https://codspeed.io/aio-libs/aiohttp - :alt: Codspeed.io status for aiohttp - - -Key Features -============ - -- Supports both client and server side of HTTP protocol. -- Supports both client and server Web-Sockets out-of-the-box and avoids - Callback Hell. -- Provides Web-server with middleware and pluggable routing. - - -Getting started -=============== - -Client ------- - -To get something from the web: - -.. code-block:: python - - import aiohttp - import asyncio - - async def main(): - - async with aiohttp.ClientSession() as session: - async with session.get('http://python.org') as response: - - print("Status:", response.status) - print("Content-type:", response.headers['content-type']) - - html = await response.text() - print("Body:", html[:15], "...") - - asyncio.run(main()) - -This prints: - -.. code-block:: - - Status: 200 - Content-type: text/html; charset=utf-8 - Body: ... - -Coming from `requests `_ ? Read `why we need so many lines `_. - -Server ------- - -An example using a simple server: - -.. code-block:: python - - # examples/server_simple.py - from aiohttp import web - - async def handle(request): - name = request.match_info.get('name', "Anonymous") - text = "Hello, " + name - return web.Response(text=text) - - async def wshandle(request): - ws = web.WebSocketResponse() - await ws.prepare(request) - - async for msg in ws: - if msg.type == web.WSMsgType.text: - await ws.send_str("Hello, {}".format(msg.data)) - elif msg.type == web.WSMsgType.binary: - await ws.send_bytes(msg.data) - elif msg.type == web.WSMsgType.close: - break - - return ws - - - app = web.Application() - app.add_routes([web.get('/', handle), - web.get('/echo', wshandle), - web.get('/{name}', handle)]) - - if __name__ == '__main__': - web.run_app(app) - - -Documentation -============= - -https://aiohttp.readthedocs.io/ - - -Demos -===== - -https://github.com/aio-libs/aiohttp-demos - - -External links -============== - -* `Third party libraries - `_ -* `Built with aiohttp - `_ -* `Powered by aiohttp - `_ - -Feel free to make a Pull Request for adding your link to these pages! - - -Communication channels -====================== - -*aio-libs Discussions*: https://github.com/aio-libs/aiohttp/discussions - -*Matrix*: `#aio-libs:matrix.org `_ - -We support `Stack Overflow -`_. -Please add *aiohttp* tag to your question there. - -Requirements -============ - -- attrs_ -- multidict_ -- yarl_ -- frozenlist_ - -Optionally you may install the aiodns_ library (highly recommended for sake of speed). - -.. _aiodns: https://pypi.python.org/pypi/aiodns -.. _attrs: https://github.com/python-attrs/attrs -.. _multidict: https://pypi.python.org/pypi/multidict -.. _frozenlist: https://pypi.org/project/frozenlist/ -.. _yarl: https://pypi.python.org/pypi/yarl -.. _async-timeout: https://pypi.python.org/pypi/async_timeout - -License -======= - -``aiohttp`` is offered under the Apache 2 license. - - -Keepsafe -======== - -The aiohttp community would like to thank Keepsafe -(https://www.getkeepsafe.com) for its support in the early days of -the project. - - -Source code -=========== - -The latest developer version is available in a GitHub repository: -https://github.com/aio-libs/aiohttp - -Benchmarks -========== - -If you are interested in efficiency, the AsyncIO community maintains a -list of benchmarks on the official wiki: -https://github.com/python/asyncio/wiki/Benchmarks - --------- - -.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs:matrix.org - :alt: Matrix Room — #aio-libs:matrix.org - -.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs-space:matrix.org - :alt: Matrix Space — #aio-libs-space:matrix.org - -.. image:: https://insights.linuxfoundation.org/api/badge/health-score?project=aiohttp - :target: https://insights.linuxfoundation.org/project/aiohttp - :alt: LFX Health Score diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/RECORD deleted file mode 100644 index bdbd61e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/RECORD +++ /dev/null @@ -1,139 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_cookie_helpers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/helpers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/writer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/abc.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/base_protocol.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middlewares.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_proto.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_reqrep.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/client_ws.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/compression_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/connector.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/cookiejar.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/formdata.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/hdrs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/helpers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/http.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/http_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/http_parser.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/http_websocket.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/http_writer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/log.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/multipart.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/payload.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/payload_streamer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/pytest_plugin.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/resolver.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/streams.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/tcp_helpers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/test_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/tracing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/typedefs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_app.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_fileresponse.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_log.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_middlewares.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_protocol.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_request.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_routedef.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_runner.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_server.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_urldispatcher.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/web_ws.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiohttp/worker.cpython-39.pyc,, -aiohttp-3.13.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiohttp-3.13.3.dist-info/METADATA,sha256=CQROZCStho-eb7xiFIuAzj30JuupEU_jHpYDFiG_HhM,8145 -aiohttp-3.13.3.dist-info/RECORD,, -aiohttp-3.13.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -aiohttp-3.13.3.dist-info/WHEEL,sha256=bDWaFWigpG5bEpqw9IoRiyYs8MvmSFh0OhUAOoi_-KA,134 -aiohttp-3.13.3.dist-info/licenses/LICENSE.txt,sha256=n4DQ2311WpQdtFchcsJw7L2PCCuiFd3QlZhZQu2Uqes,588 -aiohttp-3.13.3.dist-info/licenses/vendor/llhttp/LICENSE,sha256=68qFTgE0zSVtZzYnwgSZ9CV363S6zwi58ltianPJEnc,1105 -aiohttp-3.13.3.dist-info/top_level.txt,sha256=iv-JIaacmTl-hSho3QmphcKnbRRYx1st47yjz_178Ro,8 -aiohttp/.hash/_cparser.pxd.hash,sha256=oIlezvoJGZE6-ZImy9DWJWJ9jmK4nobbsaEmkgwBkoQ,122 -aiohttp/.hash/_find_header.pxd.hash,sha256=e5PYiyDzMXiyZFd4-ALGxEv49PjPhij4cOmV12aVFxQ,126 -aiohttp/.hash/_http_parser.pyx.hash,sha256=uMWsp5Xf15lLOYGEo4_PqBTD36LVhFNCWZo-w6gQieo,126 -aiohttp/.hash/_http_writer.pyx.hash,sha256=MboJpn5z8wdmkkOhQ70m726h2Ddc9N1uep6wI4MG3kI,126 -aiohttp/.hash/hdrs.py.hash,sha256=1gLWu377IP_KPjc8HykpPdBQiMz2hKNE9YumrEChURQ,117 -aiohttp/__init__.py,sha256=QWssFaD-DaFFcwP36lLUQzRmlSZ5KxivJBU-yg5C1wg,8302 -aiohttp/_cookie_helpers.py,sha256=_p7y-B8OCAk7FLjByiuwFIpDLGuNoJn3_vixzymAFnE,13659 -aiohttp/_cparser.pxd,sha256=UnbUYCHg4NdXfgyRVYAMv2KTLWClB4P-xCrvtj_r7ew,4295 -aiohttp/_find_header.pxd,sha256=0GfwFCPN2zxEKTO1_MA5sYq2UfzsG8kcV3aTqvwlz3g,68 -aiohttp/_headers.pxi,sha256=n701k28dVPjwRnx5j6LpJhLTfj7dqu2vJt7f0O60Oyg,2007 -aiohttp/_http_parser.cpython-39-darwin.so,sha256=MUt7lBJ7X79iRS7avX4AA8MolMX87klr861pGANUHrU,435440 -aiohttp/_http_parser.pyx,sha256=-YI8YIY4uKd_7Bwr0o3FwEPwjHdexZ5-Ji3XS067c4Q,28261 -aiohttp/_http_writer.cpython-39-darwin.so,sha256=pMD8ovoirvfunOoy-5T8s3PL3atlQSWMc2sylO2Vt1Q,92416 -aiohttp/_http_writer.pyx,sha256=VlFEBM6HoVv8a0AAJtc6JwFlsv2-cDE8-gB94p3dfhQ,4664 -aiohttp/_websocket/.hash/mask.pxd.hash,sha256=ebMpBz5iaBd0tWsl9uYmnJXclUn2ZLaM1HImB0y86MQ,129 -aiohttp/_websocket/.hash/mask.pyx.hash,sha256=Td1g3PCFM0DQsJEXruY4pygFu0ScpCxKmncwQFpaStk,129 -aiohttp/_websocket/.hash/reader_c.pxd.hash,sha256=pTDxd9-I400MmfeI7xdZ26wyS3KztJHZtChc3hCklVc,133 -aiohttp/_websocket/__init__.py,sha256=Mar3R9_vBN_Ea4lsW7iTAVXD7OKswKPGqF5xgSyt77k,44 -aiohttp/_websocket/helpers.py,sha256=P-XLv8IUaihKzDenVUqfKU5DJbWE5HvG8uhvUZK8Ic4,5038 -aiohttp/_websocket/mask.cpython-39-darwin.so,sha256=gTWzkROlNdg5_RN3HMg7p_O0Y6AgQTxioT1YphAOMQw,85880 -aiohttp/_websocket/mask.pxd,sha256=sBmZ1Amym9kW4Ge8lj1fLZ7mPPya4LzLdpkQExQXv5M,112 -aiohttp/_websocket/mask.pyx,sha256=BHjOtV0O0w7xp9p0LNADRJvGmgfPn9sGeJvSs0fL__4,1397 -aiohttp/_websocket/models.py,sha256=XAzjs_8JYszWXIgZ6R3ZRrF-tX9Q_6LiD49WRYojopM,2121 -aiohttp/_websocket/reader.py,sha256=eC4qS0c5sOeQ2ebAHLaBpIaTVFaSKX79pY2xvh3Pqyw,1030 -aiohttp/_websocket/reader_c.cpython-39-darwin.so,sha256=5sh5m6mdKbC0PIF3CNXlWz99VUJQQwS_o_B3FvJXD5s,256144 -aiohttp/_websocket/reader_c.pxd,sha256=nl_njtDrzlQU0rjgGGjZDB-swguE0tX_bCPobkShVa4,2625 -aiohttp/_websocket/reader_c.py,sha256=V5YtZ2gj2BjE2Q-W9sR_MdAl1VAm1pB7ZjozVJcOpbg,18868 -aiohttp/_websocket/reader_py.py,sha256=V5YtZ2gj2BjE2Q-W9sR_MdAl1VAm1pB7ZjozVJcOpbg,18868 -aiohttp/_websocket/writer.py,sha256=2OvSktPmNh_g20h1cXJt2Xu8u6IvswnPjdur7OwBbJk,11261 -aiohttp/abc.py,sha256=M66F4S6m00bIEn7y4ha_XLTMDmVQ9dPihfOVB0pGfOo,7149 -aiohttp/base_protocol.py,sha256=Tp8cxUPQvv9kUPk3w6lAzk6d2MAzV3scwI_3Go3C47c,3025 -aiohttp/client.py,sha256=fOQfwcIUL1NGAVRV4DDj6-wipBzeD8KZpmzhO-LLKp4,58357 -aiohttp/client_exceptions.py,sha256=uyKbxI2peZhKl7lELBMx3UeusNkfpemPWpGFq0r6JeM,11367 -aiohttp/client_middleware_digest_auth.py,sha256=G5JM9YtzL9AWklz6NP28xEOBeAvrAZgDzU657JqO4qs,17627 -aiohttp/client_middlewares.py,sha256=kP5N9CMzQPMGPIEydeVUiLUTLsw8Vl8Gr4qAWYdu3vM,1918 -aiohttp/client_proto.py,sha256=56_WtLStZGBFPYKzgEgY6v24JkhV1y6JEmmuxeJT2So,12110 -aiohttp/client_reqrep.py,sha256=eEREDrZ0M8ZFTt1wjHduR-P8_sm40K65gNz-iMGYask,53391 -aiohttp/client_ws.py,sha256=1CIjIXwyzOMIYw6AjUES4-qUwbyVHW1seJKQfg_Rta8,15109 -aiohttp/compression_utils.py,sha256=hJ2LXhN2OWukFHm5b78TJFGKcAiL2kthi9Sf5PRYO-U,11738 -aiohttp/connector.py,sha256=vT22BNuCDtbadE1Uq7HC7zpOWCHMxI4n3PtCz7zZZkw,69004 -aiohttp/cookiejar.py,sha256=e28ZMQwJ5P0vbPX1OX4Se7-k3zeGvocFEqzGhwpG53k,18922 -aiohttp/formdata.py,sha256=xqYMbUo1qoLYPuzY92XeR4pyEe-w-DNcToARDF3GUhA,6384 -aiohttp/hdrs.py,sha256=2rj5MyA-6yRdYPhW5UKkW4iNWhEAlGIOSBH5D4FmKNE,5111 -aiohttp/helpers.py,sha256=Q1307PCEnWz4RP8crUw8dk58c0YF2Ei3JywkKfRxz5E,30629 -aiohttp/http.py,sha256=8o8j8xH70OWjnfTWA9V44NR785QPxEPrUtzMXiAVpwc,1842 -aiohttp/http_exceptions.py,sha256=BjIxD4LtrQgytqoR5lOI9zAttNmSygRgksUsMRy7sss,3069 -aiohttp/http_parser.py,sha256=z6djZDOUs7hdPzplTEsAVyz0of-rQAwT7xz8OpXhnuY,38177 -aiohttp/http_websocket.py,sha256=8VXFKw6KQUEmPg48GtRMB37v0gTK7A0inoxXuDxMZEc,842 -aiohttp/http_writer.py,sha256=fbRtKPYSqRbtAdr_gqpjF2-4sI1ESL8dPDF-xY_mAMY,12446 -aiohttp/log.py,sha256=BbNKx9e3VMIm0xYjZI0IcBBoS7wjdeIeSaiJE7-qK2g,325 -aiohttp/multipart.py,sha256=326npYdWxYI3raoRfmpBeUV_ef3-LRn8sV9WqcIOoPk,40482 -aiohttp/payload.py,sha256=O6nsYNULL7AeM2cyJ6TYX73ncVnL5xJwt5AegxwMKqw,40874 -aiohttp/payload_streamer.py,sha256=ZzEYyfzcjGWkVkK3XR2pBthSCSIykYvY3Wr5cGQ2eTc,2211 -aiohttp/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 -aiohttp/pytest_plugin.py,sha256=z4XwqmsKdyJCKxbGiA5kFf90zcedvomqk4RqjZbhKNk,12901 -aiohttp/resolver.py,sha256=gsrfUpFf8iHlcHfJvY-1fiBHW3PRvRVNb5lNZBg3zlY,10031 -aiohttp/streams.py,sha256=rlwL7ek6CkMMYil_e_EokWv26uHmtzi3lKqlnLNrXCc,23666 -aiohttp/tcp_helpers.py,sha256=BSadqVWaBpMFDRWnhaaR941N9MiDZ7bdTrxgCb0CW-M,961 -aiohttp/test_utils.py,sha256=ZJSzZWjC76KSbtwddTKcP6vHpUl_ozfAf3F93ewmHRU,23016 -aiohttp/tracing.py,sha256=-6aaW6l0J9uJD45LzR4cijYH0j62pt0U_nn_aVzFku4,14558 -aiohttp/typedefs.py,sha256=wUlqwe9Mw9W8jT3HsYJcYk00qP3EMPz3nTkYXmeNN48,1657 -aiohttp/web.py,sha256=JzSNmejg5G6YeFAnkIgZfytqbU86sNu844yYKmoUpqs,17852 -aiohttp/web_app.py,sha256=lGU_aAMN-h3wy-LTTHi6SeKH8ydt1G51BXcCspgD5ZA,19452 -aiohttp/web_exceptions.py,sha256=7nIuiwhZ39vJJ9KrWqArA5QcWbUdqkz2CLwEpJapeN8,10360 -aiohttp/web_fileresponse.py,sha256=Xzau8EMrWNrFg3u46h4UEteg93G4zYq94CU6vy0HiqE,16362 -aiohttp/web_log.py,sha256=rX5D7xLOX2B6BMdiZ-chme_KfJfW5IXEoFwLfkfkajs,7865 -aiohttp/web_middlewares.py,sha256=sFI0AgeNjdyAjuz92QtMIpngmJSOxrqe2Jfbs4BNUu0,4165 -aiohttp/web_protocol.py,sha256=6s9dMzmaqW77bzM1T111uGNSLFo6gNmfDg7XzYnA8xk,27010 -aiohttp/web_request.py,sha256=KqrOp6AeWB5e6tKrG55Lo7Zbwq49DxdrKniuW2t2u04,29849 -aiohttp/web_response.py,sha256=PKcziNU4LmftXqKVvoRMrAbOeVClpSN-iznHsiWezmU,29341 -aiohttp/web_routedef.py,sha256=VT1GAx6BrawoDh5RwBwBu5wSABSqgWwAe74AUCyZAEo,6110 -aiohttp/web_runner.py,sha256=v1G1nKiOOQgFnTSR4IMc6I9ReEFDMaHtMLvO_roDM-A,11786 -aiohttp/web_server.py,sha256=-9WDKUAiR9ll-rSdwXSqG6YjaoW79d1R4y0BGSqgUMA,2888 -aiohttp/web_urldispatcher.py,sha256=JM-TlriKCNbTLNL43Ra9sdZ0zChxZmIEYQM6ZpbyjI4,44290 -aiohttp/web_ws.py,sha256=lItgmyatkXh0M6EY7JoZnSZkUl6R0wv8B88X4ILqQbU,22739 -aiohttp/worker.py,sha256=zT0iWN5Xze194bO6_VjHou0x7lR_k0MviN6Kadnk22g,8152 diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/WHEEL deleted file mode 100644 index d7eb6c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_11_0_arm64 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/LICENSE.txt b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/LICENSE.txt deleted file mode 100644 index e497a32..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,13 +0,0 @@ - Copyright aio-libs contributors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/vendor/llhttp/LICENSE b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/vendor/llhttp/LICENSE deleted file mode 100644 index 6c1512d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/licenses/vendor/llhttp/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -This software is licensed under the MIT License. - -Copyright Fedor Indutny, 2018. - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/top_level.txt deleted file mode 100644 index ee4ba4f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp-3.13.3.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -aiohttp diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash deleted file mode 100644 index 7d07df1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_cparser.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -5276d46021e0e0d7577e0c9155800cbf62932d60a50783fec42aefb63febedec /Users/runner/work/aiohttp/aiohttp/aiohttp/_cparser.pxd diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash deleted file mode 100644 index aa57b04..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_find_header.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -d067f01423cddb3c442933b5fcc039b18ab651fcec1bc91c577693aafc25cf78 /Users/runner/work/aiohttp/aiohttp/aiohttp/_find_header.pxd diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash deleted file mode 100644 index 0036162..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_parser.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -f9823c608638b8a77fec1c2bd28dc5c043f08c775ec59e7e262dd74b4ebb7384 /Users/runner/work/aiohttp/aiohttp/aiohttp/_http_parser.pyx diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash deleted file mode 100644 index 0a4c8f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/_http_writer.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -56514404ce87a15bfc6b400026d73a270165b2fdbe70313cfa007de29ddd7e14 /Users/runner/work/aiohttp/aiohttp/aiohttp/_http_writer.pyx diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash deleted file mode 100644 index 2c647cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/.hash/hdrs.py.hash +++ /dev/null @@ -1 +0,0 @@ -dab8f933203eeb245d60f856e542a45b888d5a110094620e4811f90f816628d1 /Users/runner/work/aiohttp/aiohttp/aiohttp/hdrs.py diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/__init__.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/__init__.py deleted file mode 100644 index 357baf0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/__init__.py +++ /dev/null @@ -1,278 +0,0 @@ -__version__ = "3.13.3" - -from typing import TYPE_CHECKING, Tuple - -from . import hdrs as hdrs -from .client import ( - BaseConnector, - ClientConnectionError, - ClientConnectionResetError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientError, - ClientHttpProxyError, - ClientOSError, - ClientPayloadError, - ClientProxyConnectionError, - ClientRequest, - ClientResponse, - ClientResponseError, - ClientSession, - ClientSSLError, - ClientTimeout, - ClientWebSocketResponse, - ClientWSTimeout, - ConnectionTimeoutError, - ContentTypeError, - Fingerprint, - InvalidURL, - InvalidUrlClientError, - InvalidUrlRedirectClientError, - NamedPipeConnector, - NonHttpUrlClientError, - NonHttpUrlRedirectClientError, - RedirectClientError, - RequestInfo, - ServerConnectionError, - ServerDisconnectedError, - ServerFingerprintMismatch, - ServerTimeoutError, - SocketTimeoutError, - TCPConnector, - TooManyRedirects, - UnixConnector, - WSMessageTypeError, - WSServerHandshakeError, - request, -) -from .client_middleware_digest_auth import DigestAuthMiddleware -from .client_middlewares import ClientHandlerType, ClientMiddlewareType -from .compression_utils import set_zlib_backend -from .connector import ( - AddrInfoType as AddrInfoType, - SocketFactoryType as SocketFactoryType, -) -from .cookiejar import CookieJar as CookieJar, DummyCookieJar as DummyCookieJar -from .formdata import FormData as FormData -from .helpers import BasicAuth, ChainMapProxy, ETag -from .http import ( - HttpVersion as HttpVersion, - HttpVersion10 as HttpVersion10, - HttpVersion11 as HttpVersion11, - WebSocketError as WebSocketError, - WSCloseCode as WSCloseCode, - WSMessage as WSMessage, - WSMsgType as WSMsgType, -) -from .multipart import ( - BadContentDispositionHeader as BadContentDispositionHeader, - BadContentDispositionParam as BadContentDispositionParam, - BodyPartReader as BodyPartReader, - MultipartReader as MultipartReader, - MultipartWriter as MultipartWriter, - content_disposition_filename as content_disposition_filename, - parse_content_disposition as parse_content_disposition, -) -from .payload import ( - PAYLOAD_REGISTRY as PAYLOAD_REGISTRY, - AsyncIterablePayload as AsyncIterablePayload, - BufferedReaderPayload as BufferedReaderPayload, - BytesIOPayload as BytesIOPayload, - BytesPayload as BytesPayload, - IOBasePayload as IOBasePayload, - JsonPayload as JsonPayload, - Payload as Payload, - StringIOPayload as StringIOPayload, - StringPayload as StringPayload, - TextIOPayload as TextIOPayload, - get_payload as get_payload, - payload_type as payload_type, -) -from .payload_streamer import streamer as streamer -from .resolver import ( - AsyncResolver as AsyncResolver, - DefaultResolver as DefaultResolver, - ThreadedResolver as ThreadedResolver, -) -from .streams import ( - EMPTY_PAYLOAD as EMPTY_PAYLOAD, - DataQueue as DataQueue, - EofStream as EofStream, - FlowControlDataQueue as FlowControlDataQueue, - StreamReader as StreamReader, -) -from .tracing import ( - TraceConfig as TraceConfig, - TraceConnectionCreateEndParams as TraceConnectionCreateEndParams, - TraceConnectionCreateStartParams as TraceConnectionCreateStartParams, - TraceConnectionQueuedEndParams as TraceConnectionQueuedEndParams, - TraceConnectionQueuedStartParams as TraceConnectionQueuedStartParams, - TraceConnectionReuseconnParams as TraceConnectionReuseconnParams, - TraceDnsCacheHitParams as TraceDnsCacheHitParams, - TraceDnsCacheMissParams as TraceDnsCacheMissParams, - TraceDnsResolveHostEndParams as TraceDnsResolveHostEndParams, - TraceDnsResolveHostStartParams as TraceDnsResolveHostStartParams, - TraceRequestChunkSentParams as TraceRequestChunkSentParams, - TraceRequestEndParams as TraceRequestEndParams, - TraceRequestExceptionParams as TraceRequestExceptionParams, - TraceRequestHeadersSentParams as TraceRequestHeadersSentParams, - TraceRequestRedirectParams as TraceRequestRedirectParams, - TraceRequestStartParams as TraceRequestStartParams, - TraceResponseChunkReceivedParams as TraceResponseChunkReceivedParams, -) - -if TYPE_CHECKING: - # At runtime these are lazy-loaded at the bottom of the file. - from .worker import ( - GunicornUVLoopWebWorker as GunicornUVLoopWebWorker, - GunicornWebWorker as GunicornWebWorker, - ) - -__all__: Tuple[str, ...] = ( - "hdrs", - # client - "AddrInfoType", - "BaseConnector", - "ClientConnectionError", - "ClientConnectionResetError", - "ClientConnectorCertificateError", - "ClientConnectorDNSError", - "ClientConnectorError", - "ClientConnectorSSLError", - "ClientError", - "ClientHttpProxyError", - "ClientOSError", - "ClientPayloadError", - "ClientProxyConnectionError", - "ClientResponse", - "ClientRequest", - "ClientResponseError", - "ClientSSLError", - "ClientSession", - "ClientTimeout", - "ClientWebSocketResponse", - "ClientWSTimeout", - "ConnectionTimeoutError", - "ContentTypeError", - "Fingerprint", - "FlowControlDataQueue", - "InvalidURL", - "InvalidUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlClientError", - "NonHttpUrlRedirectClientError", - "RedirectClientError", - "RequestInfo", - "ServerConnectionError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ServerTimeoutError", - "SocketFactoryType", - "SocketTimeoutError", - "TCPConnector", - "TooManyRedirects", - "UnixConnector", - "NamedPipeConnector", - "WSServerHandshakeError", - "request", - # client_middleware - "ClientMiddlewareType", - "ClientHandlerType", - # cookiejar - "CookieJar", - "DummyCookieJar", - # formdata - "FormData", - # helpers - "BasicAuth", - "ChainMapProxy", - "DigestAuthMiddleware", - "ETag", - "set_zlib_backend", - # http - "HttpVersion", - "HttpVersion10", - "HttpVersion11", - "WSMsgType", - "WSCloseCode", - "WSMessage", - "WebSocketError", - # multipart - "BadContentDispositionHeader", - "BadContentDispositionParam", - "BodyPartReader", - "MultipartReader", - "MultipartWriter", - "content_disposition_filename", - "parse_content_disposition", - # payload - "AsyncIterablePayload", - "BufferedReaderPayload", - "BytesIOPayload", - "BytesPayload", - "IOBasePayload", - "JsonPayload", - "PAYLOAD_REGISTRY", - "Payload", - "StringIOPayload", - "StringPayload", - "TextIOPayload", - "get_payload", - "payload_type", - # payload_streamer - "streamer", - # resolver - "AsyncResolver", - "DefaultResolver", - "ThreadedResolver", - # streams - "DataQueue", - "EMPTY_PAYLOAD", - "EofStream", - "StreamReader", - # tracing - "TraceConfig", - "TraceConnectionCreateEndParams", - "TraceConnectionCreateStartParams", - "TraceConnectionQueuedEndParams", - "TraceConnectionQueuedStartParams", - "TraceConnectionReuseconnParams", - "TraceDnsCacheHitParams", - "TraceDnsCacheMissParams", - "TraceDnsResolveHostEndParams", - "TraceDnsResolveHostStartParams", - "TraceRequestChunkSentParams", - "TraceRequestEndParams", - "TraceRequestExceptionParams", - "TraceRequestHeadersSentParams", - "TraceRequestRedirectParams", - "TraceRequestStartParams", - "TraceResponseChunkReceivedParams", - # workers (imported lazily with __getattr__) - "GunicornUVLoopWebWorker", - "GunicornWebWorker", - "WSMessageTypeError", -) - - -def __dir__() -> Tuple[str, ...]: - return __all__ + ("__doc__",) - - -def __getattr__(name: str) -> object: - global GunicornUVLoopWebWorker, GunicornWebWorker - - # Importing gunicorn takes a long time (>100ms), so only import if actually needed. - if name in ("GunicornUVLoopWebWorker", "GunicornWebWorker"): - try: - from .worker import GunicornUVLoopWebWorker as guv, GunicornWebWorker as gw - except ImportError: - return None - - GunicornUVLoopWebWorker = guv # type: ignore[misc] - GunicornWebWorker = gw # type: ignore[misc] - return guv if name == "GunicornUVLoopWebWorker" else gw - - raise AttributeError(f"module {__name__} has no attribute {name}") diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py deleted file mode 100644 index 10e2e0e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_cookie_helpers.py +++ /dev/null @@ -1,338 +0,0 @@ -""" -Internal cookie handling helpers. - -This module contains internal utilities for cookie parsing and manipulation. -These are not part of the public API and may change without notice. -""" - -import re -from http.cookies import Morsel -from typing import List, Optional, Sequence, Tuple, cast - -from .log import internal_logger - -__all__ = ( - "parse_set_cookie_headers", - "parse_cookie_header", - "preserve_morsel_with_coded_value", -) - -# Cookie parsing constants -# Allow more characters in cookie names to handle real-world cookies -# that don't strictly follow RFC standards (fixes #2683) -# RFC 6265 defines cookie-name token as per RFC 2616 Section 2.2, -# but many servers send cookies with characters like {} [] () etc. -# This makes the cookie parser more tolerant of real-world cookies -# while still providing some validation to catch obviously malformed names. -_COOKIE_NAME_RE = re.compile(r"^[!#$%&\'()*+\-./0-9:<=>?@A-Z\[\]^_`a-z{|}~]+$") -_COOKIE_KNOWN_ATTRS = frozenset( # AKA Morsel._reserved - ( - "path", - "domain", - "max-age", - "expires", - "secure", - "httponly", - "samesite", - "partitioned", - "version", - "comment", - ) -) -_COOKIE_BOOL_ATTRS = frozenset( # AKA Morsel._flags - ("secure", "httponly", "partitioned") -) - -# SimpleCookie's pattern for parsing cookies with relaxed validation -# Based on http.cookies pattern but extended to allow more characters in cookie names -# to handle real-world cookies (fixes #2683) -_COOKIE_PATTERN = re.compile( - r""" - \s* # Optional whitespace at start of cookie - (?P # Start of group 'key' - # aiohttp has extended to include [] for compatibility with real-world cookies - [\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\[\]]+ # Any word of at least one letter - ) # End of group 'key' - ( # Optional group: there may not be a value. - \s*=\s* # Equal Sign - (?P # Start of group 'val' - "(?:[^\\"]|\\.)*" # Any double-quoted string (properly closed) - | # or - "[^";]* # Unmatched opening quote (differs from SimpleCookie - issue #7993) - | # or - # Special case for "expires" attr - RFC 822, RFC 850, RFC 1036, RFC 1123 - (\w{3,6}day|\w{3}),\s # Day of the week or abbreviated day (with comma) - [\w\d\s-]{9,11}\s[\d:]{8}\s # Date and time in specific format - (GMT|[+-]\d{4}) # Timezone: GMT or RFC 2822 offset like -0000, +0100 - # NOTE: RFC 2822 timezone support is an aiohttp extension - # for issue #4493 - SimpleCookie does NOT support this - | # or - # ANSI C asctime() format: "Wed Jun 9 10:18:14 2021" - # NOTE: This is an aiohttp extension for issue #4327 - SimpleCookie does NOT support this format - \w{3}\s+\w{3}\s+[\s\d]\d\s+\d{2}:\d{2}:\d{2}\s+\d{4} - | # or - [\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=\[\]]* # Any word or empty string - ) # End of group 'val' - )? # End of optional value group - \s* # Any number of spaces. - (\s+|;|$) # Ending either at space, semicolon, or EOS. - """, - re.VERBOSE | re.ASCII, -) - - -def preserve_morsel_with_coded_value(cookie: Morsel[str]) -> Morsel[str]: - """ - Preserve a Morsel's coded_value exactly as received from the server. - - This function ensures that cookie encoding is preserved exactly as sent by - the server, which is critical for compatibility with old servers that have - strict requirements about cookie formats. - - This addresses the issue described in https://github.com/aio-libs/aiohttp/pull/1453 - where Python's SimpleCookie would re-encode cookies, breaking authentication - with certain servers. - - Args: - cookie: A Morsel object from SimpleCookie - - Returns: - A Morsel object with preserved coded_value - - """ - mrsl_val = cast("Morsel[str]", cookie.get(cookie.key, Morsel())) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - mrsl_val.__setstate__( # type: ignore[attr-defined] - {"key": cookie.key, "value": cookie.value, "coded_value": cookie.coded_value} - ) - return mrsl_val - - -_unquote_sub = re.compile(r"\\(?:([0-3][0-7][0-7])|(.))").sub - - -def _unquote_replace(m: re.Match[str]) -> str: - """ - Replace function for _unquote_sub regex substitution. - - Handles escaped characters in cookie values: - - Octal sequences are converted to their character representation - - Other escaped characters are unescaped by removing the backslash - """ - if m[1]: - return chr(int(m[1], 8)) - return m[2] - - -def _unquote(value: str) -> str: - """ - Unquote a cookie value. - - Vendored from http.cookies._unquote to ensure compatibility. - - Note: The original implementation checked for None, but we've removed - that check since all callers already ensure the value is not None. - """ - # If there aren't any doublequotes, - # then there can't be any special characters. See RFC 2109. - if len(value) < 2: - return value - if value[0] != '"' or value[-1] != '"': - return value - - # We have to assume that we must decode this string. - # Down to work. - - # Remove the "s - value = value[1:-1] - - # Check for special sequences. Examples: - # \012 --> \n - # \" --> " - # - return _unquote_sub(_unquote_replace, value) - - -def parse_cookie_header(header: str) -> List[Tuple[str, Morsel[str]]]: - """ - Parse a Cookie header according to RFC 6265 Section 5.4. - - Cookie headers contain only name-value pairs separated by semicolons. - There are no attributes in Cookie headers - even names that match - attribute names (like 'path' or 'secure') should be treated as cookies. - - This parser uses the same regex-based approach as parse_set_cookie_headers - to properly handle quoted values that may contain semicolons. When the - regex fails to match a malformed cookie, it falls back to simple parsing - to ensure subsequent cookies are not lost - https://github.com/aio-libs/aiohttp/issues/11632 - - Args: - header: The Cookie header value to parse - - Returns: - List of (name, Morsel) tuples for compatibility with SimpleCookie.update() - """ - if not header: - return [] - - cookies: List[Tuple[str, Morsel[str]]] = [] - morsel: Morsel[str] - i = 0 - n = len(header) - - invalid_names = [] - while i < n: - # Use the same pattern as parse_set_cookie_headers to find cookies - match = _COOKIE_PATTERN.match(header, i) - if not match: - # Fallback for malformed cookies https://github.com/aio-libs/aiohttp/issues/11632 - # Find next semicolon to skip or attempt simple key=value parsing - next_semi = header.find(";", i) - eq_pos = header.find("=", i) - - # Try to extract key=value if '=' comes before ';' - if eq_pos != -1 and (next_semi == -1 or eq_pos < next_semi): - end_pos = next_semi if next_semi != -1 else n - key = header[i:eq_pos].strip() - value = header[eq_pos + 1 : end_pos].strip() - - # Validate the name (same as regex path) - if not _COOKIE_NAME_RE.match(key): - invalid_names.append(key) - else: - morsel = Morsel() - morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - cookies.append((key, morsel)) - - # Move to next cookie or end - i = next_semi + 1 if next_semi != -1 else n - continue - - key = match.group("key") - value = match.group("val") or "" - i = match.end(0) - - # Validate the name - if not key or not _COOKIE_NAME_RE.match(key): - invalid_names.append(key) - continue - - # Create new morsel - morsel = Morsel() - # Preserve the original value as coded_value (with quotes if present) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - - cookies.append((key, morsel)) - - if invalid_names: - internal_logger.debug( - "Cannot load cookie. Illegal cookie names: %r", invalid_names - ) - - return cookies - - -def parse_set_cookie_headers(headers: Sequence[str]) -> List[Tuple[str, Morsel[str]]]: - """ - Parse cookie headers using a vendored version of SimpleCookie parsing. - - This implementation is based on SimpleCookie.__parse_string to ensure - compatibility with how SimpleCookie parses cookies, including handling - of malformed cookies with missing semicolons. - - This function is used for both Cookie and Set-Cookie headers in order to be - forgiving. Ideally we would have followed RFC 6265 Section 5.2 (for Cookie - headers) and RFC 6265 Section 4.2.1 (for Set-Cookie headers), but the - real world data makes it impossible since we need to be a bit more forgiving. - - NOTE: This implementation differs from SimpleCookie in handling unmatched quotes. - SimpleCookie will stop parsing when it encounters a cookie value with an unmatched - quote (e.g., 'cookie="value'), causing subsequent cookies to be silently dropped. - This implementation handles unmatched quotes more gracefully to prevent cookie loss. - See https://github.com/aio-libs/aiohttp/issues/7993 - """ - parsed_cookies: List[Tuple[str, Morsel[str]]] = [] - - for header in headers: - if not header: - continue - - # Parse cookie string using SimpleCookie's algorithm - i = 0 - n = len(header) - current_morsel: Optional[Morsel[str]] = None - morsel_seen = False - - while 0 <= i < n: - # Start looking for a cookie - match = _COOKIE_PATTERN.match(header, i) - if not match: - # No more cookies - break - - key, value = match.group("key"), match.group("val") - i = match.end(0) - lower_key = key.lower() - - if key[0] == "$": - if not morsel_seen: - # We ignore attributes which pertain to the cookie - # mechanism as a whole, such as "$Version". - continue - # Process as attribute - if current_morsel is not None: - attr_lower_key = lower_key[1:] - if attr_lower_key in _COOKIE_KNOWN_ATTRS: - current_morsel[attr_lower_key] = value or "" - elif lower_key in _COOKIE_KNOWN_ATTRS: - if not morsel_seen: - # Invalid cookie string - attribute before cookie - break - if lower_key in _COOKIE_BOOL_ATTRS: - # Boolean attribute with any value should be True - if current_morsel is not None and current_morsel.isReservedKey(key): - current_morsel[lower_key] = True - elif value is None: - # Invalid cookie string - non-boolean attribute without value - break - elif current_morsel is not None: - # Regular attribute with value - current_morsel[lower_key] = _unquote(value) - elif value is not None: - # This is a cookie name=value pair - # Validate the name - if key in _COOKIE_KNOWN_ATTRS or not _COOKIE_NAME_RE.match(key): - internal_logger.warning( - "Can not load cookies: Illegal cookie name %r", key - ) - current_morsel = None - else: - # Create new morsel - current_morsel = Morsel() - # Preserve the original value as coded_value (with quotes if present) - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - current_morsel.__setstate__( # type: ignore[attr-defined] - {"key": key, "value": _unquote(value), "coded_value": value} - ) - parsed_cookies.append((key, current_morsel)) - morsel_seen = True - else: - # Invalid cookie string - no value for non-attribute - break - - return parsed_cookies diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_cparser.pxd b/backend/venv39/lib/python3.9/site-packages/aiohttp/_cparser.pxd deleted file mode 100644 index 1b3be6d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_cparser.pxd +++ /dev/null @@ -1,158 +0,0 @@ -from libc.stdint cimport int32_t, uint8_t, uint16_t, uint64_t - - -cdef extern from "llhttp.h": - - struct llhttp__internal_s: - int32_t _index - void* _span_pos0 - void* _span_cb0 - int32_t error - const char* reason - const char* error_pos - void* data - void* _current - uint64_t content_length - uint8_t type - uint8_t method - uint8_t http_major - uint8_t http_minor - uint8_t header_state - uint8_t lenient_flags - uint8_t upgrade - uint8_t finish - uint16_t flags - uint16_t status_code - void* settings - - ctypedef llhttp__internal_s llhttp__internal_t - ctypedef llhttp__internal_t llhttp_t - - ctypedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length) except -1 - ctypedef int (*llhttp_cb)(llhttp_t*) except -1 - - struct llhttp_settings_s: - llhttp_cb on_message_begin - llhttp_data_cb on_url - llhttp_data_cb on_status - llhttp_data_cb on_header_field - llhttp_data_cb on_header_value - llhttp_cb on_headers_complete - llhttp_data_cb on_body - llhttp_cb on_message_complete - llhttp_cb on_chunk_header - llhttp_cb on_chunk_complete - - llhttp_cb on_url_complete - llhttp_cb on_status_complete - llhttp_cb on_header_field_complete - llhttp_cb on_header_value_complete - - ctypedef llhttp_settings_s llhttp_settings_t - - enum llhttp_errno: - HPE_OK, - HPE_INTERNAL, - HPE_STRICT, - HPE_LF_EXPECTED, - HPE_UNEXPECTED_CONTENT_LENGTH, - HPE_CLOSED_CONNECTION, - HPE_INVALID_METHOD, - HPE_INVALID_URL, - HPE_INVALID_CONSTANT, - HPE_INVALID_VERSION, - HPE_INVALID_HEADER_TOKEN, - HPE_INVALID_CONTENT_LENGTH, - HPE_INVALID_CHUNK_SIZE, - HPE_INVALID_STATUS, - HPE_INVALID_EOF_STATE, - HPE_INVALID_TRANSFER_ENCODING, - HPE_CB_MESSAGE_BEGIN, - HPE_CB_HEADERS_COMPLETE, - HPE_CB_MESSAGE_COMPLETE, - HPE_CB_CHUNK_HEADER, - HPE_CB_CHUNK_COMPLETE, - HPE_PAUSED, - HPE_PAUSED_UPGRADE, - HPE_USER - - ctypedef llhttp_errno llhttp_errno_t - - enum llhttp_flags: - F_CHUNKED, - F_CONTENT_LENGTH - - enum llhttp_type: - HTTP_REQUEST, - HTTP_RESPONSE, - HTTP_BOTH - - enum llhttp_method: - HTTP_DELETE, - HTTP_GET, - HTTP_HEAD, - HTTP_POST, - HTTP_PUT, - HTTP_CONNECT, - HTTP_OPTIONS, - HTTP_TRACE, - HTTP_COPY, - HTTP_LOCK, - HTTP_MKCOL, - HTTP_MOVE, - HTTP_PROPFIND, - HTTP_PROPPATCH, - HTTP_SEARCH, - HTTP_UNLOCK, - HTTP_BIND, - HTTP_REBIND, - HTTP_UNBIND, - HTTP_ACL, - HTTP_REPORT, - HTTP_MKACTIVITY, - HTTP_CHECKOUT, - HTTP_MERGE, - HTTP_MSEARCH, - HTTP_NOTIFY, - HTTP_SUBSCRIBE, - HTTP_UNSUBSCRIBE, - HTTP_PATCH, - HTTP_PURGE, - HTTP_MKCALENDAR, - HTTP_LINK, - HTTP_UNLINK, - HTTP_SOURCE, - HTTP_PRI, - HTTP_DESCRIBE, - HTTP_ANNOUNCE, - HTTP_SETUP, - HTTP_PLAY, - HTTP_PAUSE, - HTTP_TEARDOWN, - HTTP_GET_PARAMETER, - HTTP_SET_PARAMETER, - HTTP_REDIRECT, - HTTP_RECORD, - HTTP_FLUSH - - ctypedef llhttp_method llhttp_method_t; - - void llhttp_settings_init(llhttp_settings_t* settings) - void llhttp_init(llhttp_t* parser, llhttp_type type, - const llhttp_settings_t* settings) - - llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) - - int llhttp_should_keep_alive(const llhttp_t* parser) - - void llhttp_resume_after_upgrade(llhttp_t* parser) - - llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) - const char* llhttp_get_error_reason(const llhttp_t* parser) - const char* llhttp_get_error_pos(const llhttp_t* parser) - - const char* llhttp_method_name(llhttp_method_t method) - - void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) - void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) - void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_find_header.pxd b/backend/venv39/lib/python3.9/site-packages/aiohttp/_find_header.pxd deleted file mode 100644 index 37a6c37..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_find_header.pxd +++ /dev/null @@ -1,2 +0,0 @@ -cdef extern from "_find_header.h": - int find_header(char *, int) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_headers.pxi b/backend/venv39/lib/python3.9/site-packages/aiohttp/_headers.pxi deleted file mode 100644 index 3744721..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_headers.pxi +++ /dev/null @@ -1,83 +0,0 @@ -# The file is autogenerated from aiohttp/hdrs.py -# Run ./tools/gen.py to update it after the origin changing. - -from . import hdrs -cdef tuple headers = ( - hdrs.ACCEPT, - hdrs.ACCEPT_CHARSET, - hdrs.ACCEPT_ENCODING, - hdrs.ACCEPT_LANGUAGE, - hdrs.ACCEPT_RANGES, - hdrs.ACCESS_CONTROL_ALLOW_CREDENTIALS, - hdrs.ACCESS_CONTROL_ALLOW_HEADERS, - hdrs.ACCESS_CONTROL_ALLOW_METHODS, - hdrs.ACCESS_CONTROL_ALLOW_ORIGIN, - hdrs.ACCESS_CONTROL_EXPOSE_HEADERS, - hdrs.ACCESS_CONTROL_MAX_AGE, - hdrs.ACCESS_CONTROL_REQUEST_HEADERS, - hdrs.ACCESS_CONTROL_REQUEST_METHOD, - hdrs.AGE, - hdrs.ALLOW, - hdrs.AUTHORIZATION, - hdrs.CACHE_CONTROL, - hdrs.CONNECTION, - hdrs.CONTENT_DISPOSITION, - hdrs.CONTENT_ENCODING, - hdrs.CONTENT_LANGUAGE, - hdrs.CONTENT_LENGTH, - hdrs.CONTENT_LOCATION, - hdrs.CONTENT_MD5, - hdrs.CONTENT_RANGE, - hdrs.CONTENT_TRANSFER_ENCODING, - hdrs.CONTENT_TYPE, - hdrs.COOKIE, - hdrs.DATE, - hdrs.DESTINATION, - hdrs.DIGEST, - hdrs.ETAG, - hdrs.EXPECT, - hdrs.EXPIRES, - hdrs.FORWARDED, - hdrs.FROM, - hdrs.HOST, - hdrs.IF_MATCH, - hdrs.IF_MODIFIED_SINCE, - hdrs.IF_NONE_MATCH, - hdrs.IF_RANGE, - hdrs.IF_UNMODIFIED_SINCE, - hdrs.KEEP_ALIVE, - hdrs.LAST_EVENT_ID, - hdrs.LAST_MODIFIED, - hdrs.LINK, - hdrs.LOCATION, - hdrs.MAX_FORWARDS, - hdrs.ORIGIN, - hdrs.PRAGMA, - hdrs.PROXY_AUTHENTICATE, - hdrs.PROXY_AUTHORIZATION, - hdrs.RANGE, - hdrs.REFERER, - hdrs.RETRY_AFTER, - hdrs.SEC_WEBSOCKET_ACCEPT, - hdrs.SEC_WEBSOCKET_EXTENSIONS, - hdrs.SEC_WEBSOCKET_KEY, - hdrs.SEC_WEBSOCKET_KEY1, - hdrs.SEC_WEBSOCKET_PROTOCOL, - hdrs.SEC_WEBSOCKET_VERSION, - hdrs.SERVER, - hdrs.SET_COOKIE, - hdrs.TE, - hdrs.TRAILER, - hdrs.TRANSFER_ENCODING, - hdrs.URI, - hdrs.UPGRADE, - hdrs.USER_AGENT, - hdrs.VARY, - hdrs.VIA, - hdrs.WWW_AUTHENTICATE, - hdrs.WANT_DIGEST, - hdrs.WARNING, - hdrs.X_FORWARDED_FOR, - hdrs.X_FORWARDED_HOST, - hdrs.X_FORWARDED_PROTO, -) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-darwin.so deleted file mode 100755 index f3facc4..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.pyx b/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.pyx deleted file mode 100644 index 4a7101e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_parser.pyx +++ /dev/null @@ -1,835 +0,0 @@ -# Based on https://github.com/MagicStack/httptools -# - -from cpython cimport ( - Py_buffer, - PyBUF_SIMPLE, - PyBuffer_Release, - PyBytes_AsString, - PyBytes_AsStringAndSize, - PyObject_GetBuffer, -) -from cpython.mem cimport PyMem_Free, PyMem_Malloc -from libc.limits cimport ULLONG_MAX -from libc.string cimport memcpy - -from multidict import CIMultiDict as _CIMultiDict, CIMultiDictProxy as _CIMultiDictProxy -from yarl import URL as _URL - -from aiohttp import hdrs -from aiohttp.helpers import DEBUG, set_exception - -from .http_exceptions import ( - BadHttpMessage, - BadHttpMethod, - BadStatusLine, - ContentLengthError, - InvalidHeader, - InvalidURLError, - LineTooLong, - PayloadEncodingError, - TransferEncodingError, -) -from .http_parser import DeflateBuffer as _DeflateBuffer -from .http_writer import ( - HttpVersion as _HttpVersion, - HttpVersion10 as _HttpVersion10, - HttpVersion11 as _HttpVersion11, -) -from .streams import EMPTY_PAYLOAD as _EMPTY_PAYLOAD, StreamReader as _StreamReader - -cimport cython - -from aiohttp cimport _cparser as cparser - -include "_headers.pxi" - -from aiohttp cimport _find_header - -ALLOWED_UPGRADES = frozenset({"websocket"}) -DEF DEFAULT_FREELIST_SIZE = 250 - -cdef extern from "Python.h": - int PyByteArray_Resize(object, Py_ssize_t) except -1 - Py_ssize_t PyByteArray_Size(object) except -1 - char* PyByteArray_AsString(object) - -__all__ = ('HttpRequestParser', 'HttpResponseParser', - 'RawRequestMessage', 'RawResponseMessage') - -cdef object URL = _URL -cdef object URL_build = URL.build -cdef object CIMultiDict = _CIMultiDict -cdef object CIMultiDictProxy = _CIMultiDictProxy -cdef object HttpVersion = _HttpVersion -cdef object HttpVersion10 = _HttpVersion10 -cdef object HttpVersion11 = _HttpVersion11 -cdef object SEC_WEBSOCKET_KEY1 = hdrs.SEC_WEBSOCKET_KEY1 -cdef object CONTENT_ENCODING = hdrs.CONTENT_ENCODING -cdef object EMPTY_PAYLOAD = _EMPTY_PAYLOAD -cdef object StreamReader = _StreamReader -cdef object DeflateBuffer = _DeflateBuffer -cdef bytes EMPTY_BYTES = b"" - -cdef inline object extend(object buf, const char* at, size_t length): - cdef Py_ssize_t s - cdef char* ptr - s = PyByteArray_Size(buf) - PyByteArray_Resize(buf, s + length) - ptr = PyByteArray_AsString(buf) - memcpy(ptr + s, at, length) - - -DEF METHODS_COUNT = 46; - -cdef list _http_method = [] - -for i in range(METHODS_COUNT): - _http_method.append( - cparser.llhttp_method_name( i).decode('ascii')) - - -cdef inline str http_method_str(int i): - if i < METHODS_COUNT: - return _http_method[i] - else: - return "" - -cdef inline object find_header(bytes raw_header): - cdef Py_ssize_t size - cdef char *buf - cdef int idx - PyBytes_AsStringAndSize(raw_header, &buf, &size) - idx = _find_header.find_header(buf, size) - if idx == -1: - return raw_header.decode('utf-8', 'surrogateescape') - return headers[idx] - - -@cython.freelist(DEFAULT_FREELIST_SIZE) -cdef class RawRequestMessage: - cdef readonly str method - cdef readonly str path - cdef readonly object version # HttpVersion - cdef readonly object headers # CIMultiDict - cdef readonly object raw_headers # tuple - cdef readonly object should_close - cdef readonly object compression - cdef readonly object upgrade - cdef readonly object chunked - cdef readonly object url # yarl.URL - - def __init__(self, method, path, version, headers, raw_headers, - should_close, compression, upgrade, chunked, url): - self.method = method - self.path = path - self.version = version - self.headers = headers - self.raw_headers = raw_headers - self.should_close = should_close - self.compression = compression - self.upgrade = upgrade - self.chunked = chunked - self.url = url - - def __repr__(self): - info = [] - info.append(("method", self.method)) - info.append(("path", self.path)) - info.append(("version", self.version)) - info.append(("headers", self.headers)) - info.append(("raw_headers", self.raw_headers)) - info.append(("should_close", self.should_close)) - info.append(("compression", self.compression)) - info.append(("upgrade", self.upgrade)) - info.append(("chunked", self.chunked)) - info.append(("url", self.url)) - sinfo = ', '.join(name + '=' + repr(val) for name, val in info) - return '' - - def _replace(self, **dct): - cdef RawRequestMessage ret - ret = _new_request_message(self.method, - self.path, - self.version, - self.headers, - self.raw_headers, - self.should_close, - self.compression, - self.upgrade, - self.chunked, - self.url) - if "method" in dct: - ret.method = dct["method"] - if "path" in dct: - ret.path = dct["path"] - if "version" in dct: - ret.version = dct["version"] - if "headers" in dct: - ret.headers = dct["headers"] - if "raw_headers" in dct: - ret.raw_headers = dct["raw_headers"] - if "should_close" in dct: - ret.should_close = dct["should_close"] - if "compression" in dct: - ret.compression = dct["compression"] - if "upgrade" in dct: - ret.upgrade = dct["upgrade"] - if "chunked" in dct: - ret.chunked = dct["chunked"] - if "url" in dct: - ret.url = dct["url"] - return ret - -cdef _new_request_message(str method, - str path, - object version, - object headers, - object raw_headers, - bint should_close, - object compression, - bint upgrade, - bint chunked, - object url): - cdef RawRequestMessage ret - ret = RawRequestMessage.__new__(RawRequestMessage) - ret.method = method - ret.path = path - ret.version = version - ret.headers = headers - ret.raw_headers = raw_headers - ret.should_close = should_close - ret.compression = compression - ret.upgrade = upgrade - ret.chunked = chunked - ret.url = url - return ret - - -@cython.freelist(DEFAULT_FREELIST_SIZE) -cdef class RawResponseMessage: - cdef readonly object version # HttpVersion - cdef readonly int code - cdef readonly str reason - cdef readonly object headers # CIMultiDict - cdef readonly object raw_headers # tuple - cdef readonly object should_close - cdef readonly object compression - cdef readonly object upgrade - cdef readonly object chunked - - def __init__(self, version, code, reason, headers, raw_headers, - should_close, compression, upgrade, chunked): - self.version = version - self.code = code - self.reason = reason - self.headers = headers - self.raw_headers = raw_headers - self.should_close = should_close - self.compression = compression - self.upgrade = upgrade - self.chunked = chunked - - def __repr__(self): - info = [] - info.append(("version", self.version)) - info.append(("code", self.code)) - info.append(("reason", self.reason)) - info.append(("headers", self.headers)) - info.append(("raw_headers", self.raw_headers)) - info.append(("should_close", self.should_close)) - info.append(("compression", self.compression)) - info.append(("upgrade", self.upgrade)) - info.append(("chunked", self.chunked)) - sinfo = ', '.join(name + '=' + repr(val) for name, val in info) - return '' - - -cdef _new_response_message(object version, - int code, - str reason, - object headers, - object raw_headers, - bint should_close, - object compression, - bint upgrade, - bint chunked): - cdef RawResponseMessage ret - ret = RawResponseMessage.__new__(RawResponseMessage) - ret.version = version - ret.code = code - ret.reason = reason - ret.headers = headers - ret.raw_headers = raw_headers - ret.should_close = should_close - ret.compression = compression - ret.upgrade = upgrade - ret.chunked = chunked - return ret - - -@cython.internal -cdef class HttpParser: - - cdef: - cparser.llhttp_t* _cparser - cparser.llhttp_settings_t* _csettings - - bytes _raw_name - object _name - bytes _raw_value - bint _has_value - - object _protocol - object _loop - object _timer - - size_t _max_line_size - size_t _max_field_size - size_t _max_headers - bint _response_with_body - bint _read_until_eof - - bint _started - object _url - bytearray _buf - str _path - str _reason - list _headers - list _raw_headers - bint _upgraded - list _messages - object _payload - bint _payload_error - object _payload_exception - object _last_error - bint _auto_decompress - int _limit - - str _content_encoding - - Py_buffer py_buf - - def __cinit__(self): - self._cparser = \ - PyMem_Malloc(sizeof(cparser.llhttp_t)) - if self._cparser is NULL: - raise MemoryError() - - self._csettings = \ - PyMem_Malloc(sizeof(cparser.llhttp_settings_t)) - if self._csettings is NULL: - raise MemoryError() - - def __dealloc__(self): - PyMem_Free(self._cparser) - PyMem_Free(self._csettings) - - cdef _init( - self, cparser.llhttp_type mode, - object protocol, object loop, int limit, - object timer=None, - size_t max_line_size=8190, size_t max_headers=32768, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True, - ): - cparser.llhttp_settings_init(self._csettings) - cparser.llhttp_init(self._cparser, mode, self._csettings) - self._cparser.data = self - self._cparser.content_length = 0 - - self._protocol = protocol - self._loop = loop - self._timer = timer - - self._buf = bytearray() - self._payload = None - self._payload_error = 0 - self._payload_exception = payload_exception - self._messages = [] - - self._raw_name = EMPTY_BYTES - self._raw_value = EMPTY_BYTES - self._has_value = False - - self._max_line_size = max_line_size - self._max_headers = max_headers - self._max_field_size = max_field_size - self._response_with_body = response_with_body - self._read_until_eof = read_until_eof - self._upgraded = False - self._auto_decompress = auto_decompress - self._content_encoding = None - - self._csettings.on_url = cb_on_url - self._csettings.on_status = cb_on_status - self._csettings.on_header_field = cb_on_header_field - self._csettings.on_header_value = cb_on_header_value - self._csettings.on_headers_complete = cb_on_headers_complete - self._csettings.on_body = cb_on_body - self._csettings.on_message_begin = cb_on_message_begin - self._csettings.on_message_complete = cb_on_message_complete - self._csettings.on_chunk_header = cb_on_chunk_header - self._csettings.on_chunk_complete = cb_on_chunk_complete - - self._last_error = None - self._limit = limit - - cdef _process_header(self): - cdef str value - if self._raw_name is not EMPTY_BYTES: - name = find_header(self._raw_name) - value = self._raw_value.decode('utf-8', 'surrogateescape') - - self._headers.append((name, value)) - - if name is CONTENT_ENCODING: - self._content_encoding = value - - self._has_value = False - self._raw_headers.append((self._raw_name, self._raw_value)) - self._raw_name = EMPTY_BYTES - self._raw_value = EMPTY_BYTES - - cdef _on_header_field(self, char* at, size_t length): - if self._has_value: - self._process_header() - - if self._raw_name is EMPTY_BYTES: - self._raw_name = at[:length] - else: - self._raw_name += at[:length] - - cdef _on_header_value(self, char* at, size_t length): - if self._raw_value is EMPTY_BYTES: - self._raw_value = at[:length] - else: - self._raw_value += at[:length] - self._has_value = True - - cdef _on_headers_complete(self): - self._process_header() - - should_close = not cparser.llhttp_should_keep_alive(self._cparser) - upgrade = self._cparser.upgrade - chunked = self._cparser.flags & cparser.F_CHUNKED - - raw_headers = tuple(self._raw_headers) - headers = CIMultiDictProxy(CIMultiDict(self._headers)) - - if self._cparser.type == cparser.HTTP_REQUEST: - h_upg = headers.get("upgrade", "") - allowed = upgrade and h_upg.isascii() and h_upg.lower() in ALLOWED_UPGRADES - if allowed or self._cparser.method == cparser.HTTP_CONNECT: - self._upgraded = True - else: - if upgrade and self._cparser.status_code == 101: - self._upgraded = True - - # do not support old websocket spec - if SEC_WEBSOCKET_KEY1 in headers: - raise InvalidHeader(SEC_WEBSOCKET_KEY1) - - encoding = None - enc = self._content_encoding - if enc is not None: - self._content_encoding = None - if enc.isascii() and enc.lower() in {"gzip", "deflate", "br", "zstd"}: - encoding = enc - - if self._cparser.type == cparser.HTTP_REQUEST: - method = http_method_str(self._cparser.method) - msg = _new_request_message( - method, self._path, - self.http_version(), headers, raw_headers, - should_close, encoding, upgrade, chunked, self._url) - else: - msg = _new_response_message( - self.http_version(), self._cparser.status_code, self._reason, - headers, raw_headers, should_close, encoding, - upgrade, chunked) - - if ( - ULLONG_MAX > self._cparser.content_length > 0 or chunked or - self._cparser.method == cparser.HTTP_CONNECT or - (self._cparser.status_code >= 199 and - self._cparser.content_length == 0 and - self._read_until_eof) - ): - payload = StreamReader( - self._protocol, timer=self._timer, loop=self._loop, - limit=self._limit) - else: - payload = EMPTY_PAYLOAD - - self._payload = payload - if encoding is not None and self._auto_decompress: - self._payload = DeflateBuffer(payload, encoding) - - if not self._response_with_body: - payload = EMPTY_PAYLOAD - - self._messages.append((msg, payload)) - - cdef _on_message_complete(self): - self._payload.feed_eof() - self._payload = None - - cdef _on_chunk_header(self): - self._payload.begin_http_chunk_receiving() - - cdef _on_chunk_complete(self): - self._payload.end_http_chunk_receiving() - - cdef object _on_status_complete(self): - pass - - cdef inline http_version(self): - cdef cparser.llhttp_t* parser = self._cparser - - if parser.http_major == 1: - if parser.http_minor == 0: - return HttpVersion10 - elif parser.http_minor == 1: - return HttpVersion11 - - return HttpVersion(parser.http_major, parser.http_minor) - - ### Public API ### - - def feed_eof(self): - cdef bytes desc - - if self._payload is not None: - if self._cparser.flags & cparser.F_CHUNKED: - raise TransferEncodingError( - "Not enough data to satisfy transfer length header.") - elif self._cparser.flags & cparser.F_CONTENT_LENGTH: - raise ContentLengthError( - "Not enough data to satisfy content length header.") - elif cparser.llhttp_get_errno(self._cparser) != cparser.HPE_OK: - desc = cparser.llhttp_get_error_reason(self._cparser) - raise PayloadEncodingError(desc.decode('latin-1')) - else: - self._payload.feed_eof() - elif self._started: - self._on_headers_complete() - if self._messages: - return self._messages[-1][0] - - def feed_data(self, data): - cdef: - size_t data_len - size_t nb - cdef cparser.llhttp_errno_t errno - - PyObject_GetBuffer(data, &self.py_buf, PyBUF_SIMPLE) - data_len = self.py_buf.len - - errno = cparser.llhttp_execute( - self._cparser, - self.py_buf.buf, - data_len) - - if errno is cparser.HPE_PAUSED_UPGRADE: - cparser.llhttp_resume_after_upgrade(self._cparser) - - nb = cparser.llhttp_get_error_pos(self._cparser) - self.py_buf.buf - - PyBuffer_Release(&self.py_buf) - - if errno not in (cparser.HPE_OK, cparser.HPE_PAUSED_UPGRADE): - if self._payload_error == 0: - if self._last_error is not None: - ex = self._last_error - self._last_error = None - else: - after = cparser.llhttp_get_error_pos(self._cparser) - before = data[:after - self.py_buf.buf] - after_b = after.split(b"\r\n", 1)[0] - before = before.rsplit(b"\r\n", 1)[-1] - data = before + after_b - pointer = " " * (len(repr(before))-1) + "^" - ex = parser_error_from_errno(self._cparser, data, pointer) - self._payload = None - raise ex - - if self._messages: - messages = self._messages - self._messages = [] - else: - messages = () - - if self._upgraded: - return messages, True, data[nb:] - else: - return messages, False, b"" - - def set_upgraded(self, val): - self._upgraded = val - - -cdef class HttpRequestParser(HttpParser): - - def __init__( - self, protocol, loop, int limit, timer=None, - size_t max_line_size=8190, size_t max_headers=32768, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True, - ): - self._init(cparser.HTTP_REQUEST, protocol, loop, limit, timer, - max_line_size, max_headers, max_field_size, - payload_exception, response_with_body, read_until_eof, - auto_decompress) - - cdef object _on_status_complete(self): - cdef int idx1, idx2 - if not self._buf: - return - self._path = self._buf.decode('utf-8', 'surrogateescape') - try: - idx3 = len(self._path) - if self._cparser.method == cparser.HTTP_CONNECT: - # authority-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 - self._url = URL.build(authority=self._path, encoded=True) - elif idx3 > 1 and self._path[0] == '/': - # origin-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 - idx1 = self._path.find("?") - if idx1 == -1: - query = "" - idx2 = self._path.find("#") - if idx2 == -1: - path = self._path - fragment = "" - else: - path = self._path[0: idx2] - fragment = self._path[idx2+1:] - - else: - path = self._path[0:idx1] - idx1 += 1 - idx2 = self._path.find("#", idx1+1) - if idx2 == -1: - query = self._path[idx1:] - fragment = "" - else: - query = self._path[idx1: idx2] - fragment = self._path[idx2+1:] - - self._url = URL.build( - path=path, - query_string=query, - fragment=fragment, - encoded=True, - ) - else: - # absolute-form for proxy maybe, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 - self._url = URL(self._path, encoded=True) - finally: - PyByteArray_Resize(self._buf, 0) - - -cdef class HttpResponseParser(HttpParser): - - def __init__( - self, protocol, loop, int limit, timer=None, - size_t max_line_size=8190, size_t max_headers=32768, - size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint read_until_eof=False, - bint auto_decompress=True - ): - self._init(cparser.HTTP_RESPONSE, protocol, loop, limit, timer, - max_line_size, max_headers, max_field_size, - payload_exception, response_with_body, read_until_eof, - auto_decompress) - # Use strict parsing on dev mode, so users are warned about broken servers. - if not DEBUG: - cparser.llhttp_set_lenient_headers(self._cparser, 1) - cparser.llhttp_set_lenient_optional_cr_before_lf(self._cparser, 1) - cparser.llhttp_set_lenient_spaces_after_chunk_size(self._cparser, 1) - - cdef object _on_status_complete(self): - if self._buf: - self._reason = self._buf.decode('utf-8', 'surrogateescape') - PyByteArray_Resize(self._buf, 0) - else: - self._reason = self._reason or '' - -cdef int cb_on_message_begin(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - - pyparser._started = True - pyparser._headers = [] - pyparser._raw_headers = [] - PyByteArray_Resize(pyparser._buf, 0) - pyparser._path = None - pyparser._reason = None - return 0 - - -cdef int cb_on_url(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - try: - if length > pyparser._max_line_size: - raise LineTooLong( - 'Status line is too long', pyparser._max_line_size, length) - extend(pyparser._buf, at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_status(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef str reason - try: - if length > pyparser._max_line_size: - raise LineTooLong( - 'Status line is too long', pyparser._max_line_size, length) - extend(pyparser._buf, at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_header_field(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef Py_ssize_t size - try: - pyparser._on_status_complete() - size = len(pyparser._raw_name) + length - if size > pyparser._max_field_size: - raise LineTooLong( - 'Header name is too long', pyparser._max_field_size, size) - pyparser._on_header_field(at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_header_value(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef Py_ssize_t size - try: - size = len(pyparser._raw_value) + length - if size > pyparser._max_field_size: - raise LineTooLong( - 'Header value is too long', pyparser._max_field_size, size) - pyparser._on_header_value(at, length) - except BaseException as ex: - pyparser._last_error = ex - return -1 - else: - return 0 - - -cdef int cb_on_headers_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_status_complete() - pyparser._on_headers_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - if pyparser._upgraded or pyparser._cparser.method == cparser.HTTP_CONNECT: - return 2 - else: - return 0 - - -cdef int cb_on_body(cparser.llhttp_t* parser, - const char *at, size_t length) except -1: - cdef HttpParser pyparser = parser.data - cdef bytes body = at[:length] - try: - pyparser._payload.feed_data(body, length) - except BaseException as underlying_exc: - reraised_exc = underlying_exc - if pyparser._payload_exception is not None: - reraised_exc = pyparser._payload_exception(str(underlying_exc)) - - set_exception(pyparser._payload, reraised_exc, underlying_exc) - - pyparser._payload_error = 1 - return -1 - else: - return 0 - - -cdef int cb_on_message_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._started = False - pyparser._on_message_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef int cb_on_chunk_header(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_chunk_header() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef int cb_on_chunk_complete(cparser.llhttp_t* parser) except -1: - cdef HttpParser pyparser = parser.data - try: - pyparser._on_chunk_complete() - except BaseException as exc: - pyparser._last_error = exc - return -1 - else: - return 0 - - -cdef parser_error_from_errno(cparser.llhttp_t* parser, data, pointer): - cdef cparser.llhttp_errno_t errno = cparser.llhttp_get_errno(parser) - cdef bytes desc = cparser.llhttp_get_error_reason(parser) - - err_msg = "{}:\n\n {!r}\n {}".format(desc.decode("latin-1"), data, pointer) - - if errno in {cparser.HPE_CB_MESSAGE_BEGIN, - cparser.HPE_CB_HEADERS_COMPLETE, - cparser.HPE_CB_MESSAGE_COMPLETE, - cparser.HPE_CB_CHUNK_HEADER, - cparser.HPE_CB_CHUNK_COMPLETE, - cparser.HPE_INVALID_CONSTANT, - cparser.HPE_INVALID_HEADER_TOKEN, - cparser.HPE_INVALID_CONTENT_LENGTH, - cparser.HPE_INVALID_CHUNK_SIZE, - cparser.HPE_INVALID_EOF_STATE, - cparser.HPE_INVALID_TRANSFER_ENCODING}: - return BadHttpMessage(err_msg) - elif errno == cparser.HPE_INVALID_METHOD: - return BadHttpMethod(error=err_msg) - elif errno in {cparser.HPE_INVALID_STATUS, - cparser.HPE_INVALID_VERSION}: - return BadStatusLine(error=err_msg) - elif errno == cparser.HPE_INVALID_URL: - return InvalidURLError(err_msg) - - return BadHttpMessage(err_msg) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-darwin.so deleted file mode 100755 index c1ed806..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.pyx b/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.pyx deleted file mode 100644 index 7989c18..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_http_writer.pyx +++ /dev/null @@ -1,162 +0,0 @@ -from cpython.bytes cimport PyBytes_FromStringAndSize -from cpython.exc cimport PyErr_NoMemory -from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc -from cpython.object cimport PyObject_Str -from libc.stdint cimport uint8_t, uint64_t -from libc.string cimport memcpy - -from multidict import istr - -DEF BUF_SIZE = 16 * 1024 # 16KiB - -cdef object _istr = istr - - -# ----------------- writer --------------------------- - -cdef struct Writer: - char *buf - Py_ssize_t size - Py_ssize_t pos - bint heap_allocated - -cdef inline void _init_writer(Writer* writer, char *buf): - writer.buf = buf - writer.size = BUF_SIZE - writer.pos = 0 - writer.heap_allocated = 0 - - -cdef inline void _release_writer(Writer* writer): - if writer.heap_allocated: - PyMem_Free(writer.buf) - - -cdef inline int _write_byte(Writer* writer, uint8_t ch): - cdef char * buf - cdef Py_ssize_t size - - if writer.pos == writer.size: - # reallocate - size = writer.size + BUF_SIZE - if not writer.heap_allocated: - buf = PyMem_Malloc(size) - if buf == NULL: - PyErr_NoMemory() - return -1 - memcpy(buf, writer.buf, writer.size) - else: - buf = PyMem_Realloc(writer.buf, size) - if buf == NULL: - PyErr_NoMemory() - return -1 - writer.buf = buf - writer.size = size - writer.heap_allocated = 1 - writer.buf[writer.pos] = ch - writer.pos += 1 - return 0 - - -cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): - cdef uint64_t utf = symbol - - if utf < 0x80: - return _write_byte(writer, utf) - elif utf < 0x800: - if _write_byte(writer, (0xc0 | (utf >> 6))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - elif 0xD800 <= utf <= 0xDFFF: - # surogate pair, ignored - return 0 - elif utf < 0x10000: - if _write_byte(writer, (0xe0 | (utf >> 12))) < 0: - return -1 - if _write_byte(writer, (0x80 | ((utf >> 6) & 0x3f))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - elif utf > 0x10FFFF: - # symbol is too large - return 0 - else: - if _write_byte(writer, (0xf0 | (utf >> 18))) < 0: - return -1 - if _write_byte(writer, - (0x80 | ((utf >> 12) & 0x3f))) < 0: - return -1 - if _write_byte(writer, - (0x80 | ((utf >> 6) & 0x3f))) < 0: - return -1 - return _write_byte(writer, (0x80 | (utf & 0x3f))) - - -cdef inline int _write_str(Writer* writer, str s): - cdef Py_UCS4 ch - for ch in s: - if _write_utf8(writer, ch) < 0: - return -1 - - -cdef inline int _write_str_raise_on_nlcr(Writer* writer, object s): - cdef Py_UCS4 ch - cdef str out_str - if type(s) is str: - out_str = s - elif type(s) is _istr: - out_str = PyObject_Str(s) - elif not isinstance(s, str): - raise TypeError("Cannot serialize non-str key {!r}".format(s)) - else: - out_str = str(s) - - for ch in out_str: - if ch == 0x0D or ch == 0x0A: - raise ValueError( - "Newline or carriage return detected in headers. " - "Potential header injection attack." - ) - if _write_utf8(writer, ch) < 0: - return -1 - - -# --------------- _serialize_headers ---------------------- - -def _serialize_headers(str status_line, headers): - cdef Writer writer - cdef object key - cdef object val - cdef char buf[BUF_SIZE] - - _init_writer(&writer, buf) - - try: - if _write_str(&writer, status_line) < 0: - raise - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - for key, val in headers.items(): - if _write_str_raise_on_nlcr(&writer, key) < 0: - raise - if _write_byte(&writer, b':') < 0: - raise - if _write_byte(&writer, b' ') < 0: - raise - if _write_str_raise_on_nlcr(&writer, val) < 0: - raise - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - if _write_byte(&writer, b'\r') < 0: - raise - if _write_byte(&writer, b'\n') < 0: - raise - - return PyBytes_FromStringAndSize(writer.buf, writer.pos) - finally: - _release_writer(&writer) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash deleted file mode 100644 index f782cc2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -b01999d409b29bd916e067bc963d5f2d9ee63cfc9ae0bccb769910131417bf93 /Users/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pxd diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash deleted file mode 100644 index cfb49b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash +++ /dev/null @@ -1 +0,0 @@ -0478ceb55d0ed30ef1a7da742cd003449bc69a07cf9fdb06789bd2b347cbfffe /Users/runner/work/aiohttp/aiohttp/aiohttp/_websocket/mask.pyx diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash deleted file mode 100644 index e24cce4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash +++ /dev/null @@ -1 +0,0 @@ -9e5fe78ed0ebce5414d2b8e01868d90c1facc20b84d2d5ff6c23e86e44a155ae /Users/runner/work/aiohttp/aiohttp/aiohttp/_websocket/reader_c.pxd diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py deleted file mode 100644 index 836257c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py deleted file mode 100644 index 0bb58df..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/helpers.py +++ /dev/null @@ -1,147 +0,0 @@ -"""Helpers for WebSocket protocol versions 13 and 8.""" - -import functools -import re -from struct import Struct -from typing import TYPE_CHECKING, Final, List, Optional, Pattern, Tuple - -from ..helpers import NO_EXTENSIONS -from .models import WSHandshakeError - -UNPACK_LEN3 = Struct("!Q").unpack_from -UNPACK_CLOSE_CODE = Struct("!H").unpack -PACK_LEN1 = Struct("!BB").pack -PACK_LEN2 = Struct("!BBH").pack -PACK_LEN3 = Struct("!BBQ").pack -PACK_CLOSE_CODE = Struct("!H").pack -PACK_RANDBITS = Struct("!L").pack -MSG_SIZE: Final[int] = 2**14 -MASK_LEN: Final[int] = 4 - -WS_KEY: Final[bytes] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - -# Used by _websocket_mask_python -@functools.lru_cache -def _xor_table() -> List[bytes]: - return [bytes(a ^ b for a in range(256)) for b in range(256)] - - -def _websocket_mask_python(mask: bytes, data: bytearray) -> None: - """Websocket masking function. - - `mask` is a `bytes` object of length 4; `data` is a `bytearray` - object of any length. The contents of `data` are masked with `mask`, - as specified in section 5.3 of RFC 6455. - - Note that this function mutates the `data` argument. - - This pure-python implementation may be replaced by an optimized - version when available. - - """ - assert isinstance(data, bytearray), data - assert len(mask) == 4, mask - - if data: - _XOR_TABLE = _xor_table() - a, b, c, d = (_XOR_TABLE[n] for n in mask) - data[::4] = data[::4].translate(a) - data[1::4] = data[1::4].translate(b) - data[2::4] = data[2::4].translate(c) - data[3::4] = data[3::4].translate(d) - - -if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover - websocket_mask = _websocket_mask_python -else: - try: - from .mask import _websocket_mask_cython # type: ignore[import-not-found] - - websocket_mask = _websocket_mask_cython - except ImportError: # pragma: no cover - websocket_mask = _websocket_mask_python - - -_WS_EXT_RE: Final[Pattern[str]] = re.compile( - r"^(?:;\s*(?:" - r"(server_no_context_takeover)|" - r"(client_no_context_takeover)|" - r"(server_max_window_bits(?:=(\d+))?)|" - r"(client_max_window_bits(?:=(\d+))?)))*$" -) - -_WS_EXT_RE_SPLIT: Final[Pattern[str]] = re.compile(r"permessage-deflate([^,]+)?") - - -def ws_ext_parse(extstr: Optional[str], isserver: bool = False) -> Tuple[int, bool]: - if not extstr: - return 0, False - - compress = 0 - notakeover = False - for ext in _WS_EXT_RE_SPLIT.finditer(extstr): - defext = ext.group(1) - # Return compress = 15 when get `permessage-deflate` - if not defext: - compress = 15 - break - match = _WS_EXT_RE.match(defext) - if match: - compress = 15 - if isserver: - # Server never fail to detect compress handshake. - # Server does not need to send max wbit to client - if match.group(4): - compress = int(match.group(4)) - # Group3 must match if group4 matches - # Compress wbit 8 does not support in zlib - # If compress level not support, - # CONTINUE to next extension - if compress > 15 or compress < 9: - compress = 0 - continue - if match.group(1): - notakeover = True - # Ignore regex group 5 & 6 for client_max_window_bits - break - else: - if match.group(6): - compress = int(match.group(6)) - # Group5 must match if group6 matches - # Compress wbit 8 does not support in zlib - # If compress level not support, - # FAIL the parse progress - if compress > 15 or compress < 9: - raise WSHandshakeError("Invalid window size") - if match.group(2): - notakeover = True - # Ignore regex group 5 & 6 for client_max_window_bits - break - # Return Fail if client side and not match - elif not isserver: - raise WSHandshakeError("Extension for deflate not supported" + ext.group(1)) - - return compress, notakeover - - -def ws_ext_gen( - compress: int = 15, isserver: bool = False, server_notakeover: bool = False -) -> str: - # client_notakeover=False not used for server - # compress wbit 8 does not support in zlib - if compress < 9 or compress > 15: - raise ValueError( - "Compress wbits must between 9 and 15, zlib does not support wbits=8" - ) - enabledext = ["permessage-deflate"] - if not isserver: - enabledext.append("client_max_window_bits") - - if compress < 15: - enabledext.append("server_max_window_bits=" + str(compress)) - if server_notakeover: - enabledext.append("server_no_context_takeover") - # if client_notakeover: - # enabledext.append('client_no_context_takeover') - return "; ".join(enabledext) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-darwin.so deleted file mode 100755 index 5cbb2c0..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd deleted file mode 100644 index 90983de..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pxd +++ /dev/null @@ -1,3 +0,0 @@ -"""Cython declarations for websocket masking.""" - -cpdef void _websocket_mask_cython(bytes mask, bytearray data) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx deleted file mode 100644 index 2d956c8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/mask.pyx +++ /dev/null @@ -1,48 +0,0 @@ -from cpython cimport PyBytes_AsString - - -#from cpython cimport PyByteArray_AsString # cython still not exports that -cdef extern from "Python.h": - char* PyByteArray_AsString(bytearray ba) except NULL - -from libc.stdint cimport uint32_t, uint64_t, uintmax_t - - -cpdef void _websocket_mask_cython(bytes mask, bytearray data): - """Note, this function mutates its `data` argument - """ - cdef: - Py_ssize_t data_len, i - # bit operations on signed integers are implementation-specific - unsigned char * in_buf - const unsigned char * mask_buf - uint32_t uint32_msk - uint64_t uint64_msk - - assert len(mask) == 4 - - data_len = len(data) - in_buf = PyByteArray_AsString(data) - mask_buf = PyBytes_AsString(mask) - uint32_msk = (mask_buf)[0] - - # TODO: align in_data ptr to achieve even faster speeds - # does it need in python ?! malloc() always aligns to sizeof(long) bytes - - if sizeof(size_t) >= 8: - uint64_msk = uint32_msk - uint64_msk = (uint64_msk << 32) | uint32_msk - - while data_len >= 8: - (in_buf)[0] ^= uint64_msk - in_buf += 8 - data_len -= 8 - - - while data_len >= 4: - (in_buf)[0] ^= uint32_msk - in_buf += 4 - data_len -= 4 - - for i in range(0, data_len): - in_buf[i] ^= mask_buf[i] diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/models.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/models.py deleted file mode 100644 index 7e89b96..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/models.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Models for WebSocket protocol versions 13 and 8.""" - -import json -from enum import IntEnum -from typing import Any, Callable, Final, NamedTuple, Optional, cast - -WS_DEFLATE_TRAILING: Final[bytes] = bytes([0x00, 0x00, 0xFF, 0xFF]) - - -class WSCloseCode(IntEnum): - OK = 1000 - GOING_AWAY = 1001 - PROTOCOL_ERROR = 1002 - UNSUPPORTED_DATA = 1003 - ABNORMAL_CLOSURE = 1006 - INVALID_TEXT = 1007 - POLICY_VIOLATION = 1008 - MESSAGE_TOO_BIG = 1009 - MANDATORY_EXTENSION = 1010 - INTERNAL_ERROR = 1011 - SERVICE_RESTART = 1012 - TRY_AGAIN_LATER = 1013 - BAD_GATEWAY = 1014 - - -class WSMsgType(IntEnum): - # websocket spec types - CONTINUATION = 0x0 - TEXT = 0x1 - BINARY = 0x2 - PING = 0x9 - PONG = 0xA - CLOSE = 0x8 - - # aiohttp specific types - CLOSING = 0x100 - CLOSED = 0x101 - ERROR = 0x102 - - text = TEXT - binary = BINARY - ping = PING - pong = PONG - close = CLOSE - closing = CLOSING - closed = CLOSED - error = ERROR - - -class WSMessage(NamedTuple): - type: WSMsgType - # To type correctly, this would need some kind of tagged union for each type. - data: Any - extra: Optional[str] - - def json(self, *, loads: Callable[[Any], Any] = json.loads) -> Any: - """Return parsed JSON data. - - .. versionadded:: 0.22 - """ - return loads(self.data) - - -# Constructing the tuple directly to avoid the overhead of -# the lambda and arg processing since NamedTuples are constructed -# with a run time built lambda -# https://github.com/python/cpython/blob/d83fcf8371f2f33c7797bc8f5423a8bca8c46e5c/Lib/collections/__init__.py#L441 -WS_CLOSED_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSED, None, None)) -WS_CLOSING_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSING, None, None)) - - -class WebSocketError(Exception): - """WebSocket protocol parser error.""" - - def __init__(self, code: int, message: str) -> None: - self.code = code - super().__init__(code, message) - - def __str__(self) -> str: - return cast(str, self.args[1]) - - -class WSHandshakeError(Exception): - """WebSocket protocol handshake error.""" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader.py deleted file mode 100644 index 23f3226..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -from typing import TYPE_CHECKING - -from ..helpers import NO_EXTENSIONS - -if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover - from .reader_py import ( - WebSocketDataQueue as WebSocketDataQueuePython, - WebSocketReader as WebSocketReaderPython, - ) - - WebSocketReader = WebSocketReaderPython - WebSocketDataQueue = WebSocketDataQueuePython -else: - try: - from .reader_c import ( # type: ignore[import-not-found] - WebSocketDataQueue as WebSocketDataQueueCython, - WebSocketReader as WebSocketReaderCython, - ) - - WebSocketReader = WebSocketReaderCython - WebSocketDataQueue = WebSocketDataQueueCython - except ImportError: # pragma: no cover - from .reader_py import ( - WebSocketDataQueue as WebSocketDataQueuePython, - WebSocketReader as WebSocketReaderPython, - ) - - WebSocketReader = WebSocketReaderPython - WebSocketDataQueue = WebSocketDataQueuePython diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-darwin.so deleted file mode 100755 index 9c72006..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd deleted file mode 100644 index a7620d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.pxd +++ /dev/null @@ -1,110 +0,0 @@ -import cython - -from .mask cimport _websocket_mask_cython as websocket_mask - - -cdef unsigned int READ_HEADER -cdef unsigned int READ_PAYLOAD_LENGTH -cdef unsigned int READ_PAYLOAD_MASK -cdef unsigned int READ_PAYLOAD - -cdef int OP_CODE_NOT_SET -cdef int OP_CODE_CONTINUATION -cdef int OP_CODE_TEXT -cdef int OP_CODE_BINARY -cdef int OP_CODE_CLOSE -cdef int OP_CODE_PING -cdef int OP_CODE_PONG - -cdef int COMPRESSED_NOT_SET -cdef int COMPRESSED_FALSE -cdef int COMPRESSED_TRUE - -cdef object UNPACK_LEN3 -cdef object UNPACK_CLOSE_CODE -cdef object TUPLE_NEW - -cdef object WSMsgType -cdef object WSMessage - -cdef object WS_MSG_TYPE_TEXT -cdef object WS_MSG_TYPE_BINARY - -cdef set ALLOWED_CLOSE_CODES -cdef set MESSAGE_TYPES_WITH_CONTENT - -cdef tuple EMPTY_FRAME -cdef tuple EMPTY_FRAME_ERROR - -cdef class WebSocketDataQueue: - - cdef unsigned int _size - cdef public object _protocol - cdef unsigned int _limit - cdef object _loop - cdef bint _eof - cdef object _waiter - cdef object _exception - cdef public object _buffer - cdef object _get_buffer - cdef object _put_buffer - - cdef void _release_waiter(self) - - cpdef void feed_data(self, object data, unsigned int size) - - @cython.locals(size="unsigned int") - cdef _read_from_buffer(self) - -cdef class WebSocketReader: - - cdef WebSocketDataQueue queue - cdef unsigned int _max_msg_size - - cdef Exception _exc - cdef bytearray _partial - cdef unsigned int _state - - cdef int _opcode - cdef bint _frame_fin - cdef int _frame_opcode - cdef list _payload_fragments - cdef Py_ssize_t _frame_payload_len - - cdef bytes _tail - cdef bint _has_mask - cdef bytes _frame_mask - cdef Py_ssize_t _payload_bytes_to_read - cdef unsigned int _payload_len_flag - cdef int _compressed - cdef object _decompressobj - cdef bint _compress - - cpdef tuple feed_data(self, object data) - - @cython.locals( - is_continuation=bint, - fin=bint, - has_partial=bint, - payload_merged=bytes, - ) - cpdef void _handle_frame(self, bint fin, int opcode, object payload, int compressed) except * - - @cython.locals( - start_pos=Py_ssize_t, - data_len=Py_ssize_t, - length=Py_ssize_t, - chunk_size=Py_ssize_t, - chunk_len=Py_ssize_t, - data_len=Py_ssize_t, - data_cstr="const unsigned char *", - first_byte="unsigned char", - second_byte="unsigned char", - f_start_pos=Py_ssize_t, - f_end_pos=Py_ssize_t, - has_mask=bint, - fin=bint, - had_fragments=Py_ssize_t, - payload_bytearray=bytearray, - ) - cpdef void _feed_data(self, bytes data) except * diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py deleted file mode 100644 index 5166d7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_c.py +++ /dev/null @@ -1,478 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -import asyncio -import builtins -from collections import deque -from typing import Deque, Final, Optional, Set, Tuple, Union - -from ..base_protocol import BaseProtocol -from ..compression_utils import ZLibDecompressor -from ..helpers import _EXC_SENTINEL, set_exception -from ..streams import EofStream -from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask -from .models import ( - WS_DEFLATE_TRAILING, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) - -ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} - -# States for the reader, used to parse the WebSocket frame -# integer values are used so they can be cythonized -READ_HEADER = 1 -READ_PAYLOAD_LENGTH = 2 -READ_PAYLOAD_MASK = 3 -READ_PAYLOAD = 4 - -WS_MSG_TYPE_BINARY = WSMsgType.BINARY -WS_MSG_TYPE_TEXT = WSMsgType.TEXT - -# WSMsgType values unpacked so they can by cythonized to ints -OP_CODE_NOT_SET = -1 -OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value -OP_CODE_TEXT = WSMsgType.TEXT.value -OP_CODE_BINARY = WSMsgType.BINARY.value -OP_CODE_CLOSE = WSMsgType.CLOSE.value -OP_CODE_PING = WSMsgType.PING.value -OP_CODE_PONG = WSMsgType.PONG.value - -EMPTY_FRAME_ERROR = (True, b"") -EMPTY_FRAME = (False, b"") - -COMPRESSED_NOT_SET = -1 -COMPRESSED_FALSE = 0 -COMPRESSED_TRUE = 1 - -TUPLE_NEW = tuple.__new__ - -cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd - - -class WebSocketDataQueue: - """WebSocketDataQueue resumes and pauses an underlying stream. - - It is a destination for WebSocket data. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Union[BaseException, None] = None - self._buffer: Deque[Tuple[WSMessage, int]] = deque() - self._get_buffer = self._buffer.popleft - self._put_buffer = self._buffer.append - - def is_eof(self) -> bool: - return self._eof - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: builtins.BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def _release_waiter(self) -> None: - if (waiter := self._waiter) is None: - return - self._waiter = None - if not waiter.done(): - waiter.set_result(None) - - def feed_eof(self) -> None: - self._eof = True - self._release_waiter() - self._exception = None # Break cyclic references - - def feed_data(self, data: "WSMessage", size: "cython_int") -> None: - self._size += size - self._put_buffer((data, size)) - self._release_waiter() - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> WSMessage: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - return self._read_from_buffer() - - def _read_from_buffer(self) -> WSMessage: - if self._buffer: - data, size = self._get_buffer() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - -class WebSocketReader: - def __init__( - self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True - ) -> None: - self.queue = queue - self._max_msg_size = max_msg_size - - self._exc: Optional[Exception] = None - self._partial = bytearray() - self._state = READ_HEADER - - self._opcode: int = OP_CODE_NOT_SET - self._frame_fin = False - self._frame_opcode: int = OP_CODE_NOT_SET - self._payload_fragments: list[bytes] = [] - self._frame_payload_len = 0 - - self._tail: bytes = b"" - self._has_mask = False - self._frame_mask: Optional[bytes] = None - self._payload_bytes_to_read = 0 - self._payload_len_flag = 0 - self._compressed: int = COMPRESSED_NOT_SET - self._decompressobj: Optional[ZLibDecompressor] = None - self._compress = compress - - def feed_eof(self) -> None: - self.queue.feed_eof() - - # data can be bytearray on Windows because proactor event loop uses bytearray - # and asyncio types this to Union[bytes, bytearray, memoryview] so we need - # coerce data to bytes if it is not - def feed_data( - self, data: Union[bytes, bytearray, memoryview] - ) -> Tuple[bool, bytes]: - if type(data) is not bytes: - data = bytes(data) - - if self._exc is not None: - return True, data - - try: - self._feed_data(data) - except Exception as exc: - self._exc = exc - set_exception(self.queue, exc) - return EMPTY_FRAME_ERROR - - return EMPTY_FRAME - - def _handle_frame( - self, - fin: bool, - opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int - payload: Union[bytes, bytearray], - compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int - ) -> None: - msg: WSMessage - if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: - # Validate continuation frames before processing - if opcode == OP_CODE_CONTINUATION and self._opcode == OP_CODE_NOT_SET: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Continuation frame for non started message", - ) - - # load text/binary - if not fin: - # got partial frame payload - if opcode != OP_CODE_CONTINUATION: - self._opcode = opcode - self._partial += payload - if self._max_msg_size and len(self._partial) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(self._partial)} " - f"exceeds limit {self._max_msg_size}", - ) - return - - has_partial = bool(self._partial) - if opcode == OP_CODE_CONTINUATION: - opcode = self._opcode - self._opcode = OP_CODE_NOT_SET - # previous frame was non finished - # we should get continuation opcode - elif has_partial: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "The opcode in non-fin frame is expected " - f"to be zero, got {opcode!r}", - ) - - assembled_payload: Union[bytes, bytearray] - if has_partial: - assembled_payload = self._partial + payload - self._partial.clear() - else: - assembled_payload = payload - - if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(assembled_payload)} " - f"exceeds limit {self._max_msg_size}", - ) - - # Decompress process must to be done after all packets - # received. - if compressed: - if not self._decompressobj: - self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) - # XXX: It's possible that the zlib backend (isal is known to - # do this, maybe others too?) will return max_length bytes, - # but internally buffer more data such that the payload is - # >max_length, so we return one extra byte and if we're able - # to do that, then the message is too big. - payload_merged = self._decompressobj.decompress_sync( - assembled_payload + WS_DEFLATE_TRAILING, - ( - self._max_msg_size + 1 - if self._max_msg_size - else self._max_msg_size - ), - ) - if self._max_msg_size and len(payload_merged) > self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Decompressed message exceeds size limit {self._max_msg_size}", - ) - elif type(assembled_payload) is bytes: - payload_merged = assembled_payload - else: - payload_merged = bytes(assembled_payload) - - if opcode == OP_CODE_TEXT: - try: - text = payload_merged.decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - - # XXX: The Text and Binary messages here can be a performance - # bottleneck, so we use tuple.__new__ to improve performance. - # This is not type safe, but many tests should fail in - # test_client_ws_functional.py if this is wrong. - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), - len(payload_merged), - ) - else: - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), - len(payload_merged), - ) - elif opcode == OP_CODE_CLOSE: - if len(payload) >= 2: - close_code = UNPACK_CLOSE_CODE(payload[:2])[0] - if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close code: {close_code}", - ) - try: - close_message = payload[2:].decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) - elif payload: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close frame: {fin} {opcode} {payload!r}", - ) - else: - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) - - self.queue.feed_data(msg, 0) - elif opcode == OP_CODE_PING: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) - self.queue.feed_data(msg, len(payload)) - elif opcode == OP_CODE_PONG: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) - self.queue.feed_data(msg, len(payload)) - else: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" - ) - - def _feed_data(self, data: bytes) -> None: - """Return the next frame from the socket.""" - if self._tail: - data, self._tail = self._tail + data, b"" - - start_pos: int = 0 - data_len = len(data) - data_cstr = data - - while True: - # read header - if self._state == READ_HEADER: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - - fin = (first_byte >> 7) & 1 - rsv1 = (first_byte >> 6) & 1 - rsv2 = (first_byte >> 5) & 1 - rsv3 = (first_byte >> 4) & 1 - opcode = first_byte & 0xF - - # frame-fin = %x0 ; more frames of this message follow - # / %x1 ; final frame of this message - # frame-rsv1 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv2 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv3 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # - # Remove rsv1 from this test for deflate development - if rsv2 or rsv3 or (rsv1 and not self._compress): - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - if opcode > 0x7 and fin == 0: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received fragmented control frame", - ) - - has_mask = (second_byte >> 7) & 1 - length = second_byte & 0x7F - - # Control frames MUST have a payload - # length of 125 bytes or less - if opcode > 0x7 and length > 125: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Control frame payload cannot be larger than 125 bytes", - ) - - # Set compress status if last package is FIN - # OR set compress status if this is first fragment - # Raise error if not first fragment with rsv1 = 0x1 - if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: - self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE - elif rsv1: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - self._frame_fin = bool(fin) - self._frame_opcode = opcode - self._has_mask = bool(has_mask) - self._payload_len_flag = length - self._state = READ_PAYLOAD_LENGTH - - # read payload length - if self._state == READ_PAYLOAD_LENGTH: - len_flag = self._payload_len_flag - if len_flag == 126: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - self._payload_bytes_to_read = first_byte << 8 | second_byte - elif len_flag > 126: - if data_len - start_pos < 8: - break - self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] - start_pos += 8 - else: - self._payload_bytes_to_read = len_flag - - self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD - - # read payload mask - if self._state == READ_PAYLOAD_MASK: - if data_len - start_pos < 4: - break - self._frame_mask = data_cstr[start_pos : start_pos + 4] - start_pos += 4 - self._state = READ_PAYLOAD - - if self._state == READ_PAYLOAD: - chunk_len = data_len - start_pos - if self._payload_bytes_to_read >= chunk_len: - f_end_pos = data_len - self._payload_bytes_to_read -= chunk_len - else: - f_end_pos = start_pos + self._payload_bytes_to_read - self._payload_bytes_to_read = 0 - - had_fragments = self._frame_payload_len - self._frame_payload_len += f_end_pos - start_pos - f_start_pos = start_pos - start_pos = f_end_pos - - if self._payload_bytes_to_read != 0: - # If we don't have a complete frame, we need to save the - # data for the next call to feed_data. - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - break - - payload: Union[bytes, bytearray] - if had_fragments: - # We have to join the payload fragments get the payload - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - if self._has_mask: - assert self._frame_mask is not None - payload_bytearray = bytearray(b"".join(self._payload_fragments)) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = b"".join(self._payload_fragments) - self._payload_fragments.clear() - elif self._has_mask: - assert self._frame_mask is not None - payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] - if type(payload_bytearray) is not bytearray: # pragma: no branch - # Cython will do the conversion for us - # but we need to do it for Python and we - # will always get here in Python - payload_bytearray = bytearray(payload_bytearray) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = data_cstr[f_start_pos:f_end_pos] - - self._handle_frame( - self._frame_fin, self._frame_opcode, payload, self._compressed - ) - self._frame_payload_len = 0 - self._state = READ_HEADER - - # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. - self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py deleted file mode 100644 index 5166d7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/reader_py.py +++ /dev/null @@ -1,478 +0,0 @@ -"""Reader for WebSocket protocol versions 13 and 8.""" - -import asyncio -import builtins -from collections import deque -from typing import Deque, Final, Optional, Set, Tuple, Union - -from ..base_protocol import BaseProtocol -from ..compression_utils import ZLibDecompressor -from ..helpers import _EXC_SENTINEL, set_exception -from ..streams import EofStream -from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask -from .models import ( - WS_DEFLATE_TRAILING, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) - -ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} - -# States for the reader, used to parse the WebSocket frame -# integer values are used so they can be cythonized -READ_HEADER = 1 -READ_PAYLOAD_LENGTH = 2 -READ_PAYLOAD_MASK = 3 -READ_PAYLOAD = 4 - -WS_MSG_TYPE_BINARY = WSMsgType.BINARY -WS_MSG_TYPE_TEXT = WSMsgType.TEXT - -# WSMsgType values unpacked so they can by cythonized to ints -OP_CODE_NOT_SET = -1 -OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value -OP_CODE_TEXT = WSMsgType.TEXT.value -OP_CODE_BINARY = WSMsgType.BINARY.value -OP_CODE_CLOSE = WSMsgType.CLOSE.value -OP_CODE_PING = WSMsgType.PING.value -OP_CODE_PONG = WSMsgType.PONG.value - -EMPTY_FRAME_ERROR = (True, b"") -EMPTY_FRAME = (False, b"") - -COMPRESSED_NOT_SET = -1 -COMPRESSED_FALSE = 0 -COMPRESSED_TRUE = 1 - -TUPLE_NEW = tuple.__new__ - -cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd - - -class WebSocketDataQueue: - """WebSocketDataQueue resumes and pauses an underlying stream. - - It is a destination for WebSocket data. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Union[BaseException, None] = None - self._buffer: Deque[Tuple[WSMessage, int]] = deque() - self._get_buffer = self._buffer.popleft - self._put_buffer = self._buffer.append - - def is_eof(self) -> bool: - return self._eof - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: builtins.BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def _release_waiter(self) -> None: - if (waiter := self._waiter) is None: - return - self._waiter = None - if not waiter.done(): - waiter.set_result(None) - - def feed_eof(self) -> None: - self._eof = True - self._release_waiter() - self._exception = None # Break cyclic references - - def feed_data(self, data: "WSMessage", size: "cython_int") -> None: - self._size += size - self._put_buffer((data, size)) - self._release_waiter() - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> WSMessage: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - return self._read_from_buffer() - - def _read_from_buffer(self) -> WSMessage: - if self._buffer: - data, size = self._get_buffer() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - -class WebSocketReader: - def __init__( - self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True - ) -> None: - self.queue = queue - self._max_msg_size = max_msg_size - - self._exc: Optional[Exception] = None - self._partial = bytearray() - self._state = READ_HEADER - - self._opcode: int = OP_CODE_NOT_SET - self._frame_fin = False - self._frame_opcode: int = OP_CODE_NOT_SET - self._payload_fragments: list[bytes] = [] - self._frame_payload_len = 0 - - self._tail: bytes = b"" - self._has_mask = False - self._frame_mask: Optional[bytes] = None - self._payload_bytes_to_read = 0 - self._payload_len_flag = 0 - self._compressed: int = COMPRESSED_NOT_SET - self._decompressobj: Optional[ZLibDecompressor] = None - self._compress = compress - - def feed_eof(self) -> None: - self.queue.feed_eof() - - # data can be bytearray on Windows because proactor event loop uses bytearray - # and asyncio types this to Union[bytes, bytearray, memoryview] so we need - # coerce data to bytes if it is not - def feed_data( - self, data: Union[bytes, bytearray, memoryview] - ) -> Tuple[bool, bytes]: - if type(data) is not bytes: - data = bytes(data) - - if self._exc is not None: - return True, data - - try: - self._feed_data(data) - except Exception as exc: - self._exc = exc - set_exception(self.queue, exc) - return EMPTY_FRAME_ERROR - - return EMPTY_FRAME - - def _handle_frame( - self, - fin: bool, - opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int - payload: Union[bytes, bytearray], - compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int - ) -> None: - msg: WSMessage - if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: - # Validate continuation frames before processing - if opcode == OP_CODE_CONTINUATION and self._opcode == OP_CODE_NOT_SET: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Continuation frame for non started message", - ) - - # load text/binary - if not fin: - # got partial frame payload - if opcode != OP_CODE_CONTINUATION: - self._opcode = opcode - self._partial += payload - if self._max_msg_size and len(self._partial) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(self._partial)} " - f"exceeds limit {self._max_msg_size}", - ) - return - - has_partial = bool(self._partial) - if opcode == OP_CODE_CONTINUATION: - opcode = self._opcode - self._opcode = OP_CODE_NOT_SET - # previous frame was non finished - # we should get continuation opcode - elif has_partial: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "The opcode in non-fin frame is expected " - f"to be zero, got {opcode!r}", - ) - - assembled_payload: Union[bytes, bytearray] - if has_partial: - assembled_payload = self._partial + payload - self._partial.clear() - else: - assembled_payload = payload - - if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Message size {len(assembled_payload)} " - f"exceeds limit {self._max_msg_size}", - ) - - # Decompress process must to be done after all packets - # received. - if compressed: - if not self._decompressobj: - self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) - # XXX: It's possible that the zlib backend (isal is known to - # do this, maybe others too?) will return max_length bytes, - # but internally buffer more data such that the payload is - # >max_length, so we return one extra byte and if we're able - # to do that, then the message is too big. - payload_merged = self._decompressobj.decompress_sync( - assembled_payload + WS_DEFLATE_TRAILING, - ( - self._max_msg_size + 1 - if self._max_msg_size - else self._max_msg_size - ), - ) - if self._max_msg_size and len(payload_merged) > self._max_msg_size: - raise WebSocketError( - WSCloseCode.MESSAGE_TOO_BIG, - f"Decompressed message exceeds size limit {self._max_msg_size}", - ) - elif type(assembled_payload) is bytes: - payload_merged = assembled_payload - else: - payload_merged = bytes(assembled_payload) - - if opcode == OP_CODE_TEXT: - try: - text = payload_merged.decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - - # XXX: The Text and Binary messages here can be a performance - # bottleneck, so we use tuple.__new__ to improve performance. - # This is not type safe, but many tests should fail in - # test_client_ws_functional.py if this is wrong. - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), - len(payload_merged), - ) - else: - self.queue.feed_data( - TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), - len(payload_merged), - ) - elif opcode == OP_CODE_CLOSE: - if len(payload) >= 2: - close_code = UNPACK_CLOSE_CODE(payload[:2])[0] - if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close code: {close_code}", - ) - try: - close_message = payload[2:].decode("utf-8") - except UnicodeDecodeError as exc: - raise WebSocketError( - WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" - ) from exc - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) - elif payload: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - f"Invalid close frame: {fin} {opcode} {payload!r}", - ) - else: - msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) - - self.queue.feed_data(msg, 0) - elif opcode == OP_CODE_PING: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) - self.queue.feed_data(msg, len(payload)) - elif opcode == OP_CODE_PONG: - msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) - self.queue.feed_data(msg, len(payload)) - else: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" - ) - - def _feed_data(self, data: bytes) -> None: - """Return the next frame from the socket.""" - if self._tail: - data, self._tail = self._tail + data, b"" - - start_pos: int = 0 - data_len = len(data) - data_cstr = data - - while True: - # read header - if self._state == READ_HEADER: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - - fin = (first_byte >> 7) & 1 - rsv1 = (first_byte >> 6) & 1 - rsv2 = (first_byte >> 5) & 1 - rsv3 = (first_byte >> 4) & 1 - opcode = first_byte & 0xF - - # frame-fin = %x0 ; more frames of this message follow - # / %x1 ; final frame of this message - # frame-rsv1 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv2 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # frame-rsv3 = %x0 ; - # 1 bit, MUST be 0 unless negotiated otherwise - # - # Remove rsv1 from this test for deflate development - if rsv2 or rsv3 or (rsv1 and not self._compress): - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - if opcode > 0x7 and fin == 0: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received fragmented control frame", - ) - - has_mask = (second_byte >> 7) & 1 - length = second_byte & 0x7F - - # Control frames MUST have a payload - # length of 125 bytes or less - if opcode > 0x7 and length > 125: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Control frame payload cannot be larger than 125 bytes", - ) - - # Set compress status if last package is FIN - # OR set compress status if this is first fragment - # Raise error if not first fragment with rsv1 = 0x1 - if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: - self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE - elif rsv1: - raise WebSocketError( - WSCloseCode.PROTOCOL_ERROR, - "Received frame with non-zero reserved bits", - ) - - self._frame_fin = bool(fin) - self._frame_opcode = opcode - self._has_mask = bool(has_mask) - self._payload_len_flag = length - self._state = READ_PAYLOAD_LENGTH - - # read payload length - if self._state == READ_PAYLOAD_LENGTH: - len_flag = self._payload_len_flag - if len_flag == 126: - if data_len - start_pos < 2: - break - first_byte = data_cstr[start_pos] - second_byte = data_cstr[start_pos + 1] - start_pos += 2 - self._payload_bytes_to_read = first_byte << 8 | second_byte - elif len_flag > 126: - if data_len - start_pos < 8: - break - self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] - start_pos += 8 - else: - self._payload_bytes_to_read = len_flag - - self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD - - # read payload mask - if self._state == READ_PAYLOAD_MASK: - if data_len - start_pos < 4: - break - self._frame_mask = data_cstr[start_pos : start_pos + 4] - start_pos += 4 - self._state = READ_PAYLOAD - - if self._state == READ_PAYLOAD: - chunk_len = data_len - start_pos - if self._payload_bytes_to_read >= chunk_len: - f_end_pos = data_len - self._payload_bytes_to_read -= chunk_len - else: - f_end_pos = start_pos + self._payload_bytes_to_read - self._payload_bytes_to_read = 0 - - had_fragments = self._frame_payload_len - self._frame_payload_len += f_end_pos - start_pos - f_start_pos = start_pos - start_pos = f_end_pos - - if self._payload_bytes_to_read != 0: - # If we don't have a complete frame, we need to save the - # data for the next call to feed_data. - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - break - - payload: Union[bytes, bytearray] - if had_fragments: - # We have to join the payload fragments get the payload - self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) - if self._has_mask: - assert self._frame_mask is not None - payload_bytearray = bytearray(b"".join(self._payload_fragments)) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = b"".join(self._payload_fragments) - self._payload_fragments.clear() - elif self._has_mask: - assert self._frame_mask is not None - payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] - if type(payload_bytearray) is not bytearray: # pragma: no branch - # Cython will do the conversion for us - # but we need to do it for Python and we - # will always get here in Python - payload_bytearray = bytearray(payload_bytearray) - websocket_mask(self._frame_mask, payload_bytearray) - payload = payload_bytearray - else: - payload = data_cstr[f_start_pos:f_end_pos] - - self._handle_frame( - self._frame_fin, self._frame_opcode, payload, self._compressed - ) - self._frame_payload_len = 0 - self._state = READ_HEADER - - # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. - self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/writer.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/writer.py deleted file mode 100644 index 9604202..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/_websocket/writer.py +++ /dev/null @@ -1,262 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" - -import asyncio -import random -import sys -from functools import partial -from typing import Final, Optional, Set, Union - -from ..base_protocol import BaseProtocol -from ..client_exceptions import ClientConnectionResetError -from ..compression_utils import ZLibBackend, ZLibCompressor -from .helpers import ( - MASK_LEN, - MSG_SIZE, - PACK_CLOSE_CODE, - PACK_LEN1, - PACK_LEN2, - PACK_LEN3, - PACK_RANDBITS, - websocket_mask, -) -from .models import WS_DEFLATE_TRAILING, WSMsgType - -DEFAULT_LIMIT: Final[int] = 2**16 - -# WebSocket opcode boundary: opcodes 0-7 are data frames, 8-15 are control frames -# Control frames (ping, pong, close) are never compressed -WS_CONTROL_FRAME_OPCODE: Final[int] = 8 - -# For websockets, keeping latency low is extremely important as implementations -# generally expect to be able to send and receive messages quickly. We use a -# larger chunk size to reduce the number of executor calls and avoid task -# creation overhead, since both are significant sources of latency when chunks -# are small. A size of 16KiB was chosen as a balance between avoiding task -# overhead and not blocking the event loop too long with synchronous compression. - -WEBSOCKET_MAX_SYNC_CHUNK_SIZE = 16 * 1024 - - -class WebSocketWriter: - """WebSocket writer. - - The writer is responsible for sending messages to the client. It is - created by the protocol when a connection is established. The writer - should avoid implementing any application logic and should only be - concerned with the low-level details of the WebSocket protocol. - """ - - def __init__( - self, - protocol: BaseProtocol, - transport: asyncio.Transport, - *, - use_mask: bool = False, - limit: int = DEFAULT_LIMIT, - random: random.Random = random.Random(), - compress: int = 0, - notakeover: bool = False, - ) -> None: - """Initialize a WebSocket writer.""" - self.protocol = protocol - self.transport = transport - self.use_mask = use_mask - self.get_random_bits = partial(random.getrandbits, 32) - self.compress = compress - self.notakeover = notakeover - self._closing = False - self._limit = limit - self._output_size = 0 - self._compressobj: Optional[ZLibCompressor] = None - self._send_lock = asyncio.Lock() - self._background_tasks: Set[asyncio.Task[None]] = set() - - async def send_frame( - self, message: bytes, opcode: int, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket with message as its payload.""" - if self._closing and not (opcode & WSMsgType.CLOSE): - raise ClientConnectionResetError("Cannot write to closing transport") - - if not (compress or self.compress) or opcode >= WS_CONTROL_FRAME_OPCODE: - # Non-compressed frames don't need lock or shield - self._write_websocket_frame(message, opcode, 0) - elif len(message) <= WEBSOCKET_MAX_SYNC_CHUNK_SIZE: - # Small compressed payloads - compress synchronously in event loop - # We need the lock even though sync compression has no await points. - # This prevents small frames from interleaving with large frames that - # compress in the executor, avoiding compressor state corruption. - async with self._send_lock: - self._send_compressed_frame_sync(message, opcode, compress) - else: - # Large compressed frames need shield to prevent corruption - # For large compressed frames, the entire compress+send - # operation must be atomic. If cancelled after compression but - # before send, the compressor state would be advanced but data - # not sent, corrupting subsequent frames. - # Create a task to shield from cancellation - # The lock is acquired inside the shielded task so the entire - # operation (lock + compress + send) completes atomically. - # Use eager_start on Python 3.12+ to avoid scheduling overhead - loop = asyncio.get_running_loop() - coro = self._send_compressed_frame_async_locked(message, opcode, compress) - if sys.version_info >= (3, 12): - send_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - send_task = loop.create_task(coro) - # Keep a strong reference to prevent garbage collection - self._background_tasks.add(send_task) - send_task.add_done_callback(self._background_tasks.discard) - await asyncio.shield(send_task) - - # It is safe to return control to the event loop when using compression - # after this point as we have already sent or buffered all the data. - # Once we have written output_size up to the limit, we call the - # drain helper which waits for the transport to be ready to accept - # more data. This is a flow control mechanism to prevent the buffer - # from growing too large. The drain helper will return right away - # if the writer is not paused. - if self._output_size > self._limit: - self._output_size = 0 - if self.protocol._paused: - await self.protocol._drain_helper() - - def _write_websocket_frame(self, message: bytes, opcode: int, rsv: int) -> None: - """ - Write a websocket frame to the transport. - - This method handles frame header construction, masking, and writing to transport. - It does not handle compression or flow control - those are the responsibility - of the caller. - """ - msg_length = len(message) - - use_mask = self.use_mask - mask_bit = 0x80 if use_mask else 0 - - # Depending on the message length, the header is assembled differently. - # The first byte is reserved for the opcode and the RSV bits. - first_byte = 0x80 | rsv | opcode - if msg_length < 126: - header = PACK_LEN1(first_byte, msg_length | mask_bit) - header_len = 2 - elif msg_length < 65536: - header = PACK_LEN2(first_byte, 126 | mask_bit, msg_length) - header_len = 4 - else: - header = PACK_LEN3(first_byte, 127 | mask_bit, msg_length) - header_len = 10 - - if self.transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.3 - # If we are using a mask, we need to generate it randomly - # and apply it to the message before sending it. A mask is - # a 32-bit value that is applied to the message using a - # bitwise XOR operation. It is used to prevent certain types - # of attacks on the websocket protocol. The mask is only used - # when aiohttp is acting as a client. Servers do not use a mask. - if use_mask: - mask = PACK_RANDBITS(self.get_random_bits()) - message = bytearray(message) - websocket_mask(mask, message) - self.transport.write(header + mask + message) - self._output_size += MASK_LEN - elif msg_length > MSG_SIZE: - self.transport.write(header) - self.transport.write(message) - else: - self.transport.write(header + message) - - self._output_size += header_len + msg_length - - def _get_compressor(self, compress: Optional[int]) -> ZLibCompressor: - """Get or create a compressor object for the given compression level.""" - if compress: - # Do not set self._compress if compressing is for this frame - return ZLibCompressor( - level=ZLibBackend.Z_BEST_SPEED, - wbits=-compress, - max_sync_chunk_size=WEBSOCKET_MAX_SYNC_CHUNK_SIZE, - ) - if not self._compressobj: - self._compressobj = ZLibCompressor( - level=ZLibBackend.Z_BEST_SPEED, - wbits=-self.compress, - max_sync_chunk_size=WEBSOCKET_MAX_SYNC_CHUNK_SIZE, - ) - return self._compressobj - - def _send_compressed_frame_sync( - self, message: bytes, opcode: int, compress: Optional[int] - ) -> None: - """ - Synchronous send for small compressed frames. - - This is used for small compressed payloads that compress synchronously in the event loop. - Since there are no await points, this is inherently cancellation-safe. - """ - # RSV are the reserved bits in the frame header. They are used to - # indicate that the frame is using an extension. - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 - compressobj = self._get_compressor(compress) - # (0x40) RSV1 is set for compressed frames - # https://datatracker.ietf.org/doc/html/rfc7692#section-7.2.3.1 - self._write_websocket_frame( - ( - compressobj.compress_sync(message) - + compressobj.flush( - ZLibBackend.Z_FULL_FLUSH - if self.notakeover - else ZLibBackend.Z_SYNC_FLUSH - ) - ).removesuffix(WS_DEFLATE_TRAILING), - opcode, - 0x40, - ) - - async def _send_compressed_frame_async_locked( - self, message: bytes, opcode: int, compress: Optional[int] - ) -> None: - """ - Async send for large compressed frames with lock. - - Acquires the lock and compresses large payloads asynchronously in - the executor. The lock is held for the entire operation to ensure - the compressor state is not corrupted by concurrent sends. - - MUST be run shielded from cancellation. If cancelled after - compression but before sending, the compressor state would be - advanced but data not sent, corrupting subsequent frames. - """ - async with self._send_lock: - # RSV are the reserved bits in the frame header. They are used to - # indicate that the frame is using an extension. - # https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 - compressobj = self._get_compressor(compress) - # (0x40) RSV1 is set for compressed frames - # https://datatracker.ietf.org/doc/html/rfc7692#section-7.2.3.1 - self._write_websocket_frame( - ( - await compressobj.compress(message) - + compressobj.flush( - ZLibBackend.Z_FULL_FLUSH - if self.notakeover - else ZLibBackend.Z_SYNC_FLUSH - ) - ).removesuffix(WS_DEFLATE_TRAILING), - opcode, - 0x40, - ) - - async def close(self, code: int = 1000, message: Union[bytes, str] = b"") -> None: - """Close the websocket, sending the specified code and message.""" - if isinstance(message, str): - message = message.encode("utf-8") - try: - await self.send_frame( - PACK_CLOSE_CODE(code) + message, opcode=WSMsgType.CLOSE - ) - finally: - self._closing = True diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/abc.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/abc.py deleted file mode 100644 index faf0957..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/abc.py +++ /dev/null @@ -1,268 +0,0 @@ -import asyncio -import logging -import socket -from abc import ABC, abstractmethod -from collections.abc import Sized -from http.cookies import BaseCookie, Morsel -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Dict, - Generator, - Iterable, - List, - Optional, - Sequence, - Tuple, - TypedDict, - Union, -) - -from multidict import CIMultiDict -from yarl import URL - -from ._cookie_helpers import parse_set_cookie_headers -from .typedefs import LooseCookies - -if TYPE_CHECKING: - from .web_app import Application - from .web_exceptions import HTTPException - from .web_request import BaseRequest, Request - from .web_response import StreamResponse -else: - BaseRequest = Request = Application = StreamResponse = None - HTTPException = None - - -class AbstractRouter(ABC): - def __init__(self) -> None: - self._frozen = False - - def post_init(self, app: Application) -> None: - """Post init stage. - - Not an abstract method for sake of backward compatibility, - but if the router wants to be aware of the application - it can override this. - """ - - @property - def frozen(self) -> bool: - return self._frozen - - def freeze(self) -> None: - """Freeze router.""" - self._frozen = True - - @abstractmethod - async def resolve(self, request: Request) -> "AbstractMatchInfo": - """Return MATCH_INFO for given request""" - - -class AbstractMatchInfo(ABC): - - __slots__ = () - - @property # pragma: no branch - @abstractmethod - def handler(self) -> Callable[[Request], Awaitable[StreamResponse]]: - """Execute matched request handler""" - - @property - @abstractmethod - def expect_handler( - self, - ) -> Callable[[Request], Awaitable[Optional[StreamResponse]]]: - """Expect handler for 100-continue processing""" - - @property # pragma: no branch - @abstractmethod - def http_exception(self) -> Optional[HTTPException]: - """HTTPException instance raised on router's resolving, or None""" - - @abstractmethod # pragma: no branch - def get_info(self) -> Dict[str, Any]: - """Return a dict with additional info useful for introspection""" - - @property # pragma: no branch - @abstractmethod - def apps(self) -> Tuple[Application, ...]: - """Stack of nested applications. - - Top level application is left-most element. - - """ - - @abstractmethod - def add_app(self, app: Application) -> None: - """Add application to the nested apps stack.""" - - @abstractmethod - def freeze(self) -> None: - """Freeze the match info. - - The method is called after route resolution. - - After the call .add_app() is forbidden. - - """ - - -class AbstractView(ABC): - """Abstract class based view.""" - - def __init__(self, request: Request) -> None: - self._request = request - - @property - def request(self) -> Request: - """Request instance.""" - return self._request - - @abstractmethod - def __await__(self) -> Generator[None, None, StreamResponse]: - """Execute the view handler.""" - - -class ResolveResult(TypedDict): - """Resolve result. - - This is the result returned from an AbstractResolver's - resolve method. - - :param hostname: The hostname that was provided. - :param host: The IP address that was resolved. - :param port: The port that was resolved. - :param family: The address family that was resolved. - :param proto: The protocol that was resolved. - :param flags: The flags that were resolved. - """ - - hostname: str - host: str - port: int - family: int - proto: int - flags: int - - -class AbstractResolver(ABC): - """Abstract DNS resolver.""" - - @abstractmethod - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - """Return IP address for given hostname""" - - @abstractmethod - async def close(self) -> None: - """Release resolver""" - - -if TYPE_CHECKING: - IterableBase = Iterable[Morsel[str]] -else: - IterableBase = Iterable - - -ClearCookiePredicate = Callable[["Morsel[str]"], bool] - - -class AbstractCookieJar(Sized, IterableBase): - """Abstract Cookie Jar.""" - - def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() - - @property - @abstractmethod - def quote_cookie(self) -> bool: - """Return True if cookies should be quoted.""" - - @abstractmethod - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - """Clear all cookies if no predicate is passed.""" - - @abstractmethod - def clear_domain(self, domain: str) -> None: - """Clear all cookies for domain and all subdomains.""" - - @abstractmethod - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - """Update cookies.""" - - def update_cookies_from_headers( - self, headers: Sequence[str], response_url: URL - ) -> None: - """Update cookies from raw Set-Cookie headers.""" - if headers and (cookies_to_update := parse_set_cookie_headers(headers)): - self.update_cookies(cookies_to_update, response_url) - - @abstractmethod - def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": - """Return the jar's cookies filtered by their attributes.""" - - -class AbstractStreamWriter(ABC): - """Abstract stream writer.""" - - buffer_size: int = 0 - output_size: int = 0 - length: Optional[int] = 0 - - @abstractmethod - async def write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: - """Write chunk into stream.""" - - @abstractmethod - async def write_eof(self, chunk: bytes = b"") -> None: - """Write last chunk.""" - - @abstractmethod - async def drain(self) -> None: - """Flush the write buffer.""" - - @abstractmethod - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - """Enable HTTP body compression""" - - @abstractmethod - def enable_chunking(self) -> None: - """Enable HTTP chunked mode""" - - @abstractmethod - async def write_headers( - self, status_line: str, headers: "CIMultiDict[str]" - ) -> None: - """Write HTTP headers""" - - def send_headers(self) -> None: - """Force sending buffered headers if not already sent. - - Required only if write_headers() buffers headers instead of sending immediately. - For backwards compatibility, this method does nothing by default. - """ - - -class AbstractAccessLogger(ABC): - """Abstract writer to access log.""" - - __slots__ = ("logger", "log_format") - - def __init__(self, logger: logging.Logger, log_format: str) -> None: - self.logger = logger - self.log_format = log_format - - @abstractmethod - def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: - """Emit log to logger.""" - - @property - def enabled(self) -> bool: - """Check if logger is enabled.""" - return True diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/base_protocol.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/base_protocol.py deleted file mode 100644 index b0a67ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/base_protocol.py +++ /dev/null @@ -1,100 +0,0 @@ -import asyncio -from typing import Optional, cast - -from .client_exceptions import ClientConnectionResetError -from .helpers import set_exception -from .tcp_helpers import tcp_nodelay - - -class BaseProtocol(asyncio.Protocol): - __slots__ = ( - "_loop", - "_paused", - "_drain_waiter", - "_connection_lost", - "_reading_paused", - "transport", - ) - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop: asyncio.AbstractEventLoop = loop - self._paused = False - self._drain_waiter: Optional[asyncio.Future[None]] = None - self._reading_paused = False - - self.transport: Optional[asyncio.Transport] = None - - @property - def connected(self) -> bool: - """Return True if the connection is open.""" - return self.transport is not None - - @property - def writing_paused(self) -> bool: - return self._paused - - def pause_writing(self) -> None: - assert not self._paused - self._paused = True - - def resume_writing(self) -> None: - assert self._paused - self._paused = False - - waiter = self._drain_waiter - if waiter is not None: - self._drain_waiter = None - if not waiter.done(): - waiter.set_result(None) - - def pause_reading(self) -> None: - if not self._reading_paused and self.transport is not None: - try: - self.transport.pause_reading() - except (AttributeError, NotImplementedError, RuntimeError): - pass - self._reading_paused = True - - def resume_reading(self) -> None: - if self._reading_paused and self.transport is not None: - try: - self.transport.resume_reading() - except (AttributeError, NotImplementedError, RuntimeError): - pass - self._reading_paused = False - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - tr = cast(asyncio.Transport, transport) - tcp_nodelay(tr, True) - self.transport = tr - - def connection_lost(self, exc: Optional[BaseException]) -> None: - # Wake up the writer if currently paused. - self.transport = None - if not self._paused: - return - waiter = self._drain_waiter - if waiter is None: - return - self._drain_waiter = None - if waiter.done(): - return - if exc is None: - waiter.set_result(None) - else: - set_exception( - waiter, - ConnectionError("Connection lost"), - exc, - ) - - async def _drain_helper(self) -> None: - if self.transport is None: - raise ClientConnectionResetError("Connection lost") - if not self._paused: - return - waiter = self._drain_waiter - if waiter is None: - waiter = self._loop.create_future() - self._drain_waiter = waiter - await asyncio.shield(waiter) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client.py deleted file mode 100644 index bc4ee17..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client.py +++ /dev/null @@ -1,1635 +0,0 @@ -"""HTTP Client for asyncio.""" - -import asyncio -import base64 -import hashlib -import json -import os -import sys -import traceback -import warnings -from contextlib import suppress -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Coroutine, - Final, - FrozenSet, - Generator, - Generic, - Iterable, - List, - Mapping, - Optional, - Sequence, - Set, - Tuple, - Type, - TypedDict, - TypeVar, - Union, -) - -import attr -from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr -from yarl import URL - -from . import hdrs, http, payload -from ._websocket.reader import WebSocketDataQueue -from .abc import AbstractCookieJar -from .client_exceptions import ( - ClientConnectionError, - ClientConnectionResetError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientError, - ClientHttpProxyError, - ClientOSError, - ClientPayloadError, - ClientProxyConnectionError, - ClientResponseError, - ClientSSLError, - ConnectionTimeoutError, - ContentTypeError, - InvalidURL, - InvalidUrlClientError, - InvalidUrlRedirectClientError, - NonHttpUrlClientError, - NonHttpUrlRedirectClientError, - RedirectClientError, - ServerConnectionError, - ServerDisconnectedError, - ServerFingerprintMismatch, - ServerTimeoutError, - SocketTimeoutError, - TooManyRedirects, - WSMessageTypeError, - WSServerHandshakeError, -) -from .client_middlewares import ClientMiddlewareType, build_client_middlewares -from .client_reqrep import ( - ClientRequest as ClientRequest, - ClientResponse as ClientResponse, - Fingerprint as Fingerprint, - RequestInfo as RequestInfo, - _merge_ssl_params, -) -from .client_ws import ( - DEFAULT_WS_CLIENT_TIMEOUT, - ClientWebSocketResponse as ClientWebSocketResponse, - ClientWSTimeout as ClientWSTimeout, -) -from .connector import ( - HTTP_AND_EMPTY_SCHEMA_SET, - BaseConnector as BaseConnector, - NamedPipeConnector as NamedPipeConnector, - TCPConnector as TCPConnector, - UnixConnector as UnixConnector, -) -from .cookiejar import CookieJar -from .helpers import ( - _SENTINEL, - DEBUG, - EMPTY_BODY_METHODS, - BasicAuth, - TimeoutHandle, - basicauth_from_netrc, - get_env_proxy_for_url, - netrc_from_env, - sentinel, - strip_auth_from_url, -) -from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter -from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse -from .tracing import Trace, TraceConfig -from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL - -__all__ = ( - # client_exceptions - "ClientConnectionError", - "ClientConnectionResetError", - "ClientConnectorCertificateError", - "ClientConnectorDNSError", - "ClientConnectorError", - "ClientConnectorSSLError", - "ClientError", - "ClientHttpProxyError", - "ClientOSError", - "ClientPayloadError", - "ClientProxyConnectionError", - "ClientResponseError", - "ClientSSLError", - "ConnectionTimeoutError", - "ContentTypeError", - "InvalidURL", - "InvalidUrlClientError", - "RedirectClientError", - "NonHttpUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlRedirectClientError", - "ServerConnectionError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ServerTimeoutError", - "SocketTimeoutError", - "TooManyRedirects", - "WSServerHandshakeError", - # client_reqrep - "ClientRequest", - "ClientResponse", - "Fingerprint", - "RequestInfo", - # connector - "BaseConnector", - "TCPConnector", - "UnixConnector", - "NamedPipeConnector", - # client_ws - "ClientWebSocketResponse", - # client - "ClientSession", - "ClientTimeout", - "ClientWSTimeout", - "request", - "WSMessageTypeError", -) - - -if TYPE_CHECKING: - from ssl import SSLContext -else: - SSLContext = None - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - from typing import Unpack - - -class _RequestOptions(TypedDict, total=False): - params: Query - data: Any - json: Any - cookies: Union[LooseCookies, None] - headers: Union[LooseHeaders, None] - skip_auto_headers: Union[Iterable[str], None] - auth: Union[BasicAuth, None] - allow_redirects: bool - max_redirects: int - compress: Union[str, bool, None] - chunked: Union[bool, None] - expect100: bool - raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]] - read_until_eof: bool - proxy: Union[StrOrURL, None] - proxy_auth: Union[BasicAuth, None] - timeout: "Union[ClientTimeout, _SENTINEL, None]" - ssl: Union[SSLContext, bool, Fingerprint] - server_hostname: Union[str, None] - proxy_headers: Union[LooseHeaders, None] - trace_request_ctx: Union[Mapping[str, Any], None] - read_bufsize: Union[int, None] - auto_decompress: Union[bool, None] - max_line_size: Union[int, None] - max_field_size: Union[int, None] - middlewares: Optional[Sequence[ClientMiddlewareType]] - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ClientTimeout: - total: Optional[float] = None - connect: Optional[float] = None - sock_read: Optional[float] = None - sock_connect: Optional[float] = None - ceil_threshold: float = 5 - - # pool_queue_timeout: Optional[float] = None - # dns_resolution_timeout: Optional[float] = None - # socket_connect_timeout: Optional[float] = None - # connection_acquiring_timeout: Optional[float] = None - # new_connection_timeout: Optional[float] = None - # http_header_timeout: Optional[float] = None - # response_body_timeout: Optional[float] = None - - # to create a timeout specific for a single request, either - # - create a completely new one to overwrite the default - # - or use http://www.attrs.org/en/stable/api.html#attr.evolve - # to overwrite the defaults - - -# 5 Minute default read timeout -DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30) - -# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 -IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"}) - -_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse) -_CharsetResolver = Callable[[ClientResponse, bytes], str] - - -class ClientSession: - """First-class interface for making HTTP requests.""" - - ATTRS = frozenset( - [ - "_base_url", - "_base_url_origin", - "_source_traceback", - "_connector", - "_loop", - "_cookie_jar", - "_connector_owner", - "_default_auth", - "_version", - "_json_serialize", - "_requote_redirect_url", - "_timeout", - "_raise_for_status", - "_auto_decompress", - "_trust_env", - "_default_headers", - "_skip_auto_headers", - "_request_class", - "_response_class", - "_ws_response_class", - "_trace_configs", - "_read_bufsize", - "_max_line_size", - "_max_field_size", - "_resolve_charset", - "_default_proxy", - "_default_proxy_auth", - "_retry_connection", - "_middlewares", - "requote_redirect_url", - ] - ) - - _source_traceback: Optional[traceback.StackSummary] = None - _connector: Optional[BaseConnector] = None - - def __init__( - self, - base_url: Optional[StrOrURL] = None, - *, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - cookies: Optional[LooseCookies] = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - auth: Optional[BasicAuth] = None, - json_serialize: JSONEncoder = json.dumps, - request_class: Type[ClientRequest] = ClientRequest, - response_class: Type[ClientResponse] = ClientResponse, - ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse, - version: HttpVersion = http.HttpVersion11, - cookie_jar: Optional[AbstractCookieJar] = None, - connector_owner: bool = True, - raise_for_status: Union[ - bool, Callable[[ClientResponse], Awaitable[None]] - ] = False, - read_timeout: Union[float, _SENTINEL] = sentinel, - conn_timeout: Optional[float] = None, - timeout: Union[object, ClientTimeout] = sentinel, - auto_decompress: bool = True, - trust_env: bool = False, - requote_redirect_url: bool = True, - trace_configs: Optional[List[TraceConfig]] = None, - read_bufsize: int = 2**16, - max_line_size: int = 8190, - max_field_size: int = 8190, - fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8", - middlewares: Sequence[ClientMiddlewareType] = (), - ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, - ) -> None: - # We initialise _connector to None immediately, as it's referenced in __del__() - # and could cause issues if an exception occurs during initialisation. - self._connector: Optional[BaseConnector] = None - - if loop is None: - if connector is not None: - loop = connector._loop - - loop = loop or asyncio.get_running_loop() - - if base_url is None or isinstance(base_url, URL): - self._base_url: Optional[URL] = base_url - self._base_url_origin = None if base_url is None else base_url.origin() - else: - self._base_url = URL(base_url) - self._base_url_origin = self._base_url.origin() - assert self._base_url.absolute, "Only absolute URLs are supported" - if self._base_url is not None and not self._base_url.path.endswith("/"): - raise ValueError("base_url must have a trailing '/'") - - if timeout is sentinel or timeout is None: - self._timeout = DEFAULT_TIMEOUT - if read_timeout is not sentinel: - warnings.warn( - "read_timeout is deprecated, use timeout argument instead", - DeprecationWarning, - stacklevel=2, - ) - self._timeout = attr.evolve(self._timeout, total=read_timeout) - if conn_timeout is not None: - self._timeout = attr.evolve(self._timeout, connect=conn_timeout) - warnings.warn( - "conn_timeout is deprecated, use timeout argument instead", - DeprecationWarning, - stacklevel=2, - ) - else: - if not isinstance(timeout, ClientTimeout): - raise ValueError( - f"timeout parameter cannot be of {type(timeout)} type, " - "please use 'timeout=ClientTimeout(...)'", - ) - self._timeout = timeout - if read_timeout is not sentinel: - raise ValueError( - "read_timeout and timeout parameters " - "conflict, please setup " - "timeout.read" - ) - if conn_timeout is not None: - raise ValueError( - "conn_timeout and timeout parameters " - "conflict, please setup " - "timeout.connect" - ) - - if ssl_shutdown_timeout is not sentinel: - warnings.warn( - "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", - DeprecationWarning, - stacklevel=2, - ) - - if connector is None: - connector = TCPConnector( - loop=loop, ssl_shutdown_timeout=ssl_shutdown_timeout - ) - - if connector._loop is not loop: - raise RuntimeError("Session and connector has to use same event loop") - - self._loop = loop - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - if cookie_jar is None: - cookie_jar = CookieJar(loop=loop) - self._cookie_jar = cookie_jar - - if cookies: - self._cookie_jar.update_cookies(cookies) - - self._connector = connector - self._connector_owner = connector_owner - self._default_auth = auth - self._version = version - self._json_serialize = json_serialize - self._raise_for_status = raise_for_status - self._auto_decompress = auto_decompress - self._trust_env = trust_env - self._requote_redirect_url = requote_redirect_url - self._read_bufsize = read_bufsize - self._max_line_size = max_line_size - self._max_field_size = max_field_size - - # Convert to list of tuples - if headers: - real_headers: CIMultiDict[str] = CIMultiDict(headers) - else: - real_headers = CIMultiDict() - self._default_headers: CIMultiDict[str] = real_headers - if skip_auto_headers is not None: - self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers) - else: - self._skip_auto_headers = frozenset() - - self._request_class = request_class - self._response_class = response_class - self._ws_response_class = ws_response_class - - self._trace_configs = trace_configs or [] - for trace_config in self._trace_configs: - trace_config.freeze() - - self._resolve_charset = fallback_charset_resolver - - self._default_proxy = proxy - self._default_proxy_auth = proxy_auth - self._retry_connection: bool = True - self._middlewares = middlewares - - def __init_subclass__(cls: Type["ClientSession"]) -> None: - warnings.warn( - "Inheritance class {} from ClientSession " - "is discouraged".format(cls.__name__), - DeprecationWarning, - stacklevel=2, - ) - - if DEBUG: - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom ClientSession.{} attribute " - "is discouraged".format(name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - def __del__(self, _warnings: Any = warnings) -> None: - if not self.closed: - kwargs = {"source": self} - _warnings.warn( - f"Unclosed client session {self!r}", ResourceWarning, **kwargs - ) - context = {"client_session": self, "message": "Unclosed client session"} - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - self, - method: str, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - else: - - def request( - self, method: str, url: StrOrURL, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP request.""" - return _RequestContextManager(self._request(method, url, **kwargs)) - - def _build_url(self, str_or_url: StrOrURL) -> URL: - url = URL(str_or_url) - if self._base_url and not url.absolute: - return self._base_url.join(url) - return url - - async def _request( - self, - method: str, - str_or_url: StrOrURL, - *, - params: Query = None, - data: Any = None, - json: Any = None, - cookies: Optional[LooseCookies] = None, - headers: Optional[LooseHeaders] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - auth: Optional[BasicAuth] = None, - allow_redirects: bool = True, - max_redirects: int = 10, - compress: Union[str, bool, None] = None, - chunked: Optional[bool] = None, - expect100: bool = False, - raise_for_status: Union[ - None, bool, Callable[[ClientResponse], Awaitable[None]] - ] = None, - read_until_eof: bool = True, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - timeout: Union[ClientTimeout, _SENTINEL] = sentinel, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - trace_request_ctx: Optional[Mapping[str, Any]] = None, - read_bufsize: Optional[int] = None, - auto_decompress: Optional[bool] = None, - max_line_size: Optional[int] = None, - max_field_size: Optional[int] = None, - middlewares: Optional[Sequence[ClientMiddlewareType]] = None, - ) -> ClientResponse: - - # NOTE: timeout clamps existing connect and read timeouts. We cannot - # set the default to None because we need to detect if the user wants - # to use the existing timeouts by setting timeout to None. - - if self.closed: - raise RuntimeError("Session is closed") - - ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - if data is not None and json is not None: - raise ValueError( - "data and json parameters can not be used at the same time" - ) - elif json is not None: - data = payload.JsonPayload(json, dumps=self._json_serialize) - - if not isinstance(chunked, bool) and chunked is not None: - warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) - - redirects = 0 - history: List[ClientResponse] = [] - version = self._version - params = params or {} - - # Merge with default headers and transform to CIMultiDict - headers = self._prepare_headers(headers) - - try: - url = self._build_url(str_or_url) - except ValueError as e: - raise InvalidUrlClientError(str_or_url) from e - - assert self._connector is not None - if url.scheme not in self._connector.allowed_protocol_schema_set: - raise NonHttpUrlClientError(url) - - skip_headers: Optional[Iterable[istr]] - if skip_auto_headers is not None: - skip_headers = { - istr(i) for i in skip_auto_headers - } | self._skip_auto_headers - elif self._skip_auto_headers: - skip_headers = self._skip_auto_headers - else: - skip_headers = None - - if proxy is None: - proxy = self._default_proxy - if proxy_auth is None: - proxy_auth = self._default_proxy_auth - - if proxy is None: - proxy_headers = None - else: - proxy_headers = self._prepare_headers(proxy_headers) - try: - proxy = URL(proxy) - except ValueError as e: - raise InvalidURL(proxy) from e - - if timeout is sentinel: - real_timeout: ClientTimeout = self._timeout - else: - if not isinstance(timeout, ClientTimeout): - real_timeout = ClientTimeout(total=timeout) - else: - real_timeout = timeout - # timeout is cumulative for all request operations - # (request, redirects, responses, data consuming) - tm = TimeoutHandle( - self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold - ) - handle = tm.start() - - if read_bufsize is None: - read_bufsize = self._read_bufsize - - if auto_decompress is None: - auto_decompress = self._auto_decompress - - if max_line_size is None: - max_line_size = self._max_line_size - - if max_field_size is None: - max_field_size = self._max_field_size - - traces = [ - Trace( - self, - trace_config, - trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx), - ) - for trace_config in self._trace_configs - ] - - for trace in traces: - await trace.send_request_start(method, url.update_query(params), headers) - - timer = tm.timer() - try: - with timer: - # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests - retry_persistent_connection = ( - self._retry_connection and method in IDEMPOTENT_METHODS - ) - while True: - url, auth_from_url = strip_auth_from_url(url) - if not url.raw_host: - # NOTE: Bail early, otherwise, causes `InvalidURL` through - # NOTE: `self._request_class()` below. - err_exc_cls = ( - InvalidUrlRedirectClientError - if redirects - else InvalidUrlClientError - ) - raise err_exc_cls(url) - # If `auth` was passed for an already authenticated URL, - # disallow only if this is the initial URL; this is to avoid issues - # with sketchy redirects that are not the caller's responsibility - if not history and (auth and auth_from_url): - raise ValueError( - "Cannot combine AUTH argument with " - "credentials encoded in URL" - ) - - # Override the auth with the one from the URL only if we - # have no auth, or if we got an auth from a redirect URL - if auth is None or (history and auth_from_url is not None): - auth = auth_from_url - - if ( - auth is None - and self._default_auth - and ( - not self._base_url or self._base_url_origin == url.origin() - ) - ): - auth = self._default_auth - - # Try netrc if auth is still None and trust_env is enabled. - if auth is None and self._trust_env and url.host is not None: - auth = await self._loop.run_in_executor( - None, self._get_netrc_auth, url.host - ) - - # It would be confusing if we support explicit - # Authorization header with auth argument - if ( - headers is not None - and auth is not None - and hdrs.AUTHORIZATION in headers - ): - raise ValueError( - "Cannot combine AUTHORIZATION header " - "with AUTH argument or credentials " - "encoded in URL" - ) - - all_cookies = self._cookie_jar.filter_cookies(url) - - if cookies is not None: - tmp_cookie_jar = CookieJar( - quote_cookie=self._cookie_jar.quote_cookie - ) - tmp_cookie_jar.update_cookies(cookies) - req_cookies = tmp_cookie_jar.filter_cookies(url) - if req_cookies: - all_cookies.load(req_cookies) - - proxy_: Optional[URL] = None - if proxy is not None: - proxy_ = URL(proxy) - elif self._trust_env: - with suppress(LookupError): - proxy_, proxy_auth = await asyncio.to_thread( - get_env_proxy_for_url, url - ) - - req = self._request_class( - method, - url, - params=params, - headers=headers, - skip_auto_headers=skip_headers, - data=data, - cookies=all_cookies, - auth=auth, - version=version, - compress=compress, - chunked=chunked, - expect100=expect100, - loop=self._loop, - response_class=self._response_class, - proxy=proxy_, - proxy_auth=proxy_auth, - timer=timer, - session=self, - ssl=ssl if ssl is not None else True, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - traces=traces, - trust_env=self.trust_env, - ) - - async def _connect_and_send_request( - req: ClientRequest, - ) -> ClientResponse: - # connection timeout - assert self._connector is not None - try: - conn = await self._connector.connect( - req, traces=traces, timeout=real_timeout - ) - except asyncio.TimeoutError as exc: - raise ConnectionTimeoutError( - f"Connection timeout to host {req.url}" - ) from exc - - assert conn.protocol is not None - conn.protocol.set_response_params( - timer=timer, - skip_payload=req.method in EMPTY_BODY_METHODS, - read_until_eof=read_until_eof, - auto_decompress=auto_decompress, - read_timeout=real_timeout.sock_read, - read_bufsize=read_bufsize, - timeout_ceil_threshold=self._connector._timeout_ceil_threshold, - max_line_size=max_line_size, - max_field_size=max_field_size, - ) - try: - resp = await req.send(conn) - try: - await resp.start(conn) - except BaseException: - resp.close() - raise - except BaseException: - conn.close() - raise - return resp - - # Apply middleware (if any) - per-request middleware overrides session middleware - effective_middlewares = ( - self._middlewares if middlewares is None else middlewares - ) - - if effective_middlewares: - handler = build_client_middlewares( - _connect_and_send_request, effective_middlewares - ) - else: - handler = _connect_and_send_request - - try: - resp = await handler(req) - # Client connector errors should not be retried - except ( - ConnectionTimeoutError, - ClientConnectorError, - ClientConnectorCertificateError, - ClientConnectorSSLError, - ): - raise - except (ClientOSError, ServerDisconnectedError): - if retry_persistent_connection: - retry_persistent_connection = False - continue - raise - except ClientError: - raise - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise ClientOSError(*exc.args) from exc - - # Update cookies from raw headers to preserve duplicates - if resp._raw_cookie_headers: - self._cookie_jar.update_cookies_from_headers( - resp._raw_cookie_headers, resp.url - ) - - # redirects - if resp.status in (301, 302, 303, 307, 308) and allow_redirects: - - for trace in traces: - await trace.send_request_redirect( - method, url.update_query(params), headers, resp - ) - - redirects += 1 - history.append(resp) - if max_redirects and redirects >= max_redirects: - if req._body is not None: - await req._body.close() - resp.close() - raise TooManyRedirects( - history[0].request_info, tuple(history) - ) - - # For 301 and 302, mimic IE, now changed in RFC - # https://github.com/kennethreitz/requests/pull/269 - if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or ( - resp.status in (301, 302) and resp.method == hdrs.METH_POST - ): - method = hdrs.METH_GET - data = None - if headers.get(hdrs.CONTENT_LENGTH): - headers.pop(hdrs.CONTENT_LENGTH) - else: - # For 307/308, always preserve the request body - # For 301/302 with non-POST methods, preserve the request body - # https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3-3.1 - # Use the existing payload to avoid recreating it from a potentially consumed file - data = req._body - - r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get( - hdrs.URI - ) - if r_url is None: - # see github.com/aio-libs/aiohttp/issues/2022 - break - else: - # reading from correct redirection - # response is forbidden - resp.release() - - try: - parsed_redirect_url = URL( - r_url, encoded=not self._requote_redirect_url - ) - except ValueError as e: - if req._body is not None: - await req._body.close() - resp.close() - raise InvalidUrlRedirectClientError( - r_url, - "Server attempted redirecting to a location that does not look like a URL", - ) from e - - scheme = parsed_redirect_url.scheme - if scheme not in HTTP_AND_EMPTY_SCHEMA_SET: - if req._body is not None: - await req._body.close() - resp.close() - raise NonHttpUrlRedirectClientError(r_url) - elif not scheme: - parsed_redirect_url = url.join(parsed_redirect_url) - - try: - redirect_origin = parsed_redirect_url.origin() - except ValueError as origin_val_err: - if req._body is not None: - await req._body.close() - resp.close() - raise InvalidUrlRedirectClientError( - parsed_redirect_url, - "Invalid redirect URL origin", - ) from origin_val_err - - if url.origin() != redirect_origin: - auth = None - headers.pop(hdrs.AUTHORIZATION, None) - - url = parsed_redirect_url - params = {} - resp.release() - continue - - break - - if req._body is not None: - await req._body.close() - # check response status - if raise_for_status is None: - raise_for_status = self._raise_for_status - - if raise_for_status is None: - pass - elif callable(raise_for_status): - await raise_for_status(resp) - elif raise_for_status: - resp.raise_for_status() - - # register connection - if handle is not None: - if resp.connection is not None: - resp.connection.add_callback(handle.cancel) - else: - handle.cancel() - - resp._history = tuple(history) - - for trace in traces: - await trace.send_request_end( - method, url.update_query(params), headers, resp - ) - return resp - - except BaseException as e: - # cleanup timer - tm.close() - if handle: - handle.cancel() - handle = None - - for trace in traces: - await trace.send_request_exception( - method, url.update_query(params), headers, e - ) - raise - - def ws_connect( - self, - url: StrOrURL, - *, - method: str = hdrs.METH_GET, - protocols: Iterable[str] = (), - timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - auth: Optional[BasicAuth] = None, - origin: Optional[str] = None, - params: Query = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - compress: int = 0, - max_msg_size: int = 4 * 1024 * 1024, - ) -> "_WSRequestContextManager": - """Initiate websocket connection.""" - return _WSRequestContextManager( - self._ws_connect( - url, - method=method, - protocols=protocols, - timeout=timeout, - receive_timeout=receive_timeout, - autoclose=autoclose, - autoping=autoping, - heartbeat=heartbeat, - auth=auth, - origin=origin, - params=params, - headers=headers, - proxy=proxy, - proxy_auth=proxy_auth, - ssl=ssl, - verify_ssl=verify_ssl, - fingerprint=fingerprint, - ssl_context=ssl_context, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - compress=compress, - max_msg_size=max_msg_size, - ) - ) - - async def _ws_connect( - self, - url: StrOrURL, - *, - method: str = hdrs.METH_GET, - protocols: Iterable[str] = (), - timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - auth: Optional[BasicAuth] = None, - origin: Optional[str] = None, - params: Query = None, - headers: Optional[LooseHeaders] = None, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - verify_ssl: Optional[bool] = None, - fingerprint: Optional[bytes] = None, - ssl_context: Optional[SSLContext] = None, - server_hostname: Optional[str] = None, - proxy_headers: Optional[LooseHeaders] = None, - compress: int = 0, - max_msg_size: int = 4 * 1024 * 1024, - ) -> ClientWebSocketResponse: - if timeout is not sentinel: - if isinstance(timeout, ClientWSTimeout): - ws_timeout = timeout - else: - warnings.warn( - "parameter 'timeout' of type 'float' " - "is deprecated, please use " - "'timeout=ClientWSTimeout(ws_close=...)'", - DeprecationWarning, - stacklevel=2, - ) - ws_timeout = ClientWSTimeout(ws_close=timeout) - else: - ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT - if receive_timeout is not None: - warnings.warn( - "float parameter 'receive_timeout' " - "is deprecated, please use parameter " - "'timeout=ClientWSTimeout(ws_receive=...)'", - DeprecationWarning, - stacklevel=2, - ) - ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout) - - if headers is None: - real_headers: CIMultiDict[str] = CIMultiDict() - else: - real_headers = CIMultiDict(headers) - - default_headers = { - hdrs.UPGRADE: "websocket", - hdrs.CONNECTION: "Upgrade", - hdrs.SEC_WEBSOCKET_VERSION: "13", - } - - for key, value in default_headers.items(): - real_headers.setdefault(key, value) - - sec_key = base64.b64encode(os.urandom(16)) - real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode() - - if protocols: - real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols) - if origin is not None: - real_headers[hdrs.ORIGIN] = origin - if compress: - extstr = ws_ext_gen(compress=compress) - real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr - - # For the sake of backward compatibility, if user passes in None, convert it to True - if ssl is None: - warnings.warn( - "ssl=None is deprecated, please use ssl=True", - DeprecationWarning, - stacklevel=2, - ) - ssl = True - ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - # send request - resp = await self.request( - method, - url, - params=params, - headers=real_headers, - read_until_eof=False, - auth=auth, - proxy=proxy, - proxy_auth=proxy_auth, - ssl=ssl, - server_hostname=server_hostname, - proxy_headers=proxy_headers, - ) - - try: - # check handshake - if resp.status != 101: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid response status", - status=resp.status, - headers=resp.headers, - ) - - if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket": - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid upgrade header", - status=resp.status, - headers=resp.headers, - ) - - if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade": - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid connection header", - status=resp.status, - headers=resp.headers, - ) - - # key calculation - r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "") - match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode() - if r_key != match: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message="Invalid challenge response", - status=resp.status, - headers=resp.headers, - ) - - # websocket protocol - protocol = None - if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers: - resp_protocols = [ - proto.strip() - for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") - ] - - for proto in resp_protocols: - if proto in protocols: - protocol = proto - break - - # websocket compress - notakeover = False - if compress: - compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) - if compress_hdrs: - try: - compress, notakeover = ws_ext_parse(compress_hdrs) - except WSHandshakeError as exc: - raise WSServerHandshakeError( - resp.request_info, - resp.history, - message=exc.args[0], - status=resp.status, - headers=resp.headers, - ) from exc - else: - compress = 0 - notakeover = False - - conn = resp.connection - assert conn is not None - conn_proto = conn.protocol - assert conn_proto is not None - - # For WS connection the read_timeout must be either receive_timeout or greater - # None == no timeout, i.e. infinite timeout, so None is the max timeout possible - if ws_timeout.ws_receive is None: - # Reset regardless - conn_proto.read_timeout = None - elif conn_proto.read_timeout is not None: - conn_proto.read_timeout = max( - ws_timeout.ws_receive, conn_proto.read_timeout - ) - - transport = conn.transport - assert transport is not None - reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop) - conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader) - writer = WebSocketWriter( - conn_proto, - transport, - use_mask=True, - compress=compress, - notakeover=notakeover, - ) - except BaseException: - resp.close() - raise - else: - return self._ws_response_class( - reader, - writer, - protocol, - resp, - ws_timeout, - autoclose, - autoping, - self._loop, - heartbeat=heartbeat, - compress=compress, - client_notakeover=notakeover, - ) - - def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]": - """Add default headers and transform it to CIMultiDict""" - # Convert headers to MultiDict - result = CIMultiDict(self._default_headers) - if headers: - if not isinstance(headers, (MultiDictProxy, MultiDict)): - headers = CIMultiDict(headers) - added_names: Set[str] = set() - for key, value in headers.items(): - if key in added_names: - result.add(key, value) - else: - result[key] = value - added_names.add(key) - return result - - def _get_netrc_auth(self, host: str) -> Optional[BasicAuth]: - """ - Get auth from netrc for the given host. - - This method is designed to be called in an executor to avoid - blocking I/O in the event loop. - """ - netrc_obj = netrc_from_env() - try: - return basicauth_from_netrc(netrc_obj, host) - except LookupError: - return None - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def get( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def options( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def head( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def post( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def put( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def patch( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - def delete( - self, - url: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> "_RequestContextManager": ... - - else: - - def get( - self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP GET request.""" - return _RequestContextManager( - self._request( - hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def options( - self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP OPTIONS request.""" - return _RequestContextManager( - self._request( - hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def head( - self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP HEAD request.""" - return _RequestContextManager( - self._request( - hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs - ) - ) - - def post( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP POST request.""" - return _RequestContextManager( - self._request(hdrs.METH_POST, url, data=data, **kwargs) - ) - - def put( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP PUT request.""" - return _RequestContextManager( - self._request(hdrs.METH_PUT, url, data=data, **kwargs) - ) - - def patch( - self, url: StrOrURL, *, data: Any = None, **kwargs: Any - ) -> "_RequestContextManager": - """Perform HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_PATCH, url, data=data, **kwargs) - ) - - def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager": - """Perform HTTP DELETE request.""" - return _RequestContextManager( - self._request(hdrs.METH_DELETE, url, **kwargs) - ) - - async def close(self) -> None: - """Close underlying connector. - - Release all acquired resources. - """ - if not self.closed: - if self._connector is not None and self._connector_owner: - await self._connector.close() - self._connector = None - - @property - def closed(self) -> bool: - """Is client session closed. - - A readonly property. - """ - return self._connector is None or self._connector.closed - - @property - def connector(self) -> Optional[BaseConnector]: - """Connector instance used for the session.""" - return self._connector - - @property - def cookie_jar(self) -> AbstractCookieJar: - """The session cookies.""" - return self._cookie_jar - - @property - def version(self) -> Tuple[int, int]: - """The session HTTP protocol version.""" - return self._version - - @property - def requote_redirect_url(self) -> bool: - """Do URL requoting on redirection handling.""" - return self._requote_redirect_url - - @requote_redirect_url.setter - def requote_redirect_url(self, val: bool) -> None: - """Do URL requoting on redirection handling.""" - warnings.warn( - "session.requote_redirect_url modification is deprecated #2778", - DeprecationWarning, - stacklevel=2, - ) - self._requote_redirect_url = val - - @property - def loop(self) -> asyncio.AbstractEventLoop: - """Session's loop.""" - warnings.warn( - "client.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - @property - def timeout(self) -> ClientTimeout: - """Timeout for the session.""" - return self._timeout - - @property - def headers(self) -> "CIMultiDict[str]": - """The default headers of the client session.""" - return self._default_headers - - @property - def skip_auto_headers(self) -> FrozenSet[istr]: - """Headers for which autogeneration should be skipped""" - return self._skip_auto_headers - - @property - def auth(self) -> Optional[BasicAuth]: - """An object that represents HTTP Basic Authorization""" - return self._default_auth - - @property - def json_serialize(self) -> JSONEncoder: - """Json serializer callable""" - return self._json_serialize - - @property - def connector_owner(self) -> bool: - """Should connector be closed on session closing""" - return self._connector_owner - - @property - def raise_for_status( - self, - ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]: - """Should `ClientResponse.raise_for_status()` be called for each response.""" - return self._raise_for_status - - @property - def auto_decompress(self) -> bool: - """Should the body response be automatically decompressed.""" - return self._auto_decompress - - @property - def trust_env(self) -> bool: - """ - Should proxies information from environment or netrc be trusted. - - Information is from HTTP_PROXY / HTTPS_PROXY environment variables - or ~/.netrc file if present. - """ - return self._trust_env - - @property - def trace_configs(self) -> List[TraceConfig]: - """A list of TraceConfig instances used for client tracing""" - return self._trace_configs - - def detach(self) -> None: - """Detach connector from session without closing the former. - - Session is switched to closed state anyway. - """ - self._connector = None - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> "ClientSession": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - await self.close() - - -class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]): - - __slots__ = ("_coro", "_resp") - - def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None: - self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro - - def send(self, arg: None) -> "asyncio.Future[Any]": - return self._coro.send(arg) - - def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]": - return self._coro.throw(*args, **kwargs) - - def close(self) -> None: - return self._coro.close() - - def __await__(self) -> Generator[Any, None, _RetType]: - ret = self._coro.__await__() - return ret - - def __iter__(self) -> Generator[Any, None, _RetType]: - return self.__await__() - - async def __aenter__(self) -> _RetType: - self._resp: _RetType = await self._coro - return await self._resp.__aenter__() - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - await self._resp.__aexit__(exc_type, exc, tb) - - -_RequestContextManager = _BaseRequestContextManager[ClientResponse] -_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse] - - -class _SessionRequestContextManager: - - __slots__ = ("_coro", "_resp", "_session") - - def __init__( - self, - coro: Coroutine["asyncio.Future[Any]", None, ClientResponse], - session: ClientSession, - ) -> None: - self._coro = coro - self._resp: Optional[ClientResponse] = None - self._session = session - - async def __aenter__(self) -> ClientResponse: - try: - self._resp = await self._coro - except BaseException: - await self._session.close() - raise - else: - return self._resp - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - assert self._resp is not None - self._resp.close() - await self._session.close() - - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - method: str, - url: StrOrURL, - *, - version: HttpVersion = http.HttpVersion11, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Unpack[_RequestOptions], - ) -> _SessionRequestContextManager: ... - -else: - - def request( - method: str, - url: StrOrURL, - *, - version: HttpVersion = http.HttpVersion11, - connector: Optional[BaseConnector] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> _SessionRequestContextManager: - """Constructs and sends a request. - - Returns response object. - method - HTTP method - url - request url - params - (optional) Dictionary or bytes to be sent in the query - string of the new request - data - (optional) Dictionary, bytes, or file-like object to - send in the body of the request - json - (optional) Any json compatible python object - headers - (optional) Dictionary of HTTP Headers to send with - the request - cookies - (optional) Dict object to send with the request - auth - (optional) BasicAuth named tuple represent HTTP Basic Auth - auth - aiohttp.helpers.BasicAuth - allow_redirects - (optional) If set to False, do not follow - redirects - version - Request HTTP version. - compress - Set to True if request has to be compressed - with deflate encoding. - chunked - Set to chunk size for chunked transfer encoding. - expect100 - Expect 100-continue response from server. - connector - BaseConnector sub-class instance to support - connection pooling. - read_until_eof - Read response until eof if response - does not have Content-Length header. - loop - Optional event loop. - timeout - Optional ClientTimeout settings structure, 5min - total timeout by default. - Usage:: - >>> import aiohttp - >>> async with aiohttp.request('GET', 'http://python.org/') as resp: - ... print(resp) - ... data = await resp.read() - - """ - connector_owner = False - if connector is None: - connector_owner = True - connector = TCPConnector(loop=loop, force_close=True) - - session = ClientSession( - loop=loop, - cookies=kwargs.pop("cookies", None), - version=version, - timeout=kwargs.pop("timeout", sentinel), - connector=connector, - connector_owner=connector_owner, - ) - - return _SessionRequestContextManager( - session._request(method, url, **kwargs), - session, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_exceptions.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_exceptions.py deleted file mode 100644 index 1d298e9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_exceptions.py +++ /dev/null @@ -1,421 +0,0 @@ -"""HTTP related errors.""" - -import asyncio -import warnings -from typing import TYPE_CHECKING, Optional, Tuple, Union - -from multidict import MultiMapping - -from .typedefs import StrOrURL - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = SSLContext = None # type: ignore[assignment] - -if TYPE_CHECKING: - from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo - from .http_parser import RawResponseMessage -else: - RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None - -__all__ = ( - "ClientError", - "ClientConnectionError", - "ClientConnectionResetError", - "ClientOSError", - "ClientConnectorError", - "ClientProxyConnectionError", - "ClientSSLError", - "ClientConnectorDNSError", - "ClientConnectorSSLError", - "ClientConnectorCertificateError", - "ConnectionTimeoutError", - "SocketTimeoutError", - "ServerConnectionError", - "ServerTimeoutError", - "ServerDisconnectedError", - "ServerFingerprintMismatch", - "ClientResponseError", - "ClientHttpProxyError", - "WSServerHandshakeError", - "ContentTypeError", - "ClientPayloadError", - "InvalidURL", - "InvalidUrlClientError", - "RedirectClientError", - "NonHttpUrlClientError", - "InvalidUrlRedirectClientError", - "NonHttpUrlRedirectClientError", - "WSMessageTypeError", -) - - -class ClientError(Exception): - """Base class for client connection errors.""" - - -class ClientResponseError(ClientError): - """Base class for exceptions that occur after getting a response. - - request_info: An instance of RequestInfo. - history: A sequence of responses, if redirects occurred. - status: HTTP status code. - message: Error message. - headers: Response headers. - """ - - def __init__( - self, - request_info: RequestInfo, - history: Tuple[ClientResponse, ...], - *, - code: Optional[int] = None, - status: Optional[int] = None, - message: str = "", - headers: Optional[MultiMapping[str]] = None, - ) -> None: - self.request_info = request_info - if code is not None: - if status is not None: - raise ValueError( - "Both code and status arguments are provided; " - "code is deprecated, use status instead" - ) - warnings.warn( - "code argument is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - if status is not None: - self.status = status - elif code is not None: - self.status = code - else: - self.status = 0 - self.message = message - self.headers = headers - self.history = history - self.args = (request_info, history) - - def __str__(self) -> str: - return "{}, message={!r}, url={!r}".format( - self.status, - self.message, - str(self.request_info.real_url), - ) - - def __repr__(self) -> str: - args = f"{self.request_info!r}, {self.history!r}" - if self.status != 0: - args += f", status={self.status!r}" - if self.message != "": - args += f", message={self.message!r}" - if self.headers is not None: - args += f", headers={self.headers!r}" - return f"{type(self).__name__}({args})" - - @property - def code(self) -> int: - warnings.warn( - "code property is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - return self.status - - @code.setter - def code(self, value: int) -> None: - warnings.warn( - "code property is deprecated, use status instead", - DeprecationWarning, - stacklevel=2, - ) - self.status = value - - -class ContentTypeError(ClientResponseError): - """ContentType found is not valid.""" - - -class WSServerHandshakeError(ClientResponseError): - """websocket server handshake error.""" - - -class ClientHttpProxyError(ClientResponseError): - """HTTP proxy error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - proxy responds with status other than ``200 OK`` - on ``CONNECT`` request. - """ - - -class TooManyRedirects(ClientResponseError): - """Client was redirected too many times.""" - - -class ClientConnectionError(ClientError): - """Base class for client socket errors.""" - - -class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): - """ConnectionResetError""" - - -class ClientOSError(ClientConnectionError, OSError): - """OSError error.""" - - -class ClientConnectorError(ClientOSError): - """Client connector error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - a connection can not be established. - """ - - def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None: - self._conn_key = connection_key - self._os_error = os_error - super().__init__(os_error.errno, os_error.strerror) - self.args = (connection_key, os_error) - - @property - def os_error(self) -> OSError: - return self._os_error - - @property - def host(self) -> str: - return self._conn_key.host - - @property - def port(self) -> Optional[int]: - return self._conn_key.port - - @property - def ssl(self) -> Union[SSLContext, bool, "Fingerprint"]: - return self._conn_key.ssl - - def __str__(self) -> str: - return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format( - self, "default" if self.ssl is True else self.ssl, self.strerror - ) - - # OSError.__reduce__ does too much black magick - __reduce__ = BaseException.__reduce__ - - -class ClientConnectorDNSError(ClientConnectorError): - """DNS resolution failed during client connection. - - Raised in :class:`aiohttp.connector.TCPConnector` if - DNS resolution fails. - """ - - -class ClientProxyConnectionError(ClientConnectorError): - """Proxy connection error. - - Raised in :class:`aiohttp.connector.TCPConnector` if - connection to proxy can not be established. - """ - - -class UnixClientConnectorError(ClientConnectorError): - """Unix connector error. - - Raised in :py:class:`aiohttp.connector.UnixConnector` - if connection to unix socket can not be established. - """ - - def __init__( - self, path: str, connection_key: ConnectionKey, os_error: OSError - ) -> None: - self._path = path - super().__init__(connection_key, os_error) - - @property - def path(self) -> str: - return self._path - - def __str__(self) -> str: - return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format( - self, "default" if self.ssl is True else self.ssl, self.strerror - ) - - -class ServerConnectionError(ClientConnectionError): - """Server connection errors.""" - - -class ServerDisconnectedError(ServerConnectionError): - """Server disconnected.""" - - def __init__(self, message: Union[RawResponseMessage, str, None] = None) -> None: - if message is None: - message = "Server disconnected" - - self.args = (message,) - self.message = message - - -class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): - """Server timeout error.""" - - -class ConnectionTimeoutError(ServerTimeoutError): - """Connection timeout error.""" - - -class SocketTimeoutError(ServerTimeoutError): - """Socket timeout error.""" - - -class ServerFingerprintMismatch(ServerConnectionError): - """SSL certificate does not match expected fingerprint.""" - - def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None: - self.expected = expected - self.got = got - self.host = host - self.port = port - self.args = (expected, got, host, port) - - def __repr__(self) -> str: - return "<{} expected={!r} got={!r} host={!r} port={!r}>".format( - self.__class__.__name__, self.expected, self.got, self.host, self.port - ) - - -class ClientPayloadError(ClientError): - """Response payload error.""" - - -class InvalidURL(ClientError, ValueError): - """Invalid URL. - - URL used for fetching is malformed, e.g. it doesn't contains host - part. - """ - - # Derive from ValueError for backward compatibility - - def __init__(self, url: StrOrURL, description: Union[str, None] = None) -> None: - # The type of url is not yarl.URL because the exception can be raised - # on URL(url) call - self._url = url - self._description = description - - if description: - super().__init__(url, description) - else: - super().__init__(url) - - @property - def url(self) -> StrOrURL: - return self._url - - @property - def description(self) -> "str | None": - return self._description - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self}>" - - def __str__(self) -> str: - if self._description: - return f"{self._url} - {self._description}" - return str(self._url) - - -class InvalidUrlClientError(InvalidURL): - """Invalid URL client error.""" - - -class RedirectClientError(ClientError): - """Client redirect error.""" - - -class NonHttpUrlClientError(ClientError): - """Non http URL client error.""" - - -class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): - """Invalid URL redirect client error.""" - - -class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): - """Non http URL redirect client error.""" - - -class ClientSSLError(ClientConnectorError): - """Base error for ssl.*Errors.""" - - -if ssl is not None: - cert_errors = (ssl.CertificateError,) - cert_errors_bases = ( - ClientSSLError, - ssl.CertificateError, - ) - - ssl_errors = (ssl.SSLError,) - ssl_error_bases = (ClientSSLError, ssl.SSLError) -else: # pragma: no cover - cert_errors = tuple() - cert_errors_bases = ( - ClientSSLError, - ValueError, - ) - - ssl_errors = tuple() - ssl_error_bases = (ClientSSLError,) - - -class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc] - """Response ssl error.""" - - -class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc] - """Response certificate error.""" - - def __init__( - self, connection_key: ConnectionKey, certificate_error: Exception - ) -> None: - self._conn_key = connection_key - self._certificate_error = certificate_error - self.args = (connection_key, certificate_error) - - @property - def certificate_error(self) -> Exception: - return self._certificate_error - - @property - def host(self) -> str: - return self._conn_key.host - - @property - def port(self) -> Optional[int]: - return self._conn_key.port - - @property - def ssl(self) -> bool: - return self._conn_key.is_ssl - - def __str__(self) -> str: - return ( - "Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} " - "[{0.certificate_error.__class__.__name__}: " - "{0.certificate_error.args}]".format(self) - ) - - -class WSMessageTypeError(TypeError): - """WebSocket message type is not valid.""" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py deleted file mode 100644 index 5aab5ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middleware_digest_auth.py +++ /dev/null @@ -1,480 +0,0 @@ -""" -Digest authentication middleware for aiohttp client. - -This middleware implements HTTP Digest Authentication according to RFC 7616, -providing a more secure alternative to Basic Authentication. It supports all -standard hash algorithms including MD5, SHA, SHA-256, SHA-512 and their session -variants, as well as both 'auth' and 'auth-int' quality of protection (qop) options. -""" - -import hashlib -import os -import re -import sys -import time -from typing import ( - Callable, - Dict, - Final, - FrozenSet, - List, - Literal, - Tuple, - TypedDict, - Union, -) - -from yarl import URL - -from . import hdrs -from .client_exceptions import ClientError -from .client_middlewares import ClientHandlerType -from .client_reqrep import ClientRequest, ClientResponse -from .payload import Payload - - -class DigestAuthChallenge(TypedDict, total=False): - realm: str - nonce: str - qop: str - algorithm: str - opaque: str - domain: str - stale: str - - -DigestFunctions: Dict[str, Callable[[bytes], "hashlib._Hash"]] = { - "MD5": hashlib.md5, - "MD5-SESS": hashlib.md5, - "SHA": hashlib.sha1, - "SHA-SESS": hashlib.sha1, - "SHA256": hashlib.sha256, - "SHA256-SESS": hashlib.sha256, - "SHA-256": hashlib.sha256, - "SHA-256-SESS": hashlib.sha256, - "SHA512": hashlib.sha512, - "SHA512-SESS": hashlib.sha512, - "SHA-512": hashlib.sha512, - "SHA-512-SESS": hashlib.sha512, -} - - -# Compile the regex pattern once at module level for performance -_HEADER_PAIRS_PATTERN = re.compile( - r'(?:^|\s|,\s*)(\w+)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))' - if sys.version_info < (3, 11) - else r'(?:^|\s|,\s*)((?>\w+))\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^\s,]+))' - # +------------|--------|--|-|-|--|----|------|----|--||-----|-> Match valid start/sep - # +--------|--|-|-|--|----|------|----|--||-----|-> alphanumeric key (atomic - # | | | | | | | | || | group reduces backtracking) - # +--|-|-|--|----|------|----|--||-----|-> maybe whitespace - # | | | | | | | || | - # +-|-|--|----|------|----|--||-----|-> = (delimiter) - # +-|--|----|------|----|--||-----|-> maybe whitespace - # | | | | | || | - # +--|----|------|----|--||-----|-> group quoted or unquoted - # | | | | || | - # +----|------|----|--||-----|-> if quoted... - # +------|----|--||-----|-> anything but " or \ - # +----|--||-----|-> escaped characters allowed - # +--||-----|-> or can be empty string - # || | - # +|-----|-> if unquoted... - # +-----|-> anything but , or - # +-> at least one char req'd -) - - -# RFC 7616: Challenge parameters to extract -CHALLENGE_FIELDS: Final[ - Tuple[ - Literal["realm", "nonce", "qop", "algorithm", "opaque", "domain", "stale"], ... - ] -] = ( - "realm", - "nonce", - "qop", - "algorithm", - "opaque", - "domain", - "stale", -) - -# Supported digest authentication algorithms -# Use a tuple of sorted keys for predictable documentation and error messages -SUPPORTED_ALGORITHMS: Final[Tuple[str, ...]] = tuple(sorted(DigestFunctions.keys())) - -# RFC 7616: Fields that require quoting in the Digest auth header -# These fields must be enclosed in double quotes in the Authorization header. -# Algorithm, qop, and nc are never quoted per RFC specifications. -# This frozen set is used by the template-based header construction to -# automatically determine which fields need quotes. -QUOTED_AUTH_FIELDS: Final[FrozenSet[str]] = frozenset( - {"username", "realm", "nonce", "uri", "response", "opaque", "cnonce"} -) - - -def escape_quotes(value: str) -> str: - """Escape double quotes for HTTP header values.""" - return value.replace('"', '\\"') - - -def unescape_quotes(value: str) -> str: - """Unescape double quotes in HTTP header values.""" - return value.replace('\\"', '"') - - -def parse_header_pairs(header: str) -> Dict[str, str]: - """ - Parse key-value pairs from WWW-Authenticate or similar HTTP headers. - - This function handles the complex format of WWW-Authenticate header values, - supporting both quoted and unquoted values, proper handling of commas in - quoted values, and whitespace variations per RFC 7616. - - Examples of supported formats: - - key1="value1", key2=value2 - - key1 = "value1" , key2="value, with, commas" - - key1=value1,key2="value2" - - realm="example.com", nonce="12345", qop="auth" - - Args: - header: The header value string to parse - - Returns: - Dictionary mapping parameter names to their values - """ - return { - stripped_key: unescape_quotes(quoted_val) if quoted_val else unquoted_val - for key, quoted_val, unquoted_val in _HEADER_PAIRS_PATTERN.findall(header) - if (stripped_key := key.strip()) - } - - -class DigestAuthMiddleware: - """ - HTTP digest authentication middleware for aiohttp client. - - This middleware intercepts 401 Unauthorized responses containing a Digest - authentication challenge, calculates the appropriate digest credentials, - and automatically retries the request with the proper Authorization header. - - Features: - - Handles all aspects of Digest authentication handshake automatically - - Supports all standard hash algorithms: - - MD5, MD5-SESS - - SHA, SHA-SESS - - SHA256, SHA256-SESS, SHA-256, SHA-256-SESS - - SHA512, SHA512-SESS, SHA-512, SHA-512-SESS - - Supports 'auth' and 'auth-int' quality of protection modes - - Properly handles quoted strings and parameter parsing - - Includes replay attack protection with client nonce count tracking - - Supports preemptive authentication per RFC 7616 Section 3.6 - - Standards compliance: - - RFC 7616: HTTP Digest Access Authentication (primary reference) - - RFC 2617: HTTP Authentication (deprecated by RFC 7616) - - RFC 1945: Section 11.1 (username restrictions) - - Implementation notes: - The core digest calculation is inspired by the implementation in - https://github.com/requests/requests/blob/v2.18.4/requests/auth.py - with added support for modern digest auth features and error handling. - """ - - def __init__( - self, - login: str, - password: str, - preemptive: bool = True, - ) -> None: - if login is None: - raise ValueError("None is not allowed as login value") - - if password is None: - raise ValueError("None is not allowed as password value") - - if ":" in login: - raise ValueError('A ":" is not allowed in username (RFC 1945#section-11.1)') - - self._login_str: Final[str] = login - self._login_bytes: Final[bytes] = login.encode("utf-8") - self._password_bytes: Final[bytes] = password.encode("utf-8") - - self._last_nonce_bytes = b"" - self._nonce_count = 0 - self._challenge: DigestAuthChallenge = {} - self._preemptive: bool = preemptive - # Set of URLs defining the protection space - self._protection_space: List[str] = [] - - async def _encode( - self, method: str, url: URL, body: Union[Payload, Literal[b""]] - ) -> str: - """ - Build digest authorization header for the current challenge. - - Args: - method: The HTTP method (GET, POST, etc.) - url: The request URL - body: The request body (used for qop=auth-int) - - Returns: - A fully formatted Digest authorization header string - - Raises: - ClientError: If the challenge is missing required parameters or - contains unsupported values - - """ - challenge = self._challenge - if "realm" not in challenge: - raise ClientError( - "Malformed Digest auth challenge: Missing 'realm' parameter" - ) - - if "nonce" not in challenge: - raise ClientError( - "Malformed Digest auth challenge: Missing 'nonce' parameter" - ) - - # Empty realm values are allowed per RFC 7616 (SHOULD, not MUST, contain host name) - realm = challenge["realm"] - nonce = challenge["nonce"] - - # Empty nonce values are not allowed as they are security-critical for replay protection - if not nonce: - raise ClientError( - "Security issue: Digest auth challenge contains empty 'nonce' value" - ) - - qop_raw = challenge.get("qop", "") - # Preserve original algorithm case for response while using uppercase for processing - algorithm_original = challenge.get("algorithm", "MD5") - algorithm = algorithm_original.upper() - opaque = challenge.get("opaque", "") - - # Convert string values to bytes once - nonce_bytes = nonce.encode("utf-8") - realm_bytes = realm.encode("utf-8") - path = URL(url).path_qs - - # Process QoP - qop = "" - qop_bytes = b"" - if qop_raw: - valid_qops = {"auth", "auth-int"}.intersection( - {q.strip() for q in qop_raw.split(",") if q.strip()} - ) - if not valid_qops: - raise ClientError( - f"Digest auth error: Unsupported Quality of Protection (qop) value(s): {qop_raw}" - ) - - qop = "auth-int" if "auth-int" in valid_qops else "auth" - qop_bytes = qop.encode("utf-8") - - if algorithm not in DigestFunctions: - raise ClientError( - f"Digest auth error: Unsupported hash algorithm: {algorithm}. " - f"Supported algorithms: {', '.join(SUPPORTED_ALGORITHMS)}" - ) - hash_fn: Final = DigestFunctions[algorithm] - - def H(x: bytes) -> bytes: - """RFC 7616 Section 3: Hash function H(data) = hex(hash(data)).""" - return hash_fn(x).hexdigest().encode() - - def KD(s: bytes, d: bytes) -> bytes: - """RFC 7616 Section 3: KD(secret, data) = H(concat(secret, ":", data)).""" - return H(b":".join((s, d))) - - # Calculate A1 and A2 - A1 = b":".join((self._login_bytes, realm_bytes, self._password_bytes)) - A2 = f"{method.upper()}:{path}".encode() - if qop == "auth-int": - if isinstance(body, Payload): # will always be empty bytes unless Payload - entity_bytes = await body.as_bytes() # Get bytes from Payload - else: - entity_bytes = body - entity_hash = H(entity_bytes) - A2 = b":".join((A2, entity_hash)) - - HA1 = H(A1) - HA2 = H(A2) - - # Nonce count handling - if nonce_bytes == self._last_nonce_bytes: - self._nonce_count += 1 - else: - self._nonce_count = 1 - - self._last_nonce_bytes = nonce_bytes - ncvalue = f"{self._nonce_count:08x}" - ncvalue_bytes = ncvalue.encode("utf-8") - - # Generate client nonce - cnonce = hashlib.sha1( - b"".join( - [ - str(self._nonce_count).encode("utf-8"), - nonce_bytes, - time.ctime().encode("utf-8"), - os.urandom(8), - ] - ) - ).hexdigest()[:16] - cnonce_bytes = cnonce.encode("utf-8") - - # Special handling for session-based algorithms - if algorithm.upper().endswith("-SESS"): - HA1 = H(b":".join((HA1, nonce_bytes, cnonce_bytes))) - - # Calculate the response digest - if qop: - noncebit = b":".join( - (nonce_bytes, ncvalue_bytes, cnonce_bytes, qop_bytes, HA2) - ) - response_digest = KD(HA1, noncebit) - else: - response_digest = KD(HA1, b":".join((nonce_bytes, HA2))) - - # Define a dict mapping of header fields to their values - # Group fields into always-present, optional, and qop-dependent - header_fields = { - # Always present fields - "username": escape_quotes(self._login_str), - "realm": escape_quotes(realm), - "nonce": escape_quotes(nonce), - "uri": path, - "response": response_digest.decode(), - "algorithm": algorithm_original, - } - - # Optional fields - if opaque: - header_fields["opaque"] = escape_quotes(opaque) - - # QoP-dependent fields - if qop: - header_fields["qop"] = qop - header_fields["nc"] = ncvalue - header_fields["cnonce"] = cnonce - - # Build header using templates for each field type - pairs: List[str] = [] - for field, value in header_fields.items(): - if field in QUOTED_AUTH_FIELDS: - pairs.append(f'{field}="{value}"') - else: - pairs.append(f"{field}={value}") - - return f"Digest {', '.join(pairs)}" - - def _in_protection_space(self, url: URL) -> bool: - """ - Check if the given URL is within the current protection space. - - According to RFC 7616, a URI is in the protection space if any URI - in the protection space is a prefix of it (after both have been made absolute). - """ - request_str = str(url) - for space_str in self._protection_space: - # Check if request starts with space URL - if not request_str.startswith(space_str): - continue - # Exact match or space ends with / (proper directory prefix) - if len(request_str) == len(space_str) or space_str[-1] == "/": - return True - # Check next char is / to ensure proper path boundary - if request_str[len(space_str)] == "/": - return True - return False - - def _authenticate(self, response: ClientResponse) -> bool: - """ - Takes the given response and tries digest-auth, if needed. - - Returns true if the original request must be resent. - """ - if response.status != 401: - return False - - auth_header = response.headers.get("www-authenticate", "") - if not auth_header: - return False # No authentication header present - - method, sep, headers = auth_header.partition(" ") - if not sep: - # No space found in www-authenticate header - return False # Malformed auth header, missing scheme separator - - if method.lower() != "digest": - # Not a digest auth challenge (could be Basic, Bearer, etc.) - return False - - if not headers: - # We have a digest scheme but no parameters - return False # Malformed digest header, missing parameters - - # We have a digest auth header with content - if not (header_pairs := parse_header_pairs(headers)): - # Failed to parse any key-value pairs - return False # Malformed digest header, no valid parameters - - # Extract challenge parameters - self._challenge = {} - for field in CHALLENGE_FIELDS: - if value := header_pairs.get(field): - self._challenge[field] = value - - # Update protection space based on domain parameter or default to origin - origin = response.url.origin() - - if domain := self._challenge.get("domain"): - # Parse space-separated list of URIs - self._protection_space = [] - for uri in domain.split(): - # Remove quotes if present - uri = uri.strip('"') - if uri.startswith("/"): - # Path-absolute, relative to origin - self._protection_space.append(str(origin.join(URL(uri)))) - else: - # Absolute URI - self._protection_space.append(str(URL(uri))) - else: - # No domain specified, protection space is entire origin - self._protection_space = [str(origin)] - - # Return True only if we found at least one challenge parameter - return bool(self._challenge) - - async def __call__( - self, request: ClientRequest, handler: ClientHandlerType - ) -> ClientResponse: - """Run the digest auth middleware.""" - response = None - for retry_count in range(2): - # Apply authorization header if: - # 1. This is a retry after 401 (retry_count > 0), OR - # 2. Preemptive auth is enabled AND we have a challenge AND the URL is in protection space - if retry_count > 0 or ( - self._preemptive - and self._challenge - and self._in_protection_space(request.url) - ): - request.headers[hdrs.AUTHORIZATION] = await self._encode( - request.method, request.url, request.body - ) - - # Send the request - response = await handler(request) - - # Check if we need to authenticate - if not self._authenticate(response): - break - - # At this point, response is guaranteed to be defined - assert response is not None - return response diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middlewares.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middlewares.py deleted file mode 100644 index 3ca2cb2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_middlewares.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Client middleware support.""" - -from collections.abc import Awaitable, Callable, Sequence - -from .client_reqrep import ClientRequest, ClientResponse - -__all__ = ("ClientMiddlewareType", "ClientHandlerType", "build_client_middlewares") - -# Type alias for client request handlers - functions that process requests and return responses -ClientHandlerType = Callable[[ClientRequest], Awaitable[ClientResponse]] - -# Type for client middleware - similar to server but uses ClientRequest/ClientResponse -ClientMiddlewareType = Callable[ - [ClientRequest, ClientHandlerType], Awaitable[ClientResponse] -] - - -def build_client_middlewares( - handler: ClientHandlerType, - middlewares: Sequence[ClientMiddlewareType], -) -> ClientHandlerType: - """ - Apply middlewares to request handler. - - The middlewares are applied in reverse order, so the first middleware - in the list wraps all subsequent middlewares and the handler. - - This implementation avoids using partial/update_wrapper to minimize overhead - and doesn't cache to avoid holding references to stateful middleware. - """ - # Optimize for single middleware case - if len(middlewares) == 1: - middleware = middlewares[0] - - async def single_middleware_handler(req: ClientRequest) -> ClientResponse: - return await middleware(req, handler) - - return single_middleware_handler - - # Build the chain for multiple middlewares - current_handler = handler - - for middleware in reversed(middlewares): - # Create a new closure that captures the current state - def make_wrapper( - mw: ClientMiddlewareType, next_h: ClientHandlerType - ) -> ClientHandlerType: - async def wrapped(req: ClientRequest) -> ClientResponse: - return await mw(req, next_h) - - return wrapped - - current_handler = make_wrapper(middleware, current_handler) - - return current_handler diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_proto.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_proto.py deleted file mode 100644 index e2fb1ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_proto.py +++ /dev/null @@ -1,359 +0,0 @@ -import asyncio -from contextlib import suppress -from typing import Any, Optional, Tuple, Union - -from .base_protocol import BaseProtocol -from .client_exceptions import ( - ClientConnectionError, - ClientOSError, - ClientPayloadError, - ServerDisconnectedError, - SocketTimeoutError, -) -from .helpers import ( - _EXC_SENTINEL, - EMPTY_BODY_STATUS_CODES, - BaseTimerContext, - set_exception, - set_result, -) -from .http import HttpResponseParser, RawResponseMessage -from .http_exceptions import HttpProcessingError -from .streams import EMPTY_PAYLOAD, DataQueue, StreamReader - - -class ResponseHandler(BaseProtocol, DataQueue[Tuple[RawResponseMessage, StreamReader]]): - """Helper class to adapt between Protocol and StreamReader.""" - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - BaseProtocol.__init__(self, loop=loop) - DataQueue.__init__(self, loop) - - self._should_close = False - - self._payload: Optional[StreamReader] = None - self._skip_payload = False - self._payload_parser = None - - self._timer = None - - self._tail = b"" - self._upgraded = False - self._parser: Optional[HttpResponseParser] = None - - self._read_timeout: Optional[float] = None - self._read_timeout_handle: Optional[asyncio.TimerHandle] = None - - self._timeout_ceil_threshold: Optional[float] = 5 - - self._closed: Union[None, asyncio.Future[None]] = None - self._connection_lost_called = False - - @property - def closed(self) -> Union[None, asyncio.Future[None]]: - """Future that is set when the connection is closed. - - This property returns a Future that will be completed when the connection - is closed. The Future is created lazily on first access to avoid creating - futures that will never be awaited. - - Returns: - - A Future[None] if the connection is still open or was closed after - this property was accessed - - None if connection_lost() was already called before this property - was ever accessed (indicating no one is waiting for the closure) - """ - if self._closed is None and not self._connection_lost_called: - self._closed = self._loop.create_future() - return self._closed - - @property - def upgraded(self) -> bool: - return self._upgraded - - @property - def should_close(self) -> bool: - return bool( - self._should_close - or (self._payload is not None and not self._payload.is_eof()) - or self._upgraded - or self._exception is not None - or self._payload_parser is not None - or self._buffer - or self._tail - ) - - def force_close(self) -> None: - self._should_close = True - - def close(self) -> None: - self._exception = None # Break cyclic references - transport = self.transport - if transport is not None: - transport.close() - self.transport = None - self._payload = None - self._drop_timeout() - - def abort(self) -> None: - self._exception = None # Break cyclic references - transport = self.transport - if transport is not None: - transport.abort() - self.transport = None - self._payload = None - self._drop_timeout() - - def is_connected(self) -> bool: - return self.transport is not None and not self.transport.is_closing() - - def connection_lost(self, exc: Optional[BaseException]) -> None: - self._connection_lost_called = True - self._drop_timeout() - - original_connection_error = exc - reraised_exc = original_connection_error - - connection_closed_cleanly = original_connection_error is None - - if self._closed is not None: - # If someone is waiting for the closed future, - # we should set it to None or an exception. If - # self._closed is None, it means that - # connection_lost() was called already - # or nobody is waiting for it. - if connection_closed_cleanly: - set_result(self._closed, None) - else: - assert original_connection_error is not None - set_exception( - self._closed, - ClientConnectionError( - f"Connection lost: {original_connection_error !s}", - ), - original_connection_error, - ) - - if self._payload_parser is not None: - with suppress(Exception): # FIXME: log this somehow? - self._payload_parser.feed_eof() - - uncompleted = None - if self._parser is not None: - try: - uncompleted = self._parser.feed_eof() - except Exception as underlying_exc: - if self._payload is not None: - client_payload_exc_msg = ( - f"Response payload is not completed: {underlying_exc !r}" - ) - if not connection_closed_cleanly: - client_payload_exc_msg = ( - f"{client_payload_exc_msg !s}. " - f"{original_connection_error !r}" - ) - set_exception( - self._payload, - ClientPayloadError(client_payload_exc_msg), - underlying_exc, - ) - - if not self.is_eof(): - if isinstance(original_connection_error, OSError): - reraised_exc = ClientOSError(*original_connection_error.args) - if connection_closed_cleanly: - reraised_exc = ServerDisconnectedError(uncompleted) - # assigns self._should_close to True as side effect, - # we do it anyway below - underlying_non_eof_exc = ( - _EXC_SENTINEL - if connection_closed_cleanly - else original_connection_error - ) - assert underlying_non_eof_exc is not None - assert reraised_exc is not None - self.set_exception(reraised_exc, underlying_non_eof_exc) - - self._should_close = True - self._parser = None - self._payload = None - self._payload_parser = None - self._reading_paused = False - - super().connection_lost(reraised_exc) - - def eof_received(self) -> None: - # should call parser.feed_eof() most likely - self._drop_timeout() - - def pause_reading(self) -> None: - super().pause_reading() - self._drop_timeout() - - def resume_reading(self) -> None: - super().resume_reading() - self._reschedule_timeout() - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._should_close = True - self._drop_timeout() - super().set_exception(exc, exc_cause) - - def set_parser(self, parser: Any, payload: Any) -> None: - # TODO: actual types are: - # parser: WebSocketReader - # payload: WebSocketDataQueue - # but they are not generi enough - # Need an ABC for both types - self._payload = payload - self._payload_parser = parser - - self._drop_timeout() - - if self._tail: - data, self._tail = self._tail, b"" - self.data_received(data) - - def set_response_params( - self, - *, - timer: Optional[BaseTimerContext] = None, - skip_payload: bool = False, - read_until_eof: bool = False, - auto_decompress: bool = True, - read_timeout: Optional[float] = None, - read_bufsize: int = 2**16, - timeout_ceil_threshold: float = 5, - max_line_size: int = 8190, - max_field_size: int = 8190, - ) -> None: - self._skip_payload = skip_payload - - self._read_timeout = read_timeout - - self._timeout_ceil_threshold = timeout_ceil_threshold - - self._parser = HttpResponseParser( - self, - self._loop, - read_bufsize, - timer=timer, - payload_exception=ClientPayloadError, - response_with_body=not skip_payload, - read_until_eof=read_until_eof, - auto_decompress=auto_decompress, - max_line_size=max_line_size, - max_field_size=max_field_size, - ) - - if self._tail: - data, self._tail = self._tail, b"" - self.data_received(data) - - def _drop_timeout(self) -> None: - if self._read_timeout_handle is not None: - self._read_timeout_handle.cancel() - self._read_timeout_handle = None - - def _reschedule_timeout(self) -> None: - timeout = self._read_timeout - if self._read_timeout_handle is not None: - self._read_timeout_handle.cancel() - - if timeout: - self._read_timeout_handle = self._loop.call_later( - timeout, self._on_read_timeout - ) - else: - self._read_timeout_handle = None - - def start_timeout(self) -> None: - self._reschedule_timeout() - - @property - def read_timeout(self) -> Optional[float]: - return self._read_timeout - - @read_timeout.setter - def read_timeout(self, read_timeout: Optional[float]) -> None: - self._read_timeout = read_timeout - - def _on_read_timeout(self) -> None: - exc = SocketTimeoutError("Timeout on reading data from socket") - self.set_exception(exc) - if self._payload is not None: - set_exception(self._payload, exc) - - def data_received(self, data: bytes) -> None: - self._reschedule_timeout() - - if not data: - return - - # custom payload parser - currently always WebSocketReader - if self._payload_parser is not None: - eof, tail = self._payload_parser.feed_data(data) - if eof: - self._payload = None - self._payload_parser = None - - if tail: - self.data_received(tail) - return - - if self._upgraded or self._parser is None: - # i.e. websocket connection, websocket parser is not set yet - self._tail += data - return - - # parse http messages - try: - messages, upgraded, tail = self._parser.feed_data(data) - except BaseException as underlying_exc: - if self.transport is not None: - # connection.release() could be called BEFORE - # data_received(), the transport is already - # closed in this case - self.transport.close() - # should_close is True after the call - if isinstance(underlying_exc, HttpProcessingError): - exc = HttpProcessingError( - code=underlying_exc.code, - message=underlying_exc.message, - headers=underlying_exc.headers, - ) - else: - exc = HttpProcessingError() - self.set_exception(exc, underlying_exc) - return - - self._upgraded = upgraded - - payload: Optional[StreamReader] = None - for message, payload in messages: - if message.should_close: - self._should_close = True - - self._payload = payload - - if self._skip_payload or message.code in EMPTY_BODY_STATUS_CODES: - self.feed_data((message, EMPTY_PAYLOAD), 0) - else: - self.feed_data((message, payload), 0) - - if payload is not None: - # new message(s) was processed - # register timeout handler unsubscribing - # either on end-of-stream or immediately for - # EMPTY_PAYLOAD - if payload is not EMPTY_PAYLOAD: - payload.on_eof(self._drop_timeout) - else: - self._drop_timeout() - - if upgraded and tail: - self.data_received(tail) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_reqrep.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_reqrep.py deleted file mode 100644 index a9e0795..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_reqrep.py +++ /dev/null @@ -1,1536 +0,0 @@ -import asyncio -import codecs -import contextlib -import functools -import io -import re -import sys -import traceback -import warnings -from collections.abc import Mapping -from hashlib import md5, sha1, sha256 -from http.cookies import Morsel, SimpleCookie -from types import MappingProxyType, TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Iterable, - List, - Literal, - NamedTuple, - Optional, - Tuple, - Type, - Union, -) - -import attr -from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy -from yarl import URL - -from . import hdrs, helpers, http, multipart, payload -from ._cookie_helpers import ( - parse_cookie_header, - parse_set_cookie_headers, - preserve_morsel_with_coded_value, -) -from .abc import AbstractStreamWriter -from .client_exceptions import ( - ClientConnectionError, - ClientOSError, - ClientResponseError, - ContentTypeError, - InvalidURL, - ServerFingerprintMismatch, -) -from .compression_utils import HAS_BROTLI, HAS_ZSTD -from .formdata import FormData -from .helpers import ( - _SENTINEL, - BaseTimerContext, - BasicAuth, - HeadersMixin, - TimerNoop, - noop, - reify, - sentinel, - set_exception, - set_result, -) -from .http import ( - SERVER_SOFTWARE, - HttpVersion, - HttpVersion10, - HttpVersion11, - StreamWriter, -) -from .streams import StreamReader -from .typedefs import ( - DEFAULT_JSON_DECODER, - JSONDecoder, - LooseCookies, - LooseHeaders, - Query, - RawHeaders, -) - -if TYPE_CHECKING: - import ssl - from ssl import SSLContext -else: - try: - import ssl - from ssl import SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - - -__all__ = ("ClientRequest", "ClientResponse", "RequestInfo", "Fingerprint") - - -if TYPE_CHECKING: - from .client import ClientSession - from .connector import Connection - from .tracing import Trace - - -_CONNECTION_CLOSED_EXCEPTION = ClientConnectionError("Connection closed") -_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") -json_re = re.compile(r"^application/(?:[\w.+-]+?\+)?json") - - -def _gen_default_accept_encoding() -> str: - encodings = [ - "gzip", - "deflate", - ] - if HAS_BROTLI: - encodings.append("br") - if HAS_ZSTD: - encodings.append("zstd") - return ", ".join(encodings) - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ContentDisposition: - type: Optional[str] - parameters: "MappingProxyType[str, str]" - filename: Optional[str] - - -class _RequestInfo(NamedTuple): - url: URL - method: str - headers: "CIMultiDictProxy[str]" - real_url: URL - - -class RequestInfo(_RequestInfo): - - def __new__( - cls, - url: URL, - method: str, - headers: "CIMultiDictProxy[str]", - real_url: Union[URL, _SENTINEL] = sentinel, - ) -> "RequestInfo": - """Create a new RequestInfo instance. - - For backwards compatibility, the real_url parameter is optional. - """ - return tuple.__new__( - cls, (url, method, headers, url if real_url is sentinel else real_url) - ) - - -class Fingerprint: - HASHFUNC_BY_DIGESTLEN = { - 16: md5, - 20: sha1, - 32: sha256, - } - - def __init__(self, fingerprint: bytes) -> None: - digestlen = len(fingerprint) - hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen) - if not hashfunc: - raise ValueError("fingerprint has invalid length") - elif hashfunc is md5 or hashfunc is sha1: - raise ValueError("md5 and sha1 are insecure and not supported. Use sha256.") - self._hashfunc = hashfunc - self._fingerprint = fingerprint - - @property - def fingerprint(self) -> bytes: - return self._fingerprint - - def check(self, transport: asyncio.Transport) -> None: - if not transport.get_extra_info("sslcontext"): - return - sslobj = transport.get_extra_info("ssl_object") - cert = sslobj.getpeercert(binary_form=True) - got = self._hashfunc(cert).digest() - if got != self._fingerprint: - host, port, *_ = transport.get_extra_info("peername") - raise ServerFingerprintMismatch(self._fingerprint, got, host, port) - - -if ssl is not None: - SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None)) -else: # pragma: no cover - SSL_ALLOWED_TYPES = (bool, type(None)) - - -def _merge_ssl_params( - ssl: Union["SSLContext", bool, Fingerprint], - verify_ssl: Optional[bool], - ssl_context: Optional["SSLContext"], - fingerprint: Optional[bytes], -) -> Union["SSLContext", bool, Fingerprint]: - if ssl is None: - ssl = True # Double check for backwards compatibility - if verify_ssl is not None and not verify_ssl: - warnings.warn( - "verify_ssl is deprecated, use ssl=False instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = False - if ssl_context is not None: - warnings.warn( - "ssl_context is deprecated, use ssl=context instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = ssl_context - if fingerprint is not None: - warnings.warn( - "fingerprint is deprecated, use ssl=Fingerprint(fingerprint) instead", - DeprecationWarning, - stacklevel=3, - ) - if ssl is not True: - raise ValueError( - "verify_ssl, ssl_context, fingerprint and ssl " - "parameters are mutually exclusive" - ) - else: - ssl = Fingerprint(fingerprint) - if not isinstance(ssl, SSL_ALLOWED_TYPES): - raise TypeError( - "ssl should be SSLContext, bool, Fingerprint or None, " - "got {!r} instead.".format(ssl) - ) - return ssl - - -_SSL_SCHEMES = frozenset(("https", "wss")) - - -# ConnectionKey is a NamedTuple because it is used as a key in a dict -# and a set in the connector. Since a NamedTuple is a tuple it uses -# the fast native tuple __hash__ and __eq__ implementation in CPython. -class ConnectionKey(NamedTuple): - # the key should contain an information about used proxy / TLS - # to prevent reusing wrong connections from a pool - host: str - port: Optional[int] - is_ssl: bool - ssl: Union[SSLContext, bool, Fingerprint] - proxy: Optional[URL] - proxy_auth: Optional[BasicAuth] - proxy_headers_hash: Optional[int] # hash(CIMultiDict) - - -def _is_expected_content_type( - response_content_type: str, expected_content_type: str -) -> bool: - if expected_content_type == "application/json": - return json_re.match(response_content_type) is not None - return expected_content_type in response_content_type - - -def _warn_if_unclosed_payload(payload: payload.Payload, stacklevel: int = 2) -> None: - """Warn if the payload is not closed. - - Callers must check that the body is a Payload before calling this method. - - Args: - payload: The payload to check - stacklevel: Stack level for the warning (default 2 for direct callers) - """ - if not payload.autoclose and not payload.consumed: - warnings.warn( - "The previous request body contains unclosed resources. " - "Use await request.update_body() instead of setting request.body " - "directly to properly close resources and avoid leaks.", - ResourceWarning, - stacklevel=stacklevel, - ) - - -class ClientResponse(HeadersMixin): - - # Some of these attributes are None when created, - # but will be set by the start() method. - # As the end user will likely never see the None values, we cheat the types below. - # from the Status-Line of the response - version: Optional[HttpVersion] = None # HTTP-Version - status: int = None # type: ignore[assignment] # Status-Code - reason: Optional[str] = None # Reason-Phrase - - content: StreamReader = None # type: ignore[assignment] # Payload stream - _body: Optional[bytes] = None - _headers: CIMultiDictProxy[str] = None # type: ignore[assignment] - _history: Tuple["ClientResponse", ...] = () - _raw_headers: RawHeaders = None # type: ignore[assignment] - - _connection: Optional["Connection"] = None # current connection - _cookies: Optional[SimpleCookie] = None - _raw_cookie_headers: Optional[Tuple[str, ...]] = None - _continue: Optional["asyncio.Future[bool]"] = None - _source_traceback: Optional[traceback.StackSummary] = None - _session: Optional["ClientSession"] = None - # set up by ClientRequest after ClientResponse object creation - # post-init stage allows to not change ctor signature - _closed = True # to allow __del__ for non-initialized properly response - _released = False - _in_context = False - - _resolve_charset: Callable[["ClientResponse", bytes], str] = lambda *_: "utf-8" - - __writer: Optional["asyncio.Task[None]"] = None - - def __init__( - self, - method: str, - url: URL, - *, - writer: "Optional[asyncio.Task[None]]", - continue100: Optional["asyncio.Future[bool]"], - timer: BaseTimerContext, - request_info: RequestInfo, - traces: List["Trace"], - loop: asyncio.AbstractEventLoop, - session: "ClientSession", - ) -> None: - # URL forbids subclasses, so a simple type check is enough. - assert type(url) is URL - - self.method = method - - self._real_url = url - self._url = url.with_fragment(None) if url.raw_fragment else url - if writer is not None: - self._writer = writer - if continue100 is not None: - self._continue = continue100 - self._request_info = request_info - self._timer = timer if timer is not None else TimerNoop() - self._cache: Dict[str, Any] = {} - self._traces = traces - self._loop = loop - # Save reference to _resolve_charset, so that get_encoding() will still - # work after the response has finished reading the body. - # TODO: Fix session=None in tests (see ClientRequest.__init__). - if session is not None: - # store a reference to session #1985 - self._session = session - self._resolve_charset = session._resolve_charset - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - def __reset_writer(self, _: object = None) -> None: - self.__writer = None - - @property - def _writer(self) -> Optional["asyncio.Task[None]"]: - """The writer task for streaming data. - - _writer is only provided for backwards compatibility - for subclasses that may need to access it. - """ - return self.__writer - - @_writer.setter - def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None: - """Set the writer task for streaming data.""" - if self.__writer is not None: - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = writer - if writer is None: - return - if writer.done(): - # The writer is already done, so we can clear it immediately. - self.__writer = None - else: - writer.add_done_callback(self.__reset_writer) - - @property - def cookies(self) -> SimpleCookie: - if self._cookies is None: - if self._raw_cookie_headers is not None: - # Parse cookies for response.cookies (SimpleCookie for backward compatibility) - cookies = SimpleCookie() - # Use parse_set_cookie_headers for more lenient parsing that handles - # malformed cookies better than SimpleCookie.load - cookies.update(parse_set_cookie_headers(self._raw_cookie_headers)) - self._cookies = cookies - else: - self._cookies = SimpleCookie() - return self._cookies - - @cookies.setter - def cookies(self, cookies: SimpleCookie) -> None: - self._cookies = cookies - # Generate raw cookie headers from the SimpleCookie - if cookies: - self._raw_cookie_headers = tuple( - morsel.OutputString() for morsel in cookies.values() - ) - else: - self._raw_cookie_headers = None - - @reify - def url(self) -> URL: - return self._url - - @reify - def url_obj(self) -> URL: - warnings.warn("Deprecated, use .url #1654", DeprecationWarning, stacklevel=2) - return self._url - - @reify - def real_url(self) -> URL: - return self._real_url - - @reify - def host(self) -> str: - assert self._url.host is not None - return self._url.host - - @reify - def headers(self) -> "CIMultiDictProxy[str]": - return self._headers - - @reify - def raw_headers(self) -> RawHeaders: - return self._raw_headers - - @reify - def request_info(self) -> RequestInfo: - return self._request_info - - @reify - def content_disposition(self) -> Optional[ContentDisposition]: - raw = self._headers.get(hdrs.CONTENT_DISPOSITION) - if raw is None: - return None - disposition_type, params_dct = multipart.parse_content_disposition(raw) - params = MappingProxyType(params_dct) - filename = multipart.content_disposition_filename(params) - return ContentDisposition(disposition_type, params, filename) - - def __del__(self, _warnings: Any = warnings) -> None: - if self._closed: - return - - if self._connection is not None: - self._connection.release() - self._cleanup_writer() - - if self._loop.get_debug(): - kwargs = {"source": self} - _warnings.warn(f"Unclosed response {self!r}", ResourceWarning, **kwargs) - context = {"client_response": self, "message": "Unclosed response"} - if self._source_traceback: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __repr__(self) -> str: - out = io.StringIO() - ascii_encodable_url = str(self.url) - if self.reason: - ascii_encodable_reason = self.reason.encode( - "ascii", "backslashreplace" - ).decode("ascii") - else: - ascii_encodable_reason = "None" - print( - "".format( - ascii_encodable_url, self.status, ascii_encodable_reason - ), - file=out, - ) - print(self.headers, file=out) - return out.getvalue() - - @property - def connection(self) -> Optional["Connection"]: - return self._connection - - @reify - def history(self) -> Tuple["ClientResponse", ...]: - """A sequence of of responses, if redirects occurred.""" - return self._history - - @reify - def links(self) -> "MultiDictProxy[MultiDictProxy[Union[str, URL]]]": - links_str = ", ".join(self.headers.getall("link", [])) - - if not links_str: - return MultiDictProxy(MultiDict()) - - links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict() - - for val in re.split(r",(?=\s*<)", links_str): - match = re.match(r"\s*<(.*)>(.*)", val) - if match is None: # pragma: no cover - # the check exists to suppress mypy error - continue - url, params_str = match.groups() - params = params_str.split(";")[1:] - - link: MultiDict[Union[str, URL]] = MultiDict() - - for param in params: - match = re.match(r"^\s*(\S*)\s*=\s*(['\"]?)(.*?)(\2)\s*$", param, re.M) - if match is None: # pragma: no cover - # the check exists to suppress mypy error - continue - key, _, value, _ = match.groups() - - link.add(key, value) - - key = link.get("rel", url) - - link.add("url", self.url.join(URL(url))) - - links.add(str(key), MultiDictProxy(link)) - - return MultiDictProxy(links) - - async def start(self, connection: "Connection") -> "ClientResponse": - """Start response processing.""" - self._closed = False - self._protocol = connection.protocol - self._connection = connection - - with self._timer: - while True: - # read response - try: - protocol = self._protocol - message, payload = await protocol.read() # type: ignore[union-attr] - except http.HttpProcessingError as exc: - raise ClientResponseError( - self.request_info, - self.history, - status=exc.code, - message=exc.message, - headers=exc.headers, - ) from exc - - if message.code < 100 or message.code > 199 or message.code == 101: - break - - if self._continue is not None: - set_result(self._continue, True) - self._continue = None - - # payload eof handler - payload.on_eof(self._response_eof) - - # response status - self.version = message.version - self.status = message.code - self.reason = message.reason - - # headers - self._headers = message.headers # type is CIMultiDictProxy - self._raw_headers = message.raw_headers # type is Tuple[bytes, bytes] - - # payload - self.content = payload - - # cookies - if cookie_hdrs := self.headers.getall(hdrs.SET_COOKIE, ()): - # Store raw cookie headers for CookieJar - self._raw_cookie_headers = tuple(cookie_hdrs) - return self - - def _response_eof(self) -> None: - if self._closed: - return - - # protocol could be None because connection could be detached - protocol = self._connection and self._connection.protocol - if protocol is not None and protocol.upgraded: - return - - self._closed = True - self._cleanup_writer() - self._release_connection() - - @property - def closed(self) -> bool: - return self._closed - - def close(self) -> None: - if not self._released: - self._notify_content() - - self._closed = True - if self._loop is None or self._loop.is_closed(): - return - - self._cleanup_writer() - if self._connection is not None: - self._connection.close() - self._connection = None - - def release(self) -> Any: - if not self._released: - self._notify_content() - - self._closed = True - - self._cleanup_writer() - self._release_connection() - return noop() - - @property - def ok(self) -> bool: - """Returns ``True`` if ``status`` is less than ``400``, ``False`` if not. - - This is **not** a check for ``200 OK`` but a check that the response - status is under 400. - """ - return 400 > self.status - - def raise_for_status(self) -> None: - if not self.ok: - # reason should always be not None for a started response - assert self.reason is not None - - # If we're in a context we can rely on __aexit__() to release as the - # exception propagates. - if not self._in_context: - self.release() - - raise ClientResponseError( - self.request_info, - self.history, - status=self.status, - message=self.reason, - headers=self.headers, - ) - - def _release_connection(self) -> None: - if self._connection is not None: - if self.__writer is None: - self._connection.release() - self._connection = None - else: - self.__writer.add_done_callback(lambda f: self._release_connection()) - - async def _wait_released(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - self._release_connection() - - def _cleanup_writer(self) -> None: - if self.__writer is not None: - self.__writer.cancel() - self._session = None - - def _notify_content(self) -> None: - content = self.content - if content and content.exception() is None: - set_exception(content, _CONNECTION_CLOSED_EXCEPTION) - self._released = True - - async def wait_for_close(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - self.release() - - async def read(self) -> bytes: - """Read response payload.""" - if self._body is None: - try: - self._body = await self.content.read() - for trace in self._traces: - await trace.send_response_chunk_received( - self.method, self.url, self._body - ) - except BaseException: - self.close() - raise - elif self._released: # Response explicitly released - raise ClientConnectionError("Connection closed") - - protocol = self._connection and self._connection.protocol - if protocol is None or not protocol.upgraded: - await self._wait_released() # Underlying connection released - return self._body - - def get_encoding(self) -> str: - ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() - mimetype = helpers.parse_mimetype(ctype) - - encoding = mimetype.parameters.get("charset") - if encoding: - with contextlib.suppress(LookupError, ValueError): - return codecs.lookup(encoding).name - - if mimetype.type == "application" and ( - mimetype.subtype == "json" or mimetype.subtype == "rdap" - ): - # RFC 7159 states that the default encoding is UTF-8. - # RFC 7483 defines application/rdap+json - return "utf-8" - - if self._body is None: - raise RuntimeError( - "Cannot compute fallback encoding of a not yet read body" - ) - - return self._resolve_charset(self, self._body) - - async def text(self, encoding: Optional[str] = None, errors: str = "strict") -> str: - """Read response payload and decode.""" - if self._body is None: - await self.read() - - if encoding is None: - encoding = self.get_encoding() - - return self._body.decode(encoding, errors=errors) # type: ignore[union-attr] - - async def json( - self, - *, - encoding: Optional[str] = None, - loads: JSONDecoder = DEFAULT_JSON_DECODER, - content_type: Optional[str] = "application/json", - ) -> Any: - """Read and decodes JSON response.""" - if self._body is None: - await self.read() - - if content_type: - ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() - if not _is_expected_content_type(ctype, content_type): - raise ContentTypeError( - self.request_info, - self.history, - status=self.status, - message=( - "Attempt to decode JSON with unexpected mimetype: %s" % ctype - ), - headers=self.headers, - ) - - stripped = self._body.strip() # type: ignore[union-attr] - if not stripped: - return None - - if encoding is None: - encoding = self.get_encoding() - - return loads(stripped.decode(encoding)) - - async def __aenter__(self) -> "ClientResponse": - self._in_context = True - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - self._in_context = False - # similar to _RequestContextManager, we do not need to check - # for exceptions, response object can close connection - # if state is broken - self.release() - await self.wait_for_close() - - -class ClientRequest: - GET_METHODS = { - hdrs.METH_GET, - hdrs.METH_HEAD, - hdrs.METH_OPTIONS, - hdrs.METH_TRACE, - } - POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT} - ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE}) - - DEFAULT_HEADERS = { - hdrs.ACCEPT: "*/*", - hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(), - } - - # Type of body depends on PAYLOAD_REGISTRY, which is dynamic. - _body: Union[None, payload.Payload] = None - auth = None - response = None - - __writer: Optional["asyncio.Task[None]"] = None # async task for streaming data - - # These class defaults help create_autospec() work correctly. - # If autospec is improved in future, maybe these can be removed. - url = URL() - method = "GET" - - _continue = None # waiter future for '100 Continue' response - - _skip_auto_headers: Optional["CIMultiDict[None]"] = None - - # N.B. - # Adding __del__ method with self._writer closing doesn't make sense - # because _writer is instance method, thus it keeps a reference to self. - # Until writer has finished finalizer will not be called. - - def __init__( - self, - method: str, - url: URL, - *, - params: Query = None, - headers: Optional[LooseHeaders] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - data: Any = None, - cookies: Optional[LooseCookies] = None, - auth: Optional[BasicAuth] = None, - version: http.HttpVersion = http.HttpVersion11, - compress: Union[str, bool, None] = None, - chunked: Optional[bool] = None, - expect100: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - response_class: Optional[Type["ClientResponse"]] = None, - proxy: Optional[URL] = None, - proxy_auth: Optional[BasicAuth] = None, - timer: Optional[BaseTimerContext] = None, - session: Optional["ClientSession"] = None, - ssl: Union[SSLContext, bool, Fingerprint] = True, - proxy_headers: Optional[LooseHeaders] = None, - traces: Optional[List["Trace"]] = None, - trust_env: bool = False, - server_hostname: Optional[str] = None, - ): - if loop is None: - loop = asyncio.get_event_loop() - if match := _CONTAINS_CONTROL_CHAR_RE.search(method): - raise ValueError( - f"Method cannot contain non-token characters {method!r} " - f"(found at least {match.group()!r})" - ) - # URL forbids subclasses, so a simple type check is enough. - assert type(url) is URL, url - if proxy is not None: - assert type(proxy) is URL, proxy - # FIXME: session is None in tests only, need to fix tests - # assert session is not None - if TYPE_CHECKING: - assert session is not None - self._session = session - if params: - url = url.extend_query(params) - self.original_url = url - self.url = url.with_fragment(None) if url.raw_fragment else url - self.method = method.upper() - self.chunked = chunked - self.compress = compress - self.loop = loop - self.length = None - if response_class is None: - real_response_class = ClientResponse - else: - real_response_class = response_class - self.response_class: Type[ClientResponse] = real_response_class - self._timer = timer if timer is not None else TimerNoop() - self._ssl = ssl if ssl is not None else True - self.server_hostname = server_hostname - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - self.update_version(version) - self.update_host(url) - self.update_headers(headers) - self.update_auto_headers(skip_auto_headers) - self.update_cookies(cookies) - self.update_content_encoding(data) - self.update_auth(auth, trust_env) - self.update_proxy(proxy, proxy_auth, proxy_headers) - - self.update_body_from_data(data) - if data is not None or self.method not in self.GET_METHODS: - self.update_transfer_encoding() - self.update_expect_continue(expect100) - self._traces = [] if traces is None else traces - - def __reset_writer(self, _: object = None) -> None: - self.__writer = None - - def _get_content_length(self) -> Optional[int]: - """Extract and validate Content-Length header value. - - Returns parsed Content-Length value or None if not set. - Raises ValueError if header exists but cannot be parsed as an integer. - """ - if hdrs.CONTENT_LENGTH not in self.headers: - return None - - content_length_hdr = self.headers[hdrs.CONTENT_LENGTH] - try: - return int(content_length_hdr) - except ValueError: - raise ValueError( - f"Invalid Content-Length header: {content_length_hdr}" - ) from None - - @property - def skip_auto_headers(self) -> CIMultiDict[None]: - return self._skip_auto_headers or CIMultiDict() - - @property - def _writer(self) -> Optional["asyncio.Task[None]"]: - return self.__writer - - @_writer.setter - def _writer(self, writer: "asyncio.Task[None]") -> None: - if self.__writer is not None: - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = writer - writer.add_done_callback(self.__reset_writer) - - def is_ssl(self) -> bool: - return self.url.scheme in _SSL_SCHEMES - - @property - def ssl(self) -> Union["SSLContext", bool, Fingerprint]: - return self._ssl - - @property - def connection_key(self) -> ConnectionKey: - if proxy_headers := self.proxy_headers: - h: Optional[int] = hash(tuple(proxy_headers.items())) - else: - h = None - url = self.url - return tuple.__new__( - ConnectionKey, - ( - url.raw_host or "", - url.port, - url.scheme in _SSL_SCHEMES, - self._ssl, - self.proxy, - self.proxy_auth, - h, - ), - ) - - @property - def host(self) -> str: - ret = self.url.raw_host - assert ret is not None - return ret - - @property - def port(self) -> Optional[int]: - return self.url.port - - @property - def body(self) -> Union[payload.Payload, Literal[b""]]: - """Request body.""" - # empty body is represented as bytes for backwards compatibility - return self._body or b"" - - @body.setter - def body(self, value: Any) -> None: - """Set request body with warning for non-autoclose payloads. - - WARNING: This setter must be called from within an event loop and is not - thread-safe. Setting body outside of an event loop may raise RuntimeError - when closing file-based payloads. - - DEPRECATED: Direct assignment to body is deprecated and will be removed - in a future version. Use await update_body() instead for proper resource - management. - """ - # Close existing payload if present - if self._body is not None: - # Warn if the payload needs manual closing - # stacklevel=3: user code -> body setter -> _warn_if_unclosed_payload - _warn_if_unclosed_payload(self._body, stacklevel=3) - # NOTE: In the future, when we remove sync close support, - # this setter will need to be removed and only the async - # update_body() method will be available. For now, we call - # _close() for backwards compatibility. - self._body._close() - self._update_body(value) - - @property - def request_info(self) -> RequestInfo: - headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers) - # These are created on every request, so we use a NamedTuple - # for performance reasons. We don't use the RequestInfo.__new__ - # method because it has a different signature which is provided - # for backwards compatibility only. - return tuple.__new__( - RequestInfo, (self.url, self.method, headers, self.original_url) - ) - - @property - def session(self) -> "ClientSession": - """Return the ClientSession instance. - - This property provides access to the ClientSession that initiated - this request, allowing middleware to make additional requests - using the same session. - """ - return self._session - - def update_host(self, url: URL) -> None: - """Update destination host, port and connection type (ssl).""" - # get host/port - if not url.raw_host: - raise InvalidURL(url) - - # basic auth info - if url.raw_user or url.raw_password: - self.auth = helpers.BasicAuth(url.user or "", url.password or "") - - def update_version(self, version: Union[http.HttpVersion, str]) -> None: - """Convert request version to two elements tuple. - - parser HTTP version '1.1' => (1, 1) - """ - if isinstance(version, str): - v = [part.strip() for part in version.split(".", 1)] - try: - version = http.HttpVersion(int(v[0]), int(v[1])) - except ValueError: - raise ValueError( - f"Can not parse http version number: {version}" - ) from None - self.version = version - - def update_headers(self, headers: Optional[LooseHeaders]) -> None: - """Update request headers.""" - self.headers: CIMultiDict[str] = CIMultiDict() - - # Build the host header - host = self.url.host_port_subcomponent - - # host_port_subcomponent is None when the URL is a relative URL. - # but we know we do not have a relative URL here. - assert host is not None - self.headers[hdrs.HOST] = host - - if not headers: - return - - if isinstance(headers, (dict, MultiDictProxy, MultiDict)): - headers = headers.items() - - for key, value in headers: # type: ignore[misc] - # A special case for Host header - if key in hdrs.HOST_ALL: - self.headers[key] = value - else: - self.headers.add(key, value) - - def update_auto_headers(self, skip_auto_headers: Optional[Iterable[str]]) -> None: - if skip_auto_headers is not None: - self._skip_auto_headers = CIMultiDict( - (hdr, None) for hdr in sorted(skip_auto_headers) - ) - used_headers = self.headers.copy() - used_headers.extend(self._skip_auto_headers) # type: ignore[arg-type] - else: - # Fast path when there are no headers to skip - # which is the most common case. - used_headers = self.headers - - for hdr, val in self.DEFAULT_HEADERS.items(): - if hdr not in used_headers: - self.headers[hdr] = val - - if hdrs.USER_AGENT not in used_headers: - self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE - - def update_cookies(self, cookies: Optional[LooseCookies]) -> None: - """Update request cookies header.""" - if not cookies: - return - - c = SimpleCookie() - if hdrs.COOKIE in self.headers: - # parse_cookie_header for RFC 6265 compliant Cookie header parsing - c.update(parse_cookie_header(self.headers.get(hdrs.COOKIE, ""))) - del self.headers[hdrs.COOKIE] - - if isinstance(cookies, Mapping): - iter_cookies = cookies.items() - else: - iter_cookies = cookies # type: ignore[assignment] - for name, value in iter_cookies: - if isinstance(value, Morsel): - # Use helper to preserve coded_value exactly as sent by server - c[name] = preserve_morsel_with_coded_value(value) - else: - c[name] = value # type: ignore[assignment] - - self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip() - - def update_content_encoding(self, data: Any) -> None: - """Set request content encoding.""" - if not data: - # Don't compress an empty body. - self.compress = None - return - - if self.headers.get(hdrs.CONTENT_ENCODING): - if self.compress: - raise ValueError( - "compress can not be set if Content-Encoding header is set" - ) - elif self.compress: - if not isinstance(self.compress, str): - self.compress = "deflate" - self.headers[hdrs.CONTENT_ENCODING] = self.compress - self.chunked = True # enable chunked, no need to deal with length - - def update_transfer_encoding(self) -> None: - """Analyze transfer-encoding header.""" - te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower() - - if "chunked" in te: - if self.chunked: - raise ValueError( - "chunked can not be set " - 'if "Transfer-Encoding: chunked" header is set' - ) - - elif self.chunked: - if hdrs.CONTENT_LENGTH in self.headers: - raise ValueError( - "chunked can not be set if Content-Length header is set" - ) - - self.headers[hdrs.TRANSFER_ENCODING] = "chunked" - - def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None: - """Set basic auth.""" - if auth is None: - auth = self.auth - if auth is None: - return - - if not isinstance(auth, helpers.BasicAuth): - raise TypeError("BasicAuth() tuple is required instead") - - self.headers[hdrs.AUTHORIZATION] = auth.encode() - - def update_body_from_data(self, body: Any, _stacklevel: int = 3) -> None: - """Update request body from data.""" - if self._body is not None: - _warn_if_unclosed_payload(self._body, stacklevel=_stacklevel) - - if body is None: - self._body = None - # Set Content-Length to 0 when body is None for methods that expect a body - if ( - self.method not in self.GET_METHODS - and not self.chunked - and hdrs.CONTENT_LENGTH not in self.headers - ): - self.headers[hdrs.CONTENT_LENGTH] = "0" - return - - # FormData - maybe_payload = body() if isinstance(body, FormData) else body - - try: - body_payload = payload.PAYLOAD_REGISTRY.get(maybe_payload, disposition=None) - except payload.LookupError: - body_payload = FormData(maybe_payload)() # type: ignore[arg-type] - - self._body = body_payload - # enable chunked encoding if needed - if not self.chunked and hdrs.CONTENT_LENGTH not in self.headers: - if (size := body_payload.size) is not None: - self.headers[hdrs.CONTENT_LENGTH] = str(size) - else: - self.chunked = True - - # copy payload headers - assert body_payload.headers - headers = self.headers - skip_headers = self._skip_auto_headers - for key, value in body_payload.headers.items(): - if key in headers or (skip_headers is not None and key in skip_headers): - continue - headers[key] = value - - def _update_body(self, body: Any) -> None: - """Update request body after its already been set.""" - # Remove existing Content-Length header since body is changing - if hdrs.CONTENT_LENGTH in self.headers: - del self.headers[hdrs.CONTENT_LENGTH] - - # Remove existing Transfer-Encoding header to avoid conflicts - if self.chunked and hdrs.TRANSFER_ENCODING in self.headers: - del self.headers[hdrs.TRANSFER_ENCODING] - - # Now update the body using the existing method - # Called from _update_body, add 1 to stacklevel from caller - self.update_body_from_data(body, _stacklevel=4) - - # Update transfer encoding headers if needed (same logic as __init__) - if body is not None or self.method not in self.GET_METHODS: - self.update_transfer_encoding() - - async def update_body(self, body: Any) -> None: - """ - Update request body and close previous payload if needed. - - This method safely updates the request body by first closing any existing - payload to prevent resource leaks, then setting the new body. - - IMPORTANT: Always use this method instead of setting request.body directly. - Direct assignment to request.body will leak resources if the previous body - contains file handles, streams, or other resources that need cleanup. - - Args: - body: The new body content. Can be: - - bytes/bytearray: Raw binary data - - str: Text data (will be encoded using charset from Content-Type) - - FormData: Form data that will be encoded as multipart/form-data - - Payload: A pre-configured payload object - - AsyncIterable: An async iterable of bytes chunks - - File-like object: Will be read and sent as binary data - - None: Clears the body - - Usage: - # CORRECT: Use update_body - await request.update_body(b"new request data") - - # WRONG: Don't set body directly - # request.body = b"new request data" # This will leak resources! - - # Update with form data - form_data = FormData() - form_data.add_field('field', 'value') - await request.update_body(form_data) - - # Clear body - await request.update_body(None) - - Note: - This method is async because it may need to close file handles or - other resources associated with the previous payload. Always await - this method to ensure proper cleanup. - - Warning: - Setting request.body directly is highly discouraged and can lead to: - - Resource leaks (unclosed file handles, streams) - - Memory leaks (unreleased buffers) - - Unexpected behavior with streaming payloads - - It is not recommended to change the payload type in middleware. If the - body was already set (e.g., as bytes), it's best to keep the same type - rather than converting it (e.g., to str) as this may result in unexpected - behavior. - - See Also: - - update_body_from_data: Synchronous body update without cleanup - - body property: Direct body access (STRONGLY DISCOURAGED) - - """ - # Close existing payload if it exists and needs closing - if self._body is not None: - await self._body.close() - self._update_body(body) - - def update_expect_continue(self, expect: bool = False) -> None: - if expect: - self.headers[hdrs.EXPECT] = "100-continue" - elif ( - hdrs.EXPECT in self.headers - and self.headers[hdrs.EXPECT].lower() == "100-continue" - ): - expect = True - - if expect: - self._continue = self.loop.create_future() - - def update_proxy( - self, - proxy: Optional[URL], - proxy_auth: Optional[BasicAuth], - proxy_headers: Optional[LooseHeaders], - ) -> None: - self.proxy = proxy - if proxy is None: - self.proxy_auth = None - self.proxy_headers = None - return - - if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth): - raise ValueError("proxy_auth must be None or BasicAuth() tuple") - self.proxy_auth = proxy_auth - - if proxy_headers is not None and not isinstance( - proxy_headers, (MultiDict, MultiDictProxy) - ): - proxy_headers = CIMultiDict(proxy_headers) - self.proxy_headers = proxy_headers - - async def write_bytes( - self, - writer: AbstractStreamWriter, - conn: "Connection", - content_length: Optional[int] = None, - ) -> None: - """ - Write the request body to the connection stream. - - This method handles writing different types of request bodies: - 1. Payload objects (using their specialized write_with_length method) - 2. Bytes/bytearray objects - 3. Iterable body content - - Args: - writer: The stream writer to write the body to - conn: The connection being used for this request - content_length: Optional maximum number of bytes to write from the body - (None means write the entire body) - - The method properly handles: - - Waiting for 100-Continue responses if required - - Content length constraints for chunked encoding - - Error handling for network issues, cancellation, and other exceptions - - Signaling EOF and timeout management - - Raises: - ClientOSError: When there's an OS-level error writing the body - ClientConnectionError: When there's a general connection error - asyncio.CancelledError: When the operation is cancelled - - """ - # 100 response - if self._continue is not None: - # Force headers to be sent before waiting for 100-continue - writer.send_headers() - await writer.drain() - await self._continue - - protocol = conn.protocol - assert protocol is not None - try: - # This should be a rare case but the - # self._body can be set to None while - # the task is being started or we wait above - # for the 100-continue response. - # The more likely case is we have an empty - # payload, but 100-continue is still expected. - if self._body is not None: - await self._body.write_with_length(writer, content_length) - except OSError as underlying_exc: - reraised_exc = underlying_exc - - # Distinguish between timeout and other OS errors for better error reporting - exc_is_not_timeout = underlying_exc.errno is not None or not isinstance( - underlying_exc, asyncio.TimeoutError - ) - if exc_is_not_timeout: - reraised_exc = ClientOSError( - underlying_exc.errno, - f"Can not write request body for {self.url !s}", - ) - - set_exception(protocol, reraised_exc, underlying_exc) - except asyncio.CancelledError: - # Body hasn't been fully sent, so connection can't be reused - conn.close() - raise - except Exception as underlying_exc: - set_exception( - protocol, - ClientConnectionError( - "Failed to send bytes into the underlying connection " - f"{conn !s}: {underlying_exc!r}", - ), - underlying_exc, - ) - else: - # Successfully wrote the body, signal EOF and start response timeout - await writer.write_eof() - protocol.start_timeout() - - async def send(self, conn: "Connection") -> "ClientResponse": - # Specify request target: - # - CONNECT request must send authority form URI - # - not CONNECT proxy must send absolute form URI - # - most common is origin form URI - if self.method == hdrs.METH_CONNECT: - connect_host = self.url.host_subcomponent - assert connect_host is not None - path = f"{connect_host}:{self.url.port}" - elif self.proxy and not self.is_ssl(): - path = str(self.url) - else: - path = self.url.raw_path_qs - - protocol = conn.protocol - assert protocol is not None - writer = StreamWriter( - protocol, - self.loop, - on_chunk_sent=( - functools.partial(self._on_chunk_request_sent, self.method, self.url) - if self._traces - else None - ), - on_headers_sent=( - functools.partial(self._on_headers_request_sent, self.method, self.url) - if self._traces - else None - ), - ) - - if self.compress: - writer.enable_compression(self.compress) # type: ignore[arg-type] - - if self.chunked is not None: - writer.enable_chunking() - - # set default content-type - if ( - self.method in self.POST_METHODS - and ( - self._skip_auto_headers is None - or hdrs.CONTENT_TYPE not in self._skip_auto_headers - ) - and hdrs.CONTENT_TYPE not in self.headers - ): - self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream" - - v = self.version - if hdrs.CONNECTION not in self.headers: - if conn._connector.force_close: - if v == HttpVersion11: - self.headers[hdrs.CONNECTION] = "close" - elif v == HttpVersion10: - self.headers[hdrs.CONNECTION] = "keep-alive" - - # status + headers - status_line = f"{self.method} {path} HTTP/{v.major}.{v.minor}" - - # Buffer headers for potential coalescing with body - await writer.write_headers(status_line, self.headers) - - task: Optional["asyncio.Task[None]"] - if self._body or self._continue is not None or protocol.writing_paused: - coro = self.write_bytes(writer, conn, self._get_content_length()) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to write - # bytes immediately to avoid having to schedule - # the task on the event loop. - task = asyncio.Task(coro, loop=self.loop, eager_start=True) - else: - task = self.loop.create_task(coro) - if task.done(): - task = None - else: - self._writer = task - else: - # We have nothing to write because - # - there is no body - # - the protocol does not have writing paused - # - we are not waiting for a 100-continue response - protocol.start_timeout() - writer.set_eof() - task = None - response_class = self.response_class - assert response_class is not None - self.response = response_class( - self.method, - self.original_url, - writer=task, - continue100=self._continue, - timer=self._timer, - request_info=self.request_info, - traces=self._traces, - loop=self.loop, - session=self._session, - ) - return self.response - - async def close(self) -> None: - if self.__writer is not None: - try: - await self.__writer - except asyncio.CancelledError: - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - - def terminate(self) -> None: - if self.__writer is not None: - if not self.loop.is_closed(): - self.__writer.cancel() - self.__writer.remove_done_callback(self.__reset_writer) - self.__writer = None - - async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None: - for trace in self._traces: - await trace.send_request_chunk_sent(method, url, chunk) - - async def _on_headers_request_sent( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - for trace in self._traces: - await trace.send_request_headers(method, url, headers) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_ws.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/client_ws.py deleted file mode 100644 index daa57d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/client_ws.py +++ /dev/null @@ -1,428 +0,0 @@ -"""WebSocket client for asyncio.""" - -import asyncio -import sys -from types import TracebackType -from typing import Any, Optional, Type, cast - -import attr - -from ._websocket.reader import WebSocketDataQueue -from .client_exceptions import ClientError, ServerTimeoutError, WSMessageTypeError -from .client_reqrep import ClientResponse -from .helpers import calculate_timeout_when, set_result -from .http import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WebSocketError, - WSCloseCode, - WSMessage, - WSMsgType, -) -from .http_websocket import _INTERNAL_RECEIVE_TYPES, WebSocketWriter -from .streams import EofStream -from .typedefs import ( - DEFAULT_JSON_DECODER, - DEFAULT_JSON_ENCODER, - JSONDecoder, - JSONEncoder, -) - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - - -@attr.s(frozen=True, slots=True) -class ClientWSTimeout: - ws_receive = attr.ib(type=Optional[float], default=None) - ws_close = attr.ib(type=Optional[float], default=None) - - -DEFAULT_WS_CLIENT_TIMEOUT = ClientWSTimeout(ws_receive=None, ws_close=10.0) - - -class ClientWebSocketResponse: - def __init__( - self, - reader: WebSocketDataQueue, - writer: WebSocketWriter, - protocol: Optional[str], - response: ClientResponse, - timeout: ClientWSTimeout, - autoclose: bool, - autoping: bool, - loop: asyncio.AbstractEventLoop, - *, - heartbeat: Optional[float] = None, - compress: int = 0, - client_notakeover: bool = False, - ) -> None: - self._response = response - self._conn = response.connection - - self._writer = writer - self._reader = reader - self._protocol = protocol - self._closed = False - self._closing = False - self._close_code: Optional[int] = None - self._timeout = timeout - self._autoclose = autoclose - self._autoping = autoping - self._heartbeat = heartbeat - self._heartbeat_cb: Optional[asyncio.TimerHandle] = None - self._heartbeat_when: float = 0.0 - if heartbeat is not None: - self._pong_heartbeat = heartbeat / 2.0 - self._pong_response_cb: Optional[asyncio.TimerHandle] = None - self._loop = loop - self._waiting: bool = False - self._close_wait: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._compress = compress - self._client_notakeover = client_notakeover - self._ping_task: Optional[asyncio.Task[None]] = None - - self._reset_heartbeat() - - def _cancel_heartbeat(self) -> None: - self._cancel_pong_response_cb() - if self._heartbeat_cb is not None: - self._heartbeat_cb.cancel() - self._heartbeat_cb = None - if self._ping_task is not None: - self._ping_task.cancel() - self._ping_task = None - - def _cancel_pong_response_cb(self) -> None: - if self._pong_response_cb is not None: - self._pong_response_cb.cancel() - self._pong_response_cb = None - - def _reset_heartbeat(self) -> None: - if self._heartbeat is None: - return - self._cancel_pong_response_cb() - loop = self._loop - assert loop is not None - conn = self._conn - timeout_ceil_threshold = ( - conn._connector._timeout_ceil_threshold if conn is not None else 5 - ) - now = loop.time() - when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) - self._heartbeat_when = when - if self._heartbeat_cb is None: - # We do not cancel the previous heartbeat_cb here because - # it generates a significant amount of TimerHandle churn - # which causes asyncio to rebuild the heap frequently. - # Instead _send_heartbeat() will reschedule the next - # heartbeat if it fires too early. - self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) - - def _send_heartbeat(self) -> None: - self._heartbeat_cb = None - loop = self._loop - now = loop.time() - if now < self._heartbeat_when: - # Heartbeat fired too early, reschedule - self._heartbeat_cb = loop.call_at( - self._heartbeat_when, self._send_heartbeat - ) - return - - conn = self._conn - timeout_ceil_threshold = ( - conn._connector._timeout_ceil_threshold if conn is not None else 5 - ) - when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) - self._cancel_pong_response_cb() - self._pong_response_cb = loop.call_at(when, self._pong_not_received) - - coro = self._writer.send_frame(b"", WSMsgType.PING) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send the ping - # immediately to avoid having to schedule - # the task on the event loop. - ping_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - ping_task = loop.create_task(coro) - - if not ping_task.done(): - self._ping_task = ping_task - ping_task.add_done_callback(self._ping_task_done) - else: - self._ping_task_done(ping_task) - - def _ping_task_done(self, task: "asyncio.Task[None]") -> None: - """Callback for when the ping task completes.""" - if not task.cancelled() and (exc := task.exception()): - self._handle_ping_pong_exception(exc) - self._ping_task = None - - def _pong_not_received(self) -> None: - self._handle_ping_pong_exception( - ServerTimeoutError(f"No PONG received after {self._pong_heartbeat} seconds") - ) - - def _handle_ping_pong_exception(self, exc: BaseException) -> None: - """Handle exceptions raised during ping/pong processing.""" - if self._closed: - return - self._set_closed() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - if self._waiting and not self._closing: - self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) - - def _set_closed(self) -> None: - """Set the connection to closed. - - Cancel any heartbeat timers and set the closed flag. - """ - self._closed = True - self._cancel_heartbeat() - - def _set_closing(self) -> None: - """Set the connection to closing. - - Cancel any heartbeat timers and set the closing flag. - """ - self._closing = True - self._cancel_heartbeat() - - @property - def closed(self) -> bool: - return self._closed - - @property - def close_code(self) -> Optional[int]: - return self._close_code - - @property - def protocol(self) -> Optional[str]: - return self._protocol - - @property - def compress(self) -> int: - return self._compress - - @property - def client_notakeover(self) -> bool: - return self._client_notakeover - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """extra info from connection transport""" - conn = self._response.connection - if conn is None: - return default - transport = conn.transport - if transport is None: - return default - return transport.get_extra_info(name, default) - - def exception(self) -> Optional[BaseException]: - return self._exception - - async def ping(self, message: bytes = b"") -> None: - await self._writer.send_frame(message, WSMsgType.PING) - - async def pong(self, message: bytes = b"") -> None: - await self._writer.send_frame(message, WSMsgType.PONG) - - async def send_frame( - self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket.""" - await self._writer.send_frame(message, opcode, compress) - - async def send_str(self, data: str, compress: Optional[int] = None) -> None: - if not isinstance(data, str): - raise TypeError("data argument must be str (%r)" % type(data)) - await self._writer.send_frame( - data.encode("utf-8"), WSMsgType.TEXT, compress=compress - ) - - async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: - if not isinstance(data, (bytes, bytearray, memoryview)): - raise TypeError("data argument must be byte-ish (%r)" % type(data)) - await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) - - async def send_json( - self, - data: Any, - compress: Optional[int] = None, - *, - dumps: JSONEncoder = DEFAULT_JSON_ENCODER, - ) -> None: - await self.send_str(dumps(data), compress=compress) - - async def close(self, *, code: int = WSCloseCode.OK, message: bytes = b"") -> bool: - # we need to break `receive()` cycle first, - # `close()` may be called from different task - if self._waiting and not self._closing: - assert self._loop is not None - self._close_wait = self._loop.create_future() - self._set_closing() - self._reader.feed_data(WS_CLOSING_MESSAGE, 0) - await self._close_wait - - if self._closed: - return False - - self._set_closed() - try: - await self._writer.close(code, message) - except asyncio.CancelledError: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._response.close() - raise - except Exception as exc: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - return True - - if self._close_code: - self._response.close() - return True - - while True: - try: - async with async_timeout.timeout(self._timeout.ws_close): - msg = await self._reader.read() - except asyncio.CancelledError: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._response.close() - raise - except Exception as exc: - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - self._exception = exc - self._response.close() - return True - - if msg.type is WSMsgType.CLOSE: - self._close_code = msg.data - self._response.close() - return True - - async def receive(self, timeout: Optional[float] = None) -> WSMessage: - receive_timeout = timeout or self._timeout.ws_receive - - while True: - if self._waiting: - raise RuntimeError("Concurrent call to receive() is not allowed") - - if self._closed: - return WS_CLOSED_MESSAGE - elif self._closing: - await self.close() - return WS_CLOSED_MESSAGE - - try: - self._waiting = True - try: - if receive_timeout: - # Entering the context manager and creating - # Timeout() object can take almost 50% of the - # run time in this loop so we avoid it if - # there is no read timeout. - async with async_timeout.timeout(receive_timeout): - msg = await self._reader.read() - else: - msg = await self._reader.read() - self._reset_heartbeat() - finally: - self._waiting = False - if self._close_wait: - set_result(self._close_wait, None) - except (asyncio.CancelledError, asyncio.TimeoutError): - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - raise - except EofStream: - self._close_code = WSCloseCode.OK - await self.close() - return WSMessage(WSMsgType.CLOSED, None, None) - except ClientError: - # Likely ServerDisconnectedError when connection is lost - self._set_closed() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - return WS_CLOSED_MESSAGE - except WebSocketError as exc: - self._close_code = exc.code - await self.close(code=exc.code) - return WSMessage(WSMsgType.ERROR, exc, None) - except Exception as exc: - self._exception = exc - self._set_closing() - self._close_code = WSCloseCode.ABNORMAL_CLOSURE - await self.close() - return WSMessage(WSMsgType.ERROR, exc, None) - - if msg.type not in _INTERNAL_RECEIVE_TYPES: - # If its not a close/closing/ping/pong message - # we can return it immediately - return msg - - if msg.type is WSMsgType.CLOSE: - self._set_closing() - self._close_code = msg.data - if not self._closed and self._autoclose: - await self.close() - elif msg.type is WSMsgType.CLOSING: - self._set_closing() - elif msg.type is WSMsgType.PING and self._autoping: - await self.pong(msg.data) - continue - elif msg.type is WSMsgType.PONG and self._autoping: - continue - - return msg - - async def receive_str(self, *, timeout: Optional[float] = None) -> str: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.TEXT: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" - ) - return cast(str, msg.data) - - async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.BINARY: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" - ) - return cast(bytes, msg.data) - - async def receive_json( - self, - *, - loads: JSONDecoder = DEFAULT_JSON_DECODER, - timeout: Optional[float] = None, - ) -> Any: - data = await self.receive_str(timeout=timeout) - return loads(data) - - def __aiter__(self) -> "ClientWebSocketResponse": - return self - - async def __anext__(self) -> WSMessage: - msg = await self.receive() - if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): - raise StopAsyncIteration - return msg - - async def __aenter__(self) -> "ClientWebSocketResponse": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - await self.close() diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/compression_utils.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/compression_utils.py deleted file mode 100644 index e478d24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/compression_utils.py +++ /dev/null @@ -1,348 +0,0 @@ -import asyncio -import sys -import zlib -from abc import ABC, abstractmethod -from concurrent.futures import Executor -from typing import Any, Final, Optional, Protocol, TypedDict, cast - -if sys.version_info >= (3, 12): - from collections.abc import Buffer -else: - from typing import Union - - Buffer = Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - -try: - try: - import brotlicffi as brotli - except ImportError: - import brotli - - HAS_BROTLI = True -except ImportError: # pragma: no cover - HAS_BROTLI = False - -try: - if sys.version_info >= (3, 14): - from compression.zstd import ZstdDecompressor # noqa: I900 - else: # TODO(PY314): Remove mentions of backports.zstd across codebase - from backports.zstd import ZstdDecompressor - - HAS_ZSTD = True -except ImportError: - HAS_ZSTD = False - - -MAX_SYNC_CHUNK_SIZE = 4096 -DEFAULT_MAX_DECOMPRESS_SIZE = 2**25 # 32MiB - -# Unlimited decompression constants - different libraries use different conventions -ZLIB_MAX_LENGTH_UNLIMITED = 0 # zlib uses 0 to mean unlimited -ZSTD_MAX_LENGTH_UNLIMITED = -1 # zstd uses -1 to mean unlimited - - -class ZLibCompressObjProtocol(Protocol): - def compress(self, data: Buffer) -> bytes: ... - def flush(self, mode: int = ..., /) -> bytes: ... - - -class ZLibDecompressObjProtocol(Protocol): - def decompress(self, data: Buffer, max_length: int = ...) -> bytes: ... - def flush(self, length: int = ..., /) -> bytes: ... - - @property - def eof(self) -> bool: ... - - -class ZLibBackendProtocol(Protocol): - MAX_WBITS: int - Z_FULL_FLUSH: int - Z_SYNC_FLUSH: int - Z_BEST_SPEED: int - Z_FINISH: int - - def compressobj( - self, - level: int = ..., - method: int = ..., - wbits: int = ..., - memLevel: int = ..., - strategy: int = ..., - zdict: Optional[Buffer] = ..., - ) -> ZLibCompressObjProtocol: ... - def decompressobj( - self, wbits: int = ..., zdict: Buffer = ... - ) -> ZLibDecompressObjProtocol: ... - - def compress( - self, data: Buffer, /, level: int = ..., wbits: int = ... - ) -> bytes: ... - def decompress( - self, data: Buffer, /, wbits: int = ..., bufsize: int = ... - ) -> bytes: ... - - -class CompressObjArgs(TypedDict, total=False): - wbits: int - strategy: int - level: int - - -class ZLibBackendWrapper: - def __init__(self, _zlib_backend: ZLibBackendProtocol): - self._zlib_backend: ZLibBackendProtocol = _zlib_backend - - @property - def name(self) -> str: - return getattr(self._zlib_backend, "__name__", "undefined") - - @property - def MAX_WBITS(self) -> int: - return self._zlib_backend.MAX_WBITS - - @property - def Z_FULL_FLUSH(self) -> int: - return self._zlib_backend.Z_FULL_FLUSH - - @property - def Z_SYNC_FLUSH(self) -> int: - return self._zlib_backend.Z_SYNC_FLUSH - - @property - def Z_BEST_SPEED(self) -> int: - return self._zlib_backend.Z_BEST_SPEED - - @property - def Z_FINISH(self) -> int: - return self._zlib_backend.Z_FINISH - - def compressobj(self, *args: Any, **kwargs: Any) -> ZLibCompressObjProtocol: - return self._zlib_backend.compressobj(*args, **kwargs) - - def decompressobj(self, *args: Any, **kwargs: Any) -> ZLibDecompressObjProtocol: - return self._zlib_backend.decompressobj(*args, **kwargs) - - def compress(self, data: Buffer, *args: Any, **kwargs: Any) -> bytes: - return self._zlib_backend.compress(data, *args, **kwargs) - - def decompress(self, data: Buffer, *args: Any, **kwargs: Any) -> bytes: - return self._zlib_backend.decompress(data, *args, **kwargs) - - # Everything not explicitly listed in the Protocol we just pass through - def __getattr__(self, attrname: str) -> Any: - return getattr(self._zlib_backend, attrname) - - -ZLibBackend: ZLibBackendWrapper = ZLibBackendWrapper(zlib) - - -def set_zlib_backend(new_zlib_backend: ZLibBackendProtocol) -> None: - ZLibBackend._zlib_backend = new_zlib_backend - - -def encoding_to_mode( - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, -) -> int: - if encoding == "gzip": - return 16 + ZLibBackend.MAX_WBITS - - return -ZLibBackend.MAX_WBITS if suppress_deflate_header else ZLibBackend.MAX_WBITS - - -class DecompressionBaseHandler(ABC): - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - """Base class for decompression handlers.""" - self._executor = executor - self._max_sync_chunk_size = max_sync_chunk_size - - @abstractmethod - def decompress_sync( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - - async def decompress( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - if ( - self._max_sync_chunk_size is not None - and len(data) > self._max_sync_chunk_size - ): - return await asyncio.get_event_loop().run_in_executor( - self._executor, self.decompress_sync, data, max_length - ) - return self.decompress_sync(data, max_length) - - -class ZLibCompressor: - def __init__( - self, - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, - level: Optional[int] = None, - wbits: Optional[int] = None, - strategy: Optional[int] = None, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - self._executor = executor - self._max_sync_chunk_size = max_sync_chunk_size - self._mode = ( - encoding_to_mode(encoding, suppress_deflate_header) - if wbits is None - else wbits - ) - self._zlib_backend: Final = ZLibBackendWrapper(ZLibBackend._zlib_backend) - - kwargs: CompressObjArgs = {} - kwargs["wbits"] = self._mode - if strategy is not None: - kwargs["strategy"] = strategy - if level is not None: - kwargs["level"] = level - self._compressor = self._zlib_backend.compressobj(**kwargs) - - def compress_sync(self, data: bytes) -> bytes: - return self._compressor.compress(data) - - async def compress(self, data: bytes) -> bytes: - """Compress the data and returned the compressed bytes. - - Note that flush() must be called after the last call to compress() - - If the data size is large than the max_sync_chunk_size, the compression - will be done in the executor. Otherwise, the compression will be done - in the event loop. - - **WARNING: This method is NOT cancellation-safe when used with flush().** - If this operation is cancelled, the compressor state may be corrupted. - The connection MUST be closed after cancellation to avoid data corruption - in subsequent compress operations. - - For cancellation-safe compression (e.g., WebSocket), the caller MUST wrap - compress() + flush() + send operations in a shield and lock to ensure atomicity. - """ - # For large payloads, offload compression to executor to avoid blocking event loop - should_use_executor = ( - self._max_sync_chunk_size is not None - and len(data) > self._max_sync_chunk_size - ) - if should_use_executor: - return await asyncio.get_running_loop().run_in_executor( - self._executor, self._compressor.compress, data - ) - return self.compress_sync(data) - - def flush(self, mode: Optional[int] = None) -> bytes: - """Flush the compressor synchronously. - - **WARNING: This method is NOT cancellation-safe when called after compress().** - The flush() operation accesses shared compressor state. If compress() was - cancelled, calling flush() may result in corrupted data. The connection MUST - be closed after compress() cancellation. - - For cancellation-safe compression (e.g., WebSocket), the caller MUST wrap - compress() + flush() + send operations in a shield and lock to ensure atomicity. - """ - return self._compressor.flush( - mode if mode is not None else self._zlib_backend.Z_FINISH - ) - - -class ZLibDecompressor(DecompressionBaseHandler): - def __init__( - self, - encoding: Optional[str] = None, - suppress_deflate_header: bool = False, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ): - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - self._mode = encoding_to_mode(encoding, suppress_deflate_header) - self._zlib_backend: Final = ZLibBackendWrapper(ZLibBackend._zlib_backend) - self._decompressor = self._zlib_backend.decompressobj(wbits=self._mode) - - def decompress_sync( - self, data: Buffer, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - return self._decompressor.decompress(data, max_length) - - def flush(self, length: int = 0) -> bytes: - return ( - self._decompressor.flush(length) - if length > 0 - else self._decompressor.flush() - ) - - @property - def eof(self) -> bool: - return self._decompressor.eof - - -class BrotliDecompressor(DecompressionBaseHandler): - # Supports both 'brotlipy' and 'Brotli' packages - # since they share an import name. The top branches - # are for 'brotlipy' and bottom branches for 'Brotli' - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ) -> None: - """Decompress data using the Brotli library.""" - if not HAS_BROTLI: - raise RuntimeError( - "The brotli decompression is not available. " - "Please install `Brotli` module" - ) - self._obj = brotli.Decompressor() - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - - def decompress_sync( - self, data: Buffer, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - """Decompress the given data.""" - if hasattr(self._obj, "decompress"): - return cast(bytes, self._obj.decompress(data, max_length)) - return cast(bytes, self._obj.process(data, max_length)) - - def flush(self) -> bytes: - """Flush the decompressor.""" - if hasattr(self._obj, "flush"): - return cast(bytes, self._obj.flush()) - return b"" - - -class ZSTDDecompressor(DecompressionBaseHandler): - def __init__( - self, - executor: Optional[Executor] = None, - max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, - ) -> None: - if not HAS_ZSTD: - raise RuntimeError( - "The zstd decompression is not available. " - "Please install `backports.zstd` module" - ) - self._obj = ZstdDecompressor() - super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size) - - def decompress_sync( - self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED - ) -> bytes: - # zstd uses -1 for unlimited, while zlib uses 0 for unlimited - # Convert the zlib convention (0=unlimited) to zstd convention (-1=unlimited) - zstd_max_length = ( - ZSTD_MAX_LENGTH_UNLIMITED - if max_length == ZLIB_MAX_LENGTH_UNLIMITED - else max_length - ) - return self._obj.decompress(data, zstd_max_length) - - def flush(self) -> bytes: - return b"" diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/connector.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/connector.py deleted file mode 100644 index 290a424..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/connector.py +++ /dev/null @@ -1,1842 +0,0 @@ -import asyncio -import functools -import random -import socket -import sys -import traceback -import warnings -from collections import OrderedDict, defaultdict, deque -from contextlib import suppress -from http import HTTPStatus -from itertools import chain, cycle, islice -from time import monotonic -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - DefaultDict, - Deque, - Dict, - Iterator, - List, - Literal, - Optional, - Sequence, - Set, - Tuple, - Type, - Union, - cast, -) - -import aiohappyeyeballs -from aiohappyeyeballs import AddrInfoType, SocketFactoryType - -from . import hdrs, helpers -from .abc import AbstractResolver, ResolveResult -from .client_exceptions import ( - ClientConnectionError, - ClientConnectorCertificateError, - ClientConnectorDNSError, - ClientConnectorError, - ClientConnectorSSLError, - ClientHttpProxyError, - ClientProxyConnectionError, - ServerFingerprintMismatch, - UnixClientConnectorError, - cert_errors, - ssl_errors, -) -from .client_proto import ResponseHandler -from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params -from .helpers import ( - _SENTINEL, - ceil_timeout, - is_ip_address, - noop, - sentinel, - set_exception, - set_result, -) -from .log import client_logger -from .resolver import DefaultResolver - -if sys.version_info >= (3, 12): - from collections.abc import Buffer -else: - Buffer = Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - -EMPTY_SCHEMA_SET = frozenset({""}) -HTTP_SCHEMA_SET = frozenset({"http", "https"}) -WS_SCHEMA_SET = frozenset({"ws", "wss"}) - -HTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET -HIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET - -NEEDS_CLEANUP_CLOSED = (3, 13, 0) <= sys.version_info < ( - 3, - 13, - 1, -) or sys.version_info < (3, 12, 7) -# Cleanup closed is no longer needed after https://github.com/python/cpython/pull/118960 -# which first appeared in Python 3.12.7 and 3.13.1 - - -__all__ = ( - "BaseConnector", - "TCPConnector", - "UnixConnector", - "NamedPipeConnector", - "AddrInfoType", - "SocketFactoryType", -) - - -if TYPE_CHECKING: - from .client import ClientTimeout - from .client_reqrep import ConnectionKey - from .tracing import Trace - - -class _DeprecationWaiter: - __slots__ = ("_awaitable", "_awaited") - - def __init__(self, awaitable: Awaitable[Any]) -> None: - self._awaitable = awaitable - self._awaited = False - - def __await__(self) -> Any: - self._awaited = True - return self._awaitable.__await__() - - def __del__(self) -> None: - if not self._awaited: - warnings.warn( - "Connector.close() is a coroutine, " - "please use await connector.close()", - DeprecationWarning, - ) - - -async def _wait_for_close(waiters: List[Awaitable[object]]) -> None: - """Wait for all waiters to finish closing.""" - results = await asyncio.gather(*waiters, return_exceptions=True) - for res in results: - if isinstance(res, Exception): - client_logger.debug("Error while closing connector: %r", res) - - -class Connection: - - _source_traceback = None - - def __init__( - self, - connector: "BaseConnector", - key: "ConnectionKey", - protocol: ResponseHandler, - loop: asyncio.AbstractEventLoop, - ) -> None: - self._key = key - self._connector = connector - self._loop = loop - self._protocol: Optional[ResponseHandler] = protocol - self._callbacks: List[Callable[[], None]] = [] - - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - def __repr__(self) -> str: - return f"Connection<{self._key}>" - - def __del__(self, _warnings: Any = warnings) -> None: - if self._protocol is not None: - kwargs = {"source": self} - _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs) - if self._loop.is_closed(): - return - - self._connector._release(self._key, self._protocol, should_close=True) - - context = {"client_connection": self, "message": "Unclosed connection"} - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __bool__(self) -> Literal[True]: - """Force subclasses to not be falsy, to make checks simpler.""" - return True - - @property - def loop(self) -> asyncio.AbstractEventLoop: - warnings.warn( - "connector.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - @property - def transport(self) -> Optional[asyncio.Transport]: - if self._protocol is None: - return None - return self._protocol.transport - - @property - def protocol(self) -> Optional[ResponseHandler]: - return self._protocol - - def add_callback(self, callback: Callable[[], None]) -> None: - if callback is not None: - self._callbacks.append(callback) - - def _notify_release(self) -> None: - callbacks, self._callbacks = self._callbacks[:], [] - - for cb in callbacks: - with suppress(Exception): - cb() - - def close(self) -> None: - self._notify_release() - - if self._protocol is not None: - self._connector._release(self._key, self._protocol, should_close=True) - self._protocol = None - - def release(self) -> None: - self._notify_release() - - if self._protocol is not None: - self._connector._release(self._key, self._protocol) - self._protocol = None - - @property - def closed(self) -> bool: - return self._protocol is None or not self._protocol.is_connected() - - -class _ConnectTunnelConnection(Connection): - """Special connection wrapper for CONNECT tunnels that must never be pooled. - - This connection wraps the proxy connection that will be upgraded with TLS. - It must never be released to the pool because: - 1. Its 'closed' future will never complete, causing session.close() to hang - 2. It represents an intermediate state, not a reusable connection - 3. The real connection (with TLS) will be created separately - """ - - def release(self) -> None: - """Do nothing - don't pool or close the connection. - - These connections are an intermediate state during the CONNECT tunnel - setup and will be cleaned up naturally after the TLS upgrade. If they - were to be pooled, they would never be properly closed, causing - session.close() to wait forever for their 'closed' future. - """ - - -class _TransportPlaceholder: - """placeholder for BaseConnector.connect function""" - - __slots__ = ("closed", "transport") - - def __init__(self, closed_future: asyncio.Future[Optional[Exception]]) -> None: - """Initialize a placeholder for a transport.""" - self.closed = closed_future - self.transport = None - - def close(self) -> None: - """Close the placeholder.""" - - def abort(self) -> None: - """Abort the placeholder (does nothing).""" - - -class BaseConnector: - """Base connector class. - - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - enable_cleanup_closed - Enables clean-up closed ssl transports. - Disabled by default. - timeout_ceil_threshold - Trigger ceiling of timeout values when - it's above timeout_ceil_threshold. - loop - Optional event loop. - """ - - _closed = True # prevent AttributeError in __del__ if ctor was failed - _source_traceback = None - - # abort transport after 2 seconds (cleanup broken connections) - _cleanup_closed_period = 2.0 - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET - - def __init__( - self, - *, - keepalive_timeout: Union[object, None, float] = sentinel, - force_close: bool = False, - limit: int = 100, - limit_per_host: int = 0, - enable_cleanup_closed: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - timeout_ceil_threshold: float = 5, - ) -> None: - - if force_close: - if keepalive_timeout is not None and keepalive_timeout is not sentinel: - raise ValueError( - "keepalive_timeout cannot be set if force_close is True" - ) - else: - if keepalive_timeout is sentinel: - keepalive_timeout = 15.0 - - loop = loop or asyncio.get_running_loop() - self._timeout_ceil_threshold = timeout_ceil_threshold - - self._closed = False - if loop.get_debug(): - self._source_traceback = traceback.extract_stack(sys._getframe(1)) - - # Connection pool of reusable connections. - # We use a deque to store connections because it has O(1) popleft() - # and O(1) append() operations to implement a FIFO queue. - self._conns: DefaultDict[ - ConnectionKey, Deque[Tuple[ResponseHandler, float]] - ] = defaultdict(deque) - self._limit = limit - self._limit_per_host = limit_per_host - self._acquired: Set[ResponseHandler] = set() - self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = ( - defaultdict(set) - ) - self._keepalive_timeout = cast(float, keepalive_timeout) - self._force_close = force_close - - # {host_key: FIFO list of waiters} - # The FIFO is implemented with an OrderedDict with None keys because - # python does not have an ordered set. - self._waiters: DefaultDict[ - ConnectionKey, OrderedDict[asyncio.Future[None], None] - ] = defaultdict(OrderedDict) - - self._loop = loop - self._factory = functools.partial(ResponseHandler, loop=loop) - - # start keep-alive connection cleanup task - self._cleanup_handle: Optional[asyncio.TimerHandle] = None - - # start cleanup closed transports task - self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None - - if enable_cleanup_closed and not NEEDS_CLEANUP_CLOSED: - warnings.warn( - "enable_cleanup_closed ignored because " - "https://github.com/python/cpython/pull/118960 is fixed " - f"in Python version {sys.version_info}", - DeprecationWarning, - stacklevel=2, - ) - enable_cleanup_closed = False - - self._cleanup_closed_disabled = not enable_cleanup_closed - self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = [] - self._placeholder_future: asyncio.Future[Optional[Exception]] = ( - loop.create_future() - ) - self._placeholder_future.set_result(None) - self._cleanup_closed() - - def __del__(self, _warnings: Any = warnings) -> None: - if self._closed: - return - if not self._conns: - return - - conns = [repr(c) for c in self._conns.values()] - - self._close() - - kwargs = {"source": self} - _warnings.warn(f"Unclosed connector {self!r}", ResourceWarning, **kwargs) - context = { - "connector": self, - "connections": conns, - "message": "Unclosed connector", - } - if self._source_traceback is not None: - context["source_traceback"] = self._source_traceback - self._loop.call_exception_handler(context) - - def __enter__(self) -> "BaseConnector": - warnings.warn( - '"with Connector():" is deprecated, ' - 'use "async with Connector():" instead', - DeprecationWarning, - ) - return self - - def __exit__(self, *exc: Any) -> None: - self._close() - - async def __aenter__(self) -> "BaseConnector": - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]] = None, - exc_value: Optional[BaseException] = None, - exc_traceback: Optional[TracebackType] = None, - ) -> None: - await self.close() - - @property - def force_close(self) -> bool: - """Ultimately close connection on releasing if True.""" - return self._force_close - - @property - def limit(self) -> int: - """The total number for simultaneous connections. - - If limit is 0 the connector has no limit. - The default limit size is 100. - """ - return self._limit - - @property - def limit_per_host(self) -> int: - """The limit for simultaneous connections to the same endpoint. - - Endpoints are the same if they are have equal - (host, port, is_ssl) triple. - """ - return self._limit_per_host - - def _cleanup(self) -> None: - """Cleanup unused transports.""" - if self._cleanup_handle: - self._cleanup_handle.cancel() - # _cleanup_handle should be unset, otherwise _release() will not - # recreate it ever! - self._cleanup_handle = None - - now = monotonic() - timeout = self._keepalive_timeout - - if self._conns: - connections = defaultdict(deque) - deadline = now - timeout - for key, conns in self._conns.items(): - alive: Deque[Tuple[ResponseHandler, float]] = deque() - for proto, use_time in conns: - if proto.is_connected() and use_time - deadline >= 0: - alive.append((proto, use_time)) - continue - transport = proto.transport - proto.close() - if not self._cleanup_closed_disabled and key.is_ssl: - self._cleanup_closed_transports.append(transport) - - if alive: - connections[key] = alive - - self._conns = connections - - if self._conns: - self._cleanup_handle = helpers.weakref_handle( - self, - "_cleanup", - timeout, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - def _cleanup_closed(self) -> None: - """Double confirmation for transport close. - - Some broken ssl servers may leave socket open without proper close. - """ - if self._cleanup_closed_handle: - self._cleanup_closed_handle.cancel() - - for transport in self._cleanup_closed_transports: - if transport is not None: - transport.abort() - - self._cleanup_closed_transports = [] - - if not self._cleanup_closed_disabled: - self._cleanup_closed_handle = helpers.weakref_handle( - self, - "_cleanup_closed", - self._cleanup_closed_period, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - def close(self, *, abort_ssl: bool = False) -> Awaitable[None]: - """Close all opened transports. - - :param abort_ssl: If True, SSL connections will be aborted immediately - without performing the shutdown handshake. This provides - faster cleanup at the cost of less graceful disconnection. - """ - if not (waiters := self._close(abort_ssl=abort_ssl)): - # If there are no connections to close, we can return a noop - # awaitable to avoid scheduling a task on the event loop. - return _DeprecationWaiter(noop()) - coro = _wait_for_close(waiters) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to close connections - # immediately to avoid having to schedule the task on the event loop. - task = asyncio.Task(coro, loop=self._loop, eager_start=True) - else: - task = self._loop.create_task(coro) - return _DeprecationWaiter(task) - - def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]: - waiters: List[Awaitable[object]] = [] - - if self._closed: - return waiters - - self._closed = True - - try: - if self._loop.is_closed(): - return waiters - - # cancel cleanup task - if self._cleanup_handle: - self._cleanup_handle.cancel() - - # cancel cleanup close task - if self._cleanup_closed_handle: - self._cleanup_closed_handle.cancel() - - for data in self._conns.values(): - for proto, _ in data: - if ( - abort_ssl - and proto.transport - and proto.transport.get_extra_info("sslcontext") is not None - ): - proto.abort() - else: - proto.close() - if closed := proto.closed: - waiters.append(closed) - - for proto in self._acquired: - if ( - abort_ssl - and proto.transport - and proto.transport.get_extra_info("sslcontext") is not None - ): - proto.abort() - else: - proto.close() - if closed := proto.closed: - waiters.append(closed) - - for transport in self._cleanup_closed_transports: - if transport is not None: - transport.abort() - - return waiters - - finally: - self._conns.clear() - self._acquired.clear() - for keyed_waiters in self._waiters.values(): - for keyed_waiter in keyed_waiters: - keyed_waiter.cancel() - self._waiters.clear() - self._cleanup_handle = None - self._cleanup_closed_transports.clear() - self._cleanup_closed_handle = None - - @property - def closed(self) -> bool: - """Is connector closed. - - A readonly property. - """ - return self._closed - - def _available_connections(self, key: "ConnectionKey") -> int: - """ - Return number of available connections. - - The limit, limit_per_host and the connection key are taken into account. - - If it returns less than 1 means that there are no connections - available. - """ - # check total available connections - # If there are no limits, this will always return 1 - total_remain = 1 - - if self._limit and (total_remain := self._limit - len(self._acquired)) <= 0: - return total_remain - - # check limit per host - if host_remain := self._limit_per_host: - if acquired := self._acquired_per_host.get(key): - host_remain -= len(acquired) - if total_remain > host_remain: - return host_remain - - return total_remain - - def _update_proxy_auth_header_and_build_proxy_req( - self, req: ClientRequest - ) -> ClientRequest: - """Set Proxy-Authorization header for non-SSL proxy requests and builds the proxy request for SSL proxy requests.""" - url = req.proxy - assert url is not None - headers: Dict[str, str] = {} - if req.proxy_headers is not None: - headers = req.proxy_headers # type: ignore[assignment] - headers[hdrs.HOST] = req.headers[hdrs.HOST] - proxy_req = ClientRequest( - hdrs.METH_GET, - url, - headers=headers, - auth=req.proxy_auth, - loop=self._loop, - ssl=req.ssl, - ) - auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None) - if auth is not None: - if not req.is_ssl(): - req.headers[hdrs.PROXY_AUTHORIZATION] = auth - else: - proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth - return proxy_req - - async def connect( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> Connection: - """Get from pool or create new connection.""" - key = req.connection_key - if (conn := await self._get(key, traces)) is not None: - # If we do not have to wait and we can get a connection from the pool - # we can avoid the timeout ceil logic and directly return the connection - if req.proxy: - self._update_proxy_auth_header_and_build_proxy_req(req) - return conn - - async with ceil_timeout(timeout.connect, timeout.ceil_threshold): - if self._available_connections(key) <= 0: - await self._wait_for_available_connection(key, traces) - if (conn := await self._get(key, traces)) is not None: - if req.proxy: - self._update_proxy_auth_header_and_build_proxy_req(req) - return conn - - placeholder = cast( - ResponseHandler, _TransportPlaceholder(self._placeholder_future) - ) - self._acquired.add(placeholder) - if self._limit_per_host: - self._acquired_per_host[key].add(placeholder) - - try: - # Traces are done inside the try block to ensure that the - # that the placeholder is still cleaned up if an exception - # is raised. - if traces: - for trace in traces: - await trace.send_connection_create_start() - proto = await self._create_connection(req, traces, timeout) - if traces: - for trace in traces: - await trace.send_connection_create_end() - except BaseException: - self._release_acquired(key, placeholder) - raise - else: - if self._closed: - proto.close() - raise ClientConnectionError("Connector is closed.") - - # The connection was successfully created, drop the placeholder - # and add the real connection to the acquired set. There should - # be no awaits after the proto is added to the acquired set - # to ensure that the connection is not left in the acquired set - # on cancellation. - self._acquired.remove(placeholder) - self._acquired.add(proto) - if self._limit_per_host: - acquired_per_host = self._acquired_per_host[key] - acquired_per_host.remove(placeholder) - acquired_per_host.add(proto) - return Connection(self, key, proto, self._loop) - - async def _wait_for_available_connection( - self, key: "ConnectionKey", traces: List["Trace"] - ) -> None: - """Wait for an available connection slot.""" - # We loop here because there is a race between - # the connection limit check and the connection - # being acquired. If the connection is acquired - # between the check and the await statement, we - # need to loop again to check if the connection - # slot is still available. - attempts = 0 - while True: - fut: asyncio.Future[None] = self._loop.create_future() - keyed_waiters = self._waiters[key] - keyed_waiters[fut] = None - if attempts: - # If we have waited before, we need to move the waiter - # to the front of the queue as otherwise we might get - # starved and hit the timeout. - keyed_waiters.move_to_end(fut, last=False) - - try: - # Traces happen in the try block to ensure that the - # the waiter is still cleaned up if an exception is raised. - if traces: - for trace in traces: - await trace.send_connection_queued_start() - await fut - if traces: - for trace in traces: - await trace.send_connection_queued_end() - finally: - # pop the waiter from the queue if its still - # there and not already removed by _release_waiter - keyed_waiters.pop(fut, None) - if not self._waiters.get(key, True): - del self._waiters[key] - - if self._available_connections(key) > 0: - break - attempts += 1 - - async def _get( - self, key: "ConnectionKey", traces: List["Trace"] - ) -> Optional[Connection]: - """Get next reusable connection for the key or None. - - The connection will be marked as acquired. - """ - if (conns := self._conns.get(key)) is None: - return None - - t1 = monotonic() - while conns: - proto, t0 = conns.popleft() - # We will we reuse the connection if its connected and - # the keepalive timeout has not been exceeded - if proto.is_connected() and t1 - t0 <= self._keepalive_timeout: - if not conns: - # The very last connection was reclaimed: drop the key - del self._conns[key] - self._acquired.add(proto) - if self._limit_per_host: - self._acquired_per_host[key].add(proto) - if traces: - for trace in traces: - try: - await trace.send_connection_reuseconn() - except BaseException: - self._release_acquired(key, proto) - raise - return Connection(self, key, proto, self._loop) - - # Connection cannot be reused, close it - transport = proto.transport - proto.close() - # only for SSL transports - if not self._cleanup_closed_disabled and key.is_ssl: - self._cleanup_closed_transports.append(transport) - - # No more connections: drop the key - del self._conns[key] - return None - - def _release_waiter(self) -> None: - """ - Iterates over all waiters until one to be released is found. - - The one to be released is not finished and - belongs to a host that has available connections. - """ - if not self._waiters: - return - - # Having the dict keys ordered this avoids to iterate - # at the same order at each call. - queues = list(self._waiters) - random.shuffle(queues) - - for key in queues: - if self._available_connections(key) < 1: - continue - - waiters = self._waiters[key] - while waiters: - waiter, _ = waiters.popitem(last=False) - if not waiter.done(): - waiter.set_result(None) - return - - def _release_acquired(self, key: "ConnectionKey", proto: ResponseHandler) -> None: - """Release acquired connection.""" - if self._closed: - # acquired connection is already released on connector closing - return - - self._acquired.discard(proto) - if self._limit_per_host and (conns := self._acquired_per_host.get(key)): - conns.discard(proto) - if not conns: - del self._acquired_per_host[key] - self._release_waiter() - - def _release( - self, - key: "ConnectionKey", - protocol: ResponseHandler, - *, - should_close: bool = False, - ) -> None: - if self._closed: - # acquired connection is already released on connector closing - return - - self._release_acquired(key, protocol) - - if self._force_close or should_close or protocol.should_close: - transport = protocol.transport - protocol.close() - - if key.is_ssl and not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(transport) - return - - self._conns[key].append((protocol, monotonic())) - - if self._cleanup_handle is None: - self._cleanup_handle = helpers.weakref_handle( - self, - "_cleanup", - self._keepalive_timeout, - self._loop, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - raise NotImplementedError() - - -class _DNSCacheTable: - def __init__(self, ttl: Optional[float] = None) -> None: - self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {} - self._timestamps: Dict[Tuple[str, int], float] = {} - self._ttl = ttl - - def __contains__(self, host: object) -> bool: - return host in self._addrs_rr - - def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None: - self._addrs_rr[key] = (cycle(addrs), len(addrs)) - - if self._ttl is not None: - self._timestamps[key] = monotonic() - - def remove(self, key: Tuple[str, int]) -> None: - self._addrs_rr.pop(key, None) - - if self._ttl is not None: - self._timestamps.pop(key, None) - - def clear(self) -> None: - self._addrs_rr.clear() - self._timestamps.clear() - - def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]: - loop, length = self._addrs_rr[key] - addrs = list(islice(loop, length)) - # Consume one more element to shift internal state of `cycle` - next(loop) - return addrs - - def expired(self, key: Tuple[str, int]) -> bool: - if self._ttl is None: - return False - - return self._timestamps[key] + self._ttl < monotonic() - - -def _make_ssl_context(verified: bool) -> SSLContext: - """Create SSL context. - - This method is not async-friendly and should be called from a thread - because it will load certificates from disk and do other blocking I/O. - """ - if ssl is None: - # No ssl support - return None - if verified: - sslcontext = ssl.create_default_context() - else: - sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - sslcontext.options |= ssl.OP_NO_SSLv2 - sslcontext.options |= ssl.OP_NO_SSLv3 - sslcontext.check_hostname = False - sslcontext.verify_mode = ssl.CERT_NONE - sslcontext.options |= ssl.OP_NO_COMPRESSION - sslcontext.set_default_verify_paths() - sslcontext.set_alpn_protocols(("http/1.1",)) - return sslcontext - - -# The default SSLContext objects are created at import time -# since they do blocking I/O to load certificates from disk, -# and imports should always be done before the event loop starts -# or in a thread. -_SSL_CONTEXT_VERIFIED = _make_ssl_context(True) -_SSL_CONTEXT_UNVERIFIED = _make_ssl_context(False) - - -class TCPConnector(BaseConnector): - """TCP connector. - - verify_ssl - Set to True to check ssl certifications. - fingerprint - Pass the binary sha256 - digest of the expected certificate in DER format to verify - that the certificate the server presents matches. See also - https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning - resolver - Enable DNS lookups and use this - resolver - use_dns_cache - Use memory cache for DNS lookups. - ttl_dns_cache - Max seconds having cached a DNS entry, None forever. - family - socket address family - local_addr - local tuple of (host, port) to bind socket to - - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - enable_cleanup_closed - Enables clean-up closed ssl transports. - Disabled by default. - happy_eyeballs_delay - This is the “Connection Attempt Delay” - as defined in RFC 8305. To disable - the happy eyeballs algorithm, set to None. - interleave - “First Address Family Count” as defined in RFC 8305 - loop - Optional event loop. - socket_factory - A SocketFactoryType function that, if supplied, - will be used to create sockets given an - AddrInfoType. - ssl_shutdown_timeout - DEPRECATED. Will be removed in aiohttp 4.0. - Grace period for SSL shutdown handshake on TLS - connections. Default is 0 seconds (immediate abort). - This parameter allowed for a clean SSL shutdown by - notifying the remote peer of connection closure, - while avoiding excessive delays during connector cleanup. - Note: Only takes effect on Python 3.11+. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"tcp"}) - - def __init__( - self, - *, - verify_ssl: bool = True, - fingerprint: Optional[bytes] = None, - use_dns_cache: bool = True, - ttl_dns_cache: Optional[int] = 10, - family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC, - ssl_context: Optional[SSLContext] = None, - ssl: Union[bool, Fingerprint, SSLContext] = True, - local_addr: Optional[Tuple[str, int]] = None, - resolver: Optional[AbstractResolver] = None, - keepalive_timeout: Union[None, float, object] = sentinel, - force_close: bool = False, - limit: int = 100, - limit_per_host: int = 0, - enable_cleanup_closed: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - timeout_ceil_threshold: float = 5, - happy_eyeballs_delay: Optional[float] = 0.25, - interleave: Optional[int] = None, - socket_factory: Optional[SocketFactoryType] = None, - ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, - ): - super().__init__( - keepalive_timeout=keepalive_timeout, - force_close=force_close, - limit=limit, - limit_per_host=limit_per_host, - enable_cleanup_closed=enable_cleanup_closed, - loop=loop, - timeout_ceil_threshold=timeout_ceil_threshold, - ) - - self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) - - self._resolver: AbstractResolver - if resolver is None: - self._resolver = DefaultResolver(loop=self._loop) - self._resolver_owner = True - else: - self._resolver = resolver - self._resolver_owner = False - - self._use_dns_cache = use_dns_cache - self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache) - self._throttle_dns_futures: Dict[ - Tuple[str, int], Set["asyncio.Future[None]"] - ] = {} - self._family = family - self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr) - self._happy_eyeballs_delay = happy_eyeballs_delay - self._interleave = interleave - self._resolve_host_tasks: Set["asyncio.Task[List[ResolveResult]]"] = set() - self._socket_factory = socket_factory - self._ssl_shutdown_timeout: Optional[float] - # Handle ssl_shutdown_timeout with warning for Python < 3.11 - if ssl_shutdown_timeout is sentinel: - self._ssl_shutdown_timeout = 0 - else: - # Deprecation warning for ssl_shutdown_timeout parameter - warnings.warn( - "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", - DeprecationWarning, - stacklevel=2, - ) - if ( - sys.version_info < (3, 11) - and ssl_shutdown_timeout is not None - and ssl_shutdown_timeout != 0 - ): - warnings.warn( - f"ssl_shutdown_timeout={ssl_shutdown_timeout} is ignored on Python < 3.11; " - "only ssl_shutdown_timeout=0 is supported. The timeout will be ignored.", - RuntimeWarning, - stacklevel=2, - ) - self._ssl_shutdown_timeout = ssl_shutdown_timeout - - def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]: - """Close all ongoing DNS calls.""" - for fut in chain.from_iterable(self._throttle_dns_futures.values()): - fut.cancel() - - waiters = super()._close(abort_ssl=abort_ssl) - - for t in self._resolve_host_tasks: - t.cancel() - waiters.append(t) - - return waiters - - async def close(self, *, abort_ssl: bool = False) -> None: - """ - Close all opened transports. - - :param abort_ssl: If True, SSL connections will be aborted immediately - without performing the shutdown handshake. If False (default), - the behavior is determined by ssl_shutdown_timeout: - - If ssl_shutdown_timeout=0: connections are aborted - - If ssl_shutdown_timeout>0: graceful shutdown is performed - """ - if self._resolver_owner: - await self._resolver.close() - # Use abort_ssl param if explicitly set, otherwise use ssl_shutdown_timeout default - await super().close(abort_ssl=abort_ssl or self._ssl_shutdown_timeout == 0) - - @property - def family(self) -> int: - """Socket family like AF_INET.""" - return self._family - - @property - def use_dns_cache(self) -> bool: - """True if local DNS caching is enabled.""" - return self._use_dns_cache - - def clear_dns_cache( - self, host: Optional[str] = None, port: Optional[int] = None - ) -> None: - """Remove specified host/port or clear all dns local cache.""" - if host is not None and port is not None: - self._cached_hosts.remove((host, port)) - elif host is not None or port is not None: - raise ValueError("either both host and port or none of them are allowed") - else: - self._cached_hosts.clear() - - async def _resolve_host( - self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None - ) -> List[ResolveResult]: - """Resolve host and return list of addresses.""" - if is_ip_address(host): - return [ - { - "hostname": host, - "host": host, - "port": port, - "family": self._family, - "proto": 0, - "flags": 0, - } - ] - - if not self._use_dns_cache: - - if traces: - for trace in traces: - await trace.send_dns_resolvehost_start(host) - - res = await self._resolver.resolve(host, port, family=self._family) - - if traces: - for trace in traces: - await trace.send_dns_resolvehost_end(host) - - return res - - key = (host, port) - if key in self._cached_hosts and not self._cached_hosts.expired(key): - # get result early, before any await (#4014) - result = self._cached_hosts.next_addrs(key) - - if traces: - for trace in traces: - await trace.send_dns_cache_hit(host) - return result - - futures: Set["asyncio.Future[None]"] - # - # If multiple connectors are resolving the same host, we wait - # for the first one to resolve and then use the result for all of them. - # We use a throttle to ensure that we only resolve the host once - # and then use the result for all the waiters. - # - if key in self._throttle_dns_futures: - # get futures early, before any await (#4014) - futures = self._throttle_dns_futures[key] - future: asyncio.Future[None] = self._loop.create_future() - futures.add(future) - if traces: - for trace in traces: - await trace.send_dns_cache_hit(host) - try: - await future - finally: - futures.discard(future) - return self._cached_hosts.next_addrs(key) - - # update dict early, before any await (#4014) - self._throttle_dns_futures[key] = futures = set() - # In this case we need to create a task to ensure that we can shield - # the task from cancellation as cancelling this lookup should not cancel - # the underlying lookup or else the cancel event will get broadcast to - # all the waiters across all connections. - # - coro = self._resolve_host_with_throttle(key, host, port, futures, traces) - loop = asyncio.get_running_loop() - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send immediately - resolved_host_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - resolved_host_task = loop.create_task(coro) - - if not resolved_host_task.done(): - self._resolve_host_tasks.add(resolved_host_task) - resolved_host_task.add_done_callback(self._resolve_host_tasks.discard) - - try: - return await asyncio.shield(resolved_host_task) - except asyncio.CancelledError: - - def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None: - with suppress(Exception, asyncio.CancelledError): - fut.result() - - resolved_host_task.add_done_callback(drop_exception) - raise - - async def _resolve_host_with_throttle( - self, - key: Tuple[str, int], - host: str, - port: int, - futures: Set["asyncio.Future[None]"], - traces: Optional[Sequence["Trace"]], - ) -> List[ResolveResult]: - """Resolve host and set result for all waiters. - - This method must be run in a task and shielded from cancellation - to avoid cancelling the underlying lookup. - """ - try: - if traces: - for trace in traces: - await trace.send_dns_cache_miss(host) - - for trace in traces: - await trace.send_dns_resolvehost_start(host) - - addrs = await self._resolver.resolve(host, port, family=self._family) - if traces: - for trace in traces: - await trace.send_dns_resolvehost_end(host) - - self._cached_hosts.add(key, addrs) - for fut in futures: - set_result(fut, None) - except BaseException as e: - # any DNS exception is set for the waiters to raise the same exception. - # This coro is always run in task that is shielded from cancellation so - # we should never be propagating cancellation here. - for fut in futures: - set_exception(fut, e) - raise - finally: - self._throttle_dns_futures.pop(key) - - return self._cached_hosts.next_addrs(key) - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - """Create connection. - - Has same keyword arguments as BaseEventLoop.create_connection. - """ - if req.proxy: - _, proto = await self._create_proxy_connection(req, traces, timeout) - else: - _, proto = await self._create_direct_connection(req, traces, timeout) - - return proto - - def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]: - """Logic to get the correct SSL context - - 0. if req.ssl is false, return None - - 1. if ssl_context is specified in req, use it - 2. if _ssl_context is specified in self, use it - 3. otherwise: - 1. if verify_ssl is not specified in req, use self.ssl_context - (will generate a default context according to self.verify_ssl) - 2. if verify_ssl is True in req, generate a default SSL context - 3. if verify_ssl is False in req, generate a SSL context that - won't verify - """ - if not req.is_ssl(): - return None - - if ssl is None: # pragma: no cover - raise RuntimeError("SSL is not supported.") - sslcontext = req.ssl - if isinstance(sslcontext, ssl.SSLContext): - return sslcontext - if sslcontext is not True: - # not verified or fingerprinted - return _SSL_CONTEXT_UNVERIFIED - sslcontext = self._ssl - if isinstance(sslcontext, ssl.SSLContext): - return sslcontext - if sslcontext is not True: - # not verified or fingerprinted - return _SSL_CONTEXT_UNVERIFIED - return _SSL_CONTEXT_VERIFIED - - def _get_fingerprint(self, req: ClientRequest) -> Optional["Fingerprint"]: - ret = req.ssl - if isinstance(ret, Fingerprint): - return ret - ret = self._ssl - if isinstance(ret, Fingerprint): - return ret - return None - - async def _wrap_create_connection( - self, - *args: Any, - addr_infos: List[AddrInfoType], - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - **kwargs: Any, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - sock = await aiohappyeyeballs.start_connection( - addr_infos=addr_infos, - local_addr_infos=self._local_addr_infos, - happy_eyeballs_delay=self._happy_eyeballs_delay, - interleave=self._interleave, - loop=self._loop, - socket_factory=self._socket_factory, - ) - # Add ssl_shutdown_timeout for Python 3.11+ when SSL is used - if ( - kwargs.get("ssl") - and self._ssl_shutdown_timeout - and sys.version_info >= (3, 11) - ): - kwargs["ssl_shutdown_timeout"] = self._ssl_shutdown_timeout - return await self._loop.create_connection(*args, **kwargs, sock=sock) - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - - async def _wrap_existing_connection( - self, - *args: Any, - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - **kwargs: Any, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - return await self._loop.create_connection(*args, **kwargs) - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - - def _fail_on_no_start_tls(self, req: "ClientRequest") -> None: - """Raise a :py:exc:`RuntimeError` on missing ``start_tls()``. - - It is necessary for TLS-in-TLS so that it is possible to - send HTTPS queries through HTTPS proxies. - - This doesn't affect regular HTTP requests, though. - """ - if not req.is_ssl(): - return - - proxy_url = req.proxy - assert proxy_url is not None - if proxy_url.scheme != "https": - return - - self._check_loop_for_start_tls() - - def _check_loop_for_start_tls(self) -> None: - try: - self._loop.start_tls - except AttributeError as attr_exc: - raise RuntimeError( - "An HTTPS request is being sent through an HTTPS proxy. " - "This needs support for TLS in TLS but it is not implemented " - "in your runtime for the stdlib asyncio.\n\n" - "Please upgrade to Python 3.11 or higher. For more details, " - "please see:\n" - "* https://bugs.python.org/issue37179\n" - "* https://github.com/python/cpython/pull/28073\n" - "* https://docs.aiohttp.org/en/stable/" - "client_advanced.html#proxy-support\n" - "* https://github.com/aio-libs/aiohttp/discussions/6044\n", - ) from attr_exc - - def _loop_supports_start_tls(self) -> bool: - try: - self._check_loop_for_start_tls() - except RuntimeError: - return False - else: - return True - - def _warn_about_tls_in_tls( - self, - underlying_transport: asyncio.Transport, - req: ClientRequest, - ) -> None: - """Issue a warning if the requested URL has HTTPS scheme.""" - if req.request_info.url.scheme != "https": - return - - # Check if uvloop is being used, which supports TLS in TLS, - # otherwise assume that asyncio's native transport is being used. - if type(underlying_transport).__module__.startswith("uvloop"): - return - - # Support in asyncio was added in Python 3.11 (bpo-44011) - asyncio_supports_tls_in_tls = sys.version_info >= (3, 11) or getattr( - underlying_transport, - "_start_tls_compatible", - False, - ) - - if asyncio_supports_tls_in_tls: - return - - warnings.warn( - "An HTTPS request is being sent through an HTTPS proxy. " - "This support for TLS in TLS is known to be disabled " - "in the stdlib asyncio (Python <3.11). This is why you'll probably see " - "an error in the log below.\n\n" - "It is possible to enable it via monkeypatching. " - "For more details, see:\n" - "* https://bugs.python.org/issue37179\n" - "* https://github.com/python/cpython/pull/28073\n\n" - "You can temporarily patch this as follows:\n" - "* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\n" - "* https://github.com/aio-libs/aiohttp/discussions/6044\n", - RuntimeWarning, - source=self, - # Why `4`? At least 3 of the calls in the stack originate - # from the methods in this class. - stacklevel=3, - ) - - async def _start_tls_connection( - self, - underlying_transport: asyncio.Transport, - req: ClientRequest, - timeout: "ClientTimeout", - client_error: Type[Exception] = ClientConnectorError, - ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: - """Wrap the raw TCP transport with TLS.""" - tls_proto = self._factory() # Create a brand new proto for TLS - sslcontext = self._get_ssl_context(req) - if TYPE_CHECKING: - # _start_tls_connection is unreachable in the current code path - # if sslcontext is None. - assert sslcontext is not None - - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - try: - # ssl_shutdown_timeout is only available in Python 3.11+ - if sys.version_info >= (3, 11) and self._ssl_shutdown_timeout: - tls_transport = await self._loop.start_tls( - underlying_transport, - tls_proto, - sslcontext, - server_hostname=req.server_hostname or req.host, - ssl_handshake_timeout=timeout.total, - ssl_shutdown_timeout=self._ssl_shutdown_timeout, - ) - else: - tls_transport = await self._loop.start_tls( - underlying_transport, - tls_proto, - sslcontext, - server_hostname=req.server_hostname or req.host, - ssl_handshake_timeout=timeout.total, - ) - except BaseException: - # We need to close the underlying transport since - # `start_tls()` probably failed before it had a - # chance to do this: - if self._ssl_shutdown_timeout == 0: - underlying_transport.abort() - else: - underlying_transport.close() - raise - if isinstance(tls_transport, asyncio.Transport): - fingerprint = self._get_fingerprint(req) - if fingerprint: - try: - fingerprint.check(tls_transport) - except ServerFingerprintMismatch: - tls_transport.close() - if not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(tls_transport) - raise - except cert_errors as exc: - raise ClientConnectorCertificateError(req.connection_key, exc) from exc - except ssl_errors as exc: - raise ClientConnectorSSLError(req.connection_key, exc) from exc - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise client_error(req.connection_key, exc) from exc - except TypeError as type_err: - # Example cause looks like this: - # TypeError: transport is not supported by start_tls() - - raise ClientConnectionError( - "Cannot initialize a TLS-in-TLS connection to host " - f"{req.host!s}:{req.port:d} through an underlying connection " - f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} " - f"[{type_err!s}]" - ) from type_err - else: - if tls_transport is None: - msg = "Failed to start TLS (possibly caused by closing transport)" - raise client_error(req.connection_key, OSError(msg)) - tls_proto.connection_made( - tls_transport - ) # Kick the state machine of the new TLS protocol - - return tls_transport, tls_proto - - def _convert_hosts_to_addr_infos( - self, hosts: List[ResolveResult] - ) -> List[AddrInfoType]: - """Converts the list of hosts to a list of addr_infos. - - The list of hosts is the result of a DNS lookup. The list of - addr_infos is the result of a call to `socket.getaddrinfo()`. - """ - addr_infos: List[AddrInfoType] = [] - for hinfo in hosts: - host = hinfo["host"] - is_ipv6 = ":" in host - family = socket.AF_INET6 if is_ipv6 else socket.AF_INET - if self._family and self._family != family: - continue - addr = (host, hinfo["port"], 0, 0) if is_ipv6 else (host, hinfo["port"]) - addr_infos.append( - (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr) - ) - return addr_infos - - async def _create_direct_connection( - self, - req: ClientRequest, - traces: List["Trace"], - timeout: "ClientTimeout", - *, - client_error: Type[Exception] = ClientConnectorError, - ) -> Tuple[asyncio.Transport, ResponseHandler]: - sslcontext = self._get_ssl_context(req) - fingerprint = self._get_fingerprint(req) - - host = req.url.raw_host - assert host is not None - # Replace multiple trailing dots with a single one. - # A trailing dot is only present for fully-qualified domain names. - # See https://github.com/aio-libs/aiohttp/pull/7364. - if host.endswith(".."): - host = host.rstrip(".") + "." - port = req.port - assert port is not None - try: - # Cancelling this lookup should not cancel the underlying lookup - # or else the cancel event will get broadcast to all the waiters - # across all connections. - hosts = await self._resolve_host(host, port, traces=traces) - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - # in case of proxy it is not ClientProxyConnectionError - # it is problem of resolving proxy ip itself - raise ClientConnectorDNSError(req.connection_key, exc) from exc - - last_exc: Optional[Exception] = None - addr_infos = self._convert_hosts_to_addr_infos(hosts) - while addr_infos: - # Strip trailing dots, certificates contain FQDN without dots. - # See https://github.com/aio-libs/aiohttp/issues/3636 - server_hostname = ( - (req.server_hostname or host).rstrip(".") if sslcontext else None - ) - - try: - transp, proto = await self._wrap_create_connection( - self._factory, - timeout=timeout, - ssl=sslcontext, - addr_infos=addr_infos, - server_hostname=server_hostname, - req=req, - client_error=client_error, - ) - except (ClientConnectorError, asyncio.TimeoutError) as exc: - last_exc = exc - aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave) - continue - - if req.is_ssl() and fingerprint: - try: - fingerprint.check(transp) - except ServerFingerprintMismatch as exc: - transp.close() - if not self._cleanup_closed_disabled: - self._cleanup_closed_transports.append(transp) - last_exc = exc - # Remove the bad peer from the list of addr_infos - sock: socket.socket = transp.get_extra_info("socket") - bad_peer = sock.getpeername() - aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer) - continue - - return transp, proto - else: - assert last_exc is not None - raise last_exc - - async def _create_proxy_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: - self._fail_on_no_start_tls(req) - runtime_has_start_tls = self._loop_supports_start_tls() - proxy_req = self._update_proxy_auth_header_and_build_proxy_req(req) - - # create connection to proxy server - transport, proto = await self._create_direct_connection( - proxy_req, [], timeout, client_error=ClientProxyConnectionError - ) - - if req.is_ssl(): - if runtime_has_start_tls: - self._warn_about_tls_in_tls(transport, req) - - # For HTTPS requests over HTTP proxy - # we must notify proxy to tunnel connection - # so we send CONNECT command: - # CONNECT www.python.org:443 HTTP/1.1 - # Host: www.python.org - # - # next we must do TLS handshake and so on - # to do this we must wrap raw socket into secure one - # asyncio handles this perfectly - proxy_req.method = hdrs.METH_CONNECT - proxy_req.url = req.url - key = req.connection_key._replace( - proxy=None, proxy_auth=None, proxy_headers_hash=None - ) - conn = _ConnectTunnelConnection(self, key, proto, self._loop) - proxy_resp = await proxy_req.send(conn) - try: - protocol = conn._protocol - assert protocol is not None - - # read_until_eof=True will ensure the connection isn't closed - # once the response is received and processed allowing - # START_TLS to work on the connection below. - protocol.set_response_params( - read_until_eof=runtime_has_start_tls, - timeout_ceil_threshold=self._timeout_ceil_threshold, - ) - resp = await proxy_resp.start(conn) - except BaseException: - proxy_resp.close() - conn.close() - raise - else: - conn._protocol = None - try: - if resp.status != 200: - message = resp.reason - if message is None: - message = HTTPStatus(resp.status).phrase - raise ClientHttpProxyError( - proxy_resp.request_info, - resp.history, - status=resp.status, - message=message, - headers=resp.headers, - ) - if not runtime_has_start_tls: - rawsock = transport.get_extra_info("socket", default=None) - if rawsock is None: - raise RuntimeError( - "Transport does not expose socket instance" - ) - # Duplicate the socket, so now we can close proxy transport - rawsock = rawsock.dup() - except BaseException: - # It shouldn't be closed in `finally` because it's fed to - # `loop.start_tls()` and the docs say not to touch it after - # passing there. - transport.close() - raise - finally: - if not runtime_has_start_tls: - transport.close() - - if not runtime_has_start_tls: - # HTTP proxy with support for upgrade to HTTPS - sslcontext = self._get_ssl_context(req) - return await self._wrap_existing_connection( - self._factory, - timeout=timeout, - ssl=sslcontext, - sock=rawsock, - server_hostname=req.host, - req=req, - ) - - return await self._start_tls_connection( - # Access the old transport for the last time before it's - # closed and forgotten forever: - transport, - req=req, - timeout=timeout, - ) - finally: - proxy_resp.close() - - return transport, proto - - -class UnixConnector(BaseConnector): - """Unix socket connector. - - path - Unix socket path. - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - loop - Optional event loop. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"unix"}) - - def __init__( - self, - path: str, - force_close: bool = False, - keepalive_timeout: Union[object, float, None] = sentinel, - limit: int = 100, - limit_per_host: int = 0, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__( - force_close=force_close, - keepalive_timeout=keepalive_timeout, - limit=limit, - limit_per_host=limit_per_host, - loop=loop, - ) - self._path = path - - @property - def path(self) -> str: - """Path to unix socket.""" - return self._path - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - _, proto = await self._loop.create_unix_connection( - self._factory, self._path - ) - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc - - return proto - - -class NamedPipeConnector(BaseConnector): - """Named pipe connector. - - Only supported by the proactor event loop. - See also: https://docs.python.org/3/library/asyncio-eventloop.html - - path - Windows named pipe path. - keepalive_timeout - (optional) Keep-alive timeout. - force_close - Set to True to force close and do reconnect - after each request (and between redirects). - limit - The total number of simultaneous connections. - limit_per_host - Number of simultaneous connections to one host. - loop - Optional event loop. - """ - - allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"npipe"}) - - def __init__( - self, - path: str, - force_close: bool = False, - keepalive_timeout: Union[object, float, None] = sentinel, - limit: int = 100, - limit_per_host: int = 0, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__( - force_close=force_close, - keepalive_timeout=keepalive_timeout, - limit=limit, - limit_per_host=limit_per_host, - loop=loop, - ) - if not isinstance( - self._loop, - asyncio.ProactorEventLoop, # type: ignore[attr-defined] - ): - raise RuntimeError( - "Named Pipes only available in proactor loop under windows" - ) - self._path = path - - @property - def path(self) -> str: - """Path to the named pipe.""" - return self._path - - async def _create_connection( - self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" - ) -> ResponseHandler: - try: - async with ceil_timeout( - timeout.sock_connect, ceil_threshold=timeout.ceil_threshold - ): - _, proto = await self._loop.create_pipe_connection( # type: ignore[attr-defined] - self._factory, self._path - ) - # the drain is required so that the connection_made is called - # and transport is set otherwise it is not set before the - # `assert conn.transport is not None` - # in client.py's _request method - await asyncio.sleep(0) - # other option is to manually set transport like - # `proto.transport = trans` - except OSError as exc: - if exc.errno is None and isinstance(exc, asyncio.TimeoutError): - raise - raise ClientConnectorError(req.connection_key, exc) from exc - - return cast(ResponseHandler, proto) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/cookiejar.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/cookiejar.py deleted file mode 100644 index 193648d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/cookiejar.py +++ /dev/null @@ -1,522 +0,0 @@ -import asyncio -import calendar -import contextlib -import datetime -import heapq -import itertools -import os # noqa -import pathlib -import pickle -import re -import time -import warnings -from collections import defaultdict -from collections.abc import Mapping -from http.cookies import BaseCookie, Morsel, SimpleCookie -from typing import ( - DefaultDict, - Dict, - Iterable, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) - -from yarl import URL - -from ._cookie_helpers import preserve_morsel_with_coded_value -from .abc import AbstractCookieJar, ClearCookiePredicate -from .helpers import is_ip_address -from .typedefs import LooseCookies, PathLike, StrOrURL - -__all__ = ("CookieJar", "DummyCookieJar") - - -CookieItem = Union[str, "Morsel[str]"] - -# We cache these string methods here as their use is in performance critical code. -_FORMAT_PATH = "{}/{}".format -_FORMAT_DOMAIN_REVERSED = "{1}.{0}".format - -# The minimum number of scheduled cookie expirations before we start cleaning up -# the expiration heap. This is a performance optimization to avoid cleaning up the -# heap too often when there are only a few scheduled expirations. -_MIN_SCHEDULED_COOKIE_EXPIRATION = 100 -_SIMPLE_COOKIE = SimpleCookie() - - -class CookieJar(AbstractCookieJar): - """Implements cookie storage adhering to RFC 6265.""" - - DATE_TOKENS_RE = re.compile( - r"[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]*" - r"(?P[\x00-\x08\x0A-\x1F\d:a-zA-Z\x7F-\xFF]+)" - ) - - DATE_HMS_TIME_RE = re.compile(r"(\d{1,2}):(\d{1,2}):(\d{1,2})") - - DATE_DAY_OF_MONTH_RE = re.compile(r"(\d{1,2})") - - DATE_MONTH_RE = re.compile( - "(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)", - re.I, - ) - - DATE_YEAR_RE = re.compile(r"(\d{2,4})") - - # calendar.timegm() fails for timestamps after datetime.datetime.max - # Minus one as a loss of precision occurs when timestamp() is called. - MAX_TIME = ( - int(datetime.datetime.max.replace(tzinfo=datetime.timezone.utc).timestamp()) - 1 - ) - try: - calendar.timegm(time.gmtime(MAX_TIME)) - except (OSError, ValueError): - # Hit the maximum representable time on Windows - # https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-localtime32-localtime64 - # Throws ValueError on PyPy 3.9, OSError elsewhere - MAX_TIME = calendar.timegm((3000, 12, 31, 23, 59, 59, -1, -1, -1)) - except OverflowError: - # #4515: datetime.max may not be representable on 32-bit platforms - MAX_TIME = 2**31 - 1 - # Avoid minuses in the future, 3x faster - SUB_MAX_TIME = MAX_TIME - 1 - - def __init__( - self, - *, - unsafe: bool = False, - quote_cookie: bool = True, - treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - super().__init__(loop=loop) - self._cookies: DefaultDict[Tuple[str, str], SimpleCookie] = defaultdict( - SimpleCookie - ) - self._morsel_cache: DefaultDict[Tuple[str, str], Dict[str, Morsel[str]]] = ( - defaultdict(dict) - ) - self._host_only_cookies: Set[Tuple[str, str]] = set() - self._unsafe = unsafe - self._quote_cookie = quote_cookie - if treat_as_secure_origin is None: - treat_as_secure_origin = [] - elif isinstance(treat_as_secure_origin, URL): - treat_as_secure_origin = [treat_as_secure_origin.origin()] - elif isinstance(treat_as_secure_origin, str): - treat_as_secure_origin = [URL(treat_as_secure_origin).origin()] - else: - treat_as_secure_origin = [ - URL(url).origin() if isinstance(url, str) else url.origin() - for url in treat_as_secure_origin - ] - self._treat_as_secure_origin = treat_as_secure_origin - self._expire_heap: List[Tuple[float, Tuple[str, str, str]]] = [] - self._expirations: Dict[Tuple[str, str, str], float] = {} - - @property - def quote_cookie(self) -> bool: - return self._quote_cookie - - def save(self, file_path: PathLike) -> None: - file_path = pathlib.Path(file_path) - with file_path.open(mode="wb") as f: - pickle.dump(self._cookies, f, pickle.HIGHEST_PROTOCOL) - - def load(self, file_path: PathLike) -> None: - file_path = pathlib.Path(file_path) - with file_path.open(mode="rb") as f: - self._cookies = pickle.load(f) - - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - if predicate is None: - self._expire_heap.clear() - self._cookies.clear() - self._morsel_cache.clear() - self._host_only_cookies.clear() - self._expirations.clear() - return - - now = time.time() - to_del = [ - key - for (domain, path), cookie in self._cookies.items() - for name, morsel in cookie.items() - if ( - (key := (domain, path, name)) in self._expirations - and self._expirations[key] <= now - ) - or predicate(morsel) - ] - if to_del: - self._delete_cookies(to_del) - - def clear_domain(self, domain: str) -> None: - self.clear(lambda x: self._is_domain_match(domain, x["domain"])) - - def __iter__(self) -> "Iterator[Morsel[str]]": - self._do_expiration() - for val in self._cookies.values(): - yield from val.values() - - def __len__(self) -> int: - """Return number of cookies. - - This function does not iterate self to avoid unnecessary expiration - checks. - """ - return sum(len(cookie.values()) for cookie in self._cookies.values()) - - def _do_expiration(self) -> None: - """Remove expired cookies.""" - if not (expire_heap_len := len(self._expire_heap)): - return - - # If the expiration heap grows larger than the number expirations - # times two, we clean it up to avoid keeping expired entries in - # the heap and consuming memory. We guard this with a minimum - # threshold to avoid cleaning up the heap too often when there are - # only a few scheduled expirations. - if ( - expire_heap_len > _MIN_SCHEDULED_COOKIE_EXPIRATION - and expire_heap_len > len(self._expirations) * 2 - ): - # Remove any expired entries from the expiration heap - # that do not match the expiration time in the expirations - # as it means the cookie has been re-added to the heap - # with a different expiration time. - self._expire_heap = [ - entry - for entry in self._expire_heap - if self._expirations.get(entry[1]) == entry[0] - ] - heapq.heapify(self._expire_heap) - - now = time.time() - to_del: List[Tuple[str, str, str]] = [] - # Find any expired cookies and add them to the to-delete list - while self._expire_heap: - when, cookie_key = self._expire_heap[0] - if when > now: - break - heapq.heappop(self._expire_heap) - # Check if the cookie hasn't been re-added to the heap - # with a different expiration time as it will be removed - # later when it reaches the top of the heap and its - # expiration time is met. - if self._expirations.get(cookie_key) == when: - to_del.append(cookie_key) - - if to_del: - self._delete_cookies(to_del) - - def _delete_cookies(self, to_del: List[Tuple[str, str, str]]) -> None: - for domain, path, name in to_del: - self._host_only_cookies.discard((domain, name)) - self._cookies[(domain, path)].pop(name, None) - self._morsel_cache[(domain, path)].pop(name, None) - self._expirations.pop((domain, path, name), None) - - def _expire_cookie(self, when: float, domain: str, path: str, name: str) -> None: - cookie_key = (domain, path, name) - if self._expirations.get(cookie_key) == when: - # Avoid adding duplicates to the heap - return - heapq.heappush(self._expire_heap, (when, cookie_key)) - self._expirations[cookie_key] = when - - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - """Update cookies.""" - hostname = response_url.raw_host - - if not self._unsafe and is_ip_address(hostname): - # Don't accept cookies from IPs - return - - if isinstance(cookies, Mapping): - cookies = cookies.items() - - for name, cookie in cookies: - if not isinstance(cookie, Morsel): - tmp = SimpleCookie() - tmp[name] = cookie # type: ignore[assignment] - cookie = tmp[name] - - domain = cookie["domain"] - - # ignore domains with trailing dots - if domain and domain[-1] == ".": - domain = "" - del cookie["domain"] - - if not domain and hostname is not None: - # Set the cookie's domain to the response hostname - # and set its host-only-flag - self._host_only_cookies.add((hostname, name)) - domain = cookie["domain"] = hostname - - if domain and domain[0] == ".": - # Remove leading dot - domain = domain[1:] - cookie["domain"] = domain - - if hostname and not self._is_domain_match(domain, hostname): - # Setting cookies for different domains is not allowed - continue - - path = cookie["path"] - if not path or path[0] != "/": - # Set the cookie's path to the response path - path = response_url.path - if not path.startswith("/"): - path = "/" - else: - # Cut everything from the last slash to the end - path = "/" + path[1 : path.rfind("/")] - cookie["path"] = path - path = path.rstrip("/") - - if max_age := cookie["max-age"]: - try: - delta_seconds = int(max_age) - max_age_expiration = min(time.time() + delta_seconds, self.MAX_TIME) - self._expire_cookie(max_age_expiration, domain, path, name) - except ValueError: - cookie["max-age"] = "" - - elif expires := cookie["expires"]: - if expire_time := self._parse_date(expires): - self._expire_cookie(expire_time, domain, path, name) - else: - cookie["expires"] = "" - - key = (domain, path) - if self._cookies[key].get(name) != cookie: - # Don't blow away the cache if the same - # cookie gets set again - self._cookies[key][name] = cookie - self._morsel_cache[key].pop(name, None) - - self._do_expiration() - - def filter_cookies(self, request_url: URL = URL()) -> "BaseCookie[str]": - """Returns this jar's cookies filtered by their attributes.""" - # We always use BaseCookie now since all - # cookies set on on filtered are fully constructed - # Morsels, not just names and values. - filtered: BaseCookie[str] = BaseCookie() - if not self._cookies: - # Skip do_expiration() if there are no cookies. - return filtered - self._do_expiration() - if not self._cookies: - # Skip rest of function if no non-expired cookies. - return filtered - if type(request_url) is not URL: - warnings.warn( - "filter_cookies expects yarl.URL instances only," - f"and will stop working in 4.x, got {type(request_url)}", - DeprecationWarning, - stacklevel=2, - ) - request_url = URL(request_url) - hostname = request_url.raw_host or "" - - is_not_secure = request_url.scheme not in ("https", "wss") - if is_not_secure and self._treat_as_secure_origin: - request_origin = URL() - with contextlib.suppress(ValueError): - request_origin = request_url.origin() - is_not_secure = request_origin not in self._treat_as_secure_origin - - # Send shared cookie - key = ("", "") - for c in self._cookies[key].values(): - # Check cache first - if c.key in self._morsel_cache[key]: - filtered[c.key] = self._morsel_cache[key][c.key] - continue - - # Build and cache the morsel - mrsl_val = self._build_morsel(c) - self._morsel_cache[key][c.key] = mrsl_val - filtered[c.key] = mrsl_val - - if is_ip_address(hostname): - if not self._unsafe: - return filtered - domains: Iterable[str] = (hostname,) - else: - # Get all the subdomains that might match a cookie (e.g. "foo.bar.com", "bar.com", "com") - domains = itertools.accumulate( - reversed(hostname.split(".")), _FORMAT_DOMAIN_REVERSED - ) - - # Get all the path prefixes that might match a cookie (e.g. "", "/foo", "/foo/bar") - paths = itertools.accumulate(request_url.path.split("/"), _FORMAT_PATH) - # Create every combination of (domain, path) pairs. - pairs = itertools.product(domains, paths) - - path_len = len(request_url.path) - # Point 2: https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 - for p in pairs: - if p not in self._cookies: - continue - for name, cookie in self._cookies[p].items(): - domain = cookie["domain"] - - if (domain, name) in self._host_only_cookies and domain != hostname: - continue - - # Skip edge case when the cookie has a trailing slash but request doesn't. - if len(cookie["path"]) > path_len: - continue - - if is_not_secure and cookie["secure"]: - continue - - # We already built the Morsel so reuse it here - if name in self._morsel_cache[p]: - filtered[name] = self._morsel_cache[p][name] - continue - - # Build and cache the morsel - mrsl_val = self._build_morsel(cookie) - self._morsel_cache[p][name] = mrsl_val - filtered[name] = mrsl_val - - return filtered - - def _build_morsel(self, cookie: Morsel[str]) -> Morsel[str]: - """Build a morsel for sending, respecting quote_cookie setting.""" - if self._quote_cookie and cookie.coded_value and cookie.coded_value[0] == '"': - return preserve_morsel_with_coded_value(cookie) - morsel: Morsel[str] = Morsel() - if self._quote_cookie: - value, coded_value = _SIMPLE_COOKIE.value_encode(cookie.value) - else: - coded_value = value = cookie.value - # We use __setstate__ instead of the public set() API because it allows us to - # bypass validation and set already validated state. This is more stable than - # setting protected attributes directly and unlikely to change since it would - # break pickling. - morsel.__setstate__({"key": cookie.key, "value": value, "coded_value": coded_value}) # type: ignore[attr-defined] - return morsel - - @staticmethod - def _is_domain_match(domain: str, hostname: str) -> bool: - """Implements domain matching adhering to RFC 6265.""" - if hostname == domain: - return True - - if not hostname.endswith(domain): - return False - - non_matching = hostname[: -len(domain)] - - if not non_matching.endswith("."): - return False - - return not is_ip_address(hostname) - - @classmethod - def _parse_date(cls, date_str: str) -> Optional[int]: - """Implements date string parsing adhering to RFC 6265.""" - if not date_str: - return None - - found_time = False - found_day = False - found_month = False - found_year = False - - hour = minute = second = 0 - day = 0 - month = 0 - year = 0 - - for token_match in cls.DATE_TOKENS_RE.finditer(date_str): - - token = token_match.group("token") - - if not found_time: - time_match = cls.DATE_HMS_TIME_RE.match(token) - if time_match: - found_time = True - hour, minute, second = (int(s) for s in time_match.groups()) - continue - - if not found_day: - day_match = cls.DATE_DAY_OF_MONTH_RE.match(token) - if day_match: - found_day = True - day = int(day_match.group()) - continue - - if not found_month: - month_match = cls.DATE_MONTH_RE.match(token) - if month_match: - found_month = True - assert month_match.lastindex is not None - month = month_match.lastindex - continue - - if not found_year: - year_match = cls.DATE_YEAR_RE.match(token) - if year_match: - found_year = True - year = int(year_match.group()) - - if 70 <= year <= 99: - year += 1900 - elif 0 <= year <= 69: - year += 2000 - - if False in (found_day, found_month, found_year, found_time): - return None - - if not 1 <= day <= 31: - return None - - if year < 1601 or hour > 23 or minute > 59 or second > 59: - return None - - return calendar.timegm((year, month, day, hour, minute, second, -1, -1, -1)) - - -class DummyCookieJar(AbstractCookieJar): - """Implements a dummy cookie storage. - - It can be used with the ClientSession when no cookie processing is needed. - - """ - - def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - super().__init__(loop=loop) - - def __iter__(self) -> "Iterator[Morsel[str]]": - while False: - yield None - - def __len__(self) -> int: - return 0 - - @property - def quote_cookie(self) -> bool: - return True - - def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: - pass - - def clear_domain(self, domain: str) -> None: - pass - - def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: - pass - - def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": - return SimpleCookie() diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/formdata.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/formdata.py deleted file mode 100644 index a5a4f60..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/formdata.py +++ /dev/null @@ -1,179 +0,0 @@ -import io -import warnings -from typing import Any, Iterable, List, Optional -from urllib.parse import urlencode - -from multidict import MultiDict, MultiDictProxy - -from . import hdrs, multipart, payload -from .helpers import guess_filename -from .payload import Payload - -__all__ = ("FormData",) - - -class FormData: - """Helper class for form body generation. - - Supports multipart/form-data and application/x-www-form-urlencoded. - """ - - def __init__( - self, - fields: Iterable[Any] = (), - quote_fields: bool = True, - charset: Optional[str] = None, - *, - default_to_multipart: bool = False, - ) -> None: - self._writer = multipart.MultipartWriter("form-data") - self._fields: List[Any] = [] - self._is_multipart = default_to_multipart - self._quote_fields = quote_fields - self._charset = charset - - if isinstance(fields, dict): - fields = list(fields.items()) - elif not isinstance(fields, (list, tuple)): - fields = (fields,) - self.add_fields(*fields) - - @property - def is_multipart(self) -> bool: - return self._is_multipart - - def add_field( - self, - name: str, - value: Any, - *, - content_type: Optional[str] = None, - filename: Optional[str] = None, - content_transfer_encoding: Optional[str] = None, - ) -> None: - - if isinstance(value, io.IOBase): - self._is_multipart = True - elif isinstance(value, (bytes, bytearray, memoryview)): - msg = ( - "In v4, passing bytes will no longer create a file field. " - "Please explicitly use the filename parameter or pass a BytesIO object." - ) - if filename is None and content_transfer_encoding is None: - warnings.warn(msg, DeprecationWarning) - filename = name - - type_options: MultiDict[str] = MultiDict({"name": name}) - if filename is not None and not isinstance(filename, str): - raise TypeError("filename must be an instance of str. Got: %s" % filename) - if filename is None and isinstance(value, io.IOBase): - filename = guess_filename(value, name) - if filename is not None: - type_options["filename"] = filename - self._is_multipart = True - - headers = {} - if content_type is not None: - if not isinstance(content_type, str): - raise TypeError( - "content_type must be an instance of str. Got: %s" % content_type - ) - headers[hdrs.CONTENT_TYPE] = content_type - self._is_multipart = True - if content_transfer_encoding is not None: - if not isinstance(content_transfer_encoding, str): - raise TypeError( - "content_transfer_encoding must be an instance" - " of str. Got: %s" % content_transfer_encoding - ) - msg = ( - "content_transfer_encoding is deprecated. " - "To maintain compatibility with v4 please pass a BytesPayload." - ) - warnings.warn(msg, DeprecationWarning) - self._is_multipart = True - - self._fields.append((type_options, headers, value)) - - def add_fields(self, *fields: Any) -> None: - to_add = list(fields) - - while to_add: - rec = to_add.pop(0) - - if isinstance(rec, io.IOBase): - k = guess_filename(rec, "unknown") - self.add_field(k, rec) # type: ignore[arg-type] - - elif isinstance(rec, (MultiDictProxy, MultiDict)): - to_add.extend(rec.items()) - - elif isinstance(rec, (list, tuple)) and len(rec) == 2: - k, fp = rec - self.add_field(k, fp) - - else: - raise TypeError( - "Only io.IOBase, multidict and (name, file) " - "pairs allowed, use .add_field() for passing " - "more complex parameters, got {!r}".format(rec) - ) - - def _gen_form_urlencoded(self) -> payload.BytesPayload: - # form data (x-www-form-urlencoded) - data = [] - for type_options, _, value in self._fields: - data.append((type_options["name"], value)) - - charset = self._charset if self._charset is not None else "utf-8" - - if charset == "utf-8": - content_type = "application/x-www-form-urlencoded" - else: - content_type = "application/x-www-form-urlencoded; charset=%s" % charset - - return payload.BytesPayload( - urlencode(data, doseq=True, encoding=charset).encode(), - content_type=content_type, - ) - - def _gen_form_data(self) -> multipart.MultipartWriter: - """Encode a list of fields using the multipart/form-data MIME format""" - for dispparams, headers, value in self._fields: - try: - if hdrs.CONTENT_TYPE in headers: - part = payload.get_payload( - value, - content_type=headers[hdrs.CONTENT_TYPE], - headers=headers, - encoding=self._charset, - ) - else: - part = payload.get_payload( - value, headers=headers, encoding=self._charset - ) - except Exception as exc: - raise TypeError( - "Can not serialize value type: %r\n " - "headers: %r\n value: %r" % (type(value), headers, value) - ) from exc - - if dispparams: - part.set_content_disposition( - "form-data", quote_fields=self._quote_fields, **dispparams - ) - # FIXME cgi.FieldStorage doesn't likes body parts with - # Content-Length which were sent via chunked transfer encoding - assert part.headers is not None - part.headers.popall(hdrs.CONTENT_LENGTH, None) - - self._writer.append_payload(part) - - self._fields.clear() - return self._writer - - def __call__(self) -> Payload: - if self._is_multipart: - return self._gen_form_data() - else: - return self._gen_form_urlencoded() diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/hdrs.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/hdrs.py deleted file mode 100644 index c8d6b35..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/hdrs.py +++ /dev/null @@ -1,121 +0,0 @@ -"""HTTP Headers constants.""" - -# After changing the file content call ./tools/gen.py -# to regenerate the headers parser -import itertools -from typing import Final, Set - -from multidict import istr - -METH_ANY: Final[str] = "*" -METH_CONNECT: Final[str] = "CONNECT" -METH_HEAD: Final[str] = "HEAD" -METH_GET: Final[str] = "GET" -METH_DELETE: Final[str] = "DELETE" -METH_OPTIONS: Final[str] = "OPTIONS" -METH_PATCH: Final[str] = "PATCH" -METH_POST: Final[str] = "POST" -METH_PUT: Final[str] = "PUT" -METH_TRACE: Final[str] = "TRACE" - -METH_ALL: Final[Set[str]] = { - METH_CONNECT, - METH_HEAD, - METH_GET, - METH_DELETE, - METH_OPTIONS, - METH_PATCH, - METH_POST, - METH_PUT, - METH_TRACE, -} - -ACCEPT: Final[istr] = istr("Accept") -ACCEPT_CHARSET: Final[istr] = istr("Accept-Charset") -ACCEPT_ENCODING: Final[istr] = istr("Accept-Encoding") -ACCEPT_LANGUAGE: Final[istr] = istr("Accept-Language") -ACCEPT_RANGES: Final[istr] = istr("Accept-Ranges") -ACCESS_CONTROL_MAX_AGE: Final[istr] = istr("Access-Control-Max-Age") -ACCESS_CONTROL_ALLOW_CREDENTIALS: Final[istr] = istr("Access-Control-Allow-Credentials") -ACCESS_CONTROL_ALLOW_HEADERS: Final[istr] = istr("Access-Control-Allow-Headers") -ACCESS_CONTROL_ALLOW_METHODS: Final[istr] = istr("Access-Control-Allow-Methods") -ACCESS_CONTROL_ALLOW_ORIGIN: Final[istr] = istr("Access-Control-Allow-Origin") -ACCESS_CONTROL_EXPOSE_HEADERS: Final[istr] = istr("Access-Control-Expose-Headers") -ACCESS_CONTROL_REQUEST_HEADERS: Final[istr] = istr("Access-Control-Request-Headers") -ACCESS_CONTROL_REQUEST_METHOD: Final[istr] = istr("Access-Control-Request-Method") -AGE: Final[istr] = istr("Age") -ALLOW: Final[istr] = istr("Allow") -AUTHORIZATION: Final[istr] = istr("Authorization") -CACHE_CONTROL: Final[istr] = istr("Cache-Control") -CONNECTION: Final[istr] = istr("Connection") -CONTENT_DISPOSITION: Final[istr] = istr("Content-Disposition") -CONTENT_ENCODING: Final[istr] = istr("Content-Encoding") -CONTENT_LANGUAGE: Final[istr] = istr("Content-Language") -CONTENT_LENGTH: Final[istr] = istr("Content-Length") -CONTENT_LOCATION: Final[istr] = istr("Content-Location") -CONTENT_MD5: Final[istr] = istr("Content-MD5") -CONTENT_RANGE: Final[istr] = istr("Content-Range") -CONTENT_TRANSFER_ENCODING: Final[istr] = istr("Content-Transfer-Encoding") -CONTENT_TYPE: Final[istr] = istr("Content-Type") -COOKIE: Final[istr] = istr("Cookie") -DATE: Final[istr] = istr("Date") -DESTINATION: Final[istr] = istr("Destination") -DIGEST: Final[istr] = istr("Digest") -ETAG: Final[istr] = istr("Etag") -EXPECT: Final[istr] = istr("Expect") -EXPIRES: Final[istr] = istr("Expires") -FORWARDED: Final[istr] = istr("Forwarded") -FROM: Final[istr] = istr("From") -HOST: Final[istr] = istr("Host") -IF_MATCH: Final[istr] = istr("If-Match") -IF_MODIFIED_SINCE: Final[istr] = istr("If-Modified-Since") -IF_NONE_MATCH: Final[istr] = istr("If-None-Match") -IF_RANGE: Final[istr] = istr("If-Range") -IF_UNMODIFIED_SINCE: Final[istr] = istr("If-Unmodified-Since") -KEEP_ALIVE: Final[istr] = istr("Keep-Alive") -LAST_EVENT_ID: Final[istr] = istr("Last-Event-ID") -LAST_MODIFIED: Final[istr] = istr("Last-Modified") -LINK: Final[istr] = istr("Link") -LOCATION: Final[istr] = istr("Location") -MAX_FORWARDS: Final[istr] = istr("Max-Forwards") -ORIGIN: Final[istr] = istr("Origin") -PRAGMA: Final[istr] = istr("Pragma") -PROXY_AUTHENTICATE: Final[istr] = istr("Proxy-Authenticate") -PROXY_AUTHORIZATION: Final[istr] = istr("Proxy-Authorization") -RANGE: Final[istr] = istr("Range") -REFERER: Final[istr] = istr("Referer") -RETRY_AFTER: Final[istr] = istr("Retry-After") -SEC_WEBSOCKET_ACCEPT: Final[istr] = istr("Sec-WebSocket-Accept") -SEC_WEBSOCKET_VERSION: Final[istr] = istr("Sec-WebSocket-Version") -SEC_WEBSOCKET_PROTOCOL: Final[istr] = istr("Sec-WebSocket-Protocol") -SEC_WEBSOCKET_EXTENSIONS: Final[istr] = istr("Sec-WebSocket-Extensions") -SEC_WEBSOCKET_KEY: Final[istr] = istr("Sec-WebSocket-Key") -SEC_WEBSOCKET_KEY1: Final[istr] = istr("Sec-WebSocket-Key1") -SERVER: Final[istr] = istr("Server") -SET_COOKIE: Final[istr] = istr("Set-Cookie") -TE: Final[istr] = istr("TE") -TRAILER: Final[istr] = istr("Trailer") -TRANSFER_ENCODING: Final[istr] = istr("Transfer-Encoding") -UPGRADE: Final[istr] = istr("Upgrade") -URI: Final[istr] = istr("URI") -USER_AGENT: Final[istr] = istr("User-Agent") -VARY: Final[istr] = istr("Vary") -VIA: Final[istr] = istr("Via") -WANT_DIGEST: Final[istr] = istr("Want-Digest") -WARNING: Final[istr] = istr("Warning") -WWW_AUTHENTICATE: Final[istr] = istr("WWW-Authenticate") -X_FORWARDED_FOR: Final[istr] = istr("X-Forwarded-For") -X_FORWARDED_HOST: Final[istr] = istr("X-Forwarded-Host") -X_FORWARDED_PROTO: Final[istr] = istr("X-Forwarded-Proto") - -# These are the upper/lower case variants of the headers/methods -# Example: {'hOst', 'host', 'HoST', 'HOSt', 'hOsT', 'HosT', 'hoSt', ...} -METH_HEAD_ALL: Final = frozenset( - map("".join, itertools.product(*zip(METH_HEAD.upper(), METH_HEAD.lower()))) -) -METH_CONNECT_ALL: Final = frozenset( - map("".join, itertools.product(*zip(METH_CONNECT.upper(), METH_CONNECT.lower()))) -) -HOST_ALL: Final = frozenset( - map("".join, itertools.product(*zip(HOST.upper(), HOST.lower()))) -) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/helpers.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/helpers.py deleted file mode 100644 index dfab987..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/helpers.py +++ /dev/null @@ -1,986 +0,0 @@ -"""Various helper functions""" - -import asyncio -import base64 -import binascii -import contextlib -import datetime -import enum -import functools -import inspect -import netrc -import os -import platform -import re -import sys -import time -import weakref -from collections import namedtuple -from contextlib import suppress -from email.message import EmailMessage -from email.parser import HeaderParser -from email.policy import HTTP -from email.utils import parsedate -from math import ceil -from pathlib import Path -from types import MappingProxyType, TracebackType -from typing import ( - Any, - Callable, - ContextManager, - Dict, - Generator, - Generic, - Iterable, - Iterator, - List, - Mapping, - Optional, - Protocol, - Tuple, - Type, - TypeVar, - Union, - get_args, - overload, -) -from urllib.parse import quote -from urllib.request import getproxies, proxy_bypass - -import attr -from multidict import MultiDict, MultiDictProxy, MultiMapping -from propcache.api import under_cached_property as reify -from yarl import URL - -from . import hdrs -from .log import client_logger - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - -__all__ = ("BasicAuth", "ChainMapProxy", "ETag", "reify") - -IS_MACOS = platform.system() == "Darwin" -IS_WINDOWS = platform.system() == "Windows" - -PY_310 = sys.version_info >= (3, 10) -PY_311 = sys.version_info >= (3, 11) - - -_T = TypeVar("_T") -_S = TypeVar("_S") - -_SENTINEL = enum.Enum("_SENTINEL", "sentinel") -sentinel = _SENTINEL.sentinel - -NO_EXTENSIONS = bool(os.environ.get("AIOHTTP_NO_EXTENSIONS")) - -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 -EMPTY_BODY_STATUS_CODES = frozenset((204, 304, *range(100, 200))) -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 -# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.2 -EMPTY_BODY_METHODS = hdrs.METH_HEAD_ALL - -DEBUG = sys.flags.dev_mode or ( - not sys.flags.ignore_environment and bool(os.environ.get("PYTHONASYNCIODEBUG")) -) - - -CHAR = {chr(i) for i in range(0, 128)} -CTL = {chr(i) for i in range(0, 32)} | { - chr(127), -} -SEPARATORS = { - "(", - ")", - "<", - ">", - "@", - ",", - ";", - ":", - "\\", - '"', - "/", - "[", - "]", - "?", - "=", - "{", - "}", - " ", - chr(9), -} -TOKEN = CHAR ^ CTL ^ SEPARATORS - - -class noop: - def __await__(self) -> Generator[None, None, None]: - yield - - -class BasicAuth(namedtuple("BasicAuth", ["login", "password", "encoding"])): - """Http basic authentication helper.""" - - def __new__( - cls, login: str, password: str = "", encoding: str = "latin1" - ) -> "BasicAuth": - if login is None: - raise ValueError("None is not allowed as login value") - - if password is None: - raise ValueError("None is not allowed as password value") - - if ":" in login: - raise ValueError('A ":" is not allowed in login (RFC 1945#section-11.1)') - - return super().__new__(cls, login, password, encoding) - - @classmethod - def decode(cls, auth_header: str, encoding: str = "latin1") -> "BasicAuth": - """Create a BasicAuth object from an Authorization HTTP header.""" - try: - auth_type, encoded_credentials = auth_header.split(" ", 1) - except ValueError: - raise ValueError("Could not parse authorization header.") - - if auth_type.lower() != "basic": - raise ValueError("Unknown authorization method %s" % auth_type) - - try: - decoded = base64.b64decode( - encoded_credentials.encode("ascii"), validate=True - ).decode(encoding) - except binascii.Error: - raise ValueError("Invalid base64 encoding.") - - try: - # RFC 2617 HTTP Authentication - # https://www.ietf.org/rfc/rfc2617.txt - # the colon must be present, but the username and password may be - # otherwise blank. - username, password = decoded.split(":", 1) - except ValueError: - raise ValueError("Invalid credentials.") - - return cls(username, password, encoding=encoding) - - @classmethod - def from_url(cls, url: URL, *, encoding: str = "latin1") -> Optional["BasicAuth"]: - """Create BasicAuth from url.""" - if not isinstance(url, URL): - raise TypeError("url should be yarl.URL instance") - # Check raw_user and raw_password first as yarl is likely - # to already have these values parsed from the netloc in the cache. - if url.raw_user is None and url.raw_password is None: - return None - return cls(url.user or "", url.password or "", encoding=encoding) - - def encode(self) -> str: - """Encode credentials.""" - creds = (f"{self.login}:{self.password}").encode(self.encoding) - return "Basic %s" % base64.b64encode(creds).decode(self.encoding) - - -def strip_auth_from_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: - """Remove user and password from URL if present and return BasicAuth object.""" - # Check raw_user and raw_password first as yarl is likely - # to already have these values parsed from the netloc in the cache. - if url.raw_user is None and url.raw_password is None: - return url, None - return url.with_user(None), BasicAuth(url.user or "", url.password or "") - - -def netrc_from_env() -> Optional[netrc.netrc]: - """Load netrc from file. - - Attempt to load it from the path specified by the env-var - NETRC or in the default location in the user's home directory. - - Returns None if it couldn't be found or fails to parse. - """ - netrc_env = os.environ.get("NETRC") - - if netrc_env is not None: - netrc_path = Path(netrc_env) - else: - try: - home_dir = Path.home() - except RuntimeError as e: # pragma: no cover - # if pathlib can't resolve home, it may raise a RuntimeError - client_logger.debug( - "Could not resolve home directory when " - "trying to look for .netrc file: %s", - e, - ) - return None - - netrc_path = home_dir / ("_netrc" if IS_WINDOWS else ".netrc") - - try: - return netrc.netrc(str(netrc_path)) - except netrc.NetrcParseError as e: - client_logger.warning("Could not parse .netrc file: %s", e) - except OSError as e: - netrc_exists = False - with contextlib.suppress(OSError): - netrc_exists = netrc_path.is_file() - # we couldn't read the file (doesn't exist, permissions, etc.) - if netrc_env or netrc_exists: - # only warn if the environment wanted us to load it, - # or it appears like the default file does actually exist - client_logger.warning("Could not read .netrc file: %s", e) - - return None - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ProxyInfo: - proxy: URL - proxy_auth: Optional[BasicAuth] - - -def basicauth_from_netrc(netrc_obj: Optional[netrc.netrc], host: str) -> BasicAuth: - """ - Return :py:class:`~aiohttp.BasicAuth` credentials for ``host`` from ``netrc_obj``. - - :raises LookupError: if ``netrc_obj`` is :py:data:`None` or if no - entry is found for the ``host``. - """ - if netrc_obj is None: - raise LookupError("No .netrc file found") - auth_from_netrc = netrc_obj.authenticators(host) - - if auth_from_netrc is None: - raise LookupError(f"No entry for {host!s} found in the `.netrc` file.") - login, account, password = auth_from_netrc - - # TODO(PY311): username = login or account - # Up to python 3.10, account could be None if not specified, - # and login will be empty string if not specified. From 3.11, - # login and account will be empty string if not specified. - username = login if (login or account is None) else account - - # TODO(PY311): Remove this, as password will be empty string - # if not specified - if password is None: - password = "" - - return BasicAuth(username, password) - - -def proxies_from_env() -> Dict[str, ProxyInfo]: - proxy_urls = { - k: URL(v) - for k, v in getproxies().items() - if k in ("http", "https", "ws", "wss") - } - netrc_obj = netrc_from_env() - stripped = {k: strip_auth_from_url(v) for k, v in proxy_urls.items()} - ret = {} - for proto, val in stripped.items(): - proxy, auth = val - if proxy.scheme in ("https", "wss"): - client_logger.warning( - "%s proxies %s are not supported, ignoring", proxy.scheme.upper(), proxy - ) - continue - if netrc_obj and auth is None: - if proxy.host is not None: - try: - auth = basicauth_from_netrc(netrc_obj, proxy.host) - except LookupError: - auth = None - ret[proto] = ProxyInfo(proxy, auth) - return ret - - -def get_env_proxy_for_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: - """Get a permitted proxy for the given URL from the env.""" - if url.host is not None and proxy_bypass(url.host): - raise LookupError(f"Proxying is disallowed for `{url.host!r}`") - - proxies_in_env = proxies_from_env() - try: - proxy_info = proxies_in_env[url.scheme] - except KeyError: - raise LookupError(f"No proxies found for `{url!s}` in the env") - else: - return proxy_info.proxy, proxy_info.proxy_auth - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class MimeType: - type: str - subtype: str - suffix: str - parameters: "MultiDictProxy[str]" - - -@functools.lru_cache(maxsize=56) -def parse_mimetype(mimetype: str) -> MimeType: - """Parses a MIME type into its components. - - mimetype is a MIME type string. - - Returns a MimeType object. - - Example: - - >>> parse_mimetype('text/html; charset=utf-8') - MimeType(type='text', subtype='html', suffix='', - parameters={'charset': 'utf-8'}) - - """ - if not mimetype: - return MimeType( - type="", subtype="", suffix="", parameters=MultiDictProxy(MultiDict()) - ) - - parts = mimetype.split(";") - params: MultiDict[str] = MultiDict() - for item in parts[1:]: - if not item: - continue - key, _, value = item.partition("=") - params.add(key.lower().strip(), value.strip(' "')) - - fulltype = parts[0].strip().lower() - if fulltype == "*": - fulltype = "*/*" - - mtype, _, stype = fulltype.partition("/") - stype, _, suffix = stype.partition("+") - - return MimeType( - type=mtype, subtype=stype, suffix=suffix, parameters=MultiDictProxy(params) - ) - - -class EnsureOctetStream(EmailMessage): - def __init__(self) -> None: - super().__init__() - # https://www.rfc-editor.org/rfc/rfc9110#section-8.3-5 - self.set_default_type("application/octet-stream") - - def get_content_type(self) -> str: - """Re-implementation from Message - - Returns application/octet-stream in place of plain/text when - value is wrong. - - The way this class is used guarantees that content-type will - be present so simplify the checks wrt to the base implementation. - """ - value = self.get("content-type", "").lower() - - # Based on the implementation of _splitparam in the standard library - ctype, _, _ = value.partition(";") - ctype = ctype.strip() - if ctype.count("/") != 1: - return self.get_default_type() - return ctype - - -@functools.lru_cache(maxsize=56) -def parse_content_type(raw: str) -> Tuple[str, MappingProxyType[str, str]]: - """Parse Content-Type header. - - Returns a tuple of the parsed content type and a - MappingProxyType of parameters. The default returned value - is `application/octet-stream` - """ - msg = HeaderParser(EnsureOctetStream, policy=HTTP).parsestr(f"Content-Type: {raw}") - content_type = msg.get_content_type() - params = msg.get_params(()) - content_dict = dict(params[1:]) # First element is content type again - return content_type, MappingProxyType(content_dict) - - -def guess_filename(obj: Any, default: Optional[str] = None) -> Optional[str]: - name = getattr(obj, "name", None) - if name and isinstance(name, str) and name[0] != "<" and name[-1] != ">": - return Path(name).name - return default - - -not_qtext_re = re.compile(r"[^\041\043-\133\135-\176]") -QCONTENT = {chr(i) for i in range(0x20, 0x7F)} | {"\t"} - - -def quoted_string(content: str) -> str: - """Return 7-bit content as quoted-string. - - Format content into a quoted-string as defined in RFC5322 for - Internet Message Format. Notice that this is not the 8-bit HTTP - format, but the 7-bit email format. Content must be in usascii or - a ValueError is raised. - """ - if not (QCONTENT > set(content)): - raise ValueError(f"bad content for quoted-string {content!r}") - return not_qtext_re.sub(lambda x: "\\" + x.group(0), content) - - -def content_disposition_header( - disptype: str, quote_fields: bool = True, _charset: str = "utf-8", **params: str -) -> str: - """Sets ``Content-Disposition`` header for MIME. - - This is the MIME payload Content-Disposition header from RFC 2183 - and RFC 7579 section 4.2, not the HTTP Content-Disposition from - RFC 6266. - - disptype is a disposition type: inline, attachment, form-data. - Should be valid extension token (see RFC 2183) - - quote_fields performs value quoting to 7-bit MIME headers - according to RFC 7578. Set to quote_fields to False if recipient - can take 8-bit file names and field values. - - _charset specifies the charset to use when quote_fields is True. - - params is a dict with disposition params. - """ - if not disptype or not (TOKEN > set(disptype)): - raise ValueError(f"bad content disposition type {disptype!r}") - - value = disptype - if params: - lparams = [] - for key, val in params.items(): - if not key or not (TOKEN > set(key)): - raise ValueError(f"bad content disposition parameter {key!r}={val!r}") - if quote_fields: - if key.lower() == "filename": - qval = quote(val, "", encoding=_charset) - lparams.append((key, '"%s"' % qval)) - else: - try: - qval = quoted_string(val) - except ValueError: - qval = "".join( - (_charset, "''", quote(val, "", encoding=_charset)) - ) - lparams.append((key + "*", qval)) - else: - lparams.append((key, '"%s"' % qval)) - else: - qval = val.replace("\\", "\\\\").replace('"', '\\"') - lparams.append((key, '"%s"' % qval)) - sparams = "; ".join("=".join(pair) for pair in lparams) - value = "; ".join((value, sparams)) - return value - - -def is_ip_address(host: Optional[str]) -> bool: - """Check if host looks like an IP Address. - - This check is only meant as a heuristic to ensure that - a host is not a domain name. - """ - if not host: - return False - # For a host to be an ipv4 address, it must be all numeric. - # The host must contain a colon to be an IPv6 address. - return ":" in host or host.replace(".", "").isdigit() - - -_cached_current_datetime: Optional[int] = None -_cached_formatted_datetime = "" - - -def rfc822_formatted_time() -> str: - global _cached_current_datetime - global _cached_formatted_datetime - - now = int(time.time()) - if now != _cached_current_datetime: - # Weekday and month names for HTTP date/time formatting; - # always English! - # Tuples are constants stored in codeobject! - _weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") - _monthname = ( - "", # Dummy so we can use 1-based month numbers - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ) - - year, month, day, hh, mm, ss, wd, *tail = time.gmtime(now) - _cached_formatted_datetime = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( - _weekdayname[wd], - day, - _monthname[month], - year, - hh, - mm, - ss, - ) - _cached_current_datetime = now - return _cached_formatted_datetime - - -def _weakref_handle(info: "Tuple[weakref.ref[object], str]") -> None: - ref, name = info - ob = ref() - if ob is not None: - with suppress(Exception): - getattr(ob, name)() - - -def weakref_handle( - ob: object, - name: str, - timeout: float, - loop: asyncio.AbstractEventLoop, - timeout_ceil_threshold: float = 5, -) -> Optional[asyncio.TimerHandle]: - if timeout is not None and timeout > 0: - when = loop.time() + timeout - if timeout >= timeout_ceil_threshold: - when = ceil(when) - - return loop.call_at(when, _weakref_handle, (weakref.ref(ob), name)) - return None - - -def call_later( - cb: Callable[[], Any], - timeout: float, - loop: asyncio.AbstractEventLoop, - timeout_ceil_threshold: float = 5, -) -> Optional[asyncio.TimerHandle]: - if timeout is None or timeout <= 0: - return None - now = loop.time() - when = calculate_timeout_when(now, timeout, timeout_ceil_threshold) - return loop.call_at(when, cb) - - -def calculate_timeout_when( - loop_time: float, - timeout: float, - timeout_ceiling_threshold: float, -) -> float: - """Calculate when to execute a timeout.""" - when = loop_time + timeout - if timeout > timeout_ceiling_threshold: - return ceil(when) - return when - - -class TimeoutHandle: - """Timeout handle""" - - __slots__ = ("_timeout", "_loop", "_ceil_threshold", "_callbacks") - - def __init__( - self, - loop: asyncio.AbstractEventLoop, - timeout: Optional[float], - ceil_threshold: float = 5, - ) -> None: - self._timeout = timeout - self._loop = loop - self._ceil_threshold = ceil_threshold - self._callbacks: List[ - Tuple[Callable[..., None], Tuple[Any, ...], Dict[str, Any]] - ] = [] - - def register( - self, callback: Callable[..., None], *args: Any, **kwargs: Any - ) -> None: - self._callbacks.append((callback, args, kwargs)) - - def close(self) -> None: - self._callbacks.clear() - - def start(self) -> Optional[asyncio.TimerHandle]: - timeout = self._timeout - if timeout is not None and timeout > 0: - when = self._loop.time() + timeout - if timeout >= self._ceil_threshold: - when = ceil(when) - return self._loop.call_at(when, self.__call__) - else: - return None - - def timer(self) -> "BaseTimerContext": - if self._timeout is not None and self._timeout > 0: - timer = TimerContext(self._loop) - self.register(timer.timeout) - return timer - else: - return TimerNoop() - - def __call__(self) -> None: - for cb, args, kwargs in self._callbacks: - with suppress(Exception): - cb(*args, **kwargs) - - self._callbacks.clear() - - -class BaseTimerContext(ContextManager["BaseTimerContext"]): - - __slots__ = () - - def assert_timeout(self) -> None: - """Raise TimeoutError if timeout has been exceeded.""" - - -class TimerNoop(BaseTimerContext): - - __slots__ = () - - def __enter__(self) -> BaseTimerContext: - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - return - - -class TimerContext(BaseTimerContext): - """Low resolution timeout context manager""" - - __slots__ = ("_loop", "_tasks", "_cancelled", "_cancelling") - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop = loop - self._tasks: List[asyncio.Task[Any]] = [] - self._cancelled = False - self._cancelling = 0 - - def assert_timeout(self) -> None: - """Raise TimeoutError if timer has already been cancelled.""" - if self._cancelled: - raise asyncio.TimeoutError from None - - def __enter__(self) -> BaseTimerContext: - task = asyncio.current_task(loop=self._loop) - if task is None: - raise RuntimeError("Timeout context manager should be used inside a task") - - if sys.version_info >= (3, 11): - # Remember if the task was already cancelling - # so when we __exit__ we can decide if we should - # raise asyncio.TimeoutError or let the cancellation propagate - self._cancelling = task.cancelling() - - if self._cancelled: - raise asyncio.TimeoutError from None - - self._tasks.append(task) - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> Optional[bool]: - enter_task: Optional[asyncio.Task[Any]] = None - if self._tasks: - enter_task = self._tasks.pop() - - if exc_type is asyncio.CancelledError and self._cancelled: - assert enter_task is not None - # The timeout was hit, and the task was cancelled - # so we need to uncancel the last task that entered the context manager - # since the cancellation should not leak out of the context manager - if sys.version_info >= (3, 11): - # If the task was already cancelling don't raise - # asyncio.TimeoutError and instead return None - # to allow the cancellation to propagate - if enter_task.uncancel() > self._cancelling: - return None - raise asyncio.TimeoutError from exc_val - return None - - def timeout(self) -> None: - if not self._cancelled: - for task in set(self._tasks): - task.cancel() - - self._cancelled = True - - -def ceil_timeout( - delay: Optional[float], ceil_threshold: float = 5 -) -> async_timeout.Timeout: - if delay is None or delay <= 0: - return async_timeout.timeout(None) - - loop = asyncio.get_running_loop() - now = loop.time() - when = now + delay - if delay > ceil_threshold: - when = ceil(when) - return async_timeout.timeout_at(when) - - -class HeadersMixin: - """Mixin for handling headers.""" - - ATTRS = frozenset(["_content_type", "_content_dict", "_stored_content_type"]) - - _headers: MultiMapping[str] - _content_type: Optional[str] = None - _content_dict: Optional[Dict[str, str]] = None - _stored_content_type: Union[str, None, _SENTINEL] = sentinel - - def _parse_content_type(self, raw: Optional[str]) -> None: - self._stored_content_type = raw - if raw is None: - # default value according to RFC 2616 - self._content_type = "application/octet-stream" - self._content_dict = {} - else: - content_type, content_mapping_proxy = parse_content_type(raw) - self._content_type = content_type - # _content_dict needs to be mutable so we can update it - self._content_dict = content_mapping_proxy.copy() - - @property - def content_type(self) -> str: - """The value of content part for Content-Type HTTP header.""" - raw = self._headers.get(hdrs.CONTENT_TYPE) - if self._stored_content_type != raw: - self._parse_content_type(raw) - assert self._content_type is not None - return self._content_type - - @property - def charset(self) -> Optional[str]: - """The value of charset part for Content-Type HTTP header.""" - raw = self._headers.get(hdrs.CONTENT_TYPE) - if self._stored_content_type != raw: - self._parse_content_type(raw) - assert self._content_dict is not None - return self._content_dict.get("charset") - - @property - def content_length(self) -> Optional[int]: - """The value of Content-Length HTTP header.""" - content_length = self._headers.get(hdrs.CONTENT_LENGTH) - return None if content_length is None else int(content_length) - - -def set_result(fut: "asyncio.Future[_T]", result: _T) -> None: - if not fut.done(): - fut.set_result(result) - - -_EXC_SENTINEL = BaseException() - - -class ErrorableProtocol(Protocol): - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = ..., - ) -> None: ... # pragma: no cover - - -def set_exception( - fut: "asyncio.Future[_T] | ErrorableProtocol", - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, -) -> None: - """Set future exception. - - If the future is marked as complete, this function is a no-op. - - :param exc_cause: An exception that is a direct cause of ``exc``. - Only set if provided. - """ - if asyncio.isfuture(fut) and fut.done(): - return - - exc_is_sentinel = exc_cause is _EXC_SENTINEL - exc_causes_itself = exc is exc_cause - if not exc_is_sentinel and not exc_causes_itself: - exc.__cause__ = exc_cause - - fut.set_exception(exc) - - -@functools.total_ordering -class AppKey(Generic[_T]): - """Keys for static typing support in Application.""" - - __slots__ = ("_name", "_t", "__orig_class__") - - # This may be set by Python when instantiating with a generic type. We need to - # support this, in order to support types that are not concrete classes, - # like Iterable, which can't be passed as the second parameter to __init__. - __orig_class__: Type[object] - - def __init__(self, name: str, t: Optional[Type[_T]] = None): - # Prefix with module name to help deduplicate key names. - frame = inspect.currentframe() - while frame: - if frame.f_code.co_name == "": - module: str = frame.f_globals["__name__"] - break - frame = frame.f_back - - self._name = module + "." + name - self._t = t - - def __lt__(self, other: object) -> bool: - if isinstance(other, AppKey): - return self._name < other._name - return True # Order AppKey above other types. - - def __repr__(self) -> str: - t = self._t - if t is None: - with suppress(AttributeError): - # Set to type arg. - t = get_args(self.__orig_class__)[0] - - if t is None: - t_repr = "<>" - elif isinstance(t, type): - if t.__module__ == "builtins": - t_repr = t.__qualname__ - else: - t_repr = f"{t.__module__}.{t.__qualname__}" - else: - t_repr = repr(t) - return f"" - - -class ChainMapProxy(Mapping[Union[str, AppKey[Any]], Any]): - __slots__ = ("_maps",) - - def __init__(self, maps: Iterable[Mapping[Union[str, AppKey[Any]], Any]]) -> None: - self._maps = tuple(maps) - - def __init_subclass__(cls) -> None: - raise TypeError( - "Inheritance class {} from ChainMapProxy " - "is forbidden".format(cls.__name__) - ) - - @overload # type: ignore[override] - def __getitem__(self, key: AppKey[_T]) -> _T: ... - - @overload - def __getitem__(self, key: str) -> Any: ... - - def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: - for mapping in self._maps: - try: - return mapping[key] - except KeyError: - pass - raise KeyError(key) - - @overload # type: ignore[override] - def get(self, key: AppKey[_T], default: _S) -> Union[_T, _S]: ... - - @overload - def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... - - @overload - def get(self, key: str, default: Any = ...) -> Any: ... - - def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: - try: - return self[key] - except KeyError: - return default - - def __len__(self) -> int: - # reuses stored hash values if possible - return len(set().union(*self._maps)) - - def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: - d: Dict[Union[str, AppKey[Any]], Any] = {} - for mapping in reversed(self._maps): - # reuses stored hash values if possible - d.update(mapping) - return iter(d) - - def __contains__(self, key: object) -> bool: - return any(key in m for m in self._maps) - - def __bool__(self) -> bool: - return any(self._maps) - - def __repr__(self) -> str: - content = ", ".join(map(repr, self._maps)) - return f"ChainMapProxy({content})" - - -# https://tools.ietf.org/html/rfc7232#section-2.3 -_ETAGC = r"[!\x23-\x7E\x80-\xff]+" -_ETAGC_RE = re.compile(_ETAGC) -_QUOTED_ETAG = rf'(W/)?"({_ETAGC})"' -QUOTED_ETAG_RE = re.compile(_QUOTED_ETAG) -LIST_QUOTED_ETAG_RE = re.compile(rf"({_QUOTED_ETAG})(?:\s*,\s*|$)|(.)") - -ETAG_ANY = "*" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class ETag: - value: str - is_weak: bool = False - - -def validate_etag_value(value: str) -> None: - if value != ETAG_ANY and not _ETAGC_RE.fullmatch(value): - raise ValueError( - f"Value {value!r} is not a valid etag. Maybe it contains '\"'?" - ) - - -def parse_http_date(date_str: Optional[str]) -> Optional[datetime.datetime]: - """Process a date string, return a datetime object""" - if date_str is not None: - timetuple = parsedate(date_str) - if timetuple is not None: - with suppress(ValueError): - return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc) - return None - - -@functools.lru_cache -def must_be_empty_body(method: str, code: int) -> bool: - """Check if a request must return an empty body.""" - return ( - code in EMPTY_BODY_STATUS_CODES - or method in EMPTY_BODY_METHODS - or (200 <= code < 300 and method in hdrs.METH_CONNECT_ALL) - ) - - -def should_remove_content_length(method: str, code: int) -> bool: - """Check if a Content-Length header should be removed. - - This should always be a subset of must_be_empty_body - """ - # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-8 - # https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4.5-4 - return code in EMPTY_BODY_STATUS_CODES or ( - 200 <= code < 300 and method in hdrs.METH_CONNECT_ALL - ) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/http.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/http.py deleted file mode 100644 index a1feae2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/http.py +++ /dev/null @@ -1,72 +0,0 @@ -import sys -from http import HTTPStatus -from typing import Mapping, Tuple - -from . import __version__ -from .http_exceptions import HttpProcessingError as HttpProcessingError -from .http_parser import ( - HeadersParser as HeadersParser, - HttpParser as HttpParser, - HttpRequestParser as HttpRequestParser, - HttpResponseParser as HttpResponseParser, - RawRequestMessage as RawRequestMessage, - RawResponseMessage as RawResponseMessage, -) -from .http_websocket import ( - WS_CLOSED_MESSAGE as WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE as WS_CLOSING_MESSAGE, - WS_KEY as WS_KEY, - WebSocketError as WebSocketError, - WebSocketReader as WebSocketReader, - WebSocketWriter as WebSocketWriter, - WSCloseCode as WSCloseCode, - WSMessage as WSMessage, - WSMsgType as WSMsgType, - ws_ext_gen as ws_ext_gen, - ws_ext_parse as ws_ext_parse, -) -from .http_writer import ( - HttpVersion as HttpVersion, - HttpVersion10 as HttpVersion10, - HttpVersion11 as HttpVersion11, - StreamWriter as StreamWriter, -) - -__all__ = ( - "HttpProcessingError", - "RESPONSES", - "SERVER_SOFTWARE", - # .http_writer - "StreamWriter", - "HttpVersion", - "HttpVersion10", - "HttpVersion11", - # .http_parser - "HeadersParser", - "HttpParser", - "HttpRequestParser", - "HttpResponseParser", - "RawRequestMessage", - "RawResponseMessage", - # .http_websocket - "WS_CLOSED_MESSAGE", - "WS_CLOSING_MESSAGE", - "WS_KEY", - "WebSocketReader", - "WebSocketWriter", - "ws_ext_gen", - "ws_ext_parse", - "WSMessage", - "WebSocketError", - "WSMsgType", - "WSCloseCode", -) - - -SERVER_SOFTWARE: str = "Python/{0[0]}.{0[1]} aiohttp/{1}".format( - sys.version_info, __version__ -) - -RESPONSES: Mapping[int, Tuple[str, str]] = { - v: (v.phrase, v.description) for v in HTTPStatus.__members__.values() -} diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_exceptions.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/http_exceptions.py deleted file mode 100644 index 0b5867c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_exceptions.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Low-level http related exceptions.""" - -from textwrap import indent -from typing import Optional, Union - -from .typedefs import _CIMultiDict - -__all__ = ("HttpProcessingError",) - - -class HttpProcessingError(Exception): - """HTTP error. - - Shortcut for raising HTTP errors with custom code, message and headers. - - code: HTTP Error code. - message: (optional) Error message. - headers: (optional) Headers to be sent in response, a list of pairs - """ - - code = 0 - message = "" - headers = None - - def __init__( - self, - *, - code: Optional[int] = None, - message: str = "", - headers: Optional[_CIMultiDict] = None, - ) -> None: - if code is not None: - self.code = code - self.headers = headers - self.message = message - - def __str__(self) -> str: - msg = indent(self.message, " ") - return f"{self.code}, message:\n{msg}" - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}: {self.code}, message={self.message!r}>" - - -class BadHttpMessage(HttpProcessingError): - - code = 400 - message = "Bad Request" - - def __init__(self, message: str, *, headers: Optional[_CIMultiDict] = None) -> None: - super().__init__(message=message, headers=headers) - self.args = (message,) - - -class HttpBadRequest(BadHttpMessage): - - code = 400 - message = "Bad Request" - - -class PayloadEncodingError(BadHttpMessage): - """Base class for payload errors""" - - -class ContentEncodingError(PayloadEncodingError): - """Content encoding error.""" - - -class TransferEncodingError(PayloadEncodingError): - """transfer encoding error.""" - - -class ContentLengthError(PayloadEncodingError): - """Not enough data to satisfy content length header.""" - - -class DecompressSizeError(PayloadEncodingError): - """Decompressed size exceeds the configured limit.""" - - -class LineTooLong(BadHttpMessage): - def __init__( - self, line: str, limit: str = "Unknown", actual_size: str = "Unknown" - ) -> None: - super().__init__( - f"Got more than {limit} bytes ({actual_size}) when reading {line}." - ) - self.args = (line, limit, actual_size) - - -class InvalidHeader(BadHttpMessage): - def __init__(self, hdr: Union[bytes, str]) -> None: - hdr_s = hdr.decode(errors="backslashreplace") if isinstance(hdr, bytes) else hdr - super().__init__(f"Invalid HTTP header: {hdr!r}") - self.hdr = hdr_s - self.args = (hdr,) - - -class BadStatusLine(BadHttpMessage): - def __init__(self, line: str = "", error: Optional[str] = None) -> None: - if not isinstance(line, str): - line = repr(line) - super().__init__(error or f"Bad status line {line!r}") - self.args = (line,) - self.line = line - - -class BadHttpMethod(BadStatusLine): - """Invalid HTTP method in status line.""" - - def __init__(self, line: str = "", error: Optional[str] = None) -> None: - super().__init__(line, error or f"Bad HTTP method in status line {line!r}") - - -class InvalidURLError(BadHttpMessage): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_parser.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/http_parser.py deleted file mode 100644 index 393e76a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_parser.py +++ /dev/null @@ -1,1086 +0,0 @@ -import abc -import asyncio -import re -import string -from contextlib import suppress -from enum import IntEnum -from typing import ( - Any, - ClassVar, - Final, - Generic, - List, - Literal, - NamedTuple, - Optional, - Pattern, - Set, - Tuple, - Type, - TypeVar, - Union, -) - -from multidict import CIMultiDict, CIMultiDictProxy, istr -from yarl import URL - -from . import hdrs -from .base_protocol import BaseProtocol -from .compression_utils import ( - DEFAULT_MAX_DECOMPRESS_SIZE, - HAS_BROTLI, - HAS_ZSTD, - BrotliDecompressor, - ZLibDecompressor, - ZSTDDecompressor, -) -from .helpers import ( - _EXC_SENTINEL, - DEBUG, - EMPTY_BODY_METHODS, - EMPTY_BODY_STATUS_CODES, - NO_EXTENSIONS, - BaseTimerContext, - set_exception, -) -from .http_exceptions import ( - BadHttpMessage, - BadHttpMethod, - BadStatusLine, - ContentEncodingError, - ContentLengthError, - DecompressSizeError, - InvalidHeader, - InvalidURLError, - LineTooLong, - TransferEncodingError, -) -from .http_writer import HttpVersion, HttpVersion10 -from .streams import EMPTY_PAYLOAD, StreamReader -from .typedefs import RawHeaders - -__all__ = ( - "HeadersParser", - "HttpParser", - "HttpRequestParser", - "HttpResponseParser", - "RawRequestMessage", - "RawResponseMessage", -) - -_SEP = Literal[b"\r\n", b"\n"] - -ASCIISET: Final[Set[str]] = set(string.printable) - -# See https://www.rfc-editor.org/rfc/rfc9110.html#name-overview -# and https://www.rfc-editor.org/rfc/rfc9110.html#name-tokens -# -# method = token -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / -# "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA -# token = 1*tchar -_TCHAR_SPECIALS: Final[str] = re.escape("!#$%&'*+-.^_`|~") -TOKENRE: Final[Pattern[str]] = re.compile(f"[0-9A-Za-z{_TCHAR_SPECIALS}]+") -VERSRE: Final[Pattern[str]] = re.compile(r"HTTP/(\d)\.(\d)", re.ASCII) -DIGITS: Final[Pattern[str]] = re.compile(r"\d+", re.ASCII) -HEXDIGITS: Final[Pattern[bytes]] = re.compile(rb"[0-9a-fA-F]+") - - -class RawRequestMessage(NamedTuple): - method: str - path: str - version: HttpVersion - headers: "CIMultiDictProxy[str]" - raw_headers: RawHeaders - should_close: bool - compression: Optional[str] - upgrade: bool - chunked: bool - url: URL - - -class RawResponseMessage(NamedTuple): - version: HttpVersion - code: int - reason: str - headers: CIMultiDictProxy[str] - raw_headers: RawHeaders - should_close: bool - compression: Optional[str] - upgrade: bool - chunked: bool - - -_MsgT = TypeVar("_MsgT", RawRequestMessage, RawResponseMessage) - - -class ParseState(IntEnum): - - PARSE_NONE = 0 - PARSE_LENGTH = 1 - PARSE_CHUNKED = 2 - PARSE_UNTIL_EOF = 3 - - -class ChunkState(IntEnum): - PARSE_CHUNKED_SIZE = 0 - PARSE_CHUNKED_CHUNK = 1 - PARSE_CHUNKED_CHUNK_EOF = 2 - PARSE_MAYBE_TRAILERS = 3 - PARSE_TRAILERS = 4 - - -class HeadersParser: - def __init__( - self, - max_line_size: int = 8190, - max_headers: int = 32768, - max_field_size: int = 8190, - lax: bool = False, - ) -> None: - self.max_line_size = max_line_size - self.max_headers = max_headers - self.max_field_size = max_field_size - self._lax = lax - - def parse_headers( - self, lines: List[bytes] - ) -> Tuple["CIMultiDictProxy[str]", RawHeaders]: - headers: CIMultiDict[str] = CIMultiDict() - # note: "raw" does not mean inclusion of OWS before/after the field value - raw_headers = [] - - lines_idx = 0 - line = lines[lines_idx] - line_count = len(lines) - - while line: - # Parse initial header name : value pair. - try: - bname, bvalue = line.split(b":", 1) - except ValueError: - raise InvalidHeader(line) from None - - if len(bname) == 0: - raise InvalidHeader(bname) - - # https://www.rfc-editor.org/rfc/rfc9112.html#section-5.1-2 - if {bname[0], bname[-1]} & {32, 9}: # {" ", "\t"} - raise InvalidHeader(line) - - bvalue = bvalue.lstrip(b" \t") - if len(bname) > self.max_field_size: - raise LineTooLong( - "request header name {}".format( - bname.decode("utf8", "backslashreplace") - ), - str(self.max_field_size), - str(len(bname)), - ) - name = bname.decode("utf-8", "surrogateescape") - if not TOKENRE.fullmatch(name): - raise InvalidHeader(bname) - - header_length = len(bvalue) - - # next line - lines_idx += 1 - line = lines[lines_idx] - - # consume continuation lines - continuation = self._lax and line and line[0] in (32, 9) # (' ', '\t') - - # Deprecated: https://www.rfc-editor.org/rfc/rfc9112.html#name-obsolete-line-folding - if continuation: - bvalue_lst = [bvalue] - while continuation: - header_length += len(line) - if header_length > self.max_field_size: - raise LineTooLong( - "request header field {}".format( - bname.decode("utf8", "backslashreplace") - ), - str(self.max_field_size), - str(header_length), - ) - bvalue_lst.append(line) - - # next line - lines_idx += 1 - if lines_idx < line_count: - line = lines[lines_idx] - if line: - continuation = line[0] in (32, 9) # (' ', '\t') - else: - line = b"" - break - bvalue = b"".join(bvalue_lst) - else: - if header_length > self.max_field_size: - raise LineTooLong( - "request header field {}".format( - bname.decode("utf8", "backslashreplace") - ), - str(self.max_field_size), - str(header_length), - ) - - bvalue = bvalue.strip(b" \t") - value = bvalue.decode("utf-8", "surrogateescape") - - # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-5 - if "\n" in value or "\r" in value or "\x00" in value: - raise InvalidHeader(bvalue) - - headers.add(name, value) - raw_headers.append((bname, bvalue)) - - return (CIMultiDictProxy(headers), tuple(raw_headers)) - - -def _is_supported_upgrade(headers: CIMultiDictProxy[str]) -> bool: - """Check if the upgrade header is supported.""" - u = headers.get(hdrs.UPGRADE, "") - # .lower() can transform non-ascii characters. - return u.isascii() and u.lower() in {"tcp", "websocket"} - - -class HttpParser(abc.ABC, Generic[_MsgT]): - lax: ClassVar[bool] = False - - def __init__( - self, - protocol: Optional[BaseProtocol] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - limit: int = 2**16, - max_line_size: int = 8190, - max_headers: int = 32768, - max_field_size: int = 8190, - timer: Optional[BaseTimerContext] = None, - code: Optional[int] = None, - method: Optional[str] = None, - payload_exception: Optional[Type[BaseException]] = None, - response_with_body: bool = True, - read_until_eof: bool = False, - auto_decompress: bool = True, - ) -> None: - self.protocol = protocol - self.loop = loop - self.max_line_size = max_line_size - self.max_headers = max_headers - self.max_field_size = max_field_size - self.timer = timer - self.code = code - self.method = method - self.payload_exception = payload_exception - self.response_with_body = response_with_body - self.read_until_eof = read_until_eof - - self._lines: List[bytes] = [] - self._tail = b"" - self._upgraded = False - self._payload = None - self._payload_parser: Optional[HttpPayloadParser] = None - self._auto_decompress = auto_decompress - self._limit = limit - self._headers_parser = HeadersParser( - max_line_size, max_headers, max_field_size, self.lax - ) - - @abc.abstractmethod - def parse_message(self, lines: List[bytes]) -> _MsgT: ... - - @abc.abstractmethod - def _is_chunked_te(self, te: str) -> bool: ... - - def feed_eof(self) -> Optional[_MsgT]: - if self._payload_parser is not None: - self._payload_parser.feed_eof() - self._payload_parser = None - else: - # try to extract partial message - if self._tail: - self._lines.append(self._tail) - - if self._lines: - if self._lines[-1] != "\r\n": - self._lines.append(b"") - with suppress(Exception): - return self.parse_message(self._lines) - return None - - def feed_data( - self, - data: bytes, - SEP: _SEP = b"\r\n", - EMPTY: bytes = b"", - CONTENT_LENGTH: istr = hdrs.CONTENT_LENGTH, - METH_CONNECT: str = hdrs.METH_CONNECT, - SEC_WEBSOCKET_KEY1: istr = hdrs.SEC_WEBSOCKET_KEY1, - ) -> Tuple[List[Tuple[_MsgT, StreamReader]], bool, bytes]: - - messages = [] - - if self._tail: - data, self._tail = self._tail + data, b"" - - data_len = len(data) - start_pos = 0 - loop = self.loop - - should_close = False - while start_pos < data_len: - - # read HTTP message (request/response line + headers), \r\n\r\n - # and split by lines - if self._payload_parser is None and not self._upgraded: - pos = data.find(SEP, start_pos) - # consume \r\n - if pos == start_pos and not self._lines: - start_pos = pos + len(SEP) - continue - - if pos >= start_pos: - if should_close: - raise BadHttpMessage("Data after `Connection: close`") - - # line found - line = data[start_pos:pos] - if SEP == b"\n": # For lax response parsing - line = line.rstrip(b"\r") - self._lines.append(line) - start_pos = pos + len(SEP) - - # \r\n\r\n found - if self._lines[-1] == EMPTY: - try: - msg: _MsgT = self.parse_message(self._lines) - finally: - self._lines.clear() - - def get_content_length() -> Optional[int]: - # payload length - length_hdr = msg.headers.get(CONTENT_LENGTH) - if length_hdr is None: - return None - - # Shouldn't allow +/- or other number formats. - # https://www.rfc-editor.org/rfc/rfc9110#section-8.6-2 - # msg.headers is already stripped of leading/trailing wsp - if not DIGITS.fullmatch(length_hdr): - raise InvalidHeader(CONTENT_LENGTH) - - return int(length_hdr) - - length = get_content_length() - # do not support old websocket spec - if SEC_WEBSOCKET_KEY1 in msg.headers: - raise InvalidHeader(SEC_WEBSOCKET_KEY1) - - self._upgraded = msg.upgrade and _is_supported_upgrade( - msg.headers - ) - - method = getattr(msg, "method", self.method) - # code is only present on responses - code = getattr(msg, "code", 0) - - assert self.protocol is not None - # calculate payload - empty_body = code in EMPTY_BODY_STATUS_CODES or bool( - method and method in EMPTY_BODY_METHODS - ) - if not empty_body and ( - ((length is not None and length > 0) or msg.chunked) - and not self._upgraded - ): - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - payload_parser = HttpPayloadParser( - payload, - length=length, - chunked=msg.chunked, - method=method, - compression=msg.compression, - code=self.code, - response_with_body=self.response_with_body, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - ) - if not payload_parser.done: - self._payload_parser = payload_parser - elif method == METH_CONNECT: - assert isinstance(msg, RawRequestMessage) - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - self._upgraded = True - self._payload_parser = HttpPayloadParser( - payload, - method=msg.method, - compression=msg.compression, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - ) - elif not empty_body and length is None and self.read_until_eof: - payload = StreamReader( - self.protocol, - timer=self.timer, - loop=loop, - limit=self._limit, - ) - payload_parser = HttpPayloadParser( - payload, - length=length, - chunked=msg.chunked, - method=method, - compression=msg.compression, - code=self.code, - response_with_body=self.response_with_body, - auto_decompress=self._auto_decompress, - lax=self.lax, - headers_parser=self._headers_parser, - ) - if not payload_parser.done: - self._payload_parser = payload_parser - else: - payload = EMPTY_PAYLOAD - - messages.append((msg, payload)) - should_close = msg.should_close - else: - self._tail = data[start_pos:] - data = EMPTY - break - - # no parser, just store - elif self._payload_parser is None and self._upgraded: - assert not self._lines - break - - # feed payload - elif data and start_pos < data_len: - assert not self._lines - assert self._payload_parser is not None - try: - eof, data = self._payload_parser.feed_data(data[start_pos:], SEP) - except BaseException as underlying_exc: - reraised_exc = underlying_exc - if self.payload_exception is not None: - reraised_exc = self.payload_exception(str(underlying_exc)) - - set_exception( - self._payload_parser.payload, - reraised_exc, - underlying_exc, - ) - - eof = True - data = b"" - if isinstance( - underlying_exc, (InvalidHeader, TransferEncodingError) - ): - raise - - if eof: - start_pos = 0 - data_len = len(data) - self._payload_parser = None - continue - else: - break - - if data and start_pos < data_len: - data = data[start_pos:] - else: - data = EMPTY - - return messages, self._upgraded, data - - def parse_headers( - self, lines: List[bytes] - ) -> Tuple[ - "CIMultiDictProxy[str]", RawHeaders, Optional[bool], Optional[str], bool, bool - ]: - """Parses RFC 5322 headers from a stream. - - Line continuations are supported. Returns list of header name - and value pairs. Header name is in upper case. - """ - headers, raw_headers = self._headers_parser.parse_headers(lines) - close_conn = None - encoding = None - upgrade = False - chunked = False - - # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-6 - # https://www.rfc-editor.org/rfc/rfc9110.html#name-collected-abnf - singletons = ( - hdrs.CONTENT_LENGTH, - hdrs.CONTENT_LOCATION, - hdrs.CONTENT_RANGE, - hdrs.CONTENT_TYPE, - hdrs.ETAG, - hdrs.HOST, - hdrs.MAX_FORWARDS, - hdrs.SERVER, - hdrs.TRANSFER_ENCODING, - hdrs.USER_AGENT, - ) - bad_hdr = next((h for h in singletons if len(headers.getall(h, ())) > 1), None) - if bad_hdr is not None: - raise BadHttpMessage(f"Duplicate '{bad_hdr}' header found.") - - # keep-alive - conn = headers.get(hdrs.CONNECTION) - if conn: - v = conn.lower() - if v == "close": - close_conn = True - elif v == "keep-alive": - close_conn = False - # https://www.rfc-editor.org/rfc/rfc9110.html#name-101-switching-protocols - elif v == "upgrade" and headers.get(hdrs.UPGRADE): - upgrade = True - - # encoding - enc = headers.get(hdrs.CONTENT_ENCODING, "") - if enc.isascii() and enc.lower() in {"gzip", "deflate", "br", "zstd"}: - encoding = enc - - # chunking - te = headers.get(hdrs.TRANSFER_ENCODING) - if te is not None: - if self._is_chunked_te(te): - chunked = True - - if hdrs.CONTENT_LENGTH in headers: - raise BadHttpMessage( - "Transfer-Encoding can't be present with Content-Length", - ) - - return (headers, raw_headers, close_conn, encoding, upgrade, chunked) - - def set_upgraded(self, val: bool) -> None: - """Set connection upgraded (to websocket) mode. - - :param bool val: new state. - """ - self._upgraded = val - - -class HttpRequestParser(HttpParser[RawRequestMessage]): - """Read request status line. - - Exception .http_exceptions.BadStatusLine - could be raised in case of any errors in status line. - Returns RawRequestMessage. - """ - - def parse_message(self, lines: List[bytes]) -> RawRequestMessage: - # request line - line = lines[0].decode("utf-8", "surrogateescape") - try: - method, path, version = line.split(" ", maxsplit=2) - except ValueError: - raise BadHttpMethod(line) from None - - if len(path) > self.max_line_size: - raise LineTooLong( - "Status line is too long", str(self.max_line_size), str(len(path)) - ) - - # method - if not TOKENRE.fullmatch(method): - raise BadHttpMethod(method) - - # version - match = VERSRE.fullmatch(version) - if match is None: - raise BadStatusLine(line) - version_o = HttpVersion(int(match.group(1)), int(match.group(2))) - - if method == "CONNECT": - # authority-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 - url = URL.build(authority=path, encoded=True) - elif path.startswith("/"): - # origin-form, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 - path_part, _hash_separator, url_fragment = path.partition("#") - path_part, _question_mark_separator, qs_part = path_part.partition("?") - - # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based - # NOTE: parser does, otherwise it results into the same - # NOTE: HTTP Request-Line input producing different - # NOTE: `yarl.URL()` objects - url = URL.build( - path=path_part, - query_string=qs_part, - fragment=url_fragment, - encoded=True, - ) - elif path == "*" and method == "OPTIONS": - # asterisk-form, - url = URL(path, encoded=True) - else: - # absolute-form for proxy maybe, - # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 - url = URL(path, encoded=True) - if url.scheme == "": - # not absolute-form - raise InvalidURLError( - path.encode(errors="surrogateescape").decode("latin1") - ) - - # read headers - ( - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) = self.parse_headers(lines[1:]) - - if close is None: # then the headers weren't set in the request - if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close - close = True - else: # HTTP 1.1 must ask to close. - close = False - - return RawRequestMessage( - method, - path, - version_o, - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - url, - ) - - def _is_chunked_te(self, te: str) -> bool: - te = te.rsplit(",", maxsplit=1)[-1].strip(" \t") - # .lower() transforms some non-ascii chars, so must check first. - if te.isascii() and te.lower() == "chunked": - return True - # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.3 - raise BadHttpMessage("Request has invalid `Transfer-Encoding`") - - -class HttpResponseParser(HttpParser[RawResponseMessage]): - """Read response status line and headers. - - BadStatusLine could be raised in case of any errors in status line. - Returns RawResponseMessage. - """ - - # Lax mode should only be enabled on response parser. - lax = not DEBUG - - def feed_data( - self, - data: bytes, - SEP: Optional[_SEP] = None, - *args: Any, - **kwargs: Any, - ) -> Tuple[List[Tuple[RawResponseMessage, StreamReader]], bool, bytes]: - if SEP is None: - SEP = b"\r\n" if DEBUG else b"\n" - return super().feed_data(data, SEP, *args, **kwargs) - - def parse_message(self, lines: List[bytes]) -> RawResponseMessage: - line = lines[0].decode("utf-8", "surrogateescape") - try: - version, status = line.split(maxsplit=1) - except ValueError: - raise BadStatusLine(line) from None - - try: - status, reason = status.split(maxsplit=1) - except ValueError: - status = status.strip() - reason = "" - - if len(reason) > self.max_line_size: - raise LineTooLong( - "Status line is too long", str(self.max_line_size), str(len(reason)) - ) - - # version - match = VERSRE.fullmatch(version) - if match is None: - raise BadStatusLine(line) - version_o = HttpVersion(int(match.group(1)), int(match.group(2))) - - # The status code is a three-digit ASCII number, no padding - if len(status) != 3 or not DIGITS.fullmatch(status): - raise BadStatusLine(line) - status_i = int(status) - - # read headers - ( - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) = self.parse_headers(lines[1:]) - - if close is None: - if version_o <= HttpVersion10: - close = True - # https://www.rfc-editor.org/rfc/rfc9112.html#name-message-body-length - elif 100 <= status_i < 200 or status_i in {204, 304}: - close = False - elif hdrs.CONTENT_LENGTH in headers or hdrs.TRANSFER_ENCODING in headers: - close = False - else: - # https://www.rfc-editor.org/rfc/rfc9112.html#section-6.3-2.8 - close = True - - return RawResponseMessage( - version_o, - status_i, - reason.strip(), - headers, - raw_headers, - close, - compression, - upgrade, - chunked, - ) - - def _is_chunked_te(self, te: str) -> bool: - # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.2 - return te.rsplit(",", maxsplit=1)[-1].strip(" \t").lower() == "chunked" - - -class HttpPayloadParser: - def __init__( - self, - payload: StreamReader, - length: Optional[int] = None, - chunked: bool = False, - compression: Optional[str] = None, - code: Optional[int] = None, - method: Optional[str] = None, - response_with_body: bool = True, - auto_decompress: bool = True, - lax: bool = False, - *, - headers_parser: HeadersParser, - ) -> None: - self._length = 0 - self._type = ParseState.PARSE_UNTIL_EOF - self._chunk = ChunkState.PARSE_CHUNKED_SIZE - self._chunk_size = 0 - self._chunk_tail = b"" - self._auto_decompress = auto_decompress - self._lax = lax - self._headers_parser = headers_parser - self._trailer_lines: list[bytes] = [] - self.done = False - - # payload decompression wrapper - if response_with_body and compression and self._auto_decompress: - real_payload: Union[StreamReader, DeflateBuffer] = DeflateBuffer( - payload, compression - ) - else: - real_payload = payload - - # payload parser - if not response_with_body: - # don't parse payload if it's not expected to be received - self._type = ParseState.PARSE_NONE - real_payload.feed_eof() - self.done = True - elif chunked: - self._type = ParseState.PARSE_CHUNKED - elif length is not None: - self._type = ParseState.PARSE_LENGTH - self._length = length - if self._length == 0: - real_payload.feed_eof() - self.done = True - - self.payload = real_payload - - def feed_eof(self) -> None: - if self._type == ParseState.PARSE_UNTIL_EOF: - self.payload.feed_eof() - elif self._type == ParseState.PARSE_LENGTH: - raise ContentLengthError( - "Not enough data to satisfy content length header." - ) - elif self._type == ParseState.PARSE_CHUNKED: - raise TransferEncodingError( - "Not enough data to satisfy transfer length header." - ) - - def feed_data( - self, chunk: bytes, SEP: _SEP = b"\r\n", CHUNK_EXT: bytes = b";" - ) -> Tuple[bool, bytes]: - # Read specified amount of bytes - if self._type == ParseState.PARSE_LENGTH: - required = self._length - chunk_len = len(chunk) - - if required >= chunk_len: - self._length = required - chunk_len - self.payload.feed_data(chunk, chunk_len) - if self._length == 0: - self.payload.feed_eof() - return True, b"" - else: - self._length = 0 - self.payload.feed_data(chunk[:required], required) - self.payload.feed_eof() - return True, chunk[required:] - - # Chunked transfer encoding parser - elif self._type == ParseState.PARSE_CHUNKED: - if self._chunk_tail: - chunk = self._chunk_tail + chunk - self._chunk_tail = b"" - - while chunk: - - # read next chunk size - if self._chunk == ChunkState.PARSE_CHUNKED_SIZE: - pos = chunk.find(SEP) - if pos >= 0: - i = chunk.find(CHUNK_EXT, 0, pos) - if i >= 0: - size_b = chunk[:i] # strip chunk-extensions - # Verify no LF in the chunk-extension - if b"\n" in (ext := chunk[i:pos]): - exc = TransferEncodingError( - f"Unexpected LF in chunk-extension: {ext!r}" - ) - set_exception(self.payload, exc) - raise exc - else: - size_b = chunk[:pos] - - if self._lax: # Allow whitespace in lax mode. - size_b = size_b.strip() - - if not re.fullmatch(HEXDIGITS, size_b): - exc = TransferEncodingError( - chunk[:pos].decode("ascii", "surrogateescape") - ) - set_exception(self.payload, exc) - raise exc - size = int(bytes(size_b), 16) - - chunk = chunk[pos + len(SEP) :] - if size == 0: # eof marker - self._chunk = ChunkState.PARSE_TRAILERS - if self._lax and chunk.startswith(b"\r"): - chunk = chunk[1:] - else: - self._chunk = ChunkState.PARSE_CHUNKED_CHUNK - self._chunk_size = size - self.payload.begin_http_chunk_receiving() - else: - self._chunk_tail = chunk - return False, b"" - - # read chunk and feed buffer - if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK: - required = self._chunk_size - chunk_len = len(chunk) - - if required > chunk_len: - self._chunk_size = required - chunk_len - self.payload.feed_data(chunk, chunk_len) - return False, b"" - else: - self._chunk_size = 0 - self.payload.feed_data(chunk[:required], required) - chunk = chunk[required:] - self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF - self.payload.end_http_chunk_receiving() - - # toss the CRLF at the end of the chunk - if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF: - if self._lax and chunk.startswith(b"\r"): - chunk = chunk[1:] - if chunk[: len(SEP)] == SEP: - chunk = chunk[len(SEP) :] - self._chunk = ChunkState.PARSE_CHUNKED_SIZE - else: - self._chunk_tail = chunk - return False, b"" - - if self._chunk == ChunkState.PARSE_TRAILERS: - pos = chunk.find(SEP) - if pos < 0: # No line found - self._chunk_tail = chunk - return False, b"" - - line = chunk[:pos] - chunk = chunk[pos + len(SEP) :] - if SEP == b"\n": # For lax response parsing - line = line.rstrip(b"\r") - self._trailer_lines.append(line) - - # \r\n\r\n found, end of stream - if self._trailer_lines[-1] == b"": - # Headers and trailers are defined the same way, - # so we reuse the HeadersParser here. - try: - trailers, raw_trailers = self._headers_parser.parse_headers( - self._trailer_lines - ) - finally: - self._trailer_lines.clear() - self.payload.feed_eof() - return True, chunk - - # Read all bytes until eof - elif self._type == ParseState.PARSE_UNTIL_EOF: - self.payload.feed_data(chunk, len(chunk)) - - return False, b"" - - -class DeflateBuffer: - """DeflateStream decompress stream and feed data into specified stream.""" - - decompressor: Any - - def __init__( - self, - out: StreamReader, - encoding: Optional[str], - max_decompress_size: int = DEFAULT_MAX_DECOMPRESS_SIZE, - ) -> None: - self.out = out - self.size = 0 - out.total_compressed_bytes = self.size - self.encoding = encoding - self._started_decoding = False - - self.decompressor: Union[BrotliDecompressor, ZLibDecompressor, ZSTDDecompressor] - if encoding == "br": - if not HAS_BROTLI: # pragma: no cover - raise ContentEncodingError( - "Can not decode content-encoding: brotli (br). " - "Please install `Brotli`" - ) - self.decompressor = BrotliDecompressor() - elif encoding == "zstd": - if not HAS_ZSTD: - raise ContentEncodingError( - "Can not decode content-encoding: zstandard (zstd). " - "Please install `backports.zstd`" - ) - self.decompressor = ZSTDDecompressor() - else: - self.decompressor = ZLibDecompressor(encoding=encoding) - - self._max_decompress_size = max_decompress_size - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - set_exception(self.out, exc, exc_cause) - - def feed_data(self, chunk: bytes, size: int) -> None: - if not size: - return - - self.size += size - self.out.total_compressed_bytes = self.size - - # RFC1950 - # bits 0..3 = CM = 0b1000 = 8 = "deflate" - # bits 4..7 = CINFO = 1..7 = windows size. - if ( - not self._started_decoding - and self.encoding == "deflate" - and chunk[0] & 0xF != 8 - ): - # Change the decoder to decompress incorrectly compressed data - # Actually we should issue a warning about non-RFC-compliant data. - self.decompressor = ZLibDecompressor( - encoding=self.encoding, suppress_deflate_header=True - ) - - try: - # Decompress with limit + 1 so we can detect if output exceeds limit - chunk = self.decompressor.decompress_sync( - chunk, max_length=self._max_decompress_size + 1 - ) - except Exception: - raise ContentEncodingError( - "Can not decode content-encoding: %s" % self.encoding - ) - - self._started_decoding = True - - # Check if decompression limit was exceeded - if len(chunk) > self._max_decompress_size: - raise DecompressSizeError( - "Decompressed data exceeds the configured limit of %d bytes" - % self._max_decompress_size - ) - - if chunk: - self.out.feed_data(chunk, len(chunk)) - - def feed_eof(self) -> None: - chunk = self.decompressor.flush() - - if chunk or self.size > 0: - self.out.feed_data(chunk, len(chunk)) - if self.encoding == "deflate" and not self.decompressor.eof: - raise ContentEncodingError("deflate") - - self.out.feed_eof() - - def begin_http_chunk_receiving(self) -> None: - self.out.begin_http_chunk_receiving() - - def end_http_chunk_receiving(self) -> None: - self.out.end_http_chunk_receiving() - - -HttpRequestParserPy = HttpRequestParser -HttpResponseParserPy = HttpResponseParser -RawRequestMessagePy = RawRequestMessage -RawResponseMessagePy = RawResponseMessage - -try: - if not NO_EXTENSIONS: - from ._http_parser import ( # type: ignore[import-not-found,no-redef] - HttpRequestParser, - HttpResponseParser, - RawRequestMessage, - RawResponseMessage, - ) - - HttpRequestParserC = HttpRequestParser - HttpResponseParserC = HttpResponseParser - RawRequestMessageC = RawRequestMessage - RawResponseMessageC = RawResponseMessage -except ImportError: # pragma: no cover - pass diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_websocket.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/http_websocket.py deleted file mode 100644 index 6b4b30e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_websocket.py +++ /dev/null @@ -1,36 +0,0 @@ -"""WebSocket protocol versions 13 and 8.""" - -from ._websocket.helpers import WS_KEY, ws_ext_gen, ws_ext_parse -from ._websocket.models import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WebSocketError, - WSCloseCode, - WSHandshakeError, - WSMessage, - WSMsgType, -) -from ._websocket.reader import WebSocketReader -from ._websocket.writer import WebSocketWriter - -# Messages that the WebSocketResponse.receive needs to handle internally -_INTERNAL_RECEIVE_TYPES = frozenset( - (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.PING, WSMsgType.PONG) -) - - -__all__ = ( - "WS_CLOSED_MESSAGE", - "WS_CLOSING_MESSAGE", - "WS_KEY", - "WebSocketReader", - "WebSocketWriter", - "WSMessage", - "WebSocketError", - "WSMsgType", - "WSCloseCode", - "ws_ext_gen", - "ws_ext_parse", - "WSHandshakeError", - "WSMessage", -) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_writer.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/http_writer.py deleted file mode 100644 index a140b21..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/http_writer.py +++ /dev/null @@ -1,378 +0,0 @@ -"""Http related parsers and protocol.""" - -import asyncio -import sys -from typing import ( # noqa - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - List, - NamedTuple, - Optional, - Union, -) - -from multidict import CIMultiDict - -from .abc import AbstractStreamWriter -from .base_protocol import BaseProtocol -from .client_exceptions import ClientConnectionResetError -from .compression_utils import ZLibCompressor -from .helpers import NO_EXTENSIONS - -__all__ = ("StreamWriter", "HttpVersion", "HttpVersion10", "HttpVersion11") - - -MIN_PAYLOAD_FOR_WRITELINES = 2048 -IS_PY313_BEFORE_313_2 = (3, 13, 0) <= sys.version_info < (3, 13, 2) -IS_PY_BEFORE_312_9 = sys.version_info < (3, 12, 9) -SKIP_WRITELINES = IS_PY313_BEFORE_313_2 or IS_PY_BEFORE_312_9 -# writelines is not safe for use -# on Python 3.12+ until 3.12.9 -# on Python 3.13+ until 3.13.2 -# and on older versions it not any faster than write -# CVE-2024-12254: https://github.com/python/cpython/pull/127656 - - -class HttpVersion(NamedTuple): - major: int - minor: int - - -HttpVersion10 = HttpVersion(1, 0) -HttpVersion11 = HttpVersion(1, 1) - - -_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] -_T_OnHeadersSent = Optional[Callable[["CIMultiDict[str]"], Awaitable[None]]] - - -class StreamWriter(AbstractStreamWriter): - - length: Optional[int] = None - chunked: bool = False - _eof: bool = False - _compress: Optional[ZLibCompressor] = None - - def __init__( - self, - protocol: BaseProtocol, - loop: asyncio.AbstractEventLoop, - on_chunk_sent: _T_OnChunkSent = None, - on_headers_sent: _T_OnHeadersSent = None, - ) -> None: - self._protocol = protocol - self.loop = loop - self._on_chunk_sent: _T_OnChunkSent = on_chunk_sent - self._on_headers_sent: _T_OnHeadersSent = on_headers_sent - self._headers_buf: Optional[bytes] = None - self._headers_written: bool = False - - @property - def transport(self) -> Optional[asyncio.Transport]: - return self._protocol.transport - - @property - def protocol(self) -> BaseProtocol: - return self._protocol - - def enable_chunking(self) -> None: - self.chunked = True - - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - self._compress = ZLibCompressor(encoding=encoding, strategy=strategy) - - def _write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: - size = len(chunk) - self.buffer_size += size - self.output_size += size - transport = self._protocol.transport - if transport is None or transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - transport.write(chunk) - - def _writelines(self, chunks: Iterable[bytes]) -> None: - size = 0 - for chunk in chunks: - size += len(chunk) - self.buffer_size += size - self.output_size += size - transport = self._protocol.transport - if transport is None or transport.is_closing(): - raise ClientConnectionResetError("Cannot write to closing transport") - if SKIP_WRITELINES or size < MIN_PAYLOAD_FOR_WRITELINES: - transport.write(b"".join(chunks)) - else: - transport.writelines(chunks) - - def _write_chunked_payload( - self, chunk: Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"] - ) -> None: - """Write a chunk with proper chunked encoding.""" - chunk_len_pre = f"{len(chunk):x}\r\n".encode("ascii") - self._writelines((chunk_len_pre, chunk, b"\r\n")) - - def _send_headers_with_payload( - self, - chunk: Union[bytes, bytearray, "memoryview[int]", "memoryview[bytes]"], - is_eof: bool, - ) -> None: - """Send buffered headers with payload, coalescing into single write.""" - # Mark headers as written - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because callers (write() and write_eof()) only invoke this method - # after checking that self._headers_buf is truthy - assert headers_buf is not None - - if not self.chunked: - # Non-chunked: coalesce headers with body - if chunk: - self._writelines((headers_buf, chunk)) - else: - self._write(headers_buf) - return - - # Coalesce headers with chunked data - if chunk: - chunk_len_pre = f"{len(chunk):x}\r\n".encode("ascii") - if is_eof: - self._writelines((headers_buf, chunk_len_pre, chunk, b"\r\n0\r\n\r\n")) - else: - self._writelines((headers_buf, chunk_len_pre, chunk, b"\r\n")) - elif is_eof: - self._writelines((headers_buf, b"0\r\n\r\n")) - else: - self._write(headers_buf) - - async def write( - self, - chunk: Union[bytes, bytearray, memoryview], - *, - drain: bool = True, - LIMIT: int = 0x10000, - ) -> None: - """ - Writes chunk of data to a stream. - - write_eof() indicates end of stream. - writer can't be used after write_eof() method being called. - write() return drain future. - """ - if self._on_chunk_sent is not None: - await self._on_chunk_sent(chunk) - - if isinstance(chunk, memoryview): - if chunk.nbytes != len(chunk): - # just reshape it - chunk = chunk.cast("c") - - if self._compress is not None: - chunk = await self._compress.compress(chunk) - if not chunk: - return - - if self.length is not None: - chunk_len = len(chunk) - if self.length >= chunk_len: - self.length = self.length - chunk_len - else: - chunk = chunk[: self.length] - self.length = 0 - if not chunk: - return - - # Handle buffered headers for small payload optimization - if self._headers_buf and not self._headers_written: - self._send_headers_with_payload(chunk, False) - if drain and self.buffer_size > LIMIT: - self.buffer_size = 0 - await self.drain() - return - - if chunk: - if self.chunked: - self._write_chunked_payload(chunk) - else: - self._write(chunk) - - if drain and self.buffer_size > LIMIT: - self.buffer_size = 0 - await self.drain() - - async def write_headers( - self, status_line: str, headers: "CIMultiDict[str]" - ) -> None: - """Write headers to the stream.""" - if self._on_headers_sent is not None: - await self._on_headers_sent(headers) - # status + headers - buf = _serialize_headers(status_line, headers) - self._headers_written = False - self._headers_buf = buf - - def send_headers(self) -> None: - """Force sending buffered headers if not already sent.""" - if not self._headers_buf or self._headers_written: - return - - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because we only enter this block when self._headers_buf is truthy - assert headers_buf is not None - - self._write(headers_buf) - - def set_eof(self) -> None: - """Indicate that the message is complete.""" - if self._eof: - return - - # If headers haven't been sent yet, send them now - # This handles the case where there's no body at all - if self._headers_buf and not self._headers_written: - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if TYPE_CHECKING: - # Safe because we only enter this block when self._headers_buf is truthy - assert headers_buf is not None - - # Combine headers and chunked EOF marker in a single write - if self.chunked: - self._writelines((headers_buf, b"0\r\n\r\n")) - else: - self._write(headers_buf) - elif self.chunked and self._headers_written: - # Headers already sent, just send the final chunk marker - self._write(b"0\r\n\r\n") - - self._eof = True - - async def write_eof(self, chunk: bytes = b"") -> None: - if self._eof: - return - - if chunk and self._on_chunk_sent is not None: - await self._on_chunk_sent(chunk) - - # Handle body/compression - if self._compress: - chunks: List[bytes] = [] - chunks_len = 0 - if chunk and (compressed_chunk := await self._compress.compress(chunk)): - chunks_len = len(compressed_chunk) - chunks.append(compressed_chunk) - - flush_chunk = self._compress.flush() - chunks_len += len(flush_chunk) - chunks.append(flush_chunk) - assert chunks_len - - # Send buffered headers with compressed data if not yet sent - if self._headers_buf and not self._headers_written: - self._headers_written = True - headers_buf = self._headers_buf - self._headers_buf = None - - if self.chunked: - # Coalesce headers with compressed chunked data - chunk_len_pre = f"{chunks_len:x}\r\n".encode("ascii") - self._writelines( - (headers_buf, chunk_len_pre, *chunks, b"\r\n0\r\n\r\n") - ) - else: - # Coalesce headers with compressed data - self._writelines((headers_buf, *chunks)) - await self.drain() - self._eof = True - return - - # Headers already sent, just write compressed data - if self.chunked: - chunk_len_pre = f"{chunks_len:x}\r\n".encode("ascii") - self._writelines((chunk_len_pre, *chunks, b"\r\n0\r\n\r\n")) - elif len(chunks) > 1: - self._writelines(chunks) - else: - self._write(chunks[0]) - await self.drain() - self._eof = True - return - - # No compression - send buffered headers if not yet sent - if self._headers_buf and not self._headers_written: - # Use helper to send headers with payload - self._send_headers_with_payload(chunk, True) - await self.drain() - self._eof = True - return - - # Handle remaining body - if self.chunked: - if chunk: - # Write final chunk with EOF marker - self._writelines( - (f"{len(chunk):x}\r\n".encode("ascii"), chunk, b"\r\n0\r\n\r\n") - ) - else: - self._write(b"0\r\n\r\n") - await self.drain() - self._eof = True - return - - if chunk: - self._write(chunk) - await self.drain() - - self._eof = True - - async def drain(self) -> None: - """Flush the write buffer. - - The intended use is to write - - await w.write(data) - await w.drain() - """ - protocol = self._protocol - if protocol.transport is not None and protocol._paused: - await protocol._drain_helper() - - -def _safe_header(string: str) -> str: - if "\r" in string or "\n" in string: - raise ValueError( - "Newline or carriage return detected in headers. " - "Potential header injection attack." - ) - return string - - -def _py_serialize_headers(status_line: str, headers: "CIMultiDict[str]") -> bytes: - headers_gen = (_safe_header(k) + ": " + _safe_header(v) for k, v in headers.items()) - line = status_line + "\r\n" + "\r\n".join(headers_gen) + "\r\n\r\n" - return line.encode("utf-8") - - -_serialize_headers = _py_serialize_headers - -try: - import aiohttp._http_writer as _http_writer # type: ignore[import-not-found] - - _c_serialize_headers = _http_writer._serialize_headers - if not NO_EXTENSIONS: - _serialize_headers = _c_serialize_headers -except ImportError: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/log.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/log.py deleted file mode 100644 index 3cecea2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/log.py +++ /dev/null @@ -1,8 +0,0 @@ -import logging - -access_logger = logging.getLogger("aiohttp.access") -client_logger = logging.getLogger("aiohttp.client") -internal_logger = logging.getLogger("aiohttp.internal") -server_logger = logging.getLogger("aiohttp.server") -web_logger = logging.getLogger("aiohttp.web") -ws_logger = logging.getLogger("aiohttp.websocket") diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/multipart.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/multipart.py deleted file mode 100644 index 9c37f0b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/multipart.py +++ /dev/null @@ -1,1152 +0,0 @@ -import base64 -import binascii -import json -import re -import sys -import uuid -import warnings -from collections import deque -from collections.abc import Mapping, Sequence -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Deque, - Dict, - Iterator, - List, - Optional, - Tuple, - Type, - Union, - cast, -) -from urllib.parse import parse_qsl, unquote, urlencode - -from multidict import CIMultiDict, CIMultiDictProxy - -from .abc import AbstractStreamWriter -from .compression_utils import ( - DEFAULT_MAX_DECOMPRESS_SIZE, - ZLibCompressor, - ZLibDecompressor, -) -from .hdrs import ( - CONTENT_DISPOSITION, - CONTENT_ENCODING, - CONTENT_LENGTH, - CONTENT_TRANSFER_ENCODING, - CONTENT_TYPE, -) -from .helpers import CHAR, TOKEN, parse_mimetype, reify -from .http import HeadersParser -from .log import internal_logger -from .payload import ( - JsonPayload, - LookupError, - Order, - Payload, - StringPayload, - get_payload, - payload_type, -) -from .streams import StreamReader - -if sys.version_info >= (3, 11): - from typing import Self -else: - from typing import TypeVar - - Self = TypeVar("Self", bound="BodyPartReader") - -__all__ = ( - "MultipartReader", - "MultipartWriter", - "BodyPartReader", - "BadContentDispositionHeader", - "BadContentDispositionParam", - "parse_content_disposition", - "content_disposition_filename", -) - - -if TYPE_CHECKING: - from .client_reqrep import ClientResponse - - -class BadContentDispositionHeader(RuntimeWarning): - pass - - -class BadContentDispositionParam(RuntimeWarning): - pass - - -def parse_content_disposition( - header: Optional[str], -) -> Tuple[Optional[str], Dict[str, str]]: - def is_token(string: str) -> bool: - return bool(string) and TOKEN >= set(string) - - def is_quoted(string: str) -> bool: - return string[0] == string[-1] == '"' - - def is_rfc5987(string: str) -> bool: - return is_token(string) and string.count("'") == 2 - - def is_extended_param(string: str) -> bool: - return string.endswith("*") - - def is_continuous_param(string: str) -> bool: - pos = string.find("*") + 1 - if not pos: - return False - substring = string[pos:-1] if string.endswith("*") else string[pos:] - return substring.isdigit() - - def unescape(text: str, *, chars: str = "".join(map(re.escape, CHAR))) -> str: - return re.sub(f"\\\\([{chars}])", "\\1", text) - - if not header: - return None, {} - - disptype, *parts = header.split(";") - if not is_token(disptype): - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - params: Dict[str, str] = {} - while parts: - item = parts.pop(0) - - if not item: # To handle trailing semicolons - warnings.warn(BadContentDispositionHeader(header)) - continue - - if "=" not in item: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - key, value = item.split("=", 1) - key = key.lower().strip() - value = value.lstrip() - - if key in params: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - if not is_token(key): - warnings.warn(BadContentDispositionParam(item)) - continue - - elif is_continuous_param(key): - if is_quoted(value): - value = unescape(value[1:-1]) - elif not is_token(value): - warnings.warn(BadContentDispositionParam(item)) - continue - - elif is_extended_param(key): - if is_rfc5987(value): - encoding, _, value = value.split("'", 2) - encoding = encoding or "utf-8" - else: - warnings.warn(BadContentDispositionParam(item)) - continue - - try: - value = unquote(value, encoding, "strict") - except UnicodeDecodeError: # pragma: nocover - warnings.warn(BadContentDispositionParam(item)) - continue - - else: - failed = True - if is_quoted(value): - failed = False - value = unescape(value[1:-1].lstrip("\\/")) - elif is_token(value): - failed = False - elif parts: - # maybe just ; in filename, in any case this is just - # one case fix, for proper fix we need to redesign parser - _value = f"{value};{parts[0]}" - if is_quoted(_value): - parts.pop(0) - value = unescape(_value[1:-1].lstrip("\\/")) - failed = False - - if failed: - warnings.warn(BadContentDispositionHeader(header)) - return None, {} - - params[key] = value - - return disptype.lower(), params - - -def content_disposition_filename( - params: Mapping[str, str], name: str = "filename" -) -> Optional[str]: - name_suf = "%s*" % name - if not params: - return None - elif name_suf in params: - return params[name_suf] - elif name in params: - return params[name] - else: - parts = [] - fnparams = sorted( - (key, value) for key, value in params.items() if key.startswith(name_suf) - ) - for num, (key, value) in enumerate(fnparams): - _, tail = key.split("*", 1) - if tail.endswith("*"): - tail = tail[:-1] - if tail == str(num): - parts.append(value) - else: - break - if not parts: - return None - value = "".join(parts) - if "'" in value: - encoding, _, value = value.split("'", 2) - encoding = encoding or "utf-8" - return unquote(value, encoding, "strict") - return value - - -class MultipartResponseWrapper: - """Wrapper around the MultipartReader. - - It takes care about - underlying connection and close it when it needs in. - """ - - def __init__( - self, - resp: "ClientResponse", - stream: "MultipartReader", - ) -> None: - self.resp = resp - self.stream = stream - - def __aiter__(self) -> "MultipartResponseWrapper": - return self - - async def __anext__( - self, - ) -> Union["MultipartReader", "BodyPartReader"]: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - def at_eof(self) -> bool: - """Returns True when all response data had been read.""" - return self.resp.content.at_eof() - - async def next( - self, - ) -> Optional[Union["MultipartReader", "BodyPartReader"]]: - """Emits next multipart reader object.""" - item = await self.stream.next() - if self.stream.at_eof(): - await self.release() - return item - - async def release(self) -> None: - """Release the connection gracefully. - - All remaining content is read to the void. - """ - await self.resp.release() - - -class BodyPartReader: - """Multipart reader for single body part.""" - - chunk_size = 8192 - - def __init__( - self, - boundary: bytes, - headers: "CIMultiDictProxy[str]", - content: StreamReader, - *, - subtype: str = "mixed", - default_charset: Optional[str] = None, - max_decompress_size: int = DEFAULT_MAX_DECOMPRESS_SIZE, - ) -> None: - self.headers = headers - self._boundary = boundary - self._boundary_len = len(boundary) + 2 # Boundary + \r\n - self._content = content - self._default_charset = default_charset - self._at_eof = False - self._is_form_data = subtype == "form-data" - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None) - self._length = int(length) if length is not None else None - self._read_bytes = 0 - self._unread: Deque[bytes] = deque() - self._prev_chunk: Optional[bytes] = None - self._content_eof = 0 - self._cache: Dict[str, Any] = {} - self._max_decompress_size = max_decompress_size - - def __aiter__(self: Self) -> Self: - return self - - async def __anext__(self) -> bytes: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - async def next(self) -> Optional[bytes]: - item = await self.read() - if not item: - return None - return item - - async def read(self, *, decode: bool = False) -> bytes: - """Reads body part data. - - decode: Decodes data following by encoding - method from Content-Encoding header. If it missed - data remains untouched - """ - if self._at_eof: - return b"" - data = bytearray() - while not self._at_eof: - data.extend(await self.read_chunk(self.chunk_size)) - if decode: - return await self.decode(data) - return data - - async def read_chunk(self, size: int = chunk_size) -> bytes: - """Reads body part content chunk of the specified size. - - size: chunk size - """ - if self._at_eof: - return b"" - if self._length: - chunk = await self._read_chunk_from_length(size) - else: - chunk = await self._read_chunk_from_stream(size) - - # For the case of base64 data, we must read a fragment of size with a - # remainder of 0 by dividing by 4 for string without symbols \n or \r - encoding = self.headers.get(CONTENT_TRANSFER_ENCODING) - if encoding and encoding.lower() == "base64": - stripped_chunk = b"".join(chunk.split()) - remainder = len(stripped_chunk) % 4 - - while remainder != 0 and not self.at_eof(): - over_chunk_size = 4 - remainder - over_chunk = b"" - - if self._prev_chunk: - over_chunk = self._prev_chunk[:over_chunk_size] - self._prev_chunk = self._prev_chunk[len(over_chunk) :] - - if len(over_chunk) != over_chunk_size: - over_chunk += await self._content.read(4 - len(over_chunk)) - - if not over_chunk: - self._at_eof = True - - stripped_chunk += b"".join(over_chunk.split()) - chunk += over_chunk - remainder = len(stripped_chunk) % 4 - - self._read_bytes += len(chunk) - if self._read_bytes == self._length: - self._at_eof = True - if self._at_eof and await self._content.readline() != b"\r\n": - raise ValueError("Reader did not read all the data or it is malformed") - return chunk - - async def _read_chunk_from_length(self, size: int) -> bytes: - # Reads body part content chunk of the specified size. - # The body part must has Content-Length header with proper value. - assert self._length is not None, "Content-Length required for chunked read" - chunk_size = min(size, self._length - self._read_bytes) - chunk = await self._content.read(chunk_size) - if self._content.at_eof(): - self._at_eof = True - return chunk - - async def _read_chunk_from_stream(self, size: int) -> bytes: - # Reads content chunk of body part with unknown length. - # The Content-Length header for body part is not necessary. - assert ( - size >= self._boundary_len - ), "Chunk size must be greater or equal than boundary length + 2" - first_chunk = self._prev_chunk is None - if first_chunk: - # We need to re-add the CRLF that got removed from headers parsing. - self._prev_chunk = b"\r\n" + await self._content.read(size) - - chunk = b"" - # content.read() may return less than size, so we need to loop to ensure - # we have enough data to detect the boundary. - while len(chunk) < self._boundary_len: - chunk += await self._content.read(size) - self._content_eof += int(self._content.at_eof()) - if self._content_eof > 2: - raise ValueError("Reading after EOF") - if self._content_eof: - break - if len(chunk) > size: - self._content.unread_data(chunk[size:]) - chunk = chunk[:size] - - assert self._prev_chunk is not None - window = self._prev_chunk + chunk - sub = b"\r\n" + self._boundary - if first_chunk: - idx = window.find(sub) - else: - idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub))) - if idx >= 0: - # pushing boundary back to content - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - self._content.unread_data(window[idx:]) - self._prev_chunk = self._prev_chunk[:idx] - chunk = window[len(self._prev_chunk) : idx] - if not chunk: - self._at_eof = True - result = self._prev_chunk[2 if first_chunk else 0 :] # Strip initial CRLF - self._prev_chunk = chunk - return result - - async def readline(self) -> bytes: - """Reads body part by line by line.""" - if self._at_eof: - return b"" - - if self._unread: - line = self._unread.popleft() - else: - line = await self._content.readline() - - if line.startswith(self._boundary): - # the very last boundary may not come with \r\n, - # so set single rules for everyone - sline = line.rstrip(b"\r\n") - boundary = self._boundary - last_boundary = self._boundary + b"--" - # ensure that we read exactly the boundary, not something alike - if sline == boundary or sline == last_boundary: - self._at_eof = True - self._unread.append(line) - return b"" - else: - next_line = await self._content.readline() - if next_line.startswith(self._boundary): - line = line[:-2] # strip CRLF but only once - self._unread.append(next_line) - - return line - - async def release(self) -> None: - """Like read(), but reads all the data to the void.""" - if self._at_eof: - return - while not self._at_eof: - await self.read_chunk(self.chunk_size) - - async def text(self, *, encoding: Optional[str] = None) -> str: - """Like read(), but assumes that body part contains text data.""" - data = await self.read(decode=True) - # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm - # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send - encoding = encoding or self.get_charset(default="utf-8") - return data.decode(encoding) - - async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]: - """Like read(), but assumes that body parts contains JSON data.""" - data = await self.read(decode=True) - if not data: - return None - encoding = encoding or self.get_charset(default="utf-8") - return cast(Dict[str, Any], json.loads(data.decode(encoding))) - - async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]: - """Like read(), but assumes that body parts contain form urlencoded data.""" - data = await self.read(decode=True) - if not data: - return [] - if encoding is not None: - real_encoding = encoding - else: - real_encoding = self.get_charset(default="utf-8") - try: - decoded_data = data.rstrip().decode(real_encoding) - except UnicodeDecodeError: - raise ValueError("data cannot be decoded with %s encoding" % real_encoding) - - return parse_qsl( - decoded_data, - keep_blank_values=True, - encoding=real_encoding, - ) - - def at_eof(self) -> bool: - """Returns True if the boundary was reached or False otherwise.""" - return self._at_eof - - async def decode(self, data: bytes) -> bytes: - """Decodes data. - - Decoding is done according the specified Content-Encoding - or Content-Transfer-Encoding headers value. - """ - if CONTENT_TRANSFER_ENCODING in self.headers: - data = self._decode_content_transfer(data) - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - if not self._is_form_data and CONTENT_ENCODING in self.headers: - return await self._decode_content(data) - return data - - async def _decode_content(self, data: bytes) -> bytes: - encoding = self.headers.get(CONTENT_ENCODING, "").lower() - if encoding == "identity": - return data - if encoding in {"deflate", "gzip"}: - return await ZLibDecompressor( - encoding=encoding, - suppress_deflate_header=True, - ).decompress(data, max_length=self._max_decompress_size) - - raise RuntimeError(f"unknown content encoding: {encoding}") - - def _decode_content_transfer(self, data: bytes) -> bytes: - encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() - - if encoding == "base64": - return base64.b64decode(data) - elif encoding == "quoted-printable": - return binascii.a2b_qp(data) - elif encoding in ("binary", "8bit", "7bit"): - return data - else: - raise RuntimeError(f"unknown content transfer encoding: {encoding}") - - def get_charset(self, default: str) -> str: - """Returns charset parameter from Content-Type header or default.""" - ctype = self.headers.get(CONTENT_TYPE, "") - mimetype = parse_mimetype(ctype) - return mimetype.parameters.get("charset", self._default_charset or default) - - @reify - def name(self) -> Optional[str]: - """Returns name specified in Content-Disposition header. - - If the header is missing or malformed, returns None. - """ - _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) - return content_disposition_filename(params, "name") - - @reify - def filename(self) -> Optional[str]: - """Returns filename specified in Content-Disposition header. - - Returns None if the header is missing or malformed. - """ - _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) - return content_disposition_filename(params, "filename") - - -@payload_type(BodyPartReader, order=Order.try_first) -class BodyPartReaderPayload(Payload): - _value: BodyPartReader - # _autoclose = False (inherited) - Streaming reader that may have resources - - def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None: - super().__init__(value, *args, **kwargs) - - params: Dict[str, str] = {} - if value.name is not None: - params["name"] = value.name - if value.filename is not None: - params["filename"] = value.filename - - if params: - self.set_content_disposition("attachment", True, **params) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - raise TypeError("Unable to decode.") - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """Raises TypeError as body parts should be consumed via write(). - - This is intentional: BodyPartReader payloads are designed for streaming - large data (potentially gigabytes) and must be consumed only once via - the write() method to avoid memory exhaustion. They cannot be buffered - in memory for reuse. - """ - raise TypeError("Unable to read body part as bytes. Use write() to consume.") - - async def write(self, writer: AbstractStreamWriter) -> None: - field = self._value - chunk = await field.read_chunk(size=2**16) - while chunk: - await writer.write(await field.decode(chunk)) - chunk = await field.read_chunk(size=2**16) - - -class MultipartReader: - """Multipart body reader.""" - - #: Response wrapper, used when multipart readers constructs from response. - response_wrapper_cls = MultipartResponseWrapper - #: Multipart reader class, used to handle multipart/* body parts. - #: None points to type(self) - multipart_reader_cls: Optional[Type["MultipartReader"]] = None - #: Body part reader class for non multipart/* content types. - part_reader_cls = BodyPartReader - - def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None: - self._mimetype = parse_mimetype(headers[CONTENT_TYPE]) - assert self._mimetype.type == "multipart", "multipart/* content type expected" - if "boundary" not in self._mimetype.parameters: - raise ValueError( - "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE] - ) - - self.headers = headers - self._boundary = ("--" + self._get_boundary()).encode() - self._content = content - self._default_charset: Optional[str] = None - self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None - self._at_eof = False - self._at_bof = True - self._unread: List[bytes] = [] - - def __aiter__(self: Self) -> Self: - return self - - async def __anext__( - self, - ) -> Optional[Union["MultipartReader", BodyPartReader]]: - part = await self.next() - if part is None: - raise StopAsyncIteration - return part - - @classmethod - def from_response( - cls, - response: "ClientResponse", - ) -> MultipartResponseWrapper: - """Constructs reader instance from HTTP response. - - :param response: :class:`~aiohttp.client.ClientResponse` instance - """ - obj = cls.response_wrapper_cls( - response, cls(response.headers, response.content) - ) - return obj - - def at_eof(self) -> bool: - """Returns True if the final boundary was reached, false otherwise.""" - return self._at_eof - - async def next( - self, - ) -> Optional[Union["MultipartReader", BodyPartReader]]: - """Emits the next multipart body part.""" - # So, if we're at BOF, we need to skip till the boundary. - if self._at_eof: - return None - await self._maybe_release_last_part() - if self._at_bof: - await self._read_until_first_boundary() - self._at_bof = False - else: - await self._read_boundary() - if self._at_eof: # we just read the last boundary, nothing to do there - return None - - part = await self.fetch_next_part() - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6 - if ( - self._last_part is None - and self._mimetype.subtype == "form-data" - and isinstance(part, BodyPartReader) - ): - _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION)) - if params.get("name") == "_charset_": - # Longest encoding in https://encoding.spec.whatwg.org/encodings.json - # is 19 characters, so 32 should be more than enough for any valid encoding. - charset = await part.read_chunk(32) - if len(charset) > 31: - raise RuntimeError("Invalid default charset") - self._default_charset = charset.strip().decode() - part = await self.fetch_next_part() - self._last_part = part - return self._last_part - - async def release(self) -> None: - """Reads all the body parts to the void till the final boundary.""" - while not self._at_eof: - item = await self.next() - if item is None: - break - await item.release() - - async def fetch_next_part( - self, - ) -> Union["MultipartReader", BodyPartReader]: - """Returns the next body part reader.""" - headers = await self._read_headers() - return self._get_part_reader(headers) - - def _get_part_reader( - self, - headers: "CIMultiDictProxy[str]", - ) -> Union["MultipartReader", BodyPartReader]: - """Dispatches the response by the `Content-Type` header. - - Returns a suitable reader instance. - - :param dict headers: Response headers - """ - ctype = headers.get(CONTENT_TYPE, "") - mimetype = parse_mimetype(ctype) - - if mimetype.type == "multipart": - if self.multipart_reader_cls is None: - return type(self)(headers, self._content) - return self.multipart_reader_cls(headers, self._content) - else: - return self.part_reader_cls( - self._boundary, - headers, - self._content, - subtype=self._mimetype.subtype, - default_charset=self._default_charset, - ) - - def _get_boundary(self) -> str: - boundary = self._mimetype.parameters["boundary"] - if len(boundary) > 70: - raise ValueError("boundary %r is too long (70 chars max)" % boundary) - - return boundary - - async def _readline(self) -> bytes: - if self._unread: - return self._unread.pop() - return await self._content.readline() - - async def _read_until_first_boundary(self) -> None: - while True: - chunk = await self._readline() - if chunk == b"": - raise ValueError( - "Could not find starting boundary %r" % (self._boundary) - ) - chunk = chunk.rstrip() - if chunk == self._boundary: - return - elif chunk == self._boundary + b"--": - self._at_eof = True - return - - async def _read_boundary(self) -> None: - chunk = (await self._readline()).rstrip() - if chunk == self._boundary: - pass - elif chunk == self._boundary + b"--": - self._at_eof = True - epilogue = await self._readline() - next_line = await self._readline() - - # the epilogue is expected and then either the end of input or the - # parent multipart boundary, if the parent boundary is found then - # it should be marked as unread and handed to the parent for - # processing - if next_line[:2] == b"--": - self._unread.append(next_line) - # otherwise the request is likely missing an epilogue and both - # lines should be passed to the parent for processing - # (this handles the old behavior gracefully) - else: - self._unread.extend([next_line, epilogue]) - else: - raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}") - - async def _read_headers(self) -> "CIMultiDictProxy[str]": - lines = [] - while True: - chunk = await self._content.readline() - chunk = chunk.rstrip(b"\r\n") - lines.append(chunk) - if not chunk: - break - parser = HeadersParser() - headers, raw_headers = parser.parse_headers(lines) - return headers - - async def _maybe_release_last_part(self) -> None: - """Ensures that the last read body part is read completely.""" - if self._last_part is not None: - if not self._last_part.at_eof(): - await self._last_part.release() - self._unread.extend(self._last_part._unread) - self._last_part = None - - -_Part = Tuple[Payload, str, str] - - -class MultipartWriter(Payload): - """Multipart body writer.""" - - _value: None - # _consumed = False (inherited) - Can be encoded multiple times - _autoclose = True # No file handles, just collects parts in memory - - def __init__(self, subtype: str = "mixed", boundary: Optional[str] = None) -> None: - boundary = boundary if boundary is not None else uuid.uuid4().hex - # The underlying Payload API demands a str (utf-8), not bytes, - # so we need to ensure we don't lose anything during conversion. - # As a result, require the boundary to be ASCII only. - # In both situations. - - try: - self._boundary = boundary.encode("ascii") - except UnicodeEncodeError: - raise ValueError("boundary should contain ASCII only chars") from None - ctype = f"multipart/{subtype}; boundary={self._boundary_value}" - - super().__init__(None, content_type=ctype) - - self._parts: List[_Part] = [] - self._is_form_data = subtype == "form-data" - - def __enter__(self) -> "MultipartWriter": - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - pass - - def __iter__(self) -> Iterator[_Part]: - return iter(self._parts) - - def __len__(self) -> int: - return len(self._parts) - - def __bool__(self) -> bool: - return True - - _valid_tchar_regex = re.compile(rb"\A[!#$%&'*+\-.^_`|~\w]+\Z") - _invalid_qdtext_char_regex = re.compile(rb"[\x00-\x08\x0A-\x1F\x7F]") - - @property - def _boundary_value(self) -> str: - """Wrap boundary parameter value in quotes, if necessary. - - Reads self.boundary and returns a unicode string. - """ - # Refer to RFCs 7231, 7230, 5234. - # - # parameter = token "=" ( token / quoted-string ) - # token = 1*tchar - # quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE - # qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text - # obs-text = %x80-FF - # quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" - # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" - # / DIGIT / ALPHA - # ; any VCHAR, except delimiters - # VCHAR = %x21-7E - value = self._boundary - if re.match(self._valid_tchar_regex, value): - return value.decode("ascii") # cannot fail - - if re.search(self._invalid_qdtext_char_regex, value): - raise ValueError("boundary value contains invalid characters") - - # escape %x5C and %x22 - quoted_value_content = value.replace(b"\\", b"\\\\") - quoted_value_content = quoted_value_content.replace(b'"', b'\\"') - - return '"' + quoted_value_content.decode("ascii") + '"' - - @property - def boundary(self) -> str: - return self._boundary.decode("ascii") - - def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload: - if headers is None: - headers = CIMultiDict() - - if isinstance(obj, Payload): - obj.headers.update(headers) - return self.append_payload(obj) - else: - try: - payload = get_payload(obj, headers=headers) - except LookupError: - raise TypeError("Cannot create payload from %r" % obj) - else: - return self.append_payload(payload) - - def append_payload(self, payload: Payload) -> Payload: - """Adds a new body part to multipart writer.""" - encoding: Optional[str] = None - te_encoding: Optional[str] = None - if self._is_form_data: - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7 - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 - assert ( - not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} - & payload.headers.keys() - ) - # Set default Content-Disposition in case user doesn't create one - if CONTENT_DISPOSITION not in payload.headers: - name = f"section-{len(self._parts)}" - payload.set_content_disposition("form-data", name=name) - else: - # compression - encoding = payload.headers.get(CONTENT_ENCODING, "").lower() - if encoding and encoding not in ("deflate", "gzip", "identity"): - raise RuntimeError(f"unknown content encoding: {encoding}") - if encoding == "identity": - encoding = None - - # te encoding - te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() - if te_encoding not in ("", "base64", "quoted-printable", "binary"): - raise RuntimeError(f"unknown content transfer encoding: {te_encoding}") - if te_encoding == "binary": - te_encoding = None - - # size - size = payload.size - if size is not None and not (encoding or te_encoding): - payload.headers[CONTENT_LENGTH] = str(size) - - self._parts.append((payload, encoding, te_encoding)) # type: ignore[arg-type] - return payload - - def append_json( - self, obj: Any, headers: Optional[Mapping[str, str]] = None - ) -> Payload: - """Helper to append JSON part.""" - if headers is None: - headers = CIMultiDict() - - return self.append_payload(JsonPayload(obj, headers=headers)) - - def append_form( - self, - obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]], - headers: Optional[Mapping[str, str]] = None, - ) -> Payload: - """Helper to append form urlencoded part.""" - assert isinstance(obj, (Sequence, Mapping)) - - if headers is None: - headers = CIMultiDict() - - if isinstance(obj, Mapping): - obj = list(obj.items()) - data = urlencode(obj, doseq=True) - - return self.append_payload( - StringPayload( - data, headers=headers, content_type="application/x-www-form-urlencoded" - ) - ) - - @property - def size(self) -> Optional[int]: - """Size of the payload.""" - total = 0 - for part, encoding, te_encoding in self._parts: - part_size = part.size - if encoding or te_encoding or part_size is None: - return None - - total += int( - 2 - + len(self._boundary) - + 2 - + part_size # b'--'+self._boundary+b'\r\n' - + len(part._binary_headers) - + 2 # b'\r\n' - ) - - total += 2 + len(self._boundary) + 4 # b'--'+self._boundary+b'--\r\n' - return total - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """Return string representation of the multipart data. - - WARNING: This method may do blocking I/O if parts contain file payloads. - It should not be called in the event loop. Use as_bytes().decode() instead. - """ - return "".join( - "--" - + self.boundary - + "\r\n" - + part._binary_headers.decode(encoding, errors) - + part.decode() - for part, _e, _te in self._parts - ) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """Return bytes representation of the multipart data. - - This method is async-safe and calls as_bytes on underlying payloads. - """ - parts: List[bytes] = [] - - # Process each part - for part, _e, _te in self._parts: - # Add boundary - parts.append(b"--" + self._boundary + b"\r\n") - - # Add headers - parts.append(part._binary_headers) - - # Add payload content using as_bytes for async safety - part_bytes = await part.as_bytes(encoding, errors) - parts.append(part_bytes) - - # Add trailing CRLF - parts.append(b"\r\n") - - # Add closing boundary - parts.append(b"--" + self._boundary + b"--\r\n") - - return b"".join(parts) - - async def write( - self, writer: AbstractStreamWriter, close_boundary: bool = True - ) -> None: - """Write body.""" - for part, encoding, te_encoding in self._parts: - if self._is_form_data: - # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 - assert CONTENT_DISPOSITION in part.headers - assert "name=" in part.headers[CONTENT_DISPOSITION] - - await writer.write(b"--" + self._boundary + b"\r\n") - await writer.write(part._binary_headers) - - if encoding or te_encoding: - w = MultipartPayloadWriter(writer) - if encoding: - w.enable_compression(encoding) - if te_encoding: - w.enable_encoding(te_encoding) - await part.write(w) # type: ignore[arg-type] - await w.write_eof() - else: - await part.write(writer) - - await writer.write(b"\r\n") - - if close_boundary: - await writer.write(b"--" + self._boundary + b"--\r\n") - - async def close(self) -> None: - """ - Close all part payloads that need explicit closing. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - """ - if self._consumed: - return - self._consumed = True - - # Close all parts that need explicit closing - # We catch and log exceptions to ensure all parts get a chance to close - # we do not use asyncio.gather() here because we are not allowed - # to suspend given we may be called during cleanup - for idx, (part, _, _) in enumerate(self._parts): - if not part.autoclose and not part.consumed: - try: - await part.close() - except Exception as exc: - internal_logger.error( - "Failed to close multipart part %d: %s", idx, exc, exc_info=True - ) - - -class MultipartPayloadWriter: - def __init__(self, writer: AbstractStreamWriter) -> None: - self._writer = writer - self._encoding: Optional[str] = None - self._compress: Optional[ZLibCompressor] = None - self._encoding_buffer: Optional[bytearray] = None - - def enable_encoding(self, encoding: str) -> None: - if encoding == "base64": - self._encoding = encoding - self._encoding_buffer = bytearray() - elif encoding == "quoted-printable": - self._encoding = "quoted-printable" - - def enable_compression( - self, encoding: str = "deflate", strategy: Optional[int] = None - ) -> None: - self._compress = ZLibCompressor( - encoding=encoding, - suppress_deflate_header=True, - strategy=strategy, - ) - - async def write_eof(self) -> None: - if self._compress is not None: - chunk = self._compress.flush() - if chunk: - self._compress = None - await self.write(chunk) - - if self._encoding == "base64": - if self._encoding_buffer: - await self._writer.write(base64.b64encode(self._encoding_buffer)) - - async def write(self, chunk: bytes) -> None: - if self._compress is not None: - if chunk: - chunk = await self._compress.compress(chunk) - if not chunk: - return - - if self._encoding == "base64": - buf = self._encoding_buffer - assert buf is not None - buf.extend(chunk) - - if buf: - div, mod = divmod(len(buf), 3) - enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :]) - if enc_chunk: - b64chunk = base64.b64encode(enc_chunk) - await self._writer.write(b64chunk) - elif self._encoding == "quoted-printable": - await self._writer.write(binascii.b2a_qp(chunk)) - else: - await self._writer.write(chunk) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/payload.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/payload.py deleted file mode 100644 index 5b88fa0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/payload.py +++ /dev/null @@ -1,1120 +0,0 @@ -import asyncio -import enum -import io -import json -import mimetypes -import os -import sys -import warnings -from abc import ABC, abstractmethod -from collections.abc import Iterable -from itertools import chain -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - Final, - List, - Optional, - Set, - TextIO, - Tuple, - Type, - Union, -) - -from multidict import CIMultiDict - -from . import hdrs -from .abc import AbstractStreamWriter -from .helpers import ( - _SENTINEL, - content_disposition_header, - guess_filename, - parse_mimetype, - sentinel, -) -from .streams import StreamReader -from .typedefs import JSONEncoder, _CIMultiDict - -__all__ = ( - "PAYLOAD_REGISTRY", - "get_payload", - "payload_type", - "Payload", - "BytesPayload", - "StringPayload", - "IOBasePayload", - "BytesIOPayload", - "BufferedReaderPayload", - "TextIOPayload", - "StringIOPayload", - "JsonPayload", - "AsyncIterablePayload", -) - -TOO_LARGE_BYTES_BODY: Final[int] = 2**20 # 1 MB -READ_SIZE: Final[int] = 2**16 # 64 KB -_CLOSE_FUTURES: Set[asyncio.Future[None]] = set() - - -class LookupError(Exception): - """Raised when no payload factory is found for the given data type.""" - - -class Order(str, enum.Enum): - normal = "normal" - try_first = "try_first" - try_last = "try_last" - - -def get_payload(data: Any, *args: Any, **kwargs: Any) -> "Payload": - return PAYLOAD_REGISTRY.get(data, *args, **kwargs) - - -def register_payload( - factory: Type["Payload"], type: Any, *, order: Order = Order.normal -) -> None: - PAYLOAD_REGISTRY.register(factory, type, order=order) - - -class payload_type: - def __init__(self, type: Any, *, order: Order = Order.normal) -> None: - self.type = type - self.order = order - - def __call__(self, factory: Type["Payload"]) -> Type["Payload"]: - register_payload(factory, self.type, order=self.order) - return factory - - -PayloadType = Type["Payload"] -_PayloadRegistryItem = Tuple[PayloadType, Any] - - -class PayloadRegistry: - """Payload registry. - - note: we need zope.interface for more efficient adapter search - """ - - __slots__ = ("_first", "_normal", "_last", "_normal_lookup") - - def __init__(self) -> None: - self._first: List[_PayloadRegistryItem] = [] - self._normal: List[_PayloadRegistryItem] = [] - self._last: List[_PayloadRegistryItem] = [] - self._normal_lookup: Dict[Any, PayloadType] = {} - - def get( - self, - data: Any, - *args: Any, - _CHAIN: "Type[chain[_PayloadRegistryItem]]" = chain, - **kwargs: Any, - ) -> "Payload": - if self._first: - for factory, type_ in self._first: - if isinstance(data, type_): - return factory(data, *args, **kwargs) - # Try the fast lookup first - if lookup_factory := self._normal_lookup.get(type(data)): - return lookup_factory(data, *args, **kwargs) - # Bail early if its already a Payload - if isinstance(data, Payload): - return data - # Fallback to the slower linear search - for factory, type_ in _CHAIN(self._normal, self._last): - if isinstance(data, type_): - return factory(data, *args, **kwargs) - raise LookupError() - - def register( - self, factory: PayloadType, type: Any, *, order: Order = Order.normal - ) -> None: - if order is Order.try_first: - self._first.append((factory, type)) - elif order is Order.normal: - self._normal.append((factory, type)) - if isinstance(type, Iterable): - for t in type: - self._normal_lookup[t] = factory - else: - self._normal_lookup[type] = factory - elif order is Order.try_last: - self._last.append((factory, type)) - else: - raise ValueError(f"Unsupported order {order!r}") - - -class Payload(ABC): - - _default_content_type: str = "application/octet-stream" - _size: Optional[int] = None - _consumed: bool = False # Default: payload has not been consumed yet - _autoclose: bool = False # Default: assume resource needs explicit closing - - def __init__( - self, - value: Any, - headers: Optional[ - Union[_CIMultiDict, Dict[str, str], Iterable[Tuple[str, str]]] - ] = None, - content_type: Union[str, None, _SENTINEL] = sentinel, - filename: Optional[str] = None, - encoding: Optional[str] = None, - **kwargs: Any, - ) -> None: - self._encoding = encoding - self._filename = filename - self._headers: _CIMultiDict = CIMultiDict() - self._value = value - if content_type is not sentinel and content_type is not None: - self._headers[hdrs.CONTENT_TYPE] = content_type - elif self._filename is not None: - if sys.version_info >= (3, 13): - guesser = mimetypes.guess_file_type - else: - guesser = mimetypes.guess_type - content_type = guesser(self._filename)[0] - if content_type is None: - content_type = self._default_content_type - self._headers[hdrs.CONTENT_TYPE] = content_type - else: - self._headers[hdrs.CONTENT_TYPE] = self._default_content_type - if headers: - self._headers.update(headers) - - @property - def size(self) -> Optional[int]: - """Size of the payload in bytes. - - Returns the number of bytes that will be transmitted when the payload - is written. For string payloads, this is the size after encoding to bytes, - not the length of the string. - """ - return self._size - - @property - def filename(self) -> Optional[str]: - """Filename of the payload.""" - return self._filename - - @property - def headers(self) -> _CIMultiDict: - """Custom item headers""" - return self._headers - - @property - def _binary_headers(self) -> bytes: - return ( - "".join([k + ": " + v + "\r\n" for k, v in self.headers.items()]).encode( - "utf-8" - ) - + b"\r\n" - ) - - @property - def encoding(self) -> Optional[str]: - """Payload encoding""" - return self._encoding - - @property - def content_type(self) -> str: - """Content type""" - return self._headers[hdrs.CONTENT_TYPE] - - @property - def consumed(self) -> bool: - """Whether the payload has been consumed and cannot be reused.""" - return self._consumed - - @property - def autoclose(self) -> bool: - """ - Whether the payload can close itself automatically. - - Returns True if the payload has no file handles or resources that need - explicit closing. If False, callers must await close() to release resources. - """ - return self._autoclose - - def set_content_disposition( - self, - disptype: str, - quote_fields: bool = True, - _charset: str = "utf-8", - **params: Any, - ) -> None: - """Sets ``Content-Disposition`` header.""" - self._headers[hdrs.CONTENT_DISPOSITION] = content_disposition_header( - disptype, quote_fields=quote_fields, _charset=_charset, **params - ) - - @abstractmethod - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - This is named decode() to allow compatibility with bytes objects. - """ - - @abstractmethod - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This is a legacy method that writes the entire payload without length constraints. - - Important: - For new implementations, use write_with_length() instead of this method. - This method is maintained for backwards compatibility and will eventually - delegate to write_with_length(writer, None) in all implementations. - - All payload subclasses must override this method for backwards compatibility, - but new code should use write_with_length for more flexibility and control. - - """ - - # write_with_length is new in aiohttp 3.12 - # it should be overridden by subclasses - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method allows writing payload content with a specific length constraint, - which is particularly useful for HTTP responses with Content-Length header. - - Note: - This is the base implementation that provides backwards compatibility - for subclasses that don't override this method. Specific payload types - should override this method to implement proper length-constrained writing. - - """ - # Backwards compatibility for subclasses that don't override this method - # and for the default implementation - await self.write(writer) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This is a convenience method that calls decode() and encodes the result - to bytes using the specified encoding. - """ - # Use instance encoding if available, otherwise use parameter - actual_encoding = self._encoding or encoding - return self.decode(actual_encoding, errors).encode(actual_encoding) - - def _close(self) -> None: - """ - Async safe synchronous close operations for backwards compatibility. - - This method exists only for backwards compatibility with code that - needs to clean up payloads synchronously. In the future, we will - drop this method and only support the async close() method. - - WARNING: This method must be safe to call from within the event loop - without blocking. Subclasses should not perform any blocking I/O here. - - WARNING: This method must be called from within an event loop for - certain payload types (e.g., IOBasePayload). Calling it outside an - event loop may raise RuntimeError. - """ - # This is a no-op by default, but subclasses can override it - # for non-blocking cleanup operations. - - async def close(self) -> None: - """ - Close the payload if it holds any resources. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - - In the future, this will be the only close method supported. - """ - self._close() - - -class BytesPayload(Payload): - _value: bytes - # _consumed = False (inherited) - Bytes are immutable and can be reused - _autoclose = True # No file handle, just bytes in memory - - def __init__( - self, value: Union[bytes, bytearray, memoryview], *args: Any, **kwargs: Any - ) -> None: - if "content_type" not in kwargs: - kwargs["content_type"] = "application/octet-stream" - - super().__init__(value, *args, **kwargs) - - if isinstance(value, memoryview): - self._size = value.nbytes - elif isinstance(value, (bytes, bytearray)): - self._size = len(value) - else: - raise TypeError(f"value argument must be byte-ish, not {type(value)!r}") - - if self._size > TOO_LARGE_BYTES_BODY: - kwargs = {"source": self} - warnings.warn( - "Sending a large body directly with raw bytes might" - " lock the event loop. You should probably pass an " - "io.BytesIO object instead", - ResourceWarning, - **kwargs, - ) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - return self._value.decode(encoding, errors) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method returns the raw bytes content of the payload. - It is equivalent to accessing the _value attribute directly. - """ - return self._value - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire bytes payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method writes the entire bytes content without any length constraint. - - Note: - For new implementations that need length control, use write_with_length(). - This method is maintained for backwards compatibility and is equivalent - to write_with_length(writer, None). - - """ - await writer.write(self._value) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write bytes payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method writes either the entire byte sequence or a slice of it - up to the specified content_length. For BytesPayload, this operation - is performed efficiently using array slicing. - - """ - if content_length is not None: - await writer.write(self._value[:content_length]) - else: - await writer.write(self._value) - - -class StringPayload(BytesPayload): - def __init__( - self, - value: str, - *args: Any, - encoding: Optional[str] = None, - content_type: Optional[str] = None, - **kwargs: Any, - ) -> None: - - if encoding is None: - if content_type is None: - real_encoding = "utf-8" - content_type = "text/plain; charset=utf-8" - else: - mimetype = parse_mimetype(content_type) - real_encoding = mimetype.parameters.get("charset", "utf-8") - else: - if content_type is None: - content_type = "text/plain; charset=%s" % encoding - real_encoding = encoding - - super().__init__( - value.encode(real_encoding), - encoding=real_encoding, - content_type=content_type, - *args, - **kwargs, - ) - - -class StringIOPayload(StringPayload): - def __init__(self, value: IO[str], *args: Any, **kwargs: Any) -> None: - super().__init__(value.read(), *args, **kwargs) - - -class IOBasePayload(Payload): - _value: io.IOBase - # _consumed = False (inherited) - File can be re-read from the same position - _start_position: Optional[int] = None - # _autoclose = False (inherited) - Has file handle that needs explicit closing - - def __init__( - self, value: IO[Any], disposition: str = "attachment", *args: Any, **kwargs: Any - ) -> None: - if "filename" not in kwargs: - kwargs["filename"] = guess_filename(value) - - super().__init__(value, *args, **kwargs) - - if self._filename is not None and disposition is not None: - if hdrs.CONTENT_DISPOSITION not in self.headers: - self.set_content_disposition(disposition, filename=self._filename) - - def _set_or_restore_start_position(self) -> None: - """Set or restore the start position of the file-like object.""" - if self._start_position is None: - try: - self._start_position = self._value.tell() - except (OSError, AttributeError): - self._consumed = True # Cannot seek, mark as consumed - return - try: - self._value.seek(self._start_position) - except (OSError, AttributeError): - # Failed to seek back - mark as consumed since we've already read - self._consumed = True - - def _read_and_available_len( - self, remaining_content_len: Optional[int] - ) -> Tuple[Optional[int], bytes]: - """ - Read the file-like object and return both its total size and the first chunk. - - Args: - remaining_content_len: Optional limit on how many bytes to read in this operation. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A tuple containing: - - The total size of the remaining unread content (None if size cannot be determined) - - The first chunk of bytes read from the file object - - This method is optimized to perform both size calculation and initial read - in a single operation, which is executed in a single executor job to minimize - context switches and file operations when streaming content. - - """ - self._set_or_restore_start_position() - size = self.size # Call size only once since it does I/O - return size, self._value.read( - min(READ_SIZE, size or READ_SIZE, remaining_content_len or READ_SIZE) - ) - - def _read(self, remaining_content_len: Optional[int]) -> bytes: - """ - Read a chunk of data from the file-like object. - - Args: - remaining_content_len: Optional maximum number of bytes to read. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A chunk of bytes read from the file object, respecting the - remaining_content_len limit if specified. - - This method is used for subsequent reads during streaming after - the initial _read_and_available_len call has been made. - - """ - return self._value.read(remaining_content_len or READ_SIZE) # type: ignore[no-any-return] - - @property - def size(self) -> Optional[int]: - """ - Size of the payload in bytes. - - Returns the total size of the payload content from the initial position. - This ensures consistent Content-Length for requests, including 307/308 redirects - where the same payload instance is reused. - - Returns None if the size cannot be determined (e.g., for unseekable streams). - """ - try: - # Store the start position on first access. - # This is critical when the same payload instance is reused (e.g., 307/308 - # redirects). Without storing the initial position, after the payload is - # read once, the file position would be at EOF, which would cause the - # size calculation to return 0 (file_size - EOF position). - # By storing the start position, we ensure the size calculation always - # returns the correct total size for any subsequent use. - if self._start_position is None: - self._start_position = self._value.tell() - - # Return the total size from the start position - # This ensures Content-Length is correct even after reading - return os.fstat(self._value.fileno()).st_size - self._start_position - except (AttributeError, OSError): - return None - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire file-like payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method writes the entire file content without any length constraint. - It delegates to write_with_length() with no length limit for implementation - consistency. - - Note: - For new implementations that need length control, use write_with_length() directly. - This method is maintained for backwards compatibility with existing code. - - """ - await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write file-like payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This method implements optimized streaming of file content with length constraints: - - 1. File reading is performed in a thread pool to avoid blocking the event loop - 2. Content is read and written in chunks to maintain memory efficiency - 3. Writing stops when either: - - All available file content has been written (when size is known) - - The specified content_length has been reached - 4. File resources are properly closed even if the operation is cancelled - - The implementation carefully handles both known-size and unknown-size payloads, - as well as constrained and unconstrained content lengths. - - """ - loop = asyncio.get_running_loop() - total_written_len = 0 - remaining_content_len = content_length - - # Get initial data and available length - available_len, chunk = await loop.run_in_executor( - None, self._read_and_available_len, remaining_content_len - ) - # Process data chunks until done - while chunk: - chunk_len = len(chunk) - - # Write data with or without length constraint - if remaining_content_len is None: - await writer.write(chunk) - else: - await writer.write(chunk[:remaining_content_len]) - remaining_content_len -= chunk_len - - total_written_len += chunk_len - - # Check if we're done writing - if self._should_stop_writing( - available_len, total_written_len, remaining_content_len - ): - return - - # Read next chunk - chunk = await loop.run_in_executor( - None, - self._read, - ( - min(READ_SIZE, remaining_content_len) - if remaining_content_len is not None - else READ_SIZE - ), - ) - - def _should_stop_writing( - self, - available_len: Optional[int], - total_written_len: int, - remaining_content_len: Optional[int], - ) -> bool: - """ - Determine if we should stop writing data. - - Args: - available_len: Known size of the payload if available (None if unknown) - total_written_len: Number of bytes already written - remaining_content_len: Remaining bytes to be written for content-length limited responses - - Returns: - True if we should stop writing data, based on either: - - Having written all available data (when size is known) - - Having written all requested content (when content-length is specified) - - """ - return (available_len is not None and total_written_len >= available_len) or ( - remaining_content_len is not None and remaining_content_len <= 0 - ) - - def _close(self) -> None: - """ - Async safe synchronous close operations for backwards compatibility. - - This method exists only for backwards - compatibility. Use the async close() method instead. - - WARNING: This method MUST be called from within an event loop. - Calling it outside an event loop will raise RuntimeError. - """ - # Skip if already consumed - if self._consumed: - return - self._consumed = True # Mark as consumed to prevent further writes - # Schedule file closing without awaiting to prevent cancellation issues - loop = asyncio.get_running_loop() - close_future = loop.run_in_executor(None, self._value.close) - # Hold a strong reference to the future to prevent it from being - # garbage collected before it completes. - _CLOSE_FUTURES.add(close_future) - close_future.add_done_callback(_CLOSE_FUTURES.remove) - - async def close(self) -> None: - """ - Close the payload if it holds any resources. - - IMPORTANT: This method must not await anything that might not finish - immediately, as it may be called during cleanup/cancellation. Schedule - any long-running operations without awaiting them. - """ - self._close() - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - WARNING: This method does blocking I/O and should not be called in the event loop. - """ - return self._read_all().decode(encoding, errors) - - def _read_all(self) -> bytes: - """Read the entire file-like object and return its content as bytes.""" - self._set_or_restore_start_position() - # Use readlines() to ensure we get all content - return b"".join(self._value.readlines()) - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire file content and returns it as bytes. - It is equivalent to reading the file-like object directly. - The file reading is performed in an executor to avoid blocking the event loop. - """ - loop = asyncio.get_running_loop() - return await loop.run_in_executor(None, self._read_all) - - -class TextIOPayload(IOBasePayload): - _value: io.TextIOBase - # _autoclose = False (inherited) - Has text file handle that needs explicit closing - - def __init__( - self, - value: TextIO, - *args: Any, - encoding: Optional[str] = None, - content_type: Optional[str] = None, - **kwargs: Any, - ) -> None: - - if encoding is None: - if content_type is None: - encoding = "utf-8" - content_type = "text/plain; charset=utf-8" - else: - mimetype = parse_mimetype(content_type) - encoding = mimetype.parameters.get("charset", "utf-8") - else: - if content_type is None: - content_type = "text/plain; charset=%s" % encoding - - super().__init__( - value, - content_type=content_type, - encoding=encoding, - *args, - **kwargs, - ) - - def _read_and_available_len( - self, remaining_content_len: Optional[int] - ) -> Tuple[Optional[int], bytes]: - """ - Read the text file-like object and return both its total size and the first chunk. - - Args: - remaining_content_len: Optional limit on how many bytes to read in this operation. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A tuple containing: - - The total size of the remaining unread content (None if size cannot be determined) - - The first chunk of bytes read from the file object, encoded using the payload's encoding - - This method is optimized to perform both size calculation and initial read - in a single operation, which is executed in a single executor job to minimize - context switches and file operations when streaming content. - - Note: - TextIOPayload handles encoding of the text content before writing it - to the stream. If no encoding is specified, UTF-8 is used as the default. - - """ - self._set_or_restore_start_position() - size = self.size - chunk = self._value.read( - min(READ_SIZE, size or READ_SIZE, remaining_content_len or READ_SIZE) - ) - return size, chunk.encode(self._encoding) if self._encoding else chunk.encode() - - def _read(self, remaining_content_len: Optional[int]) -> bytes: - """ - Read a chunk of data from the text file-like object. - - Args: - remaining_content_len: Optional maximum number of bytes to read. - If None, READ_SIZE will be used as the default chunk size. - - Returns: - A chunk of bytes read from the file object and encoded using the payload's - encoding. The data is automatically converted from text to bytes. - - This method is used for subsequent reads during streaming after - the initial _read_and_available_len call has been made. It properly - handles text encoding, converting the text content to bytes using - the specified encoding (or UTF-8 if none was provided). - - """ - chunk = self._value.read(remaining_content_len or READ_SIZE) - return chunk.encode(self._encoding) if self._encoding else chunk.encode() - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """ - Return string representation of the value. - - WARNING: This method does blocking I/O and should not be called in the event loop. - """ - self._set_or_restore_start_position() - return self._value.read() - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire text file content and returns it as bytes. - It encodes the text content using the specified encoding. - The file reading is performed in an executor to avoid blocking the event loop. - """ - loop = asyncio.get_running_loop() - - # Use instance encoding if available, otherwise use parameter - actual_encoding = self._encoding or encoding - - def _read_and_encode() -> bytes: - self._set_or_restore_start_position() - # TextIO read() always returns the full content - return self._value.read().encode(actual_encoding, errors) - - return await loop.run_in_executor(None, _read_and_encode) - - -class BytesIOPayload(IOBasePayload): - _value: io.BytesIO - _size: int # Always initialized in __init__ - _autoclose = True # BytesIO is in-memory, safe to auto-close - - def __init__(self, value: io.BytesIO, *args: Any, **kwargs: Any) -> None: - super().__init__(value, *args, **kwargs) - # Calculate size once during initialization - self._size = len(self._value.getbuffer()) - self._value.tell() - - @property - def size(self) -> int: - """Size of the payload in bytes. - - Returns the number of bytes in the BytesIO buffer that will be transmitted. - This is calculated once during initialization for efficiency. - """ - return self._size - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - self._set_or_restore_start_position() - return self._value.read().decode(encoding, errors) - - async def write(self, writer: AbstractStreamWriter) -> None: - return await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write BytesIO payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This implementation is specifically optimized for BytesIO objects: - - 1. Reads content in chunks to maintain memory efficiency - 2. Yields control back to the event loop periodically to prevent blocking - when dealing with large BytesIO objects - 3. Respects content_length constraints when specified - 4. Properly cleans up by closing the BytesIO object when done or on error - - The periodic yielding to the event loop is important for maintaining - responsiveness when processing large in-memory buffers. - - """ - self._set_or_restore_start_position() - loop_count = 0 - remaining_bytes = content_length - while chunk := self._value.read(READ_SIZE): - if loop_count > 0: - # Avoid blocking the event loop - # if they pass a large BytesIO object - # and we are not in the first iteration - # of the loop - await asyncio.sleep(0) - if remaining_bytes is None: - await writer.write(chunk) - else: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - if remaining_bytes <= 0: - return - loop_count += 1 - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire BytesIO content and returns it as bytes. - It is equivalent to accessing the _value attribute directly. - """ - self._set_or_restore_start_position() - return self._value.read() - - async def close(self) -> None: - """ - Close the BytesIO payload. - - This does nothing since BytesIO is in-memory and does not require explicit closing. - """ - - -class BufferedReaderPayload(IOBasePayload): - _value: io.BufferedIOBase - # _autoclose = False (inherited) - Has buffered file handle that needs explicit closing - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - self._set_or_restore_start_position() - return self._value.read().decode(encoding, errors) - - -class JsonPayload(BytesPayload): - def __init__( - self, - value: Any, - encoding: str = "utf-8", - content_type: str = "application/json", - dumps: JSONEncoder = json.dumps, - *args: Any, - **kwargs: Any, - ) -> None: - - super().__init__( - dumps(value).encode(encoding), - content_type=content_type, - encoding=encoding, - *args, - **kwargs, - ) - - -if TYPE_CHECKING: - from typing import AsyncIterable, AsyncIterator - - _AsyncIterator = AsyncIterator[bytes] - _AsyncIterable = AsyncIterable[bytes] -else: - from collections.abc import AsyncIterable, AsyncIterator - - _AsyncIterator = AsyncIterator - _AsyncIterable = AsyncIterable - - -class AsyncIterablePayload(Payload): - - _iter: Optional[_AsyncIterator] = None - _value: _AsyncIterable - _cached_chunks: Optional[List[bytes]] = None - # _consumed stays False to allow reuse with cached content - _autoclose = True # Iterator doesn't need explicit closing - - def __init__(self, value: _AsyncIterable, *args: Any, **kwargs: Any) -> None: - if not isinstance(value, AsyncIterable): - raise TypeError( - "value argument must support " - "collections.abc.AsyncIterable interface, " - "got {!r}".format(type(value)) - ) - - if "content_type" not in kwargs: - kwargs["content_type"] = "application/octet-stream" - - super().__init__(value, *args, **kwargs) - - self._iter = value.__aiter__() - - async def write(self, writer: AbstractStreamWriter) -> None: - """ - Write the entire async iterable payload to the writer stream. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - - This method iterates through the async iterable and writes each chunk - to the writer without any length constraint. - - Note: - For new implementations that need length control, use write_with_length() directly. - This method is maintained for backwards compatibility with existing code. - - """ - await self.write_with_length(writer, None) - - async def write_with_length( - self, writer: AbstractStreamWriter, content_length: Optional[int] - ) -> None: - """ - Write async iterable payload with a specific content length constraint. - - Args: - writer: An AbstractStreamWriter instance that handles the actual writing - content_length: Maximum number of bytes to write (None for unlimited) - - This implementation handles streaming of async iterable content with length constraints: - - 1. If cached chunks are available, writes from them - 2. Otherwise iterates through the async iterable one chunk at a time - 3. Respects content_length constraints when specified - 4. Does NOT generate cache - that's done by as_bytes() - - """ - # If we have cached chunks, use them - if self._cached_chunks is not None: - remaining_bytes = content_length - for chunk in self._cached_chunks: - if remaining_bytes is None: - await writer.write(chunk) - elif remaining_bytes > 0: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - else: - break - return - - # If iterator is exhausted and we don't have cached chunks, nothing to write - if self._iter is None: - return - - # Stream from the iterator - remaining_bytes = content_length - - try: - while True: - if sys.version_info >= (3, 10): - chunk = await anext(self._iter) - else: - chunk = await self._iter.__anext__() - if remaining_bytes is None: - await writer.write(chunk) - # If we have a content length limit - elif remaining_bytes > 0: - await writer.write(chunk[:remaining_bytes]) - remaining_bytes -= len(chunk) - # We still want to exhaust the iterator even - # if we have reached the content length limit - # since the file handle may not get closed by - # the iterator if we don't do this - except StopAsyncIteration: - # Iterator is exhausted - self._iter = None - self._consumed = True # Mark as consumed when streamed without caching - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - """Decode the payload content as a string if cached chunks are available.""" - if self._cached_chunks is not None: - return b"".join(self._cached_chunks).decode(encoding, errors) - raise TypeError("Unable to decode - content not cached. Call as_bytes() first.") - - async def as_bytes(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: - """ - Return bytes representation of the value. - - This method reads the entire async iterable content and returns it as bytes. - It generates and caches the chunks for future reuse. - """ - # If we have cached chunks, return them joined - if self._cached_chunks is not None: - return b"".join(self._cached_chunks) - - # If iterator is exhausted and no cache, return empty - if self._iter is None: - return b"" - - # Read all chunks and cache them - chunks: List[bytes] = [] - async for chunk in self._iter: - chunks.append(chunk) - - # Iterator is exhausted, cache the chunks - self._iter = None - self._cached_chunks = chunks - # Keep _consumed as False to allow reuse with cached chunks - - return b"".join(chunks) - - -class StreamReaderPayload(AsyncIterablePayload): - def __init__(self, value: StreamReader, *args: Any, **kwargs: Any) -> None: - super().__init__(value.iter_any(), *args, **kwargs) - - -PAYLOAD_REGISTRY = PayloadRegistry() -PAYLOAD_REGISTRY.register(BytesPayload, (bytes, bytearray, memoryview)) -PAYLOAD_REGISTRY.register(StringPayload, str) -PAYLOAD_REGISTRY.register(StringIOPayload, io.StringIO) -PAYLOAD_REGISTRY.register(TextIOPayload, io.TextIOBase) -PAYLOAD_REGISTRY.register(BytesIOPayload, io.BytesIO) -PAYLOAD_REGISTRY.register(BufferedReaderPayload, (io.BufferedReader, io.BufferedRandom)) -PAYLOAD_REGISTRY.register(IOBasePayload, io.IOBase) -PAYLOAD_REGISTRY.register(StreamReaderPayload, StreamReader) -# try_last for giving a chance to more specialized async interables like -# multipart.BodyPartReaderPayload override the default -PAYLOAD_REGISTRY.register(AsyncIterablePayload, AsyncIterable, order=Order.try_last) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/payload_streamer.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/payload_streamer.py deleted file mode 100644 index 831fdc0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/payload_streamer.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Payload implementation for coroutines as data provider. - -As a simple case, you can upload data from file:: - - @aiohttp.streamer - async def file_sender(writer, file_name=None): - with open(file_name, 'rb') as f: - chunk = f.read(2**16) - while chunk: - await writer.write(chunk) - - chunk = f.read(2**16) - -Then you can use `file_sender` like this: - - async with session.post('http://httpbin.org/post', - data=file_sender(file_name='huge_file')) as resp: - print(await resp.text()) - -..note:: Coroutine must accept `writer` as first argument - -""" - -import types -import warnings -from typing import Any, Awaitable, Callable, Dict, Tuple - -from .abc import AbstractStreamWriter -from .payload import Payload, payload_type - -__all__ = ("streamer",) - - -class _stream_wrapper: - def __init__( - self, - coro: Callable[..., Awaitable[None]], - args: Tuple[Any, ...], - kwargs: Dict[str, Any], - ) -> None: - self.coro = types.coroutine(coro) - self.args = args - self.kwargs = kwargs - - async def __call__(self, writer: AbstractStreamWriter) -> None: - await self.coro(writer, *self.args, **self.kwargs) - - -class streamer: - def __init__(self, coro: Callable[..., Awaitable[None]]) -> None: - warnings.warn( - "@streamer is deprecated, use async generators instead", - DeprecationWarning, - stacklevel=2, - ) - self.coro = coro - - def __call__(self, *args: Any, **kwargs: Any) -> _stream_wrapper: - return _stream_wrapper(self.coro, args, kwargs) - - -@payload_type(_stream_wrapper) -class StreamWrapperPayload(Payload): - async def write(self, writer: AbstractStreamWriter) -> None: - await self._value(writer) - - def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: - raise TypeError("Unable to decode.") - - -@payload_type(streamer) -class StreamPayload(StreamWrapperPayload): - def __init__(self, value: Any, *args: Any, **kwargs: Any) -> None: - super().__init__(value(), *args, **kwargs) - - async def write(self, writer: AbstractStreamWriter) -> None: - await self._value(writer) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/py.typed b/backend/venv39/lib/python3.9/site-packages/aiohttp/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/pytest_plugin.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/pytest_plugin.py deleted file mode 100644 index 7d59fe8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/pytest_plugin.py +++ /dev/null @@ -1,444 +0,0 @@ -import asyncio -import contextlib -import inspect -import warnings -from typing import ( - Any, - Awaitable, - Callable, - Dict, - Iterator, - Optional, - Protocol, - Union, - overload, -) - -import pytest - -from .test_utils import ( - BaseTestServer, - RawTestServer, - TestClient, - TestServer, - loop_context, - setup_test_loop, - teardown_test_loop, - unused_port as _unused_port, -) -from .web import Application, BaseRequest, Request -from .web_protocol import _RequestHandler - -try: - import uvloop -except ImportError: # pragma: no cover - uvloop = None # type: ignore[assignment] - - -class AiohttpClient(Protocol): - @overload - async def __call__( - self, - __param: Application, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Request, Application]: ... - @overload - async def __call__( - self, - __param: BaseTestServer, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[BaseRequest, None]: ... - - -class AiohttpServer(Protocol): - def __call__( - self, app: Application, *, port: Optional[int] = None, **kwargs: Any - ) -> Awaitable[TestServer]: ... - - -class AiohttpRawServer(Protocol): - def __call__( - self, handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any - ) -> Awaitable[RawTestServer]: ... - - -def pytest_addoption(parser): # type: ignore[no-untyped-def] - parser.addoption( - "--aiohttp-fast", - action="store_true", - default=False, - help="run tests faster by disabling extra checks", - ) - parser.addoption( - "--aiohttp-loop", - action="store", - default="pyloop", - help="run tests with specific loop: pyloop, uvloop or all", - ) - parser.addoption( - "--aiohttp-enable-loop-debug", - action="store_true", - default=False, - help="enable event loop debug mode", - ) - - -def pytest_fixture_setup(fixturedef): # type: ignore[no-untyped-def] - """Set up pytest fixture. - - Allow fixtures to be coroutines. Run coroutine fixtures in an event loop. - """ - func = fixturedef.func - - if inspect.isasyncgenfunction(func): - # async generator fixture - is_async_gen = True - elif inspect.iscoroutinefunction(func): - # regular async fixture - is_async_gen = False - else: - # not an async fixture, nothing to do - return - - strip_request = False - if "request" not in fixturedef.argnames: - fixturedef.argnames += ("request",) - strip_request = True - - def wrapper(*args, **kwargs): # type: ignore[no-untyped-def] - request = kwargs["request"] - if strip_request: - del kwargs["request"] - - # if neither the fixture nor the test use the 'loop' fixture, - # 'getfixturevalue' will fail because the test is not parameterized - # (this can be removed someday if 'loop' is no longer parameterized) - if "loop" not in request.fixturenames: - raise Exception( - "Asynchronous fixtures must depend on the 'loop' fixture or " - "be used in tests depending from it." - ) - - _loop = request.getfixturevalue("loop") - - if is_async_gen: - # for async generators, we need to advance the generator once, - # then advance it again in a finalizer - gen = func(*args, **kwargs) - - def finalizer(): # type: ignore[no-untyped-def] - try: - return _loop.run_until_complete(gen.__anext__()) - except StopAsyncIteration: - pass - - request.addfinalizer(finalizer) - return _loop.run_until_complete(gen.__anext__()) - else: - return _loop.run_until_complete(func(*args, **kwargs)) - - fixturedef.func = wrapper - - -@pytest.fixture -def fast(request): # type: ignore[no-untyped-def] - """--fast config option""" - return request.config.getoption("--aiohttp-fast") - - -@pytest.fixture -def loop_debug(request): # type: ignore[no-untyped-def] - """--enable-loop-debug config option""" - return request.config.getoption("--aiohttp-enable-loop-debug") - - -@contextlib.contextmanager -def _runtime_warning_context(): # type: ignore[no-untyped-def] - """Context manager which checks for RuntimeWarnings. - - This exists specifically to - avoid "coroutine 'X' was never awaited" warnings being missed. - - If RuntimeWarnings occur in the context a RuntimeError is raised. - """ - with warnings.catch_warnings(record=True) as _warnings: - yield - rw = [ - "{w.filename}:{w.lineno}:{w.message}".format(w=w) - for w in _warnings - if w.category == RuntimeWarning - ] - if rw: - raise RuntimeError( - "{} Runtime Warning{},\n{}".format( - len(rw), "" if len(rw) == 1 else "s", "\n".join(rw) - ) - ) - - -@contextlib.contextmanager -def _passthrough_loop_context(loop, fast=False): # type: ignore[no-untyped-def] - """Passthrough loop context. - - Sets up and tears down a loop unless one is passed in via the loop - argument when it's passed straight through. - """ - if loop: - # loop already exists, pass it straight through - yield loop - else: - # this shadows loop_context's standard behavior - loop = setup_test_loop() - yield loop - teardown_test_loop(loop, fast=fast) - - -def pytest_pycollect_makeitem(collector, name, obj): # type: ignore[no-untyped-def] - """Fix pytest collecting for coroutines.""" - if collector.funcnamefilter(name) and inspect.iscoroutinefunction(obj): - return list(collector._genfunctions(name, obj)) - - -def pytest_pyfunc_call(pyfuncitem): # type: ignore[no-untyped-def] - """Run coroutines in an event loop instead of a normal function call.""" - fast = pyfuncitem.config.getoption("--aiohttp-fast") - if inspect.iscoroutinefunction(pyfuncitem.function): - existing_loop = ( - pyfuncitem.funcargs.get("proactor_loop") - or pyfuncitem.funcargs.get("selector_loop") - or pyfuncitem.funcargs.get("uvloop_loop") - or pyfuncitem.funcargs.get("loop", None) - ) - - with _runtime_warning_context(): - with _passthrough_loop_context(existing_loop, fast=fast) as _loop: - testargs = { - arg: pyfuncitem.funcargs[arg] - for arg in pyfuncitem._fixtureinfo.argnames - } - _loop.run_until_complete(pyfuncitem.obj(**testargs)) - - return True - - -def pytest_generate_tests(metafunc): # type: ignore[no-untyped-def] - if "loop_factory" not in metafunc.fixturenames: - return - - loops = metafunc.config.option.aiohttp_loop - avail_factories: dict[str, Callable[[], asyncio.AbstractEventLoop]] - avail_factories = {"pyloop": asyncio.new_event_loop} - - if uvloop is not None: # pragma: no cover - avail_factories["uvloop"] = uvloop.new_event_loop - - if loops == "all": - loops = "pyloop,uvloop?" - - factories = {} # type: ignore[var-annotated] - for name in loops.split(","): - required = not name.endswith("?") - name = name.strip(" ?") - if name not in avail_factories: # pragma: no cover - if required: - raise ValueError( - "Unknown loop '%s', available loops: %s" - % (name, list(factories.keys())) - ) - else: - continue - factories[name] = avail_factories[name] - metafunc.parametrize( - "loop_factory", list(factories.values()), ids=list(factories.keys()) - ) - - -@pytest.fixture -def loop( - loop_factory: Callable[[], asyncio.AbstractEventLoop], - fast: bool, - loop_debug: bool, -) -> Iterator[asyncio.AbstractEventLoop]: - """Return an instance of the event loop.""" - with loop_context(loop_factory, fast=fast) as _loop: - if loop_debug: - _loop.set_debug(True) # pragma: no cover - asyncio.set_event_loop(_loop) - yield _loop - - -@pytest.fixture -def proactor_loop() -> Iterator[asyncio.AbstractEventLoop]: - factory = asyncio.ProactorEventLoop # type: ignore[attr-defined] - - with loop_context(factory) as _loop: - asyncio.set_event_loop(_loop) - yield _loop - - -@pytest.fixture -def unused_port(aiohttp_unused_port: Callable[[], int]) -> Callable[[], int]: - warnings.warn( - "Deprecated, use aiohttp_unused_port fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_unused_port - - -@pytest.fixture -def aiohttp_unused_port() -> Callable[[], int]: - """Return a port that is unused on the current host.""" - return _unused_port - - -@pytest.fixture -def aiohttp_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpServer]: - """Factory to create a TestServer instance, given an app. - - aiohttp_server(app, **kwargs) - """ - servers = [] - - async def go( - app: Application, - *, - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ) -> TestServer: - server = TestServer(app, host=host, port=port) - await server.start_server(loop=loop, **kwargs) - servers.append(server) - return server - - yield go - - async def finalize() -> None: - while servers: - await servers.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def test_server(aiohttp_server): # type: ignore[no-untyped-def] # pragma: no cover - warnings.warn( - "Deprecated, use aiohttp_server fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_server - - -@pytest.fixture -def aiohttp_raw_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpRawServer]: - """Factory to create a RawTestServer instance, given a web handler. - - aiohttp_raw_server(handler, **kwargs) - """ - servers = [] - - async def go( - handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any - ) -> RawTestServer: - server = RawTestServer(handler, port=port) - await server.start_server(loop=loop, **kwargs) - servers.append(server) - return server - - yield go - - async def finalize() -> None: - while servers: - await servers.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def raw_test_server( # type: ignore[no-untyped-def] # pragma: no cover - aiohttp_raw_server, -): - warnings.warn( - "Deprecated, use aiohttp_raw_server fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_raw_server - - -@pytest.fixture -def aiohttp_client(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpClient]: - """Factory to create a TestClient instance. - - aiohttp_client(app, **kwargs) - aiohttp_client(server, **kwargs) - aiohttp_client(raw_server, **kwargs) - """ - clients = [] - - @overload - async def go( - __param: Application, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Request, Application]: ... - - @overload - async def go( - __param: BaseTestServer, - *, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[BaseRequest, None]: ... - - async def go( - __param: Union[Application, BaseTestServer], - *args: Any, - server_kwargs: Optional[Dict[str, Any]] = None, - **kwargs: Any, - ) -> TestClient[Any, Any]: - if isinstance(__param, Callable) and not isinstance( # type: ignore[arg-type] - __param, (Application, BaseTestServer) - ): - __param = __param(loop, *args, **kwargs) - kwargs = {} - else: - assert not args, "args should be empty" - - if isinstance(__param, Application): - server_kwargs = server_kwargs or {} - server = TestServer(__param, loop=loop, **server_kwargs) - client = TestClient(server, loop=loop, **kwargs) - elif isinstance(__param, BaseTestServer): - client = TestClient(__param, loop=loop, **kwargs) - else: - raise ValueError("Unknown argument type: %r" % type(__param)) - - await client.start_server() - clients.append(client) - return client - - yield go - - async def finalize() -> None: - while clients: - await clients.pop().close() - - loop.run_until_complete(finalize()) - - -@pytest.fixture -def test_client(aiohttp_client): # type: ignore[no-untyped-def] # pragma: no cover - warnings.warn( - "Deprecated, use aiohttp_client fixture instead", - DeprecationWarning, - stacklevel=2, - ) - return aiohttp_client diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/resolver.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/resolver.py deleted file mode 100644 index b20e567..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/resolver.py +++ /dev/null @@ -1,274 +0,0 @@ -import asyncio -import socket -import weakref -from typing import Any, Dict, Final, List, Optional, Tuple, Type, Union - -from .abc import AbstractResolver, ResolveResult - -__all__ = ("ThreadedResolver", "AsyncResolver", "DefaultResolver") - - -try: - import aiodns - - aiodns_default = hasattr(aiodns.DNSResolver, "getaddrinfo") -except ImportError: # pragma: no cover - aiodns = None # type: ignore[assignment] - aiodns_default = False - - -_NUMERIC_SOCKET_FLAGS = socket.AI_NUMERICHOST | socket.AI_NUMERICSERV -_NAME_SOCKET_FLAGS = socket.NI_NUMERICHOST | socket.NI_NUMERICSERV -_AI_ADDRCONFIG = socket.AI_ADDRCONFIG -if hasattr(socket, "AI_MASK"): - _AI_ADDRCONFIG &= socket.AI_MASK - - -class ThreadedResolver(AbstractResolver): - """Threaded resolver. - - Uses an Executor for synchronous getaddrinfo() calls. - concurrent.futures.ThreadPoolExecutor is used by default. - """ - - def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: - self._loop = loop or asyncio.get_running_loop() - - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - infos = await self._loop.getaddrinfo( - host, - port, - type=socket.SOCK_STREAM, - family=family, - flags=_AI_ADDRCONFIG, - ) - - hosts: List[ResolveResult] = [] - for family, _, proto, _, address in infos: - if family == socket.AF_INET6: - if len(address) < 3: - # IPv6 is not supported by Python build, - # or IPv6 is not enabled in the host - continue - if address[3]: - # This is essential for link-local IPv6 addresses. - # LL IPv6 is a VERY rare case. Strictly speaking, we should use - # getnameinfo() unconditionally, but performance makes sense. - resolved_host, _port = await self._loop.getnameinfo( - address, _NAME_SOCKET_FLAGS - ) - port = int(_port) - else: - resolved_host, port = address[:2] - else: # IPv4 - assert family == socket.AF_INET - resolved_host, port = address # type: ignore[misc] - hosts.append( - ResolveResult( - hostname=host, - host=resolved_host, - port=port, - family=family, - proto=proto, - flags=_NUMERIC_SOCKET_FLAGS, - ) - ) - - return hosts - - async def close(self) -> None: - pass - - -class AsyncResolver(AbstractResolver): - """Use the `aiodns` package to make asynchronous DNS lookups""" - - def __init__( - self, - loop: Optional[asyncio.AbstractEventLoop] = None, - *args: Any, - **kwargs: Any, - ) -> None: - if aiodns is None: - raise RuntimeError("Resolver requires aiodns library") - - self._loop = loop or asyncio.get_running_loop() - self._manager: Optional[_DNSResolverManager] = None - # If custom args are provided, create a dedicated resolver instance - # This means each AsyncResolver with custom args gets its own - # aiodns.DNSResolver instance - if args or kwargs: - self._resolver = aiodns.DNSResolver(*args, **kwargs) - return - # Use the shared resolver from the manager for default arguments - self._manager = _DNSResolverManager() - self._resolver = self._manager.get_resolver(self, self._loop) - - if not hasattr(self._resolver, "gethostbyname"): - # aiodns 1.1 is not available, fallback to DNSResolver.query - self.resolve = self._resolve_with_query # type: ignore - - async def resolve( - self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET - ) -> List[ResolveResult]: - try: - resp = await self._resolver.getaddrinfo( - host, - port=port, - type=socket.SOCK_STREAM, - family=family, - flags=_AI_ADDRCONFIG, - ) - except aiodns.error.DNSError as exc: - msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(None, msg) from exc - hosts: List[ResolveResult] = [] - for node in resp.nodes: - address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr - family = node.family - if family == socket.AF_INET6: - if len(address) > 3 and address[3]: - # This is essential for link-local IPv6 addresses. - # LL IPv6 is a VERY rare case. Strictly speaking, we should use - # getnameinfo() unconditionally, but performance makes sense. - result = await self._resolver.getnameinfo( - (address[0].decode("ascii"), *address[1:]), - _NAME_SOCKET_FLAGS, - ) - resolved_host = result.node - else: - resolved_host = address[0].decode("ascii") - port = address[1] - else: # IPv4 - assert family == socket.AF_INET - resolved_host = address[0].decode("ascii") - port = address[1] - hosts.append( - ResolveResult( - hostname=host, - host=resolved_host, - port=port, - family=family, - proto=0, - flags=_NUMERIC_SOCKET_FLAGS, - ) - ) - - if not hosts: - raise OSError(None, "DNS lookup failed") - - return hosts - - async def _resolve_with_query( - self, host: str, port: int = 0, family: int = socket.AF_INET - ) -> List[Dict[str, Any]]: - qtype: Final = "AAAA" if family == socket.AF_INET6 else "A" - - try: - resp = await self._resolver.query(host, qtype) - except aiodns.error.DNSError as exc: - msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(None, msg) from exc - - hosts = [] - for rr in resp: - hosts.append( - { - "hostname": host, - "host": rr.host, - "port": port, - "family": family, - "proto": 0, - "flags": socket.AI_NUMERICHOST, - } - ) - - if not hosts: - raise OSError(None, "DNS lookup failed") - - return hosts - - async def close(self) -> None: - if self._manager: - # Release the resolver from the manager if using the shared resolver - self._manager.release_resolver(self, self._loop) - self._manager = None # Clear reference to manager - self._resolver = None # type: ignore[assignment] # Clear reference to resolver - return - # Otherwise cancel our dedicated resolver - if self._resolver is not None: - self._resolver.cancel() - self._resolver = None # type: ignore[assignment] # Clear reference - - -class _DNSResolverManager: - """Manager for aiodns.DNSResolver objects. - - This class manages shared aiodns.DNSResolver instances - with no custom arguments across different event loops. - """ - - _instance: Optional["_DNSResolverManager"] = None - - def __new__(cls) -> "_DNSResolverManager": - if cls._instance is None: - cls._instance = super().__new__(cls) - cls._instance._init() - return cls._instance - - def _init(self) -> None: - # Use WeakKeyDictionary to allow event loops to be garbage collected - self._loop_data: weakref.WeakKeyDictionary[ - asyncio.AbstractEventLoop, - tuple["aiodns.DNSResolver", weakref.WeakSet["AsyncResolver"]], - ] = weakref.WeakKeyDictionary() - - def get_resolver( - self, client: "AsyncResolver", loop: asyncio.AbstractEventLoop - ) -> "aiodns.DNSResolver": - """Get or create the shared aiodns.DNSResolver instance for a specific event loop. - - Args: - client: The AsyncResolver instance requesting the resolver. - This is required to track resolver usage. - loop: The event loop to use for the resolver. - """ - # Create a new resolver and client set for this loop if it doesn't exist - if loop not in self._loop_data: - resolver = aiodns.DNSResolver(loop=loop) - client_set: weakref.WeakSet["AsyncResolver"] = weakref.WeakSet() - self._loop_data[loop] = (resolver, client_set) - else: - # Get the existing resolver and client set - resolver, client_set = self._loop_data[loop] - - # Register this client with the loop - client_set.add(client) - return resolver - - def release_resolver( - self, client: "AsyncResolver", loop: asyncio.AbstractEventLoop - ) -> None: - """Release the resolver for an AsyncResolver client when it's closed. - - Args: - client: The AsyncResolver instance to release. - loop: The event loop the resolver was using. - """ - # Remove client from its loop's tracking - current_loop_data = self._loop_data.get(loop) - if current_loop_data is None: - return - resolver, client_set = current_loop_data - client_set.discard(client) - # If no more clients for this loop, cancel and remove its resolver - if not client_set: - if resolver is not None: - resolver.cancel() - del self._loop_data[loop] - - -_DefaultType = Type[Union[AsyncResolver, ThreadedResolver]] -DefaultResolver: _DefaultType = AsyncResolver if aiodns_default else ThreadedResolver diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/streams.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/streams.py deleted file mode 100644 index 6cc74fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/streams.py +++ /dev/null @@ -1,758 +0,0 @@ -import asyncio -import collections -import warnings -from typing import ( - Awaitable, - Callable, - Deque, - Final, - Generic, - List, - Optional, - Tuple, - TypeVar, -) - -from .base_protocol import BaseProtocol -from .helpers import ( - _EXC_SENTINEL, - BaseTimerContext, - TimerNoop, - set_exception, - set_result, -) -from .log import internal_logger - -__all__ = ( - "EMPTY_PAYLOAD", - "EofStream", - "StreamReader", - "DataQueue", -) - -_T = TypeVar("_T") - - -class EofStream(Exception): - """eof stream indication.""" - - -class AsyncStreamIterator(Generic[_T]): - - __slots__ = ("read_func",) - - def __init__(self, read_func: Callable[[], Awaitable[_T]]) -> None: - self.read_func = read_func - - def __aiter__(self) -> "AsyncStreamIterator[_T]": - return self - - async def __anext__(self) -> _T: - try: - rv = await self.read_func() - except EofStream: - raise StopAsyncIteration - if rv == b"": - raise StopAsyncIteration - return rv - - -class ChunkTupleAsyncStreamIterator: - - __slots__ = ("_stream",) - - def __init__(self, stream: "StreamReader") -> None: - self._stream = stream - - def __aiter__(self) -> "ChunkTupleAsyncStreamIterator": - return self - - async def __anext__(self) -> Tuple[bytes, bool]: - rv = await self._stream.readchunk() - if rv == (b"", False): - raise StopAsyncIteration - return rv - - -class AsyncStreamReaderMixin: - - __slots__ = () - - def __aiter__(self) -> AsyncStreamIterator[bytes]: - return AsyncStreamIterator(self.readline) # type: ignore[attr-defined] - - def iter_chunked(self, n: int) -> AsyncStreamIterator[bytes]: - """Returns an asynchronous iterator that yields chunks of size n.""" - return AsyncStreamIterator(lambda: self.read(n)) # type: ignore[attr-defined] - - def iter_any(self) -> AsyncStreamIterator[bytes]: - """Yield all available data as soon as it is received.""" - return AsyncStreamIterator(self.readany) # type: ignore[attr-defined] - - def iter_chunks(self) -> ChunkTupleAsyncStreamIterator: - """Yield chunks of data as they are received by the server. - - The yielded objects are tuples - of (bytes, bool) as returned by the StreamReader.readchunk method. - """ - return ChunkTupleAsyncStreamIterator(self) # type: ignore[arg-type] - - -class StreamReader(AsyncStreamReaderMixin): - """An enhancement of asyncio.StreamReader. - - Supports asynchronous iteration by line, chunk or as available:: - - async for line in reader: - ... - async for chunk in reader.iter_chunked(1024): - ... - async for slice in reader.iter_any(): - ... - - """ - - __slots__ = ( - "_protocol", - "_low_water", - "_high_water", - "_low_water_chunks", - "_high_water_chunks", - "_loop", - "_size", - "_cursor", - "_http_chunk_splits", - "_buffer", - "_buffer_offset", - "_eof", - "_waiter", - "_eof_waiter", - "_exception", - "_timer", - "_eof_callbacks", - "_eof_counter", - "total_bytes", - "total_compressed_bytes", - ) - - def __init__( - self, - protocol: BaseProtocol, - limit: int, - *, - timer: Optional[BaseTimerContext] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - ) -> None: - self._protocol = protocol - self._low_water = limit - self._high_water = limit * 2 - if loop is None: - loop = asyncio.get_event_loop() - # Ensure high_water_chunks >= 3 so it's always > low_water_chunks. - self._high_water_chunks = max(3, limit // 4) - # Use max(2, ...) because there's always at least 1 chunk split remaining - # (the current position), so we need low_water >= 2 to allow resume. - self._low_water_chunks = max(2, self._high_water_chunks // 2) - self._loop = loop - self._size = 0 - self._cursor = 0 - self._http_chunk_splits: Optional[Deque[int]] = None - self._buffer: Deque[bytes] = collections.deque() - self._buffer_offset = 0 - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._eof_waiter: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._timer = TimerNoop() if timer is None else timer - self._eof_callbacks: List[Callable[[], None]] = [] - self._eof_counter = 0 - self.total_bytes = 0 - self.total_compressed_bytes: Optional[int] = None - - def __repr__(self) -> str: - info = [self.__class__.__name__] - if self._size: - info.append("%d bytes" % self._size) - if self._eof: - info.append("eof") - if self._low_water != 2**16: # default limit - info.append("low=%d high=%d" % (self._low_water, self._high_water)) - if self._waiter: - info.append("w=%r" % self._waiter) - if self._exception: - info.append("e=%r" % self._exception) - return "<%s>" % " ".join(info) - - def get_read_buffer_limits(self) -> Tuple[int, int]: - return (self._low_water, self._high_water) - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._exception = exc - self._eof_callbacks.clear() - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - waiter = self._eof_waiter - if waiter is not None: - self._eof_waiter = None - set_exception(waiter, exc, exc_cause) - - def on_eof(self, callback: Callable[[], None]) -> None: - if self._eof: - try: - callback() - except Exception: - internal_logger.exception("Exception in eof callback") - else: - self._eof_callbacks.append(callback) - - def feed_eof(self) -> None: - self._eof = True - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - waiter = self._eof_waiter - if waiter is not None: - self._eof_waiter = None - set_result(waiter, None) - - if self._protocol._reading_paused: - self._protocol.resume_reading() - - for cb in self._eof_callbacks: - try: - cb() - except Exception: - internal_logger.exception("Exception in eof callback") - - self._eof_callbacks.clear() - - def is_eof(self) -> bool: - """Return True if 'feed_eof' was called.""" - return self._eof - - def at_eof(self) -> bool: - """Return True if the buffer is empty and 'feed_eof' was called.""" - return self._eof and not self._buffer - - async def wait_eof(self) -> None: - if self._eof: - return - - assert self._eof_waiter is None - self._eof_waiter = self._loop.create_future() - try: - await self._eof_waiter - finally: - self._eof_waiter = None - - @property - def total_raw_bytes(self) -> int: - if self.total_compressed_bytes is None: - return self.total_bytes - return self.total_compressed_bytes - - def unread_data(self, data: bytes) -> None: - """rollback reading some data from stream, inserting it to buffer head.""" - warnings.warn( - "unread_data() is deprecated " - "and will be removed in future releases (#3260)", - DeprecationWarning, - stacklevel=2, - ) - if not data: - return - - if self._buffer_offset: - self._buffer[0] = self._buffer[0][self._buffer_offset :] - self._buffer_offset = 0 - self._size += len(data) - self._cursor -= len(data) - self._buffer.appendleft(data) - self._eof_counter = 0 - - # TODO: size is ignored, remove the param later - def feed_data(self, data: bytes, size: int = 0) -> None: - assert not self._eof, "feed_data after feed_eof" - - if not data: - return - - data_len = len(data) - self._size += data_len - self._buffer.append(data) - self.total_bytes += data_len - - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - if self._size > self._high_water and not self._protocol._reading_paused: - self._protocol.pause_reading() - - def begin_http_chunk_receiving(self) -> None: - if self._http_chunk_splits is None: - if self.total_bytes: - raise RuntimeError( - "Called begin_http_chunk_receiving when some data was already fed" - ) - self._http_chunk_splits = collections.deque() - - def end_http_chunk_receiving(self) -> None: - if self._http_chunk_splits is None: - raise RuntimeError( - "Called end_chunk_receiving without calling " - "begin_chunk_receiving first" - ) - - # self._http_chunk_splits contains logical byte offsets from start of - # the body transfer. Each offset is the offset of the end of a chunk. - # "Logical" means bytes, accessible for a user. - # If no chunks containing logical data were received, current position - # is difinitely zero. - pos = self._http_chunk_splits[-1] if self._http_chunk_splits else 0 - - if self.total_bytes == pos: - # We should not add empty chunks here. So we check for that. - # Note, when chunked + gzip is used, we can receive a chunk - # of compressed data, but that data may not be enough for gzip FSM - # to yield any uncompressed data. That's why current position may - # not change after receiving a chunk. - return - - self._http_chunk_splits.append(self.total_bytes) - - # If we get too many small chunks before self._high_water is reached, then any - # .read() call becomes computationally expensive, and could block the event loop - # for too long, hence an additional self._high_water_chunks here. - if ( - len(self._http_chunk_splits) > self._high_water_chunks - and not self._protocol._reading_paused - ): - self._protocol.pause_reading() - - # wake up readchunk when end of http chunk received - waiter = self._waiter - if waiter is not None: - self._waiter = None - set_result(waiter, None) - - async def _wait(self, func_name: str) -> None: - if not self._protocol.connected: - raise RuntimeError("Connection closed.") - - # StreamReader uses a future to link the protocol feed_data() method - # to a read coroutine. Running two read coroutines at the same time - # would have an unexpected behaviour. It would not possible to know - # which coroutine would get the next data. - if self._waiter is not None: - raise RuntimeError( - "%s() called while another coroutine is " - "already waiting for incoming data" % func_name - ) - - waiter = self._waiter = self._loop.create_future() - try: - with self._timer: - await waiter - finally: - self._waiter = None - - async def readline(self) -> bytes: - return await self.readuntil() - - async def readuntil(self, separator: bytes = b"\n") -> bytes: - seplen = len(separator) - if seplen == 0: - raise ValueError("Separator should be at least one-byte string") - - if self._exception is not None: - raise self._exception - - chunk = b"" - chunk_size = 0 - not_enough = True - - while not_enough: - while self._buffer and not_enough: - offset = self._buffer_offset - ichar = self._buffer[0].find(separator, offset) + 1 - # Read from current offset to found separator or to the end. - data = self._read_nowait_chunk( - ichar - offset + seplen - 1 if ichar else -1 - ) - chunk += data - chunk_size += len(data) - if ichar: - not_enough = False - - if chunk_size > self._high_water: - raise ValueError("Chunk too big") - - if self._eof: - break - - if not_enough: - await self._wait("readuntil") - - return chunk - - async def read(self, n: int = -1) -> bytes: - if self._exception is not None: - raise self._exception - - # migration problem; with DataQueue you have to catch - # EofStream exception, so common way is to run payload.read() inside - # infinite loop. what can cause real infinite loop with StreamReader - # lets keep this code one major release. - if __debug__: - if self._eof and not self._buffer: - self._eof_counter = getattr(self, "_eof_counter", 0) + 1 - if self._eof_counter > 5: - internal_logger.warning( - "Multiple access to StreamReader in eof state, " - "might be infinite loop.", - stack_info=True, - ) - - if not n: - return b"" - - if n < 0: - # This used to just loop creating a new waiter hoping to - # collect everything in self._buffer, but that would - # deadlock if the subprocess sends more than self.limit - # bytes. So just call self.readany() until EOF. - blocks = [] - while True: - block = await self.readany() - if not block: - break - blocks.append(block) - return b"".join(blocks) - - # TODO: should be `if` instead of `while` - # because waiter maybe triggered on chunk end, - # without feeding any data - while not self._buffer and not self._eof: - await self._wait("read") - - return self._read_nowait(n) - - async def readany(self) -> bytes: - if self._exception is not None: - raise self._exception - - # TODO: should be `if` instead of `while` - # because waiter maybe triggered on chunk end, - # without feeding any data - while not self._buffer and not self._eof: - await self._wait("readany") - - return self._read_nowait(-1) - - async def readchunk(self) -> Tuple[bytes, bool]: - """Returns a tuple of (data, end_of_http_chunk). - - When chunked transfer - encoding is used, end_of_http_chunk is a boolean indicating if the end - of the data corresponds to the end of a HTTP chunk , otherwise it is - always False. - """ - while True: - if self._exception is not None: - raise self._exception - - while self._http_chunk_splits: - pos = self._http_chunk_splits.popleft() - if pos == self._cursor: - return (b"", True) - if pos > self._cursor: - return (self._read_nowait(pos - self._cursor), True) - internal_logger.warning( - "Skipping HTTP chunk end due to data " - "consumption beyond chunk boundary" - ) - - if self._buffer: - return (self._read_nowait_chunk(-1), False) - # return (self._read_nowait(-1), False) - - if self._eof: - # Special case for signifying EOF. - # (b'', True) is not a final return value actually. - return (b"", False) - - await self._wait("readchunk") - - async def readexactly(self, n: int) -> bytes: - if self._exception is not None: - raise self._exception - - blocks: List[bytes] = [] - while n > 0: - block = await self.read(n) - if not block: - partial = b"".join(blocks) - raise asyncio.IncompleteReadError(partial, len(partial) + n) - blocks.append(block) - n -= len(block) - - return b"".join(blocks) - - def read_nowait(self, n: int = -1) -> bytes: - # default was changed to be consistent with .read(-1) - # - # I believe the most users don't know about the method and - # they are not affected. - if self._exception is not None: - raise self._exception - - if self._waiter and not self._waiter.done(): - raise RuntimeError( - "Called while some coroutine is waiting for incoming data." - ) - - return self._read_nowait(n) - - def _read_nowait_chunk(self, n: int) -> bytes: - first_buffer = self._buffer[0] - offset = self._buffer_offset - if n != -1 and len(first_buffer) - offset > n: - data = first_buffer[offset : offset + n] - self._buffer_offset += n - - elif offset: - self._buffer.popleft() - data = first_buffer[offset:] - self._buffer_offset = 0 - - else: - data = self._buffer.popleft() - - data_len = len(data) - self._size -= data_len - self._cursor += data_len - - chunk_splits = self._http_chunk_splits - # Prevent memory leak: drop useless chunk splits - while chunk_splits and chunk_splits[0] < self._cursor: - chunk_splits.popleft() - - if ( - self._protocol._reading_paused - and self._size < self._low_water - and ( - self._http_chunk_splits is None - or len(self._http_chunk_splits) < self._low_water_chunks - ) - ): - self._protocol.resume_reading() - return data - - def _read_nowait(self, n: int) -> bytes: - """Read not more than n bytes, or whole buffer if n == -1""" - self._timer.assert_timeout() - - chunks = [] - while self._buffer: - chunk = self._read_nowait_chunk(n) - chunks.append(chunk) - if n != -1: - n -= len(chunk) - if n == 0: - break - - return b"".join(chunks) if chunks else b"" - - -class EmptyStreamReader(StreamReader): # lgtm [py/missing-call-to-init] - - __slots__ = ("_read_eof_chunk",) - - def __init__(self) -> None: - self._read_eof_chunk = False - self.total_bytes = 0 - - def __repr__(self) -> str: - return "<%s>" % self.__class__.__name__ - - def exception(self) -> Optional[BaseException]: - return None - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - pass - - def on_eof(self, callback: Callable[[], None]) -> None: - try: - callback() - except Exception: - internal_logger.exception("Exception in eof callback") - - def feed_eof(self) -> None: - pass - - def is_eof(self) -> bool: - return True - - def at_eof(self) -> bool: - return True - - async def wait_eof(self) -> None: - return - - def feed_data(self, data: bytes, n: int = 0) -> None: - pass - - async def readline(self) -> bytes: - return b"" - - async def read(self, n: int = -1) -> bytes: - return b"" - - # TODO add async def readuntil - - async def readany(self) -> bytes: - return b"" - - async def readchunk(self) -> Tuple[bytes, bool]: - if not self._read_eof_chunk: - self._read_eof_chunk = True - return (b"", False) - - return (b"", True) - - async def readexactly(self, n: int) -> bytes: - raise asyncio.IncompleteReadError(b"", n) - - def read_nowait(self, n: int = -1) -> bytes: - return b"" - - -EMPTY_PAYLOAD: Final[StreamReader] = EmptyStreamReader() - - -class DataQueue(Generic[_T]): - """DataQueue is a general-purpose blocking queue with one reader.""" - - def __init__(self, loop: asyncio.AbstractEventLoop) -> None: - self._loop = loop - self._eof = False - self._waiter: Optional[asyncio.Future[None]] = None - self._exception: Optional[BaseException] = None - self._buffer: Deque[Tuple[_T, int]] = collections.deque() - - def __len__(self) -> int: - return len(self._buffer) - - def is_eof(self) -> bool: - return self._eof - - def at_eof(self) -> bool: - return self._eof and not self._buffer - - def exception(self) -> Optional[BaseException]: - return self._exception - - def set_exception( - self, - exc: BaseException, - exc_cause: BaseException = _EXC_SENTINEL, - ) -> None: - self._eof = True - self._exception = exc - if (waiter := self._waiter) is not None: - self._waiter = None - set_exception(waiter, exc, exc_cause) - - def feed_data(self, data: _T, size: int = 0) -> None: - self._buffer.append((data, size)) - if (waiter := self._waiter) is not None: - self._waiter = None - set_result(waiter, None) - - def feed_eof(self) -> None: - self._eof = True - if (waiter := self._waiter) is not None: - self._waiter = None - set_result(waiter, None) - - async def read(self) -> _T: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - if self._buffer: - data, _ = self._buffer.popleft() - return data - if self._exception is not None: - raise self._exception - raise EofStream - - def __aiter__(self) -> AsyncStreamIterator[_T]: - return AsyncStreamIterator(self.read) - - -class FlowControlDataQueue(DataQueue[_T]): - """FlowControlDataQueue resumes and pauses an underlying stream. - - It is a destination for parsed data. - - This class is deprecated and will be removed in version 4.0. - """ - - def __init__( - self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop - ) -> None: - super().__init__(loop=loop) - self._size = 0 - self._protocol = protocol - self._limit = limit * 2 - - def feed_data(self, data: _T, size: int = 0) -> None: - super().feed_data(data, size) - self._size += size - - if self._size > self._limit and not self._protocol._reading_paused: - self._protocol.pause_reading() - - async def read(self) -> _T: - if not self._buffer and not self._eof: - assert not self._waiter - self._waiter = self._loop.create_future() - try: - await self._waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._waiter = None - raise - if self._buffer: - data, size = self._buffer.popleft() - self._size -= size - if self._size < self._limit and self._protocol._reading_paused: - self._protocol.resume_reading() - return data - if self._exception is not None: - raise self._exception - raise EofStream diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/tcp_helpers.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/tcp_helpers.py deleted file mode 100644 index 88b2442..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/tcp_helpers.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Helper methods to tune a TCP connection""" - -import asyncio -import socket -from contextlib import suppress -from typing import Optional # noqa - -__all__ = ("tcp_keepalive", "tcp_nodelay") - - -if hasattr(socket, "SO_KEEPALIVE"): - - def tcp_keepalive(transport: asyncio.Transport) -> None: - sock = transport.get_extra_info("socket") - if sock is not None: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - -else: - - def tcp_keepalive(transport: asyncio.Transport) -> None: # pragma: no cover - pass - - -def tcp_nodelay(transport: asyncio.Transport, value: bool) -> None: - sock = transport.get_extra_info("socket") - - if sock is None: - return - - if sock.family not in (socket.AF_INET, socket.AF_INET6): - return - - value = bool(value) - - # socket may be closed already, on windows OSError get raised - with suppress(OSError): - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, value) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/test_utils.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/test_utils.py deleted file mode 100644 index 87c3142..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/test_utils.py +++ /dev/null @@ -1,774 +0,0 @@ -"""Utilities shared by tests.""" - -import asyncio -import contextlib -import gc -import inspect -import ipaddress -import os -import socket -import sys -import warnings -from abc import ABC, abstractmethod -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generic, - Iterator, - List, - Optional, - Type, - TypeVar, - cast, - overload, -) -from unittest import IsolatedAsyncioTestCase, mock - -from aiosignal import Signal -from multidict import CIMultiDict, CIMultiDictProxy -from yarl import URL - -import aiohttp -from aiohttp.client import ( - _RequestContextManager, - _RequestOptions, - _WSRequestContextManager, -) - -from . import ClientSession, hdrs -from .abc import AbstractCookieJar -from .client_reqrep import ClientResponse -from .client_ws import ClientWebSocketResponse -from .helpers import sentinel -from .http import HttpVersion, RawRequestMessage -from .streams import EMPTY_PAYLOAD, StreamReader -from .typedefs import StrOrURL -from .web import ( - Application, - AppRunner, - BaseRequest, - BaseRunner, - Request, - Server, - ServerRunner, - SockSite, - UrlMappingMatchInfo, -) -from .web_protocol import _RequestHandler - -if TYPE_CHECKING: - from ssl import SSLContext -else: - SSLContext = None - -if sys.version_info >= (3, 11) and TYPE_CHECKING: - from typing import Unpack - -if sys.version_info >= (3, 11): - from typing import Self -else: - Self = Any - -_ApplicationNone = TypeVar("_ApplicationNone", Application, None) -_Request = TypeVar("_Request", bound=BaseRequest) - -REUSE_ADDRESS = os.name == "posix" and sys.platform != "cygwin" - - -def get_unused_port_socket( - host: str, family: socket.AddressFamily = socket.AF_INET -) -> socket.socket: - return get_port_socket(host, 0, family) - - -def get_port_socket( - host: str, port: int, family: socket.AddressFamily -) -> socket.socket: - s = socket.socket(family, socket.SOCK_STREAM) - if REUSE_ADDRESS: - # Windows has different semantics for SO_REUSEADDR, - # so don't set it. Ref: - # https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind((host, port)) - return s - - -def unused_port() -> int: - """Return a port that is unused on the current host.""" - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("127.0.0.1", 0)) - return cast(int, s.getsockname()[1]) - - -class BaseTestServer(ABC): - __test__ = False - - def __init__( - self, - *, - scheme: str = "", - loop: Optional[asyncio.AbstractEventLoop] = None, - host: str = "127.0.0.1", - port: Optional[int] = None, - skip_url_asserts: bool = False, - socket_factory: Callable[ - [str, int, socket.AddressFamily], socket.socket - ] = get_port_socket, - **kwargs: Any, - ) -> None: - self._loop = loop - self.runner: Optional[BaseRunner] = None - self._root: Optional[URL] = None - self.host = host - self.port = port - self._closed = False - self.scheme = scheme - self.skip_url_asserts = skip_url_asserts - self.socket_factory = socket_factory - - async def start_server( - self, loop: Optional[asyncio.AbstractEventLoop] = None, **kwargs: Any - ) -> None: - if self.runner: - return - self._loop = loop - self._ssl = kwargs.pop("ssl", None) - self.runner = await self._make_runner(handler_cancellation=True, **kwargs) - await self.runner.setup() - if not self.port: - self.port = 0 - absolute_host = self.host - try: - version = ipaddress.ip_address(self.host).version - except ValueError: - version = 4 - if version == 6: - absolute_host = f"[{self.host}]" - family = socket.AF_INET6 if version == 6 else socket.AF_INET - _sock = self.socket_factory(self.host, self.port, family) - self.host, self.port = _sock.getsockname()[:2] - site = SockSite(self.runner, sock=_sock, ssl_context=self._ssl) - await site.start() - server = site._server - assert server is not None - sockets = server.sockets # type: ignore[attr-defined] - assert sockets is not None - self.port = sockets[0].getsockname()[1] - if not self.scheme: - self.scheme = "https" if self._ssl else "http" - self._root = URL(f"{self.scheme}://{absolute_host}:{self.port}") - - @abstractmethod # pragma: no cover - async def _make_runner(self, **kwargs: Any) -> BaseRunner: - pass - - def make_url(self, path: StrOrURL) -> URL: - assert self._root is not None - url = URL(path) - if not self.skip_url_asserts: - assert not url.absolute - return self._root.join(url) - else: - return URL(str(self._root) + str(path)) - - @property - def started(self) -> bool: - return self.runner is not None - - @property - def closed(self) -> bool: - return self._closed - - @property - def handler(self) -> Server: - # for backward compatibility - # web.Server instance - runner = self.runner - assert runner is not None - assert runner.server is not None - return runner.server - - async def close(self) -> None: - """Close all fixtures created by the test client. - - After that point, the TestClient is no longer usable. - - This is an idempotent function: running close multiple times - will not have any additional effects. - - close is also run when the object is garbage collected, and on - exit when used as a context manager. - - """ - if self.started and not self.closed: - assert self.runner is not None - await self.runner.cleanup() - self._root = None - self.port = None - self._closed = True - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> "BaseTestServer": - await self.start_server(loop=self._loop) - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], - ) -> None: - await self.close() - - -class TestServer(BaseTestServer): - def __init__( - self, - app: Application, - *, - scheme: str = "", - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ): - self.app = app - super().__init__(scheme=scheme, host=host, port=port, **kwargs) - - async def _make_runner(self, **kwargs: Any) -> BaseRunner: - return AppRunner(self.app, **kwargs) - - -class RawTestServer(BaseTestServer): - def __init__( - self, - handler: _RequestHandler, - *, - scheme: str = "", - host: str = "127.0.0.1", - port: Optional[int] = None, - **kwargs: Any, - ) -> None: - self._handler = handler - super().__init__(scheme=scheme, host=host, port=port, **kwargs) - - async def _make_runner(self, debug: bool = True, **kwargs: Any) -> ServerRunner: - srv = Server(self._handler, loop=self._loop, debug=debug, **kwargs) - return ServerRunner(srv, debug=debug, **kwargs) - - -class TestClient(Generic[_Request, _ApplicationNone]): - """ - A test client implementation. - - To write functional tests for aiohttp based servers. - - """ - - __test__ = False - - @overload - def __init__( - self: "TestClient[Request, Application]", - server: TestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - **kwargs: Any, - ) -> None: ... - @overload - def __init__( - self: "TestClient[_Request, None]", - server: BaseTestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - **kwargs: Any, - ) -> None: ... - def __init__( - self, - server: BaseTestServer, - *, - cookie_jar: Optional[AbstractCookieJar] = None, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> None: - if not isinstance(server, BaseTestServer): - raise TypeError( - "server must be TestServer instance, found type: %r" % type(server) - ) - self._server = server - self._loop = loop - if cookie_jar is None: - cookie_jar = aiohttp.CookieJar(unsafe=True, loop=loop) - self._session = ClientSession(loop=loop, cookie_jar=cookie_jar, **kwargs) - self._session._retry_connection = False - self._closed = False - self._responses: List[ClientResponse] = [] - self._websockets: List[ClientWebSocketResponse] = [] - - async def start_server(self) -> None: - await self._server.start_server(loop=self._loop) - - @property - def host(self) -> str: - return self._server.host - - @property - def port(self) -> Optional[int]: - return self._server.port - - @property - def server(self) -> BaseTestServer: - return self._server - - @property - def app(self) -> _ApplicationNone: - return getattr(self._server, "app", None) # type: ignore[return-value] - - @property - def session(self) -> ClientSession: - """An internal aiohttp.ClientSession. - - Unlike the methods on the TestClient, client session requests - do not automatically include the host in the url queried, and - will require an absolute path to the resource. - - """ - return self._session - - def make_url(self, path: StrOrURL) -> URL: - return self._server.make_url(path) - - async def _request( - self, method: str, path: StrOrURL, **kwargs: Any - ) -> ClientResponse: - resp = await self._session.request(method, self.make_url(path), **kwargs) - # save it to close later - self._responses.append(resp) - return resp - - if sys.version_info >= (3, 11) and TYPE_CHECKING: - - def request( - self, method: str, path: StrOrURL, **kwargs: Unpack[_RequestOptions] - ) -> _RequestContextManager: ... - - def get( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def options( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def head( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def post( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def put( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def patch( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - def delete( - self, - path: StrOrURL, - **kwargs: Unpack[_RequestOptions], - ) -> _RequestContextManager: ... - - else: - - def request( - self, method: str, path: StrOrURL, **kwargs: Any - ) -> _RequestContextManager: - """Routes a request to tested http server. - - The interface is identical to aiohttp.ClientSession.request, - except the loop kwarg is overridden by the instance used by the - test server. - - """ - return _RequestContextManager(self._request(method, path, **kwargs)) - - def get(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP GET request.""" - return _RequestContextManager(self._request(hdrs.METH_GET, path, **kwargs)) - - def post(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP POST request.""" - return _RequestContextManager(self._request(hdrs.METH_POST, path, **kwargs)) - - def options(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP OPTIONS request.""" - return _RequestContextManager( - self._request(hdrs.METH_OPTIONS, path, **kwargs) - ) - - def head(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP HEAD request.""" - return _RequestContextManager(self._request(hdrs.METH_HEAD, path, **kwargs)) - - def put(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PUT request.""" - return _RequestContextManager(self._request(hdrs.METH_PUT, path, **kwargs)) - - def patch(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_PATCH, path, **kwargs) - ) - - def delete(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: - """Perform an HTTP PATCH request.""" - return _RequestContextManager( - self._request(hdrs.METH_DELETE, path, **kwargs) - ) - - def ws_connect(self, path: StrOrURL, **kwargs: Any) -> _WSRequestContextManager: - """Initiate websocket connection. - - The api corresponds to aiohttp.ClientSession.ws_connect. - - """ - return _WSRequestContextManager(self._ws_connect(path, **kwargs)) - - async def _ws_connect( - self, path: StrOrURL, **kwargs: Any - ) -> ClientWebSocketResponse: - ws = await self._session.ws_connect(self.make_url(path), **kwargs) - self._websockets.append(ws) - return ws - - async def close(self) -> None: - """Close all fixtures created by the test client. - - After that point, the TestClient is no longer usable. - - This is an idempotent function: running close multiple times - will not have any additional effects. - - close is also run on exit when used as a(n) (asynchronous) - context manager. - - """ - if not self._closed: - for resp in self._responses: - resp.close() - for ws in self._websockets: - await ws.close() - await self._session.close() - await self._server.close() - self._closed = True - - def __enter__(self) -> None: - raise TypeError("Use async with instead") - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - # __exit__ should exist in pair with __enter__ but never executed - pass # pragma: no cover - - async def __aenter__(self) -> Self: - await self.start_server() - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - await self.close() - - -class AioHTTPTestCase(IsolatedAsyncioTestCase): - """A base class to allow for unittest web applications using aiohttp. - - Provides the following: - - * self.client (aiohttp.test_utils.TestClient): an aiohttp test client. - * self.loop (asyncio.BaseEventLoop): the event loop in which the - application and server are running. - * self.app (aiohttp.web.Application): the application returned by - self.get_application() - - Note that the TestClient's methods are asynchronous: you have to - execute function on the test client using asynchronous methods. - """ - - async def get_application(self) -> Application: - """Get application. - - This method should be overridden - to return the aiohttp.web.Application - object to test. - """ - return self.get_app() - - def get_app(self) -> Application: - """Obsolete method used to constructing web application. - - Use .get_application() coroutine instead. - """ - raise RuntimeError("Did you forget to define get_application()?") - - async def asyncSetUp(self) -> None: - self.loop = asyncio.get_running_loop() - return await self.setUpAsync() - - async def setUpAsync(self) -> None: - self.app = await self.get_application() - self.server = await self.get_server(self.app) - self.client = await self.get_client(self.server) - - await self.client.start_server() - - async def asyncTearDown(self) -> None: - return await self.tearDownAsync() - - async def tearDownAsync(self) -> None: - await self.client.close() - - async def get_server(self, app: Application) -> TestServer: - """Return a TestServer instance.""" - return TestServer(app, loop=self.loop) - - async def get_client(self, server: TestServer) -> TestClient[Request, Application]: - """Return a TestClient instance.""" - return TestClient(server, loop=self.loop) - - -def unittest_run_loop(func: Any, *args: Any, **kwargs: Any) -> Any: - """ - A decorator dedicated to use with asynchronous AioHTTPTestCase test methods. - - In 3.8+, this does nothing. - """ - warnings.warn( - "Decorator `@unittest_run_loop` is no longer needed in aiohttp 3.8+", - DeprecationWarning, - stacklevel=2, - ) - return func - - -_LOOP_FACTORY = Callable[[], asyncio.AbstractEventLoop] - - -@contextlib.contextmanager -def loop_context( - loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, fast: bool = False -) -> Iterator[asyncio.AbstractEventLoop]: - """A contextmanager that creates an event_loop, for test purposes. - - Handles the creation and cleanup of a test loop. - """ - loop = setup_test_loop(loop_factory) - yield loop - teardown_test_loop(loop, fast=fast) - - -def setup_test_loop( - loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, -) -> asyncio.AbstractEventLoop: - """Create and return an asyncio.BaseEventLoop instance. - - The caller should also call teardown_test_loop, - once they are done with the loop. - """ - loop = loop_factory() - asyncio.set_event_loop(loop) - return loop - - -def teardown_test_loop(loop: asyncio.AbstractEventLoop, fast: bool = False) -> None: - """Teardown and cleanup an event_loop created by setup_test_loop.""" - closed = loop.is_closed() - if not closed: - loop.call_soon(loop.stop) - loop.run_forever() - loop.close() - - if not fast: - gc.collect() - - asyncio.set_event_loop(None) - - -def _create_app_mock() -> mock.MagicMock: - def get_dict(app: Any, key: str) -> Any: - return app.__app_dict[key] - - def set_dict(app: Any, key: str, value: Any) -> None: - app.__app_dict[key] = value - - app = mock.MagicMock(spec=Application) - app.__app_dict = {} - app.__getitem__ = get_dict - app.__setitem__ = set_dict - - app._debug = False - app.on_response_prepare = Signal(app) - app.on_response_prepare.freeze() - return app - - -def _create_transport(sslcontext: Optional[SSLContext] = None) -> mock.Mock: - transport = mock.Mock() - - def get_extra_info(key: str) -> Optional[SSLContext]: - if key == "sslcontext": - return sslcontext - else: - return None - - transport.get_extra_info.side_effect = get_extra_info - return transport - - -def make_mocked_request( - method: str, - path: str, - headers: Any = None, - *, - match_info: Any = sentinel, - version: HttpVersion = HttpVersion(1, 1), - closing: bool = False, - app: Any = None, - writer: Any = sentinel, - protocol: Any = sentinel, - transport: Any = sentinel, - payload: StreamReader = EMPTY_PAYLOAD, - sslcontext: Optional[SSLContext] = None, - client_max_size: int = 1024**2, - loop: Any = ..., -) -> Request: - """Creates mocked web.Request testing purposes. - - Useful in unit tests, when spinning full web server is overkill or - specific conditions and errors are hard to trigger. - """ - task = mock.Mock() - if loop is ...: - # no loop passed, try to get the current one if - # its is running as we need a real loop to create - # executor jobs to be able to do testing - # with a real executor - try: - loop = asyncio.get_running_loop() - except RuntimeError: - loop = mock.Mock() - loop.create_future.return_value = () - - if version < HttpVersion(1, 1): - closing = True - - if headers: - headers = CIMultiDictProxy(CIMultiDict(headers)) - raw_hdrs = tuple( - (k.encode("utf-8"), v.encode("utf-8")) for k, v in headers.items() - ) - else: - headers = CIMultiDictProxy(CIMultiDict()) - raw_hdrs = () - - chunked = "chunked" in headers.get(hdrs.TRANSFER_ENCODING, "").lower() - - message = RawRequestMessage( - method, - path, - version, - headers, - raw_hdrs, - closing, - None, - False, - chunked, - URL(path), - ) - if app is None: - app = _create_app_mock() - - if transport is sentinel: - transport = _create_transport(sslcontext) - - if protocol is sentinel: - protocol = mock.Mock() - protocol.transport = transport - type(protocol).peername = mock.PropertyMock( - return_value=transport.get_extra_info("peername") - ) - type(protocol).ssl_context = mock.PropertyMock(return_value=sslcontext) - - if writer is sentinel: - writer = mock.Mock() - writer.write_headers = make_mocked_coro(None) - writer.write = make_mocked_coro(None) - writer.write_eof = make_mocked_coro(None) - writer.drain = make_mocked_coro(None) - writer.transport = transport - - protocol.transport = transport - protocol.writer = writer - - req = Request( - message, payload, protocol, writer, task, loop, client_max_size=client_max_size - ) - - match_info = UrlMappingMatchInfo( - {} if match_info is sentinel else match_info, mock.Mock() - ) - match_info.add_app(app) - req._match_info = match_info - - return req - - -def make_mocked_coro( - return_value: Any = sentinel, raise_exception: Any = sentinel -) -> Any: - """Creates a coroutine mock.""" - - async def mock_coro(*args: Any, **kwargs: Any) -> Any: - if raise_exception is not sentinel: - raise raise_exception - if not inspect.isawaitable(return_value): - return return_value - await return_value - - return mock.Mock(wraps=mock_coro) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/tracing.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/tracing.py deleted file mode 100644 index 568fa7f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/tracing.py +++ /dev/null @@ -1,455 +0,0 @@ -from types import SimpleNamespace -from typing import TYPE_CHECKING, Mapping, Optional, Type, TypeVar - -import attr -from aiosignal import Signal -from multidict import CIMultiDict -from yarl import URL - -from .client_reqrep import ClientResponse - -if TYPE_CHECKING: - from .client import ClientSession - - _ParamT_contra = TypeVar("_ParamT_contra", contravariant=True) - _TracingSignal = Signal[ClientSession, SimpleNamespace, _ParamT_contra] - - -__all__ = ( - "TraceConfig", - "TraceRequestStartParams", - "TraceRequestEndParams", - "TraceRequestExceptionParams", - "TraceConnectionQueuedStartParams", - "TraceConnectionQueuedEndParams", - "TraceConnectionCreateStartParams", - "TraceConnectionCreateEndParams", - "TraceConnectionReuseconnParams", - "TraceDnsResolveHostStartParams", - "TraceDnsResolveHostEndParams", - "TraceDnsCacheHitParams", - "TraceDnsCacheMissParams", - "TraceRequestRedirectParams", - "TraceRequestChunkSentParams", - "TraceResponseChunkReceivedParams", - "TraceRequestHeadersSentParams", -) - - -class TraceConfig: - """First-class used to trace requests launched via ClientSession objects.""" - - def __init__( - self, trace_config_ctx_factory: Type[SimpleNamespace] = SimpleNamespace - ) -> None: - self._on_request_start: _TracingSignal[TraceRequestStartParams] = Signal(self) - self._on_request_chunk_sent: _TracingSignal[TraceRequestChunkSentParams] = ( - Signal(self) - ) - self._on_response_chunk_received: _TracingSignal[ - TraceResponseChunkReceivedParams - ] = Signal(self) - self._on_request_end: _TracingSignal[TraceRequestEndParams] = Signal(self) - self._on_request_exception: _TracingSignal[TraceRequestExceptionParams] = ( - Signal(self) - ) - self._on_request_redirect: _TracingSignal[TraceRequestRedirectParams] = Signal( - self - ) - self._on_connection_queued_start: _TracingSignal[ - TraceConnectionQueuedStartParams - ] = Signal(self) - self._on_connection_queued_end: _TracingSignal[ - TraceConnectionQueuedEndParams - ] = Signal(self) - self._on_connection_create_start: _TracingSignal[ - TraceConnectionCreateStartParams - ] = Signal(self) - self._on_connection_create_end: _TracingSignal[ - TraceConnectionCreateEndParams - ] = Signal(self) - self._on_connection_reuseconn: _TracingSignal[ - TraceConnectionReuseconnParams - ] = Signal(self) - self._on_dns_resolvehost_start: _TracingSignal[ - TraceDnsResolveHostStartParams - ] = Signal(self) - self._on_dns_resolvehost_end: _TracingSignal[TraceDnsResolveHostEndParams] = ( - Signal(self) - ) - self._on_dns_cache_hit: _TracingSignal[TraceDnsCacheHitParams] = Signal(self) - self._on_dns_cache_miss: _TracingSignal[TraceDnsCacheMissParams] = Signal(self) - self._on_request_headers_sent: _TracingSignal[TraceRequestHeadersSentParams] = ( - Signal(self) - ) - - self._trace_config_ctx_factory = trace_config_ctx_factory - - def trace_config_ctx( - self, trace_request_ctx: Optional[Mapping[str, str]] = None - ) -> SimpleNamespace: - """Return a new trace_config_ctx instance""" - return self._trace_config_ctx_factory(trace_request_ctx=trace_request_ctx) - - def freeze(self) -> None: - self._on_request_start.freeze() - self._on_request_chunk_sent.freeze() - self._on_response_chunk_received.freeze() - self._on_request_end.freeze() - self._on_request_exception.freeze() - self._on_request_redirect.freeze() - self._on_connection_queued_start.freeze() - self._on_connection_queued_end.freeze() - self._on_connection_create_start.freeze() - self._on_connection_create_end.freeze() - self._on_connection_reuseconn.freeze() - self._on_dns_resolvehost_start.freeze() - self._on_dns_resolvehost_end.freeze() - self._on_dns_cache_hit.freeze() - self._on_dns_cache_miss.freeze() - self._on_request_headers_sent.freeze() - - @property - def on_request_start(self) -> "_TracingSignal[TraceRequestStartParams]": - return self._on_request_start - - @property - def on_request_chunk_sent( - self, - ) -> "_TracingSignal[TraceRequestChunkSentParams]": - return self._on_request_chunk_sent - - @property - def on_response_chunk_received( - self, - ) -> "_TracingSignal[TraceResponseChunkReceivedParams]": - return self._on_response_chunk_received - - @property - def on_request_end(self) -> "_TracingSignal[TraceRequestEndParams]": - return self._on_request_end - - @property - def on_request_exception( - self, - ) -> "_TracingSignal[TraceRequestExceptionParams]": - return self._on_request_exception - - @property - def on_request_redirect( - self, - ) -> "_TracingSignal[TraceRequestRedirectParams]": - return self._on_request_redirect - - @property - def on_connection_queued_start( - self, - ) -> "_TracingSignal[TraceConnectionQueuedStartParams]": - return self._on_connection_queued_start - - @property - def on_connection_queued_end( - self, - ) -> "_TracingSignal[TraceConnectionQueuedEndParams]": - return self._on_connection_queued_end - - @property - def on_connection_create_start( - self, - ) -> "_TracingSignal[TraceConnectionCreateStartParams]": - return self._on_connection_create_start - - @property - def on_connection_create_end( - self, - ) -> "_TracingSignal[TraceConnectionCreateEndParams]": - return self._on_connection_create_end - - @property - def on_connection_reuseconn( - self, - ) -> "_TracingSignal[TraceConnectionReuseconnParams]": - return self._on_connection_reuseconn - - @property - def on_dns_resolvehost_start( - self, - ) -> "_TracingSignal[TraceDnsResolveHostStartParams]": - return self._on_dns_resolvehost_start - - @property - def on_dns_resolvehost_end( - self, - ) -> "_TracingSignal[TraceDnsResolveHostEndParams]": - return self._on_dns_resolvehost_end - - @property - def on_dns_cache_hit(self) -> "_TracingSignal[TraceDnsCacheHitParams]": - return self._on_dns_cache_hit - - @property - def on_dns_cache_miss(self) -> "_TracingSignal[TraceDnsCacheMissParams]": - return self._on_dns_cache_miss - - @property - def on_request_headers_sent( - self, - ) -> "_TracingSignal[TraceRequestHeadersSentParams]": - return self._on_request_headers_sent - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestStartParams: - """Parameters sent by the `on_request_start` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestChunkSentParams: - """Parameters sent by the `on_request_chunk_sent` signal""" - - method: str - url: URL - chunk: bytes - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceResponseChunkReceivedParams: - """Parameters sent by the `on_response_chunk_received` signal""" - - method: str - url: URL - chunk: bytes - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestEndParams: - """Parameters sent by the `on_request_end` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - response: ClientResponse - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestExceptionParams: - """Parameters sent by the `on_request_exception` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - exception: BaseException - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestRedirectParams: - """Parameters sent by the `on_request_redirect` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - response: ClientResponse - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionQueuedStartParams: - """Parameters sent by the `on_connection_queued_start` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionQueuedEndParams: - """Parameters sent by the `on_connection_queued_end` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionCreateStartParams: - """Parameters sent by the `on_connection_create_start` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionCreateEndParams: - """Parameters sent by the `on_connection_create_end` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceConnectionReuseconnParams: - """Parameters sent by the `on_connection_reuseconn` signal""" - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsResolveHostStartParams: - """Parameters sent by the `on_dns_resolvehost_start` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsResolveHostEndParams: - """Parameters sent by the `on_dns_resolvehost_end` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsCacheHitParams: - """Parameters sent by the `on_dns_cache_hit` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceDnsCacheMissParams: - """Parameters sent by the `on_dns_cache_miss` signal""" - - host: str - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class TraceRequestHeadersSentParams: - """Parameters sent by the `on_request_headers_sent` signal""" - - method: str - url: URL - headers: "CIMultiDict[str]" - - -class Trace: - """Internal dependency holder class. - - Used to keep together the main dependencies used - at the moment of send a signal. - """ - - def __init__( - self, - session: "ClientSession", - trace_config: TraceConfig, - trace_config_ctx: SimpleNamespace, - ) -> None: - self._trace_config = trace_config - self._trace_config_ctx = trace_config_ctx - self._session = session - - async def send_request_start( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - return await self._trace_config.on_request_start.send( - self._session, - self._trace_config_ctx, - TraceRequestStartParams(method, url, headers), - ) - - async def send_request_chunk_sent( - self, method: str, url: URL, chunk: bytes - ) -> None: - return await self._trace_config.on_request_chunk_sent.send( - self._session, - self._trace_config_ctx, - TraceRequestChunkSentParams(method, url, chunk), - ) - - async def send_response_chunk_received( - self, method: str, url: URL, chunk: bytes - ) -> None: - return await self._trace_config.on_response_chunk_received.send( - self._session, - self._trace_config_ctx, - TraceResponseChunkReceivedParams(method, url, chunk), - ) - - async def send_request_end( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - response: ClientResponse, - ) -> None: - return await self._trace_config.on_request_end.send( - self._session, - self._trace_config_ctx, - TraceRequestEndParams(method, url, headers, response), - ) - - async def send_request_exception( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - exception: BaseException, - ) -> None: - return await self._trace_config.on_request_exception.send( - self._session, - self._trace_config_ctx, - TraceRequestExceptionParams(method, url, headers, exception), - ) - - async def send_request_redirect( - self, - method: str, - url: URL, - headers: "CIMultiDict[str]", - response: ClientResponse, - ) -> None: - return await self._trace_config._on_request_redirect.send( - self._session, - self._trace_config_ctx, - TraceRequestRedirectParams(method, url, headers, response), - ) - - async def send_connection_queued_start(self) -> None: - return await self._trace_config.on_connection_queued_start.send( - self._session, self._trace_config_ctx, TraceConnectionQueuedStartParams() - ) - - async def send_connection_queued_end(self) -> None: - return await self._trace_config.on_connection_queued_end.send( - self._session, self._trace_config_ctx, TraceConnectionQueuedEndParams() - ) - - async def send_connection_create_start(self) -> None: - return await self._trace_config.on_connection_create_start.send( - self._session, self._trace_config_ctx, TraceConnectionCreateStartParams() - ) - - async def send_connection_create_end(self) -> None: - return await self._trace_config.on_connection_create_end.send( - self._session, self._trace_config_ctx, TraceConnectionCreateEndParams() - ) - - async def send_connection_reuseconn(self) -> None: - return await self._trace_config.on_connection_reuseconn.send( - self._session, self._trace_config_ctx, TraceConnectionReuseconnParams() - ) - - async def send_dns_resolvehost_start(self, host: str) -> None: - return await self._trace_config.on_dns_resolvehost_start.send( - self._session, self._trace_config_ctx, TraceDnsResolveHostStartParams(host) - ) - - async def send_dns_resolvehost_end(self, host: str) -> None: - return await self._trace_config.on_dns_resolvehost_end.send( - self._session, self._trace_config_ctx, TraceDnsResolveHostEndParams(host) - ) - - async def send_dns_cache_hit(self, host: str) -> None: - return await self._trace_config.on_dns_cache_hit.send( - self._session, self._trace_config_ctx, TraceDnsCacheHitParams(host) - ) - - async def send_dns_cache_miss(self, host: str) -> None: - return await self._trace_config.on_dns_cache_miss.send( - self._session, self._trace_config_ctx, TraceDnsCacheMissParams(host) - ) - - async def send_request_headers( - self, method: str, url: URL, headers: "CIMultiDict[str]" - ) -> None: - return await self._trace_config._on_request_headers_sent.send( - self._session, - self._trace_config_ctx, - TraceRequestHeadersSentParams(method, url, headers), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/typedefs.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/typedefs.py deleted file mode 100644 index cc8c082..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/typedefs.py +++ /dev/null @@ -1,69 +0,0 @@ -import json -import os -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable, - Mapping, - Protocol, - Tuple, - Union, -) - -from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy, istr -from yarl import URL, Query as _Query - -Query = _Query - -DEFAULT_JSON_ENCODER = json.dumps -DEFAULT_JSON_DECODER = json.loads - -if TYPE_CHECKING: - _CIMultiDict = CIMultiDict[str] - _CIMultiDictProxy = CIMultiDictProxy[str] - _MultiDict = MultiDict[str] - _MultiDictProxy = MultiDictProxy[str] - from http.cookies import BaseCookie, Morsel - - from .web import Request, StreamResponse -else: - _CIMultiDict = CIMultiDict - _CIMultiDictProxy = CIMultiDictProxy - _MultiDict = MultiDict - _MultiDictProxy = MultiDictProxy - -Byteish = Union[bytes, bytearray, memoryview] -JSONEncoder = Callable[[Any], str] -JSONDecoder = Callable[[str], Any] -LooseHeaders = Union[ - Mapping[str, str], - Mapping[istr, str], - _CIMultiDict, - _CIMultiDictProxy, - Iterable[Tuple[Union[str, istr], str]], -] -RawHeaders = Tuple[Tuple[bytes, bytes], ...] -StrOrURL = Union[str, URL] - -LooseCookiesMappings = Mapping[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] -LooseCookiesIterables = Iterable[ - Tuple[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] -] -LooseCookies = Union[ - LooseCookiesMappings, - LooseCookiesIterables, - "BaseCookie[str]", -] - -Handler = Callable[["Request"], Awaitable["StreamResponse"]] - - -class Middleware(Protocol): - def __call__( - self, request: "Request", handler: Handler - ) -> Awaitable["StreamResponse"]: ... - - -PathLike = Union[str, "os.PathLike[str]"] diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web.py deleted file mode 100644 index 5a1fc96..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web.py +++ /dev/null @@ -1,592 +0,0 @@ -import asyncio -import logging -import os -import socket -import sys -import warnings -from argparse import ArgumentParser -from collections.abc import Iterable -from contextlib import suppress -from importlib import import_module -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Iterable as TypingIterable, - List, - Optional, - Set, - Type, - Union, - cast, -) - -from .abc import AbstractAccessLogger -from .helpers import AppKey as AppKey -from .log import access_logger -from .typedefs import PathLike -from .web_app import Application as Application, CleanupError as CleanupError -from .web_exceptions import ( - HTTPAccepted as HTTPAccepted, - HTTPBadGateway as HTTPBadGateway, - HTTPBadRequest as HTTPBadRequest, - HTTPClientError as HTTPClientError, - HTTPConflict as HTTPConflict, - HTTPCreated as HTTPCreated, - HTTPError as HTTPError, - HTTPException as HTTPException, - HTTPExpectationFailed as HTTPExpectationFailed, - HTTPFailedDependency as HTTPFailedDependency, - HTTPForbidden as HTTPForbidden, - HTTPFound as HTTPFound, - HTTPGatewayTimeout as HTTPGatewayTimeout, - HTTPGone as HTTPGone, - HTTPInsufficientStorage as HTTPInsufficientStorage, - HTTPInternalServerError as HTTPInternalServerError, - HTTPLengthRequired as HTTPLengthRequired, - HTTPMethodNotAllowed as HTTPMethodNotAllowed, - HTTPMisdirectedRequest as HTTPMisdirectedRequest, - HTTPMove as HTTPMove, - HTTPMovedPermanently as HTTPMovedPermanently, - HTTPMultipleChoices as HTTPMultipleChoices, - HTTPNetworkAuthenticationRequired as HTTPNetworkAuthenticationRequired, - HTTPNoContent as HTTPNoContent, - HTTPNonAuthoritativeInformation as HTTPNonAuthoritativeInformation, - HTTPNotAcceptable as HTTPNotAcceptable, - HTTPNotExtended as HTTPNotExtended, - HTTPNotFound as HTTPNotFound, - HTTPNotImplemented as HTTPNotImplemented, - HTTPNotModified as HTTPNotModified, - HTTPOk as HTTPOk, - HTTPPartialContent as HTTPPartialContent, - HTTPPaymentRequired as HTTPPaymentRequired, - HTTPPermanentRedirect as HTTPPermanentRedirect, - HTTPPreconditionFailed as HTTPPreconditionFailed, - HTTPPreconditionRequired as HTTPPreconditionRequired, - HTTPProxyAuthenticationRequired as HTTPProxyAuthenticationRequired, - HTTPRedirection as HTTPRedirection, - HTTPRequestEntityTooLarge as HTTPRequestEntityTooLarge, - HTTPRequestHeaderFieldsTooLarge as HTTPRequestHeaderFieldsTooLarge, - HTTPRequestRangeNotSatisfiable as HTTPRequestRangeNotSatisfiable, - HTTPRequestTimeout as HTTPRequestTimeout, - HTTPRequestURITooLong as HTTPRequestURITooLong, - HTTPResetContent as HTTPResetContent, - HTTPSeeOther as HTTPSeeOther, - HTTPServerError as HTTPServerError, - HTTPServiceUnavailable as HTTPServiceUnavailable, - HTTPSuccessful as HTTPSuccessful, - HTTPTemporaryRedirect as HTTPTemporaryRedirect, - HTTPTooManyRequests as HTTPTooManyRequests, - HTTPUnauthorized as HTTPUnauthorized, - HTTPUnavailableForLegalReasons as HTTPUnavailableForLegalReasons, - HTTPUnprocessableEntity as HTTPUnprocessableEntity, - HTTPUnsupportedMediaType as HTTPUnsupportedMediaType, - HTTPUpgradeRequired as HTTPUpgradeRequired, - HTTPUseProxy as HTTPUseProxy, - HTTPVariantAlsoNegotiates as HTTPVariantAlsoNegotiates, - HTTPVersionNotSupported as HTTPVersionNotSupported, - NotAppKeyWarning as NotAppKeyWarning, -) -from .web_fileresponse import FileResponse as FileResponse -from .web_log import AccessLogger -from .web_middlewares import ( - middleware as middleware, - normalize_path_middleware as normalize_path_middleware, -) -from .web_protocol import ( - PayloadAccessError as PayloadAccessError, - RequestHandler as RequestHandler, - RequestPayloadError as RequestPayloadError, -) -from .web_request import ( - BaseRequest as BaseRequest, - FileField as FileField, - Request as Request, -) -from .web_response import ( - ContentCoding as ContentCoding, - Response as Response, - StreamResponse as StreamResponse, - json_response as json_response, -) -from .web_routedef import ( - AbstractRouteDef as AbstractRouteDef, - RouteDef as RouteDef, - RouteTableDef as RouteTableDef, - StaticDef as StaticDef, - delete as delete, - get as get, - head as head, - options as options, - patch as patch, - post as post, - put as put, - route as route, - static as static, - view as view, -) -from .web_runner import ( - AppRunner as AppRunner, - BaseRunner as BaseRunner, - BaseSite as BaseSite, - GracefulExit as GracefulExit, - NamedPipeSite as NamedPipeSite, - ServerRunner as ServerRunner, - SockSite as SockSite, - TCPSite as TCPSite, - UnixSite as UnixSite, -) -from .web_server import Server as Server -from .web_urldispatcher import ( - AbstractResource as AbstractResource, - AbstractRoute as AbstractRoute, - DynamicResource as DynamicResource, - PlainResource as PlainResource, - PrefixedSubAppResource as PrefixedSubAppResource, - Resource as Resource, - ResourceRoute as ResourceRoute, - StaticResource as StaticResource, - UrlDispatcher as UrlDispatcher, - UrlMappingMatchInfo as UrlMappingMatchInfo, - View as View, -) -from .web_ws import ( - WebSocketReady as WebSocketReady, - WebSocketResponse as WebSocketResponse, - WSMsgType as WSMsgType, -) - -__all__ = ( - # web_app - "AppKey", - "Application", - "CleanupError", - # web_exceptions - "NotAppKeyWarning", - "HTTPAccepted", - "HTTPBadGateway", - "HTTPBadRequest", - "HTTPClientError", - "HTTPConflict", - "HTTPCreated", - "HTTPError", - "HTTPException", - "HTTPExpectationFailed", - "HTTPFailedDependency", - "HTTPForbidden", - "HTTPFound", - "HTTPGatewayTimeout", - "HTTPGone", - "HTTPInsufficientStorage", - "HTTPInternalServerError", - "HTTPLengthRequired", - "HTTPMethodNotAllowed", - "HTTPMisdirectedRequest", - "HTTPMove", - "HTTPMovedPermanently", - "HTTPMultipleChoices", - "HTTPNetworkAuthenticationRequired", - "HTTPNoContent", - "HTTPNonAuthoritativeInformation", - "HTTPNotAcceptable", - "HTTPNotExtended", - "HTTPNotFound", - "HTTPNotImplemented", - "HTTPNotModified", - "HTTPOk", - "HTTPPartialContent", - "HTTPPaymentRequired", - "HTTPPermanentRedirect", - "HTTPPreconditionFailed", - "HTTPPreconditionRequired", - "HTTPProxyAuthenticationRequired", - "HTTPRedirection", - "HTTPRequestEntityTooLarge", - "HTTPRequestHeaderFieldsTooLarge", - "HTTPRequestRangeNotSatisfiable", - "HTTPRequestTimeout", - "HTTPRequestURITooLong", - "HTTPResetContent", - "HTTPSeeOther", - "HTTPServerError", - "HTTPServiceUnavailable", - "HTTPSuccessful", - "HTTPTemporaryRedirect", - "HTTPTooManyRequests", - "HTTPUnauthorized", - "HTTPUnavailableForLegalReasons", - "HTTPUnprocessableEntity", - "HTTPUnsupportedMediaType", - "HTTPUpgradeRequired", - "HTTPUseProxy", - "HTTPVariantAlsoNegotiates", - "HTTPVersionNotSupported", - # web_fileresponse - "FileResponse", - # web_middlewares - "middleware", - "normalize_path_middleware", - # web_protocol - "PayloadAccessError", - "RequestHandler", - "RequestPayloadError", - # web_request - "BaseRequest", - "FileField", - "Request", - # web_response - "ContentCoding", - "Response", - "StreamResponse", - "json_response", - # web_routedef - "AbstractRouteDef", - "RouteDef", - "RouteTableDef", - "StaticDef", - "delete", - "get", - "head", - "options", - "patch", - "post", - "put", - "route", - "static", - "view", - # web_runner - "AppRunner", - "BaseRunner", - "BaseSite", - "GracefulExit", - "ServerRunner", - "SockSite", - "TCPSite", - "UnixSite", - "NamedPipeSite", - # web_server - "Server", - # web_urldispatcher - "AbstractResource", - "AbstractRoute", - "DynamicResource", - "PlainResource", - "PrefixedSubAppResource", - "Resource", - "ResourceRoute", - "StaticResource", - "UrlDispatcher", - "UrlMappingMatchInfo", - "View", - # web_ws - "WebSocketReady", - "WebSocketResponse", - "WSMsgType", - # web - "run_app", -) - - -if TYPE_CHECKING: - from ssl import SSLContext -else: - try: - from ssl import SSLContext - except ImportError: # pragma: no cover - SSLContext = object # type: ignore[misc,assignment] - -# Only display warning when using -Wdefault, -We, -X dev or similar. -warnings.filterwarnings("ignore", category=NotAppKeyWarning, append=True) - -HostSequence = TypingIterable[str] - - -async def _run_app( - app: Union[Application, Awaitable[Application]], - *, - host: Optional[Union[str, HostSequence]] = None, - port: Optional[int] = None, - path: Union[PathLike, TypingIterable[PathLike], None] = None, - sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, - ssl_context: Optional[SSLContext] = None, - print: Optional[Callable[..., None]] = print, - backlog: int = 128, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - **kwargs: Any, # TODO(PY311): Use Unpack -) -> None: - # An internal function to actually do all dirty job for application running - if asyncio.iscoroutine(app): - app = await app - - app = cast(Application, app) - - runner = AppRunner(app, **kwargs) - - await runner.setup() - - sites: List[BaseSite] = [] - - try: - if host is not None: - if isinstance(host, str): - sites.append( - TCPSite( - runner, - host, - port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - else: - for h in host: - sites.append( - TCPSite( - runner, - h, - port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - elif path is None and sock is None or port is not None: - sites.append( - TCPSite( - runner, - port=port, - ssl_context=ssl_context, - backlog=backlog, - reuse_address=reuse_address, - reuse_port=reuse_port, - ) - ) - - if path is not None: - if isinstance(path, (str, os.PathLike)): - sites.append( - UnixSite( - runner, - path, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - else: - for p in path: - sites.append( - UnixSite( - runner, - p, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - - if sock is not None: - if not isinstance(sock, Iterable): - sites.append( - SockSite( - runner, - sock, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - else: - for s in sock: - sites.append( - SockSite( - runner, - s, - ssl_context=ssl_context, - backlog=backlog, - ) - ) - for site in sites: - await site.start() - - if print: # pragma: no branch - names = sorted(str(s.name) for s in runner.sites) - print( - "======== Running on {} ========\n" - "(Press CTRL+C to quit)".format(", ".join(names)) - ) - - # sleep forever by 1 hour intervals, - while True: - await asyncio.sleep(3600) - finally: - await runner.cleanup() - - -def _cancel_tasks( - to_cancel: Set["asyncio.Task[Any]"], loop: asyncio.AbstractEventLoop -) -> None: - if not to_cancel: - return - - for task in to_cancel: - task.cancel() - - loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) - - for task in to_cancel: - if task.cancelled(): - continue - if task.exception() is not None: - loop.call_exception_handler( - { - "message": "unhandled exception during asyncio.run() shutdown", - "exception": task.exception(), - "task": task, - } - ) - - -def run_app( - app: Union[Application, Awaitable[Application]], - *, - host: Optional[Union[str, HostSequence]] = None, - port: Optional[int] = None, - path: Union[PathLike, TypingIterable[PathLike], None] = None, - sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, - shutdown_timeout: float = 60.0, - keepalive_timeout: float = 75.0, - ssl_context: Optional[SSLContext] = None, - print: Optional[Callable[..., None]] = print, - backlog: int = 128, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - access_log_format: str = AccessLogger.LOG_FORMAT, - access_log: Optional[logging.Logger] = access_logger, - handle_signals: bool = True, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - handler_cancellation: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, -) -> None: - """Run an app locally""" - if loop is None: - loop = asyncio.new_event_loop() - - # Configure if and only if in debugging mode and using the default logger - if loop.get_debug() and access_log and access_log.name == "aiohttp.access": - if access_log.level == logging.NOTSET: - access_log.setLevel(logging.DEBUG) - if not access_log.hasHandlers(): - access_log.addHandler(logging.StreamHandler()) - - main_task = loop.create_task( - _run_app( - app, - host=host, - port=port, - path=path, - sock=sock, - shutdown_timeout=shutdown_timeout, - keepalive_timeout=keepalive_timeout, - ssl_context=ssl_context, - print=print, - backlog=backlog, - access_log_class=access_log_class, - access_log_format=access_log_format, - access_log=access_log, - handle_signals=handle_signals, - reuse_address=reuse_address, - reuse_port=reuse_port, - handler_cancellation=handler_cancellation, - **kwargs, - ) - ) - - try: - asyncio.set_event_loop(loop) - loop.run_until_complete(main_task) - except (GracefulExit, KeyboardInterrupt): # pragma: no cover - pass - finally: - try: - main_task.cancel() - with suppress(asyncio.CancelledError): - loop.run_until_complete(main_task) - finally: - _cancel_tasks(asyncio.all_tasks(loop), loop) - loop.run_until_complete(loop.shutdown_asyncgens()) - loop.close() - - -def main(argv: List[str]) -> None: - arg_parser = ArgumentParser( - description="aiohttp.web Application server", prog="aiohttp.web" - ) - arg_parser.add_argument( - "entry_func", - help=( - "Callable returning the `aiohttp.web.Application` instance to " - "run. Should be specified in the 'module:function' syntax." - ), - metavar="entry-func", - ) - arg_parser.add_argument( - "-H", - "--hostname", - help="TCP/IP hostname to serve on (default: localhost)", - default=None, - ) - arg_parser.add_argument( - "-P", - "--port", - help="TCP/IP port to serve on (default: %(default)r)", - type=int, - default=8080, - ) - arg_parser.add_argument( - "-U", - "--path", - help="Unix file system path to serve on. Can be combined with hostname " - "to serve on both Unix and TCP.", - ) - args, extra_argv = arg_parser.parse_known_args(argv) - - # Import logic - mod_str, _, func_str = args.entry_func.partition(":") - if not func_str or not mod_str: - arg_parser.error("'entry-func' not in 'module:function' syntax") - if mod_str.startswith("."): - arg_parser.error("relative module names not supported") - try: - module = import_module(mod_str) - except ImportError as ex: - arg_parser.error(f"unable to import {mod_str}: {ex}") - try: - func = getattr(module, func_str) - except AttributeError: - arg_parser.error(f"module {mod_str!r} has no attribute {func_str!r}") - - # Compatibility logic - if args.path is not None and not hasattr(socket, "AF_UNIX"): - arg_parser.error( - "file system paths not supported by your operating environment" - ) - - logging.basicConfig(level=logging.DEBUG) - - if args.path and args.hostname is None: - host = port = None - else: - host = args.hostname or "localhost" - port = args.port - - app = func(extra_argv) - run_app(app, host=host, port=port, path=args.path) - arg_parser.exit(message="Stopped\n") - - -if __name__ == "__main__": # pragma: no branch - main(sys.argv[1:]) # pragma: no cover diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_app.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_app.py deleted file mode 100644 index 619c008..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_app.py +++ /dev/null @@ -1,620 +0,0 @@ -import asyncio -import logging -import warnings -from functools import lru_cache, partial, update_wrapper -from typing import ( - TYPE_CHECKING, - Any, - AsyncIterator, - Awaitable, - Callable, - Dict, - Iterable, - Iterator, - List, - Mapping, - MutableMapping, - Optional, - Sequence, - Tuple, - Type, - TypeVar, - Union, - cast, - overload, -) - -from aiosignal import Signal -from frozenlist import FrozenList - -from . import hdrs -from .abc import ( - AbstractAccessLogger, - AbstractMatchInfo, - AbstractRouter, - AbstractStreamWriter, -) -from .helpers import DEBUG, AppKey -from .http_parser import RawRequestMessage -from .log import web_logger -from .streams import StreamReader -from .typedefs import Handler, Middleware -from .web_exceptions import NotAppKeyWarning -from .web_log import AccessLogger -from .web_middlewares import _fix_request_current_app -from .web_protocol import RequestHandler -from .web_request import Request -from .web_response import StreamResponse -from .web_routedef import AbstractRouteDef -from .web_server import Server -from .web_urldispatcher import ( - AbstractResource, - AbstractRoute, - Domain, - MaskDomain, - MatchedSubAppResource, - PrefixedSubAppResource, - SystemRoute, - UrlDispatcher, -) - -__all__ = ("Application", "CleanupError") - - -if TYPE_CHECKING: - _AppSignal = Signal["Application"] - _RespPrepareSignal = Signal[Request, StreamResponse] - _Middlewares = FrozenList[Middleware] - _MiddlewaresHandlers = Optional[Sequence[Tuple[Middleware, bool]]] - _Subapps = List["Application"] -else: - # No type checker mode, skip types - _AppSignal = Signal - _RespPrepareSignal = Signal - _Middlewares = FrozenList - _MiddlewaresHandlers = Optional[Sequence] - _Subapps = List - -_T = TypeVar("_T") -_U = TypeVar("_U") -_Resource = TypeVar("_Resource", bound=AbstractResource) - - -def _build_middlewares( - handler: Handler, apps: Tuple["Application", ...] -) -> Callable[[Request], Awaitable[StreamResponse]]: - """Apply middlewares to handler.""" - for app in apps[::-1]: - for m, _ in app._middlewares_handlers: # type: ignore[union-attr] - handler = update_wrapper(partial(m, handler=handler), handler) - return handler - - -_cached_build_middleware = lru_cache(maxsize=1024)(_build_middlewares) - - -class Application(MutableMapping[Union[str, AppKey[Any]], Any]): - ATTRS = frozenset( - [ - "logger", - "_debug", - "_router", - "_loop", - "_handler_args", - "_middlewares", - "_middlewares_handlers", - "_has_legacy_middlewares", - "_run_middlewares", - "_state", - "_frozen", - "_pre_frozen", - "_subapps", - "_on_response_prepare", - "_on_startup", - "_on_shutdown", - "_on_cleanup", - "_client_max_size", - "_cleanup_ctx", - ] - ) - - def __init__( - self, - *, - logger: logging.Logger = web_logger, - router: Optional[UrlDispatcher] = None, - middlewares: Iterable[Middleware] = (), - handler_args: Optional[Mapping[str, Any]] = None, - client_max_size: int = 1024**2, - loop: Optional[asyncio.AbstractEventLoop] = None, - debug: Any = ..., # mypy doesn't support ellipsis - ) -> None: - if router is None: - router = UrlDispatcher() - else: - warnings.warn( - "router argument is deprecated", DeprecationWarning, stacklevel=2 - ) - assert isinstance(router, AbstractRouter), router - - if loop is not None: - warnings.warn( - "loop argument is deprecated", DeprecationWarning, stacklevel=2 - ) - - if debug is not ...: - warnings.warn( - "debug argument is deprecated", DeprecationWarning, stacklevel=2 - ) - self._debug = debug - self._router: UrlDispatcher = router - self._loop = loop - self._handler_args = handler_args - self.logger = logger - - self._middlewares: _Middlewares = FrozenList(middlewares) - - # initialized on freezing - self._middlewares_handlers: _MiddlewaresHandlers = None - # initialized on freezing - self._run_middlewares: Optional[bool] = None - self._has_legacy_middlewares: bool = True - - self._state: Dict[Union[AppKey[Any], str], object] = {} - self._frozen = False - self._pre_frozen = False - self._subapps: _Subapps = [] - - self._on_response_prepare: _RespPrepareSignal = Signal(self) - self._on_startup: _AppSignal = Signal(self) - self._on_shutdown: _AppSignal = Signal(self) - self._on_cleanup: _AppSignal = Signal(self) - self._cleanup_ctx = CleanupContext() - self._on_startup.append(self._cleanup_ctx._on_startup) - self._on_cleanup.append(self._cleanup_ctx._on_cleanup) - self._client_max_size = client_max_size - - def __init_subclass__(cls: Type["Application"]) -> None: - warnings.warn( - "Inheritance class {} from web.Application " - "is discouraged".format(cls.__name__), - DeprecationWarning, - stacklevel=3, - ) - - if DEBUG: # pragma: no cover - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom web.Application.{} attribute " - "is discouraged".format(name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - # MutableMapping API - - def __eq__(self, other: object) -> bool: - return self is other - - @overload # type: ignore[override] - def __getitem__(self, key: AppKey[_T]) -> _T: ... - - @overload - def __getitem__(self, key: str) -> Any: ... - - def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: - return self._state[key] - - def _check_frozen(self) -> None: - if self._frozen: - warnings.warn( - "Changing state of started or joined application is deprecated", - DeprecationWarning, - stacklevel=3, - ) - - @overload # type: ignore[override] - def __setitem__(self, key: AppKey[_T], value: _T) -> None: ... - - @overload - def __setitem__(self, key: str, value: Any) -> None: ... - - def __setitem__(self, key: Union[str, AppKey[_T]], value: Any) -> None: - self._check_frozen() - if not isinstance(key, AppKey): - warnings.warn( - "It is recommended to use web.AppKey instances for keys.\n" - + "https://docs.aiohttp.org/en/stable/web_advanced.html" - + "#application-s-config", - category=NotAppKeyWarning, - stacklevel=2, - ) - self._state[key] = value - - def __delitem__(self, key: Union[str, AppKey[_T]]) -> None: - self._check_frozen() - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: - return iter(self._state) - - def __hash__(self) -> int: - return id(self) - - @overload # type: ignore[override] - def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... - - @overload - def get(self, key: AppKey[_T], default: _U) -> Union[_T, _U]: ... - - @overload - def get(self, key: str, default: Any = ...) -> Any: ... - - def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: - return self._state.get(key, default) - - ######## - @property - def loop(self) -> asyncio.AbstractEventLoop: - # Technically the loop can be None - # but we mask it by explicit type cast - # to provide more convenient type annotation - warnings.warn("loop property is deprecated", DeprecationWarning, stacklevel=2) - return cast(asyncio.AbstractEventLoop, self._loop) - - def _set_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: - if loop is None: - loop = asyncio.get_event_loop() - if self._loop is not None and self._loop is not loop: - raise RuntimeError( - "web.Application instance initialized with different loop" - ) - - self._loop = loop - - # set loop debug - if self._debug is ...: - self._debug = loop.get_debug() - - # set loop to sub applications - for subapp in self._subapps: - subapp._set_loop(loop) - - @property - def pre_frozen(self) -> bool: - return self._pre_frozen - - def pre_freeze(self) -> None: - if self._pre_frozen: - return - - self._pre_frozen = True - self._middlewares.freeze() - self._router.freeze() - self._on_response_prepare.freeze() - self._cleanup_ctx.freeze() - self._on_startup.freeze() - self._on_shutdown.freeze() - self._on_cleanup.freeze() - self._middlewares_handlers = tuple(self._prepare_middleware()) - self._has_legacy_middlewares = any( - not new_style for _, new_style in self._middlewares_handlers - ) - - # If current app and any subapp do not have middlewares avoid run all - # of the code footprint that it implies, which have a middleware - # hardcoded per app that sets up the current_app attribute. If no - # middlewares are configured the handler will receive the proper - # current_app without needing all of this code. - self._run_middlewares = True if self.middlewares else False - - for subapp in self._subapps: - subapp.pre_freeze() - self._run_middlewares = self._run_middlewares or subapp._run_middlewares - - @property - def frozen(self) -> bool: - return self._frozen - - def freeze(self) -> None: - if self._frozen: - return - - self.pre_freeze() - self._frozen = True - for subapp in self._subapps: - subapp.freeze() - - @property - def debug(self) -> bool: - warnings.warn("debug property is deprecated", DeprecationWarning, stacklevel=2) - return self._debug # type: ignore[no-any-return] - - def _reg_subapp_signals(self, subapp: "Application") -> None: - def reg_handler(signame: str) -> None: - subsig = getattr(subapp, signame) - - async def handler(app: "Application") -> None: - await subsig.send(subapp) - - appsig = getattr(self, signame) - appsig.append(handler) - - reg_handler("on_startup") - reg_handler("on_shutdown") - reg_handler("on_cleanup") - - def add_subapp(self, prefix: str, subapp: "Application") -> PrefixedSubAppResource: - if not isinstance(prefix, str): - raise TypeError("Prefix must be str") - prefix = prefix.rstrip("/") - if not prefix: - raise ValueError("Prefix cannot be empty") - factory = partial(PrefixedSubAppResource, prefix, subapp) - return self._add_subapp(factory, subapp) - - def _add_subapp( - self, resource_factory: Callable[[], _Resource], subapp: "Application" - ) -> _Resource: - if self.frozen: - raise RuntimeError("Cannot add sub application to frozen application") - if subapp.frozen: - raise RuntimeError("Cannot add frozen application") - resource = resource_factory() - self.router.register_resource(resource) - self._reg_subapp_signals(subapp) - self._subapps.append(subapp) - subapp.pre_freeze() - if self._loop is not None: - subapp._set_loop(self._loop) - return resource - - def add_domain(self, domain: str, subapp: "Application") -> MatchedSubAppResource: - if not isinstance(domain, str): - raise TypeError("Domain must be str") - elif "*" in domain: - rule: Domain = MaskDomain(domain) - else: - rule = Domain(domain) - factory = partial(MatchedSubAppResource, rule, subapp) - return self._add_subapp(factory, subapp) - - def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: - return self.router.add_routes(routes) - - @property - def on_response_prepare(self) -> _RespPrepareSignal: - return self._on_response_prepare - - @property - def on_startup(self) -> _AppSignal: - return self._on_startup - - @property - def on_shutdown(self) -> _AppSignal: - return self._on_shutdown - - @property - def on_cleanup(self) -> _AppSignal: - return self._on_cleanup - - @property - def cleanup_ctx(self) -> "CleanupContext": - return self._cleanup_ctx - - @property - def router(self) -> UrlDispatcher: - return self._router - - @property - def middlewares(self) -> _Middlewares: - return self._middlewares - - def _make_handler( - self, - *, - loop: Optional[asyncio.AbstractEventLoop] = None, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - **kwargs: Any, - ) -> Server: - - if not issubclass(access_log_class, AbstractAccessLogger): - raise TypeError( - "access_log_class must be subclass of " - "aiohttp.abc.AbstractAccessLogger, got {}".format(access_log_class) - ) - - self._set_loop(loop) - self.freeze() - - kwargs["debug"] = self._debug - kwargs["access_log_class"] = access_log_class - if self._handler_args: - for k, v in self._handler_args.items(): - kwargs[k] = v - - return Server( - self._handle, # type: ignore[arg-type] - request_factory=self._make_request, - loop=self._loop, - **kwargs, - ) - - def make_handler( - self, - *, - loop: Optional[asyncio.AbstractEventLoop] = None, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - **kwargs: Any, - ) -> Server: - - warnings.warn( - "Application.make_handler(...) is deprecated, use AppRunner API instead", - DeprecationWarning, - stacklevel=2, - ) - - return self._make_handler( - loop=loop, access_log_class=access_log_class, **kwargs - ) - - async def startup(self) -> None: - """Causes on_startup signal - - Should be called in the event loop along with the request handler. - """ - await self.on_startup.send(self) - - async def shutdown(self) -> None: - """Causes on_shutdown signal - - Should be called before cleanup() - """ - await self.on_shutdown.send(self) - - async def cleanup(self) -> None: - """Causes on_cleanup signal - - Should be called after shutdown() - """ - if self.on_cleanup.frozen: - await self.on_cleanup.send(self) - else: - # If an exception occurs in startup, ensure cleanup contexts are completed. - await self._cleanup_ctx._on_cleanup(self) - - def _make_request( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: RequestHandler, - writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - _cls: Type[Request] = Request, - ) -> Request: - if TYPE_CHECKING: - assert self._loop is not None - return _cls( - message, - payload, - protocol, - writer, - task, - self._loop, - client_max_size=self._client_max_size, - ) - - def _prepare_middleware(self) -> Iterator[Tuple[Middleware, bool]]: - for m in reversed(self._middlewares): - if getattr(m, "__middleware_version__", None) == 1: - yield m, True - else: - warnings.warn( - f'old-style middleware "{m!r}" deprecated, see #2252', - DeprecationWarning, - stacklevel=2, - ) - yield m, False - - yield _fix_request_current_app(self), True - - async def _handle(self, request: Request) -> StreamResponse: - loop = asyncio.get_event_loop() - debug = loop.get_debug() - match_info = await self._router.resolve(request) - if debug: # pragma: no cover - if not isinstance(match_info, AbstractMatchInfo): - raise TypeError( - "match_info should be AbstractMatchInfo " - "instance, not {!r}".format(match_info) - ) - match_info.add_app(self) - - match_info.freeze() - - request._match_info = match_info - - if request.headers.get(hdrs.EXPECT): - resp = await match_info.expect_handler(request) - await request.writer.drain() - if resp is not None: - return resp - - handler = match_info.handler - - if self._run_middlewares: - # If its a SystemRoute, don't cache building the middlewares since - # they are constructed for every MatchInfoError as a new handler - # is made each time. - if not self._has_legacy_middlewares and not isinstance( - match_info.route, SystemRoute - ): - handler = _cached_build_middleware(handler, match_info.apps) - else: - for app in match_info.apps[::-1]: - for m, new_style in app._middlewares_handlers: # type: ignore[union-attr] - if new_style: - handler = update_wrapper( - partial(m, handler=handler), handler - ) - else: - handler = await m(app, handler) # type: ignore[arg-type,assignment] - - return await handler(request) - - def __call__(self) -> "Application": - """gunicorn compatibility""" - return self - - def __repr__(self) -> str: - return f"" - - def __bool__(self) -> bool: - return True - - -class CleanupError(RuntimeError): - @property - def exceptions(self) -> List[BaseException]: - return cast(List[BaseException], self.args[1]) - - -if TYPE_CHECKING: - _CleanupContextBase = FrozenList[Callable[[Application], AsyncIterator[None]]] -else: - _CleanupContextBase = FrozenList - - -class CleanupContext(_CleanupContextBase): - def __init__(self) -> None: - super().__init__() - self._exits: List[AsyncIterator[None]] = [] - - async def _on_startup(self, app: Application) -> None: - for cb in self: - it = cb(app).__aiter__() - await it.__anext__() - self._exits.append(it) - - async def _on_cleanup(self, app: Application) -> None: - errors = [] - for it in reversed(self._exits): - try: - await it.__anext__() - except StopAsyncIteration: - pass - except (Exception, asyncio.CancelledError) as exc: - errors.append(exc) - else: - errors.append(RuntimeError(f"{it!r} has more than one 'yield'")) - if errors: - if len(errors) == 1: - raise errors[0] - else: - raise CleanupError("Multiple errors on cleanup stage", errors) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_exceptions.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_exceptions.py deleted file mode 100644 index ee2c1e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_exceptions.py +++ /dev/null @@ -1,452 +0,0 @@ -import warnings -from typing import Any, Dict, Iterable, List, Optional, Set # noqa - -from yarl import URL - -from .typedefs import LooseHeaders, StrOrURL -from .web_response import Response - -__all__ = ( - "HTTPException", - "HTTPError", - "HTTPRedirection", - "HTTPSuccessful", - "HTTPOk", - "HTTPCreated", - "HTTPAccepted", - "HTTPNonAuthoritativeInformation", - "HTTPNoContent", - "HTTPResetContent", - "HTTPPartialContent", - "HTTPMove", - "HTTPMultipleChoices", - "HTTPMovedPermanently", - "HTTPFound", - "HTTPSeeOther", - "HTTPNotModified", - "HTTPUseProxy", - "HTTPTemporaryRedirect", - "HTTPPermanentRedirect", - "HTTPClientError", - "HTTPBadRequest", - "HTTPUnauthorized", - "HTTPPaymentRequired", - "HTTPForbidden", - "HTTPNotFound", - "HTTPMethodNotAllowed", - "HTTPNotAcceptable", - "HTTPProxyAuthenticationRequired", - "HTTPRequestTimeout", - "HTTPConflict", - "HTTPGone", - "HTTPLengthRequired", - "HTTPPreconditionFailed", - "HTTPRequestEntityTooLarge", - "HTTPRequestURITooLong", - "HTTPUnsupportedMediaType", - "HTTPRequestRangeNotSatisfiable", - "HTTPExpectationFailed", - "HTTPMisdirectedRequest", - "HTTPUnprocessableEntity", - "HTTPFailedDependency", - "HTTPUpgradeRequired", - "HTTPPreconditionRequired", - "HTTPTooManyRequests", - "HTTPRequestHeaderFieldsTooLarge", - "HTTPUnavailableForLegalReasons", - "HTTPServerError", - "HTTPInternalServerError", - "HTTPNotImplemented", - "HTTPBadGateway", - "HTTPServiceUnavailable", - "HTTPGatewayTimeout", - "HTTPVersionNotSupported", - "HTTPVariantAlsoNegotiates", - "HTTPInsufficientStorage", - "HTTPNotExtended", - "HTTPNetworkAuthenticationRequired", -) - - -class NotAppKeyWarning(UserWarning): - """Warning when not using AppKey in Application.""" - - -############################################################ -# HTTP Exceptions -############################################################ - - -class HTTPException(Response, Exception): - - # You should set in subclasses: - # status = 200 - - status_code = -1 - empty_body = False - - __http_exception__ = True - - def __init__( - self, - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - if body is not None: - warnings.warn( - "body argument is deprecated for http web exceptions", - DeprecationWarning, - ) - Response.__init__( - self, - status=self.status_code, - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - Exception.__init__(self, self.reason) - if self.body is None and not self.empty_body: - self.text = f"{self.status}: {self.reason}" - - def __bool__(self) -> bool: - return True - - -class HTTPError(HTTPException): - """Base class for exceptions with status codes in the 400s and 500s.""" - - -class HTTPRedirection(HTTPException): - """Base class for exceptions with status codes in the 300s.""" - - -class HTTPSuccessful(HTTPException): - """Base class for exceptions with status codes in the 200s.""" - - -class HTTPOk(HTTPSuccessful): - status_code = 200 - - -class HTTPCreated(HTTPSuccessful): - status_code = 201 - - -class HTTPAccepted(HTTPSuccessful): - status_code = 202 - - -class HTTPNonAuthoritativeInformation(HTTPSuccessful): - status_code = 203 - - -class HTTPNoContent(HTTPSuccessful): - status_code = 204 - empty_body = True - - -class HTTPResetContent(HTTPSuccessful): - status_code = 205 - empty_body = True - - -class HTTPPartialContent(HTTPSuccessful): - status_code = 206 - - -############################################################ -# 3xx redirection -############################################################ - - -class HTTPMove(HTTPRedirection): - def __init__( - self, - location: StrOrURL, - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - if not location: - raise ValueError("HTTP redirects need a location to redirect to.") - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self.headers["Location"] = str(URL(location)) - self.location = location - - -class HTTPMultipleChoices(HTTPMove): - status_code = 300 - - -class HTTPMovedPermanently(HTTPMove): - status_code = 301 - - -class HTTPFound(HTTPMove): - status_code = 302 - - -# This one is safe after a POST (the redirected location will be -# retrieved with GET): -class HTTPSeeOther(HTTPMove): - status_code = 303 - - -class HTTPNotModified(HTTPRedirection): - # FIXME: this should include a date or etag header - status_code = 304 - empty_body = True - - -class HTTPUseProxy(HTTPMove): - # Not a move, but looks a little like one - status_code = 305 - - -class HTTPTemporaryRedirect(HTTPMove): - status_code = 307 - - -class HTTPPermanentRedirect(HTTPMove): - status_code = 308 - - -############################################################ -# 4xx client error -############################################################ - - -class HTTPClientError(HTTPError): - pass - - -class HTTPBadRequest(HTTPClientError): - status_code = 400 - - -class HTTPUnauthorized(HTTPClientError): - status_code = 401 - - -class HTTPPaymentRequired(HTTPClientError): - status_code = 402 - - -class HTTPForbidden(HTTPClientError): - status_code = 403 - - -class HTTPNotFound(HTTPClientError): - status_code = 404 - - -class HTTPMethodNotAllowed(HTTPClientError): - status_code = 405 - - def __init__( - self, - method: str, - allowed_methods: Iterable[str], - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - allow = ",".join(sorted(allowed_methods)) - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self.headers["Allow"] = allow - self.allowed_methods: Set[str] = set(allowed_methods) - self.method = method.upper() - - -class HTTPNotAcceptable(HTTPClientError): - status_code = 406 - - -class HTTPProxyAuthenticationRequired(HTTPClientError): - status_code = 407 - - -class HTTPRequestTimeout(HTTPClientError): - status_code = 408 - - -class HTTPConflict(HTTPClientError): - status_code = 409 - - -class HTTPGone(HTTPClientError): - status_code = 410 - - -class HTTPLengthRequired(HTTPClientError): - status_code = 411 - - -class HTTPPreconditionFailed(HTTPClientError): - status_code = 412 - - -class HTTPRequestEntityTooLarge(HTTPClientError): - status_code = 413 - - def __init__(self, max_size: float, actual_size: float, **kwargs: Any) -> None: - kwargs.setdefault( - "text", - "Maximum request body size {} exceeded, " - "actual body size {}".format(max_size, actual_size), - ) - super().__init__(**kwargs) - - -class HTTPRequestURITooLong(HTTPClientError): - status_code = 414 - - -class HTTPUnsupportedMediaType(HTTPClientError): - status_code = 415 - - -class HTTPRequestRangeNotSatisfiable(HTTPClientError): - status_code = 416 - - -class HTTPExpectationFailed(HTTPClientError): - status_code = 417 - - -class HTTPMisdirectedRequest(HTTPClientError): - status_code = 421 - - -class HTTPUnprocessableEntity(HTTPClientError): - status_code = 422 - - -class HTTPFailedDependency(HTTPClientError): - status_code = 424 - - -class HTTPUpgradeRequired(HTTPClientError): - status_code = 426 - - -class HTTPPreconditionRequired(HTTPClientError): - status_code = 428 - - -class HTTPTooManyRequests(HTTPClientError): - status_code = 429 - - -class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): - status_code = 431 - - -class HTTPUnavailableForLegalReasons(HTTPClientError): - status_code = 451 - - def __init__( - self, - link: Optional[StrOrURL], - *, - headers: Optional[LooseHeaders] = None, - reason: Optional[str] = None, - body: Any = None, - text: Optional[str] = None, - content_type: Optional[str] = None, - ) -> None: - super().__init__( - headers=headers, - reason=reason, - body=body, - text=text, - content_type=content_type, - ) - self._link = None - if link: - self._link = URL(link) - self.headers["Link"] = f'<{str(self._link)}>; rel="blocked-by"' - - @property - def link(self) -> Optional[URL]: - return self._link - - -############################################################ -# 5xx Server Error -############################################################ -# Response status codes beginning with the digit "5" indicate cases in -# which the server is aware that it has erred or is incapable of -# performing the request. Except when responding to a HEAD request, the -# server SHOULD include an entity containing an explanation of the error -# situation, and whether it is a temporary or permanent condition. User -# agents SHOULD display any included entity to the user. These response -# codes are applicable to any request method. - - -class HTTPServerError(HTTPError): - pass - - -class HTTPInternalServerError(HTTPServerError): - status_code = 500 - - -class HTTPNotImplemented(HTTPServerError): - status_code = 501 - - -class HTTPBadGateway(HTTPServerError): - status_code = 502 - - -class HTTPServiceUnavailable(HTTPServerError): - status_code = 503 - - -class HTTPGatewayTimeout(HTTPServerError): - status_code = 504 - - -class HTTPVersionNotSupported(HTTPServerError): - status_code = 505 - - -class HTTPVariantAlsoNegotiates(HTTPServerError): - status_code = 506 - - -class HTTPInsufficientStorage(HTTPServerError): - status_code = 507 - - -class HTTPNotExtended(HTTPServerError): - status_code = 510 - - -class HTTPNetworkAuthenticationRequired(HTTPServerError): - status_code = 511 diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_fileresponse.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_fileresponse.py deleted file mode 100644 index 26484b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_fileresponse.py +++ /dev/null @@ -1,418 +0,0 @@ -import asyncio -import io -import os -import pathlib -import sys -from contextlib import suppress -from enum import Enum, auto -from mimetypes import MimeTypes -from stat import S_ISREG -from types import MappingProxyType -from typing import ( # noqa - IO, - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Final, - Iterator, - List, - Optional, - Set, - Tuple, - Union, - cast, -) - -from . import hdrs -from .abc import AbstractStreamWriter -from .helpers import ETAG_ANY, ETag, must_be_empty_body -from .typedefs import LooseHeaders, PathLike -from .web_exceptions import ( - HTTPForbidden, - HTTPNotFound, - HTTPNotModified, - HTTPPartialContent, - HTTPPreconditionFailed, - HTTPRequestRangeNotSatisfiable, -) -from .web_response import StreamResponse - -__all__ = ("FileResponse",) - -if TYPE_CHECKING: - from .web_request import BaseRequest - - -_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] - - -NOSENDFILE: Final[bool] = bool(os.environ.get("AIOHTTP_NOSENDFILE")) - -CONTENT_TYPES: Final[MimeTypes] = MimeTypes() - -# File extension to IANA encodings map that will be checked in the order defined. -ENCODING_EXTENSIONS = MappingProxyType( - {ext: CONTENT_TYPES.encodings_map[ext] for ext in (".br", ".gz")} -) - -FALLBACK_CONTENT_TYPE = "application/octet-stream" - -# Provide additional MIME type/extension pairs to be recognized. -# https://en.wikipedia.org/wiki/List_of_archive_formats#Compression_only -ADDITIONAL_CONTENT_TYPES = MappingProxyType( - { - "application/gzip": ".gz", - "application/x-brotli": ".br", - "application/x-bzip2": ".bz2", - "application/x-compress": ".Z", - "application/x-xz": ".xz", - } -) - - -class _FileResponseResult(Enum): - """The result of the file response.""" - - SEND_FILE = auto() # Ie a regular file to send - NOT_ACCEPTABLE = auto() # Ie a socket, or non-regular file - PRE_CONDITION_FAILED = auto() # Ie If-Match or If-None-Match failed - NOT_MODIFIED = auto() # 304 Not Modified - - -# Add custom pairs and clear the encodings map so guess_type ignores them. -CONTENT_TYPES.encodings_map.clear() -for content_type, extension in ADDITIONAL_CONTENT_TYPES.items(): - CONTENT_TYPES.add_type(content_type, extension) - - -_CLOSE_FUTURES: Set[asyncio.Future[None]] = set() - - -class FileResponse(StreamResponse): - """A response object can be used to send files.""" - - def __init__( - self, - path: PathLike, - chunk_size: int = 256 * 1024, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - ) -> None: - super().__init__(status=status, reason=reason, headers=headers) - - self._path = pathlib.Path(path) - self._chunk_size = chunk_size - - def _seek_and_read(self, fobj: IO[Any], offset: int, chunk_size: int) -> bytes: - fobj.seek(offset) - return fobj.read(chunk_size) # type: ignore[no-any-return] - - async def _sendfile_fallback( - self, writer: AbstractStreamWriter, fobj: IO[Any], offset: int, count: int - ) -> AbstractStreamWriter: - # To keep memory usage low,fobj is transferred in chunks - # controlled by the constructor's chunk_size argument. - - chunk_size = self._chunk_size - loop = asyncio.get_event_loop() - chunk = await loop.run_in_executor( - None, self._seek_and_read, fobj, offset, chunk_size - ) - while chunk: - await writer.write(chunk) - count = count - chunk_size - if count <= 0: - break - chunk = await loop.run_in_executor(None, fobj.read, min(chunk_size, count)) - - await writer.drain() - return writer - - async def _sendfile( - self, request: "BaseRequest", fobj: IO[Any], offset: int, count: int - ) -> AbstractStreamWriter: - writer = await super().prepare(request) - assert writer is not None - - if NOSENDFILE or self.compression: - return await self._sendfile_fallback(writer, fobj, offset, count) - - loop = request._loop - transport = request.transport - assert transport is not None - - try: - await loop.sendfile(transport, fobj, offset, count) - except NotImplementedError: - return await self._sendfile_fallback(writer, fobj, offset, count) - - await super().write_eof() - return writer - - @staticmethod - def _etag_match(etag_value: str, etags: Tuple[ETag, ...], *, weak: bool) -> bool: - if len(etags) == 1 and etags[0].value == ETAG_ANY: - return True - return any( - etag.value == etag_value for etag in etags if weak or not etag.is_weak - ) - - async def _not_modified( - self, request: "BaseRequest", etag_value: str, last_modified: float - ) -> Optional[AbstractStreamWriter]: - self.set_status(HTTPNotModified.status_code) - self._length_check = False - self.etag = etag_value - self.last_modified = last_modified - # Delete any Content-Length headers provided by user. HTTP 304 - # should always have empty response body - return await super().prepare(request) - - async def _precondition_failed( - self, request: "BaseRequest" - ) -> Optional[AbstractStreamWriter]: - self.set_status(HTTPPreconditionFailed.status_code) - self.content_length = 0 - return await super().prepare(request) - - def _make_response( - self, request: "BaseRequest", accept_encoding: str - ) -> Tuple[ - _FileResponseResult, Optional[io.BufferedReader], os.stat_result, Optional[str] - ]: - """Return the response result, io object, stat result, and encoding. - - If an uncompressed file is returned, the encoding is set to - :py:data:`None`. - - This method should be called from a thread executor - since it calls os.stat which may block. - """ - file_path, st, file_encoding = self._get_file_path_stat_encoding( - accept_encoding - ) - if not file_path: - return _FileResponseResult.NOT_ACCEPTABLE, None, st, None - - etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" - - # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.1-2 - if (ifmatch := request.if_match) is not None and not self._etag_match( - etag_value, ifmatch, weak=False - ): - return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding - - if ( - (unmodsince := request.if_unmodified_since) is not None - and ifmatch is None - and st.st_mtime > unmodsince.timestamp() - ): - return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding - - # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.2-2 - if (ifnonematch := request.if_none_match) is not None and self._etag_match( - etag_value, ifnonematch, weak=True - ): - return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding - - if ( - (modsince := request.if_modified_since) is not None - and ifnonematch is None - and st.st_mtime <= modsince.timestamp() - ): - return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding - - fobj = file_path.open("rb") - with suppress(OSError): - # fstat() may not be available on all platforms - # Once we open the file, we want the fstat() to ensure - # the file has not changed between the first stat() - # and the open(). - st = os.stat(fobj.fileno()) - return _FileResponseResult.SEND_FILE, fobj, st, file_encoding - - def _get_file_path_stat_encoding( - self, accept_encoding: str - ) -> Tuple[Optional[pathlib.Path], os.stat_result, Optional[str]]: - file_path = self._path - for file_extension, file_encoding in ENCODING_EXTENSIONS.items(): - if file_encoding not in accept_encoding: - continue - - compressed_path = file_path.with_suffix(file_path.suffix + file_extension) - with suppress(OSError): - # Do not follow symlinks and ignore any non-regular files. - st = compressed_path.lstat() - if S_ISREG(st.st_mode): - return compressed_path, st, file_encoding - - # Fallback to the uncompressed file - st = file_path.stat() - return file_path if S_ISREG(st.st_mode) else None, st, None - - async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: - loop = asyncio.get_running_loop() - # Encoding comparisons should be case-insensitive - # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 - accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() - try: - response_result, fobj, st, file_encoding = await loop.run_in_executor( - None, self._make_response, request, accept_encoding - ) - except PermissionError: - self.set_status(HTTPForbidden.status_code) - return await super().prepare(request) - except OSError: - # Most likely to be FileNotFoundError or OSError for circular - # symlinks in python >= 3.13, so respond with 404. - self.set_status(HTTPNotFound.status_code) - return await super().prepare(request) - - # Forbid special files like sockets, pipes, devices, etc. - if response_result is _FileResponseResult.NOT_ACCEPTABLE: - self.set_status(HTTPForbidden.status_code) - return await super().prepare(request) - - if response_result is _FileResponseResult.PRE_CONDITION_FAILED: - return await self._precondition_failed(request) - - if response_result is _FileResponseResult.NOT_MODIFIED: - etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" - last_modified = st.st_mtime - return await self._not_modified(request, etag_value, last_modified) - - assert fobj is not None - try: - return await self._prepare_open_file(request, fobj, st, file_encoding) - finally: - # We do not await here because we do not want to wait - # for the executor to finish before returning the response - # so the connection can begin servicing another request - # as soon as possible. - close_future = loop.run_in_executor(None, fobj.close) - # Hold a strong reference to the future to prevent it from being - # garbage collected before it completes. - _CLOSE_FUTURES.add(close_future) - close_future.add_done_callback(_CLOSE_FUTURES.remove) - - async def _prepare_open_file( - self, - request: "BaseRequest", - fobj: io.BufferedReader, - st: os.stat_result, - file_encoding: Optional[str], - ) -> Optional[AbstractStreamWriter]: - status = self._status - file_size: int = st.st_size - file_mtime: float = st.st_mtime - count: int = file_size - start: Optional[int] = None - - if (ifrange := request.if_range) is None or file_mtime <= ifrange.timestamp(): - # If-Range header check: - # condition = cached date >= last modification date - # return 206 if True else 200. - # if False: - # Range header would not be processed, return 200 - # if True but Range header missing - # return 200 - try: - rng = request.http_range - start = rng.start - end: Optional[int] = rng.stop - except ValueError: - # https://tools.ietf.org/html/rfc7233: - # A server generating a 416 (Range Not Satisfiable) response to - # a byte-range request SHOULD send a Content-Range header field - # with an unsatisfied-range value. - # The complete-length in a 416 response indicates the current - # length of the selected representation. - # - # Will do the same below. Many servers ignore this and do not - # send a Content-Range header with HTTP 416 - self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" - self.set_status(HTTPRequestRangeNotSatisfiable.status_code) - return await super().prepare(request) - - # If a range request has been made, convert start, end slice - # notation into file pointer offset and count - if start is not None: - if start < 0 and end is None: # return tail of file - start += file_size - if start < 0: - # if Range:bytes=-1000 in request header but file size - # is only 200, there would be trouble without this - start = 0 - count = file_size - start - else: - # rfc7233:If the last-byte-pos value is - # absent, or if the value is greater than or equal to - # the current length of the representation data, - # the byte range is interpreted as the remainder - # of the representation (i.e., the server replaces the - # value of last-byte-pos with a value that is one less than - # the current length of the selected representation). - count = ( - min(end if end is not None else file_size, file_size) - start - ) - - if start >= file_size: - # HTTP 416 should be returned in this case. - # - # According to https://tools.ietf.org/html/rfc7233: - # If a valid byte-range-set includes at least one - # byte-range-spec with a first-byte-pos that is less than - # the current length of the representation, or at least one - # suffix-byte-range-spec with a non-zero suffix-length, - # then the byte-range-set is satisfiable. Otherwise, the - # byte-range-set is unsatisfiable. - self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" - self.set_status(HTTPRequestRangeNotSatisfiable.status_code) - return await super().prepare(request) - - status = HTTPPartialContent.status_code - # Even though you are sending the whole file, you should still - # return a HTTP 206 for a Range request. - self.set_status(status) - - # If the Content-Type header is not already set, guess it based on the - # extension of the request path. The encoding returned by guess_type - # can be ignored since the map was cleared above. - if hdrs.CONTENT_TYPE not in self._headers: - if sys.version_info >= (3, 13): - guesser = CONTENT_TYPES.guess_file_type - else: - guesser = CONTENT_TYPES.guess_type - self.content_type = guesser(self._path)[0] or FALLBACK_CONTENT_TYPE - - if file_encoding: - self._headers[hdrs.CONTENT_ENCODING] = file_encoding - self._headers[hdrs.VARY] = hdrs.ACCEPT_ENCODING - # Disable compression if we are already sending - # a compressed file since we don't want to double - # compress. - self._compression = False - - self.etag = f"{st.st_mtime_ns:x}-{st.st_size:x}" - self.last_modified = file_mtime - self.content_length = count - - self._headers[hdrs.ACCEPT_RANGES] = "bytes" - - if status == HTTPPartialContent.status_code: - real_start = start - assert real_start is not None - self._headers[hdrs.CONTENT_RANGE] = "bytes {}-{}/{}".format( - real_start, real_start + count - 1, file_size - ) - - # If we are sending 0 bytes calling sendfile() will throw a ValueError - if count == 0 or must_be_empty_body(request.method, status): - return await super().prepare(request) - - # be aware that start could be None or int=0 here. - offset = start or 0 - - return await self._sendfile(request, fobj, offset, count) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_log.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_log.py deleted file mode 100644 index d5ea2be..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_log.py +++ /dev/null @@ -1,216 +0,0 @@ -import datetime -import functools -import logging -import os -import re -import time as time_mod -from collections import namedtuple -from typing import Any, Callable, Dict, Iterable, List, Tuple # noqa - -from .abc import AbstractAccessLogger -from .web_request import BaseRequest -from .web_response import StreamResponse - -KeyMethod = namedtuple("KeyMethod", "key method") - - -class AccessLogger(AbstractAccessLogger): - """Helper object to log access. - - Usage: - log = logging.getLogger("spam") - log_format = "%a %{User-Agent}i" - access_logger = AccessLogger(log, log_format) - access_logger.log(request, response, time) - - Format: - %% The percent sign - %a Remote IP-address (IP-address of proxy if using reverse proxy) - %t Time when the request was started to process - %P The process ID of the child that serviced the request - %r First line of request - %s Response status code - %b Size of response in bytes, including HTTP headers - %T Time taken to serve the request, in seconds - %Tf Time taken to serve the request, in seconds with floating fraction - in .06f format - %D Time taken to serve the request, in microseconds - %{FOO}i request.headers['FOO'] - %{FOO}o response.headers['FOO'] - %{FOO}e os.environ['FOO'] - - """ - - LOG_FORMAT_MAP = { - "a": "remote_address", - "t": "request_start_time", - "P": "process_id", - "r": "first_request_line", - "s": "response_status", - "b": "response_size", - "T": "request_time", - "Tf": "request_time_frac", - "D": "request_time_micro", - "i": "request_header", - "o": "response_header", - } - - LOG_FORMAT = '%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"' - FORMAT_RE = re.compile(r"%(\{([A-Za-z0-9\-_]+)\}([ioe])|[atPrsbOD]|Tf?)") - CLEANUP_RE = re.compile(r"(%[^s])") - _FORMAT_CACHE: Dict[str, Tuple[str, List[KeyMethod]]] = {} - - def __init__(self, logger: logging.Logger, log_format: str = LOG_FORMAT) -> None: - """Initialise the logger. - - logger is a logger object to be used for logging. - log_format is a string with apache compatible log format description. - - """ - super().__init__(logger, log_format=log_format) - - _compiled_format = AccessLogger._FORMAT_CACHE.get(log_format) - if not _compiled_format: - _compiled_format = self.compile_format(log_format) - AccessLogger._FORMAT_CACHE[log_format] = _compiled_format - - self._log_format, self._methods = _compiled_format - - def compile_format(self, log_format: str) -> Tuple[str, List[KeyMethod]]: - """Translate log_format into form usable by modulo formatting - - All known atoms will be replaced with %s - Also methods for formatting of those atoms will be added to - _methods in appropriate order - - For example we have log_format = "%a %t" - This format will be translated to "%s %s" - Also contents of _methods will be - [self._format_a, self._format_t] - These method will be called and results will be passed - to translated string format. - - Each _format_* method receive 'args' which is list of arguments - given to self.log - - Exceptions are _format_e, _format_i and _format_o methods which - also receive key name (by functools.partial) - - """ - # list of (key, method) tuples, we don't use an OrderedDict as users - # can repeat the same key more than once - methods = list() - - for atom in self.FORMAT_RE.findall(log_format): - if atom[1] == "": - format_key1 = self.LOG_FORMAT_MAP[atom[0]] - m = getattr(AccessLogger, "_format_%s" % atom[0]) - key_method = KeyMethod(format_key1, m) - else: - format_key2 = (self.LOG_FORMAT_MAP[atom[2]], atom[1]) - m = getattr(AccessLogger, "_format_%s" % atom[2]) - key_method = KeyMethod(format_key2, functools.partial(m, atom[1])) - - methods.append(key_method) - - log_format = self.FORMAT_RE.sub(r"%s", log_format) - log_format = self.CLEANUP_RE.sub(r"%\1", log_format) - return log_format, methods - - @staticmethod - def _format_i( - key: str, request: BaseRequest, response: StreamResponse, time: float - ) -> str: - if request is None: - return "(no headers)" - - # suboptimal, make istr(key) once - return request.headers.get(key, "-") - - @staticmethod - def _format_o( - key: str, request: BaseRequest, response: StreamResponse, time: float - ) -> str: - # suboptimal, make istr(key) once - return response.headers.get(key, "-") - - @staticmethod - def _format_a(request: BaseRequest, response: StreamResponse, time: float) -> str: - if request is None: - return "-" - ip = request.remote - return ip if ip is not None else "-" - - @staticmethod - def _format_t(request: BaseRequest, response: StreamResponse, time: float) -> str: - tz = datetime.timezone(datetime.timedelta(seconds=-time_mod.timezone)) - now = datetime.datetime.now(tz) - start_time = now - datetime.timedelta(seconds=time) - return start_time.strftime("[%d/%b/%Y:%H:%M:%S %z]") - - @staticmethod - def _format_P(request: BaseRequest, response: StreamResponse, time: float) -> str: - return "<%s>" % os.getpid() - - @staticmethod - def _format_r(request: BaseRequest, response: StreamResponse, time: float) -> str: - if request is None: - return "-" - return "{} {} HTTP/{}.{}".format( - request.method, - request.path_qs, - request.version.major, - request.version.minor, - ) - - @staticmethod - def _format_s(request: BaseRequest, response: StreamResponse, time: float) -> int: - return response.status - - @staticmethod - def _format_b(request: BaseRequest, response: StreamResponse, time: float) -> int: - return response.body_length - - @staticmethod - def _format_T(request: BaseRequest, response: StreamResponse, time: float) -> str: - return str(round(time)) - - @staticmethod - def _format_Tf(request: BaseRequest, response: StreamResponse, time: float) -> str: - return "%06f" % time - - @staticmethod - def _format_D(request: BaseRequest, response: StreamResponse, time: float) -> str: - return str(round(time * 1000000)) - - def _format_line( - self, request: BaseRequest, response: StreamResponse, time: float - ) -> Iterable[Tuple[str, Callable[[BaseRequest, StreamResponse, float], str]]]: - return [(key, method(request, response, time)) for key, method in self._methods] - - @property - def enabled(self) -> bool: - """Check if logger is enabled.""" - # Avoid formatting the log line if it will not be emitted. - return self.logger.isEnabledFor(logging.INFO) - - def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: - try: - fmt_info = self._format_line(request, response, time) - - values = list() - extra = dict() - for key, value in fmt_info: - values.append(value) - - if key.__class__ is str: - extra[key] = value - else: - k1, k2 = key # type: ignore[misc] - dct = extra.get(k1, {}) # type: ignore[var-annotated,has-type] - dct[k2] = value # type: ignore[index,has-type] - extra[k1] = dct # type: ignore[has-type,assignment] - - self.logger.info(self._log_format % tuple(values), extra=extra) - except Exception: - self.logger.exception("Error in logging") diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_middlewares.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_middlewares.py deleted file mode 100644 index 2f1f5f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_middlewares.py +++ /dev/null @@ -1,121 +0,0 @@ -import re -from typing import TYPE_CHECKING, Tuple, Type, TypeVar - -from .typedefs import Handler, Middleware -from .web_exceptions import HTTPMove, HTTPPermanentRedirect -from .web_request import Request -from .web_response import StreamResponse -from .web_urldispatcher import SystemRoute - -__all__ = ( - "middleware", - "normalize_path_middleware", -) - -if TYPE_CHECKING: - from .web_app import Application - -_Func = TypeVar("_Func") - - -async def _check_request_resolves(request: Request, path: str) -> Tuple[bool, Request]: - alt_request = request.clone(rel_url=path) - - match_info = await request.app.router.resolve(alt_request) - alt_request._match_info = match_info - - if match_info.http_exception is None: - return True, alt_request - - return False, request - - -def middleware(f: _Func) -> _Func: - f.__middleware_version__ = 1 # type: ignore[attr-defined] - return f - - -def normalize_path_middleware( - *, - append_slash: bool = True, - remove_slash: bool = False, - merge_slashes: bool = True, - redirect_class: Type[HTTPMove] = HTTPPermanentRedirect, -) -> Middleware: - """Factory for producing a middleware that normalizes the path of a request. - - Normalizing means: - - Add or remove a trailing slash to the path. - - Double slashes are replaced by one. - - The middleware returns as soon as it finds a path that resolves - correctly. The order if both merge and append/remove are enabled is - 1) merge slashes - 2) append/remove slash - 3) both merge slashes and append/remove slash. - If the path resolves with at least one of those conditions, it will - redirect to the new path. - - Only one of `append_slash` and `remove_slash` can be enabled. If both - are `True` the factory will raise an assertion error - - If `append_slash` is `True` the middleware will append a slash when - needed. If a resource is defined with trailing slash and the request - comes without it, it will append it automatically. - - If `remove_slash` is `True`, `append_slash` must be `False`. When enabled - the middleware will remove trailing slashes and redirect if the resource - is defined - - If merge_slashes is True, merge multiple consecutive slashes in the - path into one. - """ - correct_configuration = not (append_slash and remove_slash) - assert correct_configuration, "Cannot both remove and append slash" - - @middleware - async def impl(request: Request, handler: Handler) -> StreamResponse: - if isinstance(request.match_info.route, SystemRoute): - paths_to_check = [] - if "?" in request.raw_path: - path, query = request.raw_path.split("?", 1) - query = "?" + query - else: - query = "" - path = request.raw_path - - if merge_slashes: - paths_to_check.append(re.sub("//+", "/", path)) - if append_slash and not request.path.endswith("/"): - paths_to_check.append(path + "/") - if remove_slash and request.path.endswith("/"): - paths_to_check.append(path[:-1]) - if merge_slashes and append_slash: - paths_to_check.append(re.sub("//+", "/", path + "/")) - if merge_slashes and remove_slash: - merged_slashes = re.sub("//+", "/", path) - paths_to_check.append(merged_slashes[:-1]) - - for path in paths_to_check: - path = re.sub("^//+", "/", path) # SECURITY: GHSA-v6wp-4m6f-gcjg - resolves, request = await _check_request_resolves(request, path) - if resolves: - raise redirect_class(request.raw_path + query) - - return await handler(request) - - return impl - - -def _fix_request_current_app(app: "Application") -> Middleware: - @middleware - async def impl(request: Request, handler: Handler) -> StreamResponse: - match_info = request.match_info - prev = match_info.current_app - match_info.current_app = app - try: - return await handler(request) - finally: - match_info.current_app = prev - - return impl diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_protocol.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_protocol.py deleted file mode 100644 index 1bd344a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_protocol.py +++ /dev/null @@ -1,792 +0,0 @@ -import asyncio -import asyncio.streams -import sys -import traceback -import warnings -from collections import deque -from contextlib import suppress -from html import escape as html_escape -from http import HTTPStatus -from logging import Logger -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Deque, - Optional, - Sequence, - Tuple, - Type, - Union, - cast, -) - -import attr -import yarl -from propcache import under_cached_property - -from .abc import AbstractAccessLogger, AbstractStreamWriter -from .base_protocol import BaseProtocol -from .helpers import ceil_timeout -from .http import ( - HttpProcessingError, - HttpRequestParser, - HttpVersion10, - RawRequestMessage, - StreamWriter, -) -from .http_exceptions import BadHttpMethod -from .log import access_logger, server_logger -from .streams import EMPTY_PAYLOAD, StreamReader -from .tcp_helpers import tcp_keepalive -from .web_exceptions import HTTPException, HTTPInternalServerError -from .web_log import AccessLogger -from .web_request import BaseRequest -from .web_response import Response, StreamResponse - -__all__ = ("RequestHandler", "RequestPayloadError", "PayloadAccessError") - -if TYPE_CHECKING: - import ssl - - from .web_server import Server - - -_RequestFactory = Callable[ - [ - RawRequestMessage, - StreamReader, - "RequestHandler", - AbstractStreamWriter, - "asyncio.Task[None]", - ], - BaseRequest, -] - -_RequestHandler = Callable[[BaseRequest], Awaitable[StreamResponse]] - -ERROR = RawRequestMessage( - "UNKNOWN", - "/", - HttpVersion10, - {}, # type: ignore[arg-type] - {}, # type: ignore[arg-type] - True, - None, - False, - False, - yarl.URL("/"), -) - - -class RequestPayloadError(Exception): - """Payload parsing error.""" - - -class PayloadAccessError(Exception): - """Payload was accessed after response was sent.""" - - -_PAYLOAD_ACCESS_ERROR = PayloadAccessError() - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class _ErrInfo: - status: int - exc: BaseException - message: str - - -_MsgType = Tuple[Union[RawRequestMessage, _ErrInfo], StreamReader] - - -class RequestHandler(BaseProtocol): - """HTTP protocol implementation. - - RequestHandler handles incoming HTTP request. It reads request line, - request headers and request payload and calls handle_request() method. - By default it always returns with 404 response. - - RequestHandler handles errors in incoming request, like bad - status line, bad headers or incomplete payload. If any error occurs, - connection gets closed. - - keepalive_timeout -- number of seconds before closing - keep-alive connection - - tcp_keepalive -- TCP keep-alive is on, default is on - - debug -- enable debug mode - - logger -- custom logger object - - access_log_class -- custom class for access_logger - - access_log -- custom logging object - - access_log_format -- access log format string - - loop -- Optional event loop - - max_line_size -- Optional maximum header line size - - max_field_size -- Optional maximum header field size - - max_headers -- Optional maximum header size - - timeout_ceil_threshold -- Optional value to specify - threshold to ceil() timeout - values - - """ - - __slots__ = ( - "_request_count", - "_keepalive", - "_manager", - "_request_handler", - "_request_factory", - "_tcp_keepalive", - "_next_keepalive_close_time", - "_keepalive_handle", - "_keepalive_timeout", - "_lingering_time", - "_messages", - "_message_tail", - "_handler_waiter", - "_waiter", - "_task_handler", - "_upgrade", - "_payload_parser", - "_request_parser", - "_reading_paused", - "logger", - "debug", - "access_log", - "access_logger", - "_close", - "_force_close", - "_current_request", - "_timeout_ceil_threshold", - "_request_in_progress", - "_logging_enabled", - "_cache", - ) - - def __init__( - self, - manager: "Server", - *, - loop: asyncio.AbstractEventLoop, - # Default should be high enough that it's likely longer than a reverse proxy. - keepalive_timeout: float = 3630, - tcp_keepalive: bool = True, - logger: Logger = server_logger, - access_log_class: Type[AbstractAccessLogger] = AccessLogger, - access_log: Logger = access_logger, - access_log_format: str = AccessLogger.LOG_FORMAT, - debug: bool = False, - max_line_size: int = 8190, - max_headers: int = 32768, - max_field_size: int = 8190, - lingering_time: float = 10.0, - read_bufsize: int = 2**16, - auto_decompress: bool = True, - timeout_ceil_threshold: float = 5, - ): - super().__init__(loop) - - # _request_count is the number of requests processed with the same connection. - self._request_count = 0 - self._keepalive = False - self._current_request: Optional[BaseRequest] = None - self._manager: Optional[Server] = manager - self._request_handler: Optional[_RequestHandler] = manager.request_handler - self._request_factory: Optional[_RequestFactory] = manager.request_factory - - self._tcp_keepalive = tcp_keepalive - # placeholder to be replaced on keepalive timeout setup - self._next_keepalive_close_time = 0.0 - self._keepalive_handle: Optional[asyncio.Handle] = None - self._keepalive_timeout = keepalive_timeout - self._lingering_time = float(lingering_time) - - self._messages: Deque[_MsgType] = deque() - self._message_tail = b"" - - self._waiter: Optional[asyncio.Future[None]] = None - self._handler_waiter: Optional[asyncio.Future[None]] = None - self._task_handler: Optional[asyncio.Task[None]] = None - - self._upgrade = False - self._payload_parser: Any = None - self._request_parser: Optional[HttpRequestParser] = HttpRequestParser( - self, - loop, - read_bufsize, - max_line_size=max_line_size, - max_field_size=max_field_size, - max_headers=max_headers, - payload_exception=RequestPayloadError, - auto_decompress=auto_decompress, - ) - - self._timeout_ceil_threshold: float = 5 - try: - self._timeout_ceil_threshold = float(timeout_ceil_threshold) - except (TypeError, ValueError): - pass - - self.logger = logger - self.debug = debug - self.access_log = access_log - if access_log: - self.access_logger: Optional[AbstractAccessLogger] = access_log_class( - access_log, access_log_format - ) - self._logging_enabled = self.access_logger.enabled - else: - self.access_logger = None - self._logging_enabled = False - - self._close = False - self._force_close = False - self._request_in_progress = False - self._cache: dict[str, Any] = {} - - def __repr__(self) -> str: - return "<{} {}>".format( - self.__class__.__name__, - "connected" if self.transport is not None else "disconnected", - ) - - @under_cached_property - def ssl_context(self) -> Optional["ssl.SSLContext"]: - """Return SSLContext if available.""" - return ( - None - if self.transport is None - else self.transport.get_extra_info("sslcontext") - ) - - @under_cached_property - def peername( - self, - ) -> Optional[Union[str, Tuple[str, int, int, int], Tuple[str, int]]]: - """Return peername if available.""" - return ( - None - if self.transport is None - else self.transport.get_extra_info("peername") - ) - - @property - def keepalive_timeout(self) -> float: - return self._keepalive_timeout - - async def shutdown(self, timeout: Optional[float] = 15.0) -> None: - """Do worker process exit preparations. - - We need to clean up everything and stop accepting requests. - It is especially important for keep-alive connections. - """ - self._force_close = True - - if self._keepalive_handle is not None: - self._keepalive_handle.cancel() - - # Wait for graceful handler completion - if self._request_in_progress: - # The future is only created when we are shutting - # down while the handler is still processing a request - # to avoid creating a future for every request. - self._handler_waiter = self._loop.create_future() - try: - async with ceil_timeout(timeout): - await self._handler_waiter - except (asyncio.CancelledError, asyncio.TimeoutError): - self._handler_waiter = None - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - # Then cancel handler and wait - try: - async with ceil_timeout(timeout): - if self._current_request is not None: - self._current_request._cancel(asyncio.CancelledError()) - - if self._task_handler is not None and not self._task_handler.done(): - await asyncio.shield(self._task_handler) - except (asyncio.CancelledError, asyncio.TimeoutError): - if ( - sys.version_info >= (3, 11) - and (task := asyncio.current_task()) - and task.cancelling() - ): - raise - - # force-close non-idle handler - if self._task_handler is not None: - self._task_handler.cancel() - - self.force_close() - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - super().connection_made(transport) - - real_transport = cast(asyncio.Transport, transport) - if self._tcp_keepalive: - tcp_keepalive(real_transport) - - assert self._manager is not None - self._manager.connection_made(self, real_transport) - - loop = self._loop - if sys.version_info >= (3, 12): - task = asyncio.Task(self.start(), loop=loop, eager_start=True) - else: - task = loop.create_task(self.start()) - self._task_handler = task - - def connection_lost(self, exc: Optional[BaseException]) -> None: - if self._manager is None: - return - self._manager.connection_lost(self, exc) - - # Grab value before setting _manager to None. - handler_cancellation = self._manager.handler_cancellation - - self.force_close() - super().connection_lost(exc) - self._manager = None - self._request_factory = None - self._request_handler = None - self._request_parser = None - - if self._keepalive_handle is not None: - self._keepalive_handle.cancel() - - if self._current_request is not None: - if exc is None: - exc = ConnectionResetError("Connection lost") - self._current_request._cancel(exc) - - if handler_cancellation and self._task_handler is not None: - self._task_handler.cancel() - - self._task_handler = None - - if self._payload_parser is not None: - self._payload_parser.feed_eof() - self._payload_parser = None - - def set_parser(self, parser: Any) -> None: - # Actual type is WebReader - assert self._payload_parser is None - - self._payload_parser = parser - - if self._message_tail: - self._payload_parser.feed_data(self._message_tail) - self._message_tail = b"" - - def eof_received(self) -> None: - pass - - def data_received(self, data: bytes) -> None: - if self._force_close or self._close: - return - # parse http messages - messages: Sequence[_MsgType] - if self._payload_parser is None and not self._upgrade: - assert self._request_parser is not None - try: - messages, upgraded, tail = self._request_parser.feed_data(data) - except HttpProcessingError as exc: - messages = [ - (_ErrInfo(status=400, exc=exc, message=exc.message), EMPTY_PAYLOAD) - ] - upgraded = False - tail = b"" - - for msg, payload in messages or (): - self._request_count += 1 - self._messages.append((msg, payload)) - - waiter = self._waiter - if messages and waiter is not None and not waiter.done(): - # don't set result twice - waiter.set_result(None) - - self._upgrade = upgraded - if upgraded and tail: - self._message_tail = tail - - # no parser, just store - elif self._payload_parser is None and self._upgrade and data: - self._message_tail += data - - # feed payload - elif data: - eof, tail = self._payload_parser.feed_data(data) - if eof: - self.close() - - def keep_alive(self, val: bool) -> None: - """Set keep-alive connection mode. - - :param bool val: new state. - """ - self._keepalive = val - if self._keepalive_handle: - self._keepalive_handle.cancel() - self._keepalive_handle = None - - def close(self) -> None: - """Close connection. - - Stop accepting new pipelining messages and close - connection when handlers done processing messages. - """ - self._close = True - if self._waiter: - self._waiter.cancel() - - def force_close(self) -> None: - """Forcefully close connection.""" - self._force_close = True - if self._waiter: - self._waiter.cancel() - if self.transport is not None: - self.transport.close() - self.transport = None - - def log_access( - self, request: BaseRequest, response: StreamResponse, time: Optional[float] - ) -> None: - if self._logging_enabled and self.access_logger is not None: - if TYPE_CHECKING: - assert time is not None - self.access_logger.log(request, response, self._loop.time() - time) - - def log_debug(self, *args: Any, **kw: Any) -> None: - if self.debug: - self.logger.debug(*args, **kw) - - def log_exception(self, *args: Any, **kw: Any) -> None: - self.logger.exception(*args, **kw) - - def _process_keepalive(self) -> None: - self._keepalive_handle = None - if self._force_close or not self._keepalive: - return - - loop = self._loop - now = loop.time() - close_time = self._next_keepalive_close_time - if now < close_time: - # Keep alive close check fired too early, reschedule - self._keepalive_handle = loop.call_at(close_time, self._process_keepalive) - return - - # handler in idle state - if self._waiter and not self._waiter.done(): - self.force_close() - - async def _handle_request( - self, - request: BaseRequest, - start_time: Optional[float], - request_handler: Callable[[BaseRequest], Awaitable[StreamResponse]], - ) -> Tuple[StreamResponse, bool]: - self._request_in_progress = True - try: - try: - self._current_request = request - resp = await request_handler(request) - finally: - self._current_request = None - except HTTPException as exc: - resp = exc - resp, reset = await self.finish_response(request, resp, start_time) - except asyncio.CancelledError: - raise - except asyncio.TimeoutError as exc: - self.log_debug("Request handler timed out.", exc_info=exc) - resp = self.handle_error(request, 504) - resp, reset = await self.finish_response(request, resp, start_time) - except Exception as exc: - resp = self.handle_error(request, 500, exc) - resp, reset = await self.finish_response(request, resp, start_time) - else: - # Deprecation warning (See #2415) - if getattr(resp, "__http_exception__", False): - warnings.warn( - "returning HTTPException object is deprecated " - "(#2415) and will be removed, " - "please raise the exception instead", - DeprecationWarning, - ) - - resp, reset = await self.finish_response(request, resp, start_time) - finally: - self._request_in_progress = False - if self._handler_waiter is not None: - self._handler_waiter.set_result(None) - - return resp, reset - - async def start(self) -> None: - """Process incoming request. - - It reads request line, request headers and request payload, then - calls handle_request() method. Subclass has to override - handle_request(). start() handles various exceptions in request - or response handling. Connection is being closed always unless - keep_alive(True) specified. - """ - loop = self._loop - manager = self._manager - assert manager is not None - keepalive_timeout = self._keepalive_timeout - resp = None - assert self._request_factory is not None - assert self._request_handler is not None - - while not self._force_close: - if not self._messages: - try: - # wait for next request - self._waiter = loop.create_future() - await self._waiter - finally: - self._waiter = None - - message, payload = self._messages.popleft() - - # time is only fetched if logging is enabled as otherwise - # its thrown away and never used. - start = loop.time() if self._logging_enabled else None - - manager.requests_count += 1 - writer = StreamWriter(self, loop) - if isinstance(message, _ErrInfo): - # make request_factory work - request_handler = self._make_error_handler(message) - message = ERROR - else: - request_handler = self._request_handler - - # Important don't hold a reference to the current task - # as on traceback it will prevent the task from being - # collected and will cause a memory leak. - request = self._request_factory( - message, - payload, - self, - writer, - self._task_handler or asyncio.current_task(loop), # type: ignore[arg-type] - ) - try: - # a new task is used for copy context vars (#3406) - coro = self._handle_request(request, start, request_handler) - if sys.version_info >= (3, 12): - task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - task = loop.create_task(coro) - try: - resp, reset = await task - except ConnectionError: - self.log_debug("Ignored premature client disconnection") - break - - # Drop the processed task from asyncio.Task.all_tasks() early - del task - if reset: - self.log_debug("Ignored premature client disconnection 2") - break - - # notify server about keep-alive - self._keepalive = bool(resp.keep_alive) - - # check payload - if not payload.is_eof(): - lingering_time = self._lingering_time - if not self._force_close and lingering_time: - self.log_debug( - "Start lingering close timer for %s sec.", lingering_time - ) - - now = loop.time() - end_t = now + lingering_time - - try: - while not payload.is_eof() and now < end_t: - async with ceil_timeout(end_t - now): - # read and ignore - await payload.readany() - now = loop.time() - except (asyncio.CancelledError, asyncio.TimeoutError): - if ( - sys.version_info >= (3, 11) - and (t := asyncio.current_task()) - and t.cancelling() - ): - raise - - # if payload still uncompleted - if not payload.is_eof() and not self._force_close: - self.log_debug("Uncompleted request.") - self.close() - - payload.set_exception(_PAYLOAD_ACCESS_ERROR) - - except asyncio.CancelledError: - self.log_debug("Ignored premature client disconnection") - self.force_close() - raise - except Exception as exc: - self.log_exception("Unhandled exception", exc_info=exc) - self.force_close() - except BaseException: - self.force_close() - raise - finally: - request._task = None # type: ignore[assignment] # Break reference cycle in case of exception - if self.transport is None and resp is not None: - self.log_debug("Ignored premature client disconnection.") - - if self._keepalive and not self._close and not self._force_close: - # start keep-alive timer - close_time = loop.time() + keepalive_timeout - self._next_keepalive_close_time = close_time - if self._keepalive_handle is None: - self._keepalive_handle = loop.call_at( - close_time, self._process_keepalive - ) - else: - break - - # remove handler, close transport if no handlers left - if not self._force_close: - self._task_handler = None - if self.transport is not None: - self.transport.close() - - async def finish_response( - self, request: BaseRequest, resp: StreamResponse, start_time: Optional[float] - ) -> Tuple[StreamResponse, bool]: - """Prepare the response and write_eof, then log access. - - This has to - be called within the context of any exception so the access logger - can get exception information. Returns True if the client disconnects - prematurely. - """ - request._finish() - if self._request_parser is not None: - self._request_parser.set_upgraded(False) - self._upgrade = False - if self._message_tail: - self._request_parser.feed_data(self._message_tail) - self._message_tail = b"" - try: - prepare_meth = resp.prepare - except AttributeError: - if resp is None: - self.log_exception("Missing return statement on request handler") - else: - self.log_exception( - "Web-handler should return a response instance, " - "got {!r}".format(resp) - ) - exc = HTTPInternalServerError() - resp = Response( - status=exc.status, reason=exc.reason, text=exc.text, headers=exc.headers - ) - prepare_meth = resp.prepare - try: - await prepare_meth(request) - await resp.write_eof() - except ConnectionError: - self.log_access(request, resp, start_time) - return resp, True - - self.log_access(request, resp, start_time) - return resp, False - - def handle_error( - self, - request: BaseRequest, - status: int = 500, - exc: Optional[BaseException] = None, - message: Optional[str] = None, - ) -> StreamResponse: - """Handle errors. - - Returns HTTP response with specific status code. Logs additional - information. It always closes current connection. - """ - if self._request_count == 1 and isinstance(exc, BadHttpMethod): - # BadHttpMethod is common when a client sends non-HTTP - # or encrypted traffic to an HTTP port. This is expected - # to happen when connected to the public internet so we log - # it at the debug level as to not fill logs with noise. - self.logger.debug( - "Error handling request from %s", request.remote, exc_info=exc - ) - else: - self.log_exception( - "Error handling request from %s", request.remote, exc_info=exc - ) - - # some data already got sent, connection is broken - if request.writer.output_size > 0: - raise ConnectionError( - "Response is sent already, cannot send another response " - "with the error message" - ) - - ct = "text/plain" - if status == HTTPStatus.INTERNAL_SERVER_ERROR: - title = "{0.value} {0.phrase}".format(HTTPStatus.INTERNAL_SERVER_ERROR) - msg = HTTPStatus.INTERNAL_SERVER_ERROR.description - tb = None - if self.debug: - with suppress(Exception): - tb = traceback.format_exc() - - if "text/html" in request.headers.get("Accept", ""): - if tb: - tb = html_escape(tb) - msg = f"

Traceback:

\n
{tb}
" - message = ( - "" - "{title}" - "\n

{title}

" - "\n{msg}\n\n" - ).format(title=title, msg=msg) - ct = "text/html" - else: - if tb: - msg = tb - message = title + "\n\n" + msg - - resp = Response(status=status, text=message, content_type=ct) - resp.force_close() - - return resp - - def _make_error_handler( - self, err_info: _ErrInfo - ) -> Callable[[BaseRequest], Awaitable[StreamResponse]]: - async def handler(request: BaseRequest) -> StreamResponse: - return self.handle_error( - request, err_info.status, err_info.exc, err_info.message - ) - - return handler diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_request.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_request.py deleted file mode 100644 index 0eafcd6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_request.py +++ /dev/null @@ -1,914 +0,0 @@ -import asyncio -import datetime -import io -import re -import socket -import string -import tempfile -import types -import warnings -from types import MappingProxyType -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Final, - Iterator, - Mapping, - MutableMapping, - Optional, - Pattern, - Tuple, - Union, - cast, -) -from urllib.parse import parse_qsl - -import attr -from multidict import ( - CIMultiDict, - CIMultiDictProxy, - MultiDict, - MultiDictProxy, - MultiMapping, -) -from yarl import URL - -from . import hdrs -from ._cookie_helpers import parse_cookie_header -from .abc import AbstractStreamWriter -from .helpers import ( - _SENTINEL, - DEBUG, - ETAG_ANY, - LIST_QUOTED_ETAG_RE, - ChainMapProxy, - ETag, - HeadersMixin, - parse_http_date, - reify, - sentinel, - set_exception, -) -from .http_parser import RawRequestMessage -from .http_writer import HttpVersion -from .multipart import BodyPartReader, MultipartReader -from .streams import EmptyStreamReader, StreamReader -from .typedefs import ( - DEFAULT_JSON_DECODER, - JSONDecoder, - LooseHeaders, - RawHeaders, - StrOrURL, -) -from .web_exceptions import HTTPRequestEntityTooLarge -from .web_response import StreamResponse - -__all__ = ("BaseRequest", "FileField", "Request") - - -if TYPE_CHECKING: - from .web_app import Application - from .web_protocol import RequestHandler - from .web_urldispatcher import UrlMappingMatchInfo - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class FileField: - name: str - filename: str - file: io.BufferedReader - content_type: str - headers: CIMultiDictProxy[str] - - -_TCHAR: Final[str] = string.digits + string.ascii_letters + r"!#$%&'*+.^_`|~-" -# '-' at the end to prevent interpretation as range in a char class - -_TOKEN: Final[str] = rf"[{_TCHAR}]+" - -_QDTEXT: Final[str] = r"[{}]".format( - r"".join(chr(c) for c in (0x09, 0x20, 0x21) + tuple(range(0x23, 0x7F))) -) -# qdtext includes 0x5C to escape 0x5D ('\]') -# qdtext excludes obs-text (because obsoleted, and encoding not specified) - -_QUOTED_PAIR: Final[str] = r"\\[\t !-~]" - -_QUOTED_STRING: Final[str] = r'"(?:{quoted_pair}|{qdtext})*"'.format( - qdtext=_QDTEXT, quoted_pair=_QUOTED_PAIR -) - -_FORWARDED_PAIR: Final[str] = ( - r"({token})=({token}|{quoted_string})(:\d{{1,4}})?".format( - token=_TOKEN, quoted_string=_QUOTED_STRING - ) -) - -_QUOTED_PAIR_REPLACE_RE: Final[Pattern[str]] = re.compile(r"\\([\t !-~])") -# same pattern as _QUOTED_PAIR but contains a capture group - -_FORWARDED_PAIR_RE: Final[Pattern[str]] = re.compile(_FORWARDED_PAIR) - -############################################################ -# HTTP Request -############################################################ - - -class BaseRequest(MutableMapping[str, Any], HeadersMixin): - - POST_METHODS = { - hdrs.METH_PATCH, - hdrs.METH_POST, - hdrs.METH_PUT, - hdrs.METH_TRACE, - hdrs.METH_DELETE, - } - - ATTRS = HeadersMixin.ATTRS | frozenset( - [ - "_message", - "_protocol", - "_payload_writer", - "_payload", - "_headers", - "_method", - "_version", - "_rel_url", - "_post", - "_read_bytes", - "_state", - "_cache", - "_task", - "_client_max_size", - "_loop", - "_transport_sslcontext", - "_transport_peername", - ] - ) - _post: Optional[MultiDictProxy[Union[str, bytes, FileField]]] = None - _read_bytes: Optional[bytes] = None - - def __init__( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: "RequestHandler", - payload_writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - loop: asyncio.AbstractEventLoop, - *, - client_max_size: int = 1024**2, - state: Optional[Dict[str, Any]] = None, - scheme: Optional[str] = None, - host: Optional[str] = None, - remote: Optional[str] = None, - ) -> None: - self._message = message - self._protocol = protocol - self._payload_writer = payload_writer - - self._payload = payload - self._headers: CIMultiDictProxy[str] = message.headers - self._method = message.method - self._version = message.version - self._cache: Dict[str, Any] = {} - url = message.url - if url.absolute: - if scheme is not None: - url = url.with_scheme(scheme) - if host is not None: - url = url.with_host(host) - # absolute URL is given, - # override auto-calculating url, host, and scheme - # all other properties should be good - self._cache["url"] = url - self._cache["host"] = url.host - self._cache["scheme"] = url.scheme - self._rel_url = url.relative() - else: - self._rel_url = url - if scheme is not None: - self._cache["scheme"] = scheme - if host is not None: - self._cache["host"] = host - - self._state = {} if state is None else state - self._task = task - self._client_max_size = client_max_size - self._loop = loop - - self._transport_sslcontext = protocol.ssl_context - self._transport_peername = protocol.peername - - if remote is not None: - self._cache["remote"] = remote - - def clone( - self, - *, - method: Union[str, _SENTINEL] = sentinel, - rel_url: Union[StrOrURL, _SENTINEL] = sentinel, - headers: Union[LooseHeaders, _SENTINEL] = sentinel, - scheme: Union[str, _SENTINEL] = sentinel, - host: Union[str, _SENTINEL] = sentinel, - remote: Union[str, _SENTINEL] = sentinel, - client_max_size: Union[int, _SENTINEL] = sentinel, - ) -> "BaseRequest": - """Clone itself with replacement some attributes. - - Creates and returns a new instance of Request object. If no parameters - are given, an exact copy is returned. If a parameter is not passed, it - will reuse the one from the current request object. - """ - if self._read_bytes: - raise RuntimeError("Cannot clone request after reading its content") - - dct: Dict[str, Any] = {} - if method is not sentinel: - dct["method"] = method - if rel_url is not sentinel: - new_url: URL = URL(rel_url) - dct["url"] = new_url - dct["path"] = str(new_url) - if headers is not sentinel: - # a copy semantic - dct["headers"] = CIMultiDictProxy(CIMultiDict(headers)) - dct["raw_headers"] = tuple( - (k.encode("utf-8"), v.encode("utf-8")) - for k, v in dct["headers"].items() - ) - - message = self._message._replace(**dct) - - kwargs = {} - if scheme is not sentinel: - kwargs["scheme"] = scheme - if host is not sentinel: - kwargs["host"] = host - if remote is not sentinel: - kwargs["remote"] = remote - if client_max_size is sentinel: - client_max_size = self._client_max_size - - return self.__class__( - message, - self._payload, - self._protocol, - self._payload_writer, - self._task, - self._loop, - client_max_size=client_max_size, - state=self._state.copy(), - **kwargs, - ) - - @property - def task(self) -> "asyncio.Task[None]": - return self._task - - @property - def protocol(self) -> "RequestHandler": - return self._protocol - - @property - def transport(self) -> Optional[asyncio.Transport]: - if self._protocol is None: - return None - return self._protocol.transport - - @property - def writer(self) -> AbstractStreamWriter: - return self._payload_writer - - @property - def client_max_size(self) -> int: - return self._client_max_size - - @reify - def message(self) -> RawRequestMessage: - warnings.warn("Request.message is deprecated", DeprecationWarning, stacklevel=3) - return self._message - - @reify - def rel_url(self) -> URL: - return self._rel_url - - @reify - def loop(self) -> asyncio.AbstractEventLoop: - warnings.warn( - "request.loop property is deprecated", DeprecationWarning, stacklevel=2 - ) - return self._loop - - # MutableMapping API - - def __getitem__(self, key: str) -> Any: - return self._state[key] - - def __setitem__(self, key: str, value: Any) -> None: - self._state[key] = value - - def __delitem__(self, key: str) -> None: - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[str]: - return iter(self._state) - - ######## - - @reify - def secure(self) -> bool: - """A bool indicating if the request is handled with SSL.""" - return self.scheme == "https" - - @reify - def forwarded(self) -> Tuple[Mapping[str, str], ...]: - """A tuple containing all parsed Forwarded header(s). - - Makes an effort to parse Forwarded headers as specified by RFC 7239: - - - It adds one (immutable) dictionary per Forwarded 'field-value', ie - per proxy. The element corresponds to the data in the Forwarded - field-value added by the first proxy encountered by the client. Each - subsequent item corresponds to those added by later proxies. - - It checks that every value has valid syntax in general as specified - in section 4: either a 'token' or a 'quoted-string'. - - It un-escapes found escape sequences. - - It does NOT validate 'by' and 'for' contents as specified in section - 6. - - It does NOT validate 'host' contents (Host ABNF). - - It does NOT validate 'proto' contents for valid URI scheme names. - - Returns a tuple containing one or more immutable dicts - """ - elems = [] - for field_value in self._message.headers.getall(hdrs.FORWARDED, ()): - length = len(field_value) - pos = 0 - need_separator = False - elem: Dict[str, str] = {} - elems.append(types.MappingProxyType(elem)) - while 0 <= pos < length: - match = _FORWARDED_PAIR_RE.match(field_value, pos) - if match is not None: # got a valid forwarded-pair - if need_separator: - # bad syntax here, skip to next comma - pos = field_value.find(",", pos) - else: - name, value, port = match.groups() - if value[0] == '"': - # quoted string: remove quotes and unescape - value = _QUOTED_PAIR_REPLACE_RE.sub(r"\1", value[1:-1]) - if port: - value += port - elem[name.lower()] = value - pos += len(match.group(0)) - need_separator = True - elif field_value[pos] == ",": # next forwarded-element - need_separator = False - elem = {} - elems.append(types.MappingProxyType(elem)) - pos += 1 - elif field_value[pos] == ";": # next forwarded-pair - need_separator = False - pos += 1 - elif field_value[pos] in " \t": - # Allow whitespace even between forwarded-pairs, though - # RFC 7239 doesn't. This simplifies code and is in line - # with Postel's law. - pos += 1 - else: - # bad syntax here, skip to next comma - pos = field_value.find(",", pos) - return tuple(elems) - - @reify - def scheme(self) -> str: - """A string representing the scheme of the request. - - Hostname is resolved in this order: - - - overridden value by .clone(scheme=new_scheme) call. - - type of connection to peer: HTTPS if socket is SSL, HTTP otherwise. - - 'http' or 'https'. - """ - if self._transport_sslcontext: - return "https" - else: - return "http" - - @reify - def method(self) -> str: - """Read only property for getting HTTP method. - - The value is upper-cased str like 'GET', 'POST', 'PUT' etc. - """ - return self._method - - @reify - def version(self) -> HttpVersion: - """Read only property for getting HTTP version of request. - - Returns aiohttp.protocol.HttpVersion instance. - """ - return self._version - - @reify - def host(self) -> str: - """Hostname of the request. - - Hostname is resolved in this order: - - - overridden value by .clone(host=new_host) call. - - HOST HTTP header - - socket.getfqdn() value - - For example, 'example.com' or 'localhost:8080'. - - For historical reasons, the port number may be included. - """ - host = self._message.headers.get(hdrs.HOST) - if host is not None: - return host - return socket.getfqdn() - - @reify - def remote(self) -> Optional[str]: - """Remote IP of client initiated HTTP request. - - The IP is resolved in this order: - - - overridden value by .clone(remote=new_remote) call. - - peername of opened socket - """ - if self._transport_peername is None: - return None - if isinstance(self._transport_peername, (list, tuple)): - return str(self._transport_peername[0]) - return str(self._transport_peername) - - @reify - def url(self) -> URL: - """The full URL of the request.""" - # authority is used here because it may include the port number - # and we want yarl to parse it correctly - return URL.build(scheme=self.scheme, authority=self.host).join(self._rel_url) - - @reify - def path(self) -> str: - """The URL including *PATH INFO* without the host or scheme. - - E.g., ``/app/blog`` - """ - return self._rel_url.path - - @reify - def path_qs(self) -> str: - """The URL including PATH_INFO and the query string. - - E.g, /app/blog?id=10 - """ - return str(self._rel_url) - - @reify - def raw_path(self) -> str: - """The URL including raw *PATH INFO* without the host or scheme. - - Warning, the path is unquoted and may contains non valid URL characters - - E.g., ``/my%2Fpath%7Cwith%21some%25strange%24characters`` - """ - return self._message.path - - @reify - def query(self) -> "MultiMapping[str]": - """A multidict with all the variables in the query string.""" - return self._rel_url.query - - @reify - def query_string(self) -> str: - """The query string in the URL. - - E.g., id=10 - """ - return self._rel_url.query_string - - @reify - def headers(self) -> CIMultiDictProxy[str]: - """A case-insensitive multidict proxy with all headers.""" - return self._headers - - @reify - def raw_headers(self) -> RawHeaders: - """A sequence of pairs for all headers.""" - return self._message.raw_headers - - @reify - def if_modified_since(self) -> Optional[datetime.datetime]: - """The value of If-Modified-Since HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_MODIFIED_SINCE)) - - @reify - def if_unmodified_since(self) -> Optional[datetime.datetime]: - """The value of If-Unmodified-Since HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_UNMODIFIED_SINCE)) - - @staticmethod - def _etag_values(etag_header: str) -> Iterator[ETag]: - """Extract `ETag` objects from raw header.""" - if etag_header == ETAG_ANY: - yield ETag( - is_weak=False, - value=ETAG_ANY, - ) - else: - for match in LIST_QUOTED_ETAG_RE.finditer(etag_header): - is_weak, value, garbage = match.group(2, 3, 4) - # Any symbol captured by 4th group means - # that the following sequence is invalid. - if garbage: - break - - yield ETag( - is_weak=bool(is_weak), - value=value, - ) - - @classmethod - def _if_match_or_none_impl( - cls, header_value: Optional[str] - ) -> Optional[Tuple[ETag, ...]]: - if not header_value: - return None - - return tuple(cls._etag_values(header_value)) - - @reify - def if_match(self) -> Optional[Tuple[ETag, ...]]: - """The value of If-Match HTTP header, or None. - - This header is represented as a `tuple` of `ETag` objects. - """ - return self._if_match_or_none_impl(self.headers.get(hdrs.IF_MATCH)) - - @reify - def if_none_match(self) -> Optional[Tuple[ETag, ...]]: - """The value of If-None-Match HTTP header, or None. - - This header is represented as a `tuple` of `ETag` objects. - """ - return self._if_match_or_none_impl(self.headers.get(hdrs.IF_NONE_MATCH)) - - @reify - def if_range(self) -> Optional[datetime.datetime]: - """The value of If-Range HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self.headers.get(hdrs.IF_RANGE)) - - @reify - def keep_alive(self) -> bool: - """Is keepalive enabled by client?""" - return not self._message.should_close - - @reify - def cookies(self) -> Mapping[str, str]: - """Return request cookies. - - A read-only dictionary-like object. - """ - # Use parse_cookie_header for RFC 6265 compliant Cookie header parsing - # that accepts special characters in cookie names (fixes #2683) - parsed = parse_cookie_header(self.headers.get(hdrs.COOKIE, "")) - # Extract values from Morsel objects - return MappingProxyType({name: morsel.value for name, morsel in parsed}) - - @reify - def http_range(self) -> slice: - """The content of Range HTTP header. - - Return a slice instance. - - """ - rng = self._headers.get(hdrs.RANGE) - start, end = None, None - if rng is not None: - try: - pattern = r"^bytes=(\d*)-(\d*)$" - start, end = re.findall(pattern, rng, re.ASCII)[0] - except IndexError: # pattern was not found in header - raise ValueError("range not in acceptable format") - - end = int(end) if end else None - start = int(start) if start else None - - if start is None and end is not None: - # end with no start is to return tail of content - start = -end - end = None - - if start is not None and end is not None: - # end is inclusive in range header, exclusive for slice - end += 1 - - if start >= end: - raise ValueError("start cannot be after end") - - if start is end is None: # No valid range supplied - raise ValueError("No start or end of range specified") - - return slice(start, end, 1) - - @reify - def content(self) -> StreamReader: - """Return raw payload stream.""" - return self._payload - - @property - def has_body(self) -> bool: - """Return True if request's HTTP BODY can be read, False otherwise.""" - warnings.warn( - "Deprecated, use .can_read_body #2005", DeprecationWarning, stacklevel=2 - ) - return not self._payload.at_eof() - - @property - def can_read_body(self) -> bool: - """Return True if request's HTTP BODY can be read, False otherwise.""" - return not self._payload.at_eof() - - @reify - def body_exists(self) -> bool: - """Return True if request has HTTP BODY, False otherwise.""" - return type(self._payload) is not EmptyStreamReader - - async def release(self) -> None: - """Release request. - - Eat unread part of HTTP BODY if present. - """ - while not self._payload.at_eof(): - await self._payload.readany() - - async def read(self) -> bytes: - """Read request body if present. - - Returns bytes object with full request content. - """ - if self._read_bytes is None: - body = bytearray() - while True: - chunk = await self._payload.readany() - body.extend(chunk) - if self._client_max_size: - body_size = len(body) - if body_size >= self._client_max_size: - raise HTTPRequestEntityTooLarge( - max_size=self._client_max_size, actual_size=body_size - ) - if not chunk: - break - self._read_bytes = bytes(body) - return self._read_bytes - - async def text(self) -> str: - """Return BODY as text using encoding from .charset.""" - bytes_body = await self.read() - encoding = self.charset or "utf-8" - return bytes_body.decode(encoding) - - async def json(self, *, loads: JSONDecoder = DEFAULT_JSON_DECODER) -> Any: - """Return BODY as JSON.""" - body = await self.text() - return loads(body) - - async def multipart(self) -> MultipartReader: - """Return async iterator to process BODY as multipart.""" - return MultipartReader(self._headers, self._payload) - - async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]": - """Return POST parameters.""" - if self._post is not None: - return self._post - if self._method not in self.POST_METHODS: - self._post = MultiDictProxy(MultiDict()) - return self._post - - content_type = self.content_type - if content_type not in ( - "", - "application/x-www-form-urlencoded", - "multipart/form-data", - ): - self._post = MultiDictProxy(MultiDict()) - return self._post - - out: MultiDict[Union[str, bytes, FileField]] = MultiDict() - - if content_type == "multipart/form-data": - multipart = await self.multipart() - max_size = self._client_max_size - - size = 0 - while (field := await multipart.next()) is not None: - field_ct = field.headers.get(hdrs.CONTENT_TYPE) - - if isinstance(field, BodyPartReader): - if field.name is None: - raise ValueError("Multipart field missing name.") - - # Note that according to RFC 7578, the Content-Type header - # is optional, even for files, so we can't assume it's - # present. - # https://tools.ietf.org/html/rfc7578#section-4.4 - if field.filename: - # store file in temp file - tmp = await self._loop.run_in_executor( - None, tempfile.TemporaryFile - ) - chunk = await field.read_chunk(size=2**16) - while chunk: - chunk = await field.decode(chunk) - await self._loop.run_in_executor(None, tmp.write, chunk) - size += len(chunk) - if 0 < max_size < size: - await self._loop.run_in_executor(None, tmp.close) - raise HTTPRequestEntityTooLarge( - max_size=max_size, actual_size=size - ) - chunk = await field.read_chunk(size=2**16) - await self._loop.run_in_executor(None, tmp.seek, 0) - - if field_ct is None: - field_ct = "application/octet-stream" - - ff = FileField( - field.name, - field.filename, - cast(io.BufferedReader, tmp), - field_ct, - field.headers, - ) - out.add(field.name, ff) - else: - # deal with ordinary data - value = await field.read(decode=True) - if field_ct is None or field_ct.startswith("text/"): - charset = field.get_charset(default="utf-8") - out.add(field.name, value.decode(charset)) - else: - out.add(field.name, value) - size += len(value) - if 0 < max_size < size: - raise HTTPRequestEntityTooLarge( - max_size=max_size, actual_size=size - ) - else: - raise ValueError( - "To decode nested multipart you need to use custom reader", - ) - else: - data = await self.read() - if data: - charset = self.charset or "utf-8" - out.extend( - parse_qsl( - data.rstrip().decode(charset), - keep_blank_values=True, - encoding=charset, - ) - ) - - self._post = MultiDictProxy(out) - return self._post - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """Extra info from protocol transport""" - protocol = self._protocol - if protocol is None: - return default - - transport = protocol.transport - if transport is None: - return default - - return transport.get_extra_info(name, default) - - def __repr__(self) -> str: - ascii_encodable_path = self.path.encode("ascii", "backslashreplace").decode( - "ascii" - ) - return "<{} {} {} >".format( - self.__class__.__name__, self._method, ascii_encodable_path - ) - - def __eq__(self, other: object) -> bool: - return id(self) == id(other) - - def __bool__(self) -> bool: - return True - - async def _prepare_hook(self, response: StreamResponse) -> None: - return - - def _cancel(self, exc: BaseException) -> None: - set_exception(self._payload, exc) - - def _finish(self) -> None: - if self._post is None or self.content_type != "multipart/form-data": - return - - # NOTE: Release file descriptors for the - # NOTE: `tempfile.Temporaryfile`-created `_io.BufferedRandom` - # NOTE: instances of files sent within multipart request body - # NOTE: via HTTP POST request. - for file_name, file_field_object in self._post.items(): - if isinstance(file_field_object, FileField): - file_field_object.file.close() - - -class Request(BaseRequest): - - ATTRS = BaseRequest.ATTRS | frozenset(["_match_info"]) - - _match_info: Optional["UrlMappingMatchInfo"] = None - - if DEBUG: - - def __setattr__(self, name: str, val: Any) -> None: - if name not in self.ATTRS: - warnings.warn( - "Setting custom {}.{} attribute " - "is discouraged".format(self.__class__.__name__, name), - DeprecationWarning, - stacklevel=2, - ) - super().__setattr__(name, val) - - def clone( - self, - *, - method: Union[str, _SENTINEL] = sentinel, - rel_url: Union[StrOrURL, _SENTINEL] = sentinel, - headers: Union[LooseHeaders, _SENTINEL] = sentinel, - scheme: Union[str, _SENTINEL] = sentinel, - host: Union[str, _SENTINEL] = sentinel, - remote: Union[str, _SENTINEL] = sentinel, - client_max_size: Union[int, _SENTINEL] = sentinel, - ) -> "Request": - ret = super().clone( - method=method, - rel_url=rel_url, - headers=headers, - scheme=scheme, - host=host, - remote=remote, - client_max_size=client_max_size, - ) - new_ret = cast(Request, ret) - new_ret._match_info = self._match_info - return new_ret - - @reify - def match_info(self) -> "UrlMappingMatchInfo": - """Result of route resolving.""" - match_info = self._match_info - assert match_info is not None - return match_info - - @property - def app(self) -> "Application": - """Application instance.""" - match_info = self._match_info - assert match_info is not None - return match_info.current_app - - @property - def config_dict(self) -> ChainMapProxy: - match_info = self._match_info - assert match_info is not None - lst = match_info.apps - app = self.app - idx = lst.index(app) - sublist = list(reversed(lst[: idx + 1])) - return ChainMapProxy(sublist) - - async def _prepare_hook(self, response: StreamResponse) -> None: - match_info = self._match_info - if match_info is None: - return - for app in match_info._apps: - if on_response_prepare := app.on_response_prepare: - await on_response_prepare.send(self, response) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_response.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_response.py deleted file mode 100644 index e5f8b6c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_response.py +++ /dev/null @@ -1,856 +0,0 @@ -import asyncio -import collections.abc -import datetime -import enum -import json -import math -import time -import warnings -from concurrent.futures import Executor -from http import HTTPStatus -from http.cookies import SimpleCookie -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Iterator, - MutableMapping, - Optional, - Union, - cast, -) - -from multidict import CIMultiDict, istr - -from . import hdrs, payload -from .abc import AbstractStreamWriter -from .compression_utils import ZLibCompressor -from .helpers import ( - ETAG_ANY, - QUOTED_ETAG_RE, - ETag, - HeadersMixin, - must_be_empty_body, - parse_http_date, - rfc822_formatted_time, - sentinel, - should_remove_content_length, - validate_etag_value, -) -from .http import SERVER_SOFTWARE, HttpVersion10, HttpVersion11 -from .payload import Payload -from .typedefs import JSONEncoder, LooseHeaders - -REASON_PHRASES = {http_status.value: http_status.phrase for http_status in HTTPStatus} -LARGE_BODY_SIZE = 1024**2 - -__all__ = ("ContentCoding", "StreamResponse", "Response", "json_response") - - -if TYPE_CHECKING: - from .web_request import BaseRequest - - BaseClass = MutableMapping[str, Any] -else: - BaseClass = collections.abc.MutableMapping - - -# TODO(py311): Convert to StrEnum for wider use -class ContentCoding(enum.Enum): - # The content codings that we have support for. - # - # Additional registered codings are listed at: - # https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding - deflate = "deflate" - gzip = "gzip" - identity = "identity" - - -CONTENT_CODINGS = {coding.value: coding for coding in ContentCoding} - -############################################################ -# HTTP Response classes -############################################################ - - -class StreamResponse(BaseClass, HeadersMixin): - - _body: Union[None, bytes, bytearray, Payload] - _length_check = True - _body = None - _keep_alive: Optional[bool] = None - _chunked: bool = False - _compression: bool = False - _compression_strategy: Optional[int] = None - _compression_force: Optional[ContentCoding] = None - _req: Optional["BaseRequest"] = None - _payload_writer: Optional[AbstractStreamWriter] = None - _eof_sent: bool = False - _must_be_empty_body: Optional[bool] = None - _body_length = 0 - _cookies: Optional[SimpleCookie] = None - _send_headers_immediately = True - - def __init__( - self, - *, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - _real_headers: Optional[CIMultiDict[str]] = None, - ) -> None: - """Initialize a new stream response object. - - _real_headers is an internal parameter used to pass a pre-populated - headers object. It is used by the `Response` class to avoid copying - the headers when creating a new response object. It is not intended - to be used by external code. - """ - self._state: Dict[str, Any] = {} - - if _real_headers is not None: - self._headers = _real_headers - elif headers is not None: - self._headers: CIMultiDict[str] = CIMultiDict(headers) - else: - self._headers = CIMultiDict() - - self._set_status(status, reason) - - @property - def prepared(self) -> bool: - return self._eof_sent or self._payload_writer is not None - - @property - def task(self) -> "Optional[asyncio.Task[None]]": - if self._req: - return self._req.task - else: - return None - - @property - def status(self) -> int: - return self._status - - @property - def chunked(self) -> bool: - return self._chunked - - @property - def compression(self) -> bool: - return self._compression - - @property - def reason(self) -> str: - return self._reason - - def set_status( - self, - status: int, - reason: Optional[str] = None, - ) -> None: - assert ( - not self.prepared - ), "Cannot change the response status code after the headers have been sent" - self._set_status(status, reason) - - def _set_status(self, status: int, reason: Optional[str]) -> None: - self._status = int(status) - if reason is None: - reason = REASON_PHRASES.get(self._status, "") - elif "\n" in reason: - raise ValueError("Reason cannot contain \\n") - self._reason = reason - - @property - def keep_alive(self) -> Optional[bool]: - return self._keep_alive - - def force_close(self) -> None: - self._keep_alive = False - - @property - def body_length(self) -> int: - return self._body_length - - @property - def output_length(self) -> int: - warnings.warn("output_length is deprecated", DeprecationWarning) - assert self._payload_writer - return self._payload_writer.buffer_size - - def enable_chunked_encoding(self, chunk_size: Optional[int] = None) -> None: - """Enables automatic chunked transfer encoding.""" - if hdrs.CONTENT_LENGTH in self._headers: - raise RuntimeError( - "You can't enable chunked encoding when a content length is set" - ) - if chunk_size is not None: - warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) - self._chunked = True - - def enable_compression( - self, - force: Optional[Union[bool, ContentCoding]] = None, - strategy: Optional[int] = None, - ) -> None: - """Enables response compression encoding.""" - # Backwards compatibility for when force was a bool <0.17. - if isinstance(force, bool): - force = ContentCoding.deflate if force else ContentCoding.identity - warnings.warn( - "Using boolean for force is deprecated #3318", DeprecationWarning - ) - elif force is not None: - assert isinstance( - force, ContentCoding - ), "force should one of None, bool or ContentEncoding" - - self._compression = True - self._compression_force = force - self._compression_strategy = strategy - - @property - def headers(self) -> "CIMultiDict[str]": - return self._headers - - @property - def cookies(self) -> SimpleCookie: - if self._cookies is None: - self._cookies = SimpleCookie() - return self._cookies - - def set_cookie( - self, - name: str, - value: str, - *, - expires: Optional[str] = None, - domain: Optional[str] = None, - max_age: Optional[Union[int, str]] = None, - path: str = "/", - secure: Optional[bool] = None, - httponly: Optional[bool] = None, - version: Optional[str] = None, - samesite: Optional[str] = None, - partitioned: Optional[bool] = None, - ) -> None: - """Set or update response cookie. - - Sets new cookie or updates existent with new value. - Also updates only those params which are not None. - """ - if self._cookies is None: - self._cookies = SimpleCookie() - - self._cookies[name] = value - c = self._cookies[name] - - if expires is not None: - c["expires"] = expires - elif c.get("expires") == "Thu, 01 Jan 1970 00:00:00 GMT": - del c["expires"] - - if domain is not None: - c["domain"] = domain - - if max_age is not None: - c["max-age"] = str(max_age) - elif "max-age" in c: - del c["max-age"] - - c["path"] = path - - if secure is not None: - c["secure"] = secure - if httponly is not None: - c["httponly"] = httponly - if version is not None: - c["version"] = version - if samesite is not None: - c["samesite"] = samesite - - if partitioned is not None: - c["partitioned"] = partitioned - - def del_cookie( - self, - name: str, - *, - domain: Optional[str] = None, - path: str = "/", - secure: Optional[bool] = None, - httponly: Optional[bool] = None, - samesite: Optional[str] = None, - ) -> None: - """Delete cookie. - - Creates new empty expired cookie. - """ - # TODO: do we need domain/path here? - if self._cookies is not None: - self._cookies.pop(name, None) - self.set_cookie( - name, - "", - max_age=0, - expires="Thu, 01 Jan 1970 00:00:00 GMT", - domain=domain, - path=path, - secure=secure, - httponly=httponly, - samesite=samesite, - ) - - @property - def content_length(self) -> Optional[int]: - # Just a placeholder for adding setter - return super().content_length - - @content_length.setter - def content_length(self, value: Optional[int]) -> None: - if value is not None: - value = int(value) - if self._chunked: - raise RuntimeError( - "You can't set content length when chunked encoding is enable" - ) - self._headers[hdrs.CONTENT_LENGTH] = str(value) - else: - self._headers.pop(hdrs.CONTENT_LENGTH, None) - - @property - def content_type(self) -> str: - # Just a placeholder for adding setter - return super().content_type - - @content_type.setter - def content_type(self, value: str) -> None: - self.content_type # read header values if needed - self._content_type = str(value) - self._generate_content_type_header() - - @property - def charset(self) -> Optional[str]: - # Just a placeholder for adding setter - return super().charset - - @charset.setter - def charset(self, value: Optional[str]) -> None: - ctype = self.content_type # read header values if needed - if ctype == "application/octet-stream": - raise RuntimeError( - "Setting charset for application/octet-stream " - "doesn't make sense, setup content_type first" - ) - assert self._content_dict is not None - if value is None: - self._content_dict.pop("charset", None) - else: - self._content_dict["charset"] = str(value).lower() - self._generate_content_type_header() - - @property - def last_modified(self) -> Optional[datetime.datetime]: - """The value of Last-Modified HTTP header, or None. - - This header is represented as a `datetime` object. - """ - return parse_http_date(self._headers.get(hdrs.LAST_MODIFIED)) - - @last_modified.setter - def last_modified( - self, value: Optional[Union[int, float, datetime.datetime, str]] - ) -> None: - if value is None: - self._headers.pop(hdrs.LAST_MODIFIED, None) - elif isinstance(value, (int, float)): - self._headers[hdrs.LAST_MODIFIED] = time.strftime( - "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value)) - ) - elif isinstance(value, datetime.datetime): - self._headers[hdrs.LAST_MODIFIED] = time.strftime( - "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple() - ) - elif isinstance(value, str): - self._headers[hdrs.LAST_MODIFIED] = value - else: - msg = f"Unsupported type for last_modified: {type(value).__name__}" - raise TypeError(msg) - - @property - def etag(self) -> Optional[ETag]: - quoted_value = self._headers.get(hdrs.ETAG) - if not quoted_value: - return None - elif quoted_value == ETAG_ANY: - return ETag(value=ETAG_ANY) - match = QUOTED_ETAG_RE.fullmatch(quoted_value) - if not match: - return None - is_weak, value = match.group(1, 2) - return ETag( - is_weak=bool(is_weak), - value=value, - ) - - @etag.setter - def etag(self, value: Optional[Union[ETag, str]]) -> None: - if value is None: - self._headers.pop(hdrs.ETAG, None) - elif (isinstance(value, str) and value == ETAG_ANY) or ( - isinstance(value, ETag) and value.value == ETAG_ANY - ): - self._headers[hdrs.ETAG] = ETAG_ANY - elif isinstance(value, str): - validate_etag_value(value) - self._headers[hdrs.ETAG] = f'"{value}"' - elif isinstance(value, ETag) and isinstance(value.value, str): - validate_etag_value(value.value) - hdr_value = f'W/"{value.value}"' if value.is_weak else f'"{value.value}"' - self._headers[hdrs.ETAG] = hdr_value - else: - raise ValueError( - f"Unsupported etag type: {type(value)}. " - f"etag must be str, ETag or None" - ) - - def _generate_content_type_header( - self, CONTENT_TYPE: istr = hdrs.CONTENT_TYPE - ) -> None: - assert self._content_dict is not None - assert self._content_type is not None - params = "; ".join(f"{k}={v}" for k, v in self._content_dict.items()) - if params: - ctype = self._content_type + "; " + params - else: - ctype = self._content_type - self._headers[CONTENT_TYPE] = ctype - - async def _do_start_compression(self, coding: ContentCoding) -> None: - if coding is ContentCoding.identity: - return - assert self._payload_writer is not None - self._headers[hdrs.CONTENT_ENCODING] = coding.value - self._payload_writer.enable_compression( - coding.value, self._compression_strategy - ) - # Compressed payload may have different content length, - # remove the header - self._headers.popall(hdrs.CONTENT_LENGTH, None) - - async def _start_compression(self, request: "BaseRequest") -> None: - if self._compression_force: - await self._do_start_compression(self._compression_force) - return - # Encoding comparisons should be case-insensitive - # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 - accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() - for value, coding in CONTENT_CODINGS.items(): - if value in accept_encoding: - await self._do_start_compression(coding) - return - - async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: - if self._eof_sent: - return None - if self._payload_writer is not None: - return self._payload_writer - self._must_be_empty_body = must_be_empty_body(request.method, self.status) - return await self._start(request) - - async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: - self._req = request - writer = self._payload_writer = request._payload_writer - - await self._prepare_headers() - await request._prepare_hook(self) - await self._write_headers() - - return writer - - async def _prepare_headers(self) -> None: - request = self._req - assert request is not None - writer = self._payload_writer - assert writer is not None - keep_alive = self._keep_alive - if keep_alive is None: - keep_alive = request.keep_alive - self._keep_alive = keep_alive - - version = request.version - - headers = self._headers - if self._cookies: - for cookie in self._cookies.values(): - value = cookie.output(header="")[1:] - headers.add(hdrs.SET_COOKIE, value) - - if self._compression: - await self._start_compression(request) - - if self._chunked: - if version != HttpVersion11: - raise RuntimeError( - "Using chunked encoding is forbidden " - "for HTTP/{0.major}.{0.minor}".format(request.version) - ) - if not self._must_be_empty_body: - writer.enable_chunking() - headers[hdrs.TRANSFER_ENCODING] = "chunked" - elif self._length_check: # Disabled for WebSockets - writer.length = self.content_length - if writer.length is None: - if version >= HttpVersion11: - if not self._must_be_empty_body: - writer.enable_chunking() - headers[hdrs.TRANSFER_ENCODING] = "chunked" - elif not self._must_be_empty_body: - keep_alive = False - - # HTTP 1.1: https://tools.ietf.org/html/rfc7230#section-3.3.2 - # HTTP 1.0: https://tools.ietf.org/html/rfc1945#section-10.4 - if self._must_be_empty_body: - if hdrs.CONTENT_LENGTH in headers and should_remove_content_length( - request.method, self.status - ): - del headers[hdrs.CONTENT_LENGTH] - # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-10 - # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-13 - if hdrs.TRANSFER_ENCODING in headers: - del headers[hdrs.TRANSFER_ENCODING] - elif (writer.length if self._length_check else self.content_length) != 0: - # https://www.rfc-editor.org/rfc/rfc9110#section-8.3-5 - headers.setdefault(hdrs.CONTENT_TYPE, "application/octet-stream") - headers.setdefault(hdrs.DATE, rfc822_formatted_time()) - headers.setdefault(hdrs.SERVER, SERVER_SOFTWARE) - - # connection header - if hdrs.CONNECTION not in headers: - if keep_alive: - if version == HttpVersion10: - headers[hdrs.CONNECTION] = "keep-alive" - elif version == HttpVersion11: - headers[hdrs.CONNECTION] = "close" - - async def _write_headers(self) -> None: - request = self._req - assert request is not None - writer = self._payload_writer - assert writer is not None - # status line - version = request.version - status_line = f"HTTP/{version[0]}.{version[1]} {self._status} {self._reason}" - await writer.write_headers(status_line, self._headers) - # Send headers immediately if not opted into buffering - if self._send_headers_immediately: - writer.send_headers() - - async def write(self, data: Union[bytes, bytearray, memoryview]) -> None: - assert isinstance( - data, (bytes, bytearray, memoryview) - ), "data argument must be byte-ish (%r)" % type(data) - - if self._eof_sent: - raise RuntimeError("Cannot call write() after write_eof()") - if self._payload_writer is None: - raise RuntimeError("Cannot call write() before prepare()") - - await self._payload_writer.write(data) - - async def drain(self) -> None: - assert not self._eof_sent, "EOF has already been sent" - assert self._payload_writer is not None, "Response has not been started" - warnings.warn( - "drain method is deprecated, use await resp.write()", - DeprecationWarning, - stacklevel=2, - ) - await self._payload_writer.drain() - - async def write_eof(self, data: bytes = b"") -> None: - assert isinstance( - data, (bytes, bytearray, memoryview) - ), "data argument must be byte-ish (%r)" % type(data) - - if self._eof_sent: - return - - assert self._payload_writer is not None, "Response has not been started" - - await self._payload_writer.write_eof(data) - self._eof_sent = True - self._req = None - self._body_length = self._payload_writer.output_size - self._payload_writer = None - - def __repr__(self) -> str: - if self._eof_sent: - info = "eof" - elif self.prepared: - assert self._req is not None - info = f"{self._req.method} {self._req.path} " - else: - info = "not prepared" - return f"<{self.__class__.__name__} {self.reason} {info}>" - - def __getitem__(self, key: str) -> Any: - return self._state[key] - - def __setitem__(self, key: str, value: Any) -> None: - self._state[key] = value - - def __delitem__(self, key: str) -> None: - del self._state[key] - - def __len__(self) -> int: - return len(self._state) - - def __iter__(self) -> Iterator[str]: - return iter(self._state) - - def __hash__(self) -> int: - return hash(id(self)) - - def __eq__(self, other: object) -> bool: - return self is other - - def __bool__(self) -> bool: - return True - - -class Response(StreamResponse): - - _compressed_body: Optional[bytes] = None - _send_headers_immediately = False - - def __init__( - self, - *, - body: Any = None, - status: int = 200, - reason: Optional[str] = None, - text: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - content_type: Optional[str] = None, - charset: Optional[str] = None, - zlib_executor_size: Optional[int] = None, - zlib_executor: Optional[Executor] = None, - ) -> None: - if body is not None and text is not None: - raise ValueError("body and text are not allowed together") - - if headers is None: - real_headers: CIMultiDict[str] = CIMultiDict() - else: - real_headers = CIMultiDict(headers) - - if content_type is not None and "charset" in content_type: - raise ValueError("charset must not be in content_type argument") - - if text is not None: - if hdrs.CONTENT_TYPE in real_headers: - if content_type or charset: - raise ValueError( - "passing both Content-Type header and " - "content_type or charset params " - "is forbidden" - ) - else: - # fast path for filling headers - if not isinstance(text, str): - raise TypeError("text argument must be str (%r)" % type(text)) - if content_type is None: - content_type = "text/plain" - if charset is None: - charset = "utf-8" - real_headers[hdrs.CONTENT_TYPE] = content_type + "; charset=" + charset - body = text.encode(charset) - text = None - elif hdrs.CONTENT_TYPE in real_headers: - if content_type is not None or charset is not None: - raise ValueError( - "passing both Content-Type header and " - "content_type or charset params " - "is forbidden" - ) - elif content_type is not None: - if charset is not None: - content_type += "; charset=" + charset - real_headers[hdrs.CONTENT_TYPE] = content_type - - super().__init__(status=status, reason=reason, _real_headers=real_headers) - - if text is not None: - self.text = text - else: - self.body = body - - self._zlib_executor_size = zlib_executor_size - self._zlib_executor = zlib_executor - - @property - def body(self) -> Optional[Union[bytes, Payload]]: - return self._body - - @body.setter - def body(self, body: Any) -> None: - if body is None: - self._body = None - elif isinstance(body, (bytes, bytearray)): - self._body = body - else: - try: - self._body = body = payload.PAYLOAD_REGISTRY.get(body) - except payload.LookupError: - raise ValueError("Unsupported body type %r" % type(body)) - - headers = self._headers - - # set content-type - if hdrs.CONTENT_TYPE not in headers: - headers[hdrs.CONTENT_TYPE] = body.content_type - - # copy payload headers - if body.headers: - for key, value in body.headers.items(): - if key not in headers: - headers[key] = value - - self._compressed_body = None - - @property - def text(self) -> Optional[str]: - if self._body is None: - return None - # Note: When _body is a Payload (e.g. FilePayload), this may do blocking I/O - # This is generally safe as most common payloads (BytesPayload, StringPayload) - # don't do blocking I/O, but be careful with file-based payloads - return self._body.decode(self.charset or "utf-8") - - @text.setter - def text(self, text: str) -> None: - assert text is None or isinstance( - text, str - ), "text argument must be str (%r)" % type(text) - - if self.content_type == "application/octet-stream": - self.content_type = "text/plain" - if self.charset is None: - self.charset = "utf-8" - - self._body = text.encode(self.charset) - self._compressed_body = None - - @property - def content_length(self) -> Optional[int]: - if self._chunked: - return None - - if hdrs.CONTENT_LENGTH in self._headers: - return int(self._headers[hdrs.CONTENT_LENGTH]) - - if self._compressed_body is not None: - # Return length of the compressed body - return len(self._compressed_body) - elif isinstance(self._body, Payload): - # A payload without content length, or a compressed payload - return None - elif self._body is not None: - return len(self._body) - else: - return 0 - - @content_length.setter - def content_length(self, value: Optional[int]) -> None: - raise RuntimeError("Content length is set automatically") - - async def write_eof(self, data: bytes = b"") -> None: - if self._eof_sent: - return - if self._compressed_body is None: - body: Optional[Union[bytes, Payload]] = self._body - else: - body = self._compressed_body - assert not data, f"data arg is not supported, got {data!r}" - assert self._req is not None - assert self._payload_writer is not None - if body is None or self._must_be_empty_body: - await super().write_eof() - elif isinstance(self._body, Payload): - await self._body.write(self._payload_writer) - await self._body.close() - await super().write_eof() - else: - await super().write_eof(cast(bytes, body)) - - async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: - if hdrs.CONTENT_LENGTH in self._headers: - if should_remove_content_length(request.method, self.status): - del self._headers[hdrs.CONTENT_LENGTH] - elif not self._chunked: - if isinstance(self._body, Payload): - if (size := self._body.size) is not None: - self._headers[hdrs.CONTENT_LENGTH] = str(size) - else: - body_len = len(self._body) if self._body else "0" - # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-7 - if body_len != "0" or ( - self.status != 304 and request.method not in hdrs.METH_HEAD_ALL - ): - self._headers[hdrs.CONTENT_LENGTH] = str(body_len) - - return await super()._start(request) - - async def _do_start_compression(self, coding: ContentCoding) -> None: - if self._chunked or isinstance(self._body, Payload): - return await super()._do_start_compression(coding) - if coding is ContentCoding.identity: - return - # Instead of using _payload_writer.enable_compression, - # compress the whole body - compressor = ZLibCompressor( - encoding=coding.value, - max_sync_chunk_size=self._zlib_executor_size, - executor=self._zlib_executor, - ) - assert self._body is not None - if self._zlib_executor_size is None and len(self._body) > LARGE_BODY_SIZE: - warnings.warn( - "Synchronous compression of large response bodies " - f"({len(self._body)} bytes) might block the async event loop. " - "Consider providing a custom value to zlib_executor_size/" - "zlib_executor response properties or disabling compression on it." - ) - self._compressed_body = ( - await compressor.compress(self._body) + compressor.flush() - ) - self._headers[hdrs.CONTENT_ENCODING] = coding.value - self._headers[hdrs.CONTENT_LENGTH] = str(len(self._compressed_body)) - - -def json_response( - data: Any = sentinel, - *, - text: Optional[str] = None, - body: Optional[bytes] = None, - status: int = 200, - reason: Optional[str] = None, - headers: Optional[LooseHeaders] = None, - content_type: str = "application/json", - dumps: JSONEncoder = json.dumps, -) -> Response: - if data is not sentinel: - if text or body: - raise ValueError("only one of data, text, or body should be specified") - else: - text = dumps(data) - return Response( - text=text, - body=body, - status=status, - reason=reason, - headers=headers, - content_type=content_type, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_routedef.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_routedef.py deleted file mode 100644 index f51b6cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_routedef.py +++ /dev/null @@ -1,214 +0,0 @@ -import abc -import os # noqa -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Iterator, - List, - Optional, - Sequence, - Type, - Union, - overload, -) - -import attr - -from . import hdrs -from .abc import AbstractView -from .typedefs import Handler, PathLike - -if TYPE_CHECKING: - from .web_request import Request - from .web_response import StreamResponse - from .web_urldispatcher import AbstractRoute, UrlDispatcher -else: - Request = StreamResponse = UrlDispatcher = AbstractRoute = None - - -__all__ = ( - "AbstractRouteDef", - "RouteDef", - "StaticDef", - "RouteTableDef", - "head", - "options", - "get", - "post", - "patch", - "put", - "delete", - "route", - "view", - "static", -) - - -class AbstractRouteDef(abc.ABC): - @abc.abstractmethod - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - pass # pragma: no cover - - -_HandlerType = Union[Type[AbstractView], Handler] - - -@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) -class RouteDef(AbstractRouteDef): - method: str - path: str - handler: _HandlerType - kwargs: Dict[str, Any] - - def __repr__(self) -> str: - info = [] - for name, value in sorted(self.kwargs.items()): - info.append(f", {name}={value!r}") - return " {handler.__name__!r}{info}>".format( - method=self.method, path=self.path, handler=self.handler, info="".join(info) - ) - - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - if self.method in hdrs.METH_ALL: - reg = getattr(router, "add_" + self.method.lower()) - return [reg(self.path, self.handler, **self.kwargs)] - else: - return [ - router.add_route(self.method, self.path, self.handler, **self.kwargs) - ] - - -@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) -class StaticDef(AbstractRouteDef): - prefix: str - path: PathLike - kwargs: Dict[str, Any] - - def __repr__(self) -> str: - info = [] - for name, value in sorted(self.kwargs.items()): - info.append(f", {name}={value!r}") - return " {path}{info}>".format( - prefix=self.prefix, path=self.path, info="".join(info) - ) - - def register(self, router: UrlDispatcher) -> List[AbstractRoute]: - resource = router.add_static(self.prefix, self.path, **self.kwargs) - routes = resource.get_info().get("routes", {}) - return list(routes.values()) - - -def route(method: str, path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return RouteDef(method, path, handler, kwargs) - - -def head(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_HEAD, path, handler, **kwargs) - - -def options(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_OPTIONS, path, handler, **kwargs) - - -def get( - path: str, - handler: _HandlerType, - *, - name: Optional[str] = None, - allow_head: bool = True, - **kwargs: Any, -) -> RouteDef: - return route( - hdrs.METH_GET, path, handler, name=name, allow_head=allow_head, **kwargs - ) - - -def post(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_POST, path, handler, **kwargs) - - -def put(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_PUT, path, handler, **kwargs) - - -def patch(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_PATCH, path, handler, **kwargs) - - -def delete(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: - return route(hdrs.METH_DELETE, path, handler, **kwargs) - - -def view(path: str, handler: Type[AbstractView], **kwargs: Any) -> RouteDef: - return route(hdrs.METH_ANY, path, handler, **kwargs) - - -def static(prefix: str, path: PathLike, **kwargs: Any) -> StaticDef: - return StaticDef(prefix, path, kwargs) - - -_Deco = Callable[[_HandlerType], _HandlerType] - - -class RouteTableDef(Sequence[AbstractRouteDef]): - """Route definition table""" - - def __init__(self) -> None: - self._items: List[AbstractRouteDef] = [] - - def __repr__(self) -> str: - return f"" - - @overload - def __getitem__(self, index: int) -> AbstractRouteDef: ... - - @overload - def __getitem__(self, index: slice) -> List[AbstractRouteDef]: ... - - def __getitem__(self, index): # type: ignore[no-untyped-def] - return self._items[index] - - def __iter__(self) -> Iterator[AbstractRouteDef]: - return iter(self._items) - - def __len__(self) -> int: - return len(self._items) - - def __contains__(self, item: object) -> bool: - return item in self._items - - def route(self, method: str, path: str, **kwargs: Any) -> _Deco: - def inner(handler: _HandlerType) -> _HandlerType: - self._items.append(RouteDef(method, path, handler, kwargs)) - return handler - - return inner - - def head(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_HEAD, path, **kwargs) - - def get(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_GET, path, **kwargs) - - def post(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_POST, path, **kwargs) - - def put(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_PUT, path, **kwargs) - - def patch(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_PATCH, path, **kwargs) - - def delete(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_DELETE, path, **kwargs) - - def options(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_OPTIONS, path, **kwargs) - - def view(self, path: str, **kwargs: Any) -> _Deco: - return self.route(hdrs.METH_ANY, path, **kwargs) - - def static(self, prefix: str, path: PathLike, **kwargs: Any) -> None: - self._items.append(StaticDef(prefix, path, kwargs)) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_runner.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_runner.py deleted file mode 100644 index bcfec72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_runner.py +++ /dev/null @@ -1,399 +0,0 @@ -import asyncio -import signal -import socket -import warnings -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, List, Optional, Set - -from yarl import URL - -from .typedefs import PathLike -from .web_app import Application -from .web_server import Server - -if TYPE_CHECKING: - from ssl import SSLContext -else: - try: - from ssl import SSLContext - except ImportError: # pragma: no cover - SSLContext = object # type: ignore[misc,assignment] - -__all__ = ( - "BaseSite", - "TCPSite", - "UnixSite", - "NamedPipeSite", - "SockSite", - "BaseRunner", - "AppRunner", - "ServerRunner", - "GracefulExit", -) - - -class GracefulExit(SystemExit): - code = 1 - - -def _raise_graceful_exit() -> None: - raise GracefulExit() - - -class BaseSite(ABC): - __slots__ = ("_runner", "_ssl_context", "_backlog", "_server") - - def __init__( - self, - runner: "BaseRunner", - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - if runner.server is None: - raise RuntimeError("Call runner.setup() before making a site") - if shutdown_timeout != 60.0: - msg = "shutdown_timeout should be set on BaseRunner" - warnings.warn(msg, DeprecationWarning, stacklevel=2) - runner._shutdown_timeout = shutdown_timeout - self._runner = runner - self._ssl_context = ssl_context - self._backlog = backlog - self._server: Optional[asyncio.AbstractServer] = None - - @property - @abstractmethod - def name(self) -> str: - pass # pragma: no cover - - @abstractmethod - async def start(self) -> None: - self._runner._reg_site(self) - - async def stop(self) -> None: - self._runner._check_site(self) - if self._server is not None: # Maybe not started yet - self._server.close() - - self._runner._unreg_site(self) - - -class TCPSite(BaseSite): - __slots__ = ("_host", "_port", "_reuse_address", "_reuse_port") - - def __init__( - self, - runner: "BaseRunner", - host: Optional[str] = None, - port: Optional[int] = None, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - reuse_address: Optional[bool] = None, - reuse_port: Optional[bool] = None, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._host = host - if port is None: - port = 8443 if self._ssl_context else 8080 - self._port = port - self._reuse_address = reuse_address - self._reuse_port = reuse_port - - @property - def name(self) -> str: - scheme = "https" if self._ssl_context else "http" - host = "0.0.0.0" if not self._host else self._host - return str(URL.build(scheme=scheme, host=host, port=self._port)) - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_server( - server, - self._host, - self._port, - ssl=self._ssl_context, - backlog=self._backlog, - reuse_address=self._reuse_address, - reuse_port=self._reuse_port, - ) - - -class UnixSite(BaseSite): - __slots__ = ("_path",) - - def __init__( - self, - runner: "BaseRunner", - path: PathLike, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._path = path - - @property - def name(self) -> str: - scheme = "https" if self._ssl_context else "http" - return f"{scheme}://unix:{self._path}:" - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_unix_server( - server, - self._path, - ssl=self._ssl_context, - backlog=self._backlog, - ) - - -class NamedPipeSite(BaseSite): - __slots__ = ("_path",) - - def __init__( - self, runner: "BaseRunner", path: str, *, shutdown_timeout: float = 60.0 - ) -> None: - loop = asyncio.get_event_loop() - if not isinstance( - loop, asyncio.ProactorEventLoop # type: ignore[attr-defined] - ): - raise RuntimeError( - "Named Pipes only available in proactor loop under windows" - ) - super().__init__(runner, shutdown_timeout=shutdown_timeout) - self._path = path - - @property - def name(self) -> str: - return self._path - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - _server = await loop.start_serving_pipe( # type: ignore[attr-defined] - server, self._path - ) - self._server = _server[0] - - -class SockSite(BaseSite): - __slots__ = ("_sock", "_name") - - def __init__( - self, - runner: "BaseRunner", - sock: socket.socket, - *, - shutdown_timeout: float = 60.0, - ssl_context: Optional[SSLContext] = None, - backlog: int = 128, - ) -> None: - super().__init__( - runner, - shutdown_timeout=shutdown_timeout, - ssl_context=ssl_context, - backlog=backlog, - ) - self._sock = sock - scheme = "https" if self._ssl_context else "http" - if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: - name = f"{scheme}://unix:{sock.getsockname()}:" - else: - host, port = sock.getsockname()[:2] - name = str(URL.build(scheme=scheme, host=host, port=port)) - self._name = name - - @property - def name(self) -> str: - return self._name - - async def start(self) -> None: - await super().start() - loop = asyncio.get_event_loop() - server = self._runner.server - assert server is not None - self._server = await loop.create_server( - server, sock=self._sock, ssl=self._ssl_context, backlog=self._backlog - ) - - -class BaseRunner(ABC): - __slots__ = ("_handle_signals", "_kwargs", "_server", "_sites", "_shutdown_timeout") - - def __init__( - self, - *, - handle_signals: bool = False, - shutdown_timeout: float = 60.0, - **kwargs: Any, - ) -> None: - self._handle_signals = handle_signals - self._kwargs = kwargs - self._server: Optional[Server] = None - self._sites: List[BaseSite] = [] - self._shutdown_timeout = shutdown_timeout - - @property - def server(self) -> Optional[Server]: - return self._server - - @property - def addresses(self) -> List[Any]: - ret: List[Any] = [] - for site in self._sites: - server = site._server - if server is not None: - sockets = server.sockets # type: ignore[attr-defined] - if sockets is not None: - for sock in sockets: - ret.append(sock.getsockname()) - return ret - - @property - def sites(self) -> Set[BaseSite]: - return set(self._sites) - - async def setup(self) -> None: - loop = asyncio.get_event_loop() - - if self._handle_signals: - try: - loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit) - loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit) - except NotImplementedError: # pragma: no cover - # add_signal_handler is not implemented on Windows - pass - - self._server = await self._make_server() - - @abstractmethod - async def shutdown(self) -> None: - """Call any shutdown hooks to help server close gracefully.""" - - async def cleanup(self) -> None: - # The loop over sites is intentional, an exception on gather() - # leaves self._sites in unpredictable state. - # The loop guaranties that a site is either deleted on success or - # still present on failure - for site in list(self._sites): - await site.stop() - - if self._server: # If setup succeeded - # Yield to event loop to ensure incoming requests prior to stopping the sites - # have all started to be handled before we proceed to close idle connections. - await asyncio.sleep(0) - self._server.pre_shutdown() - await self.shutdown() - await self._server.shutdown(self._shutdown_timeout) - await self._cleanup_server() - - self._server = None - if self._handle_signals: - loop = asyncio.get_running_loop() - try: - loop.remove_signal_handler(signal.SIGINT) - loop.remove_signal_handler(signal.SIGTERM) - except NotImplementedError: # pragma: no cover - # remove_signal_handler is not implemented on Windows - pass - - @abstractmethod - async def _make_server(self) -> Server: - pass # pragma: no cover - - @abstractmethod - async def _cleanup_server(self) -> None: - pass # pragma: no cover - - def _reg_site(self, site: BaseSite) -> None: - if site in self._sites: - raise RuntimeError(f"Site {site} is already registered in runner {self}") - self._sites.append(site) - - def _check_site(self, site: BaseSite) -> None: - if site not in self._sites: - raise RuntimeError(f"Site {site} is not registered in runner {self}") - - def _unreg_site(self, site: BaseSite) -> None: - if site not in self._sites: - raise RuntimeError(f"Site {site} is not registered in runner {self}") - self._sites.remove(site) - - -class ServerRunner(BaseRunner): - """Low-level web server runner""" - - __slots__ = ("_web_server",) - - def __init__( - self, web_server: Server, *, handle_signals: bool = False, **kwargs: Any - ) -> None: - super().__init__(handle_signals=handle_signals, **kwargs) - self._web_server = web_server - - async def shutdown(self) -> None: - pass - - async def _make_server(self) -> Server: - return self._web_server - - async def _cleanup_server(self) -> None: - pass - - -class AppRunner(BaseRunner): - """Web Application runner""" - - __slots__ = ("_app",) - - def __init__( - self, app: Application, *, handle_signals: bool = False, **kwargs: Any - ) -> None: - super().__init__(handle_signals=handle_signals, **kwargs) - if not isinstance(app, Application): - raise TypeError( - "The first argument should be web.Application " - "instance, got {!r}".format(app) - ) - self._app = app - - @property - def app(self) -> Application: - return self._app - - async def shutdown(self) -> None: - await self._app.shutdown() - - async def _make_server(self) -> Server: - loop = asyncio.get_event_loop() - self._app._set_loop(loop) - self._app.on_startup.freeze() - await self._app.startup() - self._app.freeze() - - return self._app._make_handler(loop=loop, **self._kwargs) - - async def _cleanup_server(self) -> None: - await self._app.cleanup() diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_server.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_server.py deleted file mode 100644 index 328aca1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_server.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Low level HTTP server.""" - -import asyncio -from typing import Any, Awaitable, Callable, Dict, List, Optional # noqa - -from .abc import AbstractStreamWriter -from .http_parser import RawRequestMessage -from .streams import StreamReader -from .web_protocol import RequestHandler, _RequestFactory, _RequestHandler -from .web_request import BaseRequest - -__all__ = ("Server",) - - -class Server: - def __init__( - self, - handler: _RequestHandler, - *, - request_factory: Optional[_RequestFactory] = None, - handler_cancellation: bool = False, - loop: Optional[asyncio.AbstractEventLoop] = None, - **kwargs: Any, - ) -> None: - self._loop = loop or asyncio.get_running_loop() - self._connections: Dict[RequestHandler, asyncio.Transport] = {} - self._kwargs = kwargs - # requests_count is the number of requests being processed by the server - # for the lifetime of the server. - self.requests_count = 0 - self.request_handler = handler - self.request_factory = request_factory or self._make_request - self.handler_cancellation = handler_cancellation - - @property - def connections(self) -> List[RequestHandler]: - return list(self._connections.keys()) - - def connection_made( - self, handler: RequestHandler, transport: asyncio.Transport - ) -> None: - self._connections[handler] = transport - - def connection_lost( - self, handler: RequestHandler, exc: Optional[BaseException] = None - ) -> None: - if handler in self._connections: - if handler._task_handler: - handler._task_handler.add_done_callback( - lambda f: self._connections.pop(handler, None) - ) - else: - del self._connections[handler] - - def _make_request( - self, - message: RawRequestMessage, - payload: StreamReader, - protocol: RequestHandler, - writer: AbstractStreamWriter, - task: "asyncio.Task[None]", - ) -> BaseRequest: - return BaseRequest(message, payload, protocol, writer, task, self._loop) - - def pre_shutdown(self) -> None: - for conn in self._connections: - conn.close() - - async def shutdown(self, timeout: Optional[float] = None) -> None: - coros = (conn.shutdown(timeout) for conn in self._connections) - await asyncio.gather(*coros) - self._connections.clear() - - def __call__(self) -> RequestHandler: - try: - return RequestHandler(self, loop=self._loop, **self._kwargs) - except TypeError: - # Failsafe creation: remove all custom handler_args - kwargs = { - k: v - for k, v in self._kwargs.items() - if k in ["debug", "access_log_class"] - } - return RequestHandler(self, loop=self._loop, **kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py deleted file mode 100644 index cfa57a3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py +++ /dev/null @@ -1,1305 +0,0 @@ -import abc -import asyncio -import base64 -import functools -import hashlib -import html -import inspect -import keyword -import os -import platform -import re -import sys -import warnings -from functools import wraps -from pathlib import Path -from types import MappingProxyType -from typing import ( - TYPE_CHECKING, - Any, - Awaitable, - Callable, - Container, - Dict, - Final, - Generator, - Iterable, - Iterator, - List, - Mapping, - NoReturn, - Optional, - Pattern, - Set, - Sized, - Tuple, - Type, - TypedDict, - Union, - cast, -) - -from yarl import URL, __version__ as yarl_version - -from . import hdrs -from .abc import AbstractMatchInfo, AbstractRouter, AbstractView -from .helpers import DEBUG -from .http import HttpVersion11 -from .typedefs import Handler, PathLike -from .web_exceptions import ( - HTTPException, - HTTPExpectationFailed, - HTTPForbidden, - HTTPMethodNotAllowed, - HTTPNotFound, -) -from .web_fileresponse import FileResponse -from .web_request import Request -from .web_response import Response, StreamResponse -from .web_routedef import AbstractRouteDef - -__all__ = ( - "UrlDispatcher", - "UrlMappingMatchInfo", - "AbstractResource", - "Resource", - "PlainResource", - "DynamicResource", - "AbstractRoute", - "ResourceRoute", - "StaticResource", - "View", -) - - -if TYPE_CHECKING: - from .web_app import Application - - BaseDict = Dict[str, str] -else: - BaseDict = dict - -CIRCULAR_SYMLINK_ERROR = ( - (OSError,) - if sys.version_info < (3, 10) and sys.platform.startswith("win32") - else (RuntimeError,) if sys.version_info < (3, 13) else () -) - -YARL_VERSION: Final[Tuple[int, ...]] = tuple(map(int, yarl_version.split(".")[:2])) - -HTTP_METHOD_RE: Final[Pattern[str]] = re.compile( - r"^[0-9A-Za-z!#\$%&'\*\+\-\.\^_`\|~]+$" -) -ROUTE_RE: Final[Pattern[str]] = re.compile( - r"(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})" -) -PATH_SEP: Final[str] = re.escape("/") - -IS_WINDOWS: Final[bool] = platform.system() == "Windows" - -_ExpectHandler = Callable[[Request], Awaitable[Optional[StreamResponse]]] -_Resolve = Tuple[Optional["UrlMappingMatchInfo"], Set[str]] - -html_escape = functools.partial(html.escape, quote=True) - - -class _InfoDict(TypedDict, total=False): - path: str - - formatter: str - pattern: Pattern[str] - - directory: Path - prefix: str - routes: Mapping[str, "AbstractRoute"] - - app: "Application" - - domain: str - - rule: "AbstractRuleMatching" - - http_exception: HTTPException - - -class AbstractResource(Sized, Iterable["AbstractRoute"]): - def __init__(self, *, name: Optional[str] = None) -> None: - self._name = name - - @property - def name(self) -> Optional[str]: - return self._name - - @property - @abc.abstractmethod - def canonical(self) -> str: - """Exposes the resource's canonical path. - - For example '/foo/bar/{name}' - - """ - - @abc.abstractmethod # pragma: no branch - def url_for(self, **kwargs: str) -> URL: - """Construct url for resource with additional params.""" - - @abc.abstractmethod # pragma: no branch - async def resolve(self, request: Request) -> _Resolve: - """Resolve resource. - - Return (UrlMappingMatchInfo, allowed_methods) pair. - """ - - @abc.abstractmethod - def add_prefix(self, prefix: str) -> None: - """Add a prefix to processed URLs. - - Required for subapplications support. - """ - - @abc.abstractmethod - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - def freeze(self) -> None: - pass - - @abc.abstractmethod - def raw_match(self, path: str) -> bool: - """Perform a raw match against path""" - - -class AbstractRoute(abc.ABC): - def __init__( - self, - method: str, - handler: Union[Handler, Type[AbstractView]], - *, - expect_handler: Optional[_ExpectHandler] = None, - resource: Optional[AbstractResource] = None, - ) -> None: - - if expect_handler is None: - expect_handler = _default_expect_handler - - assert inspect.iscoroutinefunction(expect_handler) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler) - ), f"Coroutine is expected, got {expect_handler!r}" - - method = method.upper() - if not HTTP_METHOD_RE.match(method): - raise ValueError(f"{method} is not allowed HTTP method") - - assert callable(handler), handler - if inspect.iscoroutinefunction(handler) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler) - ): - pass - elif inspect.isgeneratorfunction(handler): - if TYPE_CHECKING: - assert False - warnings.warn( - "Bare generators are deprecated, use @coroutine wrapper", - DeprecationWarning, - ) - elif isinstance(handler, type) and issubclass(handler, AbstractView): - pass - else: - warnings.warn( - "Bare functions are deprecated, use async ones", DeprecationWarning - ) - - @wraps(handler) - async def handler_wrapper(request: Request) -> StreamResponse: - result = old_handler(request) # type: ignore[call-arg] - if asyncio.iscoroutine(result): - result = await result - assert isinstance(result, StreamResponse) - return result - - old_handler = handler - handler = handler_wrapper - - self._method = method - self._handler = handler - self._expect_handler = expect_handler - self._resource = resource - - @property - def method(self) -> str: - return self._method - - @property - def handler(self) -> Handler: - return self._handler - - @property - @abc.abstractmethod - def name(self) -> Optional[str]: - """Optional route's name, always equals to resource's name.""" - - @property - def resource(self) -> Optional[AbstractResource]: - return self._resource - - @abc.abstractmethod - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - @abc.abstractmethod # pragma: no branch - def url_for(self, *args: str, **kwargs: str) -> URL: - """Construct url for route with additional params.""" - - async def handle_expect_header(self, request: Request) -> Optional[StreamResponse]: - return await self._expect_handler(request) - - -class UrlMappingMatchInfo(BaseDict, AbstractMatchInfo): - - __slots__ = ("_route", "_apps", "_current_app", "_frozen") - - def __init__(self, match_dict: Dict[str, str], route: AbstractRoute) -> None: - super().__init__(match_dict) - self._route = route - self._apps: List[Application] = [] - self._current_app: Optional[Application] = None - self._frozen = False - - @property - def handler(self) -> Handler: - return self._route.handler - - @property - def route(self) -> AbstractRoute: - return self._route - - @property - def expect_handler(self) -> _ExpectHandler: - return self._route.handle_expect_header - - @property - def http_exception(self) -> Optional[HTTPException]: - return None - - def get_info(self) -> _InfoDict: # type: ignore[override] - return self._route.get_info() - - @property - def apps(self) -> Tuple["Application", ...]: - return tuple(self._apps) - - def add_app(self, app: "Application") -> None: - if self._frozen: - raise RuntimeError("Cannot change apps stack after .freeze() call") - if self._current_app is None: - self._current_app = app - self._apps.insert(0, app) - - @property - def current_app(self) -> "Application": - app = self._current_app - assert app is not None - return app - - @current_app.setter - def current_app(self, app: "Application") -> None: - if DEBUG: # pragma: no cover - if app not in self._apps: - raise RuntimeError( - "Expected one of the following apps {!r}, got {!r}".format( - self._apps, app - ) - ) - self._current_app = app - - def freeze(self) -> None: - self._frozen = True - - def __repr__(self) -> str: - return f"" - - -class MatchInfoError(UrlMappingMatchInfo): - - __slots__ = ("_exception",) - - def __init__(self, http_exception: HTTPException) -> None: - self._exception = http_exception - super().__init__({}, SystemRoute(self._exception)) - - @property - def http_exception(self) -> HTTPException: - return self._exception - - def __repr__(self) -> str: - return "".format( - self._exception.status, self._exception.reason - ) - - -async def _default_expect_handler(request: Request) -> None: - """Default handler for Expect header. - - Just send "100 Continue" to client. - raise HTTPExpectationFailed if value of header is not "100-continue" - """ - expect = request.headers.get(hdrs.EXPECT, "") - if request.version == HttpVersion11: - if expect.lower() == "100-continue": - await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n") - # Reset output_size as we haven't started the main body yet. - request.writer.output_size = 0 - else: - raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect) - - -class Resource(AbstractResource): - def __init__(self, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - self._routes: Dict[str, ResourceRoute] = {} - self._any_route: Optional[ResourceRoute] = None - self._allowed_methods: Set[str] = set() - - def add_route( - self, - method: str, - handler: Union[Type[AbstractView], Handler], - *, - expect_handler: Optional[_ExpectHandler] = None, - ) -> "ResourceRoute": - if route := self._routes.get(method, self._any_route): - raise RuntimeError( - "Added route will never be executed, " - f"method {route.method} is already " - "registered" - ) - - route_obj = ResourceRoute(method, handler, self, expect_handler=expect_handler) - self.register_route(route_obj) - return route_obj - - def register_route(self, route: "ResourceRoute") -> None: - assert isinstance( - route, ResourceRoute - ), f"Instance of Route class is required, got {route!r}" - if route.method == hdrs.METH_ANY: - self._any_route = route - self._allowed_methods.add(route.method) - self._routes[route.method] = route - - async def resolve(self, request: Request) -> _Resolve: - if (match_dict := self._match(request.rel_url.path_safe)) is None: - return None, set() - if route := self._routes.get(request.method, self._any_route): - return UrlMappingMatchInfo(match_dict, route), self._allowed_methods - return None, self._allowed_methods - - @abc.abstractmethod - def _match(self, path: str) -> Optional[Dict[str, str]]: - pass # pragma: no cover - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator["ResourceRoute"]: - return iter(self._routes.values()) - - # TODO: implement all abstract methods - - -class PlainResource(Resource): - def __init__(self, path: str, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - assert not path or path.startswith("/") - self._path = path - - @property - def canonical(self) -> str: - return self._path - - def freeze(self) -> None: - if not self._path: - self._path = "/" - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._path = prefix + self._path - - def _match(self, path: str) -> Optional[Dict[str, str]]: - # string comparison is about 10 times faster than regexp matching - if self._path == path: - return {} - return None - - def raw_match(self, path: str) -> bool: - return self._path == path - - def get_info(self) -> _InfoDict: - return {"path": self._path} - - def url_for(self) -> URL: # type: ignore[override] - return URL.build(path=self._path, encoded=True) - - def __repr__(self) -> str: - name = "'" + self.name + "' " if self.name is not None else "" - return f"" - - -class DynamicResource(Resource): - - DYN = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*)\}") - DYN_WITH_RE = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*):(?P.+)\}") - GOOD = r"[^{}/]+" - - def __init__(self, path: str, *, name: Optional[str] = None) -> None: - super().__init__(name=name) - self._orig_path = path - pattern = "" - formatter = "" - for part in ROUTE_RE.split(path): - match = self.DYN.fullmatch(part) - if match: - pattern += "(?P<{}>{})".format(match.group("var"), self.GOOD) - formatter += "{" + match.group("var") + "}" - continue - - match = self.DYN_WITH_RE.fullmatch(part) - if match: - pattern += "(?P<{var}>{re})".format(**match.groupdict()) - formatter += "{" + match.group("var") + "}" - continue - - if "{" in part or "}" in part: - raise ValueError(f"Invalid path '{path}'['{part}']") - - part = _requote_path(part) - formatter += part - pattern += re.escape(part) - - try: - compiled = re.compile(pattern) - except re.error as exc: - raise ValueError(f"Bad pattern '{pattern}': {exc}") from None - assert compiled.pattern.startswith(PATH_SEP) - assert formatter.startswith("/") - self._pattern = compiled - self._formatter = formatter - - @property - def canonical(self) -> str: - return self._formatter - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._pattern = re.compile(re.escape(prefix) + self._pattern.pattern) - self._formatter = prefix + self._formatter - - def _match(self, path: str) -> Optional[Dict[str, str]]: - match = self._pattern.fullmatch(path) - if match is None: - return None - return { - key: _unquote_path_safe(value) for key, value in match.groupdict().items() - } - - def raw_match(self, path: str) -> bool: - return self._orig_path == path - - def get_info(self) -> _InfoDict: - return {"formatter": self._formatter, "pattern": self._pattern} - - def url_for(self, **parts: str) -> URL: - url = self._formatter.format_map({k: _quote_path(v) for k, v in parts.items()}) - return URL.build(path=url, encoded=True) - - def __repr__(self) -> str: - name = "'" + self.name + "' " if self.name is not None else "" - return "".format( - name=name, formatter=self._formatter - ) - - -class PrefixResource(AbstractResource): - def __init__(self, prefix: str, *, name: Optional[str] = None) -> None: - assert not prefix or prefix.startswith("/"), prefix - assert prefix in ("", "/") or not prefix.endswith("/"), prefix - super().__init__(name=name) - self._prefix = _requote_path(prefix) - self._prefix2 = self._prefix + "/" - - @property - def canonical(self) -> str: - return self._prefix - - def add_prefix(self, prefix: str) -> None: - assert prefix.startswith("/") - assert not prefix.endswith("/") - assert len(prefix) > 1 - self._prefix = prefix + self._prefix - self._prefix2 = self._prefix + "/" - - def raw_match(self, prefix: str) -> bool: - return False - - # TODO: impl missing abstract methods - - -class StaticResource(PrefixResource): - VERSION_KEY = "v" - - def __init__( - self, - prefix: str, - directory: PathLike, - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - chunk_size: int = 256 * 1024, - show_index: bool = False, - follow_symlinks: bool = False, - append_version: bool = False, - ) -> None: - super().__init__(prefix, name=name) - try: - directory = Path(directory).expanduser().resolve(strict=True) - except FileNotFoundError as error: - raise ValueError(f"'{directory}' does not exist") from error - if not directory.is_dir(): - raise ValueError(f"'{directory}' is not a directory") - self._directory = directory - self._show_index = show_index - self._chunk_size = chunk_size - self._follow_symlinks = follow_symlinks - self._expect_handler = expect_handler - self._append_version = append_version - - self._routes = { - "GET": ResourceRoute( - "GET", self._handle, self, expect_handler=expect_handler - ), - "HEAD": ResourceRoute( - "HEAD", self._handle, self, expect_handler=expect_handler - ), - } - self._allowed_methods = set(self._routes) - - def url_for( # type: ignore[override] - self, - *, - filename: PathLike, - append_version: Optional[bool] = None, - ) -> URL: - if append_version is None: - append_version = self._append_version - filename = str(filename).lstrip("/") - - url = URL.build(path=self._prefix, encoded=True) - # filename is not encoded - if YARL_VERSION < (1, 6): - url = url / filename.replace("%", "%25") - else: - url = url / filename - - if append_version: - unresolved_path = self._directory.joinpath(filename) - try: - if self._follow_symlinks: - normalized_path = Path(os.path.normpath(unresolved_path)) - normalized_path.relative_to(self._directory) - filepath = normalized_path.resolve() - else: - filepath = unresolved_path.resolve() - filepath.relative_to(self._directory) - except (ValueError, FileNotFoundError): - # ValueError for case when path point to symlink - # with follow_symlinks is False - return url # relatively safe - if filepath.is_file(): - # TODO cache file content - # with file watcher for cache invalidation - with filepath.open("rb") as f: - file_bytes = f.read() - h = self._get_file_hash(file_bytes) - url = url.with_query({self.VERSION_KEY: h}) - return url - return url - - @staticmethod - def _get_file_hash(byte_array: bytes) -> str: - m = hashlib.sha256() # todo sha256 can be configurable param - m.update(byte_array) - b64 = base64.urlsafe_b64encode(m.digest()) - return b64.decode("ascii") - - def get_info(self) -> _InfoDict: - return { - "directory": self._directory, - "prefix": self._prefix, - "routes": self._routes, - } - - def set_options_route(self, handler: Handler) -> None: - if "OPTIONS" in self._routes: - raise RuntimeError("OPTIONS route was set already") - self._routes["OPTIONS"] = ResourceRoute( - "OPTIONS", handler, self, expect_handler=self._expect_handler - ) - self._allowed_methods.add("OPTIONS") - - async def resolve(self, request: Request) -> _Resolve: - path = request.rel_url.path_safe - method = request.method - # We normalise here to avoid matches that traverse below the static root. - # e.g. /static/../../../../home/user/webapp/static/ - norm_path = os.path.normpath(path) - if IS_WINDOWS: - norm_path = norm_path.replace("\\", "/") - if not norm_path.startswith(self._prefix2) and norm_path != self._prefix: - return None, set() - - allowed_methods = self._allowed_methods - if method not in allowed_methods: - return None, allowed_methods - - match_dict = {"filename": _unquote_path_safe(path[len(self._prefix) + 1 :])} - return (UrlMappingMatchInfo(match_dict, self._routes[method]), allowed_methods) - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator[AbstractRoute]: - return iter(self._routes.values()) - - async def _handle(self, request: Request) -> StreamResponse: - filename = request.match_info["filename"] - unresolved_path = self._directory.joinpath(filename) - loop = asyncio.get_running_loop() - return await loop.run_in_executor( - None, self._resolve_path_to_response, unresolved_path - ) - - def _resolve_path_to_response(self, unresolved_path: Path) -> StreamResponse: - """Take the unresolved path and query the file system to form a response.""" - # Check for access outside the root directory. For follow symlinks, URI - # cannot traverse out, but symlinks can. Otherwise, no access outside - # root is permitted. - try: - if self._follow_symlinks: - normalized_path = Path(os.path.normpath(unresolved_path)) - normalized_path.relative_to(self._directory) - file_path = normalized_path.resolve() - else: - file_path = unresolved_path.resolve() - file_path.relative_to(self._directory) - except (ValueError, *CIRCULAR_SYMLINK_ERROR) as error: - # ValueError is raised for the relative check. Circular symlinks - # raise here on resolving for python < 3.13. - raise HTTPNotFound() from error - - # if path is a directory, return the contents if permitted. Note the - # directory check will raise if a segment is not readable. - try: - if file_path.is_dir(): - if self._show_index: - return Response( - text=self._directory_as_html(file_path), - content_type="text/html", - ) - else: - raise HTTPForbidden() - except PermissionError as error: - raise HTTPForbidden() from error - - # Return the file response, which handles all other checks. - return FileResponse(file_path, chunk_size=self._chunk_size) - - def _directory_as_html(self, dir_path: Path) -> str: - """returns directory's index as html.""" - assert dir_path.is_dir() - - relative_path_to_dir = dir_path.relative_to(self._directory).as_posix() - index_of = f"Index of /{html_escape(relative_path_to_dir)}" - h1 = f"

{index_of}

" - - index_list = [] - dir_index = dir_path.iterdir() - for _file in sorted(dir_index): - # show file url as relative to static path - rel_path = _file.relative_to(self._directory).as_posix() - quoted_file_url = _quote_path(f"{self._prefix}/{rel_path}") - - # if file is a directory, add '/' to the end of the name - if _file.is_dir(): - file_name = f"{_file.name}/" - else: - file_name = _file.name - - index_list.append( - f'
  • {html_escape(file_name)}
  • ' - ) - ul = "
      \n{}\n
    ".format("\n".join(index_list)) - body = f"\n{h1}\n{ul}\n" - - head_str = f"\n{index_of}\n" - html = f"\n{head_str}\n{body}\n" - - return html - - def __repr__(self) -> str: - name = "'" + self.name + "'" if self.name is not None else "" - return " {directory!r}>".format( - name=name, path=self._prefix, directory=self._directory - ) - - -class PrefixedSubAppResource(PrefixResource): - def __init__(self, prefix: str, app: "Application") -> None: - super().__init__(prefix) - self._app = app - self._add_prefix_to_resources(prefix) - - def add_prefix(self, prefix: str) -> None: - super().add_prefix(prefix) - self._add_prefix_to_resources(prefix) - - def _add_prefix_to_resources(self, prefix: str) -> None: - router = self._app.router - for resource in router.resources(): - # Since the canonical path of a resource is about - # to change, we need to unindex it and then reindex - router.unindex_resource(resource) - resource.add_prefix(prefix) - router.index_resource(resource) - - def url_for(self, *args: str, **kwargs: str) -> URL: - raise RuntimeError(".url_for() is not supported by sub-application root") - - def get_info(self) -> _InfoDict: - return {"app": self._app, "prefix": self._prefix} - - async def resolve(self, request: Request) -> _Resolve: - match_info = await self._app.router.resolve(request) - match_info.add_app(self._app) - if isinstance(match_info.http_exception, HTTPMethodNotAllowed): - methods = match_info.http_exception.allowed_methods - else: - methods = set() - return match_info, methods - - def __len__(self) -> int: - return len(self._app.router.routes()) - - def __iter__(self) -> Iterator[AbstractRoute]: - return iter(self._app.router.routes()) - - def __repr__(self) -> str: - return " {app!r}>".format( - prefix=self._prefix, app=self._app - ) - - -class AbstractRuleMatching(abc.ABC): - @abc.abstractmethod # pragma: no branch - async def match(self, request: Request) -> bool: - """Return bool if the request satisfies the criteria""" - - @abc.abstractmethod # pragma: no branch - def get_info(self) -> _InfoDict: - """Return a dict with additional info useful for introspection""" - - @property - @abc.abstractmethod # pragma: no branch - def canonical(self) -> str: - """Return a str""" - - -class Domain(AbstractRuleMatching): - re_part = re.compile(r"(?!-)[a-z\d-]{1,63}(? None: - super().__init__() - self._domain = self.validation(domain) - - @property - def canonical(self) -> str: - return self._domain - - def validation(self, domain: str) -> str: - if not isinstance(domain, str): - raise TypeError("Domain must be str") - domain = domain.rstrip(".").lower() - if not domain: - raise ValueError("Domain cannot be empty") - elif "://" in domain: - raise ValueError("Scheme not supported") - url = URL("http://" + domain) - assert url.raw_host is not None - if not all(self.re_part.fullmatch(x) for x in url.raw_host.split(".")): - raise ValueError("Domain not valid") - if url.port == 80: - return url.raw_host - return f"{url.raw_host}:{url.port}" - - async def match(self, request: Request) -> bool: - host = request.headers.get(hdrs.HOST) - if not host: - return False - return self.match_domain(host) - - def match_domain(self, host: str) -> bool: - return host.lower() == self._domain - - def get_info(self) -> _InfoDict: - return {"domain": self._domain} - - -class MaskDomain(Domain): - re_part = re.compile(r"(?!-)[a-z\d\*-]{1,63}(? None: - super().__init__(domain) - mask = self._domain.replace(".", r"\.").replace("*", ".*") - self._mask = re.compile(mask) - - @property - def canonical(self) -> str: - return self._mask.pattern - - def match_domain(self, host: str) -> bool: - return self._mask.fullmatch(host) is not None - - -class MatchedSubAppResource(PrefixedSubAppResource): - def __init__(self, rule: AbstractRuleMatching, app: "Application") -> None: - AbstractResource.__init__(self) - self._prefix = "" - self._app = app - self._rule = rule - - @property - def canonical(self) -> str: - return self._rule.canonical - - def get_info(self) -> _InfoDict: - return {"app": self._app, "rule": self._rule} - - async def resolve(self, request: Request) -> _Resolve: - if not await self._rule.match(request): - return None, set() - match_info = await self._app.router.resolve(request) - match_info.add_app(self._app) - if isinstance(match_info.http_exception, HTTPMethodNotAllowed): - methods = match_info.http_exception.allowed_methods - else: - methods = set() - return match_info, methods - - def __repr__(self) -> str: - return f" {self._app!r}>" - - -class ResourceRoute(AbstractRoute): - """A route with resource""" - - def __init__( - self, - method: str, - handler: Union[Handler, Type[AbstractView]], - resource: AbstractResource, - *, - expect_handler: Optional[_ExpectHandler] = None, - ) -> None: - super().__init__( - method, handler, expect_handler=expect_handler, resource=resource - ) - - def __repr__(self) -> str: - return " {handler!r}".format( - method=self.method, resource=self._resource, handler=self.handler - ) - - @property - def name(self) -> Optional[str]: - if self._resource is None: - return None - return self._resource.name - - def url_for(self, *args: str, **kwargs: str) -> URL: - """Construct url for route with additional params.""" - assert self._resource is not None - return self._resource.url_for(*args, **kwargs) - - def get_info(self) -> _InfoDict: - assert self._resource is not None - return self._resource.get_info() - - -class SystemRoute(AbstractRoute): - def __init__(self, http_exception: HTTPException) -> None: - super().__init__(hdrs.METH_ANY, self._handle) - self._http_exception = http_exception - - def url_for(self, *args: str, **kwargs: str) -> URL: - raise RuntimeError(".url_for() is not allowed for SystemRoute") - - @property - def name(self) -> Optional[str]: - return None - - def get_info(self) -> _InfoDict: - return {"http_exception": self._http_exception} - - async def _handle(self, request: Request) -> StreamResponse: - raise self._http_exception - - @property - def status(self) -> int: - return self._http_exception.status - - @property - def reason(self) -> str: - return self._http_exception.reason - - def __repr__(self) -> str: - return "".format(self=self) - - -class View(AbstractView): - async def _iter(self) -> StreamResponse: - if self.request.method not in hdrs.METH_ALL: - self._raise_allowed_methods() - method: Optional[Callable[[], Awaitable[StreamResponse]]] - method = getattr(self, self.request.method.lower(), None) - if method is None: - self._raise_allowed_methods() - ret = await method() - assert isinstance(ret, StreamResponse) - return ret - - def __await__(self) -> Generator[None, None, StreamResponse]: - return self._iter().__await__() - - def _raise_allowed_methods(self) -> NoReturn: - allowed_methods = {m for m in hdrs.METH_ALL if hasattr(self, m.lower())} - raise HTTPMethodNotAllowed(self.request.method, allowed_methods) - - -class ResourcesView(Sized, Iterable[AbstractResource], Container[AbstractResource]): - def __init__(self, resources: List[AbstractResource]) -> None: - self._resources = resources - - def __len__(self) -> int: - return len(self._resources) - - def __iter__(self) -> Iterator[AbstractResource]: - yield from self._resources - - def __contains__(self, resource: object) -> bool: - return resource in self._resources - - -class RoutesView(Sized, Iterable[AbstractRoute], Container[AbstractRoute]): - def __init__(self, resources: List[AbstractResource]): - self._routes: List[AbstractRoute] = [] - for resource in resources: - for route in resource: - self._routes.append(route) - - def __len__(self) -> int: - return len(self._routes) - - def __iter__(self) -> Iterator[AbstractRoute]: - yield from self._routes - - def __contains__(self, route: object) -> bool: - return route in self._routes - - -class UrlDispatcher(AbstractRouter, Mapping[str, AbstractResource]): - - NAME_SPLIT_RE = re.compile(r"[.:-]") - - def __init__(self) -> None: - super().__init__() - self._resources: List[AbstractResource] = [] - self._named_resources: Dict[str, AbstractResource] = {} - self._resource_index: dict[str, list[AbstractResource]] = {} - self._matched_sub_app_resources: List[MatchedSubAppResource] = [] - - async def resolve(self, request: Request) -> UrlMappingMatchInfo: - resource_index = self._resource_index - allowed_methods: Set[str] = set() - - # MatchedSubAppResource is primarily used to match on domain names - # (though custom rules could match on other things). This means that - # the traversal algorithm below can't be applied, and that we likely - # need to check these first so a sub app that defines the same path - # as a parent app will get priority if there's a domain match. - # - # For most cases we do not expect there to be many of these since - # currently they are only added by `.add_domain()`. - for resource in self._matched_sub_app_resources: - match_dict, allowed = await resource.resolve(request) - if match_dict is not None: - return match_dict - else: - allowed_methods |= allowed - - # Walk the url parts looking for candidates. We walk the url backwards - # to ensure the most explicit match is found first. If there are multiple - # candidates for a given url part because there are multiple resources - # registered for the same canonical path, we resolve them in a linear - # fashion to ensure registration order is respected. - url_part = request.rel_url.path_safe - while url_part: - for candidate in resource_index.get(url_part, ()): - match_dict, allowed = await candidate.resolve(request) - if match_dict is not None: - return match_dict - else: - allowed_methods |= allowed - if url_part == "/": - break - url_part = url_part.rpartition("/")[0] or "/" - - if allowed_methods: - return MatchInfoError(HTTPMethodNotAllowed(request.method, allowed_methods)) - - return MatchInfoError(HTTPNotFound()) - - def __iter__(self) -> Iterator[str]: - return iter(self._named_resources) - - def __len__(self) -> int: - return len(self._named_resources) - - def __contains__(self, resource: object) -> bool: - return resource in self._named_resources - - def __getitem__(self, name: str) -> AbstractResource: - return self._named_resources[name] - - def resources(self) -> ResourcesView: - return ResourcesView(self._resources) - - def routes(self) -> RoutesView: - return RoutesView(self._resources) - - def named_resources(self) -> Mapping[str, AbstractResource]: - return MappingProxyType(self._named_resources) - - def register_resource(self, resource: AbstractResource) -> None: - assert isinstance( - resource, AbstractResource - ), f"Instance of AbstractResource class is required, got {resource!r}" - if self.frozen: - raise RuntimeError("Cannot register a resource into frozen router.") - - name = resource.name - - if name is not None: - parts = self.NAME_SPLIT_RE.split(name) - for part in parts: - if keyword.iskeyword(part): - raise ValueError( - f"Incorrect route name {name!r}, " - "python keywords cannot be used " - "for route name" - ) - if not part.isidentifier(): - raise ValueError( - "Incorrect route name {!r}, " - "the name should be a sequence of " - "python identifiers separated " - "by dash, dot or column".format(name) - ) - if name in self._named_resources: - raise ValueError( - "Duplicate {!r}, " - "already handled by {!r}".format(name, self._named_resources[name]) - ) - self._named_resources[name] = resource - self._resources.append(resource) - - if isinstance(resource, MatchedSubAppResource): - # We cannot index match sub-app resources because they have match rules - self._matched_sub_app_resources.append(resource) - else: - self.index_resource(resource) - - def _get_resource_index_key(self, resource: AbstractResource) -> str: - """Return a key to index the resource in the resource index.""" - if "{" in (index_key := resource.canonical): - # strip at the first { to allow for variables, and than - # rpartition at / to allow for variable parts in the path - # For example if the canonical path is `/core/locations{tail:.*}` - # the index key will be `/core` since index is based on the - # url parts split by `/` - index_key = index_key.partition("{")[0].rpartition("/")[0] - return index_key.rstrip("/") or "/" - - def index_resource(self, resource: AbstractResource) -> None: - """Add a resource to the resource index.""" - resource_key = self._get_resource_index_key(resource) - # There may be multiple resources for a canonical path - # so we keep them in a list to ensure that registration - # order is respected. - self._resource_index.setdefault(resource_key, []).append(resource) - - def unindex_resource(self, resource: AbstractResource) -> None: - """Remove a resource from the resource index.""" - resource_key = self._get_resource_index_key(resource) - self._resource_index[resource_key].remove(resource) - - def add_resource(self, path: str, *, name: Optional[str] = None) -> Resource: - if path and not path.startswith("/"): - raise ValueError("path should be started with / or be empty") - # Reuse last added resource if path and name are the same - if self._resources: - resource = self._resources[-1] - if resource.name == name and resource.raw_match(path): - return cast(Resource, resource) - if not ("{" in path or "}" in path or ROUTE_RE.search(path)): - resource = PlainResource(path, name=name) - self.register_resource(resource) - return resource - resource = DynamicResource(path, name=name) - self.register_resource(resource) - return resource - - def add_route( - self, - method: str, - path: str, - handler: Union[Handler, Type[AbstractView]], - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - ) -> AbstractRoute: - resource = self.add_resource(path, name=name) - return resource.add_route(method, handler, expect_handler=expect_handler) - - def add_static( - self, - prefix: str, - path: PathLike, - *, - name: Optional[str] = None, - expect_handler: Optional[_ExpectHandler] = None, - chunk_size: int = 256 * 1024, - show_index: bool = False, - follow_symlinks: bool = False, - append_version: bool = False, - ) -> AbstractResource: - """Add static files view. - - prefix - url prefix - path - folder with files - - """ - assert prefix.startswith("/") - if prefix.endswith("/"): - prefix = prefix[:-1] - resource = StaticResource( - prefix, - path, - name=name, - expect_handler=expect_handler, - chunk_size=chunk_size, - show_index=show_index, - follow_symlinks=follow_symlinks, - append_version=append_version, - ) - self.register_resource(resource) - return resource - - def add_head(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method HEAD.""" - return self.add_route(hdrs.METH_HEAD, path, handler, **kwargs) - - def add_options(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method OPTIONS.""" - return self.add_route(hdrs.METH_OPTIONS, path, handler, **kwargs) - - def add_get( - self, - path: str, - handler: Handler, - *, - name: Optional[str] = None, - allow_head: bool = True, - **kwargs: Any, - ) -> AbstractRoute: - """Shortcut for add_route with method GET. - - If allow_head is true, another - route is added allowing head requests to the same endpoint. - """ - resource = self.add_resource(path, name=name) - if allow_head: - resource.add_route(hdrs.METH_HEAD, handler, **kwargs) - return resource.add_route(hdrs.METH_GET, handler, **kwargs) - - def add_post(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method POST.""" - return self.add_route(hdrs.METH_POST, path, handler, **kwargs) - - def add_put(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method PUT.""" - return self.add_route(hdrs.METH_PUT, path, handler, **kwargs) - - def add_patch(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method PATCH.""" - return self.add_route(hdrs.METH_PATCH, path, handler, **kwargs) - - def add_delete(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: - """Shortcut for add_route with method DELETE.""" - return self.add_route(hdrs.METH_DELETE, path, handler, **kwargs) - - def add_view( - self, path: str, handler: Type[AbstractView], **kwargs: Any - ) -> AbstractRoute: - """Shortcut for add_route with ANY methods for a class-based view.""" - return self.add_route(hdrs.METH_ANY, path, handler, **kwargs) - - def freeze(self) -> None: - super().freeze() - for resource in self._resources: - resource.freeze() - - def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: - """Append routes to route table. - - Parameter should be a sequence of RouteDef objects. - - Returns a list of registered AbstractRoute instances. - """ - registered_routes = [] - for route_def in routes: - registered_routes.extend(route_def.register(self)) - return registered_routes - - -def _quote_path(value: str) -> str: - if YARL_VERSION < (1, 6): - value = value.replace("%", "%25") - return URL.build(path=value, encoded=False).raw_path - - -def _unquote_path_safe(value: str) -> str: - if "%" not in value: - return value - return value.replace("%2F", "/").replace("%25", "%") - - -def _requote_path(value: str) -> str: - # Quote non-ascii characters and other characters which must be quoted, - # but preserve existing %-sequences. - result = _quote_path(value) - if "%" in value: - result = result.replace("%25", "%") - return result diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_ws.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/web_ws.py deleted file mode 100644 index 575f9a3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/web_ws.py +++ /dev/null @@ -1,631 +0,0 @@ -import asyncio -import base64 -import binascii -import hashlib -import json -import sys -from typing import Any, Final, Iterable, Optional, Tuple, Union, cast - -import attr -from multidict import CIMultiDict - -from . import hdrs -from ._websocket.reader import WebSocketDataQueue -from ._websocket.writer import DEFAULT_LIMIT -from .abc import AbstractStreamWriter -from .client_exceptions import WSMessageTypeError -from .helpers import calculate_timeout_when, set_exception, set_result -from .http import ( - WS_CLOSED_MESSAGE, - WS_CLOSING_MESSAGE, - WS_KEY, - WebSocketError, - WebSocketReader, - WebSocketWriter, - WSCloseCode, - WSMessage, - WSMsgType as WSMsgType, - ws_ext_gen, - ws_ext_parse, -) -from .http_websocket import _INTERNAL_RECEIVE_TYPES -from .log import ws_logger -from .streams import EofStream -from .typedefs import JSONDecoder, JSONEncoder -from .web_exceptions import HTTPBadRequest, HTTPException -from .web_request import BaseRequest -from .web_response import StreamResponse - -if sys.version_info >= (3, 11): - import asyncio as async_timeout -else: - import async_timeout - -__all__ = ( - "WebSocketResponse", - "WebSocketReady", - "WSMsgType", -) - -THRESHOLD_CONNLOST_ACCESS: Final[int] = 5 - - -@attr.s(auto_attribs=True, frozen=True, slots=True) -class WebSocketReady: - ok: bool - protocol: Optional[str] - - def __bool__(self) -> bool: - return self.ok - - -class WebSocketResponse(StreamResponse): - - _length_check: bool = False - _ws_protocol: Optional[str] = None - _writer: Optional[WebSocketWriter] = None - _reader: Optional[WebSocketDataQueue] = None - _closed: bool = False - _closing: bool = False - _conn_lost: int = 0 - _close_code: Optional[int] = None - _loop: Optional[asyncio.AbstractEventLoop] = None - _waiting: bool = False - _close_wait: Optional[asyncio.Future[None]] = None - _exception: Optional[BaseException] = None - _heartbeat_when: float = 0.0 - _heartbeat_cb: Optional[asyncio.TimerHandle] = None - _pong_response_cb: Optional[asyncio.TimerHandle] = None - _ping_task: Optional[asyncio.Task[None]] = None - - def __init__( - self, - *, - timeout: float = 10.0, - receive_timeout: Optional[float] = None, - autoclose: bool = True, - autoping: bool = True, - heartbeat: Optional[float] = None, - protocols: Iterable[str] = (), - compress: bool = True, - max_msg_size: int = 4 * 1024 * 1024, - writer_limit: int = DEFAULT_LIMIT, - ) -> None: - super().__init__(status=101) - self._protocols = protocols - self._timeout = timeout - self._receive_timeout = receive_timeout - self._autoclose = autoclose - self._autoping = autoping - self._heartbeat = heartbeat - if heartbeat is not None: - self._pong_heartbeat = heartbeat / 2.0 - self._compress: Union[bool, int] = compress - self._max_msg_size = max_msg_size - self._writer_limit = writer_limit - - def _cancel_heartbeat(self) -> None: - self._cancel_pong_response_cb() - if self._heartbeat_cb is not None: - self._heartbeat_cb.cancel() - self._heartbeat_cb = None - if self._ping_task is not None: - self._ping_task.cancel() - self._ping_task = None - - def _cancel_pong_response_cb(self) -> None: - if self._pong_response_cb is not None: - self._pong_response_cb.cancel() - self._pong_response_cb = None - - def _reset_heartbeat(self) -> None: - if self._heartbeat is None: - return - self._cancel_pong_response_cb() - req = self._req - timeout_ceil_threshold = ( - req._protocol._timeout_ceil_threshold if req is not None else 5 - ) - loop = self._loop - assert loop is not None - now = loop.time() - when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) - self._heartbeat_when = when - if self._heartbeat_cb is None: - # We do not cancel the previous heartbeat_cb here because - # it generates a significant amount of TimerHandle churn - # which causes asyncio to rebuild the heap frequently. - # Instead _send_heartbeat() will reschedule the next - # heartbeat if it fires too early. - self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) - - def _send_heartbeat(self) -> None: - self._heartbeat_cb = None - loop = self._loop - assert loop is not None and self._writer is not None - now = loop.time() - if now < self._heartbeat_when: - # Heartbeat fired too early, reschedule - self._heartbeat_cb = loop.call_at( - self._heartbeat_when, self._send_heartbeat - ) - return - - req = self._req - timeout_ceil_threshold = ( - req._protocol._timeout_ceil_threshold if req is not None else 5 - ) - when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) - self._cancel_pong_response_cb() - self._pong_response_cb = loop.call_at(when, self._pong_not_received) - - coro = self._writer.send_frame(b"", WSMsgType.PING) - if sys.version_info >= (3, 12): - # Optimization for Python 3.12, try to send the ping - # immediately to avoid having to schedule - # the task on the event loop. - ping_task = asyncio.Task(coro, loop=loop, eager_start=True) - else: - ping_task = loop.create_task(coro) - - if not ping_task.done(): - self._ping_task = ping_task - ping_task.add_done_callback(self._ping_task_done) - else: - self._ping_task_done(ping_task) - - def _ping_task_done(self, task: "asyncio.Task[None]") -> None: - """Callback for when the ping task completes.""" - if not task.cancelled() and (exc := task.exception()): - self._handle_ping_pong_exception(exc) - self._ping_task = None - - def _pong_not_received(self) -> None: - if self._req is not None and self._req.transport is not None: - self._handle_ping_pong_exception( - asyncio.TimeoutError( - f"No PONG received after {self._pong_heartbeat} seconds" - ) - ) - - def _handle_ping_pong_exception(self, exc: BaseException) -> None: - """Handle exceptions raised during ping/pong processing.""" - if self._closed: - return - self._set_closed() - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - self._exception = exc - if self._waiting and not self._closing and self._reader is not None: - self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) - - def _set_closed(self) -> None: - """Set the connection to closed. - - Cancel any heartbeat timers and set the closed flag. - """ - self._closed = True - self._cancel_heartbeat() - - async def prepare(self, request: BaseRequest) -> AbstractStreamWriter: - # make pre-check to don't hide it by do_handshake() exceptions - if self._payload_writer is not None: - return self._payload_writer - - protocol, writer = self._pre_start(request) - payload_writer = await super().prepare(request) - assert payload_writer is not None - self._post_start(request, protocol, writer) - await payload_writer.drain() - return payload_writer - - def _handshake( - self, request: BaseRequest - ) -> Tuple["CIMultiDict[str]", Optional[str], int, bool]: - headers = request.headers - if "websocket" != headers.get(hdrs.UPGRADE, "").lower().strip(): - raise HTTPBadRequest( - text=( - "No WebSocket UPGRADE hdr: {}\n Can " - '"Upgrade" only to "WebSocket".' - ).format(headers.get(hdrs.UPGRADE)) - ) - - if "upgrade" not in headers.get(hdrs.CONNECTION, "").lower(): - raise HTTPBadRequest( - text="No CONNECTION upgrade hdr: {}".format( - headers.get(hdrs.CONNECTION) - ) - ) - - # find common sub-protocol between client and server - protocol: Optional[str] = None - if hdrs.SEC_WEBSOCKET_PROTOCOL in headers: - req_protocols = [ - str(proto.strip()) - for proto in headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") - ] - - for proto in req_protocols: - if proto in self._protocols: - protocol = proto - break - else: - # No overlap found: Return no protocol as per spec - ws_logger.warning( - "%s: Client protocols %r don’t overlap server-known ones %r", - request.remote, - req_protocols, - self._protocols, - ) - - # check supported version - version = headers.get(hdrs.SEC_WEBSOCKET_VERSION, "") - if version not in ("13", "8", "7"): - raise HTTPBadRequest(text=f"Unsupported version: {version}") - - # check client handshake for validity - key = headers.get(hdrs.SEC_WEBSOCKET_KEY) - try: - if not key or len(base64.b64decode(key)) != 16: - raise HTTPBadRequest(text=f"Handshake error: {key!r}") - except binascii.Error: - raise HTTPBadRequest(text=f"Handshake error: {key!r}") from None - - accept_val = base64.b64encode( - hashlib.sha1(key.encode() + WS_KEY).digest() - ).decode() - response_headers = CIMultiDict( - { - hdrs.UPGRADE: "websocket", - hdrs.CONNECTION: "upgrade", - hdrs.SEC_WEBSOCKET_ACCEPT: accept_val, - } - ) - - notakeover = False - compress = 0 - if self._compress: - extensions = headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) - # Server side always get return with no exception. - # If something happened, just drop compress extension - compress, notakeover = ws_ext_parse(extensions, isserver=True) - if compress: - enabledext = ws_ext_gen( - compress=compress, isserver=True, server_notakeover=notakeover - ) - response_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = enabledext - - if protocol: - response_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = protocol - return ( - response_headers, - protocol, - compress, - notakeover, - ) - - def _pre_start(self, request: BaseRequest) -> Tuple[Optional[str], WebSocketWriter]: - self._loop = request._loop - - headers, protocol, compress, notakeover = self._handshake(request) - - self.set_status(101) - self.headers.update(headers) - self.force_close() - self._compress = compress - transport = request._protocol.transport - assert transport is not None - writer = WebSocketWriter( - request._protocol, - transport, - compress=compress, - notakeover=notakeover, - limit=self._writer_limit, - ) - - return protocol, writer - - def _post_start( - self, request: BaseRequest, protocol: Optional[str], writer: WebSocketWriter - ) -> None: - self._ws_protocol = protocol - self._writer = writer - - self._reset_heartbeat() - - loop = self._loop - assert loop is not None - self._reader = WebSocketDataQueue(request._protocol, 2**16, loop=loop) - request.protocol.set_parser( - WebSocketReader( - self._reader, self._max_msg_size, compress=bool(self._compress) - ) - ) - # disable HTTP keepalive for WebSocket - request.protocol.keep_alive(False) - - def can_prepare(self, request: BaseRequest) -> WebSocketReady: - if self._writer is not None: - raise RuntimeError("Already started") - try: - _, protocol, _, _ = self._handshake(request) - except HTTPException: - return WebSocketReady(False, None) - else: - return WebSocketReady(True, protocol) - - @property - def prepared(self) -> bool: - return self._writer is not None - - @property - def closed(self) -> bool: - return self._closed - - @property - def close_code(self) -> Optional[int]: - return self._close_code - - @property - def ws_protocol(self) -> Optional[str]: - return self._ws_protocol - - @property - def compress(self) -> Union[int, bool]: - return self._compress - - def get_extra_info(self, name: str, default: Any = None) -> Any: - """Get optional transport information. - - If no value associated with ``name`` is found, ``default`` is returned. - """ - writer = self._writer - if writer is None: - return default - transport = writer.transport - if transport is None: - return default - return transport.get_extra_info(name, default) - - def exception(self) -> Optional[BaseException]: - return self._exception - - async def ping(self, message: bytes = b"") -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, WSMsgType.PING) - - async def pong(self, message: bytes = b"") -> None: - # unsolicited pong - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, WSMsgType.PONG) - - async def send_frame( - self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None - ) -> None: - """Send a frame over the websocket.""" - if self._writer is None: - raise RuntimeError("Call .prepare() first") - await self._writer.send_frame(message, opcode, compress) - - async def send_str(self, data: str, compress: Optional[int] = None) -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - if not isinstance(data, str): - raise TypeError("data argument must be str (%r)" % type(data)) - await self._writer.send_frame( - data.encode("utf-8"), WSMsgType.TEXT, compress=compress - ) - - async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: - if self._writer is None: - raise RuntimeError("Call .prepare() first") - if not isinstance(data, (bytes, bytearray, memoryview)): - raise TypeError("data argument must be byte-ish (%r)" % type(data)) - await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) - - async def send_json( - self, - data: Any, - compress: Optional[int] = None, - *, - dumps: JSONEncoder = json.dumps, - ) -> None: - await self.send_str(dumps(data), compress=compress) - - async def write_eof(self) -> None: # type: ignore[override] - if self._eof_sent: - return - if self._payload_writer is None: - raise RuntimeError("Response has not been started") - - await self.close() - self._eof_sent = True - - async def close( - self, *, code: int = WSCloseCode.OK, message: bytes = b"", drain: bool = True - ) -> bool: - """Close websocket connection.""" - if self._writer is None: - raise RuntimeError("Call .prepare() first") - - if self._closed: - return False - self._set_closed() - - try: - await self._writer.close(code, message) - writer = self._payload_writer - assert writer is not None - if drain: - await writer.drain() - except (asyncio.CancelledError, asyncio.TimeoutError): - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - raise - except Exception as exc: - self._exception = exc - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - return True - - reader = self._reader - assert reader is not None - # we need to break `receive()` cycle before we can call - # `reader.read()` as `close()` may be called from different task - if self._waiting: - assert self._loop is not None - assert self._close_wait is None - self._close_wait = self._loop.create_future() - reader.feed_data(WS_CLOSING_MESSAGE, 0) - await self._close_wait - - if self._closing: - self._close_transport() - return True - - try: - async with async_timeout.timeout(self._timeout): - while True: - msg = await reader.read() - if msg.type is WSMsgType.CLOSE: - self._set_code_close_transport(msg.data) - return True - except asyncio.CancelledError: - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - raise - except Exception as exc: - self._exception = exc - self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) - return True - - def _set_closing(self, code: WSCloseCode) -> None: - """Set the close code and mark the connection as closing.""" - self._closing = True - self._close_code = code - self._cancel_heartbeat() - - def _set_code_close_transport(self, code: WSCloseCode) -> None: - """Set the close code and close the transport.""" - self._close_code = code - self._close_transport() - - def _close_transport(self) -> None: - """Close the transport.""" - if self._req is not None and self._req.transport is not None: - self._req.transport.close() - - async def receive(self, timeout: Optional[float] = None) -> WSMessage: - if self._reader is None: - raise RuntimeError("Call .prepare() first") - - receive_timeout = timeout or self._receive_timeout - while True: - if self._waiting: - raise RuntimeError("Concurrent call to receive() is not allowed") - - if self._closed: - self._conn_lost += 1 - if self._conn_lost >= THRESHOLD_CONNLOST_ACCESS: - raise RuntimeError("WebSocket connection is closed.") - return WS_CLOSED_MESSAGE - elif self._closing: - return WS_CLOSING_MESSAGE - - try: - self._waiting = True - try: - if receive_timeout: - # Entering the context manager and creating - # Timeout() object can take almost 50% of the - # run time in this loop so we avoid it if - # there is no read timeout. - async with async_timeout.timeout(receive_timeout): - msg = await self._reader.read() - else: - msg = await self._reader.read() - self._reset_heartbeat() - finally: - self._waiting = False - if self._close_wait: - set_result(self._close_wait, None) - except asyncio.TimeoutError: - raise - except EofStream: - self._close_code = WSCloseCode.OK - await self.close() - return WSMessage(WSMsgType.CLOSED, None, None) - except WebSocketError as exc: - self._close_code = exc.code - await self.close(code=exc.code) - return WSMessage(WSMsgType.ERROR, exc, None) - except Exception as exc: - self._exception = exc - self._set_closing(WSCloseCode.ABNORMAL_CLOSURE) - await self.close() - return WSMessage(WSMsgType.ERROR, exc, None) - - if msg.type not in _INTERNAL_RECEIVE_TYPES: - # If its not a close/closing/ping/pong message - # we can return it immediately - return msg - - if msg.type is WSMsgType.CLOSE: - self._set_closing(msg.data) - # Could be closed while awaiting reader. - if not self._closed and self._autoclose: - # The client is likely going to close the - # connection out from under us so we do not - # want to drain any pending writes as it will - # likely result writing to a broken pipe. - await self.close(drain=False) - elif msg.type is WSMsgType.CLOSING: - self._set_closing(WSCloseCode.OK) - elif msg.type is WSMsgType.PING and self._autoping: - await self.pong(msg.data) - continue - elif msg.type is WSMsgType.PONG and self._autoping: - continue - - return msg - - async def receive_str(self, *, timeout: Optional[float] = None) -> str: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.TEXT: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" - ) - return cast(str, msg.data) - - async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: - msg = await self.receive(timeout) - if msg.type is not WSMsgType.BINARY: - raise WSMessageTypeError( - f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" - ) - return cast(bytes, msg.data) - - async def receive_json( - self, *, loads: JSONDecoder = json.loads, timeout: Optional[float] = None - ) -> Any: - data = await self.receive_str(timeout=timeout) - return loads(data) - - async def write(self, data: bytes) -> None: - raise RuntimeError("Cannot call .write() for websocket") - - def __aiter__(self) -> "WebSocketResponse": - return self - - async def __anext__(self) -> WSMessage: - msg = await self.receive() - if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): - raise StopAsyncIteration - return msg - - def _cancel(self, exc: BaseException) -> None: - # web_protocol calls this from connection_lost - # or when the server is shutting down. - self._closing = True - self._cancel_heartbeat() - if self._reader is not None: - set_exception(self._reader, exc) diff --git a/backend/venv39/lib/python3.9/site-packages/aiohttp/worker.py b/backend/venv39/lib/python3.9/site-packages/aiohttp/worker.py deleted file mode 100644 index f7281bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiohttp/worker.py +++ /dev/null @@ -1,255 +0,0 @@ -"""Async gunicorn worker for aiohttp.web""" - -import asyncio -import inspect -import os -import re -import signal -import sys -from types import FrameType -from typing import TYPE_CHECKING, Any, Optional - -from gunicorn.config import AccessLogFormat as GunicornAccessLogFormat -from gunicorn.workers import base - -from aiohttp import web - -from .helpers import set_result -from .web_app import Application -from .web_log import AccessLogger - -if TYPE_CHECKING: - import ssl - - SSLContext = ssl.SSLContext -else: - try: - import ssl - - SSLContext = ssl.SSLContext - except ImportError: # pragma: no cover - ssl = None # type: ignore[assignment] - SSLContext = object # type: ignore[misc,assignment] - - -__all__ = ("GunicornWebWorker", "GunicornUVLoopWebWorker") - - -class GunicornWebWorker(base.Worker): # type: ignore[misc,no-any-unimported] - - DEFAULT_AIOHTTP_LOG_FORMAT = AccessLogger.LOG_FORMAT - DEFAULT_GUNICORN_LOG_FORMAT = GunicornAccessLogFormat.default - - def __init__(self, *args: Any, **kw: Any) -> None: # pragma: no cover - super().__init__(*args, **kw) - - self._task: Optional[asyncio.Task[None]] = None - self.exit_code = 0 - self._notify_waiter: Optional[asyncio.Future[bool]] = None - - def init_process(self) -> None: - # create new event_loop after fork - asyncio.get_event_loop().close() - - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - super().init_process() - - def run(self) -> None: - self._task = self.loop.create_task(self._run()) - - try: # ignore all finalization problems - self.loop.run_until_complete(self._task) - except Exception: - self.log.exception("Exception in gunicorn worker") - self.loop.run_until_complete(self.loop.shutdown_asyncgens()) - self.loop.close() - - sys.exit(self.exit_code) - - async def _run(self) -> None: - runner = None - if isinstance(self.wsgi, Application): - app = self.wsgi - elif inspect.iscoroutinefunction(self.wsgi) or ( - sys.version_info < (3, 14) and asyncio.iscoroutinefunction(self.wsgi) - ): - wsgi = await self.wsgi() - if isinstance(wsgi, web.AppRunner): - runner = wsgi - app = runner.app - else: - app = wsgi - else: - raise RuntimeError( - "wsgi app should be either Application or " - "async function returning Application, got {}".format(self.wsgi) - ) - - if runner is None: - access_log = self.log.access_log if self.cfg.accesslog else None - runner = web.AppRunner( - app, - logger=self.log, - keepalive_timeout=self.cfg.keepalive, - access_log=access_log, - access_log_format=self._get_valid_log_format( - self.cfg.access_log_format - ), - shutdown_timeout=self.cfg.graceful_timeout / 100 * 95, - ) - await runner.setup() - - ctx = self._create_ssl_context(self.cfg) if self.cfg.is_ssl else None - - runner = runner - assert runner is not None - server = runner.server - assert server is not None - for sock in self.sockets: - site = web.SockSite( - runner, - sock, - ssl_context=ctx, - ) - await site.start() - - # If our parent changed then we shut down. - pid = os.getpid() - try: - while self.alive: # type: ignore[has-type] - self.notify() - - cnt = server.requests_count - if self.max_requests and cnt > self.max_requests: - self.alive = False - self.log.info("Max requests, shutting down: %s", self) - - elif pid == os.getpid() and self.ppid != os.getppid(): - self.alive = False - self.log.info("Parent changed, shutting down: %s", self) - else: - await self._wait_next_notify() - except BaseException: - pass - - await runner.cleanup() - - def _wait_next_notify(self) -> "asyncio.Future[bool]": - self._notify_waiter_done() - - loop = self.loop - assert loop is not None - self._notify_waiter = waiter = loop.create_future() - self.loop.call_later(1.0, self._notify_waiter_done, waiter) - - return waiter - - def _notify_waiter_done( - self, waiter: Optional["asyncio.Future[bool]"] = None - ) -> None: - if waiter is None: - waiter = self._notify_waiter - if waiter is not None: - set_result(waiter, True) - - if waiter is self._notify_waiter: - self._notify_waiter = None - - def init_signals(self) -> None: - # Set up signals through the event loop API. - - self.loop.add_signal_handler( - signal.SIGQUIT, self.handle_quit, signal.SIGQUIT, None - ) - - self.loop.add_signal_handler( - signal.SIGTERM, self.handle_exit, signal.SIGTERM, None - ) - - self.loop.add_signal_handler( - signal.SIGINT, self.handle_quit, signal.SIGINT, None - ) - - self.loop.add_signal_handler( - signal.SIGWINCH, self.handle_winch, signal.SIGWINCH, None - ) - - self.loop.add_signal_handler( - signal.SIGUSR1, self.handle_usr1, signal.SIGUSR1, None - ) - - self.loop.add_signal_handler( - signal.SIGABRT, self.handle_abort, signal.SIGABRT, None - ) - - # Don't let SIGTERM and SIGUSR1 disturb active requests - # by interrupting system calls - signal.siginterrupt(signal.SIGTERM, False) - signal.siginterrupt(signal.SIGUSR1, False) - # Reset signals so Gunicorn doesn't swallow subprocess return codes - # See: https://github.com/aio-libs/aiohttp/issues/6130 - - def handle_quit(self, sig: int, frame: Optional[FrameType]) -> None: - self.alive = False - - # worker_int callback - self.cfg.worker_int(self) - - # wakeup closing process - self._notify_waiter_done() - - def handle_abort(self, sig: int, frame: Optional[FrameType]) -> None: - self.alive = False - self.exit_code = 1 - self.cfg.worker_abort(self) - sys.exit(1) - - @staticmethod - def _create_ssl_context(cfg: Any) -> "SSLContext": - """Creates SSLContext instance for usage in asyncio.create_server. - - See ssl.SSLSocket.__init__ for more details. - """ - if ssl is None: # pragma: no cover - raise RuntimeError("SSL is not supported.") - - ctx = ssl.SSLContext(cfg.ssl_version) - ctx.load_cert_chain(cfg.certfile, cfg.keyfile) - ctx.verify_mode = cfg.cert_reqs - if cfg.ca_certs: - ctx.load_verify_locations(cfg.ca_certs) - if cfg.ciphers: - ctx.set_ciphers(cfg.ciphers) - return ctx - - def _get_valid_log_format(self, source_format: str) -> str: - if source_format == self.DEFAULT_GUNICORN_LOG_FORMAT: - return self.DEFAULT_AIOHTTP_LOG_FORMAT - elif re.search(r"%\([^\)]+\)", source_format): - raise ValueError( - "Gunicorn's style options in form of `%(name)s` are not " - "supported for the log formatting. Please use aiohttp's " - "format specification to configure access log formatting: " - "http://docs.aiohttp.org/en/stable/logging.html" - "#format-specification" - ) - else: - return source_format - - -class GunicornUVLoopWebWorker(GunicornWebWorker): - def init_process(self) -> None: - import uvloop - - # Close any existing event loop before setting a - # new policy. - asyncio.get_event_loop().close() - - # Setup uvloop policy, so that every - # asyncio.get_event_loop() will create an instance - # of uvloop event loop. - asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) - - super().init_process() diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA deleted file mode 100644 index 03a6f0f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/METADATA +++ /dev/null @@ -1,112 +0,0 @@ -Metadata-Version: 2.4 -Name: aiosignal -Version: 1.4.0 -Summary: aiosignal: a list of registered asynchronous callbacks -Home-page: https://github.com/aio-libs/aiosignal -Maintainer: aiohttp team -Maintainer-email: team@aiohttp.org -License: Apache 2.0 -Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiosignal/actions -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiosignal -Project-URL: Docs: RTD, https://docs.aiosignal.org -Project-URL: GitHub: issues, https://github.com/aio-libs/aiosignal/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/aiosignal -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Development Status :: 5 - Production/Stable -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Framework :: AsyncIO -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: frozenlist>=1.1.0 -Requires-Dist: typing-extensions>=4.2; python_version < "3.13" -Dynamic: license-file - -========= -aiosignal -========= - -.. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg - :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI - :alt: GitHub status for master branch - -.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg?flag=pytest - :target: https://codecov.io/gh/aio-libs/aiosignal?flags[0]=pytest - :alt: codecov.io status for master branch - -.. image:: https://badge.fury.io/py/aiosignal.svg - :target: https://pypi.org/project/aiosignal - :alt: Latest PyPI package version - -.. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest - :target: https://aiosignal.readthedocs.io/ - :alt: Latest Read The Docs - -.. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F - :target: https://aio-libs.discourse.group/ - :alt: Discourse group for io-libs - -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter - -Introduction -============ - -A project to manage callbacks in `asyncio` projects. - -``Signal`` is a list of registered asynchronous callbacks. - -The signal's life-cycle has two stages: after creation its content -could be filled by using standard list operations: ``sig.append()`` -etc. - -After you call ``sig.freeze()`` the signal is *frozen*: adding, removing -and dropping callbacks is forbidden. - -The only available operation is calling the previously registered -callbacks by using ``await sig.send(data)``. - -For concrete usage examples see the `Signals - -section of the `Web Server Advanced -` chapter of the `aiohttp -documentation`_. - - -Installation ------------- - -:: - - $ pip install aiosignal - - -Documentation -============= - -https://aiosignal.readthedocs.io/ - -License -======= - -``aiosignal`` is offered under the Apache 2 license. - -Source code -=========== - -The project is hosted on GitHub_ - -Please file an issue in the `bug tracker -`_ if you have found a bug -or have some suggestions to improve the library. - -.. _GitHub: https://github.com/aio-libs/aiosignal -.. _aiohttp documentation: https://docs.aiohttp.org/ diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD deleted file mode 100644 index 45be226..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/RECORD +++ /dev/null @@ -1,9 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/aiosignal/__init__.cpython-39.pyc,, -aiosignal-1.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -aiosignal-1.4.0.dist-info/METADATA,sha256=CSR-8dqLxpZyjUcTDnAuQwf299EB1sSFv_nzpxznAI0,3662 -aiosignal-1.4.0.dist-info/RECORD,, -aiosignal-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -aiosignal-1.4.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 -aiosignal-1.4.0.dist-info/top_level.txt,sha256=z45aNOKGDdrI1roqZY3BGXQ22kJFPHBmVdwtLYLtXC0,10 -aiosignal/__init__.py,sha256=TIkmUG9HTBt4dfq2nISYBiZiRB2xwvFtEZydLP0HPL4,1537 -aiosignal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE deleted file mode 100644 index 7082a2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2013-2019 Nikolay Kim and Andrew Svetlov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt deleted file mode 100644 index ac6df3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal-1.4.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -aiosignal diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal/__init__.py b/backend/venv39/lib/python3.9/site-packages/aiosignal/__init__.py deleted file mode 100644 index 5ede009..0000000 --- a/backend/venv39/lib/python3.9/site-packages/aiosignal/__init__.py +++ /dev/null @@ -1,59 +0,0 @@ -import sys -from typing import Any, Awaitable, Callable, TypeVar - -from frozenlist import FrozenList - -if sys.version_info >= (3, 11): - from typing import Unpack -else: - from typing_extensions import Unpack - -if sys.version_info >= (3, 13): - from typing import TypeVarTuple -else: - from typing_extensions import TypeVarTuple - -_T = TypeVar("_T") -_Ts = TypeVarTuple("_Ts", default=Unpack[tuple[()]]) - -__version__ = "1.4.0" - -__all__ = ("Signal",) - - -class Signal(FrozenList[Callable[[Unpack[_Ts]], Awaitable[object]]]): - """Coroutine-based signal implementation. - - To connect a callback to a signal, use any list method. - - Signals are fired using the send() coroutine, which takes named - arguments. - """ - - __slots__ = ("_owner",) - - def __init__(self, owner: object): - super().__init__() - self._owner = owner - - def __repr__(self) -> str: - return "".format( - self._owner, self.frozen, list(self) - ) - - async def send(self, *args: Unpack[_Ts], **kwargs: Any) -> None: - """ - Sends data to all registered receivers. - """ - if not self.frozen: - raise RuntimeError("Cannot send non-frozen signal.") - - for receiver in self: - await receiver(*args, **kwargs) - - def __call__( - self, func: Callable[[Unpack[_Ts]], Awaitable[_T]] - ) -> Callable[[Unpack[_Ts]], Awaitable[_T]]: - """Decorator to add a function to this Signal.""" - self.append(func) - return func diff --git a/backend/venv39/lib/python3.9/site-packages/aiosignal/py.typed b/backend/venv39/lib/python3.9/site-packages/aiosignal/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/METADATA deleted file mode 100644 index 9bf7a9e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/METADATA +++ /dev/null @@ -1,145 +0,0 @@ -Metadata-Version: 2.4 -Name: annotated-doc -Version: 0.0.4 -Summary: Document parameters, class attributes, return types, and variables inline, with Annotated. -Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= -License-Expression: MIT -License-File: LICENSE -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development -Classifier: Typing :: Typed -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Project-URL: Homepage, https://github.com/fastapi/annotated-doc -Project-URL: Documentation, https://github.com/fastapi/annotated-doc -Project-URL: Repository, https://github.com/fastapi/annotated-doc -Project-URL: Issues, https://github.com/fastapi/annotated-doc/issues -Project-URL: Changelog, https://github.com/fastapi/annotated-doc/release-notes.md -Requires-Python: >=3.8 -Description-Content-Type: text/markdown - -# Annotated Doc - -Document parameters, class attributes, return types, and variables inline, with `Annotated`. - - - Test - - - Coverage - - - Package version - - - Supported Python versions - - -## Installation - -```bash -pip install annotated-doc -``` - -Or with `uv`: - -```Python -uv add annotated-doc -``` - -## Usage - -Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable. - -For example, to document a parameter `name` in a function `hi` you could do: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") -``` - -You can also use it to document class attributes: - -```Python -from typing import Annotated - -from annotated_doc import Doc - -class User: - name: Annotated[str, Doc("The user's name")] - age: Annotated[int, Doc("The user's age")] -``` - -The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`. - -## Who Uses This - -`annotated-doc` was made for: - -* [FastAPI](https://fastapi.tiangolo.com/) -* [Typer](https://typer.tiangolo.com/) -* [SQLModel](https://sqlmodel.tiangolo.com/) -* [Asyncer](https://asyncer.tiangolo.com/) - -`annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/). - -## Reasons not to use `annotated-doc` - -You are already comfortable with one of the existing docstring formats, like: - -* Sphinx -* numpydoc -* Google -* Keras - -Your team is already comfortable using them. - -You prefer having the documentation about parameters all together in a docstring, separated from the code defining them. - -You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use. - -## Reasons to use `annotated-doc` - -* No micro-syntax to learn for newcomers, it’s **just Python** syntax. -* **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc. -* **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create. -* **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring. -* **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation. -* **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**. -* **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed. -* **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions. -* A more formalized way to document other symbols, like type aliases, that could use Annotated. -* **Support** for apps using FastAPI, Typer and others. -* **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer. - -## History - -I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition. - -The conclusion was that this was better done as an external effort, in a third-party library. - -So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends. - -## License - -This project is licensed under the terms of the MIT license. diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/RECORD deleted file mode 100644 index de0e9ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/annotated_doc/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/annotated_doc/main.cpython-39.pyc,, -annotated_doc-0.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -annotated_doc-0.0.4.dist-info/METADATA,sha256=Irm5KJua33dY2qKKAjJ-OhKaVBVIfwFGej_dSe3Z1TU,6566 -annotated_doc-0.0.4.dist-info/RECORD,, -annotated_doc-0.0.4.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90 -annotated_doc-0.0.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34 -annotated_doc-0.0.4.dist-info/licenses/LICENSE,sha256=__Fwd5pqy_ZavbQFwIfxzuF4ZpHkqWpANFF-SlBKDN8,1086 -annotated_doc/__init__.py,sha256=VuyxxUe80kfEyWnOrCx_Bk8hybo3aKo6RYBlkBBYW8k,52 -annotated_doc/main.py,sha256=5Zfvxv80SwwLqpRW73AZyZyiM4bWma9QWRbp_cgD20s,1075 -annotated_doc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/WHEEL deleted file mode 100644 index 045c8ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: pdm-backend (2.4.5) -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt deleted file mode 100644 index c3ad472..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt +++ /dev/null @@ -1,4 +0,0 @@ -[console_scripts] - -[gui_scripts] - diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE deleted file mode 100644 index 7a25446..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2025 Sebastián Ramírez - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc/__init__.py b/backend/venv39/lib/python3.9/site-packages/annotated_doc/__init__.py deleted file mode 100644 index a0152a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .main import Doc as Doc - -__version__ = "0.0.4" diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc/main.py b/backend/venv39/lib/python3.9/site-packages/annotated_doc/main.py deleted file mode 100644 index 7063c59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_doc/main.py +++ /dev/null @@ -1,36 +0,0 @@ -class Doc: - """Define the documentation of a type annotation using `Annotated`, to be - used in class attributes, function and method parameters, return values, - and variables. - - The value should be a positional-only string literal to allow static tools - like editors and documentation generators to use it. - - This complements docstrings. - - The string value passed is available in the attribute `documentation`. - - Example: - - ```Python - from typing import Annotated - from annotated_doc import Doc - - def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None: - print(f"Hi, {name}!") - ``` - """ - - def __init__(self, documentation: str, /) -> None: - self.documentation = documentation - - def __repr__(self) -> str: - return f"Doc({self.documentation!r})" - - def __hash__(self) -> int: - return hash(self.documentation) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Doc): - return NotImplemented - return self.documentation == other.documentation diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_doc/py.typed b/backend/venv39/lib/python3.9/site-packages/annotated_doc/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/METADATA deleted file mode 100644 index 3ac05cf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/METADATA +++ /dev/null @@ -1,295 +0,0 @@ -Metadata-Version: 2.3 -Name: annotated-types -Version: 0.7.0 -Summary: Reusable constraint types to use with typing.Annotated -Project-URL: Homepage, https://github.com/annotated-types/annotated-types -Project-URL: Source, https://github.com/annotated-types/annotated-types -Project-URL: Changelog, https://github.com/annotated-types/annotated-types/releases -Author-email: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Samuel Colvin , Zac Hatfield-Dodds -License-File: LICENSE -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Console -Classifier: Environment :: MacOS X -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Information Technology -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Unix -Classifier: Programming Language :: Python :: 3 :: Only -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: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Requires-Dist: typing-extensions>=4.0.0; python_version < '3.9' -Description-Content-Type: text/markdown - -# annotated-types - -[![CI](https://github.com/annotated-types/annotated-types/workflows/CI/badge.svg?event=push)](https://github.com/annotated-types/annotated-types/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) -[![pypi](https://img.shields.io/pypi/v/annotated-types.svg)](https://pypi.python.org/pypi/annotated-types) -[![versions](https://img.shields.io/pypi/pyversions/annotated-types.svg)](https://github.com/annotated-types/annotated-types) -[![license](https://img.shields.io/github/license/annotated-types/annotated-types.svg)](https://github.com/annotated-types/annotated-types/blob/main/LICENSE) - -[PEP-593](https://peps.python.org/pep-0593/) added `typing.Annotated` as a way of -adding context-specific metadata to existing types, and specifies that -`Annotated[T, x]` _should_ be treated as `T` by any tool or library without special -logic for `x`. - -This package provides metadata objects which can be used to represent common -constraints such as upper and lower bounds on scalar values and collection sizes, -a `Predicate` marker for runtime checks, and -descriptions of how we intend these metadata to be interpreted. In some cases, -we also note alternative representations which do not require this package. - -## Install - -```bash -pip install annotated-types -``` - -## Examples - -```python -from typing import Annotated -from annotated_types import Gt, Len, Predicate - -class MyClass: - age: Annotated[int, Gt(18)] # Valid: 19, 20, ... - # Invalid: 17, 18, "19", 19.0, ... - factors: list[Annotated[int, Predicate(is_prime)]] # Valid: 2, 3, 5, 7, 11, ... - # Invalid: 4, 8, -2, 5.0, "prime", ... - - my_list: Annotated[list[int], Len(0, 10)] # Valid: [], [10, 20, 30, 40, 50] - # Invalid: (1, 2), ["abc"], [0] * 20 -``` - -## Documentation - -_While `annotated-types` avoids runtime checks for performance, users should not -construct invalid combinations such as `MultipleOf("non-numeric")` or `Annotated[int, Len(3)]`. -Downstream implementors may choose to raise an error, emit a warning, silently ignore -a metadata item, etc., if the metadata objects described below are used with an -incompatible type - or for any other reason!_ - -### Gt, Ge, Lt, Le - -Express inclusive and/or exclusive bounds on orderable values - which may be numbers, -dates, times, strings, sets, etc. Note that the boundary value need not be of the -same type that was annotated, so long as they can be compared: `Annotated[int, Gt(1.5)]` -is fine, for example, and implies that the value is an integer x such that `x > 1.5`. - -We suggest that implementors may also interpret `functools.partial(operator.le, 1.5)` -as being equivalent to `Gt(1.5)`, for users who wish to avoid a runtime dependency on -the `annotated-types` package. - -To be explicit, these types have the following meanings: - -* `Gt(x)` - value must be "Greater Than" `x` - equivalent to exclusive minimum -* `Ge(x)` - value must be "Greater than or Equal" to `x` - equivalent to inclusive minimum -* `Lt(x)` - value must be "Less Than" `x` - equivalent to exclusive maximum -* `Le(x)` - value must be "Less than or Equal" to `x` - equivalent to inclusive maximum - -### Interval - -`Interval(gt, ge, lt, le)` allows you to specify an upper and lower bound with a single -metadata object. `None` attributes should be ignored, and non-`None` attributes -treated as per the single bounds above. - -### MultipleOf - -`MultipleOf(multiple_of=x)` might be interpreted in two ways: - -1. Python semantics, implying `value % multiple_of == 0`, or -2. [JSONschema semantics](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.2.1), - where `int(value / multiple_of) == value / multiple_of`. - -We encourage users to be aware of these two common interpretations and their -distinct behaviours, especially since very large or non-integer numbers make -it easy to cause silent data corruption due to floating-point imprecision. - -We encourage libraries to carefully document which interpretation they implement. - -### MinLen, MaxLen, Len - -`Len()` implies that `min_length <= len(value) <= max_length` - lower and upper bounds are inclusive. - -As well as `Len()` which can optionally include upper and lower bounds, we also -provide `MinLen(x)` and `MaxLen(y)` which are equivalent to `Len(min_length=x)` -and `Len(max_length=y)` respectively. - -`Len`, `MinLen`, and `MaxLen` may be used with any type which supports `len(value)`. - -Examples of usage: - -* `Annotated[list, MaxLen(10)]` (or `Annotated[list, Len(max_length=10))`) - list must have a length of 10 or less -* `Annotated[str, MaxLen(10)]` - string must have a length of 10 or less -* `Annotated[list, MinLen(3))` (or `Annotated[list, Len(min_length=3))`) - list must have a length of 3 or more -* `Annotated[list, Len(4, 6)]` - list must have a length of 4, 5, or 6 -* `Annotated[list, Len(8, 8)]` - list must have a length of exactly 8 - -#### Changed in v0.4.0 - -* `min_inclusive` has been renamed to `min_length`, no change in meaning -* `max_exclusive` has been renamed to `max_length`, upper bound is now **inclusive** instead of **exclusive** -* The recommendation that slices are interpreted as `Len` has been removed due to ambiguity and different semantic - meaning of the upper bound in slices vs. `Len` - -See [issue #23](https://github.com/annotated-types/annotated-types/issues/23) for discussion. - -### Timezone - -`Timezone` can be used with a `datetime` or a `time` to express which timezones -are allowed. `Annotated[datetime, Timezone(None)]` must be a naive datetime. -`Timezone[...]` ([literal ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis)) -expresses that any timezone-aware datetime is allowed. You may also pass a specific -timezone string or [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) -object such as `Timezone(timezone.utc)` or `Timezone("Africa/Abidjan")` to express that you only -allow a specific timezone, though we note that this is often a symptom of fragile design. - -#### Changed in v0.x.x - -* `Timezone` accepts [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) objects instead of - `timezone`, extending compatibility to [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and third party libraries. - -### Unit - -`Unit(unit: str)` expresses that the annotated numeric value is the magnitude of -a quantity with the specified unit. For example, `Annotated[float, Unit("m/s")]` -would be a float representing a velocity in meters per second. - -Please note that `annotated_types` itself makes no attempt to parse or validate -the unit string in any way. That is left entirely to downstream libraries, -such as [`pint`](https://pint.readthedocs.io) or -[`astropy.units`](https://docs.astropy.org/en/stable/units/). - -An example of how a library might use this metadata: - -```python -from annotated_types import Unit -from typing import Annotated, TypeVar, Callable, Any, get_origin, get_args - -# given a type annotated with a unit: -Meters = Annotated[float, Unit("m")] - - -# you can cast the annotation to a specific unit type with any -# callable that accepts a string and returns the desired type -T = TypeVar("T") -def cast_unit(tp: Any, unit_cls: Callable[[str], T]) -> T | None: - if get_origin(tp) is Annotated: - for arg in get_args(tp): - if isinstance(arg, Unit): - return unit_cls(arg.unit) - return None - - -# using `pint` -import pint -pint_unit = cast_unit(Meters, pint.Unit) - - -# using `astropy.units` -import astropy.units as u -astropy_unit = cast_unit(Meters, u.Unit) -``` - -### Predicate - -`Predicate(func: Callable)` expresses that `func(value)` is truthy for valid values. -Users should prefer the statically inspectable metadata above, but if you need -the full power and flexibility of arbitrary runtime predicates... here it is. - -For some common constraints, we provide generic types: - -* `IsLower = Annotated[T, Predicate(str.islower)]` -* `IsUpper = Annotated[T, Predicate(str.isupper)]` -* `IsDigit = Annotated[T, Predicate(str.isdigit)]` -* `IsFinite = Annotated[T, Predicate(math.isfinite)]` -* `IsNotFinite = Annotated[T, Predicate(Not(math.isfinite))]` -* `IsNan = Annotated[T, Predicate(math.isnan)]` -* `IsNotNan = Annotated[T, Predicate(Not(math.isnan))]` -* `IsInfinite = Annotated[T, Predicate(math.isinf)]` -* `IsNotInfinite = Annotated[T, Predicate(Not(math.isinf))]` - -so that you can write e.g. `x: IsFinite[float] = 2.0` instead of the longer -(but exactly equivalent) `x: Annotated[float, Predicate(math.isfinite)] = 2.0`. - -Some libraries might have special logic to handle known or understandable predicates, -for example by checking for `str.isdigit` and using its presence to both call custom -logic to enforce digit-only strings, and customise some generated external schema. -Users are therefore encouraged to avoid indirection like `lambda s: s.lower()`, in -favor of introspectable methods such as `str.lower` or `re.compile("pattern").search`. - -To enable basic negation of commonly used predicates like `math.isnan` without introducing introspection that makes it impossible for implementers to introspect the predicate we provide a `Not` wrapper that simply negates the predicate in an introspectable manner. Several of the predicates listed above are created in this manner. - -We do not specify what behaviour should be expected for predicates that raise -an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently -skip invalid constraints, or statically raise an error; or it might try calling it -and then propagate or discard the resulting -`TypeError: descriptor 'isdigit' for 'str' objects doesn't apply to a 'int' object` -exception. We encourage libraries to document the behaviour they choose. - -### Doc - -`doc()` can be used to add documentation information in `Annotated`, for function and method parameters, variables, class attributes, return types, and any place where `Annotated` can be used. - -It expects a value that can be statically analyzed, as the main use case is for static analysis, editors, documentation generators, and similar tools. - -It returns a `DocInfo` class with a single attribute `documentation` containing the value passed to `doc()`. - -This is the early adopter's alternative form of the [`typing-doc` proposal](https://github.com/tiangolo/fastapi/blob/typing-doc/typing_doc.md). - -### Integrating downstream types with `GroupedMetadata` - -Implementers may choose to provide a convenience wrapper that groups multiple pieces of metadata. -This can help reduce verbosity and cognitive overhead for users. -For example, an implementer like Pydantic might provide a `Field` or `Meta` type that accepts keyword arguments and transforms these into low-level metadata: - -```python -from dataclasses import dataclass -from typing import Iterator -from annotated_types import GroupedMetadata, Ge - -@dataclass -class Field(GroupedMetadata): - ge: int | None = None - description: str | None = None - - def __iter__(self) -> Iterator[object]: - # Iterating over a GroupedMetadata object should yield annotated-types - # constraint metadata objects which describe it as fully as possible, - # and may include other unknown objects too. - if self.ge is not None: - yield Ge(self.ge) - if self.description is not None: - yield Description(self.description) -``` - -Libraries consuming annotated-types constraints should check for `GroupedMetadata` and unpack it by iterating over the object and treating the results as if they had been "unpacked" in the `Annotated` type. The same logic should be applied to the [PEP 646 `Unpack` type](https://peps.python.org/pep-0646/), so that `Annotated[T, Field(...)]`, `Annotated[T, Unpack[Field(...)]]` and `Annotated[T, *Field(...)]` are all treated consistently. - -Libraries consuming annotated-types should also ignore any metadata they do not recongize that came from unpacking a `GroupedMetadata`, just like they ignore unrecognized metadata in `Annotated` itself. - -Our own `annotated_types.Interval` class is a `GroupedMetadata` which unpacks itself into `Gt`, `Lt`, etc., so this is not an abstract concern. Similarly, `annotated_types.Len` is a `GroupedMetadata` which unpacks itself into `MinLen` (optionally) and `MaxLen`. - -### Consuming metadata - -We intend to not be prescriptive as to _how_ the metadata and constraints are used, but as an example of how one might parse constraints from types annotations see our [implementation in `test_main.py`](https://github.com/annotated-types/annotated-types/blob/f59cf6d1b5255a0fe359b93896759a180bec30ae/tests/test_main.py#L94-L103). - -It is up to the implementer to determine how this metadata is used. -You could use the metadata for runtime type checking, for generating schemas or to generate example data, amongst other use cases. - -## Design & History - -This package was designed at the PyCon 2022 sprints by the maintainers of Pydantic -and Hypothesis, with the goal of making it as easy as possible for end-users to -provide more informative annotations for use by runtime libraries. - -It is deliberately minimal, and following PEP-593 allows considerable downstream -discretion in what (if anything!) they choose to support. Nonetheless, we expect -that staying simple and covering _only_ the most common use-cases will give users -and maintainers the best experience we can. If you'd like more constraints for your -types - follow our lead, by defining them and documenting them downstream! diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/RECORD deleted file mode 100644 index a7644d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/annotated_types/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/annotated_types/test_cases.cpython-39.pyc,, -annotated_types-0.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -annotated_types-0.7.0.dist-info/METADATA,sha256=7ltqxksJJ0wCYFGBNIQCWTlWQGeAH0hRFdnK3CB895E,15046 -annotated_types-0.7.0.dist-info/RECORD,, -annotated_types-0.7.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87 -annotated_types-0.7.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083 -annotated_types/__init__.py,sha256=RynLsRKUEGI0KimXydlD1fZEfEzWwDo0Uon3zOKhG1Q,13819 -annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -annotated_types/test_cases.py,sha256=zHFX6EpcMbGJ8FzBYDbO56bPwx_DYIVSKbZM-4B3_lg,6421 diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/WHEEL deleted file mode 100644 index 516596c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.24.2 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE deleted file mode 100644 index d99323a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 the contributors - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types/__init__.py b/backend/venv39/lib/python3.9/site-packages/annotated_types/__init__.py deleted file mode 100644 index 74e0dee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types/__init__.py +++ /dev/null @@ -1,432 +0,0 @@ -import math -import sys -import types -from dataclasses import dataclass -from datetime import tzinfo -from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, SupportsFloat, SupportsIndex, TypeVar, Union - -if sys.version_info < (3, 8): - from typing_extensions import Protocol, runtime_checkable -else: - from typing import Protocol, runtime_checkable - -if sys.version_info < (3, 9): - from typing_extensions import Annotated, Literal -else: - from typing import Annotated, Literal - -if sys.version_info < (3, 10): - EllipsisType = type(Ellipsis) - KW_ONLY = {} - SLOTS = {} -else: - from types import EllipsisType - - KW_ONLY = {"kw_only": True} - SLOTS = {"slots": True} - - -__all__ = ( - 'BaseMetadata', - 'GroupedMetadata', - 'Gt', - 'Ge', - 'Lt', - 'Le', - 'Interval', - 'MultipleOf', - 'MinLen', - 'MaxLen', - 'Len', - 'Timezone', - 'Predicate', - 'LowerCase', - 'UpperCase', - 'IsDigits', - 'IsFinite', - 'IsNotFinite', - 'IsNan', - 'IsNotNan', - 'IsInfinite', - 'IsNotInfinite', - 'doc', - 'DocInfo', - '__version__', -) - -__version__ = '0.7.0' - - -T = TypeVar('T') - - -# arguments that start with __ are considered -# positional only -# see https://peps.python.org/pep-0484/#positional-only-arguments - - -class SupportsGt(Protocol): - def __gt__(self: T, __other: T) -> bool: - ... - - -class SupportsGe(Protocol): - def __ge__(self: T, __other: T) -> bool: - ... - - -class SupportsLt(Protocol): - def __lt__(self: T, __other: T) -> bool: - ... - - -class SupportsLe(Protocol): - def __le__(self: T, __other: T) -> bool: - ... - - -class SupportsMod(Protocol): - def __mod__(self: T, __other: T) -> T: - ... - - -class SupportsDiv(Protocol): - def __div__(self: T, __other: T) -> T: - ... - - -class BaseMetadata: - """Base class for all metadata. - - This exists mainly so that implementers - can do `isinstance(..., BaseMetadata)` while traversing field annotations. - """ - - __slots__ = () - - -@dataclass(frozen=True, **SLOTS) -class Gt(BaseMetadata): - """Gt(gt=x) implies that the value must be greater than x. - - It can be used with any type that supports the ``>`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - gt: SupportsGt - - -@dataclass(frozen=True, **SLOTS) -class Ge(BaseMetadata): - """Ge(ge=x) implies that the value must be greater than or equal to x. - - It can be used with any type that supports the ``>=`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - ge: SupportsGe - - -@dataclass(frozen=True, **SLOTS) -class Lt(BaseMetadata): - """Lt(lt=x) implies that the value must be less than x. - - It can be used with any type that supports the ``<`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - lt: SupportsLt - - -@dataclass(frozen=True, **SLOTS) -class Le(BaseMetadata): - """Le(le=x) implies that the value must be less than or equal to x. - - It can be used with any type that supports the ``<=`` operator, - including numbers, dates and times, strings, sets, and so on. - """ - - le: SupportsLe - - -@runtime_checkable -class GroupedMetadata(Protocol): - """A grouping of multiple objects, like typing.Unpack. - - `GroupedMetadata` on its own is not metadata and has no meaning. - All of the constraints and metadata should be fully expressable - in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`. - - Concrete implementations should override `GroupedMetadata.__iter__()` - to add their own metadata. - For example: - - >>> @dataclass - >>> class Field(GroupedMetadata): - >>> gt: float | None = None - >>> description: str | None = None - ... - >>> def __iter__(self) -> Iterable[object]: - >>> if self.gt is not None: - >>> yield Gt(self.gt) - >>> if self.description is not None: - >>> yield Description(self.gt) - - Also see the implementation of `Interval` below for an example. - - Parsers should recognize this and unpack it so that it can be used - both with and without unpacking: - - - `Annotated[int, Field(...)]` (parser must unpack Field) - - `Annotated[int, *Field(...)]` (PEP-646) - """ # noqa: trailing-whitespace - - @property - def __is_annotated_types_grouped_metadata__(self) -> Literal[True]: - return True - - def __iter__(self) -> Iterator[object]: - ... - - if not TYPE_CHECKING: - __slots__ = () # allow subclasses to use slots - - def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None: - # Basic ABC like functionality without the complexity of an ABC - super().__init_subclass__(*args, **kwargs) - if cls.__iter__ is GroupedMetadata.__iter__: - raise TypeError("Can't subclass GroupedMetadata without implementing __iter__") - - def __iter__(self) -> Iterator[object]: # noqa: F811 - raise NotImplementedError # more helpful than "None has no attribute..." type errors - - -@dataclass(frozen=True, **KW_ONLY, **SLOTS) -class Interval(GroupedMetadata): - """Interval can express inclusive or exclusive bounds with a single object. - - It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which - are interpreted the same way as the single-bound constraints. - """ - - gt: Union[SupportsGt, None] = None - ge: Union[SupportsGe, None] = None - lt: Union[SupportsLt, None] = None - le: Union[SupportsLe, None] = None - - def __iter__(self) -> Iterator[BaseMetadata]: - """Unpack an Interval into zero or more single-bounds.""" - if self.gt is not None: - yield Gt(self.gt) - if self.ge is not None: - yield Ge(self.ge) - if self.lt is not None: - yield Lt(self.lt) - if self.le is not None: - yield Le(self.le) - - -@dataclass(frozen=True, **SLOTS) -class MultipleOf(BaseMetadata): - """MultipleOf(multiple_of=x) might be interpreted in two ways: - - 1. Python semantics, implying ``value % multiple_of == 0``, or - 2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of`` - - We encourage users to be aware of these two common interpretations, - and libraries to carefully document which they implement. - """ - - multiple_of: Union[SupportsDiv, SupportsMod] - - -@dataclass(frozen=True, **SLOTS) -class MinLen(BaseMetadata): - """ - MinLen() implies minimum inclusive length, - e.g. ``len(value) >= min_length``. - """ - - min_length: Annotated[int, Ge(0)] - - -@dataclass(frozen=True, **SLOTS) -class MaxLen(BaseMetadata): - """ - MaxLen() implies maximum inclusive length, - e.g. ``len(value) <= max_length``. - """ - - max_length: Annotated[int, Ge(0)] - - -@dataclass(frozen=True, **SLOTS) -class Len(GroupedMetadata): - """ - Len() implies that ``min_length <= len(value) <= max_length``. - - Upper bound may be omitted or ``None`` to indicate no upper length bound. - """ - - min_length: Annotated[int, Ge(0)] = 0 - max_length: Optional[Annotated[int, Ge(0)]] = None - - def __iter__(self) -> Iterator[BaseMetadata]: - """Unpack a Len into zone or more single-bounds.""" - if self.min_length > 0: - yield MinLen(self.min_length) - if self.max_length is not None: - yield MaxLen(self.max_length) - - -@dataclass(frozen=True, **SLOTS) -class Timezone(BaseMetadata): - """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive). - - ``Annotated[datetime, Timezone(None)]`` must be a naive datetime. - ``Timezone[...]`` (the ellipsis literal) expresses that the datetime must be - tz-aware but any timezone is allowed. - - You may also pass a specific timezone string or tzinfo object such as - ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that - you only allow a specific timezone, though we note that this is often - a symptom of poor design. - """ - - tz: Union[str, tzinfo, EllipsisType, None] - - -@dataclass(frozen=True, **SLOTS) -class Unit(BaseMetadata): - """Indicates that the value is a physical quantity with the specified unit. - - It is intended for usage with numeric types, where the value represents the - magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]`` - or ``speed: Annotated[float, Unit('m/s')]``. - - Interpretation of the unit string is left to the discretion of the consumer. - It is suggested to follow conventions established by python libraries that work - with physical quantities, such as - - - ``pint`` : - - ``astropy.units``: - - For indicating a quantity with a certain dimensionality but without a specific unit - it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`. - Note, however, ``annotated_types`` itself makes no use of the unit string. - """ - - unit: str - - -@dataclass(frozen=True, **SLOTS) -class Predicate(BaseMetadata): - """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values. - - Users should prefer statically inspectable metadata, but if you need the full - power and flexibility of arbitrary runtime predicates... here it is. - - We provide a few predefined predicates for common string constraints: - ``IsLower = Predicate(str.islower)``, ``IsUpper = Predicate(str.isupper)``, and - ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which - can be given special handling, and avoid indirection like ``lambda s: s.lower()``. - - Some libraries might have special logic to handle certain predicates, e.g. by - checking for `str.isdigit` and using its presence to both call custom logic to - enforce digit-only strings, and customise some generated external schema. - - We do not specify what behaviour should be expected for predicates that raise - an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently - skip invalid constraints, or statically raise an error; or it might try calling it - and then propagate or discard the resulting exception. - """ - - func: Callable[[Any], bool] - - def __repr__(self) -> str: - if getattr(self.func, "__name__", "") == "": - return f"{self.__class__.__name__}({self.func!r})" - if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and ( - namespace := getattr(self.func.__self__, "__name__", None) - ): - return f"{self.__class__.__name__}({namespace}.{self.func.__name__})" - if isinstance(self.func, type(str.isascii)): # method descriptor - return f"{self.__class__.__name__}({self.func.__qualname__})" - return f"{self.__class__.__name__}({self.func.__name__})" - - -@dataclass -class Not: - func: Callable[[Any], bool] - - def __call__(self, __v: Any) -> bool: - return not self.func(__v) - - -_StrType = TypeVar("_StrType", bound=str) - -LowerCase = Annotated[_StrType, Predicate(str.islower)] -""" -Return True if the string is a lowercase string, False otherwise. - -A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string. -""" # noqa: E501 -UpperCase = Annotated[_StrType, Predicate(str.isupper)] -""" -Return True if the string is an uppercase string, False otherwise. - -A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string. -""" # noqa: E501 -IsDigit = Annotated[_StrType, Predicate(str.isdigit)] -IsDigits = IsDigit # type: ignore # plural for backwards compatibility, see #63 -""" -Return True if the string is a digit string, False otherwise. - -A string is a digit string if all characters in the string are digits and there is at least one character in the string. -""" # noqa: E501 -IsAscii = Annotated[_StrType, Predicate(str.isascii)] -""" -Return True if all characters in the string are ASCII, False otherwise. - -ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too. -""" - -_NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex]) -IsFinite = Annotated[_NumericType, Predicate(math.isfinite)] -"""Return True if x is neither an infinity nor a NaN, and False otherwise.""" -IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))] -"""Return True if x is one of infinity or NaN, and False otherwise""" -IsNan = Annotated[_NumericType, Predicate(math.isnan)] -"""Return True if x is a NaN (not a number), and False otherwise.""" -IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))] -"""Return True if x is anything but NaN (not a number), and False otherwise.""" -IsInfinite = Annotated[_NumericType, Predicate(math.isinf)] -"""Return True if x is a positive or negative infinity, and False otherwise.""" -IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))] -"""Return True if x is neither a positive or negative infinity, and False otherwise.""" - -try: - from typing_extensions import DocInfo, doc # type: ignore [attr-defined] -except ImportError: - - @dataclass(frozen=True, **SLOTS) - class DocInfo: # type: ignore [no-redef] - """ " - The return value of doc(), mainly to be used by tools that want to extract the - Annotated documentation at runtime. - """ - - documentation: str - """The documentation string passed to doc().""" - - def doc( - documentation: str, - ) -> DocInfo: - """ - Add documentation to a type annotation inside of Annotated. - - For example: - - >>> def hi(name: Annotated[int, doc("The name of the user")]) -> None: ... - """ - return DocInfo(documentation) diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types/py.typed b/backend/venv39/lib/python3.9/site-packages/annotated_types/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/annotated_types/test_cases.py b/backend/venv39/lib/python3.9/site-packages/annotated_types/test_cases.py deleted file mode 100644 index d9164d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/annotated_types/test_cases.py +++ /dev/null @@ -1,151 +0,0 @@ -import math -import sys -from datetime import date, datetime, timedelta, timezone -from decimal import Decimal -from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Set, Tuple - -if sys.version_info < (3, 9): - from typing_extensions import Annotated -else: - from typing import Annotated - -import annotated_types as at - - -class Case(NamedTuple): - """ - A test case for `annotated_types`. - """ - - annotation: Any - valid_cases: Iterable[Any] - invalid_cases: Iterable[Any] - - -def cases() -> Iterable[Case]: - # Gt, Ge, Lt, Le - yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1)) - yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1)) - yield Case( - Annotated[datetime, at.Gt(datetime(2000, 1, 1))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(2000, 1, 1), datetime(1999, 12, 31)], - ) - yield Case( - Annotated[datetime, at.Gt(date(2000, 1, 1))], - [date(2000, 1, 2), date(2000, 1, 3)], - [date(2000, 1, 1), date(1999, 12, 31)], - ) - yield Case( - Annotated[datetime, at.Gt(Decimal('1.123'))], - [Decimal('1.1231'), Decimal('123')], - [Decimal('1.123'), Decimal('0')], - ) - - yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1)) - yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1)) - yield Case( - Annotated[datetime, at.Ge(datetime(2000, 1, 1))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(1998, 1, 1), datetime(1999, 12, 31)], - ) - - yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4)) - yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9)) - yield Case( - Annotated[datetime, at.Lt(datetime(2000, 1, 1))], - [datetime(1999, 12, 31), datetime(1999, 12, 31)], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - ) - - yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000)) - yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9)) - yield Case( - Annotated[datetime, at.Le(datetime(2000, 1, 1))], - [datetime(2000, 1, 1), datetime(1999, 12, 31)], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - ) - - # Interval - yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1)) - yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1)) - yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1)) - yield Case( - Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))], - [datetime(2000, 1, 2), datetime(2000, 1, 3)], - [datetime(2000, 1, 1), datetime(2000, 1, 4)], - ) - - yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4)) - yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1)) - - # lengths - - yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) - yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) - yield Case(Annotated[List[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) - yield Case(Annotated[List[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) - - yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10)) - yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10)) - yield Case(Annotated[List[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) - yield Case(Annotated[List[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) - - yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10)) - yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234')) - - yield Case(Annotated[Dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}]) - yield Case(Annotated[Set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4})) - yield Case(Annotated[Tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4))) - - # Timezone - - yield Case( - Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)] - ) - yield Case( - Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)] - ) - yield Case( - Annotated[datetime, at.Timezone(timezone.utc)], - [datetime(2000, 1, 1, tzinfo=timezone.utc)], - [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], - ) - yield Case( - Annotated[datetime, at.Timezone('Europe/London')], - [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))], - [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], - ) - - # Quantity - - yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m')) - - # predicate types - - yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom']) - yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC']) - yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2']) - yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀']) - - yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5]) - - yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf]) - yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23]) - yield Case(at.IsNan[float], [math.nan], [1.23, math.inf]) - yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan]) - yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23]) - yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf]) - - # check stacked predicates - yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan]) - - # doc - yield Case(Annotated[int, at.doc("A number")], [1, 2], []) - - # custom GroupedMetadata - class MyCustomGroupedMetadata(at.GroupedMetadata): - def __iter__(self) -> Iterator[at.Predicate]: - yield at.Predicate(lambda x: float(x).is_integer()) - - yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5]) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/METADATA deleted file mode 100644 index dbeb198..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/METADATA +++ /dev/null @@ -1,96 +0,0 @@ -Metadata-Version: 2.4 -Name: anyio -Version: 4.12.1 -Summary: High-level concurrency and networking framework on top of asyncio or Trio -Author-email: Alex Grönholm -License-Expression: MIT -Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/ -Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html -Project-URL: Source code, https://github.com/agronholm/anyio -Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Framework :: AnyIO -Classifier: Typing :: Typed -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11" -Requires-Dist: idna>=2.8 -Requires-Dist: typing_extensions>=4.5; python_version < "3.13" -Provides-Extra: trio -Requires-Dist: trio>=0.32.0; python_version >= "3.10" and extra == "trio" -Requires-Dist: trio>=0.31.0; python_version < "3.10" and extra == "trio" -Dynamic: license-file - -.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/anyio/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master - :target: https://coveralls.io/github/agronholm/anyio?branch=master - :alt: Code Coverage -.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest - :target: https://anyio.readthedocs.io/en/latest/?badge=latest - :alt: Documentation -.. image:: https://badges.gitter.im/gitterHQ/gitter.svg - :target: https://gitter.im/python-trio/AnyIO - :alt: Gitter chat - -AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or -Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony -with the native SC of Trio itself. - -Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or -Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full -refactoring necessary. It will blend in with the native libraries of your chosen backend. - -To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it -`here `_. - -Documentation -------------- - -View full documentation at: https://anyio.readthedocs.io/ - -Features --------- - -AnyIO offers the following functionality: - -* Task groups (nurseries_ in trio terminology) -* High-level networking (TCP, UDP and UNIX sockets) - - * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python - 3.8) - * async/await style UDP sockets (unlike asyncio where you still have to use Transports and - Protocols) - -* A versatile API for byte streams and object streams -* Inter-task synchronization and communication (locks, conditions, events, semaphores, object - streams) -* Worker threads -* Subprocesses -* Subinterpreter support for code parallelization (on Python 3.13 and later) -* Asynchronous file I/O (using worker threads) -* Signal handling -* Asynchronous version of the functools_ module - -AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures. -It even works with the popular Hypothesis_ library. - -.. _asyncio: https://docs.python.org/3/library/asyncio.html -.. _Trio: https://github.com/python-trio/trio -.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency -.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning -.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs -.. _pytest: https://docs.pytest.org/en/latest/ -.. _functools: https://docs.python.org/3/library/functools.html -.. _Hypothesis: https://hypothesis.works/ diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/RECORD deleted file mode 100644 index 50adcf4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/RECORD +++ /dev/null @@ -1,92 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_backends/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_asyncio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_trio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_contextmanagers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_eventloop.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_fileio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_resources.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_signals.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_sockets.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_streams.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_subprocesses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_synchronization.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tasks.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tempfile.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_testing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/_core/_typedattr.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_eventloop.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_resources.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_sockets.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_streams.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_subprocesses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_tasks.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/abc/_testing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/from_thread.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/functools.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/lowlevel.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/pytest_plugin.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/buffered.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/file.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/memory.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/stapled.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/streams/tls.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/to_interpreter.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/to_process.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/anyio/to_thread.cpython-39.pyc,, -anyio-4.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -anyio-4.12.1.dist-info/METADATA,sha256=DfiDab9Tmmcfy802lOLTMEHJQShkOSbopCwqCYbLuJk,4277 -anyio-4.12.1.dist-info/RECORD,, -anyio-4.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -anyio-4.12.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 -anyio-4.12.1.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 -anyio-4.12.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 -anyio/__init__.py,sha256=7iDVqMUprUuKNY91FuoKqayAhR-OY136YDPI6P78HHk,6170 -anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_backends/_asyncio.py,sha256=xG6qv60mgGnL0mK82dxjH2b8hlkMlJ-x2BqIq3qv70Y,98863 -anyio/_backends/_trio.py,sha256=30Rctb7lm8g63ZHljVPVnj5aH-uK6oQvphjwUBoAzuI,41456 -anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626 -anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215 -anyio/_core/_eventloop.py,sha256=c2EdcBX-xnKwxPcC4Pjn3_qG9I-x4IWFO2R9RqCGjM4,6448 -anyio/_core/_exceptions.py,sha256=Y3aq-Wxd7Q2HqwSg7nZPvRsHEuGazv_qeet6gqEBdPk,4407 -anyio/_core/_fileio.py,sha256=uc7t10Vb-If7GbdWM_zFf-ajUe6uek63fSt7IBLlZW0,25731 -anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435 -anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016 -anyio/_core/_sockets.py,sha256=RBXHcUqZt5gg_-OOfgHVv8uq2FSKk1uVUzTdpjBoI1o,34977 -anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806 -anyio/_core/_subprocesses.py,sha256=EXm5igL7dj55iYkPlbYVAqtbqxJxjU-6OndSTIx9SRg,8047 -anyio/_core/_synchronization.py,sha256=MgVVqFzvt580tHC31LiOcq1G6aryut--xRG4Ff8KwxQ,20869 -anyio/_core/_tasks.py,sha256=pVB7K6AAulzUM8YgXAeqNZG44nSyZ1bYJjH8GznC00I,5435 -anyio/_core/_tempfile.py,sha256=lHb7CW4FyIlpkf5ADAf4VmLHCKwEHF9nxqNyBCFFUiA,19697 -anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340 -anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508 -anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869 -anyio/abc/_eventloop.py,sha256=GlzgB3UJGgG6Kr7olpjOZ-o00PghecXuofVDQ_5611Q,10749 -anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783 -anyio/abc/_sockets.py,sha256=ECTY0jLEF18gryANHR3vFzXzGdZ-xPwELq1QdgOb0Jo,13258 -anyio/abc/_streams.py,sha256=005GKSCXGprxnhucILboSqc2JFovECZk9m3p-qqxXVc,7640 -anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067 -anyio/abc/_tasks.py,sha256=KC7wrciE48AINOI-AhPutnFhe1ewfP7QnamFlDzqesQ,3721 -anyio/abc/_testing.py,sha256=tBJUzkSfOXJw23fe8qSJ03kJlShOYjjaEyFB6k6MYT8,1821 -anyio/from_thread.py,sha256=L-0w1HxJ6BSb-KuVi57k5Tkc3yzQrx3QK5tAxMPcY-0,19141 -anyio/functools.py,sha256=HWj7GBEmc0Z-mZg3uok7Z7ZJn0rEC_0Pzbt0nYUDaTQ,10973 -anyio/lowlevel.py,sha256=AyKLVK3LaWSoK39LkCKxE4_GDMLKZBNqTrLUgk63y80,5158 -anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/pytest_plugin.py,sha256=3jAFQn0jv_pyoWE2GBBlHaj9sqXj4e8vob0_hgrsXE8,10244 -anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -anyio/streams/buffered.py,sha256=2R3PeJhe4EXrdYqz44Y6-Eg9R6DrmlsYrP36Ir43-po,6263 -anyio/streams/file.py,sha256=4WZ7XGz5WNu39FQHvqbe__TQ0HDP9OOhgO1mk9iVpVU,4470 -anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740 -anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390 -anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765 -anyio/streams/tls.py,sha256=Jpxy0Mfbcp1BxHCwE-YjSSFaLnIBbnnwur-excYThs4,15368 -anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100 -anyio/to_process.py,sha256=J7gAA_YOuoHqnpDAf5fm1Qu6kOmTzdFbiDNvnV755vk,9798 -anyio/to_thread.py,sha256=menEgXYmUV7Fjg_9WqCV95P9MAtQS8BzPGGcWB_QnfQ,2687 diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/entry_points.txt deleted file mode 100644 index 44dd9bd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[pytest11] -anyio = anyio.pytest_plugin diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE deleted file mode 100644 index 104eebf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Alex Grönholm - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/top_level.txt deleted file mode 100644 index c77c069..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio-4.12.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -anyio diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/__init__.py b/backend/venv39/lib/python3.9/site-packages/anyio/__init__.py deleted file mode 100644 index d23c5a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin -from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin -from ._core._eventloop import current_time as current_time -from ._core._eventloop import get_all_backends as get_all_backends -from ._core._eventloop import get_available_backends as get_available_backends -from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class -from ._core._eventloop import run as run -from ._core._eventloop import sleep as sleep -from ._core._eventloop import sleep_forever as sleep_forever -from ._core._eventloop import sleep_until as sleep_until -from ._core._exceptions import BrokenResourceError as BrokenResourceError -from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter -from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess -from ._core._exceptions import BusyResourceError as BusyResourceError -from ._core._exceptions import ClosedResourceError as ClosedResourceError -from ._core._exceptions import ConnectionFailed as ConnectionFailed -from ._core._exceptions import DelimiterNotFound as DelimiterNotFound -from ._core._exceptions import EndOfStream as EndOfStream -from ._core._exceptions import IncompleteRead as IncompleteRead -from ._core._exceptions import NoEventLoopError as NoEventLoopError -from ._core._exceptions import RunFinishedError as RunFinishedError -from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError -from ._core._exceptions import WouldBlock as WouldBlock -from ._core._fileio import AsyncFile as AsyncFile -from ._core._fileio import Path as Path -from ._core._fileio import open_file as open_file -from ._core._fileio import wrap_file as wrap_file -from ._core._resources import aclose_forcefully as aclose_forcefully -from ._core._signals import open_signal_receiver as open_signal_receiver -from ._core._sockets import TCPConnectable as TCPConnectable -from ._core._sockets import UNIXConnectable as UNIXConnectable -from ._core._sockets import as_connectable as as_connectable -from ._core._sockets import connect_tcp as connect_tcp -from ._core._sockets import connect_unix as connect_unix -from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket -from ._core._sockets import ( - create_connected_unix_datagram_socket as create_connected_unix_datagram_socket, -) -from ._core._sockets import create_tcp_listener as create_tcp_listener -from ._core._sockets import create_udp_socket as create_udp_socket -from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket -from ._core._sockets import create_unix_listener as create_unix_listener -from ._core._sockets import getaddrinfo as getaddrinfo -from ._core._sockets import getnameinfo as getnameinfo -from ._core._sockets import notify_closing as notify_closing -from ._core._sockets import wait_readable as wait_readable -from ._core._sockets import wait_socket_readable as wait_socket_readable -from ._core._sockets import wait_socket_writable as wait_socket_writable -from ._core._sockets import wait_writable as wait_writable -from ._core._streams import create_memory_object_stream as create_memory_object_stream -from ._core._subprocesses import open_process as open_process -from ._core._subprocesses import run_process as run_process -from ._core._synchronization import CapacityLimiter as CapacityLimiter -from ._core._synchronization import ( - CapacityLimiterStatistics as CapacityLimiterStatistics, -) -from ._core._synchronization import Condition as Condition -from ._core._synchronization import ConditionStatistics as ConditionStatistics -from ._core._synchronization import Event as Event -from ._core._synchronization import EventStatistics as EventStatistics -from ._core._synchronization import Lock as Lock -from ._core._synchronization import LockStatistics as LockStatistics -from ._core._synchronization import ResourceGuard as ResourceGuard -from ._core._synchronization import Semaphore as Semaphore -from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics -from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED -from ._core._tasks import CancelScope as CancelScope -from ._core._tasks import create_task_group as create_task_group -from ._core._tasks import current_effective_deadline as current_effective_deadline -from ._core._tasks import fail_after as fail_after -from ._core._tasks import move_on_after as move_on_after -from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile -from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile -from ._core._tempfile import TemporaryDirectory as TemporaryDirectory -from ._core._tempfile import TemporaryFile as TemporaryFile -from ._core._tempfile import gettempdir as gettempdir -from ._core._tempfile import gettempdirb as gettempdirb -from ._core._tempfile import mkdtemp as mkdtemp -from ._core._tempfile import mkstemp as mkstemp -from ._core._testing import TaskInfo as TaskInfo -from ._core._testing import get_current_task as get_current_task -from ._core._testing import get_running_tasks as get_running_tasks -from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked -from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider -from ._core._typedattr import TypedAttributeSet as TypedAttributeSet -from ._core._typedattr import typed_attribute as typed_attribute - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio."): - __value.__module__ = __name__ - - -del __value - - -def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]: - """Support deprecated aliases.""" - if attr == "BrokenWorkerIntepreter": - import warnings - - warnings.warn( - "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.", - DeprecationWarning, - stacklevel=2, - ) - return BrokenWorkerInterpreter - - raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_backends/__init__.py b/backend/venv39/lib/python3.9/site-packages/anyio/_backends/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_asyncio.py b/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_asyncio.py deleted file mode 100644 index 8ff009e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_asyncio.py +++ /dev/null @@ -1,2980 +0,0 @@ -from __future__ import annotations - -import array -import asyncio -import concurrent.futures -import contextvars -import math -import os -import socket -import sys -import threading -import weakref -from asyncio import ( - AbstractEventLoop, - CancelledError, - all_tasks, - create_task, - current_task, - get_running_loop, - sleep, -) -from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined] -from collections import OrderedDict, deque -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from concurrent.futures import Future -from contextlib import AbstractContextManager, suppress -from contextvars import Context, copy_context -from dataclasses import dataclass, field -from functools import partial, wraps -from inspect import ( - CORO_RUNNING, - CORO_SUSPENDED, - getcoroutinestate, - iscoroutine, -) -from io import IOBase -from os import PathLike -from queue import Queue -from signal import Signals -from socket import AddressFamily, SocketKind -from threading import Thread -from types import CodeType, TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Optional, - TypeVar, - cast, -) -from weakref import WeakKeyDictionary - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - TaskInfo, - abc, -) -from .._core._eventloop import ( - claim_worker_thread, - set_current_async_library, - threadlocals, -) -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, - RunFinishedError, - WouldBlock, - iterate_exceptions, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from ..abc import ( - AsyncBackend, - IPSockAddrType, - SocketListener, - UDPPacketType, - UNIXDatagramPacketType, -) -from ..abc._eventloop import StrOrBytesPath -from ..lowlevel import RunVar -from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -if sys.version_info >= (3, 11): - from asyncio import Runner - from typing import TypeVarTuple, Unpack -else: - import contextvars - import enum - import signal - from asyncio import coroutines, events, exceptions, tasks - - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - - class _State(enum.Enum): - CREATED = "created" - INITIALIZED = "initialized" - CLOSED = "closed" - - class Runner: - # Copied from CPython 3.11 - def __init__( - self, - *, - debug: bool | None = None, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ): - self._state = _State.CREATED - self._debug = debug - self._loop_factory = loop_factory - self._loop: AbstractEventLoop | None = None - self._context = None - self._interrupt_count = 0 - self._set_event_loop = False - - def __enter__(self) -> Runner: - self._lazy_init() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """Shutdown and close event loop.""" - loop = self._loop - if self._state is not _State.INITIALIZED or loop is None: - return - try: - _cancel_all_tasks(loop) - loop.run_until_complete(loop.shutdown_asyncgens()) - if hasattr(loop, "shutdown_default_executor"): - loop.run_until_complete(loop.shutdown_default_executor()) - else: - loop.run_until_complete(_shutdown_default_executor(loop)) - finally: - if self._set_event_loop: - events.set_event_loop(None) - loop.close() - self._loop = None - self._state = _State.CLOSED - - def get_loop(self) -> AbstractEventLoop: - """Return embedded event loop.""" - self._lazy_init() - return self._loop - - def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval: - """Run a coroutine inside the embedded event loop.""" - if not coroutines.iscoroutine(coro): - raise ValueError(f"a coroutine was expected, got {coro!r}") - - if events._get_running_loop() is not None: - # fail fast with short traceback - raise RuntimeError( - "Runner.run() cannot be called from a running event loop" - ) - - self._lazy_init() - - if context is None: - context = self._context - task = context.run(self._loop.create_task, coro) - - if ( - threading.current_thread() is threading.main_thread() - and signal.getsignal(signal.SIGINT) is signal.default_int_handler - ): - sigint_handler = partial(self._on_sigint, main_task=task) - try: - signal.signal(signal.SIGINT, sigint_handler) - except ValueError: - # `signal.signal` may throw if `threading.main_thread` does - # not support signals (e.g. embedded interpreter with signals - # not registered - see gh-91880) - sigint_handler = None - else: - sigint_handler = None - - self._interrupt_count = 0 - try: - return self._loop.run_until_complete(task) - except exceptions.CancelledError: - if self._interrupt_count > 0: - uncancel = getattr(task, "uncancel", None) - if uncancel is not None and uncancel() == 0: - raise KeyboardInterrupt # noqa: B904 - raise # CancelledError - finally: - if ( - sigint_handler is not None - and signal.getsignal(signal.SIGINT) is sigint_handler - ): - signal.signal(signal.SIGINT, signal.default_int_handler) - - def _lazy_init(self) -> None: - if self._state is _State.CLOSED: - raise RuntimeError("Runner is closed") - if self._state is _State.INITIALIZED: - return - if self._loop_factory is None: - self._loop = events.new_event_loop() - if not self._set_event_loop: - # Call set_event_loop only once to avoid calling - # attach_loop multiple times on child watchers - events.set_event_loop(self._loop) - self._set_event_loop = True - else: - self._loop = self._loop_factory() - if self._debug is not None: - self._loop.set_debug(self._debug) - self._context = contextvars.copy_context() - self._state = _State.INITIALIZED - - def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None: - self._interrupt_count += 1 - if self._interrupt_count == 1 and not main_task.done(): - main_task.cancel() - # wakeup loop if it is blocked by select() with long timeout - self._loop.call_soon_threadsafe(lambda: None) - return - raise KeyboardInterrupt() - - def _cancel_all_tasks(loop: AbstractEventLoop) -> None: - to_cancel = tasks.all_tasks(loop) - if not to_cancel: - return - - for task in to_cancel: - task.cancel() - - loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True)) - - for task in to_cancel: - if task.cancelled(): - continue - if task.exception() is not None: - loop.call_exception_handler( - { - "message": "unhandled exception during asyncio.run() shutdown", - "exception": task.exception(), - "task": task, - } - ) - - async def _shutdown_default_executor(loop: AbstractEventLoop) -> None: - """Schedule the shutdown of the default executor.""" - - def _do_shutdown(future: asyncio.futures.Future) -> None: - try: - loop._default_executor.shutdown(wait=True) # type: ignore[attr-defined] - loop.call_soon_threadsafe(future.set_result, None) - except Exception as ex: - loop.call_soon_threadsafe(future.set_exception, ex) - - loop._executor_shutdown_called = True - if loop._default_executor is None: - return - future = loop.create_future() - thread = threading.Thread(target=_do_shutdown, args=(future,)) - thread.start() - try: - await future - finally: - thread.join() - - -T_Retval = TypeVar("T_Retval") -T_contra = TypeVar("T_contra", contravariant=True) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - -_root_task: RunVar[asyncio.Task | None] = RunVar("_root_task") - - -def find_root_task() -> asyncio.Task: - root_task = _root_task.get(None) - if root_task is not None and not root_task.done(): - return root_task - - # Look for a task that has been started via run_until_complete() - for task in all_tasks(): - if task._callbacks and not task.done(): - callbacks = [cb for cb, context in task._callbacks] - for cb in callbacks: - if ( - cb is _run_until_complete_cb - or getattr(cb, "__module__", None) == "uvloop.loop" - ): - _root_task.set(task) - return task - - # Look up the topmost task in the AnyIO task tree, if possible - task = cast(asyncio.Task, current_task()) - state = _task_states.get(task) - if state: - cancel_scope = state.cancel_scope - while cancel_scope and cancel_scope._parent_scope is not None: - cancel_scope = cancel_scope._parent_scope - - if cancel_scope is not None: - return cast(asyncio.Task, cancel_scope._host_task) - - return task - - -def get_callable_name(func: Callable) -> str: - module = getattr(func, "__module__", None) - qualname = getattr(func, "__qualname__", None) - return ".".join([x for x in (module, qualname) if x]) - - -# -# Event loop -# - -_run_vars: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] = WeakKeyDictionary() - - -def _task_started(task: asyncio.Task) -> bool: - """Return ``True`` if the task has been started and has not finished.""" - # The task coro should never be None here, as we never add finished tasks to the - # task list - coro = task.get_coro() - assert coro is not None - try: - return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) - except AttributeError: - # task coro is async_genenerator_asend https://bugs.python.org/issue37771 - raise Exception(f"Cannot determine if task {task} has started or not") from None - - -# -# Timeouts and cancellation -# - - -def is_anyio_cancellation(exc: CancelledError) -> bool: - # Sometimes third party frameworks catch a CancelledError and raise a new one, so as - # a workaround we have to look at the previous ones in __context__ too for a - # matching cancel message - while True: - if ( - exc.args - and isinstance(exc.args[0], str) - and exc.args[0].startswith("Cancelled via cancel scope ") - ): - return True - - if isinstance(exc.__context__, CancelledError): - exc = exc.__context__ - continue - - return False - - -class CancelScope(BaseCancelScope): - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, deadline: float = math.inf, shield: bool = False): - self._deadline = deadline - self._shield = shield - self._parent_scope: CancelScope | None = None - self._child_scopes: set[CancelScope] = set() - self._cancel_called = False - self._cancel_reason: str | None = None - self._cancelled_caught = False - self._active = False - self._timeout_handle: asyncio.TimerHandle | None = None - self._cancel_handle: asyncio.Handle | None = None - self._tasks: set[asyncio.Task] = set() - self._host_task: asyncio.Task | None = None - if sys.version_info >= (3, 11): - self._pending_uncancellations: int | None = 0 - else: - self._pending_uncancellations = None - - def __enter__(self) -> CancelScope: - if self._active: - raise RuntimeError( - "Each CancelScope may only be used for a single 'with' block" - ) - - self._host_task = host_task = cast(asyncio.Task, current_task()) - self._tasks.add(host_task) - try: - task_state = _task_states[host_task] - except KeyError: - task_state = TaskState(None, self) - _task_states[host_task] = task_state - else: - self._parent_scope = task_state.cancel_scope - task_state.cancel_scope = self - if self._parent_scope is not None: - # If using an eager task factory, the parent scope may not even contain - # the host task - self._parent_scope._child_scopes.add(self) - self._parent_scope._tasks.discard(host_task) - - self._timeout() - self._active = True - - # Start cancelling the host task if the scope was cancelled before entering - if self._cancel_called: - self._deliver_cancellation(self) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - del exc_tb - - if not self._active: - raise RuntimeError("This cancel scope is not active") - if current_task() is not self._host_task: - raise RuntimeError( - "Attempted to exit cancel scope in a different task than it was " - "entered in" - ) - - assert self._host_task is not None - host_task_state = _task_states.get(self._host_task) - if host_task_state is None or host_task_state.cancel_scope is not self: - raise RuntimeError( - "Attempted to exit a cancel scope that isn't the current tasks's " - "current cancel scope" - ) - - try: - self._active = False - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._tasks.remove(self._host_task) - if self._parent_scope is not None: - self._parent_scope._child_scopes.remove(self) - self._parent_scope._tasks.add(self._host_task) - - host_task_state.cancel_scope = self._parent_scope - - # Restart the cancellation effort in the closest visible, cancelled parent - # scope if necessary - self._restart_cancellation_in_parent() - - # We only swallow the exception iff it was an AnyIO CancelledError, either - # directly as exc_val or inside an exception group and there are no cancelled - # parent cancel scopes visible to us here - if self._cancel_called and not self._parent_cancellation_is_visible_to_us: - # For each level-cancel() call made on the host task, call uncancel() - while self._pending_uncancellations: - self._host_task.uncancel() - self._pending_uncancellations -= 1 - - # Update cancelled_caught and check for exceptions we must not swallow - cannot_swallow_exc_val = False - if exc_val is not None: - for exc in iterate_exceptions(exc_val): - if isinstance(exc, CancelledError) and is_anyio_cancellation( - exc - ): - self._cancelled_caught = True - else: - cannot_swallow_exc_val = True - - return self._cancelled_caught and not cannot_swallow_exc_val - else: - if self._pending_uncancellations: - assert self._parent_scope is not None - assert self._parent_scope._pending_uncancellations is not None - self._parent_scope._pending_uncancellations += ( - self._pending_uncancellations - ) - self._pending_uncancellations = 0 - - return False - finally: - self._host_task = None - del exc_val - - @property - def _effectively_cancelled(self) -> bool: - cancel_scope: CancelScope | None = self - while cancel_scope is not None: - if cancel_scope._cancel_called: - return True - - if cancel_scope.shield: - return False - - cancel_scope = cancel_scope._parent_scope - - return False - - @property - def _parent_cancellation_is_visible_to_us(self) -> bool: - return ( - self._parent_scope is not None - and not self.shield - and self._parent_scope._effectively_cancelled - ) - - def _timeout(self) -> None: - if self._deadline != math.inf: - loop = get_running_loop() - if loop.time() >= self._deadline: - self.cancel("deadline exceeded") - else: - self._timeout_handle = loop.call_at(self._deadline, self._timeout) - - def _deliver_cancellation(self, origin: CancelScope) -> bool: - """ - Deliver cancellation to directly contained tasks and nested cancel scopes. - - Schedule another run at the end if we still have tasks eligible for - cancellation. - - :param origin: the cancel scope that originated the cancellation - :return: ``True`` if the delivery needs to be retried on the next cycle - - """ - should_retry = False - current = current_task() - for task in self._tasks: - should_retry = True - if task._must_cancel: # type: ignore[attr-defined] - continue - - # The task is eligible for cancellation if it has started - if task is not current and (task is self._host_task or _task_started(task)): - waiter = task._fut_waiter # type: ignore[attr-defined] - if not isinstance(waiter, asyncio.Future) or not waiter.done(): - task.cancel(origin._cancel_reason) - if ( - task is origin._host_task - and origin._pending_uncancellations is not None - ): - origin._pending_uncancellations += 1 - - # Deliver cancellation to child scopes that aren't shielded or running their own - # cancellation callbacks - for scope in self._child_scopes: - if not scope._shield and not scope.cancel_called: - should_retry = scope._deliver_cancellation(origin) or should_retry - - # Schedule another callback if there are still tasks left - if origin is self: - if should_retry: - self._cancel_handle = get_running_loop().call_soon( - self._deliver_cancellation, origin - ) - else: - self._cancel_handle = None - - return should_retry - - def _restart_cancellation_in_parent(self) -> None: - """ - Restart the cancellation effort in the closest directly cancelled parent scope. - - """ - scope = self._parent_scope - while scope is not None: - if scope._cancel_called: - if scope._cancel_handle is None: - scope._deliver_cancellation(scope) - - break - - # No point in looking beyond any shielded scope - if scope._shield: - break - - scope = scope._parent_scope - - def cancel(self, reason: str | None = None) -> None: - if not self._cancel_called: - if self._timeout_handle: - self._timeout_handle.cancel() - self._timeout_handle = None - - self._cancel_called = True - self._cancel_reason = f"Cancelled via cancel scope {id(self):x}" - if task := current_task(): - self._cancel_reason += f" by {task}" - - if reason: - self._cancel_reason += f"; reason: {reason}" - - if self._host_task is not None: - self._deliver_cancellation(self) - - @property - def deadline(self) -> float: - return self._deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self._deadline = float(value) - if self._timeout_handle is not None: - self._timeout_handle.cancel() - self._timeout_handle = None - - if self._active and not self._cancel_called: - self._timeout() - - @property - def cancel_called(self) -> bool: - return self._cancel_called - - @property - def cancelled_caught(self) -> bool: - return self._cancelled_caught - - @property - def shield(self) -> bool: - return self._shield - - @shield.setter - def shield(self, value: bool) -> None: - if self._shield != value: - self._shield = value - if not value: - self._restart_cancellation_in_parent() - - -# -# Task states -# - - -class TaskState: - """ - Encapsulates auxiliary task information that cannot be added to the Task instance - itself because there are no guarantees about its implementation. - """ - - __slots__ = "parent_id", "cancel_scope", "__weakref__" - - def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None): - self.parent_id = parent_id - self.cancel_scope = cancel_scope - - -_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary() - - -# -# Task groups -# - - -class _AsyncioTaskStatus(abc.TaskStatus): - def __init__(self, future: asyncio.Future, parent_id: int): - self._future = future - self._parent_id = parent_id - - def started(self, value: T_contra | None = None) -> None: - try: - self._future.set_result(value) - except asyncio.InvalidStateError: - if not self._future.cancelled(): - raise RuntimeError( - "called 'started' twice on the same task status" - ) from None - - task = cast(asyncio.Task, current_task()) - _task_states[task].parent_id = self._parent_id - - -if sys.version_info >= (3, 12): - _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__ -else: - _eager_task_factory_code = None - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self.cancel_scope: CancelScope = CancelScope() - self._active = False - self._exceptions: list[BaseException] = [] - self._tasks: set[asyncio.Task] = set() - self._on_completed_fut: asyncio.Future[None] | None = None - - async def __aenter__(self) -> TaskGroup: - self.cancel_scope.__enter__() - self._active = True - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - if exc_val is not None: - self.cancel_scope.cancel() - if not isinstance(exc_val, CancelledError): - self._exceptions.append(exc_val) - - loop = get_running_loop() - try: - if self._tasks: - with CancelScope() as wait_scope: - while self._tasks: - self._on_completed_fut = loop.create_future() - - try: - await self._on_completed_fut - except CancelledError as exc: - # Shield the scope against further cancellation attempts, - # as they're not productive (#695) - wait_scope.shield = True - self.cancel_scope.cancel() - - # Set exc_val from the cancellation exception if it was - # previously unset. However, we should not replace a native - # cancellation exception with one raise by a cancel scope. - if exc_val is None or ( - isinstance(exc_val, CancelledError) - and not is_anyio_cancellation(exc) - ): - exc_val = exc - - self._on_completed_fut = None - else: - # If there are no child tasks to wait on, run at least one checkpoint - # anyway - await AsyncIOBackend.cancel_shielded_checkpoint() - - self._active = False - if self._exceptions: - # The exception that got us here should already have been - # added to self._exceptions so it's ok to break exception - # chaining and avoid adding a "During handling of above..." - # for each nesting level. - raise BaseExceptionGroup( - "unhandled errors in a TaskGroup", self._exceptions - ) from None - elif exc_val: - raise exc_val - except BaseException as exc: - if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__): - return True - - raise - - return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) - finally: - del exc_val, exc_tb, self._exceptions - - def _spawn( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - args: tuple[Unpack[PosArgsT]], - name: object, - task_status_future: asyncio.Future | None = None, - ) -> asyncio.Task: - def task_done(_task: asyncio.Task) -> None: - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_discard_from_awaited_by( - _task, self.cancel_scope._host_task - ) - - task_state = _task_states[_task] - assert task_state.cancel_scope is not None - assert _task in task_state.cancel_scope._tasks - task_state.cancel_scope._tasks.remove(_task) - self._tasks.remove(task) - del _task_states[_task] - - if self._on_completed_fut is not None and not self._tasks: - try: - self._on_completed_fut.set_result(None) - except asyncio.InvalidStateError: - pass - - try: - exc = _task.exception() - except CancelledError as e: - while isinstance(e.__context__, CancelledError): - e = e.__context__ - - exc = e - - if exc is not None: - # The future can only be in the cancelled state if the host task was - # cancelled, so return immediately instead of adding one more - # CancelledError to the exceptions list - if task_status_future is not None and task_status_future.cancelled(): - return - - if task_status_future is None or task_status_future.done(): - if not isinstance(exc, CancelledError): - self._exceptions.append(exc) - - if not self.cancel_scope._effectively_cancelled: - self.cancel_scope.cancel() - else: - task_status_future.set_exception(exc) - elif task_status_future is not None and not task_status_future.done(): - task_status_future.set_exception( - RuntimeError("Child exited without calling task_status.started()") - ) - - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - kwargs = {} - if task_status_future: - parent_id = id(current_task()) - kwargs["task_status"] = _AsyncioTaskStatus( - task_status_future, id(self.cancel_scope._host_task) - ) - else: - parent_id = id(self.cancel_scope._host_task) - - coro = func(*args, **kwargs) - if not iscoroutine(coro): - prefix = f"{func.__module__}." if hasattr(func, "__module__") else "" - raise TypeError( - f"Expected {prefix}{func.__qualname__}() to return a coroutine, but " - f"the return value ({coro!r}) is not a coroutine object" - ) - - name = get_callable_name(func) if name is None else str(name) - loop = asyncio.get_running_loop() - if ( - (factory := loop.get_task_factory()) - and getattr(factory, "__code__", None) is _eager_task_factory_code - and (closure := getattr(factory, "__closure__", None)) - ): - custom_task_constructor = closure[0].cell_contents - task = custom_task_constructor(coro, loop=loop, name=name) - else: - task = create_task(coro, name=name) - - # Make the spawned task inherit the task group's cancel scope - _task_states[task] = TaskState( - parent_id=parent_id, cancel_scope=self.cancel_scope - ) - self.cancel_scope._tasks.add(task) - self._tasks.add(task) - if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: - asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task) - - task.add_done_callback(task_done) - return task - - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - self._spawn(func, args, name) - - async def start( - self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None - ) -> Any: - future: asyncio.Future = asyncio.Future() - task = self._spawn(func, args, name, future) - - # If the task raises an exception after sending a start value without a switch - # point between, the task group is cancelled and this method never proceeds to - # process the completed future. That's why we have to have a shielded cancel - # scope here. - try: - return await future - except CancelledError: - # Cancel the task and wait for it to exit before returning - task.cancel() - with CancelScope(shield=True), suppress(CancelledError): - await task - - raise - - -# -# Threads -# - -_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]] - - -class WorkerThread(Thread): - MAX_IDLE_TIME = 10 # seconds - - def __init__( - self, - root_task: asyncio.Task, - workers: set[WorkerThread], - idle_workers: deque[WorkerThread], - ): - super().__init__(name="AnyIO worker thread") - self.root_task = root_task - self.workers = workers - self.idle_workers = idle_workers - self.loop = root_task._loop - self.queue: Queue[ - tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None - ] = Queue(2) - self.idle_since = AsyncIOBackend.current_time() - self.stopping = False - - def _report_result( - self, future: asyncio.Future, result: Any, exc: BaseException | None - ) -> None: - self.idle_since = AsyncIOBackend.current_time() - if not self.stopping: - self.idle_workers.append(self) - - if not future.cancelled(): - if exc is not None: - if isinstance(exc, StopIteration): - new_exc = RuntimeError("coroutine raised StopIteration") - new_exc.__cause__ = exc - exc = new_exc - - future.set_exception(exc) - else: - future.set_result(result) - - def run(self) -> None: - with claim_worker_thread(AsyncIOBackend, self.loop): - while True: - item = self.queue.get() - if item is None: - # Shutdown command received - return - - context, func, args, future, cancel_scope = item - if not future.cancelled(): - result = None - exception: BaseException | None = None - threadlocals.current_cancel_scope = cancel_scope - try: - result = context.run(func, *args) - except BaseException as exc: - exception = exc - finally: - del threadlocals.current_cancel_scope - - if not self.loop.is_closed(): - self.loop.call_soon_threadsafe( - self._report_result, future, result, exception - ) - - del result, exception - - self.queue.task_done() - del item, context, func, args, future, cancel_scope - - def stop(self, f: asyncio.Task | None = None) -> None: - self.stopping = True - self.queue.put_nowait(None) - self.workers.discard(self) - try: - self.idle_workers.remove(self) - except ValueError: - pass - - -_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar( - "_threadpool_idle_workers" -) -_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers") - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class StreamReaderWrapper(abc.ByteReceiveStream): - _stream: asyncio.StreamReader - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._stream.read(max_bytes) - if data: - return data - else: - raise EndOfStream - - async def aclose(self) -> None: - self._stream.set_exception(ClosedResourceError()) - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class StreamWriterWrapper(abc.ByteSendStream): - _stream: asyncio.StreamWriter - _closed: bool = field(init=False, default=False) - - async def send(self, item: bytes) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - stream_paused = self._stream._protocol._paused # type: ignore[attr-defined] - try: - self._stream.write(item) - await self._stream.drain() - except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc: - # If closed by us and/or the peer: - # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError - # * on uvloop and Winloop, write() eventually starts raising RuntimeError - if self._closed: - raise ClosedResourceError from exc - elif self._stream.is_closing(): - raise BrokenResourceError from exc - - raise - - if not stream_paused: - await AsyncIOBackend.cancel_shielded_checkpoint() - - async def aclose(self) -> None: - self._closed = True - self._stream.close() - await AsyncIOBackend.checkpoint() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: asyncio.subprocess.Process - _stdin: StreamWriterWrapper | None - _stdout: StreamReaderWrapper | None - _stderr: StreamReaderWrapper | None - - async def aclose(self) -> None: - with CancelScope(shield=True) as scope: - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - scope.shield = False - try: - await self.wait() - except BaseException: - scope.shield = True - self.kill() - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: int) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -def _forcibly_shutdown_process_pool_on_exit( - workers: set[Process], _task: object -) -> None: - """ - Forcibly shuts down worker processes belonging to this event loop.""" - child_watcher: asyncio.AbstractChildWatcher | None = None # type: ignore[name-defined] - if sys.version_info < (3, 12): - try: - child_watcher = asyncio.get_event_loop_policy().get_child_watcher() - except NotImplementedError: - pass - - # Close as much as possible (w/o async/await) to avoid warnings - for process in workers.copy(): - if process.returncode is None: - continue - - process._stdin._stream._transport.close() # type: ignore[union-attr] - process._stdout._stream._transport.close() # type: ignore[union-attr] - process._stderr._stream._transport.close() # type: ignore[union-attr] - process.kill() - if child_watcher: - child_watcher.remove_child_handler(process.pid) - - -async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None: - """ - Shuts down worker processes belonging to this event loop. - - NOTE: this only works when the event loop was started using asyncio.run() or - anyio.run(). - - """ - process: abc.Process - try: - await sleep(math.inf) - except asyncio.CancelledError: - workers = workers.copy() - for process in workers: - if process.returncode is None: - process.kill() - - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class StreamProtocol(asyncio.Protocol): - read_queue: deque[bytes] - read_event: asyncio.Event - write_event: asyncio.Event - exception: Exception | None = None - is_at_eof: bool = False - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque() - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.write_event.set() - cast(asyncio.Transport, transport).set_write_buffer_limits(0) - - def connection_lost(self, exc: Exception | None) -> None: - if exc: - self.exception = BrokenResourceError() - self.exception.__cause__ = exc - - self.read_event.set() - self.write_event.set() - - def data_received(self, data: bytes) -> None: - # ProactorEventloop sometimes sends bytearray instead of bytes - self.read_queue.append(bytes(data)) - self.read_event.set() - - def eof_received(self) -> bool | None: - self.is_at_eof = True - self.read_event.set() - return True - - def pause_writing(self) -> None: - self.write_event = asyncio.Event() - - def resume_writing(self) -> None: - self.write_event.set() - - -class DatagramProtocol(asyncio.DatagramProtocol): - read_queue: deque[tuple[bytes, IPSockAddrType]] - read_event: asyncio.Event - write_event: asyncio.Event - exception: Exception | None = None - - def connection_made(self, transport: asyncio.BaseTransport) -> None: - self.read_queue = deque(maxlen=100) # arbitrary value - self.read_event = asyncio.Event() - self.write_event = asyncio.Event() - self.write_event.set() - - def connection_lost(self, exc: Exception | None) -> None: - self.read_event.set() - self.write_event.set() - - def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None: - addr = convert_ipv6_sockaddr(addr) - self.read_queue.append((data, addr)) - self.read_event.set() - - def error_received(self, exc: Exception) -> None: - self.exception = exc - - def pause_writing(self) -> None: - self.write_event.clear() - - def resume_writing(self) -> None: - self.write_event.set() - - -class SocketStream(abc.SocketStream): - def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - if ( - not self._protocol.read_event.is_set() - and not self._transport.is_closing() - and not self._protocol.is_at_eof - ): - self._transport.resume_reading() - await self._protocol.read_event.wait() - self._transport.pause_reading() - else: - await AsyncIOBackend.checkpoint() - - try: - chunk = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - elif self._protocol.exception: - raise self._protocol.exception from None - else: - raise EndOfStream from None - - if len(chunk) > max_bytes: - # Split the oversized chunk - chunk, leftover = chunk[:max_bytes], chunk[max_bytes:] - self._protocol.read_queue.appendleft(leftover) - - # If the read queue is empty, clear the flag so that the next call will - # block until data is available - if not self._protocol.read_queue: - self._protocol.read_event.clear() - - return chunk - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - - if self._closed: - raise ClosedResourceError - elif self._protocol.exception is not None: - raise self._protocol.exception - - try: - self._transport.write(item) - except RuntimeError as exc: - if self._transport.is_closing(): - raise BrokenResourceError from exc - else: - raise - - await self._protocol.write_event.wait() - - async def send_eof(self) -> None: - try: - self._transport.write_eof() - except OSError: - pass - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - try: - self._transport.write_eof() - except OSError: - pass - - self._transport.close() - await sleep(0) - self._transport.abort() - - -class _RawSocketMixin: - _receive_future: asyncio.Future | None = None - _send_future: asyncio.Future | None = None - _closing = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._receive_future - loop.remove_reader(self.__raw_socket) - - f = self._receive_future = asyncio.Future() - loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: - def callback(f: object) -> None: - del self._send_future - loop.remove_writer(self.__raw_socket) - - f = self._send_future = asyncio.Future() - loop.add_writer(self.__raw_socket, f.set_result, None) - f.add_done_callback(callback) - return f - - async def aclose(self) -> None: - if not self._closing: - self._closing = True - if self.__raw_socket.fileno() != -1: - self.__raw_socket.close() - - if self._receive_future: - self._receive_future.set_result(None) - if self._send_future: - self._send_future.set_result(None) - - -class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream): - async def send_eof(self) -> None: - with self._send_guard: - self._raw_socket.shutdown(socket.SHUT_WR) - - async def receive(self, max_bytes: int = 65536) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(max_bytes) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = self._raw_socket.send(view) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - view = view[bytes_sent:] - - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - loop = get_running_loop() - fds = array.array("i") - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = self._raw_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - loop = get_running_loop() - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - # The ignore can be removed after mypy picks up - # https://github.com/python/typeshed/pull/5545 - self._raw_socket.sendmsg( - [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)] - ) - break - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - -class TCPSocketListener(abc.SocketListener): - _accept_scope: CancelScope | None = None - _closed = False - - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = cast(asyncio.BaseEventLoop, get_running_loop()) - self._accept_guard = ResourceGuard("accepting connections from") - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - async def accept(self) -> abc.SocketStream: - if self._closed: - raise ClosedResourceError - - with self._accept_guard: - await AsyncIOBackend.checkpoint() - with CancelScope() as self._accept_scope: - try: - client_sock, _addr = await self._loop.sock_accept(self._raw_socket) - except asyncio.CancelledError: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - if self._closed: - raise ClosedResourceError from None - - raise - finally: - self._accept_scope = None - - client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - transport, protocol = await self._loop.connect_accepted_socket( - StreamProtocol, client_sock - ) - return SocketStream(transport, protocol) - - async def aclose(self) -> None: - if self._closed: - return - - self._closed = True - if self._accept_scope: - # Workaround for https://bugs.python.org/issue41317 - try: - self._loop.remove_reader(self._raw_socket) - except (ValueError, NotImplementedError): - pass - - self._accept_scope.cancel() - await sleep(0) - - self._raw_socket.close() - - -class UNIXSocketListener(abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - self.__raw_socket = raw_socket - self._loop = get_running_loop() - self._accept_guard = ResourceGuard("accepting connections from") - self._closed = False - - async def accept(self) -> abc.SocketStream: - await AsyncIOBackend.checkpoint() - with self._accept_guard: - while True: - try: - client_sock, _ = self.__raw_socket.accept() - client_sock.setblocking(False) - return UNIXSocketStream(client_sock) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - self._loop.add_reader(self.__raw_socket, f.set_result, None) - f.add_done_callback( - lambda _: self._loop.remove_reader(self.__raw_socket) - ) - await f - except OSError as exc: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - - async def aclose(self) -> None: - self._closed = True - self.__raw_socket.close() - - @property - def _raw_socket(self) -> socket.socket: - return self.__raw_socket - - -class UDPSocket(abc.UDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - return self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(*item) - - -class ConnectedUDPSocket(abc.ConnectedUDPSocket): - def __init__( - self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol - ): - self._transport = transport - self._protocol = protocol - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - self._closed = False - - @property - def _raw_socket(self) -> socket.socket: - return self._transport.get_extra_info("socket") - - async def aclose(self) -> None: - self._closed = True - if not self._transport.is_closing(): - self._transport.close() - - async def receive(self) -> bytes: - with self._receive_guard: - await AsyncIOBackend.checkpoint() - - # If the buffer is empty, ask for more data - if not self._protocol.read_queue and not self._transport.is_closing(): - self._protocol.read_event.clear() - await self._protocol.read_event.wait() - - try: - packet = self._protocol.read_queue.popleft() - except IndexError: - if self._closed: - raise ClosedResourceError from None - else: - raise BrokenResourceError from None - - return packet[0] - - async def send(self, item: bytes) -> None: - with self._send_guard: - await AsyncIOBackend.checkpoint() - await self._protocol.write_event.wait() - if self._closed: - raise ClosedResourceError - elif self._transport.is_closing(): - raise BrokenResourceError - else: - self._transport.sendto(item) - - -class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket): - async def receive(self) -> UNIXDatagramPacketType: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recvfrom(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: UNIXDatagramPacketType) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.sendto(*item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket): - async def receive(self) -> bytes: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._receive_guard: - while True: - try: - data = self._raw_socket.recv(65536) - except BlockingIOError: - await self._wait_until_readable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return data - - async def send(self, item: bytes) -> None: - loop = get_running_loop() - await AsyncIOBackend.checkpoint() - with self._send_guard: - while True: - try: - self._raw_socket.send(item) - except BlockingIOError: - await self._wait_until_writable(loop) - except OSError as exc: - if self._closing: - raise ClosedResourceError from None - else: - raise BrokenResourceError from exc - else: - return - - -_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events") -_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events") - - -# -# Synchronization -# - - -class Event(BaseEvent): - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self._event = asyncio.Event() - - def set(self) -> None: - self._event.set() - - def is_set(self) -> bool: - return self._event.is_set() - - async def wait(self) -> None: - if self.is_set(): - await AsyncIOBackend.checkpoint() - else: - await self._event.wait() - - def statistics(self) -> EventStatistics: - return EventStatistics(len(self._event._waiters)) - - -class Lock(BaseLock): - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self._owner_task: asyncio.Task | None = None - self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque() - - async def acquire(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._owner_task = task - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - if self._owner_task == task: - raise RuntimeError("Attempted to acquire an already held Lock") - - fut: asyncio.Future[None] = asyncio.Future() - item = task, fut - self._waiters.append(item) - try: - await fut - except CancelledError: - self._waiters.remove(item) - if self._owner_task is task: - self.release() - - raise - - self._waiters.remove(item) - - def acquire_nowait(self) -> None: - task = cast(asyncio.Task, current_task()) - if self._owner_task is None and not self._waiters: - self._owner_task = task - return - - if self._owner_task is task: - raise RuntimeError("Attempted to acquire an already held Lock") - - raise WouldBlock - - def locked(self) -> bool: - return self._owner_task is not None - - def release(self) -> None: - if self._owner_task != current_task(): - raise RuntimeError("The current task is not holding this lock") - - for task, fut in self._waiters: - if not fut.cancelled(): - self._owner_task = task - fut.set_result(None) - return - - self._owner_task = None - - def statistics(self) -> LockStatistics: - task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None - return LockStatistics(self.locked(), task_info, len(self._waiters)) - - -class Semaphore(BaseSemaphore): - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - super().__init__(initial_value, max_value=max_value) - self._value = initial_value - self._max_value = max_value - self._fast_acquire = fast_acquire - self._waiters: deque[asyncio.Future[None]] = deque() - - async def acquire(self) -> None: - if self._value > 0 and not self._waiters: - await AsyncIOBackend.checkpoint_if_cancelled() - self._value -= 1 - - # Unless on the "fast path", yield control of the event loop so that other - # tasks can run too - if not self._fast_acquire: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except CancelledError: - self.release() - raise - - return - - fut: asyncio.Future[None] = asyncio.Future() - self._waiters.append(fut) - try: - await fut - except CancelledError: - try: - self._waiters.remove(fut) - except ValueError: - self.release() - - raise - - def acquire_nowait(self) -> None: - if self._value == 0: - raise WouldBlock - - self._value -= 1 - - def release(self) -> None: - if self._max_value is not None and self._value == self._max_value: - raise ValueError("semaphore released too many times") - - for fut in self._waiters: - if not fut.cancelled(): - fut.set_result(None) - self._waiters.remove(fut) - return - - self._value += 1 - - @property - def value(self) -> int: - return self._value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - return SemaphoreStatistics(len(self._waiters)) - - -class CapacityLimiter(BaseCapacityLimiter): - _total_tokens: float = 0 - - def __new__(cls, total_tokens: float) -> CapacityLimiter: - return object.__new__(cls) - - def __init__(self, total_tokens: float): - self._borrowers: set[Any] = set() - self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict() - self.total_tokens = total_tokens - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - @property - def total_tokens(self) -> float: - return self._total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and not math.isinf(value): - raise TypeError("total_tokens must be an int or math.inf") - - if value < 0: - raise ValueError("total_tokens must be >= 0") - - waiters_to_notify = max(value - self._total_tokens, 0) - self._total_tokens = value - - # Notify waiting tasks that they have acquired the limiter - while self._wait_queue and waiters_to_notify: - event = self._wait_queue.popitem(last=False)[1] - event.set() - waiters_to_notify -= 1 - - @property - def borrowed_tokens(self) -> int: - return len(self._borrowers) - - @property - def available_tokens(self) -> float: - return self._total_tokens - len(self._borrowers) - - def _notify_next_waiter(self) -> None: - """Notify the next task in line if this limiter has free capacity now.""" - if self._wait_queue and len(self._borrowers) < self._total_tokens: - event = self._wait_queue.popitem(last=False)[1] - event.set() - - def acquire_nowait(self) -> None: - self.acquire_on_behalf_of_nowait(current_task()) - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - if borrower in self._borrowers: - raise RuntimeError( - "this borrower is already holding one of this CapacityLimiter's tokens" - ) - - if self._wait_queue or len(self._borrowers) >= self._total_tokens: - raise WouldBlock - - self._borrowers.add(borrower) - - async def acquire(self) -> None: - return await self.acquire_on_behalf_of(current_task()) - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await AsyncIOBackend.checkpoint_if_cancelled() - try: - self.acquire_on_behalf_of_nowait(borrower) - except WouldBlock: - event = asyncio.Event() - self._wait_queue[borrower] = event - try: - await event.wait() - except BaseException: - self._wait_queue.pop(borrower, None) - if event.is_set(): - self._notify_next_waiter() - - raise - - self._borrowers.add(borrower) - else: - try: - await AsyncIOBackend.cancel_shielded_checkpoint() - except BaseException: - self.release() - raise - - def release(self) -> None: - self.release_on_behalf_of(current_task()) - - def release_on_behalf_of(self, borrower: object) -> None: - try: - self._borrowers.remove(borrower) - except KeyError: - raise RuntimeError( - "this borrower isn't holding any of this CapacityLimiter's tokens" - ) from None - - self._notify_next_waiter() - - def statistics(self) -> CapacityLimiterStatistics: - return CapacityLimiterStatistics( - self.borrowed_tokens, - self.total_tokens, - tuple(self._borrowers), - len(self._wait_queue), - ) - - -_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter") - - -# -# Operating system signals -# - - -class _SignalReceiver: - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - self._loop = get_running_loop() - self._signal_queue: deque[Signals] = deque() - self._future: asyncio.Future = asyncio.Future() - self._handled_signals: set[Signals] = set() - - def _deliver(self, signum: Signals) -> None: - self._signal_queue.append(signum) - if not self._future.done(): - self._future.set_result(None) - - def __enter__(self) -> _SignalReceiver: - for sig in set(self._signals): - self._loop.add_signal_handler(sig, self._deliver, sig) - self._handled_signals.add(sig) - - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - for sig in self._handled_signals: - self._loop.remove_signal_handler(sig) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - await AsyncIOBackend.checkpoint() - if not self._signal_queue: - self._future = asyncio.Future() - await self._future - - return self._signal_queue.popleft() - - -# -# Testing and debugging -# - - -class AsyncIOTaskInfo(TaskInfo): - def __init__(self, task: asyncio.Task): - task_state = _task_states.get(task) - if task_state is None: - parent_id = None - else: - parent_id = task_state.parent_id - - coro = task.get_coro() - assert coro is not None, "created TaskInfo from a completed Task" - super().__init__(id(task), parent_id, task.get_name(), coro) - self._task = weakref.ref(task) - - def has_pending_cancellation(self) -> bool: - if not (task := self._task()): - # If the task isn't around anymore, it won't have a pending cancellation - return False - - if task._must_cancel: # type: ignore[attr-defined] - return True - elif ( - isinstance(task._fut_waiter, asyncio.Future) # type: ignore[attr-defined] - and task._fut_waiter.cancelled() # type: ignore[attr-defined] - ): - return True - - if task_state := _task_states.get(task): - if cancel_scope := task_state.cancel_scope: - return cancel_scope._effectively_cancelled - - return False - - -class TestRunner(abc.TestRunner): - _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]] - - def __init__( - self, - *, - debug: bool | None = None, - use_uvloop: bool = False, - loop_factory: Callable[[], AbstractEventLoop] | None = None, - ) -> None: - if use_uvloop and loop_factory is None: - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - self._runner = Runner(debug=debug, loop_factory=loop_factory) - self._exceptions: list[BaseException] = [] - self._runner_task: asyncio.Task | None = None - - def __enter__(self) -> TestRunner: - self._runner.__enter__() - self.get_loop().set_exception_handler(self._exception_handler) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._runner.__exit__(exc_type, exc_val, exc_tb) - - def get_loop(self) -> AbstractEventLoop: - return self._runner.get_loop() - - def _exception_handler( - self, loop: asyncio.AbstractEventLoop, context: dict[str, Any] - ) -> None: - if isinstance(context.get("exception"), Exception): - self._exceptions.append(context["exception"]) - else: - loop.default_exception_handler(context) - - def _raise_async_exceptions(self) -> None: - # Re-raise any exceptions raised in asynchronous callbacks - if self._exceptions: - exceptions, self._exceptions = self._exceptions, [] - if len(exceptions) == 1: - raise exceptions[0] - elif exceptions: - raise BaseExceptionGroup( - "Multiple exceptions occurred in asynchronous callbacks", exceptions - ) - - async def _run_tests_and_fixtures( - self, - receive_stream: MemoryObjectReceiveStream[ - tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]] - ], - ) -> None: - from _pytest.outcomes import OutcomeException - - with receive_stream, self._send_stream: - async for coro, future in receive_stream: - try: - retval = await coro - except CancelledError as exc: - if not future.cancelled(): - future.cancel(*exc.args) - - raise - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - if not isinstance(exc, (Exception, OutcomeException)): - raise - else: - if not future.cancelled(): - future.set_result(retval) - - async def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if not self._runner_task: - self._send_stream, receive_stream = create_memory_object_stream[ - tuple[Awaitable[Any], asyncio.Future] - ](1) - self._runner_task = self.get_loop().create_task( - self._run_tests_and_fixtures(receive_stream) - ) - - coro = func(*args, **kwargs) - future: asyncio.Future[T_Retval] = self.get_loop().create_future() - self._send_stream.send_nowait((coro, future)) - return await future - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - self._raise_async_exceptions() - - yield fixturevalue - - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(asyncgen.asend, None) - ) - except StopAsyncIteration: - self._raise_async_exceptions() - else: - self.get_loop().run_until_complete(asyncgen.aclose()) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - retval = self.get_loop().run_until_complete( - self._call_in_runner_task(fixture_func, **kwargs) - ) - self._raise_async_exceptions() - return retval - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - try: - self.get_loop().run_until_complete( - self._call_in_runner_task(test_func, **kwargs) - ) - except Exception as exc: - self._exceptions.append(exc) - - self._raise_async_exceptions() - - -class AsyncIOBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - @wraps(func) - async def wrapper() -> T_Retval: - task = cast(asyncio.Task, current_task()) - task.set_name(get_callable_name(func)) - _task_states[task] = TaskState(None, None) - - try: - return await func(*args) - finally: - del _task_states[task] - - debug = options.get("debug", None) - loop_factory = options.get("loop_factory", None) - if loop_factory is None and options.get("use_uvloop", False): - if sys.platform != "win32": - import uvloop - - loop_factory = uvloop.new_event_loop - else: - import winloop - - loop_factory = winloop.new_event_loop - - with Runner(debug=debug, loop_factory=loop_factory) as runner: - return runner.run(wrapper()) - - @classmethod - def current_token(cls) -> object: - return get_running_loop() - - @classmethod - def current_time(cls) -> float: - return get_running_loop().time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return CancelledError - - @classmethod - async def checkpoint(cls) -> None: - await sleep(0) - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - task = current_task() - if task is None: - return - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return - - while cancel_scope: - if cancel_scope.cancel_called: - await sleep(0) - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - with CancelScope(shield=True): - await sleep(0) - - @classmethod - async def sleep(cls, delay: float) -> None: - await sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - if (task := current_task()) is None: - return math.inf - - try: - cancel_scope = _task_states[task].cancel_scope - except KeyError: - return math.inf - - deadline = math.inf - while cancel_scope: - deadline = min(deadline, cancel_scope.deadline) - if cancel_scope._cancel_called: - deadline = -math.inf - break - elif cancel_scope.shield: - break - else: - cancel_scope = cancel_scope._parent_scope - - return deadline - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> abc.Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> abc.CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( # type: ignore[return] - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - await cls.checkpoint() - - # If this is the first run in this event loop thread, set up the necessary - # variables - try: - idle_workers = _threadpool_idle_workers.get() - workers = _threadpool_workers.get() - except LookupError: - idle_workers = deque() - workers = set() - _threadpool_idle_workers.set(idle_workers) - _threadpool_workers.set(workers) - - async with limiter or cls.current_default_thread_limiter(): - with CancelScope(shield=not abandon_on_cancel) as scope: - future = asyncio.Future[T_Retval]() - root_task = find_root_task() - if not idle_workers: - worker = WorkerThread(root_task, workers, idle_workers) - worker.start() - workers.add(worker) - root_task.add_done_callback( - worker.stop, context=contextvars.Context() - ) - else: - worker = idle_workers.pop() - - # Prune any other workers that have been idle for MAX_IDLE_TIME - # seconds or longer - now = cls.current_time() - while idle_workers: - if ( - now - idle_workers[0].idle_since - < WorkerThread.MAX_IDLE_TIME - ): - break - - expired_worker = idle_workers.popleft() - expired_worker.root_task.remove_done_callback( - expired_worker.stop - ) - expired_worker.stop() - - context = copy_context() - context.run(set_current_async_library, None) - if abandon_on_cancel or scope._parent_scope is None: - worker_scope = scope - else: - worker_scope = scope._parent_scope - - worker.queue.put_nowait((context, func, args, future, worker_scope)) - return await future - - @classmethod - def check_cancelled(cls) -> None: - scope: CancelScope | None = threadlocals.current_cancel_scope - while scope is not None: - if scope.cancel_called: - raise CancelledError(f"Cancelled by cancel scope {id(scope):x}") - - if scope.shield: - return - - scope = scope._parent_scope - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - async def task_wrapper() -> T_Retval: - __tracebackhide__ = True - if scope is not None: - task = cast(asyncio.Task, current_task()) - _task_states[task] = TaskState(None, scope) - scope._tasks.add(task) - try: - return await func(*args) - except CancelledError as exc: - raise concurrent.futures.CancelledError(str(exc)) from None - finally: - if scope is not None: - scope._tasks.discard(task) - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - context = copy_context() - context.run(set_current_async_library, "asyncio") - scope = getattr(threadlocals, "current_cancel_scope", None) - f: concurrent.futures.Future[T_Retval] = context.run( - asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop - ) - return f.result() - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - @wraps(func) - def wrapper() -> None: - try: - set_current_async_library("asyncio") - f.set_result(func(*args)) - except BaseException as exc: - f.set_exception(exc) - if not isinstance(exc, Exception): - raise - - loop = cast( - "AbstractEventLoop", token or threadlocals.current_token.native_token - ) - if loop.is_closed(): - raise RunFinishedError - - f: concurrent.futures.Future[T_Retval] = Future() - loop.call_soon_threadsafe(wrapper) - return f.result() - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - await cls.checkpoint() - if isinstance(command, PathLike): - command = os.fspath(command) - - if isinstance(command, (str, bytes)): - process = await asyncio.create_subprocess_shell( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - else: - process = await asyncio.create_subprocess_exec( - *command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - **kwargs, - ) - - stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None - stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None - stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - create_task( - _shutdown_process_pool_on_exit(workers), - name="AnyIO process pool shutdown task", - ) - find_root_task().add_done_callback( - partial(_forcibly_shutdown_process_pool_on_exit, workers) # type:ignore[arg-type] - ) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> abc.SocketStream: - transport, protocol = cast( - tuple[asyncio.Transport, StreamProtocol], - await get_running_loop().create_connection( - StreamProtocol, host, port, local_addr=local_address - ), - ) - transport.pause_reading() - return SocketStream(transport, protocol) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - await cls.checkpoint() - loop = get_running_loop() - raw_socket = socket.socket(socket.AF_UNIX) - raw_socket.setblocking(False) - while True: - try: - raw_socket.connect(path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return UNIXSocketStream(raw_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, - local_addr=local_address, - remote_addr=remote_address, - family=family, - reuse_port=reuse_port, - ) - if protocol.exception: - transport.close() - raise protocol.exception - - if not remote_address: - return UDPSocket(transport, protocol) - else: - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def create_unix_datagram_socket( # type: ignore[override] - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - await cls.checkpoint() - loop = get_running_loop() - - if remote_path: - while True: - try: - raw_socket.connect(remote_path) - except BlockingIOError: - f: asyncio.Future = asyncio.Future() - loop.add_writer(raw_socket, f.set_result, None) - f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) - await f - except BaseException: - raw_socket.close() - raise - else: - return ConnectedUNIXDatagramSocket(raw_socket) - else: - return UNIXDatagramSocket(raw_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await get_running_loop().getaddrinfo( - host, port, family=family, type=type, proto=proto, flags=flags - ) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await get_running_loop().getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - read_events = _read_events.get() - except LookupError: - read_events = {} - _read_events.set(read_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if read_events.get(fd): - raise BusyResourceError("reading from") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_reader(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_reader(fd, cb) - remove_reader = selector.remove_reader - else: - remove_reader = loop.remove_reader - - read_events[fd] = fut - try: - success = await fut - finally: - try: - del read_events[fd] - except KeyError: - pass - else: - remove_reader(fd) - - if not success: - raise ClosedResourceError - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - write_events = _write_events.get() - except LookupError: - write_events = {} - _write_events.set(write_events) - - fd = obj if isinstance(obj, int) else obj.fileno() - if write_events.get(fd): - raise BusyResourceError("writing to") - - loop = get_running_loop() - fut: asyncio.Future[bool] = loop.create_future() - - def cb() -> None: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - try: - fut.set_result(True) - except asyncio.InvalidStateError: - pass - - try: - loop.add_writer(fd, cb) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - selector = get_selector() - selector.add_writer(fd, cb) - remove_writer = selector.remove_writer - else: - remove_writer = loop.remove_writer - - write_events[fd] = fut - try: - success = await fut - finally: - try: - del write_events[fd] - except KeyError: - pass - else: - remove_writer(fd) - - if not success: - raise ClosedResourceError - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - fd = obj if isinstance(obj, int) else obj.fileno() - loop = get_running_loop() - - try: - write_events = _write_events.get() - except LookupError: - pass - else: - try: - fut = write_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_writer(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_writer(fd) - - try: - read_events = _read_events.get() - except LookupError: - pass - else: - try: - fut = read_events.pop(fd) - except KeyError: - pass - else: - try: - fut.set_result(False) - except asyncio.InvalidStateError: - pass - - try: - loop.remove_reader(fd) - except NotImplementedError: - from anyio._core._asyncio_selector_thread import get_selector - - get_selector().remove_reader(fd) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener: - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - transport, protocol = await get_running_loop().create_connection( - StreamProtocol, sock=sock - ) - return SocketStream(transport, protocol) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - return UNIXSocketStream(sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return UDPSocket(transport, protocol) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - transport, protocol = await get_running_loop().create_datagram_endpoint( - DatagramProtocol, sock=sock - ) - return ConnectedUDPSocket(transport, protocol) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - return UNIXDatagramSocket(sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - return ConnectedUNIXDatagramSocket(sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _default_thread_limiter.get() - except LookupError: - limiter = CapacityLimiter(40) - _default_thread_limiter.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - return AsyncIOTaskInfo(current_task()) # type: ignore[arg-type] - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()] - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - await cls.checkpoint() - this_task = current_task() - while True: - for task in all_tasks(): - if task is this_task: - continue - - waiter = task._fut_waiter # type: ignore[attr-defined] - if waiter is None or waiter.done(): - await sleep(0.1) - break - else: - return - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = AsyncIOBackend diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_trio.py b/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_trio.py deleted file mode 100644 index f460a7f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_backends/_trio.py +++ /dev/null @@ -1,1346 +0,0 @@ -from __future__ import annotations - -import array -import math -import os -import socket -import sys -import types -import weakref -from collections.abc import ( - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Collection, - Coroutine, - Iterable, - Sequence, -) -from contextlib import AbstractContextManager -from dataclasses import dataclass -from io import IOBase -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind -from types import TracebackType -from typing import ( - IO, - TYPE_CHECKING, - Any, - Generic, - NoReturn, - TypeVar, - cast, - overload, -) - -import trio.from_thread -import trio.lowlevel -from outcome import Error, Outcome, Value -from trio.lowlevel import ( - current_root_task, - current_task, - notify_closing, - wait_readable, - wait_writable, -) -from trio.socket import SocketType as TrioSocketType -from trio.to_thread import run_sync - -from .. import ( - CapacityLimiterStatistics, - EventStatistics, - LockStatistics, - RunFinishedError, - TaskInfo, - WouldBlock, - abc, -) -from .._core._eventloop import claim_worker_thread -from .._core._exceptions import ( - BrokenResourceError, - BusyResourceError, - ClosedResourceError, - EndOfStream, -) -from .._core._sockets import convert_ipv6_sockaddr -from .._core._streams import create_memory_object_stream -from .._core._synchronization import ( - CapacityLimiter as BaseCapacityLimiter, -) -from .._core._synchronization import Event as BaseEvent -from .._core._synchronization import Lock as BaseLock -from .._core._synchronization import ( - ResourceGuard, - SemaphoreStatistics, -) -from .._core._synchronization import Semaphore as BaseSemaphore -from .._core._tasks import CancelScope as BaseCancelScope -from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType -from ..abc._eventloop import AsyncBackend, StrOrBytesPath -from ..streams.memory import MemoryObjectSendStream - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -if sys.version_info >= (3, 10): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from exceptiongroup import BaseExceptionGroup - from typing_extensions import TypeVarTuple, Unpack - -T = TypeVar("T") -T_Retval = TypeVar("T_Retval") -T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) -PosArgsT = TypeVarTuple("PosArgsT") -P = ParamSpec("P") - - -# -# Event loop -# - -RunVar = trio.lowlevel.RunVar - - -# -# Timeouts and cancellation -# - - -class CancelScope(BaseCancelScope): - def __new__( - cls, original: trio.CancelScope | None = None, **kwargs: object - ) -> CancelScope: - return object.__new__(cls) - - def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None: - self.__original = original or trio.CancelScope(**kwargs) - - def __enter__(self) -> CancelScope: - self.__original.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - return self.__original.__exit__(exc_type, exc_val, exc_tb) - - def cancel(self, reason: str | None = None) -> None: - self.__original.cancel(reason) - - @property - def deadline(self) -> float: - return self.__original.deadline - - @deadline.setter - def deadline(self, value: float) -> None: - self.__original.deadline = value - - @property - def cancel_called(self) -> bool: - return self.__original.cancel_called - - @property - def cancelled_caught(self) -> bool: - return self.__original.cancelled_caught - - @property - def shield(self) -> bool: - return self.__original.shield - - @shield.setter - def shield(self, value: bool) -> None: - self.__original.shield = value - - -# -# Task groups -# - - -class TaskGroup(abc.TaskGroup): - def __init__(self) -> None: - self._active = False - self._nursery_manager = trio.open_nursery(strict_exception_groups=True) - self.cancel_scope = None # type: ignore[assignment] - - async def __aenter__(self) -> TaskGroup: - self._active = True - self._nursery = await self._nursery_manager.__aenter__() - self.cancel_scope = CancelScope(self._nursery.cancel_scope) - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - try: - # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type - return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value] - except BaseExceptionGroup as exc: - if not exc.split(trio.Cancelled)[1]: - raise trio.Cancelled._create() from exc - - raise - finally: - del exc_val, exc_tb - self._active = False - - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - self._nursery.start_soon(func, *args, name=name) - - async def start( - self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None - ) -> Any: - if not self._active: - raise RuntimeError( - "This task group is not active; no new tasks can be started." - ) - - return await self._nursery.start(func, *args, name=name) - - -# -# Subprocesses -# - - -@dataclass(eq=False) -class ReceiveStreamWrapper(abc.ByteReceiveStream): - _stream: trio.abc.ReceiveStream - - async def receive(self, max_bytes: int | None = None) -> bytes: - try: - data = await self._stream.receive_some(max_bytes) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - if data: - return bytes(data) - else: - raise EndOfStream - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class SendStreamWrapper(abc.ByteSendStream): - _stream: trio.abc.SendStream - - async def send(self, item: bytes) -> None: - try: - await self._stream.send_all(item) - except trio.ClosedResourceError as exc: - raise ClosedResourceError from exc.__cause__ - except trio.BrokenResourceError as exc: - raise BrokenResourceError from exc.__cause__ - - async def aclose(self) -> None: - await self._stream.aclose() - - -@dataclass(eq=False) -class Process(abc.Process): - _process: trio.Process - _stdin: abc.ByteSendStream | None - _stdout: abc.ByteReceiveStream | None - _stderr: abc.ByteReceiveStream | None - - async def aclose(self) -> None: - with CancelScope(shield=True): - if self._stdin: - await self._stdin.aclose() - if self._stdout: - await self._stdout.aclose() - if self._stderr: - await self._stderr.aclose() - - try: - await self.wait() - except BaseException: - self.kill() - with CancelScope(shield=True): - await self.wait() - raise - - async def wait(self) -> int: - return await self._process.wait() - - def terminate(self) -> None: - self._process.terminate() - - def kill(self) -> None: - self._process.kill() - - def send_signal(self, signal: Signals) -> None: - self._process.send_signal(signal) - - @property - def pid(self) -> int: - return self._process.pid - - @property - def returncode(self) -> int | None: - return self._process.returncode - - @property - def stdin(self) -> abc.ByteSendStream | None: - return self._stdin - - @property - def stdout(self) -> abc.ByteReceiveStream | None: - return self._stdout - - @property - def stderr(self) -> abc.ByteReceiveStream | None: - return self._stderr - - -class _ProcessPoolShutdownInstrument(trio.abc.Instrument): - def after_run(self) -> None: - super().after_run() - - -current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar( - "current_default_worker_process_limiter" -) - - -async def _shutdown_process_pool(workers: set[abc.Process]) -> None: - try: - await trio.sleep(math.inf) - except trio.Cancelled: - for process in workers: - if process.returncode is None: - process.kill() - - with CancelScope(shield=True): - for process in workers: - await process.aclose() - - -# -# Sockets and networking -# - - -class _TrioSocketMixin(Generic[T_SockAddr]): - def __init__(self, trio_socket: TrioSocketType) -> None: - self._trio_socket = trio_socket - self._closed = False - - def _check_closed(self) -> None: - if self._closed: - raise ClosedResourceError - if self._trio_socket.fileno() < 0: - raise BrokenResourceError - - @property - def _raw_socket(self) -> socket.socket: - return self._trio_socket._sock # type: ignore[attr-defined] - - async def aclose(self) -> None: - if self._trio_socket.fileno() >= 0: - self._closed = True - self._trio_socket.close() - - def _convert_socket_error(self, exc: BaseException) -> NoReturn: - if isinstance(exc, trio.ClosedResourceError): - raise ClosedResourceError from exc - elif self._trio_socket.fileno() < 0 and self._closed: - raise ClosedResourceError from None - elif isinstance(exc, OSError): - raise BrokenResourceError from exc - else: - raise exc - - -class SocketStream(_TrioSocketMixin, abc.SocketStream): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self, max_bytes: int = 65536) -> bytes: - with self._receive_guard: - try: - data = await self._trio_socket.recv(max_bytes) - except BaseException as exc: - self._convert_socket_error(exc) - - if data: - return data - else: - raise EndOfStream - - async def send(self, item: bytes) -> None: - with self._send_guard: - view = memoryview(item) - while view: - try: - bytes_sent = await self._trio_socket.send(view) - except BaseException as exc: - self._convert_socket_error(exc) - - view = view[bytes_sent:] - - async def send_eof(self) -> None: - self._trio_socket.shutdown(socket.SHUT_WR) - - -class UNIXSocketStream(SocketStream, abc.UNIXSocketStream): - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - if not isinstance(msglen, int) or msglen < 0: - raise ValueError("msglen must be a non-negative integer") - if not isinstance(maxfds, int) or maxfds < 1: - raise ValueError("maxfds must be a positive integer") - - fds = array.array("i") - await trio.lowlevel.checkpoint() - with self._receive_guard: - while True: - try: - message, ancdata, flags, addr = await self._trio_socket.recvmsg( - msglen, socket.CMSG_LEN(maxfds * fds.itemsize) - ) - except BaseException as exc: - self._convert_socket_error(exc) - else: - if not message and not ancdata: - raise EndOfStream - - break - - for cmsg_level, cmsg_type, cmsg_data in ancdata: - if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: - raise RuntimeError( - f"Received unexpected ancillary data; message = {message!r}, " - f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" - ) - - fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) - - return message, list(fds) - - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - if not message: - raise ValueError("message must not be empty") - if not fds: - raise ValueError("fds must not be empty") - - filenos: list[int] = [] - for fd in fds: - if isinstance(fd, int): - filenos.append(fd) - elif isinstance(fd, IOBase): - filenos.append(fd.fileno()) - - fdarray = array.array("i", filenos) - await trio.lowlevel.checkpoint() - with self._send_guard: - while True: - try: - await self._trio_socket.sendmsg( - [message], - [ - ( - socket.SOL_SOCKET, - socket.SCM_RIGHTS, - fdarray, - ) - ], - ) - break - except BaseException as exc: - self._convert_socket_error(exc) - - -class TCPSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> SocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return SocketStream(trio_socket) - - -class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener): - def __init__(self, raw_socket: socket.socket): - super().__init__(trio.socket.from_stdlib_socket(raw_socket)) - self._accept_guard = ResourceGuard("accepting connections from") - - async def accept(self) -> UNIXSocketStream: - with self._accept_guard: - try: - trio_socket, _addr = await self._trio_socket.accept() - except BaseException as exc: - self._convert_socket_error(exc) - - return UNIXSocketStream(trio_socket) - - -class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> tuple[bytes, IPSockAddrType]: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, convert_ipv6_sockaddr(addr) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UDPPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> UNIXDatagramPacketType: - with self._receive_guard: - try: - data, addr = await self._trio_socket.recvfrom(65536) - return data, addr - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: UNIXDatagramPacketType) -> None: - with self._send_guard: - try: - await self._trio_socket.sendto(*item) - except BaseException as exc: - self._convert_socket_error(exc) - - -class ConnectedUNIXDatagramSocket( - _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket -): - def __init__(self, trio_socket: TrioSocketType) -> None: - super().__init__(trio_socket) - self._receive_guard = ResourceGuard("reading from") - self._send_guard = ResourceGuard("writing to") - - async def receive(self) -> bytes: - with self._receive_guard: - try: - return await self._trio_socket.recv(65536) - except BaseException as exc: - self._convert_socket_error(exc) - - async def send(self, item: bytes) -> None: - with self._send_guard: - try: - await self._trio_socket.send(item) - except BaseException as exc: - self._convert_socket_error(exc) - - -# -# Synchronization -# - - -class Event(BaseEvent): - def __new__(cls) -> Event: - return object.__new__(cls) - - def __init__(self) -> None: - self.__original = trio.Event() - - def is_set(self) -> bool: - return self.__original.is_set() - - async def wait(self) -> None: - return await self.__original.wait() - - def statistics(self) -> EventStatistics: - orig_statistics = self.__original.statistics() - return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting) - - def set(self) -> None: - self.__original.set() - - -class Lock(BaseLock): - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False) -> None: - self._fast_acquire = fast_acquire - self.__original = trio.Lock() - - @staticmethod - def _convert_runtime_error_msg(exc: RuntimeError) -> None: - if exc.args == ("attempt to re-acquire an already held Lock",): - exc.args = ("Attempted to acquire an already held Lock",) - - async def acquire(self) -> None: - if not self._fast_acquire: - try: - await self.__original.acquire() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - except RuntimeError as exc: - self._convert_runtime_error_msg(exc) - raise - - def locked(self) -> bool: - return self.__original.locked() - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> LockStatistics: - orig_statistics = self.__original.statistics() - owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None - return LockStatistics( - orig_statistics.locked, owner, orig_statistics.tasks_waiting - ) - - -class Semaphore(BaseSemaphore): - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self.__original = trio.Semaphore(initial_value, max_value=max_value) - - async def acquire(self) -> None: - if not self._fast_acquire: - await self.__original.acquire() - return - - # This is the "fast path" where we don't let other tasks run - await trio.lowlevel.checkpoint_if_cancelled() - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - await self.__original._lot.park() - - def acquire_nowait(self) -> None: - try: - self.__original.acquire_nowait() - except trio.WouldBlock: - raise WouldBlock from None - - @property - def max_value(self) -> int | None: - return self.__original.max_value - - @property - def value(self) -> int: - return self.__original.value - - def release(self) -> None: - self.__original.release() - - def statistics(self) -> SemaphoreStatistics: - orig_statistics = self.__original.statistics() - return SemaphoreStatistics(orig_statistics.tasks_waiting) - - -class CapacityLimiter(BaseCapacityLimiter): - def __new__( - cls, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> CapacityLimiter: - return object.__new__(cls) - - def __init__( - self, - total_tokens: float | None = None, - *, - original: trio.CapacityLimiter | None = None, - ) -> None: - if original is not None: - self.__original = original - else: - assert total_tokens is not None - self.__original = trio.CapacityLimiter(total_tokens) - - async def __aenter__(self) -> None: - return await self.__original.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.__original.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - return self.__original.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - self.__original.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - return self.__original.borrowed_tokens - - @property - def available_tokens(self) -> float: - return self.__original.available_tokens - - def acquire_nowait(self) -> None: - self.__original.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self.__original.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self.__original.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self.__original.acquire_on_behalf_of(borrower) - - def release(self) -> None: - return self.__original.release() - - def release_on_behalf_of(self, borrower: object) -> None: - return self.__original.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - orig = self.__original.statistics() - return CapacityLimiterStatistics( - borrowed_tokens=orig.borrowed_tokens, - total_tokens=orig.total_tokens, - borrowers=tuple(orig.borrowers), - tasks_waiting=orig.tasks_waiting, - ) - - -_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper") - - -# -# Signal handling -# - - -class _SignalReceiver: - _iterator: AsyncIterator[int] - - def __init__(self, signals: tuple[Signals, ...]): - self._signals = signals - - def __enter__(self) -> _SignalReceiver: - self._cm = trio.open_signal_receiver(*self._signals) - self._iterator = self._cm.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool | None: - return self._cm.__exit__(exc_type, exc_val, exc_tb) - - def __aiter__(self) -> _SignalReceiver: - return self - - async def __anext__(self) -> Signals: - signum = await self._iterator.__anext__() - return Signals(signum) - - -# -# Testing and debugging -# - - -class TestRunner(abc.TestRunner): - def __init__(self, **options: Any) -> None: - from queue import Queue - - self._call_queue: Queue[Callable[[], object]] = Queue() - self._send_stream: MemoryObjectSendStream | None = None - self._options = options - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> None: - if self._send_stream: - self._send_stream.close() - while self._send_stream is not None: - self._call_queue.get()() - - async def _run_tests_and_fixtures(self) -> None: - self._send_stream, receive_stream = create_memory_object_stream(1) - with receive_stream: - async for coro, outcome_holder in receive_stream: - try: - retval = await coro - except BaseException as exc: - outcome_holder.append(Error(exc)) - else: - outcome_holder.append(Value(retval)) - - def _main_task_finished(self, outcome: object) -> None: - self._send_stream = None - - def _call_in_runner_task( - self, - func: Callable[P, Awaitable[T_Retval]], - *args: P.args, - **kwargs: P.kwargs, - ) -> T_Retval: - if self._send_stream is None: - trio.lowlevel.start_guest_run( - self._run_tests_and_fixtures, - run_sync_soon_threadsafe=self._call_queue.put, - done_callback=self._main_task_finished, - **self._options, - ) - while self._send_stream is None: - self._call_queue.get()() - - outcome_holder: list[Outcome] = [] - self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder)) - while not outcome_holder: - self._call_queue.get()() - - return outcome_holder[0].unwrap() - - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], - kwargs: dict[str, Any], - ) -> Iterable[T_Retval]: - asyncgen = fixture_func(**kwargs) - fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None) - - yield fixturevalue - - try: - self._call_in_runner_task(asyncgen.asend, None) - except StopAsyncIteration: - pass - else: - self._call_in_runner_task(asyncgen.aclose) - raise RuntimeError("Async generator fixture did not stop") - - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], - kwargs: dict[str, Any], - ) -> T_Retval: - return self._call_in_runner_task(fixture_func, **kwargs) - - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - self._call_in_runner_task(test_func, **kwargs) - - -class TrioTaskInfo(TaskInfo): - def __init__(self, task: trio.lowlevel.Task): - parent_id = None - if task.parent_nursery and task.parent_nursery.parent_task: - parent_id = id(task.parent_nursery.parent_task) - - super().__init__(id(task), parent_id, task.name, task.coro) - self._task = weakref.proxy(task) - - def has_pending_cancellation(self) -> bool: - try: - return self._task._cancel_status.effectively_cancelled - except ReferenceError: - # If the task is no longer around, it surely doesn't have a cancellation - # pending - return False - - -class TrioBackend(AsyncBackend): - @classmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - return trio.run(func, *args) - - @classmethod - def current_token(cls) -> object: - return trio.lowlevel.current_trio_token() - - @classmethod - def current_time(cls) -> float: - return trio.current_time() - - @classmethod - def cancelled_exception_class(cls) -> type[BaseException]: - return trio.Cancelled - - @classmethod - async def checkpoint(cls) -> None: - await trio.lowlevel.checkpoint() - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - await trio.lowlevel.checkpoint_if_cancelled() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - await trio.lowlevel.cancel_shielded_checkpoint() - - @classmethod - async def sleep(cls, delay: float) -> None: - await trio.sleep(delay) - - @classmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> abc.CancelScope: - return CancelScope(deadline=deadline, shield=shield) - - @classmethod - def current_effective_deadline(cls) -> float: - return trio.current_effective_deadline() - - @classmethod - def create_task_group(cls) -> abc.TaskGroup: - return TaskGroup() - - @classmethod - def create_event(cls) -> abc.Event: - return Event() - - @classmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - return Lock(fast_acquire=fast_acquire) - - @classmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> abc.Semaphore: - return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) - - @classmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - return CapacityLimiter(total_tokens) - - @classmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: abc.CapacityLimiter | None = None, - ) -> T_Retval: - def wrapper() -> T_Retval: - with claim_worker_thread(TrioBackend, token): - return func(*args) - - token = TrioBackend.current_token() - return await run_sync( - wrapper, - abandon_on_cancel=abandon_on_cancel, - limiter=cast(trio.CapacityLimiter, limiter), - ) - - @classmethod - def check_cancelled(cls) -> None: - trio.from_thread.check_cancelled() - - @classmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - trio_token = cast("trio.lowlevel.TrioToken | None", token) - try: - return trio.from_thread.run_sync(func, *args, trio_token=trio_token) - except trio.RunFinishedError: - raise RunFinishedError from None - - @classmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - def convert_item(item: StrOrBytesPath) -> str: - str_or_bytes = os.fspath(item) - if isinstance(str_or_bytes, str): - return str_or_bytes - else: - return os.fsdecode(str_or_bytes) - - if isinstance(command, (str, bytes, PathLike)): - process = await trio.lowlevel.open_process( - convert_item(command), - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=True, - **kwargs, - ) - else: - process = await trio.lowlevel.open_process( - [convert_item(item) for item in command], - stdin=stdin, - stdout=stdout, - stderr=stderr, - shell=False, - **kwargs, - ) - - stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None - stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None - stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None - return Process(process, stdin_stream, stdout_stream, stderr_stream) - - @classmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: - trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers) - - @classmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - family = socket.AF_INET6 if ":" in host else socket.AF_INET - trio_socket = trio.socket.socket(family) - trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - if local_address: - await trio_socket.bind(local_address) - - try: - await trio_socket.connect((host, port)) - except BaseException: - trio_socket.close() - raise - - return SocketStream(trio_socket) - - @classmethod - async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: - trio_socket = trio.socket.socket(socket.AF_UNIX) - try: - await trio_socket.connect(path) - except BaseException: - trio_socket.close() - raise - - return UNIXSocketStream(trio_socket) - - @classmethod - def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener: - return TCPSocketListener(sock) - - @classmethod - def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener: - return UNIXSocketListener(sock) - - @classmethod - async def create_udp_socket( - cls, - family: socket.AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM) - - if reuse_port: - trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - if local_address: - await trio_socket.bind(local_address) - - if remote_address: - await trio_socket.connect(remote_address) - return ConnectedUDPSocket(trio_socket) - else: - return UDPSocket(trio_socket) - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: None - ) -> abc.UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes - ) -> abc.ConnectedUNIXDatagramSocket: ... - - @classmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket.socket, remote_path: str | bytes | None - ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: - trio_socket = trio.socket.from_stdlib_socket(raw_socket) - - if remote_path: - await trio_socket.connect(remote_path) - return ConnectedUNIXDatagramSocket(trio_socket) - else: - return UNIXDatagramSocket(trio_socket) - - @classmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - return await trio.socket.getaddrinfo(host, port, family, type, proto, flags) - - @classmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - return await trio.socket.getnameinfo(sockaddr, flags) - - @classmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_readable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("reading from") from None - - @classmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - try: - await wait_writable(obj) - except trio.ClosedResourceError as exc: - raise ClosedResourceError().with_traceback(exc.__traceback__) from None - except trio.BusyResourceError: - raise BusyResourceError("writing to") from None - - @classmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - notify_closing(obj) - - @classmethod - async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener: - return TCPSocketListener(sock) - - @classmethod - async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return SocketStream(trio_sock) - - @classmethod - async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXSocketStream(trio_sock) - - @classmethod - async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UDPSocket(trio_sock) - - @classmethod - async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUDPSocket(trio_sock) - - @classmethod - async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return UNIXDatagramSocket(trio_sock) - - @classmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket.socket - ) -> ConnectedUNIXDatagramSocket: - trio_sock = trio.socket.from_stdlib_socket(sock) - return ConnectedUNIXDatagramSocket(trio_sock) - - @classmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - try: - return _capacity_limiter_wrapper.get() - except LookupError: - limiter = CapacityLimiter( - original=trio.to_thread.current_default_thread_limiter() - ) - _capacity_limiter_wrapper.set(limiter) - return limiter - - @classmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - return _SignalReceiver(signals) - - @classmethod - def get_current_task(cls) -> TaskInfo: - task = current_task() - return TrioTaskInfo(task) - - @classmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - root_task = current_root_task() - assert root_task - task_infos = [TrioTaskInfo(root_task)] - nurseries = root_task.child_nurseries - while nurseries: - new_nurseries: list[trio.Nursery] = [] - for nursery in nurseries: - for task in nursery.child_tasks: - task_infos.append(TrioTaskInfo(task)) - new_nurseries.extend(task.child_nurseries) - - nurseries = new_nurseries - - return task_infos - - @classmethod - async def wait_all_tasks_blocked(cls) -> None: - from trio.testing import wait_all_tasks_blocked - - await wait_all_tasks_blocked() - - @classmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - return TestRunner(**options) - - -backend_class = TrioBackend diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/__init__.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.py deleted file mode 100644 index 9f35bae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.py +++ /dev/null @@ -1,167 +0,0 @@ -from __future__ import annotations - -import asyncio -import socket -import threading -from collections.abc import Callable -from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector -from typing import TYPE_CHECKING, Any - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - -_selector_lock = threading.Lock() -_selector: Selector | None = None - - -class Selector: - def __init__(self) -> None: - self._thread = threading.Thread(target=self.run, name="AnyIO socket selector") - self._selector = DefaultSelector() - self._send, self._receive = socket.socketpair() - self._send.setblocking(False) - self._receive.setblocking(False) - # This somewhat reduces the amount of memory wasted queueing up data - # for wakeups. With these settings, maximum number of 1-byte sends - # before getting BlockingIOError: - # Linux 4.8: 6 - # macOS (darwin 15.5): 1 - # Windows 10: 525347 - # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send - # blocking, even on non-blocking sockets, so don't do that.) - self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1) - self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) - # On Windows this is a TCP socket so this might matter. On other - # platforms this fails b/c AF_UNIX sockets aren't actually TCP. - try: - self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except OSError: - pass - - self._selector.register(self._receive, EVENT_READ) - self._closed = False - - def start(self) -> None: - self._thread.start() - threading._register_atexit(self._stop) # type: ignore[attr-defined] - - def _stop(self) -> None: - global _selector - self._closed = True - self._notify_self() - self._send.close() - self._thread.join() - self._selector.unregister(self._receive) - self._receive.close() - self._selector.close() - _selector = None - assert not self._selector.get_map(), ( - "selector still has registered file descriptors after shutdown" - ) - - def _notify_self(self) -> None: - try: - self._send.send(b"\x00") - except BlockingIOError: - pass - - def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)}) - else: - if EVENT_READ in key.data: - raise ValueError( - "this file descriptor is already registered for reading" - ) - - key.data[EVENT_READ] = loop, callback - self._selector.modify(fd, key.events | EVENT_READ, key.data) - - self._notify_self() - - def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: - loop = asyncio.get_running_loop() - try: - key = self._selector.get_key(fd) - except KeyError: - self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)}) - else: - if EVENT_WRITE in key.data: - raise ValueError( - "this file descriptor is already registered for writing" - ) - - key.data[EVENT_WRITE] = loop, callback - self._selector.modify(fd, key.events | EVENT_WRITE, key.data) - - self._notify_self() - - def remove_reader(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_READ: - del key.data[EVENT_READ] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def remove_writer(self, fd: FileDescriptorLike) -> bool: - try: - key = self._selector.get_key(fd) - except KeyError: - return False - - if new_events := key.events ^ EVENT_WRITE: - del key.data[EVENT_WRITE] - self._selector.modify(fd, new_events, key.data) - else: - self._selector.unregister(fd) - - return True - - def run(self) -> None: - while not self._closed: - for key, events in self._selector.select(): - if key.fileobj is self._receive: - try: - while self._receive.recv(4096): - pass - except BlockingIOError: - pass - - continue - - if events & EVENT_READ: - loop, callback = key.data[EVENT_READ] - self.remove_reader(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - if events & EVENT_WRITE: - loop, callback = key.data[EVENT_WRITE] - self.remove_writer(key.fd) - try: - loop.call_soon_threadsafe(callback) - except RuntimeError: - pass # the loop was already closed - - -def get_selector() -> Selector: - global _selector - - with _selector_lock: - if _selector is None: - _selector = Selector() - _selector.start() - - return _selector diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_contextmanagers.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_contextmanagers.py deleted file mode 100644 index 302f32b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_contextmanagers.py +++ /dev/null @@ -1,200 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from contextlib import AbstractAsyncContextManager, AbstractContextManager -from inspect import isasyncgen, iscoroutine, isgenerator -from types import TracebackType -from typing import Protocol, TypeVar, cast, final - -_T_co = TypeVar("_T_co", covariant=True) -_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None") - - -class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]): - def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ... - - -class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]): - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ... - - -class ContextManagerMixin: - """ - Mixin class providing context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via :meth:`__contextmanager__` - which should return a generator. The mechanics are meant to mirror those of - :func:`@contextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractContextManager[object, bool | None] | None = None - - @final - def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__contextmanager__() - if not isinstance(cm, AbstractContextManager): - if isgenerator(cm): - raise TypeError( - "__contextmanager__() returned a generator object instead of " - "a context manager. Did you forget to add the @contextmanager " - "decorator?" - ) - - raise TypeError( - f"__contextmanager__() did not return a context manager object, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__contextmanager__() returned " - f"self. Did you forget to add the @contextmanager decorator and a " - f"'yield' statement?" - ) - - value = cm.__enter__() - self.__cm = cm - return value - - @final - def __exit__( - self: _SupportsCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, ContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __contextmanager__(self) -> AbstractContextManager[object, bool | None]: - """ - Implement your context manager logic here. - - This method **must** be decorated with - :func:`@contextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: a context manager object - """ - - -class AsyncContextManagerMixin: - """ - Mixin class providing async context manager functionality via a generator-based - implementation. - - This class allows you to implement a context manager via - :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of - :func:`@asynccontextmanager `. - - .. note:: Classes using this mix-in are not reentrant as context managers, meaning - that once you enter it, you can't re-enter before first exiting it. - - .. seealso:: :doc:`contextmanagers` - """ - - __cm: AbstractAsyncContextManager[object, bool | None] | None = None - - @final - async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co: - # Needed for mypy to assume self still has the __cm member - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is not None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has already been entered" - ) - - cm = self.__asynccontextmanager__() - if not isinstance(cm, AbstractAsyncContextManager): - if isasyncgen(cm): - raise TypeError( - "__asynccontextmanager__() returned an async generator instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator?" - ) - elif iscoroutine(cm): - cm.close() - raise TypeError( - "__asynccontextmanager__() returned a coroutine object instead of " - "an async context manager. Did you forget to add the " - "@asynccontextmanager decorator and a 'yield' statement?" - ) - - raise TypeError( - f"__asynccontextmanager__() did not return an async context manager, " - f"but {cm.__class__!r}" - ) - - if cm is self: - raise TypeError( - f"{self.__class__.__qualname__}.__asynccontextmanager__() returned " - f"self. Did you forget to add the @asynccontextmanager decorator and a " - f"'yield' statement?" - ) - - value = await cm.__aenter__() - self.__cm = cm - return value - - @final - async def __aexit__( - self: _SupportsAsyncCtxMgr[object, _ExitT_co], - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> _ExitT_co: - assert isinstance(self, AsyncContextManagerMixin) - if self.__cm is None: - raise RuntimeError( - f"this {self.__class__.__qualname__} has not been entered yet" - ) - - # Prevent circular references - cm = self.__cm - del self.__cm - - return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb)) - - @abstractmethod - def __asynccontextmanager__( - self, - ) -> AbstractAsyncContextManager[object, bool | None]: - """ - Implement your async context manager logic here. - - This method **must** be decorated with - :func:`@asynccontextmanager `. - - .. note:: Remember that the ``yield`` will raise any exception raised in the - enclosed context block, so use a ``finally:`` block to clean up resources! - - :return: an async context manager object - """ diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_eventloop.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_eventloop.py deleted file mode 100644 index 59a69cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_eventloop.py +++ /dev/null @@ -1,234 +0,0 @@ -from __future__ import annotations - -import math -import sys -import threading -from collections.abc import Awaitable, Callable, Generator -from contextlib import contextmanager -from contextvars import Token -from importlib import import_module -from typing import TYPE_CHECKING, Any, TypeVar - -from ._exceptions import NoEventLoopError - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -sniffio: Any -try: - import sniffio -except ModuleNotFoundError: - sniffio = None - -if TYPE_CHECKING: - from ..abc import AsyncBackend - -# This must be updated when new backends are introduced -BACKENDS = "asyncio", "trio" - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -threadlocals = threading.local() -loaded_backends: dict[str, type[AsyncBackend]] = {} - - -def run( - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, -) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param backend: name of the asynchronous event loop implementation – currently - either ``asyncio`` or ``trio`` - :param backend_options: keyword arguments to call the backend ``run()`` - implementation with (documented :ref:`here `) - :return: the return value of the coroutine function - :raises RuntimeError: if an asynchronous event loop is already running in this - thread - :raises LookupError: if the named backend is not found - - """ - if asynclib_name := current_async_library(): - raise RuntimeError(f"Already running {asynclib_name} in this thread") - - try: - async_backend = get_async_backend(backend) - except ImportError as exc: - raise LookupError(f"No such backend: {backend}") from exc - - token = None - if asynclib_name is None: - # Since we're in control of the event loop, we can cache the name of the async - # library - token = set_current_async_library(backend) - - try: - backend_options = backend_options or {} - return async_backend.run(func, args, {}, backend_options) - finally: - reset_current_async_library(token) - - -async def sleep(delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - - """ - return await get_async_backend().sleep(delay) - - -async def sleep_forever() -> None: - """ - Pause the current task until it's cancelled. - - This is a shortcut for ``sleep(math.inf)``. - - .. versionadded:: 3.1 - - """ - await sleep(math.inf) - - -async def sleep_until(deadline: float) -> None: - """ - Pause the current task until the given time. - - :param deadline: the absolute time to wake up at (according to the internal - monotonic clock of the event loop) - - .. versionadded:: 3.1 - - """ - now = current_time() - await sleep(max(deadline - now, 0)) - - -def current_time() -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_time() - - -def get_all_backends() -> tuple[str, ...]: - """Return a tuple of the names of all built-in backends.""" - return BACKENDS - - -def get_available_backends() -> tuple[str, ...]: - """ - Test for the availability of built-in backends. - - :return a tuple of the built-in backend names that were successfully imported - - .. versionadded:: 4.12 - - """ - available_backends: list[str] = [] - for backend_name in get_all_backends(): - try: - get_async_backend(backend_name) - except ImportError: - continue - - available_backends.append(backend_name) - - return tuple(available_backends) - - -def get_cancelled_exc_class() -> type[BaseException]: - """ - Return the current async library's cancellation exception class. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().cancelled_exception_class() - - -# -# Private API -# - - -@contextmanager -def claim_worker_thread( - backend_class: type[AsyncBackend], token: object -) -> Generator[Any, None, None]: - from ..lowlevel import EventLoopToken - - threadlocals.current_token = EventLoopToken(backend_class, token) - try: - yield - finally: - del threadlocals.current_token - - -def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]: - if asynclib_name is None: - asynclib_name = current_async_library() - if not asynclib_name: - raise NoEventLoopError( - f"Not currently running on any asynchronous event loop. " - f"Available async backends: {', '.join(get_all_backends())}" - ) - - # We use our own dict instead of sys.modules to get the already imported back-end - # class because the appropriate modules in sys.modules could potentially be only - # partially initialized - try: - return loaded_backends[asynclib_name] - except KeyError: - module = import_module(f"anyio._backends._{asynclib_name}") - loaded_backends[asynclib_name] = module.backend_class - return module.backend_class - - -def current_async_library() -> str | None: - if sniffio is None: - # If sniffio is not installed, we assume we're either running asyncio or nothing - import asyncio - - try: - asyncio.get_running_loop() - return "asyncio" - except RuntimeError: - pass - else: - try: - return sniffio.current_async_library() - except sniffio.AsyncLibraryNotFoundError: - pass - - return None - - -def set_current_async_library(asynclib_name: str | None) -> Token | None: - # no-op if sniffio is not installed - if sniffio is None: - return None - - return sniffio.current_async_library_cvar.set(asynclib_name) - - -def reset_current_async_library(token: Token | None) -> None: - if token is not None: - sniffio.current_async_library_cvar.reset(token) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_exceptions.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_exceptions.py deleted file mode 100644 index 3776bed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_exceptions.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import Generator -from textwrap import dedent -from typing import Any - -if sys.version_info < (3, 11): - from exceptiongroup import BaseExceptionGroup - - -class BrokenResourceError(Exception): - """ - Raised when trying to use a resource that has been rendered unusable due to external - causes (e.g. a send stream whose peer has disconnected). - """ - - -class BrokenWorkerProcess(Exception): - """ - Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or - otherwise misbehaves. - """ - - -class BrokenWorkerInterpreter(Exception): - """ - Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is - raised in the subinterpreter. - """ - - def __init__(self, excinfo: Any): - # This was adapted from concurrent.futures.interpreter.ExecutionFailed - msg = excinfo.formatted - if not msg: - if excinfo.type and excinfo.msg: - msg = f"{excinfo.type.__name__}: {excinfo.msg}" - else: - msg = excinfo.type.__name__ or excinfo.msg - - super().__init__(msg) - self.excinfo = excinfo - - def __str__(self) -> str: - try: - formatted = self.excinfo.errdisplay - except Exception: - return super().__str__() - else: - return dedent( - f""" - {super().__str__()} - - Uncaught in the interpreter: - - {formatted} - """.strip() - ) - - -class BusyResourceError(Exception): - """ - Raised when two tasks are trying to read from or write to the same resource - concurrently. - """ - - def __init__(self, action: str): - super().__init__(f"Another task is already {action} this resource") - - -class ClosedResourceError(Exception): - """Raised when trying to use a resource that has been closed.""" - - -class ConnectionFailed(OSError): - """ - Raised when a connection attempt fails. - - .. note:: This class inherits from :exc:`OSError` for backwards compatibility. - """ - - -def iterate_exceptions( - exception: BaseException, -) -> Generator[BaseException, None, None]: - if isinstance(exception, BaseExceptionGroup): - for exc in exception.exceptions: - yield from iterate_exceptions(exc) - else: - yield exception - - -class DelimiterNotFound(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - maximum number of bytes has been read without the delimiter being found. - """ - - def __init__(self, max_bytes: int) -> None: - super().__init__( - f"The delimiter was not found among the first {max_bytes} bytes" - ) - - -class EndOfStream(Exception): - """ - Raised when trying to read from a stream that has been closed from the other end. - """ - - -class IncompleteRead(Exception): - """ - Raised during - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or - :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the - connection is closed before the requested amount of bytes has been read. - """ - - def __init__(self) -> None: - super().__init__( - "The stream was closed before the read operation could be completed" - ) - - -class TypedAttributeLookupError(LookupError): - """ - Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute - is not found and no default value has been given. - """ - - -class WouldBlock(Exception): - """Raised by ``X_nowait`` functions if ``X()`` would block.""" - - -class NoEventLoopError(RuntimeError): - """ - Raised by several functions that require an event loop to be running in the current - thread when there is no running event loop. - - This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` - if not calling from an AnyIO worker thread, and no ``token`` was passed. - """ - - -class RunFinishedError(RuntimeError): - """ - Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event - loop associated with the explicitly passed token has already finished. - """ - - def __init__(self) -> None: - super().__init__( - "The event loop associated with the given token has already finished" - ) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_fileio.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_fileio.py deleted file mode 100644 index 061f0d7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_fileio.py +++ /dev/null @@ -1,797 +0,0 @@ -from __future__ import annotations - -import os -import pathlib -import sys -from collections.abc import ( - AsyncIterator, - Callable, - Iterable, - Iterator, - Sequence, -) -from dataclasses import dataclass -from functools import partial -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - AnyStr, - ClassVar, - Final, - Generic, - overload, -) - -from .. import to_thread -from ..abc import AsyncResource - -if TYPE_CHECKING: - from types import ModuleType - - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer -else: - ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object - - -class AsyncFile(AsyncResource, Generic[AnyStr]): - """ - An asynchronous file object. - - This class wraps a standard file object and provides async friendly versions of the - following blocking methods (where available on the original file object): - - * read - * read1 - * readline - * readlines - * readinto - * readinto1 - * write - * writelines - * truncate - * seek - * tell - * flush - - All other methods are directly passed through. - - This class supports the asynchronous context manager protocol which closes the - underlying file at the end of the context block. - - This class also supports asynchronous iteration:: - - async with await open_file(...) as f: - async for line in f: - print(line) - """ - - def __init__(self, fp: IO[AnyStr]) -> None: - self._fp: Any = fp - - def __getattr__(self, name: str) -> object: - return getattr(self._fp, name) - - @property - def wrapped(self) -> IO[AnyStr]: - """The wrapped file object.""" - return self._fp - - async def __aiter__(self) -> AsyncIterator[AnyStr]: - while True: - line = await self.readline() - if line: - yield line - else: - break - - async def aclose(self) -> None: - return await to_thread.run_sync(self._fp.close) - - async def read(self, size: int = -1) -> AnyStr: - return await to_thread.run_sync(self._fp.read, size) - - async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes: - return await to_thread.run_sync(self._fp.read1, size) - - async def readline(self) -> AnyStr: - return await to_thread.run_sync(self._fp.readline) - - async def readlines(self) -> list[AnyStr]: - return await to_thread.run_sync(self._fp.readlines) - - async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto, b) - - async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int: - return await to_thread.run_sync(self._fp.readinto1, b) - - @overload - async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ... - - @overload - async def write(self: AsyncFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - return await to_thread.run_sync(self._fp.write, b) - - @overload - async def writelines( - self: AsyncFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - - @overload - async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ... - - async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None: - return await to_thread.run_sync(self._fp.writelines, lines) - - async def truncate(self, size: int | None = None) -> int: - return await to_thread.run_sync(self._fp.truncate, size) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - return await to_thread.run_sync(self._fp.seek, offset, whence) - - async def tell(self) -> int: - return await to_thread.run_sync(self._fp.tell) - - async def flush(self) -> None: - return await to_thread.run_sync(self._fp.flush) - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., -) -> AsyncFile[bytes]: ... - - -@overload -async def open_file( - file: str | PathLike[str] | int, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - closefd: bool = ..., - opener: Callable[[str, int], int] | None = ..., -) -> AsyncFile[str]: ... - - -async def open_file( - file: str | PathLike[str] | int, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - closefd: bool = True, - opener: Callable[[str, int], int] | None = None, -) -> AsyncFile[Any]: - """ - Open a file asynchronously. - - The arguments are exactly the same as for the builtin :func:`open`. - - :return: an asynchronous file object - - """ - fp = await to_thread.run_sync( - open, file, mode, buffering, encoding, errors, newline, closefd, opener - ) - return AsyncFile(fp) - - -def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]: - """ - Wrap an existing file as an asynchronous file. - - :param file: an existing file-like object - :return: an asynchronous file object - - """ - return AsyncFile(file) - - -@dataclass(eq=False) -class _PathIterator(AsyncIterator["Path"]): - iterator: Iterator[PathLike[str]] - - async def __anext__(self) -> Path: - nextval = await to_thread.run_sync( - next, self.iterator, None, abandon_on_cancel=True - ) - if nextval is None: - raise StopAsyncIteration from None - - return Path(nextval) - - -class Path: - """ - An asynchronous version of :class:`pathlib.Path`. - - This class cannot be substituted for :class:`pathlib.Path` or - :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike` - interface. - - It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for - the deprecated :meth:`~pathlib.Path.link_to` method. - - Some methods may be unavailable or have limited functionality, based on the Python - version: - - * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later) - * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later) - * :attr:`~pathlib.Path.info` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later) - * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only - available on Python 3.13 or later) - * :meth:`~pathlib.Path.move` (available on Python 3.14 or later) - * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later) - * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available - on Python 3.12 or later) - * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later) - - Any methods that do disk I/O need to be awaited on. These methods are: - - * :meth:`~pathlib.Path.absolute` - * :meth:`~pathlib.Path.chmod` - * :meth:`~pathlib.Path.cwd` - * :meth:`~pathlib.Path.exists` - * :meth:`~pathlib.Path.expanduser` - * :meth:`~pathlib.Path.group` - * :meth:`~pathlib.Path.hardlink_to` - * :meth:`~pathlib.Path.home` - * :meth:`~pathlib.Path.is_block_device` - * :meth:`~pathlib.Path.is_char_device` - * :meth:`~pathlib.Path.is_dir` - * :meth:`~pathlib.Path.is_fifo` - * :meth:`~pathlib.Path.is_file` - * :meth:`~pathlib.Path.is_junction` - * :meth:`~pathlib.Path.is_mount` - * :meth:`~pathlib.Path.is_socket` - * :meth:`~pathlib.Path.is_symlink` - * :meth:`~pathlib.Path.lchmod` - * :meth:`~pathlib.Path.lstat` - * :meth:`~pathlib.Path.mkdir` - * :meth:`~pathlib.Path.open` - * :meth:`~pathlib.Path.owner` - * :meth:`~pathlib.Path.read_bytes` - * :meth:`~pathlib.Path.read_text` - * :meth:`~pathlib.Path.readlink` - * :meth:`~pathlib.Path.rename` - * :meth:`~pathlib.Path.replace` - * :meth:`~pathlib.Path.resolve` - * :meth:`~pathlib.Path.rmdir` - * :meth:`~pathlib.Path.samefile` - * :meth:`~pathlib.Path.stat` - * :meth:`~pathlib.Path.symlink_to` - * :meth:`~pathlib.Path.touch` - * :meth:`~pathlib.Path.unlink` - * :meth:`~pathlib.Path.walk` - * :meth:`~pathlib.Path.write_bytes` - * :meth:`~pathlib.Path.write_text` - - Additionally, the following methods return an async iterator yielding - :class:`~.Path` objects: - - * :meth:`~pathlib.Path.glob` - * :meth:`~pathlib.Path.iterdir` - * :meth:`~pathlib.Path.rglob` - """ - - __slots__ = "_path", "__weakref__" - - __weakref__: Any - - def __init__(self, *args: str | PathLike[str]) -> None: - self._path: Final[pathlib.Path] = pathlib.Path(*args) - - def __fspath__(self) -> str: - return self._path.__fspath__() - - def __str__(self) -> str: - return self._path.__str__() - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.as_posix()!r})" - - def __bytes__(self) -> bytes: - return self._path.__bytes__() - - def __hash__(self) -> int: - return self._path.__hash__() - - def __eq__(self, other: object) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__eq__(target) - - def __lt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__lt__(target) - - def __le__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__le__(target) - - def __gt__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__gt__(target) - - def __ge__(self, other: pathlib.PurePath | Path) -> bool: - target = other._path if isinstance(other, Path) else other - return self._path.__ge__(target) - - def __truediv__(self, other: str | PathLike[str]) -> Path: - return Path(self._path / other) - - def __rtruediv__(self, other: str | PathLike[str]) -> Path: - return Path(other) / self - - @property - def parts(self) -> tuple[str, ...]: - return self._path.parts - - @property - def drive(self) -> str: - return self._path.drive - - @property - def root(self) -> str: - return self._path.root - - @property - def anchor(self) -> str: - return self._path.anchor - - @property - def parents(self) -> Sequence[Path]: - return tuple(Path(p) for p in self._path.parents) - - @property - def parent(self) -> Path: - return Path(self._path.parent) - - @property - def name(self) -> str: - return self._path.name - - @property - def suffix(self) -> str: - return self._path.suffix - - @property - def suffixes(self) -> list[str]: - return self._path.suffixes - - @property - def stem(self) -> str: - return self._path.stem - - async def absolute(self) -> Path: - path = await to_thread.run_sync(self._path.absolute) - return Path(path) - - def as_posix(self) -> str: - return self._path.as_posix() - - def as_uri(self) -> str: - return self._path.as_uri() - - if sys.version_info >= (3, 13): - parser: ClassVar[ModuleType] = pathlib.Path.parser - - @classmethod - def from_uri(cls, uri: str) -> Path: - return Path(pathlib.Path.from_uri(uri)) - - def full_match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.full_match(path_pattern, case_sensitive=case_sensitive) - - def match( - self, path_pattern: str, *, case_sensitive: bool | None = None - ) -> bool: - return self._path.match(path_pattern, case_sensitive=case_sensitive) - else: - - def match(self, path_pattern: str) -> bool: - return self._path.match(path_pattern) - - if sys.version_info >= (3, 14): - - @property - def info(self) -> Any: # TODO: add return type annotation when Typeshed gets it - return self._path.info - - async def copy( - self, - target: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Path: - func = partial( - self._path.copy, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return Path(await to_thread.run_sync(func, pathlib.Path(target))) - - async def copy_into( - self, - target_dir: str | os.PathLike[str], - *, - follow_symlinks: bool = True, - preserve_metadata: bool = False, - ) -> Path: - func = partial( - self._path.copy_into, - follow_symlinks=follow_symlinks, - preserve_metadata=preserve_metadata, - ) - return Path(await to_thread.run_sync(func, pathlib.Path(target_dir))) - - async def move(self, target: str | os.PathLike[str]) -> Path: - # Upstream does not handle anyio.Path properly as a PathLike - target = pathlib.Path(target) - return Path(await to_thread.run_sync(self._path.move, target)) - - async def move_into( - self, - target_dir: str | os.PathLike[str], - ) -> Path: - return Path(await to_thread.run_sync(self._path.move_into, target_dir)) - - def is_relative_to(self, other: str | PathLike[str]) -> bool: - try: - self.relative_to(other) - return True - except ValueError: - return False - - async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: - func = partial(os.chmod, follow_symlinks=follow_symlinks) - return await to_thread.run_sync(func, self._path, mode) - - @classmethod - async def cwd(cls) -> Path: - path = await to_thread.run_sync(pathlib.Path.cwd) - return cls(path) - - async def exists(self) -> bool: - return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True) - - async def expanduser(self) -> Path: - return Path( - await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True) - ) - - if sys.version_info < (3, 12): - # Python 3.11 and earlier - def glob(self, pattern: str) -> AsyncIterator[Path]: - gen = self._path.glob(pattern) - return _PathIterator(gen) - elif (3, 12) <= sys.version_info < (3, 13): - # changed in Python 3.12: - # - The case_sensitive parameter was added. - def glob( - self, - pattern: str, - *, - case_sensitive: bool | None = None, - ) -> AsyncIterator[Path]: - gen = self._path.glob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Path]: - gen = self._path.glob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen) - - async def group(self) -> str: - return await to_thread.run_sync(self._path.group, abandon_on_cancel=True) - - async def hardlink_to( - self, target: str | bytes | PathLike[str] | PathLike[bytes] - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(os.link, target, self) - - @classmethod - async def home(cls) -> Path: - home_path = await to_thread.run_sync(pathlib.Path.home) - return cls(home_path) - - def is_absolute(self) -> bool: - return self._path.is_absolute() - - async def is_block_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_block_device, abandon_on_cancel=True - ) - - async def is_char_device(self) -> bool: - return await to_thread.run_sync( - self._path.is_char_device, abandon_on_cancel=True - ) - - async def is_dir(self) -> bool: - return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True) - - async def is_fifo(self) -> bool: - return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True) - - async def is_file(self) -> bool: - return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True) - - if sys.version_info >= (3, 12): - - async def is_junction(self) -> bool: - return await to_thread.run_sync(self._path.is_junction) - - async def is_mount(self) -> bool: - return await to_thread.run_sync( - os.path.ismount, self._path, abandon_on_cancel=True - ) - - def is_reserved(self) -> bool: - return self._path.is_reserved() - - async def is_socket(self) -> bool: - return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True) - - async def is_symlink(self) -> bool: - return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True) - - async def iterdir(self) -> AsyncIterator[Path]: - gen = ( - self._path.iterdir() - if sys.version_info < (3, 13) - else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True) - ) - async for path in _PathIterator(gen): - yield path - - def joinpath(self, *args: str | PathLike[str]) -> Path: - return Path(self._path.joinpath(*args)) - - async def lchmod(self, mode: int) -> None: - await to_thread.run_sync(self._path.lchmod, mode) - - async def lstat(self) -> os.stat_result: - return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True) - - async def mkdir( - self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False - ) -> None: - await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok) - - @overload - async def open( - self, - mode: OpenBinaryMode, - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[bytes]: ... - - @overload - async def open( - self, - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - ) -> AsyncFile[str]: ... - - async def open( - self, - mode: str = "r", - buffering: int = -1, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> AsyncFile[Any]: - fp = await to_thread.run_sync( - self._path.open, mode, buffering, encoding, errors, newline - ) - return AsyncFile(fp) - - async def owner(self) -> str: - return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True) - - async def read_bytes(self) -> bytes: - return await to_thread.run_sync(self._path.read_bytes) - - async def read_text( - self, encoding: str | None = None, errors: str | None = None - ) -> str: - return await to_thread.run_sync(self._path.read_text, encoding, errors) - - if sys.version_info >= (3, 12): - - def relative_to( - self, *other: str | PathLike[str], walk_up: bool = False - ) -> Path: - # relative_to() should work with any PathLike but it doesn't - others = [pathlib.Path(other) for other in other] - return Path(self._path.relative_to(*others, walk_up=walk_up)) - - else: - - def relative_to(self, *other: str | PathLike[str]) -> Path: - return Path(self._path.relative_to(*other)) - - async def readlink(self) -> Path: - target = await to_thread.run_sync(os.readlink, self._path) - return Path(target) - - async def rename(self, target: str | pathlib.PurePath | Path) -> Path: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.rename, target) - return Path(target) - - async def replace(self, target: str | pathlib.PurePath | Path) -> Path: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.replace, target) - return Path(target) - - async def resolve(self, strict: bool = False) -> Path: - func = partial(self._path.resolve, strict=strict) - return Path(await to_thread.run_sync(func, abandon_on_cancel=True)) - - if sys.version_info < (3, 12): - # Pre Python 3.12 - def rglob(self, pattern: str) -> AsyncIterator[Path]: - gen = self._path.rglob(pattern) - return _PathIterator(gen) - elif (3, 12) <= sys.version_info < (3, 13): - # Changed in Python 3.12: - # - The case_sensitive parameter was added. - def rglob( - self, pattern: str, *, case_sensitive: bool | None = None - ) -> AsyncIterator[Path]: - gen = self._path.rglob(pattern, case_sensitive=case_sensitive) - return _PathIterator(gen) - elif sys.version_info >= (3, 13): - # Changed in Python 3.13: - # - The recurse_symlinks parameter was added. - # - The pattern parameter accepts a path-like object. - def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block - self, - pattern: str | PathLike[str], - *, - case_sensitive: bool | None = None, - recurse_symlinks: bool = False, - ) -> AsyncIterator[Path]: - gen = self._path.rglob( - pattern, # type: ignore[arg-type] - case_sensitive=case_sensitive, - recurse_symlinks=recurse_symlinks, - ) - return _PathIterator(gen) - - async def rmdir(self) -> None: - await to_thread.run_sync(self._path.rmdir) - - async def samefile(self, other_path: str | PathLike[str]) -> bool: - if isinstance(other_path, Path): - other_path = other_path._path - - return await to_thread.run_sync( - self._path.samefile, other_path, abandon_on_cancel=True - ) - - async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: - func = partial(os.stat, follow_symlinks=follow_symlinks) - return await to_thread.run_sync(func, self._path, abandon_on_cancel=True) - - async def symlink_to( - self, - target: str | bytes | PathLike[str] | PathLike[bytes], - target_is_directory: bool = False, - ) -> None: - if isinstance(target, Path): - target = target._path - - await to_thread.run_sync(self._path.symlink_to, target, target_is_directory) - - async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: - await to_thread.run_sync(self._path.touch, mode, exist_ok) - - async def unlink(self, missing_ok: bool = False) -> None: - try: - await to_thread.run_sync(self._path.unlink) - except FileNotFoundError: - if not missing_ok: - raise - - if sys.version_info >= (3, 12): - - async def walk( - self, - top_down: bool = True, - on_error: Callable[[OSError], object] | None = None, - follow_symlinks: bool = False, - ) -> AsyncIterator[tuple[Path, list[str], list[str]]]: - def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None: - try: - return next(gen) - except StopIteration: - return None - - gen = self._path.walk(top_down, on_error, follow_symlinks) - while True: - value = await to_thread.run_sync(get_next_value) - if value is None: - return - - root, dirs, paths = value - yield Path(root), dirs, paths - - def with_name(self, name: str) -> Path: - return Path(self._path.with_name(name)) - - def with_stem(self, stem: str) -> Path: - return Path(self._path.with_name(stem + self._path.suffix)) - - def with_suffix(self, suffix: str) -> Path: - return Path(self._path.with_suffix(suffix)) - - def with_segments(self, *pathsegments: str | PathLike[str]) -> Path: - return Path(*pathsegments) - - async def write_bytes(self, data: bytes) -> int: - return await to_thread.run_sync(self._path.write_bytes, data) - - async def write_text( - self, - data: str, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - ) -> int: - # Path.write_text() does not support the "newline" parameter before Python 3.10 - def sync_write_text() -> int: - with self._path.open( - "w", encoding=encoding, errors=errors, newline=newline - ) as fp: - return fp.write(data) - - return await to_thread.run_sync(sync_write_text) - - -PathLike.register(Path) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_resources.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_resources.py deleted file mode 100644 index b9a5344..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_resources.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -from ..abc import AsyncResource -from ._tasks import CancelScope - - -async def aclose_forcefully(resource: AsyncResource) -> None: - """ - Close an asynchronous resource in a cancelled scope. - - Doing this closes the resource without waiting on anything. - - :param resource: the resource to close - - """ - with CancelScope() as scope: - scope.cancel() - await resource.aclose() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_signals.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_signals.py deleted file mode 100644 index e24c79e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_signals.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from collections.abc import AsyncIterator -from contextlib import AbstractContextManager -from signal import Signals - -from ._eventloop import get_async_backend - - -def open_signal_receiver( - *signals: Signals, -) -> AbstractContextManager[AsyncIterator[Signals]]: - """ - Start receiving operating system signals. - - :param signals: signals to receive (e.g. ``signal.SIGINT``) - :return: an asynchronous context manager for an asynchronous iterator which yields - signal numbers - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. warning:: Windows does not support signals natively so it is best to avoid - relying on this in cross-platform applications. - - .. warning:: On asyncio, this permanently replaces any previous signal handler for - the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`. - - """ - return get_async_backend().open_signal_receiver(*signals) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_sockets.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_sockets.py deleted file mode 100644 index 6c99b3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_sockets.py +++ /dev/null @@ -1,1003 +0,0 @@ -from __future__ import annotations - -import errno -import os -import socket -import ssl -import stat -import sys -from collections.abc import Awaitable -from dataclasses import dataclass -from ipaddress import IPv4Address, IPv6Address, ip_address -from os import PathLike, chmod -from socket import AddressFamily, SocketKind -from typing import TYPE_CHECKING, Any, Literal, cast, overload - -from .. import ConnectionFailed, to_thread -from ..abc import ( - ByteStreamConnectable, - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPAddressType, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, -) -from ..streams.stapled import MultiListener -from ..streams.tls import TLSConnectable, TLSStream -from ._eventloop import get_async_backend -from ._resources import aclose_forcefully -from ._synchronization import Event -from ._tasks import create_task_group, move_on_after - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike -else: - FileDescriptorLike = object - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -if sys.version_info < (3, 13): - from typing_extensions import deprecated -else: - from warnings import deprecated - -IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515 - -AnyIPAddressFamily = Literal[ - AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6 -] -IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6] - - -# tls_hostname given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str, - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# ssl_context given -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - ssl_context: ssl.SSLContext, - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=True -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - tls: Literal[True], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> TLSStream: ... - - -# tls=False -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - tls: Literal[False], - ssl_context: ssl.SSLContext | None = ..., - tls_standard_compatible: bool = ..., - tls_hostname: str | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -# No TLS arguments -@overload -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = ..., - happy_eyeballs_delay: float = ..., -) -> SocketStream: ... - - -async def connect_tcp( - remote_host: IPAddressType, - remote_port: int, - *, - local_host: IPAddressType | None = None, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_standard_compatible: bool = True, - tls_hostname: str | None = None, - happy_eyeballs_delay: float = 0.25, -) -> SocketStream | TLSStream: - """ - Connect to a host using the TCP protocol. - - This function implements the stateless version of the Happy Eyeballs algorithm (RFC - 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses, - each one is tried until one connection attempt succeeds. If the first attempt does - not connected within 250 milliseconds, a second attempt is started using the next - address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if - available) is tried first. - - When the connection has been established, a TLS handshake will be done if either - ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``. - - :param remote_host: the IP address or host name to connect to - :param remote_port: port on the target host to connect to - :param local_host: the interface address or name to bind the socket to before - connecting - :param tls: ``True`` to do a TLS handshake with the connected stream and return a - :class:`~anyio.streams.tls.TLSStream` instead - :param ssl_context: the SSL context object to use (if omitted, a default context is - created) - :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake - before closing the stream and requires that the server does this as well. - Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream. - Some protocols, such as HTTP, require this option to be ``False``. - See :meth:`~ssl.SSLContext.wrap_socket` for details. - :param tls_hostname: host name to check the server certificate against (defaults to - the value of ``remote_host``) - :param happy_eyeballs_delay: delay (in seconds) before starting the next connection - attempt - :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream - :raises ConnectionFailed: if the connection fails - - """ - # Placed here due to https://github.com/python/mypy/issues/7057 - connected_stream: SocketStream | None = None - - async def try_connect(remote_host: str, event: Event) -> None: - nonlocal connected_stream - try: - stream = await asynclib.connect_tcp(remote_host, remote_port, local_address) - except OSError as exc: - oserrors.append(exc) - return - else: - if connected_stream is None: - connected_stream = stream - tg.cancel_scope.cancel() - else: - await stream.aclose() - finally: - event.set() - - asynclib = get_async_backend() - local_address: IPSockAddrType | None = None - family = socket.AF_UNSPEC - if local_host: - gai_res = await getaddrinfo(str(local_host), None) - family, *_, local_address = gai_res[0] - - target_host = str(remote_host) - try: - addr_obj = ip_address(remote_host) - except ValueError: - addr_obj = None - - if addr_obj is not None: - if isinstance(addr_obj, IPv6Address): - target_addrs = [(socket.AF_INET6, addr_obj.compressed)] - else: - target_addrs = [(socket.AF_INET, addr_obj.compressed)] - else: - # getaddrinfo() will raise an exception if name resolution fails - gai_res = await getaddrinfo( - target_host, remote_port, family=family, type=socket.SOCK_STREAM - ) - - # Organize the list so that the first address is an IPv6 address (if available) - # and the second one is an IPv4 addresses. The rest can be in whatever order. - v6_found = v4_found = False - target_addrs = [] - for af, *_, sa in gai_res: - if af == socket.AF_INET6 and not v6_found: - v6_found = True - target_addrs.insert(0, (af, sa[0])) - elif af == socket.AF_INET and not v4_found and v6_found: - v4_found = True - target_addrs.insert(1, (af, sa[0])) - else: - target_addrs.append((af, sa[0])) - - oserrors: list[OSError] = [] - try: - async with create_task_group() as tg: - for _af, addr in target_addrs: - event = Event() - tg.start_soon(try_connect, addr, event) - with move_on_after(happy_eyeballs_delay): - await event.wait() - - if connected_stream is None: - cause = ( - oserrors[0] - if len(oserrors) == 1 - else ExceptionGroup("multiple connection attempts failed", oserrors) - ) - raise OSError("All connection attempts failed") from cause - finally: - oserrors.clear() - - if tls or tls_hostname or ssl_context: - try: - return await TLSStream.wrap( - connected_stream, - server_side=False, - hostname=tls_hostname or str(remote_host), - ssl_context=ssl_context, - standard_compatible=tls_standard_compatible, - ) - except BaseException: - await aclose_forcefully(connected_stream) - raise - - return connected_stream - - -async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream: - """ - Connect to the given UNIX socket. - - Not available on Windows. - - :param path: path to the socket - :return: a socket stream object - :raises ConnectionFailed: if the connection fails - - """ - path = os.fspath(path) - return await get_async_backend().connect_unix(path) - - -async def create_tcp_listener( - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC, - backlog: int = 65536, - reuse_port: bool = False, -) -> MultiListener[SocketStream]: - """ - Create a TCP socket listener. - - :param local_port: port number to listen on - :param local_host: IP address of the interface to listen on. If omitted, listen on - all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address - family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6. - :param family: address family (used if ``local_host`` was omitted) - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a multi-listener object containing one or more socket listeners - :raises OSError: if there's an error creating a socket, or binding to one or more - interfaces failed - - """ - asynclib = get_async_backend() - backlog = min(backlog, 65536) - local_host = str(local_host) if local_host is not None else None - - def setup_raw_socket( - fam: AddressFamily, - bind_addr: tuple[str, int] | tuple[str, int, int, int], - *, - v6only: bool = True, - ) -> socket.socket: - sock = socket.socket(fam) - try: - sock.setblocking(False) - - if fam == AddressFamily.AF_INET6: - sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only) - - # For Windows, enable exclusive address use. For others, enable address - # reuse. - if sys.platform == "win32": - sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) - else: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - if reuse_port: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - - # Workaround for #554 - if fam == socket.AF_INET6 and "%" in bind_addr[0]: - addr, scope_id = bind_addr[0].split("%", 1) - bind_addr = (addr, bind_addr[1], 0, int(scope_id)) - - sock.bind(bind_addr) - sock.listen(backlog) - except BaseException: - sock.close() - raise - - return sock - - # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug - # where we don't get the correct scope ID for IPv6 link-local addresses when passing - # type=socket.SOCK_STREAM to getaddrinfo(): - # https://github.com/MagicStack/uvloop/issues/539 - gai_res = await getaddrinfo( - local_host, - local_port, - family=family, - type=socket.SOCK_STREAM if sys.platform == "win32" else 0, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - - # The set comprehension is here to work around a glibc bug: - # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 - sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM}) - - # Special case for dual-stack binding on the "any" interface - if ( - local_host is None - and family == AddressFamily.AF_UNSPEC - and socket.has_dualstack_ipv6() - and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res) - ): - raw_socket = setup_raw_socket( - AddressFamily.AF_INET6, ("::", local_port), v6only=False - ) - listener = asynclib.create_tcp_listener(raw_socket) - return MultiListener([listener]) - - errors: list[OSError] = [] - try: - for _ in range(len(sockaddrs)): - listeners: list[SocketListener] = [] - bound_ephemeral_port = local_port - try: - for fam, *_, sockaddr in sockaddrs: - sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:] - raw_socket = setup_raw_socket(fam, sockaddr) - - # Store the assigned port if an ephemeral port was requested, so - # we'll bind to the same port on all interfaces - if local_port == 0 and len(gai_res) > 1: - bound_ephemeral_port = raw_socket.getsockname()[1] - - listeners.append(asynclib.create_tcp_listener(raw_socket)) - except BaseException as exc: - for listener in listeners: - await listener.aclose() - - # If an ephemeral port was requested but binding the assigned port - # failed for another interface, rotate the address list and try again - if ( - isinstance(exc, OSError) - and exc.errno == errno.EADDRINUSE - and local_port == 0 - and bound_ephemeral_port - ): - errors.append(exc) - sockaddrs.append(sockaddrs.pop(0)) - continue - - raise - - return MultiListener(listeners) - - raise OSError( - f"Could not create {len(sockaddrs)} listeners with a consistent port" - ) from ExceptionGroup("Several bind attempts failed", errors) - finally: - del errors # Prevent reference cycles - - -async def create_unix_listener( - path: str | bytes | PathLike[Any], - *, - mode: int | None = None, - backlog: int = 65536, -) -> SocketListener: - """ - Create a UNIX socket listener. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param backlog: maximum number of queued incoming connections (up to a maximum of - 2**16, or 65536) - :return: a listener object - - .. versionchanged:: 3.0 - If a socket already exists on the file system in the given path, it will be - removed first. - - """ - backlog = min(backlog, 65536) - raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM) - try: - raw_socket.listen(backlog) - return get_async_backend().create_unix_listener(raw_socket) - except BaseException: - raw_socket.close() - raise - - -async def create_udp_socket( - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - *, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> UDPSocket: - """ - Create a UDP socket. - - If ``port`` has been given, the socket will be bound to this port on the local - machine, making this socket suitable for providing UDP based services. - - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a UDP socket - - """ - if family is AddressFamily.AF_UNSPEC and not local_host: - raise ValueError('Either "family" or "local_host" must be given') - - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - elif family is AddressFamily.AF_INET6: - local_address = ("::", 0) - else: - local_address = ("0.0.0.0", 0) - - sock = await get_async_backend().create_udp_socket( - family, local_address, None, reuse_port - ) - return cast(UDPSocket, sock) - - -async def create_connected_udp_socket( - remote_host: IPAddressType, - remote_port: int, - *, - family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, - local_host: IPAddressType | None = None, - local_port: int = 0, - reuse_port: bool = False, -) -> ConnectedUDPSocket: - """ - Create a connected UDP socket. - - Connected UDP sockets can only communicate with the specified remote host/port, an - any packets sent from other sources are dropped. - - :param remote_host: remote host to set as the default target - :param remote_port: port on the remote host to set as the default target - :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically - determined from ``local_host`` or ``remote_host`` if omitted - :param local_host: IP address or host name of the local interface to bind to - :param local_port: local port to bind to - :param reuse_port: ``True`` to allow multiple sockets to bind to the same - address/port (not supported on Windows) - :return: a connected UDP socket - - """ - local_address = None - if local_host: - gai_res = await getaddrinfo( - str(local_host), - local_port, - family=family, - type=socket.SOCK_DGRAM, - flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - local_address = gai_res[0][-1] - - gai_res = await getaddrinfo( - str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM - ) - family = cast(AnyIPAddressFamily, gai_res[0][0]) - remote_address = gai_res[0][-1] - - sock = await get_async_backend().create_udp_socket( - family, local_address, remote_address, reuse_port - ) - return cast(ConnectedUDPSocket, sock) - - -async def create_unix_datagram_socket( - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> UNIXDatagramSocket: - """ - Create a UNIX datagram socket. - - Not available on Windows. - - If ``local_path`` has been given, the socket will be bound to this path, making this - socket suitable for receiving datagrams from other processes. Other processes can - send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a UNIX datagram socket - - """ - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket(raw_socket, None) - - -async def create_connected_unix_datagram_socket( - remote_path: str | bytes | PathLike[Any], - *, - local_path: None | str | bytes | PathLike[Any] = None, - local_mode: int | None = None, -) -> ConnectedUNIXDatagramSocket: - """ - Create a connected UNIX datagram socket. - - Connected datagram sockets can only communicate with the specified remote path. - - If ``local_path`` has been given, the socket will be bound to this path, making - this socket suitable for receiving datagrams from other processes. Other processes - can send datagrams to this socket only if ``local_path`` is set. - - If a socket already exists on the file system in the ``local_path``, it will be - removed first. - - :param remote_path: the path to set as the default target - :param local_path: the path on which to bind to - :param local_mode: permissions to set on the local socket - :return: a connected UNIX datagram socket - - """ - remote_path = os.fspath(remote_path) - raw_socket = await setup_unix_local_socket( - local_path, local_mode, socket.SOCK_DGRAM - ) - return await get_async_backend().create_unix_datagram_socket( - raw_socket, remote_path - ) - - -async def getaddrinfo( - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, -) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]: - """ - Look up a numeric IP address given a host name. - - Internationalized domain names are translated according to the (non-transitional) - IDNA 2008 standard. - - .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of - (host, port), unlike what :func:`socket.getaddrinfo` does. - - :param host: host name - :param port: port number - :param family: socket family (`'AF_INET``, ...) - :param type: socket type (``SOCK_STREAM``, ...) - :param proto: protocol number - :param flags: flags to pass to upstream ``getaddrinfo()`` - :return: list of tuples containing (family, type, proto, canonname, sockaddr) - - .. seealso:: :func:`socket.getaddrinfo` - - """ - # Handle unicode hostnames - if isinstance(host, str): - try: - encoded_host: bytes | None = host.encode("ascii") - except UnicodeEncodeError: - import idna - - encoded_host = idna.encode(host, uts46=True) - else: - encoded_host = host - - gai_res = await get_async_backend().getaddrinfo( - encoded_host, port, family=family, type=type, proto=proto, flags=flags - ) - return [ - (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr)) - for family, type, proto, canonname, sockaddr in gai_res - # filter out IPv6 results when IPv6 is disabled - if not isinstance(sockaddr[0], int) - ] - - -def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]: - """ - Look up the host name of an IP address. - - :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4) - :param flags: flags to pass to upstream ``getnameinfo()`` - :return: a tuple of (host name, service name) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: :func:`socket.getnameinfo` - - """ - return get_async_backend().getnameinfo(sockaddr, flags) - - -@deprecated("This function is deprecated; use `wait_readable` instead") -def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_readable` instead. - - Wait until the given socket has data to be read. - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(sock.fileno()) - - -@deprecated("This function is deprecated; use `wait_writable` instead") -def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: - """ - .. deprecated:: 4.7.0 - Use :func:`wait_writable` instead. - - Wait until the given socket can be written to. - - This does **NOT** work on Windows when using the asyncio backend with a proactor - event loop (default on py3.8+). - - .. warning:: Only use this on raw sockets that have not been wrapped by any higher - level constructs like socket streams! - - :param sock: a socket object - :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the - socket to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the socket - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_writable(sock.fileno()) - - -def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object has data to be read. - - On Unix systems, ``obj`` must either be an integer file descriptor, or else an - object with a ``.fileno()`` method which returns an integer file descriptor. Any - kind of file descriptor can be passed, though the exact semantics will depend on - your kernel. For example, this probably won't do anything useful for on-disk files. - - On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an - object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File - descriptors aren't supported, and neither are handles that refer to anything besides - a ``SOCKET``. - - On backends where this functionality is not natively provided (asyncio - ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread - which is set to shut down when the interpreter shuts down. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become readable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become readable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().wait_readable(obj) - - -def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]: - """ - Wait until the given object can be written to. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the - object to become writable - :raises ~anyio.BusyResourceError: if another task is already waiting for the object - to become writable - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. seealso:: See the documentation of :func:`wait_readable` for the definition of - ``obj`` and notes on backend compatibility. - - .. warning:: Don't use this on raw sockets that have been wrapped by any higher - level constructs like socket streams! - - """ - return get_async_backend().wait_writable(obj) - - -def notify_closing(obj: FileDescriptorLike) -> None: - """ - Call this before closing a file descriptor (on Unix) or socket (on - Windows). This will cause any `wait_readable` or `wait_writable` - calls on the given object to immediately wake up and raise - `~anyio.ClosedResourceError`. - - This doesn't actually close the object – you still have to do that - yourself afterwards. Also, you want to be careful to make sure no - new tasks start waiting on the object in between when you call this - and when it's actually closed. So to close something properly, you - usually want to do these steps in order: - - 1. Explicitly mark the object as closed, so that any new attempts - to use it will abort before they start. - 2. Call `notify_closing` to wake up any already-existing users. - 3. Actually close the object. - - It's also possible to do them in a different order if that's more - convenient, *but only if* you make sure not to have any checkpoints in - between the steps. This way they all happen in a single atomic - step, so other tasks won't be able to tell what order they happened - in anyway. - - :param obj: an object with a ``.fileno()`` method or an integer handle - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - get_async_backend().notify_closing(obj) - - -# -# Private API -# - - -def convert_ipv6_sockaddr( - sockaddr: tuple[str, int, int, int] | tuple[str, int], -) -> tuple[str, int]: - """ - Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format. - - If the scope ID is nonzero, it is added to the address, separated with ``%``. - Otherwise the flow id and scope id are simply cut off from the tuple. - Any other kinds of socket addresses are returned as-is. - - :param sockaddr: the result of :meth:`~socket.socket.getsockname` - :return: the converted socket address - - """ - # This is more complicated than it should be because of MyPy - if isinstance(sockaddr, tuple) and len(sockaddr) == 4: - host, port, flowinfo, scope_id = sockaddr - if scope_id: - # PyPy (as of v7.3.11) leaves the interface name in the result, so - # we discard it and only get the scope ID from the end - # (https://foss.heptapod.net/pypy/pypy/-/issues/3938) - host = host.split("%")[0] - - # Add scope_id to the address - return f"{host}%{scope_id}", port - else: - return host, port - else: - return sockaddr - - -async def setup_unix_local_socket( - path: None | str | bytes | PathLike[Any], - mode: int | None, - socktype: int, -) -> socket.socket: - """ - Create a UNIX local socket object, deleting the socket at the given path if it - exists. - - Not available on Windows. - - :param path: path of the socket - :param mode: permissions to set on the socket - :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM - - """ - path_str: str | None - if path is not None: - path_str = os.fsdecode(path) - - # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call - if not path_str.startswith("\0"): - # Copied from pathlib... - try: - stat_result = os.stat(path) - except OSError as e: - if e.errno not in ( - errno.ENOENT, - errno.ENOTDIR, - errno.EBADF, - errno.ELOOP, - ): - raise - else: - if stat.S_ISSOCK(stat_result.st_mode): - os.unlink(path) - else: - path_str = None - - raw_socket = socket.socket(socket.AF_UNIX, socktype) - raw_socket.setblocking(False) - - if path_str is not None: - try: - await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True) - if mode is not None: - await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True) - except BaseException: - raw_socket.close() - raise - - return raw_socket - - -@dataclass -class TCPConnectable(ByteStreamConnectable): - """ - Connects to a TCP server at the given host and port. - - :param host: host name or IP address of the server - :param port: TCP port number of the server - """ - - host: str | IPv4Address | IPv6Address - port: int - - def __post_init__(self) -> None: - if self.port < 1 or self.port > 65535: - raise ValueError("TCP port number out of range") - - @override - async def connect(self) -> SocketStream: - try: - return await connect_tcp(self.host, self.port) - except OSError as exc: - raise ConnectionFailed( - f"error connecting to {self.host}:{self.port}: {exc}" - ) from exc - - -@dataclass -class UNIXConnectable(ByteStreamConnectable): - """ - Connects to a UNIX domain socket at the given path. - - :param path: the file system path of the socket - """ - - path: str | bytes | PathLike[str] | PathLike[bytes] - - @override - async def connect(self) -> UNIXSocketStream: - try: - return await connect_unix(self.path) - except OSError as exc: - raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc - - -def as_connectable( - remote: ByteStreamConnectable - | tuple[str | IPv4Address | IPv6Address, int] - | str - | bytes - | PathLike[str], - /, - *, - tls: bool = False, - ssl_context: ssl.SSLContext | None = None, - tls_hostname: str | None = None, - tls_standard_compatible: bool = True, -) -> ByteStreamConnectable: - """ - Return a byte stream connectable from the given object. - - If a bytestream connectable is given, it is returned unchanged. - If a tuple of (host, port) is given, a TCP connectable is returned. - If a string or bytes path is given, a UNIX connectable is returned. - - If ``tls=True``, the connectable will be wrapped in a - :class:`~.streams.tls.TLSConnectable`. - - :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket - :param tls: if ``True``, wrap the plaintext connectable in a - :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings) - :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided, - a secure default will be created) - :param tls_hostname: if ``tls=True``, host name of the server to use for checking - the server certificate (defaults to the host portion of the address for TCP - connectables) - :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream - skip the closing handshake when closing the connection, so it won't raise an - exception if the server does the same - - """ - connectable: TCPConnectable | UNIXConnectable | TLSConnectable - if isinstance(remote, ByteStreamConnectable): - return remote - elif isinstance(remote, tuple) and len(remote) == 2: - connectable = TCPConnectable(*remote) - elif isinstance(remote, (str, bytes, PathLike)): - connectable = UNIXConnectable(remote) - else: - raise TypeError(f"cannot convert {remote!r} to a connectable") - - if tls: - if not tls_hostname and isinstance(connectable, TCPConnectable): - tls_hostname = str(connectable.host) - - connectable = TLSConnectable( - connectable, - ssl_context=ssl_context, - hostname=tls_hostname, - standard_compatible=tls_standard_compatible, - ) - - return connectable diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_streams.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_streams.py deleted file mode 100644 index 2b9c7df..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_streams.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import math -from typing import TypeVar -from warnings import warn - -from ..streams.memory import ( - MemoryObjectReceiveStream, - MemoryObjectSendStream, - _MemoryObjectStreamState, -) - -T_Item = TypeVar("T_Item") - - -class create_memory_object_stream( - tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]], -): - """ - Create a memory object stream. - - The stream's item type can be annotated like - :func:`create_memory_object_stream[T_Item]`. - - :param max_buffer_size: number of items held in the buffer until ``send()`` starts - blocking - :param item_type: old way of marking the streams with the right generic type for - static typing (does nothing on AnyIO 4) - - .. deprecated:: 4.0 - Use ``create_memory_object_stream[YourItemType](...)`` instead. - :return: a tuple of (send stream, receive stream) - - """ - - def __new__( # type: ignore[misc] - cls, max_buffer_size: float = 0, item_type: object = None - ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]: - if max_buffer_size != math.inf and not isinstance(max_buffer_size, int): - raise ValueError("max_buffer_size must be either an integer or math.inf") - if max_buffer_size < 0: - raise ValueError("max_buffer_size cannot be negative") - if item_type is not None: - warn( - "The item_type argument has been deprecated in AnyIO 4.0. " - "Use create_memory_object_stream[YourItemType](...) instead.", - DeprecationWarning, - stacklevel=2, - ) - - state = _MemoryObjectStreamState[T_Item](max_buffer_size) - return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state)) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_subprocesses.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_subprocesses.py deleted file mode 100644 index 36d9b30..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_subprocesses.py +++ /dev/null @@ -1,202 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import AsyncIterable, Iterable, Mapping, Sequence -from io import BytesIO -from os import PathLike -from subprocess import PIPE, CalledProcessError, CompletedProcess -from typing import IO, Any, Union, cast - -from ..abc import Process -from ._eventloop import get_async_backend -from ._tasks import create_task_group - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"] - - -async def run_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - input: bytes | None = None, - stdin: int | IO[Any] | None = None, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - check: bool = True, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> CompletedProcess[bytes]: - """ - Run an external command in a subprocess and wait until it completes. - - .. seealso:: :func:`subprocess.run` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param input: bytes passed to the standard input of the subprocess - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None`; ``input`` overrides this - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or `None` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or `None` - :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the - process terminates with a return code other than 0 - :param cwd: If not ``None``, change the working directory to this before running the - command - :param env: if not ``None``, this mapping replaces the inherited environment - variables from the parent process - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (Python >= 3.9, POSIX only) - :param group: effective group to run the process as (Python >= 3.9, POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9, - POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (Python >= 3.9, POSIX only) - :return: an object representing the completed process - :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process - exits with a nonzero return code - - """ - - async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None: - buffer = BytesIO() - async for chunk in stream: - buffer.write(chunk) - - stream_contents[index] = buffer.getvalue() - - if stdin is not None and input is not None: - raise ValueError("only one of stdin and input is allowed") - - async with await open_process( - command, - stdin=PIPE if input else stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - user=user, - group=group, - extra_groups=extra_groups, - umask=umask, - ) as process: - stream_contents: list[bytes | None] = [None, None] - async with create_task_group() as tg: - if process.stdout: - tg.start_soon(drain_stream, process.stdout, 0) - - if process.stderr: - tg.start_soon(drain_stream, process.stderr, 1) - - if process.stdin and input: - await process.stdin.send(input) - await process.stdin.aclose() - - await process.wait() - - output, errors = stream_contents - if check and process.returncode != 0: - raise CalledProcessError(cast(int, process.returncode), command, output, errors) - - return CompletedProcess(command, cast(int, process.returncode), output, errors) - - -async def open_process( - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None = PIPE, - stdout: int | IO[Any] | None = PIPE, - stderr: int | IO[Any] | None = PIPE, - cwd: StrOrBytesPath | None = None, - env: Mapping[str, str] | None = None, - startupinfo: Any = None, - creationflags: int = 0, - start_new_session: bool = False, - pass_fds: Sequence[int] = (), - user: str | int | None = None, - group: str | int | None = None, - extra_groups: Iterable[str | int] | None = None, - umask: int = -1, -) -> Process: - """ - Start an external command in a subprocess. - - .. seealso:: :class:`subprocess.Popen` - - :param command: either a string to pass to the shell, or an iterable of strings - containing the executable name or path and its arguments - :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a - file-like object, or ``None`` - :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - a file-like object, or ``None`` - :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, - :data:`subprocess.STDOUT`, a file-like object, or ``None`` - :param cwd: If not ``None``, the working directory is changed before executing - :param env: If env is not ``None``, it must be a mapping that defines the - environment variables for the new process - :param creationflags: flags that can be used to control the creation of the - subprocess (see :class:`subprocess.Popen` for the specifics) - :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used - to specify process startup parameters (Windows only) - :param start_new_session: if ``true`` the setsid() system call will be made in the - child process prior to the execution of the subprocess. (POSIX only) - :param pass_fds: sequence of file descriptors to keep open between the parent and - child processes. (POSIX only) - :param user: effective user to run the process as (POSIX only) - :param group: effective group to run the process as (POSIX only) - :param extra_groups: supplementary groups to set in the subprocess (POSIX only) - :param umask: if not negative, this umask is applied in the child process before - running the given command (POSIX only) - :return: an asynchronous process object - - """ - kwargs: dict[str, Any] = {} - if user is not None: - kwargs["user"] = user - - if group is not None: - kwargs["group"] = group - - if extra_groups is not None: - kwargs["extra_groups"] = group - - if umask >= 0: - kwargs["umask"] = umask - - return await get_async_backend().open_process( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd, - env=env, - startupinfo=startupinfo, - creationflags=creationflags, - start_new_session=start_new_session, - pass_fds=pass_fds, - **kwargs, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_synchronization.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_synchronization.py deleted file mode 100644 index c0ef27a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_synchronization.py +++ /dev/null @@ -1,753 +0,0 @@ -from __future__ import annotations - -import math -from collections import deque -from collections.abc import Callable -from dataclasses import dataclass -from types import TracebackType -from typing import TypeVar - -from ..lowlevel import checkpoint_if_cancelled -from ._eventloop import get_async_backend -from ._exceptions import BusyResourceError, NoEventLoopError -from ._tasks import CancelScope -from ._testing import TaskInfo, get_current_task - -T = TypeVar("T") - - -@dataclass(frozen=True) -class EventStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait` - """ - - tasks_waiting: int - - -@dataclass(frozen=True) -class CapacityLimiterStatistics: - """ - :ivar int borrowed_tokens: number of tokens currently borrowed by tasks - :ivar float total_tokens: total number of available tokens - :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from - this limiter - :ivar int tasks_waiting: number of tasks waiting on - :meth:`~.CapacityLimiter.acquire` or - :meth:`~.CapacityLimiter.acquire_on_behalf_of` - """ - - borrowed_tokens: int - total_tokens: float - borrowers: tuple[object, ...] - tasks_waiting: int - - -@dataclass(frozen=True) -class LockStatistics: - """ - :ivar bool locked: flag indicating if this lock is locked or not - :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the - lock is not held by any task) - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire` - """ - - locked: bool - owner: TaskInfo | None - tasks_waiting: int - - -@dataclass(frozen=True) -class ConditionStatistics: - """ - :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait` - :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying - :class:`~.Lock` - """ - - tasks_waiting: int - lock_statistics: LockStatistics - - -@dataclass(frozen=True) -class SemaphoreStatistics: - """ - :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire` - - """ - - tasks_waiting: int - - -class Event: - def __new__(cls) -> Event: - try: - return get_async_backend().create_event() - except NoEventLoopError: - return EventAdapter() - - def set(self) -> None: - """Set the flag, notifying all listeners.""" - raise NotImplementedError - - def is_set(self) -> bool: - """Return ``True`` if the flag is set, ``False`` if not.""" - raise NotImplementedError - - async def wait(self) -> None: - """ - Wait until the flag has been set. - - If the flag has already been set when this method is called, it returns - immediately. - - """ - raise NotImplementedError - - def statistics(self) -> EventStatistics: - """Return statistics about the current state of this event.""" - raise NotImplementedError - - -class EventAdapter(Event): - _internal_event: Event | None = None - _is_set: bool = False - - def __new__(cls) -> EventAdapter: - return object.__new__(cls) - - @property - def _event(self) -> Event: - if self._internal_event is None: - self._internal_event = get_async_backend().create_event() - if self._is_set: - self._internal_event.set() - - return self._internal_event - - def set(self) -> None: - if self._internal_event is None: - self._is_set = True - else: - self._event.set() - - def is_set(self) -> bool: - if self._internal_event is None: - return self._is_set - - return self._internal_event.is_set() - - async def wait(self) -> None: - await self._event.wait() - - def statistics(self) -> EventStatistics: - if self._internal_event is None: - return EventStatistics(tasks_waiting=0) - - return self._internal_event.statistics() - - -class Lock: - def __new__(cls, *, fast_acquire: bool = False) -> Lock: - try: - return get_async_backend().create_lock(fast_acquire=fast_acquire) - except NoEventLoopError: - return LockAdapter(fast_acquire=fast_acquire) - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Release the lock.""" - raise NotImplementedError - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - raise NotImplementedError - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class LockAdapter(Lock): - _internal_lock: Lock | None = None - - def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter: - return object.__new__(cls) - - def __init__(self, *, fast_acquire: bool = False): - self._fast_acquire = fast_acquire - - @property - def _lock(self) -> Lock: - if self._internal_lock is None: - self._internal_lock = get_async_backend().create_lock( - fast_acquire=self._fast_acquire - ) - - return self._internal_lock - - async def __aenter__(self) -> None: - await self._lock.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self._internal_lock is not None: - self._internal_lock.release() - - async def acquire(self) -> None: - """Acquire the lock.""" - await self._lock.acquire() - - def acquire_nowait(self) -> None: - """ - Acquire the lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - - def release(self) -> None: - """Release the lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is currently held.""" - return self._lock.locked() - - def statistics(self) -> LockStatistics: - """ - Return statistics about the current state of this lock. - - .. versionadded:: 3.0 - - """ - if self._internal_lock is None: - return LockStatistics(False, None, 0) - - return self._internal_lock.statistics() - - -class Condition: - _owner_task: TaskInfo | None = None - - def __init__(self, lock: Lock | None = None): - self._lock = lock or Lock() - self._waiters: deque[Event] = deque() - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - def _check_acquired(self) -> None: - if self._owner_task != get_current_task(): - raise RuntimeError("The current task is not holding the underlying lock") - - async def acquire(self) -> None: - """Acquire the underlying lock.""" - await self._lock.acquire() - self._owner_task = get_current_task() - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - self._lock.acquire_nowait() - self._owner_task = get_current_task() - - def release(self) -> None: - """Release the underlying lock.""" - self._lock.release() - - def locked(self) -> bool: - """Return True if the lock is set.""" - return self._lock.locked() - - def notify(self, n: int = 1) -> None: - """Notify exactly n listeners.""" - self._check_acquired() - for _ in range(n): - try: - event = self._waiters.popleft() - except IndexError: - break - - event.set() - - def notify_all(self) -> None: - """Notify all the listeners.""" - self._check_acquired() - for event in self._waiters: - event.set() - - self._waiters.clear() - - async def wait(self) -> None: - """Wait for a notification.""" - await checkpoint_if_cancelled() - self._check_acquired() - event = Event() - self._waiters.append(event) - self.release() - try: - await event.wait() - except BaseException: - if not event.is_set(): - self._waiters.remove(event) - - raise - finally: - with CancelScope(shield=True): - await self.acquire() - - async def wait_for(self, predicate: Callable[[], T]) -> T: - """ - Wait until a predicate becomes true. - - :param predicate: a callable that returns a truthy value when the condition is - met - :return: the result of the predicate - - .. versionadded:: 4.11.0 - - """ - while not (result := predicate()): - await self.wait() - - return result - - def statistics(self) -> ConditionStatistics: - """ - Return statistics about the current state of this condition. - - .. versionadded:: 3.0 - """ - return ConditionStatistics(len(self._waiters), self._lock.statistics()) - - -class Semaphore: - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - try: - return get_async_backend().create_semaphore( - initial_value, max_value=max_value, fast_acquire=fast_acquire - ) - except NoEventLoopError: - return SemaphoreAdapter(initial_value, max_value=max_value) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ): - if not isinstance(initial_value, int): - raise TypeError("initial_value must be an integer") - if initial_value < 0: - raise ValueError("initial_value must be >= 0") - if max_value is not None: - if not isinstance(max_value, int): - raise TypeError("max_value must be an integer or None") - if max_value < initial_value: - raise ValueError( - "max_value must be equal to or higher than initial_value" - ) - - self._fast_acquire = fast_acquire - - async def __aenter__(self) -> Semaphore: - await self.acquire() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.release() - - async def acquire(self) -> None: - """Decrement the semaphore value, blocking if necessary.""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire the underlying lock, without blocking. - - :raises ~anyio.WouldBlock: if the operation would block - - """ - raise NotImplementedError - - def release(self) -> None: - """Increment the semaphore value.""" - raise NotImplementedError - - @property - def value(self) -> int: - """The current value of the semaphore.""" - raise NotImplementedError - - @property - def max_value(self) -> int | None: - """The maximum value of the semaphore.""" - raise NotImplementedError - - def statistics(self) -> SemaphoreStatistics: - """ - Return statistics about the current state of this semaphore. - - .. versionadded:: 3.0 - """ - raise NotImplementedError - - -class SemaphoreAdapter(Semaphore): - _internal_semaphore: Semaphore | None = None - - def __new__( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> SemaphoreAdapter: - return object.__new__(cls) - - def __init__( - self, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> None: - super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) - self._initial_value = initial_value - self._max_value = max_value - - @property - def _semaphore(self) -> Semaphore: - if self._internal_semaphore is None: - self._internal_semaphore = get_async_backend().create_semaphore( - self._initial_value, max_value=self._max_value - ) - - return self._internal_semaphore - - async def acquire(self) -> None: - await self._semaphore.acquire() - - def acquire_nowait(self) -> None: - self._semaphore.acquire_nowait() - - def release(self) -> None: - self._semaphore.release() - - @property - def value(self) -> int: - if self._internal_semaphore is None: - return self._initial_value - - return self._semaphore.value - - @property - def max_value(self) -> int | None: - return self._max_value - - def statistics(self) -> SemaphoreStatistics: - if self._internal_semaphore is None: - return SemaphoreStatistics(tasks_waiting=0) - - return self._semaphore.statistics() - - -class CapacityLimiter: - def __new__(cls, total_tokens: float) -> CapacityLimiter: - try: - return get_async_backend().create_capacity_limiter(total_tokens) - except NoEventLoopError: - return CapacityLimiterAdapter(total_tokens) - - async def __aenter__(self) -> None: - raise NotImplementedError - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - raise NotImplementedError - - @property - def total_tokens(self) -> float: - """ - The total number of tokens available for borrowing. - - This is a read-write property. If the total number of tokens is increased, the - proportionate number of tasks waiting on this limiter will be granted their - tokens. - - .. versionchanged:: 3.0 - The property is now writable. - .. versionchanged:: 4.12 - The value can now be set to 0. - - """ - raise NotImplementedError - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - raise NotImplementedError - - @property - def borrowed_tokens(self) -> int: - """The number of tokens that have currently been borrowed.""" - raise NotImplementedError - - @property - def available_tokens(self) -> float: - """The number of tokens currently available to be borrowed""" - raise NotImplementedError - - def acquire_nowait(self) -> None: - """ - Acquire a token for the current task without waiting for one to become - available. - - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - """ - Acquire a token without waiting for one to become available. - - :param borrower: the entity borrowing a token - :raises ~anyio.WouldBlock: if there are no tokens available for borrowing - - """ - raise NotImplementedError - - async def acquire(self) -> None: - """ - Acquire a token for the current task, waiting if necessary for one to become - available. - - """ - raise NotImplementedError - - async def acquire_on_behalf_of(self, borrower: object) -> None: - """ - Acquire a token, waiting if necessary for one to become available. - - :param borrower: the entity borrowing a token - - """ - raise NotImplementedError - - def release(self) -> None: - """ - Release the token held by the current task. - - :raises RuntimeError: if the current task has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def release_on_behalf_of(self, borrower: object) -> None: - """ - Release the token held by the given borrower. - - :raises RuntimeError: if the borrower has not borrowed a token from this - limiter. - - """ - raise NotImplementedError - - def statistics(self) -> CapacityLimiterStatistics: - """ - Return statistics about the current state of this limiter. - - .. versionadded:: 3.0 - - """ - raise NotImplementedError - - -class CapacityLimiterAdapter(CapacityLimiter): - _internal_limiter: CapacityLimiter | None = None - - def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter: - return object.__new__(cls) - - def __init__(self, total_tokens: float) -> None: - self.total_tokens = total_tokens - - @property - def _limiter(self) -> CapacityLimiter: - if self._internal_limiter is None: - self._internal_limiter = get_async_backend().create_capacity_limiter( - self._total_tokens - ) - - return self._internal_limiter - - async def __aenter__(self) -> None: - await self._limiter.__aenter__() - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - return await self._limiter.__aexit__(exc_type, exc_val, exc_tb) - - @property - def total_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.total_tokens - - @total_tokens.setter - def total_tokens(self, value: float) -> None: - if not isinstance(value, int) and value is not math.inf: - raise TypeError("total_tokens must be an int or math.inf") - elif value < 1: - raise ValueError("total_tokens must be >= 1") - - if self._internal_limiter is None: - self._total_tokens = value - return - - self._limiter.total_tokens = value - - @property - def borrowed_tokens(self) -> int: - if self._internal_limiter is None: - return 0 - - return self._internal_limiter.borrowed_tokens - - @property - def available_tokens(self) -> float: - if self._internal_limiter is None: - return self._total_tokens - - return self._internal_limiter.available_tokens - - def acquire_nowait(self) -> None: - self._limiter.acquire_nowait() - - def acquire_on_behalf_of_nowait(self, borrower: object) -> None: - self._limiter.acquire_on_behalf_of_nowait(borrower) - - async def acquire(self) -> None: - await self._limiter.acquire() - - async def acquire_on_behalf_of(self, borrower: object) -> None: - await self._limiter.acquire_on_behalf_of(borrower) - - def release(self) -> None: - self._limiter.release() - - def release_on_behalf_of(self, borrower: object) -> None: - self._limiter.release_on_behalf_of(borrower) - - def statistics(self) -> CapacityLimiterStatistics: - if self._internal_limiter is None: - return CapacityLimiterStatistics( - borrowed_tokens=0, - total_tokens=self.total_tokens, - borrowers=(), - tasks_waiting=0, - ) - - return self._internal_limiter.statistics() - - -class ResourceGuard: - """ - A context manager for ensuring that a resource is only used by a single task at a - time. - - Entering this context manager while the previous has not exited it yet will trigger - :exc:`BusyResourceError`. - - :param action: the action to guard against (visible in the :exc:`BusyResourceError` - when triggered, e.g. "Another task is already {action} this resource") - - .. versionadded:: 4.1 - """ - - __slots__ = "action", "_guarded" - - def __init__(self, action: str = "using"): - self.action: str = action - self._guarded = False - - def __enter__(self) -> None: - if self._guarded: - raise BusyResourceError(self.action) - - self._guarded = True - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._guarded = False diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tasks.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tasks.py deleted file mode 100644 index 0688bfe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tasks.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -import math -from collections.abc import Generator -from contextlib import contextmanager -from types import TracebackType - -from ..abc._tasks import TaskGroup, TaskStatus -from ._eventloop import get_async_backend - - -class _IgnoredTaskStatus(TaskStatus[object]): - def started(self, value: object = None) -> None: - pass - - -TASK_STATUS_IGNORED = _IgnoredTaskStatus() - - -class CancelScope: - """ - Wraps a unit of work that can be made separately cancellable. - - :param deadline: The time (clock value) when this scope is cancelled automatically - :param shield: ``True`` to shield the cancel scope from external cancellation - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - def __new__( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline) - - def cancel(self, reason: str | None = None) -> None: - """ - Cancel this scope immediately. - - :param reason: a message describing the reason for the cancellation - - """ - raise NotImplementedError - - @property - def deadline(self) -> float: - """ - The time (clock value) when this scope is cancelled automatically. - - Will be ``float('inf')`` if no timeout has been set. - - """ - raise NotImplementedError - - @deadline.setter - def deadline(self, value: float) -> None: - raise NotImplementedError - - @property - def cancel_called(self) -> bool: - """``True`` if :meth:`cancel` has been called.""" - raise NotImplementedError - - @property - def cancelled_caught(self) -> bool: - """ - ``True`` if this scope suppressed a cancellation exception it itself raised. - - This is typically used to check if any work was interrupted, or to see if the - scope was cancelled due to its deadline being reached. The value will, however, - only be ``True`` if the cancellation was triggered by the scope itself (and not - an outer scope). - - """ - raise NotImplementedError - - @property - def shield(self) -> bool: - """ - ``True`` if this scope is shielded from external cancellation. - - While a scope is shielded, it will not receive cancellations from outside. - - """ - raise NotImplementedError - - @shield.setter - def shield(self, value: bool) -> None: - raise NotImplementedError - - def __enter__(self) -> CancelScope: - raise NotImplementedError - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - raise NotImplementedError - - -@contextmanager -def fail_after( - delay: float | None, shield: bool = False -) -> Generator[CancelScope, None, None]: - """ - Create a context manager which raises a :class:`TimeoutError` if does not finish in - time. - - :param delay: maximum allowed time (in seconds) before raising the exception, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a context manager that yields a cancel scope - :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\] - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - current_time = get_async_backend().current_time - deadline = (current_time() + delay) if delay is not None else math.inf - with get_async_backend().create_cancel_scope( - deadline=deadline, shield=shield - ) as cancel_scope: - yield cancel_scope - - if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline: - raise TimeoutError - - -def move_on_after(delay: float | None, shield: bool = False) -> CancelScope: - """ - Create a cancel scope with a deadline that expires after the given delay. - - :param delay: maximum allowed time (in seconds) before exiting the context block, or - ``None`` to disable the timeout - :param shield: ``True`` to shield the cancel scope from external cancellation - :return: a cancel scope - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - deadline = ( - (get_async_backend().current_time() + delay) if delay is not None else math.inf - ) - return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield) - - -def current_effective_deadline() -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the current - task. - - :return: a clock value from the event loop's internal clock (or ``float('inf')`` if - there is no deadline in effect, or ``float('-inf')`` if the current scope has - been cancelled) - :rtype: float - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_effective_deadline() - - -def create_task_group() -> TaskGroup: - """ - Create a task group. - - :return: a task group - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().create_task_group() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tempfile.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tempfile.py deleted file mode 100644 index fbb6b14..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_tempfile.py +++ /dev/null @@ -1,616 +0,0 @@ -from __future__ import annotations - -import os -import sys -import tempfile -from collections.abc import Iterable -from io import BytesIO, TextIOWrapper -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - AnyStr, - Generic, - overload, -) - -from .. import to_thread -from .._core._fileio import AsyncFile -from ..lowlevel import checkpoint_if_cancelled - -if TYPE_CHECKING: - from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer - - -class TemporaryFile(Generic[AnyStr]): - """ - An asynchronous temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager interface to a temporary file. - The file is created using Python's standard `tempfile.TemporaryFile` function in a - background thread, and is wrapped as an asynchronous file using `AsyncFile`. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: TemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: TemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - mode: OpenTextMode | OpenBinaryMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self.mode = mode - self.buffering = buffering - self.encoding = encoding - self.newline = newline - self.suffix: str | None = suffix - self.prefix: str | None = prefix - self.dir: str | None = dir - self.errors = errors - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile( - self.mode, - self.buffering, - self.encoding, - self.newline, - self.suffix, - self.prefix, - self.dir, - errors=self.errors, - ) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class NamedTemporaryFile(Generic[AnyStr]): - """ - An asynchronous named temporary file that is automatically created and cleaned up. - - This class provides an asynchronous context manager for a temporary file with a - visible name in the file system. It uses Python's standard - :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with - :class:`AsyncFile` for asynchronous operations. - - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file. Only applicable in - text mode. - :param newline: Controls how universal newlines mode works (only applicable in text - mode). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param delete: Whether to delete the file when it is closed. - :param errors: The error handling scheme used for encoding/decoding errors. - :param delete_on_close: (Python 3.12+) Whether to delete the file on close. - """ - - _async_file: AsyncFile[AnyStr] - - @overload - def __init__( - self: NamedTemporaryFile[bytes], - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - @overload - def __init__( - self: NamedTemporaryFile[str], - mode: OpenTextMode, - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - delete: bool = ..., - *, - errors: str | None = ..., - delete_on_close: bool = ..., - ): ... - - def __init__( - self, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - delete: bool = True, - *, - errors: str | None = None, - delete_on_close: bool = True, - ) -> None: - self._params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "delete": delete, - "errors": errors, - } - if sys.version_info >= (3, 12): - self._params["delete_on_close"] = delete_on_close - - async def __aenter__(self) -> AsyncFile[AnyStr]: - fp = await to_thread.run_sync( - lambda: tempfile.NamedTemporaryFile(**self._params) - ) - self._async_file = AsyncFile(fp) - return self._async_file - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - await self._async_file.aclose() - - -class SpooledTemporaryFile(AsyncFile[AnyStr]): - """ - An asynchronous spooled temporary file that starts in memory and is spooled to disk. - - This class provides an asynchronous interface to a spooled temporary file, much like - Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous - write operations and provides a method to force a rollover to disk. - - :param max_size: Maximum size in bytes before the file is rolled over to disk. - :param mode: The mode in which the file is opened. Defaults to "w+b". - :param buffering: The buffering policy (-1 means the default buffering). - :param encoding: The encoding used to decode or encode the file (text mode only). - :param newline: Controls how universal newlines mode works (text mode only). - :param suffix: The suffix for the temporary file name. - :param prefix: The prefix for the temporary file name. - :param dir: The directory in which the temporary file is created. - :param errors: The error handling scheme used for encoding/decoding errors. - """ - - _rolled: bool = False - - @overload - def __init__( - self: SpooledTemporaryFile[bytes], - max_size: int = ..., - mode: OpenBinaryMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - @overload - def __init__( - self: SpooledTemporaryFile[str], - max_size: int = ..., - mode: OpenTextMode = ..., - buffering: int = ..., - encoding: str | None = ..., - newline: str | None = ..., - suffix: str | None = ..., - prefix: str | None = ..., - dir: str | None = ..., - *, - errors: str | None = ..., - ): ... - - def __init__( - self, - max_size: int = 0, - mode: OpenBinaryMode | OpenTextMode = "w+b", - buffering: int = -1, - encoding: str | None = None, - newline: str | None = None, - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - *, - errors: str | None = None, - ) -> None: - self._tempfile_params: dict[str, Any] = { - "mode": mode, - "buffering": buffering, - "encoding": encoding, - "newline": newline, - "suffix": suffix, - "prefix": prefix, - "dir": dir, - "errors": errors, - } - self._max_size = max_size - if "b" in mode: - super().__init__(BytesIO()) # type: ignore[arg-type] - else: - super().__init__( - TextIOWrapper( # type: ignore[arg-type] - BytesIO(), - encoding=encoding, - errors=errors, - newline=newline, - write_through=True, - ) - ) - - async def aclose(self) -> None: - if not self._rolled: - self._fp.close() - return - - await super().aclose() - - async def _check(self) -> None: - if self._rolled or self._fp.tell() <= self._max_size: - return - - await self.rollover() - - async def rollover(self) -> None: - if self._rolled: - return - - self._rolled = True - buffer = self._fp - buffer.seek(0) - self._fp = await to_thread.run_sync( - lambda: tempfile.TemporaryFile(**self._tempfile_params) - ) - await self.write(buffer.read()) - buffer.close() - - @property - def closed(self) -> bool: - return self._fp.closed - - async def read(self, size: int = -1) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read(size) - - return await super().read(size) # type: ignore[return-value] - - async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.read1(size) - - return await super().read1(size) - - async def readline(self) -> AnyStr: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readline() - - return await super().readline() # type: ignore[return-value] - - async def readlines(self) -> list[AnyStr]: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.readlines() - - return await super().readlines() # type: ignore[return-value] - - async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto(b) - - async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - self._fp.readinto(b) - - return await super().readinto1(b) - - async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.seek(offset, whence) - - return await super().seek(offset, whence) - - async def tell(self) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.tell() - - return await super().tell() - - async def truncate(self, size: int | None = None) -> int: - if not self._rolled: - await checkpoint_if_cancelled() - return self._fp.truncate(size) - - return await super().truncate(size) - - @overload - async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ... - @overload - async def write(self: SpooledTemporaryFile[str], b: str) -> int: ... - - async def write(self, b: ReadableBuffer | str) -> int: - """ - Asynchronously write data to the spooled temporary file. - - If the file has not yet been rolled over, the data is written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param s: The data to write. - :return: The number of bytes written. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.write(b) - await self._check() - return result - - return await super().write(b) # type: ignore[misc] - - @overload - async def writelines( - self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer] - ) -> None: ... - @overload - async def writelines( - self: SpooledTemporaryFile[str], lines: Iterable[str] - ) -> None: ... - - async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None: - """ - Asynchronously write a list of lines to the spooled temporary file. - - If the file has not yet been rolled over, the lines are written synchronously, - and a rollover is triggered if the size exceeds the maximum size. - - :param lines: An iterable of lines to write. - :raises RuntimeError: If the underlying file is not initialized. - - """ - if not self._rolled: - await checkpoint_if_cancelled() - result = self._fp.writelines(lines) - await self._check() - return result - - return await super().writelines(lines) # type: ignore[misc] - - -class TemporaryDirectory(Generic[AnyStr]): - """ - An asynchronous temporary directory that is created and cleaned up automatically. - - This class provides an asynchronous context manager for creating a temporary - directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to - perform directory creation and cleanup operations in a background thread. - - :param suffix: Suffix to be added to the temporary directory name. - :param prefix: Prefix to be added to the temporary directory name. - :param dir: The parent directory where the temporary directory is created. - :param ignore_cleanup_errors: Whether to ignore errors during cleanup - (Python 3.10+). - :param delete: Whether to delete the directory upon closing (Python 3.12+). - """ - - def __init__( - self, - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - *, - ignore_cleanup_errors: bool = False, - delete: bool = True, - ) -> None: - self.suffix: AnyStr | None = suffix - self.prefix: AnyStr | None = prefix - self.dir: AnyStr | None = dir - self.ignore_cleanup_errors = ignore_cleanup_errors - self.delete = delete - - self._tempdir: tempfile.TemporaryDirectory | None = None - - async def __aenter__(self) -> str: - params: dict[str, Any] = { - "suffix": self.suffix, - "prefix": self.prefix, - "dir": self.dir, - } - if sys.version_info >= (3, 10): - params["ignore_cleanup_errors"] = self.ignore_cleanup_errors - - if sys.version_info >= (3, 12): - params["delete"] = self.delete - - self._tempdir = await to_thread.run_sync( - lambda: tempfile.TemporaryDirectory(**params) - ) - return await to_thread.run_sync(self._tempdir.__enter__) - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, - ) -> None: - if self._tempdir is not None: - await to_thread.run_sync( - self._tempdir.__exit__, exc_type, exc_value, traceback - ) - - async def cleanup(self) -> None: - if self._tempdir is not None: - await to_thread.run_sync(self._tempdir.cleanup) - - -@overload -async def mkstemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, - text: bool = False, -) -> tuple[int, str]: ... - - -@overload -async def mkstemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, - text: bool = False, -) -> tuple[int, bytes]: ... - - -async def mkstemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, - text: bool = False, -) -> tuple[int, str | bytes]: - """ - Asynchronously create a temporary file and return an OS-level handle and the file - name. - - This function wraps `tempfile.mkstemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the file name. - :param prefix: Prefix to be added to the file name. - :param dir: Directory in which the temporary file is created. - :param text: Whether the file is opened in text mode. - :return: A tuple containing the file descriptor and the file name. - - """ - return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text) - - -@overload -async def mkdtemp( - suffix: str | None = None, - prefix: str | None = None, - dir: str | None = None, -) -> str: ... - - -@overload -async def mkdtemp( - suffix: bytes | None = None, - prefix: bytes | None = None, - dir: bytes | None = None, -) -> bytes: ... - - -async def mkdtemp( - suffix: AnyStr | None = None, - prefix: AnyStr | None = None, - dir: AnyStr | None = None, -) -> str | bytes: - """ - Asynchronously create a temporary directory and return its path. - - This function wraps `tempfile.mkdtemp` and executes it in a background thread. - - :param suffix: Suffix to be added to the directory name. - :param prefix: Prefix to be added to the directory name. - :param dir: Parent directory where the temporary directory is created. - :return: The path of the created temporary directory. - - """ - return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir) - - -async def gettempdir() -> str: - """ - Asynchronously return the name of the directory used for temporary files. - - This function wraps `tempfile.gettempdir` and executes it in a background thread. - - :return: The path of the temporary directory as a string. - - """ - return await to_thread.run_sync(tempfile.gettempdir) - - -async def gettempdirb() -> bytes: - """ - Asynchronously return the name of the directory used for temporary files in bytes. - - This function wraps `tempfile.gettempdirb` and executes it in a background thread. - - :return: The path of the temporary directory as bytes. - - """ - return await to_thread.run_sync(tempfile.gettempdirb) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_testing.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_testing.py deleted file mode 100644 index 369e65c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_testing.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import annotations - -from collections.abc import Awaitable, Generator -from typing import Any, cast - -from ._eventloop import get_async_backend - - -class TaskInfo: - """ - Represents an asynchronous task. - - :ivar int id: the unique identifier of the task - :ivar parent_id: the identifier of the parent task, if any - :vartype parent_id: Optional[int] - :ivar str name: the description of the task (if any) - :ivar ~collections.abc.Coroutine coro: the coroutine object of the task - """ - - __slots__ = "_name", "id", "parent_id", "name", "coro" - - def __init__( - self, - id: int, - parent_id: int | None, - name: str | None, - coro: Generator[Any, Any, Any] | Awaitable[Any], - ): - func = get_current_task - self._name = f"{func.__module__}.{func.__qualname__}" - self.id: int = id - self.parent_id: int | None = parent_id - self.name: str | None = name - self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro - - def __eq__(self, other: object) -> bool: - if isinstance(other, TaskInfo): - return self.id == other.id - - return NotImplemented - - def __hash__(self) -> int: - return hash(self.id) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})" - - def has_pending_cancellation(self) -> bool: - """ - Return ``True`` if the task has a cancellation pending, ``False`` otherwise. - - """ - return False - - -def get_current_task() -> TaskInfo: - """ - Return the current task. - - :return: a representation of the current task - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().get_current_task() - - -def get_running_tasks() -> list[TaskInfo]: - """ - Return a list of running tasks in the current event loop. - - :return: a list of task info objects - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return cast("list[TaskInfo]", get_async_backend().get_running_tasks()) - - -async def wait_all_tasks_blocked() -> None: - """Wait until all other tasks are waiting for something.""" - await get_async_backend().wait_all_tasks_blocked() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_typedattr.py b/backend/venv39/lib/python3.9/site-packages/anyio/_core/_typedattr.py deleted file mode 100644 index f358a44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/_core/_typedattr.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from collections.abc import Callable, Mapping -from typing import Any, TypeVar, final, overload - -from ._exceptions import TypedAttributeLookupError - -T_Attr = TypeVar("T_Attr") -T_Default = TypeVar("T_Default") -undefined = object() - - -def typed_attribute() -> Any: - """Return a unique object, used to mark typed attributes.""" - return object() - - -class TypedAttributeSet: - """ - Superclass for typed attribute collections. - - Checks that every public attribute of every subclass has a type annotation. - """ - - def __init_subclass__(cls) -> None: - annotations: dict[str, Any] = getattr(cls, "__annotations__", {}) - for attrname in dir(cls): - if not attrname.startswith("_") and attrname not in annotations: - raise TypeError( - f"Attribute {attrname!r} is missing its type annotation" - ) - - super().__init_subclass__() - - -class TypedAttributeProvider: - """Base class for classes that wish to provide typed extra attributes.""" - - @property - def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: - """ - A mapping of the extra attributes to callables that return the corresponding - values. - - If the provider wraps another provider, the attributes from that wrapper should - also be included in the returned mapping (but the wrapper may override the - callables from the wrapped instance). - - """ - return {} - - @overload - def extra(self, attribute: T_Attr) -> T_Attr: ... - - @overload - def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ... - - @final - def extra(self, attribute: Any, default: object = undefined) -> object: - """ - extra(attribute, default=undefined) - - Return the value of the given typed extra attribute. - - :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to - look for - :param default: the value that should be returned if no value is found for the - attribute - :raises ~anyio.TypedAttributeLookupError: if the search failed and no default - value was given - - """ - try: - getter = self.extra_attributes[attribute] - except KeyError: - if default is undefined: - raise TypedAttributeLookupError("Attribute not found") from None - else: - return default - - return getter() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/__init__.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/__init__.py deleted file mode 100644 index d560ce3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -from ._eventloop import AsyncBackend as AsyncBackend -from ._resources import AsyncResource as AsyncResource -from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket -from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket -from ._sockets import IPAddressType as IPAddressType -from ._sockets import IPSockAddrType as IPSockAddrType -from ._sockets import SocketAttribute as SocketAttribute -from ._sockets import SocketListener as SocketListener -from ._sockets import SocketStream as SocketStream -from ._sockets import UDPPacketType as UDPPacketType -from ._sockets import UDPSocket as UDPSocket -from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType -from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket -from ._sockets import UNIXSocketStream as UNIXSocketStream -from ._streams import AnyByteReceiveStream as AnyByteReceiveStream -from ._streams import AnyByteSendStream as AnyByteSendStream -from ._streams import AnyByteStream as AnyByteStream -from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable -from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream -from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream -from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream -from ._streams import ByteReceiveStream as ByteReceiveStream -from ._streams import ByteSendStream as ByteSendStream -from ._streams import ByteStream as ByteStream -from ._streams import ByteStreamConnectable as ByteStreamConnectable -from ._streams import Listener as Listener -from ._streams import ObjectReceiveStream as ObjectReceiveStream -from ._streams import ObjectSendStream as ObjectSendStream -from ._streams import ObjectStream as ObjectStream -from ._streams import ObjectStreamConnectable as ObjectStreamConnectable -from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream -from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream -from ._streams import UnreliableObjectStream as UnreliableObjectStream -from ._subprocesses import Process as Process -from ._tasks import TaskGroup as TaskGroup -from ._tasks import TaskStatus as TaskStatus -from ._testing import TestRunner as TestRunner - -# Re-exported here, for backwards compatibility -# isort: off -from .._core._synchronization import ( - CapacityLimiter as CapacityLimiter, - Condition as Condition, - Event as Event, - Lock as Lock, - Semaphore as Semaphore, -) -from .._core._tasks import CancelScope as CancelScope -from ..from_thread import BlockingPortal as BlockingPortal - -# Re-export imports so they look like they live directly in this package -for __value in list(locals().values()): - if getattr(__value, "__module__", "").startswith("anyio.abc."): - __value.__module__ = __name__ - -del __value diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_eventloop.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_eventloop.py deleted file mode 100644 index b1bd085..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_eventloop.py +++ /dev/null @@ -1,414 +0,0 @@ -from __future__ import annotations - -import math -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncIterator, Awaitable, Callable, Sequence -from contextlib import AbstractContextManager -from os import PathLike -from signal import Signals -from socket import AddressFamily, SocketKind, socket -from typing import ( - IO, - TYPE_CHECKING, - Any, - TypeVar, - Union, - overload, -) - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -if TYPE_CHECKING: - from _typeshed import FileDescriptorLike - - from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore - from .._core._tasks import CancelScope - from .._core._testing import TaskInfo - from ._sockets import ( - ConnectedUDPSocket, - ConnectedUNIXDatagramSocket, - IPSockAddrType, - SocketListener, - SocketStream, - UDPSocket, - UNIXDatagramSocket, - UNIXSocketStream, - ) - from ._subprocesses import Process - from ._tasks import TaskGroup - from ._testing import TestRunner - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") -StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"] - - -class AsyncBackend(metaclass=ABCMeta): - @classmethod - @abstractmethod - def run( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - options: dict[str, Any], - ) -> T_Retval: - """ - Run the given coroutine function in an asynchronous event loop. - - The current thread must not be already running an event loop. - - :param func: a coroutine function - :param args: positional arguments to ``func`` - :param kwargs: positional arguments to ``func`` - :param options: keyword arguments to call the backend ``run()`` implementation - with - :return: the return value of the coroutine function - """ - - @classmethod - @abstractmethod - def current_token(cls) -> object: - """ - Return an object that allows other threads to run code inside the event loop. - - :return: a token object, specific to the event loop running in the current - thread - """ - - @classmethod - @abstractmethod - def current_time(cls) -> float: - """ - Return the current value of the event loop's internal clock. - - :return: the clock value (seconds) - """ - - @classmethod - @abstractmethod - def cancelled_exception_class(cls) -> type[BaseException]: - """Return the exception class that is raised in a task if it's cancelled.""" - - @classmethod - @abstractmethod - async def checkpoint(cls) -> None: - """ - Check if the task has been cancelled, and allow rescheduling of other tasks. - - This is effectively the same as running :meth:`checkpoint_if_cancelled` and then - :meth:`cancel_shielded_checkpoint`. - """ - - @classmethod - async def checkpoint_if_cancelled(cls) -> None: - """ - Check if the current task group has been cancelled. - - This will check if the task has been cancelled, but will not allow other tasks - to be scheduled if not. - - """ - if cls.current_effective_deadline() == -math.inf: - await cls.checkpoint() - - @classmethod - async def cancel_shielded_checkpoint(cls) -> None: - """ - Allow the rescheduling of other tasks. - - This will give other tasks the opportunity to run, but without checking if the - current task group has been cancelled, unlike with :meth:`checkpoint`. - - """ - with cls.create_cancel_scope(shield=True): - await cls.sleep(0) - - @classmethod - @abstractmethod - async def sleep(cls, delay: float) -> None: - """ - Pause the current task for the specified duration. - - :param delay: the duration, in seconds - """ - - @classmethod - @abstractmethod - def create_cancel_scope( - cls, *, deadline: float = math.inf, shield: bool = False - ) -> CancelScope: - pass - - @classmethod - @abstractmethod - def current_effective_deadline(cls) -> float: - """ - Return the nearest deadline among all the cancel scopes effective for the - current task. - - :return: - - a clock value from the event loop's internal clock - - ``inf`` if there is no deadline in effect - - ``-inf`` if the current scope has been cancelled - :rtype: float - """ - - @classmethod - @abstractmethod - def create_task_group(cls) -> TaskGroup: - pass - - @classmethod - @abstractmethod - def create_event(cls) -> Event: - pass - - @classmethod - @abstractmethod - def create_lock(cls, *, fast_acquire: bool) -> Lock: - pass - - @classmethod - @abstractmethod - def create_semaphore( - cls, - initial_value: int, - *, - max_value: int | None = None, - fast_acquire: bool = False, - ) -> Semaphore: - pass - - @classmethod - @abstractmethod - def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - async def run_sync_in_worker_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - abandon_on_cancel: bool = False, - limiter: CapacityLimiter | None = None, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - def check_cancelled(cls) -> None: - pass - - @classmethod - @abstractmethod - def run_async_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - def run_sync_from_thread( - cls, - func: Callable[[Unpack[PosArgsT]], T_Retval], - args: tuple[Unpack[PosArgsT]], - token: object, - ) -> T_Retval: - pass - - @classmethod - @abstractmethod - async def open_process( - cls, - command: StrOrBytesPath | Sequence[StrOrBytesPath], - *, - stdin: int | IO[Any] | None, - stdout: int | IO[Any] | None, - stderr: int | IO[Any] | None, - **kwargs: Any, - ) -> Process: - pass - - @classmethod - @abstractmethod - def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None: - pass - - @classmethod - @abstractmethod - async def connect_tcp( - cls, host: str, port: int, local_address: IPSockAddrType | None = None - ) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - def create_tcp_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - def create_unix_listener(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def create_udp_socket( - cls, - family: AddressFamily, - local_address: IPSockAddrType | None, - remote_address: IPSockAddrType | None, - reuse_port: bool, - ) -> UDPSocket | ConnectedUDPSocket: - pass - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: None - ) -> UNIXDatagramSocket: ... - - @classmethod - @overload - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes - ) -> ConnectedUNIXDatagramSocket: ... - - @classmethod - @abstractmethod - async def create_unix_datagram_socket( - cls, raw_socket: socket, remote_path: str | bytes | None - ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def getaddrinfo( - cls, - host: bytes | str | None, - port: str | int | None, - *, - family: int | AddressFamily = 0, - type: int | SocketKind = 0, - proto: int = 0, - flags: int = 0, - ) -> Sequence[ - tuple[ - AddressFamily, - SocketKind, - int, - str, - tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], - ] - ]: - pass - - @classmethod - @abstractmethod - async def getnameinfo( - cls, sockaddr: IPSockAddrType, flags: int = 0 - ) -> tuple[str, str]: - pass - - @classmethod - @abstractmethod - async def wait_readable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wait_writable(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - def notify_closing(cls, obj: FileDescriptorLike) -> None: - pass - - @classmethod - @abstractmethod - async def wrap_listener_socket(cls, sock: socket) -> SocketListener: - pass - - @classmethod - @abstractmethod - async def wrap_stream_socket(cls, sock: socket) -> SocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream: - pass - - @classmethod - @abstractmethod - async def wrap_udp_socket(cls, sock: socket) -> UDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket: - pass - - @classmethod - @abstractmethod - async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - async def wrap_connected_unix_datagram_socket( - cls, sock: socket - ) -> ConnectedUNIXDatagramSocket: - pass - - @classmethod - @abstractmethod - def current_default_thread_limiter(cls) -> CapacityLimiter: - pass - - @classmethod - @abstractmethod - def open_signal_receiver( - cls, *signals: Signals - ) -> AbstractContextManager[AsyncIterator[Signals]]: - pass - - @classmethod - @abstractmethod - def get_current_task(cls) -> TaskInfo: - pass - - @classmethod - @abstractmethod - def get_running_tasks(cls) -> Sequence[TaskInfo]: - pass - - @classmethod - @abstractmethod - async def wait_all_tasks_blocked(cls) -> None: - pass - - @classmethod - @abstractmethod - def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_resources.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_resources.py deleted file mode 100644 index 10df115..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_resources.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -from abc import ABCMeta, abstractmethod -from types import TracebackType -from typing import TypeVar - -T = TypeVar("T") - - -class AsyncResource(metaclass=ABCMeta): - """ - Abstract base class for all closeable asynchronous resources. - - Works as an asynchronous context manager which returns the instance itself on enter, - and calls :meth:`aclose` on exit. - """ - - __slots__ = () - - async def __aenter__(self: T) -> T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.aclose() - - @abstractmethod - async def aclose(self) -> None: - """Close the resource.""" diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_sockets.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_sockets.py deleted file mode 100644 index 3ff60d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_sockets.py +++ /dev/null @@ -1,405 +0,0 @@ -from __future__ import annotations - -import errno -import socket -import sys -from abc import abstractmethod -from collections.abc import Callable, Collection, Mapping -from contextlib import AsyncExitStack -from io import IOBase -from ipaddress import IPv4Address, IPv6Address -from socket import AddressFamily -from typing import Any, TypeVar, Union - -from .._core._eventloop import get_async_backend -from .._core._typedattr import ( - TypedAttributeProvider, - TypedAttributeSet, - typed_attribute, -) -from ._streams import ByteStream, Listener, UnreliableObjectStream -from ._tasks import TaskGroup - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -IPAddressType: TypeAlias = Union[str, IPv4Address, IPv6Address] -IPSockAddrType: TypeAlias = tuple[str, int] -SockAddrType: TypeAlias = Union[IPSockAddrType, str] -UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType] -UNIXDatagramPacketType: TypeAlias = tuple[bytes, str] -T_Retval = TypeVar("T_Retval") - - -def _validate_socket( - sock_or_fd: socket.socket | int, - sock_type: socket.SocketKind, - addr_family: socket.AddressFamily = socket.AF_UNSPEC, - *, - require_connected: bool = False, - require_bound: bool = False, -) -> socket.socket: - if isinstance(sock_or_fd, int): - try: - sock = socket.socket(fileno=sock_or_fd) - except OSError as exc: - if exc.errno == errno.ENOTSOCK: - raise ValueError( - "the file descriptor does not refer to a socket" - ) from exc - elif require_connected: - raise ValueError("the socket must be connected") from exc - elif require_bound: - raise ValueError("the socket must be bound to a local address") from exc - else: - raise - elif isinstance(sock_or_fd, socket.socket): - sock = sock_or_fd - else: - raise TypeError( - f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead" - ) - - try: - if require_connected: - try: - sock.getpeername() - except OSError as exc: - raise ValueError("the socket must be connected") from exc - - if require_bound: - try: - if sock.family in (socket.AF_INET, socket.AF_INET6): - bound_addr = sock.getsockname()[1] - else: - bound_addr = sock.getsockname() - except OSError: - bound_addr = None - - if not bound_addr: - raise ValueError("the socket must be bound to a local address") - - if addr_family != socket.AF_UNSPEC and sock.family != addr_family: - raise ValueError( - f"address family mismatch: expected {addr_family.name}, got " - f"{sock.family.name}" - ) - - if sock.type != sock_type: - raise ValueError( - f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}" - ) - except BaseException: - # Avoid ResourceWarning from the locally constructed socket object - if isinstance(sock_or_fd, int): - sock.detach() - - raise - - sock.setblocking(False) - return sock - - -class SocketAttribute(TypedAttributeSet): - """ - .. attribute:: family - :type: socket.AddressFamily - - the address family of the underlying socket - - .. attribute:: local_address - :type: tuple[str, int] | str - - the local address the underlying socket is connected to - - .. attribute:: local_port - :type: int - - for IP based sockets, the local port the underlying socket is bound to - - .. attribute:: raw_socket - :type: socket.socket - - the underlying stdlib socket object - - .. attribute:: remote_address - :type: tuple[str, int] | str - - the remote address the underlying socket is connected to - - .. attribute:: remote_port - :type: int - - for IP based sockets, the remote port the underlying socket is connected to - """ - - family: AddressFamily = typed_attribute() - local_address: SockAddrType = typed_attribute() - local_port: int = typed_attribute() - raw_socket: socket.socket = typed_attribute() - remote_address: SockAddrType = typed_attribute() - remote_port: int = typed_attribute() - - -class _SocketProvider(TypedAttributeProvider): - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - from .._core._sockets import convert_ipv6_sockaddr as convert - - attributes: dict[Any, Callable[[], Any]] = { - SocketAttribute.family: lambda: self._raw_socket.family, - SocketAttribute.local_address: lambda: convert( - self._raw_socket.getsockname() - ), - SocketAttribute.raw_socket: lambda: self._raw_socket, - } - try: - peername: tuple[str, int] | None = convert(self._raw_socket.getpeername()) - except OSError: - peername = None - - # Provide the remote address for connected sockets - if peername is not None: - attributes[SocketAttribute.remote_address] = lambda: peername - - # Provide local and remote ports for IP based sockets - if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6): - attributes[SocketAttribute.local_port] = ( - lambda: self._raw_socket.getsockname()[1] - ) - if peername is not None: - remote_port = peername[1] - attributes[SocketAttribute.remote_port] = lambda: remote_port - - return attributes - - @property - @abstractmethod - def _raw_socket(self) -> socket.socket: - pass - - -class SocketStream(ByteStream, _SocketProvider): - """ - Transports bytes over a socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream: - """ - Wrap an existing socket object or file descriptor as a socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket stream - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True) - return await get_async_backend().wrap_stream_socket(sock) - - -class UNIXSocketStream(SocketStream): - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream: - """ - Wrap an existing socket object or file descriptor as a UNIX socket stream. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX socket stream - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_unix_stream_socket(sock) - - @abstractmethod - async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: - """ - Send file descriptors along with a message to the peer. - - :param message: a non-empty bytestring - :param fds: a collection of files (either numeric file descriptors or open file - or socket objects) - """ - - @abstractmethod - async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: - """ - Receive file descriptors along with a message from the peer. - - :param msglen: length of the message to expect from the peer - :param maxfds: maximum number of file descriptors to expect from the peer - :return: a tuple of (message, file descriptors) - """ - - -class SocketListener(Listener[SocketStream], _SocketProvider): - """ - Listens to incoming socket connections. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> SocketListener: - """ - Wrap an existing socket object or file descriptor as a socket listener. - - The newly created listener takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a socket listener - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True) - return await get_async_backend().wrap_listener_socket(sock) - - @abstractmethod - async def accept(self) -> SocketStream: - """Accept an incoming connection.""" - - async def serve( - self, - handler: Callable[[SocketStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - from .. import create_task_group - - async with AsyncExitStack() as stack: - if task_group is None: - task_group = await stack.enter_async_context(create_task_group()) - - while True: - stream = await self.accept() - task_group.start_soon(handler, stream) - - -class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider): - """ - Represents an unconnected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket: - """ - Wrap an existing socket object or file descriptor as a UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must be bound to a local address. - - :param sock_or_fd: a socket object or file descriptor - :return: a UDP socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True) - return await get_async_backend().wrap_udp_socket(sock) - - async def sendto(self, data: bytes, host: str, port: int) -> None: - """ - Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))). - - """ - return await self.send((data, (host, port))) - - -class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents an connected UDP socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket: - """ - Wrap an existing socket object or file descriptor as a connected UDP socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UDP socket - - """ - sock = _validate_socket( - sock_or_fd, - socket.SOCK_DGRAM, - require_connected=True, - ) - return await get_async_backend().wrap_connected_udp_socket(sock) - - -class UNIXDatagramSocket( - UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider -): - """ - Represents an unconnected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> UNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - - :param sock_or_fd: a socket object or file descriptor - :return: a UNIX datagram socket - - """ - sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX) - return await get_async_backend().wrap_unix_datagram_socket(sock) - - async def sendto(self, data: bytes, path: str) -> None: - """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path)).""" - return await self.send((data, path)) - - -class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider): - """ - Represents a connected Unix datagram socket. - - Supports all relevant extra attributes from :class:`~SocketAttribute`. - """ - - @classmethod - async def from_socket( - cls, - sock_or_fd: socket.socket | int, - ) -> ConnectedUNIXDatagramSocket: - """ - Wrap an existing socket object or file descriptor as a connected UNIX datagram - socket. - - The newly created socket wrapper takes ownership of the socket being passed in. - The existing socket must already be connected. - - :param sock_or_fd: a socket object or file descriptor - :return: a connected UNIX datagram socket - - """ - sock = _validate_socket( - sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True - ) - return await get_async_backend().wrap_connected_unix_datagram_socket(sock) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_streams.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_streams.py deleted file mode 100644 index 369df3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_streams.py +++ /dev/null @@ -1,239 +0,0 @@ -from __future__ import annotations - -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import Callable -from typing import Any, Generic, TypeVar, Union - -from .._core._exceptions import EndOfStream -from .._core._typedattr import TypedAttributeProvider -from ._resources import AsyncResource -from ._tasks import TaskGroup - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class UnreliableObjectReceiveStream( - Generic[T_co], AsyncResource, TypedAttributeProvider -): - """ - An interface for receiving objects. - - This interface makes no guarantees that the received messages arrive in the order in - which they were sent, or that no messages are missed. - - Asynchronously iterating over objects of this type will yield objects matching the - given type parameter. - """ - - def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]: - return self - - async def __anext__(self) -> T_co: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self) -> T_co: - """ - Receive the next item. - - :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly - closed - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectSendStream( - Generic[T_contra], AsyncResource, TypedAttributeProvider -): - """ - An interface for sending objects. - - This interface makes no guarantees that the messages sent will reach the - recipient(s) in the same order in which they were sent, or at all. - """ - - @abstractmethod - async def send(self, item: T_contra) -> None: - """ - Send an item to the peer(s). - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if the send stream has been explicitly - closed - :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable - due to external causes - """ - - -class UnreliableObjectStream( - UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item] -): - """ - A bidirectional message stream which does not guarantee the order or reliability of - message delivery. - """ - - -class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]): - """ - A receive message stream which guarantees that messages are received in the same - order in which they were sent, and that no messages are missed. - """ - - -class ObjectSendStream(UnreliableObjectSendStream[T_contra]): - """ - A send message stream which guarantees that messages are delivered in the same order - in which they were sent, without missing any messages in the middle. - """ - - -class ObjectStream( - ObjectReceiveStream[T_Item], - ObjectSendStream[T_Item], - UnreliableObjectStream[T_Item], -): - """ - A bidirectional message stream which guarantees the order and reliability of message - delivery. - """ - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -class ByteReceiveStream(AsyncResource, TypedAttributeProvider): - """ - An interface for receiving bytes from a single peer. - - Iterating this byte stream will yield a byte string of arbitrary length, but no more - than 65536 bytes. - """ - - def __aiter__(self) -> ByteReceiveStream: - return self - - async def __anext__(self) -> bytes: - try: - return await self.receive() - except EndOfStream: - raise StopAsyncIteration from None - - @abstractmethod - async def receive(self, max_bytes: int = 65536) -> bytes: - """ - Receive at most ``max_bytes`` bytes from the peer. - - .. note:: Implementers of this interface should not return an empty - :class:`bytes` object, and users should ignore them. - - :param max_bytes: maximum number of bytes to receive - :return: the received bytes - :raises ~anyio.EndOfStream: if this stream has been closed from the other end - """ - - -class ByteSendStream(AsyncResource, TypedAttributeProvider): - """An interface for sending bytes to a single peer.""" - - @abstractmethod - async def send(self, item: bytes) -> None: - """ - Send the given bytes to the peer. - - :param item: the bytes to send - """ - - -class ByteStream(ByteReceiveStream, ByteSendStream): - """A bidirectional byte stream.""" - - @abstractmethod - async def send_eof(self) -> None: - """ - Send an end-of-file indication to the peer. - - You should not try to send any further data to this stream after calling this - method. This method is idempotent (does nothing on successive calls). - """ - - -#: Type alias for all unreliable bytes-oriented receive streams. -AnyUnreliableByteReceiveStream: TypeAlias = Union[ - UnreliableObjectReceiveStream[bytes], ByteReceiveStream -] -#: Type alias for all unreliable bytes-oriented send streams. -AnyUnreliableByteSendStream: TypeAlias = Union[ - UnreliableObjectSendStream[bytes], ByteSendStream -] -#: Type alias for all unreliable bytes-oriented streams. -AnyUnreliableByteStream: TypeAlias = Union[UnreliableObjectStream[bytes], ByteStream] -#: Type alias for all bytes-oriented receive streams. -AnyByteReceiveStream: TypeAlias = Union[ObjectReceiveStream[bytes], ByteReceiveStream] -#: Type alias for all bytes-oriented send streams. -AnyByteSendStream: TypeAlias = Union[ObjectSendStream[bytes], ByteSendStream] -#: Type alias for all bytes-oriented streams. -AnyByteStream: TypeAlias = Union[ObjectStream[bytes], ByteStream] - - -class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider): - """An interface for objects that let you accept incoming connections.""" - - @abstractmethod - async def serve( - self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None - ) -> None: - """ - Accept incoming connections as they come in and start tasks to handle them. - - :param handler: a callable that will be used to handle each accepted connection - :param task_group: the task group that will be used to start tasks for handling - each accepted connection (if omitted, an ad-hoc task group will be created) - """ - - -class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ObjectStream[T_co]: - """ - Connect to the remote endpoint. - - :return: an object stream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -class ByteStreamConnectable(metaclass=ABCMeta): - @abstractmethod - async def connect(self) -> ByteStream: - """ - Connect to the remote endpoint. - - :return: a bytestream connected to the remote end - :raises ConnectionFailed: if the connection fails - """ - - -#: Type alias for all connectables returning bytestreams or bytes-oriented object streams -AnyByteStreamConnectable: TypeAlias = Union[ - ObjectStreamConnectable[bytes], ByteStreamConnectable -] diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_subprocesses.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_subprocesses.py deleted file mode 100644 index ce0564c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_subprocesses.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from signal import Signals - -from ._resources import AsyncResource -from ._streams import ByteReceiveStream, ByteSendStream - - -class Process(AsyncResource): - """An asynchronous version of :class:`subprocess.Popen`.""" - - @abstractmethod - async def wait(self) -> int: - """ - Wait until the process exits. - - :return: the exit code of the process - """ - - @abstractmethod - def terminate(self) -> None: - """ - Terminates the process, gracefully if possible. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGTERM`` to the process. - - .. seealso:: :meth:`subprocess.Popen.terminate` - """ - - @abstractmethod - def kill(self) -> None: - """ - Kills the process. - - On Windows, this calls ``TerminateProcess()``. - On POSIX systems, this sends ``SIGKILL`` to the process. - - .. seealso:: :meth:`subprocess.Popen.kill` - """ - - @abstractmethod - def send_signal(self, signal: Signals) -> None: - """ - Send a signal to the subprocess. - - .. seealso:: :meth:`subprocess.Popen.send_signal` - - :param signal: the signal number (e.g. :data:`signal.SIGHUP`) - """ - - @property - @abstractmethod - def pid(self) -> int: - """The process ID of the process.""" - - @property - @abstractmethod - def returncode(self) -> int | None: - """ - The return code of the process. If the process has not yet terminated, this will - be ``None``. - """ - - @property - @abstractmethod - def stdin(self) -> ByteSendStream | None: - """The stream for the standard input of the process.""" - - @property - @abstractmethod - def stdout(self) -> ByteReceiveStream | None: - """The stream for the standard output of the process.""" - - @property - @abstractmethod - def stderr(self) -> ByteReceiveStream | None: - """The stream for the standard error output of the process.""" diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_tasks.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_tasks.py deleted file mode 100644 index 516b3ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_tasks.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -import sys -from abc import ABCMeta, abstractmethod -from collections.abc import Awaitable, Callable -from types import TracebackType -from typing import TYPE_CHECKING, Any, Protocol, overload - -if sys.version_info >= (3, 13): - from typing import TypeVar -else: - from typing_extensions import TypeVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if TYPE_CHECKING: - from .._core._tasks import CancelScope - -T_Retval = TypeVar("T_Retval") -T_contra = TypeVar("T_contra", contravariant=True, default=None) -PosArgsT = TypeVarTuple("PosArgsT") - - -class TaskStatus(Protocol[T_contra]): - @overload - def started(self: TaskStatus[None]) -> None: ... - - @overload - def started(self, value: T_contra) -> None: ... - - def started(self, value: T_contra | None = None) -> None: - """ - Signal that the task has started. - - :param value: object passed back to the starter of the task - """ - - -class TaskGroup(metaclass=ABCMeta): - """ - Groups several asynchronous tasks together. - - :ivar cancel_scope: the cancel scope inherited by all child tasks - :vartype cancel_scope: CancelScope - - .. note:: On asyncio, support for eager task factories is considered to be - **experimental**. In particular, they don't follow the usual semantics of new - tasks being scheduled on the next iteration of the event loop, and may thus - cause unexpected behavior in code that wasn't written with such semantics in - mind. - """ - - cancel_scope: CancelScope - - @abstractmethod - def start_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[Any]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> None: - """ - Start a new task in this task group. - - :param func: a coroutine function - :param args: positional arguments to call the function with - :param name: name of the task, for the purposes of introspection and debugging - - .. versionadded:: 3.0 - """ - - @abstractmethod - async def start( - self, - func: Callable[..., Awaitable[Any]], - *args: object, - name: object = None, - ) -> Any: - """ - Start a new task and wait until it signals for readiness. - - The target callable must accept a keyword argument ``task_status`` (of type - :class:`TaskStatus`). Awaiting on this method will return whatever was passed to - ``task_status.started()`` (``None`` by default). - - .. note:: The :class:`TaskStatus` class is generic, and the type argument should - indicate the type of the value that will be passed to - ``task_status.started()``. - - :param func: a coroutine function that accepts the ``task_status`` keyword - argument - :param args: positional arguments to call the function with - :param name: an optional name for the task, for introspection and debugging - :return: the value passed to ``task_status.started()`` - :raises RuntimeError: if the task finishes without calling - ``task_status.started()`` - - .. seealso:: :ref:`start_initialize` - - .. versionadded:: 3.0 - """ - - @abstractmethod - async def __aenter__(self) -> TaskGroup: - """Enter the task group context and allow starting new tasks.""" - - @abstractmethod - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - """Exit the task group context waiting for all tasks to finish.""" diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_testing.py b/backend/venv39/lib/python3.9/site-packages/anyio/abc/_testing.py deleted file mode 100644 index 7c50ed7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/abc/_testing.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -import types -from abc import ABCMeta, abstractmethod -from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable -from typing import Any, TypeVar - -_T = TypeVar("_T") - - -class TestRunner(metaclass=ABCMeta): - """ - Encapsulates a running event loop. Every call made through this object will use the - same event loop. - """ - - def __enter__(self) -> TestRunner: - return self - - @abstractmethod - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: types.TracebackType | None, - ) -> bool | None: ... - - @abstractmethod - def run_asyncgen_fixture( - self, - fixture_func: Callable[..., AsyncGenerator[_T, Any]], - kwargs: dict[str, Any], - ) -> Iterable[_T]: - """ - Run an async generator fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: an iterator yielding the value yielded from the async generator - """ - - @abstractmethod - def run_fixture( - self, - fixture_func: Callable[..., Coroutine[Any, Any, _T]], - kwargs: dict[str, Any], - ) -> _T: - """ - Run an async fixture. - - :param fixture_func: the fixture function - :param kwargs: keyword arguments to call the fixture function with - :return: the return value of the fixture function - """ - - @abstractmethod - def run_test( - self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] - ) -> None: - """ - Run an async test function. - - :param test_func: the test function - :param kwargs: keyword arguments to call the test function with - """ diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/from_thread.py b/backend/venv39/lib/python3.9/site-packages/anyio/from_thread.py deleted file mode 100644 index 837de5e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/from_thread.py +++ /dev/null @@ -1,578 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BlockingPortal", - "BlockingPortalProvider", - "check_cancelled", - "run", - "run_sync", - "start_blocking_portal", -) - -import sys -from collections.abc import Awaitable, Callable, Generator -from concurrent.futures import Future -from contextlib import ( - AbstractAsyncContextManager, - AbstractContextManager, - contextmanager, -) -from dataclasses import dataclass, field -from functools import partial -from inspect import isawaitable -from threading import Lock, Thread, current_thread, get_ident -from types import TracebackType -from typing import ( - Any, - Generic, - TypeVar, - cast, - overload, -) - -from ._core._eventloop import ( - get_cancelled_exc_class, - threadlocals, -) -from ._core._eventloop import run as run_eventloop -from ._core._exceptions import NoEventLoopError -from ._core._synchronization import Event -from ._core._tasks import CancelScope, create_task_group -from .abc._tasks import TaskStatus -from .lowlevel import EventLoopToken, current_token - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -T_co = TypeVar("T_co", covariant=True) -PosArgsT = TypeVarTuple("PosArgsT") - - -def _token_or_error(token: EventLoopToken | None) -> EventLoopToken: - if token is not None: - return token - - try: - return threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "Not running inside an AnyIO worker thread, and no event loop token was " - "provided" - ) from None - - -def run( - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_Retval: - """ - Call a coroutine function from a worker thread. - - :param func: a coroutine function - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the coroutine function - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_async_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - token: EventLoopToken | None = None, -) -> T_Retval: - """ - Call a function in the event loop thread from a worker thread. - - :param func: a callable - :param args: positional arguments for the callable - :param token: an event loop token to use to get back to the event loop thread - (required if calling this function from outside an AnyIO worker thread) - :return: the return value of the callable - :raises MissingTokenError: if no token was provided and called from outside an - AnyIO worker thread - :raises RunFinishedError: if the event loop tied to ``token`` is no longer running - - .. versionchanged:: 4.11.0 - Added the ``token`` parameter. - - """ - explicit_token = token is not None - token = _token_or_error(token) - return token.backend_class.run_sync_from_thread( - func, args, token=token.native_token if explicit_token else None - ) - - -class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager): - _enter_future: Future[T_co] - _exit_future: Future[bool | None] - _exit_event: Event - _exit_exc_info: tuple[ - type[BaseException] | None, BaseException | None, TracebackType | None - ] = (None, None, None) - - def __init__( - self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal - ): - self._async_cm = async_cm - self._portal = portal - - async def run_async_cm(self) -> bool | None: - try: - self._exit_event = Event() - value = await self._async_cm.__aenter__() - except BaseException as exc: - self._enter_future.set_exception(exc) - raise - else: - self._enter_future.set_result(value) - - try: - # Wait for the sync context manager to exit. - # This next statement can raise `get_cancelled_exc_class()` if - # something went wrong in a task group in this async context - # manager. - await self._exit_event.wait() - finally: - # In case of cancellation, it could be that we end up here before - # `_BlockingAsyncContextManager.__exit__` is called, and an - # `_exit_exc_info` has been set. - result = await self._async_cm.__aexit__(*self._exit_exc_info) - - return result - - def __enter__(self) -> T_co: - self._enter_future = Future() - self._exit_future = self._portal.start_task_soon(self.run_async_cm) - return self._enter_future.result() - - def __exit__( - self, - __exc_type: type[BaseException] | None, - __exc_value: BaseException | None, - __traceback: TracebackType | None, - ) -> bool | None: - self._exit_exc_info = __exc_type, __exc_value, __traceback - self._portal.call(self._exit_event.set) - return self._exit_future.result() - - -class _BlockingPortalTaskStatus(TaskStatus): - def __init__(self, future: Future): - self._future = future - - def started(self, value: object = None) -> None: - self._future.set_result(value) - - -class BlockingPortal: - """ - An object that lets external threads run code in an asynchronous event loop. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - """ - - def __init__(self) -> None: - self._token = current_token() - self._event_loop_thread_id: int | None = get_ident() - self._stop_event = Event() - self._task_group = create_task_group() - - async def __aenter__(self) -> BlockingPortal: - await self._task_group.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> bool: - await self.stop() - return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) - - def _check_running(self) -> None: - if self._event_loop_thread_id is None: - raise RuntimeError("This portal is not running") - if self._event_loop_thread_id == get_ident(): - raise RuntimeError( - "This method cannot be called from the event loop thread" - ) - - async def sleep_until_stopped(self) -> None: - """Sleep until :meth:`stop` is called.""" - await self._stop_event.wait() - - async def stop(self, cancel_remaining: bool = False) -> None: - """ - Signal the portal to shut down. - - This marks the portal as no longer accepting new calls and exits from - :meth:`sleep_until_stopped`. - - :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False`` - to let them finish before returning - - """ - self._event_loop_thread_id = None - self._stop_event.set() - if cancel_remaining: - self._task_group.cancel_scope.cancel("the blocking portal is shutting down") - - async def _call_func( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - future: Future[T_Retval], - ) -> None: - def callback(f: Future[T_Retval]) -> None: - if f.cancelled(): - if self._event_loop_thread_id == get_ident(): - scope.cancel("the future was cancelled") - elif self._event_loop_thread_id is not None: - self.call(scope.cancel, "the future was cancelled") - - try: - retval_or_awaitable = func(*args, **kwargs) - if isawaitable(retval_or_awaitable): - with CancelScope() as scope: - future.add_done_callback(callback) - retval = await retval_or_awaitable - else: - retval = retval_or_awaitable - except get_cancelled_exc_class(): - future.cancel() - future.set_running_or_notify_cancel() - except BaseException as exc: - if not future.cancelled(): - future.set_exception(exc) - - # Let base exceptions fall through - if not isinstance(exc, Exception): - raise - else: - if not future.cancelled(): - future.set_result(retval) - finally: - scope = None # type: ignore[assignment] - - def _spawn_task_from_thread( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - args: tuple[Unpack[PosArgsT]], - kwargs: dict[str, Any], - name: object, - future: Future[T_Retval], - ) -> None: - """ - Spawn a new task using the given callable. - - :param func: a callable - :param args: positional arguments to be passed to the callable - :param kwargs: keyword arguments to be passed to the callable - :param name: name of the task (will be coerced to a string if not ``None``) - :param future: a future that will resolve to the return value of the callable, - or the exception raised during its execution - - """ - run_sync( - partial(self._task_group.start_soon, name=name), - self._call_func, - func, - args, - kwargs, - future, - token=self._token, - ) - - @overload - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - ) -> T_Retval: ... - - @overload - def call( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: ... - - def call( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - ) -> T_Retval: - """ - Call the given function in the event loop thread. - - If the callable returns a coroutine object, it is awaited on. - - :param func: any callable - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - - """ - return cast(T_Retval, self.start_task_soon(func, *args).result()) - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - @overload - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: ... - - def start_task_soon( - self, - func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], - *args: Unpack[PosArgsT], - name: object = None, - ) -> Future[T_Retval]: - """ - Start a task in the portal's task group. - - The task will be run inside a cancel scope which can be cancelled by cancelling - the returned future. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a future that resolves with the return value of the callable if the - task completes successfully, or with the exception raised in the task - :raises RuntimeError: if the portal is not running or if this method is called - from within the event loop thread - :rtype: concurrent.futures.Future[T_Retval] - - .. versionadded:: 3.0 - - """ - self._check_running() - f: Future[T_Retval] = Future() - self._spawn_task_from_thread(func, args, {}, name, f) - return f - - def start_task( - self, - func: Callable[..., Awaitable[T_Retval]], - *args: object, - name: object = None, - ) -> tuple[Future[T_Retval], Any]: - """ - Start a task in the portal's task group and wait until it signals for readiness. - - This method works the same way as :meth:`.abc.TaskGroup.start`. - - :param func: the target function - :param args: positional arguments passed to ``func`` - :param name: name of the task (will be coerced to a string if not ``None``) - :return: a tuple of (future, task_status_value) where the ``task_status_value`` - is the value passed to ``task_status.started()`` from within the target - function - :rtype: tuple[concurrent.futures.Future[T_Retval], Any] - - .. versionadded:: 3.0 - - """ - - def task_done(future: Future[T_Retval]) -> None: - if not task_status_future.done(): - if future.cancelled(): - task_status_future.cancel() - elif future.exception(): - task_status_future.set_exception(future.exception()) - else: - exc = RuntimeError( - "Task exited without calling task_status.started()" - ) - task_status_future.set_exception(exc) - - self._check_running() - task_status_future: Future = Future() - task_status = _BlockingPortalTaskStatus(task_status_future) - f: Future = Future() - f.add_done_callback(task_done) - self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f) - return f, task_status_future.result() - - def wrap_async_context_manager( - self, cm: AbstractAsyncContextManager[T_co] - ) -> AbstractContextManager[T_co]: - """ - Wrap an async context manager as a synchronous context manager via this portal. - - Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping - in the middle until the synchronous context manager exits. - - :param cm: an asynchronous context manager - :return: a synchronous context manager - - .. versionadded:: 2.1 - - """ - return _BlockingAsyncContextManager(cm, self) - - -@dataclass -class BlockingPortalProvider: - """ - A manager for a blocking portal. Used as a context manager. The first thread to - enter this context manager causes a blocking portal to be started with the specific - parameters, and the last thread to exit causes the portal to be shut down. Thus, - there will be exactly one blocking portal running in this context as long as at - least one thread has entered this context manager. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - - .. versionadded:: 4.4 - """ - - backend: str = "asyncio" - backend_options: dict[str, Any] | None = None - _lock: Lock = field(init=False, default_factory=Lock) - _leases: int = field(init=False, default=0) - _portal: BlockingPortal = field(init=False) - _portal_cm: AbstractContextManager[BlockingPortal] | None = field( - init=False, default=None - ) - - def __enter__(self) -> BlockingPortal: - with self._lock: - if self._portal_cm is None: - self._portal_cm = start_blocking_portal( - self.backend, self.backend_options - ) - self._portal = self._portal_cm.__enter__() - - self._leases += 1 - return self._portal - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - portal_cm: AbstractContextManager[BlockingPortal] | None = None - with self._lock: - assert self._portal_cm - assert self._leases > 0 - self._leases -= 1 - if not self._leases: - portal_cm = self._portal_cm - self._portal_cm = None - del self._portal - - if portal_cm: - portal_cm.__exit__(None, None, None) - - -@contextmanager -def start_blocking_portal( - backend: str = "asyncio", - backend_options: dict[str, Any] | None = None, - *, - name: str | None = None, -) -> Generator[BlockingPortal, Any, None]: - """ - Start a new event loop in a new thread and run a blocking portal in its main task. - - The parameters are the same as for :func:`~anyio.run`. - - :param backend: name of the backend - :param backend_options: backend options - :param name: name of the thread - :return: a context manager that yields a blocking portal - - .. versionchanged:: 3.0 - Usage as a context manager is now required. - - """ - - async def run_portal() -> None: - async with BlockingPortal() as portal_: - if name is None: - current_thread().name = f"{backend}-portal-{id(portal_):x}" - - future.set_result(portal_) - await portal_.sleep_until_stopped() - - def run_blocking_portal() -> None: - if future.set_running_or_notify_cancel(): - try: - run_eventloop( - run_portal, backend=backend, backend_options=backend_options - ) - except BaseException as exc: - if not future.done(): - future.set_exception(exc) - - future: Future[BlockingPortal] = Future() - thread = Thread(target=run_blocking_portal, daemon=True, name=name) - thread.start() - try: - cancel_remaining_tasks = False - portal = future.result() - try: - yield portal - except BaseException: - cancel_remaining_tasks = True - raise - finally: - try: - portal.call(portal.stop, cancel_remaining_tasks) - except RuntimeError: - pass - finally: - thread.join() - - -def check_cancelled() -> None: - """ - Check if the cancel scope of the host task's running the current worker thread has - been cancelled. - - If the host task's current cancel scope has indeed been cancelled, the - backend-specific cancellation exception will be raised. - - :raises RuntimeError: if the current thread was not spawned by - :func:`.to_thread.run_sync` - - """ - try: - token: EventLoopToken = threadlocals.current_token - except AttributeError: - raise NoEventLoopError( - "This function can only be called inside an AnyIO worker thread" - ) from None - - token.backend_class.check_cancelled() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/functools.py b/backend/venv39/lib/python3.9/site-packages/anyio/functools.py deleted file mode 100644 index b80afe6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/functools.py +++ /dev/null @@ -1,375 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "AsyncCacheInfo", - "AsyncCacheParameters", - "AsyncLRUCacheWrapper", - "cache", - "lru_cache", - "reduce", -) - -import functools -import sys -from collections import OrderedDict -from collections.abc import ( - AsyncIterable, - Awaitable, - Callable, - Coroutine, - Hashable, - Iterable, -) -from functools import update_wrapper -from inspect import iscoroutinefunction -from typing import ( - Any, - Generic, - NamedTuple, - TypedDict, - TypeVar, - cast, - final, - overload, -) -from weakref import WeakKeyDictionary - -from ._core._synchronization import Lock -from .lowlevel import RunVar, checkpoint - -if sys.version_info >= (3, 11): - from typing import ParamSpec -else: - from typing_extensions import ParamSpec - -T = TypeVar("T") -S = TypeVar("S") -P = ParamSpec("P") -lru_cache_items: RunVar[ - WeakKeyDictionary[ - AsyncLRUCacheWrapper[Any, Any], - OrderedDict[Hashable, tuple[_InitialMissingType, Lock] | tuple[Any, None]], - ] -] = RunVar("lru_cache_items") - - -class _InitialMissingType: - pass - - -initial_missing: _InitialMissingType = _InitialMissingType() - - -class AsyncCacheInfo(NamedTuple): - hits: int - misses: int - maxsize: int | None - currsize: int - - -class AsyncCacheParameters(TypedDict): - maxsize: int | None - typed: bool - always_checkpoint: bool - - -class _LRUMethodWrapper(Generic[T]): - def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object): - self.__wrapper = wrapper - self.__instance = instance - - def cache_info(self) -> AsyncCacheInfo: - return self.__wrapper.cache_info() - - def cache_parameters(self) -> AsyncCacheParameters: - return self.__wrapper.cache_parameters() - - def cache_clear(self) -> None: - self.__wrapper.cache_clear() - - async def __call__(self, *args: Any, **kwargs: Any) -> T: - if self.__instance is None: - return await self.__wrapper(*args, **kwargs) - - return await self.__wrapper(self.__instance, *args, **kwargs) - - -@final -class AsyncLRUCacheWrapper(Generic[P, T]): - def __init__( - self, - func: Callable[P, Awaitable[T]], - maxsize: int | None, - typed: bool, - always_checkpoint: bool, - ): - self.__wrapped__ = func - self._hits: int = 0 - self._misses: int = 0 - self._maxsize = max(maxsize, 0) if maxsize is not None else None - self._currsize: int = 0 - self._typed = typed - self._always_checkpoint = always_checkpoint - update_wrapper(self, func) - - def cache_info(self) -> AsyncCacheInfo: - return AsyncCacheInfo(self._hits, self._misses, self._maxsize, self._currsize) - - def cache_parameters(self) -> AsyncCacheParameters: - return { - "maxsize": self._maxsize, - "typed": self._typed, - "always_checkpoint": self._always_checkpoint, - } - - def cache_clear(self) -> None: - if cache := lru_cache_items.get(None): - cache.pop(self, None) - self._hits = self._misses = self._currsize = 0 - - async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: - # Easy case first: if maxsize == 0, no caching is done - if self._maxsize == 0: - value = await self.__wrapped__(*args, **kwargs) - self._misses += 1 - return value - - # The key is constructed as a flat tuple to avoid memory overhead - key: tuple[Any, ...] = args - if kwargs: - # initial_missing is used as a separator - key += (initial_missing,) + sum(kwargs.items(), ()) - - if self._typed: - key += tuple(type(arg) for arg in args) - if kwargs: - key += (initial_missing,) + tuple(type(val) for val in kwargs.values()) - - try: - cache = lru_cache_items.get() - except LookupError: - cache = WeakKeyDictionary() - lru_cache_items.set(cache) - - try: - cache_entry = cache[self] - except KeyError: - cache_entry = cache[self] = OrderedDict() - - cached_value: T | _InitialMissingType - try: - cached_value, lock = cache_entry[key] - except KeyError: - # We're the first task to call this function - cached_value, lock = ( - initial_missing, - Lock(fast_acquire=not self._always_checkpoint), - ) - cache_entry[key] = cached_value, lock - - if lock is None: - # The value was already cached - self._hits += 1 - cache_entry.move_to_end(key) - if self._always_checkpoint: - await checkpoint() - - return cast(T, cached_value) - - async with lock: - # Check if another task filled the cache while we acquired the lock - if (cached_value := cache_entry[key][0]) is initial_missing: - self._misses += 1 - if self._maxsize is not None and self._currsize >= self._maxsize: - cache_entry.popitem(last=False) - else: - self._currsize += 1 - - value = await self.__wrapped__(*args, **kwargs) - cache_entry[key] = value, None - else: - # Another task filled the cache while we were waiting for the lock - self._hits += 1 - cache_entry.move_to_end(key) - value = cast(T, cached_value) - - return value - - def __get__( - self, instance: object, owner: type | None = None - ) -> _LRUMethodWrapper[T]: - wrapper = _LRUMethodWrapper(self, instance) - update_wrapper(wrapper, self.__wrapped__) - return wrapper - - -class _LRUCacheWrapper(Generic[T]): - def __init__(self, maxsize: int | None, typed: bool, always_checkpoint: bool): - self._maxsize = maxsize - self._typed = typed - self._always_checkpoint = always_checkpoint - - @overload - def __call__( # type: ignore[overload-overlap] - self, func: Callable[P, Coroutine[Any, Any, T]], / - ) -> AsyncLRUCacheWrapper[P, T]: ... - - @overload - def __call__( - self, func: Callable[..., T], / - ) -> functools._lru_cache_wrapper[T]: ... - - def __call__( - self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], / - ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: - if iscoroutinefunction(f): - return AsyncLRUCacheWrapper( - f, self._maxsize, self._typed, self._always_checkpoint - ) - - return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type] - - -@overload -def cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def cache( - func: Callable[..., T] | Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: - """ - A convenient shortcut for :func:`lru_cache` with ``maxsize=None``. - - This is the asynchronous equivalent to :func:`functools.cache`. - - """ - return lru_cache(maxsize=None)(func) - - -@overload -def lru_cache( - *, maxsize: int | None = ..., typed: bool = ..., always_checkpoint: bool = ... -) -> _LRUCacheWrapper[Any]: ... - - -@overload -def lru_cache( # type: ignore[overload-overlap] - func: Callable[P, Coroutine[Any, Any, T]], / -) -> AsyncLRUCacheWrapper[P, T]: ... - - -@overload -def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... - - -def lru_cache( - func: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T] | None = None, - /, - *, - maxsize: int | None = 128, - typed: bool = False, - always_checkpoint: bool = False, -) -> ( - AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T] | _LRUCacheWrapper[Any] -): - """ - An asynchronous version of :func:`functools.lru_cache`. - - If a synchronous function is passed, the standard library - :func:`functools.lru_cache` is applied instead. - - :param always_checkpoint: if ``True``, every call to the cached function will be - guaranteed to yield control to the event loop at least once - - .. note:: Caches and locks are managed on a per-event loop basis. - - """ - if func is None: - return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint) - - if not callable(func): - raise TypeError("the first argument must be callable") - - return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint)(func) - - -@overload -async def reduce( - function: Callable[[T, S], Awaitable[T]], - iterable: Iterable[S] | AsyncIterable[S], - /, - initial: T, -) -> T: ... - - -@overload -async def reduce( - function: Callable[[T, T], Awaitable[T]], - iterable: Iterable[T] | AsyncIterable[T], - /, -) -> T: ... - - -async def reduce( # type: ignore[misc] - function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]], - iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S], - /, - initial: T | _InitialMissingType = initial_missing, -) -> T: - """ - Asynchronous version of :func:`functools.reduce`. - - :param function: a coroutine function that takes two arguments: the accumulated - value and the next element from the iterable - :param iterable: an iterable or async iterable - :param initial: the initial value (if missing, the first element of the iterable is - used as the initial value) - - """ - element: Any - function_called = False - if isinstance(iterable, AsyncIterable): - async_it = iterable.__aiter__() - if initial is initial_missing: - try: - value = cast(T, await async_it.__anext__()) - except StopAsyncIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - async for element in async_it: - value = await function(value, element) - function_called = True - elif isinstance(iterable, Iterable): - it = iter(iterable) - if initial is initial_missing: - try: - value = cast(T, next(it)) - except StopIteration: - raise TypeError( - "reduce() of empty sequence with no initial value" - ) from None - else: - value = cast(T, initial) - - for element in it: - value = await function(value, element) - function_called = True - else: - raise TypeError("reduce() argument 2 must be an iterable or async iterable") - - # Make sure there is at least one checkpoint, even if an empty iterable and an - # initial value were given - if not function_called: - await checkpoint() - - return value diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/lowlevel.py b/backend/venv39/lib/python3.9/site-packages/anyio/lowlevel.py deleted file mode 100644 index ffbb75a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/lowlevel.py +++ /dev/null @@ -1,196 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "EventLoopToken", - "RunvarToken", - "RunVar", - "checkpoint", - "checkpoint_if_cancelled", - "cancel_shielded_checkpoint", - "current_token", -) - -import enum -from dataclasses import dataclass -from types import TracebackType -from typing import Any, Generic, Literal, TypeVar, final, overload -from weakref import WeakKeyDictionary - -from ._core._eventloop import get_async_backend -from .abc import AsyncBackend - -T = TypeVar("T") -D = TypeVar("D") - - -async def checkpoint() -> None: - """ - Check for cancellation and allow the scheduler to switch to another task. - - Equivalent to (but more efficient than):: - - await checkpoint_if_cancelled() - await cancel_shielded_checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint() - - -async def checkpoint_if_cancelled() -> None: - """ - Enter a checkpoint if the enclosing cancel scope has been cancelled. - - This does not allow the scheduler to switch to a different task. - - .. versionadded:: 3.0 - - """ - await get_async_backend().checkpoint_if_cancelled() - - -async def cancel_shielded_checkpoint() -> None: - """ - Allow the scheduler to switch to another task but without checking for cancellation. - - Equivalent to (but potentially more efficient than):: - - with CancelScope(shield=True): - await checkpoint() - - .. versionadded:: 3.0 - - """ - await get_async_backend().cancel_shielded_checkpoint() - - -@final -@dataclass(frozen=True, repr=False) -class EventLoopToken: - """ - An opaque object that holds a reference to an event loop. - - .. versionadded:: 4.11.0 - """ - - backend_class: type[AsyncBackend] - native_token: object - - -def current_token() -> EventLoopToken: - """ - Return a token object that can be used to call code in the current event loop from - another thread. - - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - .. versionadded:: 4.11.0 - - """ - backend_class = get_async_backend() - raw_token = backend_class.current_token() - return EventLoopToken(backend_class, raw_token) - - -_run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary() - - -class _NoValueSet(enum.Enum): - NO_VALUE_SET = enum.auto() - - -class RunvarToken(Generic[T]): - __slots__ = "_var", "_value", "_redeemed" - - def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]): - self._var = var - self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value - self._redeemed = False - - def __enter__(self) -> RunvarToken[T]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self._var.reset(self) - - -class RunVar(Generic[T]): - """ - Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop. - - Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that - will reset the variable to its previous value when the context block is exited. - """ - - __slots__ = "_name", "_default" - - NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET - - def __init__( - self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ): - self._name = name - self._default = default - - @property - def _current_vars(self) -> dict[RunVar[T], T]: - native_token = current_token().native_token - try: - return _run_vars[native_token] - except KeyError: - run_vars = _run_vars[native_token] = {} - return run_vars - - @overload - def get(self, default: D) -> T | D: ... - - @overload - def get(self) -> T: ... - - def get( - self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET - ) -> T | D: - try: - return self._current_vars[self] - except KeyError: - if default is not RunVar.NO_VALUE_SET: - return default - elif self._default is not RunVar.NO_VALUE_SET: - return self._default - - raise LookupError( - f'Run variable "{self._name}" has no value and no default set' - ) - - def set(self, value: T) -> RunvarToken[T]: - current_vars = self._current_vars - token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET)) - current_vars[self] = value - return token - - def reset(self, token: RunvarToken[T]) -> None: - if token._var is not self: - raise ValueError("This token does not belong to this RunVar") - - if token._redeemed: - raise ValueError("This token has already been used") - - if token._value is _NoValueSet.NO_VALUE_SET: - try: - del self._current_vars[self] - except KeyError: - pass - else: - self._current_vars[self] = token._value - - token._redeemed = True - - def __repr__(self) -> str: - return f"" diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/py.typed b/backend/venv39/lib/python3.9/site-packages/anyio/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/pytest_plugin.py b/backend/venv39/lib/python3.9/site-packages/anyio/pytest_plugin.py deleted file mode 100644 index 4222816..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/pytest_plugin.py +++ /dev/null @@ -1,302 +0,0 @@ -from __future__ import annotations - -import socket -import sys -from collections.abc import Callable, Generator, Iterator -from contextlib import ExitStack, contextmanager -from inspect import isasyncgenfunction, iscoroutinefunction, ismethod -from typing import Any, cast - -import pytest -from _pytest.fixtures import SubRequest -from _pytest.outcomes import Exit - -from . import get_available_backends -from ._core._eventloop import ( - current_async_library, - get_async_backend, - reset_current_async_library, - set_current_async_library, -) -from ._core._exceptions import iterate_exceptions -from .abc import TestRunner - -if sys.version_info < (3, 11): - from exceptiongroup import ExceptionGroup - -_current_runner: TestRunner | None = None -_runner_stack: ExitStack | None = None -_runner_leases = 0 - - -def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]: - if isinstance(backend, str): - return backend, {} - elif isinstance(backend, tuple) and len(backend) == 2: - if isinstance(backend[0], str) and isinstance(backend[1], dict): - return cast(tuple[str, dict[str, Any]], backend) - - raise TypeError("anyio_backend must be either a string or tuple of (string, dict)") - - -@contextmanager -def get_runner( - backend_name: str, backend_options: dict[str, Any] -) -> Iterator[TestRunner]: - global _current_runner, _runner_leases, _runner_stack - if _current_runner is None: - asynclib = get_async_backend(backend_name) - _runner_stack = ExitStack() - if current_async_library() is None: - # Since we're in control of the event loop, we can cache the name of the - # async library - token = set_current_async_library(backend_name) - _runner_stack.callback(reset_current_async_library, token) - - backend_options = backend_options or {} - _current_runner = _runner_stack.enter_context( - asynclib.create_test_runner(backend_options) - ) - - _runner_leases += 1 - try: - yield _current_runner - finally: - _runner_leases -= 1 - if not _runner_leases: - assert _runner_stack is not None - _runner_stack.close() - _runner_stack = _current_runner = None - - -def pytest_addoption(parser: pytest.Parser) -> None: - parser.addini( - "anyio_mode", - default="strict", - help='AnyIO plugin mode (either "strict" or "auto")', - ) - - -def pytest_configure(config: pytest.Config) -> None: - config.addinivalue_line( - "markers", - "anyio: mark the (coroutine function) test to be run asynchronously via anyio.", - ) - if ( - config.getini("anyio_mode") == "auto" - and config.pluginmanager.has_plugin("asyncio") - and config.getini("asyncio_mode") == "auto" - ): - config.issue_config_time_warning( - pytest.PytestConfigWarning( - "AnyIO auto mode has been enabled together with pytest-asyncio auto " - "mode. This may cause unexpected behavior." - ), - 1, - ) - - -@pytest.hookimpl(hookwrapper=True) -def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]: - def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any: - # Rebind any fixture methods to the request instance - if ( - request.instance - and ismethod(func) - and type(func.__self__) is type(request.instance) - ): - local_func = func.__func__.__get__(request.instance) - else: - local_func = func - - backend_name, backend_options = extract_backend_and_options(anyio_backend) - if has_backend_arg: - kwargs["anyio_backend"] = anyio_backend - - if has_request_arg: - kwargs["request"] = request - - with get_runner(backend_name, backend_options) as runner: - if isasyncgenfunction(local_func): - yield from runner.run_asyncgen_fixture(local_func, kwargs) - else: - yield runner.run_fixture(local_func, kwargs) - - # Only apply this to coroutine functions and async generator functions in requests - # that involve the anyio_backend fixture - func = fixturedef.func - if isasyncgenfunction(func) or iscoroutinefunction(func): - if "anyio_backend" in request.fixturenames: - fixturedef.func = wrapper - original_argname = fixturedef.argnames - - if not (has_backend_arg := "anyio_backend" in fixturedef.argnames): - fixturedef.argnames += ("anyio_backend",) - - if not (has_request_arg := "request" in fixturedef.argnames): - fixturedef.argnames += ("request",) - - try: - return (yield) - finally: - fixturedef.func = func - fixturedef.argnames = original_argname - - return (yield) - - -@pytest.hookimpl(tryfirst=True) -def pytest_pycollect_makeitem( - collector: pytest.Module | pytest.Class, name: str, obj: object -) -> None: - if collector.istestfunction(obj, name): - inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj - if iscoroutinefunction(inner_func): - anyio_auto_mode = collector.config.getini("anyio_mode") == "auto" - marker = collector.get_closest_marker("anyio") - own_markers = getattr(obj, "pytestmark", ()) - if ( - anyio_auto_mode - or marker - or any(marker.name == "anyio" for marker in own_markers) - ): - pytest.mark.usefixtures("anyio_backend")(obj) - - -@pytest.hookimpl(tryfirst=True) -def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None: - def run_with_hypothesis(**kwargs: Any) -> None: - with get_runner(backend_name, backend_options) as runner: - runner.run_test(original_func, kwargs) - - backend = pyfuncitem.funcargs.get("anyio_backend") - if backend: - backend_name, backend_options = extract_backend_and_options(backend) - - if hasattr(pyfuncitem.obj, "hypothesis"): - # Wrap the inner test function unless it's already wrapped - original_func = pyfuncitem.obj.hypothesis.inner_test - if original_func.__qualname__ != run_with_hypothesis.__qualname__: - if iscoroutinefunction(original_func): - pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis - - return None - - if iscoroutinefunction(pyfuncitem.obj): - funcargs = pyfuncitem.funcargs - testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} - with get_runner(backend_name, backend_options) as runner: - try: - runner.run_test(pyfuncitem.obj, testargs) - except ExceptionGroup as excgrp: - for exc in iterate_exceptions(excgrp): - if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)): - raise exc from excgrp - - raise - - return True - - return None - - -@pytest.fixture(scope="module", params=get_available_backends()) -def anyio_backend(request: Any) -> Any: - return request.param - - -@pytest.fixture -def anyio_backend_name(anyio_backend: Any) -> str: - if isinstance(anyio_backend, str): - return anyio_backend - else: - return anyio_backend[0] - - -@pytest.fixture -def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]: - if isinstance(anyio_backend, str): - return {} - else: - return anyio_backend[1] - - -class FreePortFactory: - """ - Manages port generation based on specified socket kind, ensuring no duplicate - ports are generated. - - This class provides functionality for generating available free ports on the - system. It is initialized with a specific socket kind and can generate ports - for given address families while avoiding reuse of previously generated ports. - - Users should not instantiate this class directly, but use the - ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple - uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead. - """ - - def __init__(self, kind: socket.SocketKind) -> None: - self._kind = kind - self._generated = set[int]() - - @property - def kind(self) -> socket.SocketKind: - """ - The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or - :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability - - """ - return self._kind - - def __call__(self, family: socket.AddressFamily | None = None) -> int: - """ - Return an unbound port for the given address family. - - :param family: if omitted, both IPv4 and IPv6 addresses will be tried - :return: a port number - - """ - if family is not None: - families = [family] - else: - families = [socket.AF_INET] - if socket.has_ipv6: - families.append(socket.AF_INET6) - - while True: - port = 0 - with ExitStack() as stack: - for family in families: - sock = stack.enter_context(socket.socket(family, self._kind)) - addr = "::1" if family == socket.AF_INET6 else "127.0.0.1" - try: - sock.bind((addr, port)) - except OSError: - break - - if not port: - port = sock.getsockname()[1] - else: - if port not in self._generated: - self._generated.add(port) - return port - - -@pytest.fixture(scope="session") -def free_tcp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_STREAM) - - -@pytest.fixture(scope="session") -def free_udp_port_factory() -> FreePortFactory: - return FreePortFactory(socket.SOCK_DGRAM) - - -@pytest.fixture -def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int: - return free_tcp_port_factory() - - -@pytest.fixture -def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int: - return free_udp_port_factory() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/__init__.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/buffered.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/buffered.py deleted file mode 100644 index 57c7cd7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/buffered.py +++ /dev/null @@ -1,188 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "BufferedByteReceiveStream", - "BufferedByteStream", - "BufferedConnectable", -) - -import sys -from collections.abc import Callable, Iterable, Mapping -from dataclasses import dataclass, field -from typing import Any, SupportsIndex - -from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead -from ..abc import ( - AnyByteReceiveStream, - AnyByteStream, - AnyByteStreamConnectable, - ByteReceiveStream, - ByteStream, - ByteStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class BufferedByteReceiveStream(ByteReceiveStream): - """ - Wraps any bytes-based receive stream and uses a buffer to provide sophisticated - receiving capabilities in the form of a byte stream. - """ - - receive_stream: AnyByteReceiveStream - _buffer: bytearray = field(init=False, default_factory=bytearray) - _closed: bool = field(init=False, default=False) - - async def aclose(self) -> None: - await self.receive_stream.aclose() - self._closed = True - - @property - def buffer(self) -> bytes: - """The bytes currently in the buffer.""" - return bytes(self._buffer) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.receive_stream.extra_attributes - - def feed_data(self, data: Iterable[SupportsIndex], /) -> None: - """ - Append data directly into the buffer. - - Any data in the buffer will be consumed by receive operations before receiving - anything from the wrapped stream. - - :param data: the data to append to the buffer (can be bytes or anything else - that supports ``__index__()``) - - """ - self._buffer.extend(data) - - async def receive(self, max_bytes: int = 65536) -> bytes: - if self._closed: - raise ClosedResourceError - - if self._buffer: - chunk = bytes(self._buffer[:max_bytes]) - del self._buffer[:max_bytes] - return chunk - elif isinstance(self.receive_stream, ByteReceiveStream): - return await self.receive_stream.receive(max_bytes) - else: - # With a bytes-oriented object stream, we need to handle any surplus bytes - # we get from the receive() call - chunk = await self.receive_stream.receive() - if len(chunk) > max_bytes: - # Save the surplus bytes in the buffer - self._buffer.extend(chunk[max_bytes:]) - return chunk[:max_bytes] - else: - return chunk - - async def receive_exactly(self, nbytes: int) -> bytes: - """ - Read exactly the given amount of bytes from the stream. - - :param nbytes: the number of bytes to read - :return: the bytes read - :raises ~anyio.IncompleteRead: if the stream was closed before the requested - amount of bytes could be read from the stream - - """ - while True: - remaining = nbytes - len(self._buffer) - if remaining <= 0: - retval = self._buffer[:nbytes] - del self._buffer[:nbytes] - return bytes(retval) - - try: - if isinstance(self.receive_stream, ByteReceiveStream): - chunk = await self.receive_stream.receive(remaining) - else: - chunk = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - self._buffer.extend(chunk) - - async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes: - """ - Read from the stream until the delimiter is found or max_bytes have been read. - - :param delimiter: the marker to look for in the stream - :param max_bytes: maximum number of bytes that will be read before raising - :exc:`~anyio.DelimiterNotFound` - :return: the bytes read (not including the delimiter) - :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter - was found - :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the - bytes read up to the maximum allowed - - """ - delimiter_size = len(delimiter) - offset = 0 - while True: - # Check if the delimiter can be found in the current buffer - index = self._buffer.find(delimiter, offset) - if index >= 0: - found = self._buffer[:index] - del self._buffer[: index + len(delimiter) :] - return bytes(found) - - # Check if the buffer is already at or over the limit - if len(self._buffer) >= max_bytes: - raise DelimiterNotFound(max_bytes) - - # Read more data into the buffer from the socket - try: - data = await self.receive_stream.receive() - except EndOfStream as exc: - raise IncompleteRead from exc - - # Move the offset forward and add the new data to the buffer - offset = max(len(self._buffer) - delimiter_size + 1, 0) - self._buffer.extend(data) - - -class BufferedByteStream(BufferedByteReceiveStream, ByteStream): - """ - A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed - through to the wrapped stream as-is. - """ - - def __init__(self, stream: AnyByteStream): - """ - :param stream: the stream to be wrapped - - """ - super().__init__(stream) - self._stream = stream - - @override - async def send_eof(self) -> None: - await self._stream.send_eof() - - @override - async def send(self, item: bytes) -> None: - await self._stream.send(item) - - -class BufferedConnectable(ByteStreamConnectable): - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the connectable to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> BufferedByteStream: - stream = await self.connectable.connect() - return BufferedByteStream(stream) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/file.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/file.py deleted file mode 100644 index 82d2da8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/file.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "FileReadStream", - "FileStreamAttribute", - "FileWriteStream", -) - -from collections.abc import Callable, Mapping -from io import SEEK_SET, UnsupportedOperation -from os import PathLike -from pathlib import Path -from typing import Any, BinaryIO, cast - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - TypedAttributeSet, - to_thread, - typed_attribute, -) -from ..abc import ByteReceiveStream, ByteSendStream - - -class FileStreamAttribute(TypedAttributeSet): - #: the open file descriptor - file: BinaryIO = typed_attribute() - #: the path of the file on the file system, if available (file must be a real file) - path: Path = typed_attribute() - #: the file number, if available (file must be a real file or a TTY) - fileno: int = typed_attribute() - - -class _BaseFileStream: - def __init__(self, file: BinaryIO): - self._file = file - - async def aclose(self) -> None: - await to_thread.run_sync(self._file.close) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict[Any, Callable[[], Any]] = { - FileStreamAttribute.file: lambda: self._file, - } - - if hasattr(self._file, "name"): - attributes[FileStreamAttribute.path] = lambda: Path(self._file.name) - - try: - self._file.fileno() - except UnsupportedOperation: - pass - else: - attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno() - - return attributes - - -class FileReadStream(_BaseFileStream, ByteReceiveStream): - """ - A byte stream that reads from a file in the file system. - - :param file: a file that has been opened for reading in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path(cls, path: str | PathLike[str]) -> FileReadStream: - """ - Create a file read stream by opening the given file. - - :param path: path of the file to read from - - """ - file = await to_thread.run_sync(Path(path).open, "rb") - return cls(cast(BinaryIO, file)) - - async def receive(self, max_bytes: int = 65536) -> bytes: - try: - data = await to_thread.run_sync(self._file.read, max_bytes) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc - - if data: - return data - else: - raise EndOfStream - - async def seek(self, position: int, whence: int = SEEK_SET) -> int: - """ - Seek the file to the given position. - - .. seealso:: :meth:`io.IOBase.seek` - - .. note:: Not all file descriptors are seekable. - - :param position: position to seek the file to - :param whence: controls how ``position`` is interpreted - :return: the new absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.seek, position, whence) - - async def tell(self) -> int: - """ - Return the current stream position. - - .. note:: Not all file descriptors are seekable. - - :return: the current absolute position - :raises OSError: if the file is not seekable - - """ - return await to_thread.run_sync(self._file.tell) - - -class FileWriteStream(_BaseFileStream, ByteSendStream): - """ - A byte stream that writes to a file in the file system. - - :param file: a file that has been opened for writing in binary mode - - .. versionadded:: 3.0 - """ - - @classmethod - async def from_path( - cls, path: str | PathLike[str], append: bool = False - ) -> FileWriteStream: - """ - Create a file write stream by opening the given file for writing. - - :param path: path of the file to write to - :param append: if ``True``, open the file for appending; if ``False``, any - existing file at the given path will be truncated - - """ - mode = "ab" if append else "wb" - file = await to_thread.run_sync(Path(path).open, mode) - return cls(cast(BinaryIO, file)) - - async def send(self, item: bytes) -> None: - try: - await to_thread.run_sync(self._file.write, item) - except ValueError: - raise ClosedResourceError from None - except OSError as exc: - raise BrokenResourceError from exc diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/memory.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/memory.py deleted file mode 100644 index a3fa0c3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/memory.py +++ /dev/null @@ -1,325 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MemoryObjectReceiveStream", - "MemoryObjectSendStream", - "MemoryObjectStreamStatistics", -) - -import warnings -from collections import OrderedDict, deque -from dataclasses import dataclass, field -from types import TracebackType -from typing import Generic, NamedTuple, TypeVar - -from .. import ( - BrokenResourceError, - ClosedResourceError, - EndOfStream, - WouldBlock, -) -from .._core._testing import TaskInfo, get_current_task -from ..abc import Event, ObjectReceiveStream, ObjectSendStream -from ..lowlevel import checkpoint - -T_Item = TypeVar("T_Item") -T_co = TypeVar("T_co", covariant=True) -T_contra = TypeVar("T_contra", contravariant=True) - - -class MemoryObjectStreamStatistics(NamedTuple): - current_buffer_used: int #: number of items stored in the buffer - #: maximum number of items that can be stored on this stream (or :data:`math.inf`) - max_buffer_size: float - open_send_streams: int #: number of unclosed clones of the send stream - open_receive_streams: int #: number of unclosed clones of the receive stream - #: number of tasks blocked on :meth:`MemoryObjectSendStream.send` - tasks_waiting_send: int - #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive` - tasks_waiting_receive: int - - -@dataclass(eq=False) -class _MemoryObjectItemReceiver(Generic[T_Item]): - task_info: TaskInfo = field(init=False, default_factory=get_current_task) - item: T_Item = field(init=False) - - def __repr__(self) -> str: - # When item is not defined, we get following error with default __repr__: - # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item' - item = getattr(self, "item", None) - return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})" - - -@dataclass(eq=False) -class _MemoryObjectStreamState(Generic[T_Item]): - max_buffer_size: float = field() - buffer: deque[T_Item] = field(init=False, default_factory=deque) - open_send_channels: int = field(init=False, default=0) - open_receive_channels: int = field(init=False, default=0) - waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field( - init=False, default_factory=OrderedDict - ) - waiting_senders: OrderedDict[Event, T_Item] = field( - init=False, default_factory=OrderedDict - ) - - def statistics(self) -> MemoryObjectStreamStatistics: - return MemoryObjectStreamStatistics( - len(self.buffer), - self.max_buffer_size, - self.open_send_channels, - self.open_receive_channels, - len(self.waiting_senders), - len(self.waiting_receivers), - ) - - -@dataclass(eq=False) -class MemoryObjectReceiveStream(Generic[T_co], ObjectReceiveStream[T_co]): - _state: _MemoryObjectStreamState[T_co] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_receive_channels += 1 - - def receive_nowait(self) -> T_co: - """ - Receive the next item if it can be done without waiting. - - :return: the received item - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been - closed from the sending end - :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks - waiting to send - - """ - if self._closed: - raise ClosedResourceError - - if self._state.waiting_senders: - # Get the item from the next sender - send_event, item = self._state.waiting_senders.popitem(last=False) - self._state.buffer.append(item) - send_event.set() - - if self._state.buffer: - return self._state.buffer.popleft() - elif not self._state.open_send_channels: - raise EndOfStream - - raise WouldBlock - - async def receive(self) -> T_co: - await checkpoint() - try: - return self.receive_nowait() - except WouldBlock: - # Add ourselves in the queue - receive_event = Event() - receiver = _MemoryObjectItemReceiver[T_co]() - self._state.waiting_receivers[receive_event] = receiver - - try: - await receive_event.wait() - finally: - self._state.waiting_receivers.pop(receive_event, None) - - try: - return receiver.item - except AttributeError: - raise EndOfStream from None - - def clone(self) -> MemoryObjectReceiveStream[T_co]: - """ - Create a clone of this receive stream. - - Each clone can be closed separately. Only when all clones have been closed will - the receiving end of the memory stream be considered closed by the sending ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectReceiveStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_receive_channels -= 1 - if self._state.open_receive_channels == 0: - send_events = list(self._state.waiting_senders.keys()) - for event in send_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectReceiveStream[T_co]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) - - -@dataclass(eq=False) -class MemoryObjectSendStream(Generic[T_contra], ObjectSendStream[T_contra]): - _state: _MemoryObjectStreamState[T_contra] - _closed: bool = field(init=False, default=False) - - def __post_init__(self) -> None: - self._state.open_send_channels += 1 - - def send_nowait(self, item: T_contra) -> None: - """ - Send an item immediately if it can be done without waiting. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting - to receive - - """ - if self._closed: - raise ClosedResourceError - if not self._state.open_receive_channels: - raise BrokenResourceError - - while self._state.waiting_receivers: - receive_event, receiver = self._state.waiting_receivers.popitem(last=False) - if not receiver.task_info.has_pending_cancellation(): - receiver.item = item - receive_event.set() - return - - if len(self._state.buffer) < self._state.max_buffer_size: - self._state.buffer.append(item) - else: - raise WouldBlock - - async def send(self, item: T_contra) -> None: - """ - Send an item to the stream. - - If the buffer is full, this method blocks until there is again room in the - buffer or the item can be sent directly to a receiver. - - :param item: the item to send - :raises ~anyio.ClosedResourceError: if this send stream has been closed - :raises ~anyio.BrokenResourceError: if the stream has been closed from the - receiving end - - """ - await checkpoint() - try: - self.send_nowait(item) - except WouldBlock: - # Wait until there's someone on the receiving end - send_event = Event() - self._state.waiting_senders[send_event] = item - try: - await send_event.wait() - except BaseException: - self._state.waiting_senders.pop(send_event, None) - raise - - if send_event in self._state.waiting_senders: - del self._state.waiting_senders[send_event] - raise BrokenResourceError from None - - def clone(self) -> MemoryObjectSendStream[T_contra]: - """ - Create a clone of this send stream. - - Each clone can be closed separately. Only when all clones have been closed will - the sending end of the memory stream be considered closed by the receiving ends. - - :return: the cloned stream - - """ - if self._closed: - raise ClosedResourceError - - return MemoryObjectSendStream(_state=self._state) - - def close(self) -> None: - """ - Close the stream. - - This works the exact same way as :meth:`aclose`, but is provided as a special - case for the benefit of synchronous callbacks. - - """ - if not self._closed: - self._closed = True - self._state.open_send_channels -= 1 - if self._state.open_send_channels == 0: - receive_events = list(self._state.waiting_receivers.keys()) - self._state.waiting_receivers.clear() - for event in receive_events: - event.set() - - async def aclose(self) -> None: - self.close() - - def statistics(self) -> MemoryObjectStreamStatistics: - """ - Return statistics about the current state of this stream. - - .. versionadded:: 3.0 - """ - return self._state.statistics() - - def __enter__(self) -> MemoryObjectSendStream[T_contra]: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def __del__(self) -> None: - if not self._closed: - warnings.warn( - f"Unclosed <{self.__class__.__name__} at {id(self):x}>", - ResourceWarning, - stacklevel=1, - source=self, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/stapled.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/stapled.py deleted file mode 100644 index 9248b68..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/stapled.py +++ /dev/null @@ -1,147 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "MultiListener", - "StapledByteStream", - "StapledObjectStream", -) - -from collections.abc import Callable, Mapping, Sequence -from dataclasses import dataclass -from typing import Any, Generic, TypeVar - -from ..abc import ( - ByteReceiveStream, - ByteSendStream, - ByteStream, - Listener, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - TaskGroup, -) - -T_Item = TypeVar("T_Item") -T_Stream = TypeVar("T_Stream") - - -@dataclass(eq=False) -class StapledByteStream(ByteStream): - """ - Combines two byte streams into a single, bidirectional byte stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ByteSendStream send_stream: the sending byte stream - :param ByteReceiveStream receive_stream: the receiving byte stream - """ - - send_stream: ByteSendStream - receive_stream: ByteReceiveStream - - async def receive(self, max_bytes: int = 65536) -> bytes: - return await self.receive_stream.receive(max_bytes) - - async def send(self, item: bytes) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]): - """ - Combines two object streams into a single, bidirectional object stream. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param ObjectSendStream send_stream: the sending object stream - :param ObjectReceiveStream receive_stream: the receiving object stream - """ - - send_stream: ObjectSendStream[T_Item] - receive_stream: ObjectReceiveStream[T_Item] - - async def receive(self) -> T_Item: - return await self.receive_stream.receive() - - async def send(self, item: T_Item) -> None: - await self.send_stream.send(item) - - async def send_eof(self) -> None: - await self.send_stream.aclose() - - async def aclose(self) -> None: - await self.send_stream.aclose() - await self.receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.send_stream.extra_attributes, - **self.receive_stream.extra_attributes, - } - - -@dataclass(eq=False) -class MultiListener(Generic[T_Stream], Listener[T_Stream]): - """ - Combines multiple listeners into one, serving connections from all of them at once. - - Any MultiListeners in the given collection of listeners will have their listeners - moved into this one. - - Extra attributes are provided from each listener, with each successive listener - overriding any conflicting attributes from the previous one. - - :param listeners: listeners to serve - :type listeners: Sequence[Listener[T_Stream]] - """ - - listeners: Sequence[Listener[T_Stream]] - - def __post_init__(self) -> None: - listeners: list[Listener[T_Stream]] = [] - for listener in self.listeners: - if isinstance(listener, MultiListener): - listeners.extend(listener.listeners) - del listener.listeners[:] # type: ignore[attr-defined] - else: - listeners.append(listener) - - self.listeners = listeners - - async def serve( - self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None - ) -> None: - from .. import create_task_group - - async with create_task_group() as tg: - for listener in self.listeners: - tg.start_soon(listener.serve, handler, task_group) - - async def aclose(self) -> None: - for listener in self.listeners: - await listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - attributes: dict = {} - for listener in self.listeners: - attributes.update(listener.extra_attributes) - - return attributes diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/text.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/text.py deleted file mode 100644 index 296cd25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/text.py +++ /dev/null @@ -1,176 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TextConnectable", - "TextReceiveStream", - "TextSendStream", - "TextStream", -) - -import codecs -import sys -from collections.abc import Callable, Mapping -from dataclasses import InitVar, dataclass, field -from typing import Any - -from ..abc import ( - AnyByteReceiveStream, - AnyByteSendStream, - AnyByteStream, - AnyByteStreamConnectable, - ObjectReceiveStream, - ObjectSendStream, - ObjectStream, - ObjectStreamConnectable, -) - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - - -@dataclass(eq=False) -class TextReceiveStream(ObjectReceiveStream[str]): - """ - Stream wrapper that decodes bytes to strings using the given encoding. - - Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any - completely received unicode characters as soon as they come in. - - :param transport_stream: any bytes-based receive stream - :param encoding: character encoding to use for decoding bytes to strings (defaults - to ``utf-8``) - :param errors: handling scheme for decoding errors (defaults to ``strict``; see the - `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteReceiveStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _decoder: codecs.IncrementalDecoder = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - decoder_class = codecs.getincrementaldecoder(encoding) - self._decoder = decoder_class(errors=errors) - - async def receive(self) -> str: - while True: - chunk = await self.transport_stream.receive() - decoded = self._decoder.decode(chunk) - if decoded: - return decoded - - async def aclose(self) -> None: - await self.transport_stream.aclose() - self._decoder.reset() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextSendStream(ObjectSendStream[str]): - """ - Sends strings to the wrapped stream as bytes using the given encoding. - - :param AnyByteSendStream transport_stream: any bytes-based send stream - :param str encoding: character encoding to use for encoding strings to bytes - (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteSendStream - encoding: InitVar[str] = "utf-8" - errors: str = "strict" - _encoder: Callable[..., tuple[bytes, int]] = field(init=False) - - def __post_init__(self, encoding: str) -> None: - self._encoder = codecs.getencoder(encoding) - - async def send(self, item: str) -> None: - encoded = self._encoder(item, self.errors)[0] - await self.transport_stream.send(encoded) - - async def aclose(self) -> None: - await self.transport_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return self.transport_stream.extra_attributes - - -@dataclass(eq=False) -class TextStream(ObjectStream[str]): - """ - A bidirectional stream that decodes bytes to strings on receive and encodes strings - to bytes on send. - - Extra attributes will be provided from both streams, with the receive stream - providing the values in case of a conflict. - - :param AnyByteStream transport_stream: any bytes-based stream - :param str encoding: character encoding to use for encoding/decoding strings to/from - bytes (defaults to ``utf-8``) - :param str errors: handling scheme for encoding errors (defaults to ``strict``; see - the `codecs module documentation`_ for a comprehensive list of options) - - .. _codecs module documentation: - https://docs.python.org/3/library/codecs.html#codec-objects - """ - - transport_stream: AnyByteStream - encoding: InitVar[str] = "utf-8" - errors: InitVar[str] = "strict" - _receive_stream: TextReceiveStream = field(init=False) - _send_stream: TextSendStream = field(init=False) - - def __post_init__(self, encoding: str, errors: str) -> None: - self._receive_stream = TextReceiveStream( - self.transport_stream, encoding=encoding, errors=errors - ) - self._send_stream = TextSendStream( - self.transport_stream, encoding=encoding, errors=errors - ) - - async def receive(self) -> str: - return await self._receive_stream.receive() - - async def send(self, item: str) -> None: - await self._send_stream.send(item) - - async def send_eof(self) -> None: - await self.transport_stream.send_eof() - - async def aclose(self) -> None: - await self._send_stream.aclose() - await self._receive_stream.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self._send_stream.extra_attributes, - **self._receive_stream.extra_attributes, - } - - -class TextConnectable(ObjectStreamConnectable[str]): - def __init__(self, connectable: AnyByteStreamConnectable): - """ - :param connectable: the bytestream endpoint to wrap - - """ - self.connectable = connectable - - @override - async def connect(self) -> TextStream: - stream = await self.connectable.connect() - return TextStream(stream) diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/streams/tls.py b/backend/venv39/lib/python3.9/site-packages/anyio/streams/tls.py deleted file mode 100644 index b507488..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/streams/tls.py +++ /dev/null @@ -1,424 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "TLSAttribute", - "TLSConnectable", - "TLSListener", - "TLSStream", -) - -import logging -import re -import ssl -import sys -from collections.abc import Callable, Mapping -from dataclasses import dataclass -from functools import wraps -from ssl import SSLContext -from typing import Any, TypeVar - -from .. import ( - BrokenResourceError, - EndOfStream, - aclose_forcefully, - get_cancelled_exc_class, - to_thread, -) -from .._core._typedattr import TypedAttributeSet, typed_attribute -from ..abc import ( - AnyByteStream, - AnyByteStreamConnectable, - ByteStream, - ByteStreamConnectable, - Listener, - TaskGroup, -) - -if sys.version_info >= (3, 10): - from typing import TypeAlias -else: - from typing_extensions import TypeAlias - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 12): - from typing import override -else: - from typing_extensions import override - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") -_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] -_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] - - -class TLSAttribute(TypedAttributeSet): - """Contains Transport Layer Security related attributes.""" - - #: the selected ALPN protocol - alpn_protocol: str | None = typed_attribute() - #: the channel binding for type ``tls-unique`` - channel_binding_tls_unique: bytes = typed_attribute() - #: the selected cipher - cipher: tuple[str, str, int] = typed_attribute() - #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` - # for more information) - peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute() - #: the peer certificate in binary form - peer_certificate_binary: bytes | None = typed_attribute() - #: ``True`` if this is the server side of the connection - server_side: bool = typed_attribute() - #: ciphers shared by the client during the TLS handshake (``None`` if this is the - #: client side) - shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute() - #: the :class:`~ssl.SSLObject` used for encryption - ssl_object: ssl.SSLObject = typed_attribute() - #: ``True`` if this stream does (and expects) a closing TLS handshake when the - #: stream is being closed - standard_compatible: bool = typed_attribute() - #: the TLS protocol version (e.g. ``TLSv1.2``) - tls_version: str = typed_attribute() - - -@dataclass(eq=False) -class TLSStream(ByteStream): - """ - A stream wrapper that encrypts all sent data and decrypts received data. - - This class has no public initializer; use :meth:`wrap` instead. - All extra attributes from :class:`~TLSAttribute` are supported. - - :var AnyByteStream transport_stream: the wrapped stream - - """ - - transport_stream: AnyByteStream - standard_compatible: bool - _ssl_object: ssl.SSLObject - _read_bio: ssl.MemoryBIO - _write_bio: ssl.MemoryBIO - - @classmethod - async def wrap( - cls, - transport_stream: AnyByteStream, - *, - server_side: bool | None = None, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> TLSStream: - """ - Wrap an existing stream with Transport Layer Security. - - This performs a TLS handshake with the peer. - - :param transport_stream: a bytes-transporting stream to wrap - :param server_side: ``True`` if this is the server side of the connection, - ``False`` if this is the client side (if omitted, will be set to ``False`` - if ``hostname`` has been provided, ``False`` otherwise). Used only to create - a default context when an explicit context has not been provided. - :param hostname: host name of the peer (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure - default will be created) - :param standard_compatible: if ``False``, skip the closing handshake when - closing the connection, and don't raise an exception if the peer does the - same - :raises ~ssl.SSLError: if the TLS handshake fails - - """ - if server_side is None: - server_side = not hostname - - if not ssl_context: - purpose = ( - ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH - ) - ssl_context = ssl.create_default_context(purpose) - - # Re-enable detection of unexpected EOFs if it was disabled by Python - if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): - ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF - - bio_in = ssl.MemoryBIO() - bio_out = ssl.MemoryBIO() - - # External SSLContext implementations may do blocking I/O in wrap_bio(), - # but the standard library implementation won't - if type(ssl_context) is ssl.SSLContext: - ssl_object = ssl_context.wrap_bio( - bio_in, bio_out, server_side=server_side, server_hostname=hostname - ) - else: - ssl_object = await to_thread.run_sync( - ssl_context.wrap_bio, - bio_in, - bio_out, - server_side, - hostname, - None, - ) - - wrapper = cls( - transport_stream=transport_stream, - standard_compatible=standard_compatible, - _ssl_object=ssl_object, - _read_bio=bio_in, - _write_bio=bio_out, - ) - await wrapper._call_sslobject_method(ssl_object.do_handshake) - return wrapper - - async def _call_sslobject_method( - self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] - ) -> T_Retval: - while True: - try: - result = func(*args) - except ssl.SSLWantReadError: - try: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - data = await self.transport_stream.receive() - except EndOfStream: - self._read_bio.write_eof() - except OSError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - else: - self._read_bio.write(data) - except ssl.SSLWantWriteError: - await self.transport_stream.send(self._write_bio.read()) - except ssl.SSLSyscallError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - raise BrokenResourceError from exc - except ssl.SSLError as exc: - self._read_bio.write_eof() - self._write_bio.write_eof() - if isinstance(exc, ssl.SSLEOFError) or ( - exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror - ): - if self.standard_compatible: - raise BrokenResourceError from exc - else: - raise EndOfStream from None - - raise - else: - # Flush any pending writes first - if self._write_bio.pending: - await self.transport_stream.send(self._write_bio.read()) - - return result - - async def unwrap(self) -> tuple[AnyByteStream, bytes]: - """ - Does the TLS closing handshake. - - :return: a tuple of (wrapped byte stream, bytes left in the read buffer) - - """ - await self._call_sslobject_method(self._ssl_object.unwrap) - self._read_bio.write_eof() - self._write_bio.write_eof() - return self.transport_stream, self._read_bio.read() - - async def aclose(self) -> None: - if self.standard_compatible: - try: - await self.unwrap() - except BaseException: - await aclose_forcefully(self.transport_stream) - raise - - await self.transport_stream.aclose() - - async def receive(self, max_bytes: int = 65536) -> bytes: - data = await self._call_sslobject_method(self._ssl_object.read, max_bytes) - if not data: - raise EndOfStream - - return data - - async def send(self, item: bytes) -> None: - await self._call_sslobject_method(self._ssl_object.write, item) - - async def send_eof(self) -> None: - tls_version = self.extra(TLSAttribute.tls_version) - match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version) - if match: - major, minor = int(match.group(1)), int(match.group(2) or 0) - if (major, minor) < (1, 3): - raise NotImplementedError( - f"send_eof() requires at least TLSv1.3; current " - f"session uses {tls_version}" - ) - - raise NotImplementedError( - "send_eof() has not yet been implemented for TLS streams" - ) - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - **self.transport_stream.extra_attributes, - TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol, - TLSAttribute.channel_binding_tls_unique: ( - self._ssl_object.get_channel_binding - ), - TLSAttribute.cipher: self._ssl_object.cipher, - TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False), - TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert( - True - ), - TLSAttribute.server_side: lambda: self._ssl_object.server_side, - TLSAttribute.shared_ciphers: lambda: self._ssl_object.shared_ciphers() - if self._ssl_object.server_side - else None, - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - TLSAttribute.ssl_object: lambda: self._ssl_object, - TLSAttribute.tls_version: self._ssl_object.version, - } - - -@dataclass(eq=False) -class TLSListener(Listener[TLSStream]): - """ - A convenience listener that wraps another listener and auto-negotiates a TLS session - on every accepted connection. - - If the TLS handshake times out or raises an exception, - :meth:`handle_handshake_error` is called to do whatever post-mortem processing is - deemed necessary. - - Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute. - - :param Listener listener: the listener to wrap - :param ssl_context: the SSL context object - :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap` - :param handshake_timeout: time limit for the TLS handshake - (passed to :func:`~anyio.fail_after`) - """ - - listener: Listener[Any] - ssl_context: ssl.SSLContext - standard_compatible: bool = True - handshake_timeout: float = 30 - - @staticmethod - async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None: - """ - Handle an exception raised during the TLS handshake. - - This method does 3 things: - - #. Forcefully closes the original stream - #. Logs the exception (unless it was a cancellation exception) using the - ``anyio.streams.tls`` logger - #. Reraises the exception if it was a base exception or a cancellation exception - - :param exc: the exception - :param stream: the original stream - - """ - await aclose_forcefully(stream) - - # Log all except cancellation exceptions - if not isinstance(exc, get_cancelled_exc_class()): - # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using - # any asyncio implementation, so we explicitly pass the exception to log - # (https://github.com/python/cpython/issues/108668). Trio does not have this - # issue because it works around the CPython bug. - logging.getLogger(__name__).exception( - "Error during TLS handshake", exc_info=exc - ) - - # Only reraise base exceptions and cancellation exceptions - if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()): - raise - - async def serve( - self, - handler: Callable[[TLSStream], Any], - task_group: TaskGroup | None = None, - ) -> None: - @wraps(handler) - async def handler_wrapper(stream: AnyByteStream) -> None: - from .. import fail_after - - try: - with fail_after(self.handshake_timeout): - wrapped_stream = await TLSStream.wrap( - stream, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException as exc: - await self.handle_handshake_error(exc, stream) - else: - await handler(wrapped_stream) - - await self.listener.serve(handler_wrapper, task_group) - - async def aclose(self) -> None: - await self.listener.aclose() - - @property - def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: - return { - TLSAttribute.standard_compatible: lambda: self.standard_compatible, - } - - -class TLSConnectable(ByteStreamConnectable): - """ - Wraps another connectable and does TLS negotiation after a successful connection. - - :param connectable: the connectable to wrap - :param hostname: host name of the server (if host name checking is desired) - :param ssl_context: the SSLContext object to use (if not provided, a secure default - will be created) - :param standard_compatible: if ``False``, skip the closing handshake when closing - the connection, and don't raise an exception if the server does the same - """ - - def __init__( - self, - connectable: AnyByteStreamConnectable, - *, - hostname: str | None = None, - ssl_context: ssl.SSLContext | None = None, - standard_compatible: bool = True, - ) -> None: - self.connectable = connectable - self.ssl_context: SSLContext = ssl_context or ssl.create_default_context( - ssl.Purpose.SERVER_AUTH - ) - if not isinstance(self.ssl_context, ssl.SSLContext): - raise TypeError( - "ssl_context must be an instance of ssl.SSLContext, not " - f"{type(self.ssl_context).__name__}" - ) - self.hostname = hostname - self.standard_compatible = standard_compatible - - @override - async def connect(self) -> TLSStream: - stream = await self.connectable.connect() - try: - return await TLSStream.wrap( - stream, - hostname=self.hostname, - ssl_context=self.ssl_context, - standard_compatible=self.standard_compatible, - ) - except BaseException: - await aclose_forcefully(stream) - raise diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/to_interpreter.py b/backend/venv39/lib/python3.9/site-packages/anyio/to_interpreter.py deleted file mode 100644 index 694dbe7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/to_interpreter.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_interpreter_limiter", -) - -import atexit -import os -import sys -from collections import deque -from collections.abc import Callable -from typing import Any, Final, TypeVar - -from . import current_time, to_thread -from ._core._exceptions import BrokenWorkerInterpreter -from ._core._synchronization import CapacityLimiter -from .lowlevel import RunVar - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -if sys.version_info >= (3, 14): - from concurrent.interpreters import ExecutionFailed, create - - def _interp_call( - func: Callable[..., Any], args: tuple[Any, ...] - ) -> tuple[Any, bool]: - try: - retval = func(*args) - except BaseException as exc: - return exc, True - else: - return retval, False - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter = create() - - def destroy(self) -> None: - self._interpreter.close() - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - try: - res, is_exception = self._interpreter.call(_interp_call, func, args) - except ExecutionFailed as exc: - raise BrokenWorkerInterpreter(exc.excinfo) from exc - - if is_exception: - raise res - - return res -elif sys.version_info >= (3, 13): - import _interpqueues - import _interpreters - - UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib - FMT_UNPICKLED: Final = 0 - FMT_PICKLED: Final = 1 - QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND) - QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND) - - _run_func = compile( - """ -import _interpqueues -from _interpreters import NotShareableError -from pickle import loads, dumps, HIGHEST_PROTOCOL - -QUEUE_PICKLE_ARGS = (1, 2) -QUEUE_UNPICKLE_ARGS = (0, 2) - -item = _interpqueues.get(queue_id)[0] -try: - func, args = loads(item) - retval = func(*args) -except BaseException as exc: - is_exception = True - retval = exc -else: - is_exception = False - -try: - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS) -except NotShareableError: - retval = dumps(retval, HIGHEST_PROTOCOL) - _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS) - """, - "", - "exec", - ) - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - self._interpreter_id = _interpreters.create() - self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS) - _interpreters.set___main___attrs( - self._interpreter_id, {"queue_id": self._queue_id} - ) - - def destroy(self) -> None: - _interpqueues.destroy(self._queue_id) - _interpreters.destroy(self._interpreter_id) - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - import pickle - - item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL) - _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS) - exc_info = _interpreters.exec(self._interpreter_id, _run_func) - if exc_info: - raise BrokenWorkerInterpreter(exc_info) - - res = _interpqueues.get(self._queue_id) - (res, is_exception), fmt = res[:2] - if fmt == FMT_PICKLED: - res = pickle.loads(res) - - if is_exception: - raise res - - return res -else: - - class _Worker: - last_used: float = 0 - - def __init__(self) -> None: - raise RuntimeError("subinterpreters require at least Python 3.13") - - def call( - self, - func: Callable[..., T_Retval], - args: tuple[Any, ...], - ) -> T_Retval: - raise NotImplementedError - - def destroy(self) -> None: - pass - - -DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value -MAX_WORKER_IDLE_TIME = ( - 30 # seconds a subinterpreter can be idle before becoming eligible for pruning -) - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_idle_workers = RunVar[deque[_Worker]]("_available_workers") -_default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter") - - -def _stop_workers(workers: deque[_Worker]) -> None: - for worker in workers: - worker.destroy() - - workers.clear() - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a subinterpreter. - - .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet - available, so the code path for that Python version relies on an undocumented, - private API. As such, it is recommended to not rely on this function for anything - mission-critical on Python 3.13. - - :param func: a callable - :param args: the positional arguments for the callable - :param limiter: capacity limiter to use to limit the total number of subinterpreters - running (if omitted, the default limiter is used) - :return: the result of the call - :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter - - """ - if limiter is None: - limiter = current_default_interpreter_limiter() - - try: - idle_workers = _idle_workers.get() - except LookupError: - idle_workers = deque() - _idle_workers.set(idle_workers) - atexit.register(_stop_workers, idle_workers) - - async with limiter: - try: - worker = idle_workers.pop() - except IndexError: - worker = _Worker() - - try: - return await to_thread.run_sync( - worker.call, - func, - args, - limiter=limiter, - ) - finally: - # Prune workers that have been idle for too long - now = current_time() - while idle_workers: - if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME: - break - - await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter) - - worker.last_used = current_time() - idle_workers.append(worker) - - -def current_default_interpreter_limiter() -> CapacityLimiter: - """ - Return the capacity limiter used by default to limit the number of concurrently - running subinterpreters. - - Defaults to the number of CPU cores. - - :return: a capacity limiter object - - """ - try: - return _default_interpreter_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT) - _default_interpreter_limiter.set(limiter) - return limiter diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/to_process.py b/backend/venv39/lib/python3.9/site-packages/anyio/to_process.py deleted file mode 100644 index b289234..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/to_process.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "current_default_process_limiter", - "process_worker", - "run_sync", -) - -import os -import pickle -import subprocess -import sys -from collections import deque -from collections.abc import Callable -from importlib.util import module_from_spec, spec_from_file_location -from typing import TypeVar, cast - -from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class -from ._core._exceptions import BrokenWorkerProcess -from ._core._subprocesses import open_process -from ._core._synchronization import CapacityLimiter -from ._core._tasks import CancelScope, fail_after -from .abc import ByteReceiveStream, ByteSendStream, Process -from .lowlevel import RunVar, checkpoint_if_cancelled -from .streams.buffered import BufferedByteReceiveStream - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -WORKER_MAX_IDLE_TIME = 300 # 5 minutes - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - -_process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers") -_process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar( - "_process_pool_idle_workers" -) -_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter") - - -async def run_sync( # type: ignore[return] - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - cancellable: bool = False, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker process. - - If the ``cancellable`` option is enabled and the task waiting for its completion is - cancelled, the worker process running it will be abruptly terminated using SIGKILL - (or ``terminateProcess()`` on Windows). - - :param func: a callable - :param args: positional arguments for the callable - :param cancellable: ``True`` to allow cancellation of the operation while it's - running - :param limiter: capacity limiter to use to limit the total amount of processes - running (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - - async def send_raw_command(pickled_cmd: bytes) -> object: - try: - await stdin.send(pickled_cmd) - response = await buffered.receive_until(b"\n", 50) - status, length = response.split(b" ") - if status not in (b"RETURN", b"EXCEPTION"): - raise RuntimeError( - f"Worker process returned unexpected response: {response!r}" - ) - - pickled_response = await buffered.receive_exactly(int(length)) - except BaseException as exc: - workers.discard(process) - try: - process.kill() - with CancelScope(shield=True): - await process.aclose() - except ProcessLookupError: - pass - - if isinstance(exc, get_cancelled_exc_class()): - raise - else: - raise BrokenWorkerProcess from exc - - retval = pickle.loads(pickled_response) - if status == b"EXCEPTION": - assert isinstance(retval, BaseException) - raise retval - else: - return retval - - # First pickle the request before trying to reserve a worker process - await checkpoint_if_cancelled() - request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL) - - # If this is the first run in this event loop thread, set up the necessary variables - try: - workers = _process_pool_workers.get() - idle_workers = _process_pool_idle_workers.get() - except LookupError: - workers = set() - idle_workers = deque() - _process_pool_workers.set(workers) - _process_pool_idle_workers.set(idle_workers) - get_async_backend().setup_process_pool_exit_at_shutdown(workers) - - async with limiter or current_default_process_limiter(): - # Pop processes from the pool (starting from the most recently used) until we - # find one that hasn't exited yet - process: Process - while idle_workers: - process, idle_since = idle_workers.pop() - if process.returncode is None: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - - # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME - # seconds or longer - now = current_time() - killed_processes: list[Process] = [] - while idle_workers: - if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME: - break - - process_to_kill, idle_since = idle_workers.popleft() - process_to_kill.kill() - workers.remove(process_to_kill) - killed_processes.append(process_to_kill) - - with CancelScope(shield=True): - for killed_process in killed_processes: - await killed_process.aclose() - - break - - workers.remove(process) - else: - command = [sys.executable, "-u", "-m", __name__] - process = await open_process( - command, stdin=subprocess.PIPE, stdout=subprocess.PIPE - ) - try: - stdin = cast(ByteSendStream, process.stdin) - buffered = BufferedByteReceiveStream( - cast(ByteReceiveStream, process.stdout) - ) - with fail_after(20): - message = await buffered.receive(6) - - if message != b"READY\n": - raise BrokenWorkerProcess( - f"Worker process returned unexpected response: {message!r}" - ) - - main_module_path = getattr(sys.modules["__main__"], "__file__", None) - pickled = pickle.dumps( - ("init", sys.path, main_module_path), - protocol=pickle.HIGHEST_PROTOCOL, - ) - await send_raw_command(pickled) - except (BrokenWorkerProcess, get_cancelled_exc_class()): - raise - except BaseException as exc: - process.kill() - raise BrokenWorkerProcess( - "Error during worker process initialization" - ) from exc - - workers.add(process) - - with CancelScope(shield=not cancellable): - try: - return cast(T_Retval, await send_raw_command(request)) - finally: - if process in workers: - idle_workers.append((process, current_time())) - - -def current_default_process_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of worker - processes. - - :return: a capacity limiter object - - """ - try: - return _default_process_limiter.get() - except LookupError: - limiter = CapacityLimiter(os.cpu_count() or 2) - _default_process_limiter.set(limiter) - return limiter - - -def process_worker() -> None: - # Redirect standard streams to os.devnull so that user code won't interfere with the - # parent-worker communication - stdin = sys.stdin - stdout = sys.stdout - sys.stdin = open(os.devnull) - sys.stdout = open(os.devnull, "w") - - stdout.buffer.write(b"READY\n") - while True: - retval = exception = None - try: - command, *args = pickle.load(stdin.buffer) - except EOFError: - return - except BaseException as exc: - exception = exc - else: - if command == "run": - func, args = args - try: - retval = func(*args) - except BaseException as exc: - exception = exc - elif command == "init": - main_module_path: str | None - sys.path, main_module_path = args - del sys.modules["__main__"] - if main_module_path and os.path.isfile(main_module_path): - # Load the parent's main module but as __mp_main__ instead of - # __main__ (like multiprocessing does) to avoid infinite recursion - try: - spec = spec_from_file_location("__mp_main__", main_module_path) - if spec and spec.loader: - main = module_from_spec(spec) - spec.loader.exec_module(main) - sys.modules["__main__"] = main - except BaseException as exc: - exception = exc - try: - if exception is not None: - status = b"EXCEPTION" - pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL) - else: - status = b"RETURN" - pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL) - except BaseException as exc: - exception = exc - status = b"EXCEPTION" - pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL) - - stdout.buffer.write(b"%s %d\n" % (status, len(pickled))) - stdout.buffer.write(pickled) - - # Respect SIGTERM - if isinstance(exception, SystemExit): - raise exception - - -if __name__ == "__main__": - process_worker() diff --git a/backend/venv39/lib/python3.9/site-packages/anyio/to_thread.py b/backend/venv39/lib/python3.9/site-packages/anyio/to_thread.py deleted file mode 100644 index 4be5b71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/anyio/to_thread.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -__all__ = ( - "run_sync", - "current_default_thread_limiter", -) - -import sys -from collections.abc import Callable -from typing import TypeVar -from warnings import warn - -from ._core._eventloop import get_async_backend -from .abc import CapacityLimiter - -if sys.version_info >= (3, 11): - from typing import TypeVarTuple, Unpack -else: - from typing_extensions import TypeVarTuple, Unpack - -T_Retval = TypeVar("T_Retval") -PosArgsT = TypeVarTuple("PosArgsT") - - -async def run_sync( - func: Callable[[Unpack[PosArgsT]], T_Retval], - *args: Unpack[PosArgsT], - abandon_on_cancel: bool = False, - cancellable: bool | None = None, - limiter: CapacityLimiter | None = None, -) -> T_Retval: - """ - Call the given function with the given arguments in a worker thread. - - If the ``cancellable`` option is enabled and the task waiting for its completion is - cancelled, the thread will still run its course but its return value (or any raised - exception) will be ignored. - - :param func: a callable - :param args: positional arguments for the callable - :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run - unchecked on own) if the host task is cancelled, ``False`` to ignore - cancellations in the host task until the operation has completed in the worker - thread - :param cancellable: deprecated alias of ``abandon_on_cancel``; will override - ``abandon_on_cancel`` if both parameters are passed - :param limiter: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - :return: an awaitable that yields the return value of the function. - - """ - if cancellable is not None: - abandon_on_cancel = cancellable - warn( - "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is " - "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead", - DeprecationWarning, - stacklevel=2, - ) - - return await get_async_backend().run_sync_in_worker_thread( - func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter - ) - - -def current_default_thread_limiter() -> CapacityLimiter: - """ - Return the capacity limiter that is used by default to limit the number of - concurrent threads. - - :return: a capacity limiter object - :raises NoEventLoopError: if no supported asynchronous event loop is running in the - current thread - - """ - return get_async_backend().current_default_thread_limiter() diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/__init__.py b/backend/venv39/lib/python3.9/site-packages/argon2/__init__.py deleted file mode 100644 index bea9839..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/__init__.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Argon2 for Python -""" - -from . import exceptions, low_level, profiles -from ._legacy import hash_password, hash_password_raw, verify_password -from ._password_hasher import ( - DEFAULT_HASH_LENGTH, - DEFAULT_MEMORY_COST, - DEFAULT_PARALLELISM, - DEFAULT_RANDOM_SALT_LENGTH, - DEFAULT_TIME_COST, - PasswordHasher, -) -from ._utils import Parameters, extract_parameters -from .low_level import Type - - -__title__ = "argon2-cffi" - -__author__ = "Hynek Schlawack" -__copyright__ = "Copyright (c) 2015 " + __author__ -__license__ = "MIT" - - -__all__ = [ - "DEFAULT_HASH_LENGTH", - "DEFAULT_MEMORY_COST", - "DEFAULT_PARALLELISM", - "DEFAULT_RANDOM_SALT_LENGTH", - "DEFAULT_TIME_COST", - "Parameters", - "PasswordHasher", - "Type", - "exceptions", - "extract_parameters", - "hash_password", - "hash_password_raw", - "low_level", - "profiles", - "verify_password", -] - - -def __getattr__(name: str) -> str: - dunder_to_metadata = { - "__version__": "version", - "__description__": "summary", - "__uri__": "", - "__url__": "", - "__email__": "", - } - if name not in dunder_to_metadata: - msg = f"module {__name__} has no attribute {name}" - raise AttributeError(msg) - - import warnings - - from importlib.metadata import metadata - - warnings.warn( - f"Accessing argon2.{name} is deprecated and will be " - "removed in a future release. Use importlib.metadata directly " - "to query for argon2-cffi's packaging metadata.", - DeprecationWarning, - stacklevel=2, - ) - - meta = metadata("argon2-cffi") - - if name in ("__uri__", "__url__"): - return meta["Project-URL"].split(" ", 1)[-1] - - if name == "__email__": - return meta["Author-email"].split("<", 1)[1].rstrip(">") - - return meta[dunder_to_metadata[name]] diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/__main__.py b/backend/venv39/lib/python3.9/site-packages/argon2/__main__.py deleted file mode 100644 index 80ba933..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/__main__.py +++ /dev/null @@ -1,91 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import argparse -import sys -import timeit - -from . import ( - DEFAULT_HASH_LENGTH, - DEFAULT_MEMORY_COST, - DEFAULT_PARALLELISM, - DEFAULT_TIME_COST, - PasswordHasher, - profiles, -) - - -def main(argv: list[str]) -> None: - parser = argparse.ArgumentParser( - description="Benchmark Argon2.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "-n", type=int, default=100, help="Number of iterations to measure." - ) - parser.add_argument( - "-t", type=int, help="`time_cost`", default=DEFAULT_TIME_COST - ) - parser.add_argument( - "-m", type=int, help="`memory_cost`", default=DEFAULT_MEMORY_COST - ) - parser.add_argument( - "-p", type=int, help="`parallelism`", default=DEFAULT_PARALLELISM - ) - parser.add_argument( - "-l", type=int, help="`hash_length`", default=DEFAULT_HASH_LENGTH - ) - parser.add_argument( - "--profile", - type=str, - help="A profile from `argon2.profiles. Takes precedence.", - default=None, - ) - - args = parser.parse_args(argv[1:]) - - password = b"secret" - if args.profile: - ph = PasswordHasher.from_parameters( - getattr(profiles, args.profile.upper()) - ) - else: - ph = PasswordHasher( - time_cost=args.t, - memory_cost=args.m, - parallelism=args.p, - hash_len=args.l, - ) - hash = ph.hash(password) - - print(f"Running Argon2id {args.n} times with:") - - for name, value, units in [ - ("hash_len", ph.hash_len, "bytes"), - ("memory_cost", ph.memory_cost, "KiB"), - ("parallelism", ph.parallelism, "threads"), - ("time_cost", ph.time_cost, "iterations"), - ]: - print(f"{name}: {value} {units}") - - print("\nMeasuring...") - duration = timeit.timeit( - f"ph.verify({hash!r}, {password!r})", - setup=f"""\ -from argon2 import PasswordHasher - -ph = PasswordHasher( - time_cost={args.t!r}, - memory_cost={args.m!r}, - parallelism={args.p!r}, - hash_len={args.l!r}, -) -gc.enable()""", - number=args.n, - ) - print(f"\n{duration / args.n * 1000:.1f}ms per password verification") - - -if __name__ == "__main__": # pragma: no cover - main(sys.argv) diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/_legacy.py b/backend/venv39/lib/python3.9/site-packages/argon2/_legacy.py deleted file mode 100644 index 05a1e81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/_legacy.py +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Legacy mid-level functions. -""" - -from __future__ import annotations - -import os -import warnings - -from typing import Literal - -from ._password_hasher import ( - DEFAULT_HASH_LENGTH, - DEFAULT_MEMORY_COST, - DEFAULT_PARALLELISM, - DEFAULT_RANDOM_SALT_LENGTH, - DEFAULT_TIME_COST, -) -from .low_level import Type, hash_secret, hash_secret_raw, verify_secret - - -_INSTEAD = " is deprecated, use argon2.PasswordHasher instead" - - -def hash_password( - password: bytes, - salt: bytes | None = None, - time_cost: int = DEFAULT_TIME_COST, - memory_cost: int = DEFAULT_MEMORY_COST, - parallelism: int = DEFAULT_PARALLELISM, - hash_len: int = DEFAULT_HASH_LENGTH, - type: Type = Type.I, -) -> bytes: - """ - Legacy alias for :func:`argon2.low_level.hash_secret` with default - parameters. - - .. deprecated:: 16.0.0 - Use :class:`argon2.PasswordHasher` for passwords. - """ - warnings.warn( - "argon2.hash_password" + _INSTEAD, DeprecationWarning, stacklevel=2 - ) - if salt is None: - salt = os.urandom(DEFAULT_RANDOM_SALT_LENGTH) - return hash_secret( - password, salt, time_cost, memory_cost, parallelism, hash_len, type - ) - - -def hash_password_raw( - password: bytes, - salt: bytes | None = None, - time_cost: int = DEFAULT_TIME_COST, - memory_cost: int = DEFAULT_MEMORY_COST, - parallelism: int = DEFAULT_PARALLELISM, - hash_len: int = DEFAULT_HASH_LENGTH, - type: Type = Type.I, -) -> bytes: - """ - Legacy alias for :func:`argon2.low_level.hash_secret_raw` with default - parameters. - - .. deprecated:: 16.0.0 - Use :class:`argon2.PasswordHasher` for passwords. - """ - warnings.warn( - "argon2.hash_password_raw" + _INSTEAD, DeprecationWarning, stacklevel=2 - ) - if salt is None: - salt = os.urandom(DEFAULT_RANDOM_SALT_LENGTH) - return hash_secret_raw( - password, salt, time_cost, memory_cost, parallelism, hash_len, type - ) - - -def verify_password( - hash: bytes, password: bytes, type: Type = Type.I -) -> Literal[True]: - """ - Legacy alias for :func:`argon2.low_level.verify_secret` with default - parameters. - - .. deprecated:: 16.0.0 - Use :class:`argon2.PasswordHasher` for passwords. - """ - warnings.warn( - "argon2.verify_password" + _INSTEAD, DeprecationWarning, stacklevel=2 - ) - return verify_secret(hash, password, type) diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/_password_hasher.py b/backend/venv39/lib/python3.9/site-packages/argon2/_password_hasher.py deleted file mode 100644 index ddf1ce5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/_password_hasher.py +++ /dev/null @@ -1,287 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import os - -from typing import ClassVar, Literal - -from ._utils import ( - Parameters, - _check_types, - extract_parameters, - validate_params_for_platform, -) -from .exceptions import InvalidHashError -from .low_level import Type, hash_secret, verify_secret -from .profiles import get_default_parameters - - -default_params = get_default_parameters() - -DEFAULT_RANDOM_SALT_LENGTH = default_params.salt_len -DEFAULT_HASH_LENGTH = default_params.hash_len -DEFAULT_TIME_COST = default_params.time_cost -DEFAULT_MEMORY_COST = default_params.memory_cost -DEFAULT_PARALLELISM = default_params.parallelism - - -def _ensure_bytes(s: bytes | str, encoding: str) -> bytes: - """ - Ensure *s* is a bytes string. Encode using *encoding* if it isn't. - """ - if isinstance(s, bytes): - return s - return s.encode(encoding) - - -class PasswordHasher: - r""" - High level class to hash passwords with sensible defaults. - - Uses Argon2\ **id** by default and uses a random salt_ for hashing. But it - can verify any type of Argon2 as long as the hash is correctly encoded. - - The reason for this being a class is both for convenience to carry - parameters and to verify the parameters only *once*. Any unnecessary - slowdown when hashing is a tangible advantage for a brute-force attacker. - - Args: - time_cost: - Defines the amount of computation realized and therefore the - execution time, given in number of iterations. - - memory_cost: Defines the memory usage, given in kibibytes_. - - parallelism: - Defines the number of parallel threads (*changes* the resulting - hash value). - - hash_len: Length of the hash in bytes. - - salt_len: Length of random salt to be generated for each password. - - encoding: - The Argon2 C library expects bytes. So if :meth:`hash` or - :meth:`verify` are passed a ``str``, it will be encoded using this - encoding. - - type: - Argon2 type to use. Only change for interoperability with legacy - systems. - - .. versionadded:: 16.0.0 - .. versionchanged:: 18.2.0 - Switch from Argon2i to Argon2id based on the recommendation by the - current RFC draft. See also :doc:`parameters`. - .. versionchanged:: 18.2.0 - Changed default *memory_cost* to 100 MiB and default *parallelism* to 8. - .. versionchanged:: 18.2.0 ``verify`` now will determine the type of hash. - .. versionchanged:: 18.3.0 The Argon2 type is configurable now. - .. versionadded:: 21.2.0 :meth:`from_parameters` - .. versionchanged:: 21.2.0 - Changed defaults to :data:`argon2.profiles.RFC_9106_LOW_MEMORY`. - - .. _salt: https://en.wikipedia.org/wiki/Salt_(cryptography) - .. _kibibytes: https://en.wikipedia.org/wiki/Binary_prefix#kibi - """ - - __slots__ = ["_parameters", "encoding"] - - _parameters: Parameters - encoding: str - - def __init__( - self, - time_cost: int = DEFAULT_TIME_COST, - memory_cost: int = DEFAULT_MEMORY_COST, - parallelism: int = DEFAULT_PARALLELISM, - hash_len: int = DEFAULT_HASH_LENGTH, - salt_len: int = DEFAULT_RANDOM_SALT_LENGTH, - encoding: str = "utf-8", - type: Type = Type.ID, - ): - e = _check_types( - time_cost=(time_cost, int), - memory_cost=(memory_cost, int), - parallelism=(parallelism, int), - hash_len=(hash_len, int), - salt_len=(salt_len, int), - encoding=(encoding, str), - type=(type, Type), - ) - if e: - raise TypeError(e) - - params = Parameters( - type=type, - version=19, - salt_len=salt_len, - hash_len=hash_len, - time_cost=time_cost, - memory_cost=memory_cost, - parallelism=parallelism, - ) - - validate_params_for_platform(params) - - # Cache a Parameters object for check_needs_rehash. - self._parameters = params - self.encoding = encoding - - @classmethod - def from_parameters(cls, params: Parameters) -> PasswordHasher: - """ - Construct a `PasswordHasher` from *params*. - - Returns: - A `PasswordHasher` instance with the parameters from *params*. - - .. versionadded:: 21.2.0 - """ - - return cls( - time_cost=params.time_cost, - memory_cost=params.memory_cost, - parallelism=params.parallelism, - hash_len=params.hash_len, - salt_len=params.salt_len, - type=params.type, - ) - - @property - def time_cost(self) -> int: - return self._parameters.time_cost - - @property - def memory_cost(self) -> int: - return self._parameters.memory_cost - - @property - def parallelism(self) -> int: - return self._parameters.parallelism - - @property - def hash_len(self) -> int: - return self._parameters.hash_len - - @property - def salt_len(self) -> int: - return self._parameters.salt_len - - @property - def type(self) -> Type: - return self._parameters.type - - def hash(self, password: str | bytes, *, salt: bytes | None = None) -> str: - """ - Hash *password* and return an encoded hash. - - Args: - password: Password to hash. - - salt: - If None, a random salt is securely created. - - .. danger:: - - You should **not** pass a salt unless you really know what - you are doing. - - Raises: - argon2.exceptions.HashingError: If hashing fails. - - Returns: - Hashed *password*. - - .. versionadded:: 23.1.0 *salt* parameter - """ - return hash_secret( - secret=_ensure_bytes(password, self.encoding), - salt=salt or os.urandom(self.salt_len), - time_cost=self.time_cost, - memory_cost=self.memory_cost, - parallelism=self.parallelism, - hash_len=self.hash_len, - type=self.type, - ).decode("ascii") - - _header_to_type: ClassVar[dict[bytes, Type]] = { - b"$argon2i$": Type.I, - b"$argon2d$": Type.D, - b"$argon2id": Type.ID, - } - - def verify( - self, hash: str | bytes, password: str | bytes - ) -> Literal[True]: - """ - Verify that *password* matches *hash*. - - .. warning:: - - It is assumed that the caller is in full control of the hash. No - other parsing than the determination of the hash type is done by - *argon2-cffi*. - - Args: - hash: An encoded hash as returned from :meth:`PasswordHasher.hash`. - - password: The password to verify. - - Raises: - argon2.exceptions.VerifyMismatchError: - If verification fails because *hash* is not valid for - *password*. - - argon2.exceptions.VerificationError: - If verification fails for other reasons. - - argon2.exceptions.InvalidHashError: - If *hash* is so clearly invalid, that it couldn't be passed to - Argon2. - - Returns: - ``True`` on success, otherwise an exception is raised. - - .. versionchanged:: 16.1.0 - Raise :exc:`~argon2.exceptions.VerifyMismatchError` on mismatches - instead of its more generic superclass. - .. versionadded:: 18.2.0 Hash type agility. - """ - hash = _ensure_bytes(hash, "ascii") - try: - hash_type = self._header_to_type[hash[:9]] - except LookupError: - raise InvalidHashError from None - - return verify_secret( - hash, _ensure_bytes(password, self.encoding), hash_type - ) - - def check_needs_rehash(self, hash: str | bytes) -> bool: - """ - Check whether *hash* was created using the instance's parameters. - - Whenever your Argon2 parameters -- or *argon2-cffi*'s defaults! -- - change, you should rehash your passwords at the next opportunity. The - common approach is to do that whenever a user logs in, since that - should be the only time when you have access to the cleartext - password. - - Therefore it's best practice to check -- and if necessary rehash -- - passwords after each successful authentication. - - Args: - hash: An encoded Argon2 password hash. - - Returns: - Whether *hash* was created using the instance's parameters. - - .. versionadded:: 18.2.0 - .. versionchanged:: 24.1.0 Accepts bytes for *hash*. - """ - if isinstance(hash, bytes): - hash = hash.decode("ascii") - - return self._parameters != extract_parameters(hash) diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/_utils.py b/backend/venv39/lib/python3.9/site-packages/argon2/_utils.py deleted file mode 100644 index 21a6362..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/_utils.py +++ /dev/null @@ -1,174 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import platform -import sys - -from dataclasses import dataclass -from typing import Any - -from .exceptions import InvalidHashError, UnsupportedParametersError -from .low_level import Type - - -NoneType = type(None) - - -def _check_types(**kw: Any) -> str | None: - """ - Check each ``name: (value, types)`` in *kw*. - - Returns a human-readable string of all violations or `None``. - """ - errors = [] - for name, (value, types) in kw.items(): - if not isinstance(value, types): - if isinstance(types, tuple): - types = ", or ".join(t.__name__ for t in types) - else: - types = types.__name__ - errors.append( - f"'{name}' must be a {types} (got {type(value).__name__})" - ) - - if errors != []: - return ", ".join(errors) + "." - - return None - - -def _is_wasm() -> bool: - return sys.platform == "emscripten" or platform.machine() in [ - "wasm32", - "wasm64", - ] - - -def _decoded_str_len(length: int) -> int: - """ - Compute how long an encoded string of length *l* becomes. - """ - rem = length % 4 - - if rem == 3: - last_group_len = 2 - elif rem == 2: - last_group_len = 1 - else: - last_group_len = 0 - - return length // 4 * 3 + last_group_len - - -@dataclass -class Parameters: - """ - Argon2 hash parameters. - - See :doc:`parameters` on how to pick them. - - Attributes: - type: Hash type. - - version: Argon2 version. - - salt_len: Length of the salt in bytes. - - hash_len: Length of the hash in bytes. - - time_cost: Time cost in iterations. - - memory_cost: Memory cost in kibibytes. - - parallelism: Number of parallel threads. - - .. versionadded:: 18.2.0 - """ - - type: Type - version: int - salt_len: int - hash_len: int - time_cost: int - memory_cost: int - parallelism: int - - __slots__ = ( - "hash_len", - "memory_cost", - "parallelism", - "salt_len", - "time_cost", - "type", - "version", - ) - - -_NAME_TO_TYPE = {"argon2id": Type.ID, "argon2i": Type.I, "argon2d": Type.D} -_REQUIRED_KEYS = sorted(("v", "m", "t", "p")) - - -def extract_parameters(hash: str) -> Parameters: - """ - Extract parameters from an encoded *hash*. - - Args: - hash: An encoded Argon2 hash string. - - Returns: - The parameters used to create the hash. - - .. versionadded:: 18.2.0 - """ - parts = hash.split("$") - - # Backwards compatibility for Argon v1.2 hashes - if len(parts) == 5: - parts.insert(2, "v=18") - - if len(parts) != 6: - raise InvalidHashError - - if parts[0]: - raise InvalidHashError - - try: - type = _NAME_TO_TYPE[parts[1]] - - kvs = { - k: int(v) - for k, v in ( - s.split("=") for s in [parts[2], *parts[3].split(",")] - ) - } - except Exception: # noqa: BLE001 - raise InvalidHashError from None - - if sorted(kvs.keys()) != _REQUIRED_KEYS: - raise InvalidHashError - - return Parameters( - type=type, - salt_len=_decoded_str_len(len(parts[4])), - hash_len=_decoded_str_len(len(parts[5])), - version=kvs["v"], - time_cost=kvs["t"], - memory_cost=kvs["m"], - parallelism=kvs["p"], - ) - - -def validate_params_for_platform(params: Parameters) -> None: - """ - Validate *params* against current platform. - - Args: - params: Parameters to be validated - - Returns: - None - """ - if _is_wasm() and params.parallelism != 1: - msg = "In WebAssembly environments `parallelism` must be 1." - raise UnsupportedParametersError(msg) diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/exceptions.py b/backend/venv39/lib/python3.9/site-packages/argon2/exceptions.py deleted file mode 100644 index a0dade5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/exceptions.py +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - - -class Argon2Error(Exception): - """ - Superclass of all argon2 exceptions. - - Never thrown directly. - """ - - -class VerificationError(Argon2Error): - """ - Verification failed. - - You can find the original error message from Argon2 in ``args[0]``. - """ - - -class VerifyMismatchError(VerificationError): - """ - The secret does not match the hash. - - Subclass of :exc:`argon2.exceptions.VerificationError`. - - .. versionadded:: 16.1.0 - """ - - -class HashingError(Argon2Error): - """ - Raised if hashing failed. - - You can find the original error message from Argon2 in ``args[0]``. - """ - - -class InvalidHashError(ValueError): - """ - Raised if the hash is invalid before passing it to Argon2. - - .. versionadded:: 23.1.0 - As a replacement for :exc:`argon2.exceptions.InvalidHash`. - """ - - -class UnsupportedParametersError(ValueError): - """ - Raised if the current platform does not support the parameters. - - For example, in WebAssembly parallelism must be set to 1. - - .. versionadded:: 25.1.0 - """ - - -InvalidHash = InvalidHashError -""" -Deprecated alias for :class:`InvalidHashError`. - -.. versionadded:: 18.2.0 -.. deprecated:: 23.1.0 - Use :exc:`argon2.exceptions.InvalidHashError` instead. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/low_level.py b/backend/venv39/lib/python3.9/site-packages/argon2/low_level.py deleted file mode 100644 index 0598466..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/low_level.py +++ /dev/null @@ -1,253 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Low-level functions if you want to build your own higher level abstractions. - -.. warning:: - This is a "Hazardous Materials" module. You should **ONLY** use it if - you're 100% absolutely sure that you know what you're doing because this - module is full of land mines, dragons, and dinosaurs with laser guns. -""" - -from __future__ import annotations - -from enum import Enum -from typing import Any, Literal - -from _argon2_cffi_bindings import ffi, lib - -from .exceptions import HashingError, VerificationError, VerifyMismatchError - - -__all__ = [ - "ARGON2_VERSION", - "Type", - "ffi", - "hash_secret", - "hash_secret_raw", - "verify_secret", -] - -ARGON2_VERSION = lib.ARGON2_VERSION_NUMBER -""" -The latest version of the Argon2 algorithm that is supported (and used by -default). - -.. versionadded:: 16.1.0 -""" - - -class Type(Enum): - """ - Enum of Argon2 variants. - - Please see :doc:`parameters` on how to pick one. - """ - - D = lib.Argon2_d - I = lib.Argon2_i # noqa: E741 - ID = lib.Argon2_id - - -def hash_secret( - secret: bytes, - salt: bytes, - time_cost: int, - memory_cost: int, - parallelism: int, - hash_len: int, - type: Type, - version: int = ARGON2_VERSION, -) -> bytes: - """ - Hash *secret* and return an **encoded** hash. - - An encoded hash can be directly passed into :func:`verify_secret` as it - contains all parameters and the salt. - - Args: - secret: Secret to hash. - - salt: A salt_. Should be random and different for each secret. - - type: Which Argon2 variant to use. - - version: Which Argon2 version to use. - - For an explanation of the Argon2 parameters see - :class:`argon2.PasswordHasher`. - - Returns: - An encoded Argon2 hash. - - Raises: - argon2.exceptions.HashingError: If hashing fails. - - .. versionadded:: 16.0.0 - - .. _salt: https://en.wikipedia.org/wiki/Salt_(cryptography) - """ - size = ( - lib.argon2_encodedlen( - time_cost, - memory_cost, - parallelism, - len(salt), - hash_len, - type.value, - ) - + 1 - ) - buf = ffi.new("char[]", size) - rv = lib.argon2_hash( - time_cost, - memory_cost, - parallelism, - ffi.new("uint8_t[]", secret), - len(secret), - ffi.new("uint8_t[]", salt), - len(salt), - ffi.NULL, - hash_len, - buf, - size, - type.value, - version, - ) - if rv != lib.ARGON2_OK: - raise HashingError(error_to_str(rv)) - - return ffi.string(buf) # type: ignore[no-any-return] - - -def hash_secret_raw( - secret: bytes, - salt: bytes, - time_cost: int, - memory_cost: int, - parallelism: int, - hash_len: int, - type: Type, - version: int = ARGON2_VERSION, -) -> bytes: - """ - Hash *password* and return a **raw** hash. - - This function takes the same parameters as :func:`hash_secret`. - - .. versionadded:: 16.0.0 - """ - buf = ffi.new("uint8_t[]", hash_len) - - rv = lib.argon2_hash( - time_cost, - memory_cost, - parallelism, - ffi.new("uint8_t[]", secret), - len(secret), - ffi.new("uint8_t[]", salt), - len(salt), - buf, - hash_len, - ffi.NULL, - 0, - type.value, - version, - ) - if rv != lib.ARGON2_OK: - raise HashingError(error_to_str(rv)) - - return bytes(ffi.buffer(buf, hash_len)) - - -def verify_secret(hash: bytes, secret: bytes, type: Type) -> Literal[True]: - """ - Verify whether *secret* is correct for *hash* of *type*. - - Args: - hash: - An encoded Argon2 hash as returned by :func:`hash_secret`. - - secret: - The secret to verify whether it matches the one in *hash*. - - type: Type for *hash*. - - Raises: - argon2.exceptions.VerifyMismatchError: - If verification fails because *hash* is not valid for *secret* of - *type*. - - argon2.exceptions.VerificationError: - If verification fails for other reasons. - - Returns: - ``True`` on success, raise :exc:`~argon2.exceptions.VerificationError` - otherwise. - - .. versionadded:: 16.0.0 - .. versionchanged:: 16.1.0 - Raise :exc:`~argon2.exceptions.VerifyMismatchError` on mismatches - instead of its more generic superclass. - """ - rv = lib.argon2_verify( - ffi.new("char[]", hash), - ffi.new("uint8_t[]", secret), - len(secret), - type.value, - ) - - if rv == lib.ARGON2_OK: - return True - - if rv == lib.ARGON2_VERIFY_MISMATCH: - raise VerifyMismatchError(error_to_str(rv)) - - raise VerificationError(error_to_str(rv)) - - -def core(context: Any, type: int) -> int: - """ - Direct binding to the ``argon2_ctx`` function. - - .. warning:: - This is a strictly advanced function working on raw C data structures. - Both Argon2's and *argon2-cffi*'s higher-level bindings do a lot of - sanity checks and housekeeping work that *you* are now responsible for - (e.g. clearing buffers). The structure of the *context* object can, - has, and will change with *any* release! - - Use at your own peril; *argon2-cffi* does *not* use this binding - itself. - - Args: - context: - A CFFI Argon2 context object (i.e. an ``struct Argon2_Context`` / - ``argon2_context``). - - type: - Which Argon2 variant to use. You can use the ``value`` field of - :class:`Type`'s fields. - - Returns: - An Argon2 error code. Can be transformed into a string using - :func:`error_to_str`. - - .. versionadded:: 16.0.0 - """ - return lib.argon2_ctx(context, type) # type: ignore[no-any-return] - - -def error_to_str(error: int) -> str: - """ - Convert an Argon2 error code into a native string. - - Args: - error: An Argon2 error code as returned by :func:`core`. - - Returns: - A human-readable string describing the error. - - .. versionadded:: 16.0.0 - """ - return ffi.string(lib.argon2_error_message(error)).decode("ascii") # type: ignore[no-any-return] diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/profiles.py b/backend/venv39/lib/python3.9/site-packages/argon2/profiles.py deleted file mode 100644 index e6fd69b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2/profiles.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -This module offers access to standardized parameters that you can load using -:meth:`argon2.PasswordHasher.from_parameters()`. See the `source code -`_ for -concrete values and :doc:`parameters` for more information. - -.. versionadded:: 21.2.0 -""" - -from __future__ import annotations - -import dataclasses - -from ._utils import Parameters, _is_wasm -from .low_level import Type - - -def get_default_parameters() -> Parameters: - """ - Create default parameters for current platform. - - Returns: - Default, compatible, parameters for current platform. - - .. versionadded:: 25.1.0 - """ - params = RFC_9106_LOW_MEMORY - - if _is_wasm(): - params = dataclasses.replace(params, parallelism=1) - - return params - - -# FIRST RECOMMENDED option per RFC 9106. -RFC_9106_HIGH_MEMORY = Parameters( - type=Type.ID, - version=19, - salt_len=16, - hash_len=32, - time_cost=1, - memory_cost=2097152, # 2 GiB - parallelism=4, -) - -# SECOND RECOMMENDED option per RFC 9106. -RFC_9106_LOW_MEMORY = Parameters( - type=Type.ID, - version=19, - salt_len=16, - hash_len=32, - time_cost=3, - memory_cost=65536, # 64 MiB - parallelism=4, -) - -# The pre-RFC defaults in argon2-cffi 18.2.0 - 21.1.0. -PRE_21_2 = Parameters( - type=Type.ID, - version=19, - salt_len=16, - hash_len=16, - time_cost=2, - memory_cost=102400, # 100 MiB - parallelism=8, -) - -# Only for testing! -CHEAPEST = Parameters( - type=Type.ID, - version=19, - salt_len=8, - hash_len=4, - time_cost=1, - memory_cost=8, - parallelism=1, -) diff --git a/backend/venv39/lib/python3.9/site-packages/argon2/py.typed b/backend/venv39/lib/python3.9/site-packages/argon2/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/METADATA deleted file mode 100644 index a138028..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/METADATA +++ /dev/null @@ -1,105 +0,0 @@ -Metadata-Version: 2.4 -Name: argon2-cffi -Version: 25.1.0 -Summary: Argon2 for Python -Project-URL: Documentation, https://argon2-cffi.readthedocs.io/ -Project-URL: Changelog, https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md -Project-URL: GitHub, https://github.com/hynek/argon2-cffi -Project-URL: Funding, https://github.com/sponsors/hynek -Project-URL: Tidelift, https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek -Author-email: Hynek Schlawack -License-Expression: MIT -License-File: LICENSE -Keywords: hash,hashing,password,security -Classifier: Development Status :: 5 - Production/Stable -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: POSIX -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Security :: Cryptography -Classifier: Typing :: Typed -Requires-Python: >=3.8 -Requires-Dist: argon2-cffi-bindings -Description-Content-Type: text/markdown - -# *argon2-cffi*: Argon2 for Python - - -[Argon2](https://github.com/p-h-c/phc-winner-argon2) won the [Password Hashing Competition](https://www.password-hashing.net/) and *argon2-cffi* is the simplest way to use it in Python: - -```pycon ->>> from argon2 import PasswordHasher ->>> ph = PasswordHasher() ->>> hash = ph.hash("correct horse battery staple") ->>> hash # doctest: +SKIP -'$argon2id$v=19$m=65536,t=3,p=4$MIIRqgvgQbgj220jfp0MPA$YfwJSVjtjSU0zzV/P3S9nnQ/USre2wvJMjfCIjrTQbg' ->>> ph.verify(hash, "correct horse battery staple") -True ->>> ph.check_needs_rehash(hash) -False ->>> ph.verify(hash, "Tr0ub4dor&3") -Traceback (most recent call last): - ... -argon2.exceptions.VerifyMismatchError: The password does not match the supplied hash - -``` - - -## Project Links - -- [**PyPI**](https://pypi.org/project/argon2-cffi/) -- [**GitHub**](https://github.com/hynek/argon2-cffi) -- [**Documentation**](https://argon2-cffi.readthedocs.io/) -- [**Changelog**](https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md) -- [**Funding**](https://hynek.me/say-thanks/) -- The low-level Argon2 CFFI bindings are maintained in the separate [*argon2-cffi-bindings*](https://github.com/hynek/argon2-cffi-bindings) project. - -## Release Information - -### Added - -- Official support for Python 3.13 and 3.14. - No code changes were necessary. - - -### Removed - -- Python 3.7 is not supported anymore. - [#186](https://github.com/hynek/argon2-cffi/pull/186) - - -### Changed - -- `argon2.PasswordHasher.check_needs_rehash()` now also accepts bytes like the rest of the API. - [#174](https://github.com/hynek/argon2-cffi/pull/174) - -- Improved parameter compatibility handling for Pyodide / WebAssembly environments. - [#190](https://github.com/hynek/argon2-cffi/pull/190) - - ---- - -[Full Changelog →](https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md) - - -## Credits - -*argon2-cffi* is maintained by [Hynek Schlawack](https://hynek.me/). - -The development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *argon2-cffi* [Tidelift subscribers](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). - - -## *argon2-cffi* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *argon2-cffi* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open-source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/RECORD deleted file mode 100644 index 9a9b319..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/RECORD +++ /dev/null @@ -1,22 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/_legacy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/_password_hasher.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/low_level.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/argon2/profiles.cpython-39.pyc,, -argon2/__init__.py,sha256=N4S3LvR1y3WstysObwDQsF4yt8NpEot8uGAmy_MZ5fw,1869 -argon2/__main__.py,sha256=bCi1rJkhMBpiDZe3W-MfC2DFH5wYJH4RDmySLcL_Jwg,2332 -argon2/_legacy.py,sha256=eIfk7SWuIQQGZz3FY80YW4XQQAnrjzFgeyRFgo2KtCo,2416 -argon2/_password_hasher.py,sha256=pJgSap4C2ey74IUDifbbR_Eeq-GeXvl3nRZc1Qzv3jI,8839 -argon2/_utils.py,sha256=Y3JkroYRioSHXQ5E3Sav7CclqAZkCXKo1cbsJiwqgZk,3751 -argon2/exceptions.py,sha256=sA6k8Tnlqce5uGNNbOQG2PggV91EFd2ZE2dIiB4H6nU,1322 -argon2/low_level.py,sha256=QMSxPwUQPPanGKqJqLExUh4gtqw0u49QPEqjz1nNlYM,6172 -argon2/profiles.py,sha256=nK2-7oYFuGtDxev9g050bFZsh214qwlEX3qejwOQEMY,1650 -argon2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -argon2_cffi-25.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -argon2_cffi-25.1.0.dist-info/METADATA,sha256=6QhRB1toJh-sz0B7KUMPRealsaB1mg1QuNkxAbDeIXk,4119 -argon2_cffi-25.1.0.dist-info/RECORD,, -argon2_cffi-25.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -argon2_cffi-25.1.0.dist-info/licenses/LICENSE,sha256=tpRNOG6HzPSdljLaCDaFpLdiRzPmhqf-KD3S1Cg0HXc,1115 diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/licenses/LICENSE deleted file mode 100644 index d1b626b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi-25.1.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack and the argon2-cffi contributors - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/METADATA deleted file mode 100644 index 052a20a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/METADATA +++ /dev/null @@ -1,153 +0,0 @@ -Metadata-Version: 2.4 -Name: argon2-cffi-bindings -Version: 25.1.0 -Summary: Low-level CFFI bindings for Argon2 -Author-email: Hynek Schlawack -License-Expression: MIT -Project-URL: Tidelift, https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek -Project-URL: Changelog, https://github.com/hynek/argon2-cffi-bindings/blob/main/CHANGELOG.md -Project-URL: GitHub, https://github.com/hynek/argon2-cffi-bindings -Project-URL: Funding, https://github.com/sponsors/hynek -Keywords: password,hash,hashing,security,bindings,cffi -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: POSIX -Classifier: Operating System :: Unix -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Free Threading -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Security :: Cryptography -Classifier: Topic :: Security -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: cffi>=1.0.1; python_version < "3.14" -Requires-Dist: cffi>=2.0.0b1; python_version >= "3.14" -Dynamic: license-file - -# Low-level Python CFFI Bindings for Argon2 - -[![License: MIT](https://img.shields.io/badge/license-MIT-C06524)](https://github.com/hynek/argon2-cffi-bindings/blob/main/LICENSE) -[![PyPI version](https://img.shields.io/pypi/v/argon2-cffi-bindings)](https://pypi.org/project/argon2-cffi-bindings/) -[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/argon2-cffi-bindings.svg)](https://pypi.org/project/argon2-cffi-bindings) - -*argon2-cffi-bindings* provides low-level [CFFI](https://cffi.readthedocs.io/) bindings to the official implementation of the [Argon2] password hashing algorithm. - - -The currently vendored Argon2 commit ID is [**`f57e61e`**](https://github.com/P-H-C/phc-winner-argon2/commit/f57e61e19229e23c4445b85494dbf7c07de721cb). - - -> [!NOTE] -> If you want to hash passwords in an application, this package is **not** for you. -> Have a look at [*argon2-cffi*] with its high-level abstractions! - -These bindings have been extracted from [*argon2-cffi*] and it remains its main consumer. -However, they may be used by other packages that want to use the Argon2 library without dealing with C-related complexities. - - -## Usage - -*argon2-cffi-bindings* is available from [PyPI](https://pypi.org/project/argon2-cffi-bindings/). -The provided CFFI bindings are compiled in API mode. - -Best effort is given to provide binary wheels for as many platforms as possible. - - -### Disabling Vendored Code - -A copy of [Argon2] is vendored and used by default, but can be disabled if *argon2-cffi-bindings* is installed using: - -```console -$ env ARGON2_CFFI_USE_SYSTEM=1 \ - python -Im pip install --no-binary=argon2-cffi-bindings argon2-cffi-bindings -``` - - -### Overriding Automatic SSE2 Detection - -Usually the build process tries to guess whether or not it should use [SSE2](https://en.wikipedia.org/wiki/SSE2)-optimized code (see [`_ffi_build.py`](https://github.com/hynek/argon2-cffi-bindings/blob/main/src/_argon2_cffi_bindings/_ffi_build.py) for details). -This can go wrong and is problematic for cross-compiling. - -Therefore you can use the `ARGON2_CFFI_USE_SSE2` environment variable to control the process: - -- If you set it to ``1``, *argon2-cffi-bindings* will build **with** SSE2 support. -- If you set it to ``0``, *argon2-cffi-bindings* will build **without** SSE2 support. -- If you set it to anything else, it will be ignored and *argon2-cffi-bindings* will try to guess. - -However, if our heuristics fail you, we would welcome a bug report. - - -### Python API - -Since this package is intended to be an implementation detail, it uses a private module name to prevent your users from using it by accident. - -Therefore you have to import the symbols from `_argon2_cffi_bindings`: - -```python -from _argon2_cffi_bindings import ffi, lib -``` - -Please refer to [*cffi* documentation](https://cffi.readthedocs.io/en/latest/using.html) on how to use the `ffi` and `lib` objects. - -The list of symbols that are provided can be found in the [`_ffi_build.py` file](https://github.com/hynek/argon2-cffi-bindings/blob/main/src/_argon2_cffi_bindings/_ffi_build.py). - -[Argon2]: https://github.com/p-h-c/phc-winner-argon2 -[*argon2-cffi*]: https://argon2-cffi.readthedocs.io/ - - -## Project Information - -- [**Changelog**](https://github.com/hynek/argon2-cffi-bindings/blob/main/CHANGELOG.md) -- [**Documentation**](https://github.com/hynek/argon2-cffi-bindings#readme) -- [**PyPI**](https://pypi.org/project/argon2-cffi-bindings/) -- [**Source Code**](https://github.com/hynek/argon2-cffi-bindings) - - -### Credits & License - -*argon2-cffi-bindings* is written and maintained by [Hynek Schlawack](https://hynek.me/about/). -It is released under the [MIT license](https://github.com/hynek/argon2-cffi/blob/main/LICENSE>). - -The development is kindly supported by [Variomedia AG](https://www.variomedia.de/) and all my amazing [GitHub Sponsors](https://github.com/sponsors/hynek). - -The authors of Argon2 were very helpful to get the library to compile on ancient versions of Visual Studio for ancient versions of Python. - -The documentation quotes frequently in verbatim from the Argon2 [paper](https://www.password-hashing.net/argon2-specs.pdf) to avoid mistakes by rephrasing. - - -#### Vendored Code - -The original Argon2 repo can be found at . - -Except for the components listed below, the Argon2 code in this repository is copyright (c) 2015 Daniel Dinu, Dmitry Khovratovich (main authors), Jean-Philippe Aumasson and Samuel Neves, and under [CC0] license. - -The string encoding routines in `src/encoding.c` are copyright (c) 2015 Thomas Pornin, and under [CC0] license. - -The [BLAKE2](https://www.blake2.net) code in `src/blake2/` is copyright (c) Samuel Neves, 2013-2015, and under [CC0] license. - -[CC0]: https://creativecommons.org/publicdomain/zero/1.0/ - - -### *argon2-cffi-bindings* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *argon2-cffi-bindings* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open-source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/RECORD deleted file mode 100644 index 5b60bd3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/_argon2_cffi_bindings/_ffi_build.cpython-39.pyc,, -_argon2_cffi_bindings/__init__.py,sha256=b6Da6_RCsMXKbA9QyzKmeGqm9cYijmtkAJqNOV2V50Y,86 -_argon2_cffi_bindings/_ffi.abi3.so,sha256=lcsF9F2IHWbc9m-YniP0hl7Ci9tOni8VKbpm5pxPsf8,86160 -_argon2_cffi_bindings/_ffi_build.py,sha256=qhZUHeEejfsTqxDgJwmmtroWG3ZcfXF_5IKtgHOCnO4,6289 -argon2_cffi_bindings-25.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -argon2_cffi_bindings-25.1.0.dist-info/METADATA,sha256=Lo7NiLg2SB_yoPzTIGzhSWlonx04LFJ33dbXJA8Snw8,7352 -argon2_cffi_bindings-25.1.0.dist-info/RECORD,, -argon2_cffi_bindings-25.1.0.dist-info/WHEEL,sha256=ABbCLNyMOjk3G47ycAleK7GxTLgTblZV1QN66WnLOkk,134 -argon2_cffi_bindings-25.1.0.dist-info/licenses/LICENSE,sha256=nBWNT0M2J_SKwktrTTeXCv5BclFGc8UxgBTXzKFXxt8,1082 -argon2_cffi_bindings-25.1.0.dist-info/top_level.txt,sha256=WyRJzxvIv58cyvTye2AsVz50Lw0hDxUYBuCH1rUb_tg,27 diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/WHEEL deleted file mode 100644 index 5fe4cfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-abi3-macosx_11_0_arm64 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/licenses/LICENSE deleted file mode 100644 index 263e33c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2021 Hynek Schlawack - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/top_level.txt deleted file mode 100644 index f8264db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/argon2_cffi_bindings-25.1.0.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -_argon2_cffi_bindings -_ffi diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE deleted file mode 100644 index 033c86b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2016-2020 aio-libs collaboration. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA deleted file mode 100644 index 1eecd7d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/METADATA +++ /dev/null @@ -1,163 +0,0 @@ -Metadata-Version: 2.1 -Name: async-timeout -Version: 5.0.1 -Summary: Timeout context manager for asyncio programs -Home-page: https://github.com/aio-libs/async-timeout -Author: Andrew Svetlov -Author-email: andrew.svetlov@gmail.com -License: Apache 2 -Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby -Project-URL: CI: GitHub Actions, https://github.com/aio-libs/async-timeout/actions -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/async-timeout -Project-URL: GitHub: issues, https://github.com/aio-libs/async-timeout/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/async-timeout -Classifier: Development Status :: 5 - Production/Stable -Classifier: Topic :: Software Development :: Libraries -Classifier: Framework :: AsyncIO -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-File: LICENSE - -async-timeout -============= -.. image:: https://travis-ci.com/aio-libs/async-timeout.svg?branch=master - :target: https://travis-ci.com/aio-libs/async-timeout -.. image:: https://codecov.io/gh/aio-libs/async-timeout/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/async-timeout -.. image:: https://img.shields.io/pypi/v/async-timeout.svg - :target: https://pypi.python.org/pypi/async-timeout -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter - -asyncio-compatible timeout context manager. - - - -DEPRECATED ----------- - -This library has effectively been upstreamed into Python 3.11+. - -Therefore this library is considered deprecated and no longer actively supported. - -Version 5.0+ provides dual-mode when executed on Python 3.11+: -``asyncio_timeout.Timeout`` is fully compatible with ``asyncio.Timeout`` *and* old -versions of the library. - -Anyway, using upstream is highly recommended. ``asyncio_timeout`` exists only for the -sake of backward compatibility, easy supporting both old and new Python by the same -code, and easy misgration. - -If rescheduling API is not important and only ``async with timeout(...): ...`` functionality is required, -a user could apply conditional import:: - - if sys.version_info >= (3, 11): - from asyncio import timeout, timeout_at - else: - from async_timeout import timeout, timeout_at - - -Usage example -------------- - - -The context manager is useful in cases when you want to apply timeout -logic around block of code or in cases when ``asyncio.wait_for()`` is -not suitable. Also it's much faster than ``asyncio.wait_for()`` -because ``timeout`` doesn't create a new task. - -The ``timeout(delay, *, loop=None)`` call returns a context manager -that cancels a block on *timeout* expiring:: - - from async_timeout import timeout - async with timeout(1.5): - await inner() - -1. If ``inner()`` is executed faster than in ``1.5`` seconds nothing - happens. -2. Otherwise ``inner()`` is cancelled internally by sending - ``asyncio.CancelledError`` into but ``asyncio.TimeoutError`` is - raised outside of context manager scope. - -*timeout* parameter could be ``None`` for skipping timeout functionality. - - -Alternatively, ``timeout_at(when)`` can be used for scheduling -at the absolute time:: - - loop = asyncio.get_event_loop() - now = loop.time() - - async with timeout_at(now + 1.5): - await inner() - - -Please note: it is not POSIX time but a time with -undefined starting base, e.g. the time of the system power on. - - -Context manager has ``.expired()`` / ``.expired`` for check if timeout happens -exactly in context manager:: - - async with timeout(1.5) as cm: - await inner() - print(cm.expired()) # recommended api - print(cm.expired) # compatible api - -The property is ``True`` if ``inner()`` execution is cancelled by -timeout context manager. - -If ``inner()`` call explicitly raises ``TimeoutError`` ``cm.expired`` -is ``False``. - -The scheduled deadline time is available as ``.when()`` / ``.deadline``:: - - async with timeout(1.5) as cm: - cm.when() # recommended api - cm.deadline # compatible api - -Not finished yet timeout can be rescheduled by ``shift()`` -or ``update()`` methods:: - - async with timeout(1.5) as cm: - # recommended api - cm.reschedule(cm.when() + 1) # add another second on waiting - # compatible api - cm.shift(1) # add another second on waiting - cm.update(loop.time() + 5) # reschedule to now+5 seconds - -Rescheduling is forbidden if the timeout is expired or after exit from ``async with`` -code block. - - -Disable scheduled timeout:: - - async with timeout(1.5) as cm: - cm.reschedule(None) # recommended api - cm.reject() # compatible api - - - -Installation ------------- - -:: - - $ pip install async-timeout - -The library is Python 3 only! - - - -Authors and License -------------------- - -The module is written by Andrew Svetlov. - -It's *Apache 2* licensed and freely available. diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD deleted file mode 100644 index 656425c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/async_timeout/__init__.cpython-39.pyc,, -async_timeout-5.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -async_timeout-5.0.1.dist-info/LICENSE,sha256=4Y17uPUT4sRrtYXJS1hb0wcg3TzLId2weG9y0WZY-Sw,568 -async_timeout-5.0.1.dist-info/METADATA,sha256=RVDNEIPYIBJKPsjThJDaKRX1h79-4QYQNuBLSXPItU8,5131 -async_timeout-5.0.1.dist-info/RECORD,, -async_timeout-5.0.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91 -async_timeout-5.0.1.dist-info/top_level.txt,sha256=9oM4e7Twq8iD_7_Q3Mz0E6GPIB6vJvRFo-UBwUQtBDU,14 -async_timeout-5.0.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -async_timeout/__init__.py,sha256=QF0zpfX1vGmxib7kAqNPm9YehPV0oBVozxJ--Mxq9dI,9186 -async_timeout/py.typed,sha256=tyozzRT1fziXETDxokmuyt6jhOmtjUbnVNJdZcG7ik0,12 diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL deleted file mode 100644 index 9b78c44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (75.3.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt deleted file mode 100644 index ad29955..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -async_timeout diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe b/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout-5.0.1.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout/__init__.py b/backend/venv39/lib/python3.9/site-packages/async_timeout/__init__.py deleted file mode 100644 index fe4aa58..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout/__init__.py +++ /dev/null @@ -1,276 +0,0 @@ -import asyncio -import enum -import sys -from types import TracebackType -from typing import Optional, Type, final - - -__version__ = "5.0.1" - - -__all__ = ("timeout", "timeout_at", "Timeout") - - -def timeout(delay: Optional[float]) -> "Timeout": - """timeout context manager. - - Useful in cases when you want to apply timeout logic around block - of code or in cases when asyncio.wait_for is not suitable. For example: - - >>> async with timeout(0.001): - ... async with aiohttp.get('https://github.com') as r: - ... await r.text() - - - delay - value in seconds or None to disable timeout logic - """ - loop = asyncio.get_running_loop() - if delay is not None: - deadline = loop.time() + delay # type: Optional[float] - else: - deadline = None - return Timeout(deadline, loop) - - -def timeout_at(deadline: Optional[float]) -> "Timeout": - """Schedule the timeout at absolute time. - - deadline argument points on the time in the same clock system - as loop.time(). - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - - >>> async with timeout_at(loop.time() + 10): - ... async with aiohttp.get('https://github.com') as r: - ... await r.text() - - - """ - loop = asyncio.get_running_loop() - return Timeout(deadline, loop) - - -class _State(enum.Enum): - INIT = "INIT" - ENTER = "ENTER" - TIMEOUT = "TIMEOUT" - EXIT = "EXIT" - - -if sys.version_info >= (3, 11): - - class _Expired: - __slots__ = ("_val",) - - def __init__(self, val: bool) -> None: - self._val = val - - def __call__(self) -> bool: - return self._val - - def __bool__(self) -> bool: - return self._val - - def __repr__(self) -> str: - return repr(self._val) - - def __str__(self) -> str: - return str(self._val) - - @final - class Timeout(asyncio.Timeout): # type: ignore[misc] - # Supports full asyncio.Timeout API. - # Also provides several asyncio_timeout specific methods - # for backward compatibility. - def __init__( - self, deadline: Optional[float], loop: asyncio.AbstractEventLoop - ) -> None: - super().__init__(deadline) - - @property - def expired(self) -> _Expired: - # a hacky property hat can provide both roles: - # timeout.expired() from asyncio - # timeout.expired from asyncio_timeout - return _Expired(super().expired()) - - @property - def deadline(self) -> Optional[float]: - return self.when() - - def reject(self) -> None: - """Reject scheduled timeout if any.""" - # cancel is maybe better name but - # task.cancel() raises CancelledError in asyncio world. - self.reschedule(None) - - def shift(self, delay: float) -> None: - """Advance timeout on delay seconds. - - The delay can be negative. - - Raise RuntimeError if shift is called when deadline is not scheduled - """ - deadline = self.when() - if deadline is None: - raise RuntimeError("cannot shift timeout if deadline is not scheduled") - self.reschedule(deadline + delay) - - def update(self, deadline: float) -> None: - """Set deadline to absolute value. - - deadline argument points on the time in the same clock system - as loop.time(). - - If new deadline is in the past the timeout is raised immediately. - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - """ - self.reschedule(deadline) - -else: - - @final - class Timeout: - # Internal class, please don't instantiate it directly - # Use timeout() and timeout_at() public factories instead. - # - # Implementation note: `async with timeout()` is preferred - # over `with timeout()`. - # While technically the Timeout class implementation - # doesn't need to be async at all, - # the `async with` statement explicitly points that - # the context manager should be used from async function context. - # - # This design allows to avoid many silly misusages. - # - # TimeoutError is raised immediately when scheduled - # if the deadline is passed. - # The purpose is to time out as soon as possible - # without waiting for the next await expression. - - __slots__ = ("_deadline", "_loop", "_state", "_timeout_handler", "_task") - - def __init__( - self, deadline: Optional[float], loop: asyncio.AbstractEventLoop - ) -> None: - self._loop = loop - self._state = _State.INIT - - self._task: Optional["asyncio.Task[object]"] = None - self._timeout_handler = None # type: Optional[asyncio.Handle] - if deadline is None: - self._deadline = None # type: Optional[float] - else: - self.update(deadline) - - async def __aenter__(self) -> "Timeout": - self._do_enter() - return self - - async def __aexit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> Optional[bool]: - self._do_exit(exc_type) - return None - - @property - def expired(self) -> bool: - """Is timeout expired during execution?""" - return self._state == _State.TIMEOUT - - @property - def deadline(self) -> Optional[float]: - return self._deadline - - def reject(self) -> None: - """Reject scheduled timeout if any.""" - # cancel is maybe better name but - # task.cancel() raises CancelledError in asyncio world. - if self._state not in (_State.INIT, _State.ENTER): - raise RuntimeError(f"invalid state {self._state.value}") - self._reject() - - def _reject(self) -> None: - self._task = None - if self._timeout_handler is not None: - self._timeout_handler.cancel() - self._timeout_handler = None - - def shift(self, delay: float) -> None: - """Advance timeout on delay seconds. - - The delay can be negative. - - Raise RuntimeError if shift is called when deadline is not scheduled - """ - deadline = self._deadline - if deadline is None: - raise RuntimeError("cannot shift timeout if deadline is not scheduled") - self.update(deadline + delay) - - def update(self, deadline: float) -> None: - """Set deadline to absolute value. - - deadline argument points on the time in the same clock system - as loop.time(). - - If new deadline is in the past the timeout is raised immediately. - - Please note: it is not POSIX time but a time with - undefined starting base, e.g. the time of the system power on. - """ - if self._state == _State.EXIT: - raise RuntimeError("cannot reschedule after exit from context manager") - if self._state == _State.TIMEOUT: - raise RuntimeError("cannot reschedule expired timeout") - if self._timeout_handler is not None: - self._timeout_handler.cancel() - self._deadline = deadline - if self._state != _State.INIT: - self._reschedule() - - def _reschedule(self) -> None: - assert self._state == _State.ENTER - deadline = self._deadline - if deadline is None: - return - - now = self._loop.time() - if self._timeout_handler is not None: - self._timeout_handler.cancel() - - self._task = asyncio.current_task() - if deadline <= now: - self._timeout_handler = self._loop.call_soon(self._on_timeout) - else: - self._timeout_handler = self._loop.call_at(deadline, self._on_timeout) - - def _do_enter(self) -> None: - if self._state != _State.INIT: - raise RuntimeError(f"invalid state {self._state.value}") - self._state = _State.ENTER - self._reschedule() - - def _do_exit(self, exc_type: Optional[Type[BaseException]]) -> None: - if exc_type is asyncio.CancelledError and self._state == _State.TIMEOUT: - assert self._task is not None - self._timeout_handler = None - self._task = None - raise asyncio.TimeoutError - # timeout has not expired - self._state = _State.EXIT - self._reject() - return None - - def _on_timeout(self) -> None: - assert self._task is not None - self._task.cancel() - self._state = _State.TIMEOUT - # drop the reference early - self._timeout_handler = None diff --git a/backend/venv39/lib/python3.9/site-packages/async_timeout/py.typed b/backend/venv39/lib/python3.9/site-packages/async_timeout/py.typed deleted file mode 100644 index 3b94f91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/async_timeout/py.typed +++ /dev/null @@ -1 +0,0 @@ -Placeholder diff --git a/backend/venv39/lib/python3.9/site-packages/attr/__init__.py b/backend/venv39/lib/python3.9/site-packages/attr/__init__.py deleted file mode 100644 index 5c6e065..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Classes Without Boilerplate -""" - -from functools import partial -from typing import Callable, Literal, Protocol - -from . import converters, exceptions, filters, setters, validators -from ._cmp import cmp_using -from ._config import get_run_validators, set_run_validators -from ._funcs import asdict, assoc, astuple, has, resolve_types -from ._make import ( - NOTHING, - Attribute, - Converter, - Factory, - _Nothing, - attrib, - attrs, - evolve, - fields, - fields_dict, - make_class, - validate, -) -from ._next_gen import define, field, frozen, mutable -from ._version_info import VersionInfo - - -s = attributes = attrs -ib = attr = attrib -dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) - - -class AttrsInstance(Protocol): - pass - - -NothingType = Literal[_Nothing.NOTHING] - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "Converter", - "Factory", - "NothingType", - "asdict", - "assoc", - "astuple", - "attr", - "attrib", - "attributes", - "attrs", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "get_run_validators", - "has", - "ib", - "make_class", - "mutable", - "resolve_types", - "s", - "set_run_validators", - "setters", - "validate", - "validators", -] - - -def _make_getattr(mod_name: str) -> Callable: - """ - Create a metadata proxy for packaging information that uses *mod_name* in - its warnings and errors. - """ - - def __getattr__(name: str) -> str: - if name not in ("__version__", "__version_info__"): - msg = f"module {mod_name} has no attribute {name}" - raise AttributeError(msg) - - from importlib.metadata import metadata - - meta = metadata("attrs") - - if name == "__version_info__": - return VersionInfo._from_version_string(meta["version"]) - - return meta["version"] - - return __getattr__ - - -__getattr__ = _make_getattr(__name__) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/attr/__init__.pyi deleted file mode 100644 index 8d78fa1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/__init__.pyi +++ /dev/null @@ -1,389 +0,0 @@ -import enum -import sys - -from typing import ( - Any, - Callable, - Generic, - Literal, - Mapping, - Protocol, - Sequence, - TypeVar, - overload, -) - -# `import X as X` is required to make these public -from . import converters as converters -from . import exceptions as exceptions -from . import filters as filters -from . import setters as setters -from . import validators as validators -from ._cmp import cmp_using as cmp_using -from ._typing_compat import AttrsInstance_ -from ._version_info import VersionInfo -from attrs import ( - define as define, - field as field, - mutable as mutable, - frozen as frozen, - _EqOrderType, - _ValidatorType, - _ConverterType, - _ReprArgType, - _OnSetAttrType, - _OnSetAttrArgType, - _FieldTransformer, - _ValidatorArgType, -) - -if sys.version_info >= (3, 10): - from typing import TypeGuard, TypeAlias -else: - from typing_extensions import TypeGuard, TypeAlias - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -__version__: str -__version_info__: VersionInfo -__title__: str -__description__: str -__url__: str -__uri__: str -__author__: str -__email__: str -__license__: str -__copyright__: str - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_FilterType = Callable[["Attribute[_T]", _T], bool] - -# We subclass this here to keep the protocol's qualified name clean. -class AttrsInstance(AttrsInstance_, Protocol): - pass - -_A = TypeVar("_A", bound=type[AttrsInstance]) - -class _Nothing(enum.Enum): - NOTHING = enum.auto() - -NOTHING = _Nothing.NOTHING -NothingType: TypeAlias = Literal[_Nothing.NOTHING] - -# NOTE: Factory lies about its return type to make this possible: -# `x: List[int] # = Factory(list)` -# Work around mypy issue #4554 in the common case by using an overload. - -@overload -def Factory(factory: Callable[[], _T]) -> _T: ... -@overload -def Factory( - factory: Callable[[Any], _T], - takes_self: Literal[True], -) -> _T: ... -@overload -def Factory( - factory: Callable[[], _T], - takes_self: Literal[False], -) -> _T: ... - -In = TypeVar("In") -Out = TypeVar("Out") - -class Converter(Generic[In, Out]): - @overload - def __init__(self, converter: Callable[[In], Out]) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance, Attribute], Out], - *, - takes_self: Literal[True], - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, Attribute], Out], - *, - takes_field: Literal[True], - ) -> None: ... - @overload - def __init__( - self, - converter: Callable[[In, AttrsInstance], Out], - *, - takes_self: Literal[True], - ) -> None: ... - -class Attribute(Generic[_T]): - name: str - default: _T | None - validator: _ValidatorType[_T] | None - repr: _ReprArgType - cmp: _EqOrderType - eq: _EqOrderType - order: _EqOrderType - hash: bool | None - init: bool - converter: Converter | None - metadata: dict[Any, Any] - type: type[_T] | None - kw_only: bool - on_setattr: _OnSetAttrType - alias: str | None - - def evolve(self, **changes: Any) -> "Attribute[Any]": ... - -# NOTE: We had several choices for the annotation to use for type arg: -# 1) Type[_T] -# - Pros: Handles simple cases correctly -# - Cons: Might produce less informative errors in the case of conflicting -# TypeVars e.g. `attr.ib(default='bad', type=int)` -# 2) Callable[..., _T] -# - Pros: Better error messages than #1 for conflicting TypeVars -# - Cons: Terrible error messages for validator checks. -# e.g. attr.ib(type=int, validator=validate_str) -# -> error: Cannot infer function type argument -# 3) type (and do all of the work in the mypy plugin) -# - Pros: Simple here, and we could customize the plugin with our own errors. -# - Cons: Would need to write mypy plugin code to handle all the cases. -# We chose option #1. - -# `attr` lies about its return type to make the following possible: -# attr() -> Any -# attr(8) -> int -# attr(validator=) -> Whatever the callable expects. -# This makes this type of assignments possible: -# x: int = attr(8) -# -# This form catches explicit None or no default but with no other arguments -# returns Any. -@overload -def attrib( - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def attrib( - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def attrib( - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: type[_T] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def attrib( - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - type: object = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., -) -> Any: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: _C, - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> _C: ... -@overload -@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) -def attrs( - maybe_cls: None = ..., - these: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - auto_detect: bool = ..., - collect_by_mro: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., - unsafe_hash: bool | None = ..., -) -> Callable[[_C], _C]: ... -def fields(cls: type[AttrsInstance]) -> Any: ... -def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... -def validate(inst: AttrsInstance) -> None: ... -def resolve_types( - cls: _A, - globalns: dict[str, Any] | None = ..., - localns: dict[str, Any] | None = ..., - attribs: list[Attribute[Any]] | None = ..., - include_extras: bool = ..., -) -> _A: ... - -# TODO: add support for returning a proper attrs class from the mypy plugin -# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', -# [attr.ib()])` is valid -def make_class( - name: str, - attrs: list[str] | tuple[str, ...] | dict[str, Any], - bases: tuple[type, ...] = ..., - class_body: dict[str, Any] | None = ..., - repr_ns: str | None = ..., - repr: bool = ..., - cmp: _EqOrderType | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - collect_by_mro: bool = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., -) -> type: ... - -# _funcs -- - -# TODO: add support for returning TypedDict from the mypy plugin -# FIXME: asdict/astuple do not honor their factory args. Waiting on one of -# these: -# https://github.com/python/mypy/issues/4236 -# https://github.com/python/typing/issues/253 -# XXX: remember to fix attrs.asdict/astuple too! -def asdict( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - dict_factory: type[Mapping[Any, Any]] = ..., - retain_collection_types: bool = ..., - value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., - tuple_keys: bool | None = ..., -) -> dict[str, Any]: ... - -# TODO: add support for returning NamedTuple from the mypy plugin -def astuple( - inst: AttrsInstance, - recurse: bool = ..., - filter: _FilterType[Any] | None = ..., - tuple_factory: type[Sequence[Any]] = ..., - retain_collection_types: bool = ..., -) -> tuple[Any, ...]: ... -def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... -def assoc(inst: _T, **changes: Any) -> _T: ... -def evolve(inst: _T, **changes: Any) -> _T: ... - -# _config -- - -def set_run_validators(run: bool) -> None: ... -def get_run_validators() -> bool: ... - -# aliases -- - -s = attributes = attrs -ib = attr = attrib -dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_cmp.py b/backend/venv39/lib/python3.9/site-packages/attr/_cmp.py deleted file mode 100644 index 09bab49..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_cmp.py +++ /dev/null @@ -1,160 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import functools -import types - -from ._make import __ne__ - - -_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} - - -def cmp_using( - eq=None, - lt=None, - le=None, - gt=None, - ge=None, - require_same_type=True, - class_name="Comparable", -): - """ - Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, - and ``cmp`` arguments to customize field comparison. - - The resulting class will have a full set of ordering methods if at least - one of ``{lt, le, gt, ge}`` and ``eq`` are provided. - - Args: - eq (typing.Callable | None): - Callable used to evaluate equality of two objects. - - lt (typing.Callable | None): - Callable used to evaluate whether one object is less than another - object. - - le (typing.Callable | None): - Callable used to evaluate whether one object is less than or equal - to another object. - - gt (typing.Callable | None): - Callable used to evaluate whether one object is greater than - another object. - - ge (typing.Callable | None): - Callable used to evaluate whether one object is greater than or - equal to another object. - - require_same_type (bool): - When `True`, equality and ordering methods will return - `NotImplemented` if objects are not of the same type. - - class_name (str | None): Name of class. Defaults to "Comparable". - - See `comparison` for more details. - - .. versionadded:: 21.1.0 - """ - - body = { - "__slots__": ["value"], - "__init__": _make_init(), - "_requirements": [], - "_is_comparable_to": _is_comparable_to, - } - - # Add operations. - num_order_functions = 0 - has_eq_function = False - - if eq is not None: - has_eq_function = True - body["__eq__"] = _make_operator("eq", eq) - body["__ne__"] = __ne__ - - if lt is not None: - num_order_functions += 1 - body["__lt__"] = _make_operator("lt", lt) - - if le is not None: - num_order_functions += 1 - body["__le__"] = _make_operator("le", le) - - if gt is not None: - num_order_functions += 1 - body["__gt__"] = _make_operator("gt", gt) - - if ge is not None: - num_order_functions += 1 - body["__ge__"] = _make_operator("ge", ge) - - type_ = types.new_class( - class_name, (object,), {}, lambda ns: ns.update(body) - ) - - # Add same type requirement. - if require_same_type: - type_._requirements.append(_check_same_type) - - # Add total ordering if at least one operation was defined. - if 0 < num_order_functions < 4: - if not has_eq_function: - # functools.total_ordering requires __eq__ to be defined, - # so raise early error here to keep a nice stack. - msg = "eq must be define is order to complete ordering from lt, le, gt, ge." - raise ValueError(msg) - type_ = functools.total_ordering(type_) - - return type_ - - -def _make_init(): - """ - Create __init__ method. - """ - - def __init__(self, value): - """ - Initialize object with *value*. - """ - self.value = value - - return __init__ - - -def _make_operator(name, func): - """ - Create operator method. - """ - - def method(self, other): - if not self._is_comparable_to(other): - return NotImplemented - - result = func(self.value, other.value) - if result is NotImplemented: - return NotImplemented - - return result - - method.__name__ = f"__{name}__" - method.__doc__ = ( - f"Return a {_operation_names[name]} b. Computed by attrs." - ) - - return method - - -def _is_comparable_to(self, other): - """ - Check whether `other` is comparable to `self`. - """ - return all(func(self, other) for func in self._requirements) - - -def _check_same_type(self, other): - """ - Return True if *self* and *other* are of the same type, False otherwise. - """ - return other.value.__class__ is self.value.__class__ diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_cmp.pyi b/backend/venv39/lib/python3.9/site-packages/attr/_cmp.pyi deleted file mode 100644 index cc7893b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_cmp.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any, Callable - -_CompareWithType = Callable[[Any, Any], bool] - -def cmp_using( - eq: _CompareWithType | None = ..., - lt: _CompareWithType | None = ..., - le: _CompareWithType | None = ..., - gt: _CompareWithType | None = ..., - ge: _CompareWithType | None = ..., - require_same_type: bool = ..., - class_name: str = ..., -) -> type: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_compat.py b/backend/venv39/lib/python3.9/site-packages/attr/_compat.py deleted file mode 100644 index bc68ed9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_compat.py +++ /dev/null @@ -1,99 +0,0 @@ -# SPDX-License-Identifier: MIT - -import inspect -import platform -import sys -import threading - -from collections.abc import Mapping, Sequence # noqa: F401 -from typing import _GenericAlias - - -PYPY = platform.python_implementation() == "PyPy" -PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) -PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) -PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) -PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) -PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) - - -if PY_3_14_PLUS: - import annotationlib - - # We request forward-ref annotations to not break in the presence of - # forward references. - - def _get_annotations(cls): - return annotationlib.get_annotations( - cls, format=annotationlib.Format.FORWARDREF - ) - -else: - - def _get_annotations(cls): - """ - Get annotations for *cls*. - """ - return cls.__dict__.get("__annotations__", {}) - - -class _AnnotationExtractor: - """ - Extract type annotations from a callable, returning None whenever there - is none. - """ - - __slots__ = ["sig"] - - def __init__(self, callable): - try: - self.sig = inspect.signature(callable) - except (ValueError, TypeError): # inspect failed - self.sig = None - - def get_first_param_type(self): - """ - Return the type annotation of the first argument if it's not empty. - """ - if not self.sig: - return None - - params = list(self.sig.parameters.values()) - if params and params[0].annotation is not inspect.Parameter.empty: - return params[0].annotation - - return None - - def get_return_type(self): - """ - Return the return type if it's not empty. - """ - if ( - self.sig - and self.sig.return_annotation is not inspect.Signature.empty - ): - return self.sig.return_annotation - - return None - - -# Thread-local global to track attrs instances which are already being repr'd. -# This is needed because there is no other (thread-safe) way to pass info -# about the instances that are already being repr'd through the call stack -# in order to ensure we don't perform infinite recursion. -# -# For instance, if an instance contains a dict which contains that instance, -# we need to know that we're already repr'ing the outside instance from within -# the dict's repr() call. -# -# This lives here rather than in _make.py so that the functions in _make.py -# don't have a direct reference to the thread-local in their globals dict. -# If they have such a reference, it breaks cloudpickle. -repr_context = threading.local() - - -def get_generic_base(cl): - """If this is a generic class (A[str]), return the generic base for it.""" - if cl.__class__ is _GenericAlias: - return cl.__origin__ - return None diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_config.py b/backend/venv39/lib/python3.9/site-packages/attr/_config.py deleted file mode 100644 index 4b25772..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_config.py +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: MIT - -__all__ = ["get_run_validators", "set_run_validators"] - -_run_validators = True - - -def set_run_validators(run): - """ - Set whether or not validators are run. By default, they are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` - instead. - """ - if not isinstance(run, bool): - msg = "'run' must be bool." - raise TypeError(msg) - global _run_validators - _run_validators = run - - -def get_run_validators(): - """ - Return whether or not validators are run. - - .. deprecated:: 21.3.0 It will not be removed, but it also will not be - moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` - instead. - """ - return _run_validators diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_funcs.py b/backend/venv39/lib/python3.9/site-packages/attr/_funcs.py deleted file mode 100644 index 1adb500..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_funcs.py +++ /dev/null @@ -1,497 +0,0 @@ -# SPDX-License-Identifier: MIT - - -import copy - -from ._compat import get_generic_base -from ._make import _OBJ_SETATTR, NOTHING, fields -from .exceptions import AttrsAttributeNotFoundError - - -_ATOMIC_TYPES = frozenset( - { - type(None), - bool, - int, - float, - str, - complex, - bytes, - type(...), - type, - range, - property, - } -) - - -def asdict( - inst, - recurse=True, - filter=None, - dict_factory=dict, - retain_collection_types=False, - value_serializer=None, -): - """ - Return the *attrs* attribute values of *inst* as a dict. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - dict_factory (~typing.Callable): - A callable to produce dictionaries from. For example, to produce - ordered dictionaries instead of normal Python dictionaries, pass in - ``collections.OrderedDict``. - - retain_collection_types (bool): - Do not convert to `list` when encountering an attribute whose type - is `tuple` or `set`. Only meaningful if *recurse* is `True`. - - value_serializer (typing.Callable | None): - A hook that is called for every attribute or dict key/value. It - receives the current instance, field and value and must return the - (updated) value. The hook is run *after* the optional *filter* has - been applied. - - Returns: - Return type of *dict_factory*. - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.0.0 *dict_factory* - .. versionadded:: 16.1.0 *retain_collection_types* - .. versionadded:: 20.3.0 *value_serializer* - .. versionadded:: 21.3.0 - If a dict has a collection for a key, it is serialized as a tuple. - """ - attrs = fields(inst.__class__) - rv = dict_factory() - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - - if value_serializer is not None: - v = value_serializer(inst, a, v) - - if recurse is True: - value_type = type(v) - if value_type in _ATOMIC_TYPES: - rv[a.name] = v - elif has(value_type): - rv[a.name] = asdict( - v, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif issubclass(value_type, (tuple, list, set, frozenset)): - cf = value_type if retain_collection_types is True else list - items = [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in v - ] - try: - rv[a.name] = cf(items) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv[a.name] = cf(*items) - elif issubclass(value_type, dict): - df = dict_factory - rv[a.name] = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in v.items() - ) - else: - rv[a.name] = v - else: - rv[a.name] = v - return rv - - -def _asdict_anything( - val, - is_key, - filter, - dict_factory, - retain_collection_types, - value_serializer, -): - """ - ``asdict`` only works on attrs instances, this works on anything. - """ - val_type = type(val) - if val_type in _ATOMIC_TYPES: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - elif getattr(val_type, "__attrs_attrs__", None) is not None: - # Attrs class. - rv = asdict( - val, - recurse=True, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - elif issubclass(val_type, (tuple, list, set, frozenset)): - if retain_collection_types is True: - cf = val.__class__ - elif is_key: - cf = tuple - else: - cf = list - - rv = cf( - [ - _asdict_anything( - i, - is_key=False, - filter=filter, - dict_factory=dict_factory, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ) - for i in val - ] - ) - elif issubclass(val_type, dict): - df = dict_factory - rv = df( - ( - _asdict_anything( - kk, - is_key=True, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - _asdict_anything( - vv, - is_key=False, - filter=filter, - dict_factory=df, - retain_collection_types=retain_collection_types, - value_serializer=value_serializer, - ), - ) - for kk, vv in val.items() - ) - else: - rv = val - if value_serializer is not None: - rv = value_serializer(None, None, rv) - - return rv - - -def astuple( - inst, - recurse=True, - filter=None, - tuple_factory=tuple, - retain_collection_types=False, -): - """ - Return the *attrs* attribute values of *inst* as a tuple. - - Optionally recurse into other *attrs*-decorated classes. - - Args: - inst: Instance of an *attrs*-decorated class. - - recurse (bool): - Recurse into classes that are also *attrs*-decorated. - - filter (~typing.Callable): - A callable whose return code determines whether an attribute or - element is included (`True`) or dropped (`False`). Is called with - the `attrs.Attribute` as the first argument and the value as the - second argument. - - tuple_factory (~typing.Callable): - A callable to produce tuples from. For example, to produce lists - instead of tuples. - - retain_collection_types (bool): - Do not convert to `list` or `dict` when encountering an attribute - which type is `tuple`, `dict` or `set`. Only meaningful if - *recurse* is `True`. - - Returns: - Return type of *tuple_factory* - - Raises: - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 16.2.0 - """ - attrs = fields(inst.__class__) - rv = [] - retain = retain_collection_types # Very long. :/ - for a in attrs: - v = getattr(inst, a.name) - if filter is not None and not filter(a, v): - continue - value_type = type(v) - if recurse is True: - if value_type in _ATOMIC_TYPES: - rv.append(v) - elif has(value_type): - rv.append( - astuple( - v, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - ) - elif issubclass(value_type, (tuple, list, set, frozenset)): - cf = v.__class__ if retain is True else list - items = [ - ( - astuple( - j, - recurse=True, - filter=filter, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(j.__class__) - else j - ) - for j in v - ] - try: - rv.append(cf(items)) - except TypeError: - if not issubclass(cf, tuple): - raise - # Workaround for TypeError: cf.__new__() missing 1 required - # positional argument (which appears, for a namedturle) - rv.append(cf(*items)) - elif issubclass(value_type, dict): - df = value_type if retain is True else dict - rv.append( - df( - ( - ( - astuple( - kk, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(kk.__class__) - else kk - ), - ( - astuple( - vv, - tuple_factory=tuple_factory, - retain_collection_types=retain, - ) - if has(vv.__class__) - else vv - ), - ) - for kk, vv in v.items() - ) - ) - else: - rv.append(v) - else: - rv.append(v) - - return rv if tuple_factory is list else tuple_factory(rv) - - -def has(cls): - """ - Check whether *cls* is a class with *attrs* attributes. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - Returns: - bool: - """ - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is not None: - return True - - # No attrs, maybe it's a specialized generic (A[str])? - generic_base = get_generic_base(cls) - if generic_base is not None: - generic_attrs = getattr(generic_base, "__attrs_attrs__", None) - if generic_attrs is not None: - # Stick it on here for speed next time. - cls.__attrs_attrs__ = generic_attrs - return generic_attrs is not None - return False - - -def assoc(inst, **changes): - """ - Copy *inst* and apply *changes*. - - This is different from `evolve` that applies the changes to the arguments - that create the new instance. - - `evolve`'s behavior is preferable, but there are `edge cases`_ where it - doesn't work. Therefore `assoc` is deprecated, but will not be removed. - - .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 - - Args: - inst: Instance of a class with *attrs* attributes. - - changes: Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - attrs.exceptions.AttrsAttributeNotFoundError: - If *attr_name* couldn't be found on *cls*. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. deprecated:: 17.1.0 - Use `attrs.evolve` instead if you can. This function will not be - removed du to the slightly different approach compared to - `attrs.evolve`, though. - """ - new = copy.copy(inst) - attrs = fields(inst.__class__) - for k, v in changes.items(): - a = getattr(attrs, k, NOTHING) - if a is NOTHING: - msg = f"{k} is not an attrs attribute on {new.__class__}." - raise AttrsAttributeNotFoundError(msg) - _OBJ_SETATTR(new, k, v) - return new - - -def resolve_types( - cls, globalns=None, localns=None, attribs=None, include_extras=True -): - """ - Resolve any strings and forward annotations in type annotations. - - This is only required if you need concrete types in :class:`Attribute`'s - *type* field. In other words, you don't need to resolve your types if you - only use them for static type checking. - - With no arguments, names will be looked up in the module in which the class - was created. If this is not what you want, for example, if the name only - exists inside a method, you may pass *globalns* or *localns* to specify - other dictionaries in which to look up these names. See the docs of - `typing.get_type_hints` for more details. - - Args: - cls (type): Class to resolve. - - globalns (dict | None): Dictionary containing global variables. - - localns (dict | None): Dictionary containing local variables. - - attribs (list | None): - List of attribs for the given class. This is necessary when calling - from inside a ``field_transformer`` since *cls* is not an *attrs* - class yet. - - include_extras (bool): - Resolve more accurately, if possible. Pass ``include_extras`` to - ``typing.get_hints``, if supported by the typing module. On - supported Python versions (3.9+), this resolves the types more - accurately. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class and you didn't pass any attribs. - - NameError: If types cannot be resolved because of missing variables. - - Returns: - *cls* so you can use this function also as a class decorator. Please - note that you have to apply it **after** `attrs.define`. That means the - decorator has to come in the line **before** `attrs.define`. - - .. versionadded:: 20.1.0 - .. versionadded:: 21.1.0 *attribs* - .. versionadded:: 23.1.0 *include_extras* - """ - # Since calling get_type_hints is expensive we cache whether we've - # done it already. - if getattr(cls, "__attrs_types_resolved__", None) != cls: - import typing - - kwargs = { - "globalns": globalns, - "localns": localns, - "include_extras": include_extras, - } - - hints = typing.get_type_hints(cls, **kwargs) - for field in fields(cls) if attribs is None else attribs: - if field.name in hints: - # Since fields have been frozen we must work around it. - _OBJ_SETATTR(field, "type", hints[field.name]) - # We store the class we resolved so that subclasses know they haven't - # been resolved. - cls.__attrs_types_resolved__ = cls - - # Return the class so you can use it as a decorator too. - return cls diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_make.py b/backend/venv39/lib/python3.9/site-packages/attr/_make.py deleted file mode 100644 index d24d9ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_make.py +++ /dev/null @@ -1,3362 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -import abc -import contextlib -import copy -import enum -import inspect -import itertools -import linecache -import sys -import types -import unicodedata -import weakref - -from collections.abc import Callable, Mapping -from functools import cached_property -from typing import Any, NamedTuple, TypeVar - -# We need to import _compat itself in addition to the _compat members to avoid -# having the thread-local in the globals here. -from . import _compat, _config, setters -from ._compat import ( - PY_3_10_PLUS, - PY_3_11_PLUS, - PY_3_13_PLUS, - _AnnotationExtractor, - _get_annotations, - get_generic_base, -) -from .exceptions import ( - DefaultAlreadySetError, - FrozenInstanceError, - NotAnAttrsClassError, - UnannotatedAttributeError, -) - - -# This is used at least twice, so cache it here. -_OBJ_SETATTR = object.__setattr__ -_INIT_FACTORY_PAT = "__attr_factory_%s" -_CLASSVAR_PREFIXES = ( - "typing.ClassVar", - "t.ClassVar", - "ClassVar", - "typing_extensions.ClassVar", -) -# we don't use a double-underscore prefix because that triggers -# name mangling when trying to create a slot for the field -# (when slots=True) -_HASH_CACHE_FIELD = "_attrs_cached_hash" - -_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) - -# Unique object for unequivocal getattr() defaults. -_SENTINEL = object() - -_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) - - -class _Nothing(enum.Enum): - """ - Sentinel to indicate the lack of a value when `None` is ambiguous. - - If extending attrs, you can use ``typing.Literal[NOTHING]`` to show - that a value may be ``NOTHING``. - - .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. - .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. - """ - - NOTHING = enum.auto() - - def __repr__(self): - return "NOTHING" - - def __bool__(self): - return False - - -NOTHING = _Nothing.NOTHING -""" -Sentinel to indicate the lack of a value when `None` is ambiguous. - -When using in 3rd party code, use `attrs.NothingType` for type annotations. -""" - - -class _CacheHashWrapper(int): - """ - An integer subclass that pickles / copies as None - - This is used for non-slots classes with ``cache_hash=True``, to avoid - serializing a potentially (even likely) invalid hash value. Since `None` - is the default value for uncalculated hashes, whenever this is copied, - the copy's value for the hash should automatically reset. - - See GH #613 for more details. - """ - - def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 - return _none_constructor, _args - - -def attrib( - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=None, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new field / attribute on a class. - - Identical to `attrs.field`, except it's not keyword-only. - - Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, - though). - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attr.s` (or similar)! - - - .. versionadded:: 15.2.0 *convert* - .. versionadded:: 16.3.0 *metadata* - .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. - .. versionchanged:: 17.1.0 - *hash* is `None` and therefore mirrors *eq* by default. - .. versionadded:: 17.3.0 *type* - .. deprecated:: 17.4.0 *convert* - .. versionadded:: 17.4.0 - *converter* as a replacement for the deprecated *convert* to achieve - consistency with other noun-based arguments. - .. versionadded:: 18.1.0 - ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. - .. versionadded:: 18.2.0 *kw_only* - .. versionchanged:: 19.2.0 *convert* keyword argument removed. - .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 22.2.0 *alias* - .. versionchanged:: 25.4.0 - *kw_only* can now be None, and its default is also changed from False to - None. - """ - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq, order, True - ) - - if hash is not None and hash is not True and hash is not False: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - if factory is not None: - if default is not NOTHING: - msg = ( - "The `default` and `factory` arguments are mutually exclusive." - ) - raise ValueError(msg) - if not callable(factory): - msg = "The `factory` argument must be a callable." - raise ValueError(msg) - default = Factory(factory) - - if metadata is None: - metadata = {} - - # Apply syntactic sugar by auto-wrapping. - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - if validator and isinstance(validator, (list, tuple)): - validator = and_(*validator) - - if converter and isinstance(converter, (list, tuple)): - converter = pipe(*converter) - - return _CountingAttr( - default=default, - validator=validator, - repr=repr, - cmp=None, - hash=hash, - init=init, - converter=converter, - metadata=metadata, - type=type, - kw_only=kw_only, - eq=eq, - eq_key=eq_key, - order=order, - order_key=order_key, - on_setattr=on_setattr, - alias=alias, - ) - - -def _compile_and_eval( - script: str, - globs: dict[str, Any] | None, - locs: Mapping[str, object] | None = None, - filename: str = "", -) -> None: - """ - Evaluate the script with the given global (globs) and local (locs) - variables. - """ - bytecode = compile(script, filename, "exec") - eval(bytecode, globs, locs) - - -def _linecache_and_compile( - script: str, - filename: str, - globs: dict[str, Any] | None, - locals: Mapping[str, object] | None = None, -) -> dict[str, Any]: - """ - Cache the script with _linecache_, compile it and return the _locals_. - """ - - locs = {} if locals is None else locals - - # In order of debuggers like PDB being able to step through the code, - # we add a fake linecache entry. - count = 1 - base_filename = filename - while True: - linecache_tuple = ( - len(script), - None, - script.splitlines(True), - filename, - ) - old_val = linecache.cache.setdefault(filename, linecache_tuple) - if old_val == linecache_tuple: - break - - filename = f"{base_filename[:-1]}-{count}>" - count += 1 - - _compile_and_eval(script, globs, locs, filename) - - return locs - - -def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: - """ - Create a tuple subclass to hold `Attribute`s for an `attrs` class. - - The subclass is a bare tuple with properties for names. - - class MyClassAttributes(tuple): - __slots__ = () - x = property(itemgetter(0)) - """ - attr_class_name = f"{cls_name}Attributes" - body = {} - for i, attr_name in enumerate(attr_names): - - def getter(self, i=i): - return self[i] - - body[attr_name] = property(getter) - return type(attr_class_name, (tuple,), body) - - -# Tuple class for extracted attributes from a class definition. -# `base_attrs` is a subset of `attrs`. -class _Attributes(NamedTuple): - attrs: type - base_attrs: list[Attribute] - base_attrs_map: dict[str, type] - - -def _is_class_var(annot): - """ - Check whether *annot* is a typing.ClassVar. - - The string comparison hack is used to avoid evaluating all string - annotations which would put attrs-based classes at a performance - disadvantage compared to plain old classes. - """ - annot = str(annot) - - # Annotation can be quoted. - if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): - annot = annot[1:-1] - - return annot.startswith(_CLASSVAR_PREFIXES) - - -def _has_own_attribute(cls, attrib_name): - """ - Check whether *cls* defines *attrib_name* (and doesn't just inherit it). - """ - return attrib_name in cls.__dict__ - - -def _collect_base_attrs( - cls, taken_attr_names -) -> tuple[list[Attribute], dict[str, type]]: - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in reversed(cls.__mro__[1:-1]): - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.inherited or a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - # For each name, only keep the freshest definition i.e. the furthest at the - # back. base_attr_map is fine because it gets overwritten with every new - # instance. - filtered = [] - seen = set() - for a in reversed(base_attrs): - if a.name in seen: - continue - filtered.insert(0, a) - seen.add(a.name) - - return filtered, base_attr_map - - -def _collect_base_attrs_broken(cls, taken_attr_names): - """ - Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. - - N.B. *taken_attr_names* will be mutated. - - Adhere to the old incorrect behavior. - - Notably it collects from the front and considers inherited attributes which - leads to the buggy behavior reported in #428. - """ - base_attrs = [] - base_attr_map = {} # A dictionary of base attrs to their classes. - - # Traverse the MRO and collect attributes. - for base_cls in cls.__mro__[1:-1]: - for a in getattr(base_cls, "__attrs_attrs__", []): - if a.name in taken_attr_names: - continue - - a = a.evolve(inherited=True) # noqa: PLW2901 - taken_attr_names.add(a.name) - base_attrs.append(a) - base_attr_map[a.name] = base_cls - - return base_attrs, base_attr_map - - -def _transform_attrs( - cls, - these, - auto_attribs, - kw_only, - collect_by_mro, - field_transformer, -) -> _Attributes: - """ - Transform all `_CountingAttr`s on a class into `Attribute`s. - - If *these* is passed, use that and don't look for them on the class. - - If *collect_by_mro* is True, collect them in the correct MRO order, - otherwise use the old -- incorrect -- order. See #428. - - Return an `_Attributes`. - """ - cd = cls.__dict__ - anns = _get_annotations(cls) - - if these is not None: - ca_list = list(these.items()) - elif auto_attribs is True: - ca_names = { - name - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - } - ca_list = [] - annot_names = set() - for attr_name, type in anns.items(): - if _is_class_var(type): - continue - annot_names.add(attr_name) - a = cd.get(attr_name, NOTHING) - - if a.__class__ is not _CountingAttr: - a = attrib(a) - ca_list.append((attr_name, a)) - - unannotated = ca_names - annot_names - if unannotated: - raise UnannotatedAttributeError( - "The following `attr.ib`s lack a type annotation: " - + ", ".join( - sorted(unannotated, key=lambda n: cd.get(n).counter) - ) - + "." - ) - else: - ca_list = sorted( - ( - (name, attr) - for name, attr in cd.items() - if attr.__class__ is _CountingAttr - ), - key=lambda e: e[1].counter, - ) - - fca = Attribute.from_counting_attr - no = ClassProps.KeywordOnly.NO - own_attrs = [ - fca( - attr_name, - ca, - kw_only is not no, - anns.get(attr_name), - ) - for attr_name, ca in ca_list - ] - - if collect_by_mro: - base_attrs, base_attr_map = _collect_base_attrs( - cls, {a.name for a in own_attrs} - ) - else: - base_attrs, base_attr_map = _collect_base_attrs_broken( - cls, {a.name for a in own_attrs} - ) - - if kw_only is ClassProps.KeywordOnly.FORCE: - own_attrs = [a.evolve(kw_only=True) for a in own_attrs] - base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - - attrs = base_attrs + own_attrs - - if field_transformer is not None: - attrs = tuple(field_transformer(cls, attrs)) - - # Check attr order after executing the field_transformer. - # Mandatory vs non-mandatory attr order only matters when they are part of - # the __init__ signature and when they aren't kw_only (which are moved to - # the end and can be mandatory or non-mandatory in any order, as they will - # be specified as keyword args anyway). Check the order of those attrs: - had_default = False - for a in (a for a in attrs if a.init is not False and a.kw_only is False): - if had_default is True and a.default is NOTHING: - msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" - raise ValueError(msg) - - if had_default is False and a.default is not NOTHING: - had_default = True - - # Resolve default field alias after executing field_transformer. - # This allows field_transformer to differentiate between explicit vs - # default aliases and supply their own defaults. - for a in attrs: - if not a.alias: - # Evolve is very slow, so we hold our nose and do it dirty. - _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) - - # Create AttrsClass *after* applying the field_transformer since it may - # add or remove attributes! - attr_names = [a.name for a in attrs] - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - - return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) - - -def _make_cached_property_getattr(cached_properties, original_getattr, cls): - lines = [ - # Wrapped to get `__class__` into closure cell for super() - # (It will be replaced with the newly constructed class after construction). - "def wrapper(_cls):", - " __class__ = _cls", - " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", - " func = cached_properties.get(item)", - " if func is not None:", - " result = func(self)", - " _setter = _cached_setattr_get(self)", - " _setter(item, result)", - " return result", - ] - if original_getattr is not None: - lines.append( - " return original_getattr(self, item)", - ) - else: - lines.extend( - [ - " try:", - " return super().__getattribute__(item)", - " except AttributeError:", - " if not hasattr(super(), '__getattr__'):", - " raise", - " return super().__getattr__(item)", - " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", - " raise AttributeError(original_error)", - ] - ) - - lines.extend( - [ - " return __getattr__", - "__getattr__ = wrapper(_cls)", - ] - ) - - unique_filename = _generate_unique_filename(cls, "getattr") - - glob = { - "cached_properties": cached_properties, - "_cached_setattr_get": _OBJ_SETATTR.__get__, - "original_getattr": original_getattr, - } - - return _linecache_and_compile( - "\n".join(lines), unique_filename, glob, locals={"_cls": cls} - )["__getattr__"] - - -def _frozen_setattrs(self, name, value): - """ - Attached to frozen classes as __setattr__. - """ - if isinstance(self, BaseException) and name in ( - "__cause__", - "__context__", - "__traceback__", - "__suppress_context__", - "__notes__", - ): - BaseException.__setattr__(self, name, value) - return - - raise FrozenInstanceError - - -def _frozen_delattrs(self, name): - """ - Attached to frozen classes as __delattr__. - """ - if isinstance(self, BaseException) and name in ("__notes__",): - BaseException.__delattr__(self, name) - return - - raise FrozenInstanceError - - -def evolve(*args, **changes): - """ - Create a new instance, based on the first positional argument with - *changes* applied. - - .. tip:: - - On Python 3.13 and later, you can also use `copy.replace` instead. - - Args: - - inst: - Instance of a class with *attrs* attributes. *inst* must be passed - as a positional argument. - - changes: - Keyword changes in the new copy. - - Returns: - A copy of inst with *changes* incorporated. - - Raises: - TypeError: - If *attr_name* couldn't be found in the class ``__init__``. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - .. versionadded:: 17.1.0 - .. deprecated:: 23.1.0 - It is now deprecated to pass the instance using the keyword argument - *inst*. It will raise a warning until at least April 2024, after which - it will become an error. Always pass the instance as a positional - argument. - .. versionchanged:: 24.1.0 - *inst* can't be passed as a keyword argument anymore. - """ - try: - (inst,) = args - except ValueError: - msg = ( - f"evolve() takes 1 positional argument, but {len(args)} were given" - ) - raise TypeError(msg) from None - - cls = inst.__class__ - attrs = fields(cls) - for a in attrs: - if not a.init: - continue - attr_name = a.name # To deal with private attributes. - init_name = a.alias - if init_name not in changes: - changes[init_name] = getattr(inst, attr_name) - - return cls(**changes) - - -class _ClassBuilder: - """ - Iteratively build *one* class. - """ - - __slots__ = ( - "_add_method_dunders", - "_attr_names", - "_attrs", - "_base_attr_map", - "_base_names", - "_cache_hash", - "_cls", - "_cls_dict", - "_delete_attribs", - "_frozen", - "_has_custom_setattr", - "_has_post_init", - "_has_pre_init", - "_is_exc", - "_on_setattr", - "_pre_init_has_args", - "_repr_added", - "_script_snippets", - "_slots", - "_weakref_slot", - "_wrote_own_setattr", - ) - - def __init__( - self, - cls: type, - these, - auto_attribs: bool, - props: ClassProps, - has_custom_setattr: bool, - ): - attrs, base_attrs, base_map = _transform_attrs( - cls, - these, - auto_attribs, - props.kw_only, - props.collected_fields_by_mro, - props.field_transformer, - ) - - self._cls = cls - self._cls_dict = dict(cls.__dict__) if props.is_slotted else {} - self._attrs = attrs - self._base_names = {a.name for a in base_attrs} - self._base_attr_map = base_map - self._attr_names = tuple(a.name for a in attrs) - self._slots = props.is_slotted - self._frozen = props.is_frozen - self._weakref_slot = props.has_weakref_slot - self._cache_hash = ( - props.hashability is ClassProps.Hashability.HASHABLE_CACHED - ) - self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) - self._pre_init_has_args = False - if self._has_pre_init: - # Check if the pre init method has more arguments than just `self` - # We want to pass arguments if pre init expects arguments - pre_init_func = cls.__attrs_pre_init__ - pre_init_signature = inspect.signature(pre_init_func) - self._pre_init_has_args = len(pre_init_signature.parameters) > 1 - self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) - self._delete_attribs = not bool(these) - self._is_exc = props.is_exception - self._on_setattr = props.on_setattr_hook - - self._has_custom_setattr = has_custom_setattr - self._wrote_own_setattr = False - - self._cls_dict["__attrs_attrs__"] = self._attrs - self._cls_dict["__attrs_props__"] = props - - if props.is_frozen: - self._cls_dict["__setattr__"] = _frozen_setattrs - self._cls_dict["__delattr__"] = _frozen_delattrs - - self._wrote_own_setattr = True - elif self._on_setattr in ( - _DEFAULT_ON_SETATTR, - setters.validate, - setters.convert, - ): - has_validator = has_converter = False - for a in attrs: - if a.validator is not None: - has_validator = True - if a.converter is not None: - has_converter = True - - if has_validator and has_converter: - break - if ( - ( - self._on_setattr == _DEFAULT_ON_SETATTR - and not (has_validator or has_converter) - ) - or (self._on_setattr == setters.validate and not has_validator) - or (self._on_setattr == setters.convert and not has_converter) - ): - # If class-level on_setattr is set to convert + validate, but - # there's no field to convert or validate, pretend like there's - # no on_setattr. - self._on_setattr = None - - if props.added_pickling: - ( - self._cls_dict["__getstate__"], - self._cls_dict["__setstate__"], - ) = self._make_getstate_setstate() - - # tuples of script, globs, hook - self._script_snippets: list[ - tuple[str, dict, Callable[[dict, dict], Any]] - ] = [] - self._repr_added = False - - # We want to only do this check once; in 99.9% of cases these - # exist. - if not hasattr(self._cls, "__module__") or not hasattr( - self._cls, "__qualname__" - ): - self._add_method_dunders = self._add_method_dunders_safe - else: - self._add_method_dunders = self._add_method_dunders_unsafe - - def __repr__(self): - return f"<_ClassBuilder(cls={self._cls.__name__})>" - - def _eval_snippets(self) -> None: - """ - Evaluate any registered snippets in one go. - """ - script = "\n".join([snippet[0] for snippet in self._script_snippets]) - globs = {} - for _, snippet_globs, _ in self._script_snippets: - globs.update(snippet_globs) - - locs = _linecache_and_compile( - script, - _generate_unique_filename(self._cls, "methods"), - globs, - ) - - for _, _, hook in self._script_snippets: - hook(self._cls_dict, locs) - - def build_class(self): - """ - Finalize class based on the accumulated configuration. - - Builder cannot be used after calling this method. - """ - self._eval_snippets() - if self._slots is True: - cls = self._create_slots_class() - self._cls.__attrs_base_of_slotted__ = weakref.ref(cls) - else: - cls = self._patch_original_class() - if PY_3_10_PLUS: - cls = abc.update_abstractmethods(cls) - - # The method gets only called if it's not inherited from a base class. - # _has_own_attribute does NOT work properly for classmethods. - if ( - getattr(cls, "__attrs_init_subclass__", None) - and "__attrs_init_subclass__" not in cls.__dict__ - ): - cls.__attrs_init_subclass__() - - return cls - - def _patch_original_class(self): - """ - Apply accumulated methods and return the class. - """ - cls = self._cls - base_names = self._base_names - - # Clean class of attribute definitions (`attr.ib()`s). - if self._delete_attribs: - for name in self._attr_names: - if ( - name not in base_names - and getattr(cls, name, _SENTINEL) is not _SENTINEL - ): - # An AttributeError can happen if a base class defines a - # class variable and we want to set an attribute with the - # same name by using only a type annotation. - with contextlib.suppress(AttributeError): - delattr(cls, name) - - # Attach our dunder methods. - for name, value in self._cls_dict.items(): - setattr(cls, name, value) - - # If we've inherited an attrs __setattr__ and don't write our own, - # reset it to object's. - if not self._wrote_own_setattr and getattr( - cls, "__attrs_own_setattr__", False - ): - cls.__attrs_own_setattr__ = False - - if not self._has_custom_setattr: - cls.__setattr__ = _OBJ_SETATTR - - return cls - - def _create_slots_class(self): - """ - Build and return a new class with a `__slots__` attribute. - """ - cd = { - k: v - for k, v in self._cls_dict.items() - if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") - } - - # 3.14.0rc2+ - if hasattr(sys, "_clear_type_descriptors"): - sys._clear_type_descriptors(self._cls) - - # If our class doesn't have its own implementation of __setattr__ - # (either from the user or by us), check the bases, if one of them has - # an attrs-made __setattr__, that needs to be reset. We don't walk the - # MRO because we only care about our immediate base classes. - # XXX: This can be confused by subclassing a slotted attrs class with - # XXX: a non-attrs class and subclass the resulting class with an attrs - # XXX: class. See `test_slotted_confused` for details. For now that's - # XXX: OK with us. - if not self._wrote_own_setattr: - cd["__attrs_own_setattr__"] = False - - if not self._has_custom_setattr: - for base_cls in self._cls.__bases__: - if base_cls.__dict__.get("__attrs_own_setattr__", False): - cd["__setattr__"] = _OBJ_SETATTR - break - - # Traverse the MRO to collect existing slots - # and check for an existing __weakref__. - existing_slots = {} - weakref_inherited = False - for base_cls in self._cls.__mro__[1:-1]: - if base_cls.__dict__.get("__weakref__", None) is not None: - weakref_inherited = True - existing_slots.update( - { - name: getattr(base_cls, name) - for name in getattr(base_cls, "__slots__", []) - } - ) - - base_names = set(self._base_names) - - names = self._attr_names - if ( - self._weakref_slot - and "__weakref__" not in getattr(self._cls, "__slots__", ()) - and "__weakref__" not in names - and not weakref_inherited - ): - names += ("__weakref__",) - - cached_properties = { - name: cached_prop.func - for name, cached_prop in cd.items() - if isinstance(cached_prop, cached_property) - } - - # Collect methods with a `__class__` reference that are shadowed in the new class. - # To know to update them. - additional_closure_functions_to_update = [] - if cached_properties: - class_annotations = _get_annotations(self._cls) - for name, func in cached_properties.items(): - # Add cached properties to names for slotting. - names += (name,) - # Clear out function from class to avoid clashing. - del cd[name] - additional_closure_functions_to_update.append(func) - annotation = inspect.signature(func).return_annotation - if annotation is not inspect.Parameter.empty: - class_annotations[name] = annotation - - original_getattr = cd.get("__getattr__") - if original_getattr is not None: - additional_closure_functions_to_update.append(original_getattr) - - cd["__getattr__"] = _make_cached_property_getattr( - cached_properties, original_getattr, self._cls - ) - - # We only add the names of attributes that aren't inherited. - # Setting __slots__ to inherited attributes wastes memory. - slot_names = [name for name in names if name not in base_names] - - # There are slots for attributes from current class - # that are defined in parent classes. - # As their descriptors may be overridden by a child class, - # we collect them here and update the class dict - reused_slots = { - slot: slot_descriptor - for slot, slot_descriptor in existing_slots.items() - if slot in slot_names - } - slot_names = [name for name in slot_names if name not in reused_slots] - cd.update(reused_slots) - if self._cache_hash: - slot_names.append(_HASH_CACHE_FIELD) - - cd["__slots__"] = tuple(slot_names) - - cd["__qualname__"] = self._cls.__qualname__ - - # Create new class based on old class and our methods. - cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) - - # The following is a fix for - # . - # If a method mentions `__class__` or uses the no-arg super(), the - # compiler will bake a reference to the class in the method itself - # as `method.__closure__`. Since we replace the class with a - # clone, we rewrite these references so it keeps working. - for item in itertools.chain( - cls.__dict__.values(), additional_closure_functions_to_update - ): - if isinstance(item, (classmethod, staticmethod)): - # Class- and staticmethods hide their functions inside. - # These might need to be rewritten as well. - closure_cells = getattr(item.__func__, "__closure__", None) - elif isinstance(item, property): - # Workaround for property `super()` shortcut (PY3-only). - # There is no universal way for other descriptors. - closure_cells = getattr(item.fget, "__closure__", None) - else: - closure_cells = getattr(item, "__closure__", None) - - if not closure_cells: # Catch None or the empty list. - continue - for cell in closure_cells: - try: - match = cell.cell_contents is self._cls - except ValueError: # noqa: PERF203 - # ValueError: Cell is empty - pass - else: - if match: - cell.cell_contents = cls - return cls - - def add_repr(self, ns): - script, globs = _make_repr_script(self._attrs, ns) - - def _attach_repr(cls_dict, globs): - cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) - - self._script_snippets.append((script, globs, _attach_repr)) - self._repr_added = True - return self - - def add_str(self): - if not self._repr_added: - msg = "__str__ can only be generated if a __repr__ exists." - raise ValueError(msg) - - def __str__(self): - return self.__repr__() - - self._cls_dict["__str__"] = self._add_method_dunders(__str__) - return self - - def _make_getstate_setstate(self): - """ - Create custom __setstate__ and __getstate__ methods. - """ - # __weakref__ is not writable. - state_attr_names = tuple( - an for an in self._attr_names if an != "__weakref__" - ) - - def slots_getstate(self): - """ - Automatically created by attrs. - """ - return {name: getattr(self, name) for name in state_attr_names} - - hash_caching_enabled = self._cache_hash - - def slots_setstate(self, state): - """ - Automatically created by attrs. - """ - __bound_setattr = _OBJ_SETATTR.__get__(self) - if isinstance(state, tuple): - # Backward compatibility with attrs instances pickled with - # attrs versions before v22.2.0 which stored tuples. - for name, value in zip(state_attr_names, state): - __bound_setattr(name, value) - else: - for name in state_attr_names: - if name in state: - __bound_setattr(name, state[name]) - - # The hash code cache is not included when the object is - # serialized, but it still needs to be initialized to None to - # indicate that the first call to __hash__ should be a cache - # miss. - if hash_caching_enabled: - __bound_setattr(_HASH_CACHE_FIELD, None) - - return slots_getstate, slots_setstate - - def make_unhashable(self): - self._cls_dict["__hash__"] = None - return self - - def add_hash(self): - script, globs = _make_hash_script( - self._cls, - self._attrs, - frozen=self._frozen, - cache_hash=self._cache_hash, - ) - - def attach_hash(cls_dict: dict, locs: dict) -> None: - cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) - - self._script_snippets.append((script, globs, attach_hash)) - - return self - - def add_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=False, - ) - - def _attach_init(cls_dict, globs): - init = globs["__init__"] - init.__annotations__ = annotations - cls_dict["__init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_init)) - - return self - - def add_replace(self): - self._cls_dict["__replace__"] = self._add_method_dunders( - lambda self, **changes: evolve(self, **changes) - ) - return self - - def add_match_args(self): - self._cls_dict["__match_args__"] = tuple( - field.name - for field in self._attrs - if field.init and not field.kw_only - ) - - def add_attrs_init(self): - script, globs, annotations = _make_init_script( - self._cls, - self._attrs, - self._has_pre_init, - self._pre_init_has_args, - self._has_post_init, - self._frozen, - self._slots, - self._cache_hash, - self._base_attr_map, - self._is_exc, - self._on_setattr, - attrs_init=True, - ) - - def _attach_attrs_init(cls_dict, globs): - init = globs["__attrs_init__"] - init.__annotations__ = annotations - cls_dict["__attrs_init__"] = self._add_method_dunders(init) - - self._script_snippets.append((script, globs, _attach_attrs_init)) - - return self - - def add_eq(self): - cd = self._cls_dict - - script, globs = _make_eq_script(self._attrs) - - def _attach_eq(cls_dict, globs): - cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) - - self._script_snippets.append((script, globs, _attach_eq)) - - cd["__ne__"] = __ne__ - - return self - - def add_order(self): - cd = self._cls_dict - - cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( - self._add_method_dunders(meth) - for meth in _make_order(self._cls, self._attrs) - ) - - return self - - def add_setattr(self): - sa_attrs = {} - for a in self._attrs: - on_setattr = a.on_setattr or self._on_setattr - if on_setattr and on_setattr is not setters.NO_OP: - sa_attrs[a.name] = a, on_setattr - - if not sa_attrs: - return self - - if self._has_custom_setattr: - # We need to write a __setattr__ but there already is one! - msg = "Can't combine custom __setattr__ with on_setattr hooks." - raise ValueError(msg) - - # docstring comes from _add_method_dunders - def __setattr__(self, name, val): - try: - a, hook = sa_attrs[name] - except KeyError: - nval = val - else: - nval = hook(self, a, val) - - _OBJ_SETATTR(self, name, nval) - - self._cls_dict["__attrs_own_setattr__"] = True - self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) - self._wrote_own_setattr = True - - return self - - def _add_method_dunders_unsafe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method*. - """ - method.__module__ = self._cls.__module__ - - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - method.__doc__ = ( - f"Method generated by attrs for class {self._cls.__qualname__}." - ) - - return method - - def _add_method_dunders_safe(self, method: Callable) -> Callable: - """ - Add __module__ and __qualname__ to a *method* if possible. - """ - with contextlib.suppress(AttributeError): - method.__module__ = self._cls.__module__ - - with contextlib.suppress(AttributeError): - method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" - - with contextlib.suppress(AttributeError): - method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." - - return method - - -def _determine_attrs_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - return cmp, cmp - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq = default_eq - - if order is None: - order = eq - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, order - - -def _determine_attrib_eq_order(cmp, eq, order, default_eq): - """ - Validate the combination of *cmp*, *eq*, and *order*. Derive the effective - values of eq and order. If *eq* is None, set it to *default_eq*. - """ - if cmp is not None and any((eq is not None, order is not None)): - msg = "Don't mix `cmp` with `eq' and `order`." - raise ValueError(msg) - - def decide_callable_or_boolean(value): - """ - Decide whether a key function is used. - """ - if callable(value): - value, key = True, value - else: - key = None - return value, key - - # cmp takes precedence due to bw-compatibility. - if cmp is not None: - cmp, cmp_key = decide_callable_or_boolean(cmp) - return cmp, cmp_key, cmp, cmp_key - - # If left None, equality is set to the specified default and ordering - # mirrors equality. - if eq is None: - eq, eq_key = default_eq, None - else: - eq, eq_key = decide_callable_or_boolean(eq) - - if order is None: - order, order_key = eq, eq_key - else: - order, order_key = decide_callable_or_boolean(order) - - if eq is False and order is True: - msg = "`order` can only be True if `eq` is True too." - raise ValueError(msg) - - return eq, eq_key, order, order_key - - -def _determine_whether_to_implement( - cls, flag, auto_detect, dunders, default=True -): - """ - Check whether we should implement a set of methods for *cls*. - - *flag* is the argument passed into @attr.s like 'init', *auto_detect* the - same as passed into @attr.s and *dunders* is a tuple of attribute names - whose presence signal that the user has implemented it themselves. - - Return *default* if no reason for either for or against is found. - """ - if flag is True or flag is False: - return flag - - if flag is None and auto_detect is False: - return default - - # Logically, flag is None and auto_detect is True here. - for dunder in dunders: - if _has_own_attribute(cls, dunder): - return False - - return default - - -def attrs( - maybe_cls=None, - these=None, - repr_ns=None, - repr=None, - cmp=None, - hash=None, - init=None, - slots=False, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=False, - kw_only=False, - cache_hash=False, - auto_exc=False, - eq=None, - order=None, - auto_detect=False, - collect_by_mro=False, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - unsafe_hash=None, - force_kw_only=True, -): - r""" - A class decorator that adds :term:`dunder methods` according to the - specified attributes using `attr.ib` or the *these* argument. - - Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will - *never* go away, though). - - Args: - repr_ns (str): - When using nested classes, there was no way in Python 2 to - automatically detect that. This argument allows to set a custom - name for a more meaningful ``repr`` output. This argument is - pointless in Python 3 and is therefore deprecated. - - .. caution:: - Refer to `attrs.define` for the rest of the parameters, but note that they - can have different defaults. - - Notably, leaving *on_setattr* as `None` will **not** add any hooks. - - .. versionadded:: 16.0.0 *slots* - .. versionadded:: 16.1.0 *frozen* - .. versionadded:: 16.3.0 *str* - .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. - .. versionchanged:: 17.1.0 - *hash* supports `None` as value which is also the default now. - .. versionadded:: 17.3.0 *auto_attribs* - .. versionchanged:: 18.1.0 - If *these* is passed, no attributes are deleted from the class body. - .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. - .. versionadded:: 18.2.0 *weakref_slot* - .. deprecated:: 18.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a - `DeprecationWarning` if the classes compared are subclasses of - each other. ``__eq`` and ``__ne__`` never tried to compared subclasses - to each other. - .. versionchanged:: 19.2.0 - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider - subclasses comparable anymore. - .. versionadded:: 18.2.0 *kw_only* - .. versionadded:: 18.2.0 *cache_hash* - .. versionadded:: 19.1.0 *auto_exc* - .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. - .. versionadded:: 19.2.0 *eq* and *order* - .. versionadded:: 20.1.0 *auto_detect* - .. versionadded:: 20.1.0 *collect_by_mro* - .. versionadded:: 20.1.0 *getstate_setstate* - .. versionadded:: 20.1.0 *on_setattr* - .. versionadded:: 20.3.0 *field_transformer* - .. versionchanged:: 21.1.0 - ``init=False`` injects ``__attrs_init__`` - .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` - .. versionchanged:: 21.1.0 *cmp* undeprecated - .. versionadded:: 21.3.0 *match_args* - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. deprecated:: 24.1.0 *repr_ns* - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionchanged:: 25.4.0 - *kw_only* now only applies to attributes defined in the current class, - and respects attribute-level ``kw_only=False`` settings. - .. versionadded:: 25.4.0 *force_kw_only* - """ - if repr_ns is not None: - import warnings - - warnings.warn( - DeprecationWarning( - "The `repr_ns` argument is deprecated and will be removed in or after August 2025." - ), - stacklevel=2, - ) - - eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) - - # unsafe_hash takes precedence due to PEP 681. - if unsafe_hash is not None: - hash = unsafe_hash - - if isinstance(on_setattr, (list, tuple)): - on_setattr = setters.pipe(*on_setattr) - - def wrap(cls): - nonlocal hash - is_frozen = frozen or _has_frozen_base_class(cls) - is_exc = auto_exc is True and issubclass(cls, BaseException) - has_own_setattr = auto_detect and _has_own_attribute( - cls, "__setattr__" - ) - - if has_own_setattr and is_frozen: - msg = "Can't freeze a class with a custom __setattr__." - raise ValueError(msg) - - eq = not is_exc and _determine_whether_to_implement( - cls, eq_, auto_detect, ("__eq__", "__ne__") - ) - - Hashability = ClassProps.Hashability - - if is_exc: - hashability = Hashability.LEAVE_ALONE - elif hash is True: - hashability = ( - Hashability.HASHABLE_CACHED - if cache_hash - else Hashability.HASHABLE - ) - elif hash is False: - hashability = Hashability.LEAVE_ALONE - elif hash is None: - if auto_detect is True and _has_own_attribute(cls, "__hash__"): - hashability = Hashability.LEAVE_ALONE - elif eq is True and is_frozen is True: - hashability = ( - Hashability.HASHABLE_CACHED - if cache_hash - else Hashability.HASHABLE - ) - elif eq is False: - hashability = Hashability.LEAVE_ALONE - else: - hashability = Hashability.UNHASHABLE - else: - msg = "Invalid value for hash. Must be True, False, or None." - raise TypeError(msg) - - KeywordOnly = ClassProps.KeywordOnly - if kw_only: - kwo = KeywordOnly.FORCE if force_kw_only else KeywordOnly.YES - else: - kwo = KeywordOnly.NO - - props = ClassProps( - is_exception=is_exc, - is_frozen=is_frozen, - is_slotted=slots, - collected_fields_by_mro=collect_by_mro, - added_init=_determine_whether_to_implement( - cls, init, auto_detect, ("__init__",) - ), - added_repr=_determine_whether_to_implement( - cls, repr, auto_detect, ("__repr__",) - ), - added_eq=eq, - added_ordering=not is_exc - and _determine_whether_to_implement( - cls, - order_, - auto_detect, - ("__lt__", "__le__", "__gt__", "__ge__"), - ), - hashability=hashability, - added_match_args=match_args, - kw_only=kwo, - has_weakref_slot=weakref_slot, - added_str=str, - added_pickling=_determine_whether_to_implement( - cls, - getstate_setstate, - auto_detect, - ("__getstate__", "__setstate__"), - default=slots, - ), - on_setattr_hook=on_setattr, - field_transformer=field_transformer, - ) - - if not props.is_hashable and cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." - raise TypeError(msg) - - builder = _ClassBuilder( - cls, - these, - auto_attribs=auto_attribs, - props=props, - has_custom_setattr=has_own_setattr, - ) - - if props.added_repr: - builder.add_repr(repr_ns) - - if props.added_str: - builder.add_str() - - if props.added_eq: - builder.add_eq() - if props.added_ordering: - builder.add_order() - - if not frozen: - builder.add_setattr() - - if props.is_hashable: - builder.add_hash() - elif props.hashability is Hashability.UNHASHABLE: - builder.make_unhashable() - - if props.added_init: - builder.add_init() - else: - builder.add_attrs_init() - if cache_hash: - msg = "Invalid value for cache_hash. To use hash caching, init must be True." - raise TypeError(msg) - - if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): - builder.add_replace() - - if ( - PY_3_10_PLUS - and match_args - and not _has_own_attribute(cls, "__match_args__") - ): - builder.add_match_args() - - return builder.build_class() - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -_attrs = attrs -""" -Internal alias so we can use it in functions that take an argument called -*attrs*. -""" - - -def _has_frozen_base_class(cls): - """ - Check whether *cls* has a frozen ancestor by looking at its - __setattr__. - """ - return cls.__setattr__ is _frozen_setattrs - - -def _generate_unique_filename(cls: type, func_name: str) -> str: - """ - Create a "filename" suitable for a function being generated. - """ - return ( - f"" - ) - - -def _make_hash_script( - cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool -) -> tuple[str, dict]: - attrs = tuple( - a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) - ) - - tab = " " - - type_hash = hash(_generate_unique_filename(cls, "hash")) - # If eq is custom generated, we need to include the functions in globs - globs = {} - - hash_def = "def __hash__(self" - hash_func = "hash((" - closing_braces = "))" - if not cache_hash: - hash_def += "):" - else: - hash_def += ", *" - - hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" - hash_func = "_cache_wrapper(" + hash_func - closing_braces += ")" - - method_lines = [hash_def] - - def append_hash_computation_lines(prefix, indent): - """ - Generate the code for actually computing the hash code. - Below this will either be returned directly or used to compute - a value which is then cached, depending on the value of cache_hash - """ - - method_lines.extend( - [ - indent + prefix + hash_func, - indent + f" {type_hash},", - ] - ) - - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - globs[cmp_name] = a.eq_key - method_lines.append( - indent + f" {cmp_name}(self.{a.name})," - ) - else: - method_lines.append(indent + f" self.{a.name},") - - method_lines.append(indent + " " + closing_braces) - - if cache_hash: - method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") - if frozen: - append_hash_computation_lines( - f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 - ) - method_lines.append(tab * 2 + ")") # close __setattr__ - else: - append_hash_computation_lines( - f"self.{_HASH_CACHE_FIELD} = ", tab * 2 - ) - method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") - else: - append_hash_computation_lines("return ", tab) - - script = "\n".join(method_lines) - return script, globs - - -def _add_hash(cls: type, attrs: list[Attribute]): - """ - Add a hash method to *cls*. - """ - script, globs = _make_hash_script( - cls, attrs, frozen=False, cache_hash=False - ) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__hash__") - ) - cls.__hash__ = globs["__hash__"] - return cls - - -def __ne__(self, other): - """ - Check equality and either forward a NotImplemented or - return the result negated. - """ - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - - return not result - - -def _make_eq_script(attrs: list) -> tuple[str, dict]: - """ - Create __eq__ method for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.eq] - - lines = [ - "def __eq__(self, other):", - " if other.__class__ is not self.__class__:", - " return NotImplemented", - ] - - globs = {} - if attrs: - lines.append(" return (") - for a in attrs: - if a.eq_key: - cmp_name = f"_{a.name}_key" - # Add the key function to the global namespace - # of the evaluated function. - globs[cmp_name] = a.eq_key - lines.append( - f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" - ) - else: - lines.append(f" self.{a.name} == other.{a.name}") - if a is not attrs[-1]: - lines[-1] = f"{lines[-1]} and" - lines.append(" )") - else: - lines.append(" return True") - - script = "\n".join(lines) - - return script, globs - - -def _make_order(cls, attrs): - """ - Create ordering methods for *cls* with *attrs*. - """ - attrs = [a for a in attrs if a.order] - - def attrs_to_tuple(obj): - """ - Save us some typing. - """ - return tuple( - key(value) if key else value - for value, key in ( - (getattr(obj, a.name), a.order_key) for a in attrs - ) - ) - - def __lt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) < attrs_to_tuple(other) - - return NotImplemented - - def __le__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) <= attrs_to_tuple(other) - - return NotImplemented - - def __gt__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) > attrs_to_tuple(other) - - return NotImplemented - - def __ge__(self, other): - """ - Automatically created by attrs. - """ - if other.__class__ is self.__class__: - return attrs_to_tuple(self) >= attrs_to_tuple(other) - - return NotImplemented - - return __lt__, __le__, __gt__, __ge__ - - -def _add_eq(cls, attrs=None): - """ - Add equality methods to *cls* with *attrs*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_eq_script(attrs) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__eq__") - ) - cls.__eq__ = globs["__eq__"] - cls.__ne__ = __ne__ - - return cls - - -def _make_repr_script(attrs, ns) -> tuple[str, dict]: - """ - Create the source and globs for a __repr__ and return it. - """ - # Figure out which attributes to include, and which function to use to - # format them. The a.repr value can be either bool or a custom - # callable. - attr_names_with_reprs = tuple( - (a.name, (repr if a.repr is True else a.repr), a.init) - for a in attrs - if a.repr is not False - ) - globs = { - name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr - } - globs["_compat"] = _compat - globs["AttributeError"] = AttributeError - globs["NOTHING"] = NOTHING - attribute_fragments = [] - for name, r, i in attr_names_with_reprs: - accessor = ( - "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' - ) - fragment = ( - "%s={%s!r}" % (name, accessor) - if r == repr - else "%s={%s_repr(%s)}" % (name, name, accessor) - ) - attribute_fragments.append(fragment) - repr_fragment = ", ".join(attribute_fragments) - - if ns is None: - cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' - else: - cls_name_fragment = ns + ".{self.__class__.__name__}" - - lines = [ - "def __repr__(self):", - " try:", - " already_repring = _compat.repr_context.already_repring", - " except AttributeError:", - " already_repring = {id(self),}", - " _compat.repr_context.already_repring = already_repring", - " else:", - " if id(self) in already_repring:", - " return '...'", - " else:", - " already_repring.add(id(self))", - " try:", - f" return f'{cls_name_fragment}({repr_fragment})'", - " finally:", - " already_repring.remove(id(self))", - ] - - return "\n".join(lines), globs - - -def _add_repr(cls, ns=None, attrs=None): - """ - Add a repr method to *cls*. - """ - if attrs is None: - attrs = cls.__attrs_attrs__ - - script, globs = _make_repr_script(attrs, ns) - _compile_and_eval( - script, globs, filename=_generate_unique_filename(cls, "__repr__") - ) - cls.__repr__ = globs["__repr__"] - return cls - - -def fields(cls): - """ - Return the tuple of *attrs* attributes for a class. - - The tuple also allows accessing the fields by their names (see below for - examples). - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - tuple (with name accessors) of `attrs.Attribute` - - .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields - by name. - .. versionchanged:: 23.1.0 Add support for generic classes. - """ - generic_base = get_generic_base(cls) - - if generic_base is None and not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - - attrs = getattr(cls, "__attrs_attrs__", None) - - if attrs is None: - if generic_base is not None: - attrs = getattr(generic_base, "__attrs_attrs__", None) - if attrs is not None: - # Even though this is global state, stick it on here to speed - # it up. We rely on `cls` being cached for this to be - # efficient. - cls.__attrs_attrs__ = attrs - return attrs - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - - return attrs - - -def fields_dict(cls): - """ - Return an ordered dictionary of *attrs* attributes for a class, whose keys - are the attribute names. - - Args: - cls (type): Class to introspect. - - Raises: - TypeError: If *cls* is not a class. - - attrs.exceptions.NotAnAttrsClassError: - If *cls* is not an *attrs* class. - - Returns: - dict[str, attrs.Attribute]: Dict of attribute name to definition - - .. versionadded:: 18.1.0 - """ - if not isinstance(cls, type): - msg = "Passed object must be a class." - raise TypeError(msg) - attrs = getattr(cls, "__attrs_attrs__", None) - if attrs is None: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) - return {a.name: a for a in attrs} - - -def validate(inst): - """ - Validate all attributes on *inst* that have a validator. - - Leaves all exceptions through. - - Args: - inst: Instance of a class with *attrs* attributes. - """ - if _config._run_validators is False: - return - - for a in fields(inst.__class__): - v = a.validator - if v is not None: - v(inst, a, getattr(inst, a.name)) - - -def _is_slot_attr(a_name, base_attr_map): - """ - Check if the attribute name comes from a slot class. - """ - cls = base_attr_map.get(a_name) - return cls and "__slots__" in cls.__dict__ - - -def _make_init_script( - cls, - attrs, - pre_init, - pre_init_has_args, - post_init, - frozen, - slots, - cache_hash, - base_attr_map, - is_exc, - cls_on_setattr, - attrs_init, -) -> tuple[str, dict, dict]: - has_cls_on_setattr = ( - cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP - ) - - if frozen and has_cls_on_setattr: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = cache_hash or frozen - filtered_attrs = [] - attr_dict = {} - for a in attrs: - if not a.init and a.default is NOTHING: - continue - - filtered_attrs.append(a) - attr_dict[a.name] = a - - if a.on_setattr is not None: - if frozen is True: - msg = "Frozen classes can't use on_setattr." - raise ValueError(msg) - - needs_cached_setattr = True - elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: - needs_cached_setattr = True - - script, globs, annotations = _attrs_to_init_script( - filtered_attrs, - frozen, - slots, - pre_init, - pre_init_has_args, - post_init, - cache_hash, - base_attr_map, - is_exc, - needs_cached_setattr, - has_cls_on_setattr, - "__attrs_init__" if attrs_init else "__init__", - ) - if cls.__module__ in sys.modules: - # This makes typing.get_type_hints(CLS.__init__) resolve string types. - globs.update(sys.modules[cls.__module__].__dict__) - - globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) - - if needs_cached_setattr: - # Save the lookup overhead in __init__ if we need to circumvent - # setattr hooks. - globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ - - return script, globs, annotations - - -def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*. - """ - return f"_setattr('{attr_name}', {value_var})" - - -def _setattr_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Use the cached object.setattr to set *attr_name* to *value_var*, but run - its converter first. - """ - return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" - - -def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise - relegate to _setattr. - """ - if has_on_setattr: - return _setattr(attr_name, value, True) - - return f"self.{attr_name} = {value}" - - -def _assign_with_converter( - attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter -) -> str: - """ - Unless *attr_name* has an on_setattr hook, use normal assignment after - conversion. Otherwise relegate to _setattr_with_converter. - """ - if has_on_setattr: - return _setattr_with_converter(attr_name, value_var, True, converter) - - return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" - - -def _determine_setters( - frozen: bool, slots: bool, base_attr_map: dict[str, type] -): - """ - Determine the correct setter functions based on whether a class is frozen - and/or slotted. - """ - if frozen is True: - if slots is True: - return (), _setattr, _setattr_with_converter - - # Dict frozen classes assign directly to __dict__. - # But only if the attribute doesn't come from an ancestor slot - # class. - # Note _inst_dict will be used again below if cache_hash is True - - def fmt_setter( - attr_name: str, value_var: str, has_on_setattr: bool - ) -> str: - if _is_slot_attr(attr_name, base_attr_map): - return _setattr(attr_name, value_var, has_on_setattr) - - return f"_inst_dict['{attr_name}'] = {value_var}" - - def fmt_setter_with_converter( - attr_name: str, - value_var: str, - has_on_setattr: bool, - converter: Converter, - ) -> str: - if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): - return _setattr_with_converter( - attr_name, value_var, has_on_setattr, converter - ) - - return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" - - return ( - ("_inst_dict = self.__dict__",), - fmt_setter, - fmt_setter_with_converter, - ) - - # Not frozen -- we can just assign directly. - return (), _assign, _assign_with_converter - - -def _attrs_to_init_script( - attrs: list[Attribute], - is_frozen: bool, - is_slotted: bool, - call_pre_init: bool, - pre_init_has_args: bool, - call_post_init: bool, - does_cache_hash: bool, - base_attr_map: dict[str, type], - is_exc: bool, - needs_cached_setattr: bool, - has_cls_on_setattr: bool, - method_name: str, -) -> tuple[str, dict, dict]: - """ - Return a script of an initializer for *attrs*, a dict of globals, and - annotations for the initializer. - - The globals are required by the generated script. - """ - lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] - - if needs_cached_setattr: - lines.append( - # Circumvent the __setattr__ descriptor to save one lookup per - # assignment. Note _setattr will be used again below if - # does_cache_hash is True. - "_setattr = _cached_setattr_get(self)" - ) - - extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( - is_frozen, is_slotted, base_attr_map - ) - lines.extend(extra_lines) - - args = [] # Parameters in the definition of __init__ - pre_init_args = [] # Parameters in the call to __attrs_pre_init__ - kw_only_args = [] # Used for both 'args' and 'pre_init_args' above - attrs_to_validate = [] - - # This is a dictionary of names to validator and converter callables. - # Injecting this into __init__ globals lets us avoid lookups. - names_for_globals = {} - annotations = {"return": None} - - for a in attrs: - if a.validator: - attrs_to_validate.append(a) - - attr_name = a.name - has_on_setattr = a.on_setattr is not None or ( - a.on_setattr is not setters.NO_OP and has_cls_on_setattr - ) - # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not - # explicitly provided - arg_name = a.alias - - has_factory = isinstance(a.default, Factory) - maybe_self = "self" if has_factory and a.default.takes_self else "" - - if a.converter is not None and not isinstance(a.converter, Converter): - converter = Converter(a.converter) - else: - converter = a.converter - - if a.init is False: - if has_factory: - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - init_factory_name + f"({maybe_self})", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - elif converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - fmt_setter( - attr_name, - f"attr_dict['{attr_name}'].default", - has_on_setattr, - ) - ) - elif a.default is not NOTHING and not has_factory: - arg = f"{arg_name}=attr_dict['{attr_name}'].default" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - pre_init_args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - elif has_factory: - arg = f"{arg_name}=NOTHING" - if a.kw_only: - kw_only_args.append(arg) - else: - args.append(arg) - pre_init_args.append(arg_name) - lines.append(f"if {arg_name} is not NOTHING:") - - init_factory_name = _INIT_FACTORY_PAT % (a.name,) - if converter is not None: - lines.append( - " " - + fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter_with_converter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - converter, - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append( - " " + fmt_setter(attr_name, arg_name, has_on_setattr) - ) - lines.append("else:") - lines.append( - " " - + fmt_setter( - attr_name, - init_factory_name + "(" + maybe_self + ")", - has_on_setattr, - ) - ) - names_for_globals[init_factory_name] = a.default.factory - else: - if a.kw_only: - kw_only_args.append(arg_name) - else: - args.append(arg_name) - pre_init_args.append(arg_name) - - if converter is not None: - lines.append( - fmt_setter_with_converter( - attr_name, arg_name, has_on_setattr, converter - ) - ) - names_for_globals[converter._get_global_name(a.name)] = ( - converter.converter - ) - else: - lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) - - if a.init is True: - if a.type is not None and converter is None: - annotations[arg_name] = a.type - elif converter is not None and converter._first_param_type: - # Use the type from the converter if present. - annotations[arg_name] = converter._first_param_type - - if attrs_to_validate: # we can skip this if there are no validators. - names_for_globals["_config"] = _config - lines.append("if _config._run_validators is True:") - for a in attrs_to_validate: - val_name = "__attr_validator_" + a.name - attr_name = "__attr_" + a.name - lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") - names_for_globals[val_name] = a.validator - names_for_globals[attr_name] = a - - if call_post_init: - lines.append("self.__attrs_post_init__()") - - # Because this is set only after __attrs_post_init__ is called, a crash - # will result if post-init tries to access the hash code. This seemed - # preferable to setting this beforehand, in which case alteration to field - # values during post-init combined with post-init accessing the hash code - # would result in silent bugs. - if does_cache_hash: - if is_frozen: - if is_slotted: - init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" - else: - init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" - else: - init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" - lines.append(init_hash_cache) - - # For exceptions we rely on BaseException.__init__ for proper - # initialization. - if is_exc: - vals = ",".join(f"self.{a.name}" for a in attrs if a.init) - - lines.append(f"BaseException.__init__(self, {vals})") - - args = ", ".join(args) - pre_init_args = ", ".join(pre_init_args) - if kw_only_args: - # leading comma & kw_only args - args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" - pre_init_kw_only_args = ", ".join( - [ - f"{kw_arg_name}={kw_arg_name}" - # We need to remove the defaults from the kw_only_args. - for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) - ] - ) - pre_init_args += ", " if pre_init_args else "" - pre_init_args += pre_init_kw_only_args - - if call_pre_init and pre_init_has_args: - # If pre init method has arguments, pass the values given to __init__. - lines[0] = f"self.__attrs_pre_init__({pre_init_args})" - - # Python <3.12 doesn't allow backslashes in f-strings. - NL = "\n " - return ( - f"""def {method_name}(self, {args}): - {NL.join(lines) if lines else "pass"} -""", - names_for_globals, - annotations, - ) - - -def _default_init_alias_for(name: str) -> str: - """ - The default __init__ parameter name for a field. - - This performs private-name adjustment via leading-unscore stripping, - and is the default value of Attribute.alias if not provided. - """ - - return name.lstrip("_") - - -class Attribute: - """ - *Read-only* representation of an attribute. - - .. warning:: - - You should never instantiate this class yourself. - - The class has *all* arguments of `attr.ib` (except for ``factory`` which is - only syntactic sugar for ``default=Factory(...)`` plus the following: - - - ``name`` (`str`): The name of the attribute. - - ``alias`` (`str`): The __init__ parameter name of the attribute, after - any explicit overrides and default private-attribute-name handling. - - ``inherited`` (`bool`): Whether or not that attribute has been inherited - from a base class. - - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The - callables that are used for comparing and ordering objects by this - attribute, respectively. These are set by passing a callable to - `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also - :ref:`comparison customization `. - - Instances of this class are frequently used for introspection purposes - like: - - - `fields` returns a tuple of them. - - Validators get them passed as the first argument. - - The :ref:`field transformer ` hook receives a list of - them. - - The ``alias`` property exposes the __init__ parameter name of the field, - with any overrides and default private-attribute handling applied. - - - .. versionadded:: 20.1.0 *inherited* - .. versionadded:: 20.1.0 *on_setattr* - .. versionchanged:: 20.2.0 *inherited* is not taken into account for - equality checks and hashing anymore. - .. versionadded:: 21.1.0 *eq_key* and *order_key* - .. versionadded:: 22.2.0 *alias* - - For the full version history of the fields, see `attr.ib`. - """ - - # These slots must NOT be reordered because we use them later for - # instantiation. - __slots__ = ( # noqa: RUF023 - "name", - "default", - "validator", - "repr", - "eq", - "eq_key", - "order", - "order_key", - "hash", - "init", - "metadata", - "type", - "converter", - "kw_only", - "inherited", - "on_setattr", - "alias", - ) - - def __init__( - self, - name, - default, - validator, - repr, - cmp, # XXX: unused, remove along with other cmp code. - hash, - init, - inherited, - metadata=None, - type=None, - converter=None, - kw_only=False, - eq=None, - eq_key=None, - order=None, - order_key=None, - on_setattr=None, - alias=None, - ): - eq, eq_key, order, order_key = _determine_attrib_eq_order( - cmp, eq_key or eq, order_key or order, True - ) - - # Cache this descriptor here to speed things up later. - bound_setattr = _OBJ_SETATTR.__get__(self) - - # Despite the big red warning, people *do* instantiate `Attribute` - # themselves. - bound_setattr("name", name) - bound_setattr("default", default) - bound_setattr("validator", validator) - bound_setattr("repr", repr) - bound_setattr("eq", eq) - bound_setattr("eq_key", eq_key) - bound_setattr("order", order) - bound_setattr("order_key", order_key) - bound_setattr("hash", hash) - bound_setattr("init", init) - bound_setattr("converter", converter) - bound_setattr( - "metadata", - ( - types.MappingProxyType(dict(metadata)) # Shallow copy - if metadata - else _EMPTY_METADATA_SINGLETON - ), - ) - bound_setattr("type", type) - bound_setattr("kw_only", kw_only) - bound_setattr("inherited", inherited) - bound_setattr("on_setattr", on_setattr) - bound_setattr("alias", alias) - - def __setattr__(self, name, value): - raise FrozenInstanceError - - @classmethod - def from_counting_attr( - cls, name: str, ca: _CountingAttr, kw_only: bool, type=None - ): - # The 'kw_only' argument is the class-level setting, and is used if the - # attribute itself does not explicitly set 'kw_only'. - # type holds the annotated value. deal with conflicts: - if type is None: - type = ca.type - elif ca.type is not None: - msg = f"Type annotation and type argument cannot both be present for '{name}'." - raise ValueError(msg) - return cls( - name, - ca._default, - ca._validator, - ca.repr, - None, - ca.hash, - ca.init, - False, - ca.metadata, - type, - ca.converter, - kw_only if ca.kw_only is None else ca.kw_only, - ca.eq, - ca.eq_key, - ca.order, - ca.order_key, - ca.on_setattr, - ca.alias, - ) - - # Don't use attrs.evolve since fields(Attribute) doesn't work - def evolve(self, **changes): - """ - Copy *self* and apply *changes*. - - This works similarly to `attrs.evolve` but that function does not work - with :class:`attrs.Attribute`. - - It is mainly meant to be used for `transform-fields`. - - .. versionadded:: 20.3.0 - """ - new = copy.copy(self) - - new._setattrs(changes.items()) - - return new - - # Don't use _add_pickle since fields(Attribute) doesn't work - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple( - getattr(self, name) if name != "metadata" else dict(self.metadata) - for name in self.__slots__ - ) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - self._setattrs(zip(self.__slots__, state)) - - def _setattrs(self, name_values_pairs): - bound_setattr = _OBJ_SETATTR.__get__(self) - for name, value in name_values_pairs: - if name != "metadata": - bound_setattr(name, value) - else: - bound_setattr( - name, - ( - types.MappingProxyType(dict(value)) - if value - else _EMPTY_METADATA_SINGLETON - ), - ) - - -_a = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=(name != "metadata"), - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in Attribute.__slots__ -] - -Attribute = _add_hash( - _add_eq( - _add_repr(Attribute, attrs=_a), - attrs=[a for a in _a if a.name != "inherited"], - ), - attrs=[a for a in _a if a.hash and a.name != "inherited"], -) - - -class _CountingAttr: - """ - Intermediate representation of attributes that uses a counter to preserve - the order in which the attributes have been defined. - - *Internal* data structure of the attrs library. Running into is most - likely the result of a bug like a forgotten `@attr.s` decorator. - """ - - __slots__ = ( - "_default", - "_validator", - "alias", - "converter", - "counter", - "eq", - "eq_key", - "hash", - "init", - "kw_only", - "metadata", - "on_setattr", - "order", - "order_key", - "repr", - "type", - ) - __attrs_attrs__ = ( - *tuple( - Attribute( - name=name, - alias=_default_init_alias_for(name), - default=NOTHING, - validator=None, - repr=True, - cmp=None, - hash=True, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ) - for name in ( - "counter", - "_default", - "repr", - "eq", - "order", - "hash", - "init", - "on_setattr", - "alias", - ) - ), - Attribute( - name="metadata", - alias="metadata", - default=None, - validator=None, - repr=True, - cmp=None, - hash=False, - init=True, - kw_only=False, - eq=True, - eq_key=None, - order=False, - order_key=None, - inherited=False, - on_setattr=None, - ), - ) - cls_counter = 0 - - def __init__( - self, - default, - validator, - repr, - cmp, - hash, - init, - converter, - metadata, - type, - kw_only, - eq, - eq_key, - order, - order_key, - on_setattr, - alias, - ): - _CountingAttr.cls_counter += 1 - self.counter = _CountingAttr.cls_counter - self._default = default - self._validator = validator - self.converter = converter - self.repr = repr - self.eq = eq - self.eq_key = eq_key - self.order = order - self.order_key = order_key - self.hash = hash - self.init = init - self.metadata = metadata - self.type = type - self.kw_only = kw_only - self.on_setattr = on_setattr - self.alias = alias - - def validator(self, meth): - """ - Decorator that adds *meth* to the list of validators. - - Returns *meth* unchanged. - - .. versionadded:: 17.1.0 - """ - if self._validator is None: - self._validator = meth - else: - self._validator = and_(self._validator, meth) - return meth - - def default(self, meth): - """ - Decorator that allows to set the default for an attribute. - - Returns *meth* unchanged. - - Raises: - DefaultAlreadySetError: If default has been set before. - - .. versionadded:: 17.1.0 - """ - if self._default is not NOTHING: - raise DefaultAlreadySetError - - self._default = Factory(meth, takes_self=True) - - return meth - - -_CountingAttr = _add_eq(_add_repr(_CountingAttr)) - - -class ClassProps: - """ - Effective class properties as derived from parameters to `attr.s()` or - `define()` decorators. - - This is the same data structure that *attrs* uses internally to decide how - to construct the final class. - - Warning: - - This feature is currently **experimental** and is not covered by our - strict backwards-compatibility guarantees. - - - Attributes: - is_exception (bool): - Whether the class is treated as an exception class. - - is_slotted (bool): - Whether the class is `slotted `. - - has_weakref_slot (bool): - Whether the class has a slot for weak references. - - is_frozen (bool): - Whether the class is frozen. - - kw_only (KeywordOnly): - Whether / how the class enforces keyword-only arguments on the - ``__init__`` method. - - collected_fields_by_mro (bool): - Whether the class fields were collected by method resolution order. - That is, correctly but unlike `dataclasses`. - - added_init (bool): - Whether the class has an *attrs*-generated ``__init__`` method. - - added_repr (bool): - Whether the class has an *attrs*-generated ``__repr__`` method. - - added_eq (bool): - Whether the class has *attrs*-generated equality methods. - - added_ordering (bool): - Whether the class has *attrs*-generated ordering methods. - - hashability (Hashability): How `hashable ` the class is. - - added_match_args (bool): - Whether the class supports positional `match ` over its - fields. - - added_str (bool): - Whether the class has an *attrs*-generated ``__str__`` method. - - added_pickling (bool): - Whether the class has *attrs*-generated ``__getstate__`` and - ``__setstate__`` methods for `pickle`. - - on_setattr_hook (Callable[[Any, Attribute[Any], Any], Any] | None): - The class's ``__setattr__`` hook. - - field_transformer (Callable[[Attribute[Any]], Attribute[Any]] | None): - The class's `field transformers `. - - .. versionadded:: 25.4.0 - """ - - class Hashability(enum.Enum): - """ - The hashability of a class. - - .. versionadded:: 25.4.0 - """ - - HASHABLE = "hashable" - """Write a ``__hash__``.""" - HASHABLE_CACHED = "hashable_cache" - """Write a ``__hash__`` and cache the hash.""" - UNHASHABLE = "unhashable" - """Set ``__hash__`` to ``None``.""" - LEAVE_ALONE = "leave_alone" - """Don't touch ``__hash__``.""" - - class KeywordOnly(enum.Enum): - """ - How attributes should be treated regarding keyword-only parameters. - - .. versionadded:: 25.4.0 - """ - - NO = "no" - """Attributes are not keyword-only.""" - YES = "yes" - """Attributes in current class without kw_only=False are keyword-only.""" - FORCE = "force" - """All attributes are keyword-only.""" - - __slots__ = ( # noqa: RUF023 -- order matters for __init__ - "is_exception", - "is_slotted", - "has_weakref_slot", - "is_frozen", - "kw_only", - "collected_fields_by_mro", - "added_init", - "added_repr", - "added_eq", - "added_ordering", - "hashability", - "added_match_args", - "added_str", - "added_pickling", - "on_setattr_hook", - "field_transformer", - ) - - def __init__( - self, - is_exception, - is_slotted, - has_weakref_slot, - is_frozen, - kw_only, - collected_fields_by_mro, - added_init, - added_repr, - added_eq, - added_ordering, - hashability, - added_match_args, - added_str, - added_pickling, - on_setattr_hook, - field_transformer, - ): - self.is_exception = is_exception - self.is_slotted = is_slotted - self.has_weakref_slot = has_weakref_slot - self.is_frozen = is_frozen - self.kw_only = kw_only - self.collected_fields_by_mro = collected_fields_by_mro - self.added_init = added_init - self.added_repr = added_repr - self.added_eq = added_eq - self.added_ordering = added_ordering - self.hashability = hashability - self.added_match_args = added_match_args - self.added_str = added_str - self.added_pickling = added_pickling - self.on_setattr_hook = on_setattr_hook - self.field_transformer = field_transformer - - @property - def is_hashable(self): - return ( - self.hashability is ClassProps.Hashability.HASHABLE - or self.hashability is ClassProps.Hashability.HASHABLE_CACHED - ) - - -_cas = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - alias=_default_init_alias_for(name), - ) - for name in ClassProps.__slots__ -] - -ClassProps = _add_eq(_add_repr(ClassProps, attrs=_cas), attrs=_cas) - - -class Factory: - """ - Stores a factory callable. - - If passed as the default value to `attrs.field`, the factory is used to - generate a new value. - - Args: - factory (typing.Callable): - A callable that takes either none or exactly one mandatory - positional argument depending on *takes_self*. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. - - .. versionadded:: 17.1.0 *takes_self* - """ - - __slots__ = ("factory", "takes_self") - - def __init__(self, factory, takes_self=False): - self.factory = factory - self.takes_self = takes_self - - def __getstate__(self): - """ - Play nice with pickle. - """ - return tuple(getattr(self, name) for name in self.__slots__) - - def __setstate__(self, state): - """ - Play nice with pickle. - """ - for name, value in zip(self.__slots__, state): - setattr(self, name, value) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in Factory.__slots__ -] - -Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) - - -class Converter: - """ - Stores a converter callable. - - Allows for the wrapped converter to take additional arguments. The - arguments are passed in the order they are documented. - - Args: - converter (Callable): A callable that converts the passed value. - - takes_self (bool): - Pass the partially initialized instance that is being initialized - as a positional argument. (default: `False`) - - takes_field (bool): - Pass the field definition (an :class:`Attribute`) into the - converter as a positional argument. (default: `False`) - - .. versionadded:: 24.1.0 - """ - - __slots__ = ( - "__call__", - "_first_param_type", - "_global_name", - "converter", - "takes_field", - "takes_self", - ) - - def __init__(self, converter, *, takes_self=False, takes_field=False): - self.converter = converter - self.takes_self = takes_self - self.takes_field = takes_field - - ex = _AnnotationExtractor(converter) - self._first_param_type = ex.get_first_param_type() - - if not (self.takes_self or self.takes_field): - self.__call__ = lambda value, _, __: self.converter(value) - elif self.takes_self and not self.takes_field: - self.__call__ = lambda value, instance, __: self.converter( - value, instance - ) - elif not self.takes_self and self.takes_field: - self.__call__ = lambda value, __, field: self.converter( - value, field - ) - else: - self.__call__ = lambda value, instance, field: self.converter( - value, instance, field - ) - - rt = ex.get_return_type() - if rt is not None: - self.__call__.__annotations__["return"] = rt - - @staticmethod - def _get_global_name(attr_name: str) -> str: - """ - Return the name that a converter for an attribute name *attr_name* - would have. - """ - return f"__attr_converter_{attr_name}" - - def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: - """ - Return a string that calls the converter for an attribute name - *attr_name* and the value in variable named *value_var* according to - `self.takes_self` and `self.takes_field`. - """ - if not (self.takes_self or self.takes_field): - return f"{self._get_global_name(attr_name)}({value_var})" - - if self.takes_self and self.takes_field: - return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" - - if self.takes_self: - return f"{self._get_global_name(attr_name)}({value_var}, self)" - - return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" - - def __getstate__(self): - """ - Return a dict containing only converter and takes_self -- the rest gets - computed when loading. - """ - return { - "converter": self.converter, - "takes_self": self.takes_self, - "takes_field": self.takes_field, - } - - def __setstate__(self, state): - """ - Load instance from state. - """ - self.__init__(**state) - - -_f = [ - Attribute( - name=name, - default=NOTHING, - validator=None, - repr=True, - cmp=None, - eq=True, - order=False, - hash=True, - init=True, - inherited=False, - ) - for name in ("converter", "takes_self", "takes_field") -] - -Converter = _add_hash( - _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f -) - - -def make_class( - name, attrs, bases=(object,), class_body=None, **attributes_arguments -): - r""" - A quick way to create a new class called *name* with *attrs*. - - .. note:: - - ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` - which means that it doesn't come with some of the improved defaults. - - For example, if you want the same ``on_setattr`` behavior as in - `attrs.define`, you have to pass the hooks yourself: ``make_class(..., - on_setattr=setters.pipe(setters.convert, setters.validate)`` - - .. warning:: - - It is *your* duty to ensure that the class name and the attribute names - are valid identifiers. ``make_class()`` will *not* validate them for - you. - - Args: - name (str): The name for the new class. - - attrs (list | dict): - A list of names or a dictionary of mappings of names to `attr.ib`\ - s / `attrs.field`\ s. - - The order is deduced from the order of the names or attributes - inside *attrs*. Otherwise the order of the definition of the - attributes is used. - - bases (tuple[type, ...]): Classes that the new class will subclass. - - class_body (dict): - An optional dictionary of class attributes for the new class. - - attributes_arguments: Passed unmodified to `attr.s`. - - Returns: - type: A new class with *attrs*. - - .. versionadded:: 17.1.0 *bases* - .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. - .. versionchanged:: 23.2.0 *class_body* - .. versionchanged:: 25.2.0 Class names can now be unicode. - """ - # Class identifiers are converted into the normal form NFKC while parsing - name = unicodedata.normalize("NFKC", name) - - if isinstance(attrs, dict): - cls_dict = attrs - elif isinstance(attrs, (list, tuple)): - cls_dict = {a: attrib() for a in attrs} - else: - msg = "attrs argument must be a dict or a list." - raise TypeError(msg) - - pre_init = cls_dict.pop("__attrs_pre_init__", None) - post_init = cls_dict.pop("__attrs_post_init__", None) - user_init = cls_dict.pop("__init__", None) - - body = {} - if class_body is not None: - body.update(class_body) - if pre_init is not None: - body["__attrs_pre_init__"] = pre_init - if post_init is not None: - body["__attrs_post_init__"] = post_init - if user_init is not None: - body["__init__"] = user_init - - type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) - - # For pickling to work, the __module__ variable needs to be set to the - # frame where the class is created. Bypass this step in environments where - # sys._getframe is not defined (Jython for example) or sys._getframe is not - # defined for arguments greater than 0 (IronPython). - with contextlib.suppress(AttributeError, ValueError): - type_.__module__ = sys._getframe(1).f_globals.get( - "__name__", "__main__" - ) - - # We do it here for proper warnings with meaningful stacklevel. - cmp = attributes_arguments.pop("cmp", None) - ( - attributes_arguments["eq"], - attributes_arguments["order"], - ) = _determine_attrs_eq_order( - cmp, - attributes_arguments.get("eq"), - attributes_arguments.get("order"), - True, - ) - - cls = _attrs(these=cls_dict, **attributes_arguments)(type_) - # Only add type annotations now or "_attrs()" will complain: - cls.__annotations__ = { - k: v.type for k, v in cls_dict.items() if v.type is not None - } - return cls - - -# These are required by within this module so we define them here and merely -# import into .validators / .converters. - - -@attrs(slots=True, unsafe_hash=True) -class _AndValidator: - """ - Compose many validators to a single one. - """ - - _validators = attrib() - - def __call__(self, inst, attr, value): - for v in self._validators: - v(inst, attr, value) - - -def and_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - .. versionadded:: 17.1.0 - """ - vals = [] - for validator in validators: - vals.extend( - validator._validators - if isinstance(validator, _AndValidator) - else [validator] - ) - - return _AndValidator(tuple(vals)) - - -def pipe(*converters): - """ - A converter that composes multiple converters into one. - - When called on a value, it runs all wrapped converters, returning the - *last* value. - - Type annotations will be inferred from the wrapped converters', if they - have any. - - converters (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of converters. - - .. versionadded:: 20.1.0 - """ - - return_instance = any(isinstance(c, Converter) for c in converters) - - if return_instance: - - def pipe_converter(val, inst, field): - for c in converters: - val = ( - c(val, inst, field) if isinstance(c, Converter) else c(val) - ) - - return val - - else: - - def pipe_converter(val): - for c in converters: - val = c(val) - - return val - - if not converters: - # If the converter list is empty, pipe_converter is the identity. - A = TypeVar("A") - pipe_converter.__annotations__.update({"val": A, "return": A}) - else: - # Get parameter type from first converter. - t = _AnnotationExtractor(converters[0]).get_first_param_type() - if t: - pipe_converter.__annotations__["val"] = t - - last = converters[-1] - if not PY_3_11_PLUS and isinstance(last, Converter): - last = last.__call__ - - # Get return type from last converter. - rt = _AnnotationExtractor(last).get_return_type() - if rt: - pipe_converter.__annotations__["return"] = rt - - if return_instance: - return Converter(pipe_converter, takes_self=True, takes_field=True) - return pipe_converter diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_next_gen.py b/backend/venv39/lib/python3.9/site-packages/attr/_next_gen.py deleted file mode 100644 index 4ccd0da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_next_gen.py +++ /dev/null @@ -1,674 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -These are keyword-only APIs that call `attr.s` and `attr.ib` with different -default values. -""" - -from functools import partial - -from . import setters -from ._funcs import asdict as _asdict -from ._funcs import astuple as _astuple -from ._make import ( - _DEFAULT_ON_SETATTR, - NOTHING, - _frozen_setattrs, - attrib, - attrs, -) -from .exceptions import NotAnAttrsClassError, UnannotatedAttributeError - - -def define( - maybe_cls=None, - *, - these=None, - repr=None, - unsafe_hash=None, - hash=None, - init=None, - slots=True, - frozen=False, - weakref_slot=True, - str=False, - auto_attribs=None, - kw_only=False, - cache_hash=False, - auto_exc=True, - eq=None, - order=False, - auto_detect=True, - getstate_setstate=None, - on_setattr=None, - field_transformer=None, - match_args=True, - force_kw_only=False, -): - r""" - A class decorator that adds :term:`dunder methods` according to - :term:`fields ` specified using :doc:`type annotations `, - `field()` calls, or the *these* argument. - - Since *attrs* patches or replaces an existing class, you cannot use - `object.__init_subclass__` with *attrs* classes, because it runs too early. - As a replacement, you can define ``__attrs_init_subclass__`` on your class. - It will be called by *attrs* classes that subclass it after they're - created. See also :ref:`init-subclass`. - - Args: - slots (bool): - Create a :term:`slotted class ` that's more - memory-efficient. Slotted classes are generally superior to the - default dict classes, but have some gotchas you should know about, - so we encourage you to read the :term:`glossary entry `. - - auto_detect (bool): - Instead of setting the *init*, *repr*, *eq*, and *hash* arguments - explicitly, assume they are set to True **unless any** of the - involved methods for one of the arguments is implemented in the - *current* class (meaning, it is *not* inherited from some base - class). - - So, for example by implementing ``__eq__`` on a class yourself, - *attrs* will deduce ``eq=False`` and will create *neither* - ``__eq__`` *nor* ``__ne__`` (but Python classes come with a - sensible ``__ne__`` by default, so it *should* be enough to only - implement ``__eq__`` in most cases). - - Passing :data:`True` or :data:`False` to *init*, *repr*, *eq*, or *hash* - overrides whatever *auto_detect* would determine. - - auto_exc (bool): - If the class subclasses `BaseException` (which implicitly includes - any subclass of any exception), the following happens to behave - like a well-behaved Python exception class: - - - the values for *eq*, *order*, and *hash* are ignored and the - instances compare and hash by the instance's ids [#]_ , - - all attributes that are either passed into ``__init__`` or have a - default value are additionally available as a tuple in the - ``args`` attribute, - - the value of *str* is ignored leaving ``__str__`` to base - classes. - - .. [#] - Note that *attrs* will *not* remove existing implementations of - ``__hash__`` or the equality methods. It just won't add own - ones. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - A callable that is run whenever the user attempts to set an - attribute (either by assignment like ``i.x = 42`` or by using - `setattr` like ``setattr(i, "x", 42)``). It receives the same - arguments as validators: the instance, the attribute that is being - modified, and the new value. - - If no exception is raised, the attribute is set to the return value - of the callable. - - If a list of callables is passed, they're automatically wrapped in - an `attrs.setters.pipe`. - - If left None, the default behavior is to run converters and - validators whenever an attribute is set. - - init (bool): - Create a ``__init__`` method that initializes the *attrs* - attributes. Leading underscores are stripped for the argument name, - unless an alias is set on the attribute. - - .. seealso:: - `init` shows advanced ways to customize the generated - ``__init__`` method, including executing code before and after. - - repr(bool): - Create a ``__repr__`` method with a human readable representation - of *attrs* attributes. - - str (bool): - Create a ``__str__`` method that is identical to ``__repr__``. This - is usually not necessary except for `Exception`\ s. - - eq (bool | None): - If True or None (default), add ``__eq__`` and ``__ne__`` methods - that check two instances for equality. - - .. seealso:: - `comparison` describes how to customize the comparison behavior - going as far comparing NumPy arrays. - - order (bool | None): - If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` - methods that behave like *eq* above and allow instances to be - ordered. - - They compare the instances as if they were tuples of their *attrs* - attributes if and only if the types of both classes are - *identical*. - - If `None` mirror value of *eq*. - - .. seealso:: `comparison` - - unsafe_hash (bool | None): - If None (default), the ``__hash__`` method is generated according - how *eq* and *frozen* are set. - - 1. If *both* are True, *attrs* will generate a ``__hash__`` for - you. - 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set - to None, marking it unhashable (which it is). - 3. If *eq* is False, ``__hash__`` will be left untouched meaning - the ``__hash__`` method of the base class will be used. If the - base class is `object`, this means it will fall back to id-based - hashing. - - Although not recommended, you can decide for yourself and force - *attrs* to create one (for example, if the class is immutable even - though you didn't freeze it programmatically) by passing True or - not. Both of these cases are rather special and should be used - carefully. - - .. seealso:: - - - Our documentation on `hashing`, - - Python's documentation on `object.__hash__`, - - and the `GitHub issue that led to the default \ behavior - `_ for more - details. - - hash (bool | None): - Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. - - cache_hash (bool): - Ensure that the object's hash code is computed only once and stored - on the object. If this is set to True, hashing must be either - explicitly or implicitly enabled for this class. If the hash code - is cached, avoid any reassignments of fields involved in hash code - computation or mutations of the objects those fields point to after - object creation. If such changes occur, the behavior of the - object's hash code is undefined. - - frozen (bool): - Make instances immutable after initialization. If someone attempts - to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` - is raised. - - .. note:: - - 1. This is achieved by installing a custom ``__setattr__`` - method on your class, so you can't implement your own. - - 2. True immutability is impossible in Python. - - 3. This *does* have a minor a runtime performance `impact - ` when initializing new instances. In other - words: ``__init__`` is slightly slower with ``frozen=True``. - - 4. If a class is frozen, you cannot modify ``self`` in - ``__attrs_post_init__`` or a self-written ``__init__``. You - can circumvent that limitation by using - ``object.__setattr__(self, "attribute_name", value)``. - - 5. Subclasses of a frozen class are frozen too. - - kw_only (bool): - Make attributes keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). Attributes that - explicitly set ``kw_only=False`` are not affected; base class - attributes are also not affected. - - Also see *force_kw_only*. - - weakref_slot (bool): - Make instances weak-referenceable. This has no effect unless - *slots* is True. - - field_transformer (~typing.Callable | None): - A function that is called with the original class object and all - fields right before *attrs* finalizes the class. You can use this, - for example, to automatically add converters or validators to - fields based on their types. - - .. seealso:: `transform-fields` - - match_args (bool): - If True (default), set ``__match_args__`` on the class to support - :pep:`634` (*Structural Pattern Matching*). It is a tuple of all - non-keyword-only ``__init__`` parameter names on Python 3.10 and - later. Ignored on older Python versions. - - collect_by_mro (bool): - If True, *attrs* collects attributes from base classes correctly - according to the `method resolution order - `_. If False, *attrs* - will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. - - See also `issue #428 - `_. - - force_kw_only (bool): - A back-compat flag for restoring pre-25.4.0 behavior. If True and - ``kw_only=True``, all attributes are made keyword-only, including - base class attributes, and those set to ``kw_only=False`` at the - attribute level. Defaults to False. - - See also `issue #980 - `_. - - getstate_setstate (bool | None): - .. note:: - - This is usually only interesting for slotted classes and you - should probably just set *auto_detect* to True. - - If True, ``__getstate__`` and ``__setstate__`` are generated and - attached to the class. This is necessary for slotted classes to be - pickleable. If left None, it's True by default for slotted classes - and False for dict classes. - - If *auto_detect* is True, and *getstate_setstate* is left None, and - **either** ``__getstate__`` or ``__setstate__`` is detected - directly on the class (meaning: not inherited), it is set to False - (this is usually what you want). - - auto_attribs (bool | None): - If True, look at type annotations to determine which attributes to - use, like `dataclasses`. If False, it will only look for explicit - :func:`field` class attributes, like classic *attrs*. - - If left None, it will guess: - - 1. If any attributes are annotated and no unannotated - `attrs.field`\ s are found, it assumes *auto_attribs=True*. - 2. Otherwise it assumes *auto_attribs=False* and tries to collect - `attrs.field`\ s. - - If *attrs* decides to look at type annotations, **all** fields - **must** be annotated. If *attrs* encounters a field that is set to - a :func:`field` / `attr.ib` but lacks a type annotation, an - `attrs.exceptions.UnannotatedAttributeError` is raised. Use - ``field_name: typing.Any = field(...)`` if you don't want to set a - type. - - .. warning:: - - For features that use the attribute name to create decorators - (for example, :ref:`validators `), you still *must* - assign :func:`field` / `attr.ib` to them. Otherwise Python will - either not find the name or try to use the default value to - call, for example, ``validator`` on it. - - Attributes annotated as `typing.ClassVar`, and attributes that are - neither annotated nor set to an `field()` are **ignored**. - - these (dict[str, object]): - A dictionary of name to the (private) return value of `field()` - mappings. This is useful to avoid the definition of your attributes - within the class body because you can't (for example, if you want - to add ``__repr__`` methods to Django models) or don't want to. - - If *these* is not `None`, *attrs* will *not* search the class body - for attributes and will *not* remove any attributes from it. - - The order is deduced from the order of the attributes inside - *these*. - - Arguably, this is a rather obscure feature. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. - .. versionadded:: 22.2.0 - *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). - .. versionchanged:: 24.1.0 - Instances are not compared as tuples of attributes anymore, but using a - big ``and`` condition. This is faster and has more correct behavior for - uncomparable values like `math.nan`. - .. versionadded:: 24.1.0 - If a class has an *inherited* classmethod called - ``__attrs_init_subclass__``, it is executed after the class is created. - .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. - .. versionadded:: 24.3.0 - Unless already present, a ``__replace__`` method is automatically - created for `copy.replace` (Python 3.13+ only). - .. versionchanged:: 25.4.0 - *kw_only* now only applies to attributes defined in the current class, - and respects attribute-level ``kw_only=False`` settings. - .. versionadded:: 25.4.0 - Added *force_kw_only* to go back to the previous *kw_only* behavior. - - .. note:: - - The main differences to the classic `attr.s` are: - - - Automatically detect whether or not *auto_attribs* should be `True` - (c.f. *auto_attribs* parameter). - - Converters and validators run when attributes are set by default -- - if *frozen* is `False`. - - *slots=True* - - Usually, this has only upsides and few visible effects in everyday - programming. But it *can* lead to some surprising behaviors, so - please make sure to read :term:`slotted classes`. - - - *auto_exc=True* - - *auto_detect=True* - - *order=False* - - *force_kw_only=False* - - Some options that were only relevant on Python 2 or were kept around - for backwards-compatibility have been removed. - - """ - - def do_it(cls, auto_attribs): - return attrs( - maybe_cls=cls, - these=these, - repr=repr, - hash=hash, - unsafe_hash=unsafe_hash, - init=init, - slots=slots, - frozen=frozen, - weakref_slot=weakref_slot, - str=str, - auto_attribs=auto_attribs, - kw_only=kw_only, - cache_hash=cache_hash, - auto_exc=auto_exc, - eq=eq, - order=order, - auto_detect=auto_detect, - collect_by_mro=True, - getstate_setstate=getstate_setstate, - on_setattr=on_setattr, - field_transformer=field_transformer, - match_args=match_args, - force_kw_only=force_kw_only, - ) - - def wrap(cls): - """ - Making this a wrapper ensures this code runs during class creation. - - We also ensure that frozen-ness of classes is inherited. - """ - nonlocal frozen, on_setattr - - had_on_setattr = on_setattr not in (None, setters.NO_OP) - - # By default, mutable classes convert & validate on setattr. - if frozen is False and on_setattr is None: - on_setattr = _DEFAULT_ON_SETATTR - - # However, if we subclass a frozen class, we inherit the immutability - # and disable on_setattr. - for base_cls in cls.__bases__: - if base_cls.__setattr__ is _frozen_setattrs: - if had_on_setattr: - msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." - raise ValueError(msg) - - on_setattr = setters.NO_OP - break - - if auto_attribs is not None: - return do_it(cls, auto_attribs) - - try: - return do_it(cls, True) - except UnannotatedAttributeError: - return do_it(cls, False) - - # maybe_cls's type depends on the usage of the decorator. It's a class - # if it's used as `@attrs` but `None` if used as `@attrs()`. - if maybe_cls is None: - return wrap - - return wrap(maybe_cls) - - -mutable = define -frozen = partial(define, frozen=True, on_setattr=None) - - -def field( - *, - default=NOTHING, - validator=None, - repr=True, - hash=None, - init=True, - metadata=None, - type=None, - converter=None, - factory=None, - kw_only=None, - eq=None, - order=None, - on_setattr=None, - alias=None, -): - """ - Create a new :term:`field` / :term:`attribute` on a class. - - .. warning:: - - Does **nothing** unless the class is also decorated with - `attrs.define` (or similar)! - - Args: - default: - A value that is used if an *attrs*-generated ``__init__`` is used - and no value is passed while instantiating or the attribute is - excluded using ``init=False``. - - If the value is an instance of `attrs.Factory`, its callable will - be used to construct a new value (useful for mutable data types - like lists or dicts). - - If a default is not set (or set manually to `attrs.NOTHING`), a - value *must* be supplied when instantiating; otherwise a - `TypeError` will be raised. - - .. seealso:: `defaults` - - factory (~typing.Callable): - Syntactic sugar for ``default=attr.Factory(factory)``. - - validator (~typing.Callable | list[~typing.Callable]): - Callable that is called by *attrs*-generated ``__init__`` methods - after the instance has been initialized. They receive the - initialized instance, the :func:`~attrs.Attribute`, and the passed - value. - - The return value is *not* inspected so the validator has to throw - an exception itself. - - If a `list` is passed, its items are treated as validators and must - all pass. - - Validators can be globally disabled and re-enabled using - `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. - - The validator can also be set using decorator notation as shown - below. - - .. seealso:: :ref:`validators` - - repr (bool | ~typing.Callable): - Include this attribute in the generated ``__repr__`` method. If - True, include the attribute; if False, omit it. By default, the - built-in ``repr()`` function is used. To override how the attribute - value is formatted, pass a ``callable`` that takes a single value - and returns a string. Note that the resulting string is used as-is, - which means it will be used directly *instead* of calling - ``repr()`` (the default). - - eq (bool | ~typing.Callable): - If True (default), include this attribute in the generated - ``__eq__`` and ``__ne__`` methods that check two instances for - equality. To override how the attribute value is compared, pass a - callable that takes a single value and returns the value to be - compared. - - .. seealso:: `comparison` - - order (bool | ~typing.Callable): - If True (default), include this attributes in the generated - ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To - override how the attribute value is ordered, pass a callable that - takes a single value and returns the value to be ordered. - - .. seealso:: `comparison` - - hash (bool | None): - Include this attribute in the generated ``__hash__`` method. If - None (default), mirror *eq*'s value. This is the correct behavior - according the Python spec. Setting this value to anything else - than None is *discouraged*. - - .. seealso:: `hashing` - - init (bool): - Include this attribute in the generated ``__init__`` method. - - It is possible to set this to False and set a default value. In - that case this attributed is unconditionally initialized with the - specified default value or factory. - - .. seealso:: `init` - - converter (typing.Callable | Converter): - A callable that is called by *attrs*-generated ``__init__`` methods - to convert attribute's value to the desired format. - - If a vanilla callable is passed, it is given the passed-in value as - the only positional argument. It is possible to receive additional - arguments by wrapping the callable in a `Converter`. - - Either way, the returned value will be used as the new value of the - attribute. The value is converted before being passed to the - validator, if any. - - .. seealso:: :ref:`converters` - - metadata (dict | None): - An arbitrary mapping, to be used by third-party code. - - .. seealso:: `extending-metadata`. - - type (type): - The type of the attribute. Nowadays, the preferred method to - specify the type is using a variable annotation (see :pep:`526`). - This argument is provided for backwards-compatibility and for usage - with `make_class`. Regardless of the approach used, the type will - be stored on ``Attribute.type``. - - Please note that *attrs* doesn't do anything with this metadata by - itself. You can use it as part of your own code or for `static type - checking `. - - kw_only (bool | None): - Make this attribute keyword-only in the generated ``__init__`` (if - *init* is False, this parameter is ignored). If None (default), - mirror the setting from `attrs.define`. - - on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): - Allows to overwrite the *on_setattr* setting from `attr.s`. If left - None, the *on_setattr* value from `attr.s` is used. Set to - `attrs.setters.NO_OP` to run **no** `setattr` hooks for this - attribute -- regardless of the setting in `define()`. - - alias (str | None): - Override this attribute's parameter name in the generated - ``__init__`` method. If left None, default to ``name`` stripped - of leading underscores. See `private-attributes`. - - .. versionadded:: 20.1.0 - .. versionchanged:: 21.1.0 - *eq*, *order*, and *cmp* also accept a custom callable - .. versionadded:: 22.2.0 *alias* - .. versionadded:: 23.1.0 - The *type* parameter has been re-added; mostly for `attrs.make_class`. - Please note that type checkers ignore this metadata. - .. versionchanged:: 25.4.0 - *kw_only* can now be None, and its default is also changed from False to - None. - - .. seealso:: - - `attr.ib` - """ - return attrib( - default=default, - validator=validator, - repr=repr, - hash=hash, - init=init, - metadata=metadata, - type=type, - converter=converter, - factory=factory, - kw_only=kw_only, - eq=eq, - order=order, - on_setattr=on_setattr, - alias=alias, - ) - - -def asdict(inst, *, recurse=True, filter=None, value_serializer=None): - """ - Same as `attr.asdict`, except that collections types are always retained - and dict is always used as *dict_factory*. - - .. versionadded:: 21.3.0 - """ - return _asdict( - inst=inst, - recurse=recurse, - filter=filter, - value_serializer=value_serializer, - retain_collection_types=True, - ) - - -def astuple(inst, *, recurse=True, filter=None): - """ - Same as `attr.astuple`, except that collections types are always retained - and `tuple` is always used as the *tuple_factory*. - - .. versionadded:: 21.3.0 - """ - return _astuple( - inst=inst, recurse=recurse, filter=filter, retain_collection_types=True - ) - - -def inspect(cls): - """ - Inspect the class and return its effective build parameters. - - Warning: - This feature is currently **experimental** and is not covered by our - strict backwards-compatibility guarantees. - - Args: - cls: The *attrs*-decorated class to inspect. - - Returns: - The effective build parameters of the class. - - Raises: - NotAnAttrsClassError: If the class is not an *attrs*-decorated class. - - .. versionadded:: 25.4.0 - """ - try: - return cls.__dict__["__attrs_props__"] - except KeyError: - msg = f"{cls!r} is not an attrs-decorated class." - raise NotAnAttrsClassError(msg) from None diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_typing_compat.pyi b/backend/venv39/lib/python3.9/site-packages/attr/_typing_compat.pyi deleted file mode 100644 index ca7b71e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_typing_compat.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, ClassVar, Protocol - -# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. -MYPY = False - -if MYPY: - # A protocol to be able to statically accept an attrs class. - class AttrsInstance_(Protocol): - __attrs_attrs__: ClassVar[Any] - -else: - # For type checkers without plug-in support use an empty protocol that - # will (hopefully) be combined into a union. - class AttrsInstance_(Protocol): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_version_info.py b/backend/venv39/lib/python3.9/site-packages/attr/_version_info.py deleted file mode 100644 index 27f1888..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_version_info.py +++ /dev/null @@ -1,89 +0,0 @@ -# SPDX-License-Identifier: MIT - - -from functools import total_ordering - -from ._funcs import astuple -from ._make import attrib, attrs - - -@total_ordering -@attrs(eq=False, order=False, slots=True, frozen=True) -class VersionInfo: - """ - A version object that can be compared to tuple of length 1--4: - - >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) - True - >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) - True - >>> vi = attr.VersionInfo(19, 2, 0, "final") - >>> vi < (19, 1, 1) - False - >>> vi < (19,) - False - >>> vi == (19, 2,) - True - >>> vi == (19, 2, 1) - False - - .. versionadded:: 19.2 - """ - - year = attrib(type=int) - minor = attrib(type=int) - micro = attrib(type=int) - releaselevel = attrib(type=str) - - @classmethod - def _from_version_string(cls, s): - """ - Parse *s* and return a _VersionInfo. - """ - v = s.split(".") - if len(v) == 3: - v.append("final") - - return cls( - year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] - ) - - def _ensure_tuple(self, other): - """ - Ensure *other* is a tuple of a valid length. - - Returns a possibly transformed *other* and ourselves as a tuple of - the same length as *other*. - """ - - if self.__class__ is other.__class__: - other = astuple(other) - - if not isinstance(other, tuple): - raise NotImplementedError - - if not (1 <= len(other) <= 4): - raise NotImplementedError - - return astuple(self)[: len(other)], other - - def __eq__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - return us == them - - def __lt__(self, other): - try: - us, them = self._ensure_tuple(other) - except NotImplementedError: - return NotImplemented - - # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't - # have to do anything special with releaselevel for now. - return us < them - - def __hash__(self): - return hash((self.year, self.minor, self.micro, self.releaselevel)) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/_version_info.pyi b/backend/venv39/lib/python3.9/site-packages/attr/_version_info.pyi deleted file mode 100644 index 45ced08..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/_version_info.pyi +++ /dev/null @@ -1,9 +0,0 @@ -class VersionInfo: - @property - def year(self) -> int: ... - @property - def minor(self) -> int: ... - @property - def micro(self) -> int: ... - @property - def releaselevel(self) -> str: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attr/converters.py b/backend/venv39/lib/python3.9/site-packages/attr/converters.py deleted file mode 100644 index 0a79dee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/converters.py +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful converters. -""" - -import typing - -from ._compat import _AnnotationExtractor -from ._make import NOTHING, Converter, Factory, pipe - - -__all__ = [ - "default_if_none", - "optional", - "pipe", - "to_bool", -] - - -def optional(converter): - """ - A converter that allows an attribute to be optional. An optional attribute - is one which can be set to `None`. - - Type annotations will be inferred from the wrapped converter's, if it has - any. - - Args: - converter (typing.Callable): - the converter that is used for non-`None` values. - - .. versionadded:: 17.1.0 - """ - - if isinstance(converter, Converter): - - def optional_converter(val, inst, field): - if val is None: - return None - return converter(val, inst, field) - - else: - - def optional_converter(val): - if val is None: - return None - return converter(val) - - xtr = _AnnotationExtractor(converter) - - t = xtr.get_first_param_type() - if t: - optional_converter.__annotations__["val"] = typing.Optional[t] - - rt = xtr.get_return_type() - if rt: - optional_converter.__annotations__["return"] = typing.Optional[rt] - - if isinstance(converter, Converter): - return Converter(optional_converter, takes_self=True, takes_field=True) - - return optional_converter - - -def default_if_none(default=NOTHING, factory=None): - """ - A converter that allows to replace `None` values by *default* or the result - of *factory*. - - Args: - default: - Value to be used if `None` is passed. Passing an instance of - `attrs.Factory` is supported, however the ``takes_self`` option is - *not*. - - factory (typing.Callable): - A callable that takes no parameters whose result is used if `None` - is passed. - - Raises: - TypeError: If **neither** *default* or *factory* is passed. - - TypeError: If **both** *default* and *factory* are passed. - - ValueError: - If an instance of `attrs.Factory` is passed with - ``takes_self=True``. - - .. versionadded:: 18.2.0 - """ - if default is NOTHING and factory is None: - msg = "Must pass either `default` or `factory`." - raise TypeError(msg) - - if default is not NOTHING and factory is not None: - msg = "Must pass either `default` or `factory` but not both." - raise TypeError(msg) - - if factory is not None: - default = Factory(factory) - - if isinstance(default, Factory): - if default.takes_self: - msg = "`takes_self` is not supported by default_if_none." - raise ValueError(msg) - - def default_if_none_converter(val): - if val is not None: - return val - - return default.factory() - - else: - - def default_if_none_converter(val): - if val is not None: - return val - - return default - - return default_if_none_converter - - -def to_bool(val): - """ - Convert "boolean" strings (for example, from environment variables) to real - booleans. - - Values mapping to `True`: - - - ``True`` - - ``"true"`` / ``"t"`` - - ``"yes"`` / ``"y"`` - - ``"on"`` - - ``"1"`` - - ``1`` - - Values mapping to `False`: - - - ``False`` - - ``"false"`` / ``"f"`` - - ``"no"`` / ``"n"`` - - ``"off"`` - - ``"0"`` - - ``0`` - - Raises: - ValueError: For any other value. - - .. versionadded:: 21.3.0 - """ - if isinstance(val, str): - val = val.lower() - - if val in (True, "true", "t", "yes", "y", "on", "1", 1): - return True - if val in (False, "false", "f", "no", "n", "off", "0", 0): - return False - - msg = f"Cannot convert value to bool: {val!r}" - raise ValueError(msg) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/converters.pyi b/backend/venv39/lib/python3.9/site-packages/attr/converters.pyi deleted file mode 100644 index 12bd0c4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/converters.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Callable, Any, overload - -from attrs import _ConverterType, _CallableConverterType - -@overload -def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... -@overload -def pipe(*validators: _ConverterType) -> _ConverterType: ... -@overload -def optional(converter: _CallableConverterType) -> _CallableConverterType: ... -@overload -def optional(converter: _ConverterType) -> _ConverterType: ... -@overload -def default_if_none(default: Any) -> _CallableConverterType: ... -@overload -def default_if_none( - *, factory: Callable[[], Any] -) -> _CallableConverterType: ... -def to_bool(val: str | int | bool) -> bool: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attr/exceptions.py b/backend/venv39/lib/python3.9/site-packages/attr/exceptions.py deleted file mode 100644 index 3b7abb8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/exceptions.py +++ /dev/null @@ -1,95 +0,0 @@ -# SPDX-License-Identifier: MIT - -from __future__ import annotations - -from typing import ClassVar - - -class FrozenError(AttributeError): - """ - A frozen/immutable instance or attribute have been attempted to be - modified. - - It mirrors the behavior of ``namedtuples`` by using the same error message - and subclassing `AttributeError`. - - .. versionadded:: 20.1.0 - """ - - msg = "can't set attribute" - args: ClassVar[tuple[str]] = [msg] - - -class FrozenInstanceError(FrozenError): - """ - A frozen instance has been attempted to be modified. - - .. versionadded:: 16.1.0 - """ - - -class FrozenAttributeError(FrozenError): - """ - A frozen attribute has been attempted to be modified. - - .. versionadded:: 20.1.0 - """ - - -class AttrsAttributeNotFoundError(ValueError): - """ - An *attrs* function couldn't find an attribute that the user asked for. - - .. versionadded:: 16.2.0 - """ - - -class NotAnAttrsClassError(ValueError): - """ - A non-*attrs* class has been passed into an *attrs* function. - - .. versionadded:: 16.2.0 - """ - - -class DefaultAlreadySetError(RuntimeError): - """ - A default has been set when defining the field and is attempted to be reset - using the decorator. - - .. versionadded:: 17.1.0 - """ - - -class UnannotatedAttributeError(RuntimeError): - """ - A class with ``auto_attribs=True`` has a field without a type annotation. - - .. versionadded:: 17.3.0 - """ - - -class PythonTooOldError(RuntimeError): - """ - It was attempted to use an *attrs* feature that requires a newer Python - version. - - .. versionadded:: 18.2.0 - """ - - -class NotCallableError(TypeError): - """ - A field requiring a callable has been set with a value that is not - callable. - - .. versionadded:: 19.2.0 - """ - - def __init__(self, msg, value): - super(TypeError, self).__init__(msg, value) - self.msg = msg - self.value = value - - def __str__(self): - return str(self.msg) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/exceptions.pyi b/backend/venv39/lib/python3.9/site-packages/attr/exceptions.pyi deleted file mode 100644 index f268011..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any - -class FrozenError(AttributeError): - msg: str = ... - -class FrozenInstanceError(FrozenError): ... -class FrozenAttributeError(FrozenError): ... -class AttrsAttributeNotFoundError(ValueError): ... -class NotAnAttrsClassError(ValueError): ... -class DefaultAlreadySetError(RuntimeError): ... -class UnannotatedAttributeError(RuntimeError): ... -class PythonTooOldError(RuntimeError): ... - -class NotCallableError(TypeError): - msg: str = ... - value: Any = ... - def __init__(self, msg: str, value: Any) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attr/filters.py b/backend/venv39/lib/python3.9/site-packages/attr/filters.py deleted file mode 100644 index 689b170..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/filters.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful filters for `attrs.asdict` and `attrs.astuple`. -""" - -from ._make import Attribute - - -def _split_what(what): - """ - Returns a tuple of `frozenset`s of classes and attributes. - """ - return ( - frozenset(cls for cls in what if isinstance(cls, type)), - frozenset(cls for cls in what if isinstance(cls, str)), - frozenset(cls for cls in what if isinstance(cls, Attribute)), - ) - - -def include(*what): - """ - Create a filter that only allows *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to include. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.1.0 Accept strings with field names. - """ - cls, names, attrs = _split_what(what) - - def include_(attribute, value): - return ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return include_ - - -def exclude(*what): - """ - Create a filter that does **not** allow *what*. - - Args: - what (list[type, str, attrs.Attribute]): - What to exclude. Can be a type, a name, or an attribute. - - Returns: - Callable: - A callable that can be passed to `attrs.asdict`'s and - `attrs.astuple`'s *filter* argument. - - .. versionchanged:: 23.3.0 Accept field name string as input argument - """ - cls, names, attrs = _split_what(what) - - def exclude_(attribute, value): - return not ( - value.__class__ in cls - or attribute.name in names - or attribute in attrs - ) - - return exclude_ diff --git a/backend/venv39/lib/python3.9/site-packages/attr/filters.pyi b/backend/venv39/lib/python3.9/site-packages/attr/filters.pyi deleted file mode 100644 index 974abdc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/filters.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Any - -from . import Attribute, _FilterType - -def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... -def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attr/py.typed b/backend/venv39/lib/python3.9/site-packages/attr/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/attr/setters.py b/backend/venv39/lib/python3.9/site-packages/attr/setters.py deleted file mode 100644 index 78b0839..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/setters.py +++ /dev/null @@ -1,79 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly used hooks for on_setattr. -""" - -from . import _config -from .exceptions import FrozenAttributeError - - -def pipe(*setters): - """ - Run all *setters* and return the return value of the last one. - - .. versionadded:: 20.1.0 - """ - - def wrapped_pipe(instance, attrib, new_value): - rv = new_value - - for setter in setters: - rv = setter(instance, attrib, rv) - - return rv - - return wrapped_pipe - - -def frozen(_, __, ___): - """ - Prevent an attribute to be modified. - - .. versionadded:: 20.1.0 - """ - raise FrozenAttributeError - - -def validate(instance, attrib, new_value): - """ - Run *attrib*'s validator on *new_value* if it has one. - - .. versionadded:: 20.1.0 - """ - if _config._run_validators is False: - return new_value - - v = attrib.validator - if not v: - return new_value - - v(instance, attrib, new_value) - - return new_value - - -def convert(instance, attrib, new_value): - """ - Run *attrib*'s converter -- if it has one -- on *new_value* and return the - result. - - .. versionadded:: 20.1.0 - """ - c = attrib.converter - if c: - # This can be removed once we drop 3.8 and use attrs.Converter instead. - from ._make import Converter - - if not isinstance(c, Converter): - return c(new_value) - - return c(new_value, instance, attrib) - - return new_value - - -# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. -# Sphinx's autodata stopped working, so the docstring is inlined in the API -# docs. -NO_OP = object() diff --git a/backend/venv39/lib/python3.9/site-packages/attr/setters.pyi b/backend/venv39/lib/python3.9/site-packages/attr/setters.pyi deleted file mode 100644 index 73abf36..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/setters.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any, NewType, NoReturn, TypeVar - -from . import Attribute -from attrs import _OnSetAttrType - -_T = TypeVar("_T") - -def frozen( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> NoReturn: ... -def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... -def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... - -# convert is allowed to return Any, because they can be chained using pipe. -def convert( - instance: Any, attribute: Attribute[Any], new_value: Any -) -> Any: ... - -_NoOpType = NewType("_NoOpType", object) -NO_OP: _NoOpType diff --git a/backend/venv39/lib/python3.9/site-packages/attr/validators.py b/backend/venv39/lib/python3.9/site-packages/attr/validators.py deleted file mode 100644 index 837e003..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/validators.py +++ /dev/null @@ -1,748 +0,0 @@ -# SPDX-License-Identifier: MIT - -""" -Commonly useful validators. -""" - -import operator -import re - -from contextlib import contextmanager -from re import Pattern - -from ._config import get_run_validators, set_run_validators -from ._make import _AndValidator, and_, attrib, attrs -from .converters import default_if_none -from .exceptions import NotCallableError - - -__all__ = [ - "and_", - "deep_iterable", - "deep_mapping", - "disabled", - "ge", - "get_disabled", - "gt", - "in_", - "instance_of", - "is_callable", - "le", - "lt", - "matches_re", - "max_len", - "min_len", - "not_", - "optional", - "or_", - "set_disabled", -] - - -def set_disabled(disabled): - """ - Globally disable or enable running validators. - - By default, they are run. - - Args: - disabled (bool): If `True`, disable running all validators. - - .. warning:: - - This function is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(not disabled) - - -def get_disabled(): - """ - Return a bool indicating whether validators are currently disabled or not. - - Returns: - bool:`True` if validators are currently disabled. - - .. versionadded:: 21.3.0 - """ - return not get_run_validators() - - -@contextmanager -def disabled(): - """ - Context manager that disables running validators within its context. - - .. warning:: - - This context manager is not thread-safe! - - .. versionadded:: 21.3.0 - """ - set_run_validators(False) - try: - yield - finally: - set_run_validators(True) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InstanceOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not isinstance(value, self.type): - msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def instance_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `isinstance` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type]): The type to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _InstanceOfValidator(type) - - -@attrs(repr=False, frozen=True, slots=True) -class _MatchesReValidator: - pattern = attrib() - match_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.match_func(value): - msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" - raise ValueError( - msg, - attr, - self.pattern, - value, - ) - - def __repr__(self): - return f"" - - -def matches_re(regex, flags=0, func=None): - r""" - A validator that raises `ValueError` if the initializer is called with a - string that doesn't match *regex*. - - Args: - regex (str, re.Pattern): - A regex string or precompiled pattern to match against - - flags (int): - Flags that will be passed to the underlying re function (default 0) - - func (typing.Callable): - Which underlying `re` function to call. Valid options are - `re.fullmatch`, `re.search`, and `re.match`; the default `None` - means `re.fullmatch`. For performance reasons, the pattern is - always precompiled using `re.compile`. - - .. versionadded:: 19.2.0 - .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. - """ - valid_funcs = (re.fullmatch, None, re.search, re.match) - if func not in valid_funcs: - msg = "'func' must be one of {}.".format( - ", ".join( - sorted((e and e.__name__) or "None" for e in set(valid_funcs)) - ) - ) - raise ValueError(msg) - - if isinstance(regex, Pattern): - if flags: - msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" - raise TypeError(msg) - pattern = regex - else: - pattern = re.compile(regex, flags) - - if func is re.match: - match_func = pattern.match - elif func is re.search: - match_func = pattern.search - else: - match_func = pattern.fullmatch - - return _MatchesReValidator(pattern, match_func) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OptionalValidator: - validator = attrib() - - def __call__(self, inst, attr, value): - if value is None: - return - - self.validator(inst, attr, value) - - def __repr__(self): - return f"" - - -def optional(validator): - """ - A validator that makes an attribute optional. An optional attribute is one - which can be set to `None` in addition to satisfying the requirements of - the sub-validator. - - Args: - validator - (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): - A validator (or validators) that is used for non-`None` values. - - .. versionadded:: 15.1.0 - .. versionchanged:: 17.1.0 *validator* can be a list of validators. - .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. - """ - if isinstance(validator, (list, tuple)): - return _OptionalValidator(_AndValidator(validator)) - - return _OptionalValidator(validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _InValidator: - options = attrib() - _original_options = attrib(hash=False) - - def __call__(self, inst, attr, value): - try: - in_options = value in self.options - except TypeError: # e.g. `1 in "abc"` - in_options = False - - if not in_options: - msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" - raise ValueError( - msg, - attr, - self._original_options, - value, - ) - - def __repr__(self): - return f"" - - -def in_(options): - """ - A validator that raises a `ValueError` if the initializer is called with a - value that does not belong in the *options* provided. - - The check is performed using ``value in options``, so *options* has to - support that operation. - - To keep the validator hashable, dicts, lists, and sets are transparently - transformed into a `tuple`. - - Args: - options: Allowed options. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected options, and the value it got. - - .. versionadded:: 17.1.0 - .. versionchanged:: 22.1.0 - The ValueError was incomplete until now and only contained the human - readable error message. Now it contains all the information that has - been promised since 17.1.0. - .. versionchanged:: 24.1.0 - *options* that are a list, dict, or a set are now transformed into a - tuple to keep the validator hashable. - """ - repr_options = options - if isinstance(options, (list, dict, set)): - options = tuple(options) - - return _InValidator(options, repr_options) - - -@attrs(repr=False, slots=False, unsafe_hash=True) -class _IsCallableValidator: - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not callable(value): - message = ( - "'{name}' must be callable " - "(got {value!r} that is a {actual!r})." - ) - raise NotCallableError( - msg=message.format( - name=attr.name, value=value, actual=value.__class__ - ), - value=value, - ) - - def __repr__(self): - return "" - - -def is_callable(): - """ - A validator that raises a `attrs.exceptions.NotCallableError` if the - initializer is called with a value for this particular attribute that is - not callable. - - .. versionadded:: 19.1.0 - - Raises: - attrs.exceptions.NotCallableError: - With a human readable error message containing the attribute - (`attrs.Attribute`) name, and the value it got. - """ - return _IsCallableValidator() - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepIterable: - member_validator = attrib(validator=is_callable()) - iterable_validator = attrib( - default=None, validator=optional(is_callable()) - ) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.iterable_validator is not None: - self.iterable_validator(inst, attr, value) - - for member in value: - self.member_validator(inst, attr, member) - - def __repr__(self): - iterable_identifier = ( - "" - if self.iterable_validator is None - else f" {self.iterable_validator!r}" - ) - return ( - f"" - ) - - -def deep_iterable(member_validator, iterable_validator=None): - """ - A validator that performs deep validation of an iterable. - - Args: - member_validator: Validator(s) to apply to iterable members. - - iterable_validator: - Validator(s) to apply to iterable itself (optional). - - Raises - TypeError: if any sub-validators fail - - .. versionadded:: 19.1.0 - - .. versionchanged:: 25.4.0 - *member_validator* and *iterable_validator* can now be a list or tuple - of validators. - """ - if isinstance(member_validator, (list, tuple)): - member_validator = and_(*member_validator) - if isinstance(iterable_validator, (list, tuple)): - iterable_validator = and_(*iterable_validator) - return _DeepIterable(member_validator, iterable_validator) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _DeepMapping: - key_validator = attrib(validator=optional(is_callable())) - value_validator = attrib(validator=optional(is_callable())) - mapping_validator = attrib(validator=optional(is_callable())) - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if self.mapping_validator is not None: - self.mapping_validator(inst, attr, value) - - for key in value: - if self.key_validator is not None: - self.key_validator(inst, attr, key) - if self.value_validator is not None: - self.value_validator(inst, attr, value[key]) - - def __repr__(self): - return f"" - - -def deep_mapping( - key_validator=None, value_validator=None, mapping_validator=None -): - """ - A validator that performs deep validation of a dictionary. - - All validators are optional, but at least one of *key_validator* or - *value_validator* must be provided. - - Args: - key_validator: Validator(s) to apply to dictionary keys. - - value_validator: Validator(s) to apply to dictionary values. - - mapping_validator: - Validator(s) to apply to top-level mapping attribute. - - .. versionadded:: 19.1.0 - - .. versionchanged:: 25.4.0 - *key_validator* and *value_validator* are now optional, but at least one - of them must be provided. - - .. versionchanged:: 25.4.0 - *key_validator*, *value_validator*, and *mapping_validator* can now be a - list or tuple of validators. - - Raises: - TypeError: If any sub-validator fails on validation. - - ValueError: - If neither *key_validator* nor *value_validator* is provided on - instantiation. - """ - if key_validator is None and value_validator is None: - msg = ( - "At least one of key_validator or value_validator must be provided" - ) - raise ValueError(msg) - - if isinstance(key_validator, (list, tuple)): - key_validator = and_(*key_validator) - if isinstance(value_validator, (list, tuple)): - value_validator = and_(*value_validator) - if isinstance(mapping_validator, (list, tuple)): - mapping_validator = and_(*mapping_validator) - - return _DeepMapping(key_validator, value_validator, mapping_validator) - - -@attrs(repr=False, frozen=True, slots=True) -class _NumberValidator: - bound = attrib() - compare_op = attrib() - compare_func = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not self.compare_func(value, self.bound): - msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def lt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number larger or equal to *val*. - - The validator uses `operator.lt` to compare the values. - - Args: - val: Exclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<", operator.lt) - - -def le(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number greater than *val*. - - The validator uses `operator.le` to compare the values. - - Args: - val: Inclusive upper bound for values. - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, "<=", operator.le) - - -def ge(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller than *val*. - - The validator uses `operator.ge` to compare the values. - - Args: - val: Inclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">=", operator.ge) - - -def gt(val): - """ - A validator that raises `ValueError` if the initializer is called with a - number smaller or equal to *val*. - - The validator uses `operator.gt` to compare the values. - - Args: - val: Exclusive lower bound for values - - .. versionadded:: 21.3.0 - """ - return _NumberValidator(val, ">", operator.gt) - - -@attrs(repr=False, frozen=True, slots=True) -class _MaxLengthValidator: - max_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) > self.max_length: - msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def max_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is longer than *length*. - - Args: - length (int): Maximum length of the string or iterable - - .. versionadded:: 21.3.0 - """ - return _MaxLengthValidator(length) - - -@attrs(repr=False, frozen=True, slots=True) -class _MinLengthValidator: - min_length = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if len(value) < self.min_length: - msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def min_len(length): - """ - A validator that raises `ValueError` if the initializer is called - with a string or iterable that is shorter than *length*. - - Args: - length (int): Minimum length of the string or iterable - - .. versionadded:: 22.1.0 - """ - return _MinLengthValidator(length) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _SubclassOfValidator: - type = attrib() - - def __call__(self, inst, attr, value): - """ - We use a callable class to be able to change the ``__repr__``. - """ - if not issubclass(value, self.type): - msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." - raise TypeError( - msg, - attr, - self.type, - value, - ) - - def __repr__(self): - return f"" - - -def _subclass_of(type): - """ - A validator that raises a `TypeError` if the initializer is called with a - wrong type for this particular attribute (checks are performed using - `issubclass` therefore it's also valid to pass a tuple of types). - - Args: - type (type | tuple[type, ...]): The type(s) to check for. - - Raises: - TypeError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the expected type, and the value it got. - """ - return _SubclassOfValidator(type) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _NotValidator: - validator = attrib() - msg = attrib( - converter=default_if_none( - "not_ validator child '{validator!r}' " - "did not raise a captured error" - ) - ) - exc_types = attrib( - validator=deep_iterable( - member_validator=_subclass_of(Exception), - iterable_validator=instance_of(tuple), - ), - ) - - def __call__(self, inst, attr, value): - try: - self.validator(inst, attr, value) - except self.exc_types: - pass # suppress error to invert validity - else: - raise ValueError( - self.msg.format( - validator=self.validator, - exc_types=self.exc_types, - ), - attr, - self.validator, - value, - self.exc_types, - ) - - def __repr__(self): - return f"" - - -def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): - """ - A validator that wraps and logically 'inverts' the validator passed to it. - It will raise a `ValueError` if the provided validator *doesn't* raise a - `ValueError` or `TypeError` (by default), and will suppress the exception - if the provided validator *does*. - - Intended to be used with existing validators to compose logic without - needing to create inverted variants, for example, ``not_(in_(...))``. - - Args: - validator: A validator to be logically inverted. - - msg (str): - Message to raise if validator fails. Formatted with keys - ``exc_types`` and ``validator``. - - exc_types (tuple[type, ...]): - Exception type(s) to capture. Other types raised by child - validators will not be intercepted and pass through. - - Raises: - ValueError: - With a human readable error message, the attribute (of type - `attrs.Attribute`), the validator that failed to raise an - exception, the value it got, and the expected exception types. - - .. versionadded:: 22.2.0 - """ - try: - exc_types = tuple(exc_types) - except TypeError: - exc_types = (exc_types,) - return _NotValidator(validator, msg, exc_types) - - -@attrs(repr=False, slots=True, unsafe_hash=True) -class _OrValidator: - validators = attrib() - - def __call__(self, inst, attr, value): - for v in self.validators: - try: - v(inst, attr, value) - except Exception: # noqa: BLE001, PERF203, S112 - continue - else: - return - - msg = f"None of {self.validators!r} satisfied for value {value!r}" - raise ValueError(msg) - - def __repr__(self): - return f"" - - -def or_(*validators): - """ - A validator that composes multiple validators into one. - - When called on a value, it runs all wrapped validators until one of them is - satisfied. - - Args: - validators (~collections.abc.Iterable[typing.Callable]): - Arbitrary number of validators. - - Raises: - ValueError: - If no validator is satisfied. Raised with a human-readable error - message listing all the wrapped validators and the value that - failed all of them. - - .. versionadded:: 24.1.0 - """ - vals = [] - for v in validators: - vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) - - return _OrValidator(tuple(vals)) diff --git a/backend/venv39/lib/python3.9/site-packages/attr/validators.pyi b/backend/venv39/lib/python3.9/site-packages/attr/validators.pyi deleted file mode 100644 index 36a7e80..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attr/validators.pyi +++ /dev/null @@ -1,140 +0,0 @@ -from types import UnionType -from typing import ( - Any, - AnyStr, - Callable, - Container, - ContextManager, - Iterable, - Mapping, - Match, - Pattern, - TypeVar, - overload, -) - -from attrs import _ValidatorType -from attrs import _ValidatorArgType - -_T = TypeVar("_T") -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -_T3 = TypeVar("_T3") -_T4 = TypeVar("_T4") -_T5 = TypeVar("_T5") -_T6 = TypeVar("_T6") -_I = TypeVar("_I", bound=Iterable) -_K = TypeVar("_K") -_V = TypeVar("_V") -_M = TypeVar("_M", bound=Mapping) - -def set_disabled(run: bool) -> None: ... -def get_disabled() -> bool: ... -def disabled() -> ContextManager[None]: ... - -# To be more precise on instance_of use some overloads. -# If there are more than 3 items in the tuple then we fall back to Any -@overload -def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... -@overload -def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2]], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def instance_of( - type: tuple[type[_T1], type[_T2], type[_T3]], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... -@overload -def instance_of(type: UnionType) -> _ValidatorType[Any]: ... -def optional( - validator: ( - _ValidatorType[_T] - | list[_ValidatorType[_T]] - | tuple[_ValidatorType[_T]] - ), -) -> _ValidatorType[_T | None]: ... -def in_(options: Container[_T]) -> _ValidatorType[_T]: ... -def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... -def matches_re( - regex: Pattern[AnyStr] | AnyStr, - flags: int = ..., - func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., -) -> _ValidatorType[AnyStr]: ... -def deep_iterable( - member_validator: _ValidatorArgType[_T], - iterable_validator: _ValidatorArgType[_I] | None = ..., -) -> _ValidatorType[_I]: ... -@overload -def deep_mapping( - key_validator: _ValidatorArgType[_K], - value_validator: _ValidatorArgType[_V] | None = ..., - mapping_validator: _ValidatorArgType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -@overload -def deep_mapping( - key_validator: _ValidatorArgType[_K] | None = ..., - value_validator: _ValidatorArgType[_V] = ..., - mapping_validator: _ValidatorArgType[_M] | None = ..., -) -> _ValidatorType[_M]: ... -def is_callable() -> _ValidatorType[_T]: ... -def lt(val: _T) -> _ValidatorType[_T]: ... -def le(val: _T) -> _ValidatorType[_T]: ... -def ge(val: _T) -> _ValidatorType[_T]: ... -def gt(val: _T) -> _ValidatorType[_T]: ... -def max_len(length: int) -> _ValidatorType[_T]: ... -def min_len(length: int) -> _ValidatorType[_T]: ... -def not_( - validator: _ValidatorType[_T], - *, - msg: str | None = None, - exc_types: type[Exception] | Iterable[type[Exception]] = ..., -) -> _ValidatorType[_T]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], -) -> _ValidatorType[_T1 | _T2]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], -) -> _ValidatorType[_T1 | _T2 | _T3]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], - __v5: _ValidatorType[_T5], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5]: ... -@overload -def or_( - __v1: _ValidatorType[_T1], - __v2: _ValidatorType[_T2], - __v3: _ValidatorType[_T3], - __v4: _ValidatorType[_T4], - __v5: _ValidatorType[_T5], - __v6: _ValidatorType[_T6], -) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5 | _T6]: ... -@overload -def or_( - __v1: _ValidatorType[Any], - __v2: _ValidatorType[Any], - __v3: _ValidatorType[Any], - __v4: _ValidatorType[Any], - __v5: _ValidatorType[Any], - __v6: _ValidatorType[Any], - *validators: _ValidatorType[Any], -) -> _ValidatorType[Any]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/METADATA deleted file mode 100644 index 51128bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/METADATA +++ /dev/null @@ -1,235 +0,0 @@ -Metadata-Version: 2.4 -Name: attrs -Version: 25.4.0 -Summary: Classes Without Boilerplate -Project-URL: Documentation, https://www.attrs.org/ -Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html -Project-URL: GitHub, https://github.com/python-attrs/attrs -Project-URL: Funding, https://github.com/sponsors/hynek -Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi -Author-email: Hynek Schlawack -License-Expression: MIT -License-File: LICENSE -Keywords: attribute,boilerplate,class -Classifier: Development Status :: 5 - Production/Stable -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Typing :: Typed -Requires-Python: >=3.9 -Description-Content-Type: text/markdown - -

    - - attrs - -

    - - -*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). -Trusted by NASA for [Mars missions since 2020](https://github.com/readme/featured/nasa-ingenuity-helicopter)! - -Its main goal is to help you to write **concise** and **correct** software without slowing down your code. - - -## Sponsors - -*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). -Especially those generously supporting us at the *The Organization* tier and higher: - - - -

    - - - - - - - - - -

    - - - -

    - Please consider joining them to help make attrs’s maintenance more sustainable! -

    - - - -## Example - -*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: - - - -```pycon ->>> from attrs import asdict, define, make_class, Factory - ->>> @define -... class SomeClass: -... a_number: int = 42 -... list_of_numbers: list[int] = Factory(list) -... -... def hard_math(self, another_number): -... return self.a_number + sum(self.list_of_numbers) * another_number - - ->>> sc = SomeClass(1, [1, 2, 3]) ->>> sc -SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) - ->>> sc.hard_math(3) -19 ->>> sc == SomeClass(1, [1, 2, 3]) -True ->>> sc != SomeClass(2, [3, 2, 1]) -True - ->>> asdict(sc) -{'a_number': 1, 'list_of_numbers': [1, 2, 3]} - ->>> SomeClass() -SomeClass(a_number=42, list_of_numbers=[]) - ->>> C = make_class("C", ["a", "b"]) ->>> C("foo", "bar") -C(a='foo', b='bar') -``` - -After *declaring* your attributes, *attrs* gives you: - -- a concise and explicit overview of the class's attributes, -- a nice human-readable `__repr__`, -- equality-checking methods, -- an initializer, -- and much more, - -*without* writing dull boilerplate code again and again and *without* runtime performance penalties. - ---- - -This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. -The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. - -Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! - - -### Hate Type Annotations!? - -No problem! -Types are entirely **optional** with *attrs*. -Simply assign `attrs.field()` to the attributes instead of annotating them with types: - -```python -from attrs import define, field - -@define -class SomeClass: - a_number = field(default=42) - list_of_numbers = field(factory=list) -``` - - -## Data Classes - -On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). -In practice it does a lot more and is more flexible. -For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. - -For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. - - -## Project Information - -- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) -- [**Documentation**](https://www.attrs.org/) -- [**PyPI**](https://pypi.org/project/attrs/) -- [**Source Code**](https://github.com/python-attrs/attrs) -- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) -- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) -- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) - - -### *attrs* for Enterprise - -Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). - -The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. -Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. - -## Release Information - -### Backwards-incompatible Changes - -- Class-level `kw_only=True` behavior is now consistent with `dataclasses`. - - Previously, a class that sets `kw_only=True` makes all attributes keyword-only, including those from base classes. - If an attribute sets `kw_only=False`, that setting is ignored, and it is still made keyword-only. - - Now, only the attributes defined in that class that doesn't explicitly set `kw_only=False` are made keyword-only. - - This shouldn't be a problem for most users, unless you have a pattern like this: - - ```python - @attrs.define(kw_only=True) - class Base: - a: int - b: int = attrs.field(default=1, kw_only=False) - - @attrs.define - class Subclass(Base): - c: int - ``` - - Here, we have a `kw_only=True` *attrs* class (`Base`) with an attribute that sets `kw_only=False` and has a default (`Base.b`), and then create a subclass (`Subclass`) with required arguments (`Subclass.c`). - Previously this would work, since it would make `Base.b` keyword-only, but now this fails since `Base.b` is positional, and we have a required positional argument (`Subclass.c`) following another argument with defaults. - [#1457](https://github.com/python-attrs/attrs/issues/1457) - - -### Changes - -- Values passed to the `__init__()` method of `attrs` classes are now correctly passed to `__attrs_pre_init__()` instead of their default values (in cases where *kw_only* was not specified). - [#1427](https://github.com/python-attrs/attrs/issues/1427) -- Added support for Python 3.14 and [PEP 749](https://peps.python.org/pep-0749/). - [#1446](https://github.com/python-attrs/attrs/issues/1446), - [#1451](https://github.com/python-attrs/attrs/issues/1451) -- `attrs.validators.deep_mapping()` now allows to leave out either *key_validator* xor *value_validator*. - [#1448](https://github.com/python-attrs/attrs/issues/1448) -- `attrs.validators.deep_iterator()` and `attrs.validators.deep_mapping()` now accept lists and tuples for all validators and wrap them into a `attrs.validators.and_()`. - [#1449](https://github.com/python-attrs/attrs/issues/1449) -- Added a new **experimental** way to inspect classes: - - `attrs.inspect(cls)` returns the _effective_ class-wide parameters that were used by *attrs* to construct the class. - - The returned class is the same data structure that *attrs* uses internally to decide how to construct the final class. - [#1454](https://github.com/python-attrs/attrs/issues/1454) -- Fixed annotations for `attrs.field(converter=...)`. - Previously, a `tuple` of converters was only accepted if it had exactly one element. - [#1461](https://github.com/python-attrs/attrs/issues/1461) -- The performance of `attrs.asdict()` has been improved by 45–260%. - [#1463](https://github.com/python-attrs/attrs/issues/1463) -- The performance of `attrs.astuple()` has been improved by 49–270%. - [#1469](https://github.com/python-attrs/attrs/issues/1469) -- The type annotation for `attrs.validators.or_()` now allows for different types of validators. - - This was only an issue on Pyright. - [#1474](https://github.com/python-attrs/attrs/issues/1474) - - - ---- - -[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/RECORD deleted file mode 100644 index e0f8e64..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/RECORD +++ /dev/null @@ -1,55 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_cmp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_funcs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_make.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_next_gen.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/_version_info.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/converters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/filters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/setters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attr/validators.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/converters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/filters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/setters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/attrs/validators.cpython-39.pyc,, -attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 -attr/__init__.pyi,sha256=IZkzIjvtbRqDWGkDBIF9dd12FgDa379JYq3GHnVOvFQ,11309 -attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 -attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 -attr/_compat.py,sha256=x0g7iEUOnBVJC72zyFCgb1eKqyxS-7f2LGnNyZ_r95s,2829 -attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 -attr/_funcs.py,sha256=Ix5IETTfz5F01F-12MF_CSFomIn2h8b67EVVz2gCtBE,16479 -attr/_make.py,sha256=NRJDGS8syg2h3YNflVNoK2FwR3CpdSZxx8M6lacwljA,104141 -attr/_next_gen.py,sha256=BQtCUlzwg2gWHTYXBQvrEYBnzBUrDvO57u0Py6UCPhc,26274 -attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 -attr/_version_info.py,sha256=w4R-FYC3NK_kMkGUWJlYP4cVAlH9HRaC-um3fcjYkHM,2222 -attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 -attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 -attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 -attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977 -attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 -attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 -attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 -attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 -attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 -attr/validators.py,sha256=1BnYGTuYvSucGEI4ju-RPNJteVzG0ZlfWpJiWoSFHQ8,21458 -attr/validators.pyi,sha256=ftmW3m4KJ3pQcIXAj-BejT7BY4ZfqrC1G-5W7XvoPds,4082 -attrs-25.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -attrs-25.4.0.dist-info/METADATA,sha256=2Rerxj7agcMRxiwdkt6lC2guqHAmkGKCH13nWWK7ZoQ,10473 -attrs-25.4.0.dist-info/RECORD,, -attrs-25.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -attrs-25.4.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 -attrs/__init__.py,sha256=RxaAZNwYiEh-fcvHLZNpQ_DWKni73M_jxEPEftiq1Zc,1183 -attrs/__init__.pyi,sha256=2gV79g9UxJppGSM48hAZJ6h_MHb70dZoJL31ZNJeZYI,9416 -attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 -attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 -attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 -attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 -attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/licenses/LICENSE deleted file mode 100644 index 2bd6453..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs-25.4.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Hynek Schlawack and the attrs contributors - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/__init__.py b/backend/venv39/lib/python3.9/site-packages/attrs/__init__.py deleted file mode 100644 index dc1ce4b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/__init__.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr import ( - NOTHING, - Attribute, - AttrsInstance, - Converter, - Factory, - NothingType, - _make_getattr, - assoc, - cmp_using, - define, - evolve, - field, - fields, - fields_dict, - frozen, - has, - make_class, - mutable, - resolve_types, - validate, -) -from attr._make import ClassProps -from attr._next_gen import asdict, astuple, inspect - -from . import converters, exceptions, filters, setters, validators - - -__all__ = [ - "NOTHING", - "Attribute", - "AttrsInstance", - "ClassProps", - "Converter", - "Factory", - "NothingType", - "__author__", - "__copyright__", - "__description__", - "__doc__", - "__email__", - "__license__", - "__title__", - "__url__", - "__version__", - "__version_info__", - "asdict", - "assoc", - "astuple", - "cmp_using", - "converters", - "define", - "evolve", - "exceptions", - "field", - "fields", - "fields_dict", - "filters", - "frozen", - "has", - "inspect", - "make_class", - "mutable", - "resolve_types", - "setters", - "validate", - "validators", -] - -__getattr__ = _make_getattr(__name__) diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/attrs/__init__.pyi deleted file mode 100644 index 6364bac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/__init__.pyi +++ /dev/null @@ -1,314 +0,0 @@ -import sys - -from typing import ( - Any, - Callable, - Mapping, - Sequence, - overload, - TypeVar, -) - -# Because we need to type our own stuff, we have to make everything from -# attr explicitly public too. -from attr import __author__ as __author__ -from attr import __copyright__ as __copyright__ -from attr import __description__ as __description__ -from attr import __email__ as __email__ -from attr import __license__ as __license__ -from attr import __title__ as __title__ -from attr import __url__ as __url__ -from attr import __version__ as __version__ -from attr import __version_info__ as __version_info__ -from attr import assoc as assoc -from attr import Attribute as Attribute -from attr import AttrsInstance as AttrsInstance -from attr import cmp_using as cmp_using -from attr import converters as converters -from attr import Converter as Converter -from attr import evolve as evolve -from attr import exceptions as exceptions -from attr import Factory as Factory -from attr import fields as fields -from attr import fields_dict as fields_dict -from attr import filters as filters -from attr import has as has -from attr import make_class as make_class -from attr import NOTHING as NOTHING -from attr import resolve_types as resolve_types -from attr import setters as setters -from attr import validate as validate -from attr import validators as validators -from attr import attrib, asdict as asdict, astuple as astuple -from attr import NothingType as NothingType - -if sys.version_info >= (3, 11): - from typing import dataclass_transform -else: - from typing_extensions import dataclass_transform - -_T = TypeVar("_T") -_C = TypeVar("_C", bound=type) - -_EqOrderType = bool | Callable[[Any], Any] -_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] -_CallableConverterType = Callable[[Any], Any] -_ConverterType = _CallableConverterType | Converter[Any, Any] -_ReprType = Callable[[Any], str] -_ReprArgType = bool | _ReprType -_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] -_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType -_FieldTransformer = Callable[ - [type, list["Attribute[Any]"]], list["Attribute[Any]"] -] -# FIXME: in reality, if multiple validators are passed they must be in a list -# or tuple, but those are invariant and so would prevent subtypes of -# _ValidatorType from working when passed in a list or tuple. -_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] - -@overload -def field( - *, - default: None = ..., - validator: None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: None = ..., - factory: None = ..., - kw_only: bool | None = ..., - eq: bool | None = ..., - order: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... - -# This form catches an explicit None or no default and infers the type from the -# other arguments. -@overload -def field( - *, - default: None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form catches an explicit default argument. -@overload -def field( - *, - default: _T, - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> _T: ... - -# This form covers type=non-Type: e.g. forward references (str), Any -@overload -def field( - *, - default: _T | None = ..., - validator: _ValidatorArgType[_T] | None = ..., - repr: _ReprArgType = ..., - hash: bool | None = ..., - init: bool = ..., - metadata: Mapping[Any, Any] | None = ..., - converter: _ConverterType - | list[_ConverterType] - | tuple[_ConverterType, ...] - | None = ..., - factory: Callable[[], _T] | None = ..., - kw_only: bool | None = ..., - eq: _EqOrderType | None = ..., - order: _EqOrderType | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - alias: str | None = ..., - type: type | None = ..., -) -> Any: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(field_specifiers=(attrib, field)) -def define( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -mutable = define - -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: _C, - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> _C: ... -@overload -@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) -def frozen( - maybe_cls: None = ..., - *, - these: dict[str, Any] | None = ..., - repr: bool = ..., - unsafe_hash: bool | None = ..., - hash: bool | None = ..., - init: bool = ..., - slots: bool = ..., - frozen: bool = ..., - weakref_slot: bool = ..., - str: bool = ..., - auto_attribs: bool = ..., - kw_only: bool = ..., - cache_hash: bool = ..., - auto_exc: bool = ..., - eq: bool | None = ..., - order: bool | None = ..., - auto_detect: bool = ..., - getstate_setstate: bool | None = ..., - on_setattr: _OnSetAttrArgType | None = ..., - field_transformer: _FieldTransformer | None = ..., - match_args: bool = ..., -) -> Callable[[_C], _C]: ... - -class ClassProps: - # XXX: somehow when defining/using enums Mypy starts looking at our own - # (untyped) code and causes tons of errors. - Hashability: Any - KeywordOnly: Any - - is_exception: bool - is_slotted: bool - has_weakref_slot: bool - is_frozen: bool - # kw_only: ClassProps.KeywordOnly - kw_only: Any - collected_fields_by_mro: bool - added_init: bool - added_repr: bool - added_eq: bool - added_ordering: bool - # hashability: ClassProps.Hashability - hashability: Any - added_match_args: bool - added_str: bool - added_pickling: bool - on_setattr_hook: _OnSetAttrType | None - field_transformer: Callable[[Attribute[Any]], Attribute[Any]] | None - - def __init__( - self, - is_exception: bool, - is_slotted: bool, - has_weakref_slot: bool, - is_frozen: bool, - # kw_only: ClassProps.KeywordOnly - kw_only: Any, - collected_fields_by_mro: bool, - added_init: bool, - added_repr: bool, - added_eq: bool, - added_ordering: bool, - # hashability: ClassProps.Hashability - hashability: Any, - added_match_args: bool, - added_str: bool, - added_pickling: bool, - on_setattr_hook: _OnSetAttrType, - field_transformer: Callable[[Attribute[Any]], Attribute[Any]], - ) -> None: ... - @property - def is_hashable(self) -> bool: ... - -def inspect(cls: type) -> ClassProps: ... diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/converters.py b/backend/venv39/lib/python3.9/site-packages/attrs/converters.py deleted file mode 100644 index 7821f6c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/converters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.converters import * # noqa: F403 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/exceptions.py b/backend/venv39/lib/python3.9/site-packages/attrs/exceptions.py deleted file mode 100644 index 3323f9d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/exceptions.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.exceptions import * # noqa: F403 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/filters.py b/backend/venv39/lib/python3.9/site-packages/attrs/filters.py deleted file mode 100644 index 3080f48..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/filters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.filters import * # noqa: F403 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/py.typed b/backend/venv39/lib/python3.9/site-packages/attrs/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/setters.py b/backend/venv39/lib/python3.9/site-packages/attrs/setters.py deleted file mode 100644 index f3d73bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/setters.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.setters import * # noqa: F403 diff --git a/backend/venv39/lib/python3.9/site-packages/attrs/validators.py b/backend/venv39/lib/python3.9/site-packages/attrs/validators.py deleted file mode 100644 index 037e124..0000000 --- a/backend/venv39/lib/python3.9/site-packages/attrs/validators.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: MIT - -from attr.validators import * # noqa: F403 diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/LICENSE deleted file mode 100644 index 11069ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/METADATA deleted file mode 100644 index 86f46ae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/METADATA +++ /dev/null @@ -1,342 +0,0 @@ -Metadata-Version: 2.1 -Name: bcrypt -Version: 5.0.0 -Summary: Modern password hashing for your software and your servers -Author-email: The Python Cryptographic Authority developers -License: Apache-2.0 -Project-URL: homepage, https://github.com/pyca/bcrypt/ -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-File: LICENSE -Provides-Extra: tests -Requires-Dist: pytest!=3.3.0,>=3.2.1; extra == "tests" -Provides-Extra: typecheck -Requires-Dist: mypy; extra == "typecheck" - -bcrypt -====== - -.. image:: https://img.shields.io/pypi/v/bcrypt.svg - :target: https://pypi.org/project/bcrypt/ - :alt: Latest Version - -.. image:: https://github.com/pyca/bcrypt/workflows/CI/badge.svg?branch=main - :target: https://github.com/pyca/bcrypt/actions?query=workflow%3ACI+branch%3Amain - -Acceptable password hashing for your software and your servers (but you should -really use argon2id or scrypt) - - -Installation -============ - -To install bcrypt, simply: - -.. code:: console - - $ pip install bcrypt - -Note that bcrypt should build very easily on Linux provided you have a C -compiler and a Rust compiler (the minimum supported Rust version is 1.56.0). - -For Debian and Ubuntu, the following command will ensure that the required dependencies are installed: - -.. code:: console - - $ sudo apt-get install build-essential cargo - -For Fedora and RHEL-derivatives, the following command will ensure that the required dependencies are installed: - -.. code:: console - - $ sudo yum install gcc cargo - -For Alpine, the following command will ensure that the required dependencies are installed: - -.. code:: console - - $ apk add --update musl-dev gcc cargo - - -Alternatives -============ - -While bcrypt remains an acceptable choice for password storage, depending on your specific use case you may also want to consider using scrypt (either via `standard library`_ or `cryptography`_) or argon2id via `argon2_cffi`_. - -Changelog -========= - -5.0.0 ------ - -* Bumped MSRV to 1.74. -* Added support for Python 3.14 and free-threaded Python 3.14. -* Added support for Windows on ARM. -* Passing ``hashpw`` a password longer than 72 bytes now raises a - ``ValueError``. Previously the password was silently truncated, following the - behavior of the original OpenBSD ``bcrypt`` implementation. - -4.3.0 ------ - -* Dropped support for Python 3.7. -* We now support free-threaded Python 3.13. -* We now support PyPy 3.11. -* We now publish wheels for free-threaded Python 3.13, for PyPy 3.11 on - ``manylinux``, and for ARMv7l on ``manylinux``. - -4.2.1 ------ - -* Bump Rust dependency versions - this should resolve crashes on Python 3.13 - free-threaded builds. -* We no longer build ``manylinux`` wheels for PyPy 3.9. - -4.2.0 ------ - -* Bump Rust dependency versions -* Removed the ``BCRYPT_ALLOW_RUST_163`` environment variable. - -4.1.3 ------ - -* Bump Rust dependency versions - -4.1.2 ------ - -* Publish both ``py37`` and ``py39`` wheels. This should resolve some errors - relating to initializing a module multiple times per process. - -4.1.1 ------ - -* Fixed the type signature on the ``kdf`` method. -* Fixed packaging bug on Windows. -* Fixed incompatibility with passlib package detection assumptions. - -4.1.0 ------ - -* Dropped support for Python 3.6. -* Bumped MSRV to 1.64. (Note: Rust 1.63 can be used by setting the ``BCRYPT_ALLOW_RUST_163`` environment variable) - -4.0.1 ------ - -* We now build PyPy ``manylinux`` wheels. -* Fixed a bug where passing an invalid ``salt`` to ``checkpw`` could result in - a ``pyo3_runtime.PanicException``. It now correctly raises a ``ValueError``. - -4.0.0 ------ - -* ``bcrypt`` is now implemented in Rust. Users building from source will need - to have a Rust compiler available. Nothing will change for users downloading - wheels. -* We no longer ship ``manylinux2010`` wheels. Users should upgrade to the latest - ``pip`` to ensure this doesn’t cause issues downloading wheels on their - platform. We now ship ``manylinux_2_28`` wheels for users on new enough platforms. -* ``NUL`` bytes are now allowed in inputs. - - -3.2.2 ------ - -* Fixed packaging of ``py.typed`` files in wheels so that ``mypy`` works. - -3.2.1 ------ - -* Added support for compilation on z/OS -* The next release of ``bcrypt`` with be 4.0 and it will require Rust at - compile time, for users building from source. There will be no additional - requirement for users who are installing from wheels. Users on most - platforms will be able to obtain a wheel by making sure they have an up to - date ``pip``. The minimum supported Rust version will be 1.56.0. -* This will be the final release for which we ship ``manylinux2010`` wheels. - Going forward the minimum supported manylinux ABI for our wheels will be - ``manylinux2014``. The vast majority of users will continue to receive - ``manylinux`` wheels provided they have an up to date ``pip``. - - -3.2.0 ------ - -* Added typehints for library functions. -* Dropped support for Python versions less than 3.6 (2.7, 3.4, 3.5). -* Shipped ``abi3`` Windows wheels (requires pip >= 20). - -3.1.7 ------ - -* Set a ``setuptools`` lower bound for PEP517 wheel building. -* We no longer distribute 32-bit ``manylinux1`` wheels. Continuing to produce - them was a maintenance burden. - -3.1.6 ------ - -* Added support for compilation on Haiku. - -3.1.5 ------ - -* Added support for compilation on AIX. -* Dropped Python 2.6 and 3.3 support. -* Switched to using ``abi3`` wheels for Python 3. If you are not getting a - wheel on a compatible platform please upgrade your ``pip`` version. - -3.1.4 ------ - -* Fixed compilation with mingw and on illumos. - -3.1.3 ------ -* Fixed a compilation issue on Solaris. -* Added a warning when using too few rounds with ``kdf``. - -3.1.2 ------ -* Fixed a compile issue affecting big endian platforms. -* Fixed invalid escape sequence warnings on Python 3.6. -* Fixed building in non-UTF8 environments on Python 2. - -3.1.1 ------ -* Resolved a ``UserWarning`` when used with ``cffi`` 1.8.3. - -3.1.0 ------ -* Added support for ``checkpw``, a convenience method for verifying a password. -* Ensure that you get a ``$2y$`` hash when you input a ``$2y$`` salt. -* Fixed a regression where ``$2a`` hashes were vulnerable to a wraparound bug. -* Fixed compilation under Alpine Linux. - -3.0.0 ------ -* Switched the C backend to code obtained from the OpenBSD project rather than - openwall. -* Added support for ``bcrypt_pbkdf`` via the ``kdf`` function. - -2.0.0 ------ -* Added support for an adjustible prefix when calling ``gensalt``. -* Switched to CFFI 1.0+ - -Usage ------ - -Password Hashing -~~~~~~~~~~~~~~~~ - -Hashing and then later checking that a password matches the previous hashed -password is very simple: - -.. code:: pycon - - >>> import bcrypt - >>> password = b"super secret password" - >>> # Hash a password for the first time, with a randomly-generated salt - >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt()) - >>> # Check that an unhashed password matches one that has previously been - >>> # hashed - >>> if bcrypt.checkpw(password, hashed): - ... print("It Matches!") - ... else: - ... print("It Does not Match :(") - -KDF -~~~ - -As of 3.0.0 ``bcrypt`` now offers a ``kdf`` function which does ``bcrypt_pbkdf``. -This KDF is used in OpenSSH's newer encrypted private key format. - -.. code:: pycon - - >>> import bcrypt - >>> key = bcrypt.kdf( - ... password=b'password', - ... salt=b'salt', - ... desired_key_bytes=32, - ... rounds=100) - - -Adjustable Work Factor -~~~~~~~~~~~~~~~~~~~~~~ -One of bcrypt's features is an adjustable logarithmic work factor. To adjust -the work factor merely pass the desired number of rounds to -``bcrypt.gensalt(rounds=12)`` which defaults to 12): - -.. code:: pycon - - >>> import bcrypt - >>> password = b"super secret password" - >>> # Hash a password for the first time, with a certain number of rounds - >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt(14)) - >>> # Check that a unhashed password matches one that has previously been - >>> # hashed - >>> if bcrypt.checkpw(password, hashed): - ... print("It Matches!") - ... else: - ... print("It Does not Match :(") - - -Adjustable Prefix -~~~~~~~~~~~~~~~~~ - -Another one of bcrypt's features is an adjustable prefix to let you define what -libraries you'll remain compatible with. To adjust this, pass either ``2a`` or -``2b`` (the default) to ``bcrypt.gensalt(prefix=b"2b")`` as a bytes object. - -As of 3.0.0 the ``$2y$`` prefix is still supported in ``hashpw`` but deprecated. - -Maximum Password Length -~~~~~~~~~~~~~~~~~~~~~~~ - -The bcrypt algorithm only handles passwords up to 72 characters, any characters -beyond that are ignored. To work around this, a common approach is to hash a -password with a cryptographic hash (such as ``sha256``) and then base64 -encode it to prevent NULL byte problems before hashing the result with -``bcrypt``: - -.. code:: pycon - - >>> password = b"an incredibly long password" * 10 - >>> hashed = bcrypt.hashpw( - ... base64.b64encode(hashlib.sha256(password).digest()), - ... bcrypt.gensalt() - ... ) - -Compatibility -------------- - -This library should be compatible with py-bcrypt and it will run on Python -3.8+ (including free-threaded builds), and PyPy 3. - -Security --------- - -``bcrypt`` follows the `same security policy as cryptography`_, if you -identify a vulnerability, we ask you to contact us privately. - -.. _`same security policy as cryptography`: https://cryptography.io/en/latest/security.html -.. _`standard library`: https://docs.python.org/3/library/hashlib.html#hashlib.scrypt -.. _`argon2_cffi`: https://argon2-cffi.readthedocs.io -.. _`cryptography`: https://cryptography.io/en/latest/hazmat/primitives/key-derivation-functions/#cryptography.hazmat.primitives.kdf.scrypt.Scrypt diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/RECORD deleted file mode 100644 index 1387320..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/RECORD +++ /dev/null @@ -1,11 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.cpython-39.pyc,, -bcrypt-5.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -bcrypt-5.0.0.dist-info/LICENSE,sha256=gXPVwptPlW1TJ4HSuG5OMPg-a3h43OGMkZRR1rpwfJA,10850 -bcrypt-5.0.0.dist-info/METADATA,sha256=i0d9VpcvYkuW9auAAC8TC5fGEFIS3SEm6I24DcbuiE0,10502 -bcrypt-5.0.0.dist-info/RECORD,, -bcrypt-5.0.0.dist-info/WHEEL,sha256=TPSuvIjdmY_fZ57irZdtZVUvrlrOM05O6Px8Mk8bzIc,114 -bcrypt-5.0.0.dist-info/top_level.txt,sha256=BkR_qBzDbSuycMzHWE1vzXrfYecAzUVmQs6G2CukqNI,7 -bcrypt/__init__.py,sha256=cv-NupIX6P7o6A4PK_F0ur6IZoDr3GnvyzFO9k16wKQ,1000 -bcrypt/__init__.pyi,sha256=ITUCB9mPVU8sKUbJQMDUH5YfQXZb1O55F9qvKZR_o8I,333 -bcrypt/_bcrypt.abi3.so,sha256=W22eAZGZwn0KnLuNoPYfBYhZO29Q9l67TOmjuLbXEYw,1172304 -bcrypt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/WHEEL deleted file mode 100644 index eabad67..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.45.1) -Root-Is-Purelib: false -Tag: cp39-abi3-macosx_10_12_universal2 - diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/top_level.txt deleted file mode 100644 index 7f0b6e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt-5.0.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -bcrypt diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.py b/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.py deleted file mode 100644 index 81a92fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from ._bcrypt import ( - __author__, - __copyright__, - __email__, - __license__, - __summary__, - __title__, - __uri__, - checkpw, - gensalt, - hashpw, - kdf, -) -from ._bcrypt import ( - __version_ex__ as __version__, -) - -__all__ = [ - "__author__", - "__copyright__", - "__email__", - "__license__", - "__summary__", - "__title__", - "__uri__", - "__version__", - "checkpw", - "gensalt", - "hashpw", - "kdf", -] diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.pyi deleted file mode 100644 index 12e4a2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/bcrypt/__init__.pyi +++ /dev/null @@ -1,10 +0,0 @@ -def gensalt(rounds: int = 12, prefix: bytes = b"2b") -> bytes: ... -def hashpw(password: bytes, salt: bytes) -> bytes: ... -def checkpw(password: bytes, hashed_password: bytes) -> bool: ... -def kdf( - password: bytes, - salt: bytes, - desired_key_bytes: int, - rounds: int, - ignore_few_rounds: bool = False, -) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so b/backend/venv39/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so deleted file mode 100755 index ec26ceb..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/bcrypt/py.typed b/backend/venv39/lib/python3.9/site-packages/bcrypt/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/METADATA deleted file mode 100644 index d1bc526..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/METADATA +++ /dev/null @@ -1,78 +0,0 @@ -Metadata-Version: 2.4 -Name: certifi -Version: 2026.1.4 -Summary: Python package for providing Mozilla's CA Bundle. -Home-page: https://github.com/certifi/python-certifi -Author: Kenneth Reitz -Author-email: me@kennethreitz.com -License: MPL-2.0 -Project-URL: Source, https://github.com/certifi/python-certifi -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.7 -License-File: LICENSE -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: project-url -Dynamic: requires-python -Dynamic: summary - -Certifi: Python SSL Certificates -================================ - -Certifi provides Mozilla's carefully curated collection of Root Certificates for -validating the trustworthiness of SSL certificates while verifying the identity -of TLS hosts. It has been extracted from the `Requests`_ project. - -Installation ------------- - -``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - -Usage ------ - -To reference the installed certificate authority (CA) bundle, you can use the -built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' - -Or from the command line:: - - $ python -m certifi - /usr/local/lib/python3.7/site-packages/certifi/cacert.pem - -Enjoy! - -.. _`Requests`: https://requests.readthedocs.io/en/master/ - -Addition/Removal of Certificates --------------------------------- - -Certifi does not support any addition/removal or other modification of the -CA trust store content. This project is intended to provide a reliable and -highly portable root of trust to python deployments. Look to upstream projects -for methods to use alternate trust. diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/RECORD deleted file mode 100644 index 711daf6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/RECORD +++ /dev/null @@ -1,14 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/certifi/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/certifi/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/certifi/core.cpython-39.pyc,, -certifi-2026.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -certifi-2026.1.4.dist-info/METADATA,sha256=FSfJEfKuMo6bJlofUrtRpn4PFTYtbYyXpHN_A3ZFpIY,2473 -certifi-2026.1.4.dist-info/RECORD,, -certifi-2026.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -certifi-2026.1.4.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 -certifi-2026.1.4.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 -certifi/__init__.py,sha256=969deMMS7Uchipr0oO4dbRBUvRi0uNYCn07VmG1aTrg,94 -certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 -certifi/cacert.pem,sha256=Tzl1_zCrvzVEO0hgZK6Ly0Hf9wf_31dsdtKS-0WKoKk,270954 -certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 -certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/licenses/LICENSE deleted file mode 100644 index 62b076c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/licenses/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -This package contains a modified version of ca-bundle.crt: - -ca-bundle.crt -- Bundle of CA Root Certificates - -This is a bundle of X.509 certificates of public Certificate Authorities -(CA). These were automatically extracted from Mozilla's root certificates -file (certdata.txt). This file can be found in the mozilla source tree: -https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt -It contains the certificates in PEM format and therefore -can be directly used with curl / libcurl / php_curl, or with -an Apache+mod_ssl webserver for SSL client authentication. -Just configure this file as the SSLCACertificateFile.# - -***** BEGIN LICENSE BLOCK ***** -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at http://mozilla.org/MPL/2.0/. - -***** END LICENSE BLOCK ***** -@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/top_level.txt deleted file mode 100644 index 963eac5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi-2026.1.4.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -certifi diff --git a/backend/venv39/lib/python3.9/site-packages/certifi/__init__.py b/backend/venv39/lib/python3.9/site-packages/certifi/__init__.py deleted file mode 100644 index 090fd58..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .core import contents, where - -__all__ = ["contents", "where"] -__version__ = "2026.01.04" diff --git a/backend/venv39/lib/python3.9/site-packages/certifi/__main__.py b/backend/venv39/lib/python3.9/site-packages/certifi/__main__.py deleted file mode 100644 index 8945b5d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -import argparse - -from certifi import contents, where - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--contents", action="store_true") -args = parser.parse_args() - -if args.contents: - print(contents()) -else: - print(where()) diff --git a/backend/venv39/lib/python3.9/site-packages/certifi/cacert.pem b/backend/venv39/lib/python3.9/site-packages/certifi/cacert.pem deleted file mode 100644 index 132db0d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi/cacert.pem +++ /dev/null @@ -1,4468 +0,0 @@ - -# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2" -# Serial: 1289 -# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b -# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 -# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3" -# Serial: 1478 -# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf -# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 -# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root CA" -# Serial: 17154717934120587862167794914071425081 -# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 -# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 -# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert High Assurance EV Root CA" -# Serial: 3553400076410547919724730734378100087 -# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a -# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 -# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Label: "SwissSign Gold CA - G2" -# Serial: 13492815561806991280 -# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 -# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 -# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- - -# Issuer: CN=SecureTrust CA O=SecureTrust Corporation -# Subject: CN=SecureTrust CA O=SecureTrust Corporation -# Label: "SecureTrust CA" -# Serial: 17199774589125277788362757014266862032 -# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 -# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 -# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -# Issuer: CN=Secure Global CA O=SecureTrust Corporation -# Subject: CN=Secure Global CA O=SecureTrust Corporation -# Label: "Secure Global CA" -# Serial: 9751836167731051554232119481456978597 -# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de -# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b -# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO Certification Authority O=COMODO CA Limited -# Label: "COMODO Certification Authority" -# Serial: 104350513648249232941998508985834464573 -# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 -# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b -# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -# Issuer: CN=Certigna O=Dhimyotis -# Subject: CN=Certigna O=Dhimyotis -# Label: "Certigna" -# Serial: 18364802974209362175 -# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff -# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 -# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -# Issuer: O=certSIGN OU=certSIGN ROOT CA -# Subject: O=certSIGN OU=certSIGN ROOT CA -# Label: "certSIGN ROOT CA" -# Serial: 35210227249154 -# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 -# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b -# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- - -# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Label: "TeliaSonera Root CA v1" -# Serial: 199041966741090107964904287217786801558 -# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c -# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 -# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw -NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv -b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD -VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F -VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 -7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X -Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ -/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs -81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm -dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe -Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu -sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 -pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs -slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ -arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG -9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl -dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj -TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed -Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 -Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI -OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 -vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW -t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn -HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx -SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Label: "GlobalSign Root CA - R6" -# Serial: 1417766617973444989252670301619537 -# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae -# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 -# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GC CA" -# Serial: 44084345621038548146064804565436152554 -# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 -# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 -# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -# Issuer: CN=UCA Global G2 Root O=UniTrust -# Subject: CN=UCA Global G2 Root O=UniTrust -# Label: "UCA Global G2 Root" -# Serial: 124779693093741543919145257850076631279 -# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 -# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a -# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- - -# Issuer: CN=UCA Extended Validation Root O=UniTrust -# Subject: CN=UCA Extended Validation Root O=UniTrust -# Label: "UCA Extended Validation Root" -# Serial: 106100277556486529736699587978573607008 -# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 -# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a -# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- - -# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Label: "Certigna Root CA" -# Serial: 269714418870597844693661054334862075617 -# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 -# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 -# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign Root CA - G1" -# Serial: 235931866688319308814040 -# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac -# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c -# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign ECC Root CA - G3" -# Serial: 287880440101571086945156 -# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 -# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 -# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Label: "emSign Root CA - C1" -# Serial: 825510296613316004955058 -# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 -# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 -# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Label: "emSign ECC Root CA - C3" -# Serial: 582948710642506000014504 -# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 -# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 -# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Label: "Hongkong Post Root CA 3" -# Serial: 46170865288971385588281144162979347873371282084 -# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 -# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 -# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL -BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ -SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n -a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 -NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT -CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u -Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO -dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI -VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV -9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY -2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY -vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt -bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb -x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ -l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK -TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj -Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw -DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG -7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk -MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr -gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk -GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS -3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm -Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ -l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c -JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP -L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa -LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG -mpv0 ------END CERTIFICATE----- - -# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft ECC Root Certificate Authority 2017" -# Serial: 136839042543790627607696632466672567020 -# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 -# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 -# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft RSA Root Certificate Authority 2017" -# Serial: 40975477897264996090493496164228220339 -# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 -# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 -# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Label: "e-Szigno Root CA 2017" -# Serial: 411379200276854331539784714 -# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 -# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 -# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- - -# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Label: "certSIGN Root CA G2" -# Serial: 313609486401300475190 -# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 -# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 -# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global Certification Authority" -# Serial: 1846098327275375458322922162 -# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e -# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 -# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw -CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x -ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 -c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx -OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI -SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn -swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu -7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 -1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW -80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP -JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l -RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw -hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 -coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc -BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n -twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W -0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe -uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q -lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB -aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE -sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT -MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe -qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh -VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 -h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 -EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK -yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P256 Certification Authority" -# Serial: 4151900041497450638097112925 -# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 -# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf -# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN -FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w -DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw -CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh -DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P384 Certification Authority" -# Serial: 2704997926503831671788816187 -# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 -# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 -# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB -BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ -j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF -1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G -A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 -AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC -MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu -Sw== ------END CERTIFICATE----- - -# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Label: "NAVER Global Root Certification Authority" -# Serial: 9013692873798656336226253319739695165984492813 -# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b -# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 -# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- - -# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" -# Serial: 131542671362353147877283741781055151509 -# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb -# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a -# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Label: "GlobalSign Root R46" -# Serial: 1552617688466950547958867513931858518042577 -# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef -# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 -# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Label: "GlobalSign Root E46" -# Serial: 1552617690338932563915843282459653771421763 -# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f -# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 -# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Label: "ANF Secure Server Root CA" -# Serial: 996390341000653745 -# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 -# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 -# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV -BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk -YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV -BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN -MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF -UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD -VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v -dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj -cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q -yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH -2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX -H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL -zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR -p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz -W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ -SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn -LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 -n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B -u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L -9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej -rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK -pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 -vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq -OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ -/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 -2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI -+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 -MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo -tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- - -# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum EC-384 CA" -# Serial: 160250656287871593594747141429395092468 -# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 -# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed -# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Root CA" -# Serial: 40870380103424195783807378461123655149 -# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 -# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 -# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 -MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu -MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV -BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw -MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg -U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ -n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q -p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq -NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF -8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 -HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa -mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi -7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF -ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P -qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ -v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 -Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD -ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 -WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo -zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR -5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ -GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf -5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq -0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D -P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM -qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP -0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf -E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- - -# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique -# Label: "TunTrust Root CA" -# Serial: 108534058042236574382096126452369648152337120275 -# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 -# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb -# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL -BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg -Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv -b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG -EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u -IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ -n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd -2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF -VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ -GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF -li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU -r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 -eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb -MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg -jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB -7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW -5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE -ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 -90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z -xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu -QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 -FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH -22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP -xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn -dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 -Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b -nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ -CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH -u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj -d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS RSA Root CA 2021" -# Serial: 76817823531813593706434026085292783742 -# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 -# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d -# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs -MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg -Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL -MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl -YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv -b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l -mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE -4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv -a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M -pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw -Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b -LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY -AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB -AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq -E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr -W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ -CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU -X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 -f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja -H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP -JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P -zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt -jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 -/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT -BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 -aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW -xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU -63ZTGI0RmLo= ------END CERTIFICATE----- - -# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA -# Label: "HARICA TLS ECC Root CA 2021" -# Serial: 137515985548005187474074462014555733966 -# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 -# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 -# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 ------BEGIN CERTIFICATE----- -MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw -CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh -cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v -dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG -A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj -aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg -Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 -KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y -STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD -AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw -SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN -nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps ------END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 1977337328857672817 -# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 -# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe -# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 -MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc -tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd -IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j -b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC -AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw -ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m -iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF -Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ -hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P -Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE -EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV -1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t -CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR -5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw -f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 -ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK -GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV ------END CERTIFICATE----- - -# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus ECC Root CA" -# Serial: 630369271402956006249506845124680065938238527194 -# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 -# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 -# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 ------BEGIN CERTIFICATE----- -MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw -RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY -BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz -MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u -LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 -v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd -e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw -V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA -AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG -GJTO ------END CERTIFICATE----- - -# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. -# Label: "vTrus Root CA" -# Serial: 387574501246983434957692974888460947164905180485 -# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc -# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 -# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL -BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x -FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx -MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s -THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc -IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU -AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ -GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 -8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH -flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt -J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim -0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN -pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ -UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW -OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB -AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet -8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd -nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j -bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM -Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv -TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS -S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr -I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 -b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB -UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P -Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven -sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X2 O=Internet Security Research Group -# Subject: CN=ISRG Root X2 O=Internet Security Research Group -# Label: "ISRG Root X2" -# Serial: 87493402998870891108772069816698636114 -# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 -# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af -# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- - -# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. -# Label: "HiPKI Root CA - G1" -# Serial: 60966262342023497858655262305426234976 -# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 -# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 -# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc ------BEGIN CERTIFICATE----- -MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa -Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 -YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw -qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv -Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 -lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz -Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ -KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK -FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj -HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr -y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ -/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM -a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 -fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG -SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi -7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc -SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza -ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc -XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg -iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho -L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF -Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr -kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ -vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU -YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 159662223612894884239637590694 -# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc -# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 -# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 ------BEGIN CERTIFICATE----- -MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD -VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw -MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g -UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT -BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx -uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV -HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ -+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 -bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 159662320309726417404178440727 -# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 -# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a -# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R2 O=Google Trust Services LLC -# Subject: CN=GTS Root R2 O=Google Trust Services LLC -# Label: "GTS Root R2" -# Serial: 159662449406622349769042896298 -# MD5 Fingerprint: 1e:39:c0:53:e6:1e:29:82:0b:ca:52:55:36:5d:57:dc -# SHA1 Fingerprint: 9a:44:49:76:32:db:de:fa:d0:bc:fb:5a:7b:17:bd:9e:56:09:24:94 -# SHA256 Fingerprint: 8d:25:cd:97:22:9d:bf:70:35:6b:da:4e:b3:cc:73:40:31:e2:4c:f0:0f:af:cf:d3:2d:c7:6e:b5:84:1c:7e:a8 ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt -nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY -6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu -MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k -RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg -f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV -+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo -dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW -Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa -G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq -gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H -vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 -0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC -B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u -NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg -yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev -HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 -xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR -TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg -JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV -7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl -6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R3 O=Google Trust Services LLC -# Subject: CN=GTS Root R3 O=Google Trust Services LLC -# Label: "GTS Root R3" -# Serial: 159662495401136852707857743206 -# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 -# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 -# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G -jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 -4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 -VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm -ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 159662532700760215368942768210 -# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 -# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 -# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi -QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR -HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D -9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 -p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE----- - -# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj -# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj -# Label: "Telia Root CA v2" -# Serial: 7288924052977061235122729490515358 -# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 -# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd -# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx -CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE -AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 -NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ -MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq -AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 -vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 -lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD -n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT -7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o -6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC -TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 -WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R -DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI -pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj -YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy -rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ -8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi -0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM -A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS -SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K -TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF -6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er -3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt -Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT -VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW -ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA -rBPuUBQemMc= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 1 2020" -# Serial: 165870826978392376648679885835942448534 -# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed -# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 -# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 -NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS -zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 -QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ -VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW -wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV -dWNbFJWcHwHP2NVypw87 ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 1 2020" -# Serial: 126288379621884218666039612629459926992 -# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e -# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 -# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db ------BEGIN CERTIFICATE----- -MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw -CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS -VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 -NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG -A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC -/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD -wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 -OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g -PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf -Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l -dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 -c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO -PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA -y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb -gfM0agPnIjhQW+0ZT0MW ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS ECC P384 Root G5" -# Serial: 13129116028163249804115411775095713523 -# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed -# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee -# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05 ------BEGIN CERTIFICATE----- -MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp -Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 -MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ -bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS -7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp -0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS -B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 -BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ -LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 -DXZDjC5Ty3zfDBeWUA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. -# Label: "DigiCert TLS RSA4096 Root G5" -# Serial: 11930366277458970227240571539258396554 -# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1 -# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35 -# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75 ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT -HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN -NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs -IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ -ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 -2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp -wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM -pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD -nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po -sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx -Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd -Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX -KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe -XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL -tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv -TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw -GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H -PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF -O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ -REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik -AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv -/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ -p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw -MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF -qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK -ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root R1 O=Certainly -# Subject: CN=Certainly Root R1 O=Certainly -# Label: "Certainly Root R1" -# Serial: 188833316161142517227353805653483829216 -# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12 -# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af -# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw -PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy -dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 -YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 -1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT -vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed -aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 -1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 -r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 -cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ -wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ -6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA -2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH -Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR -eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB -/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u -d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr -PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d -8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi -1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd -rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di -taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 -lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj -yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn -Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy -yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n -wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 -OV+KmalBWQewLK8= ------END CERTIFICATE----- - -# Issuer: CN=Certainly Root E1 O=Certainly -# Subject: CN=Certainly Root E1 O=Certainly -# Label: "Certainly Root E1" -# Serial: 8168531406727139161245376702891150584 -# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9 -# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b -# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2 ------BEGIN CERTIFICATE----- -MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw -CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu -bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ -BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s -eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK -+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 -QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 -hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm -ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG -BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR ------END CERTIFICATE----- - -# Issuer: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Subject: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. -# Label: "Security Communication ECC RootCA1" -# Serial: 15446673492073852651 -# MD5 Fingerprint: 7e:43:b0:92:68:ec:05:43:4c:98:ab:5d:35:2e:7e:86 -# SHA1 Fingerprint: b8:0e:26:a9:bf:d2:b2:3b:c0:ef:46:c9:ba:c7:bb:f6:1d:0d:41:41 -# SHA256 Fingerprint: e7:4f:bd:a5:5b:d5:64:c4:73:a3:6b:44:1a:a7:99:c8:a6:8e:07:74:40:e8:28:8b:9f:a1:e5:0e:4b:ba:ca:11 ------BEGIN CERTIFICATE----- -MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT -AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD -VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx -NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT -HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 -IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl -dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK -ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu -9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O -be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA1" -# Serial: 113562791157148395269083148143378328608 -# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90 -# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a -# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU -MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI -T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz -MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF -SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh -bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z -xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ -spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 -58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR -at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll -5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq -nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK -V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ -pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO -z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn -jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ -WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF -7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 -YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli -awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u -+2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 -X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN -SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo -P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI -+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz -znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 -eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 -YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy -r/6zcCwupvI= ------END CERTIFICATE----- - -# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY -# Label: "BJCA Global Root CA2" -# Serial: 58605626836079930195615843123109055211 -# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c -# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6 -# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82 ------BEGIN CERTIFICATE----- -MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw -CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ -VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy -MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ -TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS -b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B -IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ -+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK -sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA -94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B -43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root E46" -# Serial: 88989738453351742415770396670917916916 -# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01 -# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a -# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83 ------BEGIN CERTIFICATE----- -MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw -CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T -ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN -MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG -A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT -ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC -WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ -6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B -Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa -qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q -4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== ------END CERTIFICATE----- - -# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited -# Label: "Sectigo Public Server Authentication Root R46" -# Serial: 156256931880233212765902055439220583700 -# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5 -# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38 -# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06 ------BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf -MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD -Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw -HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY -MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp -YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa -ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz -SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf -iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X -ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 -IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS -VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE -SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu -+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt -8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L -HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt -zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P -AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c -mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ -YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 -gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA -Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB -JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX -DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui -TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 -dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 -LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp -0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY -QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS RSA Root CA 2022" -# Serial: 148535279242832292258835760425842727825 -# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da -# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca -# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed ------BEGIN CERTIFICATE----- -MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO -MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD -DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX -DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw -b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP -L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY -t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins -S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 -PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO -L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 -R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w -dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS -+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS -d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG -AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f -gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z -NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt -hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM -QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf -R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ -DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW -P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy -lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq -bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w -AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q -r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji -Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU -98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation -# Label: "SSL.com TLS ECC Root CA 2022" -# Serial: 26605119622390491762507526719404364228 -# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5 -# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39 -# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43 ------BEGIN CERTIFICATE----- -MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw -CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT -U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 -MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh -dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG -ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm -acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN -SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME -GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW -uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp -15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN -b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA ECC TLS 2021" -# Serial: 81873346711060652204712539181482831616 -# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8 -# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd -# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8 ------BEGIN CERTIFICATE----- -MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w -LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w -CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 -MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF -Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI -zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X -tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 -AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 -KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD -aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu -CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo -9H1/IISpQuQo ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos -# Label: "Atos TrustedRoot Root CA RSA TLS 2021" -# Serial: 111436099570196163832749341232207667876 -# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2 -# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48 -# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f ------BEGIN CERTIFICATE----- -MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM -MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx -MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 -MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD -QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z -4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv -Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ -kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs -GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln -nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh -3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD -0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy -geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 -ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB -c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI -pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS -4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs -o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ -qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw -xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM -rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 -AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR -0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY -o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 -dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE -oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G3" -# Serial: 576386314500428537169965010905813481816650257167 -# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04 -# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7 -# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08 ------BEGIN CERTIFICATE----- -MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM -BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe -Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw -IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU -cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS -T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK -AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 -nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep -qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA -yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs -hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX -zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv -kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT -f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA -uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih -MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E -BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 -wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 -XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 -JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j -ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV -VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx -xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on -AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d -7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj -gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV -+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo -FGWsJwt0ivKH ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. -# Label: "TrustAsia Global Root CA G4" -# Serial: 451799571007117016466790293371524403291602933463 -# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb -# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a -# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c ------BEGIN CERTIFICATE----- -MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw -WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y -MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD -VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz -dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx -s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw -LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD -pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE -AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR -UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj -/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS ECC Root 2020" -# Serial: 72082518505882327255703894282316633856 -# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd -# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec -# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1 ------BEGIN CERTIFICATE----- -MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw -CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH -bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw -MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx -JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE -AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O -tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP -f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA -MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di -z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn -27iQ7t0l ------END CERTIFICATE----- - -# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH -# Label: "Telekom Security TLS RSA Root 2023" -# Serial: 44676229530606711399881795178081572759 -# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2 -# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93 -# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46 ------BEGIN CERTIFICATE----- -MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj -MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 -eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy -MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC -REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG -A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 -cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV -cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA -U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 -Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug -BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy -8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J -co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg -8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 -rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 -mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg -+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX -gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 -p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ -pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm -9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw -M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd -GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ -CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t -xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ -w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK -L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj -X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q -ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm -dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= ------END CERTIFICATE----- - -# Issuer: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA -# Subject: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA -# Label: "FIRMAPROFESIONAL CA ROOT-A WEB" -# Serial: 65916896770016886708751106294915943533 -# MD5 Fingerprint: 82:b2:ad:45:00:82:b0:66:63:f8:5f:c3:67:4e:ce:a3 -# SHA1 Fingerprint: a8:31:11:74:a6:14:15:0d:ca:77:dd:0e:e4:0c:5d:58:fc:a0:72:a5 -# SHA256 Fingerprint: be:f2:56:da:f2:6e:9c:69:bd:ec:16:02:35:97:98:f3:ca:f7:18:21:a0:3e:01:82:57:c5:3c:65:61:7f:3d:4a ------BEGIN CERTIFICATE----- -MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw -CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE -YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB -IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw -CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE -YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB -IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf -e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C -cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O -BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO -PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw -hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG -XSaQpYXFuXqUPoeovQA= ------END CERTIFICATE----- - -# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA CYBER Root CA" -# Serial: 85076849864375384482682434040119489222 -# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51 -# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66 -# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58 ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ -MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 -IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 -WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO -LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg -Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P -40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF -avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ -34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i -JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu -j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf -Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP -2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA -S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA -oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC -kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW -5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd -BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB -AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t -tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn -68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn -TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t -RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx -f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI -Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz -8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 -NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX -xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 -t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA12" -# Serial: 587887345431707215246142177076162061960426065942 -# MD5 Fingerprint: c6:89:ca:64:42:9b:62:08:49:0b:1e:7f:e9:07:3d:e8 -# SHA1 Fingerprint: 7a:22:1e:3d:de:1b:06:ac:9e:c8:47:70:16:8e:3c:e5:f7:6b:06:f4 -# SHA256 Fingerprint: 3f:03:4b:b5:70:4d:44:b2:d0:85:45:a0:20:57:de:93:eb:f3:90:5f:ce:72:1a:cb:c7:30:c0:6d:da:ee:90:4e ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw -NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF -KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt -p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd -J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur -FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J -hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K -h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF -AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld -mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ -mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA -8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV -55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/ -yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA14" -# Serial: 575790784512929437950770173562378038616896959179 -# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5 -# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f -# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38 ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM -BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u -LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw -NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD -eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS -b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/ -FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg -vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy -6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo -/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J -kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ -0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib -y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac -18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs -0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB -SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL -ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk -86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E -rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib -ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT -zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS -DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4 -2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo -FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy -K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6 -dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl -Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB -365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c -JRNItX+S ------END CERTIFICATE----- - -# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. -# Label: "SecureSign Root CA15" -# Serial: 126083514594751269499665114766174399806381178503 -# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47 -# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d -# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a ------BEGIN CERTIFICATE----- -MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw -UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM -dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy -NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl -cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290 -IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4 -wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR -ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT -9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp -4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 -bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST BR Root CA 2 2023" -# Serial: 153168538924886464690566649552453098598 -# MD5 Fingerprint: e1:09:ed:d3:60:d4:56:1b:47:1f:b7:0c:5f:1b:5f:85 -# SHA1 Fingerprint: 2d:b0:70:ee:71:94:af:69:68:17:db:79:ce:58:9f:a0:6b:96:f7:87 -# SHA256 Fingerprint: 05:52:e6:f8:3f:df:65:e8:fa:96:70:e6:66:df:28:a4:e2:13:40:b5:10:cb:e5:25:66:f9:7c:4f:b9:4b:2b:d1 ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw -OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr -i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE -gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 -k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT -Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl -2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U -cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP -/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS -uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ -0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N -DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ -XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 -GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI -FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n -riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR -VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc -LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn -4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD -hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG -koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 -ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS -Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 -knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ -hJ65bvspmZDogNOfJA== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS ECC Root CA" -# Serial: 310892014698942880364840003424242768478804666567 -# MD5 Fingerprint: 09:48:04:77:d2:fc:65:93:71:66:b1:11:95:4f:06:8c -# SHA1 Fingerprint: b5:ec:39:f3:a1:66:37:ae:c3:05:94:57:e2:be:11:be:b7:a1:7f:36 -# SHA256 Fingerprint: c0:07:6b:9e:f0:53:1f:b1:a6:56:d6:7c:4e:be:97:cd:5d:ba:a4:1e:f4:45:98:ac:c2:48:98:78:c9:2d:87:11 ------BEGIN CERTIFICATE----- -MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw -WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs -IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw -NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE -ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB -c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ -AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp -guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw -DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 -L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR -OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== ------END CERTIFICATE----- - -# Issuer: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Subject: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. -# Label: "TrustAsia TLS RSA Root CA" -# Serial: 160405846464868906657516898462547310235378010780 -# MD5 Fingerprint: 3b:9e:c3:86:0f:34:3c:6b:c5:46:c4:8e:1d:e7:19:12 -# SHA1 Fingerprint: a5:46:50:c5:62:ea:95:9a:1a:a7:04:6f:17:58:c7:29:53:3d:03:fa -# SHA256 Fingerprint: 06:c0:8d:7d:af:d8:76:97:1e:b1:12:4f:e6:7f:84:7e:c0:c7:a1:58:d3:ea:53:cb:e9:40:e2:ea:97:91:f4:c3 ------BEGIN CERTIFICATE----- -MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM -BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp -ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN -MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG -A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 -c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC -AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ -NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ -Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 -HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 -ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb -xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX -i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ -UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j -TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT -bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 -S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 -Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 -iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt -7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp -2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ -g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj -pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M -pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP -XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe -SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 -ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy -323imttUQ/hHWKNddBWcwauwxzQ= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Subject: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH -# Label: "D-TRUST EV Root CA 2 2023" -# Serial: 139766439402180512324132425437959641711 -# MD5 Fingerprint: 96:b4:78:09:f0:09:cb:77:eb:bb:1b:4d:6f:36:bc:b6 -# SHA1 Fingerprint: a5:5b:d8:47:6c:8f:19:f7:4c:f4:6d:6b:b6:c2:79:82:22:df:54:8b -# SHA256 Fingerprint: 8e:82:21:b2:e7:d4:00:78:36:a1:67:2f:0d:cc:29:9c:33:bc:07:d3:16:f1:32:fa:1a:20:6d:58:71:50:f1:ce ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI -MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE -LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw -OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi -MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK -F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE -7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe -EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 -lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb -RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV -jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc -jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx -TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ -ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk -hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF -NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH -kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG -OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y -XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 -QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 -pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q -3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU -t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX -cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 -ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT -2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs -7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP -gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst -Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh -XBxvWHZks/wCuPWdCg== ------END CERTIFICATE----- - -# Issuer: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Subject: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG -# Label: "SwissSign RSA TLS Root CA 2022 - 1" -# Serial: 388078645722908516278762308316089881486363258315 -# MD5 Fingerprint: 16:2e:e4:19:76:81:85:ba:8e:91:58:f1:15:ef:72:39 -# SHA1 Fingerprint: 81:34:0a:be:4c:cd:ce:cc:e7:7d:cc:8a:d4:57:e2:45:a0:77:5d:ce -# SHA256 Fingerprint: 19:31:44:f4:31:e0:fd:db:74:07:17:d4:de:92:6a:57:11:33:88:4b:43:60:d3:0e:27:29:13:cb:e6:60:ce:41 ------BEGIN CERTIFICATE----- -MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE -AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx -MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT -d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg -MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX -vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 -LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX -5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE -EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt -/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x -0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 -KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM -0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd -OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta -clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK -wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 -DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL -BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 -10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz -Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ -iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc -gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM -ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF -LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp -zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td -Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 -rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO -gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root ECC G1 O=OISTE Foundation -# Label: "OISTE Server Root ECC G1" -# Serial: 47819833811561661340092227008453318557 -# MD5 Fingerprint: 42:a7:d2:35:ae:02:92:db:19:76:08:de:2f:05:b4:d4 -# SHA1 Fingerprint: 3b:f6:8b:09:ae:2a:92:7b:ba:e3:8d:3f:11:95:d9:e6:44:0c:45:e2 -# SHA256 Fingerprint: ee:c9:97:c0:c3:0f:21:6f:7e:3b:8b:30:7d:2b:ae:42:41:2d:75:3f:c8:21:9d:af:d1:52:0b:25:72:85:0f:49 ------BEGIN CERTIFICATE----- -MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQsw -CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY -T0lTVEUgU2VydmVyIFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUy -NDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp -b24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBHMTB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOujvqQy -cvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N -2xml4z+cKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3 -TYhlz/w9itWj8UnATgwQb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9C -tJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFR -QD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxgZzFDJe0CMQCSia7pXGKD -YmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= ------END CERTIFICATE----- - -# Issuer: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Subject: CN=OISTE Server Root RSA G1 O=OISTE Foundation -# Label: " OISTE Server Root RSA G1" -# Serial: 113845518112613905024960613408179309848 -# MD5 Fingerprint: 23:a7:9e:d4:70:b8:b9:14:57:41:8a:7e:44:59:e2:68 -# SHA1 Fingerprint: f7:00:34:25:94:88:68:31:e4:34:87:3f:70:fe:86:b3:86:9f:f0:6e -# SHA256 Fingerprint: 9a:e3:62:32:a5:18:9f:fd:db:35:3d:fd:26:52:0c:01:53:95:d2:27:77:da:c5:9d:b5:7b:98:c0:89:a6:51:e6 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBL -MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE -AwwYT0lTVEUgU2VydmVyIFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4 -MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k -YXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJTQSBHMTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxVYOPM -vLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7b -rEi56rAUjtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzk -ik/HEzxux9UTl7Ko2yRpg1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4z -O8vbUZeUapU8zhhabkvG/AePLhq5SvdkNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8R -tOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY+m0o/DjH40ytas7ZTpOS -jswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+lKXHiHUh -sd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+Ho -mnqT8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu -+zrkL8Fl47l6QGzwBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYR -i3drVByjtdgQ8K4p92cIiBdcuJd5z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnT -kCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU -8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC77EUOSh+1sbM2 -zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 -I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG -5D1rd9QhEOP28yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8 -qyiWXmFcuCIzGEgWUOrKL+mlSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dP -AGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l8PjaV8GUgeV6Vg27Rn9vkf195hfk -gSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+FKrDgHGdPY3ofRRs -YWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNqqYY1 -9tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome -/msVuduCmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3 -J8tRd/iWkx7P8nd9H0aTolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2 -wq1yVAb+axj5d9spLFKebXd7Yv0PTY6YMjAwcRLWJTXjn/hvnLXrahut6hDTlhZy -BiElxky8j3C7DOReIoMt0r7+hVu05L0= ------END CERTIFICATE----- diff --git a/backend/venv39/lib/python3.9/site-packages/certifi/core.py b/backend/venv39/lib/python3.9/site-packages/certifi/core.py deleted file mode 100644 index 1c9661c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/certifi/core.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -certifi.py -~~~~~~~~~~ - -This module returns the installation location of cacert.pem or its contents. -""" -import sys -import atexit - -def exit_cacert_ctx() -> None: - _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] - - -if sys.version_info >= (3, 11): - - from importlib.resources import as_file, files - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") - -else: - - from importlib.resources import path as get_path, read_text - - _CACERT_CTX = None - _CACERT_PATH = None - - def where() -> str: - # This is slightly terrible, but we want to delay extracting the - # file in cases where we're inside of a zipimport situation until - # someone actually calls where(), but we don't want to re-extract - # the file on every call of where(), so we'll do it once then store - # it in a global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you - # to manage the cleanup of this file, so it doesn't actually - # return a path, it returns a context manager that will give - # you the path when you enter it and will do any cleanup when - # you leave it. In the common case of not needing a temporary - # file, it will just return the file system location and the - # __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - atexit.register(exit_cacert_ctx) - - return _CACERT_PATH - - def contents() -> str: - return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/backend/venv39/lib/python3.9/site-packages/certifi/py.typed b/backend/venv39/lib/python3.9/site-packages/certifi/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA deleted file mode 100644 index 67508e5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/METADATA +++ /dev/null @@ -1,68 +0,0 @@ -Metadata-Version: 2.4 -Name: cffi -Version: 2.0.0 -Summary: Foreign Function Interface for Python calling C code. -Author: Armin Rigo, Maciej Fijalkowski -Maintainer: Matt Davis, Matt Clay, Matti Picus -License-Expression: MIT -Project-URL: Documentation, https://cffi.readthedocs.io/ -Project-URL: Changelog, https://cffi.readthedocs.io/en/latest/whatsnew.html -Project-URL: Downloads, https://github.com/python-cffi/cffi/releases -Project-URL: Contact, https://groups.google.com/forum/#!forum/python-cffi -Project-URL: Source Code, https://github.com/python-cffi/cffi -Project-URL: Issue Tracker, https://github.com/python-cffi/cffi/issues -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta -Classifier: Programming Language :: Python :: Implementation :: CPython -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-File: LICENSE -License-File: AUTHORS -Requires-Dist: pycparser; implementation_name != "PyPy" -Dynamic: license-file - -[![GitHub Actions Status](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml?query=branch%3Amain++) -[![PyPI version](https://img.shields.io/pypi/v/cffi.svg)](https://pypi.org/project/cffi) -[![Read the Docs](https://img.shields.io/badge/docs-latest-blue.svg)][Documentation] - - -CFFI -==== - -Foreign Function Interface for Python calling C code. - -Please see the [Documentation] or uncompiled in the `doc/` subdirectory. - -Download --------- - -[Download page](https://github.com/python-cffi/cffi/releases) - -Source Code ------------ - -Source code is publicly available on -[GitHub](https://github.com/python-cffi/cffi). - -Contact -------- - -[Mailing list](https://groups.google.com/forum/#!forum/python-cffi) - -Testing/development tips ------------------------- - -After `git clone` or `wget && tar`, we will get a directory called `cffi` or `cffi-x.x.x`. we call it `repo-directory`. To run tests under CPython, run the following in the `repo-directory`: - - pip install pytest - pip install -e . # editable install of CFFI for local development - pytest src/c/ testing/ - -[Documentation]: http://cffi.readthedocs.org/ diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD deleted file mode 100644 index 0514f3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/RECORD +++ /dev/null @@ -1,49 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/_imp_emulation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/backend_ctypes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/cffi_opcode.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/commontypes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/cparser.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/ffiplatform.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/lock.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/pkgconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/recompiler.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/setuptools_ext.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/vengine_cpy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/vengine_gen.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cffi/verifier.cpython-39.pyc,, -_cffi_backend.cpython-39-darwin.so,sha256=xqQLrJ-1MlI3_i7LqFutf5qA9sc9WnnkbiqdkohJV7A,212816 -cffi-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cffi-2.0.0.dist-info/METADATA,sha256=uYzn40F68Im8EtXHNBLZs7FoPM-OxzyYbDWsjJvhujk,2559 -cffi-2.0.0.dist-info/RECORD,, -cffi-2.0.0.dist-info/WHEEL,sha256=bDWaFWigpG5bEpqw9IoRiyYs8MvmSFh0OhUAOoi_-KA,134 -cffi-2.0.0.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 -cffi-2.0.0.dist-info/licenses/AUTHORS,sha256=KmemC7-zN1nWfWRf8TG45ta8TK_CMtdR_Kw-2k0xTMg,208 -cffi-2.0.0.dist-info/licenses/LICENSE,sha256=W6JN3FcGf5JJrdZEw6_EGl1tw34jQz73Wdld83Cwr2M,1123 -cffi-2.0.0.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 -cffi/__init__.py,sha256=-ksBQ7MfDzVvbBlV_ftYBWAmEqfA86ljIzMxzaZeAlI,511 -cffi/_cffi_errors.h,sha256=zQXt7uR_m8gUW-fI2hJg0KoSkJFwXv8RGUkEDZ177dQ,3908 -cffi/_cffi_include.h,sha256=Exhmgm9qzHWzWivjfTe0D7Xp4rPUkVxdNuwGhMTMzbw,15055 -cffi/_embedding.h,sha256=Ai33FHblE7XSpHOCp8kPcWwN5_9BV14OvN0JVa6ITpw,18786 -cffi/_imp_emulation.py,sha256=RxREG8zAbI2RPGBww90u_5fi8sWdahpdipOoPzkp7C0,2960 -cffi/_shimmed_dist_utils.py,sha256=Bjj2wm8yZbvFvWEx5AEfmqaqZyZFhYfoyLLQHkXZuao,2230 -cffi/api.py,sha256=alBv6hZQkjpmZplBphdaRn2lPO9-CORs_M7ixabvZWI,42169 -cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454 -cffi/cffi_opcode.py,sha256=JDV5l0R0_OadBX_uE7xPPTYtMdmpp8I9UYd6av7aiDU,5731 -cffi/commontypes.py,sha256=7N6zPtCFlvxXMWhHV08psUjdYIK2XgsN3yo5dgua_v4,2805 -cffi/cparser.py,sha256=QUTfmlL-aO-MYR8bFGlvAUHc36OQr7XYLe0WLkGFjRo,44790 -cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 -cffi/ffiplatform.py,sha256=avxFjdikYGJoEtmJO7ewVmwG_VEVl6EZ_WaNhZYCqv4,3584 -cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 -cffi/model.py,sha256=W30UFQZE73jL5Mx5N81YT77us2W2iJjTm0XYfnwz1cg,21797 -cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 -cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374 -cffi/recompiler.py,sha256=78J6lMEEOygXNmjN9-fOFFO3j7eW-iFxSrxfvQb54bY,65509 -cffi/setuptools_ext.py,sha256=0rCwBJ1W7FHWtiMKfNXsSST88V8UXrui5oeXFlDNLG8,9411 -cffi/vengine_cpy.py,sha256=oyQKD23kpE0aChUKA8Jg0e723foPiYzLYEdb-J0MiNs,43881 -cffi/vengine_gen.py,sha256=DUlEIrDiVin1Pnhn1sfoamnS5NLqfJcOdhRoeSNeJRg,26939 -cffi/verifier.py,sha256=oX8jpaohg2Qm3aHcznidAdvrVm5N4sQYG0a3Eo5mIl4,11182 diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL deleted file mode 100644 index d7eb6c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_11_0_arm64 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt deleted file mode 100644 index 4b0274f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[distutils.setup_keywords] -cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS deleted file mode 100644 index 370a25d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -This package has been mostly done by Armin Rigo with help from -Maciej Fijałkowski. The idea is heavily based (although not directly -copied) from LuaJIT ffi by Mike Pall. - - -Other contributors: - - Google Inc. diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE deleted file mode 100644 index 0a1dbfb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ - -Except when otherwise stated (look for LICENSE files in directories or -information at the beginning of each file) all software and -documentation is licensed as follows: - - MIT No Attribution - - 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. - - 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. - diff --git a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt deleted file mode 100644 index f645779..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi-2.0.0.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -_cffi_backend -cffi diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/__init__.py b/backend/venv39/lib/python3.9/site-packages/cffi/__init__.py deleted file mode 100644 index c99ec3d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', - 'FFIError'] - -from .api import FFI -from .error import CDefError, FFIError, VerificationError, VerificationMissing -from .error import PkgConfigError - -__version__ = "2.0.0" -__version_info__ = (2, 0, 0) - -# The verifier module file names are based on the CRC32 of a string that -# contains the following version number. It may be older than __version__ -# if nothing is clearly incompatible. -__version_verifier_modules__ = "0.8.6" diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_errors.h b/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_errors.h deleted file mode 100644 index 158e059..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_errors.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef CFFI_MESSAGEBOX -# ifdef _MSC_VER -# define CFFI_MESSAGEBOX 1 -# else -# define CFFI_MESSAGEBOX 0 -# endif -#endif - - -#if CFFI_MESSAGEBOX -/* Windows only: logic to take the Python-CFFI embedding logic - initialization errors and display them in a background thread - with MessageBox. The idea is that if the whole program closes - as a result of this problem, then likely it is already a console - program and you can read the stderr output in the console too. - If it is not a console program, then it will likely show its own - dialog to complain, or generally not abruptly close, and for this - case the background thread should stay alive. -*/ -static void *volatile _cffi_bootstrap_text; - -static PyObject *_cffi_start_error_capture(void) -{ - PyObject *result = NULL; - PyObject *x, *m, *bi; - - if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, - (void *)1, NULL) != NULL) - return (PyObject *)1; - - m = PyImport_AddModule("_cffi_error_capture"); - if (m == NULL) - goto error; - - result = PyModule_GetDict(m); - if (result == NULL) - goto error; - -#if PY_MAJOR_VERSION >= 3 - bi = PyImport_ImportModule("builtins"); -#else - bi = PyImport_ImportModule("__builtin__"); -#endif - if (bi == NULL) - goto error; - PyDict_SetItemString(result, "__builtins__", bi); - Py_DECREF(bi); - - x = PyRun_String( - "import sys\n" - "class FileLike:\n" - " def write(self, x):\n" - " try:\n" - " of.write(x)\n" - " except: pass\n" - " self.buf += x\n" - " def flush(self):\n" - " pass\n" - "fl = FileLike()\n" - "fl.buf = ''\n" - "of = sys.stderr\n" - "sys.stderr = fl\n" - "def done():\n" - " sys.stderr = of\n" - " return fl.buf\n", /* make sure the returned value stays alive */ - Py_file_input, - result, result); - Py_XDECREF(x); - - error: - if (PyErr_Occurred()) - { - PyErr_WriteUnraisable(Py_None); - PyErr_Clear(); - } - return result; -} - -#pragma comment(lib, "user32.lib") - -static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) -{ - Sleep(666); /* may be interrupted if the whole process is closing */ -#if PY_MAJOR_VERSION >= 3 - MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, - L"Python-CFFI error", - MB_OK | MB_ICONERROR); -#else - MessageBoxA(NULL, (char *)_cffi_bootstrap_text, - "Python-CFFI error", - MB_OK | MB_ICONERROR); -#endif - _cffi_bootstrap_text = NULL; - return 0; -} - -static void _cffi_stop_error_capture(PyObject *ecap) -{ - PyObject *s; - void *text; - - if (ecap == (PyObject *)1) - return; - - if (ecap == NULL) - goto error; - - s = PyRun_String("done()", Py_eval_input, ecap, ecap); - if (s == NULL) - goto error; - - /* Show a dialog box, but in a background thread, and - never show multiple dialog boxes at once. */ -#if PY_MAJOR_VERSION >= 3 - text = PyUnicode_AsWideCharString(s, NULL); -#else - text = PyString_AsString(s); -#endif - - _cffi_bootstrap_text = text; - - if (text != NULL) - { - HANDLE h; - h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, - NULL, 0, NULL); - if (h != NULL) - CloseHandle(h); - } - /* decref the string, but it should stay alive as 'fl.buf' - in the small module above. It will really be freed only if - we later get another similar error. So it's a leak of at - most one copy of the small module. That's fine for this - situation which is usually a "fatal error" anyway. */ - Py_DECREF(s); - PyErr_Clear(); - return; - - error: - _cffi_bootstrap_text = NULL; - PyErr_Clear(); -} - -#else - -static PyObject *_cffi_start_error_capture(void) { return NULL; } -static void _cffi_stop_error_capture(PyObject *ecap) { } - -#endif diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_include.h b/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_include.h deleted file mode 100644 index 908a1d7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/_cffi_include.h +++ /dev/null @@ -1,389 +0,0 @@ -#define _CFFI_ - -/* We try to define Py_LIMITED_API before including Python.h. - - Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and - Py_REF_DEBUG are not defined. This is a best-effort approximation: - we can learn about Py_DEBUG from pyconfig.h, but it is unclear if - the same works for the other two macros. Py_DEBUG implies them, - but not the other way around. - - The implementation is messy (issue #350): on Windows, with _MSC_VER, - we have to define Py_LIMITED_API even before including pyconfig.h. - In that case, we guess what pyconfig.h will do to the macros above, - and check our guess after the #include. - - Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv - version >= 16.0.0. With older versions of either, you don't get a - copy of PYTHON3.DLL in the virtualenv. We can't check the version of - CPython *before* we even include pyconfig.h. ffi.set_source() puts - a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is - running on Windows < 3.5, as an attempt at fixing it, but that's - arguably wrong because it may not be the target version of Python. - Still better than nothing I guess. As another workaround, you can - remove the definition of Py_LIMITED_API here. - - See also 'py_limited_api' in cffi/setuptools_ext.py. -*/ -#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) -# ifdef _MSC_VER -# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API -# endif -# include - /* sanity-check: Py_LIMITED_API will cause crashes if any of these - are also defined. Normally, the Python file PC/pyconfig.h does not - cause any of these to be defined, with the exception that _DEBUG - causes Py_DEBUG. Double-check that. */ -# ifdef Py_LIMITED_API -# if defined(Py_DEBUG) -# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" -# endif -# if defined(Py_TRACE_REFS) -# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" -# endif -# if defined(Py_REF_DEBUG) -# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" -# endif -# endif -# else -# include -# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API -# endif -# endif -#endif - -#include -#ifdef __cplusplus -extern "C" { -#endif -#include -#include "parse_c_type.h" - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif - -#ifdef __GNUC__ -# define _CFFI_UNUSED_FN __attribute__((unused)) -#else -# define _CFFI_UNUSED_FN /* nothing */ -#endif - -#ifdef __cplusplus -# ifndef _Bool - typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ -# endif -#endif - -/********** CPython-specific section **********/ -#ifndef PYPY_VERSION - - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -#endif - -#define _cffi_from_c_double PyFloat_FromDouble -#define _cffi_from_c_float PyFloat_FromDouble -#define _cffi_from_c_long PyInt_FromLong -#define _cffi_from_c_ulong PyLong_FromUnsignedLong -#define _cffi_from_c_longlong PyLong_FromLongLong -#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong -#define _cffi_from_c__Bool PyBool_FromLong - -#define _cffi_to_c_double PyFloat_AsDouble -#define _cffi_to_c_float PyFloat_AsDouble - -#define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - sizeof(type) == sizeof(long) ? \ - PyLong_FromUnsignedLong((unsigned long)x) : \ - PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ - (sizeof(type) <= sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - PyLong_FromLongLong((long long)x))) - -#define _cffi_to_c_int(o, type) \ - ((type)( \ - sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ - : (type)_cffi_to_c_i8(o)) : \ - sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ - : (type)_cffi_to_c_i16(o)) : \ - sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ - : (type)_cffi_to_c_i32(o)) : \ - sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ - : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), (type)0))) - -#define _cffi_to_c_i8 \ - ((int(*)(PyObject *))_cffi_exports[1]) -#define _cffi_to_c_u8 \ - ((int(*)(PyObject *))_cffi_exports[2]) -#define _cffi_to_c_i16 \ - ((int(*)(PyObject *))_cffi_exports[3]) -#define _cffi_to_c_u16 \ - ((int(*)(PyObject *))_cffi_exports[4]) -#define _cffi_to_c_i32 \ - ((int(*)(PyObject *))_cffi_exports[5]) -#define _cffi_to_c_u32 \ - ((unsigned int(*)(PyObject *))_cffi_exports[6]) -#define _cffi_to_c_i64 \ - ((long long(*)(PyObject *))_cffi_exports[7]) -#define _cffi_to_c_u64 \ - ((unsigned long long(*)(PyObject *))_cffi_exports[8]) -#define _cffi_to_c_char \ - ((int(*)(PyObject *))_cffi_exports[9]) -#define _cffi_from_c_pointer \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) -#define _cffi_to_c_pointer \ - ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) -#define _cffi_get_struct_layout \ - not used any more -#define _cffi_restore_errno \ - ((void(*)(void))_cffi_exports[13]) -#define _cffi_save_errno \ - ((void(*)(void))_cffi_exports[14]) -#define _cffi_from_c_char \ - ((PyObject *(*)(char))_cffi_exports[15]) -#define _cffi_from_c_deref \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) -#define _cffi_to_c \ - ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) -#define _cffi_from_c_struct \ - ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) -#define _cffi_to_c_wchar_t \ - ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) -#define _cffi_from_c_wchar_t \ - ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) -#define _cffi_to_c_long_double \ - ((long double(*)(PyObject *))_cffi_exports[21]) -#define _cffi_to_c__Bool \ - ((_Bool(*)(PyObject *))_cffi_exports[22]) -#define _cffi_prepare_pointer_call_argument \ - ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ - PyObject *, char **))_cffi_exports[23]) -#define _cffi_convert_array_from_object \ - ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) -#define _CFFI_CPIDX 25 -#define _cffi_call_python \ - ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) -#define _cffi_to_c_wchar3216_t \ - ((int(*)(PyObject *))_cffi_exports[26]) -#define _cffi_from_c_wchar3216_t \ - ((PyObject *(*)(int))_cffi_exports[27]) -#define _CFFI_NUM_EXPORTS 28 - -struct _cffi_ctypedescr; - -static void *_cffi_exports[_CFFI_NUM_EXPORTS]; - -#define _cffi_type(index) ( \ - assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ - (struct _cffi_ctypedescr *)_cffi_types[index]) - -static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, - const struct _cffi_type_context_s *ctx) -{ - PyObject *module, *o_arg, *new_module; - void *raw[] = { - (void *)module_name, - (void *)version, - (void *)_cffi_exports, - (void *)ctx, - }; - - module = PyImport_ImportModule("_cffi_backend"); - if (module == NULL) - goto failure; - - o_arg = PyLong_FromVoidPtr((void *)raw); - if (o_arg == NULL) - goto failure; - - new_module = PyObject_CallMethod( - module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); - - Py_DECREF(o_arg); - Py_DECREF(module); - return new_module; - - failure: - Py_XDECREF(module); - return NULL; -} - - -#ifdef HAVE_WCHAR_H -typedef wchar_t _cffi_wchar_t; -#else -typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ -#endif - -_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) -{ - if (sizeof(_cffi_wchar_t) == 2) - return (uint16_t)_cffi_to_c_wchar_t(o); - else - return (uint16_t)_cffi_to_c_wchar3216_t(o); -} - -_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) -{ - if (sizeof(_cffi_wchar_t) == 2) - return _cffi_from_c_wchar_t((_cffi_wchar_t)x); - else - return _cffi_from_c_wchar3216_t((int)x); -} - -_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) -{ - if (sizeof(_cffi_wchar_t) == 4) - return (int)_cffi_to_c_wchar_t(o); - else - return (int)_cffi_to_c_wchar3216_t(o); -} - -_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) -{ - if (sizeof(_cffi_wchar_t) == 4) - return _cffi_from_c_wchar_t((_cffi_wchar_t)x); - else - return _cffi_from_c_wchar3216_t((int)x); -} - -union _cffi_union_alignment_u { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; - long double m_longdouble; -}; - -struct _cffi_freeme_s { - struct _cffi_freeme_s *next; - union _cffi_union_alignment_u alignment; -}; - -_CFFI_UNUSED_FN static int -_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, - char **output_data, Py_ssize_t datasize, - struct _cffi_freeme_s **freeme) -{ - char *p; - if (datasize < 0) - return -1; - - p = *output_data; - if (p == NULL) { - struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( - offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); - if (fp == NULL) - return -1; - fp->next = *freeme; - *freeme = fp; - p = *output_data = (char *)&fp->alignment; - } - memset((void *)p, 0, (size_t)datasize); - return _cffi_convert_array_from_object(p, ctptr, arg); -} - -_CFFI_UNUSED_FN static void -_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) -{ - do { - void *p = (void *)freeme; - freeme = freeme->next; - PyObject_Free(p); - } while (freeme != NULL); -} - -/********** end CPython-specific section **********/ -#else -_CFFI_UNUSED_FN -static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); -# define _cffi_call_python _cffi_call_python_org -#endif - - -#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) - -#define _cffi_prim_int(size, sign) \ - ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ - (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ - (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ - (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ - _CFFI__UNKNOWN_PRIM) - -#define _cffi_prim_float(size) \ - ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ - (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ - (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ - _CFFI__UNKNOWN_FLOAT_PRIM) - -#define _cffi_check_int(got, got_nonpos, expected) \ - ((got_nonpos) == (expected <= 0) && \ - (got) == (unsigned long long)expected) - -#ifdef MS_WIN32 -# define _cffi_stdcall __stdcall -#else -# define _cffi_stdcall /* nothing */ -#endif - -#ifdef __cplusplus -} -#endif diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/_embedding.h b/backend/venv39/lib/python3.9/site-packages/cffi/_embedding.h deleted file mode 100644 index 64c04f6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/_embedding.h +++ /dev/null @@ -1,550 +0,0 @@ - -/***** Support code for embedding *****/ - -#ifdef __cplusplus -extern "C" { -#endif - - -#if defined(_WIN32) -# define CFFI_DLLEXPORT __declspec(dllexport) -#elif defined(__GNUC__) -# define CFFI_DLLEXPORT __attribute__((visibility("default"))) -#else -# define CFFI_DLLEXPORT /* nothing */ -#endif - - -/* There are two global variables of type _cffi_call_python_fnptr: - - * _cffi_call_python, which we declare just below, is the one called - by ``extern "Python"`` implementations. - - * _cffi_call_python_org, which on CPython is actually part of the - _cffi_exports[] array, is the function pointer copied from - _cffi_backend. If _cffi_start_python() fails, then this is set - to NULL; otherwise, it should never be NULL. - - After initialization is complete, both are equal. However, the - first one remains equal to &_cffi_start_and_call_python until the - very end of initialization, when we are (or should be) sure that - concurrent threads also see a completely initialized world, and - only then is it changed. -*/ -#undef _cffi_call_python -typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); -static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); -static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; - - -#ifndef _MSC_VER - /* --- Assuming a GCC not infinitely old --- */ -# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) -# define cffi_write_barrier() __sync_synchronize() -# if !defined(__amd64__) && !defined(__x86_64__) && \ - !defined(__i386__) && !defined(__i386) -# define cffi_read_barrier() __sync_synchronize() -# else -# define cffi_read_barrier() (void)0 -# endif -#else - /* --- Windows threads version --- */ -# include -# define cffi_compare_and_swap(l,o,n) \ - (InterlockedCompareExchangePointer(l,n,o) == (o)) -# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) -# define cffi_read_barrier() (void)0 -static volatile LONG _cffi_dummy; -#endif - -#ifdef WITH_THREAD -# ifndef _MSC_VER -# include - static pthread_mutex_t _cffi_embed_startup_lock; -# else - static CRITICAL_SECTION _cffi_embed_startup_lock; -# endif - static char _cffi_embed_startup_lock_ready = 0; -#endif - -static void _cffi_acquire_reentrant_mutex(void) -{ - static void *volatile lock = NULL; - - while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: pthread_mutex_init() should be very fast, and - this is only run at start-up anyway. */ - } - -#ifdef WITH_THREAD - if (!_cffi_embed_startup_lock_ready) { -# ifndef _MSC_VER - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&_cffi_embed_startup_lock, &attr); -# else - InitializeCriticalSection(&_cffi_embed_startup_lock); -# endif - _cffi_embed_startup_lock_ready = 1; - } -#endif - - while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) - ; - -#ifndef _MSC_VER - pthread_mutex_lock(&_cffi_embed_startup_lock); -#else - EnterCriticalSection(&_cffi_embed_startup_lock); -#endif -} - -static void _cffi_release_reentrant_mutex(void) -{ -#ifndef _MSC_VER - pthread_mutex_unlock(&_cffi_embed_startup_lock); -#else - LeaveCriticalSection(&_cffi_embed_startup_lock); -#endif -} - - -/********** CPython-specific section **********/ -#ifndef PYPY_VERSION - -#include "_cffi_errors.h" - - -#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] - -PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ - -static void _cffi_py_initialize(void) -{ - /* XXX use initsigs=0, which "skips initialization registration of - signal handlers, which might be useful when Python is - embedded" according to the Python docs. But review and think - if it should be a user-controllable setting. - - XXX we should also give a way to write errors to a buffer - instead of to stderr. - - XXX if importing 'site' fails, CPython (any version) calls - exit(). Should we try to work around this behavior here? - */ - Py_InitializeEx(0); -} - -static int _cffi_initialize_python(void) -{ - /* This initializes Python, imports _cffi_backend, and then the - present .dll/.so is set up as a CPython C extension module. - */ - int result; - PyGILState_STATE state; - PyObject *pycode=NULL, *global_dict=NULL, *x; - PyObject *builtins; - - state = PyGILState_Ensure(); - - /* Call the initxxx() function from the present module. It will - create and initialize us as a CPython extension module, instead - of letting the startup Python code do it---it might reimport - the same .dll/.so and get maybe confused on some platforms. - It might also have troubles locating the .dll/.so again for all - I know. - */ - (void)_CFFI_PYTHON_STARTUP_FUNC(); - if (PyErr_Occurred()) - goto error; - - /* Now run the Python code provided to ffi.embedding_init_code(). - */ - pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, - "", - Py_file_input); - if (pycode == NULL) - goto error; - global_dict = PyDict_New(); - if (global_dict == NULL) - goto error; - builtins = PyEval_GetBuiltins(); - if (builtins == NULL) - goto error; - if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) - goto error; - x = PyEval_EvalCode( -#if PY_MAJOR_VERSION < 3 - (PyCodeObject *) -#endif - pycode, global_dict, global_dict); - if (x == NULL) - goto error; - Py_DECREF(x); - - /* Done! Now if we've been called from - _cffi_start_and_call_python() in an ``extern "Python"``, we can - only hope that the Python code did correctly set up the - corresponding @ffi.def_extern() function. Otherwise, the - general logic of ``extern "Python"`` functions (inside the - _cffi_backend module) will find that the reference is still - missing and print an error. - */ - result = 0; - done: - Py_XDECREF(pycode); - Py_XDECREF(global_dict); - PyGILState_Release(state); - return result; - - error:; - { - /* Print as much information as potentially useful. - Debugging load-time failures with embedding is not fun - */ - PyObject *ecap; - PyObject *exception, *v, *tb, *f, *modules, *mod; - PyErr_Fetch(&exception, &v, &tb); - ecap = _cffi_start_error_capture(); - f = PySys_GetObject((char *)"stderr"); - if (f != NULL && f != Py_None) { - PyFile_WriteString( - "Failed to initialize the Python-CFFI embedding logic:\n\n", f); - } - - if (exception != NULL) { - PyErr_NormalizeException(&exception, &v, &tb); - PyErr_Display(exception, v, tb); - } - Py_XDECREF(exception); - Py_XDECREF(v); - Py_XDECREF(tb); - - if (f != NULL && f != Py_None) { - PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 2.0.0" - "\n_cffi_backend module: ", f); - modules = PyImport_GetModuleDict(); - mod = PyDict_GetItemString(modules, "_cffi_backend"); - if (mod == NULL) { - PyFile_WriteString("not loaded", f); - } - else { - v = PyObject_GetAttrString(mod, "__file__"); - PyFile_WriteObject(v, f, 0); - Py_XDECREF(v); - } - PyFile_WriteString("\nsys.path: ", f); - PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); - PyFile_WriteString("\n\n", f); - } - _cffi_stop_error_capture(ecap); - } - result = -1; - goto done; -} - -#if PY_VERSION_HEX < 0x03080000 -PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ -#endif - -static int _cffi_carefully_make_gil(void) -{ - /* This does the basic initialization of Python. It can be called - completely concurrently from unrelated threads. It assumes - that we don't hold the GIL before (if it exists), and we don't - hold it afterwards. - - (What it really does used to be completely different in Python 2 - and Python 3, with the Python 2 solution avoiding the spin-lock - around the Py_InitializeEx() call. However, after recent changes - to CPython 2.7 (issue #358) it no longer works. So we use the - Python 3 solution everywhere.) - - This initializes Python by calling Py_InitializeEx(). - Important: this must not be called concurrently at all. - So we use a global variable as a simple spin lock. This global - variable must be from 'libpythonX.Y.so', not from this - cffi-based extension module, because it must be shared from - different cffi-based extension modules. - - In Python < 3.8, we choose - _PyParser_TokenNames[0] as a completely arbitrary pointer value - that is never written to. The default is to point to the - string "ENDMARKER". We change it temporarily to point to the - next character in that string. (Yes, I know it's REALLY - obscure.) - - In Python >= 3.8, this string array is no longer writable, so - instead we pick PyCapsuleType.tp_version_tag. We can't change - Python < 3.8 because someone might use a mixture of cffi - embedded modules, some of which were compiled before this file - changed. - - In Python >= 3.12, this stopped working because that particular - tp_version_tag gets modified during interpreter startup. It's - arguably a bad idea before 3.12 too, but again we can't change - that because someone might use a mixture of cffi embedded - modules, and no-one reported a bug so far. In Python >= 3.12 - we go instead for PyCapsuleType.tp_as_buffer, which is supposed - to always be NULL. We write to it temporarily a pointer to - a struct full of NULLs, which is semantically the same. - */ - -#ifdef WITH_THREAD -# if PY_VERSION_HEX < 0x03080000 - char *volatile *lock = (char *volatile *)_PyParser_TokenNames; - char *old_value, *locked_value; - - while (1) { /* spin loop */ - old_value = *lock; - locked_value = old_value + 1; - if (old_value[0] == 'E') { - assert(old_value[1] == 'N'); - if (cffi_compare_and_swap(lock, old_value, locked_value)) - break; - } - else { - assert(old_value[0] == 'N'); - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: PyEval_InitThreads() should be very fast, and - this is only run at start-up anyway. */ - } - } -# else -# if PY_VERSION_HEX < 0x030C0000 - int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; - int old_value, locked_value = -42; - assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); -# else - static struct ebp_s { PyBufferProcs buf; int mark; } empty_buffer_procs; - empty_buffer_procs.mark = -42; - PyBufferProcs *volatile *lock = (PyBufferProcs *volatile *) - &PyCapsule_Type.tp_as_buffer; - PyBufferProcs *old_value, *locked_value = &empty_buffer_procs.buf; -# endif - - while (1) { /* spin loop */ - old_value = *lock; - if (old_value == 0) { - if (cffi_compare_and_swap(lock, old_value, locked_value)) - break; - } - else { -# if PY_VERSION_HEX < 0x030C0000 - assert(old_value == locked_value); -# else - /* The pointer should point to a possibly different - empty_buffer_procs from another C extension module */ - assert(((struct ebp_s *)old_value)->mark == -42); -# endif - /* should ideally do a spin loop instruction here, but - hard to do it portably and doesn't really matter I - think: PyEval_InitThreads() should be very fast, and - this is only run at start-up anyway. */ - } - } -# endif -#endif - - /* call Py_InitializeEx() */ - if (!Py_IsInitialized()) { - _cffi_py_initialize(); -#if PY_VERSION_HEX < 0x03070000 - PyEval_InitThreads(); -#endif - PyEval_SaveThread(); /* release the GIL */ - /* the returned tstate must be the one that has been stored into the - autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ - } - else { -#if PY_VERSION_HEX < 0x03070000 - /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ - PyGILState_STATE state = PyGILState_Ensure(); - PyEval_InitThreads(); - PyGILState_Release(state); -#endif - } - -#ifdef WITH_THREAD - /* release the lock */ - while (!cffi_compare_and_swap(lock, locked_value, old_value)) - ; -#endif - - return 0; -} - -/********** end CPython-specific section **********/ - - -#else - - -/********** PyPy-specific section **********/ - -PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ - -static struct _cffi_pypy_init_s { - const char *name; - void *func; /* function pointer */ - const char *code; -} _cffi_pypy_init = { - _CFFI_MODULE_NAME, - _CFFI_PYTHON_STARTUP_FUNC, - _CFFI_PYTHON_STARTUP_CODE, -}; - -extern int pypy_carefully_make_gil(const char *); -extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); - -static int _cffi_carefully_make_gil(void) -{ - return pypy_carefully_make_gil(_CFFI_MODULE_NAME); -} - -static int _cffi_initialize_python(void) -{ - return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); -} - -/********** end PyPy-specific section **********/ - - -#endif - - -#ifdef __GNUC__ -__attribute__((noinline)) -#endif -static _cffi_call_python_fnptr _cffi_start_python(void) -{ - /* Delicate logic to initialize Python. This function can be - called multiple times concurrently, e.g. when the process calls - its first ``extern "Python"`` functions in multiple threads at - once. It can also be called recursively, in which case we must - ignore it. We also have to consider what occurs if several - different cffi-based extensions reach this code in parallel - threads---it is a different copy of the code, then, and we - can't have any shared global variable unless it comes from - 'libpythonX.Y.so'. - - Idea: - - * _cffi_carefully_make_gil(): "carefully" call - PyEval_InitThreads() (possibly with Py_InitializeEx() first). - - * then we use a (local) custom lock to make sure that a call to this - cffi-based extension will wait if another call to the *same* - extension is running the initialization in another thread. - It is reentrant, so that a recursive call will not block, but - only one from a different thread. - - * then we grab the GIL and (Python 2) we call Py_InitializeEx(). - At this point, concurrent calls to Py_InitializeEx() are not - possible: we have the GIL. - - * do the rest of the specific initialization, which may - temporarily release the GIL but not the custom lock. - Only release the custom lock when we are done. - */ - static char called = 0; - - if (_cffi_carefully_make_gil() != 0) - return NULL; - - _cffi_acquire_reentrant_mutex(); - - /* Here the GIL exists, but we don't have it. We're only protected - from concurrency by the reentrant mutex. */ - - /* This file only initializes the embedded module once, the first - time this is called, even if there are subinterpreters. */ - if (!called) { - called = 1; /* invoke _cffi_initialize_python() only once, - but don't set '_cffi_call_python' right now, - otherwise concurrent threads won't call - this function at all (we need them to wait) */ - if (_cffi_initialize_python() == 0) { - /* now initialization is finished. Switch to the fast-path. */ - - /* We would like nobody to see the new value of - '_cffi_call_python' without also seeing the rest of the - data initialized. However, this is not possible. But - the new value of '_cffi_call_python' is the function - 'cffi_call_python()' from _cffi_backend. So: */ - cffi_write_barrier(); - /* ^^^ we put a write barrier here, and a corresponding - read barrier at the start of cffi_call_python(). This - ensures that after that read barrier, we see everything - done here before the write barrier. - */ - - assert(_cffi_call_python_org != NULL); - _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; - } - else { - /* initialization failed. Reset this to NULL, even if it was - already set to some other value. Future calls to - _cffi_start_python() are still forced to occur, and will - always return NULL from now on. */ - _cffi_call_python_org = NULL; - } - } - - _cffi_release_reentrant_mutex(); - - return (_cffi_call_python_fnptr)_cffi_call_python_org; -} - -static -void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) -{ - _cffi_call_python_fnptr fnptr; - int current_err = errno; -#ifdef _MSC_VER - int current_lasterr = GetLastError(); -#endif - fnptr = _cffi_start_python(); - if (fnptr == NULL) { - fprintf(stderr, "function %s() called, but initialization code " - "failed. Returning 0.\n", externpy->name); - memset(args, 0, externpy->size_of_result); - } -#ifdef _MSC_VER - SetLastError(current_lasterr); -#endif - errno = current_err; - - if (fnptr != NULL) - fnptr(externpy, args); -} - - -/* The cffi_start_python() function makes sure Python is initialized - and our cffi module is set up. It can be called manually from the - user C code. The same effect is obtained automatically from any - dll-exported ``extern "Python"`` function. This function returns - -1 if initialization failed, 0 if all is OK. */ -_CFFI_UNUSED_FN -static int cffi_start_python(void) -{ - if (_cffi_call_python == &_cffi_start_and_call_python) { - if (_cffi_start_python() == NULL) - return -1; - } - cffi_read_barrier(); - return 0; -} - -#undef cffi_compare_and_swap -#undef cffi_write_barrier -#undef cffi_read_barrier - -#ifdef __cplusplus -} -#endif diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/_imp_emulation.py b/backend/venv39/lib/python3.9/site-packages/cffi/_imp_emulation.py deleted file mode 100644 index 136abdd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/_imp_emulation.py +++ /dev/null @@ -1,83 +0,0 @@ - -try: - # this works on Python < 3.12 - from imp import * - -except ImportError: - # this is a limited emulation for Python >= 3.12. - # Note that this is used only for tests or for the old ffi.verify(). - # This is copied from the source code of Python 3.11. - - from _imp import (acquire_lock, release_lock, - is_builtin, is_frozen) - - from importlib._bootstrap import _load - - from importlib import machinery - import os - import sys - import tokenize - - SEARCH_ERROR = 0 - PY_SOURCE = 1 - PY_COMPILED = 2 - C_EXTENSION = 3 - PY_RESOURCE = 4 - PKG_DIRECTORY = 5 - C_BUILTIN = 6 - PY_FROZEN = 7 - PY_CODERESOURCE = 8 - IMP_HOOK = 9 - - def get_suffixes(): - extensions = [(s, 'rb', C_EXTENSION) - for s in machinery.EXTENSION_SUFFIXES] - source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] - bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES] - return extensions + source + bytecode - - def find_module(name, path=None): - if not isinstance(name, str): - raise TypeError("'name' must be a str, not {}".format(type(name))) - elif not isinstance(path, (type(None), list)): - # Backwards-compatibility - raise RuntimeError("'path' must be None or a list, " - "not {}".format(type(path))) - - if path is None: - if is_builtin(name): - return None, None, ('', '', C_BUILTIN) - elif is_frozen(name): - return None, None, ('', '', PY_FROZEN) - else: - path = sys.path - - for entry in path: - package_directory = os.path.join(entry, name) - for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]: - package_file_name = '__init__' + suffix - file_path = os.path.join(package_directory, package_file_name) - if os.path.isfile(file_path): - return None, package_directory, ('', '', PKG_DIRECTORY) - for suffix, mode, type_ in get_suffixes(): - file_name = name + suffix - file_path = os.path.join(entry, file_name) - if os.path.isfile(file_path): - break - else: - continue - break # Break out of outer loop when breaking out of inner loop. - else: - raise ImportError(name, name=name) - - encoding = None - if 'b' not in mode: - with open(file_path, 'rb') as file: - encoding = tokenize.detect_encoding(file.readline)[0] - file = open(file_path, mode, encoding=encoding) - return file, file_path, (suffix, mode, type_) - - def load_dynamic(name, path, file=None): - loader = machinery.ExtensionFileLoader(name, path) - spec = machinery.ModuleSpec(name=name, loader=loader, origin=path) - return _load(spec) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py b/backend/venv39/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py deleted file mode 100644 index c3d2312..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/_shimmed_dist_utils.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful -error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken. - -This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI. -""" -import sys - -try: - # import setuptools first; this is the most robust way to ensure its embedded distutils is available - # (the .pth shim should usually work, but this is even more robust) - import setuptools -except Exception as ex: - if sys.version_info >= (3, 12): - # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal - raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex - - # silently ignore on older Pythons (support fallback to stdlib distutils where available) -else: - del setuptools - -try: - # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils - from distutils import log, sysconfig - from distutils.ccompiler import CCompiler - from distutils.command.build_ext import build_ext - from distutils.core import Distribution, Extension - from distutils.dir_util import mkpath - from distutils.errors import DistutilsSetupError, CompileError, LinkError - from distutils.log import set_threshold, set_verbosity - - if sys.platform == 'win32': - try: - # FUTURE: msvc9compiler module was removed in setuptools 74; consider removing, as it's only used by an ancient patch in `recompiler` - from distutils.msvc9compiler import MSVCCompiler - except ImportError: - MSVCCompiler = None -except Exception as ex: - if sys.version_info >= (3, 12): - raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex - - # anything older, just let the underlying distutils import error fly - raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex - -del sys diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/api.py b/backend/venv39/lib/python3.9/site-packages/cffi/api.py deleted file mode 100644 index 5a474f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/api.py +++ /dev/null @@ -1,967 +0,0 @@ -import sys, types -from .lock import allocate_lock -from .error import CDefError -from . import model - -try: - callable -except NameError: - # Python 3.1 - from collections import Callable - callable = lambda x: isinstance(x, Callable) - -try: - basestring -except NameError: - # Python 3.x - basestring = str - -_unspecified = object() - - - -class FFI(object): - r''' - The main top-level class that you instantiate once, or once per module. - - Example usage: - - ffi = FFI() - ffi.cdef(""" - int printf(const char *, ...); - """) - - C = ffi.dlopen(None) # standard library - -or- - C = ffi.verify() # use a C compiler: verify the decl above is right - - C.printf("hello, %s!\n", ffi.new("char[]", "world")) - ''' - - def __init__(self, backend=None): - """Create an FFI instance. The 'backend' argument is used to - select a non-default backend, mostly for tests. - """ - if backend is None: - # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with - # _cffi_backend.so compiled. - import _cffi_backend as backend - from . import __version__ - if backend.__version__ != __version__: - # bad version! Try to be as explicit as possible. - if hasattr(backend, '__file__'): - # CPython - raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( - __version__, __file__, - backend.__version__, backend.__file__)) - else: - # PyPy - raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( - __version__, __file__, backend.__version__)) - # (If you insist you can also try to pass the option - # 'backend=backend_ctypes.CTypesBackend()', but don't - # rely on it! It's probably not going to work well.) - - from . import cparser - self._backend = backend - self._lock = allocate_lock() - self._parser = cparser.Parser() - self._cached_btypes = {} - self._parsed_types = types.ModuleType('parsed_types').__dict__ - self._new_types = types.ModuleType('new_types').__dict__ - self._function_caches = [] - self._libraries = [] - self._cdefsources = [] - self._included_ffis = [] - self._windows_unicode = None - self._init_once_cache = {} - self._cdef_version = None - self._embedding = None - self._typecache = model.get_typecache(backend) - if hasattr(backend, 'set_ffi'): - backend.set_ffi(self) - for name in list(backend.__dict__): - if name.startswith('RTLD_'): - setattr(self, name, getattr(backend, name)) - # - with self._lock: - self.BVoidP = self._get_cached_btype(model.voidp_type) - self.BCharA = self._get_cached_btype(model.char_array_type) - if isinstance(backend, types.ModuleType): - # _cffi_backend: attach these constants to the class - if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(self.BVoidP, 0) - FFI.CData, FFI.CType = backend._get_types() - else: - # ctypes backend: attach these constants to the instance - self.NULL = self.cast(self.BVoidP, 0) - self.CData, self.CType = backend._get_types() - self.buffer = backend.buffer - - def cdef(self, csource, override=False, packed=False, pack=None): - """Parse the given C source. This registers all declared functions, - types, and global variables. The functions and global variables can - then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. - The types can be used in 'ffi.new()' and other functions. - If 'packed' is specified as True, all structs declared inside this - cdef are packed, i.e. laid out without any field alignment at all. - Alternatively, 'pack' can be a small integer, and requests for - alignment greater than that are ignored (pack=1 is equivalent to - packed=True). - """ - self._cdef(csource, override=override, packed=packed, pack=pack) - - def embedding_api(self, csource, packed=False, pack=None): - self._cdef(csource, packed=packed, pack=pack, dllexport=True) - if self._embedding is None: - self._embedding = '' - - def _cdef(self, csource, override=False, **options): - if not isinstance(csource, str): # unicode, on Python 2 - if not isinstance(csource, basestring): - raise TypeError("cdef() argument must be a string") - csource = csource.encode('ascii') - with self._lock: - self._cdef_version = object() - self._parser.parse(csource, override=override, **options) - self._cdefsources.append(csource) - if override: - for cache in self._function_caches: - cache.clear() - finishlist = self._parser._recomplete - if finishlist: - self._parser._recomplete = [] - for tp in finishlist: - tp.finish_backend_type(self, finishlist) - - def dlopen(self, name, flags=0): - """Load and return a dynamic library identified by 'name'. - The standard C library can be loaded by passing None. - Note that functions and types declared by 'ffi.cdef()' are not - linked to a particular library, just like C headers; in the - library we only look for the actual (untyped) symbols. - """ - if not (isinstance(name, basestring) or - name is None or - isinstance(name, self.CData)): - raise TypeError("dlopen(name): name must be a file name, None, " - "or an already-opened 'void *' handle") - with self._lock: - lib, function_cache = _make_ffi_library(self, name, flags) - self._function_caches.append(function_cache) - self._libraries.append(lib) - return lib - - def dlclose(self, lib): - """Close a library obtained with ffi.dlopen(). After this call, - access to functions or variables from the library will fail - (possibly with a segmentation fault). - """ - type(lib).__cffi_close__(lib) - - def _typeof_locked(self, cdecl): - # call me with the lock! - key = cdecl - if key in self._parsed_types: - return self._parsed_types[key] - # - if not isinstance(cdecl, str): # unicode, on Python 2 - cdecl = cdecl.encode('ascii') - # - type = self._parser.parse_type(cdecl) - really_a_function_type = type.is_raw_function - if really_a_function_type: - type = type.as_function_pointer() - btype = self._get_cached_btype(type) - result = btype, really_a_function_type - self._parsed_types[key] = result - return result - - def _typeof(self, cdecl, consider_function_as_funcptr=False): - # string -> ctype object - try: - result = self._parsed_types[cdecl] - except KeyError: - with self._lock: - result = self._typeof_locked(cdecl) - # - btype, really_a_function_type = result - if really_a_function_type and not consider_function_as_funcptr: - raise CDefError("the type %r is a function type, not a " - "pointer-to-function type" % (cdecl,)) - return btype - - def typeof(self, cdecl): - """Parse the C type given as a string and return the - corresponding object. - It can also be used on 'cdata' instance to get its C type. - """ - if isinstance(cdecl, basestring): - return self._typeof(cdecl) - if isinstance(cdecl, self.CData): - return self._backend.typeof(cdecl) - if isinstance(cdecl, types.BuiltinFunctionType): - res = _builtin_function_type(cdecl) - if res is not None: - return res - if (isinstance(cdecl, types.FunctionType) - and hasattr(cdecl, '_cffi_base_type')): - with self._lock: - return self._get_cached_btype(cdecl._cffi_base_type) - raise TypeError(type(cdecl)) - - def sizeof(self, cdecl): - """Return the size in bytes of the argument. It can be a - string naming a C type, or a 'cdata' instance. - """ - if isinstance(cdecl, basestring): - BType = self._typeof(cdecl) - return self._backend.sizeof(BType) - else: - return self._backend.sizeof(cdecl) - - def alignof(self, cdecl): - """Return the natural alignment size in bytes of the C type - given as a string. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.alignof(cdecl) - - def offsetof(self, cdecl, *fields_or_indexes): - """Return the offset of the named field inside the given - structure or array, which must be given as a C type name. - You can give several field names in case of nested structures. - You can also give numeric values which correspond to array - items, in case of an array type. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._typeoffsetof(cdecl, *fields_or_indexes)[1] - - def new(self, cdecl, init=None): - """Allocate an instance according to the specified C type and - return a pointer to it. The specified C type must be either a - pointer or an array: ``new('X *')`` allocates an X and returns - a pointer to it, whereas ``new('X[n]')`` allocates an array of - n X'es and returns an array referencing it (which works - mostly like a pointer, like in C). You can also use - ``new('X[]', n)`` to allocate an array of a non-constant - length n. - - The memory is initialized following the rules of declaring a - global variable in C: by default it is zero-initialized, but - an explicit initializer can be given which can be used to - fill all or part of the memory. - - When the returned object goes out of scope, the memory - is freed. In other words the returned object has - ownership of the value of type 'cdecl' that it points to. This - means that the raw data can be used as long as this object is - kept alive, but must not be used for a longer time. Be careful - about that when copying the pointer to the memory somewhere - else, e.g. into another structure. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.newp(cdecl, init) - - def new_allocator(self, alloc=None, free=None, - should_clear_after_alloc=True): - """Return a new allocator, i.e. a function that behaves like ffi.new() - but uses the provided low-level 'alloc' and 'free' functions. - - 'alloc' is called with the size as argument. If it returns NULL, a - MemoryError is raised. 'free' is called with the result of 'alloc' - as argument. Both can be either Python function or directly C - functions. If 'free' is None, then no free function is called. - If both 'alloc' and 'free' are None, the default is used. - - If 'should_clear_after_alloc' is set to False, then the memory - returned by 'alloc' is assumed to be already cleared (or you are - fine with garbage); otherwise CFFI will clear it. - """ - compiled_ffi = self._backend.FFI() - allocator = compiled_ffi.new_allocator(alloc, free, - should_clear_after_alloc) - def allocate(cdecl, init=None): - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return allocator(cdecl, init) - return allocate - - def cast(self, cdecl, source): - """Similar to a C cast: returns an instance of the named C - type initialized with the given 'source'. The source is - casted between integers or pointers of any type. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.cast(cdecl, source) - - def string(self, cdata, maxlen=-1): - """Return a Python string (or unicode string) from the 'cdata'. - If 'cdata' is a pointer or array of characters or bytes, returns - the null-terminated string. The returned string extends until - the first null character, or at most 'maxlen' characters. If - 'cdata' is an array then 'maxlen' defaults to its length. - - If 'cdata' is a pointer or array of wchar_t, returns a unicode - string following the same rules. - - If 'cdata' is a single character or byte or a wchar_t, returns - it as a string or unicode string. - - If 'cdata' is an enum, returns the value of the enumerator as a - string, or 'NUMBER' if the value is out of range. - """ - return self._backend.string(cdata, maxlen) - - def unpack(self, cdata, length): - """Unpack an array of C data of the given length, - returning a Python string/unicode/list. - - If 'cdata' is a pointer to 'char', returns a byte string. - It does not stop at the first null. This is equivalent to: - ffi.buffer(cdata, length)[:] - - If 'cdata' is a pointer to 'wchar_t', returns a unicode string. - 'length' is measured in wchar_t's; it is not the size in bytes. - - If 'cdata' is a pointer to anything else, returns a list of - 'length' items. This is a faster equivalent to: - [cdata[i] for i in range(length)] - """ - return self._backend.unpack(cdata, length) - - #def buffer(self, cdata, size=-1): - # """Return a read-write buffer object that references the raw C data - # pointed to by the given 'cdata'. The 'cdata' must be a pointer or - # an array. Can be passed to functions expecting a buffer, or directly - # manipulated with: - # - # buf[:] get a copy of it in a regular string, or - # buf[idx] as a single character - # buf[:] = ... - # buf[idx] = ... change the content - # """ - # note that 'buffer' is a type, set on this instance by __init__ - - def from_buffer(self, cdecl, python_buffer=_unspecified, - require_writable=False): - """Return a cdata of the given type pointing to the data of the - given Python object, which must support the buffer interface. - Note that this is not meant to be used on the built-in types - str or unicode (you can build 'char[]' arrays explicitly) - but only on objects containing large quantities of raw data - in some other format, like 'array.array' or numpy arrays. - - The first argument is optional and default to 'char[]'. - """ - if python_buffer is _unspecified: - cdecl, python_buffer = self.BCharA, cdecl - elif isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - return self._backend.from_buffer(cdecl, python_buffer, - require_writable) - - def memmove(self, dest, src, n): - """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. - - Like the C function memmove(), the memory areas may overlap; - apart from that it behaves like the C function memcpy(). - - 'src' can be any cdata ptr or array, or any Python buffer object. - 'dest' can be any cdata ptr or array, or a writable Python buffer - object. The size to copy, 'n', is always measured in bytes. - - Unlike other methods, this one supports all Python buffer including - byte strings and bytearrays---but it still does not support - non-contiguous buffers. - """ - return self._backend.memmove(dest, src, n) - - def callback(self, cdecl, python_callable=None, error=None, onerror=None): - """Return a callback object or a decorator making such a - callback object. 'cdecl' must name a C function pointer type. - The callback invokes the specified 'python_callable' (which may - be provided either directly or via a decorator). Important: the - callback object must be manually kept alive for as long as the - callback may be invoked from the C level. - """ - def callback_decorator_wrap(python_callable): - if not callable(python_callable): - raise TypeError("the 'python_callable' argument " - "is not callable") - return self._backend.callback(cdecl, python_callable, - error, onerror) - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) - if python_callable is None: - return callback_decorator_wrap # decorator mode - else: - return callback_decorator_wrap(python_callable) # direct mode - - def getctype(self, cdecl, replace_with=''): - """Return a string giving the C type 'cdecl', which may be itself - a string or a object. If 'replace_with' is given, it gives - extra text to append (or insert for more complicated C types), like - a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. - """ - if isinstance(cdecl, basestring): - cdecl = self._typeof(cdecl) - replace_with = replace_with.strip() - if (replace_with.startswith('*') - and '&[' in self._backend.getcname(cdecl, '&')): - replace_with = '(%s)' % replace_with - elif replace_with and not replace_with[0] in '[(': - replace_with = ' ' + replace_with - return self._backend.getcname(cdecl, replace_with) - - def gc(self, cdata, destructor, size=0): - """Return a new cdata object that points to the same - data. Later, when this new cdata object is garbage-collected, - 'destructor(old_cdata_object)' will be called. - - The optional 'size' gives an estimate of the size, used to - trigger the garbage collection more eagerly. So far only used - on PyPy. It tells the GC that the returned object keeps alive - roughly 'size' bytes of external memory. - """ - return self._backend.gcp(cdata, destructor, size) - - def _get_cached_btype(self, type): - assert self._lock.acquire(False) is False - # call me with the lock! - try: - BType = self._cached_btypes[type] - except KeyError: - finishlist = [] - BType = type.get_cached_btype(self, finishlist) - for type in finishlist: - type.finish_backend_type(self, finishlist) - return BType - - def verify(self, source='', tmpdir=None, **kwargs): - """Verify that the current ffi signatures compile on this - machine, and return a dynamic library object. The dynamic - library can be used to call functions and access global - variables declared in this 'ffi'. The library is compiled - by the C compiler: it gives you C-level API compatibility - (including calling macros). This is unlike 'ffi.dlopen()', - which requires binary compatibility in the signatures. - """ - from .verifier import Verifier, _caller_dir_pycache - # - # If set_unicode(True) was called, insert the UNICODE and - # _UNICODE macro declarations - if self._windows_unicode: - self._apply_windows_unicode(kwargs) - # - # Set the tmpdir here, and not in Verifier.__init__: it picks - # up the caller's directory, which we want to be the caller of - # ffi.verify(), as opposed to the caller of Veritier(). - tmpdir = tmpdir or _caller_dir_pycache() - # - # Make a Verifier() and use it to load the library. - self.verifier = Verifier(self, source, tmpdir, **kwargs) - lib = self.verifier.load_library() - # - # Save the loaded library for keep-alive purposes, even - # if the caller doesn't keep it alive itself (it should). - self._libraries.append(lib) - return lib - - def _get_errno(self): - return self._backend.get_errno() - def _set_errno(self, errno): - self._backend.set_errno(errno) - errno = property(_get_errno, _set_errno, None, - "the value of 'errno' from/to the C calls") - - def getwinerror(self, code=-1): - return self._backend.getwinerror(code) - - def _pointer_to(self, ctype): - with self._lock: - return model.pointer_cache(self, ctype) - - def addressof(self, cdata, *fields_or_indexes): - """Return the address of a . - If 'fields_or_indexes' are given, returns the address of that - field or array item in the structure or array, recursively in - case of nested structures. - """ - try: - ctype = self._backend.typeof(cdata) - except TypeError: - if '__addressof__' in type(cdata).__dict__: - return type(cdata).__addressof__(cdata, *fields_or_indexes) - raise - if fields_or_indexes: - ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) - else: - if ctype.kind == "pointer": - raise TypeError("addressof(pointer)") - offset = 0 - ctypeptr = self._pointer_to(ctype) - return self._backend.rawaddressof(ctypeptr, cdata, offset) - - def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): - ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) - for field1 in fields_or_indexes: - ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) - offset += offset1 - return ctype, offset - - def include(self, ffi_to_include): - """Includes the typedefs, structs, unions and enums defined - in another FFI instance. Usage is similar to a #include in C, - where a part of the program might include types defined in - another part for its own usage. Note that the include() - method has no effect on functions, constants and global - variables, which must anyway be accessed directly from the - lib object returned by the original FFI instance. - """ - if not isinstance(ffi_to_include, FFI): - raise TypeError("ffi.include() expects an argument that is also of" - " type cffi.FFI, not %r" % ( - type(ffi_to_include).__name__,)) - if ffi_to_include is self: - raise ValueError("self.include(self)") - with ffi_to_include._lock: - with self._lock: - self._parser.include(ffi_to_include._parser) - self._cdefsources.append('[') - self._cdefsources.extend(ffi_to_include._cdefsources) - self._cdefsources.append(']') - self._included_ffis.append(ffi_to_include) - - def new_handle(self, x): - return self._backend.newp_handle(self.BVoidP, x) - - def from_handle(self, x): - return self._backend.from_handle(x) - - def release(self, x): - self._backend.release(x) - - def set_unicode(self, enabled_flag): - """Windows: if 'enabled_flag' is True, enable the UNICODE and - _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR - to be (pointers to) wchar_t. If 'enabled_flag' is False, - declare these types to be (pointers to) plain 8-bit characters. - This is mostly for backward compatibility; you usually want True. - """ - if self._windows_unicode is not None: - raise ValueError("set_unicode() can only be called once") - enabled_flag = bool(enabled_flag) - if enabled_flag: - self.cdef("typedef wchar_t TBYTE;" - "typedef wchar_t TCHAR;" - "typedef const wchar_t *LPCTSTR;" - "typedef const wchar_t *PCTSTR;" - "typedef wchar_t *LPTSTR;" - "typedef wchar_t *PTSTR;" - "typedef TBYTE *PTBYTE;" - "typedef TCHAR *PTCHAR;") - else: - self.cdef("typedef char TBYTE;" - "typedef char TCHAR;" - "typedef const char *LPCTSTR;" - "typedef const char *PCTSTR;" - "typedef char *LPTSTR;" - "typedef char *PTSTR;" - "typedef TBYTE *PTBYTE;" - "typedef TCHAR *PTCHAR;") - self._windows_unicode = enabled_flag - - def _apply_windows_unicode(self, kwds): - defmacros = kwds.get('define_macros', ()) - if not isinstance(defmacros, (list, tuple)): - raise TypeError("'define_macros' must be a list or tuple") - defmacros = list(defmacros) + [('UNICODE', '1'), - ('_UNICODE', '1')] - kwds['define_macros'] = defmacros - - def _apply_embedding_fix(self, kwds): - # must include an argument like "-lpython2.7" for the compiler - def ensure(key, value): - lst = kwds.setdefault(key, []) - if value not in lst: - lst.append(value) - # - if '__pypy__' in sys.builtin_module_names: - import os - if sys.platform == "win32": - # we need 'libpypy-c.lib'. Current distributions of - # pypy (>= 4.1) contain it as 'libs/python27.lib'. - pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'libs')) - else: - # we need 'libpypy-c.{so,dylib}', which should be by - # default located in 'sys.prefix/bin' for installed - # systems. - if sys.version_info < (3,): - pythonlib = "pypy-c" - else: - pythonlib = "pypy3-c" - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'bin')) - # On uninstalled pypy's, the libpypy-c is typically found in - # .../pypy/goal/. - if hasattr(sys, 'prefix'): - ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) - else: - if sys.platform == "win32": - template = "python%d%d" - if hasattr(sys, 'gettotalrefcount'): - template += '_d' - else: - try: - import sysconfig - except ImportError: # 2.6 - from cffi._shimmed_dist_utils import sysconfig - template = "python%d.%d" - if sysconfig.get_config_var('DEBUG_EXT'): - template += sysconfig.get_config_var('DEBUG_EXT') - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - if hasattr(sys, 'abiflags'): - pythonlib += sys.abiflags - ensure('libraries', pythonlib) - if sys.platform == "win32": - ensure('extra_link_args', '/MANIFEST') - - def set_source(self, module_name, source, source_extension='.c', **kwds): - import os - if hasattr(self, '_assigned_source'): - raise ValueError("set_source() cannot be called several times " - "per ffi object") - if not isinstance(module_name, basestring): - raise TypeError("'module_name' must be a string") - if os.sep in module_name or (os.altsep and os.altsep in module_name): - raise ValueError("'module_name' must not contain '/': use a dotted " - "name to make a 'package.module' location") - self._assigned_source = (str(module_name), source, - source_extension, kwds) - - def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, - source_extension='.c', **kwds): - from . import pkgconfig - if not isinstance(pkgconfig_libs, list): - raise TypeError("the pkgconfig_libs argument must be a list " - "of package names") - kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) - pkgconfig.merge_flags(kwds, kwds2) - self.set_source(module_name, source, source_extension, **kwds) - - def distutils_extension(self, tmpdir='build', verbose=True): - from cffi._shimmed_dist_utils import mkpath - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored - return self.verifier.get_extension() - raise ValueError("set_source() must be called before" - " distutils_extension()") - module_name, source, source_extension, kwds = self._assigned_source - if source is None: - raise TypeError("distutils_extension() is only for C extension " - "modules, not for dlopen()-style pure Python " - "modules") - mkpath(tmpdir) - ext, updated = recompile(self, module_name, - source, tmpdir=tmpdir, extradir=tmpdir, - source_extension=source_extension, - call_c_compiler=False, **kwds) - if verbose: - if updated: - sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) - else: - sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) - return ext - - def emit_c_code(self, filename): - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before emit_c_code()") - module_name, source, source_extension, kwds = self._assigned_source - if source is None: - raise TypeError("emit_c_code() is only for C extension modules, " - "not for dlopen()-style pure Python modules") - recompile(self, module_name, source, - c_file=filename, call_c_compiler=False, - uses_ffiplatform=False, **kwds) - - def emit_python_code(self, filename): - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before emit_c_code()") - module_name, source, source_extension, kwds = self._assigned_source - if source is not None: - raise TypeError("emit_python_code() is only for dlopen()-style " - "pure Python modules, not for C extension modules") - recompile(self, module_name, source, - c_file=filename, call_c_compiler=False, - uses_ffiplatform=False, **kwds) - - def compile(self, tmpdir='.', verbose=0, target=None, debug=None): - """The 'target' argument gives the final file name of the - compiled DLL. Use '*' to force distutils' choice, suitable for - regular CPython C API modules. Use a file name ending in '.*' - to ask for the system's default extension for dynamic libraries - (.so/.dll/.dylib). - - The default is '*' when building a non-embedded C API extension, - and (module_name + '.*') when building an embedded library. - """ - from .recompiler import recompile - # - if not hasattr(self, '_assigned_source'): - raise ValueError("set_source() must be called before compile()") - module_name, source, source_extension, kwds = self._assigned_source - return recompile(self, module_name, source, tmpdir=tmpdir, - target=target, source_extension=source_extension, - compiler_verbose=verbose, debug=debug, **kwds) - - def init_once(self, func, tag): - # Read _init_once_cache[tag], which is either (False, lock) if - # we're calling the function now in some thread, or (True, result). - # Don't call setdefault() in most cases, to avoid allocating and - # immediately freeing a lock; but still use setdefaut() to avoid - # races. - try: - x = self._init_once_cache[tag] - except KeyError: - x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) - # Common case: we got (True, result), so we return the result. - if x[0]: - return x[1] - # Else, it's a lock. Acquire it to serialize the following tests. - with x[1]: - # Read again from _init_once_cache the current status. - x = self._init_once_cache[tag] - if x[0]: - return x[1] - # Call the function and store the result back. - result = func() - self._init_once_cache[tag] = (True, result) - return result - - def embedding_init_code(self, pysource): - if self._embedding: - raise ValueError("embedding_init_code() can only be called once") - # fix 'pysource' before it gets dumped into the C file: - # - remove empty lines at the beginning, so it starts at "line 1" - # - dedent, if all non-empty lines are indented - # - check for SyntaxErrors - import re - match = re.match(r'\s*\n', pysource) - if match: - pysource = pysource[match.end():] - lines = pysource.splitlines() or [''] - prefix = re.match(r'\s*', lines[0]).group() - for i in range(1, len(lines)): - line = lines[i] - if line.rstrip(): - while not line.startswith(prefix): - prefix = prefix[:-1] - i = len(prefix) - lines = [line[i:]+'\n' for line in lines] - pysource = ''.join(lines) - # - compile(pysource, "cffi_init", "exec") - # - self._embedding = pysource - - def def_extern(self, *args, **kwds): - raise ValueError("ffi.def_extern() is only available on API-mode FFI " - "objects") - - def list_types(self): - """Returns the user type names known to this FFI instance. - This returns a tuple containing three lists of names: - (typedef_names, names_of_structs, names_of_unions) - """ - typedefs = [] - structs = [] - unions = [] - for key in self._parser._declarations: - if key.startswith('typedef '): - typedefs.append(key[8:]) - elif key.startswith('struct '): - structs.append(key[7:]) - elif key.startswith('union '): - unions.append(key[6:]) - typedefs.sort() - structs.sort() - unions.sort() - return (typedefs, structs, unions) - - -def _load_backend_lib(backend, name, flags): - import os - if not isinstance(name, basestring): - if sys.platform != "win32" or name is not None: - return backend.load_library(name, flags) - name = "c" # Windows: load_library(None) fails, but this works - # on Python 2 (backward compatibility hack only) - first_error = None - if '.' in name or '/' in name or os.sep in name: - try: - return backend.load_library(name, flags) - except OSError as e: - first_error = e - import ctypes.util - path = ctypes.util.find_library(name) - if path is None: - if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): - raise OSError("dlopen(None) cannot work on Windows for Python 3 " - "(see http://bugs.python.org/issue23606)") - msg = ("ctypes.util.find_library() did not manage " - "to locate a library called %r" % (name,)) - if first_error is not None: - msg = "%s. Additionally, %s" % (first_error, msg) - raise OSError(msg) - return backend.load_library(path, flags) - -def _make_ffi_library(ffi, libname, flags): - backend = ffi._backend - backendlib = _load_backend_lib(backend, libname, flags) - # - def accessor_function(name): - key = 'function ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - value = backendlib.load_function(BType, name) - library.__dict__[name] = value - # - def accessor_variable(name): - key = 'variable ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - read_variable = backendlib.read_variable - write_variable = backendlib.write_variable - setattr(FFILibrary, name, property( - lambda self: read_variable(BType, name), - lambda self, value: write_variable(BType, name, value))) - # - def addressof_var(name): - try: - return addr_variables[name] - except KeyError: - with ffi._lock: - if name not in addr_variables: - key = 'variable ' + name - tp, _ = ffi._parser._declarations[key] - BType = ffi._get_cached_btype(tp) - if BType.kind != 'array': - BType = model.pointer_cache(ffi, BType) - p = backendlib.load_function(BType, name) - addr_variables[name] = p - return addr_variables[name] - # - def accessor_constant(name): - raise NotImplementedError("non-integer constant '%s' cannot be " - "accessed from a dlopen() library" % (name,)) - # - def accessor_int_constant(name): - library.__dict__[name] = ffi._parser._int_constants[name] - # - accessors = {} - accessors_version = [False] - addr_variables = {} - # - def update_accessors(): - if accessors_version[0] is ffi._cdef_version: - return - # - for key, (tp, _) in ffi._parser._declarations.items(): - if not isinstance(tp, model.EnumType): - tag, name = key.split(' ', 1) - if tag == 'function': - accessors[name] = accessor_function - elif tag == 'variable': - accessors[name] = accessor_variable - elif tag == 'constant': - accessors[name] = accessor_constant - else: - for i, enumname in enumerate(tp.enumerators): - def accessor_enum(name, tp=tp, i=i): - tp.check_not_partial() - library.__dict__[name] = tp.enumvalues[i] - accessors[enumname] = accessor_enum - for name in ffi._parser._int_constants: - accessors.setdefault(name, accessor_int_constant) - accessors_version[0] = ffi._cdef_version - # - def make_accessor(name): - with ffi._lock: - if name in library.__dict__ or name in FFILibrary.__dict__: - return # added by another thread while waiting for the lock - if name not in accessors: - update_accessors() - if name not in accessors: - raise AttributeError(name) - accessors[name](name) - # - class FFILibrary(object): - def __getattr__(self, name): - make_accessor(name) - return getattr(self, name) - def __setattr__(self, name, value): - try: - property = getattr(self.__class__, name) - except AttributeError: - make_accessor(name) - setattr(self, name, value) - else: - property.__set__(self, value) - def __dir__(self): - with ffi._lock: - update_accessors() - return accessors.keys() - def __addressof__(self, name): - if name in library.__dict__: - return library.__dict__[name] - if name in FFILibrary.__dict__: - return addressof_var(name) - make_accessor(name) - if name in library.__dict__: - return library.__dict__[name] - if name in FFILibrary.__dict__: - return addressof_var(name) - raise AttributeError("cffi library has no function or " - "global variable named '%s'" % (name,)) - def __cffi_close__(self): - backendlib.close_lib() - self.__dict__.clear() - # - if isinstance(libname, basestring): - try: - if not isinstance(libname, str): # unicode, on Python 2 - libname = libname.encode('utf-8') - FFILibrary.__name__ = 'FFILibrary_%s' % libname - except UnicodeError: - pass - library = FFILibrary() - return library, library.__dict__ - -def _builtin_function_type(func): - # a hack to make at least ffi.typeof(builtin_function) work, - # if the builtin function was obtained by 'vengine_cpy'. - import sys - try: - module = sys.modules[func.__module__] - ffi = module._cffi_original_ffi - types_of_builtin_funcs = module._cffi_types_of_builtin_funcs - tp = types_of_builtin_funcs[func] - except (KeyError, AttributeError, TypeError): - return None - else: - with ffi._lock: - return ffi._get_cached_btype(tp) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/backend_ctypes.py b/backend/venv39/lib/python3.9/site-packages/cffi/backend_ctypes.py deleted file mode 100644 index e7956a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/backend_ctypes.py +++ /dev/null @@ -1,1121 +0,0 @@ -import ctypes, ctypes.util, operator, sys -from . import model - -if sys.version_info < (3,): - bytechr = chr -else: - unicode = str - long = int - xrange = range - bytechr = lambda num: bytes([num]) - -class CTypesType(type): - pass - -class CTypesData(object): - __metaclass__ = CTypesType - __slots__ = ['__weakref__'] - __name__ = '' - - def __init__(self, *args): - raise TypeError("cannot instantiate %r" % (self.__class__,)) - - @classmethod - def _newp(cls, init): - raise TypeError("expected a pointer or array ctype, got '%s'" - % (cls._get_c_name(),)) - - @staticmethod - def _to_ctypes(value): - raise TypeError - - @classmethod - def _arg_to_ctypes(cls, *value): - try: - ctype = cls._ctype - except AttributeError: - raise TypeError("cannot create an instance of %r" % (cls,)) - if value: - res = cls._to_ctypes(*value) - if not isinstance(res, ctype): - res = cls._ctype(res) - else: - res = cls._ctype() - return res - - @classmethod - def _create_ctype_obj(cls, init): - if init is None: - return cls._arg_to_ctypes() - else: - return cls._arg_to_ctypes(init) - - @staticmethod - def _from_ctypes(ctypes_value): - raise TypeError - - @classmethod - def _get_c_name(cls, replace_with=''): - return cls._reftypename.replace(' &', replace_with) - - @classmethod - def _fix_class(cls): - cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) - cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) - cls.__module__ = 'ffi' - - def _get_own_repr(self): - raise NotImplementedError - - def _addr_repr(self, address): - if address == 0: - return 'NULL' - else: - if address < 0: - address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) - return '0x%x' % address - - def __repr__(self, c_name=None): - own = self._get_own_repr() - return '' % (c_name or self._get_c_name(), own) - - def _convert_to_address(self, BClass): - if BClass is None: - raise TypeError("cannot convert %r to an address" % ( - self._get_c_name(),)) - else: - raise TypeError("cannot convert %r to %r" % ( - self._get_c_name(), BClass._get_c_name())) - - @classmethod - def _get_size(cls): - return ctypes.sizeof(cls._ctype) - - def _get_size_of_instance(self): - return ctypes.sizeof(self._ctype) - - @classmethod - def _cast_from(cls, source): - raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) - - def _cast_to_integer(self): - return self._convert_to_address(None) - - @classmethod - def _alignment(cls): - return ctypes.alignment(cls._ctype) - - def __iter__(self): - raise TypeError("cdata %r does not support iteration" % ( - self._get_c_name()),) - - def _make_cmp(name): - cmpfunc = getattr(operator, name) - def cmp(self, other): - v_is_ptr = not isinstance(self, CTypesGenericPrimitive) - w_is_ptr = (isinstance(other, CTypesData) and - not isinstance(other, CTypesGenericPrimitive)) - if v_is_ptr and w_is_ptr: - return cmpfunc(self._convert_to_address(None), - other._convert_to_address(None)) - elif v_is_ptr or w_is_ptr: - return NotImplemented - else: - if isinstance(self, CTypesGenericPrimitive): - self = self._value - if isinstance(other, CTypesGenericPrimitive): - other = other._value - return cmpfunc(self, other) - cmp.func_name = name - return cmp - - __eq__ = _make_cmp('__eq__') - __ne__ = _make_cmp('__ne__') - __lt__ = _make_cmp('__lt__') - __le__ = _make_cmp('__le__') - __gt__ = _make_cmp('__gt__') - __ge__ = _make_cmp('__ge__') - - def __hash__(self): - return hash(self._convert_to_address(None)) - - def _to_string(self, maxlen): - raise TypeError("string(): %r" % (self,)) - - -class CTypesGenericPrimitive(CTypesData): - __slots__ = [] - - def __hash__(self): - return hash(self._value) - - def _get_own_repr(self): - return repr(self._from_ctypes(self._value)) - - -class CTypesGenericArray(CTypesData): - __slots__ = [] - - @classmethod - def _newp(cls, init): - return cls(init) - - def __iter__(self): - for i in xrange(len(self)): - yield self[i] - - def _get_own_repr(self): - return self._addr_repr(ctypes.addressof(self._blob)) - - -class CTypesGenericPtr(CTypesData): - __slots__ = ['_address', '_as_ctype_ptr'] - _automatic_casts = False - kind = "pointer" - - @classmethod - def _newp(cls, init): - return cls(init) - - @classmethod - def _cast_from(cls, source): - if source is None: - address = 0 - elif isinstance(source, CTypesData): - address = source._cast_to_integer() - elif isinstance(source, (int, long)): - address = source - else: - raise TypeError("bad type for cast to %r: %r" % - (cls, type(source).__name__)) - return cls._new_pointer_at(address) - - @classmethod - def _new_pointer_at(cls, address): - self = cls.__new__(cls) - self._address = address - self._as_ctype_ptr = ctypes.cast(address, cls._ctype) - return self - - def _get_own_repr(self): - try: - return self._addr_repr(self._address) - except AttributeError: - return '???' - - def _cast_to_integer(self): - return self._address - - def __nonzero__(self): - return bool(self._address) - __bool__ = __nonzero__ - - @classmethod - def _to_ctypes(cls, value): - if not isinstance(value, CTypesData): - raise TypeError("unexpected %s object" % type(value).__name__) - address = value._convert_to_address(cls) - return ctypes.cast(address, cls._ctype) - - @classmethod - def _from_ctypes(cls, ctypes_ptr): - address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 - return cls._new_pointer_at(address) - - @classmethod - def _initialize(cls, ctypes_ptr, value): - if value: - ctypes_ptr.contents = cls._to_ctypes(value).contents - - def _convert_to_address(self, BClass): - if (BClass in (self.__class__, None) or BClass._automatic_casts - or self._automatic_casts): - return self._address - else: - return CTypesData._convert_to_address(self, BClass) - - -class CTypesBaseStructOrUnion(CTypesData): - __slots__ = ['_blob'] - - @classmethod - def _create_ctype_obj(cls, init): - # may be overridden - raise TypeError("cannot instantiate opaque type %s" % (cls,)) - - def _get_own_repr(self): - return self._addr_repr(ctypes.addressof(self._blob)) - - @classmethod - def _offsetof(cls, fieldname): - return getattr(cls._ctype, fieldname).offset - - def _convert_to_address(self, BClass): - if getattr(BClass, '_BItem', None) is self.__class__: - return ctypes.addressof(self._blob) - else: - return CTypesData._convert_to_address(self, BClass) - - @classmethod - def _from_ctypes(cls, ctypes_struct_or_union): - self = cls.__new__(cls) - self._blob = ctypes_struct_or_union - return self - - @classmethod - def _to_ctypes(cls, value): - return value._blob - - def __repr__(self, c_name=None): - return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) - - -class CTypesBackend(object): - - PRIMITIVE_TYPES = { - 'char': ctypes.c_char, - 'short': ctypes.c_short, - 'int': ctypes.c_int, - 'long': ctypes.c_long, - 'long long': ctypes.c_longlong, - 'signed char': ctypes.c_byte, - 'unsigned char': ctypes.c_ubyte, - 'unsigned short': ctypes.c_ushort, - 'unsigned int': ctypes.c_uint, - 'unsigned long': ctypes.c_ulong, - 'unsigned long long': ctypes.c_ulonglong, - 'float': ctypes.c_float, - 'double': ctypes.c_double, - '_Bool': ctypes.c_bool, - } - - for _name in ['unsigned long long', 'unsigned long', - 'unsigned int', 'unsigned short', 'unsigned char']: - _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) - PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_void_p): - PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_size_t): - PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] - - for _name in ['long long', 'long', 'int', 'short', 'signed char']: - _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) - PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_void_p): - PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] - PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] - if _size == ctypes.sizeof(ctypes.c_size_t): - PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] - - - def __init__(self): - self.RTLD_LAZY = 0 # not supported anyway by ctypes - self.RTLD_NOW = 0 - self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL - self.RTLD_LOCAL = ctypes.RTLD_LOCAL - - def set_ffi(self, ffi): - self.ffi = ffi - - def _get_types(self): - return CTypesData, CTypesType - - def load_library(self, path, flags=0): - cdll = ctypes.CDLL(path, flags) - return CTypesLibrary(self, cdll) - - def new_void_type(self): - class CTypesVoid(CTypesData): - __slots__ = [] - _reftypename = 'void &' - @staticmethod - def _from_ctypes(novalue): - return None - @staticmethod - def _to_ctypes(novalue): - if novalue is not None: - raise TypeError("None expected, got %s object" % - (type(novalue).__name__,)) - return None - CTypesVoid._fix_class() - return CTypesVoid - - def new_primitive_type(self, name): - if name == 'wchar_t': - raise NotImplementedError(name) - ctype = self.PRIMITIVE_TYPES[name] - if name == 'char': - kind = 'char' - elif name in ('float', 'double'): - kind = 'float' - else: - if name in ('signed char', 'unsigned char'): - kind = 'byte' - elif name == '_Bool': - kind = 'bool' - else: - kind = 'int' - is_signed = (ctype(-1).value == -1) - # - def _cast_source_to_int(source): - if isinstance(source, (int, long, float)): - source = int(source) - elif isinstance(source, CTypesData): - source = source._cast_to_integer() - elif isinstance(source, bytes): - source = ord(source) - elif source is None: - source = 0 - else: - raise TypeError("bad type for cast to %r: %r" % - (CTypesPrimitive, type(source).__name__)) - return source - # - kind1 = kind - class CTypesPrimitive(CTypesGenericPrimitive): - __slots__ = ['_value'] - _ctype = ctype - _reftypename = '%s &' % name - kind = kind1 - - def __init__(self, value): - self._value = value - - @staticmethod - def _create_ctype_obj(init): - if init is None: - return ctype() - return ctype(CTypesPrimitive._to_ctypes(init)) - - if kind == 'int' or kind == 'byte': - @classmethod - def _cast_from(cls, source): - source = _cast_source_to_int(source) - source = ctype(source).value # cast within range - return cls(source) - def __int__(self): - return self._value - - if kind == 'bool': - @classmethod - def _cast_from(cls, source): - if not isinstance(source, (int, long, float)): - source = _cast_source_to_int(source) - return cls(bool(source)) - def __int__(self): - return int(self._value) - - if kind == 'char': - @classmethod - def _cast_from(cls, source): - source = _cast_source_to_int(source) - source = bytechr(source & 0xFF) - return cls(source) - def __int__(self): - return ord(self._value) - - if kind == 'float': - @classmethod - def _cast_from(cls, source): - if isinstance(source, float): - pass - elif isinstance(source, CTypesGenericPrimitive): - if hasattr(source, '__float__'): - source = float(source) - else: - source = int(source) - else: - source = _cast_source_to_int(source) - source = ctype(source).value # fix precision - return cls(source) - def __int__(self): - return int(self._value) - def __float__(self): - return self._value - - _cast_to_integer = __int__ - - if kind == 'int' or kind == 'byte' or kind == 'bool': - @staticmethod - def _to_ctypes(x): - if not isinstance(x, (int, long)): - if isinstance(x, CTypesData): - x = int(x) - else: - raise TypeError("integer expected, got %s" % - type(x).__name__) - if ctype(x).value != x: - if not is_signed and x < 0: - raise OverflowError("%s: negative integer" % name) - else: - raise OverflowError("%s: integer out of bounds" - % name) - return x - - if kind == 'char': - @staticmethod - def _to_ctypes(x): - if isinstance(x, bytes) and len(x) == 1: - return x - if isinstance(x, CTypesPrimitive): # > - return x._value - raise TypeError("character expected, got %s" % - type(x).__name__) - def __nonzero__(self): - return ord(self._value) != 0 - else: - def __nonzero__(self): - return self._value != 0 - __bool__ = __nonzero__ - - if kind == 'float': - @staticmethod - def _to_ctypes(x): - if not isinstance(x, (int, long, float, CTypesData)): - raise TypeError("float expected, got %s" % - type(x).__name__) - return ctype(x).value - - @staticmethod - def _from_ctypes(value): - return getattr(value, 'value', value) - - @staticmethod - def _initialize(blob, init): - blob.value = CTypesPrimitive._to_ctypes(init) - - if kind == 'char': - def _to_string(self, maxlen): - return self._value - if kind == 'byte': - def _to_string(self, maxlen): - return chr(self._value & 0xff) - # - CTypesPrimitive._fix_class() - return CTypesPrimitive - - def new_pointer_type(self, BItem): - getbtype = self.ffi._get_cached_btype - if BItem is getbtype(model.PrimitiveType('char')): - kind = 'charp' - elif BItem in (getbtype(model.PrimitiveType('signed char')), - getbtype(model.PrimitiveType('unsigned char'))): - kind = 'bytep' - elif BItem is getbtype(model.void_type): - kind = 'voidp' - else: - kind = 'generic' - # - class CTypesPtr(CTypesGenericPtr): - __slots__ = ['_own'] - if kind == 'charp': - __slots__ += ['__as_strbuf'] - _BItem = BItem - if hasattr(BItem, '_ctype'): - _ctype = ctypes.POINTER(BItem._ctype) - _bitem_size = ctypes.sizeof(BItem._ctype) - else: - _ctype = ctypes.c_void_p - if issubclass(BItem, CTypesGenericArray): - _reftypename = BItem._get_c_name('(* &)') - else: - _reftypename = BItem._get_c_name(' * &') - - def __init__(self, init): - ctypeobj = BItem._create_ctype_obj(init) - if kind == 'charp': - self.__as_strbuf = ctypes.create_string_buffer( - ctypeobj.value + b'\x00') - self._as_ctype_ptr = ctypes.cast( - self.__as_strbuf, self._ctype) - else: - self._as_ctype_ptr = ctypes.pointer(ctypeobj) - self._address = ctypes.cast(self._as_ctype_ptr, - ctypes.c_void_p).value - self._own = True - - def __add__(self, other): - if isinstance(other, (int, long)): - return self._new_pointer_at(self._address + - other * self._bitem_size) - else: - return NotImplemented - - def __sub__(self, other): - if isinstance(other, (int, long)): - return self._new_pointer_at(self._address - - other * self._bitem_size) - elif type(self) is type(other): - return (self._address - other._address) // self._bitem_size - else: - return NotImplemented - - def __getitem__(self, index): - if getattr(self, '_own', False) and index != 0: - raise IndexError - return BItem._from_ctypes(self._as_ctype_ptr[index]) - - def __setitem__(self, index, value): - self._as_ctype_ptr[index] = BItem._to_ctypes(value) - - if kind == 'charp' or kind == 'voidp': - @classmethod - def _arg_to_ctypes(cls, *value): - if value and isinstance(value[0], bytes): - return ctypes.c_char_p(value[0]) - else: - return super(CTypesPtr, cls)._arg_to_ctypes(*value) - - if kind == 'charp' or kind == 'bytep': - def _to_string(self, maxlen): - if maxlen < 0: - maxlen = sys.maxsize - p = ctypes.cast(self._as_ctype_ptr, - ctypes.POINTER(ctypes.c_char)) - n = 0 - while n < maxlen and p[n] != b'\x00': - n += 1 - return b''.join([p[i] for i in range(n)]) - - def _get_own_repr(self): - if getattr(self, '_own', False): - return 'owning %d bytes' % ( - ctypes.sizeof(self._as_ctype_ptr.contents),) - return super(CTypesPtr, self)._get_own_repr() - # - if (BItem is self.ffi._get_cached_btype(model.void_type) or - BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): - CTypesPtr._automatic_casts = True - # - CTypesPtr._fix_class() - return CTypesPtr - - def new_array_type(self, CTypesPtr, length): - if length is None: - brackets = ' &[]' - else: - brackets = ' &[%d]' % length - BItem = CTypesPtr._BItem - getbtype = self.ffi._get_cached_btype - if BItem is getbtype(model.PrimitiveType('char')): - kind = 'char' - elif BItem in (getbtype(model.PrimitiveType('signed char')), - getbtype(model.PrimitiveType('unsigned char'))): - kind = 'byte' - else: - kind = 'generic' - # - class CTypesArray(CTypesGenericArray): - __slots__ = ['_blob', '_own'] - if length is not None: - _ctype = BItem._ctype * length - else: - __slots__.append('_ctype') - _reftypename = BItem._get_c_name(brackets) - _declared_length = length - _CTPtr = CTypesPtr - - def __init__(self, init): - if length is None: - if isinstance(init, (int, long)): - len1 = init - init = None - elif kind == 'char' and isinstance(init, bytes): - len1 = len(init) + 1 # extra null - else: - init = tuple(init) - len1 = len(init) - self._ctype = BItem._ctype * len1 - self._blob = self._ctype() - self._own = True - if init is not None: - self._initialize(self._blob, init) - - @staticmethod - def _initialize(blob, init): - if isinstance(init, bytes): - init = [init[i:i+1] for i in range(len(init))] - else: - if isinstance(init, CTypesGenericArray): - if (len(init) != len(blob) or - not isinstance(init, CTypesArray)): - raise TypeError("length/type mismatch: %s" % (init,)) - init = tuple(init) - if len(init) > len(blob): - raise IndexError("too many initializers") - addr = ctypes.cast(blob, ctypes.c_void_p).value - PTR = ctypes.POINTER(BItem._ctype) - itemsize = ctypes.sizeof(BItem._ctype) - for i, value in enumerate(init): - p = ctypes.cast(addr + i * itemsize, PTR) - BItem._initialize(p.contents, value) - - def __len__(self): - return len(self._blob) - - def __getitem__(self, index): - if not (0 <= index < len(self._blob)): - raise IndexError - return BItem._from_ctypes(self._blob[index]) - - def __setitem__(self, index, value): - if not (0 <= index < len(self._blob)): - raise IndexError - self._blob[index] = BItem._to_ctypes(value) - - if kind == 'char' or kind == 'byte': - def _to_string(self, maxlen): - if maxlen < 0: - maxlen = len(self._blob) - p = ctypes.cast(self._blob, - ctypes.POINTER(ctypes.c_char)) - n = 0 - while n < maxlen and p[n] != b'\x00': - n += 1 - return b''.join([p[i] for i in range(n)]) - - def _get_own_repr(self): - if getattr(self, '_own', False): - return 'owning %d bytes' % (ctypes.sizeof(self._blob),) - return super(CTypesArray, self)._get_own_repr() - - def _convert_to_address(self, BClass): - if BClass in (CTypesPtr, None) or BClass._automatic_casts: - return ctypes.addressof(self._blob) - else: - return CTypesData._convert_to_address(self, BClass) - - @staticmethod - def _from_ctypes(ctypes_array): - self = CTypesArray.__new__(CTypesArray) - self._blob = ctypes_array - return self - - @staticmethod - def _arg_to_ctypes(value): - return CTypesPtr._arg_to_ctypes(value) - - def __add__(self, other): - if isinstance(other, (int, long)): - return CTypesPtr._new_pointer_at( - ctypes.addressof(self._blob) + - other * ctypes.sizeof(BItem._ctype)) - else: - return NotImplemented - - @classmethod - def _cast_from(cls, source): - raise NotImplementedError("casting to %r" % ( - cls._get_c_name(),)) - # - CTypesArray._fix_class() - return CTypesArray - - def _new_struct_or_union(self, kind, name, base_ctypes_class): - # - class struct_or_union(base_ctypes_class): - pass - struct_or_union.__name__ = '%s_%s' % (kind, name) - kind1 = kind - # - class CTypesStructOrUnion(CTypesBaseStructOrUnion): - __slots__ = ['_blob'] - _ctype = struct_or_union - _reftypename = '%s &' % (name,) - _kind = kind = kind1 - # - CTypesStructOrUnion._fix_class() - return CTypesStructOrUnion - - def new_struct_type(self, name): - return self._new_struct_or_union('struct', name, ctypes.Structure) - - def new_union_type(self, name): - return self._new_struct_or_union('union', name, ctypes.Union) - - def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, - totalsize=-1, totalalignment=-1, sflags=0, - pack=0): - if totalsize >= 0 or totalalignment >= 0: - raise NotImplementedError("the ctypes backend of CFFI does not support " - "structures completed by verify(); please " - "compile and install the _cffi_backend module.") - struct_or_union = CTypesStructOrUnion._ctype - fnames = [fname for (fname, BField, bitsize) in fields] - btypes = [BField for (fname, BField, bitsize) in fields] - bitfields = [bitsize for (fname, BField, bitsize) in fields] - # - bfield_types = {} - cfields = [] - for (fname, BField, bitsize) in fields: - if bitsize < 0: - cfields.append((fname, BField._ctype)) - bfield_types[fname] = BField - else: - cfields.append((fname, BField._ctype, bitsize)) - bfield_types[fname] = Ellipsis - if sflags & 8: - struct_or_union._pack_ = 1 - elif pack: - struct_or_union._pack_ = pack - struct_or_union._fields_ = cfields - CTypesStructOrUnion._bfield_types = bfield_types - # - @staticmethod - def _create_ctype_obj(init): - result = struct_or_union() - if init is not None: - initialize(result, init) - return result - CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj - # - def initialize(blob, init): - if is_union: - if len(init) > 1: - raise ValueError("union initializer: %d items given, but " - "only one supported (use a dict if needed)" - % (len(init),)) - if not isinstance(init, dict): - if isinstance(init, (bytes, unicode)): - raise TypeError("union initializer: got a str") - init = tuple(init) - if len(init) > len(fnames): - raise ValueError("too many values for %s initializer" % - CTypesStructOrUnion._get_c_name()) - init = dict(zip(fnames, init)) - addr = ctypes.addressof(blob) - for fname, value in init.items(): - BField, bitsize = name2fieldtype[fname] - assert bitsize < 0, \ - "not implemented: initializer with bit fields" - offset = CTypesStructOrUnion._offsetof(fname) - PTR = ctypes.POINTER(BField._ctype) - p = ctypes.cast(addr + offset, PTR) - BField._initialize(p.contents, value) - is_union = CTypesStructOrUnion._kind == 'union' - name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) - # - for fname, BField, bitsize in fields: - if fname == '': - raise NotImplementedError("nested anonymous structs/unions") - if hasattr(CTypesStructOrUnion, fname): - raise ValueError("the field name %r conflicts in " - "the ctypes backend" % fname) - if bitsize < 0: - def getter(self, fname=fname, BField=BField, - offset=CTypesStructOrUnion._offsetof(fname), - PTR=ctypes.POINTER(BField._ctype)): - addr = ctypes.addressof(self._blob) - p = ctypes.cast(addr + offset, PTR) - return BField._from_ctypes(p.contents) - def setter(self, value, fname=fname, BField=BField): - setattr(self._blob, fname, BField._to_ctypes(value)) - # - if issubclass(BField, CTypesGenericArray): - setter = None - if BField._declared_length == 0: - def getter(self, fname=fname, BFieldPtr=BField._CTPtr, - offset=CTypesStructOrUnion._offsetof(fname), - PTR=ctypes.POINTER(BField._ctype)): - addr = ctypes.addressof(self._blob) - p = ctypes.cast(addr + offset, PTR) - return BFieldPtr._from_ctypes(p) - # - else: - def getter(self, fname=fname, BField=BField): - return BField._from_ctypes(getattr(self._blob, fname)) - def setter(self, value, fname=fname, BField=BField): - # xxx obscure workaround - value = BField._to_ctypes(value) - oldvalue = getattr(self._blob, fname) - setattr(self._blob, fname, value) - if value != getattr(self._blob, fname): - setattr(self._blob, fname, oldvalue) - raise OverflowError("value too large for bitfield") - setattr(CTypesStructOrUnion, fname, property(getter, setter)) - # - CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) - for fname in fnames: - if hasattr(CTypesPtr, fname): - raise ValueError("the field name %r conflicts in " - "the ctypes backend" % fname) - def getter(self, fname=fname): - return getattr(self[0], fname) - def setter(self, value, fname=fname): - setattr(self[0], fname, value) - setattr(CTypesPtr, fname, property(getter, setter)) - - def new_function_type(self, BArgs, BResult, has_varargs): - nameargs = [BArg._get_c_name() for BArg in BArgs] - if has_varargs: - nameargs.append('...') - nameargs = ', '.join(nameargs) - # - class CTypesFunctionPtr(CTypesGenericPtr): - __slots__ = ['_own_callback', '_name'] - _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), - *[BArg._ctype for BArg in BArgs], - use_errno=True) - _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) - - def __init__(self, init, error=None): - # create a callback to the Python callable init() - import traceback - assert not has_varargs, "varargs not supported for callbacks" - if getattr(BResult, '_ctype', None) is not None: - error = BResult._from_ctypes( - BResult._create_ctype_obj(error)) - else: - error = None - def callback(*args): - args2 = [] - for arg, BArg in zip(args, BArgs): - args2.append(BArg._from_ctypes(arg)) - try: - res2 = init(*args2) - res2 = BResult._to_ctypes(res2) - except: - traceback.print_exc() - res2 = error - if issubclass(BResult, CTypesGenericPtr): - if res2: - res2 = ctypes.cast(res2, ctypes.c_void_p).value - # .value: http://bugs.python.org/issue1574593 - else: - res2 = None - #print repr(res2) - return res2 - if issubclass(BResult, CTypesGenericPtr): - # The only pointers callbacks can return are void*s: - # http://bugs.python.org/issue5710 - callback_ctype = ctypes.CFUNCTYPE( - ctypes.c_void_p, - *[BArg._ctype for BArg in BArgs], - use_errno=True) - else: - callback_ctype = CTypesFunctionPtr._ctype - self._as_ctype_ptr = callback_ctype(callback) - self._address = ctypes.cast(self._as_ctype_ptr, - ctypes.c_void_p).value - self._own_callback = init - - @staticmethod - def _initialize(ctypes_ptr, value): - if value: - raise NotImplementedError("ctypes backend: not supported: " - "initializers for function pointers") - - def __repr__(self): - c_name = getattr(self, '_name', None) - if c_name: - i = self._reftypename.index('(* &)') - if self._reftypename[i-1] not in ' )*': - c_name = ' ' + c_name - c_name = self._reftypename.replace('(* &)', c_name) - return CTypesData.__repr__(self, c_name) - - def _get_own_repr(self): - if getattr(self, '_own_callback', None) is not None: - return 'calling %r' % (self._own_callback,) - return super(CTypesFunctionPtr, self)._get_own_repr() - - def __call__(self, *args): - if has_varargs: - assert len(args) >= len(BArgs) - extraargs = args[len(BArgs):] - args = args[:len(BArgs)] - else: - assert len(args) == len(BArgs) - ctypes_args = [] - for arg, BArg in zip(args, BArgs): - ctypes_args.append(BArg._arg_to_ctypes(arg)) - if has_varargs: - for i, arg in enumerate(extraargs): - if arg is None: - ctypes_args.append(ctypes.c_void_p(0)) # NULL - continue - if not isinstance(arg, CTypesData): - raise TypeError( - "argument %d passed in the variadic part " - "needs to be a cdata object (got %s)" % - (1 + len(BArgs) + i, type(arg).__name__)) - ctypes_args.append(arg._arg_to_ctypes(arg)) - result = self._as_ctype_ptr(*ctypes_args) - return BResult._from_ctypes(result) - # - CTypesFunctionPtr._fix_class() - return CTypesFunctionPtr - - def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): - assert isinstance(name, str) - reverse_mapping = dict(zip(reversed(enumvalues), - reversed(enumerators))) - # - class CTypesEnum(CTypesInt): - __slots__ = [] - _reftypename = '%s &' % name - - def _get_own_repr(self): - value = self._value - try: - return '%d: %s' % (value, reverse_mapping[value]) - except KeyError: - return str(value) - - def _to_string(self, maxlen): - value = self._value - try: - return reverse_mapping[value] - except KeyError: - return str(value) - # - CTypesEnum._fix_class() - return CTypesEnum - - def get_errno(self): - return ctypes.get_errno() - - def set_errno(self, value): - ctypes.set_errno(value) - - def string(self, b, maxlen=-1): - return b._to_string(maxlen) - - def buffer(self, bptr, size=-1): - raise NotImplementedError("buffer() with ctypes backend") - - def sizeof(self, cdata_or_BType): - if isinstance(cdata_or_BType, CTypesData): - return cdata_or_BType._get_size_of_instance() - else: - assert issubclass(cdata_or_BType, CTypesData) - return cdata_or_BType._get_size() - - def alignof(self, BType): - assert issubclass(BType, CTypesData) - return BType._alignment() - - def newp(self, BType, source): - if not issubclass(BType, CTypesData): - raise TypeError - return BType._newp(source) - - def cast(self, BType, source): - return BType._cast_from(source) - - def callback(self, BType, source, error, onerror): - assert onerror is None # XXX not implemented - return BType(source, error) - - _weakref_cache_ref = None - - def gcp(self, cdata, destructor, size=0): - if self._weakref_cache_ref is None: - import weakref - class MyRef(weakref.ref): - def __eq__(self, other): - myref = self() - return self is other or ( - myref is not None and myref is other()) - def __ne__(self, other): - return not (self == other) - def __hash__(self): - try: - return self._hash - except AttributeError: - self._hash = hash(self()) - return self._hash - self._weakref_cache_ref = {}, MyRef - weak_cache, MyRef = self._weakref_cache_ref - - if destructor is None: - try: - del weak_cache[MyRef(cdata)] - except KeyError: - raise TypeError("Can remove destructor only on a object " - "previously returned by ffi.gc()") - return None - - def remove(k): - cdata, destructor = weak_cache.pop(k, (None, None)) - if destructor is not None: - destructor(cdata) - - new_cdata = self.cast(self.typeof(cdata), cdata) - assert new_cdata is not cdata - weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) - return new_cdata - - typeof = type - - def getcname(self, BType, replace_with): - return BType._get_c_name(replace_with) - - def typeoffsetof(self, BType, fieldname, num=0): - if isinstance(fieldname, str): - if num == 0 and issubclass(BType, CTypesGenericPtr): - BType = BType._BItem - if not issubclass(BType, CTypesBaseStructOrUnion): - raise TypeError("expected a struct or union ctype") - BField = BType._bfield_types[fieldname] - if BField is Ellipsis: - raise TypeError("not supported for bitfields") - return (BField, BType._offsetof(fieldname)) - elif isinstance(fieldname, (int, long)): - if issubclass(BType, CTypesGenericArray): - BType = BType._CTPtr - if not issubclass(BType, CTypesGenericPtr): - raise TypeError("expected an array or ptr ctype") - BItem = BType._BItem - offset = BItem._get_size() * fieldname - if offset > sys.maxsize: - raise OverflowError - return (BItem, offset) - else: - raise TypeError(type(fieldname)) - - def rawaddressof(self, BTypePtr, cdata, offset=None): - if isinstance(cdata, CTypesBaseStructOrUnion): - ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) - elif isinstance(cdata, CTypesGenericPtr): - if offset is None or not issubclass(type(cdata)._BItem, - CTypesBaseStructOrUnion): - raise TypeError("unexpected cdata type") - ptr = type(cdata)._to_ctypes(cdata) - elif isinstance(cdata, CTypesGenericArray): - ptr = type(cdata)._to_ctypes(cdata) - else: - raise TypeError("expected a ") - if offset: - ptr = ctypes.cast( - ctypes.c_void_p( - ctypes.cast(ptr, ctypes.c_void_p).value + offset), - type(ptr)) - return BTypePtr._from_ctypes(ptr) - - -class CTypesLibrary(object): - - def __init__(self, backend, cdll): - self.backend = backend - self.cdll = cdll - - def load_function(self, BType, name): - c_func = getattr(self.cdll, name) - funcobj = BType._from_ctypes(c_func) - funcobj._name = name - return funcobj - - def read_variable(self, BType, name): - try: - ctypes_obj = BType._ctype.in_dll(self.cdll, name) - except AttributeError as e: - raise NotImplementedError(e) - return BType._from_ctypes(ctypes_obj) - - def write_variable(self, BType, name, value): - new_ctypes_obj = BType._to_ctypes(value) - ctypes_obj = BType._ctype.in_dll(self.cdll, name) - ctypes.memmove(ctypes.addressof(ctypes_obj), - ctypes.addressof(new_ctypes_obj), - ctypes.sizeof(BType._ctype)) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/cffi_opcode.py b/backend/venv39/lib/python3.9/site-packages/cffi/cffi_opcode.py deleted file mode 100644 index 6421df6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/cffi_opcode.py +++ /dev/null @@ -1,187 +0,0 @@ -from .error import VerificationError - -class CffiOp(object): - def __init__(self, op, arg): - self.op = op - self.arg = arg - - def as_c_expr(self): - if self.op is None: - assert isinstance(self.arg, str) - return '(_cffi_opcode_t)(%s)' % (self.arg,) - classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) - - def as_python_bytes(self): - if self.op is None and self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) - if isinstance(self.arg, str): - raise VerificationError("cannot emit to Python: %r" % (self.arg,)) - return format_four_bytes((self.arg << 8) | self.op) - - def __str__(self): - classname = CLASS_NAME.get(self.op, self.op) - return '(%s %s)' % (classname, self.arg) - -def format_four_bytes(num): - return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( - (num >> 24) & 0xFF, - (num >> 16) & 0xFF, - (num >> 8) & 0xFF, - (num ) & 0xFF) - -OP_PRIMITIVE = 1 -OP_POINTER = 3 -OP_ARRAY = 5 -OP_OPEN_ARRAY = 7 -OP_STRUCT_UNION = 9 -OP_ENUM = 11 -OP_FUNCTION = 13 -OP_FUNCTION_END = 15 -OP_NOOP = 17 -OP_BITFIELD = 19 -OP_TYPENAME = 21 -OP_CPYTHON_BLTN_V = 23 # varargs -OP_CPYTHON_BLTN_N = 25 # noargs -OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) -OP_CONSTANT = 29 -OP_CONSTANT_INT = 31 -OP_GLOBAL_VAR = 33 -OP_DLOPEN_FUNC = 35 -OP_DLOPEN_CONST = 37 -OP_GLOBAL_VAR_F = 39 -OP_EXTERN_PYTHON = 41 - -PRIM_VOID = 0 -PRIM_BOOL = 1 -PRIM_CHAR = 2 -PRIM_SCHAR = 3 -PRIM_UCHAR = 4 -PRIM_SHORT = 5 -PRIM_USHORT = 6 -PRIM_INT = 7 -PRIM_UINT = 8 -PRIM_LONG = 9 -PRIM_ULONG = 10 -PRIM_LONGLONG = 11 -PRIM_ULONGLONG = 12 -PRIM_FLOAT = 13 -PRIM_DOUBLE = 14 -PRIM_LONGDOUBLE = 15 - -PRIM_WCHAR = 16 -PRIM_INT8 = 17 -PRIM_UINT8 = 18 -PRIM_INT16 = 19 -PRIM_UINT16 = 20 -PRIM_INT32 = 21 -PRIM_UINT32 = 22 -PRIM_INT64 = 23 -PRIM_UINT64 = 24 -PRIM_INTPTR = 25 -PRIM_UINTPTR = 26 -PRIM_PTRDIFF = 27 -PRIM_SIZE = 28 -PRIM_SSIZE = 29 -PRIM_INT_LEAST8 = 30 -PRIM_UINT_LEAST8 = 31 -PRIM_INT_LEAST16 = 32 -PRIM_UINT_LEAST16 = 33 -PRIM_INT_LEAST32 = 34 -PRIM_UINT_LEAST32 = 35 -PRIM_INT_LEAST64 = 36 -PRIM_UINT_LEAST64 = 37 -PRIM_INT_FAST8 = 38 -PRIM_UINT_FAST8 = 39 -PRIM_INT_FAST16 = 40 -PRIM_UINT_FAST16 = 41 -PRIM_INT_FAST32 = 42 -PRIM_UINT_FAST32 = 43 -PRIM_INT_FAST64 = 44 -PRIM_UINT_FAST64 = 45 -PRIM_INTMAX = 46 -PRIM_UINTMAX = 47 -PRIM_FLOATCOMPLEX = 48 -PRIM_DOUBLECOMPLEX = 49 -PRIM_CHAR16 = 50 -PRIM_CHAR32 = 51 - -_NUM_PRIM = 52 -_UNKNOWN_PRIM = -1 -_UNKNOWN_FLOAT_PRIM = -2 -_UNKNOWN_LONG_DOUBLE = -3 - -_IO_FILE_STRUCT = -1 - -PRIMITIVE_TO_INDEX = { - 'char': PRIM_CHAR, - 'short': PRIM_SHORT, - 'int': PRIM_INT, - 'long': PRIM_LONG, - 'long long': PRIM_LONGLONG, - 'signed char': PRIM_SCHAR, - 'unsigned char': PRIM_UCHAR, - 'unsigned short': PRIM_USHORT, - 'unsigned int': PRIM_UINT, - 'unsigned long': PRIM_ULONG, - 'unsigned long long': PRIM_ULONGLONG, - 'float': PRIM_FLOAT, - 'double': PRIM_DOUBLE, - 'long double': PRIM_LONGDOUBLE, - '_cffi_float_complex_t': PRIM_FLOATCOMPLEX, - '_cffi_double_complex_t': PRIM_DOUBLECOMPLEX, - '_Bool': PRIM_BOOL, - 'wchar_t': PRIM_WCHAR, - 'char16_t': PRIM_CHAR16, - 'char32_t': PRIM_CHAR32, - 'int8_t': PRIM_INT8, - 'uint8_t': PRIM_UINT8, - 'int16_t': PRIM_INT16, - 'uint16_t': PRIM_UINT16, - 'int32_t': PRIM_INT32, - 'uint32_t': PRIM_UINT32, - 'int64_t': PRIM_INT64, - 'uint64_t': PRIM_UINT64, - 'intptr_t': PRIM_INTPTR, - 'uintptr_t': PRIM_UINTPTR, - 'ptrdiff_t': PRIM_PTRDIFF, - 'size_t': PRIM_SIZE, - 'ssize_t': PRIM_SSIZE, - 'int_least8_t': PRIM_INT_LEAST8, - 'uint_least8_t': PRIM_UINT_LEAST8, - 'int_least16_t': PRIM_INT_LEAST16, - 'uint_least16_t': PRIM_UINT_LEAST16, - 'int_least32_t': PRIM_INT_LEAST32, - 'uint_least32_t': PRIM_UINT_LEAST32, - 'int_least64_t': PRIM_INT_LEAST64, - 'uint_least64_t': PRIM_UINT_LEAST64, - 'int_fast8_t': PRIM_INT_FAST8, - 'uint_fast8_t': PRIM_UINT_FAST8, - 'int_fast16_t': PRIM_INT_FAST16, - 'uint_fast16_t': PRIM_UINT_FAST16, - 'int_fast32_t': PRIM_INT_FAST32, - 'uint_fast32_t': PRIM_UINT_FAST32, - 'int_fast64_t': PRIM_INT_FAST64, - 'uint_fast64_t': PRIM_UINT_FAST64, - 'intmax_t': PRIM_INTMAX, - 'uintmax_t': PRIM_UINTMAX, - } - -F_UNION = 0x01 -F_CHECK_FIELDS = 0x02 -F_PACKED = 0x04 -F_EXTERNAL = 0x08 -F_OPAQUE = 0x10 - -G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) - for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', - 'F_EXTERNAL', 'F_OPAQUE']]) - -CLASS_NAME = {} -for _name, _value in list(globals().items()): - if _name.startswith('OP_') and isinstance(_value, int): - CLASS_NAME[_value] = _name[3:] diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/commontypes.py b/backend/venv39/lib/python3.9/site-packages/cffi/commontypes.py deleted file mode 100644 index d4dae35..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/commontypes.py +++ /dev/null @@ -1,82 +0,0 @@ -import sys -from . import model -from .error import FFIError - - -COMMON_TYPES = {} - -try: - # fetch "bool" and all simple Windows types - from _cffi_backend import _get_common_types - _get_common_types(COMMON_TYPES) -except ImportError: - pass - -COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') -COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above -COMMON_TYPES['float _Complex'] = '_cffi_float_complex_t' -COMMON_TYPES['double _Complex'] = '_cffi_double_complex_t' - -for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: - if _type.endswith('_t'): - COMMON_TYPES[_type] = _type -del _type - -_CACHE = {} - -def resolve_common_type(parser, commontype): - try: - return _CACHE[commontype] - except KeyError: - cdecl = COMMON_TYPES.get(commontype, commontype) - if not isinstance(cdecl, str): - result, quals = cdecl, 0 # cdecl is already a BaseType - elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: - result, quals = model.PrimitiveType(cdecl), 0 - elif cdecl == 'set-unicode-needed': - raise FFIError("The Windows type %r is only available after " - "you call ffi.set_unicode()" % (commontype,)) - else: - if commontype == cdecl: - raise FFIError( - "Unsupported type: %r. Please look at " - "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " - "and file an issue if you think this type should really " - "be supported." % (commontype,)) - result, quals = parser.parse_type_and_quals(cdecl) # recursive - - assert isinstance(result, model.BaseTypeByIdentity) - _CACHE[commontype] = result, quals - return result, quals - - -# ____________________________________________________________ -# extra types for Windows (most of them are in commontypes.c) - - -def win_common_types(): - return { - "UNICODE_STRING": model.StructType( - "_UNICODE_STRING", - ["Length", - "MaximumLength", - "Buffer"], - [model.PrimitiveType("unsigned short"), - model.PrimitiveType("unsigned short"), - model.PointerType(model.PrimitiveType("wchar_t"))], - [-1, -1, -1]), - "PUNICODE_STRING": "UNICODE_STRING *", - "PCUNICODE_STRING": "const UNICODE_STRING *", - - "TBYTE": "set-unicode-needed", - "TCHAR": "set-unicode-needed", - "LPCTSTR": "set-unicode-needed", - "PCTSTR": "set-unicode-needed", - "LPTSTR": "set-unicode-needed", - "PTSTR": "set-unicode-needed", - "PTBYTE": "set-unicode-needed", - "PTCHAR": "set-unicode-needed", - } - -if sys.platform == 'win32': - COMMON_TYPES.update(win_common_types()) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/cparser.py b/backend/venv39/lib/python3.9/site-packages/cffi/cparser.py deleted file mode 100644 index dd590d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/cparser.py +++ /dev/null @@ -1,1015 +0,0 @@ -from . import model -from .commontypes import COMMON_TYPES, resolve_common_type -from .error import FFIError, CDefError -try: - from . import _pycparser as pycparser -except ImportError: - import pycparser -import weakref, re, sys - -try: - if sys.version_info < (3,): - import thread as _thread - else: - import _thread - lock = _thread.allocate_lock() -except ImportError: - lock = None - -def _workaround_for_static_import_finders(): - # Issue #392: packaging tools like cx_Freeze can not find these - # because pycparser uses exec dynamic import. This is an obscure - # workaround. This function is never called. - import pycparser.yacctab - import pycparser.lextab - -CDEF_SOURCE_STRING = "" -_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", - re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" - r"\b((?:[^\n\\]|\\.)*?)$", - re.DOTALL | re.MULTILINE) -_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) -_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") -_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") -_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") -_r_words = re.compile(r"\w+|\S") -_parser_cache = None -_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) -_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") -_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") -_r_cdecl = re.compile(r"\b__cdecl\b") -_r_extern_python = re.compile(r'\bextern\s*"' - r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') -_r_star_const_space = re.compile( # matches "* const " - r"[*]\s*((const|volatile|restrict)\b\s*)+") -_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" - r"\.\.\.") -_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") - -def _get_parser(): - global _parser_cache - if _parser_cache is None: - _parser_cache = pycparser.CParser() - return _parser_cache - -def _workaround_for_old_pycparser(csource): - # Workaround for a pycparser issue (fixed between pycparser 2.10 and - # 2.14): "char*const***" gives us a wrong syntax tree, the same as - # for "char***(*const)". This means we can't tell the difference - # afterwards. But "char(*const(***))" gives us the right syntax - # tree. The issue only occurs if there are several stars in - # sequence with no parenthesis in between, just possibly qualifiers. - # Attempt to fix it by adding some parentheses in the source: each - # time we see "* const" or "* const *", we add an opening - # parenthesis before each star---the hard part is figuring out where - # to close them. - parts = [] - while True: - match = _r_star_const_space.search(csource) - if not match: - break - #print repr(''.join(parts)+csource), '=>', - parts.append(csource[:match.start()]) - parts.append('('); closing = ')' - parts.append(match.group()) # e.g. "* const " - endpos = match.end() - if csource.startswith('*', endpos): - parts.append('('); closing += ')' - level = 0 - i = endpos - while i < len(csource): - c = csource[i] - if c == '(': - level += 1 - elif c == ')': - if level == 0: - break - level -= 1 - elif c in ',;=': - if level == 0: - break - i += 1 - csource = csource[endpos:i] + closing + csource[i:] - #print repr(''.join(parts)+csource) - parts.append(csource) - return ''.join(parts) - -def _preprocess_extern_python(csource): - # input: `extern "Python" int foo(int);` or - # `extern "Python" { int foo(int); }` - # output: - # void __cffi_extern_python_start; - # int foo(int); - # void __cffi_extern_python_stop; - # - # input: `extern "Python+C" int foo(int);` - # output: - # void __cffi_extern_python_plus_c_start; - # int foo(int); - # void __cffi_extern_python_stop; - parts = [] - while True: - match = _r_extern_python.search(csource) - if not match: - break - endpos = match.end() - 1 - #print - #print ''.join(parts)+csource - #print '=>' - parts.append(csource[:match.start()]) - if 'C' in match.group(1): - parts.append('void __cffi_extern_python_plus_c_start; ') - else: - parts.append('void __cffi_extern_python_start; ') - if csource[endpos] == '{': - # grouping variant - closing = csource.find('}', endpos) - if closing < 0: - raise CDefError("'extern \"Python\" {': no '}' found") - if csource.find('{', endpos + 1, closing) >= 0: - raise NotImplementedError("cannot use { } inside a block " - "'extern \"Python\" { ... }'") - parts.append(csource[endpos+1:closing]) - csource = csource[closing+1:] - else: - # non-grouping variant - semicolon = csource.find(';', endpos) - if semicolon < 0: - raise CDefError("'extern \"Python\": no ';' found") - parts.append(csource[endpos:semicolon+1]) - csource = csource[semicolon+1:] - parts.append(' void __cffi_extern_python_stop;') - #print ''.join(parts)+csource - #print - parts.append(csource) - return ''.join(parts) - -def _warn_for_string_literal(csource): - if '"' not in csource: - return - for line in csource.splitlines(): - if '"' in line and not line.lstrip().startswith('#'): - import warnings - warnings.warn("String literal found in cdef() or type source. " - "String literals are ignored here, but you should " - "remove them anyway because some character sequences " - "confuse pre-parsing.") - break - -def _warn_for_non_extern_non_static_global_variable(decl): - if not decl.storage: - import warnings - warnings.warn("Global variable '%s' in cdef(): for consistency " - "with C it should have a storage class specifier " - "(usually 'extern')" % (decl.name,)) - -def _remove_line_directives(csource): - # _r_line_directive matches whole lines, without the final \n, if they - # start with '#line' with some spacing allowed, or '#NUMBER'. This - # function stores them away and replaces them with exactly the string - # '#line@N', where N is the index in the list 'line_directives'. - line_directives = [] - def replace(m): - i = len(line_directives) - line_directives.append(m.group()) - return '#line@%d' % i - csource = _r_line_directive.sub(replace, csource) - return csource, line_directives - -def _put_back_line_directives(csource, line_directives): - def replace(m): - s = m.group() - if not s.startswith('#line@'): - raise AssertionError("unexpected #line directive " - "(should have been processed and removed") - return line_directives[int(s[6:])] - return _r_line_directive.sub(replace, csource) - -def _preprocess(csource): - # First, remove the lines of the form '#line N "filename"' because - # the "filename" part could confuse the rest - csource, line_directives = _remove_line_directives(csource) - # Remove comments. NOTE: this only work because the cdef() section - # should not contain any string literals (except in line directives)! - def replace_keeping_newlines(m): - return ' ' + m.group().count('\n') * '\n' - csource = _r_comment.sub(replace_keeping_newlines, csource) - # Remove the "#define FOO x" lines - macros = {} - for match in _r_define.finditer(csource): - macroname, macrovalue = match.groups() - macrovalue = macrovalue.replace('\\\n', '').strip() - macros[macroname] = macrovalue - csource = _r_define.sub('', csource) - # - if pycparser.__version__ < '2.14': - csource = _workaround_for_old_pycparser(csource) - # - # BIG HACK: replace WINAPI or __stdcall with "volatile const". - # It doesn't make sense for the return type of a function to be - # "volatile volatile const", so we abuse it to detect __stdcall... - # Hack number 2 is that "int(volatile *fptr)();" is not valid C - # syntax, so we place the "volatile" before the opening parenthesis. - csource = _r_stdcall2.sub(' volatile volatile const(', csource) - csource = _r_stdcall1.sub(' volatile volatile const ', csource) - csource = _r_cdecl.sub(' ', csource) - # - # Replace `extern "Python"` with start/end markers - csource = _preprocess_extern_python(csource) - # - # Now there should not be any string literal left; warn if we get one - _warn_for_string_literal(csource) - # - # Replace "[...]" with "[__dotdotdotarray__]" - csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) - # - # Replace "...}" with "__dotdotdotNUM__}". This construction should - # occur only at the end of enums; at the end of structs we have "...;}" - # and at the end of vararg functions "...);". Also replace "=...[,}]" - # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when - # giving an unknown value. - matches = list(_r_partial_enum.finditer(csource)) - for number, match in enumerate(reversed(matches)): - p = match.start() - if csource[p] == '=': - p2 = csource.find('...', p, match.end()) - assert p2 > p - csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, - csource[p2+3:]) - else: - assert csource[p:p+3] == '...' - csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, - csource[p+3:]) - # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" - csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) - # Replace "float ..." or "double..." with "__dotdotdotfloat__" - csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) - # Replace all remaining "..." with the same name, "__dotdotdot__", - # which is declared with a typedef for the purpose of C parsing. - csource = csource.replace('...', ' __dotdotdot__ ') - # Finally, put back the line directives - csource = _put_back_line_directives(csource, line_directives) - return csource, macros - -def _common_type_names(csource): - # Look in the source for what looks like usages of types from the - # list of common types. A "usage" is approximated here as the - # appearance of the word, minus a "definition" of the type, which - # is the last word in a "typedef" statement. Approximative only - # but should be fine for all the common types. - look_for_words = set(COMMON_TYPES) - look_for_words.add(';') - look_for_words.add(',') - look_for_words.add('(') - look_for_words.add(')') - look_for_words.add('typedef') - words_used = set() - is_typedef = False - paren = 0 - previous_word = '' - for word in _r_words.findall(csource): - if word in look_for_words: - if word == ';': - if is_typedef: - words_used.discard(previous_word) - look_for_words.discard(previous_word) - is_typedef = False - elif word == 'typedef': - is_typedef = True - paren = 0 - elif word == '(': - paren += 1 - elif word == ')': - paren -= 1 - elif word == ',': - if is_typedef and paren == 0: - words_used.discard(previous_word) - look_for_words.discard(previous_word) - else: # word in COMMON_TYPES - words_used.add(word) - previous_word = word - return words_used - - -class Parser(object): - - def __init__(self): - self._declarations = {} - self._included_declarations = set() - self._anonymous_counter = 0 - self._structnode2type = weakref.WeakKeyDictionary() - self._options = {} - self._int_constants = {} - self._recomplete = [] - self._uses_new_feature = None - - def _parse(self, csource): - csource, macros = _preprocess(csource) - # XXX: for more efficiency we would need to poke into the - # internals of CParser... the following registers the - # typedefs, because their presence or absence influences the - # parsing itself (but what they are typedef'ed to plays no role) - ctn = _common_type_names(csource) - typenames = [] - for name in sorted(self._declarations): - if name.startswith('typedef '): - name = name[8:] - typenames.append(name) - ctn.discard(name) - typenames += sorted(ctn) - # - csourcelines = [] - csourcelines.append('# 1 ""') - for typename in typenames: - csourcelines.append('typedef int %s;' % typename) - csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' - ' __dotdotdot__;') - # this forces pycparser to consider the following in the file - # called from line 1 - csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) - csourcelines.append(csource) - csourcelines.append('') # see test_missing_newline_bug - fullcsource = '\n'.join(csourcelines) - if lock is not None: - lock.acquire() # pycparser is not thread-safe... - try: - ast = _get_parser().parse(fullcsource) - except pycparser.c_parser.ParseError as e: - self.convert_pycparser_error(e, csource) - finally: - if lock is not None: - lock.release() - # csource will be used to find buggy source text - return ast, macros, csource - - def _convert_pycparser_error(self, e, csource): - # xxx look for ":NUM:" at the start of str(e) - # and interpret that as a line number. This will not work if - # the user gives explicit ``# NUM "FILE"`` directives. - line = None - msg = str(e) - match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) - if match: - linenum = int(match.group(1), 10) - csourcelines = csource.splitlines() - if 1 <= linenum <= len(csourcelines): - line = csourcelines[linenum-1] - return line - - def convert_pycparser_error(self, e, csource): - line = self._convert_pycparser_error(e, csource) - - msg = str(e) - if line: - msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) - else: - msg = 'parse error\n%s' % (msg,) - raise CDefError(msg) - - def parse(self, csource, override=False, packed=False, pack=None, - dllexport=False): - if packed: - if packed != True: - raise ValueError("'packed' should be False or True; use " - "'pack' to give another value") - if pack: - raise ValueError("cannot give both 'pack' and 'packed'") - pack = 1 - elif pack: - if pack & (pack - 1): - raise ValueError("'pack' must be a power of two, not %r" % - (pack,)) - else: - pack = 0 - prev_options = self._options - try: - self._options = {'override': override, - 'packed': pack, - 'dllexport': dllexport} - self._internal_parse(csource) - finally: - self._options = prev_options - - def _internal_parse(self, csource): - ast, macros, csource = self._parse(csource) - # add the macros - self._process_macros(macros) - # find the first "__dotdotdot__" and use that as a separator - # between the repeated typedefs and the real csource - iterator = iter(ast.ext) - for decl in iterator: - if decl.name == '__dotdotdot__': - break - else: - assert 0 - current_decl = None - # - try: - self._inside_extern_python = '__cffi_extern_python_stop' - for decl in iterator: - current_decl = decl - if isinstance(decl, pycparser.c_ast.Decl): - self._parse_decl(decl) - elif isinstance(decl, pycparser.c_ast.Typedef): - if not decl.name: - raise CDefError("typedef does not declare any name", - decl) - quals = 0 - if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and - decl.type.type.names[-1].startswith('__dotdotdot')): - realtype = self._get_unknown_type(decl) - elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and - isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and - isinstance(decl.type.type.type, - pycparser.c_ast.IdentifierType) and - decl.type.type.type.names[-1].startswith('__dotdotdot')): - realtype = self._get_unknown_ptr_type(decl) - else: - realtype, quals = self._get_type_and_quals( - decl.type, name=decl.name, partial_length_ok=True, - typedef_example="*(%s *)0" % (decl.name,)) - self._declare('typedef ' + decl.name, realtype, quals=quals) - elif decl.__class__.__name__ == 'Pragma': - # skip pragma, only in pycparser 2.15 - import warnings - warnings.warn( - "#pragma in cdef() are entirely ignored. " - "They should be removed for now, otherwise your " - "code might behave differently in a future version " - "of CFFI if #pragma support gets added. Note that " - "'#pragma pack' needs to be replaced with the " - "'packed' keyword argument to cdef().") - else: - raise CDefError("unexpected <%s>: this construct is valid " - "C but not valid in cdef()" % - decl.__class__.__name__, decl) - except CDefError as e: - if len(e.args) == 1: - e.args = e.args + (current_decl,) - raise - except FFIError as e: - msg = self._convert_pycparser_error(e, csource) - if msg: - e.args = (e.args[0] + "\n *** Err: %s" % msg,) - raise - - def _add_constants(self, key, val): - if key in self._int_constants: - if self._int_constants[key] == val: - return # ignore identical double declarations - raise FFIError( - "multiple declarations of constant: %s" % (key,)) - self._int_constants[key] = val - - def _add_integer_constant(self, name, int_str): - int_str = int_str.lower().rstrip("ul") - neg = int_str.startswith('-') - if neg: - int_str = int_str[1:] - # "010" is not valid oct in py3 - if (int_str.startswith("0") and int_str != '0' - and not int_str.startswith("0x")): - int_str = "0o" + int_str[1:] - pyvalue = int(int_str, 0) - if neg: - pyvalue = -pyvalue - self._add_constants(name, pyvalue) - self._declare('macro ' + name, pyvalue) - - def _process_macros(self, macros): - for key, value in macros.items(): - value = value.strip() - if _r_int_literal.match(value): - self._add_integer_constant(key, value) - elif value == '...': - self._declare('macro ' + key, value) - else: - raise CDefError( - 'only supports one of the following syntax:\n' - ' #define %s ... (literally dot-dot-dot)\n' - ' #define %s NUMBER (with NUMBER an integer' - ' constant, decimal/hex/octal)\n' - 'got:\n' - ' #define %s %s' - % (key, key, key, value)) - - def _declare_function(self, tp, quals, decl): - tp = self._get_type_pointer(tp, quals) - if self._options.get('dllexport'): - tag = 'dllexport_python ' - elif self._inside_extern_python == '__cffi_extern_python_start': - tag = 'extern_python ' - elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': - tag = 'extern_python_plus_c ' - else: - tag = 'function ' - self._declare(tag + decl.name, tp) - - def _parse_decl(self, decl): - node = decl.type - if isinstance(node, pycparser.c_ast.FuncDecl): - tp, quals = self._get_type_and_quals(node, name=decl.name) - assert isinstance(tp, model.RawFunctionType) - self._declare_function(tp, quals, decl) - else: - if isinstance(node, pycparser.c_ast.Struct): - self._get_struct_union_enum_type('struct', node) - elif isinstance(node, pycparser.c_ast.Union): - self._get_struct_union_enum_type('union', node) - elif isinstance(node, pycparser.c_ast.Enum): - self._get_struct_union_enum_type('enum', node) - elif not decl.name: - raise CDefError("construct does not declare any variable", - decl) - # - if decl.name: - tp, quals = self._get_type_and_quals(node, - partial_length_ok=True) - if tp.is_raw_function: - self._declare_function(tp, quals, decl) - elif (tp.is_integer_type() and - hasattr(decl, 'init') and - hasattr(decl.init, 'value') and - _r_int_literal.match(decl.init.value)): - self._add_integer_constant(decl.name, decl.init.value) - elif (tp.is_integer_type() and - isinstance(decl.init, pycparser.c_ast.UnaryOp) and - decl.init.op == '-' and - hasattr(decl.init.expr, 'value') and - _r_int_literal.match(decl.init.expr.value)): - self._add_integer_constant(decl.name, - '-' + decl.init.expr.value) - elif (tp is model.void_type and - decl.name.startswith('__cffi_extern_python_')): - # hack: `extern "Python"` in the C source is replaced - # with "void __cffi_extern_python_start;" and - # "void __cffi_extern_python_stop;" - self._inside_extern_python = decl.name - else: - if self._inside_extern_python !='__cffi_extern_python_stop': - raise CDefError( - "cannot declare constants or " - "variables with 'extern \"Python\"'") - if (quals & model.Q_CONST) and not tp.is_array_type: - self._declare('constant ' + decl.name, tp, quals=quals) - else: - _warn_for_non_extern_non_static_global_variable(decl) - self._declare('variable ' + decl.name, tp, quals=quals) - - def parse_type(self, cdecl): - return self.parse_type_and_quals(cdecl)[0] - - def parse_type_and_quals(self, cdecl): - ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] - assert not macros - exprnode = ast.ext[-1].type.args.params[0] - if isinstance(exprnode, pycparser.c_ast.ID): - raise CDefError("unknown identifier '%s'" % (exprnode.name,)) - return self._get_type_and_quals(exprnode.type) - - def _declare(self, name, obj, included=False, quals=0): - if name in self._declarations: - prevobj, prevquals = self._declarations[name] - if prevobj is obj and prevquals == quals: - return - if not self._options.get('override'): - raise FFIError( - "multiple declarations of %s (for interactive usage, " - "try cdef(xx, override=True))" % (name,)) - assert '__dotdotdot__' not in name.split() - self._declarations[name] = (obj, quals) - if included: - self._included_declarations.add(obj) - - def _extract_quals(self, type): - quals = 0 - if isinstance(type, (pycparser.c_ast.TypeDecl, - pycparser.c_ast.PtrDecl)): - if 'const' in type.quals: - quals |= model.Q_CONST - if 'volatile' in type.quals: - quals |= model.Q_VOLATILE - if 'restrict' in type.quals: - quals |= model.Q_RESTRICT - return quals - - def _get_type_pointer(self, type, quals, declname=None): - if isinstance(type, model.RawFunctionType): - return type.as_function_pointer() - if (isinstance(type, model.StructOrUnionOrEnum) and - type.name.startswith('$') and type.name[1:].isdigit() and - type.forcename is None and declname is not None): - return model.NamedPointerType(type, declname, quals) - return model.PointerType(type, quals) - - def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, - typedef_example=None): - # first, dereference typedefs, if we have it already parsed, we're good - if (isinstance(typenode, pycparser.c_ast.TypeDecl) and - isinstance(typenode.type, pycparser.c_ast.IdentifierType) and - len(typenode.type.names) == 1 and - ('typedef ' + typenode.type.names[0]) in self._declarations): - tp, quals = self._declarations['typedef ' + typenode.type.names[0]] - quals |= self._extract_quals(typenode) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.ArrayDecl): - # array type - if typenode.dim is None: - length = None - else: - length = self._parse_constant( - typenode.dim, partial_length_ok=partial_length_ok) - # a hack: in 'typedef int foo_t[...][...];', don't use '...' as - # the length but use directly the C expression that would be - # generated by recompiler.py. This lets the typedef be used in - # many more places within recompiler.py - if typedef_example is not None: - if length == '...': - length = '_cffi_array_len(%s)' % (typedef_example,) - typedef_example = "*" + typedef_example - # - tp, quals = self._get_type_and_quals(typenode.type, - partial_length_ok=partial_length_ok, - typedef_example=typedef_example) - return model.ArrayType(tp, length), quals - # - if isinstance(typenode, pycparser.c_ast.PtrDecl): - # pointer type - itemtype, itemquals = self._get_type_and_quals(typenode.type) - tp = self._get_type_pointer(itemtype, itemquals, declname=name) - quals = self._extract_quals(typenode) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.TypeDecl): - quals = self._extract_quals(typenode) - type = typenode.type - if isinstance(type, pycparser.c_ast.IdentifierType): - # assume a primitive type. get it from .names, but reduce - # synonyms to a single chosen combination - names = list(type.names) - if names != ['signed', 'char']: # keep this unmodified - prefixes = {} - while names: - name = names[0] - if name in ('short', 'long', 'signed', 'unsigned'): - prefixes[name] = prefixes.get(name, 0) + 1 - del names[0] - else: - break - # ignore the 'signed' prefix below, and reorder the others - newnames = [] - for prefix in ('unsigned', 'short', 'long'): - for i in range(prefixes.get(prefix, 0)): - newnames.append(prefix) - if not names: - names = ['int'] # implicitly - if names == ['int']: # but kill it if 'short' or 'long' - if 'short' in prefixes or 'long' in prefixes: - names = [] - names = newnames + names - ident = ' '.join(names) - if ident == 'void': - return model.void_type, quals - if ident == '__dotdotdot__': - raise FFIError(':%d: bad usage of "..."' % - typenode.coord.line) - tp0, quals0 = resolve_common_type(self, ident) - return tp0, (quals | quals0) - # - if isinstance(type, pycparser.c_ast.Struct): - # 'struct foobar' - tp = self._get_struct_union_enum_type('struct', type, name) - return tp, quals - # - if isinstance(type, pycparser.c_ast.Union): - # 'union foobar' - tp = self._get_struct_union_enum_type('union', type, name) - return tp, quals - # - if isinstance(type, pycparser.c_ast.Enum): - # 'enum foobar' - tp = self._get_struct_union_enum_type('enum', type, name) - return tp, quals - # - if isinstance(typenode, pycparser.c_ast.FuncDecl): - # a function type - return self._parse_function_type(typenode, name), 0 - # - # nested anonymous structs or unions end up here - if isinstance(typenode, pycparser.c_ast.Struct): - return self._get_struct_union_enum_type('struct', typenode, name, - nested=True), 0 - if isinstance(typenode, pycparser.c_ast.Union): - return self._get_struct_union_enum_type('union', typenode, name, - nested=True), 0 - # - raise FFIError(":%d: bad or unsupported type declaration" % - typenode.coord.line) - - def _parse_function_type(self, typenode, funcname=None): - params = list(getattr(typenode.args, 'params', [])) - for i, arg in enumerate(params): - if not hasattr(arg, 'type'): - raise CDefError("%s arg %d: unknown type '%s'" - " (if you meant to use the old C syntax of giving" - " untyped arguments, it is not supported)" - % (funcname or 'in expression', i + 1, - getattr(arg, 'name', '?'))) - ellipsis = ( - len(params) > 0 and - isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and - isinstance(params[-1].type.type, - pycparser.c_ast.IdentifierType) and - params[-1].type.type.names == ['__dotdotdot__']) - if ellipsis: - params.pop() - if not params: - raise CDefError( - "%s: a function with only '(...)' as argument" - " is not correct C" % (funcname or 'in expression')) - args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) - for argdeclnode in params] - if not ellipsis and args == [model.void_type]: - args = [] - result, quals = self._get_type_and_quals(typenode.type) - # the 'quals' on the result type are ignored. HACK: we absure them - # to detect __stdcall functions: we textually replace "__stdcall" - # with "volatile volatile const" above. - abi = None - if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway - if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: - abi = '__stdcall' - return model.RawFunctionType(tuple(args), result, ellipsis, abi) - - def _as_func_arg(self, type, quals): - if isinstance(type, model.ArrayType): - return model.PointerType(type.item, quals) - elif isinstance(type, model.RawFunctionType): - return type.as_function_pointer() - else: - return type - - def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): - # First, a level of caching on the exact 'type' node of the AST. - # This is obscure, but needed because pycparser "unrolls" declarations - # such as "typedef struct { } foo_t, *foo_p" and we end up with - # an AST that is not a tree, but a DAG, with the "type" node of the - # two branches foo_t and foo_p of the trees being the same node. - # It's a bit silly but detecting "DAG-ness" in the AST tree seems - # to be the only way to distinguish this case from two independent - # structs. See test_struct_with_two_usages. - try: - return self._structnode2type[type] - except KeyError: - pass - # - # Note that this must handle parsing "struct foo" any number of - # times and always return the same StructType object. Additionally, - # one of these times (not necessarily the first), the fields of - # the struct can be specified with "struct foo { ...fields... }". - # If no name is given, then we have to create a new anonymous struct - # with no caching; in this case, the fields are either specified - # right now or never. - # - force_name = name - name = type.name - # - # get the type or create it if needed - if name is None: - # 'force_name' is used to guess a more readable name for - # anonymous structs, for the common case "typedef struct { } foo". - if force_name is not None: - explicit_name = '$%s' % force_name - else: - self._anonymous_counter += 1 - explicit_name = '$%d' % self._anonymous_counter - tp = None - else: - explicit_name = name - key = '%s %s' % (kind, name) - tp, _ = self._declarations.get(key, (None, None)) - # - if tp is None: - if kind == 'struct': - tp = model.StructType(explicit_name, None, None, None) - elif kind == 'union': - tp = model.UnionType(explicit_name, None, None, None) - elif kind == 'enum': - if explicit_name == '__dotdotdot__': - raise CDefError("Enums cannot be declared with ...") - tp = self._build_enum_type(explicit_name, type.values) - else: - raise AssertionError("kind = %r" % (kind,)) - if name is not None: - self._declare(key, tp) - else: - if kind == 'enum' and type.values is not None: - raise NotImplementedError( - "enum %s: the '{}' declaration should appear on the first " - "time the enum is mentioned, not later" % explicit_name) - if not tp.forcename: - tp.force_the_name(force_name) - if tp.forcename and '$' in tp.name: - self._declare('anonymous %s' % tp.forcename, tp) - # - self._structnode2type[type] = tp - # - # enums: done here - if kind == 'enum': - return tp - # - # is there a 'type.decls'? If yes, then this is the place in the - # C sources that declare the fields. If no, then just return the - # existing type, possibly still incomplete. - if type.decls is None: - return tp - # - if tp.fldnames is not None: - raise CDefError("duplicate declaration of struct %s" % name) - fldnames = [] - fldtypes = [] - fldbitsize = [] - fldquals = [] - for decl in type.decls: - if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and - ''.join(decl.type.names) == '__dotdotdot__'): - # XXX pycparser is inconsistent: 'names' should be a list - # of strings, but is sometimes just one string. Use - # str.join() as a way to cope with both. - self._make_partial(tp, nested) - continue - if decl.bitsize is None: - bitsize = -1 - else: - bitsize = self._parse_constant(decl.bitsize) - self._partial_length = False - type, fqual = self._get_type_and_quals(decl.type, - partial_length_ok=True) - if self._partial_length: - self._make_partial(tp, nested) - if isinstance(type, model.StructType) and type.partial: - self._make_partial(tp, nested) - fldnames.append(decl.name or '') - fldtypes.append(type) - fldbitsize.append(bitsize) - fldquals.append(fqual) - tp.fldnames = tuple(fldnames) - tp.fldtypes = tuple(fldtypes) - tp.fldbitsize = tuple(fldbitsize) - tp.fldquals = tuple(fldquals) - if fldbitsize != [-1] * len(fldbitsize): - if isinstance(tp, model.StructType) and tp.partial: - raise NotImplementedError("%s: using both bitfields and '...;'" - % (tp,)) - tp.packed = self._options.get('packed') - if tp.completed: # must be re-completed: it is not opaque any more - tp.completed = 0 - self._recomplete.append(tp) - return tp - - def _make_partial(self, tp, nested): - if not isinstance(tp, model.StructOrUnion): - raise CDefError("%s cannot be partial" % (tp,)) - if not tp.has_c_name() and not nested: - raise NotImplementedError("%s is partial but has no C name" %(tp,)) - tp.partial = True - - def _parse_constant(self, exprnode, partial_length_ok=False): - # for now, limited to expressions that are an immediate number - # or positive/negative number - if isinstance(exprnode, pycparser.c_ast.Constant): - s = exprnode.value - if '0' <= s[0] <= '9': - s = s.rstrip('uUlL') - try: - if s.startswith('0'): - return int(s, 8) - else: - return int(s, 10) - except ValueError: - if len(s) > 1: - if s.lower()[0:2] == '0x': - return int(s, 16) - elif s.lower()[0:2] == '0b': - return int(s, 2) - raise CDefError("invalid constant %r" % (s,)) - elif s[0] == "'" and s[-1] == "'" and ( - len(s) == 3 or (len(s) == 4 and s[1] == "\\")): - return ord(s[-2]) - else: - raise CDefError("invalid constant %r" % (s,)) - # - if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and - exprnode.op == '+'): - return self._parse_constant(exprnode.expr) - # - if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and - exprnode.op == '-'): - return -self._parse_constant(exprnode.expr) - # load previously defined int constant - if (isinstance(exprnode, pycparser.c_ast.ID) and - exprnode.name in self._int_constants): - return self._int_constants[exprnode.name] - # - if (isinstance(exprnode, pycparser.c_ast.ID) and - exprnode.name == '__dotdotdotarray__'): - if partial_length_ok: - self._partial_length = True - return '...' - raise FFIError(":%d: unsupported '[...]' here, cannot derive " - "the actual array length in this context" - % exprnode.coord.line) - # - if isinstance(exprnode, pycparser.c_ast.BinaryOp): - left = self._parse_constant(exprnode.left) - right = self._parse_constant(exprnode.right) - if exprnode.op == '+': - return left + right - elif exprnode.op == '-': - return left - right - elif exprnode.op == '*': - return left * right - elif exprnode.op == '/': - return self._c_div(left, right) - elif exprnode.op == '%': - return left - self._c_div(left, right) * right - elif exprnode.op == '<<': - return left << right - elif exprnode.op == '>>': - return left >> right - elif exprnode.op == '&': - return left & right - elif exprnode.op == '|': - return left | right - elif exprnode.op == '^': - return left ^ right - # - raise FFIError(":%d: unsupported expression: expected a " - "simple numeric constant" % exprnode.coord.line) - - def _c_div(self, a, b): - result = a // b - if ((a < 0) ^ (b < 0)) and (a % b) != 0: - result += 1 - return result - - def _build_enum_type(self, explicit_name, decls): - if decls is not None: - partial = False - enumerators = [] - enumvalues = [] - nextenumvalue = 0 - for enum in decls.enumerators: - if _r_enum_dotdotdot.match(enum.name): - partial = True - continue - if enum.value is not None: - nextenumvalue = self._parse_constant(enum.value) - enumerators.append(enum.name) - enumvalues.append(nextenumvalue) - self._add_constants(enum.name, nextenumvalue) - nextenumvalue += 1 - enumerators = tuple(enumerators) - enumvalues = tuple(enumvalues) - tp = model.EnumType(explicit_name, enumerators, enumvalues) - tp.partial = partial - else: # opaque enum - tp = model.EnumType(explicit_name, (), ()) - return tp - - def include(self, other): - for name, (tp, quals) in other._declarations.items(): - if name.startswith('anonymous $enum_$'): - continue # fix for test_anonymous_enum_include - kind = name.split(' ', 1)[0] - if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): - self._declare(name, tp, included=True, quals=quals) - for k, v in other._int_constants.items(): - self._add_constants(k, v) - - def _get_unknown_type(self, decl): - typenames = decl.type.type.names - if typenames == ['__dotdotdot__']: - return model.unknown_type(decl.name) - - if typenames == ['__dotdotdotint__']: - if self._uses_new_feature is None: - self._uses_new_feature = "'typedef int... %s'" % decl.name - return model.UnknownIntegerType(decl.name) - - if typenames == ['__dotdotdotfloat__']: - # note: not for 'long double' so far - if self._uses_new_feature is None: - self._uses_new_feature = "'typedef float... %s'" % decl.name - return model.UnknownFloatType(decl.name) - - raise FFIError(':%d: unsupported usage of "..." in typedef' - % decl.coord.line) - - def _get_unknown_ptr_type(self, decl): - if decl.type.type.type.names == ['__dotdotdot__']: - return model.unknown_ptr_type(decl.name) - raise FFIError(':%d: unsupported usage of "..." in typedef' - % decl.coord.line) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/error.py b/backend/venv39/lib/python3.9/site-packages/cffi/error.py deleted file mode 100644 index 0a27247..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/error.py +++ /dev/null @@ -1,31 +0,0 @@ - -class FFIError(Exception): - __module__ = 'cffi' - -class CDefError(Exception): - __module__ = 'cffi' - def __str__(self): - try: - current_decl = self.args[1] - filename = current_decl.coord.file - linenum = current_decl.coord.line - prefix = '%s:%d: ' % (filename, linenum) - except (AttributeError, TypeError, IndexError): - prefix = '' - return '%s%s' % (prefix, self.args[0]) - -class VerificationError(Exception): - """ An error raised when verification fails - """ - __module__ = 'cffi' - -class VerificationMissing(Exception): - """ An error raised when incomplete structures are passed into - cdef, but no verification has been done - """ - __module__ = 'cffi' - -class PkgConfigError(Exception): - """ An error raised for missing modules in pkg-config - """ - __module__ = 'cffi' diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/ffiplatform.py b/backend/venv39/lib/python3.9/site-packages/cffi/ffiplatform.py deleted file mode 100644 index adca28f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/ffiplatform.py +++ /dev/null @@ -1,113 +0,0 @@ -import sys, os -from .error import VerificationError - - -LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', - 'extra_objects', 'depends'] - -def get_extension(srcfilename, modname, sources=(), **kwds): - from cffi._shimmed_dist_utils import Extension - allsources = [srcfilename] - for src in sources: - allsources.append(os.path.normpath(src)) - return Extension(name=modname, sources=allsources, **kwds) - -def compile(tmpdir, ext, compiler_verbose=0, debug=None): - """Compile a C extension module using distutils.""" - - saved_environ = os.environ.copy() - try: - outputfilename = _build(tmpdir, ext, compiler_verbose, debug) - outputfilename = os.path.abspath(outputfilename) - finally: - # workaround for a distutils bugs where some env vars can - # become longer and longer every time it is used - for key, value in saved_environ.items(): - if os.environ.get(key) != value: - os.environ[key] = value - return outputfilename - -def _build(tmpdir, ext, compiler_verbose=0, debug=None): - # XXX compact but horrible :-( - from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity - - dist = Distribution({'ext_modules': [ext]}) - dist.parse_config_files() - options = dist.get_option_dict('build_ext') - if debug is None: - debug = sys.flags.debug - options['debug'] = ('ffiplatform', debug) - options['force'] = ('ffiplatform', True) - options['build_lib'] = ('ffiplatform', tmpdir) - options['build_temp'] = ('ffiplatform', tmpdir) - # - try: - old_level = set_threshold(0) or 0 - try: - set_verbosity(compiler_verbose) - dist.run_command('build_ext') - cmd_obj = dist.get_command_obj('build_ext') - [soname] = cmd_obj.get_outputs() - finally: - set_threshold(old_level) - except (CompileError, LinkError) as e: - raise VerificationError('%s: %s' % (e.__class__.__name__, e)) - # - return soname - -try: - from os.path import samefile -except ImportError: - def samefile(f1, f2): - return os.path.abspath(f1) == os.path.abspath(f2) - -def maybe_relative_path(path): - if not os.path.isabs(path): - return path # already relative - dir = path - names = [] - while True: - prevdir = dir - dir, name = os.path.split(prevdir) - if dir == prevdir or not dir: - return path # failed to make it relative - names.append(name) - try: - if samefile(dir, os.curdir): - names.reverse() - return os.path.join(*names) - except OSError: - pass - -# ____________________________________________________________ - -try: - int_or_long = (int, long) - import cStringIO -except NameError: - int_or_long = int # Python 3 - import io as cStringIO - -def _flatten(x, f): - if isinstance(x, str): - f.write('%ds%s' % (len(x), x)) - elif isinstance(x, dict): - keys = sorted(x.keys()) - f.write('%dd' % len(keys)) - for key in keys: - _flatten(key, f) - _flatten(x[key], f) - elif isinstance(x, (list, tuple)): - f.write('%dl' % len(x)) - for value in x: - _flatten(value, f) - elif isinstance(x, int_or_long): - f.write('%di' % (x,)) - else: - raise TypeError( - "the keywords to verify() contains unsupported object %r" % (x,)) - -def flatten(x): - f = cStringIO.StringIO() - _flatten(x, f) - return f.getvalue() diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/lock.py b/backend/venv39/lib/python3.9/site-packages/cffi/lock.py deleted file mode 100644 index db91b71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/lock.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys - -if sys.version_info < (3,): - try: - from thread import allocate_lock - except ImportError: - from dummy_thread import allocate_lock -else: - try: - from _thread import allocate_lock - except ImportError: - from _dummy_thread import allocate_lock - - -##import sys -##l1 = allocate_lock - -##class allocate_lock(object): -## def __init__(self): -## self._real = l1() -## def __enter__(self): -## for i in range(4, 0, -1): -## print sys._getframe(i).f_code -## print -## return self._real.__enter__() -## def __exit__(self, *args): -## return self._real.__exit__(*args) -## def acquire(self, f): -## assert f is False -## return self._real.acquire(f) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/model.py b/backend/venv39/lib/python3.9/site-packages/cffi/model.py deleted file mode 100644 index e5f4cae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/model.py +++ /dev/null @@ -1,618 +0,0 @@ -import types -import weakref - -from .lock import allocate_lock -from .error import CDefError, VerificationError, VerificationMissing - -# type qualifiers -Q_CONST = 0x01 -Q_RESTRICT = 0x02 -Q_VOLATILE = 0x04 - -def qualify(quals, replace_with): - if quals & Q_CONST: - replace_with = ' const ' + replace_with.lstrip() - if quals & Q_VOLATILE: - replace_with = ' volatile ' + replace_with.lstrip() - if quals & Q_RESTRICT: - # It seems that __restrict is supported by gcc and msvc. - # If you hit some different compiler, add a #define in - # _cffi_include.h for it (and in its copies, documented there) - replace_with = ' __restrict ' + replace_with.lstrip() - return replace_with - - -class BaseTypeByIdentity(object): - is_array_type = False - is_raw_function = False - - def get_c_name(self, replace_with='', context='a C file', quals=0): - result = self.c_name_with_marker - assert result.count('&') == 1 - # some logic duplication with ffi.getctype()... :-( - replace_with = replace_with.strip() - if replace_with: - if replace_with.startswith('*') and '&[' in result: - replace_with = '(%s)' % replace_with - elif not replace_with[0] in '[(': - replace_with = ' ' + replace_with - replace_with = qualify(quals, replace_with) - result = result.replace('&', replace_with) - if '$' in result: - raise VerificationError( - "cannot generate '%s' in %s: unknown type name" - % (self._get_c_name(), context)) - return result - - def _get_c_name(self): - return self.c_name_with_marker.replace('&', '') - - def has_c_name(self): - return '$' not in self._get_c_name() - - def is_integer_type(self): - return False - - def get_cached_btype(self, ffi, finishlist, can_delay=False): - try: - BType = ffi._cached_btypes[self] - except KeyError: - BType = self.build_backend_type(ffi, finishlist) - BType2 = ffi._cached_btypes.setdefault(self, BType) - assert BType2 is BType - return BType - - def __repr__(self): - return '<%s>' % (self._get_c_name(),) - - def _get_items(self): - return [(name, getattr(self, name)) for name in self._attrs_] - - -class BaseType(BaseTypeByIdentity): - - def __eq__(self, other): - return (self.__class__ == other.__class__ and - self._get_items() == other._get_items()) - - def __ne__(self, other): - return not self == other - - def __hash__(self): - return hash((self.__class__, tuple(self._get_items()))) - - -class VoidType(BaseType): - _attrs_ = () - - def __init__(self): - self.c_name_with_marker = 'void&' - - def build_backend_type(self, ffi, finishlist): - return global_cache(self, ffi, 'new_void_type') - -void_type = VoidType() - - -class BasePrimitiveType(BaseType): - def is_complex_type(self): - return False - - -class PrimitiveType(BasePrimitiveType): - _attrs_ = ('name',) - - ALL_PRIMITIVE_TYPES = { - 'char': 'c', - 'short': 'i', - 'int': 'i', - 'long': 'i', - 'long long': 'i', - 'signed char': 'i', - 'unsigned char': 'i', - 'unsigned short': 'i', - 'unsigned int': 'i', - 'unsigned long': 'i', - 'unsigned long long': 'i', - 'float': 'f', - 'double': 'f', - 'long double': 'f', - '_cffi_float_complex_t': 'j', - '_cffi_double_complex_t': 'j', - '_Bool': 'i', - # the following types are not primitive in the C sense - 'wchar_t': 'c', - 'char16_t': 'c', - 'char32_t': 'c', - 'int8_t': 'i', - 'uint8_t': 'i', - 'int16_t': 'i', - 'uint16_t': 'i', - 'int32_t': 'i', - 'uint32_t': 'i', - 'int64_t': 'i', - 'uint64_t': 'i', - 'int_least8_t': 'i', - 'uint_least8_t': 'i', - 'int_least16_t': 'i', - 'uint_least16_t': 'i', - 'int_least32_t': 'i', - 'uint_least32_t': 'i', - 'int_least64_t': 'i', - 'uint_least64_t': 'i', - 'int_fast8_t': 'i', - 'uint_fast8_t': 'i', - 'int_fast16_t': 'i', - 'uint_fast16_t': 'i', - 'int_fast32_t': 'i', - 'uint_fast32_t': 'i', - 'int_fast64_t': 'i', - 'uint_fast64_t': 'i', - 'intptr_t': 'i', - 'uintptr_t': 'i', - 'intmax_t': 'i', - 'uintmax_t': 'i', - 'ptrdiff_t': 'i', - 'size_t': 'i', - 'ssize_t': 'i', - } - - def __init__(self, name): - assert name in self.ALL_PRIMITIVE_TYPES - self.name = name - self.c_name_with_marker = name + '&' - - def is_char_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' - def is_integer_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' - def is_float_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' - def is_complex_type(self): - return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' - - def build_backend_type(self, ffi, finishlist): - return global_cache(self, ffi, 'new_primitive_type', self.name) - - -class UnknownIntegerType(BasePrimitiveType): - _attrs_ = ('name',) - - def __init__(self, name): - self.name = name - self.c_name_with_marker = name + '&' - - def is_integer_type(self): - return True - - def build_backend_type(self, ffi, finishlist): - raise NotImplementedError("integer type '%s' can only be used after " - "compilation" % self.name) - -class UnknownFloatType(BasePrimitiveType): - _attrs_ = ('name', ) - - def __init__(self, name): - self.name = name - self.c_name_with_marker = name + '&' - - def build_backend_type(self, ffi, finishlist): - raise NotImplementedError("float type '%s' can only be used after " - "compilation" % self.name) - - -class BaseFunctionType(BaseType): - _attrs_ = ('args', 'result', 'ellipsis', 'abi') - - def __init__(self, args, result, ellipsis, abi=None): - self.args = args - self.result = result - self.ellipsis = ellipsis - self.abi = abi - # - reprargs = [arg._get_c_name() for arg in self.args] - if self.ellipsis: - reprargs.append('...') - reprargs = reprargs or ['void'] - replace_with = self._base_pattern % (', '.join(reprargs),) - if abi is not None: - replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] - self.c_name_with_marker = ( - self.result.c_name_with_marker.replace('&', replace_with)) - - -class RawFunctionType(BaseFunctionType): - # Corresponds to a C type like 'int(int)', which is the C type of - # a function, but not a pointer-to-function. The backend has no - # notion of such a type; it's used temporarily by parsing. - _base_pattern = '(&)(%s)' - is_raw_function = True - - def build_backend_type(self, ffi, finishlist): - raise CDefError("cannot render the type %r: it is a function " - "type, not a pointer-to-function type" % (self,)) - - def as_function_pointer(self): - return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) - - -class FunctionPtrType(BaseFunctionType): - _base_pattern = '(*&)(%s)' - - def build_backend_type(self, ffi, finishlist): - result = self.result.get_cached_btype(ffi, finishlist) - args = [] - for tp in self.args: - args.append(tp.get_cached_btype(ffi, finishlist)) - abi_args = () - if self.abi == "__stdcall": - if not self.ellipsis: # __stdcall ignored for variadic funcs - try: - abi_args = (ffi._backend.FFI_STDCALL,) - except AttributeError: - pass - return global_cache(self, ffi, 'new_function_type', - tuple(args), result, self.ellipsis, *abi_args) - - def as_raw_function(self): - return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) - - -class PointerType(BaseType): - _attrs_ = ('totype', 'quals') - - def __init__(self, totype, quals=0): - self.totype = totype - self.quals = quals - extra = " *&" - if totype.is_array_type: - extra = "(%s)" % (extra.lstrip(),) - extra = qualify(quals, extra) - self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) - - def build_backend_type(self, ffi, finishlist): - BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) - return global_cache(self, ffi, 'new_pointer_type', BItem) - -voidp_type = PointerType(void_type) - -def ConstPointerType(totype): - return PointerType(totype, Q_CONST) - -const_voidp_type = ConstPointerType(void_type) - - -class NamedPointerType(PointerType): - _attrs_ = ('totype', 'name') - - def __init__(self, totype, name, quals=0): - PointerType.__init__(self, totype, quals) - self.name = name - self.c_name_with_marker = name + '&' - - -class ArrayType(BaseType): - _attrs_ = ('item', 'length') - is_array_type = True - - def __init__(self, item, length): - self.item = item - self.length = length - # - if length is None: - brackets = '&[]' - elif length == '...': - brackets = '&[/*...*/]' - else: - brackets = '&[%s]' % length - self.c_name_with_marker = ( - self.item.c_name_with_marker.replace('&', brackets)) - - def length_is_unknown(self): - return isinstance(self.length, str) - - def resolve_length(self, newlength): - return ArrayType(self.item, newlength) - - def build_backend_type(self, ffi, finishlist): - if self.length_is_unknown(): - raise CDefError("cannot render the type %r: unknown length" % - (self,)) - self.item.get_cached_btype(ffi, finishlist) # force the item BType - BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) - return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) - -char_array_type = ArrayType(PrimitiveType('char'), None) - - -class StructOrUnionOrEnum(BaseTypeByIdentity): - _attrs_ = ('name',) - forcename = None - - def build_c_name_with_marker(self): - name = self.forcename or '%s %s' % (self.kind, self.name) - self.c_name_with_marker = name + '&' - - def force_the_name(self, forcename): - self.forcename = forcename - self.build_c_name_with_marker() - - def get_official_name(self): - assert self.c_name_with_marker.endswith('&') - return self.c_name_with_marker[:-1] - - -class StructOrUnion(StructOrUnionOrEnum): - fixedlayout = None - completed = 0 - partial = False - packed = 0 - - def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): - self.name = name - self.fldnames = fldnames - self.fldtypes = fldtypes - self.fldbitsize = fldbitsize - self.fldquals = fldquals - self.build_c_name_with_marker() - - def anonymous_struct_fields(self): - if self.fldtypes is not None: - for name, type in zip(self.fldnames, self.fldtypes): - if name == '' and isinstance(type, StructOrUnion): - yield type - - def enumfields(self, expand_anonymous_struct_union=True): - fldquals = self.fldquals - if fldquals is None: - fldquals = (0,) * len(self.fldnames) - for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, - self.fldbitsize, fldquals): - if (name == '' and isinstance(type, StructOrUnion) - and expand_anonymous_struct_union): - # nested anonymous struct/union - for result in type.enumfields(): - yield result - else: - yield (name, type, bitsize, quals) - - def force_flatten(self): - # force the struct or union to have a declaration that lists - # directly all fields returned by enumfields(), flattening - # nested anonymous structs/unions. - names = [] - types = [] - bitsizes = [] - fldquals = [] - for name, type, bitsize, quals in self.enumfields(): - names.append(name) - types.append(type) - bitsizes.append(bitsize) - fldquals.append(quals) - self.fldnames = tuple(names) - self.fldtypes = tuple(types) - self.fldbitsize = tuple(bitsizes) - self.fldquals = tuple(fldquals) - - def get_cached_btype(self, ffi, finishlist, can_delay=False): - BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, - can_delay) - if not can_delay: - self.finish_backend_type(ffi, finishlist) - return BType - - def finish_backend_type(self, ffi, finishlist): - if self.completed: - if self.completed != 2: - raise NotImplementedError("recursive structure declaration " - "for '%s'" % (self.name,)) - return - BType = ffi._cached_btypes[self] - # - self.completed = 1 - # - if self.fldtypes is None: - pass # not completing it: it's an opaque struct - # - elif self.fixedlayout is None: - fldtypes = [tp.get_cached_btype(ffi, finishlist) - for tp in self.fldtypes] - lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) - extra_flags = () - if self.packed: - if self.packed == 1: - extra_flags = (8,) # SF_PACKED - else: - extra_flags = (0, self.packed) - ffi._backend.complete_struct_or_union(BType, lst, self, - -1, -1, *extra_flags) - # - else: - fldtypes = [] - fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout - for i in range(len(self.fldnames)): - fsize = fieldsize[i] - ftype = self.fldtypes[i] - # - if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): - # fix the length to match the total size - BItemType = ftype.item.get_cached_btype(ffi, finishlist) - nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) - if nrest != 0: - self._verification_error( - "field '%s.%s' has a bogus size?" % ( - self.name, self.fldnames[i] or '{}')) - ftype = ftype.resolve_length(nlen) - self.fldtypes = (self.fldtypes[:i] + (ftype,) + - self.fldtypes[i+1:]) - # - BFieldType = ftype.get_cached_btype(ffi, finishlist) - if isinstance(ftype, ArrayType) and ftype.length is None: - assert fsize == 0 - else: - bitemsize = ffi.sizeof(BFieldType) - if bitemsize != fsize: - self._verification_error( - "field '%s.%s' is declared as %d bytes, but is " - "really %d bytes" % (self.name, - self.fldnames[i] or '{}', - bitemsize, fsize)) - fldtypes.append(BFieldType) - # - lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) - ffi._backend.complete_struct_or_union(BType, lst, self, - totalsize, totalalignment) - self.completed = 2 - - def _verification_error(self, msg): - raise VerificationError(msg) - - def check_not_partial(self): - if self.partial and self.fixedlayout is None: - raise VerificationMissing(self._get_c_name()) - - def build_backend_type(self, ffi, finishlist): - self.check_not_partial() - finishlist.append(self) - # - return global_cache(self, ffi, 'new_%s_type' % self.kind, - self.get_official_name(), key=self) - - -class StructType(StructOrUnion): - kind = 'struct' - - -class UnionType(StructOrUnion): - kind = 'union' - - -class EnumType(StructOrUnionOrEnum): - kind = 'enum' - partial = False - partial_resolved = False - - def __init__(self, name, enumerators, enumvalues, baseinttype=None): - self.name = name - self.enumerators = enumerators - self.enumvalues = enumvalues - self.baseinttype = baseinttype - self.build_c_name_with_marker() - - def force_the_name(self, forcename): - StructOrUnionOrEnum.force_the_name(self, forcename) - if self.forcename is None: - name = self.get_official_name() - self.forcename = '$' + name.replace(' ', '_') - - def check_not_partial(self): - if self.partial and not self.partial_resolved: - raise VerificationMissing(self._get_c_name()) - - def build_backend_type(self, ffi, finishlist): - self.check_not_partial() - base_btype = self.build_baseinttype(ffi, finishlist) - return global_cache(self, ffi, 'new_enum_type', - self.get_official_name(), - self.enumerators, self.enumvalues, - base_btype, key=self) - - def build_baseinttype(self, ffi, finishlist): - if self.baseinttype is not None: - return self.baseinttype.get_cached_btype(ffi, finishlist) - # - if self.enumvalues: - smallest_value = min(self.enumvalues) - largest_value = max(self.enumvalues) - else: - import warnings - try: - # XXX! The goal is to ensure that the warnings.warn() - # will not suppress the warning. We want to get it - # several times if we reach this point several times. - __warningregistry__.clear() - except NameError: - pass - warnings.warn("%r has no values explicitly defined; " - "guessing that it is equivalent to 'unsigned int'" - % self._get_c_name()) - smallest_value = largest_value = 0 - if smallest_value < 0: # needs a signed type - sign = 1 - candidate1 = PrimitiveType("int") - candidate2 = PrimitiveType("long") - else: - sign = 0 - candidate1 = PrimitiveType("unsigned int") - candidate2 = PrimitiveType("unsigned long") - btype1 = candidate1.get_cached_btype(ffi, finishlist) - btype2 = candidate2.get_cached_btype(ffi, finishlist) - size1 = ffi.sizeof(btype1) - size2 = ffi.sizeof(btype2) - if (smallest_value >= ((-1) << (8*size1-1)) and - largest_value < (1 << (8*size1-sign))): - return btype1 - if (smallest_value >= ((-1) << (8*size2-1)) and - largest_value < (1 << (8*size2-sign))): - return btype2 - raise CDefError("%s values don't all fit into either 'long' " - "or 'unsigned long'" % self._get_c_name()) - -def unknown_type(name, structname=None): - if structname is None: - structname = '$%s' % name - tp = StructType(structname, None, None, None) - tp.force_the_name(name) - tp.origin = "unknown_type" - return tp - -def unknown_ptr_type(name, structname=None): - if structname is None: - structname = '$$%s' % name - tp = StructType(structname, None, None, None) - return NamedPointerType(tp, name) - - -global_lock = allocate_lock() -_typecache_cffi_backend = weakref.WeakValueDictionary() - -def get_typecache(backend): - # returns _typecache_cffi_backend if backend is the _cffi_backend - # module, or type(backend).__typecache if backend is an instance of - # CTypesBackend (or some FakeBackend class during tests) - if isinstance(backend, types.ModuleType): - return _typecache_cffi_backend - with global_lock: - if not hasattr(type(backend), '__typecache'): - type(backend).__typecache = weakref.WeakValueDictionary() - return type(backend).__typecache - -def global_cache(srctype, ffi, funcname, *args, **kwds): - key = kwds.pop('key', (funcname, args)) - assert not kwds - try: - return ffi._typecache[key] - except KeyError: - pass - try: - res = getattr(ffi._backend, funcname)(*args) - except NotImplementedError as e: - raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) - # note that setdefault() on WeakValueDictionary is not atomic - # and contains a rare bug (http://bugs.python.org/issue19542); - # we have to use a lock and do it ourselves - cache = ffi._typecache - with global_lock: - res1 = cache.get(key) - if res1 is None: - cache[key] = res - return res - else: - return res1 - -def pointer_cache(ffi, BType): - return global_cache('?', ffi, 'new_pointer_type', BType) - -def attach_exception_info(e, name): - if e.args and type(e.args[0]) is str: - e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/parse_c_type.h b/backend/venv39/lib/python3.9/site-packages/cffi/parse_c_type.h deleted file mode 100644 index 84e4ef8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/parse_c_type.h +++ /dev/null @@ -1,181 +0,0 @@ - -/* This part is from file 'cffi/parse_c_type.h'. It is copied at the - beginning of C sources generated by CFFI's ffi.set_source(). */ - -typedef void *_cffi_opcode_t; - -#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) -#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) -#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) - -#define _CFFI_OP_PRIMITIVE 1 -#define _CFFI_OP_POINTER 3 -#define _CFFI_OP_ARRAY 5 -#define _CFFI_OP_OPEN_ARRAY 7 -#define _CFFI_OP_STRUCT_UNION 9 -#define _CFFI_OP_ENUM 11 -#define _CFFI_OP_FUNCTION 13 -#define _CFFI_OP_FUNCTION_END 15 -#define _CFFI_OP_NOOP 17 -#define _CFFI_OP_BITFIELD 19 -#define _CFFI_OP_TYPENAME 21 -#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs -#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs -#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) -#define _CFFI_OP_CONSTANT 29 -#define _CFFI_OP_CONSTANT_INT 31 -#define _CFFI_OP_GLOBAL_VAR 33 -#define _CFFI_OP_DLOPEN_FUNC 35 -#define _CFFI_OP_DLOPEN_CONST 37 -#define _CFFI_OP_GLOBAL_VAR_F 39 -#define _CFFI_OP_EXTERN_PYTHON 41 - -#define _CFFI_PRIM_VOID 0 -#define _CFFI_PRIM_BOOL 1 -#define _CFFI_PRIM_CHAR 2 -#define _CFFI_PRIM_SCHAR 3 -#define _CFFI_PRIM_UCHAR 4 -#define _CFFI_PRIM_SHORT 5 -#define _CFFI_PRIM_USHORT 6 -#define _CFFI_PRIM_INT 7 -#define _CFFI_PRIM_UINT 8 -#define _CFFI_PRIM_LONG 9 -#define _CFFI_PRIM_ULONG 10 -#define _CFFI_PRIM_LONGLONG 11 -#define _CFFI_PRIM_ULONGLONG 12 -#define _CFFI_PRIM_FLOAT 13 -#define _CFFI_PRIM_DOUBLE 14 -#define _CFFI_PRIM_LONGDOUBLE 15 - -#define _CFFI_PRIM_WCHAR 16 -#define _CFFI_PRIM_INT8 17 -#define _CFFI_PRIM_UINT8 18 -#define _CFFI_PRIM_INT16 19 -#define _CFFI_PRIM_UINT16 20 -#define _CFFI_PRIM_INT32 21 -#define _CFFI_PRIM_UINT32 22 -#define _CFFI_PRIM_INT64 23 -#define _CFFI_PRIM_UINT64 24 -#define _CFFI_PRIM_INTPTR 25 -#define _CFFI_PRIM_UINTPTR 26 -#define _CFFI_PRIM_PTRDIFF 27 -#define _CFFI_PRIM_SIZE 28 -#define _CFFI_PRIM_SSIZE 29 -#define _CFFI_PRIM_INT_LEAST8 30 -#define _CFFI_PRIM_UINT_LEAST8 31 -#define _CFFI_PRIM_INT_LEAST16 32 -#define _CFFI_PRIM_UINT_LEAST16 33 -#define _CFFI_PRIM_INT_LEAST32 34 -#define _CFFI_PRIM_UINT_LEAST32 35 -#define _CFFI_PRIM_INT_LEAST64 36 -#define _CFFI_PRIM_UINT_LEAST64 37 -#define _CFFI_PRIM_INT_FAST8 38 -#define _CFFI_PRIM_UINT_FAST8 39 -#define _CFFI_PRIM_INT_FAST16 40 -#define _CFFI_PRIM_UINT_FAST16 41 -#define _CFFI_PRIM_INT_FAST32 42 -#define _CFFI_PRIM_UINT_FAST32 43 -#define _CFFI_PRIM_INT_FAST64 44 -#define _CFFI_PRIM_UINT_FAST64 45 -#define _CFFI_PRIM_INTMAX 46 -#define _CFFI_PRIM_UINTMAX 47 -#define _CFFI_PRIM_FLOATCOMPLEX 48 -#define _CFFI_PRIM_DOUBLECOMPLEX 49 -#define _CFFI_PRIM_CHAR16 50 -#define _CFFI_PRIM_CHAR32 51 - -#define _CFFI__NUM_PRIM 52 -#define _CFFI__UNKNOWN_PRIM (-1) -#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) -#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) - -#define _CFFI__IO_FILE_STRUCT (-1) - - -struct _cffi_global_s { - const char *name; - void *address; - _cffi_opcode_t type_op; - void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown - // OP_CPYTHON_BLTN_*: addr of direct function -}; - -struct _cffi_getconst_s { - unsigned long long value; - const struct _cffi_type_context_s *ctx; - int gindex; -}; - -struct _cffi_struct_union_s { - const char *name; - int type_index; // -> _cffi_types, on a OP_STRUCT_UNION - int flags; // _CFFI_F_* flags below - size_t size; - int alignment; - int first_field_index; // -> _cffi_fields array - int num_fields; -}; -#define _CFFI_F_UNION 0x01 // is a union, not a struct -#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the - // "standard layout" or if some are missing -#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct -#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() -#define _CFFI_F_OPAQUE 0x10 // opaque - -struct _cffi_field_s { - const char *name; - size_t field_offset; - size_t field_size; - _cffi_opcode_t field_type_op; -}; - -struct _cffi_enum_s { - const char *name; - int type_index; // -> _cffi_types, on a OP_ENUM - int type_prim; // _CFFI_PRIM_xxx - const char *enumerators; // comma-delimited string -}; - -struct _cffi_typename_s { - const char *name; - int type_index; /* if opaque, points to a possibly artificial - OP_STRUCT which is itself opaque */ -}; - -struct _cffi_type_context_s { - _cffi_opcode_t *types; - const struct _cffi_global_s *globals; - const struct _cffi_field_s *fields; - const struct _cffi_struct_union_s *struct_unions; - const struct _cffi_enum_s *enums; - const struct _cffi_typename_s *typenames; - int num_globals; - int num_struct_unions; - int num_enums; - int num_typenames; - const char *const *includes; - int num_types; - int flags; /* future extension */ -}; - -struct _cffi_parse_info_s { - const struct _cffi_type_context_s *ctx; - _cffi_opcode_t *output; - unsigned int output_size; - size_t error_location; - const char *error_message; -}; - -struct _cffi_externpy_s { - const char *name; - size_t size_of_result; - void *reserved1, *reserved2; -}; - -#ifdef _CFFI_INTERNAL -static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); -static int search_in_globals(const struct _cffi_type_context_s *ctx, - const char *search, size_t search_len); -static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, - const char *search, size_t search_len); -#endif diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/pkgconfig.py b/backend/venv39/lib/python3.9/site-packages/cffi/pkgconfig.py deleted file mode 100644 index 5c93f15..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/pkgconfig.py +++ /dev/null @@ -1,121 +0,0 @@ -# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi -import sys, os, subprocess - -from .error import PkgConfigError - - -def merge_flags(cfg1, cfg2): - """Merge values from cffi config flags cfg2 to cf1 - - Example: - merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) - {"libraries": ["one", "two"]} - """ - for key, value in cfg2.items(): - if key not in cfg1: - cfg1[key] = value - else: - if not isinstance(cfg1[key], list): - raise TypeError("cfg1[%r] should be a list of strings" % (key,)) - if not isinstance(value, list): - raise TypeError("cfg2[%r] should be a list of strings" % (key,)) - cfg1[key].extend(value) - return cfg1 - - -def call(libname, flag, encoding=sys.getfilesystemencoding()): - """Calls pkg-config and returns the output if found - """ - a = ["pkg-config", "--print-errors"] - a.append(flag) - a.append(libname) - try: - pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except EnvironmentError as e: - raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) - - bout, berr = pc.communicate() - if pc.returncode != 0: - try: - berr = berr.decode(encoding) - except Exception: - pass - raise PkgConfigError(berr.strip()) - - if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x - try: - bout = bout.decode(encoding) - except UnicodeDecodeError: - raise PkgConfigError("pkg-config %s %s returned bytes that cannot " - "be decoded with encoding %r:\n%r" % - (flag, libname, encoding, bout)) - - if os.altsep != '\\' and '\\' in bout: - raise PkgConfigError("pkg-config %s %s returned an unsupported " - "backslash-escaped output:\n%r" % - (flag, libname, bout)) - return bout - - -def flags_from_pkgconfig(libs): - r"""Return compiler line flags for FFI.set_source based on pkg-config output - - Usage - ... - ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) - - If pkg-config is installed on build machine, then arguments include_dirs, - library_dirs, libraries, define_macros, extra_compile_args and - extra_link_args are extended with an output of pkg-config for libfoo and - libbar. - - Raises PkgConfigError in case the pkg-config call fails. - """ - - def get_include_dirs(string): - return [x[2:] for x in string.split() if x.startswith("-I")] - - def get_library_dirs(string): - return [x[2:] for x in string.split() if x.startswith("-L")] - - def get_libraries(string): - return [x[2:] for x in string.split() if x.startswith("-l")] - - # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils - def get_macros(string): - def _macro(x): - x = x[2:] # drop "-D" - if '=' in x: - return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") - else: - return (x, None) # "-Dfoo" => ("foo", None) - return [_macro(x) for x in string.split() if x.startswith("-D")] - - def get_other_cflags(string): - return [x for x in string.split() if not x.startswith("-I") and - not x.startswith("-D")] - - def get_other_libs(string): - return [x for x in string.split() if not x.startswith("-L") and - not x.startswith("-l")] - - # return kwargs for given libname - def kwargs(libname): - fse = sys.getfilesystemencoding() - all_cflags = call(libname, "--cflags") - all_libs = call(libname, "--libs") - return { - "include_dirs": get_include_dirs(all_cflags), - "library_dirs": get_library_dirs(all_libs), - "libraries": get_libraries(all_libs), - "define_macros": get_macros(all_cflags), - "extra_compile_args": get_other_cflags(all_cflags), - "extra_link_args": get_other_libs(all_libs), - } - - # merge all arguments together - ret = {} - for libname in libs: - lib_flags = kwargs(libname) - merge_flags(ret, lib_flags) - return ret diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/recompiler.py b/backend/venv39/lib/python3.9/site-packages/cffi/recompiler.py deleted file mode 100644 index 7734a34..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/recompiler.py +++ /dev/null @@ -1,1598 +0,0 @@ -import io, os, sys, sysconfig -from . import ffiplatform, model -from .error import VerificationError -from .cffi_opcode import * - -VERSION_BASE = 0x2601 -VERSION_EMBEDDED = 0x2701 -VERSION_CHAR16CHAR32 = 0x2801 - -USE_LIMITED_API = ((sys.platform != 'win32' or sys.version_info < (3, 0) or - sys.version_info >= (3, 5)) and - not sysconfig.get_config_var("Py_GIL_DISABLED")) # free-threaded doesn't yet support limited API - -class GlobalExpr: - def __init__(self, name, address, type_op, size=0, check_value=0): - self.name = name - self.address = address - self.type_op = type_op - self.size = size - self.check_value = check_value - - def as_c_expr(self): - return ' { "%s", (void *)%s, %s, (void *)%s },' % ( - self.name, self.address, self.type_op.as_c_expr(), self.size) - - def as_python_expr(self): - return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, - self.check_value) - -class FieldExpr: - def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): - self.name = name - self.field_offset = field_offset - self.field_size = field_size - self.fbitsize = fbitsize - self.field_type_op = field_type_op - - def as_c_expr(self): - spaces = " " * len(self.name) - return (' { "%s", %s,\n' % (self.name, self.field_offset) + - ' %s %s,\n' % (spaces, self.field_size) + - ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) - - def as_python_expr(self): - raise NotImplementedError - - def as_field_python_expr(self): - if self.field_type_op.op == OP_NOOP: - size_expr = '' - elif self.field_type_op.op == OP_BITFIELD: - size_expr = format_four_bytes(self.fbitsize) - else: - raise NotImplementedError - return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), - size_expr, - self.name) - -class StructUnionExpr: - def __init__(self, name, type_index, flags, size, alignment, comment, - first_field_index, c_fields): - self.name = name - self.type_index = type_index - self.flags = flags - self.size = size - self.alignment = alignment - self.comment = comment - self.first_field_index = first_field_index - self.c_fields = c_fields - - def as_c_expr(self): - return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) - + '\n %s, %s, ' % (self.size, self.alignment) - + '%d, %d ' % (self.first_field_index, len(self.c_fields)) - + ('/* %s */ ' % self.comment if self.comment else '') - + '},') - - def as_python_expr(self): - flags = eval(self.flags, G_FLAGS) - fields_expr = [c_field.as_field_python_expr() - for c_field in self.c_fields] - return "(b'%s%s%s',%s)" % ( - format_four_bytes(self.type_index), - format_four_bytes(flags), - self.name, - ','.join(fields_expr)) - -class EnumExpr: - def __init__(self, name, type_index, size, signed, allenums): - self.name = name - self.type_index = type_index - self.size = size - self.signed = signed - self.allenums = allenums - - def as_c_expr(self): - return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' - ' "%s" },' % (self.name, self.type_index, - self.size, self.signed, self.allenums)) - - def as_python_expr(self): - prim_index = { - (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, - (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, - (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, - (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, - }[self.size, self.signed] - return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), - format_four_bytes(prim_index), - self.name, self.allenums) - -class TypenameExpr: - def __init__(self, name, type_index): - self.name = name - self.type_index = type_index - - def as_c_expr(self): - return ' { "%s", %d },' % (self.name, self.type_index) - - def as_python_expr(self): - return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) - - -# ____________________________________________________________ - - -class Recompiler: - _num_externpy = 0 - - def __init__(self, ffi, module_name, target_is_python=False): - self.ffi = ffi - self.module_name = module_name - self.target_is_python = target_is_python - self._version = VERSION_BASE - - def needs_version(self, ver): - self._version = max(self._version, ver) - - def collect_type_table(self): - self._typesdict = {} - self._generate("collecttype") - # - all_decls = sorted(self._typesdict, key=str) - # - # prepare all FUNCTION bytecode sequences first - self.cffi_types = [] - for tp in all_decls: - if tp.is_raw_function: - assert self._typesdict[tp] is None - self._typesdict[tp] = len(self.cffi_types) - self.cffi_types.append(tp) # placeholder - for tp1 in tp.args: - assert isinstance(tp1, (model.VoidType, - model.BasePrimitiveType, - model.PointerType, - model.StructOrUnionOrEnum, - model.FunctionPtrType)) - if self._typesdict[tp1] is None: - self._typesdict[tp1] = len(self.cffi_types) - self.cffi_types.append(tp1) # placeholder - self.cffi_types.append('END') # placeholder - # - # prepare all OTHER bytecode sequences - for tp in all_decls: - if not tp.is_raw_function and self._typesdict[tp] is None: - self._typesdict[tp] = len(self.cffi_types) - self.cffi_types.append(tp) # placeholder - if tp.is_array_type and tp.length is not None: - self.cffi_types.append('LEN') # placeholder - assert None not in self._typesdict.values() - # - # collect all structs and unions and enums - self._struct_unions = {} - self._enums = {} - for tp in all_decls: - if isinstance(tp, model.StructOrUnion): - self._struct_unions[tp] = None - elif isinstance(tp, model.EnumType): - self._enums[tp] = None - for i, tp in enumerate(sorted(self._struct_unions, - key=lambda tp: tp.name)): - self._struct_unions[tp] = i - for i, tp in enumerate(sorted(self._enums, - key=lambda tp: tp.name)): - self._enums[tp] = i - # - # emit all bytecode sequences now - for tp in all_decls: - method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) - method(tp, self._typesdict[tp]) - # - # consistency check - for op in self.cffi_types: - assert isinstance(op, CffiOp) - self.cffi_types = tuple(self.cffi_types) # don't change any more - - def _enum_fields(self, tp): - # When producing C, expand all anonymous struct/union fields. - # That's necessary to have C code checking the offsets of the - # individual fields contained in them. When producing Python, - # don't do it and instead write it like it is, with the - # corresponding fields having an empty name. Empty names are - # recognized at runtime when we import the generated Python - # file. - expand_anonymous_struct_union = not self.target_is_python - return tp.enumfields(expand_anonymous_struct_union) - - def _do_collect_type(self, tp): - if not isinstance(tp, model.BaseTypeByIdentity): - if isinstance(tp, tuple): - for x in tp: - self._do_collect_type(x) - return - if tp not in self._typesdict: - self._typesdict[tp] = None - if isinstance(tp, model.FunctionPtrType): - self._do_collect_type(tp.as_raw_function()) - elif isinstance(tp, model.StructOrUnion): - if tp.fldtypes is not None and ( - tp not in self.ffi._parser._included_declarations): - for name1, tp1, _, _ in self._enum_fields(tp): - self._do_collect_type(self._field_type(tp, name1, tp1)) - else: - for _, x in tp._get_items(): - self._do_collect_type(x) - - def _generate(self, step_name): - lst = self.ffi._parser._declarations.items() - for name, (tp, quals) in sorted(lst): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_cpy_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in recompile(): %r" % name) - try: - self._current_quals = quals - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - # ---------- - - ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] - - def collect_step_tables(self): - # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. - self._lsts = {} - for step_name in self.ALL_STEPS: - self._lsts[step_name] = [] - self._seen_struct_unions = set() - self._generate("ctx") - self._add_missing_struct_unions() - # - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - if step_name != "field": - lst.sort(key=lambda entry: entry.name) - self._lsts[step_name] = tuple(lst) # don't change any more - # - # check for a possible internal inconsistency: _cffi_struct_unions - # should have been generated with exactly self._struct_unions - lst = self._lsts["struct_union"] - for tp, i in self._struct_unions.items(): - assert i < len(lst) - assert lst[i].name == tp.name - assert len(lst) == len(self._struct_unions) - # same with enums - lst = self._lsts["enum"] - for tp, i in self._enums.items(): - assert i < len(lst) - assert lst[i].name == tp.name - assert len(lst) == len(self._enums) - - # ---------- - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def write_source_to_f(self, f, preamble): - if self.target_is_python: - assert preamble is None - self.write_py_source_to_f(f) - else: - assert preamble is not None - self.write_c_source_to_f(f, preamble) - - def _rel_readlines(self, filename): - g = open(os.path.join(os.path.dirname(__file__), filename), 'r') - lines = g.readlines() - g.close() - return lines - - def write_c_source_to_f(self, f, preamble): - self._f = f - prnt = self._prnt - if self.ffi._embedding is not None: - prnt('#define _CFFI_USE_EMBEDDING') - if not USE_LIMITED_API: - prnt('#define _CFFI_NO_LIMITED_API') - # - # first the '#include' (actually done by inlining the file's content) - lines = self._rel_readlines('_cffi_include.h') - i = lines.index('#include "parse_c_type.h"\n') - lines[i:i+1] = self._rel_readlines('parse_c_type.h') - prnt(''.join(lines)) - # - # if we have ffi._embedding != None, we give it here as a macro - # and include an extra file - base_module_name = self.module_name.split('.')[-1] - if self.ffi._embedding is not None: - prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) - prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') - self._print_string_literal_in_array(self.ffi._embedding) - prnt('0 };') - prnt('#ifdef PYPY_VERSION') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( - base_module_name,)) - prnt('#elif PY_MAJOR_VERSION >= 3') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( - base_module_name,)) - prnt('#else') - prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( - base_module_name,)) - prnt('#endif') - lines = self._rel_readlines('_embedding.h') - i = lines.index('#include "_cffi_errors.h"\n') - lines[i:i+1] = self._rel_readlines('_cffi_errors.h') - prnt(''.join(lines)) - self.needs_version(VERSION_EMBEDDED) - # - # then paste the C source given by the user, verbatim. - prnt('/************************************************************/') - prnt() - prnt(preamble) - prnt() - prnt('/************************************************************/') - prnt() - # - # the declaration of '_cffi_types' - prnt('static void *_cffi_types[] = {') - typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) - for i, op in enumerate(self.cffi_types): - comment = '' - if i in typeindex2type: - comment = ' // ' + typeindex2type[i]._get_c_name() - prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) - if not self.cffi_types: - prnt(' 0') - prnt('};') - prnt() - # - # call generate_cpy_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._seen_constants = set() - self._generate("decl") - # - # the declaration of '_cffi_globals' and '_cffi_typenames' - nums = {} - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - nums[step_name] = len(lst) - if nums[step_name] > 0: - prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( - step_name, step_name)) - for entry in lst: - prnt(entry.as_c_expr()) - prnt('};') - prnt() - # - # the declaration of '_cffi_includes' - if self.ffi._included_ffis: - prnt('static const char * const _cffi_includes[] = {') - for ffi_to_include in self.ffi._included_ffis: - try: - included_module_name, included_source = ( - ffi_to_include._assigned_source[:2]) - except AttributeError: - raise VerificationError( - "ffi object %r includes %r, but the latter has not " - "been prepared with set_source()" % ( - self.ffi, ffi_to_include,)) - if included_source is None: - raise VerificationError( - "not implemented yet: ffi.include() of a Python-based " - "ffi inside a C-based ffi") - prnt(' "%s",' % (included_module_name,)) - prnt(' NULL') - prnt('};') - prnt() - # - # the declaration of '_cffi_type_context' - prnt('static const struct _cffi_type_context_s _cffi_type_context = {') - prnt(' _cffi_types,') - for step_name in self.ALL_STEPS: - if nums[step_name] > 0: - prnt(' _cffi_%ss,' % step_name) - else: - prnt(' NULL, /* no %ss */' % step_name) - for step_name in self.ALL_STEPS: - if step_name != "field": - prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) - if self.ffi._included_ffis: - prnt(' _cffi_includes,') - else: - prnt(' NULL, /* no includes */') - prnt(' %d, /* num_types */' % (len(self.cffi_types),)) - flags = 0 - if self._num_externpy > 0 or self.ffi._embedding is not None: - flags |= 1 # set to mean that we use extern "Python" - prnt(' %d, /* flags */' % flags) - prnt('};') - prnt() - # - # the init function - prnt('#ifdef __GNUC__') - prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') - prnt('#endif') - prnt() - prnt('#ifdef PYPY_VERSION') - prnt('PyMODINIT_FUNC') - prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) - prnt('{') - if flags & 1: - prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') - prnt(' _cffi_call_python_org = ' - '(void(*)(struct _cffi_externpy_s *, char *))p[1];') - prnt(' }') - prnt(' p[0] = (const void *)0x%x;' % self._version) - prnt(' p[1] = &_cffi_type_context;') - prnt('#if PY_MAJOR_VERSION >= 3') - prnt(' return NULL;') - prnt('#endif') - prnt('}') - # on Windows, distutils insists on putting init_cffi_xyz in - # 'export_symbols', so instead of fighting it, just give up and - # give it one - prnt('# ifdef _MSC_VER') - prnt(' PyMODINIT_FUNC') - prnt('# if PY_MAJOR_VERSION >= 3') - prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) - prnt('# else') - prnt(' init%s(void) { }' % (base_module_name,)) - prnt('# endif') - prnt('# endif') - prnt('#elif PY_MAJOR_VERSION >= 3') - prnt('PyMODINIT_FUNC') - prnt('PyInit_%s(void)' % (base_module_name,)) - prnt('{') - prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( - self.module_name, self._version)) - prnt('}') - prnt('#else') - prnt('PyMODINIT_FUNC') - prnt('init%s(void)' % (base_module_name,)) - prnt('{') - prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( - self.module_name, self._version)) - prnt('}') - prnt('#endif') - prnt() - prnt('#ifdef __GNUC__') - prnt('# pragma GCC visibility pop') - prnt('#endif') - self._version = None - - def _to_py(self, x): - if isinstance(x, str): - return "b'%s'" % (x,) - if isinstance(x, (list, tuple)): - rep = [self._to_py(item) for item in x] - if len(rep) == 1: - rep.append('') - return "(%s)" % (','.join(rep),) - return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. - - def write_py_source_to_f(self, f): - self._f = f - prnt = self._prnt - # - # header - prnt("# auto-generated file") - prnt("import _cffi_backend") - # - # the 'import' of the included ffis - num_includes = len(self.ffi._included_ffis or ()) - for i in range(num_includes): - ffi_to_include = self.ffi._included_ffis[i] - try: - included_module_name, included_source = ( - ffi_to_include._assigned_source[:2]) - except AttributeError: - raise VerificationError( - "ffi object %r includes %r, but the latter has not " - "been prepared with set_source()" % ( - self.ffi, ffi_to_include,)) - if included_source is not None: - raise VerificationError( - "not implemented yet: ffi.include() of a C-based " - "ffi inside a Python-based ffi") - prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) - prnt() - prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) - prnt(" _version = 0x%x," % (self._version,)) - self._version = None - # - # the '_types' keyword argument - self.cffi_types = tuple(self.cffi_types) # don't change any more - types_lst = [op.as_python_bytes() for op in self.cffi_types] - prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) - typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) - # - # the keyword arguments from ALL_STEPS - for step_name in self.ALL_STEPS: - lst = self._lsts[step_name] - if len(lst) > 0 and step_name != "field": - prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) - # - # the '_includes' keyword argument - if num_includes > 0: - prnt(' _includes = (%s,),' % ( - ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) - # - # the footer - prnt(')') - - # ---------- - - def _gettypenum(self, type): - # a KeyError here is a bug. please report it! :-) - return self._typesdict[type] - - def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): - extraarg = '' - if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): - if tp.is_integer_type() and tp.name != '_Bool': - converter = '_cffi_to_c_int' - extraarg = ', %s' % tp.name - elif isinstance(tp, model.UnknownFloatType): - # don't check with is_float_type(): it may be a 'long - # double' here, and _cffi_to_c_double would loose precision - converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) - else: - cname = tp.get_c_name('') - converter = '(%s)_cffi_to_c_%s' % (cname, - tp.name.replace(' ', '_')) - if cname in ('char16_t', 'char32_t'): - self.needs_version(VERSION_CHAR16CHAR32) - errvalue = '-1' - # - elif isinstance(tp, model.PointerType): - self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, - tovar, errcode) - return - # - elif (isinstance(tp, model.StructOrUnionOrEnum) or - isinstance(tp, model.BasePrimitiveType)): - # a struct (not a struct pointer) as a function argument; - # or, a complex (the same code works) - self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' - % (tovar, self._gettypenum(tp), fromvar)) - self._prnt(' %s;' % errcode) - return - # - elif isinstance(tp, model.FunctionPtrType): - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - else: - raise NotImplementedError(tp) - # - self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) - self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( - tovar, tp.get_c_name(''), errvalue)) - self._prnt(' %s;' % errcode) - - def _extra_local_variables(self, tp, localvars, freelines): - if isinstance(tp, model.PointerType): - localvars.add('Py_ssize_t datasize') - localvars.add('struct _cffi_freeme_s *large_args_free = NULL') - freelines.add('if (large_args_free != NULL)' - ' _cffi_free_array_arguments(large_args_free);') - - def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): - self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') - self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( - self._gettypenum(tp), fromvar, tovar)) - self._prnt(' if (datasize != 0) {') - self._prnt(' %s = ((size_t)datasize) <= 640 ? ' - '(%s)alloca((size_t)datasize) : NULL;' % ( - tovar, tp.get_c_name(''))) - self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' - '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) - self._prnt(' datasize, &large_args_free) < 0)') - self._prnt(' %s;' % errcode) - self._prnt(' }') - - def _convert_expr_from_c(self, tp, var, context): - if isinstance(tp, model.BasePrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - return '_cffi_from_c_int(%s, %s)' % (var, tp.name) - elif isinstance(tp, model.UnknownFloatType): - return '_cffi_from_c_double(%s)' % (var,) - elif tp.name != 'long double' and not tp.is_complex_type(): - cname = tp.name.replace(' ', '_') - if cname in ('char16_t', 'char32_t'): - self.needs_version(VERSION_CHAR16CHAR32) - return '_cffi_from_c_%s(%s)' % (cname, var) - else: - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.ArrayType): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(model.PointerType(tp.item))) - elif isinstance(tp, model.StructOrUnion): - if tp.fldnames is None: - raise TypeError("'%s' is used as %s, but is opaque" % ( - tp._get_c_name(), context)) - return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.EnumType): - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - else: - raise NotImplementedError(tp) - - # ---------- - # typedefs - - def _typedef_type(self, tp, name): - return self._global_type(tp, "(*(%s *)0)" % (name,)) - - def _generate_cpy_typedef_collecttype(self, tp, name): - self._do_collect_type(self._typedef_type(tp, name)) - - def _generate_cpy_typedef_decl(self, tp, name): - pass - - def _typedef_ctx(self, tp, name): - type_index = self._typesdict[tp] - self._lsts["typename"].append(TypenameExpr(name, type_index)) - - def _generate_cpy_typedef_ctx(self, tp, name): - tp = self._typedef_type(tp, name) - self._typedef_ctx(tp, name) - if getattr(tp, "origin", None) == "unknown_type": - self._struct_ctx(tp, tp.name, approxname=None) - elif isinstance(tp, model.NamedPointerType): - self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, - named_ptr=tp) - - # ---------- - # function declarations - - def _generate_cpy_function_collecttype(self, tp, name): - self._do_collect_type(tp.as_raw_function()) - if tp.ellipsis and not self.target_is_python: - self._do_collect_type(tp) - - def _generate_cpy_function_decl(self, tp, name): - assert not self.target_is_python - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no CPython wrapper) - self._generate_cpy_constant_decl(tp, name) - return - prnt = self._prnt - numargs = len(tp.args) - if numargs == 0: - argname = 'noarg' - elif numargs == 1: - argname = 'arg0' - else: - argname = 'args' - # - # ------------------------------ - # the 'd' version of the function, only for addressof(lib, 'func') - arguments = [] - call_arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arguments.append(type.get_c_name(' x%d' % i, context)) - call_arguments.append('x%d' % i) - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - if tp.abi: - abi = tp.abi + ' ' - else: - abi = '' - name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) - prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) - prnt('{') - call_arguments = ', '.join(call_arguments) - result_code = 'return ' - if isinstance(tp.result, model.VoidType): - result_code = '' - prnt(' %s%s(%s);' % (result_code, name, call_arguments)) - prnt('}') - # - prnt('#ifndef PYPY_VERSION') # ------------------------------ - # - prnt('static PyObject *') - prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) - prnt('{') - # - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arg = type.get_c_name(' x%d' % i, context) - prnt(' %s;' % arg) - # - localvars = set() - freelines = set() - for type in tp.args: - self._extra_local_variables(type, localvars, freelines) - for decl in sorted(localvars): - prnt(' %s;' % (decl,)) - # - if not isinstance(tp.result, model.VoidType): - result_code = 'result = ' - context = 'result of %s' % name - result_decl = ' %s;' % tp.result.get_c_name(' result', context) - prnt(result_decl) - prnt(' PyObject *pyresult;') - else: - result_decl = None - result_code = '' - # - if len(tp.args) > 1: - rng = range(len(tp.args)) - for i in rng: - prnt(' PyObject *arg%d;' % i) - prnt() - prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( - name, len(rng), len(rng), - ', '.join(['&arg%d' % i for i in rng]))) - prnt(' return NULL;') - prnt() - # - for i, type in enumerate(tp.args): - self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, - 'return NULL') - prnt() - # - prnt(' Py_BEGIN_ALLOW_THREADS') - prnt(' _cffi_restore_errno();') - call_arguments = ['x%d' % i for i in range(len(tp.args))] - call_arguments = ', '.join(call_arguments) - prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) - prnt(' _cffi_save_errno();') - prnt(' Py_END_ALLOW_THREADS') - prnt() - # - prnt(' (void)self; /* unused */') - if numargs == 0: - prnt(' (void)noarg; /* unused */') - if result_code: - prnt(' pyresult = %s;' % - self._convert_expr_from_c(tp.result, 'result', 'result type')) - for freeline in freelines: - prnt(' ' + freeline) - prnt(' return pyresult;') - else: - for freeline in freelines: - prnt(' ' + freeline) - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') - prnt('}') - # - prnt('#else') # ------------------------------ - # - # the PyPy version: need to replace struct/union arguments with - # pointers, and if the result is a struct/union, insert a first - # arg that is a pointer to the result. We also do that for - # complex args and return type. - def need_indirection(type): - return (isinstance(type, model.StructOrUnion) or - (isinstance(type, model.PrimitiveType) and - type.is_complex_type())) - difference = False - arguments = [] - call_arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - indirection = '' - if need_indirection(type): - indirection = '*' - difference = True - arg = type.get_c_name(' %sx%d' % (indirection, i), context) - arguments.append(arg) - call_arguments.append('%sx%d' % (indirection, i)) - tp_result = tp.result - if need_indirection(tp_result): - context = 'result of %s' % name - arg = tp_result.get_c_name(' *result', context) - arguments.insert(0, arg) - tp_result = model.void_type - result_decl = None - result_code = '*result = ' - difference = True - if difference: - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, - repr_arguments) - prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) - prnt('{') - if result_decl: - prnt(result_decl) - call_arguments = ', '.join(call_arguments) - prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) - if result_decl: - prnt(' return result;') - prnt('}') - else: - prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) - # - prnt('#endif') # ------------------------------ - prnt() - - def _generate_cpy_function_ctx(self, tp, name): - if tp.ellipsis and not self.target_is_python: - self._generate_cpy_constant_ctx(tp, name) - return - type_index = self._typesdict[tp.as_raw_function()] - numargs = len(tp.args) - if self.target_is_python: - meth_kind = OP_DLOPEN_FUNC - elif numargs == 0: - meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' - elif numargs == 1: - meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' - else: - meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' - self._lsts["global"].append( - GlobalExpr(name, '_cffi_f_%s' % name, - CffiOp(meth_kind, type_index), - size='_cffi_d_%s' % name)) - - # ---------- - # named structs or unions - - def _field_type(self, tp_struct, field_name, tp_field): - if isinstance(tp_field, model.ArrayType): - actual_length = tp_field.length - if actual_length == '...': - ptr_struct_name = tp_struct.get_c_name('*') - actual_length = '_cffi_array_len(((%s)0)->%s)' % ( - ptr_struct_name, field_name) - tp_item = self._field_type(tp_struct, '%s[0]' % field_name, - tp_field.item) - tp_field = model.ArrayType(tp_item, actual_length) - return tp_field - - def _struct_collecttype(self, tp): - self._do_collect_type(tp) - if self.target_is_python: - # also requires nested anon struct/unions in ABI mode, recursively - for fldtype in tp.anonymous_struct_fields(): - self._struct_collecttype(fldtype) - - def _struct_decl(self, tp, cname, approxname): - if tp.fldtypes is None: - return - prnt = self._prnt - checkfuncname = '_cffi_checkfld_%s' % (approxname,) - prnt('_CFFI_UNUSED_FN') - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in self._enum_fields(tp): - try: - if ftype.is_integer_type() or fbitsize >= 0: - # accept all integers, but complain on float or double - if fname != '': - prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " - "an integer */" % (fname, cname, fname)) - continue - # only accept exactly the type declared, except that '[]' - # is interpreted as a '*' and so will match any array length. - # (It would also match '*', but that's harder to detect...) - while (isinstance(ftype, model.ArrayType) - and (ftype.length is None or ftype.length == '...')): - ftype = ftype.item - fname = fname + '[0]' - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) - prnt() - - def _struct_ctx(self, tp, cname, approxname, named_ptr=None): - type_index = self._typesdict[tp] - reason_for_not_expanding = None - flags = [] - if isinstance(tp, model.UnionType): - flags.append("_CFFI_F_UNION") - if tp.fldtypes is None: - flags.append("_CFFI_F_OPAQUE") - reason_for_not_expanding = "opaque" - if (tp not in self.ffi._parser._included_declarations and - (named_ptr is None or - named_ptr not in self.ffi._parser._included_declarations)): - if tp.fldtypes is None: - pass # opaque - elif tp.partial or any(tp.anonymous_struct_fields()): - pass # field layout obtained silently from the C compiler - else: - flags.append("_CFFI_F_CHECK_FIELDS") - if tp.packed: - if tp.packed > 1: - raise NotImplementedError( - "%r is declared with 'pack=%r'; only 0 or 1 are " - "supported in API mode (try to use \"...;\", which " - "does not require a 'pack' declaration)" % - (tp, tp.packed)) - flags.append("_CFFI_F_PACKED") - else: - flags.append("_CFFI_F_EXTERNAL") - reason_for_not_expanding = "external" - flags = '|'.join(flags) or '0' - c_fields = [] - if reason_for_not_expanding is None: - enumfields = list(self._enum_fields(tp)) - for fldname, fldtype, fbitsize, fqual in enumfields: - fldtype = self._field_type(tp, fldname, fldtype) - self._check_not_opaque(fldtype, - "field '%s.%s'" % (tp.name, fldname)) - # cname is None for _add_missing_struct_unions() only - op = OP_NOOP - if fbitsize >= 0: - op = OP_BITFIELD - size = '%d /* bits */' % fbitsize - elif cname is None or ( - isinstance(fldtype, model.ArrayType) and - fldtype.length is None): - size = '(size_t)-1' - else: - size = 'sizeof(((%s)0)->%s)' % ( - tp.get_c_name('*') if named_ptr is None - else named_ptr.name, - fldname) - if cname is None or fbitsize >= 0: - offset = '(size_t)-1' - elif named_ptr is not None: - offset = '(size_t)(((char *)&((%s)4096)->%s) - (char *)4096)' % ( - named_ptr.name, fldname) - else: - offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) - c_fields.append( - FieldExpr(fldname, offset, size, fbitsize, - CffiOp(op, self._typesdict[fldtype]))) - first_field_index = len(self._lsts["field"]) - self._lsts["field"].extend(c_fields) - # - if cname is None: # unknown name, for _add_missing_struct_unions - size = '(size_t)-2' - align = -2 - comment = "unnamed" - else: - if named_ptr is not None: - size = 'sizeof(*(%s)0)' % (named_ptr.name,) - align = '-1 /* unknown alignment */' - else: - size = 'sizeof(%s)' % (cname,) - align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) - comment = None - else: - size = '(size_t)-1' - align = -1 - first_field_index = -1 - comment = reason_for_not_expanding - self._lsts["struct_union"].append( - StructUnionExpr(tp.name, type_index, flags, size, align, comment, - first_field_index, c_fields)) - self._seen_struct_unions.add(tp) - - def _check_not_opaque(self, tp, location): - while isinstance(tp, model.ArrayType): - tp = tp.item - if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: - raise TypeError( - "%s is of an opaque type (not declared in cdef())" % location) - - def _add_missing_struct_unions(self): - # not very nice, but some struct declarations might be missing - # because they don't have any known C name. Check that they are - # not partial (we can't complete or verify them!) and emit them - # anonymously. - lst = list(self._struct_unions.items()) - lst.sort(key=lambda tp_order: tp_order[1]) - for tp, order in lst: - if tp not in self._seen_struct_unions: - if tp.partial: - raise NotImplementedError("internal inconsistency: %r is " - "partial but was not seen at " - "this point" % (tp,)) - if tp.name.startswith('$') and tp.name[1:].isdigit(): - approxname = tp.name[1:] - elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': - approxname = 'FILE' - self._typedef_ctx(tp, 'FILE') - else: - raise NotImplementedError("internal inconsistency: %r" % - (tp,)) - self._struct_ctx(tp, None, approxname) - - def _generate_cpy_struct_collecttype(self, tp, name): - self._struct_collecttype(tp) - _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype - - def _struct_names(self, tp): - cname = tp.get_c_name('') - if ' ' in cname: - return cname, cname.replace(' ', '_') - else: - return cname, '_' + cname - - def _generate_cpy_struct_decl(self, tp, name): - self._struct_decl(tp, *self._struct_names(tp)) - _generate_cpy_union_decl = _generate_cpy_struct_decl - - def _generate_cpy_struct_ctx(self, tp, name): - self._struct_ctx(tp, *self._struct_names(tp)) - _generate_cpy_union_ctx = _generate_cpy_struct_ctx - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - def _generate_cpy_anonymous_collecttype(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_collecttype(tp, name) - else: - self._struct_collecttype(tp) - - def _generate_cpy_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_decl(tp) - else: - self._struct_decl(tp, name, 'typedef_' + name) - - def _generate_cpy_anonymous_ctx(self, tp, name): - if isinstance(tp, model.EnumType): - self._enum_ctx(tp, name) - else: - self._struct_ctx(tp, name, 'typedef_' + name) - - # ---------- - # constants, declared with "static const ..." - - def _generate_cpy_const(self, is_int, name, tp=None, category='const', - check_value=None): - if (category, name) in self._seen_constants: - raise VerificationError( - "duplicate declaration of %s '%s'" % (category, name)) - self._seen_constants.add((category, name)) - # - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - if is_int: - prnt('static int %s(unsigned long long *o)' % funcname) - prnt('{') - prnt(' int n = (%s) <= 0;' % (name,)) - prnt(' *o = (unsigned long long)((%s) | 0);' - ' /* check that %s is an integer */' % (name, name)) - if check_value is not None: - if check_value > 0: - check_value = '%dU' % (check_value,) - prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) - prnt(' n |= 2;') - prnt(' return n;') - prnt('}') - else: - assert check_value is None - prnt('static void %s(char *o)' % funcname) - prnt('{') - prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) - prnt('}') - prnt() - - def _generate_cpy_constant_collecttype(self, tp, name): - is_int = tp.is_integer_type() - if not is_int or self.target_is_python: - self._do_collect_type(tp) - - def _generate_cpy_constant_decl(self, tp, name): - is_int = tp.is_integer_type() - self._generate_cpy_const(is_int, name, tp) - - def _generate_cpy_constant_ctx(self, tp, name): - if not self.target_is_python and tp.is_integer_type(): - type_op = CffiOp(OP_CONSTANT_INT, -1) - else: - if self.target_is_python: - const_kind = OP_DLOPEN_CONST - else: - const_kind = OP_CONSTANT - type_index = self._typesdict[tp] - type_op = CffiOp(const_kind, type_index) - self._lsts["global"].append( - GlobalExpr(name, '_cffi_const_%s' % name, type_op)) - - # ---------- - # enums - - def _generate_cpy_enum_collecttype(self, tp, name): - self._do_collect_type(tp) - - def _generate_cpy_enum_decl(self, tp, name=None): - for enumerator in tp.enumerators: - self._generate_cpy_const(True, enumerator) - - def _enum_ctx(self, tp, cname): - type_index = self._typesdict[tp] - type_op = CffiOp(OP_ENUM, -1) - if self.target_is_python: - tp.check_not_partial() - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._lsts["global"].append( - GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, - check_value=enumvalue)) - # - if cname is not None and '$' not in cname and not self.target_is_python: - size = "sizeof(%s)" % cname - signed = "((%s)-1) <= 0" % cname - else: - basetp = tp.build_baseinttype(self.ffi, []) - size = self.ffi.sizeof(basetp) - signed = int(int(self.ffi.cast(basetp, -1)) < 0) - allenums = ",".join(tp.enumerators) - self._lsts["enum"].append( - EnumExpr(tp.name, type_index, size, signed, allenums)) - - def _generate_cpy_enum_ctx(self, tp, name): - self._enum_ctx(tp, tp._get_c_name()) - - # ---------- - # macros: for now only for integers - - def _generate_cpy_macro_collecttype(self, tp, name): - pass - - def _generate_cpy_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_cpy_const(True, name, check_value=check_value) - - def _generate_cpy_macro_ctx(self, tp, name): - if tp == '...': - if self.target_is_python: - raise VerificationError( - "cannot use the syntax '...' in '#define %s ...' when " - "using the ABI mode" % (name,)) - check_value = None - else: - check_value = tp # an integer - type_op = CffiOp(OP_CONSTANT_INT, -1) - self._lsts["global"].append( - GlobalExpr(name, '_cffi_const_%s' % name, type_op, - check_value=check_value)) - - # ---------- - # global variables - - def _global_type(self, tp, global_name): - if isinstance(tp, model.ArrayType): - actual_length = tp.length - if actual_length == '...': - actual_length = '_cffi_array_len(%s)' % (global_name,) - tp_item = self._global_type(tp.item, '%s[0]' % global_name) - tp = model.ArrayType(tp_item, actual_length) - return tp - - def _generate_cpy_variable_collecttype(self, tp, name): - self._do_collect_type(self._global_type(tp, name)) - - def _generate_cpy_variable_decl(self, tp, name): - prnt = self._prnt - tp = self._global_type(tp, name) - if isinstance(tp, model.ArrayType) and tp.length is None: - tp = tp.item - ampersand = '' - else: - ampersand = '&' - # This code assumes that casts from "tp *" to "void *" is a - # no-op, i.e. a function that returns a "tp *" can be called - # as if it returned a "void *". This should be generally true - # on any modern machine. The only exception to that rule (on - # uncommon architectures, and as far as I can tell) might be - # if 'tp' were a function type, but that is not possible here. - # (If 'tp' is a function _pointer_ type, then casts from "fn_t - # **" to "void *" are again no-ops, as far as I can tell.) - decl = '*_cffi_var_%s(void)' % (name,) - prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) - prnt('{') - prnt(' return %s(%s);' % (ampersand, name)) - prnt('}') - prnt() - - def _generate_cpy_variable_ctx(self, tp, name): - tp = self._global_type(tp, name) - type_index = self._typesdict[tp] - if self.target_is_python: - op = OP_GLOBAL_VAR - else: - op = OP_GLOBAL_VAR_F - self._lsts["global"].append( - GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) - - # ---------- - # extern "Python" - - def _generate_cpy_extern_python_collecttype(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - self._do_collect_type(tp) - _generate_cpy_dllexport_python_collecttype = \ - _generate_cpy_extern_python_plus_c_collecttype = \ - _generate_cpy_extern_python_collecttype - - def _extern_python_decl(self, tp, name, tag_and_space): - prnt = self._prnt - if isinstance(tp.result, model.VoidType): - size_of_result = '0' - else: - context = 'result of %s' % name - size_of_result = '(int)sizeof(%s)' % ( - tp.result.get_c_name('', context),) - prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) - prnt(' { "%s.%s", %s, 0, 0 };' % ( - self.module_name, name, size_of_result)) - prnt() - # - arguments = [] - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - arg = type.get_c_name(' a%d' % i, context) - arguments.append(arg) - # - repr_arguments = ', '.join(arguments) - repr_arguments = repr_arguments or 'void' - name_and_arguments = '%s(%s)' % (name, repr_arguments) - if tp.abi == "__stdcall": - name_and_arguments = '_cffi_stdcall ' + name_and_arguments - # - def may_need_128_bits(tp): - return (isinstance(tp, model.PrimitiveType) and - tp.name == 'long double') - # - size_of_a = max(len(tp.args)*8, 8) - if may_need_128_bits(tp.result): - size_of_a = max(size_of_a, 16) - if isinstance(tp.result, model.StructOrUnion): - size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( - tp.result.get_c_name(''), size_of_a, - tp.result.get_c_name(''), size_of_a) - prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) - prnt('{') - prnt(' char a[%s];' % size_of_a) - prnt(' char *p = a;') - for i, type in enumerate(tp.args): - arg = 'a%d' % i - if (isinstance(type, model.StructOrUnion) or - may_need_128_bits(type)): - arg = '&' + arg - type = model.PointerType(type) - prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) - prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) - if not isinstance(tp.result, model.VoidType): - prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) - prnt('}') - prnt() - self._num_externpy += 1 - - def _generate_cpy_extern_python_decl(self, tp, name): - self._extern_python_decl(tp, name, 'static ') - - def _generate_cpy_dllexport_python_decl(self, tp, name): - self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') - - def _generate_cpy_extern_python_plus_c_decl(self, tp, name): - self._extern_python_decl(tp, name, '') - - def _generate_cpy_extern_python_ctx(self, tp, name): - if self.target_is_python: - raise VerificationError( - "cannot use 'extern \"Python\"' in the ABI mode") - if tp.ellipsis: - raise NotImplementedError("a vararg function is extern \"Python\"") - type_index = self._typesdict[tp] - type_op = CffiOp(OP_EXTERN_PYTHON, type_index) - self._lsts["global"].append( - GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) - - _generate_cpy_dllexport_python_ctx = \ - _generate_cpy_extern_python_plus_c_ctx = \ - _generate_cpy_extern_python_ctx - - def _print_string_literal_in_array(self, s): - prnt = self._prnt - prnt('// # NB. this is not a string because of a size limit in MSVC') - if not isinstance(s, bytes): # unicode - s = s.encode('utf-8') # -> bytes - else: - s.decode('utf-8') # got bytes, check for valid utf-8 - try: - s.decode('ascii') - except UnicodeDecodeError: - s = b'# -*- encoding: utf8 -*-\n' + s - for line in s.splitlines(True): - comment = line - if type('//') is bytes: # python2 - line = map(ord, line) # make a list of integers - else: # python3 - # type(line) is bytes, which enumerates like a list of integers - comment = ascii(comment)[1:-1] - prnt(('// ' + comment).rstrip()) - printed_line = '' - for c in line: - if len(printed_line) >= 76: - prnt(printed_line) - printed_line = '' - printed_line += '%d,' % (c,) - prnt(printed_line) - - # ---------- - # emitting the opcodes for individual types - - def _emit_bytecode_VoidType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) - - def _emit_bytecode_PrimitiveType(self, tp, index): - prim_index = PRIMITIVE_TO_INDEX[tp.name] - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) - - def _emit_bytecode_UnknownIntegerType(self, tp, index): - s = ('_cffi_prim_int(sizeof(%s), (\n' - ' ((%s)-1) | 0 /* check that %s is an integer type */\n' - ' ) <= 0)' % (tp.name, tp.name, tp.name)) - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) - - def _emit_bytecode_UnknownFloatType(self, tp, index): - s = ('_cffi_prim_float(sizeof(%s) *\n' - ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' - ' )' % (tp.name, tp.name)) - self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) - - def _emit_bytecode_RawFunctionType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) - index += 1 - for tp1 in tp.args: - realindex = self._typesdict[tp1] - if index != realindex: - if isinstance(tp1, model.PrimitiveType): - self._emit_bytecode_PrimitiveType(tp1, index) - else: - self.cffi_types[index] = CffiOp(OP_NOOP, realindex) - index += 1 - flags = int(tp.ellipsis) - if tp.abi is not None: - if tp.abi == '__stdcall': - flags |= 2 - else: - raise NotImplementedError("abi=%r" % (tp.abi,)) - self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) - - def _emit_bytecode_PointerType(self, tp, index): - self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) - - _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType - _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType - - def _emit_bytecode_FunctionPtrType(self, tp, index): - raw = tp.as_raw_function() - self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) - - def _emit_bytecode_ArrayType(self, tp, index): - item_index = self._typesdict[tp.item] - if tp.length is None: - self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) - elif tp.length == '...': - raise VerificationError( - "type %s badly placed: the '...' array length can only be " - "used on global arrays or on fields of structures" % ( - str(tp).replace('/*...*/', '...'),)) - else: - assert self.cffi_types[index + 1] == 'LEN' - self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) - self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) - - def _emit_bytecode_StructType(self, tp, index): - struct_index = self._struct_unions[tp] - self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) - _emit_bytecode_UnionType = _emit_bytecode_StructType - - def _emit_bytecode_EnumType(self, tp, index): - enum_index = self._enums[tp] - self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) - - -if sys.version_info >= (3,): - NativeIO = io.StringIO -else: - class NativeIO(io.BytesIO): - def write(self, s): - if isinstance(s, unicode): - s = s.encode('ascii') - super(NativeIO, self).write(s) - -def _is_file_like(maybefile): - # compare to xml.etree.ElementTree._get_writer - return hasattr(maybefile, 'write') - -def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): - if verbose: - print("generating %s" % (target_file,)) - recompiler = Recompiler(ffi, module_name, - target_is_python=(preamble is None)) - recompiler.collect_type_table() - recompiler.collect_step_tables() - if _is_file_like(target_file): - recompiler.write_source_to_f(target_file, preamble) - return True - f = NativeIO() - recompiler.write_source_to_f(f, preamble) - output = f.getvalue() - try: - with open(target_file, 'r') as f1: - if f1.read(len(output) + 1) != output: - raise IOError - if verbose: - print("(already up-to-date)") - return False # already up-to-date - except IOError: - tmp_file = '%s.~%d' % (target_file, os.getpid()) - with open(tmp_file, 'w') as f1: - f1.write(output) - try: - os.rename(tmp_file, target_file) - except OSError: - os.unlink(target_file) - os.rename(tmp_file, target_file) - return True - -def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): - assert preamble is not None - return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, - verbose) - -def make_py_source(ffi, module_name, target_py_file, verbose=False): - return _make_c_or_py_source(ffi, module_name, None, target_py_file, - verbose) - -def _modname_to_file(outputdir, modname, extension): - parts = modname.split('.') - try: - os.makedirs(os.path.join(outputdir, *parts[:-1])) - except OSError: - pass - parts[-1] += extension - return os.path.join(outputdir, *parts), parts - - -# Aaargh. Distutils is not tested at all for the purpose of compiling -# DLLs that are not extension modules. Here are some hacks to work -# around that, in the _patch_for_*() functions... - -def _patch_meth(patchlist, cls, name, new_meth): - old = getattr(cls, name) - patchlist.append((cls, name, old)) - setattr(cls, name, new_meth) - return old - -def _unpatch_meths(patchlist): - for cls, name, old_meth in reversed(patchlist): - setattr(cls, name, old_meth) - -def _patch_for_embedding(patchlist): - if sys.platform == 'win32': - # we must not remove the manifest when building for embedding! - # FUTURE: this module was removed in setuptools 74; this is likely dead code and should be removed, - # since the toolchain it supports (VS2005-2008) is also long dead. - from cffi._shimmed_dist_utils import MSVCCompiler - if MSVCCompiler is not None: - _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', - lambda self, manifest_file: manifest_file) - - if sys.platform == 'darwin': - # we must not make a '-bundle', but a '-dynamiclib' instead - from cffi._shimmed_dist_utils import CCompiler - def my_link_shared_object(self, *args, **kwds): - if '-bundle' in self.linker_so: - self.linker_so = list(self.linker_so) - i = self.linker_so.index('-bundle') - self.linker_so[i] = '-dynamiclib' - return old_link_shared_object(self, *args, **kwds) - old_link_shared_object = _patch_meth(patchlist, CCompiler, - 'link_shared_object', - my_link_shared_object) - -def _patch_for_target(patchlist, target): - from cffi._shimmed_dist_utils import build_ext - # if 'target' is different from '*', we need to patch some internal - # method to just return this 'target' value, instead of having it - # built from module_name - if target.endswith('.*'): - target = target[:-2] - if sys.platform == 'win32': - target += '.dll' - elif sys.platform == 'darwin': - target += '.dylib' - else: - target += '.so' - _patch_meth(patchlist, build_ext, 'get_ext_filename', - lambda self, ext_name: target) - - -def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, - c_file=None, source_extension='.c', extradir=None, - compiler_verbose=1, target=None, debug=None, - uses_ffiplatform=True, **kwds): - if not isinstance(module_name, str): - module_name = module_name.encode('ascii') - if ffi._windows_unicode: - ffi._apply_windows_unicode(kwds) - if preamble is not None: - if call_c_compiler and _is_file_like(c_file): - raise TypeError("Writing to file-like objects is not supported " - "with call_c_compiler=True") - embedding = (ffi._embedding is not None) - if embedding: - ffi._apply_embedding_fix(kwds) - if c_file is None: - c_file, parts = _modname_to_file(tmpdir, module_name, - source_extension) - if extradir: - parts = [extradir] + parts - ext_c_file = os.path.join(*parts) - else: - ext_c_file = c_file - # - if target is None: - if embedding: - target = '%s.*' % module_name - else: - target = '*' - # - if uses_ffiplatform: - ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) - else: - ext = None - updated = make_c_source(ffi, module_name, preamble, c_file, - verbose=compiler_verbose) - if call_c_compiler: - patchlist = [] - cwd = os.getcwd() - try: - if embedding: - _patch_for_embedding(patchlist) - if target != '*': - _patch_for_target(patchlist, target) - if compiler_verbose: - if tmpdir == '.': - msg = 'the current directory is' - else: - msg = 'setting the current directory to' - print('%s %r' % (msg, os.path.abspath(tmpdir))) - os.chdir(tmpdir) - outputfilename = ffiplatform.compile('.', ext, - compiler_verbose, debug) - finally: - os.chdir(cwd) - _unpatch_meths(patchlist) - return outputfilename - else: - return ext, updated - else: - if c_file is None: - c_file, _ = _modname_to_file(tmpdir, module_name, '.py') - updated = make_py_source(ffi, module_name, c_file, - verbose=compiler_verbose) - if call_c_compiler: - return c_file - else: - return None, updated - diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/setuptools_ext.py b/backend/venv39/lib/python3.9/site-packages/cffi/setuptools_ext.py deleted file mode 100644 index 5cdd246..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/setuptools_ext.py +++ /dev/null @@ -1,229 +0,0 @@ -import os -import sys -import sysconfig - -try: - basestring -except NameError: - # Python 3.x - basestring = str - -def error(msg): - from cffi._shimmed_dist_utils import DistutilsSetupError - raise DistutilsSetupError(msg) - - -def execfile(filename, glob): - # We use execfile() (here rewritten for Python 3) instead of - # __import__() to load the build script. The problem with - # a normal import is that in some packages, the intermediate - # __init__.py files may already try to import the file that - # we are generating. - with open(filename) as f: - src = f.read() - src += '\n' # Python 2.6 compatibility - code = compile(src, filename, 'exec') - exec(code, glob, glob) - - -def add_cffi_module(dist, mod_spec): - from cffi.api import FFI - - if not isinstance(mod_spec, basestring): - error("argument to 'cffi_modules=...' must be a str or a list of str," - " not %r" % (type(mod_spec).__name__,)) - mod_spec = str(mod_spec) - try: - build_file_name, ffi_var_name = mod_spec.split(':') - except ValueError: - error("%r must be of the form 'path/build.py:ffi_variable'" % - (mod_spec,)) - if not os.path.exists(build_file_name): - ext = '' - rewritten = build_file_name.replace('.', '/') + '.py' - if os.path.exists(rewritten): - ext = ' (rewrite cffi_modules to [%r])' % ( - rewritten + ':' + ffi_var_name,) - error("%r does not name an existing file%s" % (build_file_name, ext)) - - mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} - execfile(build_file_name, mod_vars) - - try: - ffi = mod_vars[ffi_var_name] - except KeyError: - error("%r: object %r not found in module" % (mod_spec, - ffi_var_name)) - if not isinstance(ffi, FFI): - ffi = ffi() # maybe it's a function instead of directly an ffi - if not isinstance(ffi, FFI): - error("%r is not an FFI instance (got %r)" % (mod_spec, - type(ffi).__name__)) - if not hasattr(ffi, '_assigned_source'): - error("%r: the set_source() method was not called" % (mod_spec,)) - module_name, source, source_extension, kwds = ffi._assigned_source - if ffi._windows_unicode: - kwds = kwds.copy() - ffi._apply_windows_unicode(kwds) - - if source is None: - _add_py_module(dist, ffi, module_name) - else: - _add_c_module(dist, ffi, module_name, source, source_extension, kwds) - -def _set_py_limited_api(Extension, kwds): - """ - Add py_limited_api to kwds if setuptools >= 26 is in use. - Do not alter the setting if it already exists. - Setuptools takes care of ignoring the flag on Python 2 and PyPy. - - CPython itself should ignore the flag in a debugging version - (by not listing .abi3.so in the extensions it supports), but - it doesn't so far, creating troubles. That's why we check - for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent - of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) - - On Windows, with CPython <= 3.4, it's better not to use py_limited_api - because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. - Recently (2020) we started shipping only >= 3.5 wheels, though. So - we'll give it another try and set py_limited_api on Windows >= 3.5. - """ - from cffi._shimmed_dist_utils import log - from cffi import recompiler - - if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') - and recompiler.USE_LIMITED_API): - import setuptools - try: - setuptools_major_version = int(setuptools.__version__.partition('.')[0]) - if setuptools_major_version >= 26: - kwds['py_limited_api'] = True - except ValueError: # certain development versions of setuptools - # If we don't know the version number of setuptools, we - # try to set 'py_limited_api' anyway. At worst, we get a - # warning. - kwds['py_limited_api'] = True - - if sysconfig.get_config_var("Py_GIL_DISABLED"): - if kwds.get('py_limited_api'): - log.info("Ignoring py_limited_api=True for free-threaded build.") - - kwds['py_limited_api'] = False - - if kwds.get('py_limited_api') is False: - # avoid setting Py_LIMITED_API if py_limited_api=False - # which _cffi_include.h does unless _CFFI_NO_LIMITED_API is defined - kwds.setdefault("define_macros", []).append(("_CFFI_NO_LIMITED_API", None)) - return kwds - -def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): - # We are a setuptools extension. Need this build_ext for py_limited_api. - from setuptools.command.build_ext import build_ext - from cffi._shimmed_dist_utils import Extension, log, mkpath - from cffi import recompiler - - allsources = ['$PLACEHOLDER'] - allsources.extend(kwds.pop('sources', [])) - kwds = _set_py_limited_api(Extension, kwds) - ext = Extension(name=module_name, sources=allsources, **kwds) - - def make_mod(tmpdir, pre_run=None): - c_file = os.path.join(tmpdir, module_name + source_extension) - log.info("generating cffi module %r" % c_file) - mkpath(tmpdir) - # a setuptools-only, API-only hook: called with the "ext" and "ffi" - # arguments just before we turn the ffi into C code. To use it, - # subclass the 'distutils.command.build_ext.build_ext' class and - # add a method 'def pre_run(self, ext, ffi)'. - if pre_run is not None: - pre_run(ext, ffi) - updated = recompiler.make_c_source(ffi, module_name, source, c_file) - if not updated: - log.info("already up-to-date") - return c_file - - if dist.ext_modules is None: - dist.ext_modules = [] - dist.ext_modules.append(ext) - - base_class = dist.cmdclass.get('build_ext', build_ext) - class build_ext_make_mod(base_class): - def run(self): - if ext.sources[0] == '$PLACEHOLDER': - pre_run = getattr(self, 'pre_run', None) - ext.sources[0] = make_mod(self.build_temp, pre_run) - base_class.run(self) - dist.cmdclass['build_ext'] = build_ext_make_mod - # NB. multiple runs here will create multiple 'build_ext_make_mod' - # classes. Even in this case the 'build_ext' command should be - # run once; but just in case, the logic above does nothing if - # called again. - - -def _add_py_module(dist, ffi, module_name): - from setuptools.command.build_py import build_py - from setuptools.command.build_ext import build_ext - from cffi._shimmed_dist_utils import log, mkpath - from cffi import recompiler - - def generate_mod(py_file): - log.info("generating cffi module %r" % py_file) - mkpath(os.path.dirname(py_file)) - updated = recompiler.make_py_source(ffi, module_name, py_file) - if not updated: - log.info("already up-to-date") - - base_class = dist.cmdclass.get('build_py', build_py) - class build_py_make_mod(base_class): - def run(self): - base_class.run(self) - module_path = module_name.split('.') - module_path[-1] += '.py' - generate_mod(os.path.join(self.build_lib, *module_path)) - def get_source_files(self): - # This is called from 'setup.py sdist' only. Exclude - # the generate .py module in this case. - saved_py_modules = self.py_modules - try: - if saved_py_modules: - self.py_modules = [m for m in saved_py_modules - if m != module_name] - return base_class.get_source_files(self) - finally: - self.py_modules = saved_py_modules - dist.cmdclass['build_py'] = build_py_make_mod - - # distutils and setuptools have no notion I could find of a - # generated python module. If we don't add module_name to - # dist.py_modules, then things mostly work but there are some - # combination of options (--root and --record) that will miss - # the module. So we add it here, which gives a few apparently - # harmless warnings about not finding the file outside the - # build directory. - # Then we need to hack more in get_source_files(); see above. - if dist.py_modules is None: - dist.py_modules = [] - dist.py_modules.append(module_name) - - # the following is only for "build_ext -i" - base_class_2 = dist.cmdclass.get('build_ext', build_ext) - class build_ext_make_mod(base_class_2): - def run(self): - base_class_2.run(self) - if self.inplace: - # from get_ext_fullpath() in distutils/command/build_ext.py - module_path = module_name.split('.') - package = '.'.join(module_path[:-1]) - build_py = self.get_finalized_command('build_py') - package_dir = build_py.get_package_dir(package) - file_name = module_path[-1] + '.py' - generate_mod(os.path.join(package_dir, file_name)) - dist.cmdclass['build_ext'] = build_ext_make_mod - -def cffi_modules(dist, attr, value): - assert attr == 'cffi_modules' - if isinstance(value, basestring): - value = [value] - - for cffi_module in value: - add_cffi_module(dist, cffi_module) diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/vengine_cpy.py b/backend/venv39/lib/python3.9/site-packages/cffi/vengine_cpy.py deleted file mode 100644 index 02e6a47..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/vengine_cpy.py +++ /dev/null @@ -1,1087 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys -from . import model -from .error import VerificationError -from . import _imp_emulation as imp - - -class VCPythonEngine(object): - _class_key = 'x' - _gen_python_module = True - - def __init__(self, verifier): - self.verifier = verifier - self.ffi = verifier.ffi - self._struct_pending_verification = {} - self._types_of_builtin_functions = {} - - def patch_extension_kwds(self, kwds): - pass - - def find_module(self, module_name, path, so_suffixes): - try: - f, filename, descr = imp.find_module(module_name, path) - except ImportError: - return None - if f is not None: - f.close() - # Note that after a setuptools installation, there are both .py - # and .so files with the same basename. The code here relies on - # imp.find_module() locating the .so in priority. - if descr[0] not in so_suffixes: - return None - return filename - - def collect_types(self): - self._typesdict = {} - self._generate("collecttype") - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def _gettypenum(self, type): - # a KeyError here is a bug. please report it! :-) - return self._typesdict[type] - - def _do_collect_type(self, tp): - if ((not isinstance(tp, model.PrimitiveType) - or tp.name == 'long double') - and tp not in self._typesdict): - num = len(self._typesdict) - self._typesdict[tp] = num - - def write_source_to_f(self): - self.collect_types() - # - # The new module will have a _cffi_setup() function that receives - # objects from the ffi world, and that calls some setup code in - # the module. This setup code is split in several independent - # functions, e.g. one per constant. The functions are "chained" - # by ending in a tail call to each other. - # - # This is further split in two chained lists, depending on if we - # can do it at import-time or if we must wait for _cffi_setup() to - # provide us with the objects. This is needed because we - # need the values of the enum constants in order to build the - # that we may have to pass to _cffi_setup(). - # - # The following two 'chained_list_constants' items contains - # the head of these two chained lists, as a string that gives the - # call to do, if any. - self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] - # - prnt = self._prnt - # first paste some standard set of lines that are mostly '#define' - prnt(cffimod_header) - prnt() - # then paste the C source given by the user, verbatim. - prnt(self.verifier.preamble) - prnt() - # - # call generate_cpy_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._generate("decl") - # - # implement the function _cffi_setup_custom() as calling the - # head of the chained list. - self._generate_setup_custom() - prnt() - # - # produce the method table, including the entries for the - # generated Python->C function wrappers, which are done - # by generate_cpy_function_method(). - prnt('static PyMethodDef _cffi_methods[] = {') - self._generate("method") - prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') - prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') - prnt('};') - prnt() - # - # standard init. - modname = self.verifier.get_module_name() - constants = self._chained_list_constants[False] - prnt('#if PY_MAJOR_VERSION >= 3') - prnt() - prnt('static struct PyModuleDef _cffi_module_def = {') - prnt(' PyModuleDef_HEAD_INIT,') - prnt(' "%s",' % modname) - prnt(' NULL,') - prnt(' -1,') - prnt(' _cffi_methods,') - prnt(' NULL, NULL, NULL, NULL') - prnt('};') - prnt() - prnt('PyMODINIT_FUNC') - prnt('PyInit_%s(void)' % modname) - prnt('{') - prnt(' PyObject *lib;') - prnt(' lib = PyModule_Create(&_cffi_module_def);') - prnt(' if (lib == NULL)') - prnt(' return NULL;') - prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) - prnt(' Py_DECREF(lib);') - prnt(' return NULL;') - prnt(' }') - prnt('#if Py_GIL_DISABLED') - prnt(' PyUnstable_Module_SetGIL(lib, Py_MOD_GIL_NOT_USED);') - prnt('#endif') - prnt(' return lib;') - prnt('}') - prnt() - prnt('#else') - prnt() - prnt('PyMODINIT_FUNC') - prnt('init%s(void)' % modname) - prnt('{') - prnt(' PyObject *lib;') - prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) - prnt(' if (lib == NULL)') - prnt(' return;') - prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) - prnt(' return;') - prnt(' return;') - prnt('}') - prnt() - prnt('#endif') - - def load_library(self, flags=None): - # XXX review all usages of 'self' here! - # import it as a new extension module - imp.acquire_lock() - try: - if hasattr(sys, "getdlopenflags"): - previous_flags = sys.getdlopenflags() - try: - if hasattr(sys, "setdlopenflags") and flags is not None: - sys.setdlopenflags(flags) - module = imp.load_dynamic(self.verifier.get_module_name(), - self.verifier.modulefilename) - except ImportError as e: - error = "importing %r: %s" % (self.verifier.modulefilename, e) - raise VerificationError(error) - finally: - if hasattr(sys, "setdlopenflags"): - sys.setdlopenflags(previous_flags) - finally: - imp.release_lock() - # - # call loading_cpy_struct() to get the struct layout inferred by - # the C compiler - self._load(module, 'loading') - # - # the C code will need the objects. Collect them in - # order in a list. - revmapping = dict([(value, key) - for (key, value) in self._typesdict.items()]) - lst = [revmapping[i] for i in range(len(revmapping))] - lst = list(map(self.ffi._get_cached_btype, lst)) - # - # build the FFILibrary class and instance and call _cffi_setup(). - # this will set up some fields like '_cffi_types', and only then - # it will invoke the chained list of functions that will really - # build (notably) the constant objects, as if they are - # pointers, and store them as attributes on the 'library' object. - class FFILibrary(object): - _cffi_python_module = module - _cffi_ffi = self.ffi - _cffi_dir = [] - def __dir__(self): - return FFILibrary._cffi_dir + list(self.__dict__) - library = FFILibrary() - if module._cffi_setup(lst, VerificationError, library): - import warnings - warnings.warn("reimporting %r might overwrite older definitions" - % (self.verifier.get_module_name())) - # - # finally, call the loaded_cpy_xxx() functions. This will perform - # the final adjustments, like copying the Python->C wrapper - # functions from the module to the 'library' object, and setting - # up the FFILibrary class with properties for the global C variables. - self._load(module, 'loaded', library=library) - module._cffi_original_ffi = self.ffi - module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions - return library - - def _get_declarations(self): - lst = [(key, tp) for (key, (tp, qual)) in - self.ffi._parser._declarations.items()] - lst.sort() - return lst - - def _generate(self, step_name): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_cpy_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in verify(): %r" % name) - try: - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _load(self, module, step_name, **kwds): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) - try: - method(tp, realname, module, **kwds) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _generate_nothing(self, tp, name): - pass - - def _loaded_noop(self, tp, name, module, **kwds): - pass - - # ---------- - - def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): - extraarg = '' - if isinstance(tp, model.PrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - converter = '_cffi_to_c_int' - extraarg = ', %s' % tp.name - elif tp.is_complex_type(): - raise VerificationError( - "not implemented in verify(): complex types") - else: - converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), - tp.name.replace(' ', '_')) - errvalue = '-1' - # - elif isinstance(tp, model.PointerType): - self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, - tovar, errcode) - return - # - elif isinstance(tp, (model.StructOrUnion, model.EnumType)): - # a struct (not a struct pointer) as a function argument - self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' - % (tovar, self._gettypenum(tp), fromvar)) - self._prnt(' %s;' % errcode) - return - # - elif isinstance(tp, model.FunctionPtrType): - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - else: - raise NotImplementedError(tp) - # - self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) - self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( - tovar, tp.get_c_name(''), errvalue)) - self._prnt(' %s;' % errcode) - - def _extra_local_variables(self, tp, localvars, freelines): - if isinstance(tp, model.PointerType): - localvars.add('Py_ssize_t datasize') - localvars.add('struct _cffi_freeme_s *large_args_free = NULL') - freelines.add('if (large_args_free != NULL)' - ' _cffi_free_array_arguments(large_args_free);') - - def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): - self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') - self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( - self._gettypenum(tp), fromvar, tovar)) - self._prnt(' if (datasize != 0) {') - self._prnt(' %s = ((size_t)datasize) <= 640 ? ' - 'alloca((size_t)datasize) : NULL;' % (tovar,)) - self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' - '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) - self._prnt(' datasize, &large_args_free) < 0)') - self._prnt(' %s;' % errcode) - self._prnt(' }') - - def _convert_expr_from_c(self, tp, var, context): - if isinstance(tp, model.PrimitiveType): - if tp.is_integer_type() and tp.name != '_Bool': - return '_cffi_from_c_int(%s, %s)' % (var, tp.name) - elif tp.name != 'long double': - return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) - else: - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.ArrayType): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(model.PointerType(tp.item))) - elif isinstance(tp, model.StructOrUnion): - if tp.fldnames is None: - raise TypeError("'%s' is used as %s, but is opaque" % ( - tp._get_c_name(), context)) - return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.EnumType): - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - else: - raise NotImplementedError(tp) - - # ---------- - # typedefs: generates no code so far - - _generate_cpy_typedef_collecttype = _generate_nothing - _generate_cpy_typedef_decl = _generate_nothing - _generate_cpy_typedef_method = _generate_nothing - _loading_cpy_typedef = _loaded_noop - _loaded_cpy_typedef = _loaded_noop - - # ---------- - # function declarations - - def _generate_cpy_function_collecttype(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - self._do_collect_type(tp) - else: - # don't call _do_collect_type(tp) in this common case, - # otherwise test_autofilled_struct_as_argument fails - for type in tp.args: - self._do_collect_type(type) - self._do_collect_type(tp.result) - - def _generate_cpy_function_decl(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no CPython wrapper) - self._generate_cpy_const(False, name, tp) - return - prnt = self._prnt - numargs = len(tp.args) - if numargs == 0: - argname = 'noarg' - elif numargs == 1: - argname = 'arg0' - else: - argname = 'args' - prnt('static PyObject *') - prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) - prnt('{') - # - context = 'argument of %s' % name - for i, type in enumerate(tp.args): - prnt(' %s;' % type.get_c_name(' x%d' % i, context)) - # - localvars = set() - freelines = set() - for type in tp.args: - self._extra_local_variables(type, localvars, freelines) - for decl in sorted(localvars): - prnt(' %s;' % (decl,)) - # - if not isinstance(tp.result, model.VoidType): - result_code = 'result = ' - context = 'result of %s' % name - prnt(' %s;' % tp.result.get_c_name(' result', context)) - prnt(' PyObject *pyresult;') - else: - result_code = '' - # - if len(tp.args) > 1: - rng = range(len(tp.args)) - for i in rng: - prnt(' PyObject *arg%d;' % i) - prnt() - prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( - 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) - prnt(' return NULL;') - prnt() - # - for i, type in enumerate(tp.args): - self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, - 'return NULL') - prnt() - # - prnt(' Py_BEGIN_ALLOW_THREADS') - prnt(' _cffi_restore_errno();') - prnt(' { %s%s(%s); }' % ( - result_code, name, - ', '.join(['x%d' % i for i in range(len(tp.args))]))) - prnt(' _cffi_save_errno();') - prnt(' Py_END_ALLOW_THREADS') - prnt() - # - prnt(' (void)self; /* unused */') - if numargs == 0: - prnt(' (void)noarg; /* unused */') - if result_code: - prnt(' pyresult = %s;' % - self._convert_expr_from_c(tp.result, 'result', 'result type')) - for freeline in freelines: - prnt(' ' + freeline) - prnt(' return pyresult;') - else: - for freeline in freelines: - prnt(' ' + freeline) - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') - prnt('}') - prnt() - - def _generate_cpy_function_method(self, tp, name): - if tp.ellipsis: - return - numargs = len(tp.args) - if numargs == 0: - meth = 'METH_NOARGS' - elif numargs == 1: - meth = 'METH_O' - else: - meth = 'METH_VARARGS' - self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) - - _loading_cpy_function = _loaded_noop - - def _loaded_cpy_function(self, tp, name, module, library): - if tp.ellipsis: - return - func = getattr(module, name) - setattr(library, name, func) - self._types_of_builtin_functions[func] = tp - - # ---------- - # named structs - - _generate_cpy_struct_collecttype = _generate_nothing - def _generate_cpy_struct_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'struct', name) - def _generate_cpy_struct_method(self, tp, name): - self._generate_struct_or_union_method(tp, 'struct', name) - def _loading_cpy_struct(self, tp, name, module): - self._loading_struct_or_union(tp, 'struct', name, module) - def _loaded_cpy_struct(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - _generate_cpy_union_collecttype = _generate_nothing - def _generate_cpy_union_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'union', name) - def _generate_cpy_union_method(self, tp, name): - self._generate_struct_or_union_method(tp, 'union', name) - def _loading_cpy_union(self, tp, name, module): - self._loading_struct_or_union(tp, 'union', name, module) - def _loaded_cpy_union(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_struct_or_union_decl(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - checkfuncname = '_cffi_check_%s_%s' % (prefix, name) - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - cname = ('%s %s' % (prefix, name)).strip() - # - prnt = self._prnt - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()) or fbitsize >= 0: - # accept all integers, but complain on float or double - prnt(' (void)((p->%s) << 1);' % fname) - else: - # only accept exactly the type declared. - try: - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - prnt('static PyObject *') - prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) - prnt('{') - prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) - prnt(' static Py_ssize_t nums[] = {') - prnt(' sizeof(%s),' % cname) - prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - prnt(' offsetof(%s, %s),' % (cname, fname)) - if isinstance(ftype, model.ArrayType) and ftype.length is None: - prnt(' 0, /* %s */' % ftype._get_c_name()) - else: - prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) - prnt(' -1') - prnt(' };') - prnt(' (void)self; /* unused */') - prnt(' (void)noarg; /* unused */') - prnt(' return _cffi_get_struct_layout(nums);') - prnt(' /* the next line is not executed, but compiled */') - prnt(' %s(0);' % (checkfuncname,)) - prnt('}') - prnt() - - def _generate_struct_or_union_method(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, - layoutfuncname)) - - def _loading_struct_or_union(self, tp, prefix, name, module): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - # - function = getattr(module, layoutfuncname) - layout = function() - if isinstance(tp, model.StructOrUnion) and tp.partial: - # use the function()'s sizes and offsets to guide the - # layout of the struct - totalsize = layout[0] - totalalignment = layout[1] - fieldofs = layout[2::2] - fieldsize = layout[3::2] - tp.force_flatten() - assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) - tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment - else: - cname = ('%s %s' % (prefix, name)).strip() - self._struct_pending_verification[tp] = layout, cname - - def _loaded_struct_or_union(self, tp): - if tp.fldnames is None: - return # nothing to do with opaque structs - self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered - - if tp in self._struct_pending_verification: - # check that the layout sizes and offsets match the real ones - def check(realvalue, expectedvalue, msg): - if realvalue != expectedvalue: - raise VerificationError( - "%s (we have %d, but C compiler says %d)" - % (msg, expectedvalue, realvalue)) - ffi = self.ffi - BStruct = ffi._get_cached_btype(tp) - layout, cname = self._struct_pending_verification.pop(tp) - check(layout[0], ffi.sizeof(BStruct), "wrong total size") - check(layout[1], ffi.alignof(BStruct), "wrong total alignment") - i = 2 - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - check(layout[i], ffi.offsetof(BStruct, fname), - "wrong offset for field %r" % (fname,)) - if layout[i+1] != 0: - BField = ffi._get_cached_btype(ftype) - check(layout[i+1], ffi.sizeof(BField), - "wrong size for field %r" % (fname,)) - i += 2 - assert i == len(layout) - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - _generate_cpy_anonymous_collecttype = _generate_nothing - - def _generate_cpy_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_cpy_enum_decl(tp, name, '') - else: - self._generate_struct_or_union_decl(tp, '', name) - - def _generate_cpy_anonymous_method(self, tp, name): - if not isinstance(tp, model.EnumType): - self._generate_struct_or_union_method(tp, '', name) - - def _loading_cpy_anonymous(self, tp, name, module): - if isinstance(tp, model.EnumType): - self._loading_cpy_enum(tp, name, module) - else: - self._loading_struct_or_union(tp, '', name, module) - - def _loaded_cpy_anonymous(self, tp, name, module, **kwds): - if isinstance(tp, model.EnumType): - self._loaded_cpy_enum(tp, name, module, **kwds) - else: - self._loaded_struct_or_union(tp) - - # ---------- - # constants, likely declared with '#define' - - def _generate_cpy_const(self, is_int, name, tp=None, category='const', - vartp=None, delayed=True, size_too=False, - check_value=None): - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - prnt('static int %s(PyObject *lib)' % funcname) - prnt('{') - prnt(' PyObject *o;') - prnt(' int res;') - if not is_int: - prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) - else: - assert category == 'const' - # - if check_value is not None: - self._check_int_constant_value(name, check_value) - # - if not is_int: - if category == 'var': - realexpr = '&' + name - else: - realexpr = name - prnt(' i = (%s);' % (realexpr,)) - prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', - 'variable type'),)) - assert delayed - else: - prnt(' o = _cffi_from_c_int_const(%s);' % name) - prnt(' if (o == NULL)') - prnt(' return -1;') - if size_too: - prnt(' {') - prnt(' PyObject *o1 = o;') - prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' - % (name,)) - prnt(' Py_DECREF(o1);') - prnt(' if (o == NULL)') - prnt(' return -1;') - prnt(' }') - prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) - prnt(' Py_DECREF(o);') - prnt(' if (res < 0)') - prnt(' return -1;') - prnt(' return %s;' % self._chained_list_constants[delayed]) - self._chained_list_constants[delayed] = funcname + '(lib)' - prnt('}') - prnt() - - def _generate_cpy_constant_collecttype(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - if not is_int: - self._do_collect_type(tp) - - def _generate_cpy_constant_decl(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - self._generate_cpy_const(is_int, name, tp) - - _generate_cpy_constant_method = _generate_nothing - _loading_cpy_constant = _loaded_noop - _loaded_cpy_constant = _loaded_noop - - # ---------- - # enums - - def _check_int_constant_value(self, name, value, err_prefix=''): - prnt = self._prnt - if value <= 0: - prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( - name, name, value)) - else: - prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( - name, name, value)) - prnt(' char buf[64];') - prnt(' if ((%s) <= 0)' % name) - prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) - prnt(' else') - prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % - name) - prnt(' PyErr_Format(_cffi_VerificationError,') - prnt(' "%s%s has the real value %s, not %s",') - prnt(' "%s", "%s", buf, "%d");' % ( - err_prefix, name, value)) - prnt(' return -1;') - prnt(' }') - - def _enum_funcname(self, prefix, name): - # "$enum_$1" => "___D_enum____D_1" - name = name.replace('$', '___D_') - return '_cffi_e_%s_%s' % (prefix, name) - - def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): - if tp.partial: - for enumerator in tp.enumerators: - self._generate_cpy_const(True, enumerator, delayed=False) - return - # - funcname = self._enum_funcname(prefix, name) - prnt = self._prnt - prnt('static int %s(PyObject *lib)' % funcname) - prnt('{') - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._check_int_constant_value(enumerator, enumvalue, - "enum %s: " % name) - prnt(' return %s;' % self._chained_list_constants[True]) - self._chained_list_constants[True] = funcname + '(lib)' - prnt('}') - prnt() - - _generate_cpy_enum_collecttype = _generate_nothing - _generate_cpy_enum_method = _generate_nothing - - def _loading_cpy_enum(self, tp, name, module): - if tp.partial: - enumvalues = [getattr(module, enumerator) - for enumerator in tp.enumerators] - tp.enumvalues = tuple(enumvalues) - tp.partial_resolved = True - - def _loaded_cpy_enum(self, tp, name, module, library): - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - setattr(library, enumerator, enumvalue) - - # ---------- - # macros: for now only for integers - - def _generate_cpy_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_cpy_const(True, name, check_value=check_value) - - _generate_cpy_macro_collecttype = _generate_nothing - _generate_cpy_macro_method = _generate_nothing - _loading_cpy_macro = _loaded_noop - _loaded_cpy_macro = _loaded_noop - - # ---------- - # global variables - - def _generate_cpy_variable_collecttype(self, tp, name): - if isinstance(tp, model.ArrayType): - tp_ptr = model.PointerType(tp.item) - else: - tp_ptr = model.PointerType(tp) - self._do_collect_type(tp_ptr) - - def _generate_cpy_variable_decl(self, tp, name): - if isinstance(tp, model.ArrayType): - tp_ptr = model.PointerType(tp.item) - self._generate_cpy_const(False, name, tp, vartp=tp_ptr, - size_too = tp.length_is_unknown()) - else: - tp_ptr = model.PointerType(tp) - self._generate_cpy_const(False, name, tp_ptr, category='var') - - _generate_cpy_variable_method = _generate_nothing - _loading_cpy_variable = _loaded_noop - - def _loaded_cpy_variable(self, tp, name, module, library): - value = getattr(library, name) - if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the - # sense that "a=..." is forbidden - if tp.length_is_unknown(): - assert isinstance(value, tuple) - (value, size) = value - BItemType = self.ffi._get_cached_btype(tp.item) - length, rest = divmod(size, self.ffi.sizeof(BItemType)) - if rest != 0: - raise VerificationError( - "bad size: %r does not seem to be an array of %s" % - (name, tp.item)) - tp = tp.resolve_length(length) - # 'value' is a which we have to replace with - # a if the N is actually known - if tp.length is not None: - BArray = self.ffi._get_cached_btype(tp) - value = self.ffi.cast(BArray, value) - setattr(library, name, value) - return - # remove ptr= from the library instance, and replace - # it by a property on the class, which reads/writes into ptr[0]. - ptr = value - delattr(library, name) - def getter(library): - return ptr[0] - def setter(library, value): - ptr[0] = value - setattr(type(library), name, property(getter, setter)) - type(library)._cffi_dir.append(name) - - # ---------- - - def _generate_setup_custom(self): - prnt = self._prnt - prnt('static int _cffi_setup_custom(PyObject *lib)') - prnt('{') - prnt(' return %s;' % self._chained_list_constants[True]) - prnt('}') - -cffimod_header = r''' -#include -#include - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif - -#if PY_MAJOR_VERSION < 3 -# undef PyCapsule_CheckExact -# undef PyCapsule_GetPointer -# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) -# define PyCapsule_GetPointer(capsule, name) \ - (PyCObject_AsVoidPtr(capsule)) -#endif - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -#endif - -#define _cffi_from_c_double PyFloat_FromDouble -#define _cffi_from_c_float PyFloat_FromDouble -#define _cffi_from_c_long PyInt_FromLong -#define _cffi_from_c_ulong PyLong_FromUnsignedLong -#define _cffi_from_c_longlong PyLong_FromLongLong -#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong -#define _cffi_from_c__Bool PyBool_FromLong - -#define _cffi_to_c_double PyFloat_AsDouble -#define _cffi_to_c_float PyFloat_AsDouble - -#define _cffi_from_c_int_const(x) \ - (((x) > 0) ? \ - ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ - PyInt_FromLong((long)(x)) : \ - PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ - ((long long)(x) >= (long long)LONG_MIN) ? \ - PyInt_FromLong((long)(x)) : \ - PyLong_FromLongLong((long long)(x))) - -#define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - sizeof(type) == sizeof(long) ? \ - PyLong_FromUnsignedLong((unsigned long)x) : \ - PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ - (sizeof(type) <= sizeof(long) ? \ - PyInt_FromLong((long)x) : \ - PyLong_FromLongLong((long long)x))) - -#define _cffi_to_c_int(o, type) \ - ((type)( \ - sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ - : (type)_cffi_to_c_i8(o)) : \ - sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ - : (type)_cffi_to_c_i16(o)) : \ - sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ - : (type)_cffi_to_c_i32(o)) : \ - sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ - : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), (type)0))) - -#define _cffi_to_c_i8 \ - ((int(*)(PyObject *))_cffi_exports[1]) -#define _cffi_to_c_u8 \ - ((int(*)(PyObject *))_cffi_exports[2]) -#define _cffi_to_c_i16 \ - ((int(*)(PyObject *))_cffi_exports[3]) -#define _cffi_to_c_u16 \ - ((int(*)(PyObject *))_cffi_exports[4]) -#define _cffi_to_c_i32 \ - ((int(*)(PyObject *))_cffi_exports[5]) -#define _cffi_to_c_u32 \ - ((unsigned int(*)(PyObject *))_cffi_exports[6]) -#define _cffi_to_c_i64 \ - ((long long(*)(PyObject *))_cffi_exports[7]) -#define _cffi_to_c_u64 \ - ((unsigned long long(*)(PyObject *))_cffi_exports[8]) -#define _cffi_to_c_char \ - ((int(*)(PyObject *))_cffi_exports[9]) -#define _cffi_from_c_pointer \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) -#define _cffi_to_c_pointer \ - ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) -#define _cffi_get_struct_layout \ - ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) -#define _cffi_restore_errno \ - ((void(*)(void))_cffi_exports[13]) -#define _cffi_save_errno \ - ((void(*)(void))_cffi_exports[14]) -#define _cffi_from_c_char \ - ((PyObject *(*)(char))_cffi_exports[15]) -#define _cffi_from_c_deref \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) -#define _cffi_to_c \ - ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) -#define _cffi_from_c_struct \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) -#define _cffi_to_c_wchar_t \ - ((wchar_t(*)(PyObject *))_cffi_exports[19]) -#define _cffi_from_c_wchar_t \ - ((PyObject *(*)(wchar_t))_cffi_exports[20]) -#define _cffi_to_c_long_double \ - ((long double(*)(PyObject *))_cffi_exports[21]) -#define _cffi_to_c__Bool \ - ((_Bool(*)(PyObject *))_cffi_exports[22]) -#define _cffi_prepare_pointer_call_argument \ - ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) -#define _cffi_convert_array_from_object \ - ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) -#define _CFFI_NUM_EXPORTS 25 - -typedef struct _ctypedescr CTypeDescrObject; - -static void *_cffi_exports[_CFFI_NUM_EXPORTS]; -static PyObject *_cffi_types, *_cffi_VerificationError; - -static int _cffi_setup_custom(PyObject *lib); /* forward */ - -static PyObject *_cffi_setup(PyObject *self, PyObject *args) -{ - PyObject *library; - int was_alive = (_cffi_types != NULL); - (void)self; /* unused */ - if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, - &library)) - return NULL; - Py_INCREF(_cffi_types); - Py_INCREF(_cffi_VerificationError); - if (_cffi_setup_custom(library) < 0) - return NULL; - return PyBool_FromLong(was_alive); -} - -union _cffi_union_alignment_u { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; - long double m_longdouble; -}; - -struct _cffi_freeme_s { - struct _cffi_freeme_s *next; - union _cffi_union_alignment_u alignment; -}; - -#ifdef __GNUC__ - __attribute__((unused)) -#endif -static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, - char **output_data, Py_ssize_t datasize, - struct _cffi_freeme_s **freeme) -{ - char *p; - if (datasize < 0) - return -1; - - p = *output_data; - if (p == NULL) { - struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( - offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); - if (fp == NULL) - return -1; - fp->next = *freeme; - *freeme = fp; - p = *output_data = (char *)&fp->alignment; - } - memset((void *)p, 0, (size_t)datasize); - return _cffi_convert_array_from_object(p, ctptr, arg); -} - -#ifdef __GNUC__ - __attribute__((unused)) -#endif -static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) -{ - do { - void *p = (void *)freeme; - freeme = freeme->next; - PyObject_Free(p); - } while (freeme != NULL); -} - -static int _cffi_init(void) -{ - PyObject *module, *c_api_object = NULL; - - module = PyImport_ImportModule("_cffi_backend"); - if (module == NULL) - goto failure; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - if (c_api_object == NULL) - goto failure; - if (!PyCapsule_CheckExact(c_api_object)) { - PyErr_SetNone(PyExc_ImportError); - goto failure; - } - memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), - _CFFI_NUM_EXPORTS * sizeof(void *)); - - Py_DECREF(module); - Py_DECREF(c_api_object); - return 0; - - failure: - Py_XDECREF(module); - Py_XDECREF(c_api_object); - return -1; -} - -#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) - -/**********/ -''' diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/vengine_gen.py b/backend/venv39/lib/python3.9/site-packages/cffi/vengine_gen.py deleted file mode 100644 index bffc821..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/vengine_gen.py +++ /dev/null @@ -1,679 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys, os -import types - -from . import model -from .error import VerificationError - - -class VGenericEngine(object): - _class_key = 'g' - _gen_python_module = False - - def __init__(self, verifier): - self.verifier = verifier - self.ffi = verifier.ffi - self.export_symbols = [] - self._struct_pending_verification = {} - - def patch_extension_kwds(self, kwds): - # add 'export_symbols' to the dictionary. Note that we add the - # list before filling it. When we fill it, it will thus also show - # up in kwds['export_symbols']. - kwds.setdefault('export_symbols', self.export_symbols) - - def find_module(self, module_name, path, so_suffixes): - for so_suffix in so_suffixes: - basename = module_name + so_suffix - if path is None: - path = sys.path - for dirname in path: - filename = os.path.join(dirname, basename) - if os.path.isfile(filename): - return filename - - def collect_types(self): - pass # not needed in the generic engine - - def _prnt(self, what=''): - self._f.write(what + '\n') - - def write_source_to_f(self): - prnt = self._prnt - # first paste some standard set of lines that are mostly '#include' - prnt(cffimod_header) - # then paste the C source given by the user, verbatim. - prnt(self.verifier.preamble) - # - # call generate_gen_xxx_decl(), for every xxx found from - # ffi._parser._declarations. This generates all the functions. - self._generate('decl') - # - # on Windows, distutils insists on putting init_cffi_xyz in - # 'export_symbols', so instead of fighting it, just give up and - # give it one - if sys.platform == 'win32': - if sys.version_info >= (3,): - prefix = 'PyInit_' - else: - prefix = 'init' - modname = self.verifier.get_module_name() - prnt("void %s%s(void) { }\n" % (prefix, modname)) - - def load_library(self, flags=0): - # import it with the CFFI backend - backend = self.ffi._backend - # needs to make a path that contains '/', on Posix - filename = os.path.join(os.curdir, self.verifier.modulefilename) - module = backend.load_library(filename, flags) - # - # call loading_gen_struct() to get the struct layout inferred by - # the C compiler - self._load(module, 'loading') - - # build the FFILibrary class and instance, this is a module subclass - # because modules are expected to have usually-constant-attributes and - # in PyPy this means the JIT is able to treat attributes as constant, - # which we want. - class FFILibrary(types.ModuleType): - _cffi_generic_module = module - _cffi_ffi = self.ffi - _cffi_dir = [] - def __dir__(self): - return FFILibrary._cffi_dir - library = FFILibrary("") - # - # finally, call the loaded_gen_xxx() functions. This will set - # up the 'library' object. - self._load(module, 'loaded', library=library) - return library - - def _get_declarations(self): - lst = [(key, tp) for (key, (tp, qual)) in - self.ffi._parser._declarations.items()] - lst.sort() - return lst - - def _generate(self, step_name): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - try: - method = getattr(self, '_generate_gen_%s_%s' % (kind, - step_name)) - except AttributeError: - raise VerificationError( - "not implemented in verify(): %r" % name) - try: - method(tp, realname) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _load(self, module, step_name, **kwds): - for name, tp in self._get_declarations(): - kind, realname = name.split(' ', 1) - method = getattr(self, '_%s_gen_%s' % (step_name, kind)) - try: - method(tp, realname, module, **kwds) - except Exception as e: - model.attach_exception_info(e, name) - raise - - def _generate_nothing(self, tp, name): - pass - - def _loaded_noop(self, tp, name, module, **kwds): - pass - - # ---------- - # typedefs: generates no code so far - - _generate_gen_typedef_decl = _generate_nothing - _loading_gen_typedef = _loaded_noop - _loaded_gen_typedef = _loaded_noop - - # ---------- - # function declarations - - def _generate_gen_function_decl(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - # cannot support vararg functions better than this: check for its - # exact type (including the fixed arguments), and build it as a - # constant function pointer (no _cffi_f_%s wrapper) - self._generate_gen_const(False, name, tp) - return - prnt = self._prnt - numargs = len(tp.args) - argnames = [] - for i, type in enumerate(tp.args): - indirection = '' - if isinstance(type, model.StructOrUnion): - indirection = '*' - argnames.append('%sx%d' % (indirection, i)) - context = 'argument of %s' % name - arglist = [type.get_c_name(' %s' % arg, context) - for type, arg in zip(tp.args, argnames)] - tpresult = tp.result - if isinstance(tpresult, model.StructOrUnion): - arglist.insert(0, tpresult.get_c_name(' *r', context)) - tpresult = model.void_type - arglist = ', '.join(arglist) or 'void' - wrappername = '_cffi_f_%s' % name - self.export_symbols.append(wrappername) - if tp.abi: - abi = tp.abi + ' ' - else: - abi = '' - funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) - context = 'result of %s' % name - prnt(tpresult.get_c_name(funcdecl, context)) - prnt('{') - # - if isinstance(tp.result, model.StructOrUnion): - result_code = '*r = ' - elif not isinstance(tp.result, model.VoidType): - result_code = 'return ' - else: - result_code = '' - prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) - prnt('}') - prnt() - - _loading_gen_function = _loaded_noop - - def _loaded_gen_function(self, tp, name, module, library): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - newfunction = self._load_constant(False, tp, name, module) - else: - indirections = [] - base_tp = tp - if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) - or isinstance(tp.result, model.StructOrUnion)): - indirect_args = [] - for i, typ in enumerate(tp.args): - if isinstance(typ, model.StructOrUnion): - typ = model.PointerType(typ) - indirections.append((i, typ)) - indirect_args.append(typ) - indirect_result = tp.result - if isinstance(indirect_result, model.StructOrUnion): - if indirect_result.fldtypes is None: - raise TypeError("'%s' is used as result type, " - "but is opaque" % ( - indirect_result._get_c_name(),)) - indirect_result = model.PointerType(indirect_result) - indirect_args.insert(0, indirect_result) - indirections.insert(0, ("result", indirect_result)) - indirect_result = model.void_type - tp = model.FunctionPtrType(tuple(indirect_args), - indirect_result, tp.ellipsis) - BFunc = self.ffi._get_cached_btype(tp) - wrappername = '_cffi_f_%s' % name - newfunction = module.load_function(BFunc, wrappername) - for i, typ in indirections: - newfunction = self._make_struct_wrapper(newfunction, i, typ, - base_tp) - setattr(library, name, newfunction) - type(library)._cffi_dir.append(name) - - def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): - backend = self.ffi._backend - BType = self.ffi._get_cached_btype(tp) - if i == "result": - ffi = self.ffi - def newfunc(*args): - res = ffi.new(BType) - oldfunc(res, *args) - return res[0] - else: - def newfunc(*args): - args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] - return oldfunc(*args) - newfunc._cffi_base_type = base_tp - return newfunc - - # ---------- - # named structs - - def _generate_gen_struct_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'struct', name) - - def _loading_gen_struct(self, tp, name, module): - self._loading_struct_or_union(tp, 'struct', name, module) - - def _loaded_gen_struct(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_gen_union_decl(self, tp, name): - assert name == tp.name - self._generate_struct_or_union_decl(tp, 'union', name) - - def _loading_gen_union(self, tp, name, module): - self._loading_struct_or_union(tp, 'union', name, module) - - def _loaded_gen_union(self, tp, name, module, **kwds): - self._loaded_struct_or_union(tp) - - def _generate_struct_or_union_decl(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - checkfuncname = '_cffi_check_%s_%s' % (prefix, name) - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - cname = ('%s %s' % (prefix, name)).strip() - # - prnt = self._prnt - prnt('static void %s(%s *p)' % (checkfuncname, cname)) - prnt('{') - prnt(' /* only to generate compile-time warnings or errors */') - prnt(' (void)p;') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()) or fbitsize >= 0: - # accept all integers, but complain on float or double - prnt(' (void)((p->%s) << 1);' % fname) - else: - # only accept exactly the type declared. - try: - prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), - fname)) - except VerificationError as e: - prnt(' /* %s */' % str(e)) # cannot verify it, ignore - prnt('}') - self.export_symbols.append(layoutfuncname) - prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) - prnt('{') - prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) - prnt(' static intptr_t nums[] = {') - prnt(' sizeof(%s),' % cname) - prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - prnt(' offsetof(%s, %s),' % (cname, fname)) - if isinstance(ftype, model.ArrayType) and ftype.length is None: - prnt(' 0, /* %s */' % ftype._get_c_name()) - else: - prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) - prnt(' -1') - prnt(' };') - prnt(' return nums[i];') - prnt(' /* the next line is not executed, but compiled */') - prnt(' %s(0);' % (checkfuncname,)) - prnt('}') - prnt() - - def _loading_struct_or_union(self, tp, prefix, name, module): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - # - BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] - function = module.load_function(BFunc, layoutfuncname) - layout = [] - num = 0 - while True: - x = function(num) - if x < 0: break - layout.append(x) - num += 1 - if isinstance(tp, model.StructOrUnion) and tp.partial: - # use the function()'s sizes and offsets to guide the - # layout of the struct - totalsize = layout[0] - totalalignment = layout[1] - fieldofs = layout[2::2] - fieldsize = layout[3::2] - tp.force_flatten() - assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) - tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment - else: - cname = ('%s %s' % (prefix, name)).strip() - self._struct_pending_verification[tp] = layout, cname - - def _loaded_struct_or_union(self, tp): - if tp.fldnames is None: - return # nothing to do with opaque structs - self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered - - if tp in self._struct_pending_verification: - # check that the layout sizes and offsets match the real ones - def check(realvalue, expectedvalue, msg): - if realvalue != expectedvalue: - raise VerificationError( - "%s (we have %d, but C compiler says %d)" - % (msg, expectedvalue, realvalue)) - ffi = self.ffi - BStruct = ffi._get_cached_btype(tp) - layout, cname = self._struct_pending_verification.pop(tp) - check(layout[0], ffi.sizeof(BStruct), "wrong total size") - check(layout[1], ffi.alignof(BStruct), "wrong total alignment") - i = 2 - for fname, ftype, fbitsize, fqual in tp.enumfields(): - if fbitsize >= 0: - continue # xxx ignore fbitsize for now - check(layout[i], ffi.offsetof(BStruct, fname), - "wrong offset for field %r" % (fname,)) - if layout[i+1] != 0: - BField = ffi._get_cached_btype(ftype) - check(layout[i+1], ffi.sizeof(BField), - "wrong size for field %r" % (fname,)) - i += 2 - assert i == len(layout) - - # ---------- - # 'anonymous' declarations. These are produced for anonymous structs - # or unions; the 'name' is obtained by a typedef. - - def _generate_gen_anonymous_decl(self, tp, name): - if isinstance(tp, model.EnumType): - self._generate_gen_enum_decl(tp, name, '') - else: - self._generate_struct_or_union_decl(tp, '', name) - - def _loading_gen_anonymous(self, tp, name, module): - if isinstance(tp, model.EnumType): - self._loading_gen_enum(tp, name, module, '') - else: - self._loading_struct_or_union(tp, '', name, module) - - def _loaded_gen_anonymous(self, tp, name, module, **kwds): - if isinstance(tp, model.EnumType): - self._loaded_gen_enum(tp, name, module, **kwds) - else: - self._loaded_struct_or_union(tp) - - # ---------- - # constants, likely declared with '#define' - - def _generate_gen_const(self, is_int, name, tp=None, category='const', - check_value=None): - prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - self.export_symbols.append(funcname) - if check_value is not None: - assert is_int - assert category == 'const' - prnt('int %s(char *out_error)' % funcname) - prnt('{') - self._check_int_constant_value(name, check_value) - prnt(' return 0;') - prnt('}') - elif is_int: - assert category == 'const' - prnt('int %s(long long *out_value)' % funcname) - prnt('{') - prnt(' *out_value = (long long)(%s);' % (name,)) - prnt(' return (%s) <= 0;' % (name,)) - prnt('}') - else: - assert tp is not None - assert check_value is None - if category == 'var': - ampersand = '&' - else: - ampersand = '' - extra = '' - if category == 'const' and isinstance(tp, model.StructOrUnion): - extra = 'const *' - ampersand = '&' - prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) - prnt('{') - prnt(' return (%s%s);' % (ampersand, name)) - prnt('}') - prnt() - - def _generate_gen_constant_decl(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - self._generate_gen_const(is_int, name, tp) - - _loading_gen_constant = _loaded_noop - - def _load_constant(self, is_int, tp, name, module, check_value=None): - funcname = '_cffi_const_%s' % name - if check_value is not None: - assert is_int - self._load_known_int_constant(module, funcname) - value = check_value - elif is_int: - BType = self.ffi._typeof_locked("long long*")[0] - BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType) - negative = function(p) - value = int(p[0]) - if value < 0 and not negative: - BLongLong = self.ffi._typeof_locked("long long")[0] - value += (1 << (8*self.ffi.sizeof(BLongLong))) - else: - assert check_value is None - fntypeextra = '(*)(void)' - if isinstance(tp, model.StructOrUnion): - fntypeextra = '*' + fntypeextra - BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] - function = module.load_function(BFunc, funcname) - value = function() - if isinstance(tp, model.StructOrUnion): - value = value[0] - return value - - def _loaded_gen_constant(self, tp, name, module, library): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - value = self._load_constant(is_int, tp, name, module) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - - # ---------- - # enums - - def _check_int_constant_value(self, name, value): - prnt = self._prnt - if value <= 0: - prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( - name, name, value)) - else: - prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( - name, name, value)) - prnt(' char buf[64];') - prnt(' if ((%s) <= 0)' % name) - prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) - prnt(' else') - prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % - name) - prnt(' sprintf(out_error, "%s has the real value %s, not %s",') - prnt(' "%s", buf, "%d");' % (name[:100], value)) - prnt(' return -1;') - prnt(' }') - - def _load_known_int_constant(self, module, funcname): - BType = self.ffi._typeof_locked("char[]")[0] - BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType, 256) - if function(p) < 0: - error = self.ffi.string(p) - if sys.version_info >= (3,): - error = str(error, 'utf-8') - raise VerificationError(error) - - def _enum_funcname(self, prefix, name): - # "$enum_$1" => "___D_enum____D_1" - name = name.replace('$', '___D_') - return '_cffi_e_%s_%s' % (prefix, name) - - def _generate_gen_enum_decl(self, tp, name, prefix='enum'): - if tp.partial: - for enumerator in tp.enumerators: - self._generate_gen_const(True, enumerator) - return - # - funcname = self._enum_funcname(prefix, name) - self.export_symbols.append(funcname) - prnt = self._prnt - prnt('int %s(char *out_error)' % funcname) - prnt('{') - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - self._check_int_constant_value(enumerator, enumvalue) - prnt(' return 0;') - prnt('}') - prnt() - - def _loading_gen_enum(self, tp, name, module, prefix='enum'): - if tp.partial: - enumvalues = [self._load_constant(True, tp, enumerator, module) - for enumerator in tp.enumerators] - tp.enumvalues = tuple(enumvalues) - tp.partial_resolved = True - else: - funcname = self._enum_funcname(prefix, name) - self._load_known_int_constant(module, funcname) - - def _loaded_gen_enum(self, tp, name, module, library): - for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - setattr(library, enumerator, enumvalue) - type(library)._cffi_dir.append(enumerator) - - # ---------- - # macros: for now only for integers - - def _generate_gen_macro_decl(self, tp, name): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - self._generate_gen_const(True, name, check_value=check_value) - - _loading_gen_macro = _loaded_noop - - def _loaded_gen_macro(self, tp, name, module, library): - if tp == '...': - check_value = None - else: - check_value = tp # an integer - value = self._load_constant(True, tp, name, module, - check_value=check_value) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - - # ---------- - # global variables - - def _generate_gen_variable_decl(self, tp, name): - if isinstance(tp, model.ArrayType): - if tp.length_is_unknown(): - prnt = self._prnt - funcname = '_cffi_sizeof_%s' % (name,) - self.export_symbols.append(funcname) - prnt("size_t %s(void)" % funcname) - prnt("{") - prnt(" return sizeof(%s);" % (name,)) - prnt("}") - tp_ptr = model.PointerType(tp.item) - self._generate_gen_const(False, name, tp_ptr) - else: - tp_ptr = model.PointerType(tp) - self._generate_gen_const(False, name, tp_ptr, category='var') - - _loading_gen_variable = _loaded_noop - - def _loaded_gen_variable(self, tp, name, module, library): - if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the - # sense that "a=..." is forbidden - if tp.length_is_unknown(): - funcname = '_cffi_sizeof_%s' % (name,) - BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] - function = module.load_function(BFunc, funcname) - size = function() - BItemType = self.ffi._get_cached_btype(tp.item) - length, rest = divmod(size, self.ffi.sizeof(BItemType)) - if rest != 0: - raise VerificationError( - "bad size: %r does not seem to be an array of %s" % - (name, tp.item)) - tp = tp.resolve_length(length) - tp_ptr = model.PointerType(tp.item) - value = self._load_constant(False, tp_ptr, name, module) - # 'value' is a which we have to replace with - # a if the N is actually known - if tp.length is not None: - BArray = self.ffi._get_cached_btype(tp) - value = self.ffi.cast(BArray, value) - setattr(library, name, value) - type(library)._cffi_dir.append(name) - return - # remove ptr= from the library instance, and replace - # it by a property on the class, which reads/writes into ptr[0]. - funcname = '_cffi_var_%s' % name - BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] - function = module.load_function(BFunc, funcname) - ptr = function() - def getter(library): - return ptr[0] - def setter(library, value): - ptr[0] = value - setattr(type(library), name, property(getter, setter)) - type(library)._cffi_dir.append(name) - -cffimod_header = r''' -#include -#include -#include -#include -#include /* XXX for ssize_t on some platforms */ - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py - and cffi/_cffi_include.h */ -#if defined(_MSC_VER) -# include /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ -# ifndef __cplusplus - typedef unsigned char _Bool; -# endif -# endif -# define _cffi_float_complex_t _Fcomplex /* include for it */ -# define _cffi_double_complex_t _Dcomplex /* include for it */ -#else -# include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include -# endif -# define _cffi_float_complex_t float _Complex -# define _cffi_double_complex_t double _Complex -#endif -''' diff --git a/backend/venv39/lib/python3.9/site-packages/cffi/verifier.py b/backend/venv39/lib/python3.9/site-packages/cffi/verifier.py deleted file mode 100644 index e392a2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cffi/verifier.py +++ /dev/null @@ -1,306 +0,0 @@ -# -# DEPRECATED: implementation for ffi.verify() -# -import sys, os, binascii, shutil, io -from . import __version_verifier_modules__ -from . import ffiplatform -from .error import VerificationError - -if sys.version_info >= (3, 3): - import importlib.machinery - def _extension_suffixes(): - return importlib.machinery.EXTENSION_SUFFIXES[:] -else: - import imp - def _extension_suffixes(): - return [suffix for suffix, _, type in imp.get_suffixes() - if type == imp.C_EXTENSION] - - -if sys.version_info >= (3,): - NativeIO = io.StringIO -else: - class NativeIO(io.BytesIO): - def write(self, s): - if isinstance(s, unicode): - s = s.encode('ascii') - super(NativeIO, self).write(s) - - -class Verifier(object): - - def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, - source_extension='.c', flags=None, relative_to=None, **kwds): - if ffi._parser._uses_new_feature: - raise VerificationError( - "feature not supported with ffi.verify(), but only " - "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) - self.ffi = ffi - self.preamble = preamble - if not modulename: - flattened_kwds = ffiplatform.flatten(kwds) - vengine_class = _locate_engine_class(ffi, force_generic_engine) - self._vengine = vengine_class(self) - self._vengine.patch_extension_kwds(kwds) - self.flags = flags - self.kwds = self.make_relative_to(kwds, relative_to) - # - if modulename: - if tag: - raise TypeError("can't specify both 'modulename' and 'tag'") - else: - key = '\x00'.join(['%d.%d' % sys.version_info[:2], - __version_verifier_modules__, - preamble, flattened_kwds] + - ffi._cdefsources) - if sys.version_info >= (3,): - key = key.encode('utf-8') - k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) - k1 = k1.lstrip('0x').rstrip('L') - k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) - k2 = k2.lstrip('0').rstrip('L') - modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, - k1, k2) - suffix = _get_so_suffixes()[0] - self.tmpdir = tmpdir or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) - self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) - self.ext_package = ext_package - self._has_source = False - self._has_module = False - - def write_source(self, file=None): - """Write the C source code. It is produced in 'self.sourcefilename', - which can be tweaked beforehand.""" - with self.ffi._lock: - if self._has_source and file is None: - raise VerificationError( - "source code already written") - self._write_source(file) - - def compile_module(self): - """Write the C source code (if not done already) and compile it. - This produces a dynamic link library in 'self.modulefilename'.""" - with self.ffi._lock: - if self._has_module: - raise VerificationError("module already compiled") - if not self._has_source: - self._write_source() - self._compile_module() - - def load_library(self): - """Get a C module from this Verifier instance. - Returns an instance of a FFILibrary class that behaves like the - objects returned by ffi.dlopen(), but that delegates all - operations to the C module. If necessary, the C code is written - and compiled first. - """ - with self.ffi._lock: - if not self._has_module: - self._locate_module() - if not self._has_module: - if not self._has_source: - self._write_source() - self._compile_module() - return self._load_library() - - def get_module_name(self): - basename = os.path.basename(self.modulefilename) - # kill both the .so extension and the other .'s, as introduced - # by Python 3: 'basename.cpython-33m.so' - basename = basename.split('.', 1)[0] - # and the _d added in Python 2 debug builds --- but try to be - # conservative and not kill a legitimate _d - if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): - basename = basename[:-2] - return basename - - def get_extension(self): - if not self._has_source: - with self.ffi._lock: - if not self._has_source: - self._write_source() - sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) - modname = self.get_module_name() - return ffiplatform.get_extension(sourcename, modname, **self.kwds) - - def generates_python_module(self): - return self._vengine._gen_python_module - - def make_relative_to(self, kwds, relative_to): - if relative_to and os.path.dirname(relative_to): - dirname = os.path.dirname(relative_to) - kwds = kwds.copy() - for key in ffiplatform.LIST_OF_FILE_NAMES: - if key in kwds: - lst = kwds[key] - if not isinstance(lst, (list, tuple)): - raise TypeError("keyword '%s' should be a list or tuple" - % (key,)) - lst = [os.path.join(dirname, fn) for fn in lst] - kwds[key] = lst - return kwds - - # ---------- - - def _locate_module(self): - if not os.path.isfile(self.modulefilename): - if self.ext_package: - try: - pkg = __import__(self.ext_package, None, None, ['__doc__']) - except ImportError: - return # cannot import the package itself, give up - # (e.g. it might be called differently before installation) - path = pkg.__path__ - else: - path = None - filename = self._vengine.find_module(self.get_module_name(), path, - _get_so_suffixes()) - if filename is None: - return - self.modulefilename = filename - self._vengine.collect_types() - self._has_module = True - - def _write_source_to(self, file): - self._vengine._f = file - try: - self._vengine.write_source_to_f() - finally: - del self._vengine._f - - def _write_source(self, file=None): - if file is not None: - self._write_source_to(file) - else: - # Write our source file to an in memory file. - f = NativeIO() - self._write_source_to(f) - source_data = f.getvalue() - - # Determine if this matches the current file - if os.path.exists(self.sourcefilename): - with open(self.sourcefilename, "r") as fp: - needs_written = not (fp.read() == source_data) - else: - needs_written = True - - # Actually write the file out if it doesn't match - if needs_written: - _ensure_dir(self.sourcefilename) - with open(self.sourcefilename, "w") as fp: - fp.write(source_data) - - # Set this flag - self._has_source = True - - def _compile_module(self): - # compile this C source - tmpdir = os.path.dirname(self.sourcefilename) - outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) - try: - same = ffiplatform.samefile(outputfilename, self.modulefilename) - except OSError: - same = False - if not same: - _ensure_dir(self.modulefilename) - shutil.move(outputfilename, self.modulefilename) - self._has_module = True - - def _load_library(self): - assert self._has_module - if self.flags is not None: - return self._vengine.load_library(self.flags) - else: - return self._vengine.load_library() - -# ____________________________________________________________ - -_FORCE_GENERIC_ENGINE = False # for tests - -def _locate_engine_class(ffi, force_generic_engine): - if _FORCE_GENERIC_ENGINE: - force_generic_engine = True - if not force_generic_engine: - if '__pypy__' in sys.builtin_module_names: - force_generic_engine = True - else: - try: - import _cffi_backend - except ImportError: - _cffi_backend = '?' - if ffi._backend is not _cffi_backend: - force_generic_engine = True - if force_generic_engine: - from . import vengine_gen - return vengine_gen.VGenericEngine - else: - from . import vengine_cpy - return vengine_cpy.VCPythonEngine - -# ____________________________________________________________ - -_TMPDIR = None - -def _caller_dir_pycache(): - if _TMPDIR: - return _TMPDIR - result = os.environ.get('CFFI_TMPDIR') - if result: - return result - filename = sys._getframe(2).f_code.co_filename - return os.path.abspath(os.path.join(os.path.dirname(filename), - '__pycache__')) - -def set_tmpdir(dirname): - """Set the temporary directory to use instead of __pycache__.""" - global _TMPDIR - _TMPDIR = dirname - -def cleanup_tmpdir(tmpdir=None, keep_so=False): - """Clean up the temporary directory by removing all files in it - called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" - tmpdir = tmpdir or _caller_dir_pycache() - try: - filelist = os.listdir(tmpdir) - except OSError: - return - if keep_so: - suffix = '.c' # only remove .c files - else: - suffix = _get_so_suffixes()[0].lower() - for fn in filelist: - if fn.lower().startswith('_cffi_') and ( - fn.lower().endswith(suffix) or fn.lower().endswith('.c')): - try: - os.unlink(os.path.join(tmpdir, fn)) - except OSError: - pass - clean_dir = [os.path.join(tmpdir, 'build')] - for dir in clean_dir: - try: - for fn in os.listdir(dir): - fn = os.path.join(dir, fn) - if os.path.isdir(fn): - clean_dir.append(fn) - else: - os.unlink(fn) - except OSError: - pass - -def _get_so_suffixes(): - suffixes = _extension_suffixes() - if not suffixes: - # bah, no C_EXTENSION available. Occurs on pypy without cpyext - if sys.platform == 'win32': - suffixes = [".pyd"] - else: - suffixes = [".so"] - - return suffixes - -def _ensure_dir(filename): - dirname = os.path.dirname(filename) - if dirname and not os.path.isdir(dirname): - os.makedirs(dirname) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/METADATA deleted file mode 100644 index 8d32edc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/METADATA +++ /dev/null @@ -1,764 +0,0 @@ -Metadata-Version: 2.4 -Name: charset-normalizer -Version: 3.4.4 -Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. -Author-email: "Ahmed R. TAHRI" -Maintainer-email: "Ahmed R. TAHRI" -License: MIT -Project-URL: Changelog, https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md -Project-URL: Documentation, https://charset-normalizer.readthedocs.io/ -Project-URL: Code, https://github.com/jawah/charset_normalizer -Project-URL: Issue tracker, https://github.com/jawah/charset_normalizer/issues -Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Text Processing :: Linguistic -Classifier: Topic :: Utilities -Classifier: Typing :: Typed -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -License-File: LICENSE -Provides-Extra: unicode-backport -Dynamic: license-file - -

    Charset Detection, for Everyone 👋

    - -

    - The Real First Universal Charset Detector
    - - - - - Download Count Total - - - - -

    -

    - Featured Packages
    - - Static Badge - - - Static Badge - -

    -

    - In other language (unofficial port - by the community)
    - - Static Badge - -

    - -> A library that helps you read text from an unknown charset encoding.
    Motivated by `chardet`, -> I'm trying to resolve the issue by taking a new approach. -> All IANA character set names for which the Python core library provides codecs are supported. - -

    - >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<< -

    - -This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**. - -| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) | -|--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:| -| `Fast` | ❌ | ✅ | ✅ | -| `Universal**` | ❌ | ✅ | ❌ | -| `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ | -| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ | -| `License` | LGPL-2.1
    _restrictive_ | MIT | MPL-1.1
    _restrictive_ | -| `Native Python` | ✅ | ✅ | ❌ | -| `Detect spoken language` | ❌ | ✅ | N/A | -| `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ | -| `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB | -| `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 | - -

    -Reading Normalized TextCat Reading Text -

    - -*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
    - -## ⚡ Performance - -This package offer better performance than its counterpart Chardet. Here are some numbers. - -| Package | Accuracy | Mean per file (ms) | File per sec (est) | -|-----------------------------------------------|:--------:|:------------------:|:------------------:| -| [chardet](https://github.com/chardet/chardet) | 86 % | 63 ms | 16 file/sec | -| charset-normalizer | **98 %** | **10 ms** | 100 file/sec | - -| Package | 99th percentile | 95th percentile | 50th percentile | -|-----------------------------------------------|:---------------:|:---------------:|:---------------:| -| [chardet](https://github.com/chardet/chardet) | 265 ms | 71 ms | 7 ms | -| charset-normalizer | 100 ms | 50 ms | 5 ms | - -_updated as of december 2024 using CPython 3.12_ - -Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload. - -> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. -> And yes, these results might change at any time. The dataset can be updated to include more files. -> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. -> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability -> (e.g. Supported Encoding) Challenge-them if you want. - -## ✨ Installation - -Using pip: - -```sh -pip install charset-normalizer -U -``` - -## 🚀 Basic Usage - -### CLI -This package comes with a CLI. - -``` -usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] - file [file ...] - -The Real First Universal Charset Detector. Discover originating encoding used -on text file. Normalize text to unicode. - -positional arguments: - files File(s) to be analysed - -optional arguments: - -h, --help show this help message and exit - -v, --verbose Display complementary information about file if any. - Stdout will contain logs about the detection process. - -a, --with-alternative - Output complementary possibilities if any. Top-level - JSON WILL be a list. - -n, --normalize Permit to normalize input file. If not set, program - does not write anything. - -m, --minimal Only output the charset detected to STDOUT. Disabling - JSON output. - -r, --replace Replace file when trying to normalize it instead of - creating a new one. - -f, --force Replace file without asking if you are sure, use this - flag with caution. - -t THRESHOLD, --threshold THRESHOLD - Define a custom maximum amount of chaos allowed in - decoded content. 0. <= chaos <= 1. - --version Show version information and exit. -``` - -```bash -normalizer ./data/sample.1.fr.srt -``` - -or - -```bash -python -m charset_normalizer ./data/sample.1.fr.srt -``` - -🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. - -```json -{ - "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", - "encoding": "cp1252", - "encoding_aliases": [ - "1252", - "windows_1252" - ], - "alternative_encodings": [ - "cp1254", - "cp1256", - "cp1258", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - "mbcs" - ], - "language": "French", - "alphabets": [ - "Basic Latin", - "Latin-1 Supplement" - ], - "has_sig_or_bom": false, - "chaos": 0.149, - "coherence": 97.152, - "unicode_path": null, - "is_preferred": true -} -``` - -### Python -*Just print out normalized text* -```python -from charset_normalizer import from_path - -results = from_path('./my_subtitle.srt') - -print(str(results.best())) -``` - -*Upgrade your code without effort* -```python -from charset_normalizer import detect -``` - -The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. - -See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) - -## 😇 Why - -When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a -reliable alternative using a completely different method. Also! I never back down on a good challenge! - -I **don't care** about the **originating charset** encoding, because **two different tables** can -produce **two identical rendered string.** -What I want is to get readable text, the best I can. - -In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 - -Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair Unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. - -## 🍰 How - - - Discard all charset encoding table that could not fit the binary content. - - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. - - Extract matches with the lowest mess detected. - - Additionally, we measure coherence / probe for a language. - -**Wait a minute**, what is noise/mess and coherence according to **YOU ?** - -*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then -**I established** some ground rules about **what is obvious** when **it seems like** a mess (aka. defining noise in rendered text). - I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to - improve or rewrite it. - -*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought -that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. - -## ⚡ Known limitations - - - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) - - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. - -## ⚠️ About Python EOLs - -**If you are running:** - -- Python >=2.7,<3.5: Unsupported -- Python 3.5: charset-normalizer < 2.1 -- Python 3.6: charset-normalizer < 3.1 -- Python 3.7: charset-normalizer < 4.0 - -Upgrade your Python interpreter as soon as possible. - -## 👤 Contributing - -Contributions, issues and feature requests are very much welcome.
    -Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. - -## 📝 License - -Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
    -This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. - -Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) - -## 💼 For Enterprise - -Professional support for charset-normalizer is available as part of the [Tidelift -Subscription][1]. Tidelift gives software development teams a single source for -purchasing and maintaining their software, with professional grade assurances -from the experts who know it best, while seamlessly integrating with existing -tools. - -[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme - -[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297) - -# Changelog -All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## [3.4.4](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.4) (2025-10-13) - -### Changed -- Bound `setuptools` to a specific constraint `setuptools>=68,<=81`. -- Raised upper bound of mypyc for the optional pre-built extension to v1.18.2 - -### Removed -- `setuptools-scm` as a build dependency. - -### Misc -- Enforced hashes in `dev-requirements.txt` and created `ci-requirements.txt` for security purposes. -- Additional pre-built wheels for riscv64, s390x, and armv7l architectures. -- Restore ` multiple.intoto.jsonl` in GitHub releases in addition to individual attestation file per wheel. - -## [3.4.3](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.3) (2025-08-09) - -### Changed -- mypy(c) is no longer a required dependency at build time if `CHARSET_NORMALIZER_USE_MYPYC` isn't set to `1`. (#595) (#583) -- automatically lower confidence on small bytes samples that are not Unicode in `detect` output legacy function. (#391) - -### Added -- Custom build backend to overcome inability to mark mypy as an optional dependency in the build phase. -- Support for Python 3.14 - -### Fixed -- sdist archive contained useless directories. -- automatically fallback on valid UTF-16 or UTF-32 even if the md says it's noisy. (#633) - -### Misc -- SBOM are automatically published to the relevant GitHub release to comply with regulatory changes. - Each published wheel comes with its SBOM. We choose CycloneDX as the format. -- Prebuilt optimized wheel are no longer distributed by default for CPython 3.7 due to a change in cibuildwheel. - -## [3.4.2](https://github.com/Ousret/charset_normalizer/compare/3.4.1...3.4.2) (2025-05-02) - -### Fixed -- Addressed the DeprecationWarning in our CLI regarding `argparse.FileType` by backporting the target class into the package. (#591) -- Improved the overall reliability of the detector with CJK Ideographs. (#605) (#587) - -### Changed -- Optional mypyc compilation upgraded to version 1.15 for Python >= 3.8 - -## [3.4.1](https://github.com/Ousret/charset_normalizer/compare/3.4.0...3.4.1) (2024-12-24) - -### Changed -- Project metadata are now stored using `pyproject.toml` instead of `setup.cfg` using setuptools as the build backend. -- Enforce annotation delayed loading for a simpler and consistent types in the project. -- Optional mypyc compilation upgraded to version 1.14 for Python >= 3.8 - -### Added -- pre-commit configuration. -- noxfile. - -### Removed -- `build-requirements.txt` as per using `pyproject.toml` native build configuration. -- `bin/integration.py` and `bin/serve.py` in favor of downstream integration test (see noxfile). -- `setup.cfg` in favor of `pyproject.toml` metadata configuration. -- Unused `utils.range_scan` function. - -### Fixed -- Converting content to Unicode bytes may insert `utf_8` instead of preferred `utf-8`. (#572) -- Deprecation warning "'count' is passed as positional argument" when converting to Unicode bytes on Python 3.13+ - -## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08) - -### Added -- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints. -- Support for Python 3.13 (#512) - -### Fixed -- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch. -- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537) -- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381) - -## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) - -### Fixed -- Unintentional memory usage regression when using large payload that match several encoding (#376) -- Regression on some detection case showcased in the documentation (#371) - -### Added -- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) - -## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) - -### Changed -- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 -- Improved the general detection reliability based on reports from the community - -## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) - -### Added -- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` -- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) - -### Removed -- (internal) Redundant utils.is_ascii function and unused function is_private_use_only -- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant - -### Changed -- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection -- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 - -### Fixed -- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) - -## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) - -### Changed -- Typehint for function `from_path` no longer enforce `PathLike` as its first argument -- Minor improvement over the global detection reliability - -### Added -- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries -- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) -- Explicit support for Python 3.12 - -### Fixed -- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) - -## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) - -### Added -- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) - -### Removed -- Support for Python 3.6 (PR #260) - -### Changed -- Optional speedup provided by mypy/c 1.0.1 - -## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) - -### Fixed -- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) - -### Changed -- Speedup provided by mypy/c 0.990 on Python >= 3.7 - -## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) - -### Added -- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results -- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES -- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio -- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) - -### Changed -- Build with static metadata using 'build' frontend -- Make the language detection stricter -- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 - -### Fixed -- CLI with opt --normalize fail when using full path for files -- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it -- Sphinx warnings when generating the documentation - -### Removed -- Coherence detector no longer return 'Simple English' instead return 'English' -- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' -- Breaking: Method `first()` and `best()` from CharsetMatch -- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) -- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches -- Breaking: Top-level function `normalize` -- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch -- Support for the backport `unicodedata2` - -## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) - -### Added -- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results -- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES -- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio - -### Changed -- Build with static metadata using 'build' frontend -- Make the language detection stricter - -### Fixed -- CLI with opt --normalize fail when using full path for files -- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it - -### Removed -- Coherence detector no longer return 'Simple English' instead return 'English' -- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' - -## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) - -### Added -- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) - -### Removed -- Breaking: Method `first()` and `best()` from CharsetMatch -- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) - -### Fixed -- Sphinx warnings when generating the documentation - -## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) - -### Changed -- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 - -### Removed -- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches -- Breaking: Top-level function `normalize` -- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch -- Support for the backport `unicodedata2` - -## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) - -### Deprecated -- Function `normalize` scheduled for removal in 3.0 - -### Changed -- Removed useless call to decode in fn is_unprintable (#206) - -### Fixed -- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) - -## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) - -### Added -- Output the Unicode table version when running the CLI with `--version` (PR #194) - -### Changed -- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) -- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) - -### Fixed -- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) -- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) - -### Removed -- Support for Python 3.5 (PR #192) - -### Deprecated -- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) - -## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) - -### Fixed -- ASCII miss-detection on rare cases (PR #170) - -## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) - -### Added -- Explicit support for Python 3.11 (PR #164) - -### Changed -- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) - -## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) - -### Fixed -- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) - -### Changed -- Skipping the language-detection (CD) on ASCII (PR #155) - -## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) - -### Changed -- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) - -### Fixed -- Wrong logging level applied when setting kwarg `explain` to True (PR #146) - -## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) -### Changed -- Improvement over Vietnamese detection (PR #126) -- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) -- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) -- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) -- Code style as refactored by Sourcery-AI (PR #131) -- Minor adjustment on the MD around european words (PR #133) -- Remove and replace SRTs from assets / tests (PR #139) -- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) -- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) - -### Fixed -- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) -- Avoid using too insignificant chunk (PR #137) - -### Added -- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) -- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) - -## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) -### Added -- Add support for Kazakh (Cyrillic) language detection (PR #109) - -### Changed -- Further, improve inferring the language from a given single-byte code page (PR #112) -- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) -- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) -- Various detection improvement (MD+CD) (PR #117) - -### Removed -- Remove redundant logging entry about detected language(s) (PR #115) - -### Fixed -- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) - -## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) -### Fixed -- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) -- Fix CLI crash when using --minimal output in certain cases (PR #103) - -### Changed -- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) - -## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) -### Changed -- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) -- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) -- The Unicode detection is slightly improved (PR #93) -- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) - -### Removed -- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) - -### Fixed -- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) -- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) -- The MANIFEST.in was not exhaustive (PR #78) - -## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) -### Fixed -- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) -- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) -- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) -- Submatch factoring could be wrong in rare edge cases (PR #72) -- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) -- Fix line endings from CRLF to LF for certain project files (PR #67) - -### Changed -- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) -- Allow fallback on specified encoding if any (PR #71) - -## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) -### Changed -- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) -- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) - -## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) -### Fixed -- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) - -### Changed -- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) - -## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) -### Fixed -- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) -- Using explain=False permanently disable the verbose output in the current runtime (PR #47) -- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) -- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) - -### Changed -- Public function normalize default args values were not aligned with from_bytes (PR #53) - -### Added -- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) - -## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) -### Changed -- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. -- Accent has been made on UTF-8 detection, should perform rather instantaneous. -- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. -- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) -- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ -- utf_7 detection has been reinstated. - -### Removed -- This package no longer require anything when used with Python 3.5 (Dropped cached_property) -- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. -- The exception hook on UnicodeDecodeError has been removed. - -### Deprecated -- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 - -### Fixed -- The CLI output used the relative path of the file(s). Should be absolute. - -## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) -### Fixed -- Logger configuration/usage no longer conflict with others (PR #44) - -## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) -### Removed -- Using standard logging instead of using the package loguru. -- Dropping nose test framework in favor of the maintained pytest. -- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. -- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. -- Stop support for UTF-7 that does not contain a SIG. -- Dropping PrettyTable, replaced with pure JSON output in CLI. - -### Fixed -- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. -- Not searching properly for the BOM when trying utf32/16 parent codec. - -### Changed -- Improving the package final size by compressing frequencies.json. -- Huge improvement over the larges payload. - -### Added -- CLI now produces JSON consumable output. -- Return ASCII if given sequences fit. Given reasonable confidence. - -## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) - -### Fixed -- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) - -## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) - -### Fixed -- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) - -## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) - -### Fixed -- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) - -## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) - -### Changed -- Amend the previous release to allow prettytable 2.0 (PR #35) - -## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) - -### Fixed -- Fix error while using the package with a python pre-release interpreter (PR #33) - -### Changed -- Dependencies refactoring, constraints revised. - -### Added -- Add python 3.9 and 3.10 to the supported interpreters - -MIT License - -Copyright (c) 2025 TAHRI Ahmed R. - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/RECORD deleted file mode 100644 index e9103a6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/RECORD +++ /dev/null @@ -1,35 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cd.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/constant.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/legacy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/charset_normalizer/version.cpython-39.pyc,, -../../../bin/normalizer,sha256=y8ki1eD8N1Kye3N6HW5G_8zIB4LJGf9HqM10crglDb8,287 -charset_normalizer-3.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -charset_normalizer-3.4.4.dist-info/METADATA,sha256=jVuUFBti8dav19YLvWissTihVdF2ozUY4KKMw7jdkBQ,37303 -charset_normalizer-3.4.4.dist-info/RECORD,, -charset_normalizer-3.4.4.dist-info/WHEEL,sha256=Sli93J_eWejDC8SYRdplFsirRhz71iXfsqaGlL-WXt4,139 -charset_normalizer-3.4.4.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 -charset_normalizer-3.4.4.dist-info/licenses/LICENSE,sha256=bQ1Bv-FwrGx9wkjJpj4lTQ-0WmDVCoJX0K-SxuJJuIc,1071 -charset_normalizer-3.4.4.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 -charset_normalizer/__init__.py,sha256=OKRxRv2Zhnqk00tqkN0c1BtJjm165fWXLydE52IKuHc,1590 -charset_normalizer/__main__.py,sha256=yzYxMR-IhKRHYwcSlavEv8oGdwxsR89mr2X09qXGdps,109 -charset_normalizer/api.py,sha256=V07i8aVeCD8T2fSia3C-fn0i9t8qQguEBhsqszg32Ns,22668 -charset_normalizer/cd.py,sha256=WKTo1HDb-H9HfCDc3Bfwq5jzS25Ziy9SE2a74SgTq88,12522 -charset_normalizer/cli/__init__.py,sha256=D8I86lFk2-py45JvqxniTirSj_sFyE6sjaY_0-G1shc,136 -charset_normalizer/cli/__main__.py,sha256=dMaXG6IJXRvqq8z2tig7Qb83-BpWTln55ooiku5_uvg,12646 -charset_normalizer/constant.py,sha256=7UVY4ldYhmQMHUdgQ_sgZmzcQ0xxYxpBunqSZ-XJZ8U,42713 -charset_normalizer/legacy.py,sha256=sYBzSpzsRrg_wF4LP536pG64BItw7Tqtc3SMQAHvFLM,2731 -charset_normalizer/md.cpython-39-darwin.so,sha256=lMwdspv1dP5y_OV-I9n8Z3rcbHDLqeFGDuGlqHsxNjs,66592 -charset_normalizer/md.py,sha256=-_oN3h3_X99nkFfqamD3yu45DC_wfk5odH0Tr_CQiXs,20145 -charset_normalizer/md__mypyc.cpython-39-darwin.so,sha256=gthuGcYNH7ONQoBblBpiZXbfeARLfhBfK1_yegXTtuU,485592 -charset_normalizer/models.py,sha256=lKXhOnIPtiakbK3i__J9wpOfzx3JDTKj7Dn3Rg0VaRI,12394 -charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -charset_normalizer/utils.py,sha256=sTejPgrdlNsKNucZfJCxJ95lMTLA0ShHLLE3n5wpT9Q,12170 -charset_normalizer/version.py,sha256=nKE4qBNk5WA4LIJ_yIH_aSDfvtsyizkWMg-PUG-UZVk,115 diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL deleted file mode 100644 index e752d95..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_10_9_universal2 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt deleted file mode 100644 index 65619e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -normalizer = charset_normalizer.cli:cli_detect diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE deleted file mode 100644 index 9725772..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 TAHRI Ahmed R. - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt deleted file mode 100644 index 66958f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -charset_normalizer diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__init__.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__init__.py deleted file mode 100644 index 0d3a379..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Charset-Normalizer -~~~~~~~~~~~~~~ -The Real First Universal Charset Detector. -A library that helps you read text from an unknown charset encoding. -Motivated by chardet, This package is trying to resolve the issue by taking a new approach. -All IANA character set names for which the Python core library provides codecs are supported. - -Basic usage: - >>> from charset_normalizer import from_bytes - >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) - >>> best_guess = results.best() - >>> str(best_guess) - 'Bсеки човек има право на образование. Oбразованието!' - -Others methods and usages are available - see the full documentation -at . -:copyright: (c) 2021 by Ahmed TAHRI -:license: MIT, see LICENSE for more details. -""" - -from __future__ import annotations - -import logging - -from .api import from_bytes, from_fp, from_path, is_binary -from .legacy import detect -from .models import CharsetMatch, CharsetMatches -from .utils import set_logging_handler -from .version import VERSION, __version__ - -__all__ = ( - "from_fp", - "from_path", - "from_bytes", - "is_binary", - "detect", - "CharsetMatch", - "CharsetMatches", - "__version__", - "VERSION", - "set_logging_handler", -) - -# Attach a NullHandler to the top level logger by default -# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library - -logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__main__.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__main__.py deleted file mode 100644 index e0e76f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import annotations - -from .cli import cli_detect - -if __name__ == "__main__": - cli_detect() diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/api.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/api.py deleted file mode 100644 index ebd9639..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/api.py +++ /dev/null @@ -1,669 +0,0 @@ -from __future__ import annotations - -import logging -from os import PathLike -from typing import BinaryIO - -from .cd import ( - coherence_ratio, - encoding_languages, - mb_encoding_languages, - merge_coherence_ratios, -) -from .constant import IANA_SUPPORTED, TOO_BIG_SEQUENCE, TOO_SMALL_SEQUENCE, TRACE -from .md import mess_ratio -from .models import CharsetMatch, CharsetMatches -from .utils import ( - any_specified_encoding, - cut_sequence_chunks, - iana_name, - identify_sig_or_bom, - is_cp_similar, - is_multi_byte_encoding, - should_strip_sig_or_bom, -) - -logger = logging.getLogger("charset_normalizer") -explain_handler = logging.StreamHandler() -explain_handler.setFormatter( - logging.Formatter("%(asctime)s | %(levelname)s | %(message)s") -) - - -def from_bytes( - sequences: bytes | bytearray, - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.2, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Given a raw bytes sequence, return the best possibles charset usable to render str objects. - If there is no results, it is a strong indicator that the source is binary/not text. - By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. - And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. - - The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page - but never take it for granted. Can improve the performance. - - You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that - purpose. - - This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. - By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' - toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. - Custom logging format and handler can be set manually. - """ - - if not isinstance(sequences, (bytearray, bytes)): - raise TypeError( - "Expected object of type bytes or bytearray, got: {}".format( - type(sequences) - ) - ) - - if explain: - previous_logger_level: int = logger.level - logger.addHandler(explain_handler) - logger.setLevel(TRACE) - - length: int = len(sequences) - - if length == 0: - logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level or logging.WARNING) - return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) - - if cp_isolation is not None: - logger.log( - TRACE, - "cp_isolation is set. use this flag for debugging purpose. " - "limited list of encoding allowed : %s.", - ", ".join(cp_isolation), - ) - cp_isolation = [iana_name(cp, False) for cp in cp_isolation] - else: - cp_isolation = [] - - if cp_exclusion is not None: - logger.log( - TRACE, - "cp_exclusion is set. use this flag for debugging purpose. " - "limited list of encoding excluded : %s.", - ", ".join(cp_exclusion), - ) - cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] - else: - cp_exclusion = [] - - if length <= (chunk_size * steps): - logger.log( - TRACE, - "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", - steps, - chunk_size, - length, - ) - steps = 1 - chunk_size = length - - if steps > 1 and length / steps < chunk_size: - chunk_size = int(length / steps) - - is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE - is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE - - if is_too_small_sequence: - logger.log( - TRACE, - "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( - length - ), - ) - elif is_too_large_sequence: - logger.log( - TRACE, - "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( - length - ), - ) - - prioritized_encodings: list[str] = [] - - specified_encoding: str | None = ( - any_specified_encoding(sequences) if preemptive_behaviour else None - ) - - if specified_encoding is not None: - prioritized_encodings.append(specified_encoding) - logger.log( - TRACE, - "Detected declarative mark in sequence. Priority +1 given for %s.", - specified_encoding, - ) - - tested: set[str] = set() - tested_but_hard_failure: list[str] = [] - tested_but_soft_failure: list[str] = [] - - fallback_ascii: CharsetMatch | None = None - fallback_u8: CharsetMatch | None = None - fallback_specified: CharsetMatch | None = None - - results: CharsetMatches = CharsetMatches() - - early_stop_results: CharsetMatches = CharsetMatches() - - sig_encoding, sig_payload = identify_sig_or_bom(sequences) - - if sig_encoding is not None: - prioritized_encodings.append(sig_encoding) - logger.log( - TRACE, - "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", - len(sig_payload), - sig_encoding, - ) - - prioritized_encodings.append("ascii") - - if "utf_8" not in prioritized_encodings: - prioritized_encodings.append("utf_8") - - for encoding_iana in prioritized_encodings + IANA_SUPPORTED: - if cp_isolation and encoding_iana not in cp_isolation: - continue - - if cp_exclusion and encoding_iana in cp_exclusion: - continue - - if encoding_iana in tested: - continue - - tested.add(encoding_iana) - - decoded_payload: str | None = None - bom_or_sig_available: bool = sig_encoding == encoding_iana - strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( - encoding_iana - ) - - if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: - logger.log( - TRACE, - "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", - encoding_iana, - ) - continue - if encoding_iana in {"utf_7"} and not bom_or_sig_available: - logger.log( - TRACE, - "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", - encoding_iana, - ) - continue - - try: - is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) - except (ModuleNotFoundError, ImportError): - logger.log( - TRACE, - "Encoding %s does not provide an IncrementalDecoder", - encoding_iana, - ) - continue - - try: - if is_too_large_sequence and is_multi_byte_decoder is False: - str( - ( - sequences[: int(50e4)] - if strip_sig_or_bom is False - else sequences[len(sig_payload) : int(50e4)] - ), - encoding=encoding_iana, - ) - else: - decoded_payload = str( - ( - sequences - if strip_sig_or_bom is False - else sequences[len(sig_payload) :] - ), - encoding=encoding_iana, - ) - except (UnicodeDecodeError, LookupError) as e: - if not isinstance(e, LookupError): - logger.log( - TRACE, - "Code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - tested_but_hard_failure.append(encoding_iana) - continue - - similar_soft_failure_test: bool = False - - for encoding_soft_failed in tested_but_soft_failure: - if is_cp_similar(encoding_iana, encoding_soft_failed): - similar_soft_failure_test = True - break - - if similar_soft_failure_test: - logger.log( - TRACE, - "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", - encoding_iana, - encoding_soft_failed, - ) - continue - - r_ = range( - 0 if not bom_or_sig_available else len(sig_payload), - length, - int(length / steps), - ) - - multi_byte_bonus: bool = ( - is_multi_byte_decoder - and decoded_payload is not None - and len(decoded_payload) < length - ) - - if multi_byte_bonus: - logger.log( - TRACE, - "Code page %s is a multi byte encoding table and it appear that at least one character " - "was encoded using n-bytes.", - encoding_iana, - ) - - max_chunk_gave_up: int = int(len(r_) / 4) - - max_chunk_gave_up = max(max_chunk_gave_up, 2) - early_stop_count: int = 0 - lazy_str_hard_failure = False - - md_chunks: list[str] = [] - md_ratios = [] - - try: - for chunk in cut_sequence_chunks( - sequences, - encoding_iana, - r_, - chunk_size, - bom_or_sig_available, - strip_sig_or_bom, - sig_payload, - is_multi_byte_decoder, - decoded_payload, - ): - md_chunks.append(chunk) - - md_ratios.append( - mess_ratio( - chunk, - threshold, - explain is True and 1 <= len(cp_isolation) <= 2, - ) - ) - - if md_ratios[-1] >= threshold: - early_stop_count += 1 - - if (early_stop_count >= max_chunk_gave_up) or ( - bom_or_sig_available and strip_sig_or_bom is False - ): - break - except ( - UnicodeDecodeError - ) as e: # Lazy str loading may have missed something there - logger.log( - TRACE, - "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - early_stop_count = max_chunk_gave_up - lazy_str_hard_failure = True - - # We might want to check the sequence again with the whole content - # Only if initial MD tests passes - if ( - not lazy_str_hard_failure - and is_too_large_sequence - and not is_multi_byte_decoder - ): - try: - sequences[int(50e3) :].decode(encoding_iana, errors="strict") - except UnicodeDecodeError as e: - logger.log( - TRACE, - "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", - encoding_iana, - str(e), - ) - tested_but_hard_failure.append(encoding_iana) - continue - - mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 - if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: - tested_but_soft_failure.append(encoding_iana) - logger.log( - TRACE, - "%s was excluded because of initial chaos probing. Gave up %i time(s). " - "Computed mean chaos is %f %%.", - encoding_iana, - early_stop_count, - round(mean_mess_ratio * 100, ndigits=3), - ) - # Preparing those fallbacks in case we got nothing. - if ( - enable_fallback - and encoding_iana - in ["ascii", "utf_8", specified_encoding, "utf_16", "utf_32"] - and not lazy_str_hard_failure - ): - fallback_entry = CharsetMatch( - sequences, - encoding_iana, - threshold, - bom_or_sig_available, - [], - decoded_payload, - preemptive_declaration=specified_encoding, - ) - if encoding_iana == specified_encoding: - fallback_specified = fallback_entry - elif encoding_iana == "ascii": - fallback_ascii = fallback_entry - else: - fallback_u8 = fallback_entry - continue - - logger.log( - TRACE, - "%s passed initial chaos probing. Mean measured chaos is %f %%", - encoding_iana, - round(mean_mess_ratio * 100, ndigits=3), - ) - - if not is_multi_byte_decoder: - target_languages: list[str] = encoding_languages(encoding_iana) - else: - target_languages = mb_encoding_languages(encoding_iana) - - if target_languages: - logger.log( - TRACE, - "{} should target any language(s) of {}".format( - encoding_iana, str(target_languages) - ), - ) - - cd_ratios = [] - - # We shall skip the CD when its about ASCII - # Most of the time its not relevant to run "language-detection" on it. - if encoding_iana != "ascii": - for chunk in md_chunks: - chunk_languages = coherence_ratio( - chunk, - language_threshold, - ",".join(target_languages) if target_languages else None, - ) - - cd_ratios.append(chunk_languages) - - cd_ratios_merged = merge_coherence_ratios(cd_ratios) - - if cd_ratios_merged: - logger.log( - TRACE, - "We detected language {} using {}".format( - cd_ratios_merged, encoding_iana - ), - ) - - current_match = CharsetMatch( - sequences, - encoding_iana, - mean_mess_ratio, - bom_or_sig_available, - cd_ratios_merged, - ( - decoded_payload - if ( - is_too_large_sequence is False - or encoding_iana in [specified_encoding, "ascii", "utf_8"] - ) - else None - ), - preemptive_declaration=specified_encoding, - ) - - results.append(current_match) - - if ( - encoding_iana in [specified_encoding, "ascii", "utf_8"] - and mean_mess_ratio < 0.1 - ): - # If md says nothing to worry about, then... stop immediately! - if mean_mess_ratio == 0.0: - logger.debug( - "Encoding detection: %s is most likely the one.", - current_match.encoding, - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([current_match]) - - early_stop_results.append(current_match) - - if ( - len(early_stop_results) - and (specified_encoding is None or specified_encoding in tested) - and "ascii" in tested - and "utf_8" in tested - ): - probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment] - logger.debug( - "Encoding detection: %s is most likely the one.", - probable_result.encoding, - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - - return CharsetMatches([probable_result]) - - if encoding_iana == sig_encoding: - logger.debug( - "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " - "the beginning of the sequence.", - encoding_iana, - ) - if explain: # Defensive: ensure exit path clean handler - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - return CharsetMatches([results[encoding_iana]]) - - if len(results) == 0: - if fallback_u8 or fallback_ascii or fallback_specified: - logger.log( - TRACE, - "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", - ) - - if fallback_specified: - logger.debug( - "Encoding detection: %s will be used as a fallback match", - fallback_specified.encoding, - ) - results.append(fallback_specified) - elif ( - (fallback_u8 and fallback_ascii is None) - or ( - fallback_u8 - and fallback_ascii - and fallback_u8.fingerprint != fallback_ascii.fingerprint - ) - or (fallback_u8 is not None) - ): - logger.debug("Encoding detection: utf_8 will be used as a fallback match") - results.append(fallback_u8) - elif fallback_ascii: - logger.debug("Encoding detection: ascii will be used as a fallback match") - results.append(fallback_ascii) - - if results: - logger.debug( - "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", - results.best().encoding, # type: ignore - len(results) - 1, - ) - else: - logger.debug("Encoding detection: Unable to determine any suitable charset.") - - if explain: - logger.removeHandler(explain_handler) - logger.setLevel(previous_logger_level) - - return results - - -def from_fp( - fp: BinaryIO, - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Same thing than the function from_bytes but using a file pointer that is already ready. - Will not close the file pointer. - """ - return from_bytes( - fp.read(), - steps, - chunk_size, - threshold, - cp_isolation, - cp_exclusion, - preemptive_behaviour, - explain, - language_threshold, - enable_fallback, - ) - - -def from_path( - path: str | bytes | PathLike, # type: ignore[type-arg] - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = True, -) -> CharsetMatches: - """ - Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. - Can raise IOError. - """ - with open(path, "rb") as fp: - return from_fp( - fp, - steps, - chunk_size, - threshold, - cp_isolation, - cp_exclusion, - preemptive_behaviour, - explain, - language_threshold, - enable_fallback, - ) - - -def is_binary( - fp_or_path_or_payload: PathLike | str | BinaryIO | bytes, # type: ignore[type-arg] - steps: int = 5, - chunk_size: int = 512, - threshold: float = 0.20, - cp_isolation: list[str] | None = None, - cp_exclusion: list[str] | None = None, - preemptive_behaviour: bool = True, - explain: bool = False, - language_threshold: float = 0.1, - enable_fallback: bool = False, -) -> bool: - """ - Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. - Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match - are disabled to be stricter around ASCII-compatible but unlikely to be a string. - """ - if isinstance(fp_or_path_or_payload, (str, PathLike)): - guesses = from_path( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - elif isinstance( - fp_or_path_or_payload, - ( - bytes, - bytearray, - ), - ): - guesses = from_bytes( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - else: - guesses = from_fp( - fp_or_path_or_payload, - steps=steps, - chunk_size=chunk_size, - threshold=threshold, - cp_isolation=cp_isolation, - cp_exclusion=cp_exclusion, - preemptive_behaviour=preemptive_behaviour, - explain=explain, - language_threshold=language_threshold, - enable_fallback=enable_fallback, - ) - - return not guesses diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cd.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cd.py deleted file mode 100644 index 71a3ed5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cd.py +++ /dev/null @@ -1,395 +0,0 @@ -from __future__ import annotations - -import importlib -from codecs import IncrementalDecoder -from collections import Counter -from functools import lru_cache -from typing import Counter as TypeCounter - -from .constant import ( - FREQUENCIES, - KO_NAMES, - LANGUAGE_SUPPORTED_COUNT, - TOO_SMALL_SEQUENCE, - ZH_NAMES, -) -from .md import is_suspiciously_successive_range -from .models import CoherenceMatches -from .utils import ( - is_accentuated, - is_latin, - is_multi_byte_encoding, - is_unicode_range_secondary, - unicode_range, -) - - -def encoding_unicode_range(iana_name: str) -> list[str]: - """ - Return associated unicode ranges in a single byte code page. - """ - if is_multi_byte_encoding(iana_name): - raise OSError("Function not supported on multi-byte code page") - - decoder = importlib.import_module(f"encodings.{iana_name}").IncrementalDecoder - - p: IncrementalDecoder = decoder(errors="ignore") - seen_ranges: dict[str, int] = {} - character_count: int = 0 - - for i in range(0x40, 0xFF): - chunk: str = p.decode(bytes([i])) - - if chunk: - character_range: str | None = unicode_range(chunk) - - if character_range is None: - continue - - if is_unicode_range_secondary(character_range) is False: - if character_range not in seen_ranges: - seen_ranges[character_range] = 0 - seen_ranges[character_range] += 1 - character_count += 1 - - return sorted( - [ - character_range - for character_range in seen_ranges - if seen_ranges[character_range] / character_count >= 0.15 - ] - ) - - -def unicode_range_languages(primary_range: str) -> list[str]: - """ - Return inferred languages used with a unicode range. - """ - languages: list[str] = [] - - for language, characters in FREQUENCIES.items(): - for character in characters: - if unicode_range(character) == primary_range: - languages.append(language) - break - - return languages - - -@lru_cache() -def encoding_languages(iana_name: str) -> list[str]: - """ - Single-byte encoding language association. Some code page are heavily linked to particular language(s). - This function does the correspondence. - """ - unicode_ranges: list[str] = encoding_unicode_range(iana_name) - primary_range: str | None = None - - for specified_range in unicode_ranges: - if "Latin" not in specified_range: - primary_range = specified_range - break - - if primary_range is None: - return ["Latin Based"] - - return unicode_range_languages(primary_range) - - -@lru_cache() -def mb_encoding_languages(iana_name: str) -> list[str]: - """ - Multi-byte encoding language association. Some code page are heavily linked to particular language(s). - This function does the correspondence. - """ - if ( - iana_name.startswith("shift_") - or iana_name.startswith("iso2022_jp") - or iana_name.startswith("euc_j") - or iana_name == "cp932" - ): - return ["Japanese"] - if iana_name.startswith("gb") or iana_name in ZH_NAMES: - return ["Chinese"] - if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: - return ["Korean"] - - return [] - - -@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) -def get_target_features(language: str) -> tuple[bool, bool]: - """ - Determine main aspects from a supported language if it contains accents and if is pure Latin. - """ - target_have_accents: bool = False - target_pure_latin: bool = True - - for character in FREQUENCIES[language]: - if not target_have_accents and is_accentuated(character): - target_have_accents = True - if target_pure_latin and is_latin(character) is False: - target_pure_latin = False - - return target_have_accents, target_pure_latin - - -def alphabet_languages( - characters: list[str], ignore_non_latin: bool = False -) -> list[str]: - """ - Return associated languages associated to given characters. - """ - languages: list[tuple[str, float]] = [] - - source_have_accents = any(is_accentuated(character) for character in characters) - - for language, language_characters in FREQUENCIES.items(): - target_have_accents, target_pure_latin = get_target_features(language) - - if ignore_non_latin and target_pure_latin is False: - continue - - if target_have_accents is False and source_have_accents: - continue - - character_count: int = len(language_characters) - - character_match_count: int = len( - [c for c in language_characters if c in characters] - ) - - ratio: float = character_match_count / character_count - - if ratio >= 0.2: - languages.append((language, ratio)) - - languages = sorted(languages, key=lambda x: x[1], reverse=True) - - return [compatible_language[0] for compatible_language in languages] - - -def characters_popularity_compare( - language: str, ordered_characters: list[str] -) -> float: - """ - Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. - The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). - Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) - """ - if language not in FREQUENCIES: - raise ValueError(f"{language} not available") - - character_approved_count: int = 0 - FREQUENCIES_language_set = set(FREQUENCIES[language]) - - ordered_characters_count: int = len(ordered_characters) - target_language_characters_count: int = len(FREQUENCIES[language]) - - large_alphabet: bool = target_language_characters_count > 26 - - for character, character_rank in zip( - ordered_characters, range(0, ordered_characters_count) - ): - if character not in FREQUENCIES_language_set: - continue - - character_rank_in_language: int = FREQUENCIES[language].index(character) - expected_projection_ratio: float = ( - target_language_characters_count / ordered_characters_count - ) - character_rank_projection: int = int(character_rank * expected_projection_ratio) - - if ( - large_alphabet is False - and abs(character_rank_projection - character_rank_in_language) > 4 - ): - continue - - if ( - large_alphabet is True - and abs(character_rank_projection - character_rank_in_language) - < target_language_characters_count / 3 - ): - character_approved_count += 1 - continue - - characters_before_source: list[str] = FREQUENCIES[language][ - 0:character_rank_in_language - ] - characters_after_source: list[str] = FREQUENCIES[language][ - character_rank_in_language: - ] - characters_before: list[str] = ordered_characters[0:character_rank] - characters_after: list[str] = ordered_characters[character_rank:] - - before_match_count: int = len( - set(characters_before) & set(characters_before_source) - ) - - after_match_count: int = len( - set(characters_after) & set(characters_after_source) - ) - - if len(characters_before_source) == 0 and before_match_count <= 4: - character_approved_count += 1 - continue - - if len(characters_after_source) == 0 and after_match_count <= 4: - character_approved_count += 1 - continue - - if ( - before_match_count / len(characters_before_source) >= 0.4 - or after_match_count / len(characters_after_source) >= 0.4 - ): - character_approved_count += 1 - continue - - return character_approved_count / len(ordered_characters) - - -def alpha_unicode_split(decoded_sequence: str) -> list[str]: - """ - Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. - Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; - One containing the latin letters and the other hebrew. - """ - layers: dict[str, str] = {} - - for character in decoded_sequence: - if character.isalpha() is False: - continue - - character_range: str | None = unicode_range(character) - - if character_range is None: - continue - - layer_target_range: str | None = None - - for discovered_range in layers: - if ( - is_suspiciously_successive_range(discovered_range, character_range) - is False - ): - layer_target_range = discovered_range - break - - if layer_target_range is None: - layer_target_range = character_range - - if layer_target_range not in layers: - layers[layer_target_range] = character.lower() - continue - - layers[layer_target_range] += character.lower() - - return list(layers.values()) - - -def merge_coherence_ratios(results: list[CoherenceMatches]) -> CoherenceMatches: - """ - This function merge results previously given by the function coherence_ratio. - The return type is the same as coherence_ratio. - """ - per_language_ratios: dict[str, list[float]] = {} - for result in results: - for sub_result in result: - language, ratio = sub_result - if language not in per_language_ratios: - per_language_ratios[language] = [ratio] - continue - per_language_ratios[language].append(ratio) - - merge = [ - ( - language, - round( - sum(per_language_ratios[language]) / len(per_language_ratios[language]), - 4, - ), - ) - for language in per_language_ratios - ] - - return sorted(merge, key=lambda x: x[1], reverse=True) - - -def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: - """ - We shall NOT return "English—" in CoherenceMatches because it is an alternative - of "English". This function only keeps the best match and remove the em-dash in it. - """ - index_results: dict[str, list[float]] = dict() - - for result in results: - language, ratio = result - no_em_name: str = language.replace("—", "") - - if no_em_name not in index_results: - index_results[no_em_name] = [] - - index_results[no_em_name].append(ratio) - - if any(len(index_results[e]) > 1 for e in index_results): - filtered_results: CoherenceMatches = [] - - for language in index_results: - filtered_results.append((language, max(index_results[language]))) - - return filtered_results - - return results - - -@lru_cache(maxsize=2048) -def coherence_ratio( - decoded_sequence: str, threshold: float = 0.1, lg_inclusion: str | None = None -) -> CoherenceMatches: - """ - Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. - A layer = Character extraction by alphabets/ranges. - """ - - results: list[tuple[str, float]] = [] - ignore_non_latin: bool = False - - sufficient_match_count: int = 0 - - lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] - if "Latin Based" in lg_inclusion_list: - ignore_non_latin = True - lg_inclusion_list.remove("Latin Based") - - for layer in alpha_unicode_split(decoded_sequence): - sequence_frequencies: TypeCounter[str] = Counter(layer) - most_common = sequence_frequencies.most_common() - - character_count: int = sum(o for c, o in most_common) - - if character_count <= TOO_SMALL_SEQUENCE: - continue - - popular_character_ordered: list[str] = [c for c, o in most_common] - - for language in lg_inclusion_list or alphabet_languages( - popular_character_ordered, ignore_non_latin - ): - ratio: float = characters_popularity_compare( - language, popular_character_ordered - ) - - if ratio < threshold: - continue - elif ratio >= 0.8: - sufficient_match_count += 1 - - results.append((language, round(ratio, 4))) - - if sufficient_match_count >= 3: - break - - return sorted( - filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True - ) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py deleted file mode 100644 index 543a5a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import annotations - -from .__main__ import cli_detect, query_yes_no - -__all__ = ( - "cli_detect", - "query_yes_no", -) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py deleted file mode 100644 index cb64156..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/cli/__main__.py +++ /dev/null @@ -1,381 +0,0 @@ -from __future__ import annotations - -import argparse -import sys -import typing -from json import dumps -from os.path import abspath, basename, dirname, join, realpath -from platform import python_version -from unicodedata import unidata_version - -import charset_normalizer.md as md_module -from charset_normalizer import from_fp -from charset_normalizer.models import CliDetectionResult -from charset_normalizer.version import __version__ - - -def query_yes_no(question: str, default: str = "yes") -> bool: - """Ask a yes/no question via input() and return their answer. - - "question" is a string that is presented to the user. - "default" is the presumed answer if the user just hits . - It must be "yes" (the default), "no" or None (meaning - an answer is required of the user). - - The "answer" return value is True for "yes" or False for "no". - - Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input - """ - valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} - if default is None: - prompt = " [y/n] " - elif default == "yes": - prompt = " [Y/n] " - elif default == "no": - prompt = " [y/N] " - else: - raise ValueError("invalid default answer: '%s'" % default) - - while True: - sys.stdout.write(question + prompt) - choice = input().lower() - if default is not None and choice == "": - return valid[default] - elif choice in valid: - return valid[choice] - else: - sys.stdout.write("Please respond with 'yes' or 'no' (or 'y' or 'n').\n") - - -class FileType: - """Factory for creating file object types - - Instances of FileType are typically passed as type= arguments to the - ArgumentParser add_argument() method. - - Keyword Arguments: - - mode -- A string indicating how the file is to be opened. Accepts the - same values as the builtin open() function. - - bufsize -- The file's desired buffer size. Accepts the same values as - the builtin open() function. - - encoding -- The file's encoding. Accepts the same values as the - builtin open() function. - - errors -- A string indicating how encoding and decoding errors are to - be handled. Accepts the same value as the builtin open() function. - - Backported from CPython 3.12 - """ - - def __init__( - self, - mode: str = "r", - bufsize: int = -1, - encoding: str | None = None, - errors: str | None = None, - ): - self._mode = mode - self._bufsize = bufsize - self._encoding = encoding - self._errors = errors - - def __call__(self, string: str) -> typing.IO: # type: ignore[type-arg] - # the special argument "-" means sys.std{in,out} - if string == "-": - if "r" in self._mode: - return sys.stdin.buffer if "b" in self._mode else sys.stdin - elif any(c in self._mode for c in "wax"): - return sys.stdout.buffer if "b" in self._mode else sys.stdout - else: - msg = f'argument "-" with mode {self._mode}' - raise ValueError(msg) - - # all other arguments are used as file names - try: - return open(string, self._mode, self._bufsize, self._encoding, self._errors) - except OSError as e: - message = f"can't open '{string}': {e}" - raise argparse.ArgumentTypeError(message) - - def __repr__(self) -> str: - args = self._mode, self._bufsize - kwargs = [("encoding", self._encoding), ("errors", self._errors)] - args_str = ", ".join( - [repr(arg) for arg in args if arg != -1] - + [f"{kw}={arg!r}" for kw, arg in kwargs if arg is not None] - ) - return f"{type(self).__name__}({args_str})" - - -def cli_detect(argv: list[str] | None = None) -> int: - """ - CLI assistant using ARGV and ArgumentParser - :param argv: - :return: 0 if everything is fine, anything else equal trouble - """ - parser = argparse.ArgumentParser( - description="The Real First Universal Charset Detector. " - "Discover originating encoding used on text file. " - "Normalize text to unicode." - ) - - parser.add_argument( - "files", type=FileType("rb"), nargs="+", help="File(s) to be analysed" - ) - parser.add_argument( - "-v", - "--verbose", - action="store_true", - default=False, - dest="verbose", - help="Display complementary information about file if any. " - "Stdout will contain logs about the detection process.", - ) - parser.add_argument( - "-a", - "--with-alternative", - action="store_true", - default=False, - dest="alternatives", - help="Output complementary possibilities if any. Top-level JSON WILL be a list.", - ) - parser.add_argument( - "-n", - "--normalize", - action="store_true", - default=False, - dest="normalize", - help="Permit to normalize input file. If not set, program does not write anything.", - ) - parser.add_argument( - "-m", - "--minimal", - action="store_true", - default=False, - dest="minimal", - help="Only output the charset detected to STDOUT. Disabling JSON output.", - ) - parser.add_argument( - "-r", - "--replace", - action="store_true", - default=False, - dest="replace", - help="Replace file when trying to normalize it instead of creating a new one.", - ) - parser.add_argument( - "-f", - "--force", - action="store_true", - default=False, - dest="force", - help="Replace file without asking if you are sure, use this flag with caution.", - ) - parser.add_argument( - "-i", - "--no-preemptive", - action="store_true", - default=False, - dest="no_preemptive", - help="Disable looking at a charset declaration to hint the detector.", - ) - parser.add_argument( - "-t", - "--threshold", - action="store", - default=0.2, - type=float, - dest="threshold", - help="Define a custom maximum amount of noise allowed in decoded content. 0. <= noise <= 1.", - ) - parser.add_argument( - "--version", - action="version", - version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( - __version__, - python_version(), - unidata_version, - "OFF" if md_module.__file__.lower().endswith(".py") else "ON", - ), - help="Show version information and exit.", - ) - - args = parser.parse_args(argv) - - if args.replace is True and args.normalize is False: - if args.files: - for my_file in args.files: - my_file.close() - print("Use --replace in addition of --normalize only.", file=sys.stderr) - return 1 - - if args.force is True and args.replace is False: - if args.files: - for my_file in args.files: - my_file.close() - print("Use --force in addition of --replace only.", file=sys.stderr) - return 1 - - if args.threshold < 0.0 or args.threshold > 1.0: - if args.files: - for my_file in args.files: - my_file.close() - print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) - return 1 - - x_ = [] - - for my_file in args.files: - matches = from_fp( - my_file, - threshold=args.threshold, - explain=args.verbose, - preemptive_behaviour=args.no_preemptive is False, - ) - - best_guess = matches.best() - - if best_guess is None: - print( - 'Unable to identify originating encoding for "{}". {}'.format( - my_file.name, - ( - "Maybe try increasing maximum amount of chaos." - if args.threshold < 1.0 - else "" - ), - ), - file=sys.stderr, - ) - x_.append( - CliDetectionResult( - abspath(my_file.name), - None, - [], - [], - "Unknown", - [], - False, - 1.0, - 0.0, - None, - True, - ) - ) - else: - x_.append( - CliDetectionResult( - abspath(my_file.name), - best_guess.encoding, - best_guess.encoding_aliases, - [ - cp - for cp in best_guess.could_be_from_charset - if cp != best_guess.encoding - ], - best_guess.language, - best_guess.alphabets, - best_guess.bom, - best_guess.percent_chaos, - best_guess.percent_coherence, - None, - True, - ) - ) - - if len(matches) > 1 and args.alternatives: - for el in matches: - if el != best_guess: - x_.append( - CliDetectionResult( - abspath(my_file.name), - el.encoding, - el.encoding_aliases, - [ - cp - for cp in el.could_be_from_charset - if cp != el.encoding - ], - el.language, - el.alphabets, - el.bom, - el.percent_chaos, - el.percent_coherence, - None, - False, - ) - ) - - if args.normalize is True: - if best_guess.encoding.startswith("utf") is True: - print( - '"{}" file does not need to be normalized, as it already came from unicode.'.format( - my_file.name - ), - file=sys.stderr, - ) - if my_file.closed is False: - my_file.close() - continue - - dir_path = dirname(realpath(my_file.name)) - file_name = basename(realpath(my_file.name)) - - o_: list[str] = file_name.split(".") - - if args.replace is False: - o_.insert(-1, best_guess.encoding) - if my_file.closed is False: - my_file.close() - elif ( - args.force is False - and query_yes_no( - 'Are you sure to normalize "{}" by replacing it ?'.format( - my_file.name - ), - "no", - ) - is False - ): - if my_file.closed is False: - my_file.close() - continue - - try: - x_[0].unicode_path = join(dir_path, ".".join(o_)) - - with open(x_[0].unicode_path, "wb") as fp: - fp.write(best_guess.output()) - except OSError as e: - print(str(e), file=sys.stderr) - if my_file.closed is False: - my_file.close() - return 2 - - if my_file.closed is False: - my_file.close() - - if args.minimal is False: - print( - dumps( - [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, - ensure_ascii=True, - indent=4, - ) - ) - else: - for my_file in args.files: - print( - ", ".join( - [ - el.encoding or "undefined" - for el in x_ - if el.path == abspath(my_file.name) - ] - ) - ) - - return 0 - - -if __name__ == "__main__": - cli_detect() diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/constant.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/constant.py deleted file mode 100644 index cc71a01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/constant.py +++ /dev/null @@ -1,2015 +0,0 @@ -from __future__ import annotations - -from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE -from encodings.aliases import aliases -from re import IGNORECASE -from re import compile as re_compile - -# Contain for each eligible encoding a list of/item bytes SIG/BOM -ENCODING_MARKS: dict[str, bytes | list[bytes]] = { - "utf_8": BOM_UTF8, - "utf_7": [ - b"\x2b\x2f\x76\x38", - b"\x2b\x2f\x76\x39", - b"\x2b\x2f\x76\x2b", - b"\x2b\x2f\x76\x2f", - b"\x2b\x2f\x76\x38\x2d", - ], - "gb18030": b"\x84\x31\x95\x33", - "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE], - "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE], -} - -TOO_SMALL_SEQUENCE: int = 32 -TOO_BIG_SEQUENCE: int = int(10e6) - -UTF8_MAXIMAL_ALLOCATION: int = 1_112_064 - -# Up-to-date Unicode ucd/15.0.0 -UNICODE_RANGES_COMBINED: dict[str, range] = { - "Control character": range(32), - "Basic Latin": range(32, 128), - "Latin-1 Supplement": range(128, 256), - "Latin Extended-A": range(256, 384), - "Latin Extended-B": range(384, 592), - "IPA Extensions": range(592, 688), - "Spacing Modifier Letters": range(688, 768), - "Combining Diacritical Marks": range(768, 880), - "Greek and Coptic": range(880, 1024), - "Cyrillic": range(1024, 1280), - "Cyrillic Supplement": range(1280, 1328), - "Armenian": range(1328, 1424), - "Hebrew": range(1424, 1536), - "Arabic": range(1536, 1792), - "Syriac": range(1792, 1872), - "Arabic Supplement": range(1872, 1920), - "Thaana": range(1920, 1984), - "NKo": range(1984, 2048), - "Samaritan": range(2048, 2112), - "Mandaic": range(2112, 2144), - "Syriac Supplement": range(2144, 2160), - "Arabic Extended-B": range(2160, 2208), - "Arabic Extended-A": range(2208, 2304), - "Devanagari": range(2304, 2432), - "Bengali": range(2432, 2560), - "Gurmukhi": range(2560, 2688), - "Gujarati": range(2688, 2816), - "Oriya": range(2816, 2944), - "Tamil": range(2944, 3072), - "Telugu": range(3072, 3200), - "Kannada": range(3200, 3328), - "Malayalam": range(3328, 3456), - "Sinhala": range(3456, 3584), - "Thai": range(3584, 3712), - "Lao": range(3712, 3840), - "Tibetan": range(3840, 4096), - "Myanmar": range(4096, 4256), - "Georgian": range(4256, 4352), - "Hangul Jamo": range(4352, 4608), - "Ethiopic": range(4608, 4992), - "Ethiopic Supplement": range(4992, 5024), - "Cherokee": range(5024, 5120), - "Unified Canadian Aboriginal Syllabics": range(5120, 5760), - "Ogham": range(5760, 5792), - "Runic": range(5792, 5888), - "Tagalog": range(5888, 5920), - "Hanunoo": range(5920, 5952), - "Buhid": range(5952, 5984), - "Tagbanwa": range(5984, 6016), - "Khmer": range(6016, 6144), - "Mongolian": range(6144, 6320), - "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400), - "Limbu": range(6400, 6480), - "Tai Le": range(6480, 6528), - "New Tai Lue": range(6528, 6624), - "Khmer Symbols": range(6624, 6656), - "Buginese": range(6656, 6688), - "Tai Tham": range(6688, 6832), - "Combining Diacritical Marks Extended": range(6832, 6912), - "Balinese": range(6912, 7040), - "Sundanese": range(7040, 7104), - "Batak": range(7104, 7168), - "Lepcha": range(7168, 7248), - "Ol Chiki": range(7248, 7296), - "Cyrillic Extended-C": range(7296, 7312), - "Georgian Extended": range(7312, 7360), - "Sundanese Supplement": range(7360, 7376), - "Vedic Extensions": range(7376, 7424), - "Phonetic Extensions": range(7424, 7552), - "Phonetic Extensions Supplement": range(7552, 7616), - "Combining Diacritical Marks Supplement": range(7616, 7680), - "Latin Extended Additional": range(7680, 7936), - "Greek Extended": range(7936, 8192), - "General Punctuation": range(8192, 8304), - "Superscripts and Subscripts": range(8304, 8352), - "Currency Symbols": range(8352, 8400), - "Combining Diacritical Marks for Symbols": range(8400, 8448), - "Letterlike Symbols": range(8448, 8528), - "Number Forms": range(8528, 8592), - "Arrows": range(8592, 8704), - "Mathematical Operators": range(8704, 8960), - "Miscellaneous Technical": range(8960, 9216), - "Control Pictures": range(9216, 9280), - "Optical Character Recognition": range(9280, 9312), - "Enclosed Alphanumerics": range(9312, 9472), - "Box Drawing": range(9472, 9600), - "Block Elements": range(9600, 9632), - "Geometric Shapes": range(9632, 9728), - "Miscellaneous Symbols": range(9728, 9984), - "Dingbats": range(9984, 10176), - "Miscellaneous Mathematical Symbols-A": range(10176, 10224), - "Supplemental Arrows-A": range(10224, 10240), - "Braille Patterns": range(10240, 10496), - "Supplemental Arrows-B": range(10496, 10624), - "Miscellaneous Mathematical Symbols-B": range(10624, 10752), - "Supplemental Mathematical Operators": range(10752, 11008), - "Miscellaneous Symbols and Arrows": range(11008, 11264), - "Glagolitic": range(11264, 11360), - "Latin Extended-C": range(11360, 11392), - "Coptic": range(11392, 11520), - "Georgian Supplement": range(11520, 11568), - "Tifinagh": range(11568, 11648), - "Ethiopic Extended": range(11648, 11744), - "Cyrillic Extended-A": range(11744, 11776), - "Supplemental Punctuation": range(11776, 11904), - "CJK Radicals Supplement": range(11904, 12032), - "Kangxi Radicals": range(12032, 12256), - "Ideographic Description Characters": range(12272, 12288), - "CJK Symbols and Punctuation": range(12288, 12352), - "Hiragana": range(12352, 12448), - "Katakana": range(12448, 12544), - "Bopomofo": range(12544, 12592), - "Hangul Compatibility Jamo": range(12592, 12688), - "Kanbun": range(12688, 12704), - "Bopomofo Extended": range(12704, 12736), - "CJK Strokes": range(12736, 12784), - "Katakana Phonetic Extensions": range(12784, 12800), - "Enclosed CJK Letters and Months": range(12800, 13056), - "CJK Compatibility": range(13056, 13312), - "CJK Unified Ideographs Extension A": range(13312, 19904), - "Yijing Hexagram Symbols": range(19904, 19968), - "CJK Unified Ideographs": range(19968, 40960), - "Yi Syllables": range(40960, 42128), - "Yi Radicals": range(42128, 42192), - "Lisu": range(42192, 42240), - "Vai": range(42240, 42560), - "Cyrillic Extended-B": range(42560, 42656), - "Bamum": range(42656, 42752), - "Modifier Tone Letters": range(42752, 42784), - "Latin Extended-D": range(42784, 43008), - "Syloti Nagri": range(43008, 43056), - "Common Indic Number Forms": range(43056, 43072), - "Phags-pa": range(43072, 43136), - "Saurashtra": range(43136, 43232), - "Devanagari Extended": range(43232, 43264), - "Kayah Li": range(43264, 43312), - "Rejang": range(43312, 43360), - "Hangul Jamo Extended-A": range(43360, 43392), - "Javanese": range(43392, 43488), - "Myanmar Extended-B": range(43488, 43520), - "Cham": range(43520, 43616), - "Myanmar Extended-A": range(43616, 43648), - "Tai Viet": range(43648, 43744), - "Meetei Mayek Extensions": range(43744, 43776), - "Ethiopic Extended-A": range(43776, 43824), - "Latin Extended-E": range(43824, 43888), - "Cherokee Supplement": range(43888, 43968), - "Meetei Mayek": range(43968, 44032), - "Hangul Syllables": range(44032, 55216), - "Hangul Jamo Extended-B": range(55216, 55296), - "High Surrogates": range(55296, 56192), - "High Private Use Surrogates": range(56192, 56320), - "Low Surrogates": range(56320, 57344), - "Private Use Area": range(57344, 63744), - "CJK Compatibility Ideographs": range(63744, 64256), - "Alphabetic Presentation Forms": range(64256, 64336), - "Arabic Presentation Forms-A": range(64336, 65024), - "Variation Selectors": range(65024, 65040), - "Vertical Forms": range(65040, 65056), - "Combining Half Marks": range(65056, 65072), - "CJK Compatibility Forms": range(65072, 65104), - "Small Form Variants": range(65104, 65136), - "Arabic Presentation Forms-B": range(65136, 65280), - "Halfwidth and Fullwidth Forms": range(65280, 65520), - "Specials": range(65520, 65536), - "Linear B Syllabary": range(65536, 65664), - "Linear B Ideograms": range(65664, 65792), - "Aegean Numbers": range(65792, 65856), - "Ancient Greek Numbers": range(65856, 65936), - "Ancient Symbols": range(65936, 66000), - "Phaistos Disc": range(66000, 66048), - "Lycian": range(66176, 66208), - "Carian": range(66208, 66272), - "Coptic Epact Numbers": range(66272, 66304), - "Old Italic": range(66304, 66352), - "Gothic": range(66352, 66384), - "Old Permic": range(66384, 66432), - "Ugaritic": range(66432, 66464), - "Old Persian": range(66464, 66528), - "Deseret": range(66560, 66640), - "Shavian": range(66640, 66688), - "Osmanya": range(66688, 66736), - "Osage": range(66736, 66816), - "Elbasan": range(66816, 66864), - "Caucasian Albanian": range(66864, 66928), - "Vithkuqi": range(66928, 67008), - "Linear A": range(67072, 67456), - "Latin Extended-F": range(67456, 67520), - "Cypriot Syllabary": range(67584, 67648), - "Imperial Aramaic": range(67648, 67680), - "Palmyrene": range(67680, 67712), - "Nabataean": range(67712, 67760), - "Hatran": range(67808, 67840), - "Phoenician": range(67840, 67872), - "Lydian": range(67872, 67904), - "Meroitic Hieroglyphs": range(67968, 68000), - "Meroitic Cursive": range(68000, 68096), - "Kharoshthi": range(68096, 68192), - "Old South Arabian": range(68192, 68224), - "Old North Arabian": range(68224, 68256), - "Manichaean": range(68288, 68352), - "Avestan": range(68352, 68416), - "Inscriptional Parthian": range(68416, 68448), - "Inscriptional Pahlavi": range(68448, 68480), - "Psalter Pahlavi": range(68480, 68528), - "Old Turkic": range(68608, 68688), - "Old Hungarian": range(68736, 68864), - "Hanifi Rohingya": range(68864, 68928), - "Rumi Numeral Symbols": range(69216, 69248), - "Yezidi": range(69248, 69312), - "Arabic Extended-C": range(69312, 69376), - "Old Sogdian": range(69376, 69424), - "Sogdian": range(69424, 69488), - "Old Uyghur": range(69488, 69552), - "Chorasmian": range(69552, 69600), - "Elymaic": range(69600, 69632), - "Brahmi": range(69632, 69760), - "Kaithi": range(69760, 69840), - "Sora Sompeng": range(69840, 69888), - "Chakma": range(69888, 69968), - "Mahajani": range(69968, 70016), - "Sharada": range(70016, 70112), - "Sinhala Archaic Numbers": range(70112, 70144), - "Khojki": range(70144, 70224), - "Multani": range(70272, 70320), - "Khudawadi": range(70320, 70400), - "Grantha": range(70400, 70528), - "Newa": range(70656, 70784), - "Tirhuta": range(70784, 70880), - "Siddham": range(71040, 71168), - "Modi": range(71168, 71264), - "Mongolian Supplement": range(71264, 71296), - "Takri": range(71296, 71376), - "Ahom": range(71424, 71504), - "Dogra": range(71680, 71760), - "Warang Citi": range(71840, 71936), - "Dives Akuru": range(71936, 72032), - "Nandinagari": range(72096, 72192), - "Zanabazar Square": range(72192, 72272), - "Soyombo": range(72272, 72368), - "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384), - "Pau Cin Hau": range(72384, 72448), - "Devanagari Extended-A": range(72448, 72544), - "Bhaiksuki": range(72704, 72816), - "Marchen": range(72816, 72896), - "Masaram Gondi": range(72960, 73056), - "Gunjala Gondi": range(73056, 73136), - "Makasar": range(73440, 73472), - "Kawi": range(73472, 73568), - "Lisu Supplement": range(73648, 73664), - "Tamil Supplement": range(73664, 73728), - "Cuneiform": range(73728, 74752), - "Cuneiform Numbers and Punctuation": range(74752, 74880), - "Early Dynastic Cuneiform": range(74880, 75088), - "Cypro-Minoan": range(77712, 77824), - "Egyptian Hieroglyphs": range(77824, 78896), - "Egyptian Hieroglyph Format Controls": range(78896, 78944), - "Anatolian Hieroglyphs": range(82944, 83584), - "Bamum Supplement": range(92160, 92736), - "Mro": range(92736, 92784), - "Tangsa": range(92784, 92880), - "Bassa Vah": range(92880, 92928), - "Pahawh Hmong": range(92928, 93072), - "Medefaidrin": range(93760, 93856), - "Miao": range(93952, 94112), - "Ideographic Symbols and Punctuation": range(94176, 94208), - "Tangut": range(94208, 100352), - "Tangut Components": range(100352, 101120), - "Khitan Small Script": range(101120, 101632), - "Tangut Supplement": range(101632, 101760), - "Kana Extended-B": range(110576, 110592), - "Kana Supplement": range(110592, 110848), - "Kana Extended-A": range(110848, 110896), - "Small Kana Extension": range(110896, 110960), - "Nushu": range(110960, 111360), - "Duployan": range(113664, 113824), - "Shorthand Format Controls": range(113824, 113840), - "Znamenny Musical Notation": range(118528, 118736), - "Byzantine Musical Symbols": range(118784, 119040), - "Musical Symbols": range(119040, 119296), - "Ancient Greek Musical Notation": range(119296, 119376), - "Kaktovik Numerals": range(119488, 119520), - "Mayan Numerals": range(119520, 119552), - "Tai Xuan Jing Symbols": range(119552, 119648), - "Counting Rod Numerals": range(119648, 119680), - "Mathematical Alphanumeric Symbols": range(119808, 120832), - "Sutton SignWriting": range(120832, 121520), - "Latin Extended-G": range(122624, 122880), - "Glagolitic Supplement": range(122880, 122928), - "Cyrillic Extended-D": range(122928, 123024), - "Nyiakeng Puachue Hmong": range(123136, 123216), - "Toto": range(123536, 123584), - "Wancho": range(123584, 123648), - "Nag Mundari": range(124112, 124160), - "Ethiopic Extended-B": range(124896, 124928), - "Mende Kikakui": range(124928, 125152), - "Adlam": range(125184, 125280), - "Indic Siyaq Numbers": range(126064, 126144), - "Ottoman Siyaq Numbers": range(126208, 126288), - "Arabic Mathematical Alphabetic Symbols": range(126464, 126720), - "Mahjong Tiles": range(126976, 127024), - "Domino Tiles": range(127024, 127136), - "Playing Cards": range(127136, 127232), - "Enclosed Alphanumeric Supplement": range(127232, 127488), - "Enclosed Ideographic Supplement": range(127488, 127744), - "Miscellaneous Symbols and Pictographs": range(127744, 128512), - "Emoticons range(Emoji)": range(128512, 128592), - "Ornamental Dingbats": range(128592, 128640), - "Transport and Map Symbols": range(128640, 128768), - "Alchemical Symbols": range(128768, 128896), - "Geometric Shapes Extended": range(128896, 129024), - "Supplemental Arrows-C": range(129024, 129280), - "Supplemental Symbols and Pictographs": range(129280, 129536), - "Chess Symbols": range(129536, 129648), - "Symbols and Pictographs Extended-A": range(129648, 129792), - "Symbols for Legacy Computing": range(129792, 130048), - "CJK Unified Ideographs Extension B": range(131072, 173792), - "CJK Unified Ideographs Extension C": range(173824, 177984), - "CJK Unified Ideographs Extension D": range(177984, 178208), - "CJK Unified Ideographs Extension E": range(178208, 183984), - "CJK Unified Ideographs Extension F": range(183984, 191472), - "CJK Compatibility Ideographs Supplement": range(194560, 195104), - "CJK Unified Ideographs Extension G": range(196608, 201552), - "CJK Unified Ideographs Extension H": range(201552, 205744), - "Tags": range(917504, 917632), - "Variation Selectors Supplement": range(917760, 918000), - "Supplementary Private Use Area-A": range(983040, 1048576), - "Supplementary Private Use Area-B": range(1048576, 1114112), -} - - -UNICODE_SECONDARY_RANGE_KEYWORD: list[str] = [ - "Supplement", - "Extended", - "Extensions", - "Modifier", - "Marks", - "Punctuation", - "Symbols", - "Forms", - "Operators", - "Miscellaneous", - "Drawing", - "Block", - "Shapes", - "Supplemental", - "Tags", -] - -RE_POSSIBLE_ENCODING_INDICATION = re_compile( - r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)", - IGNORECASE, -) - -IANA_NO_ALIASES = [ - "cp720", - "cp737", - "cp856", - "cp874", - "cp875", - "cp1006", - "koi8_r", - "koi8_t", - "koi8_u", -] - -IANA_SUPPORTED: list[str] = sorted( - filter( - lambda x: x.endswith("_codec") is False - and x not in {"rot_13", "tactis", "mbcs"}, - list(set(aliases.values())) + IANA_NO_ALIASES, - ) -) - -IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED) - -# pre-computed code page that are similar using the function cp_similarity. -IANA_SUPPORTED_SIMILAR: dict[str, list[str]] = { - "cp037": ["cp1026", "cp1140", "cp273", "cp500"], - "cp1026": ["cp037", "cp1140", "cp273", "cp500"], - "cp1125": ["cp866"], - "cp1140": ["cp037", "cp1026", "cp273", "cp500"], - "cp1250": ["iso8859_2"], - "cp1251": ["kz1048", "ptcp154"], - "cp1252": ["iso8859_15", "iso8859_9", "latin_1"], - "cp1253": ["iso8859_7"], - "cp1254": ["iso8859_15", "iso8859_9", "latin_1"], - "cp1257": ["iso8859_13"], - "cp273": ["cp037", "cp1026", "cp1140", "cp500"], - "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"], - "cp500": ["cp037", "cp1026", "cp1140", "cp273"], - "cp850": ["cp437", "cp857", "cp858", "cp865"], - "cp857": ["cp850", "cp858", "cp865"], - "cp858": ["cp437", "cp850", "cp857", "cp865"], - "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"], - "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"], - "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"], - "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"], - "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"], - "cp866": ["cp1125"], - "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"], - "iso8859_11": ["tis_620"], - "iso8859_13": ["cp1257"], - "iso8859_14": [ - "iso8859_10", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_15": [ - "cp1252", - "cp1254", - "iso8859_10", - "iso8859_14", - "iso8859_16", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_16": [ - "iso8859_14", - "iso8859_15", - "iso8859_2", - "iso8859_3", - "iso8859_9", - "latin_1", - ], - "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"], - "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"], - "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"], - "iso8859_7": ["cp1253"], - "iso8859_9": [ - "cp1252", - "cp1254", - "cp1258", - "iso8859_10", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_4", - "latin_1", - ], - "kz1048": ["cp1251", "ptcp154"], - "latin_1": [ - "cp1252", - "cp1254", - "cp1258", - "iso8859_10", - "iso8859_14", - "iso8859_15", - "iso8859_16", - "iso8859_3", - "iso8859_4", - "iso8859_9", - ], - "mac_iceland": ["mac_roman", "mac_turkish"], - "mac_roman": ["mac_iceland", "mac_turkish"], - "mac_turkish": ["mac_iceland", "mac_roman"], - "ptcp154": ["cp1251", "kz1048"], - "tis_620": ["iso8859_11"], -} - - -CHARDET_CORRESPONDENCE: dict[str, str] = { - "iso2022_kr": "ISO-2022-KR", - "iso2022_jp": "ISO-2022-JP", - "euc_kr": "EUC-KR", - "tis_620": "TIS-620", - "utf_32": "UTF-32", - "euc_jp": "EUC-JP", - "koi8_r": "KOI8-R", - "iso8859_1": "ISO-8859-1", - "iso8859_2": "ISO-8859-2", - "iso8859_5": "ISO-8859-5", - "iso8859_6": "ISO-8859-6", - "iso8859_7": "ISO-8859-7", - "iso8859_8": "ISO-8859-8", - "utf_16": "UTF-16", - "cp855": "IBM855", - "mac_cyrillic": "MacCyrillic", - "gb2312": "GB2312", - "gb18030": "GB18030", - "cp932": "CP932", - "cp866": "IBM866", - "utf_8": "utf-8", - "utf_8_sig": "UTF-8-SIG", - "shift_jis": "SHIFT_JIS", - "big5": "Big5", - "cp1250": "windows-1250", - "cp1251": "windows-1251", - "cp1252": "Windows-1252", - "cp1253": "windows-1253", - "cp1255": "windows-1255", - "cp1256": "windows-1256", - "cp1254": "Windows-1254", - "cp949": "CP949", -} - - -COMMON_SAFE_ASCII_CHARACTERS: set[str] = { - "<", - ">", - "=", - ":", - "/", - "&", - ";", - "{", - "}", - "[", - "]", - ",", - "|", - '"', - "-", - "(", - ")", -} - -# Sample character sets — replace with full lists if needed -COMMON_CHINESE_CHARACTERS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞" - -COMMON_JAPANESE_CHARACTERS = "日一国年大十二本中長出三時行見月分後前生五間上東四今金九入学高円子外八六下来気小七山話女北午百書先名川千水半男西電校語土木聞食車何南万毎白天母火右読友左休父雨" - -COMMON_KOREAN_CHARACTERS = "一二三四五六七八九十百千萬上下左右中人女子大小山川日月火水木金土父母天地國名年時文校學生" - -# Combine all into a set -COMMON_CJK_CHARACTERS = set( - "".join( - [ - COMMON_CHINESE_CHARACTERS, - COMMON_JAPANESE_CHARACTERS, - COMMON_KOREAN_CHARACTERS, - ] - ) -) - -KO_NAMES: set[str] = {"johab", "cp949", "euc_kr"} -ZH_NAMES: set[str] = {"big5", "cp950", "big5hkscs", "hz"} - -# Logging LEVEL below DEBUG -TRACE: int = 5 - - -# Language label that contain the em dash "—" -# character are to be considered alternative seq to origin -FREQUENCIES: dict[str, list[str]] = { - "English": [ - "e", - "a", - "t", - "i", - "o", - "n", - "s", - "r", - "h", - "l", - "d", - "c", - "u", - "m", - "f", - "p", - "g", - "w", - "y", - "b", - "v", - "k", - "x", - "j", - "z", - "q", - ], - "English—": [ - "e", - "a", - "t", - "i", - "o", - "n", - "s", - "r", - "h", - "l", - "d", - "c", - "m", - "u", - "f", - "p", - "g", - "w", - "b", - "y", - "v", - "k", - "j", - "x", - "z", - "q", - ], - "German": [ - "e", - "n", - "i", - "r", - "s", - "t", - "a", - "d", - "h", - "u", - "l", - "g", - "o", - "c", - "m", - "b", - "f", - "k", - "w", - "z", - "p", - "v", - "ü", - "ä", - "ö", - "j", - ], - "French": [ - "e", - "a", - "s", - "n", - "i", - "t", - "r", - "l", - "u", - "o", - "d", - "c", - "p", - "m", - "é", - "v", - "g", - "f", - "b", - "h", - "q", - "à", - "x", - "è", - "y", - "j", - ], - "Dutch": [ - "e", - "n", - "a", - "i", - "r", - "t", - "o", - "d", - "s", - "l", - "g", - "h", - "v", - "m", - "u", - "k", - "c", - "p", - "b", - "w", - "j", - "z", - "f", - "y", - "x", - "ë", - ], - "Italian": [ - "e", - "i", - "a", - "o", - "n", - "l", - "t", - "r", - "s", - "c", - "d", - "u", - "p", - "m", - "g", - "v", - "f", - "b", - "z", - "h", - "q", - "è", - "à", - "k", - "y", - "ò", - ], - "Polish": [ - "a", - "i", - "o", - "e", - "n", - "r", - "z", - "w", - "s", - "c", - "t", - "k", - "y", - "d", - "p", - "m", - "u", - "l", - "j", - "ł", - "g", - "b", - "h", - "ą", - "ę", - "ó", - ], - "Spanish": [ - "e", - "a", - "o", - "n", - "s", - "r", - "i", - "l", - "d", - "t", - "c", - "u", - "m", - "p", - "b", - "g", - "v", - "f", - "y", - "ó", - "h", - "q", - "í", - "j", - "z", - "á", - ], - "Russian": [ - "о", - "а", - "е", - "и", - "н", - "с", - "т", - "р", - "в", - "л", - "к", - "м", - "д", - "п", - "у", - "г", - "я", - "ы", - "з", - "б", - "й", - "ь", - "ч", - "х", - "ж", - "ц", - ], - # Jap-Kanji - "Japanese": [ - "人", - "一", - "大", - "亅", - "丁", - "丨", - "竹", - "笑", - "口", - "日", - "今", - "二", - "彳", - "行", - "十", - "土", - "丶", - "寸", - "寺", - "時", - "乙", - "丿", - "乂", - "气", - "気", - "冂", - "巾", - "亠", - "市", - "目", - "儿", - "見", - "八", - "小", - "凵", - "県", - "月", - "彐", - "門", - "間", - "木", - "東", - "山", - "出", - "本", - "中", - "刀", - "分", - "耳", - "又", - "取", - "最", - "言", - "田", - "心", - "思", - "刂", - "前", - "京", - "尹", - "事", - "生", - "厶", - "云", - "会", - "未", - "来", - "白", - "冫", - "楽", - "灬", - "馬", - "尸", - "尺", - "駅", - "明", - "耂", - "者", - "了", - "阝", - "都", - "高", - "卜", - "占", - "厂", - "广", - "店", - "子", - "申", - "奄", - "亻", - "俺", - "上", - "方", - "冖", - "学", - "衣", - "艮", - "食", - "自", - ], - # Jap-Katakana - "Japanese—": [ - "ー", - "ン", - "ス", - "・", - "ル", - "ト", - "リ", - "イ", - "ア", - "ラ", - "ッ", - "ク", - "ド", - "シ", - "レ", - "ジ", - "タ", - "フ", - "ロ", - "カ", - "テ", - "マ", - "ィ", - "グ", - "バ", - "ム", - "プ", - "オ", - "コ", - "デ", - "ニ", - "ウ", - "メ", - "サ", - "ビ", - "ナ", - "ブ", - "ャ", - "エ", - "ュ", - "チ", - "キ", - "ズ", - "ダ", - "パ", - "ミ", - "ェ", - "ョ", - "ハ", - "セ", - "ベ", - "ガ", - "モ", - "ツ", - "ネ", - "ボ", - "ソ", - "ノ", - "ァ", - "ヴ", - "ワ", - "ポ", - "ペ", - "ピ", - "ケ", - "ゴ", - "ギ", - "ザ", - "ホ", - "ゲ", - "ォ", - "ヤ", - "ヒ", - "ユ", - "ヨ", - "ヘ", - "ゼ", - "ヌ", - "ゥ", - "ゾ", - "ヶ", - "ヂ", - "ヲ", - "ヅ", - "ヵ", - "ヱ", - "ヰ", - "ヮ", - "ヽ", - "゠", - "ヾ", - "ヷ", - "ヿ", - "ヸ", - "ヹ", - "ヺ", - ], - # Jap-Hiragana - "Japanese——": [ - "の", - "に", - "る", - "た", - "と", - "は", - "し", - "い", - "を", - "で", - "て", - "が", - "な", - "れ", - "か", - "ら", - "さ", - "っ", - "り", - "す", - "あ", - "も", - "こ", - "ま", - "う", - "く", - "よ", - "き", - "ん", - "め", - "お", - "け", - "そ", - "つ", - "だ", - "や", - "え", - "ど", - "わ", - "ち", - "み", - "せ", - "じ", - "ば", - "へ", - "び", - "ず", - "ろ", - "ほ", - "げ", - "む", - "べ", - "ひ", - "ょ", - "ゆ", - "ぶ", - "ご", - "ゃ", - "ね", - "ふ", - "ぐ", - "ぎ", - "ぼ", - "ゅ", - "づ", - "ざ", - "ぞ", - "ぬ", - "ぜ", - "ぱ", - "ぽ", - "ぷ", - "ぴ", - "ぃ", - "ぁ", - "ぇ", - "ぺ", - "ゞ", - "ぢ", - "ぉ", - "ぅ", - "ゐ", - "ゝ", - "ゑ", - "゛", - "゜", - "ゎ", - "ゔ", - "゚", - "ゟ", - "゙", - "ゕ", - "ゖ", - ], - "Portuguese": [ - "a", - "e", - "o", - "s", - "i", - "r", - "d", - "n", - "t", - "m", - "u", - "c", - "l", - "p", - "g", - "v", - "b", - "f", - "h", - "ã", - "q", - "é", - "ç", - "á", - "z", - "í", - ], - "Swedish": [ - "e", - "a", - "n", - "r", - "t", - "s", - "i", - "l", - "d", - "o", - "m", - "k", - "g", - "v", - "h", - "f", - "u", - "p", - "ä", - "c", - "b", - "ö", - "å", - "y", - "j", - "x", - ], - "Chinese": [ - "的", - "一", - "是", - "不", - "了", - "在", - "人", - "有", - "我", - "他", - "这", - "个", - "们", - "中", - "来", - "上", - "大", - "为", - "和", - "国", - "地", - "到", - "以", - "说", - "时", - "要", - "就", - "出", - "会", - "可", - "也", - "你", - "对", - "生", - "能", - "而", - "子", - "那", - "得", - "于", - "着", - "下", - "自", - "之", - "年", - "过", - "发", - "后", - "作", - "里", - "用", - "道", - "行", - "所", - "然", - "家", - "种", - "事", - "成", - "方", - "多", - "经", - "么", - "去", - "法", - "学", - "如", - "都", - "同", - "现", - "当", - "没", - "动", - "面", - "起", - "看", - "定", - "天", - "分", - "还", - "进", - "好", - "小", - "部", - "其", - "些", - "主", - "样", - "理", - "心", - "她", - "本", - "前", - "开", - "但", - "因", - "只", - "从", - "想", - "实", - ], - "Ukrainian": [ - "о", - "а", - "н", - "і", - "и", - "р", - "в", - "т", - "е", - "с", - "к", - "л", - "у", - "д", - "м", - "п", - "з", - "я", - "ь", - "б", - "г", - "й", - "ч", - "х", - "ц", - "ї", - ], - "Norwegian": [ - "e", - "r", - "n", - "t", - "a", - "s", - "i", - "o", - "l", - "d", - "g", - "k", - "m", - "v", - "f", - "p", - "u", - "b", - "h", - "å", - "y", - "j", - "ø", - "c", - "æ", - "w", - ], - "Finnish": [ - "a", - "i", - "n", - "t", - "e", - "s", - "l", - "o", - "u", - "k", - "ä", - "m", - "r", - "v", - "j", - "h", - "p", - "y", - "d", - "ö", - "g", - "c", - "b", - "f", - "w", - "z", - ], - "Vietnamese": [ - "n", - "h", - "t", - "i", - "c", - "g", - "a", - "o", - "u", - "m", - "l", - "r", - "à", - "đ", - "s", - "e", - "v", - "p", - "b", - "y", - "ư", - "d", - "á", - "k", - "ộ", - "ế", - ], - "Czech": [ - "o", - "e", - "a", - "n", - "t", - "s", - "i", - "l", - "v", - "r", - "k", - "d", - "u", - "m", - "p", - "í", - "c", - "h", - "z", - "á", - "y", - "j", - "b", - "ě", - "é", - "ř", - ], - "Hungarian": [ - "e", - "a", - "t", - "l", - "s", - "n", - "k", - "r", - "i", - "o", - "z", - "á", - "é", - "g", - "m", - "b", - "y", - "v", - "d", - "h", - "u", - "p", - "j", - "ö", - "f", - "c", - ], - "Korean": [ - "이", - "다", - "에", - "의", - "는", - "로", - "하", - "을", - "가", - "고", - "지", - "서", - "한", - "은", - "기", - "으", - "년", - "대", - "사", - "시", - "를", - "리", - "도", - "인", - "스", - "일", - ], - "Indonesian": [ - "a", - "n", - "e", - "i", - "r", - "t", - "u", - "s", - "d", - "k", - "m", - "l", - "g", - "p", - "b", - "o", - "h", - "y", - "j", - "c", - "w", - "f", - "v", - "z", - "x", - "q", - ], - "Turkish": [ - "a", - "e", - "i", - "n", - "r", - "l", - "ı", - "k", - "d", - "t", - "s", - "m", - "y", - "u", - "o", - "b", - "ü", - "ş", - "v", - "g", - "z", - "h", - "c", - "p", - "ç", - "ğ", - ], - "Romanian": [ - "e", - "i", - "a", - "r", - "n", - "t", - "u", - "l", - "o", - "c", - "s", - "d", - "p", - "m", - "ă", - "f", - "v", - "î", - "g", - "b", - "ș", - "ț", - "z", - "h", - "â", - "j", - ], - "Farsi": [ - "ا", - "ی", - "ر", - "د", - "ن", - "ه", - "و", - "م", - "ت", - "ب", - "س", - "ل", - "ک", - "ش", - "ز", - "ف", - "گ", - "ع", - "خ", - "ق", - "ج", - "آ", - "پ", - "ح", - "ط", - "ص", - ], - "Arabic": [ - "ا", - "ل", - "ي", - "م", - "و", - "ن", - "ر", - "ت", - "ب", - "ة", - "ع", - "د", - "س", - "ف", - "ه", - "ك", - "ق", - "أ", - "ح", - "ج", - "ش", - "ط", - "ص", - "ى", - "خ", - "إ", - ], - "Danish": [ - "e", - "r", - "n", - "t", - "a", - "i", - "s", - "d", - "l", - "o", - "g", - "m", - "k", - "f", - "v", - "u", - "b", - "h", - "p", - "å", - "y", - "ø", - "æ", - "c", - "j", - "w", - ], - "Serbian": [ - "а", - "и", - "о", - "е", - "н", - "р", - "с", - "у", - "т", - "к", - "ј", - "в", - "д", - "м", - "п", - "л", - "г", - "з", - "б", - "a", - "i", - "e", - "o", - "n", - "ц", - "ш", - ], - "Lithuanian": [ - "i", - "a", - "s", - "o", - "r", - "e", - "t", - "n", - "u", - "k", - "m", - "l", - "p", - "v", - "d", - "j", - "g", - "ė", - "b", - "y", - "ų", - "š", - "ž", - "c", - "ą", - "į", - ], - "Slovene": [ - "e", - "a", - "i", - "o", - "n", - "r", - "s", - "l", - "t", - "j", - "v", - "k", - "d", - "p", - "m", - "u", - "z", - "b", - "g", - "h", - "č", - "c", - "š", - "ž", - "f", - "y", - ], - "Slovak": [ - "o", - "a", - "e", - "n", - "i", - "r", - "v", - "t", - "s", - "l", - "k", - "d", - "m", - "p", - "u", - "c", - "h", - "j", - "b", - "z", - "á", - "y", - "ý", - "í", - "č", - "é", - ], - "Hebrew": [ - "י", - "ו", - "ה", - "ל", - "ר", - "ב", - "ת", - "מ", - "א", - "ש", - "נ", - "ע", - "ם", - "ד", - "ק", - "ח", - "פ", - "ס", - "כ", - "ג", - "ט", - "צ", - "ן", - "ז", - "ך", - ], - "Bulgarian": [ - "а", - "и", - "о", - "е", - "н", - "т", - "р", - "с", - "в", - "л", - "к", - "д", - "п", - "м", - "з", - "г", - "я", - "ъ", - "у", - "б", - "ч", - "ц", - "й", - "ж", - "щ", - "х", - ], - "Croatian": [ - "a", - "i", - "o", - "e", - "n", - "r", - "j", - "s", - "t", - "u", - "k", - "l", - "v", - "d", - "m", - "p", - "g", - "z", - "b", - "c", - "č", - "h", - "š", - "ž", - "ć", - "f", - ], - "Hindi": [ - "क", - "र", - "स", - "न", - "त", - "म", - "ह", - "प", - "य", - "ल", - "व", - "ज", - "द", - "ग", - "ब", - "श", - "ट", - "अ", - "ए", - "थ", - "भ", - "ड", - "च", - "ध", - "ष", - "इ", - ], - "Estonian": [ - "a", - "i", - "e", - "s", - "t", - "l", - "u", - "n", - "o", - "k", - "r", - "d", - "m", - "v", - "g", - "p", - "j", - "h", - "ä", - "b", - "õ", - "ü", - "f", - "c", - "ö", - "y", - ], - "Thai": [ - "า", - "น", - "ร", - "อ", - "ก", - "เ", - "ง", - "ม", - "ย", - "ล", - "ว", - "ด", - "ท", - "ส", - "ต", - "ะ", - "ป", - "บ", - "ค", - "ห", - "แ", - "จ", - "พ", - "ช", - "ข", - "ใ", - ], - "Greek": [ - "α", - "τ", - "ο", - "ι", - "ε", - "ν", - "ρ", - "σ", - "κ", - "η", - "π", - "ς", - "υ", - "μ", - "λ", - "ί", - "ό", - "ά", - "γ", - "έ", - "δ", - "ή", - "ω", - "χ", - "θ", - "ύ", - ], - "Tamil": [ - "க", - "த", - "ப", - "ட", - "ர", - "ம", - "ல", - "ன", - "வ", - "ற", - "ய", - "ள", - "ச", - "ந", - "இ", - "ண", - "அ", - "ஆ", - "ழ", - "ங", - "எ", - "உ", - "ஒ", - "ஸ", - ], - "Kazakh": [ - "а", - "ы", - "е", - "н", - "т", - "р", - "л", - "і", - "д", - "с", - "м", - "қ", - "к", - "о", - "б", - "и", - "у", - "ғ", - "ж", - "ң", - "з", - "ш", - "й", - "п", - "г", - "ө", - ], -} - -LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/legacy.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/legacy.py deleted file mode 100644 index 360a310..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/legacy.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from warnings import warn - -from .api import from_bytes -from .constant import CHARDET_CORRESPONDENCE, TOO_SMALL_SEQUENCE - -# TODO: remove this check when dropping Python 3.7 support -if TYPE_CHECKING: - from typing_extensions import TypedDict - - class ResultDict(TypedDict): - encoding: str | None - language: str - confidence: float | None - - -def detect( - byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any -) -> ResultDict: - """ - chardet legacy method - Detect the encoding of the given byte string. It should be mostly backward-compatible. - Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) - This function is deprecated and should be used to migrate your project easily, consult the documentation for - further information. Not planned for removal. - - :param byte_str: The byte sequence to examine. - :param should_rename_legacy: Should we rename legacy encodings - to their more modern equivalents? - """ - if len(kwargs): - warn( - f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" - ) - - if not isinstance(byte_str, (bytearray, bytes)): - raise TypeError( # pragma: nocover - f"Expected object of type bytes or bytearray, got: {type(byte_str)}" - ) - - if isinstance(byte_str, bytearray): - byte_str = bytes(byte_str) - - r = from_bytes(byte_str).best() - - encoding = r.encoding if r is not None else None - language = r.language if r is not None and r.language != "Unknown" else "" - confidence = 1.0 - r.chaos if r is not None else None - - # automatically lower confidence - # on small bytes samples. - # https://github.com/jawah/charset_normalizer/issues/391 - if ( - confidence is not None - and confidence >= 0.9 - and encoding - not in { - "utf_8", - "ascii", - } - and r.bom is False # type: ignore[union-attr] - and len(byte_str) < TOO_SMALL_SEQUENCE - ): - confidence -= 0.2 - - # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process - # but chardet does return 'utf-8-sig' and it is a valid codec name. - if r is not None and encoding == "utf_8" and r.bom: - encoding += "_sig" - - if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: - encoding = CHARDET_CORRESPONDENCE[encoding] - - return { - "encoding": encoding, - "language": language, - "confidence": confidence, - } diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-darwin.so deleted file mode 100755 index 5e4a229..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.py deleted file mode 100644 index 12ce024..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md.py +++ /dev/null @@ -1,635 +0,0 @@ -from __future__ import annotations - -from functools import lru_cache -from logging import getLogger - -from .constant import ( - COMMON_SAFE_ASCII_CHARACTERS, - TRACE, - UNICODE_SECONDARY_RANGE_KEYWORD, -) -from .utils import ( - is_accentuated, - is_arabic, - is_arabic_isolated_form, - is_case_variable, - is_cjk, - is_emoticon, - is_hangul, - is_hiragana, - is_katakana, - is_latin, - is_punctuation, - is_separator, - is_symbol, - is_thai, - is_unprintable, - remove_accent, - unicode_range, - is_cjk_uncommon, -) - - -class MessDetectorPlugin: - """ - Base abstract class used for mess detection plugins. - All detectors MUST extend and implement given methods. - """ - - def eligible(self, character: str) -> bool: - """ - Determine if given character should be fed in. - """ - raise NotImplementedError # pragma: nocover - - def feed(self, character: str) -> None: - """ - The main routine to be executed upon character. - Insert the logic in witch the text would be considered chaotic. - """ - raise NotImplementedError # pragma: nocover - - def reset(self) -> None: # pragma: no cover - """ - Permit to reset the plugin to the initial state. - """ - raise NotImplementedError - - @property - def ratio(self) -> float: - """ - Compute the chaos ratio based on what your feed() has seen. - Must NOT be lower than 0.; No restriction gt 0. - """ - raise NotImplementedError # pragma: nocover - - -class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._punctuation_count: int = 0 - self._symbol_count: int = 0 - self._character_count: int = 0 - - self._last_printable_char: str | None = None - self._frenzy_symbol_in_word: bool = False - - def eligible(self, character: str) -> bool: - return character.isprintable() - - def feed(self, character: str) -> None: - self._character_count += 1 - - if ( - character != self._last_printable_char - and character not in COMMON_SAFE_ASCII_CHARACTERS - ): - if is_punctuation(character): - self._punctuation_count += 1 - elif ( - character.isdigit() is False - and is_symbol(character) - and is_emoticon(character) is False - ): - self._symbol_count += 2 - - self._last_printable_char = character - - def reset(self) -> None: # Abstract - self._punctuation_count = 0 - self._character_count = 0 - self._symbol_count = 0 - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - ratio_of_punctuation: float = ( - self._punctuation_count + self._symbol_count - ) / self._character_count - - return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 - - -class TooManyAccentuatedPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._character_count: int = 0 - self._accentuated_count: int = 0 - - def eligible(self, character: str) -> bool: - return character.isalpha() - - def feed(self, character: str) -> None: - self._character_count += 1 - - if is_accentuated(character): - self._accentuated_count += 1 - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._accentuated_count = 0 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - ratio_of_accentuation: float = self._accentuated_count / self._character_count - return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 - - -class UnprintablePlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._unprintable_count: int = 0 - self._character_count: int = 0 - - def eligible(self, character: str) -> bool: - return True - - def feed(self, character: str) -> None: - if is_unprintable(character): - self._unprintable_count += 1 - self._character_count += 1 - - def reset(self) -> None: # Abstract - self._unprintable_count = 0 - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - return (self._unprintable_count * 8) / self._character_count - - -class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._successive_count: int = 0 - self._character_count: int = 0 - - self._last_latin_character: str | None = None - - def eligible(self, character: str) -> bool: - return character.isalpha() and is_latin(character) - - def feed(self, character: str) -> None: - self._character_count += 1 - if ( - self._last_latin_character is not None - and is_accentuated(character) - and is_accentuated(self._last_latin_character) - ): - if character.isupper() and self._last_latin_character.isupper(): - self._successive_count += 1 - # Worse if its the same char duplicated with different accent. - if remove_accent(character) == remove_accent(self._last_latin_character): - self._successive_count += 1 - self._last_latin_character = character - - def reset(self) -> None: # Abstract - self._successive_count = 0 - self._character_count = 0 - self._last_latin_character = None - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - return (self._successive_count * 2) / self._character_count - - -class SuspiciousRange(MessDetectorPlugin): - def __init__(self) -> None: - self._suspicious_successive_range_count: int = 0 - self._character_count: int = 0 - self._last_printable_seen: str | None = None - - def eligible(self, character: str) -> bool: - return character.isprintable() - - def feed(self, character: str) -> None: - self._character_count += 1 - - if ( - character.isspace() - or is_punctuation(character) - or character in COMMON_SAFE_ASCII_CHARACTERS - ): - self._last_printable_seen = None - return - - if self._last_printable_seen is None: - self._last_printable_seen = character - return - - unicode_range_a: str | None = unicode_range(self._last_printable_seen) - unicode_range_b: str | None = unicode_range(character) - - if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): - self._suspicious_successive_range_count += 1 - - self._last_printable_seen = character - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._suspicious_successive_range_count = 0 - self._last_printable_seen = None - - @property - def ratio(self) -> float: - if self._character_count <= 13: - return 0.0 - - ratio_of_suspicious_range_usage: float = ( - self._suspicious_successive_range_count * 2 - ) / self._character_count - - return ratio_of_suspicious_range_usage - - -class SuperWeirdWordPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._word_count: int = 0 - self._bad_word_count: int = 0 - self._foreign_long_count: int = 0 - - self._is_current_word_bad: bool = False - self._foreign_long_watch: bool = False - - self._character_count: int = 0 - self._bad_character_count: int = 0 - - self._buffer: str = "" - self._buffer_accent_count: int = 0 - self._buffer_glyph_count: int = 0 - - def eligible(self, character: str) -> bool: - return True - - def feed(self, character: str) -> None: - if character.isalpha(): - self._buffer += character - if is_accentuated(character): - self._buffer_accent_count += 1 - if ( - self._foreign_long_watch is False - and (is_latin(character) is False or is_accentuated(character)) - and is_cjk(character) is False - and is_hangul(character) is False - and is_katakana(character) is False - and is_hiragana(character) is False - and is_thai(character) is False - ): - self._foreign_long_watch = True - if ( - is_cjk(character) - or is_hangul(character) - or is_katakana(character) - or is_hiragana(character) - or is_thai(character) - ): - self._buffer_glyph_count += 1 - return - if not self._buffer: - return - if ( - character.isspace() or is_punctuation(character) or is_separator(character) - ) and self._buffer: - self._word_count += 1 - buffer_length: int = len(self._buffer) - - self._character_count += buffer_length - - if buffer_length >= 4: - if self._buffer_accent_count / buffer_length >= 0.5: - self._is_current_word_bad = True - # Word/Buffer ending with an upper case accentuated letter are so rare, - # that we will consider them all as suspicious. Same weight as foreign_long suspicious. - elif ( - is_accentuated(self._buffer[-1]) - and self._buffer[-1].isupper() - and all(_.isupper() for _ in self._buffer) is False - ): - self._foreign_long_count += 1 - self._is_current_word_bad = True - elif self._buffer_glyph_count == 1: - self._is_current_word_bad = True - self._foreign_long_count += 1 - if buffer_length >= 24 and self._foreign_long_watch: - camel_case_dst = [ - i - for c, i in zip(self._buffer, range(0, buffer_length)) - if c.isupper() - ] - probable_camel_cased: bool = False - - if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3): - probable_camel_cased = True - - if not probable_camel_cased: - self._foreign_long_count += 1 - self._is_current_word_bad = True - - if self._is_current_word_bad: - self._bad_word_count += 1 - self._bad_character_count += len(self._buffer) - self._is_current_word_bad = False - - self._foreign_long_watch = False - self._buffer = "" - self._buffer_accent_count = 0 - self._buffer_glyph_count = 0 - elif ( - character not in {"<", ">", "-", "=", "~", "|", "_"} - and character.isdigit() is False - and is_symbol(character) - ): - self._is_current_word_bad = True - self._buffer += character - - def reset(self) -> None: # Abstract - self._buffer = "" - self._is_current_word_bad = False - self._foreign_long_watch = False - self._bad_word_count = 0 - self._word_count = 0 - self._character_count = 0 - self._bad_character_count = 0 - self._foreign_long_count = 0 - - @property - def ratio(self) -> float: - if self._word_count <= 10 and self._foreign_long_count == 0: - return 0.0 - - return self._bad_character_count / self._character_count - - -class CjkUncommonPlugin(MessDetectorPlugin): - """ - Detect messy CJK text that probably means nothing. - """ - - def __init__(self) -> None: - self._character_count: int = 0 - self._uncommon_count: int = 0 - - def eligible(self, character: str) -> bool: - return is_cjk(character) - - def feed(self, character: str) -> None: - self._character_count += 1 - - if is_cjk_uncommon(character): - self._uncommon_count += 1 - return - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._uncommon_count = 0 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - uncommon_form_usage: float = self._uncommon_count / self._character_count - - # we can be pretty sure it's garbage when uncommon characters are widely - # used. otherwise it could just be traditional chinese for example. - return uncommon_form_usage / 10 if uncommon_form_usage > 0.5 else 0.0 - - -class ArchaicUpperLowerPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._buf: bool = False - - self._character_count_since_last_sep: int = 0 - - self._successive_upper_lower_count: int = 0 - self._successive_upper_lower_count_final: int = 0 - - self._character_count: int = 0 - - self._last_alpha_seen: str | None = None - self._current_ascii_only: bool = True - - def eligible(self, character: str) -> bool: - return True - - def feed(self, character: str) -> None: - is_concerned = character.isalpha() and is_case_variable(character) - chunk_sep = is_concerned is False - - if chunk_sep and self._character_count_since_last_sep > 0: - if ( - self._character_count_since_last_sep <= 64 - and character.isdigit() is False - and self._current_ascii_only is False - ): - self._successive_upper_lower_count_final += ( - self._successive_upper_lower_count - ) - - self._successive_upper_lower_count = 0 - self._character_count_since_last_sep = 0 - self._last_alpha_seen = None - self._buf = False - self._character_count += 1 - self._current_ascii_only = True - - return - - if self._current_ascii_only is True and character.isascii() is False: - self._current_ascii_only = False - - if self._last_alpha_seen is not None: - if (character.isupper() and self._last_alpha_seen.islower()) or ( - character.islower() and self._last_alpha_seen.isupper() - ): - if self._buf is True: - self._successive_upper_lower_count += 2 - self._buf = False - else: - self._buf = True - else: - self._buf = False - - self._character_count += 1 - self._character_count_since_last_sep += 1 - self._last_alpha_seen = character - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._character_count_since_last_sep = 0 - self._successive_upper_lower_count = 0 - self._successive_upper_lower_count_final = 0 - self._last_alpha_seen = None - self._buf = False - self._current_ascii_only = True - - @property - def ratio(self) -> float: - if self._character_count == 0: - return 0.0 - - return self._successive_upper_lower_count_final / self._character_count - - -class ArabicIsolatedFormPlugin(MessDetectorPlugin): - def __init__(self) -> None: - self._character_count: int = 0 - self._isolated_form_count: int = 0 - - def reset(self) -> None: # Abstract - self._character_count = 0 - self._isolated_form_count = 0 - - def eligible(self, character: str) -> bool: - return is_arabic(character) - - def feed(self, character: str) -> None: - self._character_count += 1 - - if is_arabic_isolated_form(character): - self._isolated_form_count += 1 - - @property - def ratio(self) -> float: - if self._character_count < 8: - return 0.0 - - isolated_form_usage: float = self._isolated_form_count / self._character_count - - return isolated_form_usage - - -@lru_cache(maxsize=1024) -def is_suspiciously_successive_range( - unicode_range_a: str | None, unicode_range_b: str | None -) -> bool: - """ - Determine if two Unicode range seen next to each other can be considered as suspicious. - """ - if unicode_range_a is None or unicode_range_b is None: - return True - - if unicode_range_a == unicode_range_b: - return False - - if "Latin" in unicode_range_a and "Latin" in unicode_range_b: - return False - - if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: - return False - - # Latin characters can be accompanied with a combining diacritical mark - # eg. Vietnamese. - if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( - "Combining" in unicode_range_a or "Combining" in unicode_range_b - ): - return False - - keywords_range_a, keywords_range_b = ( - unicode_range_a.split(" "), - unicode_range_b.split(" "), - ) - - for el in keywords_range_a: - if el in UNICODE_SECONDARY_RANGE_KEYWORD: - continue - if el in keywords_range_b: - return False - - # Japanese Exception - range_a_jp_chars, range_b_jp_chars = ( - unicode_range_a - in ( - "Hiragana", - "Katakana", - ), - unicode_range_b in ("Hiragana", "Katakana"), - ) - if (range_a_jp_chars or range_b_jp_chars) and ( - "CJK" in unicode_range_a or "CJK" in unicode_range_b - ): - return False - if range_a_jp_chars and range_b_jp_chars: - return False - - if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: - if "CJK" in unicode_range_a or "CJK" in unicode_range_b: - return False - if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": - return False - - # Chinese/Japanese use dedicated range for punctuation and/or separators. - if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( - unicode_range_a in ["Katakana", "Hiragana"] - and unicode_range_b in ["Katakana", "Hiragana"] - ): - if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: - return False - if "Forms" in unicode_range_a or "Forms" in unicode_range_b: - return False - if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": - return False - - return True - - -@lru_cache(maxsize=2048) -def mess_ratio( - decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False -) -> float: - """ - Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. - """ - - detectors: list[MessDetectorPlugin] = [ - md_class() for md_class in MessDetectorPlugin.__subclasses__() - ] - - length: int = len(decoded_sequence) + 1 - - mean_mess_ratio: float = 0.0 - - if length < 512: - intermediary_mean_mess_ratio_calc: int = 32 - elif length <= 1024: - intermediary_mean_mess_ratio_calc = 64 - else: - intermediary_mean_mess_ratio_calc = 128 - - for character, index in zip(decoded_sequence + "\n", range(length)): - for detector in detectors: - if detector.eligible(character): - detector.feed(character) - - if ( - index > 0 and index % intermediary_mean_mess_ratio_calc == 0 - ) or index == length - 1: - mean_mess_ratio = sum(dt.ratio for dt in detectors) - - if mean_mess_ratio >= maximum_threshold: - break - - if debug: - logger = getLogger("charset_normalizer") - - logger.log( - TRACE, - "Mess-detector extended-analysis start. " - f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} " - f"maximum_threshold={maximum_threshold}", - ) - - if len(decoded_sequence) > 16: - logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") - logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") - - for dt in detectors: - logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") - - return round(mean_mess_ratio, 3) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md__mypyc.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md__mypyc.cpython-39-darwin.so deleted file mode 100755 index 3d701d4..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/md__mypyc.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/models.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/models.py deleted file mode 100644 index 1042758..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/models.py +++ /dev/null @@ -1,360 +0,0 @@ -from __future__ import annotations - -from encodings.aliases import aliases -from hashlib import sha256 -from json import dumps -from re import sub -from typing import Any, Iterator, List, Tuple - -from .constant import RE_POSSIBLE_ENCODING_INDICATION, TOO_BIG_SEQUENCE -from .utils import iana_name, is_multi_byte_encoding, unicode_range - - -class CharsetMatch: - def __init__( - self, - payload: bytes, - guessed_encoding: str, - mean_mess_ratio: float, - has_sig_or_bom: bool, - languages: CoherenceMatches, - decoded_payload: str | None = None, - preemptive_declaration: str | None = None, - ): - self._payload: bytes = payload - - self._encoding: str = guessed_encoding - self._mean_mess_ratio: float = mean_mess_ratio - self._languages: CoherenceMatches = languages - self._has_sig_or_bom: bool = has_sig_or_bom - self._unicode_ranges: list[str] | None = None - - self._leaves: list[CharsetMatch] = [] - self._mean_coherence_ratio: float = 0.0 - - self._output_payload: bytes | None = None - self._output_encoding: str | None = None - - self._string: str | None = decoded_payload - - self._preemptive_declaration: str | None = preemptive_declaration - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CharsetMatch): - if isinstance(other, str): - return iana_name(other) == self.encoding - return False - return self.encoding == other.encoding and self.fingerprint == other.fingerprint - - def __lt__(self, other: object) -> bool: - """ - Implemented to make sorted available upon CharsetMatches items. - """ - if not isinstance(other, CharsetMatch): - raise ValueError - - chaos_difference: float = abs(self.chaos - other.chaos) - coherence_difference: float = abs(self.coherence - other.coherence) - - # Below 1% difference --> Use Coherence - if chaos_difference < 0.01 and coherence_difference > 0.02: - return self.coherence > other.coherence - elif chaos_difference < 0.01 and coherence_difference <= 0.02: - # When having a difficult decision, use the result that decoded as many multi-byte as possible. - # preserve RAM usage! - if len(self._payload) >= TOO_BIG_SEQUENCE: - return self.chaos < other.chaos - return self.multi_byte_usage > other.multi_byte_usage - - return self.chaos < other.chaos - - @property - def multi_byte_usage(self) -> float: - return 1.0 - (len(str(self)) / len(self.raw)) - - def __str__(self) -> str: - # Lazy Str Loading - if self._string is None: - self._string = str(self._payload, self._encoding, "strict") - return self._string - - def __repr__(self) -> str: - return f"" - - def add_submatch(self, other: CharsetMatch) -> None: - if not isinstance(other, CharsetMatch) or other == self: - raise ValueError( - "Unable to add instance <{}> as a submatch of a CharsetMatch".format( - other.__class__ - ) - ) - - other._string = None # Unload RAM usage; dirty trick. - self._leaves.append(other) - - @property - def encoding(self) -> str: - return self._encoding - - @property - def encoding_aliases(self) -> list[str]: - """ - Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. - """ - also_known_as: list[str] = [] - for u, p in aliases.items(): - if self.encoding == u: - also_known_as.append(p) - elif self.encoding == p: - also_known_as.append(u) - return also_known_as - - @property - def bom(self) -> bool: - return self._has_sig_or_bom - - @property - def byte_order_mark(self) -> bool: - return self._has_sig_or_bom - - @property - def languages(self) -> list[str]: - """ - Return the complete list of possible languages found in decoded sequence. - Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. - """ - return [e[0] for e in self._languages] - - @property - def language(self) -> str: - """ - Most probable language found in decoded sequence. If none were detected or inferred, the property will return - "Unknown". - """ - if not self._languages: - # Trying to infer the language based on the given encoding - # Its either English or we should not pronounce ourselves in certain cases. - if "ascii" in self.could_be_from_charset: - return "English" - - # doing it there to avoid circular import - from charset_normalizer.cd import encoding_languages, mb_encoding_languages - - languages = ( - mb_encoding_languages(self.encoding) - if is_multi_byte_encoding(self.encoding) - else encoding_languages(self.encoding) - ) - - if len(languages) == 0 or "Latin Based" in languages: - return "Unknown" - - return languages[0] - - return self._languages[0][0] - - @property - def chaos(self) -> float: - return self._mean_mess_ratio - - @property - def coherence(self) -> float: - if not self._languages: - return 0.0 - return self._languages[0][1] - - @property - def percent_chaos(self) -> float: - return round(self.chaos * 100, ndigits=3) - - @property - def percent_coherence(self) -> float: - return round(self.coherence * 100, ndigits=3) - - @property - def raw(self) -> bytes: - """ - Original untouched bytes. - """ - return self._payload - - @property - def submatch(self) -> list[CharsetMatch]: - return self._leaves - - @property - def has_submatch(self) -> bool: - return len(self._leaves) > 0 - - @property - def alphabets(self) -> list[str]: - if self._unicode_ranges is not None: - return self._unicode_ranges - # list detected ranges - detected_ranges: list[str | None] = [unicode_range(char) for char in str(self)] - # filter and sort - self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) - return self._unicode_ranges - - @property - def could_be_from_charset(self) -> list[str]: - """ - The complete list of encoding that output the exact SAME str result and therefore could be the originating - encoding. - This list does include the encoding available in property 'encoding'. - """ - return [self._encoding] + [m.encoding for m in self._leaves] - - def output(self, encoding: str = "utf_8") -> bytes: - """ - Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. - Any errors will be simply ignored by the encoder NOT replaced. - """ - if self._output_encoding is None or self._output_encoding != encoding: - self._output_encoding = encoding - decoded_string = str(self) - if ( - self._preemptive_declaration is not None - and self._preemptive_declaration.lower() - not in ["utf-8", "utf8", "utf_8"] - ): - patched_header = sub( - RE_POSSIBLE_ENCODING_INDICATION, - lambda m: m.string[m.span()[0] : m.span()[1]].replace( - m.groups()[0], - iana_name(self._output_encoding).replace("_", "-"), # type: ignore[arg-type] - ), - decoded_string[:8192], - count=1, - ) - - decoded_string = patched_header + decoded_string[8192:] - - self._output_payload = decoded_string.encode(encoding, "replace") - - return self._output_payload # type: ignore - - @property - def fingerprint(self) -> str: - """ - Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one. - """ - return sha256(self.output()).hexdigest() - - -class CharsetMatches: - """ - Container with every CharsetMatch items ordered by default from most probable to the less one. - Act like a list(iterable) but does not implements all related methods. - """ - - def __init__(self, results: list[CharsetMatch] | None = None): - self._results: list[CharsetMatch] = sorted(results) if results else [] - - def __iter__(self) -> Iterator[CharsetMatch]: - yield from self._results - - def __getitem__(self, item: int | str) -> CharsetMatch: - """ - Retrieve a single item either by its position or encoding name (alias may be used here). - Raise KeyError upon invalid index or encoding not present in results. - """ - if isinstance(item, int): - return self._results[item] - if isinstance(item, str): - item = iana_name(item, False) - for result in self._results: - if item in result.could_be_from_charset: - return result - raise KeyError - - def __len__(self) -> int: - return len(self._results) - - def __bool__(self) -> bool: - return len(self._results) > 0 - - def append(self, item: CharsetMatch) -> None: - """ - Insert a single match. Will be inserted accordingly to preserve sort. - Can be inserted as a submatch. - """ - if not isinstance(item, CharsetMatch): - raise ValueError( - "Cannot append instance '{}' to CharsetMatches".format( - str(item.__class__) - ) - ) - # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) - if len(item.raw) < TOO_BIG_SEQUENCE: - for match in self._results: - if match.fingerprint == item.fingerprint and match.chaos == item.chaos: - match.add_submatch(item) - return - self._results.append(item) - self._results = sorted(self._results) - - def best(self) -> CharsetMatch | None: - """ - Simply return the first match. Strict equivalent to matches[0]. - """ - if not self._results: - return None - return self._results[0] - - def first(self) -> CharsetMatch | None: - """ - Redundant method, call the method best(). Kept for BC reasons. - """ - return self.best() - - -CoherenceMatch = Tuple[str, float] -CoherenceMatches = List[CoherenceMatch] - - -class CliDetectionResult: - def __init__( - self, - path: str, - encoding: str | None, - encoding_aliases: list[str], - alternative_encodings: list[str], - language: str, - alphabets: list[str], - has_sig_or_bom: bool, - chaos: float, - coherence: float, - unicode_path: str | None, - is_preferred: bool, - ): - self.path: str = path - self.unicode_path: str | None = unicode_path - self.encoding: str | None = encoding - self.encoding_aliases: list[str] = encoding_aliases - self.alternative_encodings: list[str] = alternative_encodings - self.language: str = language - self.alphabets: list[str] = alphabets - self.has_sig_or_bom: bool = has_sig_or_bom - self.chaos: float = chaos - self.coherence: float = coherence - self.is_preferred: bool = is_preferred - - @property - def __dict__(self) -> dict[str, Any]: # type: ignore - return { - "path": self.path, - "encoding": self.encoding, - "encoding_aliases": self.encoding_aliases, - "alternative_encodings": self.alternative_encodings, - "language": self.language, - "alphabets": self.alphabets, - "has_sig_or_bom": self.has_sig_or_bom, - "chaos": self.chaos, - "coherence": self.coherence, - "unicode_path": self.unicode_path, - "is_preferred": self.is_preferred, - } - - def to_json(self) -> str: - return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/py.typed b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/utils.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/utils.py deleted file mode 100644 index 6bf0384..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/utils.py +++ /dev/null @@ -1,414 +0,0 @@ -from __future__ import annotations - -import importlib -import logging -import unicodedata -from codecs import IncrementalDecoder -from encodings.aliases import aliases -from functools import lru_cache -from re import findall -from typing import Generator - -from _multibytecodec import ( # type: ignore[import-not-found,import] - MultibyteIncrementalDecoder, -) - -from .constant import ( - ENCODING_MARKS, - IANA_SUPPORTED_SIMILAR, - RE_POSSIBLE_ENCODING_INDICATION, - UNICODE_RANGES_COMBINED, - UNICODE_SECONDARY_RANGE_KEYWORD, - UTF8_MAXIMAL_ALLOCATION, - COMMON_CJK_CHARACTERS, -) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_accentuated(character: str) -> bool: - try: - description: str = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - return ( - "WITH GRAVE" in description - or "WITH ACUTE" in description - or "WITH CEDILLA" in description - or "WITH DIAERESIS" in description - or "WITH CIRCUMFLEX" in description - or "WITH TILDE" in description - or "WITH MACRON" in description - or "WITH RING ABOVE" in description - ) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def remove_accent(character: str) -> str: - decomposed: str = unicodedata.decomposition(character) - if not decomposed: - return character - - codes: list[str] = decomposed.split(" ") - - return chr(int(codes[0], 16)) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def unicode_range(character: str) -> str | None: - """ - Retrieve the Unicode range official name from a single character. - """ - character_ord: int = ord(character) - - for range_name, ord_range in UNICODE_RANGES_COMBINED.items(): - if character_ord in ord_range: - return range_name - - return None - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_latin(character: str) -> bool: - try: - description: str = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - return "LATIN" in description - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_punctuation(character: str) -> bool: - character_category: str = unicodedata.category(character) - - if "P" in character_category: - return True - - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Punctuation" in character_range - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_symbol(character: str) -> bool: - character_category: str = unicodedata.category(character) - - if "S" in character_category or "N" in character_category: - return True - - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Forms" in character_range and character_category != "Lo" - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_emoticon(character: str) -> bool: - character_range: str | None = unicode_range(character) - - if character_range is None: - return False - - return "Emoticons" in character_range or "Pictographs" in character_range - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_separator(character: str) -> bool: - if character.isspace() or character in {"|", "+", "<", ">"}: - return True - - character_category: str = unicodedata.category(character) - - return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_case_variable(character: str) -> bool: - return character.islower() != character.isupper() - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_cjk(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "CJK" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_hiragana(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "HIRAGANA" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_katakana(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "KATAKANA" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_hangul(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "HANGUL" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_thai(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "THAI" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_arabic(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "ARABIC" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_arabic_isolated_form(character: str) -> bool: - try: - character_name = unicodedata.name(character) - except ValueError: # Defensive: unicode database outdated? - return False - - return "ARABIC" in character_name and "ISOLATED FORM" in character_name - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_cjk_uncommon(character: str) -> bool: - return character not in COMMON_CJK_CHARACTERS - - -@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) -def is_unicode_range_secondary(range_name: str) -> bool: - return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) - - -@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) -def is_unprintable(character: str) -> bool: - return ( - character.isspace() is False # includes \n \t \r \v - and character.isprintable() is False - and character != "\x1a" # Why? Its the ASCII substitute character. - and character != "\ufeff" # bug discovered in Python, - # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. - ) - - -def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> str | None: - """ - Extract using ASCII-only decoder any specified encoding in the first n-bytes. - """ - if not isinstance(sequence, bytes): - raise TypeError - - seq_len: int = len(sequence) - - results: list[str] = findall( - RE_POSSIBLE_ENCODING_INDICATION, - sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), - ) - - if len(results) == 0: - return None - - for specified_encoding in results: - specified_encoding = specified_encoding.lower().replace("-", "_") - - encoding_alias: str - encoding_iana: str - - for encoding_alias, encoding_iana in aliases.items(): - if encoding_alias == specified_encoding: - return encoding_iana - if encoding_iana == specified_encoding: - return encoding_iana - - return None - - -@lru_cache(maxsize=128) -def is_multi_byte_encoding(name: str) -> bool: - """ - Verify is a specific encoding is a multi byte one based on it IANA name - """ - return name in { - "utf_8", - "utf_8_sig", - "utf_16", - "utf_16_be", - "utf_16_le", - "utf_32", - "utf_32_le", - "utf_32_be", - "utf_7", - } or issubclass( - importlib.import_module(f"encodings.{name}").IncrementalDecoder, - MultibyteIncrementalDecoder, - ) - - -def identify_sig_or_bom(sequence: bytes) -> tuple[str | None, bytes]: - """ - Identify and extract SIG/BOM in given sequence. - """ - - for iana_encoding in ENCODING_MARKS: - marks: bytes | list[bytes] = ENCODING_MARKS[iana_encoding] - - if isinstance(marks, bytes): - marks = [marks] - - for mark in marks: - if sequence.startswith(mark): - return iana_encoding, mark - - return None, b"" - - -def should_strip_sig_or_bom(iana_encoding: str) -> bool: - return iana_encoding not in {"utf_16", "utf_32"} - - -def iana_name(cp_name: str, strict: bool = True) -> str: - """Returns the Python normalized encoding name (Not the IANA official name).""" - cp_name = cp_name.lower().replace("-", "_") - - encoding_alias: str - encoding_iana: str - - for encoding_alias, encoding_iana in aliases.items(): - if cp_name in [encoding_alias, encoding_iana]: - return encoding_iana - - if strict: - raise ValueError(f"Unable to retrieve IANA for '{cp_name}'") - - return cp_name - - -def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: - if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): - return 0.0 - - decoder_a = importlib.import_module(f"encodings.{iana_name_a}").IncrementalDecoder - decoder_b = importlib.import_module(f"encodings.{iana_name_b}").IncrementalDecoder - - id_a: IncrementalDecoder = decoder_a(errors="ignore") - id_b: IncrementalDecoder = decoder_b(errors="ignore") - - character_match_count: int = 0 - - for i in range(255): - to_be_decoded: bytes = bytes([i]) - if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): - character_match_count += 1 - - return character_match_count / 254 - - -def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: - """ - Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using - the function cp_similarity. - """ - return ( - iana_name_a in IANA_SUPPORTED_SIMILAR - and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] - ) - - -def set_logging_handler( - name: str = "charset_normalizer", - level: int = logging.INFO, - format_string: str = "%(asctime)s | %(levelname)s | %(message)s", -) -> None: - logger = logging.getLogger(name) - logger.setLevel(level) - - handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter(format_string)) - logger.addHandler(handler) - - -def cut_sequence_chunks( - sequences: bytes, - encoding_iana: str, - offsets: range, - chunk_size: int, - bom_or_sig_available: bool, - strip_sig_or_bom: bool, - sig_payload: bytes, - is_multi_byte_decoder: bool, - decoded_payload: str | None = None, -) -> Generator[str, None, None]: - if decoded_payload and is_multi_byte_decoder is False: - for i in offsets: - chunk = decoded_payload[i : i + chunk_size] - if not chunk: - break - yield chunk - else: - for i in offsets: - chunk_end = i + chunk_size - if chunk_end > len(sequences) + 8: - continue - - cut_sequence = sequences[i : i + chunk_size] - - if bom_or_sig_available and strip_sig_or_bom is False: - cut_sequence = sig_payload + cut_sequence - - chunk = cut_sequence.decode( - encoding_iana, - errors="ignore" if is_multi_byte_decoder else "strict", - ) - - # multi-byte bad cutting detector and adjustment - # not the cleanest way to perform that fix but clever enough for now. - if is_multi_byte_decoder and i > 0: - chunk_partial_size_chk: int = min(chunk_size, 16) - - if ( - decoded_payload - and chunk[:chunk_partial_size_chk] not in decoded_payload - ): - for j in range(i, i - 4, -1): - cut_sequence = sequences[j:chunk_end] - - if bom_or_sig_available and strip_sig_or_bom is False: - cut_sequence = sig_payload + cut_sequence - - chunk = cut_sequence.decode(encoding_iana, errors="ignore") - - if chunk[:chunk_partial_size_chk] in decoded_payload: - break - - yield chunk diff --git a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/version.py b/backend/venv39/lib/python3.9/site-packages/charset_normalizer/version.py deleted file mode 100644 index c843e53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/charset_normalizer/version.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -Expose version -""" - -from __future__ import annotations - -__version__ = "3.4.4" -VERSION = __version__.split(".") diff --git a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt b/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt deleted file mode 100644 index d12a849..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2014 Pallets - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA deleted file mode 100644 index 366d1a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/METADATA +++ /dev/null @@ -1,74 +0,0 @@ -Metadata-Version: 2.3 -Name: click -Version: 8.1.8 -Summary: Composable command line interface toolkit -Maintainer-email: Pallets -Requires-Python: >=3.7 -Description-Content-Type: text/markdown -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Typing :: Typed -Requires-Dist: colorama; platform_system == 'Windows' -Requires-Dist: importlib-metadata; python_version < '3.8' -Project-URL: Changes, https://click.palletsprojects.com/changes/ -Project-URL: Chat, https://discord.gg/pallets -Project-URL: Documentation, https://click.palletsprojects.com/ -Project-URL: Donate, https://palletsprojects.com/donate -Project-URL: Source, https://github.com/pallets/click/ - -# $ click_ - -Click is a Python package for creating beautiful command line interfaces -in a composable way with as little code as necessary. It's the "Command -Line Interface Creation Kit". It's highly configurable but comes with -sensible defaults out of the box. - -It aims to make the process of writing command line tools quick and fun -while also preventing any frustration caused by the inability to -implement an intended CLI API. - -Click in three points: - -- Arbitrary nesting of commands -- Automatic help page generation -- Supports lazy loading of subcommands at runtime - - -## A Simple Example - -```python -import click - -@click.command() -@click.option("--count", default=1, help="Number of greetings.") -@click.option("--name", prompt="Your name", help="The person to greet.") -def hello(count, name): - """Simple program that greets NAME for a total of COUNT times.""" - for _ in range(count): - click.echo(f"Hello, {name}!") - -if __name__ == '__main__': - hello() -``` - -``` -$ python hello.py --count=3 -Your name: Click -Hello, Click! -Hello, Click! -Hello, Click! -``` - - -## Donate - -The Pallets organization develops and supports Click and other popular -packages. In order to grow the community of contributors and users, and -allow the maintainers to devote more time to the projects, [please -donate today][]. - -[please donate today]: https://palletsprojects.com/donate - diff --git a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD deleted file mode 100644 index dbd0ed0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/RECORD +++ /dev/null @@ -1,38 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/_termui_impl.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/_textwrap.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/_winconsole.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/core.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/decorators.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/formatting.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/globals.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/parser.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/shell_completion.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/termui.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/testing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/click/utils.cpython-39.pyc,, -click-8.1.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -click-8.1.8.dist-info/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 -click-8.1.8.dist-info/METADATA,sha256=WJtQ6uGS2ybLfvUE4vC0XIhIBr4yFGwjrMBR2fiCQ-Q,2263 -click-8.1.8.dist-info/RECORD,, -click-8.1.8.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 -click/__init__.py,sha256=j1DJeCbga4ribkv5uyvIAzI0oFN13fW9mevDKShFelo,3188 -click/_compat.py,sha256=IGKh_J5QdfKELitnRfTGHneejWxoCw_NX9tfMbdcg3w,18730 -click/_termui_impl.py,sha256=a5z7I9gOFeMmu7Gb6_RPyQ8GPuVP1EeblixcWSPSQPk,24783 -click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 -click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 -click/core.py,sha256=Q1nEVdctZwvIPOlt4vfHko0TYnHCeE40UEEul8Wpyvs,114748 -click/decorators.py,sha256=7t6F-QWowtLh6F_6l-4YV4Y4yNTcqFQEu9i37zIz68s,18925 -click/exceptions.py,sha256=V7zDT6emqJ8iNl0kF1P5kpFmLMWQ1T1L7aNNKM4YR0w,9600 -click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 -click/globals.py,sha256=cuJ6Bbo073lgEEmhjr394PeM-QFmXM-Ci-wmfsd7H5g,1954 -click/parser.py,sha256=h4sndcpF5OHrZQN8vD8IWb5OByvW7ABbhRToxovrqS8,19067 -click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -click/shell_completion.py,sha256=TR0dXEGcvWb9Eo3aaQEXGhnvNS3FF4H4QcuLnvAvYo4,18636 -click/termui.py,sha256=dLxiS70UOvIYBda_nEEZaPAFOVDVmRs1sEPMuLDowQo,28310 -click/testing.py,sha256=3RA8anCf7TZ8-5RAF5it2Te-aWXBAL5VLasQnMiC2ZQ,16282 -click/types.py,sha256=BD5Qqq4h-8kawBmOIzJlmq4xzThAf4wCvaOLZSBDNx0,36422 -click/utils.py,sha256=ce-IrO9ilII76LGkU354pOdHbepM8UftfNH7SfMU_28,20330 diff --git a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL deleted file mode 100644 index e3c6fee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click-8.1.8.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.10.1 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/click/__init__.py b/backend/venv39/lib/python3.9/site-packages/click/__init__.py deleted file mode 100644 index 2610d0e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/__init__.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -Click is a simple Python module inspired by the stdlib optparse to make -writing command line scripts fun. Unlike other modules, it's based -around a simple API that does not come with too much magic and is -composable. -""" - -from .core import Argument as Argument -from .core import BaseCommand as BaseCommand -from .core import Command as Command -from .core import CommandCollection as CommandCollection -from .core import Context as Context -from .core import Group as Group -from .core import MultiCommand as MultiCommand -from .core import Option as Option -from .core import Parameter as Parameter -from .decorators import argument as argument -from .decorators import command as command -from .decorators import confirmation_option as confirmation_option -from .decorators import group as group -from .decorators import help_option as help_option -from .decorators import HelpOption as HelpOption -from .decorators import make_pass_decorator as make_pass_decorator -from .decorators import option as option -from .decorators import pass_context as pass_context -from .decorators import pass_obj as pass_obj -from .decorators import password_option as password_option -from .decorators import version_option as version_option -from .exceptions import Abort as Abort -from .exceptions import BadArgumentUsage as BadArgumentUsage -from .exceptions import BadOptionUsage as BadOptionUsage -from .exceptions import BadParameter as BadParameter -from .exceptions import ClickException as ClickException -from .exceptions import FileError as FileError -from .exceptions import MissingParameter as MissingParameter -from .exceptions import NoSuchOption as NoSuchOption -from .exceptions import UsageError as UsageError -from .formatting import HelpFormatter as HelpFormatter -from .formatting import wrap_text as wrap_text -from .globals import get_current_context as get_current_context -from .parser import OptionParser as OptionParser -from .termui import clear as clear -from .termui import confirm as confirm -from .termui import echo_via_pager as echo_via_pager -from .termui import edit as edit -from .termui import getchar as getchar -from .termui import launch as launch -from .termui import pause as pause -from .termui import progressbar as progressbar -from .termui import prompt as prompt -from .termui import secho as secho -from .termui import style as style -from .termui import unstyle as unstyle -from .types import BOOL as BOOL -from .types import Choice as Choice -from .types import DateTime as DateTime -from .types import File as File -from .types import FLOAT as FLOAT -from .types import FloatRange as FloatRange -from .types import INT as INT -from .types import IntRange as IntRange -from .types import ParamType as ParamType -from .types import Path as Path -from .types import STRING as STRING -from .types import Tuple as Tuple -from .types import UNPROCESSED as UNPROCESSED -from .types import UUID as UUID -from .utils import echo as echo -from .utils import format_filename as format_filename -from .utils import get_app_dir as get_app_dir -from .utils import get_binary_stream as get_binary_stream -from .utils import get_text_stream as get_text_stream -from .utils import open_file as open_file - -__version__ = "8.1.8" diff --git a/backend/venv39/lib/python3.9/site-packages/click/_compat.py b/backend/venv39/lib/python3.9/site-packages/click/_compat.py deleted file mode 100644 index 9153d15..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/_compat.py +++ /dev/null @@ -1,623 +0,0 @@ -import codecs -import io -import os -import re -import sys -import typing as t -from weakref import WeakKeyDictionary - -CYGWIN = sys.platform.startswith("cygwin") -WIN = sys.platform.startswith("win") -auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None -_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") - - -def _make_text_stream( - stream: t.BinaryIO, - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if encoding is None: - encoding = get_best_encoding(stream) - if errors is None: - errors = "replace" - return _NonClosingTextIOWrapper( - stream, - encoding, - errors, - line_buffering=True, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def is_ascii_encoding(encoding: str) -> bool: - """Checks if a given encoding is ascii.""" - try: - return codecs.lookup(encoding).name == "ascii" - except LookupError: - return False - - -def get_best_encoding(stream: t.IO[t.Any]) -> str: - """Returns the default stream encoding if not found.""" - rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() - if is_ascii_encoding(rv): - return "utf-8" - return rv - - -class _NonClosingTextIOWrapper(io.TextIOWrapper): - def __init__( - self, - stream: t.BinaryIO, - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, - force_writable: bool = False, - **extra: t.Any, - ) -> None: - self._stream = stream = t.cast( - t.BinaryIO, _FixupStream(stream, force_readable, force_writable) - ) - super().__init__(stream, encoding, errors, **extra) - - def __del__(self) -> None: - try: - self.detach() - except Exception: - pass - - def isatty(self) -> bool: - # https://bitbucket.org/pypy/pypy/issue/1803 - return self._stream.isatty() - - -class _FixupStream: - """The new io interface needs more from streams than streams - traditionally implement. As such, this fix-up code is necessary in - some circumstances. - - The forcing of readable and writable flags are there because some tools - put badly patched objects on sys (one such offender are certain version - of jupyter notebook). - """ - - def __init__( - self, - stream: t.BinaryIO, - force_readable: bool = False, - force_writable: bool = False, - ): - self._stream = stream - self._force_readable = force_readable - self._force_writable = force_writable - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._stream, name) - - def read1(self, size: int) -> bytes: - f = getattr(self._stream, "read1", None) - - if f is not None: - return t.cast(bytes, f(size)) - - return self._stream.read(size) - - def readable(self) -> bool: - if self._force_readable: - return True - x = getattr(self._stream, "readable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.read(0) - except Exception: - return False - return True - - def writable(self) -> bool: - if self._force_writable: - return True - x = getattr(self._stream, "writable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.write("") # type: ignore - except Exception: - try: - self._stream.write(b"") - except Exception: - return False - return True - - def seekable(self) -> bool: - x = getattr(self._stream, "seekable", None) - if x is not None: - return t.cast(bool, x()) - try: - self._stream.seek(self._stream.tell()) - except Exception: - return False - return True - - -def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - return isinstance(stream.read(0), bytes) - except Exception: - return default - # This happens in some cases where the stream was already - # closed. In this case, we assume the default. - - -def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: - try: - stream.write(b"") - except Exception: - try: - stream.write("") - return False - except Exception: - pass - return default - return True - - -def _find_binary_reader(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_reader(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_reader(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _find_binary_writer(stream: t.IO[t.Any]) -> t.Optional[t.BinaryIO]: - # We need to figure out if the given stream is already binary. - # This can happen because the official docs recommend detaching - # the streams to get binary streams. Some code might do this, so - # we need to deal with this case explicitly. - if _is_binary_writer(stream, False): - return t.cast(t.BinaryIO, stream) - - buf = getattr(stream, "buffer", None) - - # Same situation here; this time we assume that the buffer is - # actually binary in case it's closed. - if buf is not None and _is_binary_writer(buf, True): - return t.cast(t.BinaryIO, buf) - - return None - - -def _stream_is_misconfigured(stream: t.TextIO) -> bool: - """A stream is misconfigured if its encoding is ASCII.""" - # If the stream does not have an encoding set, we assume it's set - # to ASCII. This appears to happen in certain unittest - # environments. It's not quite clear what the correct behavior is - # but this at least will force Click to recover somehow. - return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") - - -def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: - """A stream attribute is compatible if it is equal to the - desired value or the desired value is unset and the attribute - has a value. - """ - stream_value = getattr(stream, attr, None) - return stream_value == value or (value is None and stream_value is not None) - - -def _is_compatible_text_stream( - stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] -) -> bool: - """Check if a stream's encoding and errors attributes are - compatible with the desired values. - """ - return _is_compat_stream_attr( - stream, "encoding", encoding - ) and _is_compat_stream_attr(stream, "errors", errors) - - -def _force_correct_text_stream( - text_stream: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - is_binary: t.Callable[[t.IO[t.Any], bool], bool], - find_binary: t.Callable[[t.IO[t.Any]], t.Optional[t.BinaryIO]], - force_readable: bool = False, - force_writable: bool = False, -) -> t.TextIO: - if is_binary(text_stream, False): - binary_reader = t.cast(t.BinaryIO, text_stream) - else: - text_stream = t.cast(t.TextIO, text_stream) - # If the stream looks compatible, and won't default to a - # misconfigured ascii encoding, return it as-is. - if _is_compatible_text_stream(text_stream, encoding, errors) and not ( - encoding is None and _stream_is_misconfigured(text_stream) - ): - return text_stream - - # Otherwise, get the underlying binary reader. - possible_binary_reader = find_binary(text_stream) - - # If that's not possible, silently use the original reader - # and get mojibake instead of exceptions. - if possible_binary_reader is None: - return text_stream - - binary_reader = possible_binary_reader - - # Default errors to replace instead of strict in order to get - # something that works. - if errors is None: - errors = "replace" - - # Wrap the binary stream in a text stream with the correct - # encoding parameters. - return _make_text_stream( - binary_reader, - encoding, - errors, - force_readable=force_readable, - force_writable=force_writable, - ) - - -def _force_correct_text_reader( - text_reader: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - force_readable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_reader, - encoding, - errors, - _is_binary_reader, - _find_binary_reader, - force_readable=force_readable, - ) - - -def _force_correct_text_writer( - text_writer: t.IO[t.Any], - encoding: t.Optional[str], - errors: t.Optional[str], - force_writable: bool = False, -) -> t.TextIO: - return _force_correct_text_stream( - text_writer, - encoding, - errors, - _is_binary_writer, - _find_binary_writer, - force_writable=force_writable, - ) - - -def get_binary_stdin() -> t.BinaryIO: - reader = _find_binary_reader(sys.stdin) - if reader is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdin.") - return reader - - -def get_binary_stdout() -> t.BinaryIO: - writer = _find_binary_writer(sys.stdout) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stdout.") - return writer - - -def get_binary_stderr() -> t.BinaryIO: - writer = _find_binary_writer(sys.stderr) - if writer is None: - raise RuntimeError("Was not able to determine binary stream for sys.stderr.") - return writer - - -def get_text_stdin( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdin, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) - - -def get_text_stdout( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stdout, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) - - -def get_text_stderr( - encoding: t.Optional[str] = None, errors: t.Optional[str] = None -) -> t.TextIO: - rv = _get_windows_console_stream(sys.stderr, encoding, errors) - if rv is not None: - return rv - return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) - - -def _wrap_io_open( - file: t.Union[str, "os.PathLike[str]", int], - mode: str, - encoding: t.Optional[str], - errors: t.Optional[str], -) -> t.IO[t.Any]: - """Handles not passing ``encoding`` and ``errors`` in binary mode.""" - if "b" in mode: - return open(file, mode) - - return open(file, mode, encoding=encoding, errors=errors) - - -def open_stream( - filename: "t.Union[str, os.PathLike[str]]", - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - atomic: bool = False, -) -> t.Tuple[t.IO[t.Any], bool]: - binary = "b" in mode - filename = os.fspath(filename) - - # Standard streams first. These are simple because they ignore the - # atomic flag. Use fsdecode to handle Path("-"). - if os.fsdecode(filename) == "-": - if any(m in mode for m in ["w", "a", "x"]): - if binary: - return get_binary_stdout(), False - return get_text_stdout(encoding=encoding, errors=errors), False - if binary: - return get_binary_stdin(), False - return get_text_stdin(encoding=encoding, errors=errors), False - - # Non-atomic writes directly go out through the regular open functions. - if not atomic: - return _wrap_io_open(filename, mode, encoding, errors), True - - # Some usability stuff for atomic writes - if "a" in mode: - raise ValueError( - "Appending to an existing file is not supported, because that" - " would involve an expensive `copy`-operation to a temporary" - " file. Open the file in normal `w`-mode and copy explicitly" - " if that's what you're after." - ) - if "x" in mode: - raise ValueError("Use the `overwrite`-parameter instead.") - if "w" not in mode: - raise ValueError("Atomic writes only make sense with `w`-mode.") - - # Atomic writes are more complicated. They work by opening a file - # as a proxy in the same folder and then using the fdopen - # functionality to wrap it in a Python file. Then we wrap it in an - # atomic file that moves the file over on close. - import errno - import random - - try: - perm: t.Optional[int] = os.stat(filename).st_mode - except OSError: - perm = None - - flags = os.O_RDWR | os.O_CREAT | os.O_EXCL - - if binary: - flags |= getattr(os, "O_BINARY", 0) - - while True: - tmp_filename = os.path.join( - os.path.dirname(filename), - f".__atomic-write{random.randrange(1 << 32):08x}", - ) - try: - fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) - break - except OSError as e: - if e.errno == errno.EEXIST or ( - os.name == "nt" - and e.errno == errno.EACCES - and os.path.isdir(e.filename) - and os.access(e.filename, os.W_OK) - ): - continue - raise - - if perm is not None: - os.chmod(tmp_filename, perm) # in case perm includes bits in umask - - f = _wrap_io_open(fd, mode, encoding, errors) - af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) - return t.cast(t.IO[t.Any], af), True - - -class _AtomicFile: - def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: - self._f = f - self._tmp_filename = tmp_filename - self._real_filename = real_filename - self.closed = False - - @property - def name(self) -> str: - return self._real_filename - - def close(self, delete: bool = False) -> None: - if self.closed: - return - self._f.close() - os.replace(self._tmp_filename, self._real_filename) - self.closed = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._f, name) - - def __enter__(self) -> "_AtomicFile": - return self - - def __exit__(self, exc_type: t.Optional[t.Type[BaseException]], *_: t.Any) -> None: - self.close(delete=exc_type is not None) - - def __repr__(self) -> str: - return repr(self._f) - - -def strip_ansi(value: str) -> str: - return _ansi_re.sub("", value) - - -def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: - while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): - stream = stream._stream - - return stream.__class__.__module__.startswith("ipykernel.") - - -def should_strip_ansi( - stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None -) -> bool: - if color is None: - if stream is None: - stream = sys.stdin - return not isatty(stream) and not _is_jupyter_kernel_output(stream) - return not color - - -# On Windows, wrap the output streams with colorama to support ANSI -# color codes. -# NOTE: double check is needed so mypy does not analyze this on Linux -if sys.platform.startswith("win") and WIN: - from ._winconsole import _get_windows_console_stream - - def _get_argv_encoding() -> str: - import locale - - return locale.getpreferredencoding() - - _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def auto_wrap_for_ansi( - stream: t.TextIO, color: t.Optional[bool] = None - ) -> t.TextIO: - """Support ANSI color and style codes on Windows by wrapping a - stream with colorama. - """ - try: - cached = _ansi_stream_wrappers.get(stream) - except Exception: - cached = None - - if cached is not None: - return cached - - import colorama - - strip = should_strip_ansi(stream, color) - ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) - rv = t.cast(t.TextIO, ansi_wrapper.stream) - _write = rv.write - - def _safe_write(s): - try: - return _write(s) - except BaseException: - ansi_wrapper.reset_all() - raise - - rv.write = _safe_write - - try: - _ansi_stream_wrappers[stream] = rv - except Exception: - pass - - return rv - -else: - - def _get_argv_encoding() -> str: - return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() - - def _get_windows_console_stream( - f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] - ) -> t.Optional[t.TextIO]: - return None - - -def term_len(x: str) -> int: - return len(strip_ansi(x)) - - -def isatty(stream: t.IO[t.Any]) -> bool: - try: - return stream.isatty() - except Exception: - return False - - -def _make_cached_stream_func( - src_func: t.Callable[[], t.Optional[t.TextIO]], - wrapper_func: t.Callable[[], t.TextIO], -) -> t.Callable[[], t.Optional[t.TextIO]]: - cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() - - def func() -> t.Optional[t.TextIO]: - stream = src_func() - - if stream is None: - return None - - try: - rv = cache.get(stream) - except Exception: - rv = None - if rv is not None: - return rv - rv = wrapper_func() - try: - cache[stream] = rv - except Exception: - pass - return rv - - return func - - -_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) -_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) -_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) - - -binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { - "stdin": get_binary_stdin, - "stdout": get_binary_stdout, - "stderr": get_binary_stderr, -} - -text_streams: t.Mapping[ - str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] -] = { - "stdin": get_text_stdin, - "stdout": get_text_stdout, - "stderr": get_text_stderr, -} diff --git a/backend/venv39/lib/python3.9/site-packages/click/_termui_impl.py b/backend/venv39/lib/python3.9/site-packages/click/_termui_impl.py deleted file mode 100644 index ad9f8f6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/_termui_impl.py +++ /dev/null @@ -1,788 +0,0 @@ -""" -This module contains implementations for the termui module. To keep the -import time of Click down, some infrequently used functionality is -placed in this module and only imported as needed. -""" - -import contextlib -import math -import os -import sys -import time -import typing as t -from gettext import gettext as _ -from io import StringIO -from shutil import which -from types import TracebackType - -from ._compat import _default_text_stdout -from ._compat import CYGWIN -from ._compat import get_best_encoding -from ._compat import isatty -from ._compat import open_stream -from ._compat import strip_ansi -from ._compat import term_len -from ._compat import WIN -from .exceptions import ClickException -from .utils import echo - -V = t.TypeVar("V") - -if os.name == "nt": - BEFORE_BAR = "\r" - AFTER_BAR = "\n" -else: - BEFORE_BAR = "\r\033[?25l" - AFTER_BAR = "\033[?25h\n" - - -class ProgressBar(t.Generic[V]): - def __init__( - self, - iterable: t.Optional[t.Iterable[V]], - length: t.Optional[int] = None, - fill_char: str = "#", - empty_char: str = " ", - bar_template: str = "%(bar)s", - info_sep: str = " ", - show_eta: bool = True, - show_percent: t.Optional[bool] = None, - show_pos: bool = False, - item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, - label: t.Optional[str] = None, - file: t.Optional[t.TextIO] = None, - color: t.Optional[bool] = None, - update_min_steps: int = 1, - width: int = 30, - ) -> None: - self.fill_char = fill_char - self.empty_char = empty_char - self.bar_template = bar_template - self.info_sep = info_sep - self.show_eta = show_eta - self.show_percent = show_percent - self.show_pos = show_pos - self.item_show_func = item_show_func - self.label: str = label or "" - - if file is None: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - file = StringIO() - - self.file = file - self.color = color - self.update_min_steps = update_min_steps - self._completed_intervals = 0 - self.width: int = width - self.autowidth: bool = width == 0 - - if length is None: - from operator import length_hint - - length = length_hint(iterable, -1) - - if length == -1: - length = None - if iterable is None: - if length is None: - raise TypeError("iterable or length is required") - iterable = t.cast(t.Iterable[V], range(length)) - self.iter: t.Iterable[V] = iter(iterable) - self.length = length - self.pos = 0 - self.avg: t.List[float] = [] - self.last_eta: float - self.start: float - self.start = self.last_eta = time.time() - self.eta_known: bool = False - self.finished: bool = False - self.max_width: t.Optional[int] = None - self.entered: bool = False - self.current_item: t.Optional[V] = None - self.is_hidden: bool = not isatty(self.file) - self._last_line: t.Optional[str] = None - - def __enter__(self) -> "ProgressBar[V]": - self.entered = True - self.render_progress() - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self.render_finish() - - def __iter__(self) -> t.Iterator[V]: - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - self.render_progress() - return self.generator() - - def __next__(self) -> V: - # Iteration is defined in terms of a generator function, - # returned by iter(self); use that to define next(). This works - # because `self.iter` is an iterable consumed by that generator, - # so it is re-entry safe. Calling `next(self.generator())` - # twice works and does "what you want". - return next(iter(self)) - - def render_finish(self) -> None: - if self.is_hidden: - return - self.file.write(AFTER_BAR) - self.file.flush() - - @property - def pct(self) -> float: - if self.finished: - return 1.0 - return min(self.pos / (float(self.length or 1) or 1), 1.0) - - @property - def time_per_iteration(self) -> float: - if not self.avg: - return 0.0 - return sum(self.avg) / float(len(self.avg)) - - @property - def eta(self) -> float: - if self.length is not None and not self.finished: - return self.time_per_iteration * (self.length - self.pos) - return 0.0 - - def format_eta(self) -> str: - if self.eta_known: - t = int(self.eta) - seconds = t % 60 - t //= 60 - minutes = t % 60 - t //= 60 - hours = t % 24 - t //= 24 - if t > 0: - return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" - else: - return f"{hours:02}:{minutes:02}:{seconds:02}" - return "" - - def format_pos(self) -> str: - pos = str(self.pos) - if self.length is not None: - pos += f"/{self.length}" - return pos - - def format_pct(self) -> str: - return f"{int(self.pct * 100): 4}%"[1:] - - def format_bar(self) -> str: - if self.length is not None: - bar_length = int(self.pct * self.width) - bar = self.fill_char * bar_length - bar += self.empty_char * (self.width - bar_length) - elif self.finished: - bar = self.fill_char * self.width - else: - chars = list(self.empty_char * (self.width or 1)) - if self.time_per_iteration != 0: - chars[ - int( - (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) - * self.width - ) - ] = self.fill_char - bar = "".join(chars) - return bar - - def format_progress_line(self) -> str: - show_percent = self.show_percent - - info_bits = [] - if self.length is not None and show_percent is None: - show_percent = not self.show_pos - - if self.show_pos: - info_bits.append(self.format_pos()) - if show_percent: - info_bits.append(self.format_pct()) - if self.show_eta and self.eta_known and not self.finished: - info_bits.append(self.format_eta()) - if self.item_show_func is not None: - item_info = self.item_show_func(self.current_item) - if item_info is not None: - info_bits.append(item_info) - - return ( - self.bar_template - % { - "label": self.label, - "bar": self.format_bar(), - "info": self.info_sep.join(info_bits), - } - ).rstrip() - - def render_progress(self) -> None: - import shutil - - if self.is_hidden: - # Only output the label as it changes if the output is not a - # TTY. Use file=stderr if you expect to be piping stdout. - if self._last_line != self.label: - self._last_line = self.label - echo(self.label, file=self.file, color=self.color) - - return - - buf = [] - # Update width in case the terminal has been resized - if self.autowidth: - old_width = self.width - self.width = 0 - clutter_length = term_len(self.format_progress_line()) - new_width = max(0, shutil.get_terminal_size().columns - clutter_length) - if new_width < old_width: - buf.append(BEFORE_BAR) - buf.append(" " * self.max_width) # type: ignore - self.max_width = new_width - self.width = new_width - - clear_width = self.width - if self.max_width is not None: - clear_width = self.max_width - - buf.append(BEFORE_BAR) - line = self.format_progress_line() - line_len = term_len(line) - if self.max_width is None or self.max_width < line_len: - self.max_width = line_len - - buf.append(line) - buf.append(" " * (clear_width - line_len)) - line = "".join(buf) - # Render the line only if it changed. - - if line != self._last_line: - self._last_line = line - echo(line, file=self.file, color=self.color, nl=False) - self.file.flush() - - def make_step(self, n_steps: int) -> None: - self.pos += n_steps - if self.length is not None and self.pos >= self.length: - self.finished = True - - if (time.time() - self.last_eta) < 1.0: - return - - self.last_eta = time.time() - - # self.avg is a rolling list of length <= 7 of steps where steps are - # defined as time elapsed divided by the total progress through - # self.length. - if self.pos: - step = (time.time() - self.start) / self.pos - else: - step = time.time() - self.start - - self.avg = self.avg[-6:] + [step] - - self.eta_known = self.length is not None - - def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: - """Update the progress bar by advancing a specified number of - steps, and optionally set the ``current_item`` for this new - position. - - :param n_steps: Number of steps to advance. - :param current_item: Optional item to set as ``current_item`` - for the updated position. - - .. versionchanged:: 8.0 - Added the ``current_item`` optional parameter. - - .. versionchanged:: 8.0 - Only render when the number of steps meets the - ``update_min_steps`` threshold. - """ - if current_item is not None: - self.current_item = current_item - - self._completed_intervals += n_steps - - if self._completed_intervals >= self.update_min_steps: - self.make_step(self._completed_intervals) - self.render_progress() - self._completed_intervals = 0 - - def finish(self) -> None: - self.eta_known = False - self.current_item = None - self.finished = True - - def generator(self) -> t.Iterator[V]: - """Return a generator which yields the items added to the bar - during construction, and updates the progress bar *after* the - yielded block returns. - """ - # WARNING: the iterator interface for `ProgressBar` relies on - # this and only works because this is a simple generator which - # doesn't create or manage additional state. If this function - # changes, the impact should be evaluated both against - # `iter(bar)` and `next(bar)`. `next()` in particular may call - # `self.generator()` repeatedly, and this must remain safe in - # order for that interface to work. - if not self.entered: - raise RuntimeError("You need to use progress bars in a with block.") - - if self.is_hidden: - yield from self.iter - else: - for rv in self.iter: - self.current_item = rv - - # This allows show_item_func to be updated before the - # item is processed. Only trigger at the beginning of - # the update interval. - if self._completed_intervals == 0: - self.render_progress() - - yield rv - self.update(1) - - self.finish() - self.render_progress() - - -def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: - """Decide what method to use for paging through text.""" - stdout = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if stdout is None: - stdout = StringIO() - - if not isatty(sys.stdin) or not isatty(stdout): - return _nullpager(stdout, generator, color) - pager_cmd = (os.environ.get("PAGER", None) or "").strip() - if pager_cmd: - if WIN: - if _tempfilepager(generator, pager_cmd, color): - return - elif _pipepager(generator, pager_cmd, color): - return - if os.environ.get("TERM") in ("dumb", "emacs"): - return _nullpager(stdout, generator, color) - if (WIN or sys.platform.startswith("os2")) and _tempfilepager( - generator, "more", color - ): - return - if _pipepager(generator, "less", color): - return - - import tempfile - - fd, filename = tempfile.mkstemp() - os.close(fd) - try: - if _pipepager(generator, "more", color): - return - return _nullpager(stdout, generator, color) - finally: - os.unlink(filename) - - -def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> bool: - """Page through text by feeding it to another program. Invoking a - pager through this might support colors. - - Returns True if the command was found, False otherwise and thus another - pager should be attempted. - """ - cmd_absolute = which(cmd) - if cmd_absolute is None: - return False - - import subprocess - - env = dict(os.environ) - - # If we're piping to less we might support colors under the - # condition that - cmd_detail = cmd.rsplit("/", 1)[-1].split() - if color is None and cmd_detail[0] == "less": - less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" - if not less_flags: - env["LESS"] = "-R" - color = True - elif "r" in less_flags or "R" in less_flags: - color = True - - c = subprocess.Popen( - [cmd_absolute], - shell=True, - stdin=subprocess.PIPE, - env=env, - errors="replace", - text=True, - ) - assert c.stdin is not None - try: - for text in generator: - if not color: - text = strip_ansi(text) - - c.stdin.write(text) - except (OSError, KeyboardInterrupt): - pass - else: - c.stdin.close() - - # Less doesn't respect ^C, but catches it for its own UI purposes (aborting - # search or other commands inside less). - # - # That means when the user hits ^C, the parent process (click) terminates, - # but less is still alive, paging the output and messing up the terminal. - # - # If the user wants to make the pager exit on ^C, they should set - # `LESS='-K'`. It's not our decision to make. - while True: - try: - c.wait() - except KeyboardInterrupt: - pass - else: - break - - return True - - -def _tempfilepager( - generator: t.Iterable[str], - cmd: str, - color: t.Optional[bool], -) -> bool: - """Page through text by invoking a program on a temporary file. - - Returns True if the command was found, False otherwise and thus another - pager should be attempted. - """ - # Which is necessary for Windows, it is also recommended in the Popen docs. - cmd_absolute = which(cmd) - if cmd_absolute is None: - return False - - import subprocess - import tempfile - - fd, filename = tempfile.mkstemp() - # TODO: This never terminates if the passed generator never terminates. - text = "".join(generator) - if not color: - text = strip_ansi(text) - encoding = get_best_encoding(sys.stdout) - with open_stream(filename, "wb")[0] as f: - f.write(text.encode(encoding)) - try: - subprocess.call([cmd_absolute, filename]) - except OSError: - # Command not found - pass - finally: - os.close(fd) - os.unlink(filename) - - return True - - -def _nullpager( - stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] -) -> None: - """Simply print unformatted text. This is the ultimate fallback.""" - for text in generator: - if not color: - text = strip_ansi(text) - stream.write(text) - - -class Editor: - def __init__( - self, - editor: t.Optional[str] = None, - env: t.Optional[t.Mapping[str, str]] = None, - require_save: bool = True, - extension: str = ".txt", - ) -> None: - self.editor = editor - self.env = env - self.require_save = require_save - self.extension = extension - - def get_editor(self) -> str: - if self.editor is not None: - return self.editor - for key in "VISUAL", "EDITOR": - rv = os.environ.get(key) - if rv: - return rv - if WIN: - return "notepad" - for editor in "sensible-editor", "vim", "nano": - if which(editor) is not None: - return editor - return "vi" - - def edit_file(self, filename: str) -> None: - import subprocess - - editor = self.get_editor() - environ: t.Optional[t.Dict[str, str]] = None - - if self.env: - environ = os.environ.copy() - environ.update(self.env) - - try: - c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) - exit_code = c.wait() - if exit_code != 0: - raise ClickException( - _("{editor}: Editing failed").format(editor=editor) - ) - except OSError as e: - raise ClickException( - _("{editor}: Editing failed: {e}").format(editor=editor, e=e) - ) from e - - def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: - import tempfile - - if not text: - data = b"" - elif isinstance(text, (bytes, bytearray)): - data = text - else: - if text and not text.endswith("\n"): - text += "\n" - - if WIN: - data = text.replace("\n", "\r\n").encode("utf-8-sig") - else: - data = text.encode("utf-8") - - fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) - f: t.BinaryIO - - try: - with os.fdopen(fd, "wb") as f: - f.write(data) - - # If the filesystem resolution is 1 second, like Mac OS - # 10.12 Extended, or 2 seconds, like FAT32, and the editor - # closes very fast, require_save can fail. Set the modified - # time to be 2 seconds in the past to work around this. - os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) - # Depending on the resolution, the exact value might not be - # recorded, so get the new recorded value. - timestamp = os.path.getmtime(name) - - self.edit_file(name) - - if self.require_save and os.path.getmtime(name) == timestamp: - return None - - with open(name, "rb") as f: - rv = f.read() - - if isinstance(text, (bytes, bytearray)): - return rv - - return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore - finally: - os.unlink(name) - - -def open_url(url: str, wait: bool = False, locate: bool = False) -> int: - import subprocess - - def _unquote_file(url: str) -> str: - from urllib.parse import unquote - - if url.startswith("file://"): - url = unquote(url[7:]) - - return url - - if sys.platform == "darwin": - args = ["open"] - if wait: - args.append("-W") - if locate: - args.append("-R") - args.append(_unquote_file(url)) - null = open("/dev/null", "w") - try: - return subprocess.Popen(args, stderr=null).wait() - finally: - null.close() - elif WIN: - if locate: - url = _unquote_file(url) - args = ["explorer", f"/select,{url}"] - else: - args = ["start"] - if wait: - args.append("/WAIT") - args.append("") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - elif CYGWIN: - if locate: - url = _unquote_file(url) - args = ["cygstart", os.path.dirname(url)] - else: - args = ["cygstart"] - if wait: - args.append("-w") - args.append(url) - try: - return subprocess.call(args) - except OSError: - # Command not found - return 127 - - try: - if locate: - url = os.path.dirname(_unquote_file(url)) or "." - else: - url = _unquote_file(url) - c = subprocess.Popen(["xdg-open", url]) - if wait: - return c.wait() - return 0 - except OSError: - if url.startswith(("http://", "https://")) and not locate and not wait: - import webbrowser - - webbrowser.open(url) - return 0 - return 1 - - -def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: - if ch == "\x03": - raise KeyboardInterrupt() - - if ch == "\x04" and not WIN: # Unix-like, Ctrl+D - raise EOFError() - - if ch == "\x1a" and WIN: # Windows, Ctrl+Z - raise EOFError() - - return None - - -if WIN: - import msvcrt - - @contextlib.contextmanager - def raw_terminal() -> t.Iterator[int]: - yield -1 - - def getchar(echo: bool) -> str: - # The function `getch` will return a bytes object corresponding to - # the pressed character. Since Windows 10 build 1803, it will also - # return \x00 when called a second time after pressing a regular key. - # - # `getwch` does not share this probably-bugged behavior. Moreover, it - # returns a Unicode object by default, which is what we want. - # - # Either of these functions will return \x00 or \xe0 to indicate - # a special key, and you need to call the same function again to get - # the "rest" of the code. The fun part is that \u00e0 is - # "latin small letter a with grave", so if you type that on a French - # keyboard, you _also_ get a \xe0. - # E.g., consider the Up arrow. This returns \xe0 and then \x48. The - # resulting Unicode string reads as "a with grave" + "capital H". - # This is indistinguishable from when the user actually types - # "a with grave" and then "capital H". - # - # When \xe0 is returned, we assume it's part of a special-key sequence - # and call `getwch` again, but that means that when the user types - # the \u00e0 character, `getchar` doesn't return until a second - # character is typed. - # The alternative is returning immediately, but that would mess up - # cross-platform handling of arrow keys and others that start with - # \xe0. Another option is using `getch`, but then we can't reliably - # read non-ASCII characters, because return values of `getch` are - # limited to the current 8-bit codepage. - # - # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` - # is doing the right thing in more situations than with `getch`. - func: t.Callable[[], str] - - if echo: - func = msvcrt.getwche # type: ignore - else: - func = msvcrt.getwch # type: ignore - - rv = func() - - if rv in ("\x00", "\xe0"): - # \x00 and \xe0 are control characters that indicate special key, - # see above. - rv += func() - - _translate_ch_to_exc(rv) - return rv - -else: - import termios - import tty - - @contextlib.contextmanager - def raw_terminal() -> t.Iterator[int]: - f: t.Optional[t.TextIO] - fd: int - - if not isatty(sys.stdin): - f = open("/dev/tty") - fd = f.fileno() - else: - fd = sys.stdin.fileno() - f = None - - try: - old_settings = termios.tcgetattr(fd) - - try: - tty.setraw(fd) - yield fd - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - sys.stdout.flush() - - if f is not None: - f.close() - except termios.error: - pass - - def getchar(echo: bool) -> str: - with raw_terminal() as fd: - ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") - - if echo and isatty(sys.stdout): - sys.stdout.write(ch) - - _translate_ch_to_exc(ch) - return ch diff --git a/backend/venv39/lib/python3.9/site-packages/click/_textwrap.py b/backend/venv39/lib/python3.9/site-packages/click/_textwrap.py deleted file mode 100644 index b47dcbd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/_textwrap.py +++ /dev/null @@ -1,49 +0,0 @@ -import textwrap -import typing as t -from contextlib import contextmanager - - -class TextWrapper(textwrap.TextWrapper): - def _handle_long_word( - self, - reversed_chunks: t.List[str], - cur_line: t.List[str], - cur_len: int, - width: int, - ) -> None: - space_left = max(width - cur_len, 1) - - if self.break_long_words: - last = reversed_chunks[-1] - cut = last[:space_left] - res = last[space_left:] - cur_line.append(cut) - reversed_chunks[-1] = res - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - @contextmanager - def extra_indent(self, indent: str) -> t.Iterator[None]: - old_initial_indent = self.initial_indent - old_subsequent_indent = self.subsequent_indent - self.initial_indent += indent - self.subsequent_indent += indent - - try: - yield - finally: - self.initial_indent = old_initial_indent - self.subsequent_indent = old_subsequent_indent - - def indent_only(self, text: str) -> str: - rv = [] - - for idx, line in enumerate(text.splitlines()): - indent = self.initial_indent - - if idx > 0: - indent = self.subsequent_indent - - rv.append(f"{indent}{line}") - - return "\n".join(rv) diff --git a/backend/venv39/lib/python3.9/site-packages/click/_winconsole.py b/backend/venv39/lib/python3.9/site-packages/click/_winconsole.py deleted file mode 100644 index 6b20df3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/_winconsole.py +++ /dev/null @@ -1,279 +0,0 @@ -# This module is based on the excellent work by Adam Bartoš who -# provided a lot of what went into the implementation here in -# the discussion to issue1602 in the Python bug tracker. -# -# There are some general differences in regards to how this works -# compared to the original patches as we do not need to patch -# the entire interpreter but just work in our little world of -# echo and prompt. -import io -import sys -import time -import typing as t -from ctypes import byref -from ctypes import c_char -from ctypes import c_char_p -from ctypes import c_int -from ctypes import c_ssize_t -from ctypes import c_ulong -from ctypes import c_void_p -from ctypes import POINTER -from ctypes import py_object -from ctypes import Structure -from ctypes.wintypes import DWORD -from ctypes.wintypes import HANDLE -from ctypes.wintypes import LPCWSTR -from ctypes.wintypes import LPWSTR - -from ._compat import _NonClosingTextIOWrapper - -assert sys.platform == "win32" -import msvcrt # noqa: E402 -from ctypes import windll # noqa: E402 -from ctypes import WINFUNCTYPE # noqa: E402 - -c_ssize_p = POINTER(c_ssize_t) - -kernel32 = windll.kernel32 -GetStdHandle = kernel32.GetStdHandle -ReadConsoleW = kernel32.ReadConsoleW -WriteConsoleW = kernel32.WriteConsoleW -GetConsoleMode = kernel32.GetConsoleMode -GetLastError = kernel32.GetLastError -GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) -CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( - ("CommandLineToArgvW", windll.shell32) -) -LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) - -STDIN_HANDLE = GetStdHandle(-10) -STDOUT_HANDLE = GetStdHandle(-11) -STDERR_HANDLE = GetStdHandle(-12) - -PyBUF_SIMPLE = 0 -PyBUF_WRITABLE = 1 - -ERROR_SUCCESS = 0 -ERROR_NOT_ENOUGH_MEMORY = 8 -ERROR_OPERATION_ABORTED = 995 - -STDIN_FILENO = 0 -STDOUT_FILENO = 1 -STDERR_FILENO = 2 - -EOF = b"\x1a" -MAX_BYTES_WRITTEN = 32767 - -try: - from ctypes import pythonapi -except ImportError: - # On PyPy we cannot get buffers so our ability to operate here is - # severely limited. - get_buffer = None -else: - - class Py_buffer(Structure): - _fields_ = [ - ("buf", c_void_p), - ("obj", py_object), - ("len", c_ssize_t), - ("itemsize", c_ssize_t), - ("readonly", c_int), - ("ndim", c_int), - ("format", c_char_p), - ("shape", c_ssize_p), - ("strides", c_ssize_p), - ("suboffsets", c_ssize_p), - ("internal", c_void_p), - ] - - PyObject_GetBuffer = pythonapi.PyObject_GetBuffer - PyBuffer_Release = pythonapi.PyBuffer_Release - - def get_buffer(obj, writable=False): - buf = Py_buffer() - flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE - PyObject_GetBuffer(py_object(obj), byref(buf), flags) - - try: - buffer_type = c_char * buf.len - return buffer_type.from_address(buf.buf) - finally: - PyBuffer_Release(byref(buf)) - - -class _WindowsConsoleRawIOBase(io.RawIOBase): - def __init__(self, handle): - self.handle = handle - - def isatty(self): - super().isatty() - return True - - -class _WindowsConsoleReader(_WindowsConsoleRawIOBase): - def readable(self): - return True - - def readinto(self, b): - bytes_to_be_read = len(b) - if not bytes_to_be_read: - return 0 - elif bytes_to_be_read % 2: - raise ValueError( - "cannot read odd number of bytes from UTF-16-LE encoded console" - ) - - buffer = get_buffer(b, writable=True) - code_units_to_be_read = bytes_to_be_read // 2 - code_units_read = c_ulong() - - rv = ReadConsoleW( - HANDLE(self.handle), - buffer, - code_units_to_be_read, - byref(code_units_read), - None, - ) - if GetLastError() == ERROR_OPERATION_ABORTED: - # wait for KeyboardInterrupt - time.sleep(0.1) - if not rv: - raise OSError(f"Windows error: {GetLastError()}") - - if buffer[0] == EOF: - return 0 - return 2 * code_units_read.value - - -class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): - def writable(self): - return True - - @staticmethod - def _get_error_message(errno): - if errno == ERROR_SUCCESS: - return "ERROR_SUCCESS" - elif errno == ERROR_NOT_ENOUGH_MEMORY: - return "ERROR_NOT_ENOUGH_MEMORY" - return f"Windows error {errno}" - - def write(self, b): - bytes_to_be_written = len(b) - buf = get_buffer(b) - code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 - code_units_written = c_ulong() - - WriteConsoleW( - HANDLE(self.handle), - buf, - code_units_to_be_written, - byref(code_units_written), - None, - ) - bytes_written = 2 * code_units_written.value - - if bytes_written == 0 and bytes_to_be_written > 0: - raise OSError(self._get_error_message(GetLastError())) - return bytes_written - - -class ConsoleStream: - def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: - self._text_stream = text_stream - self.buffer = byte_stream - - @property - def name(self) -> str: - return self.buffer.name - - def write(self, x: t.AnyStr) -> int: - if isinstance(x, str): - return self._text_stream.write(x) - try: - self.flush() - except Exception: - pass - return self.buffer.write(x) - - def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: - for line in lines: - self.write(line) - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._text_stream, name) - - def isatty(self) -> bool: - return self.buffer.isatty() - - def __repr__(self): - return f"" - - -def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: - text_stream = _NonClosingTextIOWrapper( - io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), - "utf-16-le", - "strict", - line_buffering=True, - ) - return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) - - -_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { - 0: _get_text_stdin, - 1: _get_text_stdout, - 2: _get_text_stderr, -} - - -def _is_console(f: t.TextIO) -> bool: - if not hasattr(f, "fileno"): - return False - - try: - fileno = f.fileno() - except (OSError, io.UnsupportedOperation): - return False - - handle = msvcrt.get_osfhandle(fileno) - return bool(GetConsoleMode(handle, byref(DWORD()))) - - -def _get_windows_console_stream( - f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] -) -> t.Optional[t.TextIO]: - if ( - get_buffer is not None - and encoding in {"utf-16-le", None} - and errors in {"strict", None} - and _is_console(f) - ): - func = _stream_factories.get(f.fileno()) - if func is not None: - b = getattr(f, "buffer", None) - - if b is None: - return None - - return func(b) diff --git a/backend/venv39/lib/python3.9/site-packages/click/core.py b/backend/venv39/lib/python3.9/site-packages/click/core.py deleted file mode 100644 index e630501..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/core.py +++ /dev/null @@ -1,3047 +0,0 @@ -import enum -import errno -import inspect -import os -import sys -import typing as t -from collections import abc -from contextlib import contextmanager -from contextlib import ExitStack -from functools import update_wrapper -from gettext import gettext as _ -from gettext import ngettext -from itertools import repeat -from types import TracebackType - -from . import types -from .exceptions import Abort -from .exceptions import BadParameter -from .exceptions import ClickException -from .exceptions import Exit -from .exceptions import MissingParameter -from .exceptions import UsageError -from .formatting import HelpFormatter -from .formatting import join_options -from .globals import pop_context -from .globals import push_context -from .parser import _flag_needs_value -from .parser import OptionParser -from .parser import split_opt -from .termui import confirm -from .termui import prompt -from .termui import style -from .utils import _detect_program_name -from .utils import _expand_args -from .utils import echo -from .utils import make_default_short_help -from .utils import make_str -from .utils import PacifyFlushWrapper - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .decorators import HelpOption - from .shell_completion import CompletionItem - -F = t.TypeVar("F", bound=t.Callable[..., t.Any]) -V = t.TypeVar("V") - - -def _complete_visible_commands( - ctx: "Context", incomplete: str -) -> t.Iterator[t.Tuple[str, "Command"]]: - """List all the subcommands of a group that start with the - incomplete value and aren't hidden. - - :param ctx: Invocation context for the group. - :param incomplete: Value being completed. May be empty. - """ - multi = t.cast(MultiCommand, ctx.command) - - for name in multi.list_commands(ctx): - if name.startswith(incomplete): - command = multi.get_command(ctx, name) - - if command is not None and not command.hidden: - yield name, command - - -def _check_multicommand( - base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False -) -> None: - if not base_command.chain or not isinstance(cmd, MultiCommand): - return - if register: - hint = ( - "It is not possible to add multi commands as children to" - " another multi command that is in chain mode." - ) - else: - hint = ( - "Found a multi command as subcommand to a multi command" - " that is in chain mode. This is not supported." - ) - raise RuntimeError( - f"{hint}. Command {base_command.name!r} is set to chain and" - f" {cmd_name!r} was added as a subcommand but it in itself is a" - f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" - f" within a chained {type(base_command).__name__} named" - f" {base_command.name!r})." - ) - - -def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: - return list(zip(*repeat(iter(iterable), batch_size))) - - -@contextmanager -def augment_usage_errors( - ctx: "Context", param: t.Optional["Parameter"] = None -) -> t.Iterator[None]: - """Context manager that attaches extra information to exceptions.""" - try: - yield - except BadParameter as e: - if e.ctx is None: - e.ctx = ctx - if param is not None and e.param is None: - e.param = param - raise - except UsageError as e: - if e.ctx is None: - e.ctx = ctx - raise - - -def iter_params_for_processing( - invocation_order: t.Sequence["Parameter"], - declaration_order: t.Sequence["Parameter"], -) -> t.List["Parameter"]: - """Returns all declared parameters in the order they should be processed. - - The declared parameters are re-shuffled depending on the order in which - they were invoked, as well as the eagerness of each parameters. - - The invocation order takes precedence over the declaration order. I.e. the - order in which the user provided them to the CLI is respected. - - This behavior and its effect on callback evaluation is detailed at: - https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order - """ - - def sort_key(item: "Parameter") -> t.Tuple[bool, float]: - try: - idx: float = invocation_order.index(item) - except ValueError: - idx = float("inf") - - return not item.is_eager, idx - - return sorted(declaration_order, key=sort_key) - - -class ParameterSource(enum.Enum): - """This is an :class:`~enum.Enum` that indicates the source of a - parameter's value. - - Use :meth:`click.Context.get_parameter_source` to get the - source for a parameter by name. - - .. versionchanged:: 8.0 - Use :class:`~enum.Enum` and drop the ``validate`` method. - - .. versionchanged:: 8.0 - Added the ``PROMPT`` value. - """ - - COMMANDLINE = enum.auto() - """The value was provided by the command line args.""" - ENVIRONMENT = enum.auto() - """The value was provided with an environment variable.""" - DEFAULT = enum.auto() - """Used the default specified by the parameter.""" - DEFAULT_MAP = enum.auto() - """Used a default provided by :attr:`Context.default_map`.""" - PROMPT = enum.auto() - """Used a prompt to confirm a default or provide a value.""" - - -class Context: - """The context is a special internal object that holds state relevant - for the script execution at every single level. It's normally invisible - to commands unless they opt-in to getting access to it. - - The context is useful as it can pass internal objects around and can - control special execution features such as reading data from - environment variables. - - A context can be used as context manager in which case it will call - :meth:`close` on teardown. - - :param command: the command class for this context. - :param parent: the parent context. - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it is usually - the name of the script, for commands below it it's - the name of the script. - :param obj: an arbitrary object of user data. - :param auto_envvar_prefix: the prefix to use for automatic environment - variables. If this is `None` then reading - from environment variables is disabled. This - does not affect manually set environment - variables which are always read. - :param default_map: a dictionary (like object) with default values - for parameters. - :param terminal_width: the width of the terminal. The default is - inherit from parent context. If no context - defines the terminal width then auto - detection will be applied. - :param max_content_width: the maximum width for content rendered by - Click (this currently only affects help - pages). This defaults to 80 characters if - not overridden. In other words: even if the - terminal is larger than that, Click will not - format things wider than 80 characters by - default. In addition to that, formatters might - add some safety mapping on the right. - :param resilient_parsing: if this flag is enabled then Click will - parse without any interactivity or callback - invocation. Default values will also be - ignored. This is useful for implementing - things such as completion support. - :param allow_extra_args: if this is set to `True` then extra arguments - at the end will not raise an error and will be - kept on the context. The default is to inherit - from the command. - :param allow_interspersed_args: if this is set to `False` then options - and arguments cannot be mixed. The - default is to inherit from the command. - :param ignore_unknown_options: instructs click to ignore options it does - not know and keeps them for later - processing. - :param help_option_names: optionally a list of strings that define how - the default help parameter is named. The - default is ``['--help']``. - :param token_normalize_func: an optional function that is used to - normalize tokens (options, choices, - etc.). This for instance can be used to - implement case insensitive behavior. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are used in texts that Click prints which is by - default not the case. This for instance would affect - help output. - :param show_default: Show the default value for commands. If this - value is not set, it defaults to the value from the parent - context. ``Command.show_default`` overrides this default for the - specific command. - - .. versionchanged:: 8.1 - The ``show_default`` parameter is overridden by - ``Command.show_default``, instead of the other way around. - - .. versionchanged:: 8.0 - The ``show_default`` parameter defaults to the value from the - parent context. - - .. versionchanged:: 7.1 - Added the ``show_default`` parameter. - - .. versionchanged:: 4.0 - Added the ``color``, ``ignore_unknown_options``, and - ``max_content_width`` parameters. - - .. versionchanged:: 3.0 - Added the ``allow_extra_args`` and ``allow_interspersed_args`` - parameters. - - .. versionchanged:: 2.0 - Added the ``resilient_parsing``, ``help_option_names``, and - ``token_normalize_func`` parameters. - """ - - #: The formatter class to create with :meth:`make_formatter`. - #: - #: .. versionadded:: 8.0 - formatter_class: t.Type["HelpFormatter"] = HelpFormatter - - def __init__( - self, - command: "Command", - parent: t.Optional["Context"] = None, - info_name: t.Optional[str] = None, - obj: t.Optional[t.Any] = None, - auto_envvar_prefix: t.Optional[str] = None, - default_map: t.Optional[t.MutableMapping[str, t.Any]] = None, - terminal_width: t.Optional[int] = None, - max_content_width: t.Optional[int] = None, - resilient_parsing: bool = False, - allow_extra_args: t.Optional[bool] = None, - allow_interspersed_args: t.Optional[bool] = None, - ignore_unknown_options: t.Optional[bool] = None, - help_option_names: t.Optional[t.List[str]] = None, - token_normalize_func: t.Optional[t.Callable[[str], str]] = None, - color: t.Optional[bool] = None, - show_default: t.Optional[bool] = None, - ) -> None: - #: the parent context or `None` if none exists. - self.parent = parent - #: the :class:`Command` for this context. - self.command = command - #: the descriptive information name - self.info_name = info_name - #: Map of parameter names to their parsed values. Parameters - #: with ``expose_value=False`` are not stored. - self.params: t.Dict[str, t.Any] = {} - #: the leftover arguments. - self.args: t.List[str] = [] - #: protected arguments. These are arguments that are prepended - #: to `args` when certain parsing scenarios are encountered but - #: must be never propagated to another arguments. This is used - #: to implement nested parsing. - self.protected_args: t.List[str] = [] - #: the collected prefixes of the command's options. - self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() - - if obj is None and parent is not None: - obj = parent.obj - - #: the user object stored. - self.obj: t.Any = obj - self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) - - #: A dictionary (-like object) with defaults for parameters. - if ( - default_map is None - and info_name is not None - and parent is not None - and parent.default_map is not None - ): - default_map = parent.default_map.get(info_name) - - self.default_map: t.Optional[t.MutableMapping[str, t.Any]] = default_map - - #: This flag indicates if a subcommand is going to be executed. A - #: group callback can use this information to figure out if it's - #: being executed directly or because the execution flow passes - #: onwards to a subcommand. By default it's None, but it can be - #: the name of the subcommand to execute. - #: - #: If chaining is enabled this will be set to ``'*'`` in case - #: any commands are executed. It is however not possible to - #: figure out which ones. If you require this knowledge you - #: should use a :func:`result_callback`. - self.invoked_subcommand: t.Optional[str] = None - - if terminal_width is None and parent is not None: - terminal_width = parent.terminal_width - - #: The width of the terminal (None is autodetection). - self.terminal_width: t.Optional[int] = terminal_width - - if max_content_width is None and parent is not None: - max_content_width = parent.max_content_width - - #: The maximum width of formatted content (None implies a sensible - #: default which is 80 for most things). - self.max_content_width: t.Optional[int] = max_content_width - - if allow_extra_args is None: - allow_extra_args = command.allow_extra_args - - #: Indicates if the context allows extra args or if it should - #: fail on parsing. - #: - #: .. versionadded:: 3.0 - self.allow_extra_args = allow_extra_args - - if allow_interspersed_args is None: - allow_interspersed_args = command.allow_interspersed_args - - #: Indicates if the context allows mixing of arguments and - #: options or not. - #: - #: .. versionadded:: 3.0 - self.allow_interspersed_args: bool = allow_interspersed_args - - if ignore_unknown_options is None: - ignore_unknown_options = command.ignore_unknown_options - - #: Instructs click to ignore options that a command does not - #: understand and will store it on the context for later - #: processing. This is primarily useful for situations where you - #: want to call into external programs. Generally this pattern is - #: strongly discouraged because it's not possibly to losslessly - #: forward all arguments. - #: - #: .. versionadded:: 4.0 - self.ignore_unknown_options: bool = ignore_unknown_options - - if help_option_names is None: - if parent is not None: - help_option_names = parent.help_option_names - else: - help_option_names = ["--help"] - - #: The names for the help options. - self.help_option_names: t.List[str] = help_option_names - - if token_normalize_func is None and parent is not None: - token_normalize_func = parent.token_normalize_func - - #: An optional normalization function for tokens. This is - #: options, choices, commands etc. - self.token_normalize_func: t.Optional[t.Callable[[str], str]] = ( - token_normalize_func - ) - - #: Indicates if resilient parsing is enabled. In that case Click - #: will do its best to not cause any failures and default values - #: will be ignored. Useful for completion. - self.resilient_parsing: bool = resilient_parsing - - # If there is no envvar prefix yet, but the parent has one and - # the command on this level has a name, we can expand the envvar - # prefix automatically. - if auto_envvar_prefix is None: - if ( - parent is not None - and parent.auto_envvar_prefix is not None - and self.info_name is not None - ): - auto_envvar_prefix = ( - f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" - ) - else: - auto_envvar_prefix = auto_envvar_prefix.upper() - - if auto_envvar_prefix is not None: - auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") - - self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix - - if color is None and parent is not None: - color = parent.color - - #: Controls if styling output is wanted or not. - self.color: t.Optional[bool] = color - - if show_default is None and parent is not None: - show_default = parent.show_default - - #: Show option default values when formatting help text. - self.show_default: t.Optional[bool] = show_default - - self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] - self._depth = 0 - self._parameter_source: t.Dict[str, ParameterSource] = {} - self._exit_stack = ExitStack() - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire CLI - structure. - - .. code-block:: python - - with Context(cli) as ctx: - info = ctx.to_info_dict() - - .. versionadded:: 8.0 - """ - return { - "command": self.command.to_info_dict(self), - "info_name": self.info_name, - "allow_extra_args": self.allow_extra_args, - "allow_interspersed_args": self.allow_interspersed_args, - "ignore_unknown_options": self.ignore_unknown_options, - "auto_envvar_prefix": self.auto_envvar_prefix, - } - - def __enter__(self) -> "Context": - self._depth += 1 - push_context(self) - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self._depth -= 1 - if self._depth == 0: - self.close() - pop_context() - - @contextmanager - def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: - """This helper method can be used with the context object to promote - it to the current thread local (see :func:`get_current_context`). - The default behavior of this is to invoke the cleanup functions which - can be disabled by setting `cleanup` to `False`. The cleanup - functions are typically used for things such as closing file handles. - - If the cleanup is intended the context object can also be directly - used as a context manager. - - Example usage:: - - with ctx.scope(): - assert get_current_context() is ctx - - This is equivalent:: - - with ctx: - assert get_current_context() is ctx - - .. versionadded:: 5.0 - - :param cleanup: controls if the cleanup functions should be run or - not. The default is to run these functions. In - some situations the context only wants to be - temporarily pushed in which case this can be disabled. - Nested pushes automatically defer the cleanup. - """ - if not cleanup: - self._depth += 1 - try: - with self as rv: - yield rv - finally: - if not cleanup: - self._depth -= 1 - - @property - def meta(self) -> t.Dict[str, t.Any]: - """This is a dictionary which is shared with all the contexts - that are nested. It exists so that click utilities can store some - state here if they need to. It is however the responsibility of - that code to manage this dictionary well. - - The keys are supposed to be unique dotted strings. For instance - module paths are a good choice for it. What is stored in there is - irrelevant for the operation of click. However what is important is - that code that places data here adheres to the general semantics of - the system. - - Example usage:: - - LANG_KEY = f'{__name__}.lang' - - def set_language(value): - ctx = get_current_context() - ctx.meta[LANG_KEY] = value - - def get_language(): - return get_current_context().meta.get(LANG_KEY, 'en_US') - - .. versionadded:: 5.0 - """ - return self._meta - - def make_formatter(self) -> HelpFormatter: - """Creates the :class:`~click.HelpFormatter` for the help and - usage output. - - To quickly customize the formatter class used without overriding - this method, set the :attr:`formatter_class` attribute. - - .. versionchanged:: 8.0 - Added the :attr:`formatter_class` attribute. - """ - return self.formatter_class( - width=self.terminal_width, max_width=self.max_content_width - ) - - def with_resource(self, context_manager: t.ContextManager[V]) -> V: - """Register a resource as if it were used in a ``with`` - statement. The resource will be cleaned up when the context is - popped. - - Uses :meth:`contextlib.ExitStack.enter_context`. It calls the - resource's ``__enter__()`` method and returns the result. When - the context is popped, it closes the stack, which calls the - resource's ``__exit__()`` method. - - To register a cleanup function for something that isn't a - context manager, use :meth:`call_on_close`. Or use something - from :mod:`contextlib` to turn it into a context manager first. - - .. code-block:: python - - @click.group() - @click.option("--name") - @click.pass_context - def cli(ctx): - ctx.obj = ctx.with_resource(connect_db(name)) - - :param context_manager: The context manager to enter. - :return: Whatever ``context_manager.__enter__()`` returns. - - .. versionadded:: 8.0 - """ - return self._exit_stack.enter_context(context_manager) - - def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: - """Register a function to be called when the context tears down. - - This can be used to close resources opened during the script - execution. Resources that support Python's context manager - protocol which would be used in a ``with`` statement should be - registered with :meth:`with_resource` instead. - - :param f: The function to execute on teardown. - """ - return self._exit_stack.callback(f) - - def close(self) -> None: - """Invoke all close callbacks registered with - :meth:`call_on_close`, and exit all context managers entered - with :meth:`with_resource`. - """ - self._exit_stack.close() - # In case the context is reused, create a new exit stack. - self._exit_stack = ExitStack() - - @property - def command_path(self) -> str: - """The computed command path. This is used for the ``usage`` - information on the help page. It's automatically created by - combining the info names of the chain of contexts to the root. - """ - rv = "" - if self.info_name is not None: - rv = self.info_name - if self.parent is not None: - parent_command_path = [self.parent.command_path] - - if isinstance(self.parent.command, Command): - for param in self.parent.command.get_params(self): - parent_command_path.extend(param.get_usage_pieces(self)) - - rv = f"{' '.join(parent_command_path)} {rv}" - return rv.lstrip() - - def find_root(self) -> "Context": - """Finds the outermost context.""" - node = self - while node.parent is not None: - node = node.parent - return node - - def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: - """Finds the closest object of a given type.""" - node: t.Optional[Context] = self - - while node is not None: - if isinstance(node.obj, object_type): - return node.obj - - node = node.parent - - return None - - def ensure_object(self, object_type: t.Type[V]) -> V: - """Like :meth:`find_object` but sets the innermost object to a - new instance of `object_type` if it does not exist. - """ - rv = self.find_object(object_type) - if rv is None: - self.obj = rv = object_type() - return rv - - @t.overload - def lookup_default( - self, name: str, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def lookup_default( - self, name: str, call: "te.Literal[False]" = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: - """Get the default for a parameter from :attr:`default_map`. - - :param name: Name of the parameter. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - if self.default_map is not None: - value = self.default_map.get(name) - - if call and callable(value): - return value() - - return value - - return None - - def fail(self, message: str) -> "te.NoReturn": - """Aborts the execution of the program with a specific error - message. - - :param message: the error message to fail with. - """ - raise UsageError(message, self) - - def abort(self) -> "te.NoReturn": - """Aborts the script.""" - raise Abort() - - def exit(self, code: int = 0) -> "te.NoReturn": - """Exits the application with a given exit code.""" - raise Exit(code) - - def get_usage(self) -> str: - """Helper method to get formatted usage string for the current - context and command. - """ - return self.command.get_usage(self) - - def get_help(self) -> str: - """Helper method to get formatted help page for the current - context and command. - """ - return self.command.get_help(self) - - def _make_sub_context(self, command: "Command") -> "Context": - """Create a new context of the same type as this context, but - for a new command. - - :meta private: - """ - return type(self)(command, info_name=command.name, parent=self) - - @t.overload - def invoke( - __self, - __callback: "t.Callable[..., V]", - *args: t.Any, - **kwargs: t.Any, - ) -> V: ... - - @t.overload - def invoke( - __self, - __callback: "Command", - *args: t.Any, - **kwargs: t.Any, - ) -> t.Any: ... - - def invoke( - __self, - __callback: t.Union["Command", "t.Callable[..., V]"], - *args: t.Any, - **kwargs: t.Any, - ) -> t.Union[t.Any, V]: - """Invokes a command callback in exactly the way it expects. There - are two ways to invoke this method: - - 1. the first argument can be a callback and all other arguments and - keyword arguments are forwarded directly to the function. - 2. the first argument is a click command object. In that case all - arguments are forwarded as well but proper click parameters - (options and click arguments) must be keyword arguments and Click - will fill in defaults. - - Note that before Click 3.2 keyword arguments were not properly filled - in against the intention of this code and no context was created. For - more information about this change and why it was done in a bugfix - release see :ref:`upgrade-to-3.2`. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if :meth:`forward` is called at multiple levels. - """ - if isinstance(__callback, Command): - other_cmd = __callback - - if other_cmd.callback is None: - raise TypeError( - "The given command does not have a callback that can be invoked." - ) - else: - __callback = t.cast("t.Callable[..., V]", other_cmd.callback) - - ctx = __self._make_sub_context(other_cmd) - - for param in other_cmd.params: - if param.name not in kwargs and param.expose_value: - kwargs[param.name] = param.type_cast_value( # type: ignore - ctx, param.get_default(ctx) - ) - - # Track all kwargs as params, so that forward() will pass - # them on in subsequent calls. - ctx.params.update(kwargs) - else: - ctx = __self - - with augment_usage_errors(__self): - with ctx: - return __callback(*args, **kwargs) - - def forward(__self, __cmd: "Command", *args: t.Any, **kwargs: t.Any) -> t.Any: - """Similar to :meth:`invoke` but fills in default keyword - arguments from the current context if the other command expects - it. This cannot invoke callbacks directly, only other commands. - - .. versionchanged:: 8.0 - All ``kwargs`` are tracked in :attr:`params` so they will be - passed if ``forward`` is called at multiple levels. - """ - # Can only forward to other commands, not direct callbacks. - if not isinstance(__cmd, Command): - raise TypeError("Callback is not a command.") - - for param in __self.params: - if param not in kwargs: - kwargs[param] = __self.params[param] - - return __self.invoke(__cmd, *args, **kwargs) - - def set_parameter_source(self, name: str, source: ParameterSource) -> None: - """Set the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - :param name: The name of the parameter. - :param source: A member of :class:`~click.core.ParameterSource`. - """ - self._parameter_source[name] = source - - def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: - """Get the source of a parameter. This indicates the location - from which the value of the parameter was obtained. - - This can be useful for determining when a user specified a value - on the command line that is the same as the default value. It - will be :attr:`~click.core.ParameterSource.DEFAULT` only if the - value was actually taken from the default. - - :param name: The name of the parameter. - :rtype: ParameterSource - - .. versionchanged:: 8.0 - Returns ``None`` if the parameter was not provided from any - source. - """ - return self._parameter_source.get(name) - - -class BaseCommand: - """The base command implements the minimal API contract of commands. - Most code will never use this as it does not implement a lot of useful - functionality but it can act as the direct subclass of alternative - parsing methods that do not depend on the Click parser. - - For instance, this can be used to bridge Click and other systems like - argparse or docopt. - - Because base commands do not implement a lot of the API that other - parts of Click take for granted, they are not supported for all - operations. For instance, they cannot be used with the decorators - usually and they have no built-in callback system. - - .. versionchanged:: 2.0 - Added the `context_settings` parameter. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - """ - - #: The context class to create with :meth:`make_context`. - #: - #: .. versionadded:: 8.0 - context_class: t.Type[Context] = Context - #: the default for the :attr:`Context.allow_extra_args` flag. - allow_extra_args = False - #: the default for the :attr:`Context.allow_interspersed_args` flag. - allow_interspersed_args = True - #: the default for the :attr:`Context.ignore_unknown_options` flag. - ignore_unknown_options = False - - def __init__( - self, - name: t.Optional[str], - context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, - ) -> None: - #: the name the command thinks it has. Upon registering a command - #: on a :class:`Group` the group will default the command name - #: with this information. You should instead use the - #: :class:`Context`\'s :attr:`~Context.info_name` attribute. - self.name = name - - if context_settings is None: - context_settings = {} - - #: an optional dictionary with defaults passed to the context. - self.context_settings: t.MutableMapping[str, t.Any] = context_settings - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. This traverses the entire structure - below this command. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - :param ctx: A :class:`Context` representing this command. - - .. versionadded:: 8.0 - """ - return {"name": self.name} - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def get_usage(self, ctx: Context) -> str: - raise NotImplementedError("Base commands cannot get usage") - - def get_help(self, ctx: Context) -> str: - raise NotImplementedError("Base commands cannot get help") - - def make_context( - self, - info_name: t.Optional[str], - args: t.List[str], - parent: t.Optional[Context] = None, - **extra: t.Any, - ) -> Context: - """This function when given an info name and arguments will kick - off the parsing and create a new :class:`Context`. It does not - invoke the actual command callback though. - - To quickly customize the context class used without overriding - this method, set the :attr:`context_class` attribute. - - :param info_name: the info name for this invocation. Generally this - is the most descriptive name for the script or - command. For the toplevel script it's usually - the name of the script, for commands below it's - the name of the command. - :param args: the arguments to parse as list of strings. - :param parent: the parent context if available. - :param extra: extra keyword arguments forwarded to the context - constructor. - - .. versionchanged:: 8.0 - Added the :attr:`context_class` attribute. - """ - for key, value in self.context_settings.items(): - if key not in extra: - extra[key] = value - - ctx = self.context_class( - self, # type: ignore[arg-type] - info_name=info_name, - parent=parent, - **extra, - ) - - with ctx.scope(cleanup=False): - self.parse_args(ctx, args) - return ctx - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - """Given a context and a list of arguments this creates the parser - and parses the arguments, then modifies the context as necessary. - This is automatically invoked by :meth:`make_context`. - """ - raise NotImplementedError("Base commands do not know how to parse arguments.") - - def invoke(self, ctx: Context) -> t.Any: - """Given a context, this invokes the command. The default - implementation is raising a not implemented error. - """ - raise NotImplementedError("Base commands are not invocable by default") - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of chained multi-commands. - - Any command could be part of a chained multi-command, so sibling - commands are valid at any point during command completion. Other - command classes will return more completions. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: t.List[CompletionItem] = [] - - while ctx.parent is not None: - ctx = ctx.parent - - if isinstance(ctx.command, MultiCommand) and ctx.command.chain: - results.extend( - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - if name not in ctx.protected_args - ) - - return results - - @t.overload - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: "te.Literal[True]" = True, - **extra: t.Any, - ) -> "te.NoReturn": ... - - @t.overload - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: bool = ..., - **extra: t.Any, - ) -> t.Any: ... - - def main( - self, - args: t.Optional[t.Sequence[str]] = None, - prog_name: t.Optional[str] = None, - complete_var: t.Optional[str] = None, - standalone_mode: bool = True, - windows_expand_args: bool = True, - **extra: t.Any, - ) -> t.Any: - """This is the way to invoke a script with all the bells and - whistles as a command line application. This will always terminate - the application after a call. If this is not wanted, ``SystemExit`` - needs to be caught. - - This method is also available by directly calling the instance of - a :class:`Command`. - - :param args: the arguments that should be used for parsing. If not - provided, ``sys.argv[1:]`` is used. - :param prog_name: the program name that should be used. By default - the program name is constructed by taking the file - name from ``sys.argv[0]``. - :param complete_var: the environment variable that controls the - bash completion support. The default is - ``"__COMPLETE"`` with prog_name in - uppercase. - :param standalone_mode: the default behavior is to invoke the script - in standalone mode. Click will then - handle exceptions and convert them into - error messages and the function will never - return but shut down the interpreter. If - this is set to `False` they will be - propagated to the caller and the return - value of this function is the return value - of :meth:`invoke`. - :param windows_expand_args: Expand glob patterns, user dir, and - env vars in command line args on Windows. - :param extra: extra keyword arguments are forwarded to the context - constructor. See :class:`Context` for more information. - - .. versionchanged:: 8.0.1 - Added the ``windows_expand_args`` parameter to allow - disabling command line arg expansion on Windows. - - .. versionchanged:: 8.0 - When taking arguments from ``sys.argv`` on Windows, glob - patterns, user dir, and env vars are expanded. - - .. versionchanged:: 3.0 - Added the ``standalone_mode`` parameter. - """ - if args is None: - args = sys.argv[1:] - - if os.name == "nt" and windows_expand_args: - args = _expand_args(args) - else: - args = list(args) - - if prog_name is None: - prog_name = _detect_program_name() - - # Process shell completion requests and exit early. - self._main_shell_completion(extra, prog_name, complete_var) - - try: - try: - with self.make_context(prog_name, args, **extra) as ctx: - rv = self.invoke(ctx) - if not standalone_mode: - return rv - # it's not safe to `ctx.exit(rv)` here! - # note that `rv` may actually contain data like "1" which - # has obvious effects - # more subtle case: `rv=[None, None]` can come out of - # chained commands which all returned `None` -- so it's not - # even always obvious that `rv` indicates success/failure - # by its truthiness/falsiness - ctx.exit() - except (EOFError, KeyboardInterrupt) as e: - echo(file=sys.stderr) - raise Abort() from e - except ClickException as e: - if not standalone_mode: - raise - e.show() - sys.exit(e.exit_code) - except OSError as e: - if e.errno == errno.EPIPE: - sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) - sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) - sys.exit(1) - else: - raise - except Exit as e: - if standalone_mode: - sys.exit(e.exit_code) - else: - # in non-standalone mode, return the exit code - # note that this is only reached if `self.invoke` above raises - # an Exit explicitly -- thus bypassing the check there which - # would return its result - # the results of non-standalone execution may therefore be - # somewhat ambiguous: if there are codepaths which lead to - # `ctx.exit(1)` and to `return 1`, the caller won't be able to - # tell the difference between the two - return e.exit_code - except Abort: - if not standalone_mode: - raise - echo(_("Aborted!"), file=sys.stderr) - sys.exit(1) - - def _main_shell_completion( - self, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: t.Optional[str] = None, - ) -> None: - """Check if the shell is asking for tab completion, process - that, then exit early. Called from :meth:`main` before the - program is invoked. - - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. Defaults to - ``_{PROG_NAME}_COMPLETE``. - - .. versionchanged:: 8.2.0 - Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). - """ - if complete_var is None: - complete_name = prog_name.replace("-", "_").replace(".", "_") - complete_var = f"_{complete_name}_COMPLETE".upper() - - instruction = os.environ.get(complete_var) - - if not instruction: - return - - from .shell_completion import shell_complete - - rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) - sys.exit(rv) - - def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: - """Alias for :meth:`main`.""" - return self.main(*args, **kwargs) - - -class Command(BaseCommand): - """Commands are the basic building block of command line interfaces in - Click. A basic command handles command line parsing and might dispatch - more parsing to commands nested below it. - - :param name: the name of the command to use unless a group overrides it. - :param context_settings: an optional dictionary with defaults that are - passed to the context object. - :param callback: the callback to invoke. This is optional. - :param params: the parameters to register with this command. This can - be either :class:`Option` or :class:`Argument` objects. - :param help: the help string to use for this command. - :param epilog: like the help string but it's printed at the end of the - help page after everything else. - :param short_help: the short help to use for this command. This is - shown on the command listing of the parent command. - :param add_help_option: by default each command registers a ``--help`` - option. This can be disabled by this parameter. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is disabled by default. - If enabled this will add ``--help`` as argument - if no arguments are passed - :param hidden: hide this command from help outputs. - - :param deprecated: issues a message indicating that - the command is deprecated. - - .. versionchanged:: 8.1 - ``help``, ``epilog``, and ``short_help`` are stored unprocessed, - all formatting is done when outputting help text, not at init, - and is done even if not using the ``@command`` decorator. - - .. versionchanged:: 8.0 - Added a ``repr`` showing the command name. - - .. versionchanged:: 7.1 - Added the ``no_args_is_help`` parameter. - - .. versionchanged:: 2.0 - Added the ``context_settings`` parameter. - """ - - def __init__( - self, - name: t.Optional[str], - context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, - callback: t.Optional[t.Callable[..., t.Any]] = None, - params: t.Optional[t.List["Parameter"]] = None, - help: t.Optional[str] = None, - epilog: t.Optional[str] = None, - short_help: t.Optional[str] = None, - options_metavar: t.Optional[str] = "[OPTIONS]", - add_help_option: bool = True, - no_args_is_help: bool = False, - hidden: bool = False, - deprecated: bool = False, - ) -> None: - super().__init__(name, context_settings) - #: the callback to execute when the command fires. This might be - #: `None` in which case nothing happens. - self.callback = callback - #: the list of parameters for this command in the order they - #: should show up in the help page and execute. Eager parameters - #: will automatically be handled before non eager ones. - self.params: t.List[Parameter] = params or [] - self.help = help - self.epilog = epilog - self.options_metavar = options_metavar - self.short_help = short_help - self.add_help_option = add_help_option - self._help_option: t.Optional[HelpOption] = None - self.no_args_is_help = no_args_is_help - self.hidden = hidden - self.deprecated = deprecated - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - info_dict.update( - params=[param.to_info_dict() for param in self.get_params(ctx)], - help=self.help, - epilog=self.epilog, - short_help=self.short_help, - hidden=self.hidden, - deprecated=self.deprecated, - ) - return info_dict - - def get_usage(self, ctx: Context) -> str: - """Formats the usage line into a string and returns it. - - Calls :meth:`format_usage` internally. - """ - formatter = ctx.make_formatter() - self.format_usage(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_params(self, ctx: Context) -> t.List["Parameter"]: - rv = self.params - help_option = self.get_help_option(ctx) - - if help_option is not None: - rv = [*rv, help_option] - - return rv - - def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the usage line into the formatter. - - This is a low-level method called by :meth:`get_usage`. - """ - pieces = self.collect_usage_pieces(ctx) - formatter.write_usage(ctx.command_path, " ".join(pieces)) - - def collect_usage_pieces(self, ctx: Context) -> t.List[str]: - """Returns all the pieces that go into the usage line and returns - it as a list of strings. - """ - rv = [self.options_metavar] if self.options_metavar else [] - - for param in self.get_params(ctx): - rv.extend(param.get_usage_pieces(ctx)) - - return rv - - def get_help_option_names(self, ctx: Context) -> t.List[str]: - """Returns the names for the help option.""" - all_names = set(ctx.help_option_names) - for param in self.params: - all_names.difference_update(param.opts) - all_names.difference_update(param.secondary_opts) - return list(all_names) - - def get_help_option(self, ctx: Context) -> t.Optional["Option"]: - """Returns the help option object. - - Unless ``add_help_option`` is ``False``. - - .. versionchanged:: 8.1.8 - The help option is now cached to avoid creating it multiple times. - """ - help_options = self.get_help_option_names(ctx) - - if not help_options or not self.add_help_option: - return None - - # Cache the help option object in private _help_option attribute to - # avoid creating it multiple times. Not doing this will break the - # callback odering by iter_params_for_processing(), which relies on - # object comparison. - if self._help_option is None: - # Avoid circular import. - from .decorators import HelpOption - - self._help_option = HelpOption(help_options) - - return self._help_option - - def make_parser(self, ctx: Context) -> OptionParser: - """Creates the underlying option parser for this command.""" - parser = OptionParser(ctx) - for param in self.get_params(ctx): - param.add_to_parser(parser, ctx) - return parser - - def get_help(self, ctx: Context) -> str: - """Formats the help into a string and returns it. - - Calls :meth:`format_help` internally. - """ - formatter = ctx.make_formatter() - self.format_help(ctx, formatter) - return formatter.getvalue().rstrip("\n") - - def get_short_help_str(self, limit: int = 45) -> str: - """Gets short help for the command or makes it by shortening the - long help string. - """ - if self.short_help: - text = inspect.cleandoc(self.short_help) - elif self.help: - text = make_default_short_help(self.help, limit) - else: - text = "" - - if self.deprecated: - text = _("(Deprecated) {text}").format(text=text) - - return text.strip() - - def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help into the formatter if it exists. - - This is a low-level method called by :meth:`get_help`. - - This calls the following methods: - - - :meth:`format_usage` - - :meth:`format_help_text` - - :meth:`format_options` - - :meth:`format_epilog` - """ - self.format_usage(ctx, formatter) - self.format_help_text(ctx, formatter) - self.format_options(ctx, formatter) - self.format_epilog(ctx, formatter) - - def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the help text to the formatter if it exists.""" - if self.help is not None: - # truncate the help text to the first form feed - text = inspect.cleandoc(self.help).partition("\f")[0] - else: - text = "" - - if self.deprecated: - text = _("(Deprecated) {text}").format(text=text) - - if text: - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(text) - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes all the options into the formatter if they exist.""" - opts = [] - for param in self.get_params(ctx): - rv = param.get_help_record(ctx) - if rv is not None: - opts.append(rv) - - if opts: - with formatter.section(_("Options")): - formatter.write_dl(opts) - - def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: - """Writes the epilog into the formatter if it exists.""" - if self.epilog: - epilog = inspect.cleandoc(self.epilog) - formatter.write_paragraph() - - with formatter.indentation(): - formatter.write_text(epilog) - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - parser = self.make_parser(ctx) - opts, args, param_order = parser.parse_args(args=args) - - for param in iter_params_for_processing(param_order, self.get_params(ctx)): - value, args = param.handle_parse_result(ctx, opts, args) - - if args and not ctx.allow_extra_args and not ctx.resilient_parsing: - ctx.fail( - ngettext( - "Got unexpected extra argument ({args})", - "Got unexpected extra arguments ({args})", - len(args), - ).format(args=" ".join(map(str, args))) - ) - - ctx.args = args - ctx._opt_prefixes.update(parser._opt_prefixes) - return args - - def invoke(self, ctx: Context) -> t.Any: - """Given a context, this invokes the attached callback (if it exists) - in the right way. - """ - if self.deprecated: - message = _( - "DeprecationWarning: The command {name!r} is deprecated." - ).format(name=self.name) - echo(style(message, fg="red"), err=True) - - if self.callback is not None: - return ctx.invoke(self.callback, **ctx.params) - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of options and chained multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results: t.List[CompletionItem] = [] - - if incomplete and not incomplete[0].isalnum(): - for param in self.get_params(ctx): - if ( - not isinstance(param, Option) - or param.hidden - or ( - not param.multiple - and ctx.get_parameter_source(param.name) # type: ignore - is ParameterSource.COMMANDLINE - ) - ): - continue - - results.extend( - CompletionItem(name, help=param.help) - for name in [*param.opts, *param.secondary_opts] - if name.startswith(incomplete) - ) - - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class MultiCommand(Command): - """A multi command is the basic implementation of a command that - dispatches to subcommands. The most common version is the - :class:`Group`. - - :param invoke_without_command: this controls how the multi command itself - is invoked. By default it's only invoked - if a subcommand is provided. - :param no_args_is_help: this controls what happens if no arguments are - provided. This option is enabled by default if - `invoke_without_command` is disabled or disabled - if it's enabled. If enabled this will add - ``--help`` as argument if no arguments are - passed. - :param subcommand_metavar: the string that is used in the documentation - to indicate the subcommand place. - :param chain: if this is set to `True` chaining of multiple subcommands - is enabled. This restricts the form of commands in that - they cannot have optional arguments but it allows - multiple commands to be chained together. - :param result_callback: The result callback to attach to this multi - command. This can be set or changed later with the - :meth:`result_callback` decorator. - :param attrs: Other command arguments described in :class:`Command`. - """ - - allow_extra_args = True - allow_interspersed_args = False - - def __init__( - self, - name: t.Optional[str] = None, - invoke_without_command: bool = False, - no_args_is_help: t.Optional[bool] = None, - subcommand_metavar: t.Optional[str] = None, - chain: bool = False, - result_callback: t.Optional[t.Callable[..., t.Any]] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - - if no_args_is_help is None: - no_args_is_help = not invoke_without_command - - self.no_args_is_help = no_args_is_help - self.invoke_without_command = invoke_without_command - - if subcommand_metavar is None: - if chain: - subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." - else: - subcommand_metavar = "COMMAND [ARGS]..." - - self.subcommand_metavar = subcommand_metavar - self.chain = chain - # The result callback that is stored. This can be set or - # overridden with the :func:`result_callback` decorator. - self._result_callback = result_callback - - if self.chain: - for param in self.params: - if isinstance(param, Argument) and not param.required: - raise RuntimeError( - "Multi commands in chain mode cannot have" - " optional arguments." - ) - - def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict(ctx) - commands = {} - - for name in self.list_commands(ctx): - command = self.get_command(ctx, name) - - if command is None: - continue - - sub_ctx = ctx._make_sub_context(command) - - with sub_ctx.scope(cleanup=False): - commands[name] = command.to_info_dict(sub_ctx) - - info_dict.update(commands=commands, chain=self.chain) - return info_dict - - def collect_usage_pieces(self, ctx: Context) -> t.List[str]: - rv = super().collect_usage_pieces(ctx) - rv.append(self.subcommand_metavar) - return rv - - def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: - super().format_options(ctx, formatter) - self.format_commands(ctx, formatter) - - def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: - """Adds a result callback to the command. By default if a - result callback is already registered this will chain them but - this can be disabled with the `replace` parameter. The result - callback is invoked with the return value of the subcommand - (or the list of return values from all subcommands if chaining - is enabled) as well as the parameters as they would be passed - to the main callback. - - Example:: - - @click.group() - @click.option('-i', '--input', default=23) - def cli(input): - return 42 - - @cli.result_callback() - def process_result(result, input): - return result + input - - :param replace: if set to `True` an already existing result - callback will be removed. - - .. versionchanged:: 8.0 - Renamed from ``resultcallback``. - - .. versionadded:: 3.0 - """ - - def decorator(f: F) -> F: - old_callback = self._result_callback - - if old_callback is None or replace: - self._result_callback = f - return f - - def function(__value, *args, **kwargs): # type: ignore - inner = old_callback(__value, *args, **kwargs) - return f(inner, *args, **kwargs) - - self._result_callback = rv = update_wrapper(t.cast(F, function), f) - return rv # type: ignore[return-value] - - return decorator - - def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: - """Extra format methods for multi methods that adds all the commands - after the options. - """ - commands = [] - for subcommand in self.list_commands(ctx): - cmd = self.get_command(ctx, subcommand) - # What is this, the tool lied about a command. Ignore it - if cmd is None: - continue - if cmd.hidden: - continue - - commands.append((subcommand, cmd)) - - # allow for 3 times the default spacing - if len(commands): - limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) - - rows = [] - for subcommand, cmd in commands: - help = cmd.get_short_help_str(limit) - rows.append((subcommand, help)) - - if rows: - with formatter.section(_("Commands")): - formatter.write_dl(rows) - - def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: - if not args and self.no_args_is_help and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - rest = super().parse_args(ctx, args) - - if self.chain: - ctx.protected_args = rest - ctx.args = [] - elif rest: - ctx.protected_args, ctx.args = rest[:1], rest[1:] - - return ctx.args - - def invoke(self, ctx: Context) -> t.Any: - def _process_result(value: t.Any) -> t.Any: - if self._result_callback is not None: - value = ctx.invoke(self._result_callback, value, **ctx.params) - return value - - if not ctx.protected_args: - if self.invoke_without_command: - # No subcommand was invoked, so the result callback is - # invoked with the group return value for regular - # groups, or an empty list for chained groups. - with ctx: - rv = super().invoke(ctx) - return _process_result([] if self.chain else rv) - ctx.fail(_("Missing command.")) - - # Fetch args back out - args = [*ctx.protected_args, *ctx.args] - ctx.args = [] - ctx.protected_args = [] - - # If we're not in chain mode, we only allow the invocation of a - # single command but we also inform the current context about the - # name of the command to invoke. - if not self.chain: - # Make sure the context is entered so we do not clean up - # resources until the result processor has worked. - with ctx: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - ctx.invoked_subcommand = cmd_name - super().invoke(ctx) - sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) - with sub_ctx: - return _process_result(sub_ctx.command.invoke(sub_ctx)) - - # In chain mode we create the contexts step by step, but after the - # base command has been invoked. Because at that point we do not - # know the subcommands yet, the invoked subcommand attribute is - # set to ``*`` to inform the command that subcommands are executed - # but nothing else. - with ctx: - ctx.invoked_subcommand = "*" if args else None - super().invoke(ctx) - - # Otherwise we make every single context and invoke them in a - # chain. In that case the return value to the result processor - # is the list of all invoked subcommand's results. - contexts = [] - while args: - cmd_name, cmd, args = self.resolve_command(ctx, args) - assert cmd is not None - sub_ctx = cmd.make_context( - cmd_name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - ) - contexts.append(sub_ctx) - args, sub_ctx.args = sub_ctx.args, [] - - rv = [] - for sub_ctx in contexts: - with sub_ctx: - rv.append(sub_ctx.command.invoke(sub_ctx)) - return _process_result(rv) - - def resolve_command( - self, ctx: Context, args: t.List[str] - ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: - cmd_name = make_str(args[0]) - original_cmd_name = cmd_name - - # Get the command - cmd = self.get_command(ctx, cmd_name) - - # If we can't find the command but there is a normalization - # function available, we try with that one. - if cmd is None and ctx.token_normalize_func is not None: - cmd_name = ctx.token_normalize_func(cmd_name) - cmd = self.get_command(ctx, cmd_name) - - # If we don't find the command we want to show an error message - # to the user that it was not provided. However, there is - # something else we should do: if the first argument looks like - # an option we want to kick off parsing again for arguments to - # resolve things like --help which now should go to the main - # place. - if cmd is None and not ctx.resilient_parsing: - if split_opt(cmd_name)[0]: - self.parse_args(ctx, ctx.args) - ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) - return cmd_name if cmd else None, cmd, args[1:] - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - """Given a context and a command name, this returns a - :class:`Command` object if it exists or returns `None`. - """ - raise NotImplementedError - - def list_commands(self, ctx: Context) -> t.List[str]: - """Returns a list of subcommand names in the order they should - appear. - """ - return [] - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. Looks - at the names of options, subcommands, and chained - multi-commands. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - results = [ - CompletionItem(name, help=command.get_short_help_str()) - for name, command in _complete_visible_commands(ctx, incomplete) - ] - results.extend(super().shell_complete(ctx, incomplete)) - return results - - -class Group(MultiCommand): - """A group allows a command to have subcommands attached. This is - the most common way to implement nesting in Click. - - :param name: The name of the group command. - :param commands: A dict mapping names to :class:`Command` objects. - Can also be a list of :class:`Command`, which will use - :attr:`Command.name` to create the dict. - :param attrs: Other command arguments described in - :class:`MultiCommand`, :class:`Command`, and - :class:`BaseCommand`. - - .. versionchanged:: 8.0 - The ``commands`` argument can be a list of command objects. - """ - - #: If set, this is used by the group's :meth:`command` decorator - #: as the default :class:`Command` class. This is useful to make all - #: subcommands use a custom command class. - #: - #: .. versionadded:: 8.0 - command_class: t.Optional[t.Type[Command]] = None - - #: If set, this is used by the group's :meth:`group` decorator - #: as the default :class:`Group` class. This is useful to make all - #: subgroups use a custom group class. - #: - #: If set to the special value :class:`type` (literally - #: ``group_class = type``), this group's class will be used as the - #: default class. This makes a custom group class continue to make - #: custom groups. - #: - #: .. versionadded:: 8.0 - group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None - # Literal[type] isn't valid, so use Type[type] - - def __init__( - self, - name: t.Optional[str] = None, - commands: t.Optional[ - t.Union[t.MutableMapping[str, Command], t.Sequence[Command]] - ] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - - if commands is None: - commands = {} - elif isinstance(commands, abc.Sequence): - commands = {c.name: c for c in commands if c.name is not None} - - #: The registered subcommands by their exported names. - self.commands: t.MutableMapping[str, Command] = commands - - def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: - """Registers another :class:`Command` with this group. If the name - is not provided, the name of the command is used. - """ - name = name or cmd.name - if name is None: - raise TypeError("Command has no name.") - _check_multicommand(self, name, cmd, register=True) - self.commands[name] = cmd - - @t.overload - def command(self, __func: t.Callable[..., t.Any]) -> Command: ... - - @t.overload - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... - - def command( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: - """A shortcut decorator for declaring and attaching a command to - the group. This takes the same arguments as :func:`command` and - immediately registers the created command with this group by - calling :meth:`add_command`. - - To customize the command class used, set the - :attr:`command_class` attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`command_class` attribute. - """ - from .decorators import command - - func: t.Optional[t.Callable[..., t.Any]] = None - - if args and callable(args[0]): - assert ( - len(args) == 1 and not kwargs - ), "Use 'command(**kwargs)(callable)' to provide arguments." - (func,) = args - args = () - - if self.command_class and kwargs.get("cls") is None: - kwargs["cls"] = self.command_class - - def decorator(f: t.Callable[..., t.Any]) -> Command: - cmd: Command = command(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - @t.overload - def group(self, __func: t.Callable[..., t.Any]) -> "Group": ... - - @t.overload - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: ... - - def group( - self, *args: t.Any, **kwargs: t.Any - ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: - """A shortcut decorator for declaring and attaching a group to - the group. This takes the same arguments as :func:`group` and - immediately registers the created group with this group by - calling :meth:`add_command`. - - To customize the group class used, set the :attr:`group_class` - attribute. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.0 - Added the :attr:`group_class` attribute. - """ - from .decorators import group - - func: t.Optional[t.Callable[..., t.Any]] = None - - if args and callable(args[0]): - assert ( - len(args) == 1 and not kwargs - ), "Use 'group(**kwargs)(callable)' to provide arguments." - (func,) = args - args = () - - if self.group_class is not None and kwargs.get("cls") is None: - if self.group_class is type: - kwargs["cls"] = type(self) - else: - kwargs["cls"] = self.group_class - - def decorator(f: t.Callable[..., t.Any]) -> "Group": - cmd: Group = group(*args, **kwargs)(f) - self.add_command(cmd) - return cmd - - if func is not None: - return decorator(func) - - return decorator - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - return self.commands.get(cmd_name) - - def list_commands(self, ctx: Context) -> t.List[str]: - return sorted(self.commands) - - -class CommandCollection(MultiCommand): - """A command collection is a multi command that merges multiple multi - commands together into one. This is a straightforward implementation - that accepts a list of different multi commands as sources and - provides all the commands for each of them. - - See :class:`MultiCommand` and :class:`Command` for the description of - ``name`` and ``attrs``. - """ - - def __init__( - self, - name: t.Optional[str] = None, - sources: t.Optional[t.List[MultiCommand]] = None, - **attrs: t.Any, - ) -> None: - super().__init__(name, **attrs) - #: The list of registered multi commands. - self.sources: t.List[MultiCommand] = sources or [] - - def add_source(self, multi_cmd: MultiCommand) -> None: - """Adds a new multi command to the chain dispatcher.""" - self.sources.append(multi_cmd) - - def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: - for source in self.sources: - rv = source.get_command(ctx, cmd_name) - - if rv is not None: - if self.chain: - _check_multicommand(self, cmd_name, rv) - - return rv - - return None - - def list_commands(self, ctx: Context) -> t.List[str]: - rv: t.Set[str] = set() - - for source in self.sources: - rv.update(source.list_commands(ctx)) - - return sorted(rv) - - -def _check_iter(value: t.Any) -> t.Iterator[t.Any]: - """Check if the value is iterable but not a string. Raises a type - error, or return an iterator over the value. - """ - if isinstance(value, str): - raise TypeError - - return iter(value) - - -class Parameter: - r"""A parameter to a command comes in two versions: they are either - :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently - not supported by design as some of the internals for parsing are - intentionally not finalized. - - Some settings are supported by both options and arguments. - - :param param_decls: the parameter declarations for this option or - argument. This is a list of flags or argument - names. - :param type: the type that should be used. Either a :class:`ParamType` - or a Python type. The latter is converted into the former - automatically if supported. - :param required: controls if this is optional or not. - :param default: the default value if omitted. This can also be a callable, - in which case it's invoked when the default is needed - without any arguments. - :param callback: A function to further process or validate the value - after type conversion. It is called as ``f(ctx, param, value)`` - and must return the value. It is called for all sources, - including prompts. - :param nargs: the number of arguments to match. If not ``1`` the return - value is a tuple instead of single value. The default for - nargs is ``1`` (except if the type is a tuple, then it's - the arity of the tuple). If ``nargs=-1``, all remaining - parameters are collected. - :param metavar: how the value is represented in the help page. - :param expose_value: if this is `True` then the value is passed onwards - to the command callback and stored on the context, - otherwise it's skipped. - :param is_eager: eager values are processed before non eager ones. This - should not be set for arguments or it will inverse the - order of processing. - :param envvar: a string or list of strings that are environment variables - that should be checked. - :param shell_complete: A function that returns custom shell - completions. Used instead of the param's type completion if - given. Takes ``ctx, param, incomplete`` and must return a list - of :class:`~click.shell_completion.CompletionItem` or a list of - strings. - - .. versionchanged:: 8.0 - ``process_value`` validates required parameters and bounded - ``nargs``, and invokes the parameter callback before returning - the value. This allows the callback to validate prompts. - ``full_process_value`` is removed. - - .. versionchanged:: 8.0 - ``autocompletion`` is renamed to ``shell_complete`` and has new - semantics described above. The old name is deprecated and will - be removed in 8.1, until then it will be wrapped to match the - new requirements. - - .. versionchanged:: 8.0 - For ``multiple=True, nargs>1``, the default must be a list of - tuples. - - .. versionchanged:: 8.0 - Setting a default is no longer required for ``nargs>1``, it will - default to ``None``. ``multiple=True`` or ``nargs=-1`` will - default to ``()``. - - .. versionchanged:: 7.1 - Empty environment variables are ignored rather than taking the - empty string value. This makes it possible for scripts to clear - variables if they can't unset them. - - .. versionchanged:: 2.0 - Changed signature for parameter callback to also be passed the - parameter. The old callback format will still work, but it will - raise a warning to give you a chance to migrate the code easier. - """ - - param_type_name = "parameter" - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - type: t.Optional[t.Union[types.ParamType, t.Any]] = None, - required: bool = False, - default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, - callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, - nargs: t.Optional[int] = None, - multiple: bool = False, - metavar: t.Optional[str] = None, - expose_value: bool = True, - is_eager: bool = False, - envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, - shell_complete: t.Optional[ - t.Callable[ - [Context, "Parameter", str], - t.Union[t.List["CompletionItem"], t.List[str]], - ] - ] = None, - ) -> None: - self.name: t.Optional[str] - self.opts: t.List[str] - self.secondary_opts: t.List[str] - self.name, self.opts, self.secondary_opts = self._parse_decls( - param_decls or (), expose_value - ) - self.type: types.ParamType = types.convert_type(type, default) - - # Default nargs to what the type tells us if we have that - # information available. - if nargs is None: - if self.type.is_composite: - nargs = self.type.arity - else: - nargs = 1 - - self.required = required - self.callback = callback - self.nargs = nargs - self.multiple = multiple - self.expose_value = expose_value - self.default = default - self.is_eager = is_eager - self.metavar = metavar - self.envvar = envvar - self._custom_shell_complete = shell_complete - - if __debug__: - if self.type.is_composite and nargs != self.type.arity: - raise ValueError( - f"'nargs' must be {self.type.arity} (or None) for" - f" type {self.type!r}, but it was {nargs}." - ) - - # Skip no default or callable default. - check_default = default if not callable(default) else None - - if check_default is not None: - if multiple: - try: - # Only check the first value against nargs. - check_default = next(_check_iter(check_default), None) - except TypeError: - raise ValueError( - "'default' must be a list when 'multiple' is true." - ) from None - - # Can be None for multiple with empty default. - if nargs != 1 and check_default is not None: - try: - _check_iter(check_default) - except TypeError: - if multiple: - message = ( - "'default' must be a list of lists when 'multiple' is" - " true and 'nargs' != 1." - ) - else: - message = "'default' must be a list when 'nargs' != 1." - - raise ValueError(message) from None - - if nargs > 1 and len(check_default) != nargs: - subject = "item length" if multiple else "length" - raise ValueError( - f"'default' {subject} must match nargs={nargs}." - ) - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - return { - "name": self.name, - "param_type_name": self.param_type_name, - "opts": self.opts, - "secondary_opts": self.secondary_opts, - "type": self.type.to_info_dict(), - "required": self.required, - "nargs": self.nargs, - "multiple": self.multiple, - "default": self.default, - "envvar": self.envvar, - } - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} {self.name}>" - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - raise NotImplementedError() - - @property - def human_readable_name(self) -> str: - """Returns the human readable name of this parameter. This is the - same as the name for options, but the metavar for arguments. - """ - return self.name # type: ignore - - def make_metavar(self) -> str: - if self.metavar is not None: - return self.metavar - - metavar = self.type.get_metavar(self) - - if metavar is None: - metavar = self.type.name.upper() - - if self.nargs != 1: - metavar += "..." - - return metavar - - @t.overload - def get_default( - self, ctx: Context, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: - """Get the default for the parameter. Tries - :meth:`Context.lookup_default` first, then the local default. - - :param ctx: Current context. - :param call: If the default is a callable, call it. Disable to - return the callable instead. - - .. versionchanged:: 8.0.2 - Type casting is no longer performed when getting a default. - - .. versionchanged:: 8.0.1 - Type casting can fail in resilient parsing mode. Invalid - defaults will not prevent showing help text. - - .. versionchanged:: 8.0 - Looks at ``ctx.default_map`` first. - - .. versionchanged:: 8.0 - Added the ``call`` parameter. - """ - value = ctx.lookup_default(self.name, call=False) # type: ignore - - if value is None: - value = self.default - - if call and callable(value): - value = value() - - return value - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - raise NotImplementedError() - - def consume_value( - self, ctx: Context, opts: t.Mapping[str, t.Any] - ) -> t.Tuple[t.Any, ParameterSource]: - value = opts.get(self.name) # type: ignore - source = ParameterSource.COMMANDLINE - - if value is None: - value = self.value_from_envvar(ctx) - source = ParameterSource.ENVIRONMENT - - if value is None: - value = ctx.lookup_default(self.name) # type: ignore - source = ParameterSource.DEFAULT_MAP - - if value is None: - value = self.get_default(ctx) - source = ParameterSource.DEFAULT - - return value, source - - def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: - """Convert and validate a value against the option's - :attr:`type`, :attr:`multiple`, and :attr:`nargs`. - """ - if value is None: - return () if self.multiple or self.nargs == -1 else None - - def check_iter(value: t.Any) -> t.Iterator[t.Any]: - try: - return _check_iter(value) - except TypeError: - # This should only happen when passing in args manually, - # the parser should construct an iterable when parsing - # the command line. - raise BadParameter( - _("Value must be an iterable."), ctx=ctx, param=self - ) from None - - if self.nargs == 1 or self.type.is_composite: - - def convert(value: t.Any) -> t.Any: - return self.type(value, param=self, ctx=ctx) - - elif self.nargs == -1: - - def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...] - return tuple(self.type(x, self, ctx) for x in check_iter(value)) - - else: # nargs > 1 - - def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...] - value = tuple(check_iter(value)) - - if len(value) != self.nargs: - raise BadParameter( - ngettext( - "Takes {nargs} values but 1 was given.", - "Takes {nargs} values but {len} were given.", - len(value), - ).format(nargs=self.nargs, len=len(value)), - ctx=ctx, - param=self, - ) - - return tuple(self.type(x, self, ctx) for x in value) - - if self.multiple: - return tuple(convert(x) for x in check_iter(value)) - - return convert(value) - - def value_is_missing(self, value: t.Any) -> bool: - if value is None: - return True - - if (self.nargs != 1 or self.multiple) and value == (): - return True - - return False - - def process_value(self, ctx: Context, value: t.Any) -> t.Any: - value = self.type_cast_value(ctx, value) - - if self.required and self.value_is_missing(value): - raise MissingParameter(ctx=ctx, param=self) - - if self.callback is not None: - value = self.callback(ctx, self, value) - - return value - - def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: - if self.envvar is None: - return None - - if isinstance(self.envvar, str): - rv = os.environ.get(self.envvar) - - if rv: - return rv - else: - for envvar in self.envvar: - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: - rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) - - if rv is not None and self.nargs != 1: - rv = self.type.split_envvar_value(rv) - - return rv - - def handle_parse_result( - self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] - ) -> t.Tuple[t.Any, t.List[str]]: - with augment_usage_errors(ctx, param=self): - value, source = self.consume_value(ctx, opts) - ctx.set_parameter_source(self.name, source) # type: ignore - - try: - value = self.process_value(ctx, value) - except Exception: - if not ctx.resilient_parsing: - raise - - value = None - - if self.expose_value: - ctx.params[self.name] = value # type: ignore - - return value, args - - def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: - pass - - def get_usage_pieces(self, ctx: Context) -> t.List[str]: - return [] - - def get_error_hint(self, ctx: Context) -> str: - """Get a stringified version of the param for use in error messages to - indicate which param caused the error. - """ - hint_list = self.opts or [self.human_readable_name] - return " / ".join(f"'{x}'" for x in hint_list) - - def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: - """Return a list of completions for the incomplete value. If a - ``shell_complete`` function was given during init, it is used. - Otherwise, the :attr:`type` - :meth:`~click.types.ParamType.shell_complete` function is used. - - :param ctx: Invocation context for this command. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - if self._custom_shell_complete is not None: - results = self._custom_shell_complete(ctx, self, incomplete) - - if results and isinstance(results[0], str): - from click.shell_completion import CompletionItem - - results = [CompletionItem(c) for c in results] - - return t.cast(t.List["CompletionItem"], results) - - return self.type.shell_complete(ctx, self, incomplete) - - -class Option(Parameter): - """Options are usually optional values on the command line and - have some extra features that arguments don't have. - - All other parameters are passed onwards to the parameter constructor. - - :param show_default: Show the default value for this option in its - help text. Values are not shown by default, unless - :attr:`Context.show_default` is ``True``. If this value is a - string, it shows that string in parentheses instead of the - actual value. This is particularly useful for dynamic options. - For single option boolean flags, the default remains hidden if - its value is ``False``. - :param show_envvar: Controls if an environment variable should be - shown on the help page. Normally, environment variables are not - shown. - :param prompt: If set to ``True`` or a non empty string then the - user will be prompted for input. If set to ``True`` the prompt - will be the option name capitalized. - :param confirmation_prompt: Prompt a second time to confirm the - value if it was prompted for. Can be set to a string instead of - ``True`` to customize the message. - :param prompt_required: If set to ``False``, the user will be - prompted for input only when the option was specified as a flag - without a value. - :param hide_input: If this is ``True`` then the input on the prompt - will be hidden from the user. This is useful for password input. - :param is_flag: forces this option to act as a flag. The default is - auto detection. - :param flag_value: which value should be used for this flag if it's - enabled. This is set to a boolean automatically if - the option string contains a slash to mark two options. - :param multiple: if this is set to `True` then the argument is accepted - multiple times and recorded. This is similar to ``nargs`` - in how it works but supports arbitrary number of - arguments. - :param count: this flag makes an option increment an integer. - :param allow_from_autoenv: if this is enabled then the value of this - parameter will be pulled from an environment - variable in case a prefix is defined on the - context. - :param help: the help string. - :param hidden: hide this option from help outputs. - :param attrs: Other command arguments described in :class:`Parameter`. - - .. versionchanged:: 8.1.0 - Help text indentation is cleaned here instead of only in the - ``@option`` decorator. - - .. versionchanged:: 8.1.0 - The ``show_default`` parameter overrides - ``Context.show_default``. - - .. versionchanged:: 8.1.0 - The default of a single option boolean flag is not shown if the - default value is ``False``. - - .. versionchanged:: 8.0.1 - ``type`` is detected from ``flag_value`` if given. - """ - - param_type_name = "option" - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - show_default: t.Union[bool, str, None] = None, - prompt: t.Union[bool, str] = False, - confirmation_prompt: t.Union[bool, str] = False, - prompt_required: bool = True, - hide_input: bool = False, - is_flag: t.Optional[bool] = None, - flag_value: t.Optional[t.Any] = None, - multiple: bool = False, - count: bool = False, - allow_from_autoenv: bool = True, - type: t.Optional[t.Union[types.ParamType, t.Any]] = None, - help: t.Optional[str] = None, - hidden: bool = False, - show_choices: bool = True, - show_envvar: bool = False, - **attrs: t.Any, - ) -> None: - if help: - help = inspect.cleandoc(help) - - default_is_missing = "default" not in attrs - super().__init__(param_decls, type=type, multiple=multiple, **attrs) - - if prompt is True: - if self.name is None: - raise TypeError("'name' is required with 'prompt=True'.") - - prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() - elif prompt is False: - prompt_text = None - else: - prompt_text = prompt - - self.prompt = prompt_text - self.confirmation_prompt = confirmation_prompt - self.prompt_required = prompt_required - self.hide_input = hide_input - self.hidden = hidden - - # If prompt is enabled but not required, then the option can be - # used as a flag to indicate using prompt or flag_value. - self._flag_needs_value = self.prompt is not None and not self.prompt_required - - if is_flag is None: - if flag_value is not None: - # Implicitly a flag because flag_value was set. - is_flag = True - elif self._flag_needs_value: - # Not a flag, but when used as a flag it shows a prompt. - is_flag = False - else: - # Implicitly a flag because flag options were given. - is_flag = bool(self.secondary_opts) - elif is_flag is False and not self._flag_needs_value: - # Not a flag, and prompt is not enabled, can be used as a - # flag if flag_value is set. - self._flag_needs_value = flag_value is not None - - self.default: t.Union[t.Any, t.Callable[[], t.Any]] - - if is_flag and default_is_missing and not self.required: - if multiple: - self.default = () - else: - self.default = False - - if flag_value is None: - flag_value = not self.default - - self.type: types.ParamType - if is_flag and type is None: - # Re-guess the type from the flag value instead of the - # default. - self.type = types.convert_type(None, flag_value) - - self.is_flag: bool = is_flag - self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) - self.flag_value: t.Any = flag_value - - # Counting - self.count = count - if count: - if type is None: - self.type = types.IntRange(min=0) - if default_is_missing: - self.default = 0 - - self.allow_from_autoenv = allow_from_autoenv - self.help = help - self.show_default = show_default - self.show_choices = show_choices - self.show_envvar = show_envvar - - if __debug__: - if self.nargs == -1: - raise TypeError("nargs=-1 is not supported for options.") - - if self.prompt and self.is_flag and not self.is_bool_flag: - raise TypeError("'prompt' is not valid for non-boolean flag.") - - if not self.is_bool_flag and self.secondary_opts: - raise TypeError("Secondary flag is not valid for non-boolean flag.") - - if self.is_bool_flag and self.hide_input and self.prompt is not None: - raise TypeError( - "'prompt' with 'hide_input' is not valid for boolean flag." - ) - - if self.count: - if self.multiple: - raise TypeError("'count' is not valid with 'multiple'.") - - if self.is_flag: - raise TypeError("'count' is not valid with 'is_flag'.") - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - help=self.help, - prompt=self.prompt, - is_flag=self.is_flag, - flag_value=self.flag_value, - count=self.count, - hidden=self.hidden, - ) - return info_dict - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - opts = [] - secondary_opts = [] - name = None - possible_names = [] - - for decl in decls: - if decl.isidentifier(): - if name is not None: - raise TypeError(f"Name '{name}' defined twice") - name = decl - else: - split_char = ";" if decl[:1] == "/" else "/" - if split_char in decl: - first, second = decl.split(split_char, 1) - first = first.rstrip() - if first: - possible_names.append(split_opt(first)) - opts.append(first) - second = second.lstrip() - if second: - secondary_opts.append(second.lstrip()) - if first == second: - raise ValueError( - f"Boolean option {decl!r} cannot use the" - " same flag for true/false." - ) - else: - possible_names.append(split_opt(decl)) - opts.append(decl) - - if name is None and possible_names: - possible_names.sort(key=lambda x: -len(x[0])) # group long options first - name = possible_names[0][1].replace("-", "_").lower() - if not name.isidentifier(): - name = None - - if name is None: - if not expose_value: - return None, opts, secondary_opts - raise TypeError( - f"Could not determine name for option with declarations {decls!r}" - ) - - if not opts and not secondary_opts: - raise TypeError( - f"No options defined but a name was passed ({name})." - " Did you mean to declare an argument instead? Did" - f" you mean to pass '--{name}'?" - ) - - return name, opts, secondary_opts - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - if self.multiple: - action = "append" - elif self.count: - action = "count" - else: - action = "store" - - if self.is_flag: - action = f"{action}_const" - - if self.is_bool_flag and self.secondary_opts: - parser.add_option( - obj=self, opts=self.opts, dest=self.name, action=action, const=True - ) - parser.add_option( - obj=self, - opts=self.secondary_opts, - dest=self.name, - action=action, - const=False, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - const=self.flag_value, - ) - else: - parser.add_option( - obj=self, - opts=self.opts, - dest=self.name, - action=action, - nargs=self.nargs, - ) - - def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: - if self.hidden: - return None - - any_prefix_is_slash = False - - def _write_opts(opts: t.Sequence[str]) -> str: - nonlocal any_prefix_is_slash - - rv, any_slashes = join_options(opts) - - if any_slashes: - any_prefix_is_slash = True - - if not self.is_flag and not self.count: - rv += f" {self.make_metavar()}" - - return rv - - rv = [_write_opts(self.opts)] - - if self.secondary_opts: - rv.append(_write_opts(self.secondary_opts)) - - help = self.help or "" - extra = [] - - if self.show_envvar: - envvar = self.envvar - - if envvar is None: - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - - if envvar is not None: - var_str = ( - envvar - if isinstance(envvar, str) - else ", ".join(str(d) for d in envvar) - ) - extra.append(_("env var: {var}").format(var=var_str)) - - # Temporarily enable resilient parsing to avoid type casting - # failing for the default. Might be possible to extend this to - # help formatting in general. - resilient = ctx.resilient_parsing - ctx.resilient_parsing = True - - try: - default_value = self.get_default(ctx, call=False) - finally: - ctx.resilient_parsing = resilient - - show_default = False - show_default_is_str = False - - if self.show_default is not None: - if isinstance(self.show_default, str): - show_default_is_str = show_default = True - else: - show_default = self.show_default - elif ctx.show_default is not None: - show_default = ctx.show_default - - if show_default_is_str or (show_default and (default_value is not None)): - if show_default_is_str: - default_string = f"({self.show_default})" - elif isinstance(default_value, (list, tuple)): - default_string = ", ".join(str(d) for d in default_value) - elif inspect.isfunction(default_value): - default_string = _("(dynamic)") - elif self.is_bool_flag and self.secondary_opts: - # For boolean flags that have distinct True/False opts, - # use the opt without prefix instead of the value. - default_string = split_opt( - (self.opts if default_value else self.secondary_opts)[0] - )[1] - elif self.is_bool_flag and not self.secondary_opts and not default_value: - default_string = "" - elif default_value == "": - default_string = '""' - else: - default_string = str(default_value) - - if default_string: - extra.append(_("default: {default}").format(default=default_string)) - - if ( - isinstance(self.type, types._NumberRangeBase) - # skip count with default range type - and not (self.count and self.type.min == 0 and self.type.max is None) - ): - range_str = self.type._describe_range() - - if range_str: - extra.append(range_str) - - if self.required: - extra.append(_("required")) - - if extra: - extra_str = "; ".join(extra) - help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" - - return ("; " if any_prefix_is_slash else " / ").join(rv), help - - @t.overload - def get_default( - self, ctx: Context, call: "te.Literal[True]" = True - ) -> t.Optional[t.Any]: ... - - @t.overload - def get_default( - self, ctx: Context, call: bool = ... - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: ... - - def get_default( - self, ctx: Context, call: bool = True - ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: - # If we're a non boolean flag our default is more complex because - # we need to look at all flags in the same group to figure out - # if we're the default one in which case we return the flag - # value as default. - if self.is_flag and not self.is_bool_flag: - for param in ctx.command.params: - if param.name == self.name and param.default: - return t.cast(Option, param).flag_value - - return None - - return super().get_default(ctx, call=call) - - def prompt_for_value(self, ctx: Context) -> t.Any: - """This is an alternative flow that can be activated in the full - value processing if a value does not exist. It will prompt the - user until a valid value exists and then returns the processed - value as result. - """ - assert self.prompt is not None - - # Calculate the default before prompting anything to be stable. - default = self.get_default(ctx) - - # If this is a prompt for a flag we need to handle this - # differently. - if self.is_bool_flag: - return confirm(self.prompt, default) - - return prompt( - self.prompt, - default=default, - type=self.type, - hide_input=self.hide_input, - show_choices=self.show_choices, - confirmation_prompt=self.confirmation_prompt, - value_proc=lambda x: self.process_value(ctx, x), - ) - - def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: - rv = super().resolve_envvar_value(ctx) - - if rv is not None: - return rv - - if ( - self.allow_from_autoenv - and ctx.auto_envvar_prefix is not None - and self.name is not None - ): - envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" - rv = os.environ.get(envvar) - - if rv: - return rv - - return None - - def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: - rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) - - if rv is None: - return None - - value_depth = (self.nargs != 1) + bool(self.multiple) - - if value_depth > 0: - rv = self.type.split_envvar_value(rv) - - if self.multiple and self.nargs != 1: - rv = batch(rv, self.nargs) - - return rv - - def consume_value( - self, ctx: Context, opts: t.Mapping[str, "Parameter"] - ) -> t.Tuple[t.Any, ParameterSource]: - value, source = super().consume_value(ctx, opts) - - # The parser will emit a sentinel value if the option can be - # given as a flag without a value. This is different from None - # to distinguish from the flag not being given at all. - if value is _flag_needs_value: - if self.prompt is not None and not ctx.resilient_parsing: - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - else: - value = self.flag_value - source = ParameterSource.COMMANDLINE - - elif ( - self.multiple - and value is not None - and any(v is _flag_needs_value for v in value) - ): - value = [self.flag_value if v is _flag_needs_value else v for v in value] - source = ParameterSource.COMMANDLINE - - # The value wasn't set, or used the param's default, prompt if - # prompting is enabled. - elif ( - source in {None, ParameterSource.DEFAULT} - and self.prompt is not None - and (self.required or self.prompt_required) - and not ctx.resilient_parsing - ): - value = self.prompt_for_value(ctx) - source = ParameterSource.PROMPT - - return value, source - - -class Argument(Parameter): - """Arguments are positional parameters to a command. They generally - provide fewer features than options but can have infinite ``nargs`` - and are required by default. - - All parameters are passed onwards to the constructor of :class:`Parameter`. - """ - - param_type_name = "argument" - - def __init__( - self, - param_decls: t.Sequence[str], - required: t.Optional[bool] = None, - **attrs: t.Any, - ) -> None: - if required is None: - if attrs.get("default") is not None: - required = False - else: - required = attrs.get("nargs", 1) > 0 - - if "multiple" in attrs: - raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") - - super().__init__(param_decls, required=required, **attrs) - - if __debug__: - if self.default is not None and self.nargs == -1: - raise TypeError("'default' is not supported for nargs=-1.") - - @property - def human_readable_name(self) -> str: - if self.metavar is not None: - return self.metavar - return self.name.upper() # type: ignore - - def make_metavar(self) -> str: - if self.metavar is not None: - return self.metavar - var = self.type.get_metavar(self) - if not var: - var = self.name.upper() # type: ignore - if not self.required: - var = f"[{var}]" - if self.nargs != 1: - var += "..." - return var - - def _parse_decls( - self, decls: t.Sequence[str], expose_value: bool - ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: - if not decls: - if not expose_value: - return None, [], [] - raise TypeError("Argument is marked as exposed, but does not have a name.") - if len(decls) == 1: - name = arg = decls[0] - name = name.replace("-", "_").lower() - else: - raise TypeError( - "Arguments take exactly one parameter declaration, got" - f" {len(decls)}." - ) - return name, [arg], [] - - def get_usage_pieces(self, ctx: Context) -> t.List[str]: - return [self.make_metavar()] - - def get_error_hint(self, ctx: Context) -> str: - return f"'{self.make_metavar()}'" - - def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: - parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/backend/venv39/lib/python3.9/site-packages/click/decorators.py b/backend/venv39/lib/python3.9/site-packages/click/decorators.py deleted file mode 100644 index bcf8906..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/decorators.py +++ /dev/null @@ -1,562 +0,0 @@ -import inspect -import types -import typing as t -from functools import update_wrapper -from gettext import gettext as _ - -from .core import Argument -from .core import Command -from .core import Context -from .core import Group -from .core import Option -from .core import Parameter -from .globals import get_current_context -from .utils import echo - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") -T = t.TypeVar("T") -_AnyCallable = t.Callable[..., t.Any] -FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, Command]) - - -def pass_context(f: "t.Callable[te.Concatenate[Context, P], R]") -> "t.Callable[P, R]": - """Marks a callback as wanting to receive the current context - object as first argument. - """ - - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - return f(get_current_context(), *args, **kwargs) - - return update_wrapper(new_func, f) - - -def pass_obj(f: "t.Callable[te.Concatenate[t.Any, P], R]") -> "t.Callable[P, R]": - """Similar to :func:`pass_context`, but only pass the object on the - context onwards (:attr:`Context.obj`). This is useful if that object - represents the state of a nested system. - """ - - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - return f(get_current_context().obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - -def make_pass_decorator( - object_type: t.Type[T], ensure: bool = False -) -> t.Callable[["t.Callable[te.Concatenate[T, P], R]"], "t.Callable[P, R]"]: - """Given an object type this creates a decorator that will work - similar to :func:`pass_obj` but instead of passing the object of the - current context, it will find the innermost context of type - :func:`object_type`. - - This generates a decorator that works roughly like this:: - - from functools import update_wrapper - - def decorator(f): - @pass_context - def new_func(ctx, *args, **kwargs): - obj = ctx.find_object(object_type) - return ctx.invoke(f, obj, *args, **kwargs) - return update_wrapper(new_func, f) - return decorator - - :param object_type: the type of the object to pass. - :param ensure: if set to `True`, a new object will be created and - remembered on the context if it's not there yet. - """ - - def decorator(f: "t.Callable[te.Concatenate[T, P], R]") -> "t.Callable[P, R]": - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> "R": - ctx = get_current_context() - - obj: t.Optional[T] - if ensure: - obj = ctx.ensure_object(object_type) - else: - obj = ctx.find_object(object_type) - - if obj is None: - raise RuntimeError( - "Managed to invoke callback without a context" - f" object of type {object_type.__name__!r}" - " existing." - ) - - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - return decorator - - -def pass_meta_key( - key: str, *, doc_description: t.Optional[str] = None -) -> "t.Callable[[t.Callable[te.Concatenate[t.Any, P], R]], t.Callable[P, R]]": - """Create a decorator that passes a key from - :attr:`click.Context.meta` as the first argument to the decorated - function. - - :param key: Key in ``Context.meta`` to pass. - :param doc_description: Description of the object being passed, - inserted into the decorator's docstring. Defaults to "the 'key' - key from Context.meta". - - .. versionadded:: 8.0 - """ - - def decorator(f: "t.Callable[te.Concatenate[t.Any, P], R]") -> "t.Callable[P, R]": - def new_func(*args: "P.args", **kwargs: "P.kwargs") -> R: - ctx = get_current_context() - obj = ctx.meta[key] - return ctx.invoke(f, obj, *args, **kwargs) - - return update_wrapper(new_func, f) - - if doc_description is None: - doc_description = f"the {key!r} key from :attr:`click.Context.meta`" - - decorator.__doc__ = ( - f"Decorator that passes {doc_description} as the first argument" - " to the decorated function." - ) - return decorator - - -CmdType = t.TypeVar("CmdType", bound=Command) - - -# variant: no call, directly as decorator for a function. -@t.overload -def command(name: _AnyCallable) -> Command: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) -@t.overload -def command( - name: t.Optional[str], - cls: t.Type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) -@t.overload -def command( - name: None = None, - *, - cls: t.Type[CmdType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], CmdType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def command( - name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Command]: ... - - -def command( - name: t.Union[t.Optional[str], _AnyCallable] = None, - cls: t.Optional[t.Type[CmdType]] = None, - **attrs: t.Any, -) -> t.Union[Command, t.Callable[[_AnyCallable], t.Union[Command, CmdType]]]: - r"""Creates a new :class:`Command` and uses the decorated function as - callback. This will also automatically attach all decorated - :func:`option`\s and :func:`argument`\s as parameters to the command. - - The name of the command defaults to the name of the function with - underscores replaced by dashes. If you want to change that, you can - pass the intended name as the first argument. - - All keyword arguments are forwarded to the underlying command class. - For the ``params`` argument, any decorated params are appended to - the end of the list. - - Once decorated the function turns into a :class:`Command` instance - that can be invoked as a command line utility or be attached to a - command :class:`Group`. - - :param name: the name of the command. This defaults to the function - name with underscores replaced by dashes. - :param cls: the command class to instantiate. This defaults to - :class:`Command`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - - .. versionchanged:: 8.1 - The ``params`` argument can be used. Decorated params are - appended to the end of the list. - """ - - func: t.Optional[t.Callable[[_AnyCallable], t.Any]] = None - - if callable(name): - func = name - name = None - assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." - assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." - - if cls is None: - cls = t.cast(t.Type[CmdType], Command) - - def decorator(f: _AnyCallable) -> CmdType: - if isinstance(f, Command): - raise TypeError("Attempted to convert a callback into a command twice.") - - attr_params = attrs.pop("params", None) - params = attr_params if attr_params is not None else [] - - try: - decorator_params = f.__click_params__ # type: ignore - except AttributeError: - pass - else: - del f.__click_params__ # type: ignore - params.extend(reversed(decorator_params)) - - if attrs.get("help") is None: - attrs["help"] = f.__doc__ - - if t.TYPE_CHECKING: - assert cls is not None - assert not callable(name) - - cmd = cls( - name=name or f.__name__.lower().replace("_", "-"), - callback=f, - params=params, - **attrs, - ) - cmd.__doc__ = f.__doc__ - return cmd - - if func is not None: - return decorator(func) - - return decorator - - -GrpType = t.TypeVar("GrpType", bound=Group) - - -# variant: no call, directly as decorator for a function. -@t.overload -def group(name: _AnyCallable) -> Group: ... - - -# variant: with positional name and with positional or keyword cls argument: -# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) -@t.overload -def group( - name: t.Optional[str], - cls: t.Type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) -@t.overload -def group( - name: None = None, - *, - cls: t.Type[GrpType], - **attrs: t.Any, -) -> t.Callable[[_AnyCallable], GrpType]: ... - - -# variant: with optional string name, no cls argument provided. -@t.overload -def group( - name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any -) -> t.Callable[[_AnyCallable], Group]: ... - - -def group( - name: t.Union[str, _AnyCallable, None] = None, - cls: t.Optional[t.Type[GrpType]] = None, - **attrs: t.Any, -) -> t.Union[Group, t.Callable[[_AnyCallable], t.Union[Group, GrpType]]]: - """Creates a new :class:`Group` with a function as callback. This - works otherwise the same as :func:`command` just that the `cls` - parameter is set to :class:`Group`. - - .. versionchanged:: 8.1 - This decorator can be applied without parentheses. - """ - if cls is None: - cls = t.cast(t.Type[GrpType], Group) - - if callable(name): - return command(cls=cls, **attrs)(name) - - return command(name, cls, **attrs) - - -def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: - if isinstance(f, Command): - f.params.append(param) - else: - if not hasattr(f, "__click_params__"): - f.__click_params__ = [] # type: ignore - - f.__click_params__.append(param) # type: ignore - - -def argument( - *param_decls: str, cls: t.Optional[t.Type[Argument]] = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an argument to the command. All positional arguments are - passed as parameter declarations to :class:`Argument`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Argument` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default argument class, refer to :class:`Argument` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the argument class to instantiate. This defaults to - :class:`Argument`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Argument - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def option( - *param_decls: str, cls: t.Optional[t.Type[Option]] = None, **attrs: t.Any -) -> t.Callable[[FC], FC]: - """Attaches an option to the command. All positional arguments are - passed as parameter declarations to :class:`Option`; all keyword - arguments are forwarded unchanged (except ``cls``). - This is equivalent to creating an :class:`Option` instance manually - and attaching it to the :attr:`Command.params` list. - - For the default option class, refer to :class:`Option` and - :class:`Parameter` for descriptions of parameters. - - :param cls: the option class to instantiate. This defaults to - :class:`Option`. - :param param_decls: Passed as positional arguments to the constructor of - ``cls``. - :param attrs: Passed as keyword arguments to the constructor of ``cls``. - """ - if cls is None: - cls = Option - - def decorator(f: FC) -> FC: - _param_memo(f, cls(param_decls, **attrs)) - return f - - return decorator - - -def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--yes`` option which shows a prompt before continuing if - not passed. If the prompt is declined, the program will exit. - - :param param_decls: One or more option names. Defaults to the single - value ``"--yes"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value: - ctx.abort() - - if not param_decls: - param_decls = ("--yes",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("callback", callback) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("prompt", "Do you want to continue?") - kwargs.setdefault("help", "Confirm the action without prompting.") - return option(*param_decls, **kwargs) - - -def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--password`` option which prompts for a password, hiding - input and asking to enter the value again for confirmation. - - :param param_decls: One or more option names. Defaults to the single - value ``"--password"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - if not param_decls: - param_decls = ("--password",) - - kwargs.setdefault("prompt", True) - kwargs.setdefault("confirmation_prompt", True) - kwargs.setdefault("hide_input", True) - return option(*param_decls, **kwargs) - - -def version_option( - version: t.Optional[str] = None, - *param_decls: str, - package_name: t.Optional[str] = None, - prog_name: t.Optional[str] = None, - message: t.Optional[str] = None, - **kwargs: t.Any, -) -> t.Callable[[FC], FC]: - """Add a ``--version`` option which immediately prints the version - number and exits the program. - - If ``version`` is not provided, Click will try to detect it using - :func:`importlib.metadata.version` to get the version for the - ``package_name``. On Python < 3.8, the ``importlib_metadata`` - backport must be installed. - - If ``package_name`` is not provided, Click will try to detect it by - inspecting the stack frames. This will be used to detect the - version, so it must match the name of the installed package. - - :param version: The version number to show. If not provided, Click - will try to detect it. - :param param_decls: One or more option names. Defaults to the single - value ``"--version"``. - :param package_name: The package name to detect the version from. If - not provided, Click will try to detect it. - :param prog_name: The name of the CLI to show in the message. If not - provided, it will be detected from the command. - :param message: The message to show. The values ``%(prog)s``, - ``%(package)s``, and ``%(version)s`` are available. Defaults to - ``"%(prog)s, version %(version)s"``. - :param kwargs: Extra arguments are passed to :func:`option`. - :raise RuntimeError: ``version`` could not be detected. - - .. versionchanged:: 8.0 - Add the ``package_name`` parameter, and the ``%(package)s`` - value for messages. - - .. versionchanged:: 8.0 - Use :mod:`importlib.metadata` instead of ``pkg_resources``. The - version is detected based on the package name, not the entry - point name. The Python package name must match the installed - package name, or be passed with ``package_name=``. - """ - if message is None: - message = _("%(prog)s, version %(version)s") - - if version is None and package_name is None: - frame = inspect.currentframe() - f_back = frame.f_back if frame is not None else None - f_globals = f_back.f_globals if f_back is not None else None - # break reference cycle - # https://docs.python.org/3/library/inspect.html#the-interpreter-stack - del frame - - if f_globals is not None: - package_name = f_globals.get("__name__") - - if package_name == "__main__": - package_name = f_globals.get("__package__") - - if package_name: - package_name = package_name.partition(".")[0] - - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value or ctx.resilient_parsing: - return - - nonlocal prog_name - nonlocal version - - if prog_name is None: - prog_name = ctx.find_root().info_name - - if version is None and package_name is not None: - metadata: t.Optional[types.ModuleType] - - try: - from importlib import metadata - except ImportError: - # Python < 3.8 - import importlib_metadata as metadata # type: ignore - - try: - version = metadata.version(package_name) # type: ignore - except metadata.PackageNotFoundError: # type: ignore - raise RuntimeError( - f"{package_name!r} is not installed. Try passing" - " 'package_name' instead." - ) from None - - if version is None: - raise RuntimeError( - f"Could not determine the version for {package_name!r} automatically." - ) - - echo( - message % {"prog": prog_name, "package": package_name, "version": version}, - color=ctx.color, - ) - ctx.exit() - - if not param_decls: - param_decls = ("--version",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show the version and exit.")) - kwargs["callback"] = callback - return option(*param_decls, **kwargs) - - -class HelpOption(Option): - """Pre-configured ``--help`` option which immediately prints the help page - and exits the program. - """ - - def __init__( - self, - param_decls: t.Optional[t.Sequence[str]] = None, - **kwargs: t.Any, - ) -> None: - if not param_decls: - param_decls = ("--help",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show this message and exit.")) - kwargs.setdefault("callback", self.show_help) - - super().__init__(param_decls, **kwargs) - - @staticmethod - def show_help(ctx: Context, param: Parameter, value: bool) -> None: - """Callback that print the help page on ```` and exits.""" - if value and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - -def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Decorator for the pre-configured ``--help`` option defined above. - - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - kwargs.setdefault("cls", HelpOption) - return option(*param_decls, **kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/click/exceptions.py b/backend/venv39/lib/python3.9/site-packages/click/exceptions.py deleted file mode 100644 index 0b83151..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/exceptions.py +++ /dev/null @@ -1,296 +0,0 @@ -import typing as t -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import get_text_stderr -from .globals import resolve_color_default -from .utils import echo -from .utils import format_filename - -if t.TYPE_CHECKING: - from .core import Command - from .core import Context - from .core import Parameter - - -def _join_param_hints( - param_hint: t.Optional[t.Union[t.Sequence[str], str]], -) -> t.Optional[str]: - if param_hint is not None and not isinstance(param_hint, str): - return " / ".join(repr(x) for x in param_hint) - - return param_hint - - -class ClickException(Exception): - """An exception that Click can handle and show to the user.""" - - #: The exit code for this exception. - exit_code = 1 - - def __init__(self, message: str) -> None: - super().__init__(message) - # The context will be removed by the time we print the message, so cache - # the color settings here to be used later on (in `show`) - self.show_color: t.Optional[bool] = resolve_color_default() - self.message = message - - def format_message(self) -> str: - return self.message - - def __str__(self) -> str: - return self.message - - def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: - if file is None: - file = get_text_stderr() - - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=self.show_color, - ) - - -class UsageError(ClickException): - """An internal exception that signals a usage error. This typically - aborts any further handling. - - :param message: the error message to display. - :param ctx: optionally the context that caused this error. Click will - fill in the context automatically in some situations. - """ - - exit_code = 2 - - def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: - super().__init__(message) - self.ctx = ctx - self.cmd: t.Optional[Command] = self.ctx.command if self.ctx else None - - def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: - if file is None: - file = get_text_stderr() - color = None - hint = "" - if ( - self.ctx is not None - and self.ctx.command.get_help_option(self.ctx) is not None - ): - hint = _("Try '{command} {option}' for help.").format( - command=self.ctx.command_path, option=self.ctx.help_option_names[0] - ) - hint = f"{hint}\n" - if self.ctx is not None: - color = self.ctx.color - echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) - echo( - _("Error: {message}").format(message=self.format_message()), - file=file, - color=color, - ) - - -class BadParameter(UsageError): - """An exception that formats out a standardized error message for a - bad parameter. This is useful when thrown from a callback or type as - Click will attach contextual information to it (for instance, which - parameter it is). - - .. versionadded:: 2.0 - - :param param: the parameter object that caused this error. This can - be left out, and Click will attach this info itself - if possible. - :param param_hint: a string that shows up as parameter name. This - can be used as alternative to `param` in cases - where custom validation should happen. If it is - a string it's used as such, if it's a list then - each item is quoted and separated. - """ - - def __init__( - self, - message: str, - ctx: t.Optional["Context"] = None, - param: t.Optional["Parameter"] = None, - param_hint: t.Optional[str] = None, - ) -> None: - super().__init__(message, ctx) - self.param = param - self.param_hint = param_hint - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - return _("Invalid value: {message}").format(message=self.message) - - return _("Invalid value for {param_hint}: {message}").format( - param_hint=_join_param_hints(param_hint), message=self.message - ) - - -class MissingParameter(BadParameter): - """Raised if click required an option or argument but it was not - provided when invoking the script. - - .. versionadded:: 4.0 - - :param param_type: a string that indicates the type of the parameter. - The default is to inherit the parameter type from - the given `param`. Valid values are ``'parameter'``, - ``'option'`` or ``'argument'``. - """ - - def __init__( - self, - message: t.Optional[str] = None, - ctx: t.Optional["Context"] = None, - param: t.Optional["Parameter"] = None, - param_hint: t.Optional[str] = None, - param_type: t.Optional[str] = None, - ) -> None: - super().__init__(message or "", ctx, param, param_hint) - self.param_type = param_type - - def format_message(self) -> str: - if self.param_hint is not None: - param_hint: t.Optional[str] = self.param_hint - elif self.param is not None: - param_hint = self.param.get_error_hint(self.ctx) # type: ignore - else: - param_hint = None - - param_hint = _join_param_hints(param_hint) - param_hint = f" {param_hint}" if param_hint else "" - - param_type = self.param_type - if param_type is None and self.param is not None: - param_type = self.param.param_type_name - - msg = self.message - if self.param is not None: - msg_extra = self.param.type.get_missing_message(self.param) - if msg_extra: - if msg: - msg += f". {msg_extra}" - else: - msg = msg_extra - - msg = f" {msg}" if msg else "" - - # Translate param_type for known types. - if param_type == "argument": - missing = _("Missing argument") - elif param_type == "option": - missing = _("Missing option") - elif param_type == "parameter": - missing = _("Missing parameter") - else: - missing = _("Missing {param_type}").format(param_type=param_type) - - return f"{missing}{param_hint}.{msg}" - - def __str__(self) -> str: - if not self.message: - param_name = self.param.name if self.param else None - return _("Missing parameter: {param_name}").format(param_name=param_name) - else: - return self.message - - -class NoSuchOption(UsageError): - """Raised if click attempted to handle an option that does not - exist. - - .. versionadded:: 4.0 - """ - - def __init__( - self, - option_name: str, - message: t.Optional[str] = None, - possibilities: t.Optional[t.Sequence[str]] = None, - ctx: t.Optional["Context"] = None, - ) -> None: - if message is None: - message = _("No such option: {name}").format(name=option_name) - - super().__init__(message, ctx) - self.option_name = option_name - self.possibilities = possibilities - - def format_message(self) -> str: - if not self.possibilities: - return self.message - - possibility_str = ", ".join(sorted(self.possibilities)) - suggest = ngettext( - "Did you mean {possibility}?", - "(Possible options: {possibilities})", - len(self.possibilities), - ).format(possibility=possibility_str, possibilities=possibility_str) - return f"{self.message} {suggest}" - - -class BadOptionUsage(UsageError): - """Raised if an option is generally supplied but the use of the option - was incorrect. This is for instance raised if the number of arguments - for an option is not correct. - - .. versionadded:: 4.0 - - :param option_name: the name of the option being used incorrectly. - """ - - def __init__( - self, option_name: str, message: str, ctx: t.Optional["Context"] = None - ) -> None: - super().__init__(message, ctx) - self.option_name = option_name - - -class BadArgumentUsage(UsageError): - """Raised if an argument is generally supplied but the use of the argument - was incorrect. This is for instance raised if the number of values - for an argument is not correct. - - .. versionadded:: 6.0 - """ - - -class FileError(ClickException): - """Raised if a file cannot be opened.""" - - def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: - if hint is None: - hint = _("unknown error") - - super().__init__(hint) - self.ui_filename: str = format_filename(filename) - self.filename = filename - - def format_message(self) -> str: - return _("Could not open file {filename!r}: {message}").format( - filename=self.ui_filename, message=self.message - ) - - -class Abort(RuntimeError): - """An internal signalling exception that signals Click to abort.""" - - -class Exit(RuntimeError): - """An exception that indicates that the application should exit with some - status code. - - :param code: the status code to exit with. - """ - - __slots__ = ("exit_code",) - - def __init__(self, code: int = 0) -> None: - self.exit_code: int = code diff --git a/backend/venv39/lib/python3.9/site-packages/click/formatting.py b/backend/venv39/lib/python3.9/site-packages/click/formatting.py deleted file mode 100644 index ddd2a2f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/formatting.py +++ /dev/null @@ -1,301 +0,0 @@ -import typing as t -from contextlib import contextmanager -from gettext import gettext as _ - -from ._compat import term_len -from .parser import split_opt - -# Can force a width. This is used by the test system -FORCED_WIDTH: t.Optional[int] = None - - -def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: - widths: t.Dict[int, int] = {} - - for row in rows: - for idx, col in enumerate(row): - widths[idx] = max(widths.get(idx, 0), term_len(col)) - - return tuple(y for x, y in sorted(widths.items())) - - -def iter_rows( - rows: t.Iterable[t.Tuple[str, str]], col_count: int -) -> t.Iterator[t.Tuple[str, ...]]: - for row in rows: - yield row + ("",) * (col_count - len(row)) - - -def wrap_text( - text: str, - width: int = 78, - initial_indent: str = "", - subsequent_indent: str = "", - preserve_paragraphs: bool = False, -) -> str: - """A helper function that intelligently wraps text. By default, it - assumes that it operates on a single paragraph of text but if the - `preserve_paragraphs` parameter is provided it will intelligently - handle paragraphs (defined by two empty lines). - - If paragraphs are handled, a paragraph can be prefixed with an empty - line containing the ``\\b`` character (``\\x08``) to indicate that - no rewrapping should happen in that block. - - :param text: the text that should be rewrapped. - :param width: the maximum width for the text. - :param initial_indent: the initial indent that should be placed on the - first line as a string. - :param subsequent_indent: the indent string that should be placed on - each consecutive line. - :param preserve_paragraphs: if this flag is set then the wrapping will - intelligently handle paragraphs. - """ - from ._textwrap import TextWrapper - - text = text.expandtabs() - wrapper = TextWrapper( - width, - initial_indent=initial_indent, - subsequent_indent=subsequent_indent, - replace_whitespace=False, - ) - if not preserve_paragraphs: - return wrapper.fill(text) - - p: t.List[t.Tuple[int, bool, str]] = [] - buf: t.List[str] = [] - indent = None - - def _flush_par() -> None: - if not buf: - return - if buf[0].strip() == "\b": - p.append((indent or 0, True, "\n".join(buf[1:]))) - else: - p.append((indent or 0, False, " ".join(buf))) - del buf[:] - - for line in text.splitlines(): - if not line: - _flush_par() - indent = None - else: - if indent is None: - orig_len = term_len(line) - line = line.lstrip() - indent = orig_len - term_len(line) - buf.append(line) - _flush_par() - - rv = [] - for indent, raw, text in p: - with wrapper.extra_indent(" " * indent): - if raw: - rv.append(wrapper.indent_only(text)) - else: - rv.append(wrapper.fill(text)) - - return "\n\n".join(rv) - - -class HelpFormatter: - """This class helps with formatting text-based help pages. It's - usually just needed for very special internal cases, but it's also - exposed so that developers can write their own fancy outputs. - - At present, it always writes into memory. - - :param indent_increment: the additional increment for each level. - :param width: the width for the text. This defaults to the terminal - width clamped to a maximum of 78. - """ - - def __init__( - self, - indent_increment: int = 2, - width: t.Optional[int] = None, - max_width: t.Optional[int] = None, - ) -> None: - import shutil - - self.indent_increment = indent_increment - if max_width is None: - max_width = 80 - if width is None: - width = FORCED_WIDTH - if width is None: - width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) - self.width = width - self.current_indent = 0 - self.buffer: t.List[str] = [] - - def write(self, string: str) -> None: - """Writes a unicode string into the internal buffer.""" - self.buffer.append(string) - - def indent(self) -> None: - """Increases the indentation.""" - self.current_indent += self.indent_increment - - def dedent(self) -> None: - """Decreases the indentation.""" - self.current_indent -= self.indent_increment - - def write_usage( - self, prog: str, args: str = "", prefix: t.Optional[str] = None - ) -> None: - """Writes a usage line into the buffer. - - :param prog: the program name. - :param args: whitespace separated list of arguments. - :param prefix: The prefix for the first line. Defaults to - ``"Usage: "``. - """ - if prefix is None: - prefix = f"{_('Usage:')} " - - usage_prefix = f"{prefix:>{self.current_indent}}{prog} " - text_width = self.width - self.current_indent - - if text_width >= (term_len(usage_prefix) + 20): - # The arguments will fit to the right of the prefix. - indent = " " * term_len(usage_prefix) - self.write( - wrap_text( - args, - text_width, - initial_indent=usage_prefix, - subsequent_indent=indent, - ) - ) - else: - # The prefix is too long, put the arguments on the next line. - self.write(usage_prefix) - self.write("\n") - indent = " " * (max(self.current_indent, term_len(prefix)) + 4) - self.write( - wrap_text( - args, text_width, initial_indent=indent, subsequent_indent=indent - ) - ) - - self.write("\n") - - def write_heading(self, heading: str) -> None: - """Writes a heading into the buffer.""" - self.write(f"{'':>{self.current_indent}}{heading}:\n") - - def write_paragraph(self) -> None: - """Writes a paragraph into the buffer.""" - if self.buffer: - self.write("\n") - - def write_text(self, text: str) -> None: - """Writes re-indented text into the buffer. This rewraps and - preserves paragraphs. - """ - indent = " " * self.current_indent - self.write( - wrap_text( - text, - self.width, - initial_indent=indent, - subsequent_indent=indent, - preserve_paragraphs=True, - ) - ) - self.write("\n") - - def write_dl( - self, - rows: t.Sequence[t.Tuple[str, str]], - col_max: int = 30, - col_spacing: int = 2, - ) -> None: - """Writes a definition list into the buffer. This is how options - and commands are usually formatted. - - :param rows: a list of two item tuples for the terms and values. - :param col_max: the maximum width of the first column. - :param col_spacing: the number of spaces between the first and - second column. - """ - rows = list(rows) - widths = measure_table(rows) - if len(widths) != 2: - raise TypeError("Expected two columns for definition list") - - first_col = min(widths[0], col_max) + col_spacing - - for first, second in iter_rows(rows, len(widths)): - self.write(f"{'':>{self.current_indent}}{first}") - if not second: - self.write("\n") - continue - if term_len(first) <= first_col - col_spacing: - self.write(" " * (first_col - term_len(first))) - else: - self.write("\n") - self.write(" " * (first_col + self.current_indent)) - - text_width = max(self.width - first_col - 2, 10) - wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) - lines = wrapped_text.splitlines() - - if lines: - self.write(f"{lines[0]}\n") - - for line in lines[1:]: - self.write(f"{'':>{first_col + self.current_indent}}{line}\n") - else: - self.write("\n") - - @contextmanager - def section(self, name: str) -> t.Iterator[None]: - """Helpful context manager that writes a paragraph, a heading, - and the indents. - - :param name: the section name that is written as heading. - """ - self.write_paragraph() - self.write_heading(name) - self.indent() - try: - yield - finally: - self.dedent() - - @contextmanager - def indentation(self) -> t.Iterator[None]: - """A context manager that increases the indentation.""" - self.indent() - try: - yield - finally: - self.dedent() - - def getvalue(self) -> str: - """Returns the buffer contents.""" - return "".join(self.buffer) - - -def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: - """Given a list of option strings this joins them in the most appropriate - way and returns them in the form ``(formatted_string, - any_prefix_is_slash)`` where the second item in the tuple is a flag that - indicates if any of the option prefixes was a slash. - """ - rv = [] - any_prefix_is_slash = False - - for opt in options: - prefix = split_opt(opt)[0] - - if prefix == "/": - any_prefix_is_slash = True - - rv.append((len(prefix), opt)) - - rv.sort(key=lambda x: x[0]) - return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/backend/venv39/lib/python3.9/site-packages/click/globals.py b/backend/venv39/lib/python3.9/site-packages/click/globals.py deleted file mode 100644 index 191e712..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/globals.py +++ /dev/null @@ -1,67 +0,0 @@ -import typing as t -from threading import local - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - -_local = local() - - -@t.overload -def get_current_context(silent: "te.Literal[False]" = False) -> "Context": ... - - -@t.overload -def get_current_context(silent: bool = ...) -> t.Optional["Context"]: ... - - -def get_current_context(silent: bool = False) -> t.Optional["Context"]: - """Returns the current click context. This can be used as a way to - access the current context object from anywhere. This is a more implicit - alternative to the :func:`pass_context` decorator. This function is - primarily useful for helpers such as :func:`echo` which might be - interested in changing its behavior based on the current context. - - To push the current context, :meth:`Context.scope` can be used. - - .. versionadded:: 5.0 - - :param silent: if set to `True` the return value is `None` if no context - is available. The default behavior is to raise a - :exc:`RuntimeError`. - """ - try: - return t.cast("Context", _local.stack[-1]) - except (AttributeError, IndexError) as e: - if not silent: - raise RuntimeError("There is no active click context.") from e - - return None - - -def push_context(ctx: "Context") -> None: - """Pushes a new context to the current stack.""" - _local.__dict__.setdefault("stack", []).append(ctx) - - -def pop_context() -> None: - """Removes the top level from the stack.""" - _local.stack.pop() - - -def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: - """Internal helper to get the default value of the color flag. If a - value is passed it's returned unchanged, otherwise it's looked up from - the current context. - """ - if color is not None: - return color - - ctx = get_current_context(silent=True) - - if ctx is not None: - return ctx.color - - return None diff --git a/backend/venv39/lib/python3.9/site-packages/click/parser.py b/backend/venv39/lib/python3.9/site-packages/click/parser.py deleted file mode 100644 index 600b843..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/parser.py +++ /dev/null @@ -1,531 +0,0 @@ -""" -This module started out as largely a copy paste from the stdlib's -optparse module with the features removed that we do not need from -optparse because we implement them in Click on a higher level (for -instance type handling, help formatting and a lot more). - -The plan is to remove more and more from here over time. - -The reason this is a different module and not optparse from the stdlib -is that there are differences in 2.x and 3.x about the error messages -generated and optparse in the stdlib uses gettext for no good reason -and might cause us issues. - -Click uses parts of optparse written by Gregory P. Ward and maintained -by the Python Software Foundation. This is limited to code in parser.py. - -Copyright 2001-2006 Gregory P. Ward. All rights reserved. -Copyright 2002-2006 Python Software Foundation. All rights reserved. -""" - -# This code uses parts of optparse written by Gregory P. Ward and -# maintained by the Python Software Foundation. -# Copyright 2001-2006 Gregory P. Ward -# Copyright 2002-2006 Python Software Foundation -import typing as t -from collections import deque -from gettext import gettext as _ -from gettext import ngettext - -from .exceptions import BadArgumentUsage -from .exceptions import BadOptionUsage -from .exceptions import NoSuchOption -from .exceptions import UsageError - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Argument as CoreArgument - from .core import Context - from .core import Option as CoreOption - from .core import Parameter as CoreParameter - -V = t.TypeVar("V") - -# Sentinel value that indicates an option was passed as a flag without a -# value but is not a flag option. Option.consume_value uses this to -# prompt or use the flag_value. -_flag_needs_value = object() - - -def _unpack_args( - args: t.Sequence[str], nargs_spec: t.Sequence[int] -) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: - """Given an iterable of arguments and an iterable of nargs specifications, - it returns a tuple with all the unpacked arguments at the first index - and all remaining arguments as the second. - - The nargs specification is the number of arguments that should be consumed - or `-1` to indicate that this position should eat up all the remainders. - - Missing items are filled with `None`. - """ - args = deque(args) - nargs_spec = deque(nargs_spec) - rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] - spos: t.Optional[int] = None - - def _fetch(c: "te.Deque[V]") -> t.Optional[V]: - try: - if spos is None: - return c.popleft() - else: - return c.pop() - except IndexError: - return None - - while nargs_spec: - nargs = _fetch(nargs_spec) - - if nargs is None: - continue - - if nargs == 1: - rv.append(_fetch(args)) - elif nargs > 1: - x = [_fetch(args) for _ in range(nargs)] - - # If we're reversed, we're pulling in the arguments in reverse, - # so we need to turn them around. - if spos is not None: - x.reverse() - - rv.append(tuple(x)) - elif nargs < 0: - if spos is not None: - raise TypeError("Cannot have two nargs < 0") - - spos = len(rv) - rv.append(None) - - # spos is the position of the wildcard (star). If it's not `None`, - # we fill it with the remainder. - if spos is not None: - rv[spos] = tuple(args) - args = [] - rv[spos + 1 :] = reversed(rv[spos + 1 :]) - - return tuple(rv), list(args) - - -def split_opt(opt: str) -> t.Tuple[str, str]: - first = opt[:1] - if first.isalnum(): - return "", opt - if opt[1:2] == first: - return opt[:2], opt[2:] - return first, opt[1:] - - -def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: - if ctx is None or ctx.token_normalize_func is None: - return opt - prefix, opt = split_opt(opt) - return f"{prefix}{ctx.token_normalize_func(opt)}" - - -def split_arg_string(string: str) -> t.List[str]: - """Split an argument string as with :func:`shlex.split`, but don't - fail if the string is incomplete. Ignores a missing closing quote or - incomplete escape sequence and uses the partial token as-is. - - .. code-block:: python - - split_arg_string("example 'my file") - ["example", "my file"] - - split_arg_string("example my\\") - ["example", "my"] - - :param string: String to split. - """ - import shlex - - lex = shlex.shlex(string, posix=True) - lex.whitespace_split = True - lex.commenters = "" - out = [] - - try: - for token in lex: - out.append(token) - except ValueError: - # Raised when end-of-string is reached in an invalid state. Use - # the partial token as-is. The quote or escape character is in - # lex.state, not lex.token. - out.append(lex.token) - - return out - - -class Option: - def __init__( - self, - obj: "CoreOption", - opts: t.Sequence[str], - dest: t.Optional[str], - action: t.Optional[str] = None, - nargs: int = 1, - const: t.Optional[t.Any] = None, - ): - self._short_opts = [] - self._long_opts = [] - self.prefixes: t.Set[str] = set() - - for opt in opts: - prefix, value = split_opt(opt) - if not prefix: - raise ValueError(f"Invalid start character for option ({opt})") - self.prefixes.add(prefix[0]) - if len(prefix) == 1 and len(value) == 1: - self._short_opts.append(opt) - else: - self._long_opts.append(opt) - self.prefixes.add(prefix) - - if action is None: - action = "store" - - self.dest = dest - self.action = action - self.nargs = nargs - self.const = const - self.obj = obj - - @property - def takes_value(self) -> bool: - return self.action in ("store", "append") - - def process(self, value: t.Any, state: "ParsingState") -> None: - if self.action == "store": - state.opts[self.dest] = value # type: ignore - elif self.action == "store_const": - state.opts[self.dest] = self.const # type: ignore - elif self.action == "append": - state.opts.setdefault(self.dest, []).append(value) # type: ignore - elif self.action == "append_const": - state.opts.setdefault(self.dest, []).append(self.const) # type: ignore - elif self.action == "count": - state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore - else: - raise ValueError(f"unknown action '{self.action}'") - state.order.append(self.obj) - - -class Argument: - def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): - self.dest = dest - self.nargs = nargs - self.obj = obj - - def process( - self, - value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], - state: "ParsingState", - ) -> None: - if self.nargs > 1: - assert value is not None - holes = sum(1 for x in value if x is None) - if holes == len(value): - value = None - elif holes != 0: - raise BadArgumentUsage( - _("Argument {name!r} takes {nargs} values.").format( - name=self.dest, nargs=self.nargs - ) - ) - - if self.nargs == -1 and self.obj.envvar is not None and value == (): - # Replace empty tuple with None so that a value from the - # environment may be tried. - value = None - - state.opts[self.dest] = value # type: ignore - state.order.append(self.obj) - - -class ParsingState: - def __init__(self, rargs: t.List[str]) -> None: - self.opts: t.Dict[str, t.Any] = {} - self.largs: t.List[str] = [] - self.rargs = rargs - self.order: t.List[CoreParameter] = [] - - -class OptionParser: - """The option parser is an internal class that is ultimately used to - parse options and arguments. It's modelled after optparse and brings - a similar but vastly simplified API. It should generally not be used - directly as the high level Click classes wrap it for you. - - It's not nearly as extensible as optparse or argparse as it does not - implement features that are implemented on a higher level (such as - types or defaults). - - :param ctx: optionally the :class:`~click.Context` where this parser - should go with. - """ - - def __init__(self, ctx: t.Optional["Context"] = None) -> None: - #: The :class:`~click.Context` for this parser. This might be - #: `None` for some advanced use cases. - self.ctx = ctx - #: This controls how the parser deals with interspersed arguments. - #: If this is set to `False`, the parser will stop on the first - #: non-option. Click uses this to implement nested subcommands - #: safely. - self.allow_interspersed_args: bool = True - #: This tells the parser how to deal with unknown options. By - #: default it will error out (which is sensible), but there is a - #: second mode where it will ignore it and continue processing - #: after shifting all the unknown options into the resulting args. - self.ignore_unknown_options: bool = False - - if ctx is not None: - self.allow_interspersed_args = ctx.allow_interspersed_args - self.ignore_unknown_options = ctx.ignore_unknown_options - - self._short_opt: t.Dict[str, Option] = {} - self._long_opt: t.Dict[str, Option] = {} - self._opt_prefixes = {"-", "--"} - self._args: t.List[Argument] = [] - - def add_option( - self, - obj: "CoreOption", - opts: t.Sequence[str], - dest: t.Optional[str], - action: t.Optional[str] = None, - nargs: int = 1, - const: t.Optional[t.Any] = None, - ) -> None: - """Adds a new option named `dest` to the parser. The destination - is not inferred (unlike with optparse) and needs to be explicitly - provided. Action can be any of ``store``, ``store_const``, - ``append``, ``append_const`` or ``count``. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - opts = [normalize_opt(opt, self.ctx) for opt in opts] - option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) - self._opt_prefixes.update(option.prefixes) - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - - def add_argument( - self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 - ) -> None: - """Adds a positional argument named `dest` to the parser. - - The `obj` can be used to identify the option in the order list - that is returned from the parser. - """ - self._args.append(Argument(obj, dest=dest, nargs=nargs)) - - def parse_args( - self, args: t.List[str] - ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: - """Parses positional arguments and returns ``(values, args, order)`` - for the parsed options and arguments as well as the leftover - arguments if there are any. The order is a list of objects as they - appear on the command line. If arguments appear multiple times they - will be memorized multiple times as well. - """ - state = ParsingState(args) - try: - self._process_args_for_options(state) - self._process_args_for_args(state) - except UsageError: - if self.ctx is None or not self.ctx.resilient_parsing: - raise - return state.opts, state.largs, state.order - - def _process_args_for_args(self, state: ParsingState) -> None: - pargs, args = _unpack_args( - state.largs + state.rargs, [x.nargs for x in self._args] - ) - - for idx, arg in enumerate(self._args): - arg.process(pargs[idx], state) - - state.largs = args - state.rargs = [] - - def _process_args_for_options(self, state: ParsingState) -> None: - while state.rargs: - arg = state.rargs.pop(0) - arglen = len(arg) - # Double dashes always handled explicitly regardless of what - # prefixes are valid. - if arg == "--": - return - elif arg[:1] in self._opt_prefixes and arglen > 1: - self._process_opts(arg, state) - elif self.allow_interspersed_args: - state.largs.append(arg) - else: - state.rargs.insert(0, arg) - return - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of - # [arg0, ..., arg(i-1)] (any options and their arguments will have - # been removed from largs). - # - # The while loop will usually consume 1 or more arguments per pass. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - def _match_long_opt( - self, opt: str, explicit_value: t.Optional[str], state: ParsingState - ) -> None: - if opt not in self._long_opt: - from difflib import get_close_matches - - possibilities = get_close_matches(opt, self._long_opt) - raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) - - option = self._long_opt[opt] - if option.takes_value: - # At this point it's safe to modify rargs by injecting the - # explicit value, because no exception is raised in this - # branch. This means that the inserted value will be fully - # consumed. - if explicit_value is not None: - state.rargs.insert(0, explicit_value) - - value = self._get_value_from_state(opt, option, state) - - elif explicit_value is not None: - raise BadOptionUsage( - opt, _("Option {name!r} does not take a value.").format(name=opt) - ) - - else: - value = None - - option.process(value, state) - - def _match_short_opt(self, arg: str, state: ParsingState) -> None: - stop = False - i = 1 - prefix = arg[0] - unknown_options = [] - - for ch in arg[1:]: - opt = normalize_opt(f"{prefix}{ch}", self.ctx) - option = self._short_opt.get(opt) - i += 1 - - if not option: - if self.ignore_unknown_options: - unknown_options.append(ch) - continue - raise NoSuchOption(opt, ctx=self.ctx) - if option.takes_value: - # Any characters left in arg? Pretend they're the - # next arg, and stop consuming characters of arg. - if i < len(arg): - state.rargs.insert(0, arg[i:]) - stop = True - - value = self._get_value_from_state(opt, option, state) - - else: - value = None - - option.process(value, state) - - if stop: - break - - # If we got any unknown options we recombine the string of the - # remaining options and re-attach the prefix, then report that - # to the state as new larg. This way there is basic combinatorics - # that can be achieved while still ignoring unknown arguments. - if self.ignore_unknown_options and unknown_options: - state.largs.append(f"{prefix}{''.join(unknown_options)}") - - def _get_value_from_state( - self, option_name: str, option: Option, state: ParsingState - ) -> t.Any: - nargs = option.nargs - - if len(state.rargs) < nargs: - if option.obj._flag_needs_value: - # Option allows omitting the value. - value = _flag_needs_value - else: - raise BadOptionUsage( - option_name, - ngettext( - "Option {name!r} requires an argument.", - "Option {name!r} requires {nargs} arguments.", - nargs, - ).format(name=option_name, nargs=nargs), - ) - elif nargs == 1: - next_rarg = state.rargs[0] - - if ( - option.obj._flag_needs_value - and isinstance(next_rarg, str) - and next_rarg[:1] in self._opt_prefixes - and len(next_rarg) > 1 - ): - # The next arg looks like the start of an option, don't - # use it as the value if omitting the value is allowed. - value = _flag_needs_value - else: - value = state.rargs.pop(0) - else: - value = tuple(state.rargs[:nargs]) - del state.rargs[:nargs] - - return value - - def _process_opts(self, arg: str, state: ParsingState) -> None: - explicit_value = None - # Long option handling happens in two parts. The first part is - # supporting explicitly attached values. In any case, we will try - # to long match the option first. - if "=" in arg: - long_opt, explicit_value = arg.split("=", 1) - else: - long_opt = arg - norm_long_opt = normalize_opt(long_opt, self.ctx) - - # At this point we will match the (assumed) long option through - # the long option matching code. Note that this allows options - # like "-foo" to be matched as long options. - try: - self._match_long_opt(norm_long_opt, explicit_value, state) - except NoSuchOption: - # At this point the long option matching failed, and we need - # to try with short options. However there is a special rule - # which says, that if we have a two character options prefix - # (applies to "--foo" for instance), we do not dispatch to the - # short option code and will instead raise the no option - # error. - if arg[:2] not in self._opt_prefixes: - self._match_short_opt(arg, state) - return - - if not self.ignore_unknown_options: - raise - - state.largs.append(arg) diff --git a/backend/venv39/lib/python3.9/site-packages/click/py.typed b/backend/venv39/lib/python3.9/site-packages/click/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/click/shell_completion.py b/backend/venv39/lib/python3.9/site-packages/click/shell_completion.py deleted file mode 100644 index 07d0f09..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/shell_completion.py +++ /dev/null @@ -1,603 +0,0 @@ -import os -import re -import typing as t -from gettext import gettext as _ - -from .core import Argument -from .core import BaseCommand -from .core import Context -from .core import MultiCommand -from .core import Option -from .core import Parameter -from .core import ParameterSource -from .parser import split_arg_string -from .utils import echo - - -def shell_complete( - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - instruction: str, -) -> int: - """Perform shell completion for the given CLI program. - - :param cli: Command being called. - :param ctx_args: Extra arguments to pass to - ``cli.make_context``. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - :param instruction: Value of ``complete_var`` with the completion - instruction and shell, in the form ``instruction_shell``. - :return: Status code to exit with. - """ - shell, _, instruction = instruction.partition("_") - comp_cls = get_completion_class(shell) - - if comp_cls is None: - return 1 - - comp = comp_cls(cli, ctx_args, prog_name, complete_var) - - if instruction == "source": - echo(comp.source()) - return 0 - - if instruction == "complete": - echo(comp.complete()) - return 0 - - return 1 - - -class CompletionItem: - """Represents a completion value and metadata about the value. The - default metadata is ``type`` to indicate special shell handling, - and ``help`` if a shell supports showing a help string next to the - value. - - Arbitrary parameters can be passed when creating the object, and - accessed using ``item.attr``. If an attribute wasn't passed, - accessing it returns ``None``. - - :param value: The completion suggestion. - :param type: Tells the shell script to provide special completion - support for the type. Click uses ``"dir"`` and ``"file"``. - :param help: String shown next to the value if supported. - :param kwargs: Arbitrary metadata. The built-in implementations - don't use this, but custom type completions paired with custom - shell support could use it. - """ - - __slots__ = ("value", "type", "help", "_info") - - def __init__( - self, - value: t.Any, - type: str = "plain", - help: t.Optional[str] = None, - **kwargs: t.Any, - ) -> None: - self.value: t.Any = value - self.type: str = type - self.help: t.Optional[str] = help - self._info = kwargs - - def __getattr__(self, name: str) -> t.Any: - return self._info.get(name) - - -# Only Bash >= 4.4 has the nosort option. -_SOURCE_BASH = """\ -%(complete_func)s() { - local IFS=$'\\n' - local response - - response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ -%(complete_var)s=bash_complete $1) - - for completion in $response; do - IFS=',' read type value <<< "$completion" - - if [[ $type == 'dir' ]]; then - COMPREPLY=() - compopt -o dirnames - elif [[ $type == 'file' ]]; then - COMPREPLY=() - compopt -o default - elif [[ $type == 'plain' ]]; then - COMPREPLY+=($value) - fi - done - - return 0 -} - -%(complete_func)s_setup() { - complete -o nosort -F %(complete_func)s %(prog_name)s -} - -%(complete_func)s_setup; -""" - -_SOURCE_ZSH = """\ -#compdef %(prog_name)s - -%(complete_func)s() { - local -a completions - local -a completions_with_descriptions - local -a response - (( ! $+commands[%(prog_name)s] )) && return 1 - - response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ -%(complete_var)s=zsh_complete %(prog_name)s)}") - - for type key descr in ${response}; do - if [[ "$type" == "plain" ]]; then - if [[ "$descr" == "_" ]]; then - completions+=("$key") - else - completions_with_descriptions+=("$key":"$descr") - fi - elif [[ "$type" == "dir" ]]; then - _path_files -/ - elif [[ "$type" == "file" ]]; then - _path_files -f - fi - done - - if [ -n "$completions_with_descriptions" ]; then - _describe -V unsorted completions_with_descriptions -U - fi - - if [ -n "$completions" ]; then - compadd -U -V unsorted -a completions - fi -} - -if [[ $zsh_eval_context[-1] == loadautofunc ]]; then - # autoload from fpath, call function directly - %(complete_func)s "$@" -else - # eval/source/. command, register function for later - compdef %(complete_func)s %(prog_name)s -fi -""" - -_SOURCE_FISH = """\ -function %(complete_func)s; - set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ -COMP_CWORD=(commandline -t) %(prog_name)s); - - for completion in $response; - set -l metadata (string split "," $completion); - - if test $metadata[1] = "dir"; - __fish_complete_directories $metadata[2]; - else if test $metadata[1] = "file"; - __fish_complete_path $metadata[2]; - else if test $metadata[1] = "plain"; - echo $metadata[2]; - end; - end; -end; - -complete --no-files --command %(prog_name)s --arguments \ -"(%(complete_func)s)"; -""" - - -class ShellComplete: - """Base class for providing shell completion support. A subclass for - a given shell will override attributes and methods to implement the - completion instructions (``source`` and ``complete``). - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param complete_var: Name of the environment variable that holds - the completion instruction. - - .. versionadded:: 8.0 - """ - - name: t.ClassVar[str] - """Name to register the shell as with :func:`add_completion_class`. - This is used in completion instructions (``{name}_source`` and - ``{name}_complete``). - """ - - source_template: t.ClassVar[str] - """Completion script template formatted by :meth:`source`. This must - be provided by subclasses. - """ - - def __init__( - self, - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - complete_var: str, - ) -> None: - self.cli = cli - self.ctx_args = ctx_args - self.prog_name = prog_name - self.complete_var = complete_var - - @property - def func_name(self) -> str: - """The name of the shell function defined by the completion - script. - """ - safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) - return f"_{safe_name}_completion" - - def source_vars(self) -> t.Dict[str, t.Any]: - """Vars for formatting :attr:`source_template`. - - By default this provides ``complete_func``, ``complete_var``, - and ``prog_name``. - """ - return { - "complete_func": self.func_name, - "complete_var": self.complete_var, - "prog_name": self.prog_name, - } - - def source(self) -> str: - """Produce the shell script that defines the completion - function. By default this ``%``-style formats - :attr:`source_template` with the dict returned by - :meth:`source_vars`. - """ - return self.source_template % self.source_vars() - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - """Use the env vars defined by the shell script to return a - tuple of ``args, incomplete``. This must be implemented by - subclasses. - """ - raise NotImplementedError - - def get_completions( - self, args: t.List[str], incomplete: str - ) -> t.List[CompletionItem]: - """Determine the context and last complete command or parameter - from the complete args. Call that object's ``shell_complete`` - method to get the completions for the incomplete value. - - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) - obj, incomplete = _resolve_incomplete(ctx, args, incomplete) - return obj.shell_complete(ctx, incomplete) - - def format_completion(self, item: CompletionItem) -> str: - """Format a completion item into the form recognized by the - shell script. This must be implemented by subclasses. - - :param item: Completion item to format. - """ - raise NotImplementedError - - def complete(self) -> str: - """Produce the completion data to send back to the shell. - - By default this calls :meth:`get_completion_args`, gets the - completions, then calls :meth:`format_completion` for each - completion. - """ - args, incomplete = self.get_completion_args() - completions = self.get_completions(args, incomplete) - out = [self.format_completion(item) for item in completions] - return "\n".join(out) - - -class BashComplete(ShellComplete): - """Shell completion for Bash.""" - - name = "bash" - source_template = _SOURCE_BASH - - @staticmethod - def _check_version() -> None: - import shutil - import subprocess - - bash_exe = shutil.which("bash") - - if bash_exe is None: - match = None - else: - output = subprocess.run( - [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], - stdout=subprocess.PIPE, - ) - match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) - - if match is not None: - major, minor = match.groups() - - if major < "4" or major == "4" and minor < "4": - echo( - _( - "Shell completion is not supported for Bash" - " versions older than 4.4." - ), - err=True, - ) - else: - echo( - _("Couldn't detect Bash version, shell completion is not supported."), - err=True, - ) - - def source(self) -> str: - self._check_version() - return super().source() - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type},{item.value}" - - -class ZshComplete(ShellComplete): - """Shell completion for Zsh.""" - - name = "zsh" - source_template = _SOURCE_ZSH - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - cword = int(os.environ["COMP_CWORD"]) - args = cwords[1:cword] - - try: - incomplete = cwords[cword] - except IndexError: - incomplete = "" - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" - - -class FishComplete(ShellComplete): - """Shell completion for Fish.""" - - name = "fish" - source_template = _SOURCE_FISH - - def get_completion_args(self) -> t.Tuple[t.List[str], str]: - cwords = split_arg_string(os.environ["COMP_WORDS"]) - incomplete = os.environ["COMP_CWORD"] - args = cwords[1:] - - # Fish stores the partial word in both COMP_WORDS and - # COMP_CWORD, remove it from complete args. - if incomplete and args and args[-1] == incomplete: - args.pop() - - return args, incomplete - - def format_completion(self, item: CompletionItem) -> str: - if item.help: - return f"{item.type},{item.value}\t{item.help}" - - return f"{item.type},{item.value}" - - -ShellCompleteType = t.TypeVar("ShellCompleteType", bound=t.Type[ShellComplete]) - - -_available_shells: t.Dict[str, t.Type[ShellComplete]] = { - "bash": BashComplete, - "fish": FishComplete, - "zsh": ZshComplete, -} - - -def add_completion_class( - cls: ShellCompleteType, name: t.Optional[str] = None -) -> ShellCompleteType: - """Register a :class:`ShellComplete` subclass under the given name. - The name will be provided by the completion instruction environment - variable during completion. - - :param cls: The completion class that will handle completion for the - shell. - :param name: Name to register the class under. Defaults to the - class's ``name`` attribute. - """ - if name is None: - name = cls.name - - _available_shells[name] = cls - - return cls - - -def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]: - """Look up a registered :class:`ShellComplete` subclass by the name - provided by the completion instruction environment variable. If the - name isn't registered, returns ``None``. - - :param shell: Name the class is registered under. - """ - return _available_shells.get(shell) - - -def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: - """Determine if the given parameter is an argument that can still - accept values. - - :param ctx: Invocation context for the command represented by the - parsed complete args. - :param param: Argument object being checked. - """ - if not isinstance(param, Argument): - return False - - assert param.name is not None - # Will be None if expose_value is False. - value = ctx.params.get(param.name) - return ( - param.nargs == -1 - or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE - or ( - param.nargs > 1 - and isinstance(value, (tuple, list)) - and len(value) < param.nargs - ) - ) - - -def _start_of_option(ctx: Context, value: str) -> bool: - """Check if the value looks like the start of an option.""" - if not value: - return False - - c = value[0] - return c in ctx._opt_prefixes - - -def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: - """Determine if the given parameter is an option that needs a value. - - :param args: List of complete args before the incomplete value. - :param param: Option object being checked. - """ - if not isinstance(param, Option): - return False - - if param.is_flag or param.count: - return False - - last_option = None - - for index, arg in enumerate(reversed(args)): - if index + 1 > param.nargs: - break - - if _start_of_option(ctx, arg): - last_option = arg - - return last_option is not None and last_option in param.opts - - -def _resolve_context( - cli: BaseCommand, - ctx_args: t.MutableMapping[str, t.Any], - prog_name: str, - args: t.List[str], -) -> Context: - """Produce the context hierarchy starting with the command and - traversing the complete arguments. This only follows the commands, - it doesn't trigger input prompts or callbacks. - - :param cli: Command being called. - :param prog_name: Name of the executable in the shell. - :param args: List of complete args before the incomplete value. - """ - ctx_args["resilient_parsing"] = True - ctx = cli.make_context(prog_name, args.copy(), **ctx_args) - args = ctx.protected_args + ctx.args - - while args: - command = ctx.command - - if isinstance(command, MultiCommand): - if not command.chain: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) - args = ctx.protected_args + ctx.args - else: - sub_ctx = ctx - - while args: - name, cmd, args = command.resolve_command(ctx, args) - - if cmd is None: - return ctx - - sub_ctx = cmd.make_context( - name, - args, - parent=ctx, - allow_extra_args=True, - allow_interspersed_args=False, - resilient_parsing=True, - ) - args = sub_ctx.args - - ctx = sub_ctx - args = [*sub_ctx.protected_args, *sub_ctx.args] - else: - break - - return ctx - - -def _resolve_incomplete( - ctx: Context, args: t.List[str], incomplete: str -) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: - """Find the Click object that will handle the completion of the - incomplete value. Return the object and the incomplete value. - - :param ctx: Invocation context for the command represented by - the parsed complete args. - :param args: List of complete args before the incomplete value. - :param incomplete: Value being completed. May be empty. - """ - # Different shells treat an "=" between a long option name and - # value differently. Might keep the value joined, return the "=" - # as a separate item, or return the split name and value. Always - # split and discard the "=" to make completion easier. - if incomplete == "=": - incomplete = "" - elif "=" in incomplete and _start_of_option(ctx, incomplete): - name, _, incomplete = incomplete.partition("=") - args.append(name) - - # The "--" marker tells Click to stop treating values as options - # even if they start with the option character. If it hasn't been - # given and the incomplete arg looks like an option, the current - # command will provide option name completions. - if "--" not in args and _start_of_option(ctx, incomplete): - return ctx.command, incomplete - - params = ctx.command.get_params(ctx) - - # If the last complete arg is an option name with an incomplete - # value, the option will provide value completions. - for param in params: - if _is_incomplete_option(ctx, args, param): - return param, incomplete - - # It's not an option name or value. The first argument without a - # parsed value will provide value completions. - for param in params: - if _is_incomplete_argument(ctx, param): - return param, incomplete - - # There were no unparsed arguments, the command may be a group that - # will provide command name completions. - return ctx.command, incomplete diff --git a/backend/venv39/lib/python3.9/site-packages/click/termui.py b/backend/venv39/lib/python3.9/site-packages/click/termui.py deleted file mode 100644 index c084f19..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/termui.py +++ /dev/null @@ -1,784 +0,0 @@ -import inspect -import io -import itertools -import sys -import typing as t -from gettext import gettext as _ - -from ._compat import isatty -from ._compat import strip_ansi -from .exceptions import Abort -from .exceptions import UsageError -from .globals import resolve_color_default -from .types import Choice -from .types import convert_type -from .types import ParamType -from .utils import echo -from .utils import LazyFile - -if t.TYPE_CHECKING: - from ._termui_impl import ProgressBar - -V = t.TypeVar("V") - -# The prompt functions to use. The doc tools currently override these -# functions to customize how they work. -visible_prompt_func: t.Callable[[str], str] = input - -_ansi_colors = { - "black": 30, - "red": 31, - "green": 32, - "yellow": 33, - "blue": 34, - "magenta": 35, - "cyan": 36, - "white": 37, - "reset": 39, - "bright_black": 90, - "bright_red": 91, - "bright_green": 92, - "bright_yellow": 93, - "bright_blue": 94, - "bright_magenta": 95, - "bright_cyan": 96, - "bright_white": 97, -} -_ansi_reset_all = "\033[0m" - - -def hidden_prompt_func(prompt: str) -> str: - import getpass - - return getpass.getpass(prompt) - - -def _build_prompt( - text: str, - suffix: str, - show_default: bool = False, - default: t.Optional[t.Any] = None, - show_choices: bool = True, - type: t.Optional[ParamType] = None, -) -> str: - prompt = text - if type is not None and show_choices and isinstance(type, Choice): - prompt += f" ({', '.join(map(str, type.choices))})" - if default is not None and show_default: - prompt = f"{prompt} [{_format_default(default)}]" - return f"{prompt}{suffix}" - - -def _format_default(default: t.Any) -> t.Any: - if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): - return default.name - - return default - - -def prompt( - text: str, - default: t.Optional[t.Any] = None, - hide_input: bool = False, - confirmation_prompt: t.Union[bool, str] = False, - type: t.Optional[t.Union[ParamType, t.Any]] = None, - value_proc: t.Optional[t.Callable[[str], t.Any]] = None, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, - show_choices: bool = True, -) -> t.Any: - """Prompts a user for input. This is a convenience function that can - be used to prompt a user for input later. - - If the user aborts the input by sending an interrupt signal, this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the text to show for the prompt. - :param default: the default value to use if no input happens. If this - is not given it will prompt until it's aborted. - :param hide_input: if this is set to true then the input value will - be hidden. - :param confirmation_prompt: Prompt a second time to confirm the - value. Can be set to a string instead of ``True`` to customize - the message. - :param type: the type to use to check the value against. - :param value_proc: if this parameter is provided it's a function that - is invoked instead of the type conversion to - convert a value. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - :param show_choices: Show or hide choices if the passed type is a Choice. - For example if type is a Choice of either day or week, - show_choices is true and text is "Group by" then the - prompt will be "Group by (day, week): ". - - .. versionadded:: 8.0 - ``confirmation_prompt`` can be a custom string. - - .. versionadded:: 7.0 - Added the ``show_choices`` parameter. - - .. versionadded:: 6.0 - Added unicode support for cmd.exe on Windows. - - .. versionadded:: 4.0 - Added the `err` parameter. - - """ - - def prompt_func(text: str) -> str: - f = hidden_prompt_func if hide_input else visible_prompt_func - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(text.rstrip(" "), nl=False, err=err) - # Echo a space to stdout to work around an issue where - # readline causes backspace to clear the whole line. - return f(" ") - except (KeyboardInterrupt, EOFError): - # getpass doesn't print a newline if the user aborts input with ^C. - # Allegedly this behavior is inherited from getpass(3). - # A doc bug has been filed at https://bugs.python.org/issue24711 - if hide_input: - echo(None, err=err) - raise Abort() from None - - if value_proc is None: - value_proc = convert_type(type, default) - - prompt = _build_prompt( - text, prompt_suffix, show_default, default, show_choices, type - ) - - if confirmation_prompt: - if confirmation_prompt is True: - confirmation_prompt = _("Repeat for confirmation") - - confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) - - while True: - while True: - value = prompt_func(prompt) - if value: - break - elif default is not None: - value = default - break - try: - result = value_proc(value) - except UsageError as e: - if hide_input: - echo(_("Error: The value you entered was invalid."), err=err) - else: - echo(_("Error: {e.message}").format(e=e), err=err) - continue - if not confirmation_prompt: - return result - while True: - value2 = prompt_func(confirmation_prompt) - is_empty = not value and not value2 - if value2 or is_empty: - break - if value == value2: - return result - echo(_("Error: The two entered values do not match."), err=err) - - -def confirm( - text: str, - default: t.Optional[bool] = False, - abort: bool = False, - prompt_suffix: str = ": ", - show_default: bool = True, - err: bool = False, -) -> bool: - """Prompts for confirmation (yes/no question). - - If the user aborts the input by sending a interrupt signal this - function will catch it and raise a :exc:`Abort` exception. - - :param text: the question to ask. - :param default: The default value to use when no input is given. If - ``None``, repeat until input is given. - :param abort: if this is set to `True` a negative answer aborts the - exception by raising :exc:`Abort`. - :param prompt_suffix: a suffix that should be added to the prompt. - :param show_default: shows or hides the default value in the prompt. - :param err: if set to true the file defaults to ``stderr`` instead of - ``stdout``, the same as with echo. - - .. versionchanged:: 8.0 - Repeat until input is given if ``default`` is ``None``. - - .. versionadded:: 4.0 - Added the ``err`` parameter. - """ - prompt = _build_prompt( - text, - prompt_suffix, - show_default, - "y/n" if default is None else ("Y/n" if default else "y/N"), - ) - - while True: - try: - # Write the prompt separately so that we get nice - # coloring through colorama on Windows - echo(prompt.rstrip(" "), nl=False, err=err) - # Echo a space to stdout to work around an issue where - # readline causes backspace to clear the whole line. - value = visible_prompt_func(" ").lower().strip() - except (KeyboardInterrupt, EOFError): - raise Abort() from None - if value in ("y", "yes"): - rv = True - elif value in ("n", "no"): - rv = False - elif default is not None and value == "": - rv = default - else: - echo(_("Error: invalid input"), err=err) - continue - break - if abort and not rv: - raise Abort() - return rv - - -def echo_via_pager( - text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], - color: t.Optional[bool] = None, -) -> None: - """This function takes a text and shows it via an environment specific - pager on stdout. - - .. versionchanged:: 3.0 - Added the `color` flag. - - :param text_or_generator: the text to page, or alternatively, a - generator emitting the text to page. - :param color: controls if the pager supports ANSI colors or not. The - default is autodetection. - """ - color = resolve_color_default(color) - - if inspect.isgeneratorfunction(text_or_generator): - i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() - elif isinstance(text_or_generator, str): - i = [text_or_generator] - else: - i = iter(t.cast(t.Iterable[str], text_or_generator)) - - # convert every element of i to a text type if necessary - text_generator = (el if isinstance(el, str) else str(el) for el in i) - - from ._termui_impl import pager - - return pager(itertools.chain(text_generator, "\n"), color) - - -def progressbar( - iterable: t.Optional[t.Iterable[V]] = None, - length: t.Optional[int] = None, - label: t.Optional[str] = None, - show_eta: bool = True, - show_percent: t.Optional[bool] = None, - show_pos: bool = False, - item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, - fill_char: str = "#", - empty_char: str = "-", - bar_template: str = "%(label)s [%(bar)s] %(info)s", - info_sep: str = " ", - width: int = 36, - file: t.Optional[t.TextIO] = None, - color: t.Optional[bool] = None, - update_min_steps: int = 1, -) -> "ProgressBar[V]": - """This function creates an iterable context manager that can be used - to iterate over something while showing a progress bar. It will - either iterate over the `iterable` or `length` items (that are counted - up). While iteration happens, this function will print a rendered - progress bar to the given `file` (defaults to stdout) and will attempt - to calculate remaining time and more. By default, this progress bar - will not be rendered if the file is not a terminal. - - The context manager creates the progress bar. When the context - manager is entered the progress bar is already created. With every - iteration over the progress bar, the iterable passed to the bar is - advanced and the bar is updated. When the context manager exits, - a newline is printed and the progress bar is finalized on screen. - - Note: The progress bar is currently designed for use cases where the - total progress can be expected to take at least several seconds. - Because of this, the ProgressBar class object won't display - progress that is considered too fast, and progress where the time - between steps is less than a second. - - No printing must happen or the progress bar will be unintentionally - destroyed. - - Example usage:: - - with progressbar(items) as bar: - for item in bar: - do_something_with(item) - - Alternatively, if no iterable is specified, one can manually update the - progress bar through the `update()` method instead of directly - iterating over the progress bar. The update method accepts the number - of steps to increment the bar with:: - - with progressbar(length=chunks.total_bytes) as bar: - for chunk in chunks: - process_chunk(chunk) - bar.update(chunks.bytes) - - The ``update()`` method also takes an optional value specifying the - ``current_item`` at the new position. This is useful when used - together with ``item_show_func`` to customize the output for each - manual step:: - - with click.progressbar( - length=total_size, - label='Unzipping archive', - item_show_func=lambda a: a.filename - ) as bar: - for archive in zip_file: - archive.extract() - bar.update(archive.size, archive) - - :param iterable: an iterable to iterate over. If not provided the length - is required. - :param length: the number of items to iterate over. By default the - progressbar will attempt to ask the iterator about its - length, which might or might not work. If an iterable is - also provided this parameter can be used to override the - length. If an iterable is not provided the progress bar - will iterate over a range of that length. - :param label: the label to show next to the progress bar. - :param show_eta: enables or disables the estimated time display. This is - automatically disabled if the length cannot be - determined. - :param show_percent: enables or disables the percentage display. The - default is `True` if the iterable has a length or - `False` if not. - :param show_pos: enables or disables the absolute position display. The - default is `False`. - :param item_show_func: A function called with the current item which - can return a string to show next to the progress bar. If the - function returns ``None`` nothing is shown. The current item can - be ``None``, such as when entering and exiting the bar. - :param fill_char: the character to use to show the filled part of the - progress bar. - :param empty_char: the character to use to show the non-filled part of - the progress bar. - :param bar_template: the format string to use as template for the bar. - The parameters in it are ``label`` for the label, - ``bar`` for the progress bar and ``info`` for the - info section. - :param info_sep: the separator between multiple info items (eta etc.) - :param width: the width of the progress bar in characters, 0 means full - terminal width - :param file: The file to write to. If this is not a terminal then - only the label is printed. - :param color: controls if the terminal supports ANSI colors or not. The - default is autodetection. This is only needed if ANSI - codes are included anywhere in the progress bar output - which is not the case by default. - :param update_min_steps: Render only when this many updates have - completed. This allows tuning for very fast iterators. - - .. versionchanged:: 8.0 - Output is shown even if execution time is less than 0.5 seconds. - - .. versionchanged:: 8.0 - ``item_show_func`` shows the current item, not the previous one. - - .. versionchanged:: 8.0 - Labels are echoed if the output is not a TTY. Reverts a change - in 7.0 that removed all output. - - .. versionadded:: 8.0 - Added the ``update_min_steps`` parameter. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. Added the ``update`` method to - the object. - - .. versionadded:: 2.0 - """ - from ._termui_impl import ProgressBar - - color = resolve_color_default(color) - return ProgressBar( - iterable=iterable, - length=length, - show_eta=show_eta, - show_percent=show_percent, - show_pos=show_pos, - item_show_func=item_show_func, - fill_char=fill_char, - empty_char=empty_char, - bar_template=bar_template, - info_sep=info_sep, - file=file, - label=label, - width=width, - color=color, - update_min_steps=update_min_steps, - ) - - -def clear() -> None: - """Clears the terminal screen. This will have the effect of clearing - the whole visible space of the terminal and moving the cursor to the - top left. This does not do anything if not connected to a terminal. - - .. versionadded:: 2.0 - """ - if not isatty(sys.stdout): - return - - # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor - echo("\033[2J\033[1;1H", nl=False) - - -def _interpret_color( - color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 -) -> str: - if isinstance(color, int): - return f"{38 + offset};5;{color:d}" - - if isinstance(color, (tuple, list)): - r, g, b = color - return f"{38 + offset};2;{r:d};{g:d};{b:d}" - - return str(_ansi_colors[color] + offset) - - -def style( - text: t.Any, - fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, - bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, - bold: t.Optional[bool] = None, - dim: t.Optional[bool] = None, - underline: t.Optional[bool] = None, - overline: t.Optional[bool] = None, - italic: t.Optional[bool] = None, - blink: t.Optional[bool] = None, - reverse: t.Optional[bool] = None, - strikethrough: t.Optional[bool] = None, - reset: bool = True, -) -> str: - """Styles a text with ANSI styles and returns the new string. By - default the styling is self contained which means that at the end - of the string a reset code is issued. This can be prevented by - passing ``reset=False``. - - Examples:: - - click.echo(click.style('Hello World!', fg='green')) - click.echo(click.style('ATTENTION!', blink=True)) - click.echo(click.style('Some things', reverse=True, fg='cyan')) - click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) - - Supported color names: - - * ``black`` (might be a gray) - * ``red`` - * ``green`` - * ``yellow`` (might be an orange) - * ``blue`` - * ``magenta`` - * ``cyan`` - * ``white`` (might be light gray) - * ``bright_black`` - * ``bright_red`` - * ``bright_green`` - * ``bright_yellow`` - * ``bright_blue`` - * ``bright_magenta`` - * ``bright_cyan`` - * ``bright_white`` - * ``reset`` (reset the color code only) - - If the terminal supports it, color may also be specified as: - - - An integer in the interval [0, 255]. The terminal must support - 8-bit/256-color mode. - - An RGB tuple of three integers in [0, 255]. The terminal must - support 24-bit/true-color mode. - - See https://en.wikipedia.org/wiki/ANSI_color and - https://gist.github.com/XVilka/8346728 for more information. - - :param text: the string to style with ansi codes. - :param fg: if provided this will become the foreground color. - :param bg: if provided this will become the background color. - :param bold: if provided this will enable or disable bold mode. - :param dim: if provided this will enable or disable dim mode. This is - badly supported. - :param underline: if provided this will enable or disable underline. - :param overline: if provided this will enable or disable overline. - :param italic: if provided this will enable or disable italic. - :param blink: if provided this will enable or disable blinking. - :param reverse: if provided this will enable or disable inverse - rendering (foreground becomes background and the - other way round). - :param strikethrough: if provided this will enable or disable - striking through text. - :param reset: by default a reset-all code is added at the end of the - string which means that styles do not carry over. This - can be disabled to compose styles. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. - - .. versionchanged:: 8.0 - Added support for 256 and RGB color codes. - - .. versionchanged:: 8.0 - Added the ``strikethrough``, ``italic``, and ``overline`` - parameters. - - .. versionchanged:: 7.0 - Added support for bright colors. - - .. versionadded:: 2.0 - """ - if not isinstance(text, str): - text = str(text) - - bits = [] - - if fg: - try: - bits.append(f"\033[{_interpret_color(fg)}m") - except KeyError: - raise TypeError(f"Unknown color {fg!r}") from None - - if bg: - try: - bits.append(f"\033[{_interpret_color(bg, 10)}m") - except KeyError: - raise TypeError(f"Unknown color {bg!r}") from None - - if bold is not None: - bits.append(f"\033[{1 if bold else 22}m") - if dim is not None: - bits.append(f"\033[{2 if dim else 22}m") - if underline is not None: - bits.append(f"\033[{4 if underline else 24}m") - if overline is not None: - bits.append(f"\033[{53 if overline else 55}m") - if italic is not None: - bits.append(f"\033[{3 if italic else 23}m") - if blink is not None: - bits.append(f"\033[{5 if blink else 25}m") - if reverse is not None: - bits.append(f"\033[{7 if reverse else 27}m") - if strikethrough is not None: - bits.append(f"\033[{9 if strikethrough else 29}m") - bits.append(text) - if reset: - bits.append(_ansi_reset_all) - return "".join(bits) - - -def unstyle(text: str) -> str: - """Removes ANSI styling information from a string. Usually it's not - necessary to use this function as Click's echo function will - automatically remove styling if necessary. - - .. versionadded:: 2.0 - - :param text: the text to remove style information from. - """ - return strip_ansi(text) - - -def secho( - message: t.Optional[t.Any] = None, - file: t.Optional[t.IO[t.AnyStr]] = None, - nl: bool = True, - err: bool = False, - color: t.Optional[bool] = None, - **styles: t.Any, -) -> None: - """This function combines :func:`echo` and :func:`style` into one - call. As such the following two calls are the same:: - - click.secho('Hello World!', fg='green') - click.echo(click.style('Hello World!', fg='green')) - - All keyword arguments are forwarded to the underlying functions - depending on which one they go with. - - Non-string types will be converted to :class:`str`. However, - :class:`bytes` are passed directly to :meth:`echo` without applying - style. If you want to style bytes that represent text, call - :meth:`bytes.decode` first. - - .. versionchanged:: 8.0 - A non-string ``message`` is converted to a string. Bytes are - passed through without style applied. - - .. versionadded:: 2.0 - """ - if message is not None and not isinstance(message, (bytes, bytearray)): - message = style(message, **styles) - - return echo(message, file=file, nl=nl, err=err, color=color) - - -def edit( - text: t.Optional[t.AnyStr] = None, - editor: t.Optional[str] = None, - env: t.Optional[t.Mapping[str, str]] = None, - require_save: bool = True, - extension: str = ".txt", - filename: t.Optional[str] = None, -) -> t.Optional[t.AnyStr]: - r"""Edits the given text in the defined editor. If an editor is given - (should be the full path to the executable but the regular operating - system search path is used for finding the executable) it overrides - the detected editor. Optionally, some environment variables can be - used. If the editor is closed without changes, `None` is returned. In - case a file is edited directly the return value is always `None` and - `require_save` and `extension` are ignored. - - If the editor cannot be opened a :exc:`UsageError` is raised. - - Note for Windows: to simplify cross-platform usage, the newlines are - automatically converted from POSIX to Windows and vice versa. As such, - the message here will have ``\n`` as newline markers. - - :param text: the text to edit. - :param editor: optionally the editor to use. Defaults to automatic - detection. - :param env: environment variables to forward to the editor. - :param require_save: if this is true, then not saving in the editor - will make the return value become `None`. - :param extension: the extension to tell the editor about. This defaults - to `.txt` but changing this might change syntax - highlighting. - :param filename: if provided it will edit this file instead of the - provided text contents. It will not use a temporary - file as an indirection in that case. - """ - from ._termui_impl import Editor - - ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) - - if filename is None: - return ed.edit(text) - - ed.edit_file(filename) - return None - - -def launch(url: str, wait: bool = False, locate: bool = False) -> int: - """This function launches the given URL (or filename) in the default - viewer application for this file type. If this is an executable, it - might launch the executable in a new session. The return value is - the exit code of the launched application. Usually, ``0`` indicates - success. - - Examples:: - - click.launch('https://click.palletsprojects.com/') - click.launch('/my/downloaded/file', locate=True) - - .. versionadded:: 2.0 - - :param url: URL or filename of the thing to launch. - :param wait: Wait for the program to exit before returning. This - only works if the launched program blocks. In particular, - ``xdg-open`` on Linux does not block. - :param locate: if this is set to `True` then instead of launching the - application associated with the URL it will attempt to - launch a file manager with the file located. This - might have weird effects if the URL does not point to - the filesystem. - """ - from ._termui_impl import open_url - - return open_url(url, wait=wait, locate=locate) - - -# If this is provided, getchar() calls into this instead. This is used -# for unittesting purposes. -_getchar: t.Optional[t.Callable[[bool], str]] = None - - -def getchar(echo: bool = False) -> str: - """Fetches a single character from the terminal and returns it. This - will always return a unicode character and under certain rare - circumstances this might return more than one character. The - situations which more than one character is returned is when for - whatever reason multiple characters end up in the terminal buffer or - standard input was not actually a terminal. - - Note that this will always read from the terminal, even if something - is piped into the standard input. - - Note for Windows: in rare cases when typing non-ASCII characters, this - function might wait for a second character and then return both at once. - This is because certain Unicode characters look like special-key markers. - - .. versionadded:: 2.0 - - :param echo: if set to `True`, the character read will also show up on - the terminal. The default is to not show it. - """ - global _getchar - - if _getchar is None: - from ._termui_impl import getchar as f - - _getchar = f - - return _getchar(echo) - - -def raw_terminal() -> t.ContextManager[int]: - from ._termui_impl import raw_terminal as f - - return f() - - -def pause(info: t.Optional[str] = None, err: bool = False) -> None: - """This command stops execution and waits for the user to press any - key to continue. This is similar to the Windows batch "pause" - command. If the program is not run through a terminal, this command - will instead do nothing. - - .. versionadded:: 2.0 - - .. versionadded:: 4.0 - Added the `err` parameter. - - :param info: The message to print before pausing. Defaults to - ``"Press any key to continue..."``. - :param err: if set to message goes to ``stderr`` instead of - ``stdout``, the same as with echo. - """ - if not isatty(sys.stdin) or not isatty(sys.stdout): - return - - if info is None: - info = _("Press any key to continue...") - - try: - if info: - echo(info, nl=False, err=err) - try: - getchar() - except (KeyboardInterrupt, EOFError): - pass - finally: - if info: - echo(err=err) diff --git a/backend/venv39/lib/python3.9/site-packages/click/testing.py b/backend/venv39/lib/python3.9/site-packages/click/testing.py deleted file mode 100644 index 772b215..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/testing.py +++ /dev/null @@ -1,483 +0,0 @@ -import contextlib -import io -import os -import shlex -import shutil -import sys -import tempfile -import typing as t -from types import TracebackType - -from . import _compat -from . import formatting -from . import termui -from . import utils -from ._compat import _find_binary_reader - -if t.TYPE_CHECKING: - from .core import BaseCommand - - -class EchoingStdin: - def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: - self._input = input - self._output = output - self._paused = False - - def __getattr__(self, x: str) -> t.Any: - return getattr(self._input, x) - - def _echo(self, rv: bytes) -> bytes: - if not self._paused: - self._output.write(rv) - - return rv - - def read(self, n: int = -1) -> bytes: - return self._echo(self._input.read(n)) - - def read1(self, n: int = -1) -> bytes: - return self._echo(self._input.read1(n)) # type: ignore - - def readline(self, n: int = -1) -> bytes: - return self._echo(self._input.readline(n)) - - def readlines(self) -> t.List[bytes]: - return [self._echo(x) for x in self._input.readlines()] - - def __iter__(self) -> t.Iterator[bytes]: - return iter(self._echo(x) for x in self._input) - - def __repr__(self) -> str: - return repr(self._input) - - -@contextlib.contextmanager -def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: - if stream is None: - yield - else: - stream._paused = True - yield - stream._paused = False - - -class _NamedTextIOWrapper(io.TextIOWrapper): - def __init__( - self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any - ) -> None: - super().__init__(buffer, **kwargs) - self._name = name - self._mode = mode - - @property - def name(self) -> str: - return self._name - - @property - def mode(self) -> str: - return self._mode - - -def make_input_stream( - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]], charset: str -) -> t.BinaryIO: - # Is already an input stream. - if hasattr(input, "read"): - rv = _find_binary_reader(t.cast(t.IO[t.Any], input)) - - if rv is not None: - return rv - - raise TypeError("Could not find binary reader for input stream.") - - if input is None: - input = b"" - elif isinstance(input, str): - input = input.encode(charset) - - return io.BytesIO(input) - - -class Result: - """Holds the captured result of an invoked CLI script.""" - - def __init__( - self, - runner: "CliRunner", - stdout_bytes: bytes, - stderr_bytes: t.Optional[bytes], - return_value: t.Any, - exit_code: int, - exception: t.Optional[BaseException], - exc_info: t.Optional[ - t.Tuple[t.Type[BaseException], BaseException, TracebackType] - ] = None, - ): - #: The runner that created the result - self.runner = runner - #: The standard output as bytes. - self.stdout_bytes = stdout_bytes - #: The standard error as bytes, or None if not available - self.stderr_bytes = stderr_bytes - #: The value returned from the invoked command. - #: - #: .. versionadded:: 8.0 - self.return_value = return_value - #: The exit code as integer. - self.exit_code = exit_code - #: The exception that happened if one did. - self.exception = exception - #: The traceback - self.exc_info = exc_info - - @property - def output(self) -> str: - """The (standard) output as unicode string.""" - return self.stdout - - @property - def stdout(self) -> str: - """The standard output as unicode string.""" - return self.stdout_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - @property - def stderr(self) -> str: - """The standard error as unicode string.""" - if self.stderr_bytes is None: - raise ValueError("stderr not separately captured") - return self.stderr_bytes.decode(self.runner.charset, "replace").replace( - "\r\n", "\n" - ) - - def __repr__(self) -> str: - exc_str = repr(self.exception) if self.exception else "okay" - return f"<{type(self).__name__} {exc_str}>" - - -class CliRunner: - """The CLI runner provides functionality to invoke a Click command line - script for unittesting purposes in a isolated environment. This only - works in single-threaded systems without any concurrency as it changes the - global interpreter state. - - :param charset: the character set for the input and output data. - :param env: a dictionary with environment variables for overriding. - :param echo_stdin: if this is set to `True`, then reading from stdin writes - to stdout. This is useful for showing examples in - some circumstances. Note that regular prompts - will automatically echo the input. - :param mix_stderr: if this is set to `False`, then stdout and stderr are - preserved as independent streams. This is useful for - Unix-philosophy apps that have predictable stdout and - noisy stderr, such that each may be measured - independently - """ - - def __init__( - self, - charset: str = "utf-8", - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - echo_stdin: bool = False, - mix_stderr: bool = True, - ) -> None: - self.charset = charset - self.env: t.Mapping[str, t.Optional[str]] = env or {} - self.echo_stdin = echo_stdin - self.mix_stderr = mix_stderr - - def get_default_prog_name(self, cli: "BaseCommand") -> str: - """Given a command object it will return the default program name - for it. The default is the `name` attribute or ``"root"`` if not - set. - """ - return cli.name or "root" - - def make_env( - self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None - ) -> t.Mapping[str, t.Optional[str]]: - """Returns the environment overrides for invoking a script.""" - rv = dict(self.env) - if overrides: - rv.update(overrides) - return rv - - @contextlib.contextmanager - def isolation( - self, - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - color: bool = False, - ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: - """A context manager that sets up the isolation for invoking of a - command line tool. This sets up stdin with the given input data - and `os.environ` with the overrides from the given dictionary. - This also rebinds some internals in Click to be mocked (like the - prompt functionality). - - This is automatically done in the :meth:`invoke` method. - - :param input: the input stream to put into sys.stdin. - :param env: the environment overrides as dictionary. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionchanged:: 8.0 - ``stderr`` is opened with ``errors="backslashreplace"`` - instead of the default ``"strict"``. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - """ - bytes_input = make_input_stream(input, self.charset) - echo_input = None - - old_stdin = sys.stdin - old_stdout = sys.stdout - old_stderr = sys.stderr - old_forced_width = formatting.FORCED_WIDTH - formatting.FORCED_WIDTH = 80 - - env = self.make_env(env) - - bytes_output = io.BytesIO() - - if self.echo_stdin: - bytes_input = echo_input = t.cast( - t.BinaryIO, EchoingStdin(bytes_input, bytes_output) - ) - - sys.stdin = text_input = _NamedTextIOWrapper( - bytes_input, encoding=self.charset, name="", mode="r" - ) - - if self.echo_stdin: - # Force unbuffered reads, otherwise TextIOWrapper reads a - # large chunk which is echoed early. - text_input._CHUNK_SIZE = 1 # type: ignore - - sys.stdout = _NamedTextIOWrapper( - bytes_output, encoding=self.charset, name="", mode="w" - ) - - bytes_error = None - if self.mix_stderr: - sys.stderr = sys.stdout - else: - bytes_error = io.BytesIO() - sys.stderr = _NamedTextIOWrapper( - bytes_error, - encoding=self.charset, - name="", - mode="w", - errors="backslashreplace", - ) - - @_pause_echo(echo_input) # type: ignore - def visible_input(prompt: t.Optional[str] = None) -> str: - sys.stdout.write(prompt or "") - val = text_input.readline().rstrip("\r\n") - sys.stdout.write(f"{val}\n") - sys.stdout.flush() - return val - - @_pause_echo(echo_input) # type: ignore - def hidden_input(prompt: t.Optional[str] = None) -> str: - sys.stdout.write(f"{prompt or ''}\n") - sys.stdout.flush() - return text_input.readline().rstrip("\r\n") - - @_pause_echo(echo_input) # type: ignore - def _getchar(echo: bool) -> str: - char = sys.stdin.read(1) - - if echo: - sys.stdout.write(char) - - sys.stdout.flush() - return char - - default_color = color - - def should_strip_ansi( - stream: t.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = None - ) -> bool: - if color is None: - return not default_color - return not color - - old_visible_prompt_func = termui.visible_prompt_func - old_hidden_prompt_func = termui.hidden_prompt_func - old__getchar_func = termui._getchar - old_should_strip_ansi = utils.should_strip_ansi # type: ignore - old__compat_should_strip_ansi = _compat.should_strip_ansi - termui.visible_prompt_func = visible_input - termui.hidden_prompt_func = hidden_input - termui._getchar = _getchar - utils.should_strip_ansi = should_strip_ansi # type: ignore - _compat.should_strip_ansi = should_strip_ansi - - old_env = {} - try: - for key, value in env.items(): - old_env[key] = os.environ.get(key) - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - yield (bytes_output, bytes_error) - finally: - for key, value in old_env.items(): - if value is None: - try: - del os.environ[key] - except Exception: - pass - else: - os.environ[key] = value - sys.stdout = old_stdout - sys.stderr = old_stderr - sys.stdin = old_stdin - termui.visible_prompt_func = old_visible_prompt_func - termui.hidden_prompt_func = old_hidden_prompt_func - termui._getchar = old__getchar_func - utils.should_strip_ansi = old_should_strip_ansi # type: ignore - _compat.should_strip_ansi = old__compat_should_strip_ansi - formatting.FORCED_WIDTH = old_forced_width - - def invoke( - self, - cli: "BaseCommand", - args: t.Optional[t.Union[str, t.Sequence[str]]] = None, - input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, - env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, - catch_exceptions: bool = True, - color: bool = False, - **extra: t.Any, - ) -> Result: - """Invokes a command in an isolated environment. The arguments are - forwarded directly to the command line script, the `extra` keyword - arguments are passed to the :meth:`~clickpkg.Command.main` function of - the command. - - This returns a :class:`Result` object. - - :param cli: the command to invoke - :param args: the arguments to invoke. It may be given as an iterable - or a string. When given as string it will be interpreted - as a Unix shell command. More details at - :func:`shlex.split`. - :param input: the input data for `sys.stdin`. - :param env: the environment overrides. - :param catch_exceptions: Whether to catch any other exceptions than - ``SystemExit``. - :param extra: the keyword arguments to pass to :meth:`main`. - :param color: whether the output should contain color codes. The - application can still override this explicitly. - - .. versionchanged:: 8.0 - The result object has the ``return_value`` attribute with - the value returned from the invoked command. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionchanged:: 3.0 - Added the ``catch_exceptions`` parameter. - - .. versionchanged:: 3.0 - The result object has the ``exc_info`` attribute with the - traceback if available. - """ - exc_info = None - with self.isolation(input=input, env=env, color=color) as outstreams: - return_value = None - exception: t.Optional[BaseException] = None - exit_code = 0 - - if isinstance(args, str): - args = shlex.split(args) - - try: - prog_name = extra.pop("prog_name") - except KeyError: - prog_name = self.get_default_prog_name(cli) - - try: - return_value = cli.main(args=args or (), prog_name=prog_name, **extra) - except SystemExit as e: - exc_info = sys.exc_info() - e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) - - if e_code is None: - e_code = 0 - - if e_code != 0: - exception = e - - if not isinstance(e_code, int): - sys.stdout.write(str(e_code)) - sys.stdout.write("\n") - e_code = 1 - - exit_code = e_code - - except Exception as e: - if not catch_exceptions: - raise - exception = e - exit_code = 1 - exc_info = sys.exc_info() - finally: - sys.stdout.flush() - stdout = outstreams[0].getvalue() - if self.mix_stderr: - stderr = None - else: - stderr = outstreams[1].getvalue() # type: ignore - - return Result( - runner=self, - stdout_bytes=stdout, - stderr_bytes=stderr, - return_value=return_value, - exit_code=exit_code, - exception=exception, - exc_info=exc_info, # type: ignore - ) - - @contextlib.contextmanager - def isolated_filesystem( - self, temp_dir: t.Optional[t.Union[str, "os.PathLike[str]"]] = None - ) -> t.Iterator[str]: - """A context manager that creates a temporary directory and - changes the current working directory to it. This isolates tests - that affect the contents of the CWD to prevent them from - interfering with each other. - - :param temp_dir: Create the temporary directory under this - directory. If given, the created directory is not removed - when exiting. - - .. versionchanged:: 8.0 - Added the ``temp_dir`` parameter. - """ - cwd = os.getcwd() - dt = tempfile.mkdtemp(dir=temp_dir) - os.chdir(dt) - - try: - yield dt - finally: - os.chdir(cwd) - - if temp_dir is None: - try: - shutil.rmtree(dt) - except OSError: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/click/types.py b/backend/venv39/lib/python3.9/site-packages/click/types.py deleted file mode 100644 index a70fd58..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/types.py +++ /dev/null @@ -1,1093 +0,0 @@ -import os -import stat -import sys -import typing as t -from datetime import datetime -from gettext import gettext as _ -from gettext import ngettext - -from ._compat import _get_argv_encoding -from ._compat import open_stream -from .exceptions import BadParameter -from .utils import format_filename -from .utils import LazyFile -from .utils import safecall - -if t.TYPE_CHECKING: - import typing_extensions as te - - from .core import Context - from .core import Parameter - from .shell_completion import CompletionItem - - -class ParamType: - """Represents the type of a parameter. Validates and converts values - from the command line or Python into the correct type. - - To implement a custom type, subclass and implement at least the - following: - - - The :attr:`name` class attribute must be set. - - Calling an instance of the type with ``None`` must return - ``None``. This is already implemented by default. - - :meth:`convert` must convert string values to the correct type. - - :meth:`convert` must accept values that are already the correct - type. - - It must be able to convert a value if the ``ctx`` and ``param`` - arguments are ``None``. This can occur when converting prompt - input. - """ - - is_composite: t.ClassVar[bool] = False - arity: t.ClassVar[int] = 1 - - #: the descriptive name of this type - name: str - - #: if a list of this type is expected and the value is pulled from a - #: string environment variable, this is what splits it up. `None` - #: means any whitespace. For all parameters the general rule is that - #: whitespace splits them up. The exception are paths and files which - #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on - #: Windows). - envvar_list_splitter: t.ClassVar[t.Optional[str]] = None - - def to_info_dict(self) -> t.Dict[str, t.Any]: - """Gather information that could be useful for a tool generating - user-facing documentation. - - Use :meth:`click.Context.to_info_dict` to traverse the entire - CLI structure. - - .. versionadded:: 8.0 - """ - # The class name without the "ParamType" suffix. - param_type = type(self).__name__.partition("ParamType")[0] - param_type = param_type.partition("ParameterType")[0] - - # Custom subclasses might not remember to set a name. - if hasattr(self, "name"): - name = self.name - else: - name = param_type - - return {"param_type": param_type, "name": name} - - def __call__( - self, - value: t.Any, - param: t.Optional["Parameter"] = None, - ctx: t.Optional["Context"] = None, - ) -> t.Any: - if value is not None: - return self.convert(value, param, ctx) - - def get_metavar(self, param: "Parameter") -> t.Optional[str]: - """Returns the metavar default for this param if it provides one.""" - - def get_missing_message(self, param: "Parameter") -> t.Optional[str]: - """Optionally might return extra information about a missing - parameter. - - .. versionadded:: 2.0 - """ - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - """Convert the value to the correct type. This is not called if - the value is ``None`` (the missing value). - - This must accept string values from the command line, as well as - values that are already the correct type. It may also convert - other compatible types. - - The ``param`` and ``ctx`` arguments may be ``None`` in certain - situations, such as when converting prompt input. - - If the value cannot be converted, call :meth:`fail` with a - descriptive message. - - :param value: The value to convert. - :param param: The parameter that is using this type to convert - its value. May be ``None``. - :param ctx: The current context that arrived at this value. May - be ``None``. - """ - return value - - def split_envvar_value(self, rv: str) -> t.Sequence[str]: - """Given a value from an environment variable this splits it up - into small chunks depending on the defined envvar list splitter. - - If the splitter is set to `None`, which means that whitespace splits, - then leading and trailing whitespace is ignored. Otherwise, leading - and trailing splitters usually lead to empty items being included. - """ - return (rv or "").split(self.envvar_list_splitter) - - def fail( - self, - message: str, - param: t.Optional["Parameter"] = None, - ctx: t.Optional["Context"] = None, - ) -> "t.NoReturn": - """Helper method to fail with an invalid value message.""" - raise BadParameter(message, ctx=ctx, param=param) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a list of - :class:`~click.shell_completion.CompletionItem` objects for the - incomplete value. Most types do not provide completions, but - some do, and this allows custom types to provide custom - completions as well. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - return [] - - -class CompositeParamType(ParamType): - is_composite = True - - @property - def arity(self) -> int: # type: ignore - raise NotImplementedError() - - -class FuncParamType(ParamType): - def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: - self.name: str = func.__name__ - self.func = func - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["func"] = self.func - return info_dict - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - try: - return self.func(value) - except ValueError: - try: - value = str(value) - except UnicodeError: - value = value.decode("utf-8", "replace") - - self.fail(value, param, ctx) - - -class UnprocessedParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - return value - - def __repr__(self) -> str: - return "UNPROCESSED" - - -class StringParamType(ParamType): - name = "text" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if isinstance(value, bytes): - enc = _get_argv_encoding() - try: - value = value.decode(enc) - except UnicodeError: - fs_enc = sys.getfilesystemencoding() - if fs_enc != enc: - try: - value = value.decode(fs_enc) - except UnicodeError: - value = value.decode("utf-8", "replace") - else: - value = value.decode("utf-8", "replace") - return value - return str(value) - - def __repr__(self) -> str: - return "STRING" - - -class Choice(ParamType): - """The choice type allows a value to be checked against a fixed set - of supported values. All of these values have to be strings. - - You should only pass a list or tuple of choices. Other iterables - (like generators) may lead to surprising results. - - The resulting value will always be one of the originally passed choices - regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` - being specified. - - See :ref:`choice-opts` for an example. - - :param case_sensitive: Set to false to make choices case - insensitive. Defaults to true. - """ - - name = "choice" - - def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: - self.choices = choices - self.case_sensitive = case_sensitive - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["choices"] = self.choices - info_dict["case_sensitive"] = self.case_sensitive - return info_dict - - def get_metavar(self, param: "Parameter") -> str: - choices_str = "|".join(self.choices) - - # Use curly braces to indicate a required argument. - if param.required and param.param_type_name == "argument": - return f"{{{choices_str}}}" - - # Use square braces to indicate an option or optional argument. - return f"[{choices_str}]" - - def get_missing_message(self, param: "Parameter") -> str: - return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - # Match through normalization and case sensitivity - # first do token_normalize_func, then lowercase - # preserve original `value` to produce an accurate message in - # `self.fail` - normed_value = value - normed_choices = {choice: choice for choice in self.choices} - - if ctx is not None and ctx.token_normalize_func is not None: - normed_value = ctx.token_normalize_func(value) - normed_choices = { - ctx.token_normalize_func(normed_choice): original - for normed_choice, original in normed_choices.items() - } - - if not self.case_sensitive: - normed_value = normed_value.casefold() - normed_choices = { - normed_choice.casefold(): original - for normed_choice, original in normed_choices.items() - } - - if normed_value in normed_choices: - return normed_choices[normed_value] - - choices_str = ", ".join(map(repr, self.choices)) - self.fail( - ngettext( - "{value!r} is not {choice}.", - "{value!r} is not one of {choices}.", - len(self.choices), - ).format(value=value, choice=choices_str, choices=choices_str), - param, - ctx, - ) - - def __repr__(self) -> str: - return f"Choice({list(self.choices)})" - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Complete choices that start with the incomplete value. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - str_choices = map(str, self.choices) - - if self.case_sensitive: - matched = (c for c in str_choices if c.startswith(incomplete)) - else: - incomplete = incomplete.lower() - matched = (c for c in str_choices if c.lower().startswith(incomplete)) - - return [CompletionItem(c) for c in matched] - - -class DateTime(ParamType): - """The DateTime type converts date strings into `datetime` objects. - - The format strings which are checked are configurable, but default to some - common (non-timezone aware) ISO 8601 formats. - - When specifying *DateTime* formats, you should only pass a list or a tuple. - Other iterables, like generators, may lead to surprising results. - - The format strings are processed using ``datetime.strptime``, and this - consequently defines the format strings which are allowed. - - Parsing is tried using each format, in order, and the first format which - parses successfully is used. - - :param formats: A list or tuple of date format strings, in the order in - which they should be tried. Defaults to - ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, - ``'%Y-%m-%d %H:%M:%S'``. - """ - - name = "datetime" - - def __init__(self, formats: t.Optional[t.Sequence[str]] = None): - self.formats: t.Sequence[str] = formats or [ - "%Y-%m-%d", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%d %H:%M:%S", - ] - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["formats"] = self.formats - return info_dict - - def get_metavar(self, param: "Parameter") -> str: - return f"[{'|'.join(self.formats)}]" - - def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: - try: - return datetime.strptime(value, format) - except ValueError: - return None - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if isinstance(value, datetime): - return value - - for format in self.formats: - converted = self._try_to_convert_date(value, format) - - if converted is not None: - return converted - - formats_str = ", ".join(map(repr, self.formats)) - self.fail( - ngettext( - "{value!r} does not match the format {format}.", - "{value!r} does not match the formats {formats}.", - len(self.formats), - ).format(value=value, format=formats_str, formats=formats_str), - param, - ctx, - ) - - def __repr__(self) -> str: - return "DateTime" - - -class _NumberParamTypeBase(ParamType): - _number_class: t.ClassVar[t.Type[t.Any]] - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - try: - return self._number_class(value) - except ValueError: - self.fail( - _("{value!r} is not a valid {number_type}.").format( - value=value, number_type=self.name - ), - param, - ctx, - ) - - -class _NumberRangeBase(_NumberParamTypeBase): - def __init__( - self, - min: t.Optional[float] = None, - max: t.Optional[float] = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - self.min = min - self.max = max - self.min_open = min_open - self.max_open = max_open - self.clamp = clamp - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - min=self.min, - max=self.max, - min_open=self.min_open, - max_open=self.max_open, - clamp=self.clamp, - ) - return info_dict - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - import operator - - rv = super().convert(value, param, ctx) - lt_min: bool = self.min is not None and ( - operator.le if self.min_open else operator.lt - )(rv, self.min) - gt_max: bool = self.max is not None and ( - operator.ge if self.max_open else operator.gt - )(rv, self.max) - - if self.clamp: - if lt_min: - return self._clamp(self.min, 1, self.min_open) # type: ignore - - if gt_max: - return self._clamp(self.max, -1, self.max_open) # type: ignore - - if lt_min or gt_max: - self.fail( - _("{value} is not in the range {range}.").format( - value=rv, range=self._describe_range() - ), - param, - ctx, - ) - - return rv - - def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: - """Find the valid value to clamp to bound in the given - direction. - - :param bound: The boundary value. - :param dir: 1 or -1 indicating the direction to move. - :param open: If true, the range does not include the bound. - """ - raise NotImplementedError - - def _describe_range(self) -> str: - """Describe the range for use in help text.""" - if self.min is None: - op = "<" if self.max_open else "<=" - return f"x{op}{self.max}" - - if self.max is None: - op = ">" if self.min_open else ">=" - return f"x{op}{self.min}" - - lop = "<" if self.min_open else "<=" - rop = "<" if self.max_open else "<=" - return f"{self.min}{lop}x{rop}{self.max}" - - def __repr__(self) -> str: - clamp = " clamped" if self.clamp else "" - return f"<{type(self).__name__} {self._describe_range()}{clamp}>" - - -class IntParamType(_NumberParamTypeBase): - name = "integer" - _number_class = int - - def __repr__(self) -> str: - return "INT" - - -class IntRange(_NumberRangeBase, IntParamType): - """Restrict an :data:`click.INT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "integer range" - - def _clamp( # type: ignore - self, bound: int, dir: "te.Literal[1, -1]", open: bool - ) -> int: - if not open: - return bound - - return bound + dir - - -class FloatParamType(_NumberParamTypeBase): - name = "float" - _number_class = float - - def __repr__(self) -> str: - return "FLOAT" - - -class FloatRange(_NumberRangeBase, FloatParamType): - """Restrict a :data:`click.FLOAT` value to a range of accepted - values. See :ref:`ranges`. - - If ``min`` or ``max`` are not passed, any value is accepted in that - direction. If ``min_open`` or ``max_open`` are enabled, the - corresponding boundary is not included in the range. - - If ``clamp`` is enabled, a value outside the range is clamped to the - boundary instead of failing. This is not supported if either - boundary is marked ``open``. - - .. versionchanged:: 8.0 - Added the ``min_open`` and ``max_open`` parameters. - """ - - name = "float range" - - def __init__( - self, - min: t.Optional[float] = None, - max: t.Optional[float] = None, - min_open: bool = False, - max_open: bool = False, - clamp: bool = False, - ) -> None: - super().__init__( - min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp - ) - - if (min_open or max_open) and clamp: - raise TypeError("Clamping is not supported for open bounds.") - - def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: - if not open: - return bound - - # Could use Python 3.9's math.nextafter here, but clamping an - # open float range doesn't seem to be particularly useful. It's - # left up to the user to write a callback to do it if needed. - raise RuntimeError("Clamping is not supported for open bounds.") - - -class BoolParamType(ParamType): - name = "boolean" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - if value in {False, True}: - return bool(value) - - norm = value.strip().lower() - - if norm in {"1", "true", "t", "yes", "y", "on"}: - return True - - if norm in {"0", "false", "f", "no", "n", "off"}: - return False - - self.fail( - _("{value!r} is not a valid boolean.").format(value=value), param, ctx - ) - - def __repr__(self) -> str: - return "BOOL" - - -class UUIDParameterType(ParamType): - name = "uuid" - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - import uuid - - if isinstance(value, uuid.UUID): - return value - - value = value.strip() - - try: - return uuid.UUID(value) - except ValueError: - self.fail( - _("{value!r} is not a valid UUID.").format(value=value), param, ctx - ) - - def __repr__(self) -> str: - return "UUID" - - -class File(ParamType): - """Declares a parameter to be a file for reading or writing. The file - is automatically closed once the context tears down (after the command - finished working). - - Files can be opened for reading or writing. The special value ``-`` - indicates stdin or stdout depending on the mode. - - By default, the file is opened for reading text data, but it can also be - opened in binary mode or for writing. The encoding parameter can be used - to force a specific encoding. - - The `lazy` flag controls if the file should be opened immediately or upon - first IO. The default is to be non-lazy for standard input and output - streams as well as files opened for reading, `lazy` otherwise. When opening a - file lazily for reading, it is still opened temporarily for validation, but - will not be held open until first IO. lazy is mainly useful when opening - for writing to avoid creating the file until it is needed. - - Files can also be opened atomically in which case all writes go into a - separate file in the same folder and upon completion the file will - be moved over to the original location. This is useful if a file - regularly read by other users is modified. - - See :ref:`file-args` for more information. - - .. versionchanged:: 2.0 - Added the ``atomic`` parameter. - """ - - name = "filename" - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - lazy: t.Optional[bool] = None, - atomic: bool = False, - ) -> None: - self.mode = mode - self.encoding = encoding - self.errors = errors - self.lazy = lazy - self.atomic = atomic - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update(mode=self.mode, encoding=self.encoding) - return info_dict - - def resolve_lazy_flag(self, value: "t.Union[str, os.PathLike[str]]") -> bool: - if self.lazy is not None: - return self.lazy - if os.fspath(value) == "-": - return False - elif "w" in self.mode: - return True - return False - - def convert( - self, - value: t.Union[str, "os.PathLike[str]", t.IO[t.Any]], - param: t.Optional["Parameter"], - ctx: t.Optional["Context"], - ) -> t.IO[t.Any]: - if _is_file_like(value): - return value - - value = t.cast("t.Union[str, os.PathLike[str]]", value) - - try: - lazy = self.resolve_lazy_flag(value) - - if lazy: - lf = LazyFile( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - if ctx is not None: - ctx.call_on_close(lf.close_intelligently) - - return t.cast(t.IO[t.Any], lf) - - f, should_close = open_stream( - value, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - - # If a context is provided, we automatically close the file - # at the end of the context execution (or flush out). If a - # context does not exist, it's the caller's responsibility to - # properly close the file. This for instance happens when the - # type is used with prompts. - if ctx is not None: - if should_close: - ctx.call_on_close(safecall(f.close)) - else: - ctx.call_on_close(safecall(f.flush)) - - return f - except OSError as e: - self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a special completion marker that tells the completion - system to use the shell to provide file path completions. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - return [CompletionItem(incomplete, type="file")] - - -def _is_file_like(value: t.Any) -> "te.TypeGuard[t.IO[t.Any]]": - return hasattr(value, "read") or hasattr(value, "write") - - -class Path(ParamType): - """The ``Path`` type is similar to the :class:`File` type, but - returns the filename instead of an open file. Various checks can be - enabled to validate the type of file and permissions. - - :param exists: The file or directory needs to exist for the value to - be valid. If this is not set to ``True``, and the file does not - exist, then all further checks are silently skipped. - :param file_okay: Allow a file as a value. - :param dir_okay: Allow a directory as a value. - :param readable: if true, a readable check is performed. - :param writable: if true, a writable check is performed. - :param executable: if true, an executable check is performed. - :param resolve_path: Make the value absolute and resolve any - symlinks. A ``~`` is not expanded, as this is supposed to be - done by the shell only. - :param allow_dash: Allow a single dash as a value, which indicates - a standard stream (but does not open it). Use - :func:`~click.open_file` to handle opening this value. - :param path_type: Convert the incoming path value to this type. If - ``None``, keep Python's default, which is ``str``. Useful to - convert to :class:`pathlib.Path`. - - .. versionchanged:: 8.1 - Added the ``executable`` parameter. - - .. versionchanged:: 8.0 - Allow passing ``path_type=pathlib.Path``. - - .. versionchanged:: 6.0 - Added the ``allow_dash`` parameter. - """ - - envvar_list_splitter: t.ClassVar[str] = os.path.pathsep - - def __init__( - self, - exists: bool = False, - file_okay: bool = True, - dir_okay: bool = True, - writable: bool = False, - readable: bool = True, - resolve_path: bool = False, - allow_dash: bool = False, - path_type: t.Optional[t.Type[t.Any]] = None, - executable: bool = False, - ): - self.exists = exists - self.file_okay = file_okay - self.dir_okay = dir_okay - self.readable = readable - self.writable = writable - self.executable = executable - self.resolve_path = resolve_path - self.allow_dash = allow_dash - self.type = path_type - - if self.file_okay and not self.dir_okay: - self.name: str = _("file") - elif self.dir_okay and not self.file_okay: - self.name = _("directory") - else: - self.name = _("path") - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict.update( - exists=self.exists, - file_okay=self.file_okay, - dir_okay=self.dir_okay, - writable=self.writable, - readable=self.readable, - allow_dash=self.allow_dash, - ) - return info_dict - - def coerce_path_result( - self, value: "t.Union[str, os.PathLike[str]]" - ) -> "t.Union[str, bytes, os.PathLike[str]]": - if self.type is not None and not isinstance(value, self.type): - if self.type is str: - return os.fsdecode(value) - elif self.type is bytes: - return os.fsencode(value) - else: - return t.cast("os.PathLike[str]", self.type(value)) - - return value - - def convert( - self, - value: "t.Union[str, os.PathLike[str]]", - param: t.Optional["Parameter"], - ctx: t.Optional["Context"], - ) -> "t.Union[str, bytes, os.PathLike[str]]": - rv = value - - is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") - - if not is_dash: - if self.resolve_path: - # os.path.realpath doesn't resolve symlinks on Windows - # until Python 3.8. Use pathlib for now. - import pathlib - - rv = os.fsdecode(pathlib.Path(rv).resolve()) - - try: - st = os.stat(rv) - except OSError: - if not self.exists: - return self.coerce_path_result(rv) - self.fail( - _("{name} {filename!r} does not exist.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if not self.file_okay and stat.S_ISREG(st.st_mode): - self.fail( - _("{name} {filename!r} is a file.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - if not self.dir_okay and stat.S_ISDIR(st.st_mode): - self.fail( - _("{name} {filename!r} is a directory.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.readable and not os.access(rv, os.R_OK): - self.fail( - _("{name} {filename!r} is not readable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.writable and not os.access(rv, os.W_OK): - self.fail( - _("{name} {filename!r} is not writable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - if self.executable and not os.access(value, os.X_OK): - self.fail( - _("{name} {filename!r} is not executable.").format( - name=self.name.title(), filename=format_filename(value) - ), - param, - ctx, - ) - - return self.coerce_path_result(rv) - - def shell_complete( - self, ctx: "Context", param: "Parameter", incomplete: str - ) -> t.List["CompletionItem"]: - """Return a special completion marker that tells the completion - system to use the shell to provide path completions for only - directories or any paths. - - :param ctx: Invocation context for this command. - :param param: The parameter that is requesting completion. - :param incomplete: Value being completed. May be empty. - - .. versionadded:: 8.0 - """ - from click.shell_completion import CompletionItem - - type = "dir" if self.dir_okay and not self.file_okay else "file" - return [CompletionItem(incomplete, type=type)] - - -class Tuple(CompositeParamType): - """The default behavior of Click is to apply a type on a value directly. - This works well in most cases, except for when `nargs` is set to a fixed - count and different types should be used for different items. In this - case the :class:`Tuple` type can be used. This type can only be used - if `nargs` is set to a fixed number. - - For more information see :ref:`tuple-type`. - - This can be selected by using a Python tuple literal as a type. - - :param types: a list of types that should be used for the tuple items. - """ - - def __init__(self, types: t.Sequence[t.Union[t.Type[t.Any], ParamType]]) -> None: - self.types: t.Sequence[ParamType] = [convert_type(ty) for ty in types] - - def to_info_dict(self) -> t.Dict[str, t.Any]: - info_dict = super().to_info_dict() - info_dict["types"] = [t.to_info_dict() for t in self.types] - return info_dict - - @property - def name(self) -> str: # type: ignore - return f"<{' '.join(ty.name for ty in self.types)}>" - - @property - def arity(self) -> int: # type: ignore - return len(self.types) - - def convert( - self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] - ) -> t.Any: - len_type = len(self.types) - len_value = len(value) - - if len_value != len_type: - self.fail( - ngettext( - "{len_type} values are required, but {len_value} was given.", - "{len_type} values are required, but {len_value} were given.", - len_value, - ).format(len_type=len_type, len_value=len_value), - param=param, - ctx=ctx, - ) - - return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) - - -def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: - """Find the most appropriate :class:`ParamType` for the given Python - type. If the type isn't provided, it can be inferred from a default - value. - """ - guessed_type = False - - if ty is None and default is not None: - if isinstance(default, (tuple, list)): - # If the default is empty, ty will remain None and will - # return STRING. - if default: - item = default[0] - - # A tuple of tuples needs to detect the inner types. - # Can't call convert recursively because that would - # incorrectly unwind the tuple to a single type. - if isinstance(item, (tuple, list)): - ty = tuple(map(type, item)) - else: - ty = type(item) - else: - ty = type(default) - - guessed_type = True - - if isinstance(ty, tuple): - return Tuple(ty) - - if isinstance(ty, ParamType): - return ty - - if ty is str or ty is None: - return STRING - - if ty is int: - return INT - - if ty is float: - return FLOAT - - if ty is bool: - return BOOL - - if guessed_type: - return STRING - - if __debug__: - try: - if issubclass(ty, ParamType): - raise AssertionError( - f"Attempted to use an uninstantiated parameter type ({ty})." - ) - except TypeError: - # ty is an instance (correct), so issubclass fails. - pass - - return FuncParamType(ty) - - -#: A dummy parameter type that just does nothing. From a user's -#: perspective this appears to just be the same as `STRING` but -#: internally no string conversion takes place if the input was bytes. -#: This is usually useful when working with file paths as they can -#: appear in bytes and unicode. -#: -#: For path related uses the :class:`Path` type is a better choice but -#: there are situations where an unprocessed type is useful which is why -#: it is is provided. -#: -#: .. versionadded:: 4.0 -UNPROCESSED = UnprocessedParamType() - -#: A unicode string parameter type which is the implicit default. This -#: can also be selected by using ``str`` as type. -STRING = StringParamType() - -#: An integer parameter. This can also be selected by using ``int`` as -#: type. -INT = IntParamType() - -#: A floating point value parameter. This can also be selected by using -#: ``float`` as type. -FLOAT = FloatParamType() - -#: A boolean parameter. This is the default for boolean flags. This can -#: also be selected by using ``bool`` as a type. -BOOL = BoolParamType() - -#: A UUID parameter. -UUID = UUIDParameterType() diff --git a/backend/venv39/lib/python3.9/site-packages/click/utils.py b/backend/venv39/lib/python3.9/site-packages/click/utils.py deleted file mode 100644 index 836c6f2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/click/utils.py +++ /dev/null @@ -1,624 +0,0 @@ -import os -import re -import sys -import typing as t -from functools import update_wrapper -from types import ModuleType -from types import TracebackType - -from ._compat import _default_text_stderr -from ._compat import _default_text_stdout -from ._compat import _find_binary_writer -from ._compat import auto_wrap_for_ansi -from ._compat import binary_streams -from ._compat import open_stream -from ._compat import should_strip_ansi -from ._compat import strip_ansi -from ._compat import text_streams -from ._compat import WIN -from .globals import resolve_color_default - -if t.TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = t.TypeVar("R") - - -def _posixify(name: str) -> str: - return "-".join(name.split()).lower() - - -def safecall(func: "t.Callable[P, R]") -> "t.Callable[P, t.Optional[R]]": - """Wraps a function so that it swallows exceptions.""" - - def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> t.Optional[R]: - try: - return func(*args, **kwargs) - except Exception: - pass - return None - - return update_wrapper(wrapper, func) - - -def make_str(value: t.Any) -> str: - """Converts a value into a valid string.""" - if isinstance(value, bytes): - try: - return value.decode(sys.getfilesystemencoding()) - except UnicodeError: - return value.decode("utf-8", "replace") - return str(value) - - -def make_default_short_help(help: str, max_length: int = 45) -> str: - """Returns a condensed version of help string.""" - # Consider only the first paragraph. - paragraph_end = help.find("\n\n") - - if paragraph_end != -1: - help = help[:paragraph_end] - - # Collapse newlines, tabs, and spaces. - words = help.split() - - if not words: - return "" - - # The first paragraph started with a "no rewrap" marker, ignore it. - if words[0] == "\b": - words = words[1:] - - total_length = 0 - last_index = len(words) - 1 - - for i, word in enumerate(words): - total_length += len(word) + (i > 0) - - if total_length > max_length: # too long, truncate - break - - if word[-1] == ".": # sentence end, truncate without "..." - return " ".join(words[: i + 1]) - - if total_length == max_length and i != last_index: - break # not at sentence end, truncate with "..." - else: - return " ".join(words) # no truncation needed - - # Account for the length of the suffix. - total_length += len("...") - - # remove words until the length is short enough - while i > 0: - total_length -= len(words[i]) + (i > 0) - - if total_length <= max_length: - break - - i -= 1 - - return " ".join(words[:i]) + "..." - - -class LazyFile: - """A lazy file works like a regular file but it does not fully open - the file but it does perform some basic checks early to see if the - filename parameter does make sense. This is useful for safely opening - files for writing. - """ - - def __init__( - self, - filename: t.Union[str, "os.PathLike[str]"], - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - atomic: bool = False, - ): - self.name: str = os.fspath(filename) - self.mode = mode - self.encoding = encoding - self.errors = errors - self.atomic = atomic - self._f: t.Optional[t.IO[t.Any]] - self.should_close: bool - - if self.name == "-": - self._f, self.should_close = open_stream(filename, mode, encoding, errors) - else: - if "r" in mode: - # Open and close the file in case we're opening it for - # reading so that we can catch at least some errors in - # some cases early. - open(filename, mode).close() - self._f = None - self.should_close = True - - def __getattr__(self, name: str) -> t.Any: - return getattr(self.open(), name) - - def __repr__(self) -> str: - if self._f is not None: - return repr(self._f) - return f"" - - def open(self) -> t.IO[t.Any]: - """Opens the file if it's not yet open. This call might fail with - a :exc:`FileError`. Not handling this error will produce an error - that Click shows. - """ - if self._f is not None: - return self._f - try: - rv, self.should_close = open_stream( - self.name, self.mode, self.encoding, self.errors, atomic=self.atomic - ) - except OSError as e: - from .exceptions import FileError - - raise FileError(self.name, hint=e.strerror) from e - self._f = rv - return rv - - def close(self) -> None: - """Closes the underlying file, no matter what.""" - if self._f is not None: - self._f.close() - - def close_intelligently(self) -> None: - """This function only closes the file if it was opened by the lazy - file wrapper. For instance this will never close stdin. - """ - if self.should_close: - self.close() - - def __enter__(self) -> "LazyFile": - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - self.close_intelligently() - - def __iter__(self) -> t.Iterator[t.AnyStr]: - self.open() - return iter(self._f) # type: ignore - - -class KeepOpenFile: - def __init__(self, file: t.IO[t.Any]) -> None: - self._file: t.IO[t.Any] = file - - def __getattr__(self, name: str) -> t.Any: - return getattr(self._file, name) - - def __enter__(self) -> "KeepOpenFile": - return self - - def __exit__( - self, - exc_type: t.Optional[t.Type[BaseException]], - exc_value: t.Optional[BaseException], - tb: t.Optional[TracebackType], - ) -> None: - pass - - def __repr__(self) -> str: - return repr(self._file) - - def __iter__(self) -> t.Iterator[t.AnyStr]: - return iter(self._file) - - -def echo( - message: t.Optional[t.Any] = None, - file: t.Optional[t.IO[t.Any]] = None, - nl: bool = True, - err: bool = False, - color: t.Optional[bool] = None, -) -> None: - """Print a message and newline to stdout or a file. This should be - used instead of :func:`print` because it provides better support - for different data, files, and environments. - - Compared to :func:`print`, this does the following: - - - Ensures that the output encoding is not misconfigured on Linux. - - Supports Unicode in the Windows console. - - Supports writing to binary outputs, and supports writing bytes - to text outputs. - - Supports colors and styles on Windows. - - Removes ANSI color and style codes if the output does not look - like an interactive terminal. - - Always flushes the output. - - :param message: The string or bytes to output. Other objects are - converted to strings. - :param file: The file to write to. Defaults to ``stdout``. - :param err: Write to ``stderr`` instead of ``stdout``. - :param nl: Print a newline after the message. Enabled by default. - :param color: Force showing or hiding colors and other styles. By - default Click will remove color if the output does not look like - an interactive terminal. - - .. versionchanged:: 6.0 - Support Unicode output on the Windows console. Click does not - modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` - will still not support Unicode. - - .. versionchanged:: 4.0 - Added the ``color`` parameter. - - .. versionadded:: 3.0 - Added the ``err`` parameter. - - .. versionchanged:: 2.0 - Support colors on Windows if colorama is installed. - """ - if file is None: - if err: - file = _default_text_stderr() - else: - file = _default_text_stdout() - - # There are no standard streams attached to write to. For example, - # pythonw on Windows. - if file is None: - return - - # Convert non bytes/text into the native string type. - if message is not None and not isinstance(message, (str, bytes, bytearray)): - out: t.Optional[t.Union[str, bytes]] = str(message) - else: - out = message - - if nl: - out = out or "" - if isinstance(out, str): - out += "\n" - else: - out += b"\n" - - if not out: - file.flush() - return - - # If there is a message and the value looks like bytes, we manually - # need to find the binary stream and write the message in there. - # This is done separately so that most stream types will work as you - # would expect. Eg: you can write to StringIO for other cases. - if isinstance(out, (bytes, bytearray)): - binary_file = _find_binary_writer(file) - - if binary_file is not None: - file.flush() - binary_file.write(out) - binary_file.flush() - return - - # ANSI style code support. For no message or bytes, nothing happens. - # When outputting to a file instead of a terminal, strip codes. - else: - color = resolve_color_default(color) - - if should_strip_ansi(file, color): - out = strip_ansi(out) - elif WIN: - if auto_wrap_for_ansi is not None: - file = auto_wrap_for_ansi(file, color) # type: ignore - elif not color: - out = strip_ansi(out) - - file.write(out) # type: ignore - file.flush() - - -def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: - """Returns a system stream for byte processing. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - """ - opener = binary_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener() - - -def get_text_stream( - name: "te.Literal['stdin', 'stdout', 'stderr']", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", -) -> t.TextIO: - """Returns a system stream for text processing. This usually returns - a wrapped stream around a binary stream returned from - :func:`get_binary_stream` but it also can take shortcuts for already - correctly configured streams. - - :param name: the name of the stream to open. Valid names are ``'stdin'``, - ``'stdout'`` and ``'stderr'`` - :param encoding: overrides the detected default encoding. - :param errors: overrides the default error mode. - """ - opener = text_streams.get(name) - if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") - return opener(encoding, errors) - - -def open_file( - filename: t.Union[str, "os.PathLike[str]"], - mode: str = "r", - encoding: t.Optional[str] = None, - errors: t.Optional[str] = "strict", - lazy: bool = False, - atomic: bool = False, -) -> t.IO[t.Any]: - """Open a file, with extra behavior to handle ``'-'`` to indicate - a standard stream, lazy open on write, and atomic write. Similar to - the behavior of the :class:`~click.File` param type. - - If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is - wrapped so that using it in a context manager will not close it. - This makes it possible to use the function without accidentally - closing a standard stream: - - .. code-block:: python - - with open_file(filename) as f: - ... - - :param filename: The name or Path of the file to open, or ``'-'`` for - ``stdin``/``stdout``. - :param mode: The mode in which to open the file. - :param encoding: The encoding to decode or encode a file opened in - text mode. - :param errors: The error handling mode. - :param lazy: Wait to open the file until it is accessed. For read - mode, the file is temporarily opened to raise access errors - early, then closed until it is read again. - :param atomic: Write to a temporary file and replace the given file - on close. - - .. versionadded:: 3.0 - """ - if lazy: - return t.cast( - t.IO[t.Any], LazyFile(filename, mode, encoding, errors, atomic=atomic) - ) - - f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) - - if not should_close: - f = t.cast(t.IO[t.Any], KeepOpenFile(f)) - - return f - - -def format_filename( - filename: "t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]]", - shorten: bool = False, -) -> str: - """Format a filename as a string for display. Ensures the filename can be - displayed by replacing any invalid bytes or surrogate escapes in the name - with the replacement character ``�``. - - Invalid bytes or surrogate escapes will raise an error when written to a - stream with ``errors="strict"``. This will typically happen with ``stdout`` - when the locale is something like ``en_GB.UTF-8``. - - Many scenarios *are* safe to write surrogates though, due to PEP 538 and - PEP 540, including: - - - Writing to ``stderr``, which uses ``errors="backslashreplace"``. - - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens - stdout and stderr with ``errors="surrogateescape"``. - - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. - - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. - Python opens stdout and stderr with ``errors="surrogateescape"``. - - :param filename: formats a filename for UI display. This will also convert - the filename into unicode without failing. - :param shorten: this optionally shortens the filename to strip of the - path that leads up to it. - """ - if shorten: - filename = os.path.basename(filename) - else: - filename = os.fspath(filename) - - if isinstance(filename, bytes): - filename = filename.decode(sys.getfilesystemencoding(), "replace") - else: - filename = filename.encode("utf-8", "surrogateescape").decode( - "utf-8", "replace" - ) - - return filename - - -def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: - r"""Returns the config folder for the application. The default behavior - is to return whatever is most appropriate for the operating system. - - To give you an idea, for an app called ``"Foo Bar"``, something like - the following folders could be returned: - - Mac OS X: - ``~/Library/Application Support/Foo Bar`` - Mac OS X (POSIX): - ``~/.foo-bar`` - Unix: - ``~/.config/foo-bar`` - Unix (POSIX): - ``~/.foo-bar`` - Windows (roaming): - ``C:\Users\\AppData\Roaming\Foo Bar`` - Windows (not roaming): - ``C:\Users\\AppData\Local\Foo Bar`` - - .. versionadded:: 2.0 - - :param app_name: the application name. This should be properly capitalized - and can contain whitespace. - :param roaming: controls if the folder should be roaming or not on Windows. - Has no effect otherwise. - :param force_posix: if this is set to `True` then on any POSIX system the - folder will be stored in the home folder with a leading - dot instead of the XDG config home or darwin's - application support folder. - """ - if WIN: - key = "APPDATA" if roaming else "LOCALAPPDATA" - folder = os.environ.get(key) - if folder is None: - folder = os.path.expanduser("~") - return os.path.join(folder, app_name) - if force_posix: - return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) - if sys.platform == "darwin": - return os.path.join( - os.path.expanduser("~/Library/Application Support"), app_name - ) - return os.path.join( - os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), - _posixify(app_name), - ) - - -class PacifyFlushWrapper: - """This wrapper is used to catch and suppress BrokenPipeErrors resulting - from ``.flush()`` being called on broken pipe during the shutdown/final-GC - of the Python interpreter. Notably ``.flush()`` is always called on - ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any - other cleanup code, and the case where the underlying file is not a broken - pipe, all calls and attributes are proxied. - """ - - def __init__(self, wrapped: t.IO[t.Any]) -> None: - self.wrapped = wrapped - - def flush(self) -> None: - try: - self.wrapped.flush() - except OSError as e: - import errno - - if e.errno != errno.EPIPE: - raise - - def __getattr__(self, attr: str) -> t.Any: - return getattr(self.wrapped, attr) - - -def _detect_program_name( - path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None -) -> str: - """Determine the command used to run the program, for use in help - text. If a file or entry point was executed, the file name is - returned. If ``python -m`` was used to execute a module or package, - ``python -m name`` is returned. - - This doesn't try to be too precise, the goal is to give a concise - name for help text. Files are only shown as their name without the - path. ``python`` is only shown for modules, and the full path to - ``sys.executable`` is not shown. - - :param path: The Python file being executed. Python puts this in - ``sys.argv[0]``, which is used by default. - :param _main: The ``__main__`` module. This should only be passed - during internal testing. - - .. versionadded:: 8.0 - Based on command args detection in the Werkzeug reloader. - - :meta private: - """ - if _main is None: - _main = sys.modules["__main__"] - - if not path: - path = sys.argv[0] - - # The value of __package__ indicates how Python was called. It may - # not exist if a setuptools script is installed as an egg. It may be - # set incorrectly for entry points created with pip on Windows. - # It is set to "" inside a Shiv or PEX zipapp. - if getattr(_main, "__package__", None) in {None, ""} or ( - os.name == "nt" - and _main.__package__ == "" - and not os.path.exists(path) - and os.path.exists(f"{path}.exe") - ): - # Executed a file, like "python app.py". - return os.path.basename(path) - - # Executed a module, like "python -m example". - # Rewritten by Python from "-m script" to "/path/to/script.py". - # Need to look at main module to determine how it was executed. - py_module = t.cast(str, _main.__package__) - name = os.path.splitext(os.path.basename(path))[0] - - # A submodule like "example.cli". - if name != "__main__": - py_module = f"{py_module}.{name}" - - return f"python -m {py_module.lstrip('.')}" - - -def _expand_args( - args: t.Iterable[str], - *, - user: bool = True, - env: bool = True, - glob_recursive: bool = True, -) -> t.List[str]: - """Simulate Unix shell expansion with Python functions. - - See :func:`glob.glob`, :func:`os.path.expanduser`, and - :func:`os.path.expandvars`. - - This is intended for use on Windows, where the shell does not do any - expansion. It may not exactly match what a Unix shell would do. - - :param args: List of command line arguments to expand. - :param user: Expand user home directory. - :param env: Expand environment variables. - :param glob_recursive: ``**`` matches directories recursively. - - .. versionchanged:: 8.1 - Invalid glob patterns are treated as empty expansions rather - than raising an error. - - .. versionadded:: 8.0 - - :meta private: - """ - from glob import glob - - out = [] - - for arg in args: - if user: - arg = os.path.expanduser(arg) - - if env: - arg = os.path.expandvars(arg) - - try: - matches = glob(arg, recursive=glob_recursive) - except re.error: - matches = [] - - if not matches: - out.append(arg) - else: - out.extend(matches) - - return out diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/METADATA deleted file mode 100644 index 7b07ee7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/METADATA +++ /dev/null @@ -1,139 +0,0 @@ -Metadata-Version: 2.4 -Name: cryptography -Version: 46.0.3 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable -Classifier: Topic :: Security :: Cryptography -Requires-Dist: cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy' -Requires-Dist: cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy' -Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11' -Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh' -Requires-Dist: nox[uv]>=2024.4.15 ; extra == 'nox' -Requires-Dist: cryptography-vectors==46.0.3 ; extra == 'test' -Requires-Dist: pytest>=7.4.0 ; extra == 'test' -Requires-Dist: pytest-benchmark>=4.0 ; extra == 'test' -Requires-Dist: pytest-cov>=2.10.1 ; extra == 'test' -Requires-Dist: pytest-xdist>=3.5.0 ; extra == 'test' -Requires-Dist: pretend>=0.7 ; extra == 'test' -Requires-Dist: certifi>=2024 ; extra == 'test' -Requires-Dist: pytest-randomly ; extra == 'test-randomorder' -Requires-Dist: sphinx>=5.3.0 ; extra == 'docs' -Requires-Dist: sphinx-rtd-theme>=3.0.0 ; extra == 'docs' -Requires-Dist: sphinx-inline-tabs ; extra == 'docs' -Requires-Dist: pyenchant>=3 ; extra == 'docstest' -Requires-Dist: readme-renderer>=30.0 ; extra == 'docstest' -Requires-Dist: sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest' -Requires-Dist: build>=1.0.0 ; extra == 'sdist' -Requires-Dist: ruff>=0.11.11 ; extra == 'pep8test' -Requires-Dist: mypy>=1.14 ; extra == 'pep8test' -Requires-Dist: check-sdist ; extra == 'pep8test' -Requires-Dist: click>=8.0.1 ; extra == 'pep8test' -Provides-Extra: ssh -Provides-Extra: nox -Provides-Extra: test -Provides-Extra: test-randomorder -Provides-Extra: docs -Provides-Extra: docstest -Provides-Extra: sdist -Provides-Extra: pep8test -License-File: LICENSE -License-File: LICENSE.APACHE -License-File: LICENSE.BSD -Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. -Author-email: The Python Cryptographic Authority and individual contributors -License-Expression: Apache-2.0 OR BSD-3-Clause -Requires-Python: >=3.8, !=3.9.0, !=3.9.1 -Description-Content-Type: text/x-rst; charset=UTF-8 -Project-URL: homepage, https://github.com/pyca/cryptography -Project-URL: documentation, https://cryptography.io/ -Project-URL: source, https://github.com/pyca/cryptography/ -Project-URL: issues, https://github.com/pyca/cryptography/issues -Project-URL: changelog, https://cryptography.io/en/latest/changelog/ - -pyca/cryptography -================= - -.. image:: https://img.shields.io/pypi/v/cryptography.svg - :target: https://pypi.org/project/cryptography/ - :alt: Latest Version - -.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest - :target: https://cryptography.io - :alt: Latest Docs - -.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg - :target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain - -``cryptography`` is a package which provides cryptographic recipes and -primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 3.8+ and PyPy3 7.3.11+. - -``cryptography`` includes both high level recipes and low level interfaces to -common cryptographic algorithms such as symmetric ciphers, message digests, and -key derivation functions. For example, to encrypt something with -``cryptography``'s high level symmetric encryption recipe: - -.. code-block:: pycon - - >>> from cryptography.fernet import Fernet - >>> # Put this somewhere safe! - >>> key = Fernet.generate_key() - >>> f = Fernet(key) - >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") - >>> token - b'...' - >>> f.decrypt(token) - b'A really secret message. Not for prying eyes.' - -You can find more information in the `documentation`_. - -You can install ``cryptography`` with: - -.. code-block:: console - - $ pip install cryptography - -For full details see `the installation documentation`_. - -Discussion -~~~~~~~~~~ - -If you run into bugs, you can file them in our `issue tracker`_. - -We maintain a `cryptography-dev`_ mailing list for development discussion. - -You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get -involved. - -Security -~~~~~~~~ - -Need to report a security issue? Please consult our `security reporting`_ -documentation. - - -.. _`documentation`: https://cryptography.io/ -.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ -.. _`issue tracker`: https://github.com/pyca/cryptography/issues -.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev -.. _`security reporting`: https://cryptography.io/en/latest/security/ - diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/RECORD deleted file mode 100644 index 9f11eed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/RECORD +++ /dev/null @@ -1,180 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/__about__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/fernet.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/_oid.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/extensions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/general_name.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/name.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/ocsp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/oid.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/cryptography/x509/verification.cpython-39.pyc,, -cryptography-46.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cryptography-46.0.3.dist-info/METADATA,sha256=bx2LyCEmOVUC8FH5hsGEZewWPiZoIIYTq0hM9mu9r4s,5748 -cryptography-46.0.3.dist-info/RECORD,, -cryptography-46.0.3.dist-info/WHEEL,sha256=fPMWsH0x0SkVhDADhT1_1cBQw9LWEszkPTNMfqIZV3E,107 -cryptography-46.0.3.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197 -cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 -cryptography-46.0.3.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 -cryptography/__about__.py,sha256=QCLxNH_Abbygdc9RQGpUmrK14Wp3Cl_SEiB2byLwyxo,445 -cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364 -cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087 -cryptography/fernet.py,sha256=3Cvxkh0KJSbX8HbnCHu4wfCW7U0GgfUA3v_qQ8a8iWc,6963 -cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455 -cryptography/hazmat/_oid.py,sha256=p8ThjwJB56Ci_rAIrjyJ1f8VjgD6e39es2dh8JIUBOw,17240 -cryptography/hazmat/asn1/__init__.py,sha256=hS_EWx3wVvZzfbCcNV8hzcDnyMM8H-BhIoS1TipUosk,293 -cryptography/hazmat/asn1/asn1.py,sha256=eMEThEXa19LQjcyVofgHsW6tsZnjp3ddH7bWkkcxfLM,3860 -cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361 -cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305 -cryptography/hazmat/backends/openssl/backend.py,sha256=tV5AxBoFJ2GfA0DMWSY-0TxQJrpQoexzI9R4Kybb--4,10215 -cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/bindings/_rust.abi3.so,sha256=8cWaMSqAJGYiroRaX3jOIzc9mTAwNmuX1P-S3lsvPWA,21389968 -cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=KhqLhXFPArPzzJ7DYO9Fl8FoXB_BagAd_r4Dm_Ze9Xo,1257 -cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=mpNJLuYLbCVrd5i33FBTmWwL_55Dw7JPkSLlSX9Q7oI,230 -cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354 -cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=2ECFmYue1EPkHEE2Bm7aLwkjB0mSUTpr23v9MN4pri4,892 -cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640 -cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020 -cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=iOAMDyHoNwwCSZfZzuXDr64g4GpGUeDgEN-LjXqdrBM,1522 -cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=4Nddw6-ynzIB3w2W86WvkGKTLlTDk_6F5l54RHCuy3E,2688 -cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315 -cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564 -cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564 -cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299 -cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691 -cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532 -cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514 -cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=OWZvBx7xfo_HJl41Nc--DugVyCVPIprZ3HlOPTSWH9g,984 -cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702 -cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=xXfFBb9QehHfDtEaxV_65Z0YK7NquOVIChpTLkgAs_k,2029 -cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912 -cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585 -cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364 -cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523 -cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505 -cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605 -cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601 -cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757 -cryptography/hazmat/bindings/_rust/x509.pyi,sha256=n9X0IQ6ICbdIi-ExdCFZoBgeY6njm3QOVAVZwDQdnbk,9784 -cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/bindings/openssl/_conditional.py,sha256=DMOpA_XN4l70zTc5_J9DpwlbQeUBRTWpfIJ4yRIn1-U,5791 -cryptography/hazmat/bindings/openssl/binding.py,sha256=x8eocEmukO4cm7cHqfVmOoYY7CCXdoF1v1WhZQt9neo,4610 -cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 -cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 -cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=YrKgHS4MfwWaMmPBYRymRRlC0phwWp9ycICFezeJPGk,2595 -cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532 -cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522 -cryptography/hazmat/primitives/_serialization.py,sha256=chgPCSF2jxI2Cr5gB-qbWXOvOfupBh4CARS0KAhv9AM,5123 -cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 -cryptography/hazmat/primitives/asymmetric/dh.py,sha256=0v_vEFFz5pQ1QG-FkWDyvgv7IfuVZSH5Q6LyFI5A8rg,3645 -cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=Ld_bbbqQFz12dObHxIkzEQzX0SWWP41RLSWkYSaKhqE,4213 -cryptography/hazmat/primitives/asymmetric/ec.py,sha256=Vf5ig2PcS3PVnsb5N49Kx1uIkFBJyhg4BWXThDz5cug,12999 -cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=jZW5cs472wXXV3eB0sE1b8w64gdazwwU0_MT5UOTiXs,3700 -cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=yAetgn2f2JYf0BO8MapGzXeThsvSMG5LmUCrxVOidAA,3729 -cryptography/hazmat/primitives/asymmetric/padding.py,sha256=vQ6l6gOg9HqcbOsvHrSiJRVLdEj9L4m4HkRGYziTyFA,2854 -cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=ZnKOo2f34MCCOupC03Y1uR-_jiSG5IrelHEmxaME3D4,8303 -cryptography/hazmat/primitives/asymmetric/types.py,sha256=LnsOJym-wmPUJ7Knu_7bCNU3kIiELCd6krOaW_JU08I,2996 -cryptography/hazmat/primitives/asymmetric/utils.py,sha256=DPTs6T4F-UhwzFQTh-1fSEpQzazH2jf2xpIro3ItF4o,790 -cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=_4nQeZ3yJ3Lg0RpXnaqA-1yt6vbx1F-wzLcaZHwSpeE,3613 -cryptography/hazmat/primitives/asymmetric/x448.py,sha256=WKBLtuVfJqiBRro654fGaQAlvsKbqbNkK7c4A_ZCdV0,3642 -cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680 -cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634 -cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=Q7ZJwcsx83Mgxv5y7r6CyJKSdsOwC-my-5A67-ma2vw,3407 -cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253 -cryptography/hazmat/primitives/ciphers/modes.py,sha256=20stpwhDtbAvpH0SMf9EDHIciwmTF-JMBUOZ9bU8WiQ,8318 -cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338 -cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422 -cryptography/hazmat/primitives/hashes.py,sha256=M8BrlKB3U6DEtHvWTV5VRjpteHv1kS3Zxm_Bsk04cr8,5184 -cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423 -cryptography/hazmat/primitives/kdf/__init__.py,sha256=4XibZnrYq4hh5xBjWiIXzaYW6FKx8hPbVaa_cB9zS64,750 -cryptography/hazmat/primitives/kdf/argon2.py,sha256=UFDNXG0v-rw3DqAQTB1UQAsQC2M5Ejg0k_6OCyhLKus,460 -cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=Ua8KoLXXnzgsrAUmHpyKymaPt8aPRP0EHEaBz7QCQ9I,3737 -cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543 -cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=oZepvo4evhKkkJQWRDwaPoIbyTaFmDc5NPimxg6lfKg,9165 -cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=1WIwhELR0w8ztTpTu8BrFiYWmK3hUfJq08I79TxwieE,1957 -cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590 -cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=zLTcF665QFvXX2f8TS7fmBZTteXpFjKahzfjjQcCJyw,1999 -cryptography/hazmat/primitives/keywrap.py,sha256=XV4Pj2fqSeD-RqZVvY2cA3j5_7RwJSFygYuLfk2ujCo,5650 -cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865 -cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355 -cryptography/hazmat/primitives/serialization/__init__.py,sha256=Q7uTgDlt7n3WfsMT6jYwutC6DIg_7SEeoAm1GHZ5B5E,1705 -cryptography/hazmat/primitives/serialization/base.py,sha256=ikq5MJIwp_oUnjiaBco_PmQwOTYuGi-XkYUYHKy8Vo0,615 -cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104 -cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=5OR_Tkysxaprn4FegvJIfbep9rJ9wok6FLWvWwQ5-Mg,13943 -cryptography/hazmat/primitives/serialization/ssh.py,sha256=hPV5obFznz0QhFfXFPOeQ8y6MsurA0xVMQiLnLESEs8,53700 -cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258 -cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256 -cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652 -cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cryptography/utils.py,sha256=bZAjFC5KVpfmF29qS_18vvpW3mKxmdiRALcusHhTTkg,4301 -cryptography/x509/__init__.py,sha256=xloN0swseNx-m2WFZmCA17gOoxQWqeU82UVjEdJBePQ,8257 -cryptography/x509/base.py,sha256=OrmTw3y8B6AE_nGXQPN8x9kq-d7rDWeH13gCq6T6D6U,27997 -cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797 -cryptography/x509/extensions.py,sha256=QxYrqR6SF1qzR9ZraP8wDiIczlEVlAFuwDRVcltB6Tk,77724 -cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836 -cryptography/x509/name.py,sha256=ty0_xf0LnHwZAdEf-d8FLO1K4hGqx_7DsD3CHwoLJiY,15101 -cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699 -cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931 -cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/WHEEL deleted file mode 100644 index 28030e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.9.4) -Root-Is-Purelib: false -Tag: cp38-abi3-macosx_10_9_universal2 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE deleted file mode 100644 index b11f379..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE +++ /dev/null @@ -1,3 +0,0 @@ -This software is made available under the terms of *either* of the licenses -found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made -under the terms of *both* these licenses. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE deleted file mode 100644 index 62589ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.BSD b/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.BSD deleted file mode 100644 index ec1a29d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.BSD +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) Individual contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of PyCA Cryptography nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/__about__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/__about__.py deleted file mode 100644 index a811628..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/__about__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -__all__ = [ - "__author__", - "__copyright__", - "__version__", -] - -__version__ = "46.0.3" - - -__author__ = "The Python Cryptographic Authority and individual contributors" -__copyright__ = f"Copyright 2013-2025 {__author__}" diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/__init__.py deleted file mode 100644 index d374f75..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.__about__ import __author__, __copyright__, __version__ - -__all__ = [ - "__author__", - "__copyright__", - "__version__", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/exceptions.py b/backend/venv39/lib/python3.9/site-packages/cryptography/exceptions.py deleted file mode 100644 index fe125ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/exceptions.py +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.bindings._rust import exceptions as rust_exceptions - -if typing.TYPE_CHECKING: - from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -_Reasons = rust_exceptions._Reasons - - -class UnsupportedAlgorithm(Exception): - def __init__(self, message: str, reason: _Reasons | None = None) -> None: - super().__init__(message) - self._reason = reason - - -class AlreadyFinalized(Exception): - pass - - -class AlreadyUpdated(Exception): - pass - - -class NotYetFinalized(Exception): - pass - - -class InvalidTag(Exception): - pass - - -class InvalidSignature(Exception): - pass - - -class InternalError(Exception): - def __init__( - self, msg: str, err_code: list[rust_openssl.OpenSSLError] - ) -> None: - super().__init__(msg) - self.err_code = err_code - - -class InvalidKey(Exception): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/fernet.py b/backend/venv39/lib/python3.9/site-packages/cryptography/fernet.py deleted file mode 100644 index c6744ae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/fernet.py +++ /dev/null @@ -1,224 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import base64 -import binascii -import os -import time -import typing -from collections.abc import Iterable - -from cryptography import utils -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives import hashes, padding -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes -from cryptography.hazmat.primitives.hmac import HMAC - - -class InvalidToken(Exception): - pass - - -_MAX_CLOCK_SKEW = 60 - - -class Fernet: - def __init__( - self, - key: bytes | str, - backend: typing.Any = None, - ) -> None: - try: - key = base64.urlsafe_b64decode(key) - except binascii.Error as exc: - raise ValueError( - "Fernet key must be 32 url-safe base64-encoded bytes." - ) from exc - if len(key) != 32: - raise ValueError( - "Fernet key must be 32 url-safe base64-encoded bytes." - ) - - self._signing_key = key[:16] - self._encryption_key = key[16:] - - @classmethod - def generate_key(cls) -> bytes: - return base64.urlsafe_b64encode(os.urandom(32)) - - def encrypt(self, data: bytes) -> bytes: - return self.encrypt_at_time(data, int(time.time())) - - def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: - iv = os.urandom(16) - return self._encrypt_from_parts(data, current_time, iv) - - def _encrypt_from_parts( - self, data: bytes, current_time: int, iv: bytes - ) -> bytes: - utils._check_bytes("data", data) - - padder = padding.PKCS7(algorithms.AES.block_size).padder() - padded_data = padder.update(data) + padder.finalize() - encryptor = Cipher( - algorithms.AES(self._encryption_key), - modes.CBC(iv), - ).encryptor() - ciphertext = encryptor.update(padded_data) + encryptor.finalize() - - basic_parts = ( - b"\x80" - + current_time.to_bytes(length=8, byteorder="big") - + iv - + ciphertext - ) - - h = HMAC(self._signing_key, hashes.SHA256()) - h.update(basic_parts) - hmac = h.finalize() - return base64.urlsafe_b64encode(basic_parts + hmac) - - def decrypt(self, token: bytes | str, ttl: int | None = None) -> bytes: - timestamp, data = Fernet._get_unverified_token_data(token) - if ttl is None: - time_info = None - else: - time_info = (ttl, int(time.time())) - return self._decrypt_data(data, timestamp, time_info) - - def decrypt_at_time( - self, token: bytes | str, ttl: int, current_time: int - ) -> bytes: - if ttl is None: - raise ValueError( - "decrypt_at_time() can only be used with a non-None ttl" - ) - timestamp, data = Fernet._get_unverified_token_data(token) - return self._decrypt_data(data, timestamp, (ttl, current_time)) - - def extract_timestamp(self, token: bytes | str) -> int: - timestamp, data = Fernet._get_unverified_token_data(token) - # Verify the token was not tampered with. - self._verify_signature(data) - return timestamp - - @staticmethod - def _get_unverified_token_data(token: bytes | str) -> tuple[int, bytes]: - if not isinstance(token, (str, bytes)): - raise TypeError("token must be bytes or str") - - try: - data = base64.urlsafe_b64decode(token) - except (TypeError, binascii.Error): - raise InvalidToken - - if not data or data[0] != 0x80: - raise InvalidToken - - if len(data) < 9: - raise InvalidToken - - timestamp = int.from_bytes(data[1:9], byteorder="big") - return timestamp, data - - def _verify_signature(self, data: bytes) -> None: - h = HMAC(self._signing_key, hashes.SHA256()) - h.update(data[:-32]) - try: - h.verify(data[-32:]) - except InvalidSignature: - raise InvalidToken - - def _decrypt_data( - self, - data: bytes, - timestamp: int, - time_info: tuple[int, int] | None, - ) -> bytes: - if time_info is not None: - ttl, current_time = time_info - if timestamp + ttl < current_time: - raise InvalidToken - - if current_time + _MAX_CLOCK_SKEW < timestamp: - raise InvalidToken - - self._verify_signature(data) - - iv = data[9:25] - ciphertext = data[25:-32] - decryptor = Cipher( - algorithms.AES(self._encryption_key), modes.CBC(iv) - ).decryptor() - plaintext_padded = decryptor.update(ciphertext) - try: - plaintext_padded += decryptor.finalize() - except ValueError: - raise InvalidToken - unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() - - unpadded = unpadder.update(plaintext_padded) - try: - unpadded += unpadder.finalize() - except ValueError: - raise InvalidToken - return unpadded - - -class MultiFernet: - def __init__(self, fernets: Iterable[Fernet]): - fernets = list(fernets) - if not fernets: - raise ValueError( - "MultiFernet requires at least one Fernet instance" - ) - self._fernets = fernets - - def encrypt(self, msg: bytes) -> bytes: - return self.encrypt_at_time(msg, int(time.time())) - - def encrypt_at_time(self, msg: bytes, current_time: int) -> bytes: - return self._fernets[0].encrypt_at_time(msg, current_time) - - def rotate(self, msg: bytes | str) -> bytes: - timestamp, data = Fernet._get_unverified_token_data(msg) - for f in self._fernets: - try: - p = f._decrypt_data(data, timestamp, None) - break - except InvalidToken: - pass - else: - raise InvalidToken - - iv = os.urandom(16) - return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) - - def decrypt(self, msg: bytes | str, ttl: int | None = None) -> bytes: - for f in self._fernets: - try: - return f.decrypt(msg, ttl) - except InvalidToken: - pass - raise InvalidToken - - def decrypt_at_time( - self, msg: bytes | str, ttl: int, current_time: int - ) -> bytes: - for f in self._fernets: - try: - return f.decrypt_at_time(msg, ttl, current_time) - except InvalidToken: - pass - raise InvalidToken - - def extract_timestamp(self, msg: bytes | str) -> int: - for f in self._fernets: - try: - return f.extract_timestamp(msg) - except InvalidToken: - pass - raise InvalidToken diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/__init__.py deleted file mode 100644 index b9f1187..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -""" -Hazardous Materials - -This is a "Hazardous Materials" module. You should ONLY use it if you're -100% absolutely sure that you know what you're doing because this module -is full of land mines, dragons, and dinosaurs with laser guns. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/_oid.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/_oid.py deleted file mode 100644 index 4bf138d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/_oid.py +++ /dev/null @@ -1,356 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import ( - ObjectIdentifier as ObjectIdentifier, -) -from cryptography.hazmat.primitives import hashes - - -class ExtensionOID: - SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") - SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") - KEY_USAGE = ObjectIdentifier("2.5.29.15") - PRIVATE_KEY_USAGE_PERIOD = ObjectIdentifier("2.5.29.16") - SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") - ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") - BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") - NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") - CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") - CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") - POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") - AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") - POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") - EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") - FRESHEST_CRL = ObjectIdentifier("2.5.29.46") - INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") - ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") - AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") - SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") - OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") - TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") - CRL_NUMBER = ObjectIdentifier("2.5.29.20") - DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") - PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( - "1.3.6.1.4.1.11129.2.4.2" - ) - PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") - SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") - MS_CERTIFICATE_TEMPLATE = ObjectIdentifier("1.3.6.1.4.1.311.21.7") - ADMISSIONS = ObjectIdentifier("1.3.36.8.3.3") - - -class OCSPExtensionOID: - NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") - ACCEPTABLE_RESPONSES = ObjectIdentifier("1.3.6.1.5.5.7.48.1.4") - - -class CRLEntryExtensionOID: - CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") - CRL_REASON = ObjectIdentifier("2.5.29.21") - INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") - - -class NameOID: - COMMON_NAME = ObjectIdentifier("2.5.4.3") - COUNTRY_NAME = ObjectIdentifier("2.5.4.6") - LOCALITY_NAME = ObjectIdentifier("2.5.4.7") - STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") - STREET_ADDRESS = ObjectIdentifier("2.5.4.9") - ORGANIZATION_IDENTIFIER = ObjectIdentifier("2.5.4.97") - ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") - ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") - SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") - SURNAME = ObjectIdentifier("2.5.4.4") - GIVEN_NAME = ObjectIdentifier("2.5.4.42") - TITLE = ObjectIdentifier("2.5.4.12") - INITIALS = ObjectIdentifier("2.5.4.43") - GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") - X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") - DN_QUALIFIER = ObjectIdentifier("2.5.4.46") - PSEUDONYM = ObjectIdentifier("2.5.4.65") - USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") - DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") - EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") - JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") - JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") - JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( - "1.3.6.1.4.1.311.60.2.1.2" - ) - BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") - POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") - POSTAL_CODE = ObjectIdentifier("2.5.4.17") - INN = ObjectIdentifier("1.2.643.3.131.1.1") - OGRN = ObjectIdentifier("1.2.643.100.1") - SNILS = ObjectIdentifier("1.2.643.100.3") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -class SignatureAlgorithmOID: - RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") - RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") - # This is an alternate OID for RSA with SHA1 that is occasionally seen - _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") - RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") - RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") - RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") - RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") - RSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.13") - RSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.14") - RSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.15") - RSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.16") - RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") - ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") - ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") - ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") - ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") - ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") - ECDSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.9") - ECDSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.10") - ECDSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.11") - ECDSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.12") - DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") - DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") - DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") - DSA_WITH_SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.3.3") - DSA_WITH_SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.3.4") - ED25519 = ObjectIdentifier("1.3.101.112") - ED448 = ObjectIdentifier("1.3.101.113") - GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") - GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") - GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") - - -_SIG_OIDS_TO_HASH: dict[ObjectIdentifier, hashes.HashAlgorithm | None] = { - SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), - SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.RSA_WITH_SHA3_224: hashes.SHA3_224(), - SignatureAlgorithmOID.RSA_WITH_SHA3_256: hashes.SHA3_256(), - SignatureAlgorithmOID.RSA_WITH_SHA3_384: hashes.SHA3_384(), - SignatureAlgorithmOID.RSA_WITH_SHA3_512: hashes.SHA3_512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_224: hashes.SHA3_224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_256: hashes.SHA3_256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_384: hashes.SHA3_384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA3_512: hashes.SHA3_512(), - SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ED25519: None, - SignatureAlgorithmOID.ED448: None, - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, -} - - -class HashAlgorithmOID: - SHA1 = ObjectIdentifier("1.3.14.3.2.26") - SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.2.4") - SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.2.1") - SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.2.2") - SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.2.3") - SHA3_224 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.224") - SHA3_256 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.256") - SHA3_384 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.384") - SHA3_512 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.512") - SHA3_224_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.7") - SHA3_256_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.8") - SHA3_384_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.9") - SHA3_512_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.10") - - -class PublicKeyAlgorithmOID: - DSA = ObjectIdentifier("1.2.840.10040.4.1") - EC_PUBLIC_KEY = ObjectIdentifier("1.2.840.10045.2.1") - RSAES_PKCS1_v1_5 = ObjectIdentifier("1.2.840.113549.1.1.1") - RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") - X25519 = ObjectIdentifier("1.3.101.110") - X448 = ObjectIdentifier("1.3.101.111") - ED25519 = ObjectIdentifier("1.3.101.112") - ED448 = ObjectIdentifier("1.3.101.113") - - -class ExtendedKeyUsageOID: - SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") - CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") - CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") - EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") - TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") - OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") - ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") - SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") - KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") - IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") - BUNDLE_SECURITY = ObjectIdentifier("1.3.6.1.5.5.7.3.35") - CERTIFICATE_TRANSPARENCY = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4") - - -class OtherNameFormOID: - PERMANENT_IDENTIFIER = ObjectIdentifier("1.3.6.1.5.5.7.8.3") - HW_MODULE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.4") - DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") - NAI_REALM = ObjectIdentifier("1.3.6.1.5.5.7.8.8") - SMTP_UTF8_MAILBOX = ObjectIdentifier("1.3.6.1.5.5.7.8.9") - ACP_NODE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.10") - BUNDLE_EID = ObjectIdentifier("1.3.6.1.5.5.7.8.11") - - -class AuthorityInformationAccessOID: - CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") - OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") - - -class SubjectInformationAccessOID: - CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") - - -class CertificatePoliciesOID: - CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") - CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") - ANY_POLICY = ObjectIdentifier("2.5.29.32.0") - - -class AttributeOID: - CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -_OID_NAMES = { - NameOID.COMMON_NAME: "commonName", - NameOID.COUNTRY_NAME: "countryName", - NameOID.LOCALITY_NAME: "localityName", - NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", - NameOID.STREET_ADDRESS: "streetAddress", - NameOID.ORGANIZATION_NAME: "organizationName", - NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", - NameOID.SERIAL_NUMBER: "serialNumber", - NameOID.SURNAME: "surname", - NameOID.GIVEN_NAME: "givenName", - NameOID.TITLE: "title", - NameOID.GENERATION_QUALIFIER: "generationQualifier", - NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", - NameOID.DN_QUALIFIER: "dnQualifier", - NameOID.PSEUDONYM: "pseudonym", - NameOID.USER_ID: "userID", - NameOID.DOMAIN_COMPONENT: "domainComponent", - NameOID.EMAIL_ADDRESS: "emailAddress", - NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", - NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", - NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( - "jurisdictionStateOrProvinceName" - ), - NameOID.BUSINESS_CATEGORY: "businessCategory", - NameOID.POSTAL_ADDRESS: "postalAddress", - NameOID.POSTAL_CODE: "postalCode", - NameOID.INN: "INN", - NameOID.OGRN: "OGRN", - NameOID.SNILS: "SNILS", - NameOID.UNSTRUCTURED_NAME: "unstructuredName", - SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", - SignatureAlgorithmOID.RSASSA_PSS: "rsassaPss", - SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", - SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", - SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", - SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", - SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", - SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", - SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", - SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", - SignatureAlgorithmOID.ED25519: "ed25519", - SignatureAlgorithmOID.ED448: "ed448", - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( - "GOST R 34.11-94 with GOST R 34.10-2001" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" - ), - HashAlgorithmOID.SHA1: "sha1", - HashAlgorithmOID.SHA224: "sha224", - HashAlgorithmOID.SHA256: "sha256", - HashAlgorithmOID.SHA384: "sha384", - HashAlgorithmOID.SHA512: "sha512", - HashAlgorithmOID.SHA3_224: "sha3_224", - HashAlgorithmOID.SHA3_256: "sha3_256", - HashAlgorithmOID.SHA3_384: "sha3_384", - HashAlgorithmOID.SHA3_512: "sha3_512", - HashAlgorithmOID.SHA3_224_NIST: "sha3_224", - HashAlgorithmOID.SHA3_256_NIST: "sha3_256", - HashAlgorithmOID.SHA3_384_NIST: "sha3_384", - HashAlgorithmOID.SHA3_512_NIST: "sha3_512", - PublicKeyAlgorithmOID.DSA: "dsaEncryption", - PublicKeyAlgorithmOID.EC_PUBLIC_KEY: "id-ecPublicKey", - PublicKeyAlgorithmOID.RSAES_PKCS1_v1_5: "rsaEncryption", - PublicKeyAlgorithmOID.X25519: "X25519", - PublicKeyAlgorithmOID.X448: "X448", - ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", - ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", - ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", - ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", - ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", - ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", - ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", - ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", - ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", - ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", - ExtensionOID.KEY_USAGE: "keyUsage", - ExtensionOID.PRIVATE_KEY_USAGE_PERIOD: "privateKeyUsagePeriod", - ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", - ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", - ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.PRECERT_POISON: "ctPoison", - ExtensionOID.MS_CERTIFICATE_TEMPLATE: "msCertificateTemplate", - ExtensionOID.ADMISSIONS: "Admissions", - CRLEntryExtensionOID.CRL_REASON: "cRLReason", - CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", - CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", - ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", - ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", - ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", - ExtensionOID.POLICY_MAPPINGS: "policyMappings", - ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", - ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", - ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", - ExtensionOID.FRESHEST_CRL: "freshestCRL", - ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", - ExtensionOID.ISSUING_DISTRIBUTION_POINT: "issuingDistributionPoint", - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", - ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", - ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", - ExtensionOID.CRL_NUMBER: "cRLNumber", - ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", - ExtensionOID.TLS_FEATURE: "TLSFeature", - AuthorityInformationAccessOID.OCSP: "OCSP", - AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", - SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", - CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", - CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", - OCSPExtensionOID.NONCE: "OCSPNonce", - AttributeOID.CHALLENGE_PASSWORD: "challengePassword", -} diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py deleted file mode 100644 index be68373..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.asn1.asn1 import encode_der, sequence - -__all__ = [ - "encode_der", - "sequence", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py deleted file mode 100644 index dedad6f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/asn1/asn1.py +++ /dev/null @@ -1,116 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import dataclasses -import sys -import typing - -if sys.version_info < (3, 11): - import typing_extensions - - # We use the `include_extras` parameter of `get_type_hints`, which was - # added in Python 3.9. This can be replaced by the `typing` version - # once the min version is >= 3.9 - if sys.version_info < (3, 9): - get_type_hints = typing_extensions.get_type_hints - else: - get_type_hints = typing.get_type_hints -else: - get_type_hints = typing.get_type_hints - -from cryptography.hazmat.bindings._rust import declarative_asn1 - -T = typing.TypeVar("T", covariant=True) -U = typing.TypeVar("U") - - -encode_der = declarative_asn1.encode_der - - -def _normalize_field_type( - field_type: typing.Any, field_name: str -) -> declarative_asn1.AnnotatedType: - annotation = declarative_asn1.Annotation() - - if hasattr(field_type, "__asn1_root__"): - annotated_root = field_type.__asn1_root__ - if not isinstance(annotated_root, declarative_asn1.AnnotatedType): - raise TypeError(f"unsupported root type: {annotated_root}") - return annotated_root - else: - rust_field_type = declarative_asn1.non_root_python_to_rust(field_type) - - return declarative_asn1.AnnotatedType(rust_field_type, annotation) - - -def _annotate_fields( - raw_fields: dict[str, type], -) -> dict[str, declarative_asn1.AnnotatedType]: - fields = {} - for field_name, field_type in raw_fields.items(): - # Recursively normalize the field type into something that the - # Rust code can understand. - annotated_field_type = _normalize_field_type(field_type, field_name) - fields[field_name] = annotated_field_type - - return fields - - -def _register_asn1_sequence(cls: type[U]) -> None: - raw_fields = get_type_hints(cls, include_extras=True) - root = declarative_asn1.AnnotatedType( - declarative_asn1.Type.Sequence(cls, _annotate_fields(raw_fields)), - declarative_asn1.Annotation(), - ) - - setattr(cls, "__asn1_root__", root) - - -# Due to https://github.com/python/mypy/issues/19731, we can't define an alias -# for `dataclass_transform` that conditionally points to `typing` or -# `typing_extensions` depending on the Python version (like we do for -# `get_type_hints`). -# We work around it by making the whole decorated class conditional on the -# Python version. -if sys.version_info < (3, 11): - - @typing_extensions.dataclass_transform(kw_only_default=True) - def sequence(cls: type[U]) -> type[U]: - # We use `dataclasses.dataclass` to add an __init__ method - # to the class with keyword-only parameters. - if sys.version_info >= (3, 10): - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - # `match_args` was added in Python 3.10 and defaults - # to True - match_args=False, - # `kw_only` was added in Python 3.10 and defaults to - # False - kw_only=True, - )(cls) - else: - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - )(cls) - _register_asn1_sequence(dataclass_cls) - return dataclass_cls - -else: - - @typing.dataclass_transform(kw_only_default=True) - def sequence(cls: type[U]) -> type[U]: - # Only add an __init__ method, with keyword-only - # parameters. - dataclass_cls = dataclasses.dataclass( - repr=False, - eq=False, - match_args=False, - kw_only=True, - )(cls) - _register_asn1_sequence(dataclass_cls) - return dataclass_cls diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py deleted file mode 100644 index b4400aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from typing import Any - - -def default_backend() -> Any: - from cryptography.hazmat.backends.openssl.backend import backend - - return backend diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py deleted file mode 100644 index 51b0447..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.backends.openssl.backend import backend - -__all__ = ["backend"] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py deleted file mode 100644 index 248b8c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py +++ /dev/null @@ -1,302 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.bindings.openssl import binding -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.hazmat.primitives.asymmetric.padding import ( - MGF1, - OAEP, - PSS, - PKCS1v15, -) -from cryptography.hazmat.primitives.ciphers import ( - CipherAlgorithm, -) -from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, -) -from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, - Mode, -) - - -class Backend: - """ - OpenSSL API binding interfaces. - """ - - name = "openssl" - - # TripleDES encryption is disallowed/deprecated throughout 2023 in - # FIPS 140-3. To keep it simple we denylist any use of TripleDES (TDEA). - _fips_ciphers = (AES,) - # Sometimes SHA1 is still permissible. That logic is contained - # within the various *_supported methods. - _fips_hashes = ( - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA512_224, - hashes.SHA512_256, - hashes.SHA3_224, - hashes.SHA3_256, - hashes.SHA3_384, - hashes.SHA3_512, - hashes.SHAKE128, - hashes.SHAKE256, - ) - _fips_ecdh_curves = ( - ec.SECP224R1, - ec.SECP256R1, - ec.SECP384R1, - ec.SECP521R1, - ) - _fips_rsa_min_key_size = 2048 - _fips_rsa_min_public_exponent = 65537 - _fips_dsa_min_modulus = 1 << 2048 - _fips_dh_min_key_size = 2048 - _fips_dh_min_modulus = 1 << _fips_dh_min_key_size - - def __init__(self) -> None: - self._binding = binding.Binding() - self._ffi = self._binding.ffi - self._lib = self._binding.lib - self._fips_enabled = rust_openssl.is_fips_enabled() - - def __repr__(self) -> str: - return ( - f"" - ) - - def openssl_assert(self, ok: bool) -> None: - return binding._openssl_assert(ok) - - def _enable_fips(self) -> None: - # This function enables FIPS mode for OpenSSL 3.0.0 on installs that - # have the FIPS provider installed properly. - rust_openssl.enable_fips(rust_openssl._providers) - assert rust_openssl.is_fips_enabled() - self._fips_enabled = rust_openssl.is_fips_enabled() - - def openssl_version_text(self) -> str: - """ - Friendly string name of the loaded OpenSSL library. This is not - necessarily the same version as it was compiled against. - - Example: OpenSSL 3.2.1 30 Jan 2024 - """ - return rust_openssl.openssl_version_text() - - def openssl_version_number(self) -> int: - return rust_openssl.openssl_version() - - def hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): - return False - - return rust_openssl.hashes.hash_supported(algorithm) - - def signature_hash_supported( - self, algorithm: hashes.HashAlgorithm - ) -> bool: - # Dedicated check for hashing algorithm use in message digest for - # signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption). - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return False - return self.hash_supported(algorithm) - - def scrypt_supported(self) -> bool: - if self._fips_enabled: - return False - else: - return hasattr(rust_openssl.kdf.Scrypt, "derive") - - def argon2_supported(self) -> bool: - if self._fips_enabled: - return False - else: - return hasattr(rust_openssl.kdf.Argon2id, "derive") - - def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - # FIPS mode still allows SHA1 for HMAC - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return True - if rust_openssl.CRYPTOGRAPHY_IS_AWSLC: - return isinstance( - algorithm, - ( - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA512_224, - hashes.SHA512_256, - ), - ) - return self.hash_supported(algorithm) - - def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: - if self._fips_enabled: - # FIPS mode requires AES. TripleDES is disallowed/deprecated in - # FIPS 140-3. - if not isinstance(cipher, self._fips_ciphers): - return False - - return rust_openssl.ciphers.cipher_supported(cipher, mode) - - def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - return self.hmac_supported(algorithm) - - def _consume_errors(self) -> list[rust_openssl.OpenSSLError]: - return rust_openssl.capture_error_stack() - - def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if self._fips_enabled and isinstance(algorithm, hashes.SHA1): - return False - - return isinstance( - algorithm, - ( - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - ), - ) - - def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool: - if isinstance(padding, PKCS1v15): - return True - elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): - # FIPS 186-4 only allows salt length == digest length for PSS - # It is technically acceptable to set an explicit salt length - # equal to the digest length and this will incorrectly fail, but - # since we don't do that in the tests and this method is - # private, we'll ignore that until we need to do otherwise. - if ( - self._fips_enabled - and padding._salt_length != PSS.DIGEST_LENGTH - ): - return False - return self.hash_supported(padding._mgf._algorithm) - elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): - return self._oaep_hash_supported( - padding._mgf._algorithm - ) and self._oaep_hash_supported(padding._algorithm) - else: - return False - - def rsa_encryption_supported(self, padding: AsymmetricPadding) -> bool: - if self._fips_enabled and isinstance(padding, PKCS1v15): - return False - else: - return self.rsa_padding_supported(padding) - - def dsa_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not self._fips_enabled - ) - - def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: - if not self.dsa_supported(): - return False - return self.signature_hash_supported(algorithm) - - def cmac_algorithm_supported(self, algorithm) -> bool: - return self.cipher_supported( - algorithm, CBC(b"\x00" * algorithm.block_size) - ) - - def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: - if self._fips_enabled and not isinstance( - curve, self._fips_ecdh_curves - ): - return False - - return rust_openssl.ec.curve_supported(curve) - - def elliptic_curve_signature_algorithm_supported( - self, - signature_algorithm: ec.EllipticCurveSignatureAlgorithm, - curve: ec.EllipticCurve, - ) -> bool: - # We only support ECDSA right now. - if not isinstance(signature_algorithm, ec.ECDSA): - return False - - return self.elliptic_curve_supported(curve) and ( - isinstance(signature_algorithm.algorithm, asym_utils.Prehashed) - or self.hash_supported(signature_algorithm.algorithm) - ) - - def elliptic_curve_exchange_algorithm_supported( - self, algorithm: ec.ECDH, curve: ec.EllipticCurve - ) -> bool: - return self.elliptic_curve_supported(curve) and isinstance( - algorithm, ec.ECDH - ) - - def dh_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def dh_x942_serialization_supported(self) -> bool: - return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 - - def x25519_supported(self) -> bool: - return not self._fips_enabled - - def x448_supported(self) -> bool: - if self._fips_enabled: - return False - return ( - not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL - and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def ed25519_supported(self) -> bool: - return not self._fips_enabled - - def ed448_supported(self) -> bool: - if self._fips_enabled: - return False - return ( - not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL - and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - def ecdsa_deterministic_supported(self) -> bool: - return ( - rust_openssl.CRYPTOGRAPHY_OPENSSL_320_OR_GREATER - and not self._fips_enabled - ) - - def poly1305_supported(self) -> bool: - return not self._fips_enabled - - def pkcs7_supported(self) -> bool: - return ( - not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC - ) - - -backend = Backend() diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py deleted file mode 100644 index b509336..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so deleted file mode 100755 index e35ae26..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi deleted file mode 100644 index 2f4eef4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi +++ /dev/null @@ -1,37 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import padding -from cryptography.utils import Buffer - -class PKCS7PaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class ANSIX923PaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class PKCS7UnpaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class ANSIX923UnpaddingContext(padding.PaddingContext): - def __init__(self, block_size: int) -> None: ... - def update(self, data: Buffer) -> bytes: ... - def finalize(self) -> bytes: ... - -class ObjectIdentifier: - def __init__(self, value: str) -> None: ... - @property - def dotted_string(self) -> str: ... - @property - def _name(self) -> str: ... - -T = typing.TypeVar("T") diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi deleted file mode 100644 index 8010008..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi +++ /dev/null @@ -1,8 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -lib = typing.Any -ffi = typing.Any diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi deleted file mode 100644 index 3b5f208..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi +++ /dev/null @@ -1,7 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -def decode_dss_signature(signature: bytes) -> tuple[int, int]: ... -def encode_dss_signature(r: int, s: int) -> bytes: ... -def parse_spki_for_data(data: bytes) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi deleted file mode 100644 index 8563c11..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi +++ /dev/null @@ -1,32 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. -import typing - -def encode_der(value: typing.Any) -> bytes: ... -def non_root_python_to_rust(cls: type) -> Type: ... - -# Type is a Rust enum with tuple variants. For now, we express the type -# annotations like this: -class Type: - Sequence: typing.ClassVar[type] - PyInt: typing.ClassVar[type] - -class Annotation: - def __new__( - cls, - ) -> Annotation: ... - -class AnnotatedType: - inner: Type - annotation: Annotation - - def __new__(cls, inner: Type, annotation: Annotation) -> AnnotatedType: ... - -class AnnotatedTypeObject: - annotated_type: AnnotatedType - value: typing.Any - - def __new__( - cls, annotated_type: AnnotatedType, value: typing.Any - ) -> AnnotatedTypeObject: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi deleted file mode 100644 index 09f46b1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi +++ /dev/null @@ -1,17 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -class _Reasons: - BACKEND_MISSING_INTERFACE: _Reasons - UNSUPPORTED_HASH: _Reasons - UNSUPPORTED_CIPHER: _Reasons - UNSUPPORTED_PADDING: _Reasons - UNSUPPORTED_MGF: _Reasons - UNSUPPORTED_PUBLIC_KEY_ALGORITHM: _Reasons - UNSUPPORTED_ELLIPTIC_CURVE: _Reasons - UNSUPPORTED_SERIALIZATION: _Reasons - UNSUPPORTED_X509: _Reasons - UNSUPPORTED_EXCHANGE_ALGORITHM: _Reasons - UNSUPPORTED_DIFFIE_HELLMAN: _Reasons - UNSUPPORTED_MAC: _Reasons diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi deleted file mode 100644 index 103e96c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi +++ /dev/null @@ -1,117 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import datetime -from collections.abc import Iterator - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes -from cryptography.x509 import ocsp - -class OCSPRequest: - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - @property - def extensions(self) -> x509.Extensions: ... - -class OCSPResponse: - @property - def responses(self) -> Iterator[OCSPSingleResponse]: ... - @property - def response_status(self) -> ocsp.OCSPResponseStatus: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_response_bytes(self) -> bytes: ... - @property - def certificates(self) -> list[x509.Certificate]: ... - @property - def responder_key_hash(self) -> bytes | None: ... - @property - def responder_name(self) -> x509.Name | None: ... - @property - def produced_at(self) -> datetime.datetime: ... - @property - def produced_at_utc(self) -> datetime.datetime: ... - @property - def certificate_status(self) -> ocsp.OCSPCertStatus: ... - @property - def revocation_time(self) -> datetime.datetime | None: ... - @property - def revocation_time_utc(self) -> datetime.datetime | None: ... - @property - def revocation_reason(self) -> x509.ReasonFlags | None: ... - @property - def this_update(self) -> datetime.datetime: ... - @property - def this_update_utc(self) -> datetime.datetime: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def single_extensions(self) -> x509.Extensions: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - -class OCSPSingleResponse: - @property - def certificate_status(self) -> ocsp.OCSPCertStatus: ... - @property - def revocation_time(self) -> datetime.datetime | None: ... - @property - def revocation_time_utc(self) -> datetime.datetime | None: ... - @property - def revocation_reason(self) -> x509.ReasonFlags | None: ... - @property - def this_update(self) -> datetime.datetime: ... - @property - def this_update_utc(self) -> datetime.datetime: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def issuer_key_hash(self) -> bytes: ... - @property - def issuer_name_hash(self) -> bytes: ... - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def serial_number(self) -> int: ... - -def load_der_ocsp_request(data: bytes) -> ocsp.OCSPRequest: ... -def load_der_ocsp_response(data: bytes) -> ocsp.OCSPResponse: ... -def create_ocsp_request( - builder: ocsp.OCSPRequestBuilder, -) -> ocsp.OCSPRequest: ... -def create_ocsp_response( - status: ocsp.OCSPResponseStatus, - builder: ocsp.OCSPResponseBuilder | None, - private_key: PrivateKeyTypes | None, - hash_algorithm: hashes.HashAlgorithm | None, -) -> ocsp.OCSPResponse: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi deleted file mode 100644 index 5fb3cb2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ /dev/null @@ -1,75 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.bindings._rust.openssl import ( - aead, - ciphers, - cmac, - dh, - dsa, - ec, - ed448, - ed25519, - hashes, - hmac, - kdf, - keys, - poly1305, - rsa, - x448, - x25519, -) - -__all__ = [ - "aead", - "ciphers", - "cmac", - "dh", - "dsa", - "ec", - "ed448", - "ed25519", - "hashes", - "hmac", - "kdf", - "keys", - "openssl_version", - "openssl_version_text", - "poly1305", - "raise_openssl_error", - "rsa", - "x448", - "x25519", -] - -CRYPTOGRAPHY_IS_LIBRESSL: bool -CRYPTOGRAPHY_IS_BORINGSSL: bool -CRYPTOGRAPHY_IS_AWSLC: bool -CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_309_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_320_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_330_OR_GREATER: bool -CRYPTOGRAPHY_OPENSSL_350_OR_GREATER: bool - -class Providers: ... - -_legacy_provider_loaded: bool -_providers: Providers - -def openssl_version() -> int: ... -def openssl_version_text() -> str: ... -def raise_openssl_error() -> typing.NoReturn: ... -def capture_error_stack() -> list[OpenSSLError]: ... -def is_fips_enabled() -> bool: ... -def enable_fips(providers: Providers) -> None: ... - -class OpenSSLError: - @property - def lib(self) -> int: ... - @property - def reason(self) -> int: ... - @property - def reason_text(self) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi deleted file mode 100644 index 831fcd1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi +++ /dev/null @@ -1,107 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from collections.abc import Sequence - -from cryptography.utils import Buffer - -class AESGCM: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - -class ChaCha20Poly1305: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key() -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - -class AESCCM: - def __init__(self, key: Buffer, tag_length: int = 16) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - -class AESSIV: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - ) -> bytes: ... - def decrypt( - self, - data: Buffer, - associated_data: Sequence[Buffer] | None, - ) -> bytes: ... - -class AESOCB3: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - -class AESGCMSIV: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_key(bit_length: int) -> bytes: ... - def encrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... - def decrypt( - self, - nonce: Buffer, - data: Buffer, - associated_data: Buffer | None, - ) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi deleted file mode 100644 index a48fb01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi +++ /dev/null @@ -1,38 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import ciphers -from cryptography.hazmat.primitives.ciphers import modes - -@typing.overload -def create_encryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag -) -> ciphers.AEADEncryptionContext: ... -@typing.overload -def create_encryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None -) -> ciphers.CipherContext: ... -@typing.overload -def create_decryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag -) -> ciphers.AEADDecryptionContext: ... -@typing.overload -def create_decryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None -) -> ciphers.CipherContext: ... -def cipher_supported( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode -) -> bool: ... -def _advance( - ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int -) -> None: ... -def _advance_aad( - ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int -) -> None: ... - -class CipherContext: ... -class AEADEncryptionContext: ... -class AEADDecryptionContext: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi deleted file mode 100644 index 9c03508..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi +++ /dev/null @@ -1,18 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import ciphers - -class CMAC: - def __init__( - self, - algorithm: ciphers.BlockCipherAlgorithm, - backend: typing.Any = None, - ) -> None: ... - def update(self, data: bytes) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, signature: bytes) -> None: ... - def copy(self) -> CMAC: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi deleted file mode 100644 index 08733d7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi +++ /dev/null @@ -1,51 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import dh - -MIN_MODULUS_SIZE: int - -class DHPrivateKey: ... -class DHPublicKey: ... -class DHParameters: ... - -class DHPrivateNumbers: - def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None: ... - def private_key(self, backend: typing.Any = None) -> dh.DHPrivateKey: ... - @property - def x(self) -> int: ... - @property - def public_numbers(self) -> DHPublicNumbers: ... - -class DHPublicNumbers: - def __init__( - self, y: int, parameter_numbers: DHParameterNumbers - ) -> None: ... - def public_key(self, backend: typing.Any = None) -> dh.DHPublicKey: ... - @property - def y(self) -> int: ... - @property - def parameter_numbers(self) -> DHParameterNumbers: ... - -class DHParameterNumbers: - def __init__(self, p: int, g: int, q: int | None = None) -> None: ... - def parameters(self, backend: typing.Any = None) -> dh.DHParameters: ... - @property - def p(self) -> int: ... - @property - def g(self) -> int: ... - @property - def q(self) -> int | None: ... - -def generate_parameters( - generator: int, key_size: int, backend: typing.Any = None -) -> dh.DHParameters: ... -def from_pem_parameters( - data: bytes, backend: typing.Any = None -) -> dh.DHParameters: ... -def from_der_parameters( - data: bytes, backend: typing.Any = None -) -> dh.DHParameters: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi deleted file mode 100644 index 0922a4c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi +++ /dev/null @@ -1,41 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import dsa - -class DSAPrivateKey: ... -class DSAPublicKey: ... -class DSAParameters: ... - -class DSAPrivateNumbers: - def __init__(self, x: int, public_numbers: DSAPublicNumbers) -> None: ... - @property - def x(self) -> int: ... - @property - def public_numbers(self) -> DSAPublicNumbers: ... - def private_key(self, backend: typing.Any = None) -> dsa.DSAPrivateKey: ... - -class DSAPublicNumbers: - def __init__( - self, y: int, parameter_numbers: DSAParameterNumbers - ) -> None: ... - @property - def y(self) -> int: ... - @property - def parameter_numbers(self) -> DSAParameterNumbers: ... - def public_key(self, backend: typing.Any = None) -> dsa.DSAPublicKey: ... - -class DSAParameterNumbers: - def __init__(self, p: int, q: int, g: int) -> None: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def g(self) -> int: ... - def parameters(self, backend: typing.Any = None) -> dsa.DSAParameters: ... - -def generate_parameters(key_size: int) -> dsa.DSAParameters: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi deleted file mode 100644 index 5c3b7bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import ec - -class ECPrivateKey: ... -class ECPublicKey: ... - -class EllipticCurvePrivateNumbers: - def __init__( - self, private_value: int, public_numbers: EllipticCurvePublicNumbers - ) -> None: ... - def private_key( - self, backend: typing.Any = None - ) -> ec.EllipticCurvePrivateKey: ... - @property - def private_value(self) -> int: ... - @property - def public_numbers(self) -> EllipticCurvePublicNumbers: ... - -class EllipticCurvePublicNumbers: - def __init__(self, x: int, y: int, curve: ec.EllipticCurve) -> None: ... - def public_key( - self, backend: typing.Any = None - ) -> ec.EllipticCurvePublicKey: ... - @property - def x(self) -> int: ... - @property - def y(self) -> int: ... - @property - def curve(self) -> ec.EllipticCurve: ... - def __eq__(self, other: object) -> bool: ... - -def curve_supported(curve: ec.EllipticCurve) -> bool: ... -def generate_private_key( - curve: ec.EllipticCurve, backend: typing.Any = None -) -> ec.EllipticCurvePrivateKey: ... -def from_private_numbers( - numbers: ec.EllipticCurvePrivateNumbers, -) -> ec.EllipticCurvePrivateKey: ... -def from_public_numbers( - numbers: ec.EllipticCurvePublicNumbers, -) -> ec.EllipticCurvePublicKey: ... -def from_public_bytes( - curve: ec.EllipticCurve, data: bytes -) -> ec.EllipticCurvePublicKey: ... -def derive_private_key( - private_value: int, curve: ec.EllipticCurve -) -> ec.EllipticCurvePrivateKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi deleted file mode 100644 index f85b3d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import ed25519 -from cryptography.utils import Buffer - -class Ed25519PrivateKey: ... -class Ed25519PublicKey: ... - -def generate_key() -> ed25519.Ed25519PrivateKey: ... -def from_private_bytes(data: Buffer) -> ed25519.Ed25519PrivateKey: ... -def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi deleted file mode 100644 index c8ca0ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import ed448 -from cryptography.utils import Buffer - -class Ed448PrivateKey: ... -class Ed448PublicKey: ... - -def generate_key() -> ed448.Ed448PrivateKey: ... -def from_private_bytes(data: Buffer) -> ed448.Ed448PrivateKey: ... -def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi deleted file mode 100644 index 6bfd295..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi +++ /dev/null @@ -1,28 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import hashes -from cryptography.utils import Buffer - -class Hash(hashes.HashContext): - def __init__( - self, algorithm: hashes.HashAlgorithm, backend: typing.Any = None - ) -> None: ... - @property - def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def copy(self) -> Hash: ... - -def hash_supported(algorithm: hashes.HashAlgorithm) -> bool: ... - -class XOFHash: - def __init__(self, algorithm: hashes.ExtendableOutputFunction) -> None: ... - @property - def algorithm(self) -> hashes.ExtendableOutputFunction: ... - def update(self, data: Buffer) -> None: ... - def squeeze(self, length: int) -> bytes: ... - def copy(self) -> XOFHash: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi deleted file mode 100644 index 3883d1b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi +++ /dev/null @@ -1,22 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives import hashes -from cryptography.utils import Buffer - -class HMAC(hashes.HashContext): - def __init__( - self, - key: Buffer, - algorithm: hashes.HashAlgorithm, - backend: typing.Any = None, - ) -> None: ... - @property - def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, signature: bytes) -> None: ... - def copy(self) -> HMAC: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi deleted file mode 100644 index 9e2d8d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +++ /dev/null @@ -1,72 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.hashes import HashAlgorithm -from cryptography.utils import Buffer - -def derive_pbkdf2_hmac( - key_material: Buffer, - algorithm: HashAlgorithm, - salt: bytes, - iterations: int, - length: int, -) -> bytes: ... - -class Scrypt: - def __init__( - self, - salt: bytes, - length: int, - n: int, - r: int, - p: int, - backend: typing.Any = None, - ) -> None: ... - def derive(self, key_material: Buffer) -> bytes: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class Argon2id: - def __init__( - self, - *, - salt: bytes, - length: int, - iterations: int, - lanes: int, - memory_cost: int, - ad: bytes | None = None, - secret: bytes | None = None, - ) -> None: ... - def derive(self, key_material: bytes) -> bytes: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - def derive_phc_encoded(self, key_material: bytes) -> str: ... - @classmethod - def verify_phc_encoded( - cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None - ) -> None: ... - -class HKDF: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - salt: bytes | None, - info: bytes | None, - backend: typing.Any = None, - ): ... - def derive(self, key_material: Buffer) -> bytes: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... - -class HKDFExpand: - def __init__( - self, - algorithm: HashAlgorithm, - length: int, - info: bytes | None, - backend: typing.Any = None, - ): ... - def derive(self, key_material: Buffer) -> bytes: ... - def verify(self, key_material: bytes, expected_key: bytes) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi deleted file mode 100644 index 404057e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi +++ /dev/null @@ -1,34 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric.types import ( - PrivateKeyTypes, - PublicKeyTypes, -) -from cryptography.utils import Buffer - -def load_der_private_key( - data: Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> PrivateKeyTypes: ... -def load_pem_private_key( - data: Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> PrivateKeyTypes: ... -def load_der_public_key( - data: bytes, - backend: typing.Any = None, -) -> PublicKeyTypes: ... -def load_pem_public_key( - data: bytes, - backend: typing.Any = None, -) -> PublicKeyTypes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi deleted file mode 100644 index 45a2a39..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi +++ /dev/null @@ -1,15 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.utils import Buffer - -class Poly1305: - def __init__(self, key: Buffer) -> None: ... - @staticmethod - def generate_tag(key: Buffer, data: Buffer) -> bytes: ... - @staticmethod - def verify_tag(key: Buffer, data: Buffer, tag: bytes) -> None: ... - def update(self, data: Buffer) -> None: ... - def finalize(self) -> bytes: ... - def verify(self, tag: bytes) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi deleted file mode 100644 index ef7752d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi +++ /dev/null @@ -1,55 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing - -from cryptography.hazmat.primitives.asymmetric import rsa - -class RSAPrivateKey: ... -class RSAPublicKey: ... - -class RSAPrivateNumbers: - def __init__( - self, - p: int, - q: int, - d: int, - dmp1: int, - dmq1: int, - iqmp: int, - public_numbers: RSAPublicNumbers, - ) -> None: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def d(self) -> int: ... - @property - def dmp1(self) -> int: ... - @property - def dmq1(self) -> int: ... - @property - def iqmp(self) -> int: ... - @property - def public_numbers(self) -> RSAPublicNumbers: ... - def private_key( - self, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, - ) -> rsa.RSAPrivateKey: ... - -class RSAPublicNumbers: - def __init__(self, e: int, n: int) -> None: ... - @property - def n(self) -> int: ... - @property - def e(self) -> int: ... - def public_key(self, backend: typing.Any = None) -> rsa.RSAPublicKey: ... - -def generate_private_key( - public_exponent: int, - key_size: int, -) -> rsa.RSAPrivateKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi deleted file mode 100644 index 38d2add..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import x25519 -from cryptography.utils import Buffer - -class X25519PrivateKey: ... -class X25519PublicKey: ... - -def generate_key() -> x25519.X25519PrivateKey: ... -def from_private_bytes(data: Buffer) -> x25519.X25519PrivateKey: ... -def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi deleted file mode 100644 index 3ac0980..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.primitives.asymmetric import x448 -from cryptography.utils import Buffer - -class X448PrivateKey: ... -class X448PublicKey: ... - -def generate_key() -> x448.X448PrivateKey: ... -def from_private_bytes(data: Buffer) -> x448.X448PrivateKey: ... -def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi deleted file mode 100644 index b25becb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi +++ /dev/null @@ -1,52 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import typing -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes -from cryptography.hazmat.primitives.serialization import ( - KeySerializationEncryption, -) -from cryptography.hazmat.primitives.serialization.pkcs12 import ( - PKCS12KeyAndCertificates, - PKCS12PrivateKeyTypes, -) -from cryptography.utils import Buffer - -class PKCS12Certificate: - def __init__( - self, cert: x509.Certificate, friendly_name: bytes | None - ) -> None: ... - @property - def friendly_name(self) -> bytes | None: ... - @property - def certificate(self) -> x509.Certificate: ... - -def load_key_and_certificates( - data: Buffer, - password: Buffer | None, - backend: typing.Any = None, -) -> tuple[ - PrivateKeyTypes | None, - x509.Certificate | None, - list[x509.Certificate], -]: ... -def load_pkcs12( - data: bytes, - password: bytes | None, - backend: typing.Any = None, -) -> PKCS12KeyAndCertificates: ... -def serialize_java_truststore( - certs: Iterable[PKCS12Certificate], - encryption_algorithm: KeySerializationEncryption, -) -> bytes: ... -def serialize_key_and_certificates( - name: bytes | None, - key: PKCS12PrivateKeyTypes | None, - cert: x509.Certificate | None, - cas: Iterable[x509.Certificate | PKCS12Certificate] | None, - encryption_algorithm: KeySerializationEncryption, -) -> bytes: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi deleted file mode 100644 index 358b135..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi +++ /dev/null @@ -1,50 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives.serialization import pkcs7 - -def serialize_certificates( - certs: list[x509.Certificate], - encoding: serialization.Encoding, -) -> bytes: ... -def encrypt_and_serialize( - builder: pkcs7.PKCS7EnvelopeBuilder, - content_encryption_algorithm: pkcs7.ContentEncryptionAlgorithm, - encoding: serialization.Encoding, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def sign_and_serialize( - builder: pkcs7.PKCS7SignatureBuilder, - encoding: serialization.Encoding, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_der( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_pem( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def decrypt_smime( - data: bytes, - certificate: x509.Certificate, - private_key: rsa.RSAPrivateKey, - options: Iterable[pkcs7.PKCS7Options], -) -> bytes: ... -def load_pem_pkcs7_certificates( - data: bytes, -) -> list[x509.Certificate]: ... -def load_der_pkcs7_certificates( - data: bytes, -) -> list[x509.Certificate]: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi deleted file mode 100644 index c6c6d0b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography import x509 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.serialization import pkcs7 -from cryptography.utils import Buffer - -class TestCertificate: - not_after_tag: int - not_before_tag: int - issuer_value_tags: list[int] - subject_value_tags: list[int] - -def test_parse_certificate(data: bytes) -> TestCertificate: ... -def pkcs7_verify( - encoding: serialization.Encoding, - sig: bytes, - msg: Buffer | None, - certs: list[x509.Certificate], - options: list[pkcs7.PKCS7Options], -) -> None: ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi deleted file mode 100644 index 83c3441..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +++ /dev/null @@ -1,301 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import datetime -import typing -from collections.abc import Iterator - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric.ec import ECDSA -from cryptography.hazmat.primitives.asymmetric.padding import PSS, PKCS1v15 -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPublicKeyTypes, - CertificatePublicKeyTypes, - PrivateKeyTypes, -) -from cryptography.x509 import certificate_transparency - -def load_pem_x509_certificate( - data: bytes, backend: typing.Any = None -) -> x509.Certificate: ... -def load_der_x509_certificate( - data: bytes, backend: typing.Any = None -) -> x509.Certificate: ... -def load_pem_x509_certificates( - data: bytes, -) -> list[x509.Certificate]: ... -def load_pem_x509_crl( - data: bytes, backend: typing.Any = None -) -> x509.CertificateRevocationList: ... -def load_der_x509_crl( - data: bytes, backend: typing.Any = None -) -> x509.CertificateRevocationList: ... -def load_pem_x509_csr( - data: bytes, backend: typing.Any = None -) -> x509.CertificateSigningRequest: ... -def load_der_x509_csr( - data: bytes, backend: typing.Any = None -) -> x509.CertificateSigningRequest: ... -def encode_name_bytes(name: x509.Name) -> bytes: ... -def encode_extension_value(extension: x509.ExtensionType) -> bytes: ... -def create_x509_certificate( - builder: x509.CertificateBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.Certificate: ... -def create_x509_csr( - builder: x509.CertificateSigningRequestBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.CertificateSigningRequest: ... -def create_x509_crl( - builder: x509.CertificateRevocationListBuilder, - private_key: PrivateKeyTypes, - hash_algorithm: hashes.HashAlgorithm | None, - rsa_padding: PKCS1v15 | PSS | None, - ecdsa_deterministic: bool | None, -) -> x509.CertificateRevocationList: ... - -class Sct: - @property - def version(self) -> certificate_transparency.Version: ... - @property - def log_id(self) -> bytes: ... - @property - def timestamp(self) -> datetime.datetime: ... - @property - def entry_type(self) -> certificate_transparency.LogEntryType: ... - @property - def signature_hash_algorithm(self) -> hashes.HashAlgorithm: ... - @property - def signature_algorithm( - self, - ) -> certificate_transparency.SignatureAlgorithm: ... - @property - def signature(self) -> bytes: ... - @property - def extension_bytes(self) -> bytes: ... - -class Certificate: - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... - @property - def serial_number(self) -> int: ... - @property - def version(self) -> x509.Version: ... - def public_key(self) -> CertificatePublicKeyTypes: ... - @property - def public_key_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def not_valid_before(self) -> datetime.datetime: ... - @property - def not_valid_before_utc(self) -> datetime.datetime: ... - @property - def not_valid_after(self) -> datetime.datetime: ... - @property - def not_valid_after_utc(self) -> datetime.datetime: ... - @property - def issuer(self) -> x509.Name: ... - @property - def subject(self) -> x509.Name: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certificate_bytes(self) -> bytes: ... - @property - def tbs_precertificate_bytes(self) -> bytes: ... - def __eq__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - def verify_directly_issued_by(self, issuer: Certificate) -> None: ... - -class RevokedCertificate: ... - -class CertificateRevocationList: - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... - def get_revoked_certificate_by_serial_number( - self, serial_number: int - ) -> x509.RevokedCertificate | None: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def issuer(self) -> x509.Name: ... - @property - def next_update(self) -> datetime.datetime | None: ... - @property - def next_update_utc(self) -> datetime.datetime | None: ... - @property - def last_update(self) -> datetime.datetime: ... - @property - def last_update_utc(self) -> datetime.datetime: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certlist_bytes(self) -> bytes: ... - def __eq__(self, other: object) -> bool: ... - def __len__(self) -> int: ... - @typing.overload - def __getitem__(self, idx: int) -> x509.RevokedCertificate: ... - @typing.overload - def __getitem__(self, idx: slice) -> list[x509.RevokedCertificate]: ... - def __iter__(self) -> Iterator[x509.RevokedCertificate]: ... - def is_signature_valid( - self, public_key: CertificateIssuerPublicKeyTypes - ) -> bool: ... - -class CertificateSigningRequest: - def __eq__(self, other: object) -> bool: ... - def __hash__(self) -> int: ... - def public_key(self) -> CertificatePublicKeyTypes: ... - @property - def subject(self) -> x509.Name: ... - @property - def signature_hash_algorithm( - self, - ) -> hashes.HashAlgorithm | None: ... - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... - @property - def signature_algorithm_parameters( - self, - ) -> PSS | PKCS1v15 | ECDSA | None: ... - @property - def extensions(self) -> x509.Extensions: ... - @property - def attributes(self) -> x509.Attributes: ... - def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... - @property - def signature(self) -> bytes: ... - @property - def tbs_certrequest_bytes(self) -> bytes: ... - @property - def is_signature_valid(self) -> bool: ... - -class PolicyBuilder: - def time(self, time: datetime.datetime) -> PolicyBuilder: ... - def store(self, store: Store) -> PolicyBuilder: ... - def max_chain_depth(self, max_chain_depth: int) -> PolicyBuilder: ... - def extension_policies( - self, *, ca_policy: ExtensionPolicy, ee_policy: ExtensionPolicy - ) -> PolicyBuilder: ... - def build_client_verifier(self) -> ClientVerifier: ... - def build_server_verifier( - self, subject: x509.verification.Subject - ) -> ServerVerifier: ... - -class Policy: - @property - def max_chain_depth(self) -> int: ... - @property - def subject(self) -> x509.verification.Subject | None: ... - @property - def validation_time(self) -> datetime.datetime: ... - @property - def extended_key_usage(self) -> x509.ObjectIdentifier: ... - @property - def minimum_rsa_modulus(self) -> int: ... - -class Criticality: - CRITICAL: Criticality - AGNOSTIC: Criticality - NON_CRITICAL: Criticality - -T = typing.TypeVar("T", contravariant=True, bound=x509.ExtensionType) - -MaybeExtensionValidatorCallback = typing.Callable[ - [ - Policy, - x509.Certificate, - T | None, - ], - None, -] - -PresentExtensionValidatorCallback = typing.Callable[ - [Policy, x509.Certificate, T], - None, -] - -class ExtensionPolicy: - @staticmethod - def permit_all() -> ExtensionPolicy: ... - @staticmethod - def webpki_defaults_ca() -> ExtensionPolicy: ... - @staticmethod - def webpki_defaults_ee() -> ExtensionPolicy: ... - def require_not_present( - self, extension_type: type[x509.ExtensionType] - ) -> ExtensionPolicy: ... - def may_be_present( - self, - extension_type: type[T], - criticality: Criticality, - validator: MaybeExtensionValidatorCallback[T] | None, - ) -> ExtensionPolicy: ... - def require_present( - self, - extension_type: type[T], - criticality: Criticality, - validator: PresentExtensionValidatorCallback[T] | None, - ) -> ExtensionPolicy: ... - -class VerifiedClient: - @property - def subjects(self) -> list[x509.GeneralName] | None: ... - @property - def chain(self) -> list[x509.Certificate]: ... - -class ClientVerifier: - @property - def policy(self) -> Policy: ... - @property - def store(self) -> Store: ... - def verify( - self, - leaf: x509.Certificate, - intermediates: list[x509.Certificate], - ) -> VerifiedClient: ... - -class ServerVerifier: - @property - def policy(self) -> Policy: ... - @property - def store(self) -> Store: ... - def verify( - self, - leaf: x509.Certificate, - intermediates: list[x509.Certificate], - ) -> list[x509.Certificate]: ... - -class Store: - def __init__(self, certs: list[x509.Certificate]) -> None: ... - -class VerificationError(Exception): ... diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py deleted file mode 100644 index b509336..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py deleted file mode 100644 index 063bcf5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +++ /dev/null @@ -1,207 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - - -def cryptography_has_set_cert_cb() -> list[str]: - return [ - "SSL_CTX_set_cert_cb", - "SSL_set_cert_cb", - ] - - -def cryptography_has_ssl_st() -> list[str]: - return [ - "SSL_ST_BEFORE", - "SSL_ST_OK", - "SSL_ST_INIT", - "SSL_ST_RENEGOTIATE", - ] - - -def cryptography_has_tls_st() -> list[str]: - return [ - "TLS_ST_BEFORE", - "TLS_ST_OK", - ] - - -def cryptography_has_ssl_sigalgs() -> list[str]: - return [ - "SSL_CTX_set1_sigalgs_list", - ] - - -def cryptography_has_psk() -> list[str]: - return [ - "SSL_CTX_use_psk_identity_hint", - "SSL_CTX_set_psk_server_callback", - "SSL_CTX_set_psk_client_callback", - ] - - -def cryptography_has_psk_tlsv13() -> list[str]: - return [ - "SSL_CTX_set_psk_find_session_callback", - "SSL_CTX_set_psk_use_session_callback", - "Cryptography_SSL_SESSION_new", - "SSL_CIPHER_find", - "SSL_SESSION_set1_master_key", - "SSL_SESSION_set_cipher", - "SSL_SESSION_set_protocol_version", - ] - - -def cryptography_has_custom_ext() -> list[str]: - return [ - "SSL_CTX_add_client_custom_ext", - "SSL_CTX_add_server_custom_ext", - "SSL_extension_supported", - ] - - -def cryptography_has_tlsv13_functions() -> list[str]: - return [ - "SSL_CTX_set_ciphersuites", - ] - - -def cryptography_has_tlsv13_hs_functions() -> list[str]: - return [ - "SSL_VERIFY_POST_HANDSHAKE", - "SSL_verify_client_post_handshake", - "SSL_CTX_set_post_handshake_auth", - "SSL_set_post_handshake_auth", - "SSL_SESSION_get_max_early_data", - "SSL_write_early_data", - "SSL_read_early_data", - "SSL_CTX_set_max_early_data", - ] - - -def cryptography_has_ssl_verify_client_post_handshake() -> list[str]: - return [ - "SSL_verify_client_post_handshake", - ] - - -def cryptography_has_engine() -> list[str]: - return [ - "ENGINE_by_id", - "ENGINE_init", - "ENGINE_finish", - "ENGINE_get_default_RAND", - "ENGINE_set_default_RAND", - "ENGINE_unregister_RAND", - "ENGINE_ctrl_cmd", - "ENGINE_free", - "ENGINE_get_name", - "ENGINE_ctrl_cmd_string", - "ENGINE_load_builtin_engines", - "ENGINE_load_private_key", - "ENGINE_load_public_key", - "SSL_CTX_set_client_cert_engine", - ] - - -def cryptography_has_verified_chain() -> list[str]: - return [ - "SSL_get0_verified_chain", - ] - - -def cryptography_has_srtp() -> list[str]: - return [ - "SSL_CTX_set_tlsext_use_srtp", - "SSL_set_tlsext_use_srtp", - "SSL_get_selected_srtp_profile", - ] - - -def cryptography_has_op_no_renegotiation() -> list[str]: - return [ - "SSL_OP_NO_RENEGOTIATION", - ] - - -def cryptography_has_dtls_get_data_mtu() -> list[str]: - return [ - "DTLS_get_data_mtu", - ] - - -def cryptography_has_ssl_cookie() -> list[str]: - return [ - "SSL_OP_COOKIE_EXCHANGE", - "DTLSv1_listen", - "SSL_CTX_set_cookie_generate_cb", - "SSL_CTX_set_cookie_verify_cb", - ] - - -def cryptography_has_prime_checks() -> list[str]: - return [ - "BN_prime_checks_for_size", - ] - - -def cryptography_has_unexpected_eof_while_reading() -> list[str]: - return ["SSL_R_UNEXPECTED_EOF_WHILE_READING"] - - -def cryptography_has_ssl_op_ignore_unexpected_eof() -> list[str]: - return [ - "SSL_OP_IGNORE_UNEXPECTED_EOF", - ] - - -def cryptography_has_get_extms_support() -> list[str]: - return ["SSL_get_extms_support"] - - -def cryptography_has_ssl_get0_group_name() -> list[str]: - return ["SSL_get0_group_name"] - - -# This is a mapping of -# {condition: function-returning-names-dependent-on-that-condition} so we can -# loop over them and delete unsupported names at runtime. It will be removed -# when cffi supports #if in cdef. We use functions instead of just a dict of -# lists so we can use coverage to measure which are used. -CONDITIONAL_NAMES = { - "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, - "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, - "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, - "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, - "Cryptography_HAS_PSK": cryptography_has_psk, - "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, - "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, - "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, - "Cryptography_HAS_TLSv1_3_HS_FUNCTIONS": ( - cryptography_has_tlsv13_hs_functions - ), - "Cryptography_HAS_SSL_VERIFY_CLIENT_POST_HANDSHAKE": ( - cryptography_has_ssl_verify_client_post_handshake - ), - "Cryptography_HAS_ENGINE": cryptography_has_engine, - "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, - "Cryptography_HAS_SRTP": cryptography_has_srtp, - "Cryptography_HAS_OP_NO_RENEGOTIATION": ( - cryptography_has_op_no_renegotiation - ), - "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, - "Cryptography_HAS_SSL_COOKIE": cryptography_has_ssl_cookie, - "Cryptography_HAS_PRIME_CHECKS": cryptography_has_prime_checks, - "Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING": ( - cryptography_has_unexpected_eof_while_reading - ), - "Cryptography_HAS_SSL_OP_IGNORE_UNEXPECTED_EOF": ( - cryptography_has_ssl_op_ignore_unexpected_eof - ), - "Cryptography_HAS_GET_EXTMS_SUPPORT": cryptography_has_get_extms_support, - "Cryptography_HAS_SSL_GET0_GROUP_NAME": ( - cryptography_has_ssl_get0_group_name - ), -} diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py deleted file mode 100644 index 4494c71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py +++ /dev/null @@ -1,137 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import os -import sys -import threading -import types -import typing -import warnings -from collections.abc import Callable - -import cryptography -from cryptography.exceptions import InternalError -from cryptography.hazmat.bindings._rust import _openssl, openssl -from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES -from cryptography.utils import CryptographyDeprecationWarning - - -def _openssl_assert(ok: bool) -> None: - if not ok: - errors = openssl.capture_error_stack() - - raise InternalError( - "Unknown OpenSSL error. This error is commonly encountered when " - "another library is not cleaning up the OpenSSL error stack. If " - "you are using cryptography with another library that uses " - "OpenSSL try disabling it before reporting a bug. Otherwise " - "please file an issue at https://github.com/pyca/cryptography/" - "issues with information on how to reproduce " - f"this. ({errors!r})", - errors, - ) - - -def build_conditional_library( - lib: typing.Any, - conditional_names: dict[str, Callable[[], list[str]]], -) -> typing.Any: - conditional_lib = types.ModuleType("lib") - conditional_lib._original_lib = lib # type: ignore[attr-defined] - excluded_names = set() - for condition, names_cb in conditional_names.items(): - if not getattr(lib, condition): - excluded_names.update(names_cb()) - - for attr in dir(lib): - if attr not in excluded_names: - setattr(conditional_lib, attr, getattr(lib, attr)) - - return conditional_lib - - -class Binding: - """ - OpenSSL API wrapper. - """ - - lib: typing.ClassVar[typing.Any] = None - ffi = _openssl.ffi - _lib_loaded = False - _init_lock = threading.Lock() - - def __init__(self) -> None: - self._ensure_ffi_initialized() - - @classmethod - def _ensure_ffi_initialized(cls) -> None: - with cls._init_lock: - if not cls._lib_loaded: - cls.lib = build_conditional_library( - _openssl.lib, CONDITIONAL_NAMES - ) - cls._lib_loaded = True - - @classmethod - def init_static_locks(cls) -> None: - cls._ensure_ffi_initialized() - - -def _verify_package_version(version: str) -> None: - # Occasionally we run into situations where the version of the Python - # package does not match the version of the shared object that is loaded. - # This may occur in environments where multiple versions of cryptography - # are installed and available in the python path. To avoid errors cropping - # up later this code checks that the currently imported package and the - # shared object that were loaded have the same version and raise an - # ImportError if they do not - so_package_version = _openssl.ffi.string( - _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION - ) - if version.encode("ascii") != so_package_version: - raise ImportError( - "The version of cryptography does not match the loaded " - "shared object. This can happen if you have multiple copies of " - "cryptography installed in your Python path. Please try creating " - "a new virtual environment to resolve this issue. " - f"Loaded python version: {version}, " - f"shared object version: {so_package_version}" - ) - - _openssl_assert( - _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(), - ) - - -_verify_package_version(cryptography.__version__) - -Binding.init_static_locks() - -if ( - sys.platform == "win32" - and os.environ.get("PROCESSOR_ARCHITEW6432") is not None -): - warnings.warn( - "You are using cryptography on a 32-bit Python on a 64-bit Windows " - "Operating System. Cryptography will be significantly faster if you " - "switch to using a 64-bit Python.", - UserWarning, - stacklevel=2, - ) - -if ( - not openssl.CRYPTOGRAPHY_IS_LIBRESSL - and not openssl.CRYPTOGRAPHY_IS_BORINGSSL - and not openssl.CRYPTOGRAPHY_IS_AWSLC - and not openssl.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER -): - warnings.warn( - "You are using OpenSSL < 3.0. Support for OpenSSL < 3.0 is deprecated " - "and will be removed in the next release. Please upgrade to OpenSSL " - "3.0 or later.", - CryptographyDeprecationWarning, - stacklevel=2, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py deleted file mode 100644 index 41d7318..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py deleted file mode 100644 index 41d7318..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py deleted file mode 100644 index 072a991..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py +++ /dev/null @@ -1,112 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, - _verify_key_size, -) - - -class ARC4(CipherAlgorithm): - name = "RC4" - key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class TripleDES(BlockCipherAlgorithm): - name = "3DES" - block_size = 64 - key_sizes = frozenset([64, 128, 192]) - - def __init__(self, key: bytes): - if len(key) == 8: - key += key + key - elif len(key) == 16: - key += key[:8] - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -# Not actually supported, marker for tests -class _DES: - key_size = 64 - - -class Blowfish(BlockCipherAlgorithm): - name = "Blowfish" - block_size = 64 - key_sizes = frozenset(range(32, 449, 8)) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class CAST5(BlockCipherAlgorithm): - name = "CAST5" - block_size = 64 - key_sizes = frozenset(range(40, 129, 8)) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class SEED(BlockCipherAlgorithm): - name = "SEED" - block_size = 128 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class IDEA(BlockCipherAlgorithm): - name = "IDEA" - block_size = 64 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -# This class only allows RC2 with a 128-bit key. No support for -# effective key bits or other key sizes is provided. -class RC2(BlockCipherAlgorithm): - name = "RC2" - block_size = 64 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py deleted file mode 100644 index b509336..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py deleted file mode 100644 index ea55ffd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -# This exists to break an import cycle. It is normally accessible from the -# asymmetric padding module. - - -class AsymmetricPadding(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this padding (e.g. "PSS", "PKCS1"). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py deleted file mode 100644 index 305a9fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py +++ /dev/null @@ -1,60 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils - -# This exists to break an import cycle. It is normally accessible from the -# ciphers module. - - -class CipherAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this mode (e.g. "AES", "Camellia"). - """ - - @property - @abc.abstractmethod - def key_sizes(self) -> frozenset[int]: - """ - Valid key sizes for this algorithm in bits - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The size of the key being used as an integer in bits (e.g. 128, 256). - """ - - -class BlockCipherAlgorithm(CipherAlgorithm): - key: utils.Buffer - - @property - @abc.abstractmethod - def block_size(self) -> int: - """ - The size of a block as an integer in bits (e.g. 64, 128). - """ - - -def _verify_key_size( - algorithm: CipherAlgorithm, key: utils.Buffer -) -> utils.Buffer: - # Verify that the key is instance of bytes - utils._check_byteslike("key", key) - - # Verify that the key size matches the expected key size - if len(key) * 8 not in algorithm.key_sizes: - raise ValueError( - f"Invalid key size ({len(key) * 8}) for {algorithm.name}." - ) - return key diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py deleted file mode 100644 index e998865..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py +++ /dev/null @@ -1,168 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.hazmat.primitives.hashes import HashAlgorithm - -# This exists to break an import cycle. These classes are normally accessible -# from the serialization module. - - -class PBES(utils.Enum): - PBESv1SHA1And3KeyTripleDESCBC = "PBESv1 using SHA1 and 3-Key TripleDES" - PBESv2SHA256AndAES256CBC = "PBESv2 using SHA256 PBKDF2 and AES256 CBC" - - -class Encoding(utils.Enum): - PEM = "PEM" - DER = "DER" - OpenSSH = "OpenSSH" - Raw = "Raw" - X962 = "ANSI X9.62" - SMIME = "S/MIME" - - -class PrivateFormat(utils.Enum): - PKCS8 = "PKCS8" - TraditionalOpenSSL = "TraditionalOpenSSL" - Raw = "Raw" - OpenSSH = "OpenSSH" - PKCS12 = "PKCS12" - - def encryption_builder(self) -> KeySerializationEncryptionBuilder: - if self not in (PrivateFormat.OpenSSH, PrivateFormat.PKCS12): - raise ValueError( - "encryption_builder only supported with PrivateFormat.OpenSSH" - " and PrivateFormat.PKCS12" - ) - return KeySerializationEncryptionBuilder(self) - - -class PublicFormat(utils.Enum): - SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" - PKCS1 = "Raw PKCS#1" - OpenSSH = "OpenSSH" - Raw = "Raw" - CompressedPoint = "X9.62 Compressed Point" - UncompressedPoint = "X9.62 Uncompressed Point" - - -class ParameterFormat(utils.Enum): - PKCS3 = "PKCS3" - - -class KeySerializationEncryption(metaclass=abc.ABCMeta): - pass - - -class BestAvailableEncryption(KeySerializationEncryption): - def __init__(self, password: bytes): - if not isinstance(password, bytes) or len(password) == 0: - raise ValueError("Password must be 1 or more bytes.") - - self.password = password - - -class NoEncryption(KeySerializationEncryption): - pass - - -class KeySerializationEncryptionBuilder: - def __init__( - self, - format: PrivateFormat, - *, - _kdf_rounds: int | None = None, - _hmac_hash: HashAlgorithm | None = None, - _key_cert_algorithm: PBES | None = None, - ) -> None: - self._format = format - - self._kdf_rounds = _kdf_rounds - self._hmac_hash = _hmac_hash - self._key_cert_algorithm = _key_cert_algorithm - - def kdf_rounds(self, rounds: int) -> KeySerializationEncryptionBuilder: - if self._kdf_rounds is not None: - raise ValueError("kdf_rounds already set") - - if not isinstance(rounds, int): - raise TypeError("kdf_rounds must be an integer") - - if rounds < 1: - raise ValueError("kdf_rounds must be a positive integer") - - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=rounds, - _hmac_hash=self._hmac_hash, - _key_cert_algorithm=self._key_cert_algorithm, - ) - - def hmac_hash( - self, algorithm: HashAlgorithm - ) -> KeySerializationEncryptionBuilder: - if self._format is not PrivateFormat.PKCS12: - raise TypeError( - "hmac_hash only supported with PrivateFormat.PKCS12" - ) - - if self._hmac_hash is not None: - raise ValueError("hmac_hash already set") - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=self._kdf_rounds, - _hmac_hash=algorithm, - _key_cert_algorithm=self._key_cert_algorithm, - ) - - def key_cert_algorithm( - self, algorithm: PBES - ) -> KeySerializationEncryptionBuilder: - if self._format is not PrivateFormat.PKCS12: - raise TypeError( - "key_cert_algorithm only supported with PrivateFormat.PKCS12" - ) - if self._key_cert_algorithm is not None: - raise ValueError("key_cert_algorithm already set") - return KeySerializationEncryptionBuilder( - self._format, - _kdf_rounds=self._kdf_rounds, - _hmac_hash=self._hmac_hash, - _key_cert_algorithm=algorithm, - ) - - def build(self, password: bytes) -> KeySerializationEncryption: - if not isinstance(password, bytes) or len(password) == 0: - raise ValueError("Password must be 1 or more bytes.") - - return _KeySerializationEncryption( - self._format, - password, - kdf_rounds=self._kdf_rounds, - hmac_hash=self._hmac_hash, - key_cert_algorithm=self._key_cert_algorithm, - ) - - -class _KeySerializationEncryption(KeySerializationEncryption): - def __init__( - self, - format: PrivateFormat, - password: bytes, - *, - kdf_rounds: int | None, - hmac_hash: HashAlgorithm | None, - key_cert_algorithm: PBES | None, - ): - self._format = format - self.password = password - - self._kdf_rounds = kdf_rounds - self._hmac_hash = hmac_hash - self._key_cert_algorithm = key_cert_algorithm diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py deleted file mode 100644 index b509336..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py deleted file mode 100644 index 1822e99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py +++ /dev/null @@ -1,147 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization - -generate_parameters = rust_openssl.dh.generate_parameters - - -DHPrivateNumbers = rust_openssl.dh.DHPrivateNumbers -DHPublicNumbers = rust_openssl.dh.DHPublicNumbers -DHParameterNumbers = rust_openssl.dh.DHParameterNumbers - - -class DHParameters(metaclass=abc.ABCMeta): - @abc.abstractmethod - def generate_private_key(self) -> DHPrivateKey: - """ - Generates and returns a DHPrivateKey. - """ - - @abc.abstractmethod - def parameter_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.ParameterFormat, - ) -> bytes: - """ - Returns the parameters serialized as bytes. - """ - - @abc.abstractmethod - def parameter_numbers(self) -> DHParameterNumbers: - """ - Returns a DHParameterNumbers. - """ - - -DHParametersWithSerialization = DHParameters -DHParameters.register(rust_openssl.dh.DHParameters) - - -class DHPublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def parameters(self) -> DHParameters: - """ - The DHParameters object associated with this public key. - """ - - @abc.abstractmethod - def public_numbers(self) -> DHPublicNumbers: - """ - Returns a DHPublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> DHPublicKey: - """ - Returns a copy. - """ - - -DHPublicKeyWithSerialization = DHPublicKey -DHPublicKey.register(rust_openssl.dh.DHPublicKey) - - -class DHPrivateKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def public_key(self) -> DHPublicKey: - """ - The DHPublicKey associated with this private key. - """ - - @abc.abstractmethod - def parameters(self) -> DHParameters: - """ - The DHParameters object associated with this private key. - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: DHPublicKey) -> bytes: - """ - Given peer's DHPublicKey, carry out the key exchange and - return shared key as bytes. - """ - - @abc.abstractmethod - def private_numbers(self) -> DHPrivateNumbers: - """ - Returns a DHPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> DHPrivateKey: - """ - Returns a copy. - """ - - -DHPrivateKeyWithSerialization = DHPrivateKey -DHPrivateKey.register(rust_openssl.dh.DHPrivateKey) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py deleted file mode 100644 index 21d78ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py +++ /dev/null @@ -1,167 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.utils import Buffer - - -class DSAParameters(metaclass=abc.ABCMeta): - @abc.abstractmethod - def generate_private_key(self) -> DSAPrivateKey: - """ - Generates and returns a DSAPrivateKey. - """ - - @abc.abstractmethod - def parameter_numbers(self) -> DSAParameterNumbers: - """ - Returns a DSAParameterNumbers. - """ - - -DSAParametersWithNumbers = DSAParameters -DSAParameters.register(rust_openssl.dsa.DSAParameters) - - -class DSAPrivateKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def public_key(self) -> DSAPublicKey: - """ - The DSAPublicKey associated with this private key. - """ - - @abc.abstractmethod - def parameters(self) -> DSAParameters: - """ - The DSAParameters object associated with this private key. - """ - - @abc.abstractmethod - def sign( - self, - data: Buffer, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> bytes: - """ - Signs the data - """ - - @abc.abstractmethod - def private_numbers(self) -> DSAPrivateNumbers: - """ - Returns a DSAPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> DSAPrivateKey: - """ - Returns a copy. - """ - - -DSAPrivateKeyWithSerialization = DSAPrivateKey -DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) - - -class DSAPublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the prime modulus. - """ - - @abc.abstractmethod - def parameters(self) -> DSAParameters: - """ - The DSAParameters object associated with this public key. - """ - - @abc.abstractmethod - def public_numbers(self) -> DSAPublicNumbers: - """ - Returns a DSAPublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: Buffer, - data: Buffer, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> DSAPublicKey: - """ - Returns a copy. - """ - - -DSAPublicKeyWithSerialization = DSAPublicKey -DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) - -DSAPrivateNumbers = rust_openssl.dsa.DSAPrivateNumbers -DSAPublicNumbers = rust_openssl.dsa.DSAPublicNumbers -DSAParameterNumbers = rust_openssl.dsa.DSAParameterNumbers - - -def generate_parameters( - key_size: int, backend: typing.Any = None -) -> DSAParameters: - if key_size not in (1024, 2048, 3072, 4096): - raise ValueError("Key size must be 1024, 2048, 3072, or 4096 bits.") - - return rust_openssl.dsa.generate_parameters(key_size) - - -def generate_private_key( - key_size: int, backend: typing.Any = None -) -> DSAPrivateKey: - parameters = generate_parameters(key_size) - return parameters.generate_private_key() diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py deleted file mode 100644 index a13d982..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py +++ /dev/null @@ -1,447 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat._oid import ObjectIdentifier -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils - - -class EllipticCurveOID: - SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") - SECP224R1 = ObjectIdentifier("1.3.132.0.33") - SECP256K1 = ObjectIdentifier("1.3.132.0.10") - SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") - SECP384R1 = ObjectIdentifier("1.3.132.0.34") - SECP521R1 = ObjectIdentifier("1.3.132.0.35") - BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") - BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") - BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") - SECT163K1 = ObjectIdentifier("1.3.132.0.1") - SECT163R2 = ObjectIdentifier("1.3.132.0.15") - SECT233K1 = ObjectIdentifier("1.3.132.0.26") - SECT233R1 = ObjectIdentifier("1.3.132.0.27") - SECT283K1 = ObjectIdentifier("1.3.132.0.16") - SECT283R1 = ObjectIdentifier("1.3.132.0.17") - SECT409K1 = ObjectIdentifier("1.3.132.0.36") - SECT409R1 = ObjectIdentifier("1.3.132.0.37") - SECT571K1 = ObjectIdentifier("1.3.132.0.38") - SECT571R1 = ObjectIdentifier("1.3.132.0.39") - - -class EllipticCurve(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - The name of the curve. e.g. secp256r1. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @property - @abc.abstractmethod - def group_order(self) -> int: - """ - The order of the curve's group. - """ - - -class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def algorithm( - self, - ) -> asym_utils.Prehashed | hashes.HashAlgorithm: - """ - The digest algorithm used with this signature. - """ - - -class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def exchange( - self, algorithm: ECDH, peer_public_key: EllipticCurvePublicKey - ) -> bytes: - """ - Performs a key exchange operation using the provided algorithm with the - provided peer's public key. - """ - - @abc.abstractmethod - def public_key(self) -> EllipticCurvePublicKey: - """ - The EllipticCurvePublicKey for this private key. - """ - - @property - @abc.abstractmethod - def curve(self) -> EllipticCurve: - """ - The EllipticCurve that this key is on. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @abc.abstractmethod - def sign( - self, - data: utils.Buffer, - signature_algorithm: EllipticCurveSignatureAlgorithm, - ) -> bytes: - """ - Signs the data - """ - - @abc.abstractmethod - def private_numbers(self) -> EllipticCurvePrivateNumbers: - """ - Returns an EllipticCurvePrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> EllipticCurvePrivateKey: - """ - Returns a copy. - """ - - -EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey -EllipticCurvePrivateKey.register(rust_openssl.ec.ECPrivateKey) - - -class EllipticCurvePublicKey(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def curve(self) -> EllipticCurve: - """ - The EllipticCurve that this key is on. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - Bit size of a secret scalar for the curve. - """ - - @abc.abstractmethod - def public_numbers(self) -> EllipticCurvePublicNumbers: - """ - Returns an EllipticCurvePublicNumbers. - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: utils.Buffer, - data: utils.Buffer, - signature_algorithm: EllipticCurveSignatureAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @classmethod - def from_encoded_point( - cls, curve: EllipticCurve, data: bytes - ) -> EllipticCurvePublicKey: - utils._check_bytes("data", data) - - if len(data) == 0: - raise ValueError("data must not be an empty byte string") - - if data[0] not in [0x02, 0x03, 0x04]: - raise ValueError("Unsupported elliptic curve point type") - - return rust_openssl.ec.from_public_bytes(curve, data) - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> EllipticCurvePublicKey: - """ - Returns a copy. - """ - - -EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey -EllipticCurvePublicKey.register(rust_openssl.ec.ECPublicKey) - -EllipticCurvePrivateNumbers = rust_openssl.ec.EllipticCurvePrivateNumbers -EllipticCurvePublicNumbers = rust_openssl.ec.EllipticCurvePublicNumbers - - -class SECT571R1(EllipticCurve): - name = "sect571r1" - key_size = 570 - group_order = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47 # noqa: E501 - - -class SECT409R1(EllipticCurve): - name = "sect409r1" - key_size = 409 - group_order = 0x10000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173 # noqa: E501 - - -class SECT283R1(EllipticCurve): - name = "sect283r1" - key_size = 283 - group_order = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307 # noqa: E501 - - -class SECT233R1(EllipticCurve): - name = "sect233r1" - key_size = 233 - group_order = 0x1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7 - - -class SECT163R2(EllipticCurve): - name = "sect163r2" - key_size = 163 - group_order = 0x40000000000000000000292FE77E70C12A4234C33 - - -class SECT571K1(EllipticCurve): - name = "sect571k1" - key_size = 571 - group_order = 0x20000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001 # noqa: E501 - - -class SECT409K1(EllipticCurve): - name = "sect409k1" - key_size = 409 - group_order = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF # noqa: E501 - - -class SECT283K1(EllipticCurve): - name = "sect283k1" - key_size = 283 - group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61 # noqa: E501 - - -class SECT233K1(EllipticCurve): - name = "sect233k1" - key_size = 233 - group_order = 0x8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF - - -class SECT163K1(EllipticCurve): - name = "sect163k1" - key_size = 163 - group_order = 0x4000000000000000000020108A2E0CC0D99F8A5EF - - -class SECP521R1(EllipticCurve): - name = "secp521r1" - key_size = 521 - group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409 # noqa: E501 - - -class SECP384R1(EllipticCurve): - name = "secp384r1" - key_size = 384 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 # noqa: E501 - - -class SECP256R1(EllipticCurve): - name = "secp256r1" - key_size = 256 - group_order = ( - 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - ) - - -class SECP256K1(EllipticCurve): - name = "secp256k1" - key_size = 256 - group_order = ( - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - ) - - -class SECP224R1(EllipticCurve): - name = "secp224r1" - key_size = 224 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D - - -class SECP192R1(EllipticCurve): - name = "secp192r1" - key_size = 192 - group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 - - -class BrainpoolP256R1(EllipticCurve): - name = "brainpoolP256r1" - key_size = 256 - group_order = ( - 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 - ) - - -class BrainpoolP384R1(EllipticCurve): - name = "brainpoolP384r1" - key_size = 384 - group_order = 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565 # noqa: E501 - - -class BrainpoolP512R1(EllipticCurve): - name = "brainpoolP512r1" - key_size = 512 - group_order = 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069 # noqa: E501 - - -_CURVE_TYPES: dict[str, EllipticCurve] = { - "prime192v1": SECP192R1(), - "prime256v1": SECP256R1(), - "secp192r1": SECP192R1(), - "secp224r1": SECP224R1(), - "secp256r1": SECP256R1(), - "secp384r1": SECP384R1(), - "secp521r1": SECP521R1(), - "secp256k1": SECP256K1(), - "sect163k1": SECT163K1(), - "sect233k1": SECT233K1(), - "sect283k1": SECT283K1(), - "sect409k1": SECT409K1(), - "sect571k1": SECT571K1(), - "sect163r2": SECT163R2(), - "sect233r1": SECT233R1(), - "sect283r1": SECT283R1(), - "sect409r1": SECT409R1(), - "sect571r1": SECT571R1(), - "brainpoolP256r1": BrainpoolP256R1(), - "brainpoolP384r1": BrainpoolP384R1(), - "brainpoolP512r1": BrainpoolP512R1(), -} - - -class ECDSA(EllipticCurveSignatureAlgorithm): - def __init__( - self, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - deterministic_signing: bool = False, - ): - from cryptography.hazmat.backends.openssl.backend import backend - - if ( - deterministic_signing - and not backend.ecdsa_deterministic_supported() - ): - raise UnsupportedAlgorithm( - "ECDSA with deterministic signature (RFC 6979) is not " - "supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - self._algorithm = algorithm - self._deterministic_signing = deterministic_signing - - @property - def algorithm( - self, - ) -> asym_utils.Prehashed | hashes.HashAlgorithm: - return self._algorithm - - @property - def deterministic_signing( - self, - ) -> bool: - return self._deterministic_signing - - -generate_private_key = rust_openssl.ec.generate_private_key - - -def derive_private_key( - private_value: int, - curve: EllipticCurve, - backend: typing.Any = None, -) -> EllipticCurvePrivateKey: - if not isinstance(private_value, int): - raise TypeError("private_value must be an integer type.") - - if private_value <= 0: - raise ValueError("private_value must be a positive integer.") - - return rust_openssl.ec.derive_private_key(private_value, curve) - - -class ECDH: - pass - - -_OID_TO_CURVE = { - EllipticCurveOID.SECP192R1: SECP192R1, - EllipticCurveOID.SECP224R1: SECP224R1, - EllipticCurveOID.SECP256K1: SECP256K1, - EllipticCurveOID.SECP256R1: SECP256R1, - EllipticCurveOID.SECP384R1: SECP384R1, - EllipticCurveOID.SECP521R1: SECP521R1, - EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, - EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, - EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, - EllipticCurveOID.SECT163K1: SECT163K1, - EllipticCurveOID.SECT163R2: SECT163R2, - EllipticCurveOID.SECT233K1: SECT233K1, - EllipticCurveOID.SECT233R1: SECT233R1, - EllipticCurveOID.SECT283K1: SECT283K1, - EllipticCurveOID.SECT283R1: SECT283R1, - EllipticCurveOID.SECT409K1: SECT409K1, - EllipticCurveOID.SECT409R1: SECT409R1, - EllipticCurveOID.SECT571K1: SECT571K1, - EllipticCurveOID.SECT571R1: SECT571R1, -} - - -def get_curve_for_oid(oid: ObjectIdentifier) -> type[EllipticCurve]: - try: - return _OID_TO_CURVE[oid] - except KeyError: - raise LookupError( - "The provided object identifier has no matching elliptic " - "curve class" - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py deleted file mode 100644 index e576dc9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ /dev/null @@ -1,129 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class Ed25519PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> Ed25519PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed25519_supported(): - raise UnsupportedAlgorithm( - "ed25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed25519.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def verify(self, signature: Buffer, data: Buffer) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed25519PublicKey: - """ - Returns a copy. - """ - - -Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey) - - -class Ed25519PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> Ed25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed25519_supported(): - raise UnsupportedAlgorithm( - "ed25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed25519.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> Ed25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed25519_supported(): - raise UnsupportedAlgorithm( - "ed25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed25519.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> Ed25519PublicKey: - """ - The Ed25519PublicKey derived from the private key. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def sign(self, data: Buffer) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed25519PrivateKey: - """ - Returns a copy. - """ - - -Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py deleted file mode 100644 index 89db209..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py +++ /dev/null @@ -1,131 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class Ed448PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> Ed448PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def verify(self, signature: Buffer, data: Buffer) -> None: - """ - Verify the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> Ed448PublicKey: - """ - Returns a copy. - """ - - -if hasattr(rust_openssl, "ed448"): - Ed448PublicKey.register(rust_openssl.ed448.Ed448PublicKey) - - -class Ed448PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> Ed448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> Ed448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.ed448_supported(): - raise UnsupportedAlgorithm( - "ed448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, - ) - - return rust_openssl.ed448.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> Ed448PublicKey: - """ - The Ed448PublicKey derived from the private key. - """ - - @abc.abstractmethod - def sign(self, data: Buffer) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def __copy__(self) -> Ed448PrivateKey: - """ - Returns a copy. - """ - - -if hasattr(rust_openssl, "x448"): - Ed448PrivateKey.register(rust_openssl.ed448.Ed448PrivateKey) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py deleted file mode 100644 index 5121a28..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives._asymmetric import ( - AsymmetricPadding as AsymmetricPadding, -) -from cryptography.hazmat.primitives.asymmetric import rsa - - -class PKCS1v15(AsymmetricPadding): - name = "EMSA-PKCS1-v1_5" - - -class _MaxLength: - "Sentinel value for `MAX_LENGTH`." - - -class _Auto: - "Sentinel value for `AUTO`." - - -class _DigestLength: - "Sentinel value for `DIGEST_LENGTH`." - - -class PSS(AsymmetricPadding): - MAX_LENGTH = _MaxLength() - AUTO = _Auto() - DIGEST_LENGTH = _DigestLength() - name = "EMSA-PSS" - _salt_length: int | _MaxLength | _Auto | _DigestLength - - def __init__( - self, - mgf: MGF, - salt_length: int | _MaxLength | _Auto | _DigestLength, - ) -> None: - self._mgf = mgf - - if not isinstance( - salt_length, (int, _MaxLength, _Auto, _DigestLength) - ): - raise TypeError( - "salt_length must be an integer, MAX_LENGTH, " - "DIGEST_LENGTH, or AUTO" - ) - - if isinstance(salt_length, int) and salt_length < 0: - raise ValueError("salt_length must be zero or greater.") - - self._salt_length = salt_length - - @property - def mgf(self) -> MGF: - return self._mgf - - -class OAEP(AsymmetricPadding): - name = "EME-OAEP" - - def __init__( - self, - mgf: MGF, - algorithm: hashes.HashAlgorithm, - label: bytes | None, - ): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - - self._mgf = mgf - self._algorithm = algorithm - self._label = label - - @property - def algorithm(self) -> hashes.HashAlgorithm: - return self._algorithm - - @property - def mgf(self) -> MGF: - return self._mgf - - -class MGF(metaclass=abc.ABCMeta): - _algorithm: hashes.HashAlgorithm - - -class MGF1(MGF): - def __init__(self, algorithm: hashes.HashAlgorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - - self._algorithm = algorithm - - -def calculate_max_pss_salt_length( - key: rsa.RSAPrivateKey | rsa.RSAPublicKey, - hash_algorithm: hashes.HashAlgorithm, -) -> int: - if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): - raise TypeError("key must be an RSA public or private key") - # bit length - 1 per RFC 3447 - emlen = (key.key_size + 6) // 8 - salt_length = emlen - hash_algorithm.digest_size - 2 - assert salt_length >= 0 - return salt_length diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py deleted file mode 100644 index f94812e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +++ /dev/null @@ -1,285 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import random -import typing -from math import gcd - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization, hashes -from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils - - -class RSAPrivateKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: - """ - Decrypts the provided ciphertext. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the public modulus. - """ - - @abc.abstractmethod - def public_key(self) -> RSAPublicKey: - """ - The RSAPublicKey associated with this private key. - """ - - @abc.abstractmethod - def sign( - self, - data: bytes, - padding: AsymmetricPadding, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> bytes: - """ - Signs the data. - """ - - @abc.abstractmethod - def private_numbers(self) -> RSAPrivateNumbers: - """ - Returns an RSAPrivateNumbers. - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def __copy__(self) -> RSAPrivateKey: - """ - Returns a copy. - """ - - -RSAPrivateKeyWithSerialization = RSAPrivateKey -RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey) - - -class RSAPublicKey(metaclass=abc.ABCMeta): - @abc.abstractmethod - def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: - """ - Encrypts the given plaintext. - """ - - @property - @abc.abstractmethod - def key_size(self) -> int: - """ - The bit length of the public modulus. - """ - - @abc.abstractmethod - def public_numbers(self) -> RSAPublicNumbers: - """ - Returns an RSAPublicNumbers - """ - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - Returns the key serialized as bytes. - """ - - @abc.abstractmethod - def verify( - self, - signature: bytes, - data: bytes, - padding: AsymmetricPadding, - algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, - ) -> None: - """ - Verifies the signature of the data. - """ - - @abc.abstractmethod - def recover_data_from_signature( - self, - signature: bytes, - padding: AsymmetricPadding, - algorithm: hashes.HashAlgorithm | None, - ) -> bytes: - """ - Recovers the original data from the signature. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> RSAPublicKey: - """ - Returns a copy. - """ - - -RSAPublicKeyWithSerialization = RSAPublicKey -RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey) - -RSAPrivateNumbers = rust_openssl.rsa.RSAPrivateNumbers -RSAPublicNumbers = rust_openssl.rsa.RSAPublicNumbers - - -def generate_private_key( - public_exponent: int, - key_size: int, - backend: typing.Any = None, -) -> RSAPrivateKey: - _verify_rsa_parameters(public_exponent, key_size) - return rust_openssl.rsa.generate_private_key(public_exponent, key_size) - - -def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None: - if public_exponent not in (3, 65537): - raise ValueError( - "public_exponent must be either 3 (for legacy compatibility) or " - "65537. Almost everyone should choose 65537 here!" - ) - - if key_size < 1024: - raise ValueError("key_size must be at least 1024-bits.") - - -def _modinv(e: int, m: int) -> int: - """ - Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 - """ - x1, x2 = 1, 0 - a, b = e, m - while b > 0: - q, r = divmod(a, b) - xn = x1 - q * x2 - a, b, x1, x2 = b, r, x2, xn - return x1 % m - - -def rsa_crt_iqmp(p: int, q: int) -> int: - """ - Compute the CRT (q ** -1) % p value from RSA primes p and q. - """ - if p <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - return _modinv(q, p) - - -def rsa_crt_dmp1(private_exponent: int, p: int) -> int: - """ - Compute the CRT private_exponent % (p - 1) value from the RSA - private_exponent (d) and p. - """ - if private_exponent <= 1 or p <= 1: - raise ValueError("Values can't be <= 1") - return private_exponent % (p - 1) - - -def rsa_crt_dmq1(private_exponent: int, q: int) -> int: - """ - Compute the CRT private_exponent % (q - 1) value from the RSA - private_exponent (d) and q. - """ - if private_exponent <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - return private_exponent % (q - 1) - - -def rsa_recover_private_exponent(e: int, p: int, q: int) -> int: - """ - Compute the RSA private_exponent (d) given the public exponent (e) - and the RSA primes p and q. - - This uses the Carmichael totient function to generate the - smallest possible working value of the private exponent. - """ - # This lambda_n is the Carmichael totient function. - # The original RSA paper uses the Euler totient function - # here: phi_n = (p - 1) * (q - 1) - # Either version of the private exponent will work, but the - # one generated by the older formulation may be larger - # than necessary. (lambda_n always divides phi_n) - # - # TODO: Replace with lcm(p - 1, q - 1) once the minimum - # supported Python version is >= 3.9. - if e <= 1 or p <= 1 or q <= 1: - raise ValueError("Values can't be <= 1") - lambda_n = (p - 1) * (q - 1) // gcd(p - 1, q - 1) - return _modinv(e, lambda_n) - - -# Controls the number of iterations rsa_recover_prime_factors will perform -# to obtain the prime factors. -_MAX_RECOVERY_ATTEMPTS = 500 - - -def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]: - """ - Compute factors p and q from the private exponent d. We assume that n has - no more than two factors. This function is adapted from code in PyCrypto. - """ - # reject invalid values early - if d <= 1 or e <= 1: - raise ValueError("d, e can't be <= 1") - if 17 != pow(17, e * d, n): - raise ValueError("n, d, e don't match") - # See 8.2.2(i) in Handbook of Applied Cryptography. - ktot = d * e - 1 - # The quantity d*e-1 is a multiple of phi(n), even, - # and can be represented as t*2^s. - t = ktot - while t % 2 == 0: - t = t // 2 - # Cycle through all multiplicative inverses in Zn. - # The algorithm is non-deterministic, but there is a 50% chance - # any candidate a leads to successful factoring. - # See "Digitalized Signatures and Public Key Functions as Intractable - # as Factorization", M. Rabin, 1979 - spotted = False - tries = 0 - while not spotted and tries < _MAX_RECOVERY_ATTEMPTS: - a = random.randint(2, n - 1) - tries += 1 - k = t - # Cycle through all values a^{t*2^i}=a^k - while k < ktot: - cand = pow(a, k, n) - # Check if a^k is a non-trivial root of unity (mod n) - if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: - # We have found a number such that (cand-1)(cand+1)=0 (mod n). - # Either of the terms divides n. - p = gcd(cand + 1, n) - spotted = True - break - k *= 2 - if not spotted: - raise ValueError("Unable to compute factors p and q from exponent d.") - # Found ! - q, r = divmod(n, p) - assert r == 0 - p, q = sorted((p, q), reverse=True) - return (p, q) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py deleted file mode 100644 index 1fe4eaf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import utils -from cryptography.hazmat.primitives.asymmetric import ( - dh, - dsa, - ec, - ed448, - ed25519, - rsa, - x448, - x25519, -) - -# Every asymmetric key type -PublicKeyTypes = typing.Union[ - dh.DHPublicKey, - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, -] -PUBLIC_KEY_TYPES = PublicKeyTypes -utils.deprecated( - PUBLIC_KEY_TYPES, - __name__, - "Use PublicKeyTypes instead", - utils.DeprecatedIn40, - name="PUBLIC_KEY_TYPES", -) -# Every asymmetric key type -PrivateKeyTypes = typing.Union[ - dh.DHPrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - x25519.X25519PrivateKey, - x448.X448PrivateKey, -] -PRIVATE_KEY_TYPES = PrivateKeyTypes -utils.deprecated( - PRIVATE_KEY_TYPES, - __name__, - "Use PrivateKeyTypes instead", - utils.DeprecatedIn40, - name="PRIVATE_KEY_TYPES", -) -# Just the key types we allow to be used for x509 signing. This mirrors -# the certificate public key types -CertificateIssuerPrivateKeyTypes = typing.Union[ - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, -] -CERTIFICATE_PRIVATE_KEY_TYPES = CertificateIssuerPrivateKeyTypes -utils.deprecated( - CERTIFICATE_PRIVATE_KEY_TYPES, - __name__, - "Use CertificateIssuerPrivateKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_PRIVATE_KEY_TYPES", -) -# Just the key types we allow to be used for x509 signing. This mirrors -# the certificate private key types -CertificateIssuerPublicKeyTypes = typing.Union[ - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, -] -CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES = CertificateIssuerPublicKeyTypes -utils.deprecated( - CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, - __name__, - "Use CertificateIssuerPublicKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES", -) -# This type removes DHPublicKey. x448/x25519 can be a public key -# but cannot be used in signing so they are allowed here. -CertificatePublicKeyTypes = typing.Union[ - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, -] -CERTIFICATE_PUBLIC_KEY_TYPES = CertificatePublicKeyTypes -utils.deprecated( - CERTIFICATE_PUBLIC_KEY_TYPES, - __name__, - "Use CertificatePublicKeyTypes instead", - utils.DeprecatedIn40, - name="CERTIFICATE_PUBLIC_KEY_TYPES", -) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py deleted file mode 100644 index 826b956..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py +++ /dev/null @@ -1,24 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import asn1 -from cryptography.hazmat.primitives import hashes - -decode_dss_signature = asn1.decode_dss_signature -encode_dss_signature = asn1.encode_dss_signature - - -class Prehashed: - def __init__(self, algorithm: hashes.HashAlgorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of HashAlgorithm.") - - self._algorithm = algorithm - self._digest_size = algorithm.digest_size - - @property - def digest_size(self) -> int: - return self._digest_size diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py deleted file mode 100644 index a499376..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py +++ /dev/null @@ -1,122 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class X25519PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> X25519PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x25519.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> X25519PublicKey: - """ - Returns a copy. - """ - - -X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey) - - -class X25519PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> X25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - return rust_openssl.x25519.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> X25519PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x25519_supported(): - raise UnsupportedAlgorithm( - "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x25519.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> X25519PublicKey: - """ - Returns the public key associated with this private key - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: X25519PublicKey) -> bytes: - """ - Performs a key exchange operation using the provided peer's public key. - """ - - @abc.abstractmethod - def __copy__(self) -> X25519PrivateKey: - """ - Returns a copy. - """ - - -X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py deleted file mode 100644 index c6fd71b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py +++ /dev/null @@ -1,125 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import _serialization -from cryptography.utils import Buffer - - -class X448PublicKey(metaclass=abc.ABCMeta): - @classmethod - def from_public_bytes(cls, data: bytes) -> X448PublicKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.from_public_bytes(data) - - @abc.abstractmethod - def public_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PublicFormat, - ) -> bytes: - """ - The serialized bytes of the public key. - """ - - @abc.abstractmethod - def public_bytes_raw(self) -> bytes: - """ - The raw bytes of the public key. - Equivalent to public_bytes(Raw, Raw). - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Checks equality. - """ - - @abc.abstractmethod - def __copy__(self) -> X448PublicKey: - """ - Returns a copy. - """ - - -if hasattr(rust_openssl, "x448"): - X448PublicKey.register(rust_openssl.x448.X448PublicKey) - - -class X448PrivateKey(metaclass=abc.ABCMeta): - @classmethod - def generate(cls) -> X448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.generate_key() - - @classmethod - def from_private_bytes(cls, data: Buffer) -> X448PrivateKey: - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.x448_supported(): - raise UnsupportedAlgorithm( - "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, - ) - - return rust_openssl.x448.from_private_bytes(data) - - @abc.abstractmethod - def public_key(self) -> X448PublicKey: - """ - Returns the public key associated with this private key - """ - - @abc.abstractmethod - def private_bytes( - self, - encoding: _serialization.Encoding, - format: _serialization.PrivateFormat, - encryption_algorithm: _serialization.KeySerializationEncryption, - ) -> bytes: - """ - The serialized bytes of the private key. - """ - - @abc.abstractmethod - def private_bytes_raw(self) -> bytes: - """ - The raw bytes of the private key. - Equivalent to private_bytes(Raw, Raw, NoEncryption()). - """ - - @abc.abstractmethod - def exchange(self, peer_public_key: X448PublicKey) -> bytes: - """ - Performs a key exchange operation using the provided peer's public key. - """ - - @abc.abstractmethod - def __copy__(self) -> X448PrivateKey: - """ - Returns a copy. - """ - - -if hasattr(rust_openssl, "x448"): - X448PrivateKey.register(rust_openssl.x448.X448PrivateKey) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py deleted file mode 100644 index 10c15d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) -from cryptography.hazmat.primitives.ciphers.base import ( - AEADCipherContext, - AEADDecryptionContext, - AEADEncryptionContext, - Cipher, - CipherContext, -) - -__all__ = [ - "AEADCipherContext", - "AEADDecryptionContext", - "AEADEncryptionContext", - "BlockCipherAlgorithm", - "Cipher", - "CipherAlgorithm", - "CipherContext", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py deleted file mode 100644 index c8a582d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = [ - "AESCCM", - "AESGCM", - "AESGCMSIV", - "AESOCB3", - "AESSIV", - "ChaCha20Poly1305", -] - -AESGCM = rust_openssl.aead.AESGCM -ChaCha20Poly1305 = rust_openssl.aead.ChaCha20Poly1305 -AESCCM = rust_openssl.aead.AESCCM -AESSIV = rust_openssl.aead.AESSIV -AESOCB3 = rust_openssl.aead.AESOCB3 -AESGCMSIV = rust_openssl.aead.AESGCMSIV diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py deleted file mode 100644 index 1e402c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +++ /dev/null @@ -1,136 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - ARC4 as ARC4, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - CAST5 as CAST5, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - IDEA as IDEA, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - SEED as SEED, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - Blowfish as Blowfish, -) -from cryptography.hazmat.decrepit.ciphers.algorithms import ( - TripleDES as TripleDES, -) -from cryptography.hazmat.primitives._cipheralgorithm import _verify_key_size -from cryptography.hazmat.primitives.ciphers import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) - - -class AES(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - # 512 added to support AES-256-XTS, which uses 512-bit keys - key_sizes = frozenset([128, 192, 256, 512]) - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class AES128(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - key_sizes = frozenset([128]) - key_size = 128 - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - -class AES256(BlockCipherAlgorithm): - name = "AES" - block_size = 128 - key_sizes = frozenset([256]) - key_size = 256 - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - -class Camellia(BlockCipherAlgorithm): - name = "camellia" - block_size = 128 - key_sizes = frozenset([128, 192, 256]) - - def __init__(self, key: utils.Buffer): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -utils.deprecated( - ARC4, - __name__, - "ARC4 has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", - utils.DeprecatedIn43, - name="ARC4", -) - - -utils.deprecated( - TripleDES, - __name__, - "TripleDES has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", - utils.DeprecatedIn43, - name="TripleDES", -) - - -class ChaCha20(CipherAlgorithm): - name = "ChaCha20" - key_sizes = frozenset([256]) - - def __init__(self, key: utils.Buffer, nonce: utils.Buffer): - self.key = _verify_key_size(self, key) - utils._check_byteslike("nonce", nonce) - - if len(nonce) != 16: - raise ValueError("nonce must be 128-bits (16 bytes)") - - self._nonce = nonce - - @property - def nonce(self) -> utils.Buffer: - return self._nonce - - @property - def key_size(self) -> int: - return len(self.key) * 8 - - -class SM4(BlockCipherAlgorithm): - name = "SM4" - block_size = 128 - key_sizes = frozenset([128]) - - def __init__(self, key: bytes): - self.key = _verify_key_size(self, key) - - @property - def key_size(self) -> int: - return len(self.key) * 8 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py deleted file mode 100644 index 24fceea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import typing - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm -from cryptography.hazmat.primitives.ciphers import modes -from cryptography.utils import Buffer - - -class CipherContext(metaclass=abc.ABCMeta): - @abc.abstractmethod - def update(self, data: Buffer) -> bytes: - """ - Processes the provided bytes through the cipher and returns the results - as bytes. - """ - - @abc.abstractmethod - def update_into(self, data: Buffer, buf: Buffer) -> int: - """ - Processes the provided bytes and writes the resulting data into the - provided buffer. Returns the number of bytes written. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Returns the results of processing the final block as bytes. - """ - - @abc.abstractmethod - def reset_nonce(self, nonce: bytes) -> None: - """ - Resets the nonce for the cipher context to the provided value. - Raises an exception if it does not support reset or if the - provided nonce does not have a valid length. - """ - - -class AEADCipherContext(CipherContext, metaclass=abc.ABCMeta): - @abc.abstractmethod - def authenticate_additional_data(self, data: Buffer) -> None: - """ - Authenticates the provided bytes. - """ - - -class AEADDecryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): - @abc.abstractmethod - def finalize_with_tag(self, tag: bytes) -> bytes: - """ - Returns the results of processing the final block as bytes and allows - delayed passing of the authentication tag. - """ - - -class AEADEncryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tag(self) -> bytes: - """ - Returns tag bytes. This is only available after encryption is - finalized. - """ - - -Mode = typing.TypeVar( - "Mode", bound=typing.Optional[modes.Mode], covariant=True -) - - -class Cipher(typing.Generic[Mode]): - def __init__( - self, - algorithm: CipherAlgorithm, - mode: Mode, - backend: typing.Any = None, - ) -> None: - if not isinstance(algorithm, CipherAlgorithm): - raise TypeError("Expected interface of CipherAlgorithm.") - - if mode is not None: - # mypy needs this assert to narrow the type from our generic - # type. Maybe it won't some time in the future. - assert isinstance(mode, modes.Mode) - mode.validate_for_algorithm(algorithm) - - self.algorithm = algorithm - self.mode = mode - - @typing.overload - def encryptor( - self: Cipher[modes.ModeWithAuthenticationTag], - ) -> AEADEncryptionContext: ... - - @typing.overload - def encryptor( - self: _CIPHER_TYPE, - ) -> CipherContext: ... - - def encryptor(self): - if isinstance(self.mode, modes.ModeWithAuthenticationTag): - if self.mode.tag is not None: - raise ValueError( - "Authentication tag must be None when encrypting." - ) - - return rust_openssl.ciphers.create_encryption_ctx( - self.algorithm, self.mode - ) - - @typing.overload - def decryptor( - self: Cipher[modes.ModeWithAuthenticationTag], - ) -> AEADDecryptionContext: ... - - @typing.overload - def decryptor( - self: _CIPHER_TYPE, - ) -> CipherContext: ... - - def decryptor(self): - return rust_openssl.ciphers.create_decryption_ctx( - self.algorithm, self.mode - ) - - -_CIPHER_TYPE = Cipher[ - typing.Union[ - modes.ModeWithNonce, - modes.ModeWithTweak, - modes.ECB, - modes.ModeWithInitializationVector, - None, - ] -] - -CipherContext.register(rust_openssl.ciphers.CipherContext) -AEADEncryptionContext.register(rust_openssl.ciphers.AEADEncryptionContext) -AEADDecryptionContext.register(rust_openssl.ciphers.AEADDecryptionContext) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py deleted file mode 100644 index 36c555c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py +++ /dev/null @@ -1,268 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.primitives._cipheralgorithm import ( - BlockCipherAlgorithm, - CipherAlgorithm, -) -from cryptography.hazmat.primitives.ciphers import algorithms - - -class Mode(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this mode (e.g. "ECB", "CBC"). - """ - - @abc.abstractmethod - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - """ - Checks that all the necessary invariants of this (mode, algorithm) - combination are met. - """ - - -class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def initialization_vector(self) -> utils.Buffer: - """ - The value of the initialization vector for this mode as bytes. - """ - - -class ModeWithTweak(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tweak(self) -> utils.Buffer: - """ - The value of the tweak for this mode as bytes. - """ - - -class ModeWithNonce(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def nonce(self) -> utils.Buffer: - """ - The value of the nonce for this mode as bytes. - """ - - -class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def tag(self) -> bytes | None: - """ - The value of the tag supplied to the constructor of this mode. - """ - - -def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None: - if algorithm.key_size > 256 and algorithm.name == "AES": - raise ValueError( - "Only 128, 192, and 256 bit keys are allowed for this AES mode" - ) - - -def _check_iv_length( - self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm -) -> None: - iv_len = len(self.initialization_vector) - if iv_len * 8 != algorithm.block_size: - raise ValueError(f"Invalid IV size ({iv_len}) for {self.name}.") - - -def _check_nonce_length( - nonce: utils.Buffer, name: str, algorithm: CipherAlgorithm -) -> None: - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - f"{name} requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - if len(nonce) * 8 != algorithm.block_size: - raise ValueError(f"Invalid nonce size ({len(nonce)}) for {name}.") - - -def _check_iv_and_key_length( - self: ModeWithInitializationVector, algorithm: CipherAlgorithm -) -> None: - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - f"{self} requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - _check_aes_key_length(self, algorithm) - _check_iv_length(self, algorithm) - - -class CBC(ModeWithInitializationVector): - name = "CBC" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class XTS(ModeWithTweak): - name = "XTS" - - def __init__(self, tweak: utils.Buffer): - utils._check_byteslike("tweak", tweak) - - if len(tweak) != 16: - raise ValueError("tweak must be 128-bits (16 bytes)") - - self._tweak = tweak - - @property - def tweak(self) -> utils.Buffer: - return self._tweak - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - if isinstance(algorithm, (algorithms.AES128, algorithms.AES256)): - raise TypeError( - "The AES128 and AES256 classes do not support XTS, please use " - "the standard AES class instead." - ) - - if algorithm.key_size not in (256, 512): - raise ValueError( - "The XTS specification requires a 256-bit key for AES-128-XTS" - " and 512-bit key for AES-256-XTS" - ) - - -class ECB(Mode): - name = "ECB" - - validate_for_algorithm = _check_aes_key_length - - -class OFB(ModeWithInitializationVector): - name = "OFB" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class CFB(ModeWithInitializationVector): - name = "CFB" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class CFB8(ModeWithInitializationVector): - name = "CFB8" - - def __init__(self, initialization_vector: utils.Buffer): - utils._check_byteslike("initialization_vector", initialization_vector) - self._initialization_vector = initialization_vector - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - validate_for_algorithm = _check_iv_and_key_length - - -class CTR(ModeWithNonce): - name = "CTR" - - def __init__(self, nonce: utils.Buffer): - utils._check_byteslike("nonce", nonce) - self._nonce = nonce - - @property - def nonce(self) -> utils.Buffer: - return self._nonce - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - _check_aes_key_length(self, algorithm) - _check_nonce_length(self.nonce, self.name, algorithm) - - -class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): - name = "GCM" - _MAX_ENCRYPTED_BYTES = (2**39 - 256) // 8 - _MAX_AAD_BYTES = (2**64) // 8 - - def __init__( - self, - initialization_vector: utils.Buffer, - tag: bytes | None = None, - min_tag_length: int = 16, - ): - # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive - # This is a sane limit anyway so we'll enforce it here. - utils._check_byteslike("initialization_vector", initialization_vector) - if len(initialization_vector) < 8 or len(initialization_vector) > 128: - raise ValueError( - "initialization_vector must be between 8 and 128 bytes (64 " - "and 1024 bits)." - ) - self._initialization_vector = initialization_vector - if tag is not None: - utils._check_bytes("tag", tag) - if min_tag_length < 4: - raise ValueError("min_tag_length must be >= 4") - if len(tag) < min_tag_length: - raise ValueError( - f"Authentication tag must be {min_tag_length} bytes or " - "longer." - ) - self._tag = tag - self._min_tag_length = min_tag_length - - @property - def tag(self) -> bytes | None: - return self._tag - - @property - def initialization_vector(self) -> utils.Buffer: - return self._initialization_vector - - def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: - _check_aes_key_length(self, algorithm) - if not isinstance(algorithm, BlockCipherAlgorithm): - raise UnsupportedAlgorithm( - "GCM requires a block cipher algorithm", - _Reasons.UNSUPPORTED_CIPHER, - ) - block_size_bytes = algorithm.block_size // 8 - if self._tag is not None and len(self._tag) > block_size_bytes: - raise ValueError( - f"Authentication tag cannot be more than {block_size_bytes} " - "bytes." - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py deleted file mode 100644 index 2c67ce2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = ["CMAC"] -CMAC = rust_openssl.cmac.CMAC diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py deleted file mode 100644 index 3975c71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import hmac - - -def bytes_eq(a: bytes, b: bytes) -> bool: - if not isinstance(a, bytes) or not isinstance(b, bytes): - raise TypeError("a and b must be bytes.") - - return hmac.compare_digest(a, b) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py deleted file mode 100644 index 4b55ec3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py +++ /dev/null @@ -1,246 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.utils import Buffer - -__all__ = [ - "MD5", - "SHA1", - "SHA3_224", - "SHA3_256", - "SHA3_384", - "SHA3_512", - "SHA224", - "SHA256", - "SHA384", - "SHA512", - "SHA512_224", - "SHA512_256", - "SHAKE128", - "SHAKE256", - "SM3", - "BLAKE2b", - "BLAKE2s", - "ExtendableOutputFunction", - "Hash", - "HashAlgorithm", - "HashContext", - "XOFHash", -] - - -class HashAlgorithm(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def name(self) -> str: - """ - A string naming this algorithm (e.g. "sha256", "md5"). - """ - - @property - @abc.abstractmethod - def digest_size(self) -> int: - """ - The size of the resulting digest in bytes. - """ - - @property - @abc.abstractmethod - def block_size(self) -> int | None: - """ - The internal block size of the hash function, or None if the hash - function does not use blocks internally (e.g. SHA3). - """ - - -class HashContext(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def algorithm(self) -> HashAlgorithm: - """ - A HashAlgorithm that will be used by this context. - """ - - @abc.abstractmethod - def update(self, data: Buffer) -> None: - """ - Processes the provided bytes through the hash. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Finalizes the hash context and returns the hash digest as bytes. - """ - - @abc.abstractmethod - def copy(self) -> HashContext: - """ - Return a HashContext that is a copy of the current context. - """ - - -Hash = rust_openssl.hashes.Hash -HashContext.register(Hash) - -XOFHash = rust_openssl.hashes.XOFHash - - -class ExtendableOutputFunction(metaclass=abc.ABCMeta): - """ - An interface for extendable output functions. - """ - - -class SHA1(HashAlgorithm): - name = "sha1" - digest_size = 20 - block_size = 64 - - -class SHA512_224(HashAlgorithm): # noqa: N801 - name = "sha512-224" - digest_size = 28 - block_size = 128 - - -class SHA512_256(HashAlgorithm): # noqa: N801 - name = "sha512-256" - digest_size = 32 - block_size = 128 - - -class SHA224(HashAlgorithm): - name = "sha224" - digest_size = 28 - block_size = 64 - - -class SHA256(HashAlgorithm): - name = "sha256" - digest_size = 32 - block_size = 64 - - -class SHA384(HashAlgorithm): - name = "sha384" - digest_size = 48 - block_size = 128 - - -class SHA512(HashAlgorithm): - name = "sha512" - digest_size = 64 - block_size = 128 - - -class SHA3_224(HashAlgorithm): # noqa: N801 - name = "sha3-224" - digest_size = 28 - block_size = None - - -class SHA3_256(HashAlgorithm): # noqa: N801 - name = "sha3-256" - digest_size = 32 - block_size = None - - -class SHA3_384(HashAlgorithm): # noqa: N801 - name = "sha3-384" - digest_size = 48 - block_size = None - - -class SHA3_512(HashAlgorithm): # noqa: N801 - name = "sha3-512" - digest_size = 64 - block_size = None - - -class SHAKE128(HashAlgorithm, ExtendableOutputFunction): - name = "shake128" - block_size = None - - def __init__(self, digest_size: int): - if not isinstance(digest_size, int): - raise TypeError("digest_size must be an integer") - - if digest_size < 1: - raise ValueError("digest_size must be a positive integer") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class SHAKE256(HashAlgorithm, ExtendableOutputFunction): - name = "shake256" - block_size = None - - def __init__(self, digest_size: int): - if not isinstance(digest_size, int): - raise TypeError("digest_size must be an integer") - - if digest_size < 1: - raise ValueError("digest_size must be a positive integer") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class MD5(HashAlgorithm): - name = "md5" - digest_size = 16 - block_size = 64 - - -class BLAKE2b(HashAlgorithm): - name = "blake2b" - _max_digest_size = 64 - _min_digest_size = 1 - block_size = 128 - - def __init__(self, digest_size: int): - if digest_size != 64: - raise ValueError("Digest size must be 64") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class BLAKE2s(HashAlgorithm): - name = "blake2s" - block_size = 64 - _max_digest_size = 32 - _min_digest_size = 1 - - def __init__(self, digest_size: int): - if digest_size != 32: - raise ValueError("Digest size must be 32") - - self._digest_size = digest_size - - @property - def digest_size(self) -> int: - return self._digest_size - - -class SM3(HashAlgorithm): - name = "sm3" - digest_size = 32 - block_size = 64 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py deleted file mode 100644 index a9442d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import hashes - -__all__ = ["HMAC"] - -HMAC = rust_openssl.hmac.HMAC -hashes.HashContext.register(HMAC) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py deleted file mode 100644 index 79bb459..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - - -class KeyDerivationFunction(metaclass=abc.ABCMeta): - @abc.abstractmethod - def derive(self, key_material: bytes) -> bytes: - """ - Deterministically generates and returns a new key based on the existing - key material. - """ - - @abc.abstractmethod - def verify(self, key_material: bytes, expected_key: bytes) -> None: - """ - Checks whether the key generated by the key material matches the - expected derived key. Raises an exception if they do not match. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py deleted file mode 100644 index 405fc8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/argon2.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -Argon2id = rust_openssl.kdf.Argon2id -KeyDerivationFunction.register(Argon2id) - -__all__ = ["Argon2id"] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py deleted file mode 100644 index 1b92841..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +++ /dev/null @@ -1,125 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing -from collections.abc import Callable - -from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, InvalidKey -from cryptography.hazmat.primitives import constant_time, hashes, hmac -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - - -def _int_to_u32be(n: int) -> bytes: - return n.to_bytes(length=4, byteorder="big") - - -def _common_args_checks( - algorithm: hashes.HashAlgorithm, - length: int, - otherinfo: bytes | None, -) -> None: - max_length = algorithm.digest_size * (2**32 - 1) - if length > max_length: - raise ValueError(f"Cannot derive keys larger than {max_length} bits.") - if otherinfo is not None: - utils._check_bytes("otherinfo", otherinfo) - - -def _concatkdf_derive( - key_material: utils.Buffer, - length: int, - auxfn: Callable[[], hashes.HashContext], - otherinfo: bytes, -) -> bytes: - utils._check_byteslike("key_material", key_material) - output = [b""] - outlen = 0 - counter = 1 - - while length > outlen: - h = auxfn() - h.update(_int_to_u32be(counter)) - h.update(key_material) - h.update(otherinfo) - output.append(h.finalize()) - outlen += len(output[-1]) - counter += 1 - - return b"".join(output)[:length] - - -class ConcatKDFHash(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - otherinfo: bytes | None, - backend: typing.Any = None, - ): - _common_args_checks(algorithm, length, otherinfo) - self._algorithm = algorithm - self._length = length - self._otherinfo: bytes = otherinfo if otherinfo is not None else b"" - - self._used = False - - def _hash(self) -> hashes.Hash: - return hashes.Hash(self._algorithm) - - def derive(self, key_material: utils.Buffer) -> bytes: - if self._used: - raise AlreadyFinalized - self._used = True - return _concatkdf_derive( - key_material, self._length, self._hash, self._otherinfo - ) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey - - -class ConcatKDFHMAC(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - salt: bytes | None, - otherinfo: bytes | None, - backend: typing.Any = None, - ): - _common_args_checks(algorithm, length, otherinfo) - self._algorithm = algorithm - self._length = length - self._otherinfo: bytes = otherinfo if otherinfo is not None else b"" - - if algorithm.block_size is None: - raise TypeError(f"{algorithm.name} is unsupported for ConcatKDF") - - if salt is None: - salt = b"\x00" * algorithm.block_size - else: - utils._check_bytes("salt", salt) - - self._salt = salt - - self._used = False - - def _hmac(self) -> hmac.HMAC: - return hmac.HMAC(self._salt, self._algorithm) - - def derive(self, key_material: utils.Buffer) -> bytes: - if self._used: - raise AlreadyFinalized - self._used = True - return _concatkdf_derive( - key_material, self._length, self._hmac, self._otherinfo - ) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py deleted file mode 100644 index 1e162d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -HKDF = rust_openssl.kdf.HKDF -HKDFExpand = rust_openssl.kdf.HKDFExpand - -KeyDerivationFunction.register(HKDF) -KeyDerivationFunction.register(HKDFExpand) - -__all__ = ["HKDF", "HKDFExpand"] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py deleted file mode 100644 index 5b47137..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +++ /dev/null @@ -1,303 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing -from collections.abc import Callable - -from cryptography import utils -from cryptography.exceptions import ( - AlreadyFinalized, - InvalidKey, - UnsupportedAlgorithm, - _Reasons, -) -from cryptography.hazmat.primitives import ( - ciphers, - cmac, - constant_time, - hashes, - hmac, -) -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - - -class Mode(utils.Enum): - CounterMode = "ctr" - - -class CounterLocation(utils.Enum): - BeforeFixed = "before_fixed" - AfterFixed = "after_fixed" - MiddleFixed = "middle_fixed" - - -class _KBKDFDeriver: - def __init__( - self, - prf: Callable, - mode: Mode, - length: int, - rlen: int, - llen: int | None, - location: CounterLocation, - break_location: int | None, - label: bytes | None, - context: bytes | None, - fixed: bytes | None, - ): - assert callable(prf) - - if not isinstance(mode, Mode): - raise TypeError("mode must be of type Mode") - - if not isinstance(location, CounterLocation): - raise TypeError("location must be of type CounterLocation") - - if break_location is None and location is CounterLocation.MiddleFixed: - raise ValueError("Please specify a break_location") - - if ( - break_location is not None - and location != CounterLocation.MiddleFixed - ): - raise ValueError( - "break_location is ignored when location is not" - " CounterLocation.MiddleFixed" - ) - - if break_location is not None and not isinstance(break_location, int): - raise TypeError("break_location must be an integer") - - if break_location is not None and break_location < 0: - raise ValueError("break_location must be a positive integer") - - if (label or context) and fixed: - raise ValueError( - "When supplying fixed data, label and context are ignored." - ) - - if rlen is None or not self._valid_byte_length(rlen): - raise ValueError("rlen must be between 1 and 4") - - if llen is None and fixed is None: - raise ValueError("Please specify an llen") - - if llen is not None and not isinstance(llen, int): - raise TypeError("llen must be an integer") - - if llen == 0: - raise ValueError("llen must be non-zero") - - if label is None: - label = b"" - - if context is None: - context = b"" - - utils._check_bytes("label", label) - utils._check_bytes("context", context) - self._prf = prf - self._mode = mode - self._length = length - self._rlen = rlen - self._llen = llen - self._location = location - self._break_location = break_location - self._label = label - self._context = context - self._used = False - self._fixed_data = fixed - - @staticmethod - def _valid_byte_length(value: int) -> bool: - if not isinstance(value, int): - raise TypeError("value must be of type int") - - value_bin = utils.int_to_bytes(1, value) - return 1 <= len(value_bin) <= 4 - - def derive( - self, key_material: utils.Buffer, prf_output_size: int - ) -> bytes: - if self._used: - raise AlreadyFinalized - - utils._check_byteslike("key_material", key_material) - self._used = True - - # inverse floor division (equivalent to ceiling) - rounds = -(-self._length // prf_output_size) - - output = [b""] - - # For counter mode, the number of iterations shall not be - # larger than 2^r-1, where r <= 32 is the binary length of the counter - # This ensures that the counter values used as an input to the - # PRF will not repeat during a particular call to the KDF function. - r_bin = utils.int_to_bytes(1, self._rlen) - if rounds > pow(2, len(r_bin) * 8) - 1: - raise ValueError("There are too many iterations.") - - fixed = self._generate_fixed_input() - - if self._location == CounterLocation.BeforeFixed: - data_before_ctr = b"" - data_after_ctr = fixed - elif self._location == CounterLocation.AfterFixed: - data_before_ctr = fixed - data_after_ctr = b"" - else: - if isinstance( - self._break_location, int - ) and self._break_location > len(fixed): - raise ValueError("break_location offset > len(fixed)") - data_before_ctr = fixed[: self._break_location] - data_after_ctr = fixed[self._break_location :] - - for i in range(1, rounds + 1): - h = self._prf(key_material) - - counter = utils.int_to_bytes(i, self._rlen) - input_data = data_before_ctr + counter + data_after_ctr - - h.update(input_data) - - output.append(h.finalize()) - - return b"".join(output)[: self._length] - - def _generate_fixed_input(self) -> bytes: - if self._fixed_data and isinstance(self._fixed_data, bytes): - return self._fixed_data - - l_val = utils.int_to_bytes(self._length * 8, self._llen) - - return b"".join([self._label, b"\x00", self._context, l_val]) - - -class KBKDFHMAC(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - mode: Mode, - length: int, - rlen: int, - llen: int | None, - location: CounterLocation, - label: bytes | None, - context: bytes | None, - fixed: bytes | None, - backend: typing.Any = None, - *, - break_location: int | None = None, - ): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported hash algorithm.", - _Reasons.UNSUPPORTED_HASH, - ) - - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - if not ossl.hmac_supported(algorithm): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported hmac algorithm.", - _Reasons.UNSUPPORTED_HASH, - ) - - self._algorithm = algorithm - - self._deriver = _KBKDFDeriver( - self._prf, - mode, - length, - rlen, - llen, - location, - break_location, - label, - context, - fixed, - ) - - def _prf(self, key_material: bytes) -> hmac.HMAC: - return hmac.HMAC(key_material, self._algorithm) - - def derive(self, key_material: utils.Buffer) -> bytes: - return self._deriver.derive(key_material, self._algorithm.digest_size) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey - - -class KBKDFCMAC(KeyDerivationFunction): - def __init__( - self, - algorithm, - mode: Mode, - length: int, - rlen: int, - llen: int | None, - location: CounterLocation, - label: bytes | None, - context: bytes | None, - fixed: bytes | None, - backend: typing.Any = None, - *, - break_location: int | None = None, - ): - if not issubclass( - algorithm, ciphers.BlockCipherAlgorithm - ) or not issubclass(algorithm, ciphers.CipherAlgorithm): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported cipher algorithm.", - _Reasons.UNSUPPORTED_CIPHER, - ) - - self._algorithm = algorithm - self._cipher: ciphers.BlockCipherAlgorithm | None = None - - self._deriver = _KBKDFDeriver( - self._prf, - mode, - length, - rlen, - llen, - location, - break_location, - label, - context, - fixed, - ) - - def _prf(self, _: bytes) -> cmac.CMAC: - assert self._cipher is not None - - return cmac.CMAC(self._cipher) - - def derive(self, key_material: utils.Buffer) -> bytes: - self._cipher = self._algorithm(key_material) - - assert self._cipher is not None - - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - if not ossl.cmac_algorithm_supported(self._cipher): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported cipher algorithm.", - _Reasons.UNSUPPORTED_CIPHER, - ) - - return self._deriver.derive(key_material, self._cipher.block_size // 8) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py deleted file mode 100644 index d539f13..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import utils -from cryptography.exceptions import ( - AlreadyFinalized, - InvalidKey, - UnsupportedAlgorithm, - _Reasons, -) -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives import constant_time, hashes -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - - -class PBKDF2HMAC(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - salt: bytes, - iterations: int, - backend: typing.Any = None, - ): - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - if not ossl.pbkdf2_hmac_supported(algorithm): - raise UnsupportedAlgorithm( - f"{algorithm.name} is not supported for PBKDF2.", - _Reasons.UNSUPPORTED_HASH, - ) - self._used = False - self._algorithm = algorithm - self._length = length - utils._check_bytes("salt", salt) - self._salt = salt - self._iterations = iterations - - def derive(self, key_material: utils.Buffer) -> bytes: - if self._used: - raise AlreadyFinalized("PBKDF2 instances can only be used once.") - self._used = True - - return rust_openssl.kdf.derive_pbkdf2_hmac( - key_material, - self._algorithm, - self._salt, - self._iterations, - self._length, - ) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - derived_key = self.derive(key_material) - if not constant_time.bytes_eq(derived_key, expected_key): - raise InvalidKey("Keys do not match.") diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py deleted file mode 100644 index f791cee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import sys - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - -# This is used by the scrypt tests to skip tests that require more memory -# than the MEM_LIMIT -_MEM_LIMIT = sys.maxsize // 2 - -Scrypt = rust_openssl.kdf.Scrypt -KeyDerivationFunction.register(Scrypt) - -__all__ = ["Scrypt"] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py deleted file mode 100644 index 63870cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, InvalidKey -from cryptography.hazmat.primitives import constant_time, hashes -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction - - -def _int_to_u32be(n: int) -> bytes: - return n.to_bytes(length=4, byteorder="big") - - -class X963KDF(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - sharedinfo: bytes | None, - backend: typing.Any = None, - ): - max_len = algorithm.digest_size * (2**32 - 1) - if length > max_len: - raise ValueError(f"Cannot derive keys larger than {max_len} bits.") - if sharedinfo is not None: - utils._check_bytes("sharedinfo", sharedinfo) - - self._algorithm = algorithm - self._length = length - self._sharedinfo = sharedinfo - self._used = False - - def derive(self, key_material: utils.Buffer) -> bytes: - if self._used: - raise AlreadyFinalized - self._used = True - utils._check_byteslike("key_material", key_material) - output = [b""] - outlen = 0 - counter = 1 - - while self._length > outlen: - h = hashes.Hash(self._algorithm) - h.update(key_material) - h.update(_int_to_u32be(counter)) - if self._sharedinfo is not None: - h.update(self._sharedinfo) - output.append(h.finalize()) - outlen += len(output[-1]) - counter += 1 - - return b"".join(output)[: self._length] - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py deleted file mode 100644 index b93d87d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py +++ /dev/null @@ -1,177 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers.algorithms import AES -from cryptography.hazmat.primitives.ciphers.modes import ECB -from cryptography.hazmat.primitives.constant_time import bytes_eq - - -def _wrap_core( - wrapping_key: bytes, - a: bytes, - r: list[bytes], -) -> bytes: - # RFC 3394 Key Wrap - 2.2.1 (index method) - encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() - n = len(r) - for j in range(6): - for i in range(n): - # every encryption operation is a discrete 16 byte chunk (because - # AES has a 128-bit block size) and since we're using ECB it is - # safe to reuse the encryptor for the entire operation - b = encryptor.update(a + r[i]) - a = ( - int.from_bytes(b[:8], byteorder="big") ^ ((n * j) + i + 1) - ).to_bytes(length=8, byteorder="big") - r[i] = b[-8:] - - assert encryptor.finalize() == b"" - - return a + b"".join(r) - - -def aes_key_wrap( - wrapping_key: bytes, - key_to_wrap: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - if len(key_to_wrap) < 16: - raise ValueError("The key to wrap must be at least 16 bytes") - - if len(key_to_wrap) % 8 != 0: - raise ValueError("The key to wrap must be a multiple of 8 bytes") - - a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] - return _wrap_core(wrapping_key, a, r) - - -def _unwrap_core( - wrapping_key: bytes, - a: bytes, - r: list[bytes], -) -> tuple[bytes, list[bytes]]: - # Implement RFC 3394 Key Unwrap - 2.2.2 (index method) - decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() - n = len(r) - for j in reversed(range(6)): - for i in reversed(range(n)): - atr = ( - int.from_bytes(a, byteorder="big") ^ ((n * j) + i + 1) - ).to_bytes(length=8, byteorder="big") + r[i] - # every decryption operation is a discrete 16 byte chunk so - # it is safe to reuse the decryptor for the entire operation - b = decryptor.update(atr) - a = b[:8] - r[i] = b[-8:] - - assert decryptor.finalize() == b"" - return a, r - - -def aes_key_wrap_with_padding( - wrapping_key: bytes, - key_to_wrap: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - aiv = b"\xa6\x59\x59\xa6" + len(key_to_wrap).to_bytes( - length=4, byteorder="big" - ) - # pad the key to wrap if necessary - pad = (8 - (len(key_to_wrap) % 8)) % 8 - key_to_wrap = key_to_wrap + b"\x00" * pad - if len(key_to_wrap) == 8: - # RFC 5649 - 4.1 - exactly 8 octets after padding - encryptor = Cipher(AES(wrapping_key), ECB()).encryptor() - b = encryptor.update(aiv + key_to_wrap) - assert encryptor.finalize() == b"" - return b - else: - r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] - return _wrap_core(wrapping_key, aiv, r) - - -def aes_key_unwrap_with_padding( - wrapping_key: bytes, - wrapped_key: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapped_key) < 16: - raise InvalidUnwrap("Must be at least 16 bytes") - - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - if len(wrapped_key) == 16: - # RFC 5649 - 4.2 - exactly two 64-bit blocks - decryptor = Cipher(AES(wrapping_key), ECB()).decryptor() - out = decryptor.update(wrapped_key) - assert decryptor.finalize() == b"" - a = out[:8] - data = out[8:] - n = 1 - else: - r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] - encrypted_aiv = r.pop(0) - n = len(r) - a, r = _unwrap_core(wrapping_key, encrypted_aiv, r) - data = b"".join(r) - - # 1) Check that MSB(32,A) = A65959A6. - # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let - # MLI = LSB(32,A). - # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of - # the output data are zero. - mli = int.from_bytes(a[4:], byteorder="big") - b = (8 * n) - mli - if ( - not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") - or not 8 * (n - 1) < mli <= 8 * n - or (b != 0 and not bytes_eq(data[-b:], b"\x00" * b)) - ): - raise InvalidUnwrap() - - if b == 0: - return data - else: - return data[:-b] - - -def aes_key_unwrap( - wrapping_key: bytes, - wrapped_key: bytes, - backend: typing.Any = None, -) -> bytes: - if len(wrapped_key) < 24: - raise InvalidUnwrap("Must be at least 24 bytes") - - if len(wrapped_key) % 8 != 0: - raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes") - - if len(wrapping_key) not in [16, 24, 32]: - raise ValueError("The wrapping key must be a valid AES key length") - - aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] - a = r.pop(0) - a, r = _unwrap_core(wrapping_key, a, r) - if not bytes_eq(a, aiv): - raise InvalidUnwrap() - - return b"".join(r) - - -class InvalidUnwrap(Exception): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py deleted file mode 100644 index f9cd1f1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py +++ /dev/null @@ -1,69 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc - -from cryptography import utils -from cryptography.hazmat.bindings._rust import ( - ANSIX923PaddingContext, - ANSIX923UnpaddingContext, - PKCS7PaddingContext, - PKCS7UnpaddingContext, -) - - -class PaddingContext(metaclass=abc.ABCMeta): - @abc.abstractmethod - def update(self, data: utils.Buffer) -> bytes: - """ - Pads the provided bytes and returns any available data as bytes. - """ - - @abc.abstractmethod - def finalize(self) -> bytes: - """ - Finalize the padding, returns bytes. - """ - - -def _byte_padding_check(block_size: int) -> None: - if not (0 <= block_size <= 2040): - raise ValueError("block_size must be in range(0, 2041).") - - if block_size % 8 != 0: - raise ValueError("block_size must be a multiple of 8.") - - -class PKCS7: - def __init__(self, block_size: int): - _byte_padding_check(block_size) - self.block_size = block_size - - def padder(self) -> PaddingContext: - return PKCS7PaddingContext(self.block_size) - - def unpadder(self) -> PaddingContext: - return PKCS7UnpaddingContext(self.block_size) - - -PaddingContext.register(PKCS7PaddingContext) -PaddingContext.register(PKCS7UnpaddingContext) - - -class ANSIX923: - def __init__(self, block_size: int): - _byte_padding_check(block_size) - self.block_size = block_size - - def padder(self) -> PaddingContext: - return ANSIX923PaddingContext(self.block_size) - - def unpadder(self) -> PaddingContext: - return ANSIX923UnpaddingContext(self.block_size) - - -PaddingContext.register(ANSIX923PaddingContext) -PaddingContext.register(ANSIX923UnpaddingContext) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py deleted file mode 100644 index 7f5a77a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py +++ /dev/null @@ -1,11 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -__all__ = ["Poly1305"] - -Poly1305 = rust_openssl.poly1305.Poly1305 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py deleted file mode 100644 index 62283cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +++ /dev/null @@ -1,65 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat.primitives._serialization import ( - BestAvailableEncryption, - Encoding, - KeySerializationEncryption, - NoEncryption, - ParameterFormat, - PrivateFormat, - PublicFormat, - _KeySerializationEncryption, -) -from cryptography.hazmat.primitives.serialization.base import ( - load_der_parameters, - load_der_private_key, - load_der_public_key, - load_pem_parameters, - load_pem_private_key, - load_pem_public_key, -) -from cryptography.hazmat.primitives.serialization.ssh import ( - SSHCertificate, - SSHCertificateBuilder, - SSHCertificateType, - SSHCertPrivateKeyTypes, - SSHCertPublicKeyTypes, - SSHPrivateKeyTypes, - SSHPublicKeyTypes, - load_ssh_private_key, - load_ssh_public_identity, - load_ssh_public_key, - ssh_key_fingerprint, -) - -__all__ = [ - "BestAvailableEncryption", - "Encoding", - "KeySerializationEncryption", - "NoEncryption", - "ParameterFormat", - "PrivateFormat", - "PublicFormat", - "SSHCertPrivateKeyTypes", - "SSHCertPublicKeyTypes", - "SSHCertificate", - "SSHCertificateBuilder", - "SSHCertificateType", - "SSHPrivateKeyTypes", - "SSHPublicKeyTypes", - "_KeySerializationEncryption", - "load_der_parameters", - "load_der_private_key", - "load_der_public_key", - "load_pem_parameters", - "load_pem_private_key", - "load_pem_public_key", - "load_ssh_private_key", - "load_ssh_public_identity", - "load_ssh_public_key", - "ssh_key_fingerprint", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py deleted file mode 100644 index e7c998b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py +++ /dev/null @@ -1,14 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -load_pem_private_key = rust_openssl.keys.load_pem_private_key -load_der_private_key = rust_openssl.keys.load_der_private_key - -load_pem_public_key = rust_openssl.keys.load_pem_public_key -load_der_public_key = rust_openssl.keys.load_der_public_key - -load_pem_parameters = rust_openssl.dh.from_pem_parameters -load_der_parameters = rust_openssl.dh.from_der_parameters diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py deleted file mode 100644 index 58884ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +++ /dev/null @@ -1,176 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing -from collections.abc import Iterable - -from cryptography import x509 -from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12 -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives._serialization import PBES as PBES -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed448, - ed25519, - rsa, -) -from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes - -__all__ = [ - "PBES", - "PKCS12Certificate", - "PKCS12KeyAndCertificates", - "PKCS12PrivateKeyTypes", - "load_key_and_certificates", - "load_pkcs12", - "serialize_java_truststore", - "serialize_key_and_certificates", -] - -PKCS12PrivateKeyTypes = typing.Union[ - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, -] - - -PKCS12Certificate = rust_pkcs12.PKCS12Certificate - - -class PKCS12KeyAndCertificates: - def __init__( - self, - key: PrivateKeyTypes | None, - cert: PKCS12Certificate | None, - additional_certs: list[PKCS12Certificate], - ): - if key is not None and not isinstance( - key, - ( - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - ), - ): - raise TypeError( - "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" - " private key, or None." - ) - if cert is not None and not isinstance(cert, PKCS12Certificate): - raise TypeError("cert must be a PKCS12Certificate object or None") - if not all( - isinstance(add_cert, PKCS12Certificate) - for add_cert in additional_certs - ): - raise TypeError( - "all values in additional_certs must be PKCS12Certificate" - " objects" - ) - self._key = key - self._cert = cert - self._additional_certs = additional_certs - - @property - def key(self) -> PrivateKeyTypes | None: - return self._key - - @property - def cert(self) -> PKCS12Certificate | None: - return self._cert - - @property - def additional_certs(self) -> list[PKCS12Certificate]: - return self._additional_certs - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PKCS12KeyAndCertificates): - return NotImplemented - - return ( - self.key == other.key - and self.cert == other.cert - and self.additional_certs == other.additional_certs - ) - - def __hash__(self) -> int: - return hash((self.key, self.cert, tuple(self.additional_certs))) - - def __repr__(self) -> str: - fmt = ( - "" - ) - return fmt.format(self.key, self.cert, self.additional_certs) - - -load_key_and_certificates = rust_pkcs12.load_key_and_certificates -load_pkcs12 = rust_pkcs12.load_pkcs12 - - -_PKCS12CATypes = typing.Union[ - x509.Certificate, - PKCS12Certificate, -] - - -def serialize_java_truststore( - certs: Iterable[PKCS12Certificate], - encryption_algorithm: serialization.KeySerializationEncryption, -) -> bytes: - if not certs: - raise ValueError("You must supply at least one cert") - - if not isinstance( - encryption_algorithm, serialization.KeySerializationEncryption - ): - raise TypeError( - "Key encryption algorithm must be a " - "KeySerializationEncryption instance" - ) - - return rust_pkcs12.serialize_java_truststore(certs, encryption_algorithm) - - -def serialize_key_and_certificates( - name: bytes | None, - key: PKCS12PrivateKeyTypes | None, - cert: x509.Certificate | None, - cas: Iterable[_PKCS12CATypes] | None, - encryption_algorithm: serialization.KeySerializationEncryption, -) -> bytes: - if key is not None and not isinstance( - key, - ( - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ec.EllipticCurvePrivateKey, - ed25519.Ed25519PrivateKey, - ed448.Ed448PrivateKey, - ), - ): - raise TypeError( - "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" - " private key, or None." - ) - - if not isinstance( - encryption_algorithm, serialization.KeySerializationEncryption - ): - raise TypeError( - "Key encryption algorithm must be a " - "KeySerializationEncryption instance" - ) - - if key is None and cert is None and not cas: - raise ValueError("You must supply at least one of key, cert, or cas") - - return rust_pkcs12.serialize_key_and_certificates( - name, key, cert, cas, encryption_algorithm - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py deleted file mode 100644 index 456dc5b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +++ /dev/null @@ -1,411 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import email.base64mime -import email.generator -import email.message -import email.policy -import io -import typing -from collections.abc import Iterable - -from cryptography import utils, x509 -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa -from cryptography.hazmat.primitives.ciphers import ( - algorithms, -) -from cryptography.utils import _check_byteslike - -load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates - -load_der_pkcs7_certificates = rust_pkcs7.load_der_pkcs7_certificates - -serialize_certificates = rust_pkcs7.serialize_certificates - -PKCS7HashTypes = typing.Union[ - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, -] - -PKCS7PrivateKeyTypes = typing.Union[ - rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey -] - -ContentEncryptionAlgorithm = typing.Union[ - typing.Type[algorithms.AES128], typing.Type[algorithms.AES256] -] - - -class PKCS7Options(utils.Enum): - Text = "Add text/plain MIME type" - Binary = "Don't translate input data into canonical MIME format" - DetachedSignature = "Don't embed data in the PKCS7 structure" - NoCapabilities = "Don't embed SMIME capabilities" - NoAttributes = "Don't embed authenticatedAttributes" - NoCerts = "Don't embed signer certificate" - - -class PKCS7SignatureBuilder: - def __init__( - self, - data: utils.Buffer | None = None, - signers: list[ - tuple[ - x509.Certificate, - PKCS7PrivateKeyTypes, - PKCS7HashTypes, - padding.PSS | padding.PKCS1v15 | None, - ] - ] = [], - additional_certs: list[x509.Certificate] = [], - ): - self._data = data - self._signers = signers - self._additional_certs = additional_certs - - def set_data(self, data: utils.Buffer) -> PKCS7SignatureBuilder: - _check_byteslike("data", data) - if self._data is not None: - raise ValueError("data may only be set once") - - return PKCS7SignatureBuilder(data, self._signers) - - def add_signer( - self, - certificate: x509.Certificate, - private_key: PKCS7PrivateKeyTypes, - hash_algorithm: PKCS7HashTypes, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ) -> PKCS7SignatureBuilder: - if not isinstance( - hash_algorithm, - ( - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - ), - ): - raise TypeError( - "hash_algorithm must be one of hashes.SHA224, " - "SHA256, SHA384, or SHA512" - ) - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - if not isinstance( - private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) - ): - raise TypeError("Only RSA & EC keys are supported at this time.") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - return PKCS7SignatureBuilder( - self._data, - [ - *self._signers, - (certificate, private_key, hash_algorithm, rsa_padding), - ], - ) - - def add_certificate( - self, certificate: x509.Certificate - ) -> PKCS7SignatureBuilder: - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - return PKCS7SignatureBuilder( - self._data, self._signers, [*self._additional_certs, certificate] - ) - - def sign( - self, - encoding: serialization.Encoding, - options: Iterable[PKCS7Options], - backend: typing.Any = None, - ) -> bytes: - if len(self._signers) == 0: - raise ValueError("Must have at least one signer") - if self._data is None: - raise ValueError("You must add data to sign") - options = list(options) - if not all(isinstance(x, PKCS7Options) for x in options): - raise ValueError("options must be from the PKCS7Options enum") - if encoding not in ( - serialization.Encoding.PEM, - serialization.Encoding.DER, - serialization.Encoding.SMIME, - ): - raise ValueError( - "Must be PEM, DER, or SMIME from the Encoding enum" - ) - - # Text is a meaningless option unless it is accompanied by - # DetachedSignature - if ( - PKCS7Options.Text in options - and PKCS7Options.DetachedSignature not in options - ): - raise ValueError( - "When passing the Text option you must also pass " - "DetachedSignature" - ) - - if PKCS7Options.Text in options and encoding in ( - serialization.Encoding.DER, - serialization.Encoding.PEM, - ): - raise ValueError( - "The Text option is only available for SMIME serialization" - ) - - # No attributes implies no capabilities so we'll error if you try to - # pass both. - if ( - PKCS7Options.NoAttributes in options - and PKCS7Options.NoCapabilities in options - ): - raise ValueError( - "NoAttributes is a superset of NoCapabilities. Do not pass " - "both values." - ) - - return rust_pkcs7.sign_and_serialize(self, encoding, options) - - -class PKCS7EnvelopeBuilder: - def __init__( - self, - *, - _data: bytes | None = None, - _recipients: list[x509.Certificate] | None = None, - _content_encryption_algorithm: ContentEncryptionAlgorithm - | None = None, - ): - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - if not ossl.rsa_encryption_supported(padding=padding.PKCS1v15()): - raise UnsupportedAlgorithm( - "RSA with PKCS1 v1.5 padding is not supported by this version" - " of OpenSSL.", - _Reasons.UNSUPPORTED_PADDING, - ) - self._data = _data - self._recipients = _recipients if _recipients is not None else [] - self._content_encryption_algorithm = _content_encryption_algorithm - - def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder: - _check_byteslike("data", data) - if self._data is not None: - raise ValueError("data may only be set once") - - return PKCS7EnvelopeBuilder( - _data=data, - _recipients=self._recipients, - _content_encryption_algorithm=self._content_encryption_algorithm, - ) - - def add_recipient( - self, - certificate: x509.Certificate, - ) -> PKCS7EnvelopeBuilder: - if not isinstance(certificate, x509.Certificate): - raise TypeError("certificate must be a x509.Certificate") - - if not isinstance(certificate.public_key(), rsa.RSAPublicKey): - raise TypeError("Only RSA keys are supported at this time.") - - return PKCS7EnvelopeBuilder( - _data=self._data, - _recipients=[ - *self._recipients, - certificate, - ], - _content_encryption_algorithm=self._content_encryption_algorithm, - ) - - def set_content_encryption_algorithm( - self, content_encryption_algorithm: ContentEncryptionAlgorithm - ) -> PKCS7EnvelopeBuilder: - if self._content_encryption_algorithm is not None: - raise ValueError("Content encryption algo may only be set once") - if content_encryption_algorithm not in { - algorithms.AES128, - algorithms.AES256, - }: - raise TypeError("Only AES128 and AES256 are supported") - - return PKCS7EnvelopeBuilder( - _data=self._data, - _recipients=self._recipients, - _content_encryption_algorithm=content_encryption_algorithm, - ) - - def encrypt( - self, - encoding: serialization.Encoding, - options: Iterable[PKCS7Options], - ) -> bytes: - if len(self._recipients) == 0: - raise ValueError("Must have at least one recipient") - if self._data is None: - raise ValueError("You must add data to encrypt") - - # The default content encryption algorithm is AES-128, which the S/MIME - # v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) - content_encryption_algorithm = ( - self._content_encryption_algorithm or algorithms.AES128 - ) - - options = list(options) - if not all(isinstance(x, PKCS7Options) for x in options): - raise ValueError("options must be from the PKCS7Options enum") - if encoding not in ( - serialization.Encoding.PEM, - serialization.Encoding.DER, - serialization.Encoding.SMIME, - ): - raise ValueError( - "Must be PEM, DER, or SMIME from the Encoding enum" - ) - - # Only allow options that make sense for encryption - if any( - opt not in [PKCS7Options.Text, PKCS7Options.Binary] - for opt in options - ): - raise ValueError( - "Only the following options are supported for encryption: " - "Text, Binary" - ) - elif PKCS7Options.Text in options and PKCS7Options.Binary in options: - # OpenSSL accepts both options at the same time, but ignores Text. - # We fail defensively to avoid unexpected outputs. - raise ValueError( - "Cannot use Binary and Text options at the same time" - ) - - return rust_pkcs7.encrypt_and_serialize( - self, content_encryption_algorithm, encoding, options - ) - - -pkcs7_decrypt_der = rust_pkcs7.decrypt_der -pkcs7_decrypt_pem = rust_pkcs7.decrypt_pem -pkcs7_decrypt_smime = rust_pkcs7.decrypt_smime - - -def _smime_signed_encode( - data: bytes, signature: bytes, micalg: str, text_mode: bool -) -> bytes: - # This function works pretty hard to replicate what OpenSSL does - # precisely. For good and for ill. - - m = email.message.Message() - m.add_header("MIME-Version", "1.0") - m.add_header( - "Content-Type", - "multipart/signed", - protocol="application/x-pkcs7-signature", - micalg=micalg, - ) - - m.preamble = "This is an S/MIME signed message\n" - - msg_part = OpenSSLMimePart() - msg_part.set_payload(data) - if text_mode: - msg_part.add_header("Content-Type", "text/plain") - m.attach(msg_part) - - sig_part = email.message.MIMEPart() - sig_part.add_header( - "Content-Type", "application/x-pkcs7-signature", name="smime.p7s" - ) - sig_part.add_header("Content-Transfer-Encoding", "base64") - sig_part.add_header( - "Content-Disposition", "attachment", filename="smime.p7s" - ) - sig_part.set_payload( - email.base64mime.body_encode(signature, maxlinelen=65) - ) - del sig_part["MIME-Version"] - m.attach(sig_part) - - fp = io.BytesIO() - g = email.generator.BytesGenerator( - fp, - maxheaderlen=0, - mangle_from_=False, - policy=m.policy.clone(linesep="\r\n"), - ) - g.flatten(m) - return fp.getvalue() - - -def _smime_enveloped_encode(data: bytes) -> bytes: - m = email.message.Message() - m.add_header("MIME-Version", "1.0") - m.add_header("Content-Disposition", "attachment", filename="smime.p7m") - m.add_header( - "Content-Type", - "application/pkcs7-mime", - smime_type="enveloped-data", - name="smime.p7m", - ) - m.add_header("Content-Transfer-Encoding", "base64") - - m.set_payload(email.base64mime.body_encode(data, maxlinelen=65)) - - return m.as_bytes(policy=m.policy.clone(linesep="\n", max_line_length=0)) - - -def _smime_enveloped_decode(data: bytes) -> bytes: - m = email.message_from_bytes(data) - if m.get_content_type() not in { - "application/x-pkcs7-mime", - "application/pkcs7-mime", - }: - raise ValueError("Not an S/MIME enveloped message") - return bytes(m.get_payload(decode=True)) - - -def _smime_remove_text_headers(data: bytes) -> bytes: - m = email.message_from_bytes(data) - # Using get() instead of get_content_type() since it has None as default, - # where the latter has "text/plain". Both methods are case-insensitive. - content_type = m.get("content-type") - if content_type is None: - raise ValueError( - "Decrypted MIME data has no 'Content-Type' header. " - "Please remove the 'Text' option to parse it manually." - ) - if "text/plain" not in content_type: - raise ValueError( - f"Decrypted MIME data content type is '{content_type}', not " - "'text/plain'. Remove the 'Text' option to parse it manually." - ) - return bytes(m.get_payload(decode=True)) - - -class OpenSSLMimePart(email.message.MIMEPart): - # A MIMEPart subclass that replicates OpenSSL's behavior of not including - # a newline if there are no headers. - def _write_headers(self, generator) -> None: - if list(self.raw_items()): - generator._write_headers(self) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py deleted file mode 100644 index cb10cf8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +++ /dev/null @@ -1,1619 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import binascii -import enum -import os -import re -import typing -import warnings -from base64 import encodebytes as _base64_encode -from dataclasses import dataclass - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed25519, - padding, - rsa, -) -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.hazmat.primitives.ciphers import ( - AEADDecryptionContext, - Cipher, - algorithms, - modes, -) -from cryptography.hazmat.primitives.serialization import ( - Encoding, - KeySerializationEncryption, - NoEncryption, - PrivateFormat, - PublicFormat, - _KeySerializationEncryption, -) - -try: - from bcrypt import kdf as _bcrypt_kdf - - _bcrypt_supported = True -except ImportError: - _bcrypt_supported = False - - def _bcrypt_kdf( - password: bytes, - salt: bytes, - desired_key_bytes: int, - rounds: int, - ignore_few_rounds: bool = False, - ) -> bytes: - raise UnsupportedAlgorithm("Need bcrypt module") - - -_SSH_ED25519 = b"ssh-ed25519" -_SSH_RSA = b"ssh-rsa" -_SSH_DSA = b"ssh-dss" -_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256" -_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384" -_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521" -_CERT_SUFFIX = b"-cert-v01@openssh.com" - -# U2F application string suffixed pubkey -_SK_SSH_ED25519 = b"sk-ssh-ed25519@openssh.com" -_SK_SSH_ECDSA_NISTP256 = b"sk-ecdsa-sha2-nistp256@openssh.com" - -# These are not key types, only algorithms, so they cannot appear -# as a public key type -_SSH_RSA_SHA256 = b"rsa-sha2-256" -_SSH_RSA_SHA512 = b"rsa-sha2-512" - -_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") -_SK_MAGIC = b"openssh-key-v1\0" -_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----" -_SK_END = b"-----END OPENSSH PRIVATE KEY-----" -_BCRYPT = b"bcrypt" -_NONE = b"none" -_DEFAULT_CIPHER = b"aes256-ctr" -_DEFAULT_ROUNDS = 16 - -# re is only way to work on bytes-like data -_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL) - -# padding for max blocksize -_PADDING = memoryview(bytearray(range(1, 1 + 16))) - - -@dataclass -class _SSHCipher: - alg: type[algorithms.AES] - key_len: int - mode: type[modes.CTR] | type[modes.CBC] | type[modes.GCM] - block_len: int - iv_len: int - tag_len: int | None - is_aead: bool - - -# ciphers that are actually used in key wrapping -_SSH_CIPHERS: dict[bytes, _SSHCipher] = { - b"aes256-ctr": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.CTR, - block_len=16, - iv_len=16, - tag_len=None, - is_aead=False, - ), - b"aes256-cbc": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.CBC, - block_len=16, - iv_len=16, - tag_len=None, - is_aead=False, - ), - b"aes256-gcm@openssh.com": _SSHCipher( - alg=algorithms.AES, - key_len=32, - mode=modes.GCM, - block_len=16, - iv_len=12, - tag_len=16, - is_aead=True, - ), -} - -# map local curve name to key type -_ECDSA_KEY_TYPE = { - "secp256r1": _ECDSA_NISTP256, - "secp384r1": _ECDSA_NISTP384, - "secp521r1": _ECDSA_NISTP521, -} - - -def _get_ssh_key_type(key: SSHPrivateKeyTypes | SSHPublicKeyTypes) -> bytes: - if isinstance(key, ec.EllipticCurvePrivateKey): - key_type = _ecdsa_key_type(key.public_key()) - elif isinstance(key, ec.EllipticCurvePublicKey): - key_type = _ecdsa_key_type(key) - elif isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): - key_type = _SSH_RSA - elif isinstance(key, (dsa.DSAPrivateKey, dsa.DSAPublicKey)): - key_type = _SSH_DSA - elif isinstance( - key, (ed25519.Ed25519PrivateKey, ed25519.Ed25519PublicKey) - ): - key_type = _SSH_ED25519 - else: - raise ValueError("Unsupported key type") - - return key_type - - -def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes: - """Return SSH key_type and curve_name for private key.""" - curve = public_key.curve - if curve.name not in _ECDSA_KEY_TYPE: - raise ValueError( - f"Unsupported curve for ssh private key: {curve.name!r}" - ) - return _ECDSA_KEY_TYPE[curve.name] - - -def _ssh_pem_encode( - data: utils.Buffer, - prefix: bytes = _SK_START + b"\n", - suffix: bytes = _SK_END + b"\n", -) -> bytes: - return b"".join([prefix, _base64_encode(data), suffix]) - - -def _check_block_size(data: utils.Buffer, block_len: int) -> None: - """Require data to be full blocks""" - if not data or len(data) % block_len != 0: - raise ValueError("Corrupt data: missing padding") - - -def _check_empty(data: utils.Buffer) -> None: - """All data should have been parsed.""" - if data: - raise ValueError("Corrupt data: unparsed data") - - -def _init_cipher( - ciphername: bytes, - password: bytes | None, - salt: bytes, - rounds: int, -) -> Cipher[modes.CBC | modes.CTR | modes.GCM]: - """Generate key + iv and return cipher.""" - if not password: - raise TypeError( - "Key is password-protected, but password was not provided." - ) - - ciph = _SSH_CIPHERS[ciphername] - seed = _bcrypt_kdf( - password, salt, ciph.key_len + ciph.iv_len, rounds, True - ) - return Cipher( - ciph.alg(seed[: ciph.key_len]), - ciph.mode(seed[ciph.key_len :]), - ) - - -def _get_u32(data: memoryview) -> tuple[int, memoryview]: - """Uint32""" - if len(data) < 4: - raise ValueError("Invalid data") - return int.from_bytes(data[:4], byteorder="big"), data[4:] - - -def _get_u64(data: memoryview) -> tuple[int, memoryview]: - """Uint64""" - if len(data) < 8: - raise ValueError("Invalid data") - return int.from_bytes(data[:8], byteorder="big"), data[8:] - - -def _get_sshstr(data: memoryview) -> tuple[memoryview, memoryview]: - """Bytes with u32 length prefix""" - n, data = _get_u32(data) - if n > len(data): - raise ValueError("Invalid data") - return data[:n], data[n:] - - -def _get_mpint(data: memoryview) -> tuple[int, memoryview]: - """Big integer.""" - val, data = _get_sshstr(data) - if val and val[0] > 0x7F: - raise ValueError("Invalid data") - return int.from_bytes(val, "big"), data - - -def _to_mpint(val: int) -> bytes: - """Storage format for signed bigint.""" - if val < 0: - raise ValueError("negative mpint not allowed") - if not val: - return b"" - nbytes = (val.bit_length() + 8) // 8 - return utils.int_to_bytes(val, nbytes) - - -class _FragList: - """Build recursive structure without data copy.""" - - flist: list[utils.Buffer] - - def __init__(self, init: list[utils.Buffer] | None = None) -> None: - self.flist = [] - if init: - self.flist.extend(init) - - def put_raw(self, val: utils.Buffer) -> None: - """Add plain bytes""" - self.flist.append(val) - - def put_u32(self, val: int) -> None: - """Big-endian uint32""" - self.flist.append(val.to_bytes(length=4, byteorder="big")) - - def put_u64(self, val: int) -> None: - """Big-endian uint64""" - self.flist.append(val.to_bytes(length=8, byteorder="big")) - - def put_sshstr(self, val: bytes | _FragList) -> None: - """Bytes prefixed with u32 length""" - if isinstance(val, (bytes, memoryview, bytearray)): - self.put_u32(len(val)) - self.flist.append(val) - else: - self.put_u32(val.size()) - self.flist.extend(val.flist) - - def put_mpint(self, val: int) -> None: - """Big-endian bigint prefixed with u32 length""" - self.put_sshstr(_to_mpint(val)) - - def size(self) -> int: - """Current number of bytes""" - return sum(map(len, self.flist)) - - def render(self, dstbuf: memoryview, pos: int = 0) -> int: - """Write into bytearray""" - for frag in self.flist: - flen = len(frag) - start, pos = pos, pos + flen - dstbuf[start:pos] = frag - return pos - - def tobytes(self) -> bytes: - """Return as bytes""" - buf = memoryview(bytearray(self.size())) - self.render(buf) - return buf.tobytes() - - -class _SSHFormatRSA: - """Format for RSA keys. - - Public: - mpint e, n - Private: - mpint n, e, d, iqmp, p, q - """ - - def get_public( - self, data: memoryview - ) -> tuple[tuple[int, int], memoryview]: - """RSA public fields""" - e, data = _get_mpint(data) - n, data = _get_mpint(data) - return (e, n), data - - def load_public( - self, data: memoryview - ) -> tuple[rsa.RSAPublicKey, memoryview]: - """Make RSA public key from data.""" - (e, n), data = self.get_public(data) - public_numbers = rsa.RSAPublicNumbers(e, n) - public_key = public_numbers.public_key() - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[rsa.RSAPrivateKey, memoryview]: - """Make RSA private key from data.""" - n, data = _get_mpint(data) - e, data = _get_mpint(data) - d, data = _get_mpint(data) - iqmp, data = _get_mpint(data) - p, data = _get_mpint(data) - q, data = _get_mpint(data) - - if (e, n) != pubfields: - raise ValueError("Corrupt data: rsa field mismatch") - dmp1 = rsa.rsa_crt_dmp1(d, p) - dmq1 = rsa.rsa_crt_dmq1(d, q) - public_numbers = rsa.RSAPublicNumbers(e, n) - private_numbers = rsa.RSAPrivateNumbers( - p, q, d, dmp1, dmq1, iqmp, public_numbers - ) - private_key = private_numbers.private_key( - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation - ) - return private_key, data - - def encode_public( - self, public_key: rsa.RSAPublicKey, f_pub: _FragList - ) -> None: - """Write RSA public key""" - pubn = public_key.public_numbers() - f_pub.put_mpint(pubn.e) - f_pub.put_mpint(pubn.n) - - def encode_private( - self, private_key: rsa.RSAPrivateKey, f_priv: _FragList - ) -> None: - """Write RSA private key""" - private_numbers = private_key.private_numbers() - public_numbers = private_numbers.public_numbers - - f_priv.put_mpint(public_numbers.n) - f_priv.put_mpint(public_numbers.e) - - f_priv.put_mpint(private_numbers.d) - f_priv.put_mpint(private_numbers.iqmp) - f_priv.put_mpint(private_numbers.p) - f_priv.put_mpint(private_numbers.q) - - -class _SSHFormatDSA: - """Format for DSA keys. - - Public: - mpint p, q, g, y - Private: - mpint p, q, g, y, x - """ - - def get_public(self, data: memoryview) -> tuple[tuple, memoryview]: - """DSA public fields""" - p, data = _get_mpint(data) - q, data = _get_mpint(data) - g, data = _get_mpint(data) - y, data = _get_mpint(data) - return (p, q, g, y), data - - def load_public( - self, data: memoryview - ) -> tuple[dsa.DSAPublicKey, memoryview]: - """Make DSA public key from data.""" - (p, q, g, y), data = self.get_public(data) - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) - self._validate(public_numbers) - public_key = public_numbers.public_key() - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[dsa.DSAPrivateKey, memoryview]: - """Make DSA private key from data.""" - (p, q, g, y), data = self.get_public(data) - x, data = _get_mpint(data) - - if (p, q, g, y) != pubfields: - raise ValueError("Corrupt data: dsa field mismatch") - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) - self._validate(public_numbers) - private_numbers = dsa.DSAPrivateNumbers(x, public_numbers) - private_key = private_numbers.private_key() - return private_key, data - - def encode_public( - self, public_key: dsa.DSAPublicKey, f_pub: _FragList - ) -> None: - """Write DSA public key""" - public_numbers = public_key.public_numbers() - parameter_numbers = public_numbers.parameter_numbers - self._validate(public_numbers) - - f_pub.put_mpint(parameter_numbers.p) - f_pub.put_mpint(parameter_numbers.q) - f_pub.put_mpint(parameter_numbers.g) - f_pub.put_mpint(public_numbers.y) - - def encode_private( - self, private_key: dsa.DSAPrivateKey, f_priv: _FragList - ) -> None: - """Write DSA private key""" - self.encode_public(private_key.public_key(), f_priv) - f_priv.put_mpint(private_key.private_numbers().x) - - def _validate(self, public_numbers: dsa.DSAPublicNumbers) -> None: - parameter_numbers = public_numbers.parameter_numbers - if parameter_numbers.p.bit_length() != 1024: - raise ValueError("SSH supports only 1024 bit DSA keys") - - -class _SSHFormatECDSA: - """Format for ECDSA keys. - - Public: - str curve - bytes point - Private: - str curve - bytes point - mpint secret - """ - - def __init__(self, ssh_curve_name: bytes, curve: ec.EllipticCurve): - self.ssh_curve_name = ssh_curve_name - self.curve = curve - - def get_public( - self, data: memoryview - ) -> tuple[tuple[memoryview, memoryview], memoryview]: - """ECDSA public fields""" - curve, data = _get_sshstr(data) - point, data = _get_sshstr(data) - if curve != self.ssh_curve_name: - raise ValueError("Curve name mismatch") - if point[0] != 4: - raise NotImplementedError("Need uncompressed point") - return (curve, point), data - - def load_public( - self, data: memoryview - ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: - """Make ECDSA public key from data.""" - (_, point), data = self.get_public(data) - public_key = ec.EllipticCurvePublicKey.from_encoded_point( - self.curve, point.tobytes() - ) - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[ec.EllipticCurvePrivateKey, memoryview]: - """Make ECDSA private key from data.""" - (curve_name, point), data = self.get_public(data) - secret, data = _get_mpint(data) - - if (curve_name, point) != pubfields: - raise ValueError("Corrupt data: ecdsa field mismatch") - private_key = ec.derive_private_key(secret, self.curve) - return private_key, data - - def encode_public( - self, public_key: ec.EllipticCurvePublicKey, f_pub: _FragList - ) -> None: - """Write ECDSA public key""" - point = public_key.public_bytes( - Encoding.X962, PublicFormat.UncompressedPoint - ) - f_pub.put_sshstr(self.ssh_curve_name) - f_pub.put_sshstr(point) - - def encode_private( - self, private_key: ec.EllipticCurvePrivateKey, f_priv: _FragList - ) -> None: - """Write ECDSA private key""" - public_key = private_key.public_key() - private_numbers = private_key.private_numbers() - - self.encode_public(public_key, f_priv) - f_priv.put_mpint(private_numbers.private_value) - - -class _SSHFormatEd25519: - """Format for Ed25519 keys. - - Public: - bytes point - Private: - bytes point - bytes secret_and_point - """ - - def get_public( - self, data: memoryview - ) -> tuple[tuple[memoryview], memoryview]: - """Ed25519 public fields""" - point, data = _get_sshstr(data) - return (point,), data - - def load_public( - self, data: memoryview - ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: - """Make Ed25519 public key from data.""" - (point,), data = self.get_public(data) - public_key = ed25519.Ed25519PublicKey.from_public_bytes( - point.tobytes() - ) - return public_key, data - - def load_private( - self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool - ) -> tuple[ed25519.Ed25519PrivateKey, memoryview]: - """Make Ed25519 private key from data.""" - (point,), data = self.get_public(data) - keypair, data = _get_sshstr(data) - - secret = keypair[:32] - point2 = keypair[32:] - if point != point2 or (point,) != pubfields: - raise ValueError("Corrupt data: ed25519 field mismatch") - private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) - return private_key, data - - def encode_public( - self, public_key: ed25519.Ed25519PublicKey, f_pub: _FragList - ) -> None: - """Write Ed25519 public key""" - raw_public_key = public_key.public_bytes( - Encoding.Raw, PublicFormat.Raw - ) - f_pub.put_sshstr(raw_public_key) - - def encode_private( - self, private_key: ed25519.Ed25519PrivateKey, f_priv: _FragList - ) -> None: - """Write Ed25519 private key""" - public_key = private_key.public_key() - raw_private_key = private_key.private_bytes( - Encoding.Raw, PrivateFormat.Raw, NoEncryption() - ) - raw_public_key = public_key.public_bytes( - Encoding.Raw, PublicFormat.Raw - ) - f_keypair = _FragList([raw_private_key, raw_public_key]) - - self.encode_public(public_key, f_priv) - f_priv.put_sshstr(f_keypair) - - -def load_application(data) -> tuple[memoryview, memoryview]: - """ - U2F application strings - """ - application, data = _get_sshstr(data) - if not application.tobytes().startswith(b"ssh:"): - raise ValueError( - "U2F application string does not start with b'ssh:' " - f"({application})" - ) - return application, data - - -class _SSHFormatSKEd25519: - """ - The format of a sk-ssh-ed25519@openssh.com public key is: - - string "sk-ssh-ed25519@openssh.com" - string public key - string application (user-specified, but typically "ssh:") - """ - - def load_public( - self, data: memoryview - ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: - """Make Ed25519 public key from data.""" - public_key, data = _lookup_kformat(_SSH_ED25519).load_public(data) - _, data = load_application(data) - return public_key, data - - def get_public(self, data: memoryview) -> typing.NoReturn: - # Confusingly `get_public` is an entry point used by private key - # loading. - raise UnsupportedAlgorithm( - "sk-ssh-ed25519 private keys cannot be loaded" - ) - - -class _SSHFormatSKECDSA: - """ - The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is: - - string "sk-ecdsa-sha2-nistp256@openssh.com" - string curve name - ec_point Q - string application (user-specified, but typically "ssh:") - """ - - def load_public( - self, data: memoryview - ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: - """Make ECDSA public key from data.""" - public_key, data = _lookup_kformat(_ECDSA_NISTP256).load_public(data) - _, data = load_application(data) - return public_key, data - - def get_public(self, data: memoryview) -> typing.NoReturn: - # Confusingly `get_public` is an entry point used by private key - # loading. - raise UnsupportedAlgorithm( - "sk-ecdsa-sha2-nistp256 private keys cannot be loaded" - ) - - -_KEY_FORMATS = { - _SSH_RSA: _SSHFormatRSA(), - _SSH_DSA: _SSHFormatDSA(), - _SSH_ED25519: _SSHFormatEd25519(), - _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()), - _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()), - _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()), - _SK_SSH_ED25519: _SSHFormatSKEd25519(), - _SK_SSH_ECDSA_NISTP256: _SSHFormatSKECDSA(), -} - - -def _lookup_kformat(key_type: utils.Buffer): - """Return valid format or throw error""" - if not isinstance(key_type, bytes): - key_type = memoryview(key_type).tobytes() - if key_type in _KEY_FORMATS: - return _KEY_FORMATS[key_type] - raise UnsupportedAlgorithm(f"Unsupported key type: {key_type!r}") - - -SSHPrivateKeyTypes = typing.Union[ - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - dsa.DSAPrivateKey, - ed25519.Ed25519PrivateKey, -] - - -def load_ssh_private_key( - data: utils.Buffer, - password: bytes | None, - backend: typing.Any = None, - *, - unsafe_skip_rsa_key_validation: bool = False, -) -> SSHPrivateKeyTypes: - """Load private key from OpenSSH custom encoding.""" - utils._check_byteslike("data", data) - if password is not None: - utils._check_bytes("password", password) - - m = _PEM_RC.search(data) - if not m: - raise ValueError("Not OpenSSH private key format") - p1 = m.start(1) - p2 = m.end(1) - data = binascii.a2b_base64(memoryview(data)[p1:p2]) - if not data.startswith(_SK_MAGIC): - raise ValueError("Not OpenSSH private key format") - data = memoryview(data)[len(_SK_MAGIC) :] - - # parse header - ciphername, data = _get_sshstr(data) - kdfname, data = _get_sshstr(data) - kdfoptions, data = _get_sshstr(data) - nkeys, data = _get_u32(data) - if nkeys != 1: - raise ValueError("Only one key supported") - - # load public key data - pubdata, data = _get_sshstr(data) - pub_key_type, pubdata = _get_sshstr(pubdata) - kformat = _lookup_kformat(pub_key_type) - pubfields, pubdata = kformat.get_public(pubdata) - _check_empty(pubdata) - - if ciphername != _NONE or kdfname != _NONE: - ciphername_bytes = ciphername.tobytes() - if ciphername_bytes not in _SSH_CIPHERS: - raise UnsupportedAlgorithm( - f"Unsupported cipher: {ciphername_bytes!r}" - ) - if kdfname != _BCRYPT: - raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}") - blklen = _SSH_CIPHERS[ciphername_bytes].block_len - tag_len = _SSH_CIPHERS[ciphername_bytes].tag_len - # load secret data - edata, data = _get_sshstr(data) - # see https://bugzilla.mindrot.org/show_bug.cgi?id=3553 for - # information about how OpenSSH handles AEAD tags - if _SSH_CIPHERS[ciphername_bytes].is_aead: - tag = bytes(data) - if len(tag) != tag_len: - raise ValueError("Corrupt data: invalid tag length for cipher") - else: - _check_empty(data) - _check_block_size(edata, blklen) - salt, kbuf = _get_sshstr(kdfoptions) - rounds, kbuf = _get_u32(kbuf) - _check_empty(kbuf) - ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds) - dec = ciph.decryptor() - edata = memoryview(dec.update(edata)) - if _SSH_CIPHERS[ciphername_bytes].is_aead: - assert isinstance(dec, AEADDecryptionContext) - _check_empty(dec.finalize_with_tag(tag)) - else: - # _check_block_size requires data to be a full block so there - # should be no output from finalize - _check_empty(dec.finalize()) - else: - if password: - raise TypeError( - "Password was given but private key is not encrypted." - ) - # load secret data - edata, data = _get_sshstr(data) - _check_empty(data) - blklen = 8 - _check_block_size(edata, blklen) - ck1, edata = _get_u32(edata) - ck2, edata = _get_u32(edata) - if ck1 != ck2: - raise ValueError("Corrupt data: broken checksum") - - # load per-key struct - key_type, edata = _get_sshstr(edata) - if key_type != pub_key_type: - raise ValueError("Corrupt data: key type mismatch") - private_key, edata = kformat.load_private( - edata, - pubfields, - unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, - ) - # We don't use the comment - _, edata = _get_sshstr(edata) - - # yes, SSH does padding check *after* all other parsing is done. - # need to follow as it writes zero-byte padding too. - if edata != _PADDING[: len(edata)]: - raise ValueError("Corrupt data: invalid padding") - - if isinstance(private_key, dsa.DSAPrivateKey): - warnings.warn( - "SSH DSA keys are deprecated and will be removed in a future " - "release.", - utils.DeprecatedIn40, - stacklevel=2, - ) - - return private_key - - -def _serialize_ssh_private_key( - private_key: SSHPrivateKeyTypes, - password: bytes, - encryption_algorithm: KeySerializationEncryption, -) -> bytes: - """Serialize private key with OpenSSH custom encoding.""" - utils._check_bytes("password", password) - if isinstance(private_key, dsa.DSAPrivateKey): - warnings.warn( - "SSH DSA key support is deprecated and will be " - "removed in a future release", - utils.DeprecatedIn40, - stacklevel=4, - ) - - key_type = _get_ssh_key_type(private_key) - kformat = _lookup_kformat(key_type) - - # setup parameters - f_kdfoptions = _FragList() - if password: - ciphername = _DEFAULT_CIPHER - blklen = _SSH_CIPHERS[ciphername].block_len - kdfname = _BCRYPT - rounds = _DEFAULT_ROUNDS - if ( - isinstance(encryption_algorithm, _KeySerializationEncryption) - and encryption_algorithm._kdf_rounds is not None - ): - rounds = encryption_algorithm._kdf_rounds - salt = os.urandom(16) - f_kdfoptions.put_sshstr(salt) - f_kdfoptions.put_u32(rounds) - ciph = _init_cipher(ciphername, password, salt, rounds) - else: - ciphername = kdfname = _NONE - blklen = 8 - ciph = None - nkeys = 1 - checkval = os.urandom(4) - comment = b"" - - # encode public and private parts together - f_public_key = _FragList() - f_public_key.put_sshstr(key_type) - kformat.encode_public(private_key.public_key(), f_public_key) - - f_secrets = _FragList([checkval, checkval]) - f_secrets.put_sshstr(key_type) - kformat.encode_private(private_key, f_secrets) - f_secrets.put_sshstr(comment) - f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)]) - - # top-level structure - f_main = _FragList() - f_main.put_raw(_SK_MAGIC) - f_main.put_sshstr(ciphername) - f_main.put_sshstr(kdfname) - f_main.put_sshstr(f_kdfoptions) - f_main.put_u32(nkeys) - f_main.put_sshstr(f_public_key) - f_main.put_sshstr(f_secrets) - - # copy result info bytearray - slen = f_secrets.size() - mlen = f_main.size() - buf = memoryview(bytearray(mlen + blklen)) - f_main.render(buf) - ofs = mlen - slen - - # encrypt in-place - if ciph is not None: - ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:]) - - return _ssh_pem_encode(buf[:mlen]) - - -SSHPublicKeyTypes = typing.Union[ - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - dsa.DSAPublicKey, - ed25519.Ed25519PublicKey, -] - -SSHCertPublicKeyTypes = typing.Union[ - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - ed25519.Ed25519PublicKey, -] - - -class SSHCertificateType(enum.Enum): - USER = 1 - HOST = 2 - - -class SSHCertificate: - def __init__( - self, - _nonce: memoryview, - _public_key: SSHPublicKeyTypes, - _serial: int, - _cctype: int, - _key_id: memoryview, - _valid_principals: list[bytes], - _valid_after: int, - _valid_before: int, - _critical_options: dict[bytes, bytes], - _extensions: dict[bytes, bytes], - _sig_type: memoryview, - _sig_key: memoryview, - _inner_sig_type: memoryview, - _signature: memoryview, - _tbs_cert_body: memoryview, - _cert_key_type: bytes, - _cert_body: memoryview, - ): - self._nonce = _nonce - self._public_key = _public_key - self._serial = _serial - try: - self._type = SSHCertificateType(_cctype) - except ValueError: - raise ValueError("Invalid certificate type") - self._key_id = _key_id - self._valid_principals = _valid_principals - self._valid_after = _valid_after - self._valid_before = _valid_before - self._critical_options = _critical_options - self._extensions = _extensions - self._sig_type = _sig_type - self._sig_key = _sig_key - self._inner_sig_type = _inner_sig_type - self._signature = _signature - self._cert_key_type = _cert_key_type - self._cert_body = _cert_body - self._tbs_cert_body = _tbs_cert_body - - @property - def nonce(self) -> bytes: - return bytes(self._nonce) - - def public_key(self) -> SSHCertPublicKeyTypes: - # make mypy happy until we remove DSA support entirely and - # the underlying union won't have a disallowed type - return typing.cast(SSHCertPublicKeyTypes, self._public_key) - - @property - def serial(self) -> int: - return self._serial - - @property - def type(self) -> SSHCertificateType: - return self._type - - @property - def key_id(self) -> bytes: - return bytes(self._key_id) - - @property - def valid_principals(self) -> list[bytes]: - return self._valid_principals - - @property - def valid_before(self) -> int: - return self._valid_before - - @property - def valid_after(self) -> int: - return self._valid_after - - @property - def critical_options(self) -> dict[bytes, bytes]: - return self._critical_options - - @property - def extensions(self) -> dict[bytes, bytes]: - return self._extensions - - def signature_key(self) -> SSHCertPublicKeyTypes: - sigformat = _lookup_kformat(self._sig_type) - signature_key, sigkey_rest = sigformat.load_public(self._sig_key) - _check_empty(sigkey_rest) - return signature_key - - def public_bytes(self) -> bytes: - return ( - bytes(self._cert_key_type) - + b" " - + binascii.b2a_base64(bytes(self._cert_body), newline=False) - ) - - def verify_cert_signature(self) -> None: - signature_key = self.signature_key() - if isinstance(signature_key, ed25519.Ed25519PublicKey): - signature_key.verify( - bytes(self._signature), bytes(self._tbs_cert_body) - ) - elif isinstance(signature_key, ec.EllipticCurvePublicKey): - # The signature is encoded as a pair of big-endian integers - r, data = _get_mpint(self._signature) - s, data = _get_mpint(data) - _check_empty(data) - computed_sig = asym_utils.encode_dss_signature(r, s) - hash_alg = _get_ec_hash_alg(signature_key.curve) - signature_key.verify( - computed_sig, bytes(self._tbs_cert_body), ec.ECDSA(hash_alg) - ) - else: - assert isinstance(signature_key, rsa.RSAPublicKey) - if self._inner_sig_type == _SSH_RSA: - hash_alg = hashes.SHA1() - elif self._inner_sig_type == _SSH_RSA_SHA256: - hash_alg = hashes.SHA256() - else: - assert self._inner_sig_type == _SSH_RSA_SHA512 - hash_alg = hashes.SHA512() - signature_key.verify( - bytes(self._signature), - bytes(self._tbs_cert_body), - padding.PKCS1v15(), - hash_alg, - ) - - -def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm: - if isinstance(curve, ec.SECP256R1): - return hashes.SHA256() - elif isinstance(curve, ec.SECP384R1): - return hashes.SHA384() - else: - assert isinstance(curve, ec.SECP521R1) - return hashes.SHA512() - - -def _load_ssh_public_identity( - data: utils.Buffer, - _legacy_dsa_allowed=False, -) -> SSHCertificate | SSHPublicKeyTypes: - utils._check_byteslike("data", data) - - m = _SSH_PUBKEY_RC.match(data) - if not m: - raise ValueError("Invalid line format") - key_type = orig_key_type = m.group(1) - key_body = m.group(2) - with_cert = False - if key_type.endswith(_CERT_SUFFIX): - with_cert = True - key_type = key_type[: -len(_CERT_SUFFIX)] - if key_type == _SSH_DSA and not _legacy_dsa_allowed: - raise UnsupportedAlgorithm( - "DSA keys aren't supported in SSH certificates" - ) - kformat = _lookup_kformat(key_type) - - try: - rest = memoryview(binascii.a2b_base64(key_body)) - except (TypeError, binascii.Error): - raise ValueError("Invalid format") - - if with_cert: - cert_body = rest - inner_key_type, rest = _get_sshstr(rest) - if inner_key_type != orig_key_type: - raise ValueError("Invalid key format") - if with_cert: - nonce, rest = _get_sshstr(rest) - public_key, rest = kformat.load_public(rest) - if with_cert: - serial, rest = _get_u64(rest) - cctype, rest = _get_u32(rest) - key_id, rest = _get_sshstr(rest) - principals, rest = _get_sshstr(rest) - valid_principals = [] - while principals: - principal, principals = _get_sshstr(principals) - valid_principals.append(bytes(principal)) - valid_after, rest = _get_u64(rest) - valid_before, rest = _get_u64(rest) - crit_options, rest = _get_sshstr(rest) - critical_options = _parse_exts_opts(crit_options) - exts, rest = _get_sshstr(rest) - extensions = _parse_exts_opts(exts) - # Get the reserved field, which is unused. - _, rest = _get_sshstr(rest) - sig_key_raw, rest = _get_sshstr(rest) - sig_type, sig_key = _get_sshstr(sig_key_raw) - if sig_type == _SSH_DSA and not _legacy_dsa_allowed: - raise UnsupportedAlgorithm( - "DSA signatures aren't supported in SSH certificates" - ) - # Get the entire cert body and subtract the signature - tbs_cert_body = cert_body[: -len(rest)] - signature_raw, rest = _get_sshstr(rest) - _check_empty(rest) - inner_sig_type, sig_rest = _get_sshstr(signature_raw) - # RSA certs can have multiple algorithm types - if ( - sig_type == _SSH_RSA - and inner_sig_type - not in [_SSH_RSA_SHA256, _SSH_RSA_SHA512, _SSH_RSA] - ) or (sig_type != _SSH_RSA and inner_sig_type != sig_type): - raise ValueError("Signature key type does not match") - signature, sig_rest = _get_sshstr(sig_rest) - _check_empty(sig_rest) - return SSHCertificate( - nonce, - public_key, - serial, - cctype, - key_id, - valid_principals, - valid_after, - valid_before, - critical_options, - extensions, - sig_type, - sig_key, - inner_sig_type, - signature, - tbs_cert_body, - orig_key_type, - cert_body, - ) - else: - _check_empty(rest) - return public_key - - -def load_ssh_public_identity( - data: utils.Buffer, -) -> SSHCertificate | SSHPublicKeyTypes: - return _load_ssh_public_identity(data) - - -def _parse_exts_opts(exts_opts: memoryview) -> dict[bytes, bytes]: - result: dict[bytes, bytes] = {} - last_name = None - while exts_opts: - name, exts_opts = _get_sshstr(exts_opts) - bname: bytes = bytes(name) - if bname in result: - raise ValueError("Duplicate name") - if last_name is not None and bname < last_name: - raise ValueError("Fields not lexically sorted") - value, exts_opts = _get_sshstr(exts_opts) - if len(value) > 0: - value, extra = _get_sshstr(value) - if len(extra) > 0: - raise ValueError("Unexpected extra data after value") - result[bname] = bytes(value) - last_name = bname - return result - - -def ssh_key_fingerprint( - key: SSHPublicKeyTypes, - hash_algorithm: hashes.MD5 | hashes.SHA256, -) -> bytes: - if not isinstance(hash_algorithm, (hashes.MD5, hashes.SHA256)): - raise TypeError("hash_algorithm must be either MD5 or SHA256") - - key_type = _get_ssh_key_type(key) - kformat = _lookup_kformat(key_type) - - f_pub = _FragList() - f_pub.put_sshstr(key_type) - kformat.encode_public(key, f_pub) - - ssh_binary_data = f_pub.tobytes() - - # Hash the binary data - hash_obj = hashes.Hash(hash_algorithm) - hash_obj.update(ssh_binary_data) - return hash_obj.finalize() - - -def load_ssh_public_key( - data: utils.Buffer, backend: typing.Any = None -) -> SSHPublicKeyTypes: - cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True) - public_key: SSHPublicKeyTypes - if isinstance(cert_or_key, SSHCertificate): - public_key = cert_or_key.public_key() - else: - public_key = cert_or_key - - if isinstance(public_key, dsa.DSAPublicKey): - warnings.warn( - "SSH DSA keys are deprecated and will be removed in a future " - "release.", - utils.DeprecatedIn40, - stacklevel=2, - ) - return public_key - - -def serialize_ssh_public_key(public_key: SSHPublicKeyTypes) -> bytes: - """One-line public key format for OpenSSH""" - if isinstance(public_key, dsa.DSAPublicKey): - warnings.warn( - "SSH DSA key support is deprecated and will be " - "removed in a future release", - utils.DeprecatedIn40, - stacklevel=4, - ) - key_type = _get_ssh_key_type(public_key) - kformat = _lookup_kformat(key_type) - - f_pub = _FragList() - f_pub.put_sshstr(key_type) - kformat.encode_public(public_key, f_pub) - - pub = binascii.b2a_base64(f_pub.tobytes()).strip() - return b"".join([key_type, b" ", pub]) - - -SSHCertPrivateKeyTypes = typing.Union[ - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - ed25519.Ed25519PrivateKey, -] - - -# This is an undocumented limit enforced in the openssh codebase for sshd and -# ssh-keygen, but it is undefined in the ssh certificates spec. -_SSHKEY_CERT_MAX_PRINCIPALS = 256 - - -class SSHCertificateBuilder: - def __init__( - self, - _public_key: SSHCertPublicKeyTypes | None = None, - _serial: int | None = None, - _type: SSHCertificateType | None = None, - _key_id: bytes | None = None, - _valid_principals: list[bytes] = [], - _valid_for_all_principals: bool = False, - _valid_before: int | None = None, - _valid_after: int | None = None, - _critical_options: list[tuple[bytes, bytes]] = [], - _extensions: list[tuple[bytes, bytes]] = [], - ): - self._public_key = _public_key - self._serial = _serial - self._type = _type - self._key_id = _key_id - self._valid_principals = _valid_principals - self._valid_for_all_principals = _valid_for_all_principals - self._valid_before = _valid_before - self._valid_after = _valid_after - self._critical_options = _critical_options - self._extensions = _extensions - - def public_key( - self, public_key: SSHCertPublicKeyTypes - ) -> SSHCertificateBuilder: - if not isinstance( - public_key, - ( - ec.EllipticCurvePublicKey, - rsa.RSAPublicKey, - ed25519.Ed25519PublicKey, - ), - ): - raise TypeError("Unsupported key type") - if self._public_key is not None: - raise ValueError("public_key already set") - - return SSHCertificateBuilder( - _public_key=public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def serial(self, serial: int) -> SSHCertificateBuilder: - if not isinstance(serial, int): - raise TypeError("serial must be an integer") - if not 0 <= serial < 2**64: - raise ValueError("serial must be between 0 and 2**64") - if self._serial is not None: - raise ValueError("serial already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def type(self, type: SSHCertificateType) -> SSHCertificateBuilder: - if not isinstance(type, SSHCertificateType): - raise TypeError("type must be an SSHCertificateType") - if self._type is not None: - raise ValueError("type already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def key_id(self, key_id: bytes) -> SSHCertificateBuilder: - if not isinstance(key_id, bytes): - raise TypeError("key_id must be bytes") - if self._key_id is not None: - raise ValueError("key_id already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_principals( - self, valid_principals: list[bytes] - ) -> SSHCertificateBuilder: - if self._valid_for_all_principals: - raise ValueError( - "Principals can't be set because the cert is valid " - "for all principals" - ) - if ( - not all(isinstance(x, bytes) for x in valid_principals) - or not valid_principals - ): - raise TypeError( - "principals must be a list of bytes and can't be empty" - ) - if self._valid_principals: - raise ValueError("valid_principals already set") - - if len(valid_principals) > _SSHKEY_CERT_MAX_PRINCIPALS: - raise ValueError( - "Reached or exceeded the maximum number of valid_principals" - ) - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_for_all_principals(self): - if self._valid_principals: - raise ValueError( - "valid_principals already set, can't set " - "valid_for_all_principals" - ) - if self._valid_for_all_principals: - raise ValueError("valid_for_all_principals already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=True, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_before(self, valid_before: int | float) -> SSHCertificateBuilder: - if not isinstance(valid_before, (int, float)): - raise TypeError("valid_before must be an int or float") - valid_before = int(valid_before) - if valid_before < 0 or valid_before >= 2**64: - raise ValueError("valid_before must [0, 2**64)") - if self._valid_before is not None: - raise ValueError("valid_before already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def valid_after(self, valid_after: int | float) -> SSHCertificateBuilder: - if not isinstance(valid_after, (int, float)): - raise TypeError("valid_after must be an int or float") - valid_after = int(valid_after) - if valid_after < 0 or valid_after >= 2**64: - raise ValueError("valid_after must [0, 2**64)") - if self._valid_after is not None: - raise ValueError("valid_after already set") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=valid_after, - _critical_options=self._critical_options, - _extensions=self._extensions, - ) - - def add_critical_option( - self, name: bytes, value: bytes - ) -> SSHCertificateBuilder: - if not isinstance(name, bytes) or not isinstance(value, bytes): - raise TypeError("name and value must be bytes") - # This is O(n**2) - if name in [name for name, _ in self._critical_options]: - raise ValueError("Duplicate critical option name") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=[*self._critical_options, (name, value)], - _extensions=self._extensions, - ) - - def add_extension( - self, name: bytes, value: bytes - ) -> SSHCertificateBuilder: - if not isinstance(name, bytes) or not isinstance(value, bytes): - raise TypeError("name and value must be bytes") - # This is O(n**2) - if name in [name for name, _ in self._extensions]: - raise ValueError("Duplicate extension name") - - return SSHCertificateBuilder( - _public_key=self._public_key, - _serial=self._serial, - _type=self._type, - _key_id=self._key_id, - _valid_principals=self._valid_principals, - _valid_for_all_principals=self._valid_for_all_principals, - _valid_before=self._valid_before, - _valid_after=self._valid_after, - _critical_options=self._critical_options, - _extensions=[*self._extensions, (name, value)], - ) - - def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate: - if not isinstance( - private_key, - ( - ec.EllipticCurvePrivateKey, - rsa.RSAPrivateKey, - ed25519.Ed25519PrivateKey, - ), - ): - raise TypeError("Unsupported private key type") - - if self._public_key is None: - raise ValueError("public_key must be set") - - # Not required - serial = 0 if self._serial is None else self._serial - - if self._type is None: - raise ValueError("type must be set") - - # Not required - key_id = b"" if self._key_id is None else self._key_id - - # A zero length list is valid, but means the certificate - # is valid for any principal of the specified type. We require - # the user to explicitly set valid_for_all_principals to get - # that behavior. - if not self._valid_principals and not self._valid_for_all_principals: - raise ValueError( - "valid_principals must be set if valid_for_all_principals " - "is False" - ) - - if self._valid_before is None: - raise ValueError("valid_before must be set") - - if self._valid_after is None: - raise ValueError("valid_after must be set") - - if self._valid_after > self._valid_before: - raise ValueError("valid_after must be earlier than valid_before") - - # lexically sort our byte strings - self._critical_options.sort(key=lambda x: x[0]) - self._extensions.sort(key=lambda x: x[0]) - - key_type = _get_ssh_key_type(self._public_key) - cert_prefix = key_type + _CERT_SUFFIX - - # Marshal the bytes to be signed - nonce = os.urandom(32) - kformat = _lookup_kformat(key_type) - f = _FragList() - f.put_sshstr(cert_prefix) - f.put_sshstr(nonce) - kformat.encode_public(self._public_key, f) - f.put_u64(serial) - f.put_u32(self._type.value) - f.put_sshstr(key_id) - fprincipals = _FragList() - for p in self._valid_principals: - fprincipals.put_sshstr(p) - f.put_sshstr(fprincipals.tobytes()) - f.put_u64(self._valid_after) - f.put_u64(self._valid_before) - fcrit = _FragList() - for name, value in self._critical_options: - fcrit.put_sshstr(name) - if len(value) > 0: - foptval = _FragList() - foptval.put_sshstr(value) - fcrit.put_sshstr(foptval.tobytes()) - else: - fcrit.put_sshstr(value) - f.put_sshstr(fcrit.tobytes()) - fext = _FragList() - for name, value in self._extensions: - fext.put_sshstr(name) - if len(value) > 0: - fextval = _FragList() - fextval.put_sshstr(value) - fext.put_sshstr(fextval.tobytes()) - else: - fext.put_sshstr(value) - f.put_sshstr(fext.tobytes()) - f.put_sshstr(b"") # RESERVED FIELD - # encode CA public key - ca_type = _get_ssh_key_type(private_key) - caformat = _lookup_kformat(ca_type) - caf = _FragList() - caf.put_sshstr(ca_type) - caformat.encode_public(private_key.public_key(), caf) - f.put_sshstr(caf.tobytes()) - # Sigs according to the rules defined for the CA's public key - # (RFC4253 section 6.6 for ssh-rsa, RFC5656 for ECDSA, - # and RFC8032 for Ed25519). - if isinstance(private_key, ed25519.Ed25519PrivateKey): - signature = private_key.sign(f.tobytes()) - fsig = _FragList() - fsig.put_sshstr(ca_type) - fsig.put_sshstr(signature) - f.put_sshstr(fsig.tobytes()) - elif isinstance(private_key, ec.EllipticCurvePrivateKey): - hash_alg = _get_ec_hash_alg(private_key.curve) - signature = private_key.sign(f.tobytes(), ec.ECDSA(hash_alg)) - r, s = asym_utils.decode_dss_signature(signature) - fsig = _FragList() - fsig.put_sshstr(ca_type) - fsigblob = _FragList() - fsigblob.put_mpint(r) - fsigblob.put_mpint(s) - fsig.put_sshstr(fsigblob.tobytes()) - f.put_sshstr(fsig.tobytes()) - - else: - assert isinstance(private_key, rsa.RSAPrivateKey) - # Just like Golang, we're going to use SHA512 for RSA - # https://cs.opensource.google/go/x/crypto/+/refs/tags/ - # v0.4.0:ssh/certs.go;l=445 - # RFC 8332 defines SHA256 and 512 as options - fsig = _FragList() - fsig.put_sshstr(_SSH_RSA_SHA512) - signature = private_key.sign( - f.tobytes(), padding.PKCS1v15(), hashes.SHA512() - ) - fsig.put_sshstr(signature) - f.put_sshstr(fsig.tobytes()) - - cert_data = binascii.b2a_base64(f.tobytes()).strip() - # load_ssh_public_identity returns a union, but this is - # guaranteed to be an SSHCertificate, so we cast to make - # mypy happy. - return typing.cast( - SSHCertificate, - load_ssh_public_identity(b"".join([cert_prefix, b" ", cert_data])), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py deleted file mode 100644 index c1af423..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - - -class InvalidToken(Exception): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py deleted file mode 100644 index 21fb000..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +++ /dev/null @@ -1,101 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import base64 -import typing -from urllib.parse import quote, urlencode - -from cryptography.hazmat.primitives import constant_time, hmac -from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 -from cryptography.hazmat.primitives.twofactor import InvalidToken -from cryptography.utils import Buffer - -HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512] - - -def _generate_uri( - hotp: HOTP, - type_name: str, - account_name: str, - issuer: str | None, - extra_parameters: list[tuple[str, int]], -) -> str: - parameters = [ - ("digits", hotp._length), - ("secret", base64.b32encode(hotp._key)), - ("algorithm", hotp._algorithm.name.upper()), - ] - - if issuer is not None: - parameters.append(("issuer", issuer)) - - parameters.extend(extra_parameters) - - label = ( - f"{quote(issuer)}:{quote(account_name)}" - if issuer - else quote(account_name) - ) - return f"otpauth://{type_name}/{label}?{urlencode(parameters)}" - - -class HOTP: - def __init__( - self, - key: Buffer, - length: int, - algorithm: HOTPHashTypes, - backend: typing.Any = None, - enforce_key_length: bool = True, - ) -> None: - if len(key) < 16 and enforce_key_length is True: - raise ValueError("Key length has to be at least 128 bits.") - - if not isinstance(length, int): - raise TypeError("Length parameter must be an integer type.") - - if length < 6 or length > 8: - raise ValueError("Length of HOTP has to be between 6 and 8.") - - if not isinstance(algorithm, (SHA1, SHA256, SHA512)): - raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.") - - self._key = key - self._length = length - self._algorithm = algorithm - - def generate(self, counter: int) -> bytes: - if not isinstance(counter, int): - raise TypeError("Counter parameter must be an integer type.") - - truncated_value = self._dynamic_truncate(counter) - hotp = truncated_value % (10**self._length) - return "{0:0{1}}".format(hotp, self._length).encode() - - def verify(self, hotp: bytes, counter: int) -> None: - if not constant_time.bytes_eq(self.generate(counter), hotp): - raise InvalidToken("Supplied HOTP value does not match.") - - def _dynamic_truncate(self, counter: int) -> int: - ctx = hmac.HMAC(self._key, self._algorithm) - - try: - ctx.update(counter.to_bytes(length=8, byteorder="big")) - except OverflowError: - raise ValueError(f"Counter must be between 0 and {2**64 - 1}.") - - hmac_value = ctx.finalize() - - offset = hmac_value[len(hmac_value) - 1] & 0b1111 - p = hmac_value[offset : offset + 4] - return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF - - def get_provisioning_uri( - self, account_name: str, counter: int, issuer: str | None - ) -> str: - return _generate_uri( - self, "hotp", account_name, issuer, [("counter", int(counter))] - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py b/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py deleted file mode 100644 index 10c725c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.primitives import constant_time -from cryptography.hazmat.primitives.twofactor import InvalidToken -from cryptography.hazmat.primitives.twofactor.hotp import ( - HOTP, - HOTPHashTypes, - _generate_uri, -) -from cryptography.utils import Buffer - - -class TOTP: - def __init__( - self, - key: Buffer, - length: int, - algorithm: HOTPHashTypes, - time_step: int, - backend: typing.Any = None, - enforce_key_length: bool = True, - ): - self._time_step = time_step - self._hotp = HOTP( - key, length, algorithm, enforce_key_length=enforce_key_length - ) - - def generate(self, time: int | float) -> bytes: - if not isinstance(time, (int, float)): - raise TypeError( - "Time parameter must be an integer type or float type." - ) - - counter = int(time / self._time_step) - return self._hotp.generate(counter) - - def verify(self, totp: bytes, time: int) -> None: - if not constant_time.bytes_eq(self.generate(time), totp): - raise InvalidToken("Supplied TOTP value does not match.") - - def get_provisioning_uri( - self, account_name: str, issuer: str | None - ) -> str: - return _generate_uri( - self._hotp, - "totp", - account_name, - issuer, - [("period", int(self._time_step))], - ) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/py.typed b/backend/venv39/lib/python3.9/site-packages/cryptography/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/utils.py b/backend/venv39/lib/python3.9/site-packages/cryptography/utils.py deleted file mode 100644 index a0fc3b1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/utils.py +++ /dev/null @@ -1,137 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import enum -import sys -import types -import typing -import warnings -from collections.abc import Callable, Sequence - - -# We use a UserWarning subclass, instead of DeprecationWarning, because CPython -# decided deprecation warnings should be invisible by default. -class CryptographyDeprecationWarning(UserWarning): - pass - - -# Several APIs were deprecated with no specific end-of-life date because of the -# ubiquity of their use. They should not be removed until we agree on when that -# cycle ends. -DeprecatedIn36 = CryptographyDeprecationWarning -DeprecatedIn40 = CryptographyDeprecationWarning -DeprecatedIn41 = CryptographyDeprecationWarning -DeprecatedIn42 = CryptographyDeprecationWarning -DeprecatedIn43 = CryptographyDeprecationWarning - - -# If you're wondering why we don't use `Buffer`, it's because `Buffer` would -# be more accurately named: Bufferable. It means something which has an -# `__buffer__`. Which means you can't actually treat the result as a buffer -# (and do things like take a `len()`). -if sys.version_info >= (3, 9): - Buffer = typing.Union[bytes, bytearray, memoryview] -else: - Buffer = typing.ByteString - - -def _check_bytes(name: str, value: bytes) -> None: - if not isinstance(value, bytes): - raise TypeError(f"{name} must be bytes") - - -def _check_byteslike(name: str, value: Buffer) -> None: - try: - memoryview(value) - except TypeError: - raise TypeError(f"{name} must be bytes-like") - - -def int_to_bytes(integer: int, length: int | None = None) -> bytes: - if length == 0: - raise ValueError("length argument can't be 0") - return integer.to_bytes( - length or (integer.bit_length() + 7) // 8 or 1, "big" - ) - - -class InterfaceNotImplemented(Exception): - pass - - -class _DeprecatedValue: - def __init__(self, value: object, message: str, warning_class): - self.value = value - self.message = message - self.warning_class = warning_class - - -class _ModuleWithDeprecations(types.ModuleType): - def __init__(self, module: types.ModuleType): - super().__init__(module.__name__) - self.__dict__["_module"] = module - - def __getattr__(self, attr: str) -> object: - obj = getattr(self._module, attr) - if isinstance(obj, _DeprecatedValue): - warnings.warn(obj.message, obj.warning_class, stacklevel=2) - obj = obj.value - return obj - - def __setattr__(self, attr: str, value: object) -> None: - setattr(self._module, attr, value) - - def __delattr__(self, attr: str) -> None: - obj = getattr(self._module, attr) - if isinstance(obj, _DeprecatedValue): - warnings.warn(obj.message, obj.warning_class, stacklevel=2) - - delattr(self._module, attr) - - def __dir__(self) -> Sequence[str]: - return ["_module", *dir(self._module)] - - -def deprecated( - value: object, - module_name: str, - message: str, - warning_class: type[Warning], - name: str | None = None, -) -> _DeprecatedValue: - module = sys.modules[module_name] - if not isinstance(module, _ModuleWithDeprecations): - sys.modules[module_name] = module = _ModuleWithDeprecations(module) - dv = _DeprecatedValue(value, message, warning_class) - # Maintain backwards compatibility with `name is None` for pyOpenSSL. - if name is not None: - setattr(module, name, dv) - return dv - - -def cached_property(func: Callable) -> property: - cached_name = f"_cached_{func}" - sentinel = object() - - def inner(instance: object): - cache = getattr(instance, cached_name, sentinel) - if cache is not sentinel: - return cache - result = func(instance) - setattr(instance, cached_name, result) - return result - - return property(inner) - - -# Python 3.10 changed representation of enums. We use well-defined object -# representation and string representation from Python 3.9. -class Enum(enum.Enum): - def __repr__(self) -> str: - return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" - - def __str__(self) -> str: - return f"{self.__class__.__name__}.{self._name_}" diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/__init__.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/__init__.py deleted file mode 100644 index 318eecc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/__init__.py +++ /dev/null @@ -1,270 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.x509 import certificate_transparency, verification -from cryptography.x509.base import ( - Attribute, - AttributeNotFound, - Attributes, - Certificate, - CertificateBuilder, - CertificateRevocationList, - CertificateRevocationListBuilder, - CertificateSigningRequest, - CertificateSigningRequestBuilder, - InvalidVersion, - RevokedCertificate, - RevokedCertificateBuilder, - Version, - load_der_x509_certificate, - load_der_x509_crl, - load_der_x509_csr, - load_pem_x509_certificate, - load_pem_x509_certificates, - load_pem_x509_crl, - load_pem_x509_csr, - random_serial_number, -) -from cryptography.x509.extensions import ( - AccessDescription, - Admission, - Admissions, - AuthorityInformationAccess, - AuthorityKeyIdentifier, - BasicConstraints, - CertificateIssuer, - CertificatePolicies, - CRLDistributionPoints, - CRLNumber, - CRLReason, - DeltaCRLIndicator, - DistributionPoint, - DuplicateExtension, - ExtendedKeyUsage, - Extension, - ExtensionNotFound, - Extensions, - ExtensionType, - FreshestCRL, - GeneralNames, - InhibitAnyPolicy, - InvalidityDate, - IssuerAlternativeName, - IssuingDistributionPoint, - KeyUsage, - MSCertificateTemplate, - NameConstraints, - NamingAuthority, - NoticeReference, - OCSPAcceptableResponses, - OCSPNoCheck, - OCSPNonce, - PolicyConstraints, - PolicyInformation, - PrecertificateSignedCertificateTimestamps, - PrecertPoison, - PrivateKeyUsagePeriod, - ProfessionInfo, - ReasonFlags, - SignedCertificateTimestamps, - SubjectAlternativeName, - SubjectInformationAccess, - SubjectKeyIdentifier, - TLSFeature, - TLSFeatureType, - UnrecognizedExtension, - UserNotice, -) -from cryptography.x509.general_name import ( - DirectoryName, - DNSName, - GeneralName, - IPAddress, - OtherName, - RegisteredID, - RFC822Name, - UniformResourceIdentifier, - UnsupportedGeneralNameType, -) -from cryptography.x509.name import ( - Name, - NameAttribute, - RelativeDistinguishedName, -) -from cryptography.x509.oid import ( - AuthorityInformationAccessOID, - CertificatePoliciesOID, - CRLEntryExtensionOID, - ExtendedKeyUsageOID, - ExtensionOID, - NameOID, - ObjectIdentifier, - PublicKeyAlgorithmOID, - SignatureAlgorithmOID, -) - -OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS -OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER -OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS -OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES -OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS -OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE -OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL -OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY -OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME -OID_KEY_USAGE = ExtensionOID.KEY_USAGE -OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD -OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS -OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK -OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS -OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS -OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME -OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES -OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS -OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER - -OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1 -OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224 -OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256 -OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1 -OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224 -OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256 -OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384 -OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512 -OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5 -OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1 -OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224 -OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 -OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 -OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 -OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS - -OID_COMMON_NAME = NameOID.COMMON_NAME -OID_COUNTRY_NAME = NameOID.COUNTRY_NAME -OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT -OID_DN_QUALIFIER = NameOID.DN_QUALIFIER -OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS -OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER -OID_GIVEN_NAME = NameOID.GIVEN_NAME -OID_LOCALITY_NAME = NameOID.LOCALITY_NAME -OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME -OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME -OID_PSEUDONYM = NameOID.PSEUDONYM -OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER -OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME -OID_SURNAME = NameOID.SURNAME -OID_TITLE = NameOID.TITLE - -OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH -OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING -OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION -OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING -OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH -OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING - -OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY -OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER -OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE - -OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER -OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON -OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE - -OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS -OID_OCSP = AuthorityInformationAccessOID.OCSP - -__all__ = [ - "OID_CA_ISSUERS", - "OID_OCSP", - "AccessDescription", - "Admission", - "Admissions", - "Attribute", - "AttributeNotFound", - "Attributes", - "AuthorityInformationAccess", - "AuthorityKeyIdentifier", - "BasicConstraints", - "CRLDistributionPoints", - "CRLNumber", - "CRLReason", - "Certificate", - "CertificateBuilder", - "CertificateIssuer", - "CertificatePolicies", - "CertificateRevocationList", - "CertificateRevocationListBuilder", - "CertificateSigningRequest", - "CertificateSigningRequestBuilder", - "DNSName", - "DeltaCRLIndicator", - "DirectoryName", - "DistributionPoint", - "DuplicateExtension", - "ExtendedKeyUsage", - "Extension", - "ExtensionNotFound", - "ExtensionType", - "Extensions", - "FreshestCRL", - "GeneralName", - "GeneralNames", - "IPAddress", - "InhibitAnyPolicy", - "InvalidVersion", - "InvalidityDate", - "IssuerAlternativeName", - "IssuingDistributionPoint", - "KeyUsage", - "MSCertificateTemplate", - "Name", - "NameAttribute", - "NameConstraints", - "NameOID", - "NamingAuthority", - "NoticeReference", - "OCSPAcceptableResponses", - "OCSPNoCheck", - "OCSPNonce", - "ObjectIdentifier", - "OtherName", - "PolicyConstraints", - "PolicyInformation", - "PrecertPoison", - "PrecertificateSignedCertificateTimestamps", - "PrivateKeyUsagePeriod", - "ProfessionInfo", - "PublicKeyAlgorithmOID", - "RFC822Name", - "ReasonFlags", - "RegisteredID", - "RelativeDistinguishedName", - "RevokedCertificate", - "RevokedCertificateBuilder", - "SignatureAlgorithmOID", - "SignedCertificateTimestamps", - "SubjectAlternativeName", - "SubjectInformationAccess", - "SubjectKeyIdentifier", - "TLSFeature", - "TLSFeatureType", - "UniformResourceIdentifier", - "UnrecognizedExtension", - "UnsupportedGeneralNameType", - "UserNotice", - "Version", - "certificate_transparency", - "load_der_x509_certificate", - "load_der_x509_crl", - "load_der_x509_csr", - "load_pem_x509_certificate", - "load_pem_x509_certificates", - "load_pem_x509_crl", - "load_pem_x509_csr", - "random_serial_number", - "verification", - "verification", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/base.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/base.py deleted file mode 100644 index 1be612b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/base.py +++ /dev/null @@ -1,848 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import datetime -import os -import typing -import warnings -from collections.abc import Iterable - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ( - dsa, - ec, - ed448, - ed25519, - padding, - rsa, - x448, - x25519, -) -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPrivateKeyTypes, - CertificatePublicKeyTypes, -) -from cryptography.x509.extensions import ( - Extension, - Extensions, - ExtensionType, - _make_sequence_methods, -) -from cryptography.x509.name import Name, _ASN1Type -from cryptography.x509.oid import ObjectIdentifier - -_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) - -# This must be kept in sync with sign.rs's list of allowable types in -# identify_hash_type -_AllowedHashTypes = typing.Union[ - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, - hashes.SHA3_224, - hashes.SHA3_256, - hashes.SHA3_384, - hashes.SHA3_512, -] - - -class AttributeNotFound(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -def _reject_duplicate_extension( - extension: Extension[ExtensionType], - extensions: list[Extension[ExtensionType]], -) -> None: - # This is quadratic in the number of extensions - for e in extensions: - if e.oid == extension.oid: - raise ValueError("This extension has already been set.") - - -def _reject_duplicate_attribute( - oid: ObjectIdentifier, - attributes: list[tuple[ObjectIdentifier, bytes, int | None]], -) -> None: - # This is quadratic in the number of attributes - for attr_oid, _, _ in attributes: - if attr_oid == oid: - raise ValueError("This attribute has already been set.") - - -def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: - """Normalizes a datetime to a naive datetime in UTC. - - time -- datetime to normalize. Assumed to be in UTC if not timezone - aware. - """ - if time.tzinfo is not None: - offset = time.utcoffset() - offset = offset if offset else datetime.timedelta() - return time.replace(tzinfo=None) - offset - else: - return time - - -class Attribute: - def __init__( - self, - oid: ObjectIdentifier, - value: bytes, - _type: int = _ASN1Type.UTF8String.value, - ) -> None: - self._oid = oid - self._value = value - self._type = _type - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Attribute): - return NotImplemented - - return ( - self.oid == other.oid - and self.value == other.value - and self._type == other._type - ) - - def __hash__(self) -> int: - return hash((self.oid, self.value, self._type)) - - -class Attributes: - def __init__( - self, - attributes: Iterable[Attribute], - ) -> None: - self._attributes = list(attributes) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes") - - def __repr__(self) -> str: - return f"" - - def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute: - for attr in self: - if attr.oid == oid: - return attr - - raise AttributeNotFound(f"No {oid} attribute was found", oid) - - -class Version(utils.Enum): - v1 = 0 - v3 = 2 - - -class InvalidVersion(Exception): - def __init__(self, msg: str, parsed_version: int) -> None: - super().__init__(msg) - self.parsed_version = parsed_version - - -Certificate = rust_x509.Certificate - - -class RevokedCertificate(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def serial_number(self) -> int: - """ - Returns the serial number of the revoked certificate. - """ - - @property - @abc.abstractmethod - def revocation_date(self) -> datetime.datetime: - """ - Returns the date of when this certificate was revoked. - """ - - @property - @abc.abstractmethod - def revocation_date_utc(self) -> datetime.datetime: - """ - Returns the date of when this certificate was revoked as a non-naive - UTC datetime. - """ - - @property - @abc.abstractmethod - def extensions(self) -> Extensions: - """ - Returns an Extensions object containing a list of Revoked extensions. - """ - - -# Runtime isinstance checks need this since the rust class is not a subclass. -RevokedCertificate.register(rust_x509.RevokedCertificate) - - -class _RawRevokedCertificate(RevokedCertificate): - def __init__( - self, - serial_number: int, - revocation_date: datetime.datetime, - extensions: Extensions, - ): - self._serial_number = serial_number - self._revocation_date = revocation_date - self._extensions = extensions - - @property - def serial_number(self) -> int: - return self._serial_number - - @property - def revocation_date(self) -> datetime.datetime: - warnings.warn( - "Properties that return a naïve datetime object have been " - "deprecated. Please switch to revocation_date_utc.", - utils.DeprecatedIn42, - stacklevel=2, - ) - return self._revocation_date - - @property - def revocation_date_utc(self) -> datetime.datetime: - return self._revocation_date.replace(tzinfo=datetime.timezone.utc) - - @property - def extensions(self) -> Extensions: - return self._extensions - - -CertificateRevocationList = rust_x509.CertificateRevocationList -CertificateSigningRequest = rust_x509.CertificateSigningRequest - - -load_pem_x509_certificate = rust_x509.load_pem_x509_certificate -load_der_x509_certificate = rust_x509.load_der_x509_certificate - -load_pem_x509_certificates = rust_x509.load_pem_x509_certificates - -load_pem_x509_csr = rust_x509.load_pem_x509_csr -load_der_x509_csr = rust_x509.load_der_x509_csr - -load_pem_x509_crl = rust_x509.load_pem_x509_crl -load_der_x509_crl = rust_x509.load_der_x509_crl - - -class CertificateSigningRequestBuilder: - def __init__( - self, - subject_name: Name | None = None, - extensions: list[Extension[ExtensionType]] = [], - attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [], - ): - """ - Creates an empty X.509 certificate request (v1). - """ - self._subject_name = subject_name - self._extensions = extensions - self._attributes = attributes - - def subject_name(self, name: Name) -> CertificateSigningRequestBuilder: - """ - Sets the certificate requestor's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._subject_name is not None: - raise ValueError("The subject name may only be set once.") - return CertificateSigningRequestBuilder( - name, self._extensions, self._attributes - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateSigningRequestBuilder: - """ - Adds an X.509 extension to the certificate request. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return CertificateSigningRequestBuilder( - self._subject_name, - [*self._extensions, extension], - self._attributes, - ) - - def add_attribute( - self, - oid: ObjectIdentifier, - value: bytes, - *, - _tag: _ASN1Type | None = None, - ) -> CertificateSigningRequestBuilder: - """ - Adds an X.509 attribute with an OID and associated value. - """ - if not isinstance(oid, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - - if not isinstance(value, bytes): - raise TypeError("value must be bytes") - - if _tag is not None and not isinstance(_tag, _ASN1Type): - raise TypeError("tag must be _ASN1Type") - - _reject_duplicate_attribute(oid, self._attributes) - - if _tag is not None: - tag = _tag.value - else: - tag = None - - return CertificateSigningRequestBuilder( - self._subject_name, - self._extensions, - [*self._attributes, (oid, value, tag)], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> CertificateSigningRequest: - """ - Signs the request using the requestor's private key. - """ - if self._subject_name is None: - raise ValueError("A CertificateSigningRequest must have a subject") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_csr( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class CertificateBuilder: - _extensions: list[Extension[ExtensionType]] - - def __init__( - self, - issuer_name: Name | None = None, - subject_name: Name | None = None, - public_key: CertificatePublicKeyTypes | None = None, - serial_number: int | None = None, - not_valid_before: datetime.datetime | None = None, - not_valid_after: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - ) -> None: - self._version = Version.v3 - self._issuer_name = issuer_name - self._subject_name = subject_name - self._public_key = public_key - self._serial_number = serial_number - self._not_valid_before = not_valid_before - self._not_valid_after = not_valid_after - self._extensions = extensions - - def issuer_name(self, name: Name) -> CertificateBuilder: - """ - Sets the CA's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._issuer_name is not None: - raise ValueError("The issuer name may only be set once.") - return CertificateBuilder( - name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def subject_name(self, name: Name) -> CertificateBuilder: - """ - Sets the requestor's distinguished name. - """ - if not isinstance(name, Name): - raise TypeError("Expecting x509.Name object.") - if self._subject_name is not None: - raise ValueError("The subject name may only be set once.") - return CertificateBuilder( - self._issuer_name, - name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def public_key( - self, - key: CertificatePublicKeyTypes, - ) -> CertificateBuilder: - """ - Sets the requestor's public key (as found in the signing request). - """ - if not isinstance( - key, - ( - dsa.DSAPublicKey, - rsa.RSAPublicKey, - ec.EllipticCurvePublicKey, - ed25519.Ed25519PublicKey, - ed448.Ed448PublicKey, - x25519.X25519PublicKey, - x448.X448PublicKey, - ), - ): - raise TypeError( - "Expecting one of DSAPublicKey, RSAPublicKey," - " EllipticCurvePublicKey, Ed25519PublicKey," - " Ed448PublicKey, X25519PublicKey, or " - "X448PublicKey." - ) - if self._public_key is not None: - raise ValueError("The public key may only be set once.") - return CertificateBuilder( - self._issuer_name, - self._subject_name, - key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def serial_number(self, number: int) -> CertificateBuilder: - """ - Sets the certificate serial number. - """ - if not isinstance(number, int): - raise TypeError("Serial number must be of integral type.") - if self._serial_number is not None: - raise ValueError("The serial number may only be set once.") - if number <= 0: - raise ValueError("The serial number should be positive.") - - # ASN.1 integers are always signed, so most significant bit must be - # zero. - if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError( - "The serial number should not be more than 159 bits." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - number, - self._not_valid_before, - self._not_valid_after, - self._extensions, - ) - - def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder: - """ - Sets the certificate activation time. - """ - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._not_valid_before is not None: - raise ValueError("The not valid before may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The not valid before date must be on or after" - " 1950 January 1)." - ) - if self._not_valid_after is not None and time > self._not_valid_after: - raise ValueError( - "The not valid before date must be before the not valid after " - "date." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - time, - self._not_valid_after, - self._extensions, - ) - - def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder: - """ - Sets the certificate expiration time. - """ - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._not_valid_after is not None: - raise ValueError("The not valid after may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The not valid after date must be on or after 1950 January 1." - ) - if ( - self._not_valid_before is not None - and time < self._not_valid_before - ): - raise ValueError( - "The not valid after date must be after the not valid before " - "date." - ) - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - time, - self._extensions, - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateBuilder: - """ - Adds an X.509 extension to the certificate. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return CertificateBuilder( - self._issuer_name, - self._subject_name, - self._public_key, - self._serial_number, - self._not_valid_before, - self._not_valid_after, - [*self._extensions, extension], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> Certificate: - """ - Signs the certificate using the CA's private key. - """ - if self._subject_name is None: - raise ValueError("A certificate must have a subject name") - - if self._issuer_name is None: - raise ValueError("A certificate must have an issuer name") - - if self._serial_number is None: - raise ValueError("A certificate must have a serial number") - - if self._not_valid_before is None: - raise ValueError("A certificate must have a not valid before time") - - if self._not_valid_after is None: - raise ValueError("A certificate must have a not valid after time") - - if self._public_key is None: - raise ValueError("A certificate must have a public key") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_certificate( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class CertificateRevocationListBuilder: - _extensions: list[Extension[ExtensionType]] - _revoked_certificates: list[RevokedCertificate] - - def __init__( - self, - issuer_name: Name | None = None, - last_update: datetime.datetime | None = None, - next_update: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - revoked_certificates: list[RevokedCertificate] = [], - ): - self._issuer_name = issuer_name - self._last_update = last_update - self._next_update = next_update - self._extensions = extensions - self._revoked_certificates = revoked_certificates - - def issuer_name( - self, issuer_name: Name - ) -> CertificateRevocationListBuilder: - if not isinstance(issuer_name, Name): - raise TypeError("Expecting x509.Name object.") - if self._issuer_name is not None: - raise ValueError("The issuer name may only be set once.") - return CertificateRevocationListBuilder( - issuer_name, - self._last_update, - self._next_update, - self._extensions, - self._revoked_certificates, - ) - - def last_update( - self, last_update: datetime.datetime - ) -> CertificateRevocationListBuilder: - if not isinstance(last_update, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._last_update is not None: - raise ValueError("Last update may only be set once.") - last_update = _convert_to_naive_utc_time(last_update) - if last_update < _EARLIEST_UTC_TIME: - raise ValueError( - "The last update date must be on or after 1950 January 1." - ) - if self._next_update is not None and last_update > self._next_update: - raise ValueError( - "The last update date must be before the next update date." - ) - return CertificateRevocationListBuilder( - self._issuer_name, - last_update, - self._next_update, - self._extensions, - self._revoked_certificates, - ) - - def next_update( - self, next_update: datetime.datetime - ) -> CertificateRevocationListBuilder: - if not isinstance(next_update, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._next_update is not None: - raise ValueError("Last update may only be set once.") - next_update = _convert_to_naive_utc_time(next_update) - if next_update < _EARLIEST_UTC_TIME: - raise ValueError( - "The last update date must be on or after 1950 January 1." - ) - if self._last_update is not None and next_update < self._last_update: - raise ValueError( - "The next update date must be after the last update date." - ) - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - next_update, - self._extensions, - self._revoked_certificates, - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> CertificateRevocationListBuilder: - """ - Adds an X.509 extension to the certificate revocation list. - """ - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - self._next_update, - [*self._extensions, extension], - self._revoked_certificates, - ) - - def add_revoked_certificate( - self, revoked_certificate: RevokedCertificate - ) -> CertificateRevocationListBuilder: - """ - Adds a revoked certificate to the CRL. - """ - if not isinstance(revoked_certificate, RevokedCertificate): - raise TypeError("Must be an instance of RevokedCertificate") - - return CertificateRevocationListBuilder( - self._issuer_name, - self._last_update, - self._next_update, - self._extensions, - [*self._revoked_certificates, revoked_certificate], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: _AllowedHashTypes | None, - backend: typing.Any = None, - *, - rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, - ecdsa_deterministic: bool | None = None, - ) -> CertificateRevocationList: - if self._issuer_name is None: - raise ValueError("A CRL must have an issuer name") - - if self._last_update is None: - raise ValueError("A CRL must have a last update time") - - if self._next_update is None: - raise ValueError("A CRL must have a next update time") - - if rsa_padding is not None: - if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): - raise TypeError("Padding must be PSS or PKCS1v15") - if not isinstance(private_key, rsa.RSAPrivateKey): - raise TypeError("Padding is only supported for RSA keys") - - if ecdsa_deterministic is not None: - if not isinstance(private_key, ec.EllipticCurvePrivateKey): - raise TypeError( - "Deterministic ECDSA is only supported for EC keys" - ) - - return rust_x509.create_x509_crl( - self, - private_key, - algorithm, - rsa_padding, - ecdsa_deterministic, - ) - - -class RevokedCertificateBuilder: - def __init__( - self, - serial_number: int | None = None, - revocation_date: datetime.datetime | None = None, - extensions: list[Extension[ExtensionType]] = [], - ): - self._serial_number = serial_number - self._revocation_date = revocation_date - self._extensions = extensions - - def serial_number(self, number: int) -> RevokedCertificateBuilder: - if not isinstance(number, int): - raise TypeError("Serial number must be of integral type.") - if self._serial_number is not None: - raise ValueError("The serial number may only be set once.") - if number <= 0: - raise ValueError("The serial number should be positive") - - # ASN.1 integers are always signed, so most significant bit must be - # zero. - if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError( - "The serial number should not be more than 159 bits." - ) - return RevokedCertificateBuilder( - number, self._revocation_date, self._extensions - ) - - def revocation_date( - self, time: datetime.datetime - ) -> RevokedCertificateBuilder: - if not isinstance(time, datetime.datetime): - raise TypeError("Expecting datetime object.") - if self._revocation_date is not None: - raise ValueError("The revocation date may only be set once.") - time = _convert_to_naive_utc_time(time) - if time < _EARLIEST_UTC_TIME: - raise ValueError( - "The revocation date must be on or after 1950 January 1." - ) - return RevokedCertificateBuilder( - self._serial_number, time, self._extensions - ) - - def add_extension( - self, extval: ExtensionType, critical: bool - ) -> RevokedCertificateBuilder: - if not isinstance(extval, ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - return RevokedCertificateBuilder( - self._serial_number, - self._revocation_date, - [*self._extensions, extension], - ) - - def build(self, backend: typing.Any = None) -> RevokedCertificate: - if self._serial_number is None: - raise ValueError("A revoked certificate must have a serial number") - if self._revocation_date is None: - raise ValueError( - "A revoked certificate must have a revocation date" - ) - return _RawRevokedCertificate( - self._serial_number, - self._revocation_date, - Extensions(self._extensions), - ) - - -def random_serial_number() -> int: - return int.from_bytes(os.urandom(20), "big") >> 1 diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py deleted file mode 100644 index fb66cc6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py +++ /dev/null @@ -1,35 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 - - -class LogEntryType(utils.Enum): - X509_CERTIFICATE = 0 - PRE_CERTIFICATE = 1 - - -class Version(utils.Enum): - v1 = 0 - - -class SignatureAlgorithm(utils.Enum): - """ - Signature algorithms that are valid for SCTs. - - These are exactly the same as SignatureAlgorithm in RFC 5246 (TLS 1.2). - - See: - """ - - ANONYMOUS = 0 - RSA = 1 - DSA = 2 - ECDSA = 3 - - -SignedCertificateTimestamp = rust_x509.Sct diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/extensions.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/extensions.py deleted file mode 100644 index dfa472d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/extensions.py +++ /dev/null @@ -1,2528 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import datetime -import hashlib -import ipaddress -import typing -from collections.abc import Iterable, Iterator - -from cryptography import utils -from cryptography.hazmat.bindings._rust import asn1 -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.hazmat.primitives import constant_time, serialization -from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPublicKeyTypes, - CertificatePublicKeyTypes, -) -from cryptography.x509.certificate_transparency import ( - SignedCertificateTimestamp, -) -from cryptography.x509.general_name import ( - DirectoryName, - DNSName, - GeneralName, - IPAddress, - OtherName, - RegisteredID, - RFC822Name, - UniformResourceIdentifier, - _IPAddressTypes, -) -from cryptography.x509.name import Name, RelativeDistinguishedName -from cryptography.x509.oid import ( - CRLEntryExtensionOID, - ExtensionOID, - ObjectIdentifier, - OCSPExtensionOID, -) - -ExtensionTypeVar = typing.TypeVar( - "ExtensionTypeVar", bound="ExtensionType", covariant=True -) - - -def _key_identifier_from_public_key( - public_key: CertificatePublicKeyTypes, -) -> bytes: - if isinstance(public_key, RSAPublicKey): - data = public_key.public_bytes( - serialization.Encoding.DER, - serialization.PublicFormat.PKCS1, - ) - elif isinstance(public_key, EllipticCurvePublicKey): - data = public_key.public_bytes( - serialization.Encoding.X962, - serialization.PublicFormat.UncompressedPoint, - ) - else: - # This is a very slow way to do this. - serialized = public_key.public_bytes( - serialization.Encoding.DER, - serialization.PublicFormat.SubjectPublicKeyInfo, - ) - data = asn1.parse_spki_for_data(serialized) - - return hashlib.sha1(data).digest() - - -def _make_sequence_methods(field_name: str): - def len_method(self) -> int: - return len(getattr(self, field_name)) - - def iter_method(self): - return iter(getattr(self, field_name)) - - def getitem_method(self, idx): - return getattr(self, field_name)[idx] - - return len_method, iter_method, getitem_method - - -class DuplicateExtension(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -class ExtensionNotFound(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier) -> None: - super().__init__(msg) - self.oid = oid - - -class ExtensionType(metaclass=abc.ABCMeta): - oid: typing.ClassVar[ObjectIdentifier] - - def public_bytes(self) -> bytes: - """ - Serializes the extension type to DER. - """ - raise NotImplementedError( - f"public_bytes is not implemented for extension type {self!r}" - ) - - -class Extensions: - def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None: - self._extensions = list(extensions) - - def get_extension_for_oid( - self, oid: ObjectIdentifier - ) -> Extension[ExtensionType]: - for ext in self: - if ext.oid == oid: - return ext - - raise ExtensionNotFound(f"No {oid} extension was found", oid) - - def get_extension_for_class( - self, extclass: type[ExtensionTypeVar] - ) -> Extension[ExtensionTypeVar]: - if extclass is UnrecognizedExtension: - raise TypeError( - "UnrecognizedExtension can't be used with " - "get_extension_for_class because more than one instance of the" - " class may be present." - ) - - for ext in self: - if isinstance(ext.value, extclass): - return ext - - raise ExtensionNotFound( - f"No {extclass} extension was found", extclass.oid - ) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") - - def __repr__(self) -> str: - return f"" - - -class CRLNumber(ExtensionType): - oid = ExtensionOID.CRL_NUMBER - - def __init__(self, crl_number: int) -> None: - if not isinstance(crl_number, int): - raise TypeError("crl_number must be an integer") - - self._crl_number = crl_number - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLNumber): - return NotImplemented - - return self.crl_number == other.crl_number - - def __hash__(self) -> int: - return hash(self.crl_number) - - def __repr__(self) -> str: - return f"" - - @property - def crl_number(self) -> int: - return self._crl_number - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AuthorityKeyIdentifier(ExtensionType): - oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER - - def __init__( - self, - key_identifier: bytes | None, - authority_cert_issuer: Iterable[GeneralName] | None, - authority_cert_serial_number: int | None, - ) -> None: - if (authority_cert_issuer is None) != ( - authority_cert_serial_number is None - ): - raise ValueError( - "authority_cert_issuer and authority_cert_serial_number " - "must both be present or both None" - ) - - if authority_cert_issuer is not None: - authority_cert_issuer = list(authority_cert_issuer) - if not all( - isinstance(x, GeneralName) for x in authority_cert_issuer - ): - raise TypeError( - "authority_cert_issuer must be a list of GeneralName " - "objects" - ) - - if authority_cert_serial_number is not None and not isinstance( - authority_cert_serial_number, int - ): - raise TypeError("authority_cert_serial_number must be an integer") - - self._key_identifier = key_identifier - self._authority_cert_issuer = authority_cert_issuer - self._authority_cert_serial_number = authority_cert_serial_number - - # This takes a subset of CertificatePublicKeyTypes because an issuer - # cannot have an X25519/X448 key. This introduces some unfortunate - # asymmetry that requires typing users to explicitly - # narrow their type, but we should make this accurate and not just - # convenient. - @classmethod - def from_issuer_public_key( - cls, public_key: CertificateIssuerPublicKeyTypes - ) -> AuthorityKeyIdentifier: - digest = _key_identifier_from_public_key(public_key) - return cls( - key_identifier=digest, - authority_cert_issuer=None, - authority_cert_serial_number=None, - ) - - @classmethod - def from_issuer_subject_key_identifier( - cls, ski: SubjectKeyIdentifier - ) -> AuthorityKeyIdentifier: - return cls( - key_identifier=ski.digest, - authority_cert_issuer=None, - authority_cert_serial_number=None, - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AuthorityKeyIdentifier): - return NotImplemented - - return ( - self.key_identifier == other.key_identifier - and self.authority_cert_issuer == other.authority_cert_issuer - and self.authority_cert_serial_number - == other.authority_cert_serial_number - ) - - def __hash__(self) -> int: - if self.authority_cert_issuer is None: - aci = None - else: - aci = tuple(self.authority_cert_issuer) - return hash( - (self.key_identifier, aci, self.authority_cert_serial_number) - ) - - @property - def key_identifier(self) -> bytes | None: - return self._key_identifier - - @property - def authority_cert_issuer( - self, - ) -> list[GeneralName] | None: - return self._authority_cert_issuer - - @property - def authority_cert_serial_number(self) -> int | None: - return self._authority_cert_serial_number - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SubjectKeyIdentifier(ExtensionType): - oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER - - def __init__(self, digest: bytes) -> None: - self._digest = digest - - @classmethod - def from_public_key( - cls, public_key: CertificatePublicKeyTypes - ) -> SubjectKeyIdentifier: - return cls(_key_identifier_from_public_key(public_key)) - - @property - def digest(self) -> bytes: - return self._digest - - @property - def key_identifier(self) -> bytes: - return self._digest - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectKeyIdentifier): - return NotImplemented - - return constant_time.bytes_eq(self.digest, other.digest) - - def __hash__(self) -> int: - return hash(self.digest) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AuthorityInformationAccess(ExtensionType): - oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS - - def __init__(self, descriptions: Iterable[AccessDescription]) -> None: - descriptions = list(descriptions) - if not all(isinstance(x, AccessDescription) for x in descriptions): - raise TypeError( - "Every item in the descriptions list must be an " - "AccessDescription" - ) - - self._descriptions = descriptions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AuthorityInformationAccess): - return NotImplemented - - return self._descriptions == other._descriptions - - def __hash__(self) -> int: - return hash(tuple(self._descriptions)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SubjectInformationAccess(ExtensionType): - oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS - - def __init__(self, descriptions: Iterable[AccessDescription]) -> None: - descriptions = list(descriptions) - if not all(isinstance(x, AccessDescription) for x in descriptions): - raise TypeError( - "Every item in the descriptions list must be an " - "AccessDescription" - ) - - self._descriptions = descriptions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectInformationAccess): - return NotImplemented - - return self._descriptions == other._descriptions - - def __hash__(self) -> int: - return hash(tuple(self._descriptions)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class AccessDescription: - def __init__( - self, access_method: ObjectIdentifier, access_location: GeneralName - ) -> None: - if not isinstance(access_method, ObjectIdentifier): - raise TypeError("access_method must be an ObjectIdentifier") - - if not isinstance(access_location, GeneralName): - raise TypeError("access_location must be a GeneralName") - - self._access_method = access_method - self._access_location = access_location - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, AccessDescription): - return NotImplemented - - return ( - self.access_method == other.access_method - and self.access_location == other.access_location - ) - - def __hash__(self) -> int: - return hash((self.access_method, self.access_location)) - - @property - def access_method(self) -> ObjectIdentifier: - return self._access_method - - @property - def access_location(self) -> GeneralName: - return self._access_location - - -class BasicConstraints(ExtensionType): - oid = ExtensionOID.BASIC_CONSTRAINTS - - def __init__(self, ca: bool, path_length: int | None) -> None: - if not isinstance(ca, bool): - raise TypeError("ca must be a boolean value") - - if path_length is not None and not ca: - raise ValueError("path_length must be None when ca is False") - - if path_length is not None and ( - not isinstance(path_length, int) or path_length < 0 - ): - raise TypeError( - "path_length must be a non-negative integer or None" - ) - - self._ca = ca - self._path_length = path_length - - @property - def ca(self) -> bool: - return self._ca - - @property - def path_length(self) -> int | None: - return self._path_length - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, BasicConstraints): - return NotImplemented - - return self.ca == other.ca and self.path_length == other.path_length - - def __hash__(self) -> int: - return hash((self.ca, self.path_length)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class DeltaCRLIndicator(ExtensionType): - oid = ExtensionOID.DELTA_CRL_INDICATOR - - def __init__(self, crl_number: int) -> None: - if not isinstance(crl_number, int): - raise TypeError("crl_number must be an integer") - - self._crl_number = crl_number - - @property - def crl_number(self) -> int: - return self._crl_number - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DeltaCRLIndicator): - return NotImplemented - - return self.crl_number == other.crl_number - - def __hash__(self) -> int: - return hash(self.crl_number) - - def __repr__(self) -> str: - return f"" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CRLDistributionPoints(ExtensionType): - oid = ExtensionOID.CRL_DISTRIBUTION_POINTS - - def __init__( - self, distribution_points: Iterable[DistributionPoint] - ) -> None: - distribution_points = list(distribution_points) - if not all( - isinstance(x, DistributionPoint) for x in distribution_points - ): - raise TypeError( - "distribution_points must be a list of DistributionPoint " - "objects" - ) - - self._distribution_points = distribution_points - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_distribution_points" - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLDistributionPoints): - return NotImplemented - - return self._distribution_points == other._distribution_points - - def __hash__(self) -> int: - return hash(tuple(self._distribution_points)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class FreshestCRL(ExtensionType): - oid = ExtensionOID.FRESHEST_CRL - - def __init__( - self, distribution_points: Iterable[DistributionPoint] - ) -> None: - distribution_points = list(distribution_points) - if not all( - isinstance(x, DistributionPoint) for x in distribution_points - ): - raise TypeError( - "distribution_points must be a list of DistributionPoint " - "objects" - ) - - self._distribution_points = distribution_points - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_distribution_points" - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, FreshestCRL): - return NotImplemented - - return self._distribution_points == other._distribution_points - - def __hash__(self) -> int: - return hash(tuple(self._distribution_points)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class DistributionPoint: - def __init__( - self, - full_name: Iterable[GeneralName] | None, - relative_name: RelativeDistinguishedName | None, - reasons: frozenset[ReasonFlags] | None, - crl_issuer: Iterable[GeneralName] | None, - ) -> None: - if full_name and relative_name: - raise ValueError( - "You cannot provide both full_name and relative_name, at " - "least one must be None." - ) - if not full_name and not relative_name and not crl_issuer: - raise ValueError( - "Either full_name, relative_name or crl_issuer must be " - "provided." - ) - - if full_name is not None: - full_name = list(full_name) - if not all(isinstance(x, GeneralName) for x in full_name): - raise TypeError( - "full_name must be a list of GeneralName objects" - ) - - if relative_name: - if not isinstance(relative_name, RelativeDistinguishedName): - raise TypeError( - "relative_name must be a RelativeDistinguishedName" - ) - - if crl_issuer is not None: - crl_issuer = list(crl_issuer) - if not all(isinstance(x, GeneralName) for x in crl_issuer): - raise TypeError( - "crl_issuer must be None or a list of general names" - ) - - if reasons and ( - not isinstance(reasons, frozenset) - or not all(isinstance(x, ReasonFlags) for x in reasons) - ): - raise TypeError("reasons must be None or frozenset of ReasonFlags") - - if reasons and ( - ReasonFlags.unspecified in reasons - or ReasonFlags.remove_from_crl in reasons - ): - raise ValueError( - "unspecified and remove_from_crl are not valid reasons in a " - "DistributionPoint" - ) - - self._full_name = full_name - self._relative_name = relative_name - self._reasons = reasons - self._crl_issuer = crl_issuer - - def __repr__(self) -> str: - return ( - "".format(self) - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DistributionPoint): - return NotImplemented - - return ( - self.full_name == other.full_name - and self.relative_name == other.relative_name - and self.reasons == other.reasons - and self.crl_issuer == other.crl_issuer - ) - - def __hash__(self) -> int: - if self.full_name is not None: - fn: tuple[GeneralName, ...] | None = tuple(self.full_name) - else: - fn = None - - if self.crl_issuer is not None: - crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer) - else: - crl_issuer = None - - return hash((fn, self.relative_name, self.reasons, crl_issuer)) - - @property - def full_name(self) -> list[GeneralName] | None: - return self._full_name - - @property - def relative_name(self) -> RelativeDistinguishedName | None: - return self._relative_name - - @property - def reasons(self) -> frozenset[ReasonFlags] | None: - return self._reasons - - @property - def crl_issuer(self) -> list[GeneralName] | None: - return self._crl_issuer - - -class ReasonFlags(utils.Enum): - unspecified = "unspecified" - key_compromise = "keyCompromise" - ca_compromise = "cACompromise" - affiliation_changed = "affiliationChanged" - superseded = "superseded" - cessation_of_operation = "cessationOfOperation" - certificate_hold = "certificateHold" - privilege_withdrawn = "privilegeWithdrawn" - aa_compromise = "aACompromise" - remove_from_crl = "removeFromCRL" - - -# These are distribution point bit string mappings. Not to be confused with -# CRLReason reason flags bit string mappings. -# ReasonFlags ::= BIT STRING { -# unused (0), -# keyCompromise (1), -# cACompromise (2), -# affiliationChanged (3), -# superseded (4), -# cessationOfOperation (5), -# certificateHold (6), -# privilegeWithdrawn (7), -# aACompromise (8) } -_REASON_BIT_MAPPING = { - 1: ReasonFlags.key_compromise, - 2: ReasonFlags.ca_compromise, - 3: ReasonFlags.affiliation_changed, - 4: ReasonFlags.superseded, - 5: ReasonFlags.cessation_of_operation, - 6: ReasonFlags.certificate_hold, - 7: ReasonFlags.privilege_withdrawn, - 8: ReasonFlags.aa_compromise, -} - -_CRLREASONFLAGS = { - ReasonFlags.key_compromise: 1, - ReasonFlags.ca_compromise: 2, - ReasonFlags.affiliation_changed: 3, - ReasonFlags.superseded: 4, - ReasonFlags.cessation_of_operation: 5, - ReasonFlags.certificate_hold: 6, - ReasonFlags.privilege_withdrawn: 7, - ReasonFlags.aa_compromise: 8, -} - -# CRLReason ::= ENUMERATED { -# unspecified (0), -# keyCompromise (1), -# cACompromise (2), -# affiliationChanged (3), -# superseded (4), -# cessationOfOperation (5), -# certificateHold (6), -# -- value 7 is not used -# removeFromCRL (8), -# privilegeWithdrawn (9), -# aACompromise (10) } -_CRL_ENTRY_REASON_ENUM_TO_CODE = { - ReasonFlags.unspecified: 0, - ReasonFlags.key_compromise: 1, - ReasonFlags.ca_compromise: 2, - ReasonFlags.affiliation_changed: 3, - ReasonFlags.superseded: 4, - ReasonFlags.cessation_of_operation: 5, - ReasonFlags.certificate_hold: 6, - ReasonFlags.remove_from_crl: 8, - ReasonFlags.privilege_withdrawn: 9, - ReasonFlags.aa_compromise: 10, -} - - -class PolicyConstraints(ExtensionType): - oid = ExtensionOID.POLICY_CONSTRAINTS - - def __init__( - self, - require_explicit_policy: int | None, - inhibit_policy_mapping: int | None, - ) -> None: - if require_explicit_policy is not None and not isinstance( - require_explicit_policy, int - ): - raise TypeError( - "require_explicit_policy must be a non-negative integer or " - "None" - ) - - if inhibit_policy_mapping is not None and not isinstance( - inhibit_policy_mapping, int - ): - raise TypeError( - "inhibit_policy_mapping must be a non-negative integer or None" - ) - - if inhibit_policy_mapping is None and require_explicit_policy is None: - raise ValueError( - "At least one of require_explicit_policy and " - "inhibit_policy_mapping must not be None" - ) - - self._require_explicit_policy = require_explicit_policy - self._inhibit_policy_mapping = inhibit_policy_mapping - - def __repr__(self) -> str: - return ( - "".format(self) - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PolicyConstraints): - return NotImplemented - - return ( - self.require_explicit_policy == other.require_explicit_policy - and self.inhibit_policy_mapping == other.inhibit_policy_mapping - ) - - def __hash__(self) -> int: - return hash( - (self.require_explicit_policy, self.inhibit_policy_mapping) - ) - - @property - def require_explicit_policy(self) -> int | None: - return self._require_explicit_policy - - @property - def inhibit_policy_mapping(self) -> int | None: - return self._inhibit_policy_mapping - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CertificatePolicies(ExtensionType): - oid = ExtensionOID.CERTIFICATE_POLICIES - - def __init__(self, policies: Iterable[PolicyInformation]) -> None: - policies = list(policies) - if not all(isinstance(x, PolicyInformation) for x in policies): - raise TypeError( - "Every item in the policies list must be a PolicyInformation" - ) - - self._policies = policies - - __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CertificatePolicies): - return NotImplemented - - return self._policies == other._policies - - def __hash__(self) -> int: - return hash(tuple(self._policies)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PolicyInformation: - def __init__( - self, - policy_identifier: ObjectIdentifier, - policy_qualifiers: Iterable[str | UserNotice] | None, - ) -> None: - if not isinstance(policy_identifier, ObjectIdentifier): - raise TypeError("policy_identifier must be an ObjectIdentifier") - - self._policy_identifier = policy_identifier - - if policy_qualifiers is not None: - policy_qualifiers = list(policy_qualifiers) - if not all( - isinstance(x, (str, UserNotice)) for x in policy_qualifiers - ): - raise TypeError( - "policy_qualifiers must be a list of strings and/or " - "UserNotice objects or None" - ) - - self._policy_qualifiers = policy_qualifiers - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PolicyInformation): - return NotImplemented - - return ( - self.policy_identifier == other.policy_identifier - and self.policy_qualifiers == other.policy_qualifiers - ) - - def __hash__(self) -> int: - if self.policy_qualifiers is not None: - pq = tuple(self.policy_qualifiers) - else: - pq = None - - return hash((self.policy_identifier, pq)) - - @property - def policy_identifier(self) -> ObjectIdentifier: - return self._policy_identifier - - @property - def policy_qualifiers( - self, - ) -> list[str | UserNotice] | None: - return self._policy_qualifiers - - -class UserNotice: - def __init__( - self, - notice_reference: NoticeReference | None, - explicit_text: str | None, - ) -> None: - if notice_reference and not isinstance( - notice_reference, NoticeReference - ): - raise TypeError( - "notice_reference must be None or a NoticeReference" - ) - - self._notice_reference = notice_reference - self._explicit_text = explicit_text - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UserNotice): - return NotImplemented - - return ( - self.notice_reference == other.notice_reference - and self.explicit_text == other.explicit_text - ) - - def __hash__(self) -> int: - return hash((self.notice_reference, self.explicit_text)) - - @property - def notice_reference(self) -> NoticeReference | None: - return self._notice_reference - - @property - def explicit_text(self) -> str | None: - return self._explicit_text - - -class NoticeReference: - def __init__( - self, - organization: str | None, - notice_numbers: Iterable[int], - ) -> None: - self._organization = organization - notice_numbers = list(notice_numbers) - if not all(isinstance(x, int) for x in notice_numbers): - raise TypeError("notice_numbers must be a list of integers") - - self._notice_numbers = notice_numbers - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NoticeReference): - return NotImplemented - - return ( - self.organization == other.organization - and self.notice_numbers == other.notice_numbers - ) - - def __hash__(self) -> int: - return hash((self.organization, tuple(self.notice_numbers))) - - @property - def organization(self) -> str | None: - return self._organization - - @property - def notice_numbers(self) -> list[int]: - return self._notice_numbers - - -class ExtendedKeyUsage(ExtensionType): - oid = ExtensionOID.EXTENDED_KEY_USAGE - - def __init__(self, usages: Iterable[ObjectIdentifier]) -> None: - usages = list(usages) - if not all(isinstance(x, ObjectIdentifier) for x in usages): - raise TypeError( - "Every item in the usages list must be an ObjectIdentifier" - ) - - self._usages = usages - - __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, ExtendedKeyUsage): - return NotImplemented - - return self._usages == other._usages - - def __hash__(self) -> int: - return hash(tuple(self._usages)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPNoCheck(ExtensionType): - oid = ExtensionOID.OCSP_NO_CHECK - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPNoCheck): - return NotImplemented - - return True - - def __hash__(self) -> int: - return hash(OCSPNoCheck) - - def __repr__(self) -> str: - return "" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrecertPoison(ExtensionType): - oid = ExtensionOID.PRECERT_POISON - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrecertPoison): - return NotImplemented - - return True - - def __hash__(self) -> int: - return hash(PrecertPoison) - - def __repr__(self) -> str: - return "" - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class TLSFeature(ExtensionType): - oid = ExtensionOID.TLS_FEATURE - - def __init__(self, features: Iterable[TLSFeatureType]) -> None: - features = list(features) - if ( - not all(isinstance(x, TLSFeatureType) for x in features) - or len(features) == 0 - ): - raise TypeError( - "features must be a list of elements from the TLSFeatureType " - "enum" - ) - - self._features = features - - __len__, __iter__, __getitem__ = _make_sequence_methods("_features") - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, TLSFeature): - return NotImplemented - - return self._features == other._features - - def __hash__(self) -> int: - return hash(tuple(self._features)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class TLSFeatureType(utils.Enum): - # status_request is defined in RFC 6066 and is used for what is commonly - # called OCSP Must-Staple when present in the TLS Feature extension in an - # X.509 certificate. - status_request = 5 - # status_request_v2 is defined in RFC 6961 and allows multiple OCSP - # responses to be provided. It is not currently in use by clients or - # servers. - status_request_v2 = 17 - - -_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} - - -class InhibitAnyPolicy(ExtensionType): - oid = ExtensionOID.INHIBIT_ANY_POLICY - - def __init__(self, skip_certs: int) -> None: - if not isinstance(skip_certs, int): - raise TypeError("skip_certs must be an integer") - - if skip_certs < 0: - raise ValueError("skip_certs must be a non-negative integer") - - self._skip_certs = skip_certs - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, InhibitAnyPolicy): - return NotImplemented - - return self.skip_certs == other.skip_certs - - def __hash__(self) -> int: - return hash(self.skip_certs) - - @property - def skip_certs(self) -> int: - return self._skip_certs - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class KeyUsage(ExtensionType): - oid = ExtensionOID.KEY_USAGE - - def __init__( - self, - digital_signature: bool, - content_commitment: bool, - key_encipherment: bool, - data_encipherment: bool, - key_agreement: bool, - key_cert_sign: bool, - crl_sign: bool, - encipher_only: bool, - decipher_only: bool, - ) -> None: - if not key_agreement and (encipher_only or decipher_only): - raise ValueError( - "encipher_only and decipher_only can only be true when " - "key_agreement is true" - ) - - self._digital_signature = digital_signature - self._content_commitment = content_commitment - self._key_encipherment = key_encipherment - self._data_encipherment = data_encipherment - self._key_agreement = key_agreement - self._key_cert_sign = key_cert_sign - self._crl_sign = crl_sign - self._encipher_only = encipher_only - self._decipher_only = decipher_only - - @property - def digital_signature(self) -> bool: - return self._digital_signature - - @property - def content_commitment(self) -> bool: - return self._content_commitment - - @property - def key_encipherment(self) -> bool: - return self._key_encipherment - - @property - def data_encipherment(self) -> bool: - return self._data_encipherment - - @property - def key_agreement(self) -> bool: - return self._key_agreement - - @property - def key_cert_sign(self) -> bool: - return self._key_cert_sign - - @property - def crl_sign(self) -> bool: - return self._crl_sign - - @property - def encipher_only(self) -> bool: - if not self.key_agreement: - raise ValueError( - "encipher_only is undefined unless key_agreement is true" - ) - else: - return self._encipher_only - - @property - def decipher_only(self) -> bool: - if not self.key_agreement: - raise ValueError( - "decipher_only is undefined unless key_agreement is true" - ) - else: - return self._decipher_only - - def __repr__(self) -> str: - try: - encipher_only = self.encipher_only - decipher_only = self.decipher_only - except ValueError: - # Users found None confusing because even though encipher/decipher - # have no meaning unless key_agreement is true, to construct an - # instance of the class you still need to pass False. - encipher_only = False - decipher_only = False - - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, KeyUsage): - return NotImplemented - - return ( - self.digital_signature == other.digital_signature - and self.content_commitment == other.content_commitment - and self.key_encipherment == other.key_encipherment - and self.data_encipherment == other.data_encipherment - and self.key_agreement == other.key_agreement - and self.key_cert_sign == other.key_cert_sign - and self.crl_sign == other.crl_sign - and self._encipher_only == other._encipher_only - and self._decipher_only == other._decipher_only - ) - - def __hash__(self) -> int: - return hash( - ( - self.digital_signature, - self.content_commitment, - self.key_encipherment, - self.data_encipherment, - self.key_agreement, - self.key_cert_sign, - self.crl_sign, - self._encipher_only, - self._decipher_only, - ) - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrivateKeyUsagePeriod(ExtensionType): - oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD - - def __init__( - self, - not_before: datetime.datetime | None, - not_after: datetime.datetime | None, - ) -> None: - if ( - not isinstance(not_before, datetime.datetime) - and not_before is not None - ): - raise TypeError("not_before must be a datetime.datetime or None") - - if ( - not isinstance(not_after, datetime.datetime) - and not_after is not None - ): - raise TypeError("not_after must be a datetime.datetime or None") - - if not_before is None and not_after is None: - raise ValueError( - "At least one of not_before and not_after must not be None" - ) - - if ( - not_before is not None - and not_after is not None - and not_before > not_after - ): - raise ValueError("not_before must be before not_after") - - self._not_before = not_before - self._not_after = not_after - - @property - def not_before(self) -> datetime.datetime | None: - return self._not_before - - @property - def not_after(self) -> datetime.datetime | None: - return self._not_after - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrivateKeyUsagePeriod): - return NotImplemented - - return ( - self.not_before == other.not_before - and self.not_after == other.not_after - ) - - def __hash__(self) -> int: - return hash((self.not_before, self.not_after)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class NameConstraints(ExtensionType): - oid = ExtensionOID.NAME_CONSTRAINTS - - def __init__( - self, - permitted_subtrees: Iterable[GeneralName] | None, - excluded_subtrees: Iterable[GeneralName] | None, - ) -> None: - if permitted_subtrees is not None: - permitted_subtrees = list(permitted_subtrees) - if not permitted_subtrees: - raise ValueError( - "permitted_subtrees must be a non-empty list or None" - ) - if not all(isinstance(x, GeneralName) for x in permitted_subtrees): - raise TypeError( - "permitted_subtrees must be a list of GeneralName objects " - "or None" - ) - - self._validate_tree(permitted_subtrees) - - if excluded_subtrees is not None: - excluded_subtrees = list(excluded_subtrees) - if not excluded_subtrees: - raise ValueError( - "excluded_subtrees must be a non-empty list or None" - ) - if not all(isinstance(x, GeneralName) for x in excluded_subtrees): - raise TypeError( - "excluded_subtrees must be a list of GeneralName objects " - "or None" - ) - - self._validate_tree(excluded_subtrees) - - if permitted_subtrees is None and excluded_subtrees is None: - raise ValueError( - "At least one of permitted_subtrees and excluded_subtrees " - "must not be None" - ) - - self._permitted_subtrees = permitted_subtrees - self._excluded_subtrees = excluded_subtrees - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NameConstraints): - return NotImplemented - - return ( - self.excluded_subtrees == other.excluded_subtrees - and self.permitted_subtrees == other.permitted_subtrees - ) - - def _validate_tree(self, tree: Iterable[GeneralName]) -> None: - self._validate_ip_name(tree) - self._validate_dns_name(tree) - - def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None: - if any( - isinstance(name, IPAddress) - and not isinstance( - name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) - ) - for name in tree - ): - raise TypeError( - "IPAddress name constraints must be an IPv4Network or" - " IPv6Network object" - ) - - def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None: - if any( - isinstance(name, DNSName) and "*" in name.value for name in tree - ): - raise ValueError( - "DNSName name constraints must not contain the '*' wildcard" - " character" - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - def __hash__(self) -> int: - if self.permitted_subtrees is not None: - ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees) - else: - ps = None - - if self.excluded_subtrees is not None: - es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees) - else: - es = None - - return hash((ps, es)) - - @property - def permitted_subtrees( - self, - ) -> list[GeneralName] | None: - return self._permitted_subtrees - - @property - def excluded_subtrees( - self, - ) -> list[GeneralName] | None: - return self._excluded_subtrees - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class Extension(typing.Generic[ExtensionTypeVar]): - def __init__( - self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar - ) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError( - "oid argument must be an ObjectIdentifier instance." - ) - - if not isinstance(critical, bool): - raise TypeError("critical must be a boolean value") - - self._oid = oid - self._critical = critical - self._value = value - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def critical(self) -> bool: - return self._critical - - @property - def value(self) -> ExtensionTypeVar: - return self._value - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Extension): - return NotImplemented - - return ( - self.oid == other.oid - and self.critical == other.critical - and self.value == other.value - ) - - def __hash__(self) -> int: - return hash((self.oid, self.critical, self.value)) - - -class GeneralNames: - def __init__(self, general_names: Iterable[GeneralName]) -> None: - general_names = list(general_names) - if not all(isinstance(x, GeneralName) for x in general_names): - raise TypeError( - "Every item in the general_names list must be an " - "object conforming to the GeneralName interface" - ) - - self._general_names = general_names - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - # Return the value of each GeneralName, except for OtherName instances - # which we return directly because it has two important properties not - # just one value. - objs = (i for i in self if isinstance(i, type)) - if type != OtherName: - return [i.value for i in objs] - return list(objs) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, GeneralNames): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(tuple(self._general_names)) - - -class SubjectAlternativeName(ExtensionType): - oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SubjectAlternativeName): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class IssuerAlternativeName(ExtensionType): - oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IssuerAlternativeName): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CertificateIssuer(ExtensionType): - oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER - - def __init__(self, general_names: Iterable[GeneralName]) -> None: - self._general_names = GeneralNames(general_names) - - __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - - @typing.overload - def get_values_for_type( - self, - type: type[DNSName] - | type[UniformResourceIdentifier] - | type[RFC822Name], - ) -> list[str]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[DirectoryName], - ) -> list[Name]: ... - - @typing.overload - def get_values_for_type( - self, - type: type[RegisteredID], - ) -> list[ObjectIdentifier]: ... - - @typing.overload - def get_values_for_type( - self, type: type[IPAddress] - ) -> list[_IPAddressTypes]: ... - - @typing.overload - def get_values_for_type( - self, type: type[OtherName] - ) -> list[OtherName]: ... - - def get_values_for_type( - self, - type: type[DNSName] - | type[DirectoryName] - | type[IPAddress] - | type[OtherName] - | type[RFC822Name] - | type[RegisteredID] - | type[UniformResourceIdentifier], - ) -> ( - list[_IPAddressTypes] - | list[str] - | list[OtherName] - | list[Name] - | list[ObjectIdentifier] - ): - return self._general_names.get_values_for_type(type) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CertificateIssuer): - return NotImplemented - - return self._general_names == other._general_names - - def __hash__(self) -> int: - return hash(self._general_names) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class CRLReason(ExtensionType): - oid = CRLEntryExtensionOID.CRL_REASON - - def __init__(self, reason: ReasonFlags) -> None: - if not isinstance(reason, ReasonFlags): - raise TypeError("reason must be an element from ReasonFlags") - - self._reason = reason - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, CRLReason): - return NotImplemented - - return self.reason == other.reason - - def __hash__(self) -> int: - return hash(self.reason) - - @property - def reason(self) -> ReasonFlags: - return self._reason - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class InvalidityDate(ExtensionType): - oid = CRLEntryExtensionOID.INVALIDITY_DATE - - def __init__(self, invalidity_date: datetime.datetime) -> None: - if not isinstance(invalidity_date, datetime.datetime): - raise TypeError("invalidity_date must be a datetime.datetime") - - self._invalidity_date = invalidity_date - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, InvalidityDate): - return NotImplemented - - return self.invalidity_date == other.invalidity_date - - def __hash__(self) -> int: - return hash(self.invalidity_date) - - @property - def invalidity_date(self) -> datetime.datetime: - return self._invalidity_date - - @property - def invalidity_date_utc(self) -> datetime.datetime: - if self._invalidity_date.tzinfo is None: - return self._invalidity_date.replace(tzinfo=datetime.timezone.utc) - else: - return self._invalidity_date.astimezone(tz=datetime.timezone.utc) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class PrecertificateSignedCertificateTimestamps(ExtensionType): - oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS - - def __init__( - self, - signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], - ) -> None: - signed_certificate_timestamps = list(signed_certificate_timestamps) - if not all( - isinstance(sct, SignedCertificateTimestamp) - for sct in signed_certificate_timestamps - ): - raise TypeError( - "Every item in the signed_certificate_timestamps list must be " - "a SignedCertificateTimestamp" - ) - self._signed_certificate_timestamps = signed_certificate_timestamps - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_signed_certificate_timestamps" - ) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash(tuple(self._signed_certificate_timestamps)) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, PrecertificateSignedCertificateTimestamps): - return NotImplemented - - return ( - self._signed_certificate_timestamps - == other._signed_certificate_timestamps - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class SignedCertificateTimestamps(ExtensionType): - oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS - - def __init__( - self, - signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], - ) -> None: - signed_certificate_timestamps = list(signed_certificate_timestamps) - if not all( - isinstance(sct, SignedCertificateTimestamp) - for sct in signed_certificate_timestamps - ): - raise TypeError( - "Every item in the signed_certificate_timestamps list must be " - "a SignedCertificateTimestamp" - ) - self._signed_certificate_timestamps = signed_certificate_timestamps - - __len__, __iter__, __getitem__ = _make_sequence_methods( - "_signed_certificate_timestamps" - ) - - def __repr__(self) -> str: - return f"" - - def __hash__(self) -> int: - return hash(tuple(self._signed_certificate_timestamps)) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, SignedCertificateTimestamps): - return NotImplemented - - return ( - self._signed_certificate_timestamps - == other._signed_certificate_timestamps - ) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPNonce(ExtensionType): - oid = OCSPExtensionOID.NONCE - - def __init__(self, nonce: bytes) -> None: - if not isinstance(nonce, bytes): - raise TypeError("nonce must be bytes") - - self._nonce = nonce - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPNonce): - return NotImplemented - - return self.nonce == other.nonce - - def __hash__(self) -> int: - return hash(self.nonce) - - def __repr__(self) -> str: - return f"" - - @property - def nonce(self) -> bytes: - return self._nonce - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class OCSPAcceptableResponses(ExtensionType): - oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES - - def __init__(self, responses: Iterable[ObjectIdentifier]) -> None: - responses = list(responses) - if any(not isinstance(r, ObjectIdentifier) for r in responses): - raise TypeError("All responses must be ObjectIdentifiers") - - self._responses = responses - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OCSPAcceptableResponses): - return NotImplemented - - return self._responses == other._responses - - def __hash__(self) -> int: - return hash(tuple(self._responses)) - - def __repr__(self) -> str: - return f"" - - def __iter__(self) -> Iterator[ObjectIdentifier]: - return iter(self._responses) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class IssuingDistributionPoint(ExtensionType): - oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT - - def __init__( - self, - full_name: Iterable[GeneralName] | None, - relative_name: RelativeDistinguishedName | None, - only_contains_user_certs: bool, - only_contains_ca_certs: bool, - only_some_reasons: frozenset[ReasonFlags] | None, - indirect_crl: bool, - only_contains_attribute_certs: bool, - ) -> None: - if full_name is not None: - full_name = list(full_name) - - if only_some_reasons and ( - not isinstance(only_some_reasons, frozenset) - or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) - ): - raise TypeError( - "only_some_reasons must be None or frozenset of ReasonFlags" - ) - - if only_some_reasons and ( - ReasonFlags.unspecified in only_some_reasons - or ReasonFlags.remove_from_crl in only_some_reasons - ): - raise ValueError( - "unspecified and remove_from_crl are not valid reasons in an " - "IssuingDistributionPoint" - ) - - if not ( - isinstance(only_contains_user_certs, bool) - and isinstance(only_contains_ca_certs, bool) - and isinstance(indirect_crl, bool) - and isinstance(only_contains_attribute_certs, bool) - ): - raise TypeError( - "only_contains_user_certs, only_contains_ca_certs, " - "indirect_crl and only_contains_attribute_certs " - "must all be boolean." - ) - - # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension - # in a CRL can have only one of onlyContainsUserCerts, - # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE. - crl_constraints = [ - only_contains_user_certs, - only_contains_ca_certs, - only_contains_attribute_certs, - ] - - if len([x for x in crl_constraints if x]) > 1: - raise ValueError( - "Only one of the following can be set to True: " - "only_contains_user_certs, only_contains_ca_certs, " - "only_contains_attribute_certs" - ) - - if not any( - [ - only_contains_user_certs, - only_contains_ca_certs, - indirect_crl, - only_contains_attribute_certs, - full_name, - relative_name, - only_some_reasons, - ] - ): - raise ValueError( - "Cannot create empty extension: " - "if only_contains_user_certs, only_contains_ca_certs, " - "indirect_crl, and only_contains_attribute_certs are all False" - ", then either full_name, relative_name, or only_some_reasons " - "must have a value." - ) - - self._only_contains_user_certs = only_contains_user_certs - self._only_contains_ca_certs = only_contains_ca_certs - self._indirect_crl = indirect_crl - self._only_contains_attribute_certs = only_contains_attribute_certs - self._only_some_reasons = only_some_reasons - self._full_name = full_name - self._relative_name = relative_name - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IssuingDistributionPoint): - return NotImplemented - - return ( - self.full_name == other.full_name - and self.relative_name == other.relative_name - and self.only_contains_user_certs == other.only_contains_user_certs - and self.only_contains_ca_certs == other.only_contains_ca_certs - and self.only_some_reasons == other.only_some_reasons - and self.indirect_crl == other.indirect_crl - and self.only_contains_attribute_certs - == other.only_contains_attribute_certs - ) - - def __hash__(self) -> int: - return hash( - ( - self.full_name, - self.relative_name, - self.only_contains_user_certs, - self.only_contains_ca_certs, - self.only_some_reasons, - self.indirect_crl, - self.only_contains_attribute_certs, - ) - ) - - @property - def full_name(self) -> list[GeneralName] | None: - return self._full_name - - @property - def relative_name(self) -> RelativeDistinguishedName | None: - return self._relative_name - - @property - def only_contains_user_certs(self) -> bool: - return self._only_contains_user_certs - - @property - def only_contains_ca_certs(self) -> bool: - return self._only_contains_ca_certs - - @property - def only_some_reasons( - self, - ) -> frozenset[ReasonFlags] | None: - return self._only_some_reasons - - @property - def indirect_crl(self) -> bool: - return self._indirect_crl - - @property - def only_contains_attribute_certs(self) -> bool: - return self._only_contains_attribute_certs - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class MSCertificateTemplate(ExtensionType): - oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE - - def __init__( - self, - template_id: ObjectIdentifier, - major_version: int | None, - minor_version: int | None, - ) -> None: - if not isinstance(template_id, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - self._template_id = template_id - if ( - major_version is not None and not isinstance(major_version, int) - ) or ( - minor_version is not None and not isinstance(minor_version, int) - ): - raise TypeError( - "major_version and minor_version must be integers or None" - ) - self._major_version = major_version - self._minor_version = minor_version - - @property - def template_id(self) -> ObjectIdentifier: - return self._template_id - - @property - def major_version(self) -> int | None: - return self._major_version - - @property - def minor_version(self) -> int | None: - return self._minor_version - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, MSCertificateTemplate): - return NotImplemented - - return ( - self.template_id == other.template_id - and self.major_version == other.major_version - and self.minor_version == other.minor_version - ) - - def __hash__(self) -> int: - return hash((self.template_id, self.major_version, self.minor_version)) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class NamingAuthority: - def __init__( - self, - id: ObjectIdentifier | None, - url: str | None, - text: str | None, - ) -> None: - if id is not None and not isinstance(id, ObjectIdentifier): - raise TypeError("id must be an ObjectIdentifier") - - if url is not None and not isinstance(url, str): - raise TypeError("url must be a str") - - if text is not None and not isinstance(text, str): - raise TypeError("text must be a str") - - self._id = id - self._url = url - self._text = text - - @property - def id(self) -> ObjectIdentifier | None: - return self._id - - @property - def url(self) -> str | None: - return self._url - - @property - def text(self) -> str | None: - return self._text - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NamingAuthority): - return NotImplemented - - return ( - self.id == other.id - and self.url == other.url - and self.text == other.text - ) - - def __hash__(self) -> int: - return hash( - ( - self.id, - self.url, - self.text, - ) - ) - - -class ProfessionInfo: - def __init__( - self, - naming_authority: NamingAuthority | None, - profession_items: Iterable[str], - profession_oids: Iterable[ObjectIdentifier] | None, - registration_number: str | None, - add_profession_info: bytes | None, - ) -> None: - if naming_authority is not None and not isinstance( - naming_authority, NamingAuthority - ): - raise TypeError("naming_authority must be a NamingAuthority") - - profession_items = list(profession_items) - if not all(isinstance(item, str) for item in profession_items): - raise TypeError( - "Every item in the profession_items list must be a str" - ) - - if profession_oids is not None: - profession_oids = list(profession_oids) - if not all( - isinstance(oid, ObjectIdentifier) for oid in profession_oids - ): - raise TypeError( - "Every item in the profession_oids list must be an " - "ObjectIdentifier" - ) - - if registration_number is not None and not isinstance( - registration_number, str - ): - raise TypeError("registration_number must be a str") - - if add_profession_info is not None and not isinstance( - add_profession_info, bytes - ): - raise TypeError("add_profession_info must be bytes") - - self._naming_authority = naming_authority - self._profession_items = profession_items - self._profession_oids = profession_oids - self._registration_number = registration_number - self._add_profession_info = add_profession_info - - @property - def naming_authority(self) -> NamingAuthority | None: - return self._naming_authority - - @property - def profession_items(self) -> list[str]: - return self._profession_items - - @property - def profession_oids(self) -> list[ObjectIdentifier] | None: - return self._profession_oids - - @property - def registration_number(self) -> str | None: - return self._registration_number - - @property - def add_profession_info(self) -> bytes | None: - return self._add_profession_info - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, ProfessionInfo): - return NotImplemented - - return ( - self.naming_authority == other.naming_authority - and self.profession_items == other.profession_items - and self.profession_oids == other.profession_oids - and self.registration_number == other.registration_number - and self.add_profession_info == other.add_profession_info - ) - - def __hash__(self) -> int: - if self.profession_oids is not None: - profession_oids = tuple(self.profession_oids) - else: - profession_oids = None - return hash( - ( - self.naming_authority, - tuple(self.profession_items), - profession_oids, - self.registration_number, - self.add_profession_info, - ) - ) - - -class Admission: - def __init__( - self, - admission_authority: GeneralName | None, - naming_authority: NamingAuthority | None, - profession_infos: Iterable[ProfessionInfo], - ) -> None: - if admission_authority is not None and not isinstance( - admission_authority, GeneralName - ): - raise TypeError("admission_authority must be a GeneralName") - - if naming_authority is not None and not isinstance( - naming_authority, NamingAuthority - ): - raise TypeError("naming_authority must be a NamingAuthority") - - profession_infos = list(profession_infos) - if not all( - isinstance(info, ProfessionInfo) for info in profession_infos - ): - raise TypeError( - "Every item in the profession_infos list must be a " - "ProfessionInfo" - ) - - self._admission_authority = admission_authority - self._naming_authority = naming_authority - self._profession_infos = profession_infos - - @property - def admission_authority(self) -> GeneralName | None: - return self._admission_authority - - @property - def naming_authority(self) -> NamingAuthority | None: - return self._naming_authority - - @property - def profession_infos(self) -> list[ProfessionInfo]: - return self._profession_infos - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Admission): - return NotImplemented - - return ( - self.admission_authority == other.admission_authority - and self.naming_authority == other.naming_authority - and self.profession_infos == other.profession_infos - ) - - def __hash__(self) -> int: - return hash( - ( - self.admission_authority, - self.naming_authority, - tuple(self.profession_infos), - ) - ) - - -class Admissions(ExtensionType): - oid = ExtensionOID.ADMISSIONS - - def __init__( - self, - authority: GeneralName | None, - admissions: Iterable[Admission], - ) -> None: - if authority is not None and not isinstance(authority, GeneralName): - raise TypeError("authority must be a GeneralName") - - admissions = list(admissions) - if not all( - isinstance(admission, Admission) for admission in admissions - ): - raise TypeError( - "Every item in the contents_of_admissions list must be an " - "Admission" - ) - - self._authority = authority - self._admissions = admissions - - __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions") - - @property - def authority(self) -> GeneralName | None: - return self._authority - - def __repr__(self) -> str: - return ( - f"" - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Admissions): - return NotImplemented - - return ( - self.authority == other.authority - and self._admissions == other._admissions - ) - - def __hash__(self) -> int: - return hash((self.authority, tuple(self._admissions))) - - def public_bytes(self) -> bytes: - return rust_x509.encode_extension_value(self) - - -class UnrecognizedExtension(ExtensionType): - def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError("oid must be an ObjectIdentifier") - self._oid = oid - self._value = value - - @property - def oid(self) -> ObjectIdentifier: # type: ignore[override] - return self._oid - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UnrecognizedExtension): - return NotImplemented - - return self.oid == other.oid and self.value == other.value - - def __hash__(self) -> int: - return hash((self.oid, self.value)) - - def public_bytes(self) -> bytes: - return self.value diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/general_name.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/general_name.py deleted file mode 100644 index 672f287..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/general_name.py +++ /dev/null @@ -1,281 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import abc -import ipaddress -import typing -from email.utils import parseaddr - -from cryptography.x509.name import Name -from cryptography.x509.oid import ObjectIdentifier - -_IPAddressTypes = typing.Union[ - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, -] - - -class UnsupportedGeneralNameType(Exception): - pass - - -class GeneralName(metaclass=abc.ABCMeta): - @property - @abc.abstractmethod - def value(self) -> typing.Any: - """ - Return the value of the object - """ - - -class RFC822Name(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "RFC822Name values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - name, address = parseaddr(value) - if name or not address: - # parseaddr has found a name (e.g. Name ) or the entire - # value is an empty string. - raise ValueError("Invalid rfc822name value") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> RFC822Name: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RFC822Name): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class DNSName(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "DNSName values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> DNSName: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DNSName): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class UniformResourceIdentifier(GeneralName): - def __init__(self, value: str) -> None: - if isinstance(value, str): - try: - value.encode("ascii") - except UnicodeEncodeError: - raise ValueError( - "URI values should be passed as an A-label string. " - "This means unicode characters should be encoded via " - "a library like idna." - ) - else: - raise TypeError("value must be string") - - self._value = value - - @property - def value(self) -> str: - return self._value - - @classmethod - def _init_without_validation(cls, value: str) -> UniformResourceIdentifier: - instance = cls.__new__(cls) - instance._value = value - return instance - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, UniformResourceIdentifier): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class DirectoryName(GeneralName): - def __init__(self, value: Name) -> None: - if not isinstance(value, Name): - raise TypeError("value must be a Name") - - self._value = value - - @property - def value(self) -> Name: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, DirectoryName): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class RegisteredID(GeneralName): - def __init__(self, value: ObjectIdentifier) -> None: - if not isinstance(value, ObjectIdentifier): - raise TypeError("value must be an ObjectIdentifier") - - self._value = value - - @property - def value(self) -> ObjectIdentifier: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RegisteredID): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class IPAddress(GeneralName): - def __init__(self, value: _IPAddressTypes) -> None: - if not isinstance( - value, - ( - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, - ), - ): - raise TypeError( - "value must be an instance of ipaddress.IPv4Address, " - "ipaddress.IPv6Address, ipaddress.IPv4Network, or " - "ipaddress.IPv6Network" - ) - - self._value = value - - @property - def value(self) -> _IPAddressTypes: - return self._value - - def _packed(self) -> bytes: - if isinstance( - self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) - ): - return self.value.packed - else: - return ( - self.value.network_address.packed + self.value.netmask.packed - ) - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, IPAddress): - return NotImplemented - - return self.value == other.value - - def __hash__(self) -> int: - return hash(self.value) - - -class OtherName(GeneralName): - def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: - if not isinstance(type_id, ObjectIdentifier): - raise TypeError("type_id must be an ObjectIdentifier") - if not isinstance(value, bytes): - raise TypeError("value must be a binary string") - - self._type_id = type_id - self._value = value - - @property - def type_id(self) -> ObjectIdentifier: - return self._type_id - - @property - def value(self) -> bytes: - return self._value - - def __repr__(self) -> str: - return f"" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, OtherName): - return NotImplemented - - return self.type_id == other.type_id and self.value == other.value - - def __hash__(self) -> int: - return hash((self.type_id, self.value)) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/name.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/name.py deleted file mode 100644 index 685f921..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/name.py +++ /dev/null @@ -1,476 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import binascii -import re -import sys -import typing -import warnings -from collections.abc import Iterable, Iterator - -from cryptography import utils -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.x509.oid import NameOID, ObjectIdentifier - - -class _ASN1Type(utils.Enum): - BitString = 3 - OctetString = 4 - UTF8String = 12 - NumericString = 18 - PrintableString = 19 - T61String = 20 - IA5String = 22 - UTCTime = 23 - GeneralizedTime = 24 - VisibleString = 26 - UniversalString = 28 - BMPString = 30 - - -_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type} -_NAMEOID_DEFAULT_TYPE: dict[ObjectIdentifier, _ASN1Type] = { - NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, - NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, - NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, - NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, - NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, - NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, -} - -# Type alias -_OidNameMap = typing.Mapping[ObjectIdentifier, str] -_NameOidMap = typing.Mapping[str, ObjectIdentifier] - -#: Short attribute names from RFC 4514: -#: https://tools.ietf.org/html/rfc4514#page-7 -_NAMEOID_TO_NAME: _OidNameMap = { - NameOID.COMMON_NAME: "CN", - NameOID.LOCALITY_NAME: "L", - NameOID.STATE_OR_PROVINCE_NAME: "ST", - NameOID.ORGANIZATION_NAME: "O", - NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", - NameOID.COUNTRY_NAME: "C", - NameOID.STREET_ADDRESS: "STREET", - NameOID.DOMAIN_COMPONENT: "DC", - NameOID.USER_ID: "UID", -} -_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()} - -_NAMEOID_LENGTH_LIMIT = { - NameOID.COUNTRY_NAME: (2, 2), - NameOID.JURISDICTION_COUNTRY_NAME: (2, 2), - NameOID.COMMON_NAME: (1, 64), -} - - -def _escape_dn_value(val: str | bytes) -> str: - """Escape special characters in RFC4514 Distinguished Name value.""" - - if not val: - return "" - - # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character - # followed by the hexadecimal encoding of the octets. - if isinstance(val, bytes): - return "#" + binascii.hexlify(val).decode("utf8") - - # See https://tools.ietf.org/html/rfc4514#section-2.4 - val = val.replace("\\", "\\\\") - val = val.replace('"', '\\"') - val = val.replace("+", "\\+") - val = val.replace(",", "\\,") - val = val.replace(";", "\\;") - val = val.replace("<", "\\<") - val = val.replace(">", "\\>") - val = val.replace("\0", "\\00") - - if val[0] in ("#", " "): - val = "\\" + val - if val[-1] == " ": - val = val[:-1] + "\\ " - - return val - - -def _unescape_dn_value(val: str) -> str: - if not val: - return "" - - # See https://tools.ietf.org/html/rfc4514#section-3 - - # special = escaped / SPACE / SHARP / EQUALS - # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE - def sub(m): - val = m.group(1) - # Regular escape - if len(val) == 1: - return val - # Hex-value scape - return chr(int(val, 16)) - - return _RFC4514NameParser._PAIR_RE.sub(sub, val) - - -NameAttributeValueType = typing.TypeVar( - "NameAttributeValueType", - typing.Union[str, bytes], - str, - bytes, - covariant=True, -) - - -class NameAttribute(typing.Generic[NameAttributeValueType]): - def __init__( - self, - oid: ObjectIdentifier, - value: NameAttributeValueType, - _type: _ASN1Type | None = None, - *, - _validate: bool = True, - ) -> None: - if not isinstance(oid, ObjectIdentifier): - raise TypeError( - "oid argument must be an ObjectIdentifier instance." - ) - if _type == _ASN1Type.BitString: - if oid != NameOID.X500_UNIQUE_IDENTIFIER: - raise TypeError( - "oid must be X500_UNIQUE_IDENTIFIER for BitString type." - ) - if not isinstance(value, bytes): - raise TypeError("value must be bytes for BitString") - elif not isinstance(value, str): - raise TypeError("value argument must be a str") - - length_limits = _NAMEOID_LENGTH_LIMIT.get(oid) - if length_limits is not None: - min_length, max_length = length_limits - assert isinstance(value, str) - c_len = len(value.encode("utf8")) - if c_len < min_length or c_len > max_length: - msg = ( - f"Attribute's length must be >= {min_length} and " - f"<= {max_length}, but it was {c_len}" - ) - if _validate is True: - raise ValueError(msg) - else: - warnings.warn(msg, stacklevel=2) - - # The appropriate ASN1 string type varies by OID and is defined across - # multiple RFCs including 2459, 3280, and 5280. In general UTF8String - # is preferred (2459), but 3280 and 5280 specify several OIDs with - # alternate types. This means when we see the sentinel value we need - # to look up whether the OID has a non-UTF8 type. If it does, set it - # to that. Otherwise, UTF8! - if _type is None: - _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) - - if not isinstance(_type, _ASN1Type): - raise TypeError("_type must be from the _ASN1Type enum") - - self._oid = oid - self._value: NameAttributeValueType = value - self._type: _ASN1Type = _type - - @property - def oid(self) -> ObjectIdentifier: - return self._oid - - @property - def value(self) -> NameAttributeValueType: - return self._value - - @property - def rfc4514_attribute_name(self) -> str: - """ - The short attribute name (for example "CN") if available, - otherwise the OID dotted string. - """ - return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - - Use short attribute name if available, otherwise fall back to OID - dotted string. - """ - attr_name = ( - attr_name_overrides.get(self.oid) if attr_name_overrides else None - ) - if attr_name is None: - attr_name = self.rfc4514_attribute_name - - return f"{attr_name}={_escape_dn_value(self.value)}" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NameAttribute): - return NotImplemented - - return self.oid == other.oid and self.value == other.value - - def __hash__(self) -> int: - return hash((self.oid, self.value)) - - def __repr__(self) -> str: - return f"" - - -class RelativeDistinguishedName: - def __init__(self, attributes: Iterable[NameAttribute]): - attributes = list(attributes) - if not attributes: - raise ValueError("a relative distinguished name cannot be empty") - if not all(isinstance(x, NameAttribute) for x in attributes): - raise TypeError("attributes must be an iterable of NameAttribute") - - # Keep list and frozenset to preserve attribute order where it matters - self._attributes = attributes - self._attribute_set = frozenset(attributes) - - if len(self._attribute_set) != len(attributes): - raise ValueError("duplicate attributes are not allowed") - - def get_attributes_for_oid( - self, - oid: ObjectIdentifier, - ) -> list[NameAttribute[str | bytes]]: - return [i for i in self if i.oid == oid] - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - - Within each RDN, attributes are joined by '+', although that is rarely - used in certificates. - """ - return "+".join( - attr.rfc4514_string(attr_name_overrides) - for attr in self._attributes - ) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, RelativeDistinguishedName): - return NotImplemented - - return self._attribute_set == other._attribute_set - - def __hash__(self) -> int: - return hash(self._attribute_set) - - def __iter__(self) -> Iterator[NameAttribute]: - return iter(self._attributes) - - def __len__(self) -> int: - return len(self._attributes) - - def __repr__(self) -> str: - return f"" - - -class Name: - @typing.overload - def __init__(self, attributes: Iterable[NameAttribute]) -> None: ... - - @typing.overload - def __init__( - self, attributes: Iterable[RelativeDistinguishedName] - ) -> None: ... - - def __init__( - self, - attributes: Iterable[NameAttribute | RelativeDistinguishedName], - ) -> None: - attributes = list(attributes) - if all(isinstance(x, NameAttribute) for x in attributes): - self._attributes = [ - RelativeDistinguishedName([typing.cast(NameAttribute, x)]) - for x in attributes - ] - elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): - self._attributes = typing.cast( - typing.List[RelativeDistinguishedName], attributes - ) - else: - raise TypeError( - "attributes must be a list of NameAttribute" - " or a list RelativeDistinguishedName" - ) - - @classmethod - def from_rfc4514_string( - cls, - data: str, - attr_name_overrides: _NameOidMap | None = None, - ) -> Name: - return _RFC4514NameParser(data, attr_name_overrides or {}).parse() - - def rfc4514_string( - self, attr_name_overrides: _OidNameMap | None = None - ) -> str: - """ - Format as RFC4514 Distinguished Name string. - For example 'CN=foobar.com,O=Foo Corp,C=US' - - An X.509 name is a two-level structure: a list of sets of attributes. - Each list element is separated by ',' and within each list element, set - elements are separated by '+'. The latter is almost never used in - real world certificates. According to RFC4514 section 2.1 the - RDNSequence must be reversed when converting to string representation. - """ - return ",".join( - attr.rfc4514_string(attr_name_overrides) - for attr in reversed(self._attributes) - ) - - def get_attributes_for_oid( - self, - oid: ObjectIdentifier, - ) -> list[NameAttribute[str | bytes]]: - return [i for i in self if i.oid == oid] - - @property - def rdns(self) -> list[RelativeDistinguishedName]: - return self._attributes - - def public_bytes(self, backend: typing.Any = None) -> bytes: - return rust_x509.encode_name_bytes(self) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Name): - return NotImplemented - - return self._attributes == other._attributes - - def __hash__(self) -> int: - # TODO: this is relatively expensive, if this looks like a bottleneck - # for you, consider optimizing! - return hash(tuple(self._attributes)) - - def __iter__(self) -> Iterator[NameAttribute]: - for rdn in self._attributes: - yield from rdn - - def __len__(self) -> int: - return sum(len(rdn) for rdn in self._attributes) - - def __repr__(self) -> str: - rdns = ",".join(attr.rfc4514_string() for attr in self._attributes) - return f"" - - -class _RFC4514NameParser: - _OID_RE = re.compile(r"(0|([1-9]\d*))(\.(0|([1-9]\d*)))+") - _DESCR_RE = re.compile(r"[a-zA-Z][a-zA-Z\d-]*") - - _PAIR = r"\\([\\ #=\"\+,;<>]|[\da-zA-Z]{2})" - _PAIR_RE = re.compile(_PAIR) - _LUTF1 = r"[\x01-\x1f\x21\x24-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _SUTF1 = r"[\x01-\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _TUTF1 = r"[\x01-\x1F\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" - _UTFMB = rf"[\x80-{chr(sys.maxunicode)}]" - _LEADCHAR = rf"{_LUTF1}|{_UTFMB}" - _STRINGCHAR = rf"{_SUTF1}|{_UTFMB}" - _TRAILCHAR = rf"{_TUTF1}|{_UTFMB}" - _STRING_RE = re.compile( - rf""" - ( - ({_LEADCHAR}|{_PAIR}) - ( - ({_STRINGCHAR}|{_PAIR})* - ({_TRAILCHAR}|{_PAIR}) - )? - )? - """, - re.VERBOSE, - ) - _HEXSTRING_RE = re.compile(r"#([\da-zA-Z]{2})+") - - def __init__(self, data: str, attr_name_overrides: _NameOidMap) -> None: - self._data = data - self._idx = 0 - - self._attr_name_overrides = attr_name_overrides - - def _has_data(self) -> bool: - return self._idx < len(self._data) - - def _peek(self) -> str | None: - if self._has_data(): - return self._data[self._idx] - return None - - def _read_char(self, ch: str) -> None: - if self._peek() != ch: - raise ValueError - self._idx += 1 - - def _read_re(self, pat) -> str: - match = pat.match(self._data, pos=self._idx) - if match is None: - raise ValueError - val = match.group() - self._idx += len(val) - return val - - def parse(self) -> Name: - """ - Parses the `data` string and converts it to a Name. - - According to RFC4514 section 2.1 the RDNSequence must be - reversed when converting to string representation. So, when - we parse it, we need to reverse again to get the RDNs on the - correct order. - """ - - if not self._has_data(): - return Name([]) - - rdns = [self._parse_rdn()] - - while self._has_data(): - self._read_char(",") - rdns.append(self._parse_rdn()) - - return Name(reversed(rdns)) - - def _parse_rdn(self) -> RelativeDistinguishedName: - nas = [self._parse_na()] - while self._peek() == "+": - self._read_char("+") - nas.append(self._parse_na()) - - return RelativeDistinguishedName(nas) - - def _parse_na(self) -> NameAttribute: - try: - oid_value = self._read_re(self._OID_RE) - except ValueError: - name = self._read_re(self._DESCR_RE) - oid = self._attr_name_overrides.get( - name, _NAME_TO_NAMEOID.get(name) - ) - if oid is None: - raise ValueError - else: - oid = ObjectIdentifier(oid_value) - - self._read_char("=") - if self._peek() == "#": - value = self._read_re(self._HEXSTRING_RE) - value = binascii.unhexlify(value[1:]).decode() - else: - raw_value = self._read_re(self._STRING_RE) - value = _unescape_dn_value(raw_value) - - return NameAttribute(oid, value) diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/ocsp.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/ocsp.py deleted file mode 100644 index f61ed80..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/ocsp.py +++ /dev/null @@ -1,379 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import datetime -from collections.abc import Iterable - -from cryptography import utils, x509 -from cryptography.hazmat.bindings._rust import ocsp -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric.types import ( - CertificateIssuerPrivateKeyTypes, -) -from cryptography.x509.base import _reject_duplicate_extension - - -class OCSPResponderEncoding(utils.Enum): - HASH = "By Hash" - NAME = "By Name" - - -class OCSPResponseStatus(utils.Enum): - SUCCESSFUL = 0 - MALFORMED_REQUEST = 1 - INTERNAL_ERROR = 2 - TRY_LATER = 3 - SIG_REQUIRED = 5 - UNAUTHORIZED = 6 - - -_ALLOWED_HASHES = ( - hashes.SHA1, - hashes.SHA224, - hashes.SHA256, - hashes.SHA384, - hashes.SHA512, -) - - -def _verify_algorithm(algorithm: hashes.HashAlgorithm) -> None: - if not isinstance(algorithm, _ALLOWED_HASHES): - raise ValueError( - "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512" - ) - - -class OCSPCertStatus(utils.Enum): - GOOD = 0 - REVOKED = 1 - UNKNOWN = 2 - - -class _SingleResponse: - def __init__( - self, - resp: tuple[x509.Certificate, x509.Certificate] | None, - resp_hash: tuple[bytes, bytes, int] | None, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ): - _verify_algorithm(algorithm) - if not isinstance(this_update, datetime.datetime): - raise TypeError("this_update must be a datetime object") - if next_update is not None and not isinstance( - next_update, datetime.datetime - ): - raise TypeError("next_update must be a datetime object or None") - - self._resp = resp - self._resp_hash = resp_hash - self._algorithm = algorithm - self._this_update = this_update - self._next_update = next_update - - if not isinstance(cert_status, OCSPCertStatus): - raise TypeError( - "cert_status must be an item from the OCSPCertStatus enum" - ) - if cert_status is not OCSPCertStatus.REVOKED: - if revocation_time is not None: - raise ValueError( - "revocation_time can only be provided if the certificate " - "is revoked" - ) - if revocation_reason is not None: - raise ValueError( - "revocation_reason can only be provided if the certificate" - " is revoked" - ) - else: - if not isinstance(revocation_time, datetime.datetime): - raise TypeError("revocation_time must be a datetime object") - - if revocation_reason is not None and not isinstance( - revocation_reason, x509.ReasonFlags - ): - raise TypeError( - "revocation_reason must be an item from the ReasonFlags " - "enum or None" - ) - - self._cert_status = cert_status - self._revocation_time = revocation_time - self._revocation_reason = revocation_reason - - -OCSPRequest = ocsp.OCSPRequest -OCSPResponse = ocsp.OCSPResponse -OCSPSingleResponse = ocsp.OCSPSingleResponse - - -class OCSPRequestBuilder: - def __init__( - self, - request: tuple[ - x509.Certificate, x509.Certificate, hashes.HashAlgorithm - ] - | None = None, - request_hash: tuple[bytes, bytes, int, hashes.HashAlgorithm] - | None = None, - extensions: list[x509.Extension[x509.ExtensionType]] = [], - ) -> None: - self._request = request - self._request_hash = request_hash - self._extensions = extensions - - def add_certificate( - self, - cert: x509.Certificate, - issuer: x509.Certificate, - algorithm: hashes.HashAlgorithm, - ) -> OCSPRequestBuilder: - if self._request is not None or self._request_hash is not None: - raise ValueError("Only one certificate can be added to a request") - - _verify_algorithm(algorithm) - if not isinstance(cert, x509.Certificate) or not isinstance( - issuer, x509.Certificate - ): - raise TypeError("cert and issuer must be a Certificate") - - return OCSPRequestBuilder( - (cert, issuer, algorithm), self._request_hash, self._extensions - ) - - def add_certificate_by_hash( - self, - issuer_name_hash: bytes, - issuer_key_hash: bytes, - serial_number: int, - algorithm: hashes.HashAlgorithm, - ) -> OCSPRequestBuilder: - if self._request is not None or self._request_hash is not None: - raise ValueError("Only one certificate can be added to a request") - - if not isinstance(serial_number, int): - raise TypeError("serial_number must be an integer") - - _verify_algorithm(algorithm) - utils._check_bytes("issuer_name_hash", issuer_name_hash) - utils._check_bytes("issuer_key_hash", issuer_key_hash) - if algorithm.digest_size != len( - issuer_name_hash - ) or algorithm.digest_size != len(issuer_key_hash): - raise ValueError( - "issuer_name_hash and issuer_key_hash must be the same length " - "as the digest size of the algorithm" - ) - - return OCSPRequestBuilder( - self._request, - (issuer_name_hash, issuer_key_hash, serial_number, algorithm), - self._extensions, - ) - - def add_extension( - self, extval: x509.ExtensionType, critical: bool - ) -> OCSPRequestBuilder: - if not isinstance(extval, x509.ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = x509.Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return OCSPRequestBuilder( - self._request, self._request_hash, [*self._extensions, extension] - ) - - def build(self) -> OCSPRequest: - if self._request is None and self._request_hash is None: - raise ValueError("You must add a certificate before building") - - return ocsp.create_ocsp_request(self) - - -class OCSPResponseBuilder: - def __init__( - self, - response: _SingleResponse | None = None, - responder_id: tuple[x509.Certificate, OCSPResponderEncoding] - | None = None, - certs: list[x509.Certificate] | None = None, - extensions: list[x509.Extension[x509.ExtensionType]] = [], - ): - self._response = response - self._responder_id = responder_id - self._certs = certs - self._extensions = extensions - - def add_response( - self, - cert: x509.Certificate, - issuer: x509.Certificate, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ) -> OCSPResponseBuilder: - if self._response is not None: - raise ValueError("Only one response per OCSPResponse.") - - if not isinstance(cert, x509.Certificate) or not isinstance( - issuer, x509.Certificate - ): - raise TypeError("cert and issuer must be a Certificate") - - singleresp = _SingleResponse( - (cert, issuer), - None, - algorithm, - cert_status, - this_update, - next_update, - revocation_time, - revocation_reason, - ) - return OCSPResponseBuilder( - singleresp, - self._responder_id, - self._certs, - self._extensions, - ) - - def add_response_by_hash( - self, - issuer_name_hash: bytes, - issuer_key_hash: bytes, - serial_number: int, - algorithm: hashes.HashAlgorithm, - cert_status: OCSPCertStatus, - this_update: datetime.datetime, - next_update: datetime.datetime | None, - revocation_time: datetime.datetime | None, - revocation_reason: x509.ReasonFlags | None, - ) -> OCSPResponseBuilder: - if self._response is not None: - raise ValueError("Only one response per OCSPResponse.") - - if not isinstance(serial_number, int): - raise TypeError("serial_number must be an integer") - - utils._check_bytes("issuer_name_hash", issuer_name_hash) - utils._check_bytes("issuer_key_hash", issuer_key_hash) - _verify_algorithm(algorithm) - if algorithm.digest_size != len( - issuer_name_hash - ) or algorithm.digest_size != len(issuer_key_hash): - raise ValueError( - "issuer_name_hash and issuer_key_hash must be the same length " - "as the digest size of the algorithm" - ) - - singleresp = _SingleResponse( - None, - (issuer_name_hash, issuer_key_hash, serial_number), - algorithm, - cert_status, - this_update, - next_update, - revocation_time, - revocation_reason, - ) - return OCSPResponseBuilder( - singleresp, - self._responder_id, - self._certs, - self._extensions, - ) - - def responder_id( - self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate - ) -> OCSPResponseBuilder: - if self._responder_id is not None: - raise ValueError("responder_id can only be set once") - if not isinstance(responder_cert, x509.Certificate): - raise TypeError("responder_cert must be a Certificate") - if not isinstance(encoding, OCSPResponderEncoding): - raise TypeError( - "encoding must be an element from OCSPResponderEncoding" - ) - - return OCSPResponseBuilder( - self._response, - (responder_cert, encoding), - self._certs, - self._extensions, - ) - - def certificates( - self, certs: Iterable[x509.Certificate] - ) -> OCSPResponseBuilder: - if self._certs is not None: - raise ValueError("certificates may only be set once") - certs = list(certs) - if len(certs) == 0: - raise ValueError("certs must not be an empty list") - if not all(isinstance(x, x509.Certificate) for x in certs): - raise TypeError("certs must be a list of Certificates") - return OCSPResponseBuilder( - self._response, - self._responder_id, - certs, - self._extensions, - ) - - def add_extension( - self, extval: x509.ExtensionType, critical: bool - ) -> OCSPResponseBuilder: - if not isinstance(extval, x509.ExtensionType): - raise TypeError("extension must be an ExtensionType") - - extension = x509.Extension(extval.oid, critical, extval) - _reject_duplicate_extension(extension, self._extensions) - - return OCSPResponseBuilder( - self._response, - self._responder_id, - self._certs, - [*self._extensions, extension], - ) - - def sign( - self, - private_key: CertificateIssuerPrivateKeyTypes, - algorithm: hashes.HashAlgorithm | None, - ) -> OCSPResponse: - if self._response is None: - raise ValueError("You must add a response before signing") - if self._responder_id is None: - raise ValueError("You must add a responder_id before signing") - - return ocsp.create_ocsp_response( - OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm - ) - - @classmethod - def build_unsuccessful( - cls, response_status: OCSPResponseStatus - ) -> OCSPResponse: - if not isinstance(response_status, OCSPResponseStatus): - raise TypeError( - "response_status must be an item from OCSPResponseStatus" - ) - if response_status is OCSPResponseStatus.SUCCESSFUL: - raise ValueError("response_status cannot be SUCCESSFUL") - - return ocsp.create_ocsp_response(response_status, None, None, None) - - -load_der_ocsp_request = ocsp.load_der_ocsp_request -load_der_ocsp_response = ocsp.load_der_ocsp_response diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/oid.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/oid.py deleted file mode 100644 index 520fc7a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/oid.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -from cryptography.hazmat._oid import ( - AttributeOID, - AuthorityInformationAccessOID, - CertificatePoliciesOID, - CRLEntryExtensionOID, - ExtendedKeyUsageOID, - ExtensionOID, - NameOID, - ObjectIdentifier, - OCSPExtensionOID, - OtherNameFormOID, - PublicKeyAlgorithmOID, - SignatureAlgorithmOID, - SubjectInformationAccessOID, -) - -__all__ = [ - "AttributeOID", - "AuthorityInformationAccessOID", - "CRLEntryExtensionOID", - "CertificatePoliciesOID", - "ExtendedKeyUsageOID", - "ExtensionOID", - "NameOID", - "OCSPExtensionOID", - "ObjectIdentifier", - "OtherNameFormOID", - "PublicKeyAlgorithmOID", - "SignatureAlgorithmOID", - "SubjectInformationAccessOID", -] diff --git a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/verification.py b/backend/venv39/lib/python3.9/site-packages/cryptography/x509/verification.py deleted file mode 100644 index 2db4324..0000000 --- a/backend/venv39/lib/python3.9/site-packages/cryptography/x509/verification.py +++ /dev/null @@ -1,34 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.bindings._rust import x509 as rust_x509 -from cryptography.x509.general_name import DNSName, IPAddress - -__all__ = [ - "ClientVerifier", - "Criticality", - "ExtensionPolicy", - "Policy", - "PolicyBuilder", - "ServerVerifier", - "Store", - "Subject", - "VerificationError", - "VerifiedClient", -] - -Store = rust_x509.Store -Subject = typing.Union[DNSName, IPAddress] -VerifiedClient = rust_x509.VerifiedClient -ClientVerifier = rust_x509.ClientVerifier -ServerVerifier = rust_x509.ServerVerifier -PolicyBuilder = rust_x509.PolicyBuilder -Policy = rust_x509.Policy -ExtensionPolicy = rust_x509.ExtensionPolicy -Criticality = rust_x509.Criticality -VerificationError = rust_x509.VerificationError diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/LICENSE deleted file mode 100644 index e06d208..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/METADATA deleted file mode 100644 index 9312e8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/METADATA +++ /dev/null @@ -1,184 +0,0 @@ -Metadata-Version: 2.1 -Name: distro -Version: 1.9.0 -Summary: Distro - an OS platform information API -Home-page: https://github.com/python-distro/distro -Author: Nir Cohen -Author-email: nir36g@gmail.com -License: Apache License, Version 2.0 -Platform: All -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: BSD :: FreeBSD -Classifier: Operating System :: POSIX :: BSD :: NetBSD -Classifier: Operating System :: POSIX :: BSD :: OpenBSD -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.6 -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: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Operating System -Requires-Python: >=3.6 -Description-Content-Type: text/markdown -License-File: LICENSE - -Distro - an OS platform information API -======================================= - -[![CI Status](https://github.com/python-distro/distro/workflows/CI/badge.svg)](https://github.com/python-distro/distro/actions/workflows/ci.yaml) -[![PyPI version](http://img.shields.io/pypi/v/distro.svg)](https://pypi.python.org/pypi/distro) -[![Supported Python Versions](https://img.shields.io/pypi/pyversions/distro.svg)](https://img.shields.io/pypi/pyversions/distro.svg) -[![Code Coverage](https://codecov.io/github/python-distro/distro/coverage.svg?branch=master)](https://codecov.io/github/python-distro/distro?branch=master) -[![Is Wheel](https://img.shields.io/pypi/wheel/distro.svg?style=flat)](https://pypi.python.org/pypi/distro) -[![Latest Github Release](https://readthedocs.org/projects/distro/badge/?version=stable)](http://distro.readthedocs.io/en/latest/) - -`distro` provides information about the -OS distribution it runs on, such as a reliable machine-readable ID, or -version information. - -It is the recommended replacement for Python's original -[`platform.linux_distribution`](https://docs.python.org/3.7/library/platform.html#platform.linux_distribution) -function (removed in Python 3.8). It also provides much more functionality -which isn't necessarily Python bound, like a command-line interface. - -Distro currently supports Linux and BSD based systems but [Windows and OS X support](https://github.com/python-distro/distro/issues/177) is also planned. - -For Python 2.6 support, see https://github.com/python-distro/distro/tree/python2.6-support - -## Installation - -Installation of the latest released version from PyPI: - -```shell -pip install distro -``` - -Installation of the latest development version: - -```shell -pip install https://github.com/python-distro/distro/archive/master.tar.gz -``` - -To use as a standalone script, download `distro.py` directly: - -```shell -curl -O https://raw.githubusercontent.com/python-distro/distro/master/src/distro/distro.py -python distro.py -``` - -``distro`` is safe to vendor within projects that do not wish to add -dependencies. - -```shell -cd myproject -curl -O https://raw.githubusercontent.com/python-distro/distro/master/src/distro/distro.py -``` - -## Usage - -```bash -$ distro -Name: Antergos Linux -Version: 2015.10 (ISO-Rolling) -Codename: ISO-Rolling - -$ distro -j -{ - "codename": "ISO-Rolling", - "id": "antergos", - "like": "arch", - "version": "16.9", - "version_parts": { - "build_number": "", - "major": "16", - "minor": "9" - } -} - - -$ python ->>> import distro ->>> distro.name(pretty=True) -'CentOS Linux 8' ->>> distro.id() -'centos' ->>> distro.version(best=True) -'8.4.2105' -``` - - -## Documentation - -On top of the aforementioned API, several more functions are available. For a complete description of the -API, see the [latest API documentation](http://distro.readthedocs.org/en/latest/). - -## Background - -An alternative implementation became necessary because Python 3.5 deprecated -this function, and Python 3.8 removed it altogether. Its predecessor function -[`platform.dist`](https://docs.python.org/3.7/library/platform.html#platform.dist) -was already deprecated since Python 2.6 and removed in Python 3.8. Still, there -are many cases in which access to that information is needed. See [Python issue -1322](https://bugs.python.org/issue1322) for more information. - -The `distro` package implements a robust and inclusive way of retrieving the -information about a distribution based on new standards and old methods, -namely from these data sources (from high to low precedence): - -* The os-release file `/etc/os-release` if present, with a fall-back on `/usr/lib/os-release` if needed. -* The output of the `lsb_release` command, if available. -* The distro release file (`/etc/*(-|_)(release|version)`), if present. -* The `uname` command for BSD based distrubtions. - - -## Python and Distribution Support - -`distro` is supported and tested on Python 3.6+ and PyPy and on any -distribution that provides one or more of the data sources covered. - -This package is tested with test data that mimics the exact behavior of the data sources of [a number of Linux distributions](https://github.com/python-distro/distro/tree/master/tests/resources/distros). - - -## Testing - -```shell -git clone git@github.com:python-distro/distro.git -cd distro -pip install tox -tox -``` - - -## Contributions - -Pull requests are always welcome to deal with specific distributions or just -for general merriment. - -See [CONTRIBUTIONS](https://github.com/python-distro/distro/blob/master/CONTRIBUTING.md) for contribution info. - -Reference implementations for supporting additional distributions and file -formats can be found here: - -* https://github.com/saltstack/salt/blob/develop/salt/grains/core.py#L1172 -* https://github.com/chef/ohai/blob/master/lib/ohai/plugins/linux/platform.rb -* https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py -* https://github.com/puppetlabs/facter/blob/master/lib/src/facts/linux/os_linux.cc - -## Package manager distributions - -* https://src.fedoraproject.org/rpms/python-distro -* https://www.archlinux.org/packages/community/any/python-distro/ -* https://launchpad.net/ubuntu/+source/python-distro -* https://packages.debian.org/stable/python3-distro -* https://packages.gentoo.org/packages/dev-python/distro -* https://pkgs.org/download/python3-distro -* https://slackbuilds.org/repository/14.2/python/python-distro/ diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/RECORD deleted file mode 100644 index dd9c21d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/RECORD +++ /dev/null @@ -1,15 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/distro/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/distro/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/distro/distro.cpython-39.pyc,, -../../../bin/distro,sha256=Z0v_fuMHowQCiwENtaTLrlVLPuNEn1ndfY5Q7xIkxgA,266 -distro-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -distro-1.9.0.dist-info/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325 -distro-1.9.0.dist-info/METADATA,sha256=MWMqst5VkRMQkbM5e9zfeXcYV52Fp1GG8Gg53QwJ6B0,6791 -distro-1.9.0.dist-info/RECORD,, -distro-1.9.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 -distro-1.9.0.dist-info/entry_points.txt,sha256=3ObjqQMbh1xeQQwsWtgbfDNDMDD-EbggR1Oj_z8s9hc,46 -distro-1.9.0.dist-info/top_level.txt,sha256=ikde_V_XEdSBqaGd5tEriN_wzYHLgTX_zVtlsGLHvwQ,7 -distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981 -distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64 -distro/distro.py,sha256=XqbefacAhDT4zr_trnbA15eY8vdK4GTghgmvUGrEM_4,49430 -distro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/WHEEL deleted file mode 100644 index 98c0d20..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.42.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/entry_points.txt deleted file mode 100644 index 08d29c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -distro = distro.distro:main diff --git a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/top_level.txt deleted file mode 100644 index 0e09331..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro-1.9.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -distro diff --git a/backend/venv39/lib/python3.9/site-packages/distro/__init__.py b/backend/venv39/lib/python3.9/site-packages/distro/__init__.py deleted file mode 100644 index 7686fe8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -from .distro import ( - NORMALIZED_DISTRO_ID, - NORMALIZED_LSB_ID, - NORMALIZED_OS_ID, - LinuxDistribution, - __version__, - build_number, - codename, - distro_release_attr, - distro_release_info, - id, - info, - like, - linux_distribution, - lsb_release_attr, - lsb_release_info, - major_version, - minor_version, - name, - os_release_attr, - os_release_info, - uname_attr, - uname_info, - version, - version_parts, -) - -__all__ = [ - "NORMALIZED_DISTRO_ID", - "NORMALIZED_LSB_ID", - "NORMALIZED_OS_ID", - "LinuxDistribution", - "build_number", - "codename", - "distro_release_attr", - "distro_release_info", - "id", - "info", - "like", - "linux_distribution", - "lsb_release_attr", - "lsb_release_info", - "major_version", - "minor_version", - "name", - "os_release_attr", - "os_release_info", - "uname_attr", - "uname_info", - "version", - "version_parts", -] - -__version__ = __version__ diff --git a/backend/venv39/lib/python3.9/site-packages/distro/__main__.py b/backend/venv39/lib/python3.9/site-packages/distro/__main__.py deleted file mode 100644 index 0c01d5b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .distro import main - -if __name__ == "__main__": - main() diff --git a/backend/venv39/lib/python3.9/site-packages/distro/distro.py b/backend/venv39/lib/python3.9/site-packages/distro/distro.py deleted file mode 100644 index 78ccdfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distro/distro.py +++ /dev/null @@ -1,1403 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015-2021 Nir Cohen -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -The ``distro`` package (``distro`` stands for Linux Distribution) provides -information about the Linux distribution it runs on, such as a reliable -machine-readable distro ID, or version information. - -It is the recommended replacement for Python's original -:py:func:`platform.linux_distribution` function, but it provides much more -functionality. An alternative implementation became necessary because Python -3.5 deprecated this function, and Python 3.8 removed it altogether. Its -predecessor function :py:func:`platform.dist` was already deprecated since -Python 2.6 and removed in Python 3.8. Still, there are many cases in which -access to OS distribution information is needed. See `Python issue 1322 -`_ for more information. -""" - -import argparse -import json -import logging -import os -import re -import shlex -import subprocess -import sys -import warnings -from typing import ( - Any, - Callable, - Dict, - Iterable, - Optional, - Sequence, - TextIO, - Tuple, - Type, -) - -try: - from typing import TypedDict -except ImportError: - # Python 3.7 - TypedDict = dict - -__version__ = "1.9.0" - - -class VersionDict(TypedDict): - major: str - minor: str - build_number: str - - -class InfoDict(TypedDict): - id: str - version: str - version_parts: VersionDict - like: str - codename: str - - -_UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc") -_UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib") -_OS_RELEASE_BASENAME = "os-release" - -#: Translation table for normalizing the "ID" attribute defined in os-release -#: files, for use by the :func:`distro.id` method. -#: -#: * Key: Value as defined in the os-release file, translated to lower case, -#: with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_OS_ID = { - "ol": "oracle", # Oracle Linux - "opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap -} - -#: Translation table for normalizing the "Distributor ID" attribute returned by -#: the lsb_release command, for use by the :func:`distro.id` method. -#: -#: * Key: Value as returned by the lsb_release command, translated to lower -#: case, with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_LSB_ID = { - "enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4 - "enterpriseenterpriseserver": "oracle", # Oracle Linux 5 - "redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation - "redhatenterpriseserver": "rhel", # RHEL 6, 7 Server - "redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode -} - -#: Translation table for normalizing the distro ID derived from the file name -#: of distro release files, for use by the :func:`distro.id` method. -#: -#: * Key: Value as derived from the file name of a distro release file, -#: translated to lower case, with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_DISTRO_ID = { - "redhat": "rhel", # RHEL 6.x, 7.x -} - -# Pattern for content of distro release file (reversed) -_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( - r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)" -) - -# Pattern for base file name of distro release file -_DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$") - -# Base file names to be looked up for if _UNIXCONFDIR is not readable. -_DISTRO_RELEASE_BASENAMES = [ - "SuSE-release", - "altlinux-release", - "arch-release", - "base-release", - "centos-release", - "fedora-release", - "gentoo-release", - "mageia-release", - "mandrake-release", - "mandriva-release", - "mandrivalinux-release", - "manjaro-release", - "oracle-release", - "redhat-release", - "rocky-release", - "sl-release", - "slackware-version", -] - -# Base file names to be ignored when searching for distro release file -_DISTRO_RELEASE_IGNORE_BASENAMES = ( - "debian_version", - "lsb-release", - "oem-release", - _OS_RELEASE_BASENAME, - "system-release", - "plesk-release", - "iredmail-release", - "board-release", - "ec2_version", -) - - -def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]: - """ - .. deprecated:: 1.6.0 - - :func:`distro.linux_distribution()` is deprecated. It should only be - used as a compatibility shim with Python's - :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`, - :func:`distro.version` and :func:`distro.name` instead. - - Return information about the current OS distribution as a tuple - ``(id_name, version, codename)`` with items as follows: - - * ``id_name``: If *full_distribution_name* is false, the result of - :func:`distro.id`. Otherwise, the result of :func:`distro.name`. - - * ``version``: The result of :func:`distro.version`. - - * ``codename``: The extra item (usually in parentheses) after the - os-release version number, or the result of :func:`distro.codename`. - - The interface of this function is compatible with the original - :py:func:`platform.linux_distribution` function, supporting a subset of - its parameters. - - The data it returns may not exactly be the same, because it uses more data - sources than the original function, and that may lead to different data if - the OS distribution is not consistent across multiple data sources it - provides (there are indeed such distributions ...). - - Another reason for differences is the fact that the :func:`distro.id` - method normalizes the distro ID string to a reliable machine-readable value - for a number of popular OS distributions. - """ - warnings.warn( - "distro.linux_distribution() is deprecated. It should only be used as a " - "compatibility shim with Python's platform.linux_distribution(). Please use " - "distro.id(), distro.version() and distro.name() instead.", - DeprecationWarning, - stacklevel=2, - ) - return _distro.linux_distribution(full_distribution_name) - - -def id() -> str: - """ - Return the distro ID of the current distribution, as a - machine-readable string. - - For a number of OS distributions, the returned distro ID value is - *reliable*, in the sense that it is documented and that it does not change - across releases of the distribution. - - This package maintains the following reliable distro ID values: - - ============== ========================================= - Distro ID Distribution - ============== ========================================= - "ubuntu" Ubuntu - "debian" Debian - "rhel" RedHat Enterprise Linux - "centos" CentOS - "fedora" Fedora - "sles" SUSE Linux Enterprise Server - "opensuse" openSUSE - "amzn" Amazon Linux - "arch" Arch Linux - "buildroot" Buildroot - "cloudlinux" CloudLinux OS - "exherbo" Exherbo Linux - "gentoo" GenToo Linux - "ibm_powerkvm" IBM PowerKVM - "kvmibm" KVM for IBM z Systems - "linuxmint" Linux Mint - "mageia" Mageia - "mandriva" Mandriva Linux - "parallels" Parallels - "pidora" Pidora - "raspbian" Raspbian - "oracle" Oracle Linux (and Oracle Enterprise Linux) - "scientific" Scientific Linux - "slackware" Slackware - "xenserver" XenServer - "openbsd" OpenBSD - "netbsd" NetBSD - "freebsd" FreeBSD - "midnightbsd" MidnightBSD - "rocky" Rocky Linux - "aix" AIX - "guix" Guix System - "altlinux" ALT Linux - ============== ========================================= - - If you have a need to get distros for reliable IDs added into this set, - or if you find that the :func:`distro.id` function returns a different - distro ID for one of the listed distros, please create an issue in the - `distro issue tracker`_. - - **Lookup hierarchy and transformations:** - - First, the ID is obtained from the following sources, in the specified - order. The first available and non-empty value is used: - - * the value of the "ID" attribute of the os-release file, - - * the value of the "Distributor ID" attribute returned by the lsb_release - command, - - * the first part of the file name of the distro release file, - - The so determined ID value then passes the following transformations, - before it is returned by this method: - - * it is translated to lower case, - - * blanks (which should not be there anyway) are translated to underscores, - - * a normalization of the ID is performed, based upon - `normalization tables`_. The purpose of this normalization is to ensure - that the ID is as reliable as possible, even across incompatible changes - in the OS distributions. A common reason for an incompatible change is - the addition of an os-release file, or the addition of the lsb_release - command, with ID values that differ from what was previously determined - from the distro release file name. - """ - return _distro.id() - - -def name(pretty: bool = False) -> str: - """ - Return the name of the current OS distribution, as a human-readable - string. - - If *pretty* is false, the name is returned without version or codename. - (e.g. "CentOS Linux") - - If *pretty* is true, the version and codename are appended. - (e.g. "CentOS Linux 7.1.1503 (Core)") - - **Lookup hierarchy:** - - The name is obtained from the following sources, in the specified order. - The first available and non-empty value is used: - - * If *pretty* is false: - - - the value of the "NAME" attribute of the os-release file, - - - the value of the "Distributor ID" attribute returned by the lsb_release - command, - - - the value of the "" field of the distro release file. - - * If *pretty* is true: - - - the value of the "PRETTY_NAME" attribute of the os-release file, - - - the value of the "Description" attribute returned by the lsb_release - command, - - - the value of the "" field of the distro release file, appended - with the value of the pretty version ("" and "" - fields) of the distro release file, if available. - """ - return _distro.name(pretty) - - -def version(pretty: bool = False, best: bool = False) -> str: - """ - Return the version of the current OS distribution, as a human-readable - string. - - If *pretty* is false, the version is returned without codename (e.g. - "7.0"). - - If *pretty* is true, the codename in parenthesis is appended, if the - codename is non-empty (e.g. "7.0 (Maipo)"). - - Some distributions provide version numbers with different precisions in - the different sources of distribution information. Examining the different - sources in a fixed priority order does not always yield the most precise - version (e.g. for Debian 8.2, or CentOS 7.1). - - Some other distributions may not provide this kind of information. In these - cases, an empty string would be returned. This behavior can be observed - with rolling releases distributions (e.g. Arch Linux). - - The *best* parameter can be used to control the approach for the returned - version: - - If *best* is false, the first non-empty version number in priority order of - the examined sources is returned. - - If *best* is true, the most precise version number out of all examined - sources is returned. - - **Lookup hierarchy:** - - In all cases, the version number is obtained from the following sources. - If *best* is false, this order represents the priority order: - - * the value of the "VERSION_ID" attribute of the os-release file, - * the value of the "Release" attribute returned by the lsb_release - command, - * the version number parsed from the "" field of the first line - of the distro release file, - * the version number parsed from the "PRETTY_NAME" attribute of the - os-release file, if it follows the format of the distro release files. - * the version number parsed from the "Description" attribute returned by - the lsb_release command, if it follows the format of the distro release - files. - """ - return _distro.version(pretty, best) - - -def version_parts(best: bool = False) -> Tuple[str, str, str]: - """ - Return the version of the current OS distribution as a tuple - ``(major, minor, build_number)`` with items as follows: - - * ``major``: The result of :func:`distro.major_version`. - - * ``minor``: The result of :func:`distro.minor_version`. - - * ``build_number``: The result of :func:`distro.build_number`. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.version_parts(best) - - -def major_version(best: bool = False) -> str: - """ - Return the major version of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The major version is the first - part of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.major_version(best) - - -def minor_version(best: bool = False) -> str: - """ - Return the minor version of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The minor version is the second - part of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.minor_version(best) - - -def build_number(best: bool = False) -> str: - """ - Return the build number of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The build number is the third part - of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.build_number(best) - - -def like() -> str: - """ - Return a space-separated list of distro IDs of distributions that are - closely related to the current OS distribution in regards to packaging - and programming interfaces, for example distributions the current - distribution is a derivative from. - - **Lookup hierarchy:** - - This information item is only provided by the os-release file. - For details, see the description of the "ID_LIKE" attribute in the - `os-release man page - `_. - """ - return _distro.like() - - -def codename() -> str: - """ - Return the codename for the release of the current OS distribution, - as a string. - - If the distribution does not have a codename, an empty string is returned. - - Note that the returned codename is not always really a codename. For - example, openSUSE returns "x86_64". This function does not handle such - cases in any special way and just returns the string it finds, if any. - - **Lookup hierarchy:** - - * the codename within the "VERSION" attribute of the os-release file, if - provided, - - * the value of the "Codename" attribute returned by the lsb_release - command, - - * the value of the "" field of the distro release file. - """ - return _distro.codename() - - -def info(pretty: bool = False, best: bool = False) -> InfoDict: - """ - Return certain machine-readable information items about the current OS - distribution in a dictionary, as shown in the following example: - - .. sourcecode:: python - - { - 'id': 'rhel', - 'version': '7.0', - 'version_parts': { - 'major': '7', - 'minor': '0', - 'build_number': '' - }, - 'like': 'fedora', - 'codename': 'Maipo' - } - - The dictionary structure and keys are always the same, regardless of which - information items are available in the underlying data sources. The values - for the various keys are as follows: - - * ``id``: The result of :func:`distro.id`. - - * ``version``: The result of :func:`distro.version`. - - * ``version_parts -> major``: The result of :func:`distro.major_version`. - - * ``version_parts -> minor``: The result of :func:`distro.minor_version`. - - * ``version_parts -> build_number``: The result of - :func:`distro.build_number`. - - * ``like``: The result of :func:`distro.like`. - - * ``codename``: The result of :func:`distro.codename`. - - For a description of the *pretty* and *best* parameters, see the - :func:`distro.version` method. - """ - return _distro.info(pretty, best) - - -def os_release_info() -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information items - from the os-release file data source of the current OS distribution. - - See `os-release file`_ for details about these information items. - """ - return _distro.os_release_info() - - -def lsb_release_info() -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information items - from the lsb_release command data source of the current OS distribution. - - See `lsb_release command output`_ for details about these information - items. - """ - return _distro.lsb_release_info() - - -def distro_release_info() -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information items - from the distro release file data source of the current OS distribution. - - See `distro release file`_ for details about these information items. - """ - return _distro.distro_release_info() - - -def uname_info() -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information items - from the distro release file data source of the current OS distribution. - """ - return _distro.uname_info() - - -def os_release_attr(attribute: str) -> str: - """ - Return a single named information item from the os-release file data source - of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `os-release file`_ for details about these information items. - """ - return _distro.os_release_attr(attribute) - - -def lsb_release_attr(attribute: str) -> str: - """ - Return a single named information item from the lsb_release command output - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `lsb_release command output`_ for details about these information - items. - """ - return _distro.lsb_release_attr(attribute) - - -def distro_release_attr(attribute: str) -> str: - """ - Return a single named information item from the distro release file - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `distro release file`_ for details about these information items. - """ - return _distro.distro_release_attr(attribute) - - -def uname_attr(attribute: str) -> str: - """ - Return a single named information item from the distro release file - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - """ - return _distro.uname_attr(attribute) - - -try: - from functools import cached_property -except ImportError: - # Python < 3.8 - class cached_property: # type: ignore - """A version of @property which caches the value. On access, it calls the - underlying function and sets the value in `__dict__` so future accesses - will not re-call the property. - """ - - def __init__(self, f: Callable[[Any], Any]) -> None: - self._fname = f.__name__ - self._f = f - - def __get__(self, obj: Any, owner: Type[Any]) -> Any: - assert obj is not None, f"call {self._fname} on an instance" - ret = obj.__dict__[self._fname] = self._f(obj) - return ret - - -class LinuxDistribution: - """ - Provides information about a OS distribution. - - This package creates a private module-global instance of this class with - default initialization arguments, that is used by the - `consolidated accessor functions`_ and `single source accessor functions`_. - By using default initialization arguments, that module-global instance - returns data about the current OS distribution (i.e. the distro this - package runs on). - - Normally, it is not necessary to create additional instances of this class. - However, in situations where control is needed over the exact data sources - that are used, instances of this class can be created with a specific - distro release file, or a specific os-release file, or without invoking the - lsb_release command. - """ - - def __init__( - self, - include_lsb: Optional[bool] = None, - os_release_file: str = "", - distro_release_file: str = "", - include_uname: Optional[bool] = None, - root_dir: Optional[str] = None, - include_oslevel: Optional[bool] = None, - ) -> None: - """ - The initialization method of this class gathers information from the - available data sources, and stores that in private instance attributes. - Subsequent access to the information items uses these private instance - attributes, so that the data sources are read only once. - - Parameters: - - * ``include_lsb`` (bool): Controls whether the - `lsb_release command output`_ is included as a data source. - - If the lsb_release command is not available in the program execution - path, the data source for the lsb_release command will be empty. - - * ``os_release_file`` (string): The path name of the - `os-release file`_ that is to be used as a data source. - - An empty string (the default) will cause the default path name to - be used (see `os-release file`_ for details). - - If the specified or defaulted os-release file does not exist, the - data source for the os-release file will be empty. - - * ``distro_release_file`` (string): The path name of the - `distro release file`_ that is to be used as a data source. - - An empty string (the default) will cause a default search algorithm - to be used (see `distro release file`_ for details). - - If the specified distro release file does not exist, or if no default - distro release file can be found, the data source for the distro - release file will be empty. - - * ``include_uname`` (bool): Controls whether uname command output is - included as a data source. If the uname command is not available in - the program execution path the data source for the uname command will - be empty. - - * ``root_dir`` (string): The absolute path to the root directory to use - to find distro-related information files. Note that ``include_*`` - parameters must not be enabled in combination with ``root_dir``. - - * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command - output is included as a data source. If the oslevel command is not - available in the program execution path the data source will be - empty. - - Public instance attributes: - - * ``os_release_file`` (string): The path name of the - `os-release file`_ that is actually used as a data source. The - empty string if no distro release file is used as a data source. - - * ``distro_release_file`` (string): The path name of the - `distro release file`_ that is actually used as a data source. The - empty string if no distro release file is used as a data source. - - * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. - This controls whether the lsb information will be loaded. - - * ``include_uname`` (bool): The result of the ``include_uname`` - parameter. This controls whether the uname information will - be loaded. - - * ``include_oslevel`` (bool): The result of the ``include_oslevel`` - parameter. This controls whether (AIX) oslevel information will be - loaded. - - * ``root_dir`` (string): The result of the ``root_dir`` parameter. - The absolute path to the root directory to use to find distro-related - information files. - - Raises: - - * :py:exc:`ValueError`: Initialization parameters combination is not - supported. - - * :py:exc:`OSError`: Some I/O issue with an os-release file or distro - release file. - - * :py:exc:`UnicodeError`: A data source has unexpected characters or - uses an unexpected encoding. - """ - self.root_dir = root_dir - self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR - self.usr_lib_dir = ( - os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR - ) - - if os_release_file: - self.os_release_file = os_release_file - else: - etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME) - usr_lib_os_release_file = os.path.join( - self.usr_lib_dir, _OS_RELEASE_BASENAME - ) - - # NOTE: The idea is to respect order **and** have it set - # at all times for API backwards compatibility. - if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile( - usr_lib_os_release_file - ): - self.os_release_file = etc_dir_os_release_file - else: - self.os_release_file = usr_lib_os_release_file - - self.distro_release_file = distro_release_file or "" # updated later - - is_root_dir_defined = root_dir is not None - if is_root_dir_defined and (include_lsb or include_uname or include_oslevel): - raise ValueError( - "Including subprocess data sources from specific root_dir is disallowed" - " to prevent false information" - ) - self.include_lsb = ( - include_lsb if include_lsb is not None else not is_root_dir_defined - ) - self.include_uname = ( - include_uname if include_uname is not None else not is_root_dir_defined - ) - self.include_oslevel = ( - include_oslevel if include_oslevel is not None else not is_root_dir_defined - ) - - def __repr__(self) -> str: - """Return repr of all info""" - return ( - "LinuxDistribution(" - "os_release_file={self.os_release_file!r}, " - "distro_release_file={self.distro_release_file!r}, " - "include_lsb={self.include_lsb!r}, " - "include_uname={self.include_uname!r}, " - "include_oslevel={self.include_oslevel!r}, " - "root_dir={self.root_dir!r}, " - "_os_release_info={self._os_release_info!r}, " - "_lsb_release_info={self._lsb_release_info!r}, " - "_distro_release_info={self._distro_release_info!r}, " - "_uname_info={self._uname_info!r}, " - "_oslevel_info={self._oslevel_info!r})".format(self=self) - ) - - def linux_distribution( - self, full_distribution_name: bool = True - ) -> Tuple[str, str, str]: - """ - Return information about the OS distribution that is compatible - with Python's :func:`platform.linux_distribution`, supporting a subset - of its parameters. - - For details, see :func:`distro.linux_distribution`. - """ - return ( - self.name() if full_distribution_name else self.id(), - self.version(), - self._os_release_info.get("release_codename") or self.codename(), - ) - - def id(self) -> str: - """Return the distro ID of the OS distribution, as a string. - - For details, see :func:`distro.id`. - """ - - def normalize(distro_id: str, table: Dict[str, str]) -> str: - distro_id = distro_id.lower().replace(" ", "_") - return table.get(distro_id, distro_id) - - distro_id = self.os_release_attr("id") - if distro_id: - return normalize(distro_id, NORMALIZED_OS_ID) - - distro_id = self.lsb_release_attr("distributor_id") - if distro_id: - return normalize(distro_id, NORMALIZED_LSB_ID) - - distro_id = self.distro_release_attr("id") - if distro_id: - return normalize(distro_id, NORMALIZED_DISTRO_ID) - - distro_id = self.uname_attr("id") - if distro_id: - return normalize(distro_id, NORMALIZED_DISTRO_ID) - - return "" - - def name(self, pretty: bool = False) -> str: - """ - Return the name of the OS distribution, as a string. - - For details, see :func:`distro.name`. - """ - name = ( - self.os_release_attr("name") - or self.lsb_release_attr("distributor_id") - or self.distro_release_attr("name") - or self.uname_attr("name") - ) - if pretty: - name = self.os_release_attr("pretty_name") or self.lsb_release_attr( - "description" - ) - if not name: - name = self.distro_release_attr("name") or self.uname_attr("name") - version = self.version(pretty=True) - if version: - name = f"{name} {version}" - return name or "" - - def version(self, pretty: bool = False, best: bool = False) -> str: - """ - Return the version of the OS distribution, as a string. - - For details, see :func:`distro.version`. - """ - versions = [ - self.os_release_attr("version_id"), - self.lsb_release_attr("release"), - self.distro_release_attr("version_id"), - self._parse_distro_release_content(self.os_release_attr("pretty_name")).get( - "version_id", "" - ), - self._parse_distro_release_content( - self.lsb_release_attr("description") - ).get("version_id", ""), - self.uname_attr("release"), - ] - if self.uname_attr("id").startswith("aix"): - # On AIX platforms, prefer oslevel command output. - versions.insert(0, self.oslevel_info()) - elif self.id() == "debian" or "debian" in self.like().split(): - # On Debian-like, add debian_version file content to candidates list. - versions.append(self._debian_version) - version = "" - if best: - # This algorithm uses the last version in priority order that has - # the best precision. If the versions are not in conflict, that - # does not matter; otherwise, using the last one instead of the - # first one might be considered a surprise. - for v in versions: - if v.count(".") > version.count(".") or version == "": - version = v - else: - for v in versions: - if v != "": - version = v - break - if pretty and version and self.codename(): - version = f"{version} ({self.codename()})" - return version - - def version_parts(self, best: bool = False) -> Tuple[str, str, str]: - """ - Return the version of the OS distribution, as a tuple of version - numbers. - - For details, see :func:`distro.version_parts`. - """ - version_str = self.version(best=best) - if version_str: - version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?") - matches = version_regex.match(version_str) - if matches: - major, minor, build_number = matches.groups() - return major, minor or "", build_number or "" - return "", "", "" - - def major_version(self, best: bool = False) -> str: - """ - Return the major version number of the current distribution. - - For details, see :func:`distro.major_version`. - """ - return self.version_parts(best)[0] - - def minor_version(self, best: bool = False) -> str: - """ - Return the minor version number of the current distribution. - - For details, see :func:`distro.minor_version`. - """ - return self.version_parts(best)[1] - - def build_number(self, best: bool = False) -> str: - """ - Return the build number of the current distribution. - - For details, see :func:`distro.build_number`. - """ - return self.version_parts(best)[2] - - def like(self) -> str: - """ - Return the IDs of distributions that are like the OS distribution. - - For details, see :func:`distro.like`. - """ - return self.os_release_attr("id_like") or "" - - def codename(self) -> str: - """ - Return the codename of the OS distribution. - - For details, see :func:`distro.codename`. - """ - try: - # Handle os_release specially since distros might purposefully set - # this to empty string to have no codename - return self._os_release_info["codename"] - except KeyError: - return ( - self.lsb_release_attr("codename") - or self.distro_release_attr("codename") - or "" - ) - - def info(self, pretty: bool = False, best: bool = False) -> InfoDict: - """ - Return certain machine-readable information about the OS - distribution. - - For details, see :func:`distro.info`. - """ - return InfoDict( - id=self.id(), - version=self.version(pretty, best), - version_parts=VersionDict( - major=self.major_version(best), - minor=self.minor_version(best), - build_number=self.build_number(best), - ), - like=self.like(), - codename=self.codename(), - ) - - def os_release_info(self) -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information - items from the os-release file data source of the OS distribution. - - For details, see :func:`distro.os_release_info`. - """ - return self._os_release_info - - def lsb_release_info(self) -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information - items from the lsb_release command data source of the OS - distribution. - - For details, see :func:`distro.lsb_release_info`. - """ - return self._lsb_release_info - - def distro_release_info(self) -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information - items from the distro release file data source of the OS - distribution. - - For details, see :func:`distro.distro_release_info`. - """ - return self._distro_release_info - - def uname_info(self) -> Dict[str, str]: - """ - Return a dictionary containing key-value pairs for the information - items from the uname command data source of the OS distribution. - - For details, see :func:`distro.uname_info`. - """ - return self._uname_info - - def oslevel_info(self) -> str: - """ - Return AIX' oslevel command output. - """ - return self._oslevel_info - - def os_release_attr(self, attribute: str) -> str: - """ - Return a single named information item from the os-release file data - source of the OS distribution. - - For details, see :func:`distro.os_release_attr`. - """ - return self._os_release_info.get(attribute, "") - - def lsb_release_attr(self, attribute: str) -> str: - """ - Return a single named information item from the lsb_release command - output data source of the OS distribution. - - For details, see :func:`distro.lsb_release_attr`. - """ - return self._lsb_release_info.get(attribute, "") - - def distro_release_attr(self, attribute: str) -> str: - """ - Return a single named information item from the distro release file - data source of the OS distribution. - - For details, see :func:`distro.distro_release_attr`. - """ - return self._distro_release_info.get(attribute, "") - - def uname_attr(self, attribute: str) -> str: - """ - Return a single named information item from the uname command - output data source of the OS distribution. - - For details, see :func:`distro.uname_attr`. - """ - return self._uname_info.get(attribute, "") - - @cached_property - def _os_release_info(self) -> Dict[str, str]: - """ - Get the information items from the specified os-release file. - - Returns: - A dictionary containing all information items. - """ - if os.path.isfile(self.os_release_file): - with open(self.os_release_file, encoding="utf-8") as release_file: - return self._parse_os_release_content(release_file) - return {} - - @staticmethod - def _parse_os_release_content(lines: TextIO) -> Dict[str, str]: - """ - Parse the lines of an os-release file. - - Parameters: - - * lines: Iterable through the lines in the os-release file. - Each line must be a unicode string or a UTF-8 encoded byte - string. - - Returns: - A dictionary containing all information items. - """ - props = {} - lexer = shlex.shlex(lines, posix=True) - lexer.whitespace_split = True - - tokens = list(lexer) - for token in tokens: - # At this point, all shell-like parsing has been done (i.e. - # comments processed, quotes and backslash escape sequences - # processed, multi-line values assembled, trailing newlines - # stripped, etc.), so the tokens are now either: - # * variable assignments: var=value - # * commands or their arguments (not allowed in os-release) - # Ignore any tokens that are not variable assignments - if "=" in token: - k, v = token.split("=", 1) - props[k.lower()] = v - - if "version" in props: - # extract release codename (if any) from version attribute - match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"]) - if match: - release_codename = match.group(1) or match.group(2) - props["codename"] = props["release_codename"] = release_codename - - if "version_codename" in props: - # os-release added a version_codename field. Use that in - # preference to anything else Note that some distros purposefully - # do not have code names. They should be setting - # version_codename="" - props["codename"] = props["version_codename"] - elif "ubuntu_codename" in props: - # Same as above but a non-standard field name used on older Ubuntus - props["codename"] = props["ubuntu_codename"] - - return props - - @cached_property - def _lsb_release_info(self) -> Dict[str, str]: - """ - Get the information items from the lsb_release command output. - - Returns: - A dictionary containing all information items. - """ - if not self.include_lsb: - return {} - try: - cmd = ("lsb_release", "-a") - stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) - # Command not found or lsb_release returned error - except (OSError, subprocess.CalledProcessError): - return {} - content = self._to_str(stdout).splitlines() - return self._parse_lsb_release_content(content) - - @staticmethod - def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]: - """ - Parse the output of the lsb_release command. - - Parameters: - - * lines: Iterable through the lines of the lsb_release output. - Each line must be a unicode string or a UTF-8 encoded byte - string. - - Returns: - A dictionary containing all information items. - """ - props = {} - for line in lines: - kv = line.strip("\n").split(":", 1) - if len(kv) != 2: - # Ignore lines without colon. - continue - k, v = kv - props.update({k.replace(" ", "_").lower(): v.strip()}) - return props - - @cached_property - def _uname_info(self) -> Dict[str, str]: - if not self.include_uname: - return {} - try: - cmd = ("uname", "-rs") - stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL) - except OSError: - return {} - content = self._to_str(stdout).splitlines() - return self._parse_uname_content(content) - - @cached_property - def _oslevel_info(self) -> str: - if not self.include_oslevel: - return "" - try: - stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL) - except (OSError, subprocess.CalledProcessError): - return "" - return self._to_str(stdout).strip() - - @cached_property - def _debian_version(self) -> str: - try: - with open( - os.path.join(self.etc_dir, "debian_version"), encoding="ascii" - ) as fp: - return fp.readline().rstrip() - except FileNotFoundError: - return "" - - @staticmethod - def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]: - if not lines: - return {} - props = {} - match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip()) - if match: - name, version = match.groups() - - # This is to prevent the Linux kernel version from - # appearing as the 'best' version on otherwise - # identifiable distributions. - if name == "Linux": - return {} - props["id"] = name.lower() - props["name"] = name - props["release"] = version - return props - - @staticmethod - def _to_str(bytestring: bytes) -> str: - encoding = sys.getfilesystemencoding() - return bytestring.decode(encoding) - - @cached_property - def _distro_release_info(self) -> Dict[str, str]: - """ - Get the information items from the specified distro release file. - - Returns: - A dictionary containing all information items. - """ - if self.distro_release_file: - # If it was specified, we use it and parse what we can, even if - # its file name or content does not match the expected pattern. - distro_info = self._parse_distro_release_file(self.distro_release_file) - basename = os.path.basename(self.distro_release_file) - # The file name pattern for user-specified distro release files - # is somewhat more tolerant (compared to when searching for the - # file), because we want to use what was specified as best as - # possible. - match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) - else: - try: - basenames = [ - basename - for basename in os.listdir(self.etc_dir) - if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES - and os.path.isfile(os.path.join(self.etc_dir, basename)) - ] - # We sort for repeatability in cases where there are multiple - # distro specific files; e.g. CentOS, Oracle, Enterprise all - # containing `redhat-release` on top of their own. - basenames.sort() - except OSError: - # This may occur when /etc is not readable but we can't be - # sure about the *-release files. Check common entries of - # /etc for information. If they turn out to not be there the - # error is handled in `_parse_distro_release_file()`. - basenames = _DISTRO_RELEASE_BASENAMES - for basename in basenames: - match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) - if match is None: - continue - filepath = os.path.join(self.etc_dir, basename) - distro_info = self._parse_distro_release_file(filepath) - # The name is always present if the pattern matches. - if "name" not in distro_info: - continue - self.distro_release_file = filepath - break - else: # the loop didn't "break": no candidate. - return {} - - if match is not None: - distro_info["id"] = match.group(1) - - # CloudLinux < 7: manually enrich info with proper id. - if "cloudlinux" in distro_info.get("name", "").lower(): - distro_info["id"] = "cloudlinux" - - return distro_info - - def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]: - """ - Parse a distro release file. - - Parameters: - - * filepath: Path name of the distro release file. - - Returns: - A dictionary containing all information items. - """ - try: - with open(filepath, encoding="utf-8") as fp: - # Only parse the first line. For instance, on SLES there - # are multiple lines. We don't want them... - return self._parse_distro_release_content(fp.readline()) - except OSError: - # Ignore not being able to read a specific, seemingly version - # related file. - # See https://github.com/python-distro/distro/issues/162 - return {} - - @staticmethod - def _parse_distro_release_content(line: str) -> Dict[str, str]: - """ - Parse a line from a distro release file. - - Parameters: - * line: Line from the distro release file. Must be a unicode string - or a UTF-8 encoded byte string. - - Returns: - A dictionary containing all information items. - """ - matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1]) - distro_info = {} - if matches: - # regexp ensures non-None - distro_info["name"] = matches.group(3)[::-1] - if matches.group(2): - distro_info["version_id"] = matches.group(2)[::-1] - if matches.group(1): - distro_info["codename"] = matches.group(1)[::-1] - elif line: - distro_info["name"] = line.strip() - return distro_info - - -_distro = LinuxDistribution() - - -def main() -> None: - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - logger.addHandler(logging.StreamHandler(sys.stdout)) - - parser = argparse.ArgumentParser(description="OS distro info tool") - parser.add_argument( - "--json", "-j", help="Output in machine readable format", action="store_true" - ) - - parser.add_argument( - "--root-dir", - "-r", - type=str, - dest="root_dir", - help="Path to the root filesystem directory (defaults to /)", - ) - - args = parser.parse_args() - - if args.root_dir: - dist = LinuxDistribution( - include_lsb=False, - include_uname=False, - include_oslevel=False, - root_dir=args.root_dir, - ) - else: - dist = _distro - - if args.json: - logger.info(json.dumps(dist.info(), indent=4, sort_keys=True)) - else: - logger.info("Name: %s", dist.name(pretty=True)) - distribution_version = dist.version(pretty=True) - logger.info("Version: %s", distribution_version) - distribution_codename = dist.codename() - logger.info("Codename: %s", distribution_codename) - - -if __name__ == "__main__": - main() diff --git a/backend/venv39/lib/python3.9/site-packages/distro/py.typed b/backend/venv39/lib/python3.9/site-packages/distro/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/distutils-precedence.pth b/backend/venv39/lib/python3.9/site-packages/distutils-precedence.pth deleted file mode 100644 index 6de4198..0000000 --- a/backend/venv39/lib/python3.9/site-packages/distutils-precedence.pth +++ /dev/null @@ -1 +0,0 @@ -import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'stdlib') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/backend/venv39/lib/python3.9/site-packages/dns/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/__init__.py deleted file mode 100644 index a4249b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/__init__.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""dnspython DNS toolkit""" - -__all__ = [ - "asyncbackend", - "asyncquery", - "asyncresolver", - "dnssec", - "dnssecalgs", - "dnssectypes", - "e164", - "edns", - "entropy", - "exception", - "flags", - "immutable", - "inet", - "ipv4", - "ipv6", - "message", - "name", - "namedict", - "node", - "opcode", - "query", - "quic", - "rcode", - "rdata", - "rdataclass", - "rdataset", - "rdatatype", - "renderer", - "resolver", - "reversename", - "rrset", - "serial", - "set", - "tokenizer", - "transaction", - "tsig", - "tsigkeyring", - "ttl", - "rdtypes", - "update", - "version", - "versioned", - "wire", - "xfr", - "zone", - "zonetypes", - "zonefile", -] - -from dns.version import version as __version__ # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_asyncbackend.py b/backend/venv39/lib/python3.9/site-packages/dns/_asyncbackend.py deleted file mode 100644 index f6760fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_asyncbackend.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# This is a nullcontext for both sync and async. 3.7 has a nullcontext, -# but it is only for sync use. - - -class NullContext: - def __init__(self, enter_result=None): - self.enter_result = enter_result - - def __enter__(self): - return self.enter_result - - def __exit__(self, exc_type, exc_value, traceback): - pass - - async def __aenter__(self): - return self.enter_result - - async def __aexit__(self, exc_type, exc_value, traceback): - pass - - -# These are declared here so backends can import them without creating -# circular dependencies with dns.asyncbackend. - - -class Socket: # pragma: no cover - def __init__(self, family: int, type: int): - self.family = family - self.type = type - - async def close(self): - pass - - async def getpeername(self): - raise NotImplementedError - - async def getsockname(self): - raise NotImplementedError - - async def getpeercert(self, timeout): - raise NotImplementedError - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_value, traceback): - await self.close() - - -class DatagramSocket(Socket): # pragma: no cover - async def sendto(self, what, destination, timeout): - raise NotImplementedError - - async def recvfrom(self, size, timeout): - raise NotImplementedError - - -class StreamSocket(Socket): # pragma: no cover - async def sendall(self, what, timeout): - raise NotImplementedError - - async def recv(self, size, timeout): - raise NotImplementedError - - -class NullTransport: - async def connect_tcp(self, host, port, timeout, local_address): - raise NotImplementedError - - -class Backend: # pragma: no cover - def name(self): - return "unknown" - - async def make_socket( - self, - af, - socktype, - proto=0, - source=None, - destination=None, - timeout=None, - ssl_context=None, - server_hostname=None, - ): - raise NotImplementedError - - def datagram_connection_required(self): - return False - - async def sleep(self, interval): - raise NotImplementedError - - def get_transport_class(self): - raise NotImplementedError - - async def wait_for(self, awaitable, timeout): - raise NotImplementedError diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_asyncio_backend.py b/backend/venv39/lib/python3.9/site-packages/dns/_asyncio_backend.py deleted file mode 100644 index 6ab168d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_asyncio_backend.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -"""asyncio library query support""" - -import asyncio -import socket -import sys - -import dns._asyncbackend -import dns._features -import dns.exception -import dns.inet - -_is_win32 = sys.platform == "win32" - - -def _get_running_loop(): - try: - return asyncio.get_running_loop() - except AttributeError: # pragma: no cover - return asyncio.get_event_loop() - - -class _DatagramProtocol: - def __init__(self): - self.transport = None - self.recvfrom = None - - def connection_made(self, transport): - self.transport = transport - - def datagram_received(self, data, addr): - if self.recvfrom and not self.recvfrom.done(): - self.recvfrom.set_result((data, addr)) - - def error_received(self, exc): # pragma: no cover - if self.recvfrom and not self.recvfrom.done(): - self.recvfrom.set_exception(exc) - - def connection_lost(self, exc): - if self.recvfrom and not self.recvfrom.done(): - if exc is None: - # EOF we triggered. Is there a better way to do this? - try: - raise EOFError("EOF") - except EOFError as e: - self.recvfrom.set_exception(e) - else: - self.recvfrom.set_exception(exc) - - def close(self): - self.transport.close() - - -async def _maybe_wait_for(awaitable, timeout): - if timeout is not None: - try: - return await asyncio.wait_for(awaitable, timeout) - except asyncio.TimeoutError: - raise dns.exception.Timeout(timeout=timeout) - else: - return await awaitable - - -class DatagramSocket(dns._asyncbackend.DatagramSocket): - def __init__(self, family, transport, protocol): - super().__init__(family, socket.SOCK_DGRAM) - self.transport = transport - self.protocol = protocol - - async def sendto(self, what, destination, timeout): # pragma: no cover - # no timeout for asyncio sendto - self.transport.sendto(what, destination) - return len(what) - - async def recvfrom(self, size, timeout): - # ignore size as there's no way I know to tell protocol about it - done = _get_running_loop().create_future() - try: - assert self.protocol.recvfrom is None - self.protocol.recvfrom = done - await _maybe_wait_for(done, timeout) - return done.result() - finally: - self.protocol.recvfrom = None - - async def close(self): - self.protocol.close() - - async def getpeername(self): - return self.transport.get_extra_info("peername") - - async def getsockname(self): - return self.transport.get_extra_info("sockname") - - async def getpeercert(self, timeout): - raise NotImplementedError - - -class StreamSocket(dns._asyncbackend.StreamSocket): - def __init__(self, af, reader, writer): - super().__init__(af, socket.SOCK_STREAM) - self.reader = reader - self.writer = writer - - async def sendall(self, what, timeout): - self.writer.write(what) - return await _maybe_wait_for(self.writer.drain(), timeout) - - async def recv(self, size, timeout): - return await _maybe_wait_for(self.reader.read(size), timeout) - - async def close(self): - self.writer.close() - - async def getpeername(self): - return self.writer.get_extra_info("peername") - - async def getsockname(self): - return self.writer.get_extra_info("sockname") - - async def getpeercert(self, timeout): - return self.writer.get_extra_info("peercert") - - -if dns._features.have("doh"): - import anyio - import httpcore - import httpcore._backends.anyio - import httpx - - _CoreAsyncNetworkBackend = httpcore.AsyncNetworkBackend - _CoreAnyIOStream = httpcore._backends.anyio.AnyIOStream - - from dns.query import _compute_times, _expiration_for_this_attempt, _remaining - - class _NetworkBackend(_CoreAsyncNetworkBackend): - def __init__(self, resolver, local_port, bootstrap_address, family): - super().__init__() - self._local_port = local_port - self._resolver = resolver - self._bootstrap_address = bootstrap_address - self._family = family - if local_port != 0: - raise NotImplementedError( - "the asyncio transport for HTTPX cannot set the local port" - ) - - async def connect_tcp( - self, host, port, timeout, local_address, socket_options=None - ): # pylint: disable=signature-differs - addresses = [] - _, expiration = _compute_times(timeout) - if dns.inet.is_address(host): - addresses.append(host) - elif self._bootstrap_address is not None: - addresses.append(self._bootstrap_address) - else: - timeout = _remaining(expiration) - family = self._family - if local_address: - family = dns.inet.af_for_address(local_address) - answers = await self._resolver.resolve_name( - host, family=family, lifetime=timeout - ) - addresses = answers.addresses() - for address in addresses: - try: - attempt_expiration = _expiration_for_this_attempt(2.0, expiration) - timeout = _remaining(attempt_expiration) - with anyio.fail_after(timeout): - stream = await anyio.connect_tcp( - remote_host=address, - remote_port=port, - local_host=local_address, - ) - return _CoreAnyIOStream(stream) - except Exception: - pass - raise httpcore.ConnectError - - async def connect_unix_socket( - self, path, timeout, socket_options=None - ): # pylint: disable=signature-differs - raise NotImplementedError - - async def sleep(self, seconds): # pylint: disable=signature-differs - await anyio.sleep(seconds) - - class _HTTPTransport(httpx.AsyncHTTPTransport): - def __init__( - self, - *args, - local_port=0, - bootstrap_address=None, - resolver=None, - family=socket.AF_UNSPEC, - **kwargs, - ): - if resolver is None and bootstrap_address is None: - # pylint: disable=import-outside-toplevel,redefined-outer-name - import dns.asyncresolver - - resolver = dns.asyncresolver.Resolver() - super().__init__(*args, **kwargs) - self._pool._network_backend = _NetworkBackend( - resolver, local_port, bootstrap_address, family - ) - -else: - _HTTPTransport = dns._asyncbackend.NullTransport # type: ignore - - -class Backend(dns._asyncbackend.Backend): - def name(self): - return "asyncio" - - async def make_socket( - self, - af, - socktype, - proto=0, - source=None, - destination=None, - timeout=None, - ssl_context=None, - server_hostname=None, - ): - loop = _get_running_loop() - if socktype == socket.SOCK_DGRAM: - if _is_win32 and source is None: - # Win32 wants explicit binding before recvfrom(). This is the - # proper fix for [#637]. - source = (dns.inet.any_for_af(af), 0) - transport, protocol = await loop.create_datagram_endpoint( - _DatagramProtocol, - source, - family=af, - proto=proto, - remote_addr=destination, - ) - return DatagramSocket(af, transport, protocol) - elif socktype == socket.SOCK_STREAM: - if destination is None: - # This shouldn't happen, but we check to make code analysis software - # happier. - raise ValueError("destination required for stream sockets") - (r, w) = await _maybe_wait_for( - asyncio.open_connection( - destination[0], - destination[1], - ssl=ssl_context, - family=af, - proto=proto, - local_addr=source, - server_hostname=server_hostname, - ), - timeout, - ) - return StreamSocket(af, r, w) - raise NotImplementedError( - "unsupported socket " + f"type {socktype}" - ) # pragma: no cover - - async def sleep(self, interval): - await asyncio.sleep(interval) - - def datagram_connection_required(self): - return False - - def get_transport_class(self): - return _HTTPTransport - - async def wait_for(self, awaitable, timeout): - return await _maybe_wait_for(awaitable, timeout) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_ddr.py b/backend/venv39/lib/python3.9/site-packages/dns/_ddr.py deleted file mode 100644 index bf5c11e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_ddr.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license -# -# Support for Discovery of Designated Resolvers - -import socket -import time -from urllib.parse import urlparse - -import dns.asyncbackend -import dns.inet -import dns.name -import dns.nameserver -import dns.query -import dns.rdtypes.svcbbase - -# The special name of the local resolver when using DDR -_local_resolver_name = dns.name.from_text("_dns.resolver.arpa") - - -# -# Processing is split up into I/O independent and I/O dependent parts to -# make supporting sync and async versions easy. -# - - -class _SVCBInfo: - def __init__(self, bootstrap_address, port, hostname, nameservers): - self.bootstrap_address = bootstrap_address - self.port = port - self.hostname = hostname - self.nameservers = nameservers - - def ddr_check_certificate(self, cert): - """Verify that the _SVCBInfo's address is in the cert's subjectAltName (SAN)""" - for name, value in cert["subjectAltName"]: - if name == "IP Address" and value == self.bootstrap_address: - return True - return False - - def make_tls_context(self): - ssl = dns.query.ssl - ctx = ssl.create_default_context() - ctx.minimum_version = ssl.TLSVersion.TLSv1_2 - return ctx - - def ddr_tls_check_sync(self, lifetime): - ctx = self.make_tls_context() - expiration = time.time() + lifetime - with socket.create_connection( - (self.bootstrap_address, self.port), lifetime - ) as s: - with ctx.wrap_socket(s, server_hostname=self.hostname) as ts: - ts.settimeout(dns.query._remaining(expiration)) - ts.do_handshake() - cert = ts.getpeercert() - return self.ddr_check_certificate(cert) - - async def ddr_tls_check_async(self, lifetime, backend=None): - if backend is None: - backend = dns.asyncbackend.get_default_backend() - ctx = self.make_tls_context() - expiration = time.time() + lifetime - async with await backend.make_socket( - dns.inet.af_for_address(self.bootstrap_address), - socket.SOCK_STREAM, - 0, - None, - (self.bootstrap_address, self.port), - lifetime, - ctx, - self.hostname, - ) as ts: - cert = await ts.getpeercert(dns.query._remaining(expiration)) - return self.ddr_check_certificate(cert) - - -def _extract_nameservers_from_svcb(answer): - bootstrap_address = answer.nameserver - if not dns.inet.is_address(bootstrap_address): - return [] - infos = [] - for rr in answer.rrset.processing_order(): - nameservers = [] - param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.ALPN) - if param is None: - continue - alpns = set(param.ids) - host = rr.target.to_text(omit_final_dot=True) - port = None - param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.PORT) - if param is not None: - port = param.port - # For now we ignore address hints and address resolution and always use the - # bootstrap address - if b"h2" in alpns: - param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.DOHPATH) - if param is None or not param.value.endswith(b"{?dns}"): - continue - path = param.value[:-6].decode() - if not path.startswith("/"): - path = "/" + path - if port is None: - port = 443 - url = f"https://{host}:{port}{path}" - # check the URL - try: - urlparse(url) - nameservers.append(dns.nameserver.DoHNameserver(url, bootstrap_address)) - except Exception: - # continue processing other ALPN types - pass - if b"dot" in alpns: - if port is None: - port = 853 - nameservers.append( - dns.nameserver.DoTNameserver(bootstrap_address, port, host) - ) - if b"doq" in alpns: - if port is None: - port = 853 - nameservers.append( - dns.nameserver.DoQNameserver(bootstrap_address, port, True, host) - ) - if len(nameservers) > 0: - infos.append(_SVCBInfo(bootstrap_address, port, host, nameservers)) - return infos - - -def _get_nameservers_sync(answer, lifetime): - """Return a list of TLS-validated resolver nameservers extracted from an SVCB - answer.""" - nameservers = [] - infos = _extract_nameservers_from_svcb(answer) - for info in infos: - try: - if info.ddr_tls_check_sync(lifetime): - nameservers.extend(info.nameservers) - except Exception: - pass - return nameservers - - -async def _get_nameservers_async(answer, lifetime): - """Return a list of TLS-validated resolver nameservers extracted from an SVCB - answer.""" - nameservers = [] - infos = _extract_nameservers_from_svcb(answer) - for info in infos: - try: - if await info.ddr_tls_check_async(lifetime): - nameservers.extend(info.nameservers) - except Exception: - pass - return nameservers diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_features.py b/backend/venv39/lib/python3.9/site-packages/dns/_features.py deleted file mode 100644 index fa6d495..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_features.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import importlib.metadata -import itertools -import string -from typing import Dict, List, Tuple - - -def _tuple_from_text(version: str) -> Tuple: - text_parts = version.split(".") - int_parts = [] - for text_part in text_parts: - digit_prefix = "".join( - itertools.takewhile(lambda x: x in string.digits, text_part) - ) - try: - int_parts.append(int(digit_prefix)) - except Exception: - break - return tuple(int_parts) - - -def _version_check( - requirement: str, -) -> bool: - """Is the requirement fulfilled? - - The requirement must be of the form - - package>=version - """ - package, minimum = requirement.split(">=") - try: - version = importlib.metadata.version(package) - # This shouldn't happen, but it apparently can. - if version is None: - return False - except Exception: - return False - t_version = _tuple_from_text(version) - t_minimum = _tuple_from_text(minimum) - if t_version < t_minimum: - return False - return True - - -_cache: Dict[str, bool] = {} - - -def have(feature: str) -> bool: - """Is *feature* available? - - This tests if all optional packages needed for the - feature are available and recent enough. - - Returns ``True`` if the feature is available, - and ``False`` if it is not or if metadata is - missing. - """ - value = _cache.get(feature) - if value is not None: - return value - requirements = _requirements.get(feature) - if requirements is None: - # we make a cache entry here for consistency not performance - _cache[feature] = False - return False - ok = True - for requirement in requirements: - if not _version_check(requirement): - ok = False - break - _cache[feature] = ok - return ok - - -def force(feature: str, enabled: bool) -> None: - """Force the status of *feature* to be *enabled*. - - This method is provided as a workaround for any cases - where importlib.metadata is ineffective, or for testing. - """ - _cache[feature] = enabled - - -_requirements: Dict[str, List[str]] = { - ### BEGIN generated requirements - "dnssec": ["cryptography>=43"], - "doh": ["httpcore>=1.0.0", "httpx>=0.26.0", "h2>=4.1.0"], - "doq": ["aioquic>=1.0.0"], - "idna": ["idna>=3.7"], - "trio": ["trio>=0.23"], - "wmi": ["wmi>=1.5.1"], - ### END generated requirements -} diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_immutable_ctx.py b/backend/venv39/lib/python3.9/site-packages/dns/_immutable_ctx.py deleted file mode 100644 index ae7a33b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_immutable_ctx.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# This implementation of the immutable decorator requires python >= -# 3.7, and is significantly more storage efficient when making classes -# with slots immutable. It's also faster. - -import contextvars -import inspect - -_in__init__ = contextvars.ContextVar("_immutable_in__init__", default=False) - - -class _Immutable: - """Immutable mixin class""" - - # We set slots to the empty list to say "we don't have any attributes". - # We do this so that if we're mixed in with a class with __slots__, we - # don't cause a __dict__ to be added which would waste space. - - __slots__ = () - - def __setattr__(self, name, value): - if _in__init__.get() is not self: - raise TypeError("object doesn't support attribute assignment") - else: - super().__setattr__(name, value) - - def __delattr__(self, name): - if _in__init__.get() is not self: - raise TypeError("object doesn't support attribute assignment") - else: - super().__delattr__(name) - - -def _immutable_init(f): - def nf(*args, **kwargs): - previous = _in__init__.set(args[0]) - try: - # call the actual __init__ - f(*args, **kwargs) - finally: - _in__init__.reset(previous) - - nf.__signature__ = inspect.signature(f) - return nf - - -def immutable(cls): - if _Immutable in cls.__mro__: - # Some ancestor already has the mixin, so just make sure we keep - # following the __init__ protocol. - cls.__init__ = _immutable_init(cls.__init__) - if hasattr(cls, "__setstate__"): - cls.__setstate__ = _immutable_init(cls.__setstate__) - ncls = cls - else: - # Mixin the Immutable class and follow the __init__ protocol. - class ncls(_Immutable, cls): - # We have to do the __slots__ declaration here too! - __slots__ = () - - @_immutable_init - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if hasattr(cls, "__setstate__"): - - @_immutable_init - def __setstate__(self, *args, **kwargs): - super().__setstate__(*args, **kwargs) - - # make ncls have the same name and module as cls - ncls.__name__ = cls.__name__ - ncls.__qualname__ = cls.__qualname__ - ncls.__module__ = cls.__module__ - return ncls diff --git a/backend/venv39/lib/python3.9/site-packages/dns/_trio_backend.py b/backend/venv39/lib/python3.9/site-packages/dns/_trio_backend.py deleted file mode 100644 index 0ed904d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/_trio_backend.py +++ /dev/null @@ -1,253 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -"""trio async I/O library query support""" - -import socket - -import trio -import trio.socket # type: ignore - -import dns._asyncbackend -import dns._features -import dns.exception -import dns.inet - -if not dns._features.have("trio"): - raise ImportError("trio not found or too old") - - -def _maybe_timeout(timeout): - if timeout is not None: - return trio.move_on_after(timeout) - else: - return dns._asyncbackend.NullContext() - - -# for brevity -_lltuple = dns.inet.low_level_address_tuple - -# pylint: disable=redefined-outer-name - - -class DatagramSocket(dns._asyncbackend.DatagramSocket): - def __init__(self, sock): - super().__init__(sock.family, socket.SOCK_DGRAM) - self.socket = sock - - async def sendto(self, what, destination, timeout): - with _maybe_timeout(timeout): - if destination is None: - return await self.socket.send(what) - else: - return await self.socket.sendto(what, destination) - raise dns.exception.Timeout( - timeout=timeout - ) # pragma: no cover lgtm[py/unreachable-statement] - - async def recvfrom(self, size, timeout): - with _maybe_timeout(timeout): - return await self.socket.recvfrom(size) - raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement] - - async def close(self): - self.socket.close() - - async def getpeername(self): - return self.socket.getpeername() - - async def getsockname(self): - return self.socket.getsockname() - - async def getpeercert(self, timeout): - raise NotImplementedError - - -class StreamSocket(dns._asyncbackend.StreamSocket): - def __init__(self, family, stream, tls=False): - super().__init__(family, socket.SOCK_STREAM) - self.stream = stream - self.tls = tls - - async def sendall(self, what, timeout): - with _maybe_timeout(timeout): - return await self.stream.send_all(what) - raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement] - - async def recv(self, size, timeout): - with _maybe_timeout(timeout): - return await self.stream.receive_some(size) - raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement] - - async def close(self): - await self.stream.aclose() - - async def getpeername(self): - if self.tls: - return self.stream.transport_stream.socket.getpeername() - else: - return self.stream.socket.getpeername() - - async def getsockname(self): - if self.tls: - return self.stream.transport_stream.socket.getsockname() - else: - return self.stream.socket.getsockname() - - async def getpeercert(self, timeout): - if self.tls: - with _maybe_timeout(timeout): - await self.stream.do_handshake() - return self.stream.getpeercert() - else: - raise NotImplementedError - - -if dns._features.have("doh"): - import httpcore - import httpcore._backends.trio - import httpx - - _CoreAsyncNetworkBackend = httpcore.AsyncNetworkBackend - _CoreTrioStream = httpcore._backends.trio.TrioStream - - from dns.query import _compute_times, _expiration_for_this_attempt, _remaining - - class _NetworkBackend(_CoreAsyncNetworkBackend): - def __init__(self, resolver, local_port, bootstrap_address, family): - super().__init__() - self._local_port = local_port - self._resolver = resolver - self._bootstrap_address = bootstrap_address - self._family = family - - async def connect_tcp( - self, host, port, timeout, local_address, socket_options=None - ): # pylint: disable=signature-differs - addresses = [] - _, expiration = _compute_times(timeout) - if dns.inet.is_address(host): - addresses.append(host) - elif self._bootstrap_address is not None: - addresses.append(self._bootstrap_address) - else: - timeout = _remaining(expiration) - family = self._family - if local_address: - family = dns.inet.af_for_address(local_address) - answers = await self._resolver.resolve_name( - host, family=family, lifetime=timeout - ) - addresses = answers.addresses() - for address in addresses: - try: - af = dns.inet.af_for_address(address) - if local_address is not None or self._local_port != 0: - source = (local_address, self._local_port) - else: - source = None - destination = (address, port) - attempt_expiration = _expiration_for_this_attempt(2.0, expiration) - timeout = _remaining(attempt_expiration) - sock = await Backend().make_socket( - af, socket.SOCK_STREAM, 0, source, destination, timeout - ) - return _CoreTrioStream(sock.stream) - except Exception: - continue - raise httpcore.ConnectError - - async def connect_unix_socket( - self, path, timeout, socket_options=None - ): # pylint: disable=signature-differs - raise NotImplementedError - - async def sleep(self, seconds): # pylint: disable=signature-differs - await trio.sleep(seconds) - - class _HTTPTransport(httpx.AsyncHTTPTransport): - def __init__( - self, - *args, - local_port=0, - bootstrap_address=None, - resolver=None, - family=socket.AF_UNSPEC, - **kwargs, - ): - if resolver is None and bootstrap_address is None: - # pylint: disable=import-outside-toplevel,redefined-outer-name - import dns.asyncresolver - - resolver = dns.asyncresolver.Resolver() - super().__init__(*args, **kwargs) - self._pool._network_backend = _NetworkBackend( - resolver, local_port, bootstrap_address, family - ) - -else: - _HTTPTransport = dns._asyncbackend.NullTransport # type: ignore - - -class Backend(dns._asyncbackend.Backend): - def name(self): - return "trio" - - async def make_socket( - self, - af, - socktype, - proto=0, - source=None, - destination=None, - timeout=None, - ssl_context=None, - server_hostname=None, - ): - s = trio.socket.socket(af, socktype, proto) - stream = None - try: - if source: - await s.bind(_lltuple(source, af)) - if socktype == socket.SOCK_STREAM or destination is not None: - connected = False - with _maybe_timeout(timeout): - await s.connect(_lltuple(destination, af)) - connected = True - if not connected: - raise dns.exception.Timeout( - timeout=timeout - ) # lgtm[py/unreachable-statement] - except Exception: # pragma: no cover - s.close() - raise - if socktype == socket.SOCK_DGRAM: - return DatagramSocket(s) - elif socktype == socket.SOCK_STREAM: - stream = trio.SocketStream(s) - tls = False - if ssl_context: - tls = True - try: - stream = trio.SSLStream( - stream, ssl_context, server_hostname=server_hostname - ) - except Exception: # pragma: no cover - await stream.aclose() - raise - return StreamSocket(af, stream, tls) - raise NotImplementedError( - "unsupported socket " + f"type {socktype}" - ) # pragma: no cover - - async def sleep(self, interval): - await trio.sleep(interval) - - def get_transport_class(self): - return _HTTPTransport - - async def wait_for(self, awaitable, timeout): - with _maybe_timeout(timeout): - return await awaitable - raise dns.exception.Timeout( - timeout=timeout - ) # pragma: no cover lgtm[py/unreachable-statement] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/asyncbackend.py b/backend/venv39/lib/python3.9/site-packages/dns/asyncbackend.py deleted file mode 100644 index 0ec58b0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/asyncbackend.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -from typing import Dict - -import dns.exception - -# pylint: disable=unused-import -from dns._asyncbackend import ( # noqa: F401 lgtm[py/unused-import] - Backend, - DatagramSocket, - Socket, - StreamSocket, -) - -# pylint: enable=unused-import - -_default_backend = None - -_backends: Dict[str, Backend] = {} - -# Allow sniffio import to be disabled for testing purposes -_no_sniffio = False - - -class AsyncLibraryNotFoundError(dns.exception.DNSException): - pass - - -def get_backend(name: str) -> Backend: - """Get the specified asynchronous backend. - - *name*, a ``str``, the name of the backend. Currently the "trio" - and "asyncio" backends are available. - - Raises NotImplementedError if an unknown backend name is specified. - """ - # pylint: disable=import-outside-toplevel,redefined-outer-name - backend = _backends.get(name) - if backend: - return backend - if name == "trio": - import dns._trio_backend - - backend = dns._trio_backend.Backend() - elif name == "asyncio": - import dns._asyncio_backend - - backend = dns._asyncio_backend.Backend() - else: - raise NotImplementedError(f"unimplemented async backend {name}") - _backends[name] = backend - return backend - - -def sniff() -> str: - """Attempt to determine the in-use asynchronous I/O library by using - the ``sniffio`` module if it is available. - - Returns the name of the library, or raises AsyncLibraryNotFoundError - if the library cannot be determined. - """ - # pylint: disable=import-outside-toplevel - try: - if _no_sniffio: - raise ImportError - import sniffio - - try: - return sniffio.current_async_library() - except sniffio.AsyncLibraryNotFoundError: - raise AsyncLibraryNotFoundError("sniffio cannot determine async library") - except ImportError: - import asyncio - - try: - asyncio.get_running_loop() - return "asyncio" - except RuntimeError: - raise AsyncLibraryNotFoundError("no async library detected") - - -def get_default_backend() -> Backend: - """Get the default backend, initializing it if necessary.""" - if _default_backend: - return _default_backend - - return set_default_backend(sniff()) - - -def set_default_backend(name: str) -> Backend: - """Set the default backend. - - It's not normally necessary to call this method, as - ``get_default_backend()`` will initialize the backend - appropriately in many cases. If ``sniffio`` is not installed, or - in testing situations, this function allows the backend to be set - explicitly. - """ - global _default_backend - _default_backend = get_backend(name) - return _default_backend diff --git a/backend/venv39/lib/python3.9/site-packages/dns/asyncquery.py b/backend/venv39/lib/python3.9/site-packages/dns/asyncquery.py deleted file mode 100644 index efad0fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/asyncquery.py +++ /dev/null @@ -1,913 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Talk to a DNS server.""" - -import base64 -import contextlib -import random -import socket -import struct -import time -import urllib.parse -from typing import Any, Dict, Optional, Tuple, Union, cast - -import dns.asyncbackend -import dns.exception -import dns.inet -import dns.message -import dns.name -import dns.quic -import dns.rcode -import dns.rdataclass -import dns.rdatatype -import dns.transaction -from dns._asyncbackend import NullContext -from dns.query import ( - BadResponse, - HTTPVersion, - NoDOH, - NoDOQ, - UDPMode, - _check_status, - _compute_times, - _make_dot_ssl_context, - _matches_destination, - _remaining, - have_doh, - ssl, -) - -if have_doh: - import httpx - -# for brevity -_lltuple = dns.inet.low_level_address_tuple - - -def _source_tuple(af, address, port): - # Make a high level source tuple, or return None if address and port - # are both None - if address or port: - if address is None: - if af == socket.AF_INET: - address = "0.0.0.0" - elif af == socket.AF_INET6: - address = "::" - else: - raise NotImplementedError(f"unknown address family {af}") - return (address, port) - else: - return None - - -def _timeout(expiration, now=None): - if expiration is not None: - if not now: - now = time.time() - return max(expiration - now, 0) - else: - return None - - -async def send_udp( - sock: dns.asyncbackend.DatagramSocket, - what: Union[dns.message.Message, bytes], - destination: Any, - expiration: Optional[float] = None, -) -> Tuple[int, float]: - """Send a DNS message to the specified UDP socket. - - *sock*, a ``dns.asyncbackend.DatagramSocket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where to send the query. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. The expiration value is meaningless for the asyncio backend, as - asyncio's transport sendto() never blocks. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. - """ - - if isinstance(what, dns.message.Message): - what = what.to_wire() - sent_time = time.time() - n = await sock.sendto(what, destination, _timeout(expiration, sent_time)) - return (n, sent_time) - - -async def receive_udp( - sock: dns.asyncbackend.DatagramSocket, - destination: Optional[Any] = None, - expiration: Optional[float] = None, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None, - request_mac: Optional[bytes] = b"", - ignore_trailing: bool = False, - raise_on_truncation: bool = False, - ignore_errors: bool = False, - query: Optional[dns.message.Message] = None, -) -> Any: - """Read a DNS message from a UDP socket. - - *sock*, a ``dns.asyncbackend.DatagramSocket``. - - See :py:func:`dns.query.receive_udp()` for the documentation of the other - parameters, and exceptions. - - Returns a ``(dns.message.Message, float, tuple)`` tuple of the received message, the - received time, and the address where the message arrived from. - """ - - wire = b"" - while True: - (wire, from_address) = await sock.recvfrom(65535, _timeout(expiration)) - if not _matches_destination( - sock.family, from_address, destination, ignore_unexpected - ): - continue - received_time = time.time() - try: - r = dns.message.from_wire( - wire, - keyring=keyring, - request_mac=request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - raise_on_truncation=raise_on_truncation, - ) - except dns.message.Truncated as e: - # See the comment in query.py for details. - if ( - ignore_errors - and query is not None - and not query.is_response(e.message()) - ): - continue - else: - raise - except Exception: - if ignore_errors: - continue - else: - raise - if ignore_errors and query is not None and not query.is_response(r): - continue - return (r, received_time, from_address) - - -async def udp( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - raise_on_truncation: bool = False, - sock: Optional[dns.asyncbackend.DatagramSocket] = None, - backend: Optional[dns.asyncbackend.Backend] = None, - ignore_errors: bool = False, -) -> dns.message.Message: - """Return the response obtained after sending a query via UDP. - - *sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``, - the socket to use for the query. If ``None``, the default, a - socket is created. Note that if a socket is provided, the - *source*, *source_port*, and *backend* are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.udp()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - wire = q.to_wire() - (begin_time, expiration) = _compute_times(timeout) - af = dns.inet.af_for_address(where) - destination = _lltuple((where, port), af) - if sock: - cm: contextlib.AbstractAsyncContextManager = NullContext(sock) - else: - if not backend: - backend = dns.asyncbackend.get_default_backend() - stuple = _source_tuple(af, source, source_port) - if backend.datagram_connection_required(): - dtuple = (where, port) - else: - dtuple = None - cm = await backend.make_socket(af, socket.SOCK_DGRAM, 0, stuple, dtuple) - async with cm as s: - await send_udp(s, wire, destination, expiration) - (r, received_time, _) = await receive_udp( - s, - destination, - expiration, - ignore_unexpected, - one_rr_per_rrset, - q.keyring, - q.mac, - ignore_trailing, - raise_on_truncation, - ignore_errors, - q, - ) - r.time = received_time - begin_time - # We don't need to check q.is_response() if we are in ignore_errors mode - # as receive_udp() will have checked it. - if not (ignore_errors or q.is_response(r)): - raise BadResponse - return r - - -async def udp_with_fallback( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - udp_sock: Optional[dns.asyncbackend.DatagramSocket] = None, - tcp_sock: Optional[dns.asyncbackend.StreamSocket] = None, - backend: Optional[dns.asyncbackend.Backend] = None, - ignore_errors: bool = False, -) -> Tuple[dns.message.Message, bool]: - """Return the response to the query, trying UDP first and falling back - to TCP if UDP results in a truncated response. - - *udp_sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``, - the socket to use for the UDP query. If ``None``, the default, a - socket is created. Note that if a socket is provided the *source*, - *source_port*, and *backend* are ignored for the UDP query. - - *tcp_sock*, a ``dns.asyncbackend.StreamSocket``, or ``None``, the - socket to use for the TCP query. If ``None``, the default, a - socket is created. Note that if a socket is provided *where*, - *source*, *source_port*, and *backend* are ignored for the TCP query. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.udp_with_fallback()` for the documentation - of the other parameters, exceptions, and return type of this - method. - """ - try: - response = await udp( - q, - where, - timeout, - port, - source, - source_port, - ignore_unexpected, - one_rr_per_rrset, - ignore_trailing, - True, - udp_sock, - backend, - ignore_errors, - ) - return (response, False) - except dns.message.Truncated: - response = await tcp( - q, - where, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - tcp_sock, - backend, - ) - return (response, True) - - -async def send_tcp( - sock: dns.asyncbackend.StreamSocket, - what: Union[dns.message.Message, bytes], - expiration: Optional[float] = None, -) -> Tuple[int, float]: - """Send a DNS message to the specified TCP socket. - - *sock*, a ``dns.asyncbackend.StreamSocket``. - - See :py:func:`dns.query.send_tcp()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - - if isinstance(what, dns.message.Message): - tcpmsg = what.to_wire(prepend_length=True) - else: - # copying the wire into tcpmsg is inefficient, but lets us - # avoid writev() or doing a short write that would get pushed - # onto the net - tcpmsg = len(what).to_bytes(2, "big") + what - sent_time = time.time() - await sock.sendall(tcpmsg, _timeout(expiration, sent_time)) - return (len(tcpmsg), sent_time) - - -async def _read_exactly(sock, count, expiration): - """Read the specified number of bytes from stream. Keep trying until we - either get the desired amount, or we hit EOF. - """ - s = b"" - while count > 0: - n = await sock.recv(count, _timeout(expiration)) - if n == b"": - raise EOFError("EOF") - count = count - len(n) - s = s + n - return s - - -async def receive_tcp( - sock: dns.asyncbackend.StreamSocket, - expiration: Optional[float] = None, - one_rr_per_rrset: bool = False, - keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None, - request_mac: Optional[bytes] = b"", - ignore_trailing: bool = False, -) -> Tuple[dns.message.Message, float]: - """Read a DNS message from a TCP socket. - - *sock*, a ``dns.asyncbackend.StreamSocket``. - - See :py:func:`dns.query.receive_tcp()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - - ldata = await _read_exactly(sock, 2, expiration) - (l,) = struct.unpack("!H", ldata) - wire = await _read_exactly(sock, l, expiration) - received_time = time.time() - r = dns.message.from_wire( - wire, - keyring=keyring, - request_mac=request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - return (r, received_time) - - -async def tcp( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - sock: Optional[dns.asyncbackend.StreamSocket] = None, - backend: Optional[dns.asyncbackend.Backend] = None, -) -> dns.message.Message: - """Return the response obtained after sending a query via TCP. - - *sock*, a ``dns.asyncbacket.StreamSocket``, or ``None``, the - socket to use for the query. If ``None``, the default, a socket - is created. Note that if a socket is provided - *where*, *port*, *source*, *source_port*, and *backend* are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.tcp()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - - wire = q.to_wire() - (begin_time, expiration) = _compute_times(timeout) - if sock: - # Verify that the socket is connected, as if it's not connected, - # it's not writable, and the polling in send_tcp() will time out or - # hang forever. - await sock.getpeername() - cm: contextlib.AbstractAsyncContextManager = NullContext(sock) - else: - # These are simple (address, port) pairs, not family-dependent tuples - # you pass to low-level socket code. - af = dns.inet.af_for_address(where) - stuple = _source_tuple(af, source, source_port) - dtuple = (where, port) - if not backend: - backend = dns.asyncbackend.get_default_backend() - cm = await backend.make_socket( - af, socket.SOCK_STREAM, 0, stuple, dtuple, timeout - ) - async with cm as s: - await send_tcp(s, wire, expiration) - (r, received_time) = await receive_tcp( - s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing - ) - r.time = received_time - begin_time - if not q.is_response(r): - raise BadResponse - return r - - -async def tls( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - sock: Optional[dns.asyncbackend.StreamSocket] = None, - backend: Optional[dns.asyncbackend.Backend] = None, - ssl_context: Optional[ssl.SSLContext] = None, - server_hostname: Optional[str] = None, - verify: Union[bool, str] = True, -) -> dns.message.Message: - """Return the response obtained after sending a query via TLS. - - *sock*, an ``asyncbackend.StreamSocket``, or ``None``, the socket - to use for the query. If ``None``, the default, a socket is - created. Note that if a socket is provided, it must be a - connected SSL stream socket, and *where*, *port*, - *source*, *source_port*, *backend*, *ssl_context*, and *server_hostname* - are ignored. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.tls()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - (begin_time, expiration) = _compute_times(timeout) - if sock: - cm: contextlib.AbstractAsyncContextManager = NullContext(sock) - else: - if ssl_context is None: - ssl_context = _make_dot_ssl_context(server_hostname, verify) - af = dns.inet.af_for_address(where) - stuple = _source_tuple(af, source, source_port) - dtuple = (where, port) - if not backend: - backend = dns.asyncbackend.get_default_backend() - cm = await backend.make_socket( - af, - socket.SOCK_STREAM, - 0, - stuple, - dtuple, - timeout, - ssl_context, - server_hostname, - ) - async with cm as s: - timeout = _timeout(expiration) - response = await tcp( - q, - where, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - s, - backend, - ) - end_time = time.time() - response.time = end_time - begin_time - return response - - -def _maybe_get_resolver( - resolver: Optional["dns.asyncresolver.Resolver"], -) -> "dns.asyncresolver.Resolver": - # We need a separate method for this to avoid overriding the global - # variable "dns" with the as-yet undefined local variable "dns" - # in https(). - if resolver is None: - # pylint: disable=import-outside-toplevel,redefined-outer-name - import dns.asyncresolver - - resolver = dns.asyncresolver.Resolver() - return resolver - - -async def https( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 443, - source: Optional[str] = None, - source_port: int = 0, # pylint: disable=W0613 - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - client: Optional["httpx.AsyncClient"] = None, - path: str = "/dns-query", - post: bool = True, - verify: Union[bool, str] = True, - bootstrap_address: Optional[str] = None, - resolver: Optional["dns.asyncresolver.Resolver"] = None, - family: int = socket.AF_UNSPEC, - http_version: HTTPVersion = HTTPVersion.DEFAULT, -) -> dns.message.Message: - """Return the response obtained after sending a query via DNS-over-HTTPS. - - *client*, a ``httpx.AsyncClient``. If provided, the client to use for - the query. - - Unlike the other dnspython async functions, a backend cannot be provided - in this function because httpx always auto-detects the async backend. - - See :py:func:`dns.query.https()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - - try: - af = dns.inet.af_for_address(where) - except ValueError: - af = None - if af is not None and dns.inet.is_address(where): - if af == socket.AF_INET: - url = f"https://{where}:{port}{path}" - elif af == socket.AF_INET6: - url = f"https://[{where}]:{port}{path}" - else: - url = where - - extensions = {} - if bootstrap_address is None: - # pylint: disable=possibly-used-before-assignment - parsed = urllib.parse.urlparse(url) - if parsed.hostname is None: - raise ValueError("no hostname in URL") - if dns.inet.is_address(parsed.hostname): - bootstrap_address = parsed.hostname - extensions["sni_hostname"] = parsed.hostname - if parsed.port is not None: - port = parsed.port - - if http_version == HTTPVersion.H3 or ( - http_version == HTTPVersion.DEFAULT and not have_doh - ): - if bootstrap_address is None: - resolver = _maybe_get_resolver(resolver) - assert parsed.hostname is not None # for mypy - answers = await resolver.resolve_name(parsed.hostname, family) - bootstrap_address = random.choice(list(answers.addresses())) - return await _http3( - q, - bootstrap_address, - url, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - verify=verify, - post=post, - ) - - if not have_doh: - raise NoDOH # pragma: no cover - # pylint: disable=possibly-used-before-assignment - if client and not isinstance(client, httpx.AsyncClient): - raise ValueError("session parameter must be an httpx.AsyncClient") - # pylint: enable=possibly-used-before-assignment - - wire = q.to_wire() - headers = {"accept": "application/dns-message"} - - h1 = http_version in (HTTPVersion.H1, HTTPVersion.DEFAULT) - h2 = http_version in (HTTPVersion.H2, HTTPVersion.DEFAULT) - - backend = dns.asyncbackend.get_default_backend() - - if source is None: - local_address = None - local_port = 0 - else: - local_address = source - local_port = source_port - - if client: - cm: contextlib.AbstractAsyncContextManager = NullContext(client) - else: - transport = backend.get_transport_class()( - local_address=local_address, - http1=h1, - http2=h2, - verify=verify, - local_port=local_port, - bootstrap_address=bootstrap_address, - resolver=resolver, - family=family, - ) - - cm = httpx.AsyncClient(http1=h1, http2=h2, verify=verify, transport=transport) - - async with cm as the_client: - # see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH - # GET and POST examples - if post: - headers.update( - { - "content-type": "application/dns-message", - "content-length": str(len(wire)), - } - ) - response = await backend.wait_for( - the_client.post( - url, - headers=headers, - content=wire, - extensions=extensions, - ), - timeout, - ) - else: - wire = base64.urlsafe_b64encode(wire).rstrip(b"=") - twire = wire.decode() # httpx does a repr() if we give it bytes - response = await backend.wait_for( - the_client.get( - url, - headers=headers, - params={"dns": twire}, - extensions=extensions, - ), - timeout, - ) - - # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH - # status codes - if response.status_code < 200 or response.status_code > 299: - raise ValueError( - f"{where} responded with status code {response.status_code}" - f"\nResponse body: {response.content!r}" - ) - r = dns.message.from_wire( - response.content, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = response.elapsed.total_seconds() - if not q.is_response(r): - raise BadResponse - return r - - -async def _http3( - q: dns.message.Message, - where: str, - url: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - verify: Union[bool, str] = True, - backend: Optional[dns.asyncbackend.Backend] = None, - hostname: Optional[str] = None, - post: bool = True, -) -> dns.message.Message: - if not dns.quic.have_quic: - raise NoDOH("DNS-over-HTTP3 is not available.") # pragma: no cover - - url_parts = urllib.parse.urlparse(url) - hostname = url_parts.hostname - if url_parts.port is not None: - port = url_parts.port - - q.id = 0 - wire = q.to_wire() - (cfactory, mfactory) = dns.quic.factories_for_backend(backend) - - async with cfactory() as context: - async with mfactory( - context, verify_mode=verify, server_name=hostname, h3=True - ) as the_manager: - the_connection = the_manager.connect(where, port, source, source_port) - (start, expiration) = _compute_times(timeout) - stream = await the_connection.make_stream(timeout) - async with stream: - # note that send_h3() does not need await - stream.send_h3(url, wire, post) - wire = await stream.receive(_remaining(expiration)) - _check_status(stream.headers(), where, wire) - finish = time.time() - r = dns.message.from_wire( - wire, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = max(finish - start, 0.0) - if not q.is_response(r): - raise BadResponse - return r - - -async def quic( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - connection: Optional[dns.quic.AsyncQuicConnection] = None, - verify: Union[bool, str] = True, - backend: Optional[dns.asyncbackend.Backend] = None, - hostname: Optional[str] = None, - server_hostname: Optional[str] = None, -) -> dns.message.Message: - """Return the response obtained after sending an asynchronous query via - DNS-over-QUIC. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.quic()` for the documentation of the other - parameters, exceptions, and return type of this method. - """ - - if not dns.quic.have_quic: - raise NoDOQ("DNS-over-QUIC is not available.") # pragma: no cover - - if server_hostname is not None and hostname is None: - hostname = server_hostname - - q.id = 0 - wire = q.to_wire() - the_connection: dns.quic.AsyncQuicConnection - if connection: - cfactory = dns.quic.null_factory - mfactory = dns.quic.null_factory - the_connection = connection - else: - (cfactory, mfactory) = dns.quic.factories_for_backend(backend) - - async with cfactory() as context: - async with mfactory( - context, - verify_mode=verify, - server_name=server_hostname, - ) as the_manager: - if not connection: - the_connection = the_manager.connect(where, port, source, source_port) - (start, expiration) = _compute_times(timeout) - stream = await the_connection.make_stream(timeout) - async with stream: - await stream.send(wire, True) - wire = await stream.receive(_remaining(expiration)) - finish = time.time() - r = dns.message.from_wire( - wire, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = max(finish - start, 0.0) - if not q.is_response(r): - raise BadResponse - return r - - -async def _inbound_xfr( - txn_manager: dns.transaction.TransactionManager, - s: dns.asyncbackend.Socket, - query: dns.message.Message, - serial: Optional[int], - timeout: Optional[float], - expiration: float, -) -> Any: - """Given a socket, does the zone transfer.""" - rdtype = query.question[0].rdtype - is_ixfr = rdtype == dns.rdatatype.IXFR - origin = txn_manager.from_wire_origin() - wire = query.to_wire() - is_udp = s.type == socket.SOCK_DGRAM - if is_udp: - udp_sock = cast(dns.asyncbackend.DatagramSocket, s) - await udp_sock.sendto(wire, None, _timeout(expiration)) - else: - tcp_sock = cast(dns.asyncbackend.StreamSocket, s) - tcpmsg = struct.pack("!H", len(wire)) + wire - await tcp_sock.sendall(tcpmsg, expiration) - with dns.xfr.Inbound(txn_manager, rdtype, serial, is_udp) as inbound: - done = False - tsig_ctx = None - while not done: - (_, mexpiration) = _compute_times(timeout) - if mexpiration is None or ( - expiration is not None and mexpiration > expiration - ): - mexpiration = expiration - if is_udp: - timeout = _timeout(mexpiration) - (rwire, _) = await udp_sock.recvfrom(65535, timeout) - else: - ldata = await _read_exactly(tcp_sock, 2, mexpiration) - (l,) = struct.unpack("!H", ldata) - rwire = await _read_exactly(tcp_sock, l, mexpiration) - r = dns.message.from_wire( - rwire, - keyring=query.keyring, - request_mac=query.mac, - xfr=True, - origin=origin, - tsig_ctx=tsig_ctx, - multi=(not is_udp), - one_rr_per_rrset=is_ixfr, - ) - done = inbound.process_message(r) - yield r - tsig_ctx = r.tsig_ctx - if query.keyring and not r.had_tsig: - raise dns.exception.FormError("missing TSIG") - - -async def inbound_xfr( - where: str, - txn_manager: dns.transaction.TransactionManager, - query: Optional[dns.message.Message] = None, - port: int = 53, - timeout: Optional[float] = None, - lifetime: Optional[float] = None, - source: Optional[str] = None, - source_port: int = 0, - udp_mode: UDPMode = UDPMode.NEVER, - backend: Optional[dns.asyncbackend.Backend] = None, -) -> None: - """Conduct an inbound transfer and apply it via a transaction from the - txn_manager. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.query.inbound_xfr()` for the documentation of - the other parameters, exceptions, and return type of this method. - """ - if query is None: - (query, serial) = dns.xfr.make_query(txn_manager) - else: - serial = dns.xfr.extract_serial_from_query(query) - af = dns.inet.af_for_address(where) - stuple = _source_tuple(af, source, source_port) - dtuple = (where, port) - if not backend: - backend = dns.asyncbackend.get_default_backend() - (_, expiration) = _compute_times(lifetime) - if query.question[0].rdtype == dns.rdatatype.IXFR and udp_mode != UDPMode.NEVER: - s = await backend.make_socket( - af, socket.SOCK_DGRAM, 0, stuple, dtuple, _timeout(expiration) - ) - async with s: - try: - async for _ in _inbound_xfr( - txn_manager, s, query, serial, timeout, expiration - ): - pass - return - except dns.xfr.UseTCP: - if udp_mode == UDPMode.ONLY: - raise - - s = await backend.make_socket( - af, socket.SOCK_STREAM, 0, stuple, dtuple, _timeout(expiration) - ) - async with s: - async for _ in _inbound_xfr(txn_manager, s, query, serial, timeout, expiration): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/dns/asyncresolver.py b/backend/venv39/lib/python3.9/site-packages/dns/asyncresolver.py deleted file mode 100644 index 8f5e062..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/asyncresolver.py +++ /dev/null @@ -1,475 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Asynchronous DNS stub resolver.""" - -import socket -import time -from typing import Any, Dict, List, Optional, Union - -import dns._ddr -import dns.asyncbackend -import dns.asyncquery -import dns.exception -import dns.name -import dns.query -import dns.rdataclass -import dns.rdatatype -import dns.resolver # lgtm[py/import-and-import-from] - -# import some resolver symbols for brevity -from dns.resolver import NXDOMAIN, NoAnswer, NoRootSOA, NotAbsolute - -# for indentation purposes below -_udp = dns.asyncquery.udp -_tcp = dns.asyncquery.tcp - - -class Resolver(dns.resolver.BaseResolver): - """Asynchronous DNS stub resolver.""" - - async def resolve( - self, - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, - backend: Optional[dns.asyncbackend.Backend] = None, - ) -> dns.resolver.Answer: - """Query nameservers asynchronously to find the answer to the question. - - *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, - the default, then dnspython will use the default backend. - - See :py:func:`dns.resolver.Resolver.resolve()` for the - documentation of the other parameters, exceptions, and return - type of this method. - """ - - resolution = dns.resolver._Resolution( - self, qname, rdtype, rdclass, tcp, raise_on_no_answer, search - ) - if not backend: - backend = dns.asyncbackend.get_default_backend() - start = time.time() - while True: - (request, answer) = resolution.next_request() - # Note we need to say "if answer is not None" and not just - # "if answer" because answer implements __len__, and python - # will call that. We want to return if we have an answer - # object, including in cases where its length is 0. - if answer is not None: - # cache hit! - return answer - assert request is not None # needed for type checking - done = False - while not done: - (nameserver, tcp, backoff) = resolution.next_nameserver() - if backoff: - await backend.sleep(backoff) - timeout = self._compute_timeout(start, lifetime, resolution.errors) - try: - response = await nameserver.async_query( - request, - timeout=timeout, - source=source, - source_port=source_port, - max_size=tcp, - backend=backend, - ) - except Exception as ex: - (_, done) = resolution.query_result(None, ex) - continue - (answer, done) = resolution.query_result(response, None) - # Note we need to say "if answer is not None" and not just - # "if answer" because answer implements __len__, and python - # will call that. We want to return if we have an answer - # object, including in cases where its length is 0. - if answer is not None: - return answer - - async def resolve_address( - self, ipaddr: str, *args: Any, **kwargs: Any - ) -> dns.resolver.Answer: - """Use an asynchronous resolver to run a reverse query for PTR - records. - - This utilizes the resolve() method to perform a PTR lookup on the - specified IP address. - - *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get - the PTR record for. - - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. - - """ - # We make a modified kwargs for type checking happiness, as otherwise - # we get a legit warning about possibly having rdtype and rdclass - # in the kwargs more than once. - modified_kwargs: Dict[str, Any] = {} - modified_kwargs.update(kwargs) - modified_kwargs["rdtype"] = dns.rdatatype.PTR - modified_kwargs["rdclass"] = dns.rdataclass.IN - return await self.resolve( - dns.reversename.from_address(ipaddr), *args, **modified_kwargs - ) - - async def resolve_name( - self, - name: Union[dns.name.Name, str], - family: int = socket.AF_UNSPEC, - **kwargs: Any, - ) -> dns.resolver.HostAnswers: - """Use an asynchronous resolver to query for address records. - - This utilizes the resolve() method to perform A and/or AAAA lookups on - the specified name. - - *qname*, a ``dns.name.Name`` or ``str``, the name to resolve. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC - (the default), both A and AAAA records will be retrieved. - - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. - """ - # We make a modified kwargs for type checking happiness, as otherwise - # we get a legit warning about possibly having rdtype and rdclass - # in the kwargs more than once. - modified_kwargs: Dict[str, Any] = {} - modified_kwargs.update(kwargs) - modified_kwargs.pop("rdtype", None) - modified_kwargs["rdclass"] = dns.rdataclass.IN - - if family == socket.AF_INET: - v4 = await self.resolve(name, dns.rdatatype.A, **modified_kwargs) - return dns.resolver.HostAnswers.make(v4=v4) - elif family == socket.AF_INET6: - v6 = await self.resolve(name, dns.rdatatype.AAAA, **modified_kwargs) - return dns.resolver.HostAnswers.make(v6=v6) - elif family != socket.AF_UNSPEC: - raise NotImplementedError(f"unknown address family {family}") - - raise_on_no_answer = modified_kwargs.pop("raise_on_no_answer", True) - lifetime = modified_kwargs.pop("lifetime", None) - start = time.time() - v6 = await self.resolve( - name, - dns.rdatatype.AAAA, - raise_on_no_answer=False, - lifetime=self._compute_timeout(start, lifetime), - **modified_kwargs, - ) - # Note that setting name ensures we query the same name - # for A as we did for AAAA. (This is just in case search lists - # are active by default in the resolver configuration and - # we might be talking to a server that says NXDOMAIN when it - # wants to say NOERROR no data. - name = v6.qname - v4 = await self.resolve( - name, - dns.rdatatype.A, - raise_on_no_answer=False, - lifetime=self._compute_timeout(start, lifetime), - **modified_kwargs, - ) - answers = dns.resolver.HostAnswers.make( - v6=v6, v4=v4, add_empty=not raise_on_no_answer - ) - if not answers: - raise NoAnswer(response=v6.response) - return answers - - # pylint: disable=redefined-outer-name - - async def canonical_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name: - """Determine the canonical name of *name*. - - The canonical name is the name the resolver uses for queries - after all CNAME and DNAME renamings have been applied. - - *name*, a ``dns.name.Name`` or ``str``, the query name. - - This method can raise any exception that ``resolve()`` can - raise, other than ``dns.resolver.NoAnswer`` and - ``dns.resolver.NXDOMAIN``. - - Returns a ``dns.name.Name``. - """ - try: - answer = await self.resolve(name, raise_on_no_answer=False) - canonical_name = answer.canonical_name - except dns.resolver.NXDOMAIN as e: - canonical_name = e.canonical_name - return canonical_name - - async def try_ddr(self, lifetime: float = 5.0) -> None: - """Try to update the resolver's nameservers using Discovery of Designated - Resolvers (DDR). If successful, the resolver will subsequently use - DNS-over-HTTPS or DNS-over-TLS for future queries. - - *lifetime*, a float, is the maximum time to spend attempting DDR. The default - is 5 seconds. - - If the SVCB query is successful and results in a non-empty list of nameservers, - then the resolver's nameservers are set to the returned servers in priority - order. - - The current implementation does not use any address hints from the SVCB record, - nor does it resolve addresses for the SCVB target name, rather it assumes that - the bootstrap nameserver will always be one of the addresses and uses it. - A future revision to the code may offer fuller support. The code verifies that - the bootstrap nameserver is in the Subject Alternative Name field of the - TLS certficate. - """ - try: - expiration = time.time() + lifetime - answer = await self.resolve( - dns._ddr._local_resolver_name, "svcb", lifetime=lifetime - ) - timeout = dns.query._remaining(expiration) - nameservers = await dns._ddr._get_nameservers_async(answer, timeout) - if len(nameservers) > 0: - self.nameservers = nameservers - except Exception: - pass - - -default_resolver = None - - -def get_default_resolver() -> Resolver: - """Get the default asynchronous resolver, initializing it if necessary.""" - if default_resolver is None: - reset_default_resolver() - assert default_resolver is not None - return default_resolver - - -def reset_default_resolver() -> None: - """Re-initialize default asynchronous resolver. - - Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX - systems) will be re-read immediately. - """ - - global default_resolver - default_resolver = Resolver() - - -async def resolve( - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, - backend: Optional[dns.asyncbackend.Backend] = None, -) -> dns.resolver.Answer: - """Query nameservers asynchronously to find the answer to the question. - - This is a convenience function that uses the default resolver - object to make the query. - - See :py:func:`dns.asyncresolver.Resolver.resolve` for more - information on the parameters. - """ - - return await get_default_resolver().resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - search, - backend, - ) - - -async def resolve_address( - ipaddr: str, *args: Any, **kwargs: Any -) -> dns.resolver.Answer: - """Use a resolver to run a reverse query for PTR records. - - See :py:func:`dns.asyncresolver.Resolver.resolve_address` for more - information on the parameters. - """ - - return await get_default_resolver().resolve_address(ipaddr, *args, **kwargs) - - -async def resolve_name( - name: Union[dns.name.Name, str], family: int = socket.AF_UNSPEC, **kwargs: Any -) -> dns.resolver.HostAnswers: - """Use a resolver to asynchronously query for address records. - - See :py:func:`dns.asyncresolver.Resolver.resolve_name` for more - information on the parameters. - """ - - return await get_default_resolver().resolve_name(name, family, **kwargs) - - -async def canonical_name(name: Union[dns.name.Name, str]) -> dns.name.Name: - """Determine the canonical name of *name*. - - See :py:func:`dns.resolver.Resolver.canonical_name` for more - information on the parameters and possible exceptions. - """ - - return await get_default_resolver().canonical_name(name) - - -async def try_ddr(timeout: float = 5.0) -> None: - """Try to update the default resolver's nameservers using Discovery of Designated - Resolvers (DDR). If successful, the resolver will subsequently use - DNS-over-HTTPS or DNS-over-TLS for future queries. - - See :py:func:`dns.resolver.Resolver.try_ddr` for more information. - """ - return await get_default_resolver().try_ddr(timeout) - - -async def zone_for_name( - name: Union[dns.name.Name, str], - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - tcp: bool = False, - resolver: Optional[Resolver] = None, - backend: Optional[dns.asyncbackend.Backend] = None, -) -> dns.name.Name: - """Find the name of the zone which contains the specified name. - - See :py:func:`dns.resolver.Resolver.zone_for_name` for more - information on the parameters and possible exceptions. - """ - - if isinstance(name, str): - name = dns.name.from_text(name, dns.name.root) - if resolver is None: - resolver = get_default_resolver() - if not name.is_absolute(): - raise NotAbsolute(name) - while True: - try: - answer = await resolver.resolve( - name, dns.rdatatype.SOA, rdclass, tcp, backend=backend - ) - assert answer.rrset is not None - if answer.rrset.name == name: - return name - # otherwise we were CNAMEd or DNAMEd and need to look higher - except (NXDOMAIN, NoAnswer): - pass - try: - name = name.parent() - except dns.name.NoParent: # pragma: no cover - raise NoRootSOA - - -async def make_resolver_at( - where: Union[dns.name.Name, str], - port: int = 53, - family: int = socket.AF_UNSPEC, - resolver: Optional[Resolver] = None, -) -> Resolver: - """Make a stub resolver using the specified destination as the full resolver. - - *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the - full resolver. - - *port*, an ``int``, the port to use. If not specified, the default is 53. - - *family*, an ``int``, the address family to use. This parameter is used if - *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case - the first address returned by ``resolve_name()`` will be used, otherwise the - first address of the specified family will be used. - - *resolver*, a ``dns.asyncresolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames. If not specified, the default resolver will be used. - - Returns a ``dns.resolver.Resolver`` or raises an exception. - """ - if resolver is None: - resolver = get_default_resolver() - nameservers: List[Union[str, dns.nameserver.Nameserver]] = [] - if isinstance(where, str) and dns.inet.is_address(where): - nameservers.append(dns.nameserver.Do53Nameserver(where, port)) - else: - answers = await resolver.resolve_name(where, family) - for address in answers.addresses(): - nameservers.append(dns.nameserver.Do53Nameserver(address, port)) - res = dns.asyncresolver.Resolver(configure=False) - res.nameservers = nameservers - return res - - -async def resolve_at( - where: Union[dns.name.Name, str], - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, - backend: Optional[dns.asyncbackend.Backend] = None, - port: int = 53, - family: int = socket.AF_UNSPEC, - resolver: Optional[Resolver] = None, -) -> dns.resolver.Answer: - """Query nameservers to find the answer to the question. - - This is a convenience function that calls ``dns.asyncresolver.make_resolver_at()`` - to make a resolver, and then uses it to resolve the query. - - See ``dns.asyncresolver.Resolver.resolve`` for more information on the resolution - parameters, and ``dns.asyncresolver.make_resolver_at`` for information about the - resolver parameters *where*, *port*, *family*, and *resolver*. - - If making more than one query, it is more efficient to call - ``dns.asyncresolver.make_resolver_at()`` and then use that resolver for the queries - instead of calling ``resolve_at()`` multiple times. - """ - res = await make_resolver_at(where, port, family, resolver) - return await res.resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - search, - backend, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssec.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssec.py deleted file mode 100644 index b69d0a1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssec.py +++ /dev/null @@ -1,1247 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNSSEC-related functions and constants.""" - - -import base64 -import contextlib -import functools -import hashlib -import struct -import time -from datetime import datetime -from typing import Callable, Dict, List, Optional, Set, Tuple, Union, cast - -import dns._features -import dns.exception -import dns.name -import dns.node -import dns.rdata -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.rrset -import dns.transaction -import dns.zone -from dns.dnssectypes import Algorithm, DSDigest, NSEC3Hash -from dns.exception import ( # pylint: disable=W0611 - AlgorithmKeyMismatch, - DeniedByPolicy, - UnsupportedAlgorithm, - ValidationFailure, -) -from dns.rdtypes.ANY.CDNSKEY import CDNSKEY -from dns.rdtypes.ANY.CDS import CDS -from dns.rdtypes.ANY.DNSKEY import DNSKEY -from dns.rdtypes.ANY.DS import DS -from dns.rdtypes.ANY.NSEC import NSEC, Bitmap -from dns.rdtypes.ANY.NSEC3PARAM import NSEC3PARAM -from dns.rdtypes.ANY.RRSIG import RRSIG, sigtime_to_posixtime -from dns.rdtypes.dnskeybase import Flag - -PublicKey = Union[ - "GenericPublicKey", - "rsa.RSAPublicKey", - "ec.EllipticCurvePublicKey", - "ed25519.Ed25519PublicKey", - "ed448.Ed448PublicKey", -] - -PrivateKey = Union[ - "GenericPrivateKey", - "rsa.RSAPrivateKey", - "ec.EllipticCurvePrivateKey", - "ed25519.Ed25519PrivateKey", - "ed448.Ed448PrivateKey", -] - -RRsetSigner = Callable[[dns.transaction.Transaction, dns.rrset.RRset], None] - - -def algorithm_from_text(text: str) -> Algorithm: - """Convert text into a DNSSEC algorithm value. - - *text*, a ``str``, the text to convert to into an algorithm value. - - Returns an ``int``. - """ - - return Algorithm.from_text(text) - - -def algorithm_to_text(value: Union[Algorithm, int]) -> str: - """Convert a DNSSEC algorithm value to text - - *value*, a ``dns.dnssec.Algorithm``. - - Returns a ``str``, the name of a DNSSEC algorithm. - """ - - return Algorithm.to_text(value) - - -def to_timestamp(value: Union[datetime, str, float, int]) -> int: - """Convert various format to a timestamp""" - if isinstance(value, datetime): - return int(value.timestamp()) - elif isinstance(value, str): - return sigtime_to_posixtime(value) - elif isinstance(value, float): - return int(value) - elif isinstance(value, int): - return value - else: - raise TypeError("Unsupported timestamp type") - - -def key_id(key: Union[DNSKEY, CDNSKEY]) -> int: - """Return the key id (a 16-bit number) for the specified key. - - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` - - Returns an ``int`` between 0 and 65535 - """ - - rdata = key.to_wire() - assert rdata is not None # for mypy - if key.algorithm == Algorithm.RSAMD5: - return (rdata[-3] << 8) + rdata[-2] - else: - total = 0 - for i in range(len(rdata) // 2): - total += (rdata[2 * i] << 8) + rdata[2 * i + 1] - if len(rdata) % 2 != 0: - total += rdata[len(rdata) - 1] << 8 - total += (total >> 16) & 0xFFFF - return total & 0xFFFF - - -class Policy: - def __init__(self): - pass - - def ok_to_sign(self, _: DNSKEY) -> bool: # pragma: no cover - return False - - def ok_to_validate(self, _: DNSKEY) -> bool: # pragma: no cover - return False - - def ok_to_create_ds(self, _: DSDigest) -> bool: # pragma: no cover - return False - - def ok_to_validate_ds(self, _: DSDigest) -> bool: # pragma: no cover - return False - - -class SimpleDeny(Policy): - def __init__(self, deny_sign, deny_validate, deny_create_ds, deny_validate_ds): - super().__init__() - self._deny_sign = deny_sign - self._deny_validate = deny_validate - self._deny_create_ds = deny_create_ds - self._deny_validate_ds = deny_validate_ds - - def ok_to_sign(self, key: DNSKEY) -> bool: - return key.algorithm not in self._deny_sign - - def ok_to_validate(self, key: DNSKEY) -> bool: - return key.algorithm not in self._deny_validate - - def ok_to_create_ds(self, algorithm: DSDigest) -> bool: - return algorithm not in self._deny_create_ds - - def ok_to_validate_ds(self, algorithm: DSDigest) -> bool: - return algorithm not in self._deny_validate_ds - - -rfc_8624_policy = SimpleDeny( - {Algorithm.RSAMD5, Algorithm.DSA, Algorithm.DSANSEC3SHA1, Algorithm.ECCGOST}, - {Algorithm.RSAMD5, Algorithm.DSA, Algorithm.DSANSEC3SHA1}, - {DSDigest.NULL, DSDigest.SHA1, DSDigest.GOST}, - {DSDigest.NULL}, -) - -allow_all_policy = SimpleDeny(set(), set(), set(), set()) - - -default_policy = rfc_8624_policy - - -def make_ds( - name: Union[dns.name.Name, str], - key: dns.rdata.Rdata, - algorithm: Union[DSDigest, str], - origin: Optional[dns.name.Name] = None, - policy: Optional[Policy] = None, - validating: bool = False, -) -> DS: - """Create a DS record for a DNSSEC key. - - *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. - - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``, - the key the DS is about. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name, - then it will be made absolute using the specified origin. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - *validating*, a ``bool``. If ``True``, then policy is checked in - validating mode, i.e. "Is it ok to validate using this digest algorithm?". - Otherwise the policy is checked in creating mode, i.e. "Is it ok to create a DS with - this digest algorithm?". - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Raises ``DeniedByPolicy`` if the algorithm is denied by policy. - - Returns a ``dns.rdtypes.ANY.DS.DS`` - """ - - if policy is None: - policy = default_policy - try: - if isinstance(algorithm, str): - algorithm = DSDigest[algorithm.upper()] - except Exception: - raise UnsupportedAlgorithm(f'unsupported algorithm "{algorithm}"') - if validating: - check = policy.ok_to_validate_ds - else: - check = policy.ok_to_create_ds - if not check(algorithm): - raise DeniedByPolicy - if not isinstance(key, (DNSKEY, CDNSKEY)): - raise ValueError("key is not a DNSKEY/CDNSKEY") - if algorithm == DSDigest.SHA1: - dshash = hashlib.sha1() - elif algorithm == DSDigest.SHA256: - dshash = hashlib.sha256() - elif algorithm == DSDigest.SHA384: - dshash = hashlib.sha384() - else: - raise UnsupportedAlgorithm(f'unsupported algorithm "{algorithm}"') - - if isinstance(name, str): - name = dns.name.from_text(name, origin) - wire = name.canonicalize().to_wire() - kwire = key.to_wire(origin=origin) - assert wire is not None and kwire is not None # for mypy - dshash.update(wire) - dshash.update(kwire) - digest = dshash.digest() - - dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, algorithm) + digest - ds = dns.rdata.from_wire( - dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata) - ) - return cast(DS, ds) - - -def make_cds( - name: Union[dns.name.Name, str], - key: dns.rdata.Rdata, - algorithm: Union[DSDigest, str], - origin: Optional[dns.name.Name] = None, -) -> CDS: - """Create a CDS record for a DNSSEC key. - - *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. - - *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``, - the key the DS is about. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.rdtypes.ANY.DS.CDS`` - """ - - ds = make_ds(name, key, algorithm, origin) - return CDS( - rdclass=ds.rdclass, - rdtype=dns.rdatatype.CDS, - key_tag=ds.key_tag, - algorithm=ds.algorithm, - digest_type=ds.digest_type, - digest=ds.digest, - ) - - -def _find_candidate_keys( - keys: Dict[dns.name.Name, Union[dns.rdataset.Rdataset, dns.node.Node]], rrsig: RRSIG -) -> Optional[List[DNSKEY]]: - value = keys.get(rrsig.signer) - if isinstance(value, dns.node.Node): - rdataset = value.get_rdataset(dns.rdataclass.IN, dns.rdatatype.DNSKEY) - else: - rdataset = value - if rdataset is None: - return None - return [ - cast(DNSKEY, rd) - for rd in rdataset - if rd.algorithm == rrsig.algorithm - and key_id(rd) == rrsig.key_tag - and (rd.flags & Flag.ZONE) == Flag.ZONE # RFC 4034 2.1.1 - and rd.protocol == 3 # RFC 4034 2.1.2 - ] - - -def _get_rrname_rdataset( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], -) -> Tuple[dns.name.Name, dns.rdataset.Rdataset]: - if isinstance(rrset, tuple): - return rrset[0], rrset[1] - else: - return rrset.name, rrset - - -def _validate_signature(sig: bytes, data: bytes, key: DNSKEY) -> None: - # pylint: disable=possibly-used-before-assignment - public_cls = get_algorithm_cls_from_dnskey(key).public_cls - try: - public_key = public_cls.from_dnskey(key) - except ValueError: - raise ValidationFailure("invalid public key") - public_key.verify(sig, data) - - -def _validate_rrsig( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - rrsig: RRSIG, - keys: Dict[dns.name.Name, Union[dns.node.Node, dns.rdataset.Rdataset]], - origin: Optional[dns.name.Name] = None, - now: Optional[float] = None, - policy: Optional[Policy] = None, -) -> None: - """Validate an RRset against a single signature rdata, throwing an - exception if validation is not successful. - - *rrset*, the RRset to validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *rrsig*, a ``dns.rdata.Rdata``, the signature to validate. - - *keys*, the key dictionary, used to find the DNSKEY associated - with a given name. The dictionary is keyed by a - ``dns.name.Name``, and has ``dns.node.Node`` or - ``dns.rdataset.Rdataset`` values. - - *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative - names. - - *now*, a ``float`` or ``None``, the time, in seconds since the epoch, to - use as the current time when validating. If ``None``, the actual current - time is used. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - Raises ``ValidationFailure`` if the signature is expired, not yet valid, - the public key is invalid, the algorithm is unknown, the verification - fails, etc. - - Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by - dnspython but not implemented. - """ - - if policy is None: - policy = default_policy - - candidate_keys = _find_candidate_keys(keys, rrsig) - if candidate_keys is None: - raise ValidationFailure("unknown key") - - if now is None: - now = time.time() - if rrsig.expiration < now: - raise ValidationFailure("expired") - if rrsig.inception > now: - raise ValidationFailure("not yet valid") - - data = _make_rrsig_signature_data(rrset, rrsig, origin) - - # pylint: disable=possibly-used-before-assignment - for candidate_key in candidate_keys: - if not policy.ok_to_validate(candidate_key): - continue - try: - _validate_signature(rrsig.signature, data, candidate_key) - return - except (InvalidSignature, ValidationFailure): - # this happens on an individual validation failure - continue - # nothing verified -- raise failure: - raise ValidationFailure("verify failure") - - -def _validate( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - rrsigset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - keys: Dict[dns.name.Name, Union[dns.node.Node, dns.rdataset.Rdataset]], - origin: Optional[dns.name.Name] = None, - now: Optional[float] = None, - policy: Optional[Policy] = None, -) -> None: - """Validate an RRset against a signature RRset, throwing an exception - if none of the signatures validate. - - *rrset*, the RRset to validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *rrsigset*, the signature RRset. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *keys*, the key dictionary, used to find the DNSKEY associated - with a given name. The dictionary is keyed by a - ``dns.name.Name``, and has ``dns.node.Node`` or - ``dns.rdataset.Rdataset`` values. - - *origin*, a ``dns.name.Name``, the origin to use for relative names; - defaults to None. - - *now*, an ``int`` or ``None``, the time, in seconds since the epoch, to - use as the current time when validating. If ``None``, the actual current - time is used. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - Raises ``ValidationFailure`` if the signature is expired, not yet valid, - the public key is invalid, the algorithm is unknown, the verification - fails, etc. - """ - - if policy is None: - policy = default_policy - - if isinstance(origin, str): - origin = dns.name.from_text(origin, dns.name.root) - - if isinstance(rrset, tuple): - rrname = rrset[0] - else: - rrname = rrset.name - - if isinstance(rrsigset, tuple): - rrsigname = rrsigset[0] - rrsigrdataset = rrsigset[1] - else: - rrsigname = rrsigset.name - rrsigrdataset = rrsigset - - rrname = rrname.choose_relativity(origin) - rrsigname = rrsigname.choose_relativity(origin) - if rrname != rrsigname: - raise ValidationFailure("owner names do not match") - - for rrsig in rrsigrdataset: - if not isinstance(rrsig, RRSIG): - raise ValidationFailure("expected an RRSIG") - try: - _validate_rrsig(rrset, rrsig, keys, origin, now, policy) - return - except (ValidationFailure, UnsupportedAlgorithm): - pass - raise ValidationFailure("no RRSIGs validated") - - -def _sign( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - private_key: PrivateKey, - signer: dns.name.Name, - dnskey: DNSKEY, - inception: Optional[Union[datetime, str, int, float]] = None, - expiration: Optional[Union[datetime, str, int, float]] = None, - lifetime: Optional[int] = None, - verify: bool = False, - policy: Optional[Policy] = None, - origin: Optional[dns.name.Name] = None, - deterministic: bool = True, -) -> RRSIG: - """Sign RRset using private key. - - *rrset*, the RRset to validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *private_key*, the private key to use for signing, a - ``cryptography.hazmat.primitives.asymmetric`` private key class applicable - for DNSSEC. - - *signer*, a ``dns.name.Name``, the Signer's name. - - *dnskey*, a ``DNSKEY`` matching ``private_key``. - - *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the - signature inception time. If ``None``, the current time is used. If a ``str``, the - format is "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX - epoch in text form; this is the same the RRSIG rdata's text form. - Values of type `int` or `float` are interpreted as seconds since the UNIX epoch. - - *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - expiration time. If ``None``, the expiration time will be the inception time plus - the value of the *lifetime* parameter. See the description of *inception* above - for how the various parameter types are interpreted. - - *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This - parameter is only meaningful if *expiration* is ``None``. - - *verify*, a ``bool``. If set to ``True``, the signer will verify signatures - after they are created; the default is ``False``. - - *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy, - ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624. - - *origin*, a ``dns.name.Name`` or ``None``. If ``None``, the default, then all - names in the rrset (including its owner name) must be absolute; otherwise the - specified origin will be used to make names absolute when signing. - - *deterministic*, a ``bool``. If ``True``, the default, use deterministic - (reproducible) signatures when supported by the algorithm used for signing. - Currently, this only affects ECDSA. - - Raises ``DeniedByPolicy`` if the signature is denied by policy. - """ - - if policy is None: - policy = default_policy - if not policy.ok_to_sign(dnskey): - raise DeniedByPolicy - - if isinstance(rrset, tuple): - rdclass = rrset[1].rdclass - rdtype = rrset[1].rdtype - rrname = rrset[0] - original_ttl = rrset[1].ttl - else: - rdclass = rrset.rdclass - rdtype = rrset.rdtype - rrname = rrset.name - original_ttl = rrset.ttl - - if inception is not None: - rrsig_inception = to_timestamp(inception) - else: - rrsig_inception = int(time.time()) - - if expiration is not None: - rrsig_expiration = to_timestamp(expiration) - elif lifetime is not None: - rrsig_expiration = rrsig_inception + lifetime - else: - raise ValueError("expiration or lifetime must be specified") - - # Derelativize now because we need a correct labels length for the - # rrsig_template. - if origin is not None: - rrname = rrname.derelativize(origin) - labels = len(rrname) - 1 - - # Adjust labels appropriately for wildcards. - if rrname.is_wild(): - labels -= 1 - - rrsig_template = RRSIG( - rdclass=rdclass, - rdtype=dns.rdatatype.RRSIG, - type_covered=rdtype, - algorithm=dnskey.algorithm, - labels=labels, - original_ttl=original_ttl, - expiration=rrsig_expiration, - inception=rrsig_inception, - key_tag=key_id(dnskey), - signer=signer, - signature=b"", - ) - - data = dns.dnssec._make_rrsig_signature_data(rrset, rrsig_template, origin) - - # pylint: disable=possibly-used-before-assignment - if isinstance(private_key, GenericPrivateKey): - signing_key = private_key - else: - try: - private_cls = get_algorithm_cls_from_dnskey(dnskey) - signing_key = private_cls(key=private_key) - except UnsupportedAlgorithm: - raise TypeError("Unsupported key algorithm") - - signature = signing_key.sign(data, verify, deterministic) - - return cast(RRSIG, rrsig_template.replace(signature=signature)) - - -def _make_rrsig_signature_data( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - rrsig: RRSIG, - origin: Optional[dns.name.Name] = None, -) -> bytes: - """Create signature rdata. - - *rrset*, the RRset to sign/validate. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *rrsig*, a ``dns.rdata.Rdata``, the signature to validate, or the - signature template used when signing. - - *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative - names. - - Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by - dnspython but not implemented. - """ - - if isinstance(origin, str): - origin = dns.name.from_text(origin, dns.name.root) - - signer = rrsig.signer - if not signer.is_absolute(): - if origin is None: - raise ValidationFailure("relative RR name without an origin specified") - signer = signer.derelativize(origin) - - # For convenience, allow the rrset to be specified as a (name, - # rdataset) tuple as well as a proper rrset - rrname, rdataset = _get_rrname_rdataset(rrset) - - data = b"" - wire = rrsig.to_wire(origin=signer) - assert wire is not None # for mypy - data += wire[:18] - data += rrsig.signer.to_digestable(signer) - - # Derelativize the name before considering labels. - if not rrname.is_absolute(): - if origin is None: - raise ValidationFailure("relative RR name without an origin specified") - rrname = rrname.derelativize(origin) - - name_len = len(rrname) - if rrname.is_wild() and rrsig.labels != name_len - 2: - raise ValidationFailure("wild owner name has wrong label length") - if name_len - 1 < rrsig.labels: - raise ValidationFailure("owner name longer than RRSIG labels") - elif rrsig.labels < name_len - 1: - suffix = rrname.split(rrsig.labels + 1)[1] - rrname = dns.name.from_text("*", suffix) - rrnamebuf = rrname.to_digestable() - rrfixed = struct.pack("!HHI", rdataset.rdtype, rdataset.rdclass, rrsig.original_ttl) - rdatas = [rdata.to_digestable(origin) for rdata in rdataset] - for rdata in sorted(rdatas): - data += rrnamebuf - data += rrfixed - rrlen = struct.pack("!H", len(rdata)) - data += rrlen - data += rdata - - return data - - -def _make_dnskey( - public_key: PublicKey, - algorithm: Union[int, str], - flags: int = Flag.ZONE, - protocol: int = 3, -) -> DNSKEY: - """Convert a public key to DNSKEY Rdata - - *public_key*, a ``PublicKey`` (``GenericPublicKey`` or - ``cryptography.hazmat.primitives.asymmetric``) to convert. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *flags*: DNSKEY flags field as an integer. - - *protocol*: DNSKEY protocol field as an integer. - - Raises ``ValueError`` if the specified key algorithm parameters are not - unsupported, ``TypeError`` if the key type is unsupported, - `UnsupportedAlgorithm` if the algorithm is unknown and - `AlgorithmKeyMismatch` if the algorithm does not match the key type. - - Return DNSKEY ``Rdata``. - """ - - algorithm = Algorithm.make(algorithm) - - # pylint: disable=possibly-used-before-assignment - if isinstance(public_key, GenericPublicKey): - return public_key.to_dnskey(flags=flags, protocol=protocol) - else: - public_cls = get_algorithm_cls(algorithm).public_cls - return public_cls(key=public_key).to_dnskey(flags=flags, protocol=protocol) - - -def _make_cdnskey( - public_key: PublicKey, - algorithm: Union[int, str], - flags: int = Flag.ZONE, - protocol: int = 3, -) -> CDNSKEY: - """Convert a public key to CDNSKEY Rdata - - *public_key*, the public key to convert, a - ``cryptography.hazmat.primitives.asymmetric`` public key class applicable - for DNSSEC. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *flags*: DNSKEY flags field as an integer. - - *protocol*: DNSKEY protocol field as an integer. - - Raises ``ValueError`` if the specified key algorithm parameters are not - unsupported, ``TypeError`` if the key type is unsupported, - `UnsupportedAlgorithm` if the algorithm is unknown and - `AlgorithmKeyMismatch` if the algorithm does not match the key type. - - Return CDNSKEY ``Rdata``. - """ - - dnskey = _make_dnskey(public_key, algorithm, flags, protocol) - - return CDNSKEY( - rdclass=dnskey.rdclass, - rdtype=dns.rdatatype.CDNSKEY, - flags=dnskey.flags, - protocol=dnskey.protocol, - algorithm=dnskey.algorithm, - key=dnskey.key, - ) - - -def nsec3_hash( - domain: Union[dns.name.Name, str], - salt: Optional[Union[str, bytes]], - iterations: int, - algorithm: Union[int, str], -) -> str: - """ - Calculate the NSEC3 hash, according to - https://tools.ietf.org/html/rfc5155#section-5 - - *domain*, a ``dns.name.Name`` or ``str``, the name to hash. - - *salt*, a ``str``, ``bytes``, or ``None``, the hash salt. If a - string, it is decoded as a hex string. - - *iterations*, an ``int``, the number of iterations. - - *algorithm*, a ``str`` or ``int``, the hash algorithm. - The only defined algorithm is SHA1. - - Returns a ``str``, the encoded NSEC3 hash. - """ - - b32_conversion = str.maketrans( - "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "0123456789ABCDEFGHIJKLMNOPQRSTUV" - ) - - try: - if isinstance(algorithm, str): - algorithm = NSEC3Hash[algorithm.upper()] - except Exception: - raise ValueError("Wrong hash algorithm (only SHA1 is supported)") - - if algorithm != NSEC3Hash.SHA1: - raise ValueError("Wrong hash algorithm (only SHA1 is supported)") - - if salt is None: - salt_encoded = b"" - elif isinstance(salt, str): - if len(salt) % 2 == 0: - salt_encoded = bytes.fromhex(salt) - else: - raise ValueError("Invalid salt length") - else: - salt_encoded = salt - - if not isinstance(domain, dns.name.Name): - domain = dns.name.from_text(domain) - domain_encoded = domain.canonicalize().to_wire() - assert domain_encoded is not None - - digest = hashlib.sha1(domain_encoded + salt_encoded).digest() - for _ in range(iterations): - digest = hashlib.sha1(digest + salt_encoded).digest() - - output = base64.b32encode(digest).decode("utf-8") - output = output.translate(b32_conversion) - - return output - - -def make_ds_rdataset( - rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]], - algorithms: Set[Union[DSDigest, str]], - origin: Optional[dns.name.Name] = None, -) -> dns.rdataset.Rdataset: - """Create a DS record from DNSKEY/CDNSKEY/CDS. - - *rrset*, the RRset to create DS Rdataset for. This can be a - ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``) - tuple. - - *algorithms*, a set of ``str`` or ``int`` specifying the hash algorithms. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. If the RRset is a CDS, only digest - algorithms matching algorithms are accepted. - - *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if any of the algorithms are unknown and - ``ValueError`` if the given RRset is not usable. - - Returns a ``dns.rdataset.Rdataset`` - """ - - rrname, rdataset = _get_rrname_rdataset(rrset) - - if rdataset.rdtype not in ( - dns.rdatatype.DNSKEY, - dns.rdatatype.CDNSKEY, - dns.rdatatype.CDS, - ): - raise ValueError("rrset not a DNSKEY/CDNSKEY/CDS") - - _algorithms = set() - for algorithm in algorithms: - try: - if isinstance(algorithm, str): - algorithm = DSDigest[algorithm.upper()] - except Exception: - raise UnsupportedAlgorithm(f'unsupported algorithm "{algorithm}"') - _algorithms.add(algorithm) - - if rdataset.rdtype == dns.rdatatype.CDS: - res = [] - for rdata in cds_rdataset_to_ds_rdataset(rdataset): - if rdata.digest_type in _algorithms: - res.append(rdata) - if len(res) == 0: - raise ValueError("no acceptable CDS rdata found") - return dns.rdataset.from_rdata_list(rdataset.ttl, res) - - res = [] - for algorithm in _algorithms: - res.extend(dnskey_rdataset_to_cds_rdataset(rrname, rdataset, algorithm, origin)) - return dns.rdataset.from_rdata_list(rdataset.ttl, res) - - -def cds_rdataset_to_ds_rdataset( - rdataset: dns.rdataset.Rdataset, -) -> dns.rdataset.Rdataset: - """Create a CDS record from DS. - - *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for. - - Raises ``ValueError`` if the rdataset is not CDS. - - Returns a ``dns.rdataset.Rdataset`` - """ - - if rdataset.rdtype != dns.rdatatype.CDS: - raise ValueError("rdataset not a CDS") - res = [] - for rdata in rdataset: - res.append( - CDS( - rdclass=rdata.rdclass, - rdtype=dns.rdatatype.DS, - key_tag=rdata.key_tag, - algorithm=rdata.algorithm, - digest_type=rdata.digest_type, - digest=rdata.digest, - ) - ) - return dns.rdataset.from_rdata_list(rdataset.ttl, res) - - -def dnskey_rdataset_to_cds_rdataset( - name: Union[dns.name.Name, str], - rdataset: dns.rdataset.Rdataset, - algorithm: Union[DSDigest, str], - origin: Optional[dns.name.Name] = None, -) -> dns.rdataset.Rdataset: - """Create a CDS record from DNSKEY/CDNSKEY. - - *name*, a ``dns.name.Name`` or ``str``, the owner name of the CDS record. - - *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for. - - *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. - The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case - does not matter for these strings. - - *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name, - then it will be made absolute using the specified origin. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown or - ``ValueError`` if the rdataset is not DNSKEY/CDNSKEY. - - Returns a ``dns.rdataset.Rdataset`` - """ - - if rdataset.rdtype not in (dns.rdatatype.DNSKEY, dns.rdatatype.CDNSKEY): - raise ValueError("rdataset not a DNSKEY/CDNSKEY") - res = [] - for rdata in rdataset: - res.append(make_cds(name, rdata, algorithm, origin)) - return dns.rdataset.from_rdata_list(rdataset.ttl, res) - - -def dnskey_rdataset_to_cdnskey_rdataset( - rdataset: dns.rdataset.Rdataset, -) -> dns.rdataset.Rdataset: - """Create a CDNSKEY record from DNSKEY. - - *rdataset*, a ``dns.rdataset.Rdataset``, to create CDNSKEY Rdataset for. - - Returns a ``dns.rdataset.Rdataset`` - """ - - if rdataset.rdtype != dns.rdatatype.DNSKEY: - raise ValueError("rdataset not a DNSKEY") - res = [] - for rdata in rdataset: - res.append( - CDNSKEY( - rdclass=rdataset.rdclass, - rdtype=rdataset.rdtype, - flags=rdata.flags, - protocol=rdata.protocol, - algorithm=rdata.algorithm, - key=rdata.key, - ) - ) - return dns.rdataset.from_rdata_list(rdataset.ttl, res) - - -def default_rrset_signer( - txn: dns.transaction.Transaction, - rrset: dns.rrset.RRset, - signer: dns.name.Name, - ksks: List[Tuple[PrivateKey, DNSKEY]], - zsks: List[Tuple[PrivateKey, DNSKEY]], - inception: Optional[Union[datetime, str, int, float]] = None, - expiration: Optional[Union[datetime, str, int, float]] = None, - lifetime: Optional[int] = None, - policy: Optional[Policy] = None, - origin: Optional[dns.name.Name] = None, - deterministic: bool = True, -) -> None: - """Default RRset signer""" - - if rrset.rdtype in set( - [ - dns.rdatatype.RdataType.DNSKEY, - dns.rdatatype.RdataType.CDS, - dns.rdatatype.RdataType.CDNSKEY, - ] - ): - keys = ksks - else: - keys = zsks - - for private_key, dnskey in keys: - rrsig = dns.dnssec.sign( - rrset=rrset, - private_key=private_key, - dnskey=dnskey, - inception=inception, - expiration=expiration, - lifetime=lifetime, - signer=signer, - policy=policy, - origin=origin, - deterministic=deterministic, - ) - txn.add(rrset.name, rrset.ttl, rrsig) - - -def sign_zone( - zone: dns.zone.Zone, - txn: Optional[dns.transaction.Transaction] = None, - keys: Optional[List[Tuple[PrivateKey, DNSKEY]]] = None, - add_dnskey: bool = True, - dnskey_ttl: Optional[int] = None, - inception: Optional[Union[datetime, str, int, float]] = None, - expiration: Optional[Union[datetime, str, int, float]] = None, - lifetime: Optional[int] = None, - nsec3: Optional[NSEC3PARAM] = None, - rrset_signer: Optional[RRsetSigner] = None, - policy: Optional[Policy] = None, - deterministic: bool = True, -) -> None: - """Sign zone. - - *zone*, a ``dns.zone.Zone``, the zone to sign. - - *txn*, a ``dns.transaction.Transaction``, an optional transaction to use for - signing. - - *keys*, a list of (``PrivateKey``, ``DNSKEY``) tuples, to use for signing. KSK/ZSK - roles are assigned automatically if the SEP flag is used, otherwise all RRsets are - signed by all keys. - - *add_dnskey*, a ``bool``. If ``True``, the default, all specified DNSKEYs are - automatically added to the zone on signing. - - *dnskey_ttl*, a``int``, specifies the TTL for DNSKEY RRs. If not specified the TTL - of the existing DNSKEY RRset used or the TTL of the SOA RRset. - - *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - inception time. If ``None``, the current time is used. If a ``str``, the format is - "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX epoch in text - form; this is the same the RRSIG rdata's text form. Values of type `int` or `float` - are interpreted as seconds since the UNIX epoch. - - *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature - expiration time. If ``None``, the expiration time will be the inception time plus - the value of the *lifetime* parameter. See the description of *inception* above for - how the various parameter types are interpreted. - - *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This - parameter is only meaningful if *expiration* is ``None``. - - *nsec3*, a ``NSEC3PARAM`` Rdata, configures signing using NSEC3. Not yet - implemented. - - *rrset_signer*, a ``Callable``, an optional function for signing RRsets. The - function requires two arguments: transaction and RRset. If the not specified, - ``dns.dnssec.default_rrset_signer`` will be used. - - *deterministic*, a ``bool``. If ``True``, the default, use deterministic - (reproducible) signatures when supported by the algorithm used for signing. - Currently, this only affects ECDSA. - - Returns ``None``. - """ - - ksks = [] - zsks = [] - - # if we have both KSKs and ZSKs, split by SEP flag. if not, sign all - # records with all keys - if keys: - for key in keys: - if key[1].flags & Flag.SEP: - ksks.append(key) - else: - zsks.append(key) - if not ksks: - ksks = keys - if not zsks: - zsks = keys - else: - keys = [] - - if txn: - cm: contextlib.AbstractContextManager = contextlib.nullcontext(txn) - else: - cm = zone.writer() - - if zone.origin is None: - raise ValueError("no zone origin") - - with cm as _txn: - if add_dnskey: - if dnskey_ttl is None: - dnskey = _txn.get(zone.origin, dns.rdatatype.DNSKEY) - if dnskey: - dnskey_ttl = dnskey.ttl - else: - soa = _txn.get(zone.origin, dns.rdatatype.SOA) - dnskey_ttl = soa.ttl - for _, dnskey in keys: - _txn.add(zone.origin, dnskey_ttl, dnskey) - - if nsec3: - raise NotImplementedError("Signing with NSEC3 not yet implemented") - else: - _rrset_signer = rrset_signer or functools.partial( - default_rrset_signer, - signer=zone.origin, - ksks=ksks, - zsks=zsks, - inception=inception, - expiration=expiration, - lifetime=lifetime, - policy=policy, - origin=zone.origin, - deterministic=deterministic, - ) - return _sign_zone_nsec(zone, _txn, _rrset_signer) - - -def _sign_zone_nsec( - zone: dns.zone.Zone, - txn: dns.transaction.Transaction, - rrset_signer: Optional[RRsetSigner] = None, -) -> None: - """NSEC zone signer""" - - def _txn_add_nsec( - txn: dns.transaction.Transaction, - name: dns.name.Name, - next_secure: Optional[dns.name.Name], - rdclass: dns.rdataclass.RdataClass, - ttl: int, - rrset_signer: Optional[RRsetSigner] = None, - ) -> None: - """NSEC zone signer helper""" - mandatory_types = set( - [dns.rdatatype.RdataType.RRSIG, dns.rdatatype.RdataType.NSEC] - ) - node = txn.get_node(name) - if node and next_secure: - types = ( - set([rdataset.rdtype for rdataset in node.rdatasets]) | mandatory_types - ) - windows = Bitmap.from_rdtypes(list(types)) - rrset = dns.rrset.from_rdata( - name, - ttl, - NSEC( - rdclass=rdclass, - rdtype=dns.rdatatype.RdataType.NSEC, - next=next_secure, - windows=windows, - ), - ) - txn.add(rrset) - if rrset_signer: - rrset_signer(txn, rrset) - - rrsig_ttl = zone.get_soa().minimum - delegation = None - last_secure = None - - for name in sorted(txn.iterate_names()): - if delegation and name.is_subdomain(delegation): - # names below delegations are not secure - continue - elif txn.get(name, dns.rdatatype.NS) and name != zone.origin: - # inside delegation - delegation = name - else: - # outside delegation - delegation = None - - if rrset_signer: - node = txn.get_node(name) - if node: - for rdataset in node.rdatasets: - if rdataset.rdtype == dns.rdatatype.RRSIG: - # do not sign RRSIGs - continue - elif delegation and rdataset.rdtype != dns.rdatatype.DS: - # do not sign delegations except DS records - continue - else: - rrset = dns.rrset.from_rdata(name, rdataset.ttl, *rdataset) - rrset_signer(txn, rrset) - - # We need "is not None" as the empty name is False because its length is 0. - if last_secure is not None: - _txn_add_nsec(txn, last_secure, name, zone.rdclass, rrsig_ttl, rrset_signer) - last_secure = name - - if last_secure: - _txn_add_nsec( - txn, last_secure, zone.origin, zone.rdclass, rrsig_ttl, rrset_signer - ) - - -def _need_pyca(*args, **kwargs): - raise ImportError( - "DNSSEC validation requires python cryptography" - ) # pragma: no cover - - -if dns._features.have("dnssec"): - from cryptography.exceptions import InvalidSignature - from cryptography.hazmat.primitives.asymmetric import dsa # pylint: disable=W0611 - from cryptography.hazmat.primitives.asymmetric import ec # pylint: disable=W0611 - from cryptography.hazmat.primitives.asymmetric import ed448 # pylint: disable=W0611 - from cryptography.hazmat.primitives.asymmetric import rsa # pylint: disable=W0611 - from cryptography.hazmat.primitives.asymmetric import ( # pylint: disable=W0611 - ed25519, - ) - - from dns.dnssecalgs import ( # pylint: disable=C0412 - get_algorithm_cls, - get_algorithm_cls_from_dnskey, - ) - from dns.dnssecalgs.base import GenericPrivateKey, GenericPublicKey - - validate = _validate # type: ignore - validate_rrsig = _validate_rrsig # type: ignore - sign = _sign - make_dnskey = _make_dnskey - make_cdnskey = _make_cdnskey - _have_pyca = True -else: # pragma: no cover - validate = _need_pyca - validate_rrsig = _need_pyca - sign = _need_pyca - make_dnskey = _need_pyca - make_cdnskey = _need_pyca - _have_pyca = False - -### BEGIN generated Algorithm constants - -RSAMD5 = Algorithm.RSAMD5 -DH = Algorithm.DH -DSA = Algorithm.DSA -ECC = Algorithm.ECC -RSASHA1 = Algorithm.RSASHA1 -DSANSEC3SHA1 = Algorithm.DSANSEC3SHA1 -RSASHA1NSEC3SHA1 = Algorithm.RSASHA1NSEC3SHA1 -RSASHA256 = Algorithm.RSASHA256 -RSASHA512 = Algorithm.RSASHA512 -ECCGOST = Algorithm.ECCGOST -ECDSAP256SHA256 = Algorithm.ECDSAP256SHA256 -ECDSAP384SHA384 = Algorithm.ECDSAP384SHA384 -ED25519 = Algorithm.ED25519 -ED448 = Algorithm.ED448 -INDIRECT = Algorithm.INDIRECT -PRIVATEDNS = Algorithm.PRIVATEDNS -PRIVATEOID = Algorithm.PRIVATEOID - -### END generated Algorithm constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/__init__.py deleted file mode 100644 index 602367e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/__init__.py +++ /dev/null @@ -1,121 +0,0 @@ -from typing import Dict, Optional, Tuple, Type, Union - -import dns.name -from dns.dnssecalgs.base import GenericPrivateKey -from dns.dnssectypes import Algorithm -from dns.exception import UnsupportedAlgorithm -from dns.rdtypes.ANY.DNSKEY import DNSKEY - -if dns._features.have("dnssec"): - from dns.dnssecalgs.dsa import PrivateDSA, PrivateDSANSEC3SHA1 - from dns.dnssecalgs.ecdsa import PrivateECDSAP256SHA256, PrivateECDSAP384SHA384 - from dns.dnssecalgs.eddsa import PrivateED448, PrivateED25519 - from dns.dnssecalgs.rsa import ( - PrivateRSAMD5, - PrivateRSASHA1, - PrivateRSASHA1NSEC3SHA1, - PrivateRSASHA256, - PrivateRSASHA512, - ) - - _have_cryptography = True -else: - _have_cryptography = False - -AlgorithmPrefix = Optional[Union[bytes, dns.name.Name]] - -algorithms: Dict[Tuple[Algorithm, AlgorithmPrefix], Type[GenericPrivateKey]] = {} -if _have_cryptography: - # pylint: disable=possibly-used-before-assignment - algorithms.update( - { - (Algorithm.RSAMD5, None): PrivateRSAMD5, - (Algorithm.DSA, None): PrivateDSA, - (Algorithm.RSASHA1, None): PrivateRSASHA1, - (Algorithm.DSANSEC3SHA1, None): PrivateDSANSEC3SHA1, - (Algorithm.RSASHA1NSEC3SHA1, None): PrivateRSASHA1NSEC3SHA1, - (Algorithm.RSASHA256, None): PrivateRSASHA256, - (Algorithm.RSASHA512, None): PrivateRSASHA512, - (Algorithm.ECDSAP256SHA256, None): PrivateECDSAP256SHA256, - (Algorithm.ECDSAP384SHA384, None): PrivateECDSAP384SHA384, - (Algorithm.ED25519, None): PrivateED25519, - (Algorithm.ED448, None): PrivateED448, - } - ) - - -def get_algorithm_cls( - algorithm: Union[int, str], prefix: AlgorithmPrefix = None -) -> Type[GenericPrivateKey]: - """Get Private Key class from Algorithm. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.dnssecalgs.GenericPrivateKey`` - """ - algorithm = Algorithm.make(algorithm) - cls = algorithms.get((algorithm, prefix)) - if cls: - return cls - raise UnsupportedAlgorithm( - f'algorithm "{Algorithm.to_text(algorithm)}" not supported by dnspython' - ) - - -def get_algorithm_cls_from_dnskey(dnskey: DNSKEY) -> Type[GenericPrivateKey]: - """Get Private Key class from DNSKEY. - - *dnskey*, a ``DNSKEY`` to get Algorithm class for. - - Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. - - Returns a ``dns.dnssecalgs.GenericPrivateKey`` - """ - prefix: AlgorithmPrefix = None - if dnskey.algorithm == Algorithm.PRIVATEDNS: - prefix, _ = dns.name.from_wire(dnskey.key, 0) - elif dnskey.algorithm == Algorithm.PRIVATEOID: - length = int(dnskey.key[0]) - prefix = dnskey.key[0 : length + 1] - return get_algorithm_cls(dnskey.algorithm, prefix) - - -def register_algorithm_cls( - algorithm: Union[int, str], - algorithm_cls: Type[GenericPrivateKey], - name: Optional[Union[dns.name.Name, str]] = None, - oid: Optional[bytes] = None, -) -> None: - """Register Algorithm Private Key class. - - *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm. - - *algorithm_cls*: A `GenericPrivateKey` class. - - *name*, an optional ``dns.name.Name`` or ``str``, for for PRIVATEDNS algorithms. - - *oid*: an optional BER-encoded `bytes` for PRIVATEOID algorithms. - - Raises ``ValueError`` if a name or oid is specified incorrectly. - """ - if not issubclass(algorithm_cls, GenericPrivateKey): - raise TypeError("Invalid algorithm class") - algorithm = Algorithm.make(algorithm) - prefix: AlgorithmPrefix = None - if algorithm == Algorithm.PRIVATEDNS: - if name is None: - raise ValueError("Name required for PRIVATEDNS algorithms") - if isinstance(name, str): - name = dns.name.from_text(name) - prefix = name - elif algorithm == Algorithm.PRIVATEOID: - if oid is None: - raise ValueError("OID required for PRIVATEOID algorithms") - prefix = bytes([len(oid)]) + oid - elif name: - raise ValueError("Name only supported for PRIVATEDNS algorithm") - elif oid: - raise ValueError("OID only supported for PRIVATEOID algorithm") - algorithms[(algorithm, prefix)] = algorithm_cls diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/base.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/base.py deleted file mode 100644 index 752ee48..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/base.py +++ /dev/null @@ -1,89 +0,0 @@ -from abc import ABC, abstractmethod # pylint: disable=no-name-in-module -from typing import Any, Optional, Type - -import dns.rdataclass -import dns.rdatatype -from dns.dnssectypes import Algorithm -from dns.exception import AlgorithmKeyMismatch -from dns.rdtypes.ANY.DNSKEY import DNSKEY -from dns.rdtypes.dnskeybase import Flag - - -class GenericPublicKey(ABC): - algorithm: Algorithm - - @abstractmethod - def __init__(self, key: Any) -> None: - pass - - @abstractmethod - def verify(self, signature: bytes, data: bytes) -> None: - """Verify signed DNSSEC data""" - - @abstractmethod - def encode_key_bytes(self) -> bytes: - """Encode key as bytes for DNSKEY""" - - @classmethod - def _ensure_algorithm_key_combination(cls, key: DNSKEY) -> None: - if key.algorithm != cls.algorithm: - raise AlgorithmKeyMismatch - - def to_dnskey(self, flags: int = Flag.ZONE, protocol: int = 3) -> DNSKEY: - """Return public key as DNSKEY""" - return DNSKEY( - rdclass=dns.rdataclass.IN, - rdtype=dns.rdatatype.DNSKEY, - flags=flags, - protocol=protocol, - algorithm=self.algorithm, - key=self.encode_key_bytes(), - ) - - @classmethod - @abstractmethod - def from_dnskey(cls, key: DNSKEY) -> "GenericPublicKey": - """Create public key from DNSKEY""" - - @classmethod - @abstractmethod - def from_pem(cls, public_pem: bytes) -> "GenericPublicKey": - """Create public key from PEM-encoded SubjectPublicKeyInfo as specified - in RFC 5280""" - - @abstractmethod - def to_pem(self) -> bytes: - """Return public-key as PEM-encoded SubjectPublicKeyInfo as specified - in RFC 5280""" - - -class GenericPrivateKey(ABC): - public_cls: Type[GenericPublicKey] - - @abstractmethod - def __init__(self, key: Any) -> None: - pass - - @abstractmethod - def sign( - self, - data: bytes, - verify: bool = False, - deterministic: bool = True, - ) -> bytes: - """Sign DNSSEC data""" - - @abstractmethod - def public_key(self) -> "GenericPublicKey": - """Return public key instance""" - - @classmethod - @abstractmethod - def from_pem( - cls, private_pem: bytes, password: Optional[bytes] = None - ) -> "GenericPrivateKey": - """Create private key from PEM-encoded PKCS#8""" - - @abstractmethod - def to_pem(self, password: Optional[bytes] = None) -> bytes: - """Return private key as PEM-encoded PKCS#8""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/cryptography.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/cryptography.py deleted file mode 100644 index 5a31a81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/cryptography.py +++ /dev/null @@ -1,68 +0,0 @@ -from typing import Any, Optional, Type - -from cryptography.hazmat.primitives import serialization - -from dns.dnssecalgs.base import GenericPrivateKey, GenericPublicKey -from dns.exception import AlgorithmKeyMismatch - - -class CryptographyPublicKey(GenericPublicKey): - key: Any = None - key_cls: Any = None - - def __init__(self, key: Any) -> None: # pylint: disable=super-init-not-called - if self.key_cls is None: - raise TypeError("Undefined private key class") - if not isinstance( # pylint: disable=isinstance-second-argument-not-valid-type - key, self.key_cls - ): - raise AlgorithmKeyMismatch - self.key = key - - @classmethod - def from_pem(cls, public_pem: bytes) -> "GenericPublicKey": - key = serialization.load_pem_public_key(public_pem) - return cls(key=key) - - def to_pem(self) -> bytes: - return self.key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo, - ) - - -class CryptographyPrivateKey(GenericPrivateKey): - key: Any = None - key_cls: Any = None - public_cls: Type[CryptographyPublicKey] - - def __init__(self, key: Any) -> None: # pylint: disable=super-init-not-called - if self.key_cls is None: - raise TypeError("Undefined private key class") - if not isinstance( # pylint: disable=isinstance-second-argument-not-valid-type - key, self.key_cls - ): - raise AlgorithmKeyMismatch - self.key = key - - def public_key(self) -> "CryptographyPublicKey": - return self.public_cls(key=self.key.public_key()) - - @classmethod - def from_pem( - cls, private_pem: bytes, password: Optional[bytes] = None - ) -> "GenericPrivateKey": - key = serialization.load_pem_private_key(private_pem, password=password) - return cls(key=key) - - def to_pem(self, password: Optional[bytes] = None) -> bytes: - encryption_algorithm: serialization.KeySerializationEncryption - if password: - encryption_algorithm = serialization.BestAvailableEncryption(password) - else: - encryption_algorithm = serialization.NoEncryption() - return self.key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.PKCS8, - encryption_algorithm=encryption_algorithm, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/dsa.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/dsa.py deleted file mode 100644 index adca3de..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/dsa.py +++ /dev/null @@ -1,106 +0,0 @@ -import struct - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import dsa, utils - -from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey -from dns.dnssectypes import Algorithm -from dns.rdtypes.ANY.DNSKEY import DNSKEY - - -class PublicDSA(CryptographyPublicKey): - key: dsa.DSAPublicKey - key_cls = dsa.DSAPublicKey - algorithm = Algorithm.DSA - chosen_hash = hashes.SHA1() - - def verify(self, signature: bytes, data: bytes) -> None: - sig_r = signature[1:21] - sig_s = signature[21:] - sig = utils.encode_dss_signature( - int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big") - ) - self.key.verify(sig, data, self.chosen_hash) - - def encode_key_bytes(self) -> bytes: - """Encode a public key per RFC 2536, section 2.""" - pn = self.key.public_numbers() - dsa_t = (self.key.key_size // 8 - 64) // 8 - if dsa_t > 8: - raise ValueError("unsupported DSA key size") - octets = 64 + dsa_t * 8 - res = struct.pack("!B", dsa_t) - res += pn.parameter_numbers.q.to_bytes(20, "big") - res += pn.parameter_numbers.p.to_bytes(octets, "big") - res += pn.parameter_numbers.g.to_bytes(octets, "big") - res += pn.y.to_bytes(octets, "big") - return res - - @classmethod - def from_dnskey(cls, key: DNSKEY) -> "PublicDSA": - cls._ensure_algorithm_key_combination(key) - keyptr = key.key - (t,) = struct.unpack("!B", keyptr[0:1]) - keyptr = keyptr[1:] - octets = 64 + t * 8 - dsa_q = keyptr[0:20] - keyptr = keyptr[20:] - dsa_p = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_g = keyptr[0:octets] - keyptr = keyptr[octets:] - dsa_y = keyptr[0:octets] - return cls( - key=dsa.DSAPublicNumbers( # type: ignore - int.from_bytes(dsa_y, "big"), - dsa.DSAParameterNumbers( - int.from_bytes(dsa_p, "big"), - int.from_bytes(dsa_q, "big"), - int.from_bytes(dsa_g, "big"), - ), - ).public_key(default_backend()), - ) - - -class PrivateDSA(CryptographyPrivateKey): - key: dsa.DSAPrivateKey - key_cls = dsa.DSAPrivateKey - public_cls = PublicDSA - - def sign( - self, - data: bytes, - verify: bool = False, - deterministic: bool = True, - ) -> bytes: - """Sign using a private key per RFC 2536, section 3.""" - public_dsa_key = self.key.public_key() - if public_dsa_key.key_size > 1024: - raise ValueError("DSA key size overflow") - der_signature = self.key.sign(data, self.public_cls.chosen_hash) - dsa_r, dsa_s = utils.decode_dss_signature(der_signature) - dsa_t = (public_dsa_key.key_size // 8 - 64) // 8 - octets = 20 - signature = ( - struct.pack("!B", dsa_t) - + int.to_bytes(dsa_r, length=octets, byteorder="big") - + int.to_bytes(dsa_s, length=octets, byteorder="big") - ) - if verify: - self.public_key().verify(signature, data) - return signature - - @classmethod - def generate(cls, key_size: int) -> "PrivateDSA": - return cls( - key=dsa.generate_private_key(key_size=key_size), - ) - - -class PublicDSANSEC3SHA1(PublicDSA): - algorithm = Algorithm.DSANSEC3SHA1 - - -class PrivateDSANSEC3SHA1(PrivateDSA): - public_cls = PublicDSANSEC3SHA1 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/ecdsa.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/ecdsa.py deleted file mode 100644 index 86d5764..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/ecdsa.py +++ /dev/null @@ -1,97 +0,0 @@ -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ec, utils - -from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey -from dns.dnssectypes import Algorithm -from dns.rdtypes.ANY.DNSKEY import DNSKEY - - -class PublicECDSA(CryptographyPublicKey): - key: ec.EllipticCurvePublicKey - key_cls = ec.EllipticCurvePublicKey - algorithm: Algorithm - chosen_hash: hashes.HashAlgorithm - curve: ec.EllipticCurve - octets: int - - def verify(self, signature: bytes, data: bytes) -> None: - sig_r = signature[0 : self.octets] - sig_s = signature[self.octets :] - sig = utils.encode_dss_signature( - int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big") - ) - self.key.verify(sig, data, ec.ECDSA(self.chosen_hash)) - - def encode_key_bytes(self) -> bytes: - """Encode a public key per RFC 6605, section 4.""" - pn = self.key.public_numbers() - return pn.x.to_bytes(self.octets, "big") + pn.y.to_bytes(self.octets, "big") - - @classmethod - def from_dnskey(cls, key: DNSKEY) -> "PublicECDSA": - cls._ensure_algorithm_key_combination(key) - ecdsa_x = key.key[0 : cls.octets] - ecdsa_y = key.key[cls.octets : cls.octets * 2] - return cls( - key=ec.EllipticCurvePublicNumbers( - curve=cls.curve, - x=int.from_bytes(ecdsa_x, "big"), - y=int.from_bytes(ecdsa_y, "big"), - ).public_key(default_backend()), - ) - - -class PrivateECDSA(CryptographyPrivateKey): - key: ec.EllipticCurvePrivateKey - key_cls = ec.EllipticCurvePrivateKey - public_cls = PublicECDSA - - def sign( - self, - data: bytes, - verify: bool = False, - deterministic: bool = True, - ) -> bytes: - """Sign using a private key per RFC 6605, section 4.""" - algorithm = ec.ECDSA( - self.public_cls.chosen_hash, deterministic_signing=deterministic - ) - der_signature = self.key.sign(data, algorithm) - dsa_r, dsa_s = utils.decode_dss_signature(der_signature) - signature = int.to_bytes( - dsa_r, length=self.public_cls.octets, byteorder="big" - ) + int.to_bytes(dsa_s, length=self.public_cls.octets, byteorder="big") - if verify: - self.public_key().verify(signature, data) - return signature - - @classmethod - def generate(cls) -> "PrivateECDSA": - return cls( - key=ec.generate_private_key( - curve=cls.public_cls.curve, backend=default_backend() - ), - ) - - -class PublicECDSAP256SHA256(PublicECDSA): - algorithm = Algorithm.ECDSAP256SHA256 - chosen_hash = hashes.SHA256() - curve = ec.SECP256R1() - octets = 32 - - -class PrivateECDSAP256SHA256(PrivateECDSA): - public_cls = PublicECDSAP256SHA256 - - -class PublicECDSAP384SHA384(PublicECDSA): - algorithm = Algorithm.ECDSAP384SHA384 - chosen_hash = hashes.SHA384() - curve = ec.SECP384R1() - octets = 48 - - -class PrivateECDSAP384SHA384(PrivateECDSA): - public_cls = PublicECDSAP384SHA384 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/eddsa.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/eddsa.py deleted file mode 100644 index 604bcbf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/eddsa.py +++ /dev/null @@ -1,70 +0,0 @@ -from typing import Type - -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import ed448, ed25519 - -from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey -from dns.dnssectypes import Algorithm -from dns.rdtypes.ANY.DNSKEY import DNSKEY - - -class PublicEDDSA(CryptographyPublicKey): - def verify(self, signature: bytes, data: bytes) -> None: - self.key.verify(signature, data) - - def encode_key_bytes(self) -> bytes: - """Encode a public key per RFC 8080, section 3.""" - return self.key.public_bytes( - encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw - ) - - @classmethod - def from_dnskey(cls, key: DNSKEY) -> "PublicEDDSA": - cls._ensure_algorithm_key_combination(key) - return cls( - key=cls.key_cls.from_public_bytes(key.key), - ) - - -class PrivateEDDSA(CryptographyPrivateKey): - public_cls: Type[PublicEDDSA] - - def sign( - self, - data: bytes, - verify: bool = False, - deterministic: bool = True, - ) -> bytes: - """Sign using a private key per RFC 8080, section 4.""" - signature = self.key.sign(data) - if verify: - self.public_key().verify(signature, data) - return signature - - @classmethod - def generate(cls) -> "PrivateEDDSA": - return cls(key=cls.key_cls.generate()) - - -class PublicED25519(PublicEDDSA): - key: ed25519.Ed25519PublicKey - key_cls = ed25519.Ed25519PublicKey - algorithm = Algorithm.ED25519 - - -class PrivateED25519(PrivateEDDSA): - key: ed25519.Ed25519PrivateKey - key_cls = ed25519.Ed25519PrivateKey - public_cls = PublicED25519 - - -class PublicED448(PublicEDDSA): - key: ed448.Ed448PublicKey - key_cls = ed448.Ed448PublicKey - algorithm = Algorithm.ED448 - - -class PrivateED448(PrivateEDDSA): - key: ed448.Ed448PrivateKey - key_cls = ed448.Ed448PrivateKey - public_cls = PublicED448 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/rsa.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/rsa.py deleted file mode 100644 index 27537aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/rsa.py +++ /dev/null @@ -1,124 +0,0 @@ -import math -import struct - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import padding, rsa - -from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey -from dns.dnssectypes import Algorithm -from dns.rdtypes.ANY.DNSKEY import DNSKEY - - -class PublicRSA(CryptographyPublicKey): - key: rsa.RSAPublicKey - key_cls = rsa.RSAPublicKey - algorithm: Algorithm - chosen_hash: hashes.HashAlgorithm - - def verify(self, signature: bytes, data: bytes) -> None: - self.key.verify(signature, data, padding.PKCS1v15(), self.chosen_hash) - - def encode_key_bytes(self) -> bytes: - """Encode a public key per RFC 3110, section 2.""" - pn = self.key.public_numbers() - _exp_len = math.ceil(int.bit_length(pn.e) / 8) - exp = int.to_bytes(pn.e, length=_exp_len, byteorder="big") - if _exp_len > 255: - exp_header = b"\0" + struct.pack("!H", _exp_len) - else: - exp_header = struct.pack("!B", _exp_len) - if pn.n.bit_length() < 512 or pn.n.bit_length() > 4096: - raise ValueError("unsupported RSA key length") - return exp_header + exp + pn.n.to_bytes((pn.n.bit_length() + 7) // 8, "big") - - @classmethod - def from_dnskey(cls, key: DNSKEY) -> "PublicRSA": - cls._ensure_algorithm_key_combination(key) - keyptr = key.key - (bytes_,) = struct.unpack("!B", keyptr[0:1]) - keyptr = keyptr[1:] - if bytes_ == 0: - (bytes_,) = struct.unpack("!H", keyptr[0:2]) - keyptr = keyptr[2:] - rsa_e = keyptr[0:bytes_] - rsa_n = keyptr[bytes_:] - return cls( - key=rsa.RSAPublicNumbers( - int.from_bytes(rsa_e, "big"), int.from_bytes(rsa_n, "big") - ).public_key(default_backend()) - ) - - -class PrivateRSA(CryptographyPrivateKey): - key: rsa.RSAPrivateKey - key_cls = rsa.RSAPrivateKey - public_cls = PublicRSA - default_public_exponent = 65537 - - def sign( - self, - data: bytes, - verify: bool = False, - deterministic: bool = True, - ) -> bytes: - """Sign using a private key per RFC 3110, section 3.""" - signature = self.key.sign(data, padding.PKCS1v15(), self.public_cls.chosen_hash) - if verify: - self.public_key().verify(signature, data) - return signature - - @classmethod - def generate(cls, key_size: int) -> "PrivateRSA": - return cls( - key=rsa.generate_private_key( - public_exponent=cls.default_public_exponent, - key_size=key_size, - backend=default_backend(), - ) - ) - - -class PublicRSAMD5(PublicRSA): - algorithm = Algorithm.RSAMD5 - chosen_hash = hashes.MD5() - - -class PrivateRSAMD5(PrivateRSA): - public_cls = PublicRSAMD5 - - -class PublicRSASHA1(PublicRSA): - algorithm = Algorithm.RSASHA1 - chosen_hash = hashes.SHA1() - - -class PrivateRSASHA1(PrivateRSA): - public_cls = PublicRSASHA1 - - -class PublicRSASHA1NSEC3SHA1(PublicRSA): - algorithm = Algorithm.RSASHA1NSEC3SHA1 - chosen_hash = hashes.SHA1() - - -class PrivateRSASHA1NSEC3SHA1(PrivateRSA): - public_cls = PublicRSASHA1NSEC3SHA1 - - -class PublicRSASHA256(PublicRSA): - algorithm = Algorithm.RSASHA256 - chosen_hash = hashes.SHA256() - - -class PrivateRSASHA256(PrivateRSA): - public_cls = PublicRSASHA256 - - -class PublicRSASHA512(PublicRSA): - algorithm = Algorithm.RSASHA512 - chosen_hash = hashes.SHA512() - - -class PrivateRSASHA512(PrivateRSA): - public_cls = PublicRSASHA512 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/dnssectypes.py b/backend/venv39/lib/python3.9/site-packages/dns/dnssectypes.py deleted file mode 100644 index 02131e0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/dnssectypes.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNSSEC-related types.""" - -# This is a separate file to avoid import circularity between dns.dnssec and -# the implementations of the DS and DNSKEY types. - -import dns.enum - - -class Algorithm(dns.enum.IntEnum): - RSAMD5 = 1 - DH = 2 - DSA = 3 - ECC = 4 - RSASHA1 = 5 - DSANSEC3SHA1 = 6 - RSASHA1NSEC3SHA1 = 7 - RSASHA256 = 8 - RSASHA512 = 10 - ECCGOST = 12 - ECDSAP256SHA256 = 13 - ECDSAP384SHA384 = 14 - ED25519 = 15 - ED448 = 16 - INDIRECT = 252 - PRIVATEDNS = 253 - PRIVATEOID = 254 - - @classmethod - def _maximum(cls): - return 255 - - -class DSDigest(dns.enum.IntEnum): - """DNSSEC Delegation Signer Digest Algorithm""" - - NULL = 0 - SHA1 = 1 - SHA256 = 2 - GOST = 3 - SHA384 = 4 - - @classmethod - def _maximum(cls): - return 255 - - -class NSEC3Hash(dns.enum.IntEnum): - """NSEC3 hash algorithm""" - - SHA1 = 1 - - @classmethod - def _maximum(cls): - return 255 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/e164.py b/backend/venv39/lib/python3.9/site-packages/dns/e164.py deleted file mode 100644 index 453736d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/e164.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS E.164 helpers.""" - -from typing import Iterable, Optional, Union - -import dns.exception -import dns.name -import dns.resolver - -#: The public E.164 domain. -public_enum_domain = dns.name.from_text("e164.arpa.") - - -def from_e164( - text: str, origin: Optional[dns.name.Name] = public_enum_domain -) -> dns.name.Name: - """Convert an E.164 number in textual form into a Name object whose - value is the ENUM domain name for that number. - - Non-digits in the text are ignored, i.e. "16505551212", - "+1.650.555.1212" and "1 (650) 555-1212" are all the same. - - *text*, a ``str``, is an E.164 number in textual form. - - *origin*, a ``dns.name.Name``, the domain in which the number - should be constructed. The default is ``e164.arpa.``. - - Returns a ``dns.name.Name``. - """ - - parts = [d for d in text if d.isdigit()] - parts.reverse() - return dns.name.from_text(".".join(parts), origin=origin) - - -def to_e164( - name: dns.name.Name, - origin: Optional[dns.name.Name] = public_enum_domain, - want_plus_prefix: bool = True, -) -> str: - """Convert an ENUM domain name into an E.164 number. - - Note that dnspython does not have any information about preferred - number formats within national numbering plans, so all numbers are - emitted as a simple string of digits, prefixed by a '+' (unless - *want_plus_prefix* is ``False``). - - *name* is a ``dns.name.Name``, the ENUM domain name. - - *origin* is a ``dns.name.Name``, a domain containing the ENUM - domain name. The name is relativized to this domain before being - converted to text. If ``None``, no relativization is done. - - *want_plus_prefix* is a ``bool``. If True, add a '+' to the beginning of - the returned number. - - Returns a ``str``. - - """ - if origin is not None: - name = name.relativize(origin) - dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1] - if len(dlabels) != len(name.labels): - raise dns.exception.SyntaxError("non-digit labels in ENUM domain name") - dlabels.reverse() - text = b"".join(dlabels) - if want_plus_prefix: - text = b"+" + text - return text.decode() - - -def query( - number: str, - domains: Iterable[Union[dns.name.Name, str]], - resolver: Optional[dns.resolver.Resolver] = None, -) -> dns.resolver.Answer: - """Look for NAPTR RRs for the specified number in the specified domains. - - e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) - - *number*, a ``str`` is the number to look for. - - *domains* is an iterable containing ``dns.name.Name`` values. - - *resolver*, a ``dns.resolver.Resolver``, is the resolver to use. If - ``None``, the default resolver is used. - """ - - if resolver is None: - resolver = dns.resolver.get_default_resolver() - e_nx = dns.resolver.NXDOMAIN() - for domain in domains: - if isinstance(domain, str): - domain = dns.name.from_text(domain) - qname = dns.e164.from_e164(number, domain) - try: - return resolver.resolve(qname, "NAPTR") - except dns.resolver.NXDOMAIN as e: - e_nx += e - raise e_nx diff --git a/backend/venv39/lib/python3.9/site-packages/dns/edns.py b/backend/venv39/lib/python3.9/site-packages/dns/edns.py deleted file mode 100644 index f7d9ff9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/edns.py +++ /dev/null @@ -1,572 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2009-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""EDNS Options""" - -import binascii -import math -import socket -import struct -from typing import Any, Dict, Optional, Union - -import dns.enum -import dns.inet -import dns.rdata -import dns.wire - - -class OptionType(dns.enum.IntEnum): - #: NSID - NSID = 3 - #: DAU - DAU = 5 - #: DHU - DHU = 6 - #: N3U - N3U = 7 - #: ECS (client-subnet) - ECS = 8 - #: EXPIRE - EXPIRE = 9 - #: COOKIE - COOKIE = 10 - #: KEEPALIVE - KEEPALIVE = 11 - #: PADDING - PADDING = 12 - #: CHAIN - CHAIN = 13 - #: EDE (extended-dns-error) - EDE = 15 - #: REPORTCHANNEL - REPORTCHANNEL = 18 - - @classmethod - def _maximum(cls): - return 65535 - - -class Option: - """Base class for all EDNS option types.""" - - def __init__(self, otype: Union[OptionType, str]): - """Initialize an option. - - *otype*, a ``dns.edns.OptionType``, is the option type. - """ - self.otype = OptionType.make(otype) - - def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]: - """Convert an option to wire format. - - Returns a ``bytes`` or ``None``. - - """ - raise NotImplementedError # pragma: no cover - - def to_text(self) -> str: - raise NotImplementedError # pragma: no cover - - @classmethod - def from_wire_parser(cls, otype: OptionType, parser: "dns.wire.Parser") -> "Option": - """Build an EDNS option object from wire format. - - *otype*, a ``dns.edns.OptionType``, is the option type. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restructed to the option length. - - Returns a ``dns.edns.Option``. - """ - raise NotImplementedError # pragma: no cover - - def _cmp(self, other): - """Compare an EDNS option with another option of the same type. - - Returns < 0 if < *other*, 0 if == *other*, and > 0 if > *other*. - """ - wire = self.to_wire() - owire = other.to_wire() - if wire == owire: - return 0 - if wire > owire: - return 1 - return -1 - - def __eq__(self, other): - if not isinstance(other, Option): - return False - if self.otype != other.otype: - return False - return self._cmp(other) == 0 - - def __ne__(self, other): - if not isinstance(other, Option): - return True - if self.otype != other.otype: - return True - return self._cmp(other) != 0 - - def __lt__(self, other): - if not isinstance(other, Option) or self.otype != other.otype: - return NotImplemented - return self._cmp(other) < 0 - - def __le__(self, other): - if not isinstance(other, Option) or self.otype != other.otype: - return NotImplemented - return self._cmp(other) <= 0 - - def __ge__(self, other): - if not isinstance(other, Option) or self.otype != other.otype: - return NotImplemented - return self._cmp(other) >= 0 - - def __gt__(self, other): - if not isinstance(other, Option) or self.otype != other.otype: - return NotImplemented - return self._cmp(other) > 0 - - def __str__(self): - return self.to_text() - - -class GenericOption(Option): # lgtm[py/missing-equals] - """Generic Option Class - - This class is used for EDNS option types for which we have no better - implementation. - """ - - def __init__(self, otype: Union[OptionType, str], data: Union[bytes, str]): - super().__init__(otype) - self.data = dns.rdata.Rdata._as_bytes(data, True) - - def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]: - if file: - file.write(self.data) - return None - else: - return self.data - - def to_text(self) -> str: - return "Generic %d" % self.otype - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: "dns.wire.Parser" - ) -> Option: - return cls(otype, parser.get_remaining()) - - -class ECSOption(Option): # lgtm[py/missing-equals] - """EDNS Client Subnet (ECS, RFC7871)""" - - def __init__(self, address: str, srclen: Optional[int] = None, scopelen: int = 0): - """*address*, a ``str``, is the client address information. - - *srclen*, an ``int``, the source prefix length, which is the - leftmost number of bits of the address to be used for the - lookup. The default is 24 for IPv4 and 56 for IPv6. - - *scopelen*, an ``int``, the scope prefix length. This value - must be 0 in queries, and should be set in responses. - """ - - super().__init__(OptionType.ECS) - af = dns.inet.af_for_address(address) - - if af == socket.AF_INET6: - self.family = 2 - if srclen is None: - srclen = 56 - address = dns.rdata.Rdata._as_ipv6_address(address) - srclen = dns.rdata.Rdata._as_int(srclen, 0, 128) - scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 128) - elif af == socket.AF_INET: - self.family = 1 - if srclen is None: - srclen = 24 - address = dns.rdata.Rdata._as_ipv4_address(address) - srclen = dns.rdata.Rdata._as_int(srclen, 0, 32) - scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 32) - else: # pragma: no cover (this will never happen) - raise ValueError("Bad address family") - - assert srclen is not None - self.address = address - self.srclen = srclen - self.scopelen = scopelen - - addrdata = dns.inet.inet_pton(af, address) - nbytes = int(math.ceil(srclen / 8.0)) - - # Truncate to srclen and pad to the end of the last octet needed - # See RFC section 6 - self.addrdata = addrdata[:nbytes] - nbits = srclen % 8 - if nbits != 0: - last = struct.pack("B", ord(self.addrdata[-1:]) & (0xFF << (8 - nbits))) - self.addrdata = self.addrdata[:-1] + last - - def to_text(self) -> str: - return f"ECS {self.address}/{self.srclen} scope/{self.scopelen}" - - @staticmethod - def from_text(text: str) -> Option: - """Convert a string into a `dns.edns.ECSOption` - - *text*, a `str`, the text form of the option. - - Returns a `dns.edns.ECSOption`. - - Examples: - - >>> import dns.edns - >>> - >>> # basic example - >>> dns.edns.ECSOption.from_text('1.2.3.4/24') - >>> - >>> # also understands scope - >>> dns.edns.ECSOption.from_text('1.2.3.4/24/32') - >>> - >>> # IPv6 - >>> dns.edns.ECSOption.from_text('2001:4b98::1/64/64') - >>> - >>> # it understands results from `dns.edns.ECSOption.to_text()` - >>> dns.edns.ECSOption.from_text('ECS 1.2.3.4/24/32') - """ - optional_prefix = "ECS" - tokens = text.split() - ecs_text = None - if len(tokens) == 1: - ecs_text = tokens[0] - elif len(tokens) == 2: - if tokens[0] != optional_prefix: - raise ValueError(f'could not parse ECS from "{text}"') - ecs_text = tokens[1] - else: - raise ValueError(f'could not parse ECS from "{text}"') - n_slashes = ecs_text.count("/") - if n_slashes == 1: - address, tsrclen = ecs_text.split("/") - tscope = "0" - elif n_slashes == 2: - address, tsrclen, tscope = ecs_text.split("/") - else: - raise ValueError(f'could not parse ECS from "{text}"') - try: - scope = int(tscope) - except ValueError: - raise ValueError("invalid scope " + f'"{tscope}": scope must be an integer') - try: - srclen = int(tsrclen) - except ValueError: - raise ValueError( - "invalid srclen " + f'"{tsrclen}": srclen must be an integer' - ) - return ECSOption(address, srclen, scope) - - def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]: - value = ( - struct.pack("!HBB", self.family, self.srclen, self.scopelen) + self.addrdata - ) - if file: - file.write(value) - return None - else: - return value - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: "dns.wire.Parser" - ) -> Option: - family, src, scope = parser.get_struct("!HBB") - addrlen = int(math.ceil(src / 8.0)) - prefix = parser.get_bytes(addrlen) - if family == 1: - pad = 4 - addrlen - addr = dns.ipv4.inet_ntoa(prefix + b"\x00" * pad) - elif family == 2: - pad = 16 - addrlen - addr = dns.ipv6.inet_ntoa(prefix + b"\x00" * pad) - else: - raise ValueError("unsupported family") - - return cls(addr, src, scope) - - -class EDECode(dns.enum.IntEnum): - OTHER = 0 - UNSUPPORTED_DNSKEY_ALGORITHM = 1 - UNSUPPORTED_DS_DIGEST_TYPE = 2 - STALE_ANSWER = 3 - FORGED_ANSWER = 4 - DNSSEC_INDETERMINATE = 5 - DNSSEC_BOGUS = 6 - SIGNATURE_EXPIRED = 7 - SIGNATURE_NOT_YET_VALID = 8 - DNSKEY_MISSING = 9 - RRSIGS_MISSING = 10 - NO_ZONE_KEY_BIT_SET = 11 - NSEC_MISSING = 12 - CACHED_ERROR = 13 - NOT_READY = 14 - BLOCKED = 15 - CENSORED = 16 - FILTERED = 17 - PROHIBITED = 18 - STALE_NXDOMAIN_ANSWER = 19 - NOT_AUTHORITATIVE = 20 - NOT_SUPPORTED = 21 - NO_REACHABLE_AUTHORITY = 22 - NETWORK_ERROR = 23 - INVALID_DATA = 24 - - @classmethod - def _maximum(cls): - return 65535 - - -class EDEOption(Option): # lgtm[py/missing-equals] - """Extended DNS Error (EDE, RFC8914)""" - - _preserve_case = {"DNSKEY", "DS", "DNSSEC", "RRSIGs", "NSEC", "NXDOMAIN"} - - def __init__(self, code: Union[EDECode, str], text: Optional[str] = None): - """*code*, a ``dns.edns.EDECode`` or ``str``, the info code of the - extended error. - - *text*, a ``str`` or ``None``, specifying additional information about - the error. - """ - - super().__init__(OptionType.EDE) - - self.code = EDECode.make(code) - if text is not None and not isinstance(text, str): - raise ValueError("text must be string or None") - self.text = text - - def to_text(self) -> str: - output = f"EDE {self.code}" - if self.code in EDECode: - desc = EDECode.to_text(self.code) - desc = " ".join( - word if word in self._preserve_case else word.title() - for word in desc.split("_") - ) - output += f" ({desc})" - if self.text is not None: - output += f": {self.text}" - return output - - def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]: - value = struct.pack("!H", self.code) - if self.text is not None: - value += self.text.encode("utf8") - - if file: - file.write(value) - return None - else: - return value - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: "dns.wire.Parser" - ) -> Option: - code = EDECode.make(parser.get_uint16()) - text = parser.get_remaining() - - if text: - if text[-1] == 0: # text MAY be null-terminated - text = text[:-1] - btext = text.decode("utf8") - else: - btext = None - - return cls(code, btext) - - -class NSIDOption(Option): - def __init__(self, nsid: bytes): - super().__init__(OptionType.NSID) - self.nsid = nsid - - def to_wire(self, file: Any = None) -> Optional[bytes]: - if file: - file.write(self.nsid) - return None - else: - return self.nsid - - def to_text(self) -> str: - if all(c >= 0x20 and c <= 0x7E for c in self.nsid): - # All ASCII printable, so it's probably a string. - value = self.nsid.decode() - else: - value = binascii.hexlify(self.nsid).decode() - return f"NSID {value}" - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: dns.wire.Parser - ) -> Option: - return cls(parser.get_remaining()) - - -class CookieOption(Option): - def __init__(self, client: bytes, server: bytes): - super().__init__(dns.edns.OptionType.COOKIE) - self.client = client - self.server = server - if len(client) != 8: - raise ValueError("client cookie must be 8 bytes") - if len(server) != 0 and (len(server) < 8 or len(server) > 32): - raise ValueError("server cookie must be empty or between 8 and 32 bytes") - - def to_wire(self, file: Any = None) -> Optional[bytes]: - if file: - file.write(self.client) - if len(self.server) > 0: - file.write(self.server) - return None - else: - return self.client + self.server - - def to_text(self) -> str: - client = binascii.hexlify(self.client).decode() - if len(self.server) > 0: - server = binascii.hexlify(self.server).decode() - else: - server = "" - return f"COOKIE {client}{server}" - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: dns.wire.Parser - ) -> Option: - return cls(parser.get_bytes(8), parser.get_remaining()) - - -class ReportChannelOption(Option): - # RFC 9567 - def __init__(self, agent_domain: dns.name.Name): - super().__init__(OptionType.REPORTCHANNEL) - self.agent_domain = agent_domain - - def to_wire(self, file: Any = None) -> Optional[bytes]: - return self.agent_domain.to_wire(file) - - def to_text(self) -> str: - return "REPORTCHANNEL " + self.agent_domain.to_text() - - @classmethod - def from_wire_parser( - cls, otype: Union[OptionType, str], parser: dns.wire.Parser - ) -> Option: - return cls(parser.get_name()) - - -_type_to_class: Dict[OptionType, Any] = { - OptionType.ECS: ECSOption, - OptionType.EDE: EDEOption, - OptionType.NSID: NSIDOption, - OptionType.COOKIE: CookieOption, - OptionType.REPORTCHANNEL: ReportChannelOption, -} - - -def get_option_class(otype: OptionType) -> Any: - """Return the class for the specified option type. - - The GenericOption class is used if a more specific class is not - known. - """ - - cls = _type_to_class.get(otype) - if cls is None: - cls = GenericOption - return cls - - -def option_from_wire_parser( - otype: Union[OptionType, str], parser: "dns.wire.Parser" -) -> Option: - """Build an EDNS option object from wire format. - - *otype*, an ``int``, is the option type. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restricted to the option length. - - Returns an instance of a subclass of ``dns.edns.Option``. - """ - otype = OptionType.make(otype) - cls = get_option_class(otype) - return cls.from_wire_parser(otype, parser) - - -def option_from_wire( - otype: Union[OptionType, str], wire: bytes, current: int, olen: int -) -> Option: - """Build an EDNS option object from wire format. - - *otype*, an ``int``, is the option type. - - *wire*, a ``bytes``, is the wire-format message. - - *current*, an ``int``, is the offset in *wire* of the beginning - of the rdata. - - *olen*, an ``int``, is the length of the wire-format option data - - Returns an instance of a subclass of ``dns.edns.Option``. - """ - parser = dns.wire.Parser(wire, current) - with parser.restrict_to(olen): - return option_from_wire_parser(otype, parser) - - -def register_type(implementation: Any, otype: OptionType) -> None: - """Register the implementation of an option type. - - *implementation*, a ``class``, is a subclass of ``dns.edns.Option``. - - *otype*, an ``int``, is the option type. - """ - - _type_to_class[otype] = implementation - - -### BEGIN generated OptionType constants - -NSID = OptionType.NSID -DAU = OptionType.DAU -DHU = OptionType.DHU -N3U = OptionType.N3U -ECS = OptionType.ECS -EXPIRE = OptionType.EXPIRE -COOKIE = OptionType.COOKIE -KEEPALIVE = OptionType.KEEPALIVE -PADDING = OptionType.PADDING -CHAIN = OptionType.CHAIN -EDE = OptionType.EDE -REPORTCHANNEL = OptionType.REPORTCHANNEL - -### END generated OptionType constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/entropy.py b/backend/venv39/lib/python3.9/site-packages/dns/entropy.py deleted file mode 100644 index 4dcdc62..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/entropy.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2009-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import hashlib -import os -import random -import threading -import time -from typing import Any, Optional - - -class EntropyPool: - # This is an entropy pool for Python implementations that do not - # have a working SystemRandom. I'm not sure there are any, but - # leaving this code doesn't hurt anything as the library code - # is used if present. - - def __init__(self, seed: Optional[bytes] = None): - self.pool_index = 0 - self.digest: Optional[bytearray] = None - self.next_byte = 0 - self.lock = threading.Lock() - self.hash = hashlib.sha1() - self.hash_len = 20 - self.pool = bytearray(b"\0" * self.hash_len) - if seed is not None: - self._stir(seed) - self.seeded = True - self.seed_pid = os.getpid() - else: - self.seeded = False - self.seed_pid = 0 - - def _stir(self, entropy: bytes) -> None: - for c in entropy: - if self.pool_index == self.hash_len: - self.pool_index = 0 - b = c & 0xFF - self.pool[self.pool_index] ^= b - self.pool_index += 1 - - def stir(self, entropy: bytes) -> None: - with self.lock: - self._stir(entropy) - - def _maybe_seed(self) -> None: - if not self.seeded or self.seed_pid != os.getpid(): - try: - seed = os.urandom(16) - except Exception: # pragma: no cover - try: - with open("/dev/urandom", "rb", 0) as r: - seed = r.read(16) - except Exception: - seed = str(time.time()).encode() - self.seeded = True - self.seed_pid = os.getpid() - self.digest = None - seed = bytearray(seed) - self._stir(seed) - - def random_8(self) -> int: - with self.lock: - self._maybe_seed() - if self.digest is None or self.next_byte == self.hash_len: - self.hash.update(bytes(self.pool)) - self.digest = bytearray(self.hash.digest()) - self._stir(self.digest) - self.next_byte = 0 - value = self.digest[self.next_byte] - self.next_byte += 1 - return value - - def random_16(self) -> int: - return self.random_8() * 256 + self.random_8() - - def random_32(self) -> int: - return self.random_16() * 65536 + self.random_16() - - def random_between(self, first: int, last: int) -> int: - size = last - first + 1 - if size > 4294967296: - raise ValueError("too big") - if size > 65536: - rand = self.random_32 - max = 4294967295 - elif size > 256: - rand = self.random_16 - max = 65535 - else: - rand = self.random_8 - max = 255 - return first + size * rand() // (max + 1) - - -pool = EntropyPool() - -system_random: Optional[Any] -try: - system_random = random.SystemRandom() -except Exception: # pragma: no cover - system_random = None - - -def random_16() -> int: - if system_random is not None: - return system_random.randrange(0, 65536) - else: - return pool.random_16() - - -def between(first: int, last: int) -> int: - if system_random is not None: - return system_random.randrange(first, last + 1) - else: - return pool.random_between(first, last) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/enum.py b/backend/venv39/lib/python3.9/site-packages/dns/enum.py deleted file mode 100644 index 71461f1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/enum.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import enum -from typing import Type, TypeVar, Union - -TIntEnum = TypeVar("TIntEnum", bound="IntEnum") - - -class IntEnum(enum.IntEnum): - @classmethod - def _missing_(cls, value): - cls._check_value(value) - val = int.__new__(cls, value) - val._name_ = cls._extra_to_text(value, None) or f"{cls._prefix()}{value}" - val._value_ = value - return val - - @classmethod - def _check_value(cls, value): - max = cls._maximum() - if not isinstance(value, int): - raise TypeError - if value < 0 or value > max: - name = cls._short_name() - raise ValueError(f"{name} must be an int between >= 0 and <= {max}") - - @classmethod - def from_text(cls: Type[TIntEnum], text: str) -> TIntEnum: - text = text.upper() - try: - return cls[text] - except KeyError: - pass - value = cls._extra_from_text(text) - if value: - return value - prefix = cls._prefix() - if text.startswith(prefix) and text[len(prefix) :].isdigit(): - value = int(text[len(prefix) :]) - cls._check_value(value) - try: - return cls(value) - except ValueError: - return value - raise cls._unknown_exception_class() - - @classmethod - def to_text(cls: Type[TIntEnum], value: int) -> str: - cls._check_value(value) - try: - text = cls(value).name - except ValueError: - text = None - text = cls._extra_to_text(value, text) - if text is None: - text = f"{cls._prefix()}{value}" - return text - - @classmethod - def make(cls: Type[TIntEnum], value: Union[int, str]) -> TIntEnum: - """Convert text or a value into an enumerated type, if possible. - - *value*, the ``int`` or ``str`` to convert. - - Raises a class-specific exception if a ``str`` is provided that - cannot be converted. - - Raises ``ValueError`` if the value is out of range. - - Returns an enumeration from the calling class corresponding to the - value, if one is defined, or an ``int`` otherwise. - """ - - if isinstance(value, str): - return cls.from_text(value) - cls._check_value(value) - return cls(value) - - @classmethod - def _maximum(cls): - raise NotImplementedError # pragma: no cover - - @classmethod - def _short_name(cls): - return cls.__name__.lower() - - @classmethod - def _prefix(cls): - return "" - - @classmethod - def _extra_from_text(cls, text): # pylint: disable=W0613 - return None - - @classmethod - def _extra_to_text(cls, value, current_text): # pylint: disable=W0613 - return current_text - - @classmethod - def _unknown_exception_class(cls): - return ValueError diff --git a/backend/venv39/lib/python3.9/site-packages/dns/exception.py b/backend/venv39/lib/python3.9/site-packages/dns/exception.py deleted file mode 100644 index 223f2d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/exception.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Common DNS Exceptions. - -Dnspython modules may also define their own exceptions, which will -always be subclasses of ``DNSException``. -""" - - -from typing import Optional, Set - - -class DNSException(Exception): - """Abstract base class shared by all dnspython exceptions. - - It supports two basic modes of operation: - - a) Old/compatible mode is used if ``__init__`` was called with - empty *kwargs*. In compatible mode all *args* are passed - to the standard Python Exception class as before and all *args* are - printed by the standard ``__str__`` implementation. Class variable - ``msg`` (or doc string if ``msg`` is ``None``) is returned from ``str()`` - if *args* is empty. - - b) New/parametrized mode is used if ``__init__`` was called with - non-empty *kwargs*. - In the new mode *args* must be empty and all kwargs must match - those set in class variable ``supp_kwargs``. All kwargs are stored inside - ``self.kwargs`` and used in a new ``__str__`` implementation to construct - a formatted message based on the ``fmt`` class variable, a ``string``. - - In the simplest case it is enough to override the ``supp_kwargs`` - and ``fmt`` class variables to get nice parametrized messages. - """ - - msg: Optional[str] = None # non-parametrized message - supp_kwargs: Set[str] = set() # accepted parameters for _fmt_kwargs (sanity check) - fmt: Optional[str] = None # message parametrized with results from _fmt_kwargs - - def __init__(self, *args, **kwargs): - self._check_params(*args, **kwargs) - if kwargs: - # This call to a virtual method from __init__ is ok in our usage - self.kwargs = self._check_kwargs(**kwargs) # lgtm[py/init-calls-subclass] - self.msg = str(self) - else: - self.kwargs = dict() # defined but empty for old mode exceptions - if self.msg is None: - # doc string is better implicit message than empty string - self.msg = self.__doc__ - if args: - super().__init__(*args) - else: - super().__init__(self.msg) - - def _check_params(self, *args, **kwargs): - """Old exceptions supported only args and not kwargs. - - For sanity we do not allow to mix old and new behavior.""" - if args or kwargs: - assert bool(args) != bool( - kwargs - ), "keyword arguments are mutually exclusive with positional args" - - def _check_kwargs(self, **kwargs): - if kwargs: - assert ( - set(kwargs.keys()) == self.supp_kwargs - ), f"following set of keyword args is required: {self.supp_kwargs}" - return kwargs - - def _fmt_kwargs(self, **kwargs): - """Format kwargs before printing them. - - Resulting dictionary has to have keys necessary for str.format call - on fmt class variable. - """ - fmtargs = {} - for kw, data in kwargs.items(): - if isinstance(data, (list, set)): - # convert list of to list of str() - fmtargs[kw] = list(map(str, data)) - if len(fmtargs[kw]) == 1: - # remove list brackets [] from single-item lists - fmtargs[kw] = fmtargs[kw].pop() - else: - fmtargs[kw] = data - return fmtargs - - def __str__(self): - if self.kwargs and self.fmt: - # provide custom message constructed from keyword arguments - fmtargs = self._fmt_kwargs(**self.kwargs) - return self.fmt.format(**fmtargs) - else: - # print *args directly in the same way as old DNSException - return super().__str__() - - -class FormError(DNSException): - """DNS message is malformed.""" - - -class SyntaxError(DNSException): - """Text input is malformed.""" - - -class UnexpectedEnd(SyntaxError): - """Text input ended unexpectedly.""" - - -class TooBig(DNSException): - """The DNS message is too big.""" - - -class Timeout(DNSException): - """The DNS operation timed out.""" - - supp_kwargs = {"timeout"} - fmt = "The DNS operation timed out after {timeout:.3f} seconds" - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - -class UnsupportedAlgorithm(DNSException): - """The DNSSEC algorithm is not supported.""" - - -class AlgorithmKeyMismatch(UnsupportedAlgorithm): - """The DNSSEC algorithm is not supported for the given key type.""" - - -class ValidationFailure(DNSException): - """The DNSSEC signature is invalid.""" - - -class DeniedByPolicy(DNSException): - """Denied by DNSSEC policy.""" - - -class ExceptionWrapper: - def __init__(self, exception_class): - self.exception_class = exception_class - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if exc_type is not None and not isinstance(exc_val, self.exception_class): - raise self.exception_class(str(exc_val)) from exc_val - return False diff --git a/backend/venv39/lib/python3.9/site-packages/dns/flags.py b/backend/venv39/lib/python3.9/site-packages/dns/flags.py deleted file mode 100644 index 4c60be1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/flags.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Message Flags.""" - -import enum -from typing import Any - -# Standard DNS flags - - -class Flag(enum.IntFlag): - #: Query Response - QR = 0x8000 - #: Authoritative Answer - AA = 0x0400 - #: Truncated Response - TC = 0x0200 - #: Recursion Desired - RD = 0x0100 - #: Recursion Available - RA = 0x0080 - #: Authentic Data - AD = 0x0020 - #: Checking Disabled - CD = 0x0010 - - -# EDNS flags - - -class EDNSFlag(enum.IntFlag): - #: DNSSEC answer OK - DO = 0x8000 - - -def _from_text(text: str, enum_class: Any) -> int: - flags = 0 - tokens = text.split() - for t in tokens: - flags |= enum_class[t.upper()] - return flags - - -def _to_text(flags: int, enum_class: Any) -> str: - text_flags = [] - for k, v in enum_class.__members__.items(): - if flags & v != 0: - text_flags.append(k) - return " ".join(text_flags) - - -def from_text(text: str) -> int: - """Convert a space-separated list of flag text values into a flags - value. - - Returns an ``int`` - """ - - return _from_text(text, Flag) - - -def to_text(flags: int) -> str: - """Convert a flags value into a space-separated list of flag text - values. - - Returns a ``str``. - """ - - return _to_text(flags, Flag) - - -def edns_from_text(text: str) -> int: - """Convert a space-separated list of EDNS flag text values into a EDNS - flags value. - - Returns an ``int`` - """ - - return _from_text(text, EDNSFlag) - - -def edns_to_text(flags: int) -> str: - """Convert an EDNS flags value into a space-separated list of EDNS flag - text values. - - Returns a ``str``. - """ - - return _to_text(flags, EDNSFlag) - - -### BEGIN generated Flag constants - -QR = Flag.QR -AA = Flag.AA -TC = Flag.TC -RD = Flag.RD -RA = Flag.RA -AD = Flag.AD -CD = Flag.CD - -### END generated Flag constants - -### BEGIN generated EDNSFlag constants - -DO = EDNSFlag.DO - -### END generated EDNSFlag constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/grange.py b/backend/venv39/lib/python3.9/site-packages/dns/grange.py deleted file mode 100644 index a967ca4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/grange.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2012-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS GENERATE range conversion.""" - -from typing import Tuple - -import dns - - -def from_text(text: str) -> Tuple[int, int, int]: - """Convert the text form of a range in a ``$GENERATE`` statement to an - integer. - - *text*, a ``str``, the textual range in ``$GENERATE`` form. - - Returns a tuple of three ``int`` values ``(start, stop, step)``. - """ - - start = -1 - stop = -1 - step = 1 - cur = "" - state = 0 - # state 0 1 2 - # x - y / z - - if text and text[0] == "-": - raise dns.exception.SyntaxError("Start cannot be a negative number") - - for c in text: - if c == "-" and state == 0: - start = int(cur) - cur = "" - state = 1 - elif c == "/": - stop = int(cur) - cur = "" - state = 2 - elif c.isdigit(): - cur += c - else: - raise dns.exception.SyntaxError(f"Could not parse {c}") - - if state == 0: - raise dns.exception.SyntaxError("no stop value specified") - elif state == 1: - stop = int(cur) - else: - assert state == 2 - step = int(cur) - - assert step >= 1 - assert start >= 0 - if start > stop: - raise dns.exception.SyntaxError("start must be <= stop") - - return (start, stop, step) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/immutable.py b/backend/venv39/lib/python3.9/site-packages/dns/immutable.py deleted file mode 100644 index 36b0362..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/immutable.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import collections.abc -from typing import Any, Callable - -from dns._immutable_ctx import immutable - - -@immutable -class Dict(collections.abc.Mapping): # lgtm[py/missing-equals] - def __init__( - self, - dictionary: Any, - no_copy: bool = False, - map_factory: Callable[[], collections.abc.MutableMapping] = dict, - ): - """Make an immutable dictionary from the specified dictionary. - - If *no_copy* is `True`, then *dictionary* will be wrapped instead - of copied. Only set this if you are sure there will be no external - references to the dictionary. - """ - if no_copy and isinstance(dictionary, collections.abc.MutableMapping): - self._odict = dictionary - else: - self._odict = map_factory() - self._odict.update(dictionary) - self._hash = None - - def __getitem__(self, key): - return self._odict.__getitem__(key) - - def __hash__(self): # pylint: disable=invalid-hash-returned - if self._hash is None: - h = 0 - for key in sorted(self._odict.keys()): - h ^= hash(key) - object.__setattr__(self, "_hash", h) - # this does return an int, but pylint doesn't figure that out - return self._hash - - def __len__(self): - return len(self._odict) - - def __iter__(self): - return iter(self._odict) - - -def constify(o: Any) -> Any: - """ - Convert mutable types to immutable types. - """ - if isinstance(o, bytearray): - return bytes(o) - if isinstance(o, tuple): - try: - hash(o) - return o - except Exception: - return tuple(constify(elt) for elt in o) - if isinstance(o, list): - return tuple(constify(elt) for elt in o) - if isinstance(o, dict): - cdict = dict() - for k, v in o.items(): - cdict[k] = constify(v) - return Dict(cdict, True) - return o diff --git a/backend/venv39/lib/python3.9/site-packages/dns/inet.py b/backend/venv39/lib/python3.9/site-packages/dns/inet.py deleted file mode 100644 index 4a03f99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/inet.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Generic Internet address helper functions.""" - -import socket -from typing import Any, Optional, Tuple - -import dns.ipv4 -import dns.ipv6 - -# We assume that AF_INET and AF_INET6 are always defined. We keep -# these here for the benefit of any old code (unlikely though that -# is!). -AF_INET = socket.AF_INET -AF_INET6 = socket.AF_INET6 - - -def inet_pton(family: int, text: str) -> bytes: - """Convert the textual form of a network address into its binary form. - - *family* is an ``int``, the address family. - - *text* is a ``str``, the textual address. - - Raises ``NotImplementedError`` if the address family specified is not - implemented. - - Returns a ``bytes``. - """ - - if family == AF_INET: - return dns.ipv4.inet_aton(text) - elif family == AF_INET6: - return dns.ipv6.inet_aton(text, True) - else: - raise NotImplementedError - - -def inet_ntop(family: int, address: bytes) -> str: - """Convert the binary form of a network address into its textual form. - - *family* is an ``int``, the address family. - - *address* is a ``bytes``, the network address in binary form. - - Raises ``NotImplementedError`` if the address family specified is not - implemented. - - Returns a ``str``. - """ - - if family == AF_INET: - return dns.ipv4.inet_ntoa(address) - elif family == AF_INET6: - return dns.ipv6.inet_ntoa(address) - else: - raise NotImplementedError - - -def af_for_address(text: str) -> int: - """Determine the address family of a textual-form network address. - - *text*, a ``str``, the textual address. - - Raises ``ValueError`` if the address family cannot be determined - from the input. - - Returns an ``int``. - """ - - try: - dns.ipv4.inet_aton(text) - return AF_INET - except Exception: - try: - dns.ipv6.inet_aton(text, True) - return AF_INET6 - except Exception: - raise ValueError - - -def is_multicast(text: str) -> bool: - """Is the textual-form network address a multicast address? - - *text*, a ``str``, the textual address. - - Raises ``ValueError`` if the address family cannot be determined - from the input. - - Returns a ``bool``. - """ - - try: - first = dns.ipv4.inet_aton(text)[0] - return first >= 224 and first <= 239 - except Exception: - try: - first = dns.ipv6.inet_aton(text, True)[0] - return first == 255 - except Exception: - raise ValueError - - -def is_address(text: str) -> bool: - """Is the specified string an IPv4 or IPv6 address? - - *text*, a ``str``, the textual address. - - Returns a ``bool``. - """ - - try: - dns.ipv4.inet_aton(text) - return True - except Exception: - try: - dns.ipv6.inet_aton(text, True) - return True - except Exception: - return False - - -def low_level_address_tuple( - high_tuple: Tuple[str, int], af: Optional[int] = None -) -> Any: - """Given a "high-level" address tuple, i.e. - an (address, port) return the appropriate "low-level" address tuple - suitable for use in socket calls. - - If an *af* other than ``None`` is provided, it is assumed the - address in the high-level tuple is valid and has that af. If af - is ``None``, then af_for_address will be called. - """ - address, port = high_tuple - if af is None: - af = af_for_address(address) - if af == AF_INET: - return (address, port) - elif af == AF_INET6: - i = address.find("%") - if i < 0: - # no scope, shortcut! - return (address, port, 0, 0) - # try to avoid getaddrinfo() - addrpart = address[:i] - scope = address[i + 1 :] - if scope.isdigit(): - return (addrpart, port, 0, int(scope)) - try: - return (addrpart, port, 0, socket.if_nametoindex(scope)) - except AttributeError: # pragma: no cover (we can't really test this) - ai_flags = socket.AI_NUMERICHOST - ((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags) - return tup - else: - raise NotImplementedError(f"unknown address family {af}") - - -def any_for_af(af): - """Return the 'any' address for the specified address family.""" - if af == socket.AF_INET: - return "0.0.0.0" - elif af == socket.AF_INET6: - return "::" - raise NotImplementedError(f"unknown address family {af}") - - -def canonicalize(text: str) -> str: - """Verify that *address* is a valid text form IPv4 or IPv6 address and return its - canonical text form. IPv6 addresses with scopes are rejected. - - *text*, a ``str``, the address in textual form. - - Raises ``ValueError`` if the text is not valid. - """ - try: - return dns.ipv6.canonicalize(text) - except Exception: - try: - return dns.ipv4.canonicalize(text) - except Exception: - raise ValueError diff --git a/backend/venv39/lib/python3.9/site-packages/dns/ipv4.py b/backend/venv39/lib/python3.9/site-packages/dns/ipv4.py deleted file mode 100644 index 65ee69c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/ipv4.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""IPv4 helper functions.""" - -import struct -from typing import Union - -import dns.exception - - -def inet_ntoa(address: bytes) -> str: - """Convert an IPv4 address in binary form to text form. - - *address*, a ``bytes``, the IPv4 address in binary form. - - Returns a ``str``. - """ - - if len(address) != 4: - raise dns.exception.SyntaxError - return "%u.%u.%u.%u" % (address[0], address[1], address[2], address[3]) - - -def inet_aton(text: Union[str, bytes]) -> bytes: - """Convert an IPv4 address in text form to binary form. - - *text*, a ``str`` or ``bytes``, the IPv4 address in textual form. - - Returns a ``bytes``. - """ - - if not isinstance(text, bytes): - btext = text.encode() - else: - btext = text - parts = btext.split(b".") - if len(parts) != 4: - raise dns.exception.SyntaxError - for part in parts: - if not part.isdigit(): - raise dns.exception.SyntaxError - if len(part) > 1 and part[0] == ord("0"): - # No leading zeros - raise dns.exception.SyntaxError - try: - b = [int(part) for part in parts] - return struct.pack("BBBB", *b) - except Exception: - raise dns.exception.SyntaxError - - -def canonicalize(text: Union[str, bytes]) -> str: - """Verify that *address* is a valid text form IPv4 address and return its - canonical text form. - - *text*, a ``str`` or ``bytes``, the IPv4 address in textual form. - - Raises ``dns.exception.SyntaxError`` if the text is not valid. - """ - # Note that inet_aton() only accepts canonial form, but we still run through - # inet_ntoa() to ensure the output is a str. - return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/ipv6.py b/backend/venv39/lib/python3.9/site-packages/dns/ipv6.py deleted file mode 100644 index 4dd1d1c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/ipv6.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""IPv6 helper functions.""" - -import binascii -import re -from typing import List, Union - -import dns.exception -import dns.ipv4 - -_leading_zero = re.compile(r"0+([0-9a-f]+)") - - -def inet_ntoa(address: bytes) -> str: - """Convert an IPv6 address in binary form to text form. - - *address*, a ``bytes``, the IPv6 address in binary form. - - Raises ``ValueError`` if the address isn't 16 bytes long. - Returns a ``str``. - """ - - if len(address) != 16: - raise ValueError("IPv6 addresses are 16 bytes long") - hex = binascii.hexlify(address) - chunks = [] - i = 0 - l = len(hex) - while i < l: - chunk = hex[i : i + 4].decode() - # strip leading zeros. we do this with an re instead of - # with lstrip() because lstrip() didn't support chars until - # python 2.2.2 - m = _leading_zero.match(chunk) - if m is not None: - chunk = m.group(1) - chunks.append(chunk) - i += 4 - # - # Compress the longest subsequence of 0-value chunks to :: - # - best_start = 0 - best_len = 0 - start = -1 - last_was_zero = False - for i in range(8): - if chunks[i] != "0": - if last_was_zero: - end = i - current_len = end - start - if current_len > best_len: - best_start = start - best_len = current_len - last_was_zero = False - elif not last_was_zero: - start = i - last_was_zero = True - if last_was_zero: - end = 8 - current_len = end - start - if current_len > best_len: - best_start = start - best_len = current_len - if best_len > 1: - if best_start == 0 and (best_len == 6 or best_len == 5 and chunks[5] == "ffff"): - # We have an embedded IPv4 address - if best_len == 6: - prefix = "::" - else: - prefix = "::ffff:" - thex = prefix + dns.ipv4.inet_ntoa(address[12:]) - else: - thex = ( - ":".join(chunks[:best_start]) - + "::" - + ":".join(chunks[best_start + best_len :]) - ) - else: - thex = ":".join(chunks) - return thex - - -_v4_ending = re.compile(rb"(.*):(\d+\.\d+\.\d+\.\d+)$") -_colon_colon_start = re.compile(rb"::.*") -_colon_colon_end = re.compile(rb".*::$") - - -def inet_aton(text: Union[str, bytes], ignore_scope: bool = False) -> bytes: - """Convert an IPv6 address in text form to binary form. - - *text*, a ``str`` or ``bytes``, the IPv6 address in textual form. - - *ignore_scope*, a ``bool``. If ``True``, a scope will be ignored. - If ``False``, the default, it is an error for a scope to be present. - - Returns a ``bytes``. - """ - - # - # Our aim here is not something fast; we just want something that works. - # - if not isinstance(text, bytes): - btext = text.encode() - else: - btext = text - - if ignore_scope: - parts = btext.split(b"%") - l = len(parts) - if l == 2: - btext = parts[0] - elif l > 2: - raise dns.exception.SyntaxError - - if btext == b"": - raise dns.exception.SyntaxError - elif btext.endswith(b":") and not btext.endswith(b"::"): - raise dns.exception.SyntaxError - elif btext.startswith(b":") and not btext.startswith(b"::"): - raise dns.exception.SyntaxError - elif btext == b"::": - btext = b"0::" - # - # Get rid of the icky dot-quad syntax if we have it. - # - m = _v4_ending.match(btext) - if m is not None: - b = dns.ipv4.inet_aton(m.group(2)) - btext = ( - f"{m.group(1).decode()}:{b[0]:02x}{b[1]:02x}:{b[2]:02x}{b[3]:02x}" - ).encode() - # - # Try to turn '::' into ':'; if no match try to - # turn '::' into ':' - # - m = _colon_colon_start.match(btext) - if m is not None: - btext = btext[1:] - else: - m = _colon_colon_end.match(btext) - if m is not None: - btext = btext[:-1] - # - # Now canonicalize into 8 chunks of 4 hex digits each - # - chunks = btext.split(b":") - l = len(chunks) - if l > 8: - raise dns.exception.SyntaxError - seen_empty = False - canonical: List[bytes] = [] - for c in chunks: - if c == b"": - if seen_empty: - raise dns.exception.SyntaxError - seen_empty = True - for _ in range(0, 8 - l + 1): - canonical.append(b"0000") - else: - lc = len(c) - if lc > 4: - raise dns.exception.SyntaxError - if lc != 4: - c = (b"0" * (4 - lc)) + c - canonical.append(c) - if l < 8 and not seen_empty: - raise dns.exception.SyntaxError - btext = b"".join(canonical) - - # - # Finally we can go to binary. - # - try: - return binascii.unhexlify(btext) - except (binascii.Error, TypeError): - raise dns.exception.SyntaxError - - -_mapped_prefix = b"\x00" * 10 + b"\xff\xff" - - -def is_mapped(address: bytes) -> bool: - """Is the specified address a mapped IPv4 address? - - *address*, a ``bytes`` is an IPv6 address in binary form. - - Returns a ``bool``. - """ - - return address.startswith(_mapped_prefix) - - -def canonicalize(text: Union[str, bytes]) -> str: - """Verify that *address* is a valid text form IPv6 address and return its - canonical text form. Addresses with scopes are rejected. - - *text*, a ``str`` or ``bytes``, the IPv6 address in textual form. - - Raises ``dns.exception.SyntaxError`` if the text is not valid. - """ - return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/message.py b/backend/venv39/lib/python3.9/site-packages/dns/message.py deleted file mode 100644 index e978a0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/message.py +++ /dev/null @@ -1,1933 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Messages""" - -import contextlib -import enum -import io -import time -from typing import Any, Dict, List, Optional, Tuple, Union, cast - -import dns.edns -import dns.entropy -import dns.enum -import dns.exception -import dns.flags -import dns.name -import dns.opcode -import dns.rcode -import dns.rdata -import dns.rdataclass -import dns.rdatatype -import dns.rdtypes.ANY.OPT -import dns.rdtypes.ANY.TSIG -import dns.renderer -import dns.rrset -import dns.tsig -import dns.ttl -import dns.wire - - -class ShortHeader(dns.exception.FormError): - """The DNS packet passed to from_wire() is too short.""" - - -class TrailingJunk(dns.exception.FormError): - """The DNS packet passed to from_wire() has extra junk at the end of it.""" - - -class UnknownHeaderField(dns.exception.DNSException): - """The header field name was not recognized when converting from text - into a message.""" - - -class BadEDNS(dns.exception.FormError): - """An OPT record occurred somewhere other than - the additional data section.""" - - -class BadTSIG(dns.exception.FormError): - """A TSIG record occurred somewhere other than the end of - the additional data section.""" - - -class UnknownTSIGKey(dns.exception.DNSException): - """A TSIG with an unknown key was received.""" - - -class Truncated(dns.exception.DNSException): - """The truncated flag is set.""" - - supp_kwargs = {"message"} - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def message(self): - """As much of the message as could be processed. - - Returns a ``dns.message.Message``. - """ - return self.kwargs["message"] - - -class NotQueryResponse(dns.exception.DNSException): - """Message is not a response to a query.""" - - -class ChainTooLong(dns.exception.DNSException): - """The CNAME chain is too long.""" - - -class AnswerForNXDOMAIN(dns.exception.DNSException): - """The rcode is NXDOMAIN but an answer was found.""" - - -class NoPreviousName(dns.exception.SyntaxError): - """No previous name was known.""" - - -class MessageSection(dns.enum.IntEnum): - """Message sections""" - - QUESTION = 0 - ANSWER = 1 - AUTHORITY = 2 - ADDITIONAL = 3 - - @classmethod - def _maximum(cls): - return 3 - - -class MessageError: - def __init__(self, exception: Exception, offset: int): - self.exception = exception - self.offset = offset - - -DEFAULT_EDNS_PAYLOAD = 1232 -MAX_CHAIN = 16 - -IndexKeyType = Tuple[ - int, - dns.name.Name, - dns.rdataclass.RdataClass, - dns.rdatatype.RdataType, - Optional[dns.rdatatype.RdataType], - Optional[dns.rdataclass.RdataClass], -] -IndexType = Dict[IndexKeyType, dns.rrset.RRset] -SectionType = Union[int, str, List[dns.rrset.RRset]] - - -class Message: - """A DNS message.""" - - _section_enum = MessageSection - - def __init__(self, id: Optional[int] = None): - if id is None: - self.id = dns.entropy.random_16() - else: - self.id = id - self.flags = 0 - self.sections: List[List[dns.rrset.RRset]] = [[], [], [], []] - self.opt: Optional[dns.rrset.RRset] = None - self.request_payload = 0 - self.pad = 0 - self.keyring: Any = None - self.tsig: Optional[dns.rrset.RRset] = None - self.request_mac = b"" - self.xfr = False - self.origin: Optional[dns.name.Name] = None - self.tsig_ctx: Optional[Any] = None - self.index: IndexType = {} - self.errors: List[MessageError] = [] - self.time = 0.0 - self.wire: Optional[bytes] = None - - @property - def question(self) -> List[dns.rrset.RRset]: - """The question section.""" - return self.sections[0] - - @question.setter - def question(self, v): - self.sections[0] = v - - @property - def answer(self) -> List[dns.rrset.RRset]: - """The answer section.""" - return self.sections[1] - - @answer.setter - def answer(self, v): - self.sections[1] = v - - @property - def authority(self) -> List[dns.rrset.RRset]: - """The authority section.""" - return self.sections[2] - - @authority.setter - def authority(self, v): - self.sections[2] = v - - @property - def additional(self) -> List[dns.rrset.RRset]: - """The additional data section.""" - return self.sections[3] - - @additional.setter - def additional(self, v): - self.sections[3] = v - - def __repr__(self): - return "" - - def __str__(self): - return self.to_text() - - def to_text( - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - **kw: Dict[str, Any], - ) -> str: - """Convert the message to text. - - The *origin*, *relativize*, and any other keyword - arguments are passed to the RRset ``to_wire()`` method. - - Returns a ``str``. - """ - - s = io.StringIO() - s.write("id %d\n" % self.id) - s.write(f"opcode {dns.opcode.to_text(self.opcode())}\n") - s.write(f"rcode {dns.rcode.to_text(self.rcode())}\n") - s.write(f"flags {dns.flags.to_text(self.flags)}\n") - if self.edns >= 0: - s.write(f"edns {self.edns}\n") - if self.ednsflags != 0: - s.write(f"eflags {dns.flags.edns_to_text(self.ednsflags)}\n") - s.write("payload %d\n" % self.payload) - for opt in self.options: - s.write(f"option {opt.to_text()}\n") - for name, which in self._section_enum.__members__.items(): - s.write(f";{name}\n") - for rrset in self.section_from_number(which): - s.write(rrset.to_text(origin, relativize, **kw)) - s.write("\n") - # - # We strip off the final \n so the caller can print the result without - # doing weird things to get around eccentricities in Python print - # formatting - # - return s.getvalue()[:-1] - - def __eq__(self, other): - """Two messages are equal if they have the same content in the - header, question, answer, and authority sections. - - Returns a ``bool``. - """ - - if not isinstance(other, Message): - return False - if self.id != other.id: - return False - if self.flags != other.flags: - return False - for i, section in enumerate(self.sections): - other_section = other.sections[i] - for n in section: - if n not in other_section: - return False - for n in other_section: - if n not in section: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def is_response(self, other: "Message") -> bool: - """Is *other*, also a ``dns.message.Message``, a response to this - message? - - Returns a ``bool``. - """ - - if ( - other.flags & dns.flags.QR == 0 - or self.id != other.id - or dns.opcode.from_flags(self.flags) != dns.opcode.from_flags(other.flags) - ): - return False - if other.rcode() in { - dns.rcode.FORMERR, - dns.rcode.SERVFAIL, - dns.rcode.NOTIMP, - dns.rcode.REFUSED, - }: - # We don't check the question section in these cases if - # the other question section is empty, even though they - # still really ought to have a question section. - if len(other.question) == 0: - return True - if dns.opcode.is_update(self.flags): - # This is assuming the "sender doesn't include anything - # from the update", but we don't care to check the other - # case, which is that all the sections are returned and - # identical. - return True - for n in self.question: - if n not in other.question: - return False - for n in other.question: - if n not in self.question: - return False - return True - - def section_number(self, section: List[dns.rrset.RRset]) -> int: - """Return the "section number" of the specified section for use - in indexing. - - *section* is one of the section attributes of this message. - - Raises ``ValueError`` if the section isn't known. - - Returns an ``int``. - """ - - for i, our_section in enumerate(self.sections): - if section is our_section: - return self._section_enum(i) - raise ValueError("unknown section") - - def section_from_number(self, number: int) -> List[dns.rrset.RRset]: - """Return the section list associated with the specified section - number. - - *number* is a section number `int` or the text form of a section - name. - - Raises ``ValueError`` if the section isn't known. - - Returns a ``list``. - """ - - section = self._section_enum.make(number) - return self.sections[section] - - def find_rrset( - self, - section: SectionType, - name: dns.name.Name, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - deleting: Optional[dns.rdataclass.RdataClass] = None, - create: bool = False, - force_unique: bool = False, - idna_codec: Optional[dns.name.IDNACodec] = None, - ) -> dns.rrset.RRset: - """Find the RRset with the given attributes in the specified section. - - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to search. For example:: - - my_message.find_rrset(my_message.answer, name, rdclass, rdtype) - my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype) - my_message.find_rrset("ANSWER", name, rdclass, rdtype) - - *name*, a ``dns.name.Name`` or ``str``, the name of the RRset. - - *rdclass*, an ``int`` or ``str``, the class of the RRset. - - *rdtype*, an ``int`` or ``str``, the type of the RRset. - - *covers*, an ``int`` or ``str``, the covers value of the RRset. - The default is ``dns.rdatatype.NONE``. - - *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the - RRset. The default is ``None``. - - *create*, a ``bool``. If ``True``, create the RRset if it is not found. - The created RRset is appended to *section*. - - *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``, - create a new RRset regardless of whether a matching RRset exists - already. The default is ``False``. This is useful when creating - DDNS Update messages, as order matters for them. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Raises ``KeyError`` if the RRset was not found and create was - ``False``. - - Returns a ``dns.rrset.RRset object``. - """ - - if isinstance(section, int): - section_number = section - section = self.section_from_number(section_number) - elif isinstance(section, str): - section_number = self._section_enum.from_text(section) - section = self.section_from_number(section_number) - else: - section_number = self.section_number(section) - if isinstance(name, str): - name = dns.name.from_text(name, idna_codec=idna_codec) - rdtype = dns.rdatatype.RdataType.make(rdtype) - rdclass = dns.rdataclass.RdataClass.make(rdclass) - covers = dns.rdatatype.RdataType.make(covers) - if deleting is not None: - deleting = dns.rdataclass.RdataClass.make(deleting) - key = (section_number, name, rdclass, rdtype, covers, deleting) - if not force_unique: - if self.index is not None: - rrset = self.index.get(key) - if rrset is not None: - return rrset - else: - for rrset in section: - if rrset.full_match(name, rdclass, rdtype, covers, deleting): - return rrset - if not create: - raise KeyError - rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting) - section.append(rrset) - if self.index is not None: - self.index[key] = rrset - return rrset - - def get_rrset( - self, - section: SectionType, - name: dns.name.Name, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - deleting: Optional[dns.rdataclass.RdataClass] = None, - create: bool = False, - force_unique: bool = False, - idna_codec: Optional[dns.name.IDNACodec] = None, - ) -> Optional[dns.rrset.RRset]: - """Get the RRset with the given attributes in the specified section. - - If the RRset is not found, None is returned. - - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to search. For example:: - - my_message.get_rrset(my_message.answer, name, rdclass, rdtype) - my_message.get_rrset(dns.message.ANSWER, name, rdclass, rdtype) - my_message.get_rrset("ANSWER", name, rdclass, rdtype) - - *name*, a ``dns.name.Name`` or ``str``, the name of the RRset. - - *rdclass*, an ``int`` or ``str``, the class of the RRset. - - *rdtype*, an ``int`` or ``str``, the type of the RRset. - - *covers*, an ``int`` or ``str``, the covers value of the RRset. - The default is ``dns.rdatatype.NONE``. - - *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the - RRset. The default is ``None``. - - *create*, a ``bool``. If ``True``, create the RRset if it is not found. - The created RRset is appended to *section*. - - *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``, - create a new RRset regardless of whether a matching RRset exists - already. The default is ``False``. This is useful when creating - DDNS Update messages, as order matters for them. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Returns a ``dns.rrset.RRset object`` or ``None``. - """ - - try: - rrset = self.find_rrset( - section, - name, - rdclass, - rdtype, - covers, - deleting, - create, - force_unique, - idna_codec, - ) - except KeyError: - rrset = None - return rrset - - def section_count(self, section: SectionType) -> int: - """Returns the number of records in the specified section. - - *section*, an ``int`` section number, a ``str`` section name, or one of - the section attributes of this message. This specifies the - the section of the message to count. For example:: - - my_message.section_count(my_message.answer) - my_message.section_count(dns.message.ANSWER) - my_message.section_count("ANSWER") - """ - - if isinstance(section, int): - section_number = section - section = self.section_from_number(section_number) - elif isinstance(section, str): - section_number = self._section_enum.from_text(section) - section = self.section_from_number(section_number) - else: - section_number = self.section_number(section) - count = sum(max(1, len(rrs)) for rrs in section) - if section_number == MessageSection.ADDITIONAL: - if self.opt is not None: - count += 1 - if self.tsig is not None: - count += 1 - return count - - def _compute_opt_reserve(self) -> int: - """Compute the size required for the OPT RR, padding excluded""" - if not self.opt: - return 0 - # 1 byte for the root name, 10 for the standard RR fields - size = 11 - # This would be more efficient if options had a size() method, but we won't - # worry about that for now. We also don't worry if there is an existing padding - # option, as it is unlikely and probably harmless, as the worst case is that we - # may add another, and this seems to be legal. - for option in self.opt[0].options: - wire = option.to_wire() - # We add 4 here to account for the option type and length - size += len(wire) + 4 - if self.pad: - # Padding will be added, so again add the option type and length. - size += 4 - return size - - def _compute_tsig_reserve(self) -> int: - """Compute the size required for the TSIG RR""" - # This would be more efficient if TSIGs had a size method, but we won't - # worry about for now. Also, we can't really cope with the potential - # compressibility of the TSIG owner name, so we estimate with the uncompressed - # size. We will disable compression when TSIG and padding are both is active - # so that the padding comes out right. - if not self.tsig: - return 0 - f = io.BytesIO() - self.tsig.to_wire(f) - return len(f.getvalue()) - - def to_wire( - self, - origin: Optional[dns.name.Name] = None, - max_size: int = 0, - multi: bool = False, - tsig_ctx: Optional[Any] = None, - prepend_length: bool = False, - prefer_truncation: bool = False, - **kw: Dict[str, Any], - ) -> bytes: - """Return a string containing the message in DNS compressed wire - format. - - Additional keyword arguments are passed to the RRset ``to_wire()`` - method. - - *origin*, a ``dns.name.Name`` or ``None``, the origin to be appended - to any relative names. If ``None``, and the message has an origin - attribute that is not ``None``, then it will be used. - - *max_size*, an ``int``, the maximum size of the wire format - output; default is 0, which means "the message's request - payload, if nonzero, or 65535". - - *multi*, a ``bool``, should be set to ``True`` if this message is - part of a multiple message sequence. - - *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the - ongoing TSIG context, used when signing zone transfers. - - *prepend_length*, a ``bool``, should be set to ``True`` if the caller - wants the message length prepended to the message itself. This is - useful for messages sent over TCP, TLS (DoT), or QUIC (DoQ). - - *prefer_truncation*, a ``bool``, should be set to ``True`` if the caller - wants the message to be truncated if it would otherwise exceed the - maximum length. If the truncation occurs before the additional section, - the TC bit will be set. - - Raises ``dns.exception.TooBig`` if *max_size* was exceeded. - - Returns a ``bytes``. - """ - - if origin is None and self.origin is not None: - origin = self.origin - if max_size == 0: - if self.request_payload != 0: - max_size = self.request_payload - else: - max_size = 65535 - if max_size < 512: - max_size = 512 - elif max_size > 65535: - max_size = 65535 - r = dns.renderer.Renderer(self.id, self.flags, max_size, origin) - opt_reserve = self._compute_opt_reserve() - r.reserve(opt_reserve) - tsig_reserve = self._compute_tsig_reserve() - r.reserve(tsig_reserve) - try: - for rrset in self.question: - r.add_question(rrset.name, rrset.rdtype, rrset.rdclass) - for rrset in self.answer: - r.add_rrset(dns.renderer.ANSWER, rrset, **kw) - for rrset in self.authority: - r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw) - for rrset in self.additional: - r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw) - except dns.exception.TooBig: - if prefer_truncation: - if r.section < dns.renderer.ADDITIONAL: - r.flags |= dns.flags.TC - else: - raise - r.release_reserved() - if self.opt is not None: - r.add_opt(self.opt, self.pad, opt_reserve, tsig_reserve) - r.write_header() - if self.tsig is not None: - (new_tsig, ctx) = dns.tsig.sign( - r.get_wire(), - self.keyring, - self.tsig[0], - int(time.time()), - self.request_mac, - tsig_ctx, - multi, - ) - self.tsig.clear() - self.tsig.add(new_tsig) - r.add_rrset(dns.renderer.ADDITIONAL, self.tsig) - r.write_header() - if multi: - self.tsig_ctx = ctx - wire = r.get_wire() - self.wire = wire - if prepend_length: - wire = len(wire).to_bytes(2, "big") + wire - return wire - - @staticmethod - def _make_tsig( - keyname, algorithm, time_signed, fudge, mac, original_id, error, other - ): - tsig = dns.rdtypes.ANY.TSIG.TSIG( - dns.rdataclass.ANY, - dns.rdatatype.TSIG, - algorithm, - time_signed, - fudge, - mac, - original_id, - error, - other, - ) - return dns.rrset.from_rdata(keyname, 0, tsig) - - def use_tsig( - self, - keyring: Any, - keyname: Optional[Union[dns.name.Name, str]] = None, - fudge: int = 300, - original_id: Optional[int] = None, - tsig_error: int = 0, - other_data: bytes = b"", - algorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm, - ) -> None: - """When sending, a TSIG signature using the specified key - should be added. - - *key*, a ``dns.tsig.Key`` is the key to use. If a key is specified, - the *keyring* and *algorithm* fields are not used. - - *keyring*, a ``dict``, ``callable`` or ``dns.tsig.Key``, is either - the TSIG keyring or key to use. - - The format of a keyring dict is a mapping from TSIG key name, as - ``dns.name.Name`` to ``dns.tsig.Key`` or a TSIG secret, a ``bytes``. - If a ``dict`` *keyring* is specified but a *keyname* is not, the key - used will be the first key in the *keyring*. Note that the order of - keys in a dictionary is not defined, so applications should supply a - keyname when a ``dict`` keyring is used, unless they know the keyring - contains only one key. If a ``callable`` keyring is specified, the - callable will be called with the message and the keyname, and is - expected to return a key. - - *keyname*, a ``dns.name.Name``, ``str`` or ``None``, the name of - this TSIG key to use; defaults to ``None``. If *keyring* is a - ``dict``, the key must be defined in it. If *keyring* is a - ``dns.tsig.Key``, this is ignored. - - *fudge*, an ``int``, the TSIG time fudge. - - *original_id*, an ``int``, the TSIG original id. If ``None``, - the message's id is used. - - *tsig_error*, an ``int``, the TSIG error code. - - *other_data*, a ``bytes``, the TSIG other data. - - *algorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use. This is - only used if *keyring* is a ``dict``, and the key entry is a ``bytes``. - """ - - if isinstance(keyring, dns.tsig.Key): - key = keyring - keyname = key.name - elif callable(keyring): - key = keyring(self, keyname) - else: - if isinstance(keyname, str): - keyname = dns.name.from_text(keyname) - if keyname is None: - keyname = next(iter(keyring)) - key = keyring[keyname] - if isinstance(key, bytes): - key = dns.tsig.Key(keyname, key, algorithm) - self.keyring = key - if original_id is None: - original_id = self.id - self.tsig = self._make_tsig( - keyname, - self.keyring.algorithm, - 0, - fudge, - b"\x00" * dns.tsig.mac_sizes[self.keyring.algorithm], - original_id, - tsig_error, - other_data, - ) - - @property - def keyname(self) -> Optional[dns.name.Name]: - if self.tsig: - return self.tsig.name - else: - return None - - @property - def keyalgorithm(self) -> Optional[dns.name.Name]: - if self.tsig: - return self.tsig[0].algorithm - else: - return None - - @property - def mac(self) -> Optional[bytes]: - if self.tsig: - return self.tsig[0].mac - else: - return None - - @property - def tsig_error(self) -> Optional[int]: - if self.tsig: - return self.tsig[0].error - else: - return None - - @property - def had_tsig(self) -> bool: - return bool(self.tsig) - - @staticmethod - def _make_opt(flags=0, payload=DEFAULT_EDNS_PAYLOAD, options=None): - opt = dns.rdtypes.ANY.OPT.OPT(payload, dns.rdatatype.OPT, options or ()) - return dns.rrset.from_rdata(dns.name.root, int(flags), opt) - - def use_edns( - self, - edns: Optional[Union[int, bool]] = 0, - ednsflags: int = 0, - payload: int = DEFAULT_EDNS_PAYLOAD, - request_payload: Optional[int] = None, - options: Optional[List[dns.edns.Option]] = None, - pad: int = 0, - ) -> None: - """Configure EDNS behavior. - - *edns*, an ``int``, is the EDNS level to use. Specifying ``None``, ``False``, - or ``-1`` means "do not use EDNS", and in this case the other parameters are - ignored. Specifying ``True`` is equivalent to specifying 0, i.e. "use EDNS0". - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the maximum - size of UDP datagram the sender can handle. I.e. how big a response to this - message can be. - - *request_payload*, an ``int``, is the EDNS payload size to use when sending this - message. If not specified, defaults to the value of *payload*. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS options. - - *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add - padding bytes to make the message size a multiple of *pad*. Note that if - padding is non-zero, an EDNS PADDING option will always be added to the - message. - """ - - if edns is None or edns is False: - edns = -1 - elif edns is True: - edns = 0 - if edns < 0: - self.opt = None - self.request_payload = 0 - else: - # make sure the EDNS version in ednsflags agrees with edns - ednsflags &= 0xFF00FFFF - ednsflags |= edns << 16 - if options is None: - options = [] - self.opt = self._make_opt(ednsflags, payload, options) - if request_payload is None: - request_payload = payload - self.request_payload = request_payload - if pad < 0: - raise ValueError("pad must be non-negative") - self.pad = pad - - @property - def edns(self) -> int: - if self.opt: - return (self.ednsflags & 0xFF0000) >> 16 - else: - return -1 - - @property - def ednsflags(self) -> int: - if self.opt: - return self.opt.ttl - else: - return 0 - - @ednsflags.setter - def ednsflags(self, v): - if self.opt: - self.opt.ttl = v - elif v: - self.opt = self._make_opt(v) - - @property - def payload(self) -> int: - if self.opt: - return self.opt[0].payload - else: - return 0 - - @property - def options(self) -> Tuple: - if self.opt: - return self.opt[0].options - else: - return () - - def want_dnssec(self, wanted: bool = True) -> None: - """Enable or disable 'DNSSEC desired' flag in requests. - - *wanted*, a ``bool``. If ``True``, then DNSSEC data is - desired in the response, EDNS is enabled if required, and then - the DO bit is set. If ``False``, the DO bit is cleared if - EDNS is enabled. - """ - - if wanted: - self.ednsflags |= dns.flags.DO - elif self.opt: - self.ednsflags &= ~int(dns.flags.DO) - - def rcode(self) -> dns.rcode.Rcode: - """Return the rcode. - - Returns a ``dns.rcode.Rcode``. - """ - return dns.rcode.from_flags(int(self.flags), int(self.ednsflags)) - - def set_rcode(self, rcode: dns.rcode.Rcode) -> None: - """Set the rcode. - - *rcode*, a ``dns.rcode.Rcode``, is the rcode to set. - """ - (value, evalue) = dns.rcode.to_flags(rcode) - self.flags &= 0xFFF0 - self.flags |= value - self.ednsflags &= 0x00FFFFFF - self.ednsflags |= evalue - - def opcode(self) -> dns.opcode.Opcode: - """Return the opcode. - - Returns a ``dns.opcode.Opcode``. - """ - return dns.opcode.from_flags(int(self.flags)) - - def set_opcode(self, opcode: dns.opcode.Opcode) -> None: - """Set the opcode. - - *opcode*, a ``dns.opcode.Opcode``, is the opcode to set. - """ - self.flags &= 0x87FF - self.flags |= dns.opcode.to_flags(opcode) - - def get_options(self, otype: dns.edns.OptionType) -> List[dns.edns.Option]: - """Return the list of options of the specified type.""" - return [option for option in self.options if option.otype == otype] - - def extended_errors(self) -> List[dns.edns.EDEOption]: - """Return the list of Extended DNS Error (EDE) options in the message""" - return cast(List[dns.edns.EDEOption], self.get_options(dns.edns.OptionType.EDE)) - - def _get_one_rr_per_rrset(self, value): - # What the caller picked is fine. - return value - - # pylint: disable=unused-argument - - def _parse_rr_header(self, section, name, rdclass, rdtype): - return (rdclass, rdtype, None, False) - - # pylint: enable=unused-argument - - def _parse_special_rr_header(self, section, count, position, name, rdclass, rdtype): - if rdtype == dns.rdatatype.OPT: - if ( - section != MessageSection.ADDITIONAL - or self.opt - or name != dns.name.root - ): - raise BadEDNS - elif rdtype == dns.rdatatype.TSIG: - if ( - section != MessageSection.ADDITIONAL - or rdclass != dns.rdatatype.ANY - or position != count - 1 - ): - raise BadTSIG - return (rdclass, rdtype, None, False) - - -class ChainingResult: - """The result of a call to dns.message.QueryMessage.resolve_chaining(). - - The ``answer`` attribute is the answer RRSet, or ``None`` if it doesn't - exist. - - The ``canonical_name`` attribute is the canonical name after all - chaining has been applied (this is the same name as ``rrset.name`` in cases - where rrset is not ``None``). - - The ``minimum_ttl`` attribute is the minimum TTL, i.e. the TTL to - use if caching the data. It is the smallest of all the CNAME TTLs - and either the answer TTL if it exists or the SOA TTL and SOA - minimum values for negative answers. - - The ``cnames`` attribute is a list of all the CNAME RRSets followed to - get to the canonical name. - """ - - def __init__( - self, - canonical_name: dns.name.Name, - answer: Optional[dns.rrset.RRset], - minimum_ttl: int, - cnames: List[dns.rrset.RRset], - ): - self.canonical_name = canonical_name - self.answer = answer - self.minimum_ttl = minimum_ttl - self.cnames = cnames - - -class QueryMessage(Message): - def resolve_chaining(self) -> ChainingResult: - """Follow the CNAME chain in the response to determine the answer - RRset. - - Raises ``dns.message.NotQueryResponse`` if the message is not - a response. - - Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long. - - Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN - but an answer was found. - - Raises ``dns.exception.FormError`` if the question count is not 1. - - Returns a ChainingResult object. - """ - if self.flags & dns.flags.QR == 0: - raise NotQueryResponse - if len(self.question) != 1: - raise dns.exception.FormError - question = self.question[0] - qname = question.name - min_ttl = dns.ttl.MAX_TTL - answer = None - count = 0 - cnames = [] - while count < MAX_CHAIN: - try: - answer = self.find_rrset( - self.answer, qname, question.rdclass, question.rdtype - ) - min_ttl = min(min_ttl, answer.ttl) - break - except KeyError: - if question.rdtype != dns.rdatatype.CNAME: - try: - crrset = self.find_rrset( - self.answer, qname, question.rdclass, dns.rdatatype.CNAME - ) - cnames.append(crrset) - min_ttl = min(min_ttl, crrset.ttl) - for rd in crrset: - qname = rd.target - break - count += 1 - continue - except KeyError: - # Exit the chaining loop - break - else: - # Exit the chaining loop - break - if count >= MAX_CHAIN: - raise ChainTooLong - if self.rcode() == dns.rcode.NXDOMAIN and answer is not None: - raise AnswerForNXDOMAIN - if answer is None: - # Further minimize the TTL with NCACHE. - auname = qname - while True: - # Look for an SOA RR whose owner name is a superdomain - # of qname. - try: - srrset = self.find_rrset( - self.authority, auname, question.rdclass, dns.rdatatype.SOA - ) - min_ttl = min(min_ttl, srrset.ttl, srrset[0].minimum) - break - except KeyError: - try: - auname = auname.parent() - except dns.name.NoParent: - break - return ChainingResult(qname, answer, min_ttl, cnames) - - def canonical_name(self) -> dns.name.Name: - """Return the canonical name of the first name in the question - section. - - Raises ``dns.message.NotQueryResponse`` if the message is not - a response. - - Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long. - - Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN - but an answer was found. - - Raises ``dns.exception.FormError`` if the question count is not 1. - """ - return self.resolve_chaining().canonical_name - - -def _maybe_import_update(): - # We avoid circular imports by doing this here. We do it in another - # function as doing it in _message_factory_from_opcode() makes "dns" - # a local symbol, and the first line fails :) - - # pylint: disable=redefined-outer-name,import-outside-toplevel,unused-import - import dns.update # noqa: F401 - - -def _message_factory_from_opcode(opcode): - if opcode == dns.opcode.QUERY: - return QueryMessage - elif opcode == dns.opcode.UPDATE: - _maybe_import_update() - return dns.update.UpdateMessage - else: - return Message - - -class _WireReader: - """Wire format reader. - - parser: the binary parser - message: The message object being built - initialize_message: Callback to set message parsing options - question_only: Are we only reading the question? - one_rr_per_rrset: Put each RR into its own RRset? - keyring: TSIG keyring - ignore_trailing: Ignore trailing junk at end of request? - multi: Is this message part of a multi-message sequence? - DNS dynamic updates. - continue_on_error: try to extract as much information as possible from - the message, accumulating MessageErrors in the *errors* attribute instead of - raising them. - """ - - def __init__( - self, - wire, - initialize_message, - question_only=False, - one_rr_per_rrset=False, - ignore_trailing=False, - keyring=None, - multi=False, - continue_on_error=False, - ): - self.parser = dns.wire.Parser(wire) - self.message = None - self.initialize_message = initialize_message - self.question_only = question_only - self.one_rr_per_rrset = one_rr_per_rrset - self.ignore_trailing = ignore_trailing - self.keyring = keyring - self.multi = multi - self.continue_on_error = continue_on_error - self.errors = [] - - def _get_question(self, section_number, qcount): - """Read the next *qcount* records from the wire data and add them to - the question section. - """ - assert self.message is not None - section = self.message.sections[section_number] - for _ in range(qcount): - qname = self.parser.get_name(self.message.origin) - (rdtype, rdclass) = self.parser.get_struct("!HH") - (rdclass, rdtype, _, _) = self.message._parse_rr_header( - section_number, qname, rdclass, rdtype - ) - self.message.find_rrset( - section, qname, rdclass, rdtype, create=True, force_unique=True - ) - - def _add_error(self, e): - self.errors.append(MessageError(e, self.parser.current)) - - def _get_section(self, section_number, count): - """Read the next I{count} records from the wire data and add them to - the specified section. - - section_number: the section of the message to which to add records - count: the number of records to read - """ - assert self.message is not None - section = self.message.sections[section_number] - force_unique = self.one_rr_per_rrset - for i in range(count): - rr_start = self.parser.current - absolute_name = self.parser.get_name() - if self.message.origin is not None: - name = absolute_name.relativize(self.message.origin) - else: - name = absolute_name - (rdtype, rdclass, ttl, rdlen) = self.parser.get_struct("!HHIH") - if rdtype in (dns.rdatatype.OPT, dns.rdatatype.TSIG): - ( - rdclass, - rdtype, - deleting, - empty, - ) = self.message._parse_special_rr_header( - section_number, count, i, name, rdclass, rdtype - ) - else: - (rdclass, rdtype, deleting, empty) = self.message._parse_rr_header( - section_number, name, rdclass, rdtype - ) - rdata_start = self.parser.current - try: - if empty: - if rdlen > 0: - raise dns.exception.FormError - rd = None - covers = dns.rdatatype.NONE - else: - with self.parser.restrict_to(rdlen): - rd = dns.rdata.from_wire_parser( - rdclass, rdtype, self.parser, self.message.origin - ) - covers = rd.covers() - if self.message.xfr and rdtype == dns.rdatatype.SOA: - force_unique = True - if rdtype == dns.rdatatype.OPT: - self.message.opt = dns.rrset.from_rdata(name, ttl, rd) - elif rdtype == dns.rdatatype.TSIG: - if self.keyring is None or self.keyring is True: - raise UnknownTSIGKey("got signed message without keyring") - elif isinstance(self.keyring, dict): - key = self.keyring.get(absolute_name) - if isinstance(key, bytes): - key = dns.tsig.Key(absolute_name, key, rd.algorithm) - elif callable(self.keyring): - key = self.keyring(self.message, absolute_name) - else: - key = self.keyring - if key is None: - raise UnknownTSIGKey(f"key '{name}' unknown") - if key: - self.message.keyring = key - self.message.tsig_ctx = dns.tsig.validate( - self.parser.wire, - key, - absolute_name, - rd, - int(time.time()), - self.message.request_mac, - rr_start, - self.message.tsig_ctx, - self.multi, - ) - self.message.tsig = dns.rrset.from_rdata(absolute_name, 0, rd) - else: - rrset = self.message.find_rrset( - section, - name, - rdclass, - rdtype, - covers, - deleting, - True, - force_unique, - ) - if rd is not None: - if ttl > 0x7FFFFFFF: - ttl = 0 - rrset.add(rd, ttl) - except Exception as e: - if self.continue_on_error: - self._add_error(e) - self.parser.seek(rdata_start + rdlen) - else: - raise - - def read(self): - """Read a wire format DNS message and build a dns.message.Message - object.""" - - if self.parser.remaining() < 12: - raise ShortHeader - (id, flags, qcount, ancount, aucount, adcount) = self.parser.get_struct( - "!HHHHHH" - ) - factory = _message_factory_from_opcode(dns.opcode.from_flags(flags)) - self.message = factory(id=id) - self.message.flags = dns.flags.Flag(flags) - self.message.wire = self.parser.wire - self.initialize_message(self.message) - self.one_rr_per_rrset = self.message._get_one_rr_per_rrset( - self.one_rr_per_rrset - ) - try: - self._get_question(MessageSection.QUESTION, qcount) - if self.question_only: - return self.message - self._get_section(MessageSection.ANSWER, ancount) - self._get_section(MessageSection.AUTHORITY, aucount) - self._get_section(MessageSection.ADDITIONAL, adcount) - if not self.ignore_trailing and self.parser.remaining() != 0: - raise TrailingJunk - if self.multi and self.message.tsig_ctx and not self.message.had_tsig: - self.message.tsig_ctx.update(self.parser.wire) - except Exception as e: - if self.continue_on_error: - self._add_error(e) - else: - raise - return self.message - - -def from_wire( - wire: bytes, - keyring: Optional[Any] = None, - request_mac: Optional[bytes] = b"", - xfr: bool = False, - origin: Optional[dns.name.Name] = None, - tsig_ctx: Optional[Union[dns.tsig.HMACTSig, dns.tsig.GSSTSig]] = None, - multi: bool = False, - question_only: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - raise_on_truncation: bool = False, - continue_on_error: bool = False, -) -> Message: - """Convert a DNS wire format message into a message object. - - *keyring*, a ``dns.tsig.Key``, ``dict``, ``bool``, or ``None``, the key or keyring - to use if the message is signed. If ``None`` or ``True``, then trying to decode - a message with a TSIG will fail as it cannot be validated. If ``False``, then - TSIG validation is disabled. - - *request_mac*, a ``bytes`` or ``None``. If the message is a response to a - TSIG-signed request, *request_mac* should be set to the MAC of that request. - - *xfr*, a ``bool``, should be set to ``True`` if this message is part of a zone - transfer. - - *origin*, a ``dns.name.Name`` or ``None``. If the message is part of a zone - transfer, *origin* should be the origin name of the zone. If not ``None``, names - will be relativized to the origin. - - *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the ongoing TSIG - context, used when validating zone transfers. - - *multi*, a ``bool``, should be set to ``True`` if this message is part of a multiple - message sequence. - - *question_only*, a ``bool``. If ``True``, read only up to the end of the question - section. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if the TC bit is - set. - - *continue_on_error*, a ``bool``. If ``True``, try to continue parsing even if - errors occur. Erroneous rdata will be ignored. Errors will be accumulated as a - list of MessageError objects in the message's ``errors`` attribute. This option is - recommended only for DNS analysis tools, or for use in a server as part of an error - handling path. The default is ``False``. - - Raises ``dns.message.ShortHeader`` if the message is less than 12 octets long. - - Raises ``dns.message.TrailingJunk`` if there were octets in the message past the end - of the proper DNS message, and *ignore_trailing* is ``False``. - - Raises ``dns.message.BadEDNS`` if an OPT record was in the wrong section, or - occurred more than once. - - Raises ``dns.message.BadTSIG`` if a TSIG record was not the last record of the - additional data section. - - Raises ``dns.message.Truncated`` if the TC flag is set and *raise_on_truncation* is - ``True``. - - Returns a ``dns.message.Message``. - """ - - # We permit None for request_mac solely for backwards compatibility - if request_mac is None: - request_mac = b"" - - def initialize_message(message): - message.request_mac = request_mac - message.xfr = xfr - message.origin = origin - message.tsig_ctx = tsig_ctx - - reader = _WireReader( - wire, - initialize_message, - question_only, - one_rr_per_rrset, - ignore_trailing, - keyring, - multi, - continue_on_error, - ) - try: - m = reader.read() - except dns.exception.FormError: - if ( - reader.message - and (reader.message.flags & dns.flags.TC) - and raise_on_truncation - ): - raise Truncated(message=reader.message) - else: - raise - # Reading a truncated message might not have any errors, so we - # have to do this check here too. - if m.flags & dns.flags.TC and raise_on_truncation: - raise Truncated(message=m) - if continue_on_error: - m.errors = reader.errors - - return m - - -class _TextReader: - """Text format reader. - - tok: the tokenizer. - message: The message object being built. - DNS dynamic updates. - last_name: The most recently read name when building a message object. - one_rr_per_rrset: Put each RR into its own RRset? - origin: The origin for relative names - relativize: relativize names? - relativize_to: the origin to relativize to. - """ - - def __init__( - self, - text, - idna_codec, - one_rr_per_rrset=False, - origin=None, - relativize=True, - relativize_to=None, - ): - self.message = None - self.tok = dns.tokenizer.Tokenizer(text, idna_codec=idna_codec) - self.last_name = None - self.one_rr_per_rrset = one_rr_per_rrset - self.origin = origin - self.relativize = relativize - self.relativize_to = relativize_to - self.id = None - self.edns = -1 - self.ednsflags = 0 - self.payload = DEFAULT_EDNS_PAYLOAD - self.rcode = None - self.opcode = dns.opcode.QUERY - self.flags = 0 - - def _header_line(self, _): - """Process one line from the text format header section.""" - - token = self.tok.get() - what = token.value - if what == "id": - self.id = self.tok.get_int() - elif what == "flags": - while True: - token = self.tok.get() - if not token.is_identifier(): - self.tok.unget(token) - break - self.flags = self.flags | dns.flags.from_text(token.value) - elif what == "edns": - self.edns = self.tok.get_int() - self.ednsflags = self.ednsflags | (self.edns << 16) - elif what == "eflags": - if self.edns < 0: - self.edns = 0 - while True: - token = self.tok.get() - if not token.is_identifier(): - self.tok.unget(token) - break - self.ednsflags = self.ednsflags | dns.flags.edns_from_text(token.value) - elif what == "payload": - self.payload = self.tok.get_int() - if self.edns < 0: - self.edns = 0 - elif what == "opcode": - text = self.tok.get_string() - self.opcode = dns.opcode.from_text(text) - self.flags = self.flags | dns.opcode.to_flags(self.opcode) - elif what == "rcode": - text = self.tok.get_string() - self.rcode = dns.rcode.from_text(text) - else: - raise UnknownHeaderField - self.tok.get_eol() - - def _question_line(self, section_number): - """Process one line from the text format question section.""" - - section = self.message.sections[section_number] - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = self.tok.as_name( - token, self.message.origin, self.relativize, self.relativize_to - ) - name = self.last_name - if name is None: - raise NoPreviousName - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = dns.rdataclass.IN - # Type - rdtype = dns.rdatatype.from_text(token.value) - (rdclass, rdtype, _, _) = self.message._parse_rr_header( - section_number, name, rdclass, rdtype - ) - self.message.find_rrset( - section, name, rdclass, rdtype, create=True, force_unique=True - ) - self.tok.get_eol() - - def _rr_line(self, section_number): - """Process one line from the text format answer, authority, or - additional data sections. - """ - - section = self.message.sections[section_number] - # Name - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = self.tok.as_name( - token, self.message.origin, self.relativize, self.relativize_to - ) - name = self.last_name - if name is None: - raise NoPreviousName - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - # TTL - try: - ttl = int(token.value, 0) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - ttl = 0 - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = dns.rdataclass.IN - # Type - rdtype = dns.rdatatype.from_text(token.value) - (rdclass, rdtype, deleting, empty) = self.message._parse_rr_header( - section_number, name, rdclass, rdtype - ) - token = self.tok.get() - if empty and not token.is_eol_or_eof(): - raise dns.exception.SyntaxError - if not empty and token.is_eol_or_eof(): - raise dns.exception.UnexpectedEnd - if not token.is_eol_or_eof(): - self.tok.unget(token) - rd = dns.rdata.from_text( - rdclass, - rdtype, - self.tok, - self.message.origin, - self.relativize, - self.relativize_to, - ) - covers = rd.covers() - else: - rd = None - covers = dns.rdatatype.NONE - rrset = self.message.find_rrset( - section, - name, - rdclass, - rdtype, - covers, - deleting, - True, - self.one_rr_per_rrset, - ) - if rd is not None: - rrset.add(rd, ttl) - - def _make_message(self): - factory = _message_factory_from_opcode(self.opcode) - message = factory(id=self.id) - message.flags = self.flags - if self.edns >= 0: - message.use_edns(self.edns, self.ednsflags, self.payload) - if self.rcode: - message.set_rcode(self.rcode) - if self.origin: - message.origin = self.origin - return message - - def read(self): - """Read a text format DNS message and build a dns.message.Message - object.""" - - line_method = self._header_line - section_number = None - while 1: - token = self.tok.get(True, True) - if token.is_eol_or_eof(): - break - if token.is_comment(): - u = token.value.upper() - if u == "HEADER": - line_method = self._header_line - - if self.message: - message = self.message - else: - # If we don't have a message, create one with the current - # opcode, so that we know which section names to parse. - message = self._make_message() - try: - section_number = message._section_enum.from_text(u) - # We found a section name. If we don't have a message, - # use the one we just created. - if not self.message: - self.message = message - self.one_rr_per_rrset = message._get_one_rr_per_rrset( - self.one_rr_per_rrset - ) - if section_number == MessageSection.QUESTION: - line_method = self._question_line - else: - line_method = self._rr_line - except Exception: - # It's just a comment. - pass - self.tok.get_eol() - continue - self.tok.unget(token) - line_method(section_number) - if not self.message: - self.message = self._make_message() - return self.message - - -def from_text( - text: str, - idna_codec: Optional[dns.name.IDNACodec] = None, - one_rr_per_rrset: bool = False, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, -) -> Message: - """Convert the text format message into a message object. - - The reader stops after reading the first blank line in the input to - facilitate reading multiple messages from a single file with - ``dns.message.from_file()``. - - *text*, a ``str``, the text format message. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put - into its own rrset. The default is ``False``. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Raises ``dns.message.UnknownHeaderField`` if a header is unknown. - - Raises ``dns.exception.SyntaxError`` if the text is badly formed. - - Returns a ``dns.message.Message object`` - """ - - # 'text' can also be a file, but we don't publish that fact - # since it's an implementation detail. The official file - # interface is from_file(). - - reader = _TextReader( - text, idna_codec, one_rr_per_rrset, origin, relativize, relativize_to - ) - return reader.read() - - -def from_file( - f: Any, - idna_codec: Optional[dns.name.IDNACodec] = None, - one_rr_per_rrset: bool = False, -) -> Message: - """Read the next text format message from the specified file. - - Message blocks are separated by a single blank line. - - *f*, a ``file`` or ``str``. If *f* is text, it is treated as the - pathname of a file to open. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put - into its own rrset. The default is ``False``. - - Raises ``dns.message.UnknownHeaderField`` if a header is unknown. - - Raises ``dns.exception.SyntaxError`` if the text is badly formed. - - Returns a ``dns.message.Message object`` - """ - - if isinstance(f, str): - cm: contextlib.AbstractContextManager = open(f) - else: - cm = contextlib.nullcontext(f) - with cm as f: - return from_text(f, idna_codec, one_rr_per_rrset) - assert False # for mypy lgtm[py/unreachable-statement] - - -def make_query( - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - use_edns: Optional[Union[int, bool]] = None, - want_dnssec: bool = False, - ednsflags: Optional[int] = None, - payload: Optional[int] = None, - request_payload: Optional[int] = None, - options: Optional[List[dns.edns.Option]] = None, - idna_codec: Optional[dns.name.IDNACodec] = None, - id: Optional[int] = None, - flags: int = dns.flags.RD, - pad: int = 0, -) -> QueryMessage: - """Make a query message. - - The query name, type, and class may all be specified either - as objects of the appropriate type, or as strings. - - The query will have a randomly chosen query id, and its DNS flags - will be set to dns.flags.RD. - - qname, a ``dns.name.Name`` or ``str``, the query name. - - *rdtype*, an ``int`` or ``str``, the desired rdata type. - - *rdclass*, an ``int`` or ``str``, the desired rdata class; the default - is class IN. - - *use_edns*, an ``int``, ``bool`` or ``None``. The EDNS level to use; the - default is ``None``. If ``None``, EDNS will be enabled only if other - parameters (*ednsflags*, *payload*, *request_payload*, or *options*) are - set. - See the description of dns.message.Message.use_edns() for the possible - values for use_edns and their meanings. - - *want_dnssec*, a ``bool``. If ``True``, DNSSEC data is desired. - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the - maximum size of UDP datagram the sender can handle. I.e. how big - a response to this message can be. - - *request_payload*, an ``int``, is the EDNS payload size to use when - sending this message. If not specified, defaults to the value of - *payload*. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS - options. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *id*, an ``int`` or ``None``, the desired query id. The default is - ``None``, which generates a random query id. - - *flags*, an ``int``, the desired query flags. The default is - ``dns.flags.RD``. - - *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add - padding bytes to make the message size a multiple of *pad*. Note that if - padding is non-zero, an EDNS PADDING option will always be added to the - message. - - Returns a ``dns.message.QueryMessage`` - """ - - if isinstance(qname, str): - qname = dns.name.from_text(qname, idna_codec=idna_codec) - rdtype = dns.rdatatype.RdataType.make(rdtype) - rdclass = dns.rdataclass.RdataClass.make(rdclass) - m = QueryMessage(id=id) - m.flags = dns.flags.Flag(flags) - m.find_rrset(m.question, qname, rdclass, rdtype, create=True, force_unique=True) - # only pass keywords on to use_edns if they have been set to a - # non-None value. Setting a field will turn EDNS on if it hasn't - # been configured. - kwargs: Dict[str, Any] = {} - if ednsflags is not None: - kwargs["ednsflags"] = ednsflags - if payload is not None: - kwargs["payload"] = payload - if request_payload is not None: - kwargs["request_payload"] = request_payload - if options is not None: - kwargs["options"] = options - if kwargs and use_edns is None: - use_edns = 0 - kwargs["edns"] = use_edns - kwargs["pad"] = pad - m.use_edns(**kwargs) - m.want_dnssec(want_dnssec) - return m - - -class CopyMode(enum.Enum): - """ - How should sections be copied when making an update response? - """ - - NOTHING = 0 - QUESTION = 1 - EVERYTHING = 2 - - -def make_response( - query: Message, - recursion_available: bool = False, - our_payload: int = 8192, - fudge: int = 300, - tsig_error: int = 0, - pad: Optional[int] = None, - copy_mode: Optional[CopyMode] = None, -) -> Message: - """Make a message which is a response for the specified query. - The message returned is really a response skeleton; it has all of the infrastructure - required of a response, but none of the content. - - Response section(s) which are copied are shallow copies of the matching section(s) - in the query, so the query's RRsets should not be changed. - - *query*, a ``dns.message.Message``, the query to respond to. - - *recursion_available*, a ``bool``, should RA be set in the response? - - *our_payload*, an ``int``, the payload size to advertise in EDNS responses. - - *fudge*, an ``int``, the TSIG time fudge. - - *tsig_error*, an ``int``, the TSIG error. - - *pad*, a non-negative ``int`` or ``None``. If 0, the default, do not pad; otherwise - if not ``None`` add padding bytes to make the message size a multiple of *pad*. Note - that if padding is non-zero, an EDNS PADDING option will always be added to the - message. If ``None``, add padding following RFC 8467, namely if the request is - padded, pad the response to 468 otherwise do not pad. - - *copy_mode*, a ``dns.message.CopyMode`` or ``None``, determines how sections are - copied. The default, ``None`` copies sections according to the default for the - message's opcode, which is currently ``dns.message.CopyMode.QUESTION`` for all - opcodes. ``dns.message.CopyMode.QUESTION`` copies only the question section. - ``dns.message.CopyMode.EVERYTHING`` copies all sections other than OPT or TSIG - records, which are created appropriately if needed. ``dns.message.CopyMode.NOTHING`` - copies no sections; note that this mode is for server testing purposes and is - otherwise not recommended for use. In particular, ``dns.message.is_response()`` - will be ``False`` if you create a response this way and the rcode is not - ``FORMERR``, ``SERVFAIL``, ``NOTIMP``, or ``REFUSED``. - - Returns a ``dns.message.Message`` object whose specific class is appropriate for the - query. For example, if query is a ``dns.update.UpdateMessage``, the response will - be one too. - """ - - if query.flags & dns.flags.QR: - raise dns.exception.FormError("specified query message is not a query") - opcode = query.opcode() - factory = _message_factory_from_opcode(opcode) - response = factory(id=query.id) - response.flags = dns.flags.QR | (query.flags & dns.flags.RD) - if recursion_available: - response.flags |= dns.flags.RA - response.set_opcode(opcode) - if copy_mode is None: - copy_mode = CopyMode.QUESTION - if copy_mode != CopyMode.NOTHING: - response.question = list(query.question) - if copy_mode == CopyMode.EVERYTHING: - response.answer = list(query.answer) - response.authority = list(query.authority) - response.additional = list(query.additional) - if query.edns >= 0: - if pad is None: - # Set response padding per RFC 8467 - pad = 0 - for option in query.options: - if option.otype == dns.edns.OptionType.PADDING: - pad = 468 - response.use_edns(0, 0, our_payload, query.payload, pad=pad) - if query.had_tsig: - response.use_tsig( - query.keyring, - query.keyname, - fudge, - None, - tsig_error, - b"", - query.keyalgorithm, - ) - response.request_mac = query.mac - return response - - -### BEGIN generated MessageSection constants - -QUESTION = MessageSection.QUESTION -ANSWER = MessageSection.ANSWER -AUTHORITY = MessageSection.AUTHORITY -ADDITIONAL = MessageSection.ADDITIONAL - -### END generated MessageSection constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/name.py b/backend/venv39/lib/python3.9/site-packages/dns/name.py deleted file mode 100644 index f79f0d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/name.py +++ /dev/null @@ -1,1284 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Names. -""" - -import copy -import encodings.idna # type: ignore -import functools -import struct -from typing import Any, Callable, Dict, Iterable, Optional, Tuple, Union - -import dns._features -import dns.enum -import dns.exception -import dns.immutable -import dns.wire - -if dns._features.have("idna"): - import idna # type: ignore - - have_idna_2008 = True -else: # pragma: no cover - have_idna_2008 = False - -CompressType = Dict["Name", int] - - -class NameRelation(dns.enum.IntEnum): - """Name relation result from fullcompare().""" - - # This is an IntEnum for backwards compatibility in case anyone - # has hardwired the constants. - - #: The compared names have no relationship to each other. - NONE = 0 - #: the first name is a superdomain of the second. - SUPERDOMAIN = 1 - #: The first name is a subdomain of the second. - SUBDOMAIN = 2 - #: The compared names are equal. - EQUAL = 3 - #: The compared names have a common ancestor. - COMMONANCESTOR = 4 - - @classmethod - def _maximum(cls): - return cls.COMMONANCESTOR # pragma: no cover - - @classmethod - def _short_name(cls): - return cls.__name__ # pragma: no cover - - -# Backwards compatibility -NAMERELN_NONE = NameRelation.NONE -NAMERELN_SUPERDOMAIN = NameRelation.SUPERDOMAIN -NAMERELN_SUBDOMAIN = NameRelation.SUBDOMAIN -NAMERELN_EQUAL = NameRelation.EQUAL -NAMERELN_COMMONANCESTOR = NameRelation.COMMONANCESTOR - - -class EmptyLabel(dns.exception.SyntaxError): - """A DNS label is empty.""" - - -class BadEscape(dns.exception.SyntaxError): - """An escaped code in a text format of DNS name is invalid.""" - - -class BadPointer(dns.exception.FormError): - """A DNS compression pointer points forward instead of backward.""" - - -class BadLabelType(dns.exception.FormError): - """The label type in DNS name wire format is unknown.""" - - -class NeedAbsoluteNameOrOrigin(dns.exception.DNSException): - """An attempt was made to convert a non-absolute name to - wire when there was also a non-absolute (or missing) origin.""" - - -class NameTooLong(dns.exception.FormError): - """A DNS name is > 255 octets long.""" - - -class LabelTooLong(dns.exception.SyntaxError): - """A DNS label is > 63 octets long.""" - - -class AbsoluteConcatenation(dns.exception.DNSException): - """An attempt was made to append anything other than the - empty name to an absolute DNS name.""" - - -class NoParent(dns.exception.DNSException): - """An attempt was made to get the parent of the root name - or the empty name.""" - - -class NoIDNA2008(dns.exception.DNSException): - """IDNA 2008 processing was requested but the idna module is not - available.""" - - -class IDNAException(dns.exception.DNSException): - """IDNA processing raised an exception.""" - - supp_kwargs = {"idna_exception"} - fmt = "IDNA processing exception: {idna_exception}" - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - -class NeedSubdomainOfOrigin(dns.exception.DNSException): - """An absolute name was provided that is not a subdomain of the specified origin.""" - - -_escaped = b'"().;\\@$' -_escaped_text = '"().;\\@$' - - -def _escapify(label: Union[bytes, str]) -> str: - """Escape the characters in label which need it. - @returns: the escaped string - @rtype: string""" - if isinstance(label, bytes): - # Ordinary DNS label mode. Escape special characters and values - # < 0x20 or > 0x7f. - text = "" - for c in label: - if c in _escaped: - text += "\\" + chr(c) - elif c > 0x20 and c < 0x7F: - text += chr(c) - else: - text += "\\%03d" % c - return text - - # Unicode label mode. Escape only special characters and values < 0x20 - text = "" - for uc in label: - if uc in _escaped_text: - text += "\\" + uc - elif uc <= "\x20": - text += "\\%03d" % ord(uc) - else: - text += uc - return text - - -class IDNACodec: - """Abstract base class for IDNA encoder/decoders.""" - - def __init__(self): - pass - - def is_idna(self, label: bytes) -> bool: - return label.lower().startswith(b"xn--") - - def encode(self, label: str) -> bytes: - raise NotImplementedError # pragma: no cover - - def decode(self, label: bytes) -> str: - # We do not apply any IDNA policy on decode. - if self.is_idna(label): - try: - slabel = label[4:].decode("punycode") - return _escapify(slabel) - except Exception as e: - raise IDNAException(idna_exception=e) - else: - return _escapify(label) - - -class IDNA2003Codec(IDNACodec): - """IDNA 2003 encoder/decoder.""" - - def __init__(self, strict_decode: bool = False): - """Initialize the IDNA 2003 encoder/decoder. - - *strict_decode* is a ``bool``. If `True`, then IDNA2003 checking - is done when decoding. This can cause failures if the name - was encoded with IDNA2008. The default is `False`. - """ - - super().__init__() - self.strict_decode = strict_decode - - def encode(self, label: str) -> bytes: - """Encode *label*.""" - - if label == "": - return b"" - try: - return encodings.idna.ToASCII(label) - except UnicodeError: - raise LabelTooLong - - def decode(self, label: bytes) -> str: - """Decode *label*.""" - if not self.strict_decode: - return super().decode(label) - if label == b"": - return "" - try: - return _escapify(encodings.idna.ToUnicode(label)) - except Exception as e: - raise IDNAException(idna_exception=e) - - -class IDNA2008Codec(IDNACodec): - """IDNA 2008 encoder/decoder.""" - - def __init__( - self, - uts_46: bool = False, - transitional: bool = False, - allow_pure_ascii: bool = False, - strict_decode: bool = False, - ): - """Initialize the IDNA 2008 encoder/decoder. - - *uts_46* is a ``bool``. If True, apply Unicode IDNA - compatibility processing as described in Unicode Technical - Standard #46 (https://unicode.org/reports/tr46/). - If False, do not apply the mapping. The default is False. - - *transitional* is a ``bool``: If True, use the - "transitional" mode described in Unicode Technical Standard - #46. The default is False. - - *allow_pure_ascii* is a ``bool``. If True, then a label which - consists of only ASCII characters is allowed. This is less - strict than regular IDNA 2008, but is also necessary for mixed - names, e.g. a name with starting with "_sip._tcp." and ending - in an IDN suffix which would otherwise be disallowed. The - default is False. - - *strict_decode* is a ``bool``: If True, then IDNA2008 checking - is done when decoding. This can cause failures if the name - was encoded with IDNA2003. The default is False. - """ - super().__init__() - self.uts_46 = uts_46 - self.transitional = transitional - self.allow_pure_ascii = allow_pure_ascii - self.strict_decode = strict_decode - - def encode(self, label: str) -> bytes: - if label == "": - return b"" - if self.allow_pure_ascii and is_all_ascii(label): - encoded = label.encode("ascii") - if len(encoded) > 63: - raise LabelTooLong - return encoded - if not have_idna_2008: - raise NoIDNA2008 - try: - if self.uts_46: - # pylint: disable=possibly-used-before-assignment - label = idna.uts46_remap(label, False, self.transitional) - return idna.alabel(label) - except idna.IDNAError as e: - if e.args[0] == "Label too long": - raise LabelTooLong - else: - raise IDNAException(idna_exception=e) - - def decode(self, label: bytes) -> str: - if not self.strict_decode: - return super().decode(label) - if label == b"": - return "" - if not have_idna_2008: - raise NoIDNA2008 - try: - ulabel = idna.ulabel(label) - if self.uts_46: - ulabel = idna.uts46_remap(ulabel, False, self.transitional) - return _escapify(ulabel) - except (idna.IDNAError, UnicodeError) as e: - raise IDNAException(idna_exception=e) - - -IDNA_2003_Practical = IDNA2003Codec(False) -IDNA_2003_Strict = IDNA2003Codec(True) -IDNA_2003 = IDNA_2003_Practical -IDNA_2008_Practical = IDNA2008Codec(True, False, True, False) -IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False) -IDNA_2008_Strict = IDNA2008Codec(False, False, False, True) -IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False) -IDNA_2008 = IDNA_2008_Practical - - -def _validate_labels(labels: Tuple[bytes, ...]) -> None: - """Check for empty labels in the middle of a label sequence, - labels that are too long, and for too many labels. - - Raises ``dns.name.NameTooLong`` if the name as a whole is too long. - - Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root - label) and appears in a position other than the end of the label - sequence - - """ - - l = len(labels) - total = 0 - i = -1 - j = 0 - for label in labels: - ll = len(label) - total += ll + 1 - if ll > 63: - raise LabelTooLong - if i < 0 and label == b"": - i = j - j += 1 - if total > 255: - raise NameTooLong - if i >= 0 and i != l - 1: - raise EmptyLabel - - -def _maybe_convert_to_binary(label: Union[bytes, str]) -> bytes: - """If label is ``str``, convert it to ``bytes``. If it is already - ``bytes`` just return it. - - """ - - if isinstance(label, bytes): - return label - if isinstance(label, str): - return label.encode() - raise ValueError # pragma: no cover - - -@dns.immutable.immutable -class Name: - """A DNS name. - - The dns.name.Name class represents a DNS name as a tuple of - labels. Each label is a ``bytes`` in DNS wire format. Instances - of the class are immutable. - """ - - __slots__ = ["labels"] - - def __init__(self, labels: Iterable[Union[bytes, str]]): - """*labels* is any iterable whose values are ``str`` or ``bytes``.""" - - blabels = [_maybe_convert_to_binary(x) for x in labels] - self.labels = tuple(blabels) - _validate_labels(self.labels) - - def __copy__(self): - return Name(self.labels) - - def __deepcopy__(self, memo): - return Name(copy.deepcopy(self.labels, memo)) - - def __getstate__(self): - # Names can be pickled - return {"labels": self.labels} - - def __setstate__(self, state): - super().__setattr__("labels", state["labels"]) - _validate_labels(self.labels) - - def is_absolute(self) -> bool: - """Is the most significant label of this name the root label? - - Returns a ``bool``. - """ - - return len(self.labels) > 0 and self.labels[-1] == b"" - - def is_wild(self) -> bool: - """Is this name wild? (I.e. Is the least significant label '*'?) - - Returns a ``bool``. - """ - - return len(self.labels) > 0 and self.labels[0] == b"*" - - def __hash__(self) -> int: - """Return a case-insensitive hash of the name. - - Returns an ``int``. - """ - - h = 0 - for label in self.labels: - for c in label.lower(): - h += (h << 3) + c - return h - - def fullcompare(self, other: "Name") -> Tuple[NameRelation, int, int]: - """Compare two names, returning a 3-tuple - ``(relation, order, nlabels)``. - - *relation* describes the relation ship between the names, - and is one of: ``dns.name.NameRelation.NONE``, - ``dns.name.NameRelation.SUPERDOMAIN``, ``dns.name.NameRelation.SUBDOMAIN``, - ``dns.name.NameRelation.EQUAL``, or ``dns.name.NameRelation.COMMONANCESTOR``. - - *order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and == - 0 if *self* == *other*. A relative name is always less than an - absolute name. If both names have the same relativity, then - the DNSSEC order relation is used to order them. - - *nlabels* is the number of significant labels that the two names - have in common. - - Here are some examples. Names ending in "." are absolute names, - those not ending in "." are relative names. - - ============= ============= =========== ===== ======= - self other relation order nlabels - ============= ============= =========== ===== ======= - www.example. www.example. equal 0 3 - www.example. example. subdomain > 0 2 - example. www.example. superdomain < 0 2 - example1.com. example2.com. common anc. < 0 2 - example1 example2. none < 0 0 - example1. example2 none > 0 0 - ============= ============= =========== ===== ======= - """ - - sabs = self.is_absolute() - oabs = other.is_absolute() - if sabs != oabs: - if sabs: - return (NameRelation.NONE, 1, 0) - else: - return (NameRelation.NONE, -1, 0) - l1 = len(self.labels) - l2 = len(other.labels) - ldiff = l1 - l2 - if ldiff < 0: - l = l1 - else: - l = l2 - - order = 0 - nlabels = 0 - namereln = NameRelation.NONE - while l > 0: - l -= 1 - l1 -= 1 - l2 -= 1 - label1 = self.labels[l1].lower() - label2 = other.labels[l2].lower() - if label1 < label2: - order = -1 - if nlabels > 0: - namereln = NameRelation.COMMONANCESTOR - return (namereln, order, nlabels) - elif label1 > label2: - order = 1 - if nlabels > 0: - namereln = NameRelation.COMMONANCESTOR - return (namereln, order, nlabels) - nlabels += 1 - order = ldiff - if ldiff < 0: - namereln = NameRelation.SUPERDOMAIN - elif ldiff > 0: - namereln = NameRelation.SUBDOMAIN - else: - namereln = NameRelation.EQUAL - return (namereln, order, nlabels) - - def is_subdomain(self, other: "Name") -> bool: - """Is self a subdomain of other? - - Note that the notion of subdomain includes equality, e.g. - "dnspython.org" is a subdomain of itself. - - Returns a ``bool``. - """ - - (nr, _, _) = self.fullcompare(other) - if nr == NameRelation.SUBDOMAIN or nr == NameRelation.EQUAL: - return True - return False - - def is_superdomain(self, other: "Name") -> bool: - """Is self a superdomain of other? - - Note that the notion of superdomain includes equality, e.g. - "dnspython.org" is a superdomain of itself. - - Returns a ``bool``. - """ - - (nr, _, _) = self.fullcompare(other) - if nr == NameRelation.SUPERDOMAIN or nr == NameRelation.EQUAL: - return True - return False - - def canonicalize(self) -> "Name": - """Return a name which is equal to the current name, but is in - DNSSEC canonical form. - """ - - return Name([x.lower() for x in self.labels]) - - def __eq__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] == 0 - else: - return False - - def __ne__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] != 0 - else: - return True - - def __lt__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] < 0 - else: - return NotImplemented - - def __le__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] <= 0 - else: - return NotImplemented - - def __ge__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] >= 0 - else: - return NotImplemented - - def __gt__(self, other): - if isinstance(other, Name): - return self.fullcompare(other)[1] > 0 - else: - return NotImplemented - - def __repr__(self): - return "" - - def __str__(self): - return self.to_text(False) - - def to_text(self, omit_final_dot: bool = False) -> str: - """Convert name to DNS text format. - - *omit_final_dot* is a ``bool``. If True, don't emit the final - dot (denoting the root label) for absolute names. The default - is False. - - Returns a ``str``. - """ - - if len(self.labels) == 0: - return "@" - if len(self.labels) == 1 and self.labels[0] == b"": - return "." - if omit_final_dot and self.is_absolute(): - l = self.labels[:-1] - else: - l = self.labels - s = ".".join(map(_escapify, l)) - return s - - def to_unicode( - self, omit_final_dot: bool = False, idna_codec: Optional[IDNACodec] = None - ) -> str: - """Convert name to Unicode text format. - - IDN ACE labels are converted to Unicode. - - *omit_final_dot* is a ``bool``. If True, don't emit the final - dot (denoting the root label) for absolute names. The default - is False. - *idna_codec* specifies the IDNA encoder/decoder. If None, the - dns.name.IDNA_2003_Practical encoder/decoder is used. - The IDNA_2003_Practical decoder does - not impose any policy, it just decodes punycode, so if you - don't want checking for compliance, you can use this decoder - for IDNA2008 as well. - - Returns a ``str``. - """ - - if len(self.labels) == 0: - return "@" - if len(self.labels) == 1 and self.labels[0] == b"": - return "." - if omit_final_dot and self.is_absolute(): - l = self.labels[:-1] - else: - l = self.labels - if idna_codec is None: - idna_codec = IDNA_2003_Practical - return ".".join([idna_codec.decode(x) for x in l]) - - def to_digestable(self, origin: Optional["Name"] = None) -> bytes: - """Convert name to a format suitable for digesting in hashes. - - The name is canonicalized and converted to uncompressed wire - format. All names in wire format are absolute. If the name - is a relative name, then an origin must be supplied. - - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then origin will be appended - to the name. - - Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is - relative and no origin was provided. - - Returns a ``bytes``. - """ - - digest = self.to_wire(origin=origin, canonicalize=True) - assert digest is not None - return digest - - def to_wire( - self, - file: Optional[Any] = None, - compress: Optional[CompressType] = None, - origin: Optional["Name"] = None, - canonicalize: bool = False, - ) -> Optional[bytes]: - """Convert name to wire format, possibly compressing it. - - *file* is the file where the name is emitted (typically an - io.BytesIO file). If ``None`` (the default), a ``bytes`` - containing the wire name will be returned. - - *compress*, a ``dict``, is the compression table to use. If - ``None`` (the default), names will not be compressed. Note that - the compression code assumes that compression offset 0 is the - start of *file*, and thus compression will not be correct - if this is not the case. - - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then *origin* will be appended - to it. - - *canonicalize*, a ``bool``, indicates whether the name should - be canonicalized; that is, converted to a format suitable for - digesting in hashes. - - Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is - relative and no origin was provided. - - Returns a ``bytes`` or ``None``. - """ - - if file is None: - out = bytearray() - for label in self.labels: - out.append(len(label)) - if canonicalize: - out += label.lower() - else: - out += label - if not self.is_absolute(): - if origin is None or not origin.is_absolute(): - raise NeedAbsoluteNameOrOrigin - for label in origin.labels: - out.append(len(label)) - if canonicalize: - out += label.lower() - else: - out += label - return bytes(out) - - labels: Iterable[bytes] - if not self.is_absolute(): - if origin is None or not origin.is_absolute(): - raise NeedAbsoluteNameOrOrigin - labels = list(self.labels) - labels.extend(list(origin.labels)) - else: - labels = self.labels - i = 0 - for label in labels: - n = Name(labels[i:]) - i += 1 - if compress is not None: - pos = compress.get(n) - else: - pos = None - if pos is not None: - value = 0xC000 + pos - s = struct.pack("!H", value) - file.write(s) - break - else: - if compress is not None and len(n) > 1: - pos = file.tell() - if pos <= 0x3FFF: - compress[n] = pos - l = len(label) - file.write(struct.pack("!B", l)) - if l > 0: - if canonicalize: - file.write(label.lower()) - else: - file.write(label) - return None - - def __len__(self) -> int: - """The length of the name (in labels). - - Returns an ``int``. - """ - - return len(self.labels) - - def __getitem__(self, index): - return self.labels[index] - - def __add__(self, other): - return self.concatenate(other) - - def __sub__(self, other): - return self.relativize(other) - - def split(self, depth: int) -> Tuple["Name", "Name"]: - """Split a name into a prefix and suffix names at the specified depth. - - *depth* is an ``int`` specifying the number of labels in the suffix - - Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the - name. - - Returns the tuple ``(prefix, suffix)``. - """ - - l = len(self.labels) - if depth == 0: - return (self, dns.name.empty) - elif depth == l: - return (dns.name.empty, self) - elif depth < 0 or depth > l: - raise ValueError("depth must be >= 0 and <= the length of the name") - return (Name(self[:-depth]), Name(self[-depth:])) - - def concatenate(self, other: "Name") -> "Name": - """Return a new name which is the concatenation of self and other. - - Raises ``dns.name.AbsoluteConcatenation`` if the name is - absolute and *other* is not the empty name. - - Returns a ``dns.name.Name``. - """ - - if self.is_absolute() and len(other) > 0: - raise AbsoluteConcatenation - labels = list(self.labels) - labels.extend(list(other.labels)) - return Name(labels) - - def relativize(self, origin: "Name") -> "Name": - """If the name is a subdomain of *origin*, return a new name which is - the name relative to origin. Otherwise return the name. - - For example, relativizing ``www.dnspython.org.`` to origin - ``dnspython.org.`` returns the name ``www``. Relativizing ``example.`` - to origin ``dnspython.org.`` returns ``example.``. - - Returns a ``dns.name.Name``. - """ - - if origin is not None and self.is_subdomain(origin): - return Name(self[: -len(origin)]) - else: - return self - - def derelativize(self, origin: "Name") -> "Name": - """If the name is a relative name, return a new name which is the - concatenation of the name and origin. Otherwise return the name. - - For example, derelativizing ``www`` to origin ``dnspython.org.`` - returns the name ``www.dnspython.org.``. Derelativizing ``example.`` - to origin ``dnspython.org.`` returns ``example.``. - - Returns a ``dns.name.Name``. - """ - - if not self.is_absolute(): - return self.concatenate(origin) - else: - return self - - def choose_relativity( - self, origin: Optional["Name"] = None, relativize: bool = True - ) -> "Name": - """Return a name with the relativity desired by the caller. - - If *origin* is ``None``, then the name is returned. - Otherwise, if *relativize* is ``True`` the name is - relativized, and if *relativize* is ``False`` the name is - derelativized. - - Returns a ``dns.name.Name``. - """ - - if origin: - if relativize: - return self.relativize(origin) - else: - return self.derelativize(origin) - else: - return self - - def parent(self) -> "Name": - """Return the parent of the name. - - For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``. - - Raises ``dns.name.NoParent`` if the name is either the root name or the - empty name, and thus has no parent. - - Returns a ``dns.name.Name``. - """ - - if self == root or self == empty: - raise NoParent - return Name(self.labels[1:]) - - def predecessor(self, origin: "Name", prefix_ok: bool = True) -> "Name": - """Return the maximal predecessor of *name* in the DNSSEC ordering in the zone - whose origin is *origin*, or return the longest name under *origin* if the - name is origin (i.e. wrap around to the longest name, which may still be - *origin* due to length considerations. - - The relativity of the name is preserved, so if this name is relative - then the method will return a relative name, and likewise if this name - is absolute then the predecessor will be absolute. - - *prefix_ok* indicates if prefixing labels is allowed, and - defaults to ``True``. Normally it is good to allow this, but if computing - a maximal predecessor at a zone cut point then ``False`` must be specified. - """ - return _handle_relativity_and_call( - _absolute_predecessor, self, origin, prefix_ok - ) - - def successor(self, origin: "Name", prefix_ok: bool = True) -> "Name": - """Return the minimal successor of *name* in the DNSSEC ordering in the zone - whose origin is *origin*, or return *origin* if the successor cannot be - computed due to name length limitations. - - Note that *origin* is returned in the "too long" cases because wrapping - around to the origin is how NSEC records express "end of the zone". - - The relativity of the name is preserved, so if this name is relative - then the method will return a relative name, and likewise if this name - is absolute then the successor will be absolute. - - *prefix_ok* indicates if prefixing a new minimal label is allowed, and - defaults to ``True``. Normally it is good to allow this, but if computing - a minimal successor at a zone cut point then ``False`` must be specified. - """ - return _handle_relativity_and_call(_absolute_successor, self, origin, prefix_ok) - - -#: The root name, '.' -root = Name([b""]) - -#: The empty name. -empty = Name([]) - - -def from_unicode( - text: str, origin: Optional[Name] = root, idna_codec: Optional[IDNACodec] = None -) -> Name: - """Convert unicode text into a Name object. - - Labels are encoded in IDN ACE form according to rules specified by - the IDNA codec. - - *text*, a ``str``, is the text to convert into a name. - - *origin*, a ``dns.name.Name``, specifies the origin to - append to non-absolute names. The default is the root name. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Returns a ``dns.name.Name``. - """ - - if not isinstance(text, str): - raise ValueError("input to from_unicode() must be a unicode string") - if not (origin is None or isinstance(origin, Name)): - raise ValueError("origin must be a Name or None") - labels = [] - label = "" - escaping = False - edigits = 0 - total = 0 - if idna_codec is None: - idna_codec = IDNA_2003 - if text == "@": - text = "" - if text: - if text in [".", "\u3002", "\uff0e", "\uff61"]: - return Name([b""]) # no Unicode "u" on this constant! - for c in text: - if escaping: - if edigits == 0: - if c.isdigit(): - total = int(c) - edigits += 1 - else: - label += c - escaping = False - else: - if not c.isdigit(): - raise BadEscape - total *= 10 - total += int(c) - edigits += 1 - if edigits == 3: - escaping = False - label += chr(total) - elif c in [".", "\u3002", "\uff0e", "\uff61"]: - if len(label) == 0: - raise EmptyLabel - labels.append(idna_codec.encode(label)) - label = "" - elif c == "\\": - escaping = True - edigits = 0 - total = 0 - else: - label += c - if escaping: - raise BadEscape - if len(label) > 0: - labels.append(idna_codec.encode(label)) - else: - labels.append(b"") - - if (len(labels) == 0 or labels[-1] != b"") and origin is not None: - labels.extend(list(origin.labels)) - return Name(labels) - - -def is_all_ascii(text: str) -> bool: - for c in text: - if ord(c) > 0x7F: - return False - return True - - -def from_text( - text: Union[bytes, str], - origin: Optional[Name] = root, - idna_codec: Optional[IDNACodec] = None, -) -> Name: - """Convert text into a Name object. - - *text*, a ``bytes`` or ``str``, is the text to convert into a name. - - *origin*, a ``dns.name.Name``, specifies the origin to - append to non-absolute names. The default is the root name. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - Returns a ``dns.name.Name``. - """ - - if isinstance(text, str): - if not is_all_ascii(text): - # Some codepoint in the input text is > 127, so IDNA applies. - return from_unicode(text, origin, idna_codec) - # The input is all ASCII, so treat this like an ordinary non-IDNA - # domain name. Note that "all ASCII" is about the input text, - # not the codepoints in the domain name. E.g. if text has value - # - # r'\150\151\152\153\154\155\156\157\158\159' - # - # then it's still "all ASCII" even though the domain name has - # codepoints > 127. - text = text.encode("ascii") - if not isinstance(text, bytes): - raise ValueError("input to from_text() must be a string") - if not (origin is None or isinstance(origin, Name)): - raise ValueError("origin must be a Name or None") - labels = [] - label = b"" - escaping = False - edigits = 0 - total = 0 - if text == b"@": - text = b"" - if text: - if text == b".": - return Name([b""]) - for c in text: - byte_ = struct.pack("!B", c) - if escaping: - if edigits == 0: - if byte_.isdigit(): - total = int(byte_) - edigits += 1 - else: - label += byte_ - escaping = False - else: - if not byte_.isdigit(): - raise BadEscape - total *= 10 - total += int(byte_) - edigits += 1 - if edigits == 3: - escaping = False - label += struct.pack("!B", total) - elif byte_ == b".": - if len(label) == 0: - raise EmptyLabel - labels.append(label) - label = b"" - elif byte_ == b"\\": - escaping = True - edigits = 0 - total = 0 - else: - label += byte_ - if escaping: - raise BadEscape - if len(label) > 0: - labels.append(label) - else: - labels.append(b"") - if (len(labels) == 0 or labels[-1] != b"") and origin is not None: - labels.extend(list(origin.labels)) - return Name(labels) - - -# we need 'dns.wire.Parser' quoted as dns.name and dns.wire depend on each other. - - -def from_wire_parser(parser: "dns.wire.Parser") -> Name: - """Convert possibly compressed wire format into a Name. - - *parser* is a dns.wire.Parser. - - Raises ``dns.name.BadPointer`` if a compression pointer did not - point backwards in the message. - - Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. - - Returns a ``dns.name.Name`` - """ - - labels = [] - biggest_pointer = parser.current - with parser.restore_furthest(): - count = parser.get_uint8() - while count != 0: - if count < 64: - labels.append(parser.get_bytes(count)) - elif count >= 192: - current = (count & 0x3F) * 256 + parser.get_uint8() - if current >= biggest_pointer: - raise BadPointer - biggest_pointer = current - parser.seek(current) - else: - raise BadLabelType - count = parser.get_uint8() - labels.append(b"") - return Name(labels) - - -def from_wire(message: bytes, current: int) -> Tuple[Name, int]: - """Convert possibly compressed wire format into a Name. - - *message* is a ``bytes`` containing an entire DNS message in DNS - wire form. - - *current*, an ``int``, is the offset of the beginning of the name - from the start of the message - - Raises ``dns.name.BadPointer`` if a compression pointer did not - point backwards in the message. - - Raises ``dns.name.BadLabelType`` if an invalid label type was encountered. - - Returns a ``(dns.name.Name, int)`` tuple consisting of the name - that was read and the number of bytes of the wire format message - which were consumed reading it. - """ - - if not isinstance(message, bytes): - raise ValueError("input to from_wire() must be a byte string") - parser = dns.wire.Parser(message, current) - name = from_wire_parser(parser) - return (name, parser.current - current) - - -# RFC 4471 Support - -_MINIMAL_OCTET = b"\x00" -_MINIMAL_OCTET_VALUE = ord(_MINIMAL_OCTET) -_SUCCESSOR_PREFIX = Name([_MINIMAL_OCTET]) -_MAXIMAL_OCTET = b"\xff" -_MAXIMAL_OCTET_VALUE = ord(_MAXIMAL_OCTET) -_AT_SIGN_VALUE = ord("@") -_LEFT_SQUARE_BRACKET_VALUE = ord("[") - - -def _wire_length(labels): - return functools.reduce(lambda v, x: v + len(x) + 1, labels, 0) - - -def _pad_to_max_name(name): - needed = 255 - _wire_length(name.labels) - new_labels = [] - while needed > 64: - new_labels.append(_MAXIMAL_OCTET * 63) - needed -= 64 - if needed >= 2: - new_labels.append(_MAXIMAL_OCTET * (needed - 1)) - # Note we're already maximal in the needed == 1 case as while we'd like - # to add one more byte as a new label, we can't, as adding a new non-empty - # label requires at least 2 bytes. - new_labels = list(reversed(new_labels)) - new_labels.extend(name.labels) - return Name(new_labels) - - -def _pad_to_max_label(label, suffix_labels): - length = len(label) - # We have to subtract one here to account for the length byte of label. - remaining = 255 - _wire_length(suffix_labels) - length - 1 - if remaining <= 0: - # Shouldn't happen! - return label - needed = min(63 - length, remaining) - return label + _MAXIMAL_OCTET * needed - - -def _absolute_predecessor(name: Name, origin: Name, prefix_ok: bool) -> Name: - # This is the RFC 4471 predecessor algorithm using the "absolute method" of section - # 3.1.1. - # - # Our caller must ensure that the name and origin are absolute, and that name is a - # subdomain of origin. - if name == origin: - return _pad_to_max_name(name) - least_significant_label = name[0] - if least_significant_label == _MINIMAL_OCTET: - return name.parent() - least_octet = least_significant_label[-1] - suffix_labels = name.labels[1:] - if least_octet == _MINIMAL_OCTET_VALUE: - new_labels = [least_significant_label[:-1]] - else: - octets = bytearray(least_significant_label) - octet = octets[-1] - if octet == _LEFT_SQUARE_BRACKET_VALUE: - octet = _AT_SIGN_VALUE - else: - octet -= 1 - octets[-1] = octet - least_significant_label = bytes(octets) - new_labels = [_pad_to_max_label(least_significant_label, suffix_labels)] - new_labels.extend(suffix_labels) - name = Name(new_labels) - if prefix_ok: - return _pad_to_max_name(name) - else: - return name - - -def _absolute_successor(name: Name, origin: Name, prefix_ok: bool) -> Name: - # This is the RFC 4471 successor algorithm using the "absolute method" of section - # 3.1.2. - # - # Our caller must ensure that the name and origin are absolute, and that name is a - # subdomain of origin. - if prefix_ok: - # Try prefixing \000 as new label - try: - return _SUCCESSOR_PREFIX.concatenate(name) - except NameTooLong: - pass - while name != origin: - # Try extending the least significant label. - least_significant_label = name[0] - if len(least_significant_label) < 63: - # We may be able to extend the least label with a minimal additional byte. - # This is only "may" because we could have a maximal length name even though - # the least significant label isn't maximally long. - new_labels = [least_significant_label + _MINIMAL_OCTET] - new_labels.extend(name.labels[1:]) - try: - return dns.name.Name(new_labels) - except dns.name.NameTooLong: - pass - # We can't extend the label either, so we'll try to increment the least - # signficant non-maximal byte in it. - octets = bytearray(least_significant_label) - # We do this reversed iteration with an explicit indexing variable because - # if we find something to increment, we're going to want to truncate everything - # to the right of it. - for i in range(len(octets) - 1, -1, -1): - octet = octets[i] - if octet == _MAXIMAL_OCTET_VALUE: - # We can't increment this, so keep looking. - continue - # Finally, something we can increment. We have to apply a special rule for - # incrementing "@", sending it to "[", because RFC 4034 6.1 says that when - # comparing names, uppercase letters compare as if they were their - # lower-case equivalents. If we increment "@" to "A", then it would compare - # as "a", which is after "[", "\", "]", "^", "_", and "`", so we would have - # skipped the most minimal successor, namely "[". - if octet == _AT_SIGN_VALUE: - octet = _LEFT_SQUARE_BRACKET_VALUE - else: - octet += 1 - octets[i] = octet - # We can now truncate all of the maximal values we skipped (if any) - new_labels = [bytes(octets[: i + 1])] - new_labels.extend(name.labels[1:]) - # We haven't changed the length of the name, so the Name constructor will - # always work. - return Name(new_labels) - # We couldn't increment, so chop off the least significant label and try - # again. - name = name.parent() - - # We couldn't increment at all, so return the origin, as wrapping around is the - # DNSSEC way. - return origin - - -def _handle_relativity_and_call( - function: Callable[[Name, Name, bool], Name], - name: Name, - origin: Name, - prefix_ok: bool, -) -> Name: - # Make "name" absolute if needed, ensure that the origin is absolute, - # call function(), and then relativize the result if needed. - if not origin.is_absolute(): - raise NeedAbsoluteNameOrOrigin - relative = not name.is_absolute() - if relative: - name = name.derelativize(origin) - elif not name.is_subdomain(origin): - raise NeedSubdomainOfOrigin - result_name = function(name, origin, prefix_ok) - if relative: - result_name = result_name.relativize(origin) - return result_name diff --git a/backend/venv39/lib/python3.9/site-packages/dns/namedict.py b/backend/venv39/lib/python3.9/site-packages/dns/namedict.py deleted file mode 100644 index ca8b197..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/namedict.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# Copyright (C) 2016 Coresec Systems AB -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL -# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC -# SYSTEMS AB BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS name dictionary""" - -# pylint seems to be confused about this one! -from collections.abc import MutableMapping # pylint: disable=no-name-in-module - -import dns.name - - -class NameDict(MutableMapping): - """A dictionary whose keys are dns.name.Name objects. - - In addition to being like a regular Python dictionary, this - dictionary can also get the deepest match for a given key. - """ - - __slots__ = ["max_depth", "max_depth_items", "__store"] - - def __init__(self, *args, **kwargs): - super().__init__() - self.__store = dict() - #: the maximum depth of the keys that have ever been added - self.max_depth = 0 - #: the number of items of maximum depth - self.max_depth_items = 0 - self.update(dict(*args, **kwargs)) - - def __update_max_depth(self, key): - if len(key) == self.max_depth: - self.max_depth_items = self.max_depth_items + 1 - elif len(key) > self.max_depth: - self.max_depth = len(key) - self.max_depth_items = 1 - - def __getitem__(self, key): - return self.__store[key] - - def __setitem__(self, key, value): - if not isinstance(key, dns.name.Name): - raise ValueError("NameDict key must be a name") - self.__store[key] = value - self.__update_max_depth(key) - - def __delitem__(self, key): - self.__store.pop(key) - if len(key) == self.max_depth: - self.max_depth_items = self.max_depth_items - 1 - if self.max_depth_items == 0: - self.max_depth = 0 - for k in self.__store: - self.__update_max_depth(k) - - def __iter__(self): - return iter(self.__store) - - def __len__(self): - return len(self.__store) - - def has_key(self, key): - return key in self.__store - - def get_deepest_match(self, name): - """Find the deepest match to *name* in the dictionary. - - The deepest match is the longest name in the dictionary which is - a superdomain of *name*. Note that *superdomain* includes matching - *name* itself. - - *name*, a ``dns.name.Name``, the name to find. - - Returns a ``(key, value)`` where *key* is the deepest - ``dns.name.Name``, and *value* is the value associated with *key*. - """ - - depth = len(name) - if depth > self.max_depth: - depth = self.max_depth - for i in range(-depth, 0): - n = dns.name.Name(name[i:]) - if n in self: - return (n, self[n]) - v = self[dns.name.empty] - return (dns.name.empty, v) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/nameserver.py b/backend/venv39/lib/python3.9/site-packages/dns/nameserver.py deleted file mode 100644 index b02a239..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/nameserver.py +++ /dev/null @@ -1,363 +0,0 @@ -from typing import Optional, Union -from urllib.parse import urlparse - -import dns.asyncbackend -import dns.asyncquery -import dns.inet -import dns.message -import dns.query - - -class Nameserver: - def __init__(self): - pass - - def __str__(self): - raise NotImplementedError - - def kind(self) -> str: - raise NotImplementedError - - def is_always_max_size(self) -> bool: - raise NotImplementedError - - def answer_nameserver(self) -> str: - raise NotImplementedError - - def answer_port(self) -> int: - raise NotImplementedError - - def query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - raise NotImplementedError - - async def async_query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - backend: dns.asyncbackend.Backend, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - raise NotImplementedError - - -class AddressAndPortNameserver(Nameserver): - def __init__(self, address: str, port: int): - super().__init__() - self.address = address - self.port = port - - def kind(self) -> str: - raise NotImplementedError - - def is_always_max_size(self) -> bool: - return False - - def __str__(self): - ns_kind = self.kind() - return f"{ns_kind}:{self.address}@{self.port}" - - def answer_nameserver(self) -> str: - return self.address - - def answer_port(self) -> int: - return self.port - - -class Do53Nameserver(AddressAndPortNameserver): - def __init__(self, address: str, port: int = 53): - super().__init__(address, port) - - def kind(self): - return "Do53" - - def query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - if max_size: - response = dns.query.tcp( - request, - self.address, - timeout=timeout, - port=self.port, - source=source, - source_port=source_port, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - else: - response = dns.query.udp( - request, - self.address, - timeout=timeout, - port=self.port, - source=source, - source_port=source_port, - raise_on_truncation=True, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ignore_errors=True, - ignore_unexpected=True, - ) - return response - - async def async_query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - backend: dns.asyncbackend.Backend, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - if max_size: - response = await dns.asyncquery.tcp( - request, - self.address, - timeout=timeout, - port=self.port, - source=source, - source_port=source_port, - backend=backend, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - else: - response = await dns.asyncquery.udp( - request, - self.address, - timeout=timeout, - port=self.port, - source=source, - source_port=source_port, - raise_on_truncation=True, - backend=backend, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ignore_errors=True, - ignore_unexpected=True, - ) - return response - - -class DoHNameserver(Nameserver): - def __init__( - self, - url: str, - bootstrap_address: Optional[str] = None, - verify: Union[bool, str] = True, - want_get: bool = False, - http_version: dns.query.HTTPVersion = dns.query.HTTPVersion.DEFAULT, - ): - super().__init__() - self.url = url - self.bootstrap_address = bootstrap_address - self.verify = verify - self.want_get = want_get - self.http_version = http_version - - def kind(self): - return "DoH" - - def is_always_max_size(self) -> bool: - return True - - def __str__(self): - return self.url - - def answer_nameserver(self) -> str: - return self.url - - def answer_port(self) -> int: - port = urlparse(self.url).port - if port is None: - port = 443 - return port - - def query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return dns.query.https( - request, - self.url, - timeout=timeout, - source=source, - source_port=source_port, - bootstrap_address=self.bootstrap_address, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - verify=self.verify, - post=(not self.want_get), - http_version=self.http_version, - ) - - async def async_query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - backend: dns.asyncbackend.Backend, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return await dns.asyncquery.https( - request, - self.url, - timeout=timeout, - source=source, - source_port=source_port, - bootstrap_address=self.bootstrap_address, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - verify=self.verify, - post=(not self.want_get), - http_version=self.http_version, - ) - - -class DoTNameserver(AddressAndPortNameserver): - def __init__( - self, - address: str, - port: int = 853, - hostname: Optional[str] = None, - verify: Union[bool, str] = True, - ): - super().__init__(address, port) - self.hostname = hostname - self.verify = verify - - def kind(self): - return "DoT" - - def query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return dns.query.tls( - request, - self.address, - port=self.port, - timeout=timeout, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - server_hostname=self.hostname, - verify=self.verify, - ) - - async def async_query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - backend: dns.asyncbackend.Backend, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return await dns.asyncquery.tls( - request, - self.address, - port=self.port, - timeout=timeout, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - server_hostname=self.hostname, - verify=self.verify, - ) - - -class DoQNameserver(AddressAndPortNameserver): - def __init__( - self, - address: str, - port: int = 853, - verify: Union[bool, str] = True, - server_hostname: Optional[str] = None, - ): - super().__init__(address, port) - self.verify = verify - self.server_hostname = server_hostname - - def kind(self): - return "DoQ" - - def query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return dns.query.quic( - request, - self.address, - port=self.port, - timeout=timeout, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - verify=self.verify, - server_hostname=self.server_hostname, - ) - - async def async_query( - self, - request: dns.message.QueryMessage, - timeout: float, - source: Optional[str], - source_port: int, - max_size: bool, - backend: dns.asyncbackend.Backend, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - ) -> dns.message.Message: - return await dns.asyncquery.quic( - request, - self.address, - port=self.port, - timeout=timeout, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - verify=self.verify, - server_hostname=self.server_hostname, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/node.py b/backend/venv39/lib/python3.9/site-packages/dns/node.py deleted file mode 100644 index de85a82..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/node.py +++ /dev/null @@ -1,359 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS nodes. A node is a set of rdatasets.""" - -import enum -import io -from typing import Any, Dict, Optional - -import dns.immutable -import dns.name -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.renderer -import dns.rrset - -_cname_types = { - dns.rdatatype.CNAME, -} - -# "neutral" types can coexist with a CNAME and thus are not "other data" -_neutral_types = { - dns.rdatatype.NSEC, # RFC 4035 section 2.5 - dns.rdatatype.NSEC3, # This is not likely to happen, but not impossible! - dns.rdatatype.KEY, # RFC 4035 section 2.5, RFC 3007 -} - - -def _matches_type_or_its_signature(rdtypes, rdtype, covers): - return rdtype in rdtypes or (rdtype == dns.rdatatype.RRSIG and covers in rdtypes) - - -@enum.unique -class NodeKind(enum.Enum): - """Rdatasets in nodes""" - - REGULAR = 0 # a.k.a "other data" - NEUTRAL = 1 - CNAME = 2 - - @classmethod - def classify( - cls, rdtype: dns.rdatatype.RdataType, covers: dns.rdatatype.RdataType - ) -> "NodeKind": - if _matches_type_or_its_signature(_cname_types, rdtype, covers): - return NodeKind.CNAME - elif _matches_type_or_its_signature(_neutral_types, rdtype, covers): - return NodeKind.NEUTRAL - else: - return NodeKind.REGULAR - - @classmethod - def classify_rdataset(cls, rdataset: dns.rdataset.Rdataset) -> "NodeKind": - return cls.classify(rdataset.rdtype, rdataset.covers) - - -class Node: - """A Node is a set of rdatasets. - - A node is either a CNAME node or an "other data" node. A CNAME - node contains only CNAME, KEY, NSEC, and NSEC3 rdatasets along with their - covering RRSIG rdatasets. An "other data" node contains any - rdataset other than a CNAME or RRSIG(CNAME) rdataset. When - changes are made to a node, the CNAME or "other data" state is - always consistent with the update, i.e. the most recent change - wins. For example, if you have a node which contains a CNAME - rdataset, and then add an MX rdataset to it, then the CNAME - rdataset will be deleted. Likewise if you have a node containing - an MX rdataset and add a CNAME rdataset, the MX rdataset will be - deleted. - """ - - __slots__ = ["rdatasets"] - - def __init__(self): - # the set of rdatasets, represented as a list. - self.rdatasets = [] - - def to_text(self, name: dns.name.Name, **kw: Dict[str, Any]) -> str: - """Convert a node to text format. - - Each rdataset at the node is printed. Any keyword arguments - to this method are passed on to the rdataset's to_text() method. - - *name*, a ``dns.name.Name``, the owner name of the - rdatasets. - - Returns a ``str``. - - """ - - s = io.StringIO() - for rds in self.rdatasets: - if len(rds) > 0: - s.write(rds.to_text(name, **kw)) # type: ignore[arg-type] - s.write("\n") - return s.getvalue()[:-1] - - def __repr__(self): - return "" - - def __eq__(self, other): - # - # This is inefficient. Good thing we don't need to do it much. - # - for rd in self.rdatasets: - if rd not in other.rdatasets: - return False - for rd in other.rdatasets: - if rd not in self.rdatasets: - return False - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __len__(self): - return len(self.rdatasets) - - def __iter__(self): - return iter(self.rdatasets) - - def _append_rdataset(self, rdataset): - """Append rdataset to the node with special handling for CNAME and - other data conditions. - - Specifically, if the rdataset being appended has ``NodeKind.CNAME``, - then all rdatasets other than KEY, NSEC, NSEC3, and their covering - RRSIGs are deleted. If the rdataset being appended has - ``NodeKind.REGULAR`` then CNAME and RRSIG(CNAME) are deleted. - """ - # Make having just one rdataset at the node fast. - if len(self.rdatasets) > 0: - kind = NodeKind.classify_rdataset(rdataset) - if kind == NodeKind.CNAME: - self.rdatasets = [ - rds - for rds in self.rdatasets - if NodeKind.classify_rdataset(rds) != NodeKind.REGULAR - ] - elif kind == NodeKind.REGULAR: - self.rdatasets = [ - rds - for rds in self.rdatasets - if NodeKind.classify_rdataset(rds) != NodeKind.CNAME - ] - # Otherwise the rdataset is NodeKind.NEUTRAL and we do not need to - # edit self.rdatasets. - self.rdatasets.append(rdataset) - - def find_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> dns.rdataset.Rdataset: - """Find an rdataset matching the specified properties in the - current node. - - *rdclass*, a ``dns.rdataclass.RdataClass``, the class of the rdataset. - - *rdtype*, a ``dns.rdatatype.RdataType``, the type of the rdataset. - - *covers*, a ``dns.rdatatype.RdataType``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If True, create the rdataset if it is not found. - - Raises ``KeyError`` if an rdataset of the desired type and class does - not exist and *create* is not ``True``. - - Returns a ``dns.rdataset.Rdataset``. - """ - - for rds in self.rdatasets: - if rds.match(rdclass, rdtype, covers): - return rds - if not create: - raise KeyError - rds = dns.rdataset.Rdataset(rdclass, rdtype, covers) - self._append_rdataset(rds) - return rds - - def get_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> Optional[dns.rdataset.Rdataset]: - """Get an rdataset matching the specified properties in the - current node. - - None is returned if an rdataset of the specified type and - class does not exist and *create* is not ``True``. - - *rdclass*, an ``int``, the class of the rdataset. - - *rdtype*, an ``int``, the type of the rdataset. - - *covers*, an ``int``, the covered type. Usually this value is - dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or - dns.rdatatype.RRSIG, then the covers value will be the rdata - type the SIG/RRSIG covers. The library treats the SIG and RRSIG - types as if they were a family of - types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much - easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. - - *create*, a ``bool``. If True, create the rdataset if it is not found. - - Returns a ``dns.rdataset.Rdataset`` or ``None``. - """ - - try: - rds = self.find_rdataset(rdclass, rdtype, covers, create) - except KeyError: - rds = None - return rds - - def delete_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - ) -> None: - """Delete the rdataset matching the specified properties in the - current node. - - If a matching rdataset does not exist, it is not an error. - - *rdclass*, an ``int``, the class of the rdataset. - - *rdtype*, an ``int``, the type of the rdataset. - - *covers*, an ``int``, the covered type. - """ - - rds = self.get_rdataset(rdclass, rdtype, covers) - if rds is not None: - self.rdatasets.remove(rds) - - def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None: - """Replace an rdataset. - - It is not an error if there is no rdataset matching *replacement*. - - Ownership of the *replacement* object is transferred to the node; - in other words, this method does not store a copy of *replacement* - at the node, it stores *replacement* itself. - - *replacement*, a ``dns.rdataset.Rdataset``. - - Raises ``ValueError`` if *replacement* is not a - ``dns.rdataset.Rdataset``. - """ - - if not isinstance(replacement, dns.rdataset.Rdataset): - raise ValueError("replacement is not an rdataset") - if isinstance(replacement, dns.rrset.RRset): - # RRsets are not good replacements as the match() method - # is not compatible. - replacement = replacement.to_rdataset() - self.delete_rdataset( - replacement.rdclass, replacement.rdtype, replacement.covers - ) - self._append_rdataset(replacement) - - def classify(self) -> NodeKind: - """Classify a node. - - A node which contains a CNAME or RRSIG(CNAME) is a - ``NodeKind.CNAME`` node. - - A node which contains only "neutral" types, i.e. types allowed to - co-exist with a CNAME, is a ``NodeKind.NEUTRAL`` node. The neutral - types are NSEC, NSEC3, KEY, and their associated RRSIGS. An empty node - is also considered neutral. - - A node which contains some rdataset which is not a CNAME, RRSIG(CNAME), - or a neutral type is a a ``NodeKind.REGULAR`` node. Regular nodes are - also commonly referred to as "other data". - """ - for rdataset in self.rdatasets: - kind = NodeKind.classify(rdataset.rdtype, rdataset.covers) - if kind != NodeKind.NEUTRAL: - return kind - return NodeKind.NEUTRAL - - def is_immutable(self) -> bool: - return False - - -@dns.immutable.immutable -class ImmutableNode(Node): - def __init__(self, node): - super().__init__() - self.rdatasets = tuple( - [dns.rdataset.ImmutableRdataset(rds) for rds in node.rdatasets] - ) - - def find_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> dns.rdataset.Rdataset: - if create: - raise TypeError("immutable") - return super().find_rdataset(rdclass, rdtype, covers, False) - - def get_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> Optional[dns.rdataset.Rdataset]: - if create: - raise TypeError("immutable") - return super().get_rdataset(rdclass, rdtype, covers, False) - - def delete_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - ) -> None: - raise TypeError("immutable") - - def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None: - raise TypeError("immutable") - - def is_immutable(self) -> bool: - return True diff --git a/backend/venv39/lib/python3.9/site-packages/dns/opcode.py b/backend/venv39/lib/python3.9/site-packages/dns/opcode.py deleted file mode 100644 index 78b43d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/opcode.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Opcodes.""" - -import dns.enum -import dns.exception - - -class Opcode(dns.enum.IntEnum): - #: Query - QUERY = 0 - #: Inverse Query (historical) - IQUERY = 1 - #: Server Status (unspecified and unimplemented anywhere) - STATUS = 2 - #: Notify - NOTIFY = 4 - #: Dynamic Update - UPDATE = 5 - - @classmethod - def _maximum(cls): - return 15 - - @classmethod - def _unknown_exception_class(cls): - return UnknownOpcode - - -class UnknownOpcode(dns.exception.DNSException): - """An DNS opcode is unknown.""" - - -def from_text(text: str) -> Opcode: - """Convert text into an opcode. - - *text*, a ``str``, the textual opcode - - Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown. - - Returns an ``int``. - """ - - return Opcode.from_text(text) - - -def from_flags(flags: int) -> Opcode: - """Extract an opcode from DNS message flags. - - *flags*, an ``int``, the DNS flags. - - Returns an ``int``. - """ - - return Opcode((flags & 0x7800) >> 11) - - -def to_flags(value: Opcode) -> int: - """Convert an opcode to a value suitable for ORing into DNS message - flags. - - *value*, an ``int``, the DNS opcode value. - - Returns an ``int``. - """ - - return (value << 11) & 0x7800 - - -def to_text(value: Opcode) -> str: - """Convert an opcode to text. - - *value*, an ``int`` the opcode value, - - Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown. - - Returns a ``str``. - """ - - return Opcode.to_text(value) - - -def is_update(flags: int) -> bool: - """Is the opcode in flags UPDATE? - - *flags*, an ``int``, the DNS message flags. - - Returns a ``bool``. - """ - - return from_flags(flags) == Opcode.UPDATE - - -### BEGIN generated Opcode constants - -QUERY = Opcode.QUERY -IQUERY = Opcode.IQUERY -STATUS = Opcode.STATUS -NOTIFY = Opcode.NOTIFY -UPDATE = Opcode.UPDATE - -### END generated Opcode constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/py.typed b/backend/venv39/lib/python3.9/site-packages/dns/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/query.py b/backend/venv39/lib/python3.9/site-packages/dns/query.py deleted file mode 100644 index 0d8a977..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/query.py +++ /dev/null @@ -1,1665 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Talk to a DNS server.""" - -import base64 -import contextlib -import enum -import errno -import os -import os.path -import random -import selectors -import socket -import struct -import time -import urllib.parse -from typing import Any, Dict, Optional, Tuple, Union, cast - -import dns._features -import dns.exception -import dns.inet -import dns.message -import dns.name -import dns.quic -import dns.rcode -import dns.rdataclass -import dns.rdatatype -import dns.serial -import dns.transaction -import dns.tsig -import dns.xfr - - -def _remaining(expiration): - if expiration is None: - return None - timeout = expiration - time.time() - if timeout <= 0.0: - raise dns.exception.Timeout - return timeout - - -def _expiration_for_this_attempt(timeout, expiration): - if expiration is None: - return None - return min(time.time() + timeout, expiration) - - -_have_httpx = dns._features.have("doh") -if _have_httpx: - import httpcore._backends.sync - import httpx - - _CoreNetworkBackend = httpcore.NetworkBackend - _CoreSyncStream = httpcore._backends.sync.SyncStream - - class _NetworkBackend(_CoreNetworkBackend): - def __init__(self, resolver, local_port, bootstrap_address, family): - super().__init__() - self._local_port = local_port - self._resolver = resolver - self._bootstrap_address = bootstrap_address - self._family = family - - def connect_tcp( - self, host, port, timeout, local_address, socket_options=None - ): # pylint: disable=signature-differs - addresses = [] - _, expiration = _compute_times(timeout) - if dns.inet.is_address(host): - addresses.append(host) - elif self._bootstrap_address is not None: - addresses.append(self._bootstrap_address) - else: - timeout = _remaining(expiration) - family = self._family - if local_address: - family = dns.inet.af_for_address(local_address) - answers = self._resolver.resolve_name( - host, family=family, lifetime=timeout - ) - addresses = answers.addresses() - for address in addresses: - af = dns.inet.af_for_address(address) - if local_address is not None or self._local_port != 0: - source = dns.inet.low_level_address_tuple( - (local_address, self._local_port), af - ) - else: - source = None - sock = _make_socket(af, socket.SOCK_STREAM, source) - attempt_expiration = _expiration_for_this_attempt(2.0, expiration) - try: - _connect( - sock, - dns.inet.low_level_address_tuple((address, port), af), - attempt_expiration, - ) - return _CoreSyncStream(sock) - except Exception: - pass - raise httpcore.ConnectError - - def connect_unix_socket( - self, path, timeout, socket_options=None - ): # pylint: disable=signature-differs - raise NotImplementedError - - class _HTTPTransport(httpx.HTTPTransport): - def __init__( - self, - *args, - local_port=0, - bootstrap_address=None, - resolver=None, - family=socket.AF_UNSPEC, - **kwargs, - ): - if resolver is None and bootstrap_address is None: - # pylint: disable=import-outside-toplevel,redefined-outer-name - import dns.resolver - - resolver = dns.resolver.Resolver() - super().__init__(*args, **kwargs) - self._pool._network_backend = _NetworkBackend( - resolver, local_port, bootstrap_address, family - ) - -else: - - class _HTTPTransport: # type: ignore - def connect_tcp(self, host, port, timeout, local_address): - raise NotImplementedError - - -have_doh = _have_httpx - -try: - import ssl -except ImportError: # pragma: no cover - - class ssl: # type: ignore - CERT_NONE = 0 - - class WantReadException(Exception): - pass - - class WantWriteException(Exception): - pass - - class SSLContext: - pass - - class SSLSocket: - pass - - @classmethod - def create_default_context(cls, *args, **kwargs): - raise Exception("no ssl support") # pylint: disable=broad-exception-raised - - -# Function used to create a socket. Can be overridden if needed in special -# situations. -socket_factory = socket.socket - - -class UnexpectedSource(dns.exception.DNSException): - """A DNS query response came from an unexpected address or port.""" - - -class BadResponse(dns.exception.FormError): - """A DNS query response does not respond to the question asked.""" - - -class NoDOH(dns.exception.DNSException): - """DNS over HTTPS (DOH) was requested but the httpx module is not - available.""" - - -class NoDOQ(dns.exception.DNSException): - """DNS over QUIC (DOQ) was requested but the aioquic module is not - available.""" - - -# for backwards compatibility -TransferError = dns.xfr.TransferError - - -def _compute_times(timeout): - now = time.time() - if timeout is None: - return (now, None) - else: - return (now, now + timeout) - - -def _wait_for(fd, readable, writable, _, expiration): - # Use the selected selector class to wait for any of the specified - # events. An "expiration" absolute time is converted into a relative - # timeout. - # - # The unused parameter is 'error', which is always set when - # selecting for read or write, and we have no error-only selects. - - if readable and isinstance(fd, ssl.SSLSocket) and fd.pending() > 0: - return True - sel = selectors.DefaultSelector() - events = 0 - if readable: - events |= selectors.EVENT_READ - if writable: - events |= selectors.EVENT_WRITE - if events: - sel.register(fd, events) - if expiration is None: - timeout = None - else: - timeout = expiration - time.time() - if timeout <= 0.0: - raise dns.exception.Timeout - if not sel.select(timeout): - raise dns.exception.Timeout - - -def _wait_for_readable(s, expiration): - _wait_for(s, True, False, True, expiration) - - -def _wait_for_writable(s, expiration): - _wait_for(s, False, True, True, expiration) - - -def _addresses_equal(af, a1, a2): - # Convert the first value of the tuple, which is a textual format - # address into binary form, so that we are not confused by different - # textual representations of the same address - try: - n1 = dns.inet.inet_pton(af, a1[0]) - n2 = dns.inet.inet_pton(af, a2[0]) - except dns.exception.SyntaxError: - return False - return n1 == n2 and a1[1:] == a2[1:] - - -def _matches_destination(af, from_address, destination, ignore_unexpected): - # Check that from_address is appropriate for a response to a query - # sent to destination. - if not destination: - return True - if _addresses_equal(af, from_address, destination) or ( - dns.inet.is_multicast(destination[0]) and from_address[1:] == destination[1:] - ): - return True - elif ignore_unexpected: - return False - raise UnexpectedSource( - f"got a response from {from_address} instead of " f"{destination}" - ) - - -def _destination_and_source( - where, port, source, source_port, where_must_be_address=True -): - # Apply defaults and compute destination and source tuples - # suitable for use in connect(), sendto(), or bind(). - af = None - destination = None - try: - af = dns.inet.af_for_address(where) - destination = where - except Exception: - if where_must_be_address: - raise - # URLs are ok so eat the exception - if source: - saf = dns.inet.af_for_address(source) - if af: - # We know the destination af, so source had better agree! - if saf != af: - raise ValueError( - "different address families for source and destination" - ) - else: - # We didn't know the destination af, but we know the source, - # so that's our af. - af = saf - if source_port and not source: - # Caller has specified a source_port but not an address, so we - # need to return a source, and we need to use the appropriate - # wildcard address as the address. - try: - source = dns.inet.any_for_af(af) - except Exception: - # we catch this and raise ValueError for backwards compatibility - raise ValueError("source_port specified but address family is unknown") - # Convert high-level (address, port) tuples into low-level address - # tuples. - if destination: - destination = dns.inet.low_level_address_tuple((destination, port), af) - if source: - source = dns.inet.low_level_address_tuple((source, source_port), af) - return (af, destination, source) - - -def _make_socket(af, type, source, ssl_context=None, server_hostname=None): - s = socket_factory(af, type) - try: - s.setblocking(False) - if source is not None: - s.bind(source) - if ssl_context: - # LGTM gets a false positive here, as our default context is OK - return ssl_context.wrap_socket( - s, - do_handshake_on_connect=False, # lgtm[py/insecure-protocol] - server_hostname=server_hostname, - ) - else: - return s - except Exception: - s.close() - raise - - -def _maybe_get_resolver( - resolver: Optional["dns.resolver.Resolver"], -) -> "dns.resolver.Resolver": - # We need a separate method for this to avoid overriding the global - # variable "dns" with the as-yet undefined local variable "dns" - # in https(). - if resolver is None: - # pylint: disable=import-outside-toplevel,redefined-outer-name - import dns.resolver - - resolver = dns.resolver.Resolver() - return resolver - - -class HTTPVersion(enum.IntEnum): - """Which version of HTTP should be used? - - DEFAULT will select the first version from the list [2, 1.1, 3] that - is available. - """ - - DEFAULT = 0 - HTTP_1 = 1 - H1 = 1 - HTTP_2 = 2 - H2 = 2 - HTTP_3 = 3 - H3 = 3 - - -def https( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 443, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - session: Optional[Any] = None, - path: str = "/dns-query", - post: bool = True, - bootstrap_address: Optional[str] = None, - verify: Union[bool, str] = True, - resolver: Optional["dns.resolver.Resolver"] = None, - family: int = socket.AF_UNSPEC, - http_version: HTTPVersion = HTTPVersion.DEFAULT, -) -> dns.message.Message: - """Return the response obtained after sending a query via DNS-over-HTTPS. - - *q*, a ``dns.message.Message``, the query to send. - - *where*, a ``str``, the nameserver IP address or the full URL. If an IP address is - given, the URL will be constructed using the following schema: - https://:/. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, a ``int``, the port to send the query to. The default is 443. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *session*, an ``httpx.Client``. If provided, the client session to use to send the - queries. - - *path*, a ``str``. If *where* is an IP address, then *path* will be used to - construct the URL to send the DNS query to. - - *post*, a ``bool``. If ``True``, the default, POST method will be used. - - *bootstrap_address*, a ``str``, the IP address to use to bypass resolution. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames in URLs. If not specified, a new resolver with a default - configuration will be used; note this is *not* the default resolver as that resolver - might have been configured to use DoH causing a chicken-and-egg problem. This - parameter only has an effect if the HTTP library is httpx. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC (the default), both A - and AAAA records will be retrieved. - - *http_version*, a ``dns.query.HTTPVersion``, indicating which HTTP version to use. - - Returns a ``dns.message.Message``. - """ - - (af, _, the_source) = _destination_and_source( - where, port, source, source_port, False - ) - if af is not None and dns.inet.is_address(where): - if af == socket.AF_INET: - url = f"https://{where}:{port}{path}" - elif af == socket.AF_INET6: - url = f"https://[{where}]:{port}{path}" - else: - url = where - - extensions = {} - if bootstrap_address is None: - # pylint: disable=possibly-used-before-assignment - parsed = urllib.parse.urlparse(url) - if parsed.hostname is None: - raise ValueError("no hostname in URL") - if dns.inet.is_address(parsed.hostname): - bootstrap_address = parsed.hostname - extensions["sni_hostname"] = parsed.hostname - if parsed.port is not None: - port = parsed.port - - if http_version == HTTPVersion.H3 or ( - http_version == HTTPVersion.DEFAULT and not have_doh - ): - if bootstrap_address is None: - resolver = _maybe_get_resolver(resolver) - assert parsed.hostname is not None # for mypy - answers = resolver.resolve_name(parsed.hostname, family) - bootstrap_address = random.choice(list(answers.addresses())) - return _http3( - q, - bootstrap_address, - url, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - verify=verify, - post=post, - ) - - if not have_doh: - raise NoDOH # pragma: no cover - if session and not isinstance(session, httpx.Client): - raise ValueError("session parameter must be an httpx.Client") - - wire = q.to_wire() - headers = {"accept": "application/dns-message"} - - h1 = http_version in (HTTPVersion.H1, HTTPVersion.DEFAULT) - h2 = http_version in (HTTPVersion.H2, HTTPVersion.DEFAULT) - - # set source port and source address - - if the_source is None: - local_address = None - local_port = 0 - else: - local_address = the_source[0] - local_port = the_source[1] - - if session: - cm: contextlib.AbstractContextManager = contextlib.nullcontext(session) - else: - transport = _HTTPTransport( - local_address=local_address, - http1=h1, - http2=h2, - verify=verify, - local_port=local_port, - bootstrap_address=bootstrap_address, - resolver=resolver, - family=family, - ) - - cm = httpx.Client(http1=h1, http2=h2, verify=verify, transport=transport) - with cm as session: - # see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH - # GET and POST examples - if post: - headers.update( - { - "content-type": "application/dns-message", - "content-length": str(len(wire)), - } - ) - response = session.post( - url, - headers=headers, - content=wire, - timeout=timeout, - extensions=extensions, - ) - else: - wire = base64.urlsafe_b64encode(wire).rstrip(b"=") - twire = wire.decode() # httpx does a repr() if we give it bytes - response = session.get( - url, - headers=headers, - timeout=timeout, - params={"dns": twire}, - extensions=extensions, - ) - - # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH - # status codes - if response.status_code < 200 or response.status_code > 299: - raise ValueError( - f"{where} responded with status code {response.status_code}" - f"\nResponse body: {response.content}" - ) - r = dns.message.from_wire( - response.content, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = response.elapsed.total_seconds() - if not q.is_response(r): - raise BadResponse - return r - - -def _find_header(headers: dns.quic.Headers, name: bytes) -> bytes: - if headers is None: - raise KeyError - for header, value in headers: - if header == name: - return value - raise KeyError - - -def _check_status(headers: dns.quic.Headers, peer: str, wire: bytes) -> None: - value = _find_header(headers, b":status") - if value is None: - raise SyntaxError("no :status header in response") - status = int(value) - if status < 0: - raise SyntaxError("status is negative") - if status < 200 or status > 299: - error = "" - if len(wire) > 0: - try: - error = ": " + wire.decode() - except Exception: - pass - raise ValueError(f"{peer} responded with status code {status}{error}") - - -def _http3( - q: dns.message.Message, - where: str, - url: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - verify: Union[bool, str] = True, - hostname: Optional[str] = None, - post: bool = True, -) -> dns.message.Message: - if not dns.quic.have_quic: - raise NoDOH("DNS-over-HTTP3 is not available.") # pragma: no cover - - url_parts = urllib.parse.urlparse(url) - hostname = url_parts.hostname - if url_parts.port is not None: - port = url_parts.port - - q.id = 0 - wire = q.to_wire() - manager = dns.quic.SyncQuicManager( - verify_mode=verify, server_name=hostname, h3=True - ) - - with manager: - connection = manager.connect(where, port, source, source_port) - (start, expiration) = _compute_times(timeout) - with connection.make_stream(timeout) as stream: - stream.send_h3(url, wire, post) - wire = stream.receive(_remaining(expiration)) - _check_status(stream.headers(), where, wire) - finish = time.time() - r = dns.message.from_wire( - wire, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = max(finish - start, 0.0) - if not q.is_response(r): - raise BadResponse - return r - - -def _udp_recv(sock, max_size, expiration): - """Reads a datagram from the socket. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - while True: - try: - return sock.recvfrom(max_size) - except BlockingIOError: - _wait_for_readable(sock, expiration) - - -def _udp_send(sock, data, destination, expiration): - """Sends the specified datagram to destination over the socket. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - while True: - try: - if destination: - return sock.sendto(data, destination) - else: - return sock.send(data) - except BlockingIOError: # pragma: no cover - _wait_for_writable(sock, expiration) - - -def send_udp( - sock: Any, - what: Union[dns.message.Message, bytes], - destination: Any, - expiration: Optional[float] = None, -) -> Tuple[int, float]: - """Send a DNS message to the specified UDP socket. - - *sock*, a ``socket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where to send the query. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. - """ - - if isinstance(what, dns.message.Message): - what = what.to_wire() - sent_time = time.time() - n = _udp_send(sock, what, destination, expiration) - return (n, sent_time) - - -def receive_udp( - sock: Any, - destination: Optional[Any] = None, - expiration: Optional[float] = None, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None, - request_mac: Optional[bytes] = b"", - ignore_trailing: bool = False, - raise_on_truncation: bool = False, - ignore_errors: bool = False, - query: Optional[dns.message.Message] = None, -) -> Any: - """Read a DNS message from a UDP socket. - - *sock*, a ``socket``. - - *destination*, a destination tuple appropriate for the address family - of the socket, specifying where the message is expected to arrive from. - When receiving a response, this would be where the associated query was - sent. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from - unexpected sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG). - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if - the TC bit is set. - - Raises if the message is malformed, if network errors occur, of if - there is a timeout. - - If *destination* is not ``None``, returns a ``(dns.message.Message, float)`` - tuple of the received message and the received time. - - If *destination* is ``None``, returns a - ``(dns.message.Message, float, tuple)`` - tuple of the received message, the received time, and the address where - the message arrived from. - - *ignore_errors*, a ``bool``. If various format errors or response - mismatches occur, ignore them and keep listening for a valid response. - The default is ``False``. - - *query*, a ``dns.message.Message`` or ``None``. If not ``None`` and - *ignore_errors* is ``True``, check that the received message is a response - to this query, and if not keep listening for a valid response. - """ - - wire = b"" - while True: - (wire, from_address) = _udp_recv(sock, 65535, expiration) - if not _matches_destination( - sock.family, from_address, destination, ignore_unexpected - ): - continue - received_time = time.time() - try: - r = dns.message.from_wire( - wire, - keyring=keyring, - request_mac=request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - raise_on_truncation=raise_on_truncation, - ) - except dns.message.Truncated as e: - # If we got Truncated and not FORMERR, we at least got the header with TC - # set, and very likely the question section, so we'll re-raise if the - # message seems to be a response as we need to know when truncation happens. - # We need to check that it seems to be a response as we don't want a random - # injected message with TC set to cause us to bail out. - if ( - ignore_errors - and query is not None - and not query.is_response(e.message()) - ): - continue - else: - raise - except Exception: - if ignore_errors: - continue - else: - raise - if ignore_errors and query is not None and not query.is_response(r): - continue - if destination: - return (r, received_time) - else: - return (r, received_time, from_address) - - -def udp( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - raise_on_truncation: bool = False, - sock: Optional[Any] = None, - ignore_errors: bool = False, -) -> dns.message.Message: - """Return the response obtained after sending a query via UDP. - - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from - unexpected sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if - the TC bit is set. - - *sock*, a ``socket.socket``, or ``None``, the socket to use for the - query. If ``None``, the default, a socket is created. Note that - if a socket is provided, it must be a nonblocking datagram socket, - and the *source* and *source_port* are ignored. - - *ignore_errors*, a ``bool``. If various format errors or response - mismatches occur, ignore them and keep listening for a valid response. - The default is ``False``. - - Returns a ``dns.message.Message``. - """ - - wire = q.to_wire() - (af, destination, source) = _destination_and_source( - where, port, source, source_port - ) - (begin_time, expiration) = _compute_times(timeout) - if sock: - cm: contextlib.AbstractContextManager = contextlib.nullcontext(sock) - else: - cm = _make_socket(af, socket.SOCK_DGRAM, source) - with cm as s: - send_udp(s, wire, destination, expiration) - (r, received_time) = receive_udp( - s, - destination, - expiration, - ignore_unexpected, - one_rr_per_rrset, - q.keyring, - q.mac, - ignore_trailing, - raise_on_truncation, - ignore_errors, - q, - ) - r.time = received_time - begin_time - # We don't need to check q.is_response() if we are in ignore_errors mode - # as receive_udp() will have checked it. - if not (ignore_errors or q.is_response(r)): - raise BadResponse - return r - assert ( - False # help mypy figure out we can't get here lgtm[py/unreachable-statement] - ) - - -def udp_with_fallback( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - ignore_unexpected: bool = False, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - udp_sock: Optional[Any] = None, - tcp_sock: Optional[Any] = None, - ignore_errors: bool = False, -) -> Tuple[dns.message.Message, bool]: - """Return the response to the query, trying UDP first and falling back - to TCP if UDP results in a truncated response. - - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from unexpected - sources. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the UDP query. - If ``None``, the default, a socket is created. Note that if a socket is provided, - it must be a nonblocking datagram socket, and the *source* and *source_port* are - ignored for the UDP query. - - *tcp_sock*, a ``socket.socket``, or ``None``, the connected socket to use for the - TCP query. If ``None``, the default, a socket is created. Note that if a socket is - provided, it must be a nonblocking connected stream socket, and *where*, *source* - and *source_port* are ignored for the TCP query. - - *ignore_errors*, a ``bool``. If various format errors or response mismatches occur - while listening for UDP, ignore them and keep listening for a valid response. The - default is ``False``. - - Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True`` if and only if - TCP was used. - """ - try: - response = udp( - q, - where, - timeout, - port, - source, - source_port, - ignore_unexpected, - one_rr_per_rrset, - ignore_trailing, - True, - udp_sock, - ignore_errors, - ) - return (response, False) - except dns.message.Truncated: - response = tcp( - q, - where, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - tcp_sock, - ) - return (response, True) - - -def _net_read(sock, count, expiration): - """Read the specified number of bytes from sock. Keep trying until we - either get the desired amount, or we hit EOF. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - s = b"" - while count > 0: - try: - n = sock.recv(count) - if n == b"": - raise EOFError("EOF") - count -= len(n) - s += n - except (BlockingIOError, ssl.SSLWantReadError): - _wait_for_readable(sock, expiration) - except ssl.SSLWantWriteError: # pragma: no cover - _wait_for_writable(sock, expiration) - return s - - -def _net_write(sock, data, expiration): - """Write the specified data to the socket. - A Timeout exception will be raised if the operation is not completed - by the expiration time. - """ - current = 0 - l = len(data) - while current < l: - try: - current += sock.send(data[current:]) - except (BlockingIOError, ssl.SSLWantWriteError): - _wait_for_writable(sock, expiration) - except ssl.SSLWantReadError: # pragma: no cover - _wait_for_readable(sock, expiration) - - -def send_tcp( - sock: Any, - what: Union[dns.message.Message, bytes], - expiration: Optional[float] = None, -) -> Tuple[int, float]: - """Send a DNS message to the specified TCP socket. - - *sock*, a ``socket``. - - *what*, a ``bytes`` or ``dns.message.Message``, the message to send. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - Returns an ``(int, float)`` tuple of bytes sent and the sent time. - """ - - if isinstance(what, dns.message.Message): - tcpmsg = what.to_wire(prepend_length=True) - else: - # copying the wire into tcpmsg is inefficient, but lets us - # avoid writev() or doing a short write that would get pushed - # onto the net - tcpmsg = len(what).to_bytes(2, "big") + what - sent_time = time.time() - _net_write(sock, tcpmsg, expiration) - return (len(tcpmsg), sent_time) - - -def receive_tcp( - sock: Any, - expiration: Optional[float] = None, - one_rr_per_rrset: bool = False, - keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None, - request_mac: Optional[bytes] = b"", - ignore_trailing: bool = False, -) -> Tuple[dns.message.Message, float]: - """Read a DNS message from a TCP socket. - - *sock*, a ``socket``. - - *expiration*, a ``float`` or ``None``, the absolute time at which - a timeout exception should be raised. If ``None``, no timeout will - occur. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG). - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - Raises if the message is malformed, if network errors occur, of if - there is a timeout. - - Returns a ``(dns.message.Message, float)`` tuple of the received message - and the received time. - """ - - ldata = _net_read(sock, 2, expiration) - (l,) = struct.unpack("!H", ldata) - wire = _net_read(sock, l, expiration) - received_time = time.time() - r = dns.message.from_wire( - wire, - keyring=keyring, - request_mac=request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - return (r, received_time) - - -def _connect(s, address, expiration): - err = s.connect_ex(address) - if err == 0: - return - if err in (errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY): - _wait_for_writable(s, expiration) - err = s.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise OSError(err, os.strerror(err)) - - -def tcp( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 53, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - sock: Optional[Any] = None, -) -> dns.message.Message: - """Return the response obtained after sending a query via TCP. - - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *sock*, a ``socket.socket``, or ``None``, the connected socket to use for the - query. If ``None``, the default, a socket is created. Note that - if a socket is provided, it must be a nonblocking connected stream - socket, and *where*, *port*, *source* and *source_port* are ignored. - - Returns a ``dns.message.Message``. - """ - - wire = q.to_wire() - (begin_time, expiration) = _compute_times(timeout) - if sock: - cm: contextlib.AbstractContextManager = contextlib.nullcontext(sock) - else: - (af, destination, source) = _destination_and_source( - where, port, source, source_port - ) - cm = _make_socket(af, socket.SOCK_STREAM, source) - with cm as s: - if not sock: - # pylint: disable=possibly-used-before-assignment - _connect(s, destination, expiration) - send_tcp(s, wire, expiration) - (r, received_time) = receive_tcp( - s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing - ) - r.time = received_time - begin_time - if not q.is_response(r): - raise BadResponse - return r - assert ( - False # help mypy figure out we can't get here lgtm[py/unreachable-statement] - ) - - -def _tls_handshake(s, expiration): - while True: - try: - s.do_handshake() - return - except ssl.SSLWantReadError: - _wait_for_readable(s, expiration) - except ssl.SSLWantWriteError: # pragma: no cover - _wait_for_writable(s, expiration) - - -def _make_dot_ssl_context( - server_hostname: Optional[str], verify: Union[bool, str] -) -> ssl.SSLContext: - cafile: Optional[str] = None - capath: Optional[str] = None - if isinstance(verify, str): - if os.path.isfile(verify): - cafile = verify - elif os.path.isdir(verify): - capath = verify - else: - raise ValueError("invalid verify string") - ssl_context = ssl.create_default_context(cafile=cafile, capath=capath) - ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2 - if server_hostname is None: - ssl_context.check_hostname = False - ssl_context.set_alpn_protocols(["dot"]) - if verify is False: - ssl_context.verify_mode = ssl.CERT_NONE - return ssl_context - - -def tls( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - sock: Optional[ssl.SSLSocket] = None, - ssl_context: Optional[ssl.SSLContext] = None, - server_hostname: Optional[str] = None, - verify: Union[bool, str] = True, -) -> dns.message.Message: - """Return the response obtained after sending a query via TLS. - - *q*, a ``dns.message.Message``, the query to send - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the - query times out. If ``None``, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 853. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own - RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing - junk at end of the received message. - - *sock*, an ``ssl.SSLSocket``, or ``None``, the socket to use for - the query. If ``None``, the default, a socket is created. Note - that if a socket is provided, it must be a nonblocking connected - SSL stream socket, and *where*, *port*, *source*, *source_port*, - and *ssl_context* are ignored. - - *ssl_context*, an ``ssl.SSLContext``, the context to use when establishing - a TLS connection. If ``None``, the default, creates one with the default - configuration. - - *server_hostname*, a ``str`` containing the server's hostname. The - default is ``None``, which means that no hostname is known, and if an - SSL context is created, hostname checking will be disabled. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - Returns a ``dns.message.Message``. - - """ - - if sock: - # - # If a socket was provided, there's no special TLS handling needed. - # - return tcp( - q, - where, - timeout, - port, - source, - source_port, - one_rr_per_rrset, - ignore_trailing, - sock, - ) - - wire = q.to_wire() - (begin_time, expiration) = _compute_times(timeout) - (af, destination, source) = _destination_and_source( - where, port, source, source_port - ) - if ssl_context is None and not sock: - ssl_context = _make_dot_ssl_context(server_hostname, verify) - - with _make_socket( - af, - socket.SOCK_STREAM, - source, - ssl_context=ssl_context, - server_hostname=server_hostname, - ) as s: - _connect(s, destination, expiration) - _tls_handshake(s, expiration) - send_tcp(s, wire, expiration) - (r, received_time) = receive_tcp( - s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing - ) - r.time = received_time - begin_time - if not q.is_response(r): - raise BadResponse - return r - assert ( - False # help mypy figure out we can't get here lgtm[py/unreachable-statement] - ) - - -def quic( - q: dns.message.Message, - where: str, - timeout: Optional[float] = None, - port: int = 853, - source: Optional[str] = None, - source_port: int = 0, - one_rr_per_rrset: bool = False, - ignore_trailing: bool = False, - connection: Optional[dns.quic.SyncQuicConnection] = None, - verify: Union[bool, str] = True, - hostname: Optional[str] = None, - server_hostname: Optional[str] = None, -) -> dns.message.Message: - """Return the response obtained after sending a query via DNS-over-QUIC. - - *q*, a ``dns.message.Message``, the query to send. - - *where*, a ``str``, the nameserver IP address. - - *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query - times out. If ``None``, the default, wait forever. - - *port*, a ``int``, the port to send the query to. The default is 853. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source - address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. The default is - 0. - - *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset. - - *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the - received message. - - *connection*, a ``dns.quic.SyncQuicConnection``. If provided, the connection to use - to send the query. - - *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification - of the server is done using the default CA bundle; if ``False``, then no - verification is done; if a `str` then it specifies the path to a certificate file or - directory which will be used for verification. - - *hostname*, a ``str`` containing the server's hostname or ``None``. The default is - ``None``, which means that no hostname is known, and if an SSL context is created, - hostname checking will be disabled. This value is ignored if *url* is not - ``None``. - - *server_hostname*, a ``str`` or ``None``. This item is for backwards compatibility - only, and has the same meaning as *hostname*. - - Returns a ``dns.message.Message``. - """ - - if not dns.quic.have_quic: - raise NoDOQ("DNS-over-QUIC is not available.") # pragma: no cover - - if server_hostname is not None and hostname is None: - hostname = server_hostname - - q.id = 0 - wire = q.to_wire() - the_connection: dns.quic.SyncQuicConnection - the_manager: dns.quic.SyncQuicManager - if connection: - manager: contextlib.AbstractContextManager = contextlib.nullcontext(None) - the_connection = connection - else: - manager = dns.quic.SyncQuicManager(verify_mode=verify, server_name=hostname) - the_manager = manager # for type checking happiness - - with manager: - if not connection: - the_connection = the_manager.connect(where, port, source, source_port) - (start, expiration) = _compute_times(timeout) - with the_connection.make_stream(timeout) as stream: - stream.send(wire, True) - wire = stream.receive(_remaining(expiration)) - finish = time.time() - r = dns.message.from_wire( - wire, - keyring=q.keyring, - request_mac=q.request_mac, - one_rr_per_rrset=one_rr_per_rrset, - ignore_trailing=ignore_trailing, - ) - r.time = max(finish - start, 0.0) - if not q.is_response(r): - raise BadResponse - return r - - -class UDPMode(enum.IntEnum): - """How should UDP be used in an IXFR from :py:func:`inbound_xfr()`? - - NEVER means "never use UDP; always use TCP" - TRY_FIRST means "try to use UDP but fall back to TCP if needed" - ONLY means "raise ``dns.xfr.UseTCP`` if trying UDP does not succeed" - """ - - NEVER = 0 - TRY_FIRST = 1 - ONLY = 2 - - -def _inbound_xfr( - txn_manager: dns.transaction.TransactionManager, - s: socket.socket, - query: dns.message.Message, - serial: Optional[int], - timeout: Optional[float], - expiration: float, -) -> Any: - """Given a socket, does the zone transfer.""" - rdtype = query.question[0].rdtype - is_ixfr = rdtype == dns.rdatatype.IXFR - origin = txn_manager.from_wire_origin() - wire = query.to_wire() - is_udp = s.type == socket.SOCK_DGRAM - if is_udp: - _udp_send(s, wire, None, expiration) - else: - tcpmsg = struct.pack("!H", len(wire)) + wire - _net_write(s, tcpmsg, expiration) - with dns.xfr.Inbound(txn_manager, rdtype, serial, is_udp) as inbound: - done = False - tsig_ctx = None - while not done: - (_, mexpiration) = _compute_times(timeout) - if mexpiration is None or ( - expiration is not None and mexpiration > expiration - ): - mexpiration = expiration - if is_udp: - (rwire, _) = _udp_recv(s, 65535, mexpiration) - else: - ldata = _net_read(s, 2, mexpiration) - (l,) = struct.unpack("!H", ldata) - rwire = _net_read(s, l, mexpiration) - r = dns.message.from_wire( - rwire, - keyring=query.keyring, - request_mac=query.mac, - xfr=True, - origin=origin, - tsig_ctx=tsig_ctx, - multi=(not is_udp), - one_rr_per_rrset=is_ixfr, - ) - done = inbound.process_message(r) - yield r - tsig_ctx = r.tsig_ctx - if query.keyring and not r.had_tsig: - raise dns.exception.FormError("missing TSIG") - - -def xfr( - where: str, - zone: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.AXFR, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - timeout: Optional[float] = None, - port: int = 53, - keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None, - keyname: Optional[Union[dns.name.Name, str]] = None, - relativize: bool = True, - lifetime: Optional[float] = None, - source: Optional[str] = None, - source_port: int = 0, - serial: int = 0, - use_udp: bool = False, - keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm, -) -> Any: - """Return a generator for the responses to a zone transfer. - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *zone*, a ``dns.name.Name`` or ``str``, the name of the zone to transfer. - - *rdtype*, an ``int`` or ``str``, the type of zone transfer. The - default is ``dns.rdatatype.AXFR``. ``dns.rdatatype.IXFR`` can be - used to do an incremental transfer instead. - - *rdclass*, an ``int`` or ``str``, the class of the zone transfer. - The default is ``dns.rdataclass.IN``. - - *timeout*, a ``float``, the number of seconds to wait for each - response message. If None, the default, wait forever. - - *port*, an ``int``, the port send the message to. The default is 53. - - *keyring*, a ``dict``, the keyring to use for TSIG. - - *keyname*, a ``dns.name.Name`` or ``str``, the name of the TSIG - key to use. - - *relativize*, a ``bool``. If ``True``, all names in the zone will be - relativized to the zone origin. It is essential that the - relativize setting matches the one specified to - ``dns.zone.from_xfr()`` if using this generator to make a zone. - - *lifetime*, a ``float``, the total number of seconds to spend - doing the transfer. If ``None``, the default, then there is no - limit on the time the transfer may take. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *serial*, an ``int``, the SOA serial number to use as the base for - an IXFR diff sequence (only meaningful if *rdtype* is - ``dns.rdatatype.IXFR``). - - *use_udp*, a ``bool``. If ``True``, use UDP (only meaningful for IXFR). - - *keyalgorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use. - - Raises on errors, and so does the generator. - - Returns a generator of ``dns.message.Message`` objects. - """ - - class DummyTransactionManager(dns.transaction.TransactionManager): - def __init__(self, origin, relativize): - self.info = (origin, relativize, dns.name.empty if relativize else origin) - - def origin_information(self): - return self.info - - def get_class(self) -> dns.rdataclass.RdataClass: - raise NotImplementedError # pragma: no cover - - def reader(self): - raise NotImplementedError # pragma: no cover - - def writer(self, replacement: bool = False) -> dns.transaction.Transaction: - class DummyTransaction: - def nop(self, *args, **kw): - pass - - def __getattr__(self, _): - return self.nop - - return cast(dns.transaction.Transaction, DummyTransaction()) - - if isinstance(zone, str): - zone = dns.name.from_text(zone) - rdtype = dns.rdatatype.RdataType.make(rdtype) - q = dns.message.make_query(zone, rdtype, rdclass) - if rdtype == dns.rdatatype.IXFR: - rrset = q.find_rrset( - q.authority, zone, dns.rdataclass.IN, dns.rdatatype.SOA, create=True - ) - soa = dns.rdata.from_text("IN", "SOA", ". . %u 0 0 0 0" % serial) - rrset.add(soa, 0) - if keyring is not None: - q.use_tsig(keyring, keyname, algorithm=keyalgorithm) - (af, destination, source) = _destination_and_source( - where, port, source, source_port - ) - (_, expiration) = _compute_times(lifetime) - tm = DummyTransactionManager(zone, relativize) - if use_udp and rdtype != dns.rdatatype.IXFR: - raise ValueError("cannot do a UDP AXFR") - sock_type = socket.SOCK_DGRAM if use_udp else socket.SOCK_STREAM - with _make_socket(af, sock_type, source) as s: - _connect(s, destination, expiration) - yield from _inbound_xfr(tm, s, q, serial, timeout, expiration) - - -def inbound_xfr( - where: str, - txn_manager: dns.transaction.TransactionManager, - query: Optional[dns.message.Message] = None, - port: int = 53, - timeout: Optional[float] = None, - lifetime: Optional[float] = None, - source: Optional[str] = None, - source_port: int = 0, - udp_mode: UDPMode = UDPMode.NEVER, -) -> None: - """Conduct an inbound transfer and apply it via a transaction from the - txn_manager. - - *where*, a ``str`` containing an IPv4 or IPv6 address, where - to send the message. - - *txn_manager*, a ``dns.transaction.TransactionManager``, the txn_manager - for this transfer (typically a ``dns.zone.Zone``). - - *query*, the query to send. If not supplied, a default query is - constructed using information from the *txn_manager*. - - *port*, an ``int``, the port send the message to. The default is 53. - - *timeout*, a ``float``, the number of seconds to wait for each - response message. If None, the default, wait forever. - - *lifetime*, a ``float``, the total number of seconds to spend - doing the transfer. If ``None``, the default, then there is no - limit on the time the transfer may take. - - *source*, a ``str`` containing an IPv4 or IPv6 address, specifying - the source address. The default is the wildcard address. - - *source_port*, an ``int``, the port from which to send the message. - The default is 0. - - *udp_mode*, a ``dns.query.UDPMode``, determines how UDP is used - for IXFRs. The default is ``dns.UDPMode.NEVER``, i.e. only use - TCP. Other possibilities are ``dns.UDPMode.TRY_FIRST``, which - means "try UDP but fallback to TCP if needed", and - ``dns.UDPMode.ONLY``, which means "try UDP and raise - ``dns.xfr.UseTCP`` if it does not succeed. - - Raises on errors. - """ - if query is None: - (query, serial) = dns.xfr.make_query(txn_manager) - else: - serial = dns.xfr.extract_serial_from_query(query) - - (af, destination, source) = _destination_and_source( - where, port, source, source_port - ) - (_, expiration) = _compute_times(lifetime) - if query.question[0].rdtype == dns.rdatatype.IXFR and udp_mode != UDPMode.NEVER: - with _make_socket(af, socket.SOCK_DGRAM, source) as s: - _connect(s, destination, expiration) - try: - for _ in _inbound_xfr( - txn_manager, s, query, serial, timeout, expiration - ): - pass - return - except dns.xfr.UseTCP: - if udp_mode == UDPMode.ONLY: - raise - - with _make_socket(af, socket.SOCK_STREAM, source) as s: - _connect(s, destination, expiration) - for _ in _inbound_xfr(txn_manager, s, query, serial, timeout, expiration): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/dns/quic/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/quic/__init__.py deleted file mode 100644 index 0750e72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/quic/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -from typing import List, Tuple - -import dns._features -import dns.asyncbackend - -if dns._features.have("doq"): - import aioquic.quic.configuration # type: ignore - - from dns._asyncbackend import NullContext - from dns.quic._asyncio import ( - AsyncioQuicConnection, - AsyncioQuicManager, - AsyncioQuicStream, - ) - from dns.quic._common import AsyncQuicConnection, AsyncQuicManager - from dns.quic._sync import SyncQuicConnection, SyncQuicManager, SyncQuicStream - - have_quic = True - - def null_factory( - *args, # pylint: disable=unused-argument - **kwargs, # pylint: disable=unused-argument - ): - return NullContext(None) - - def _asyncio_manager_factory( - context, *args, **kwargs # pylint: disable=unused-argument - ): - return AsyncioQuicManager(*args, **kwargs) - - # We have a context factory and a manager factory as for trio we need to have - # a nursery. - - _async_factories = {"asyncio": (null_factory, _asyncio_manager_factory)} - - if dns._features.have("trio"): - import trio - - from dns.quic._trio import ( # pylint: disable=ungrouped-imports - TrioQuicConnection, - TrioQuicManager, - TrioQuicStream, - ) - - def _trio_context_factory(): - return trio.open_nursery() - - def _trio_manager_factory(context, *args, **kwargs): - return TrioQuicManager(context, *args, **kwargs) - - _async_factories["trio"] = (_trio_context_factory, _trio_manager_factory) - - def factories_for_backend(backend=None): - if backend is None: - backend = dns.asyncbackend.get_default_backend() - return _async_factories[backend.name()] - -else: # pragma: no cover - have_quic = False - - from typing import Any - - class AsyncQuicStream: # type: ignore - pass - - class AsyncQuicConnection: # type: ignore - async def make_stream(self) -> Any: - raise NotImplementedError - - class SyncQuicStream: # type: ignore - pass - - class SyncQuicConnection: # type: ignore - def make_stream(self) -> Any: - raise NotImplementedError - - -Headers = List[Tuple[bytes, bytes]] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/quic/_asyncio.py b/backend/venv39/lib/python3.9/site-packages/dns/quic/_asyncio.py deleted file mode 100644 index f87515d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/quic/_asyncio.py +++ /dev/null @@ -1,267 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import asyncio -import socket -import ssl -import struct -import time - -import aioquic.quic.configuration # type: ignore -import aioquic.quic.connection # type: ignore -import aioquic.quic.events # type: ignore - -import dns.asyncbackend -import dns.exception -import dns.inet -from dns.quic._common import ( - QUIC_MAX_DATAGRAM, - AsyncQuicConnection, - AsyncQuicManager, - BaseQuicStream, - UnexpectedEOF, -) - - -class AsyncioQuicStream(BaseQuicStream): - def __init__(self, connection, stream_id): - super().__init__(connection, stream_id) - self._wake_up = asyncio.Condition() - - async def _wait_for_wake_up(self): - async with self._wake_up: - await self._wake_up.wait() - - async def wait_for(self, amount, expiration): - while True: - timeout = self._timeout_from_expiration(expiration) - if self._buffer.have(amount): - return - self._expecting = amount - try: - await asyncio.wait_for(self._wait_for_wake_up(), timeout) - except TimeoutError: - raise dns.exception.Timeout - self._expecting = 0 - - async def wait_for_end(self, expiration): - while True: - timeout = self._timeout_from_expiration(expiration) - if self._buffer.seen_end(): - return - try: - await asyncio.wait_for(self._wait_for_wake_up(), timeout) - except TimeoutError: - raise dns.exception.Timeout - - async def receive(self, timeout=None): - expiration = self._expiration_from_timeout(timeout) - if self._connection.is_h3(): - await self.wait_for_end(expiration) - return self._buffer.get_all() - else: - await self.wait_for(2, expiration) - (size,) = struct.unpack("!H", self._buffer.get(2)) - await self.wait_for(size, expiration) - return self._buffer.get(size) - - async def send(self, datagram, is_end=False): - data = self._encapsulate(datagram) - await self._connection.write(self._stream_id, data, is_end) - - async def _add_input(self, data, is_end): - if self._common_add_input(data, is_end): - async with self._wake_up: - self._wake_up.notify() - - async def close(self): - self._close() - - # Streams are async context managers - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - await self.close() - async with self._wake_up: - self._wake_up.notify() - return False - - -class AsyncioQuicConnection(AsyncQuicConnection): - def __init__(self, connection, address, port, source, source_port, manager=None): - super().__init__(connection, address, port, source, source_port, manager) - self._socket = None - self._handshake_complete = asyncio.Event() - self._socket_created = asyncio.Event() - self._wake_timer = asyncio.Condition() - self._receiver_task = None - self._sender_task = None - self._wake_pending = False - - async def _receiver(self): - try: - af = dns.inet.af_for_address(self._address) - backend = dns.asyncbackend.get_backend("asyncio") - # Note that peer is a low-level address tuple, but make_socket() wants - # a high-level address tuple, so we convert. - self._socket = await backend.make_socket( - af, socket.SOCK_DGRAM, 0, self._source, (self._peer[0], self._peer[1]) - ) - self._socket_created.set() - async with self._socket: - while not self._done: - (datagram, address) = await self._socket.recvfrom( - QUIC_MAX_DATAGRAM, None - ) - if address[0] != self._peer[0] or address[1] != self._peer[1]: - continue - self._connection.receive_datagram(datagram, address, time.time()) - # Wake up the timer in case the sender is sleeping, as there may be - # stuff to send now. - await self._wakeup() - except Exception: - pass - finally: - self._done = True - await self._wakeup() - self._handshake_complete.set() - - async def _wakeup(self): - self._wake_pending = True - async with self._wake_timer: - self._wake_timer.notify_all() - - async def _wait_for_wake_timer(self): - async with self._wake_timer: - if not self._wake_pending: - await self._wake_timer.wait() - self._wake_pending = False - - async def _sender(self): - await self._socket_created.wait() - while not self._done: - datagrams = self._connection.datagrams_to_send(time.time()) - for datagram, address in datagrams: - assert address == self._peer - await self._socket.sendto(datagram, self._peer, None) - (expiration, interval) = self._get_timer_values() - try: - await asyncio.wait_for(self._wait_for_wake_timer(), interval) - except Exception: - pass - self._handle_timer(expiration) - await self._handle_events() - - async def _handle_events(self): - count = 0 - while True: - event = self._connection.next_event() - if event is None: - return - if isinstance(event, aioquic.quic.events.StreamDataReceived): - if self.is_h3(): - h3_events = self._h3_conn.handle_event(event) - for h3_event in h3_events: - if isinstance(h3_event, aioquic.h3.events.HeadersReceived): - stream = self._streams.get(event.stream_id) - if stream: - if stream._headers is None: - stream._headers = h3_event.headers - elif stream._trailers is None: - stream._trailers = h3_event.headers - if h3_event.stream_ended: - await stream._add_input(b"", True) - elif isinstance(h3_event, aioquic.h3.events.DataReceived): - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input( - h3_event.data, h3_event.stream_ended - ) - else: - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input(event.data, event.end_stream) - elif isinstance(event, aioquic.quic.events.HandshakeCompleted): - self._handshake_complete.set() - elif isinstance(event, aioquic.quic.events.ConnectionTerminated): - self._done = True - self._receiver_task.cancel() - elif isinstance(event, aioquic.quic.events.StreamReset): - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input(b"", True) - - count += 1 - if count > 10: - # yield - count = 0 - await asyncio.sleep(0) - - async def write(self, stream, data, is_end=False): - self._connection.send_stream_data(stream, data, is_end) - await self._wakeup() - - def run(self): - if self._closed: - return - self._receiver_task = asyncio.Task(self._receiver()) - self._sender_task = asyncio.Task(self._sender()) - - async def make_stream(self, timeout=None): - try: - await asyncio.wait_for(self._handshake_complete.wait(), timeout) - except TimeoutError: - raise dns.exception.Timeout - if self._done: - raise UnexpectedEOF - stream_id = self._connection.get_next_available_stream_id(False) - stream = AsyncioQuicStream(self, stream_id) - self._streams[stream_id] = stream - return stream - - async def close(self): - if not self._closed: - self._manager.closed(self._peer[0], self._peer[1]) - self._closed = True - self._connection.close() - # sender might be blocked on this, so set it - self._socket_created.set() - await self._wakeup() - try: - await self._receiver_task - except asyncio.CancelledError: - pass - try: - await self._sender_task - except asyncio.CancelledError: - pass - await self._socket.close() - - -class AsyncioQuicManager(AsyncQuicManager): - def __init__( - self, conf=None, verify_mode=ssl.CERT_REQUIRED, server_name=None, h3=False - ): - super().__init__(conf, verify_mode, AsyncioQuicConnection, server_name, h3) - - def connect( - self, address, port=853, source=None, source_port=0, want_session_ticket=True - ): - (connection, start) = self._connect( - address, port, source, source_port, want_session_ticket - ) - if start: - connection.run() - return connection - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - # Copy the iterator into a list as exiting things will mutate the connections - # table. - connections = list(self._connections.values()) - for connection in connections: - await connection.close() - return False diff --git a/backend/venv39/lib/python3.9/site-packages/dns/quic/_common.py b/backend/venv39/lib/python3.9/site-packages/dns/quic/_common.py deleted file mode 100644 index ce575b0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/quic/_common.py +++ /dev/null @@ -1,339 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import base64 -import copy -import functools -import socket -import struct -import time -import urllib -from typing import Any, Optional - -import aioquic.h3.connection # type: ignore -import aioquic.h3.events # type: ignore -import aioquic.quic.configuration # type: ignore -import aioquic.quic.connection # type: ignore - -import dns.inet - -QUIC_MAX_DATAGRAM = 2048 -MAX_SESSION_TICKETS = 8 -# If we hit the max sessions limit we will delete this many of the oldest connections. -# The value must be a integer > 0 and <= MAX_SESSION_TICKETS. -SESSIONS_TO_DELETE = MAX_SESSION_TICKETS // 4 - - -class UnexpectedEOF(Exception): - pass - - -class Buffer: - def __init__(self): - self._buffer = b"" - self._seen_end = False - - def put(self, data, is_end): - if self._seen_end: - return - self._buffer += data - if is_end: - self._seen_end = True - - def have(self, amount): - if len(self._buffer) >= amount: - return True - if self._seen_end: - raise UnexpectedEOF - return False - - def seen_end(self): - return self._seen_end - - def get(self, amount): - assert self.have(amount) - data = self._buffer[:amount] - self._buffer = self._buffer[amount:] - return data - - def get_all(self): - assert self.seen_end() - data = self._buffer - self._buffer = b"" - return data - - -class BaseQuicStream: - def __init__(self, connection, stream_id): - self._connection = connection - self._stream_id = stream_id - self._buffer = Buffer() - self._expecting = 0 - self._headers = None - self._trailers = None - - def id(self): - return self._stream_id - - def headers(self): - return self._headers - - def trailers(self): - return self._trailers - - def _expiration_from_timeout(self, timeout): - if timeout is not None: - expiration = time.time() + timeout - else: - expiration = None - return expiration - - def _timeout_from_expiration(self, expiration): - if expiration is not None: - timeout = max(expiration - time.time(), 0.0) - else: - timeout = None - return timeout - - # Subclass must implement receive() as sync / async and which returns a message - # or raises. - - # Subclass must implement send() as sync / async and which takes a message and - # an EOF indicator. - - def send_h3(self, url, datagram, post=True): - if not self._connection.is_h3(): - raise SyntaxError("cannot send H3 to a non-H3 connection") - url_parts = urllib.parse.urlparse(url) - path = url_parts.path.encode() - if post: - method = b"POST" - else: - method = b"GET" - path += b"?dns=" + base64.urlsafe_b64encode(datagram).rstrip(b"=") - headers = [ - (b":method", method), - (b":scheme", url_parts.scheme.encode()), - (b":authority", url_parts.netloc.encode()), - (b":path", path), - (b"accept", b"application/dns-message"), - ] - if post: - headers.extend( - [ - (b"content-type", b"application/dns-message"), - (b"content-length", str(len(datagram)).encode()), - ] - ) - self._connection.send_headers(self._stream_id, headers, not post) - if post: - self._connection.send_data(self._stream_id, datagram, True) - - def _encapsulate(self, datagram): - if self._connection.is_h3(): - return datagram - l = len(datagram) - return struct.pack("!H", l) + datagram - - def _common_add_input(self, data, is_end): - self._buffer.put(data, is_end) - try: - return ( - self._expecting > 0 and self._buffer.have(self._expecting) - ) or self._buffer.seen_end - except UnexpectedEOF: - return True - - def _close(self): - self._connection.close_stream(self._stream_id) - self._buffer.put(b"", True) # send EOF in case we haven't seen it. - - -class BaseQuicConnection: - def __init__( - self, - connection, - address, - port, - source=None, - source_port=0, - manager=None, - ): - self._done = False - self._connection = connection - self._address = address - self._port = port - self._closed = False - self._manager = manager - self._streams = {} - if manager.is_h3(): - self._h3_conn = aioquic.h3.connection.H3Connection(connection, False) - else: - self._h3_conn = None - self._af = dns.inet.af_for_address(address) - self._peer = dns.inet.low_level_address_tuple((address, port)) - if source is None and source_port != 0: - if self._af == socket.AF_INET: - source = "0.0.0.0" - elif self._af == socket.AF_INET6: - source = "::" - else: - raise NotImplementedError - if source: - self._source = (source, source_port) - else: - self._source = None - - def is_h3(self): - return self._h3_conn is not None - - def close_stream(self, stream_id): - del self._streams[stream_id] - - def send_headers(self, stream_id, headers, is_end=False): - self._h3_conn.send_headers(stream_id, headers, is_end) - - def send_data(self, stream_id, data, is_end=False): - self._h3_conn.send_data(stream_id, data, is_end) - - def _get_timer_values(self, closed_is_special=True): - now = time.time() - expiration = self._connection.get_timer() - if expiration is None: - expiration = now + 3600 # arbitrary "big" value - interval = max(expiration - now, 0) - if self._closed and closed_is_special: - # lower sleep interval to avoid a race in the closing process - # which can lead to higher latency closing due to sleeping when - # we have events. - interval = min(interval, 0.05) - return (expiration, interval) - - def _handle_timer(self, expiration): - now = time.time() - if expiration <= now: - self._connection.handle_timer(now) - - -class AsyncQuicConnection(BaseQuicConnection): - async def make_stream(self, timeout: Optional[float] = None) -> Any: - pass - - -class BaseQuicManager: - def __init__( - self, conf, verify_mode, connection_factory, server_name=None, h3=False - ): - self._connections = {} - self._connection_factory = connection_factory - self._session_tickets = {} - self._tokens = {} - self._h3 = h3 - if conf is None: - verify_path = None - if isinstance(verify_mode, str): - verify_path = verify_mode - verify_mode = True - if h3: - alpn_protocols = ["h3"] - else: - alpn_protocols = ["doq", "doq-i03"] - conf = aioquic.quic.configuration.QuicConfiguration( - alpn_protocols=alpn_protocols, - verify_mode=verify_mode, - server_name=server_name, - ) - if verify_path is not None: - conf.load_verify_locations(verify_path) - self._conf = conf - - def _connect( - self, - address, - port=853, - source=None, - source_port=0, - want_session_ticket=True, - want_token=True, - ): - connection = self._connections.get((address, port)) - if connection is not None: - return (connection, False) - conf = self._conf - if want_session_ticket: - try: - session_ticket = self._session_tickets.pop((address, port)) - # We found a session ticket, so make a configuration that uses it. - conf = copy.copy(conf) - conf.session_ticket = session_ticket - except KeyError: - # No session ticket. - pass - # Whether or not we found a session ticket, we want a handler to save - # one. - session_ticket_handler = functools.partial( - self.save_session_ticket, address, port - ) - else: - session_ticket_handler = None - if want_token: - try: - token = self._tokens.pop((address, port)) - # We found a token, so make a configuration that uses it. - conf = copy.copy(conf) - conf.token = token - except KeyError: - # No token - pass - # Whether or not we found a token, we want a handler to save # one. - token_handler = functools.partial(self.save_token, address, port) - else: - token_handler = None - - qconn = aioquic.quic.connection.QuicConnection( - configuration=conf, - session_ticket_handler=session_ticket_handler, - token_handler=token_handler, - ) - lladdress = dns.inet.low_level_address_tuple((address, port)) - qconn.connect(lladdress, time.time()) - connection = self._connection_factory( - qconn, address, port, source, source_port, self - ) - self._connections[(address, port)] = connection - return (connection, True) - - def closed(self, address, port): - try: - del self._connections[(address, port)] - except KeyError: - pass - - def is_h3(self): - return self._h3 - - def save_session_ticket(self, address, port, ticket): - # We rely on dictionaries keys() being in insertion order here. We - # can't just popitem() as that would be LIFO which is the opposite of - # what we want. - l = len(self._session_tickets) - if l >= MAX_SESSION_TICKETS: - keys_to_delete = list(self._session_tickets.keys())[0:SESSIONS_TO_DELETE] - for key in keys_to_delete: - del self._session_tickets[key] - self._session_tickets[(address, port)] = ticket - - def save_token(self, address, port, token): - # We rely on dictionaries keys() being in insertion order here. We - # can't just popitem() as that would be LIFO which is the opposite of - # what we want. - l = len(self._tokens) - if l >= MAX_SESSION_TICKETS: - keys_to_delete = list(self._tokens.keys())[0:SESSIONS_TO_DELETE] - for key in keys_to_delete: - del self._tokens[key] - self._tokens[(address, port)] = token - - -class AsyncQuicManager(BaseQuicManager): - def connect(self, address, port=853, source=None, source_port=0): - raise NotImplementedError diff --git a/backend/venv39/lib/python3.9/site-packages/dns/quic/_sync.py b/backend/venv39/lib/python3.9/site-packages/dns/quic/_sync.py deleted file mode 100644 index 473d1f4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/quic/_sync.py +++ /dev/null @@ -1,295 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import selectors -import socket -import ssl -import struct -import threading -import time - -import aioquic.quic.configuration # type: ignore -import aioquic.quic.connection # type: ignore -import aioquic.quic.events # type: ignore - -import dns.exception -import dns.inet -from dns.quic._common import ( - QUIC_MAX_DATAGRAM, - BaseQuicConnection, - BaseQuicManager, - BaseQuicStream, - UnexpectedEOF, -) - -# Function used to create a socket. Can be overridden if needed in special -# situations. -socket_factory = socket.socket - - -class SyncQuicStream(BaseQuicStream): - def __init__(self, connection, stream_id): - super().__init__(connection, stream_id) - self._wake_up = threading.Condition() - self._lock = threading.Lock() - - def wait_for(self, amount, expiration): - while True: - timeout = self._timeout_from_expiration(expiration) - with self._lock: - if self._buffer.have(amount): - return - self._expecting = amount - with self._wake_up: - if not self._wake_up.wait(timeout): - raise dns.exception.Timeout - self._expecting = 0 - - def wait_for_end(self, expiration): - while True: - timeout = self._timeout_from_expiration(expiration) - with self._lock: - if self._buffer.seen_end(): - return - with self._wake_up: - if not self._wake_up.wait(timeout): - raise dns.exception.Timeout - - def receive(self, timeout=None): - expiration = self._expiration_from_timeout(timeout) - if self._connection.is_h3(): - self.wait_for_end(expiration) - with self._lock: - return self._buffer.get_all() - else: - self.wait_for(2, expiration) - with self._lock: - (size,) = struct.unpack("!H", self._buffer.get(2)) - self.wait_for(size, expiration) - with self._lock: - return self._buffer.get(size) - - def send(self, datagram, is_end=False): - data = self._encapsulate(datagram) - self._connection.write(self._stream_id, data, is_end) - - def _add_input(self, data, is_end): - if self._common_add_input(data, is_end): - with self._wake_up: - self._wake_up.notify() - - def close(self): - with self._lock: - self._close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - with self._wake_up: - self._wake_up.notify() - return False - - -class SyncQuicConnection(BaseQuicConnection): - def __init__(self, connection, address, port, source, source_port, manager): - super().__init__(connection, address, port, source, source_port, manager) - self._socket = socket_factory(self._af, socket.SOCK_DGRAM, 0) - if self._source is not None: - try: - self._socket.bind( - dns.inet.low_level_address_tuple(self._source, self._af) - ) - except Exception: - self._socket.close() - raise - self._socket.connect(self._peer) - (self._send_wakeup, self._receive_wakeup) = socket.socketpair() - self._receive_wakeup.setblocking(False) - self._socket.setblocking(False) - self._handshake_complete = threading.Event() - self._worker_thread = None - self._lock = threading.Lock() - - def _read(self): - count = 0 - while count < 10: - count += 1 - try: - datagram = self._socket.recv(QUIC_MAX_DATAGRAM) - except BlockingIOError: - return - with self._lock: - self._connection.receive_datagram(datagram, self._peer, time.time()) - - def _drain_wakeup(self): - while True: - try: - self._receive_wakeup.recv(32) - except BlockingIOError: - return - - def _worker(self): - try: - sel = selectors.DefaultSelector() - sel.register(self._socket, selectors.EVENT_READ, self._read) - sel.register(self._receive_wakeup, selectors.EVENT_READ, self._drain_wakeup) - while not self._done: - (expiration, interval) = self._get_timer_values(False) - items = sel.select(interval) - for key, _ in items: - key.data() - with self._lock: - self._handle_timer(expiration) - self._handle_events() - with self._lock: - datagrams = self._connection.datagrams_to_send(time.time()) - for datagram, _ in datagrams: - try: - self._socket.send(datagram) - except BlockingIOError: - # we let QUIC handle any lossage - pass - finally: - with self._lock: - self._done = True - self._socket.close() - # Ensure anyone waiting for this gets woken up. - self._handshake_complete.set() - - def _handle_events(self): - while True: - with self._lock: - event = self._connection.next_event() - if event is None: - return - if isinstance(event, aioquic.quic.events.StreamDataReceived): - if self.is_h3(): - h3_events = self._h3_conn.handle_event(event) - for h3_event in h3_events: - if isinstance(h3_event, aioquic.h3.events.HeadersReceived): - with self._lock: - stream = self._streams.get(event.stream_id) - if stream: - if stream._headers is None: - stream._headers = h3_event.headers - elif stream._trailers is None: - stream._trailers = h3_event.headers - if h3_event.stream_ended: - stream._add_input(b"", True) - elif isinstance(h3_event, aioquic.h3.events.DataReceived): - with self._lock: - stream = self._streams.get(event.stream_id) - if stream: - stream._add_input(h3_event.data, h3_event.stream_ended) - else: - with self._lock: - stream = self._streams.get(event.stream_id) - if stream: - stream._add_input(event.data, event.end_stream) - elif isinstance(event, aioquic.quic.events.HandshakeCompleted): - self._handshake_complete.set() - elif isinstance(event, aioquic.quic.events.ConnectionTerminated): - with self._lock: - self._done = True - elif isinstance(event, aioquic.quic.events.StreamReset): - with self._lock: - stream = self._streams.get(event.stream_id) - if stream: - stream._add_input(b"", True) - - def write(self, stream, data, is_end=False): - with self._lock: - self._connection.send_stream_data(stream, data, is_end) - self._send_wakeup.send(b"\x01") - - def send_headers(self, stream_id, headers, is_end=False): - with self._lock: - super().send_headers(stream_id, headers, is_end) - if is_end: - self._send_wakeup.send(b"\x01") - - def send_data(self, stream_id, data, is_end=False): - with self._lock: - super().send_data(stream_id, data, is_end) - if is_end: - self._send_wakeup.send(b"\x01") - - def run(self): - if self._closed: - return - self._worker_thread = threading.Thread(target=self._worker) - self._worker_thread.start() - - def make_stream(self, timeout=None): - if not self._handshake_complete.wait(timeout): - raise dns.exception.Timeout - with self._lock: - if self._done: - raise UnexpectedEOF - stream_id = self._connection.get_next_available_stream_id(False) - stream = SyncQuicStream(self, stream_id) - self._streams[stream_id] = stream - return stream - - def close_stream(self, stream_id): - with self._lock: - super().close_stream(stream_id) - - def close(self): - with self._lock: - if self._closed: - return - self._manager.closed(self._peer[0], self._peer[1]) - self._closed = True - self._connection.close() - self._send_wakeup.send(b"\x01") - self._worker_thread.join() - - -class SyncQuicManager(BaseQuicManager): - def __init__( - self, conf=None, verify_mode=ssl.CERT_REQUIRED, server_name=None, h3=False - ): - super().__init__(conf, verify_mode, SyncQuicConnection, server_name, h3) - self._lock = threading.Lock() - - def connect( - self, - address, - port=853, - source=None, - source_port=0, - want_session_ticket=True, - want_token=True, - ): - with self._lock: - (connection, start) = self._connect( - address, port, source, source_port, want_session_ticket, want_token - ) - if start: - connection.run() - return connection - - def closed(self, address, port): - with self._lock: - super().closed(address, port) - - def save_session_ticket(self, address, port, ticket): - with self._lock: - super().save_session_ticket(address, port, ticket) - - def save_token(self, address, port, token): - with self._lock: - super().save_token(address, port, token) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - # Copy the iterator into a list as exiting things will mutate the connections - # table. - connections = list(self._connections.values()) - for connection in connections: - connection.close() - return False diff --git a/backend/venv39/lib/python3.9/site-packages/dns/quic/_trio.py b/backend/venv39/lib/python3.9/site-packages/dns/quic/_trio.py deleted file mode 100644 index ae79f36..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/quic/_trio.py +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import socket -import ssl -import struct -import time - -import aioquic.quic.configuration # type: ignore -import aioquic.quic.connection # type: ignore -import aioquic.quic.events # type: ignore -import trio - -import dns.exception -import dns.inet -from dns._asyncbackend import NullContext -from dns.quic._common import ( - QUIC_MAX_DATAGRAM, - AsyncQuicConnection, - AsyncQuicManager, - BaseQuicStream, - UnexpectedEOF, -) - - -class TrioQuicStream(BaseQuicStream): - def __init__(self, connection, stream_id): - super().__init__(connection, stream_id) - self._wake_up = trio.Condition() - - async def wait_for(self, amount): - while True: - if self._buffer.have(amount): - return - self._expecting = amount - async with self._wake_up: - await self._wake_up.wait() - self._expecting = 0 - - async def wait_for_end(self): - while True: - if self._buffer.seen_end(): - return - async with self._wake_up: - await self._wake_up.wait() - - async def receive(self, timeout=None): - if timeout is None: - context = NullContext(None) - else: - context = trio.move_on_after(timeout) - with context: - if self._connection.is_h3(): - await self.wait_for_end() - return self._buffer.get_all() - else: - await self.wait_for(2) - (size,) = struct.unpack("!H", self._buffer.get(2)) - await self.wait_for(size) - return self._buffer.get(size) - raise dns.exception.Timeout - - async def send(self, datagram, is_end=False): - data = self._encapsulate(datagram) - await self._connection.write(self._stream_id, data, is_end) - - async def _add_input(self, data, is_end): - if self._common_add_input(data, is_end): - async with self._wake_up: - self._wake_up.notify() - - async def close(self): - self._close() - - # Streams are async context managers - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - await self.close() - async with self._wake_up: - self._wake_up.notify() - return False - - -class TrioQuicConnection(AsyncQuicConnection): - def __init__(self, connection, address, port, source, source_port, manager=None): - super().__init__(connection, address, port, source, source_port, manager) - self._socket = trio.socket.socket(self._af, socket.SOCK_DGRAM, 0) - self._handshake_complete = trio.Event() - self._run_done = trio.Event() - self._worker_scope = None - self._send_pending = False - - async def _worker(self): - try: - if self._source: - await self._socket.bind( - dns.inet.low_level_address_tuple(self._source, self._af) - ) - await self._socket.connect(self._peer) - while not self._done: - (expiration, interval) = self._get_timer_values(False) - if self._send_pending: - # Do not block forever if sends are pending. Even though we - # have a wake-up mechanism if we've already started the blocking - # read, the possibility of context switching in send means that - # more writes can happen while we have no wake up context, so - # we need self._send_pending to avoid (effectively) a "lost wakeup" - # race. - interval = 0.0 - with trio.CancelScope( - deadline=trio.current_time() + interval - ) as self._worker_scope: - datagram = await self._socket.recv(QUIC_MAX_DATAGRAM) - self._connection.receive_datagram(datagram, self._peer, time.time()) - self._worker_scope = None - self._handle_timer(expiration) - await self._handle_events() - # We clear this now, before sending anything, as sending can cause - # context switches that do more sends. We want to know if that - # happens so we don't block a long time on the recv() above. - self._send_pending = False - datagrams = self._connection.datagrams_to_send(time.time()) - for datagram, _ in datagrams: - await self._socket.send(datagram) - finally: - self._done = True - self._socket.close() - self._handshake_complete.set() - - async def _handle_events(self): - count = 0 - while True: - event = self._connection.next_event() - if event is None: - return - if isinstance(event, aioquic.quic.events.StreamDataReceived): - if self.is_h3(): - h3_events = self._h3_conn.handle_event(event) - for h3_event in h3_events: - if isinstance(h3_event, aioquic.h3.events.HeadersReceived): - stream = self._streams.get(event.stream_id) - if stream: - if stream._headers is None: - stream._headers = h3_event.headers - elif stream._trailers is None: - stream._trailers = h3_event.headers - if h3_event.stream_ended: - await stream._add_input(b"", True) - elif isinstance(h3_event, aioquic.h3.events.DataReceived): - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input( - h3_event.data, h3_event.stream_ended - ) - else: - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input(event.data, event.end_stream) - elif isinstance(event, aioquic.quic.events.HandshakeCompleted): - self._handshake_complete.set() - elif isinstance(event, aioquic.quic.events.ConnectionTerminated): - self._done = True - self._socket.close() - elif isinstance(event, aioquic.quic.events.StreamReset): - stream = self._streams.get(event.stream_id) - if stream: - await stream._add_input(b"", True) - count += 1 - if count > 10: - # yield - count = 0 - await trio.sleep(0) - - async def write(self, stream, data, is_end=False): - self._connection.send_stream_data(stream, data, is_end) - self._send_pending = True - if self._worker_scope is not None: - self._worker_scope.cancel() - - async def run(self): - if self._closed: - return - async with trio.open_nursery() as nursery: - nursery.start_soon(self._worker) - self._run_done.set() - - async def make_stream(self, timeout=None): - if timeout is None: - context = NullContext(None) - else: - context = trio.move_on_after(timeout) - with context: - await self._handshake_complete.wait() - if self._done: - raise UnexpectedEOF - stream_id = self._connection.get_next_available_stream_id(False) - stream = TrioQuicStream(self, stream_id) - self._streams[stream_id] = stream - return stream - raise dns.exception.Timeout - - async def close(self): - if not self._closed: - self._manager.closed(self._peer[0], self._peer[1]) - self._closed = True - self._connection.close() - self._send_pending = True - if self._worker_scope is not None: - self._worker_scope.cancel() - await self._run_done.wait() - - -class TrioQuicManager(AsyncQuicManager): - def __init__( - self, - nursery, - conf=None, - verify_mode=ssl.CERT_REQUIRED, - server_name=None, - h3=False, - ): - super().__init__(conf, verify_mode, TrioQuicConnection, server_name, h3) - self._nursery = nursery - - def connect( - self, address, port=853, source=None, source_port=0, want_session_ticket=True - ): - (connection, start) = self._connect( - address, port, source, source_port, want_session_ticket - ) - if start: - self._nursery.start_soon(connection.run) - return connection - - async def __aenter__(self): - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - # Copy the iterator into a list as exiting things will mutate the connections - # table. - connections = list(self._connections.values()) - for connection in connections: - await connection.close() - return False diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rcode.py b/backend/venv39/lib/python3.9/site-packages/dns/rcode.py deleted file mode 100644 index 8e6386f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rcode.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Result Codes.""" - -from typing import Tuple - -import dns.enum -import dns.exception - - -class Rcode(dns.enum.IntEnum): - #: No error - NOERROR = 0 - #: Format error - FORMERR = 1 - #: Server failure - SERVFAIL = 2 - #: Name does not exist ("Name Error" in RFC 1025 terminology). - NXDOMAIN = 3 - #: Not implemented - NOTIMP = 4 - #: Refused - REFUSED = 5 - #: Name exists. - YXDOMAIN = 6 - #: RRset exists. - YXRRSET = 7 - #: RRset does not exist. - NXRRSET = 8 - #: Not authoritative. - NOTAUTH = 9 - #: Name not in zone. - NOTZONE = 10 - #: DSO-TYPE Not Implemented - DSOTYPENI = 11 - #: Bad EDNS version. - BADVERS = 16 - #: TSIG Signature Failure - BADSIG = 16 - #: Key not recognized. - BADKEY = 17 - #: Signature out of time window. - BADTIME = 18 - #: Bad TKEY Mode. - BADMODE = 19 - #: Duplicate key name. - BADNAME = 20 - #: Algorithm not supported. - BADALG = 21 - #: Bad Truncation - BADTRUNC = 22 - #: Bad/missing Server Cookie - BADCOOKIE = 23 - - @classmethod - def _maximum(cls): - return 4095 - - @classmethod - def _unknown_exception_class(cls): - return UnknownRcode - - -class UnknownRcode(dns.exception.DNSException): - """A DNS rcode is unknown.""" - - -def from_text(text: str) -> Rcode: - """Convert text into an rcode. - - *text*, a ``str``, the textual rcode or an integer in textual form. - - Raises ``dns.rcode.UnknownRcode`` if the rcode mnemonic is unknown. - - Returns a ``dns.rcode.Rcode``. - """ - - return Rcode.from_text(text) - - -def from_flags(flags: int, ednsflags: int) -> Rcode: - """Return the rcode value encoded by flags and ednsflags. - - *flags*, an ``int``, the DNS flags field. - - *ednsflags*, an ``int``, the EDNS flags field. - - Raises ``ValueError`` if rcode is < 0 or > 4095 - - Returns a ``dns.rcode.Rcode``. - """ - - value = (flags & 0x000F) | ((ednsflags >> 20) & 0xFF0) - return Rcode.make(value) - - -def to_flags(value: Rcode) -> Tuple[int, int]: - """Return a (flags, ednsflags) tuple which encodes the rcode. - - *value*, a ``dns.rcode.Rcode``, the rcode. - - Raises ``ValueError`` if rcode is < 0 or > 4095. - - Returns an ``(int, int)`` tuple. - """ - - if value < 0 or value > 4095: - raise ValueError("rcode must be >= 0 and <= 4095") - v = value & 0xF - ev = (value & 0xFF0) << 20 - return (v, ev) - - -def to_text(value: Rcode, tsig: bool = False) -> str: - """Convert rcode into text. - - *value*, a ``dns.rcode.Rcode``, the rcode. - - Raises ``ValueError`` if rcode is < 0 or > 4095. - - Returns a ``str``. - """ - - if tsig and value == Rcode.BADVERS: - return "BADSIG" - return Rcode.to_text(value) - - -### BEGIN generated Rcode constants - -NOERROR = Rcode.NOERROR -FORMERR = Rcode.FORMERR -SERVFAIL = Rcode.SERVFAIL -NXDOMAIN = Rcode.NXDOMAIN -NOTIMP = Rcode.NOTIMP -REFUSED = Rcode.REFUSED -YXDOMAIN = Rcode.YXDOMAIN -YXRRSET = Rcode.YXRRSET -NXRRSET = Rcode.NXRRSET -NOTAUTH = Rcode.NOTAUTH -NOTZONE = Rcode.NOTZONE -DSOTYPENI = Rcode.DSOTYPENI -BADVERS = Rcode.BADVERS -BADSIG = Rcode.BADSIG -BADKEY = Rcode.BADKEY -BADTIME = Rcode.BADTIME -BADMODE = Rcode.BADMODE -BADNAME = Rcode.BADNAME -BADALG = Rcode.BADALG -BADTRUNC = Rcode.BADTRUNC -BADCOOKIE = Rcode.BADCOOKIE - -### END generated Rcode constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdata.py b/backend/venv39/lib/python3.9/site-packages/dns/rdata.py deleted file mode 100644 index 8099c26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdata.py +++ /dev/null @@ -1,911 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdata.""" - -import base64 -import binascii -import inspect -import io -import itertools -import random -from importlib import import_module -from typing import Any, Dict, Optional, Tuple, Union - -import dns.exception -import dns.immutable -import dns.ipv4 -import dns.ipv6 -import dns.name -import dns.rdataclass -import dns.rdatatype -import dns.tokenizer -import dns.ttl -import dns.wire - -_chunksize = 32 - -# We currently allow comparisons for rdata with relative names for backwards -# compatibility, but in the future we will not, as these kinds of comparisons -# can lead to subtle bugs if code is not carefully written. -# -# This switch allows the future behavior to be turned on so code can be -# tested with it. -_allow_relative_comparisons = True - - -class NoRelativeRdataOrdering(dns.exception.DNSException): - """An attempt was made to do an ordered comparison of one or more - rdata with relative names. The only reliable way of sorting rdata - is to use non-relativized rdata. - - """ - - -def _wordbreak(data, chunksize=_chunksize, separator=b" "): - """Break a binary string into chunks of chunksize characters separated by - a space. - """ - - if not chunksize: - return data.decode() - return separator.join( - [data[i : i + chunksize] for i in range(0, len(data), chunksize)] - ).decode() - - -# pylint: disable=unused-argument - - -def _hexify(data, chunksize=_chunksize, separator=b" ", **kw): - """Convert a binary string into its hex encoding, broken up into chunks - of chunksize characters separated by a separator. - """ - - return _wordbreak(binascii.hexlify(data), chunksize, separator) - - -def _base64ify(data, chunksize=_chunksize, separator=b" ", **kw): - """Convert a binary string into its base64 encoding, broken up into chunks - of chunksize characters separated by a separator. - """ - - return _wordbreak(base64.b64encode(data), chunksize, separator) - - -# pylint: enable=unused-argument - -__escaped = b'"\\' - - -def _escapify(qstring): - """Escape the characters in a quoted string which need it.""" - - if isinstance(qstring, str): - qstring = qstring.encode() - if not isinstance(qstring, bytearray): - qstring = bytearray(qstring) - - text = "" - for c in qstring: - if c in __escaped: - text += "\\" + chr(c) - elif c >= 0x20 and c < 0x7F: - text += chr(c) - else: - text += "\\%03d" % c - return text - - -def _truncate_bitmap(what): - """Determine the index of greatest byte that isn't all zeros, and - return the bitmap that contains all the bytes less than that index. - """ - - for i in range(len(what) - 1, -1, -1): - if what[i] != 0: - return what[0 : i + 1] - return what[0:1] - - -# So we don't have to edit all the rdata classes... -_constify = dns.immutable.constify - - -@dns.immutable.immutable -class Rdata: - """Base class for all DNS rdata types.""" - - __slots__ = ["rdclass", "rdtype", "rdcomment"] - - def __init__(self, rdclass, rdtype): - """Initialize an rdata. - - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - """ - - self.rdclass = self._as_rdataclass(rdclass) - self.rdtype = self._as_rdatatype(rdtype) - self.rdcomment = None - - def _get_all_slots(self): - return itertools.chain.from_iterable( - getattr(cls, "__slots__", []) for cls in self.__class__.__mro__ - ) - - def __getstate__(self): - # We used to try to do a tuple of all slots here, but it - # doesn't work as self._all_slots isn't available at - # __setstate__() time. Before that we tried to store a tuple - # of __slots__, but that didn't work as it didn't store the - # slots defined by ancestors. This older way didn't fail - # outright, but ended up with partially broken objects, e.g. - # if you unpickled an A RR it wouldn't have rdclass and rdtype - # attributes, and would compare badly. - state = {} - for slot in self._get_all_slots(): - state[slot] = getattr(self, slot) - return state - - def __setstate__(self, state): - for slot, val in state.items(): - object.__setattr__(self, slot, val) - if not hasattr(self, "rdcomment"): - # Pickled rdata from 2.0.x might not have a rdcomment, so add - # it if needed. - object.__setattr__(self, "rdcomment", None) - - def covers(self) -> dns.rdatatype.RdataType: - """Return the type a Rdata covers. - - DNS SIG/RRSIG rdatas apply to a specific type; this type is - returned by the covers() function. If the rdata type is not - SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when - creating rdatasets, allowing the rdataset to contain only RRSIGs - of a particular type, e.g. RRSIG(NS). - - Returns a ``dns.rdatatype.RdataType``. - """ - - return dns.rdatatype.NONE - - def extended_rdatatype(self) -> int: - """Return a 32-bit type value, the least significant 16 bits of - which are the ordinary DNS type, and the upper 16 bits of which are - the "covered" type, if any. - - Returns an ``int``. - """ - - return self.covers() << 16 | self.rdtype - - def to_text( - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - **kw: Dict[str, Any], - ) -> str: - """Convert an rdata to text format. - - Returns a ``str``. - """ - - raise NotImplementedError # pragma: no cover - - def _to_wire( - self, - file: Optional[Any], - compress: Optional[dns.name.CompressType] = None, - origin: Optional[dns.name.Name] = None, - canonicalize: bool = False, - ) -> None: - raise NotImplementedError # pragma: no cover - - def to_wire( - self, - file: Optional[Any] = None, - compress: Optional[dns.name.CompressType] = None, - origin: Optional[dns.name.Name] = None, - canonicalize: bool = False, - ) -> Optional[bytes]: - """Convert an rdata to wire format. - - Returns a ``bytes`` if no output file was specified, or ``None`` otherwise. - """ - - if file: - # We call _to_wire() and then return None explicitly instead of - # of just returning the None from _to_wire() as mypy's func-returns-value - # unhelpfully errors out with "error: "_to_wire" of "Rdata" does not return - # a value (it only ever returns None)" - self._to_wire(file, compress, origin, canonicalize) - return None - else: - f = io.BytesIO() - self._to_wire(f, compress, origin, canonicalize) - return f.getvalue() - - def to_generic( - self, origin: Optional[dns.name.Name] = None - ) -> "dns.rdata.GenericRdata": - """Creates a dns.rdata.GenericRdata equivalent of this rdata. - - Returns a ``dns.rdata.GenericRdata``. - """ - return dns.rdata.GenericRdata( - self.rdclass, self.rdtype, self.to_wire(origin=origin) - ) - - def to_digestable(self, origin: Optional[dns.name.Name] = None) -> bytes: - """Convert rdata to a format suitable for digesting in hashes. This - is also the DNSSEC canonical form. - - Returns a ``bytes``. - """ - wire = self.to_wire(origin=origin, canonicalize=True) - assert wire is not None # for mypy - return wire - - def __repr__(self): - covers = self.covers() - if covers == dns.rdatatype.NONE: - ctext = "" - else: - ctext = "(" + dns.rdatatype.to_text(covers) + ")" - return ( - "" - ) - - def __str__(self): - return self.to_text() - - def _cmp(self, other): - """Compare an rdata with another rdata of the same rdtype and - rdclass. - - For rdata with only absolute names: - Return < 0 if self < other in the DNSSEC ordering, 0 if self - == other, and > 0 if self > other. - For rdata with at least one relative names: - The rdata sorts before any rdata with only absolute names. - When compared with another relative rdata, all names are - made absolute as if they were relative to the root, as the - proper origin is not available. While this creates a stable - ordering, it is NOT guaranteed to be the DNSSEC ordering. - In the future, all ordering comparisons for rdata with - relative names will be disallowed. - """ - try: - our = self.to_digestable() - our_relative = False - except dns.name.NeedAbsoluteNameOrOrigin: - if _allow_relative_comparisons: - our = self.to_digestable(dns.name.root) - our_relative = True - try: - their = other.to_digestable() - their_relative = False - except dns.name.NeedAbsoluteNameOrOrigin: - if _allow_relative_comparisons: - their = other.to_digestable(dns.name.root) - their_relative = True - if _allow_relative_comparisons: - if our_relative != their_relative: - # For the purpose of comparison, all rdata with at least one - # relative name is less than an rdata with only absolute names. - if our_relative: - return -1 - else: - return 1 - elif our_relative or their_relative: - raise NoRelativeRdataOrdering - if our == their: - return 0 - elif our > their: - return 1 - else: - return -1 - - def __eq__(self, other): - if not isinstance(other, Rdata): - return False - if self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return False - our_relative = False - their_relative = False - try: - our = self.to_digestable() - except dns.name.NeedAbsoluteNameOrOrigin: - our = self.to_digestable(dns.name.root) - our_relative = True - try: - their = other.to_digestable() - except dns.name.NeedAbsoluteNameOrOrigin: - their = other.to_digestable(dns.name.root) - their_relative = True - if our_relative != their_relative: - return False - return our == their - - def __ne__(self, other): - if not isinstance(other, Rdata): - return True - if self.rdclass != other.rdclass or self.rdtype != other.rdtype: - return True - return not self.__eq__(other) - - def __lt__(self, other): - if ( - not isinstance(other, Rdata) - or self.rdclass != other.rdclass - or self.rdtype != other.rdtype - ): - return NotImplemented - return self._cmp(other) < 0 - - def __le__(self, other): - if ( - not isinstance(other, Rdata) - or self.rdclass != other.rdclass - or self.rdtype != other.rdtype - ): - return NotImplemented - return self._cmp(other) <= 0 - - def __ge__(self, other): - if ( - not isinstance(other, Rdata) - or self.rdclass != other.rdclass - or self.rdtype != other.rdtype - ): - return NotImplemented - return self._cmp(other) >= 0 - - def __gt__(self, other): - if ( - not isinstance(other, Rdata) - or self.rdclass != other.rdclass - or self.rdtype != other.rdtype - ): - return NotImplemented - return self._cmp(other) > 0 - - def __hash__(self): - return hash(self.to_digestable(dns.name.root)) - - @classmethod - def from_text( - cls, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - tok: dns.tokenizer.Tokenizer, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, - ) -> "Rdata": - raise NotImplementedError # pragma: no cover - - @classmethod - def from_wire_parser( - cls, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - parser: dns.wire.Parser, - origin: Optional[dns.name.Name] = None, - ) -> "Rdata": - raise NotImplementedError # pragma: no cover - - def replace(self, **kwargs: Any) -> "Rdata": - """ - Create a new Rdata instance based on the instance replace was - invoked on. It is possible to pass different parameters to - override the corresponding properties of the base Rdata. - - Any field specific to the Rdata type can be replaced, but the - *rdtype* and *rdclass* fields cannot. - - Returns an instance of the same Rdata subclass as *self*. - """ - - # Get the constructor parameters. - parameters = inspect.signature(self.__init__).parameters # type: ignore - - # Ensure that all of the arguments correspond to valid fields. - # Don't allow rdclass or rdtype to be changed, though. - for key in kwargs: - if key == "rdcomment": - continue - if key not in parameters: - raise AttributeError( - f"'{self.__class__.__name__}' object has no attribute '{key}'" - ) - if key in ("rdclass", "rdtype"): - raise AttributeError( - f"Cannot overwrite '{self.__class__.__name__}' attribute '{key}'" - ) - - # Construct the parameter list. For each field, use the value in - # kwargs if present, and the current value otherwise. - args = (kwargs.get(key, getattr(self, key)) for key in parameters) - - # Create, validate, and return the new object. - rd = self.__class__(*args) - # The comment is not set in the constructor, so give it special - # handling. - rdcomment = kwargs.get("rdcomment", self.rdcomment) - if rdcomment is not None: - object.__setattr__(rd, "rdcomment", rdcomment) - return rd - - # Type checking and conversion helpers. These are class methods as - # they don't touch object state and may be useful to others. - - @classmethod - def _as_rdataclass(cls, value): - return dns.rdataclass.RdataClass.make(value) - - @classmethod - def _as_rdatatype(cls, value): - return dns.rdatatype.RdataType.make(value) - - @classmethod - def _as_bytes( - cls, - value: Any, - encode: bool = False, - max_length: Optional[int] = None, - empty_ok: bool = True, - ) -> bytes: - if encode and isinstance(value, str): - bvalue = value.encode() - elif isinstance(value, bytearray): - bvalue = bytes(value) - elif isinstance(value, bytes): - bvalue = value - else: - raise ValueError("not bytes") - if max_length is not None and len(bvalue) > max_length: - raise ValueError("too long") - if not empty_ok and len(bvalue) == 0: - raise ValueError("empty bytes not allowed") - return bvalue - - @classmethod - def _as_name(cls, value): - # Note that proper name conversion (e.g. with origin and IDNA - # awareness) is expected to be done via from_text. This is just - # a simple thing for people invoking the constructor directly. - if isinstance(value, str): - return dns.name.from_text(value) - elif not isinstance(value, dns.name.Name): - raise ValueError("not a name") - return value - - @classmethod - def _as_uint8(cls, value): - if not isinstance(value, int): - raise ValueError("not an integer") - if value < 0 or value > 255: - raise ValueError("not a uint8") - return value - - @classmethod - def _as_uint16(cls, value): - if not isinstance(value, int): - raise ValueError("not an integer") - if value < 0 or value > 65535: - raise ValueError("not a uint16") - return value - - @classmethod - def _as_uint32(cls, value): - if not isinstance(value, int): - raise ValueError("not an integer") - if value < 0 or value > 4294967295: - raise ValueError("not a uint32") - return value - - @classmethod - def _as_uint48(cls, value): - if not isinstance(value, int): - raise ValueError("not an integer") - if value < 0 or value > 281474976710655: - raise ValueError("not a uint48") - return value - - @classmethod - def _as_int(cls, value, low=None, high=None): - if not isinstance(value, int): - raise ValueError("not an integer") - if low is not None and value < low: - raise ValueError("value too small") - if high is not None and value > high: - raise ValueError("value too large") - return value - - @classmethod - def _as_ipv4_address(cls, value): - if isinstance(value, str): - return dns.ipv4.canonicalize(value) - elif isinstance(value, bytes): - return dns.ipv4.inet_ntoa(value) - else: - raise ValueError("not an IPv4 address") - - @classmethod - def _as_ipv6_address(cls, value): - if isinstance(value, str): - return dns.ipv6.canonicalize(value) - elif isinstance(value, bytes): - return dns.ipv6.inet_ntoa(value) - else: - raise ValueError("not an IPv6 address") - - @classmethod - def _as_bool(cls, value): - if isinstance(value, bool): - return value - else: - raise ValueError("not a boolean") - - @classmethod - def _as_ttl(cls, value): - if isinstance(value, int): - return cls._as_int(value, 0, dns.ttl.MAX_TTL) - elif isinstance(value, str): - return dns.ttl.from_text(value) - else: - raise ValueError("not a TTL") - - @classmethod - def _as_tuple(cls, value, as_value): - try: - # For user convenience, if value is a singleton of the list - # element type, wrap it in a tuple. - return (as_value(value),) - except Exception: - # Otherwise, check each element of the iterable *value* - # against *as_value*. - return tuple(as_value(v) for v in value) - - # Processing order - - @classmethod - def _processing_order(cls, iterable): - items = list(iterable) - random.shuffle(items) - return items - - -@dns.immutable.immutable -class GenericRdata(Rdata): - """Generic Rdata Class - - This class is used for rdata types for which we have no better - implementation. It implements the DNS "unknown RRs" scheme. - """ - - __slots__ = ["data"] - - def __init__(self, rdclass, rdtype, data): - super().__init__(rdclass, rdtype) - self.data = data - - def to_text( - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - **kw: Dict[str, Any], - ) -> str: - return r"\# %d " % len(self.data) + _hexify(self.data, **kw) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - token = tok.get() - if not token.is_identifier() or token.value != r"\#": - raise dns.exception.SyntaxError(r"generic rdata does not start with \#") - length = tok.get_int() - hex = tok.concatenate_remaining_identifiers(True).encode() - data = binascii.unhexlify(hex) - if len(data) != length: - raise dns.exception.SyntaxError("generic rdata hex data has wrong length") - return cls(rdclass, rdtype, data) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(self.data) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - return cls(rdclass, rdtype, parser.get_remaining()) - - -_rdata_classes: Dict[Tuple[dns.rdataclass.RdataClass, dns.rdatatype.RdataType], Any] = ( - {} -) -_module_prefix = "dns.rdtypes" -_dynamic_load_allowed = True - - -def get_rdata_class(rdclass, rdtype, use_generic=True): - cls = _rdata_classes.get((rdclass, rdtype)) - if not cls: - cls = _rdata_classes.get((dns.rdatatype.ANY, rdtype)) - if not cls and _dynamic_load_allowed: - rdclass_text = dns.rdataclass.to_text(rdclass) - rdtype_text = dns.rdatatype.to_text(rdtype) - rdtype_text = rdtype_text.replace("-", "_") - try: - mod = import_module( - ".".join([_module_prefix, rdclass_text, rdtype_text]) - ) - cls = getattr(mod, rdtype_text) - _rdata_classes[(rdclass, rdtype)] = cls - except ImportError: - try: - mod = import_module(".".join([_module_prefix, "ANY", rdtype_text])) - cls = getattr(mod, rdtype_text) - _rdata_classes[(dns.rdataclass.ANY, rdtype)] = cls - _rdata_classes[(rdclass, rdtype)] = cls - except ImportError: - pass - if not cls and use_generic: - cls = GenericRdata - _rdata_classes[(rdclass, rdtype)] = cls - return cls - - -def load_all_types(disable_dynamic_load=True): - """Load all rdata types for which dnspython has a non-generic implementation. - - Normally dnspython loads DNS rdatatype implementations on demand, but in some - specialized cases loading all types at an application-controlled time is preferred. - - If *disable_dynamic_load*, a ``bool``, is ``True`` then dnspython will not attempt - to use its dynamic loading mechanism if an unknown type is subsequently encountered, - and will simply use the ``GenericRdata`` class. - """ - # Load class IN and ANY types. - for rdtype in dns.rdatatype.RdataType: - get_rdata_class(dns.rdataclass.IN, rdtype, False) - # Load the one non-ANY implementation we have in CH. Everything - # else in CH is an ANY type, and we'll discover those on demand but won't - # have to import anything. - get_rdata_class(dns.rdataclass.CH, dns.rdatatype.A, False) - if disable_dynamic_load: - # Now disable dynamic loading so any subsequent unknown type immediately becomes - # GenericRdata without a load attempt. - global _dynamic_load_allowed - _dynamic_load_allowed = False - - -def from_text( - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - tok: Union[dns.tokenizer.Tokenizer, str], - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, - idna_codec: Optional[dns.name.IDNACodec] = None, -) -> Rdata: - """Build an rdata object from text format. - - This function attempts to dynamically load a class which - implements the specified rdata class and type. If there is no - class-and-type-specific implementation, the GenericRdata class - is used. - - Once a class is chosen, its from_text() class method is called - with the parameters to this function. - - If *tok* is a ``str``, then a tokenizer is created and the string - is used as its input. - - *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype. - - *tok*, a ``dns.tokenizer.Tokenizer`` or a ``str``. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use if a tokenizer needs to be created. If - ``None``, the default IDNA 2003 encoder/decoder is used. If a - tokenizer is not created, then the codec associated with the tokenizer - is the one that is used. - - Returns an instance of the chosen Rdata subclass. - - """ - if isinstance(tok, str): - tok = dns.tokenizer.Tokenizer(tok, idna_codec=idna_codec) - rdclass = dns.rdataclass.RdataClass.make(rdclass) - rdtype = dns.rdatatype.RdataType.make(rdtype) - cls = get_rdata_class(rdclass, rdtype) - with dns.exception.ExceptionWrapper(dns.exception.SyntaxError): - rdata = None - if cls != GenericRdata: - # peek at first token - token = tok.get() - tok.unget(token) - if token.is_identifier() and token.value == r"\#": - # - # Known type using the generic syntax. Extract the - # wire form from the generic syntax, and then run - # from_wire on it. - # - grdata = GenericRdata.from_text( - rdclass, rdtype, tok, origin, relativize, relativize_to - ) - rdata = from_wire( - rdclass, rdtype, grdata.data, 0, len(grdata.data), origin - ) - # - # If this comparison isn't equal, then there must have been - # compressed names in the wire format, which is an error, - # there being no reasonable context to decompress with. - # - rwire = rdata.to_wire() - if rwire != grdata.data: - raise dns.exception.SyntaxError( - "compressed data in " - "generic syntax form " - "of known rdatatype" - ) - if rdata is None: - rdata = cls.from_text( - rdclass, rdtype, tok, origin, relativize, relativize_to - ) - token = tok.get_eol_as_token() - if token.comment is not None: - object.__setattr__(rdata, "rdcomment", token.comment) - return rdata - - -def from_wire_parser( - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - parser: dns.wire.Parser, - origin: Optional[dns.name.Name] = None, -) -> Rdata: - """Build an rdata object from wire format - - This function attempts to dynamically load a class which - implements the specified rdata class and type. If there is no - class-and-type-specific implementation, the GenericRdata class - is used. - - Once a class is chosen, its from_wire() class method is called - with the parameters to this function. - - *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype. - - *parser*, a ``dns.wire.Parser``, the parser, which should be - restricted to the rdata length. - - *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``, - then names will be relativized to this origin. - - Returns an instance of the chosen Rdata subclass. - """ - - rdclass = dns.rdataclass.RdataClass.make(rdclass) - rdtype = dns.rdatatype.RdataType.make(rdtype) - cls = get_rdata_class(rdclass, rdtype) - with dns.exception.ExceptionWrapper(dns.exception.FormError): - return cls.from_wire_parser(rdclass, rdtype, parser, origin) - - -def from_wire( - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - wire: bytes, - current: int, - rdlen: int, - origin: Optional[dns.name.Name] = None, -) -> Rdata: - """Build an rdata object from wire format - - This function attempts to dynamically load a class which - implements the specified rdata class and type. If there is no - class-and-type-specific implementation, the GenericRdata class - is used. - - Once a class is chosen, its from_wire() class method is called - with the parameters to this function. - - *rdclass*, an ``int``, the rdataclass. - - *rdtype*, an ``int``, the rdatatype. - - *wire*, a ``bytes``, the wire-format message. - - *current*, an ``int``, the offset in wire of the beginning of - the rdata. - - *rdlen*, an ``int``, the length of the wire-format rdata - - *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``, - then names will be relativized to this origin. - - Returns an instance of the chosen Rdata subclass. - """ - parser = dns.wire.Parser(wire, current) - with parser.restrict_to(rdlen): - return from_wire_parser(rdclass, rdtype, parser, origin) - - -class RdatatypeExists(dns.exception.DNSException): - """DNS rdatatype already exists.""" - - supp_kwargs = {"rdclass", "rdtype"} - fmt = ( - "The rdata type with class {rdclass:d} and rdtype {rdtype:d} " - + "already exists." - ) - - -def register_type( - implementation: Any, - rdtype: int, - rdtype_text: str, - is_singleton: bool = False, - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, -) -> None: - """Dynamically register a module to handle an rdatatype. - - *implementation*, a module implementing the type in the usual dnspython - way. - - *rdtype*, an ``int``, the rdatatype to register. - - *rdtype_text*, a ``str``, the textual form of the rdatatype. - - *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e. - RRsets of the type can have only one member.) - - *rdclass*, the rdataclass of the type, or ``dns.rdataclass.ANY`` if - it applies to all classes. - """ - - rdtype = dns.rdatatype.RdataType.make(rdtype) - existing_cls = get_rdata_class(rdclass, rdtype) - if existing_cls != GenericRdata or dns.rdatatype.is_metatype(rdtype): - raise RdatatypeExists(rdclass=rdclass, rdtype=rdtype) - _rdata_classes[(rdclass, rdtype)] = getattr( - implementation, rdtype_text.replace("-", "_") - ) - dns.rdatatype.register_type(rdtype, rdtype_text, is_singleton) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdataclass.py b/backend/venv39/lib/python3.9/site-packages/dns/rdataclass.py deleted file mode 100644 index 89b85a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdataclass.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Rdata Classes.""" - -import dns.enum -import dns.exception - - -class RdataClass(dns.enum.IntEnum): - """DNS Rdata Class""" - - RESERVED0 = 0 - IN = 1 - INTERNET = IN - CH = 3 - CHAOS = CH - HS = 4 - HESIOD = HS - NONE = 254 - ANY = 255 - - @classmethod - def _maximum(cls): - return 65535 - - @classmethod - def _short_name(cls): - return "class" - - @classmethod - def _prefix(cls): - return "CLASS" - - @classmethod - def _unknown_exception_class(cls): - return UnknownRdataclass - - -_metaclasses = {RdataClass.NONE, RdataClass.ANY} - - -class UnknownRdataclass(dns.exception.DNSException): - """A DNS class is unknown.""" - - -def from_text(text: str) -> RdataClass: - """Convert text into a DNS rdata class value. - - The input text can be a defined DNS RR class mnemonic or - instance of the DNS generic class syntax. - - For example, "IN" and "CLASS1" will both result in a value of 1. - - Raises ``dns.rdatatype.UnknownRdataclass`` if the class is unknown. - - Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535. - - Returns a ``dns.rdataclass.RdataClass``. - """ - - return RdataClass.from_text(text) - - -def to_text(value: RdataClass) -> str: - """Convert a DNS rdata class value to text. - - If the value has a known mnemonic, it will be used, otherwise the - DNS generic class syntax will be used. - - Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535. - - Returns a ``str``. - """ - - return RdataClass.to_text(value) - - -def is_metaclass(rdclass: RdataClass) -> bool: - """True if the specified class is a metaclass. - - The currently defined metaclasses are ANY and NONE. - - *rdclass* is a ``dns.rdataclass.RdataClass``. - """ - - if rdclass in _metaclasses: - return True - return False - - -### BEGIN generated RdataClass constants - -RESERVED0 = RdataClass.RESERVED0 -IN = RdataClass.IN -INTERNET = RdataClass.INTERNET -CH = RdataClass.CH -CHAOS = RdataClass.CHAOS -HS = RdataClass.HS -HESIOD = RdataClass.HESIOD -NONE = RdataClass.NONE -ANY = RdataClass.ANY - -### END generated RdataClass constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdataset.py b/backend/venv39/lib/python3.9/site-packages/dns/rdataset.py deleted file mode 100644 index 39cab23..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdataset.py +++ /dev/null @@ -1,512 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)""" - -import io -import random -import struct -from typing import Any, Collection, Dict, List, Optional, Union, cast - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdataclass -import dns.rdatatype -import dns.renderer -import dns.set -import dns.ttl - -# define SimpleSet here for backwards compatibility -SimpleSet = dns.set.Set - - -class DifferingCovers(dns.exception.DNSException): - """An attempt was made to add a DNS SIG/RRSIG whose covered type - is not the same as that of the other rdatas in the rdataset.""" - - -class IncompatibleTypes(dns.exception.DNSException): - """An attempt was made to add DNS RR data of an incompatible type.""" - - -class Rdataset(dns.set.Set): - """A DNS rdataset.""" - - __slots__ = ["rdclass", "rdtype", "covers", "ttl"] - - def __init__( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - ttl: int = 0, - ): - """Create a new rdataset of the specified class and type. - - *rdclass*, a ``dns.rdataclass.RdataClass``, the rdataclass. - - *rdtype*, an ``dns.rdatatype.RdataType``, the rdatatype. - - *covers*, an ``dns.rdatatype.RdataType``, the covered rdatatype. - - *ttl*, an ``int``, the TTL. - """ - - super().__init__() - self.rdclass = rdclass - self.rdtype: dns.rdatatype.RdataType = rdtype - self.covers: dns.rdatatype.RdataType = covers - self.ttl = ttl - - def _clone(self): - obj = super()._clone() - obj.rdclass = self.rdclass - obj.rdtype = self.rdtype - obj.covers = self.covers - obj.ttl = self.ttl - return obj - - def update_ttl(self, ttl: int) -> None: - """Perform TTL minimization. - - Set the TTL of the rdataset to be the lesser of the set's current - TTL or the specified TTL. If the set contains no rdatas, set the TTL - to the specified TTL. - - *ttl*, an ``int`` or ``str``. - """ - ttl = dns.ttl.make(ttl) - if len(self) == 0: - self.ttl = ttl - elif ttl < self.ttl: - self.ttl = ttl - - def add( # pylint: disable=arguments-differ,arguments-renamed - self, rd: dns.rdata.Rdata, ttl: Optional[int] = None - ) -> None: - """Add the specified rdata to the rdataset. - - If the optional *ttl* parameter is supplied, then - ``self.update_ttl(ttl)`` will be called prior to adding the rdata. - - *rd*, a ``dns.rdata.Rdata``, the rdata - - *ttl*, an ``int``, the TTL. - - Raises ``dns.rdataset.IncompatibleTypes`` if the type and class - do not match the type and class of the rdataset. - - Raises ``dns.rdataset.DifferingCovers`` if the type is a signature - type and the covered type does not match that of the rdataset. - """ - - # - # If we're adding a signature, do some special handling to - # check that the signature covers the same type as the - # other rdatas in this rdataset. If this is the first rdata - # in the set, initialize the covers field. - # - if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype: - raise IncompatibleTypes - if ttl is not None: - self.update_ttl(ttl) - if self.rdtype == dns.rdatatype.RRSIG or self.rdtype == dns.rdatatype.SIG: - covers = rd.covers() - if len(self) == 0 and self.covers == dns.rdatatype.NONE: - self.covers = covers - elif self.covers != covers: - raise DifferingCovers - if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0: - self.clear() - super().add(rd) - - def union_update(self, other): - self.update_ttl(other.ttl) - super().union_update(other) - - def intersection_update(self, other): - self.update_ttl(other.ttl) - super().intersection_update(other) - - def update(self, other): - """Add all rdatas in other to self. - - *other*, a ``dns.rdataset.Rdataset``, the rdataset from which - to update. - """ - - self.update_ttl(other.ttl) - super().update(other) - - def _rdata_repr(self): - def maybe_truncate(s): - if len(s) > 100: - return s[:100] + "..." - return s - - return "[" + ", ".join(f"<{maybe_truncate(str(rr))}>" for rr in self) + "]" - - def __repr__(self): - if self.covers == 0: - ctext = "" - else: - ctext = "(" + dns.rdatatype.to_text(self.covers) + ")" - return ( - "" - ) - - def __str__(self): - return self.to_text() - - def __eq__(self, other): - if not isinstance(other, Rdataset): - return False - if ( - self.rdclass != other.rdclass - or self.rdtype != other.rdtype - or self.covers != other.covers - ): - return False - return super().__eq__(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def to_text( - self, - name: Optional[dns.name.Name] = None, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - override_rdclass: Optional[dns.rdataclass.RdataClass] = None, - want_comments: bool = False, - **kw: Dict[str, Any], - ) -> str: - """Convert the rdataset into DNS zone file format. - - See ``dns.name.Name.choose_relativity`` for more information - on how *origin* and *relativize* determine the way names - are emitted. - - Any additional keyword arguments are passed on to the rdata - ``to_text()`` method. - - *name*, a ``dns.name.Name``. If name is not ``None``, emit RRs with - *name* as the owner name. - - *origin*, a ``dns.name.Name`` or ``None``, the origin for relative - names. - - *relativize*, a ``bool``. If ``True``, names will be relativized - to *origin*. - - *override_rdclass*, a ``dns.rdataclass.RdataClass`` or ``None``. - If not ``None``, use this class instead of the Rdataset's class. - - *want_comments*, a ``bool``. If ``True``, emit comments for rdata - which have them. The default is ``False``. - """ - - if name is not None: - name = name.choose_relativity(origin, relativize) - ntext = str(name) - pad = " " - else: - ntext = "" - pad = "" - s = io.StringIO() - if override_rdclass is not None: - rdclass = override_rdclass - else: - rdclass = self.rdclass - if len(self) == 0: - # - # Empty rdatasets are used for the question section, and in - # some dynamic updates, so we don't need to print out the TTL - # (which is meaningless anyway). - # - s.write( - f"{ntext}{pad}{dns.rdataclass.to_text(rdclass)} " - f"{dns.rdatatype.to_text(self.rdtype)}\n" - ) - else: - for rd in self: - extra = "" - if want_comments: - if rd.rdcomment: - extra = f" ;{rd.rdcomment}" - s.write( - "%s%s%d %s %s %s%s\n" - % ( - ntext, - pad, - self.ttl, - dns.rdataclass.to_text(rdclass), - dns.rdatatype.to_text(self.rdtype), - rd.to_text(origin=origin, relativize=relativize, **kw), - extra, - ) - ) - # - # We strip off the final \n for the caller's convenience in printing - # - return s.getvalue()[:-1] - - def to_wire( - self, - name: dns.name.Name, - file: Any, - compress: Optional[dns.name.CompressType] = None, - origin: Optional[dns.name.Name] = None, - override_rdclass: Optional[dns.rdataclass.RdataClass] = None, - want_shuffle: bool = True, - ) -> int: - """Convert the rdataset to wire format. - - *name*, a ``dns.name.Name`` is the owner name to use. - - *file* is the file where the name is emitted (typically a - BytesIO file). - - *compress*, a ``dict``, is the compression table to use. If - ``None`` (the default), names will not be compressed. - - *origin* is a ``dns.name.Name`` or ``None``. If the name is - relative and origin is not ``None``, then *origin* will be appended - to it. - - *override_rdclass*, an ``int``, is used as the class instead of the - class of the rdataset. This is useful when rendering rdatasets - associated with dynamic updates. - - *want_shuffle*, a ``bool``. If ``True``, then the order of the - Rdatas within the Rdataset will be shuffled before rendering. - - Returns an ``int``, the number of records emitted. - """ - - if override_rdclass is not None: - rdclass = override_rdclass - want_shuffle = False - else: - rdclass = self.rdclass - if len(self) == 0: - name.to_wire(file, compress, origin) - file.write(struct.pack("!HHIH", self.rdtype, rdclass, 0, 0)) - return 1 - else: - l: Union[Rdataset, List[dns.rdata.Rdata]] - if want_shuffle: - l = list(self) - random.shuffle(l) - else: - l = self - for rd in l: - name.to_wire(file, compress, origin) - file.write(struct.pack("!HHI", self.rdtype, rdclass, self.ttl)) - with dns.renderer.prefixed_length(file, 2): - rd.to_wire(file, compress, origin) - return len(self) - - def match( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType, - ) -> bool: - """Returns ``True`` if this rdataset matches the specified class, - type, and covers. - """ - if self.rdclass == rdclass and self.rdtype == rdtype and self.covers == covers: - return True - return False - - def processing_order(self) -> List[dns.rdata.Rdata]: - """Return rdatas in a valid processing order according to the type's - specification. For example, MX records are in preference order from - lowest to highest preferences, with items of the same preference - shuffled. - - For types that do not define a processing order, the rdatas are - simply shuffled. - """ - if len(self) == 0: - return [] - else: - return self[0]._processing_order(iter(self)) - - -@dns.immutable.immutable -class ImmutableRdataset(Rdataset): # lgtm[py/missing-equals] - """An immutable DNS rdataset.""" - - _clone_class = Rdataset - - def __init__(self, rdataset: Rdataset): - """Create an immutable rdataset from the specified rdataset.""" - - super().__init__( - rdataset.rdclass, rdataset.rdtype, rdataset.covers, rdataset.ttl - ) - self.items = dns.immutable.Dict(rdataset.items) - - def update_ttl(self, ttl): - raise TypeError("immutable") - - def add(self, rd, ttl=None): - raise TypeError("immutable") - - def union_update(self, other): - raise TypeError("immutable") - - def intersection_update(self, other): - raise TypeError("immutable") - - def update(self, other): - raise TypeError("immutable") - - def __delitem__(self, i): - raise TypeError("immutable") - - # lgtm complains about these not raising ArithmeticError, but there is - # precedent for overrides of these methods in other classes to raise - # TypeError, and it seems like the better exception. - - def __ior__(self, other): # lgtm[py/unexpected-raise-in-special-method] - raise TypeError("immutable") - - def __iand__(self, other): # lgtm[py/unexpected-raise-in-special-method] - raise TypeError("immutable") - - def __iadd__(self, other): # lgtm[py/unexpected-raise-in-special-method] - raise TypeError("immutable") - - def __isub__(self, other): # lgtm[py/unexpected-raise-in-special-method] - raise TypeError("immutable") - - def clear(self): - raise TypeError("immutable") - - def __copy__(self): - return ImmutableRdataset(super().copy()) - - def copy(self): - return ImmutableRdataset(super().copy()) - - def union(self, other): - return ImmutableRdataset(super().union(other)) - - def intersection(self, other): - return ImmutableRdataset(super().intersection(other)) - - def difference(self, other): - return ImmutableRdataset(super().difference(other)) - - def symmetric_difference(self, other): - return ImmutableRdataset(super().symmetric_difference(other)) - - -def from_text_list( - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - ttl: int, - text_rdatas: Collection[str], - idna_codec: Optional[dns.name.IDNACodec] = None, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, -) -> Rdataset: - """Create an rdataset with the specified class, type, and TTL, and with - the specified list of rdatas in text format. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Returns a ``dns.rdataset.Rdataset`` object. - """ - - rdclass = dns.rdataclass.RdataClass.make(rdclass) - rdtype = dns.rdatatype.RdataType.make(rdtype) - r = Rdataset(rdclass, rdtype) - r.update_ttl(ttl) - for t in text_rdatas: - rd = dns.rdata.from_text( - r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec - ) - r.add(rd) - return r - - -def from_text( - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - ttl: int, - *text_rdatas: Any, -) -> Rdataset: - """Create an rdataset with the specified class, type, and TTL, and with - the specified rdatas in text format. - - Returns a ``dns.rdataset.Rdataset`` object. - """ - - return from_text_list(rdclass, rdtype, ttl, cast(Collection[str], text_rdatas)) - - -def from_rdata_list(ttl: int, rdatas: Collection[dns.rdata.Rdata]) -> Rdataset: - """Create an rdataset with the specified TTL, and with - the specified list of rdata objects. - - Returns a ``dns.rdataset.Rdataset`` object. - """ - - if len(rdatas) == 0: - raise ValueError("rdata list must not be empty") - r = None - for rd in rdatas: - if r is None: - r = Rdataset(rd.rdclass, rd.rdtype) - r.update_ttl(ttl) - r.add(rd) - assert r is not None - return r - - -def from_rdata(ttl: int, *rdatas: Any) -> Rdataset: - """Create an rdataset with the specified TTL, and with - the specified rdata objects. - - Returns a ``dns.rdataset.Rdataset`` object. - """ - - return from_rdata_list(ttl, cast(Collection[dns.rdata.Rdata], rdatas)) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdatatype.py b/backend/venv39/lib/python3.9/site-packages/dns/rdatatype.py deleted file mode 100644 index aa9e561..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdatatype.py +++ /dev/null @@ -1,336 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Rdata Types.""" - -from typing import Dict - -import dns.enum -import dns.exception - - -class RdataType(dns.enum.IntEnum): - """DNS Rdata Type""" - - TYPE0 = 0 - NONE = 0 - A = 1 - NS = 2 - MD = 3 - MF = 4 - CNAME = 5 - SOA = 6 - MB = 7 - MG = 8 - MR = 9 - NULL = 10 - WKS = 11 - PTR = 12 - HINFO = 13 - MINFO = 14 - MX = 15 - TXT = 16 - RP = 17 - AFSDB = 18 - X25 = 19 - ISDN = 20 - RT = 21 - NSAP = 22 - NSAP_PTR = 23 - SIG = 24 - KEY = 25 - PX = 26 - GPOS = 27 - AAAA = 28 - LOC = 29 - NXT = 30 - SRV = 33 - NAPTR = 35 - KX = 36 - CERT = 37 - A6 = 38 - DNAME = 39 - OPT = 41 - APL = 42 - DS = 43 - SSHFP = 44 - IPSECKEY = 45 - RRSIG = 46 - NSEC = 47 - DNSKEY = 48 - DHCID = 49 - NSEC3 = 50 - NSEC3PARAM = 51 - TLSA = 52 - SMIMEA = 53 - HIP = 55 - NINFO = 56 - CDS = 59 - CDNSKEY = 60 - OPENPGPKEY = 61 - CSYNC = 62 - ZONEMD = 63 - SVCB = 64 - HTTPS = 65 - SPF = 99 - UNSPEC = 103 - NID = 104 - L32 = 105 - L64 = 106 - LP = 107 - EUI48 = 108 - EUI64 = 109 - TKEY = 249 - TSIG = 250 - IXFR = 251 - AXFR = 252 - MAILB = 253 - MAILA = 254 - ANY = 255 - URI = 256 - CAA = 257 - AVC = 258 - AMTRELAY = 260 - RESINFO = 261 - WALLET = 262 - TA = 32768 - DLV = 32769 - - @classmethod - def _maximum(cls): - return 65535 - - @classmethod - def _short_name(cls): - return "type" - - @classmethod - def _prefix(cls): - return "TYPE" - - @classmethod - def _extra_from_text(cls, text): - if text.find("-") >= 0: - try: - return cls[text.replace("-", "_")] - except KeyError: # pragma: no cover - pass - return _registered_by_text.get(text) - - @classmethod - def _extra_to_text(cls, value, current_text): - if current_text is None: - return _registered_by_value.get(value) - if current_text.find("_") >= 0: - return current_text.replace("_", "-") - return current_text - - @classmethod - def _unknown_exception_class(cls): - return UnknownRdatatype - - -_registered_by_text: Dict[str, RdataType] = {} -_registered_by_value: Dict[RdataType, str] = {} - -_metatypes = {RdataType.OPT} - -_singletons = { - RdataType.SOA, - RdataType.NXT, - RdataType.DNAME, - RdataType.NSEC, - RdataType.CNAME, -} - - -class UnknownRdatatype(dns.exception.DNSException): - """DNS resource record type is unknown.""" - - -def from_text(text: str) -> RdataType: - """Convert text into a DNS rdata type value. - - The input text can be a defined DNS RR type mnemonic or - instance of the DNS generic type syntax. - - For example, "NS" and "TYPE2" will both result in a value of 2. - - Raises ``dns.rdatatype.UnknownRdatatype`` if the type is unknown. - - Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535. - - Returns a ``dns.rdatatype.RdataType``. - """ - - return RdataType.from_text(text) - - -def to_text(value: RdataType) -> str: - """Convert a DNS rdata type value to text. - - If the value has a known mnemonic, it will be used, otherwise the - DNS generic type syntax will be used. - - Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535. - - Returns a ``str``. - """ - - return RdataType.to_text(value) - - -def is_metatype(rdtype: RdataType) -> bool: - """True if the specified type is a metatype. - - *rdtype* is a ``dns.rdatatype.RdataType``. - - The currently defined metatypes are TKEY, TSIG, IXFR, AXFR, MAILA, - MAILB, ANY, and OPT. - - Returns a ``bool``. - """ - - return (256 > rdtype >= 128) or rdtype in _metatypes - - -def is_singleton(rdtype: RdataType) -> bool: - """Is the specified type a singleton type? - - Singleton types can only have a single rdata in an rdataset, or a single - RR in an RRset. - - The currently defined singleton types are CNAME, DNAME, NSEC, NXT, and - SOA. - - *rdtype* is an ``int``. - - Returns a ``bool``. - """ - - if rdtype in _singletons: - return True - return False - - -# pylint: disable=redefined-outer-name -def register_type( - rdtype: RdataType, rdtype_text: str, is_singleton: bool = False -) -> None: - """Dynamically register an rdatatype. - - *rdtype*, a ``dns.rdatatype.RdataType``, the rdatatype to register. - - *rdtype_text*, a ``str``, the textual form of the rdatatype. - - *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e. - RRsets of the type can have only one member.) - """ - - _registered_by_text[rdtype_text] = rdtype - _registered_by_value[rdtype] = rdtype_text - if is_singleton: - _singletons.add(rdtype) - - -### BEGIN generated RdataType constants - -TYPE0 = RdataType.TYPE0 -NONE = RdataType.NONE -A = RdataType.A -NS = RdataType.NS -MD = RdataType.MD -MF = RdataType.MF -CNAME = RdataType.CNAME -SOA = RdataType.SOA -MB = RdataType.MB -MG = RdataType.MG -MR = RdataType.MR -NULL = RdataType.NULL -WKS = RdataType.WKS -PTR = RdataType.PTR -HINFO = RdataType.HINFO -MINFO = RdataType.MINFO -MX = RdataType.MX -TXT = RdataType.TXT -RP = RdataType.RP -AFSDB = RdataType.AFSDB -X25 = RdataType.X25 -ISDN = RdataType.ISDN -RT = RdataType.RT -NSAP = RdataType.NSAP -NSAP_PTR = RdataType.NSAP_PTR -SIG = RdataType.SIG -KEY = RdataType.KEY -PX = RdataType.PX -GPOS = RdataType.GPOS -AAAA = RdataType.AAAA -LOC = RdataType.LOC -NXT = RdataType.NXT -SRV = RdataType.SRV -NAPTR = RdataType.NAPTR -KX = RdataType.KX -CERT = RdataType.CERT -A6 = RdataType.A6 -DNAME = RdataType.DNAME -OPT = RdataType.OPT -APL = RdataType.APL -DS = RdataType.DS -SSHFP = RdataType.SSHFP -IPSECKEY = RdataType.IPSECKEY -RRSIG = RdataType.RRSIG -NSEC = RdataType.NSEC -DNSKEY = RdataType.DNSKEY -DHCID = RdataType.DHCID -NSEC3 = RdataType.NSEC3 -NSEC3PARAM = RdataType.NSEC3PARAM -TLSA = RdataType.TLSA -SMIMEA = RdataType.SMIMEA -HIP = RdataType.HIP -NINFO = RdataType.NINFO -CDS = RdataType.CDS -CDNSKEY = RdataType.CDNSKEY -OPENPGPKEY = RdataType.OPENPGPKEY -CSYNC = RdataType.CSYNC -ZONEMD = RdataType.ZONEMD -SVCB = RdataType.SVCB -HTTPS = RdataType.HTTPS -SPF = RdataType.SPF -UNSPEC = RdataType.UNSPEC -NID = RdataType.NID -L32 = RdataType.L32 -L64 = RdataType.L64 -LP = RdataType.LP -EUI48 = RdataType.EUI48 -EUI64 = RdataType.EUI64 -TKEY = RdataType.TKEY -TSIG = RdataType.TSIG -IXFR = RdataType.IXFR -AXFR = RdataType.AXFR -MAILB = RdataType.MAILB -MAILA = RdataType.MAILA -ANY = RdataType.ANY -URI = RdataType.URI -CAA = RdataType.CAA -AVC = RdataType.AVC -AMTRELAY = RdataType.AMTRELAY -RESINFO = RdataType.RESINFO -WALLET = RdataType.WALLET -TA = RdataType.TA -DLV = RdataType.DLV - -### END generated RdataType constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AFSDB.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AFSDB.py deleted file mode 100644 index 06a3b97..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AFSDB.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.mxbase - - -@dns.immutable.immutable -class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX): - """AFSDB record""" - - # Use the property mechanism to make "subtype" an alias for the - # "preference" attribute, and "hostname" an alias for the "exchange" - # attribute. - # - # This lets us inherit the UncompressedMX implementation but lets - # the caller use appropriate attribute names for the rdata type. - # - # We probably lose some performance vs. a cut-and-paste - # implementation, but this way we don't copy code, and that's - # good. - - @property - def subtype(self): - "the AFSDB subtype" - return self.preference - - @property - def hostname(self): - "the AFSDB hostname" - return self.exchange diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AMTRELAY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AMTRELAY.py deleted file mode 100644 index ed2b072..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AMTRELAY.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdtypes.util - - -class Relay(dns.rdtypes.util.Gateway): - name = "AMTRELAY relay" - - @property - def relay(self): - return self.gateway - - -@dns.immutable.immutable -class AMTRELAY(dns.rdata.Rdata): - """AMTRELAY record""" - - # see: RFC 8777 - - __slots__ = ["precedence", "discovery_optional", "relay_type", "relay"] - - def __init__( - self, rdclass, rdtype, precedence, discovery_optional, relay_type, relay - ): - super().__init__(rdclass, rdtype) - relay = Relay(relay_type, relay) - self.precedence = self._as_uint8(precedence) - self.discovery_optional = self._as_bool(discovery_optional) - self.relay_type = relay.type - self.relay = relay.relay - - def to_text(self, origin=None, relativize=True, **kw): - relay = Relay(self.relay_type, self.relay).to_text(origin, relativize) - return "%d %d %d %s" % ( - self.precedence, - self.discovery_optional, - self.relay_type, - relay, - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - precedence = tok.get_uint8() - discovery_optional = tok.get_uint8() - if discovery_optional > 1: - raise dns.exception.SyntaxError("expecting 0 or 1") - discovery_optional = bool(discovery_optional) - relay_type = tok.get_uint8() - if relay_type > 0x7F: - raise dns.exception.SyntaxError("expecting an integer <= 127") - relay = Relay.from_text(relay_type, tok, origin, relativize, relativize_to) - return cls( - rdclass, rdtype, precedence, discovery_optional, relay_type, relay.relay - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - relay_type = self.relay_type | (self.discovery_optional << 7) - header = struct.pack("!BB", self.precedence, relay_type) - file.write(header) - Relay(self.relay_type, self.relay).to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (precedence, relay_type) = parser.get_struct("!BB") - discovery_optional = bool(relay_type >> 7) - relay_type &= 0x7F - relay = Relay.from_wire_parser(relay_type, parser, origin) - return cls( - rdclass, rdtype, precedence, discovery_optional, relay_type, relay.relay - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AVC.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AVC.py deleted file mode 100644 index a27ae2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AVC.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2016 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class AVC(dns.rdtypes.txtbase.TXTBase): - """AVC record""" - - # See: IANA dns parameters for AVC diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CAA.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CAA.py deleted file mode 100644 index 2e6a7e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CAA.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class CAA(dns.rdata.Rdata): - """CAA (Certification Authority Authorization) record""" - - # see: RFC 6844 - - __slots__ = ["flags", "tag", "value"] - - def __init__(self, rdclass, rdtype, flags, tag, value): - super().__init__(rdclass, rdtype) - self.flags = self._as_uint8(flags) - self.tag = self._as_bytes(tag, True, 255) - if not tag.isalnum(): - raise ValueError("tag is not alphanumeric") - self.value = self._as_bytes(value) - - def to_text(self, origin=None, relativize=True, **kw): - return '%u %s "%s"' % ( - self.flags, - dns.rdata._escapify(self.tag), - dns.rdata._escapify(self.value), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - flags = tok.get_uint8() - tag = tok.get_string().encode() - value = tok.get_string().encode() - return cls(rdclass, rdtype, flags, tag, value) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!B", self.flags)) - l = len(self.tag) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.tag) - file.write(self.value) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - flags = parser.get_uint8() - tag = parser.get_counted_bytes() - value = parser.get_remaining() - return cls(rdclass, rdtype, flags, tag, value) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDNSKEY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDNSKEY.py deleted file mode 100644 index b613409..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDNSKEY.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.dnskeybase # lgtm[py/import-and-import-from] - -# pylint: disable=unused-import -from dns.rdtypes.dnskeybase import ( # noqa: F401 lgtm[py/unused-import] - REVOKE, - SEP, - ZONE, -) - -# pylint: enable=unused-import - - -@dns.immutable.immutable -class CDNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): - """CDNSKEY record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDS.py deleted file mode 100644 index 8312b97..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDS.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.dsbase - - -@dns.immutable.immutable -class CDS(dns.rdtypes.dsbase.DSBase): - """CDS record""" - - _digest_length_by_type = { - **dns.rdtypes.dsbase.DSBase._digest_length_by_type, - 0: 1, # delete, RFC 8078 Sec. 4 (including Errata ID 5049) - } diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CERT.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CERT.py deleted file mode 100644 index f369cc8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CERT.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import struct - -import dns.dnssectypes -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - -_ctype_by_value = { - 1: "PKIX", - 2: "SPKI", - 3: "PGP", - 4: "IPKIX", - 5: "ISPKI", - 6: "IPGP", - 7: "ACPKIX", - 8: "IACPKIX", - 253: "URI", - 254: "OID", -} - -_ctype_by_name = { - "PKIX": 1, - "SPKI": 2, - "PGP": 3, - "IPKIX": 4, - "ISPKI": 5, - "IPGP": 6, - "ACPKIX": 7, - "IACPKIX": 8, - "URI": 253, - "OID": 254, -} - - -def _ctype_from_text(what): - v = _ctype_by_name.get(what) - if v is not None: - return v - return int(what) - - -def _ctype_to_text(what): - v = _ctype_by_value.get(what) - if v is not None: - return v - return str(what) - - -@dns.immutable.immutable -class CERT(dns.rdata.Rdata): - """CERT record""" - - # see RFC 4398 - - __slots__ = ["certificate_type", "key_tag", "algorithm", "certificate"] - - def __init__( - self, rdclass, rdtype, certificate_type, key_tag, algorithm, certificate - ): - super().__init__(rdclass, rdtype) - self.certificate_type = self._as_uint16(certificate_type) - self.key_tag = self._as_uint16(key_tag) - self.algorithm = self._as_uint8(algorithm) - self.certificate = self._as_bytes(certificate) - - def to_text(self, origin=None, relativize=True, **kw): - certificate_type = _ctype_to_text(self.certificate_type) - return "%s %d %s %s" % ( - certificate_type, - self.key_tag, - dns.dnssectypes.Algorithm.to_text(self.algorithm), - dns.rdata._base64ify(self.certificate, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - certificate_type = _ctype_from_text(tok.get_string()) - key_tag = tok.get_uint16() - algorithm = dns.dnssectypes.Algorithm.from_text(tok.get_string()) - b64 = tok.concatenate_remaining_identifiers().encode() - certificate = base64.b64decode(b64) - return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - prefix = struct.pack( - "!HHB", self.certificate_type, self.key_tag, self.algorithm - ) - file.write(prefix) - file.write(self.certificate) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (certificate_type, key_tag, algorithm) = parser.get_struct("!HHB") - certificate = parser.get_remaining() - return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CNAME.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CNAME.py deleted file mode 100644 index 665e407..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CNAME.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.nsbase - - -@dns.immutable.immutable -class CNAME(dns.rdtypes.nsbase.NSBase): - """CNAME record - - Note: although CNAME is officially a singleton type, dnspython allows - non-singleton CNAME rdatasets because such sets have been commonly - used by BIND and other nameservers for load balancing.""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CSYNC.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CSYNC.py deleted file mode 100644 index 2f972f6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CSYNC.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011, 2016 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdatatype -import dns.rdtypes.util - - -@dns.immutable.immutable -class Bitmap(dns.rdtypes.util.Bitmap): - type_name = "CSYNC" - - -@dns.immutable.immutable -class CSYNC(dns.rdata.Rdata): - """CSYNC record""" - - __slots__ = ["serial", "flags", "windows"] - - def __init__(self, rdclass, rdtype, serial, flags, windows): - super().__init__(rdclass, rdtype) - self.serial = self._as_uint32(serial) - self.flags = self._as_uint16(flags) - if not isinstance(windows, Bitmap): - windows = Bitmap(windows) - self.windows = tuple(windows.windows) - - def to_text(self, origin=None, relativize=True, **kw): - text = Bitmap(self.windows).to_text() - return "%d %d%s" % (self.serial, self.flags, text) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - serial = tok.get_uint32() - flags = tok.get_uint16() - bitmap = Bitmap.from_text(tok) - return cls(rdclass, rdtype, serial, flags, bitmap) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!IH", self.serial, self.flags)) - Bitmap(self.windows).to_wire(file) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (serial, flags) = parser.get_struct("!IH") - bitmap = Bitmap.from_wire_parser(parser) - return cls(rdclass, rdtype, serial, flags, bitmap) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DLV.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DLV.py deleted file mode 100644 index 6c134f1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DLV.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.dsbase - - -@dns.immutable.immutable -class DLV(dns.rdtypes.dsbase.DSBase): - """DLV record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNAME.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNAME.py deleted file mode 100644 index bbf9186..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNAME.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.nsbase - - -@dns.immutable.immutable -class DNAME(dns.rdtypes.nsbase.UncompressedNS): - """DNAME record""" - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.target.to_wire(file, None, origin, canonicalize) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNSKEY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNSKEY.py deleted file mode 100644 index 6d961a9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNSKEY.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.dnskeybase # lgtm[py/import-and-import-from] - -# pylint: disable=unused-import -from dns.rdtypes.dnskeybase import ( # noqa: F401 lgtm[py/unused-import] - REVOKE, - SEP, - ZONE, -) - -# pylint: enable=unused-import - - -@dns.immutable.immutable -class DNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase): - """DNSKEY record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DS.py deleted file mode 100644 index 58b3108..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DS.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.dsbase - - -@dns.immutable.immutable -class DS(dns.rdtypes.dsbase.DSBase): - """DS record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI48.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI48.py deleted file mode 100644 index c843be5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI48.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.euibase - - -@dns.immutable.immutable -class EUI48(dns.rdtypes.euibase.EUIBase): - """EUI48 record""" - - # see: rfc7043.txt - - byte_len = 6 # 0123456789ab (in hex) - text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI64.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI64.py deleted file mode 100644 index f6d7e25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI64.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.euibase - - -@dns.immutable.immutable -class EUI64(dns.rdtypes.euibase.EUIBase): - """EUI64 record""" - - # see: rfc7043.txt - - byte_len = 8 # 0123456789abcdef (in hex) - text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab-cd-ef diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/GPOS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/GPOS.py deleted file mode 100644 index d79f4a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/GPOS.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -def _validate_float_string(what): - if len(what) == 0: - raise dns.exception.FormError - if what[0] == b"-"[0] or what[0] == b"+"[0]: - what = what[1:] - if what.isdigit(): - return - try: - (left, right) = what.split(b".") - except ValueError: - raise dns.exception.FormError - if left == b"" and right == b"": - raise dns.exception.FormError - if not left == b"" and not left.decode().isdigit(): - raise dns.exception.FormError - if not right == b"" and not right.decode().isdigit(): - raise dns.exception.FormError - - -@dns.immutable.immutable -class GPOS(dns.rdata.Rdata): - """GPOS record""" - - # see: RFC 1712 - - __slots__ = ["latitude", "longitude", "altitude"] - - def __init__(self, rdclass, rdtype, latitude, longitude, altitude): - super().__init__(rdclass, rdtype) - if isinstance(latitude, float) or isinstance(latitude, int): - latitude = str(latitude) - if isinstance(longitude, float) or isinstance(longitude, int): - longitude = str(longitude) - if isinstance(altitude, float) or isinstance(altitude, int): - altitude = str(altitude) - latitude = self._as_bytes(latitude, True, 255) - longitude = self._as_bytes(longitude, True, 255) - altitude = self._as_bytes(altitude, True, 255) - _validate_float_string(latitude) - _validate_float_string(longitude) - _validate_float_string(altitude) - self.latitude = latitude - self.longitude = longitude - self.altitude = altitude - flat = self.float_latitude - if flat < -90.0 or flat > 90.0: - raise dns.exception.FormError("bad latitude") - flong = self.float_longitude - if flong < -180.0 or flong > 180.0: - raise dns.exception.FormError("bad longitude") - - def to_text(self, origin=None, relativize=True, **kw): - return ( - f"{self.latitude.decode()} {self.longitude.decode()} " - f"{self.altitude.decode()}" - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - latitude = tok.get_string() - longitude = tok.get_string() - altitude = tok.get_string() - return cls(rdclass, rdtype, latitude, longitude, altitude) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.latitude) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.latitude) - l = len(self.longitude) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.longitude) - l = len(self.altitude) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.altitude) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - latitude = parser.get_counted_bytes() - longitude = parser.get_counted_bytes() - altitude = parser.get_counted_bytes() - return cls(rdclass, rdtype, latitude, longitude, altitude) - - @property - def float_latitude(self): - "latitude as a floating point value" - return float(self.latitude) - - @property - def float_longitude(self): - "longitude as a floating point value" - return float(self.longitude) - - @property - def float_altitude(self): - "altitude as a floating point value" - return float(self.altitude) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HINFO.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HINFO.py deleted file mode 100644 index 06ad348..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HINFO.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class HINFO(dns.rdata.Rdata): - """HINFO record""" - - # see: RFC 1035 - - __slots__ = ["cpu", "os"] - - def __init__(self, rdclass, rdtype, cpu, os): - super().__init__(rdclass, rdtype) - self.cpu = self._as_bytes(cpu, True, 255) - self.os = self._as_bytes(os, True, 255) - - def to_text(self, origin=None, relativize=True, **kw): - return f'"{dns.rdata._escapify(self.cpu)}" "{dns.rdata._escapify(self.os)}"' - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - cpu = tok.get_string(max_length=255) - os = tok.get_string(max_length=255) - return cls(rdclass, rdtype, cpu, os) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.cpu) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.cpu) - l = len(self.os) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.os) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - cpu = parser.get_counted_bytes() - os = parser.get_counted_bytes() - return cls(rdclass, rdtype, cpu, os) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HIP.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HIP.py deleted file mode 100644 index f3157da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HIP.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2010, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import binascii -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.rdatatype - - -@dns.immutable.immutable -class HIP(dns.rdata.Rdata): - """HIP record""" - - # see: RFC 5205 - - __slots__ = ["hit", "algorithm", "key", "servers"] - - def __init__(self, rdclass, rdtype, hit, algorithm, key, servers): - super().__init__(rdclass, rdtype) - self.hit = self._as_bytes(hit, True, 255) - self.algorithm = self._as_uint8(algorithm) - self.key = self._as_bytes(key, True) - self.servers = self._as_tuple(servers, self._as_name) - - def to_text(self, origin=None, relativize=True, **kw): - hit = binascii.hexlify(self.hit).decode() - key = base64.b64encode(self.key).replace(b"\n", b"").decode() - text = "" - servers = [] - for server in self.servers: - servers.append(server.choose_relativity(origin, relativize)) - if len(servers) > 0: - text += " " + " ".join(x.to_unicode() for x in servers) - return "%u %s %s%s" % (self.algorithm, hit, key, text) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_uint8() - hit = binascii.unhexlify(tok.get_string().encode()) - key = base64.b64decode(tok.get_string().encode()) - servers = [] - for token in tok.get_remaining(): - server = tok.as_name(token, origin, relativize, relativize_to) - servers.append(server) - return cls(rdclass, rdtype, hit, algorithm, key, servers) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - lh = len(self.hit) - lk = len(self.key) - file.write(struct.pack("!BBH", lh, self.algorithm, lk)) - file.write(self.hit) - file.write(self.key) - for server in self.servers: - server.to_wire(file, None, origin, False) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (lh, algorithm, lk) = parser.get_struct("!BBH") - hit = parser.get_bytes(lh) - key = parser.get_bytes(lk) - servers = [] - while parser.remaining() > 0: - server = parser.get_name(origin) - servers.append(server) - return cls(rdclass, rdtype, hit, algorithm, key, servers) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ISDN.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ISDN.py deleted file mode 100644 index 6428a0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ISDN.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class ISDN(dns.rdata.Rdata): - """ISDN record""" - - # see: RFC 1183 - - __slots__ = ["address", "subaddress"] - - def __init__(self, rdclass, rdtype, address, subaddress): - super().__init__(rdclass, rdtype) - self.address = self._as_bytes(address, True, 255) - self.subaddress = self._as_bytes(subaddress, True, 255) - - def to_text(self, origin=None, relativize=True, **kw): - if self.subaddress: - return ( - f'"{dns.rdata._escapify(self.address)}" ' - f'"{dns.rdata._escapify(self.subaddress)}"' - ) - else: - return f'"{dns.rdata._escapify(self.address)}"' - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_string() - tokens = tok.get_remaining(max_tokens=1) - if len(tokens) >= 1: - subaddress = tokens[0].unescape().value - else: - subaddress = "" - return cls(rdclass, rdtype, address, subaddress) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.address) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.address) - l = len(self.subaddress) - if l > 0: - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.subaddress) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_counted_bytes() - if parser.remaining() > 0: - subaddress = parser.get_counted_bytes() - else: - subaddress = b"" - return cls(rdclass, rdtype, address, subaddress) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L32.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L32.py deleted file mode 100644 index 09804c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L32.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import struct - -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class L32(dns.rdata.Rdata): - """L32 record""" - - # see: rfc6742.txt - - __slots__ = ["preference", "locator32"] - - def __init__(self, rdclass, rdtype, preference, locator32): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - self.locator32 = self._as_ipv4_address(locator32) - - def to_text(self, origin=None, relativize=True, **kw): - return f"{self.preference} {self.locator32}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - nodeid = tok.get_identifier() - return cls(rdclass, rdtype, preference, nodeid) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!H", self.preference)) - file.write(dns.ipv4.inet_aton(self.locator32)) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - locator32 = parser.get_remaining() - return cls(rdclass, rdtype, preference, locator32) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L64.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L64.py deleted file mode 100644 index fb76808..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L64.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import struct - -import dns.immutable -import dns.rdtypes.util - - -@dns.immutable.immutable -class L64(dns.rdata.Rdata): - """L64 record""" - - # see: rfc6742.txt - - __slots__ = ["preference", "locator64"] - - def __init__(self, rdclass, rdtype, preference, locator64): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - if isinstance(locator64, bytes): - if len(locator64) != 8: - raise ValueError("invalid locator64") - self.locator64 = dns.rdata._hexify(locator64, 4, b":") - else: - dns.rdtypes.util.parse_formatted_hex(locator64, 4, 4, ":") - self.locator64 = locator64 - - def to_text(self, origin=None, relativize=True, **kw): - return f"{self.preference} {self.locator64}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - locator64 = tok.get_identifier() - return cls(rdclass, rdtype, preference, locator64) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!H", self.preference)) - file.write(dns.rdtypes.util.parse_formatted_hex(self.locator64, 4, 4, ":")) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - locator64 = parser.get_remaining() - return cls(rdclass, rdtype, preference, locator64) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LOC.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LOC.py deleted file mode 100644 index 1153cf0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LOC.py +++ /dev/null @@ -1,353 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata - -_pows = tuple(10**i for i in range(0, 11)) - -# default values are in centimeters -_default_size = 100.0 -_default_hprec = 1000000.0 -_default_vprec = 1000.0 - -# for use by from_wire() -_MAX_LATITUDE = 0x80000000 + 90 * 3600000 -_MIN_LATITUDE = 0x80000000 - 90 * 3600000 -_MAX_LONGITUDE = 0x80000000 + 180 * 3600000 -_MIN_LONGITUDE = 0x80000000 - 180 * 3600000 - - -def _exponent_of(what, desc): - if what == 0: - return 0 - exp = None - for i, pow in enumerate(_pows): - if what < pow: - exp = i - 1 - break - if exp is None or exp < 0: - raise dns.exception.SyntaxError(f"{desc} value out of bounds") - return exp - - -def _float_to_tuple(what): - if what < 0: - sign = -1 - what *= -1 - else: - sign = 1 - what = round(what * 3600000) - degrees = int(what // 3600000) - what -= degrees * 3600000 - minutes = int(what // 60000) - what -= minutes * 60000 - seconds = int(what // 1000) - what -= int(seconds * 1000) - what = int(what) - return (degrees, minutes, seconds, what, sign) - - -def _tuple_to_float(what): - value = float(what[0]) - value += float(what[1]) / 60.0 - value += float(what[2]) / 3600.0 - value += float(what[3]) / 3600000.0 - return float(what[4]) * value - - -def _encode_size(what, desc): - what = int(what) - exponent = _exponent_of(what, desc) & 0xF - base = what // pow(10, exponent) & 0xF - return base * 16 + exponent - - -def _decode_size(what, desc): - exponent = what & 0x0F - if exponent > 9: - raise dns.exception.FormError(f"bad {desc} exponent") - base = (what & 0xF0) >> 4 - if base > 9: - raise dns.exception.FormError(f"bad {desc} base") - return base * pow(10, exponent) - - -def _check_coordinate_list(value, low, high): - if value[0] < low or value[0] > high: - raise ValueError(f"not in range [{low}, {high}]") - if value[1] < 0 or value[1] > 59: - raise ValueError("bad minutes value") - if value[2] < 0 or value[2] > 59: - raise ValueError("bad seconds value") - if value[3] < 0 or value[3] > 999: - raise ValueError("bad milliseconds value") - if value[4] != 1 and value[4] != -1: - raise ValueError("bad hemisphere value") - - -@dns.immutable.immutable -class LOC(dns.rdata.Rdata): - """LOC record""" - - # see: RFC 1876 - - __slots__ = [ - "latitude", - "longitude", - "altitude", - "size", - "horizontal_precision", - "vertical_precision", - ] - - def __init__( - self, - rdclass, - rdtype, - latitude, - longitude, - altitude, - size=_default_size, - hprec=_default_hprec, - vprec=_default_vprec, - ): - """Initialize a LOC record instance. - - The parameters I{latitude} and I{longitude} may be either a 4-tuple - of integers specifying (degrees, minutes, seconds, milliseconds), - or they may be floating point values specifying the number of - degrees. The other parameters are floats. Size, horizontal precision, - and vertical precision are specified in centimeters.""" - - super().__init__(rdclass, rdtype) - if isinstance(latitude, int): - latitude = float(latitude) - if isinstance(latitude, float): - latitude = _float_to_tuple(latitude) - _check_coordinate_list(latitude, -90, 90) - self.latitude = tuple(latitude) - if isinstance(longitude, int): - longitude = float(longitude) - if isinstance(longitude, float): - longitude = _float_to_tuple(longitude) - _check_coordinate_list(longitude, -180, 180) - self.longitude = tuple(longitude) - self.altitude = float(altitude) - self.size = float(size) - self.horizontal_precision = float(hprec) - self.vertical_precision = float(vprec) - - def to_text(self, origin=None, relativize=True, **kw): - if self.latitude[4] > 0: - lat_hemisphere = "N" - else: - lat_hemisphere = "S" - if self.longitude[4] > 0: - long_hemisphere = "E" - else: - long_hemisphere = "W" - text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( - self.latitude[0], - self.latitude[1], - self.latitude[2], - self.latitude[3], - lat_hemisphere, - self.longitude[0], - self.longitude[1], - self.longitude[2], - self.longitude[3], - long_hemisphere, - self.altitude / 100.0, - ) - - # do not print default values - if ( - self.size != _default_size - or self.horizontal_precision != _default_hprec - or self.vertical_precision != _default_vprec - ): - text += ( - f" {self.size / 100.0:0.2f}m {self.horizontal_precision / 100.0:0.2f}m" - f" {self.vertical_precision / 100.0:0.2f}m" - ) - return text - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - latitude = [0, 0, 0, 0, 1] - longitude = [0, 0, 0, 0, 1] - size = _default_size - hprec = _default_hprec - vprec = _default_vprec - - latitude[0] = tok.get_int() - t = tok.get_string() - if t.isdigit(): - latitude[1] = int(t) - t = tok.get_string() - if "." in t: - (seconds, milliseconds) = t.split(".") - if not seconds.isdigit(): - raise dns.exception.SyntaxError("bad latitude seconds value") - latitude[2] = int(seconds) - l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): - raise dns.exception.SyntaxError("bad latitude milliseconds value") - if l == 1: - m = 100 - elif l == 2: - m = 10 - else: - m = 1 - latitude[3] = m * int(milliseconds) - t = tok.get_string() - elif t.isdigit(): - latitude[2] = int(t) - t = tok.get_string() - if t == "S": - latitude[4] = -1 - elif t != "N": - raise dns.exception.SyntaxError("bad latitude hemisphere value") - - longitude[0] = tok.get_int() - t = tok.get_string() - if t.isdigit(): - longitude[1] = int(t) - t = tok.get_string() - if "." in t: - (seconds, milliseconds) = t.split(".") - if not seconds.isdigit(): - raise dns.exception.SyntaxError("bad longitude seconds value") - longitude[2] = int(seconds) - l = len(milliseconds) - if l == 0 or l > 3 or not milliseconds.isdigit(): - raise dns.exception.SyntaxError("bad longitude milliseconds value") - if l == 1: - m = 100 - elif l == 2: - m = 10 - else: - m = 1 - longitude[3] = m * int(milliseconds) - t = tok.get_string() - elif t.isdigit(): - longitude[2] = int(t) - t = tok.get_string() - if t == "W": - longitude[4] = -1 - elif t != "E": - raise dns.exception.SyntaxError("bad longitude hemisphere value") - - t = tok.get_string() - if t[-1] == "m": - t = t[0:-1] - altitude = float(t) * 100.0 # m -> cm - - tokens = tok.get_remaining(max_tokens=3) - if len(tokens) >= 1: - value = tokens[0].unescape().value - if value[-1] == "m": - value = value[0:-1] - size = float(value) * 100.0 # m -> cm - if len(tokens) >= 2: - value = tokens[1].unescape().value - if value[-1] == "m": - value = value[0:-1] - hprec = float(value) * 100.0 # m -> cm - if len(tokens) >= 3: - value = tokens[2].unescape().value - if value[-1] == "m": - value = value[0:-1] - vprec = float(value) * 100.0 # m -> cm - - # Try encoding these now so we raise if they are bad - _encode_size(size, "size") - _encode_size(hprec, "horizontal precision") - _encode_size(vprec, "vertical precision") - - return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - milliseconds = ( - self.latitude[0] * 3600000 - + self.latitude[1] * 60000 - + self.latitude[2] * 1000 - + self.latitude[3] - ) * self.latitude[4] - latitude = 0x80000000 + milliseconds - milliseconds = ( - self.longitude[0] * 3600000 - + self.longitude[1] * 60000 - + self.longitude[2] * 1000 - + self.longitude[3] - ) * self.longitude[4] - longitude = 0x80000000 + milliseconds - altitude = int(self.altitude) + 10000000 - size = _encode_size(self.size, "size") - hprec = _encode_size(self.horizontal_precision, "horizontal precision") - vprec = _encode_size(self.vertical_precision, "vertical precision") - wire = struct.pack( - "!BBBBIII", 0, size, hprec, vprec, latitude, longitude, altitude - ) - file.write(wire) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - ( - version, - size, - hprec, - vprec, - latitude, - longitude, - altitude, - ) = parser.get_struct("!BBBBIII") - if version != 0: - raise dns.exception.FormError("LOC version not zero") - if latitude < _MIN_LATITUDE or latitude > _MAX_LATITUDE: - raise dns.exception.FormError("bad latitude") - if latitude > 0x80000000: - latitude = (latitude - 0x80000000) / 3600000 - else: - latitude = -1 * (0x80000000 - latitude) / 3600000 - if longitude < _MIN_LONGITUDE or longitude > _MAX_LONGITUDE: - raise dns.exception.FormError("bad longitude") - if longitude > 0x80000000: - longitude = (longitude - 0x80000000) / 3600000 - else: - longitude = -1 * (0x80000000 - longitude) / 3600000 - altitude = float(altitude) - 10000000.0 - size = _decode_size(size, "size") - hprec = _decode_size(hprec, "horizontal precision") - vprec = _decode_size(vprec, "vertical precision") - return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec) - - @property - def float_latitude(self): - "latitude as a floating point value" - return _tuple_to_float(self.latitude) - - @property - def float_longitude(self): - "longitude as a floating point value" - return _tuple_to_float(self.longitude) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LP.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LP.py deleted file mode 100644 index 312663f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LP.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import struct - -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class LP(dns.rdata.Rdata): - """LP record""" - - # see: rfc6742.txt - - __slots__ = ["preference", "fqdn"] - - def __init__(self, rdclass, rdtype, preference, fqdn): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - self.fqdn = self._as_name(fqdn) - - def to_text(self, origin=None, relativize=True, **kw): - fqdn = self.fqdn.choose_relativity(origin, relativize) - return "%d %s" % (self.preference, fqdn) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - fqdn = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, preference, fqdn) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!H", self.preference)) - self.fqdn.to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - fqdn = parser.get_name(origin) - return cls(rdclass, rdtype, preference, fqdn) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/MX.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/MX.py deleted file mode 100644 index 0c300c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/MX.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.mxbase - - -@dns.immutable.immutable -class MX(dns.rdtypes.mxbase.MXBase): - """MX record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NID.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NID.py deleted file mode 100644 index 2f64917..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NID.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import struct - -import dns.immutable -import dns.rdtypes.util - - -@dns.immutable.immutable -class NID(dns.rdata.Rdata): - """NID record""" - - # see: rfc6742.txt - - __slots__ = ["preference", "nodeid"] - - def __init__(self, rdclass, rdtype, preference, nodeid): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - if isinstance(nodeid, bytes): - if len(nodeid) != 8: - raise ValueError("invalid nodeid") - self.nodeid = dns.rdata._hexify(nodeid, 4, b":") - else: - dns.rdtypes.util.parse_formatted_hex(nodeid, 4, 4, ":") - self.nodeid = nodeid - - def to_text(self, origin=None, relativize=True, **kw): - return f"{self.preference} {self.nodeid}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - nodeid = tok.get_identifier() - return cls(rdclass, rdtype, preference, nodeid) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!H", self.preference)) - file.write(dns.rdtypes.util.parse_formatted_hex(self.nodeid, 4, 4, ":")) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - nodeid = parser.get_remaining() - return cls(rdclass, rdtype, preference, nodeid) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NINFO.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NINFO.py deleted file mode 100644 index b177bdd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NINFO.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class NINFO(dns.rdtypes.txtbase.TXTBase): - """NINFO record""" - - # see: draft-reid-dnsext-zs-01 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NS.py deleted file mode 100644 index c3f34ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NS.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.nsbase - - -@dns.immutable.immutable -class NS(dns.rdtypes.nsbase.NSBase): - """NS record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC.py deleted file mode 100644 index 3c78b72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdatatype -import dns.rdtypes.util - - -@dns.immutable.immutable -class Bitmap(dns.rdtypes.util.Bitmap): - type_name = "NSEC" - - -@dns.immutable.immutable -class NSEC(dns.rdata.Rdata): - """NSEC record""" - - __slots__ = ["next", "windows"] - - def __init__(self, rdclass, rdtype, next, windows): - super().__init__(rdclass, rdtype) - self.next = self._as_name(next) - if not isinstance(windows, Bitmap): - windows = Bitmap(windows) - self.windows = tuple(windows.windows) - - def to_text(self, origin=None, relativize=True, **kw): - next = self.next.choose_relativity(origin, relativize) - text = Bitmap(self.windows).to_text() - return f"{next}{text}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - next = tok.get_name(origin, relativize, relativize_to) - windows = Bitmap.from_text(tok) - return cls(rdclass, rdtype, next, windows) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - # Note that NSEC downcasing, originally mandated by RFC 4034 - # section 6.2 was removed by RFC 6840 section 5.1. - self.next.to_wire(file, None, origin, False) - Bitmap(self.windows).to_wire(file) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - next = parser.get_name(origin) - bitmap = Bitmap.from_wire_parser(parser) - return cls(rdclass, rdtype, next, bitmap) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3.py deleted file mode 100644 index d71302b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import binascii -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.rdatatype -import dns.rdtypes.util - -b32_hex_to_normal = bytes.maketrans( - b"0123456789ABCDEFGHIJKLMNOPQRSTUV", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" -) -b32_normal_to_hex = bytes.maketrans( - b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", b"0123456789ABCDEFGHIJKLMNOPQRSTUV" -) - -# hash algorithm constants -SHA1 = 1 - -# flag constants -OPTOUT = 1 - - -@dns.immutable.immutable -class Bitmap(dns.rdtypes.util.Bitmap): - type_name = "NSEC3" - - -@dns.immutable.immutable -class NSEC3(dns.rdata.Rdata): - """NSEC3 record""" - - __slots__ = ["algorithm", "flags", "iterations", "salt", "next", "windows"] - - def __init__( - self, rdclass, rdtype, algorithm, flags, iterations, salt, next, windows - ): - super().__init__(rdclass, rdtype) - self.algorithm = self._as_uint8(algorithm) - self.flags = self._as_uint8(flags) - self.iterations = self._as_uint16(iterations) - self.salt = self._as_bytes(salt, True, 255) - self.next = self._as_bytes(next, True, 255) - if not isinstance(windows, Bitmap): - windows = Bitmap(windows) - self.windows = tuple(windows.windows) - - def _next_text(self): - next = base64.b32encode(self.next).translate(b32_normal_to_hex).lower().decode() - next = next.rstrip("=") - return next - - def to_text(self, origin=None, relativize=True, **kw): - next = self._next_text() - if self.salt == b"": - salt = "-" - else: - salt = binascii.hexlify(self.salt).decode() - text = Bitmap(self.windows).to_text() - return "%u %u %u %s %s%s" % ( - self.algorithm, - self.flags, - self.iterations, - salt, - next, - text, - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_uint8() - flags = tok.get_uint8() - iterations = tok.get_uint16() - salt = tok.get_string() - if salt == "-": - salt = b"" - else: - salt = binascii.unhexlify(salt.encode("ascii")) - next = tok.get_string().encode("ascii").upper().translate(b32_hex_to_normal) - if next.endswith(b"="): - raise binascii.Error("Incorrect padding") - if len(next) % 8 != 0: - next += b"=" * (8 - len(next) % 8) - next = base64.b32decode(next) - bitmap = Bitmap.from_text(tok) - return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, bitmap) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.salt) - file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l)) - file.write(self.salt) - l = len(self.next) - file.write(struct.pack("!B", l)) - file.write(self.next) - Bitmap(self.windows).to_wire(file) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (algorithm, flags, iterations) = parser.get_struct("!BBH") - salt = parser.get_counted_bytes() - next = parser.get_counted_bytes() - bitmap = Bitmap.from_wire_parser(parser) - return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, bitmap) - - def next_name(self, origin=None): - return dns.name.from_text(self._next_text(), origin) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py deleted file mode 100644 index d1e62eb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii -import struct - -import dns.exception -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class NSEC3PARAM(dns.rdata.Rdata): - """NSEC3PARAM record""" - - __slots__ = ["algorithm", "flags", "iterations", "salt"] - - def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt): - super().__init__(rdclass, rdtype) - self.algorithm = self._as_uint8(algorithm) - self.flags = self._as_uint8(flags) - self.iterations = self._as_uint16(iterations) - self.salt = self._as_bytes(salt, True, 255) - - def to_text(self, origin=None, relativize=True, **kw): - if self.salt == b"": - salt = "-" - else: - salt = binascii.hexlify(self.salt).decode() - return "%u %u %u %s" % (self.algorithm, self.flags, self.iterations, salt) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_uint8() - flags = tok.get_uint8() - iterations = tok.get_uint16() - salt = tok.get_string() - if salt == "-": - salt = "" - else: - salt = binascii.unhexlify(salt.encode()) - return cls(rdclass, rdtype, algorithm, flags, iterations, salt) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.salt) - file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l)) - file.write(self.salt) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (algorithm, flags, iterations) = parser.get_struct("!BBH") - salt = parser.get_counted_bytes() - return cls(rdclass, rdtype, algorithm, flags, iterations, salt) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py deleted file mode 100644 index 4d7a4b6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2016 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class OPENPGPKEY(dns.rdata.Rdata): - """OPENPGPKEY record""" - - # see: RFC 7929 - - def __init__(self, rdclass, rdtype, key): - super().__init__(rdclass, rdtype) - self.key = self._as_bytes(key) - - def to_text(self, origin=None, relativize=True, **kw): - return dns.rdata._base64ify(self.key, chunksize=None, **kw) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - b64 = tok.concatenate_remaining_identifiers().encode() - key = base64.b64decode(b64) - return cls(rdclass, rdtype, key) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(self.key) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - key = parser.get_remaining() - return cls(rdclass, rdtype, key) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPT.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPT.py deleted file mode 100644 index d343dfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPT.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.edns -import dns.exception -import dns.immutable -import dns.rdata - -# We don't implement from_text, and that's ok. -# pylint: disable=abstract-method - - -@dns.immutable.immutable -class OPT(dns.rdata.Rdata): - """OPT record""" - - __slots__ = ["options"] - - def __init__(self, rdclass, rdtype, options): - """Initialize an OPT rdata. - - *rdclass*, an ``int`` is the rdataclass of the Rdata, - which is also the payload size. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *options*, a tuple of ``bytes`` - """ - - super().__init__(rdclass, rdtype) - - def as_option(option): - if not isinstance(option, dns.edns.Option): - raise ValueError("option is not a dns.edns.option") - return option - - self.options = self._as_tuple(options, as_option) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - for opt in self.options: - owire = opt.to_wire() - file.write(struct.pack("!HH", opt.otype, len(owire))) - file.write(owire) - - def to_text(self, origin=None, relativize=True, **kw): - return " ".join(opt.to_text() for opt in self.options) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - options = [] - while parser.remaining() > 0: - (otype, olen) = parser.get_struct("!HH") - with parser.restrict_to(olen): - opt = dns.edns.option_from_wire_parser(otype, parser) - options.append(opt) - return cls(rdclass, rdtype, options) - - @property - def payload(self): - "payload size" - return self.rdclass diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/PTR.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/PTR.py deleted file mode 100644 index 98c3616..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/PTR.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.nsbase - - -@dns.immutable.immutable -class PTR(dns.rdtypes.nsbase.NSBase): - """PTR record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RESINFO.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RESINFO.py deleted file mode 100644 index 76c8ea2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RESINFO.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class RESINFO(dns.rdtypes.txtbase.TXTBase): - """RESINFO record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RP.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RP.py deleted file mode 100644 index a66cfc5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RP.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata - - -@dns.immutable.immutable -class RP(dns.rdata.Rdata): - """RP record""" - - # see: RFC 1183 - - __slots__ = ["mbox", "txt"] - - def __init__(self, rdclass, rdtype, mbox, txt): - super().__init__(rdclass, rdtype) - self.mbox = self._as_name(mbox) - self.txt = self._as_name(txt) - - def to_text(self, origin=None, relativize=True, **kw): - mbox = self.mbox.choose_relativity(origin, relativize) - txt = self.txt.choose_relativity(origin, relativize) - return f"{str(mbox)} {str(txt)}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - mbox = tok.get_name(origin, relativize, relativize_to) - txt = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, mbox, txt) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.mbox.to_wire(file, None, origin, canonicalize) - self.txt.to_wire(file, None, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - mbox = parser.get_name(origin) - txt = parser.get_name(origin) - return cls(rdclass, rdtype, mbox, txt) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RRSIG.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RRSIG.py deleted file mode 100644 index 8beb423..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RRSIG.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import calendar -import struct -import time - -import dns.dnssectypes -import dns.exception -import dns.immutable -import dns.rdata -import dns.rdatatype - - -class BadSigTime(dns.exception.DNSException): - """Time in DNS SIG or RRSIG resource record cannot be parsed.""" - - -def sigtime_to_posixtime(what): - if len(what) <= 10 and what.isdigit(): - return int(what) - if len(what) != 14: - raise BadSigTime - year = int(what[0:4]) - month = int(what[4:6]) - day = int(what[6:8]) - hour = int(what[8:10]) - minute = int(what[10:12]) - second = int(what[12:14]) - return calendar.timegm((year, month, day, hour, minute, second, 0, 0, 0)) - - -def posixtime_to_sigtime(what): - return time.strftime("%Y%m%d%H%M%S", time.gmtime(what)) - - -@dns.immutable.immutable -class RRSIG(dns.rdata.Rdata): - """RRSIG record""" - - __slots__ = [ - "type_covered", - "algorithm", - "labels", - "original_ttl", - "expiration", - "inception", - "key_tag", - "signer", - "signature", - ] - - def __init__( - self, - rdclass, - rdtype, - type_covered, - algorithm, - labels, - original_ttl, - expiration, - inception, - key_tag, - signer, - signature, - ): - super().__init__(rdclass, rdtype) - self.type_covered = self._as_rdatatype(type_covered) - self.algorithm = dns.dnssectypes.Algorithm.make(algorithm) - self.labels = self._as_uint8(labels) - self.original_ttl = self._as_ttl(original_ttl) - self.expiration = self._as_uint32(expiration) - self.inception = self._as_uint32(inception) - self.key_tag = self._as_uint16(key_tag) - self.signer = self._as_name(signer) - self.signature = self._as_bytes(signature) - - def covers(self): - return self.type_covered - - def to_text(self, origin=None, relativize=True, **kw): - return "%s %d %d %d %s %s %d %s %s" % ( - dns.rdatatype.to_text(self.type_covered), - self.algorithm, - self.labels, - self.original_ttl, - posixtime_to_sigtime(self.expiration), - posixtime_to_sigtime(self.inception), - self.key_tag, - self.signer.choose_relativity(origin, relativize), - dns.rdata._base64ify(self.signature, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - type_covered = dns.rdatatype.from_text(tok.get_string()) - algorithm = dns.dnssectypes.Algorithm.from_text(tok.get_string()) - labels = tok.get_int() - original_ttl = tok.get_ttl() - expiration = sigtime_to_posixtime(tok.get_string()) - inception = sigtime_to_posixtime(tok.get_string()) - key_tag = tok.get_int() - signer = tok.get_name(origin, relativize, relativize_to) - b64 = tok.concatenate_remaining_identifiers().encode() - signature = base64.b64decode(b64) - return cls( - rdclass, - rdtype, - type_covered, - algorithm, - labels, - original_ttl, - expiration, - inception, - key_tag, - signer, - signature, - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack( - "!HBBIIIH", - self.type_covered, - self.algorithm, - self.labels, - self.original_ttl, - self.expiration, - self.inception, - self.key_tag, - ) - file.write(header) - self.signer.to_wire(file, None, origin, canonicalize) - file.write(self.signature) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("!HBBIIIH") - signer = parser.get_name(origin) - signature = parser.get_remaining() - return cls(rdclass, rdtype, *header, signer, signature) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RT.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RT.py deleted file mode 100644 index 5a4d45c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RT.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.mxbase - - -@dns.immutable.immutable -class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX): - """RT record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SMIMEA.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SMIMEA.py deleted file mode 100644 index 55d87bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SMIMEA.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import dns.immutable -import dns.rdtypes.tlsabase - - -@dns.immutable.immutable -class SMIMEA(dns.rdtypes.tlsabase.TLSABase): - """SMIMEA record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SOA.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SOA.py deleted file mode 100644 index 09aa832..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SOA.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata - - -@dns.immutable.immutable -class SOA(dns.rdata.Rdata): - """SOA record""" - - # see: RFC 1035 - - __slots__ = ["mname", "rname", "serial", "refresh", "retry", "expire", "minimum"] - - def __init__( - self, rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum - ): - super().__init__(rdclass, rdtype) - self.mname = self._as_name(mname) - self.rname = self._as_name(rname) - self.serial = self._as_uint32(serial) - self.refresh = self._as_ttl(refresh) - self.retry = self._as_ttl(retry) - self.expire = self._as_ttl(expire) - self.minimum = self._as_ttl(minimum) - - def to_text(self, origin=None, relativize=True, **kw): - mname = self.mname.choose_relativity(origin, relativize) - rname = self.rname.choose_relativity(origin, relativize) - return "%s %s %d %d %d %d %d" % ( - mname, - rname, - self.serial, - self.refresh, - self.retry, - self.expire, - self.minimum, - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - mname = tok.get_name(origin, relativize, relativize_to) - rname = tok.get_name(origin, relativize, relativize_to) - serial = tok.get_uint32() - refresh = tok.get_ttl() - retry = tok.get_ttl() - expire = tok.get_ttl() - minimum = tok.get_ttl() - return cls( - rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.mname.to_wire(file, compress, origin, canonicalize) - self.rname.to_wire(file, compress, origin, canonicalize) - five_ints = struct.pack( - "!IIIII", self.serial, self.refresh, self.retry, self.expire, self.minimum - ) - file.write(five_ints) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - mname = parser.get_name(origin) - rname = parser.get_name(origin) - return cls(rdclass, rdtype, mname, rname, *parser.get_struct("!IIIII")) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SPF.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SPF.py deleted file mode 100644 index 1df3b70..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SPF.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class SPF(dns.rdtypes.txtbase.TXTBase): - """SPF record""" - - # see: RFC 4408 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SSHFP.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SSHFP.py deleted file mode 100644 index d2c4b07..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SSHFP.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii -import struct - -import dns.immutable -import dns.rdata -import dns.rdatatype - - -@dns.immutable.immutable -class SSHFP(dns.rdata.Rdata): - """SSHFP record""" - - # See RFC 4255 - - __slots__ = ["algorithm", "fp_type", "fingerprint"] - - def __init__(self, rdclass, rdtype, algorithm, fp_type, fingerprint): - super().__init__(rdclass, rdtype) - self.algorithm = self._as_uint8(algorithm) - self.fp_type = self._as_uint8(fp_type) - self.fingerprint = self._as_bytes(fingerprint, True) - - def to_text(self, origin=None, relativize=True, **kw): - kw = kw.copy() - chunksize = kw.pop("chunksize", 128) - return "%d %d %s" % ( - self.algorithm, - self.fp_type, - dns.rdata._hexify(self.fingerprint, chunksize=chunksize, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_uint8() - fp_type = tok.get_uint8() - fingerprint = tok.concatenate_remaining_identifiers().encode() - fingerprint = binascii.unhexlify(fingerprint) - return cls(rdclass, rdtype, algorithm, fp_type, fingerprint) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!BB", self.algorithm, self.fp_type) - file.write(header) - file.write(self.fingerprint) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("BB") - fingerprint = parser.get_remaining() - return cls(rdclass, rdtype, header[0], header[1], fingerprint) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TKEY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TKEY.py deleted file mode 100644 index 75f6224..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TKEY.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import struct - -import dns.exception -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class TKEY(dns.rdata.Rdata): - """TKEY Record""" - - __slots__ = [ - "algorithm", - "inception", - "expiration", - "mode", - "error", - "key", - "other", - ] - - def __init__( - self, - rdclass, - rdtype, - algorithm, - inception, - expiration, - mode, - error, - key, - other=b"", - ): - super().__init__(rdclass, rdtype) - self.algorithm = self._as_name(algorithm) - self.inception = self._as_uint32(inception) - self.expiration = self._as_uint32(expiration) - self.mode = self._as_uint16(mode) - self.error = self._as_uint16(error) - self.key = self._as_bytes(key) - self.other = self._as_bytes(other) - - def to_text(self, origin=None, relativize=True, **kw): - _algorithm = self.algorithm.choose_relativity(origin, relativize) - text = "%s %u %u %u %u %s" % ( - str(_algorithm), - self.inception, - self.expiration, - self.mode, - self.error, - dns.rdata._base64ify(self.key, 0), - ) - if len(self.other) > 0: - text += f" {dns.rdata._base64ify(self.other, 0)}" - - return text - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_name(relativize=False) - inception = tok.get_uint32() - expiration = tok.get_uint32() - mode = tok.get_uint16() - error = tok.get_uint16() - key_b64 = tok.get_string().encode() - key = base64.b64decode(key_b64) - other_b64 = tok.concatenate_remaining_identifiers(True).encode() - other = base64.b64decode(other_b64) - - return cls( - rdclass, rdtype, algorithm, inception, expiration, mode, error, key, other - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.algorithm.to_wire(file, compress, origin) - file.write( - struct.pack("!IIHH", self.inception, self.expiration, self.mode, self.error) - ) - file.write(struct.pack("!H", len(self.key))) - file.write(self.key) - file.write(struct.pack("!H", len(self.other))) - if len(self.other) > 0: - file.write(self.other) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - algorithm = parser.get_name(origin) - inception, expiration, mode, error = parser.get_struct("!IIHH") - key = parser.get_counted_bytes(2) - other = parser.get_counted_bytes(2) - - return cls( - rdclass, rdtype, algorithm, inception, expiration, mode, error, key, other - ) - - # Constants for the mode field - from RFC 2930: - # 2.5 The Mode Field - # - # The mode field specifies the general scheme for key agreement or - # the purpose of the TKEY DNS message. Servers and resolvers - # supporting this specification MUST implement the Diffie-Hellman key - # agreement mode and the key deletion mode for queries. All other - # modes are OPTIONAL. A server supporting TKEY that receives a TKEY - # request with a mode it does not support returns the BADMODE error. - # The following values of the Mode octet are defined, available, or - # reserved: - # - # Value Description - # ----- ----------- - # 0 - reserved, see section 7 - # 1 server assignment - # 2 Diffie-Hellman exchange - # 3 GSS-API negotiation - # 4 resolver assignment - # 5 key deletion - # 6-65534 - available, see section 7 - # 65535 - reserved, see section 7 - SERVER_ASSIGNMENT = 1 - DIFFIE_HELLMAN_EXCHANGE = 2 - GSSAPI_NEGOTIATION = 3 - RESOLVER_ASSIGNMENT = 4 - KEY_DELETION = 5 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TLSA.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TLSA.py deleted file mode 100644 index 4dffc55..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TLSA.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import dns.immutable -import dns.rdtypes.tlsabase - - -@dns.immutable.immutable -class TLSA(dns.rdtypes.tlsabase.TLSABase): - """TLSA record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TSIG.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TSIG.py deleted file mode 100644 index 7942382..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TSIG.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import struct - -import dns.exception -import dns.immutable -import dns.rcode -import dns.rdata - - -@dns.immutable.immutable -class TSIG(dns.rdata.Rdata): - """TSIG record""" - - __slots__ = [ - "algorithm", - "time_signed", - "fudge", - "mac", - "original_id", - "error", - "other", - ] - - def __init__( - self, - rdclass, - rdtype, - algorithm, - time_signed, - fudge, - mac, - original_id, - error, - other, - ): - """Initialize a TSIG rdata. - - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *algorithm*, a ``dns.name.Name``. - - *time_signed*, an ``int``. - - *fudge*, an ``int`. - - *mac*, a ``bytes`` - - *original_id*, an ``int`` - - *error*, an ``int`` - - *other*, a ``bytes`` - """ - - super().__init__(rdclass, rdtype) - self.algorithm = self._as_name(algorithm) - self.time_signed = self._as_uint48(time_signed) - self.fudge = self._as_uint16(fudge) - self.mac = self._as_bytes(mac) - self.original_id = self._as_uint16(original_id) - self.error = dns.rcode.Rcode.make(error) - self.other = self._as_bytes(other) - - def to_text(self, origin=None, relativize=True, **kw): - algorithm = self.algorithm.choose_relativity(origin, relativize) - error = dns.rcode.to_text(self.error, True) - text = ( - f"{algorithm} {self.time_signed} {self.fudge} " - + f"{len(self.mac)} {dns.rdata._base64ify(self.mac, 0)} " - + f"{self.original_id} {error} {len(self.other)}" - ) - if self.other: - text += f" {dns.rdata._base64ify(self.other, 0)}" - return text - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - algorithm = tok.get_name(relativize=False) - time_signed = tok.get_uint48() - fudge = tok.get_uint16() - mac_len = tok.get_uint16() - mac = base64.b64decode(tok.get_string()) - if len(mac) != mac_len: - raise SyntaxError("invalid MAC") - original_id = tok.get_uint16() - error = dns.rcode.from_text(tok.get_string()) - other_len = tok.get_uint16() - if other_len > 0: - other = base64.b64decode(tok.get_string()) - if len(other) != other_len: - raise SyntaxError("invalid other data") - else: - other = b"" - return cls( - rdclass, - rdtype, - algorithm, - time_signed, - fudge, - mac, - original_id, - error, - other, - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.algorithm.to_wire(file, None, origin, False) - file.write( - struct.pack( - "!HIHH", - (self.time_signed >> 32) & 0xFFFF, - self.time_signed & 0xFFFFFFFF, - self.fudge, - len(self.mac), - ) - ) - file.write(self.mac) - file.write(struct.pack("!HHH", self.original_id, self.error, len(self.other))) - file.write(self.other) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - algorithm = parser.get_name() - time_signed = parser.get_uint48() - fudge = parser.get_uint16() - mac = parser.get_counted_bytes(2) - (original_id, error) = parser.get_struct("!HH") - other = parser.get_counted_bytes(2) - return cls( - rdclass, - rdtype, - algorithm, - time_signed, - fudge, - mac, - original_id, - error, - other, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TXT.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TXT.py deleted file mode 100644 index 6d4dae2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TXT.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class TXT(dns.rdtypes.txtbase.TXTBase): - """TXT record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/URI.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/URI.py deleted file mode 100644 index 2efbb30..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/URI.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# Copyright (C) 2015 Red Hat, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdtypes.util - - -@dns.immutable.immutable -class URI(dns.rdata.Rdata): - """URI record""" - - # see RFC 7553 - - __slots__ = ["priority", "weight", "target"] - - def __init__(self, rdclass, rdtype, priority, weight, target): - super().__init__(rdclass, rdtype) - self.priority = self._as_uint16(priority) - self.weight = self._as_uint16(weight) - self.target = self._as_bytes(target, True) - if len(self.target) == 0: - raise dns.exception.SyntaxError("URI target cannot be empty") - - def to_text(self, origin=None, relativize=True, **kw): - return '%d %d "%s"' % (self.priority, self.weight, self.target.decode()) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - priority = tok.get_uint16() - weight = tok.get_uint16() - target = tok.get().unescape() - if not (target.is_quoted_string() or target.is_identifier()): - raise dns.exception.SyntaxError("URI target must be a string") - return cls(rdclass, rdtype, priority, weight, target.value) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - two_ints = struct.pack("!HH", self.priority, self.weight) - file.write(two_ints) - file.write(self.target) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (priority, weight) = parser.get_struct("!HH") - target = parser.get_remaining() - if len(target) == 0: - raise dns.exception.FormError("URI target may not be empty") - return cls(rdclass, rdtype, priority, weight, target) - - def _processing_priority(self): - return self.priority - - def _processing_weight(self): - return self.weight - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.weighted_processing_order(iterable) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/WALLET.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/WALLET.py deleted file mode 100644 index ff46476..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/WALLET.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import dns.immutable -import dns.rdtypes.txtbase - - -@dns.immutable.immutable -class WALLET(dns.rdtypes.txtbase.TXTBase): - """WALLET record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/X25.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/X25.py deleted file mode 100644 index 2436ddb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/X25.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class X25(dns.rdata.Rdata): - """X25 record""" - - # see RFC 1183 - - __slots__ = ["address"] - - def __init__(self, rdclass, rdtype, address): - super().__init__(rdclass, rdtype) - self.address = self._as_bytes(address, True, 255) - - def to_text(self, origin=None, relativize=True, **kw): - return f'"{dns.rdata._escapify(self.address)}"' - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_string() - return cls(rdclass, rdtype, address) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - l = len(self.address) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(self.address) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_counted_bytes() - return cls(rdclass, rdtype, address) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ZONEMD.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ZONEMD.py deleted file mode 100644 index c90e3ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ZONEMD.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import binascii -import struct - -import dns.immutable -import dns.rdata -import dns.rdatatype -import dns.zonetypes - - -@dns.immutable.immutable -class ZONEMD(dns.rdata.Rdata): - """ZONEMD record""" - - # See RFC 8976 - - __slots__ = ["serial", "scheme", "hash_algorithm", "digest"] - - def __init__(self, rdclass, rdtype, serial, scheme, hash_algorithm, digest): - super().__init__(rdclass, rdtype) - self.serial = self._as_uint32(serial) - self.scheme = dns.zonetypes.DigestScheme.make(scheme) - self.hash_algorithm = dns.zonetypes.DigestHashAlgorithm.make(hash_algorithm) - self.digest = self._as_bytes(digest) - - if self.scheme == 0: # reserved, RFC 8976 Sec. 5.2 - raise ValueError("scheme 0 is reserved") - if self.hash_algorithm == 0: # reserved, RFC 8976 Sec. 5.3 - raise ValueError("hash_algorithm 0 is reserved") - - hasher = dns.zonetypes._digest_hashers.get(self.hash_algorithm) - if hasher and hasher().digest_size != len(self.digest): - raise ValueError("digest length inconsistent with hash algorithm") - - def to_text(self, origin=None, relativize=True, **kw): - kw = kw.copy() - chunksize = kw.pop("chunksize", 128) - return "%d %d %d %s" % ( - self.serial, - self.scheme, - self.hash_algorithm, - dns.rdata._hexify(self.digest, chunksize=chunksize, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - serial = tok.get_uint32() - scheme = tok.get_uint8() - hash_algorithm = tok.get_uint8() - digest = tok.concatenate_remaining_identifiers().encode() - digest = binascii.unhexlify(digest) - return cls(rdclass, rdtype, serial, scheme, hash_algorithm, digest) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!IBB", self.serial, self.scheme, self.hash_algorithm) - file.write(header) - file.write(self.digest) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("!IBB") - digest = parser.get_remaining() - return cls(rdclass, rdtype, header[0], header[1], header[2], digest) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/__init__.py deleted file mode 100644 index 647b215..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/__init__.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Class ANY (generic) rdata type classes.""" - -__all__ = [ - "AFSDB", - "AMTRELAY", - "AVC", - "CAA", - "CDNSKEY", - "CDS", - "CERT", - "CNAME", - "CSYNC", - "DLV", - "DNAME", - "DNSKEY", - "DS", - "EUI48", - "EUI64", - "GPOS", - "HINFO", - "HIP", - "ISDN", - "L32", - "L64", - "LOC", - "LP", - "MX", - "NID", - "NINFO", - "NS", - "NSEC", - "NSEC3", - "NSEC3PARAM", - "OPENPGPKEY", - "OPT", - "PTR", - "RESINFO", - "RP", - "RRSIG", - "RT", - "SMIMEA", - "SOA", - "SPF", - "SSHFP", - "TKEY", - "TLSA", - "TSIG", - "TXT", - "URI", - "WALLET", - "X25", - "ZONEMD", -] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/A.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/A.py deleted file mode 100644 index 832e8d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/A.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.immutable -import dns.rdtypes.mxbase - - -@dns.immutable.immutable -class A(dns.rdata.Rdata): - """A record for Chaosnet""" - - # domain: the domain of the address - # address: the 16-bit address - - __slots__ = ["domain", "address"] - - def __init__(self, rdclass, rdtype, domain, address): - super().__init__(rdclass, rdtype) - self.domain = self._as_name(domain) - self.address = self._as_uint16(address) - - def to_text(self, origin=None, relativize=True, **kw): - domain = self.domain.choose_relativity(origin, relativize) - return f"{domain} {self.address:o}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - domain = tok.get_name(origin, relativize, relativize_to) - address = tok.get_uint16(base=8) - return cls(rdclass, rdtype, domain, address) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.domain.to_wire(file, compress, origin, canonicalize) - pref = struct.pack("!H", self.address) - file.write(pref) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - domain = parser.get_name(origin) - address = parser.get_uint16() - return cls(rdclass, rdtype, domain, address) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/__init__.py deleted file mode 100644 index 0760c26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Class CH rdata type classes.""" - -__all__ = [ - "A", -] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/A.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/A.py deleted file mode 100644 index e09d611..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/A.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.immutable -import dns.ipv4 -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class A(dns.rdata.Rdata): - """A record.""" - - __slots__ = ["address"] - - def __init__(self, rdclass, rdtype, address): - super().__init__(rdclass, rdtype) - self.address = self._as_ipv4_address(address) - - def to_text(self, origin=None, relativize=True, **kw): - return self.address - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_identifier() - return cls(rdclass, rdtype, address) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(dns.ipv4.inet_aton(self.address)) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_remaining() - return cls(rdclass, rdtype, address) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/AAAA.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/AAAA.py deleted file mode 100644 index 0cd139e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/AAAA.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.exception -import dns.immutable -import dns.ipv6 -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class AAAA(dns.rdata.Rdata): - """AAAA record.""" - - __slots__ = ["address"] - - def __init__(self, rdclass, rdtype, address): - super().__init__(rdclass, rdtype) - self.address = self._as_ipv6_address(address) - - def to_text(self, origin=None, relativize=True, **kw): - return self.address - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_identifier() - return cls(rdclass, rdtype, address) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(dns.ipv6.inet_aton(self.address)) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_remaining() - return cls(rdclass, rdtype, address) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/APL.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/APL.py deleted file mode 100644 index 44cb3fe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/APL.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii -import codecs -import struct - -import dns.exception -import dns.immutable -import dns.ipv4 -import dns.ipv6 -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class APLItem: - """An APL list item.""" - - __slots__ = ["family", "negation", "address", "prefix"] - - def __init__(self, family, negation, address, prefix): - self.family = dns.rdata.Rdata._as_uint16(family) - self.negation = dns.rdata.Rdata._as_bool(negation) - if self.family == 1: - self.address = dns.rdata.Rdata._as_ipv4_address(address) - self.prefix = dns.rdata.Rdata._as_int(prefix, 0, 32) - elif self.family == 2: - self.address = dns.rdata.Rdata._as_ipv6_address(address) - self.prefix = dns.rdata.Rdata._as_int(prefix, 0, 128) - else: - self.address = dns.rdata.Rdata._as_bytes(address, max_length=127) - self.prefix = dns.rdata.Rdata._as_uint8(prefix) - - def __str__(self): - if self.negation: - return "!%d:%s/%s" % (self.family, self.address, self.prefix) - else: - return "%d:%s/%s" % (self.family, self.address, self.prefix) - - def to_wire(self, file): - if self.family == 1: - address = dns.ipv4.inet_aton(self.address) - elif self.family == 2: - address = dns.ipv6.inet_aton(self.address) - else: - address = binascii.unhexlify(self.address) - # - # Truncate least significant zero bytes. - # - last = 0 - for i in range(len(address) - 1, -1, -1): - if address[i] != 0: - last = i + 1 - break - address = address[0:last] - l = len(address) - assert l < 128 - if self.negation: - l |= 0x80 - header = struct.pack("!HBB", self.family, self.prefix, l) - file.write(header) - file.write(address) - - -@dns.immutable.immutable -class APL(dns.rdata.Rdata): - """APL record.""" - - # see: RFC 3123 - - __slots__ = ["items"] - - def __init__(self, rdclass, rdtype, items): - super().__init__(rdclass, rdtype) - for item in items: - if not isinstance(item, APLItem): - raise ValueError("item not an APLItem") - self.items = tuple(items) - - def to_text(self, origin=None, relativize=True, **kw): - return " ".join(map(str, self.items)) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - items = [] - for token in tok.get_remaining(): - item = token.unescape().value - if item[0] == "!": - negation = True - item = item[1:] - else: - negation = False - (family, rest) = item.split(":", 1) - family = int(family) - (address, prefix) = rest.split("/", 1) - prefix = int(prefix) - item = APLItem(family, negation, address, prefix) - items.append(item) - - return cls(rdclass, rdtype, items) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - for item in self.items: - item.to_wire(file) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - items = [] - while parser.remaining() > 0: - header = parser.get_struct("!HBB") - afdlen = header[2] - if afdlen > 127: - negation = True - afdlen -= 128 - else: - negation = False - address = parser.get_bytes(afdlen) - l = len(address) - if header[0] == 1: - if l < 4: - address += b"\x00" * (4 - l) - elif header[0] == 2: - if l < 16: - address += b"\x00" * (16 - l) - else: - # - # This isn't really right according to the RFC, but it - # seems better than throwing an exception - # - address = codecs.encode(address, "hex_codec") - item = APLItem(header[0], negation, address, header[1]) - items.append(item) - return cls(rdclass, rdtype, items) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/DHCID.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/DHCID.py deleted file mode 100644 index 723492f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/DHCID.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 - -import dns.exception -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class DHCID(dns.rdata.Rdata): - """DHCID record""" - - # see: RFC 4701 - - __slots__ = ["data"] - - def __init__(self, rdclass, rdtype, data): - super().__init__(rdclass, rdtype) - self.data = self._as_bytes(data) - - def to_text(self, origin=None, relativize=True, **kw): - return dns.rdata._base64ify(self.data, **kw) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - b64 = tok.concatenate_remaining_identifiers().encode() - data = base64.b64decode(b64) - return cls(rdclass, rdtype, data) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(self.data) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - data = parser.get_remaining() - return cls(rdclass, rdtype, data) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/HTTPS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/HTTPS.py deleted file mode 100644 index 15464cb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/HTTPS.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import dns.immutable -import dns.rdtypes.svcbbase - - -@dns.immutable.immutable -class HTTPS(dns.rdtypes.svcbbase.SVCBBase): - """HTTPS record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/IPSECKEY.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/IPSECKEY.py deleted file mode 100644 index e3a6615..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/IPSECKEY.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import struct - -import dns.exception -import dns.immutable -import dns.rdtypes.util - - -class Gateway(dns.rdtypes.util.Gateway): - name = "IPSECKEY gateway" - - -@dns.immutable.immutable -class IPSECKEY(dns.rdata.Rdata): - """IPSECKEY record""" - - # see: RFC 4025 - - __slots__ = ["precedence", "gateway_type", "algorithm", "gateway", "key"] - - def __init__( - self, rdclass, rdtype, precedence, gateway_type, algorithm, gateway, key - ): - super().__init__(rdclass, rdtype) - gateway = Gateway(gateway_type, gateway) - self.precedence = self._as_uint8(precedence) - self.gateway_type = gateway.type - self.algorithm = self._as_uint8(algorithm) - self.gateway = gateway.gateway - self.key = self._as_bytes(key) - - def to_text(self, origin=None, relativize=True, **kw): - gateway = Gateway(self.gateway_type, self.gateway).to_text(origin, relativize) - return "%d %d %d %s %s" % ( - self.precedence, - self.gateway_type, - self.algorithm, - gateway, - dns.rdata._base64ify(self.key, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - precedence = tok.get_uint8() - gateway_type = tok.get_uint8() - algorithm = tok.get_uint8() - gateway = Gateway.from_text( - gateway_type, tok, origin, relativize, relativize_to - ) - b64 = tok.concatenate_remaining_identifiers().encode() - key = base64.b64decode(b64) - return cls( - rdclass, rdtype, precedence, gateway_type, algorithm, gateway.gateway, key - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!BBB", self.precedence, self.gateway_type, self.algorithm) - file.write(header) - Gateway(self.gateway_type, self.gateway).to_wire( - file, compress, origin, canonicalize - ) - file.write(self.key) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("!BBB") - gateway_type = header[1] - gateway = Gateway.from_wire_parser(gateway_type, parser, origin) - key = parser.get_remaining() - return cls( - rdclass, rdtype, header[0], gateway_type, header[2], gateway.gateway, key - ) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/KX.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/KX.py deleted file mode 100644 index 6073df4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/KX.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.mxbase - - -@dns.immutable.immutable -class KX(dns.rdtypes.mxbase.UncompressedDowncasingMX): - """KX record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NAPTR.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NAPTR.py deleted file mode 100644 index 195d1cb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NAPTR.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdtypes.util - - -def _write_string(file, s): - l = len(s) - assert l < 256 - file.write(struct.pack("!B", l)) - file.write(s) - - -@dns.immutable.immutable -class NAPTR(dns.rdata.Rdata): - """NAPTR record""" - - # see: RFC 3403 - - __slots__ = ["order", "preference", "flags", "service", "regexp", "replacement"] - - def __init__( - self, rdclass, rdtype, order, preference, flags, service, regexp, replacement - ): - super().__init__(rdclass, rdtype) - self.flags = self._as_bytes(flags, True, 255) - self.service = self._as_bytes(service, True, 255) - self.regexp = self._as_bytes(regexp, True, 255) - self.order = self._as_uint16(order) - self.preference = self._as_uint16(preference) - self.replacement = self._as_name(replacement) - - def to_text(self, origin=None, relativize=True, **kw): - replacement = self.replacement.choose_relativity(origin, relativize) - return '%d %d "%s" "%s" "%s" %s' % ( - self.order, - self.preference, - dns.rdata._escapify(self.flags), - dns.rdata._escapify(self.service), - dns.rdata._escapify(self.regexp), - replacement, - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - order = tok.get_uint16() - preference = tok.get_uint16() - flags = tok.get_string() - service = tok.get_string() - regexp = tok.get_string() - replacement = tok.get_name(origin, relativize, relativize_to) - return cls( - rdclass, rdtype, order, preference, flags, service, regexp, replacement - ) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - two_ints = struct.pack("!HH", self.order, self.preference) - file.write(two_ints) - _write_string(file, self.flags) - _write_string(file, self.service) - _write_string(file, self.regexp) - self.replacement.to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (order, preference) = parser.get_struct("!HH") - strings = [] - for _ in range(3): - s = parser.get_counted_bytes() - strings.append(s) - replacement = parser.get_name(origin) - return cls( - rdclass, - rdtype, - order, - preference, - strings[0], - strings[1], - strings[2], - replacement, - ) - - def _processing_priority(self): - return (self.order, self.preference) - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.priority_processing_order(iterable) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP.py deleted file mode 100644 index d55edb7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii - -import dns.exception -import dns.immutable -import dns.rdata -import dns.tokenizer - - -@dns.immutable.immutable -class NSAP(dns.rdata.Rdata): - """NSAP record.""" - - # see: RFC 1706 - - __slots__ = ["address"] - - def __init__(self, rdclass, rdtype, address): - super().__init__(rdclass, rdtype) - self.address = self._as_bytes(address) - - def to_text(self, origin=None, relativize=True, **kw): - return f"0x{binascii.hexlify(self.address).decode()}" - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_string() - if address[0:2] != "0x": - raise dns.exception.SyntaxError("string does not start with 0x") - address = address[2:].replace(".", "") - if len(address) % 2 != 0: - raise dns.exception.SyntaxError("hexstring has odd length") - address = binascii.unhexlify(address.encode()) - return cls(rdclass, rdtype, address) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(self.address) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_remaining() - return cls(rdclass, rdtype, address) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP_PTR.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP_PTR.py deleted file mode 100644 index ce1c663..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP_PTR.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import dns.immutable -import dns.rdtypes.nsbase - - -@dns.immutable.immutable -class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): - """NSAP-PTR record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/PX.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/PX.py deleted file mode 100644 index cdca153..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/PX.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdtypes.util - - -@dns.immutable.immutable -class PX(dns.rdata.Rdata): - """PX record.""" - - # see: RFC 2163 - - __slots__ = ["preference", "map822", "mapx400"] - - def __init__(self, rdclass, rdtype, preference, map822, mapx400): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - self.map822 = self._as_name(map822) - self.mapx400 = self._as_name(mapx400) - - def to_text(self, origin=None, relativize=True, **kw): - map822 = self.map822.choose_relativity(origin, relativize) - mapx400 = self.mapx400.choose_relativity(origin, relativize) - return "%d %s %s" % (self.preference, map822, mapx400) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - map822 = tok.get_name(origin, relativize, relativize_to) - mapx400 = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, preference, map822, mapx400) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - pref = struct.pack("!H", self.preference) - file.write(pref) - self.map822.to_wire(file, None, origin, canonicalize) - self.mapx400.to_wire(file, None, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - map822 = parser.get_name(origin) - mapx400 = parser.get_name(origin) - return cls(rdclass, rdtype, preference, map822, mapx400) - - def _processing_priority(self): - return self.preference - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.priority_processing_order(iterable) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SRV.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SRV.py deleted file mode 100644 index 5adef98..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SRV.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdtypes.util - - -@dns.immutable.immutable -class SRV(dns.rdata.Rdata): - """SRV record""" - - # see: RFC 2782 - - __slots__ = ["priority", "weight", "port", "target"] - - def __init__(self, rdclass, rdtype, priority, weight, port, target): - super().__init__(rdclass, rdtype) - self.priority = self._as_uint16(priority) - self.weight = self._as_uint16(weight) - self.port = self._as_uint16(port) - self.target = self._as_name(target) - - def to_text(self, origin=None, relativize=True, **kw): - target = self.target.choose_relativity(origin, relativize) - return "%d %d %d %s" % (self.priority, self.weight, self.port, target) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - priority = tok.get_uint16() - weight = tok.get_uint16() - port = tok.get_uint16() - target = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, priority, weight, port, target) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - three_ints = struct.pack("!HHH", self.priority, self.weight, self.port) - file.write(three_ints) - self.target.to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - (priority, weight, port) = parser.get_struct("!HHH") - target = parser.get_name(origin) - return cls(rdclass, rdtype, priority, weight, port, target) - - def _processing_priority(self): - return self.priority - - def _processing_weight(self): - return self.weight - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.weighted_processing_order(iterable) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SVCB.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SVCB.py deleted file mode 100644 index ff3e932..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SVCB.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import dns.immutable -import dns.rdtypes.svcbbase - - -@dns.immutable.immutable -class SVCB(dns.rdtypes.svcbbase.SVCBBase): - """SVCB record""" diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/WKS.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/WKS.py deleted file mode 100644 index 881a784..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/WKS.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import socket -import struct - -import dns.immutable -import dns.ipv4 -import dns.rdata - -try: - _proto_tcp = socket.getprotobyname("tcp") - _proto_udp = socket.getprotobyname("udp") -except OSError: - # Fall back to defaults in case /etc/protocols is unavailable. - _proto_tcp = 6 - _proto_udp = 17 - - -@dns.immutable.immutable -class WKS(dns.rdata.Rdata): - """WKS record""" - - # see: RFC 1035 - - __slots__ = ["address", "protocol", "bitmap"] - - def __init__(self, rdclass, rdtype, address, protocol, bitmap): - super().__init__(rdclass, rdtype) - self.address = self._as_ipv4_address(address) - self.protocol = self._as_uint8(protocol) - self.bitmap = self._as_bytes(bitmap) - - def to_text(self, origin=None, relativize=True, **kw): - bits = [] - for i, byte in enumerate(self.bitmap): - for j in range(0, 8): - if byte & (0x80 >> j): - bits.append(str(i * 8 + j)) - text = " ".join(bits) - return "%s %d %s" % (self.address, self.protocol, text) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - address = tok.get_string() - protocol = tok.get_string() - if protocol.isdigit(): - protocol = int(protocol) - else: - protocol = socket.getprotobyname(protocol) - bitmap = bytearray() - for token in tok.get_remaining(): - value = token.unescape().value - if value.isdigit(): - serv = int(value) - else: - if protocol != _proto_udp and protocol != _proto_tcp: - raise NotImplementedError("protocol must be TCP or UDP") - if protocol == _proto_udp: - protocol_text = "udp" - else: - protocol_text = "tcp" - serv = socket.getservbyname(value, protocol_text) - i = serv // 8 - l = len(bitmap) - if l < i + 1: - for _ in range(l, i + 1): - bitmap.append(0) - bitmap[i] = bitmap[i] | (0x80 >> (serv % 8)) - bitmap = dns.rdata._truncate_bitmap(bitmap) - return cls(rdclass, rdtype, address, protocol, bitmap) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(dns.ipv4.inet_aton(self.address)) - protocol = struct.pack("!B", self.protocol) - file.write(protocol) - file.write(self.bitmap) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - address = parser.get_bytes(4) - protocol = parser.get_uint8() - bitmap = parser.get_remaining() - return cls(rdclass, rdtype, address, protocol, bitmap) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/__init__.py deleted file mode 100644 index dcec4dd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Class IN rdata type classes.""" - -__all__ = [ - "A", - "AAAA", - "APL", - "DHCID", - "HTTPS", - "IPSECKEY", - "KX", - "NAPTR", - "NSAP", - "NSAP_PTR", - "PX", - "SRV", - "SVCB", - "WKS", -] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/__init__.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/__init__.py deleted file mode 100644 index 3997f84..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS rdata type classes""" - -__all__ = [ - "ANY", - "IN", - "CH", - "dnskeybase", - "dsbase", - "euibase", - "mxbase", - "nsbase", - "svcbbase", - "tlsabase", - "txtbase", - "util", -] diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dnskeybase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dnskeybase.py deleted file mode 100644 index db300f8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dnskeybase.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import base64 -import enum -import struct - -import dns.dnssectypes -import dns.exception -import dns.immutable -import dns.rdata - -# wildcard import -__all__ = ["SEP", "REVOKE", "ZONE"] # noqa: F822 - - -class Flag(enum.IntFlag): - SEP = 0x0001 - REVOKE = 0x0080 - ZONE = 0x0100 - - -@dns.immutable.immutable -class DNSKEYBase(dns.rdata.Rdata): - """Base class for rdata that is like a DNSKEY record""" - - __slots__ = ["flags", "protocol", "algorithm", "key"] - - def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): - super().__init__(rdclass, rdtype) - self.flags = Flag(self._as_uint16(flags)) - self.protocol = self._as_uint8(protocol) - self.algorithm = dns.dnssectypes.Algorithm.make(algorithm) - self.key = self._as_bytes(key) - - def to_text(self, origin=None, relativize=True, **kw): - return "%d %d %d %s" % ( - self.flags, - self.protocol, - self.algorithm, - dns.rdata._base64ify(self.key, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - flags = tok.get_uint16() - protocol = tok.get_uint8() - algorithm = tok.get_string() - b64 = tok.concatenate_remaining_identifiers().encode() - key = base64.b64decode(b64) - return cls(rdclass, rdtype, flags, protocol, algorithm, key) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) - file.write(header) - file.write(self.key) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("!HBB") - key = parser.get_remaining() - return cls(rdclass, rdtype, header[0], header[1], header[2], key) - - -### BEGIN generated Flag constants - -SEP = Flag.SEP -REVOKE = Flag.REVOKE -ZONE = Flag.ZONE - -### END generated Flag constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dsbase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dsbase.py deleted file mode 100644 index cd21f02..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dsbase.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2010, 2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii -import struct - -import dns.dnssectypes -import dns.immutable -import dns.rdata -import dns.rdatatype - - -@dns.immutable.immutable -class DSBase(dns.rdata.Rdata): - """Base class for rdata that is like a DS record""" - - __slots__ = ["key_tag", "algorithm", "digest_type", "digest"] - - # Digest types registry: - # https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml - _digest_length_by_type = { - 1: 20, # SHA-1, RFC 3658 Sec. 2.4 - 2: 32, # SHA-256, RFC 4509 Sec. 2.2 - 3: 32, # GOST R 34.11-94, RFC 5933 Sec. 4 in conjunction with RFC 4490 Sec. 2.1 - 4: 48, # SHA-384, RFC 6605 Sec. 2 - } - - def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, digest): - super().__init__(rdclass, rdtype) - self.key_tag = self._as_uint16(key_tag) - self.algorithm = dns.dnssectypes.Algorithm.make(algorithm) - self.digest_type = dns.dnssectypes.DSDigest.make(self._as_uint8(digest_type)) - self.digest = self._as_bytes(digest) - try: - if len(self.digest) != self._digest_length_by_type[self.digest_type]: - raise ValueError("digest length inconsistent with digest type") - except KeyError: - if self.digest_type == 0: # reserved, RFC 3658 Sec. 2.4 - raise ValueError("digest type 0 is reserved") - - def to_text(self, origin=None, relativize=True, **kw): - kw = kw.copy() - chunksize = kw.pop("chunksize", 128) - return "%d %d %d %s" % ( - self.key_tag, - self.algorithm, - self.digest_type, - dns.rdata._hexify(self.digest, chunksize=chunksize, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - key_tag = tok.get_uint16() - algorithm = tok.get_string() - digest_type = tok.get_uint8() - digest = tok.concatenate_remaining_identifiers().encode() - digest = binascii.unhexlify(digest) - return cls(rdclass, rdtype, key_tag, algorithm, digest_type, digest) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!HBB", self.key_tag, self.algorithm, self.digest_type) - file.write(header) - file.write(self.digest) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("!HBB") - digest = parser.get_remaining() - return cls(rdclass, rdtype, header[0], header[1], header[2], digest) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/euibase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/euibase.py deleted file mode 100644 index a39c166..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/euibase.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) 2015 Red Hat, Inc. -# Author: Petr Spacek -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii - -import dns.immutable -import dns.rdata - - -@dns.immutable.immutable -class EUIBase(dns.rdata.Rdata): - """EUIxx record""" - - # see: rfc7043.txt - - __slots__ = ["eui"] - # define these in subclasses - # byte_len = 6 # 0123456789ab (in hex) - # text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab - - def __init__(self, rdclass, rdtype, eui): - super().__init__(rdclass, rdtype) - self.eui = self._as_bytes(eui) - if len(self.eui) != self.byte_len: - raise dns.exception.FormError( - f"EUI{self.byte_len * 8} rdata has to have {self.byte_len} bytes" - ) - - def to_text(self, origin=None, relativize=True, **kw): - return dns.rdata._hexify(self.eui, chunksize=2, separator=b"-", **kw) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - text = tok.get_string() - if len(text) != cls.text_len: - raise dns.exception.SyntaxError( - f"Input text must have {cls.text_len} characters" - ) - for i in range(2, cls.byte_len * 3 - 1, 3): - if text[i] != "-": - raise dns.exception.SyntaxError(f"Dash expected at position {i}") - text = text.replace("-", "") - try: - data = binascii.unhexlify(text.encode()) - except (ValueError, TypeError) as ex: - raise dns.exception.SyntaxError(f"Hex decoding error: {str(ex)}") - return cls(rdclass, rdtype, data) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(self.eui) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - eui = parser.get_bytes(cls.byte_len) - return cls(rdclass, rdtype, eui) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/mxbase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/mxbase.py deleted file mode 100644 index 6d5e3d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/mxbase.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""MX-like base classes.""" - -import struct - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata -import dns.rdtypes.util - - -@dns.immutable.immutable -class MXBase(dns.rdata.Rdata): - """Base class for rdata that is like an MX record.""" - - __slots__ = ["preference", "exchange"] - - def __init__(self, rdclass, rdtype, preference, exchange): - super().__init__(rdclass, rdtype) - self.preference = self._as_uint16(preference) - self.exchange = self._as_name(exchange) - - def to_text(self, origin=None, relativize=True, **kw): - exchange = self.exchange.choose_relativity(origin, relativize) - return "%d %s" % (self.preference, exchange) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - preference = tok.get_uint16() - exchange = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, preference, exchange) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - pref = struct.pack("!H", self.preference) - file.write(pref) - self.exchange.to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - preference = parser.get_uint16() - exchange = parser.get_name(origin) - return cls(rdclass, rdtype, preference, exchange) - - def _processing_priority(self): - return self.preference - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.priority_processing_order(iterable) - - -@dns.immutable.immutable -class UncompressedMX(MXBase): - """Base class for rdata that is like an MX record, but whose name - is not compressed when converted to DNS wire format, and whose - digestable form is not downcased.""" - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - super()._to_wire(file, None, origin, False) - - -@dns.immutable.immutable -class UncompressedDowncasingMX(MXBase): - """Base class for rdata that is like an MX record, but whose name - is not compressed when convert to DNS wire format.""" - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - super()._to_wire(file, None, origin, canonicalize) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/nsbase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/nsbase.py deleted file mode 100644 index 904224f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/nsbase.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""NS-like base classes.""" - -import dns.exception -import dns.immutable -import dns.name -import dns.rdata - - -@dns.immutable.immutable -class NSBase(dns.rdata.Rdata): - """Base class for rdata that is like an NS record.""" - - __slots__ = ["target"] - - def __init__(self, rdclass, rdtype, target): - super().__init__(rdclass, rdtype) - self.target = self._as_name(target) - - def to_text(self, origin=None, relativize=True, **kw): - target = self.target.choose_relativity(origin, relativize) - return str(target) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - target = tok.get_name(origin, relativize, relativize_to) - return cls(rdclass, rdtype, target) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.target.to_wire(file, compress, origin, canonicalize) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - target = parser.get_name(origin) - return cls(rdclass, rdtype, target) - - -@dns.immutable.immutable -class UncompressedNS(NSBase): - """Base class for rdata that is like an NS record, but whose name - is not compressed when convert to DNS wire format, and whose - digestable form is not downcased.""" - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - self.target.to_wire(file, None, origin, False) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/svcbbase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/svcbbase.py deleted file mode 100644 index a2b15b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/svcbbase.py +++ /dev/null @@ -1,585 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import base64 -import enum -import struct - -import dns.enum -import dns.exception -import dns.immutable -import dns.ipv4 -import dns.ipv6 -import dns.name -import dns.rdata -import dns.rdtypes.util -import dns.renderer -import dns.tokenizer -import dns.wire - -# Until there is an RFC, this module is experimental and may be changed in -# incompatible ways. - - -class UnknownParamKey(dns.exception.DNSException): - """Unknown SVCB ParamKey""" - - -class ParamKey(dns.enum.IntEnum): - """SVCB ParamKey""" - - MANDATORY = 0 - ALPN = 1 - NO_DEFAULT_ALPN = 2 - PORT = 3 - IPV4HINT = 4 - ECH = 5 - IPV6HINT = 6 - DOHPATH = 7 - OHTTP = 8 - - @classmethod - def _maximum(cls): - return 65535 - - @classmethod - def _short_name(cls): - return "SVCBParamKey" - - @classmethod - def _prefix(cls): - return "KEY" - - @classmethod - def _unknown_exception_class(cls): - return UnknownParamKey - - -class Emptiness(enum.IntEnum): - NEVER = 0 - ALWAYS = 1 - ALLOWED = 2 - - -def _validate_key(key): - force_generic = False - if isinstance(key, bytes): - # We decode to latin-1 so we get 0-255 as valid and do NOT interpret - # UTF-8 sequences - key = key.decode("latin-1") - if isinstance(key, str): - if key.lower().startswith("key"): - force_generic = True - if key[3:].startswith("0") and len(key) != 4: - # key has leading zeros - raise ValueError("leading zeros in key") - key = key.replace("-", "_") - return (ParamKey.make(key), force_generic) - - -def key_to_text(key): - return ParamKey.to_text(key).replace("_", "-").lower() - - -# Like rdata escapify, but escapes ',' too. - -_escaped = b'",\\' - - -def _escapify(qstring): - text = "" - for c in qstring: - if c in _escaped: - text += "\\" + chr(c) - elif c >= 0x20 and c < 0x7F: - text += chr(c) - else: - text += "\\%03d" % c - return text - - -def _unescape(value): - if value == "": - return value - unescaped = b"" - l = len(value) - i = 0 - while i < l: - c = value[i] - i += 1 - if c == "\\": - if i >= l: # pragma: no cover (can't happen via tokenizer get()) - raise dns.exception.UnexpectedEnd - c = value[i] - i += 1 - if c.isdigit(): - if i >= l: - raise dns.exception.UnexpectedEnd - c2 = value[i] - i += 1 - if i >= l: - raise dns.exception.UnexpectedEnd - c3 = value[i] - i += 1 - if not (c2.isdigit() and c3.isdigit()): - raise dns.exception.SyntaxError - codepoint = int(c) * 100 + int(c2) * 10 + int(c3) - if codepoint > 255: - raise dns.exception.SyntaxError - unescaped += b"%c" % (codepoint) - continue - unescaped += c.encode() - return unescaped - - -def _split(value): - l = len(value) - i = 0 - items = [] - unescaped = b"" - while i < l: - c = value[i] - i += 1 - if c == ord("\\"): - if i >= l: # pragma: no cover (can't happen via tokenizer get()) - raise dns.exception.UnexpectedEnd - c = value[i] - i += 1 - unescaped += b"%c" % (c) - elif c == ord(","): - items.append(unescaped) - unescaped = b"" - else: - unescaped += b"%c" % (c) - items.append(unescaped) - return items - - -@dns.immutable.immutable -class Param: - """Abstract base class for SVCB parameters""" - - @classmethod - def emptiness(cls): - return Emptiness.NEVER - - -@dns.immutable.immutable -class GenericParam(Param): - """Generic SVCB parameter""" - - def __init__(self, value): - self.value = dns.rdata.Rdata._as_bytes(value, True) - - @classmethod - def emptiness(cls): - return Emptiness.ALLOWED - - @classmethod - def from_value(cls, value): - if value is None or len(value) == 0: - return None - else: - return cls(_unescape(value)) - - def to_text(self): - return '"' + dns.rdata._escapify(self.value) + '"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - value = parser.get_bytes(parser.remaining()) - if len(value) == 0: - return None - else: - return cls(value) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - file.write(self.value) - - -@dns.immutable.immutable -class MandatoryParam(Param): - def __init__(self, keys): - # check for duplicates - keys = sorted([_validate_key(key)[0] for key in keys]) - prior_k = None - for k in keys: - if k == prior_k: - raise ValueError(f"duplicate key {k:d}") - prior_k = k - if k == ParamKey.MANDATORY: - raise ValueError("listed the mandatory key as mandatory") - self.keys = tuple(keys) - - @classmethod - def from_value(cls, value): - keys = [k.encode() for k in value.split(",")] - return cls(keys) - - def to_text(self): - return '"' + ",".join([key_to_text(key) for key in self.keys]) + '"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - keys = [] - last_key = -1 - while parser.remaining() > 0: - key = parser.get_uint16() - if key < last_key: - raise dns.exception.FormError("manadatory keys not ascending") - last_key = key - keys.append(key) - return cls(keys) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - for key in self.keys: - file.write(struct.pack("!H", key)) - - -@dns.immutable.immutable -class ALPNParam(Param): - def __init__(self, ids): - self.ids = dns.rdata.Rdata._as_tuple( - ids, lambda x: dns.rdata.Rdata._as_bytes(x, True, 255, False) - ) - - @classmethod - def from_value(cls, value): - return cls(_split(_unescape(value))) - - def to_text(self): - value = ",".join([_escapify(id) for id in self.ids]) - return '"' + dns.rdata._escapify(value.encode()) + '"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - ids = [] - while parser.remaining() > 0: - id = parser.get_counted_bytes() - ids.append(id) - return cls(ids) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - for id in self.ids: - file.write(struct.pack("!B", len(id))) - file.write(id) - - -@dns.immutable.immutable -class NoDefaultALPNParam(Param): - # We don't ever expect to instantiate this class, but we need - # a from_value() and a from_wire_parser(), so we just return None - # from the class methods when things are OK. - - @classmethod - def emptiness(cls): - return Emptiness.ALWAYS - - @classmethod - def from_value(cls, value): - if value is None or value == "": - return None - else: - raise ValueError("no-default-alpn with non-empty value") - - def to_text(self): - raise NotImplementedError # pragma: no cover - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - if parser.remaining() != 0: - raise dns.exception.FormError - return None - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - raise NotImplementedError # pragma: no cover - - -@dns.immutable.immutable -class PortParam(Param): - def __init__(self, port): - self.port = dns.rdata.Rdata._as_uint16(port) - - @classmethod - def from_value(cls, value): - value = int(value) - return cls(value) - - def to_text(self): - return f'"{self.port}"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - port = parser.get_uint16() - return cls(port) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - file.write(struct.pack("!H", self.port)) - - -@dns.immutable.immutable -class IPv4HintParam(Param): - def __init__(self, addresses): - self.addresses = dns.rdata.Rdata._as_tuple( - addresses, dns.rdata.Rdata._as_ipv4_address - ) - - @classmethod - def from_value(cls, value): - addresses = value.split(",") - return cls(addresses) - - def to_text(self): - return '"' + ",".join(self.addresses) + '"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - addresses = [] - while parser.remaining() > 0: - ip = parser.get_bytes(4) - addresses.append(dns.ipv4.inet_ntoa(ip)) - return cls(addresses) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - for address in self.addresses: - file.write(dns.ipv4.inet_aton(address)) - - -@dns.immutable.immutable -class IPv6HintParam(Param): - def __init__(self, addresses): - self.addresses = dns.rdata.Rdata._as_tuple( - addresses, dns.rdata.Rdata._as_ipv6_address - ) - - @classmethod - def from_value(cls, value): - addresses = value.split(",") - return cls(addresses) - - def to_text(self): - return '"' + ",".join(self.addresses) + '"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - addresses = [] - while parser.remaining() > 0: - ip = parser.get_bytes(16) - addresses.append(dns.ipv6.inet_ntoa(ip)) - return cls(addresses) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - for address in self.addresses: - file.write(dns.ipv6.inet_aton(address)) - - -@dns.immutable.immutable -class ECHParam(Param): - def __init__(self, ech): - self.ech = dns.rdata.Rdata._as_bytes(ech, True) - - @classmethod - def from_value(cls, value): - if "\\" in value: - raise ValueError("escape in ECH value") - value = base64.b64decode(value.encode()) - return cls(value) - - def to_text(self): - b64 = base64.b64encode(self.ech).decode("ascii") - return f'"{b64}"' - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - value = parser.get_bytes(parser.remaining()) - return cls(value) - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - file.write(self.ech) - - -@dns.immutable.immutable -class OHTTPParam(Param): - # We don't ever expect to instantiate this class, but we need - # a from_value() and a from_wire_parser(), so we just return None - # from the class methods when things are OK. - - @classmethod - def emptiness(cls): - return Emptiness.ALWAYS - - @classmethod - def from_value(cls, value): - if value is None or value == "": - return None - else: - raise ValueError("ohttp with non-empty value") - - def to_text(self): - raise NotImplementedError # pragma: no cover - - @classmethod - def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 - if parser.remaining() != 0: - raise dns.exception.FormError - return None - - def to_wire(self, file, origin=None): # pylint: disable=W0613 - raise NotImplementedError # pragma: no cover - - -_class_for_key = { - ParamKey.MANDATORY: MandatoryParam, - ParamKey.ALPN: ALPNParam, - ParamKey.NO_DEFAULT_ALPN: NoDefaultALPNParam, - ParamKey.PORT: PortParam, - ParamKey.IPV4HINT: IPv4HintParam, - ParamKey.ECH: ECHParam, - ParamKey.IPV6HINT: IPv6HintParam, - ParamKey.OHTTP: OHTTPParam, -} - - -def _validate_and_define(params, key, value): - (key, force_generic) = _validate_key(_unescape(key)) - if key in params: - raise SyntaxError(f'duplicate key "{key:d}"') - cls = _class_for_key.get(key, GenericParam) - emptiness = cls.emptiness() - if value is None: - if emptiness == Emptiness.NEVER: - raise SyntaxError("value cannot be empty") - value = cls.from_value(value) - else: - if force_generic: - value = cls.from_wire_parser(dns.wire.Parser(_unescape(value))) - else: - value = cls.from_value(value) - params[key] = value - - -@dns.immutable.immutable -class SVCBBase(dns.rdata.Rdata): - """Base class for SVCB-like records""" - - # see: draft-ietf-dnsop-svcb-https-11 - - __slots__ = ["priority", "target", "params"] - - def __init__(self, rdclass, rdtype, priority, target, params): - super().__init__(rdclass, rdtype) - self.priority = self._as_uint16(priority) - self.target = self._as_name(target) - for k, v in params.items(): - k = ParamKey.make(k) - if not isinstance(v, Param) and v is not None: - raise ValueError(f"{k:d} not a Param") - self.params = dns.immutable.Dict(params) - # Make sure any parameter listed as mandatory is present in the - # record. - mandatory = params.get(ParamKey.MANDATORY) - if mandatory: - for key in mandatory.keys: - # Note we have to say "not in" as we have None as a value - # so a get() and a not None test would be wrong. - if key not in params: - raise ValueError(f"key {key:d} declared mandatory but not present") - # The no-default-alpn parameter requires the alpn parameter. - if ParamKey.NO_DEFAULT_ALPN in params: - if ParamKey.ALPN not in params: - raise ValueError("no-default-alpn present, but alpn missing") - - def to_text(self, origin=None, relativize=True, **kw): - target = self.target.choose_relativity(origin, relativize) - params = [] - for key in sorted(self.params.keys()): - value = self.params[key] - if value is None: - params.append(key_to_text(key)) - else: - kv = key_to_text(key) + "=" + value.to_text() - params.append(kv) - if len(params) > 0: - space = " " - else: - space = "" - return "%d %s%s%s" % (self.priority, target, space, " ".join(params)) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - priority = tok.get_uint16() - target = tok.get_name(origin, relativize, relativize_to) - if priority == 0: - token = tok.get() - if not token.is_eol_or_eof(): - raise SyntaxError("parameters in AliasMode") - tok.unget(token) - params = {} - while True: - token = tok.get() - if token.is_eol_or_eof(): - tok.unget(token) - break - if token.ttype != dns.tokenizer.IDENTIFIER: - raise SyntaxError("parameter is not an identifier") - equals = token.value.find("=") - if equals == len(token.value) - 1: - # 'key=', so next token should be a quoted string without - # any intervening whitespace. - key = token.value[:-1] - token = tok.get(want_leading=True) - if token.ttype != dns.tokenizer.QUOTED_STRING: - raise SyntaxError("whitespace after =") - value = token.value - elif equals > 0: - # key=value - key = token.value[:equals] - value = token.value[equals + 1 :] - elif equals == 0: - # =key - raise SyntaxError('parameter cannot start with "="') - else: - # key - key = token.value - value = None - _validate_and_define(params, key, value) - return cls(rdclass, rdtype, priority, target, params) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - file.write(struct.pack("!H", self.priority)) - self.target.to_wire(file, None, origin, False) - for key in sorted(self.params): - file.write(struct.pack("!H", key)) - value = self.params[key] - with dns.renderer.prefixed_length(file, 2): - # Note that we're still writing a length of zero if the value is None - if value is not None: - value.to_wire(file, origin) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - priority = parser.get_uint16() - target = parser.get_name(origin) - if priority == 0 and parser.remaining() != 0: - raise dns.exception.FormError("parameters in AliasMode") - params = {} - prior_key = -1 - while parser.remaining() > 0: - key = parser.get_uint16() - if key < prior_key: - raise dns.exception.FormError("keys not in order") - prior_key = key - vlen = parser.get_uint16() - pcls = _class_for_key.get(key, GenericParam) - with parser.restrict_to(vlen): - value = pcls.from_wire_parser(parser, origin) - params[key] = value - return cls(rdclass, rdtype, priority, target, params) - - def _processing_priority(self): - return self.priority - - @classmethod - def _processing_order(cls, iterable): - return dns.rdtypes.util.priority_processing_order(iterable) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/tlsabase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/tlsabase.py deleted file mode 100644 index a059d2c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/tlsabase.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import binascii -import struct - -import dns.immutable -import dns.rdata -import dns.rdatatype - - -@dns.immutable.immutable -class TLSABase(dns.rdata.Rdata): - """Base class for TLSA and SMIMEA records""" - - # see: RFC 6698 - - __slots__ = ["usage", "selector", "mtype", "cert"] - - def __init__(self, rdclass, rdtype, usage, selector, mtype, cert): - super().__init__(rdclass, rdtype) - self.usage = self._as_uint8(usage) - self.selector = self._as_uint8(selector) - self.mtype = self._as_uint8(mtype) - self.cert = self._as_bytes(cert) - - def to_text(self, origin=None, relativize=True, **kw): - kw = kw.copy() - chunksize = kw.pop("chunksize", 128) - return "%d %d %d %s" % ( - self.usage, - self.selector, - self.mtype, - dns.rdata._hexify(self.cert, chunksize=chunksize, **kw), - ) - - @classmethod - def from_text( - cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None - ): - usage = tok.get_uint8() - selector = tok.get_uint8() - mtype = tok.get_uint8() - cert = tok.concatenate_remaining_identifiers().encode() - cert = binascii.unhexlify(cert) - return cls(rdclass, rdtype, usage, selector, mtype, cert) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - header = struct.pack("!BBB", self.usage, self.selector, self.mtype) - file.write(header) - file.write(self.cert) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - header = parser.get_struct("BBB") - cert = parser.get_remaining() - return cls(rdclass, rdtype, header[0], header[1], header[2], cert) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/txtbase.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/txtbase.py deleted file mode 100644 index 73db6d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/txtbase.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""TXT-like base class.""" - -from typing import Any, Dict, Iterable, Optional, Tuple, Union - -import dns.exception -import dns.immutable -import dns.rdata -import dns.renderer -import dns.tokenizer - - -@dns.immutable.immutable -class TXTBase(dns.rdata.Rdata): - """Base class for rdata that is like a TXT record (see RFC 1035).""" - - __slots__ = ["strings"] - - def __init__( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - strings: Iterable[Union[bytes, str]], - ): - """Initialize a TXT-like rdata. - - *rdclass*, an ``int`` is the rdataclass of the Rdata. - - *rdtype*, an ``int`` is the rdatatype of the Rdata. - - *strings*, a tuple of ``bytes`` - """ - super().__init__(rdclass, rdtype) - self.strings: Tuple[bytes] = self._as_tuple( - strings, lambda x: self._as_bytes(x, True, 255) - ) - if len(self.strings) == 0: - raise ValueError("the list of strings must not be empty") - - def to_text( - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - **kw: Dict[str, Any], - ) -> str: - txt = "" - prefix = "" - for s in self.strings: - txt += f'{prefix}"{dns.rdata._escapify(s)}"' - prefix = " " - return txt - - @classmethod - def from_text( - cls, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - tok: dns.tokenizer.Tokenizer, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, - ) -> dns.rdata.Rdata: - strings = [] - for token in tok.get_remaining(): - token = token.unescape_to_bytes() - # The 'if' below is always true in the current code, but we - # are leaving this check in in case things change some day. - if not ( - token.is_quoted_string() or token.is_identifier() - ): # pragma: no cover - raise dns.exception.SyntaxError("expected a string") - if len(token.value) > 255: - raise dns.exception.SyntaxError("string too long") - strings.append(token.value) - if len(strings) == 0: - raise dns.exception.UnexpectedEnd - return cls(rdclass, rdtype, strings) - - def _to_wire(self, file, compress=None, origin=None, canonicalize=False): - for s in self.strings: - with dns.renderer.prefixed_length(file, 1): - file.write(s) - - @classmethod - def from_wire_parser(cls, rdclass, rdtype, parser, origin=None): - strings = [] - while parser.remaining() > 0: - s = parser.get_counted_bytes() - strings.append(s) - return cls(rdclass, rdtype, strings) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/util.py b/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/util.py deleted file mode 100644 index 653a0bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/util.py +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import collections -import random -import struct -from typing import Any, List - -import dns.exception -import dns.ipv4 -import dns.ipv6 -import dns.name -import dns.rdata - - -class Gateway: - """A helper class for the IPSECKEY gateway and AMTRELAY relay fields""" - - name = "" - - def __init__(self, type, gateway=None): - self.type = dns.rdata.Rdata._as_uint8(type) - self.gateway = gateway - self._check() - - @classmethod - def _invalid_type(cls, gateway_type): - return f"invalid {cls.name} type: {gateway_type}" - - def _check(self): - if self.type == 0: - if self.gateway not in (".", None): - raise SyntaxError(f"invalid {self.name} for type 0") - self.gateway = None - elif self.type == 1: - # check that it's OK - dns.ipv4.inet_aton(self.gateway) - elif self.type == 2: - # check that it's OK - dns.ipv6.inet_aton(self.gateway) - elif self.type == 3: - if not isinstance(self.gateway, dns.name.Name): - raise SyntaxError(f"invalid {self.name}; not a name") - else: - raise SyntaxError(self._invalid_type(self.type)) - - def to_text(self, origin=None, relativize=True): - if self.type == 0: - return "." - elif self.type in (1, 2): - return self.gateway - elif self.type == 3: - return str(self.gateway.choose_relativity(origin, relativize)) - else: - raise ValueError(self._invalid_type(self.type)) # pragma: no cover - - @classmethod - def from_text( - cls, gateway_type, tok, origin=None, relativize=True, relativize_to=None - ): - if gateway_type in (0, 1, 2): - gateway = tok.get_string() - elif gateway_type == 3: - gateway = tok.get_name(origin, relativize, relativize_to) - else: - raise dns.exception.SyntaxError( - cls._invalid_type(gateway_type) - ) # pragma: no cover - return cls(gateway_type, gateway) - - # pylint: disable=unused-argument - def to_wire(self, file, compress=None, origin=None, canonicalize=False): - if self.type == 0: - pass - elif self.type == 1: - file.write(dns.ipv4.inet_aton(self.gateway)) - elif self.type == 2: - file.write(dns.ipv6.inet_aton(self.gateway)) - elif self.type == 3: - self.gateway.to_wire(file, None, origin, False) - else: - raise ValueError(self._invalid_type(self.type)) # pragma: no cover - - # pylint: enable=unused-argument - - @classmethod - def from_wire_parser(cls, gateway_type, parser, origin=None): - if gateway_type == 0: - gateway = None - elif gateway_type == 1: - gateway = dns.ipv4.inet_ntoa(parser.get_bytes(4)) - elif gateway_type == 2: - gateway = dns.ipv6.inet_ntoa(parser.get_bytes(16)) - elif gateway_type == 3: - gateway = parser.get_name(origin) - else: - raise dns.exception.FormError(cls._invalid_type(gateway_type)) - return cls(gateway_type, gateway) - - -class Bitmap: - """A helper class for the NSEC/NSEC3/CSYNC type bitmaps""" - - type_name = "" - - def __init__(self, windows=None): - last_window = -1 - self.windows = windows - for window, bitmap in self.windows: - if not isinstance(window, int): - raise ValueError(f"bad {self.type_name} window type") - if window <= last_window: - raise ValueError(f"bad {self.type_name} window order") - if window > 256: - raise ValueError(f"bad {self.type_name} window number") - last_window = window - if not isinstance(bitmap, bytes): - raise ValueError(f"bad {self.type_name} octets type") - if len(bitmap) == 0 or len(bitmap) > 32: - raise ValueError(f"bad {self.type_name} octets") - - def to_text(self) -> str: - text = "" - for window, bitmap in self.windows: - bits = [] - for i, byte in enumerate(bitmap): - for j in range(0, 8): - if byte & (0x80 >> j): - rdtype = window * 256 + i * 8 + j - bits.append(dns.rdatatype.to_text(rdtype)) - text += " " + " ".join(bits) - return text - - @classmethod - def from_text(cls, tok: "dns.tokenizer.Tokenizer") -> "Bitmap": - rdtypes = [] - for token in tok.get_remaining(): - rdtype = dns.rdatatype.from_text(token.unescape().value) - if rdtype == 0: - raise dns.exception.SyntaxError(f"{cls.type_name} with bit 0") - rdtypes.append(rdtype) - return cls.from_rdtypes(rdtypes) - - @classmethod - def from_rdtypes(cls, rdtypes: List[dns.rdatatype.RdataType]) -> "Bitmap": - rdtypes = sorted(rdtypes) - window = 0 - octets = 0 - prior_rdtype = 0 - bitmap = bytearray(b"\0" * 32) - windows = [] - for rdtype in rdtypes: - if rdtype == prior_rdtype: - continue - prior_rdtype = rdtype - new_window = rdtype // 256 - if new_window != window: - if octets != 0: - windows.append((window, bytes(bitmap[0:octets]))) - bitmap = bytearray(b"\0" * 32) - window = new_window - offset = rdtype % 256 - byte = offset // 8 - bit = offset % 8 - octets = byte + 1 - bitmap[byte] = bitmap[byte] | (0x80 >> bit) - if octets != 0: - windows.append((window, bytes(bitmap[0:octets]))) - return cls(windows) - - def to_wire(self, file: Any) -> None: - for window, bitmap in self.windows: - file.write(struct.pack("!BB", window, len(bitmap))) - file.write(bitmap) - - @classmethod - def from_wire_parser(cls, parser: "dns.wire.Parser") -> "Bitmap": - windows = [] - while parser.remaining() > 0: - window = parser.get_uint8() - bitmap = parser.get_counted_bytes() - windows.append((window, bitmap)) - return cls(windows) - - -def _priority_table(items): - by_priority = collections.defaultdict(list) - for rdata in items: - by_priority[rdata._processing_priority()].append(rdata) - return by_priority - - -def priority_processing_order(iterable): - items = list(iterable) - if len(items) == 1: - return items - by_priority = _priority_table(items) - ordered = [] - for k in sorted(by_priority.keys()): - rdatas = by_priority[k] - random.shuffle(rdatas) - ordered.extend(rdatas) - return ordered - - -_no_weight = 0.1 - - -def weighted_processing_order(iterable): - items = list(iterable) - if len(items) == 1: - return items - by_priority = _priority_table(items) - ordered = [] - for k in sorted(by_priority.keys()): - rdatas = by_priority[k] - total = sum(rdata._processing_weight() or _no_weight for rdata in rdatas) - while len(rdatas) > 1: - r = random.uniform(0, total) - for n, rdata in enumerate(rdatas): # noqa: B007 - weight = rdata._processing_weight() or _no_weight - if weight > r: - break - r -= weight - total -= weight - ordered.append(rdata) # pylint: disable=undefined-loop-variable - del rdatas[n] # pylint: disable=undefined-loop-variable - ordered.append(rdatas[0]) - return ordered - - -def parse_formatted_hex(formatted, num_chunks, chunk_size, separator): - if len(formatted) != num_chunks * (chunk_size + 1) - 1: - raise ValueError("invalid formatted hex string") - value = b"" - for _ in range(num_chunks): - chunk = formatted[0:chunk_size] - value += int(chunk, 16).to_bytes(chunk_size // 2, "big") - formatted = formatted[chunk_size:] - if len(formatted) > 0 and formatted[0] != separator: - raise ValueError("invalid formatted hex string") - formatted = formatted[1:] - return value diff --git a/backend/venv39/lib/python3.9/site-packages/dns/renderer.py b/backend/venv39/lib/python3.9/site-packages/dns/renderer.py deleted file mode 100644 index a77481f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/renderer.py +++ /dev/null @@ -1,346 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Help for building DNS wire format messages""" - -import contextlib -import io -import random -import struct -import time - -import dns.exception -import dns.tsig - -QUESTION = 0 -ANSWER = 1 -AUTHORITY = 2 -ADDITIONAL = 3 - - -@contextlib.contextmanager -def prefixed_length(output, length_length): - output.write(b"\00" * length_length) - start = output.tell() - yield - end = output.tell() - length = end - start - if length > 0: - try: - output.seek(start - length_length) - try: - output.write(length.to_bytes(length_length, "big")) - except OverflowError: - raise dns.exception.FormError - finally: - output.seek(end) - - -class Renderer: - """Helper class for building DNS wire-format messages. - - Most applications can use the higher-level L{dns.message.Message} - class and its to_wire() method to generate wire-format messages. - This class is for those applications which need finer control - over the generation of messages. - - Typical use:: - - r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512) - r.add_question(qname, qtype, qclass) - r.add_rrset(dns.renderer.ANSWER, rrset_1) - r.add_rrset(dns.renderer.ANSWER, rrset_2) - r.add_rrset(dns.renderer.AUTHORITY, ns_rrset) - r.add_rrset(dns.renderer.ADDITIONAL, ad_rrset_1) - r.add_rrset(dns.renderer.ADDITIONAL, ad_rrset_2) - r.add_edns(0, 0, 4096) - r.write_header() - r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac) - wire = r.get_wire() - - If padding is going to be used, then the OPT record MUST be - written after everything else in the additional section except for - the TSIG (if any). - - output, an io.BytesIO, where rendering is written - - id: the message id - - flags: the message flags - - max_size: the maximum size of the message - - origin: the origin to use when rendering relative names - - compress: the compression table - - section: an int, the section currently being rendered - - counts: list of the number of RRs in each section - - mac: the MAC of the rendered message (if TSIG was used) - """ - - def __init__(self, id=None, flags=0, max_size=65535, origin=None): - """Initialize a new renderer.""" - - self.output = io.BytesIO() - if id is None: - self.id = random.randint(0, 65535) - else: - self.id = id - self.flags = flags - self.max_size = max_size - self.origin = origin - self.compress = {} - self.section = QUESTION - self.counts = [0, 0, 0, 0] - self.output.write(b"\x00" * 12) - self.mac = "" - self.reserved = 0 - self.was_padded = False - - def _rollback(self, where): - """Truncate the output buffer at offset *where*, and remove any - compression table entries that pointed beyond the truncation - point. - """ - - self.output.seek(where) - self.output.truncate() - keys_to_delete = [] - for k, v in self.compress.items(): - if v >= where: - keys_to_delete.append(k) - for k in keys_to_delete: - del self.compress[k] - - def _set_section(self, section): - """Set the renderer's current section. - - Sections must be rendered order: QUESTION, ANSWER, AUTHORITY, - ADDITIONAL. Sections may be empty. - - Raises dns.exception.FormError if an attempt was made to set - a section value less than the current section. - """ - - if self.section != section: - if self.section > section: - raise dns.exception.FormError - self.section = section - - @contextlib.contextmanager - def _track_size(self): - start = self.output.tell() - yield start - if self.output.tell() > self.max_size: - self._rollback(start) - raise dns.exception.TooBig - - @contextlib.contextmanager - def _temporarily_seek_to(self, where): - current = self.output.tell() - try: - self.output.seek(where) - yield - finally: - self.output.seek(current) - - def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN): - """Add a question to the message.""" - - self._set_section(QUESTION) - with self._track_size(): - qname.to_wire(self.output, self.compress, self.origin) - self.output.write(struct.pack("!HH", rdtype, rdclass)) - self.counts[QUESTION] += 1 - - def add_rrset(self, section, rrset, **kw): - """Add the rrset to the specified section. - - Any keyword arguments are passed on to the rdataset's to_wire() - routine. - """ - - self._set_section(section) - with self._track_size(): - n = rrset.to_wire(self.output, self.compress, self.origin, **kw) - self.counts[section] += n - - def add_rdataset(self, section, name, rdataset, **kw): - """Add the rdataset to the specified section, using the specified - name as the owner name. - - Any keyword arguments are passed on to the rdataset's to_wire() - routine. - """ - - self._set_section(section) - with self._track_size(): - n = rdataset.to_wire(name, self.output, self.compress, self.origin, **kw) - self.counts[section] += n - - def add_opt(self, opt, pad=0, opt_size=0, tsig_size=0): - """Add *opt* to the additional section, applying padding if desired. The - padding will take the specified precomputed OPT size and TSIG size into - account. - - Note that we don't have reliable way of knowing how big a GSS-TSIG digest - might be, so we we might not get an even multiple of the pad in that case.""" - if pad: - ttl = opt.ttl - assert opt_size >= 11 - opt_rdata = opt[0] - size_without_padding = self.output.tell() + opt_size + tsig_size - remainder = size_without_padding % pad - if remainder: - pad = b"\x00" * (pad - remainder) - else: - pad = b"" - options = list(opt_rdata.options) - options.append(dns.edns.GenericOption(dns.edns.OptionType.PADDING, pad)) - opt = dns.message.Message._make_opt(ttl, opt_rdata.rdclass, options) - self.was_padded = True - self.add_rrset(ADDITIONAL, opt) - - def add_edns(self, edns, ednsflags, payload, options=None): - """Add an EDNS OPT record to the message.""" - - # make sure the EDNS version in ednsflags agrees with edns - ednsflags &= 0xFF00FFFF - ednsflags |= edns << 16 - opt = dns.message.Message._make_opt(ednsflags, payload, options) - self.add_opt(opt) - - def add_tsig( - self, - keyname, - secret, - fudge, - id, - tsig_error, - other_data, - request_mac, - algorithm=dns.tsig.default_algorithm, - ): - """Add a TSIG signature to the message.""" - - s = self.output.getvalue() - - if isinstance(secret, dns.tsig.Key): - key = secret - else: - key = dns.tsig.Key(keyname, secret, algorithm) - tsig = dns.message.Message._make_tsig( - keyname, algorithm, 0, fudge, b"", id, tsig_error, other_data - ) - (tsig, _) = dns.tsig.sign(s, key, tsig[0], int(time.time()), request_mac) - self._write_tsig(tsig, keyname) - - def add_multi_tsig( - self, - ctx, - keyname, - secret, - fudge, - id, - tsig_error, - other_data, - request_mac, - algorithm=dns.tsig.default_algorithm, - ): - """Add a TSIG signature to the message. Unlike add_tsig(), this can be - used for a series of consecutive DNS envelopes, e.g. for a zone - transfer over TCP [RFC2845, 4.4]. - - For the first message in the sequence, give ctx=None. For each - subsequent message, give the ctx that was returned from the - add_multi_tsig() call for the previous message.""" - - s = self.output.getvalue() - - if isinstance(secret, dns.tsig.Key): - key = secret - else: - key = dns.tsig.Key(keyname, secret, algorithm) - tsig = dns.message.Message._make_tsig( - keyname, algorithm, 0, fudge, b"", id, tsig_error, other_data - ) - (tsig, ctx) = dns.tsig.sign( - s, key, tsig[0], int(time.time()), request_mac, ctx, True - ) - self._write_tsig(tsig, keyname) - return ctx - - def _write_tsig(self, tsig, keyname): - if self.was_padded: - compress = None - else: - compress = self.compress - self._set_section(ADDITIONAL) - with self._track_size(): - keyname.to_wire(self.output, compress, self.origin) - self.output.write( - struct.pack("!HHI", dns.rdatatype.TSIG, dns.rdataclass.ANY, 0) - ) - with prefixed_length(self.output, 2): - tsig.to_wire(self.output) - - self.counts[ADDITIONAL] += 1 - with self._temporarily_seek_to(10): - self.output.write(struct.pack("!H", self.counts[ADDITIONAL])) - - def write_header(self): - """Write the DNS message header. - - Writing the DNS message header is done after all sections - have been rendered, but before the optional TSIG signature - is added. - """ - - with self._temporarily_seek_to(0): - self.output.write( - struct.pack( - "!HHHHHH", - self.id, - self.flags, - self.counts[0], - self.counts[1], - self.counts[2], - self.counts[3], - ) - ) - - def get_wire(self): - """Return the wire format message.""" - - return self.output.getvalue() - - def reserve(self, size: int) -> None: - """Reserve *size* bytes.""" - if size < 0: - raise ValueError("reserved amount must be non-negative") - if size > self.max_size: - raise ValueError("cannot reserve more than the maximum size") - self.reserved += size - self.max_size -= size - - def release_reserved(self) -> None: - """Release the reserved bytes.""" - self.max_size += self.reserved - self.reserved = 0 diff --git a/backend/venv39/lib/python3.9/site-packages/dns/resolver.py b/backend/venv39/lib/python3.9/site-packages/dns/resolver.py deleted file mode 100644 index 3ba76e3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/resolver.py +++ /dev/null @@ -1,2053 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS stub resolver.""" - -import contextlib -import random -import socket -import sys -import threading -import time -import warnings -from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union -from urllib.parse import urlparse - -import dns._ddr -import dns.edns -import dns.exception -import dns.flags -import dns.inet -import dns.ipv4 -import dns.ipv6 -import dns.message -import dns.name -import dns.rdata -import dns.nameserver -import dns.query -import dns.rcode -import dns.rdataclass -import dns.rdatatype -import dns.rdtypes.svcbbase -import dns.reversename -import dns.tsig - -if sys.platform == "win32": # pragma: no cover - import dns.win32util - - -class NXDOMAIN(dns.exception.DNSException): - """The DNS query name does not exist.""" - - supp_kwargs = {"qnames", "responses"} - fmt = None # we have our own __str__ implementation - - # pylint: disable=arguments-differ - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def _check_kwargs(self, qnames, responses=None): - if not isinstance(qnames, (list, tuple, set)): - raise AttributeError("qnames must be a list, tuple or set") - if len(qnames) == 0: - raise AttributeError("qnames must contain at least one element") - if responses is None: - responses = {} - elif not isinstance(responses, dict): - raise AttributeError("responses must be a dict(qname=response)") - kwargs = dict(qnames=qnames, responses=responses) - return kwargs - - def __str__(self) -> str: - if "qnames" not in self.kwargs: - return super().__str__() - qnames = self.kwargs["qnames"] - if len(qnames) > 1: - msg = "None of DNS query names exist" - else: - msg = "The DNS query name does not exist" - qnames = ", ".join(map(str, qnames)) - return f"{msg}: {qnames}" - - @property - def canonical_name(self): - """Return the unresolved canonical name.""" - if "qnames" not in self.kwargs: - raise TypeError("parametrized exception required") - for qname in self.kwargs["qnames"]: - response = self.kwargs["responses"][qname] - try: - cname = response.canonical_name() - if cname != qname: - return cname - except Exception: # pragma: no cover - # We can just eat this exception as it means there was - # something wrong with the response. - pass - return self.kwargs["qnames"][0] - - def __add__(self, e_nx): - """Augment by results from another NXDOMAIN exception.""" - qnames0 = list(self.kwargs.get("qnames", [])) - responses0 = dict(self.kwargs.get("responses", {})) - responses1 = e_nx.kwargs.get("responses", {}) - for qname1 in e_nx.kwargs.get("qnames", []): - if qname1 not in qnames0: - qnames0.append(qname1) - if qname1 in responses1: - responses0[qname1] = responses1[qname1] - return NXDOMAIN(qnames=qnames0, responses=responses0) - - def qnames(self): - """All of the names that were tried. - - Returns a list of ``dns.name.Name``. - """ - return self.kwargs["qnames"] - - def responses(self): - """A map from queried names to their NXDOMAIN responses. - - Returns a dict mapping a ``dns.name.Name`` to a - ``dns.message.Message``. - """ - return self.kwargs["responses"] - - def response(self, qname): - """The response for query *qname*. - - Returns a ``dns.message.Message``. - """ - return self.kwargs["responses"][qname] - - -class YXDOMAIN(dns.exception.DNSException): - """The DNS query name is too long after DNAME substitution.""" - - -ErrorTuple = Tuple[ - Optional[str], - bool, - int, - Union[Exception, str], - Optional[dns.message.Message], -] - - -def _errors_to_text(errors: List[ErrorTuple]) -> List[str]: - """Turn a resolution errors trace into a list of text.""" - texts = [] - for err in errors: - texts.append(f"Server {err[0]} answered {err[3]}") - return texts - - -class LifetimeTimeout(dns.exception.Timeout): - """The resolution lifetime expired.""" - - msg = "The resolution lifetime expired." - fmt = f"{msg[:-1]} after {{timeout:.3f}} seconds: {{errors}}" - supp_kwargs = {"timeout", "errors"} - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def _fmt_kwargs(self, **kwargs): - srv_msgs = _errors_to_text(kwargs["errors"]) - return super()._fmt_kwargs( - timeout=kwargs["timeout"], errors="; ".join(srv_msgs) - ) - - -# We added more detail to resolution timeouts, but they are still -# subclasses of dns.exception.Timeout for backwards compatibility. We also -# keep dns.resolver.Timeout defined for backwards compatibility. -Timeout = LifetimeTimeout - - -class NoAnswer(dns.exception.DNSException): - """The DNS response does not contain an answer to the question.""" - - fmt = "The DNS response does not contain an answer to the question: {query}" - supp_kwargs = {"response"} - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def _fmt_kwargs(self, **kwargs): - return super()._fmt_kwargs(query=kwargs["response"].question) - - def response(self): - return self.kwargs["response"] - - -class NoNameservers(dns.exception.DNSException): - """All nameservers failed to answer the query. - - errors: list of servers and respective errors - The type of errors is - [(server IP address, any object convertible to string)]. - Non-empty errors list will add explanatory message () - """ - - msg = "All nameservers failed to answer the query." - fmt = f"{msg[:-1]} {{query}}: {{errors}}" - supp_kwargs = {"request", "errors"} - - # We do this as otherwise mypy complains about unexpected keyword argument - # idna_exception - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def _fmt_kwargs(self, **kwargs): - srv_msgs = _errors_to_text(kwargs["errors"]) - return super()._fmt_kwargs( - query=kwargs["request"].question, errors="; ".join(srv_msgs) - ) - - -class NotAbsolute(dns.exception.DNSException): - """An absolute domain name is required but a relative name was provided.""" - - -class NoRootSOA(dns.exception.DNSException): - """There is no SOA RR at the DNS root name. This should never happen!""" - - -class NoMetaqueries(dns.exception.DNSException): - """DNS metaqueries are not allowed.""" - - -class NoResolverConfiguration(dns.exception.DNSException): - """Resolver configuration could not be read or specified no nameservers.""" - - -class Answer: - """DNS stub resolver answer. - - Instances of this class bundle up the result of a successful DNS - resolution. - - For convenience, the answer object implements much of the sequence - protocol, forwarding to its ``rrset`` attribute. E.g. - ``for a in answer`` is equivalent to ``for a in answer.rrset``. - ``answer[i]`` is equivalent to ``answer.rrset[i]``, and - ``answer[i:j]`` is equivalent to ``answer.rrset[i:j]``. - - Note that CNAMEs or DNAMEs in the response may mean that answer - RRset's name might not be the query name. - """ - - def __init__( - self, - qname: dns.name.Name, - rdtype: dns.rdatatype.RdataType, - rdclass: dns.rdataclass.RdataClass, - response: dns.message.QueryMessage, - nameserver: Optional[str] = None, - port: Optional[int] = None, - ) -> None: - self.qname = qname - self.rdtype = rdtype - self.rdclass = rdclass - self.response = response - self.nameserver = nameserver - self.port = port - self.chaining_result = response.resolve_chaining() - # Copy some attributes out of chaining_result for backwards - # compatibility and convenience. - self.canonical_name = self.chaining_result.canonical_name - self.rrset = self.chaining_result.answer - self.expiration = time.time() + self.chaining_result.minimum_ttl - - def __getattr__(self, attr): # pragma: no cover - if attr == "name": - return self.rrset.name - elif attr == "ttl": - return self.rrset.ttl - elif attr == "covers": - return self.rrset.covers - elif attr == "rdclass": - return self.rrset.rdclass - elif attr == "rdtype": - return self.rrset.rdtype - else: - raise AttributeError(attr) - - def __len__(self) -> int: - return self.rrset and len(self.rrset) or 0 - - def __iter__(self) -> Iterator[dns.rdata.Rdata]: - return self.rrset and iter(self.rrset) or iter(tuple()) - - def __getitem__(self, i): - if self.rrset is None: - raise IndexError - return self.rrset[i] - - def __delitem__(self, i): - if self.rrset is None: - raise IndexError - del self.rrset[i] - - -class Answers(dict): - """A dict of DNS stub resolver answers, indexed by type.""" - - -class HostAnswers(Answers): - """A dict of DNS stub resolver answers to a host name lookup, indexed by - type. - """ - - @classmethod - def make( - cls, - v6: Optional[Answer] = None, - v4: Optional[Answer] = None, - add_empty: bool = True, - ) -> "HostAnswers": - answers = HostAnswers() - if v6 is not None and (add_empty or v6.rrset): - answers[dns.rdatatype.AAAA] = v6 - if v4 is not None and (add_empty or v4.rrset): - answers[dns.rdatatype.A] = v4 - return answers - - # Returns pairs of (address, family) from this result, potentially - # filtering by address family. - def addresses_and_families( - self, family: int = socket.AF_UNSPEC - ) -> Iterator[Tuple[str, int]]: - if family == socket.AF_UNSPEC: - yield from self.addresses_and_families(socket.AF_INET6) - yield from self.addresses_and_families(socket.AF_INET) - return - elif family == socket.AF_INET6: - answer = self.get(dns.rdatatype.AAAA) - elif family == socket.AF_INET: - answer = self.get(dns.rdatatype.A) - else: # pragma: no cover - raise NotImplementedError(f"unknown address family {family}") - if answer: - for rdata in answer: - yield (rdata.address, family) - - # Returns addresses from this result, potentially filtering by - # address family. - def addresses(self, family: int = socket.AF_UNSPEC) -> Iterator[str]: - return (pair[0] for pair in self.addresses_and_families(family)) - - # Returns the canonical name from this result. - def canonical_name(self) -> dns.name.Name: - answer = self.get(dns.rdatatype.AAAA, self.get(dns.rdatatype.A)) - return answer.canonical_name - - -class CacheStatistics: - """Cache Statistics""" - - def __init__(self, hits: int = 0, misses: int = 0) -> None: - self.hits = hits - self.misses = misses - - def reset(self) -> None: - self.hits = 0 - self.misses = 0 - - def clone(self) -> "CacheStatistics": - return CacheStatistics(self.hits, self.misses) - - -class CacheBase: - def __init__(self) -> None: - self.lock = threading.Lock() - self.statistics = CacheStatistics() - - def reset_statistics(self) -> None: - """Reset all statistics to zero.""" - with self.lock: - self.statistics.reset() - - def hits(self) -> int: - """How many hits has the cache had?""" - with self.lock: - return self.statistics.hits - - def misses(self) -> int: - """How many misses has the cache had?""" - with self.lock: - return self.statistics.misses - - def get_statistics_snapshot(self) -> CacheStatistics: - """Return a consistent snapshot of all the statistics. - - If running with multiple threads, it's better to take a - snapshot than to call statistics methods such as hits() and - misses() individually. - """ - with self.lock: - return self.statistics.clone() - - -CacheKey = Tuple[dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass] - - -class Cache(CacheBase): - """Simple thread-safe DNS answer cache.""" - - def __init__(self, cleaning_interval: float = 300.0) -> None: - """*cleaning_interval*, a ``float`` is the number of seconds between - periodic cleanings. - """ - - super().__init__() - self.data: Dict[CacheKey, Answer] = {} - self.cleaning_interval = cleaning_interval - self.next_cleaning: float = time.time() + self.cleaning_interval - - def _maybe_clean(self) -> None: - """Clean the cache if it's time to do so.""" - - now = time.time() - if self.next_cleaning <= now: - keys_to_delete = [] - for k, v in self.data.items(): - if v.expiration <= now: - keys_to_delete.append(k) - for k in keys_to_delete: - del self.data[k] - now = time.time() - self.next_cleaning = now + self.cleaning_interval - - def get(self, key: CacheKey) -> Optional[Answer]: - """Get the answer associated with *key*. - - Returns None if no answer is cached for the key. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - Returns a ``dns.resolver.Answer`` or ``None``. - """ - - with self.lock: - self._maybe_clean() - v = self.data.get(key) - if v is None or v.expiration <= time.time(): - self.statistics.misses += 1 - return None - self.statistics.hits += 1 - return v - - def put(self, key: CacheKey, value: Answer) -> None: - """Associate key and value in the cache. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - *value*, a ``dns.resolver.Answer``, the answer. - """ - - with self.lock: - self._maybe_clean() - self.data[key] = value - - def flush(self, key: Optional[CacheKey] = None) -> None: - """Flush the cache. - - If *key* is not ``None``, only that item is flushed. Otherwise the entire cache - is flushed. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - """ - - with self.lock: - if key is not None: - if key in self.data: - del self.data[key] - else: - self.data = {} - self.next_cleaning = time.time() + self.cleaning_interval - - -class LRUCacheNode: - """LRUCache node.""" - - def __init__(self, key, value): - self.key = key - self.value = value - self.hits = 0 - self.prev = self - self.next = self - - def link_after(self, node: "LRUCacheNode") -> None: - self.prev = node - self.next = node.next - node.next.prev = self - node.next = self - - def unlink(self) -> None: - self.next.prev = self.prev - self.prev.next = self.next - - -class LRUCache(CacheBase): - """Thread-safe, bounded, least-recently-used DNS answer cache. - - This cache is better than the simple cache (above) if you're - running a web crawler or other process that does a lot of - resolutions. The LRUCache has a maximum number of nodes, and when - it is full, the least-recently used node is removed to make space - for a new one. - """ - - def __init__(self, max_size: int = 100000) -> None: - """*max_size*, an ``int``, is the maximum number of nodes to cache; - it must be greater than 0. - """ - - super().__init__() - self.data: Dict[CacheKey, LRUCacheNode] = {} - self.set_max_size(max_size) - self.sentinel: LRUCacheNode = LRUCacheNode(None, None) - self.sentinel.prev = self.sentinel - self.sentinel.next = self.sentinel - - def set_max_size(self, max_size: int) -> None: - if max_size < 1: - max_size = 1 - self.max_size = max_size - - def get(self, key: CacheKey) -> Optional[Answer]: - """Get the answer associated with *key*. - - Returns None if no answer is cached for the key. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - Returns a ``dns.resolver.Answer`` or ``None``. - """ - - with self.lock: - node = self.data.get(key) - if node is None: - self.statistics.misses += 1 - return None - # Unlink because we're either going to move the node to the front - # of the LRU list or we're going to free it. - node.unlink() - if node.value.expiration <= time.time(): - del self.data[node.key] - self.statistics.misses += 1 - return None - node.link_after(self.sentinel) - self.statistics.hits += 1 - node.hits += 1 - return node.value - - def get_hits_for_key(self, key: CacheKey) -> int: - """Return the number of cache hits associated with the specified key.""" - with self.lock: - node = self.data.get(key) - if node is None or node.value.expiration <= time.time(): - return 0 - else: - return node.hits - - def put(self, key: CacheKey, value: Answer) -> None: - """Associate key and value in the cache. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - - *value*, a ``dns.resolver.Answer``, the answer. - """ - - with self.lock: - node = self.data.get(key) - if node is not None: - node.unlink() - del self.data[node.key] - while len(self.data) >= self.max_size: - gnode = self.sentinel.prev - gnode.unlink() - del self.data[gnode.key] - node = LRUCacheNode(key, value) - node.link_after(self.sentinel) - self.data[key] = node - - def flush(self, key: Optional[CacheKey] = None) -> None: - """Flush the cache. - - If *key* is not ``None``, only that item is flushed. Otherwise the entire cache - is flushed. - - *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)`` - tuple whose values are the query name, rdtype, and rdclass respectively. - """ - - with self.lock: - if key is not None: - node = self.data.get(key) - if node is not None: - node.unlink() - del self.data[node.key] - else: - gnode = self.sentinel.next - while gnode != self.sentinel: - next = gnode.next - gnode.unlink() - gnode = next - self.data = {} - - -class _Resolution: - """Helper class for dns.resolver.Resolver.resolve(). - - All of the "business logic" of resolution is encapsulated in this - class, allowing us to have multiple resolve() implementations - using different I/O schemes without copying all of the - complicated logic. - - This class is a "friend" to dns.resolver.Resolver and manipulates - resolver data structures directly. - """ - - def __init__( - self, - resolver: "BaseResolver", - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - rdclass: Union[dns.rdataclass.RdataClass, str], - tcp: bool, - raise_on_no_answer: bool, - search: Optional[bool], - ) -> None: - if isinstance(qname, str): - qname = dns.name.from_text(qname, None) - rdtype = dns.rdatatype.RdataType.make(rdtype) - if dns.rdatatype.is_metatype(rdtype): - raise NoMetaqueries - rdclass = dns.rdataclass.RdataClass.make(rdclass) - if dns.rdataclass.is_metaclass(rdclass): - raise NoMetaqueries - self.resolver = resolver - self.qnames_to_try = resolver._get_qnames_to_try(qname, search) - self.qnames = self.qnames_to_try[:] - self.rdtype = rdtype - self.rdclass = rdclass - self.tcp = tcp - self.raise_on_no_answer = raise_on_no_answer - self.nxdomain_responses: Dict[dns.name.Name, dns.message.QueryMessage] = {} - # Initialize other things to help analysis tools - self.qname = dns.name.empty - self.nameservers: List[dns.nameserver.Nameserver] = [] - self.current_nameservers: List[dns.nameserver.Nameserver] = [] - self.errors: List[ErrorTuple] = [] - self.nameserver: Optional[dns.nameserver.Nameserver] = None - self.tcp_attempt = False - self.retry_with_tcp = False - self.request: Optional[dns.message.QueryMessage] = None - self.backoff = 0.0 - - def next_request( - self, - ) -> Tuple[Optional[dns.message.QueryMessage], Optional[Answer]]: - """Get the next request to send, and check the cache. - - Returns a (request, answer) tuple. At most one of request or - answer will not be None. - """ - - # We return a tuple instead of Union[Message,Answer] as it lets - # the caller avoid isinstance(). - - while len(self.qnames) > 0: - self.qname = self.qnames.pop(0) - - # Do we know the answer? - if self.resolver.cache: - answer = self.resolver.cache.get( - (self.qname, self.rdtype, self.rdclass) - ) - if answer is not None: - if answer.rrset is None and self.raise_on_no_answer: - raise NoAnswer(response=answer.response) - else: - return (None, answer) - answer = self.resolver.cache.get( - (self.qname, dns.rdatatype.ANY, self.rdclass) - ) - if answer is not None and answer.response.rcode() == dns.rcode.NXDOMAIN: - # cached NXDOMAIN; record it and continue to next - # name. - self.nxdomain_responses[self.qname] = answer.response - continue - - # Build the request - request = dns.message.make_query(self.qname, self.rdtype, self.rdclass) - if self.resolver.keyname is not None: - request.use_tsig( - self.resolver.keyring, - self.resolver.keyname, - algorithm=self.resolver.keyalgorithm, - ) - request.use_edns( - self.resolver.edns, - self.resolver.ednsflags, - self.resolver.payload, - options=self.resolver.ednsoptions, - ) - if self.resolver.flags is not None: - request.flags = self.resolver.flags - - self.nameservers = self.resolver._enrich_nameservers( - self.resolver._nameservers, - self.resolver.nameserver_ports, - self.resolver.port, - ) - if self.resolver.rotate: - random.shuffle(self.nameservers) - self.current_nameservers = self.nameservers[:] - self.errors = [] - self.nameserver = None - self.tcp_attempt = False - self.retry_with_tcp = False - self.request = request - self.backoff = 0.10 - - return (request, None) - - # - # We've tried everything and only gotten NXDOMAINs. (We know - # it's only NXDOMAINs as anything else would have returned - # before now.) - # - raise NXDOMAIN(qnames=self.qnames_to_try, responses=self.nxdomain_responses) - - def next_nameserver(self) -> Tuple[dns.nameserver.Nameserver, bool, float]: - if self.retry_with_tcp: - assert self.nameserver is not None - assert not self.nameserver.is_always_max_size() - self.tcp_attempt = True - self.retry_with_tcp = False - return (self.nameserver, True, 0) - - backoff = 0.0 - if not self.current_nameservers: - if len(self.nameservers) == 0: - # Out of things to try! - raise NoNameservers(request=self.request, errors=self.errors) - self.current_nameservers = self.nameservers[:] - backoff = self.backoff - self.backoff = min(self.backoff * 2, 2) - - self.nameserver = self.current_nameservers.pop(0) - self.tcp_attempt = self.tcp or self.nameserver.is_always_max_size() - return (self.nameserver, self.tcp_attempt, backoff) - - def query_result( - self, response: Optional[dns.message.Message], ex: Optional[Exception] - ) -> Tuple[Optional[Answer], bool]: - # - # returns an (answer: Answer, end_loop: bool) tuple. - # - assert self.nameserver is not None - if ex: - # Exception during I/O or from_wire() - assert response is None - self.errors.append( - ( - str(self.nameserver), - self.tcp_attempt, - self.nameserver.answer_port(), - ex, - response, - ) - ) - if ( - isinstance(ex, dns.exception.FormError) - or isinstance(ex, EOFError) - or isinstance(ex, OSError) - or isinstance(ex, NotImplementedError) - ): - # This nameserver is no good, take it out of the mix. - self.nameservers.remove(self.nameserver) - elif isinstance(ex, dns.message.Truncated): - if self.tcp_attempt: - # Truncation with TCP is no good! - self.nameservers.remove(self.nameserver) - else: - self.retry_with_tcp = True - return (None, False) - # We got an answer! - assert response is not None - assert isinstance(response, dns.message.QueryMessage) - rcode = response.rcode() - if rcode == dns.rcode.NOERROR: - try: - answer = Answer( - self.qname, - self.rdtype, - self.rdclass, - response, - self.nameserver.answer_nameserver(), - self.nameserver.answer_port(), - ) - except Exception as e: - self.errors.append( - ( - str(self.nameserver), - self.tcp_attempt, - self.nameserver.answer_port(), - e, - response, - ) - ) - # The nameserver is no good, take it out of the mix. - self.nameservers.remove(self.nameserver) - return (None, False) - if self.resolver.cache: - self.resolver.cache.put((self.qname, self.rdtype, self.rdclass), answer) - if answer.rrset is None and self.raise_on_no_answer: - raise NoAnswer(response=answer.response) - return (answer, True) - elif rcode == dns.rcode.NXDOMAIN: - # Further validate the response by making an Answer, even - # if we aren't going to cache it. - try: - answer = Answer( - self.qname, dns.rdatatype.ANY, dns.rdataclass.IN, response - ) - except Exception as e: - self.errors.append( - ( - str(self.nameserver), - self.tcp_attempt, - self.nameserver.answer_port(), - e, - response, - ) - ) - # The nameserver is no good, take it out of the mix. - self.nameservers.remove(self.nameserver) - return (None, False) - self.nxdomain_responses[self.qname] = response - if self.resolver.cache: - self.resolver.cache.put( - (self.qname, dns.rdatatype.ANY, self.rdclass), answer - ) - # Make next_nameserver() return None, so caller breaks its - # inner loop and calls next_request(). - return (None, True) - elif rcode == dns.rcode.YXDOMAIN: - yex = YXDOMAIN() - self.errors.append( - ( - str(self.nameserver), - self.tcp_attempt, - self.nameserver.answer_port(), - yex, - response, - ) - ) - raise yex - else: - # - # We got a response, but we're not happy with the - # rcode in it. - # - if rcode != dns.rcode.SERVFAIL or not self.resolver.retry_servfail: - self.nameservers.remove(self.nameserver) - self.errors.append( - ( - str(self.nameserver), - self.tcp_attempt, - self.nameserver.answer_port(), - dns.rcode.to_text(rcode), - response, - ) - ) - return (None, False) - - -class BaseResolver: - """DNS stub resolver.""" - - # We initialize in reset() - # - # pylint: disable=attribute-defined-outside-init - - domain: dns.name.Name - nameserver_ports: Dict[str, int] - port: int - search: List[dns.name.Name] - use_search_by_default: bool - timeout: float - lifetime: float - keyring: Optional[Any] - keyname: Optional[Union[dns.name.Name, str]] - keyalgorithm: Union[dns.name.Name, str] - edns: int - ednsflags: int - ednsoptions: Optional[List[dns.edns.Option]] - payload: int - cache: Any - flags: Optional[int] - retry_servfail: bool - rotate: bool - ndots: Optional[int] - _nameservers: Sequence[Union[str, dns.nameserver.Nameserver]] - - def __init__( - self, filename: str = "/etc/resolv.conf", configure: bool = True - ) -> None: - """*filename*, a ``str`` or file object, specifying a file - in standard /etc/resolv.conf format. This parameter is meaningful - only when *configure* is true and the platform is POSIX. - - *configure*, a ``bool``. If True (the default), the resolver - instance is configured in the normal fashion for the operating - system the resolver is running on. (I.e. by reading a - /etc/resolv.conf file on POSIX systems and from the registry - on Windows systems.) - """ - - self.reset() - if configure: - if sys.platform == "win32": # pragma: no cover - self.read_registry() - elif filename: - self.read_resolv_conf(filename) - - def reset(self) -> None: - """Reset all resolver configuration to the defaults.""" - - self.domain = dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) - if len(self.domain) == 0: # pragma: no cover - self.domain = dns.name.root - self._nameservers = [] - self.nameserver_ports = {} - self.port = 53 - self.search = [] - self.use_search_by_default = False - self.timeout = 2.0 - self.lifetime = 5.0 - self.keyring = None - self.keyname = None - self.keyalgorithm = dns.tsig.default_algorithm - self.edns = -1 - self.ednsflags = 0 - self.ednsoptions = None - self.payload = 0 - self.cache = None - self.flags = None - self.retry_servfail = False - self.rotate = False - self.ndots = None - - def read_resolv_conf(self, f: Any) -> None: - """Process *f* as a file in the /etc/resolv.conf format. If f is - a ``str``, it is used as the name of the file to open; otherwise it - is treated as the file itself. - - Interprets the following items: - - - nameserver - name server IP address - - - domain - local domain name - - - search - search list for host-name lookup - - - options - supported options are rotate, timeout, edns0, and ndots - - """ - - nameservers = [] - if isinstance(f, str): - try: - cm: contextlib.AbstractContextManager = open(f) - except OSError: - # /etc/resolv.conf doesn't exist, can't be read, etc. - raise NoResolverConfiguration(f"cannot open {f}") - else: - cm = contextlib.nullcontext(f) - with cm as f: - for l in f: - if len(l) == 0 or l[0] == "#" or l[0] == ";": - continue - tokens = l.split() - - # Any line containing less than 2 tokens is malformed - if len(tokens) < 2: - continue - - if tokens[0] == "nameserver": - nameservers.append(tokens[1]) - elif tokens[0] == "domain": - self.domain = dns.name.from_text(tokens[1]) - # domain and search are exclusive - self.search = [] - elif tokens[0] == "search": - # the last search wins - self.search = [] - for suffix in tokens[1:]: - self.search.append(dns.name.from_text(suffix)) - # We don't set domain as it is not used if - # len(self.search) > 0 - elif tokens[0] == "options": - for opt in tokens[1:]: - if opt == "rotate": - self.rotate = True - elif opt == "edns0": - self.use_edns() - elif "timeout" in opt: - try: - self.timeout = int(opt.split(":")[1]) - except (ValueError, IndexError): - pass - elif "ndots" in opt: - try: - self.ndots = int(opt.split(":")[1]) - except (ValueError, IndexError): - pass - if len(nameservers) == 0: - raise NoResolverConfiguration("no nameservers") - # Assigning directly instead of appending means we invoke the - # setter logic, with additonal checking and enrichment. - self.nameservers = nameservers - - def read_registry(self) -> None: # pragma: no cover - """Extract resolver configuration from the Windows registry.""" - try: - info = dns.win32util.get_dns_info() # type: ignore - if info.domain is not None: - self.domain = info.domain - self.nameservers = info.nameservers - self.search = info.search - except AttributeError: - raise NotImplementedError - - def _compute_timeout( - self, - start: float, - lifetime: Optional[float] = None, - errors: Optional[List[ErrorTuple]] = None, - ) -> float: - lifetime = self.lifetime if lifetime is None else lifetime - now = time.time() - duration = now - start - if errors is None: - errors = [] - if duration < 0: - if duration < -1: - # Time going backwards is bad. Just give up. - raise LifetimeTimeout(timeout=duration, errors=errors) - else: - # Time went backwards, but only a little. This can - # happen, e.g. under vmware with older linux kernels. - # Pretend it didn't happen. - duration = 0 - if duration >= lifetime: - raise LifetimeTimeout(timeout=duration, errors=errors) - return min(lifetime - duration, self.timeout) - - def _get_qnames_to_try( - self, qname: dns.name.Name, search: Optional[bool] - ) -> List[dns.name.Name]: - # This is a separate method so we can unit test the search - # rules without requiring the Internet. - if search is None: - search = self.use_search_by_default - qnames_to_try = [] - if qname.is_absolute(): - qnames_to_try.append(qname) - else: - abs_qname = qname.concatenate(dns.name.root) - if search: - if len(self.search) > 0: - # There is a search list, so use it exclusively - search_list = self.search[:] - elif self.domain != dns.name.root and self.domain is not None: - # We have some notion of a domain that isn't the root, so - # use it as the search list. - search_list = [self.domain] - else: - search_list = [] - # Figure out the effective ndots (default is 1) - if self.ndots is None: - ndots = 1 - else: - ndots = self.ndots - for suffix in search_list: - qnames_to_try.append(qname + suffix) - if len(qname) > ndots: - # The name has at least ndots dots, so we should try an - # absolute query first. - qnames_to_try.insert(0, abs_qname) - else: - # The name has less than ndots dots, so we should search - # first, then try the absolute name. - qnames_to_try.append(abs_qname) - else: - qnames_to_try.append(abs_qname) - return qnames_to_try - - def use_tsig( - self, - keyring: Any, - keyname: Optional[Union[dns.name.Name, str]] = None, - algorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm, - ) -> None: - """Add a TSIG signature to each query. - - The parameters are passed to ``dns.message.Message.use_tsig()``; - see its documentation for details. - """ - - self.keyring = keyring - self.keyname = keyname - self.keyalgorithm = algorithm - - def use_edns( - self, - edns: Optional[Union[int, bool]] = 0, - ednsflags: int = 0, - payload: int = dns.message.DEFAULT_EDNS_PAYLOAD, - options: Optional[List[dns.edns.Option]] = None, - ) -> None: - """Configure EDNS behavior. - - *edns*, an ``int``, is the EDNS level to use. Specifying - ``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case - the other parameters are ignored. Specifying ``True`` is - equivalent to specifying 0, i.e. "use EDNS0". - - *ednsflags*, an ``int``, the EDNS flag values. - - *payload*, an ``int``, is the EDNS sender's payload field, which is the - maximum size of UDP datagram the sender can handle. I.e. how big - a response to this message can be. - - *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS - options. - """ - - if edns is None or edns is False: - edns = -1 - elif edns is True: - edns = 0 - self.edns = edns - self.ednsflags = ednsflags - self.payload = payload - self.ednsoptions = options - - def set_flags(self, flags: int) -> None: - """Overrides the default flags with your own. - - *flags*, an ``int``, the message flags to use. - """ - - self.flags = flags - - @classmethod - def _enrich_nameservers( - cls, - nameservers: Sequence[Union[str, dns.nameserver.Nameserver]], - nameserver_ports: Dict[str, int], - default_port: int, - ) -> List[dns.nameserver.Nameserver]: - enriched_nameservers = [] - if isinstance(nameservers, list): - for nameserver in nameservers: - enriched_nameserver: dns.nameserver.Nameserver - if isinstance(nameserver, dns.nameserver.Nameserver): - enriched_nameserver = nameserver - elif dns.inet.is_address(nameserver): - port = nameserver_ports.get(nameserver, default_port) - enriched_nameserver = dns.nameserver.Do53Nameserver( - nameserver, port - ) - else: - try: - if urlparse(nameserver).scheme != "https": - raise NotImplementedError - except Exception: - raise ValueError( - f"nameserver {nameserver} is not a " - "dns.nameserver.Nameserver instance or text form, " - "IP address, nor a valid https URL" - ) - enriched_nameserver = dns.nameserver.DoHNameserver(nameserver) - enriched_nameservers.append(enriched_nameserver) - else: - raise ValueError( - f"nameservers must be a list or tuple (not a {type(nameservers)})" - ) - return enriched_nameservers - - @property - def nameservers( - self, - ) -> Sequence[Union[str, dns.nameserver.Nameserver]]: - return self._nameservers - - @nameservers.setter - def nameservers( - self, nameservers: Sequence[Union[str, dns.nameserver.Nameserver]] - ) -> None: - """ - *nameservers*, a ``list`` of nameservers, where a nameserver is either - a string interpretable as a nameserver, or a ``dns.nameserver.Nameserver`` - instance. - - Raises ``ValueError`` if *nameservers* is not a list of nameservers. - """ - # We just call _enrich_nameservers() for checking - self._enrich_nameservers(nameservers, self.nameserver_ports, self.port) - self._nameservers = nameservers - - -class Resolver(BaseResolver): - """DNS stub resolver.""" - - def resolve( - self, - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, - ) -> Answer: # pylint: disable=arguments-differ - """Query nameservers to find the answer to the question. - - The *qname*, *rdtype*, and *rdclass* parameters may be objects - of the appropriate type, or strings that can be converted into objects - of the appropriate type. - - *qname*, a ``dns.name.Name`` or ``str``, the query name. - - *rdtype*, an ``int`` or ``str``, the query type. - - *rdclass*, an ``int`` or ``str``, the query class. - - *tcp*, a ``bool``. If ``True``, use TCP to make the query. - - *source*, a ``str`` or ``None``. If not ``None``, bind to this IP - address when making queries. - - *raise_on_no_answer*, a ``bool``. If ``True``, raise - ``dns.resolver.NoAnswer`` if there's no answer to the question. - - *source_port*, an ``int``, the port from which to send the message. - - *lifetime*, a ``float``, how many seconds a query should run - before timing out. - - *search*, a ``bool`` or ``None``, determines whether the - search list configured in the system's resolver configuration - are used for relative names, and whether the resolver's domain - may be added to relative names. The default is ``None``, - which causes the value of the resolver's - ``use_search_by_default`` attribute to be used. - - Raises ``dns.resolver.LifetimeTimeout`` if no answers could be found - in the specified lifetime. - - Raises ``dns.resolver.NXDOMAIN`` if the query name does not exist. - - Raises ``dns.resolver.YXDOMAIN`` if the query name is too long after - DNAME substitution. - - Raises ``dns.resolver.NoAnswer`` if *raise_on_no_answer* is - ``True`` and the query name exists but has no RRset of the - desired type and class. - - Raises ``dns.resolver.NoNameservers`` if no non-broken - nameservers are available to answer the question. - - Returns a ``dns.resolver.Answer`` instance. - - """ - - resolution = _Resolution( - self, qname, rdtype, rdclass, tcp, raise_on_no_answer, search - ) - start = time.time() - while True: - (request, answer) = resolution.next_request() - # Note we need to say "if answer is not None" and not just - # "if answer" because answer implements __len__, and python - # will call that. We want to return if we have an answer - # object, including in cases where its length is 0. - if answer is not None: - # cache hit! - return answer - assert request is not None # needed for type checking - done = False - while not done: - (nameserver, tcp, backoff) = resolution.next_nameserver() - if backoff: - time.sleep(backoff) - timeout = self._compute_timeout(start, lifetime, resolution.errors) - try: - response = nameserver.query( - request, - timeout=timeout, - source=source, - source_port=source_port, - max_size=tcp, - ) - except Exception as ex: - (_, done) = resolution.query_result(None, ex) - continue - (answer, done) = resolution.query_result(response, None) - # Note we need to say "if answer is not None" and not just - # "if answer" because answer implements __len__, and python - # will call that. We want to return if we have an answer - # object, including in cases where its length is 0. - if answer is not None: - return answer - - def query( - self, - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - ) -> Answer: # pragma: no cover - """Query nameservers to find the answer to the question. - - This method calls resolve() with ``search=True``, and is - provided for backwards compatibility with prior versions of - dnspython. See the documentation for the resolve() method for - further details. - """ - warnings.warn( - "please use dns.resolver.Resolver.resolve() instead", - DeprecationWarning, - stacklevel=2, - ) - return self.resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - True, - ) - - def resolve_address(self, ipaddr: str, *args: Any, **kwargs: Any) -> Answer: - """Use a resolver to run a reverse query for PTR records. - - This utilizes the resolve() method to perform a PTR lookup on the - specified IP address. - - *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get - the PTR record for. - - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. - """ - # We make a modified kwargs for type checking happiness, as otherwise - # we get a legit warning about possibly having rdtype and rdclass - # in the kwargs more than once. - modified_kwargs: Dict[str, Any] = {} - modified_kwargs.update(kwargs) - modified_kwargs["rdtype"] = dns.rdatatype.PTR - modified_kwargs["rdclass"] = dns.rdataclass.IN - return self.resolve( - dns.reversename.from_address(ipaddr), *args, **modified_kwargs - ) - - def resolve_name( - self, - name: Union[dns.name.Name, str], - family: int = socket.AF_UNSPEC, - **kwargs: Any, - ) -> HostAnswers: - """Use a resolver to query for address records. - - This utilizes the resolve() method to perform A and/or AAAA lookups on - the specified name. - - *qname*, a ``dns.name.Name`` or ``str``, the name to resolve. - - *family*, an ``int``, the address family. If socket.AF_UNSPEC - (the default), both A and AAAA records will be retrieved. - - All other arguments that can be passed to the resolve() function - except for rdtype and rdclass are also supported by this - function. - """ - # We make a modified kwargs for type checking happiness, as otherwise - # we get a legit warning about possibly having rdtype and rdclass - # in the kwargs more than once. - modified_kwargs: Dict[str, Any] = {} - modified_kwargs.update(kwargs) - modified_kwargs.pop("rdtype", None) - modified_kwargs["rdclass"] = dns.rdataclass.IN - - if family == socket.AF_INET: - v4 = self.resolve(name, dns.rdatatype.A, **modified_kwargs) - return HostAnswers.make(v4=v4) - elif family == socket.AF_INET6: - v6 = self.resolve(name, dns.rdatatype.AAAA, **modified_kwargs) - return HostAnswers.make(v6=v6) - elif family != socket.AF_UNSPEC: # pragma: no cover - raise NotImplementedError(f"unknown address family {family}") - - raise_on_no_answer = modified_kwargs.pop("raise_on_no_answer", True) - lifetime = modified_kwargs.pop("lifetime", None) - start = time.time() - v6 = self.resolve( - name, - dns.rdatatype.AAAA, - raise_on_no_answer=False, - lifetime=self._compute_timeout(start, lifetime), - **modified_kwargs, - ) - # Note that setting name ensures we query the same name - # for A as we did for AAAA. (This is just in case search lists - # are active by default in the resolver configuration and - # we might be talking to a server that says NXDOMAIN when it - # wants to say NOERROR no data. - name = v6.qname - v4 = self.resolve( - name, - dns.rdatatype.A, - raise_on_no_answer=False, - lifetime=self._compute_timeout(start, lifetime), - **modified_kwargs, - ) - answers = HostAnswers.make(v6=v6, v4=v4, add_empty=not raise_on_no_answer) - if not answers: - raise NoAnswer(response=v6.response) - return answers - - # pylint: disable=redefined-outer-name - - def canonical_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name: - """Determine the canonical name of *name*. - - The canonical name is the name the resolver uses for queries - after all CNAME and DNAME renamings have been applied. - - *name*, a ``dns.name.Name`` or ``str``, the query name. - - This method can raise any exception that ``resolve()`` can - raise, other than ``dns.resolver.NoAnswer`` and - ``dns.resolver.NXDOMAIN``. - - Returns a ``dns.name.Name``. - """ - try: - answer = self.resolve(name, raise_on_no_answer=False) - canonical_name = answer.canonical_name - except dns.resolver.NXDOMAIN as e: - canonical_name = e.canonical_name - return canonical_name - - # pylint: enable=redefined-outer-name - - def try_ddr(self, lifetime: float = 5.0) -> None: - """Try to update the resolver's nameservers using Discovery of Designated - Resolvers (DDR). If successful, the resolver will subsequently use - DNS-over-HTTPS or DNS-over-TLS for future queries. - - *lifetime*, a float, is the maximum time to spend attempting DDR. The default - is 5 seconds. - - If the SVCB query is successful and results in a non-empty list of nameservers, - then the resolver's nameservers are set to the returned servers in priority - order. - - The current implementation does not use any address hints from the SVCB record, - nor does it resolve addresses for the SCVB target name, rather it assumes that - the bootstrap nameserver will always be one of the addresses and uses it. - A future revision to the code may offer fuller support. The code verifies that - the bootstrap nameserver is in the Subject Alternative Name field of the - TLS certficate. - """ - try: - expiration = time.time() + lifetime - answer = self.resolve( - dns._ddr._local_resolver_name, "SVCB", lifetime=lifetime - ) - timeout = dns.query._remaining(expiration) - nameservers = dns._ddr._get_nameservers_sync(answer, timeout) - if len(nameservers) > 0: - self.nameservers = nameservers - except Exception: # pragma: no cover - pass - - -#: The default resolver. -default_resolver: Optional[Resolver] = None - - -def get_default_resolver() -> Resolver: - """Get the default resolver, initializing it if necessary.""" - if default_resolver is None: - reset_default_resolver() - assert default_resolver is not None - return default_resolver - - -def reset_default_resolver() -> None: - """Re-initialize default resolver. - - Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX - systems) will be re-read immediately. - """ - - global default_resolver - default_resolver = Resolver() - - -def resolve( - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, -) -> Answer: # pragma: no cover - """Query nameservers to find the answer to the question. - - This is a convenience function that uses the default resolver - object to make the query. - - See ``dns.resolver.Resolver.resolve`` for more information on the - parameters. - """ - - return get_default_resolver().resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - search, - ) - - -def query( - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, -) -> Answer: # pragma: no cover - """Query nameservers to find the answer to the question. - - This method calls resolve() with ``search=True``, and is - provided for backwards compatibility with prior versions of - dnspython. See the documentation for the resolve() method for - further details. - """ - warnings.warn( - "please use dns.resolver.resolve() instead", DeprecationWarning, stacklevel=2 - ) - return resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - True, - ) - - -def resolve_address(ipaddr: str, *args: Any, **kwargs: Any) -> Answer: - """Use a resolver to run a reverse query for PTR records. - - See ``dns.resolver.Resolver.resolve_address`` for more information on the - parameters. - """ - - return get_default_resolver().resolve_address(ipaddr, *args, **kwargs) - - -def resolve_name( - name: Union[dns.name.Name, str], family: int = socket.AF_UNSPEC, **kwargs: Any -) -> HostAnswers: - """Use a resolver to query for address records. - - See ``dns.resolver.Resolver.resolve_name`` for more information on the - parameters. - """ - - return get_default_resolver().resolve_name(name, family, **kwargs) - - -def canonical_name(name: Union[dns.name.Name, str]) -> dns.name.Name: - """Determine the canonical name of *name*. - - See ``dns.resolver.Resolver.canonical_name`` for more information on the - parameters and possible exceptions. - """ - - return get_default_resolver().canonical_name(name) - - -def try_ddr(lifetime: float = 5.0) -> None: # pragma: no cover - """Try to update the default resolver's nameservers using Discovery of Designated - Resolvers (DDR). If successful, the resolver will subsequently use - DNS-over-HTTPS or DNS-over-TLS for future queries. - - See :py:func:`dns.resolver.Resolver.try_ddr` for more information. - """ - return get_default_resolver().try_ddr(lifetime) - - -def zone_for_name( - name: Union[dns.name.Name, str], - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - tcp: bool = False, - resolver: Optional[Resolver] = None, - lifetime: Optional[float] = None, -) -> dns.name.Name: - """Find the name of the zone which contains the specified name. - - *name*, an absolute ``dns.name.Name`` or ``str``, the query name. - - *rdclass*, an ``int``, the query class. - - *tcp*, a ``bool``. If ``True``, use TCP to make the query. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use. - If ``None``, the default, then the default resolver is used. - - *lifetime*, a ``float``, the total time to allow for the queries needed - to determine the zone. If ``None``, the default, then only the individual - query limits of the resolver apply. - - Raises ``dns.resolver.NoRootSOA`` if there is no SOA RR at the DNS - root. (This is only likely to happen if you're using non-default - root servers in your network and they are misconfigured.) - - Raises ``dns.resolver.LifetimeTimeout`` if the answer could not be - found in the allotted lifetime. - - Returns a ``dns.name.Name``. - """ - - if isinstance(name, str): - name = dns.name.from_text(name, dns.name.root) - if resolver is None: - resolver = get_default_resolver() - if not name.is_absolute(): - raise NotAbsolute(name) - start = time.time() - expiration: Optional[float] - if lifetime is not None: - expiration = start + lifetime - else: - expiration = None - while 1: - try: - rlifetime: Optional[float] - if expiration is not None: - rlifetime = expiration - time.time() - if rlifetime <= 0: - rlifetime = 0 - else: - rlifetime = None - answer = resolver.resolve( - name, dns.rdatatype.SOA, rdclass, tcp, lifetime=rlifetime - ) - assert answer.rrset is not None - if answer.rrset.name == name: - return name - # otherwise we were CNAMEd or DNAMEd and need to look higher - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: - if isinstance(e, dns.resolver.NXDOMAIN): - response = e.responses().get(name) - else: - response = e.response() # pylint: disable=no-value-for-parameter - if response: - for rrs in response.authority: - if rrs.rdtype == dns.rdatatype.SOA and rrs.rdclass == rdclass: - (nr, _, _) = rrs.name.fullcompare(name) - if nr == dns.name.NAMERELN_SUPERDOMAIN: - # We're doing a proper superdomain check as - # if the name were equal we ought to have gotten - # it in the answer section! We are ignoring the - # possibility that the authority is insane and - # is including multiple SOA RRs for different - # authorities. - return rrs.name - # we couldn't extract anything useful from the response (e.g. it's - # a type 3 NXDOMAIN) - try: - name = name.parent() - except dns.name.NoParent: - raise NoRootSOA - - -def make_resolver_at( - where: Union[dns.name.Name, str], - port: int = 53, - family: int = socket.AF_UNSPEC, - resolver: Optional[Resolver] = None, -) -> Resolver: - """Make a stub resolver using the specified destination as the full resolver. - - *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the - full resolver. - - *port*, an ``int``, the port to use. If not specified, the default is 53. - - *family*, an ``int``, the address family to use. This parameter is used if - *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case - the first address returned by ``resolve_name()`` will be used, otherwise the - first address of the specified family will be used. - - *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for - resolution of hostnames. If not specified, the default resolver will be used. - - Returns a ``dns.resolver.Resolver`` or raises an exception. - """ - if resolver is None: - resolver = get_default_resolver() - nameservers: List[Union[str, dns.nameserver.Nameserver]] = [] - if isinstance(where, str) and dns.inet.is_address(where): - nameservers.append(dns.nameserver.Do53Nameserver(where, port)) - else: - for address in resolver.resolve_name(where, family).addresses(): - nameservers.append(dns.nameserver.Do53Nameserver(address, port)) - res = dns.resolver.Resolver(configure=False) - res.nameservers = nameservers - return res - - -def resolve_at( - where: Union[dns.name.Name, str], - qname: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A, - rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - tcp: bool = False, - source: Optional[str] = None, - raise_on_no_answer: bool = True, - source_port: int = 0, - lifetime: Optional[float] = None, - search: Optional[bool] = None, - port: int = 53, - family: int = socket.AF_UNSPEC, - resolver: Optional[Resolver] = None, -) -> Answer: - """Query nameservers to find the answer to the question. - - This is a convenience function that calls ``dns.resolver.make_resolver_at()`` to - make a resolver, and then uses it to resolve the query. - - See ``dns.resolver.Resolver.resolve`` for more information on the resolution - parameters, and ``dns.resolver.make_resolver_at`` for information about the resolver - parameters *where*, *port*, *family*, and *resolver*. - - If making more than one query, it is more efficient to call - ``dns.resolver.make_resolver_at()`` and then use that resolver for the queries - instead of calling ``resolve_at()`` multiple times. - """ - return make_resolver_at(where, port, family, resolver).resolve( - qname, - rdtype, - rdclass, - tcp, - source, - raise_on_no_answer, - source_port, - lifetime, - search, - ) - - -# -# Support for overriding the system resolver for all python code in the -# running process. -# - -_protocols_for_socktype = { - socket.SOCK_DGRAM: [socket.SOL_UDP], - socket.SOCK_STREAM: [socket.SOL_TCP], -} - -_resolver = None -_original_getaddrinfo = socket.getaddrinfo -_original_getnameinfo = socket.getnameinfo -_original_getfqdn = socket.getfqdn -_original_gethostbyname = socket.gethostbyname -_original_gethostbyname_ex = socket.gethostbyname_ex -_original_gethostbyaddr = socket.gethostbyaddr - - -def _getaddrinfo( - host=None, service=None, family=socket.AF_UNSPEC, socktype=0, proto=0, flags=0 -): - if flags & socket.AI_NUMERICHOST != 0: - # Short circuit directly into the system's getaddrinfo(). We're - # not adding any value in this case, and this avoids infinite loops - # because dns.query.* needs to call getaddrinfo() for IPv6 scoping - # reasons. We will also do this short circuit below if we - # discover that the host is an address literal. - return _original_getaddrinfo(host, service, family, socktype, proto, flags) - if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0: - # Not implemented. We raise a gaierror as opposed to a - # NotImplementedError as it helps callers handle errors more - # appropriately. [Issue #316] - # - # We raise EAI_FAIL as opposed to EAI_SYSTEM because there is - # no EAI_SYSTEM on Windows [Issue #416]. We didn't go for - # EAI_BADFLAGS as the flags aren't bad, we just don't - # implement them. - raise socket.gaierror( - socket.EAI_FAIL, "Non-recoverable failure in name resolution" - ) - if host is None and service is None: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - addrs = [] - canonical_name = None # pylint: disable=redefined-outer-name - # Is host None or an address literal? If so, use the system's - # getaddrinfo(). - if host is None: - return _original_getaddrinfo(host, service, family, socktype, proto, flags) - try: - # We don't care about the result of af_for_address(), we're just - # calling it so it raises an exception if host is not an IPv4 or - # IPv6 address. - dns.inet.af_for_address(host) - return _original_getaddrinfo(host, service, family, socktype, proto, flags) - except Exception: - pass - # Something needs resolution! - try: - answers = _resolver.resolve_name(host, family) - addrs = answers.addresses_and_families() - canonical_name = answers.canonical_name().to_text(True) - except dns.resolver.NXDOMAIN: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - except Exception: - # We raise EAI_AGAIN here as the failure may be temporary - # (e.g. a timeout) and EAI_SYSTEM isn't defined on Windows. - # [Issue #416] - raise socket.gaierror(socket.EAI_AGAIN, "Temporary failure in name resolution") - port = None - try: - # Is it a port literal? - if service is None: - port = 0 - else: - port = int(service) - except Exception: - if flags & socket.AI_NUMERICSERV == 0: - try: - port = socket.getservbyname(service) - except Exception: - pass - if port is None: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - tuples = [] - if socktype == 0: - socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM] - else: - socktypes = [socktype] - if flags & socket.AI_CANONNAME != 0: - cname = canonical_name - else: - cname = "" - for addr, af in addrs: - for socktype in socktypes: - for proto in _protocols_for_socktype[socktype]: - addr_tuple = dns.inet.low_level_address_tuple((addr, port), af) - tuples.append((af, socktype, proto, cname, addr_tuple)) - if len(tuples) == 0: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - return tuples - - -def _getnameinfo(sockaddr, flags=0): - host = sockaddr[0] - port = sockaddr[1] - if len(sockaddr) == 4: - scope = sockaddr[3] - family = socket.AF_INET6 - else: - scope = None - family = socket.AF_INET - tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, socket.SOL_TCP, 0) - if len(tuples) > 1: - raise OSError("sockaddr resolved to multiple addresses") - addr = tuples[0][4][0] - if flags & socket.NI_DGRAM: - pname = "udp" - else: - pname = "tcp" - qname = dns.reversename.from_address(addr) - if flags & socket.NI_NUMERICHOST == 0: - try: - answer = _resolver.resolve(qname, "PTR") - hostname = answer.rrset[0].target.to_text(True) - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - if flags & socket.NI_NAMEREQD: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - hostname = addr - if scope is not None: - hostname += "%" + str(scope) - else: - hostname = addr - if scope is not None: - hostname += "%" + str(scope) - if flags & socket.NI_NUMERICSERV: - service = str(port) - else: - service = socket.getservbyport(port, pname) - return (hostname, service) - - -def _getfqdn(name=None): - if name is None: - name = socket.gethostname() - try: - (name, _, _) = _gethostbyaddr(name) - # Python's version checks aliases too, but our gethostbyname - # ignores them, so we do so here as well. - except Exception: # pragma: no cover - pass - return name - - -def _gethostbyname(name): - return _gethostbyname_ex(name)[2][0] - - -def _gethostbyname_ex(name): - aliases = [] - addresses = [] - tuples = _getaddrinfo( - name, 0, socket.AF_INET, socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_CANONNAME - ) - canonical = tuples[0][3] - for item in tuples: - addresses.append(item[4][0]) - # XXX we just ignore aliases - return (canonical, aliases, addresses) - - -def _gethostbyaddr(ip): - try: - dns.ipv6.inet_aton(ip) - sockaddr = (ip, 80, 0, 0) - family = socket.AF_INET6 - except Exception: - try: - dns.ipv4.inet_aton(ip) - except Exception: - raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") - sockaddr = (ip, 80) - family = socket.AF_INET - (name, _) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) - aliases = [] - addresses = [] - tuples = _getaddrinfo( - name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_CANONNAME - ) - canonical = tuples[0][3] - # We only want to include an address from the tuples if it's the - # same as the one we asked about. We do this comparison in binary - # to avoid any differences in text representations. - bin_ip = dns.inet.inet_pton(family, ip) - for item in tuples: - addr = item[4][0] - bin_addr = dns.inet.inet_pton(family, addr) - if bin_ip == bin_addr: - addresses.append(addr) - # XXX we just ignore aliases - return (canonical, aliases, addresses) - - -def override_system_resolver(resolver: Optional[Resolver] = None) -> None: - """Override the system resolver routines in the socket module with - versions which use dnspython's resolver. - - This can be useful in testing situations where you want to control - the resolution behavior of python code without having to change - the system's resolver settings (e.g. /etc/resolv.conf). - - The resolver to use may be specified; if it's not, the default - resolver will be used. - - resolver, a ``dns.resolver.Resolver`` or ``None``, the resolver to use. - """ - - if resolver is None: - resolver = get_default_resolver() - global _resolver - _resolver = resolver - socket.getaddrinfo = _getaddrinfo - socket.getnameinfo = _getnameinfo - socket.getfqdn = _getfqdn - socket.gethostbyname = _gethostbyname - socket.gethostbyname_ex = _gethostbyname_ex - socket.gethostbyaddr = _gethostbyaddr - - -def restore_system_resolver() -> None: - """Undo the effects of prior override_system_resolver().""" - - global _resolver - _resolver = None - socket.getaddrinfo = _original_getaddrinfo - socket.getnameinfo = _original_getnameinfo - socket.getfqdn = _original_getfqdn - socket.gethostbyname = _original_gethostbyname - socket.gethostbyname_ex = _original_gethostbyname_ex - socket.gethostbyaddr = _original_gethostbyaddr diff --git a/backend/venv39/lib/python3.9/site-packages/dns/reversename.py b/backend/venv39/lib/python3.9/site-packages/dns/reversename.py deleted file mode 100644 index 8236c71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/reversename.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2006-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Reverse Map Names.""" - -import binascii - -import dns.ipv4 -import dns.ipv6 -import dns.name - -ipv4_reverse_domain = dns.name.from_text("in-addr.arpa.") -ipv6_reverse_domain = dns.name.from_text("ip6.arpa.") - - -def from_address( - text: str, - v4_origin: dns.name.Name = ipv4_reverse_domain, - v6_origin: dns.name.Name = ipv6_reverse_domain, -) -> dns.name.Name: - """Convert an IPv4 or IPv6 address in textual form into a Name object whose - value is the reverse-map domain name of the address. - - *text*, a ``str``, is an IPv4 or IPv6 address in textual form - (e.g. '127.0.0.1', '::1') - - *v4_origin*, a ``dns.name.Name`` to append to the labels corresponding to - the address if the address is an IPv4 address, instead of the default - (in-addr.arpa.) - - *v6_origin*, a ``dns.name.Name`` to append to the labels corresponding to - the address if the address is an IPv6 address, instead of the default - (ip6.arpa.) - - Raises ``dns.exception.SyntaxError`` if the address is badly formed. - - Returns a ``dns.name.Name``. - """ - - try: - v6 = dns.ipv6.inet_aton(text) - if dns.ipv6.is_mapped(v6): - parts = ["%d" % byte for byte in v6[12:]] - origin = v4_origin - else: - parts = [x for x in str(binascii.hexlify(v6).decode())] - origin = v6_origin - except Exception: - parts = ["%d" % byte for byte in dns.ipv4.inet_aton(text)] - origin = v4_origin - return dns.name.from_text(".".join(reversed(parts)), origin=origin) - - -def to_address( - name: dns.name.Name, - v4_origin: dns.name.Name = ipv4_reverse_domain, - v6_origin: dns.name.Name = ipv6_reverse_domain, -) -> str: - """Convert a reverse map domain name into textual address form. - - *name*, a ``dns.name.Name``, an IPv4 or IPv6 address in reverse-map name - form. - - *v4_origin*, a ``dns.name.Name`` representing the top-level domain for - IPv4 addresses, instead of the default (in-addr.arpa.) - - *v6_origin*, a ``dns.name.Name`` representing the top-level domain for - IPv4 addresses, instead of the default (ip6.arpa.) - - Raises ``dns.exception.SyntaxError`` if the name does not have a - reverse-map form. - - Returns a ``str``. - """ - - if name.is_subdomain(v4_origin): - name = name.relativize(v4_origin) - text = b".".join(reversed(name.labels)) - # run through inet_ntoa() to check syntax and make pretty. - return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) - elif name.is_subdomain(v6_origin): - name = name.relativize(v6_origin) - labels = list(reversed(name.labels)) - parts = [] - for i in range(0, len(labels), 4): - parts.append(b"".join(labels[i : i + 4])) - text = b":".join(parts) - # run through inet_ntoa() to check syntax and make pretty. - return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) - else: - raise dns.exception.SyntaxError("unknown reverse-map address family") diff --git a/backend/venv39/lib/python3.9/site-packages/dns/rrset.py b/backend/venv39/lib/python3.9/site-packages/dns/rrset.py deleted file mode 100644 index 6f39b10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/rrset.py +++ /dev/null @@ -1,285 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS RRsets (an RRset is a named rdataset)""" - -from typing import Any, Collection, Dict, Optional, Union, cast - -import dns.name -import dns.rdataclass -import dns.rdataset -import dns.renderer - - -class RRset(dns.rdataset.Rdataset): - """A DNS RRset (named rdataset). - - RRset inherits from Rdataset, and RRsets can be treated as - Rdatasets in most cases. There are, however, a few notable - exceptions. RRsets have different to_wire() and to_text() method - arguments, reflecting the fact that RRsets always have an owner - name. - """ - - __slots__ = ["name", "deleting"] - - def __init__( - self, - name: dns.name.Name, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - deleting: Optional[dns.rdataclass.RdataClass] = None, - ): - """Create a new RRset.""" - - super().__init__(rdclass, rdtype, covers) - self.name = name - self.deleting = deleting - - def _clone(self): - obj = super()._clone() - obj.name = self.name - obj.deleting = self.deleting - return obj - - def __repr__(self): - if self.covers == 0: - ctext = "" - else: - ctext = "(" + dns.rdatatype.to_text(self.covers) + ")" - if self.deleting is not None: - dtext = " delete=" + dns.rdataclass.to_text(self.deleting) - else: - dtext = "" - return ( - "" - ) - - def __str__(self): - return self.to_text() - - def __eq__(self, other): - if isinstance(other, RRset): - if self.name != other.name: - return False - elif not isinstance(other, dns.rdataset.Rdataset): - return False - return super().__eq__(other) - - def match(self, *args: Any, **kwargs: Any) -> bool: # type: ignore[override] - """Does this rrset match the specified attributes? - - Behaves as :py:func:`full_match()` if the first argument is a - ``dns.name.Name``, and as :py:func:`dns.rdataset.Rdataset.match()` - otherwise. - - (This behavior fixes a design mistake where the signature of this - method became incompatible with that of its superclass. The fix - makes RRsets matchable as Rdatasets while preserving backwards - compatibility.) - """ - if isinstance(args[0], dns.name.Name): - return self.full_match(*args, **kwargs) # type: ignore[arg-type] - else: - return super().match(*args, **kwargs) # type: ignore[arg-type] - - def full_match( - self, - name: dns.name.Name, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType, - deleting: Optional[dns.rdataclass.RdataClass] = None, - ) -> bool: - """Returns ``True`` if this rrset matches the specified name, class, - type, covers, and deletion state. - """ - if not super().match(rdclass, rdtype, covers): - return False - if self.name != name or self.deleting != deleting: - return False - return True - - # pylint: disable=arguments-differ - - def to_text( # type: ignore[override] - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - **kw: Dict[str, Any], - ) -> str: - """Convert the RRset into DNS zone file format. - - See ``dns.name.Name.choose_relativity`` for more information - on how *origin* and *relativize* determine the way names - are emitted. - - Any additional keyword arguments are passed on to the rdata - ``to_text()`` method. - - *origin*, a ``dns.name.Name`` or ``None``, the origin for relative - names. - - *relativize*, a ``bool``. If ``True``, names will be relativized - to *origin*. - """ - - return super().to_text( - self.name, origin, relativize, self.deleting, **kw # type: ignore - ) - - def to_wire( # type: ignore[override] - self, - file: Any, - compress: Optional[dns.name.CompressType] = None, # type: ignore - origin: Optional[dns.name.Name] = None, - **kw: Dict[str, Any], - ) -> int: - """Convert the RRset to wire format. - - All keyword arguments are passed to ``dns.rdataset.to_wire()``; see - that function for details. - - Returns an ``int``, the number of records emitted. - """ - - return super().to_wire( - self.name, file, compress, origin, self.deleting, **kw # type:ignore - ) - - # pylint: enable=arguments-differ - - def to_rdataset(self) -> dns.rdataset.Rdataset: - """Convert an RRset into an Rdataset. - - Returns a ``dns.rdataset.Rdataset``. - """ - return dns.rdataset.from_rdata_list(self.ttl, list(self)) - - -def from_text_list( - name: Union[dns.name.Name, str], - ttl: int, - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - text_rdatas: Collection[str], - idna_codec: Optional[dns.name.IDNACodec] = None, - origin: Optional[dns.name.Name] = None, - relativize: bool = True, - relativize_to: Optional[dns.name.Name] = None, -) -> RRset: - """Create an RRset with the specified name, TTL, class, and type, and with - the specified list of rdatas in text format. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - *origin*, a ``dns.name.Name`` (or ``None``), the - origin to use for relative names. - - *relativize*, a ``bool``. If true, name will be relativized. - - *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use - when relativizing names. If not set, the *origin* value will be used. - - Returns a ``dns.rrset.RRset`` object. - """ - - if isinstance(name, str): - name = dns.name.from_text(name, None, idna_codec=idna_codec) - rdclass = dns.rdataclass.RdataClass.make(rdclass) - rdtype = dns.rdatatype.RdataType.make(rdtype) - r = RRset(name, rdclass, rdtype) - r.update_ttl(ttl) - for t in text_rdatas: - rd = dns.rdata.from_text( - r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec - ) - r.add(rd) - return r - - -def from_text( - name: Union[dns.name.Name, str], - ttl: int, - rdclass: Union[dns.rdataclass.RdataClass, str], - rdtype: Union[dns.rdatatype.RdataType, str], - *text_rdatas: Any, -) -> RRset: - """Create an RRset with the specified name, TTL, class, and type and with - the specified rdatas in text format. - - Returns a ``dns.rrset.RRset`` object. - """ - - return from_text_list( - name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas) - ) - - -def from_rdata_list( - name: Union[dns.name.Name, str], - ttl: int, - rdatas: Collection[dns.rdata.Rdata], - idna_codec: Optional[dns.name.IDNACodec] = None, -) -> RRset: - """Create an RRset with the specified name and TTL, and with - the specified list of rdata objects. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder to use; if ``None``, the default IDNA 2003 - encoder/decoder is used. - - Returns a ``dns.rrset.RRset`` object. - - """ - - if isinstance(name, str): - name = dns.name.from_text(name, None, idna_codec=idna_codec) - - if len(rdatas) == 0: - raise ValueError("rdata list must not be empty") - r = None - for rd in rdatas: - if r is None: - r = RRset(name, rd.rdclass, rd.rdtype) - r.update_ttl(ttl) - r.add(rd) - assert r is not None - return r - - -def from_rdata(name: Union[dns.name.Name, str], ttl: int, *rdatas: Any) -> RRset: - """Create an RRset with the specified name and TTL, and with - the specified rdata objects. - - Returns a ``dns.rrset.RRset`` object. - """ - - return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas)) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/serial.py b/backend/venv39/lib/python3.9/site-packages/dns/serial.py deleted file mode 100644 index 3417299..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/serial.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -"""Serial Number Arthimetic from RFC 1982""" - - -class Serial: - def __init__(self, value: int, bits: int = 32): - self.value = value % 2**bits - self.bits = bits - - def __repr__(self): - return f"dns.serial.Serial({self.value}, {self.bits})" - - def __eq__(self, other): - if isinstance(other, int): - other = Serial(other, self.bits) - elif not isinstance(other, Serial) or other.bits != self.bits: - return NotImplemented - return self.value == other.value - - def __ne__(self, other): - if isinstance(other, int): - other = Serial(other, self.bits) - elif not isinstance(other, Serial) or other.bits != self.bits: - return NotImplemented - return self.value != other.value - - def __lt__(self, other): - if isinstance(other, int): - other = Serial(other, self.bits) - elif not isinstance(other, Serial) or other.bits != self.bits: - return NotImplemented - if self.value < other.value and other.value - self.value < 2 ** (self.bits - 1): - return True - elif self.value > other.value and self.value - other.value > 2 ** ( - self.bits - 1 - ): - return True - else: - return False - - def __le__(self, other): - return self == other or self < other - - def __gt__(self, other): - if isinstance(other, int): - other = Serial(other, self.bits) - elif not isinstance(other, Serial) or other.bits != self.bits: - return NotImplemented - if self.value < other.value and other.value - self.value > 2 ** (self.bits - 1): - return True - elif self.value > other.value and self.value - other.value < 2 ** ( - self.bits - 1 - ): - return True - else: - return False - - def __ge__(self, other): - return self == other or self > other - - def __add__(self, other): - v = self.value - if isinstance(other, Serial): - delta = other.value - elif isinstance(other, int): - delta = other - else: - raise ValueError - if abs(delta) > (2 ** (self.bits - 1) - 1): - raise ValueError - v += delta - v = v % 2**self.bits - return Serial(v, self.bits) - - def __iadd__(self, other): - v = self.value - if isinstance(other, Serial): - delta = other.value - elif isinstance(other, int): - delta = other - else: - raise ValueError - if abs(delta) > (2 ** (self.bits - 1) - 1): - raise ValueError - v += delta - v = v % 2**self.bits - self.value = v - return self - - def __sub__(self, other): - v = self.value - if isinstance(other, Serial): - delta = other.value - elif isinstance(other, int): - delta = other - else: - raise ValueError - if abs(delta) > (2 ** (self.bits - 1) - 1): - raise ValueError - v -= delta - v = v % 2**self.bits - return Serial(v, self.bits) - - def __isub__(self, other): - v = self.value - if isinstance(other, Serial): - delta = other.value - elif isinstance(other, int): - delta = other - else: - raise ValueError - if abs(delta) > (2 ** (self.bits - 1) - 1): - raise ValueError - v -= delta - v = v % 2**self.bits - self.value = v - return self diff --git a/backend/venv39/lib/python3.9/site-packages/dns/set.py b/backend/venv39/lib/python3.9/site-packages/dns/set.py deleted file mode 100644 index ae8f0dd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/set.py +++ /dev/null @@ -1,308 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -import itertools - - -class Set: - """A simple set class. - - This class was originally used to deal with python not having a set class, and - originally the class used lists in its implementation. The ordered and indexable - nature of RRsets and Rdatasets is unfortunately widely used in dnspython - applications, so for backwards compatibility sets continue to be a custom class, now - based on an ordered dictionary. - """ - - __slots__ = ["items"] - - def __init__(self, items=None): - """Initialize the set. - - *items*, an iterable or ``None``, the initial set of items. - """ - - self.items = dict() - if items is not None: - for item in items: - # This is safe for how we use set, but if other code - # subclasses it could be a legitimate issue. - self.add(item) # lgtm[py/init-calls-subclass] - - def __repr__(self): - return f"dns.set.Set({repr(list(self.items.keys()))})" # pragma: no cover - - def add(self, item): - """Add an item to the set.""" - - if item not in self.items: - self.items[item] = None - - def remove(self, item): - """Remove an item from the set.""" - - try: - del self.items[item] - except KeyError: - raise ValueError - - def discard(self, item): - """Remove an item from the set if present.""" - - self.items.pop(item, None) - - def pop(self): - """Remove an arbitrary item from the set.""" - (k, _) = self.items.popitem() - return k - - def _clone(self) -> "Set": - """Make a (shallow) copy of the set. - - There is a 'clone protocol' that subclasses of this class - should use. To make a copy, first call your super's _clone() - method, and use the object returned as the new instance. Then - make shallow copies of the attributes defined in the subclass. - - This protocol allows us to write the set algorithms that - return new instances (e.g. union) once, and keep using them in - subclasses. - """ - - if hasattr(self, "_clone_class"): - cls = self._clone_class # type: ignore - else: - cls = self.__class__ - obj = cls.__new__(cls) - obj.items = dict() - obj.items.update(self.items) - return obj - - def __copy__(self): - """Make a (shallow) copy of the set.""" - - return self._clone() - - def copy(self): - """Make a (shallow) copy of the set.""" - - return self._clone() - - def union_update(self, other): - """Update the set, adding any elements from other which are not - already in the set. - """ - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - if self is other: # lgtm[py/comparison-using-is] - return - for item in other.items: - self.add(item) - - def intersection_update(self, other): - """Update the set, removing any elements from other which are not - in both sets. - """ - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - if self is other: # lgtm[py/comparison-using-is] - return - # we make a copy of the list so that we can remove items from - # the list without breaking the iterator. - for item in list(self.items): - if item not in other.items: - del self.items[item] - - def difference_update(self, other): - """Update the set, removing any elements from other which are in - the set. - """ - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - if self is other: # lgtm[py/comparison-using-is] - self.items.clear() - else: - for item in other.items: - self.discard(item) - - def symmetric_difference_update(self, other): - """Update the set, retaining only elements unique to both sets.""" - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - if self is other: # lgtm[py/comparison-using-is] - self.items.clear() - else: - overlap = self.intersection(other) - self.union_update(other) - self.difference_update(overlap) - - def union(self, other): - """Return a new set which is the union of ``self`` and ``other``. - - Returns the same Set type as this set. - """ - - obj = self._clone() - obj.union_update(other) - return obj - - def intersection(self, other): - """Return a new set which is the intersection of ``self`` and - ``other``. - - Returns the same Set type as this set. - """ - - obj = self._clone() - obj.intersection_update(other) - return obj - - def difference(self, other): - """Return a new set which ``self`` - ``other``, i.e. the items - in ``self`` which are not also in ``other``. - - Returns the same Set type as this set. - """ - - obj = self._clone() - obj.difference_update(other) - return obj - - def symmetric_difference(self, other): - """Return a new set which (``self`` - ``other``) | (``other`` - - ``self), ie: the items in either ``self`` or ``other`` which - are not contained in their intersection. - - Returns the same Set type as this set. - """ - - obj = self._clone() - obj.symmetric_difference_update(other) - return obj - - def __or__(self, other): - return self.union(other) - - def __and__(self, other): - return self.intersection(other) - - def __add__(self, other): - return self.union(other) - - def __sub__(self, other): - return self.difference(other) - - def __xor__(self, other): - return self.symmetric_difference(other) - - def __ior__(self, other): - self.union_update(other) - return self - - def __iand__(self, other): - self.intersection_update(other) - return self - - def __iadd__(self, other): - self.union_update(other) - return self - - def __isub__(self, other): - self.difference_update(other) - return self - - def __ixor__(self, other): - self.symmetric_difference_update(other) - return self - - def update(self, other): - """Update the set, adding any elements from other which are not - already in the set. - - *other*, the collection of items with which to update the set, which - may be any iterable type. - """ - - for item in other: - self.add(item) - - def clear(self): - """Make the set empty.""" - self.items.clear() - - def __eq__(self, other): - return self.items == other.items - - def __ne__(self, other): - return not self.__eq__(other) - - def __len__(self): - return len(self.items) - - def __iter__(self): - return iter(self.items) - - def __getitem__(self, i): - if isinstance(i, slice): - return list(itertools.islice(self.items, i.start, i.stop, i.step)) - else: - return next(itertools.islice(self.items, i, i + 1)) - - def __delitem__(self, i): - if isinstance(i, slice): - for elt in list(self[i]): - del self.items[elt] - else: - del self.items[self[i]] - - def issubset(self, other): - """Is this set a subset of *other*? - - Returns a ``bool``. - """ - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - for item in self.items: - if item not in other.items: - return False - return True - - def issuperset(self, other): - """Is this set a superset of *other*? - - Returns a ``bool``. - """ - - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - for item in other.items: - if item not in self.items: - return False - return True - - def isdisjoint(self, other): - if not isinstance(other, Set): - raise ValueError("other must be a Set instance") - for item in other.items: - if item in self.items: - return False - return True diff --git a/backend/venv39/lib/python3.9/site-packages/dns/tokenizer.py b/backend/venv39/lib/python3.9/site-packages/dns/tokenizer.py deleted file mode 100644 index ab205bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/tokenizer.py +++ /dev/null @@ -1,708 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""Tokenize DNS zone file format""" - -import io -import sys -from typing import Any, List, Optional, Tuple - -import dns.exception -import dns.name -import dns.ttl - -_DELIMITERS = {" ", "\t", "\n", ";", "(", ")", '"'} -_QUOTING_DELIMITERS = {'"'} - -EOF = 0 -EOL = 1 -WHITESPACE = 2 -IDENTIFIER = 3 -QUOTED_STRING = 4 -COMMENT = 5 -DELIMITER = 6 - - -class UngetBufferFull(dns.exception.DNSException): - """An attempt was made to unget a token when the unget buffer was full.""" - - -class Token: - """A DNS zone file format token. - - ttype: The token type - value: The token value - has_escape: Does the token value contain escapes? - """ - - def __init__( - self, - ttype: int, - value: Any = "", - has_escape: bool = False, - comment: Optional[str] = None, - ): - """Initialize a token instance.""" - - self.ttype = ttype - self.value = value - self.has_escape = has_escape - self.comment = comment - - def is_eof(self) -> bool: - return self.ttype == EOF - - def is_eol(self) -> bool: - return self.ttype == EOL - - def is_whitespace(self) -> bool: - return self.ttype == WHITESPACE - - def is_identifier(self) -> bool: - return self.ttype == IDENTIFIER - - def is_quoted_string(self) -> bool: - return self.ttype == QUOTED_STRING - - def is_comment(self) -> bool: - return self.ttype == COMMENT - - def is_delimiter(self) -> bool: # pragma: no cover (we don't return delimiters yet) - return self.ttype == DELIMITER - - def is_eol_or_eof(self) -> bool: - return self.ttype == EOL or self.ttype == EOF - - def __eq__(self, other): - if not isinstance(other, Token): - return False - return self.ttype == other.ttype and self.value == other.value - - def __ne__(self, other): - if not isinstance(other, Token): - return True - return self.ttype != other.ttype or self.value != other.value - - def __str__(self): - return '%d "%s"' % (self.ttype, self.value) - - def unescape(self) -> "Token": - if not self.has_escape: - return self - unescaped = "" - l = len(self.value) - i = 0 - while i < l: - c = self.value[i] - i += 1 - if c == "\\": - if i >= l: # pragma: no cover (can't happen via get()) - raise dns.exception.UnexpectedEnd - c = self.value[i] - i += 1 - if c.isdigit(): - if i >= l: - raise dns.exception.UnexpectedEnd - c2 = self.value[i] - i += 1 - if i >= l: - raise dns.exception.UnexpectedEnd - c3 = self.value[i] - i += 1 - if not (c2.isdigit() and c3.isdigit()): - raise dns.exception.SyntaxError - codepoint = int(c) * 100 + int(c2) * 10 + int(c3) - if codepoint > 255: - raise dns.exception.SyntaxError - c = chr(codepoint) - unescaped += c - return Token(self.ttype, unescaped) - - def unescape_to_bytes(self) -> "Token": - # We used to use unescape() for TXT-like records, but this - # caused problems as we'd process DNS escapes into Unicode code - # points instead of byte values, and then a to_text() of the - # processed data would not equal the original input. For - # example, \226 in the TXT record would have a to_text() of - # \195\162 because we applied UTF-8 encoding to Unicode code - # point 226. - # - # We now apply escapes while converting directly to bytes, - # avoiding this double encoding. - # - # This code also handles cases where the unicode input has - # non-ASCII code-points in it by converting it to UTF-8. TXT - # records aren't defined for Unicode, but this is the best we - # can do to preserve meaning. For example, - # - # foo\u200bbar - # - # (where \u200b is Unicode code point 0x200b) will be treated - # as if the input had been the UTF-8 encoding of that string, - # namely: - # - # foo\226\128\139bar - # - unescaped = b"" - l = len(self.value) - i = 0 - while i < l: - c = self.value[i] - i += 1 - if c == "\\": - if i >= l: # pragma: no cover (can't happen via get()) - raise dns.exception.UnexpectedEnd - c = self.value[i] - i += 1 - if c.isdigit(): - if i >= l: - raise dns.exception.UnexpectedEnd - c2 = self.value[i] - i += 1 - if i >= l: - raise dns.exception.UnexpectedEnd - c3 = self.value[i] - i += 1 - if not (c2.isdigit() and c3.isdigit()): - raise dns.exception.SyntaxError - codepoint = int(c) * 100 + int(c2) * 10 + int(c3) - if codepoint > 255: - raise dns.exception.SyntaxError - unescaped += b"%c" % (codepoint) - else: - # Note that as mentioned above, if c is a Unicode - # code point outside of the ASCII range, then this - # += is converting that code point to its UTF-8 - # encoding and appending multiple bytes to - # unescaped. - unescaped += c.encode() - else: - unescaped += c.encode() - return Token(self.ttype, bytes(unescaped)) - - -class Tokenizer: - """A DNS zone file format tokenizer. - - A token object is basically a (type, value) tuple. The valid - types are EOF, EOL, WHITESPACE, IDENTIFIER, QUOTED_STRING, - COMMENT, and DELIMITER. - - file: The file to tokenize - - ungotten_char: The most recently ungotten character, or None. - - ungotten_token: The most recently ungotten token, or None. - - multiline: The current multiline level. This value is increased - by one every time a '(' delimiter is read, and decreased by one every time - a ')' delimiter is read. - - quoting: This variable is true if the tokenizer is currently - reading a quoted string. - - eof: This variable is true if the tokenizer has encountered EOF. - - delimiters: The current delimiter dictionary. - - line_number: The current line number - - filename: A filename that will be returned by the where() method. - - idna_codec: A dns.name.IDNACodec, specifies the IDNA - encoder/decoder. If None, the default IDNA 2003 - encoder/decoder is used. - """ - - def __init__( - self, - f: Any = sys.stdin, - filename: Optional[str] = None, - idna_codec: Optional[dns.name.IDNACodec] = None, - ): - """Initialize a tokenizer instance. - - f: The file to tokenize. The default is sys.stdin. - This parameter may also be a string, in which case the tokenizer - will take its input from the contents of the string. - - filename: the name of the filename that the where() method - will return. - - idna_codec: A dns.name.IDNACodec, specifies the IDNA - encoder/decoder. If None, the default IDNA 2003 - encoder/decoder is used. - """ - - if isinstance(f, str): - f = io.StringIO(f) - if filename is None: - filename = "" - elif isinstance(f, bytes): - f = io.StringIO(f.decode()) - if filename is None: - filename = "" - else: - if filename is None: - if f is sys.stdin: - filename = "" - else: - filename = "" - self.file = f - self.ungotten_char: Optional[str] = None - self.ungotten_token: Optional[Token] = None - self.multiline = 0 - self.quoting = False - self.eof = False - self.delimiters = _DELIMITERS - self.line_number = 1 - assert filename is not None - self.filename = filename - if idna_codec is None: - self.idna_codec: dns.name.IDNACodec = dns.name.IDNA_2003 - else: - self.idna_codec = idna_codec - - def _get_char(self) -> str: - """Read a character from input.""" - - if self.ungotten_char is None: - if self.eof: - c = "" - else: - c = self.file.read(1) - if c == "": - self.eof = True - elif c == "\n": - self.line_number += 1 - else: - c = self.ungotten_char - self.ungotten_char = None - return c - - def where(self) -> Tuple[str, int]: - """Return the current location in the input. - - Returns a (string, int) tuple. The first item is the filename of - the input, the second is the current line number. - """ - - return (self.filename, self.line_number) - - def _unget_char(self, c: str) -> None: - """Unget a character. - - The unget buffer for characters is only one character large; it is - an error to try to unget a character when the unget buffer is not - empty. - - c: the character to unget - raises UngetBufferFull: there is already an ungotten char - """ - - if self.ungotten_char is not None: - # this should never happen! - raise UngetBufferFull # pragma: no cover - self.ungotten_char = c - - def skip_whitespace(self) -> int: - """Consume input until a non-whitespace character is encountered. - - The non-whitespace character is then ungotten, and the number of - whitespace characters consumed is returned. - - If the tokenizer is in multiline mode, then newlines are whitespace. - - Returns the number of characters skipped. - """ - - skipped = 0 - while True: - c = self._get_char() - if c != " " and c != "\t": - if (c != "\n") or not self.multiline: - self._unget_char(c) - return skipped - skipped += 1 - - def get(self, want_leading: bool = False, want_comment: bool = False) -> Token: - """Get the next token. - - want_leading: If True, return a WHITESPACE token if the - first character read is whitespace. The default is False. - - want_comment: If True, return a COMMENT token if the - first token read is a comment. The default is False. - - Raises dns.exception.UnexpectedEnd: input ended prematurely - - Raises dns.exception.SyntaxError: input was badly formed - - Returns a Token. - """ - - if self.ungotten_token is not None: - utoken = self.ungotten_token - self.ungotten_token = None - if utoken.is_whitespace(): - if want_leading: - return utoken - elif utoken.is_comment(): - if want_comment: - return utoken - else: - return utoken - skipped = self.skip_whitespace() - if want_leading and skipped > 0: - return Token(WHITESPACE, " ") - token = "" - ttype = IDENTIFIER - has_escape = False - while True: - c = self._get_char() - if c == "" or c in self.delimiters: - if c == "" and self.quoting: - raise dns.exception.UnexpectedEnd - if token == "" and ttype != QUOTED_STRING: - if c == "(": - self.multiline += 1 - self.skip_whitespace() - continue - elif c == ")": - if self.multiline <= 0: - raise dns.exception.SyntaxError - self.multiline -= 1 - self.skip_whitespace() - continue - elif c == '"': - if not self.quoting: - self.quoting = True - self.delimiters = _QUOTING_DELIMITERS - ttype = QUOTED_STRING - continue - else: - self.quoting = False - self.delimiters = _DELIMITERS - self.skip_whitespace() - continue - elif c == "\n": - return Token(EOL, "\n") - elif c == ";": - while 1: - c = self._get_char() - if c == "\n" or c == "": - break - token += c - if want_comment: - self._unget_char(c) - return Token(COMMENT, token) - elif c == "": - if self.multiline: - raise dns.exception.SyntaxError( - "unbalanced parentheses" - ) - return Token(EOF, comment=token) - elif self.multiline: - self.skip_whitespace() - token = "" - continue - else: - return Token(EOL, "\n", comment=token) - else: - # This code exists in case we ever want a - # delimiter to be returned. It never produces - # a token currently. - token = c - ttype = DELIMITER - else: - self._unget_char(c) - break - elif self.quoting and c == "\n": - raise dns.exception.SyntaxError("newline in quoted string") - elif c == "\\": - # - # It's an escape. Put it and the next character into - # the token; it will be checked later for goodness. - # - token += c - has_escape = True - c = self._get_char() - if c == "" or (c == "\n" and not self.quoting): - raise dns.exception.UnexpectedEnd - token += c - if token == "" and ttype != QUOTED_STRING: - if self.multiline: - raise dns.exception.SyntaxError("unbalanced parentheses") - ttype = EOF - return Token(ttype, token, has_escape) - - def unget(self, token: Token) -> None: - """Unget a token. - - The unget buffer for tokens is only one token large; it is - an error to try to unget a token when the unget buffer is not - empty. - - token: the token to unget - - Raises UngetBufferFull: there is already an ungotten token - """ - - if self.ungotten_token is not None: - raise UngetBufferFull - self.ungotten_token = token - - def next(self): - """Return the next item in an iteration. - - Returns a Token. - """ - - token = self.get() - if token.is_eof(): - raise StopIteration - return token - - __next__ = next - - def __iter__(self): - return self - - # Helpers - - def get_int(self, base: int = 10) -> int: - """Read the next token and interpret it as an unsigned integer. - - Raises dns.exception.SyntaxError if not an unsigned integer. - - Returns an int. - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError("expecting an identifier") - if not token.value.isdigit(): - raise dns.exception.SyntaxError("expecting an integer") - return int(token.value, base) - - def get_uint8(self) -> int: - """Read the next token and interpret it as an 8-bit unsigned - integer. - - Raises dns.exception.SyntaxError if not an 8-bit unsigned integer. - - Returns an int. - """ - - value = self.get_int() - if value < 0 or value > 255: - raise dns.exception.SyntaxError( - "%d is not an unsigned 8-bit integer" % value - ) - return value - - def get_uint16(self, base: int = 10) -> int: - """Read the next token and interpret it as a 16-bit unsigned - integer. - - Raises dns.exception.SyntaxError if not a 16-bit unsigned integer. - - Returns an int. - """ - - value = self.get_int(base=base) - if value < 0 or value > 65535: - if base == 8: - raise dns.exception.SyntaxError( - f"{value:o} is not an octal unsigned 16-bit integer" - ) - else: - raise dns.exception.SyntaxError( - "%d is not an unsigned 16-bit integer" % value - ) - return value - - def get_uint32(self, base: int = 10) -> int: - """Read the next token and interpret it as a 32-bit unsigned - integer. - - Raises dns.exception.SyntaxError if not a 32-bit unsigned integer. - - Returns an int. - """ - - value = self.get_int(base=base) - if value < 0 or value > 4294967295: - raise dns.exception.SyntaxError( - "%d is not an unsigned 32-bit integer" % value - ) - return value - - def get_uint48(self, base: int = 10) -> int: - """Read the next token and interpret it as a 48-bit unsigned - integer. - - Raises dns.exception.SyntaxError if not a 48-bit unsigned integer. - - Returns an int. - """ - - value = self.get_int(base=base) - if value < 0 or value > 281474976710655: - raise dns.exception.SyntaxError( - "%d is not an unsigned 48-bit integer" % value - ) - return value - - def get_string(self, max_length: Optional[int] = None) -> str: - """Read the next token and interpret it as a string. - - Raises dns.exception.SyntaxError if not a string. - Raises dns.exception.SyntaxError if token value length - exceeds max_length (if specified). - - Returns a string. - """ - - token = self.get().unescape() - if not (token.is_identifier() or token.is_quoted_string()): - raise dns.exception.SyntaxError("expecting a string") - if max_length and len(token.value) > max_length: - raise dns.exception.SyntaxError("string too long") - return token.value - - def get_identifier(self) -> str: - """Read the next token, which should be an identifier. - - Raises dns.exception.SyntaxError if not an identifier. - - Returns a string. - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError("expecting an identifier") - return token.value - - def get_remaining(self, max_tokens: Optional[int] = None) -> List[Token]: - """Return the remaining tokens on the line, until an EOL or EOF is seen. - - max_tokens: If not None, stop after this number of tokens. - - Returns a list of tokens. - """ - - tokens = [] - while True: - token = self.get() - if token.is_eol_or_eof(): - self.unget(token) - break - tokens.append(token) - if len(tokens) == max_tokens: - break - return tokens - - def concatenate_remaining_identifiers(self, allow_empty: bool = False) -> str: - """Read the remaining tokens on the line, which should be identifiers. - - Raises dns.exception.SyntaxError if there are no remaining tokens, - unless `allow_empty=True` is given. - - Raises dns.exception.SyntaxError if a token is seen that is not an - identifier. - - Returns a string containing a concatenation of the remaining - identifiers. - """ - s = "" - while True: - token = self.get().unescape() - if token.is_eol_or_eof(): - self.unget(token) - break - if not token.is_identifier(): - raise dns.exception.SyntaxError - s += token.value - if not (allow_empty or s): - raise dns.exception.SyntaxError("expecting another identifier") - return s - - def as_name( - self, - token: Token, - origin: Optional[dns.name.Name] = None, - relativize: bool = False, - relativize_to: Optional[dns.name.Name] = None, - ) -> dns.name.Name: - """Try to interpret the token as a DNS name. - - Raises dns.exception.SyntaxError if not a name. - - Returns a dns.name.Name. - """ - if not token.is_identifier(): - raise dns.exception.SyntaxError("expecting an identifier") - name = dns.name.from_text(token.value, origin, self.idna_codec) - return name.choose_relativity(relativize_to or origin, relativize) - - def get_name( - self, - origin: Optional[dns.name.Name] = None, - relativize: bool = False, - relativize_to: Optional[dns.name.Name] = None, - ) -> dns.name.Name: - """Read the next token and interpret it as a DNS name. - - Raises dns.exception.SyntaxError if not a name. - - Returns a dns.name.Name. - """ - - token = self.get() - return self.as_name(token, origin, relativize, relativize_to) - - def get_eol_as_token(self) -> Token: - """Read the next token and raise an exception if it isn't EOL or - EOF. - - Returns a string. - """ - - token = self.get() - if not token.is_eol_or_eof(): - raise dns.exception.SyntaxError( - 'expected EOL or EOF, got %d "%s"' % (token.ttype, token.value) - ) - return token - - def get_eol(self) -> str: - return self.get_eol_as_token().value - - def get_ttl(self) -> int: - """Read the next token and interpret it as a DNS TTL. - - Raises dns.exception.SyntaxError or dns.ttl.BadTTL if not an - identifier or badly formed. - - Returns an int. - """ - - token = self.get().unescape() - if not token.is_identifier(): - raise dns.exception.SyntaxError("expecting an identifier") - return dns.ttl.from_text(token.value) diff --git a/backend/venv39/lib/python3.9/site-packages/dns/transaction.py b/backend/venv39/lib/python3.9/site-packages/dns/transaction.py deleted file mode 100644 index aa2e116..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/transaction.py +++ /dev/null @@ -1,649 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import collections -from typing import Any, Callable, Iterator, List, Optional, Tuple, Union - -import dns.exception -import dns.name -import dns.node -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.rrset -import dns.serial -import dns.ttl - - -class TransactionManager: - def reader(self) -> "Transaction": - """Begin a read-only transaction.""" - raise NotImplementedError # pragma: no cover - - def writer(self, replacement: bool = False) -> "Transaction": - """Begin a writable transaction. - - *replacement*, a ``bool``. If `True`, the content of the - transaction completely replaces any prior content. If False, - the default, then the content of the transaction updates the - existing content. - """ - raise NotImplementedError # pragma: no cover - - def origin_information( - self, - ) -> Tuple[Optional[dns.name.Name], bool, Optional[dns.name.Name]]: - """Returns a tuple - - (absolute_origin, relativize, effective_origin) - - giving the absolute name of the default origin for any - relative domain names, the "effective origin", and whether - names should be relativized. The "effective origin" is the - absolute origin if relativize is False, and the empty name if - relativize is true. (The effective origin is provided even - though it can be computed from the absolute_origin and - relativize setting because it avoids a lot of code - duplication.) - - If the returned names are `None`, then no origin information is - available. - - This information is used by code working with transactions to - allow it to coordinate relativization. The transaction code - itself takes what it gets (i.e. does not change name - relativity). - - """ - raise NotImplementedError # pragma: no cover - - def get_class(self) -> dns.rdataclass.RdataClass: - """The class of the transaction manager.""" - raise NotImplementedError # pragma: no cover - - def from_wire_origin(self) -> Optional[dns.name.Name]: - """Origin to use in from_wire() calls.""" - (absolute_origin, relativize, _) = self.origin_information() - if relativize: - return absolute_origin - else: - return None - - -class DeleteNotExact(dns.exception.DNSException): - """Existing data did not match data specified by an exact delete.""" - - -class ReadOnly(dns.exception.DNSException): - """Tried to write to a read-only transaction.""" - - -class AlreadyEnded(dns.exception.DNSException): - """Tried to use an already-ended transaction.""" - - -def _ensure_immutable_rdataset(rdataset): - if rdataset is None or isinstance(rdataset, dns.rdataset.ImmutableRdataset): - return rdataset - return dns.rdataset.ImmutableRdataset(rdataset) - - -def _ensure_immutable_node(node): - if node is None or node.is_immutable(): - return node - return dns.node.ImmutableNode(node) - - -CheckPutRdatasetType = Callable[ - ["Transaction", dns.name.Name, dns.rdataset.Rdataset], None -] -CheckDeleteRdatasetType = Callable[ - ["Transaction", dns.name.Name, dns.rdatatype.RdataType, dns.rdatatype.RdataType], - None, -] -CheckDeleteNameType = Callable[["Transaction", dns.name.Name], None] - - -class Transaction: - def __init__( - self, - manager: TransactionManager, - replacement: bool = False, - read_only: bool = False, - ): - self.manager = manager - self.replacement = replacement - self.read_only = read_only - self._ended = False - self._check_put_rdataset: List[CheckPutRdatasetType] = [] - self._check_delete_rdataset: List[CheckDeleteRdatasetType] = [] - self._check_delete_name: List[CheckDeleteNameType] = [] - - # - # This is the high level API - # - # Note that we currently use non-immutable types in the return type signature to - # avoid covariance problems, e.g. if the caller has a List[Rdataset], mypy will be - # unhappy if we return an ImmutableRdataset. - - def get( - self, - name: Optional[Union[dns.name.Name, str]], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> dns.rdataset.Rdataset: - """Return the rdataset associated with *name*, *rdtype*, and *covers*, - or `None` if not found. - - Note that the returned rdataset is immutable. - """ - self._check_ended() - if isinstance(name, str): - name = dns.name.from_text(name, None) - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - rdataset = self._get_rdataset(name, rdtype, covers) - return _ensure_immutable_rdataset(rdataset) - - def get_node(self, name: dns.name.Name) -> Optional[dns.node.Node]: - """Return the node at *name*, if any. - - Returns an immutable node or ``None``. - """ - return _ensure_immutable_node(self._get_node(name)) - - def _check_read_only(self) -> None: - if self.read_only: - raise ReadOnly - - def add(self, *args: Any) -> None: - """Add records. - - The arguments may be: - - - rrset - - - name, rdataset... - - - name, ttl, rdata... - """ - self._check_ended() - self._check_read_only() - self._add(False, args) - - def replace(self, *args: Any) -> None: - """Replace the existing rdataset at the name with the specified - rdataset, or add the specified rdataset if there was no existing - rdataset. - - The arguments may be: - - - rrset - - - name, rdataset... - - - name, ttl, rdata... - - Note that if you want to replace the entire node, you should do - a delete of the name followed by one or more calls to add() or - replace(). - """ - self._check_ended() - self._check_read_only() - self._add(True, args) - - def delete(self, *args: Any) -> None: - """Delete records. - - It is not an error if some of the records are not in the existing - set. - - The arguments may be: - - - rrset - - - name - - - name, rdatatype, [covers] - - - name, rdataset... - - - name, rdata... - """ - self._check_ended() - self._check_read_only() - self._delete(False, args) - - def delete_exact(self, *args: Any) -> None: - """Delete records. - - The arguments may be: - - - rrset - - - name - - - name, rdatatype, [covers] - - - name, rdataset... - - - name, rdata... - - Raises dns.transaction.DeleteNotExact if some of the records - are not in the existing set. - - """ - self._check_ended() - self._check_read_only() - self._delete(True, args) - - def name_exists(self, name: Union[dns.name.Name, str]) -> bool: - """Does the specified name exist?""" - self._check_ended() - if isinstance(name, str): - name = dns.name.from_text(name, None) - return self._name_exists(name) - - def update_serial( - self, - value: int = 1, - relative: bool = True, - name: dns.name.Name = dns.name.empty, - ) -> None: - """Update the serial number. - - *value*, an `int`, is an increment if *relative* is `True`, or the - actual value to set if *relative* is `False`. - - Raises `KeyError` if there is no SOA rdataset at *name*. - - Raises `ValueError` if *value* is negative or if the increment is - so large that it would cause the new serial to be less than the - prior value. - """ - self._check_ended() - if value < 0: - raise ValueError("negative update_serial() value") - if isinstance(name, str): - name = dns.name.from_text(name, None) - rdataset = self._get_rdataset(name, dns.rdatatype.SOA, dns.rdatatype.NONE) - if rdataset is None or len(rdataset) == 0: - raise KeyError - if relative: - serial = dns.serial.Serial(rdataset[0].serial) + value - else: - serial = dns.serial.Serial(value) - serial = serial.value # convert back to int - if serial == 0: - serial = 1 - rdata = rdataset[0].replace(serial=serial) - new_rdataset = dns.rdataset.from_rdata(rdataset.ttl, rdata) - self.replace(name, new_rdataset) - - def __iter__(self): - self._check_ended() - return self._iterate_rdatasets() - - def changed(self) -> bool: - """Has this transaction changed anything? - - For read-only transactions, the result is always `False`. - - For writable transactions, the result is `True` if at some time - during the life of the transaction, the content was changed. - """ - self._check_ended() - return self._changed() - - def commit(self) -> None: - """Commit the transaction. - - Normally transactions are used as context managers and commit - or rollback automatically, but it may be done explicitly if needed. - A ``dns.transaction.Ended`` exception will be raised if you try - to use a transaction after it has been committed or rolled back. - - Raises an exception if the commit fails (in which case the transaction - is also rolled back. - """ - self._end(True) - - def rollback(self) -> None: - """Rollback the transaction. - - Normally transactions are used as context managers and commit - or rollback automatically, but it may be done explicitly if needed. - A ``dns.transaction.AlreadyEnded`` exception will be raised if you try - to use a transaction after it has been committed or rolled back. - - Rollback cannot otherwise fail. - """ - self._end(False) - - def check_put_rdataset(self, check: CheckPutRdatasetType) -> None: - """Call *check* before putting (storing) an rdataset. - - The function is called with the transaction, the name, and the rdataset. - - The check function may safely make non-mutating transaction method - calls, but behavior is undefined if mutating transaction methods are - called. The check function should raise an exception if it objects to - the put, and otherwise should return ``None``. - """ - self._check_put_rdataset.append(check) - - def check_delete_rdataset(self, check: CheckDeleteRdatasetType) -> None: - """Call *check* before deleting an rdataset. - - The function is called with the transaction, the name, the rdatatype, - and the covered rdatatype. - - The check function may safely make non-mutating transaction method - calls, but behavior is undefined if mutating transaction methods are - called. The check function should raise an exception if it objects to - the put, and otherwise should return ``None``. - """ - self._check_delete_rdataset.append(check) - - def check_delete_name(self, check: CheckDeleteNameType) -> None: - """Call *check* before putting (storing) an rdataset. - - The function is called with the transaction and the name. - - The check function may safely make non-mutating transaction method - calls, but behavior is undefined if mutating transaction methods are - called. The check function should raise an exception if it objects to - the put, and otherwise should return ``None``. - """ - self._check_delete_name.append(check) - - def iterate_rdatasets( - self, - ) -> Iterator[Tuple[dns.name.Name, dns.rdataset.Rdataset]]: - """Iterate all the rdatasets in the transaction, returning - (`dns.name.Name`, `dns.rdataset.Rdataset`) tuples. - - Note that as is usual with python iterators, adding or removing items - while iterating will invalidate the iterator and may raise `RuntimeError` - or fail to iterate over all entries.""" - self._check_ended() - return self._iterate_rdatasets() - - def iterate_names(self) -> Iterator[dns.name.Name]: - """Iterate all the names in the transaction. - - Note that as is usual with python iterators, adding or removing names - while iterating will invalidate the iterator and may raise `RuntimeError` - or fail to iterate over all entries.""" - self._check_ended() - return self._iterate_names() - - # - # Helper methods - # - - def _raise_if_not_empty(self, method, args): - if len(args) != 0: - raise TypeError(f"extra parameters to {method}") - - def _rdataset_from_args(self, method, deleting, args): - try: - arg = args.popleft() - if isinstance(arg, dns.rrset.RRset): - rdataset = arg.to_rdataset() - elif isinstance(arg, dns.rdataset.Rdataset): - rdataset = arg - else: - if deleting: - ttl = 0 - else: - if isinstance(arg, int): - ttl = arg - if ttl > dns.ttl.MAX_TTL: - raise ValueError(f"{method}: TTL value too big") - else: - raise TypeError(f"{method}: expected a TTL") - arg = args.popleft() - if isinstance(arg, dns.rdata.Rdata): - rdataset = dns.rdataset.from_rdata(ttl, arg) - else: - raise TypeError(f"{method}: expected an Rdata") - return rdataset - except IndexError: - if deleting: - return None - else: - # reraise - raise TypeError(f"{method}: expected more arguments") - - def _add(self, replace, args): - try: - args = collections.deque(args) - if replace: - method = "replace()" - else: - method = "add()" - arg = args.popleft() - if isinstance(arg, str): - arg = dns.name.from_text(arg, None) - if isinstance(arg, dns.name.Name): - name = arg - rdataset = self._rdataset_from_args(method, False, args) - elif isinstance(arg, dns.rrset.RRset): - rrset = arg - name = rrset.name - # rrsets are also rdatasets, but they don't print the - # same and can't be stored in nodes, so convert. - rdataset = rrset.to_rdataset() - else: - raise TypeError( - f"{method} requires a name or RRset as the first argument" - ) - if rdataset.rdclass != self.manager.get_class(): - raise ValueError(f"{method} has objects of wrong RdataClass") - if rdataset.rdtype == dns.rdatatype.SOA: - (_, _, origin) = self._origin_information() - if name != origin: - raise ValueError(f"{method} has non-origin SOA") - self._raise_if_not_empty(method, args) - if not replace: - existing = self._get_rdataset(name, rdataset.rdtype, rdataset.covers) - if existing is not None: - if isinstance(existing, dns.rdataset.ImmutableRdataset): - trds = dns.rdataset.Rdataset( - existing.rdclass, existing.rdtype, existing.covers - ) - trds.update(existing) - existing = trds - rdataset = existing.union(rdataset) - self._checked_put_rdataset(name, rdataset) - except IndexError: - raise TypeError(f"not enough parameters to {method}") - - def _delete(self, exact, args): - try: - args = collections.deque(args) - if exact: - method = "delete_exact()" - else: - method = "delete()" - arg = args.popleft() - if isinstance(arg, str): - arg = dns.name.from_text(arg, None) - if isinstance(arg, dns.name.Name): - name = arg - if len(args) > 0 and ( - isinstance(args[0], int) or isinstance(args[0], str) - ): - # deleting by type and (optionally) covers - rdtype = dns.rdatatype.RdataType.make(args.popleft()) - if len(args) > 0: - covers = dns.rdatatype.RdataType.make(args.popleft()) - else: - covers = dns.rdatatype.NONE - self._raise_if_not_empty(method, args) - existing = self._get_rdataset(name, rdtype, covers) - if existing is None: - if exact: - raise DeleteNotExact(f"{method}: missing rdataset") - else: - self._checked_delete_rdataset(name, rdtype, covers) - return - else: - rdataset = self._rdataset_from_args(method, True, args) - elif isinstance(arg, dns.rrset.RRset): - rdataset = arg # rrsets are also rdatasets - name = rdataset.name - else: - raise TypeError( - f"{method} requires a name or RRset as the first argument" - ) - self._raise_if_not_empty(method, args) - if rdataset: - if rdataset.rdclass != self.manager.get_class(): - raise ValueError(f"{method} has objects of wrong RdataClass") - existing = self._get_rdataset(name, rdataset.rdtype, rdataset.covers) - if existing is not None: - if exact: - intersection = existing.intersection(rdataset) - if intersection != rdataset: - raise DeleteNotExact(f"{method}: missing rdatas") - rdataset = existing.difference(rdataset) - if len(rdataset) == 0: - self._checked_delete_rdataset( - name, rdataset.rdtype, rdataset.covers - ) - else: - self._checked_put_rdataset(name, rdataset) - elif exact: - raise DeleteNotExact(f"{method}: missing rdataset") - else: - if exact and not self._name_exists(name): - raise DeleteNotExact(f"{method}: name not known") - self._checked_delete_name(name) - except IndexError: - raise TypeError(f"not enough parameters to {method}") - - def _check_ended(self): - if self._ended: - raise AlreadyEnded - - def _end(self, commit): - self._check_ended() - try: - self._end_transaction(commit) - finally: - self._ended = True - - def _checked_put_rdataset(self, name, rdataset): - for check in self._check_put_rdataset: - check(self, name, rdataset) - self._put_rdataset(name, rdataset) - - def _checked_delete_rdataset(self, name, rdtype, covers): - for check in self._check_delete_rdataset: - check(self, name, rdtype, covers) - self._delete_rdataset(name, rdtype, covers) - - def _checked_delete_name(self, name): - for check in self._check_delete_name: - check(self, name) - self._delete_name(name) - - # - # Transactions are context managers. - # - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if not self._ended: - if exc_type is None: - self.commit() - else: - self.rollback() - return False - - # - # This is the low level API, which must be implemented by subclasses - # of Transaction. - # - - def _get_rdataset(self, name, rdtype, covers): - """Return the rdataset associated with *name*, *rdtype*, and *covers*, - or `None` if not found. - """ - raise NotImplementedError # pragma: no cover - - def _put_rdataset(self, name, rdataset): - """Store the rdataset.""" - raise NotImplementedError # pragma: no cover - - def _delete_name(self, name): - """Delete all data associated with *name*. - - It is not an error if the name does not exist. - """ - raise NotImplementedError # pragma: no cover - - def _delete_rdataset(self, name, rdtype, covers): - """Delete all data associated with *name*, *rdtype*, and *covers*. - - It is not an error if the rdataset does not exist. - """ - raise NotImplementedError # pragma: no cover - - def _name_exists(self, name): - """Does name exist? - - Returns a bool. - """ - raise NotImplementedError # pragma: no cover - - def _changed(self): - """Has this transaction changed anything?""" - raise NotImplementedError # pragma: no cover - - def _end_transaction(self, commit): - """End the transaction. - - *commit*, a bool. If ``True``, commit the transaction, otherwise - roll it back. - - If committing and the commit fails, then roll back and raise an - exception. - """ - raise NotImplementedError # pragma: no cover - - def _set_origin(self, origin): - """Set the origin. - - This method is called when reading a possibly relativized - source, and an origin setting operation occurs (e.g. $ORIGIN - in a zone file). - """ - raise NotImplementedError # pragma: no cover - - def _iterate_rdatasets(self): - """Return an iterator that yields (name, rdataset) tuples.""" - raise NotImplementedError # pragma: no cover - - def _iterate_names(self): - """Return an iterator that yields a name.""" - raise NotImplementedError # pragma: no cover - - def _get_node(self, name): - """Return the node at *name*, if any. - - Returns a node or ``None``. - """ - raise NotImplementedError # pragma: no cover - - # - # Low-level API with a default implementation, in case a subclass needs - # to override. - # - - def _origin_information(self): - # This is only used by _add() - return self.manager.origin_information() diff --git a/backend/venv39/lib/python3.9/site-packages/dns/tsig.py b/backend/venv39/lib/python3.9/site-packages/dns/tsig.py deleted file mode 100644 index 780852e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/tsig.py +++ /dev/null @@ -1,352 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS TSIG support.""" - -import base64 -import hashlib -import hmac -import struct - -import dns.exception -import dns.name -import dns.rcode -import dns.rdataclass - - -class BadTime(dns.exception.DNSException): - """The current time is not within the TSIG's validity time.""" - - -class BadSignature(dns.exception.DNSException): - """The TSIG signature fails to verify.""" - - -class BadKey(dns.exception.DNSException): - """The TSIG record owner name does not match the key.""" - - -class BadAlgorithm(dns.exception.DNSException): - """The TSIG algorithm does not match the key.""" - - -class PeerError(dns.exception.DNSException): - """Base class for all TSIG errors generated by the remote peer""" - - -class PeerBadKey(PeerError): - """The peer didn't know the key we used""" - - -class PeerBadSignature(PeerError): - """The peer didn't like the signature we sent""" - - -class PeerBadTime(PeerError): - """The peer didn't like the time we sent""" - - -class PeerBadTruncation(PeerError): - """The peer didn't like amount of truncation in the TSIG we sent""" - - -# TSIG Algorithms - -HMAC_MD5 = dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT") -HMAC_SHA1 = dns.name.from_text("hmac-sha1") -HMAC_SHA224 = dns.name.from_text("hmac-sha224") -HMAC_SHA256 = dns.name.from_text("hmac-sha256") -HMAC_SHA256_128 = dns.name.from_text("hmac-sha256-128") -HMAC_SHA384 = dns.name.from_text("hmac-sha384") -HMAC_SHA384_192 = dns.name.from_text("hmac-sha384-192") -HMAC_SHA512 = dns.name.from_text("hmac-sha512") -HMAC_SHA512_256 = dns.name.from_text("hmac-sha512-256") -GSS_TSIG = dns.name.from_text("gss-tsig") - -default_algorithm = HMAC_SHA256 - -mac_sizes = { - HMAC_SHA1: 20, - HMAC_SHA224: 28, - HMAC_SHA256: 32, - HMAC_SHA256_128: 16, - HMAC_SHA384: 48, - HMAC_SHA384_192: 24, - HMAC_SHA512: 64, - HMAC_SHA512_256: 32, - HMAC_MD5: 16, - GSS_TSIG: 128, # This is what we assume to be the worst case! -} - - -class GSSTSig: - """ - GSS-TSIG TSIG implementation. This uses the GSS-API context established - in the TKEY message handshake to sign messages using GSS-API message - integrity codes, per the RFC. - - In order to avoid a direct GSSAPI dependency, the keyring holds a ref - to the GSSAPI object required, rather than the key itself. - """ - - def __init__(self, gssapi_context): - self.gssapi_context = gssapi_context - self.data = b"" - self.name = "gss-tsig" - - def update(self, data): - self.data += data - - def sign(self): - # defer to the GSSAPI function to sign - return self.gssapi_context.get_signature(self.data) - - def verify(self, expected): - try: - # defer to the GSSAPI function to verify - return self.gssapi_context.verify_signature(self.data, expected) - except Exception: - # note the usage of a bare exception - raise BadSignature - - -class GSSTSigAdapter: - def __init__(self, keyring): - self.keyring = keyring - - def __call__(self, message, keyname): - if keyname in self.keyring: - key = self.keyring[keyname] - if isinstance(key, Key) and key.algorithm == GSS_TSIG: - if message: - GSSTSigAdapter.parse_tkey_and_step(key, message, keyname) - return key - else: - return None - - @classmethod - def parse_tkey_and_step(cls, key, message, keyname): - # if the message is a TKEY type, absorb the key material - # into the context using step(); this is used to allow the - # client to complete the GSSAPI negotiation before attempting - # to verify the signed response to a TKEY message exchange - try: - rrset = message.find_rrset( - message.answer, keyname, dns.rdataclass.ANY, dns.rdatatype.TKEY - ) - if rrset: - token = rrset[0].key - gssapi_context = key.secret - return gssapi_context.step(token) - except KeyError: - pass - - -class HMACTSig: - """ - HMAC TSIG implementation. This uses the HMAC python module to handle the - sign/verify operations. - """ - - _hashes = { - HMAC_SHA1: hashlib.sha1, - HMAC_SHA224: hashlib.sha224, - HMAC_SHA256: hashlib.sha256, - HMAC_SHA256_128: (hashlib.sha256, 128), - HMAC_SHA384: hashlib.sha384, - HMAC_SHA384_192: (hashlib.sha384, 192), - HMAC_SHA512: hashlib.sha512, - HMAC_SHA512_256: (hashlib.sha512, 256), - HMAC_MD5: hashlib.md5, - } - - def __init__(self, key, algorithm): - try: - hashinfo = self._hashes[algorithm] - except KeyError: - raise NotImplementedError(f"TSIG algorithm {algorithm} is not supported") - - # create the HMAC context - if isinstance(hashinfo, tuple): - self.hmac_context = hmac.new(key, digestmod=hashinfo[0]) - self.size = hashinfo[1] - else: - self.hmac_context = hmac.new(key, digestmod=hashinfo) - self.size = None - self.name = self.hmac_context.name - if self.size: - self.name += f"-{self.size}" - - def update(self, data): - return self.hmac_context.update(data) - - def sign(self): - # defer to the HMAC digest() function for that digestmod - digest = self.hmac_context.digest() - if self.size: - digest = digest[: (self.size // 8)] - return digest - - def verify(self, expected): - # re-digest and compare the results - mac = self.sign() - if not hmac.compare_digest(mac, expected): - raise BadSignature - - -def _digest(wire, key, rdata, time=None, request_mac=None, ctx=None, multi=None): - """Return a context containing the TSIG rdata for the input parameters - @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object - @raises ValueError: I{other_data} is too long - @raises NotImplementedError: I{algorithm} is not supported - """ - - first = not (ctx and multi) - if first: - ctx = get_context(key) - if request_mac: - ctx.update(struct.pack("!H", len(request_mac))) - ctx.update(request_mac) - ctx.update(struct.pack("!H", rdata.original_id)) - ctx.update(wire[2:]) - if first: - ctx.update(key.name.to_digestable()) - ctx.update(struct.pack("!H", dns.rdataclass.ANY)) - ctx.update(struct.pack("!I", 0)) - if time is None: - time = rdata.time_signed - upper_time = (time >> 32) & 0xFFFF - lower_time = time & 0xFFFFFFFF - time_encoded = struct.pack("!HIH", upper_time, lower_time, rdata.fudge) - other_len = len(rdata.other) - if other_len > 65535: - raise ValueError("TSIG Other Data is > 65535 bytes") - if first: - ctx.update(key.algorithm.to_digestable() + time_encoded) - ctx.update(struct.pack("!HH", rdata.error, other_len) + rdata.other) - else: - ctx.update(time_encoded) - return ctx - - -def _maybe_start_digest(key, mac, multi): - """If this is the first message in a multi-message sequence, - start a new context. - @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object - """ - if multi: - ctx = get_context(key) - ctx.update(struct.pack("!H", len(mac))) - ctx.update(mac) - return ctx - else: - return None - - -def sign(wire, key, rdata, time=None, request_mac=None, ctx=None, multi=False): - """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC TSIG rdata - for the input parameters, the HMAC MAC calculated by applying the - TSIG signature algorithm, and the TSIG digest context. - @rtype: (string, dns.tsig.HMACTSig or dns.tsig.GSSTSig object) - @raises ValueError: I{other_data} is too long - @raises NotImplementedError: I{algorithm} is not supported - """ - - ctx = _digest(wire, key, rdata, time, request_mac, ctx, multi) - mac = ctx.sign() - tsig = rdata.replace(time_signed=time, mac=mac) - - return (tsig, _maybe_start_digest(key, mac, multi)) - - -def validate( - wire, key, owner, rdata, now, request_mac, tsig_start, ctx=None, multi=False -): - """Validate the specified TSIG rdata against the other input parameters. - - @raises FormError: The TSIG is badly formed. - @raises BadTime: There is too much time skew between the client and the - server. - @raises BadSignature: The TSIG signature did not validate - @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object""" - - (adcount,) = struct.unpack("!H", wire[10:12]) - if adcount == 0: - raise dns.exception.FormError - adcount -= 1 - new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start] - if rdata.error != 0: - if rdata.error == dns.rcode.BADSIG: - raise PeerBadSignature - elif rdata.error == dns.rcode.BADKEY: - raise PeerBadKey - elif rdata.error == dns.rcode.BADTIME: - raise PeerBadTime - elif rdata.error == dns.rcode.BADTRUNC: - raise PeerBadTruncation - else: - raise PeerError("unknown TSIG error code %d" % rdata.error) - if abs(rdata.time_signed - now) > rdata.fudge: - raise BadTime - if key.name != owner: - raise BadKey - if key.algorithm != rdata.algorithm: - raise BadAlgorithm - ctx = _digest(new_wire, key, rdata, None, request_mac, ctx, multi) - ctx.verify(rdata.mac) - return _maybe_start_digest(key, rdata.mac, multi) - - -def get_context(key): - """Returns an HMAC context for the specified key. - - @rtype: HMAC context - @raises NotImplementedError: I{algorithm} is not supported - """ - - if key.algorithm == GSS_TSIG: - return GSSTSig(key.secret) - else: - return HMACTSig(key.secret, key.algorithm) - - -class Key: - def __init__(self, name, secret, algorithm=default_algorithm): - if isinstance(name, str): - name = dns.name.from_text(name) - self.name = name - if isinstance(secret, str): - secret = base64.decodebytes(secret.encode()) - self.secret = secret - if isinstance(algorithm, str): - algorithm = dns.name.from_text(algorithm) - self.algorithm = algorithm - - def __eq__(self, other): - return ( - isinstance(other, Key) - and self.name == other.name - and self.secret == other.secret - and self.algorithm == other.algorithm - ) - - def __repr__(self): - r = f" Dict[dns.name.Name, dns.tsig.Key]: - """Convert a dictionary containing (textual DNS name, base64 secret) - pairs into a binary keyring which has (dns.name.Name, bytes) pairs, or - a dictionary containing (textual DNS name, (algorithm, base64 secret)) - pairs into a binary keyring which has (dns.name.Name, dns.tsig.Key) pairs. - @rtype: dict""" - - keyring = {} - for name, value in textring.items(): - kname = dns.name.from_text(name) - if isinstance(value, str): - keyring[kname] = dns.tsig.Key(kname, value).secret - else: - (algorithm, secret) = value - keyring[kname] = dns.tsig.Key(kname, secret, algorithm) - return keyring - - -def to_text(keyring: Dict[dns.name.Name, Any]) -> Dict[str, Any]: - """Convert a dictionary containing (dns.name.Name, dns.tsig.Key) pairs - into a text keyring which has (textual DNS name, (textual algorithm, - base64 secret)) pairs, or a dictionary containing (dns.name.Name, bytes) - pairs into a text keyring which has (textual DNS name, base64 secret) pairs. - @rtype: dict""" - - textring = {} - - def b64encode(secret): - return base64.encodebytes(secret).decode().rstrip() - - for name, key in keyring.items(): - tname = name.to_text() - if isinstance(key, bytes): - textring[tname] = b64encode(key) - else: - if isinstance(key.secret, bytes): - text_secret = b64encode(key.secret) - else: - text_secret = str(key.secret) - - textring[tname] = (key.algorithm.to_text(), text_secret) - return textring diff --git a/backend/venv39/lib/python3.9/site-packages/dns/ttl.py b/backend/venv39/lib/python3.9/site-packages/dns/ttl.py deleted file mode 100644 index b9a99fe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/ttl.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS TTL conversion.""" - -from typing import Union - -import dns.exception - -# Technically TTLs are supposed to be between 0 and 2**31 - 1, with values -# greater than that interpreted as 0, but we do not impose this policy here -# as values > 2**31 - 1 occur in real world data. -# -# We leave it to applications to impose tighter bounds if desired. -MAX_TTL = 2**32 - 1 - - -class BadTTL(dns.exception.SyntaxError): - """DNS TTL value is not well-formed.""" - - -def from_text(text: str) -> int: - """Convert the text form of a TTL to an integer. - - The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. - - *text*, a ``str``, the textual TTL. - - Raises ``dns.ttl.BadTTL`` if the TTL is not well-formed. - - Returns an ``int``. - """ - - if text.isdigit(): - total = int(text) - elif len(text) == 0: - raise BadTTL - else: - total = 0 - current = 0 - need_digit = True - for c in text: - if c.isdigit(): - current *= 10 - current += int(c) - need_digit = False - else: - if need_digit: - raise BadTTL - c = c.lower() - if c == "w": - total += current * 604800 - elif c == "d": - total += current * 86400 - elif c == "h": - total += current * 3600 - elif c == "m": - total += current * 60 - elif c == "s": - total += current - else: - raise BadTTL(f"unknown unit '{c}'") - current = 0 - need_digit = True - if not current == 0: - raise BadTTL("trailing integer") - if total < 0 or total > MAX_TTL: - raise BadTTL("TTL should be between 0 and 2**32 - 1 (inclusive)") - return total - - -def make(value: Union[int, str]) -> int: - if isinstance(value, int): - return value - elif isinstance(value, str): - return dns.ttl.from_text(value) - else: - raise ValueError("cannot convert value to TTL") diff --git a/backend/venv39/lib/python3.9/site-packages/dns/update.py b/backend/venv39/lib/python3.9/site-packages/dns/update.py deleted file mode 100644 index bf1157a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/update.py +++ /dev/null @@ -1,386 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Dynamic Update Support""" - -from typing import Any, List, Optional, Union - -import dns.message -import dns.name -import dns.opcode -import dns.rdata -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.tsig - - -class UpdateSection(dns.enum.IntEnum): - """Update sections""" - - ZONE = 0 - PREREQ = 1 - UPDATE = 2 - ADDITIONAL = 3 - - @classmethod - def _maximum(cls): - return 3 - - -class UpdateMessage(dns.message.Message): # lgtm[py/missing-equals] - # ignore the mypy error here as we mean to use a different enum - _section_enum = UpdateSection # type: ignore - - def __init__( - self, - zone: Optional[Union[dns.name.Name, str]] = None, - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - keyring: Optional[Any] = None, - keyname: Optional[dns.name.Name] = None, - keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm, - id: Optional[int] = None, - ): - """Initialize a new DNS Update object. - - See the documentation of the Message class for a complete - description of the keyring dictionary. - - *zone*, a ``dns.name.Name``, ``str``, or ``None``, the zone - which is being updated. ``None`` should only be used by dnspython's - message constructors, as a zone is required for the convenience - methods like ``add()``, ``replace()``, etc. - - *rdclass*, an ``int`` or ``str``, the class of the zone. - - The *keyring*, *keyname*, and *keyalgorithm* parameters are passed to - ``use_tsig()``; see its documentation for details. - """ - super().__init__(id=id) - self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE) - if isinstance(zone, str): - zone = dns.name.from_text(zone) - self.origin = zone - rdclass = dns.rdataclass.RdataClass.make(rdclass) - self.zone_rdclass = rdclass - if self.origin: - self.find_rrset( - self.zone, - self.origin, - rdclass, - dns.rdatatype.SOA, - create=True, - force_unique=True, - ) - if keyring is not None: - self.use_tsig(keyring, keyname, algorithm=keyalgorithm) - - @property - def zone(self) -> List[dns.rrset.RRset]: - """The zone section.""" - return self.sections[0] - - @zone.setter - def zone(self, v): - self.sections[0] = v - - @property - def prerequisite(self) -> List[dns.rrset.RRset]: - """The prerequisite section.""" - return self.sections[1] - - @prerequisite.setter - def prerequisite(self, v): - self.sections[1] = v - - @property - def update(self) -> List[dns.rrset.RRset]: - """The update section.""" - return self.sections[2] - - @update.setter - def update(self, v): - self.sections[2] = v - - def _add_rr(self, name, ttl, rd, deleting=None, section=None): - """Add a single RR to the update section.""" - - if section is None: - section = self.update - covers = rd.covers() - rrset = self.find_rrset( - section, name, self.zone_rdclass, rd.rdtype, covers, deleting, True, True - ) - rrset.add(rd, ttl) - - def _add(self, replace, section, name, *args): - """Add records. - - *replace* is the replacement mode. If ``False``, - RRs are added to an existing RRset; if ``True``, the RRset - is replaced with the specified contents. The second - argument is the section to add to. The third argument - is always a name. The other arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string... - """ - - if isinstance(name, str): - name = dns.name.from_text(name, None) - if isinstance(args[0], dns.rdataset.Rdataset): - for rds in args: - if replace: - self.delete(name, rds.rdtype) - for rd in rds: - self._add_rr(name, rds.ttl, rd, section=section) - else: - args = list(args) - ttl = int(args.pop(0)) - if isinstance(args[0], dns.rdata.Rdata): - if replace: - self.delete(name, args[0].rdtype) - for rd in args: - self._add_rr(name, ttl, rd, section=section) - else: - rdtype = dns.rdatatype.RdataType.make(args.pop(0)) - if replace: - self.delete(name, rdtype) - for s in args: - rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin) - self._add_rr(name, ttl, rd, section=section) - - def add(self, name: Union[dns.name.Name, str], *args: Any) -> None: - """Add records. - - The first argument is always a name. The other - arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string... - """ - - self._add(False, self.update, name, *args) - - def delete(self, name: Union[dns.name.Name, str], *args: Any) -> None: - """Delete records. - - The first argument is always a name. The other - arguments can be: - - - *empty* - - - rdataset... - - - rdata... - - - rdtype, [string...] - """ - - if isinstance(name, str): - name = dns.name.from_text(name, None) - if len(args) == 0: - self.find_rrset( - self.update, - name, - dns.rdataclass.ANY, - dns.rdatatype.ANY, - dns.rdatatype.NONE, - dns.rdataclass.ANY, - True, - True, - ) - elif isinstance(args[0], dns.rdataset.Rdataset): - for rds in args: - for rd in rds: - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - else: - largs = list(args) - if isinstance(largs[0], dns.rdata.Rdata): - for rd in largs: - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - else: - rdtype = dns.rdatatype.RdataType.make(largs.pop(0)) - if len(largs) == 0: - self.find_rrset( - self.update, - name, - self.zone_rdclass, - rdtype, - dns.rdatatype.NONE, - dns.rdataclass.ANY, - True, - True, - ) - else: - for s in largs: - rd = dns.rdata.from_text( - self.zone_rdclass, - rdtype, - s, # type: ignore[arg-type] - self.origin, - ) - self._add_rr(name, 0, rd, dns.rdataclass.NONE) - - def replace(self, name: Union[dns.name.Name, str], *args: Any) -> None: - """Replace records. - - The first argument is always a name. The other - arguments can be: - - - rdataset... - - - ttl, rdata... - - - ttl, rdtype, string... - - Note that if you want to replace the entire node, you should do - a delete of the name followed by one or more calls to add. - """ - - self._add(True, self.update, name, *args) - - def present(self, name: Union[dns.name.Name, str], *args: Any) -> None: - """Require that an owner name (and optionally an rdata type, - or specific rdataset) exists as a prerequisite to the - execution of the update. - - The first argument is always a name. - The other arguments can be: - - - rdataset... - - - rdata... - - - rdtype, string... - """ - - if isinstance(name, str): - name = dns.name.from_text(name, None) - if len(args) == 0: - self.find_rrset( - self.prerequisite, - name, - dns.rdataclass.ANY, - dns.rdatatype.ANY, - dns.rdatatype.NONE, - None, - True, - True, - ) - elif ( - isinstance(args[0], dns.rdataset.Rdataset) - or isinstance(args[0], dns.rdata.Rdata) - or len(args) > 1 - ): - if not isinstance(args[0], dns.rdataset.Rdataset): - # Add a 0 TTL - largs = list(args) - largs.insert(0, 0) # type: ignore[arg-type] - self._add(False, self.prerequisite, name, *largs) - else: - self._add(False, self.prerequisite, name, *args) - else: - rdtype = dns.rdatatype.RdataType.make(args[0]) - self.find_rrset( - self.prerequisite, - name, - dns.rdataclass.ANY, - rdtype, - dns.rdatatype.NONE, - None, - True, - True, - ) - - def absent( - self, - name: Union[dns.name.Name, str], - rdtype: Optional[Union[dns.rdatatype.RdataType, str]] = None, - ) -> None: - """Require that an owner name (and optionally an rdata type) does - not exist as a prerequisite to the execution of the update.""" - - if isinstance(name, str): - name = dns.name.from_text(name, None) - if rdtype is None: - self.find_rrset( - self.prerequisite, - name, - dns.rdataclass.NONE, - dns.rdatatype.ANY, - dns.rdatatype.NONE, - None, - True, - True, - ) - else: - rdtype = dns.rdatatype.RdataType.make(rdtype) - self.find_rrset( - self.prerequisite, - name, - dns.rdataclass.NONE, - rdtype, - dns.rdatatype.NONE, - None, - True, - True, - ) - - def _get_one_rr_per_rrset(self, value): - # Updates are always one_rr_per_rrset - return True - - def _parse_rr_header(self, section, name, rdclass, rdtype): - deleting = None - empty = False - if section == UpdateSection.ZONE: - if ( - dns.rdataclass.is_metaclass(rdclass) - or rdtype != dns.rdatatype.SOA - or self.zone - ): - raise dns.exception.FormError - else: - if not self.zone: - raise dns.exception.FormError - if rdclass in (dns.rdataclass.ANY, dns.rdataclass.NONE): - deleting = rdclass - rdclass = self.zone[0].rdclass - empty = ( - deleting == dns.rdataclass.ANY or section == UpdateSection.PREREQ - ) - return (rdclass, rdtype, deleting, empty) - - -# backwards compatibility -Update = UpdateMessage - -### BEGIN generated UpdateSection constants - -ZONE = UpdateSection.ZONE -PREREQ = UpdateSection.PREREQ -UPDATE = UpdateSection.UPDATE -ADDITIONAL = UpdateSection.ADDITIONAL - -### END generated UpdateSection constants diff --git a/backend/venv39/lib/python3.9/site-packages/dns/version.py b/backend/venv39/lib/python3.9/site-packages/dns/version.py deleted file mode 100644 index 9ed2ce1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/version.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""dnspython release version information.""" - -#: MAJOR -MAJOR = 2 -#: MINOR -MINOR = 7 -#: MICRO -MICRO = 0 -#: RELEASELEVEL -RELEASELEVEL = 0x0F -#: SERIAL -SERIAL = 0 - -if RELEASELEVEL == 0x0F: # pragma: no cover lgtm[py/unreachable-statement] - #: version - version = "%d.%d.%d" % (MAJOR, MINOR, MICRO) # lgtm[py/unreachable-statement] -elif RELEASELEVEL == 0x00: # pragma: no cover lgtm[py/unreachable-statement] - version = "%d.%d.%ddev%d" % ( - MAJOR, - MINOR, - MICRO, - SERIAL, - ) # lgtm[py/unreachable-statement] -elif RELEASELEVEL == 0x0C: # pragma: no cover lgtm[py/unreachable-statement] - version = "%d.%d.%drc%d" % ( - MAJOR, - MINOR, - MICRO, - SERIAL, - ) # lgtm[py/unreachable-statement] -else: # pragma: no cover lgtm[py/unreachable-statement] - version = "%d.%d.%d%x%d" % ( - MAJOR, - MINOR, - MICRO, - RELEASELEVEL, - SERIAL, - ) # lgtm[py/unreachable-statement] - -#: hexversion -hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | SERIAL diff --git a/backend/venv39/lib/python3.9/site-packages/dns/versioned.py b/backend/venv39/lib/python3.9/site-packages/dns/versioned.py deleted file mode 100644 index fd78e67..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/versioned.py +++ /dev/null @@ -1,318 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -"""DNS Versioned Zones.""" - -import collections -import threading -from typing import Callable, Deque, Optional, Set, Union - -import dns.exception -import dns.immutable -import dns.name -import dns.node -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.rdtypes.ANY.SOA -import dns.zone - - -class UseTransaction(dns.exception.DNSException): - """To alter a versioned zone, use a transaction.""" - - -# Backwards compatibility -Node = dns.zone.VersionedNode -ImmutableNode = dns.zone.ImmutableVersionedNode -Version = dns.zone.Version -WritableVersion = dns.zone.WritableVersion -ImmutableVersion = dns.zone.ImmutableVersion -Transaction = dns.zone.Transaction - - -class Zone(dns.zone.Zone): # lgtm[py/missing-equals] - __slots__ = [ - "_versions", - "_versions_lock", - "_write_txn", - "_write_waiters", - "_write_event", - "_pruning_policy", - "_readers", - ] - - node_factory = Node - - def __init__( - self, - origin: Optional[Union[dns.name.Name, str]], - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - relativize: bool = True, - pruning_policy: Optional[Callable[["Zone", Version], Optional[bool]]] = None, - ): - """Initialize a versioned zone object. - - *origin* is the origin of the zone. It may be a ``dns.name.Name``, - a ``str``, or ``None``. If ``None``, then the zone's origin will - be set by the first ``$ORIGIN`` line in a zone file. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *pruning policy*, a function taking a ``Zone`` and a ``Version`` and returning - a ``bool``, or ``None``. Should the version be pruned? If ``None``, - the default policy, which retains one version is used. - """ - super().__init__(origin, rdclass, relativize) - self._versions: Deque[Version] = collections.deque() - self._version_lock = threading.Lock() - if pruning_policy is None: - self._pruning_policy = self._default_pruning_policy - else: - self._pruning_policy = pruning_policy - self._write_txn: Optional[Transaction] = None - self._write_event: Optional[threading.Event] = None - self._write_waiters: Deque[threading.Event] = collections.deque() - self._readers: Set[Transaction] = set() - self._commit_version_unlocked( - None, WritableVersion(self, replacement=True), origin - ) - - def reader( - self, id: Optional[int] = None, serial: Optional[int] = None - ) -> Transaction: # pylint: disable=arguments-differ - if id is not None and serial is not None: - raise ValueError("cannot specify both id and serial") - with self._version_lock: - if id is not None: - version = None - for v in reversed(self._versions): - if v.id == id: - version = v - break - if version is None: - raise KeyError("version not found") - elif serial is not None: - if self.relativize: - oname = dns.name.empty - else: - assert self.origin is not None - oname = self.origin - version = None - for v in reversed(self._versions): - n = v.nodes.get(oname) - if n: - rds = n.get_rdataset(self.rdclass, dns.rdatatype.SOA) - if rds and rds[0].serial == serial: - version = v - break - if version is None: - raise KeyError("serial not found") - else: - version = self._versions[-1] - txn = Transaction(self, False, version) - self._readers.add(txn) - return txn - - def writer(self, replacement: bool = False) -> Transaction: - event = None - while True: - with self._version_lock: - # Checking event == self._write_event ensures that either - # no one was waiting before we got lucky and found no write - # txn, or we were the one who was waiting and got woken up. - # This prevents "taking cuts" when creating a write txn. - if self._write_txn is None and event == self._write_event: - # Creating the transaction defers version setup - # (i.e. copying the nodes dictionary) until we - # give up the lock, so that we hold the lock as - # short a time as possible. This is why we call - # _setup_version() below. - self._write_txn = Transaction( - self, replacement, make_immutable=True - ) - # give up our exclusive right to make a Transaction - self._write_event = None - break - # Someone else is writing already, so we will have to - # wait, but we want to do the actual wait outside the - # lock. - event = threading.Event() - self._write_waiters.append(event) - # wait (note we gave up the lock!) - # - # We only wake one sleeper at a time, so it's important - # that no event waiter can exit this method (e.g. via - # cancellation) without returning a transaction or waking - # someone else up. - # - # This is not a problem with Threading module threads as - # they cannot be canceled, but could be an issue with trio - # tasks when we do the async version of writer(). - # I.e. we'd need to do something like: - # - # try: - # event.wait() - # except trio.Cancelled: - # with self._version_lock: - # self._maybe_wakeup_one_waiter_unlocked() - # raise - # - event.wait() - # Do the deferred version setup. - self._write_txn._setup_version() - return self._write_txn - - def _maybe_wakeup_one_waiter_unlocked(self): - if len(self._write_waiters) > 0: - self._write_event = self._write_waiters.popleft() - self._write_event.set() - - # pylint: disable=unused-argument - def _default_pruning_policy(self, zone, version): - return True - - # pylint: enable=unused-argument - - def _prune_versions_unlocked(self): - assert len(self._versions) > 0 - # Don't ever prune a version greater than or equal to one that - # a reader has open. This pins versions in memory while the - # reader is open, and importantly lets the reader open a txn on - # a successor version (e.g. if generating an IXFR). - # - # Note our definition of least_kept also ensures we do not try to - # delete the greatest version. - if len(self._readers) > 0: - least_kept = min(txn.version.id for txn in self._readers) - else: - least_kept = self._versions[-1].id - while self._versions[0].id < least_kept and self._pruning_policy( - self, self._versions[0] - ): - self._versions.popleft() - - def set_max_versions(self, max_versions: Optional[int]) -> None: - """Set a pruning policy that retains up to the specified number - of versions - """ - if max_versions is not None and max_versions < 1: - raise ValueError("max versions must be at least 1") - if max_versions is None: - - def policy(zone, _): # pylint: disable=unused-argument - return False - - else: - - def policy(zone, _): - return len(zone._versions) > max_versions - - self.set_pruning_policy(policy) - - def set_pruning_policy( - self, policy: Optional[Callable[["Zone", Version], Optional[bool]]] - ) -> None: - """Set the pruning policy for the zone. - - The *policy* function takes a `Version` and returns `True` if - the version should be pruned, and `False` otherwise. `None` - may also be specified for policy, in which case the default policy - is used. - - Pruning checking proceeds from the least version and the first - time the function returns `False`, the checking stops. I.e. the - retained versions are always a consecutive sequence. - """ - if policy is None: - policy = self._default_pruning_policy - with self._version_lock: - self._pruning_policy = policy - self._prune_versions_unlocked() - - def _end_read(self, txn): - with self._version_lock: - self._readers.remove(txn) - self._prune_versions_unlocked() - - def _end_write_unlocked(self, txn): - assert self._write_txn == txn - self._write_txn = None - self._maybe_wakeup_one_waiter_unlocked() - - def _end_write(self, txn): - with self._version_lock: - self._end_write_unlocked(txn) - - def _commit_version_unlocked(self, txn, version, origin): - self._versions.append(version) - self._prune_versions_unlocked() - self.nodes = version.nodes - if self.origin is None: - self.origin = origin - # txn can be None in __init__ when we make the empty version. - if txn is not None: - self._end_write_unlocked(txn) - - def _commit_version(self, txn, version, origin): - with self._version_lock: - self._commit_version_unlocked(txn, version, origin) - - def _get_next_version_id(self): - if len(self._versions) > 0: - id = self._versions[-1].id + 1 - else: - id = 1 - return id - - def find_node( - self, name: Union[dns.name.Name, str], create: bool = False - ) -> dns.node.Node: - if create: - raise UseTransaction - return super().find_node(name) - - def delete_node(self, name: Union[dns.name.Name, str]) -> None: - raise UseTransaction - - def find_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - create: bool = False, - ) -> dns.rdataset.Rdataset: - if create: - raise UseTransaction - rdataset = super().find_rdataset(name, rdtype, covers) - return dns.rdataset.ImmutableRdataset(rdataset) - - def get_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - create: bool = False, - ) -> Optional[dns.rdataset.Rdataset]: - if create: - raise UseTransaction - rdataset = super().get_rdataset(name, rdtype, covers) - if rdataset is not None: - return dns.rdataset.ImmutableRdataset(rdataset) - else: - return None - - def delete_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> None: - raise UseTransaction - - def replace_rdataset( - self, name: Union[dns.name.Name, str], replacement: dns.rdataset.Rdataset - ) -> None: - raise UseTransaction diff --git a/backend/venv39/lib/python3.9/site-packages/dns/win32util.py b/backend/venv39/lib/python3.9/site-packages/dns/win32util.py deleted file mode 100644 index 9ed3f11..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/win32util.py +++ /dev/null @@ -1,242 +0,0 @@ -import sys - -import dns._features - -if sys.platform == "win32": - from typing import Any - - import dns.name - - _prefer_wmi = True - - import winreg # pylint: disable=import-error - - # Keep pylint quiet on non-windows. - try: - _ = WindowsError # pylint: disable=used-before-assignment - except NameError: - WindowsError = Exception - - if dns._features.have("wmi"): - import threading - - import pythoncom # pylint: disable=import-error - import wmi # pylint: disable=import-error - - _have_wmi = True - else: - _have_wmi = False - - def _config_domain(domain): - # Sometimes DHCP servers add a '.' prefix to the default domain, and - # Windows just stores such values in the registry (see #687). - # Check for this and fix it. - if domain.startswith("."): - domain = domain[1:] - return dns.name.from_text(domain) - - class DnsInfo: - def __init__(self): - self.domain = None - self.nameservers = [] - self.search = [] - - if _have_wmi: - - class _WMIGetter(threading.Thread): - # pylint: disable=possibly-used-before-assignment - def __init__(self): - super().__init__() - self.info = DnsInfo() - - def run(self): - pythoncom.CoInitialize() - try: - system = wmi.WMI() - for interface in system.Win32_NetworkAdapterConfiguration(): - if interface.IPEnabled and interface.DNSServerSearchOrder: - self.info.nameservers = list(interface.DNSServerSearchOrder) - if interface.DNSDomain: - self.info.domain = _config_domain(interface.DNSDomain) - if interface.DNSDomainSuffixSearchOrder: - self.info.search = [ - _config_domain(x) - for x in interface.DNSDomainSuffixSearchOrder - ] - break - finally: - pythoncom.CoUninitialize() - - def get(self): - # We always run in a separate thread to avoid any issues with - # the COM threading model. - self.start() - self.join() - return self.info - - else: - - class _WMIGetter: # type: ignore - pass - - class _RegistryGetter: - def __init__(self): - self.info = DnsInfo() - - def _split(self, text): - # The windows registry has used both " " and "," as a delimiter, and while - # it is currently using "," in Windows 10 and later, updates can seemingly - # leave a space in too, e.g. "a, b". So we just convert all commas to - # spaces, and use split() in its default configuration, which splits on - # all whitespace and ignores empty strings. - return text.replace(",", " ").split() - - def _config_nameservers(self, nameservers): - for ns in self._split(nameservers): - if ns not in self.info.nameservers: - self.info.nameservers.append(ns) - - def _config_search(self, search): - for s in self._split(search): - s = _config_domain(s) - if s not in self.info.search: - self.info.search.append(s) - - def _config_fromkey(self, key, always_try_domain): - try: - servers, _ = winreg.QueryValueEx(key, "NameServer") - except WindowsError: - servers = None - if servers: - self._config_nameservers(servers) - if servers or always_try_domain: - try: - dom, _ = winreg.QueryValueEx(key, "Domain") - if dom: - self.info.domain = _config_domain(dom) - except WindowsError: - pass - else: - try: - servers, _ = winreg.QueryValueEx(key, "DhcpNameServer") - except WindowsError: - servers = None - if servers: - self._config_nameservers(servers) - try: - dom, _ = winreg.QueryValueEx(key, "DhcpDomain") - if dom: - self.info.domain = _config_domain(dom) - except WindowsError: - pass - try: - search, _ = winreg.QueryValueEx(key, "SearchList") - except WindowsError: - search = None - if search is None: - try: - search, _ = winreg.QueryValueEx(key, "DhcpSearchList") - except WindowsError: - search = None - if search: - self._config_search(search) - - def _is_nic_enabled(self, lm, guid): - # Look in the Windows Registry to determine whether the network - # interface corresponding to the given guid is enabled. - # - # (Code contributed by Paul Marks, thanks!) - # - try: - # This hard-coded location seems to be consistent, at least - # from Windows 2000 through Vista. - connection_key = winreg.OpenKey( - lm, - r"SYSTEM\CurrentControlSet\Control\Network" - r"\{4D36E972-E325-11CE-BFC1-08002BE10318}" - rf"\{guid}\Connection", - ) - - try: - # The PnpInstanceID points to a key inside Enum - (pnp_id, ttype) = winreg.QueryValueEx( - connection_key, "PnpInstanceID" - ) - - if ttype != winreg.REG_SZ: - raise ValueError # pragma: no cover - - device_key = winreg.OpenKey( - lm, rf"SYSTEM\CurrentControlSet\Enum\{pnp_id}" - ) - - try: - # Get ConfigFlags for this device - (flags, ttype) = winreg.QueryValueEx(device_key, "ConfigFlags") - - if ttype != winreg.REG_DWORD: - raise ValueError # pragma: no cover - - # Based on experimentation, bit 0x1 indicates that the - # device is disabled. - # - # XXXRTH I suspect we really want to & with 0x03 so - # that CONFIGFLAGS_REMOVED devices are also ignored, - # but we're shifting to WMI as ConfigFlags is not - # supposed to be used. - return not flags & 0x1 - - finally: - device_key.Close() - finally: - connection_key.Close() - except Exception: # pragma: no cover - return False - - def get(self): - """Extract resolver configuration from the Windows registry.""" - - lm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - try: - tcp_params = winreg.OpenKey( - lm, r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" - ) - try: - self._config_fromkey(tcp_params, True) - finally: - tcp_params.Close() - interfaces = winreg.OpenKey( - lm, - r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces", - ) - try: - i = 0 - while True: - try: - guid = winreg.EnumKey(interfaces, i) - i += 1 - key = winreg.OpenKey(interfaces, guid) - try: - if not self._is_nic_enabled(lm, guid): - continue - self._config_fromkey(key, False) - finally: - key.Close() - except OSError: - break - finally: - interfaces.Close() - finally: - lm.Close() - return self.info - - _getter_class: Any - if _have_wmi and _prefer_wmi: - _getter_class = _WMIGetter - else: - _getter_class = _RegistryGetter - - def get_dns_info(): - """Extract resolver configuration.""" - getter = _getter_class() - return getter.get() diff --git a/backend/venv39/lib/python3.9/site-packages/dns/wire.py b/backend/venv39/lib/python3.9/site-packages/dns/wire.py deleted file mode 100644 index 9f9b157..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/wire.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -import contextlib -import struct -from typing import Iterator, Optional, Tuple - -import dns.exception -import dns.name - - -class Parser: - def __init__(self, wire: bytes, current: int = 0): - self.wire = wire - self.current = 0 - self.end = len(self.wire) - if current: - self.seek(current) - self.furthest = current - - def remaining(self) -> int: - return self.end - self.current - - def get_bytes(self, size: int) -> bytes: - assert size >= 0 - if size > self.remaining(): - raise dns.exception.FormError - output = self.wire[self.current : self.current + size] - self.current += size - self.furthest = max(self.furthest, self.current) - return output - - def get_counted_bytes(self, length_size: int = 1) -> bytes: - length = int.from_bytes(self.get_bytes(length_size), "big") - return self.get_bytes(length) - - def get_remaining(self) -> bytes: - return self.get_bytes(self.remaining()) - - def get_uint8(self) -> int: - return struct.unpack("!B", self.get_bytes(1))[0] - - def get_uint16(self) -> int: - return struct.unpack("!H", self.get_bytes(2))[0] - - def get_uint32(self) -> int: - return struct.unpack("!I", self.get_bytes(4))[0] - - def get_uint48(self) -> int: - return int.from_bytes(self.get_bytes(6), "big") - - def get_struct(self, format: str) -> Tuple: - return struct.unpack(format, self.get_bytes(struct.calcsize(format))) - - def get_name(self, origin: Optional["dns.name.Name"] = None) -> "dns.name.Name": - name = dns.name.from_wire_parser(self) - if origin: - name = name.relativize(origin) - return name - - def seek(self, where: int) -> None: - # Note that seeking to the end is OK! (If you try to read - # after such a seek, you'll get an exception as expected.) - if where < 0 or where > self.end: - raise dns.exception.FormError - self.current = where - - @contextlib.contextmanager - def restrict_to(self, size: int) -> Iterator: - assert size >= 0 - if size > self.remaining(): - raise dns.exception.FormError - saved_end = self.end - try: - self.end = self.current + size - yield - # We make this check here and not in the finally as we - # don't want to raise if we're already raising for some - # other reason. - if self.current != self.end: - raise dns.exception.FormError - finally: - self.end = saved_end - - @contextlib.contextmanager - def restore_furthest(self) -> Iterator: - try: - yield None - finally: - self.current = self.furthest diff --git a/backend/venv39/lib/python3.9/site-packages/dns/xfr.py b/backend/venv39/lib/python3.9/site-packages/dns/xfr.py deleted file mode 100644 index 520aa32..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/xfr.py +++ /dev/null @@ -1,343 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2017 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from typing import Any, List, Optional, Tuple, Union - -import dns.exception -import dns.message -import dns.name -import dns.rcode -import dns.rdataset -import dns.rdatatype -import dns.serial -import dns.transaction -import dns.tsig -import dns.zone - - -class TransferError(dns.exception.DNSException): - """A zone transfer response got a non-zero rcode.""" - - def __init__(self, rcode): - message = f"Zone transfer error: {dns.rcode.to_text(rcode)}" - super().__init__(message) - self.rcode = rcode - - -class SerialWentBackwards(dns.exception.FormError): - """The current serial number is less than the serial we know.""" - - -class UseTCP(dns.exception.DNSException): - """This IXFR cannot be completed with UDP.""" - - -class Inbound: - """ - State machine for zone transfers. - """ - - def __init__( - self, - txn_manager: dns.transaction.TransactionManager, - rdtype: dns.rdatatype.RdataType = dns.rdatatype.AXFR, - serial: Optional[int] = None, - is_udp: bool = False, - ): - """Initialize an inbound zone transfer. - - *txn_manager* is a :py:class:`dns.transaction.TransactionManager`. - - *rdtype* can be `dns.rdatatype.AXFR` or `dns.rdatatype.IXFR` - - *serial* is the base serial number for IXFRs, and is required in - that case. - - *is_udp*, a ``bool`` indidicates if UDP is being used for this - XFR. - """ - self.txn_manager = txn_manager - self.txn: Optional[dns.transaction.Transaction] = None - self.rdtype = rdtype - if rdtype == dns.rdatatype.IXFR: - if serial is None: - raise ValueError("a starting serial must be supplied for IXFRs") - elif is_udp: - raise ValueError("is_udp specified for AXFR") - self.serial = serial - self.is_udp = is_udp - (_, _, self.origin) = txn_manager.origin_information() - self.soa_rdataset: Optional[dns.rdataset.Rdataset] = None - self.done = False - self.expecting_SOA = False - self.delete_mode = False - - def process_message(self, message: dns.message.Message) -> bool: - """Process one message in the transfer. - - The message should have the same relativization as was specified when - the `dns.xfr.Inbound` was created. The message should also have been - created with `one_rr_per_rrset=True` because order matters. - - Returns `True` if the transfer is complete, and `False` otherwise. - """ - if self.txn is None: - replacement = self.rdtype == dns.rdatatype.AXFR - self.txn = self.txn_manager.writer(replacement) - rcode = message.rcode() - if rcode != dns.rcode.NOERROR: - raise TransferError(rcode) - # - # We don't require a question section, but if it is present is - # should be correct. - # - if len(message.question) > 0: - if message.question[0].name != self.origin: - raise dns.exception.FormError("wrong question name") - if message.question[0].rdtype != self.rdtype: - raise dns.exception.FormError("wrong question rdatatype") - answer_index = 0 - if self.soa_rdataset is None: - # - # This is the first message. We're expecting an SOA at - # the origin. - # - if not message.answer or message.answer[0].name != self.origin: - raise dns.exception.FormError("No answer or RRset not for zone origin") - rrset = message.answer[0] - rdataset = rrset - if rdataset.rdtype != dns.rdatatype.SOA: - raise dns.exception.FormError("first RRset is not an SOA") - answer_index = 1 - self.soa_rdataset = rdataset.copy() - if self.rdtype == dns.rdatatype.IXFR: - if self.soa_rdataset[0].serial == self.serial: - # - # We're already up-to-date. - # - self.done = True - elif dns.serial.Serial(self.soa_rdataset[0].serial) < self.serial: - # It went backwards! - raise SerialWentBackwards - else: - if self.is_udp and len(message.answer[answer_index:]) == 0: - # - # There are no more records, so this is the - # "truncated" response. Say to use TCP - # - raise UseTCP - # - # Note we're expecting another SOA so we can detect - # if this IXFR response is an AXFR-style response. - # - self.expecting_SOA = True - # - # Process the answer section (other than the initial SOA in - # the first message). - # - for rrset in message.answer[answer_index:]: - name = rrset.name - rdataset = rrset - if self.done: - raise dns.exception.FormError("answers after final SOA") - assert self.txn is not None # for mypy - if rdataset.rdtype == dns.rdatatype.SOA and name == self.origin: - # - # Every time we see an origin SOA delete_mode inverts - # - if self.rdtype == dns.rdatatype.IXFR: - self.delete_mode = not self.delete_mode - # - # If this SOA Rdataset is equal to the first we saw - # then we're finished. If this is an IXFR we also - # check that we're seeing the record in the expected - # part of the response. - # - if rdataset == self.soa_rdataset and ( - self.rdtype == dns.rdatatype.AXFR - or (self.rdtype == dns.rdatatype.IXFR and self.delete_mode) - ): - # - # This is the final SOA - # - if self.expecting_SOA: - # We got an empty IXFR sequence! - raise dns.exception.FormError("empty IXFR sequence") - if ( - self.rdtype == dns.rdatatype.IXFR - and self.serial != rdataset[0].serial - ): - raise dns.exception.FormError("unexpected end of IXFR sequence") - self.txn.replace(name, rdataset) - self.txn.commit() - self.txn = None - self.done = True - else: - # - # This is not the final SOA - # - self.expecting_SOA = False - if self.rdtype == dns.rdatatype.IXFR: - if self.delete_mode: - # This is the start of an IXFR deletion set - if rdataset[0].serial != self.serial: - raise dns.exception.FormError( - "IXFR base serial mismatch" - ) - else: - # This is the start of an IXFR addition set - self.serial = rdataset[0].serial - self.txn.replace(name, rdataset) - else: - # We saw a non-final SOA for the origin in an AXFR. - raise dns.exception.FormError("unexpected origin SOA in AXFR") - continue - if self.expecting_SOA: - # - # We made an IXFR request and are expecting another - # SOA RR, but saw something else, so this must be an - # AXFR response. - # - self.rdtype = dns.rdatatype.AXFR - self.expecting_SOA = False - self.delete_mode = False - self.txn.rollback() - self.txn = self.txn_manager.writer(True) - # - # Note we are falling through into the code below - # so whatever rdataset this was gets written. - # - # Add or remove the data - if self.delete_mode: - self.txn.delete_exact(name, rdataset) - else: - self.txn.add(name, rdataset) - if self.is_udp and not self.done: - # - # This is a UDP IXFR and we didn't get to done, and we didn't - # get the proper "truncated" response - # - raise dns.exception.FormError("unexpected end of UDP IXFR") - return self.done - - # - # Inbounds are context managers. - # - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if self.txn: - self.txn.rollback() - return False - - -def make_query( - txn_manager: dns.transaction.TransactionManager, - serial: Optional[int] = 0, - use_edns: Optional[Union[int, bool]] = None, - ednsflags: Optional[int] = None, - payload: Optional[int] = None, - request_payload: Optional[int] = None, - options: Optional[List[dns.edns.Option]] = None, - keyring: Any = None, - keyname: Optional[dns.name.Name] = None, - keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm, -) -> Tuple[dns.message.QueryMessage, Optional[int]]: - """Make an AXFR or IXFR query. - - *txn_manager* is a ``dns.transaction.TransactionManager``, typically a - ``dns.zone.Zone``. - - *serial* is an ``int`` or ``None``. If 0, then IXFR will be - attempted using the most recent serial number from the - *txn_manager*; it is the caller's responsibility to ensure there - are no write transactions active that could invalidate the - retrieved serial. If a serial cannot be determined, AXFR will be - forced. Other integer values are the starting serial to use. - ``None`` forces an AXFR. - - Please see the documentation for :py:func:`dns.message.make_query` and - :py:func:`dns.message.Message.use_tsig` for details on the other parameters - to this function. - - Returns a `(query, serial)` tuple. - """ - (zone_origin, _, origin) = txn_manager.origin_information() - if zone_origin is None: - raise ValueError("no zone origin") - if serial is None: - rdtype = dns.rdatatype.AXFR - elif not isinstance(serial, int): - raise ValueError("serial is not an integer") - elif serial == 0: - with txn_manager.reader() as txn: - rdataset = txn.get(origin, "SOA") - if rdataset: - serial = rdataset[0].serial - rdtype = dns.rdatatype.IXFR - else: - serial = None - rdtype = dns.rdatatype.AXFR - elif serial > 0 and serial < 4294967296: - rdtype = dns.rdatatype.IXFR - else: - raise ValueError("serial out-of-range") - rdclass = txn_manager.get_class() - q = dns.message.make_query( - zone_origin, - rdtype, - rdclass, - use_edns, - False, - ednsflags, - payload, - request_payload, - options, - ) - if serial is not None: - rdata = dns.rdata.from_text(rdclass, "SOA", f". . {serial} 0 0 0 0") - rrset = q.find_rrset( - q.authority, zone_origin, rdclass, dns.rdatatype.SOA, create=True - ) - rrset.add(rdata, 0) - if keyring is not None: - q.use_tsig(keyring, keyname, algorithm=keyalgorithm) - return (q, serial) - - -def extract_serial_from_query(query: dns.message.Message) -> Optional[int]: - """Extract the SOA serial number from query if it is an IXFR and return - it, otherwise return None. - - *query* is a dns.message.QueryMessage that is an IXFR or AXFR request. - - Raises if the query is not an IXFR or AXFR, or if an IXFR doesn't have - an appropriate SOA RRset in the authority section. - """ - if not isinstance(query, dns.message.QueryMessage): - raise ValueError("query not a QueryMessage") - question = query.question[0] - if question.rdtype == dns.rdatatype.AXFR: - return None - elif question.rdtype != dns.rdatatype.IXFR: - raise ValueError("query is not an AXFR or IXFR") - soa = query.find_rrset( - query.authority, question.name, question.rdclass, dns.rdatatype.SOA - ) - return soa[0].serial diff --git a/backend/venv39/lib/python3.9/site-packages/dns/zone.py b/backend/venv39/lib/python3.9/site-packages/dns/zone.py deleted file mode 100644 index 844919e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/zone.py +++ /dev/null @@ -1,1434 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Zones.""" - -import contextlib -import io -import os -import struct -from typing import ( - Any, - Callable, - Iterable, - Iterator, - List, - MutableMapping, - Optional, - Set, - Tuple, - Union, -) - -import dns.exception -import dns.grange -import dns.immutable -import dns.name -import dns.node -import dns.rdata -import dns.rdataclass -import dns.rdataset -import dns.rdatatype -import dns.rdtypes.ANY.SOA -import dns.rdtypes.ANY.ZONEMD -import dns.rrset -import dns.tokenizer -import dns.transaction -import dns.ttl -import dns.zonefile -from dns.zonetypes import DigestHashAlgorithm, DigestScheme, _digest_hashers - - -class BadZone(dns.exception.DNSException): - """The DNS zone is malformed.""" - - -class NoSOA(BadZone): - """The DNS zone has no SOA RR at its origin.""" - - -class NoNS(BadZone): - """The DNS zone has no NS RRset at its origin.""" - - -class UnknownOrigin(BadZone): - """The DNS zone's origin is unknown.""" - - -class UnsupportedDigestScheme(dns.exception.DNSException): - """The zone digest's scheme is unsupported.""" - - -class UnsupportedDigestHashAlgorithm(dns.exception.DNSException): - """The zone digest's origin is unsupported.""" - - -class NoDigest(dns.exception.DNSException): - """The DNS zone has no ZONEMD RRset at its origin.""" - - -class DigestVerificationFailure(dns.exception.DNSException): - """The ZONEMD digest failed to verify.""" - - -def _validate_name( - name: dns.name.Name, - origin: Optional[dns.name.Name], - relativize: bool, -) -> dns.name.Name: - # This name validation code is shared by Zone and Version - if origin is None: - # This should probably never happen as other code (e.g. - # _rr_line) will notice the lack of an origin before us, but - # we check just in case! - raise KeyError("no zone origin is defined") - if name.is_absolute(): - if not name.is_subdomain(origin): - raise KeyError("name parameter must be a subdomain of the zone origin") - if relativize: - name = name.relativize(origin) - else: - # We have a relative name. Make sure that the derelativized name is - # not too long. - try: - abs_name = name.derelativize(origin) - except dns.name.NameTooLong: - # We map dns.name.NameTooLong to KeyError to be consistent with - # the other exceptions above. - raise KeyError("relative name too long for zone") - if not relativize: - # We have a relative name in a non-relative zone, so use the - # derelativized name. - name = abs_name - return name - - -class Zone(dns.transaction.TransactionManager): - """A DNS zone. - - A ``Zone`` is a mapping from names to nodes. The zone object may be - treated like a Python dictionary, e.g. ``zone[name]`` will retrieve - the node associated with that name. The *name* may be a - ``dns.name.Name object``, or it may be a string. In either case, - if the name is relative it is treated as relative to the origin of - the zone. - """ - - node_factory: Callable[[], dns.node.Node] = dns.node.Node - map_factory: Callable[[], MutableMapping[dns.name.Name, dns.node.Node]] = dict - writable_version_factory: Optional[Callable[[], "WritableVersion"]] = None - immutable_version_factory: Optional[Callable[[], "ImmutableVersion"]] = None - - __slots__ = ["rdclass", "origin", "nodes", "relativize"] - - def __init__( - self, - origin: Optional[Union[dns.name.Name, str]], - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - relativize: bool = True, - ): - """Initialize a zone object. - - *origin* is the origin of the zone. It may be a ``dns.name.Name``, - a ``str``, or ``None``. If ``None``, then the zone's origin will - be set by the first ``$ORIGIN`` line in a zone file. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - """ - - if origin is not None: - if isinstance(origin, str): - origin = dns.name.from_text(origin) - elif not isinstance(origin, dns.name.Name): - raise ValueError("origin parameter must be convertible to a DNS name") - if not origin.is_absolute(): - raise ValueError("origin parameter must be an absolute name") - self.origin = origin - self.rdclass = rdclass - self.nodes: MutableMapping[dns.name.Name, dns.node.Node] = self.map_factory() - self.relativize = relativize - - def __eq__(self, other): - """Two zones are equal if they have the same origin, class, and - nodes. - - Returns a ``bool``. - """ - - if not isinstance(other, Zone): - return False - if ( - self.rdclass != other.rdclass - or self.origin != other.origin - or self.nodes != other.nodes - ): - return False - return True - - def __ne__(self, other): - """Are two zones not equal? - - Returns a ``bool``. - """ - - return not self.__eq__(other) - - def _validate_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name: - # Note that any changes in this method should have corresponding changes - # made in the Version _validate_name() method. - if isinstance(name, str): - name = dns.name.from_text(name, None) - elif not isinstance(name, dns.name.Name): - raise KeyError("name parameter must be convertible to a DNS name") - return _validate_name(name, self.origin, self.relativize) - - def __getitem__(self, key): - key = self._validate_name(key) - return self.nodes[key] - - def __setitem__(self, key, value): - key = self._validate_name(key) - self.nodes[key] = value - - def __delitem__(self, key): - key = self._validate_name(key) - del self.nodes[key] - - def __iter__(self): - return self.nodes.__iter__() - - def keys(self): - return self.nodes.keys() - - def values(self): - return self.nodes.values() - - def items(self): - return self.nodes.items() - - def get(self, key): - key = self._validate_name(key) - return self.nodes.get(key) - - def __contains__(self, key): - key = self._validate_name(key) - return key in self.nodes - - def find_node( - self, name: Union[dns.name.Name, str], create: bool = False - ) -> dns.node.Node: - """Find a node in the zone, possibly creating it. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.node.Node``. - """ - - name = self._validate_name(name) - node = self.nodes.get(name) - if node is None: - if not create: - raise KeyError - node = self.node_factory() - self.nodes[name] = node - return node - - def get_node( - self, name: Union[dns.name.Name, str], create: bool = False - ) -> Optional[dns.node.Node]: - """Get a node in the zone, possibly creating it. - - This method is like ``find_node()``, except it returns None instead - of raising an exception if the node does not exist and creation - has not been requested. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Returns a ``dns.node.Node`` or ``None``. - """ - - try: - node = self.find_node(name, create) - except KeyError: - node = None - return node - - def delete_node(self, name: Union[dns.name.Name, str]) -> None: - """Delete the specified node if it exists. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - It is not an error if the node does not exist. - """ - - name = self._validate_name(name) - if name in self.nodes: - del self.nodes[name] - - def find_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - create: bool = False, - ) -> dns.rdataset.Rdataset: - """Look for an rdataset with the specified name and type in the zone, - and return an rdataset encapsulating it. - - The rdataset returned is not a copy; changes to it will change - the zone. - - KeyError is raised if the name or type are not found. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str`` the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rdataset.Rdataset``. - """ - - name = self._validate_name(name) - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - node = self.find_node(name, create) - return node.find_rdataset(self.rdclass, rdtype, covers, create) - - def get_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - create: bool = False, - ) -> Optional[dns.rdataset.Rdataset]: - """Look for an rdataset with the specified name and type in the zone. - - This method is like ``find_rdataset()``, except it returns None instead - of raising an exception if the rdataset does not exist and creation - has not been requested. - - The rdataset returned is not a copy; changes to it will change - the zone. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rdataset.Rdataset`` or ``None``. - """ - - try: - rdataset = self.find_rdataset(name, rdtype, covers, create) - except KeyError: - rdataset = None - return rdataset - - def delete_rdataset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> None: - """Delete the rdataset matching *rdtype* and *covers*, if it - exists at the node specified by *name*. - - It is not an error if the node does not exist, or if there is no matching - rdataset at the node. - - If the node has no rdatasets after the deletion, it will itself be deleted. - - *name*: the name of the node to find. The value may be a ``dns.name.Name`` or a - ``str``. If absolute, the name must be a subdomain of the zone's origin. If - ``zone.relativize`` is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str`` or ``None``, the covered - type. Usually this value is ``dns.rdatatype.NONE``, but if the rdtype is - ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, then the covers value will be - the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types - as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This - makes RRSIGs much easier to work with than if RRSIGs covering different rdata - types were aggregated into a single RRSIG rdataset. - """ - - name = self._validate_name(name) - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - node = self.get_node(name) - if node is not None: - node.delete_rdataset(self.rdclass, rdtype, covers) - if len(node) == 0: - self.delete_node(name) - - def replace_rdataset( - self, name: Union[dns.name.Name, str], replacement: dns.rdataset.Rdataset - ) -> None: - """Replace an rdataset at name. - - It is not an error if there is no rdataset matching I{replacement}. - - Ownership of the *replacement* object is transferred to the zone; - in other words, this method does not store a copy of *replacement* - at the node, it stores *replacement* itself. - - If the node does not exist, it is created. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *replacement*, a ``dns.rdataset.Rdataset``, the replacement rdataset. - """ - - if replacement.rdclass != self.rdclass: - raise ValueError("replacement.rdclass != zone.rdclass") - node = self.find_node(name, True) - node.replace_rdataset(replacement) - - def find_rrset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> dns.rrset.RRset: - """Look for an rdataset with the specified name and type in the zone, - and return an RRset encapsulating it. - - This method is less efficient than the similar - ``find_rdataset()`` because it creates an RRset instead of - returning the matching rdataset. It may be more convenient - for some uses since it returns an object which binds the owner - name to the rdataset. - - This method may not be used to create new nodes or rdatasets; - use ``find_rdataset`` instead. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Raises ``KeyError`` if the name is not known and create was - not specified, or if the name was not a subdomain of the origin. - - Returns a ``dns.rrset.RRset`` or ``None``. - """ - - vname = self._validate_name(name) - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - rdataset = self.nodes[vname].find_rdataset(self.rdclass, rdtype, covers) - rrset = dns.rrset.RRset(vname, self.rdclass, rdtype, covers) - rrset.update(rdataset) - return rrset - - def get_rrset( - self, - name: Union[dns.name.Name, str], - rdtype: Union[dns.rdatatype.RdataType, str], - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> Optional[dns.rrset.RRset]: - """Look for an rdataset with the specified name and type in the zone, - and return an RRset encapsulating it. - - This method is less efficient than the similar ``get_rdataset()`` - because it creates an RRset instead of returning the matching - rdataset. It may be more convenient for some uses since it - returns an object which binds the owner name to the rdataset. - - This method may not be used to create new nodes or rdatasets; - use ``get_rdataset()`` instead. - - *name*: the name of the node to find. - The value may be a ``dns.name.Name`` or a ``str``. If absolute, the - name must be a subdomain of the zone's origin. If ``zone.relativize`` - is ``True``, then the name will be relativized. - - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - - *create*, a ``bool``. If true, the node will be created if it does - not exist. - - Returns a ``dns.rrset.RRset`` or ``None``. - """ - - try: - rrset = self.find_rrset(name, rdtype, covers) - except KeyError: - rrset = None - return rrset - - def iterate_rdatasets( - self, - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.ANY, - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> Iterator[Tuple[dns.name.Name, dns.rdataset.Rdataset]]: - """Return a generator which yields (name, rdataset) tuples for - all rdatasets in the zone which have the specified *rdtype* - and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default, - then all rdatasets will be matched. - - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - """ - - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - for name, node in self.items(): - for rds in node: - if rdtype == dns.rdatatype.ANY or ( - rds.rdtype == rdtype and rds.covers == covers - ): - yield (name, rds) - - def iterate_rdatas( - self, - rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.ANY, - covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE, - ) -> Iterator[Tuple[dns.name.Name, int, dns.rdata.Rdata]]: - """Return a generator which yields (name, ttl, rdata) tuples for - all rdatas in the zone which have the specified *rdtype* - and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default, - then all rdatas will be matched. - - *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired. - - *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type. - Usually this value is ``dns.rdatatype.NONE``, but if the - rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, - then the covers value will be the rdata type the SIG/RRSIG - covers. The library treats the SIG and RRSIG types as if they - were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). - This makes RRSIGs much easier to work with than if RRSIGs - covering different rdata types were aggregated into a single - RRSIG rdataset. - """ - - rdtype = dns.rdatatype.RdataType.make(rdtype) - covers = dns.rdatatype.RdataType.make(covers) - for name, node in self.items(): - for rds in node: - if rdtype == dns.rdatatype.ANY or ( - rds.rdtype == rdtype and rds.covers == covers - ): - for rdata in rds: - yield (name, rds.ttl, rdata) - - def to_file( - self, - f: Any, - sorted: bool = True, - relativize: bool = True, - nl: Optional[str] = None, - want_comments: bool = False, - want_origin: bool = False, - ) -> None: - """Write a zone to a file. - - *f*, a file or `str`. If *f* is a string, it is treated - as the name of a file to open. - - *sorted*, a ``bool``. If True, the default, then the file - will be written with the names sorted in DNSSEC order from - least to greatest. Otherwise the names will be written in - whatever order they happen to have in the zone's dictionary. - - *relativize*, a ``bool``. If True, the default, then domain - names in the output will be relativized to the zone's origin - if possible. - - *nl*, a ``str`` or None. The end of line string. If not - ``None``, the output will use the platform's native - end-of-line marker (i.e. LF on POSIX, CRLF on Windows). - - *want_comments*, a ``bool``. If ``True``, emit end-of-line comments - as part of writing the file. If ``False``, the default, do not - emit them. - - *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at - the start of the file. If ``False``, the default, do not emit - one. - """ - - if isinstance(f, str): - cm: contextlib.AbstractContextManager = open(f, "wb") - else: - cm = contextlib.nullcontext(f) - with cm as f: - # must be in this way, f.encoding may contain None, or even - # attribute may not be there - file_enc = getattr(f, "encoding", None) - if file_enc is None: - file_enc = "utf-8" - - if nl is None: - # binary mode, '\n' is not enough - nl_b = os.linesep.encode(file_enc) - nl = "\n" - elif isinstance(nl, str): - nl_b = nl.encode(file_enc) - else: - nl_b = nl - nl = nl.decode() - - if want_origin: - assert self.origin is not None - l = "$ORIGIN " + self.origin.to_text() - l_b = l.encode(file_enc) - try: - f.write(l_b) - f.write(nl_b) - except TypeError: # textual mode - f.write(l) - f.write(nl) - - if sorted: - names = list(self.keys()) - names.sort() - else: - names = self.keys() - for n in names: - l = self[n].to_text( - n, - origin=self.origin, - relativize=relativize, - want_comments=want_comments, - ) - l_b = l.encode(file_enc) - - try: - f.write(l_b) - f.write(nl_b) - except TypeError: # textual mode - f.write(l) - f.write(nl) - - def to_text( - self, - sorted: bool = True, - relativize: bool = True, - nl: Optional[str] = None, - want_comments: bool = False, - want_origin: bool = False, - ) -> str: - """Return a zone's text as though it were written to a file. - - *sorted*, a ``bool``. If True, the default, then the file - will be written with the names sorted in DNSSEC order from - least to greatest. Otherwise the names will be written in - whatever order they happen to have in the zone's dictionary. - - *relativize*, a ``bool``. If True, the default, then domain - names in the output will be relativized to the zone's origin - if possible. - - *nl*, a ``str`` or None. The end of line string. If not - ``None``, the output will use the platform's native - end-of-line marker (i.e. LF on POSIX, CRLF on Windows). - - *want_comments*, a ``bool``. If ``True``, emit end-of-line comments - as part of writing the file. If ``False``, the default, do not - emit them. - - *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at - the start of the output. If ``False``, the default, do not emit - one. - - Returns a ``str``. - """ - temp_buffer = io.StringIO() - self.to_file(temp_buffer, sorted, relativize, nl, want_comments, want_origin) - return_value = temp_buffer.getvalue() - temp_buffer.close() - return return_value - - def check_origin(self) -> None: - """Do some simple checking of the zone's origin. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - """ - if self.relativize: - name = dns.name.empty - else: - assert self.origin is not None - name = self.origin - if self.get_rdataset(name, dns.rdatatype.SOA) is None: - raise NoSOA - if self.get_rdataset(name, dns.rdatatype.NS) is None: - raise NoNS - - def get_soa( - self, txn: Optional[dns.transaction.Transaction] = None - ) -> dns.rdtypes.ANY.SOA.SOA: - """Get the zone SOA rdata. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Returns a ``dns.rdtypes.ANY.SOA.SOA`` Rdata. - """ - if self.relativize: - origin_name = dns.name.empty - else: - if self.origin is None: - # get_soa() has been called very early, and there must not be - # an SOA if there is no origin. - raise NoSOA - origin_name = self.origin - soa: Optional[dns.rdataset.Rdataset] - if txn: - soa = txn.get(origin_name, dns.rdatatype.SOA) - else: - soa = self.get_rdataset(origin_name, dns.rdatatype.SOA) - if soa is None: - raise NoSOA - return soa[0] - - def _compute_digest( - self, - hash_algorithm: DigestHashAlgorithm, - scheme: DigestScheme = DigestScheme.SIMPLE, - ) -> bytes: - hashinfo = _digest_hashers.get(hash_algorithm) - if not hashinfo: - raise UnsupportedDigestHashAlgorithm - if scheme != DigestScheme.SIMPLE: - raise UnsupportedDigestScheme - - if self.relativize: - origin_name = dns.name.empty - else: - assert self.origin is not None - origin_name = self.origin - hasher = hashinfo() - for name, node in sorted(self.items()): - rrnamebuf = name.to_digestable(self.origin) - for rdataset in sorted(node, key=lambda rds: (rds.rdtype, rds.covers)): - if name == origin_name and dns.rdatatype.ZONEMD in ( - rdataset.rdtype, - rdataset.covers, - ): - continue - rrfixed = struct.pack( - "!HHI", rdataset.rdtype, rdataset.rdclass, rdataset.ttl - ) - rdatas = [rdata.to_digestable(self.origin) for rdata in rdataset] - for rdata in sorted(rdatas): - rrlen = struct.pack("!H", len(rdata)) - hasher.update(rrnamebuf + rrfixed + rrlen + rdata) - return hasher.digest() - - def compute_digest( - self, - hash_algorithm: DigestHashAlgorithm, - scheme: DigestScheme = DigestScheme.SIMPLE, - ) -> dns.rdtypes.ANY.ZONEMD.ZONEMD: - serial = self.get_soa().serial - digest = self._compute_digest(hash_algorithm, scheme) - return dns.rdtypes.ANY.ZONEMD.ZONEMD( - self.rdclass, dns.rdatatype.ZONEMD, serial, scheme, hash_algorithm, digest - ) - - def verify_digest( - self, zonemd: Optional[dns.rdtypes.ANY.ZONEMD.ZONEMD] = None - ) -> None: - digests: Union[dns.rdataset.Rdataset, List[dns.rdtypes.ANY.ZONEMD.ZONEMD]] - if zonemd: - digests = [zonemd] - else: - assert self.origin is not None - rds = self.get_rdataset(self.origin, dns.rdatatype.ZONEMD) - if rds is None: - raise NoDigest - digests = rds - for digest in digests: - try: - computed = self._compute_digest(digest.hash_algorithm, digest.scheme) - if computed == digest.digest: - return - except Exception: - pass - raise DigestVerificationFailure - - # TransactionManager methods - - def reader(self) -> "Transaction": - return Transaction(self, False, Version(self, 1, self.nodes, self.origin)) - - def writer(self, replacement: bool = False) -> "Transaction": - txn = Transaction(self, replacement) - txn._setup_version() - return txn - - def origin_information( - self, - ) -> Tuple[Optional[dns.name.Name], bool, Optional[dns.name.Name]]: - effective: Optional[dns.name.Name] - if self.relativize: - effective = dns.name.empty - else: - effective = self.origin - return (self.origin, self.relativize, effective) - - def get_class(self): - return self.rdclass - - # Transaction methods - - def _end_read(self, txn): - pass - - def _end_write(self, txn): - pass - - def _commit_version(self, _, version, origin): - self.nodes = version.nodes - if self.origin is None: - self.origin = origin - - def _get_next_version_id(self): - # Versions are ephemeral and all have id 1 - return 1 - - -# These classes used to be in dns.versioned, but have moved here so we can use -# the copy-on-write transaction mechanism for both kinds of zones. In a -# regular zone, the version only exists during the transaction, and the nodes -# are regular dns.node.Nodes. - -# A node with a version id. - - -class VersionedNode(dns.node.Node): # lgtm[py/missing-equals] - __slots__ = ["id"] - - def __init__(self): - super().__init__() - # A proper id will get set by the Version - self.id = 0 - - -@dns.immutable.immutable -class ImmutableVersionedNode(VersionedNode): - def __init__(self, node): - super().__init__() - self.id = node.id - self.rdatasets = tuple( - [dns.rdataset.ImmutableRdataset(rds) for rds in node.rdatasets] - ) - - def find_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> dns.rdataset.Rdataset: - if create: - raise TypeError("immutable") - return super().find_rdataset(rdclass, rdtype, covers, False) - - def get_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - create: bool = False, - ) -> Optional[dns.rdataset.Rdataset]: - if create: - raise TypeError("immutable") - return super().get_rdataset(rdclass, rdtype, covers, False) - - def delete_rdataset( - self, - rdclass: dns.rdataclass.RdataClass, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, - ) -> None: - raise TypeError("immutable") - - def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None: - raise TypeError("immutable") - - def is_immutable(self) -> bool: - return True - - -class Version: - def __init__( - self, - zone: Zone, - id: int, - nodes: Optional[MutableMapping[dns.name.Name, dns.node.Node]] = None, - origin: Optional[dns.name.Name] = None, - ): - self.zone = zone - self.id = id - if nodes is not None: - self.nodes = nodes - else: - self.nodes = zone.map_factory() - self.origin = origin - - def _validate_name(self, name: dns.name.Name) -> dns.name.Name: - return _validate_name(name, self.origin, self.zone.relativize) - - def get_node(self, name: dns.name.Name) -> Optional[dns.node.Node]: - name = self._validate_name(name) - return self.nodes.get(name) - - def get_rdataset( - self, - name: dns.name.Name, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType, - ) -> Optional[dns.rdataset.Rdataset]: - node = self.get_node(name) - if node is None: - return None - return node.get_rdataset(self.zone.rdclass, rdtype, covers) - - def keys(self): - return self.nodes.keys() - - def items(self): - return self.nodes.items() - - -class WritableVersion(Version): - def __init__(self, zone: Zone, replacement: bool = False): - # The zone._versions_lock must be held by our caller in a versioned - # zone. - id = zone._get_next_version_id() - super().__init__(zone, id) - if not replacement: - # We copy the map, because that gives us a simple and thread-safe - # way of doing versions, and we have a garbage collector to help - # us. We only make new node objects if we actually change the - # node. - self.nodes.update(zone.nodes) - # We have to copy the zone origin as it may be None in the first - # version, and we don't want to mutate the zone until we commit. - self.origin = zone.origin - self.changed: Set[dns.name.Name] = set() - - def _maybe_cow(self, name: dns.name.Name) -> dns.node.Node: - name = self._validate_name(name) - node = self.nodes.get(name) - if node is None or name not in self.changed: - new_node = self.zone.node_factory() - if hasattr(new_node, "id"): - # We keep doing this for backwards compatibility, as earlier - # code used new_node.id != self.id for the "do we need to CoW?" - # test. Now we use the changed set as this works with both - # regular zones and versioned zones. - # - # We ignore the mypy error as this is safe but it doesn't see it. - new_node.id = self.id # type: ignore - if node is not None: - # moo! copy on write! - new_node.rdatasets.extend(node.rdatasets) - self.nodes[name] = new_node - self.changed.add(name) - return new_node - else: - return node - - def delete_node(self, name: dns.name.Name) -> None: - name = self._validate_name(name) - if name in self.nodes: - del self.nodes[name] - self.changed.add(name) - - def put_rdataset( - self, name: dns.name.Name, rdataset: dns.rdataset.Rdataset - ) -> None: - node = self._maybe_cow(name) - node.replace_rdataset(rdataset) - - def delete_rdataset( - self, - name: dns.name.Name, - rdtype: dns.rdatatype.RdataType, - covers: dns.rdatatype.RdataType, - ) -> None: - node = self._maybe_cow(name) - node.delete_rdataset(self.zone.rdclass, rdtype, covers) - if len(node) == 0: - del self.nodes[name] - - -@dns.immutable.immutable -class ImmutableVersion(Version): - def __init__(self, version: WritableVersion): - # We tell super() that it's a replacement as we don't want it - # to copy the nodes, as we're about to do that with an - # immutable Dict. - super().__init__(version.zone, True) - # set the right id! - self.id = version.id - # keep the origin - self.origin = version.origin - # Make changed nodes immutable - for name in version.changed: - node = version.nodes.get(name) - # it might not exist if we deleted it in the version - if node: - version.nodes[name] = ImmutableVersionedNode(node) - # We're changing the type of the nodes dictionary here on purpose, so - # we ignore the mypy error. - self.nodes = dns.immutable.Dict( - version.nodes, True, self.zone.map_factory - ) # type: ignore - - -class Transaction(dns.transaction.Transaction): - def __init__(self, zone, replacement, version=None, make_immutable=False): - read_only = version is not None - super().__init__(zone, replacement, read_only) - self.version = version - self.make_immutable = make_immutable - - @property - def zone(self): - return self.manager - - def _setup_version(self): - assert self.version is None - factory = self.manager.writable_version_factory - if factory is None: - factory = WritableVersion - self.version = factory(self.zone, self.replacement) - - def _get_rdataset(self, name, rdtype, covers): - return self.version.get_rdataset(name, rdtype, covers) - - def _put_rdataset(self, name, rdataset): - assert not self.read_only - self.version.put_rdataset(name, rdataset) - - def _delete_name(self, name): - assert not self.read_only - self.version.delete_node(name) - - def _delete_rdataset(self, name, rdtype, covers): - assert not self.read_only - self.version.delete_rdataset(name, rdtype, covers) - - def _name_exists(self, name): - return self.version.get_node(name) is not None - - def _changed(self): - if self.read_only: - return False - else: - return len(self.version.changed) > 0 - - def _end_transaction(self, commit): - if self.read_only: - self.zone._end_read(self) - elif commit and len(self.version.changed) > 0: - if self.make_immutable: - factory = self.manager.immutable_version_factory - if factory is None: - factory = ImmutableVersion - version = factory(self.version) - else: - version = self.version - self.zone._commit_version(self, version, self.version.origin) - else: - # rollback - self.zone._end_write(self) - - def _set_origin(self, origin): - if self.version.origin is None: - self.version.origin = origin - - def _iterate_rdatasets(self): - for name, node in self.version.items(): - for rdataset in node: - yield (name, rdataset) - - def _iterate_names(self): - return self.version.keys() - - def _get_node(self, name): - return self.version.get_node(name) - - def _origin_information(self): - (absolute, relativize, effective) = self.manager.origin_information() - if absolute is None and self.version.origin is not None: - # No origin has been committed yet, but we've learned one as part of - # this txn. Use it. - absolute = self.version.origin - if relativize: - effective = dns.name.empty - else: - effective = absolute - return (absolute, relativize, effective) - - -def _from_text( - text: Any, - origin: Optional[Union[dns.name.Name, str]] = None, - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - relativize: bool = True, - zone_factory: Any = Zone, - filename: Optional[str] = None, - allow_include: bool = False, - check_origin: bool = True, - idna_codec: Optional[dns.name.IDNACodec] = None, - allow_directives: Union[bool, Iterable[str]] = True, -) -> Zone: - # See the comments for the public APIs from_text() and from_file() for - # details. - - # 'text' can also be a file, but we don't publish that fact - # since it's an implementation detail. The official file - # interface is from_file(). - - if filename is None: - filename = "" - zone = zone_factory(origin, rdclass, relativize=relativize) - with zone.writer(True) as txn: - tok = dns.tokenizer.Tokenizer(text, filename, idna_codec=idna_codec) - reader = dns.zonefile.Reader( - tok, - rdclass, - txn, - allow_include=allow_include, - allow_directives=allow_directives, - ) - try: - reader.read() - except dns.zonefile.UnknownOrigin: - # for backwards compatibility - raise dns.zone.UnknownOrigin - # Now that we're done reading, do some basic checking of the zone. - if check_origin: - zone.check_origin() - return zone - - -def from_text( - text: str, - origin: Optional[Union[dns.name.Name, str]] = None, - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - relativize: bool = True, - zone_factory: Any = Zone, - filename: Optional[str] = None, - allow_include: bool = False, - check_origin: bool = True, - idna_codec: Optional[dns.name.IDNACodec] = None, - allow_directives: Union[bool, Iterable[str]] = True, -) -> Zone: - """Build a zone object from a zone file format string. - - *text*, a ``str``, the zone file format input. - - *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin - of the zone; if not specified, the first ``$ORIGIN`` statement in the - zone file will determine the origin of the zone. - - *rdclass*, a ``dns.rdataclass.RdataClass``, the zone's rdata class; the default is - class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *zone_factory*, the zone factory to use or ``None``. If ``None``, then - ``dns.zone.Zone`` will be used. The value may be any class or callable - that returns a subclass of ``dns.zone.Zone``. - - *filename*, a ``str`` or ``None``, the filename to emit when - describing where an error occurred; the default is ``''``. - - *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE`` - directives are permitted. If ``False``, then encoutering a ``$INCLUDE`` - will raise a ``SyntaxError`` exception. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default, - then directives are permitted, and the *allow_include* parameter controls whether - ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive - processing is done and any directive-like text will be treated as a regular owner - name. If a non-empty iterable, then only the listed directives (including the - ``$``) are allowed. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Returns a subclass of ``dns.zone.Zone``. - """ - return _from_text( - text, - origin, - rdclass, - relativize, - zone_factory, - filename, - allow_include, - check_origin, - idna_codec, - allow_directives, - ) - - -def from_file( - f: Any, - origin: Optional[Union[dns.name.Name, str]] = None, - rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN, - relativize: bool = True, - zone_factory: Any = Zone, - filename: Optional[str] = None, - allow_include: bool = True, - check_origin: bool = True, - idna_codec: Optional[dns.name.IDNACodec] = None, - allow_directives: Union[bool, Iterable[str]] = True, -) -> Zone: - """Read a zone file and build a zone object. - - *f*, a file or ``str``. If *f* is a string, it is treated - as the name of a file to open. - - *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin - of the zone; if not specified, the first ``$ORIGIN`` statement in the - zone file will determine the origin of the zone. - - *rdclass*, an ``int``, the zone's rdata class; the default is class IN. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - - *zone_factory*, the zone factory to use or ``None``. If ``None``, then - ``dns.zone.Zone`` will be used. The value may be any class or callable - that returns a subclass of ``dns.zone.Zone``. - - *filename*, a ``str`` or ``None``, the filename to emit when - describing where an error occurred; the default is ``''``. - - *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE`` - directives are permitted. If ``False``, then encoutering a ``$INCLUDE`` - will raise a ``SyntaxError`` exception. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. - - *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default, - then directives are permitted, and the *allow_include* parameter controls whether - ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive - processing is done and any directive-like text will be treated as a regular owner - name. If a non-empty iterable, then only the listed directives (including the - ``$``) are allowed. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Returns a subclass of ``dns.zone.Zone``. - """ - - if isinstance(f, str): - if filename is None: - filename = f - cm: contextlib.AbstractContextManager = open(f) - else: - cm = contextlib.nullcontext(f) - with cm as f: - return _from_text( - f, - origin, - rdclass, - relativize, - zone_factory, - filename, - allow_include, - check_origin, - idna_codec, - allow_directives, - ) - assert False # make mypy happy lgtm[py/unreachable-statement] - - -def from_xfr( - xfr: Any, - zone_factory: Any = Zone, - relativize: bool = True, - check_origin: bool = True, -) -> Zone: - """Convert the output of a zone transfer generator into a zone object. - - *xfr*, a generator of ``dns.message.Message`` objects, typically - ``dns.query.xfr()``. - - *relativize*, a ``bool``, determine's whether domain names are - relativized to the zone's origin. The default is ``True``. - It is essential that the relativize setting matches the one specified - to the generator. - - *check_origin*, a ``bool``. If ``True``, the default, then sanity - checks of the origin node will be made by calling the zone's - ``check_origin()`` method. - - Raises ``dns.zone.NoSOA`` if there is no SOA RRset. - - Raises ``dns.zone.NoNS`` if there is no NS RRset. - - Raises ``KeyError`` if there is no origin node. - - Raises ``ValueError`` if no messages are yielded by the generator. - - Returns a subclass of ``dns.zone.Zone``. - """ - - z = None - for r in xfr: - if z is None: - if relativize: - origin = r.origin - else: - origin = r.answer[0].name - rdclass = r.answer[0].rdclass - z = zone_factory(origin, rdclass, relativize=relativize) - for rrset in r.answer: - znode = z.nodes.get(rrset.name) - if not znode: - znode = z.node_factory() - z.nodes[rrset.name] = znode - zrds = znode.find_rdataset(rrset.rdclass, rrset.rdtype, rrset.covers, True) - zrds.update_ttl(rrset.ttl) - for rd in rrset: - zrds.add(rd) - if z is None: - raise ValueError("empty transfer") - if check_origin: - z.check_origin() - return z diff --git a/backend/venv39/lib/python3.9/site-packages/dns/zonefile.py b/backend/venv39/lib/python3.9/site-packages/dns/zonefile.py deleted file mode 100644 index d74510b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/zonefile.py +++ /dev/null @@ -1,744 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose with or without fee is hereby granted, -# provided that the above copyright notice and this permission notice -# appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""DNS Zones.""" - -import re -import sys -from typing import Any, Iterable, List, Optional, Set, Tuple, Union - -import dns.exception -import dns.grange -import dns.name -import dns.node -import dns.rdata -import dns.rdataclass -import dns.rdatatype -import dns.rdtypes.ANY.SOA -import dns.rrset -import dns.tokenizer -import dns.transaction -import dns.ttl - - -class UnknownOrigin(dns.exception.DNSException): - """Unknown origin""" - - -class CNAMEAndOtherData(dns.exception.DNSException): - """A node has a CNAME and other data""" - - -def _check_cname_and_other_data(txn, name, rdataset): - rdataset_kind = dns.node.NodeKind.classify_rdataset(rdataset) - node = txn.get_node(name) - if node is None: - # empty nodes are neutral. - return - node_kind = node.classify() - if ( - node_kind == dns.node.NodeKind.CNAME - and rdataset_kind == dns.node.NodeKind.REGULAR - ): - raise CNAMEAndOtherData("rdataset type is not compatible with a CNAME node") - elif ( - node_kind == dns.node.NodeKind.REGULAR - and rdataset_kind == dns.node.NodeKind.CNAME - ): - raise CNAMEAndOtherData( - "CNAME rdataset is not compatible with a regular data node" - ) - # Otherwise at least one of the node and the rdataset is neutral, so - # adding the rdataset is ok - - -SavedStateType = Tuple[ - dns.tokenizer.Tokenizer, - Optional[dns.name.Name], # current_origin - Optional[dns.name.Name], # last_name - Optional[Any], # current_file - int, # last_ttl - bool, # last_ttl_known - int, # default_ttl - bool, -] # default_ttl_known - - -def _upper_dollarize(s): - s = s.upper() - if not s.startswith("$"): - s = "$" + s - return s - - -class Reader: - """Read a DNS zone file into a transaction.""" - - def __init__( - self, - tok: dns.tokenizer.Tokenizer, - rdclass: dns.rdataclass.RdataClass, - txn: dns.transaction.Transaction, - allow_include: bool = False, - allow_directives: Union[bool, Iterable[str]] = True, - force_name: Optional[dns.name.Name] = None, - force_ttl: Optional[int] = None, - force_rdclass: Optional[dns.rdataclass.RdataClass] = None, - force_rdtype: Optional[dns.rdatatype.RdataType] = None, - default_ttl: Optional[int] = None, - ): - self.tok = tok - (self.zone_origin, self.relativize, _) = txn.manager.origin_information() - self.current_origin = self.zone_origin - self.last_ttl = 0 - self.last_ttl_known = False - if force_ttl is not None: - default_ttl = force_ttl - if default_ttl is None: - self.default_ttl = 0 - self.default_ttl_known = False - else: - self.default_ttl = default_ttl - self.default_ttl_known = True - self.last_name = self.current_origin - self.zone_rdclass = rdclass - self.txn = txn - self.saved_state: List[SavedStateType] = [] - self.current_file: Optional[Any] = None - self.allowed_directives: Set[str] - if allow_directives is True: - self.allowed_directives = {"$GENERATE", "$ORIGIN", "$TTL"} - if allow_include: - self.allowed_directives.add("$INCLUDE") - elif allow_directives is False: - # allow_include was ignored in earlier releases if allow_directives was - # False, so we continue that. - self.allowed_directives = set() - else: - # Note that if directives are explicitly specified, then allow_include - # is ignored. - self.allowed_directives = set(_upper_dollarize(d) for d in allow_directives) - self.force_name = force_name - self.force_ttl = force_ttl - self.force_rdclass = force_rdclass - self.force_rdtype = force_rdtype - self.txn.check_put_rdataset(_check_cname_and_other_data) - - def _eat_line(self): - while 1: - token = self.tok.get() - if token.is_eol_or_eof(): - break - - def _get_identifier(self): - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - return token - - def _rr_line(self): - """Process one line from a DNS zone file.""" - token = None - # Name - if self.force_name is not None: - name = self.force_name - else: - if self.current_origin is None: - raise UnknownOrigin - token = self.tok.get(want_leading=True) - if not token.is_whitespace(): - self.last_name = self.tok.as_name(token, self.current_origin) - else: - token = self.tok.get() - if token.is_eol_or_eof(): - # treat leading WS followed by EOL/EOF as if they were EOL/EOF. - return - self.tok.unget(token) - name = self.last_name - if not name.is_subdomain(self.zone_origin): - self._eat_line() - return - if self.relativize: - name = name.relativize(self.zone_origin) - - # TTL - if self.force_ttl is not None: - ttl = self.force_ttl - self.last_ttl = ttl - self.last_ttl_known = True - else: - token = self._get_identifier() - ttl = None - try: - ttl = dns.ttl.from_text(token.value) - self.last_ttl = ttl - self.last_ttl_known = True - token = None - except dns.ttl.BadTTL: - self.tok.unget(token) - - # Class - if self.force_rdclass is not None: - rdclass = self.force_rdclass - else: - token = self._get_identifier() - try: - rdclass = dns.rdataclass.from_text(token.value) - except dns.exception.SyntaxError: - raise - except Exception: - rdclass = self.zone_rdclass - self.tok.unget(token) - if rdclass != self.zone_rdclass: - raise dns.exception.SyntaxError("RR class is not zone's class") - - if ttl is None: - # support for syntax - token = self._get_identifier() - ttl = None - try: - ttl = dns.ttl.from_text(token.value) - self.last_ttl = ttl - self.last_ttl_known = True - token = None - except dns.ttl.BadTTL: - if self.default_ttl_known: - ttl = self.default_ttl - elif self.last_ttl_known: - ttl = self.last_ttl - self.tok.unget(token) - - # Type - if self.force_rdtype is not None: - rdtype = self.force_rdtype - else: - token = self._get_identifier() - try: - rdtype = dns.rdatatype.from_text(token.value) - except Exception: - raise dns.exception.SyntaxError(f"unknown rdatatype '{token.value}'") - - try: - rd = dns.rdata.from_text( - rdclass, - rdtype, - self.tok, - self.current_origin, - self.relativize, - self.zone_origin, - ) - except dns.exception.SyntaxError: - # Catch and reraise. - raise - except Exception: - # All exceptions that occur in the processing of rdata - # are treated as syntax errors. This is not strictly - # correct, but it is correct almost all of the time. - # We convert them to syntax errors so that we can emit - # helpful filename:line info. - (ty, va) = sys.exc_info()[:2] - raise dns.exception.SyntaxError(f"caught exception {str(ty)}: {str(va)}") - - if not self.default_ttl_known and rdtype == dns.rdatatype.SOA: - # The pre-RFC2308 and pre-BIND9 behavior inherits the zone default - # TTL from the SOA minttl if no $TTL statement is present before the - # SOA is parsed. - self.default_ttl = rd.minimum - self.default_ttl_known = True - if ttl is None: - # if we didn't have a TTL on the SOA, set it! - ttl = rd.minimum - - # TTL check. We had to wait until now to do this as the SOA RR's - # own TTL can be inferred from its minimum. - if ttl is None: - raise dns.exception.SyntaxError("Missing default TTL value") - - self.txn.add(name, ttl, rd) - - def _parse_modify(self, side: str) -> Tuple[str, str, int, int, str]: - # Here we catch everything in '{' '}' in a group so we can replace it - # with ''. - is_generate1 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$") - is_generate2 = re.compile(r"^.*\$({(\+|-?)(\d+)}).*$") - is_generate3 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+)}).*$") - # Sometimes there are modifiers in the hostname. These come after - # the dollar sign. They are in the form: ${offset[,width[,base]]}. - # Make names - mod = "" - sign = "+" - offset = "0" - width = "0" - base = "d" - g1 = is_generate1.match(side) - if g1: - mod, sign, offset, width, base = g1.groups() - if sign == "": - sign = "+" - else: - g2 = is_generate2.match(side) - if g2: - mod, sign, offset = g2.groups() - if sign == "": - sign = "+" - width = "0" - base = "d" - else: - g3 = is_generate3.match(side) - if g3: - mod, sign, offset, width = g3.groups() - if sign == "": - sign = "+" - base = "d" - - ioffset = int(offset) - iwidth = int(width) - - if sign not in ["+", "-"]: - raise dns.exception.SyntaxError(f"invalid offset sign {sign}") - if base not in ["d", "o", "x", "X", "n", "N"]: - raise dns.exception.SyntaxError(f"invalid type {base}") - - return mod, sign, ioffset, iwidth, base - - def _generate_line(self): - # range lhs [ttl] [class] type rhs [ comment ] - """Process one line containing the GENERATE statement from a DNS - zone file.""" - if self.current_origin is None: - raise UnknownOrigin - - token = self.tok.get() - # Range (required) - try: - start, stop, step = dns.grange.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except Exception: - raise dns.exception.SyntaxError - - # lhs (required) - try: - lhs = token.value - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except Exception: - raise dns.exception.SyntaxError - - # TTL - try: - ttl = dns.ttl.from_text(token.value) - self.last_ttl = ttl - self.last_ttl_known = True - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.ttl.BadTTL: - if not (self.last_ttl_known or self.default_ttl_known): - raise dns.exception.SyntaxError("Missing default TTL value") - if self.default_ttl_known: - ttl = self.default_ttl - elif self.last_ttl_known: - ttl = self.last_ttl - # Class - try: - rdclass = dns.rdataclass.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except dns.exception.SyntaxError: - raise dns.exception.SyntaxError - except Exception: - rdclass = self.zone_rdclass - if rdclass != self.zone_rdclass: - raise dns.exception.SyntaxError("RR class is not zone's class") - # Type - try: - rdtype = dns.rdatatype.from_text(token.value) - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError - except Exception: - raise dns.exception.SyntaxError(f"unknown rdatatype '{token.value}'") - - # rhs (required) - rhs = token.value - - def _calculate_index(counter: int, offset_sign: str, offset: int) -> int: - """Calculate the index from the counter and offset.""" - if offset_sign == "-": - offset *= -1 - return counter + offset - - def _format_index(index: int, base: str, width: int) -> str: - """Format the index with the given base, and zero-fill it - to the given width.""" - if base in ["d", "o", "x", "X"]: - return format(index, base).zfill(width) - - # base can only be n or N here - hexa = _format_index(index, "x", width) - nibbles = ".".join(hexa[::-1])[:width] - if base == "N": - nibbles = nibbles.upper() - return nibbles - - lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) - rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) - for i in range(start, stop + 1, step): - # +1 because bind is inclusive and python is exclusive - - lindex = _calculate_index(i, lsign, loffset) - rindex = _calculate_index(i, rsign, roffset) - - lzfindex = _format_index(lindex, lbase, lwidth) - rzfindex = _format_index(rindex, rbase, rwidth) - - name = lhs.replace(f"${lmod}", lzfindex) - rdata = rhs.replace(f"${rmod}", rzfindex) - - self.last_name = dns.name.from_text( - name, self.current_origin, self.tok.idna_codec - ) - name = self.last_name - if not name.is_subdomain(self.zone_origin): - self._eat_line() - return - if self.relativize: - name = name.relativize(self.zone_origin) - - try: - rd = dns.rdata.from_text( - rdclass, - rdtype, - rdata, - self.current_origin, - self.relativize, - self.zone_origin, - ) - except dns.exception.SyntaxError: - # Catch and reraise. - raise - except Exception: - # All exceptions that occur in the processing of rdata - # are treated as syntax errors. This is not strictly - # correct, but it is correct almost all of the time. - # We convert them to syntax errors so that we can emit - # helpful filename:line info. - (ty, va) = sys.exc_info()[:2] - raise dns.exception.SyntaxError( - f"caught exception {str(ty)}: {str(va)}" - ) - - self.txn.add(name, ttl, rd) - - def read(self) -> None: - """Read a DNS zone file and build a zone object. - - @raises dns.zone.NoSOA: No SOA RR was found at the zone origin - @raises dns.zone.NoNS: No NS RRset was found at the zone origin - """ - - try: - while 1: - token = self.tok.get(True, True) - if token.is_eof(): - if self.current_file is not None: - self.current_file.close() - if len(self.saved_state) > 0: - ( - self.tok, - self.current_origin, - self.last_name, - self.current_file, - self.last_ttl, - self.last_ttl_known, - self.default_ttl, - self.default_ttl_known, - ) = self.saved_state.pop(-1) - continue - break - elif token.is_eol(): - continue - elif token.is_comment(): - self.tok.get_eol() - continue - elif token.value[0] == "$" and len(self.allowed_directives) > 0: - # Note that we only run directive processing code if at least - # one directive is allowed in order to be backwards compatible - c = token.value.upper() - if c not in self.allowed_directives: - raise dns.exception.SyntaxError( - f"zone file directive '{c}' is not allowed" - ) - if c == "$TTL": - token = self.tok.get() - if not token.is_identifier(): - raise dns.exception.SyntaxError("bad $TTL") - self.default_ttl = dns.ttl.from_text(token.value) - self.default_ttl_known = True - self.tok.get_eol() - elif c == "$ORIGIN": - self.current_origin = self.tok.get_name() - self.tok.get_eol() - if self.zone_origin is None: - self.zone_origin = self.current_origin - self.txn._set_origin(self.current_origin) - elif c == "$INCLUDE": - token = self.tok.get() - filename = token.value - token = self.tok.get() - new_origin: Optional[dns.name.Name] - if token.is_identifier(): - new_origin = dns.name.from_text( - token.value, self.current_origin, self.tok.idna_codec - ) - self.tok.get_eol() - elif not token.is_eol_or_eof(): - raise dns.exception.SyntaxError("bad origin in $INCLUDE") - else: - new_origin = self.current_origin - self.saved_state.append( - ( - self.tok, - self.current_origin, - self.last_name, - self.current_file, - self.last_ttl, - self.last_ttl_known, - self.default_ttl, - self.default_ttl_known, - ) - ) - self.current_file = open(filename) - self.tok = dns.tokenizer.Tokenizer(self.current_file, filename) - self.current_origin = new_origin - elif c == "$GENERATE": - self._generate_line() - else: - raise dns.exception.SyntaxError( - f"Unknown zone file directive '{c}'" - ) - continue - self.tok.unget(token) - self._rr_line() - except dns.exception.SyntaxError as detail: - (filename, line_number) = self.tok.where() - if detail is None: - detail = "syntax error" - ex = dns.exception.SyntaxError( - "%s:%d: %s" % (filename, line_number, detail) - ) - tb = sys.exc_info()[2] - raise ex.with_traceback(tb) from None - - -class RRsetsReaderTransaction(dns.transaction.Transaction): - def __init__(self, manager, replacement, read_only): - assert not read_only - super().__init__(manager, replacement, read_only) - self.rdatasets = {} - - def _get_rdataset(self, name, rdtype, covers): - return self.rdatasets.get((name, rdtype, covers)) - - def _get_node(self, name): - rdatasets = [] - for (rdataset_name, _, _), rdataset in self.rdatasets.items(): - if name == rdataset_name: - rdatasets.append(rdataset) - if len(rdatasets) == 0: - return None - node = dns.node.Node() - node.rdatasets = rdatasets - return node - - def _put_rdataset(self, name, rdataset): - self.rdatasets[(name, rdataset.rdtype, rdataset.covers)] = rdataset - - def _delete_name(self, name): - # First remove any changes involving the name - remove = [] - for key in self.rdatasets: - if key[0] == name: - remove.append(key) - if len(remove) > 0: - for key in remove: - del self.rdatasets[key] - - def _delete_rdataset(self, name, rdtype, covers): - try: - del self.rdatasets[(name, rdtype, covers)] - except KeyError: - pass - - def _name_exists(self, name): - for n, _, _ in self.rdatasets: - if n == name: - return True - return False - - def _changed(self): - return len(self.rdatasets) > 0 - - def _end_transaction(self, commit): - if commit and self._changed(): - rrsets = [] - for (name, _, _), rdataset in self.rdatasets.items(): - rrset = dns.rrset.RRset( - name, rdataset.rdclass, rdataset.rdtype, rdataset.covers - ) - rrset.update(rdataset) - rrsets.append(rrset) - self.manager.set_rrsets(rrsets) - - def _set_origin(self, origin): - pass - - def _iterate_rdatasets(self): - raise NotImplementedError # pragma: no cover - - def _iterate_names(self): - raise NotImplementedError # pragma: no cover - - -class RRSetsReaderManager(dns.transaction.TransactionManager): - def __init__( - self, origin=dns.name.root, relativize=False, rdclass=dns.rdataclass.IN - ): - self.origin = origin - self.relativize = relativize - self.rdclass = rdclass - self.rrsets = [] - - def reader(self): # pragma: no cover - raise NotImplementedError - - def writer(self, replacement=False): - assert replacement is True - return RRsetsReaderTransaction(self, True, False) - - def get_class(self): - return self.rdclass - - def origin_information(self): - if self.relativize: - effective = dns.name.empty - else: - effective = self.origin - return (self.origin, self.relativize, effective) - - def set_rrsets(self, rrsets): - self.rrsets = rrsets - - -def read_rrsets( - text: Any, - name: Optional[Union[dns.name.Name, str]] = None, - ttl: Optional[int] = None, - rdclass: Optional[Union[dns.rdataclass.RdataClass, str]] = dns.rdataclass.IN, - default_rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN, - rdtype: Optional[Union[dns.rdatatype.RdataType, str]] = None, - default_ttl: Optional[Union[int, str]] = None, - idna_codec: Optional[dns.name.IDNACodec] = None, - origin: Optional[Union[dns.name.Name, str]] = dns.name.root, - relativize: bool = False, -) -> List[dns.rrset.RRset]: - """Read one or more rrsets from the specified text, possibly subject - to restrictions. - - *text*, a file object or a string, is the input to process. - - *name*, a string, ``dns.name.Name``, or ``None``, is the owner name of - the rrset. If not ``None``, then the owner name is "forced", and the - input must not specify an owner name. If ``None``, then any owner names - are allowed and must be present in the input. - - *ttl*, an ``int``, string, or None. If not ``None``, the the TTL is - forced to be the specified value and the input must not specify a TTL. - If ``None``, then a TTL may be specified in the input. If it is not - specified, then the *default_ttl* will be used. - - *rdclass*, a ``dns.rdataclass.RdataClass``, string, or ``None``. If - not ``None``, then the class is forced to the specified value, and the - input must not specify a class. If ``None``, then the input may specify - a class that matches *default_rdclass*. Note that it is not possible to - return rrsets with differing classes; specifying ``None`` for the class - simply allows the user to optionally type a class as that may be convenient - when cutting and pasting. - - *default_rdclass*, a ``dns.rdataclass.RdataClass`` or string. The class - of the returned rrsets. - - *rdtype*, a ``dns.rdatatype.RdataType``, string, or ``None``. If not - ``None``, then the type is forced to the specified value, and the - input must not specify a type. If ``None``, then a type must be present - for each RR. - - *default_ttl*, an ``int``, string, or ``None``. If not ``None``, then if - the TTL is not forced and is not specified, then this value will be used. - if ``None``, then if the TTL is not forced an error will occur if the TTL - is not specified. - - *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA - encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder - is used. Note that codecs only apply to the owner name; dnspython does - not do IDNA for names in rdata, as there is no IDNA zonefile format. - - *origin*, a string, ``dns.name.Name``, or ``None``, is the origin for any - relative names in the input, and also the origin to relativize to if - *relativize* is ``True``. - - *relativize*, a bool. If ``True``, names are relativized to the *origin*; - if ``False`` then any relative names in the input are made absolute by - appending the *origin*. - """ - if isinstance(origin, str): - origin = dns.name.from_text(origin, dns.name.root, idna_codec) - if isinstance(name, str): - name = dns.name.from_text(name, origin, idna_codec) - if isinstance(ttl, str): - ttl = dns.ttl.from_text(ttl) - if isinstance(default_ttl, str): - default_ttl = dns.ttl.from_text(default_ttl) - if rdclass is not None: - rdclass = dns.rdataclass.RdataClass.make(rdclass) - else: - rdclass = None - default_rdclass = dns.rdataclass.RdataClass.make(default_rdclass) - if rdtype is not None: - rdtype = dns.rdatatype.RdataType.make(rdtype) - else: - rdtype = None - manager = RRSetsReaderManager(origin, relativize, default_rdclass) - with manager.writer(True) as txn: - tok = dns.tokenizer.Tokenizer(text, "", idna_codec=idna_codec) - reader = Reader( - tok, - default_rdclass, - txn, - allow_directives=False, - force_name=name, - force_ttl=ttl, - force_rdclass=rdclass, - force_rdtype=rdtype, - default_ttl=default_ttl, - ) - reader.read() - return manager.rrsets diff --git a/backend/venv39/lib/python3.9/site-packages/dns/zonetypes.py b/backend/venv39/lib/python3.9/site-packages/dns/zonetypes.py deleted file mode 100644 index 195ee2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dns/zonetypes.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license - -"""Common zone-related types.""" - -# This is a separate file to avoid import circularity between dns.zone and -# the implementation of the ZONEMD type. - -import hashlib - -import dns.enum - - -class DigestScheme(dns.enum.IntEnum): - """ZONEMD Scheme""" - - SIMPLE = 1 - - @classmethod - def _maximum(cls): - return 255 - - -class DigestHashAlgorithm(dns.enum.IntEnum): - """ZONEMD Hash Algorithm""" - - SHA384 = 1 - SHA512 = 2 - - @classmethod - def _maximum(cls): - return 255 - - -_digest_hashers = { - DigestHashAlgorithm.SHA384: hashlib.sha384, - DigestHashAlgorithm.SHA512: hashlib.sha512, -} diff --git a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/METADATA deleted file mode 100644 index ca4a4f4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/METADATA +++ /dev/null @@ -1,149 +0,0 @@ -Metadata-Version: 2.3 -Name: dnspython -Version: 2.7.0 -Summary: DNS toolkit -Project-URL: homepage, https://www.dnspython.org -Project-URL: repository, https://github.com/rthalley/dnspython.git -Project-URL: documentation, https://dnspython.readthedocs.io/en/stable/ -Project-URL: issues, https://github.com/rthalley/dnspython/issues -Author-email: Bob Halley -License: ISC -License-File: LICENSE -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: ISC License (ISCL) -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: POSIX -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Topic :: Internet :: Name Service (DNS) -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.9 -Provides-Extra: dev -Requires-Dist: black>=23.1.0; extra == 'dev' -Requires-Dist: coverage>=7.0; extra == 'dev' -Requires-Dist: flake8>=7; extra == 'dev' -Requires-Dist: hypercorn>=0.16.0; extra == 'dev' -Requires-Dist: mypy>=1.8; extra == 'dev' -Requires-Dist: pylint>=3; extra == 'dev' -Requires-Dist: pytest-cov>=4.1.0; extra == 'dev' -Requires-Dist: pytest>=7.4; extra == 'dev' -Requires-Dist: quart-trio>=0.11.0; extra == 'dev' -Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == 'dev' -Requires-Dist: sphinx>=7.2.0; extra == 'dev' -Requires-Dist: twine>=4.0.0; extra == 'dev' -Requires-Dist: wheel>=0.42.0; extra == 'dev' -Provides-Extra: dnssec -Requires-Dist: cryptography>=43; extra == 'dnssec' -Provides-Extra: doh -Requires-Dist: h2>=4.1.0; extra == 'doh' -Requires-Dist: httpcore>=1.0.0; extra == 'doh' -Requires-Dist: httpx>=0.26.0; extra == 'doh' -Provides-Extra: doq -Requires-Dist: aioquic>=1.0.0; extra == 'doq' -Provides-Extra: idna -Requires-Dist: idna>=3.7; extra == 'idna' -Provides-Extra: trio -Requires-Dist: trio>=0.23; extra == 'trio' -Provides-Extra: wmi -Requires-Dist: wmi>=1.5.1; extra == 'wmi' -Description-Content-Type: text/markdown - -# dnspython - -[![Build Status](https://github.com/rthalley/dnspython/actions/workflows/ci.yml/badge.svg)](https://github.com/rthalley/dnspython/actions/) -[![Documentation Status](https://readthedocs.org/projects/dnspython/badge/?version=latest)](https://dnspython.readthedocs.io/en/latest/?badge=latest) -[![PyPI version](https://badge.fury.io/py/dnspython.svg)](https://badge.fury.io/py/dnspython) -[![License: ISC](https://img.shields.io/badge/License-ISC-brightgreen.svg)](https://opensource.org/licenses/ISC) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) - -## INTRODUCTION - -dnspython is a DNS toolkit for Python. It supports almost all record types. It -can be used for queries, zone transfers, and dynamic updates. It supports TSIG -authenticated messages and EDNS0. - -dnspython provides both high and low level access to DNS. The high level classes -perform queries for data of a given name, type, and class, and return an answer -set. The low level classes allow direct manipulation of DNS zones, messages, -names, and records. - -To see a few of the ways dnspython can be used, look in the `examples/` -directory. - -dnspython is a utility to work with DNS, `/etc/hosts` is thus not used. For -simple forward DNS lookups, it's better to use `socket.getaddrinfo()` or -`socket.gethostbyname()`. - -dnspython originated at Nominum where it was developed -to facilitate the testing of DNS software. - -## ABOUT THIS RELEASE - -This is dnspython 2.7.0. -Please read -[What's New](https://dnspython.readthedocs.io/en/stable/whatsnew.html) for -information about the changes in this release. - -## INSTALLATION - -* Many distributions have dnspython packaged for you, so you should - check there first. -* To use a wheel downloaded from PyPi, run: - - pip install dnspython - -* To install from the source code, go into the top-level of the source code - and run: - -``` - pip install --upgrade pip build - python -m build - pip install dist/*.whl -``` - -* To install the latest from the main branch, run `pip install git+https://github.com/rthalley/dnspython.git` - -Dnspython's default installation does not depend on any modules other than -those in the Python standard library. To use some features, additional modules -must be installed. For convenience, pip options are defined for the -requirements. - -If you want to use DNS-over-HTTPS, run -`pip install dnspython[doh]`. - -If you want to use DNSSEC functionality, run -`pip install dnspython[dnssec]`. - -If you want to use internationalized domain names (IDNA) -functionality, you must run -`pip install dnspython[idna]` - -If you want to use the Trio asynchronous I/O package, run -`pip install dnspython[trio]`. - -If you want to use WMI on Windows to determine the active DNS settings -instead of the default registry scanning method, run -`pip install dnspython[wmi]`. - -If you want to try the experimental DNS-over-QUIC code, run -`pip install dnspython[doq]`. - -Note that you can install any combination of the above, e.g.: -`pip install dnspython[doh,dnssec,idna]` - -### Notices - -Python 2.x support ended with the release of 1.16.0. Dnspython 2.6.x supports -Python 3.8 and later, though support for 3.8 ends on October 14, 2024. -Dnspython 2.7.x supports Python 3.9 and later. Future support is aligned with the -lifetime of the Python 3 versions. - -Documentation has moved to -[dnspython.readthedocs.io](https://dnspython.readthedocs.io). diff --git a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/RECORD deleted file mode 100644 index d2f6b26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/RECORD +++ /dev/null @@ -1,294 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_asyncbackend.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_asyncio_backend.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_ddr.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_features.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_immutable_ctx.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/_trio_backend.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/asyncbackend.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/asyncquery.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/asyncresolver.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssec.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/cryptography.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/dsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/ecdsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/eddsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssecalgs/rsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/dnssectypes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/e164.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/edns.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/entropy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/enum.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/exception.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/flags.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/grange.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/immutable.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/inet.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/ipv4.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/ipv6.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/name.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/namedict.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/nameserver.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/node.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/opcode.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/query.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/quic/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/quic/_asyncio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/quic/_common.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/quic/_sync.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/quic/_trio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rcode.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdata.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdataclass.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdataset.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdatatype.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AFSDB.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AMTRELAY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/AVC.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CAA.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDNSKEY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CDS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CERT.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CNAME.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/CSYNC.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DLV.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNAME.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DNSKEY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/DS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI48.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/EUI64.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/GPOS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HINFO.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/HIP.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ISDN.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L32.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/L64.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LOC.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/LP.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/MX.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NID.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NINFO.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/NSEC3PARAM.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPENPGPKEY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/OPT.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/PTR.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RESINFO.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RP.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RRSIG.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/RT.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SMIMEA.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SOA.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SPF.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/SSHFP.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TKEY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TLSA.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TSIG.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/TXT.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/URI.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/WALLET.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/X25.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/ZONEMD.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/ANY/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/A.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/CH/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/A.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/AAAA.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/APL.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/DHCID.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/HTTPS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/IPSECKEY.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/KX.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NAPTR.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/NSAP_PTR.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/PX.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SRV.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/SVCB.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/WKS.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/IN/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dnskeybase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/dsbase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/euibase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/mxbase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/nsbase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/svcbbase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/tlsabase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/txtbase.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rdtypes/util.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/renderer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/resolver.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/reversename.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/rrset.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/serial.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/set.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/tokenizer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/transaction.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/tsig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/tsigkeyring.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/ttl.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/update.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/version.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/versioned.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/win32util.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/wire.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/xfr.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/zone.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/zonefile.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/dns/zonetypes.cpython-39.pyc,, -dns/__init__.py,sha256=YJZtDG14Idw5ui3h1nWooSwPM9gsxQgB8M0GBZ3aly0,1663 -dns/_asyncbackend.py,sha256=pamIAWJ73e7ic2u7Q3RJyG6_6L8t78ccttvi65682MM,2396 -dns/_asyncio_backend.py,sha256=iLqhcUXqnFWC_2tcAp9U00NOGxT5GKPn4qeXS4iKaro,9051 -dns/_ddr.py,sha256=rHXKC8kncCTT9N4KBh1flicl79nyDjQ-DDvq30MJ3B8,5247 -dns/_features.py,sha256=Ig_leAKUT9RDiOVOfA0nXmmqpiPfnOnP9TcxlISUGSk,2492 -dns/_immutable_ctx.py,sha256=gtoCLMmdHXI23zt5lRSIS3A4Ca3jZJngebdoFFOtiwU,2459 -dns/_trio_backend.py,sha256=IXNdUP1MUBPyZRgAFhGH71KHtUCh3Rm5dM8SX4bMj2U,8473 -dns/asyncbackend.py,sha256=82fXTFls_m7F_ekQbgUGOkoBbs4BI-GBLDZAWNGUvJ0,2796 -dns/asyncquery.py,sha256=PMZ_D4Z8vgSioWHftyxNw7eax1IqrPleqY5FIi40hd8,30821 -dns/asyncresolver.py,sha256=GD86dCyW9YGKs6SggWXwBKEXifW7Qdx4cEAGFKY6fA4,17852 -dns/dnssec.py,sha256=gXmIrbKK1t1hE8ht-WlhUc0giy1PpLYj07r6o0pVATY,41717 -dns/dnssecalgs/__init__.py,sha256=OWvTadxZ3oF5PxVGodNimxBt_-3YUNTOSV62HrIb4PQ,4331 -dns/dnssecalgs/base.py,sha256=jlTV_nd1Nqkvqyf-FVHIccXKFrE2LL6GVu6AW8QUh2E,2513 -dns/dnssecalgs/cryptography.py,sha256=3uqMfRm-zCkJPOrxUqlu9CmdxIMy71dVor9eAHi0wZM,2425 -dns/dnssecalgs/dsa.py,sha256=DNO68g_lbG7_oKcDN8c2xuzYRPbLaZc9Ns7oQoa0Vbc,3564 -dns/dnssecalgs/ecdsa.py,sha256=RfvFKRNExsYgd5SoXXRxMHkoBeF2Gktkz2rOwObEYAY,3172 -dns/dnssecalgs/eddsa.py,sha256=7VGARpVUzIYRjPh0gFapTPFzmsK8WJDqDZDLw2KLc8w,1981 -dns/dnssecalgs/rsa.py,sha256=_tNABpr6iwd8STBEHYIXfyLrgBpRNCj8K0UQj32_kOU,3622 -dns/dnssectypes.py,sha256=CyeuGTS_rM3zXr8wD9qMT9jkzvVfTY2JWckUcogG83E,1799 -dns/e164.py,sha256=EsK8cnOtOx7kQ0DmSwibcwkzp6efMWjbRiTyHZO8Q-M,3978 -dns/edns.py,sha256=-XDhC2jr7BRLsJrpCAWShxLn-3eG1oI0HhduWhLxdMw,17089 -dns/entropy.py,sha256=qkG8hXDLzrJS6R5My26iA59c0RhPwJNzuOhOCAZU5Bw,4242 -dns/enum.py,sha256=EepaunPKixTSrascy7iAe9UQEXXxP_MB5Gx4jUpHIhg,3691 -dns/exception.py,sha256=8vjxLf4T3T77vfANe_iKVeButAEhSJve6UrPjiBzht4,5953 -dns/flags.py,sha256=cQ3kTFyvcKiWHAxI5AwchNqxVOrsIrgJ6brgrH42Wq8,2750 -dns/grange.py,sha256=D016OrOv3i44G3mb_CzPFjDk61uZ6BMRib3yJnDQvbw,2144 -dns/immutable.py,sha256=InrtpKvPxl-74oYbzsyneZwAuX78hUqeG22f2aniZbk,2017 -dns/inet.py,sha256=j6jQs3K_ehVhDv-i4jwCKePr5HpEiSzvOXQ4uhgn1sU,5772 -dns/ipv4.py,sha256=qEUXtlqWDH_blicj6VMvyQhfX7-BF0gB_lWJliV-2FI,2552 -dns/ipv6.py,sha256=Ww8ayshM6FxtQsRYdXXuKkPFTad5ZcGbBd9lr1nFct4,6554 -dns/message.py,sha256=QOtdFBEAORhTKN0uQg86uSNvthdxJx40HhMQXYCBHng,68185 -dns/name.py,sha256=Bf3170QHhLFLDnMsWeJyik4i9ucBDbIY6Bydcz8H-2o,42778 -dns/namedict.py,sha256=hJRYpKeQv6Bd2LaUOPV0L_a0eXEIuqgggPXaH4c3Tow,4000 -dns/nameserver.py,sha256=hH4LLOkB4jeyO3VDUWK0lNpMJNNt_cFYf23-HdhpSmE,10115 -dns/node.py,sha256=NGZa0AUMq-CNledJ6wn1Rx6TFYc703cH2OraLysoNWM,12663 -dns/opcode.py,sha256=I6JyuFUL0msja_BYm6bzXHfbbfqUod_69Ss4xcv8xWQ,2730 -dns/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -dns/query.py,sha256=_Ev7EivZNEpgrUiPIn4BVnDRFCizcayHHcBXt0Ju3As,56298 -dns/quic/__init__.py,sha256=S5_2UuYzSU_LLtrLAf8DHh3KqNF2YHeKJ_-Wv991WlI,2272 -dns/quic/_asyncio.py,sha256=dnABPz5f-JOJsA7D_BdPfuyzpkL_87AaY4CUcmgNj-g,9870 -dns/quic/_common.py,sha256=koWf6rq9_gUorIOV60QZKAHwZF5MuSgQvBznzA5rGzk,10857 -dns/quic/_sync.py,sha256=QF-dW19NwiDW_BDoJZkSQmHz2uEpfgedsUKTPc0JAio,10436 -dns/quic/_trio.py,sha256=01HH4_hU1VRx-BWXl8bQo4-LZem_eKRBNy6RolTZZXY,9248 -dns/rcode.py,sha256=N6JjrIQjCdJy0boKIp8Hcky5tm__LSDscpDz3rE_sgU,4156 -dns/rdata.py,sha256=uk82eldqpWR8L2zp_CB8JG6wWWfK7zdYowWISfMC2XE,31022 -dns/rdataclass.py,sha256=TK4W4ywB1L_X7EZqk2Gmwnu7vdQpolQF5DtQWyNk5xo,2984 -dns/rdataset.py,sha256=BMNvGAzE4HfYHA-pnhsKwELfpr-saz73BzYwMucoKj0,16664 -dns/rdatatype.py,sha256=wgKWnu4mAbXnmG8wKHpV8dZHkhMqNeSsWWlWFo5HcDY,7448 -dns/rdtypes/ANY/AFSDB.py,sha256=k75wMwreF1DAfDymu4lHh16BUx7ulVP3PLeQBZnkurY,1661 -dns/rdtypes/ANY/AMTRELAY.py,sha256=19jfS61mT1CQT-8vf67ZylhDS9JVRVp4WCbFE-7l0jM,3381 -dns/rdtypes/ANY/AVC.py,sha256=SpsXYzlBirRWN0mGnQe0MdN6H8fvlgXPJX5PjOHnEak,1024 -dns/rdtypes/ANY/CAA.py,sha256=AHh59Is-4WiVWd26yovnPM3hXqKS-yx7IWfXSS0NZhE,2511 -dns/rdtypes/ANY/CDNSKEY.py,sha256=bJAdrBMsFHIJz8TF1AxZoNbdxVWBCRTG-bR_uR_r_G4,1225 -dns/rdtypes/ANY/CDS.py,sha256=Y9nIRUCAabztVLbxm2SXAdYapFemCOUuGh5JqroCDUs,1163 -dns/rdtypes/ANY/CERT.py,sha256=2Cu2LQM6-K4darqhHv1EM_blmpYpnrBIIX1GnL_rxKE,3533 -dns/rdtypes/ANY/CNAME.py,sha256=IHGGq2BDpeKUahTr1pvyBQgm0NGBI_vQ3Vs5mKTXO4w,1206 -dns/rdtypes/ANY/CSYNC.py,sha256=KkZ_rG6PfeL14il97nmJGWWmUGGS5o9nd2EqbJqOuYo,2439 -dns/rdtypes/ANY/DLV.py,sha256=J-pOrw5xXsDoaB9G0r6znlYXJtqtcqhsl1OXs6CPRU4,986 -dns/rdtypes/ANY/DNAME.py,sha256=yqXRtx4dAWwB4YCCv-qW6uaxeGhg2LPQ2uyKwWaMdXs,1150 -dns/rdtypes/ANY/DNSKEY.py,sha256=MD8HUVH5XXeAGOnFWg5aVz_w-2tXYwCeVXmzExhiIeQ,1223 -dns/rdtypes/ANY/DS.py,sha256=_gf8vk1O_uY8QXFjsfUw-bny-fm6e-QpCk3PT0JCyoM,995 -dns/rdtypes/ANY/EUI48.py,sha256=x0BkK0sY_tgzuCwfDYpw6tyuChHjjtbRpAgYhO0Y44o,1151 -dns/rdtypes/ANY/EUI64.py,sha256=1jCff2-SXHJLDnNDnMW8Cd_o-ok0P3x6zKy_bcCU5h4,1161 -dns/rdtypes/ANY/GPOS.py,sha256=u4qwiDBVoC7bsKfxDKGbPjnOKddpdjy2p1AhziDWcPw,4439 -dns/rdtypes/ANY/HINFO.py,sha256=D2WvjTsvD_XqT8BepBIyjPL2iYGMgYqb1VQa9ApO0qE,2217 -dns/rdtypes/ANY/HIP.py,sha256=c32Ewlk88schJ1nPOmT5BVR60ttIM-uH8I8LaRAkFOA,3226 -dns/rdtypes/ANY/ISDN.py,sha256=L4C2Rxrr4JJN17lmJRbZN8RhM_ujjwIskY_4V4Gd3r4,2723 -dns/rdtypes/ANY/L32.py,sha256=TMz2kdGCd0siiQZyiocVDCSnvkOdjhUuYRFyf8o622M,1286 -dns/rdtypes/ANY/L64.py,sha256=sb2BjuPA0PQt67nEyT9rBt759C9e6lH71d3EJHGGnww,1592 -dns/rdtypes/ANY/LOC.py,sha256=NZKIUJULZ3BcK1-gnb2Mk76Pc4UUZry47C5n9VBvhnk,11995 -dns/rdtypes/ANY/LP.py,sha256=wTsKIjtK6vh66qZRLSsiE0k54GO8ieVBGZH8dzVvFnE,1338 -dns/rdtypes/ANY/MX.py,sha256=qQk83idY0-SbRMDmB15JOpJi7cSyiheF-ALUD0Ev19E,995 -dns/rdtypes/ANY/NID.py,sha256=N7Xx4kXf3yVAocTlCXQeJ3BtiQNPFPQVdL1iMuyl5W4,1544 -dns/rdtypes/ANY/NINFO.py,sha256=bdL_-6Bejb2EH-xwR1rfSr_9E3SDXLTAnov7x2924FI,1041 -dns/rdtypes/ANY/NS.py,sha256=ThfaPalUlhbyZyNyvBM3k-7onl3eJKq5wCORrOGtkMM,995 -dns/rdtypes/ANY/NSEC.py,sha256=kicEYxcKaLBpV6C_M8cHdDaqBoiYl6EYtPvjyR6kExI,2465 -dns/rdtypes/ANY/NSEC3.py,sha256=696h-Zz30bmcT0n1rqoEtS5wqE6jIgsVGzaw5TfdGJo,4331 -dns/rdtypes/ANY/NSEC3PARAM.py,sha256=08p6NWS4DiLav1wOuPbxUxB9MtY2IPjfOMCtJwzzMuA,2635 -dns/rdtypes/ANY/OPENPGPKEY.py,sha256=Va0FGo_8vm1OeX62N5iDTWukAdLwrjTXIZeQ6oanE78,1851 -dns/rdtypes/ANY/OPT.py,sha256=W36RslT_Psp95OPUC70knumOYjKpaRHvGT27I-NV2qc,2561 -dns/rdtypes/ANY/PTR.py,sha256=5HcR1D77Otyk91vVY4tmqrfZfSxSXWyWvwIW-rIH5gc,997 -dns/rdtypes/ANY/RESINFO.py,sha256=Kf2NcKbkeI5gFE1bJfQNqQCaitYyXfV_9nQYl1luUZ0,1008 -dns/rdtypes/ANY/RP.py,sha256=8doJlhjYDYiAT6KNF1mAaemJ20YJFUPvit8LOx4-I-U,2174 -dns/rdtypes/ANY/RRSIG.py,sha256=O8vwzS7ldfaj_x8DypvEGFsDSb7al-D7OEnprA3QQoo,4922 -dns/rdtypes/ANY/RT.py,sha256=2t9q3FZQ28iEyceeU25KU2Ur0T5JxELAu8BTwfOUgVw,1013 -dns/rdtypes/ANY/SMIMEA.py,sha256=6yjHuVDfIEodBU9wxbCGCDZ5cWYwyY6FCk-aq2VNU0s,222 -dns/rdtypes/ANY/SOA.py,sha256=Cn8yrag1YvrvwivQgWg-KXmOCaVQVdFHSkFF77w-CE0,3145 -dns/rdtypes/ANY/SPF.py,sha256=rA3Srs9ECQx-37lqm7Zf7aYmMpp_asv4tGS8_fSQ-CU,1022 -dns/rdtypes/ANY/SSHFP.py,sha256=l6TZH2R0kytiZGWez_g-Lq94o5a2xMuwLKwUwsPMx5w,2530 -dns/rdtypes/ANY/TKEY.py,sha256=1ecTuBse2b4QPH2qmx3vn-gfPK0INcKXfxrIyAJxFHA,4927 -dns/rdtypes/ANY/TLSA.py,sha256=cytzebS3W7FFr9qeJ9gFSHq_bOwUk9aRVlXWHfnVrRs,218 -dns/rdtypes/ANY/TSIG.py,sha256=4fNQJSNWZXUKZejCciwQuUJtTw2g-YbPmqHrEj_pitg,4750 -dns/rdtypes/ANY/TXT.py,sha256=F1U9gIAhwXIV4UVT7CwOCEn_su6G1nJIdgWJsLktk20,1000 -dns/rdtypes/ANY/URI.py,sha256=dpcS8KwcJ2WJ7BkOp4CZYaUyRuw7U2S9GzvVwKUihQg,2921 -dns/rdtypes/ANY/WALLET.py,sha256=IaP2g7Nq26jWGKa8MVxvJjWXLQ0wrNR1IWJVyyMG8oU,219 -dns/rdtypes/ANY/X25.py,sha256=BzEM7uOY7CMAm7QN-dSLj-_LvgnnohwJDUjMstzwqYo,1942 -dns/rdtypes/ANY/ZONEMD.py,sha256=JQicv69EvUxh4FCT7eZSLzzU5L5brw_dSM65Um2t5lQ,2393 -dns/rdtypes/ANY/__init__.py,sha256=My5jT8T5bA66zBydmRSxkmDCFxwI81B4DBRA_S36IL8,1526 -dns/rdtypes/CH/A.py,sha256=-4G3ASZGj7oUlPfDxADibAB1WfTsZBavUO8ghDWarJ8,2212 -dns/rdtypes/CH/__init__.py,sha256=GD9YeDKb9VBDo-J5rrChX1MWEGyQXuR9Htnbhg_iYLc,923 -dns/rdtypes/IN/A.py,sha256=FfFn3SqbpneL9Ky63COP50V2ZFxqS1ldCKJh39Enwug,1814 -dns/rdtypes/IN/AAAA.py,sha256=AxrOlYy-1TTTWeQypDKeXrDCrdHGor0EKCE4fxzSQGo,1820 -dns/rdtypes/IN/APL.py,sha256=ppyFwn0KYMdyDzphxd0BUhgTmZv0QnDMRLjzQQM793U,5097 -dns/rdtypes/IN/DHCID.py,sha256=zRUh_EOxUPVpJjWY5m7taX8q4Oz5K70785ZtKv5OTCU,1856 -dns/rdtypes/IN/HTTPS.py,sha256=P-IjwcvDQMmtoBgsDHglXF7KgLX73G6jEDqCKsnaGpQ,220 -dns/rdtypes/IN/IPSECKEY.py,sha256=RyIy9K0Yt0uJRjdr6cj5S95ELHHbl--0xV-Qq9O3QQk,3290 -dns/rdtypes/IN/KX.py,sha256=K1JwItL0n5G-YGFCjWeh0C9DyDD8G8VzicsBeQiNAv0,1013 -dns/rdtypes/IN/NAPTR.py,sha256=SaOK-0hIYImwLtb5Hqewi-e49ykJaQiLNvk8ZzNoG7Q,3750 -dns/rdtypes/IN/NSAP.py,sha256=6YfWCVSIPTTBmRAzG8nVBj3LnohncXUhSFJHgp-TRdc,2163 -dns/rdtypes/IN/NSAP_PTR.py,sha256=iTxlV6fr_Y9lqivLLncSHxEhmFqz5UEElDW3HMBtuCU,1015 -dns/rdtypes/IN/PX.py,sha256=vHDNN2rfLObuUKwpYDIvpPB482BqXlHA-ZQpQn9Sb_E,2756 -dns/rdtypes/IN/SRV.py,sha256=a0zGaUwzvih_a4Q9BViUTFs7NZaCqgl7mls3-KRVHm8,2769 -dns/rdtypes/IN/SVCB.py,sha256=HeFmi2v01F00Hott8FlvQ4R7aPxFmT7RF-gt45R5K_M,218 -dns/rdtypes/IN/WKS.py,sha256=kErSG5AO2qIuot_hkMHnQuZB1_uUzUirNdqBoCp97rk,3652 -dns/rdtypes/IN/__init__.py,sha256=HbI8aw9HWroI6SgEvl8Sx6FdkDswCCXMbSRuJy5o8LQ,1083 -dns/rdtypes/__init__.py,sha256=NYizfGglJfhqt_GMtSSXf7YQXIEHHCiJ_Y_qaLVeiOI,1073 -dns/rdtypes/dnskeybase.py,sha256=FoDllfa9Pz2j2rf45VyUUYUsIt3kjjrwDy6LxrlPb5s,2856 -dns/rdtypes/dsbase.py,sha256=I85Aps1lBsiItdqGpsNY1O8icosfPtkWjiUn1J1lLUQ,3427 -dns/rdtypes/euibase.py,sha256=1yKWOM4xBwLLIFFfEj7M9JMankO2l8ljxhG-5OOxXDg,2618 -dns/rdtypes/mxbase.py,sha256=DzjbiKoAAgpqbhwMBIFGA081jR5_doqGAq-kLvy2mns,3196 -dns/rdtypes/nsbase.py,sha256=tueXVV6E8lelebOmrmoOPq47eeRvOpsxHVXH4cOFxcs,2323 -dns/rdtypes/svcbbase.py,sha256=YOH3Wz3fp5GQjdTF7hU-1ys9iDkYEC5p4d0F32ivv5g,17612 -dns/rdtypes/tlsabase.py,sha256=pIiWem6sF4IwyyKmyqx5xg55IG0w3K9r502Yx8PdziA,2596 -dns/rdtypes/txtbase.py,sha256=Dt9ptWSWtnq0Qwlni6IT6YUz_DCixQDDUl5d4P_AfqY,3696 -dns/rdtypes/util.py,sha256=c3eLaucwuxXZjXWuNyCGKzwltgub4AjT4uLVytEuxSk,9017 -dns/renderer.py,sha256=5THf1iKql2JPL2sKZt2-b4zqHKfk_vlx0FEfPtMJysY,11254 -dns/resolver.py,sha256=FH_hiMeCdVYonIYmE3QqEWJKgHOOxlTcHS0dwd_loGY,73730 -dns/reversename.py,sha256=zoqXEbMZXm6R13nXbJHgTsf6L2C6uReODj6mqSHrTiE,3828 -dns/rrset.py,sha256=J-oQPEPJuKueLLiz1FN08P-ys9fjHhPWuwpDdrL4UTQ,9170 -dns/serial.py,sha256=-t5rPW-TcJwzBMfIJo7Tl-uDtaYtpqOfCVYx9dMaDCY,3606 -dns/set.py,sha256=hublMKCIhd9zp5Hz_fvQTwF-Ze28jn7mjqei6vTGWfs,9213 -dns/tokenizer.py,sha256=65vVkEeTuml3l2AT-NePE6Gt6ucDQNvSpeIVgMpP6G0,23583 -dns/transaction.py,sha256=UhwD6CLQI51dguuz__dxJS8V91vKAoqHdQDCBErJWxE,22589 -dns/tsig.py,sha256=I-Y-c3WMBX11bVioy5puFly2BhlpptUz82ikahxuh1c,11413 -dns/tsigkeyring.py,sha256=Z0xZemcU3XjZ9HlxBYv2E2PSuIhaFreqLDlD7HcmZDA,2633 -dns/ttl.py,sha256=Y4inc4bvkfKpogZn5i1n-tpg1CAjDJxH4_HvfeVjVsM,2977 -dns/update.py,sha256=y9d6LOO8xrUaH2UrZhy3ssnx8bJEsxqTArw5V8XqBRs,12243 -dns/version.py,sha256=GTecBDFJx8cKnGiCmxJhSVjk1EkqnuNVt4xailIi3sk,1926 -dns/versioned.py,sha256=3YQj8mzGmZEsjnuVJJjcWopVmDKYLhEj4hEGTLEwzco,11765 -dns/win32util.py,sha256=r9dOvC0Tq288vwPk-ngugsVpwB5YnfW22DaRv6TTPcU,8874 -dns/wire.py,sha256=vy0SolgECbO1UXB4dnhXhDeFKOJT29nQxXvSfKOgA5s,2830 -dns/xfr.py,sha256=aoW0UtvweaE0NV8cmzgMKLYQOa3hwJ3NudRuqjit4SU,13271 -dns/zone.py,sha256=lLAarSxPtpx4Sw29OQ0ifPshD4QauGu8RnPh2dEropA,52086 -dns/zonefile.py,sha256=Y9lm6I7n4eRS35CyclooiQ_jxiOs3pSyH_0uD4FQyag,27926 -dns/zonetypes.py,sha256=HrQNZxZ_gWLWI9dskix71msi9wkYK5pgrBBbPb1T74Y,690 -dnspython-2.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -dnspython-2.7.0.dist-info/METADATA,sha256=1lF6uqZwb6RAQFYVtBkLic6pBCe9t14TQWtkK9U5eyY,5763 -dnspython-2.7.0.dist-info/RECORD,, -dnspython-2.7.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87 -dnspython-2.7.0.dist-info/licenses/LICENSE,sha256=w-o_9WVLMpwZ07xfdIGvYjw93tSmFFWFSZ-EOtPXQc0,1526 diff --git a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/WHEEL deleted file mode 100644 index cdd68a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.25.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/licenses/LICENSE deleted file mode 100644 index 390a726..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dnspython-2.7.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,35 +0,0 @@ -ISC License - -Copyright (C) Dnspython Contributors - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all -copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - - - -Copyright (C) 2001-2017 Nominum, Inc. -Copyright (C) Google Inc. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose with or without fee is hereby granted, -provided that the above copyright notice and this permission notice -appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/__init__.py b/backend/venv39/lib/python3.9/site-packages/dotenv/__init__.py deleted file mode 100644 index dde24a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Any, Optional - -from .main import dotenv_values, find_dotenv, get_key, load_dotenv, set_key, unset_key - - -def load_ipython_extension(ipython: Any) -> None: - from .ipython import load_ipython_extension - - load_ipython_extension(ipython) - - -def get_cli_string( - path: Optional[str] = None, - action: Optional[str] = None, - key: Optional[str] = None, - value: Optional[str] = None, - quote: Optional[str] = None, -): - """Returns a string suitable for running as a shell script. - - Useful for converting a arguments passed to a fabric task - to be passed to a `local` or `run` command. - """ - command = ["dotenv"] - if quote: - command.append(f"-q {quote}") - if path: - command.append(f"-f {path}") - if action: - command.append(action) - if key: - command.append(key) - if value: - if " " in value: - command.append(f'"{value}"') - else: - command.append(value) - - return " ".join(command).strip() - - -__all__ = [ - "get_cli_string", - "load_dotenv", - "dotenv_values", - "get_key", - "set_key", - "unset_key", - "find_dotenv", - "load_ipython_extension", -] diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/__main__.py b/backend/venv39/lib/python3.9/site-packages/dotenv/__main__.py deleted file mode 100644 index 3977f55..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Entry point for cli, enables execution with `python -m dotenv`""" - -from .cli import cli - -if __name__ == "__main__": - cli() diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/cli.py b/backend/venv39/lib/python3.9/site-packages/dotenv/cli.py deleted file mode 100644 index c548aa3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/cli.py +++ /dev/null @@ -1,218 +0,0 @@ -import json -import os -import shlex -import sys -from contextlib import contextmanager -from typing import IO, Any, Dict, Iterator, List, Optional - -if sys.platform == "win32": - from subprocess import Popen - -try: - import click -except ImportError: - sys.stderr.write( - "It seems python-dotenv is not installed with cli option. \n" - 'Run pip install "python-dotenv[cli]" to fix this.' - ) - sys.exit(1) - -from .main import dotenv_values, set_key, unset_key -from .version import __version__ - - -def enumerate_env() -> Optional[str]: - """ - Return a path for the ${pwd}/.env file. - - If pwd does not exist, return None. - """ - try: - cwd = os.getcwd() - except FileNotFoundError: - return None - path = os.path.join(cwd, ".env") - return path - - -@click.group() -@click.option( - "-f", - "--file", - default=enumerate_env(), - type=click.Path(file_okay=True), - help="Location of the .env file, defaults to .env file in current working directory.", -) -@click.option( - "-q", - "--quote", - default="always", - type=click.Choice(["always", "never", "auto"]), - help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.", -) -@click.option( - "-e", - "--export", - default=False, - type=click.BOOL, - help="Whether to write the dot file as an executable bash script.", -) -@click.version_option(version=__version__) -@click.pass_context -def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None: - """This script is used to set, get or unset values from a .env file.""" - ctx.obj = {"QUOTE": quote, "EXPORT": export, "FILE": file} - - -@contextmanager -def stream_file(path: os.PathLike) -> Iterator[IO[str]]: - """ - Open a file and yield the corresponding (decoded) stream. - - Exits with error code 2 if the file cannot be opened. - """ - - try: - with open(path) as stream: - yield stream - except OSError as exc: - print(f"Error opening env file: {exc}", file=sys.stderr) - sys.exit(2) - - -@cli.command(name="list") -@click.pass_context -@click.option( - "--format", - "output_format", - default="simple", - type=click.Choice(["simple", "json", "shell", "export"]), - help="The format in which to display the list. Default format is simple, " - "which displays name=value without quotes.", -) -def list_values(ctx: click.Context, output_format: str) -> None: - """Display all the stored key/value.""" - file = ctx.obj["FILE"] - - with stream_file(file) as stream: - values = dotenv_values(stream=stream) - - if output_format == "json": - click.echo(json.dumps(values, indent=2, sort_keys=True)) - else: - prefix = "export " if output_format == "export" else "" - for k in sorted(values): - v = values[k] - if v is not None: - if output_format in ("export", "shell"): - v = shlex.quote(v) - click.echo(f"{prefix}{k}={v}") - - -@cli.command(name="set") -@click.pass_context -@click.argument("key", required=True) -@click.argument("value", required=True) -def set_value(ctx: click.Context, key: Any, value: Any) -> None: - """Store the given key/value.""" - file = ctx.obj["FILE"] - quote = ctx.obj["QUOTE"] - export = ctx.obj["EXPORT"] - success, key, value = set_key(file, key, value, quote, export) - if success: - click.echo(f"{key}={value}") - else: - sys.exit(1) - - -@cli.command() -@click.pass_context -@click.argument("key", required=True) -def get(ctx: click.Context, key: Any) -> None: - """Retrieve the value for the given key.""" - file = ctx.obj["FILE"] - - with stream_file(file) as stream: - values = dotenv_values(stream=stream) - - stored_value = values.get(key) - if stored_value: - click.echo(stored_value) - else: - sys.exit(1) - - -@cli.command() -@click.pass_context -@click.argument("key", required=True) -def unset(ctx: click.Context, key: Any) -> None: - """Removes the given key.""" - file = ctx.obj["FILE"] - quote = ctx.obj["QUOTE"] - success, key = unset_key(file, key, quote) - if success: - click.echo(f"Successfully removed {key}") - else: - sys.exit(1) - - -@cli.command(context_settings={"ignore_unknown_options": True}) -@click.pass_context -@click.option( - "--override/--no-override", - default=True, - help="Override variables from the environment file with those from the .env file.", -) -@click.argument("commandline", nargs=-1, type=click.UNPROCESSED) -def run(ctx: click.Context, override: bool, commandline: List[str]) -> None: - """Run command with environment variables present.""" - file = ctx.obj["FILE"] - if not os.path.isfile(file): - raise click.BadParameter( - f"Invalid value for '-f' \"{file}\" does not exist.", ctx=ctx - ) - dotenv_as_dict = { - k: v - for (k, v) in dotenv_values(file).items() - if v is not None and (override or k not in os.environ) - } - - if not commandline: - click.echo("No command given.") - sys.exit(1) - run_command(commandline, dotenv_as_dict) - - -def run_command(command: List[str], env: Dict[str, str]) -> None: - """Replace the current process with the specified command. - - Replaces the current process with the specified command and the variables from `env` - added in the current environment variables. - - Parameters - ---------- - command: List[str] - The command and it's parameters - env: Dict - The additional environment variables - - Returns - ------- - None - This function does not return any value. It replaces the current process with the new one. - - """ - # copy the current environment variables and add the vales from - # `env` - cmd_env = os.environ.copy() - cmd_env.update(env) - - if sys.platform == "win32": - # execvpe on Windows returns control immediately - # rather than once the command has finished. - p = Popen(command, universal_newlines=True, bufsize=0, shell=False, env=cmd_env) - _, _ = p.communicate() - - sys.exit(p.returncode) - else: - os.execvpe(command[0], args=command, env=cmd_env) diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/ipython.py b/backend/venv39/lib/python3.9/site-packages/dotenv/ipython.py deleted file mode 100644 index 4e7edbb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/ipython.py +++ /dev/null @@ -1,50 +0,0 @@ -from IPython.core.magic import Magics, line_magic, magics_class # type: ignore -from IPython.core.magic_arguments import ( - argument, - magic_arguments, - parse_argstring, -) # type: ignore - -from .main import find_dotenv, load_dotenv - - -@magics_class -class IPythonDotEnv(Magics): - @magic_arguments() - @argument( - "-o", - "--override", - action="store_true", - help="Indicate to override existing variables", - ) - @argument( - "-v", - "--verbose", - action="store_true", - help="Indicate function calls to be verbose", - ) - @argument( - "dotenv_path", - nargs="?", - type=str, - default=".env", - help="Search in increasingly higher folders for the `dotenv_path`", - ) - @line_magic - def dotenv(self, line): - args = parse_argstring(self.dotenv, line) - # Locate the .env file - dotenv_path = args.dotenv_path - try: - dotenv_path = find_dotenv(dotenv_path, True, True) - except IOError: - print("cannot find .env file") - return - - # Load the .env file - load_dotenv(dotenv_path, verbose=args.verbose, override=args.override) - - -def load_ipython_extension(ipython): - """Register the %dotenv magic.""" - ipython.register_magics(IPythonDotEnv) diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/main.py b/backend/venv39/lib/python3.9/site-packages/dotenv/main.py deleted file mode 100644 index 1d6bf0b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/main.py +++ /dev/null @@ -1,435 +0,0 @@ -import io -import logging -import os -import pathlib -import shutil -import stat -import sys -import tempfile -from collections import OrderedDict -from contextlib import contextmanager -from typing import IO, Dict, Iterable, Iterator, Mapping, Optional, Tuple, Union - -from .parser import Binding, parse_stream -from .variables import parse_variables - -# A type alias for a string path to be used for the paths in this file. -# These paths may flow to `open()` and `shutil.move()`; `shutil.move()` -# only accepts string paths, not byte paths or file descriptors. See -# https://github.com/python/typeshed/pull/6832. -StrPath = Union[str, "os.PathLike[str]"] - -logger = logging.getLogger(__name__) - - -def _load_dotenv_disabled() -> bool: - """ - Determine if dotenv loading has been disabled. - """ - if "PYTHON_DOTENV_DISABLED" not in os.environ: - return False - value = os.environ["PYTHON_DOTENV_DISABLED"].casefold() - return value in {"1", "true", "t", "yes", "y"} - - -def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]: - for mapping in mappings: - if mapping.error: - logger.warning( - "python-dotenv could not parse statement starting at line %s", - mapping.original.line, - ) - yield mapping - - -class DotEnv: - def __init__( - self, - dotenv_path: Optional[StrPath], - stream: Optional[IO[str]] = None, - verbose: bool = False, - encoding: Optional[str] = None, - interpolate: bool = True, - override: bool = True, - ) -> None: - self.dotenv_path: Optional[StrPath] = dotenv_path - self.stream: Optional[IO[str]] = stream - self._dict: Optional[Dict[str, Optional[str]]] = None - self.verbose: bool = verbose - self.encoding: Optional[str] = encoding - self.interpolate: bool = interpolate - self.override: bool = override - - @contextmanager - def _get_stream(self) -> Iterator[IO[str]]: - if self.dotenv_path and _is_file_or_fifo(self.dotenv_path): - with open(self.dotenv_path, encoding=self.encoding) as stream: - yield stream - elif self.stream is not None: - yield self.stream - else: - if self.verbose: - logger.info( - "python-dotenv could not find configuration file %s.", - self.dotenv_path or ".env", - ) - yield io.StringIO("") - - def dict(self) -> Dict[str, Optional[str]]: - """Return dotenv as dict""" - if self._dict: - return self._dict - - raw_values = self.parse() - - if self.interpolate: - self._dict = OrderedDict( - resolve_variables(raw_values, override=self.override) - ) - else: - self._dict = OrderedDict(raw_values) - - return self._dict - - def parse(self) -> Iterator[Tuple[str, Optional[str]]]: - with self._get_stream() as stream: - for mapping in with_warn_for_invalid_lines(parse_stream(stream)): - if mapping.key is not None: - yield mapping.key, mapping.value - - def set_as_environment_variables(self) -> bool: - """ - Load the current dotenv as system environment variable. - """ - if not self.dict(): - return False - - for k, v in self.dict().items(): - if k in os.environ and not self.override: - continue - if v is not None: - os.environ[k] = v - - return True - - def get(self, key: str) -> Optional[str]: - """ """ - data = self.dict() - - if key in data: - return data[key] - - if self.verbose: - logger.warning("Key %s not found in %s.", key, self.dotenv_path) - - return None - - -def get_key( - dotenv_path: StrPath, - key_to_get: str, - encoding: Optional[str] = "utf-8", -) -> Optional[str]: - """ - Get the value of a given key from the given .env. - - Returns `None` if the key isn't found or doesn't have a value. - """ - return DotEnv(dotenv_path, verbose=True, encoding=encoding).get(key_to_get) - - -@contextmanager -def rewrite( - path: StrPath, - encoding: Optional[str], -) -> Iterator[Tuple[IO[str], IO[str]]]: - pathlib.Path(path).touch() - - with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as dest: - error = None - try: - with open(path, encoding=encoding) as source: - yield (source, dest) - except BaseException as err: - error = err - - if error is None: - shutil.move(dest.name, path) - else: - os.unlink(dest.name) - raise error from None - - -def set_key( - dotenv_path: StrPath, - key_to_set: str, - value_to_set: str, - quote_mode: str = "always", - export: bool = False, - encoding: Optional[str] = "utf-8", -) -> Tuple[Optional[bool], str, str]: - """ - Adds or Updates a key/value to the given .env - - If the .env path given doesn't exist, fails instead of risking creating - an orphan .env somewhere in the filesystem - """ - if quote_mode not in ("always", "auto", "never"): - raise ValueError(f"Unknown quote_mode: {quote_mode}") - - quote = quote_mode == "always" or ( - quote_mode == "auto" and not value_to_set.isalnum() - ) - - if quote: - value_out = "'{}'".format(value_to_set.replace("'", "\\'")) - else: - value_out = value_to_set - if export: - line_out = f"export {key_to_set}={value_out}\n" - else: - line_out = f"{key_to_set}={value_out}\n" - - with rewrite(dotenv_path, encoding=encoding) as (source, dest): - replaced = False - missing_newline = False - for mapping in with_warn_for_invalid_lines(parse_stream(source)): - if mapping.key == key_to_set: - dest.write(line_out) - replaced = True - else: - dest.write(mapping.original.string) - missing_newline = not mapping.original.string.endswith("\n") - if not replaced: - if missing_newline: - dest.write("\n") - dest.write(line_out) - - return True, key_to_set, value_to_set - - -def unset_key( - dotenv_path: StrPath, - key_to_unset: str, - quote_mode: str = "always", - encoding: Optional[str] = "utf-8", -) -> Tuple[Optional[bool], str]: - """ - Removes a given key from the given `.env` file. - - If the .env path given doesn't exist, fails. - If the given key doesn't exist in the .env, fails. - """ - if not os.path.exists(dotenv_path): - logger.warning("Can't delete from %s - it doesn't exist.", dotenv_path) - return None, key_to_unset - - removed = False - with rewrite(dotenv_path, encoding=encoding) as (source, dest): - for mapping in with_warn_for_invalid_lines(parse_stream(source)): - if mapping.key == key_to_unset: - removed = True - else: - dest.write(mapping.original.string) - - if not removed: - logger.warning( - "Key %s not removed from %s - key doesn't exist.", key_to_unset, dotenv_path - ) - return None, key_to_unset - - return removed, key_to_unset - - -def resolve_variables( - values: Iterable[Tuple[str, Optional[str]]], - override: bool, -) -> Mapping[str, Optional[str]]: - new_values: Dict[str, Optional[str]] = {} - - for name, value in values: - if value is None: - result = None - else: - atoms = parse_variables(value) - env: Dict[str, Optional[str]] = {} - if override: - env.update(os.environ) # type: ignore - env.update(new_values) - else: - env.update(new_values) - env.update(os.environ) # type: ignore - result = "".join(atom.resolve(env) for atom in atoms) - - new_values[name] = result - - return new_values - - -def _walk_to_root(path: str) -> Iterator[str]: - """ - Yield directories starting from the given directory up to the root - """ - if not os.path.exists(path): - raise IOError("Starting path not found") - - if os.path.isfile(path): - path = os.path.dirname(path) - - last_dir = None - current_dir = os.path.abspath(path) - while last_dir != current_dir: - yield current_dir - parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir)) - last_dir, current_dir = current_dir, parent_dir - - -def find_dotenv( - filename: str = ".env", - raise_error_if_not_found: bool = False, - usecwd: bool = False, -) -> str: - """ - Search in increasingly higher folders for the given file - - Returns path to the file if found, or an empty string otherwise - """ - - def _is_interactive(): - """Decide whether this is running in a REPL or IPython notebook""" - if hasattr(sys, "ps1") or hasattr(sys, "ps2"): - return True - try: - main = __import__("__main__", None, None, fromlist=["__file__"]) - except ModuleNotFoundError: - return False - return not hasattr(main, "__file__") - - def _is_debugger(): - return sys.gettrace() is not None - - if usecwd or _is_interactive() or _is_debugger() or getattr(sys, "frozen", False): - # Should work without __file__, e.g. in REPL or IPython notebook. - path = os.getcwd() - else: - # will work for .py files - frame = sys._getframe() - current_file = __file__ - - while frame.f_code.co_filename == current_file or not os.path.exists( - frame.f_code.co_filename - ): - assert frame.f_back is not None - frame = frame.f_back - frame_filename = frame.f_code.co_filename - path = os.path.dirname(os.path.abspath(frame_filename)) - - for dirname in _walk_to_root(path): - check_path = os.path.join(dirname, filename) - if _is_file_or_fifo(check_path): - return check_path - - if raise_error_if_not_found: - raise IOError("File not found") - - return "" - - -def load_dotenv( - dotenv_path: Optional[StrPath] = None, - stream: Optional[IO[str]] = None, - verbose: bool = False, - override: bool = False, - interpolate: bool = True, - encoding: Optional[str] = "utf-8", -) -> bool: - """Parse a .env file and then load all the variables found as environment variables. - - Parameters: - dotenv_path: Absolute or relative path to .env file. - stream: Text stream (such as `io.StringIO`) with .env content, used if - `dotenv_path` is `None`. - verbose: Whether to output a warning the .env file is missing. - override: Whether to override the system environment variables with the variables - from the `.env` file. - encoding: Encoding to be used to read the file. - Returns: - Bool: True if at least one environment variable is set else False - - If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the - .env file with it's default parameters. If you need to change the default parameters - of `find_dotenv()`, you can explicitly call `find_dotenv()` and pass the result - to this function as `dotenv_path`. - - If the environment variable `PYTHON_DOTENV_DISABLED` is set to a truthy value, - .env loading is disabled. - """ - if _load_dotenv_disabled(): - logger.debug( - "python-dotenv: .env loading disabled by PYTHON_DOTENV_DISABLED environment variable" - ) - return False - - if dotenv_path is None and stream is None: - dotenv_path = find_dotenv() - - dotenv = DotEnv( - dotenv_path=dotenv_path, - stream=stream, - verbose=verbose, - interpolate=interpolate, - override=override, - encoding=encoding, - ) - return dotenv.set_as_environment_variables() - - -def dotenv_values( - dotenv_path: Optional[StrPath] = None, - stream: Optional[IO[str]] = None, - verbose: bool = False, - interpolate: bool = True, - encoding: Optional[str] = "utf-8", -) -> Dict[str, Optional[str]]: - """ - Parse a .env file and return its content as a dict. - - The returned dict will have `None` values for keys without values in the .env file. - For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in - `{"foo": None}` - - Parameters: - dotenv_path: Absolute or relative path to the .env file. - stream: `StringIO` object with .env content, used if `dotenv_path` is `None`. - verbose: Whether to output a warning if the .env file is missing. - encoding: Encoding to be used to read the file. - - If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the - .env file. - """ - if dotenv_path is None and stream is None: - dotenv_path = find_dotenv() - - return DotEnv( - dotenv_path=dotenv_path, - stream=stream, - verbose=verbose, - interpolate=interpolate, - override=True, - encoding=encoding, - ).dict() - - -def _is_file_or_fifo(path: StrPath) -> bool: - """ - Return True if `path` exists and is either a regular file or a FIFO. - """ - if os.path.isfile(path): - return True - - try: - st = os.stat(path) - except (FileNotFoundError, OSError): - return False - - return stat.S_ISFIFO(st.st_mode) diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/parser.py b/backend/venv39/lib/python3.9/site-packages/dotenv/parser.py deleted file mode 100644 index eb100b4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/parser.py +++ /dev/null @@ -1,182 +0,0 @@ -import codecs -import re -from typing import ( - IO, - Iterator, - Match, - NamedTuple, - Optional, - Pattern, - Sequence, -) - - -def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]: - return re.compile(string, re.UNICODE | extra_flags) - - -_newline = make_regex(r"(\r\n|\n|\r)") -_multiline_whitespace = make_regex(r"\s*", extra_flags=re.MULTILINE) -_whitespace = make_regex(r"[^\S\r\n]*") -_export = make_regex(r"(?:export[^\S\r\n]+)?") -_single_quoted_key = make_regex(r"'([^']+)'") -_unquoted_key = make_regex(r"([^=\#\s]+)") -_equal_sign = make_regex(r"(=[^\S\r\n]*)") -_single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'") -_double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"') -_unquoted_value = make_regex(r"([^\r\n]*)") -_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?") -_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)") -_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?") -_double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]") -_single_quote_escapes = make_regex(r"\\[\\']") - - -class Original(NamedTuple): - string: str - line: int - - -class Binding(NamedTuple): - key: Optional[str] - value: Optional[str] - original: Original - error: bool - - -class Position: - def __init__(self, chars: int, line: int) -> None: - self.chars = chars - self.line = line - - @classmethod - def start(cls) -> "Position": - return cls(chars=0, line=1) - - def set(self, other: "Position") -> None: - self.chars = other.chars - self.line = other.line - - def advance(self, string: str) -> None: - self.chars += len(string) - self.line += len(re.findall(_newline, string)) - - -class Error(Exception): - pass - - -class Reader: - def __init__(self, stream: IO[str]) -> None: - self.string = stream.read() - self.position = Position.start() - self.mark = Position.start() - - def has_next(self) -> bool: - return self.position.chars < len(self.string) - - def set_mark(self) -> None: - self.mark.set(self.position) - - def get_marked(self) -> Original: - return Original( - string=self.string[self.mark.chars : self.position.chars], - line=self.mark.line, - ) - - def peek(self, count: int) -> str: - return self.string[self.position.chars : self.position.chars + count] - - def read(self, count: int) -> str: - result = self.string[self.position.chars : self.position.chars + count] - if len(result) < count: - raise Error("read: End of string") - self.position.advance(result) - return result - - def read_regex(self, regex: Pattern[str]) -> Sequence[str]: - match = regex.match(self.string, self.position.chars) - if match is None: - raise Error("read_regex: Pattern not found") - self.position.advance(self.string[match.start() : match.end()]) - return match.groups() - - -def decode_escapes(regex: Pattern[str], string: str) -> str: - def decode_match(match: Match[str]) -> str: - return codecs.decode(match.group(0), "unicode-escape") # type: ignore - - return regex.sub(decode_match, string) - - -def parse_key(reader: Reader) -> Optional[str]: - char = reader.peek(1) - if char == "#": - return None - elif char == "'": - (key,) = reader.read_regex(_single_quoted_key) - else: - (key,) = reader.read_regex(_unquoted_key) - return key - - -def parse_unquoted_value(reader: Reader) -> str: - (part,) = reader.read_regex(_unquoted_value) - return re.sub(r"\s+#.*", "", part).rstrip() - - -def parse_value(reader: Reader) -> str: - char = reader.peek(1) - if char == "'": - (value,) = reader.read_regex(_single_quoted_value) - return decode_escapes(_single_quote_escapes, value) - elif char == '"': - (value,) = reader.read_regex(_double_quoted_value) - return decode_escapes(_double_quote_escapes, value) - elif char in ("", "\n", "\r"): - return "" - else: - return parse_unquoted_value(reader) - - -def parse_binding(reader: Reader) -> Binding: - reader.set_mark() - try: - reader.read_regex(_multiline_whitespace) - if not reader.has_next(): - return Binding( - key=None, - value=None, - original=reader.get_marked(), - error=False, - ) - reader.read_regex(_export) - key = parse_key(reader) - reader.read_regex(_whitespace) - if reader.peek(1) == "=": - reader.read_regex(_equal_sign) - value: Optional[str] = parse_value(reader) - else: - value = None - reader.read_regex(_comment) - reader.read_regex(_end_of_line) - return Binding( - key=key, - value=value, - original=reader.get_marked(), - error=False, - ) - except Error: - reader.read_regex(_rest_of_line) - return Binding( - key=None, - value=None, - original=reader.get_marked(), - error=True, - ) - - -def parse_stream(stream: IO[str]) -> Iterator[Binding]: - reader = Reader(stream) - while reader.has_next(): - yield parse_binding(reader) diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/py.typed b/backend/venv39/lib/python3.9/site-packages/dotenv/py.typed deleted file mode 100644 index 7632ecf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/variables.py b/backend/venv39/lib/python3.9/site-packages/dotenv/variables.py deleted file mode 100644 index 667f2f2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/variables.py +++ /dev/null @@ -1,86 +0,0 @@ -import re -from abc import ABCMeta, abstractmethod -from typing import Iterator, Mapping, Optional, Pattern - -_posix_variable: Pattern[str] = re.compile( - r""" - \$\{ - (?P[^\}:]*) - (?::- - (?P[^\}]*) - )? - \} - """, - re.VERBOSE, -) - - -class Atom(metaclass=ABCMeta): - def __ne__(self, other: object) -> bool: - result = self.__eq__(other) - if result is NotImplemented: - return NotImplemented - return not result - - @abstractmethod - def resolve(self, env: Mapping[str, Optional[str]]) -> str: ... - - -class Literal(Atom): - def __init__(self, value: str) -> None: - self.value = value - - def __repr__(self) -> str: - return f"Literal(value={self.value})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, self.__class__): - return NotImplemented - return self.value == other.value - - def __hash__(self) -> int: - return hash((self.__class__, self.value)) - - def resolve(self, env: Mapping[str, Optional[str]]) -> str: - return self.value - - -class Variable(Atom): - def __init__(self, name: str, default: Optional[str]) -> None: - self.name = name - self.default = default - - def __repr__(self) -> str: - return f"Variable(name={self.name}, default={self.default})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, self.__class__): - return NotImplemented - return (self.name, self.default) == (other.name, other.default) - - def __hash__(self) -> int: - return hash((self.__class__, self.name, self.default)) - - def resolve(self, env: Mapping[str, Optional[str]]) -> str: - default = self.default if self.default is not None else "" - result = env.get(self.name, default) - return result if result is not None else "" - - -def parse_variables(value: str) -> Iterator[Atom]: - cursor = 0 - - for match in _posix_variable.finditer(value): - (start, end) = match.span() - name = match["name"] - default = match["default"] - - if start > cursor: - yield Literal(value=value[cursor:start]) - - yield Variable(name=name, default=default) - cursor = end - - length = len(value) - if cursor < length: - yield Literal(value=value[cursor:length]) diff --git a/backend/venv39/lib/python3.9/site-packages/dotenv/version.py b/backend/venv39/lib/python3.9/site-packages/dotenv/version.py deleted file mode 100644 index a955fda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/dotenv/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.2.1" diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/LICENSE deleted file mode 100644 index 474479a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -"python-ecdsa" Copyright (c) 2010 Brian Warner - -Portions written in 2005 by Peter Pearson and placed in the public domain. - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/METADATA deleted file mode 100644 index 3e63190..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/METADATA +++ /dev/null @@ -1,671 +0,0 @@ -Metadata-Version: 2.1 -Name: ecdsa -Version: 0.19.1 -Summary: ECDSA cryptographic signature library (pure python) -Home-page: http://github.com/tlsfuzzer/python-ecdsa -Author: Brian Warner -Author-email: warner@lothar.com -License: MIT -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -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 :: 3.13 -Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: six >=1.9.0 -Provides-Extra: gmpy -Requires-Dist: gmpy ; extra == 'gmpy' -Provides-Extra: gmpy2 -Requires-Dist: gmpy2 ; extra == 'gmpy2' - -# Pure-Python ECDSA and ECDH - -[![GitHub CI](https://github.com/tlsfuzzer/python-ecdsa/actions/workflows/ci.yml/badge.svg)](https://github.com/tlsfuzzer/python-ecdsa/actions/workflows/ci.yml) -[![Documentation Status](https://readthedocs.org/projects/ecdsa/badge/?version=latest)](https://ecdsa.readthedocs.io/en/latest/?badge=latest) -[![Coverage Status](https://coveralls.io/repos/github/tlsfuzzer/python-ecdsa/badge.svg?branch=master)](https://coveralls.io/github/tlsfuzzer/python-ecdsa?branch=master) -![condition coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/tomato42/9b6ca1f3410207fbeca785a178781651/raw/python-ecdsa-condition-coverage.json) -![mutation score](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/tomato42/9b6ca1f3410207fbeca785a178781651/raw/python-ecdsa-mutation-score.json) -[![CodeQL](https://github.com/tlsfuzzer/python-ecdsa/actions/workflows/codeql.yml/badge.svg)](https://github.com/tlsfuzzer/python-ecdsa/actions/workflows/codeql.yml) -[![Latest Version](https://img.shields.io/pypi/v/ecdsa.svg?style=flat)](https://pypi.python.org/pypi/ecdsa/) -![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat) - - -This is an easy-to-use implementation of ECC (Elliptic Curve Cryptography) -with support for ECDSA (Elliptic Curve Digital Signature Algorithm), -EdDSA (Edwards-curve Digital Signature Algorithm) and ECDH -(Elliptic Curve Diffie-Hellman), implemented purely in Python, released under -the MIT license. With this library, you can quickly create key pairs (signing -key and verifying key), sign messages, and verify the signatures. You can -also agree on a shared secret key based on exchanged public keys. -The keys and signatures are very short, making them easy to handle and -incorporate into other protocols. - -**NOTE: This library should not be used in production settings, see [Security](#Security) for more details.** - -## Features - -This library provides key generation, signing, verifying, and shared secret -derivation for five -popular NIST "Suite B" GF(p) (_prime field_) curves, with key lengths of 192, -224, 256, 384, and 521 bits. The "short names" for these curves, as known by -the OpenSSL tool (`openssl ecparam -list_curves`), are: `prime192v1`, -`secp224r1`, `prime256v1`, `secp384r1`, and `secp521r1`. It includes the -256-bit curve `secp256k1` used by Bitcoin. There is also support for the -regular (non-twisted) variants of Brainpool curves from 160 to 512 bits. The -"short names" of those curves are: `brainpoolP160r1`, `brainpoolP192r1`, -`brainpoolP224r1`, `brainpoolP256r1`, `brainpoolP320r1`, `brainpoolP384r1`, -`brainpoolP512r1`. Few of the small curves from SEC standard are also -included (mainly to speed-up testing of the library), those are: -`secp112r1`, `secp112r2`, `secp128r1`, and `secp160r1`. -Key generation, siging and verifying is also supported for Ed25519 and -Ed448 curves. -No other curves are included, but it is not too hard to add support for more -curves over prime fields. - -## Dependencies - -This library uses only Python and the 'six' package. It is compatible with -Python 2.6, 2.7, and 3.6+. It also supports execution on alternative -implementations like pypy and pypy3. - -If `gmpy2` or `gmpy` is installed, they will be used for faster arithmetic. -Either of them can be installed after this library is installed, -`python-ecdsa` will detect their presence on start-up and use them -automatically. -You should prefer `gmpy2` on Python3 for optimal performance. - -To run the OpenSSL compatibility tests, the 'openssl' tool must be in your -`PATH`. This release has been tested successfully against OpenSSL 0.9.8o, -1.0.0a, 1.0.2f, 1.1.1d and 3.0.1 (among others). - - -## Installation - -This library is available on PyPI, it's recommended to install it using `pip`: - -``` -pip install ecdsa -``` - -In case higher performance is wanted and using native code is not a problem, -it's possible to specify installation together with `gmpy2`: - -``` -pip install ecdsa[gmpy2] -``` - -or (slower, legacy option): -``` -pip install ecdsa[gmpy] -``` - -## Speed - -The following table shows how long this library takes to generate key pairs -(`keygen`), to sign data (`sign`), to verify those signatures (`verify`), -to derive a shared secret (`ecdh`), and -to verify the signatures with no key-specific precomputation (`no PC verify`). -All those values are in seconds. -For convenience, the inverses of those values are also provided: -how many keys per second can be generated (`keygen/s`), how many signatures -can be made per second (`sign/s`), how many signatures can be verified -per second (`verify/s`), how many shared secrets can be derived per second -(`ecdh/s`), and how many signatures with no key specific -precomputation can be verified per second (`no PC verify/s`). The size of raw -signature (generally the smallest -the way a signature can be encoded) is also provided in the `siglen` column. -Use `tox -e speed` to generate this table on your own computer. -On an Intel Core i7 4790K @ 4.0GHz I'm getting the following performance: - -``` - siglen keygen keygen/s sign sign/s verify verify/s no PC verify no PC verify/s - NIST192p: 48 0.00032s 3134.06 0.00033s 2985.53 0.00063s 1598.36 0.00129s 774.43 - NIST224p: 56 0.00040s 2469.24 0.00042s 2367.88 0.00081s 1233.41 0.00170s 586.66 - NIST256p: 64 0.00051s 1952.73 0.00054s 1867.80 0.00098s 1021.86 0.00212s 471.27 - NIST384p: 96 0.00107s 935.92 0.00111s 904.23 0.00203s 491.77 0.00446s 224.00 - NIST521p: 132 0.00210s 475.52 0.00215s 464.16 0.00398s 251.28 0.00874s 114.39 - SECP256k1: 64 0.00052s 1921.54 0.00054s 1847.49 0.00105s 948.68 0.00210s 477.01 - BRAINPOOLP160r1: 40 0.00025s 4003.88 0.00026s 3845.12 0.00053s 1893.93 0.00105s 949.92 - BRAINPOOLP192r1: 48 0.00033s 3043.97 0.00034s 2975.98 0.00063s 1581.50 0.00135s 742.29 - BRAINPOOLP224r1: 56 0.00041s 2436.44 0.00043s 2315.51 0.00078s 1278.49 0.00180s 556.16 - BRAINPOOLP256r1: 64 0.00053s 1892.49 0.00054s 1846.24 0.00114s 875.64 0.00229s 437.25 - BRAINPOOLP320r1: 80 0.00073s 1361.26 0.00076s 1309.25 0.00143s 699.29 0.00322s 310.49 - BRAINPOOLP384r1: 96 0.00107s 931.29 0.00111s 901.80 0.00230s 434.19 0.00476s 210.20 - BRAINPOOLP512r1: 128 0.00207s 483.41 0.00212s 471.42 0.00425s 235.43 0.00912s 109.61 - SECP112r1: 28 0.00015s 6672.53 0.00016s 6440.34 0.00031s 3265.41 0.00056s 1774.20 - SECP112r2: 28 0.00015s 6697.11 0.00015s 6479.98 0.00028s 3524.72 0.00058s 1716.16 - SECP128r1: 32 0.00018s 5497.65 0.00019s 5272.89 0.00036s 2747.39 0.00072s 1396.16 - SECP160r1: 42 0.00025s 3949.32 0.00026s 3894.45 0.00046s 2153.85 0.00102s 985.07 - Ed25519: 64 0.00076s 1324.48 0.00042s 2405.01 0.00109s 918.05 0.00344s 290.50 - Ed448: 114 0.00176s 569.53 0.00115s 870.94 0.00282s 355.04 0.01024s 97.69 - - ecdh ecdh/s - NIST192p: 0.00104s 964.89 - NIST224p: 0.00134s 748.63 - NIST256p: 0.00170s 587.08 - NIST384p: 0.00352s 283.90 - NIST521p: 0.00717s 139.51 - SECP256k1: 0.00154s 648.40 - BRAINPOOLP160r1: 0.00082s 1220.70 - BRAINPOOLP192r1: 0.00105s 956.75 - BRAINPOOLP224r1: 0.00136s 734.52 - BRAINPOOLP256r1: 0.00178s 563.32 - BRAINPOOLP320r1: 0.00252s 397.23 - BRAINPOOLP384r1: 0.00376s 266.27 - BRAINPOOLP512r1: 0.00733s 136.35 - SECP112r1: 0.00046s 2180.40 - SECP112r2: 0.00045s 2229.14 - SECP128r1: 0.00054s 1868.15 - SECP160r1: 0.00080s 1243.98 -``` - -To test performance with `gmpy2` loaded, use `tox -e speedgmpy2`. -On the same machine I'm getting the following performance with `gmpy2`: -``` - siglen keygen keygen/s sign sign/s verify verify/s no PC verify no PC verify/s - NIST192p: 48 0.00017s 5933.40 0.00017s 5751.70 0.00032s 3125.28 0.00067s 1502.41 - NIST224p: 56 0.00021s 4782.87 0.00022s 4610.05 0.00040s 2487.04 0.00089s 1126.90 - NIST256p: 64 0.00023s 4263.98 0.00024s 4125.16 0.00045s 2200.88 0.00098s 1016.82 - NIST384p: 96 0.00041s 2449.54 0.00042s 2399.96 0.00083s 1210.57 0.00172s 581.43 - NIST521p: 132 0.00071s 1416.07 0.00072s 1389.81 0.00144s 692.93 0.00312s 320.40 - SECP256k1: 64 0.00024s 4245.05 0.00024s 4122.09 0.00045s 2206.40 0.00094s 1068.32 - BRAINPOOLP160r1: 40 0.00014s 6939.17 0.00015s 6681.55 0.00029s 3452.43 0.00057s 1769.81 - BRAINPOOLP192r1: 48 0.00017s 5920.05 0.00017s 5774.36 0.00034s 2979.00 0.00069s 1453.19 - BRAINPOOLP224r1: 56 0.00021s 4732.12 0.00022s 4622.65 0.00041s 2422.47 0.00087s 1149.87 - BRAINPOOLP256r1: 64 0.00024s 4233.02 0.00024s 4115.20 0.00047s 2143.27 0.00098s 1015.60 - BRAINPOOLP320r1: 80 0.00032s 3162.38 0.00032s 3077.62 0.00063s 1598.83 0.00136s 737.34 - BRAINPOOLP384r1: 96 0.00041s 2436.88 0.00042s 2395.62 0.00083s 1202.68 0.00178s 562.85 - BRAINPOOLP512r1: 128 0.00063s 1587.60 0.00064s 1558.83 0.00125s 799.96 0.00281s 355.83 - SECP112r1: 28 0.00009s 11118.66 0.00009s 10775.48 0.00018s 5456.00 0.00033s 3020.83 - SECP112r2: 28 0.00009s 11322.97 0.00009s 10857.71 0.00017s 5748.77 0.00032s 3094.28 - SECP128r1: 32 0.00010s 10078.39 0.00010s 9665.27 0.00019s 5200.58 0.00036s 2760.88 - SECP160r1: 42 0.00015s 6875.51 0.00015s 6647.35 0.00029s 3422.41 0.00057s 1768.35 - Ed25519: 64 0.00030s 3322.56 0.00018s 5568.63 0.00046s 2165.35 0.00153s 654.02 - Ed448: 114 0.00060s 1680.53 0.00039s 2567.40 0.00096s 1036.67 0.00350s 285.62 - - ecdh ecdh/s - NIST192p: 0.00050s 1985.70 - NIST224p: 0.00066s 1524.16 - NIST256p: 0.00071s 1413.07 - NIST384p: 0.00127s 788.89 - NIST521p: 0.00230s 434.85 - SECP256k1: 0.00071s 1409.95 - BRAINPOOLP160r1: 0.00042s 2374.65 - BRAINPOOLP192r1: 0.00051s 1960.01 - BRAINPOOLP224r1: 0.00066s 1518.37 - BRAINPOOLP256r1: 0.00071s 1399.90 - BRAINPOOLP320r1: 0.00100s 997.21 - BRAINPOOLP384r1: 0.00129s 777.51 - BRAINPOOLP512r1: 0.00210s 475.99 - SECP112r1: 0.00022s 4457.70 - SECP112r2: 0.00024s 4252.33 - SECP128r1: 0.00028s 3589.31 - SECP160r1: 0.00043s 2305.02 -``` - -(there's also `gmpy` version, execute it using `tox -e speedgmpy`) - -For comparison, a highly optimised implementation (including curve-specific -assembly for some curves), like the one in OpenSSL 1.1.1d, provides the -following performance numbers on the same machine. -Run `openssl speed ecdsa` and `openssl speed ecdh` to reproduce it: -``` - sign verify sign/s verify/s - 192 bits ecdsa (nistp192) 0.0002s 0.0002s 4785.6 5380.7 - 224 bits ecdsa (nistp224) 0.0000s 0.0001s 22475.6 9822.0 - 256 bits ecdsa (nistp256) 0.0000s 0.0001s 45069.6 14166.6 - 384 bits ecdsa (nistp384) 0.0008s 0.0006s 1265.6 1648.1 - 521 bits ecdsa (nistp521) 0.0003s 0.0005s 3753.1 1819.5 - 256 bits ecdsa (brainpoolP256r1) 0.0003s 0.0003s 2983.5 3333.2 - 384 bits ecdsa (brainpoolP384r1) 0.0008s 0.0007s 1258.8 1528.1 - 512 bits ecdsa (brainpoolP512r1) 0.0015s 0.0012s 675.1 860.1 - - sign verify sign/s verify/s - 253 bits EdDSA (Ed25519) 0.0000s 0.0001s 28217.9 10897.7 - 456 bits EdDSA (Ed448) 0.0003s 0.0005s 3926.5 2147.7 - - op op/s - 192 bits ecdh (nistp192) 0.0002s 4853.4 - 224 bits ecdh (nistp224) 0.0001s 15252.1 - 256 bits ecdh (nistp256) 0.0001s 18436.3 - 384 bits ecdh (nistp384) 0.0008s 1292.7 - 521 bits ecdh (nistp521) 0.0003s 2884.7 - 256 bits ecdh (brainpoolP256r1) 0.0003s 3066.5 - 384 bits ecdh (brainpoolP384r1) 0.0008s 1298.0 - 512 bits ecdh (brainpoolP512r1) 0.0014s 694.8 -``` - -Keys and signature can be serialized in different ways (see Usage, below). -For a NIST192p key, the three basic representations require strings of the -following lengths (in bytes): - - to_string: signkey= 24, verifykey= 48, signature=48 - compressed: signkey=n/a, verifykey= 25, signature=n/a - DER: signkey=106, verifykey= 80, signature=55 - PEM: signkey=278, verifykey=162, (no support for PEM signatures) - -## History - -In 2006, Peter Pearson announced his pure-python implementation of ECDSA in a -[message to sci.crypt][1], available from his [download site][2]. In 2010, -Brian Warner wrote a wrapper around this code, to make it a bit easier and -safer to use. In 2020, Hubert Kario included an implementation of elliptic -curve cryptography that uses Jacobian coordinates internally, improving -performance about 20-fold. You are looking at the README for this wrapper. - -[1]: http://www.derkeiler.com/Newsgroups/sci.crypt/2006-01/msg00651.html -[2]: http://webpages.charter.net/curryfans/peter/downloads.html - -## Testing - -To run the full test suite, do this: - - tox -e coverage - -On an Intel Core i7 4790K @ 4.0GHz, the tests take about 18 seconds to execute. -The test suite uses -[`hypothesis`](https://github.com/HypothesisWorks/hypothesis) so there is some -inherent variability in the test suite execution time. - -One part of `test_pyecdsa.py` and `test_ecdh.py` checks compatibility with -OpenSSL, by running the "openssl" CLI tool, make sure it's in your `PATH` if -you want to test compatibility with it (if OpenSSL is missing, too old, or -doesn't support all the curves supported in upstream releases you will see -skipped tests in the above `coverage` run). - -## Security - -This library was not designed with security in mind. If you are processing -data that needs to be protected we suggest you use a quality wrapper around -OpenSSL. [pyca/cryptography](https://cryptography.io) is one example of such -a wrapper. The primary use-case of this library is as a portable library for -interoperability testing and as a teaching tool. - -**This library does not protect against side-channel attacks.** - -Do not allow attackers to measure how long it takes you to generate a key pair -or sign a message. Do not allow attackers to run code on the same physical -machine when key pair generation or signing is taking place (this includes -virtual machines). Do not allow attackers to measure how much power your -computer uses while generating the key pair or signing a message. Do not allow -attackers to measure RF interference coming from your computer while generating -a key pair or signing a message. Note: just loading the private key will cause -key pair generation. Other operations or attack vectors may also be -vulnerable to attacks. **For a sophisticated attacker observing just one -operation with a private key will be sufficient to completely -reconstruct the private key**. - -Please also note that any Pure-python cryptographic library will be vulnerable -to the same side-channel attacks. This is because Python does not provide -side-channel secure primitives (with the exception of -[`hmac.compare_digest()`][3]), making side-channel secure programming -impossible. - -This library depends upon a strong source of random numbers. Do not use it on -a system where `os.urandom()` does not provide cryptographically secure -random numbers. - -[3]: https://docs.python.org/3/library/hmac.html#hmac.compare_digest - -## Usage - -You start by creating a `SigningKey`. You can use this to sign data, by passing -in data as a byte string and getting back the signature (also a byte string). -You can also ask a `SigningKey` to give you the corresponding `VerifyingKey`. -The `VerifyingKey` can be used to verify a signature, by passing it both the -data string and the signature byte string: it either returns True or raises -`BadSignatureError`. - -```python -from ecdsa import SigningKey -sk = SigningKey.generate() # uses NIST192p -vk = sk.verifying_key -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -Each `SigningKey`/`VerifyingKey` is associated with a specific curve, like -NIST192p (the default one). Longer curves are more secure, but take longer to -use, and result in longer keys and signatures. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -The `SigningKey` can be serialized into several different formats: the shortest -is to call `s=sk.to_string()`, and then re-create it with -`SigningKey.from_string(s, curve)` . This short form does not record the -curve, so you must be sure to pass to `from_string()` the same curve you used -for the original key. The short form of a NIST192p-based signing key is just 24 -bytes long. If a point encoding is invalid or it does not lie on the specified -curve, `from_string()` will raise `MalformedPointError`. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -sk_string = sk.to_string() -sk2 = SigningKey.from_string(sk_string, curve=NIST384p) -print(sk_string.hex()) -print(sk2.to_string().hex()) -``` - -Note: while the methods are called `to_string()` the type they return is -actually `bytes`, the "string" part is leftover from Python 2. - -`sk.to_pem()` and `sk.to_der()` will serialize the signing key into the same -formats that OpenSSL uses. The PEM file looks like the familiar ASCII-armored -`"-----BEGIN EC PRIVATE KEY-----"` base64-encoded format, and the DER format -is a shorter binary form of the same data. -`SigningKey.from_pem()/.from_der()` will undo this serialization. These -formats include the curve name, so you do not need to pass in a curve -identifier to the deserializer. In case the file is malformed `from_der()` -and `from_pem()` will raise `UnexpectedDER` or` MalformedPointError`. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -sk_pem = sk.to_pem() -sk2 = SigningKey.from_pem(sk_pem) -# sk and sk2 are the same key -``` - -Likewise, the `VerifyingKey` can be serialized in the same way: -`vk.to_string()/VerifyingKey.from_string()`, `to_pem()/from_pem()`, and -`to_der()/from_der()`. The same `curve=` argument is needed for -`VerifyingKey.from_string()`. - -```python -from ecdsa import SigningKey, VerifyingKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk_string = vk.to_string() -vk2 = VerifyingKey.from_string(vk_string, curve=NIST384p) -# vk and vk2 are the same key - -from ecdsa import SigningKey, VerifyingKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk_pem = vk.to_pem() -vk2 = VerifyingKey.from_pem(vk_pem) -# vk and vk2 are the same key -``` - -There are a couple of different ways to compute a signature. Fundamentally, -ECDSA takes a number that represents the data being signed, and returns a -pair of numbers that represent the signature. The `hashfunc=` argument to -`sk.sign()` and `vk.verify()` is used to turn an arbitrary string into a -fixed-length digest, which is then turned into a number that ECDSA can sign, -and both sign and verify must use the same approach. The default value is -`hashlib.sha1`, but if you use NIST256p or a longer curve, you can use -`hashlib.sha256` instead. - -There are also multiple ways to represent a signature. The default -`sk.sign()` and `vk.verify()` methods present it as a short string, for -simplicity and minimal overhead. To use a different scheme, use the -`sk.sign(sigencode=)` and `vk.verify(sigdecode=)` arguments. There are helper -functions in the `ecdsa.util` module that can be useful here. - -It is also possible to create a `SigningKey` from a "seed", which is -deterministic. This can be used in protocols where you want to derive -consistent signing keys from some other secret, for example when you want -three separate keys and only want to store a single master secret. You should -start with a uniformly-distributed unguessable seed with about `curve.baselen` -bytes of entropy, and then use one of the helper functions in `ecdsa.util` to -convert it into an integer in the correct range, and then finally pass it -into `SigningKey.from_secret_exponent()`, like this: - -```python -import os -from ecdsa import NIST384p, SigningKey -from ecdsa.util import randrange_from_seed__trytryagain - -def make_key(seed): - secexp = randrange_from_seed__trytryagain(seed, NIST384p.order) - return SigningKey.from_secret_exponent(secexp, curve=NIST384p) - -seed = os.urandom(NIST384p.baselen) # or other starting point -sk1a = make_key(seed) -sk1b = make_key(seed) -# note: sk1a and sk1b are the same key -assert sk1a.to_string() == sk1b.to_string() -sk2 = make_key(b"2-"+seed) # different key -assert sk1a.to_string() != sk2.to_string() -``` - -In case the application will verify a lot of signatures made with a single -key, it's possible to precompute some of the internal values to make -signature verification significantly faster. The break-even point occurs at -about 100 signatures verified. - -To perform precomputation, you can call the `precompute()` method -on `VerifyingKey` instance: -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk.precompute() -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -Once `precompute()` was called, all signature verifications with this key will -be faster to execute. - -## OpenSSL Compatibility - -To produce signatures that can be verified by OpenSSL tools, or to verify -signatures that were produced by those tools, use: - -```python -# openssl ecparam -name prime256v1 -genkey -out sk.pem -# openssl ec -in sk.pem -pubout -out vk.pem -# echo "data for signing" > data -# openssl dgst -sha256 -sign sk.pem -out data.sig data -# openssl dgst -sha256 -verify vk.pem -signature data.sig data -# openssl dgst -sha256 -prverify sk.pem -signature data.sig data - -import hashlib -from ecdsa import SigningKey, VerifyingKey -from ecdsa.util import sigencode_der, sigdecode_der - -with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - -with open("data", "rb") as f: - data = f.read() - -with open("data.sig", "rb") as f: - signature = f.read() - -assert vk.verify(signature, data, hashlib.sha256, sigdecode=sigdecode_der) - -with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read(), hashlib.sha256) - -new_signature = sk.sign_deterministic(data, sigencode=sigencode_der) - -with open("data.sig2", "wb") as f: - f.write(new_signature) - -# openssl dgst -sha256 -verify vk.pem -signature data.sig2 data -``` - -Note: if compatibility with OpenSSL 1.0.0 or earlier is necessary, the -`sigencode_string` and `sigdecode_string` from `ecdsa.util` can be used for -respectively writing and reading the signatures. - -The keys also can be written in format that openssl can handle: - -```python -from ecdsa import SigningKey, VerifyingKey - -with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read()) -with open("sk.pem", "wb") as f: - f.write(sk.to_pem()) - -with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) -with open("vk.pem", "wb") as f: - f.write(vk.to_pem()) -``` - -## Entropy - -Creating a signing key with `SigningKey.generate()` requires some form of -entropy (as opposed to -`from_secret_exponent`/`from_string`/`from_der`/`from_pem`, -which are deterministic and do not require an entropy source). The default -source is `os.urandom()`, but you can pass any other function that behaves -like `os.urandom` as the `entropy=` argument to do something different. This -may be useful in unit tests, where you want to achieve repeatable results. The -`ecdsa.util.PRNG` utility is handy here: it takes a seed and produces a strong -pseudo-random stream from it: - -```python -from ecdsa.util import PRNG -from ecdsa import SigningKey -rng1 = PRNG(b"seed") -sk1 = SigningKey.generate(entropy=rng1) -rng2 = PRNG(b"seed") -sk2 = SigningKey.generate(entropy=rng2) -# sk1 and sk2 are the same key -``` - -Likewise, ECDSA signature generation requires a random number, and each -signature must use a different one (using the same number twice will -immediately reveal the private signing key). The `sk.sign()` method takes an -`entropy=` argument which behaves the same as `SigningKey.generate(entropy=)`. - -## Deterministic Signatures - -If you call `SigningKey.sign_deterministic(data)` instead of `.sign(data)`, -the code will generate a deterministic signature instead of a random one. -This uses the algorithm from RFC6979 to safely generate a unique `k` value, -derived from the private key and the message being signed. Each time you sign -the same message with the same key, you will get the same signature (using -the same `k`). - -This may become the default in a future version, as it is not vulnerable to -failures of the entropy source. - -## Examples - -Create a NIST192p key pair and immediately save both to disk: - -```python -from ecdsa import SigningKey -sk = SigningKey.generate() -vk = sk.verifying_key -with open("private.pem", "wb") as f: - f.write(sk.to_pem()) -with open("public.pem", "wb") as f: - f.write(vk.to_pem()) -``` - -Load a signing key from disk, use it to sign a message (using SHA-1), and write -the signature to disk: - -```python -from ecdsa import SigningKey -with open("private.pem") as f: - sk = SigningKey.from_pem(f.read()) -with open("message", "rb") as f: - message = f.read() -sig = sk.sign(message) -with open("signature", "wb") as f: - f.write(sig) -``` - -Load the verifying key, message, and signature from disk, and verify the -signature (assume SHA-1 hash): - -```python -from ecdsa import VerifyingKey, BadSignatureError -vk = VerifyingKey.from_pem(open("public.pem").read()) -with open("message", "rb") as f: - message = f.read() -with open("signature", "rb") as f: - sig = f.read() -try: - vk.verify(sig, message) - print "good signature" -except BadSignatureError: - print "BAD SIGNATURE" -``` - -Create a NIST521p key pair: - -```python -from ecdsa import SigningKey, NIST521p -sk = SigningKey.generate(curve=NIST521p) -vk = sk.verifying_key -``` - -Create three independent signing keys from a master seed: - -```python -from ecdsa import NIST192p, SigningKey -from ecdsa.util import randrange_from_seed__trytryagain - -def make_key_from_seed(seed, curve=NIST192p): - secexp = randrange_from_seed__trytryagain(seed, curve.order) - return SigningKey.from_secret_exponent(secexp, curve) - -sk1 = make_key_from_seed("1:%s" % seed) -sk2 = make_key_from_seed("2:%s" % seed) -sk3 = make_key_from_seed("3:%s" % seed) -``` - -Load a verifying key from disk and print it using hex encoding in -uncompressed and compressed format (defined in X9.62 and SEC1 standards): - -```python -from ecdsa import VerifyingKey - -with open("public.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - -print("uncompressed: {0}".format(vk.to_string("uncompressed").hex())) -print("compressed: {0}".format(vk.to_string("compressed").hex())) -``` - -Load a verifying key from a hex string from compressed format, output -uncompressed: - -```python -from ecdsa import VerifyingKey, NIST256p - -comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759' -vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p) -print(vk.to_string("uncompressed").hex()) -``` - -ECDH key exchange with remote party: - -```python -from ecdsa import ECDH, NIST256p - -ecdh = ECDH(curve=NIST256p) -ecdh.generate_private_key() -local_public_key = ecdh.get_public_key() -#send `local_public_key` to remote party and receive `remote_public_key` from remote party -with open("remote_public_key.pem") as e: - remote_public_key = e.read() -ecdh.load_received_public_key_pem(remote_public_key) -secret = ecdh.generate_sharedsecret_bytes() -``` diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/RECORD deleted file mode 100644 index 46f12f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/RECORD +++ /dev/null @@ -1,66 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/_rwlock.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/_sha3.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/_version.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/curves.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/der.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdh.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/eddsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/ellipticcurve.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/errors.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/keys.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/numbertheory.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/rfc6979.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/ssh.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_curves.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_der.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdh.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_eddsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ellipticcurve.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_jacobi.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_keys.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_malformed_sigs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_numbertheory.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_pyecdsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_rw_lock.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/test_sha3.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/ecdsa/util.cpython-39.pyc,, -ecdsa-0.19.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -ecdsa-0.19.1.dist-info/LICENSE,sha256=PsqYRXc9LluMydjBGdNF8ApIBuS9Zg1KPWzfnA6di7I,1147 -ecdsa-0.19.1.dist-info/METADATA,sha256=pgYAeXZAWaSlZnvx6ZgK6RpQAbgo7nhRuptSt4T71hY,29641 -ecdsa-0.19.1.dist-info/RECORD,, -ecdsa-0.19.1.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110 -ecdsa-0.19.1.dist-info/top_level.txt,sha256=7ovPHfAPyTou19f8gOSbHm6B9dGjTibWolcCB7Zjovs,6 -ecdsa/__init__.py,sha256=wRUnU3g01MM-mLNemnov-_8B81DlbSrqoFtOO4bZzQQ,1931 -ecdsa/_compat.py,sha256=5EP735DlmaSb8Slk4BMnh9Z7MvYpTnGS3S_DBmHETwo,4047 -ecdsa/_rwlock.py,sha256=CAwHp2V65ksI8B1UqY7EccK9LaUToiv6pDLVzm44eag,2849 -ecdsa/_sha3.py,sha256=DJs7QLmdkQMU35llyD8HQeAXNvf5sMcujO6oFdScIqI,4747 -ecdsa/_version.py,sha256=6Q6w07SB50LWxDw7_U4KvjfFSQLiAZWHvYT_iDehYqw,498 -ecdsa/curves.py,sha256=EcPE0WRFkjpPMZfVM0-hRQ63CdW5GKTkDRpK-VOy1Zo,15975 -ecdsa/der.py,sha256=wXf8ftHJLdJZ2MjpQjeT5ji_qTj05dJtqCsvmwjvbuo,16444 -ecdsa/ecdh.py,sha256=Tiirawt5xegVDrY9eS-ATvvfmTIznUyv5fy2k7VnzTk,11011 -ecdsa/ecdsa.py,sha256=82ECyve36rL4_y8Zk8jPB-Uyb67Ppx6CYdqIeFniv7w,31699 -ecdsa/eddsa.py,sha256=IzsGzoGAefcoYjF7DVjFkX5ZJqiK2LTOmAMe6wyf4UU,7170 -ecdsa/ellipticcurve.py,sha256=OhoxJsJJ_7Dp5e10AblD_ui9Uo2WxozRby37gxqcuOk,54296 -ecdsa/errors.py,sha256=b4mhnmIpRnEdHzbectHAA5F7O9MtSaI-fYoc13_vBxQ,130 -ecdsa/keys.py,sha256=FkpubL9MGCfkCJ6aVvV5c0bve4ZuBtU3P1dRRBTth0k,65503 -ecdsa/numbertheory.py,sha256=Ad2-mVFaOytMomBC-7d0cJao4tpkVLh4x7vyqj73G6A,17831 -ecdsa/rfc6979.py,sha256=zwzo33lsZJA9r2dSf7HCliI_yIbw5cJ0Ek9tLdRRO40,2850 -ecdsa/ssh.py,sha256=360JY0dbYeZaqx9k_OhlHzPZYZTw5UB5xtK2XLBqb0M,1916 -ecdsa/test_curves.py,sha256=l5N-m4Yo5IAy4a8aJMsBamaSlLAfSoYjYqCj1HDEVpU,13081 -ecdsa/test_der.py,sha256=Bqbu3QiESyl8X9bjR2IBzDW35fDHTVB-mhzk5qXgGQQ,18915 -ecdsa/test_ecdh.py,sha256=20TEYyGcnynAPS9nlr_k2ed6S7lJ1Z0bbohNU-pEGco,15380 -ecdsa/test_ecdsa.py,sha256=V5Q4Q7uUFfStVdeFtwhXVpFlFi0Nx5J5uru9T3j_3DQ,25037 -ecdsa/test_eddsa.py,sha256=1jfHF_ZSyillv6DLKJZ0SeYThauTCHsyRNAweS_4MEQ,33720 -ecdsa/test_ellipticcurve.py,sha256=mvIBD_KKrOY4Vpd4KcR3J8RCBxINJtqWls1WMEsFgnE,8798 -ecdsa/test_jacobi.py,sha256=SVrS--PSwDakCYit216khmzF8eQryWtiI3sYWd_6890,25811 -ecdsa/test_keys.py,sha256=reQ2KtfOsANa59CqvvRWjZm-SaWfscJZVJaE9RFyL94,39415 -ecdsa/test_malformed_sigs.py,sha256=Dg1Dkvgz1tO-KhZ6f9ZRljykz8FBYtld3hq1W2hLLM8,11289 -ecdsa/test_numbertheory.py,sha256=YTtclt_50n_24U__r2JyV3LEqR2BsBmA6IJghwBDz8c,13265 -ecdsa/test_pyecdsa.py,sha256=2zoWfR_xAqagKOFHVJt4dTZZacu1zT4JxXH_HJUABW8,91272 -ecdsa/test_rw_lock.py,sha256=byv0_FTM90cbuHPCI6__LeQJkHL_zYEeVYIBO8e2LLc,7021 -ecdsa/test_sha3.py,sha256=0PkWi7AnTJ10YNfDVqj2SB7adeTbV6DCvMg4n9ULad8,3042 -ecdsa/util.py,sha256=UixXH6PR9poMrWQJ93rKpUSVZHxP1AmLwlkrkI3FWFE,18006 diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/WHEEL deleted file mode 100644 index c34f116..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.41.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/top_level.txt deleted file mode 100644 index aa5efdb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa-0.19.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -ecdsa diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/__init__.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/__init__.py deleted file mode 100644 index 342538e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -# while we don't use six in this file, we did bundle it for a long time, so -# keep as part of module in a virtual way (through __all__) -import six -from .keys import ( - SigningKey, - VerifyingKey, - BadSignatureError, - BadDigestError, - MalformedPointError, -) -from .curves import ( - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - SECP256k1, - BRAINPOOLP160r1, - BRAINPOOLP192r1, - BRAINPOOLP224r1, - BRAINPOOLP256r1, - BRAINPOOLP320r1, - BRAINPOOLP384r1, - BRAINPOOLP512r1, - SECP112r1, - SECP112r2, - SECP128r1, - SECP160r1, - Ed25519, - Ed448, - BRAINPOOLP160t1, - BRAINPOOLP192t1, - BRAINPOOLP224t1, - BRAINPOOLP256t1, - BRAINPOOLP320t1, - BRAINPOOLP384t1, - BRAINPOOLP512t1, -) -from .ecdh import ( - ECDH, - NoKeyError, - NoCurveError, - InvalidCurveError, - InvalidSharedSecretError, -) -from .der import UnexpectedDER -from . import _version - -# This code comes from http://github.com/tlsfuzzer/python-ecdsa -__all__ = [ - "curves", - "der", - "ecdsa", - "ellipticcurve", - "keys", - "numbertheory", - "test_pyecdsa", - "util", - "six", -] - -_hush_pyflakes = [ - SigningKey, - VerifyingKey, - BadSignatureError, - BadDigestError, - MalformedPointError, - UnexpectedDER, - InvalidCurveError, - NoKeyError, - InvalidSharedSecretError, - ECDH, - NoCurveError, - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - SECP256k1, - BRAINPOOLP160r1, - BRAINPOOLP192r1, - BRAINPOOLP224r1, - BRAINPOOLP256r1, - BRAINPOOLP320r1, - BRAINPOOLP384r1, - BRAINPOOLP512r1, - SECP112r1, - SECP112r2, - SECP128r1, - SECP160r1, - Ed25519, - Ed448, - six.b(""), - BRAINPOOLP160t1, - BRAINPOOLP192t1, - BRAINPOOLP224t1, - BRAINPOOLP256t1, - BRAINPOOLP320t1, - BRAINPOOLP384t1, - BRAINPOOLP512t1, -] -del _hush_pyflakes - -__version__ = _version.get_versions()["version"] diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/_compat.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/_compat.py deleted file mode 100644 index 4558e33..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/_compat.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -Common functions for providing cross-python version compatibility. -""" -import sys -import re -import binascii -from six import integer_types - - -def str_idx_as_int(string, index): - """Take index'th byte from string, return as integer""" - val = string[index] - if isinstance(val, integer_types): - return val - return ord(val) - - -if sys.version_info < (3, 0): # pragma: no branch - import platform - - def normalise_bytes(buffer_object): - """Cast the input into array of bytes.""" - # flake8 runs on py3 where `buffer` indeed doesn't exist... - return buffer(buffer_object) # noqa: F821 - - def hmac_compat(ret): - return ret - - if ( - sys.version_info < (2, 7) - or sys.version_info < (2, 7, 4) - or platform.system() == "Java" - ): # pragma: no branch - - def remove_whitespace(text): - """Removes all whitespace from passed in string""" - return re.sub(r"\s+", "", text) - - def compat26_str(val): - return str(val) - - def bit_length(val): - if val == 0: - return 0 - return len(bin(val)) - 2 - - else: - - def remove_whitespace(text): - """Removes all whitespace from passed in string""" - return re.sub(r"\s+", "", text, flags=re.UNICODE) - - def compat26_str(val): - return val - - def bit_length(val): - """Return number of bits necessary to represent an integer.""" - return val.bit_length() - - def b2a_hex(val): - return binascii.b2a_hex(compat26_str(val)) - - def a2b_hex(val): - try: - return bytearray(binascii.a2b_hex(val)) - except Exception as e: - raise ValueError("base16 error: %s" % e) - - def bytes_to_int(val, byteorder): - """Convert bytes to an int.""" - if not val: - return 0 - if byteorder == "big": - return int(b2a_hex(val), 16) - if byteorder == "little": - return int(b2a_hex(val[::-1]), 16) - raise ValueError("Only 'big' and 'little' endian supported") - - def int_to_bytes(val, length=None, byteorder="big"): - """Return number converted to bytes""" - if length is None: - length = byte_length(val) - if byteorder == "big": - return bytearray( - (val >> i) & 0xFF for i in reversed(range(0, length * 8, 8)) - ) - if byteorder == "little": - return bytearray( - (val >> i) & 0xFF for i in range(0, length * 8, 8) - ) - raise ValueError("Only 'big' or 'little' endian supported") - -else: - - def hmac_compat(data): - return data - - def normalise_bytes(buffer_object): - """Cast the input into array of bytes.""" - return memoryview(buffer_object).cast("B") - - def compat26_str(val): - return val - - def remove_whitespace(text): - """Removes all whitespace from passed in string""" - return re.sub(r"\s+", "", text, flags=re.UNICODE) - - def a2b_hex(val): - try: - return bytearray(binascii.a2b_hex(bytearray(val, "ascii"))) - except Exception as e: - raise ValueError("base16 error: %s" % e) - - # pylint: disable=invalid-name - # pylint is stupid here and doesn't notice it's a function, not - # constant - bytes_to_int = int.from_bytes - # pylint: enable=invalid-name - - def bit_length(val): - """Return number of bits necessary to represent an integer.""" - return val.bit_length() - - def int_to_bytes(val, length=None, byteorder="big"): - """Convert integer to bytes.""" - if length is None: - length = byte_length(val) - # for gmpy we need to convert back to native int - if not isinstance(val, int): - val = int(val) - return bytearray(val.to_bytes(length=length, byteorder=byteorder)) - - -def byte_length(val): - """Return number of bytes necessary to represent an integer.""" - length = bit_length(val) - return (length + 7) // 8 diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/_rwlock.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/_rwlock.py deleted file mode 100644 index 010e498..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/_rwlock.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright Mateusz Kobos, (c) 2011 -# https://code.activestate.com/recipes/577803-reader-writer-lock-with-priority-for-writers/ -# released under the MIT licence - -import threading - - -__author__ = "Mateusz Kobos" - - -class RWLock: - """ - Read-Write locking primitive - - Synchronization object used in a solution of so-called second - readers-writers problem. In this problem, many readers can simultaneously - access a share, and a writer has an exclusive access to this share. - Additionally, the following constraints should be met: - 1) no reader should be kept waiting if the share is currently opened for - reading unless a writer is also waiting for the share, - 2) no writer should be kept waiting for the share longer than absolutely - necessary. - - The implementation is based on [1, secs. 4.2.2, 4.2.6, 4.2.7] - with a modification -- adding an additional lock (C{self.__readers_queue}) - -- in accordance with [2]. - - Sources: - [1] A.B. Downey: "The little book of semaphores", Version 2.1.5, 2008 - [2] P.J. Courtois, F. Heymans, D.L. Parnas: - "Concurrent Control with 'Readers' and 'Writers'", - Communications of the ACM, 1971 (via [3]) - [3] http://en.wikipedia.org/wiki/Readers-writers_problem - """ - - def __init__(self): - """ - A lock giving an even higher priority to the writer in certain - cases (see [2] for a discussion). - """ - self.__read_switch = _LightSwitch() - self.__write_switch = _LightSwitch() - self.__no_readers = threading.Lock() - self.__no_writers = threading.Lock() - self.__readers_queue = threading.Lock() - - def reader_acquire(self): - self.__readers_queue.acquire() - self.__no_readers.acquire() - self.__read_switch.acquire(self.__no_writers) - self.__no_readers.release() - self.__readers_queue.release() - - def reader_release(self): - self.__read_switch.release(self.__no_writers) - - def writer_acquire(self): - self.__write_switch.acquire(self.__no_readers) - self.__no_writers.acquire() - - def writer_release(self): - self.__no_writers.release() - self.__write_switch.release(self.__no_readers) - - -class _LightSwitch: - """An auxiliary "light switch"-like object. The first thread turns on the - "switch", the last one turns it off (see [1, sec. 4.2.2] for details).""" - - def __init__(self): - self.__counter = 0 - self.__mutex = threading.Lock() - - def acquire(self, lock): - self.__mutex.acquire() - self.__counter += 1 - if self.__counter == 1: - lock.acquire() - self.__mutex.release() - - def release(self, lock): - self.__mutex.acquire() - self.__counter -= 1 - if self.__counter == 0: - lock.release() - self.__mutex.release() diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/_sha3.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/_sha3.py deleted file mode 100644 index 2db0058..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/_sha3.py +++ /dev/null @@ -1,181 +0,0 @@ -""" -Implementation of the SHAKE-256 algorithm for Ed448 -""" - -try: - import hashlib - - hashlib.new("shake256").digest(64) - - def shake_256(msg, outlen): - return hashlib.new("shake256", msg).digest(outlen) - -except (TypeError, ValueError): - - from ._compat import bytes_to_int, int_to_bytes - - # From little endian. - def _from_le(s): - return bytes_to_int(s, byteorder="little") - - # Rotate a word x by b places to the left. - def _rol(x, b): - return ((x << b) | (x >> (64 - b))) & (2**64 - 1) - - # Do the SHA-3 state transform on state s. - def _sha3_transform(s): - ROTATIONS = [ - 0, - 1, - 62, - 28, - 27, - 36, - 44, - 6, - 55, - 20, - 3, - 10, - 43, - 25, - 39, - 41, - 45, - 15, - 21, - 8, - 18, - 2, - 61, - 56, - 14, - ] - PERMUTATION = [ - 1, - 6, - 9, - 22, - 14, - 20, - 2, - 12, - 13, - 19, - 23, - 15, - 4, - 24, - 21, - 8, - 16, - 5, - 3, - 18, - 17, - 11, - 7, - 10, - ] - RC = [ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, - ] - - for rnd in range(0, 24): - # AddColumnParity (Theta) - c = [0] * 5 - d = [0] * 5 - for i in range(0, 25): - c[i % 5] ^= s[i] - for i in range(0, 5): - d[i] = c[(i + 4) % 5] ^ _rol(c[(i + 1) % 5], 1) - for i in range(0, 25): - s[i] ^= d[i % 5] - # RotateWords (Rho) - for i in range(0, 25): - s[i] = _rol(s[i], ROTATIONS[i]) - # PermuteWords (Pi) - t = s[PERMUTATION[0]] - for i in range(0, len(PERMUTATION) - 1): - s[PERMUTATION[i]] = s[PERMUTATION[i + 1]] - s[PERMUTATION[-1]] = t - # NonlinearMixRows (Chi) - for i in range(0, 25, 5): - t = [ - s[i], - s[i + 1], - s[i + 2], - s[i + 3], - s[i + 4], - s[i], - s[i + 1], - ] - for j in range(0, 5): - s[i + j] = t[j] ^ ((~t[j + 1]) & (t[j + 2])) - # AddRoundConstant (Iota) - s[0] ^= RC[rnd] - - # Reinterpret octet array b to word array and XOR it to state s. - def _reinterpret_to_words_and_xor(s, b): - for j in range(0, len(b) // 8): - s[j] ^= _from_le(b[8 * j : 8 * j + 8]) - - # Reinterpret word array w to octet array and return it. - def _reinterpret_to_octets(w): - mp = bytearray() - for j in range(0, len(w)): - mp += int_to_bytes(w[j], 8, byteorder="little") - return mp - - def _sha3_raw(msg, r_w, o_p, e_b): - """Semi-generic SHA-3 implementation""" - r_b = 8 * r_w - s = [0] * 25 - # Handle whole blocks. - idx = 0 - blocks = len(msg) // r_b - for i in range(0, blocks): - _reinterpret_to_words_and_xor(s, msg[idx : idx + r_b]) - idx += r_b - _sha3_transform(s) - # Handle last block padding. - m = bytearray(msg[idx:]) - m.append(o_p) - while len(m) < r_b: - m.append(0) - m[len(m) - 1] |= 128 - # Handle padded last block. - _reinterpret_to_words_and_xor(s, m) - _sha3_transform(s) - # Output. - out = bytearray() - while len(out) < e_b: - out += _reinterpret_to_octets(s[:r_w]) - _sha3_transform(s) - return out[:e_b] - - def shake_256(msg, outlen): - return _sha3_raw(msg, 17, 31, outlen) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/_version.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/_version.py deleted file mode 100644 index d910ff9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/_version.py +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by 'versioneer.py' (0.21) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -{ - "date": "2025-03-13T12:48:15+0100", - "dirty": false, - "error": null, - "full-revisionid": "2a6593d840ad153a16ebdd4f9b772b290494f3e3", - "version": "0.19.1" -} -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/curves.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/curves.py deleted file mode 100644 index 38e3a75..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/curves.py +++ /dev/null @@ -1,590 +0,0 @@ -from __future__ import division - -from six import PY2 -from . import der, ecdsa, ellipticcurve, eddsa -from .util import orderlen, number_to_string, string_to_number -from ._compat import normalise_bytes, bit_length - - -# orderlen was defined in this module previously, so keep it in __all__, -# will need to mark it as deprecated later -__all__ = [ - "UnknownCurveError", - "orderlen", - "Curve", - "SECP112r1", - "SECP112r2", - "SECP128r1", - "SECP160r1", - "NIST192p", - "NIST224p", - "NIST256p", - "NIST384p", - "NIST521p", - "curves", - "find_curve", - "curve_by_name", - "SECP256k1", - "BRAINPOOLP160r1", - "BRAINPOOLP160t1", - "BRAINPOOLP192r1", - "BRAINPOOLP192t1", - "BRAINPOOLP224r1", - "BRAINPOOLP224t1", - "BRAINPOOLP256r1", - "BRAINPOOLP256t1", - "BRAINPOOLP320r1", - "BRAINPOOLP320t1", - "BRAINPOOLP384r1", - "BRAINPOOLP384t1", - "BRAINPOOLP512r1", - "BRAINPOOLP512t1", - "PRIME_FIELD_OID", - "CHARACTERISTIC_TWO_FIELD_OID", - "Ed25519", - "Ed448", -] - - -PRIME_FIELD_OID = (1, 2, 840, 10045, 1, 1) -CHARACTERISTIC_TWO_FIELD_OID = (1, 2, 840, 10045, 1, 2) - - -class UnknownCurveError(Exception): - pass - - -class Curve: - def __init__(self, name, curve, generator, oid, openssl_name=None): - self.name = name - self.openssl_name = openssl_name # maybe None - self.curve = curve - self.generator = generator - self.order = generator.order() - if isinstance(curve, ellipticcurve.CurveEdTw): - # EdDSA keys are special in that both private and public - # are the same size (as it's defined only with compressed points) - - # +1 for the sign bit and then round up - self.baselen = (bit_length(curve.p()) + 1 + 7) // 8 - self.verifying_key_length = self.baselen - else: - self.baselen = orderlen(self.order) - self.verifying_key_length = 2 * orderlen(curve.p()) - self.signature_length = 2 * self.baselen - self.oid = oid - if oid: - self.encoded_oid = der.encode_oid(*oid) - - def __eq__(self, other): - if isinstance(other, Curve): - return ( - self.curve == other.curve and self.generator == other.generator - ) - return NotImplemented - - def __ne__(self, other): - return not self == other - - def __repr__(self): - return self.name - - def to_der(self, encoding=None, point_encoding="uncompressed"): - """Serialise the curve parameters to binary string. - - :param str encoding: the format to save the curve parameters in. - Default is ``named_curve``, with fallback being the ``explicit`` - if the OID is not set for the curve. - :param str point_encoding: the point encoding of the generator when - explicit curve encoding is used. Ignored for ``named_curve`` - format. - - :return: DER encoded ECParameters structure - :rtype: bytes - """ - if encoding is None: - if self.oid: - encoding = "named_curve" - else: - encoding = "explicit" - - if encoding not in ("named_curve", "explicit"): - raise ValueError( - "Only 'named_curve' and 'explicit' encodings supported" - ) - - if encoding == "named_curve": - if not self.oid: - raise UnknownCurveError( - "Can't encode curve using named_curve encoding without " - "associated curve OID" - ) - return der.encode_oid(*self.oid) - elif isinstance(self.curve, ellipticcurve.CurveEdTw): - assert encoding == "explicit" - raise UnknownCurveError( - "Twisted Edwards curves don't support explicit encoding" - ) - - # encode the ECParameters sequence - curve_p = self.curve.p() - version = der.encode_integer(1) - field_id = der.encode_sequence( - der.encode_oid(*PRIME_FIELD_OID), der.encode_integer(curve_p) - ) - curve = der.encode_sequence( - der.encode_octet_string( - number_to_string(self.curve.a() % curve_p, curve_p) - ), - der.encode_octet_string( - number_to_string(self.curve.b() % curve_p, curve_p) - ), - ) - base = der.encode_octet_string(self.generator.to_bytes(point_encoding)) - order = der.encode_integer(self.generator.order()) - seq_elements = [version, field_id, curve, base, order] - if self.curve.cofactor(): - cofactor = der.encode_integer(self.curve.cofactor()) - seq_elements.append(cofactor) - - return der.encode_sequence(*seq_elements) - - def to_pem(self, encoding=None, point_encoding="uncompressed"): - """ - Serialise the curve parameters to the :term:`PEM` format. - - :param str encoding: the format to save the curve parameters in. - Default is ``named_curve``, with fallback being the ``explicit`` - if the OID is not set for the curve. - :param str point_encoding: the point encoding of the generator when - explicit curve encoding is used. Ignored for ``named_curve`` - format. - - :return: PEM encoded ECParameters structure - :rtype: str - """ - return der.topem( - self.to_der(encoding, point_encoding), "EC PARAMETERS" - ) - - @staticmethod - def from_der(data, valid_encodings=None): - """Decode the curve parameters from DER file. - - :param data: the binary string to decode the parameters from - :type data: :term:`bytes-like object` - :param valid_encodings: set of names of allowed encodings, by default - all (set by passing ``None``), supported ones are ``named_curve`` - and ``explicit`` - :type valid_encodings: :term:`set-like object` - """ - if not valid_encodings: - valid_encodings = set(("named_curve", "explicit")) - if not all(i in ["named_curve", "explicit"] for i in valid_encodings): - raise ValueError( - "Only named_curve and explicit encodings supported" - ) - data = normalise_bytes(data) - if not der.is_sequence(data): - if "named_curve" not in valid_encodings: - raise der.UnexpectedDER( - "named_curve curve parameters not allowed" - ) - oid, empty = der.remove_object(data) - if empty: - raise der.UnexpectedDER("Unexpected data after OID") - return find_curve(oid) - - if "explicit" not in valid_encodings: - raise der.UnexpectedDER("explicit curve parameters not allowed") - - seq, empty = der.remove_sequence(data) - if empty: - raise der.UnexpectedDER( - "Unexpected data after ECParameters structure" - ) - # decode the ECParameters sequence - version, rest = der.remove_integer(seq) - if version != 1: - raise der.UnexpectedDER("Unknown parameter encoding format") - field_id, rest = der.remove_sequence(rest) - curve, rest = der.remove_sequence(rest) - base_bytes, rest = der.remove_octet_string(rest) - order, rest = der.remove_integer(rest) - cofactor = None - if rest: - # the ASN.1 specification of ECParameters allows for future - # extensions of the sequence, so ignore the remaining bytes - cofactor, _ = der.remove_integer(rest) - - # decode the ECParameters.fieldID sequence - field_type, rest = der.remove_object(field_id) - if field_type == CHARACTERISTIC_TWO_FIELD_OID: - raise UnknownCurveError("Characteristic 2 curves unsupported") - if field_type != PRIME_FIELD_OID: - raise UnknownCurveError( - "Unknown field type: {0}".format(field_type) - ) - prime, empty = der.remove_integer(rest) - if empty: - raise der.UnexpectedDER( - "Unexpected data after ECParameters.fieldID.Prime-p element" - ) - - # decode the ECParameters.curve sequence - curve_a_bytes, rest = der.remove_octet_string(curve) - curve_b_bytes, rest = der.remove_octet_string(rest) - # seed can be defined here, but we don't parse it, so ignore `rest` - - curve_a = string_to_number(curve_a_bytes) - curve_b = string_to_number(curve_b_bytes) - - curve_fp = ellipticcurve.CurveFp(prime, curve_a, curve_b, cofactor) - - # decode the ECParameters.base point - - base = ellipticcurve.PointJacobi.from_bytes( - curve_fp, - base_bytes, - valid_encodings=("uncompressed", "compressed", "hybrid"), - order=order, - generator=True, - ) - tmp_curve = Curve("unknown", curve_fp, base, None) - - # if the curve matches one of the well-known ones, use the well-known - # one in preference, as it will have the OID and name associated - for i in curves: - if tmp_curve == i: - return i - return tmp_curve - - @classmethod - def from_pem(cls, string, valid_encodings=None): - """Decode the curve parameters from PEM file. - - :param str string: the text string to decode the parameters from - :param valid_encodings: set of names of allowed encodings, by default - all (set by passing ``None``), supported ones are ``named_curve`` - and ``explicit`` - :type valid_encodings: :term:`set-like object` - """ - if not PY2 and isinstance(string, str): # pragma: no branch - string = string.encode() - - ec_param_index = string.find(b"-----BEGIN EC PARAMETERS-----") - if ec_param_index == -1: - raise der.UnexpectedDER("EC PARAMETERS PEM header not found") - - return cls.from_der( - der.unpem(string[ec_param_index:]), valid_encodings - ) - - -# the SEC curves -SECP112r1 = Curve( - "SECP112r1", - ecdsa.curve_112r1, - ecdsa.generator_112r1, - (1, 3, 132, 0, 6), - "secp112r1", -) - - -SECP112r2 = Curve( - "SECP112r2", - ecdsa.curve_112r2, - ecdsa.generator_112r2, - (1, 3, 132, 0, 7), - "secp112r2", -) - - -SECP128r1 = Curve( - "SECP128r1", - ecdsa.curve_128r1, - ecdsa.generator_128r1, - (1, 3, 132, 0, 28), - "secp128r1", -) - - -SECP160r1 = Curve( - "SECP160r1", - ecdsa.curve_160r1, - ecdsa.generator_160r1, - (1, 3, 132, 0, 8), - "secp160r1", -) - - -# the NIST curves -NIST192p = Curve( - "NIST192p", - ecdsa.curve_192, - ecdsa.generator_192, - (1, 2, 840, 10045, 3, 1, 1), - "prime192v1", -) - - -NIST224p = Curve( - "NIST224p", - ecdsa.curve_224, - ecdsa.generator_224, - (1, 3, 132, 0, 33), - "secp224r1", -) - - -NIST256p = Curve( - "NIST256p", - ecdsa.curve_256, - ecdsa.generator_256, - (1, 2, 840, 10045, 3, 1, 7), - "prime256v1", -) - - -NIST384p = Curve( - "NIST384p", - ecdsa.curve_384, - ecdsa.generator_384, - (1, 3, 132, 0, 34), - "secp384r1", -) - - -NIST521p = Curve( - "NIST521p", - ecdsa.curve_521, - ecdsa.generator_521, - (1, 3, 132, 0, 35), - "secp521r1", -) - - -SECP256k1 = Curve( - "SECP256k1", - ecdsa.curve_secp256k1, - ecdsa.generator_secp256k1, - (1, 3, 132, 0, 10), - "secp256k1", -) - - -BRAINPOOLP160r1 = Curve( - "BRAINPOOLP160r1", - ecdsa.curve_brainpoolp160r1, - ecdsa.generator_brainpoolp160r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 1), - "brainpoolP160r1", -) - - -BRAINPOOLP160t1 = Curve( - "BRAINPOOLP160t1", - ecdsa.curve_brainpoolp160t1, - ecdsa.generator_brainpoolp160t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 2), - "brainpoolP160t1", -) - - -BRAINPOOLP192r1 = Curve( - "BRAINPOOLP192r1", - ecdsa.curve_brainpoolp192r1, - ecdsa.generator_brainpoolp192r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 3), - "brainpoolP192r1", -) - - -BRAINPOOLP192t1 = Curve( - "BRAINPOOLP192t1", - ecdsa.curve_brainpoolp192t1, - ecdsa.generator_brainpoolp192t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 4), - "brainpoolP192t1", -) - - -BRAINPOOLP224r1 = Curve( - "BRAINPOOLP224r1", - ecdsa.curve_brainpoolp224r1, - ecdsa.generator_brainpoolp224r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 5), - "brainpoolP224r1", -) - - -BRAINPOOLP224t1 = Curve( - "BRAINPOOLP224t1", - ecdsa.curve_brainpoolp224t1, - ecdsa.generator_brainpoolp224t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 6), - "brainpoolP224t1", -) - - -BRAINPOOLP256r1 = Curve( - "BRAINPOOLP256r1", - ecdsa.curve_brainpoolp256r1, - ecdsa.generator_brainpoolp256r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 7), - "brainpoolP256r1", -) - - -BRAINPOOLP256t1 = Curve( - "BRAINPOOLP256t1", - ecdsa.curve_brainpoolp256t1, - ecdsa.generator_brainpoolp256t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 8), - "brainpoolP256t1", -) - - -BRAINPOOLP320r1 = Curve( - "BRAINPOOLP320r1", - ecdsa.curve_brainpoolp320r1, - ecdsa.generator_brainpoolp320r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 9), - "brainpoolP320r1", -) - - -BRAINPOOLP320t1 = Curve( - "BRAINPOOLP320t1", - ecdsa.curve_brainpoolp320t1, - ecdsa.generator_brainpoolp320t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 10), - "brainpoolP320t1", -) - - -BRAINPOOLP384r1 = Curve( - "BRAINPOOLP384r1", - ecdsa.curve_brainpoolp384r1, - ecdsa.generator_brainpoolp384r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 11), - "brainpoolP384r1", -) - - -BRAINPOOLP384t1 = Curve( - "BRAINPOOLP384t1", - ecdsa.curve_brainpoolp384t1, - ecdsa.generator_brainpoolp384t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 12), - "brainpoolP384t1", -) - - -BRAINPOOLP512r1 = Curve( - "BRAINPOOLP512r1", - ecdsa.curve_brainpoolp512r1, - ecdsa.generator_brainpoolp512r1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 13), - "brainpoolP512r1", -) - - -BRAINPOOLP512t1 = Curve( - "BRAINPOOLP512t1", - ecdsa.curve_brainpoolp512t1, - ecdsa.generator_brainpoolp512t1, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 14), - "brainpoolP512t1", -) - - -Ed25519 = Curve( - "Ed25519", - eddsa.curve_ed25519, - eddsa.generator_ed25519, - (1, 3, 101, 112), -) - - -Ed448 = Curve( - "Ed448", - eddsa.curve_ed448, - eddsa.generator_ed448, - (1, 3, 101, 113), -) - - -# no order in particular, but keep previously added curves first -curves = [ - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - SECP256k1, - BRAINPOOLP160r1, - BRAINPOOLP192r1, - BRAINPOOLP224r1, - BRAINPOOLP256r1, - BRAINPOOLP320r1, - BRAINPOOLP384r1, - BRAINPOOLP512r1, - SECP112r1, - SECP112r2, - SECP128r1, - SECP160r1, - Ed25519, - Ed448, - BRAINPOOLP160t1, - BRAINPOOLP192t1, - BRAINPOOLP224t1, - BRAINPOOLP256t1, - BRAINPOOLP320t1, - BRAINPOOLP384t1, - BRAINPOOLP512t1, -] - - -def find_curve(oid_curve): - """Select a curve based on its OID - - :param tuple[int,...] oid_curve: ASN.1 Object Identifier of the - curve to return, like ``(1, 2, 840, 10045, 3, 1, 7)`` for ``NIST256p``. - - :raises UnknownCurveError: When the oid doesn't match any of the supported - curves - - :rtype: ~ecdsa.curves.Curve - """ - for c in curves: - if c.oid == oid_curve: - return c - raise UnknownCurveError( - "I don't know about the curve with oid %s." - "I only know about these: %s" % (oid_curve, [c.name for c in curves]) - ) - - -def curve_by_name(name): - """Select a curve based on its name. - - Returns a :py:class:`~ecdsa.curves.Curve` object with a ``name`` name. - Note that ``name`` is case-sensitve. - - :param str name: Name of the curve to return, like ``NIST256p`` or - ``prime256v1`` - - :raises UnknownCurveError: When the name doesn't match any of the supported - curves - - :rtype: ~ecdsa.curves.Curve - """ - for c in curves: - if name == c.name or (c.openssl_name and name == c.openssl_name): - return c - raise UnknownCurveError( - "Curve with name {0!r} unknown, only curves supported: {1}".format( - name, [c.name for c in curves] - ) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/der.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/der.py deleted file mode 100644 index 7a06b68..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/der.py +++ /dev/null @@ -1,478 +0,0 @@ -from __future__ import division - -import binascii -import base64 -import warnings -from itertools import chain -from six import int2byte, text_type -from ._compat import compat26_str, str_idx_as_int - - -class UnexpectedDER(Exception): - pass - - -def encode_constructed(tag, value): - return int2byte(0xA0 + tag) + encode_length(len(value)) + value - - -def encode_implicit(tag, value, cls="context-specific"): - """ - Encode and IMPLICIT value using :term:`DER`. - - :param int tag: the tag value to encode, must be between 0 an 31 inclusive - :param bytes value: the data to encode - :param str cls: the class of the tag to encode: "application", - "context-specific", or "private" - :rtype: bytes - """ - if cls not in ("application", "context-specific", "private"): - raise ValueError("invalid tag class") - if tag > 31: - raise ValueError("Long tags not supported") - - if cls == "application": - tag_class = 0b01000000 - elif cls == "context-specific": - tag_class = 0b10000000 - else: - assert cls == "private" - tag_class = 0b11000000 - - return int2byte(tag_class + tag) + encode_length(len(value)) + value - - -def encode_integer(r): - assert r >= 0 # can't support negative numbers yet - h = ("%x" % r).encode() - if len(h) % 2: - h = b"0" + h - s = binascii.unhexlify(h) - num = str_idx_as_int(s, 0) - if num <= 0x7F: - return b"\x02" + encode_length(len(s)) + s - else: - # DER integers are two's complement, so if the first byte is - # 0x80-0xff then we need an extra 0x00 byte to prevent it from - # looking negative. - return b"\x02" + encode_length(len(s) + 1) + b"\x00" + s - - -# sentry object to check if an argument was specified (used to detect -# deprecated calling convention) -_sentry = object() - - -def encode_bitstring(s, unused=_sentry): - """ - Encode a binary string as a BIT STRING using :term:`DER` encoding. - - Note, because there is no native Python object that can encode an actual - bit string, this function only accepts byte strings as the `s` argument. - The byte string is the actual bit string that will be encoded, padded - on the right (least significant bits, looking from big endian perspective) - to the first full byte. If the bit string has a bit length that is multiple - of 8, then the padding should not be included. For correct DER encoding - the padding bits MUST be set to 0. - - Number of bits of padding need to be provided as the `unused` parameter. - In case they are specified as None, it means the number of unused bits - is already encoded in the string as the first byte. - - The deprecated call convention specifies just the `s` parameters and - encodes the number of unused bits as first parameter (same convention - as with None). - - Empty string must be encoded with `unused` specified as 0. - - Future version of python-ecdsa will make specifying the `unused` argument - mandatory. - - :param s: bytes to encode - :type s: bytes like object - :param unused: number of bits at the end of `s` that are unused, must be - between 0 and 7 (inclusive) - :type unused: int or None - - :raises ValueError: when `unused` is too large or too small - - :return: `s` encoded using DER - :rtype: bytes - """ - encoded_unused = b"" - len_extra = 0 - if unused is _sentry: - warnings.warn( - "Legacy call convention used, unused= needs to be specified", - DeprecationWarning, - ) - elif unused is not None: - if not 0 <= unused <= 7: - raise ValueError("unused must be integer between 0 and 7") - if unused: - if not s: - raise ValueError("unused is non-zero but s is empty") - last = str_idx_as_int(s, -1) - if last & (2**unused - 1): - raise ValueError("unused bits must be zeros in DER") - encoded_unused = int2byte(unused) - len_extra = 1 - return b"\x03" + encode_length(len(s) + len_extra) + encoded_unused + s - - -def encode_octet_string(s): - return b"\x04" + encode_length(len(s)) + s - - -def encode_oid(first, second, *pieces): - assert 0 <= first < 2 and 0 <= second <= 39 or first == 2 and 0 <= second - body = b"".join( - chain( - [encode_number(40 * first + second)], - (encode_number(p) for p in pieces), - ) - ) - return b"\x06" + encode_length(len(body)) + body - - -def encode_sequence(*encoded_pieces): - total_len = sum([len(p) for p in encoded_pieces]) - return b"\x30" + encode_length(total_len) + b"".join(encoded_pieces) - - -def encode_number(n): - b128_digits = [] - while n: - b128_digits.insert(0, (n & 0x7F) | 0x80) - n = n >> 7 - if not b128_digits: - b128_digits.append(0) - b128_digits[-1] &= 0x7F - return b"".join([int2byte(d) for d in b128_digits]) - - -def is_sequence(string): - return string and string[:1] == b"\x30" - - -def remove_constructed(string): - s0 = str_idx_as_int(string, 0) - if (s0 & 0xE0) != 0xA0: - raise UnexpectedDER( - "wanted type 'constructed tag' (0xa0-0xbf), got 0x%02x" % s0 - ) - tag = s0 & 0x1F - length, llen = read_length(string[1:]) - body = string[1 + llen : 1 + llen + length] - rest = string[1 + llen + length :] - return tag, body, rest - - -def remove_implicit(string, exp_class="context-specific"): - """ - Removes an IMPLICIT tagged value from ``string`` following :term:`DER`. - - :param bytes string: a byte string that can have one or more - DER elements. - :param str exp_class: the expected tag class of the implicitly - encoded value. Possible values are: "context-specific", "application", - and "private". - :return: a tuple with first value being the tag without indicator bits, - second being the raw bytes of the value and the third one being - remaining bytes (or an empty string if there are none) - :rtype: tuple(int,bytes,bytes) - """ - if exp_class not in ("context-specific", "application", "private"): - raise ValueError("invalid `exp_class` value") - if exp_class == "application": - tag_class = 0b01000000 - elif exp_class == "context-specific": - tag_class = 0b10000000 - else: - assert exp_class == "private" - tag_class = 0b11000000 - tag_mask = 0b11000000 - - s0 = str_idx_as_int(string, 0) - - if (s0 & tag_mask) != tag_class: - raise UnexpectedDER( - "wanted class {0}, got 0x{1:02x} tag".format(exp_class, s0) - ) - if s0 & 0b00100000 != 0: - raise UnexpectedDER( - "wanted type primitive, got 0x{0:02x} tag".format(s0) - ) - - tag = s0 & 0x1F - length, llen = read_length(string[1:]) - body = string[1 + llen : 1 + llen + length] - rest = string[1 + llen + length :] - return tag, body, rest - - -def remove_sequence(string): - if not string: - raise UnexpectedDER("Empty string does not encode a sequence") - if string[:1] != b"\x30": - n = str_idx_as_int(string, 0) - raise UnexpectedDER("wanted type 'sequence' (0x30), got 0x%02x" % n) - length, lengthlength = read_length(string[1:]) - if length > len(string) - 1 - lengthlength: - raise UnexpectedDER("Length longer than the provided buffer") - endseq = 1 + lengthlength + length - return string[1 + lengthlength : endseq], string[endseq:] - - -def remove_octet_string(string): - if string[:1] != b"\x04": - n = str_idx_as_int(string, 0) - raise UnexpectedDER("wanted type 'octetstring' (0x04), got 0x%02x" % n) - length, llen = read_length(string[1:]) - body = string[1 + llen : 1 + llen + length] - rest = string[1 + llen + length :] - return body, rest - - -def remove_object(string): - if not string: - raise UnexpectedDER( - "Empty string does not encode an object identifier" - ) - if string[:1] != b"\x06": - n = str_idx_as_int(string, 0) - raise UnexpectedDER("wanted type 'object' (0x06), got 0x%02x" % n) - length, lengthlength = read_length(string[1:]) - body = string[1 + lengthlength : 1 + lengthlength + length] - rest = string[1 + lengthlength + length :] - if not body: - raise UnexpectedDER("Empty object identifier") - if len(body) != length: - raise UnexpectedDER( - "Length of object identifier longer than the provided buffer" - ) - numbers = [] - while body: - n, ll = read_number(body) - numbers.append(n) - body = body[ll:] - n0 = numbers.pop(0) - if n0 < 80: - first = n0 // 40 - else: - first = 2 - second = n0 - (40 * first) - numbers.insert(0, first) - numbers.insert(1, second) - return tuple(numbers), rest - - -def remove_integer(string): - if not string: - raise UnexpectedDER( - "Empty string is an invalid encoding of an integer" - ) - if string[:1] != b"\x02": - n = str_idx_as_int(string, 0) - raise UnexpectedDER("wanted type 'integer' (0x02), got 0x%02x" % n) - length, llen = read_length(string[1:]) - if length > len(string) - 1 - llen: - raise UnexpectedDER("Length longer than provided buffer") - if length == 0: - raise UnexpectedDER("0-byte long encoding of integer") - numberbytes = string[1 + llen : 1 + llen + length] - rest = string[1 + llen + length :] - msb = str_idx_as_int(numberbytes, 0) - if not msb < 0x80: - raise UnexpectedDER("Negative integers are not supported") - # check if the encoding is the minimal one (DER requirement) - if length > 1 and not msb: - # leading zero byte is allowed if the integer would have been - # considered a negative number otherwise - smsb = str_idx_as_int(numberbytes, 1) - if smsb < 0x80: - raise UnexpectedDER( - "Invalid encoding of integer, unnecessary " - "zero padding bytes" - ) - return int(binascii.hexlify(numberbytes), 16), rest - - -def read_number(string): - number = 0 - llen = 0 - if str_idx_as_int(string, 0) == 0x80: - raise UnexpectedDER("Non minimal encoding of OID subidentifier") - # base-128 big endian, with most significant bit set in all but the last - # byte - while True: - if llen >= len(string): - raise UnexpectedDER("ran out of length bytes") - number = number << 7 - d = str_idx_as_int(string, llen) - number += d & 0x7F - llen += 1 - if not d & 0x80: - break - return number, llen - - -def encode_length(l): - assert l >= 0 - if l < 0x80: - return int2byte(l) - s = ("%x" % l).encode() - if len(s) % 2: - s = b"0" + s - s = binascii.unhexlify(s) - llen = len(s) - return int2byte(0x80 | llen) + s - - -def read_length(string): - if not string: - raise UnexpectedDER("Empty string can't encode valid length value") - num = str_idx_as_int(string, 0) - if not (num & 0x80): - # short form - return (num & 0x7F), 1 - # else long-form: b0&0x7f is number of additional base256 length bytes, - # big-endian - llen = num & 0x7F - if not llen: - raise UnexpectedDER("Invalid length encoding, length of length is 0") - if llen > len(string) - 1: - raise UnexpectedDER("Length of length longer than provided buffer") - # verify that the encoding is minimal possible (DER requirement) - msb = str_idx_as_int(string, 1) - if not msb or llen == 1 and msb < 0x80: - raise UnexpectedDER("Not minimal encoding of length") - return int(binascii.hexlify(string[1 : 1 + llen]), 16), 1 + llen - - -def remove_bitstring(string, expect_unused=_sentry): - """ - Remove a BIT STRING object from `string` following :term:`DER`. - - The `expect_unused` can be used to specify if the bit string should - have the amount of unused bits decoded or not. If it's an integer, any - read BIT STRING that has number of unused bits different from specified - value will cause UnexpectedDER exception to be raised (this is especially - useful when decoding BIT STRINGS that have DER encoded object in them; - DER encoding is byte oriented, so the unused bits will always equal 0). - - If the `expect_unused` is specified as None, the first element returned - will be a tuple, with the first value being the extracted bit string - while the second value will be the decoded number of unused bits. - - If the `expect_unused` is unspecified, the decoding of byte with - number of unused bits will not be attempted and the bit string will be - returned as-is, the callee will be required to decode it and verify its - correctness. - - Future version of python will require the `expected_unused` parameter - to be specified. - - :param string: string of bytes to extract the BIT STRING from - :type string: bytes like object - :param expect_unused: number of bits that should be unused in the BIT - STRING, or None, to return it to caller - :type expect_unused: int or None - - :raises UnexpectedDER: when the encoding does not follow DER. - - :return: a tuple with first element being the extracted bit string and - the second being the remaining bytes in the string (if any); if the - `expect_unused` is specified as None, the first element of the returned - tuple will be a tuple itself, with first element being the bit string - as bytes and the second element being the number of unused bits at the - end of the byte array as an integer - :rtype: tuple - """ - if not string: - raise UnexpectedDER("Empty string does not encode a bitstring") - if expect_unused is _sentry: - warnings.warn( - "Legacy call convention used, expect_unused= needs to be" - " specified", - DeprecationWarning, - ) - num = str_idx_as_int(string, 0) - if string[:1] != b"\x03": - raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" % num) - length, llen = read_length(string[1:]) - if not length: - raise UnexpectedDER("Invalid length of bit string, can't be 0") - body = string[1 + llen : 1 + llen + length] - rest = string[1 + llen + length :] - if expect_unused is not _sentry: - unused = str_idx_as_int(body, 0) - if not 0 <= unused <= 7: - raise UnexpectedDER("Invalid encoding of unused bits") - if expect_unused is not None and expect_unused != unused: - raise UnexpectedDER("Unexpected number of unused bits") - body = body[1:] - if unused: - if not body: - raise UnexpectedDER("Invalid encoding of empty bit string") - last = str_idx_as_int(body, -1) - # verify that all the unused bits are set to zero (DER requirement) - if last & (2**unused - 1): - raise UnexpectedDER("Non zero padding bits in bit string") - if expect_unused is None: - body = (body, unused) - return body, rest - - -# SEQUENCE([1, STRING(secexp), cont[0], OBJECT(curvename), cont[1], BINTSTRING) - - -# signatures: (from RFC3279) -# ansi-X9-62 OBJECT IDENTIFIER ::= { -# iso(1) member-body(2) us(840) 10045 } -# -# id-ecSigType OBJECT IDENTIFIER ::= { -# ansi-X9-62 signatures(4) } -# ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { -# id-ecSigType 1 } -# so 1,2,840,10045,4,1 -# so 0x42, .. .. - -# Ecdsa-Sig-Value ::= SEQUENCE { -# r INTEGER, -# s INTEGER } - -# id-public-key-type OBJECT IDENTIFIER ::= { ansi-X9.62 2 } -# -# id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 } - -# I think the secp224r1 identifier is (t=06,l=05,v=2b81040021) -# secp224r1 OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) curve(0) 33 } -# and the secp384r1 is (t=06,l=05,v=2b81040022) -# secp384r1 OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) curve(0) 34 } - - -def unpem(pem): - if isinstance(pem, text_type): # pragma: no branch - pem = pem.encode() - - d = b"".join( - [ - l.strip() - for l in pem.split(b"\n") - if l and not l.startswith(b"-----") - ] - ) - return base64.b64decode(d) - - -def topem(der, name): - b64 = base64.b64encode(compat26_str(der)) - lines = [("-----BEGIN %s-----\n" % name).encode()] - lines.extend( - [b64[start : start + 76] + b"\n" for start in range(0, len(b64), 76)] - ) - lines.append(("-----END %s-----\n" % name).encode()) - return b"".join(lines) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdh.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdh.py deleted file mode 100644 index 7f697d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdh.py +++ /dev/null @@ -1,336 +0,0 @@ -""" -Class for performing Elliptic-curve Diffie-Hellman (ECDH) operations. -""" - -from .util import number_to_string -from .ellipticcurve import INFINITY -from .keys import SigningKey, VerifyingKey - - -__all__ = [ - "ECDH", - "NoKeyError", - "NoCurveError", - "InvalidCurveError", - "InvalidSharedSecretError", -] - - -class NoKeyError(Exception): - """ECDH. Key not found but it is needed for operation.""" - - pass - - -class NoCurveError(Exception): - """ECDH. Curve not set but it is needed for operation.""" - - pass - - -class InvalidCurveError(Exception): - """ - ECDH. Raised in case the public and private keys use different curves. - """ - - pass - - -class InvalidSharedSecretError(Exception): - """ECDH. Raised in case the shared secret we obtained is an INFINITY.""" - - pass - - -class ECDH(object): - """ - Elliptic-curve Diffie-Hellman (ECDH). A key agreement protocol. - - Allows two parties, each having an elliptic-curve public-private key - pair, to establish a shared secret over an insecure channel - """ - - def __init__(self, curve=None, private_key=None, public_key=None): - """ - ECDH init. - - Call can be initialised without parameters, then the first operation - (loading either key) will set the used curve. - All parameters must be ultimately set before shared secret - calculation will be allowed. - - :param curve: curve for operations - :type curve: Curve - :param private_key: `my` private key for ECDH - :type private_key: SigningKey - :param public_key: `their` public key for ECDH - :type public_key: VerifyingKey - """ - self.curve = curve - self.private_key = None - self.public_key = None - if private_key: - self.load_private_key(private_key) - if public_key: - self.load_received_public_key(public_key) - - def _get_shared_secret(self, remote_public_key): - if not self.private_key: - raise NoKeyError( - "Private key needs to be set to create shared secret" - ) - if not self.public_key: - raise NoKeyError( - "Public key needs to be set to create shared secret" - ) - if not ( - self.private_key.curve == self.curve == remote_public_key.curve - ): - raise InvalidCurveError( - "Curves for public key and private key is not equal." - ) - - # shared secret = PUBKEYtheirs * PRIVATEKEYours - result = ( - remote_public_key.pubkey.point - * self.private_key.privkey.secret_multiplier - ) - if result == INFINITY: - raise InvalidSharedSecretError("Invalid shared secret (INFINITY).") - - return result.x() - - def set_curve(self, key_curve): - """ - Set the working curve for ecdh operations. - - :param key_curve: curve from `curves` module - :type key_curve: Curve - """ - self.curve = key_curve - - def generate_private_key(self): - """ - Generate local private key for ecdh operation with curve that was set. - - :raises NoCurveError: Curve must be set before key generation. - - :return: public (verifying) key from this private key. - :rtype: VerifyingKey - """ - if not self.curve: - raise NoCurveError("Curve must be set prior to key generation.") - return self.load_private_key(SigningKey.generate(curve=self.curve)) - - def load_private_key(self, private_key): - """ - Load private key from SigningKey (keys.py) object. - - Needs to have the same curve as was set with set_curve method. - If curve is not set - it sets from this SigningKey - - :param private_key: Initialised SigningKey class - :type private_key: SigningKey - - :raises InvalidCurveError: private_key curve not the same as self.curve - - :return: public (verifying) key from this private key. - :rtype: VerifyingKey - """ - if not self.curve: - self.curve = private_key.curve - if self.curve != private_key.curve: - raise InvalidCurveError("Curve mismatch.") - self.private_key = private_key - return self.private_key.get_verifying_key() - - def load_private_key_bytes(self, private_key): - """ - Load private key from byte string. - - Uses current curve and checks if the provided key matches - the curve of ECDH key agreement. - Key loads via from_string method of SigningKey class - - :param private_key: private key in bytes string format - :type private_key: :term:`bytes-like object` - - :raises NoCurveError: Curve must be set before loading. - - :return: public (verifying) key from this private key. - :rtype: VerifyingKey - """ - if not self.curve: - raise NoCurveError("Curve must be set prior to key load.") - return self.load_private_key( - SigningKey.from_string(private_key, curve=self.curve) - ) - - def load_private_key_der(self, private_key_der): - """ - Load private key from DER byte string. - - Compares the curve of the DER-encoded key with the ECDH set curve, - uses the former if unset. - - Note, the only DER format supported is the RFC5915 - Look at keys.py:SigningKey.from_der() - - :param private_key_der: string with the DER encoding of private ECDSA - key - :type private_key_der: string - - :raises InvalidCurveError: private_key curve not the same as self.curve - - :return: public (verifying) key from this private key. - :rtype: VerifyingKey - """ - return self.load_private_key(SigningKey.from_der(private_key_der)) - - def load_private_key_pem(self, private_key_pem): - """ - Load private key from PEM string. - - Compares the curve of the DER-encoded key with the ECDH set curve, - uses the former if unset. - - Note, the only PEM format supported is the RFC5915 - Look at keys.py:SigningKey.from_pem() - it needs to have `EC PRIVATE KEY` section - - :param private_key_pem: string with PEM-encoded private ECDSA key - :type private_key_pem: string - - :raises InvalidCurveError: private_key curve not the same as self.curve - - :return: public (verifying) key from this private key. - :rtype: VerifyingKey - """ - return self.load_private_key(SigningKey.from_pem(private_key_pem)) - - def get_public_key(self): - """ - Provides a public key that matches the local private key. - - Needs to be sent to the remote party. - - :return: public (verifying) key from local private key. - :rtype: VerifyingKey - """ - return self.private_key.get_verifying_key() - - def load_received_public_key(self, public_key): - """ - Load public key from VerifyingKey (keys.py) object. - - Needs to have the same curve as set as current for ecdh operation. - If curve is not set - it sets it from VerifyingKey. - - :param public_key: Initialised VerifyingKey class - :type public_key: VerifyingKey - - :raises InvalidCurveError: public_key curve not the same as self.curve - """ - if not self.curve: - self.curve = public_key.curve - if self.curve != public_key.curve: - raise InvalidCurveError("Curve mismatch.") - self.public_key = public_key - - def load_received_public_key_bytes( - self, public_key_str, valid_encodings=None - ): - """ - Load public key from byte string. - - Uses current curve and checks if key length corresponds to - the current curve. - Key loads via from_string method of VerifyingKey class - - :param public_key_str: public key in bytes string format - :type public_key_str: :term:`bytes-like object` - :param valid_encodings: list of acceptable point encoding formats, - supported ones are: :term:`uncompressed`, :term:`compressed`, - :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` - name). All formats by default (specified with ``None``). - :type valid_encodings: :term:`set-like object` - """ - return self.load_received_public_key( - VerifyingKey.from_string( - public_key_str, self.curve, valid_encodings - ) - ) - - def load_received_public_key_der(self, public_key_der): - """ - Load public key from DER byte string. - - Compares the curve of the DER-encoded key with the ECDH set curve, - uses the former if unset. - - Note, the only DER format supported is the RFC5912 - Look at keys.py:VerifyingKey.from_der() - - :param public_key_der: string with the DER encoding of public ECDSA key - :type public_key_der: string - - :raises InvalidCurveError: public_key curve not the same as self.curve - """ - return self.load_received_public_key( - VerifyingKey.from_der(public_key_der) - ) - - def load_received_public_key_pem(self, public_key_pem): - """ - Load public key from PEM string. - - Compares the curve of the PEM-encoded key with the ECDH set curve, - uses the former if unset. - - Note, the only PEM format supported is the RFC5912 - Look at keys.py:VerifyingKey.from_pem() - - :param public_key_pem: string with PEM-encoded public ECDSA key - :type public_key_pem: string - - :raises InvalidCurveError: public_key curve not the same as self.curve - """ - return self.load_received_public_key( - VerifyingKey.from_pem(public_key_pem) - ) - - def generate_sharedsecret_bytes(self): - """ - Generate shared secret from local private key and remote public key. - - The objects needs to have both private key and received public key - before generation is allowed. - - :raises InvalidCurveError: public_key curve not the same as self.curve - :raises NoKeyError: public_key or private_key is not set - - :return: shared secret - :rtype: bytes - """ - return number_to_string( - self.generate_sharedsecret(), self.private_key.curve.curve.p() - ) - - def generate_sharedsecret(self): - """ - Generate shared secret from local private key and remote public key. - - The objects needs to have both private key and received public key - before generation is allowed. - - It's the same for local and remote party, - shared secret(local private key, remote public key) == - shared secret(local public key, remote private key) - - :raises InvalidCurveError: public_key curve not the same as self.curve - :raises NoKeyError: public_key or private_key is not set - - :return: shared secret - :rtype: int - """ - return self._get_shared_secret(self.public_key) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdsa.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdsa.py deleted file mode 100644 index f710965..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/ecdsa.py +++ /dev/null @@ -1,1094 +0,0 @@ -#! /usr/bin/env python - -""" -Low level implementation of Elliptic-Curve Digital Signatures. - -.. note :: - You're most likely looking for the :py:class:`~ecdsa.keys` module. - This is a low-level implementation of the ECDSA that operates on - integers, not byte strings. - -NOTE: This a low level implementation of ECDSA, for normal applications -you should be looking at the keys.py module. - -Classes and methods for elliptic-curve signatures: -private keys, public keys, signatures, -and definitions of prime-modulus curves. - -Example: - -.. code-block:: python - - # (In real-life applications, you would probably want to - # protect against defects in SystemRandom.) - from random import SystemRandom - randrange = SystemRandom().randrange - - # Generate a public/private key pair using the NIST Curve P-192: - - g = generator_192 - n = g.order() - secret = randrange( 1, n ) - pubkey = Public_key( g, g * secret ) - privkey = Private_key( pubkey, secret ) - - # Signing a hash value: - - hash = randrange( 1, n ) - signature = privkey.sign( hash, randrange( 1, n ) ) - - # Verifying a signature for a hash value: - - if pubkey.verifies( hash, signature ): - print("Demo verification succeeded.") - else: - print("*** Demo verification failed.") - - # Verification fails if the hash value is modified: - - if pubkey.verifies( hash-1, signature ): - print("**** Demo verification failed to reject tampered hash.") - else: - print("Demo verification correctly rejected tampered hash.") - -Revision history: - 2005.12.31 - Initial version. - - 2008.11.25 - Substantial revisions introducing new classes. - - 2009.05.16 - Warn against using random.randrange in real applications. - - 2009.05.17 - Use random.SystemRandom by default. - -Originally written in 2005 by Peter Pearson and placed in the public domain, -modified as part of the python-ecdsa package. -""" - -import warnings -from six import int2byte -from . import ellipticcurve -from . import numbertheory -from .util import bit_length -from ._compat import remove_whitespace - - -class RSZeroError(RuntimeError): - pass - - -class InvalidPointError(RuntimeError): - pass - - -class Signature(object): - """ - ECDSA signature. - - :ivar int r: the ``r`` element of the ECDSA signature - :ivar int s: the ``s`` element of the ECDSA signature - """ - - def __init__(self, r, s): - self.r = r - self.s = s - - def recover_public_keys(self, hash, generator): - """ - Returns two public keys for which the signature is valid - - :param int hash: signed hash - :param AbstractPoint generator: is the generator used in creation - of the signature - :rtype: tuple(Public_key, Public_key) - :return: a pair of public keys that can validate the signature - """ - curve = generator.curve() - n = generator.order() - r = self.r - s = self.s - e = hash - x = r - - # Compute the curve point with x as x-coordinate - alpha = ( - pow(x, 3, curve.p()) + (curve.a() * x) + curve.b() - ) % curve.p() - beta = numbertheory.square_root_mod_prime(alpha, curve.p()) - y = beta if beta % 2 == 0 else curve.p() - beta - - # Compute the public key - R1 = ellipticcurve.PointJacobi(curve, x, y, 1, n) - Q1 = numbertheory.inverse_mod(r, n) * (s * R1 + (-e % n) * generator) - Pk1 = Public_key(generator, Q1) - - # And the second solution - R2 = ellipticcurve.PointJacobi(curve, x, -y, 1, n) - Q2 = numbertheory.inverse_mod(r, n) * (s * R2 + (-e % n) * generator) - Pk2 = Public_key(generator, Q2) - - return [Pk1, Pk2] - - -class Public_key(object): - """Public key for ECDSA.""" - - def __init__(self, generator, point, verify=True): - """Low level ECDSA public key object. - - :param generator: the Point that generates the group (the base point) - :param point: the Point that defines the public key - :param bool verify: if True check if point is valid point on curve - - :raises InvalidPointError: if the point parameters are invalid or - point does not lay on the curve - """ - - self.curve = generator.curve() - self.generator = generator - self.point = point - n = generator.order() - p = self.curve.p() - if not (0 <= point.x() < p) or not (0 <= point.y() < p): - raise InvalidPointError( - "The public point has x or y out of range." - ) - if verify and not self.curve.contains_point(point.x(), point.y()): - raise InvalidPointError("Point does not lay on the curve") - if not n: - raise InvalidPointError("Generator point must have order.") - # for curve parameters with base point with cofactor 1, all points - # that are on the curve are scalar multiples of the base point, so - # verifying that is not necessary. See Section 3.2.2.1 of SEC 1 v2 - if ( - verify - and self.curve.cofactor() != 1 - and not n * point == ellipticcurve.INFINITY - ): - raise InvalidPointError("Generator point order is bad.") - - def __eq__(self, other): - """Return True if the keys are identical, False otherwise. - - Note: for comparison, only placement on the same curve and point - equality is considered, use of the same generator point is not - considered. - """ - if isinstance(other, Public_key): - return self.curve == other.curve and self.point == other.point - return NotImplemented - - def __ne__(self, other): - """Return False if the keys are identical, True otherwise.""" - return not self == other - - def verifies(self, hash, signature): - """Verify that signature is a valid signature of hash. - Return True if the signature is valid. - """ - - # From X9.62 J.3.1. - - G = self.generator - n = G.order() - r = signature.r - s = signature.s - if r < 1 or r > n - 1: - return False - if s < 1 or s > n - 1: - return False - c = numbertheory.inverse_mod(s, n) - u1 = (hash * c) % n - u2 = (r * c) % n - if hasattr(G, "mul_add"): - xy = G.mul_add(u1, self.point, u2) - else: - xy = u1 * G + u2 * self.point - v = xy.x() % n - return v == r - - -class Private_key(object): - """Private key for ECDSA.""" - - def __init__(self, public_key, secret_multiplier): - """public_key is of class Public_key; - secret_multiplier is a large integer. - """ - - self.public_key = public_key - self.secret_multiplier = secret_multiplier - - def __eq__(self, other): - """Return True if the points are identical, False otherwise.""" - if isinstance(other, Private_key): - return ( - self.public_key == other.public_key - and self.secret_multiplier == other.secret_multiplier - ) - return NotImplemented - - def __ne__(self, other): - """Return False if the points are identical, True otherwise.""" - return not self == other - - def sign(self, hash, random_k): - """Return a signature for the provided hash, using the provided - random nonce. It is absolutely vital that random_k be an unpredictable - number in the range [1, self.public_key.point.order()-1]. If - an attacker can guess random_k, he can compute our private key from a - single signature. Also, if an attacker knows a few high-order - bits (or a few low-order bits) of random_k, he can compute our private - key from many signatures. The generation of nonces with adequate - cryptographic strength is very difficult and far beyond the scope - of this comment. - - May raise RuntimeError, in which case retrying with a new - random value k is in order. - """ - - G = self.public_key.generator - n = G.order() - k = random_k % n - # Fix the bit-length of the random nonce, - # so that it doesn't leak via timing. - # This does not change that ks = k mod n - ks = k + n - kt = ks + n - if bit_length(ks) == bit_length(n): - p1 = kt * G - else: - p1 = ks * G - r = p1.x() % n - if r == 0: - raise RSZeroError("amazingly unlucky random number r") - s = ( - numbertheory.inverse_mod(k, n) - * (hash + (self.secret_multiplier * r) % n) - ) % n - if s == 0: - raise RSZeroError("amazingly unlucky random number s") - return Signature(r, s) - - -def int_to_string(x): # pragma: no cover - """Convert integer x into a string of bytes, as per X9.62.""" - # deprecated in 0.19 - warnings.warn( - "Function is unused in library code. If you use this code, " - "change to util.number_to_string.", - DeprecationWarning, - ) - assert x >= 0 - if x == 0: - return b"\0" - result = [] - while x: - ordinal = x & 0xFF - result.append(int2byte(ordinal)) - x >>= 8 - - result.reverse() - return b"".join(result) - - -def string_to_int(s): # pragma: no cover - """Convert a string of bytes into an integer, as per X9.62.""" - # deprecated in 0.19 - warnings.warn( - "Function is unused in library code. If you use this code, " - "change to util.string_to_number.", - DeprecationWarning, - ) - result = 0 - for c in s: - if not isinstance(c, int): - c = ord(c) - result = 256 * result + c - return result - - -def digest_integer(m): # pragma: no cover - """Convert an integer into a string of bytes, compute - its SHA-1 hash, and convert the result to an integer.""" - # deprecated in 0.19 - warnings.warn( - "Function is unused in library code. If you use this code, " - "change to a one-liner with util.number_to_string and " - "util.string_to_number methods.", - DeprecationWarning, - ) - # - # I don't expect this function to be used much. I wrote - # it in order to be able to duplicate the examples - # in ECDSAVS. - # - from hashlib import sha1 - - return string_to_int(sha1(int_to_string(m)).digest()) - - -def point_is_valid(generator, x, y): - """Is (x,y) a valid public key based on the specified generator?""" - - # These are the tests specified in X9.62. - - n = generator.order() - curve = generator.curve() - p = curve.p() - if not (0 <= x < p) or not (0 <= y < p): - return False - if not curve.contains_point(x, y): - return False - if ( - curve.cofactor() != 1 - and not n * ellipticcurve.PointJacobi(curve, x, y, 1) - == ellipticcurve.INFINITY - ): - return False - return True - - -# secp112r1 curve -_p = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD208B"), 16) -# s = 00F50B02 8E4D696E 67687561 51752904 72783FB1 -_a = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD2088"), 16) -_b = int(remove_whitespace("659E F8BA0439 16EEDE89 11702B22"), 16) -_Gx = int(remove_whitespace("09487239 995A5EE7 6B55F9C2 F098"), 16) -_Gy = int(remove_whitespace("A89C E5AF8724 C0A23E0E 0FF77500"), 16) -_r = int(remove_whitespace("DB7C 2ABF62E3 5E7628DF AC6561C5"), 16) -_h = 1 -curve_112r1 = ellipticcurve.CurveFp(_p, _a, _b, _h) -generator_112r1 = ellipticcurve.PointJacobi( - curve_112r1, _Gx, _Gy, 1, _r, generator=True -) - - -# secp112r2 curve -_p = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD208B"), 16) -# s = 022757A1 114D69E 67687561 51755316 C05E0BD4 -_a = int(remove_whitespace("6127 C24C05F3 8A0AAAF6 5C0EF02C"), 16) -_b = int(remove_whitespace("51DE F1815DB5 ED74FCC3 4C85D709"), 16) -_Gx = int(remove_whitespace("4BA30AB5 E892B4E1 649DD092 8643"), 16) -_Gy = int(remove_whitespace("ADCD 46F5882E 3747DEF3 6E956E97"), 16) -_r = int(remove_whitespace("36DF 0AAFD8B8 D7597CA1 0520D04B"), 16) -_h = 4 -curve_112r2 = ellipticcurve.CurveFp(_p, _a, _b, _h) -generator_112r2 = ellipticcurve.PointJacobi( - curve_112r2, _Gx, _Gy, 1, _r, generator=True -) - - -# secp128r1 curve -_p = int(remove_whitespace("FFFFFFFD FFFFFFFF FFFFFFFF FFFFFFFF"), 16) -# S = 000E0D4D 69E6768 75615175 0CC03A44 73D03679 -# a and b are mod p, so a is equal to p-3, or simply -3 -# _a = -3 -_b = int(remove_whitespace("E87579C1 1079F43D D824993C 2CEE5ED3"), 16) -_Gx = int(remove_whitespace("161FF752 8B899B2D 0C28607C A52C5B86"), 16) -_Gy = int(remove_whitespace("CF5AC839 5BAFEB13 C02DA292 DDED7A83"), 16) -_r = int(remove_whitespace("FFFFFFFE 00000000 75A30D1B 9038A115"), 16) -_h = 1 -curve_128r1 = ellipticcurve.CurveFp(_p, -3, _b, _h) -generator_128r1 = ellipticcurve.PointJacobi( - curve_128r1, _Gx, _Gy, 1, _r, generator=True -) - - -# secp160r1 -_p = int(remove_whitespace("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 7FFFFFFF"), 16) -# S = 1053CDE4 2C14D696 E6768756 1517533B F3F83345 -# a and b are mod p, so a is equal to p-3, or simply -3 -# _a = -3 -_b = int(remove_whitespace("1C97BEFC 54BD7A8B 65ACF89F 81D4D4AD C565FA45"), 16) -_Gx = int( - remove_whitespace("4A96B568 8EF57328 46646989 68C38BB9 13CBFC82"), - 16, -) -_Gy = int( - remove_whitespace("23A62855 3168947D 59DCC912 04235137 7AC5FB32"), - 16, -) -_r = int( - remove_whitespace("01 00000000 00000000 0001F4C8 F927AED3 CA752257"), - 16, -) -_h = 1 -curve_160r1 = ellipticcurve.CurveFp(_p, -3, _b, _h) -generator_160r1 = ellipticcurve.PointJacobi( - curve_160r1, _Gx, _Gy, 1, _r, generator=True -) - - -# NIST Curve P-192: -_p = 6277101735386680763835789423207666416083908700390324961279 -_r = 6277101735386680763835789423176059013767194773182842284081 -# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L -# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L -_b = int( - remove_whitespace( - """ - 64210519 E59C80E7 0FA7E9AB 72243049 FEB8DEEC C146B9B1""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - 188DA80E B03090F6 7CBF20EB 43A18800 F4FF0AFD 82FF1012""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 07192B95 FFC8DA78 631011ED 6B24CDD5 73F977A1 1E794811""" - ), - 16, -) - -curve_192 = ellipticcurve.CurveFp(_p, -3, _b, 1) -generator_192 = ellipticcurve.PointJacobi( - curve_192, _Gx, _Gy, 1, _r, generator=True -) - - -# NIST Curve P-224: -_p = int( - remove_whitespace( - """ - 2695994666715063979466701508701963067355791626002630814351 - 0066298881""" - ) -) -_r = int( - remove_whitespace( - """ - 2695994666715063979466701508701962594045780771442439172168 - 2722368061""" - ) -) -# s = 0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5L -# c = 0x5b056c7e11dd68f40469ee7f3c7a7d74f7d121116506d031218291fbL -_b = int( - remove_whitespace( - """ - B4050A85 0C04B3AB F5413256 5044B0B7 D7BFD8BA 270B3943 - 2355FFB4""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - B70E0CBD 6BB4BF7F 321390B9 4A03C1D3 56C21122 343280D6 - 115C1D21""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - BD376388 B5F723FB 4C22DFE6 CD4375A0 5A074764 44D58199 - 85007E34""" - ), - 16, -) - -curve_224 = ellipticcurve.CurveFp(_p, -3, _b, 1) -generator_224 = ellipticcurve.PointJacobi( - curve_224, _Gx, _Gy, 1, _r, generator=True -) - -# NIST Curve P-256: -_p = int( - remove_whitespace( - """ - 1157920892103562487626974469494075735300861434152903141955 - 33631308867097853951""" - ) -) -_r = int( - remove_whitespace( - """ - 115792089210356248762697446949407573529996955224135760342 - 422259061068512044369""" - ) -) -# s = 0xc49d360886e704936a6678e1139d26b7819f7e90L -# c = 0x7efba1662985be9403cb055c75d4f7e0ce8d84a9c5114abcaf3177680104fa0dL -_b = int( - remove_whitespace( - """ - 5AC635D8 AA3A93E7 B3EBBD55 769886BC 651D06B0 CC53B0F6 - 3BCE3C3E 27D2604B""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - 6B17D1F2 E12C4247 F8BCE6E5 63A440F2 77037D81 2DEB33A0 - F4A13945 D898C296""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 4FE342E2 FE1A7F9B 8EE7EB4A 7C0F9E16 2BCE3357 6B315ECE - CBB64068 37BF51F5""" - ), - 16, -) - -curve_256 = ellipticcurve.CurveFp(_p, -3, _b, 1) -generator_256 = ellipticcurve.PointJacobi( - curve_256, _Gx, _Gy, 1, _r, generator=True -) - -# NIST Curve P-384: -_p = int( - remove_whitespace( - """ - 3940200619639447921227904010014361380507973927046544666794 - 8293404245721771496870329047266088258938001861606973112319""" - ) -) -_r = int( - remove_whitespace( - """ - 3940200619639447921227904010014361380507973927046544666794 - 6905279627659399113263569398956308152294913554433653942643""" - ) -) -# s = 0xa335926aa319a27a1d00896a6773a4827acdac73L -# c = int(remove_whitespace( -# """ -# 79d1e655 f868f02f ff48dcde e14151dd b80643c1 406d0ca1 -# 0dfe6fc5 2009540a 495e8042 ea5f744f 6e184667 cc722483""" -# ), 16) -_b = int( - remove_whitespace( - """ - B3312FA7 E23EE7E4 988E056B E3F82D19 181D9C6E FE814112 - 0314088F 5013875A C656398D 8A2ED19D 2A85C8ED D3EC2AEF""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - AA87CA22 BE8B0537 8EB1C71E F320AD74 6E1D3B62 8BA79B98 - 59F741E0 82542A38 5502F25D BF55296C 3A545E38 72760AB7""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 3617DE4A 96262C6F 5D9E98BF 9292DC29 F8F41DBD 289A147C - E9DA3113 B5F0B8C0 0A60B1CE 1D7E819D 7A431D7C 90EA0E5F""" - ), - 16, -) - -curve_384 = ellipticcurve.CurveFp(_p, -3, _b, 1) -generator_384 = ellipticcurve.PointJacobi( - curve_384, _Gx, _Gy, 1, _r, generator=True -) - -# NIST Curve P-521: -_p = int( - "686479766013060971498190079908139321726943530014330540939" - "446345918554318339765605212255964066145455497729631139148" - "0858037121987999716643812574028291115057151" -) -_r = int( - "686479766013060971498190079908139321726943530014330540939" - "446345918554318339765539424505774633321719753296399637136" - "3321113864768612440380340372808892707005449" -) -# s = 0xd09e8800291cb85396cc6717393284aaa0da64baL -# c = int(remove_whitespace( -# """ -# 0b4 8bfa5f42 0a349495 39d2bdfc 264eeeeb 077688e4 -# 4fbf0ad8 f6d0edb3 7bd6b533 28100051 8e19f1b9 ffbe0fe9 -# ed8a3c22 00b8f875 e523868c 70c1e5bf 55bad637""" -# ), 16) -_b = int( - remove_whitespace( - """ - 051 953EB961 8E1C9A1F 929A21A0 B68540EE A2DA725B - 99B315F3 B8B48991 8EF109E1 56193951 EC7E937B 1652C0BD - 3BB1BF07 3573DF88 3D2C34F1 EF451FD4 6B503F00""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - C6 858E06B7 0404E9CD 9E3ECB66 2395B442 9C648139 - 053FB521 F828AF60 6B4D3DBA A14B5E77 EFE75928 FE1DC127 - A2FFA8DE 3348B3C1 856A429B F97E7E31 C2E5BD66""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 118 39296A78 9A3BC004 5C8A5FB4 2C7D1BD9 98F54449 - 579B4468 17AFBD17 273E662C 97EE7299 5EF42640 C550B901 - 3FAD0761 353C7086 A272C240 88BE9476 9FD16650""" - ), - 16, -) - -curve_521 = ellipticcurve.CurveFp(_p, -3, _b, 1) -generator_521 = ellipticcurve.PointJacobi( - curve_521, _Gx, _Gy, 1, _r, generator=True -) - -# Certicom secp256-k1 -_a = 0x0000000000000000000000000000000000000000000000000000000000000000 -_b = 0x0000000000000000000000000000000000000000000000000000000000000007 -_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 -_Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 -_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - -curve_secp256k1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_secp256k1 = ellipticcurve.PointJacobi( - curve_secp256k1, _Gx, _Gy, 1, _r, generator=True -) - -# Brainpool P-160-r1 -_a = 0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300 -_b = 0x1E589A8595423412134FAA2DBDEC95C8D8675E58 -_p = 0xE95E4A5F737059DC60DFC7AD95B3D8139515620F -_Gx = 0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3 -_Gy = 0x1667CB477A1A8EC338F94741669C976316DA6321 -_q = 0xE95E4A5F737059DC60DF5991D45029409E60FC09 - -curve_brainpoolp160r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp160r1 = ellipticcurve.PointJacobi( - curve_brainpoolp160r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-160-t1 -_a = 0xE95E4A5F737059DC60DFC7AD95B3D8139515620C -_b = 0x7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380 -# _z = 0x24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B -_Gx = 0xB199B13B9B34EFC1397E64BAEB05ACC265FF2378 -_Gy = 0xADD6718B7C7C1961F0991B842443772152C9E0AD -_q = 0xE95E4A5F737059DC60DF5991D45029409E60FC09 -curve_brainpoolp160t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp160t1 = ellipticcurve.PointJacobi( - curve_brainpoolp160t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-192-r1 -_a = 0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF -_b = 0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9 -_p = 0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297 -_Gx = 0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6 -_Gy = 0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F -_q = 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1 - -curve_brainpoolp192r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp192r1 = ellipticcurve.PointJacobi( - curve_brainpoolp192r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-192-t1 -_a = 0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294 -_b = 0x13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79 -# _z = 0x1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB -_Gx = 0x3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129 -_Gy = 0x097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9 -_q = 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1 - -curve_brainpoolp192t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp192t1 = ellipticcurve.PointJacobi( - curve_brainpoolp192t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-224-r1 -_a = 0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43 -_b = 0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B -_p = 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF -_Gx = 0x0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D -_Gy = 0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD -_q = 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F - -curve_brainpoolp224r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp224r1 = ellipticcurve.PointJacobi( - curve_brainpoolp224r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-224-t1 -_a = 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC -_b = 0x4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D -# _z = 0x2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F -_Gx = 0x6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580 -_Gy = 0x0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C -_q = 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F - -curve_brainpoolp224t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp224t1 = ellipticcurve.PointJacobi( - curve_brainpoolp224t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-256-r1 -_a = 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9 -_b = 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6 -_p = 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377 -_Gx = 0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262 -_Gy = 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997 -_q = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 - -curve_brainpoolp256r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp256r1 = ellipticcurve.PointJacobi( - curve_brainpoolp256r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-256-t1 -_a = 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374 -_b = 0x662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04 -# _z = 0x3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0 -_Gx = 0xA3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4 -_Gy = 0x2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE -_q = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 - -curve_brainpoolp256t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp256t1 = ellipticcurve.PointJacobi( - curve_brainpoolp256t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-320-r1 -_a = int( - remove_whitespace( - """ - 3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9 - F492F375A97D860EB4""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - 520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539 - 816F5EB4AC8FB1F1A6""" - ), - 16, -) -_p = int( - remove_whitespace( - """ - D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC - 28FCD412B1F1B32E27""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - 43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599 - C710AF8D0D39E20611""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6A - C7D35245D1692E8EE1""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658 - E98691555B44C59311""" - ), - 16, -) - -curve_brainpoolp320r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp320r1 = ellipticcurve.PointJacobi( - curve_brainpoolp320r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-320-t1 -_a = int( - remove_whitespace( - """ - D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC - 28FCD412B1F1B32E24""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547 - CEB5B4FEF422340353""" - ), - 16, -) -# _z = int( -# remove_whitespace( -# """ -# 15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18F -# EFC3E5AB7496F3C7B1""" -# ), -# 16, -# ) -_Gx = int( - remove_whitespace( - """ - 925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136F - FF3357F624A21BED52""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE7 - 1B1B9BC0455FB0D2C3""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658 - E98691555B44C59311""" - ), - 16, -) - -curve_brainpoolp320t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp320t1 = ellipticcurve.PointJacobi( - curve_brainpoolp320t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-384-r1 -_a = int( - remove_whitespace( - """ - 7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F9 - 0F8AA5814A503AD4EB04A8C7DD22CE2826""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - 04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62 - D57CB4390295DBC9943AB78696FA504C11""" - ), - 16, -) -_p = int( - remove_whitespace( - """ - 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB711 - 23ACD3A729901D1A71874700133107EC53""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - 1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10 - E8E826E03436D646AAEF87B2E247D4AF1E""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF991292 - 80E4646217791811142820341263C5315""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425 - A7CF3AB6AF6B7FC3103B883202E9046565""" - ), - 16, -) - -curve_brainpoolp384r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp384r1 = ellipticcurve.PointJacobi( - curve_brainpoolp384r1, _Gx, _Gy, 1, _q, generator=True -) - -_a = int( - remove_whitespace( - """ - 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB711 - 23ACD3A729901D1A71874700133107EC50""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - 7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE - 1D2074AA263B88805CED70355A33B471EE""" - ), - 16, -) -# _z = int( -# remove_whitespace( -# """ -# 41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE -# 97D2D63DBC87BCCDDCCC5DA39E8589291C""" -# ), -# 16, -# ) -_Gx = int( - remove_whitespace( - """ - 18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AAB - FFC4FF191B946A5F54D8D0AA2F418808CC""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CC - FE469408584DC2B2912675BF5B9E582928""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425 - A7CF3AB6AF6B7FC3103B883202E9046565""" - ), - 16, -) - -curve_brainpoolp384t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp384t1 = ellipticcurve.PointJacobi( - curve_brainpoolp384t1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-512-r1 -_a = int( - remove_whitespace( - """ - 7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863 - BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - 3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117 - A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723""" - ), - 16, -) -_p = int( - remove_whitespace( - """ - AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 - 717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3""" - ), - 16, -) -_Gx = int( - remove_whitespace( - """ - 81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D009 - 8EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F81 - 11B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 - 70553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069""" - ), - 16, -) - -curve_brainpoolp512r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp512r1 = ellipticcurve.PointJacobi( - curve_brainpoolp512r1, _Gx, _Gy, 1, _q, generator=True -) - -# Brainpool P-512-t1 -_a = int( - remove_whitespace( - """ - AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 - 717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0""" - ), - 16, -) -_b = int( - remove_whitespace( - """ - 7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36 - A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E""" - ), - 16, -) -# _z = int( -# remove_whitespace( -# """ -# 12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B -# 64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB""" -# ), -# 16, -# ) -_Gx = int( - remove_whitespace( - """ - 640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C031 - 3D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA""" - ), - 16, -) -_Gy = int( - remove_whitespace( - """ - 5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CE - E9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332""" - ), - 16, -) -_q = int( - remove_whitespace( - """ - AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 - 70553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069""" - ), - 16, -) - -curve_brainpoolp512t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) -generator_brainpoolp512t1 = ellipticcurve.PointJacobi( - curve_brainpoolp512t1, _Gx, _Gy, 1, _q, generator=True -) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/eddsa.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/eddsa.py deleted file mode 100644 index 9769cfd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/eddsa.py +++ /dev/null @@ -1,252 +0,0 @@ -"""Implementation of Edwards Digital Signature Algorithm.""" - -import hashlib -from ._sha3 import shake_256 -from . import ellipticcurve -from ._compat import ( - remove_whitespace, - bit_length, - bytes_to_int, - int_to_bytes, - compat26_str, -) - -# edwards25519, defined in RFC7748 -_p = 2**255 - 19 -_a = -1 -_d = int( - remove_whitespace( - "370957059346694393431380835087545651895421138798432190163887855330" - "85940283555" - ) -) -_h = 8 - -_Gx = int( - remove_whitespace( - "151122213495354007725011514095885315114540126930418572060461132" - "83949847762202" - ) -) -_Gy = int( - remove_whitespace( - "463168356949264781694283940034751631413079938662562256157830336" - "03165251855960" - ) -) -_r = 2**252 + 0x14DEF9DEA2F79CD65812631A5CF5D3ED - - -def _sha512(data): - return hashlib.new("sha512", compat26_str(data)).digest() - - -curve_ed25519 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _sha512) -generator_ed25519 = ellipticcurve.PointEdwards( - curve_ed25519, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True -) - - -# edwards448, defined in RFC7748 -_p = 2**448 - 2**224 - 1 -_a = 1 -_d = -39081 % _p -_h = 4 - -_Gx = int( - remove_whitespace( - "224580040295924300187604334099896036246789641632564134246125461" - "686950415467406032909029192869357953282578032075146446173674602635" - "247710" - ) -) -_Gy = int( - remove_whitespace( - "298819210078481492676017930443930673437544040154080242095928241" - "372331506189835876003536878655418784733982303233503462500531545062" - "832660" - ) -) -_r = 2**446 - 0x8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D - - -def _shake256(data): - return shake_256(data, 114) - - -curve_ed448 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _shake256) -generator_ed448 = ellipticcurve.PointEdwards( - curve_ed448, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True -) - - -class PublicKey(object): - """Public key for the Edwards Digital Signature Algorithm.""" - - def __init__(self, generator, public_key, public_point=None): - self.generator = generator - self.curve = generator.curve() - self.__encoded = public_key - # plus one for the sign bit and round up - self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8 - if len(public_key) != self.baselen: - raise ValueError( - "Incorrect size of the public key, expected: {0} bytes".format( - self.baselen - ) - ) - if public_point: - self.__point = public_point - else: - self.__point = ellipticcurve.PointEdwards.from_bytes( - self.curve, public_key - ) - - def __eq__(self, other): - if isinstance(other, PublicKey): - return ( - self.curve == other.curve and self.__encoded == other.__encoded - ) - return NotImplemented - - def __ne__(self, other): - return not self == other - - @property - def point(self): - return self.__point - - @point.setter - def point(self, other): - if self.__point != other: - raise ValueError("Can't change the coordinates of the point") - self.__point = other - - def public_point(self): - return self.__point - - def public_key(self): - return self.__encoded - - def verify(self, data, signature): - """Verify a Pure EdDSA signature over data.""" - data = compat26_str(data) - if len(signature) != 2 * self.baselen: - raise ValueError( - "Invalid signature length, expected: {0} bytes".format( - 2 * self.baselen - ) - ) - R = ellipticcurve.PointEdwards.from_bytes( - self.curve, signature[: self.baselen] - ) - S = bytes_to_int(signature[self.baselen :], "little") - if S >= self.generator.order(): - raise ValueError("Invalid signature") - - dom = bytearray() - if self.curve == curve_ed448: - dom = bytearray(b"SigEd448" + b"\x00\x00") - - k = bytes_to_int( - self.curve.hash_func(dom + R.to_bytes() + self.__encoded + data), - "little", - ) - - if self.generator * S != self.__point * k + R: - raise ValueError("Invalid signature") - - return True - - -class PrivateKey(object): - """Private key for the Edwards Digital Signature Algorithm.""" - - def __init__(self, generator, private_key): - self.generator = generator - self.curve = generator.curve() - # plus one for the sign bit and round up - self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8 - if len(private_key) != self.baselen: - raise ValueError( - "Incorrect size of private key, expected: {0} bytes".format( - self.baselen - ) - ) - self.__private_key = bytes(private_key) - self.__h = bytearray(self.curve.hash_func(private_key)) - self.__public_key = None - - a = self.__h[: self.baselen] - a = self._key_prune(a) - scalar = bytes_to_int(a, "little") - self.__s = scalar - - @property - def private_key(self): - return self.__private_key - - def __eq__(self, other): - if isinstance(other, PrivateKey): - return ( - self.curve == other.curve - and self.__private_key == other.__private_key - ) - return NotImplemented - - def __ne__(self, other): - return not self == other - - def _key_prune(self, key): - # make sure the key is not in a small subgroup - h = self.curve.cofactor() - if h == 4: - h_log = 2 - elif h == 8: - h_log = 3 - else: - raise ValueError("Only cofactor 4 and 8 curves supported") - key[0] &= ~((1 << h_log) - 1) - - # ensure the highest bit is set but no higher - l = bit_length(self.curve.p()) - if l % 8 == 0: - key[-1] = 0 - key[-2] |= 0x80 - else: - key[-1] = key[-1] & (1 << (l % 8)) - 1 | 1 << (l % 8) - 1 - return key - - def public_key(self): - """Generate the public key based on the included private key""" - if self.__public_key: - return self.__public_key - - public_point = self.generator * self.__s - - self.__public_key = PublicKey( - self.generator, public_point.to_bytes(), public_point - ) - - return self.__public_key - - def sign(self, data): - """Perform a Pure EdDSA signature over data.""" - data = compat26_str(data) - A = self.public_key().public_key() - - prefix = self.__h[self.baselen :] - - dom = bytearray() - if self.curve == curve_ed448: - dom = bytearray(b"SigEd448" + b"\x00\x00") - - r = bytes_to_int(self.curve.hash_func(dom + prefix + data), "little") - R = (self.generator * r).to_bytes() - - k = bytes_to_int(self.curve.hash_func(dom + R + A + data), "little") - k %= self.generator.order() - - S = (r + k * self.__s) % self.generator.order() - - return R + int_to_bytes(S, self.baselen, "little") diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/ellipticcurve.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/ellipticcurve.py deleted file mode 100644 index a982c1e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/ellipticcurve.py +++ /dev/null @@ -1,1609 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- -# -# Implementation of elliptic curves, for cryptographic applications. -# -# This module doesn't provide any way to choose a random elliptic -# curve, nor to verify that an elliptic curve was chosen randomly, -# because one can simply use NIST's standard curves. -# -# Notes from X9.62-1998 (draft): -# Nomenclature: -# - Q is a public key. -# The "Elliptic Curve Domain Parameters" include: -# - q is the "field size", which in our case equals p. -# - p is a big prime. -# - G is a point of prime order (5.1.1.1). -# - n is the order of G (5.1.1.1). -# Public-key validation (5.2.2): -# - Verify that Q is not the point at infinity. -# - Verify that X_Q and Y_Q are in [0,p-1]. -# - Verify that Q is on the curve. -# - Verify that nQ is the point at infinity. -# Signature generation (5.3): -# - Pick random k from [1,n-1]. -# Signature checking (5.4.2): -# - Verify that r and s are in [1,n-1]. -# -# Revision history: -# 2005.12.31 - Initial version. -# 2008.11.25 - Change CurveFp.is_on to contains_point. -# -# Written in 2005 by Peter Pearson and placed in the public domain. -# Modified extensively as part of python-ecdsa. - -from __future__ import division - -try: - from gmpy2 import mpz - - GMPY = True -except ImportError: # pragma: no branch - try: - from gmpy import mpz - - GMPY = True - except ImportError: - GMPY = False - - -from six import python_2_unicode_compatible -from . import numbertheory -from ._compat import normalise_bytes, int_to_bytes, bit_length, bytes_to_int -from .errors import MalformedPointError -from .util import orderlen, string_to_number, number_to_string - - -@python_2_unicode_compatible -class CurveFp(object): - """ - :term:`Short Weierstrass Elliptic Curve ` over a - prime field. - """ - - if GMPY: # pragma: no branch - - def __init__(self, p, a, b, h=None): - """ - The curve of points satisfying y^2 = x^3 + a*x + b (mod p). - - h is an integer that is the cofactor of the elliptic curve domain - parameters; it is the number of points satisfying the elliptic - curve equation divided by the order of the base point. It is used - for selection of efficient algorithm for public point verification. - """ - self.__p = mpz(p) - self.__a = mpz(a) - self.__b = mpz(b) - # h is not used in calculations and it can be None, so don't use - # gmpy with it - self.__h = h - - else: # pragma: no branch - - def __init__(self, p, a, b, h=None): - """ - The curve of points satisfying y^2 = x^3 + a*x + b (mod p). - - h is an integer that is the cofactor of the elliptic curve domain - parameters; it is the number of points satisfying the elliptic - curve equation divided by the order of the base point. It is used - for selection of efficient algorithm for public point verification. - """ - self.__p = p - self.__a = a - self.__b = b - self.__h = h - - def __eq__(self, other): - """Return True if other is an identical curve, False otherwise. - - Note: the value of the cofactor of the curve is not taken into account - when comparing curves, as it's derived from the base point and - intrinsic curve characteristic (but it's complex to compute), - only the prime and curve parameters are considered. - """ - if isinstance(other, CurveFp): - p = self.__p - return ( - self.__p == other.__p - and self.__a % p == other.__a % p - and self.__b % p == other.__b % p - ) - return NotImplemented - - def __ne__(self, other): - """Return False if other is an identical curve, True otherwise.""" - return not self == other - - def __hash__(self): - return hash((self.__p, self.__a, self.__b)) - - def p(self): - return self.__p - - def a(self): - return self.__a - - def b(self): - return self.__b - - def cofactor(self): - return self.__h - - def contains_point(self, x, y): - """Is the point (x,y) on this curve?""" - return (y * y - ((x * x + self.__a) * x + self.__b)) % self.__p == 0 - - def __str__(self): - if self.__h is not None: - return "CurveFp(p={0}, a={1}, b={2}, h={3})".format( - self.__p, - self.__a, - self.__b, - self.__h, - ) - return "CurveFp(p={0}, a={1}, b={2})".format( - self.__p, - self.__a, - self.__b, - ) - - -class CurveEdTw(object): - """Parameters for a Twisted Edwards Elliptic Curve""" - - if GMPY: # pragma: no branch - - def __init__(self, p, a, d, h=None, hash_func=None): - """ - The curve of points satisfying a*x^2 + y^2 = 1 + d*x^2*y^2 (mod p). - - h is the cofactor of the curve. - hash_func is the hash function associated with the curve - (like SHA-512 for Ed25519) - """ - self.__p = mpz(p) - self.__a = mpz(a) - self.__d = mpz(d) - self.__h = h - self.__hash_func = hash_func - - else: - - def __init__(self, p, a, d, h=None, hash_func=None): - """ - The curve of points satisfying a*x^2 + y^2 = 1 + d*x^2*y^2 (mod p). - - h is the cofactor of the curve. - hash_func is the hash function associated with the curve - (like SHA-512 for Ed25519) - """ - self.__p = p - self.__a = a - self.__d = d - self.__h = h - self.__hash_func = hash_func - - def __eq__(self, other): - """Returns True if other is an identical curve.""" - if isinstance(other, CurveEdTw): - p = self.__p - return ( - self.__p == other.__p - and self.__a % p == other.__a % p - and self.__d % p == other.__d % p - ) - return NotImplemented - - def __ne__(self, other): - """Return False if the other is an identical curve, True otherwise.""" - return not self == other - - def __hash__(self): - return hash((self.__p, self.__a, self.__d)) - - def contains_point(self, x, y): - """Is the point (x, y) on this curve?""" - return ( - self.__a * x * x + y * y - 1 - self.__d * x * x * y * y - ) % self.__p == 0 - - def p(self): - return self.__p - - def a(self): - return self.__a - - def d(self): - return self.__d - - def hash_func(self, data): - return self.__hash_func(data) - - def cofactor(self): - return self.__h - - def __str__(self): - if self.__h is not None: - return "CurveEdTw(p={0}, a={1}, d={2}, h={3})".format( - self.__p, - self.__a, - self.__d, - self.__h, - ) - return "CurveEdTw(p={0}, a={1}, d={2})".format( - self.__p, - self.__a, - self.__d, - ) - - -class AbstractPoint(object): - """Class for common methods of elliptic curve points.""" - - @staticmethod - def _from_raw_encoding(data, raw_encoding_length): - """ - Decode public point from :term:`raw encoding`. - - :term:`raw encoding` is the same as the :term:`uncompressed` encoding, - but without the 0x04 byte at the beginning. - """ - # real assert, from_bytes() should not call us with different length - assert len(data) == raw_encoding_length - xs = data[: raw_encoding_length // 2] - ys = data[raw_encoding_length // 2 :] - # real assert, raw_encoding_length is calculated by multiplying an - # integer by two so it will always be even - assert len(xs) == raw_encoding_length // 2 - assert len(ys) == raw_encoding_length // 2 - coord_x = string_to_number(xs) - coord_y = string_to_number(ys) - - return coord_x, coord_y - - @staticmethod - def _from_compressed(data, curve): - """Decode public point from compressed encoding.""" - if data[:1] not in (b"\x02", b"\x03"): - raise MalformedPointError("Malformed compressed point encoding") - - is_even = data[:1] == b"\x02" - x = string_to_number(data[1:]) - p = curve.p() - alpha = (pow(x, 3, p) + (curve.a() * x) + curve.b()) % p - try: - beta = numbertheory.square_root_mod_prime(alpha, p) - except numbertheory.Error as e: - raise MalformedPointError( - "Encoding does not correspond to a point on curve", e - ) - if is_even == bool(beta & 1): - y = p - beta - else: - y = beta - return x, y - - @classmethod - def _from_hybrid(cls, data, raw_encoding_length, validate_encoding): - """Decode public point from hybrid encoding.""" - # real assert, from_bytes() should not call us with different types - assert data[:1] in (b"\x06", b"\x07") - - # primarily use the uncompressed as it's easiest to handle - x, y = cls._from_raw_encoding(data[1:], raw_encoding_length) - - # but validate if it's self-consistent if we're asked to do that - if validate_encoding and ( - y & 1 - and data[:1] != b"\x07" - or (not y & 1) - and data[:1] != b"\x06" - ): - raise MalformedPointError("Inconsistent hybrid point encoding") - - return x, y - - @classmethod - def _from_edwards(cls, curve, data): - """Decode a point on an Edwards curve.""" - data = bytearray(data) - p = curve.p() - # add 1 for the sign bit and then round up - exp_len = (bit_length(p) + 1 + 7) // 8 - if len(data) != exp_len: - raise MalformedPointError("Point length doesn't match the curve.") - x_0 = (data[-1] & 0x80) >> 7 - - data[-1] &= 0x80 - 1 - - y = bytes_to_int(data, "little") - if GMPY: - y = mpz(y) - - x2 = ( - (y * y - 1) - * numbertheory.inverse_mod(curve.d() * y * y - curve.a(), p) - % p - ) - - try: - x = numbertheory.square_root_mod_prime(x2, p) - except numbertheory.Error as e: - raise MalformedPointError( - "Encoding does not correspond to a point on curve", e - ) - - if x % 2 != x_0: - x = -x % p - - return x, y - - @classmethod - def from_bytes( - cls, curve, data, validate_encoding=True, valid_encodings=None - ): - """ - Initialise the object from byte encoding of a point. - - The method does accept and automatically detect the type of point - encoding used. It supports the :term:`raw encoding`, - :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. - - Note: generally you will want to call the ``from_bytes()`` method of - either a child class, PointJacobi or Point. - - :param data: single point encoding of the public key - :type data: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lay - :type curve: ~ecdsa.ellipticcurve.CurveFp - :param validate_encoding: whether to verify that the encoding of the - point is self-consistent, defaults to True, has effect only - on ``hybrid`` encoding - :type validate_encoding: bool - :param valid_encodings: list of acceptable point encoding formats, - supported ones are: :term:`uncompressed`, :term:`compressed`, - :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` - name). All formats by default (specified with ``None``). - :type valid_encodings: :term:`set-like object` - - :raises `~ecdsa.errors.MalformedPointError`: if the public point does - not lay on the curve or the encoding is invalid - - :return: x and y coordinates of the encoded point - :rtype: tuple(int, int) - """ - if not valid_encodings: - valid_encodings = set( - ["uncompressed", "compressed", "hybrid", "raw"] - ) - if not all( - i in set(("uncompressed", "compressed", "hybrid", "raw")) - for i in valid_encodings - ): - raise ValueError( - "Only uncompressed, compressed, hybrid or raw encoding " - "supported." - ) - data = normalise_bytes(data) - - if isinstance(curve, CurveEdTw): - return cls._from_edwards(curve, data) - - key_len = len(data) - raw_encoding_length = 2 * orderlen(curve.p()) - if key_len == raw_encoding_length and "raw" in valid_encodings: - coord_x, coord_y = cls._from_raw_encoding( - data, raw_encoding_length - ) - elif key_len == raw_encoding_length + 1 and ( - "hybrid" in valid_encodings or "uncompressed" in valid_encodings - ): - if data[:1] in (b"\x06", b"\x07") and "hybrid" in valid_encodings: - coord_x, coord_y = cls._from_hybrid( - data, raw_encoding_length, validate_encoding - ) - elif data[:1] == b"\x04" and "uncompressed" in valid_encodings: - coord_x, coord_y = cls._from_raw_encoding( - data[1:], raw_encoding_length - ) - else: - raise MalformedPointError( - "Invalid X9.62 encoding of the public point" - ) - elif ( - key_len == raw_encoding_length // 2 + 1 - and "compressed" in valid_encodings - ): - coord_x, coord_y = cls._from_compressed(data, curve) - else: - raise MalformedPointError( - "Length of string does not match lengths of " - "any of the enabled ({0}) encodings of the " - "curve.".format(", ".join(valid_encodings)) - ) - return coord_x, coord_y - - def _raw_encode(self): - """Convert the point to the :term:`raw encoding`.""" - prime = self.curve().p() - x_str = number_to_string(self.x(), prime) - y_str = number_to_string(self.y(), prime) - return x_str + y_str - - def _compressed_encode(self): - """Encode the point into the compressed form.""" - prime = self.curve().p() - x_str = number_to_string(self.x(), prime) - if self.y() & 1: - return b"\x03" + x_str - return b"\x02" + x_str - - def _hybrid_encode(self): - """Encode the point into the hybrid form.""" - raw_enc = self._raw_encode() - if self.y() & 1: - return b"\x07" + raw_enc - return b"\x06" + raw_enc - - def _edwards_encode(self): - """Encode the point according to RFC8032 encoding.""" - self.scale() - x, y, p = self.x(), self.y(), self.curve().p() - - # add 1 for the sign bit and then round up - enc_len = (bit_length(p) + 1 + 7) // 8 - y_str = int_to_bytes(y, enc_len, "little") - if x % 2: - y_str[-1] |= 0x80 - return y_str - - def to_bytes(self, encoding="raw"): - """ - Convert the point to a byte string. - - The method by default uses the :term:`raw encoding` (specified - by `encoding="raw"`. It can also output points in :term:`uncompressed`, - :term:`compressed`, and :term:`hybrid` formats. - - For points on Edwards curves `encoding` is ignored and only the - encoding defined in RFC 8032 is supported. - - :return: :term:`raw encoding` of a public on the curve - :rtype: bytes - """ - assert encoding in ("raw", "uncompressed", "compressed", "hybrid") - curve = self.curve() - if isinstance(curve, CurveEdTw): - return self._edwards_encode() - elif encoding == "raw": - return self._raw_encode() - elif encoding == "uncompressed": - return b"\x04" + self._raw_encode() - elif encoding == "hybrid": - return self._hybrid_encode() - else: - return self._compressed_encode() - - @staticmethod - def _naf(mult): - """Calculate non-adjacent form of number.""" - ret = [] - while mult: - if mult % 2: - nd = mult % 4 - if nd >= 2: - nd -= 4 - ret.append(nd) - mult -= nd - else: - ret.append(0) - mult //= 2 - return ret - - -class PointJacobi(AbstractPoint): - """ - Point on a short Weierstrass elliptic curve. Uses Jacobi coordinates. - - In Jacobian coordinates, there are three parameters, X, Y and Z. - They correspond to affine parameters 'x' and 'y' like so: - - x = X / Z² - y = Y / Z³ - """ - - def __init__(self, curve, x, y, z, order=None, generator=False): - """ - Initialise a point that uses Jacobi representation internally. - - :param CurveFp curve: curve on which the point resides - :param int x: the X parameter of Jacobi representation (equal to x when - converting from affine coordinates - :param int y: the Y parameter of Jacobi representation (equal to y when - converting from affine coordinates - :param int z: the Z parameter of Jacobi representation (equal to 1 when - converting from affine coordinates - :param int order: the point order, must be non zero when using - generator=True - :param bool generator: the point provided is a curve generator, as - such, it will be commonly used with scalar multiplication. This will - cause to precompute multiplication table generation for it - """ - super(PointJacobi, self).__init__() - self.__curve = curve - if GMPY: # pragma: no branch - self.__coords = (mpz(x), mpz(y), mpz(z)) - self.__order = order and mpz(order) - else: # pragma: no branch - self.__coords = (x, y, z) - self.__order = order - self.__generator = generator - self.__precompute = [] - - @classmethod - def from_bytes( - cls, - curve, - data, - validate_encoding=True, - valid_encodings=None, - order=None, - generator=False, - ): - """ - Initialise the object from byte encoding of a point. - - The method does accept and automatically detect the type of point - encoding used. It supports the :term:`raw encoding`, - :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. - - :param data: single point encoding of the public key - :type data: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lay - :type curve: ~ecdsa.ellipticcurve.CurveFp - :param validate_encoding: whether to verify that the encoding of the - point is self-consistent, defaults to True, has effect only - on ``hybrid`` encoding - :type validate_encoding: bool - :param valid_encodings: list of acceptable point encoding formats, - supported ones are: :term:`uncompressed`, :term:`compressed`, - :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` - name). All formats by default (specified with ``None``). - :type valid_encodings: :term:`set-like object` - :param int order: the point order, must be non zero when using - generator=True - :param bool generator: the point provided is a curve generator, as - such, it will be commonly used with scalar multiplication. This - will cause to precompute multiplication table generation for it - - :raises `~ecdsa.errors.MalformedPointError`: if the public point does - not lay on the curve or the encoding is invalid - - :return: Point on curve - :rtype: PointJacobi - """ - coord_x, coord_y = super(PointJacobi, cls).from_bytes( - curve, data, validate_encoding, valid_encodings - ) - return PointJacobi(curve, coord_x, coord_y, 1, order, generator) - - def _maybe_precompute(self): - if not self.__generator or self.__precompute: - return - - # since this code will execute just once, and it's fully deterministic, - # depend on atomicity of the last assignment to switch from empty - # self.__precompute to filled one and just ignore the unlikely - # situation when two threads execute it at the same time (as it won't - # lead to inconsistent __precompute) - order = self.__order - assert order - precompute = [] - i = 1 - order *= 2 - coord_x, coord_y, coord_z = self.__coords - doubler = PointJacobi(self.__curve, coord_x, coord_y, coord_z, order) - order *= 2 - precompute.append((doubler.x(), doubler.y())) - - while i < order: - i *= 2 - doubler = doubler.double().scale() - precompute.append((doubler.x(), doubler.y())) - - self.__precompute = precompute - - def __getstate__(self): - # while this code can execute at the same time as _maybe_precompute() - # is updating the __precompute or scale() is updating the __coords, - # there is no requirement for consistency between __coords and - # __precompute - state = self.__dict__.copy() - return state - - def __setstate__(self, state): - self.__dict__.update(state) - - def __eq__(self, other): - """Compare for equality two points with each-other. - - Note: only points that lay on the same curve can be equal. - """ - x1, y1, z1 = self.__coords - if other is INFINITY: - return not z1 - if isinstance(other, Point): - x2, y2, z2 = other.x(), other.y(), 1 - elif isinstance(other, PointJacobi): - x2, y2, z2 = other.__coords - else: - return NotImplemented - if self.__curve != other.curve(): - return False - p = self.__curve.p() - - zz1 = z1 * z1 % p - zz2 = z2 * z2 % p - - # compare the fractions by bringing them to the same denominator - # depend on short-circuit to save 4 multiplications in case of - # inequality - return (x1 * zz2 - x2 * zz1) % p == 0 and ( - y1 * zz2 * z2 - y2 * zz1 * z1 - ) % p == 0 - - def __ne__(self, other): - """Compare for inequality two points with each-other.""" - return not self == other - - def order(self): - """Return the order of the point. - - None if it is undefined. - """ - return self.__order - - def curve(self): - """Return curve over which the point is defined.""" - return self.__curve - - def x(self): - """ - Return affine x coordinate. - - This method should be used only when the 'y' coordinate is not needed. - It's computationally more efficient to use `to_affine()` and then - call x() and y() on the returned instance. Or call `scale()` - and then x() and y() on the returned instance. - """ - x, _, z = self.__coords - if z == 1: - return x - p = self.__curve.p() - z = numbertheory.inverse_mod(z, p) - return x * z**2 % p - - def y(self): - """ - Return affine y coordinate. - - This method should be used only when the 'x' coordinate is not needed. - It's computationally more efficient to use `to_affine()` and then - call x() and y() on the returned instance. Or call `scale()` - and then x() and y() on the returned instance. - """ - _, y, z = self.__coords - if z == 1: - return y - p = self.__curve.p() - z = numbertheory.inverse_mod(z, p) - return y * z**3 % p - - def scale(self): - """ - Return point scaled so that z == 1. - - Modifies point in place, returns self. - """ - x, y, z = self.__coords - if z == 1: - return self - - # scaling is deterministic, so even if two threads execute the below - # code at the same time, they will set __coords to the same value - p = self.__curve.p() - z_inv = numbertheory.inverse_mod(z, p) - zz_inv = z_inv * z_inv % p - x = x * zz_inv % p - y = y * zz_inv * z_inv % p - self.__coords = (x, y, 1) - return self - - def to_affine(self): - """Return point in affine form.""" - _, _, z = self.__coords - p = self.__curve.p() - if not (z % p): - return INFINITY - self.scale() - x, y, z = self.__coords - assert z == 1 - return Point(self.__curve, x, y, self.__order) - - @staticmethod - def from_affine(point, generator=False): - """Create from an affine point. - - :param bool generator: set to True to make the point to precalculate - multiplication table - useful for public point when verifying many - signatures (around 100 or so) or for generator points of a curve. - """ - return PointJacobi( - point.curve(), point.x(), point.y(), 1, point.order(), generator - ) - - # please note that all the methods that use the equations from - # hyperelliptic - # are formatted in a way to maximise performance. - # Things that make code faster: multiplying instead of taking to the power - # (`xx = x * x; xxxx = xx * xx % p` is faster than `xxxx = x**4 % p` and - # `pow(x, 4, p)`), - # multiple assignments at the same time (`x1, x2 = self.x1, self.x2` is - # faster than `x1 = self.x1; x2 = self.x2`), - # similarly, sometimes the `% p` is skipped if it makes the calculation - # faster and the result of calculation is later reduced modulo `p` - - def _double_with_z_1(self, X1, Y1, p, a): - """Add a point to itself with z == 1.""" - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-mdbl-2007-bl - XX, YY = X1 * X1 % p, Y1 * Y1 % p - if not YY: - return 0, 0, 0 - YYYY = YY * YY % p - S = 2 * ((X1 + YY) ** 2 - XX - YYYY) % p - M = 3 * XX + a - T = (M * M - 2 * S) % p - # X3 = T - Y3 = (M * (S - T) - 8 * YYYY) % p - Z3 = 2 * Y1 % p - return T, Y3, Z3 - - def _double(self, X1, Y1, Z1, p, a): - """Add a point to itself, arbitrary z.""" - if Z1 == 1: - return self._double_with_z_1(X1, Y1, p, a) - if not Z1: - return 0, 0, 0 - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl - XX, YY = X1 * X1 % p, Y1 * Y1 % p - if not YY: - return 0, 0, 0 - YYYY = YY * YY % p - ZZ = Z1 * Z1 % p - S = 2 * ((X1 + YY) ** 2 - XX - YYYY) % p - M = (3 * XX + a * ZZ * ZZ) % p - T = (M * M - 2 * S) % p - # X3 = T - Y3 = (M * (S - T) - 8 * YYYY) % p - Z3 = ((Y1 + Z1) ** 2 - YY - ZZ) % p - - return T, Y3, Z3 - - def double(self): - """Add a point to itself.""" - X1, Y1, Z1 = self.__coords - - if not Z1: - return INFINITY - - p, a = self.__curve.p(), self.__curve.a() - - X3, Y3, Z3 = self._double(X1, Y1, Z1, p, a) - - if not Z3: - return INFINITY - return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - - def _add_with_z_1(self, X1, Y1, X2, Y2, p): - """add points when both Z1 and Z2 equal 1""" - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-mmadd-2007-bl - H = X2 - X1 - HH = H * H - I = 4 * HH % p - J = H * I - r = 2 * (Y2 - Y1) - if not H and not r: - return self._double_with_z_1(X1, Y1, p, self.__curve.a()) - V = X1 * I - X3 = (r**2 - J - 2 * V) % p - Y3 = (r * (V - X3) - 2 * Y1 * J) % p - Z3 = 2 * H % p - return X3, Y3, Z3 - - def _add_with_z_eq(self, X1, Y1, Z1, X2, Y2, p): - """add points when Z1 == Z2""" - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-zadd-2007-m - A = (X2 - X1) ** 2 % p - B = X1 * A % p - C = X2 * A - D = (Y2 - Y1) ** 2 % p - if not A and not D: - return self._double(X1, Y1, Z1, p, self.__curve.a()) - X3 = (D - B - C) % p - Y3 = ((Y2 - Y1) * (B - X3) - Y1 * (C - B)) % p - Z3 = Z1 * (X2 - X1) % p - return X3, Y3, Z3 - - def _add_with_z2_1(self, X1, Y1, Z1, X2, Y2, p): - """add points when Z2 == 1""" - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-madd-2007-bl - Z1Z1 = Z1 * Z1 % p - U2, S2 = X2 * Z1Z1 % p, Y2 * Z1 * Z1Z1 % p - H = (U2 - X1) % p - HH = H * H % p - I = 4 * HH % p - J = H * I - r = 2 * (S2 - Y1) % p - if not r and not H: - return self._double_with_z_1(X2, Y2, p, self.__curve.a()) - V = X1 * I - X3 = (r * r - J - 2 * V) % p - Y3 = (r * (V - X3) - 2 * Y1 * J) % p - Z3 = ((Z1 + H) ** 2 - Z1Z1 - HH) % p - return X3, Y3, Z3 - - def _add_with_z_ne(self, X1, Y1, Z1, X2, Y2, Z2, p): - """add points with arbitrary z""" - # after: - # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl - Z1Z1 = Z1 * Z1 % p - Z2Z2 = Z2 * Z2 % p - U1 = X1 * Z2Z2 % p - U2 = X2 * Z1Z1 % p - S1 = Y1 * Z2 * Z2Z2 % p - S2 = Y2 * Z1 * Z1Z1 % p - H = U2 - U1 - I = 4 * H * H % p - J = H * I % p - r = 2 * (S2 - S1) % p - if not H and not r: - return self._double(X1, Y1, Z1, p, self.__curve.a()) - V = U1 * I - X3 = (r * r - J - 2 * V) % p - Y3 = (r * (V - X3) - 2 * S1 * J) % p - Z3 = ((Z1 + Z2) ** 2 - Z1Z1 - Z2Z2) * H % p - - return X3, Y3, Z3 - - def __radd__(self, other): - """Add other to self.""" - return self + other - - def _add(self, X1, Y1, Z1, X2, Y2, Z2, p): - """add two points, select fastest method.""" - if not Z1: - return X2 % p, Y2 % p, Z2 % p - if not Z2: - return X1 % p, Y1 % p, Z1 % p - if Z1 == Z2: - if Z1 == 1: - return self._add_with_z_1(X1, Y1, X2, Y2, p) - return self._add_with_z_eq(X1, Y1, Z1, X2, Y2, p) - if Z1 == 1: - return self._add_with_z2_1(X2, Y2, Z2, X1, Y1, p) - if Z2 == 1: - return self._add_with_z2_1(X1, Y1, Z1, X2, Y2, p) - return self._add_with_z_ne(X1, Y1, Z1, X2, Y2, Z2, p) - - def __add__(self, other): - """Add two points on elliptic curve.""" - if self == INFINITY: - return other - if other == INFINITY: - return self - if isinstance(other, Point): - other = PointJacobi.from_affine(other) - if self.__curve != other.__curve: - raise ValueError("The other point is on different curve") - - p = self.__curve.p() - X1, Y1, Z1 = self.__coords - X2, Y2, Z2 = other.__coords - - X3, Y3, Z3 = self._add(X1, Y1, Z1, X2, Y2, Z2, p) - - if not Z3: - return INFINITY - return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - - def __rmul__(self, other): - """Multiply point by an integer.""" - return self * other - - def _mul_precompute(self, other): - """Multiply point by integer with precomputation table.""" - X3, Y3, Z3, p = 0, 0, 0, self.__curve.p() - _add = self._add - for X2, Y2 in self.__precompute: - if other % 2: - if other % 4 >= 2: - other = (other + 1) // 2 - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p) - else: - other = (other - 1) // 2 - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p) - else: - other //= 2 - - if not Z3: - return INFINITY - return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - - def __mul__(self, other): - """Multiply point by an integer.""" - if not self.__coords[1] or not other: - return INFINITY - if other == 1: - return self - if self.__order: - # order*2 as a protection for Minerva - other = other % (self.__order * 2) - self._maybe_precompute() - if self.__precompute: - return self._mul_precompute(other) - - self = self.scale() - X2, Y2, _ = self.__coords - X3, Y3, Z3 = 0, 0, 0 - p, a = self.__curve.p(), self.__curve.a() - _double = self._double - _add = self._add - # since adding points when at least one of them is scaled - # is quicker, reverse the NAF order - for i in reversed(self._naf(other)): - X3, Y3, Z3 = _double(X3, Y3, Z3, p, a) - if i < 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p) - elif i > 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p) - - if not Z3: - return INFINITY - - return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - - def mul_add(self, self_mul, other, other_mul): - """ - Do two multiplications at the same time, add results. - - calculates self*self_mul + other*other_mul - """ - if other == INFINITY or other_mul == 0: - return self * self_mul - if self_mul == 0: - return other * other_mul - if not isinstance(other, PointJacobi): - other = PointJacobi.from_affine(other) - # when the points have precomputed answers, then multiplying them alone - # is faster (as it uses NAF and no point doublings) - self._maybe_precompute() - other._maybe_precompute() - if self.__precompute and other.__precompute: - return self * self_mul + other * other_mul - - if self.__order: - self_mul = self_mul % self.__order - other_mul = other_mul % self.__order - - # (X3, Y3, Z3) is the accumulator - X3, Y3, Z3 = 0, 0, 0 - p, a = self.__curve.p(), self.__curve.a() - - # as we have 6 unique points to work with, we can't scale all of them, - # but do scale the ones that are used most often - self.scale() - X1, Y1, Z1 = self.__coords - other.scale() - X2, Y2, Z2 = other.__coords - - _double = self._double - _add = self._add - - # with NAF we have 3 options: no add, subtract, add - # so with 2 points, we have 9 combinations: - # 0, -A, +A, -B, -A-B, +A-B, +B, -A+B, +A+B - # so we need 4 combined points: - mAmB_X, mAmB_Y, mAmB_Z = _add(X1, -Y1, Z1, X2, -Y2, Z2, p) - pAmB_X, pAmB_Y, pAmB_Z = _add(X1, Y1, Z1, X2, -Y2, Z2, p) - mApB_X, mApB_Y, mApB_Z = pAmB_X, -pAmB_Y, pAmB_Z - pApB_X, pApB_Y, pApB_Z = mAmB_X, -mAmB_Y, mAmB_Z - # when the self and other sum to infinity, we need to add them - # one by one to get correct result but as that's very unlikely to - # happen in regular operation, we don't need to optimise this case - if not pApB_Z: - return self * self_mul + other * other_mul - - # gmp object creation has cumulatively higher overhead than the - # speedup we get from calculating the NAF using gmp so ensure use - # of int() - self_naf = list(reversed(self._naf(int(self_mul)))) - other_naf = list(reversed(self._naf(int(other_mul)))) - # ensure that the lists are the same length (zip() will truncate - # longer one otherwise) - if len(self_naf) < len(other_naf): - self_naf = [0] * (len(other_naf) - len(self_naf)) + self_naf - elif len(self_naf) > len(other_naf): - other_naf = [0] * (len(self_naf) - len(other_naf)) + other_naf - - for A, B in zip(self_naf, other_naf): - X3, Y3, Z3 = _double(X3, Y3, Z3, p, a) - - # conditions ordered from most to least likely - if A == 0: - if B == 0: - pass - elif B < 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, Z2, p) - else: - assert B > 0 - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, Z2, p) - elif A < 0: - if B == 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, X1, -Y1, Z1, p) - elif B < 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, mAmB_X, mAmB_Y, mAmB_Z, p) - else: - assert B > 0 - X3, Y3, Z3 = _add(X3, Y3, Z3, mApB_X, mApB_Y, mApB_Z, p) - else: - assert A > 0 - if B == 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, X1, Y1, Z1, p) - elif B < 0: - X3, Y3, Z3 = _add(X3, Y3, Z3, pAmB_X, pAmB_Y, pAmB_Z, p) - else: - assert B > 0 - X3, Y3, Z3 = _add(X3, Y3, Z3, pApB_X, pApB_Y, pApB_Z, p) - - if not Z3: - return INFINITY - - return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - - def __neg__(self): - """Return negated point.""" - x, y, z = self.__coords - return PointJacobi(self.__curve, x, -y, z, self.__order) - - -class Point(AbstractPoint): - """A point on a short Weierstrass elliptic curve. Altering x and y is - forbidden, but they can be read by the x() and y() methods.""" - - def __init__(self, curve, x, y, order=None): - """curve, x, y, order; order (optional) is the order of this point.""" - super(Point, self).__init__() - self.__curve = curve - if GMPY: - self.__x = x and mpz(x) - self.__y = y and mpz(y) - self.__order = order and mpz(order) - else: - self.__x = x - self.__y = y - self.__order = order - # self.curve is allowed to be None only for INFINITY: - if self.__curve: - assert self.__curve.contains_point(x, y) - # for curves with cofactor 1, all points that are on the curve are - # scalar multiples of the base point, so performing multiplication is - # not necessary to verify that. See Section 3.2.2.1 of SEC 1 v2 - if curve and curve.cofactor() != 1 and order: - assert self * order == INFINITY - - @classmethod - def from_bytes( - cls, - curve, - data, - validate_encoding=True, - valid_encodings=None, - order=None, - ): - """ - Initialise the object from byte encoding of a point. - - The method does accept and automatically detect the type of point - encoding used. It supports the :term:`raw encoding`, - :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. - - :param data: single point encoding of the public key - :type data: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lay - :type curve: ~ecdsa.ellipticcurve.CurveFp - :param validate_encoding: whether to verify that the encoding of the - point is self-consistent, defaults to True, has effect only - on ``hybrid`` encoding - :type validate_encoding: bool - :param valid_encodings: list of acceptable point encoding formats, - supported ones are: :term:`uncompressed`, :term:`compressed`, - :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` - name). All formats by default (specified with ``None``). - :type valid_encodings: :term:`set-like object` - :param int order: the point order, must be non zero when using - generator=True - - :raises `~ecdsa.errors.MalformedPointError`: if the public point does - not lay on the curve or the encoding is invalid - - :return: Point on curve - :rtype: Point - """ - coord_x, coord_y = super(Point, cls).from_bytes( - curve, data, validate_encoding, valid_encodings - ) - return Point(curve, coord_x, coord_y, order) - - def __eq__(self, other): - """Return True if the points are identical, False otherwise. - - Note: only points that lay on the same curve can be equal. - """ - if other is INFINITY: - return self.__x is None or self.__y is None - if isinstance(other, Point): - return ( - self.__curve == other.__curve - and self.__x == other.__x - and self.__y == other.__y - ) - return NotImplemented - - def __ne__(self, other): - """Returns False if points are identical, True otherwise.""" - return not self == other - - def __neg__(self): - return Point(self.__curve, self.__x, self.__curve.p() - self.__y) - - def __add__(self, other): - """Add one point to another point.""" - - # X9.62 B.3: - - if not isinstance(other, Point): - return NotImplemented - if other == INFINITY: - return self - if self == INFINITY: - return other - assert self.__curve == other.__curve - if self.__x == other.__x: - if (self.__y + other.__y) % self.__curve.p() == 0: - return INFINITY - else: - return self.double() - - p = self.__curve.p() - - l = ( - (other.__y - self.__y) - * numbertheory.inverse_mod(other.__x - self.__x, p) - ) % p - - x3 = (l * l - self.__x - other.__x) % p - y3 = (l * (self.__x - x3) - self.__y) % p - - return Point(self.__curve, x3, y3) - - def __mul__(self, other): - """Multiply a point by an integer.""" - - def leftmost_bit(x): - assert x > 0 - result = 1 - while result <= x: - result = 2 * result - return result // 2 - - e = other - if e == 0 or (self.__order and e % self.__order == 0): - return INFINITY - if self == INFINITY: - return INFINITY - if e < 0: - return (-self) * (-e) - - # From X9.62 D.3.2: - - e3 = 3 * e - negative_self = Point( - self.__curve, - self.__x, - (-self.__y) % self.__curve.p(), - self.__order, - ) - i = leftmost_bit(e3) // 2 - result = self - # print("Multiplying %s by %d (e3 = %d):" % (self, other, e3)) - while i > 1: - result = result.double() - if (e3 & i) != 0 and (e & i) == 0: - result = result + self - if (e3 & i) == 0 and (e & i) != 0: - result = result + negative_self - # print(". . . i = %d, result = %s" % ( i, result )) - i = i // 2 - - return result - - def __rmul__(self, other): - """Multiply a point by an integer.""" - - return self * other - - def __str__(self): - if self == INFINITY: - return "infinity" - return "(%d,%d)" % (self.__x, self.__y) - - def double(self): - """Return a new point that is twice the old.""" - if self == INFINITY: - return INFINITY - - # X9.62 B.3: - - p = self.__curve.p() - a = self.__curve.a() - - l = ( - (3 * self.__x * self.__x + a) - * numbertheory.inverse_mod(2 * self.__y, p) - ) % p - - if not l: - return INFINITY - - x3 = (l * l - 2 * self.__x) % p - y3 = (l * (self.__x - x3) - self.__y) % p - - return Point(self.__curve, x3, y3) - - def x(self): - return self.__x - - def y(self): - return self.__y - - def curve(self): - return self.__curve - - def order(self): - return self.__order - - -class PointEdwards(AbstractPoint): - """Point on Twisted Edwards curve. - - Internally represents the coordinates on the curve using four parameters, - X, Y, Z, T. They correspond to affine parameters 'x' and 'y' like so: - - x = X / Z - y = Y / Z - x*y = T / Z - """ - - def __init__(self, curve, x, y, z, t, order=None, generator=False): - """ - Initialise a point that uses the extended coordinates internally. - """ - super(PointEdwards, self).__init__() - self.__curve = curve - if GMPY: # pragma: no branch - self.__coords = (mpz(x), mpz(y), mpz(z), mpz(t)) - self.__order = order and mpz(order) - else: # pragma: no branch - self.__coords = (x, y, z, t) - self.__order = order - self.__generator = generator - self.__precompute = [] - - @classmethod - def from_bytes( - cls, - curve, - data, - validate_encoding=None, - valid_encodings=None, - order=None, - generator=False, - ): - """ - Initialise the object from byte encoding of a point. - - `validate_encoding` and `valid_encodings` are provided for - compatibility with Weierstrass curves, they are ignored for Edwards - points. - - :param data: single point encoding of the public key - :type data: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lay - :type curve: ecdsa.ellipticcurve.CurveEdTw - :param None validate_encoding: Ignored, encoding is always validated - :param None valid_encodings: Ignored, there is just one encoding - supported - :param int order: the point order, must be non zero when using - generator=True - :param bool generator: Flag to mark the point as a curve generator, - this will cause the library to pre-compute some values to - make repeated usages of the point much faster - - :raises `~ecdsa.errors.MalformedPointError`: if the public point does - not lay on the curve or the encoding is invalid - - :return: Initialised point on an Edwards curve - :rtype: PointEdwards - """ - coord_x, coord_y = super(PointEdwards, cls).from_bytes( - curve, data, validate_encoding, valid_encodings - ) - return PointEdwards( - curve, coord_x, coord_y, 1, coord_x * coord_y, order, generator - ) - - def _maybe_precompute(self): - if not self.__generator or self.__precompute: - return self.__precompute - - # since this code will execute just once, and it's fully deterministic, - # depend on atomicity of the last assignment to switch from empty - # self.__precompute to filled one and just ignore the unlikely - # situation when two threads execute it at the same time (as it won't - # lead to inconsistent __precompute) - order = self.__order - assert order - precompute = [] - i = 1 - order *= 2 - coord_x, coord_y, coord_z, coord_t = self.__coords - prime = self.__curve.p() - - doubler = PointEdwards( - self.__curve, coord_x, coord_y, coord_z, coord_t, order - ) - # for "protection" against Minerva we need 1 or 2 more bits depending - # on order bit size, but it's easier to just calculate one - # point more always - order *= 4 - - while i < order: - doubler = doubler.scale() - coord_x, coord_y = doubler.x(), doubler.y() - coord_t = coord_x * coord_y % prime - precompute.append((coord_x, coord_y, coord_t)) - - i *= 2 - doubler = doubler.double() - - self.__precompute = precompute - return self.__precompute - - def x(self): - """Return affine x coordinate.""" - X1, _, Z1, _ = self.__coords - if Z1 == 1: - return X1 - p = self.__curve.p() - z_inv = numbertheory.inverse_mod(Z1, p) - return X1 * z_inv % p - - def y(self): - """Return affine y coordinate.""" - _, Y1, Z1, _ = self.__coords - if Z1 == 1: - return Y1 - p = self.__curve.p() - z_inv = numbertheory.inverse_mod(Z1, p) - return Y1 * z_inv % p - - def curve(self): - """Return the curve of the point.""" - return self.__curve - - def order(self): - return self.__order - - def scale(self): - """ - Return point scaled so that z == 1. - - Modifies point in place, returns self. - """ - X1, Y1, Z1, _ = self.__coords - if Z1 == 1: - return self - - p = self.__curve.p() - z_inv = numbertheory.inverse_mod(Z1, p) - x = X1 * z_inv % p - y = Y1 * z_inv % p - t = x * y % p - self.__coords = (x, y, 1, t) - return self - - def __eq__(self, other): - """Compare for equality two points with each-other. - - Note: only points on the same curve can be equal. - """ - x1, y1, z1, t1 = self.__coords - if other is INFINITY: - return not x1 or not t1 - if isinstance(other, PointEdwards): - x2, y2, z2, t2 = other.__coords - else: - return NotImplemented - if self.__curve != other.curve(): - return False - p = self.__curve.p() - - # cross multiply to eliminate divisions - xn1 = x1 * z2 % p - xn2 = x2 * z1 % p - yn1 = y1 * z2 % p - yn2 = y2 * z1 % p - return xn1 == xn2 and yn1 == yn2 - - def __ne__(self, other): - """Compare for inequality two points with each-other.""" - return not self == other - - def _add(self, X1, Y1, Z1, T1, X2, Y2, Z2, T2, p, a): - """add two points, assume sane parameters.""" - # after add-2008-hwcd-2 - # from https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html - # NOTE: there are more efficient formulas for Z1 or Z2 == 1 - A = X1 * X2 % p - B = Y1 * Y2 % p - C = Z1 * T2 % p - D = T1 * Z2 % p - E = D + C - F = ((X1 - Y1) * (X2 + Y2) + B - A) % p - G = B + a * A - H = D - C - if not H: - return self._double(X1, Y1, Z1, T1, p, a) - X3 = E * F % p - Y3 = G * H % p - T3 = E * H % p - Z3 = F * G % p - - return X3, Y3, Z3, T3 - - def __add__(self, other): - """Add point to another.""" - if other == INFINITY: - return self - if ( - not isinstance(other, PointEdwards) - or self.__curve != other.__curve - ): - raise ValueError("The other point is on a different curve.") - - p, a = self.__curve.p(), self.__curve.a() - X1, Y1, Z1, T1 = self.__coords - X2, Y2, Z2, T2 = other.__coords - - X3, Y3, Z3, T3 = self._add(X1, Y1, Z1, T1, X2, Y2, Z2, T2, p, a) - - if not X3 or not T3: - return INFINITY - return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) - - def __radd__(self, other): - """Add other to self.""" - return self + other - - def _double(self, X1, Y1, Z1, T1, p, a): - """Double the point, assume sane parameters.""" - # after "dbl-2008-hwcd" - # from https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html - # NOTE: there are more efficient formulas for Z1 == 1 - A = X1 * X1 % p - B = Y1 * Y1 % p - C = 2 * Z1 * Z1 % p - D = a * A % p - E = ((X1 + Y1) * (X1 + Y1) - A - B) % p - G = D + B - F = G - C - H = D - B - X3 = E * F % p - Y3 = G * H % p - T3 = E * H % p - Z3 = F * G % p - - return X3, Y3, Z3, T3 - - def double(self): - """Return point added to itself.""" - X1, Y1, Z1, T1 = self.__coords - - if not X1 or not T1: - return INFINITY - - p, a = self.__curve.p(), self.__curve.a() - - X3, Y3, Z3, T3 = self._double(X1, Y1, Z1, T1, p, a) - - # both Ed25519 and Ed448 have prime order, so no point added to - # itself will equal zero - if not X3 or not T3: # pragma: no branch - return INFINITY - return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) - - def __rmul__(self, other): - """Multiply point by an integer.""" - return self * other - - def _mul_precompute(self, other): - """Multiply point by integer with precomputation table.""" - X3, Y3, Z3, T3, p, a = 0, 1, 1, 0, self.__curve.p(), self.__curve.a() - _add = self._add - for X2, Y2, T2 in self.__precompute: - rem = other % 4 - if rem == 0 or rem == 2: - other //= 2 - elif rem == 3: - other = (other + 1) // 2 - X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, -X2, Y2, 1, -T2, p, a) - else: - assert rem == 1 - other = (other - 1) // 2 - X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, X2, Y2, 1, T2, p, a) - - if not X3 or not T3: - return INFINITY - - return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) - - def __mul__(self, other): - """Multiply point by an integer.""" - X2, Y2, Z2, T2 = self.__coords - if not X2 or not T2 or not other: - return INFINITY - if other == 1: - return self - if self.__order: - # order*2 as a "protection" for Minerva - other = other % (self.__order * 2) - if self._maybe_precompute(): - return self._mul_precompute(other) - - X3, Y3, Z3, T3 = 0, 1, 1, 0 # INFINITY in extended coordinates - p, a = self.__curve.p(), self.__curve.a() - _double = self._double - _add = self._add - - for i in reversed(self._naf(other)): - X3, Y3, Z3, T3 = _double(X3, Y3, Z3, T3, p, a) - if i < 0: - X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, -X2, Y2, Z2, -T2, p, a) - elif i > 0: - X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, X2, Y2, Z2, T2, p, a) - - if not X3 or not T3: - return INFINITY - - return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) - - -# This one point is the Point At Infinity for all purposes: -INFINITY = Point(None, None, None) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/errors.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/errors.py deleted file mode 100644 index 0184c05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/errors.py +++ /dev/null @@ -1,4 +0,0 @@ -class MalformedPointError(AssertionError): - """Raised in case the encoding of private or public key is malformed.""" - - pass diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/keys.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/keys.py deleted file mode 100644 index f74252c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/keys.py +++ /dev/null @@ -1,1631 +0,0 @@ -""" -Primary classes for performing signing and verification operations. -""" - -import binascii -from hashlib import sha1 -import os -from six import PY2 -from . import ecdsa, eddsa -from . import der, ssh -from . import rfc6979 -from . import ellipticcurve -from .curves import NIST192p, Curve, Ed25519, Ed448 -from .ecdsa import RSZeroError -from .util import string_to_number, number_to_string, randrange -from .util import sigencode_string, sigdecode_string, bit_length -from .util import ( - oid_ecPublicKey, - encoded_oid_ecPublicKey, - oid_ecDH, - oid_ecMQV, - MalformedSignature, -) -from ._compat import normalise_bytes -from .errors import MalformedPointError -from .ellipticcurve import PointJacobi, CurveEdTw - - -__all__ = [ - "BadSignatureError", - "BadDigestError", - "VerifyingKey", - "SigningKey", - "MalformedPointError", -] - - -class BadSignatureError(Exception): - """ - Raised when verification of signature failed. - - Will be raised irrespective of reason of the failure: - - * the calculated or provided hash does not match the signature - * the signature does not match the curve/public key - * the encoding of the signature is malformed - * the size of the signature does not match the curve of the VerifyingKey - """ - - pass - - -class BadDigestError(Exception): - """Raised in case the selected hash is too large for the curve.""" - - pass - - -def _truncate_and_convert_digest(digest, curve, allow_truncate): - """Truncates and converts digest to an integer.""" - if not allow_truncate: - if len(digest) > curve.baselen: - raise BadDigestError( - "this curve ({0}) is too short " - "for the length of your digest ({1})".format( - curve.name, 8 * len(digest) - ) - ) - else: - digest = digest[: curve.baselen] - number = string_to_number(digest) - if allow_truncate: - max_length = bit_length(curve.order) - # we don't use bit_length(number) as that truncates leading zeros - length = len(digest) * 8 - - # See NIST FIPS 186-4: - # - # When the length of the output of the hash function is greater - # than N (i.e., the bit length of q), then the leftmost N bits of - # the hash function output block shall be used in any calculation - # using the hash function output during the generation or - # verification of a digital signature. - # - # as such, we need to shift-out the low-order bits: - number >>= max(0, length - max_length) - - return number - - -class VerifyingKey(object): - """ - Class for handling keys that can verify signatures (public keys). - - :ivar `~ecdsa.curves.Curve` ~.curve: The Curve over which all the - cryptographic operations will take place - :ivar default_hashfunc: the function that will be used for hashing the - data. Should implement the same API as hashlib.sha1 - :vartype default_hashfunc: callable - :ivar pubkey: the actual public key - :vartype pubkey: ~ecdsa.ecdsa.Public_key - """ - - def __init__(self, _error__please_use_generate=None): - """Unsupported, please use one of the classmethods to initialise.""" - if not _error__please_use_generate: - raise TypeError( - "Please use VerifyingKey.generate() to construct me" - ) - self.curve = None - self.default_hashfunc = None - self.pubkey = None - - def __repr__(self): - pub_key = self.to_string("compressed") - if self.default_hashfunc: - hash_name = self.default_hashfunc().name - else: - hash_name = "None" - return "VerifyingKey.from_string({0!r}, {1!r}, {2})".format( - pub_key, self.curve, hash_name - ) - - def __eq__(self, other): - """Return True if the points are identical, False otherwise.""" - if isinstance(other, VerifyingKey): - return self.curve == other.curve and self.pubkey == other.pubkey - return NotImplemented - - def __ne__(self, other): - """Return False if the points are identical, True otherwise.""" - return not self == other - - @classmethod - def from_public_point( - cls, point, curve=NIST192p, hashfunc=sha1, validate_point=True - ): - """ - Initialise the object from a Point object. - - This is a low-level method, generally you will not want to use it. - - :param point: The point to wrap around, the actual public key - :type point: ~ecdsa.ellipticcurve.AbstractPoint - :param curve: The curve on which the point needs to reside, defaults - to NIST192p - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface - as :py:class:`hashlib.sha1` - :type hashfunc: callable - :type bool validate_point: whether to check if the point lays on curve - should always be used if the public point is not a result - of our own calculation - - :raises MalformedPointError: if the public point does not lay on the - curve - - :return: Initialised VerifyingKey object - :rtype: VerifyingKey - """ - self = cls(_error__please_use_generate=True) - if isinstance(curve.curve, CurveEdTw): - raise ValueError("Method incompatible with Edwards curves") - if not isinstance(point, ellipticcurve.PointJacobi): - point = ellipticcurve.PointJacobi.from_affine(point) - self.curve = curve - self.default_hashfunc = hashfunc - try: - self.pubkey = ecdsa.Public_key( - curve.generator, point, validate_point - ) - except ecdsa.InvalidPointError: - raise MalformedPointError("Point does not lay on the curve") - self.pubkey.order = curve.order - return self - - def precompute(self, lazy=False): - """ - Precompute multiplication tables for faster signature verification. - - Calling this method will cause the library to precompute the - scalar multiplication tables, used in signature verification. - While it's an expensive operation (comparable to performing - as many signatures as the bit size of the curve, i.e. 256 for NIST256p) - it speeds up verification 2 times. You should call this method - if you expect to verify hundreds of signatures (or more) using the same - VerifyingKey object. - - Note: You should call this method only once, this method generates a - new precomputation table every time it's called. - - :param bool lazy: whether to calculate the precomputation table now - (if set to False) or if it should be delayed to the time of first - use (when set to True) - """ - if isinstance(self.curve.curve, CurveEdTw): - pt = self.pubkey.point - self.pubkey.point = ellipticcurve.PointEdwards( - pt.curve(), - pt.x(), - pt.y(), - 1, - pt.x() * pt.y(), - self.curve.order, - generator=True, - ) - else: - self.pubkey.point = ellipticcurve.PointJacobi.from_affine( - self.pubkey.point, True - ) - # as precomputation in now delayed to the time of first use of the - # point and we were asked specifically to precompute now, make - # sure the precomputation is performed now to preserve the behaviour - if not lazy: - self.pubkey.point * 2 - - @classmethod - def from_string( - cls, - string, - curve=NIST192p, - hashfunc=sha1, - validate_point=True, - valid_encodings=None, - ): - """ - Initialise the object from byte encoding of public key. - - The method does accept and automatically detect the type of point - encoding used. It supports the :term:`raw encoding`, - :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. - It also works with the native encoding of Ed25519 and Ed448 public - keys (technically those are compressed, but encoded differently than - in other signature systems). - - Note, while the method is named "from_string" it's a misnomer from - Python 2 days when there were no binary strings. In Python 3 the - input needs to be a bytes-like object. - - :param string: single point encoding of the public key - :type string: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lay - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface as - hashlib.sha1. Ignored for EdDSA. - :type hashfunc: callable - :param validate_point: whether to verify that the point lays on the - provided curve or not, defaults to True. Ignored for EdDSA. - :type validate_point: bool - :param valid_encodings: list of acceptable point encoding formats, - supported ones are: :term:`uncompressed`, :term:`compressed`, - :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` - name). All formats by default (specified with ``None``). - Ignored for EdDSA. - :type valid_encodings: :term:`set-like object` - - :raises MalformedPointError: if the public point does not lay on the - curve or the encoding is invalid - - :return: Initialised VerifyingKey object - :rtype: VerifyingKey - """ - if isinstance(curve.curve, CurveEdTw): - self = cls(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = None # ignored for EdDSA - try: - self.pubkey = eddsa.PublicKey(curve.generator, string) - except ValueError: - raise MalformedPointError("Malformed point for the curve") - return self - - point = PointJacobi.from_bytes( - curve.curve, - string, - validate_encoding=validate_point, - valid_encodings=valid_encodings, - ) - return cls.from_public_point(point, curve, hashfunc, validate_point) - - @classmethod - def from_pem( - cls, - string, - hashfunc=sha1, - valid_encodings=None, - valid_curve_encodings=None, - ): - """ - Initialise from public key stored in :term:`PEM` format. - - The PEM header of the key should be ``BEGIN PUBLIC KEY``. - - See the :func:`~VerifyingKey.from_der()` method for details of the - format supported. - - Note: only a single PEM object decoding is supported in provided - string. - - :param string: text with PEM-encoded public ECDSA key - :type string: str - :param valid_encodings: list of allowed point encodings. - By default :term:`uncompressed`, :term:`compressed`, and - :term:`hybrid`. To read malformed files, include - :term:`raw encoding` with ``raw`` in the list. - :type valid_encodings: :term:`set-like object` - :param valid_curve_encodings: list of allowed encoding formats - for curve parameters. By default (``None``) all are supported: - ``named_curve`` and ``explicit``. - :type valid_curve_encodings: :term:`set-like object` - - - :return: Initialised VerifyingKey object - :rtype: VerifyingKey - """ - return cls.from_der( - der.unpem(string), - hashfunc=hashfunc, - valid_encodings=valid_encodings, - valid_curve_encodings=valid_curve_encodings, - ) - - @classmethod - def from_der( - cls, - string, - hashfunc=sha1, - valid_encodings=None, - valid_curve_encodings=None, - ): - """ - Initialise the key stored in :term:`DER` format. - - The expected format of the key is the SubjectPublicKeyInfo structure - from RFC5912 (for RSA keys, it's known as the PKCS#1 format):: - - SubjectPublicKeyInfo {PUBLIC-KEY: IOSet} ::= SEQUENCE { - algorithm AlgorithmIdentifier {PUBLIC-KEY, {IOSet}}, - subjectPublicKey BIT STRING - } - - Note: only public EC keys are supported by this method. The - SubjectPublicKeyInfo.algorithm.algorithm field must specify - id-ecPublicKey (see RFC3279). - - Only the named curve encoding is supported, thus the - SubjectPublicKeyInfo.algorithm.parameters field needs to be an - object identifier. A sequence in that field indicates an explicit - parameter curve encoding, this format is not supported. A NULL object - in that field indicates an "implicitlyCA" encoding, where the curve - parameters come from CA certificate, those, again, are not supported. - - :param string: binary string with the DER encoding of public ECDSA key - :type string: bytes-like object - :param valid_encodings: list of allowed point encodings. - By default :term:`uncompressed`, :term:`compressed`, and - :term:`hybrid`. To read malformed files, include - :term:`raw encoding` with ``raw`` in the list. - :type valid_encodings: :term:`set-like object` - :param valid_curve_encodings: list of allowed encoding formats - for curve parameters. By default (``None``) all are supported: - ``named_curve`` and ``explicit``. - :type valid_curve_encodings: :term:`set-like object` - - :return: Initialised VerifyingKey object - :rtype: VerifyingKey - """ - if valid_encodings is None: - valid_encodings = set(["uncompressed", "compressed", "hybrid"]) - string = normalise_bytes(string) - # [[oid_ecPublicKey,oid_curve], point_str_bitstring] - s1, empty = der.remove_sequence(string) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER pubkey: %s" % binascii.hexlify(empty) - ) - s2, point_str_bitstring = der.remove_sequence(s1) - # s2 = oid_ecPublicKey,oid_curve - oid_pk, rest = der.remove_object(s2) - if oid_pk in (Ed25519.oid, Ed448.oid): - if oid_pk == Ed25519.oid: - curve = Ed25519 - else: - assert oid_pk == Ed448.oid - curve = Ed448 - point_str, empty = der.remove_bitstring(point_str_bitstring, 0) - if empty: - raise der.UnexpectedDER("trailing junk after public key") - return cls.from_string(point_str, curve, None) - if not oid_pk == oid_ecPublicKey: - raise der.UnexpectedDER( - "Unexpected object identifier in DER " - "encoding: {0!r}".format(oid_pk) - ) - curve = Curve.from_der(rest, valid_curve_encodings) - point_str, empty = der.remove_bitstring(point_str_bitstring, 0) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after pubkey pointstring: %s" - % binascii.hexlify(empty) - ) - # raw encoding of point is invalid in DER files - if len(point_str) == curve.verifying_key_length: - raise der.UnexpectedDER("Malformed encoding of public point") - return cls.from_string( - point_str, - curve, - hashfunc=hashfunc, - valid_encodings=valid_encodings, - ) - - @classmethod - def from_public_key_recovery( - cls, - signature, - data, - curve, - hashfunc=sha1, - sigdecode=sigdecode_string, - allow_truncate=True, - ): - """ - Return keys that can be used as verifiers of the provided signature. - - Tries to recover the public key that can be used to verify the - signature, usually returns two keys like that. - - :param signature: the byte string with the encoded signature - :type signature: bytes-like object - :param data: the data to be hashed for signature verification - :type data: bytes-like object - :param curve: the curve over which the signature was performed - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface as hashlib.sha1 - :type hashfunc: callable - :param sigdecode: Callable to define the way the signature needs to - be decoded to an object, needs to handle `signature` as the - first parameter, the curve order (an int) as the second and return - a tuple with two integers, "r" as the first one and "s" as the - second one. See :func:`ecdsa.util.sigdecode_string` and - :func:`ecdsa.util.sigdecode_der` for examples. - :param bool allow_truncate: if True, the provided hashfunc can generate - values larger than the bit size of the order of the curve, the - extra bits (at the end of the digest) will be truncated. - :type sigdecode: callable - - :return: Initialised VerifyingKey objects - :rtype: list of VerifyingKey - """ - if isinstance(curve.curve, CurveEdTw): - raise ValueError("Method unsupported for Edwards curves") - data = normalise_bytes(data) - digest = hashfunc(data).digest() - return cls.from_public_key_recovery_with_digest( - signature, - digest, - curve, - hashfunc=hashfunc, - sigdecode=sigdecode, - allow_truncate=allow_truncate, - ) - - @classmethod - def from_public_key_recovery_with_digest( - cls, - signature, - digest, - curve, - hashfunc=sha1, - sigdecode=sigdecode_string, - allow_truncate=False, - ): - """ - Return keys that can be used as verifiers of the provided signature. - - Tries to recover the public key that can be used to verify the - signature, usually returns two keys like that. - - :param signature: the byte string with the encoded signature - :type signature: bytes-like object - :param digest: the hash value of the message signed by the signature - :type digest: bytes-like object - :param curve: the curve over which the signature was performed - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface as hashlib.sha1 - :type hashfunc: callable - :param sigdecode: Callable to define the way the signature needs to - be decoded to an object, needs to handle `signature` as the - first parameter, the curve order (an int) as the second and return - a tuple with two integers, "r" as the first one and "s" as the - second one. See :func:`ecdsa.util.sigdecode_string` and - :func:`ecdsa.util.sigdecode_der` for examples. - :type sigdecode: callable - :param bool allow_truncate: if True, the provided hashfunc can generate - values larger than the bit size of the order of the curve (and - the length of provided `digest`), the extra bits (at the end of the - digest) will be truncated. - - :return: Initialised VerifyingKey object - :rtype: VerifyingKey - """ - if isinstance(curve.curve, CurveEdTw): - raise ValueError("Method unsupported for Edwards curves") - generator = curve.generator - r, s = sigdecode(signature, generator.order()) - sig = ecdsa.Signature(r, s) - - digest = normalise_bytes(digest) - digest_as_number = _truncate_and_convert_digest( - digest, curve, allow_truncate - ) - pks = sig.recover_public_keys(digest_as_number, generator) - - # Transforms the ecdsa.Public_key object into a VerifyingKey - verifying_keys = [ - cls.from_public_point(pk.point, curve, hashfunc) for pk in pks - ] - return verifying_keys - - def to_string(self, encoding="raw"): - """ - Convert the public key to a byte string. - - The method by default uses the :term:`raw encoding` (specified - by `encoding="raw"`. It can also output keys in :term:`uncompressed`, - :term:`compressed` and :term:`hybrid` formats. - - Remember that the curve identification is not part of the encoding - so to decode the point using :func:`~VerifyingKey.from_string`, curve - needs to be specified. - - Note: while the method is called "to_string", it's a misnomer from - Python 2 days when character strings and byte strings shared type. - On Python 3 the returned type will be `bytes`. - - :return: :term:`raw encoding` of the public key (public point) on the - curve - :rtype: bytes - """ - assert encoding in ("raw", "uncompressed", "compressed", "hybrid") - return self.pubkey.point.to_bytes(encoding) - - def to_pem( - self, point_encoding="uncompressed", curve_parameters_encoding=None - ): - """ - Convert the public key to the :term:`PEM` format. - - The PEM header of the key will be ``BEGIN PUBLIC KEY``. - - The format of the key is described in the - :func:`~VerifyingKey.from_der()` method. - This method supports only "named curve" encoding of keys. - - :param str point_encoding: specification of the encoding format - of public keys. "uncompressed" is most portable, "compressed" is - smallest. "hybrid" is uncommon and unsupported by most - implementations, it is as big as "uncompressed". - :param str curve_parameters_encoding: the encoding for curve parameters - to use, by default tries to use ``named_curve`` encoding, - if that is not possible, falls back to ``explicit`` encoding. - - :return: portable encoding of the public key - :rtype: bytes - - .. warning:: The PEM is encoded to US-ASCII, it needs to be - re-encoded if the system is incompatible (e.g. uses UTF-16) - """ - return der.topem( - self.to_der(point_encoding, curve_parameters_encoding), - "PUBLIC KEY", - ) - - def to_der( - self, point_encoding="uncompressed", curve_parameters_encoding=None - ): - """ - Convert the public key to the :term:`DER` format. - - The format of the key is described in the - :func:`~VerifyingKey.from_der()` method. - This method supports only "named curve" encoding of keys. - - :param str point_encoding: specification of the encoding format - of public keys. "uncompressed" is most portable, "compressed" is - smallest. "hybrid" is uncommon and unsupported by most - implementations, it is as big as "uncompressed". - :param str curve_parameters_encoding: the encoding for curve parameters - to use, by default tries to use ``named_curve`` encoding, - if that is not possible, falls back to ``explicit`` encoding. - - :return: DER encoding of the public key - :rtype: bytes - """ - if point_encoding == "raw": - raise ValueError("raw point_encoding not allowed in DER") - point_str = self.to_string(point_encoding) - if isinstance(self.curve.curve, CurveEdTw): - return der.encode_sequence( - der.encode_sequence(der.encode_oid(*self.curve.oid)), - der.encode_bitstring(bytes(point_str), 0), - ) - return der.encode_sequence( - der.encode_sequence( - encoded_oid_ecPublicKey, - self.curve.to_der(curve_parameters_encoding, point_encoding), - ), - # 0 is the number of unused bits in the - # bit string - der.encode_bitstring(point_str, 0), - ) - - def to_ssh(self): - """ - Convert the public key to the SSH format. - - :return: SSH encoding of the public key - :rtype: bytes - """ - return ssh.serialize_public( - self.curve.name, - self.to_string(), - ) - - def verify( - self, - signature, - data, - hashfunc=None, - sigdecode=sigdecode_string, - allow_truncate=True, - ): - """ - Verify a signature made over provided data. - - Will hash `data` to verify the signature. - - By default expects signature in :term:`raw encoding`. Can also be used - to verify signatures in ASN.1 DER encoding by using - :func:`ecdsa.util.sigdecode_der` - as the `sigdecode` parameter. - - :param signature: encoding of the signature - :type signature: sigdecode method dependent - :param data: data signed by the `signature`, will be hashed using - `hashfunc`, if specified, or default hash function - :type data: :term:`bytes-like object` - :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface as hashlib.sha1 - :type hashfunc: callable - :param sigdecode: Callable to define the way the signature needs to - be decoded to an object, needs to handle `signature` as the - first parameter, the curve order (an int) as the second and return - a tuple with two integers, "r" as the first one and "s" as the - second one. See :func:`ecdsa.util.sigdecode_string` and - :func:`ecdsa.util.sigdecode_der` for examples. - :type sigdecode: callable - :param bool allow_truncate: if True, the provided digest can have - bigger bit-size than the order of the curve, the extra bits (at - the end of the digest) will be truncated. Use it when verifying - SHA-384 output using NIST256p or in similar situations. Defaults to - True. - - :raises BadSignatureError: if the signature is invalid or malformed - - :return: True if the verification was successful - :rtype: bool - """ - # signature doesn't have to be a bytes-like-object so don't normalise - # it, the decoders will do that - data = normalise_bytes(data) - if isinstance(self.curve.curve, CurveEdTw): - signature = normalise_bytes(signature) - try: - return self.pubkey.verify(data, signature) - except (ValueError, MalformedPointError) as e: - raise BadSignatureError("Signature verification failed", e) - - hashfunc = hashfunc or self.default_hashfunc - digest = hashfunc(data).digest() - return self.verify_digest(signature, digest, sigdecode, allow_truncate) - - def verify_digest( - self, - signature, - digest, - sigdecode=sigdecode_string, - allow_truncate=False, - ): - """ - Verify a signature made over provided hash value. - - By default expects signature in :term:`raw encoding`. Can also be used - to verify signatures in ASN.1 DER encoding by using - :func:`ecdsa.util.sigdecode_der` - as the `sigdecode` parameter. - - :param signature: encoding of the signature - :type signature: sigdecode method dependent - :param digest: raw hash value that the signature authenticates. - :type digest: :term:`bytes-like object` - :param sigdecode: Callable to define the way the signature needs to - be decoded to an object, needs to handle `signature` as the - first parameter, the curve order (an int) as the second and return - a tuple with two integers, "r" as the first one and "s" as the - second one. See :func:`ecdsa.util.sigdecode_string` and - :func:`ecdsa.util.sigdecode_der` for examples. - :type sigdecode: callable - :param bool allow_truncate: if True, the provided digest can have - bigger bit-size than the order of the curve, the extra bits (at - the end of the digest) will be truncated. Use it when verifying - SHA-384 output using NIST256p or in similar situations. - - :raises BadSignatureError: if the signature is invalid or malformed - :raises BadDigestError: if the provided digest is too big for the curve - associated with this VerifyingKey and allow_truncate was not set - - :return: True if the verification was successful - :rtype: bool - """ - # signature doesn't have to be a bytes-like-object so don't normalise - # it, the decoders will do that - digest = normalise_bytes(digest) - number = _truncate_and_convert_digest( - digest, - self.curve, - allow_truncate, - ) - - try: - r, s = sigdecode(signature, self.pubkey.order) - except (der.UnexpectedDER, MalformedSignature) as e: - raise BadSignatureError("Malformed formatting of signature", e) - sig = ecdsa.Signature(r, s) - if self.pubkey.verifies(number, sig): - return True - raise BadSignatureError("Signature verification failed") - - -class SigningKey(object): - """ - Class for handling keys that can create signatures (private keys). - - :ivar `~ecdsa.curves.Curve` curve: The Curve over which all the - cryptographic operations will take place - :ivar default_hashfunc: the function that will be used for hashing the - data. Should implement the same API as :py:class:`hashlib.sha1` - :ivar int baselen: the length of a :term:`raw encoding` of private key - :ivar `~ecdsa.keys.VerifyingKey` verifying_key: the public key - associated with this private key - :ivar `~ecdsa.ecdsa.Private_key` privkey: the actual private key - """ - - def __init__(self, _error__please_use_generate=None): - """Unsupported, please use one of the classmethods to initialise.""" - if not _error__please_use_generate: - raise TypeError("Please use SigningKey.generate() to construct me") - self.curve = None - self.default_hashfunc = None - self.baselen = None - self.verifying_key = None - self.privkey = None - - def __eq__(self, other): - """Return True if the points are identical, False otherwise.""" - if isinstance(other, SigningKey): - return ( - self.curve == other.curve - and self.verifying_key == other.verifying_key - and self.privkey == other.privkey - ) - return NotImplemented - - def __ne__(self, other): - """Return False if the points are identical, True otherwise.""" - return not self == other - - @classmethod - def _twisted_edwards_keygen(cls, curve, entropy): - """Generate a private key on a Twisted Edwards curve.""" - if not entropy: - entropy = os.urandom - random = entropy(curve.baselen) - private_key = eddsa.PrivateKey(curve.generator, random) - public_key = private_key.public_key() - - verifying_key = VerifyingKey.from_string( - public_key.public_key(), curve - ) - - self = cls(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = None - self.baselen = curve.baselen - self.privkey = private_key - self.verifying_key = verifying_key - return self - - @classmethod - def _weierstrass_keygen(cls, curve, entropy, hashfunc): - """Generate a private key on a Weierstrass curve.""" - secexp = randrange(curve.order, entropy) - return cls.from_secret_exponent(secexp, curve, hashfunc) - - @classmethod - def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1): - """ - Generate a random private key. - - :param curve: The curve on which the point needs to reside, defaults - to NIST192p - :type curve: ~ecdsa.curves.Curve - :param entropy: Source of randomness for generating the private keys, - should provide cryptographically secure random numbers if the keys - need to be secure. Uses os.urandom() by default. - :type entropy: callable - :param hashfunc: The default hash function that will be used for - signing, needs to implement the same interface - as hashlib.sha1 - :type hashfunc: callable - - :return: Initialised SigningKey object - :rtype: SigningKey - """ - if isinstance(curve.curve, CurveEdTw): - return cls._twisted_edwards_keygen(curve, entropy) - return cls._weierstrass_keygen(curve, entropy, hashfunc) - - @classmethod - def from_secret_exponent(cls, secexp, curve=NIST192p, hashfunc=sha1): - """ - Create a private key from a random integer. - - Note: it's a low level method, it's recommended to use the - :func:`~SigningKey.generate` method to create private keys. - - :param int secexp: secret multiplier (the actual private key in ECDSA). - Needs to be an integer between 1 and the curve order. - :param curve: The curve on which the point needs to reside - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - signing, needs to implement the same interface - as hashlib.sha1 - :type hashfunc: callable - - :raises MalformedPointError: when the provided secexp is too large - or too small for the curve selected - :raises RuntimeError: if the generation of public key from private - key failed - - :return: Initialised SigningKey object - :rtype: SigningKey - """ - if isinstance(curve.curve, CurveEdTw): - raise ValueError( - "Edwards keys don't support setting the secret scalar " - "(exponent) directly" - ) - self = cls(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = hashfunc - self.baselen = curve.baselen - n = curve.order - if not 1 <= secexp < n: - raise MalformedPointError( - "Invalid value for secexp, expected integer " - "between 1 and {0}".format(n) - ) - pubkey_point = curve.generator * secexp - if hasattr(pubkey_point, "scale"): - pubkey_point = pubkey_point.scale() - self.verifying_key = VerifyingKey.from_public_point( - pubkey_point, curve, hashfunc, False - ) - pubkey = self.verifying_key.pubkey - self.privkey = ecdsa.Private_key(pubkey, secexp) - self.privkey.order = n - return self - - @classmethod - def from_string(cls, string, curve=NIST192p, hashfunc=sha1): - """ - Decode the private key from :term:`raw encoding`. - - Note: the name of this method is a misnomer coming from days of - Python 2, when binary strings and character strings shared a type. - In Python 3, the expected type is `bytes`. - - :param string: the raw encoding of the private key - :type string: :term:`bytes-like object` - :param curve: The curve on which the point needs to reside - :type curve: ~ecdsa.curves.Curve - :param hashfunc: The default hash function that will be used for - signing, needs to implement the same interface - as hashlib.sha1 - :type hashfunc: callable - - :raises MalformedPointError: if the length of encoding doesn't match - the provided curve or the encoded values is too large - :raises RuntimeError: if the generation of public key from private - key failed - - :return: Initialised SigningKey object - :rtype: SigningKey - """ - string = normalise_bytes(string) - - if len(string) != curve.baselen: - raise MalformedPointError( - "Invalid length of private key, received {0}, " - "expected {1}".format(len(string), curve.baselen) - ) - if isinstance(curve.curve, CurveEdTw): - self = cls(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = None # Ignored for EdDSA - self.baselen = curve.baselen - self.privkey = eddsa.PrivateKey(curve.generator, string) - self.verifying_key = VerifyingKey.from_string( - self.privkey.public_key().public_key(), curve - ) - return self - secexp = string_to_number(string) - return cls.from_secret_exponent(secexp, curve, hashfunc) - - @classmethod - def from_pem(cls, string, hashfunc=sha1, valid_curve_encodings=None): - """ - Initialise from key stored in :term:`PEM` format. - - The PEM formats supported are the un-encrypted RFC5915 - (the ssleay format) supported by OpenSSL, and the more common - un-encrypted RFC5958 (the PKCS #8 format). - - The legacy format files have the header with the string - ``BEGIN EC PRIVATE KEY``. - PKCS#8 files have the header ``BEGIN PRIVATE KEY``. - Encrypted files (ones that include the string - ``Proc-Type: 4,ENCRYPTED`` - right after the PEM header) are not supported. - - See :func:`~SigningKey.from_der` for ASN.1 syntax of the objects in - this files. - - :param string: text with PEM-encoded private ECDSA key - :type string: str - :param valid_curve_encodings: list of allowed encoding formats - for curve parameters. By default (``None``) all are supported: - ``named_curve`` and ``explicit``. - :type valid_curve_encodings: :term:`set-like object` - - - :raises MalformedPointError: if the length of encoding doesn't match - the provided curve or the encoded values is too large - :raises RuntimeError: if the generation of public key from private - key failed - :raises UnexpectedDER: if the encoding of the PEM file is incorrect - - :return: Initialised SigningKey object - :rtype: SigningKey - """ - if not PY2 and isinstance(string, str): # pragma: no branch - string = string.encode() - - # The privkey pem may have multiple sections, commonly it also has - # "EC PARAMETERS", we need just "EC PRIVATE KEY". PKCS#8 should not - # have the "EC PARAMETERS" section; it's just "PRIVATE KEY". - private_key_index = string.find(b"-----BEGIN EC PRIVATE KEY-----") - if private_key_index == -1: - private_key_index = string.index(b"-----BEGIN PRIVATE KEY-----") - - return cls.from_der( - der.unpem(string[private_key_index:]), - hashfunc, - valid_curve_encodings, - ) - - @classmethod - def from_der(cls, string, hashfunc=sha1, valid_curve_encodings=None): - """ - Initialise from key stored in :term:`DER` format. - - The DER formats supported are the un-encrypted RFC5915 - (the ssleay format) supported by OpenSSL, and the more common - un-encrypted RFC5958 (the PKCS #8 format). - - Both formats contain an ASN.1 object following the syntax specified - in RFC5915:: - - ECPrivateKey ::= SEQUENCE { - version INTEGER { ecPrivkeyVer1(1) }} (ecPrivkeyVer1), - privateKey OCTET STRING, - parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - publicKey [1] BIT STRING OPTIONAL - } - - `publicKey` field is ignored completely (errors, if any, in it will - be undetected). - - Two formats are supported for the `parameters` field: the named - curve and the explicit encoding of curve parameters. - In the legacy ssleay format, this implementation requires the optional - `parameters` field to get the curve name. In PKCS #8 format, the curve - is part of the PrivateKeyAlgorithmIdentifier. - - The PKCS #8 format includes an ECPrivateKey object as the `privateKey` - field within a larger structure:: - - OneAsymmetricKey ::= SEQUENCE { - version Version, - privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - privateKey PrivateKey, - attributes [0] Attributes OPTIONAL, - ..., - [[2: publicKey [1] PublicKey OPTIONAL ]], - ... - } - - The `attributes` and `publicKey` fields are completely ignored; errors - in them will not be detected. - - :param string: binary string with DER-encoded private ECDSA key - :type string: :term:`bytes-like object` - :param valid_curve_encodings: list of allowed encoding formats - for curve parameters. By default (``None``) all are supported: - ``named_curve`` and ``explicit``. - Ignored for EdDSA. - :type valid_curve_encodings: :term:`set-like object` - - :raises MalformedPointError: if the length of encoding doesn't match - the provided curve or the encoded values is too large - :raises RuntimeError: if the generation of public key from private - key failed - :raises UnexpectedDER: if the encoding of the DER file is incorrect - - :return: Initialised SigningKey object - :rtype: SigningKey - """ - s = normalise_bytes(string) - curve = None - - s, empty = der.remove_sequence(s) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER privkey: %s" % binascii.hexlify(empty) - ) - - version, s = der.remove_integer(s) - - # At this point, PKCS #8 has a sequence containing the algorithm - # identifier and the curve identifier. The ssleay format instead has - # an octet string containing the key data, so this is how we can - # distinguish the two formats. - if der.is_sequence(s): - if version not in (0, 1): - raise der.UnexpectedDER( - "expected version '0' or '1' at start of privkey, got %d" - % version - ) - - sequence, s = der.remove_sequence(s) - algorithm_oid, algorithm_identifier = der.remove_object(sequence) - - if algorithm_oid in (Ed25519.oid, Ed448.oid): - if algorithm_identifier: - raise der.UnexpectedDER( - "Non NULL parameters for a EdDSA key" - ) - key_str_der, s = der.remove_octet_string(s) - - # As RFC5958 describe, there are may be optional Attributes - # and Publickey. Don't raise error if something after - # Privatekey - - # TODO parse attributes or validate publickey - # if s: - # raise der.UnexpectedDER( - # "trailing junk inside the privateKey" - # ) - key_str, s = der.remove_octet_string(key_str_der) - if s: - raise der.UnexpectedDER( - "trailing junk after the encoded private key" - ) - - if algorithm_oid == Ed25519.oid: - curve = Ed25519 - else: - assert algorithm_oid == Ed448.oid - curve = Ed448 - - return cls.from_string(key_str, curve, None) - - if algorithm_oid not in (oid_ecPublicKey, oid_ecDH, oid_ecMQV): - raise der.UnexpectedDER( - "unexpected algorithm identifier '%s'" % (algorithm_oid,) - ) - - curve = Curve.from_der(algorithm_identifier, valid_curve_encodings) - - # Up next is an octet string containing an ECPrivateKey. Ignore - # the optional "attributes" and "publicKey" fields that come after. - s, _ = der.remove_octet_string(s) - - # Unpack the ECPrivateKey to get to the key data octet string, - # and rejoin the ssleay parsing path. - s, empty = der.remove_sequence(s) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER privkey: %s" - % binascii.hexlify(empty) - ) - - version, s = der.remove_integer(s) - - # The version of the ECPrivateKey must be 1. - if version != 1: - raise der.UnexpectedDER( - "expected version '1' at start of DER privkey, got %d" - % version - ) - - privkey_str, s = der.remove_octet_string(s) - - if not curve: - tag, curve_oid_str, s = der.remove_constructed(s) - if tag != 0: - raise der.UnexpectedDER( - "expected tag 0 in DER privkey, got %d" % tag - ) - curve = Curve.from_der(curve_oid_str, valid_curve_encodings) - - # we don't actually care about the following fields - # - # tag, pubkey_bitstring, s = der.remove_constructed(s) - # if tag != 1: - # raise der.UnexpectedDER("expected tag 1 in DER privkey, got %d" - # % tag) - # pubkey_str = der.remove_bitstring(pubkey_bitstring, 0) - # if empty != "": - # raise der.UnexpectedDER("trailing junk after DER privkey " - # "pubkeystr: %s" - # % binascii.hexlify(empty)) - - # our from_string method likes fixed-length privkey strings - if len(privkey_str) < curve.baselen: - privkey_str = ( - b"\x00" * (curve.baselen - len(privkey_str)) + privkey_str - ) - return cls.from_string(privkey_str, curve, hashfunc) - - def to_string(self): - """ - Convert the private key to :term:`raw encoding`. - - Note: while the method is named "to_string", its name comes from - Python 2 days, when binary and character strings used the same type. - The type used in Python 3 is `bytes`. - - :return: raw encoding of private key - :rtype: bytes - """ - if isinstance(self.curve.curve, CurveEdTw): - return bytes(self.privkey.private_key) - secexp = self.privkey.secret_multiplier - s = number_to_string(secexp, self.privkey.order) - return s - - def to_pem( - self, - point_encoding="uncompressed", - format="ssleay", - curve_parameters_encoding=None, - ): - """ - Convert the private key to the :term:`PEM` format. - - See :func:`~SigningKey.from_pem` method for format description. - - Only the named curve format is supported. - The public key will be included in generated string. - - The PEM header will specify ``BEGIN EC PRIVATE KEY`` or - ``BEGIN PRIVATE KEY``, depending on the desired format. - - :param str point_encoding: format to use for encoding public point - :param str format: either ``ssleay`` (default) or ``pkcs8`` - :param str curve_parameters_encoding: format of encoded curve - parameters, default depends on the curve, if the curve has - an associated OID, ``named_curve`` format will be used, - if no OID is associated with the curve, the fallback of - ``explicit`` parameters will be used. - - :return: PEM encoded private key - :rtype: bytes - - .. warning:: The PEM is encoded to US-ASCII, it needs to be - re-encoded if the system is incompatible (e.g. uses UTF-16) - """ - # TODO: "BEGIN ECPARAMETERS" - assert format in ("ssleay", "pkcs8") - header = "EC PRIVATE KEY" if format == "ssleay" else "PRIVATE KEY" - return der.topem( - self.to_der(point_encoding, format, curve_parameters_encoding), - header, - ) - - def _encode_eddsa(self): - """Create a PKCS#8 encoding of EdDSA keys.""" - ec_private_key = der.encode_octet_string(self.to_string()) - return der.encode_sequence( - der.encode_integer(0), - der.encode_sequence(der.encode_oid(*self.curve.oid)), - der.encode_octet_string(ec_private_key), - ) - - def to_der( - self, - point_encoding="uncompressed", - format="ssleay", - curve_parameters_encoding=None, - ): - """ - Convert the private key to the :term:`DER` format. - - See :func:`~SigningKey.from_der` method for format specification. - - Only the named curve format is supported. - The public key will be included in the generated string. - - :param str point_encoding: format to use for encoding public point - Ignored for EdDSA - :param str format: either ``ssleay`` (default) or ``pkcs8``. - EdDSA keys require ``pkcs8``. - :param str curve_parameters_encoding: format of encoded curve - parameters, default depends on the curve, if the curve has - an associated OID, ``named_curve`` format will be used, - if no OID is associated with the curve, the fallback of - ``explicit`` parameters will be used. - Ignored for EdDSA. - - :return: DER encoded private key - :rtype: bytes - """ - # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1), - # cont[1],bitstring]) - if point_encoding == "raw": - raise ValueError("raw encoding not allowed in DER") - assert format in ("ssleay", "pkcs8") - if isinstance(self.curve.curve, CurveEdTw): - if format != "pkcs8": - raise ValueError("Only PKCS#8 format supported for EdDSA keys") - return self._encode_eddsa() - encoded_vk = self.get_verifying_key().to_string(point_encoding) - priv_key_elems = [ - der.encode_integer(1), - der.encode_octet_string(self.to_string()), - ] - if format == "ssleay": - priv_key_elems.append( - der.encode_constructed( - 0, self.curve.to_der(curve_parameters_encoding) - ) - ) - # the 0 in encode_bitstring specifies the number of unused bits - # in the `encoded_vk` string - priv_key_elems.append( - der.encode_constructed(1, der.encode_bitstring(encoded_vk, 0)) - ) - ec_private_key = der.encode_sequence(*priv_key_elems) - - if format == "ssleay": - return ec_private_key - else: - return der.encode_sequence( - # version = 1 means the public key is not present in the - # top-level structure. - der.encode_integer(1), - der.encode_sequence( - der.encode_oid(*oid_ecPublicKey), - self.curve.to_der(curve_parameters_encoding), - ), - der.encode_octet_string(ec_private_key), - ) - - def to_ssh(self): - """ - Convert the private key to the SSH format. - - :return: SSH encoded private key - :rtype: bytes - """ - return ssh.serialize_private( - self.curve.name, - self.verifying_key.to_string(), - self.to_string(), - ) - - def get_verifying_key(self): - """ - Return the VerifyingKey associated with this private key. - - Equivalent to reading the `verifying_key` field of an instance. - - :return: a public key that can be used to verify the signatures made - with this SigningKey - :rtype: VerifyingKey - """ - return self.verifying_key - - def sign_deterministic( - self, - data, - hashfunc=None, - sigencode=sigencode_string, - extra_entropy=b"", - ): - """ - Create signature over data. - - For Weierstrass curves it uses the deterministic RFC6979 algorithm. - For Edwards curves it uses the standard EdDSA algorithm. - - For ECDSA the data will be hashed using the `hashfunc` function before - signing. - For EdDSA the data will be hashed with the hash associated with the - curve (SHA-512 for Ed25519 and SHAKE-256 for Ed448). - - This is the recommended method for performing signatures when hashing - of data is necessary. - - :param data: data to be hashed and computed signature over - :type data: :term:`bytes-like object` - :param hashfunc: hash function to use for computing the signature, - if unspecified, the default hash function selected during - object initialisation will be used (see - `VerifyingKey.default_hashfunc`). The object needs to implement - the same interface as hashlib.sha1. - Ignored with EdDSA. - :type hashfunc: callable - :param sigencode: function used to encode the signature. - The function needs to accept three parameters: the two integers - that are the signature and the order of the curve over which the - signature was computed. It needs to return an encoded signature. - See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der` - as examples of such functions. - Ignored with EdDSA. - :type sigencode: callable - :param extra_entropy: additional data that will be fed into the random - number generator used in the RFC6979 process. Entirely optional. - Ignored with EdDSA. - :type extra_entropy: :term:`bytes-like object` - - :return: encoded signature over `data` - :rtype: bytes or sigencode function dependent type - """ - hashfunc = hashfunc or self.default_hashfunc - data = normalise_bytes(data) - - if isinstance(self.curve.curve, CurveEdTw): - return self.privkey.sign(data) - - extra_entropy = normalise_bytes(extra_entropy) - digest = hashfunc(data).digest() - - return self.sign_digest_deterministic( - digest, - hashfunc=hashfunc, - sigencode=sigencode, - extra_entropy=extra_entropy, - allow_truncate=True, - ) - - def sign_digest_deterministic( - self, - digest, - hashfunc=None, - sigencode=sigencode_string, - extra_entropy=b"", - allow_truncate=False, - ): - """ - Create signature for digest using the deterministic RFC6979 algorithm. - - `digest` should be the output of cryptographically secure hash function - like SHA256 or SHA-3-256. - - This is the recommended method for performing signatures when no - hashing of data is necessary. - - :param digest: hash of data that will be signed - :type digest: :term:`bytes-like object` - :param hashfunc: hash function to use for computing the random "k" - value from RFC6979 process, - if unspecified, the default hash function selected during - object initialisation will be used (see - :attr:`.VerifyingKey.default_hashfunc`). The object needs to - implement - the same interface as :func:`~hashlib.sha1` from :py:mod:`hashlib`. - :type hashfunc: callable - :param sigencode: function used to encode the signature. - The function needs to accept three parameters: the two integers - that are the signature and the order of the curve over which the - signature was computed. It needs to return an encoded signature. - See :func:`~ecdsa.util.sigencode_string` and - :func:`~ecdsa.util.sigencode_der` - as examples of such functions. - :type sigencode: callable - :param extra_entropy: additional data that will be fed into the random - number generator used in the RFC6979 process. Entirely optional. - :type extra_entropy: :term:`bytes-like object` - :param bool allow_truncate: if True, the provided digest can have - bigger bit-size than the order of the curve, the extra bits (at - the end of the digest) will be truncated. Use it when signing - SHA-384 output using NIST256p or in similar situations. - - :return: encoded signature for the `digest` hash - :rtype: bytes or sigencode function dependent type - """ - if isinstance(self.curve.curve, CurveEdTw): - raise ValueError("Method unsupported for Edwards curves") - secexp = self.privkey.secret_multiplier - hashfunc = hashfunc or self.default_hashfunc - digest = normalise_bytes(digest) - extra_entropy = normalise_bytes(extra_entropy) - - def simple_r_s(r, s, order): - return r, s, order - - retry_gen = 0 - while True: - k = rfc6979.generate_k( - self.curve.generator.order(), - secexp, - hashfunc, - digest, - retry_gen=retry_gen, - extra_entropy=extra_entropy, - ) - try: - r, s, order = self.sign_digest( - digest, - sigencode=simple_r_s, - k=k, - allow_truncate=allow_truncate, - ) - break - except RSZeroError: - retry_gen += 1 - - return sigencode(r, s, order) - - def sign( - self, - data, - entropy=None, - hashfunc=None, - sigencode=sigencode_string, - k=None, - allow_truncate=True, - ): - """ - Create signature over data. - - Uses the probabilistic ECDSA algorithm for Weierstrass curves - (NIST256p, etc.) and the deterministic EdDSA algorithm for the - Edwards curves (Ed25519, Ed448). - - This method uses the standard ECDSA algorithm that requires a - cryptographically secure random number generator. - - It's recommended to use the :func:`~SigningKey.sign_deterministic` - method instead of this one. - - :param data: data that will be hashed for signing - :type data: :term:`bytes-like object` - :param callable entropy: randomness source, :func:`os.urandom` by - default. Ignored with EdDSA. - :param hashfunc: hash function to use for hashing the provided - ``data``. - If unspecified the default hash function selected during - object initialisation will be used (see - :attr:`.VerifyingKey.default_hashfunc`). - Should behave like :func:`~hashlib.sha1` from :py:mod:`hashlib`. - The output length of the - hash (in bytes) must not be longer than the length of the curve - order (rounded up to the nearest byte), so using SHA256 with - NIST256p is ok, but SHA256 with NIST192p is not. (In the 2**-96ish - unlikely event of a hash output larger than the curve order, the - hash will effectively be wrapped mod n). - If you want to explicitly allow use of large hashes with small - curves set the ``allow_truncate`` to ``True``. - Use ``hashfunc=hashlib.sha1`` to match openssl's - ``-ecdsa-with-SHA1`` mode, - or ``hashfunc=hashlib.sha256`` for openssl-1.0.0's - ``-ecdsa-with-SHA256``. - Ignored for EdDSA - :type hashfunc: callable - :param sigencode: function used to encode the signature. - The function needs to accept three parameters: the two integers - that are the signature and the order of the curve over which the - signature was computed. It needs to return an encoded signature. - See :func:`~ecdsa.util.sigencode_string` and - :func:`~ecdsa.util.sigencode_der` - as examples of such functions. - Ignored for EdDSA - :type sigencode: callable - :param int k: a pre-selected nonce for calculating the signature. - In typical use cases, it should be set to None (the default) to - allow its generation from an entropy source. - Ignored for EdDSA. - :param bool allow_truncate: if ``True``, the provided digest can have - bigger bit-size than the order of the curve, the extra bits (at - the end of the digest) will be truncated. Use it when signing - SHA-384 output using NIST256p or in similar situations. True by - default. - Ignored for EdDSA. - - :raises RSZeroError: in the unlikely event when *r* parameter or - *s* parameter of the created signature is equal 0, as that would - leak the key. Caller should try a better entropy source, retry with - different ``k``, or use the - :func:`~SigningKey.sign_deterministic` in such case. - - :return: encoded signature of the hash of `data` - :rtype: bytes or sigencode function dependent type - """ - hashfunc = hashfunc or self.default_hashfunc - data = normalise_bytes(data) - if isinstance(self.curve.curve, CurveEdTw): - return self.sign_deterministic(data) - h = hashfunc(data).digest() - return self.sign_digest(h, entropy, sigencode, k, allow_truncate) - - def sign_digest( - self, - digest, - entropy=None, - sigencode=sigencode_string, - k=None, - allow_truncate=False, - ): - """ - Create signature over digest using the probabilistic ECDSA algorithm. - - This method uses the standard ECDSA algorithm that requires a - cryptographically secure random number generator. - - This method does not hash the input. - - It's recommended to use the - :func:`~SigningKey.sign_digest_deterministic` method - instead of this one. - - :param digest: hash value that will be signed - :type digest: :term:`bytes-like object` - :param callable entropy: randomness source, os.urandom by default - :param sigencode: function used to encode the signature. - The function needs to accept three parameters: the two integers - that are the signature and the order of the curve over which the - signature was computed. It needs to return an encoded signature. - See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der` - as examples of such functions. - :type sigencode: callable - :param int k: a pre-selected nonce for calculating the signature. - In typical use cases, it should be set to None (the default) to - allow its generation from an entropy source. - :param bool allow_truncate: if True, the provided digest can have - bigger bit-size than the order of the curve, the extra bits (at - the end of the digest) will be truncated. Use it when signing - SHA-384 output using NIST256p or in similar situations. - - :raises RSZeroError: in the unlikely event when "r" parameter or - "s" parameter of the created signature is equal 0, as that would - leak the key. Caller should try a better entropy source, retry with - different 'k', or use the - :func:`~SigningKey.sign_digest_deterministic` in such case. - - :return: encoded signature for the `digest` hash - :rtype: bytes or sigencode function dependent type - """ - if isinstance(self.curve.curve, CurveEdTw): - raise ValueError("Method unsupported for Edwards curves") - digest = normalise_bytes(digest) - number = _truncate_and_convert_digest( - digest, - self.curve, - allow_truncate, - ) - r, s = self.sign_number(number, entropy, k) - return sigencode(r, s, self.privkey.order) - - def sign_number(self, number, entropy=None, k=None): - """ - Sign an integer directly. - - Note, this is a low level method, usually you will want to use - :func:`~SigningKey.sign_deterministic` or - :func:`~SigningKey.sign_digest_deterministic`. - - :param int number: number to sign using the probabilistic ECDSA - algorithm. - :param callable entropy: entropy source, os.urandom by default - :param int k: pre-selected nonce for signature operation. If unset - it will be selected at random using the entropy source. - - :raises RSZeroError: in the unlikely event when "r" parameter or - "s" parameter of the created signature is equal 0, as that would - leak the key. Caller should try a better entropy source, retry with - different 'k', or use the - :func:`~SigningKey.sign_digest_deterministic` in such case. - - :return: the "r" and "s" parameters of the signature - :rtype: tuple of ints - """ - if isinstance(self.curve.curve, CurveEdTw): - raise ValueError("Method unsupported for Edwards curves") - order = self.privkey.order - - if k is not None: - _k = k - else: - _k = randrange(order, entropy) - - assert 1 <= _k < order - sig = self.privkey.sign(number, _k) - return sig.r, sig.s diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/numbertheory.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/numbertheory.py deleted file mode 100644 index fe974f8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/numbertheory.py +++ /dev/null @@ -1,835 +0,0 @@ -#! /usr/bin/env python -# -# Provide some simple capabilities from number theory. -# -# Version of 2008.11.14. -# -# Written in 2005 and 2006 by Peter Pearson and placed in the public domain. -# Revision history: -# 2008.11.14: Use pow(base, exponent, modulus) for modular_exp. -# Make gcd and lcm accept arbitrarily many arguments. - -from __future__ import division - -import sys -from six import integer_types, PY2 -from six.moves import reduce - -try: - xrange -except NameError: - xrange = range -try: - from gmpy2 import powmod, mpz - - GMPY2 = True - GMPY = False -except ImportError: # pragma: no branch - GMPY2 = False - try: - from gmpy import mpz - - GMPY = True - except ImportError: - GMPY = False - - -if GMPY2 or GMPY: # pragma: no branch - integer_types = tuple(integer_types + (type(mpz(1)),)) - - -import math -import warnings -import random -from .util import bit_length - - -class Error(Exception): - """Base class for exceptions in this module.""" - - pass - - -class JacobiError(Error): - pass - - -class SquareRootError(Error): - pass - - -class NegativeExponentError(Error): - pass - - -def modular_exp(base, exponent, modulus): # pragma: no cover - """Raise base to exponent, reducing by modulus""" - # deprecated in 0.14 - warnings.warn( - "Function is unused in library code. If you use this code, " - "change to pow() builtin.", - DeprecationWarning, - ) - if exponent < 0: - raise NegativeExponentError( - "Negative exponents (%d) not allowed" % exponent - ) - return pow(base, exponent, modulus) - - -def polynomial_reduce_mod(poly, polymod, p): - """Reduce poly by polymod, integer arithmetic modulo p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # This module has been tested only by extensive use - # in calculating modular square roots. - - # Just to make this easy, require a monic polynomial: - assert polymod[-1] == 1 - - assert len(polymod) > 1 - - while len(poly) >= len(polymod): - if poly[-1] != 0: - for i in xrange(2, len(polymod) + 1): - poly[-i] = (poly[-i] - poly[-1] * polymod[-i]) % p - poly = poly[0:-1] - - return poly - - -def polynomial_multiply_mod(m1, m2, polymod, p): - """Polynomial multiplication modulo a polynomial over ints mod p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # This is just a seat-of-the-pants implementation. - - # This module has been tested only by extensive use - # in calculating modular square roots. - - # Initialize the product to zero: - - prod = (len(m1) + len(m2) - 1) * [0] - - # Add together all the cross-terms: - - for i in xrange(len(m1)): - for j in xrange(len(m2)): - prod[i + j] = (prod[i + j] + m1[i] * m2[j]) % p - - return polynomial_reduce_mod(prod, polymod, p) - - -def polynomial_exp_mod(base, exponent, polymod, p): - """Polynomial exponentiation modulo a polynomial over ints mod p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # Based on the Handbook of Applied Cryptography, algorithm 2.227. - - # This module has been tested only by extensive use - # in calculating modular square roots. - - assert exponent < p - - if exponent == 0: - return [1] - - G = base - k = exponent - if k % 2 == 1: - s = G - else: - s = [1] - - while k > 1: - k = k // 2 - G = polynomial_multiply_mod(G, G, polymod, p) - if k % 2 == 1: - s = polynomial_multiply_mod(G, s, polymod, p) - - return s - - -def jacobi(a, n): - """Jacobi symbol""" - - # Based on the Handbook of Applied Cryptography (HAC), algorithm 2.149. - - # This function has been tested by comparison with a small - # table printed in HAC, and by extensive use in calculating - # modular square roots. - - if not n >= 3: - raise JacobiError("n must be larger than 2") - if not n % 2 == 1: - raise JacobiError("n must be odd") - a = a % n - if a == 0: - return 0 - if a == 1: - return 1 - a1, e = a, 0 - while a1 % 2 == 0: - a1, e = a1 // 2, e + 1 - if e % 2 == 0 or n % 8 == 1 or n % 8 == 7: - s = 1 - else: - s = -1 - if a1 == 1: - return s - if n % 4 == 3 and a1 % 4 == 3: - s = -s - return s * jacobi(n % a1, a1) - - -def square_root_mod_prime(a, p): - """Modular square root of a, mod p, p prime.""" - - # Based on the Handbook of Applied Cryptography, algorithms 3.34 to 3.39. - - # This module has been tested for all values in [0,p-1] for - # every prime p from 3 to 1229. - - assert 0 <= a < p - assert 1 < p - - if a == 0: - return 0 - if p == 2: - return a - - jac = jacobi(a, p) - if jac == -1: - raise SquareRootError("%d has no square root modulo %d" % (a, p)) - - if p % 4 == 3: - return pow(a, (p + 1) // 4, p) - - if p % 8 == 5: - d = pow(a, (p - 1) // 4, p) - if d == 1: - return pow(a, (p + 3) // 8, p) - assert d == p - 1 - return (2 * a * pow(4 * a, (p - 5) // 8, p)) % p - - if PY2: - # xrange on python2 can take integers representable as C long only - range_top = min(0x7FFFFFFF, p) - else: - range_top = p - for b in xrange(2, range_top): # pragma: no branch - if jacobi(b * b - 4 * a, p) == -1: - f = (a, -b, 1) - ff = polynomial_exp_mod((0, 1), (p + 1) // 2, f, p) - if ff[1]: - raise SquareRootError("p is not prime") - return ff[0] - # just an assertion - raise RuntimeError("No b found.") # pragma: no cover - - -# because all the inverse_mod code is arch/environment specific, and coveralls -# expects it to execute equal number of times, we need to waive it by -# adding the "no branch" pragma to all branches -if GMPY2: # pragma: no branch - - def inverse_mod(a, m): - """Inverse of a mod m.""" - if a == 0: # pragma: no branch - return 0 - return powmod(a, -1, m) - -elif GMPY: # pragma: no branch - - def inverse_mod(a, m): - """Inverse of a mod m.""" - # while libgmp does support inverses modulo, it is accessible - # only using the native `pow()` function, and `pow()` in gmpy sanity - # checks the parameters before passing them on to underlying - # implementation - if a == 0: # pragma: no branch - return 0 - a = mpz(a) - m = mpz(m) - - lm, hm = mpz(1), mpz(0) - low, high = a % m, m - while low > 1: # pragma: no branch - r = high // low - lm, low, hm, high = hm - lm * r, high - low * r, lm, low - - return lm % m - -elif sys.version_info >= (3, 8): # pragma: no branch - - def inverse_mod(a, m): - """Inverse of a mod m.""" - if a == 0: # pragma: no branch - return 0 - return pow(a, -1, m) - -else: # pragma: no branch - - def inverse_mod(a, m): - """Inverse of a mod m.""" - - if a == 0: # pragma: no branch - return 0 - - lm, hm = 1, 0 - low, high = a % m, m - while low > 1: # pragma: no branch - r = high // low - lm, low, hm, high = hm - lm * r, high - low * r, lm, low - - return lm % m - - -try: - gcd2 = math.gcd -except AttributeError: - - def gcd2(a, b): - """Greatest common divisor using Euclid's algorithm.""" - while a: - a, b = b % a, a - return b - - -def gcd(*a): - """Greatest common divisor. - - Usage: gcd([ 2, 4, 6 ]) - or: gcd(2, 4, 6) - """ - - if len(a) > 1: - return reduce(gcd2, a) - if hasattr(a[0], "__iter__"): - return reduce(gcd2, a[0]) - return a[0] - - -def lcm2(a, b): - """Least common multiple of two integers.""" - - return (a * b) // gcd(a, b) - - -def lcm(*a): - """Least common multiple. - - Usage: lcm([ 3, 4, 5 ]) - or: lcm(3, 4, 5) - """ - - if len(a) > 1: - return reduce(lcm2, a) - if hasattr(a[0], "__iter__"): - return reduce(lcm2, a[0]) - return a[0] - - -def factorization(n): - """Decompose n into a list of (prime,exponent) pairs.""" - - assert isinstance(n, integer_types) - - if n < 2: - return [] - - result = [] - - # Test the small primes: - - for d in smallprimes: - if d > n: - break - q, r = divmod(n, d) - if r == 0: - count = 1 - while d <= n: # pragma: no branch - n = q - q, r = divmod(n, d) - if r != 0: - break - count = count + 1 - result.append((d, count)) - - # If n is still greater than the last of our small primes, - # it may require further work: - - if n > smallprimes[-1]: - if is_prime(n): # If what's left is prime, it's easy: - result.append((n, 1)) - else: # Ugh. Search stupidly for a divisor: - d = smallprimes[-1] - while 1: - d = d + 2 # Try the next divisor. - q, r = divmod(n, d) - if q < d: # n < d*d means we're done, n = 1 or prime. - break - if r == 0: # d divides n. How many times? - count = 1 - n = q - # As long as d might still divide n, - while d <= n: # pragma: no branch - q, r = divmod(n, d) # see if it does. - if r != 0: - break - n = q # It does. Reduce n, increase count. - count = count + 1 - result.append((d, count)) - if n > 1: - result.append((n, 1)) - - return result - - -def phi(n): # pragma: no cover - """Return the Euler totient function of n.""" - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - assert isinstance(n, integer_types) - - if n < 3: - return 1 - - result = 1 - ff = factorization(n) - for f in ff: - e = f[1] - if e > 1: - result = result * f[0] ** (e - 1) * (f[0] - 1) - else: - result = result * (f[0] - 1) - return result - - -def carmichael(n): # pragma: no cover - """Return Carmichael function of n. - - Carmichael(n) is the smallest integer x such that - m**x = 1 mod n for all m relatively prime to n. - """ - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - return carmichael_of_factorized(factorization(n)) - - -def carmichael_of_factorized(f_list): # pragma: no cover - """Return the Carmichael function of a number that is - represented as a list of (prime,exponent) pairs. - """ - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - if len(f_list) < 1: - return 1 - - result = carmichael_of_ppower(f_list[0]) - for i in xrange(1, len(f_list)): - result = lcm(result, carmichael_of_ppower(f_list[i])) - - return result - - -def carmichael_of_ppower(pp): # pragma: no cover - """Carmichael function of the given power of the given prime.""" - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - p, a = pp - if p == 2 and a > 2: - return 2 ** (a - 2) - else: - return (p - 1) * p ** (a - 1) - - -def order_mod(x, m): # pragma: no cover - """Return the order of x in the multiplicative group mod m.""" - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - # Warning: this implementation is not very clever, and will - # take a long time if m is very large. - - if m <= 1: - return 0 - - assert gcd(x, m) == 1 - - z = x - result = 1 - while z != 1: - z = (z * x) % m - result = result + 1 - return result - - -def largest_factor_relatively_prime(a, b): # pragma: no cover - """Return the largest factor of a relatively prime to b.""" - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - while 1: - d = gcd(a, b) - if d <= 1: - break - b = d - while 1: - q, r = divmod(a, d) - if r > 0: - break - a = q - return a - - -def kinda_order_mod(x, m): # pragma: no cover - """Return the order of x in the multiplicative group mod m', - where m' is the largest factor of m relatively prime to x. - """ - # deprecated in 0.14 - warnings.warn( - "Function is unused by library code. If you use this code, " - "please open an issue in " - "https://github.com/tlsfuzzer/python-ecdsa", - DeprecationWarning, - ) - - return order_mod(x, largest_factor_relatively_prime(m, x)) - - -def is_prime(n): - """Return True if x is prime, False otherwise. - - We use the Miller-Rabin test, as given in Menezes et al. p. 138. - This test is not exact: there are composite values n for which - it returns True. - - In testing the odd numbers from 10000001 to 19999999, - about 66 composites got past the first test, - 5 got past the second test, and none got past the third. - Since factors of 2, 3, 5, 7, and 11 were detected during - preliminary screening, the number of numbers tested by - Miller-Rabin was (19999999 - 10000001)*(2/3)*(4/5)*(6/7) - = 4.57 million. - """ - - # (This is used to study the risk of false positives:) - global miller_rabin_test_count - - miller_rabin_test_count = 0 - - if n <= smallprimes[-1]: - if n in smallprimes: - return True - else: - return False - # 2310 = 2 * 3 * 5 * 7 * 11 - if gcd(n, 2310) != 1: - return False - - # Choose a number of iterations sufficient to reduce the - # probability of accepting a composite below 2**-80 - # (from Menezes et al. Table 4.4): - - t = 40 - n_bits = 1 + bit_length(n) - assert 11 <= n_bits <= 16384 - for k, tt in ( - (100, 27), - (150, 18), - (200, 15), - (250, 12), - (300, 9), - (350, 8), - (400, 7), - (450, 6), - (550, 5), - (650, 4), - (850, 3), - (1300, 2), - ): - if n_bits < k: - break - t = tt - - # Run the test t times: - - s = 0 - r = n - 1 - while (r % 2) == 0: - s = s + 1 - r = r // 2 - for i in xrange(t): - a = random.choice(smallprimes) - y = pow(a, r, n) - if y != 1 and y != n - 1: - j = 1 - while j <= s - 1 and y != n - 1: - y = pow(y, 2, n) - if y == 1: - miller_rabin_test_count = i + 1 - return False - j = j + 1 - if y != n - 1: - miller_rabin_test_count = i + 1 - return False - return True - - -def next_prime(starting_value): - """Return the smallest prime larger than the starting value.""" - - if starting_value < 2: - return 2 - result = (starting_value + 1) | 1 - while not is_prime(result): - result = result + 2 - return result - - -smallprimes = [ - 2, - 3, - 5, - 7, - 11, - 13, - 17, - 19, - 23, - 29, - 31, - 37, - 41, - 43, - 47, - 53, - 59, - 61, - 67, - 71, - 73, - 79, - 83, - 89, - 97, - 101, - 103, - 107, - 109, - 113, - 127, - 131, - 137, - 139, - 149, - 151, - 157, - 163, - 167, - 173, - 179, - 181, - 191, - 193, - 197, - 199, - 211, - 223, - 227, - 229, - 233, - 239, - 241, - 251, - 257, - 263, - 269, - 271, - 277, - 281, - 283, - 293, - 307, - 311, - 313, - 317, - 331, - 337, - 347, - 349, - 353, - 359, - 367, - 373, - 379, - 383, - 389, - 397, - 401, - 409, - 419, - 421, - 431, - 433, - 439, - 443, - 449, - 457, - 461, - 463, - 467, - 479, - 487, - 491, - 499, - 503, - 509, - 521, - 523, - 541, - 547, - 557, - 563, - 569, - 571, - 577, - 587, - 593, - 599, - 601, - 607, - 613, - 617, - 619, - 631, - 641, - 643, - 647, - 653, - 659, - 661, - 673, - 677, - 683, - 691, - 701, - 709, - 719, - 727, - 733, - 739, - 743, - 751, - 757, - 761, - 769, - 773, - 787, - 797, - 809, - 811, - 821, - 823, - 827, - 829, - 839, - 853, - 857, - 859, - 863, - 877, - 881, - 883, - 887, - 907, - 911, - 919, - 929, - 937, - 941, - 947, - 953, - 967, - 971, - 977, - 983, - 991, - 997, - 1009, - 1013, - 1019, - 1021, - 1031, - 1033, - 1039, - 1049, - 1051, - 1061, - 1063, - 1069, - 1087, - 1091, - 1093, - 1097, - 1103, - 1109, - 1117, - 1123, - 1129, - 1151, - 1153, - 1163, - 1171, - 1181, - 1187, - 1193, - 1201, - 1213, - 1217, - 1223, - 1229, -] - -miller_rabin_test_count = 0 diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/rfc6979.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/rfc6979.py deleted file mode 100644 index 0728b5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/rfc6979.py +++ /dev/null @@ -1,113 +0,0 @@ -""" -RFC 6979: - Deterministic Usage of the Digital Signature Algorithm (DSA) and - Elliptic Curve Digital Signature Algorithm (ECDSA) - - http://tools.ietf.org/html/rfc6979 - -Many thanks to Coda Hale for his implementation in Go language: - https://github.com/codahale/rfc6979 -""" - -import hmac -from binascii import hexlify -from .util import number_to_string, number_to_string_crop, bit_length -from ._compat import hmac_compat - - -# bit_length was defined in this module previously so keep it for backwards -# compatibility, will need to deprecate and remove it later -__all__ = ["bit_length", "bits2int", "bits2octets", "generate_k"] - - -def bits2int(data, qlen): - x = int(hexlify(data), 16) - l = len(data) * 8 - - if l > qlen: - return x >> (l - qlen) - return x - - -def bits2octets(data, order): - z1 = bits2int(data, bit_length(order)) - z2 = z1 - order - - if z2 < 0: - z2 = z1 - - return number_to_string_crop(z2, order) - - -# https://tools.ietf.org/html/rfc6979#section-3.2 -def generate_k(order, secexp, hash_func, data, retry_gen=0, extra_entropy=b""): - """ - Generate the ``k`` value - the nonce for DSA. - - :param int order: order of the DSA generator used in the signature - :param int secexp: secure exponent (private key) in numeric form - :param hash_func: reference to the same hash function used for generating - hash, like :py:class:`hashlib.sha1` - :param bytes data: hash in binary form of the signing data - :param int retry_gen: how many good 'k' values to skip before returning - :param bytes extra_entropy: additional added data in binary form as per - section-3.6 of rfc6979 - :rtype: int - """ - - qlen = bit_length(order) - holen = hash_func().digest_size - rolen = (qlen + 7) // 8 - bx = ( - hmac_compat(number_to_string(secexp, order)), - hmac_compat(bits2octets(data, order)), - hmac_compat(extra_entropy), - ) - - # Step B - v = b"\x01" * holen - - # Step C - k = b"\x00" * holen - - # Step D - - k = hmac.new(k, digestmod=hash_func) - k.update(v + b"\x00") - for i in bx: - k.update(i) - k = k.digest() - - # Step E - v = hmac.new(k, v, hash_func).digest() - - # Step F - k = hmac.new(k, digestmod=hash_func) - k.update(v + b"\x01") - for i in bx: - k.update(i) - k = k.digest() - - # Step G - v = hmac.new(k, v, hash_func).digest() - - # Step H - while True: - # Step H1 - t = b"" - - # Step H2 - while len(t) < rolen: - v = hmac.new(k, v, hash_func).digest() - t += v - - # Step H3 - secret = bits2int(t, qlen) - - if 1 <= secret < order: - if retry_gen <= 0: - return secret - retry_gen -= 1 - - k = hmac.new(k, v + b"\x00", hash_func).digest() - v = hmac.new(k, v, hash_func).digest() diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/ssh.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/ssh.py deleted file mode 100644 index 64e9403..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/ssh.py +++ /dev/null @@ -1,83 +0,0 @@ -import binascii -from . import der -from ._compat import compat26_str, int_to_bytes - -_SSH_ED25519 = b"ssh-ed25519" -_SK_MAGIC = b"openssh-key-v1\0" -_NONE = b"none" - - -def _get_key_type(name): - if name == "Ed25519": - return _SSH_ED25519 - else: - raise ValueError("Unsupported key type") - - -class _Serializer: - def __init__(self): - self.bytes = b"" - - def put_raw(self, val): - self.bytes += val - - def put_u32(self, val): - self.bytes += int_to_bytes(val, length=4, byteorder="big") - - def put_str(self, val): - self.put_u32(len(val)) - self.bytes += val - - def put_pad(self, blklen=8): - padlen = blklen - (len(self.bytes) % blklen) - self.put_raw(bytearray(range(1, 1 + padlen))) - - def encode(self): - return binascii.b2a_base64(compat26_str(self.bytes)) - - def tobytes(self): - return self.bytes - - def topem(self): - return der.topem(self.bytes, "OPENSSH PRIVATE KEY") - - -def serialize_public(name, pub): - serial = _Serializer() - ktype = _get_key_type(name) - serial.put_str(ktype) - serial.put_str(pub) - return b" ".join([ktype, serial.encode()]) - - -def serialize_private(name, pub, priv): - # encode public part - spub = _Serializer() - ktype = _get_key_type(name) - spub.put_str(ktype) - spub.put_str(pub) - - # encode private part - spriv = _Serializer() - checksum = 0 - spriv.put_u32(checksum) - spriv.put_u32(checksum) - spriv.put_raw(spub.tobytes()) - spriv.put_str(priv + pub) - comment = b"" - spriv.put_str(comment) - spriv.put_pad() - - # top-level structure - main = _Serializer() - main.put_raw(_SK_MAGIC) - ciphername = kdfname = _NONE - main.put_str(ciphername) - main.put_str(kdfname) - nokdf = 0 - main.put_u32(nokdf) - nkeys = 1 - main.put_u32(nkeys) - main.put_str(spub.tobytes()) - main.put_str(spriv.tobytes()) - return main.topem() diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_curves.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_curves.py deleted file mode 100644 index 93b6c9b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_curves.py +++ /dev/null @@ -1,361 +0,0 @@ -try: - import unittest2 as unittest -except ImportError: - import unittest - -import base64 -import pytest -from .curves import ( - Curve, - NIST256p, - curves, - UnknownCurveError, - PRIME_FIELD_OID, - curve_by_name, -) -from .ellipticcurve import CurveFp, PointJacobi, CurveEdTw -from . import der -from .util import number_to_string - - -class TestParameterEncoding(unittest.TestCase): - @classmethod - def setUpClass(cls): - # minimal, but with cofactor (excludes seed when compared to - # OpenSSL output) - cls.base64_params = ( - "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////" - "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K" - "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd" - "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1" - "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=" - ) - - def test_from_pem(self): - pem_params = ( - "-----BEGIN EC PARAMETERS-----\n" - "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" - "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" - "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" - "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" - "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" - "-----END EC PARAMETERS-----\n" - ) - curve = Curve.from_pem(pem_params) - - self.assertIs(curve, NIST256p) - - def test_from_pem_with_explicit_when_explicit_disabled(self): - pem_params = ( - "-----BEGIN EC PARAMETERS-----\n" - "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" - "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" - "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" - "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" - "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" - "-----END EC PARAMETERS-----\n" - ) - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_pem(pem_params, ["named_curve"]) - - self.assertIn("explicit curve parameters not", str(e.exception)) - - def test_from_pem_with_named_curve_with_named_curve_disabled(self): - pem_params = ( - "-----BEGIN EC PARAMETERS-----\n" - "BggqhkjOPQMBBw==\n" - "-----END EC PARAMETERS-----\n" - ) - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_pem(pem_params, ["explicit"]) - - self.assertIn("named_curve curve parameters not", str(e.exception)) - - def test_from_pem_with_wrong_header(self): - pem_params = ( - "-----BEGIN PARAMETERS-----\n" - "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" - "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" - "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" - "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" - "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" - "-----END PARAMETERS-----\n" - ) - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_pem(pem_params) - - self.assertIn("PARAMETERS PEM header", str(e.exception)) - - def test_to_pem(self): - pem_params = ( - b"-----BEGIN EC PARAMETERS-----\n" - b"BggqhkjOPQMBBw==\n" - b"-----END EC PARAMETERS-----\n" - ) - encoding = NIST256p.to_pem() - - self.assertEqual(pem_params, encoding) - - def test_compare_with_different_object(self): - self.assertNotEqual(NIST256p, 256) - - def test_named_curve_params_der(self): - encoded = NIST256p.to_der() - - # just the encoding of the NIST256p OID (prime256v1) - self.assertEqual(b"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07", encoded) - - def test_verify_that_default_is_named_curve_der(self): - encoded_default = NIST256p.to_der() - encoded_named = NIST256p.to_der("named_curve") - - self.assertEqual(encoded_default, encoded_named) - - def test_encoding_to_explicit_params(self): - encoded = NIST256p.to_der("explicit") - - self.assertEqual(encoded, bytes(base64.b64decode(self.base64_params))) - - def test_encoding_to_unsupported_type(self): - with self.assertRaises(ValueError) as e: - NIST256p.to_der("unsupported") - - self.assertIn("Only 'named_curve'", str(e.exception)) - - def test_encoding_to_explicit_compressed_params(self): - encoded = NIST256p.to_der("explicit", "compressed") - - compressed_base_point = ( - "MIHAAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" - "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" - "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEIQNrF9Hy4SxCR/i85uVjpEDydwN9" - "gS3rM6D0oTlF2JjClgIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVR" - "AgEB" - ) - - self.assertEqual( - encoded, bytes(base64.b64decode(compressed_base_point)) - ) - - def test_decoding_explicit_from_openssl(self): - # generated with openssl 1.1.1k using - # openssl ecparam -name P-256 -param_enc explicit -out /tmp/file.pem - p256_explicit = ( - "MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" - "/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" - "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+" - "kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK" - "fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz" - "ucrC/GMlUQIBAQ==" - ) - - decoded = Curve.from_der(bytes(base64.b64decode(p256_explicit))) - - self.assertEqual(NIST256p, decoded) - - def test_decoding_well_known_from_explicit_params(self): - curve = Curve.from_der(bytes(base64.b64decode(self.base64_params))) - - self.assertIs(curve, NIST256p) - - def test_decoding_with_incorrect_valid_encodings(self): - with self.assertRaises(ValueError) as e: - Curve.from_der(b"", ["explicitCA"]) - - self.assertIn("Only named_curve", str(e.exception)) - - def test_compare_curves_with_different_generators(self): - curve_fp = CurveFp(23, 1, 7) - base_a = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) - base_b = PointJacobi(curve_fp, 1, 20, 1, 9, generator=True) - - curve_a = Curve("unknown", curve_fp, base_a, None) - curve_b = Curve("unknown", curve_fp, base_b, None) - - self.assertNotEqual(curve_a, curve_b) - - def test_default_encode_for_custom_curve(self): - curve_fp = CurveFp(23, 1, 7) - base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) - - curve = Curve("unknown", curve_fp, base_point, None) - - encoded = curve.to_der() - - decoded = Curve.from_der(encoded) - - self.assertEqual(curve, decoded) - - expected = "MCECAQEwDAYHKoZIzj0BAQIBFzAGBAEBBAEHBAMEDQMCAQk=" - - self.assertEqual(encoded, bytes(base64.b64decode(expected))) - - def test_named_curve_encode_for_custom_curve(self): - curve_fp = CurveFp(23, 1, 7) - base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) - - curve = Curve("unknown", curve_fp, base_point, None) - - with self.assertRaises(UnknownCurveError) as e: - curve.to_der("named_curve") - - self.assertIn("Can't encode curve", str(e.exception)) - - def test_try_decoding_binary_explicit(self): - sect113r1_explicit = ( - "MIGRAgEBMBwGByqGSM49AQIwEQIBcQYJKoZIzj0BAgMCAgEJMDkEDwAwiCUMpufH" - "/mSc6Fgg9wQPAOi+5NPiJgdEGIvg6ccjAxUAEOcjqxTWluZ2h1YVF1b+v4/LSakE" - "HwQAnXNhbzX0qxQH1zViwQ8ApSgwJ3lY7oTRMV7TGIYCDwEAAAAAAAAA2czsijnl" - "bwIBAg==" - ) - - with self.assertRaises(UnknownCurveError) as e: - Curve.from_der(base64.b64decode(sect113r1_explicit)) - - self.assertIn("Characteristic 2 curves unsupported", str(e.exception)) - - def test_decode_malformed_named_curve(self): - bad_der = der.encode_oid(*NIST256p.oid) + der.encode_integer(1) - - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_der(bad_der) - - self.assertIn("Unexpected data after OID", str(e.exception)) - - def test_decode_malformed_explicit_garbage_after_ECParam(self): - bad_der = bytes( - base64.b64decode(self.base64_params) - ) + der.encode_integer(1) - - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_der(bad_der) - - self.assertIn("Unexpected data after ECParameters", str(e.exception)) - - def test_decode_malformed_unknown_version_number(self): - bad_der = der.encode_sequence(der.encode_integer(2)) - - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_der(bad_der) - - self.assertIn("Unknown parameter encoding format", str(e.exception)) - - def test_decode_malformed_unknown_field_type(self): - curve_p = NIST256p.curve.p() - bad_der = der.encode_sequence( - der.encode_integer(1), - der.encode_sequence( - der.encode_oid(1, 2, 3), der.encode_integer(curve_p) - ), - der.encode_sequence( - der.encode_octet_string( - number_to_string(NIST256p.curve.a() % curve_p, curve_p) - ), - der.encode_octet_string( - number_to_string(NIST256p.curve.b(), curve_p) - ), - ), - der.encode_octet_string( - NIST256p.generator.to_bytes("uncompressed") - ), - der.encode_integer(NIST256p.generator.order()), - ) - - with self.assertRaises(UnknownCurveError) as e: - Curve.from_der(bad_der) - - self.assertIn("Unknown field type: (1, 2, 3)", str(e.exception)) - - def test_decode_malformed_garbage_after_prime(self): - curve_p = NIST256p.curve.p() - bad_der = der.encode_sequence( - der.encode_integer(1), - der.encode_sequence( - der.encode_oid(*PRIME_FIELD_OID), - der.encode_integer(curve_p), - der.encode_integer(1), - ), - der.encode_sequence( - der.encode_octet_string( - number_to_string(NIST256p.curve.a() % curve_p, curve_p) - ), - der.encode_octet_string( - number_to_string(NIST256p.curve.b(), curve_p) - ), - ), - der.encode_octet_string( - NIST256p.generator.to_bytes("uncompressed") - ), - der.encode_integer(NIST256p.generator.order()), - ) - - with self.assertRaises(der.UnexpectedDER) as e: - Curve.from_der(bad_der) - - self.assertIn("Prime-p element", str(e.exception)) - - -class TestCurveSearching(unittest.TestCase): - def test_correct_name(self): - c = curve_by_name("NIST256p") - self.assertIs(c, NIST256p) - - def test_openssl_name(self): - c = curve_by_name("prime256v1") - self.assertIs(c, NIST256p) - - def test_unknown_curve(self): - with self.assertRaises(UnknownCurveError) as e: - curve_by_name("foo bar") - - self.assertIn( - "name 'foo bar' unknown, only curves supported: " - "['NIST192p', 'NIST224p'", - str(e.exception), - ) - - def test_with_None_as_parameter(self): - with self.assertRaises(UnknownCurveError) as e: - curve_by_name(None) - - self.assertIn( - "name None unknown, only curves supported: " - "['NIST192p', 'NIST224p'", - str(e.exception), - ) - - -@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) -def test_curve_params_encode_decode_named(curve): - ret = Curve.from_der(curve.to_der("named_curve")) - - assert curve == ret - - -@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) -def test_curve_params_encode_decode_explicit(curve): - if isinstance(curve.curve, CurveEdTw): - with pytest.raises(UnknownCurveError): - curve.to_der("explicit") - else: - ret = Curve.from_der(curve.to_der("explicit")) - - assert curve == ret - - -@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) -def test_curve_params_encode_decode_default(curve): - ret = Curve.from_der(curve.to_der()) - - assert curve == ret - - -@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) -def test_curve_params_encode_decode_explicit_compressed(curve): - if isinstance(curve.curve, CurveEdTw): - with pytest.raises(UnknownCurveError): - curve.to_der("explicit", "compressed") - else: - ret = Curve.from_der(curve.to_der("explicit", "compressed")) - - assert curve == ret diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_der.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_der.py deleted file mode 100644 index b095543..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_der.py +++ /dev/null @@ -1,602 +0,0 @@ -# compatibility with Python 2.6, for that we need unittest2 package, -# which is not available on 3.3 or 3.4 -import warnings -from binascii import hexlify - -try: - import unittest2 as unittest -except ImportError: - import unittest -import sys -import hypothesis.strategies as st -from hypothesis import given, settings -import pytest -from ._compat import str_idx_as_int -from .curves import NIST256p, NIST224p -from .der import ( - remove_integer, - UnexpectedDER, - read_length, - encode_bitstring, - remove_bitstring, - remove_object, - encode_oid, - remove_constructed, - remove_implicit, - remove_octet_string, - remove_sequence, - encode_implicit, -) - - -class TestRemoveInteger(unittest.TestCase): - # DER requires the integers to be 0-padded only if they would be - # interpreted as negative, check if those errors are detected - def test_non_minimal_encoding(self): - with self.assertRaises(UnexpectedDER): - remove_integer(b"\x02\x02\x00\x01") - - def test_negative_with_high_bit_set(self): - with self.assertRaises(UnexpectedDER): - remove_integer(b"\x02\x01\x80") - - def test_minimal_with_high_bit_set(self): - val, rem = remove_integer(b"\x02\x02\x00\x80") - - self.assertEqual(val, 0x80) - self.assertEqual(rem, b"") - - def test_two_zero_bytes_with_high_bit_set(self): - with self.assertRaises(UnexpectedDER): - remove_integer(b"\x02\x03\x00\x00\xff") - - def test_zero_length_integer(self): - with self.assertRaises(UnexpectedDER): - remove_integer(b"\x02\x00") - - def test_empty_string(self): - with self.assertRaises(UnexpectedDER): - remove_integer(b"") - - def test_encoding_of_zero(self): - val, rem = remove_integer(b"\x02\x01\x00") - - self.assertEqual(val, 0) - self.assertEqual(rem, b"") - - def test_encoding_of_127(self): - val, rem = remove_integer(b"\x02\x01\x7f") - - self.assertEqual(val, 127) - self.assertEqual(rem, b"") - - def test_encoding_of_128(self): - val, rem = remove_integer(b"\x02\x02\x00\x80") - - self.assertEqual(val, 128) - self.assertEqual(rem, b"") - - def test_wrong_tag(self): - with self.assertRaises(UnexpectedDER) as e: - remove_integer(b"\x01\x02\x00\x80") - - self.assertIn("wanted type 'integer'", str(e.exception)) - - def test_wrong_length(self): - with self.assertRaises(UnexpectedDER) as e: - remove_integer(b"\x02\x03\x00\x80") - - self.assertIn("Length longer", str(e.exception)) - - -class TestReadLength(unittest.TestCase): - # DER requires the lengths between 0 and 127 to be encoded using the short - # form and lengths above that encoded with minimal number of bytes - # necessary - def test_zero_length(self): - self.assertEqual((0, 1), read_length(b"\x00")) - - def test_two_byte_zero_length(self): - with self.assertRaises(UnexpectedDER): - read_length(b"\x81\x00") - - def test_two_byte_small_length(self): - with self.assertRaises(UnexpectedDER): - read_length(b"\x81\x7f") - - def test_long_form_with_zero_length(self): - with self.assertRaises(UnexpectedDER): - read_length(b"\x80") - - def test_smallest_two_byte_length(self): - self.assertEqual((128, 2), read_length(b"\x81\x80")) - - def test_zero_padded_length(self): - with self.assertRaises(UnexpectedDER): - read_length(b"\x82\x00\x80") - - def test_two_three_byte_length(self): - self.assertEqual((256, 3), read_length(b"\x82\x01\x00")) - - def test_empty_string(self): - with self.assertRaises(UnexpectedDER): - read_length(b"") - - def test_length_overflow(self): - with self.assertRaises(UnexpectedDER): - read_length(b"\x83\x01\x00") - - -class TestEncodeBitstring(unittest.TestCase): - # DER requires BIT STRINGS to include a number of padding bits in the - # encoded byte string, that padding must be between 0 and 7 - - def test_old_call_convention(self): - """This is the old way to use the function.""" - warnings.simplefilter("always") - with pytest.warns(DeprecationWarning) as warns: - der = encode_bitstring(b"\x00\xff") - - self.assertEqual(len(warns), 1) - self.assertIn( - "unused= needs to be specified", warns[0].message.args[0] - ) - - self.assertEqual(der, b"\x03\x02\x00\xff") - - def test_new_call_convention(self): - """This is how it should be called now.""" - # make sure no warnings are raised - with warnings.catch_warnings(): - warnings.simplefilter("error") - der = encode_bitstring(b"\xff", 0) - - self.assertEqual(der, b"\x03\x02\x00\xff") - - def test_implicit_unused_bits(self): - """ - Writing bit string with already included the number of unused bits. - """ - # make sure no warnings are raised - with warnings.catch_warnings(): - warnings.simplefilter("error") - der = encode_bitstring(b"\x00\xff", None) - - self.assertEqual(der, b"\x03\x02\x00\xff") - - def test_explicit_unused_bits(self): - der = encode_bitstring(b"\xff\xf0", 4) - - self.assertEqual(der, b"\x03\x03\x04\xff\xf0") - - def test_empty_string(self): - self.assertEqual(encode_bitstring(b"", 0), b"\x03\x01\x00") - - def test_invalid_unused_count(self): - with self.assertRaises(ValueError): - encode_bitstring(b"\xff\x00", 8) - - def test_invalid_unused_with_empty_string(self): - with self.assertRaises(ValueError): - encode_bitstring(b"", 1) - - def test_non_zero_padding_bits(self): - with self.assertRaises(ValueError): - encode_bitstring(b"\xff", 2) - - -class TestRemoveBitstring(unittest.TestCase): - def test_old_call_convention(self): - """This is the old way to call the function.""" - warnings.simplefilter("always") - with pytest.warns(DeprecationWarning) as warns: - bits, rest = remove_bitstring(b"\x03\x02\x00\xff") - - self.assertEqual(len(warns), 1) - self.assertIn( - "expect_unused= needs to be specified", warns[0].message.args[0] - ) - - self.assertEqual(bits, b"\x00\xff") - self.assertEqual(rest, b"") - - def test_new_call_convention(self): - # make sure no warnings are raised - with warnings.catch_warnings(): - warnings.simplefilter("error") - bits, rest = remove_bitstring(b"\x03\x02\x00\xff", 0) - - self.assertEqual(bits, b"\xff") - self.assertEqual(rest, b"") - - def test_implicit_unexpected_unused(self): - # make sure no warnings are raised - with warnings.catch_warnings(): - warnings.simplefilter("error") - bits, rest = remove_bitstring(b"\x03\x02\x00\xff", None) - - self.assertEqual(bits, (b"\xff", 0)) - self.assertEqual(rest, b"") - - def test_with_padding(self): - ret, rest = remove_bitstring(b"\x03\x02\x04\xf0", None) - - self.assertEqual(ret, (b"\xf0", 4)) - self.assertEqual(rest, b"") - - def test_not_a_bitstring(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x02\x02\x00\xff", None) - - def test_empty_encoding(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03\x00", None) - - def test_empty_string(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"", None) - - def test_no_length(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03", None) - - def test_unexpected_number_of_unused_bits(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03\x02\x00\xff", 1) - - def test_invalid_encoding_of_unused_bits(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03\x03\x08\xff\x00", None) - - def test_invalid_encoding_of_empty_string(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03\x01\x01", None) - - def test_invalid_padding_bits(self): - with self.assertRaises(UnexpectedDER): - remove_bitstring(b"\x03\x02\x01\xff", None) - - -class TestStrIdxAsInt(unittest.TestCase): - def test_str(self): - self.assertEqual(115, str_idx_as_int("str", 0)) - - def test_bytes(self): - self.assertEqual(115, str_idx_as_int(b"str", 0)) - - def test_bytearray(self): - self.assertEqual(115, str_idx_as_int(bytearray(b"str"), 0)) - - -class TestEncodeOid(unittest.TestCase): - def test_pub_key_oid(self): - oid_ecPublicKey = encode_oid(1, 2, 840, 10045, 2, 1) - self.assertEqual(hexlify(oid_ecPublicKey), b"06072a8648ce3d0201") - - def test_nist224p_oid(self): - self.assertEqual(hexlify(NIST224p.encoded_oid), b"06052b81040021") - - def test_nist256p_oid(self): - self.assertEqual( - hexlify(NIST256p.encoded_oid), b"06082a8648ce3d030107" - ) - - def test_large_second_subid(self): - # from X.690, section 8.19.5 - oid = encode_oid(2, 999, 3) - self.assertEqual(oid, b"\x06\x03\x88\x37\x03") - - def test_with_two_subids(self): - oid = encode_oid(2, 999) - self.assertEqual(oid, b"\x06\x02\x88\x37") - - def test_zero_zero(self): - oid = encode_oid(0, 0) - self.assertEqual(oid, b"\x06\x01\x00") - - def test_with_wrong_types(self): - with self.assertRaises((TypeError, AssertionError)): - encode_oid(0, None) - - def test_with_small_first_large_second(self): - with self.assertRaises(AssertionError): - encode_oid(1, 40) - - def test_small_first_max_second(self): - oid = encode_oid(1, 39) - self.assertEqual(oid, b"\x06\x01\x4f") - - def test_with_invalid_first(self): - with self.assertRaises(AssertionError): - encode_oid(3, 39) - - -class TestRemoveObject(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.oid_ecPublicKey = encode_oid(1, 2, 840, 10045, 2, 1) - - def test_pub_key_oid(self): - oid, rest = remove_object(self.oid_ecPublicKey) - self.assertEqual(rest, b"") - self.assertEqual(oid, (1, 2, 840, 10045, 2, 1)) - - def test_with_extra_bytes(self): - oid, rest = remove_object(self.oid_ecPublicKey + b"more") - self.assertEqual(rest, b"more") - self.assertEqual(oid, (1, 2, 840, 10045, 2, 1)) - - def test_with_large_second_subid(self): - # from X.690, section 8.19.5 - oid, rest = remove_object(b"\x06\x03\x88\x37\x03") - self.assertEqual(rest, b"") - self.assertEqual(oid, (2, 999, 3)) - - def test_with_padded_first_subid(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x02\x80\x00") - - def test_with_padded_second_subid(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x04\x88\x37\x80\x01") - - def test_with_missing_last_byte_of_multi_byte(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x03\x88\x37\x83") - - def test_with_two_subids(self): - oid, rest = remove_object(b"\x06\x02\x88\x37") - self.assertEqual(rest, b"") - self.assertEqual(oid, (2, 999)) - - def test_zero_zero(self): - oid, rest = remove_object(b"\x06\x01\x00") - self.assertEqual(rest, b"") - self.assertEqual(oid, (0, 0)) - - def test_empty_string(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"") - - def test_missing_length(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06") - - def test_empty_oid(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x00") - - def test_empty_oid_overflow(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x01") - - def test_with_wrong_type(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x04\x02\x88\x37") - - def test_with_too_long_length(self): - with self.assertRaises(UnexpectedDER): - remove_object(b"\x06\x03\x88\x37") - - -class TestRemoveConstructed(unittest.TestCase): - def test_simple(self): - data = b"\xa1\x02\xff\xaa" - - tag, body, rest = remove_constructed(data) - - self.assertEqual(tag, 0x01) - self.assertEqual(body, b"\xff\xaa") - self.assertEqual(rest, b"") - - def test_with_malformed_tag(self): - data = b"\x01\x02\xff\xaa" - - with self.assertRaises(UnexpectedDER) as e: - remove_constructed(data) - - self.assertIn("constructed tag", str(e.exception)) - - -class TestRemoveImplicit(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.exp_tag = 6 - cls.exp_data = b"\x0a\x0b" - # data with application tag class - cls.data_application = b"\x46\x02\x0a\x0b" - # data with context-specific tag class - cls.data_context_specific = b"\x86\x02\x0a\x0b" - # data with private tag class - cls.data_private = b"\xc6\x02\x0a\x0b" - - def test_simple(self): - tag, body, rest = remove_implicit(self.data_context_specific) - - self.assertEqual(tag, self.exp_tag) - self.assertEqual(body, self.exp_data) - self.assertEqual(rest, b"") - - def test_wrong_expected_class(self): - with self.assertRaises(ValueError) as e: - remove_implicit(self.data_context_specific, "foobar") - - self.assertIn("invalid `exp_class` value", str(e.exception)) - - def test_with_wrong_class(self): - with self.assertRaises(UnexpectedDER) as e: - remove_implicit(self.data_application) - - self.assertIn( - "wanted class context-specific, got 0x46 tag", str(e.exception) - ) - - def test_with_application_class(self): - tag, body, rest = remove_implicit(self.data_application, "application") - - self.assertEqual(tag, self.exp_tag) - self.assertEqual(body, self.exp_data) - self.assertEqual(rest, b"") - - def test_with_private_class(self): - tag, body, rest = remove_implicit(self.data_private, "private") - - self.assertEqual(tag, self.exp_tag) - self.assertEqual(body, self.exp_data) - self.assertEqual(rest, b"") - - def test_with_data_following(self): - extra_data = b"\x00\x01" - - tag, body, rest = remove_implicit( - self.data_context_specific + extra_data - ) - - self.assertEqual(tag, self.exp_tag) - self.assertEqual(body, self.exp_data) - self.assertEqual(rest, extra_data) - - def test_with_constructed(self): - data = b"\xa6\x02\x0a\x0b" - - with self.assertRaises(UnexpectedDER) as e: - remove_implicit(data) - - self.assertIn("wanted type primitive, got 0xa6 tag", str(e.exception)) - - def test_encode_decode(self): - data = b"some longish string" - - tag, body, rest = remove_implicit( - encode_implicit(6, data, "application"), "application" - ) - - self.assertEqual(tag, 6) - self.assertEqual(body, data) - self.assertEqual(rest, b"") - - -class TestEncodeImplicit(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.data = b"\x0a\x0b" - # data with application tag class - cls.data_application = b"\x46\x02\x0a\x0b" - # data with context-specific tag class - cls.data_context_specific = b"\x86\x02\x0a\x0b" - # data with private tag class - cls.data_private = b"\xc6\x02\x0a\x0b" - - def test_encode_with_default_class(self): - ret = encode_implicit(6, self.data) - - self.assertEqual(ret, self.data_context_specific) - - def test_encode_with_application_class(self): - ret = encode_implicit(6, self.data, "application") - - self.assertEqual(ret, self.data_application) - - def test_encode_with_context_specific_class(self): - ret = encode_implicit(6, self.data, "context-specific") - - self.assertEqual(ret, self.data_context_specific) - - def test_encode_with_private_class(self): - ret = encode_implicit(6, self.data, "private") - - self.assertEqual(ret, self.data_private) - - def test_encode_with_invalid_class(self): - with self.assertRaises(ValueError) as e: - encode_implicit(6, self.data, "foobar") - - self.assertIn("invalid tag class", str(e.exception)) - - def test_encode_with_too_large_tag(self): - with self.assertRaises(ValueError) as e: - encode_implicit(32, self.data) - - self.assertIn("Long tags not supported", str(e.exception)) - - -class TestRemoveOctetString(unittest.TestCase): - def test_simple(self): - data = b"\x04\x03\xaa\xbb\xcc" - body, rest = remove_octet_string(data) - self.assertEqual(body, b"\xaa\xbb\xcc") - self.assertEqual(rest, b"") - - def test_with_malformed_tag(self): - data = b"\x03\x03\xaa\xbb\xcc" - with self.assertRaises(UnexpectedDER) as e: - remove_octet_string(data) - - self.assertIn("octetstring", str(e.exception)) - - -class TestRemoveSequence(unittest.TestCase): - def test_simple(self): - data = b"\x30\x02\xff\xaa" - body, rest = remove_sequence(data) - self.assertEqual(body, b"\xff\xaa") - self.assertEqual(rest, b"") - - def test_with_empty_string(self): - with self.assertRaises(UnexpectedDER) as e: - remove_sequence(b"") - - self.assertIn("Empty string", str(e.exception)) - - def test_with_wrong_tag(self): - data = b"\x20\x02\xff\xaa" - - with self.assertRaises(UnexpectedDER) as e: - remove_sequence(data) - - self.assertIn("wanted type 'sequence'", str(e.exception)) - - def test_with_wrong_length(self): - data = b"\x30\x03\xff\xaa" - - with self.assertRaises(UnexpectedDER) as e: - remove_sequence(data) - - self.assertIn("Length longer", str(e.exception)) - - -@st.composite -def st_oid(draw, max_value=2**512, max_size=50): - """ - Hypothesis strategy that returns valid OBJECT IDENTIFIERs as tuples - - :param max_value: maximum value of any single sub-identifier - :param max_size: maximum length of the generated OID - """ - first = draw(st.integers(min_value=0, max_value=2)) - if first < 2: - second = draw(st.integers(min_value=0, max_value=39)) - else: - second = draw(st.integers(min_value=0, max_value=max_value)) - rest = draw( - st.lists( - st.integers(min_value=0, max_value=max_value), max_size=max_size - ) - ) - return (first, second) + tuple(rest) - - -HYP_SETTINGS = {} - - -if "--fast" in sys.argv: # pragma: no cover - HYP_SETTINGS["max_examples"] = 2 - - -@settings(**HYP_SETTINGS) -@given(st_oid()) -def test_oids(ids): - encoded_oid = encode_oid(*ids) - decoded_oid, rest = remove_object(encoded_oid) - assert rest == b"" - assert decoded_oid == ids diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdh.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdh.py deleted file mode 100644 index cb22580..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdh.py +++ /dev/null @@ -1,449 +0,0 @@ -import os -import sys -import shutil -import subprocess -import pytest -from binascii import unhexlify - -try: - import unittest2 as unittest -except ImportError: - import unittest - -from .curves import ( - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - BRAINPOOLP160r1, - SECP112r2, - SECP128r1, -) -from .curves import curves -from .ecdh import ( - ECDH, - InvalidCurveError, - InvalidSharedSecretError, - NoKeyError, - NoCurveError, -) -from .keys import SigningKey, VerifyingKey -from .ellipticcurve import CurveEdTw - - -if "--fast" in sys.argv: # pragma: no cover - curves = [SECP112r2, SECP128r1] - - -@pytest.mark.parametrize( - "vcurve", - curves, - ids=[curve.name for curve in curves], -) -def test_ecdh_each(vcurve): - if isinstance(vcurve.curve, CurveEdTw): - pytest.skip("ECDH is not supported for Edwards curves") - ecdh1 = ECDH(curve=vcurve) - ecdh2 = ECDH(curve=vcurve) - - ecdh2.generate_private_key() - ecdh1.load_received_public_key(ecdh2.get_public_key()) - ecdh2.load_received_public_key(ecdh1.generate_private_key()) - - secret1 = ecdh1.generate_sharedsecret_bytes() - secret2 = ecdh2.generate_sharedsecret_bytes() - assert secret1 == secret2 - - -def test_ecdh_both_keys_present(): - key1 = SigningKey.generate(BRAINPOOLP160r1) - key2 = SigningKey.generate(BRAINPOOLP160r1) - - ecdh1 = ECDH(BRAINPOOLP160r1, key1, key2.verifying_key) - ecdh2 = ECDH(private_key=key2, public_key=key1.verifying_key) - - secret1 = ecdh1.generate_sharedsecret_bytes() - secret2 = ecdh2.generate_sharedsecret_bytes() - - assert secret1 == secret2 - - -def test_ecdh_no_public_key(): - ecdh1 = ECDH(curve=NIST192p) - - with pytest.raises(NoKeyError): - ecdh1.generate_sharedsecret_bytes() - - ecdh1.generate_private_key() - - with pytest.raises(NoKeyError): - ecdh1.generate_sharedsecret_bytes() - - -class TestECDH(unittest.TestCase): - def test_load_key_from_wrong_curve(self): - ecdh1 = ECDH() - ecdh1.set_curve(NIST192p) - - key1 = SigningKey.generate(BRAINPOOLP160r1) - - with self.assertRaises(InvalidCurveError) as e: - ecdh1.load_private_key(key1) - - self.assertIn("Curve mismatch", str(e.exception)) - - def test_generate_without_curve(self): - ecdh1 = ECDH() - - with self.assertRaises(NoCurveError) as e: - ecdh1.generate_private_key() - - self.assertIn("Curve must be set", str(e.exception)) - - def test_load_bytes_without_curve_set(self): - ecdh1 = ECDH() - - with self.assertRaises(NoCurveError) as e: - ecdh1.load_private_key_bytes(b"\x01" * 32) - - self.assertIn("Curve must be set", str(e.exception)) - - def test_set_curve_from_received_public_key(self): - ecdh1 = ECDH() - - key1 = SigningKey.generate(BRAINPOOLP160r1) - - ecdh1.load_received_public_key(key1.verifying_key) - - self.assertEqual(ecdh1.curve, BRAINPOOLP160r1) - - -def test_ecdh_wrong_public_key_curve(): - ecdh1 = ECDH(curve=NIST192p) - ecdh1.generate_private_key() - ecdh2 = ECDH(curve=NIST256p) - ecdh2.generate_private_key() - - with pytest.raises(InvalidCurveError): - ecdh1.load_received_public_key(ecdh2.get_public_key()) - - with pytest.raises(InvalidCurveError): - ecdh2.load_received_public_key(ecdh1.get_public_key()) - - ecdh1.public_key = ecdh2.get_public_key() - ecdh2.public_key = ecdh1.get_public_key() - - with pytest.raises(InvalidCurveError): - ecdh1.generate_sharedsecret_bytes() - - with pytest.raises(InvalidCurveError): - ecdh2.generate_sharedsecret_bytes() - - -def test_ecdh_invalid_shared_secret_curve(): - ecdh1 = ECDH(curve=NIST256p) - ecdh1.generate_private_key() - - ecdh1.load_received_public_key( - SigningKey.generate(NIST256p).get_verifying_key() - ) - - ecdh1.private_key.privkey.secret_multiplier = ecdh1.private_key.curve.order - - with pytest.raises(InvalidSharedSecretError): - ecdh1.generate_sharedsecret_bytes() - - -# https://github.com/scogliani/ecc-test-vectors/blob/master/ecdh_kat/secp192r1.txt -# https://github.com/scogliani/ecc-test-vectors/blob/master/ecdh_kat/secp256r1.txt -# https://github.com/coruus/nist-testvectors/blob/master/csrc.nist.gov/groups/STM/cavp/documents/components/ecccdhtestvectors/KAS_ECC_CDH_PrimitiveTest.txt -@pytest.mark.parametrize( - "curve,privatekey,pubkey,secret", - [ - pytest.param( - NIST192p, - "f17d3fea367b74d340851ca4270dcb24c271f445bed9d527", - "42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0" - "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523", - "803d8ab2e5b6e6fca715737c3a82f7ce3c783124f6d51cd0", - id="NIST192p-1", - ), - pytest.param( - NIST192p, - "56e853349d96fe4c442448dacb7cf92bb7a95dcf574a9bd5", - "deb5712fa027ac8d2f22c455ccb73a91e17b6512b5e030e7" - "7e2690a02cc9b28708431a29fb54b87b1f0c14e011ac2125", - "c208847568b98835d7312cef1f97f7aa298283152313c29d", - id="NIST192p-2", - ), - pytest.param( - NIST192p, - "c6ef61fe12e80bf56f2d3f7d0bb757394519906d55500949", - "4edaa8efc5a0f40f843663ec5815e7762dddc008e663c20f" - "0a9f8dc67a3e60ef6d64b522185d03df1fc0adfd42478279", - "87229107047a3b611920d6e3b2c0c89bea4f49412260b8dd", - id="NIST192p-3", - ), - pytest.param( - NIST192p, - "e6747b9c23ba7044f38ff7e62c35e4038920f5a0163d3cda", - "8887c276edeed3e9e866b46d58d895c73fbd80b63e382e88" - "04c5097ba6645e16206cfb70f7052655947dd44a17f1f9d5", - "eec0bed8fc55e1feddc82158fd6dc0d48a4d796aaf47d46c", - id="NIST192p-4", - ), - pytest.param( - NIST192p, - "beabedd0154a1afcfc85d52181c10f5eb47adc51f655047d", - "0d045f30254adc1fcefa8a5b1f31bf4e739dd327cd18d594" - "542c314e41427c08278a08ce8d7305f3b5b849c72d8aff73", - "716e743b1b37a2cd8479f0a3d5a74c10ba2599be18d7e2f4", - id="NIST192p-5", - ), - pytest.param( - NIST192p, - "cf70354226667321d6e2baf40999e2fd74c7a0f793fa8699", - "fb35ca20d2e96665c51b98e8f6eb3d79113508d8bccd4516" - "368eec0d5bfb847721df6aaff0e5d48c444f74bf9cd8a5a7", - "f67053b934459985a315cb017bf0302891798d45d0e19508", - id="NIST192p-6", - ), - pytest.param( - NIST224p, - "8346a60fc6f293ca5a0d2af68ba71d1dd389e5e40837942df3e43cbd", - "af33cd0629bc7e996320a3f40368f74de8704fa37b8fab69abaae280" - "882092ccbba7930f419a8a4f9bb16978bbc3838729992559a6f2e2d7", - "7d96f9a3bd3c05cf5cc37feb8b9d5209d5c2597464dec3e9983743e8", - id="NIST224p", - ), - pytest.param( - NIST256p, - "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", - "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" - "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", - "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b", - id="NIST256p-1", - ), - pytest.param( - NIST256p, - "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5", - "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae" - "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3", - "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67", - id="NIST256p-2", - ), - pytest.param( - NIST256p, - "1accfaf1b97712b85a6f54b148985a1bdc4c9bec0bd258cad4b3d603f49f32c8", - "a2339c12d4a03c33546de533268b4ad667debf458b464d77443636440ee7fec3" - "ef48a3ab26e20220bcda2c1851076839dae88eae962869a497bf73cb66faf536", - "2d457b78b4614132477618a5b077965ec90730a8c81a1c75d6d4ec68005d67ec", - id="NIST256p-3", - ), - pytest.param( - NIST256p, - "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d", - "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed" - "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4", - "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024", - id="NIST256p-4", - ), - pytest.param( - NIST256p, - "59137e38152350b195c9718d39673d519838055ad908dd4757152fd8255c09bf", - "41192d2813e79561e6a1d6f53c8bc1a433a199c835e141b05a74a97b0faeb922" - "1af98cc45e98a7e041b01cf35f462b7562281351c8ebf3ffa02e33a0722a1328", - "19d44c8d63e8e8dd12c22a87b8cd4ece27acdde04dbf47f7f27537a6999a8e62", - id="NIST256p-5", - ), - pytest.param( - NIST256p, - "f5f8e0174610a661277979b58ce5c90fee6c9b3bb346a90a7196255e40b132ef", - "33e82092a0f1fb38f5649d5867fba28b503172b7035574bf8e5b7100a3052792" - "f2cf6b601e0a05945e335550bf648d782f46186c772c0f20d3cd0d6b8ca14b2f", - "664e45d5bba4ac931cd65d52017e4be9b19a515f669bea4703542a2c525cd3d3", - id="NIST256p-6", - ), - pytest.param( - NIST384p, - "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b1" - "5618b6818a661774ad463b205da88cf699ab4d43c9cf98a1", - "a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e76459" - "2efda27fe7513272734466b400091adbf2d68c58e0c50066" - "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b66" - "1efedf243451915ed0905a32b060992b468c64766fc8437a", - "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f4" - "0ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1", - id="NIST384p", - ), - pytest.param( - NIST521p, - "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4ea" - "c6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47", - "00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a949034085433" - "4b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d" - "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83" - "bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676", - "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e1366" - "72d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831", - id="NIST521p", - ), - ], -) -def test_ecdh_NIST(curve, privatekey, pubkey, secret): - ecdh = ECDH(curve=curve) - ecdh.load_private_key_bytes(unhexlify(privatekey)) - ecdh.load_received_public_key_bytes(unhexlify(pubkey)) - - sharedsecret = ecdh.generate_sharedsecret_bytes() - - assert sharedsecret == unhexlify(secret) - - -pem_local_private_key = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" - "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" - "bA==\n" - "-----END EC PRIVATE KEY-----\n" -) -der_local_private_key = ( - "305f02010104185ec8420bd6ef9252a942e989043ca29f561fa525770eb1c5a00a06082a864" - "8ce3d030101a13403320004b88177d084ef17f5e45639408028360f9f59b4a4d7264e62da06" - "51dce47a35a4c5b45cf51593423a8b557b9c2099f36c" -) -pem_remote_public_key = ( - "-----BEGIN PUBLIC KEY-----\n" - "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEuIF30ITvF/XkVjlAgCg2D59ZtKTX\n" - "Jk5i2gZR3OR6NaTFtFz1FZNCOotVe5wgmfNs\n" - "-----END PUBLIC KEY-----\n" -) -der_remote_public_key = ( - "3049301306072a8648ce3d020106082a8648ce3d03010103320004b88177d084ef17f5e4563" - "9408028360f9f59b4a4d7264e62da0651dce47a35a4c5b45cf51593423a8b557b9c2099f36c" -) -gshared_secret = "8f457e34982478d1c34b9cd2d0c15911b72dd60d869e2cea" - - -def test_ecdh_pem(): - ecdh = ECDH() - ecdh.load_private_key_pem(pem_local_private_key) - ecdh.load_received_public_key_pem(pem_remote_public_key) - - sharedsecret = ecdh.generate_sharedsecret_bytes() - - assert sharedsecret == unhexlify(gshared_secret) - - -def test_ecdh_der(): - ecdh = ECDH() - ecdh.load_private_key_der(unhexlify(der_local_private_key)) - ecdh.load_received_public_key_der(unhexlify(der_remote_public_key)) - - sharedsecret = ecdh.generate_sharedsecret_bytes() - - assert sharedsecret == unhexlify(gshared_secret) - - -# Exception classes used by run_openssl. -class RunOpenSslError(Exception): - pass - - -def run_openssl(cmd): - OPENSSL = "openssl" - p = subprocess.Popen( - [OPENSSL] + cmd.split(), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - stdout, ignored = p.communicate() - if p.returncode != 0: - raise RunOpenSslError( - "cmd '%s %s' failed: rc=%s, stdout/err was %s" - % (OPENSSL, cmd, p.returncode, stdout) - ) - return stdout.decode() - - -OPENSSL_SUPPORTED_CURVES = set( - c.split(":")[0].strip() - for c in run_openssl("ecparam -list_curves").split("\n") -) - - -@pytest.mark.slow -@pytest.mark.parametrize( - "vcurve", - curves, - ids=[curve.name for curve in curves], -) -def test_ecdh_with_openssl(vcurve): - if isinstance(vcurve.curve, CurveEdTw): - pytest.skip("Edwards curves are not supported for ECDH") - - assert vcurve.openssl_name - - if vcurve.openssl_name not in OPENSSL_SUPPORTED_CURVES: - pytest.skip("system openssl does not support " + vcurve.openssl_name) - - try: - hlp = run_openssl("pkeyutl -help") - if hlp.find("-derive") == 0: # pragma: no cover - pytest.skip("system openssl does not support `pkeyutl -derive`") - except RunOpenSslError: # pragma: no cover - pytest.skip("system openssl could not be executed") - - if os.path.isdir("t"): # pragma: no branch - shutil.rmtree("t") - os.mkdir("t") - run_openssl( - "ecparam -name %s -genkey -out t/privkey1.pem" % vcurve.openssl_name - ) - run_openssl( - "ecparam -name %s -genkey -out t/privkey2.pem" % vcurve.openssl_name - ) - run_openssl("ec -in t/privkey1.pem -pubout -out t/pubkey1.pem") - - ecdh1 = ECDH(curve=vcurve) - ecdh2 = ECDH(curve=vcurve) - with open("t/privkey1.pem") as e: - key = e.read() - ecdh1.load_private_key_pem(key) - with open("t/privkey2.pem") as e: - key = e.read() - ecdh2.load_private_key_pem(key) - - with open("t/pubkey1.pem") as e: - key = e.read() - vk1 = VerifyingKey.from_pem(key) - assert vk1.to_string() == ecdh1.get_public_key().to_string() - vk2 = ecdh2.get_public_key() - with open("t/pubkey2.pem", "wb") as e: - e.write(vk2.to_pem()) - - ecdh1.load_received_public_key(vk2) - ecdh2.load_received_public_key(vk1) - secret1 = ecdh1.generate_sharedsecret_bytes() - secret2 = ecdh2.generate_sharedsecret_bytes() - - assert secret1 == secret2 - - run_openssl( - "pkeyutl -derive -inkey t/privkey1.pem -peerkey t/pubkey2.pem -out t/secret1" - ) - run_openssl( - "pkeyutl -derive -inkey t/privkey2.pem -peerkey t/pubkey1.pem -out t/secret2" - ) - - with open("t/secret1", "rb") as e: - ssl_secret1 = e.read() - with open("t/secret1", "rb") as e: - ssl_secret2 = e.read() - - assert len(ssl_secret1) == vk1.curve.verifying_key_length // 2 - assert len(secret1) == vk1.curve.verifying_key_length // 2 - - assert ssl_secret1 == ssl_secret2 - assert secret1 == ssl_secret1 diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdsa.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdsa.py deleted file mode 100644 index c1e2582..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ecdsa.py +++ /dev/null @@ -1,694 +0,0 @@ -from __future__ import print_function -import sys -import hypothesis.strategies as st -from hypothesis import given, settings, note, example - -try: - import unittest2 as unittest -except ImportError: - import unittest -import pytest -from .ecdsa import ( - Private_key, - Public_key, - Signature, - generator_192, - digest_integer, - ellipticcurve, - point_is_valid, - generator_224, - generator_256, - generator_384, - generator_521, - generator_secp256k1, - curve_192, - InvalidPointError, - curve_112r2, - generator_112r2, - int_to_string, -) -from .ellipticcurve import Point - - -HYP_SETTINGS = {} -# old hypothesis doesn't have the "deadline" setting -if sys.version_info > (2, 7): # pragma: no branch - # SEC521p is slow, allow long execution for it - HYP_SETTINGS["deadline"] = 5000 - - -class TestP192FromX9_62(unittest.TestCase): - """Check test vectors from X9.62""" - - @classmethod - def setUpClass(cls): - cls.d = 651056770906015076056810763456358567190100156695615665659 - cls.Q = cls.d * generator_192 - cls.k = 6140507067065001063065065565667405560006161556565665656654 - cls.R = cls.k * generator_192 - - cls.msg = 968236873715988614170569073515315707566766479517 - cls.pubk = Public_key(generator_192, generator_192 * cls.d) - cls.privk = Private_key(cls.pubk, cls.d) - cls.sig = cls.privk.sign(cls.msg, cls.k) - - def test_point_multiplication(self): - assert self.Q.x() == 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5 - - def test_point_multiplication_2(self): - assert self.R.x() == 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD - assert self.R.y() == 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - - def test_mult_and_addition(self): - u1 = 2563697409189434185194736134579731015366492496392189760599 - u2 = 6266643813348617967186477710235785849136406323338782220568 - temp = u1 * generator_192 + u2 * self.Q - assert temp.x() == 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD - assert temp.y() == 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - - def test_signature(self): - r, s = self.sig.r, self.sig.s - assert r == 3342403536405981729393488334694600415596881826869351677613 - assert s == 5735822328888155254683894997897571951568553642892029982342 - - def test_verification(self): - assert self.pubk.verifies(self.msg, self.sig) - - def test_rejection(self): - assert not self.pubk.verifies(self.msg - 1, self.sig) - - def test_verification_with_regular_point(self): - pubk = Public_key( - Point( - generator_192.curve(), - generator_192.x(), - generator_192.y(), - generator_192.order(), - ), - self.pubk.point, - ) - - assert pubk.verifies(self.msg, self.sig) - - -class TestPublicKey(unittest.TestCase): - def test_equality_public_keys(self): - gen = generator_192 - x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point = ellipticcurve.Point(gen.curve(), x, y) - pub_key1 = Public_key(gen, point) - pub_key2 = Public_key(gen, point) - self.assertEqual(pub_key1, pub_key2) - - def test_inequality_public_key(self): - gen = generator_192 - x1 = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y1 = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point1 = ellipticcurve.Point(gen.curve(), x1, y1) - - x2 = 0x6A223D00BD22C52833409A163E057E5B5DA1DEF2A197DD15 - y2 = 0x7B482604199367F1F303F9EF627F922F97023E90EAE08ABF - point2 = ellipticcurve.Point(gen.curve(), x2, y2) - - pub_key1 = Public_key(gen, point1) - pub_key2 = Public_key(gen, point2) - self.assertNotEqual(pub_key1, pub_key2) - - def test_inequality_different_curves(self): - gen = generator_192 - x1 = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y1 = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point1 = ellipticcurve.Point(gen.curve(), x1, y1) - - x2 = 0x722BA0FB6B8FC8898A4C6AB49E66 - y2 = 0x2B7344BB57A7ABC8CA0F1A398C7D - point2 = ellipticcurve.Point(generator_112r2.curve(), x2, y2) - - pub_key1 = Public_key(gen, point1) - pub_key2 = Public_key(generator_112r2, point2) - self.assertNotEqual(pub_key1, pub_key2) - - def test_inequality_public_key_not_implemented(self): - gen = generator_192 - x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point = ellipticcurve.Point(gen.curve(), x, y) - pub_key = Public_key(gen, point) - self.assertNotEqual(pub_key, None) - - def test_public_key_with_generator_without_order(self): - gen = ellipticcurve.PointJacobi( - generator_192.curve(), generator_192.x(), generator_192.y(), 1 - ) - - x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point = ellipticcurve.Point(gen.curve(), x, y) - - with self.assertRaises(InvalidPointError) as e: - Public_key(gen, point) - - self.assertIn("Generator point must have order", str(e.exception)) - - def test_public_point_on_curve_not_scalar_multiple_of_base_point(self): - x = 2 - y = 0xBE6AA4938EF7CFE6FE29595B6B00 - # we need a curve with cofactor != 1 - point = ellipticcurve.PointJacobi(curve_112r2, x, y, 1) - - self.assertTrue(curve_112r2.contains_point(x, y)) - - with self.assertRaises(InvalidPointError) as e: - Public_key(generator_112r2, point) - - self.assertIn("Generator point order", str(e.exception)) - - def test_point_is_valid_with_not_scalar_multiple_of_base_point(self): - x = 2 - y = 0xBE6AA4938EF7CFE6FE29595B6B00 - - self.assertFalse(point_is_valid(generator_112r2, x, y)) - - # the tests to verify the extensiveness of tests in ecdsa.ecdsa - # if PointJacobi gets modified to calculate the x and y mod p the tests - # below will need to use a fake/mock object - def test_invalid_point_x_negative(self): - pt = ellipticcurve.PointJacobi(curve_192, -1, 0, 1) - - with self.assertRaises(InvalidPointError) as e: - Public_key(generator_192, pt) - - self.assertIn("The public point has x or y", str(e.exception)) - - def test_invalid_point_x_equal_p(self): - pt = ellipticcurve.PointJacobi(curve_192, curve_192.p(), 0, 1) - - with self.assertRaises(InvalidPointError) as e: - Public_key(generator_192, pt) - - self.assertIn("The public point has x or y", str(e.exception)) - - def test_invalid_point_y_negative(self): - pt = ellipticcurve.PointJacobi(curve_192, 0, -1, 1) - - with self.assertRaises(InvalidPointError) as e: - Public_key(generator_192, pt) - - self.assertIn("The public point has x or y", str(e.exception)) - - def test_invalid_point_y_equal_p(self): - pt = ellipticcurve.PointJacobi(curve_192, 0, curve_192.p(), 1) - - with self.assertRaises(InvalidPointError) as e: - Public_key(generator_192, pt) - - self.assertIn("The public point has x or y", str(e.exception)) - - -class TestPublicKeyVerifies(unittest.TestCase): - # test all the different ways that a signature can be publicly invalid - @classmethod - def setUpClass(cls): - gen = generator_192 - x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point = ellipticcurve.Point(gen.curve(), x, y) - - cls.pub_key = Public_key(gen, point) - - def test_sig_with_r_zero(self): - sig = Signature(0, 1) - - self.assertFalse(self.pub_key.verifies(1, sig)) - - def test_sig_with_r_order(self): - sig = Signature(generator_192.order(), 1) - - self.assertFalse(self.pub_key.verifies(1, sig)) - - def test_sig_with_s_zero(self): - sig = Signature(1, 0) - - self.assertFalse(self.pub_key.verifies(1, sig)) - - def test_sig_with_s_order(self): - sig = Signature(1, generator_192.order()) - - self.assertFalse(self.pub_key.verifies(1, sig)) - - -class TestPrivateKey(unittest.TestCase): - @classmethod - def setUpClass(cls): - gen = generator_192 - x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 - y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F - point = ellipticcurve.Point(gen.curve(), x, y) - cls.pub_key = Public_key(gen, point) - - def test_equality_private_keys(self): - pr_key1 = Private_key(self.pub_key, 100) - pr_key2 = Private_key(self.pub_key, 100) - self.assertEqual(pr_key1, pr_key2) - - def test_inequality_private_keys(self): - pr_key1 = Private_key(self.pub_key, 100) - pr_key2 = Private_key(self.pub_key, 200) - self.assertNotEqual(pr_key1, pr_key2) - - def test_inequality_private_keys_not_implemented(self): - pr_key = Private_key(self.pub_key, 100) - self.assertNotEqual(pr_key, None) - - -# Testing point validity, as per ECDSAVS.pdf B.2.2: -P192_POINTS = [ - ( - generator_192, - 0xCD6D0F029A023E9AACA429615B8F577ABEE685D8257CC83A, - 0x00019C410987680E9FB6C0B6ECC01D9A2647C8BAE27721BACDFC, - False, - ), - ( - generator_192, - 0x00017F2FCE203639E9EAF9FB50B81FC32776B30E3B02AF16C73B, - 0x95DA95C5E72DD48E229D4748D4EEE658A9A54111B23B2ADB, - False, - ), - ( - generator_192, - 0x4F77F8BC7FCCBADD5760F4938746D5F253EE2168C1CF2792, - 0x000147156FF824D131629739817EDB197717C41AAB5C2A70F0F6, - False, - ), - ( - generator_192, - 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6, - 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F, - True, - ), - ( - generator_192, - 0xCDF56C1AA3D8AFC53C521ADF3FFB96734A6A630A4A5B5A70, - 0x97C1C44A5FB229007B5EC5D25F7413D170068FFD023CAA4E, - True, - ), - ( - generator_192, - 0x89009C0DC361C81E99280C8E91DF578DF88CDF4B0CDEDCED, - 0x27BE44A529B7513E727251F128B34262A0FD4D8EC82377B9, - True, - ), - ( - generator_192, - 0x6A223D00BD22C52833409A163E057E5B5DA1DEF2A197DD15, - 0x7B482604199367F1F303F9EF627F922F97023E90EAE08ABF, - True, - ), - ( - generator_192, - 0x6DCCBDE75C0948C98DAB32EA0BC59FE125CF0FB1A3798EDA, - 0x0001171A3E0FA60CF3096F4E116B556198DE430E1FBD330C8835, - False, - ), - ( - generator_192, - 0xD266B39E1F491FC4ACBBBC7D098430931CFA66D55015AF12, - 0x193782EB909E391A3148B7764E6B234AA94E48D30A16DBB2, - False, - ), - ( - generator_192, - 0x9D6DDBCD439BAA0C6B80A654091680E462A7D1D3F1FFEB43, - 0x6AD8EFC4D133CCF167C44EB4691C80ABFFB9F82B932B8CAA, - False, - ), - ( - generator_192, - 0x146479D944E6BDA87E5B35818AA666A4C998A71F4E95EDBC, - 0xA86D6FE62BC8FBD88139693F842635F687F132255858E7F6, - False, - ), - ( - generator_192, - 0xE594D4A598046F3598243F50FD2C7BD7D380EDB055802253, - 0x509014C0C4D6B536E3CA750EC09066AF39B4C8616A53A923, - False, - ), -] - - -@pytest.mark.parametrize("generator,x,y,expected", P192_POINTS) -def test_point_validity(generator, x, y, expected): - """ - `generator` defines the curve; is `(x, y)` a point on - this curve? `expected` is True if the right answer is Yes. - """ - assert point_is_valid(generator, x, y) == expected - - -# Trying signature-verification tests from ECDSAVS.pdf B.2.4: -CURVE_192_KATS = [ - ( - generator_192, - int( - "0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee" - "425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30" - "d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff79" - "8cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d1" - "58", - 16, - ), - 0xD9DBFB332AA8E5FF091E8CE535857C37C73F6250FFB2E7AC, - 0x282102E364FEDED3AD15DDF968F88D8321AA268DD483EBC4, - 0x64DCA58A20787C488D11D6DD96313F1B766F2D8EFE122916, - 0x1ECBA28141E84AB4ECAD92F56720E2CC83EB3D22DEC72479, - True, - ), - ( - generator_192, - int( - "0x94bb5bacd5f8ea765810024db87f4224ad71362a3c28284b2b9f39fab86db1" - "2e8beb94aae899768229be8fdb6c4f12f28912bb604703a79ccff769c1607f5a" - "91450f30ba0460d359d9126cbd6296be6d9c4bb96c0ee74cbb44197c207f6db3" - "26ab6f5a659113a9034e54be7b041ced9dcf6458d7fb9cbfb2744d999f7dfd63" - "f4", - 16, - ), - 0x3E53EF8D3112AF3285C0E74842090712CD324832D4277AE7, - 0xCC75F8952D30AEC2CBB719FC6AA9934590B5D0FF5A83ADB7, - 0x8285261607283BA18F335026130BAB31840DCFD9C3E555AF, - 0x356D89E1B04541AFC9704A45E9C535CE4A50929E33D7E06C, - True, - ), - ( - generator_192, - int( - "0xf6227a8eeb34afed1621dcc89a91d72ea212cb2f476839d9b4243c66877911" - "b37b4ad6f4448792a7bbba76c63bdd63414b6facab7dc71c3396a73bd7ee14cd" - "d41a659c61c99b779cecf07bc51ab391aa3252386242b9853ea7da67fd768d30" - "3f1b9b513d401565b6f1eb722dfdb96b519fe4f9bd5de67ae131e64b40e78c42" - "dd", - 16, - ), - 0x16335DBE95F8E8254A4E04575D736BEFB258B8657F773CB7, - 0x421B13379C59BC9DCE38A1099CA79BBD06D647C7F6242336, - 0x4141BD5D64EA36C5B0BD21EF28C02DA216ED9D04522B1E91, - 0x159A6AA852BCC579E821B7BB0994C0861FB08280C38DAA09, - False, - ), - ( - generator_192, - int( - "0x16b5f93afd0d02246f662761ed8e0dd9504681ed02a253006eb36736b56309" - "7ba39f81c8e1bce7a16c1339e345efabbc6baa3efb0612948ae51103382a8ee8" - "bc448e3ef71e9f6f7a9676694831d7f5dd0db5446f179bcb737d4a526367a447" - "bfe2c857521c7f40b6d7d7e01a180d92431fb0bbd29c04a0c420a57b3ed26ccd" - "8a", - 16, - ), - 0xFD14CDF1607F5EFB7B1793037B15BDF4BAA6F7C16341AB0B, - 0x83FA0795CC6C4795B9016DAC928FD6BAC32F3229A96312C4, - 0x8DFDB832951E0167C5D762A473C0416C5C15BC1195667DC1, - 0x1720288A2DC13FA1EC78F763F8FE2FF7354A7E6FDDE44520, - False, - ), - ( - generator_192, - int( - "0x08a2024b61b79d260e3bb43ef15659aec89e5b560199bc82cf7c65c77d3919" - "2e03b9a895d766655105edd9188242b91fbde4167f7862d4ddd61e5d4ab55196" - "683d4f13ceb90d87aea6e07eb50a874e33086c4a7cb0273a8e1c4408f4b846bc" - "eae1ebaac1b2b2ea851a9b09de322efe34cebe601653efd6ddc876ce8c2f2072" - "fb", - 16, - ), - 0x674F941DC1A1F8B763C9334D726172D527B90CA324DB8828, - 0x65ADFA32E8B236CB33A3E84CF59BFB9417AE7E8EDE57A7FF, - 0x9508B9FDD7DAF0D8126F9E2BC5A35E4C6D800B5B804D7796, - 0x36F2BF6B21B987C77B53BB801B3435A577E3D493744BFAB0, - False, - ), - ( - generator_192, - int( - "0x1843aba74b0789d4ac6b0b8923848023a644a7b70afa23b1191829bbe4397c" - "e15b629bf21a8838298653ed0c19222b95fa4f7390d1b4c844d96e645537e0aa" - "e98afb5c0ac3bd0e4c37f8daaff25556c64e98c319c52687c904c4de7240a1cc" - "55cd9756b7edaef184e6e23b385726e9ffcba8001b8f574987c1a3fedaaa83ca" - "6d", - 16, - ), - 0x10ECCA1AAD7220B56A62008B35170BFD5E35885C4014A19F, - 0x04EB61984C6C12ADE3BC47F3C629ECE7AA0A033B9948D686, - 0x82BFA4E82C0DFE9274169B86694E76CE993FD83B5C60F325, - 0xA97685676C59A65DBDE002FE9D613431FB183E8006D05633, - False, - ), - ( - generator_192, - int( - "0x5a478f4084ddd1a7fea038aa9732a822106385797d02311aeef4d0264f824f" - "698df7a48cfb6b578cf3da416bc0799425bb491be5b5ecc37995b85b03420a98" - "f2c4dc5c31a69a379e9e322fbe706bbcaf0f77175e05cbb4fa162e0da82010a2" - "78461e3e974d137bc746d1880d6eb02aa95216014b37480d84b87f717bb13f76" - "e1", - 16, - ), - 0x6636653CB5B894CA65C448277B29DA3AD101C4C2300F7C04, - 0xFDF1CBB3FC3FD6A4F890B59E554544175FA77DBDBEB656C1, - 0xEAC2DDECDDFB79931A9C3D49C08DE0645C783A24CB365E1C, - 0x3549FEE3CFA7E5F93BC47D92D8BA100E881A2A93C22F8D50, - False, - ), - ( - generator_192, - int( - "0xc598774259a058fa65212ac57eaa4f52240e629ef4c310722088292d1d4af6" - "c39b49ce06ba77e4247b20637174d0bd67c9723feb57b5ead232b47ea452d5d7" - "a089f17c00b8b6767e434a5e16c231ba0efa718a340bf41d67ea2d295812ff1b" - "9277daacb8bc27b50ea5e6443bcf95ef4e9f5468fe78485236313d53d1c68f6b" - "a2", - 16, - ), - 0xA82BD718D01D354001148CD5F69B9EBF38FF6F21898F8AAA, - 0xE67CEEDE07FC2EBFAFD62462A51E4B6C6B3D5B537B7CAF3E, - 0x4D292486C620C3DE20856E57D3BB72FCDE4A73AD26376955, - 0xA85289591A6081D5728825520E62FF1C64F94235C04C7F95, - False, - ), - ( - generator_192, - int( - "0xca98ed9db081a07b7557f24ced6c7b9891269a95d2026747add9e9eb80638a" - "961cf9c71a1b9f2c29744180bd4c3d3db60f2243c5c0b7cc8a8d40a3f9a7fc91" - "0250f2187136ee6413ffc67f1a25e1c4c204fa9635312252ac0e0481d89b6d53" - "808f0c496ba87631803f6c572c1f61fa049737fdacce4adff757afed4f05beb6" - "58", - 16, - ), - 0x7D3B016B57758B160C4FCA73D48DF07AE3B6B30225126C2F, - 0x4AF3790D9775742BDE46F8DA876711BE1B65244B2B39E7EC, - 0x95F778F5F656511A5AB49A5D69DDD0929563C29CBC3A9E62, - 0x75C87FC358C251B4C83D2DD979FAAD496B539F9F2EE7A289, - False, - ), - ( - generator_192, - int( - "0x31dd9a54c8338bea06b87eca813d555ad1850fac9742ef0bbe40dad400e102" - "88acc9c11ea7dac79eb16378ebea9490e09536099f1b993e2653cd50240014c9" - "0a9c987f64545abc6a536b9bd2435eb5e911fdfde2f13be96ea36ad38df4ae9e" - "a387b29cced599af777338af2794820c9cce43b51d2112380a35802ab7e396c9" - "7a", - 16, - ), - 0x9362F28C4EF96453D8A2F849F21E881CD7566887DA8BEB4A, - 0xE64D26D8D74C48A024AE85D982EE74CD16046F4EE5333905, - 0xF3923476A296C88287E8DE914B0B324AD5A963319A4FE73B, - 0xF0BAEED7624ED00D15244D8BA2AEDE085517DBDEC8AC65F5, - True, - ), - ( - generator_192, - int( - "0xb2b94e4432267c92f9fdb9dc6040c95ffa477652761290d3c7de312283f645" - "0d89cc4aabe748554dfb6056b2d8e99c7aeaad9cdddebdee9dbc099839562d90" - "64e68e7bb5f3a6bba0749ca9a538181fc785553a4000785d73cc207922f63e8c" - "e1112768cb1de7b673aed83a1e4a74592f1268d8e2a4e9e63d414b5d442bd045" - "6d", - 16, - ), - 0xCC6FC032A846AAAC25533EB033522824F94E670FA997ECEF, - 0xE25463EF77A029ECCDA8B294FD63DD694E38D223D30862F1, - 0x066B1D07F3A40E679B620EDA7F550842A35C18B80C5EBE06, - 0xA0B0FB201E8F2DF65E2C4508EF303BDC90D934016F16B2DC, - False, - ), - ( - generator_192, - int( - "0x4366fcadf10d30d086911de30143da6f579527036937007b337f7282460eae" - "5678b15cccda853193ea5fc4bc0a6b9d7a31128f27e1214988592827520b214e" - "ed5052f7775b750b0c6b15f145453ba3fee24a085d65287e10509eb5d5f602c4" - "40341376b95c24e5c4727d4b859bfe1483d20538acdd92c7997fa9c614f0f839" - "d7", - 16, - ), - 0x955C908FE900A996F7E2089BEE2F6376830F76A19135E753, - 0xBA0C42A91D3847DE4A592A46DC3FDAF45A7CC709B90DE520, - 0x1F58AD77FC04C782815A1405B0925E72095D906CBF52A668, - 0xF2E93758B3AF75EDF784F05A6761C9B9A6043C66B845B599, - False, - ), - ( - generator_192, - int( - "0x543f8af57d750e33aa8565e0cae92bfa7a1ff78833093421c2942cadf99866" - "70a5ff3244c02a8225e790fbf30ea84c74720abf99cfd10d02d34377c3d3b412" - "69bea763384f372bb786b5846f58932defa68023136cd571863b304886e95e52" - "e7877f445b9364b3f06f3c28da12707673fecb4b8071de06b6e0a3c87da160ce" - "f3", - 16, - ), - 0x31F7FA05576D78A949B24812D4383107A9A45BB5FCCDD835, - 0x8DC0EB65994A90F02B5E19BD18B32D61150746C09107E76B, - 0xBE26D59E4E883DDE7C286614A767B31E49AD88789D3A78FF, - 0x8762CA831C1CE42DF77893C9B03119428E7A9B819B619068, - False, - ), - ( - generator_192, - int( - "0xd2e8454143ce281e609a9d748014dcebb9d0bc53adb02443a6aac2ffe6cb009f" - "387c346ecb051791404f79e902ee333ad65e5c8cb38dc0d1d39a8dc90add502357" - "2720e5b94b190d43dd0d7873397504c0c7aef2727e628eb6a74411f2e400c65670" - "716cb4a815dc91cbbfeb7cfe8c929e93184c938af2c078584da045e8f8d1", - 16, - ), - 0x66AA8EDBBDB5CF8E28CEB51B5BDA891CAE2DF84819FE25C0, - 0x0C6BC2F69030A7CE58D4A00E3B3349844784A13B8936F8DA, - 0xA4661E69B1734F4A71B788410A464B71E7FFE42334484F23, - 0x738421CF5E049159D69C57A915143E226CAC8355E149AFE9, - False, - ), - ( - generator_192, - int( - "0x6660717144040f3e2f95a4e25b08a7079c702a8b29babad5a19a87654bc5c5af" - "a261512a11b998a4fb36b5d8fe8bd942792ff0324b108120de86d63f65855e5461" - "184fc96a0a8ffd2ce6d5dfb0230cbbdd98f8543e361b3205f5da3d500fdc8bac6d" - "b377d75ebef3cb8f4d1ff738071ad0938917889250b41dd1d98896ca06fb", - 16, - ), - 0xBCFACF45139B6F5F690A4C35A5FFFA498794136A2353FC77, - 0x6F4A6C906316A6AFC6D98FE1F0399D056F128FE0270B0F22, - 0x9DB679A3DAFE48F7CCAD122933ACFE9DA0970B71C94C21C1, - 0x984C2DB99827576C0A41A5DA41E07D8CC768BC82F18C9DA9, - False, - ), -] - - -@pytest.mark.parametrize("gen,msg,qx,qy,r,s,expected", CURVE_192_KATS) -def test_signature_validity(gen, msg, qx, qy, r, s, expected): - """ - `msg` = message, `qx` and `qy` represent the base point on - elliptic curve of `gen`, `r` and `s` are the signature, and - `expected` is True iff the signature is expected to be valid.""" - pubk = Public_key(gen, ellipticcurve.Point(gen.curve(), qx, qy)) - with pytest.warns(DeprecationWarning) as warns: - msg_dgst = digest_integer(msg) - assert len(warns) == 3 - assert "unused" in warns[0].message.args[0] - assert "unused" in warns[1].message.args[0] - assert "unused" in warns[2].message.args[0] - assert expected == pubk.verifies(msg_dgst, Signature(r, s)) - - -@pytest.mark.parametrize( - "gen,msg,qx,qy,r,s,expected", [x for x in CURVE_192_KATS if x[6]] -) -def test_pk_recovery(gen, msg, r, s, qx, qy, expected): - del expected - sign = Signature(r, s) - with pytest.warns(DeprecationWarning) as warns: - msg_dgst = digest_integer(msg) - assert len(warns) == 3 - assert "unused" in warns[0].message.args[0] - assert "unused" in warns[1].message.args[0] - assert "unused" in warns[2].message.args[0] - pks = sign.recover_public_keys(msg_dgst, gen) - - assert pks - - # Test if the signature is valid for all found public keys - for pk in pks: - q = pk.point - test_signature_validity(gen, msg, q.x(), q.y(), r, s, True) - - # Test if the original public key is in the set of found keys - original_q = ellipticcurve.Point(gen.curve(), qx, qy) - points = [pk.point for pk in pks] - assert original_q in points - - -@st.composite -def st_random_gen_key_msg_nonce(draw): - """Hypothesis strategy for test_sig_verify().""" - name_gen = { - "generator_192": generator_192, - "generator_224": generator_224, - "generator_256": generator_256, - "generator_secp256k1": generator_secp256k1, - "generator_384": generator_384, - "generator_521": generator_521, - } - name = draw(st.sampled_from(sorted(name_gen.keys()))) - note("Generator used: {0}".format(name)) - generator = name_gen[name] - order = int(generator.order()) - 1 - - key = draw(st.integers(min_value=1, max_value=order)) - msg = draw(st.integers(min_value=1, max_value=order)) - nonce = draw( - st.integers(min_value=1, max_value=order) - | st.integers(min_value=order >> 1, max_value=order) - ) - return generator, key, msg, nonce - - -SIG_VER_SETTINGS = dict(HYP_SETTINGS) -if "--fast" in sys.argv: # pragma: no cover - SIG_VER_SETTINGS["max_examples"] = 1 -else: - SIG_VER_SETTINGS["max_examples"] = 10 - - -@settings(**SIG_VER_SETTINGS) -@example((generator_224, 4, 1, 1)) -@given(st_random_gen_key_msg_nonce()) -def test_sig_verify(args): - """ - Check if signing and verification works for arbitrary messages and - that signatures for other messages are rejected. - """ - generator, sec_mult, msg, nonce = args - - pubkey = Public_key(generator, generator * sec_mult) - privkey = Private_key(pubkey, sec_mult) - - signature = privkey.sign(msg, nonce) - - assert pubkey.verifies(msg, signature) - - assert not pubkey.verifies(msg - 1, signature) - - -def test_int_to_string_with_zero(): - with pytest.warns(DeprecationWarning) as warns: - assert int_to_string(0) == b"\x00" - - assert len(warns) == 1 - assert "unused" in warns[0].message.args[0] diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_eddsa.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_eddsa.py deleted file mode 100644 index 6821b3b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_eddsa.py +++ /dev/null @@ -1,1124 +0,0 @@ -import sys -import pickle -import hashlib -import pytest - -try: - import unittest2 as unittest -except ImportError: - import unittest -from hypothesis import given, settings, example -import hypothesis.strategies as st -from .ellipticcurve import PointEdwards, INFINITY, CurveEdTw -from .eddsa import ( - generator_ed25519, - curve_ed25519, - generator_ed448, - curve_ed448, - PrivateKey, - PublicKey, -) -from .ecdsa import generator_256, curve_256 -from .errors import MalformedPointError -from ._compat import a2b_hex, compat26_str - - -class TestA2B_Hex(unittest.TestCase): - def test_invalid_input(self): - with self.assertRaises(ValueError): - a2b_hex("abcdefghi") - - -def test_ed25519_curve_compare(): - assert curve_ed25519 != curve_256 - - -def test_ed25519_and_ed448_compare(): - assert curve_ed448 != curve_ed25519 - - -def test_ed25519_and_custom_curve_compare(): - a = CurveEdTw(curve_ed25519.p(), -curve_ed25519.a(), 1) - - assert curve_ed25519 != a - - -def test_ed25519_and_almost_exact_curve_compare(): - a = CurveEdTw(curve_ed25519.p(), curve_ed25519.a(), 1) - - assert curve_ed25519 != a - - -def test_ed25519_and_same_curve_params(): - a = CurveEdTw(curve_ed25519.p(), curve_ed25519.a(), curve_ed25519.d()) - - assert curve_ed25519 == a - assert not (curve_ed25519 != a) - - -def test_ed25519_contains_point(): - g = generator_ed25519 - assert curve_ed25519.contains_point(g.x(), g.y()) - - -def test_ed25519_contains_point_bad(): - assert not curve_ed25519.contains_point(1, 1) - - -def test_ed25519_double(): - a = generator_ed25519 - - z = a.double() - - assert isinstance(z, PointEdwards) - - x2 = int( - "24727413235106541002554574571675588834622768167397638456726423" - "682521233608206" - ) - y2 = int( - "15549675580280190176352668710449542251549572066445060580507079" - "593062643049417" - ) - - b = PointEdwards(curve_ed25519, x2, y2, 1, x2 * y2) - - assert z == b - assert a != b - - -def test_ed25519_add_as_double(): - a = generator_ed25519 - - z = a + a - - assert isinstance(z, PointEdwards) - - b = generator_ed25519.double() - - assert z == b - - -def test_ed25519_double_infinity(): - a = PointEdwards(curve_ed25519, 0, 1, 1, 0) - - z = a.double() - - assert z is INFINITY - - -def test_ed25519_double_badly_encoded_infinity(): - # invalid point, mostly to make instrumental happy - a = PointEdwards(curve_ed25519, 1, 1, 1, 0) - - z = a.double() - - assert z is INFINITY - - -def test_ed25519_eq_with_different_z(): - x = generator_ed25519.x() - y = generator_ed25519.y() - p = curve_ed25519.p() - - a = PointEdwards(curve_ed25519, x * 2 % p, y * 2 % p, 2, x * y * 2 % p) - b = PointEdwards(curve_ed25519, x * 3 % p, y * 3 % p, 3, x * y * 3 % p) - - assert a == b - - assert not (a != b) - - -def test_ed25519_eq_against_infinity(): - assert generator_ed25519 != INFINITY - - -def test_ed25519_eq_encoded_infinity_against_infinity(): - a = PointEdwards(curve_ed25519, 0, 1, 1, 0) - assert a == INFINITY - - -def test_ed25519_eq_bad_encode_of_infinity_against_infinity(): - # technically incorrect encoding of the point at infinity, but we check - # both X and T, so verify that just T==0 works - a = PointEdwards(curve_ed25519, 1, 1, 1, 0) - assert a == INFINITY - - -def test_ed25519_eq_against_non_Edwards_point(): - assert generator_ed25519 != generator_256 - - -def test_ed25519_eq_against_negated_point(): - g = generator_ed25519 - neg = PointEdwards(curve_ed25519, -g.x(), g.y(), 1, -g.x() * g.y()) - assert g != neg - - -def test_ed25519_eq_x_different_y(): - # not points on the curve, but __eq__ doesn't care - a = PointEdwards(curve_ed25519, 1, 1, 1, 1) - b = PointEdwards(curve_ed25519, 1, 2, 1, 2) - - assert a != b - - -def test_ed25519_mul_by_order(): - g = PointEdwards( - curve_ed25519, - generator_ed25519.x(), - generator_ed25519.y(), - 1, - generator_ed25519.x() * generator_ed25519.y(), - ) - - assert g * generator_ed25519.order() == INFINITY - - -def test_radd(): - - a = PointEdwards(curve_ed25519, 1, 1, 1, 1) - - p = INFINITY + a - - assert p == a - - -def test_ed25519_test_normalisation_and_scaling(): - x = generator_ed25519.x() - y = generator_ed25519.y() - p = curve_ed25519.p() - - a = PointEdwards(curve_ed25519, x * 11 % p, y * 11 % p, 11, x * y * 11 % p) - - assert a.x() == x - assert a.y() == y - - a.scale() - - assert a.x() == x - assert a.y() == y - - a.scale() # second execution should be a noop - - assert a.x() == x - assert a.y() == y - - -def test_ed25519_add_three_times(): - a = generator_ed25519 - - z = a + a + a - - x3 = int( - "468967334644549386571235445953867877890461982801326656862413" - "21779790909858396" - ) - y3 = int( - "832484377853344397649037712036920113830141722629755531674120" - "2210403726505172" - ) - - b = PointEdwards(curve_ed25519, x3, y3, 1, x3 * y3) - - assert z == b - - -def test_ed25519_add_to_infinity(): - # generator * (order-1) - x1 = int( - "427838232691226969392843410947554224151809796397784248136826" - "78720006717057747" - ) - y1 = int( - "463168356949264781694283940034751631413079938662562256157830" - "33603165251855960" - ) - inf_m_1 = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) - - inf = inf_m_1 + generator_ed25519 - - assert inf is INFINITY - - -def test_ed25519_add_and_mul_equivalence(): - g = generator_ed25519 - - assert g + g == g * 2 - assert g + g + g == g * 3 - - -def test_ed25519_add_literal_infinity(): - g = generator_ed25519 - z = g + INFINITY - - assert z == g - - -def test_ed25519_add_infinity(): - inf = PointEdwards(curve_ed25519, 0, 1, 1, 0) - g = generator_ed25519 - z = g + inf - - assert z == g - - z = inf + g - - assert z == g - - -class TestEd25519(unittest.TestCase): - def test_add_wrong_curves(self): - with self.assertRaises(ValueError) as e: - generator_ed25519 + generator_ed448 - - self.assertIn("different curve", str(e.exception)) - - def test_add_wrong_point_type(self): - with self.assertRaises(ValueError) as e: - generator_ed25519 + generator_256 - - self.assertIn("different curve", str(e.exception)) - - -def test_generate_with_point(): - x1 = int( - "427838232691226969392843410947554224151809796397784248136826" - "78720006717057747" - ) - y1 = int( - "463168356949264781694283940034751631413079938662562256157830" - "33603165251855960" - ) - p = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) - - pk = PublicKey(generator_ed25519, b"0" * 32, public_point=p) - - assert pk.public_point() == p - - -def test_ed25519_mul_to_order_min_1(): - x1 = int( - "427838232691226969392843410947554224151809796397784248136826" - "78720006717057747" - ) - y1 = int( - "463168356949264781694283940034751631413079938662562256157830" - "33603165251855960" - ) - inf_m_1 = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) - - assert generator_ed25519 * (generator_ed25519.order() - 1) == inf_m_1 - - -def test_ed25519_mul_to_infinity(): - assert generator_ed25519 * generator_ed25519.order() == INFINITY - - -def test_ed25519_mul_to_infinity_plus_1(): - g = generator_ed25519 - assert g * (g.order() + 1) == g - - -def test_ed25519_mul_and_add(): - g = generator_ed25519 - a = g * 128 - b = g * 64 + g * 64 - - assert a == b - - -def test_ed25519_mul_and_add_2(): - g = generator_ed25519 - - a = g * 123 - b = g * 120 + g * 3 - - assert a == b - - -def test_ed25519_mul_infinity(): - inf = PointEdwards(curve_ed25519, 0, 1, 1, 0) - - z = inf * 11 - - assert z == INFINITY - - -def test_ed25519_mul_by_zero(): - z = generator_ed25519 * 0 - - assert z == INFINITY - - -def test_ed25519_mul_by_one(): - z = generator_ed25519 * 1 - - assert z == generator_ed25519 - - -def test_ed25519_mul_custom_point(): - # verify that multiplication without order set works - - g = generator_ed25519 - - a = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) - - z = a * 11 - - assert z == g * 11 - - -def test_ed25519_pickle(): - g = generator_ed25519 - assert pickle.loads(pickle.dumps(g)) == g - - -def test_ed448_eq_against_different_curve(): - assert generator_ed25519 != generator_ed448 - - -def test_ed448_double(): - g = generator_ed448 - z = g.double() - - assert isinstance(z, PointEdwards) - - x2 = int( - "4845591495304045936995492052586696895690942404582120401876" - "6013278705691214670908136440114445572635086627683154494739" - "7859048262938744149" - ) - y2 = int( - "4940887598674337276743026725267350893505445523037277237461" - "2648447308771911703729389009346215770388834286503647778745" - "3078312060500281069" - ) - - b = PointEdwards(curve_ed448, x2, y2, 1, x2 * y2) - - assert z == b - assert g != b - - -def test_ed448_add_as_double(): - g = generator_ed448 - z = g + g - - b = g.double() - - assert z == b - - -def test_ed448_mul_as_double(): - g = generator_ed448 - z = g * 2 - b = g.double() - - assert z == b - - -def test_ed448_add_to_infinity(): - # generator * (order - 1) - x1 = int( - "5022586839996825903617194737881084981068517190547539260353" - "6473749366191269932473977736719082931859264751085238669719" - "1187378895383117729" - ) - y1 = int( - "2988192100784814926760179304439306734375440401540802420959" - "2824137233150618983587600353687865541878473398230323350346" - "2500531545062832660" - ) - inf_m_1 = PointEdwards(curve_ed448, x1, y1, 1, x1 * y1) - - inf = inf_m_1 + generator_ed448 - - assert inf is INFINITY - - -def test_ed448_mul_to_infinity(): - g = generator_ed448 - inf = g * g.order() - - assert inf is INFINITY - - -def test_ed448_mul_to_infinity_plus_1(): - g = generator_ed448 - - z = g * (g.order() + 1) - - assert z == g - - -def test_ed448_add_and_mul_equivalence(): - g = generator_ed448 - - assert g + g == g * 2 - assert g + g + g == g * 3 - - -def test_ed25519_encode(): - g = generator_ed25519 - g_bytes = g.to_bytes() - assert len(g_bytes) == 32 - exp_bytes = ( - b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - ) - assert g_bytes == exp_bytes - - -def test_ed25519_decode(): - exp_bytes = ( - b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - ) - a = PointEdwards.from_bytes(curve_ed25519, exp_bytes) - - assert a == generator_ed25519 - - -class TestEdwardsMalformed(unittest.TestCase): - def test_invalid_point(self): - exp_bytes = ( - b"\x78\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - ) - with self.assertRaises(MalformedPointError): - PointEdwards.from_bytes(curve_ed25519, exp_bytes) - - def test_invalid_length(self): - exp_bytes = ( - b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" - b"\x66" - ) - with self.assertRaises(MalformedPointError) as e: - PointEdwards.from_bytes(curve_ed25519, exp_bytes) - - self.assertIn("length", str(e.exception)) - - def test_ed448_invalid(self): - exp_bytes = b"\xff" * 57 - with self.assertRaises(MalformedPointError): - PointEdwards.from_bytes(curve_ed448, exp_bytes) - - -def test_ed448_encode(): - g = generator_ed448 - g_bytes = g.to_bytes() - assert len(g_bytes) == 57 - exp_bytes = ( - b"\x14\xfa\x30\xf2\x5b\x79\x08\x98\xad\xc8\xd7\x4e\x2c\x13\xbd" - b"\xfd\xc4\x39\x7c\xe6\x1c\xff\xd3\x3a\xd7\xc2\xa0\x05\x1e\x9c" - b"\x78\x87\x40\x98\xa3\x6c\x73\x73\xea\x4b\x62\xc7\xc9\x56\x37" - b"\x20\x76\x88\x24\xbc\xb6\x6e\x71\x46\x3f\x69\x00" - ) - assert g_bytes == exp_bytes - - -def test_ed448_decode(): - exp_bytes = ( - b"\x14\xfa\x30\xf2\x5b\x79\x08\x98\xad\xc8\xd7\x4e\x2c\x13\xbd" - b"\xfd\xc4\x39\x7c\xe6\x1c\xff\xd3\x3a\xd7\xc2\xa0\x05\x1e\x9c" - b"\x78\x87\x40\x98\xa3\x6c\x73\x73\xea\x4b\x62\xc7\xc9\x56\x37" - b"\x20\x76\x88\x24\xbc\xb6\x6e\x71\x46\x3f\x69\x00" - ) - - a = PointEdwards.from_bytes(curve_ed448, exp_bytes) - - assert a == generator_ed448 - - -class TestEdDSAEquality(unittest.TestCase): - def test_equal_public_points(self): - key1 = PublicKey(generator_ed25519, b"\x01" * 32) - key2 = PublicKey(generator_ed25519, b"\x01" * 32) - - self.assertEqual(key1, key2) - # verify that `__ne__` works as expected - self.assertFalse(key1 != key2) - - def test_unequal_public_points(self): - key1 = PublicKey(generator_ed25519, b"\x01" * 32) - key2 = PublicKey(generator_ed25519, b"\x03" * 32) - - self.assertNotEqual(key1, key2) - - def test_unequal_to_string(self): - key1 = PublicKey(generator_ed25519, b"\x01" * 32) - key2 = b"\x01" * 32 - - self.assertNotEqual(key1, key2) - - def test_unequal_publickey_curves(self): - key1 = PublicKey(generator_ed25519, b"\x01" * 32) - key2 = PublicKey(generator_ed448, b"\x03" * 56 + b"\x00") - - self.assertNotEqual(key1, key2) - # verify that `__ne__` works as expected - self.assertTrue(key1 != key2) - - def test_equal_private_keys(self): - key1 = PrivateKey(generator_ed25519, b"\x01" * 32) - key2 = PrivateKey(generator_ed25519, b"\x01" * 32) - - self.assertEqual(key1, key2) - # verify that `__ne__` works as expected - self.assertFalse(key1 != key2) - - def test_unequal_private_keys(self): - key1 = PrivateKey(generator_ed25519, b"\x01" * 32) - key2 = PrivateKey(generator_ed25519, b"\x02" * 32) - - self.assertNotEqual(key1, key2) - # verify that `__ne__` works as expected - self.assertTrue(key1 != key2) - - def test_unequal_privatekey_to_string(self): - key1 = PrivateKey(generator_ed25519, b"\x01" * 32) - key2 = b"\x01" * 32 - - self.assertNotEqual(key1, key2) - - def test_unequal_privatekey_curves(self): - key1 = PrivateKey(generator_ed25519, b"\x01" * 32) - key2 = PrivateKey(generator_ed448, b"\x01" * 57) - - self.assertNotEqual(key1, key2) - - -class TestInvalidEdDSAInputs(unittest.TestCase): - def test_wrong_length_of_private_key(self): - with self.assertRaises(ValueError): - PrivateKey(generator_ed25519, b"\x01" * 31) - - def test_wrong_length_of_public_key(self): - with self.assertRaises(ValueError): - PublicKey(generator_ed25519, b"\x01" * 33) - - def test_wrong_cofactor_curve(self): - ed_c = curve_ed25519 - - def _hash(data): - return hashlib.new("sha512", compat26_str(data)).digest() - - curve = CurveEdTw(ed_c.p(), ed_c.a(), ed_c.d(), 1, _hash) - g = generator_ed25519 - fake_gen = PointEdwards(curve, g.x(), g.y(), 1, g.x() * g.y()) - - with self.assertRaises(ValueError) as e: - PrivateKey(fake_gen, g.to_bytes()) - - self.assertIn("cofactor", str(e.exception)) - - def test_invalid_signature_length(self): - key = PublicKey(generator_ed25519, b"\x01" * 32) - - with self.assertRaises(ValueError) as e: - key.verify(b"", b"\x01" * 65) - - self.assertIn("length", str(e.exception)) - - def test_changing_public_key(self): - key = PublicKey(generator_ed25519, b"\x01" * 32) - - g = key.point - - new_g = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) - - key.point = new_g - - self.assertEqual(g, key.point) - - def test_changing_public_key_to_different_point(self): - key = PublicKey(generator_ed25519, b"\x01" * 32) - - with self.assertRaises(ValueError) as e: - key.point = generator_ed25519 - - self.assertIn("coordinates", str(e.exception)) - - def test_invalid_s_value(self): - key = PublicKey( - generator_ed25519, - b"\xd7\x5a\x98\x01\x82\xb1\x0a\xb7\xd5\x4b\xfe\xd3\xc9\x64\x07\x3a" - b"\x0e\xe1\x72\xf3\xda\xa6\x23\x25\xaf\x02\x1a\x68\xf7\x07\x51\x1a", - ) - sig_valid = bytearray( - b"\xe5\x56\x43\x00\xc3\x60\xac\x72\x90\x86\xe2\xcc\x80\x6e\x82\x8a" - b"\x84\x87\x7f\x1e\xb8\xe5\xd9\x74\xd8\x73\xe0\x65\x22\x49\x01\x55" - b"\x5f\xb8\x82\x15\x90\xa3\x3b\xac\xc6\x1e\x39\x70\x1c\xf9\xb4\x6b" - b"\xd2\x5b\xf5\xf0\x59\x5b\xbe\x24\x65\x51\x41\x43\x8e\x7a\x10\x0b" - ) - - self.assertTrue(key.verify(b"", sig_valid)) - - sig_invalid = bytearray(sig_valid) - sig_invalid[-1] = 0xFF - - with self.assertRaises(ValueError): - key.verify(b"", sig_invalid) - - def test_invalid_r_value(self): - key = PublicKey( - generator_ed25519, - b"\xd7\x5a\x98\x01\x82\xb1\x0a\xb7\xd5\x4b\xfe\xd3\xc9\x64\x07\x3a" - b"\x0e\xe1\x72\xf3\xda\xa6\x23\x25\xaf\x02\x1a\x68\xf7\x07\x51\x1a", - ) - sig_valid = bytearray( - b"\xe5\x56\x43\x00\xc3\x60\xac\x72\x90\x86\xe2\xcc\x80\x6e\x82\x8a" - b"\x84\x87\x7f\x1e\xb8\xe5\xd9\x74\xd8\x73\xe0\x65\x22\x49\x01\x55" - b"\x5f\xb8\x82\x15\x90\xa3\x3b\xac\xc6\x1e\x39\x70\x1c\xf9\xb4\x6b" - b"\xd2\x5b\xf5\xf0\x59\x5b\xbe\x24\x65\x51\x41\x43\x8e\x7a\x10\x0b" - ) - - self.assertTrue(key.verify(b"", sig_valid)) - - sig_invalid = bytearray(sig_valid) - sig_invalid[0] = 0xE0 - - with self.assertRaises(ValueError): - key.verify(b"", sig_invalid) - - -HYP_SETTINGS = dict() -if "--fast" in sys.argv: # pragma: no cover - HYP_SETTINGS["max_examples"] = 2 -else: - HYP_SETTINGS["max_examples"] = 10 - - -@settings(**HYP_SETTINGS) -@example(1) -@example(5) # smallest multiple that requires changing sign of x -@given(st.integers(min_value=1, max_value=int(generator_ed25519.order() - 1))) -def test_ed25519_encode_decode(multiple): - a = generator_ed25519 * multiple - - b = PointEdwards.from_bytes(curve_ed25519, a.to_bytes()) - - assert a == b - - -@settings(**HYP_SETTINGS) -@example(1) -@example(2) # smallest multiple that requires changing the sign of x -@given(st.integers(min_value=1, max_value=int(generator_ed448.order() - 1))) -def test_ed448_encode_decode(multiple): - a = generator_ed448 * multiple - - b = PointEdwards.from_bytes(curve_ed448, a.to_bytes()) - - assert a == b - - -@settings(**HYP_SETTINGS) -@example(1) -@example(2) -@given(st.integers(min_value=1, max_value=int(generator_ed25519.order()) - 1)) -def test_ed25519_mul_precompute_vs_naf(multiple): - """Compare multiplication with and without precomputation.""" - g = generator_ed25519 - new_g = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) - - assert g * multiple == multiple * new_g - - -# Test vectors from RFC 8032 -TEST_VECTORS = [ - # TEST 1 - ( - generator_ed25519, - "9d61b19deffd5a60ba844af492ec2cc4" "4449c5697b326919703bac031cae7f60", - "d75a980182b10ab7d54bfed3c964073a" "0ee172f3daa62325af021a68f707511a", - "", - "e5564300c360ac729086e2cc806e828a" - "84877f1eb8e5d974d873e06522490155" - "5fb8821590a33bacc61e39701cf9b46b" - "d25bf5f0595bbe24655141438e7a100b", - ), - # TEST 2 - ( - generator_ed25519, - "4ccd089b28ff96da9db6c346ec114e0f" "5b8a319f35aba624da8cf6ed4fb8a6fb", - "3d4017c3e843895a92b70aa74d1b7ebc" "9c982ccf2ec4968cc0cd55f12af4660c", - "72", - "92a009a9f0d4cab8720e820b5f642540" - "a2b27b5416503f8fb3762223ebdb69da" - "085ac1e43e15996e458f3613d0f11d8c" - "387b2eaeb4302aeeb00d291612bb0c00", - ), - # TEST 3 - ( - generator_ed25519, - "c5aa8df43f9f837bedb7442f31dcb7b1" "66d38535076f094b85ce3a2e0b4458f7", - "fc51cd8e6218a1a38da47ed00230f058" "0816ed13ba3303ac5deb911548908025", - "af82", - "6291d657deec24024827e69c3abe01a3" - "0ce548a284743a445e3680d7db5ac3ac" - "18ff9b538d16f290ae67f760984dc659" - "4a7c15e9716ed28dc027beceea1ec40a", - ), - # TEST 1024 - ( - generator_ed25519, - "f5e5767cf153319517630f226876b86c" "8160cc583bc013744c6bf255f5cc0ee5", - "278117fc144c72340f67d0f2316e8386" "ceffbf2b2428c9c51fef7c597f1d426e", - "08b8b2b733424243760fe426a4b54908" - "632110a66c2f6591eabd3345e3e4eb98" - "fa6e264bf09efe12ee50f8f54e9f77b1" - "e355f6c50544e23fb1433ddf73be84d8" - "79de7c0046dc4996d9e773f4bc9efe57" - "38829adb26c81b37c93a1b270b20329d" - "658675fc6ea534e0810a4432826bf58c" - "941efb65d57a338bbd2e26640f89ffbc" - "1a858efcb8550ee3a5e1998bd177e93a" - "7363c344fe6b199ee5d02e82d522c4fe" - "ba15452f80288a821a579116ec6dad2b" - "3b310da903401aa62100ab5d1a36553e" - "06203b33890cc9b832f79ef80560ccb9" - "a39ce767967ed628c6ad573cb116dbef" - "efd75499da96bd68a8a97b928a8bbc10" - "3b6621fcde2beca1231d206be6cd9ec7" - "aff6f6c94fcd7204ed3455c68c83f4a4" - "1da4af2b74ef5c53f1d8ac70bdcb7ed1" - "85ce81bd84359d44254d95629e9855a9" - "4a7c1958d1f8ada5d0532ed8a5aa3fb2" - "d17ba70eb6248e594e1a2297acbbb39d" - "502f1a8c6eb6f1ce22b3de1a1f40cc24" - "554119a831a9aad6079cad88425de6bd" - "e1a9187ebb6092cf67bf2b13fd65f270" - "88d78b7e883c8759d2c4f5c65adb7553" - "878ad575f9fad878e80a0c9ba63bcbcc" - "2732e69485bbc9c90bfbd62481d9089b" - "eccf80cfe2df16a2cf65bd92dd597b07" - "07e0917af48bbb75fed413d238f5555a" - "7a569d80c3414a8d0859dc65a46128ba" - "b27af87a71314f318c782b23ebfe808b" - "82b0ce26401d2e22f04d83d1255dc51a" - "ddd3b75a2b1ae0784504df543af8969b" - "e3ea7082ff7fc9888c144da2af58429e" - "c96031dbcad3dad9af0dcbaaaf268cb8" - "fcffead94f3c7ca495e056a9b47acdb7" - "51fb73e666c6c655ade8297297d07ad1" - "ba5e43f1bca32301651339e22904cc8c" - "42f58c30c04aafdb038dda0847dd988d" - "cda6f3bfd15c4b4c4525004aa06eeff8" - "ca61783aacec57fb3d1f92b0fe2fd1a8" - "5f6724517b65e614ad6808d6f6ee34df" - "f7310fdc82aebfd904b01e1dc54b2927" - "094b2db68d6f903b68401adebf5a7e08" - "d78ff4ef5d63653a65040cf9bfd4aca7" - "984a74d37145986780fc0b16ac451649" - "de6188a7dbdf191f64b5fc5e2ab47b57" - "f7f7276cd419c17a3ca8e1b939ae49e4" - "88acba6b965610b5480109c8b17b80e1" - "b7b750dfc7598d5d5011fd2dcc5600a3" - "2ef5b52a1ecc820e308aa342721aac09" - "43bf6686b64b2579376504ccc493d97e" - "6aed3fb0f9cd71a43dd497f01f17c0e2" - "cb3797aa2a2f256656168e6c496afc5f" - "b93246f6b1116398a346f1a641f3b041" - "e989f7914f90cc2c7fff357876e506b5" - "0d334ba77c225bc307ba537152f3f161" - "0e4eafe595f6d9d90d11faa933a15ef1" - "369546868a7f3a45a96768d40fd9d034" - "12c091c6315cf4fde7cb68606937380d" - "b2eaaa707b4c4185c32eddcdd306705e" - "4dc1ffc872eeee475a64dfac86aba41c" - "0618983f8741c5ef68d3a101e8a3b8ca" - "c60c905c15fc910840b94c00a0b9d0", - "0aab4c900501b3e24d7cdf4663326a3a" - "87df5e4843b2cbdb67cbf6e460fec350" - "aa5371b1508f9f4528ecea23c436d94b" - "5e8fcd4f681e30a6ac00a9704a188a03", - ), - # TEST SHA(abc) - ( - generator_ed25519, - "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42", - "ec172b93ad5e563bf4932c70e1245034" "c35467ef2efd4d64ebf819683467e2bf", - "ddaf35a193617abacc417349ae204131" - "12e6fa4e89a97ea20a9eeee64b55d39a" - "2192992a274fc1a836ba3c23a3feebbd" - "454d4423643ce80e2a9ac94fa54ca49f", - "dc2a4459e7369633a52b1bf277839a00" - "201009a3efbf3ecb69bea2186c26b589" - "09351fc9ac90b3ecfdfbc7c66431e030" - "3dca179c138ac17ad9bef1177331a704", - ), - # Blank - ( - generator_ed448, - "6c82a562cb808d10d632be89c8513ebf" - "6c929f34ddfa8c9f63c9960ef6e348a3" - "528c8a3fcc2f044e39a3fc5b94492f8f" - "032e7549a20098f95b", - "5fd7449b59b461fd2ce787ec616ad46a" - "1da1342485a70e1f8a0ea75d80e96778" - "edf124769b46c7061bd6783df1e50f6c" - "d1fa1abeafe8256180", - "", - "533a37f6bbe457251f023c0d88f976ae" - "2dfb504a843e34d2074fd823d41a591f" - "2b233f034f628281f2fd7a22ddd47d78" - "28c59bd0a21bfd3980ff0d2028d4b18a" - "9df63e006c5d1c2d345b925d8dc00b41" - "04852db99ac5c7cdda8530a113a0f4db" - "b61149f05a7363268c71d95808ff2e65" - "2600", - ), - # 1 octet - ( - generator_ed448, - "c4eab05d357007c632f3dbb48489924d" - "552b08fe0c353a0d4a1f00acda2c463a" - "fbea67c5e8d2877c5e3bc397a659949e" - "f8021e954e0a12274e", - "43ba28f430cdff456ae531545f7ecd0a" - "c834a55d9358c0372bfa0c6c6798c086" - "6aea01eb00742802b8438ea4cb82169c" - "235160627b4c3a9480", - "03", - "26b8f91727bd62897af15e41eb43c377" - "efb9c610d48f2335cb0bd0087810f435" - "2541b143c4b981b7e18f62de8ccdf633" - "fc1bf037ab7cd779805e0dbcc0aae1cb" - "cee1afb2e027df36bc04dcecbf154336" - "c19f0af7e0a6472905e799f1953d2a0f" - "f3348ab21aa4adafd1d234441cf807c0" - "3a00", - ), - # 11 octets - ( - generator_ed448, - "cd23d24f714274e744343237b93290f5" - "11f6425f98e64459ff203e8985083ffd" - "f60500553abc0e05cd02184bdb89c4cc" - "d67e187951267eb328", - "dcea9e78f35a1bf3499a831b10b86c90" - "aac01cd84b67a0109b55a36e9328b1e3" - "65fce161d71ce7131a543ea4cb5f7e9f" - "1d8b00696447001400", - "0c3e544074ec63b0265e0c", - "1f0a8888ce25e8d458a21130879b840a" - "9089d999aaba039eaf3e3afa090a09d3" - "89dba82c4ff2ae8ac5cdfb7c55e94d5d" - "961a29fe0109941e00b8dbdeea6d3b05" - "1068df7254c0cdc129cbe62db2dc957d" - "bb47b51fd3f213fb8698f064774250a5" - "028961c9bf8ffd973fe5d5c206492b14" - "0e00", - ), - # 12 octets - ( - generator_ed448, - "258cdd4ada32ed9c9ff54e63756ae582" - "fb8fab2ac721f2c8e676a72768513d93" - "9f63dddb55609133f29adf86ec9929dc" - "cb52c1c5fd2ff7e21b", - "3ba16da0c6f2cc1f30187740756f5e79" - "8d6bc5fc015d7c63cc9510ee3fd44adc" - "24d8e968b6e46e6f94d19b945361726b" - "d75e149ef09817f580", - "64a65f3cdedcdd66811e2915", - "7eeeab7c4e50fb799b418ee5e3197ff6" - "bf15d43a14c34389b59dd1a7b1b85b4a" - "e90438aca634bea45e3a2695f1270f07" - "fdcdf7c62b8efeaf00b45c2c96ba457e" - "b1a8bf075a3db28e5c24f6b923ed4ad7" - "47c3c9e03c7079efb87cb110d3a99861" - "e72003cbae6d6b8b827e4e6c143064ff" - "3c00", - ), - # 13 octets - ( - generator_ed448, - "7ef4e84544236752fbb56b8f31a23a10" - "e42814f5f55ca037cdcc11c64c9a3b29" - "49c1bb60700314611732a6c2fea98eeb" - "c0266a11a93970100e", - "b3da079b0aa493a5772029f0467baebe" - "e5a8112d9d3a22532361da294f7bb381" - "5c5dc59e176b4d9f381ca0938e13c6c0" - "7b174be65dfa578e80", - "64a65f3cdedcdd66811e2915e7", - "6a12066f55331b6c22acd5d5bfc5d712" - "28fbda80ae8dec26bdd306743c5027cb" - "4890810c162c027468675ecf645a8317" - "6c0d7323a2ccde2d80efe5a1268e8aca" - "1d6fbc194d3f77c44986eb4ab4177919" - "ad8bec33eb47bbb5fc6e28196fd1caf5" - "6b4e7e0ba5519234d047155ac727a105" - "3100", - ), - # 64 octets - ( - generator_ed448, - "d65df341ad13e008567688baedda8e9d" - "cdc17dc024974ea5b4227b6530e339bf" - "f21f99e68ca6968f3cca6dfe0fb9f4fa" - "b4fa135d5542ea3f01", - "df9705f58edbab802c7f8363cfe5560a" - "b1c6132c20a9f1dd163483a26f8ac53a" - "39d6808bf4a1dfbd261b099bb03b3fb5" - "0906cb28bd8a081f00", - "bd0f6a3747cd561bdddf4640a332461a" - "4a30a12a434cd0bf40d766d9c6d458e5" - "512204a30c17d1f50b5079631f64eb31" - "12182da3005835461113718d1a5ef944", - "554bc2480860b49eab8532d2a533b7d5" - "78ef473eeb58c98bb2d0e1ce488a98b1" - "8dfde9b9b90775e67f47d4a1c3482058" - "efc9f40d2ca033a0801b63d45b3b722e" - "f552bad3b4ccb667da350192b61c508c" - "f7b6b5adadc2c8d9a446ef003fb05cba" - "5f30e88e36ec2703b349ca229c267083" - "3900", - ), - # 256 octets - ( - generator_ed448, - "2ec5fe3c17045abdb136a5e6a913e32a" - "b75ae68b53d2fc149b77e504132d3756" - "9b7e766ba74a19bd6162343a21c8590a" - "a9cebca9014c636df5", - "79756f014dcfe2079f5dd9e718be4171" - "e2ef2486a08f25186f6bff43a9936b9b" - "fe12402b08ae65798a3d81e22e9ec80e" - "7690862ef3d4ed3a00", - "15777532b0bdd0d1389f636c5f6b9ba7" - "34c90af572877e2d272dd078aa1e567c" - "fa80e12928bb542330e8409f31745041" - "07ecd5efac61ae7504dabe2a602ede89" - "e5cca6257a7c77e27a702b3ae39fc769" - "fc54f2395ae6a1178cab4738e543072f" - "c1c177fe71e92e25bf03e4ecb72f47b6" - "4d0465aaea4c7fad372536c8ba516a60" - "39c3c2a39f0e4d832be432dfa9a706a6" - "e5c7e19f397964ca4258002f7c0541b5" - "90316dbc5622b6b2a6fe7a4abffd9610" - "5eca76ea7b98816af0748c10df048ce0" - "12d901015a51f189f3888145c03650aa" - "23ce894c3bd889e030d565071c59f409" - "a9981b51878fd6fc110624dcbcde0bf7" - "a69ccce38fabdf86f3bef6044819de11", - "c650ddbb0601c19ca11439e1640dd931" - "f43c518ea5bea70d3dcde5f4191fe53f" - "00cf966546b72bcc7d58be2b9badef28" - "743954e3a44a23f880e8d4f1cfce2d7a" - "61452d26da05896f0a50da66a239a8a1" - "88b6d825b3305ad77b73fbac0836ecc6" - "0987fd08527c1a8e80d5823e65cafe2a" - "3d00", - ), - # 1023 octets - ( - generator_ed448, - "872d093780f5d3730df7c212664b37b8" - "a0f24f56810daa8382cd4fa3f77634ec" - "44dc54f1c2ed9bea86fafb7632d8be19" - "9ea165f5ad55dd9ce8", - "a81b2e8a70a5ac94ffdbcc9badfc3feb" - "0801f258578bb114ad44ece1ec0e799d" - "a08effb81c5d685c0c56f64eecaef8cd" - "f11cc38737838cf400", - "6ddf802e1aae4986935f7f981ba3f035" - "1d6273c0a0c22c9c0e8339168e675412" - "a3debfaf435ed651558007db4384b650" - "fcc07e3b586a27a4f7a00ac8a6fec2cd" - "86ae4bf1570c41e6a40c931db27b2faa" - "15a8cedd52cff7362c4e6e23daec0fbc" - "3a79b6806e316efcc7b68119bf46bc76" - "a26067a53f296dafdbdc11c77f7777e9" - "72660cf4b6a9b369a6665f02e0cc9b6e" - "dfad136b4fabe723d2813db3136cfde9" - "b6d044322fee2947952e031b73ab5c60" - "3349b307bdc27bc6cb8b8bbd7bd32321" - "9b8033a581b59eadebb09b3c4f3d2277" - "d4f0343624acc817804728b25ab79717" - "2b4c5c21a22f9c7839d64300232eb66e" - "53f31c723fa37fe387c7d3e50bdf9813" - "a30e5bb12cf4cd930c40cfb4e1fc6225" - "92a49588794494d56d24ea4b40c89fc0" - "596cc9ebb961c8cb10adde976a5d602b" - "1c3f85b9b9a001ed3c6a4d3b1437f520" - "96cd1956d042a597d561a596ecd3d173" - "5a8d570ea0ec27225a2c4aaff26306d1" - "526c1af3ca6d9cf5a2c98f47e1c46db9" - "a33234cfd4d81f2c98538a09ebe76998" - "d0d8fd25997c7d255c6d66ece6fa56f1" - "1144950f027795e653008f4bd7ca2dee" - "85d8e90f3dc315130ce2a00375a318c7" - "c3d97be2c8ce5b6db41a6254ff264fa6" - "155baee3b0773c0f497c573f19bb4f42" - "40281f0b1f4f7be857a4e59d416c06b4" - "c50fa09e1810ddc6b1467baeac5a3668" - "d11b6ecaa901440016f389f80acc4db9" - "77025e7f5924388c7e340a732e554440" - "e76570f8dd71b7d640b3450d1fd5f041" - "0a18f9a3494f707c717b79b4bf75c984" - "00b096b21653b5d217cf3565c9597456" - "f70703497a078763829bc01bb1cbc8fa" - "04eadc9a6e3f6699587a9e75c94e5bab" - "0036e0b2e711392cff0047d0d6b05bd2" - "a588bc109718954259f1d86678a579a3" - "120f19cfb2963f177aeb70f2d4844826" - "262e51b80271272068ef5b3856fa8535" - "aa2a88b2d41f2a0e2fda7624c2850272" - "ac4a2f561f8f2f7a318bfd5caf969614" - "9e4ac824ad3460538fdc25421beec2cc" - "6818162d06bbed0c40a387192349db67" - "a118bada6cd5ab0140ee273204f628aa" - "d1c135f770279a651e24d8c14d75a605" - "9d76b96a6fd857def5e0b354b27ab937" - "a5815d16b5fae407ff18222c6d1ed263" - "be68c95f32d908bd895cd76207ae7264" - "87567f9a67dad79abec316f683b17f2d" - "02bf07e0ac8b5bc6162cf94697b3c27c" - "d1fea49b27f23ba2901871962506520c" - "392da8b6ad0d99f7013fbc06c2c17a56" - "9500c8a7696481c1cd33e9b14e40b82e" - "79a5f5db82571ba97bae3ad3e0479515" - "bb0e2b0f3bfcd1fd33034efc6245eddd" - "7ee2086ddae2600d8ca73e214e8c2b0b" - "db2b047c6a464a562ed77b73d2d841c4" - "b34973551257713b753632efba348169" - "abc90a68f42611a40126d7cb21b58695" - "568186f7e569d2ff0f9e745d0487dd2e" - "b997cafc5abf9dd102e62ff66cba87", - "e301345a41a39a4d72fff8df69c98075" - "a0cc082b802fc9b2b6bc503f926b65bd" - "df7f4c8f1cb49f6396afc8a70abe6d8a" - "ef0db478d4c6b2970076c6a0484fe76d" - "76b3a97625d79f1ce240e7c576750d29" - "5528286f719b413de9ada3e8eb78ed57" - "3603ce30d8bb761785dc30dbc320869e" - "1a00", - ), -] - - -@pytest.mark.parametrize( - "generator,private_key,public_key,message,signature", - TEST_VECTORS, -) -def test_vectors(generator, private_key, public_key, message, signature): - private_key = a2b_hex(private_key) - public_key = a2b_hex(public_key) - message = a2b_hex(message) - signature = a2b_hex(signature) - - sig_key = PrivateKey(generator, private_key) - ver_key = PublicKey(generator, public_key) - - assert sig_key.public_key().public_key() == ver_key.public_key() - - gen_sig = sig_key.sign(message) - - assert gen_sig == signature - - assert ver_key.verify(message, signature) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ellipticcurve.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ellipticcurve.py deleted file mode 100644 index 864cf10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_ellipticcurve.py +++ /dev/null @@ -1,294 +0,0 @@ -import pytest - -try: - import unittest2 as unittest -except ImportError: - import unittest -from hypothesis import given, settings -import hypothesis.strategies as st - -try: - from hypothesis import HealthCheck - - HC_PRESENT = True -except ImportError: # pragma: no cover - HC_PRESENT = False -from .numbertheory import inverse_mod -from .ellipticcurve import CurveFp, INFINITY, Point, CurveEdTw - - -HYP_SETTINGS = {} -if HC_PRESENT: # pragma: no branch - HYP_SETTINGS["suppress_health_check"] = [HealthCheck.too_slow] - HYP_SETTINGS["deadline"] = 5000 - - -# NIST Curve P-192: -p = 6277101735386680763835789423207666416083908700390324961279 -r = 6277101735386680763835789423176059013767194773182842284081 -# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5 -# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65 -b = 0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1 -Gx = 0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012 -Gy = 0x07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 - -c192 = CurveFp(p, -3, b) -p192 = Point(c192, Gx, Gy, r) - -c_23 = CurveFp(23, 1, 1) -g_23 = Point(c_23, 13, 7, 7) - - -HYP_SLOW_SETTINGS = dict(HYP_SETTINGS) -HYP_SLOW_SETTINGS["max_examples"] = 2 - - -@settings(**HYP_SLOW_SETTINGS) -@given(st.integers(min_value=1, max_value=r - 1)) -def test_p192_mult_tests(multiple): - inv_m = inverse_mod(multiple, r) - - p1 = p192 * multiple - assert p1 * inv_m == p192 - - -def add_n_times(point, n): - ret = INFINITY - i = 0 - while i <= n: - yield ret - ret = ret + point - i += 1 - - -# From X9.62 I.1 (p. 96): -@pytest.mark.parametrize( - "p, m, check", - [(g_23, n, exp) for n, exp in enumerate(add_n_times(g_23, 8))], - ids=["g_23 test with mult {0}".format(i) for i in range(9)], -) -def test_add_and_mult_equivalence(p, m, check): - assert p * m == check - - -class TestCurve(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.c_23 = CurveFp(23, 1, 1) - - def test_equality_curves(self): - self.assertEqual(self.c_23, CurveFp(23, 1, 1)) - - def test_inequality_curves(self): - c192 = CurveFp(p, -3, b) - self.assertNotEqual(self.c_23, c192) - - def test_inequality_curves_by_b_only(self): - a = CurveFp(23, 1, 0) - b = CurveFp(23, 1, 1) - self.assertNotEqual(a, b) - - def test_usability_in_a_hashed_collection_curves(self): - {self.c_23: None} - - def test_hashability_curves(self): - hash(self.c_23) - - def test_conflation_curves(self): - ne1, ne2, ne3 = CurveFp(24, 1, 1), CurveFp(23, 2, 1), CurveFp(23, 1, 2) - eq1, eq2, eq3 = CurveFp(23, 1, 1), CurveFp(23, 1, 1), self.c_23 - self.assertEqual(len(set((c_23, eq1, eq2, eq3))), 1) - self.assertEqual(len(set((c_23, ne1, ne2, ne3))), 4) - self.assertDictEqual({c_23: None}, {eq1: None}) - self.assertIn(eq2, {eq3: None}) - - def test___str__(self): - self.assertEqual(str(self.c_23), "CurveFp(p=23, a=1, b=1)") - - def test___str___with_cofactor(self): - c = CurveFp(23, 1, 1, 4) - self.assertEqual(str(c), "CurveFp(p=23, a=1, b=1, h=4)") - - -class TestCurveEdTw(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.c_23 = CurveEdTw(23, 1, 1) - - def test___str__(self): - self.assertEqual(str(self.c_23), "CurveEdTw(p=23, a=1, d=1)") - - def test___str___with_cofactor(self): - c = CurveEdTw(23, 1, 1, 4) - self.assertEqual(str(c), "CurveEdTw(p=23, a=1, d=1, h=4)") - - def test_usability_in_a_hashed_collection_curves(self): - {self.c_23: None} - - def test_hashability_curves(self): - hash(self.c_23) - - -class TestPoint(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.c_23 = CurveFp(23, 1, 1) - cls.g_23 = Point(cls.c_23, 13, 7, 7) - - p = 6277101735386680763835789423207666416083908700390324961279 - r = 6277101735386680763835789423176059013767194773182842284081 - # s = 0x3045ae6fc8422f64ed579528d38120eae12196d5 - # c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65 - b = 0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1 - Gx = 0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012 - Gy = 0x07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 - - cls.c192 = CurveFp(p, -3, b) - cls.p192 = Point(cls.c192, Gx, Gy, r) - - def test_p192(self): - # Checking against some sample computations presented - # in X9.62: - d = 651056770906015076056810763456358567190100156695615665659 - Q = d * self.p192 - self.assertEqual( - Q.x(), 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5 - ) - - k = 6140507067065001063065065565667405560006161556565665656654 - R = k * self.p192 - self.assertEqual( - R.x(), 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD - ) - self.assertEqual( - R.y(), 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - ) - - u1 = 2563697409189434185194736134579731015366492496392189760599 - u2 = 6266643813348617967186477710235785849136406323338782220568 - temp = u1 * self.p192 + u2 * Q - self.assertEqual( - temp.x(), 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD - ) - self.assertEqual( - temp.y(), 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - ) - - def test_double_infinity(self): - p1 = INFINITY - p3 = p1.double() - self.assertEqual(p1, p3) - self.assertEqual(p3.x(), p1.x()) - self.assertEqual(p3.y(), p3.y()) - - def test_double(self): - x1, y1, x3, y3 = (3, 10, 7, 12) - - p1 = Point(self.c_23, x1, y1) - p3 = p1.double() - self.assertEqual(p3.x(), x3) - self.assertEqual(p3.y(), y3) - - def test_double_to_infinity(self): - p1 = Point(self.c_23, 11, 20) - p2 = p1.double() - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2.double() - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_add_self_to_infinity(self): - p1 = Point(self.c_23, 11, 20) - p2 = p1 + p1 - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2 + p2 - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_mul_to_infinity(self): - p1 = Point(self.c_23, 11, 20) - p2 = p1 * 2 - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2 * 2 - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_multiply(self): - x1, y1, m, x3, y3 = (3, 10, 2, 7, 12) - p1 = Point(self.c_23, x1, y1) - p3 = p1 * m - self.assertEqual(p3.x(), x3) - self.assertEqual(p3.y(), y3) - - # Trivial tests from X9.62 B.3: - def test_add(self): - """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" - - x1, y1, x2, y2, x3, y3 = (3, 10, 9, 7, 17, 20) - p1 = Point(self.c_23, x1, y1) - p2 = Point(self.c_23, x2, y2) - p3 = p1 + p2 - self.assertEqual(p3.x(), x3) - self.assertEqual(p3.y(), y3) - - def test_add_as_double(self): - """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" - - x1, y1, x2, y2, x3, y3 = (3, 10, 3, 10, 7, 12) - p1 = Point(self.c_23, x1, y1) - p2 = Point(self.c_23, x2, y2) - p3 = p1 + p2 - self.assertEqual(p3.x(), x3) - self.assertEqual(p3.y(), y3) - - def test_equality_points(self): - self.assertEqual(self.g_23, Point(self.c_23, 13, 7, 7)) - - def test_inequality_points(self): - c = CurveFp(100, -3, 100) - p = Point(c, 100, 100, 100) - self.assertNotEqual(self.g_23, p) - - def test_inequality_points_diff_types(self): - c = CurveFp(100, -3, 100) - self.assertNotEqual(self.g_23, c) - - def test_inequality_diff_y(self): - p1 = Point(self.c_23, 6, 4) - p2 = Point(self.c_23, 6, 19) - - self.assertNotEqual(p1, p2) - - def test_to_bytes_from_bytes(self): - p = Point(self.c_23, 3, 10) - - self.assertEqual(p, Point.from_bytes(self.c_23, p.to_bytes())) - - def test_add_to_neg_self(self): - p = Point(self.c_23, 3, 10) - - self.assertEqual(INFINITY, p + (-p)) - - def test_add_to_infinity(self): - p = Point(self.c_23, 3, 10) - - self.assertIs(p, p + INFINITY) - - def test_mul_infinity_by_scalar(self): - self.assertIs(INFINITY, INFINITY * 10) - - def test_mul_by_negative(self): - p = Point(self.c_23, 3, 10) - - self.assertEqual(p * -5, (-p) * 5) - - def test_str_infinity(self): - self.assertEqual(str(INFINITY), "infinity") - - def test_str_point(self): - p = Point(self.c_23, 3, 10) - - self.assertEqual(str(p), "(3,10)") diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_jacobi.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_jacobi.py deleted file mode 100644 index f811b92..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_jacobi.py +++ /dev/null @@ -1,934 +0,0 @@ -import pickle -import sys - -try: - import unittest2 as unittest -except ImportError: - import unittest - -import os -import signal -import pytest -import threading -import platform -import hypothesis.strategies as st -from hypothesis import given, assume, settings, example - -from .ellipticcurve import CurveFp, PointJacobi, INFINITY, Point -from .ecdsa import ( - generator_256, - curve_256, - generator_224, - generator_brainpoolp160r1, - curve_brainpoolp160r1, - generator_112r2, - curve_112r2, -) -from .numbertheory import inverse_mod -from .util import randrange - - -NO_OLD_SETTINGS = {} -if sys.version_info > (2, 7): # pragma: no branch - NO_OLD_SETTINGS["deadline"] = 5000 - - -SLOW_SETTINGS = {} -if "--fast" in sys.argv: # pragma: no cover - SLOW_SETTINGS["max_examples"] = 2 -else: - SLOW_SETTINGS["max_examples"] = 10 - - -class TestJacobi(unittest.TestCase): - def test___init__(self): - curve = object() - x = 2 - y = 3 - z = 1 - order = 4 - pj = PointJacobi(curve, x, y, z, order) - - self.assertEqual(pj.order(), order) - self.assertIs(pj.curve(), curve) - self.assertEqual(pj.x(), x) - self.assertEqual(pj.y(), y) - - def test_add_with_different_curves(self): - p_a = PointJacobi.from_affine(generator_256) - p_b = PointJacobi.from_affine(generator_224) - - with self.assertRaises(ValueError): # pragma: no branch - p_a + p_b - - def test_compare_different_curves(self): - self.assertNotEqual(generator_256, generator_224) - - def test_equality_with_non_point(self): - pj = PointJacobi.from_affine(generator_256) - - self.assertNotEqual(pj, "value") - - def test_conversion(self): - pj = PointJacobi.from_affine(generator_256) - pw = pj.to_affine() - - self.assertEqual(generator_256, pw) - - def test_single_double(self): - pj = PointJacobi.from_affine(generator_256) - pw = generator_256.double() - - pj = pj.double() - - self.assertEqual(pj.x(), pw.x()) - self.assertEqual(pj.y(), pw.y()) - - def test_double_with_zero_point(self): - pj = PointJacobi(curve_256, 0, 0, 1) - - pj = pj.double() - - self.assertIs(pj, INFINITY) - - def test_double_with_zero_equivalent_point(self): - pj = PointJacobi(curve_256, 0, 0, 0) - - pj = pj.double() - - self.assertIs(pj, INFINITY) - - def test_double_with_zero_equivalent_point_non_zero_z_non_zero_y(self): - pj = PointJacobi(curve_256, 0, 1, curve_256.p()) - - pj = pj.double() - - self.assertIs(pj, INFINITY) - - def test_double_with_zero_equivalent_point_non_zero_z(self): - pj = PointJacobi(curve_256, 0, 0, curve_256.p()) - - pj = pj.double() - - self.assertIs(pj, INFINITY) - - def test_compare_with_affine_point(self): - pj = PointJacobi.from_affine(generator_256) - pa = pj.to_affine() - - self.assertEqual(pj, pa) - self.assertEqual(pa, pj) - - def test_to_affine_with_zero_point(self): - pj = PointJacobi(curve_256, 0, 0, 0) - - pa = pj.to_affine() - - self.assertIs(pa, INFINITY) - - def test_add_with_affine_point(self): - pj = PointJacobi.from_affine(generator_256) - pa = pj.to_affine() - - s = pj + pa - - self.assertEqual(s, pj.double()) - - def test_radd_with_affine_point(self): - pj = PointJacobi.from_affine(generator_256) - pa = pj.to_affine() - - s = pa + pj - - self.assertEqual(s, pj.double()) - - def test_add_with_infinity(self): - pj = PointJacobi.from_affine(generator_256) - - s = pj + INFINITY - - self.assertEqual(s, pj) - - def test_add_zero_point_to_affine(self): - pa = PointJacobi.from_affine(generator_256).to_affine() - pj = PointJacobi(curve_256, 0, 0, 0) - - s = pj + pa - - self.assertIs(s, pa) - - def test_multiply_by_zero(self): - pj = PointJacobi.from_affine(generator_256) - - pj = pj * 0 - - self.assertIs(pj, INFINITY) - - def test_zero_point_multiply_by_one(self): - pj = PointJacobi(curve_256, 0, 0, 1) - - pj = pj * 1 - - self.assertIs(pj, INFINITY) - - def test_multiply_by_one(self): - pj = PointJacobi.from_affine(generator_256) - pw = generator_256 * 1 - - pj = pj * 1 - - self.assertEqual(pj.x(), pw.x()) - self.assertEqual(pj.y(), pw.y()) - - def test_multiply_by_two(self): - pj = PointJacobi.from_affine(generator_256) - pw = generator_256 * 2 - - pj = pj * 2 - - self.assertEqual(pj.x(), pw.x()) - self.assertEqual(pj.y(), pw.y()) - - def test_rmul_by_two(self): - pj = PointJacobi.from_affine(generator_256) - pw = generator_256 * 2 - - pj = 2 * pj - - self.assertEqual(pj, pw) - - def test_compare_non_zero_with_infinity(self): - pj = PointJacobi.from_affine(generator_256) - - self.assertNotEqual(pj, INFINITY) - - def test_compare_non_zero_bad_scale_with_infinity(self): - pj = PointJacobi(curve_256, 1, 1, 0) - self.assertEqual(pj, INFINITY) - - def test_eq_x_0_on_curve_with_infinity(self): - c_23 = CurveFp(23, 1, 1) - pj = PointJacobi(c_23, 0, 1, 1) - - self.assertTrue(c_23.contains_point(0, 1)) - - self.assertNotEqual(pj, INFINITY) - - def test_eq_y_0_on_curve_with_infinity(self): - c_23 = CurveFp(23, 1, 1) - pj = PointJacobi(c_23, 4, 0, 1) - - self.assertTrue(c_23.contains_point(4, 0)) - - self.assertNotEqual(pj, INFINITY) - - def test_eq_with_same_x_different_y(self): - c_23 = CurveFp(23, 1, 1) - p_a = PointJacobi(c_23, 0, 22, 1) - p_b = PointJacobi(c_23, 0, 1, 1) - - self.assertNotEqual(p_a, p_b) - - def test_compare_zero_point_with_infinity(self): - pj = PointJacobi(curve_256, 0, 0, 0) - - self.assertEqual(pj, INFINITY) - - def test_compare_double_with_multiply(self): - pj = PointJacobi.from_affine(generator_256) - dbl = pj.double() - mlpl = pj * 2 - - self.assertEqual(dbl, mlpl) - - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1) - ) - ) - def test_multiplications(self, mul): - pj = PointJacobi.from_affine(generator_brainpoolp160r1) - pw = pj.to_affine() * mul - - pj = pj * mul - - self.assertEqual((pj.x(), pj.y()), (pw.x(), pw.y())) - self.assertEqual(pj, pw) - - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1) - ) - ) - @example(0) - @example(int(generator_brainpoolp160r1.order())) - def test_precompute(self, mul): - precomp = generator_brainpoolp160r1 - self.assertTrue(precomp._PointJacobi__precompute) - pj = PointJacobi.from_affine(generator_brainpoolp160r1) - - a = precomp * mul - b = pj * mul - - self.assertEqual(a, b) - - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - ) - @example(3, 3) - def test_add_scaled_points(self, a_mul, b_mul): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1) - a = PointJacobi.from_affine(j_g * a_mul) - b = PointJacobi.from_affine(j_g * b_mul) - - c = a + b - - self.assertEqual(c, j_g * (a_mul + b_mul)) - - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)), - ) - def test_add_one_scaled_point(self, a_mul, b_mul, new_z): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1) - a = PointJacobi.from_affine(j_g * a_mul) - b = PointJacobi.from_affine(j_g * b_mul) - - p = curve_brainpoolp160r1.p() - - assume(inverse_mod(new_z, p)) - - new_zz = new_z * new_z % p - - b = PointJacobi( - curve_brainpoolp160r1, - b.x() * new_zz % p, - b.y() * new_zz * new_z % p, - new_z, - ) - - c = a + b - - self.assertEqual(c, j_g * (a_mul + b_mul)) - - @pytest.mark.slow - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)), - ) - @example(1, 1, 1) - @example(3, 3, 3) - @example(2, int(generator_brainpoolp160r1.order() - 2), 1) - @example(2, int(generator_brainpoolp160r1.order() - 2), 3) - def test_add_same_scale_points(self, a_mul, b_mul, new_z): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1) - a = PointJacobi.from_affine(j_g * a_mul) - b = PointJacobi.from_affine(j_g * b_mul) - - p = curve_brainpoolp160r1.p() - - assume(inverse_mod(new_z, p)) - - new_zz = new_z * new_z % p - - a = PointJacobi( - curve_brainpoolp160r1, - a.x() * new_zz % p, - a.y() * new_zz * new_z % p, - new_z, - ) - b = PointJacobi( - curve_brainpoolp160r1, - b.x() * new_zz % p, - b.y() * new_zz * new_z % p, - new_z, - ) - - c = a + b - - self.assertEqual(c, j_g * (a_mul + b_mul)) - - def test_add_same_scale_points_static(self): - j_g = generator_brainpoolp160r1 - p = curve_brainpoolp160r1.p() - a = j_g * 11 - a.scale() - z1 = 13 - x = PointJacobi( - curve_brainpoolp160r1, - a.x() * z1**2 % p, - a.y() * z1**3 % p, - z1, - ) - y = PointJacobi( - curve_brainpoolp160r1, - a.x() * z1**2 % p, - a.y() * z1**3 % p, - z1, - ) - - c = a + a - - self.assertEqual(c, x + y) - - @pytest.mark.slow - @settings(**SLOW_SETTINGS) - @given( - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) - ), - st.lists( - st.integers( - min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1) - ), - min_size=2, - max_size=2, - unique=True, - ), - ) - @example(2, 2, [2, 1]) - @example(2, 2, [2, 3]) - @example(2, int(generator_brainpoolp160r1.order() - 2), [2, 3]) - @example(2, int(generator_brainpoolp160r1.order() - 2), [2, 1]) - def test_add_different_scale_points(self, a_mul, b_mul, new_z): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1) - a = PointJacobi.from_affine(j_g * a_mul) - b = PointJacobi.from_affine(j_g * b_mul) - - p = curve_brainpoolp160r1.p() - - assume(inverse_mod(new_z[0], p)) - assume(inverse_mod(new_z[1], p)) - - new_zz0 = new_z[0] * new_z[0] % p - new_zz1 = new_z[1] * new_z[1] % p - - a = PointJacobi( - curve_brainpoolp160r1, - a.x() * new_zz0 % p, - a.y() * new_zz0 * new_z[0] % p, - new_z[0], - ) - b = PointJacobi( - curve_brainpoolp160r1, - b.x() * new_zz1 % p, - b.y() * new_zz1 * new_z[1] % p, - new_z[1], - ) - - c = a + b - - self.assertEqual(c, j_g * (a_mul + b_mul)) - - def test_add_different_scale_points_static(self): - j_g = generator_brainpoolp160r1 - p = curve_brainpoolp160r1.p() - a = j_g * 11 - a.scale() - z1 = 13 - x = PointJacobi( - curve_brainpoolp160r1, - a.x() * z1**2 % p, - a.y() * z1**3 % p, - z1, - ) - z2 = 29 - y = PointJacobi( - curve_brainpoolp160r1, - a.x() * z2**2 % p, - a.y() * z2**3 % p, - z2, - ) - - c = a + a - - self.assertEqual(c, x + y) - - def test_add_different_points_same_scale_static(self): - j_g = generator_brainpoolp160r1 - p = curve_brainpoolp160r1.p() - a = j_g * 11 - a.scale() - b = j_g * 12 - z = 13 - x = PointJacobi( - curve_brainpoolp160r1, - a.x() * z**2 % p, - a.y() * z**3 % p, - z, - ) - y = PointJacobi( - curve_brainpoolp160r1, - b.x() * z**2 % p, - b.y() * z**3 % p, - z, - ) - - c = a + b - - self.assertEqual(c, x + y) - - def test_add_same_point_different_scale_second_z_1_static(self): - j_g = generator_112r2 - p = curve_112r2.p() - z = 11 - a = j_g * z - a.scale() - - x = PointJacobi( - curve_112r2, - a.x() * z**2 % p, - a.y() * z**3 % p, - z, - ) - y = PointJacobi( - curve_112r2, - a.x(), - a.y(), - 1, - ) - - c = a + a - - self.assertEqual(c, x + y) - - def test_add_to_infinity_static(self): - j_g = generator_112r2 - - z = 11 - a = j_g * z - a.scale() - - b = -a - - x = PointJacobi( - curve_112r2, - a.x(), - a.y(), - 1, - ) - y = PointJacobi( - curve_112r2, - b.x(), - b.y(), - 1, - ) - - self.assertEqual(INFINITY, x + y) - - def test_add_point_3_times(self): - j_g = PointJacobi.from_affine(generator_256) - - self.assertEqual(j_g * 3, j_g + j_g + j_g) - - def test_mul_without_order(self): - j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1) - - self.assertEqual(j_g * generator_256.order(), INFINITY) - - def test_mul_add_inf(self): - j_g = PointJacobi.from_affine(generator_256) - - self.assertEqual(j_g, j_g.mul_add(1, INFINITY, 1)) - - def test_mul_add_same(self): - j_g = PointJacobi.from_affine(generator_256) - - self.assertEqual(j_g * 2, j_g.mul_add(1, j_g, 1)) - - def test_mul_add_precompute(self): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True) - b = PointJacobi.from_affine(j_g * 255, True) - - self.assertEqual(j_g * 256, j_g + b) - self.assertEqual(j_g * (5 + 255 * 7), j_g * 5 + b * 7) - self.assertEqual(j_g * (5 + 255 * 7), j_g.mul_add(5, b, 7)) - - def test_mul_add_precompute_large(self): - j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True) - b = PointJacobi.from_affine(j_g * 255, True) - - self.assertEqual(j_g * 256, j_g + b) - self.assertEqual( - j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0 - ) - self.assertEqual( - j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0) - ) - - def test_mul_add_to_mul(self): - j_g = PointJacobi.from_affine(generator_256) - - a = j_g * 3 - b = j_g.mul_add(2, j_g, 1) - - self.assertEqual(a, b) - - def test_mul_add_differnt(self): - j_g = PointJacobi.from_affine(generator_256) - - w_a = j_g * 2 - - self.assertEqual(j_g.mul_add(1, w_a, 1), j_g * 3) - - def test_mul_add_slightly_different(self): - j_g = PointJacobi.from_affine(generator_256) - - w_a = j_g * 2 - w_b = j_g * 3 - - self.assertEqual(w_a.mul_add(1, w_b, 3), w_a * 1 + w_b * 3) - - def test_mul_add(self): - j_g = PointJacobi.from_affine(generator_256) - - w_a = generator_256 * 255 - w_b = generator_256 * (0xA8 * 0xF0) - j_b = j_g * 0xA8 - - ret = j_g.mul_add(255, j_b, 0xF0) - - self.assertEqual(ret.to_affine(), w_a + w_b) - - def test_mul_add_zero(self): - j_g = PointJacobi.from_affine(generator_256) - - w_a = generator_256 * 255 - w_b = generator_256 * (0 * 0xA8) - - j_b = j_g * 0xA8 - - ret = j_g.mul_add(255, j_b, 0) - - self.assertEqual(ret.to_affine(), w_a + w_b) - - def test_mul_add_large(self): - j_g = PointJacobi.from_affine(generator_256) - b = PointJacobi.from_affine(j_g * 255) - - self.assertEqual(j_g * 256, j_g + b) - self.assertEqual( - j_g * (0xFF00 + 255 * 0xF0F0), j_g * 0xFF00 + b * 0xF0F0 - ) - self.assertEqual( - j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0) - ) - - def test_mul_add_with_infinity_as_result(self): - j_g = PointJacobi.from_affine(generator_256) - - order = generator_256.order() - - b = PointJacobi.from_affine(generator_256 * 256) - - self.assertEqual(j_g.mul_add(order % 256, b, order // 256), INFINITY) - - def test_mul_add_without_order(self): - j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1) - - order = generator_256.order() - - w_b = generator_256 * 34 - w_b.scale() - - b = PointJacobi(curve_256, w_b.x(), w_b.y(), 1) - - self.assertEqual(j_g.mul_add(order % 34, b, order // 34), INFINITY) - - def test_mul_add_with_doubled_negation_of_itself(self): - j_g = PointJacobi.from_affine(generator_256 * 17) - - dbl_neg = 2 * (-j_g) - - self.assertEqual(j_g.mul_add(4, dbl_neg, 2), INFINITY) - - @given( - st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)), - st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)), - st.integers(min_value=0, max_value=int(generator_112r2.order() - 1)), - ) - @example(693, 2, 3293) # values that will hit all the conditions for NAF - def test_mul_add_random(self, mul1, mul2, mul3): - p_a = PointJacobi.from_affine(generator_112r2) - p_b = generator_112r2 * mul2 - - res = p_a.mul_add(mul1, p_b, mul3) - - self.assertEqual(res, p_a * mul1 + p_b * mul3) - - def test_equality(self): - pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) - pj2 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) - self.assertEqual(pj1, pj2) - - def test_equality_with_invalid_object(self): - j_g = PointJacobi.from_affine(generator_256) - - self.assertNotEqual(j_g, 12) - - def test_equality_with_wrong_curves(self): - p_a = PointJacobi.from_affine(generator_256) - p_b = PointJacobi.from_affine(generator_224) - - self.assertNotEqual(p_a, p_b) - - def test_add_with_point_at_infinity(self): - pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) - x, y, z = pj1._add(2, 3, 1, 5, 5, 0, 23) - - self.assertEqual((x, y, z), (2, 3, 1)) - - def test_double_to_infinity(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 11, 20, 1) - p2 = p.double() - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2.double() - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_double_to_x_0(self): - c_23_2 = CurveFp(23, 1, 2) - p = PointJacobi(c_23_2, 9, 2, 1) - p2 = p.double() - - self.assertEqual((p2.x(), p2.y()), (0, 18)) - - def test_mul_to_infinity(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 11, 20, 1) - p2 = p * 2 - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2 * 2 - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_add_to_infinity(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 11, 20, 1) - p2 = p + p - self.assertEqual((p2.x(), p2.y()), (4, 0)) - self.assertNotEqual(p2, INFINITY) - p3 = p2 + p2 - self.assertEqual(p3, INFINITY) - self.assertIs(p3, INFINITY) - - def test_mul_to_x_0(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 9, 7, 1) - - p2 = p * 13 - self.assertEqual((p2.x(), p2.y()), (0, 22)) - - def test_mul_to_y_0(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 9, 7, 1) - - p2 = p * 14 - self.assertEqual((p2.x(), p2.y()), (4, 0)) - - def test_add_to_x_0(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 9, 7, 1) - - p2 = p * 12 + p - self.assertEqual((p2.x(), p2.y()), (0, 22)) - - def test_add_to_y_0(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 9, 7, 1) - - p2 = p * 13 + p - self.assertEqual((p2.x(), p2.y()), (4, 0)) - - def test_add_diff_z_to_infinity(self): - c_23 = CurveFp(23, 1, 1) - p = PointJacobi(c_23, 9, 7, 1) - - c = p * 20 + p * 8 - self.assertIs(c, INFINITY) - - def test_pickle(self): - pj = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) - self.assertEqual(pickle.loads(pickle.dumps(pj)), pj) - - @pytest.mark.slow - @settings(**NO_OLD_SETTINGS) - @pytest.mark.skipif( - platform.python_implementation() == "PyPy", - reason="threading on PyPy breaks coverage", - ) - @given(st.integers(min_value=1, max_value=10)) - def test_multithreading(self, thread_num): # pragma: no cover - # ensure that generator's precomputation table is filled - generator_112r2 * 2 - - # create a fresh point that doesn't have a filled precomputation table - gen = generator_112r2 - gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True) - - self.assertEqual(gen._PointJacobi__precompute, []) - - def runner(generator): - order = generator.order() - for _ in range(10): - generator * randrange(order) - - threads = [] - for _ in range(thread_num): - threads.append(threading.Thread(target=runner, args=(gen,))) - - for t in threads: - t.start() - - runner(gen) - - for t in threads: - t.join() - - self.assertEqual( - gen._PointJacobi__precompute, - generator_112r2._PointJacobi__precompute, - ) - - @pytest.mark.slow - @pytest.mark.skipif( - platform.system() == "Windows" - or platform.python_implementation() == "PyPy", - reason="there are no signals on Windows, and threading breaks coverage" - " on PyPy", - ) - def test_multithreading_with_interrupts(self): # pragma: no cover - thread_num = 10 - # ensure that generator's precomputation table is filled - generator_112r2 * 2 - - # create a fresh point that doesn't have a filled precomputation table - gen = generator_112r2 - gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True) - - self.assertEqual(gen._PointJacobi__precompute, []) - - def runner(generator): - order = generator.order() - for _ in range(50): - generator * randrange(order) - - def interrupter(barrier_start, barrier_end, lock_exit): - # wait until MainThread can handle KeyboardInterrupt - barrier_start.release() - barrier_end.acquire() - os.kill(os.getpid(), signal.SIGINT) - lock_exit.release() - - threads = [] - for _ in range(thread_num): - threads.append(threading.Thread(target=runner, args=(gen,))) - - barrier_start = threading.Lock() - barrier_start.acquire() - barrier_end = threading.Lock() - barrier_end.acquire() - lock_exit = threading.Lock() - lock_exit.acquire() - - threads.append( - threading.Thread( - target=interrupter, - args=(barrier_start, barrier_end, lock_exit), - ) - ) - - for t in threads: - t.start() - - with self.assertRaises(KeyboardInterrupt): - # signal to interrupter that we can now handle the signal - barrier_start.acquire() - barrier_end.release() - runner(gen) - # use the lock to ensure we never go past the scope of - # assertRaises before the os.kill is called - lock_exit.acquire() - - for t in threads: - t.join() - - self.assertEqual( - gen._PointJacobi__precompute, - generator_112r2._PointJacobi__precompute, - ) - - -class TestZeroCurve(unittest.TestCase): - """Tests with curve that has (0, 0) on the curve.""" - - def setUp(self): - self.curve = CurveFp(23, 1, 0) - - def test_zero_point_on_curve(self): - self.assertTrue(self.curve.contains_point(0, 0)) - - def test_double_to_0_0_point(self): - p = PointJacobi(self.curve, 1, 18, 1) - - d = p.double() - - self.assertNotEqual(d, INFINITY) - self.assertEqual((0, 0), (d.x(), d.y())) - - def test_double_to_0_0_point_with_non_one_z(self): - z = 2 - p = PointJacobi(self.curve, 1 * z**2, 18 * z**3, z) - - d = p.double() - - self.assertNotEqual(d, INFINITY) - self.assertEqual((0, 0), (d.x(), d.y())) - - def test_mul_to_0_0_point(self): - p = PointJacobi(self.curve, 11, 13, 1) - - d = p * 12 - - self.assertNotEqual(d, INFINITY) - self.assertEqual((0, 0), (d.x(), d.y())) - - def test_double_of_0_0_point(self): - p = PointJacobi(self.curve, 0, 0, 1) - - d = p.double() - - self.assertIs(d, INFINITY) - - def test_compare_to_old_implementation(self): - p = PointJacobi(self.curve, 11, 13, 1) - p_c = Point(self.curve, 11, 13) - - for i in range(24): - self.assertEqual(p * i, p_c * i) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_keys.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_keys.py deleted file mode 100644 index 348475e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_keys.py +++ /dev/null @@ -1,1138 +0,0 @@ -try: - import unittest2 as unittest -except ImportError: - import unittest - -try: - buffer -except NameError: - buffer = memoryview - -import os -import array -import pytest -import hashlib - -from .keys import ( - VerifyingKey, - SigningKey, - MalformedPointError, - BadSignatureError, -) -from .der import ( - unpem, - UnexpectedDER, - encode_sequence, - encode_oid, - encode_bitstring, - encode_integer, - encode_octet_string, -) -from .util import ( - sigencode_string, - sigencode_der, - sigencode_strings, - sigdecode_string, - sigdecode_der, - sigdecode_strings, -) -from .curves import NIST256p, Curve, BRAINPOOLP160r1, Ed25519, Ed448 -from .ellipticcurve import Point, PointJacobi, CurveFp, INFINITY -from .ecdsa import generator_brainpoolp160r1 - - -class TestVerifyingKeyFromString(unittest.TestCase): - """ - Verify that ecdsa.keys.VerifyingKey.from_string() can be used with - bytes-like objects - """ - - @classmethod - def setUpClass(cls): - cls.key_bytes = ( - b"\x04L\xa2\x95\xdb\xc7Z\xd7\x1f\x93\nz\xcf\x97\xcf" - b"\xd7\xc2\xd9o\xfe8}X!\xae\xd4\xfah\xfa^\rpI\xba\xd1" - b"Y\xfb\x92xa\xebo+\x9cG\xfav\xca" - ) - cls.vk = VerifyingKey.from_string(cls.key_bytes) - - def test_bytes(self): - self.assertIsNotNone(self.vk) - self.assertIsInstance(self.vk, VerifyingKey) - self.assertEqual( - self.vk.pubkey.point.x(), - 105419898848891948935835657980914000059957975659675736097, - ) - self.assertEqual( - self.vk.pubkey.point.y(), - 4286866841217412202667522375431381222214611213481632495306, - ) - - def test_bytes_memoryview(self): - vk = VerifyingKey.from_string(buffer(self.key_bytes)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytearray(self): - vk = VerifyingKey.from_string(bytearray(self.key_bytes)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytesarray_memoryview(self): - vk = VerifyingKey.from_string(buffer(bytearray(self.key_bytes))) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_bytes(self): - arr = array.array("B", self.key_bytes) - vk = VerifyingKey.from_string(arr) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_bytes_memoryview(self): - arr = array.array("B", self.key_bytes) - vk = VerifyingKey.from_string(buffer(arr)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_ints(self): - arr = array.array("I", self.key_bytes) - vk = VerifyingKey.from_string(arr) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_ints_memoryview(self): - arr = array.array("I", self.key_bytes) - vk = VerifyingKey.from_string(buffer(arr)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytes_uncompressed(self): - vk = VerifyingKey.from_string(b"\x04" + self.key_bytes) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytearray_uncompressed(self): - vk = VerifyingKey.from_string(bytearray(b"\x04" + self.key_bytes)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytes_compressed(self): - vk = VerifyingKey.from_string(b"\x02" + self.key_bytes[:24]) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytearray_compressed(self): - vk = VerifyingKey.from_string(bytearray(b"\x02" + self.key_bytes[:24])) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_ed25519_VerifyingKey_from_string_imported(self): - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"AAA", Ed25519) - - -class TestVerifyingKeyFromDer(unittest.TestCase): - """ - Verify that ecdsa.keys.VerifyingKey.from_der() can be used with - bytes-like objects. - """ - - @classmethod - def setUpClass(cls): - prv_key_str = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" - "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" - "bA==\n" - "-----END EC PRIVATE KEY-----\n" - ) - key_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEuIF30ITvF/XkVjlAgCg2D59ZtKTX\n" - "Jk5i2gZR3OR6NaTFtFz1FZNCOotVe5wgmfNs\n" - "-----END PUBLIC KEY-----\n" - ) - cls.key_pem = key_str - - cls.key_bytes = unpem(key_str) - assert isinstance(cls.key_bytes, bytes) - cls.vk = VerifyingKey.from_pem(key_str) - cls.sk = SigningKey.from_pem(prv_key_str) - - key_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4H3iRbG4TSrsSRb/gusPQB/4YcN8\n" - "Poqzgjau4kfxBPyZimeRfuY/9g/wMmPuhGl4BUve51DsnKJFRr8psk0ieA==\n" - "-----END PUBLIC KEY-----\n" - ) - cls.vk2 = VerifyingKey.from_pem(key_str) - - cls.sk2 = SigningKey.generate(vk.curve) - - def test_load_key_with_explicit_parameters(self): - pub_key_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIr1UkgYs5jmbFc7it1/YI2X\n" - "T//IlaEjMNZft1owjqpBYH2ErJHk4U5Pp4WvWq1xmHwIZlsH7Ig4KmefCfR6SmU=\n" - "-----END PUBLIC KEY-----" - ) - pk = VerifyingKey.from_pem(pub_key_str) - - pk_exp = VerifyingKey.from_string( - b"\x04\x8a\xf5\x52\x48\x18\xb3\x98\xe6\x6c\x57\x3b\x8a\xdd\x7f" - b"\x60\x8d\x97\x4f\xff\xc8\x95\xa1\x23\x30\xd6\x5f\xb7\x5a\x30" - b"\x8e\xaa\x41\x60\x7d\x84\xac\x91\xe4\xe1\x4e\x4f\xa7\x85\xaf" - b"\x5a\xad\x71\x98\x7c\x08\x66\x5b\x07\xec\x88\x38\x2a\x67\x9f" - b"\x09\xf4\x7a\x4a\x65", - curve=NIST256p, - ) - self.assertEqual(pk, pk_exp) - - def test_load_key_with_explicit_with_explicit_disabled(self): - pub_key_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" - "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" - "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" - "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" - "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" - "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIr1UkgYs5jmbFc7it1/YI2X\n" - "T//IlaEjMNZft1owjqpBYH2ErJHk4U5Pp4WvWq1xmHwIZlsH7Ig4KmefCfR6SmU=\n" - "-----END PUBLIC KEY-----" - ) - with self.assertRaises(UnexpectedDER): - VerifyingKey.from_pem( - pub_key_str, valid_curve_encodings=["named_curve"] - ) - - def test_load_key_with_disabled_format(self): - with self.assertRaises(MalformedPointError) as e: - VerifyingKey.from_der(self.key_bytes, valid_encodings=["raw"]) - - self.assertIn("enabled (raw) encodings", str(e.exception)) - - def test_custom_hashfunc(self): - vk = VerifyingKey.from_der(self.key_bytes, hashlib.sha256) - - self.assertIs(vk.default_hashfunc, hashlib.sha256) - - def test_from_pem_with_custom_hashfunc(self): - vk = VerifyingKey.from_pem(self.key_pem, hashlib.sha256) - - self.assertIs(vk.default_hashfunc, hashlib.sha256) - - def test_bytes(self): - vk = VerifyingKey.from_der(self.key_bytes) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytes_memoryview(self): - vk = VerifyingKey.from_der(buffer(self.key_bytes)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytearray(self): - vk = VerifyingKey.from_der(bytearray(self.key_bytes)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_bytesarray_memoryview(self): - vk = VerifyingKey.from_der(buffer(bytearray(self.key_bytes))) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_bytes(self): - arr = array.array("B", self.key_bytes) - vk = VerifyingKey.from_der(arr) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_array_array_of_bytes_memoryview(self): - arr = array.array("B", self.key_bytes) - vk = VerifyingKey.from_der(buffer(arr)) - - self.assertEqual(self.vk.to_string(), vk.to_string()) - - def test_equality_on_verifying_keys(self): - self.assertTrue(self.vk == self.sk.get_verifying_key()) - - def test_inequality_on_verifying_keys(self): - self.assertFalse(self.vk == self.vk2) - - def test_inequality_on_verifying_keys_not_implemented(self): - self.assertFalse(self.vk == None) - - def test_VerifyingKey_inequality_on_same_curve(self): - self.assertNotEqual(self.vk, self.sk2.verifying_key) - - def test_SigningKey_inequality_on_same_curve(self): - self.assertNotEqual(self.sk, self.sk2) - - def test_inequality_on_wrong_types(self): - self.assertFalse(self.vk == self.sk) - - def test_from_public_point_old(self): - pj = self.vk.pubkey.point - point = Point(pj.curve(), pj.x(), pj.y()) - - vk = VerifyingKey.from_public_point(point, self.vk.curve) - - self.assertTrue(vk == self.vk) - - def test_ed25519_VerifyingKey_repr__(self): - sk = SigningKey.from_string(Ed25519.generator.to_bytes(), Ed25519) - string = repr(sk.verifying_key) - - self.assertEqual( - "VerifyingKey.from_string(" - "bytearray(b'K\\x0c\\xfbZH\\x8e\\x8c\\x8c\\x07\\xee\\xda\\xfb" - "\\xe1\\x97\\xcd\\x90\\x18\\x02\\x15h]\\xfe\\xbe\\xcbB\\xba\\xe6r" - "\\x10\\xae\\xf1P'), Ed25519, None)", - string, - ) - - def test_edwards_from_public_point(self): - point = Ed25519.generator - with self.assertRaises(ValueError) as e: - VerifyingKey.from_public_point(point, Ed25519) - - self.assertIn("incompatible with Edwards", str(e.exception)) - - def test_edwards_precompute_no_side_effect(self): - sk = SigningKey.from_string(Ed25519.generator.to_bytes(), Ed25519) - vk = sk.verifying_key - vk2 = VerifyingKey.from_string(vk.to_string(), Ed25519) - vk.precompute() - - self.assertEqual(vk, vk2) - - def test_parse_malfomed_eddsa_der_pubkey(self): - der_str = encode_sequence( - encode_sequence(encode_oid(*Ed25519.oid)), - encode_bitstring(bytes(Ed25519.generator.to_bytes()), 0), - encode_bitstring(b"\x00", 0), - ) - - with self.assertRaises(UnexpectedDER) as e: - VerifyingKey.from_der(der_str) - - self.assertIn("trailing junk after public key", str(e.exception)) - - def test_edwards_from_public_key_recovery(self): - with self.assertRaises(ValueError) as e: - VerifyingKey.from_public_key_recovery(b"", b"", Ed25519) - - self.assertIn("unsupported for Edwards", str(e.exception)) - - def test_edwards_from_public_key_recovery_with_digest(self): - with self.assertRaises(ValueError) as e: - VerifyingKey.from_public_key_recovery_with_digest( - b"", b"", Ed25519 - ) - - self.assertIn("unsupported for Edwards", str(e.exception)) - - def test_load_ed25519_from_pem(self): - vk_pem = ( - "-----BEGIN PUBLIC KEY-----\n" - "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" - "-----END PUBLIC KEY-----\n" - ) - - vk = VerifyingKey.from_pem(vk_pem) - - self.assertIsInstance(vk.curve, Curve) - self.assertIs(vk.curve, Ed25519) - - vk_str = ( - b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" - b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" - ) - - vk_2 = VerifyingKey.from_string(vk_str, Ed25519) - - self.assertEqual(vk, vk_2) - - def test_export_ed255_to_pem(self): - vk_str = ( - b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" - b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" - ) - - vk = VerifyingKey.from_string(vk_str, Ed25519) - - vk_pem = ( - b"-----BEGIN PUBLIC KEY-----\n" - b"MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" - b"-----END PUBLIC KEY-----\n" - ) - - self.assertEqual(vk_pem, vk.to_pem()) - - def test_export_ed255_to_ssh(self): - vk_str = ( - b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" - b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" - ) - - vk = VerifyingKey.from_string(vk_str, Ed25519) - - vk_ssh = b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMAUNDWZCIojuNViX5uQVeNrt5EJu5WJ7yF5gsvKstl\n" - - self.assertEqual(vk_ssh, vk.to_ssh()) - - def test_ed25519_export_import(self): - sk = SigningKey.generate(Ed25519) - vk = sk.verifying_key - - vk2 = VerifyingKey.from_pem(vk.to_pem()) - - self.assertEqual(vk, vk2) - - def test_ed25519_sig_verify(self): - vk_pem = ( - "-----BEGIN PUBLIC KEY-----\n" - "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" - "-----END PUBLIC KEY-----\n" - ) - - vk = VerifyingKey.from_pem(vk_pem) - - data = b"data\n" - - # signature created by OpenSSL 3.0.0 beta1 - sig = ( - b"\x64\x47\xab\x6a\x33\xcd\x79\x45\xad\x98\x11\x6c\xb9\xf2\x20\xeb" - b"\x90\xd6\x50\xe3\xc7\x8f\x9f\x60\x10\xec\x75\xe0\x2f\x27\xd3\x96" - b"\xda\xe8\x58\x7f\xe0\xfe\x46\x5c\x81\xef\x50\xec\x29\x9f\xae\xd5" - b"\xad\x46\x3c\x91\x68\x83\x4d\xea\x8d\xa8\x19\x04\x04\x79\x03\x0b" - ) - - self.assertTrue(vk.verify(sig, data)) - - def test_ed25519_sig_verify_malformed(self): - vk_pem = ( - "-----BEGIN PUBLIC KEY-----\n" - "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" - "-----END PUBLIC KEY-----\n" - ) - - vk = VerifyingKey.from_pem(vk_pem) - - data = b"data\n" - - # modified signature from test_ed25519_sig_verify - sig = ( - b"\xAA\x47\xab\x6a\x33\xcd\x79\x45\xad\x98\x11\x6c\xb9\xf2\x20\xeb" - b"\x90\xd6\x50\xe3\xc7\x8f\x9f\x60\x10\xec\x75\xe0\x2f\x27\xd3\x96" - b"\xda\xe8\x58\x7f\xe0\xfe\x46\x5c\x81\xef\x50\xec\x29\x9f\xae\xd5" - b"\xad\x46\x3c\x91\x68\x83\x4d\xea\x8d\xa8\x19\x04\x04\x79\x03\x0b" - ) - - with self.assertRaises(BadSignatureError): - vk.verify(sig, data) - - def test_ed448_from_pem(self): - pem_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0\n" - "dTdYD2ll94g58MhSnBiBQB9A1MMA\n" - "-----END PUBLIC KEY-----\n" - ) - - vk = VerifyingKey.from_pem(pem_str) - - self.assertIsInstance(vk.curve, Curve) - self.assertIs(vk.curve, Ed448) - - vk_str = ( - b"\x79\x0b\x5e\xb5\x2b\xbb\x08\xc1\x33\x13\xe5\xd6\x07\x5d\x01\x83" - b"\x8e\xcb\x08\x0d\x20\x88\xd8\xa4\x3b\x11\xf3\x76\x9f\xad\x67\xf7" - b"\x8a\xfc\x49\xf4\x75\x37\x58\x0f\x69\x65\xf7\x88\x39\xf0\xc8\x52" - b"\x9c\x18\x81\x40\x1f\x40\xd4\xc3\x00" - ) - - vk2 = VerifyingKey.from_string(vk_str, Ed448) - - self.assertEqual(vk, vk2) - - def test_ed448_to_pem(self): - vk_str = ( - b"\x79\x0b\x5e\xb5\x2b\xbb\x08\xc1\x33\x13\xe5\xd6\x07\x5d\x01\x83" - b"\x8e\xcb\x08\x0d\x20\x88\xd8\xa4\x3b\x11\xf3\x76\x9f\xad\x67\xf7" - b"\x8a\xfc\x49\xf4\x75\x37\x58\x0f\x69\x65\xf7\x88\x39\xf0\xc8\x52" - b"\x9c\x18\x81\x40\x1f\x40\xd4\xc3\x00" - ) - vk = VerifyingKey.from_string(vk_str, Ed448) - - vk_pem = ( - b"-----BEGIN PUBLIC KEY-----\n" - b"MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0dTdYD2ll94g5\n" - b"8MhSnBiBQB9A1MMA\n" - b"-----END PUBLIC KEY-----\n" - ) - - self.assertEqual(vk_pem, vk.to_pem()) - - def test_ed448_export_import(self): - sk = SigningKey.generate(Ed448) - vk = sk.verifying_key - - vk2 = VerifyingKey.from_pem(vk.to_pem()) - - self.assertEqual(vk, vk2) - - def test_ed448_sig_verify(self): - pem_str = ( - "-----BEGIN PUBLIC KEY-----\n" - "MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0\n" - "dTdYD2ll94g58MhSnBiBQB9A1MMA\n" - "-----END PUBLIC KEY-----\n" - ) - - vk = VerifyingKey.from_pem(pem_str) - - data = b"data\n" - - # signature created by OpenSSL 3.0.0 beta1 - sig = ( - b"\x68\xed\x2c\x70\x35\x22\xca\x1c\x35\x03\xf3\xaa\x51\x33\x3d\x00" - b"\xc0\xae\xb0\x54\xc5\xdc\x7f\x6f\x30\x57\xb4\x1d\xcb\xe9\xec\xfa" - b"\xc8\x45\x3e\x51\xc1\xcb\x60\x02\x6a\xd0\x43\x11\x0b\x5f\x9b\xfa" - b"\x32\x88\xb2\x38\x6b\xed\xac\x09\x00\x78\xb1\x7b\x5d\x7e\xf8\x16" - b"\x31\xdd\x1b\x3f\x98\xa0\xce\x19\xe7\xd8\x1c\x9f\x30\xac\x2f\xd4" - b"\x1e\x55\xbf\x21\x98\xf6\x4c\x8c\xbe\x81\xa5\x2d\x80\x4c\x62\x53" - b"\x91\xd5\xee\x03\x30\xc6\x17\x66\x4b\x9e\x0c\x8d\x40\xd0\xad\xae" - b"\x0a\x00" - ) - - self.assertTrue(vk.verify(sig, data)) - - -class TestSigningKey(unittest.TestCase): - """ - Verify that ecdsa.keys.SigningKey.from_der() can be used with - bytes-like objects. - """ - - @classmethod - def setUpClass(cls): - prv_key_str = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" - "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" - "bA==\n" - "-----END EC PRIVATE KEY-----\n" - ) - cls.sk1 = SigningKey.from_pem(prv_key_str) - - prv_key_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBheyEIL1u+SUqlC6YkE\n" - "PKKfVh+lJXcOscWhNAMyAAS4gXfQhO8X9eRWOUCAKDYPn1m0pNcmTmLaBlHc5Ho1\n" - "pMW0XPUVk0I6i1V7nCCZ82w=\n" - "-----END PRIVATE KEY-----\n" - ) - cls.sk1_pkcs8 = SigningKey.from_pem(prv_key_str) - - prv_key_str = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MHcCAQEEIKlL2EAm5NPPZuXwxRf4nXMk0A80y6UUbiQ17be/qFhRoAoGCCqGSM49\n" - "AwEHoUQDQgAE4H3iRbG4TSrsSRb/gusPQB/4YcN8Poqzgjau4kfxBPyZimeRfuY/\n" - "9g/wMmPuhGl4BUve51DsnKJFRr8psk0ieA==\n" - "-----END EC PRIVATE KEY-----\n" - ) - cls.sk2 = SigningKey.from_pem(prv_key_str) - - def test_to_der_pkcs8(self): - self.assertEqual( - self.sk1.to_der(format="pkcs8"), - b"0o\x02\x01\x010\x13\x06\x07*\x86H\xce=\x02\x01\x06\x08*\x86H" - b"\xce=\x03\x01\x01\x04U0S\x02\x01\x01\x04\x18^\xc8B\x0b\xd6\xef" - b"\x92R\xa9B\xe9\x89\x04<\xa2\x9fV\x1f\xa5%w\x0e\xb1\xc5\xa14\x03" - b"2\x00\x04\xb8\x81w\xd0\x84\xef\x17\xf5\xe4V9@\x80(6\x0f\x9fY" - b"\xb4\xa4\xd7&Nb\xda\x06Q\xdc\xe4z5\xa4\xc5\xb4\\\xf5\x15\x93B:" - b"\x8bU{\x9c \x99\xf3l", - ) - - def test_decoding_explicit_curve_parameters(self): - prv_key_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" - "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" - "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" - "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" - "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" - "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgIXtREfUmR16r\n" - "ZbmvDGD2lAEFPZa2DLPyz0czSja58yChRANCAASK9VJIGLOY5mxXO4rdf2CNl0//\n" - "yJWhIzDWX7daMI6qQWB9hKyR5OFOT6eFr1qtcZh8CGZbB+yIOCpnnwn0ekpl\n" - "-----END PRIVATE KEY-----\n" - ) - - sk = SigningKey.from_pem(prv_key_str) - - sk2 = SigningKey.from_string( - b"\x21\x7b\x51\x11\xf5\x26\x47\x5e\xab\x65\xb9\xaf\x0c\x60\xf6" - b"\x94\x01\x05\x3d\x96\xb6\x0c\xb3\xf2\xcf\x47\x33\x4a\x36\xb9" - b"\xf3\x20", - curve=NIST256p, - ) - - self.assertEqual(sk, sk2) - - def test_decoding_explicit_curve_parameters_with_explicit_disabled(self): - prv_key_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" - "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" - "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" - "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" - "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" - "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgIXtREfUmR16r\n" - "ZbmvDGD2lAEFPZa2DLPyz0czSja58yChRANCAASK9VJIGLOY5mxXO4rdf2CNl0//\n" - "yJWhIzDWX7daMI6qQWB9hKyR5OFOT6eFr1qtcZh8CGZbB+yIOCpnnwn0ekpl\n" - "-----END PRIVATE KEY-----\n" - ) - - with self.assertRaises(UnexpectedDER): - SigningKey.from_pem( - prv_key_str, valid_curve_encodings=["named_curve"] - ) - - def test_equality_on_signing_keys(self): - sk = SigningKey.from_secret_exponent( - self.sk1.privkey.secret_multiplier, self.sk1.curve - ) - self.assertEqual(self.sk1, sk) - self.assertEqual(self.sk1_pkcs8, sk) - - def test_verify_with_empty_message(self): - sig = self.sk1.sign(b"") - - self.assertTrue(sig) - - vk = self.sk1.verifying_key - - self.assertTrue(vk.verify(sig, b"")) - - def test_verify_with_precompute(self): - sig = self.sk1.sign(b"message") - - vk = self.sk1.verifying_key - - vk.precompute() - - self.assertTrue(vk.verify(sig, b"message")) - - def test_compare_verifying_key_with_precompute(self): - vk1 = self.sk1.verifying_key - vk1.precompute() - - vk2 = self.sk1_pkcs8.verifying_key - - self.assertEqual(vk1, vk2) - - def test_verify_with_lazy_precompute(self): - sig = self.sk2.sign(b"other message") - - vk = self.sk2.verifying_key - - vk.precompute(lazy=True) - - self.assertTrue(vk.verify(sig, b"other message")) - - def test_inequality_on_signing_keys(self): - self.assertNotEqual(self.sk1, self.sk2) - - def test_inequality_on_signing_keys_not_implemented(self): - self.assertNotEqual(self.sk1, None) - - def test_ed25519_from_pem(self): - pem_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" - "-----END PRIVATE KEY-----\n" - ) - - sk = SigningKey.from_pem(pem_str) - - sk_str = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - - self.assertEqual(sk, sk_str) - - def test_ed25519_from_der_bad_alg_id_params(self): - der_str = encode_sequence( - encode_integer(1), - encode_sequence(encode_oid(*Ed25519.oid), encode_integer(1)), - encode_octet_string(encode_octet_string(b"A" * 32)), - ) - - with self.assertRaises(UnexpectedDER) as e: - SigningKey.from_der(der_str) - - self.assertIn("Non NULL parameters", str(e.exception)) - - def test_ed25519_from_der_junk_after_priv_key(self): - der_str = encode_sequence( - encode_integer(1), - encode_sequence( - encode_oid(*Ed25519.oid), - ), - encode_octet_string(encode_octet_string(b"A" * 32) + b"B"), - ) - - with self.assertRaises(UnexpectedDER) as e: - SigningKey.from_der(der_str) - - self.assertIn( - "trailing junk after the encoded private key", str(e.exception) - ) - - def test_ed25519_sign(self): - sk_str = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - - msg = b"message" - - sig = sk_str.sign(msg, sigencode=sigencode_der) - - self.assertEqual( - sig, - b"\xe1,v\xc9>%\xda\xd2~>\xc3&\na\xf4@|\x9e`X\x11\x13@<\x987\xd4" - b"\r\xb1\xf5\xb3\x15\x7f%i{\xdf}\xdd\xb1\xf3\x02\x7f\x80\x02\xc2" - b'|\xe5\xd6\x06\xc4\n\xa3\xb0\xf6}\xc0\xed)"+E\xaf\x00', - ) - - def test_ed25519_sign_digest_deterministic(self): - sk_str = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - with self.assertRaises(ValueError) as e: - sk_str.sign_digest_deterministic(b"a" * 20) - - self.assertIn("Method unsupported for Edwards", str(e.exception)) - - def test_ed25519_sign_digest(self): - sk_str = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - with self.assertRaises(ValueError) as e: - sk_str.sign_digest(b"a" * 20) - - self.assertIn("Method unsupported for Edwards", str(e.exception)) - - def test_ed25519_sign_number(self): - sk_str = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - with self.assertRaises(ValueError) as e: - sk_str.sign_number(20) - - self.assertIn("Method unsupported for Edwards", str(e.exception)) - - def test_ed25519_to_der_ssleay(self): - pem_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" - "-----END PRIVATE KEY-----\n" - ) - - sk = SigningKey.from_pem(pem_str) - - with self.assertRaises(ValueError) as e: - sk.to_der(format="ssleay") - - self.assertIn("Only PKCS#8 format", str(e.exception)) - - def test_ed25519_to_pem(self): - sk = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - - pem_str = ( - b"-----BEGIN PRIVATE KEY-----\n" - b"MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" - b"-----END PRIVATE KEY-----\n" - ) - - self.assertEqual(sk.to_pem(format="pkcs8"), pem_str) - - def test_ed25519_to_ssh(self): - sk = SigningKey.from_string( - b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" - b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", - Ed25519, - ) - - ssh_str = ( - b"-----BEGIN OPENSSH PRIVATE KEY-----\n" - b"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQyNTUx\n" - b"OQAAACAjAFDQ1mQiKI7jVYl+bkFXja7eRCbuVie8heYLLyrLZQAAAIgAAAAAAAAAAAAAAAtzc2gt\n" - b"ZWQyNTUxOQAAACAjAFDQ1mQiKI7jVYl+bkFXja7eRCbuVie8heYLLyrLZQAAAEA0usfRTtTxvE+M\n" - b"SD4PGXdM/Li+rFRmRRGa19e4Bwv11CMAUNDWZCIojuNViX5uQVeNrt5EJu5WJ7yF5gsvKstlAAAA\n" - b"AAECAwQF\n" - b"-----END OPENSSH PRIVATE KEY-----\n" - ) - - self.assertEqual(sk.to_ssh(), ssh_str) - - def test_ed25519_to_and_from_pem(self): - sk = SigningKey.generate(Ed25519) - - decoded = SigningKey.from_pem(sk.to_pem(format="pkcs8")) - - self.assertEqual(sk, decoded) - - def test_ed25519_custom_entropy(self): - sk = SigningKey.generate(Ed25519, entropy=os.urandom) - - self.assertIsNotNone(sk) - - def test_ed25519_from_secret_exponent(self): - with self.assertRaises(ValueError) as e: - SigningKey.from_secret_exponent(1234567890, curve=Ed25519) - - self.assertIn("don't support setting the secret", str(e.exception)) - - def test_ed448_from_pem(self): - pem_str = ( - "-----BEGIN PRIVATE KEY-----\n" - "MEcCAQAwBQYDK2VxBDsEOTyFuXqFLXgJlV8uDqcOw9nG4IqzLiZ/i5NfBDoHPzmP\n" - "OP0JMYaLGlTzwovmvCDJ2zLaezu9NLz9aQ==\n" - "-----END PRIVATE KEY-----\n" - ) - sk = SigningKey.from_pem(pem_str) - - sk_str = SigningKey.from_string( - b"\x3C\x85\xB9\x7A\x85\x2D\x78\x09\x95\x5F\x2E\x0E\xA7\x0E\xC3\xD9" - b"\xC6\xE0\x8A\xB3\x2E\x26\x7F\x8B\x93\x5F\x04\x3A\x07\x3F\x39\x8F" - b"\x38\xFD\x09\x31\x86\x8B\x1A\x54\xF3\xC2\x8B\xE6\xBC\x20\xC9\xDB" - b"\x32\xDA\x7B\x3B\xBD\x34\xBC\xFD\x69", - Ed448, - ) - - self.assertEqual(sk, sk_str) - - def test_ed448_to_pem(self): - sk = SigningKey.from_string( - b"\x3C\x85\xB9\x7A\x85\x2D\x78\x09\x95\x5F\x2E\x0E\xA7\x0E\xC3\xD9" - b"\xC6\xE0\x8A\xB3\x2E\x26\x7F\x8B\x93\x5F\x04\x3A\x07\x3F\x39\x8F" - b"\x38\xFD\x09\x31\x86\x8B\x1A\x54\xF3\xC2\x8B\xE6\xBC\x20\xC9\xDB" - b"\x32\xDA\x7B\x3B\xBD\x34\xBC\xFD\x69", - Ed448, - ) - pem_str = ( - b"-----BEGIN PRIVATE KEY-----\n" - b"MEcCAQAwBQYDK2VxBDsEOTyFuXqFLXgJlV8uDqcOw9nG4IqzLiZ/i5NfBDoHPzmPOP0JMYaLGlTz\n" - b"wovmvCDJ2zLaezu9NLz9aQ==\n" - b"-----END PRIVATE KEY-----\n" - ) - - self.assertEqual(sk.to_pem(format="pkcs8"), pem_str) - - def test_ed448_encode_decode(self): - sk = SigningKey.generate(Ed448) - - decoded = SigningKey.from_pem(sk.to_pem(format="pkcs8")) - - self.assertEqual(decoded, sk) - - -class TestTrivialCurve(unittest.TestCase): - @classmethod - def setUpClass(cls): - # To test what happens with r or s in signing happens to be zero we - # need to find a scalar that creates one of the points on a curve that - # has x coordinate equal to zero. - # Even for secp112r2 curve that's non trivial so use this toy - # curve, for which we can iterate over all points quickly - curve = CurveFp(163, 84, 58) - gen = PointJacobi(curve, 2, 87, 1, 167, generator=True) - - cls.toy_curve = Curve("toy_p8", curve, gen, (1, 2, 0)) - - cls.sk = SigningKey.from_secret_exponent( - 140, - cls.toy_curve, - hashfunc=hashlib.sha1, - ) - - def test_generator_sanity(self): - gen = self.toy_curve.generator - - self.assertEqual(gen * gen.order(), INFINITY) - - def test_public_key_sanity(self): - self.assertEqual(self.sk.verifying_key.to_string(), b"\x98\x1e") - - def test_deterministic_sign(self): - sig = self.sk.sign_deterministic(b"message") - - self.assertEqual(sig, b"-.") - - self.assertTrue(self.sk.verifying_key.verify(sig, b"message")) - - def test_deterministic_sign_random_message(self): - msg = os.urandom(32) - sig = self.sk.sign_deterministic(msg) - self.assertEqual(len(sig), 2) - self.assertTrue(self.sk.verifying_key.verify(sig, msg)) - - def test_deterministic_sign_that_rises_R_zero_error(self): - # the raised RSZeroError is caught and handled internally by - # sign_deterministic methods - msg = b"\x00\x4f" - sig = self.sk.sign_deterministic(msg) - self.assertEqual(sig, b"\x36\x9e") - self.assertTrue(self.sk.verifying_key.verify(sig, msg)) - - def test_deterministic_sign_that_rises_S_zero_error(self): - msg = b"\x01\x6d" - sig = self.sk.sign_deterministic(msg) - self.assertEqual(sig, b"\x49\x6c") - self.assertTrue(self.sk.verifying_key.verify(sig, msg)) - - -# test VerifyingKey.verify() -prv_key_str = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" - "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" - "bA==\n" - "-----END EC PRIVATE KEY-----\n" -) -key_bytes = unpem(prv_key_str) -assert isinstance(key_bytes, bytes) -sk = SigningKey.from_der(key_bytes) -vk = sk.verifying_key - -data = ( - b"some string for signing" - b"contents don't really matter" - b"but do include also some crazy values: " - b"\x00\x01\t\r\n\x00\x00\x00\xff\xf0" -) -assert len(data) % 4 == 0 -sha1 = hashlib.sha1() -sha1.update(data) -data_hash = sha1.digest() -assert isinstance(data_hash, bytes) -sig_raw = sk.sign(data, sigencode=sigencode_string) -assert isinstance(sig_raw, bytes) -sig_der = sk.sign(data, sigencode=sigencode_der) -assert isinstance(sig_der, bytes) -sig_strings = sk.sign(data, sigencode=sigencode_strings) -assert isinstance(sig_strings[0], bytes) - -verifiers = [] -for modifier, fun in [ - ("bytes", lambda x: x), - ("bytes memoryview", buffer), - ("bytearray", bytearray), - ("bytearray memoryview", lambda x: buffer(bytearray(x))), - ("array.array of bytes", lambda x: array.array("B", x)), - ("array.array of bytes memoryview", lambda x: buffer(array.array("B", x))), - ("array.array of ints", lambda x: array.array("I", x)), - ("array.array of ints memoryview", lambda x: buffer(array.array("I", x))), -]: - if "ints" in modifier: - conv = lambda x: x - else: - conv = fun - for sig_format, signature, decoder, mod_apply in [ - ("raw", sig_raw, sigdecode_string, lambda x: conv(x)), - ("der", sig_der, sigdecode_der, lambda x: conv(x)), - ( - "strings", - sig_strings, - sigdecode_strings, - lambda x: tuple(conv(i) for i in x), - ), - ]: - for method_name, vrf_mthd, vrf_data in [ - ("verify", vk.verify, data), - ("verify_digest", vk.verify_digest, data_hash), - ]: - verifiers.append( - pytest.param( - signature, - decoder, - mod_apply, - fun, - vrf_mthd, - vrf_data, - id="{2}-{0}-{1}".format(modifier, sig_format, method_name), - ) - ) - - -@pytest.mark.parametrize( - "signature,decoder,mod_apply,fun,vrf_mthd,vrf_data", verifiers -) -def test_VerifyingKey_verify( - signature, decoder, mod_apply, fun, vrf_mthd, vrf_data -): - sig = mod_apply(signature) - - assert vrf_mthd(sig, fun(vrf_data), sigdecode=decoder) - - -# test SigningKey.from_string() -prv_key_bytes = ( - b"^\xc8B\x0b\xd6\xef\x92R\xa9B\xe9\x89\x04<\xa2" - b"\x9fV\x1f\xa5%w\x0e\xb1\xc5" -) -assert len(prv_key_bytes) == 24 -converters = [] -for modifier, convert in [ - ("bytes", lambda x: x), - ("bytes memoryview", buffer), - ("bytearray", bytearray), - ("bytearray memoryview", lambda x: buffer(bytearray(x))), - ("array.array of bytes", lambda x: array.array("B", x)), - ("array.array of bytes memoryview", lambda x: buffer(array.array("B", x))), - ("array.array of ints", lambda x: array.array("I", x)), - ("array.array of ints memoryview", lambda x: buffer(array.array("I", x))), -]: - converters.append(pytest.param(convert, id=modifier)) - - -@pytest.mark.parametrize("convert", converters) -def test_SigningKey_from_string(convert): - key = convert(prv_key_bytes) - sk = SigningKey.from_string(key) - - assert sk.to_string() == prv_key_bytes - - -# test SigningKey.from_der() -prv_key_str = ( - "-----BEGIN EC PRIVATE KEY-----\n" - "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" - "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" - "bA==\n" - "-----END EC PRIVATE KEY-----\n" -) -key_bytes = unpem(prv_key_str) -assert isinstance(key_bytes, bytes) - -# last two converters are for array.array of ints, those require input -# that's multiple of 4, which no curve we support produces -@pytest.mark.parametrize("convert", converters[:-2]) -def test_SigningKey_from_der(convert): - key = convert(key_bytes) - sk = SigningKey.from_der(key) - - assert sk.to_string() == prv_key_bytes - - -# test SigningKey.sign_deterministic() -extra_entropy = b"\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11" - - -@pytest.mark.parametrize("convert", converters) -def test_SigningKey_sign_deterministic(convert): - sig = sk.sign_deterministic( - convert(data), extra_entropy=convert(extra_entropy) - ) - - vk.verify(sig, data) - - -# test SigningKey.sign_digest_deterministic() -@pytest.mark.parametrize("convert", converters) -def test_SigningKey_sign_digest_deterministic(convert): - sig = sk.sign_digest_deterministic( - convert(data_hash), extra_entropy=convert(extra_entropy) - ) - - vk.verify(sig, data) - - -@pytest.mark.parametrize("convert", converters) -def test_SigningKey_sign(convert): - sig = sk.sign(convert(data)) - - vk.verify(sig, data) - - -@pytest.mark.parametrize("convert", converters) -def test_SigningKey_sign_digest(convert): - sig = sk.sign_digest(convert(data_hash)) - - vk.verify(sig, data) - - -def test_SigningKey_with_unlikely_value(): - sk = SigningKey.from_secret_exponent(NIST256p.order - 1, curve=NIST256p) - vk = sk.verifying_key - sig = sk.sign(b"hello") - assert vk.verify(sig, b"hello") - - -def test_SigningKey_with_custom_curve_old_point(): - generator = generator_brainpoolp160r1 - generator = Point( - generator.curve(), - generator.x(), - generator.y(), - generator.order(), - ) - - curve = Curve( - "BRAINPOOLP160r1", - generator.curve(), - generator, - (1, 3, 36, 3, 3, 2, 8, 1, 1, 1), - ) - - sk = SigningKey.from_secret_exponent(12, curve) - - sk2 = SigningKey.from_secret_exponent(12, BRAINPOOLP160r1) - - assert sk.privkey == sk2.privkey - - -def test_VerifyingKey_inequality_with_different_curves(): - sk1 = SigningKey.from_secret_exponent(2, BRAINPOOLP160r1) - sk2 = SigningKey.from_secret_exponent(2, NIST256p) - - assert not (sk1.verifying_key == sk2.verifying_key) - - -def test_VerifyingKey_inequality_with_different_secret_points(): - sk1 = SigningKey.from_secret_exponent(2, BRAINPOOLP160r1) - sk2 = SigningKey.from_secret_exponent(3, BRAINPOOLP160r1) - - assert not (sk1.verifying_key == sk2.verifying_key) - - -def test_SigningKey_from_pem_pkcs8v2_EdDSA(): - pem = """-----BEGIN PRIVATE KEY----- - MFMCAQEwBQYDK2VwBCIEICc2F2ag1n1QP0jY+g9qWx5sDkx0s/HdNi3cSRHw+zsI - oSMDIQA+HQ2xCif8a/LMWR2m5HaCm5I2pKe/cc8OiRANMHxjKQ== - -----END PRIVATE KEY-----""" - - sk = SigningKey.from_pem(pem) - assert sk.curve == Ed25519 diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_malformed_sigs.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_malformed_sigs.py deleted file mode 100644 index e5a87c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_malformed_sigs.py +++ /dev/null @@ -1,378 +0,0 @@ -from __future__ import with_statement, division - -import hashlib - -try: - from hashlib import algorithms_available -except ImportError: # pragma: no cover - algorithms_available = [ - "md5", - "sha1", - "sha224", - "sha256", - "sha384", - "sha512", - ] -# skip algorithms broken by change to OpenSSL 3.0 and early versions -# of hashlib that list algorithms that require the legacy provider to work -# https://bugs.python.org/issue38820 -algorithms_available = [ - i - for i in algorithms_available - if i not in ("mdc2", "md2", "md4", "whirlpool", "ripemd160") -] -from functools import partial -import pytest -import sys -import hypothesis.strategies as st -from hypothesis import note, assume, given, settings, example - -from .keys import SigningKey -from .keys import BadSignatureError -from .util import sigencode_der, sigencode_string -from .util import sigdecode_der, sigdecode_string -from .curves import curves, SECP112r2, SECP128r1 -from .der import ( - encode_integer, - encode_bitstring, - encode_octet_string, - encode_oid, - encode_sequence, - encode_constructed, -) -from .ellipticcurve import CurveEdTw - - -example_data = b"some data to sign" -"""Since the data is hashed for processing, really any string will do.""" - - -hash_and_size = [ - (name, hashlib.new(name).digest_size) for name in algorithms_available -] -"""Pairs of hash names and their output sizes. -Needed for pairing with curves as we don't support hashes -bigger than order sizes of curves.""" - - -if "--fast" in sys.argv: # pragma: no cover - curves = [SECP112r2, SECP128r1] - - -keys_and_sigs = [] -"""Name of the curve+hash combination, VerifyingKey and DER signature.""" - - -# for hypothesis strategy shrinking we want smallest curves and hashes first -for curve in sorted(curves, key=lambda x: x.baselen): - for hash_alg in [ - name - for name, size in sorted(hash_and_size, key=lambda x: x[1]) - if 0 < size <= curve.baselen - ]: - sk = SigningKey.generate( - curve, hashfunc=partial(hashlib.new, hash_alg) - ) - - keys_and_sigs.append( - ( - "{0} {1}".format(curve, hash_alg), - sk.verifying_key, - sk.sign(example_data, sigencode=sigencode_der), - ) - ) - - -# first make sure that the signatures can be verified -@pytest.mark.parametrize( - "verifying_key,signature", - [pytest.param(vk, sig, id=name) for name, vk, sig in keys_and_sigs], -) -def test_signatures(verifying_key, signature): - assert verifying_key.verify( - signature, example_data, sigdecode=sigdecode_der - ) - - -@st.composite -def st_fuzzed_sig(draw, keys_and_sigs): # pragma: no cover - """ - Hypothesis strategy that generates pairs of VerifyingKey and malformed - signatures created by fuzzing of a valid signature. - """ - name, verifying_key, old_sig = draw(st.sampled_from(keys_and_sigs)) - note("Configuration: {0}".format(name)) - - sig = bytearray(old_sig) - - # decide which bytes should be removed - to_remove = draw( - st.lists(st.integers(min_value=0, max_value=len(sig) - 1), unique=True) - ) - to_remove.sort() - for i in reversed(to_remove): - del sig[i] - note("Remove bytes: {0}".format(to_remove)) - - # decide which bytes of the original signature should be changed - xors = None - if sig: # pragma: no branch - xors = draw( - st.dictionaries( - st.integers(min_value=0, max_value=len(sig) - 1), - st.integers(min_value=1, max_value=255), - ) - ) - for i, val in xors.items(): - sig[i] ^= val - note("xors: {0}".format(xors)) - - # decide where new data should be inserted - insert_pos = draw(st.integers(min_value=0, max_value=len(sig))) - # NIST521p signature is about 140 bytes long, test slightly longer - insert_data = draw(st.binary(max_size=256)) - - sig = sig[:insert_pos] + insert_data + sig[insert_pos:] - note( - "Inserted at position {0} bytes: {1!r}".format(insert_pos, insert_data) - ) - - sig = bytes(sig) - # make sure that there was performed at least one mutation on the data - assume(to_remove or xors or insert_data) - # and that the mutations didn't cancel each-other out - assume(sig != old_sig) - - return verifying_key, sig - - -params = {} -# not supported in hypothesis 2.0.0 -if sys.version_info >= (2, 7): # pragma: no branch - from hypothesis import HealthCheck - - # deadline=5s because NIST521p are slow to verify - params["deadline"] = 5000 - params["suppress_health_check"] = [ - HealthCheck.data_too_large, - HealthCheck.filter_too_much, - HealthCheck.too_slow, - ] -if "--fast" in sys.argv: # pragma: no cover - params["max_examples"] = 20 - -slow_params = dict(params) -if "--fast" in sys.argv: # pragma: no cover - slow_params["max_examples"] = 1 -else: - slow_params["max_examples"] = 10 - - -@settings(**slow_params) -@given(st_fuzzed_sig(keys_and_sigs)) -def test_fuzzed_der_signatures(args): - verifying_key, sig = args - - with pytest.raises(BadSignatureError): - verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) - - -@st.composite -def st_random_der_ecdsa_sig_value(draw): # pragma: no cover - """ - Hypothesis strategy for selecting random values and encoding them - to ECDSA-Sig-Value object:: - - ECDSA-Sig-Value ::= SEQUENCE { - r INTEGER, - s INTEGER - } - """ - name, verifying_key, _ = draw(st.sampled_from(keys_and_sigs)) - note("Configuration: {0}".format(name)) - order = int(verifying_key.curve.order) - - # the encode_integer doesn't support negative numbers, would be nice - # to generate them too, but we have coverage for remove_integer() - # verifying that it doesn't accept them, so meh. - # Test all numbers around the ones that can show up (around order) - # way smaller and slightly bigger - r = draw( - st.integers(min_value=0, max_value=order << 4) - | st.integers(min_value=order >> 2, max_value=order + 1) - ) - s = draw( - st.integers(min_value=0, max_value=order << 4) - | st.integers(min_value=order >> 2, max_value=order + 1) - ) - - sig = encode_sequence(encode_integer(r), encode_integer(s)) - - return verifying_key, sig - - -@settings(**slow_params) -@given(st_random_der_ecdsa_sig_value()) -def test_random_der_ecdsa_sig_value(params): - """ - Check if random values encoded in ECDSA-Sig-Value structure are rejected - as signature. - """ - verifying_key, sig = params - - with pytest.raises(BadSignatureError): - verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) - - -def st_der_integer(*args, **kwargs): # pragma: no cover - """ - Hypothesis strategy that returns a random positive integer as DER - INTEGER. - Parameters are passed to hypothesis.strategy.integer. - """ - if "min_value" not in kwargs: # pragma: no branch - kwargs["min_value"] = 0 - return st.builds(encode_integer, st.integers(*args, **kwargs)) - - -@st.composite -def st_der_bit_string(draw, *args, **kwargs): # pragma: no cover - """ - Hypothesis strategy that returns a random DER BIT STRING. - Parameters are passed to hypothesis.strategy.binary. - """ - data = draw(st.binary(*args, **kwargs)) - if data: - unused = draw(st.integers(min_value=0, max_value=7)) - data = bytearray(data) - data[-1] &= -(2**unused) - data = bytes(data) - else: - unused = 0 - return encode_bitstring(data, unused) - - -def st_der_octet_string(*args, **kwargs): # pragma: no cover - """ - Hypothesis strategy that returns a random DER OCTET STRING object. - Parameters are passed to hypothesis.strategy.binary - """ - return st.builds(encode_octet_string, st.binary(*args, **kwargs)) - - -def st_der_null(): # pragma: no cover - """ - Hypothesis strategy that returns DER NULL object. - """ - return st.just(b"\x05\x00") - - -@st.composite -def st_der_oid(draw): # pragma: no cover - """ - Hypothesis strategy that returns DER OBJECT IDENTIFIER objects. - """ - first = draw(st.integers(min_value=0, max_value=2)) - if first < 2: - second = draw(st.integers(min_value=0, max_value=39)) - else: - second = draw(st.integers(min_value=0, max_value=2**512)) - rest = draw( - st.lists(st.integers(min_value=0, max_value=2**512), max_size=50) - ) - return encode_oid(first, second, *rest) - - -def st_der(): # pragma: no cover - """ - Hypothesis strategy that returns random DER structures. - - A valid DER structure is any primitive object, an octet encoding - of a valid DER structure, sequence of valid DER objects or a constructed - encoding of any of the above. - """ - return st.recursive( # pragma: no branch - st.just(b"") - | st_der_integer(max_value=2**4096) - | st_der_bit_string(max_size=1024**2) - | st_der_octet_string(max_size=1024**2) - | st_der_null() - | st_der_oid(), - lambda children: st.builds(encode_octet_string, st.one_of(children)) - | st.builds(lambda x: encode_bitstring(x, 0), st.one_of(children)) - | st.builds( - lambda x: encode_sequence(*x), st.lists(children, max_size=200) - ) - | st.builds( - encode_constructed, - st.integers(min_value=0, max_value=0x3F), - st.one_of(children), - ), - max_leaves=40, - ) - - -@settings(**slow_params) -@given(st.sampled_from(keys_and_sigs), st_der()) -def test_random_der_as_signature(params, der): - """Check if random DER structures are rejected as signature""" - name, verifying_key, _ = params - - with pytest.raises(BadSignatureError): - verifying_key.verify(der, example_data, sigdecode=sigdecode_der) - - -@settings(**slow_params) -@given(st.sampled_from(keys_and_sigs), st.binary(max_size=1024**2)) -@example( - keys_and_sigs[0], encode_sequence(encode_integer(0), encode_integer(0)) -) -@example( - keys_and_sigs[0], - encode_sequence(encode_integer(1), encode_integer(1)) + b"\x00", -) -@example(keys_and_sigs[0], encode_sequence(*[encode_integer(1)] * 3)) -def test_random_bytes_as_signature(params, der): - """Check if random bytes are rejected as signature""" - name, verifying_key, _ = params - - with pytest.raises(BadSignatureError): - verifying_key.verify(der, example_data, sigdecode=sigdecode_der) - - -keys_and_string_sigs = [ - ( - name, - verifying_key, - sigencode_string( - *sigdecode_der(sig, verifying_key.curve.order), - order=verifying_key.curve.order - ), - ) - for name, verifying_key, sig in keys_and_sigs - if not isinstance(verifying_key.curve.curve, CurveEdTw) -] -""" -Name of the curve+hash combination, VerifyingKey and signature as a -byte string. -""" - - -keys_and_string_sigs += [ - ( - name, - verifying_key, - sig, - ) - for name, verifying_key, sig in keys_and_sigs - if isinstance(verifying_key.curve.curve, CurveEdTw) -] - - -@settings(**slow_params) -@given(st_fuzzed_sig(keys_and_string_sigs)) -def test_fuzzed_string_signatures(params): - verifying_key, sig = params - - with pytest.raises(BadSignatureError): - verifying_key.verify(sig, example_data, sigdecode=sigdecode_string) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_numbertheory.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_numbertheory.py deleted file mode 100644 index 966eca2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_numbertheory.py +++ /dev/null @@ -1,483 +0,0 @@ -import operator -from functools import reduce -import sys - -try: - import unittest2 as unittest -except ImportError: - import unittest -import hypothesis.strategies as st -import pytest -from hypothesis import given, settings, example - -try: - from hypothesis import HealthCheck - - HC_PRESENT = True -except ImportError: # pragma: no cover - HC_PRESENT = False -from .numbertheory import ( - SquareRootError, - JacobiError, - factorization, - gcd, - lcm, - jacobi, - inverse_mod, - is_prime, - next_prime, - smallprimes, - square_root_mod_prime, -) - -try: - from gmpy2 import mpz -except ImportError: - try: - from gmpy import mpz - except ImportError: - - def mpz(x): - return x - - -BIGPRIMES = ( - 999671, - 999683, - 999721, - 999727, - 999749, - 999763, - 999769, - 999773, - 999809, - 999853, - 999863, - 999883, - 999907, - 999917, - 999931, - 999953, - 999959, - 999961, - 999979, - 999983, -) - - -@pytest.mark.parametrize( - "prime, next_p", [(p, q) for p, q in zip(BIGPRIMES[:-1], BIGPRIMES[1:])] -) -def test_next_prime(prime, next_p): - assert next_prime(prime) == next_p - - -@pytest.mark.parametrize("val", [-1, 0, 1]) -def test_next_prime_with_nums_less_2(val): - assert next_prime(val) == 2 - - -@pytest.mark.slow -@pytest.mark.parametrize("prime", smallprimes) -def test_square_root_mod_prime_for_small_primes(prime): - squares = set() - for num in range(0, 1 + prime // 2): - sq = num * num % prime - squares.add(sq) - root = square_root_mod_prime(sq, prime) - # tested for real with TestNumbertheory.test_square_root_mod_prime - assert root * root % prime == sq - - for nonsquare in range(0, prime): - if nonsquare in squares: - continue - with pytest.raises(SquareRootError): - square_root_mod_prime(nonsquare, prime) - - -def test_square_root_mod_prime_for_2(): - a = square_root_mod_prime(1, 2) - assert a == 1 - - -def test_square_root_mod_prime_for_small_prime(): - root = square_root_mod_prime(98**2 % 101, 101) - assert root * root % 101 == 9 - - -def test_square_root_mod_prime_for_p_congruent_5(): - p = 13 - assert p % 8 == 5 - - root = square_root_mod_prime(3, p) - assert root * root % p == 3 - - -def test_square_root_mod_prime_for_p_congruent_5_large_d(): - p = 29 - assert p % 8 == 5 - - root = square_root_mod_prime(4, p) - assert root * root % p == 4 - - -class TestSquareRootModPrime(unittest.TestCase): - def test_power_of_2_p(self): - with self.assertRaises(JacobiError): - square_root_mod_prime(12, 32) - - def test_no_square(self): - with self.assertRaises(SquareRootError) as e: - square_root_mod_prime(12, 31) - - self.assertIn("no square root", str(e.exception)) - - def test_non_prime(self): - with self.assertRaises(SquareRootError) as e: - square_root_mod_prime(12, 33) - - self.assertIn("p is not prime", str(e.exception)) - - def test_non_prime_with_negative(self): - with self.assertRaises(SquareRootError) as e: - square_root_mod_prime(697 - 1, 697) - - self.assertIn("p is not prime", str(e.exception)) - - -@st.composite -def st_two_nums_rel_prime(draw): - # 521-bit is the biggest curve we operate on, use 1024 for a bit - # of breathing space - mod = draw(st.integers(min_value=2, max_value=2**1024)) - num = draw( - st.integers(min_value=1, max_value=mod - 1).filter( - lambda x: gcd(x, mod) == 1 - ) - ) - return num, mod - - -@st.composite -def st_primes(draw, *args, **kwargs): - if "min_value" not in kwargs: # pragma: no branch - kwargs["min_value"] = 1 - prime = draw( - st.sampled_from(smallprimes) - | st.integers(*args, **kwargs).filter(is_prime) - ) - return prime - - -@st.composite -def st_num_square_prime(draw): - prime = draw(st_primes(max_value=2**1024)) - num = draw(st.integers(min_value=0, max_value=1 + prime // 2)) - sq = num * num % prime - return sq, prime - - -@st.composite -def st_comp_with_com_fac(draw): - """ - Strategy that returns lists of numbers, all having a common factor. - """ - primes = draw( - st.lists(st_primes(max_value=2**512), min_size=1, max_size=10) - ) - # select random prime(s) that will make the common factor of composites - com_fac_primes = draw( - st.lists(st.sampled_from(primes), min_size=1, max_size=20) - ) - com_fac = reduce(operator.mul, com_fac_primes, 1) - - # select at most 20 lists (returned numbers), - # each having at most 30 primes (factors) including none (then the number - # will be 1) - comp_primes = draw( # pragma: no branch - st.integers(min_value=1, max_value=20).flatmap( - lambda n: st.lists( - st.lists(st.sampled_from(primes), max_size=30), - min_size=1, - max_size=n, - ) - ) - ) - - return [reduce(operator.mul, nums, 1) * com_fac for nums in comp_primes] - - -@st.composite -def st_comp_no_com_fac(draw): - """ - Strategy that returns lists of numbers that don't have a common factor. - """ - primes = draw( - st.lists( - st_primes(max_value=2**512), min_size=2, max_size=10, unique=True - ) - ) - # first select the primes that will create the uncommon factor - # between returned numbers - uncom_fac_primes = draw( - st.lists( - st.sampled_from(primes), - min_size=1, - max_size=len(primes) - 1, - unique=True, - ) - ) - uncom_fac = reduce(operator.mul, uncom_fac_primes, 1) - - # then build composites from leftover primes - leftover_primes = [i for i in primes if i not in uncom_fac_primes] - - assert leftover_primes - assert uncom_fac_primes - - # select at most 20 lists, each having at most 30 primes - # selected from the leftover_primes list - number_primes = draw( # pragma: no branch - st.integers(min_value=1, max_value=20).flatmap( - lambda n: st.lists( - st.lists(st.sampled_from(leftover_primes), max_size=30), - min_size=1, - max_size=n, - ) - ) - ) - - numbers = [reduce(operator.mul, nums, 1) for nums in number_primes] - - insert_at = draw(st.integers(min_value=0, max_value=len(numbers))) - numbers.insert(insert_at, uncom_fac) - return numbers - - -HYP_SETTINGS = {} -if HC_PRESENT: # pragma: no branch - HYP_SETTINGS["suppress_health_check"] = [ - HealthCheck.filter_too_much, - HealthCheck.too_slow, - ] - # the factorization() sometimes takes a long time to finish - HYP_SETTINGS["deadline"] = 5000 - -if "--fast" in sys.argv: # pragma: no cover - HYP_SETTINGS["max_examples"] = 20 - - -HYP_SLOW_SETTINGS = dict(HYP_SETTINGS) -if "--fast" in sys.argv: # pragma: no cover - HYP_SLOW_SETTINGS["max_examples"] = 1 -else: - HYP_SLOW_SETTINGS["max_examples"] = 20 - - -class TestIsPrime(unittest.TestCase): - def test_very_small_prime(self): - assert is_prime(23) - - def test_very_small_composite(self): - assert not is_prime(22) - - def test_small_prime(self): - assert is_prime(123456791) - - def test_special_composite(self): - assert not is_prime(10261) - - def test_medium_prime_1(self): - # nextPrime[2^256] - assert is_prime(2**256 + 0x129) - - def test_medium_prime_2(self): - # nextPrime(2^256+0x129) - assert is_prime(2**256 + 0x12D) - - def test_medium_trivial_composite(self): - assert not is_prime(2**256 + 0x130) - - def test_medium_non_trivial_composite(self): - assert not is_prime(2**256 + 0x12F) - - def test_large_prime(self): - # nextPrime[2^2048] - assert is_prime(mpz(2) ** 2048 + 0x3D5) - - def test_pseudoprime_base_19(self): - assert not is_prime(1543267864443420616877677640751301) - - def test_pseudoprime_base_300(self): - # F. Arnault "Constructing Carmichael Numbers Which Are Strong - # Pseudoprimes to Several Bases". Journal of Symbolic - # Computation. 20 (2): 151-161. doi:10.1006/jsco.1995.1042. - # Section 4.4 Large Example (a pseudoprime to all bases up to - # 300) - p = int( - "29 674 495 668 685 510 550 154 174 642 905 332 730 " - "771 991 799 853 043 350 995 075 531 276 838 753 171 " - "770 199 594 238 596 428 121 188 033 664 754 218 345 " - "562 493 168 782 883".replace(" ", "") - ) - - assert is_prime(p) - for _ in range(10): - if not is_prime(p * (313 * (p - 1) + 1) * (353 * (p - 1) + 1)): - break - else: - assert False, "composite not detected" - - -class TestNumbertheory(unittest.TestCase): - def test_gcd(self): - assert gcd(3 * 5 * 7, 3 * 5 * 11, 3 * 5 * 13) == 3 * 5 - assert gcd([3 * 5 * 7, 3 * 5 * 11, 3 * 5 * 13]) == 3 * 5 - assert gcd(3) == 3 - - @unittest.skipUnless( - HC_PRESENT, - "Hypothesis 2.0.0 can't be made tolerant of hard to " - "meet requirements (like `is_prime()`), the test " - "case times-out on it", - ) - @settings(**HYP_SLOW_SETTINGS) - @example([877 * 1151, 877 * 1009]) - @given(st_comp_with_com_fac()) - def test_gcd_with_com_factor(self, numbers): - n = gcd(numbers) - assert 1 in numbers or n != 1 - for i in numbers: - assert i % n == 0 - - @unittest.skipUnless( - HC_PRESENT, - "Hypothesis 2.0.0 can't be made tolerant of hard to " - "meet requirements (like `is_prime()`), the test " - "case times-out on it", - ) - @settings(**HYP_SLOW_SETTINGS) - @example([1151, 1069, 1009]) - @given(st_comp_no_com_fac()) - def test_gcd_with_uncom_factor(self, numbers): - n = gcd(numbers) - assert n == 1 - - @settings(**HYP_SLOW_SETTINGS) - @given( - st.lists( - st.integers(min_value=1, max_value=2**8192), - min_size=1, - max_size=20, - ) - ) - def test_gcd_with_random_numbers(self, numbers): - n = gcd(numbers) - for i in numbers: - # check that at least it's a divider - assert i % n == 0 - - def test_lcm(self): - assert lcm(3, 5 * 3, 7 * 3) == 3 * 5 * 7 - assert lcm([3, 5 * 3, 7 * 3]) == 3 * 5 * 7 - assert lcm(3) == 3 - - @settings(**HYP_SLOW_SETTINGS) - @given( - st.lists( - st.integers(min_value=1, max_value=2**8192), - min_size=1, - max_size=20, - ) - ) - def test_lcm_with_random_numbers(self, numbers): - n = lcm(numbers) - for i in numbers: - assert n % i == 0 - - @unittest.skipUnless( - HC_PRESENT, - "Hypothesis 2.0.0 can't be made tolerant of hard to " - "meet requirements (like `is_prime()`), the test " - "case times-out on it", - ) - @settings(**HYP_SLOW_SETTINGS) - @given(st_num_square_prime()) - def test_square_root_mod_prime(self, vals): - square, prime = vals - - calc = square_root_mod_prime(square, prime) - assert calc * calc % prime == square - - @pytest.mark.slow - @settings(**HYP_SLOW_SETTINGS) - @given(st.integers(min_value=1, max_value=10**12)) - @example(265399 * 1526929) - @example(373297**2 * 553991) - def test_factorization(self, num): - factors = factorization(num) - mult = 1 - for i in factors: - mult *= i[0] ** i[1] - assert mult == num - - def test_factorisation_smallprimes(self): - exp = 101 * 103 - assert 101 in smallprimes - assert 103 in smallprimes - factors = factorization(exp) - mult = 1 - for i in factors: - mult *= i[0] ** i[1] - assert mult == exp - - def test_factorisation_not_smallprimes(self): - exp = 1231 * 1237 - assert 1231 not in smallprimes - assert 1237 not in smallprimes - factors = factorization(exp) - mult = 1 - for i in factors: - mult *= i[0] ** i[1] - assert mult == exp - - def test_jacobi_with_zero(self): - assert jacobi(0, 3) == 0 - - def test_jacobi_with_one(self): - assert jacobi(1, 3) == 1 - - @settings(**HYP_SLOW_SETTINGS) - @given(st.integers(min_value=3, max_value=1000).filter(lambda x: x % 2)) - def test_jacobi(self, mod): - mod = mpz(mod) - if is_prime(mod): - squares = set() - for root in range(1, mod): - root = mpz(root) - assert jacobi(root * root, mod) == 1 - squares.add(root * root % mod) - for i in range(1, mod): - if i not in squares: - i = mpz(i) - assert jacobi(i, mod) == -1 - else: - factors = factorization(mod) - for a in range(1, mod): - c = 1 - for i in factors: - c *= jacobi(a, i[0]) ** i[1] - assert c == jacobi(a, mod) - - @settings(**HYP_SLOW_SETTINGS) - @given(st_two_nums_rel_prime()) - def test_inverse_mod(self, nums): - num, mod = nums - - inv = inverse_mod(num, mod) - - assert 0 < inv < mod - assert num * inv % mod == 1 - - def test_inverse_mod_with_zero(self): - assert 0 == inverse_mod(0, 11) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_pyecdsa.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_pyecdsa.py deleted file mode 100644 index 799e9b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_pyecdsa.py +++ /dev/null @@ -1,2564 +0,0 @@ -from __future__ import with_statement, division, print_function - -try: - import unittest2 as unittest -except ImportError: - import unittest -import os -import shutil -import subprocess -import pytest -import sys -from binascii import hexlify, unhexlify -import hashlib -from functools import partial - -from hypothesis import given, settings -import hypothesis.strategies as st - -from six import binary_type -from .keys import SigningKey, VerifyingKey -from .keys import BadSignatureError, MalformedPointError, BadDigestError -from . import util -from .util import ( - sigencode_der, - sigencode_strings, - sigencode_strings_canonize, - sigencode_string_canonize, - sigencode_der_canonize, -) -from .util import sigdecode_der, sigdecode_strings, sigdecode_string -from .util import number_to_string, encoded_oid_ecPublicKey, MalformedSignature -from .curves import Curve, UnknownCurveError -from .curves import ( - SECP112r1, - SECP112r2, - SECP128r1, - SECP160r1, - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - SECP256k1, - BRAINPOOLP160r1, - BRAINPOOLP192r1, - BRAINPOOLP224r1, - BRAINPOOLP256r1, - BRAINPOOLP320r1, - BRAINPOOLP384r1, - BRAINPOOLP512r1, - BRAINPOOLP160t1, - BRAINPOOLP192t1, - BRAINPOOLP224t1, - BRAINPOOLP256t1, - BRAINPOOLP320t1, - BRAINPOOLP384t1, - BRAINPOOLP512t1, - Ed25519, - Ed448, - curves, -) -from .ecdsa import ( - curve_brainpoolp224r1, - curve_brainpoolp256r1, - curve_brainpoolp384r1, - curve_brainpoolp512r1, -) -from .ellipticcurve import Point -from . import der -from . import rfc6979 -from . import ecdsa - - -class SubprocessError(Exception): - pass - - -HYP_SETTINGS = {} - - -if "--fast" in sys.argv: # pragma: no cover - HYP_SETTINGS["max_examples"] = 2 - - -def run_openssl(cmd): - OPENSSL = "openssl" - p = subprocess.Popen( - [OPENSSL] + cmd.split(), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - stdout, ignored = p.communicate() - if p.returncode != 0: - raise SubprocessError( - "cmd '%s %s' failed: rc=%s, stdout/err was %s" - % (OPENSSL, cmd, p.returncode, stdout) - ) - return stdout.decode() - - -class ECDSA(unittest.TestCase): - def test_basic(self): - priv = SigningKey.generate() - pub = priv.get_verifying_key() - - data = b"blahblah" - sig = priv.sign(data) - - self.assertTrue(pub.verify(sig, data)) - self.assertRaises(BadSignatureError, pub.verify, sig, data + b"bad") - - pub2 = VerifyingKey.from_string(pub.to_string()) - self.assertTrue(pub2.verify(sig, data)) - - def test_deterministic(self): - data = b"blahblah" - secexp = int("9d0219792467d7d37b4d43298a7d0c05", 16) - - priv = SigningKey.from_secret_exponent( - secexp, SECP256k1, hashlib.sha256 - ) - pub = priv.get_verifying_key() - - k = rfc6979.generate_k( - SECP256k1.generator.order(), - secexp, - hashlib.sha256, - hashlib.sha256(data).digest(), - ) - - sig1 = priv.sign(data, k=k) - self.assertTrue(pub.verify(sig1, data)) - - sig2 = priv.sign(data, k=k) - self.assertTrue(pub.verify(sig2, data)) - - sig3 = priv.sign_deterministic(data, hashlib.sha256) - self.assertTrue(pub.verify(sig3, data)) - - self.assertEqual(sig1, sig2) - self.assertEqual(sig1, sig3) - - def test_bad_usage(self): - # sk=SigningKey() is wrong - self.assertRaises(TypeError, SigningKey) - self.assertRaises(TypeError, VerifyingKey) - - def test_lengths_default(self): - default = NIST192p - priv = SigningKey.generate() - pub = priv.get_verifying_key() - self.assertEqual(len(pub.to_string()), default.verifying_key_length) - sig = priv.sign(b"data") - self.assertEqual(len(sig), default.signature_length) - - def test_serialize(self): - seed = b"secret" - curve = NIST192p - secexp1 = util.randrange_from_seed__trytryagain(seed, curve.order) - secexp2 = util.randrange_from_seed__trytryagain(seed, curve.order) - self.assertEqual(secexp1, secexp2) - priv1 = SigningKey.from_secret_exponent(secexp1, curve) - priv2 = SigningKey.from_secret_exponent(secexp2, curve) - self.assertEqual( - hexlify(priv1.to_string()), hexlify(priv2.to_string()) - ) - self.assertEqual(priv1.to_pem(), priv2.to_pem()) - pub1 = priv1.get_verifying_key() - pub2 = priv2.get_verifying_key() - data = b"data" - sig1 = priv1.sign(data) - sig2 = priv2.sign(data) - self.assertTrue(pub1.verify(sig1, data)) - self.assertTrue(pub2.verify(sig1, data)) - self.assertTrue(pub1.verify(sig2, data)) - self.assertTrue(pub2.verify(sig2, data)) - self.assertEqual(hexlify(pub1.to_string()), hexlify(pub2.to_string())) - - def test_nonrandom(self): - s = b"all the entropy in the entire world, compressed into one line" - - def not_much_entropy(numbytes): - return s[:numbytes] - - # we control the entropy source, these two keys should be identical: - priv1 = SigningKey.generate(entropy=not_much_entropy) - priv2 = SigningKey.generate(entropy=not_much_entropy) - self.assertEqual( - hexlify(priv1.get_verifying_key().to_string()), - hexlify(priv2.get_verifying_key().to_string()), - ) - # likewise, signatures should be identical. Obviously you'd never - # want to do this with keys you care about, because the secrecy of - # the private key depends upon using different random numbers for - # each signature - sig1 = priv1.sign(b"data", entropy=not_much_entropy) - sig2 = priv2.sign(b"data", entropy=not_much_entropy) - self.assertEqual(hexlify(sig1), hexlify(sig2)) - - def assertTruePrivkeysEqual(self, priv1, priv2): - self.assertEqual( - priv1.privkey.secret_multiplier, priv2.privkey.secret_multiplier - ) - self.assertEqual( - priv1.privkey.public_key.generator, - priv2.privkey.public_key.generator, - ) - - def test_privkey_creation(self): - s = b"all the entropy in the entire world, compressed into one line" - - def not_much_entropy(numbytes): - return s[:numbytes] - - priv1 = SigningKey.generate() - self.assertEqual(priv1.baselen, NIST192p.baselen) - - priv1 = SigningKey.generate(curve=NIST224p) - self.assertEqual(priv1.baselen, NIST224p.baselen) - - priv1 = SigningKey.generate(entropy=not_much_entropy) - self.assertEqual(priv1.baselen, NIST192p.baselen) - priv2 = SigningKey.generate(entropy=not_much_entropy) - self.assertEqual(priv2.baselen, NIST192p.baselen) - self.assertTruePrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.from_secret_exponent(secexp=3) - self.assertEqual(priv1.baselen, NIST192p.baselen) - priv2 = SigningKey.from_secret_exponent(secexp=3) - self.assertTruePrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.from_secret_exponent(secexp=4, curve=NIST224p) - self.assertEqual(priv1.baselen, NIST224p.baselen) - - def test_privkey_strings(self): - priv1 = SigningKey.generate() - s1 = priv1.to_string() - self.assertEqual(type(s1), binary_type) - self.assertEqual(len(s1), NIST192p.baselen) - priv2 = SigningKey.from_string(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - s1 = priv1.to_pem() - self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) - self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) - priv2 = SigningKey.from_pem(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - s1 = priv1.to_der() - self.assertEqual(type(s1), binary_type) - priv2 = SigningKey.from_der(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.generate(curve=NIST256p) - s1 = priv1.to_pem() - self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) - self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) - priv2 = SigningKey.from_pem(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - s1 = priv1.to_der() - self.assertEqual(type(s1), binary_type) - priv2 = SigningKey.from_der(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - def test_privkey_strings_brainpool(self): - priv1 = SigningKey.generate(curve=BRAINPOOLP512r1) - s1 = priv1.to_pem() - self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) - self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) - priv2 = SigningKey.from_pem(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - s1 = priv1.to_der() - self.assertEqual(type(s1), binary_type) - priv2 = SigningKey.from_der(s1) - self.assertTruePrivkeysEqual(priv1, priv2) - - def assertTruePubkeysEqual(self, pub1, pub2): - self.assertEqual(pub1.pubkey.point, pub2.pubkey.point) - self.assertEqual(pub1.pubkey.generator, pub2.pubkey.generator) - self.assertEqual(pub1.curve, pub2.curve) - - def test_pubkey_strings(self): - priv1 = SigningKey.generate() - pub1 = priv1.get_verifying_key() - s1 = pub1.to_string() - self.assertEqual(type(s1), binary_type) - self.assertEqual(len(s1), NIST192p.verifying_key_length) - pub2 = VerifyingKey.from_string(s1) - self.assertTruePubkeysEqual(pub1, pub2) - - priv1 = SigningKey.generate(curve=NIST256p) - pub1 = priv1.get_verifying_key() - s1 = pub1.to_string() - self.assertEqual(type(s1), binary_type) - self.assertEqual(len(s1), NIST256p.verifying_key_length) - pub2 = VerifyingKey.from_string(s1, curve=NIST256p) - self.assertTruePubkeysEqual(pub1, pub2) - - pub1_der = pub1.to_der() - self.assertEqual(type(pub1_der), binary_type) - pub2 = VerifyingKey.from_der(pub1_der) - self.assertTruePubkeysEqual(pub1, pub2) - - self.assertRaises( - der.UnexpectedDER, VerifyingKey.from_der, pub1_der + b"junk" - ) - badpub = VerifyingKey.from_der(pub1_der) - - class FakeGenerator: - def order(self): - return 123456789 - - class FakeCurveFp: - def p(self): - return int( - "6525534529039240705020950546962731340" - "4541085228058844382513856749047873406763" - ) - - badcurve = Curve( - "unknown", FakeCurveFp(), FakeGenerator(), (1, 2, 3, 4, 5, 6), None - ) - badpub.curve = badcurve - badder = badpub.to_der() - self.assertRaises(UnknownCurveError, VerifyingKey.from_der, badder) - - pem = pub1.to_pem() - self.assertEqual(type(pem), binary_type) - self.assertTrue(pem.startswith(b"-----BEGIN PUBLIC KEY-----"), pem) - self.assertTrue(pem.strip().endswith(b"-----END PUBLIC KEY-----"), pem) - pub2 = VerifyingKey.from_pem(pem) - self.assertTruePubkeysEqual(pub1, pub2) - - def test_pubkey_strings_brainpool(self): - priv1 = SigningKey.generate(curve=BRAINPOOLP512r1) - pub1 = priv1.get_verifying_key() - s1 = pub1.to_string() - self.assertEqual(type(s1), binary_type) - self.assertEqual(len(s1), BRAINPOOLP512r1.verifying_key_length) - pub2 = VerifyingKey.from_string(s1, curve=BRAINPOOLP512r1) - self.assertTruePubkeysEqual(pub1, pub2) - - pub1_der = pub1.to_der() - self.assertEqual(type(pub1_der), binary_type) - pub2 = VerifyingKey.from_der(pub1_der) - self.assertTruePubkeysEqual(pub1, pub2) - - def test_vk_to_der_with_invalid_point_encoding(self): - sk = SigningKey.generate() - vk = sk.verifying_key - - with self.assertRaises(ValueError): - vk.to_der("raw") - - def test_sk_to_der_with_invalid_point_encoding(self): - sk = SigningKey.generate() - - with self.assertRaises(ValueError): - sk.to_der("raw") - - def test_vk_from_der_garbage_after_curve_oid(self): - type_oid_der = encoded_oid_ecPublicKey - curve_oid_der = ( - der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) + b"garbage" - ) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\x00\xff", None) - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(der.UnexpectedDER): - VerifyingKey.from_der(to_decode) - - def test_vk_from_der_invalid_key_type(self): - type_oid_der = der.encode_oid(*(1, 2, 3)) - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\x00\xff", None) - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(der.UnexpectedDER): - VerifyingKey.from_der(to_decode) - - def test_vk_from_der_garbage_after_point_string(self): - type_oid_der = encoded_oid_ecPublicKey - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\x00\xff", None) + b"garbage" - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(der.UnexpectedDER): - VerifyingKey.from_der(to_decode) - - def test_vk_from_der_invalid_bitstring(self): - type_oid_der = encoded_oid_ecPublicKey - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\x08\xff", None) - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(der.UnexpectedDER): - VerifyingKey.from_der(to_decode) - - def test_vk_from_der_with_invalid_length_of_encoding(self): - type_oid_der = encoded_oid_ecPublicKey - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\xff" * 64, 0) - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_der(to_decode) - - def test_vk_from_der_with_raw_encoding(self): - type_oid_der = encoded_oid_ecPublicKey - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\xff" * 48, 0) - to_decode = der.encode_sequence(enc_type_der, point_der) - - with self.assertRaises(der.UnexpectedDER): - VerifyingKey.from_der(to_decode) - - def test_signature_strings(self): - priv1 = SigningKey.generate() - pub1 = priv1.get_verifying_key() - data = b"data" - - sig = priv1.sign(data) - self.assertEqual(type(sig), binary_type) - self.assertEqual(len(sig), NIST192p.signature_length) - self.assertTrue(pub1.verify(sig, data)) - - sig = priv1.sign(data, sigencode=sigencode_strings) - self.assertEqual(type(sig), tuple) - self.assertEqual(len(sig), 2) - self.assertEqual(type(sig[0]), binary_type) - self.assertEqual(type(sig[1]), binary_type) - self.assertEqual(len(sig[0]), NIST192p.baselen) - self.assertEqual(len(sig[1]), NIST192p.baselen) - self.assertTrue(pub1.verify(sig, data, sigdecode=sigdecode_strings)) - - sig_der = priv1.sign(data, sigencode=sigencode_der) - self.assertEqual(type(sig_der), binary_type) - self.assertTrue(pub1.verify(sig_der, data, sigdecode=sigdecode_der)) - - def test_sigencode_string_canonize_no_change(self): - r = 12 - s = 400 - order = SECP112r1.order - - new_r, new_s = sigdecode_string( - sigencode_string_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(s, new_s) - - def test_sigencode_string_canonize(self): - r = 12 - order = SECP112r1.order - s = order - 10 - - new_r, new_s = sigdecode_string( - sigencode_string_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(order - s, new_s) - - def test_sigencode_strings_canonize_no_change(self): - r = 12 - s = 400 - order = SECP112r1.order - - new_r, new_s = sigdecode_strings( - sigencode_strings_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(s, new_s) - - def test_sigencode_strings_canonize(self): - r = 12 - order = SECP112r1.order - s = order - 10 - - new_r, new_s = sigdecode_strings( - sigencode_strings_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(order - s, new_s) - - def test_sigencode_der_canonize_no_change(self): - r = 13 - s = 200 - order = SECP112r1.order - - new_r, new_s = sigdecode_der( - sigencode_der_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(s, new_s) - - def test_sigencode_der_canonize(self): - r = 13 - order = SECP112r1.order - s = order - 14 - - new_r, new_s = sigdecode_der( - sigencode_der_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(order - s, new_s) - - def test_sigencode_der_canonize_with_close_to_half_order(self): - r = 13 - order = SECP112r1.order - s = order // 2 + 1 - - regular_encode = sigencode_der(r, s, order) - canonical_encode = sigencode_der_canonize(r, s, order) - - self.assertNotEqual(regular_encode, canonical_encode) - - new_r, new_s = sigdecode_der( - sigencode_der_canonize(r, s, order), order - ) - - self.assertEqual(r, new_r) - self.assertEqual(order - s, new_s) - - def test_sig_decode_strings_with_invalid_count(self): - with self.assertRaises(MalformedSignature): - sigdecode_strings([b"one", b"two", b"three"], 0xFF) - - def test_sig_decode_strings_with_wrong_r_len(self): - with self.assertRaises(MalformedSignature): - sigdecode_strings([b"one", b"two"], 0xFF) - - def test_sig_decode_strings_with_wrong_s_len(self): - with self.assertRaises(MalformedSignature): - sigdecode_strings([b"\xa0", b"\xb0\xff"], 0xFF) - - def test_verify_with_too_long_input(self): - sk = SigningKey.generate() - vk = sk.verifying_key - - with self.assertRaises(BadDigestError): - vk.verify_digest(None, b"\x00" * 128) - - def test_sk_from_secret_exponent_with_wrong_sec_exponent(self): - with self.assertRaises(MalformedPointError): - SigningKey.from_secret_exponent(0) - - def test_sk_from_string_with_wrong_len_string(self): - with self.assertRaises(MalformedPointError): - SigningKey.from_string(b"\x01") - - def test_sk_from_der_with_junk_after_sequence(self): - ver_der = der.encode_integer(1) - to_decode = der.encode_sequence(ver_der) + b"garbage" - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_der_with_wrong_version(self): - ver_der = der.encode_integer(0) - to_decode = der.encode_sequence(ver_der) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_der_invalid_const_tag(self): - ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b"\x00\xff") - curve_oid_der = der.encode_oid(*(1, 2, 3)) - const_der = der.encode_constructed(1, curve_oid_der) - to_decode = der.encode_sequence( - ver_der, privkey_der, const_der, curve_oid_der - ) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_der_garbage_after_privkey_oid(self): - ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b"\x00\xff") - curve_oid_der = der.encode_oid(*(1, 2, 3)) + b"garbage" - const_der = der.encode_constructed(0, curve_oid_der) - to_decode = der.encode_sequence( - ver_der, privkey_der, const_der, curve_oid_der - ) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_der_with_short_privkey(self): - ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b"\x00\xff") - curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) - const_der = der.encode_constructed(0, curve_oid_der) - to_decode = der.encode_sequence( - ver_der, privkey_der, const_der, curve_oid_der - ) - - sk = SigningKey.from_der(to_decode) - self.assertEqual(sk.privkey.secret_multiplier, 255) - - def test_sk_from_p8_der_with_wrong_version(self): - ver_der = der.encode_integer(2) - algorithm_der = der.encode_sequence( - der.encode_oid(1, 2, 840, 10045, 2, 1), - der.encode_oid(1, 2, 840, 10045, 3, 1, 1), - ) - privkey_der = der.encode_octet_string( - der.encode_sequence( - der.encode_integer(1), der.encode_octet_string(b"\x00\xff") - ) - ) - to_decode = der.encode_sequence(ver_der, algorithm_der, privkey_der) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_p8_der_with_wrong_algorithm(self): - ver_der = der.encode_integer(1) - algorithm_der = der.encode_sequence( - der.encode_oid(1, 2, 3), der.encode_oid(1, 2, 840, 10045, 3, 1, 1) - ) - privkey_der = der.encode_octet_string( - der.encode_sequence( - der.encode_integer(1), der.encode_octet_string(b"\x00\xff") - ) - ) - to_decode = der.encode_sequence(ver_der, algorithm_der, privkey_der) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_p8_der_with_trailing_junk_after_algorithm(self): - ver_der = der.encode_integer(1) - algorithm_der = der.encode_sequence( - der.encode_oid(1, 2, 840, 10045, 2, 1), - der.encode_oid(1, 2, 840, 10045, 3, 1, 1), - der.encode_octet_string(b"junk"), - ) - privkey_der = der.encode_octet_string( - der.encode_sequence( - der.encode_integer(1), der.encode_octet_string(b"\x00\xff") - ) - ) - to_decode = der.encode_sequence(ver_der, algorithm_der, privkey_der) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sk_from_p8_der_with_trailing_junk_after_key(self): - ver_der = der.encode_integer(1) - algorithm_der = der.encode_sequence( - der.encode_oid(1, 2, 840, 10045, 2, 1), - der.encode_oid(1, 2, 840, 10045, 3, 1, 1), - ) - privkey_der = der.encode_octet_string( - der.encode_sequence( - der.encode_integer(1), der.encode_octet_string(b"\x00\xff") - ) - + der.encode_integer(999) - ) - to_decode = der.encode_sequence( - ver_der, - algorithm_der, - privkey_der, - der.encode_octet_string(b"junk"), - ) - - with self.assertRaises(der.UnexpectedDER): - SigningKey.from_der(to_decode) - - def test_sign_with_too_long_hash(self): - sk = SigningKey.from_secret_exponent(12) - - with self.assertRaises(BadDigestError): - sk.sign_digest(b"\xff" * 64) - - def test_hashfunc(self): - sk = SigningKey.generate(curve=NIST256p, hashfunc=hashlib.sha256) - data = b"security level is 128 bits" - sig = sk.sign(data) - vk = VerifyingKey.from_string( - sk.get_verifying_key().to_string(), - curve=NIST256p, - hashfunc=hashlib.sha256, - ) - self.assertTrue(vk.verify(sig, data)) - - sk2 = SigningKey.generate(curve=NIST256p) - sig2 = sk2.sign(data, hashfunc=hashlib.sha256) - vk2 = VerifyingKey.from_string( - sk2.get_verifying_key().to_string(), - curve=NIST256p, - hashfunc=hashlib.sha256, - ) - self.assertTrue(vk2.verify(sig2, data)) - - vk3 = VerifyingKey.from_string( - sk.get_verifying_key().to_string(), curve=NIST256p - ) - self.assertTrue(vk3.verify(sig, data, hashfunc=hashlib.sha256)) - - def test_public_key_recovery(self): - # Create keys - curve = BRAINPOOLP160r1 - - sk = SigningKey.generate(curve=curve) - vk = sk.get_verifying_key() - - # Sign a message - data = b"blahblah" - signature = sk.sign(data) - - # Recover verifying keys - recovered_vks = VerifyingKey.from_public_key_recovery( - signature, data, curve - ) - - # Test if each pk is valid - for recovered_vk in recovered_vks: - # Test if recovered vk is valid for the data - self.assertTrue(recovered_vk.verify(signature, data)) - - # Test if properties are equal - self.assertEqual(vk.curve, recovered_vk.curve) - self.assertEqual( - vk.default_hashfunc, recovered_vk.default_hashfunc - ) - - # Test if original vk is the list of recovered keys - self.assertIn( - vk.pubkey.point, - [recovered_vk.pubkey.point for recovered_vk in recovered_vks], - ) - - def test_public_key_recovery_with_custom_hash(self): - # Create keys - curve = BRAINPOOLP160r1 - - sk = SigningKey.generate(curve=curve, hashfunc=hashlib.sha256) - vk = sk.get_verifying_key() - - # Sign a message - data = b"blahblah" - signature = sk.sign(data) - - # Recover verifying keys - recovered_vks = VerifyingKey.from_public_key_recovery( - signature, - data, - curve, - hashfunc=hashlib.sha256, - allow_truncate=True, - ) - - # Test if each pk is valid - for recovered_vk in recovered_vks: - # Test if recovered vk is valid for the data - self.assertTrue(recovered_vk.verify(signature, data)) - - # Test if properties are equal - self.assertEqual(vk.curve, recovered_vk.curve) - self.assertEqual(hashlib.sha256, recovered_vk.default_hashfunc) - - # Test if original vk is the list of recovered keys - self.assertIn( - vk.pubkey.point, - [recovered_vk.pubkey.point for recovered_vk in recovered_vks], - ) - - def test_encoding(self): - sk = SigningKey.from_secret_exponent(123456789) - vk = sk.verifying_key - - exp = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - self.assertEqual(vk.to_string(), exp) - self.assertEqual(vk.to_string("raw"), exp) - self.assertEqual(vk.to_string("uncompressed"), b"\x04" + exp) - self.assertEqual(vk.to_string("compressed"), b"\x02" + exp[:24]) - self.assertEqual(vk.to_string("hybrid"), b"\x06" + exp) - - def test_decoding(self): - sk = SigningKey.from_secret_exponent(123456789) - vk = sk.verifying_key - - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - - from_raw = VerifyingKey.from_string(enc) - self.assertEqual(from_raw.pubkey.point, vk.pubkey.point) - - from_uncompressed = VerifyingKey.from_string(b"\x04" + enc) - self.assertEqual(from_uncompressed.pubkey.point, vk.pubkey.point) - - from_compressed = VerifyingKey.from_string(b"\x02" + enc[:24]) - self.assertEqual(from_compressed.pubkey.point, vk.pubkey.point) - - from_uncompressed = VerifyingKey.from_string(b"\x06" + enc) - self.assertEqual(from_uncompressed.pubkey.point, vk.pubkey.point) - - def test_uncompressed_decoding_as_only_alowed(self): - enc = ( - b"\x04" - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - vk = VerifyingKey.from_string(enc, valid_encodings=("uncompressed",)) - sk = SigningKey.from_secret_exponent(123456789) - - self.assertEqual(vk, sk.verifying_key) - - def test_raw_decoding_with_blocked_format(self): - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - with self.assertRaises(MalformedPointError) as exp: - VerifyingKey.from_string(enc, valid_encodings=("hybrid",)) - - self.assertIn("hybrid", str(exp.exception)) - - def test_decoding_with_unknown_format(self): - with self.assertRaises(ValueError) as e: - VerifyingKey.from_string(b"", valid_encodings=("raw", "foobar")) - - self.assertIn("Only uncompressed, compressed", str(e.exception)) - - def test_uncompressed_decoding_with_blocked_format(self): - enc = ( - b"\x04" - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - with self.assertRaises(MalformedPointError) as exp: - VerifyingKey.from_string(enc, valid_encodings=("hybrid",)) - - self.assertIn("Invalid X9.62 encoding", str(exp.exception)) - - def test_hybrid_decoding_with_blocked_format(self): - enc = ( - b"\x06" - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - with self.assertRaises(MalformedPointError) as exp: - VerifyingKey.from_string(enc, valid_encodings=("uncompressed",)) - - self.assertIn("Invalid X9.62 encoding", str(exp.exception)) - - def test_hybrid_decoding_with_inconsistent_encoding_and_no_validation( - self, - ): - sk = SigningKey.from_secret_exponent(123456789) - vk = sk.verifying_key - - enc = vk.to_string("hybrid") - self.assertEqual(enc[:1], b"\x06") - enc = b"\x07" + enc[1:] - - b = VerifyingKey.from_string( - enc, valid_encodings=("hybrid",), validate_point=False - ) - - self.assertEqual(vk, b) - - def test_compressed_decoding_with_blocked_format(self): - enc = ( - b"\x02" - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - )[:25] - with self.assertRaises(MalformedPointError) as exp: - VerifyingKey.from_string(enc, valid_encodings=("hybrid", "raw")) - - self.assertIn("(hybrid, raw)", str(exp.exception)) - - def test_decoding_with_malformed_uncompressed(self): - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x02" + enc) - - def test_decoding_with_malformed_compressed(self): - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x01" + enc[:24]) - - def test_decoding_with_inconsistent_hybrid(self): - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x07" + enc) - - def test_decoding_with_inconsistent_hybrid_odd_point(self): - sk = SigningKey.from_secret_exponent(123456791) - vk = sk.verifying_key - - enc = vk.to_string("hybrid") - self.assertEqual(enc[:1], b"\x07") - enc = b"\x06" + enc[1:] - - with self.assertRaises(MalformedPointError): - b = VerifyingKey.from_string(enc, valid_encodings=("hybrid",)) - - def test_decoding_with_point_not_on_curve(self): - enc = ( - b"\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" - b"\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" - b"z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" - ) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(enc[:47] + b"\x00") - - def test_decoding_with_point_at_infinity(self): - # decoding it is unsupported, as it's not necessary to encode it - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x00") - - def test_not_lying_on_curve(self): - enc = number_to_string(NIST192p.curve.p(), NIST192p.curve.p() + 1) - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x02" + enc) - - def test_from_string_with_invalid_curve_too_short_ver_key_len(self): - # both verifying_key_length and baselen are calculated internally - # by the Curve constructor, but since we depend on them verify - # that inconsistent values are detected - curve = Curve("test", ecdsa.curve_192, ecdsa.generator_192, (1, 2)) - curve.verifying_key_length = 16 - curve.baselen = 32 - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x00" * 16, curve) - - def test_from_string_with_invalid_curve_too_long_ver_key_len(self): - # both verifying_key_length and baselen are calculated internally - # by the Curve constructor, but since we depend on them verify - # that inconsistent values are detected - curve = Curve("test", ecdsa.curve_192, ecdsa.generator_192, (1, 2)) - curve.verifying_key_length = 16 - curve.baselen = 16 - - with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b"\x00" * 16, curve) - - -@pytest.mark.parametrize( - "val,even", [(i, j) for i in range(256) for j in [True, False]] -) -def test_VerifyingKey_decode_with_small_values(val, even): - enc = number_to_string(val, NIST192p.order) - - if even: - enc = b"\x02" + enc - else: - enc = b"\x03" + enc - - # small values can both be actual valid public keys and not, verify that - # only expected exceptions are raised if they are not - try: - vk = VerifyingKey.from_string(enc) - assert isinstance(vk, VerifyingKey) - except MalformedPointError: - assert True - - -params = [] -for curve in curves: - for enc in ["raw", "uncompressed", "compressed", "hybrid"]: - params.append( - pytest.param(curve, enc, id="{0}-{1}".format(curve.name, enc)) - ) - - -@pytest.mark.parametrize("curve,encoding", params) -def test_VerifyingKey_encode_decode(curve, encoding): - sk = SigningKey.generate(curve=curve) - vk = sk.verifying_key - - encoded = vk.to_string(encoding) - - from_enc = VerifyingKey.from_string(encoded, curve=curve) - - assert vk.pubkey.point == from_enc.pubkey.point - - -if "--fast" in sys.argv: # pragma: no cover - params = [NIST192p, BRAINPOOLP160r1] -else: - params = curves - - -@pytest.mark.parametrize("curve", params) -def test_lengths(curve): - priv = SigningKey.generate(curve=curve) - pub1 = priv.get_verifying_key() - pub2 = VerifyingKey.from_string(pub1.to_string(), curve) - assert pub1.to_string() == pub2.to_string() - assert len(pub1.to_string()) == curve.verifying_key_length - sig = priv.sign(b"data") - assert len(sig) == curve.signature_length - - -@pytest.mark.slow -class OpenSSL(unittest.TestCase): - # test interoperability with OpenSSL tools. Note that openssl's ECDSA - # sign/verify arguments changed between 0.9.8 and 1.0.0: the early - # versions require "-ecdsa-with-SHA1", the later versions want just - # "-SHA1" (or to leave out that argument entirely, which means the - # signature will use some default digest algorithm, probably determined - # by the key, probably always SHA1). - # - # openssl ecparam -name secp224r1 -genkey -out privkey.pem - # openssl ec -in privkey.pem -text -noout # get the priv/pub keys - # openssl dgst -ecdsa-with-SHA1 -sign privkey.pem -out data.sig data.txt - # openssl asn1parse -in data.sig -inform DER - # data.sig is 64 bytes, probably 56b plus ASN1 overhead - # openssl dgst -ecdsa-with-SHA1 -prverify privkey.pem -signature data.sig data.txt ; echo $? - # openssl ec -in privkey.pem -pubout -out pubkey.pem - # openssl ec -in privkey.pem -pubout -outform DER -out pubkey.der - - OPENSSL_SUPPORTED_CURVES = set( - c.split(":")[0].strip() - for c in run_openssl("ecparam -list_curves").split("\n") - ) - - def get_openssl_messagedigest_arg(self, hash_name): - v = run_openssl("version") - # e.g. "OpenSSL 1.0.0 29 Mar 2010", or "OpenSSL 1.0.0a 1 Jun 2010", - # or "OpenSSL 0.9.8o 01 Jun 2010" - vs = v.split()[1].split(".") - if vs >= ["1", "0", "0"]: # pragma: no cover - return "-{0}".format(hash_name) - else: # pragma: no cover - return "-ecdsa-with-{0}".format(hash_name) - - # sk: 1:OpenSSL->python 2:python->OpenSSL - # vk: 3:OpenSSL->python 4:python->OpenSSL - # sig: 5:OpenSSL->python 6:python->OpenSSL - - @pytest.mark.slow - @pytest.mark.skipif( - "secp112r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp112r1", - ) - def test_from_openssl_secp112r1(self): - return self.do_test_from_openssl(SECP112r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp112r2" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp112r2", - ) - def test_from_openssl_secp112r2(self): - return self.do_test_from_openssl(SECP112r2) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp128r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp128r1", - ) - def test_from_openssl_secp128r1(self): - return self.do_test_from_openssl(SECP128r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp160r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp160r1", - ) - def test_from_openssl_secp160r1(self): - return self.do_test_from_openssl(SECP160r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_from_openssl_nist192p(self): - return self.do_test_from_openssl(NIST192p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_from_openssl_nist192p_sha256(self): - return self.do_test_from_openssl(NIST192p, "SHA256") - - @pytest.mark.slow - @pytest.mark.skipif( - "secp224r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp224r1", - ) - def test_from_openssl_nist224p(self): - return self.do_test_from_openssl(NIST224p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_from_openssl_nist256p(self): - return self.do_test_from_openssl(NIST256p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_from_openssl_nist256p_sha384(self): - return self.do_test_from_openssl(NIST256p, "SHA384") - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_from_openssl_nist256p_sha512(self): - return self.do_test_from_openssl(NIST256p, "SHA512") - - @pytest.mark.slow - @pytest.mark.skipif( - "secp384r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp384r1", - ) - def test_from_openssl_nist384p(self): - return self.do_test_from_openssl(NIST384p) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp521r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp521r1", - ) - def test_from_openssl_nist521p(self): - return self.do_test_from_openssl(NIST521p) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp256k1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp256k1", - ) - def test_from_openssl_secp256k1(self): - return self.do_test_from_openssl(SECP256k1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP160r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP160r1", - ) - def test_from_openssl_brainpoolp160r1(self): - return self.do_test_from_openssl(BRAINPOOLP160r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP192r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP192r1", - ) - def test_from_openssl_brainpoolp192r1(self): - return self.do_test_from_openssl(BRAINPOOLP192r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP224r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP224r1", - ) - def test_from_openssl_brainpoolp224r1(self): - return self.do_test_from_openssl(BRAINPOOLP224r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP256r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP256r1", - ) - def test_from_openssl_brainpoolp256r1(self): - return self.do_test_from_openssl(BRAINPOOLP256r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP320r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP320r1", - ) - def test_from_openssl_brainpoolp320r1(self): - return self.do_test_from_openssl(BRAINPOOLP320r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP384r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP384r1", - ) - def test_from_openssl_brainpoolp384r1(self): - return self.do_test_from_openssl(BRAINPOOLP384r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP512r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP512r1", - ) - def test_from_openssl_brainpoolp512r1(self): - return self.do_test_from_openssl(BRAINPOOLP512r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP160t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP160t1", - ) - def test_from_openssl_brainpoolp160t1(self): - return self.do_test_from_openssl(BRAINPOOLP160t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP192t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP192t1", - ) - def test_from_openssl_brainpoolp192t1(self): - return self.do_test_from_openssl(BRAINPOOLP192t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP224t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP224t1", - ) - def test_from_openssl_brainpoolp224t1(self): - return self.do_test_from_openssl(BRAINPOOLP224t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP256t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP256t1", - ) - def test_from_openssl_brainpoolp256t1(self): - return self.do_test_from_openssl(BRAINPOOLP256t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP320t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP320t1", - ) - def test_from_openssl_brainpoolp320t1(self): - return self.do_test_from_openssl(BRAINPOOLP320t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP384t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP384t1", - ) - def test_from_openssl_brainpoolp384t1(self): - return self.do_test_from_openssl(BRAINPOOLP384t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP512t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP512t1", - ) - def test_from_openssl_brainpoolp512t1(self): - return self.do_test_from_openssl(BRAINPOOLP512t1) - - def do_test_from_openssl(self, curve, hash_name="SHA1"): - curvename = curve.openssl_name - assert curvename - # OpenSSL: create sk, vk, sign. - # Python: read vk(3), checksig(5), read sk(1), sign, check - mdarg = self.get_openssl_messagedigest_arg(hash_name) - if os.path.isdir("t"): # pragma: no cover - shutil.rmtree("t") - os.mkdir("t") - run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename) - run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem") - data = b"data" - with open("t/data.txt", "wb") as e: - e.write(data) - run_openssl( - "dgst %s -sign t/privkey.pem -out t/data.sig t/data.txt" % mdarg - ) - run_openssl( - "dgst %s -verify t/pubkey.pem -signature t/data.sig t/data.txt" - % mdarg - ) - with open("t/pubkey.pem", "rb") as e: - pubkey_pem = e.read() - vk = VerifyingKey.from_pem(pubkey_pem) # 3 - with open("t/data.sig", "rb") as e: - sig_der = e.read() - self.assertTrue( - vk.verify( - sig_der, - data, # 5 - hashfunc=partial(hashlib.new, hash_name), - sigdecode=sigdecode_der, - ) - ) - - with open("t/privkey.pem") as e: - fp = e.read() - sk = SigningKey.from_pem(fp) # 1 - sig = sk.sign(data, hashfunc=partial(hashlib.new, hash_name)) - self.assertTrue( - vk.verify(sig, data, hashfunc=partial(hashlib.new, hash_name)) - ) - - run_openssl( - "pkcs8 -topk8 -nocrypt " - "-in t/privkey.pem -outform pem -out t/privkey-p8.pem" - ) - with open("t/privkey-p8.pem", "rb") as e: - privkey_p8_pem = e.read() - sk_from_p8 = SigningKey.from_pem(privkey_p8_pem) - self.assertEqual(sk, sk_from_p8) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp112r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp112r1", - ) - def test_to_openssl_secp112r1(self): - self.do_test_to_openssl(SECP112r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp112r2" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp112r2", - ) - def test_to_openssl_secp112r2(self): - self.do_test_to_openssl(SECP112r2) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp128r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp128r1", - ) - def test_to_openssl_secp128r1(self): - self.do_test_to_openssl(SECP128r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp160r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp160r1", - ) - def test_to_openssl_secp160r1(self): - self.do_test_to_openssl(SECP160r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_to_openssl_nist192p(self): - self.do_test_to_openssl(NIST192p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_to_openssl_nist192p_sha256(self): - self.do_test_to_openssl(NIST192p, "SHA256") - - @pytest.mark.slow - @pytest.mark.skipif( - "secp224r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp224r1", - ) - def test_to_openssl_nist224p(self): - self.do_test_to_openssl(NIST224p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_to_openssl_nist256p(self): - self.do_test_to_openssl(NIST256p) - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_to_openssl_nist256p_sha384(self): - self.do_test_to_openssl(NIST256p, "SHA384") - - @pytest.mark.slow - @pytest.mark.skipif( - "prime256v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime256v1", - ) - def test_to_openssl_nist256p_sha512(self): - self.do_test_to_openssl(NIST256p, "SHA512") - - @pytest.mark.slow - @pytest.mark.skipif( - "secp384r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp384r1", - ) - def test_to_openssl_nist384p(self): - self.do_test_to_openssl(NIST384p) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp521r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp521r1", - ) - def test_to_openssl_nist521p(self): - self.do_test_to_openssl(NIST521p) - - @pytest.mark.slow - @pytest.mark.skipif( - "secp256k1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support secp256k1", - ) - def test_to_openssl_secp256k1(self): - self.do_test_to_openssl(SECP256k1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP160r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP160r1", - ) - def test_to_openssl_brainpoolp160r1(self): - self.do_test_to_openssl(BRAINPOOLP160r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP192r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP192r1", - ) - def test_to_openssl_brainpoolp192r1(self): - self.do_test_to_openssl(BRAINPOOLP192r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP224r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP224r1", - ) - def test_to_openssl_brainpoolp224r1(self): - self.do_test_to_openssl(BRAINPOOLP224r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP256r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP256r1", - ) - def test_to_openssl_brainpoolp256r1(self): - self.do_test_to_openssl(BRAINPOOLP256r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP320r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP320r1", - ) - def test_to_openssl_brainpoolp320r1(self): - self.do_test_to_openssl(BRAINPOOLP320r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP384r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP384r1", - ) - def test_to_openssl_brainpoolp384r1(self): - self.do_test_to_openssl(BRAINPOOLP384r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP512r1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP512r1", - ) - def test_to_openssl_brainpoolp512r1(self): - self.do_test_to_openssl(BRAINPOOLP512r1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP160t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP160t1", - ) - def test_to_openssl_brainpoolp160t1(self): - self.do_test_to_openssl(BRAINPOOLP160t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP192t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP192t1", - ) - def test_to_openssl_brainpoolp192t1(self): - self.do_test_to_openssl(BRAINPOOLP192t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP224t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP224t1", - ) - def test_to_openssl_brainpoolp224t1(self): - self.do_test_to_openssl(BRAINPOOLP224t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP256t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP256t1", - ) - def test_to_openssl_brainpoolp256t1(self): - self.do_test_to_openssl(BRAINPOOLP256t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP320t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP320t1", - ) - def test_to_openssl_brainpoolp320t1(self): - self.do_test_to_openssl(BRAINPOOLP320t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP384t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP384t1", - ) - def test_to_openssl_brainpoolp384t1(self): - self.do_test_to_openssl(BRAINPOOLP384t1) - - @pytest.mark.slow - @pytest.mark.skipif( - "brainpoolP512t1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support brainpoolP512t1", - ) - def test_to_openssl_brainpoolp512t1(self): - self.do_test_to_openssl(BRAINPOOLP512t1) - - def do_test_to_openssl(self, curve, hash_name="SHA1"): - curvename = curve.openssl_name - assert curvename - # Python: create sk, vk, sign. - # OpenSSL: read vk(4), checksig(6), read sk(2), sign, check - mdarg = self.get_openssl_messagedigest_arg(hash_name) - if os.path.isdir("t"): # pragma: no cover - shutil.rmtree("t") - os.mkdir("t") - sk = SigningKey.generate(curve=curve) - vk = sk.get_verifying_key() - data = b"data" - with open("t/pubkey.der", "wb") as e: - e.write(vk.to_der()) # 4 - with open("t/pubkey.pem", "wb") as e: - e.write(vk.to_pem()) # 4 - sig_der = sk.sign( - data, - hashfunc=partial(hashlib.new, hash_name), - sigencode=sigencode_der, - ) - - with open("t/data.sig", "wb") as e: - e.write(sig_der) # 6 - with open("t/data.txt", "wb") as e: - e.write(data) - with open("t/baddata.txt", "wb") as e: - e.write(data + b"corrupt") - - self.assertRaises( - SubprocessError, - run_openssl, - "dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/baddata.txt" - % mdarg, - ) - run_openssl( - "dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/data.txt" - % mdarg - ) - - with open("t/privkey.pem", "wb") as e: - e.write(sk.to_pem()) # 2 - run_openssl( - "dgst %s -sign t/privkey.pem -out t/data.sig2 t/data.txt" % mdarg - ) - run_openssl( - "dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" - % mdarg - ) - - with open("t/privkey-explicit.pem", "wb") as e: - e.write(sk.to_pem(curve_parameters_encoding="explicit")) - run_openssl( - "dgst %s -sign t/privkey-explicit.pem -out t/data.sig2 t/data.txt" - % mdarg - ) - run_openssl( - "dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" - % mdarg - ) - - with open("t/privkey-p8.pem", "wb") as e: - e.write(sk.to_pem(format="pkcs8")) - run_openssl( - "dgst %s -sign t/privkey-p8.pem -out t/data.sig3 t/data.txt" - % mdarg - ) - run_openssl( - "dgst %s -verify t/pubkey.pem -signature t/data.sig3 t/data.txt" - % mdarg - ) - - with open("t/privkey-p8-explicit.pem", "wb") as e: - e.write( - sk.to_pem(format="pkcs8", curve_parameters_encoding="explicit") - ) - run_openssl( - "dgst %s -sign t/privkey-p8-explicit.pem -out t/data.sig3 t/data.txt" - % mdarg - ) - run_openssl( - "dgst %s -verify t/pubkey.pem -signature t/data.sig3 t/data.txt" - % mdarg - ) - - OPENSSL_SUPPORTED_TYPES = set() - try: - if "-rawin" in run_openssl("pkeyutl -help"): - OPENSSL_SUPPORTED_TYPES = set( # pragma: no branch - c.lower() - for c in ("ED25519", "ED448") - if c in run_openssl("list -public-key-methods") - ) - except SubprocessError: # pragma: no cover - pass - - def do_eddsa_test_to_openssl(self, curve): - if os.path.isdir("t"): - shutil.rmtree("t") - os.mkdir("t") - - sk = SigningKey.generate(curve=curve) - vk = sk.get_verifying_key() - - data = b"data" - with open("t/pubkey.der", "wb") as e: - e.write(vk.to_der()) - with open("t/pubkey.pem", "wb") as e: - e.write(vk.to_pem()) - - sig = sk.sign(data) - - with open("t/data.sig", "wb") as e: - e.write(sig) - with open("t/data.txt", "wb") as e: - e.write(data) - with open("t/baddata.txt", "wb") as e: - e.write(data + b"corrupt") - - with self.assertRaises(SubprocessError): - run_openssl( - "pkeyutl -verify -pubin -inkey t/pubkey.pem -rawin " - "-in t/baddata.txt -sigfile t/data.sig" - ) - run_openssl( - "pkeyutl -verify -pubin -inkey t/pubkey.pem -rawin " - "-in t/data.txt -sigfile t/data.sig" - ) - - shutil.rmtree("t") - - # in practice at least OpenSSL 3.0.0 is needed to make EdDSA signatures - # earlier versions support EdDSA only in X.509 certificates - @pytest.mark.slow - @pytest.mark.skipif( - "ed25519" not in OPENSSL_SUPPORTED_TYPES, - reason="system openssl does not support signing with Ed25519", - ) - def test_to_openssl_ed25519(self): - return self.do_eddsa_test_to_openssl(Ed25519) - - @pytest.mark.slow - @pytest.mark.skipif( - "ed448" not in OPENSSL_SUPPORTED_TYPES, - reason="system openssl does not support signing with Ed448", - ) - def test_to_openssl_ed448(self): - return self.do_eddsa_test_to_openssl(Ed448) - - def do_eddsa_test_from_openssl(self, curve): - curvename = curve.name - - if os.path.isdir("t"): - shutil.rmtree("t") - os.mkdir("t") - - data = b"data" - - run_openssl( - "genpkey -algorithm {0} -outform PEM -out t/privkey.pem".format( - curvename - ) - ) - run_openssl( - "pkey -outform PEM -pubout -in t/privkey.pem -out t/pubkey.pem" - ) - - with open("t/data.txt", "wb") as e: - e.write(data) - run_openssl( - "pkeyutl -sign -inkey t/privkey.pem " - "-rawin -in t/data.txt -out t/data.sig" - ) - - with open("t/data.sig", "rb") as e: - sig = e.read() - with open("t/pubkey.pem", "rb") as e: - vk = VerifyingKey.from_pem(e.read()) - - self.assertIs(vk.curve, curve) - - vk.verify(sig, data) - - shutil.rmtree("t") - - @pytest.mark.slow - @pytest.mark.skipif( - "ed25519" not in OPENSSL_SUPPORTED_TYPES, - reason="system openssl does not support signing with Ed25519", - ) - def test_from_openssl_ed25519(self): - return self.do_eddsa_test_from_openssl(Ed25519) - - @pytest.mark.slow - @pytest.mark.skipif( - "ed448" not in OPENSSL_SUPPORTED_TYPES, - reason="system openssl does not support signing with Ed448", - ) - def test_from_openssl_ed448(self): - return self.do_eddsa_test_from_openssl(Ed448) - - -class TooSmallCurve(unittest.TestCase): - OPENSSL_SUPPORTED_CURVES = set( - c.split(":")[0].strip() - for c in run_openssl("ecparam -list_curves").split("\n") - ) - - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_sign_too_small_curve_dont_allow_truncate_raises(self): - sk = SigningKey.generate(curve=NIST192p) - data = b"data" - with self.assertRaises(BadDigestError): - sk.sign( - data, - hashfunc=partial(hashlib.new, "SHA256"), - sigencode=sigencode_der, - allow_truncate=False, - ) - - @pytest.mark.skipif( - "prime192v1" not in OPENSSL_SUPPORTED_CURVES, - reason="system openssl does not support prime192v1", - ) - def test_verify_too_small_curve_dont_allow_truncate_raises(self): - sk = SigningKey.generate(curve=NIST192p) - vk = sk.get_verifying_key() - data = b"data" - sig_der = sk.sign( - data, - hashfunc=partial(hashlib.new, "SHA256"), - sigencode=sigencode_der, - allow_truncate=True, - ) - with self.assertRaises(BadDigestError): - vk.verify( - sig_der, - data, - hashfunc=partial(hashlib.new, "SHA256"), - sigdecode=sigdecode_der, - allow_truncate=False, - ) - - -class DER(unittest.TestCase): - def test_integer(self): - self.assertEqual(der.encode_integer(0), b"\x02\x01\x00") - self.assertEqual(der.encode_integer(1), b"\x02\x01\x01") - self.assertEqual(der.encode_integer(127), b"\x02\x01\x7f") - self.assertEqual(der.encode_integer(128), b"\x02\x02\x00\x80") - self.assertEqual(der.encode_integer(256), b"\x02\x02\x01\x00") - # self.assertEqual(der.encode_integer(-1), b"\x02\x01\xff") - - def s(n): - return der.remove_integer(der.encode_integer(n) + b"junk") - - self.assertEqual(s(0), (0, b"junk")) - self.assertEqual(s(1), (1, b"junk")) - self.assertEqual(s(127), (127, b"junk")) - self.assertEqual(s(128), (128, b"junk")) - self.assertEqual(s(256), (256, b"junk")) - self.assertEqual( - s(1234567890123456789012345678901234567890), - (1234567890123456789012345678901234567890, b"junk"), - ) - - def test_number(self): - self.assertEqual(der.encode_number(0), b"\x00") - self.assertEqual(der.encode_number(127), b"\x7f") - self.assertEqual(der.encode_number(128), b"\x81\x00") - self.assertEqual(der.encode_number(3 * 128 + 7), b"\x83\x07") - # self.assertEqual(der.read_number("\x81\x9b" + "more"), (155, 2)) - # self.assertEqual(der.encode_number(155), b"\x81\x9b") - for n in (0, 1, 2, 127, 128, 3 * 128 + 7, 840, 10045): # , 155): - x = der.encode_number(n) + b"more" - n1, llen = der.read_number(x) - self.assertEqual(n1, n) - self.assertEqual(x[llen:], b"more") - - def test_length(self): - self.assertEqual(der.encode_length(0), b"\x00") - self.assertEqual(der.encode_length(127), b"\x7f") - self.assertEqual(der.encode_length(128), b"\x81\x80") - self.assertEqual(der.encode_length(255), b"\x81\xff") - self.assertEqual(der.encode_length(256), b"\x82\x01\x00") - self.assertEqual(der.encode_length(3 * 256 + 7), b"\x82\x03\x07") - self.assertEqual(der.read_length(b"\x81\x9b" + b"more"), (155, 2)) - self.assertEqual(der.encode_length(155), b"\x81\x9b") - for n in (0, 1, 2, 127, 128, 255, 256, 3 * 256 + 7, 155): - x = der.encode_length(n) + b"more" - n1, llen = der.read_length(x) - self.assertEqual(n1, n) - self.assertEqual(x[llen:], b"more") - - def test_sequence(self): - x = der.encode_sequence(b"ABC", b"DEF") + b"GHI" - self.assertEqual(x, b"\x30\x06ABCDEFGHI") - x1, rest = der.remove_sequence(x) - self.assertEqual(x1, b"ABCDEF") - self.assertEqual(rest, b"GHI") - - def test_constructed(self): - x = der.encode_constructed(0, NIST224p.encoded_oid) - self.assertEqual(hexlify(x), b"a007" + b"06052b81040021") - x = der.encode_constructed(1, unhexlify(b"0102030a0b0c")) - self.assertEqual(hexlify(x), b"a106" + b"0102030a0b0c") - - -class Util(unittest.TestCase): - @pytest.mark.slow - def test_trytryagain(self): - tta = util.randrange_from_seed__trytryagain - for i in range(1000): - seed = "seed-%d" % i - for order in ( - 2**8 - 2, - 2**8 - 1, - 2**8, - 2**8 + 1, - 2**8 + 2, - 2**16 - 1, - 2**16 + 1, - ): - n = tta(seed, order) - self.assertTrue(1 <= n < order, (1, n, order)) - # this trytryagain *does* provide long-term stability - self.assertEqual( - ("%x" % (tta("seed", NIST224p.order))).encode(), - b"6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc", - ) - - def test_trytryagain_single(self): - tta = util.randrange_from_seed__trytryagain - order = 2**8 - 2 - seed = b"text" - n = tta(seed, order) - # known issue: https://github.com/warner/python-ecdsa/issues/221 - if sys.version_info < (3, 0): # pragma: no branch - self.assertEqual(n, 228) - else: # pragma: no branch - self.assertEqual(n, 18) - - @settings(**HYP_SETTINGS) - @given(st.integers(min_value=0, max_value=10**200)) - def test_randrange(self, i): - # util.randrange does not provide long-term stability: we might - # change the algorithm in the future. - entropy = util.PRNG("seed-%d" % i) - for order in ( - 2**8 - 2, - 2**8 - 1, - 2**8, - 2**16 - 1, - 2**16 + 1, - ): - # that oddball 2**16+1 takes half our runtime - n = util.randrange(order, entropy=entropy) - self.assertTrue(1 <= n < order, (1, n, order)) - - def OFF_test_prove_uniformity(self): # pragma: no cover - order = 2**8 - 2 - counts = dict([(i, 0) for i in range(1, order)]) - assert 0 not in counts - assert order not in counts - for i in range(1000000): - seed = "seed-%d" % i - n = util.randrange_from_seed__trytryagain(seed, order) - counts[n] += 1 - # this technique should use the full range - self.assertTrue(counts[order - 1]) - for i in range(1, order): - print("%3d: %s" % (i, "*" * (counts[i] // 100))) - - -class RFC6979(unittest.TestCase): - # https://tools.ietf.org/html/rfc6979#appendix-A.1 - def _do(self, generator, secexp, hsh, hash_func, expected): - actual = rfc6979.generate_k(generator.order(), secexp, hash_func, hsh) - self.assertEqual(expected, actual) - - def test_SECP256k1(self): - """RFC doesn't contain test vectors for SECP256k1 used in bitcoin. - This vector has been computed by Golang reference implementation instead.""" - self._do( - generator=SECP256k1.generator, - secexp=int("9d0219792467d7d37b4d43298a7d0c05", 16), - hsh=hashlib.sha256(b"sample").digest(), - hash_func=hashlib.sha256, - expected=int( - "8fa1f95d514760e498f28957b824ee6ec39ed64826ff4fecc2b5739ec45b91cd", - 16, - ), - ) - - def test_SECP256k1_2(self): - self._do( - generator=SECP256k1.generator, - secexp=int( - "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", - 16, - ), - hsh=hashlib.sha256(b"sample").digest(), - hash_func=hashlib.sha256, - expected=int( - "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", - 16, - ), - ) - - def test_SECP256k1_3(self): - self._do( - generator=SECP256k1.generator, - secexp=0x1, - hsh=hashlib.sha256(b"Satoshi Nakamoto").digest(), - hash_func=hashlib.sha256, - expected=0x8F8A276C19F4149656B280621E358CCE24F5F52542772691EE69063B74F15D15, - ) - - def test_SECP256k1_4(self): - self._do( - generator=SECP256k1.generator, - secexp=0x1, - hsh=hashlib.sha256( - b"All those moments will be lost in time, like tears in rain. Time to die..." - ).digest(), - hash_func=hashlib.sha256, - expected=0x38AA22D72376B4DBC472E06C3BA403EE0A394DA63FC58D88686C611ABA98D6B3, - ) - - def test_SECP256k1_5(self): - self._do( - generator=SECP256k1.generator, - secexp=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, - hsh=hashlib.sha256(b"Satoshi Nakamoto").digest(), - hash_func=hashlib.sha256, - expected=0x33A19B60E25FB6F4435AF53A3D42D493644827367E6453928554F43E49AA6F90, - ) - - def test_SECP256k1_6(self): - self._do( - generator=SECP256k1.generator, - secexp=0xF8B8AF8CE3C7CCA5E300D33939540C10D45CE001B8F252BFBC57BA0342904181, - hsh=hashlib.sha256(b"Alan Turing").digest(), - hash_func=hashlib.sha256, - expected=0x525A82B70E67874398067543FD84C83D30C175FDC45FDEEE082FE13B1D7CFDF1, - ) - - def test_1(self): - # Basic example of the RFC, it also tests 'try-try-again' from Step H of rfc6979 - self._do( - generator=Point( - None, - 0, - 0, - int("4000000000000000000020108A2E0CC0D99F8A5EF", 16), - ), - secexp=int("09A4D6792295A7F730FC3F2B49CBC0F62E862272F", 16), - hsh=unhexlify( - b"AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF" - ), - hash_func=hashlib.sha256, - expected=int("23AF4074C90A02B3FE61D286D5C87F425E6BDD81B", 16), - ) - - def test_2(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha1(b"sample").digest(), - hash_func=hashlib.sha1, - expected=int( - "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", 16 - ), - ) - - def test_3(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha256(b"sample").digest(), - hash_func=hashlib.sha256, - expected=int( - "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", 16 - ), - ) - - def test_4(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha512(b"sample").digest(), - hash_func=hashlib.sha512, - expected=int( - "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", 16 - ), - ) - - def test_5(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha1(b"test").digest(), - hash_func=hashlib.sha1, - expected=int( - "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", 16 - ), - ) - - def test_6(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha256(b"test").digest(), - hash_func=hashlib.sha256, - expected=int( - "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", 16 - ), - ) - - def test_7(self): - self._do( - generator=NIST192p.generator, - secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=hashlib.sha512(b"test").digest(), - hash_func=hashlib.sha512, - expected=int( - "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", 16 - ), - ) - - def test_8(self): - self._do( - generator=NIST521p.generator, - secexp=int( - "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", - 16, - ), - hsh=hashlib.sha1(b"sample").digest(), - hash_func=hashlib.sha1, - expected=int( - "089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", - 16, - ), - ) - - def test_9(self): - self._do( - generator=NIST521p.generator, - secexp=int( - "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", - 16, - ), - hsh=hashlib.sha256(b"sample").digest(), - hash_func=hashlib.sha256, - expected=int( - "0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", - 16, - ), - ) - - def test_10(self): - self._do( - generator=NIST521p.generator, - secexp=int( - "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", - 16, - ), - hsh=hashlib.sha512(b"test").digest(), - hash_func=hashlib.sha512, - expected=int( - "16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", - 16, - ), - ) - - -class ECDH(unittest.TestCase): - def _do(self, curve, generator, dA, x_qA, y_qA, dB, x_qB, y_qB, x_Z, y_Z): - qA = dA * generator - qB = dB * generator - Z = dA * qB - self.assertEqual(Point(curve, x_qA, y_qA), qA) - self.assertEqual(Point(curve, x_qB, y_qB), qB) - self.assertTrue( - (dA * qB) - == (dA * dB * generator) - == (dB * dA * generator) - == (dB * qA) - ) - self.assertEqual(Point(curve, x_Z, y_Z), Z) - - -class RFC6932(ECDH): - # https://tools.ietf.org/html/rfc6932#appendix-A.1 - - def test_brainpoolP224r1(self): - self._do( - curve=curve_brainpoolp224r1, - generator=BRAINPOOLP224r1.generator, - dA=int( - "7C4B7A2C8A4BAD1FBB7D79CC0955DB7C6A4660CA64CC4778159B495E", 16 - ), - x_qA=int( - "B104A67A6F6E85E14EC1825E1539E8ECDBBF584922367DD88C6BDCF2", 16 - ), - y_qA=int( - "46D782E7FDB5F60CD8404301AC5949C58EDB26BC68BA07695B750A94", 16 - ), - dB=int( - "63976D4AAE6CD0F6DD18DEFEF55D96569D0507C03E74D6486FFA28FB", 16 - ), - x_qB=int( - "2A97089A9296147B71B21A4B574E1278245B536F14D8C2B9D07A874E", 16 - ), - y_qB=int( - "9B900D7C77A709A797276B8CA1BA61BB95B546FC29F862E44D59D25B", 16 - ), - x_Z=int( - "312DFD98783F9FB77B9704945A73BEB6DCCBE3B65D0F967DCAB574EB", 16 - ), - y_Z=int( - "6F800811D64114B1C48C621AB3357CF93F496E4238696A2A012B3C98", 16 - ), - ) - - def test_brainpoolP256r1(self): - self._do( - curve=curve_brainpoolp256r1, - generator=BRAINPOOLP256r1.generator, - dA=int( - "041EB8B1E2BC681BCE8E39963B2E9FC415B05283313DD1A8BCC055F11AE" - "49699", - 16, - ), - x_qA=int( - "78028496B5ECAAB3C8B6C12E45DB1E02C9E4D26B4113BC4F015F60C5C" - "CC0D206", - 16, - ), - y_qA=int( - "A2AE1762A3831C1D20F03F8D1E3C0C39AFE6F09B4D44BBE80CD100987" - "B05F92B", - 16, - ), - dB=int( - "06F5240EACDB9837BC96D48274C8AA834B6C87BA9CC3EEDD81F99A16B8D" - "804D3", - 16, - ), - x_qB=int( - "8E07E219BA588916C5B06AA30A2F464C2F2ACFC1610A3BE2FB240B635" - "341F0DB", - 16, - ), - y_qB=int( - "148EA1D7D1E7E54B9555B6C9AC90629C18B63BEE5D7AA6949EBBF47B2" - "4FDE40D", - 16, - ), - x_Z=int( - "05E940915549E9F6A4A75693716E37466ABA79B4BF2919877A16DD2CC2" - "E23708", - 16, - ), - y_Z=int( - "6BC23B6702BC5A019438CEEA107DAAD8B94232FFBBC350F3B137628FE6" - "FD134C", - 16, - ), - ) - - @pytest.mark.slow - def test_brainpoolP384r1(self): - self._do( - curve=curve_brainpoolp384r1, - generator=BRAINPOOLP384r1.generator, - dA=int( - "014EC0755B78594BA47FB0A56F6173045B4331E74BA1A6F47322E70D79D" - "828D97E095884CA72B73FDABD5910DF0FA76A", - 16, - ), - x_qA=int( - "45CB26E4384DAF6FB776885307B9A38B7AD1B5C692E0C32F012533277" - "8F3B8D3F50CA358099B30DEB5EE69A95C058B4E", - 16, - ), - y_qA=int( - "8173A1C54AFFA7E781D0E1E1D12C0DC2B74F4DF58E4A4E3AF7026C5D3" - "2DC530A2CD89C859BB4B4B768497F49AB8CC859", - 16, - ), - dB=int( - "6B461CB79BD0EA519A87D6828815D8CE7CD9B3CAA0B5A8262CBCD550A01" - "5C90095B976F3529957506E1224A861711D54", - 16, - ), - x_qB=int( - "01BF92A92EE4BE8DED1A911125C209B03F99E3161CFCC986DC7711383" - "FC30AF9CE28CA3386D59E2C8D72CE1E7B4666E8", - 16, - ), - y_qB=int( - "3289C4A3A4FEE035E39BDB885D509D224A142FF9FBCC5CFE5CCBB3026" - "8EE47487ED8044858D31D848F7A95C635A347AC", - 16, - ), - x_Z=int( - "04CC4FF3DCCCB07AF24E0ACC529955B36D7C807772B92FCBE48F3AFE9A" - "2F370A1F98D3FA73FD0C0747C632E12F1423EC", - 16, - ), - y_Z=int( - "7F465F90BD69AFB8F828A214EB9716D66ABC59F17AF7C75EE7F1DE22AB" - "5D05085F5A01A9382D05BF72D96698FE3FF64E", - 16, - ), - ) - - @pytest.mark.slow - def test_brainpoolP512r1(self): - self._do( - curve=curve_brainpoolp512r1, - generator=BRAINPOOLP512r1.generator, - dA=int( - "636B6BE0482A6C1C41AA7AE7B245E983392DB94CECEA2660A379CFE1595" - "59E357581825391175FC195D28BAC0CF03A7841A383B95C262B98378287" - "4CCE6FE333", - 16, - ), - x_qA=int( - "0562E68B9AF7CBFD5565C6B16883B777FF11C199161ECC427A39D17EC" - "2166499389571D6A994977C56AD8252658BA8A1B72AE42F4FB7532151" - "AFC3EF0971CCDA", - 16, - ), - y_qA=int( - "A7CA2D8191E21776A89860AFBC1F582FAA308D551C1DC6133AF9F9C3C" - "AD59998D70079548140B90B1F311AFB378AA81F51B275B2BE6B7DEE97" - "8EFC7343EA642E", - 16, - ), - dB=int( - "0AF4E7F6D52EDD52907BB8DBAB3992A0BB696EC10DF11892FF205B66D38" - "1ECE72314E6A6EA079CEA06961DBA5AE6422EF2E9EE803A1F236FB96A17" - "99B86E5C8B", - 16, - ), - x_qB=int( - "5A7954E32663DFF11AE24712D87419F26B708AC2B92877D6BFEE2BFC4" - "3714D89BBDB6D24D807BBD3AEB7F0C325F862E8BADE4F74636B97EAAC" - "E739E11720D323", - 16, - ), - y_qB=int( - "96D14621A9283A1BED84DE8DD64836B2C0758B11441179DC0C54C0D49" - "A47C03807D171DD544B72CAAEF7B7CE01C7753E2CAD1A861ECA55A719" - "54EE1BA35E04BE", - 16, - ), - x_Z=int( - "1EE8321A4BBF93B9CF8921AB209850EC9B7066D1984EF08C2BB7232362" - "08AC8F1A483E79461A00E0D5F6921CE9D360502F85C812BEDEE23AC5B2" - "10E5811B191E", - 16, - ), - y_Z=int( - "2632095B7B936174B41FD2FAF369B1D18DCADEED7E410A7E251F083109" - "7C50D02CFED02607B6A2D5ADB4C0006008562208631875B58B54ECDA5A" - "4F9FE9EAABA6", - 16, - ), - ) - - -class RFC7027(ECDH): - # https://tools.ietf.org/html/rfc7027#appendix-A - - def test_brainpoolP256r1(self): - self._do( - curve=curve_brainpoolp256r1, - generator=BRAINPOOLP256r1.generator, - dA=int( - "81DB1EE100150FF2EA338D708271BE38300CB54241D79950F77B0630398" - "04F1D", - 16, - ), - x_qA=int( - "44106E913F92BC02A1705D9953A8414DB95E1AAA49E81D9E85F929A8E" - "3100BE5", - 16, - ), - y_qA=int( - "8AB4846F11CACCB73CE49CBDD120F5A900A69FD32C272223F789EF10E" - "B089BDC", - 16, - ), - dB=int( - "55E40BC41E37E3E2AD25C3C6654511FFA8474A91A0032087593852D3E7D" - "76BD3", - 16, - ), - x_qB=int( - "8D2D688C6CF93E1160AD04CC4429117DC2C41825E1E9FCA0ADDD34E6F" - "1B39F7B", - 16, - ), - y_qB=int( - "990C57520812BE512641E47034832106BC7D3E8DD0E4C7F1136D70065" - "47CEC6A", - 16, - ), - x_Z=int( - "89AFC39D41D3B327814B80940B042590F96556EC91E6AE7939BCE31F3A" - "18BF2B", - 16, - ), - y_Z=int( - "49C27868F4ECA2179BFD7D59B1E3BF34C1DBDE61AE12931648F43E5963" - "2504DE", - 16, - ), - ) - - @pytest.mark.slow - def test_brainpoolP384r1(self): - self._do( - curve=curve_brainpoolp384r1, - generator=BRAINPOOLP384r1.generator, - dA=int( - "1E20F5E048A5886F1F157C74E91BDE2B98C8B52D58E5003D57053FC4B0B" - "D65D6F15EB5D1EE1610DF870795143627D042", - 16, - ), - x_qA=int( - "68B665DD91C195800650CDD363C625F4E742E8134667B767B1B476793" - "588F885AB698C852D4A6E77A252D6380FCAF068", - 16, - ), - y_qA=int( - "55BC91A39C9EC01DEE36017B7D673A931236D2F1F5C83942D049E3FA2" - "0607493E0D038FF2FD30C2AB67D15C85F7FAA59", - 16, - ), - dB=int( - "032640BC6003C59260F7250C3DB58CE647F98E1260ACCE4ACDA3DD869F7" - "4E01F8BA5E0324309DB6A9831497ABAC96670", - 16, - ), - x_qB=int( - "4D44326F269A597A5B58BBA565DA5556ED7FD9A8A9EB76C25F46DB69D" - "19DC8CE6AD18E404B15738B2086DF37E71D1EB4", - 16, - ), - y_qB=int( - "62D692136DE56CBE93BF5FA3188EF58BC8A3A0EC6C1E151A21038A42E" - "9185329B5B275903D192F8D4E1F32FE9CC78C48", - 16, - ), - x_Z=int( - "0BD9D3A7EA0B3D519D09D8E48D0785FB744A6B355E6304BC51C229FBBC" - "E239BBADF6403715C35D4FB2A5444F575D4F42", - 16, - ), - y_Z=int( - "0DF213417EBE4D8E40A5F76F66C56470C489A3478D146DECF6DF0D94BA" - "E9E598157290F8756066975F1DB34B2324B7BD", - 16, - ), - ) - - @pytest.mark.slow - def test_brainpoolP512r1(self): - self._do( - curve=curve_brainpoolp512r1, - generator=BRAINPOOLP512r1.generator, - dA=int( - "16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD8" - "7BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764C" - "AD57665422", - 16, - ), - x_qA=int( - "0A420517E406AAC0ACDCE90FCD71487718D3B953EFD7FBEC5F7F27E28" - "C6149999397E91E029E06457DB2D3E640668B392C2A7E737A7F0BF044" - "36D11640FD09FD", - 16, - ), - y_qA=int( - "72E6882E8DB28AAD36237CD25D580DB23783961C8DC52DFA2EC138AD4" - "72A0FCEF3887CF62B623B2A87DE5C588301EA3E5FC269B373B60724F5" - "E82A6AD147FDE7", - 16, - ), - dB=int( - "230E18E1BCC88A362FA54E4EA3902009292F7F8033624FD471B5D8ACE49" - "D12CFABBC19963DAB8E2F1EBA00BFFB29E4D72D13F2224562F405CB8050" - "3666B25429", - 16, - ), - x_qB=int( - "9D45F66DE5D67E2E6DB6E93A59CE0BB48106097FF78A081DE781CDB31" - "FCE8CCBAAEA8DD4320C4119F1E9CD437A2EAB3731FA9668AB268D871D" - "EDA55A5473199F", - 16, - ), - y_qB=int( - "2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB" - "481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194" - "512B71876285FA", - 16, - ), - x_Z=int( - "A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226" - "244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1" - "454B21C4CD1F", - 16, - ), - y_Z=int( - "7DB71C3DEF63212841C463E881BDCF055523BD368240E6C3143BD8DEF8" - "B3B3223B95E0F53082FF5E412F4222537A43DF1C6D25729DDB51620A83" - "2BE6A26680A2", - 16, - ), - ) - - -# https://tools.ietf.org/html/rfc4754#page-5 -@pytest.mark.parametrize( - "w, gwx, gwy, k, msg, md, r, s, curve", - [ - pytest.param( - "DC51D3866A15BACDE33D96F992FCA99DA7E6EF0934E7097559C27F1614C88A7F", - "2442A5CC0ECD015FA3CA31DC8E2BBC70BF42D60CBCA20085E0822CB04235E970", - "6FC98BD7E50211A4A27102FA3549DF79EBCB4BF246B80945CDDFE7D509BBFD7D", - "9E56F509196784D963D1C0A401510EE7ADA3DCC5DEE04B154BF61AF1D5A6DECE", - b"abc", - hashlib.sha256, - "CB28E0999B9C7715FD0A80D8E47A77079716CBBF917DD72E97566EA1C066957C", - "86FA3BB4E26CAD5BF90B7F81899256CE7594BB1EA0C89212748BFF3B3D5B0315", - NIST256p, - id="ECDSA-256", - ), - pytest.param( - "0BEB646634BA87735D77AE4809A0EBEA865535DE4C1E1DCB692E84708E81A5AF" - "62E528C38B2A81B35309668D73524D9F", - "96281BF8DD5E0525CA049C048D345D3082968D10FEDF5C5ACA0C64E6465A97EA" - "5CE10C9DFEC21797415710721F437922", - "447688BA94708EB6E2E4D59F6AB6D7EDFF9301D249FE49C33096655F5D502FAD" - "3D383B91C5E7EDAA2B714CC99D5743CA", - "B4B74E44D71A13D568003D7489908D564C7761E229C58CBFA18950096EB7463B" - "854D7FA992F934D927376285E63414FA", - b"abc", - hashlib.sha384, - "FB017B914E29149432D8BAC29A514640B46F53DDAB2C69948084E2930F1C8F7E" - "08E07C9C63F2D21A07DCB56A6AF56EB3", - "B263A1305E057F984D38726A1B46874109F417BCA112674C528262A40A629AF1" - "CBB9F516CE0FA7D2FF630863A00E8B9F", - NIST384p, - id="ECDSA-384", - ), - pytest.param( - "0065FDA3409451DCAB0A0EAD45495112A3D813C17BFD34BDF8C1209D7DF58491" - "20597779060A7FF9D704ADF78B570FFAD6F062E95C7E0C5D5481C5B153B48B37" - "5FA1", - "0151518F1AF0F563517EDD5485190DF95A4BF57B5CBA4CF2A9A3F6474725A35F" - "7AFE0A6DDEB8BEDBCD6A197E592D40188901CECD650699C9B5E456AEA5ADD190" - "52A8", - "006F3B142EA1BFFF7E2837AD44C9E4FF6D2D34C73184BBAD90026DD5E6E85317" - "D9DF45CAD7803C6C20035B2F3FF63AFF4E1BA64D1C077577DA3F4286C58F0AEA" - "E643", - "00C1C2B305419F5A41344D7E4359933D734096F556197A9B244342B8B62F46F9" - "373778F9DE6B6497B1EF825FF24F42F9B4A4BD7382CFC3378A540B1B7F0C1B95" - "6C2F", - b"abc", - hashlib.sha512, - "0154FD3836AF92D0DCA57DD5341D3053988534FDE8318FC6AAAAB68E2E6F4339" - "B19F2F281A7E0B22C269D93CF8794A9278880ED7DBB8D9362CAEACEE54432055" - "2251", - "017705A7030290D1CEB605A9A1BB03FF9CDD521E87A696EC926C8C10C8362DF4" - "975367101F67D1CF9BCCBF2F3D239534FA509E70AAC851AE01AAC68D62F86647" - "2660", - NIST521p, - id="ECDSA-521", - ), - ], -) -def test_RFC4754_vectors(w, gwx, gwy, k, msg, md, r, s, curve): - sk = SigningKey.from_string(unhexlify(w), curve) - vk = VerifyingKey.from_string(unhexlify(gwx + gwy), curve) - assert sk.verifying_key == vk - sig = sk.sign(msg, hashfunc=md, sigencode=sigencode_strings, k=int(k, 16)) - - assert sig == (unhexlify(r), unhexlify(s)) - - assert vk.verify(sig, msg, md, sigdecode_strings) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_rw_lock.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_rw_lock.py deleted file mode 100644 index 0a84b9c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_rw_lock.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright Mateusz Kobos, (c) 2011 -# https://code.activestate.com/recipes/577803-reader-writer-lock-with-priority-for-writers/ -# released under the MIT licence - -try: - import unittest2 as unittest -except ImportError: - import unittest -import threading -import time -import copy -from ._rwlock import RWLock - - -class Writer(threading.Thread): - def __init__( - self, buffer_, rw_lock, init_sleep_time, sleep_time, to_write - ): - """ - @param buffer_: common buffer_ shared by the readers and writers - @type buffer_: list - @type rw_lock: L{RWLock} - @param init_sleep_time: sleep time before doing any action - @type init_sleep_time: C{float} - @param sleep_time: sleep time while in critical section - @type sleep_time: C{float} - @param to_write: data that will be appended to the buffer - """ - threading.Thread.__init__(self) - self.__buffer = buffer_ - self.__rw_lock = rw_lock - self.__init_sleep_time = init_sleep_time - self.__sleep_time = sleep_time - self.__to_write = to_write - self.entry_time = None - """Time of entry to the critical section""" - self.exit_time = None - """Time of exit from the critical section""" - - def run(self): - time.sleep(self.__init_sleep_time) - self.__rw_lock.writer_acquire() - self.entry_time = time.time() - time.sleep(self.__sleep_time) - self.__buffer.append(self.__to_write) - self.exit_time = time.time() - self.__rw_lock.writer_release() - - -class Reader(threading.Thread): - def __init__(self, buffer_, rw_lock, init_sleep_time, sleep_time): - """ - @param buffer_: common buffer shared by the readers and writers - @type buffer_: list - @type rw_lock: L{RWLock} - @param init_sleep_time: sleep time before doing any action - @type init_sleep_time: C{float} - @param sleep_time: sleep time while in critical section - @type sleep_time: C{float} - """ - threading.Thread.__init__(self) - self.__buffer = buffer_ - self.__rw_lock = rw_lock - self.__init_sleep_time = init_sleep_time - self.__sleep_time = sleep_time - self.buffer_read = None - """a copy of a the buffer read while in critical section""" - self.entry_time = None - """Time of entry to the critical section""" - self.exit_time = None - """Time of exit from the critical section""" - - def run(self): - time.sleep(self.__init_sleep_time) - self.__rw_lock.reader_acquire() - self.entry_time = time.time() - time.sleep(self.__sleep_time) - self.buffer_read = copy.deepcopy(self.__buffer) - self.exit_time = time.time() - self.__rw_lock.reader_release() - - -class RWLockTestCase(unittest.TestCase): - def test_readers_nonexclusive_access(self): - (buffer_, rw_lock, threads) = self.__init_variables() - - threads.append(Reader(buffer_, rw_lock, 0, 0)) - threads.append(Writer(buffer_, rw_lock, 0.2, 0.4, 1)) - threads.append(Reader(buffer_, rw_lock, 0.3, 0.3)) - threads.append(Reader(buffer_, rw_lock, 0.5, 0)) - - self.__start_and_join_threads(threads) - - ## The third reader should enter after the second one but it should - ## exit before the second one exits - ## (i.e. the readers should be in the critical section - ## at the same time) - - self.assertEqual([], threads[0].buffer_read) - self.assertEqual([1], threads[2].buffer_read) - self.assertEqual([1], threads[3].buffer_read) - self.assertTrue(threads[1].exit_time <= threads[2].entry_time) - self.assertTrue(threads[2].entry_time <= threads[3].entry_time) - self.assertTrue(threads[3].exit_time < threads[2].exit_time) - - def test_writers_exclusive_access(self): - (buffer_, rw_lock, threads) = self.__init_variables() - - threads.append(Writer(buffer_, rw_lock, 0, 0.4, 1)) - threads.append(Writer(buffer_, rw_lock, 0.1, 0, 2)) - threads.append(Reader(buffer_, rw_lock, 0.2, 0)) - - self.__start_and_join_threads(threads) - - ## The second writer should wait for the first one to exit - - self.assertEqual([1, 2], threads[2].buffer_read) - self.assertTrue(threads[0].exit_time <= threads[1].entry_time) - self.assertTrue(threads[1].exit_time <= threads[2].exit_time) - - def test_writer_priority(self): - (buffer_, rw_lock, threads) = self.__init_variables() - - threads.append(Writer(buffer_, rw_lock, 0, 0, 1)) - threads.append(Reader(buffer_, rw_lock, 0.1, 0.4)) - threads.append(Writer(buffer_, rw_lock, 0.2, 0, 2)) - threads.append(Reader(buffer_, rw_lock, 0.3, 0)) - threads.append(Reader(buffer_, rw_lock, 0.3, 0)) - - self.__start_and_join_threads(threads) - - ## The second writer should go before the second and the third reader - - self.assertEqual([1], threads[1].buffer_read) - self.assertEqual([1, 2], threads[3].buffer_read) - self.assertEqual([1, 2], threads[4].buffer_read) - self.assertTrue(threads[0].exit_time < threads[1].entry_time) - self.assertTrue(threads[1].exit_time <= threads[2].entry_time) - self.assertTrue(threads[2].exit_time <= threads[3].entry_time) - self.assertTrue(threads[2].exit_time <= threads[4].entry_time) - - def test_many_writers_priority(self): - (buffer_, rw_lock, threads) = self.__init_variables() - - threads.append(Writer(buffer_, rw_lock, 0, 0, 1)) - threads.append(Reader(buffer_, rw_lock, 0.1, 0.6)) - threads.append(Writer(buffer_, rw_lock, 0.2, 0.1, 2)) - threads.append(Reader(buffer_, rw_lock, 0.3, 0)) - threads.append(Reader(buffer_, rw_lock, 0.4, 0)) - threads.append(Writer(buffer_, rw_lock, 0.5, 0.1, 3)) - - self.__start_and_join_threads(threads) - - ## The two last writers should go first -- after the first reader and - ## before the second and the third reader - - self.assertEqual([1], threads[1].buffer_read) - self.assertEqual([1, 2, 3], threads[3].buffer_read) - self.assertEqual([1, 2, 3], threads[4].buffer_read) - self.assertTrue(threads[0].exit_time < threads[1].entry_time) - self.assertTrue(threads[1].exit_time <= threads[2].entry_time) - self.assertTrue(threads[1].exit_time <= threads[5].entry_time) - self.assertTrue(threads[2].exit_time <= threads[3].entry_time) - self.assertTrue(threads[2].exit_time <= threads[4].entry_time) - self.assertTrue(threads[5].exit_time <= threads[3].entry_time) - self.assertTrue(threads[5].exit_time <= threads[4].entry_time) - - @staticmethod - def __init_variables(): - buffer_ = [] - rw_lock = RWLock() - threads = [] - return (buffer_, rw_lock, threads) - - @staticmethod - def __start_and_join_threads(threads): - for t in threads: - t.start() - for t in threads: - t.join() diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_sha3.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/test_sha3.py deleted file mode 100644 index d30381d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/test_sha3.py +++ /dev/null @@ -1,111 +0,0 @@ -try: - import unittest2 as unittest -except ImportError: - import unittest -import pytest - -try: - from gmpy2 import mpz - - GMPY = True -except ImportError: # pragma: no cover - try: - from gmpy import mpz - - GMPY = True - except ImportError: - GMPY = False - -from ._sha3 import shake_256 -from ._compat import bytes_to_int, int_to_bytes - -B2I_VECTORS = [ - (b"\x00\x01", "big", 1), - (b"\x00\x01", "little", 0x0100), - (b"", "big", 0), - (b"\x00", "little", 0), -] - - -@pytest.mark.parametrize("bytes_in,endian,int_out", B2I_VECTORS) -def test_bytes_to_int(bytes_in, endian, int_out): - out = bytes_to_int(bytes_in, endian) - assert out == int_out - - -class TestBytesToInt(unittest.TestCase): - def test_bytes_to_int_wrong_endian(self): - with self.assertRaises(ValueError): - bytes_to_int(b"\x00", "middle") - - def test_int_to_bytes_wrong_endian(self): - with self.assertRaises(ValueError): - int_to_bytes(0, byteorder="middle") - - -@pytest.mark.skipif(GMPY == False, reason="requires gmpy or gmpy2") -def test_int_to_bytes_with_gmpy(): - assert int_to_bytes(mpz(1)) == b"\x01" - - -I2B_VECTORS = [ - (0, None, "big", b""), - (0, 1, "big", b"\x00"), - (1, None, "big", b"\x01"), - (0x0100, None, "little", b"\x00\x01"), - (0x0100, 4, "little", b"\x00\x01\x00\x00"), - (1, 4, "big", b"\x00\x00\x00\x01"), -] - - -@pytest.mark.parametrize("int_in,length,endian,bytes_out", I2B_VECTORS) -def test_int_to_bytes(int_in, length, endian, bytes_out): - out = int_to_bytes(int_in, length, endian) - assert out == bytes_out - - -SHAKE_256_VECTORS = [ - ( - b"Message.", - 32, - b"\x78\xa1\x37\xbb\x33\xae\xe2\x72\xb1\x02\x4f\x39\x43\xe5\xcf\x0c" - b"\x4e\x9c\x72\x76\x2e\x34\x4c\xf8\xf9\xc3\x25\x9d\x4f\x91\x2c\x3a", - ), - ( - b"", - 32, - b"\x46\xb9\xdd\x2b\x0b\xa8\x8d\x13\x23\x3b\x3f\xeb\x74\x3e\xeb\x24" - b"\x3f\xcd\x52\xea\x62\xb8\x1b\x82\xb5\x0c\x27\x64\x6e\xd5\x76\x2f", - ), - ( - b"message", - 32, - b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51" - b"\xa2\xa6\x5a\xf8\x64\xfc\xb1\x26\xc2\x66\x0a\xb3\x46\x51\xb1\x75", - ), - ( - b"message", - 16, - b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51", - ), - ( - b"message", - 64, - b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51" - b"\xa2\xa6\x5a\xf8\x64\xfc\xb1\x26\xc2\x66\x0a\xb3\x46\x51\xb1\x75" - b"\x30\xd6\xba\x2a\x46\x65\xf1\x9d\xf0\x62\x25\xb1\x26\xd1\x3e\xed" - b"\x91\xd5\x0d\xe7\xb9\xcb\x65\xf3\x3a\x46\xae\xd3\x6c\x7d\xc5\xe8", - ), - ( - b"A" * 1024, - 32, - b"\xa5\xef\x7e\x30\x8b\xe8\x33\x64\xe5\x9c\xf3\xb5\xf3\xba\x20\xa3" - b"\x5a\xe7\x30\xfd\xbc\x33\x11\xbf\x83\x89\x50\x82\xb4\x41\xe9\xb3", - ), -] - - -@pytest.mark.parametrize("msg,olen,ohash", SHAKE_256_VECTORS) -def test_shake_256(msg, olen, ohash): - out = shake_256(msg, olen) - assert out == bytearray(ohash) diff --git a/backend/venv39/lib/python3.9/site-packages/ecdsa/util.py b/backend/venv39/lib/python3.9/site-packages/ecdsa/util.py deleted file mode 100644 index 1aff5bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/ecdsa/util.py +++ /dev/null @@ -1,533 +0,0 @@ -""" -This module includes some utility functions. - -The methods most typically used are the sigencode and sigdecode functions -to be used with :func:`~ecdsa.keys.SigningKey.sign` and -:func:`~ecdsa.keys.VerifyingKey.verify` -respectively. See the :func:`sigencode_strings`, :func:`sigdecode_string`, -:func:`sigencode_der`, :func:`sigencode_strings_canonize`, -:func:`sigencode_string_canonize`, :func:`sigencode_der_canonize`, -:func:`sigdecode_strings`, :func:`sigdecode_string`, and -:func:`sigdecode_der` functions. -""" - -from __future__ import division - -import os -import math -import binascii -import sys -from hashlib import sha256 -from six import PY2, int2byte, next -from . import der -from ._compat import normalise_bytes - - -# RFC5480: -# The "unrestricted" algorithm identifier is: -# id-ecPublicKey OBJECT IDENTIFIER ::= { -# iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } - -oid_ecPublicKey = (1, 2, 840, 10045, 2, 1) -encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey) - -# RFC5480: -# The ECDH algorithm uses the following object identifier: -# id-ecDH OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) schemes(1) -# ecdh(12) } - -oid_ecDH = (1, 3, 132, 1, 12) - -# RFC5480: -# The ECMQV algorithm uses the following object identifier: -# id-ecMQV OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) schemes(1) -# ecmqv(13) } - -oid_ecMQV = (1, 3, 132, 1, 13) - -if sys.version_info >= (3,): # pragma: no branch - - def entropy_to_bits(ent_256): - """Convert a bytestring to string of 0's and 1's""" - return bin(int.from_bytes(ent_256, "big"))[2:].zfill(len(ent_256) * 8) - -else: - - def entropy_to_bits(ent_256): - """Convert a bytestring to string of 0's and 1's""" - return "".join(bin(ord(x))[2:].zfill(8) for x in ent_256) - - -if sys.version_info < (2, 7): # pragma: no branch - # Can't add a method to a built-in type so we are stuck with this - def bit_length(x): - return len(bin(x)) - 2 - -else: - - def bit_length(x): - return x.bit_length() or 1 - - -def orderlen(order): - return (1 + len("%x" % order)) // 2 # bytes - - -def randrange(order, entropy=None): - """Return a random integer k such that 1 <= k < order, uniformly - distributed across that range. Worst case should be a mean of 2 loops at - (2**k)+2. - - Note that this function is not declared to be forwards-compatible: we may - change the behavior in future releases. The entropy= argument (which - should get a callable that behaves like os.urandom) can be used to - achieve stability within a given release (for repeatable unit tests), but - should not be used as a long-term-compatible key generation algorithm. - """ - assert order > 1 - if entropy is None: - entropy = os.urandom - upper_2 = bit_length(order - 2) - upper_256 = upper_2 // 8 + 1 - while True: # I don't think this needs a counter with bit-wise randrange - ent_256 = entropy(upper_256) - ent_2 = entropy_to_bits(ent_256) - rand_num = int(ent_2[:upper_2], base=2) + 1 - if 0 < rand_num < order: - return rand_num - - -class PRNG: - # this returns a callable which, when invoked with an integer N, will - # return N pseudorandom bytes. Note: this is a short-term PRNG, meant - # primarily for the needs of randrange_from_seed__trytryagain(), which - # only needs to run it a few times per seed. It does not provide - # protection against state compromise (forward security). - def __init__(self, seed): - self.generator = self.block_generator(seed) - - def __call__(self, numbytes): - a = [next(self.generator) for i in range(numbytes)] - - if PY2: # pragma: no branch - return "".join(a) - else: - return bytes(a) - - def block_generator(self, seed): - counter = 0 - while True: - for byte in sha256( - ("prng-%d-%s" % (counter, seed)).encode() - ).digest(): - yield byte - counter += 1 - - -def randrange_from_seed__overshoot_modulo(seed, order): - # hash the data, then turn the digest into a number in [1,order). - # - # We use David-Sarah Hopwood's suggestion: turn it into a number that's - # sufficiently larger than the group order, then modulo it down to fit. - # This should give adequate (but not perfect) uniformity, and simple - # code. There are other choices: try-try-again is the main one. - base = PRNG(seed)(2 * orderlen(order)) - number = (int(binascii.hexlify(base), 16) % (order - 1)) + 1 - assert 1 <= number < order, (1, number, order) - return number - - -def lsb_of_ones(numbits): - return (1 << numbits) - 1 - - -def bits_and_bytes(order): - bits = int(math.log(order - 1, 2) + 1) - bytes = bits // 8 - extrabits = bits % 8 - return bits, bytes, extrabits - - -# the following randrange_from_seed__METHOD() functions take an -# arbitrarily-sized secret seed and turn it into a number that obeys the same -# range limits as randrange() above. They are meant for deriving consistent -# signing keys from a secret rather than generating them randomly, for -# example a protocol in which three signing keys are derived from a master -# secret. You should use a uniformly-distributed unguessable seed with about -# curve.baselen bytes of entropy. To use one, do this: -# seed = os.urandom(curve.baselen) # or other starting point -# secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order) -# sk = SigningKey.from_secret_exponent(secexp, curve) - - -def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256): - # hash the seed, then turn the digest into a number in [1,order), but - # don't worry about trying to uniformly fill the range. This will lose, - # on average, four bits of entropy. - bits, _bytes, extrabits = bits_and_bytes(order) - if extrabits: - _bytes += 1 - base = hashmod(seed).digest()[:_bytes] - base = "\x00" * (_bytes - len(base)) + base - number = 1 + int(binascii.hexlify(base), 16) - assert 1 <= number < order - return number - - -def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256): - # like string_to_randrange_truncate_bytes, but only lose an average of - # half a bit - bits = int(math.log(order - 1, 2) + 1) - maxbytes = (bits + 7) // 8 - base = hashmod(seed).digest()[:maxbytes] - base = "\x00" * (maxbytes - len(base)) + base - topbits = 8 * maxbytes - bits - if topbits: - base = int2byte(ord(base[0]) & lsb_of_ones(topbits)) + base[1:] - number = 1 + int(binascii.hexlify(base), 16) - assert 1 <= number < order - return number - - -def randrange_from_seed__trytryagain(seed, order): - # figure out exactly how many bits we need (rounded up to the nearest - # bit), so we can reduce the chance of looping to less than 0.5 . This is - # specified to feed from a byte-oriented PRNG, and discards the - # high-order bits of the first byte as necessary to get the right number - # of bits. The average number of loops will range from 1.0 (when - # order=2**k-1) to 2.0 (when order=2**k+1). - assert order > 1 - bits, bytes, extrabits = bits_and_bytes(order) - generate = PRNG(seed) - while True: - extrabyte = b"" - if extrabits: - extrabyte = int2byte(ord(generate(1)) & lsb_of_ones(extrabits)) - guess = string_to_number(extrabyte + generate(bytes)) + 1 - if 1 <= guess < order: - return guess - - -def number_to_string(num, order): - l = orderlen(order) - fmt_str = "%0" + str(2 * l) + "x" - string = binascii.unhexlify((fmt_str % num).encode()) - assert len(string) == l, (len(string), l) - return string - - -def number_to_string_crop(num, order): - l = orderlen(order) - fmt_str = "%0" + str(2 * l) + "x" - string = binascii.unhexlify((fmt_str % num).encode()) - return string[:l] - - -def string_to_number(string): - return int(binascii.hexlify(string), 16) - - -def string_to_number_fixedlen(string, order): - l = orderlen(order) - assert len(string) == l, (len(string), l) - return int(binascii.hexlify(string), 16) - - -def sigencode_strings(r, s, order): - """ - Encode the signature to a pair of strings in a tuple - - Encodes signature into raw encoding (:term:`raw encoding`) with the - ``r`` and ``s`` parts of the signature encoded separately. - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: raw encoding of ECDSA signature - :rtype: tuple(bytes, bytes) - """ - r_str = number_to_string(r, order) - s_str = number_to_string(s, order) - return (r_str, s_str) - - -def sigencode_string(r, s, order): - """ - Encode the signature to raw format (:term:`raw encoding`) - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: raw encoding of ECDSA signature - :rtype: bytes - """ - # for any given curve, the size of the signature numbers is - # fixed, so just use simple concatenation - r_str, s_str = sigencode_strings(r, s, order) - return r_str + s_str - - -def sigencode_der(r, s, order): - """ - Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`. - - Encodes the signature to the following :term:`ASN.1` structure:: - - Ecdsa-Sig-Value ::= SEQUENCE { - r INTEGER, - s INTEGER - } - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: DER encoding of ECDSA signature - :rtype: bytes - """ - return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) - - -def _canonize(s, order): - """ - Internal function for ensuring that the ``s`` value of a signature is in - the "canonical" format. - - :param int s: the second parameter of ECDSA signature - :param int order: the order of the curve over which the signatures was - computed - - :return: canonical value of s - :rtype: int - """ - if s > order // 2: - s = order - s - return s - - -def sigencode_strings_canonize(r, s, order): - """ - Encode the signature to a pair of strings in a tuple - - Encodes signature into raw encoding (:term:`raw encoding`) with the - ``r`` and ``s`` parts of the signature encoded separately. - - Makes sure that the signature is encoded in the canonical format, where - the ``s`` parameter is always smaller than ``order / 2``. - Most commonly used in bitcoin. - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: raw encoding of ECDSA signature - :rtype: tuple(bytes, bytes) - """ - s = _canonize(s, order) - return sigencode_strings(r, s, order) - - -def sigencode_string_canonize(r, s, order): - """ - Encode the signature to raw format (:term:`raw encoding`) - - Makes sure that the signature is encoded in the canonical format, where - the ``s`` parameter is always smaller than ``order / 2``. - Most commonly used in bitcoin. - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: raw encoding of ECDSA signature - :rtype: bytes - """ - s = _canonize(s, order) - return sigencode_string(r, s, order) - - -def sigencode_der_canonize(r, s, order): - """ - Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`. - - Makes sure that the signature is encoded in the canonical format, where - the ``s`` parameter is always smaller than ``order / 2``. - Most commonly used in bitcoin. - - Encodes the signature to the following :term:`ASN.1` structure:: - - Ecdsa-Sig-Value ::= SEQUENCE { - r INTEGER, - s INTEGER - } - - It's expected that this function will be used as a ``sigencode=`` parameter - in :func:`ecdsa.keys.SigningKey.sign` method. - - :param int r: first parameter of the signature - :param int s: second parameter of the signature - :param int order: the order of the curve over which the signature was - computed - - :return: DER encoding of ECDSA signature - :rtype: bytes - """ - s = _canonize(s, order) - return sigencode_der(r, s, order) - - -class MalformedSignature(Exception): - """ - Raised by decoding functions when the signature is malformed. - - Malformed in this context means that the relevant strings or integers - do not match what a signature over provided curve would create. Either - because the byte strings have incorrect lengths or because the encoded - values are too large. - """ - - pass - - -def sigdecode_string(signature, order): - """ - Decoder for :term:`raw encoding` of ECDSA signatures. - - raw encoding is a simple concatenation of the two integers that comprise - the signature, with each encoded using the same amount of bytes depending - on curve size/order. - - It's expected that this function will be used as the ``sigdecode=`` - parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. - - :param signature: encoded signature - :type signature: bytes like object - :param order: order of the curve over which the signature was computed - :type order: int - - :raises MalformedSignature: when the encoding of the signature is invalid - - :return: tuple with decoded ``r`` and ``s`` values of signature - :rtype: tuple of ints - """ - signature = normalise_bytes(signature) - l = orderlen(order) - if not len(signature) == 2 * l: - raise MalformedSignature( - "Invalid length of signature, expected {0} bytes long, " - "provided string is {1} bytes long".format(2 * l, len(signature)) - ) - r = string_to_number_fixedlen(signature[:l], order) - s = string_to_number_fixedlen(signature[l:], order) - return r, s - - -def sigdecode_strings(rs_strings, order): - """ - Decode the signature from two strings. - - First string needs to be a big endian encoding of ``r``, second needs to - be a big endian encoding of the ``s`` parameter of an ECDSA signature. - - It's expected that this function will be used as the ``sigdecode=`` - parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. - - :param list rs_strings: list of two bytes-like objects, each encoding one - parameter of signature - :param int order: order of the curve over which the signature was computed - - :raises MalformedSignature: when the encoding of the signature is invalid - - :return: tuple with decoded ``r`` and ``s`` values of signature - :rtype: tuple of ints - """ - if not len(rs_strings) == 2: - raise MalformedSignature( - "Invalid number of strings provided: {0}, expected 2".format( - len(rs_strings) - ) - ) - (r_str, s_str) = rs_strings - r_str = normalise_bytes(r_str) - s_str = normalise_bytes(s_str) - l = orderlen(order) - if not len(r_str) == l: - raise MalformedSignature( - "Invalid length of first string ('r' parameter), " - "expected {0} bytes long, provided string is {1} " - "bytes long".format(l, len(r_str)) - ) - if not len(s_str) == l: - raise MalformedSignature( - "Invalid length of second string ('s' parameter), " - "expected {0} bytes long, provided string is {1} " - "bytes long".format(l, len(s_str)) - ) - r = string_to_number_fixedlen(r_str, order) - s = string_to_number_fixedlen(s_str, order) - return r, s - - -def sigdecode_der(sig_der, order): - """ - Decoder for DER format of ECDSA signatures. - - DER format of signature is one that uses the :term:`ASN.1` :term:`DER` - rules to encode it as a sequence of two integers:: - - Ecdsa-Sig-Value ::= SEQUENCE { - r INTEGER, - s INTEGER - } - - It's expected that this function will be used as as the ``sigdecode=`` - parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. - - :param sig_der: encoded signature - :type sig_der: bytes like object - :param order: order of the curve over which the signature was computed - :type order: int - - :raises UnexpectedDER: when the encoding of signature is invalid - - :return: tuple with decoded ``r`` and ``s`` values of signature - :rtype: tuple of ints - """ - sig_der = normalise_bytes(sig_der) - # return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) - rs_strings, empty = der.remove_sequence(sig_der) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER sig: %s" % binascii.hexlify(empty) - ) - r, rest = der.remove_integer(rs_strings) - s, empty = der.remove_integer(rest) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER numbers: %s" % binascii.hexlify(empty) - ) - return r, s diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/METADATA deleted file mode 100644 index 04cbc2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/METADATA +++ /dev/null @@ -1,466 +0,0 @@ -Metadata-Version: 2.4 -Name: email-validator -Version: 2.3.0 -Summary: A robust email address syntax and deliverability validation library. -Home-page: https://github.com/JoshData/python-email-validator -Author: Joshua Tauberer -Author-email: jt@occams.info -License: Unlicense -Keywords: email address validator -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: The Unlicense (Unlicense) -Classifier: Programming Language :: Python :: 3 -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: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.8 -Description-Content-Type: text/markdown -License-File: LICENSE -Requires-Dist: dnspython>=2.0.0 -Requires-Dist: idna>=2.0.0 -Dynamic: license-file - -email-validator: Validate Email Addresses -========================================= - -A robust email address syntax and deliverability validation library for -Python 3.8+ by [Joshua Tauberer](https://joshdata.me). - -This library validates that a string is of the form `name@example.com` -and optionally checks that the domain name is set up to receive email. -This is the sort of validation you would want when you are identifying -users by their email address like on a registration form. - -Key features: - -* Checks that an email address has the correct syntax --- great for - email-based registration/login forms or validating data. -* Gives friendly English error messages when validation fails that you - can display to end-users. -* Checks deliverability (optional): Does the domain name resolve? - (You can override the default DNS resolver to add query caching.) -* Supports internationalized domain names (like `@ツ.life`), - internationalized local parts (like `ツ@example.com`), - and optionally parses display names (e.g. `"My Name" `). -* Rejects addresses with invalid or unsafe Unicode characters, - obsolete email address syntax that you'd find unexpected, - special use domain names like `@localhost`, - and domains without a dot by default. - This is an opinionated library! -* Normalizes email addresses (important for internationalized - and quoted-string addresses! see below). -* Python type annotations are used. - -This is an opinionated library. You should definitely also consider using -the less-opinionated [pyIsEmail](https://github.com/michaelherold/pyIsEmail) -if it works better for you. - -[![Build Status](https://github.com/JoshData/python-email-validator/actions/workflows/test_and_build.yaml/badge.svg)](https://github.com/JoshData/python-email-validator/actions/workflows/test_and_build.yaml) - -View the [CHANGELOG / Release Notes](CHANGELOG.md) for the version history of changes in the library. Occasionally this README is ahead of the latest published package --- see the CHANGELOG for details. - ---- - -Installation ------------- - -This package [is on PyPI](https://pypi.org/project/email-validator/), so: - -```sh -pip install email-validator -``` - -(You might need to use `pip3` depending on your local environment.) - -Quick Start ------------ - -If you're validating a user's email address before creating a user -account in your application, you might do this: - -```python -from email_validator import validate_email, EmailNotValidError - -email = "my+address@example.org" - -try: - - # Check that the email address is valid. Turn on check_deliverability - # for first-time validations like on account creation pages (but not - # login pages). - emailinfo = validate_email(email, check_deliverability=False) - - # After this point, use only the normalized form of the email address, - # especially before going to a database query. - email = emailinfo.normalized - -except EmailNotValidError as e: - - # The exception message is human-readable explanation of why it's - # not a valid (or deliverable) email address. - print(str(e)) -``` - -This validates the address and gives you its normalized form. You should -**put the normalized form in your database** and always normalize before -checking if an address is in your database. When using this in a login form, -set `check_deliverability` to `False` to avoid unnecessary DNS queries. - -Usage ------ - -### Overview - -The module provides a function `validate_email(email_address)` which -takes an email address and: - -- Raises a `EmailNotValidError` with a helpful, human-readable error - message explaining why the email address is not valid, or -- Returns an object with a normalized form of the email address (which - you should use!) and other information about it. - -When an email address is not valid, `validate_email` raises either an -`EmailSyntaxError` if the form of the address is invalid or an -`EmailUndeliverableError` if the domain name fails DNS checks. Both -exception classes are subclasses of `EmailNotValidError`, which in turn -is a subclass of `ValueError`. - -But when an email address is valid, an object is returned containing -a normalized form of the email address (which you should use!) and -other information. - -The validator doesn't, by default, permit obsoleted forms of email addresses -that no one uses anymore even though they are still valid and deliverable, since -they will probably give you grief if you're using email for login. (See -later in the document about how to allow some obsolete forms.) - -The validator optionally checks that the domain name in the email address has -a DNS MX record indicating that it can receive email. (Except a Null MX record. -If there is no MX record, a fallback A/AAAA-record is permitted, unless -a reject-all SPF record is present.) DNS is slow and sometimes unavailable or -unreliable, so consider whether these checks are useful for your use case and -turn them off if they aren't. -There is nothing to be gained by trying to actually contact an SMTP server, so -that's not done here. For privacy, security, and practicality reasons, servers -are good at not giving away whether an address is -deliverable or not: email addresses that appear to accept mail at first -can bounce mail after a delay, and bounced mail may indicate a temporary -failure of a good email address (sometimes an intentional failure, like -greylisting). - -### Options - -The `validate_email` function also accepts the following keyword arguments -(defaults are as shown below): - -`check_deliverability=True`: If true, DNS queries are made to check that the domain name in the email address (the part after the @-sign) can receive mail, as described above. Set to `False` to skip this DNS-based check. It is recommended to pass `False` when performing validation for login pages (but not account creation pages) since re-validation of a previously validated domain in your database by querying DNS at every login is probably undesirable. You can also set `email_validator.CHECK_DELIVERABILITY` to `False` to turn this off for all calls by default. - -`dns_resolver=None`: Pass an instance of [dns.resolver.Resolver](https://dnspython.readthedocs.io/en/latest/resolver-class.html) to control the DNS resolver including setting a timeout and [a cache](https://dnspython.readthedocs.io/en/latest/resolver-caching.html). The `caching_resolver` function shown below is a helper function to construct a dns.resolver.Resolver with a [LRUCache](https://dnspython.readthedocs.io/en/latest/resolver-caching.html#dns.resolver.LRUCache). Reuse the same resolver instance across calls to `validate_email` to make use of the cache. - -`test_environment=False`: If `True`, DNS-based deliverability checks are disabled and `test` and `**.test` domain names are permitted (see below). You can also set `email_validator.TEST_ENVIRONMENT` to `True` to turn it on for all calls by default. - -`allow_smtputf8=True`: Set to `False` to prohibit internationalized addresses that would - require the - [SMTPUTF8](https://tools.ietf.org/html/rfc6531) extension. You can also set `email_validator.ALLOW_SMTPUTF8` to `False` to turn it off for all calls by default. - -`allow_quoted_local=False`: Set to `True` to allow obscure and potentially problematic email addresses in which the part of the address before the @-sign contains spaces, @-signs, or other surprising characters when the local part is surrounded in quotes (so-called quoted-string local parts). In the object returned by `validate_email`, the normalized local part removes any unnecessary backslash-escaping and even removes the surrounding quotes if the address would be valid without them. You can also set `email_validator.ALLOW_QUOTED_LOCAL` to `True` to turn this on for all calls by default. - -`allow_domain_literal=False`: Set to `True` to allow bracketed IPv4 and "IPv6:"-prefixed IPv6 addresses in the domain part of the email address. No deliverability checks are performed for these addresses. In the object returned by `validate_email`, the normalized domain will use the condensed IPv6 format, if applicable. The object's `domain_address` attribute will hold the parsed `ipaddress.IPv4Address` or `ipaddress.IPv6Address` object if applicable. You can also set `email_validator.ALLOW_DOMAIN_LITERAL` to `True` to turn this on for all calls by default. - -`allow_display_name=False`: Set to `True` to allow a display name and bracketed address in the input string, like `My Name `. It's implemented in the spirit but not the letter of RFC 5322 3.4, so it may be stricter or more relaxed than what you want. The display name, if present, is provided in the returned object's `display_name` field after being unquoted and unescaped. You can also set `email_validator.ALLOW_DISPLAY_NAME` to `True` to turn this on for all calls by default. - -`allow_empty_local=False`: Set to `True` to allow an empty local part (i.e. - `@example.com`), e.g. for validating Postfix aliases. - -`strict=False`: Set to `True` to perform additional syntax checks (currently only a local part length check). This should be used by mail service providers at address creation to ensure email addresses meet broad compatibility requirements. - -### DNS timeout and cache - -When validating many email addresses or to control the timeout (the default is 15 seconds), create a caching [dns.resolver.Resolver](https://dnspython.readthedocs.io/en/latest/resolver-class.html) to reuse in each call. The `caching_resolver` function returns one easily for you: - -```python -from email_validator import validate_email, caching_resolver - -resolver = caching_resolver(timeout=10) - -while True: - validate_email(email, dns_resolver=resolver) -``` - -### Test addresses - -This library rejects email addresses that use the [Special Use Domain Names](https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml) `invalid`, `localhost`, `test`, and some others by raising `EmailSyntaxError`. This is to protect your system from abuse: You probably don't want a user to be able to cause an email to be sent to `localhost` (although they might be able to still do so via a malicious MX record). However, in your non-production test environments you may want to use `@test` or `@myname.test` email addresses. There are three ways you can allow this: - -1. Add `test_environment=True` to the call to `validate_email` (see above). -2. Set `email_validator.TEST_ENVIRONMENT` to `True` globally. -3. Remove the special-use domain name that you want to use from `email_validator.SPECIAL_USE_DOMAIN_NAMES`, e.g.: - -```python -import email_validator -email_validator.SPECIAL_USE_DOMAIN_NAMES.remove("test") -``` - -It is tempting to use `@example.com/net/org` in tests. They are *not* in this library's `SPECIAL_USE_DOMAIN_NAMES` list so you can, but shouldn't, use them. These domains are reserved to IANA for use in documentation so there is no risk of accidentally emailing someone at those domains. But beware that this library will nevertheless reject these domain names if DNS-based deliverability checks are not disabled because these domains do not resolve to domains that accept email. In tests, consider using your own domain name or `@test` or `@myname.test` instead. - -Internationalized email addresses ---------------------------------- - -The email protocol SMTP and the domain name system DNS have historically -only allowed English (ASCII) characters in email addresses and domain names, -respectively. Each has adapted to internationalization in a separate -way, creating two separate aspects to email address internationalization. - -(If your mail submission library doesn't support Unicode at all, then -immediately prior to mail submission you must replace the email address with -its ASCII-ized form. This library gives you back the ASCII-ized form in the -`ascii_email` field in the returned object.) - -### Internationalized domain names (IDN) - -The first is [internationalized domain names (RFC -5891)](https://tools.ietf.org/html/rfc5891), a.k.a IDNA 2008. The DNS -system has not been updated with Unicode support. Instead, internationalized -domain names are converted into a special IDNA ASCII "[Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt)" -form starting with `xn--`. When an email address has non-ASCII -characters in its domain part, the domain part is replaced with its IDNA -ASCII equivalent form in the process of mail transmission. Your mail -submission library probably does this for you transparently. ([Compliance -around the web is not very good though](http://archives.miloush.net/michkap/archive/2012/02/27/10273315.html).) This library conforms to IDNA 2008 -using the [idna](https://github.com/kjd/idna) module by Kim Davies. - -### Internationalized local parts - -The second sort of internationalization is internationalization in the -*local* part of the address (before the @-sign). In non-internationalized -email addresses, only English letters, numbers, and some punctuation -(`._!#$%&'^``*+-=~/?{|}`) are allowed. In internationalized email address -local parts, a wider range of Unicode characters are allowed. - -Email addresses with these non-ASCII characters require that your mail -submission library and all the mail servers along the route to the destination, -including your own outbound mail server, all support the -[SMTPUTF8 (RFC 6531)](https://tools.ietf.org/html/rfc6531) extension. -Support for SMTPUTF8 varies. If you know ahead of time that SMTPUTF8 is not -supported by your mail submission stack, then you must filter out addresses that -require SMTPUTF8 using the `allow_smtputf8=False` keyword argument (see above). -This will cause the validation function to raise a `EmailSyntaxError` if -delivery would require SMTPUTF8. If you do not set `allow_smtputf8=False`, -you can also check the value of the `smtputf8` field in the returned object. - -### Unsafe Unicode characters are rejected - -A surprisingly large number of Unicode characters are not safe to display, -especially when the email address is concatenated with other text, so this -library tries to protect you by not permitting reserved, non-, private use, -formatting (which can be used to alter the display order of characters), -whitespace, and control characters, and combining characters -as the first character of the local part and the domain name (so that they -cannot combine with something outside of the email address string or with -the @-sign). See https://qntm.org/safe and https://trojansource.codes/ -for relevant prior work. (Other than whitespace, these are checks that -you should be applying to nearly all user inputs in a security-sensitive -context.) This does not guard against the well known problem that many -Unicode characters look alike, which can be used to fool humans reading -displayed text. - - -Normalization -------------- - -### Unicode Normalization - -The use of Unicode in email addresses introduced a normalization -problem. Different Unicode strings can look identical and have the same -semantic meaning to the user. The `normalized` field returned on successful -validation provides the correctly normalized form of the given email -address. - -For example, the CJK fullwidth Latin letters are considered semantically -equivalent in domain names to their ASCII counterparts. This library -normalizes them to their ASCII counterparts (as required by IDNA): - -```python -emailinfo = validate_email("me@Domain.com") -print(emailinfo.normalized) -print(emailinfo.ascii_email) -# prints "me@domain.com" twice -``` - -Because an end-user might type their email address in different (but -equivalent) un-normalized forms at different times, you ought to -replace what they enter with the normalized form immediately prior to -going into your database (during account creation), querying your database -(during login), or sending outbound mail. - -The normalizations include lowercasing the domain part of the email -address (domain names are case-insensitive), [Unicode "NFC" -normalization](https://en.wikipedia.org/wiki/Unicode_equivalence) of the -whole address (which turns characters plus [combining -characters](https://en.wikipedia.org/wiki/Combining_character) into -precomposed characters where possible, replacement of [fullwidth and -halfwidth -characters](https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms) -in the domain part, possibly other -[UTS46](http://unicode.org/reports/tr46) mappings on the domain part, -and conversion from Punycode to Unicode characters. - -Normalization may change the characters in the email address and the -length of the email address, such that a string might be a valid address -before normalization but invalid after, or vice versa. This library only -permits addresses that are valid both before and after normalization. - -(See [RFC 6532 (internationalized email) section -3.1](https://tools.ietf.org/html/rfc6532#section-3.1) and [RFC 5895 -(IDNA 2008) section 2](http://www.ietf.org/rfc/rfc5895.txt).) - -### Other Normalization - -Normalization is also applied to quoted-string local parts and domain -literal IPv6 addresses if you have allowed them by the `allow_quoted_local` -and `allow_domain_literal` options. In quoted-string local parts, unnecessary -backslash escaping is removed and even the surrounding quotes are removed if -they are unnecessary. For IPv6 domain literals, the IPv6 address is -normalized to condensed form. [RFC 2142](https://datatracker.ietf.org/doc/html/rfc2142) -also requires lowercase normalization for some specific mailbox names like `postmaster@`. - - -Examples --------- - -For the email address `test@joshdata.me`, the returned object is: - -```python -ValidatedEmail( - normalized='test@joshdata.me', - local_part='test', - domain='joshdata.me', - ascii_email='test@joshdata.me', - ascii_local_part='test', - ascii_domain='joshdata.me', - smtputf8=False) -``` - -For the fictitious but valid address `example@ツ.ⓁⒾⒻⒺ`, which has an -internationalized domain but ASCII local part, the returned object is: - -```python -ValidatedEmail( - normalized='example@ツ.life', - local_part='example', - domain='ツ.life', - ascii_email='example@xn--bdk.life', - ascii_local_part='example', - ascii_domain='xn--bdk.life', - smtputf8=False) - -``` - -Note that `normalized` and other fields provide a normalized form of the -email address, domain name, and (in other cases) local part (see earlier -discussion of normalization), which you should use in your database. - -Calling `validate_email` with the ASCII form of the above email address, -`example@xn--bdk.life`, returns the exact same information (i.e., the -`normalized` field always will contain Unicode characters, not Punycode). - -For the fictitious address `ツ-test@joshdata.me`, which has an -internationalized local part, the returned object is: - -```python -ValidatedEmail( - normalized='ツ-test@joshdata.me', - local_part='ツ-test', - domain='joshdata.me', - ascii_email=None, - ascii_local_part=None, - ascii_domain='joshdata.me', - smtputf8=True) -``` - -Now `smtputf8` is `True` and `ascii_email` is `None` because the local -part of the address is internationalized. The `local_part` and `normalized` fields -return the normalized form of the address. - -Return value ------------- - -When an email address passes validation, the fields in the returned object -are: - -| Field | Value | -| -----:|-------| -| `normalized` | The normalized form of the email address that you should put in your database. This combines the `local_part` and `domain` fields (see below). | -| `ascii_email` | If set, an ASCII-only form of the normalized email address by replacing the domain part with [IDNA](https://tools.ietf.org/html/rfc5891) [Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt). This field will be present when an ASCII-only form of the email address exists (including if the email address is already ASCII). If the local part of the email address contains internationalized characters, `ascii_email` will be `None`. If set, it merely combines `ascii_local_part` and `ascii_domain`. | -| `local_part` | The normalized local part of the given email address (before the @-sign). Normalization includes Unicode NFC normalization and removing unnecessary quoted-string quotes and backslashes. If `allow_quoted_local` is True and the surrounding quotes are necessary, the quotes _will_ be present in this field. | -| `ascii_local_part` | If set, the local part, which is composed of ASCII characters only. | -| `domain` | The canonical internationalized Unicode form of the domain part of the email address. If the returned string contains non-ASCII characters, either the [SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your mail relay will be required to transmit the message or else the email address's domain part must be converted to IDNA ASCII first: Use `ascii_domain` field instead. | -| `ascii_domain` | The [IDNA](https://tools.ietf.org/html/rfc5891) [Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt)-encoded form of the domain part of the given email address, as it would be transmitted on the wire. | -| `domain_address` | If domain literals are allowed and if the email address contains one, an `ipaddress.IPv4Address` or `ipaddress.IPv6Address` object. | -| `display_name` | If no display name was present and angle brackets do not surround the address, this will be `None`; otherwise, it will be set to the display name, or the empty string if there were angle brackets but no display name. If the display name was quoted, it will be unquoted and unescaped. | -| `smtputf8` | A boolean indicating that the [SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your mail relay will be required to transmit messages to this address because the local part of the address has non-ASCII characters (the local part cannot be IDNA-encoded). If `allow_smtputf8=False` is passed as an argument, this flag will always be false because an exception is raised if it would have been true. | -| `mx` | A list of (priority, domain) tuples of MX records specified in the DNS for the domain (see [RFC 5321 section 5](https://tools.ietf.org/html/rfc5321#section-5)). May be `None` if the deliverability check could not be completed because of a temporary issue like a timeout. | -| `mx_fallback_type` | `None` if an `MX` record is found. If no MX records are actually specified in DNS and instead are inferred, through an obsolete mechanism, from A or AAAA records, the value is the type of DNS record used instead (`A` or `AAAA`). May be `None` if the deliverability check could not be completed because of a temporary issue like a timeout. | -| `spf` | Any SPF record found while checking deliverability. Only set if the SPF record is queried. | - -Assumptions ------------ - -By design, this validator does not pass all email addresses that -strictly conform to the standards. Many email address forms are obsolete -or likely to cause trouble: - -* The validator assumes the email address is intended to be - usable on the public Internet. The domain part - of the email address must be a resolvable domain name - (see the deliverability checks described above). - Most [Special Use Domain Names](https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml) - and their subdomains, as well as - domain names without a `.`, are rejected as a syntax error - (except see the `test_environment` parameter above). -* Obsolete email syntaxes are rejected: - The unusual ["(comment)" syntax](https://github.com/JoshData/python-email-validator/issues/77) - is rejected. Extremely old obsolete syntaxes are - rejected. Quoted-string local parts and domain-literal addresses - are rejected by default, but there are options to allow them (see above). - No one uses these forms anymore, and I can't think of any reason why anyone - using this library would need to accept them. - -Testing -------- - -Tests can be run using - -```sh -pip install -r test_requirements.txt -make test -``` - -Tests run with mocked DNS responses. When adding or changing tests, temporarily turn on the `BUILD_MOCKED_DNS_RESPONSE_DATA` flag in `tests/mocked_dns_responses.py` to re-build the database of mocked responses from live queries. - -For Project Maintainers ------------------------ - -The package is distributed as a universal wheel and as a source package. - -To release: - -* Update CHANGELOG.md. -* Update the version number in `email_validator/version.py`. -* Make & push a commit with the new version number and make sure tests pass. -* Make a release at https://github.com/JoshData/python-email-validator/releases/new creating a new tag (or use command below). -* Publish a source and wheel distribution to pypi (see command below). - -```sh -git tag v$(cat email_validator/version.py | sed "s/.* = //" | sed 's/"//g') -git push --tags -./release_to_pypi.sh -``` - -License -------- - -This project is free of any copyright restrictions per the [Unlicense](https://unlicense.org/). (Prior to Feb. 4, 2024, the project was made available under the terms of the [CC0 1.0 Universal public domain dedication](http://creativecommons.org/publicdomain/zero/1.0/).) See [LICENSE](LICENSE) and [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/RECORD deleted file mode 100644 index ec1e115..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/RECORD +++ /dev/null @@ -1,28 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/deliverability.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/rfc_constants.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/syntax.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/validate_email.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/email_validator/version.cpython-39.pyc,, -../../../bin/email_validator,sha256=XA4cNhlNLv9PzQ22XGsJDKyaIEbrWDiOPrt2khqKlSA,277 -email_validator-2.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -email_validator-2.3.0.dist-info/METADATA,sha256=Kpe4Hu_NhWvICwNG9H-i2AC5pDi_j5IxrgD-kx1cn7w,26006 -email_validator-2.3.0.dist-info/RECORD,, -email_validator-2.3.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -email_validator-2.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 -email_validator-2.3.0.dist-info/entry_points.txt,sha256=zRM_6bNIUSHTbNx5u6M3nK1MAguvryrc9hICC6HyrBg,66 -email_validator-2.3.0.dist-info/licenses/LICENSE,sha256=ZyF5dS4QkTSj-yvdB4Cyn9t6A5dPD1hqE66tUSlWLUw,1212 -email_validator-2.3.0.dist-info/top_level.txt,sha256=fYDOSWFZke46ut7WqdOAJjjhlpPYAaOwOwIsh3s8oWI,16 -email_validator/__init__.py,sha256=g3oVBGdXGJATgBnVqt5Q7pUhXM9QrmOl5qWSu_RtWmQ,4381 -email_validator/__main__.py,sha256=uc6i2EMCK67cCgcHr5ZFG5LqB3khljmR7lNAYZGSUKY,2302 -email_validator/deliverability.py,sha256=ZIjFkgWMzxYexanwKhrRHLTnjWMqlR5b0ltOnlA0u-E,7216 -email_validator/exceptions.py,sha256=Ry2j5FMpEe9JthmTF3zF5pGgWer-QmWc1m0szXAZ7fo,434 -email_validator/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -email_validator/rfc_constants.py,sha256=LhUiBZLBw_Nn-KHkH--nVwOWFlgz2aCuauj98ZSl-gk,3443 -email_validator/syntax.py,sha256=puufskeIG6_ORWb7fvRdV_Yczmk4bibNZPs9TjWE1K0,38971 -email_validator/types.py,sha256=mvmwN9R3lFx9Tv9wtWvDzxfit6mr_5wQmY2I0HjuqRk,5588 -email_validator/validate_email.py,sha256=bmrdQ9dGt1-Mk0rwDRrX-l6xbYhQ0US20Dz46Aatnkk,9928 -email_validator/version.py,sha256=CpK8IH_dCUAwg9tqv7zm9FxbBFkxCnED1JUiRe7cftU,22 diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/WHEEL deleted file mode 100644 index e7fa31b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/entry_points.txt deleted file mode 100644 index 03c6e23..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -email_validator = email_validator.__main__:main diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/licenses/LICENSE deleted file mode 100644 index 122e7a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -This is free and unencumbered software released into the public -domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a -compiled binary, for any purpose, commercial or non-commercial, -and by any means. - -In jurisdictions that recognize copyright laws, the author or -authors of this software dedicate any and all copyright -interest in the software to the public domain. We make this -dedication for the benefit of the public at large and to the -detriment of our heirs and successors. We intend this -dedication to be an overt act of relinquishment in perpetuity -of all present and future rights to this software under -copyright law. - -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 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. - -For more information, please refer to diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/top_level.txt deleted file mode 100644 index 798fd5e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator-2.3.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -email_validator diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/__init__.py b/backend/venv39/lib/python3.9/site-packages/email_validator/__init__.py deleted file mode 100644 index 38d0741..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/__init__.py +++ /dev/null @@ -1,103 +0,0 @@ -from typing import TYPE_CHECKING - -# Export the main method, helper methods, and the public data types. -from .exceptions import EmailNotValidError, EmailSyntaxError, EmailUndeliverableError -from .types import ValidatedEmail -from .validate_email import validate_email -from .version import __version__ - -__all__ = ["validate_email", - "ValidatedEmail", "EmailNotValidError", - "EmailSyntaxError", "EmailUndeliverableError", - "caching_resolver", "__version__"] - -if TYPE_CHECKING: - from .deliverability import caching_resolver -else: - def caching_resolver(*args, **kwargs): - # Lazy load `deliverability` as it is slow to import (due to dns.resolver) - from .deliverability import caching_resolver - - return caching_resolver(*args, **kwargs) - - -# These global attributes are a part of the library's API and can be -# changed by library users. - -# Default values for keyword arguments. - -ALLOW_SMTPUTF8 = True -ALLOW_EMPTY_LOCAL = False -ALLOW_QUOTED_LOCAL = False -ALLOW_DOMAIN_LITERAL = False -ALLOW_DISPLAY_NAME = False -STRICT = False -GLOBALLY_DELIVERABLE = True -CHECK_DELIVERABILITY = True -TEST_ENVIRONMENT = False -DEFAULT_TIMEOUT = 15 # secs - -# IANA Special Use Domain Names -# Last Updated 2021-09-21 -# https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.txt -# -# The domain names without dots would be caught by the check that the domain -# name in an email address must have a period, but this list will also catch -# subdomains of these domains, which are also reserved. -SPECIAL_USE_DOMAIN_NAMES = [ - # The "arpa" entry here is consolidated from a lot of arpa subdomains - # for private address (i.e. non-routable IP addresses like 172.16.x.x) - # reverse mapping, plus some other subdomains. Although RFC 6761 says - # that application software should not treat these domains as special, - # they are private-use domains and so cannot have globally deliverable - # email addresses, which is an assumption of this library, and probably - # all of arpa is similarly special-use, so we reject it all. - "arpa", - - # RFC 6761 says applications "SHOULD NOT" treat the "example" domains - # as special, i.e. applications should accept these domains. - # - # The domain "example" alone fails our syntax validation because it - # lacks a dot (we assume no one has an email address on a TLD directly). - # "@example.com/net/org" will currently fail DNS-based deliverability - # checks because IANA publishes a NULL MX for these domains, and - # "@mail.example[.com/net/org]" and other subdomains will fail DNS- - # based deliverability checks because IANA does not publish MX or A - # DNS records for these subdomains. - # "example", # i.e. "wwww.example" - # "example.com", - # "example.net", - # "example.org", - - # RFC 6761 says that applications are permitted to treat this domain - # as special and that DNS should return an immediate negative response, - # so we also immediately reject this domain, which also follows the - # purpose of the domain. - "invalid", - - # RFC 6762 says that applications "may" treat ".local" as special and - # that "name resolution APIs and libraries SHOULD recognize these names - # as special," and since ".local" has no global definition, we reject - # it, as we expect email addresses to be gloally routable. - "local", - - # RFC 6761 says that applications (like this library) are permitted - # to treat "localhost" as special, and since it cannot have a globally - # deliverable email address, we reject it. - "localhost", - - # RFC 7686 says "applications that do not implement the Tor protocol - # SHOULD generate an error upon the use of .onion and SHOULD NOT - # perform a DNS lookup. - "onion", - - # Although RFC 6761 says that application software should not treat - # these domains as special, it also warns users that the address may - # resolve differently in different systems, and therefore it cannot - # have a globally routable email address, which is an assumption of - # this library, so we reject "@test" and "@*.test" addresses, unless - # the test_environment keyword argument is given, to allow their use - # in application-level test environments. These domains will generally - # fail deliverability checks because "test" is not an actual TLD. - "test", -] diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/__main__.py b/backend/venv39/lib/python3.9/site-packages/email_validator/__main__.py deleted file mode 100644 index 84d9fd4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/__main__.py +++ /dev/null @@ -1,61 +0,0 @@ -# A command-line tool for testing. -# -# Usage: -# -# python -m email_validator test@example.org -# python -m email_validator < LIST_OF_ADDRESSES.TXT -# -# Provide email addresses to validate either as a command-line argument -# or in STDIN separated by newlines. Validation errors will be printed for -# invalid email addresses. When passing an email address on the command -# line, if the email address is valid, information about it will be printed. -# When using STDIN, no output will be given for valid email addresses. -# -# Keyword arguments to validate_email can be set in environment variables -# of the same name but uppercase (see below). - -import json -import os -import sys -from typing import Any, Dict, Optional - -from .validate_email import validate_email, _Resolver -from .deliverability import caching_resolver -from .exceptions import EmailNotValidError - - -def main(dns_resolver: Optional[_Resolver] = None) -> None: - # The dns_resolver argument is for tests. - - # Set options from environment variables. - options: Dict[str, Any] = {} - for varname in ('ALLOW_SMTPUTF8', 'ALLOW_EMPTY_LOCAL', 'ALLOW_QUOTED_LOCAL', 'ALLOW_DOMAIN_LITERAL', - 'ALLOW_DISPLAY_NAME', - 'GLOBALLY_DELIVERABLE', 'CHECK_DELIVERABILITY', 'TEST_ENVIRONMENT'): - if varname in os.environ: - options[varname.lower()] = bool(os.environ[varname]) - for varname in ('DEFAULT_TIMEOUT',): - if varname in os.environ: - options[varname.lower()] = float(os.environ[varname]) - - if len(sys.argv) == 1: - # Validate the email addresses passed line-by-line on STDIN. - dns_resolver = dns_resolver or caching_resolver() - for line in sys.stdin: - email = line.strip() - try: - validate_email(email, dns_resolver=dns_resolver, **options) - except EmailNotValidError as e: - print(f"{email} {e}") - else: - # Validate the email address passed on the command line. - email = sys.argv[1] - try: - result = validate_email(email, dns_resolver=dns_resolver, **options) - print(json.dumps(result.as_dict(), indent=2, sort_keys=True, ensure_ascii=False)) - except EmailNotValidError as e: - print(e) - - -if __name__ == "__main__": - main() diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/deliverability.py b/backend/venv39/lib/python3.9/site-packages/email_validator/deliverability.py deleted file mode 100644 index 6100a31..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/deliverability.py +++ /dev/null @@ -1,159 +0,0 @@ -from typing import Any, List, Optional, Tuple, TypedDict - -import ipaddress - -from .exceptions import EmailUndeliverableError - -import dns.resolver -import dns.exception - - -def caching_resolver(*, timeout: Optional[int] = None, cache: Any = None, dns_resolver: Optional[dns.resolver.Resolver] = None) -> dns.resolver.Resolver: - if timeout is None: - from . import DEFAULT_TIMEOUT - timeout = DEFAULT_TIMEOUT - resolver = dns_resolver or dns.resolver.Resolver() - resolver.cache = cache or dns.resolver.LRUCache() - resolver.lifetime = timeout # timeout, in seconds - return resolver - - -DeliverabilityInfo = TypedDict("DeliverabilityInfo", { - "mx": List[Tuple[int, str]], - "mx_fallback_type": Optional[str], - "unknown-deliverability": str, -}, total=False) - - -def validate_email_deliverability(domain: str, domain_i18n: str, timeout: Optional[int] = None, dns_resolver: Optional[dns.resolver.Resolver] = None) -> DeliverabilityInfo: - # Check that the domain resolves to an MX record. If there is no MX record, - # try an A or AAAA record which is a deprecated fallback for deliverability. - # Raises an EmailUndeliverableError on failure. On success, returns a dict - # with deliverability information. - - # If no dns.resolver.Resolver was given, get dnspython's default resolver. - # Override the default resolver's timeout. This may affect other uses of - # dnspython in this process. - if dns_resolver is None: - from . import DEFAULT_TIMEOUT - if timeout is None: - timeout = DEFAULT_TIMEOUT - dns_resolver = dns.resolver.get_default_resolver() - dns_resolver.lifetime = timeout - elif timeout is not None: - raise ValueError("It's not valid to pass both timeout and dns_resolver.") - - deliverability_info: DeliverabilityInfo = {} - - try: - try: - # Try resolving for MX records (RFC 5321 Section 5). - response = dns_resolver.resolve(domain, "MX") - - # For reporting, put them in priority order and remove the trailing dot in the qnames. - mtas = sorted([(r.preference, str(r.exchange).rstrip('.')) for r in response]) - - # RFC 7505: Null MX (0, ".") records signify the domain does not accept email. - # Remove null MX records from the mtas list (but we've stripped trailing dots, - # so the 'exchange' is just "") so we can check if there are no non-null MX - # records remaining. - mtas = [(preference, exchange) for preference, exchange in mtas - if exchange != ""] - if len(mtas) == 0: # null MX only, if there were no MX records originally a NoAnswer exception would have occurred - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not accept email.") - - deliverability_info["mx"] = mtas - deliverability_info["mx_fallback_type"] = None - - except dns.resolver.NoAnswer: - # If there was no MX record, fall back to an A or AAA record - # (RFC 5321 Section 5). Check A first since it's more common. - - # If the A/AAAA response has no Globally Reachable IP address, - # treat the response as if it were NoAnswer, i.e., the following - # address types are not allowed fallbacks: Private-Use, Loopback, - # Link-Local, and some other obscure ranges. See - # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml - # (Issue #134.) - def is_global_addr(address: Any) -> bool: - try: - ipaddr = ipaddress.ip_address(address) - except ValueError: - return False - return ipaddr.is_global - - try: - response = dns_resolver.resolve(domain, "A") - - if not any(is_global_addr(r.address) for r in response): - raise dns.resolver.NoAnswer # fall back to AAAA - - deliverability_info["mx"] = [(0, domain)] - deliverability_info["mx_fallback_type"] = "A" - - except dns.resolver.NoAnswer: - - # If there was no A record, fall back to an AAAA record. - # (It's unclear if SMTP servers actually do this.) - try: - response = dns_resolver.resolve(domain, "AAAA") - - if not any(is_global_addr(r.address) for r in response): - raise dns.resolver.NoAnswer - - deliverability_info["mx"] = [(0, domain)] - deliverability_info["mx_fallback_type"] = "AAAA" - - except dns.resolver.NoAnswer as e: - # If there was no MX, A, or AAAA record, then mail to - # this domain is not deliverable, although the domain - # name has other records (otherwise NXDOMAIN would - # have been raised). - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not accept email.") from e - - # Check for a SPF (RFC 7208) reject-all record ("v=spf1 -all") which indicates - # no emails are sent from this domain (similar to a Null MX record - # but for sending rather than receiving). In combination with the - # absence of an MX record, this is probably a good sign that the - # domain is not used for email. - try: - response = dns_resolver.resolve(domain, "TXT") - for rec in response: - value = b"".join(rec.strings) - if value.startswith(b"v=spf1 "): - if value == b"v=spf1 -all": - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not send email.") - except dns.resolver.NoAnswer: - # No TXT records means there is no SPF policy, so we cannot take any action. - pass - - except dns.resolver.NXDOMAIN as e: - # The domain name does not exist --- there are no records of any sort - # for the domain name. - raise EmailUndeliverableError(f"The domain name {domain_i18n} does not exist.") from e - - except dns.resolver.NoNameservers: - # All nameservers failed to answer the query. This might be a problem - # with local nameservers, maybe? We'll allow the domain to go through. - return { - "unknown-deliverability": "no_nameservers", - } - - except dns.exception.Timeout: - # A timeout could occur for various reasons, so don't treat it as a failure. - return { - "unknown-deliverability": "timeout", - } - - except EmailUndeliverableError: - # Don't let these get clobbered by the wider except block below. - raise - - except Exception as e: - # Unhandled conditions should not propagate. - raise EmailUndeliverableError( - "There was an error while checking if the domain name in the email address is deliverable: " + str(e) - ) from e - - return deliverability_info diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/exceptions.py b/backend/venv39/lib/python3.9/site-packages/email_validator/exceptions.py deleted file mode 100644 index 87ef13c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/exceptions.py +++ /dev/null @@ -1,13 +0,0 @@ -class EmailNotValidError(ValueError): - """Parent class of all exceptions raised by this module.""" - pass - - -class EmailSyntaxError(EmailNotValidError): - """Exception raised when an email address fails validation because of its form.""" - pass - - -class EmailUndeliverableError(EmailNotValidError): - """Exception raised when an email address fails validation because its domain name does not appear deliverable.""" - pass diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/py.typed b/backend/venv39/lib/python3.9/site-packages/email_validator/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/rfc_constants.py b/backend/venv39/lib/python3.9/site-packages/email_validator/rfc_constants.py deleted file mode 100644 index e93441b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/rfc_constants.py +++ /dev/null @@ -1,63 +0,0 @@ -# These constants are defined by the email specifications. - -import re - -# Based on RFC 5322 3.2.3, these characters are permitted in email -# addresses (not taking into account internationalization) separated by dots: -ATEXT = r'a-zA-Z0-9_!#\$%&\'\*\+\-/=\?\^`\{\|\}~' -ATEXT_RE = re.compile('[.' + ATEXT + ']') # ATEXT plus dots -DOT_ATOM_TEXT = re.compile('[' + ATEXT + ']+(?:\\.[' + ATEXT + r']+)*\Z') - -# RFC 6531 3.3 extends the allowed characters in internationalized -# addresses to also include three specific ranges of UTF8 defined in -# RFC 3629 section 4, which appear to be the Unicode code points from -# U+0080 to U+10FFFF. -ATEXT_INTL = ATEXT + "\u0080-\U0010FFFF" -ATEXT_INTL_DOT_RE = re.compile('[.' + ATEXT_INTL + ']') # ATEXT_INTL plus dots -DOT_ATOM_TEXT_INTL = re.compile('[' + ATEXT_INTL + ']+(?:\\.[' + ATEXT_INTL + r']+)*\Z') - -# The domain part of the email address, after IDNA (ASCII) encoding, -# must also satisfy the requirements of RFC 952/RFC 1123 2.1 which -# restrict the allowed characters of hostnames further. -ATEXT_HOSTNAME_INTL = re.compile(r"[a-zA-Z0-9\-\." + "\u0080-\U0010FFFF" + "]") -HOSTNAME_LABEL = r'(?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]*)?[a-zA-Z0-9])' -DOT_ATOM_TEXT_HOSTNAME = re.compile(HOSTNAME_LABEL + r'(?:\.' + HOSTNAME_LABEL + r')*\Z') -DOMAIN_NAME_REGEX = re.compile(r"[A-Za-z]\Z") # all TLDs currently end with a letter - -# Domain literal (RFC 5322 3.4.1) -DOMAIN_LITERAL_CHARS = re.compile(r"[\u0021-\u00FA\u005E-\u007E]") - -# Quoted-string local part (RFC 5321 4.1.2, internationalized by RFC 6531 3.3) -# The permitted characters in a quoted string are the characters in the range -# 32-126, except that quotes and (literal) backslashes can only appear when escaped -# by a backslash. When internationalized, UTF-8 strings are also permitted except -# the ASCII characters that are not previously permitted (see above). -# QUOTED_LOCAL_PART_ADDR = re.compile(r"^\"((?:[\u0020-\u0021\u0023-\u005B\u005D-\u007E]|\\[\u0020-\u007E])*)\"@(.*)") -QTEXT_INTL = re.compile(r"[\u0020-\u007E\u0080-\U0010FFFF]") - -# Length constants - -# RFC 3696 + errata 1003 + errata 1690 (https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690) -# explains the maximum length of an email address is 254 octets based on RFC 5321 4.5.3.1.3. A -# maximum local part length is also given at RFC 5321 4.5.3.1.1. -# -# But RFC 5321 4.5.3.1 says that these (and other) limits are in a sense suggestions, and longer -# local parts have been seen in the wild. Consequntely, the local part length is only checked -# in "strict" mode. Although the email address maximum length is also somewhat of a suggestion, -# I don't like the idea of having no length checks performed, so I'm leaving that to always be -# checked. -EMAIL_MAX_LENGTH = 254 -LOCAL_PART_MAX_LENGTH = 64 - -# Although RFC 5321 4.5.3.1.2 gives a (suggested, see above) limit of 255 octets, RFC 1035 2.3.4 also -# imposes a length limit (255 octets). But per https://stackoverflow.com/questions/32290167/what-is-the-maximum-length-of-a-dns-name, -# two of those octets are taken up by the optional final dot and null root label. -DNS_LABEL_LENGTH_LIMIT = 63 # in "octets", RFC 1035 2.3.1 -DOMAIN_MAX_LENGTH = 253 # in "octets" as transmitted - -# RFC 2142 -CASE_INSENSITIVE_MAILBOX_NAMES = [ - 'info', 'marketing', 'sales', 'support', # section 3 - 'abuse', 'noc', 'security', # section 4 - 'postmaster', 'hostmaster', 'usenet', 'news', 'webmaster', 'www', 'uucp', 'ftp', # section 5 -] diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/syntax.py b/backend/venv39/lib/python3.9/site-packages/email_validator/syntax.py deleted file mode 100644 index 0b1c7b0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/syntax.py +++ /dev/null @@ -1,822 +0,0 @@ -from .exceptions import EmailSyntaxError -from .types import ValidatedEmail -from .rfc_constants import EMAIL_MAX_LENGTH, LOCAL_PART_MAX_LENGTH, DOMAIN_MAX_LENGTH, \ - DOT_ATOM_TEXT, DOT_ATOM_TEXT_INTL, ATEXT_RE, ATEXT_INTL_DOT_RE, ATEXT_HOSTNAME_INTL, QTEXT_INTL, \ - DNS_LABEL_LENGTH_LIMIT, DOT_ATOM_TEXT_HOSTNAME, DOMAIN_NAME_REGEX, DOMAIN_LITERAL_CHARS - -import re -import unicodedata -import idna # implements IDNA 2008; Python's codec is only IDNA 2003 -import ipaddress -from typing import Optional, Tuple, TypedDict, Union - - -def split_email(email: str) -> Tuple[Optional[str], str, str, bool]: - # Return the display name, unescaped local part, and domain part - # of the address, and whether the local part was quoted. If no - # display name was present and angle brackets do not surround - # the address, display name will be None; otherwise, it will be - # set to the display name or the empty string if there were - # angle brackets but no display name. - - # Typical email addresses have a single @-sign and no quote - # characters, but the awkward "quoted string" local part form - # (RFC 5321 4.1.2) allows @-signs and escaped quotes to appear - # in the local part if the local part is quoted. - - # A `display name ` format is also present in MIME messages - # (RFC 5322 3.4) and this format is also often recognized in - # mail UIs. It's not allowed in SMTP commands or in typical web - # login forms, but parsing it has been requested, so it's done - # here as a convenience. It's implemented in the spirit but not - # the letter of RFC 5322 3.4 because MIME messages allow newlines - # and comments as a part of the CFWS rule, but this is typically - # not allowed in mail UIs (although comment syntax was requested - # once too). - # - # Display names are either basic characters (the same basic characters - # permitted in email addresses, but periods are not allowed and spaces - # are allowed; see RFC 5322 Appendix A.1.2), or or a quoted string with - # the same rules as a quoted local part. (Multiple quoted strings might - # be allowed? Unclear.) Optional space (RFC 5322 3.4 CFWS) and then the - # email address follows in angle brackets. - # - # An initial quote is ambiguous between starting a display name or - # a quoted local part --- fun. - # - # We assume the input string is already stripped of leading and - # trailing CFWS. - - def split_string_at_unquoted_special(text: str, specials: Tuple[str, ...]) -> Tuple[str, str]: - # Split the string at the first character in specials (an @-sign - # or left angle bracket) that does not occur within quotes and - # is not followed by a Unicode combining character. - # If no special character is found, raise an error. - inside_quote = False - escaped = False - left_part = "" - for i, c in enumerate(text): - # < plus U+0338 (Combining Long Solidus Overlay) normalizes to - # ≮ U+226E (Not Less-Than), and it would be confusing to treat - # the < as the start of "" syntax in that case. Likewise, - # if anything combines with an @ or ", we should probably not - # treat it as a special character. - if unicodedata.normalize("NFC", text[i:])[0] != c: - left_part += c - - elif inside_quote: - left_part += c - if c == '\\' and not escaped: - escaped = True - elif c == '"' and not escaped: - # The only way to exit the quote is an unescaped quote. - inside_quote = False - escaped = False - else: - escaped = False - elif c == '"': - left_part += c - inside_quote = True - elif c in specials: - # When unquoted, stop before a special character. - break - else: - left_part += c - - # No special symbol found. The special symbols always - # include an at-sign, so this always indicates a missing - # at-sign. The other symbol is optional. - if len(left_part) == len(text): - # The full-width at-sign might occur in CJK contexts. - # We can't accept it because we only accept addresess - # that are actually valid. But if this is common we - # may want to consider accepting and normalizing full- - # width characters for the other special symbols (and - # full-width dot is already accepted in internationalized - # domains) with a new option. - # See https://news.ycombinator.com/item?id=42235268. - if "@" in text: - raise EmailSyntaxError("The email address has the \"full-width\" at-sign (@) character instead of a regular at-sign.") - - # Check another near-homoglyph for good measure because - # homoglyphs in place of required characters could be - # very confusing. We may want to consider checking for - # homoglyphs anywhere we look for a special symbol. - if "﹫" in text: - raise EmailSyntaxError('The email address has the "small commercial at" character instead of a regular at-sign.') - - raise EmailSyntaxError("An email address must have an @-sign.") - - # The right part is whatever is left. - right_part = text[len(left_part):] - - return left_part, right_part - - def unquote_quoted_string(text: str) -> Tuple[str, bool]: - # Remove surrounding quotes and unescape escaped backslashes - # and quotes. Escapes are parsed liberally. I think only - # backslashes and quotes can be escaped but we'll allow anything - # to be. - quoted = False - escaped = False - value = "" - for i, c in enumerate(text): - if quoted: - if escaped: - value += c - escaped = False - elif c == '\\': - escaped = True - elif c == '"': - if i != len(text) - 1: - raise EmailSyntaxError("Extra character(s) found after close quote: " - + ", ".join(safe_character_display(c) for c in text[i + 1:])) - break - else: - value += c - elif i == 0 and c == '"': - quoted = True - else: - value += c - - return value, quoted - - # Split the string at the first unquoted @-sign or left angle bracket. - left_part, right_part = split_string_at_unquoted_special(email, ("@", "<")) - - # If the right part starts with an angle bracket, - # then the left part is a display name and the rest - # of the right part up to the final right angle bracket - # is the email address, . - if right_part.startswith("<"): - # Remove space between the display name and angle bracket. - left_part = left_part.rstrip() - - # Unquote and unescape the display name. - display_name, display_name_quoted = unquote_quoted_string(left_part) - - # Check that only basic characters are present in a - # non-quoted display name. - if not display_name_quoted: - bad_chars = { - safe_character_display(c) - for c in display_name - if (not ATEXT_RE.match(c) and c != ' ') or c == '.' - } - if bad_chars: - raise EmailSyntaxError("The display name contains invalid characters when not quoted: " + ", ".join(sorted(bad_chars)) + ".") - - # Check for other unsafe characters. - check_unsafe_chars(display_name, allow_space=True) - - # Check that the right part ends with an angle bracket - # but allow spaces after it, I guess. - if ">" not in right_part: - raise EmailSyntaxError("An open angle bracket at the start of the email address has to be followed by a close angle bracket at the end.") - right_part = right_part.rstrip(" ") - if right_part[-1] != ">": - raise EmailSyntaxError("There can't be anything after the email address.") - - # Remove the initial and trailing angle brackets. - addr_spec = right_part[1:].rstrip(">") - - # Split the email address at the first unquoted @-sign. - local_part, domain_part = split_string_at_unquoted_special(addr_spec, ("@",)) - - # Otherwise there is no display name. The left part is the local - # part and the right part is the domain. - else: - display_name = None - local_part, domain_part = left_part, right_part - - if domain_part.startswith("@"): - domain_part = domain_part[1:] - - # Unquote the local part if it is quoted. - local_part, is_quoted_local_part = unquote_quoted_string(local_part) - - return display_name, local_part, domain_part, is_quoted_local_part - - -def get_length_reason(addr: str, limit: int) -> str: - """Helper function to return an error message related to invalid length.""" - diff = len(addr) - limit - suffix = "s" if diff > 1 else "" - return f"({diff} character{suffix} too many)" - - -def safe_character_display(c: str) -> str: - # Return safely displayable characters in quotes. - if c == '\\': - return f"\"{c}\"" # can't use repr because it escapes it - if unicodedata.category(c)[0] in ("L", "N", "P", "S"): - return repr(c) - - # Construct a hex string in case the unicode name doesn't exist. - if ord(c) < 0xFFFF: - h = f"U+{ord(c):04x}".upper() - else: - h = f"U+{ord(c):08x}".upper() - - # Return the character name or, if it has no name, the hex string. - return unicodedata.name(c, h) - - -class LocalPartValidationResult(TypedDict): - local_part: str - ascii_local_part: Optional[str] - smtputf8: bool - - -def validate_email_local_part(local: str, allow_smtputf8: bool = True, allow_empty_local: bool = False, - quoted_local_part: bool = False, strict: bool = False) -> LocalPartValidationResult: - """Validates the syntax of the local part of an email address.""" - - if len(local) == 0: - if not allow_empty_local: - raise EmailSyntaxError("There must be something before the @-sign.") - - # The caller allows an empty local part. Useful for validating certain - # Postfix aliases. - return { - "local_part": local, - "ascii_local_part": local, - "smtputf8": False, - } - - # Check the length of the local part by counting characters. - # (RFC 5321 4.5.3.1.1) - # We're checking the number of characters here. If the local part - # is ASCII-only, then that's the same as bytes (octets). If it's - # internationalized, then the UTF-8 encoding may be longer, but - # that may not be relevant. We will check the total address length - # instead. - if strict and len(local) > LOCAL_PART_MAX_LENGTH: - reason = get_length_reason(local, limit=LOCAL_PART_MAX_LENGTH) - raise EmailSyntaxError(f"The email address is too long before the @-sign {reason}.") - - # Check the local part against the non-internationalized regular expression. - # Most email addresses match this regex so it's probably fastest to check this first. - # (RFC 5322 3.2.3) - # All local parts matching the dot-atom rule are also valid as a quoted string - # so if it was originally quoted (quoted_local_part is True) and this regex matches, - # it's ok. - # (RFC 5321 4.1.2 / RFC 5322 3.2.4). - if DOT_ATOM_TEXT.match(local): - # It's valid. And since it's just the permitted ASCII characters, - # it's normalized and safe. If the local part was originally quoted, - # the quoting was unnecessary and it'll be returned as normalized to - # non-quoted form. - - # Return the local part and flag that SMTPUTF8 is not needed. - return { - "local_part": local, - "ascii_local_part": local, - "smtputf8": False, - } - - # The local part failed the basic dot-atom check. Try the extended character set - # for internationalized addresses. It's the same pattern but with additional - # characters permitted. - # RFC 6531 section 3.3. - valid: Optional[str] = None - requires_smtputf8 = False - if DOT_ATOM_TEXT_INTL.match(local): - # But international characters in the local part may not be permitted. - if not allow_smtputf8: - # Check for invalid characters against the non-internationalized - # permitted character set. - # (RFC 5322 3.2.3) - bad_chars = { - safe_character_display(c) - for c in local - if not ATEXT_RE.match(c) - } - if bad_chars: - raise EmailSyntaxError("Internationalized characters before the @-sign are not supported: " + ", ".join(sorted(bad_chars)) + ".") - - # Although the check above should always find something, fall back to this just in case. - raise EmailSyntaxError("Internationalized characters before the @-sign are not supported.") - - # It's valid. - valid = "dot-atom" - requires_smtputf8 = True - - # There are no dot-atom syntax restrictions on quoted local parts, so - # if it was originally quoted, it is probably valid. More characters - # are allowed, like @-signs, spaces, and quotes, and there are no - # restrictions on the placement of dots, as in dot-atom local parts. - elif quoted_local_part: - # Check for invalid characters in a quoted string local part. - # (RFC 5321 4.1.2. RFC 5322 lists additional permitted *obsolete* - # characters which are *not* allowed here. RFC 6531 section 3.3 - # extends the range to UTF8 strings.) - bad_chars = { - safe_character_display(c) - for c in local - if not QTEXT_INTL.match(c) - } - if bad_chars: - raise EmailSyntaxError("The email address contains invalid characters in quotes before the @-sign: " + ", ".join(sorted(bad_chars)) + ".") - - # See if any characters are outside of the ASCII range. - bad_chars = { - safe_character_display(c) - for c in local - if not (32 <= ord(c) <= 126) - } - if bad_chars: - requires_smtputf8 = True - - # International characters in the local part may not be permitted. - if not allow_smtputf8: - raise EmailSyntaxError("Internationalized characters before the @-sign are not supported: " + ", ".join(sorted(bad_chars)) + ".") - - # It's valid. - valid = "quoted" - - # If the local part matches the internationalized dot-atom form or was quoted, - # perform additional checks for Unicode strings. - if valid: - # Check that the local part is a valid, safe, and sensible Unicode string. - # Some of this may be redundant with the range U+0080 to U+10FFFF that is checked - # by DOT_ATOM_TEXT_INTL and QTEXT_INTL. Other characters may be permitted by the - # email specs, but they may not be valid, safe, or sensible Unicode strings. - # See the function for rationale. - check_unsafe_chars(local, allow_space=(valid == "quoted")) - - # Try encoding to UTF-8. Failure is possible with some characters like - # surrogate code points, but those are checked above. Still, we don't - # want to have an unhandled exception later. - try: - local.encode("utf8") - except ValueError as e: - raise EmailSyntaxError("The email address contains an invalid character.") from e - - # If this address passes only by the quoted string form, re-quote it - # and backslash-escape quotes and backslashes (removing any unnecessary - # escapes). Per RFC 5321 4.1.2, "all quoted forms MUST be treated as equivalent, - # and the sending system SHOULD transmit the form that uses the minimum quoting possible." - if valid == "quoted": - local = '"' + re.sub(r'(["\\])', r'\\\1', local) + '"' - - return { - "local_part": local, - "ascii_local_part": local if not requires_smtputf8 else None, - "smtputf8": requires_smtputf8, - } - - # It's not a valid local part. Let's find out why. - # (Since quoted local parts are all valid or handled above, these checks - # don't apply in those cases.) - - # Check for invalid characters. - # (RFC 5322 3.2.3, plus RFC 6531 3.3) - bad_chars = { - safe_character_display(c) - for c in local - if not ATEXT_INTL_DOT_RE.match(c) - } - if bad_chars: - raise EmailSyntaxError("The email address contains invalid characters before the @-sign: " + ", ".join(sorted(bad_chars)) + ".") - - # Check for dot errors imposted by the dot-atom rule. - # (RFC 5322 3.2.3) - check_dot_atom(local, 'An email address cannot start with a {}.', 'An email address cannot have a {} immediately before the @-sign.', is_hostname=False) - - # All of the reasons should already have been checked, but just in case - # we have a fallback message. - raise EmailSyntaxError("The email address contains invalid characters before the @-sign.") - - -def check_unsafe_chars(s: str, allow_space: bool = False) -> None: - # Check for unsafe characters or characters that would make the string - # invalid or non-sensible Unicode. - bad_chars = set() - for i, c in enumerate(s): - category = unicodedata.category(c) - if category[0] in ("L", "N", "P", "S"): - # Letters, numbers, punctuation, and symbols are permitted. - pass - elif category[0] == "M": - # Combining character in first position would combine with something - # outside of the email address if concatenated, so they are not safe. - # We also check if this occurs after the @-sign, which would not be - # sensible because it would modify the @-sign. - if i == 0: - bad_chars.add(c) - elif category == "Zs": - # Spaces outside of the ASCII range are not specifically disallowed in - # internationalized addresses as far as I can tell, but they violate - # the spirit of the non-internationalized specification that email - # addresses do not contain ASCII spaces when not quoted. Excluding - # ASCII spaces when not quoted is handled directly by the atom regex. - # - # In quoted-string local parts, spaces are explicitly permitted, and - # the ASCII space has category Zs, so we must allow it here, and we'll - # allow all Unicode spaces to be consistent. - if not allow_space: - bad_chars.add(c) - elif category[0] == "Z": - # The two line and paragraph separator characters (in categories Zl and Zp) - # are not specifically disallowed in internationalized addresses - # as far as I can tell, but they violate the spirit of the non-internationalized - # specification that email addresses do not contain line breaks when not quoted. - bad_chars.add(c) - elif category[0] == "C": - # Control, format, surrogate, private use, and unassigned code points (C) - # are all unsafe in various ways. Control and format characters can affect - # text rendering if the email address is concatenated with other text. - # Bidirectional format characters are unsafe, even if used properly, because - # they cause an email address to render as a different email address. - # Private use characters do not make sense for publicly deliverable - # email addresses. - bad_chars.add(c) - else: - # All categories should be handled above, but in case there is something new - # to the Unicode specification in the future, reject all other categories. - bad_chars.add(c) - if bad_chars: - raise EmailSyntaxError("The email address contains unsafe characters: " - + ", ".join(safe_character_display(c) for c in sorted(bad_chars)) + ".") - - -def check_dot_atom(label: str, start_descr: str, end_descr: str, is_hostname: bool) -> None: - # RFC 5322 3.2.3 - if label.endswith("."): - raise EmailSyntaxError(end_descr.format("period")) - if label.startswith("."): - raise EmailSyntaxError(start_descr.format("period")) - if ".." in label: - raise EmailSyntaxError("An email address cannot have two periods in a row.") - - if is_hostname: - # RFC 952 - if label.endswith("-"): - raise EmailSyntaxError(end_descr.format("hyphen")) - if label.startswith("-"): - raise EmailSyntaxError(start_descr.format("hyphen")) - if ".-" in label or "-." in label: - raise EmailSyntaxError("An email address cannot have a period and a hyphen next to each other.") - - -def uts46_valid_char(char: str) -> bool: - # By exhaustively searching for characters rejected by - # for c in (chr(i) for i in range(0x110000)): - # idna.uts46_remap(c, std3_rules=False, transitional=False) - # I found the following rules are pretty close. - c = ord(char) - if 0x80 <= c <= 0x9f: - # 8-bit ASCII range. - return False - elif ((0x2010 <= c <= 0x2060 and not (0x2024 <= c <= 0x2026) and not (0x2028 <= c <= 0x202E)) - or c in (0x00AD, 0x2064, 0xFF0E) - or 0x200B <= c <= 0x200D - or 0x1BCA0 <= c <= 0x1BCA3): - # Characters that are permitted but fall into one of the - # tests below. - return True - elif unicodedata.category(chr(c)) in ("Cf", "Cn", "Co", "Cs", "Zs", "Zl", "Zp"): - # There are a bunch of Zs characters including regular space - # that are allowed by UTS46 but are not allowed in domain - # names anyway. - # - # There are some Cn (unassigned) characters that the idna - # package doesn't reject but we can, I think. - return False - elif "002E" in unicodedata.decomposition(chr(c)).split(" "): - # Characters that decompose into a sequence with a dot. - return False - return True - - -class DomainNameValidationResult(TypedDict): - ascii_domain: str - domain: str - - -def validate_email_domain_name(domain: str, test_environment: bool = False, globally_deliverable: bool = True) -> DomainNameValidationResult: - """Validates the syntax of the domain part of an email address.""" - - # Check for invalid characters. - # (RFC 952 plus RFC 6531 section 3.3 for internationalized addresses) - bad_chars = { - safe_character_display(c) - for c in domain - if not ATEXT_HOSTNAME_INTL.match(c) - } - if bad_chars: - raise EmailSyntaxError("The part after the @-sign contains invalid characters: " + ", ".join(sorted(bad_chars)) + ".") - - # Check for unsafe characters. - # Some of this may be redundant with the range U+0080 to U+10FFFF that is checked - # by DOT_ATOM_TEXT_INTL. Other characters may be permitted by the email specs, but - # they may not be valid, safe, or sensible Unicode strings. - check_unsafe_chars(domain) - - # Reject characters that would be rejected by UTS-46 normalization next but - # with an error message under our control. - bad_chars = { - safe_character_display(c) for c in domain - if not uts46_valid_char(c) - } - if bad_chars: - raise EmailSyntaxError("The part after the @-sign contains invalid characters: " + ", ".join(sorted(bad_chars)) + ".") - - # Perform UTS-46 normalization, which includes casefolding, NFC normalization, - # and converting all label separators (the period/full stop, fullwidth full stop, - # ideographic full stop, and halfwidth ideographic full stop) to regular dots. - # It will also raise an exception if there is an invalid character in the input, - # such as "⒈" which is invalid because it would expand to include a dot and - # U+1FEF which normalizes to a backtick, which is not an allowed hostname character. - # Since several characters *are* normalized to a dot, this has to come before - # checks related to dots, like check_dot_atom which comes next. - original_domain = domain - try: - domain = idna.uts46_remap(domain, std3_rules=False, transitional=False) - except idna.IDNAError as e: - raise EmailSyntaxError(f"The part after the @-sign contains invalid characters ({e}).") from e - - # Check for invalid characters after Unicode normalization which are not caught - # by uts46_remap (see tests for examples). - bad_chars = { - safe_character_display(c) - for c in domain - if not ATEXT_HOSTNAME_INTL.match(c) - } - if bad_chars: - raise EmailSyntaxError("The part after the @-sign contains invalid characters after Unicode normalization: " + ", ".join(sorted(bad_chars)) + ".") - - # The domain part is made up dot-separated "labels." Each label must - # have at least one character and cannot start or end with dashes, which - # means there are some surprising restrictions on periods and dashes. - # Check that before we do IDNA encoding because the IDNA library gives - # unfriendly errors for these cases, but after UTS-46 normalization because - # it can insert periods and hyphens (from fullwidth characters). - # (RFC 952, RFC 1123 2.1, RFC 5322 3.2.3) - check_dot_atom(domain, 'An email address cannot have a {} immediately after the @-sign.', 'An email address cannot end with a {}.', is_hostname=True) - - # Check for RFC 5890's invalid R-LDH labels, which are labels that start - # with two characters other than "xn" and two dashes. - for label in domain.split("."): - if re.match(r"(?!xn)..--", label, re.I): - raise EmailSyntaxError("An email address cannot have two letters followed by two dashes immediately after the @-sign or after a period, except Punycode.") - - if DOT_ATOM_TEXT_HOSTNAME.match(domain): - # This is a valid non-internationalized domain. - ascii_domain = domain - else: - # If international characters are present in the domain name, convert - # the domain to IDNA ASCII. If internationalized characters are present, - # the MTA must either support SMTPUTF8 or the mail client must convert the - # domain name to IDNA before submission. - # - # For ASCII-only domains, the transformation does nothing and is safe to - # apply. However, to ensure we don't rely on the idna library for basic - # syntax checks, we don't use it if it's not needed. - # - # idna.encode also checks the domain name length after encoding but it - # doesn't give a nice error, so we call the underlying idna.alabel method - # directly. idna.alabel checks label length and doesn't give great messages, - # but we can't easily go to lower level methods. - try: - ascii_domain = ".".join( - idna.alabel(label).decode("ascii") - for label in domain.split(".") - ) - except idna.IDNAError as e: - # Some errors would have already been raised by idna.uts46_remap. - raise EmailSyntaxError(f"The part after the @-sign is invalid ({e}).") from e - - # Check the syntax of the string returned by idna.encode. - # It should never fail. - if not DOT_ATOM_TEXT_HOSTNAME.match(ascii_domain): - raise EmailSyntaxError("The email address contains invalid characters after the @-sign after IDNA encoding.") - - # Check the length of the domain name in bytes. - # (RFC 1035 2.3.4 and RFC 5321 4.5.3.1.2) - # We're checking the number of bytes ("octets") here, which can be much - # higher than the number of characters in internationalized domains, - # on the assumption that the domain may be transmitted without SMTPUTF8 - # as IDNA ASCII. (This is also checked by idna.encode, so this exception - # is never reached for internationalized domains.) - if len(ascii_domain) > DOMAIN_MAX_LENGTH: - if ascii_domain == original_domain: - reason = get_length_reason(ascii_domain, limit=DOMAIN_MAX_LENGTH) - raise EmailSyntaxError(f"The email address is too long after the @-sign {reason}.") - else: - diff = len(ascii_domain) - DOMAIN_MAX_LENGTH - s = "" if diff == 1 else "s" - raise EmailSyntaxError(f"The email address is too long after the @-sign ({diff} byte{s} too many after IDNA encoding).") - - # Also check the label length limit. - # (RFC 1035 2.3.1) - for label in ascii_domain.split("."): - if len(label) > DNS_LABEL_LENGTH_LIMIT: - reason = get_length_reason(label, limit=DNS_LABEL_LENGTH_LIMIT) - raise EmailSyntaxError(f"After the @-sign, periods cannot be separated by so many characters {reason}.") - - if globally_deliverable: - # All publicly deliverable addresses have domain names with at least - # one period, at least for gTLDs created since 2013 (per the ICANN Board - # New gTLD Program Committee, https://www.icann.org/en/announcements/details/new-gtld-dotless-domain-names-prohibited-30-8-2013-en). - # We'll consider the lack of a period a syntax error - # since that will match people's sense of what an email address looks - # like. We'll skip this in test environments to allow '@test' email - # addresses. - if "." not in ascii_domain and not (ascii_domain == "test" and test_environment): - raise EmailSyntaxError("The part after the @-sign is not valid. It should have a period.") - - # We also know that all TLDs currently end with a letter. - if not DOMAIN_NAME_REGEX.search(ascii_domain): - raise EmailSyntaxError("The part after the @-sign is not valid. It is not within a valid top-level domain.") - - # Check special-use and reserved domain names. - # Some might fail DNS-based deliverability checks, but that - # can be turned off, so we should fail them all sooner. - # See the references in __init__.py. - from . import SPECIAL_USE_DOMAIN_NAMES - for d in SPECIAL_USE_DOMAIN_NAMES: - # See the note near the definition of SPECIAL_USE_DOMAIN_NAMES. - if d == "test" and test_environment: - continue - - if ascii_domain == d or ascii_domain.endswith("." + d): - raise EmailSyntaxError("The part after the @-sign is a special-use or reserved name that cannot be used with email.") - - # We may have been given an IDNA ASCII domain to begin with. Check - # that the domain actually conforms to IDNA. It could look like IDNA - # but not be actual IDNA. For ASCII-only domains, the conversion out - # of IDNA just gives the same thing back. - # - # This gives us the canonical internationalized form of the domain, - # which we return to the caller as a part of the normalized email - # address. - try: - domain_i18n = idna.decode(ascii_domain.encode('ascii')) - except idna.IDNAError as e: - raise EmailSyntaxError(f"The part after the @-sign is not valid IDNA ({e}).") from e - - # Check that this normalized domain name has not somehow become - # an invalid domain name. All of the checks before this point - # using the idna package probably guarantee that we now have - # a valid international domain name in most respects. But it - # doesn't hurt to re-apply some tests to be sure. See the similar - # tests above. - - # Check for invalid and unsafe characters. We have no test - # case for this. - bad_chars = { - safe_character_display(c) - for c in domain_i18n - if not ATEXT_HOSTNAME_INTL.match(c) - } - if bad_chars: - raise EmailSyntaxError("The part after the @-sign contains invalid characters: " + ", ".join(sorted(bad_chars)) + ".") - check_unsafe_chars(domain_i18n) - - # Check that it can be encoded back to IDNA ASCII. We have no test - # case for this. - try: - idna.encode(domain_i18n) - except idna.IDNAError as e: - raise EmailSyntaxError(f"The part after the @-sign became invalid after normalizing to international characters ({e}).") from e - - # Return the IDNA ASCII-encoded form of the domain, which is how it - # would be transmitted on the wire (except when used with SMTPUTF8 - # possibly), as well as the canonical Unicode form of the domain, - # which is better for display purposes. This should also take care - # of RFC 6532 section 3.1's suggestion to apply Unicode NFC - # normalization to addresses. - return { - "ascii_domain": ascii_domain, - "domain": domain_i18n, - } - - -def validate_email_length(addrinfo: ValidatedEmail) -> None: - # There are three forms of the email address whose length must be checked: - # - # 1) The original email address string. Since callers may continue to use - # this string, even though we recommend using the normalized form, we - # should not pass validation when the original input is not valid. This - # form is checked first because it is the original input. - # 2) The normalized email address. We perform Unicode NFC normalization of - # the local part, we normalize the domain to internationalized characters - # (if originally IDNA ASCII) which also includes Unicode normalization, - # and we may remove quotes in quoted local parts. We recommend that - # callers use this string, so it must be valid. - # 3) The email address with the IDNA ASCII representation of the domain - # name, since this string may be used with email stacks that don't - # support UTF-8. Since this is the least likely to be used by callers, - # it is checked last. Note that ascii_email will only be set if the - # local part is ASCII, but conceivably the caller may combine a - # internationalized local part with an ASCII domain, so we check this - # on that combination also. Since we only return the normalized local - # part, we use that (and not the unnormalized local part). - # - # In all cases, the length is checked in UTF-8 because the SMTPUTF8 - # extension to SMTP validates the length in bytes. - - addresses_to_check = [ - (addrinfo.original, None), - (addrinfo.normalized, "after normalization"), - ((addrinfo.ascii_local_part or addrinfo.local_part or "") + "@" + addrinfo.ascii_domain, "when the part after the @-sign is converted to IDNA ASCII"), - ] - - for addr, reason in addresses_to_check: - addr_len = len(addr) - addr_utf8_len = len(addr.encode("utf8")) - diff = addr_utf8_len - EMAIL_MAX_LENGTH - if diff > 0: - if reason is None and addr_len == addr_utf8_len: - # If there is no normalization or transcoding, - # we can give a simple count of the number of - # characters over the limit. - reason = get_length_reason(addr, limit=EMAIL_MAX_LENGTH) - elif reason is None: - # If there is no normalization but there is - # some transcoding to UTF-8, we can compute - # the minimum number of characters over the - # limit by dividing the number of bytes over - # the limit by the maximum number of bytes - # per character. - mbpc = max(len(c.encode("utf8")) for c in addr) - mchars = max(1, diff // mbpc) - suffix = "s" if diff > 1 else "" - if mchars == diff: - reason = f"({diff} character{suffix} too many)" - else: - reason = f"({mchars}-{diff} character{suffix} too many)" - else: - # Since there is normalization, the number of - # characters in the input that need to change is - # impossible to know. - suffix = "s" if diff > 1 else "" - reason += f" ({diff} byte{suffix} too many)" - raise EmailSyntaxError(f"The email address is too long {reason}.") - - -class DomainLiteralValidationResult(TypedDict): - domain_address: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] - domain: str - - -def validate_email_domain_literal(domain_literal: str) -> DomainLiteralValidationResult: - # This is obscure domain-literal syntax. Parse it and return - # a compressed/normalized address. - # RFC 5321 4.1.3 and RFC 5322 3.4.1. - - addr: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] - - # Try to parse the domain literal as an IPv4 address. - # There is no tag for IPv4 addresses, so we can never - # be sure if the user intends an IPv4 address. - if re.match(r"^[0-9\.]+$", domain_literal): - try: - addr = ipaddress.IPv4Address(domain_literal) - except ValueError as e: - raise EmailSyntaxError(f"The address in brackets after the @-sign is not valid: It is not an IPv4 address ({e}) or is missing an address literal tag.") from e - - # Return the IPv4Address object and the domain back unchanged. - return { - "domain_address": addr, - "domain": f"[{addr}]", - } - - # If it begins with "IPv6:" it's an IPv6 address. - if domain_literal.startswith("IPv6:"): - try: - addr = ipaddress.IPv6Address(domain_literal[5:]) - except ValueError as e: - raise EmailSyntaxError(f"The IPv6 address in brackets after the @-sign is not valid ({e}).") from e - - # Return the IPv6Address object and construct a normalized - # domain literal. - return { - "domain_address": addr, - "domain": f"[IPv6:{addr.compressed}]", - } - - # Nothing else is valid. - - if ":" not in domain_literal: - raise EmailSyntaxError("The part after the @-sign in brackets is not an IPv4 address and has no address literal tag.") - - # The tag (the part before the colon) has character restrictions, - # but since it must come from a registry of tags (in which only "IPv6" is defined), - # there's no need to check the syntax of the tag. See RFC 5321 4.1.2. - - # Check for permitted ASCII characters. This actually doesn't matter - # since there will be an exception after anyway. - bad_chars = { - safe_character_display(c) - for c in domain_literal - if not DOMAIN_LITERAL_CHARS.match(c) - } - if bad_chars: - raise EmailSyntaxError("The part after the @-sign contains invalid characters in brackets: " + ", ".join(sorted(bad_chars)) + ".") - - # There are no other domain literal tags. - # https://www.iana.org/assignments/address-literal-tags/address-literal-tags.xhtml - raise EmailSyntaxError("The part after the @-sign contains an invalid address literal tag in brackets.") diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/types.py b/backend/venv39/lib/python3.9/site-packages/email_validator/types.py deleted file mode 100644 index 1df60ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/types.py +++ /dev/null @@ -1,126 +0,0 @@ -import warnings -from typing import Any, Dict, List, Optional, Tuple, Union - - -class ValidatedEmail: - """The validate_email function returns objects of this type holding the normalized form of the email address - and other information.""" - - """The email address that was passed to validate_email. (If passed as bytes, this will be a string.)""" - original: str - - """The normalized email address, which should always be used in preference to the original address. - The normalized address converts an IDNA ASCII domain name to Unicode, if possible, and performs - Unicode normalization on the local part and on the domain (if originally Unicode). It is the - concatenation of the local_part and domain attributes, separated by an @-sign.""" - normalized: str - - """The local part of the email address after Unicode normalization.""" - local_part: str - - """The domain part of the email address after Unicode normalization or conversion to - Unicode from IDNA ascii.""" - domain: str - - """If the domain part is a domain literal, the IPv4Address or IPv6Address object.""" - domain_address: object - - """If not None, a form of the email address that uses 7-bit ASCII characters only.""" - ascii_email: Optional[str] - - """If not None, the local part of the email address using 7-bit ASCII characters only.""" - ascii_local_part: Optional[str] - - """A form of the domain name that uses 7-bit ASCII characters only.""" - ascii_domain: str - - """If True, the SMTPUTF8 feature of your mail relay will be required to transmit messages - to this address. This flag is True just when ascii_local_part is missing. Otherwise it - is False.""" - smtputf8: bool - - """If a deliverability check is performed and if it succeeds, a list of (priority, domain) - tuples of MX records specified in the DNS for the domain.""" - mx: List[Tuple[int, str]] - - """If no MX records are actually specified in DNS and instead are inferred, through an obsolete - mechanism, from A or AAAA records, the value is the type of DNS record used instead (`A` or `AAAA`).""" - mx_fallback_type: Optional[str] - - """The display name in the original input text, unquoted and unescaped, or None.""" - display_name: Optional[str] - - def __repr__(self) -> str: - return f"" - - """For backwards compatibility, support old field names.""" - def __getattr__(self, key: str) -> str: - if key == "original_email": - return self.original - if key == "email": - return self.normalized - raise AttributeError(key) - - @property - def email(self) -> str: - warnings.warn("ValidatedEmail.email is deprecated and will be removed, use ValidatedEmail.normalized instead", DeprecationWarning) - return self.normalized - - """For backwards compatibility, some fields are also exposed through a dict-like interface. Note - that some of the names changed when they became attributes.""" - def __getitem__(self, key: str) -> Union[Optional[str], bool, List[Tuple[int, str]]]: - warnings.warn("dict-like access to the return value of validate_email is deprecated and may not be supported in the future.", DeprecationWarning, stacklevel=2) - if key == "email": - return self.normalized - if key == "email_ascii": - return self.ascii_email - if key == "local": - return self.local_part - if key == "domain": - return self.ascii_domain - if key == "domain_i18n": - return self.domain - if key == "smtputf8": - return self.smtputf8 - if key == "mx": - return self.mx - if key == "mx-fallback": - return self.mx_fallback_type - raise KeyError() - - """Tests use this.""" - def __eq__(self, other: object) -> bool: - if not isinstance(other, ValidatedEmail): - return False - return ( - self.normalized == other.normalized - and self.local_part == other.local_part - and self.domain == other.domain - and getattr(self, 'ascii_email', None) == getattr(other, 'ascii_email', None) - and getattr(self, 'ascii_local_part', None) == getattr(other, 'ascii_local_part', None) - and getattr(self, 'ascii_domain', None) == getattr(other, 'ascii_domain', None) - and self.smtputf8 == other.smtputf8 - and repr(sorted(self.mx) if getattr(self, 'mx', None) else None) - == repr(sorted(other.mx) if getattr(other, 'mx', None) else None) - and getattr(self, 'mx_fallback_type', None) == getattr(other, 'mx_fallback_type', None) - and getattr(self, 'display_name', None) == getattr(other, 'display_name', None) - ) - - """This helps producing the README.""" - def as_constructor(self) -> str: - return "ValidatedEmail(" \ - + ",".join(f"\n {key}={repr(getattr(self, key))}" - for key in ('normalized', 'local_part', 'domain', - 'ascii_email', 'ascii_local_part', 'ascii_domain', - 'smtputf8', 'mx', 'mx_fallback_type', - 'display_name') - if hasattr(self, key) - ) \ - + ")" - - """Convenience method for accessing ValidatedEmail as a dict""" - def as_dict(self) -> Dict[str, Any]: - d = self.__dict__ - if d.get('domain_address'): - d['domain_address'] = repr(d['domain_address']) - return d diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/validate_email.py b/backend/venv39/lib/python3.9/site-packages/email_validator/validate_email.py deleted file mode 100644 index ae5d963..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/validate_email.py +++ /dev/null @@ -1,209 +0,0 @@ -from typing import Optional, Union, TYPE_CHECKING -import unicodedata - -from .exceptions import EmailSyntaxError -from .types import ValidatedEmail -from .syntax import split_email, validate_email_local_part, validate_email_domain_name, validate_email_domain_literal, validate_email_length -from .rfc_constants import CASE_INSENSITIVE_MAILBOX_NAMES - -if TYPE_CHECKING: - import dns.resolver - _Resolver = dns.resolver.Resolver -else: - _Resolver = object - - -def validate_email( - email: Union[str, bytes], - /, # prior arguments are positional-only - *, # subsequent arguments are keyword-only - allow_smtputf8: Optional[bool] = None, - allow_empty_local: Optional[bool] = None, - allow_quoted_local: Optional[bool] = None, - allow_domain_literal: Optional[bool] = None, - allow_display_name: Optional[bool] = None, - strict: Optional[bool] = None, - check_deliverability: Optional[bool] = None, - test_environment: Optional[bool] = None, - globally_deliverable: Optional[bool] = None, - timeout: Optional[int] = None, - dns_resolver: Optional[_Resolver] = None -) -> ValidatedEmail: - """ - Given an email address, and some options, returns a ValidatedEmail instance - with information about the address if it is valid or, if the address is not - valid, raises an EmailNotValidError. This is the main function of the module. - """ - - # Fill in default values of arguments. - from . import ALLOW_SMTPUTF8, ALLOW_EMPTY_LOCAL, ALLOW_QUOTED_LOCAL, ALLOW_DOMAIN_LITERAL, ALLOW_DISPLAY_NAME, \ - STRICT, GLOBALLY_DELIVERABLE, CHECK_DELIVERABILITY, TEST_ENVIRONMENT, DEFAULT_TIMEOUT - if allow_smtputf8 is None: - allow_smtputf8 = ALLOW_SMTPUTF8 - if allow_empty_local is None: - allow_empty_local = ALLOW_EMPTY_LOCAL - if allow_quoted_local is None: - allow_quoted_local = ALLOW_QUOTED_LOCAL - if allow_domain_literal is None: - allow_domain_literal = ALLOW_DOMAIN_LITERAL - if allow_display_name is None: - allow_display_name = ALLOW_DISPLAY_NAME - if strict is None: - strict = STRICT - if check_deliverability is None: - check_deliverability = CHECK_DELIVERABILITY - if test_environment is None: - test_environment = TEST_ENVIRONMENT - if globally_deliverable is None: - globally_deliverable = GLOBALLY_DELIVERABLE - if timeout is None and dns_resolver is None: - timeout = DEFAULT_TIMEOUT - - if isinstance(email, str): - pass - elif isinstance(email, bytes): - # Allow email to be a bytes instance as if it is what - # will be transmitted on the wire. But assume SMTPUTF8 - # is unavailable, so it must be ASCII. - try: - email = email.decode("ascii") - except ValueError as e: - raise EmailSyntaxError("The email address is not valid ASCII.") from e - else: - raise TypeError("email must be str or bytes") - - # Split the address into the display name (or None), the local part - # (before the @-sign), and the domain part (after the @-sign). - # Normally, there is only one @-sign. But the awkward "quoted string" - # local part form (RFC 5321 4.1.2) allows @-signs in the local - # part if the local part is quoted. - display_name, local_part, domain_part, is_quoted_local_part \ - = split_email(email) - - if display_name: - # UTS #39 3.3 Email Security Profiles for Identifiers requires - # display names (incorrectly called "quoted-string-part" there) - # to be NFC normalized. Since these are not a part of what we - # are really validating, we won't check that the input was NFC - # normalized, but we'll normalize in output. - display_name = unicodedata.normalize("NFC", display_name) - - # Collect return values in this instance. - ret = ValidatedEmail() - ret.original = ((local_part if not is_quoted_local_part - else ('"' + local_part + '"')) - + "@" + domain_part) # drop the display name, if any, for email length tests at the end - ret.display_name = display_name - - # Validate the email address's local part syntax and get a normalized form. - # If the original address was quoted and the decoded local part is a valid - # unquoted local part, then we'll get back a normalized (unescaped) local - # part. - local_part_info = validate_email_local_part(local_part, - allow_smtputf8=allow_smtputf8, - allow_empty_local=allow_empty_local, - quoted_local_part=is_quoted_local_part, - strict=strict) - ret.local_part = local_part_info["local_part"] - ret.ascii_local_part = local_part_info["ascii_local_part"] - ret.smtputf8 = local_part_info["smtputf8"] - - # RFC 6532 section 3.1 says that Unicode NFC normalization should be applied, - # so we'll return the NFC-normalized local part. Since the caller may use that - # string in place of the original string, ensure it is also valid. - # - # UTS #39 3.3 Email Security Profiles for Identifiers requires local parts - # to be NFKC normalized, which loses some information in characters that can - # be decomposed. We might want to consider applying NFKC normalization, but - # we can't make the change easily because it would break database lookups - # for any caller that put a normalized address from a previous version of - # this library. (UTS #39 seems to require that the *input* be NKFC normalized - # and has other requirements that are hard to check without additional Unicode - # data, and I don't know whether the rules really apply in the wild.) - normalized_local_part = unicodedata.normalize("NFC", ret.local_part) - if normalized_local_part != ret.local_part: - try: - validate_email_local_part(normalized_local_part, - allow_smtputf8=allow_smtputf8, - allow_empty_local=allow_empty_local, - quoted_local_part=is_quoted_local_part, - strict=strict) - except EmailSyntaxError as e: - raise EmailSyntaxError("After Unicode normalization: " + str(e)) from e - ret.local_part = normalized_local_part - - # If a quoted local part isn't allowed but is present, now raise an exception. - # This is done after any exceptions raised by validate_email_local_part so - # that mandatory checks have highest precedence. - if is_quoted_local_part and not allow_quoted_local: - raise EmailSyntaxError("Quoting the part before the @-sign is not allowed here.") - - # Some local parts are required to be case-insensitive, so we should normalize - # to lowercase. - # RFC 2142 - if ret.ascii_local_part is not None \ - and ret.ascii_local_part.lower() in CASE_INSENSITIVE_MAILBOX_NAMES \ - and ret.local_part is not None: - ret.ascii_local_part = ret.ascii_local_part.lower() - ret.local_part = ret.local_part.lower() - - # Validate the email address's domain part syntax and get a normalized form. - is_domain_literal = False - if len(domain_part) == 0: - raise EmailSyntaxError("There must be something after the @-sign.") - - elif domain_part.startswith("[") and domain_part.endswith("]"): - # Parse the address in the domain literal and get back a normalized domain. - domain_literal_info = validate_email_domain_literal(domain_part[1:-1]) - if not allow_domain_literal: - raise EmailSyntaxError("A bracketed IP address after the @-sign is not allowed here.") - ret.domain = domain_literal_info["domain"] - ret.ascii_domain = domain_literal_info["domain"] # Domain literals are always ASCII. - ret.domain_address = domain_literal_info["domain_address"] - is_domain_literal = True # Prevent deliverability checks. - - else: - # Check the syntax of the domain and get back a normalized - # internationalized and ASCII form. - domain_name_info = validate_email_domain_name(domain_part, test_environment=test_environment, globally_deliverable=globally_deliverable) - ret.domain = domain_name_info["domain"] - ret.ascii_domain = domain_name_info["ascii_domain"] - - # Construct the complete normalized form. - ret.normalized = ret.local_part + "@" + ret.domain - - # If the email address has an ASCII form, add it. - if not ret.smtputf8: - if not ret.ascii_domain: - raise Exception("Missing ASCII domain.") - ret.ascii_email = (ret.ascii_local_part or "") + "@" + ret.ascii_domain - else: - ret.ascii_email = None - - # Check the length of the address. - validate_email_length(ret) - - # Check that a display name is permitted. It's the last syntax check - # because we always check against optional parsing features last. - if display_name is not None and not allow_display_name: - raise EmailSyntaxError("A display name and angle brackets around the email address are not permitted here.") - - if check_deliverability and not test_environment: - # Validate the email address's deliverability using DNS - # and update the returned ValidatedEmail object with metadata. - - if is_domain_literal: - # There is nothing to check --- skip deliverability checks. - return ret - - # Lazy load `deliverability` as it is slow to import (due to dns.resolver) - from .deliverability import validate_email_deliverability - deliverability_info = validate_email_deliverability( - ret.ascii_domain, ret.domain, timeout, dns_resolver - ) - mx = deliverability_info.get("mx") - if mx is not None: - ret.mx = mx - ret.mx_fallback_type = deliverability_info.get("mx_fallback_type") - - return ret diff --git a/backend/venv39/lib/python3.9/site-packages/email_validator/version.py b/backend/venv39/lib/python3.9/site-packages/email_validator/version.py deleted file mode 100644 index 55e4709..0000000 --- a/backend/venv39/lib/python3.9/site-packages/email_validator/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "2.3.0" diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/METADATA deleted file mode 100644 index e1a9a27..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/METADATA +++ /dev/null @@ -1,159 +0,0 @@ -Metadata-Version: 2.4 -Name: exceptiongroup -Version: 1.3.1 -Summary: Backport of PEP 654 (exception groups) -Author-email: Alex Grönholm -Requires-Python: >=3.7 -Description-Content-Type: text/x-rst -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Typing :: Typed -License-File: LICENSE -Requires-Dist: typing-extensions >= 4.6.0; python_version < '3.13' -Requires-Dist: pytest >= 6 ; extra == "test" -Project-URL: Changelog, https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst -Project-URL: Issue Tracker, https://github.com/agronholm/exceptiongroup/issues -Project-URL: Source code, https://github.com/agronholm/exceptiongroup -Provides-Extra: test - -.. image:: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml/badge.svg - :target: https://github.com/agronholm/exceptiongroup/actions/workflows/test.yml - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/exceptiongroup/badge.svg?branch=main - :target: https://coveralls.io/github/agronholm/exceptiongroup?branch=main - :alt: Code Coverage - -This is a backport of the ``BaseExceptionGroup`` and ``ExceptionGroup`` classes from -Python 3.11. - -It contains the following: - -* The ``exceptiongroup.BaseExceptionGroup`` and ``exceptiongroup.ExceptionGroup`` - classes -* A utility function (``exceptiongroup.catch()``) for catching exceptions possibly - nested in an exception group -* Patches to the ``TracebackException`` class that properly formats exception groups - (installed on import) -* An exception hook that handles formatting of exception groups through - ``TracebackException`` (installed on import) -* Special versions of some of the functions from the ``traceback`` module, modified to - correctly handle exception groups even when monkey patching is disabled, or blocked by - another custom exception hook: - - * ``traceback.format_exception()`` - * ``traceback.format_exception_only()`` - * ``traceback.print_exception()`` - * ``traceback.print_exc()`` -* A backported version of ``contextlib.suppress()`` from Python 3.12.1 which also - handles suppressing exceptions inside exception groups - -If this package is imported on Python 3.11 or later, the built-in implementations of the -exception group classes are used instead, ``TracebackException`` is not monkey patched -and the exception hook won't be installed. - -See the `standard library documentation`_ for more information on exception groups. - -.. _standard library documentation: https://docs.python.org/3/library/exceptions.html - -Catching exceptions -=================== - -Due to the lack of the ``except*`` syntax introduced by `PEP 654`_ in earlier Python -versions, you need to use ``exceptiongroup.catch()`` to catch exceptions that are -potentially nested inside an exception group. This function returns a context manager -that calls the given handler for any exceptions matching the sole argument. - -The argument to ``catch()`` must be a dict (or any ``Mapping``) where each key is either -an exception class or an iterable of exception classes. Each value must be a callable -that takes a single positional argument. The handler will be called at most once, with -an exception group as an argument which will contain all the exceptions that are any -of the given types, or their subclasses. The exception group may contain nested groups -containing more matching exceptions. - -Thus, the following Python 3.11+ code: - -.. code-block:: python - - try: - ... - except* (ValueError, KeyError) as excgroup: - for exc in excgroup.exceptions: - print('Caught exception:', type(exc)) - except* RuntimeError: - print('Caught runtime error') - -would be written with this backport like this: - -.. code-block:: python - - from exceptiongroup import BaseExceptionGroup, catch - - def value_key_err_handler(excgroup: BaseExceptionGroup) -> None: - for exc in excgroup.exceptions: - print('Caught exception:', type(exc)) - - def runtime_err_handler(exc: BaseExceptionGroup) -> None: - print('Caught runtime error') - - with catch({ - (ValueError, KeyError): value_key_err_handler, - RuntimeError: runtime_err_handler - }): - ... - -**NOTE**: Just like with ``except*``, you cannot handle ``BaseExceptionGroup`` or -``ExceptionGroup`` with ``catch()``. - -Suppressing exceptions -====================== - -This library contains a backport of the ``contextlib.suppress()`` context manager from -Python 3.12.1. It allows you to selectively ignore certain exceptions, even when they're -inside exception groups: - -.. code-block:: python - - from exceptiongroup import suppress - - with suppress(RuntimeError): - raise ExceptionGroup("", [RuntimeError("boo")]) - -Notes on monkey patching -======================== - -To make exception groups render properly when an unhandled exception group is being -printed out, this package does two things when it is imported on any Python version -earlier than 3.11: - -#. The ``traceback.TracebackException`` class is monkey patched to store extra - information about exception groups (in ``__init__()``) and properly format them (in - ``format()``) -#. An exception hook is installed at ``sys.excepthook``, provided that no other hook is - already present. This hook causes the exception to be formatted using - ``traceback.TracebackException`` rather than the built-in rendered. - -If ``sys.exceptionhook`` is found to be set to something else than the default when -``exceptiongroup`` is imported, no monkeypatching is done at all. - -To prevent the exception hook and patches from being installed, set the environment -variable ``EXCEPTIONGROUP_NO_PATCH`` to ``1``. - -Formatting exception groups ---------------------------- - -Normally, the monkey patching applied by this library on import will cause exception -groups to be printed properly in tracebacks. But in cases when the monkey patching is -blocked by a third party exception hook, or monkey patching is explicitly disabled, -you can still manually format exceptions using the special versions of the ``traceback`` -functions, like ``format_exception()``, listed at the top of this page. They work just -like their counterparts in the ``traceback`` module, except that they use a separately -patched subclass of ``TracebackException`` to perform the rendering. - -Particularly in cases where a library installs its own exception hook, it is recommended -to use these special versions to do the actual formatting of exceptions/tracebacks. - -.. _PEP 654: https://www.python.org/dev/peps/pep-0654/ - diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/RECORD deleted file mode 100644 index acd52e3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/RECORD +++ /dev/null @@ -1,18 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_catch.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_formatting.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_suppress.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_version.cpython-39.pyc,, -exceptiongroup-1.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -exceptiongroup-1.3.1.dist-info/METADATA,sha256=gZhKUjovelIq0SvqeEqLuF7ewIBeu9D7TjUBaaNt2AI,6725 -exceptiongroup-1.3.1.dist-info/RECORD,, -exceptiongroup-1.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -exceptiongroup-1.3.1.dist-info/licenses/LICENSE,sha256=blBw12UDHgrUA6HL-Qrm0ZoCKPgC4yC3rP9GCqcu1Hw,3704 -exceptiongroup/__init__.py,sha256=7DHS0hDk-RIs3IQc3SbZVB0-1MhiSCJ9XgvEyEloL7M,1049 -exceptiongroup/_catch.py,sha256=CaJez3E-Jkr-7B7RT3fzusdLWnuyeekooSFn7KyWt9s,4680 -exceptiongroup/_exceptions.py,sha256=wPwPsZ64SXEptuwb4XrTIa1Mc78uqF5vmCrXTdllLn4,11463 -exceptiongroup/_formatting.py,sha256=OYTuT_T6TzM8G2v3DVt8LRBwMNyNK0tNl0fKMls3chM,21063 -exceptiongroup/_suppress.py,sha256=LX11PRNpchwfNWwEMY92nYN1F_5qFenQcS8EjIONXKE,1772 -exceptiongroup/_version.py,sha256=-4u7pjQ4caDQqa-1Qgms81j5hpkXjmjUYRCVEaLmb88,704 -exceptiongroup/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE deleted file mode 100644 index 50d4fa5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup-1.3.1.dist-info/licenses/LICENSE +++ /dev/null @@ -1,73 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 Alex Grönholm - -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. - - -This project contains code copied from the Python standard library. -The following is the required license notice for those parts. - -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/__init__.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/__init__.py deleted file mode 100644 index d8e36b2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -__all__ = [ - "BaseExceptionGroup", - "ExceptionGroup", - "catch", - "format_exception", - "format_exception_only", - "print_exception", - "print_exc", - "suppress", -] - -import os -import sys - -from ._catch import catch -from ._version import version as __version__ # noqa: F401 - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup, ExceptionGroup - from ._formatting import ( - format_exception, - format_exception_only, - print_exc, - print_exception, - ) - - if os.getenv("EXCEPTIONGROUP_NO_PATCH") != "1": - from . import _formatting # noqa: F401 - - BaseExceptionGroup.__module__ = __name__ - ExceptionGroup.__module__ = __name__ -else: - from traceback import ( - format_exception, - format_exception_only, - print_exc, - print_exception, - ) - - BaseExceptionGroup = BaseExceptionGroup - ExceptionGroup = ExceptionGroup - -if sys.version_info < (3, 12, 1): - from ._suppress import suppress -else: - from contextlib import suppress diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_catch.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_catch.py deleted file mode 100644 index 0246568..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_catch.py +++ /dev/null @@ -1,138 +0,0 @@ -from __future__ import annotations - -import inspect -import sys -from collections.abc import Callable, Iterable, Mapping -from contextlib import AbstractContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Any - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup - -if TYPE_CHECKING: - _Handler = Callable[[BaseExceptionGroup[Any]], Any] - - -class _Catcher: - def __init__(self, handler_map: Mapping[tuple[type[BaseException], ...], _Handler]): - self._handler_map = handler_map - - def __enter__(self) -> None: - pass - - def __exit__( - self, - etype: type[BaseException] | None, - exc: BaseException | None, - tb: TracebackType | None, - ) -> bool: - if exc is not None: - unhandled = self.handle_exception(exc) - if unhandled is exc: - return False - elif unhandled is None: - return True - else: - if isinstance(exc, BaseExceptionGroup): - try: - raise unhandled from exc.__cause__ - except BaseExceptionGroup: - # Change __context__ to __cause__ because Python 3.11 does this - # too - unhandled.__context__ = exc.__cause__ - raise - - raise unhandled from exc - - return False - - def handle_exception(self, exc: BaseException) -> BaseException | None: - excgroup: BaseExceptionGroup | None - if isinstance(exc, BaseExceptionGroup): - excgroup = exc - else: - excgroup = BaseExceptionGroup("", [exc]) - - new_exceptions: list[BaseException] = [] - for exc_types, handler in self._handler_map.items(): - matched, excgroup = excgroup.split(exc_types) - if matched: - try: - try: - raise matched - except BaseExceptionGroup: - result = handler(matched) - except BaseExceptionGroup as new_exc: - if new_exc is matched: - new_exceptions.append(new_exc) - else: - new_exceptions.extend(new_exc.exceptions) - except BaseException as new_exc: - new_exceptions.append(new_exc) - else: - if inspect.iscoroutine(result): - raise TypeError( - f"Error trying to handle {matched!r} with {handler!r}. " - "Exception handler must be a sync function." - ) from exc - - if not excgroup: - break - - if new_exceptions: - if len(new_exceptions) == 1: - return new_exceptions[0] - - return BaseExceptionGroup("", new_exceptions) - elif ( - excgroup and len(excgroup.exceptions) == 1 and excgroup.exceptions[0] is exc - ): - return exc - else: - return excgroup - - -def catch( - __handlers: Mapping[type[BaseException] | Iterable[type[BaseException]], _Handler], -) -> AbstractContextManager[None]: - if not isinstance(__handlers, Mapping): - raise TypeError("the argument must be a mapping") - - handler_map: dict[ - tuple[type[BaseException], ...], Callable[[BaseExceptionGroup]] - ] = {} - for type_or_iterable, handler in __handlers.items(): - iterable: tuple[type[BaseException]] - if isinstance(type_or_iterable, type) and issubclass( - type_or_iterable, BaseException - ): - iterable = (type_or_iterable,) - elif isinstance(type_or_iterable, Iterable): - iterable = tuple(type_or_iterable) - else: - raise TypeError( - "each key must be either an exception classes or an iterable thereof" - ) - - if not callable(handler): - raise TypeError("handlers must be callable") - - for exc_type in iterable: - if not isinstance(exc_type, type) or not issubclass( - exc_type, BaseException - ): - raise TypeError( - "each key must be either an exception classes or an iterable " - "thereof" - ) - - if issubclass(exc_type, BaseExceptionGroup): - raise TypeError( - "catching ExceptionGroup with catch() is not allowed. " - "Use except instead." - ) - - handler_map[iterable] = handler - - return _Catcher(handler_map) diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_exceptions.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_exceptions.py deleted file mode 100644 index f42c1ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_exceptions.py +++ /dev/null @@ -1,336 +0,0 @@ -from __future__ import annotations - -import sys -from collections.abc import Callable, Sequence -from functools import partial -from inspect import getmro, isclass -from typing import TYPE_CHECKING, Generic, Type, TypeVar, cast, overload - -if sys.version_info < (3, 13): - from typing_extensions import TypeVar - -_BaseExceptionT_co = TypeVar( - "_BaseExceptionT_co", bound=BaseException, covariant=True, default=BaseException -) -_BaseExceptionT = TypeVar("_BaseExceptionT", bound=BaseException) -_ExceptionT_co = TypeVar( - "_ExceptionT_co", bound=Exception, covariant=True, default=Exception -) -_ExceptionT = TypeVar("_ExceptionT", bound=Exception) -# using typing.Self would require a typing_extensions dependency on py<3.11 -_ExceptionGroupSelf = TypeVar("_ExceptionGroupSelf", bound="ExceptionGroup") -_BaseExceptionGroupSelf = TypeVar("_BaseExceptionGroupSelf", bound="BaseExceptionGroup") - - -def check_direct_subclass( - exc: BaseException, parents: tuple[type[BaseException]] -) -> bool: - for cls in getmro(exc.__class__)[:-1]: - if cls in parents: - return True - - return False - - -def get_condition_filter( - condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co], bool], -) -> Callable[[_BaseExceptionT_co], bool]: - if isclass(condition) and issubclass( - cast(Type[BaseException], condition), BaseException - ): - return partial(check_direct_subclass, parents=(condition,)) - elif isinstance(condition, tuple): - if all(isclass(x) and issubclass(x, BaseException) for x in condition): - return partial(check_direct_subclass, parents=condition) - elif callable(condition): - return cast("Callable[[BaseException], bool]", condition) - - raise TypeError("expected a function, exception type or tuple of exception types") - - -def _derive_and_copy_attributes(self, excs): - eg = self.derive(excs) - eg.__cause__ = self.__cause__ - eg.__context__ = self.__context__ - eg.__traceback__ = self.__traceback__ - if hasattr(self, "__notes__"): - # Create a new list so that add_note() only affects one exceptiongroup - eg.__notes__ = list(self.__notes__) - return eg - - -class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]): - """A combination of multiple unrelated exceptions.""" - - def __new__( - cls: type[_BaseExceptionGroupSelf], - __message: str, - __exceptions: Sequence[_BaseExceptionT_co], - ) -> _BaseExceptionGroupSelf: - if not isinstance(__message, str): - raise TypeError(f"argument 1 must be str, not {type(__message)}") - if not isinstance(__exceptions, Sequence): - raise TypeError("second argument (exceptions) must be a sequence") - if not __exceptions: - raise ValueError( - "second argument (exceptions) must be a non-empty sequence" - ) - - for i, exc in enumerate(__exceptions): - if not isinstance(exc, BaseException): - raise ValueError( - f"Item {i} of second argument (exceptions) is not an exception" - ) - - if cls is BaseExceptionGroup: - if all(isinstance(exc, Exception) for exc in __exceptions): - cls = ExceptionGroup - - if issubclass(cls, Exception): - for exc in __exceptions: - if not isinstance(exc, Exception): - if cls is ExceptionGroup: - raise TypeError( - "Cannot nest BaseExceptions in an ExceptionGroup" - ) - else: - raise TypeError( - f"Cannot nest BaseExceptions in {cls.__name__!r}" - ) - - instance = super().__new__(cls, __message, __exceptions) - instance._exceptions = tuple(__exceptions) - return instance - - def __init__( - self, - __message: str, - __exceptions: Sequence[_BaseExceptionT_co], - *args: object, - ) -> None: - BaseException.__init__(self, __message, __exceptions, *args) - - def add_note(self, note: str) -> None: - if not isinstance(note, str): - raise TypeError( - f"Expected a string, got note={note!r} (type {type(note).__name__})" - ) - - if not hasattr(self, "__notes__"): - self.__notes__: list[str] = [] - - self.__notes__.append(note) - - @property - def message(self) -> str: - return self.args[0] - - @property - def exceptions( - self, - ) -> tuple[_BaseExceptionT_co | BaseExceptionGroup[_BaseExceptionT_co], ...]: - return tuple(self._exceptions) - - @overload - def subgroup( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> ExceptionGroup[_ExceptionT] | None: ... - - @overload - def subgroup( - self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] - ) -> BaseExceptionGroup[_BaseExceptionT] | None: ... - - @overload - def subgroup( - self, - __condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> BaseExceptionGroup[_BaseExceptionT_co] | None: ... - - def subgroup( - self, - __condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> BaseExceptionGroup[_BaseExceptionT] | None: - condition = get_condition_filter(__condition) - modified = False - if condition(self): - return self - - exceptions: list[BaseException] = [] - for exc in self.exceptions: - if isinstance(exc, BaseExceptionGroup): - subgroup = exc.subgroup(__condition) - if subgroup is not None: - exceptions.append(subgroup) - - if subgroup is not exc: - modified = True - elif condition(exc): - exceptions.append(exc) - else: - modified = True - - if not modified: - return self - elif exceptions: - group = _derive_and_copy_attributes(self, exceptions) - return group - else: - return None - - @overload - def split( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> tuple[ - ExceptionGroup[_ExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - @overload - def split( - self, __condition: type[_BaseExceptionT] | tuple[type[_BaseExceptionT], ...] - ) -> tuple[ - BaseExceptionGroup[_BaseExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - @overload - def split( - self, - __condition: Callable[[_BaseExceptionT_co | _BaseExceptionGroupSelf], bool], - ) -> tuple[ - BaseExceptionGroup[_BaseExceptionT_co] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ]: ... - - def split( - self, - __condition: type[_BaseExceptionT] - | tuple[type[_BaseExceptionT], ...] - | Callable[[_BaseExceptionT_co], bool], - ) -> ( - tuple[ - ExceptionGroup[_ExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - | tuple[ - BaseExceptionGroup[_BaseExceptionT] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - | tuple[ - BaseExceptionGroup[_BaseExceptionT_co] | None, - BaseExceptionGroup[_BaseExceptionT_co] | None, - ] - ): - condition = get_condition_filter(__condition) - if condition(self): - return self, None - - matching_exceptions: list[BaseException] = [] - nonmatching_exceptions: list[BaseException] = [] - for exc in self.exceptions: - if isinstance(exc, BaseExceptionGroup): - matching, nonmatching = exc.split(condition) - if matching is not None: - matching_exceptions.append(matching) - - if nonmatching is not None: - nonmatching_exceptions.append(nonmatching) - elif condition(exc): - matching_exceptions.append(exc) - else: - nonmatching_exceptions.append(exc) - - matching_group: _BaseExceptionGroupSelf | None = None - if matching_exceptions: - matching_group = _derive_and_copy_attributes(self, matching_exceptions) - - nonmatching_group: _BaseExceptionGroupSelf | None = None - if nonmatching_exceptions: - nonmatching_group = _derive_and_copy_attributes( - self, nonmatching_exceptions - ) - - return matching_group, nonmatching_group - - @overload - def derive(self, __excs: Sequence[_ExceptionT]) -> ExceptionGroup[_ExceptionT]: ... - - @overload - def derive( - self, __excs: Sequence[_BaseExceptionT] - ) -> BaseExceptionGroup[_BaseExceptionT]: ... - - def derive( - self, __excs: Sequence[_BaseExceptionT] - ) -> BaseExceptionGroup[_BaseExceptionT]: - return BaseExceptionGroup(self.message, __excs) - - def __str__(self) -> str: - suffix = "" if len(self._exceptions) == 1 else "s" - return f"{self.message} ({len(self._exceptions)} sub-exception{suffix})" - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.args[0]!r}, {self.args[1]!r})" - - -class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception): - def __new__( - cls: type[_ExceptionGroupSelf], - __message: str, - __exceptions: Sequence[_ExceptionT_co], - ) -> _ExceptionGroupSelf: - return super().__new__(cls, __message, __exceptions) - - if TYPE_CHECKING: - - @property - def exceptions( - self, - ) -> tuple[_ExceptionT_co | ExceptionGroup[_ExceptionT_co], ...]: ... - - @overload # type: ignore[override] - def subgroup( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> ExceptionGroup[_ExceptionT] | None: ... - - @overload - def subgroup( - self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool] - ) -> ExceptionGroup[_ExceptionT_co] | None: ... - - def subgroup( - self, - __condition: type[_ExceptionT] - | tuple[type[_ExceptionT], ...] - | Callable[[_ExceptionT_co], bool], - ) -> ExceptionGroup[_ExceptionT] | None: - return super().subgroup(__condition) - - @overload - def split( - self, __condition: type[_ExceptionT] | tuple[type[_ExceptionT], ...] - ) -> tuple[ - ExceptionGroup[_ExceptionT] | None, ExceptionGroup[_ExceptionT_co] | None - ]: ... - - @overload - def split( - self, __condition: Callable[[_ExceptionT_co | _ExceptionGroupSelf], bool] - ) -> tuple[ - ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None - ]: ... - - def split( - self: _ExceptionGroupSelf, - __condition: type[_ExceptionT] - | tuple[type[_ExceptionT], ...] - | Callable[[_ExceptionT_co], bool], - ) -> tuple[ - ExceptionGroup[_ExceptionT_co] | None, ExceptionGroup[_ExceptionT_co] | None - ]: - return super().split(__condition) diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_formatting.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_formatting.py deleted file mode 100644 index 490e2e0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_formatting.py +++ /dev/null @@ -1,602 +0,0 @@ -# traceback_exception_init() adapted from trio -# -# _ExceptionPrintContext and traceback_exception_format() copied from the standard -# library -from __future__ import annotations - -import collections.abc -import sys -import textwrap -import traceback -from functools import singledispatch -from types import TracebackType -from typing import Any, List, Optional - -from ._exceptions import BaseExceptionGroup - -max_group_width = 15 -max_group_depth = 10 -_cause_message = ( - "\nThe above exception was the direct cause of the following exception:\n\n" -) - -_context_message = ( - "\nDuring handling of the above exception, another exception occurred:\n\n" -) - - -def _format_final_exc_line(etype, value): - valuestr = _safe_string(value, "exception") - if value is None or not valuestr: - line = f"{etype}\n" - else: - line = f"{etype}: {valuestr}\n" - - return line - - -def _safe_string(value, what, func=str): - try: - return func(value) - except BaseException: - return f"<{what} {func.__name__}() failed>" - - -class _ExceptionPrintContext: - def __init__(self): - self.seen = set() - self.exception_group_depth = 0 - self.need_close = False - - def indent(self): - return " " * (2 * self.exception_group_depth) - - def emit(self, text_gen, margin_char=None): - if margin_char is None: - margin_char = "|" - indent_str = self.indent() - if self.exception_group_depth: - indent_str += margin_char + " " - - if isinstance(text_gen, str): - yield textwrap.indent(text_gen, indent_str, lambda line: True) - else: - for text in text_gen: - yield textwrap.indent(text, indent_str, lambda line: True) - - -def exceptiongroup_excepthook( - etype: type[BaseException], value: BaseException, tb: TracebackType | None -) -> None: - sys.stderr.write("".join(traceback.format_exception(etype, value, tb))) - - -class PatchedTracebackException(traceback.TracebackException): - def __init__( - self, - exc_type: type[BaseException], - exc_value: BaseException, - exc_traceback: TracebackType | None, - *, - limit: int | None = None, - lookup_lines: bool = True, - capture_locals: bool = False, - compact: bool = False, - _seen: set[int] | None = None, - ) -> None: - kwargs: dict[str, Any] = {} - if sys.version_info >= (3, 10): - kwargs["compact"] = compact - - is_recursive_call = _seen is not None - if _seen is None: - _seen = set() - _seen.add(id(exc_value)) - - self.stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_traceback), - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - ) - self.exc_type = exc_type - # Capture now to permit freeing resources: only complication is in the - # unofficial API _format_final_exc_line - self._str = _safe_string(exc_value, "exception") - try: - self.__notes__ = getattr(exc_value, "__notes__", None) - except KeyError: - # Workaround for https://github.com/python/cpython/issues/98778 on Python - # <= 3.9, and some 3.10 and 3.11 patch versions. - HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ()) - if sys.version_info[:2] <= (3, 11) and isinstance(exc_value, HTTPError): - self.__notes__ = None - else: - raise - - if exc_type and issubclass(exc_type, SyntaxError): - # Handle SyntaxError's specially - self.filename = exc_value.filename - lno = exc_value.lineno - self.lineno = str(lno) if lno is not None else None - self.text = exc_value.text - self.offset = exc_value.offset - self.msg = exc_value.msg - if sys.version_info >= (3, 10): - end_lno = exc_value.end_lineno - self.end_lineno = str(end_lno) if end_lno is not None else None - self.end_offset = exc_value.end_offset - elif ( - exc_type - and issubclass(exc_type, (NameError, AttributeError)) - and getattr(exc_value, "name", None) is not None - ): - suggestion = _compute_suggestion_error(exc_value, exc_traceback) - if suggestion: - self._str += f". Did you mean: '{suggestion}'?" - - if lookup_lines: - # Force all lines in the stack to be loaded - for frame in self.stack: - frame.line - - self.__suppress_context__ = ( - exc_value.__suppress_context__ if exc_value is not None else False - ) - - # Convert __cause__ and __context__ to `TracebackExceptions`s, use a - # queue to avoid recursion (only the top-level call gets _seen == None) - if not is_recursive_call: - queue = [(self, exc_value)] - while queue: - te, e = queue.pop() - - if e and e.__cause__ is not None and id(e.__cause__) not in _seen: - cause = PatchedTracebackException( - type(e.__cause__), - e.__cause__, - e.__cause__.__traceback__, - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - else: - cause = None - - if compact: - need_context = ( - cause is None and e is not None and not e.__suppress_context__ - ) - else: - need_context = True - if ( - e - and e.__context__ is not None - and need_context - and id(e.__context__) not in _seen - ): - context = PatchedTracebackException( - type(e.__context__), - e.__context__, - e.__context__.__traceback__, - limit=limit, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - else: - context = None - - # Capture each of the exceptions in the ExceptionGroup along with each - # of their causes and contexts - if e and isinstance(e, BaseExceptionGroup): - exceptions = [] - for exc in e.exceptions: - texc = PatchedTracebackException( - type(exc), - exc, - exc.__traceback__, - lookup_lines=lookup_lines, - capture_locals=capture_locals, - _seen=_seen, - ) - exceptions.append(texc) - else: - exceptions = None - - te.__cause__ = cause - te.__context__ = context - te.exceptions = exceptions - if cause: - queue.append((te.__cause__, e.__cause__)) - if context: - queue.append((te.__context__, e.__context__)) - if exceptions: - queue.extend(zip(te.exceptions, e.exceptions)) - - def format(self, *, chain=True, _ctx=None, **kwargs): - if _ctx is None: - _ctx = _ExceptionPrintContext() - - output = [] - exc = self - if chain: - while exc: - if exc.__cause__ is not None: - chained_msg = _cause_message - chained_exc = exc.__cause__ - elif exc.__context__ is not None and not exc.__suppress_context__: - chained_msg = _context_message - chained_exc = exc.__context__ - else: - chained_msg = None - chained_exc = None - - output.append((chained_msg, exc)) - exc = chained_exc - else: - output.append((None, exc)) - - for msg, exc in reversed(output): - if msg is not None: - yield from _ctx.emit(msg) - if getattr(exc, "exceptions", None) is None: - if exc.stack: - yield from _ctx.emit("Traceback (most recent call last):\n") - yield from _ctx.emit(exc.stack.format()) - yield from _ctx.emit(exc.format_exception_only()) - elif _ctx.exception_group_depth > max_group_depth: - # exception group, but depth exceeds limit - yield from _ctx.emit(f"... (max_group_depth is {max_group_depth})\n") - else: - # format exception group - is_toplevel = _ctx.exception_group_depth == 0 - if is_toplevel: - _ctx.exception_group_depth += 1 - - if exc.stack: - yield from _ctx.emit( - "Exception Group Traceback (most recent call last):\n", - margin_char="+" if is_toplevel else None, - ) - yield from _ctx.emit(exc.stack.format()) - - yield from _ctx.emit(exc.format_exception_only()) - num_excs = len(exc.exceptions) - if num_excs <= max_group_width: - n = num_excs - else: - n = max_group_width + 1 - _ctx.need_close = False - for i in range(n): - last_exc = i == n - 1 - if last_exc: - # The closing frame may be added by a recursive call - _ctx.need_close = True - - if max_group_width is not None: - truncated = i >= max_group_width - else: - truncated = False - title = f"{i + 1}" if not truncated else "..." - yield ( - _ctx.indent() - + ("+-" if i == 0 else " ") - + f"+---------------- {title} ----------------\n" - ) - _ctx.exception_group_depth += 1 - if not truncated: - yield from exc.exceptions[i].format(chain=chain, _ctx=_ctx) - else: - remaining = num_excs - max_group_width - plural = "s" if remaining > 1 else "" - yield from _ctx.emit( - f"and {remaining} more exception{plural}\n" - ) - - if last_exc and _ctx.need_close: - yield _ctx.indent() + "+------------------------------------\n" - _ctx.need_close = False - _ctx.exception_group_depth -= 1 - - if is_toplevel: - assert _ctx.exception_group_depth == 1 - _ctx.exception_group_depth = 0 - - def format_exception_only(self, **kwargs): - """Format the exception part of the traceback. - The return value is a generator of strings, each ending in a newline. - Normally, the generator emits a single string; however, for - SyntaxError exceptions, it emits several lines that (when - printed) display detailed information about where the syntax - error occurred. - The message indicating which exception occurred is always the last - string in the output. - """ - if self.exc_type is None: - yield traceback._format_final_exc_line(None, self._str) - return - - stype = self.exc_type.__qualname__ - smod = self.exc_type.__module__ - if smod not in ("__main__", "builtins"): - if not isinstance(smod, str): - smod = "" - stype = smod + "." + stype - - if not issubclass(self.exc_type, SyntaxError): - yield _format_final_exc_line(stype, self._str) - elif traceback_exception_format_syntax_error is not None: - yield from traceback_exception_format_syntax_error(self, stype) - else: - yield from traceback_exception_original_format_exception_only(self) - - notes = getattr(self, "__notes__", None) - if isinstance(notes, collections.abc.Sequence): - for note in notes: - note = _safe_string(note, "note") - yield from [line + "\n" for line in note.split("\n")] - elif notes is not None: - yield _safe_string(notes, "__notes__", func=repr) - - -traceback_exception_original_format = traceback.TracebackException.format -traceback_exception_original_format_exception_only = ( - traceback.TracebackException.format_exception_only -) -traceback_exception_format_syntax_error = getattr( - traceback.TracebackException, "_format_syntax_error", None -) -if sys.excepthook is sys.__excepthook__: - traceback.TracebackException.__init__ = ( # type: ignore[assignment] - PatchedTracebackException.__init__ - ) - traceback.TracebackException.format = ( # type: ignore[assignment] - PatchedTracebackException.format - ) - traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] - PatchedTracebackException.format_exception_only - ) - sys.excepthook = exceptiongroup_excepthook - -# Ubuntu's system Python has a sitecustomize.py file that imports -# apport_python_hook and replaces sys.excepthook. -# -# The custom hook captures the error for crash reporting, and then calls -# sys.__excepthook__ to actually print the error. -# -# We don't mind it capturing the error for crash reporting, but we want to -# take over printing the error. So we monkeypatch the apport_python_hook -# module so that instead of calling sys.__excepthook__, it calls our custom -# hook. -# -# More details: https://github.com/python-trio/trio/issues/1065 -if getattr(sys.excepthook, "__name__", None) in ( - "apport_excepthook", - # on ubuntu 22.10 the hook was renamed to partial_apport_excepthook - "partial_apport_excepthook", -): - # patch traceback like above - traceback.TracebackException.__init__ = ( # type: ignore[assignment] - PatchedTracebackException.__init__ - ) - traceback.TracebackException.format = ( # type: ignore[assignment] - PatchedTracebackException.format - ) - traceback.TracebackException.format_exception_only = ( # type: ignore[assignment] - PatchedTracebackException.format_exception_only - ) - - from types import ModuleType - - import apport_python_hook - - # monkeypatch the sys module that apport has imported - fake_sys = ModuleType("exceptiongroup_fake_sys") - fake_sys.__dict__.update(sys.__dict__) - fake_sys.__excepthook__ = exceptiongroup_excepthook - apport_python_hook.sys = fake_sys - - -@singledispatch -def format_exception_only(__exc: BaseException, **kwargs: Any) -> List[str]: - return list( - PatchedTracebackException( - type(__exc), __exc, None, compact=True - ).format_exception_only() - ) - - -@format_exception_only.register -def _(__exc: type, value: BaseException, **kwargs: Any) -> List[str]: - return format_exception_only(value) - - -@singledispatch -def format_exception( - __exc: BaseException, limit: Optional[int] = None, chain: bool = True, **kwargs: Any -) -> List[str]: - return list( - PatchedTracebackException( - type(__exc), __exc, __exc.__traceback__, limit=limit, compact=True - ).format(chain=chain) - ) - - -@format_exception.register -def _( - __exc: type, - value: BaseException, - tb: TracebackType, - limit: Optional[int] = None, - chain: bool = True, - **kwargs: Any, -) -> List[str]: - return format_exception(value, limit, chain) - - -@singledispatch -def print_exception( - __exc: BaseException, - limit: Optional[int] = None, - file: Any = None, - chain: bool = True, - **kwargs: Any, -) -> None: - if file is None: - file = sys.stderr - - for line in PatchedTracebackException( - type(__exc), __exc, __exc.__traceback__, limit=limit - ).format(chain=chain): - print(line, file=file, end="") - - -@print_exception.register -def _( - __exc: type, - value: BaseException, - tb: TracebackType, - limit: Optional[int] = None, - file: Any = None, - chain: bool = True, -) -> None: - print_exception(value, limit, file, chain) - - -def print_exc( - limit: Optional[int] = None, - file: Any | None = None, - chain: bool = True, -) -> None: - value = sys.exc_info()[1] - print_exception(value, limit, file, chain) - - -# Python levenshtein edit distance code for NameError/AttributeError -# suggestions, backported from 3.12 - -_MAX_CANDIDATE_ITEMS = 750 -_MAX_STRING_SIZE = 40 -_MOVE_COST = 2 -_CASE_COST = 1 -_SENTINEL = object() - - -def _substitution_cost(ch_a, ch_b): - if ch_a == ch_b: - return 0 - if ch_a.lower() == ch_b.lower(): - return _CASE_COST - return _MOVE_COST - - -def _compute_suggestion_error(exc_value, tb): - wrong_name = getattr(exc_value, "name", None) - if wrong_name is None or not isinstance(wrong_name, str): - return None - if isinstance(exc_value, AttributeError): - obj = getattr(exc_value, "obj", _SENTINEL) - if obj is _SENTINEL: - return None - obj = exc_value.obj - try: - d = dir(obj) - except Exception: - return None - else: - assert isinstance(exc_value, NameError) - # find most recent frame - if tb is None: - return None - while tb.tb_next is not None: - tb = tb.tb_next - frame = tb.tb_frame - - d = list(frame.f_locals) + list(frame.f_globals) + list(frame.f_builtins) - if len(d) > _MAX_CANDIDATE_ITEMS: - return None - wrong_name_len = len(wrong_name) - if wrong_name_len > _MAX_STRING_SIZE: - return None - best_distance = wrong_name_len - suggestion = None - for possible_name in d: - if possible_name == wrong_name: - # A missing attribute is "found". Don't suggest it (see GH-88821). - continue - # No more than 1/3 of the involved characters should need changed. - max_distance = (len(possible_name) + wrong_name_len + 3) * _MOVE_COST // 6 - # Don't take matches we've already beaten. - max_distance = min(max_distance, best_distance - 1) - current_distance = _levenshtein_distance( - wrong_name, possible_name, max_distance - ) - if current_distance > max_distance: - continue - if not suggestion or current_distance < best_distance: - suggestion = possible_name - best_distance = current_distance - return suggestion - - -def _levenshtein_distance(a, b, max_cost): - # A Python implementation of Python/suggestions.c:levenshtein_distance. - - # Both strings are the same - if a == b: - return 0 - - # Trim away common affixes - pre = 0 - while a[pre:] and b[pre:] and a[pre] == b[pre]: - pre += 1 - a = a[pre:] - b = b[pre:] - post = 0 - while a[: post or None] and b[: post or None] and a[post - 1] == b[post - 1]: - post -= 1 - a = a[: post or None] - b = b[: post or None] - if not a or not b: - return _MOVE_COST * (len(a) + len(b)) - if len(a) > _MAX_STRING_SIZE or len(b) > _MAX_STRING_SIZE: - return max_cost + 1 - - # Prefer shorter buffer - if len(b) < len(a): - a, b = b, a - - # Quick fail when a match is impossible - if (len(b) - len(a)) * _MOVE_COST > max_cost: - return max_cost + 1 - - # Instead of producing the whole traditional len(a)-by-len(b) - # matrix, we can update just one row in place. - # Initialize the buffer row - row = list(range(_MOVE_COST, _MOVE_COST * (len(a) + 1), _MOVE_COST)) - - result = 0 - for bindex in range(len(b)): - bchar = b[bindex] - distance = result = bindex * _MOVE_COST - minimum = sys.maxsize - for index in range(len(a)): - # 1) Previous distance in this row is cost(b[:b_index], a[:index]) - substitute = distance + _substitution_cost(bchar, a[index]) - # 2) cost(b[:b_index], a[:index+1]) from previous row - distance = row[index] - # 3) existing result is cost(b[:b_index+1], a[index]) - - insert_delete = min(result, distance) + _MOVE_COST - result = min(insert_delete, substitute) - - # cost(b[:b_index+1], a[:index+1]) - row[index] = result - if result < minimum: - minimum = result - if minimum > max_cost: - # Everything in this row is too big, so bail early. - return max_cost + 1 - return result diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_suppress.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_suppress.py deleted file mode 100644 index 11467ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_suppress.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import sys -from contextlib import AbstractContextManager -from types import TracebackType -from typing import TYPE_CHECKING, Optional, Type, cast - -if sys.version_info < (3, 11): - from ._exceptions import BaseExceptionGroup - -if TYPE_CHECKING: - # requires python 3.9 - BaseClass = AbstractContextManager[None] -else: - BaseClass = AbstractContextManager - - -class suppress(BaseClass): - """Backport of :class:`contextlib.suppress` from Python 3.12.1.""" - - def __init__(self, *exceptions: type[BaseException]): - self._exceptions = exceptions - - def __enter__(self) -> None: - pass - - def __exit__( - self, - exctype: Optional[Type[BaseException]], - excinst: Optional[BaseException], - exctb: Optional[TracebackType], - ) -> bool: - # Unlike isinstance and issubclass, CPython exception handling - # currently only looks at the concrete type hierarchy (ignoring - # the instance and subclass checking hooks). While Guido considers - # that a bug rather than a feature, it's a fairly hard one to fix - # due to various internal implementation details. suppress provides - # the simpler issubclass based semantics, rather than trying to - # exactly reproduce the limitations of the CPython interpreter. - # - # See http://bugs.python.org/issue12029 for more details - if exctype is None: - return False - - if issubclass(exctype, self._exceptions): - return True - - if issubclass(exctype, BaseExceptionGroup): - match, rest = cast(BaseExceptionGroup, excinst).split(self._exceptions) - if rest is None: - return True - - raise rest - - return False diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_version.py b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_version.py deleted file mode 100644 index ebbbcb2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/_version.py +++ /dev/null @@ -1,34 +0,0 @@ -# file generated by setuptools-scm -# don't change, don't track in version control - -__all__ = [ - "__version__", - "__version_tuple__", - "version", - "version_tuple", - "__commit_id__", - "commit_id", -] - -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Tuple - from typing import Union - - VERSION_TUPLE = Tuple[Union[int, str], ...] - COMMIT_ID = Union[str, None] -else: - VERSION_TUPLE = object - COMMIT_ID = object - -version: str -__version__: str -__version_tuple__: VERSION_TUPLE -version_tuple: VERSION_TUPLE -commit_id: COMMIT_ID -__commit_id__: COMMIT_ID - -__version__ = version = '1.3.1' -__version_tuple__ = version_tuple = (1, 3, 1) - -__commit_id__ = commit_id = None diff --git a/backend/venv39/lib/python3.9/site-packages/exceptiongroup/py.typed b/backend/venv39/lib/python3.9/site-packages/exceptiongroup/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/METADATA deleted file mode 100644 index f5f8bd9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/METADATA +++ /dev/null @@ -1,645 +0,0 @@ -Metadata-Version: 2.4 -Name: fastapi -Version: 0.128.0 -Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production -Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= -License-Expression: MIT -License-File: LICENSE -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python -Classifier: Topic :: Internet -Classifier: Topic :: Software Development :: Libraries :: Application Frameworks -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development -Classifier: Typing :: Typed -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: FastAPI -Classifier: Framework :: Pydantic -Classifier: Framework :: Pydantic :: 2 -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers -Classifier: Topic :: Internet :: WWW/HTTP -Project-URL: Homepage, https://github.com/fastapi/fastapi -Project-URL: Documentation, https://fastapi.tiangolo.com/ -Project-URL: Repository, https://github.com/fastapi/fastapi -Project-URL: Issues, https://github.com/fastapi/fastapi/issues -Project-URL: Changelog, https://fastapi.tiangolo.com/release-notes/ -Requires-Python: >=3.9 -Requires-Dist: starlette<0.51.0,>=0.40.0 -Requires-Dist: pydantic>=2.7.0 -Requires-Dist: typing-extensions>=4.8.0 -Requires-Dist: annotated-doc>=0.0.2 -Provides-Extra: standard -Requires-Dist: fastapi-cli[standard]>=0.0.8; extra == "standard" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "standard" -Requires-Dist: jinja2>=3.1.5; extra == "standard" -Requires-Dist: python-multipart>=0.0.18; extra == "standard" -Requires-Dist: email-validator>=2.0.0; extra == "standard" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "standard" -Requires-Dist: pydantic-settings>=2.0.0; extra == "standard" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "standard" -Provides-Extra: standard-no-fastapi-cloud-cli -Requires-Dist: fastapi-cli[standard-no-fastapi-cloud-cli]>=0.0.8; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: jinja2>=3.1.5; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: python-multipart>=0.0.18; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: email-validator>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: pydantic-settings>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "standard-no-fastapi-cloud-cli" -Provides-Extra: all -Requires-Dist: fastapi-cli[standard]>=0.0.8; extra == "all" -Requires-Dist: httpx<1.0.0,>=0.23.0; extra == "all" -Requires-Dist: jinja2>=3.1.5; extra == "all" -Requires-Dist: python-multipart>=0.0.18; extra == "all" -Requires-Dist: itsdangerous>=1.1.0; extra == "all" -Requires-Dist: pyyaml>=5.3.1; extra == "all" -Requires-Dist: ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1; extra == "all" -Requires-Dist: orjson>=3.2.1; extra == "all" -Requires-Dist: email-validator>=2.0.0; extra == "all" -Requires-Dist: uvicorn[standard]>=0.12.0; extra == "all" -Requires-Dist: pydantic-settings>=2.0.0; extra == "all" -Requires-Dist: pydantic-extra-types>=2.0.0; extra == "all" -Description-Content-Type: text/markdown - -

    - FastAPI -

    -

    - FastAPI framework, high performance, easy to learn, fast to code, ready for production -

    -

    - - Test - - - Coverage - - - Package version - - - Supported Python versions - -

    - ---- - -**Documentation**: https://fastapi.tiangolo.com - -**Source Code**: https://github.com/fastapi/fastapi - ---- - -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints. - -The key features are: - -* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). -* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * -* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * -* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. -* **Easy**: Designed to be easy to use and learn. Less time reading docs. -* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. -* **Robust**: Get production-ready code. With automatic interactive documentation. -* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. - -* estimation based on tests conducted by an internal development team, building production applications. - -## Sponsors - - -### Keystone Sponsor - - - -### Gold and Silver Sponsors - - - - - - - - - - - - - - - - - - - - - - -Other sponsors - -## Opinions - -"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" - -
    Kabir Khan - Microsoft (ref)
    - ---- - -"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_" - -
    Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
    - ---- - -"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_" - -
    Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
    - ---- - -"_I’m over the moon excited about **FastAPI**. It’s so fun!_" - -
    Brian Okken - Python Bytes podcast host (ref)
    - ---- - -"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._" - -
    Timothy Crosley - Hug creator (ref)
    - ---- - -"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_" - -"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_" - -
    Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
    - ---- - -"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._" - -
    Deon Pillsbury - Cisco (ref)
    - ---- - -## FastAPI mini documentary - -There's a FastAPI mini documentary released at the end of 2025, you can watch it online: - -FastAPI Mini Documentary - -## **Typer**, the FastAPI of CLIs - - - -If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. - -**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 - -## Requirements - -FastAPI stands on the shoulders of giants: - -* Starlette for the web parts. -* Pydantic for the data parts. - -## Installation - -Create and activate a virtual environment and then install FastAPI: - -
    - -```console -$ pip install "fastapi[standard]" - ----> 100% -``` - -
    - -**Note**: Make sure you put `"fastapi[standard]"` in quotes to ensure it works in all terminals. - -## Example - -### Create it - -Create a file `main.py` with: - -```Python -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -
    -Or use async def... - -If your code uses `async` / `await`, use `async def`: - -```Python hl_lines="9 14" -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -async def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} -``` - -**Note**: - -If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. - -
    - -### Run it - -Run the server with: - -
    - -```console -$ fastapi dev main.py - - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - │ fastapi run │ - │ │ - ╰─────────────────────────────────────────────────────╯ - -INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [2248755] using WatchFiles -INFO: Started server process [2248757] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -
    - -
    -About the command fastapi dev main.py... - -The command `fastapi dev` reads your `main.py` file, detects the **FastAPI** app in it, and starts a server using Uvicorn. - -By default, `fastapi dev` will start with auto-reload enabled for local development. - -You can read more about it in the FastAPI CLI docs. - -
    - -### Check it - -Open your browser at http://127.0.0.1:8000/items/5?q=somequery. - -You will see the JSON response as: - -```JSON -{"item_id": 5, "q": "somequery"} -``` - -You already created an API that: - -* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. -* Both _paths_ take `GET` operations (also known as HTTP _methods_). -* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. -* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. - -### Interactive API docs - -Now go to http://127.0.0.1:8000/docs. - -You will see the automatic interactive API documentation (provided by Swagger UI): - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) - -### Alternative API docs - -And now, go to http://127.0.0.1:8000/redoc. - -You will see the alternative automatic documentation (provided by ReDoc): - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) - -## Example upgrade - -Now modify the file `main.py` to receive a body from a `PUT` request. - -Declare the body using standard Python types, thanks to Pydantic. - -```Python hl_lines="4 9-12 25-27" -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - is_offer: Union[bool, None] = None - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): - return {"item_id": item_id, "q": q} - - -@app.put("/items/{item_id}") -def update_item(item_id: int, item: Item): - return {"item_name": item.name, "item_id": item_id} -``` - -The `fastapi dev` server should reload automatically. - -### Interactive API docs upgrade - -Now go to http://127.0.0.1:8000/docs. - -* The interactive API documentation will be automatically updated, including the new body: - -![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) - -* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) - -* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: - -![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) - -### Alternative API docs upgrade - -And now, go to http://127.0.0.1:8000/redoc. - -* The alternative documentation will also reflect the new query parameter and body: - -![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) - -### Recap - -In summary, you declare **once** the types of parameters, body, etc. as function parameters. - -You do that with standard modern Python types. - -You don't have to learn a new syntax, the methods or classes of a specific library, etc. - -Just standard **Python**. - -For example, for an `int`: - -```Python -item_id: int -``` - -or for a more complex `Item` model: - -```Python -item: Item -``` - -...and with that single declaration you get: - -* Editor support, including: - * Completion. - * Type checks. -* Validation of data: - * Automatic and clear errors when the data is invalid. - * Validation even for deeply nested JSON objects. -* Conversion of input data: coming from the network to Python data and types. Reading from: - * JSON. - * Path parameters. - * Query parameters. - * Cookies. - * Headers. - * Forms. - * Files. -* Conversion of output data: converting from Python data and types to network data (as JSON): - * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). - * `datetime` objects. - * `UUID` objects. - * Database models. - * ...and many more. -* Automatic interactive API documentation, including 2 alternative user interfaces: - * Swagger UI. - * ReDoc. - ---- - -Coming back to the previous code example, **FastAPI** will: - -* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. -* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. - * If it is not, the client will see a useful, clear error. -* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. - * As the `q` parameter is declared with `= None`, it is optional. - * Without the `None` it would be required (as is the body in the case with `PUT`). -* For `PUT` requests to `/items/{item_id}`, read the body as JSON: - * Check that it has a required attribute `name` that should be a `str`. - * Check that it has a required attribute `price` that has to be a `float`. - * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. - * All this would also work for deeply nested JSON objects. -* Convert from and to JSON automatically. -* Document everything with OpenAPI, that can be used by: - * Interactive documentation systems. - * Automatic client code generation systems, for many languages. -* Provide 2 interactive documentation web interfaces directly. - ---- - -We just scratched the surface, but you already get the idea of how it all works. - -Try changing the line with: - -```Python - return {"item_name": item.name, "item_id": item_id} -``` - -...from: - -```Python - ... "item_name": item.name ... -``` - -...to: - -```Python - ... "item_price": item.price ... -``` - -...and see how your editor will auto-complete the attributes and know their types: - -![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) - -For a more complete example including more features, see the Tutorial - User Guide. - -**Spoiler alert**: the tutorial - user guide includes: - -* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. -* How to set **validation constraints** as `maximum_length` or `regex`. -* A very powerful and easy to use **Dependency Injection** system. -* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. -* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). -* **GraphQL** integration with Strawberry and other libraries. -* Many extra features (thanks to Starlette) as: - * **WebSockets** - * extremely easy tests based on HTTPX and `pytest` - * **CORS** - * **Cookie Sessions** - * ...and more. - -### Deploy your app (optional) - -You can optionally deploy your FastAPI app to FastAPI Cloud, go and join the waiting list if you haven't. 🚀 - -If you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉), you can deploy your application with one command. - -Before deploying, make sure you are logged in: - -
    - -```console -$ fastapi login - -You are logged in to FastAPI Cloud 🚀 -``` - -
    - -Then deploy your app: - -
    - -```console -$ fastapi deploy - -Deploying to FastAPI Cloud... - -✅ Deployment successful! - -🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev -``` - -
    - -That's it! Now you can access your app at that URL. ✨ - -#### About FastAPI Cloud - -**FastAPI Cloud** is built by the same author and team behind **FastAPI**. - -It streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort. - -It brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉 - -FastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨ - -#### Deploy to other cloud providers - -FastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose. - -Follow your cloud provider's guides to deploy FastAPI apps with them. 🤓 - -## Performance - -Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) - -To understand more about it, see the section Benchmarks. - -## Dependencies - -FastAPI depends on Pydantic and Starlette. - -### `standard` Dependencies - -When you install FastAPI with `pip install "fastapi[standard]"` it comes with the `standard` group of optional dependencies: - -Used by Pydantic: - -* email-validator - for email validation. - -Used by Starlette: - -* httpx - Required if you want to use the `TestClient`. -* jinja2 - Required if you want to use the default template configuration. -* python-multipart - Required if you want to support form "parsing", with `request.form()`. - -Used by FastAPI: - -* uvicorn - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving. -* `fastapi-cli[standard]` - to provide the `fastapi` command. - * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to FastAPI Cloud. - -### Without `standard` Dependencies - -If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`. - -### Without `fastapi-cloud-cli` - -If you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. - -### Additional Optional Dependencies - -There are some additional dependencies you might want to install. - -Additional optional Pydantic dependencies: - -* pydantic-settings - for settings management. -* pydantic-extra-types - for extra types to be used with Pydantic. - -Additional optional FastAPI dependencies: - -* orjson - Required if you want to use `ORJSONResponse`. -* ujson - Required if you want to use `UJSONResponse`. - -## License - -This project is licensed under the terms of the MIT license. diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/RECORD deleted file mode 100644 index 857fea9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/RECORD +++ /dev/null @@ -1,103 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/shared.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/v2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/applications.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/background.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/cli.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/concurrency.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/datastructures.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/encoders.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/exception_handlers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/logger.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/cors.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/gzip.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/httpsredirect.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/trustedhost.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/wsgi.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/constants.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/docs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/param_functions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/requests.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/responses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/routing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/api_key.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/http.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/oauth2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/open_id_connect_url.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/security/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/staticfiles.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/templating.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/testclient.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/fastapi/websockets.cpython-39.pyc,, -../../../bin/fastapi,sha256=xi2y9oou3Ro2i7SzXmJsHyxt2vFQswcZQKjkTOxzOCY,264 -fastapi-0.128.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -fastapi-0.128.0.dist-info/METADATA,sha256=hKL7LtKoBl4ojHSJ_u5MsihJRMPBU5AsppXt75m24FY,30977 -fastapi-0.128.0.dist-info/RECORD,, -fastapi-0.128.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi-0.128.0.dist-info/WHEEL,sha256=tsUv_t7BDeJeRHaSrczbGeuK-TtDpGsWi_JfpzD255I,90 -fastapi-0.128.0.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61 -fastapi-0.128.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086 -fastapi/__init__.py,sha256=wlYVfo3p5m4F8JxyVpV1aFS5XKRzgCXBfB9s231GveY,1081 -fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37 -fastapi/_compat/__init__.py,sha256=o3dg67W5LlwA52_1Y9Re_JhelcG0oj5ke_GdQHcwBnw,2226 -fastapi/_compat/shared.py,sha256=yFZWOnzG1JRIPuLOk0eaBcrwP2bap8UkP5I0XBuVZck,6842 -fastapi/_compat/v2.py,sha256=B5OawqkcpTaaDLNZDHFlasGQyYFS7VFbwyDVwUTydE0,19597 -fastapi/applications.py,sha256=IO5F5FdRacBFXYxGPk7zPbwRCa-cxN74HHf0eMEp7xE,180536 -fastapi/background.py,sha256=fDNVXWBZniIQIxW3v-Sc99FT2p4RDKOOWW2fhOe4Nko,1793 -fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418 -fastapi/concurrency.py,sha256=xHGDEOQAA6cvFEDX46oq3r2t1Zd4sVvreaRgdIE4juM,1489 -fastapi/datastructures.py,sha256=41qs2ZhTzORMGn7JSAF9qsiPY9XP4uGyGOMKhfzg4i4,5205 -fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/dependencies/models.py,sha256=TjJB2l6m-vhFkau7ysLdgcymZ6SdIJmlrJjqMJs5TZc,7317 -fastapi/dependencies/utils.py,sha256=rJQFCFUC7q765yUcOoSV78GCyTGfS2ePLbMvJ2B-yLc,38549 -fastapi/encoders.py,sha256=uQfXjliV2O93wy7sng3pUuLZw9UOw8HNsAHb2B1ZfEs,11004 -fastapi/exception_handlers.py,sha256=YVcT8Zy021VYYeecgdyh5YEUjEIHKcLspbkSf4OfbJI,1275 -fastapi/exceptions.py,sha256=enNT5h_wDyzY90qA4a_VqMDRSUNHTd1LX_vihMNa-LE,6973 -fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54 -fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58 -fastapi/middleware/asyncexitstack.py,sha256=RKGlQpGzg3GLosqVhrxBy_NCZ9qJS7zQeNHt5Y3x-00,637 -fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79 -fastapi/middleware/gzip.py,sha256=xM5PcsH8QlAimZw4VDvcmTnqQamslThsfe3CVN2voa0,79 -fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs8ix950,115 -fastapi/middleware/trustedhost.py,sha256=eE5XGRxGa7c5zPnMJDGp3BxaL25k5iVQlhnv-Pk0Pss,109 -fastapi/middleware/wsgi.py,sha256=Z3Ue-7wni4lUZMvH3G9ek__acgYdJstbnpZX_HQAboY,79 -fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153 -fastapi/openapi/docs.py,sha256=wqcXZOhBdnf2pilVNyAIfjKAhfH9MXaQiitwZeJCR7I,10335 -fastapi/openapi/models.py,sha256=xJfPRE7DqNvtqgdouXbtMCCLBrZ-4Bd87QaA_WPUVTA,15419 -fastapi/openapi/utils.py,sha256=HsOqZ8uWSTUYL18jhYI0gU-A1nLHCNu3k3UEIAVzRyY,23795 -fastapi/param_functions.py,sha256=O8bsr2xM8XODE0wjtev8sZLl3Tt_glpdQteM2relVrU,64466 -fastapi/params.py,sha256=YS7z57t0N4H8Rdogx1sU6R-KZDcLn5y46SGz8z5lX-s,26982 -fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142 -fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761 -fastapi/routing.py,sha256=dHZW6NLzbvD7jZT2N-V6fj1Irbe8HR-FDeiBNSuTHHs,178746 -fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881 -fastapi/security/api_key.py,sha256=5AriUhrA_KgdtJRJ_BtCDgcTFOUlUUvDSultdIfdApc,9799 -fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141 -fastapi/security/http.py,sha256=gckOhSa1ubLpARU819pxKiZZnmnyg_co6AwQyNE8yxw,13518 -fastapi/security/oauth2.py,sha256=8sU0yRncO_1mK8rdUES1GRijPawi2ZGwLGWphWeS02w,22477 -fastapi/security/open_id_connect_url.py,sha256=pFvSVESThhjYXSDWPlFGtm9bN62JXHzuwnVfmtyNcZE,3158 -fastapi/security/utils.py,sha256=Gk6KGztJnYqvYFTmuQO7ow_icayiqP3HL762ZFRQjfU,286 -fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69 -fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76 -fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66 -fastapi/types.py,sha256=W0HOmfeZw_3PcMDOa6GA-Or9okP9hf_260UkbCfKHY4,455 -fastapi/utils.py,sha256=sl-ddHjWbQiLUNLFiG93IXStAZgp8NSFwJsjo41mb04,5230 -fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/WHEEL deleted file mode 100644 index 2efd4ed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: pdm-backend (2.4.6) -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/entry_points.txt deleted file mode 100644 index b81849e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/entry_points.txt +++ /dev/null @@ -1,5 +0,0 @@ -[console_scripts] -fastapi = fastapi.cli:main - -[gui_scripts] - diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE deleted file mode 100644 index 3e92463..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi-0.128.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Sebastián Ramírez - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/__init__.py deleted file mode 100644 index 6133787..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" - -__version__ = "0.128.0" - -from starlette import status as status - -from .applications import FastAPI as FastAPI -from .background import BackgroundTasks as BackgroundTasks -from .datastructures import UploadFile as UploadFile -from .exceptions import HTTPException as HTTPException -from .exceptions import WebSocketException as WebSocketException -from .param_functions import Body as Body -from .param_functions import Cookie as Cookie -from .param_functions import Depends as Depends -from .param_functions import File as File -from .param_functions import Form as Form -from .param_functions import Header as Header -from .param_functions import Path as Path -from .param_functions import Query as Query -from .param_functions import Security as Security -from .requests import Request as Request -from .responses import Response as Response -from .routing import APIRouter as APIRouter -from .websockets import WebSocket as WebSocket -from .websockets import WebSocketDisconnect as WebSocketDisconnect diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/__main__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/__main__.py deleted file mode 100644 index fc36465..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from fastapi.cli import main - -main() diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/__init__.py deleted file mode 100644 index 3dfaf9b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -from .shared import PYDANTIC_V2 as PYDANTIC_V2 -from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE -from .shared import annotation_is_pydantic_v1 as annotation_is_pydantic_v1 -from .shared import field_annotation_is_scalar as field_annotation_is_scalar -from .shared import is_pydantic_v1_model_class as is_pydantic_v1_model_class -from .shared import is_pydantic_v1_model_instance as is_pydantic_v1_model_instance -from .shared import ( - is_uploadfile_or_nonable_uploadfile_annotation as is_uploadfile_or_nonable_uploadfile_annotation, -) -from .shared import ( - is_uploadfile_sequence_annotation as is_uploadfile_sequence_annotation, -) -from .shared import lenient_issubclass as lenient_issubclass -from .shared import sequence_types as sequence_types -from .shared import value_is_sequence as value_is_sequence -from .v2 import BaseConfig as BaseConfig -from .v2 import ModelField as ModelField -from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError -from .v2 import RequiredParam as RequiredParam -from .v2 import Undefined as Undefined -from .v2 import UndefinedType as UndefinedType -from .v2 import Url as Url -from .v2 import Validator as Validator -from .v2 import _regenerate_error_with_loc as _regenerate_error_with_loc -from .v2 import copy_field_info as copy_field_info -from .v2 import create_body_model as create_body_model -from .v2 import evaluate_forwardref as evaluate_forwardref -from .v2 import get_cached_model_fields as get_cached_model_fields -from .v2 import get_compat_model_name_map as get_compat_model_name_map -from .v2 import get_definitions as get_definitions -from .v2 import get_missing_field_error as get_missing_field_error -from .v2 import get_schema_from_model_field as get_schema_from_model_field -from .v2 import is_bytes_field as is_bytes_field -from .v2 import is_bytes_sequence_field as is_bytes_sequence_field -from .v2 import is_scalar_field as is_scalar_field -from .v2 import is_scalar_sequence_field as is_scalar_sequence_field -from .v2 import is_sequence_field as is_sequence_field -from .v2 import serialize_sequence_value as serialize_sequence_value -from .v2 import ( - with_info_plain_validator_function as with_info_plain_validator_function, -) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/shared.py b/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/shared.py deleted file mode 100644 index 419b58f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/shared.py +++ /dev/null @@ -1,206 +0,0 @@ -import sys -import types -import typing -import warnings -from collections import deque -from collections.abc import Mapping, Sequence -from dataclasses import is_dataclass -from typing import ( - Annotated, - Any, - Union, -) - -from fastapi.types import UnionType -from pydantic import BaseModel -from pydantic.version import VERSION as PYDANTIC_VERSION -from starlette.datastructures import UploadFile -from typing_extensions import get_args, get_origin - -# Copy from Pydantic v2, compatible with v1 -if sys.version_info < (3, 10): - WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # type: ignore[attr-defined] -else: - WithArgsTypes: tuple[Any, ...] = ( - typing._GenericAlias, # type: ignore[attr-defined] - types.GenericAlias, - types.UnionType, - ) # pyright: ignore[reportAttributeAccessIssue] - -PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2]) -PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2 - - -sequence_annotation_to_type = { - Sequence: list, - list: list, - tuple: tuple, - set: set, - frozenset: frozenset, - deque: deque, -} - -sequence_types = tuple(sequence_annotation_to_type.keys()) - -Url: type[Any] - - -# Copy of Pydantic v2, compatible with v1 -def lenient_issubclass( - cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None] -) -> bool: - try: - return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] - except TypeError: # pragma: no cover - if isinstance(cls, WithArgsTypes): - return False - raise # pragma: no cover - - -def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: - if lenient_issubclass(annotation, (str, bytes)): - return False - return lenient_issubclass(annotation, sequence_types) - - -def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if field_annotation_is_sequence(arg): - return True - return False - return _annotation_is_sequence(annotation) or _annotation_is_sequence( - get_origin(annotation) - ) - - -def value_is_sequence(value: Any) -> bool: - return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) - - -def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool: - return ( - lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile)) - or _annotation_is_sequence(annotation) - or is_dataclass(annotation) - ) - - -def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - return any(field_annotation_is_complex(arg) for arg in get_args(annotation)) - - if origin is Annotated: - return field_annotation_is_complex(get_args(annotation)[0]) - - return ( - _annotation_is_complex(annotation) - or _annotation_is_complex(origin) - or hasattr(origin, "__pydantic_core_schema__") - or hasattr(origin, "__get_pydantic_core_schema__") - ) - - -def field_annotation_is_scalar(annotation: Any) -> bool: - # handle Ellipsis here to make tuple[int, ...] work nicely - return annotation is Ellipsis or not field_annotation_is_complex(annotation) - - -def field_annotation_is_scalar_sequence(annotation: Union[type[Any], None]) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one_scalar_sequence = False - for arg in get_args(annotation): - if field_annotation_is_scalar_sequence(arg): - at_least_one_scalar_sequence = True - continue - elif not field_annotation_is_scalar(arg): - return False - return at_least_one_scalar_sequence - return field_annotation_is_sequence(annotation) and all( - field_annotation_is_scalar(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool: - if lenient_issubclass(annotation, bytes): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if lenient_issubclass(arg, bytes): - return True - return False - - -def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool: - if lenient_issubclass(annotation, UploadFile): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if lenient_issubclass(arg, UploadFile): - return True - return False - - -def is_bytes_sequence_annotation(annotation: Any) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one = False - for arg in get_args(annotation): - if is_bytes_sequence_annotation(arg): - at_least_one = True - continue - return at_least_one - return field_annotation_is_sequence(annotation) and all( - is_bytes_or_nonable_bytes_annotation(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_uploadfile_sequence_annotation(annotation: Any) -> bool: - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - at_least_one = False - for arg in get_args(annotation): - if is_uploadfile_sequence_annotation(arg): - at_least_one = True - continue - return at_least_one - return field_annotation_is_sequence(annotation) and all( - is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation) - for sub_annotation in get_args(annotation) - ) - - -def is_pydantic_v1_model_instance(obj: Any) -> bool: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", UserWarning) - from pydantic import v1 - return isinstance(obj, v1.BaseModel) - - -def is_pydantic_v1_model_class(cls: Any) -> bool: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", UserWarning) - from pydantic import v1 - return lenient_issubclass(cls, v1.BaseModel) - - -def annotation_is_pydantic_v1(annotation: Any) -> bool: - if is_pydantic_v1_model_class(annotation): - return True - origin = get_origin(annotation) - if origin is Union or origin is UnionType: - for arg in get_args(annotation): - if is_pydantic_v1_model_class(arg): - return True - if field_annotation_is_sequence(annotation): - for sub_annotation in get_args(annotation): - if annotation_is_pydantic_v1(sub_annotation): - return True - return False diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/v2.py b/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/v2.py deleted file mode 100644 index 25b6814..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/_compat/v2.py +++ /dev/null @@ -1,568 +0,0 @@ -import re -import warnings -from collections.abc import Sequence -from copy import copy, deepcopy -from dataclasses import dataclass, is_dataclass -from enum import Enum -from functools import lru_cache -from typing import ( - Annotated, - Any, - Union, - cast, -) - -from fastapi._compat import shared -from fastapi.openapi.constants import REF_TEMPLATE -from fastapi.types import IncEx, ModelNameMap, UnionType -from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, create_model -from pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError -from pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation -from pydantic import ValidationError as ValidationError -from pydantic._internal._schema_generation_shared import ( # type: ignore[attr-defined] - GetJsonSchemaHandler as GetJsonSchemaHandler, -) -from pydantic._internal._typing_extra import eval_type_lenient -from pydantic._internal._utils import lenient_issubclass as lenient_issubclass -from pydantic.fields import FieldInfo as FieldInfo -from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema -from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue -from pydantic_core import CoreSchema as CoreSchema -from pydantic_core import PydanticUndefined, PydanticUndefinedType -from pydantic_core import Url as Url -from typing_extensions import Literal, get_args, get_origin - -try: - from pydantic_core.core_schema import ( - with_info_plain_validator_function as with_info_plain_validator_function, - ) -except ImportError: # pragma: no cover - from pydantic_core.core_schema import ( - general_plain_validator_function as with_info_plain_validator_function, # noqa: F401 - ) - -RequiredParam = PydanticUndefined -Undefined = PydanticUndefined -UndefinedType = PydanticUndefinedType -evaluate_forwardref = eval_type_lenient -Validator = Any - -# TODO: remove when dropping support for Pydantic < v2.12.3 -_Attrs = { - "default": ..., - "default_factory": None, - "alias": None, - "alias_priority": None, - "validation_alias": None, - "serialization_alias": None, - "title": None, - "field_title_generator": None, - "description": None, - "examples": None, - "exclude": None, - "exclude_if": None, - "discriminator": None, - "deprecated": None, - "json_schema_extra": None, - "frozen": None, - "validate_default": None, - "repr": True, - "init": None, - "init_var": None, - "kw_only": None, -} - - -# TODO: remove when dropping support for Pydantic < v2.12.3 -def asdict(field_info: FieldInfo) -> dict[str, Any]: - attributes = {} - for attr in _Attrs: - value = getattr(field_info, attr, Undefined) - if value is not Undefined: - attributes[attr] = value - return { - "annotation": field_info.annotation, - "metadata": field_info.metadata, - "attributes": attributes, - } - - -class BaseConfig: - pass - - -class ErrorWrapper(Exception): - pass - - -@dataclass -class ModelField: - field_info: FieldInfo - name: str - mode: Literal["validation", "serialization"] = "validation" - config: Union[ConfigDict, None] = None - - @property - def alias(self) -> str: - a = self.field_info.alias - return a if a is not None else self.name - - @property - def validation_alias(self) -> Union[str, None]: - va = self.field_info.validation_alias - if isinstance(va, str) and va: - return va - return None - - @property - def serialization_alias(self) -> Union[str, None]: - sa = self.field_info.serialization_alias - return sa or None - - @property - def required(self) -> bool: - return self.field_info.is_required() - - @property - def default(self) -> Any: - return self.get_default() - - @property - def type_(self) -> Any: - return self.field_info.annotation - - def __post_init__(self) -> None: - with warnings.catch_warnings(): - # Pydantic >= 2.12.0 warns about field specific metadata that is unused - # (e.g. `TypeAdapter(Annotated[int, Field(alias='b')])`). In some cases, we - # end up building the type adapter from a model field annotation so we - # need to ignore the warning: - if shared.PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12): - from pydantic.warnings import UnsupportedFieldAttributeWarning - - warnings.simplefilter( - "ignore", category=UnsupportedFieldAttributeWarning - ) - # TODO: remove after dropping support for Python 3.8 and - # setting the min Pydantic to v2.12.3 that adds asdict() - field_dict = asdict(self.field_info) - annotated_args = ( - field_dict["annotation"], - *field_dict["metadata"], - # this FieldInfo needs to be created again so that it doesn't include - # the old field info metadata and only the rest of the attributes - Field(**field_dict["attributes"]), - ) - self._type_adapter: TypeAdapter[Any] = TypeAdapter( - Annotated[annotated_args], - config=self.config, - ) - - def get_default(self) -> Any: - if self.field_info.is_required(): - return Undefined - return self.field_info.get_default(call_default_factory=True) - - def validate( - self, - value: Any, - values: dict[str, Any] = {}, # noqa: B006 - *, - loc: tuple[Union[int, str], ...] = (), - ) -> tuple[Any, Union[list[dict[str, Any]], None]]: - try: - return ( - self._type_adapter.validate_python(value, from_attributes=True), - None, - ) - except ValidationError as exc: - return None, _regenerate_error_with_loc( - errors=exc.errors(include_url=False), loc_prefix=loc - ) - - def serialize( - self, - value: Any, - *, - mode: Literal["json", "python"] = "json", - include: Union[IncEx, None] = None, - exclude: Union[IncEx, None] = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - ) -> Any: - # What calls this code passes a value that already called - # self._type_adapter.validate_python(value) - return self._type_adapter.dump_python( - value, - mode=mode, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - def __hash__(self) -> int: - # Each ModelField is unique for our purposes, to allow making a dict from - # ModelField to its JSON Schema. - return id(self) - - -def _has_computed_fields(field: ModelField) -> bool: - computed_fields = field._type_adapter.core_schema.get("schema", {}).get( - "computed_fields", [] - ) - return len(computed_fields) > 0 - - -def get_schema_from_model_field( - *, - field: ModelField, - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue - ], - separate_input_output_schemas: bool = True, -) -> dict[str, Any]: - override_mode: Union[Literal["validation"], None] = ( - None - if (separate_input_output_schemas or _has_computed_fields(field)) - else "validation" - ) - field_alias = ( - (field.validation_alias or field.alias) - if field.mode == "validation" - else (field.serialization_alias or field.alias) - ) - - # This expects that GenerateJsonSchema was already used to generate the definitions - json_schema = field_mapping[(field, override_mode or field.mode)] - if "$ref" not in json_schema: - # TODO remove when deprecating Pydantic v1 - # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207 - json_schema["title"] = field.field_info.title or field_alias.title().replace( - "_", " " - ) - return json_schema - - -def get_definitions( - *, - fields: Sequence[ModelField], - model_name_map: ModelNameMap, - separate_input_output_schemas: bool = True, -) -> tuple[ - dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - dict[str, dict[str, Any]], -]: - schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE) - validation_fields = [field for field in fields if field.mode == "validation"] - serialization_fields = [field for field in fields if field.mode == "serialization"] - flat_validation_models = get_flat_models_from_fields( - validation_fields, known_models=set() - ) - flat_serialization_models = get_flat_models_from_fields( - serialization_fields, known_models=set() - ) - flat_validation_model_fields = [ - ModelField( - field_info=FieldInfo(annotation=model), - name=model.__name__, - mode="validation", - ) - for model in flat_validation_models - ] - flat_serialization_model_fields = [ - ModelField( - field_info=FieldInfo(annotation=model), - name=model.__name__, - mode="serialization", - ) - for model in flat_serialization_models - ] - flat_model_fields = flat_validation_model_fields + flat_serialization_model_fields - input_types = {f.type_ for f in fields} - unique_flat_model_fields = { - f for f in flat_model_fields if f.type_ not in input_types - } - inputs = [ - ( - field, - ( - field.mode - if (separate_input_output_schemas or _has_computed_fields(field)) - else "validation" - ), - field._type_adapter.core_schema, - ) - for field in list(fields) + list(unique_flat_model_fields) - ] - field_mapping, definitions = schema_generator.generate_definitions(inputs=inputs) - for item_def in cast(dict[str, dict[str, Any]], definitions).values(): - if "description" in item_def: - item_description = cast(str, item_def["description"]).split("\f")[0] - item_def["description"] = item_description - new_mapping, new_definitions = _remap_definitions_and_field_mappings( - model_name_map=model_name_map, - definitions=definitions, # type: ignore[arg-type] - field_mapping=field_mapping, - ) - return new_mapping, new_definitions - - -def _replace_refs( - *, - schema: dict[str, Any], - old_name_to_new_name_map: dict[str, str], -) -> dict[str, Any]: - new_schema = deepcopy(schema) - for key, value in new_schema.items(): - if key == "$ref": - value = schema["$ref"] - if isinstance(value, str): - ref_name = schema["$ref"].split("/")[-1] - if ref_name in old_name_to_new_name_map: - new_name = old_name_to_new_name_map[ref_name] - new_schema["$ref"] = REF_TEMPLATE.format(model=new_name) - continue - if isinstance(value, dict): - new_schema[key] = _replace_refs( - schema=value, - old_name_to_new_name_map=old_name_to_new_name_map, - ) - elif isinstance(value, list): - new_value = [] - for item in value: - if isinstance(item, dict): - new_item = _replace_refs( - schema=item, - old_name_to_new_name_map=old_name_to_new_name_map, - ) - new_value.append(new_item) - - else: - new_value.append(item) - new_schema[key] = new_value - return new_schema - - -def _remap_definitions_and_field_mappings( - *, - model_name_map: ModelNameMap, - definitions: dict[str, Any], - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue - ], -) -> tuple[ - dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - dict[str, Any], -]: - old_name_to_new_name_map = {} - for field_key, schema in field_mapping.items(): - model = field_key[0].type_ - if model not in model_name_map or "$ref" not in schema: - continue - new_name = model_name_map[model] - old_name = schema["$ref"].split("/")[-1] - if old_name in {f"{new_name}-Input", f"{new_name}-Output"}: - continue - old_name_to_new_name_map[old_name] = new_name - - new_field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue - ] = {} - for field_key, schema in field_mapping.items(): - new_schema = _replace_refs( - schema=schema, - old_name_to_new_name_map=old_name_to_new_name_map, - ) - new_field_mapping[field_key] = new_schema - - new_definitions = {} - for key, value in definitions.items(): - if key in old_name_to_new_name_map: - new_key = old_name_to_new_name_map[key] - else: - new_key = key - new_value = _replace_refs( - schema=value, - old_name_to_new_name_map=old_name_to_new_name_map, - ) - new_definitions[new_key] = new_value - return new_field_mapping, new_definitions - - -def is_scalar_field(field: ModelField) -> bool: - from fastapi import params - - return shared.field_annotation_is_scalar( - field.field_info.annotation - ) and not isinstance(field.field_info, params.Body) - - -def is_sequence_field(field: ModelField) -> bool: - return shared.field_annotation_is_sequence(field.field_info.annotation) - - -def is_scalar_sequence_field(field: ModelField) -> bool: - return shared.field_annotation_is_scalar_sequence(field.field_info.annotation) - - -def is_bytes_field(field: ModelField) -> bool: - return shared.is_bytes_or_nonable_bytes_annotation(field.type_) - - -def is_bytes_sequence_field(field: ModelField) -> bool: - return shared.is_bytes_sequence_annotation(field.type_) - - -def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: - cls = type(field_info) - merged_field_info = cls.from_annotation(annotation) - new_field_info = copy(field_info) - new_field_info.metadata = merged_field_info.metadata - new_field_info.annotation = merged_field_info.annotation - return new_field_info - - -def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: - origin_type = get_origin(field.field_info.annotation) or field.field_info.annotation - if origin_type is Union or origin_type is UnionType: # Handle optional sequences - union_args = get_args(field.field_info.annotation) - for union_arg in union_args: - if union_arg is type(None): - continue - origin_type = get_origin(union_arg) or union_arg - break - assert issubclass(origin_type, shared.sequence_types) # type: ignore[arg-type] - return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index] - - -def get_missing_field_error(loc: tuple[str, ...]) -> dict[str, Any]: - error = ValidationError.from_exception_data( - "Field required", [{"type": "missing", "loc": loc, "input": {}}] - ).errors(include_url=False)[0] - error["input"] = None - return error # type: ignore[return-value] - - -def create_body_model( - *, fields: Sequence[ModelField], model_name: str -) -> type[BaseModel]: - field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields} - BodyModel: type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload] - return BodyModel - - -def get_model_fields(model: type[BaseModel]) -> list[ModelField]: - model_fields: list[ModelField] = [] - for name, field_info in model.model_fields.items(): - type_ = field_info.annotation - if lenient_issubclass(type_, (BaseModel, dict)) or is_dataclass(type_): - model_config = None - else: - model_config = model.model_config - model_fields.append( - ModelField( - field_info=field_info, - name=name, - config=model_config, - ) - ) - return model_fields - - -@lru_cache -def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]: - return get_model_fields(model) # type: ignore[return-value] - - -# Duplicate of several schema functions from Pydantic v1 to make them compatible with -# Pydantic v2 and allow mixing the models - -TypeModelOrEnum = Union[type["BaseModel"], type[Enum]] -TypeModelSet = set[TypeModelOrEnum] - - -def normalize_name(name: str) -> str: - return re.sub(r"[^a-zA-Z0-9.\-_]", "_", name) - - -def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str]: - name_model_map = {} - for model in unique_models: - model_name = normalize_name(model.__name__) - name_model_map[model_name] = model - return {v: k for k, v in name_model_map.items()} - - -def get_compat_model_name_map(fields: list[ModelField]) -> ModelNameMap: - all_flat_models = set() - - v2_model_fields = [field for field in fields if isinstance(field, ModelField)] - v2_flat_models = get_flat_models_from_fields(v2_model_fields, known_models=set()) - all_flat_models = all_flat_models.union(v2_flat_models) # type: ignore[arg-type] - - model_name_map = get_model_name_map(all_flat_models) # type: ignore[arg-type] - return model_name_map - - -def get_flat_models_from_model( - model: type["BaseModel"], known_models: Union[TypeModelSet, None] = None -) -> TypeModelSet: - known_models = known_models or set() - fields = get_model_fields(model) - get_flat_models_from_fields(fields, known_models=known_models) - return known_models - - -def get_flat_models_from_annotation( - annotation: Any, known_models: TypeModelSet -) -> TypeModelSet: - origin = get_origin(annotation) - if origin is not None: - for arg in get_args(annotation): - if lenient_issubclass(arg, (BaseModel, Enum)) and arg not in known_models: - known_models.add(arg) - if lenient_issubclass(arg, BaseModel): - get_flat_models_from_model(arg, known_models=known_models) - else: - get_flat_models_from_annotation(arg, known_models=known_models) - return known_models - - -def get_flat_models_from_field( - field: ModelField, known_models: TypeModelSet -) -> TypeModelSet: - field_type = field.type_ - if lenient_issubclass(field_type, BaseModel): - if field_type in known_models: - return known_models - known_models.add(field_type) - get_flat_models_from_model(field_type, known_models=known_models) - elif lenient_issubclass(field_type, Enum): - known_models.add(field_type) - else: - get_flat_models_from_annotation(field_type, known_models=known_models) - return known_models - - -def get_flat_models_from_fields( - fields: Sequence[ModelField], known_models: TypeModelSet -) -> TypeModelSet: - for field in fields: - get_flat_models_from_field(field, known_models=known_models) - return known_models - - -def _regenerate_error_with_loc( - *, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...] -) -> list[dict[str, Any]]: - updated_loc_errors: list[Any] = [ - {**err, "loc": loc_prefix + err.get("loc", ())} for err in errors - ] - - return updated_loc_errors diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/applications.py b/backend/venv39/lib/python3.9/site-packages/fastapi/applications.py deleted file mode 100644 index 54175cb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/applications.py +++ /dev/null @@ -1,4669 +0,0 @@ -from collections.abc import Awaitable, Coroutine, Sequence -from enum import Enum -from typing import ( - Annotated, - Any, - Callable, - Optional, - TypeVar, - Union, -) - -from annotated_doc import Doc -from fastapi import routing -from fastapi.datastructures import Default, DefaultPlaceholder -from fastapi.exception_handlers import ( - http_exception_handler, - request_validation_exception_handler, - websocket_request_validation_exception_handler, -) -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.logger import logger -from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware -from fastapi.openapi.docs import ( - get_redoc_html, - get_swagger_ui_html, - get_swagger_ui_oauth2_redirect_html, -) -from fastapi.openapi.utils import get_openapi -from fastapi.params import Depends -from fastapi.types import DecoratedCallable, IncEx -from fastapi.utils import generate_unique_id -from starlette.applications import Starlette -from starlette.datastructures import State -from starlette.exceptions import HTTPException -from starlette.middleware import Middleware -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.middleware.errors import ServerErrorMiddleware -from starlette.middleware.exceptions import ExceptionMiddleware -from starlette.requests import Request -from starlette.responses import HTMLResponse, JSONResponse, Response -from starlette.routing import BaseRoute -from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send -from typing_extensions import deprecated - -AppType = TypeVar("AppType", bound="FastAPI") - - -class FastAPI(Starlette): - """ - `FastAPI` app class, the main entrypoint to use FastAPI. - - Read more in the - [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/). - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - ``` - """ - - def __init__( - self: AppType, - *, - debug: Annotated[ - bool, - Doc( - """ - Boolean indicating if debug tracebacks should be returned on server - errors. - - Read more in the - [Starlette docs for Applications](https://www.starlette.dev/applications/#instantiating-the-application). - """ - ), - ] = False, - routes: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - **Note**: you probably shouldn't use this parameter, it is inherited - from Starlette and supported for compatibility. - - --- - - A list of routes to serve incoming HTTP and WebSocket requests. - """ - ), - deprecated( - """ - You normally wouldn't use this parameter with FastAPI, it is inherited - from Starlette and supported for compatibility. - - In FastAPI, you normally would use the *path operation methods*, - like `app.get()`, `app.post()`, etc. - """ - ), - ] = None, - title: Annotated[ - str, - Doc( - """ - The title of the API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(title="ChimichangApp") - ``` - """ - ), - ] = "FastAPI", - summary: Annotated[ - Optional[str], - Doc( - """ - A short summary of the API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(summary="Deadpond's favorite app. Nuff said.") - ``` - """ - ), - ] = None, - description: Annotated[ - str, - Doc( - ''' - A description of the API. Supports Markdown (using - [CommonMark syntax](https://commonmark.org/)). - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI( - description=""" - ChimichangApp API helps you do awesome stuff. 🚀 - - ## Items - - You can **read items**. - - ## Users - - You will be able to: - - * **Create users** (_not implemented_). - * **Read users** (_not implemented_). - - """ - ) - ``` - ''' - ), - ] = "", - version: Annotated[ - str, - Doc( - """ - The version of the API. - - **Note** This is the version of your application, not the version of - the OpenAPI specification nor the version of FastAPI being used. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(version="0.0.1") - ``` - """ - ), - ] = "0.1.0", - openapi_url: Annotated[ - Optional[str], - Doc( - """ - The URL where the OpenAPI schema will be served from. - - If you set it to `None`, no OpenAPI schema will be served publicly, and - the default automatic endpoints `/docs` and `/redoc` will also be - disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(openapi_url="/api/v1/openapi.json") - ``` - """ - ), - ] = "/openapi.json", - openapi_tags: Annotated[ - Optional[list[dict[str, Any]]], - Doc( - """ - A list of tags used by OpenAPI, these are the same `tags` you can set - in the *path operations*, like: - - * `@app.get("/users/", tags=["users"])` - * `@app.get("/items/", tags=["items"])` - - The order of the tags can be used to specify the order shown in - tools like Swagger UI, used in the automatic path `/docs`. - - It's not required to specify all the tags used. - - The tags that are not declared MAY be organized randomly or based - on the tools' logic. Each tag name in the list MUST be unique. - - The value of each item is a `dict` containing: - - * `name`: The name of the tag. - * `description`: A short description of the tag. - [CommonMark syntax](https://commonmark.org/) MAY be used for rich - text representation. - * `externalDocs`: Additional external documentation for this tag. If - provided, it would contain a `dict` with: - * `description`: A short description of the target documentation. - [CommonMark syntax](https://commonmark.org/) MAY be used for - rich text representation. - * `url`: The URL for the target documentation. Value MUST be in - the form of a URL. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags). - - **Example** - - ```python - from fastapi import FastAPI - - tags_metadata = [ - { - "name": "users", - "description": "Operations with users. The **login** logic is also here.", - }, - { - "name": "items", - "description": "Manage items. So _fancy_ they have their own docs.", - "externalDocs": { - "description": "Items external docs", - "url": "https://fastapi.tiangolo.com/", - }, - }, - ] - - app = FastAPI(openapi_tags=tags_metadata) - ``` - """ - ), - ] = None, - servers: Annotated[ - Optional[list[dict[str, Union[str, Any]]]], - Doc( - """ - A `list` of `dict`s with connectivity information to a target server. - - You would use it, for example, if your application is served from - different domains and you want to use the same Swagger UI in the - browser to interact with each of them (instead of having multiple - browser tabs open). Or if you want to leave fixed the possible URLs. - - If the servers `list` is not provided, or is an empty `list`, the - `servers` property in the generated OpenAPI will be: - - * a `dict` with a `url` value of the application's mounting point - (`root_path`) if it's different from `/`. - * otherwise, the `servers` property will be omitted from the OpenAPI - schema. - - Each item in the `list` is a `dict` containing: - - * `url`: A URL to the target host. This URL supports Server Variables - and MAY be relative, to indicate that the host location is relative - to the location where the OpenAPI document is being served. Variable - substitutions will be made when a variable is named in `{`brackets`}`. - * `description`: An optional string describing the host designated by - the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for - rich text representation. - * `variables`: A `dict` between a variable name and its value. The value - is used for substitution in the server's URL template. - - Read more in the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI( - servers=[ - {"url": "https://stag.example.com", "description": "Staging environment"}, - {"url": "https://prod.example.com", "description": "Production environment"}, - ] - ) - ``` - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of global dependencies, they will be applied to each - *path operation*, including in sub-routers. - - Read more about it in the - [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/). - - **Example** - - ```python - from fastapi import Depends, FastAPI - - from .dependencies import func_dep_1, func_dep_2 - - app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)]) - ``` - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - - **Example** - - ```python - from fastapi import FastAPI - from fastapi.responses import ORJSONResponse - - app = FastAPI(default_response_class=ORJSONResponse) - ``` - """ - ), - ] = Default(JSONResponse), - redirect_slashes: Annotated[ - bool, - Doc( - """ - Whether to detect and redirect slashes in URLs when the client doesn't - use the same format. - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(redirect_slashes=True) # the default - - @app.get("/items/") - async def read_items(): - return [{"item_id": "Foo"}] - ``` - - With this app, if a client goes to `/items` (without a trailing slash), - they will be automatically redirected with an HTTP status code of 307 - to `/items/`. - """ - ), - ] = True, - docs_url: Annotated[ - Optional[str], - Doc( - """ - The path to the automatic interactive API documentation. - It is handled in the browser by Swagger UI. - - The default URL is `/docs`. You can disable it by setting it to `None`. - - If `openapi_url` is set to `None`, this will be automatically disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(docs_url="/documentation", redoc_url=None) - ``` - """ - ), - ] = "/docs", - redoc_url: Annotated[ - Optional[str], - Doc( - """ - The path to the alternative automatic interactive API documentation - provided by ReDoc. - - The default URL is `/redoc`. You can disable it by setting it to `None`. - - If `openapi_url` is set to `None`, this will be automatically disabled. - - Read more in the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(docs_url="/documentation", redoc_url="redocumentation") - ``` - """ - ), - ] = "/redoc", - swagger_ui_oauth2_redirect_url: Annotated[ - Optional[str], - Doc( - """ - The OAuth2 redirect endpoint for the Swagger UI. - - By default it is `/docs/oauth2-redirect`. - - This is only used if you use OAuth2 (with the "Authorize" button) - with Swagger UI. - """ - ), - ] = "/docs/oauth2-redirect", - swagger_ui_init_oauth: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - OAuth2 configuration for the Swagger UI, by default shown at `/docs`. - - Read more about the available configuration options in the - [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). - """ - ), - ] = None, - middleware: Annotated[ - Optional[Sequence[Middleware]], - Doc( - """ - List of middleware to be added when creating the application. - - In FastAPI you would normally do this with `app.add_middleware()` - instead. - - Read more in the - [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). - """ - ), - ] = None, - exception_handlers: Annotated[ - Optional[ - dict[ - Union[int, type[Exception]], - Callable[[Request, Any], Coroutine[Any, Any, Response]], - ] - ], - Doc( - """ - A dictionary with handlers for exceptions. - - In FastAPI, you would normally use the decorator - `@app.exception_handler()`. - - Read more in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - """ - ), - ] = None, - on_startup: Annotated[ - Optional[Sequence[Callable[[], Any]]], - Doc( - """ - A list of startup event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - on_shutdown: Annotated[ - Optional[Sequence[Callable[[], Any]]], - Doc( - """ - A list of shutdown event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - lifespan: Annotated[ - Optional[Lifespan[AppType]], - Doc( - """ - A `Lifespan` context manager handler. This replaces `startup` and - `shutdown` functions with a single context manager. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - terms_of_service: Annotated[ - Optional[str], - Doc( - """ - A URL to the Terms of Service for your API. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI(terms_of_service="http://example.com/terms/") - ``` - """ - ), - ] = None, - contact: Annotated[ - Optional[dict[str, Union[str, Any]]], - Doc( - """ - A dictionary with the contact information for the exposed API. - - It can contain several fields. - - * `name`: (`str`) The name of the contact person/organization. - * `url`: (`str`) A URL pointing to the contact information. MUST be in - the format of a URL. - * `email`: (`str`) The email address of the contact person/organization. - MUST be in the format of an email address. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI( - contact={ - "name": "Deadpoolio the Amazing", - "url": "http://x-force.example.com/contact/", - "email": "dp@x-force.example.com", - } - ) - ``` - """ - ), - ] = None, - license_info: Annotated[ - Optional[dict[str, Union[str, Any]]], - Doc( - """ - A dictionary with the license information for the exposed API. - - It can contain several fields. - - * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The - license name used for the API. - * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression - for the API. The `identifier` field is mutually exclusive of the `url` - field. Available since OpenAPI 3.1.0, FastAPI 0.99.0. - * `url`: (`str`) A URL to the license used for the API. This MUST be - the format of a URL. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more at the - [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). - - **Example** - - ```python - app = FastAPI( - license_info={ - "name": "Apache 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0.html", - } - ) - ``` - """ - ), - ] = None, - openapi_prefix: Annotated[ - str, - Doc( - """ - A URL prefix for the OpenAPI URL. - """ - ), - deprecated( - """ - "openapi_prefix" has been deprecated in favor of "root_path", which - follows more closely the ASGI standard, is simpler, and more - automatic. - """ - ), - ] = "", - root_path: Annotated[ - str, - Doc( - """ - A path prefix handled by a proxy that is not seen by the application - but is seen by external clients, which affects things like Swagger UI. - - Read more about it at the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(root_path="/api/v1") - ``` - """ - ), - ] = "", - root_path_in_servers: Annotated[ - bool, - Doc( - """ - To disable automatically generating the URLs in the `servers` field - in the autogenerated OpenAPI using the `root_path`. - - Read more about it in the - [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root_path). - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI(root_path_in_servers=False) - ``` - """ - ), - ] = True, - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - OpenAPI callbacks that should apply to all *path operations*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - webhooks: Annotated[ - Optional[routing.APIRouter], - Doc( - """ - Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't - depend on specific *path operations*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0. - - Read more about it in the - [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark all *path operations* as deprecated. You probably don't need it, - but it's available. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) all the *path operations* in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - swagger_ui_parameters: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Parameters to configure Swagger UI, the autogenerated interactive API - documentation (by default at `/docs`). - - Read more about it in the - [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - separate_input_output_schemas: Annotated[ - bool, - Doc( - """ - Whether to generate separate OpenAPI schemas for request body and - response body when the results would be more precise. - - This is particularly useful when automatically generating clients. - - For example, if you have a model like: - - ```python - from pydantic import BaseModel - - class Item(BaseModel): - name: str - tags: list[str] = [] - ``` - - When `Item` is used for input, a request body, `tags` is not required, - the client doesn't have to provide it. - - But when using `Item` for output, for a response body, `tags` is always - available because it has a default value, even if it's just an empty - list. So, the client should be able to always expect it. - - In this case, there would be two different schemas, one for input and - another one for output. - """ - ), - ] = True, - openapi_external_docs: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - This field allows you to provide additional external documentation links. - If provided, it must be a dictionary containing: - - * `description`: A brief description of the external documentation. - * `url`: The URL pointing to the external documentation. The value **MUST** - be a valid URL format. - - **Example**: - - ```python - from fastapi import FastAPI - - external_docs = { - "description": "Detailed API Reference", - "url": "https://example.com/api-docs", - } - - app = FastAPI(openapi_external_docs=external_docs) - ``` - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Extra keyword arguments to be stored in the app, not used by FastAPI - anywhere. - """ - ), - ], - ) -> None: - self.debug = debug - self.title = title - self.summary = summary - self.description = description - self.version = version - self.terms_of_service = terms_of_service - self.contact = contact - self.license_info = license_info - self.openapi_url = openapi_url - self.openapi_tags = openapi_tags - self.root_path_in_servers = root_path_in_servers - self.docs_url = docs_url - self.redoc_url = redoc_url - self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url - self.swagger_ui_init_oauth = swagger_ui_init_oauth - self.swagger_ui_parameters = swagger_ui_parameters - self.servers = servers or [] - self.separate_input_output_schemas = separate_input_output_schemas - self.openapi_external_docs = openapi_external_docs - self.extra = extra - self.openapi_version: Annotated[ - str, - Doc( - """ - The version string of OpenAPI. - - FastAPI will generate OpenAPI version 3.1.0, and will output that as - the OpenAPI version. But some tools, even though they might be - compatible with OpenAPI 3.1.0, might not recognize it as a valid. - - So you could override this value to trick those tools into using - the generated OpenAPI. Have in mind that this is a hack. But if you - avoid using features added in OpenAPI 3.1.0, it might work for your - use case. - - This is not passed as a parameter to the `FastAPI` class to avoid - giving the false idea that FastAPI would generate a different OpenAPI - schema. It is only available as an attribute. - - **Example** - - ```python - from fastapi import FastAPI - - app = FastAPI() - - app.openapi_version = "3.0.2" - ``` - """ - ), - ] = "3.1.0" - self.openapi_schema: Optional[dict[str, Any]] = None - if self.openapi_url: - assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" - assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" - # TODO: remove when discarding the openapi_prefix parameter - if openapi_prefix: - logger.warning( - '"openapi_prefix" has been deprecated in favor of "root_path", which ' - "follows more closely the ASGI standard, is simpler, and more " - "automatic. Check the docs at " - "https://fastapi.tiangolo.com/advanced/sub-applications/" - ) - self.webhooks: Annotated[ - routing.APIRouter, - Doc( - """ - The `app.webhooks` attribute is an `APIRouter` with the *path - operations* that will be used just for documentation of webhooks. - - Read more about it in the - [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). - """ - ), - ] = webhooks or routing.APIRouter() - self.root_path = root_path or openapi_prefix - self.state: Annotated[ - State, - Doc( - """ - A state object for the application. This is the same object for the - entire application, it doesn't change from request to request. - - You normally wouldn't use this in FastAPI, for most of the cases you - would instead use FastAPI dependencies. - - This is simply inherited from Starlette. - - Read more about it in the - [Starlette docs for Applications](https://www.starlette.dev/applications/#storing-state-on-the-app-instance). - """ - ), - ] = State() - self.dependency_overrides: Annotated[ - dict[Callable[..., Any], Callable[..., Any]], - Doc( - """ - A dictionary with overrides for the dependencies. - - Each key is the original dependency callable, and the value is the - actual dependency that should be called. - - This is for testing, to replace expensive dependencies with testing - versions. - - Read more about it in the - [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/). - """ - ), - ] = {} - self.router: routing.APIRouter = routing.APIRouter( - routes=routes, - redirect_slashes=redirect_slashes, - dependency_overrides_provider=self, - on_startup=on_startup, - on_shutdown=on_shutdown, - lifespan=lifespan, - default_response_class=default_response_class, - dependencies=dependencies, - callbacks=callbacks, - deprecated=deprecated, - include_in_schema=include_in_schema, - responses=responses, - generate_unique_id_function=generate_unique_id_function, - ) - self.exception_handlers: dict[ - Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]] - ] = {} if exception_handlers is None else dict(exception_handlers) - self.exception_handlers.setdefault(HTTPException, http_exception_handler) - self.exception_handlers.setdefault( - RequestValidationError, request_validation_exception_handler - ) - self.exception_handlers.setdefault( - WebSocketRequestValidationError, - # Starlette still has incorrect type specification for the handlers - websocket_request_validation_exception_handler, # type: ignore - ) - - self.user_middleware: list[Middleware] = ( - [] if middleware is None else list(middleware) - ) - self.middleware_stack: Union[ASGIApp, None] = None - self.setup() - - def build_middleware_stack(self) -> ASGIApp: - # Duplicate/override from Starlette to add AsyncExitStackMiddleware - # inside of ExceptionMiddleware, inside of custom user middlewares - debug = self.debug - error_handler = None - exception_handlers: dict[Any, ExceptionHandler] = {} - - for key, value in self.exception_handlers.items(): - if key in (500, Exception): - error_handler = value - else: - exception_handlers[key] = value - - middleware = ( - [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)] - + self.user_middleware - + [ - Middleware( - ExceptionMiddleware, handlers=exception_handlers, debug=debug - ), - # Add FastAPI-specific AsyncExitStackMiddleware for closing files. - # Before this was also used for closing dependencies with yield but - # those now have their own AsyncExitStack, to properly support - # streaming responses while keeping compatibility with the previous - # versions (as of writing 0.117.1) that allowed doing - # except HTTPException inside a dependency with yield. - # This needs to happen after user middlewares because those create a - # new contextvars context copy by using a new AnyIO task group. - # This AsyncExitStack preserves the context for contextvars, not - # strictly necessary for closing files but it was one of the original - # intentions. - # If the AsyncExitStack lived outside of the custom middlewares and - # contextvars were set, for example in a dependency with 'yield' - # in that internal contextvars context, the values would not be - # available in the outer context of the AsyncExitStack. - # By placing the middleware and the AsyncExitStack here, inside all - # user middlewares, the same context is used. - # This is currently not needed, only for closing files, but used to be - # important when dependencies with yield were closed here. - Middleware(AsyncExitStackMiddleware), - ] - ) - - app = self.router - for cls, args, kwargs in reversed(middleware): - app = cls(app, *args, **kwargs) - return app - - def openapi(self) -> dict[str, Any]: - """ - Generate the OpenAPI schema of the application. This is called by FastAPI - internally. - - The first time it is called it stores the result in the attribute - `app.openapi_schema`, and next times it is called, it just returns that same - result. To avoid the cost of generating the schema every time. - - If you need to modify the generated OpenAPI schema, you could modify it. - - Read more in the - [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/). - """ - if not self.openapi_schema: - self.openapi_schema = get_openapi( - title=self.title, - version=self.version, - openapi_version=self.openapi_version, - summary=self.summary, - description=self.description, - terms_of_service=self.terms_of_service, - contact=self.contact, - license_info=self.license_info, - routes=self.routes, - webhooks=self.webhooks.routes, - tags=self.openapi_tags, - servers=self.servers, - separate_input_output_schemas=self.separate_input_output_schemas, - external_docs=self.openapi_external_docs, - ) - return self.openapi_schema - - def setup(self) -> None: - if self.openapi_url: - urls = (server_data.get("url") for server_data in self.servers) - server_urls = {url for url in urls if url} - - async def openapi(req: Request) -> JSONResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - if root_path not in server_urls: - if root_path and self.root_path_in_servers: - self.servers.insert(0, {"url": root_path}) - server_urls.add(root_path) - return JSONResponse(self.openapi()) - - self.add_route(self.openapi_url, openapi, include_in_schema=False) - if self.openapi_url and self.docs_url: - - async def swagger_ui_html(req: Request) -> HTMLResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - openapi_url = root_path + self.openapi_url - oauth2_redirect_url = self.swagger_ui_oauth2_redirect_url - if oauth2_redirect_url: - oauth2_redirect_url = root_path + oauth2_redirect_url - return get_swagger_ui_html( - openapi_url=openapi_url, - title=f"{self.title} - Swagger UI", - oauth2_redirect_url=oauth2_redirect_url, - init_oauth=self.swagger_ui_init_oauth, - swagger_ui_parameters=self.swagger_ui_parameters, - ) - - self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False) - - if self.swagger_ui_oauth2_redirect_url: - - async def swagger_ui_redirect(req: Request) -> HTMLResponse: - return get_swagger_ui_oauth2_redirect_html() - - self.add_route( - self.swagger_ui_oauth2_redirect_url, - swagger_ui_redirect, - include_in_schema=False, - ) - if self.openapi_url and self.redoc_url: - - async def redoc_html(req: Request) -> HTMLResponse: - root_path = req.scope.get("root_path", "").rstrip("/") - openapi_url = root_path + self.openapi_url - return get_redoc_html( - openapi_url=openapi_url, title=f"{self.title} - ReDoc" - ) - - self.add_route(self.redoc_url, redoc_html, include_in_schema=False) - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - if self.root_path: - scope["root_path"] = self.root_path - await super().__call__(scope, receive, send) - - def add_api_route( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - name: Optional[str] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), - ) -> None: - self.router.add_api_route( - path, - endpoint=endpoint, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def api_route( - self, - path: str, - *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] = Default(JSONResponse), - name: Optional[str] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.router.add_api_route( - path, - func, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - return func - - return decorator - - def add_api_websocket_route( - self, - path: str, - endpoint: Callable[..., Any], - name: Optional[str] = None, - *, - dependencies: Optional[Sequence[Depends]] = None, - ) -> None: - self.router.add_api_websocket_route( - path, - endpoint, - name=name, - dependencies=dependencies, - ) - - def websocket( - self, - path: Annotated[ - str, - Doc( - """ - WebSocket path. - """ - ), - ], - name: Annotated[ - Optional[str], - Doc( - """ - A name for the WebSocket. Only used internally. - """ - ), - ] = None, - *, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be used for this - WebSocket. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - """ - ), - ] = None, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Decorate a WebSocket function. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - **Example** - - ```python - from fastapi import FastAPI, WebSocket - - app = FastAPI() - - @app.websocket("/ws") - async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Message text was: {data}") - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route( - path, - func, - name=name, - dependencies=dependencies, - ) - return func - - return decorator - - def include_router( - self, - router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")], - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - - **Example** - - ```python - from fastapi import Depends, FastAPI - - from .dependencies import get_token_header - from .internal import admin - - app = FastAPI() - - app.include_router( - admin.router, - dependencies=[Depends(get_token_header)], - ) - ``` - """ - ), - ] = None, - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark all the *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - **Example** - - ```python - from fastapi import FastAPI - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - deprecated=True, - ) - ``` - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include (or not) all the *path operations* in this router in the - generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - **Example** - - ```python - from fastapi import FastAPI - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - include_in_schema=False, - ) - ``` - """ - ), - ] = True, - default_response_class: Annotated[ - type[Response], - Doc( - """ - Default response class to be used for the *path operations* in this - router. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - - **Example** - - ```python - from fastapi import FastAPI - from fastapi.responses import ORJSONResponse - - from .internal import old_api - - app = FastAPI() - - app.include_router( - old_api.router, - default_response_class=ORJSONResponse, - ) - ``` - """ - ), - ] = Default(JSONResponse), - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> None: - """ - Include an `APIRouter` in the same app. - - Read more about it in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import FastAPI - - from .users import users_router - - app = FastAPI() - - app.include_router(users_router) - ``` - """ - self.router.include_router( - router, - prefix=prefix, - tags=tags, - dependencies=dependencies, - responses=responses, - deprecated=deprecated, - include_in_schema=include_in_schema, - default_response_class=default_response_class, - callbacks=callbacks, - generate_unique_id_function=generate_unique_id_function, - ) - - def get( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP GET operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.get("/items/") - def read_items(): - return [{"name": "Empanada"}, {"name": "Arepa"}] - ``` - """ - return self.router.get( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def put( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PUT operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.put("/items/{item_id}") - def replace_item(item_id: str, item: Item): - return {"message": "Item replaced", "id": item_id} - ``` - """ - return self.router.put( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def post( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP POST operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.post("/items/") - def create_item(item: Item): - return {"message": "Item created"} - ``` - """ - return self.router.post( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def delete( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP DELETE operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.delete("/items/{item_id}") - def delete_item(item_id: str): - return {"message": "Item deleted"} - ``` - """ - return self.router.delete( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def options( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP OPTIONS operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.options("/items/") - def get_item_options(): - return {"additions": ["Aji", "Guacamole"]} - ``` - """ - return self.router.options( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def head( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP HEAD operation. - - ## Example - - ```python - from fastapi import FastAPI, Response - - app = FastAPI() - - @app.head("/items/", status_code=204) - def get_items_headers(response: Response): - response.headers["X-Cat-Dog"] = "Alone in the world" - ``` - """ - return self.router.head( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def patch( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PATCH operation. - - ## Example - - ```python - from fastapi import FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - - @app.patch("/items/") - def update_item(item: Item): - return {"message": "Item updated in place"} - ``` - """ - return self.router.patch( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def trace( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[routing.APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP TRACE operation. - - ## Example - - ```python - from fastapi import FastAPI - - app = FastAPI() - - @app.trace("/items/{item_id}") - def trace_item(item_id: str): - return None - ``` - """ - return self.router.trace( - path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def websocket_route( - self, path: str, name: Union[str, None] = None - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.router.add_websocket_route(path, func, name=name) - return func - - return decorator - - @deprecated( - """ - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - """ - ) - def on_event( - self, - event_type: Annotated[ - str, - Doc( - """ - The type of event. `startup` or `shutdown`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an event handler for the application. - - `on_event` is deprecated, use `lifespan` event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). - """ - return self.router.on_event(event_type) - - def middleware( - self, - middleware_type: Annotated[ - str, - Doc( - """ - The type of middleware. Currently only supports `http`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a middleware to the application. - - Read more about it in the - [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). - - ## Example - - ```python - import time - from typing import Awaitable, Callable - - from fastapi import FastAPI, Request, Response - - app = FastAPI() - - - @app.middleware("http") - async def add_process_time_header( - request: Request, call_next: Callable[[Request], Awaitable[Response]] - ) -> Response: - start_time = time.time() - response = await call_next(request) - process_time = time.time() - start_time - response.headers["X-Process-Time"] = str(process_time) - return response - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_middleware(BaseHTTPMiddleware, dispatch=func) - return func - - return decorator - - def exception_handler( - self, - exc_class_or_status_code: Annotated[ - Union[int, type[Exception]], - Doc( - """ - The Exception class this would handle, or a status code. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an exception handler to the app. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - - ## Example - - ```python - from fastapi import FastAPI, Request - from fastapi.responses import JSONResponse - - - class UnicornException(Exception): - def __init__(self, name: str): - self.name = name - - - app = FastAPI() - - - @app.exception_handler(UnicornException) - async def unicorn_exception_handler(request: Request, exc: UnicornException): - return JSONResponse( - status_code=418, - content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, - ) - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_exception_handler(exc_class_or_status_code, func) - return func - - return decorator diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/background.py b/backend/venv39/lib/python3.9/site-packages/fastapi/background.py deleted file mode 100644 index 20803ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/background.py +++ /dev/null @@ -1,60 +0,0 @@ -from typing import Annotated, Any, Callable - -from annotated_doc import Doc -from starlette.background import BackgroundTasks as StarletteBackgroundTasks -from typing_extensions import ParamSpec - -P = ParamSpec("P") - - -class BackgroundTasks(StarletteBackgroundTasks): - """ - A collection of background tasks that will be called after a response has been - sent to the client. - - Read more about it in the - [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). - - ## Example - - ```python - from fastapi import BackgroundTasks, FastAPI - - app = FastAPI() - - - def write_notification(email: str, message=""): - with open("log.txt", mode="w") as email_file: - content = f"notification for {email}: {message}" - email_file.write(content) - - - @app.post("/send-notification/{email}") - async def send_notification(email: str, background_tasks: BackgroundTasks): - background_tasks.add_task(write_notification, email, message="some notification") - return {"message": "Notification sent in the background"} - ``` - """ - - def add_task( - self, - func: Annotated[ - Callable[P, Any], - Doc( - """ - The function to call after the response is sent. - - It can be a regular `def` function or an `async def` function. - """ - ), - ], - *args: P.args, - **kwargs: P.kwargs, - ) -> None: - """ - Add a function to be called in the background after the response is sent. - - Read more about it in the - [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). - """ - return super().add_task(func, *args, **kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/cli.py b/backend/venv39/lib/python3.9/site-packages/fastapi/cli.py deleted file mode 100644 index 8d3301e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/cli.py +++ /dev/null @@ -1,13 +0,0 @@ -try: - from fastapi_cli.cli import main as cli_main - -except ImportError: # pragma: no cover - cli_main = None # type: ignore - - -def main() -> None: - if not cli_main: # type: ignore[truthy-function] - message = 'To use the fastapi command, please install "fastapi[standard]":\n\n\tpip install "fastapi[standard]"\n' - print(message) - raise RuntimeError(message) # noqa: B904 - cli_main() diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/concurrency.py b/backend/venv39/lib/python3.9/site-packages/fastapi/concurrency.py deleted file mode 100644 index 76a5a2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/concurrency.py +++ /dev/null @@ -1,41 +0,0 @@ -from collections.abc import AsyncGenerator -from contextlib import AbstractContextManager -from contextlib import asynccontextmanager as asynccontextmanager -from typing import TypeVar - -import anyio.to_thread -from anyio import CapacityLimiter -from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa -from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa -from starlette.concurrency import ( # noqa - run_until_first_complete as run_until_first_complete, -) - -_T = TypeVar("_T") - - -@asynccontextmanager -async def contextmanager_in_threadpool( - cm: AbstractContextManager[_T], -) -> AsyncGenerator[_T, None]: - # blocking __exit__ from running waiting on a free thread - # can create race conditions/deadlocks if the context manager itself - # has its own internal pool (e.g. a database connection pool) - # to avoid this we let __exit__ run without a capacity limit - # since we're creating a new limiter for each call, any non-zero limit - # works (1 is arbitrary) - exit_limiter = CapacityLimiter(1) - try: - yield await run_in_threadpool(cm.__enter__) - except Exception as e: - ok = bool( - await anyio.to_thread.run_sync( - cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter - ) - ) - if not ok: - raise e - else: - await anyio.to_thread.run_sync( - cm.__exit__, None, None, None, limiter=exit_limiter - ) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/datastructures.py b/backend/venv39/lib/python3.9/site-packages/fastapi/datastructures.py deleted file mode 100644 index 2bf5fdb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/datastructures.py +++ /dev/null @@ -1,183 +0,0 @@ -from collections.abc import Mapping -from typing import ( - Annotated, - Any, - BinaryIO, - Callable, - Optional, - TypeVar, - cast, -) - -from annotated_doc import Doc -from pydantic import GetJsonSchemaHandler -from starlette.datastructures import URL as URL # noqa: F401 -from starlette.datastructures import Address as Address # noqa: F401 -from starlette.datastructures import FormData as FormData # noqa: F401 -from starlette.datastructures import Headers as Headers # noqa: F401 -from starlette.datastructures import QueryParams as QueryParams # noqa: F401 -from starlette.datastructures import State as State # noqa: F401 -from starlette.datastructures import UploadFile as StarletteUploadFile - - -class UploadFile(StarletteUploadFile): - """ - A file uploaded in a request. - - Define it as a *path operation function* (or dependency) parameter. - - If you are using a regular `def` function, you can use the `upload_file.file` - attribute to access the raw standard Python file (blocking, not async), useful and - needed for non-async code. - - Read more about it in the - [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import FastAPI, File, UploadFile - - app = FastAPI() - - - @app.post("/files/") - async def create_file(file: Annotated[bytes, File()]): - return {"file_size": len(file)} - - - @app.post("/uploadfile/") - async def create_upload_file(file: UploadFile): - return {"filename": file.filename} - ``` - """ - - file: Annotated[ - BinaryIO, - Doc("The standard Python file object (non-async)."), - ] - filename: Annotated[Optional[str], Doc("The original file name.")] - size: Annotated[Optional[int], Doc("The size of the file in bytes.")] - headers: Annotated[Headers, Doc("The headers of the request.")] - content_type: Annotated[ - Optional[str], Doc("The content type of the request, from the headers.") - ] - - async def write( - self, - data: Annotated[ - bytes, - Doc( - """ - The bytes to write to the file. - """ - ), - ], - ) -> None: - """ - Write some bytes to the file. - - You normally wouldn't use this from a file you read in a request. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().write(data) - - async def read( - self, - size: Annotated[ - int, - Doc( - """ - The number of bytes to read from the file. - """ - ), - ] = -1, - ) -> bytes: - """ - Read some bytes from the file. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().read(size) - - async def seek( - self, - offset: Annotated[ - int, - Doc( - """ - The position in bytes to seek to in the file. - """ - ), - ], - ) -> None: - """ - Move to a position in the file. - - Any next read or write will be done from that position. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().seek(offset) - - async def close(self) -> None: - """ - Close the file. - - To be awaitable, compatible with async, this is run in threadpool. - """ - return await super().close() - - @classmethod - def _validate(cls, __input_value: Any, _: Any) -> "UploadFile": - if not isinstance(__input_value, StarletteUploadFile): - raise ValueError(f"Expected UploadFile, received: {type(__input_value)}") - return cast(UploadFile, __input_value) - - @classmethod - def __get_pydantic_json_schema__( - cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler - ) -> dict[str, Any]: - return {"type": "string", "format": "binary"} - - @classmethod - def __get_pydantic_core_schema__( - cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]] - ) -> Mapping[str, Any]: - from ._compat.v2 import with_info_plain_validator_function - - return with_info_plain_validator_function(cls._validate) - - -class DefaultPlaceholder: - """ - You shouldn't use this class directly. - - It's used internally to recognize when a default value has been overwritten, even - if the overridden default value was truthy. - """ - - def __init__(self, value: Any): - self.value = value - - def __bool__(self) -> bool: - return bool(self.value) - - def __eq__(self, o: object) -> bool: - return isinstance(o, DefaultPlaceholder) and o.value == self.value - - -DefaultType = TypeVar("DefaultType") - - -def Default(value: DefaultType) -> DefaultType: - """ - You shouldn't use this function directly. - - It's used internally to recognize when a default value has been overwritten, even - if the overridden default value was truthy. - """ - return DefaultPlaceholder(value) # type: ignore diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/models.py b/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/models.py deleted file mode 100644 index 5839232..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/models.py +++ /dev/null @@ -1,193 +0,0 @@ -import inspect -import sys -from dataclasses import dataclass, field -from functools import cached_property, partial -from typing import Any, Callable, Optional, Union - -from fastapi._compat import ModelField -from fastapi.security.base import SecurityBase -from fastapi.types import DependencyCacheKey -from typing_extensions import Literal - -if sys.version_info >= (3, 13): # pragma: no cover - from inspect import iscoroutinefunction -else: # pragma: no cover - from asyncio import iscoroutinefunction - - -def _unwrapped_call(call: Optional[Callable[..., Any]]) -> Any: - if call is None: - return call # pragma: no cover - unwrapped = inspect.unwrap(_impartial(call)) - return unwrapped - - -def _impartial(func: Callable[..., Any]) -> Callable[..., Any]: - while isinstance(func, partial): - func = func.func - return func - - -@dataclass -class Dependant: - path_params: list[ModelField] = field(default_factory=list) - query_params: list[ModelField] = field(default_factory=list) - header_params: list[ModelField] = field(default_factory=list) - cookie_params: list[ModelField] = field(default_factory=list) - body_params: list[ModelField] = field(default_factory=list) - dependencies: list["Dependant"] = field(default_factory=list) - name: Optional[str] = None - call: Optional[Callable[..., Any]] = None - request_param_name: Optional[str] = None - websocket_param_name: Optional[str] = None - http_connection_param_name: Optional[str] = None - response_param_name: Optional[str] = None - background_tasks_param_name: Optional[str] = None - security_scopes_param_name: Optional[str] = None - own_oauth_scopes: Optional[list[str]] = None - parent_oauth_scopes: Optional[list[str]] = None - use_cache: bool = True - path: Optional[str] = None - scope: Union[Literal["function", "request"], None] = None - - @cached_property - def oauth_scopes(self) -> list[str]: - scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else [] - # This doesn't use a set to preserve order, just in case - for scope in self.own_oauth_scopes or []: - if scope not in scopes: - scopes.append(scope) - return scopes - - @cached_property - def cache_key(self) -> DependencyCacheKey: - scopes_for_cache = ( - tuple(sorted(set(self.oauth_scopes or []))) if self._uses_scopes else () - ) - return ( - self.call, - scopes_for_cache, - self.computed_scope or "", - ) - - @cached_property - def _uses_scopes(self) -> bool: - if self.own_oauth_scopes: - return True - if self.security_scopes_param_name is not None: - return True - if self._is_security_scheme: - return True - for sub_dep in self.dependencies: - if sub_dep._uses_scopes: - return True - return False - - @cached_property - def _is_security_scheme(self) -> bool: - if self.call is None: - return False # pragma: no cover - unwrapped = _unwrapped_call(self.call) - return isinstance(unwrapped, SecurityBase) - - # Mainly to get the type of SecurityBase, but it's the same self.call - @cached_property - def _security_scheme(self) -> SecurityBase: - unwrapped = _unwrapped_call(self.call) - assert isinstance(unwrapped, SecurityBase) - return unwrapped - - @cached_property - def _security_dependencies(self) -> list["Dependant"]: - security_deps = [dep for dep in self.dependencies if dep._is_security_scheme] - return security_deps - - @cached_property - def is_gen_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(self.call) - ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(dunder_call) - ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if inspect.isgeneratorfunction( - _impartial(dunder_unwrapped_call) - ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def is_async_gen_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(self.call) - ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(dunder_call) - ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if inspect.isasyncgenfunction( - _impartial(dunder_unwrapped_call) - ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def is_coroutine_callable(self) -> bool: - if self.call is None: - return False # pragma: no cover - if inspect.isroutine(_impartial(self.call)) and iscoroutinefunction( - _impartial(self.call) - ): - return True - if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction( - _unwrapped_call(self.call) - ): - return True - if inspect.isclass(_unwrapped_call(self.call)): - return False - dunder_call = getattr(_impartial(self.call), "__call__", None) # noqa: B004 - if dunder_call is None: - return False # pragma: no cover - if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction( - _unwrapped_call(dunder_call) - ): - return True - dunder_unwrapped_call = getattr(_unwrapped_call(self.call), "__call__", None) # noqa: B004 - if dunder_unwrapped_call is None: - return False # pragma: no cover - if iscoroutinefunction( - _impartial(dunder_unwrapped_call) - ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call)): - return True - return False - - @cached_property - def computed_scope(self) -> Union[str, None]: - if self.scope: - return self.scope - if self.is_gen_callable or self.is_async_gen_callable: - return "request" - return None diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/utils.py b/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/utils.py deleted file mode 100644 index 45e1ff3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/dependencies/utils.py +++ /dev/null @@ -1,1021 +0,0 @@ -import dataclasses -import inspect -import sys -from collections.abc import Coroutine, Mapping, Sequence -from contextlib import AsyncExitStack, contextmanager -from copy import copy, deepcopy -from dataclasses import dataclass -from typing import ( - Annotated, - Any, - Callable, - ForwardRef, - Optional, - Union, - cast, -) - -import anyio -from fastapi import params -from fastapi._compat import ( - ModelField, - RequiredParam, - Undefined, - _regenerate_error_with_loc, - copy_field_info, - create_body_model, - evaluate_forwardref, - field_annotation_is_scalar, - get_cached_model_fields, - get_missing_field_error, - is_bytes_field, - is_bytes_sequence_field, - is_scalar_field, - is_scalar_sequence_field, - is_sequence_field, - is_uploadfile_or_nonable_uploadfile_annotation, - is_uploadfile_sequence_annotation, - lenient_issubclass, - sequence_types, - serialize_sequence_value, - value_is_sequence, -) -from fastapi.background import BackgroundTasks -from fastapi.concurrency import ( - asynccontextmanager, - contextmanager_in_threadpool, -) -from fastapi.dependencies.models import Dependant -from fastapi.exceptions import DependencyScopeError -from fastapi.logger import logger -from fastapi.security.oauth2 import SecurityScopes -from fastapi.types import DependencyCacheKey -from fastapi.utils import create_model_field, get_path_param_names -from pydantic import BaseModel -from pydantic.fields import FieldInfo -from starlette.background import BackgroundTasks as StarletteBackgroundTasks -from starlette.concurrency import run_in_threadpool -from starlette.datastructures import ( - FormData, - Headers, - ImmutableMultiDict, - QueryParams, - UploadFile, -) -from starlette.requests import HTTPConnection, Request -from starlette.responses import Response -from starlette.websockets import WebSocket -from typing_extensions import Literal, get_args, get_origin - -multipart_not_installed_error = ( - 'Form data requires "python-multipart" to be installed. \n' - 'You can install "python-multipart" with: \n\n' - "pip install python-multipart\n" -) -multipart_incorrect_install_error = ( - 'Form data requires "python-multipart" to be installed. ' - 'It seems you installed "multipart" instead. \n' - 'You can remove "multipart" with: \n\n' - "pip uninstall multipart\n\n" - 'And then install "python-multipart" with: \n\n' - "pip install python-multipart\n" -) - - -def ensure_multipart_is_installed() -> None: - try: - from python_multipart import __version__ - - # Import an attribute that can be mocked/deleted in testing - assert __version__ > "0.0.12" - except (ImportError, AssertionError): - try: - # __version__ is available in both multiparts, and can be mocked - from multipart import __version__ # type: ignore[no-redef,import-untyped] - - assert __version__ - try: - # parse_options_header is only available in the right multipart - from multipart.multipart import ( # type: ignore[import-untyped] - parse_options_header, - ) - - assert parse_options_header - except ImportError: - logger.error(multipart_incorrect_install_error) - raise RuntimeError(multipart_incorrect_install_error) from None - except ImportError: - logger.error(multipart_not_installed_error) - raise RuntimeError(multipart_not_installed_error) from None - - -def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant: - assert callable(depends.dependency), ( - "A parameter-less dependency must have a callable dependency" - ) - own_oauth_scopes: list[str] = [] - if isinstance(depends, params.Security) and depends.scopes: - own_oauth_scopes.extend(depends.scopes) - return get_dependant( - path=path, - call=depends.dependency, - scope=depends.scope, - own_oauth_scopes=own_oauth_scopes, - ) - - -def get_flat_dependant( - dependant: Dependant, - *, - skip_repeats: bool = False, - visited: Optional[list[DependencyCacheKey]] = None, - parent_oauth_scopes: Optional[list[str]] = None, -) -> Dependant: - if visited is None: - visited = [] - visited.append(dependant.cache_key) - use_parent_oauth_scopes = (parent_oauth_scopes or []) + ( - dependant.oauth_scopes or [] - ) - - flat_dependant = Dependant( - path_params=dependant.path_params.copy(), - query_params=dependant.query_params.copy(), - header_params=dependant.header_params.copy(), - cookie_params=dependant.cookie_params.copy(), - body_params=dependant.body_params.copy(), - name=dependant.name, - call=dependant.call, - request_param_name=dependant.request_param_name, - websocket_param_name=dependant.websocket_param_name, - http_connection_param_name=dependant.http_connection_param_name, - response_param_name=dependant.response_param_name, - background_tasks_param_name=dependant.background_tasks_param_name, - security_scopes_param_name=dependant.security_scopes_param_name, - own_oauth_scopes=dependant.own_oauth_scopes, - parent_oauth_scopes=use_parent_oauth_scopes, - use_cache=dependant.use_cache, - path=dependant.path, - scope=dependant.scope, - ) - for sub_dependant in dependant.dependencies: - if skip_repeats and sub_dependant.cache_key in visited: - continue - flat_sub = get_flat_dependant( - sub_dependant, - skip_repeats=skip_repeats, - visited=visited, - parent_oauth_scopes=flat_dependant.oauth_scopes, - ) - flat_dependant.dependencies.append(flat_sub) - flat_dependant.path_params.extend(flat_sub.path_params) - flat_dependant.query_params.extend(flat_sub.query_params) - flat_dependant.header_params.extend(flat_sub.header_params) - flat_dependant.cookie_params.extend(flat_sub.cookie_params) - flat_dependant.body_params.extend(flat_sub.body_params) - flat_dependant.dependencies.extend(flat_sub.dependencies) - - return flat_dependant - - -def _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]: - if not fields: - return fields - first_field = fields[0] - if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel): - fields_to_extract = get_cached_model_fields(first_field.type_) - return fields_to_extract - return fields - - -def get_flat_params(dependant: Dependant) -> list[ModelField]: - flat_dependant = get_flat_dependant(dependant, skip_repeats=True) - path_params = _get_flat_fields_from_params(flat_dependant.path_params) - query_params = _get_flat_fields_from_params(flat_dependant.query_params) - header_params = _get_flat_fields_from_params(flat_dependant.header_params) - cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params) - return path_params + query_params + header_params + cookie_params - - -def _get_signature(call: Callable[..., Any]) -> inspect.Signature: - if sys.version_info >= (3, 10): - try: - signature = inspect.signature(call, eval_str=True) - except NameError: - # Handle type annotations with if TYPE_CHECKING, not used by FastAPI - # e.g. dependency return types - signature = inspect.signature(call) - else: - signature = inspect.signature(call) - return signature - - -def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: - signature = _get_signature(call) - unwrapped = inspect.unwrap(call) - globalns = getattr(unwrapped, "__globals__", {}) - typed_params = [ - inspect.Parameter( - name=param.name, - kind=param.kind, - default=param.default, - annotation=get_typed_annotation(param.annotation, globalns), - ) - for param in signature.parameters.values() - ] - typed_signature = inspect.Signature(typed_params) - return typed_signature - - -def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any: - if isinstance(annotation, str): - annotation = ForwardRef(annotation) - annotation = evaluate_forwardref(annotation, globalns, globalns) - if annotation is type(None): - return None - return annotation - - -def get_typed_return_annotation(call: Callable[..., Any]) -> Any: - signature = _get_signature(call) - unwrapped = inspect.unwrap(call) - annotation = signature.return_annotation - - if annotation is inspect.Signature.empty: - return None - - globalns = getattr(unwrapped, "__globals__", {}) - return get_typed_annotation(annotation, globalns) - - -def get_dependant( - *, - path: str, - call: Callable[..., Any], - name: Optional[str] = None, - own_oauth_scopes: Optional[list[str]] = None, - parent_oauth_scopes: Optional[list[str]] = None, - use_cache: bool = True, - scope: Union[Literal["function", "request"], None] = None, -) -> Dependant: - dependant = Dependant( - call=call, - name=name, - path=path, - use_cache=use_cache, - scope=scope, - own_oauth_scopes=own_oauth_scopes, - parent_oauth_scopes=parent_oauth_scopes, - ) - current_scopes = (parent_oauth_scopes or []) + (own_oauth_scopes or []) - path_param_names = get_path_param_names(path) - endpoint_signature = get_typed_signature(call) - signature_params = endpoint_signature.parameters - for param_name, param in signature_params.items(): - is_path_param = param_name in path_param_names - param_details = analyze_param( - param_name=param_name, - annotation=param.annotation, - value=param.default, - is_path_param=is_path_param, - ) - if param_details.depends is not None: - assert param_details.depends.dependency - if ( - (dependant.is_gen_callable or dependant.is_async_gen_callable) - and dependant.computed_scope == "request" - and param_details.depends.scope == "function" - ): - assert dependant.call - raise DependencyScopeError( - f'The dependency "{dependant.call.__name__}" has a scope of ' - '"request", it cannot depend on dependencies with scope "function".' - ) - sub_own_oauth_scopes: list[str] = [] - if isinstance(param_details.depends, params.Security): - if param_details.depends.scopes: - sub_own_oauth_scopes = list(param_details.depends.scopes) - sub_dependant = get_dependant( - path=path, - call=param_details.depends.dependency, - name=param_name, - own_oauth_scopes=sub_own_oauth_scopes, - parent_oauth_scopes=current_scopes, - use_cache=param_details.depends.use_cache, - scope=param_details.depends.scope, - ) - dependant.dependencies.append(sub_dependant) - continue - if add_non_field_param_to_dependency( - param_name=param_name, - type_annotation=param_details.type_annotation, - dependant=dependant, - ): - assert param_details.field is None, ( - f"Cannot specify multiple FastAPI annotations for {param_name!r}" - ) - continue - assert param_details.field is not None - if isinstance(param_details.field.field_info, params.Body): - dependant.body_params.append(param_details.field) - else: - add_param_to_fields(field=param_details.field, dependant=dependant) - return dependant - - -def add_non_field_param_to_dependency( - *, param_name: str, type_annotation: Any, dependant: Dependant -) -> Optional[bool]: - if lenient_issubclass(type_annotation, Request): - dependant.request_param_name = param_name - return True - elif lenient_issubclass(type_annotation, WebSocket): - dependant.websocket_param_name = param_name - return True - elif lenient_issubclass(type_annotation, HTTPConnection): - dependant.http_connection_param_name = param_name - return True - elif lenient_issubclass(type_annotation, Response): - dependant.response_param_name = param_name - return True - elif lenient_issubclass(type_annotation, StarletteBackgroundTasks): - dependant.background_tasks_param_name = param_name - return True - elif lenient_issubclass(type_annotation, SecurityScopes): - dependant.security_scopes_param_name = param_name - return True - return None - - -@dataclass -class ParamDetails: - type_annotation: Any - depends: Optional[params.Depends] - field: Optional[ModelField] - - -def analyze_param( - *, - param_name: str, - annotation: Any, - value: Any, - is_path_param: bool, -) -> ParamDetails: - field_info = None - depends = None - type_annotation: Any = Any - use_annotation: Any = Any - if annotation is not inspect.Signature.empty: - use_annotation = annotation - type_annotation = annotation - # Extract Annotated info - if get_origin(use_annotation) is Annotated: - annotated_args = get_args(annotation) - type_annotation = annotated_args[0] - fastapi_annotations = [ - arg - for arg in annotated_args[1:] - if isinstance(arg, (FieldInfo, params.Depends)) - ] - fastapi_specific_annotations = [ - arg - for arg in fastapi_annotations - if isinstance( - arg, - ( - params.Param, - params.Body, - params.Depends, - ), - ) - ] - if fastapi_specific_annotations: - fastapi_annotation: Union[FieldInfo, params.Depends, None] = ( - fastapi_specific_annotations[-1] - ) - else: - fastapi_annotation = None - # Set default for Annotated FieldInfo - if isinstance(fastapi_annotation, FieldInfo): - # Copy `field_info` because we mutate `field_info.default` below. - field_info = copy_field_info( - field_info=fastapi_annotation, # type: ignore[arg-type] - annotation=use_annotation, - ) - assert ( - field_info.default == Undefined or field_info.default == RequiredParam - ), ( - f"`{field_info.__class__.__name__}` default value cannot be set in" - f" `Annotated` for {param_name!r}. Set the default value with `=` instead." - ) - if value is not inspect.Signature.empty: - assert not is_path_param, "Path parameters cannot have default values" - field_info.default = value - else: - field_info.default = RequiredParam - # Get Annotated Depends - elif isinstance(fastapi_annotation, params.Depends): - depends = fastapi_annotation - # Get Depends from default value - if isinstance(value, params.Depends): - assert depends is None, ( - "Cannot specify `Depends` in `Annotated` and default value" - f" together for {param_name!r}" - ) - assert field_info is None, ( - "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a" - f" default value together for {param_name!r}" - ) - depends = value - # Get FieldInfo from default value - elif isinstance(value, FieldInfo): - assert field_info is None, ( - "Cannot specify FastAPI annotations in `Annotated` and default value" - f" together for {param_name!r}" - ) - field_info = value # type: ignore[assignment] - if isinstance(field_info, FieldInfo): - field_info.annotation = type_annotation - - # Get Depends from type annotation - if depends is not None and depends.dependency is None: - # Copy `depends` before mutating it - depends = copy(depends) - depends = dataclasses.replace(depends, dependency=type_annotation) - - # Handle non-param type annotations like Request - if lenient_issubclass( - type_annotation, - ( - Request, - WebSocket, - HTTPConnection, - Response, - StarletteBackgroundTasks, - SecurityScopes, - ), - ): - assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}" - assert field_info is None, ( - f"Cannot specify FastAPI annotation for type {type_annotation!r}" - ) - # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value - elif field_info is None and depends is None: - default_value = value if value is not inspect.Signature.empty else RequiredParam - if is_path_param: - # We might check here that `default_value is RequiredParam`, but the fact is that the same - # parameter might sometimes be a path parameter and sometimes not. See - # `tests/test_infer_param_optionality.py` for an example. - field_info = params.Path(annotation=use_annotation) - elif is_uploadfile_or_nonable_uploadfile_annotation( - type_annotation - ) or is_uploadfile_sequence_annotation(type_annotation): - field_info = params.File(annotation=use_annotation, default=default_value) - elif not field_annotation_is_scalar(annotation=type_annotation): - field_info = params.Body(annotation=use_annotation, default=default_value) - else: - field_info = params.Query(annotation=use_annotation, default=default_value) - - field = None - # It's a field_info, not a dependency - if field_info is not None: - # Handle field_info.in_ - if is_path_param: - assert isinstance(field_info, params.Path), ( - f"Cannot use `{field_info.__class__.__name__}` for path param" - f" {param_name!r}" - ) - elif ( - isinstance(field_info, params.Param) - and getattr(field_info, "in_", None) is None - ): - field_info.in_ = params.ParamTypes.query - use_annotation_from_field_info = use_annotation - if isinstance(field_info, params.Form): - ensure_multipart_is_installed() - if not field_info.alias and getattr(field_info, "convert_underscores", None): - alias = param_name.replace("_", "-") - else: - alias = field_info.alias or param_name - field_info.alias = alias - field = create_model_field( - name=param_name, - type_=use_annotation_from_field_info, - default=field_info.default, - alias=alias, - required=field_info.default in (RequiredParam, Undefined), - field_info=field_info, - ) - if is_path_param: - assert is_scalar_field(field=field), ( - "Path params must be of one of the supported types" - ) - elif isinstance(field_info, params.Query): - assert ( - is_scalar_field(field) - or is_scalar_sequence_field(field) - or ( - lenient_issubclass(field.type_, BaseModel) - # For Pydantic v1 - and getattr(field, "shape", 1) == 1 - ) - ) - - return ParamDetails(type_annotation=type_annotation, depends=depends, field=field) - - -def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None: - field_info = field.field_info - field_info_in = getattr(field_info, "in_", None) - if field_info_in == params.ParamTypes.path: - dependant.path_params.append(field) - elif field_info_in == params.ParamTypes.query: - dependant.query_params.append(field) - elif field_info_in == params.ParamTypes.header: - dependant.header_params.append(field) - else: - assert field_info_in == params.ParamTypes.cookie, ( - f"non-body parameters must be in path, query, header or cookie: {field.name}" - ) - dependant.cookie_params.append(field) - - -async def _solve_generator( - *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any] -) -> Any: - assert dependant.call - if dependant.is_async_gen_callable: - cm = asynccontextmanager(dependant.call)(**sub_values) - elif dependant.is_gen_callable: - cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values)) - return await stack.enter_async_context(cm) - - -@dataclass -class SolvedDependency: - values: dict[str, Any] - errors: list[Any] - background_tasks: Optional[StarletteBackgroundTasks] - response: Response - dependency_cache: dict[DependencyCacheKey, Any] - - -async def solve_dependencies( - *, - request: Union[Request, WebSocket], - dependant: Dependant, - body: Optional[Union[dict[str, Any], FormData]] = None, - background_tasks: Optional[StarletteBackgroundTasks] = None, - response: Optional[Response] = None, - dependency_overrides_provider: Optional[Any] = None, - dependency_cache: Optional[dict[DependencyCacheKey, Any]] = None, - # TODO: remove this parameter later, no longer used, not removing it yet as some - # people might be monkey patching this function (although that's not supported) - async_exit_stack: AsyncExitStack, - embed_body_fields: bool, -) -> SolvedDependency: - request_astack = request.scope.get("fastapi_inner_astack") - assert isinstance(request_astack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - function_astack = request.scope.get("fastapi_function_astack") - assert isinstance(function_astack, AsyncExitStack), ( - "fastapi_function_astack not found in request scope" - ) - values: dict[str, Any] = {} - errors: list[Any] = [] - if response is None: - response = Response() - del response.headers["content-length"] - response.status_code = None # type: ignore - if dependency_cache is None: - dependency_cache = {} - for sub_dependant in dependant.dependencies: - sub_dependant.call = cast(Callable[..., Any], sub_dependant.call) - call = sub_dependant.call - use_sub_dependant = sub_dependant - if ( - dependency_overrides_provider - and dependency_overrides_provider.dependency_overrides - ): - original_call = sub_dependant.call - call = getattr( - dependency_overrides_provider, "dependency_overrides", {} - ).get(original_call, original_call) - use_path: str = sub_dependant.path # type: ignore - use_sub_dependant = get_dependant( - path=use_path, - call=call, - name=sub_dependant.name, - parent_oauth_scopes=sub_dependant.oauth_scopes, - scope=sub_dependant.scope, - ) - - solved_result = await solve_dependencies( - request=request, - dependant=use_sub_dependant, - body=body, - background_tasks=background_tasks, - response=response, - dependency_overrides_provider=dependency_overrides_provider, - dependency_cache=dependency_cache, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - background_tasks = solved_result.background_tasks - if solved_result.errors: - errors.extend(solved_result.errors) - continue - if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache: - solved = dependency_cache[sub_dependant.cache_key] - elif ( - use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable - ): - use_astack = request_astack - if sub_dependant.scope == "function": - use_astack = function_astack - solved = await _solve_generator( - dependant=use_sub_dependant, - stack=use_astack, - sub_values=solved_result.values, - ) - elif use_sub_dependant.is_coroutine_callable: - solved = await call(**solved_result.values) - else: - solved = await run_in_threadpool(call, **solved_result.values) - if sub_dependant.name is not None: - values[sub_dependant.name] = solved - if sub_dependant.cache_key not in dependency_cache: - dependency_cache[sub_dependant.cache_key] = solved - path_values, path_errors = request_params_to_args( - dependant.path_params, request.path_params - ) - query_values, query_errors = request_params_to_args( - dependant.query_params, request.query_params - ) - header_values, header_errors = request_params_to_args( - dependant.header_params, request.headers - ) - cookie_values, cookie_errors = request_params_to_args( - dependant.cookie_params, request.cookies - ) - values.update(path_values) - values.update(query_values) - values.update(header_values) - values.update(cookie_values) - errors += path_errors + query_errors + header_errors + cookie_errors - if dependant.body_params: - ( - body_values, - body_errors, - ) = await request_body_to_args( # body_params checked above - body_fields=dependant.body_params, - received_body=body, - embed_body_fields=embed_body_fields, - ) - values.update(body_values) - errors.extend(body_errors) - if dependant.http_connection_param_name: - values[dependant.http_connection_param_name] = request - if dependant.request_param_name and isinstance(request, Request): - values[dependant.request_param_name] = request - elif dependant.websocket_param_name and isinstance(request, WebSocket): - values[dependant.websocket_param_name] = request - if dependant.background_tasks_param_name: - if background_tasks is None: - background_tasks = BackgroundTasks() - values[dependant.background_tasks_param_name] = background_tasks - if dependant.response_param_name: - values[dependant.response_param_name] = response - if dependant.security_scopes_param_name: - values[dependant.security_scopes_param_name] = SecurityScopes( - scopes=dependant.oauth_scopes - ) - return SolvedDependency( - values=values, - errors=errors, - background_tasks=background_tasks, - response=response, - dependency_cache=dependency_cache, - ) - - -def _validate_value_with_model_field( - *, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] -) -> tuple[Any, list[Any]]: - if value is None: - if field.required: - return None, [get_missing_field_error(loc=loc)] - else: - return deepcopy(field.default), [] - v_, errors_ = field.validate(value, values, loc=loc) - if isinstance(errors_, list): - new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=()) - return None, new_errors - else: - return v_, [] - - -def _get_multidict_value( - field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None -) -> Any: - alias = alias or get_validation_alias(field) - if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)): - value = values.getlist(alias) - else: - value = values.get(alias, None) - if ( - value is None - or ( - isinstance(field.field_info, params.Form) - and isinstance(value, str) # For type checks - and value == "" - ) - or (is_sequence_field(field) and len(value) == 0) - ): - if field.required: - return - else: - return deepcopy(field.default) - return value - - -def request_params_to_args( - fields: Sequence[ModelField], - received_params: Union[Mapping[str, Any], QueryParams, Headers], -) -> tuple[dict[str, Any], list[Any]]: - values: dict[str, Any] = {} - errors: list[dict[str, Any]] = [] - - if not fields: - return values, errors - - first_field = fields[0] - fields_to_extract = fields - single_not_embedded_field = False - default_convert_underscores = True - if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel): - fields_to_extract = get_cached_model_fields(first_field.type_) - single_not_embedded_field = True - # If headers are in a Pydantic model, the way to disable convert_underscores - # would be with Header(convert_underscores=False) at the Pydantic model level - default_convert_underscores = getattr( - first_field.field_info, "convert_underscores", True - ) - - params_to_process: dict[str, Any] = {} - - processed_keys = set() - - for field in fields_to_extract: - alias = None - if isinstance(received_params, Headers): - # Handle fields extracted from a Pydantic Model for a header, each field - # doesn't have a FieldInfo of type Header with the default convert_underscores=True - convert_underscores = getattr( - field.field_info, "convert_underscores", default_convert_underscores - ) - if convert_underscores: - alias = get_validation_alias(field) - if alias == field.name: - alias = alias.replace("_", "-") - value = _get_multidict_value(field, received_params, alias=alias) - if value is not None: - params_to_process[get_validation_alias(field)] = value - processed_keys.add(alias or get_validation_alias(field)) - - for key in received_params.keys(): - if key not in processed_keys: - if hasattr(received_params, "getlist"): - value = received_params.getlist(key) - if isinstance(value, list) and (len(value) == 1): - params_to_process[key] = value[0] - else: - params_to_process[key] = value - else: - params_to_process[key] = received_params.get(key) - - if single_not_embedded_field: - field_info = first_field.field_info - assert isinstance(field_info, params.Param), ( - "Params must be subclasses of Param" - ) - loc: tuple[str, ...] = (field_info.in_.value,) - v_, errors_ = _validate_value_with_model_field( - field=first_field, value=params_to_process, values=values, loc=loc - ) - return {first_field.name: v_}, errors_ - - for field in fields: - value = _get_multidict_value(field, received_params) - field_info = field.field_info - assert isinstance(field_info, params.Param), ( - "Params must be subclasses of Param" - ) - loc = (field_info.in_.value, get_validation_alias(field)) - v_, errors_ = _validate_value_with_model_field( - field=field, value=value, values=values, loc=loc - ) - if errors_: - errors.extend(errors_) - else: - values[field.name] = v_ - return values, errors - - -def is_union_of_base_models(field_type: Any) -> bool: - """Check if field type is a Union where all members are BaseModel subclasses.""" - from fastapi.types import UnionType - - origin = get_origin(field_type) - - # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+) - if origin is not Union and origin is not UnionType: - return False - - union_args = get_args(field_type) - - for arg in union_args: - if not lenient_issubclass(arg, BaseModel): - return False - - return True - - -def _should_embed_body_fields(fields: list[ModelField]) -> bool: - if not fields: - return False - # More than one dependency could have the same field, it would show up as multiple - # fields but it's the same one, so count them by name - body_param_names_set = {field.name for field in fields} - # A top level field has to be a single field, not multiple - if len(body_param_names_set) > 1: - return True - first_field = fields[0] - # If it explicitly specifies it is embedded, it has to be embedded - if getattr(first_field.field_info, "embed", None): - return True - # If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level - # otherwise it has to be embedded, so that the key value pair can be extracted - if ( - isinstance(first_field.field_info, params.Form) - and not lenient_issubclass(first_field.type_, BaseModel) - and not is_union_of_base_models(first_field.type_) - ): - return True - return False - - -async def _extract_form_body( - body_fields: list[ModelField], - received_body: FormData, -) -> dict[str, Any]: - values = {} - - for field in body_fields: - value = _get_multidict_value(field, received_body) - field_info = field.field_info - if ( - isinstance(field_info, params.File) - and is_bytes_field(field) - and isinstance(value, UploadFile) - ): - value = await value.read() - elif ( - is_bytes_sequence_field(field) - and isinstance(field_info, params.File) - and value_is_sequence(value) - ): - # For types - assert isinstance(value, sequence_types) - results: list[Union[bytes, str]] = [] - - async def process_fn( - fn: Callable[[], Coroutine[Any, Any, Any]], - ) -> None: - result = await fn() - results.append(result) # noqa: B023 - - async with anyio.create_task_group() as tg: - for sub_value in value: - tg.start_soon(process_fn, sub_value.read) - value = serialize_sequence_value(field=field, value=results) - if value is not None: - values[get_validation_alias(field)] = value - field_aliases = {get_validation_alias(field) for field in body_fields} - for key in received_body.keys(): - if key not in field_aliases: - param_values = received_body.getlist(key) - if len(param_values) == 1: - values[key] = param_values[0] - else: - values[key] = param_values - return values - - -async def request_body_to_args( - body_fields: list[ModelField], - received_body: Optional[Union[dict[str, Any], FormData]], - embed_body_fields: bool, -) -> tuple[dict[str, Any], list[dict[str, Any]]]: - values: dict[str, Any] = {} - errors: list[dict[str, Any]] = [] - assert body_fields, "request_body_to_args() should be called with fields" - single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields - first_field = body_fields[0] - body_to_process = received_body - - fields_to_extract: list[ModelField] = body_fields - - if ( - single_not_embedded_field - and lenient_issubclass(first_field.type_, BaseModel) - and isinstance(received_body, FormData) - ): - fields_to_extract = get_cached_model_fields(first_field.type_) - - if isinstance(received_body, FormData): - body_to_process = await _extract_form_body(fields_to_extract, received_body) - - if single_not_embedded_field: - loc: tuple[str, ...] = ("body",) - v_, errors_ = _validate_value_with_model_field( - field=first_field, value=body_to_process, values=values, loc=loc - ) - return {first_field.name: v_}, errors_ - for field in body_fields: - loc = ("body", get_validation_alias(field)) - value: Optional[Any] = None - if body_to_process is not None: - try: - value = body_to_process.get(get_validation_alias(field)) - # If the received body is a list, not a dict - except AttributeError: - errors.append(get_missing_field_error(loc)) - continue - v_, errors_ = _validate_value_with_model_field( - field=field, value=value, values=values, loc=loc - ) - if errors_: - errors.extend(errors_) - else: - values[field.name] = v_ - return values, errors - - -def get_body_field( - *, flat_dependant: Dependant, name: str, embed_body_fields: bool -) -> Optional[ModelField]: - """ - Get a ModelField representing the request body for a path operation, combining - all body parameters into a single field if necessary. - - Used to check if it's form data (with `isinstance(body_field, params.Form)`) - or JSON and to generate the JSON Schema for a request body. - - This is **not** used to validate/parse the request body, that's done with each - individual body parameter. - """ - if not flat_dependant.body_params: - return None - first_param = flat_dependant.body_params[0] - if not embed_body_fields: - return first_param - model_name = "Body_" + name - BodyModel = create_body_model( - fields=flat_dependant.body_params, model_name=model_name - ) - required = any(True for f in flat_dependant.body_params if f.required) - BodyFieldInfo_kwargs: dict[str, Any] = { - "annotation": BodyModel, - "alias": "body", - } - if not required: - BodyFieldInfo_kwargs["default"] = None - if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params): - BodyFieldInfo: type[params.Body] = params.File - elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params): - BodyFieldInfo = params.Form - else: - BodyFieldInfo = params.Body - - body_param_media_types = [ - f.field_info.media_type - for f in flat_dependant.body_params - if isinstance(f.field_info, params.Body) - ] - if len(set(body_param_media_types)) == 1: - BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0] - final_field = create_model_field( - name="body", - type_=BodyModel, - required=required, - alias="body", - field_info=BodyFieldInfo(**BodyFieldInfo_kwargs), - ) - return final_field - - -def get_validation_alias(field: ModelField) -> str: - va = getattr(field, "validation_alias", None) - return va or field.alias diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/encoders.py b/backend/venv39/lib/python3.9/site-packages/fastapi/encoders.py deleted file mode 100644 index e8610c9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/encoders.py +++ /dev/null @@ -1,346 +0,0 @@ -import dataclasses -import datetime -from collections import defaultdict, deque -from decimal import Decimal -from enum import Enum -from ipaddress import ( - IPv4Address, - IPv4Interface, - IPv4Network, - IPv6Address, - IPv6Interface, - IPv6Network, -) -from pathlib import Path, PurePath -from re import Pattern -from types import GeneratorType -from typing import Annotated, Any, Callable, Optional, Union -from uuid import UUID - -from annotated_doc import Doc -from fastapi.exceptions import PydanticV1NotSupportedError -from fastapi.types import IncEx -from pydantic import BaseModel -from pydantic.color import Color -from pydantic.networks import AnyUrl, NameEmail -from pydantic.types import SecretBytes, SecretStr -from pydantic_core import PydanticUndefinedType - -from ._compat import ( - Url, - is_pydantic_v1_model_instance, -) - - -# Taken from Pydantic v1 as is -def isoformat(o: Union[datetime.date, datetime.time]) -> str: - return o.isoformat() - - -# Adapted from Pydantic v1 -# TODO: pv2 should this return strings instead? -def decimal_encoder(dec_value: Decimal) -> Union[int, float]: - """ - Encodes a Decimal as int if there's no exponent, otherwise float - - This is useful when we use ConstrainedDecimal to represent Numeric(x,0) - where an integer (but not int typed) is used. Encoding this as a float - results in failed round-tripping between encode and parse. - Our Id type is a prime example of this. - - >>> decimal_encoder(Decimal("1.0")) - 1.0 - - >>> decimal_encoder(Decimal("1")) - 1 - - >>> decimal_encoder(Decimal("NaN")) - nan - """ - exponent = dec_value.as_tuple().exponent - if isinstance(exponent, int) and exponent >= 0: - return int(dec_value) - else: - return float(dec_value) - - -ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = { - bytes: lambda o: o.decode(), - Color: str, - datetime.date: isoformat, - datetime.datetime: isoformat, - datetime.time: isoformat, - datetime.timedelta: lambda td: td.total_seconds(), - Decimal: decimal_encoder, - Enum: lambda o: o.value, - frozenset: list, - deque: list, - GeneratorType: list, - IPv4Address: str, - IPv4Interface: str, - IPv4Network: str, - IPv6Address: str, - IPv6Interface: str, - IPv6Network: str, - NameEmail: str, - Path: str, - Pattern: lambda o: o.pattern, - SecretBytes: str, - SecretStr: str, - set: list, - UUID: str, - Url: str, - AnyUrl: str, -} - - -def generate_encoders_by_class_tuples( - type_encoder_map: dict[Any, Callable[[Any], Any]], -) -> dict[Callable[[Any], Any], tuple[Any, ...]]: - encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict( - tuple - ) - for type_, encoder in type_encoder_map.items(): - encoders_by_class_tuples[encoder] += (type_,) - return encoders_by_class_tuples - - -encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE) - - -def jsonable_encoder( - obj: Annotated[ - Any, - Doc( - """ - The input object to convert to JSON. - """ - ), - ], - include: Annotated[ - Optional[IncEx], - Doc( - """ - Pydantic's `include` parameter, passed to Pydantic models to set the - fields to include. - """ - ), - ] = None, - exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Pydantic's `exclude` parameter, passed to Pydantic models to set the - fields to exclude. - """ - ), - ] = None, - by_alias: Annotated[ - bool, - Doc( - """ - Pydantic's `by_alias` parameter, passed to Pydantic models to define if - the output should use the alias names (when provided) or the Python - attribute names. In an API, if you set an alias, it's probably because you - want to use it in the result, so you probably want to leave this set to - `True`. - """ - ), - ] = True, - exclude_unset: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_unset` parameter, passed to Pydantic models to define - if it should exclude from the output the fields that were not explicitly - set (and that only had their default values). - """ - ), - ] = False, - exclude_defaults: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define - if it should exclude from the output the fields that had the same default - value, even when they were explicitly set. - """ - ), - ] = False, - exclude_none: Annotated[ - bool, - Doc( - """ - Pydantic's `exclude_none` parameter, passed to Pydantic models to define - if it should exclude from the output any fields that have a `None` value. - """ - ), - ] = False, - custom_encoder: Annotated[ - Optional[dict[Any, Callable[[Any], Any]]], - Doc( - """ - Pydantic's `custom_encoder` parameter, passed to Pydantic models to define - a custom encoder. - """ - ), - ] = None, - sqlalchemy_safe: Annotated[ - bool, - Doc( - """ - Exclude from the output any fields that start with the name `_sa`. - - This is mainly a hack for compatibility with SQLAlchemy objects, they - store internal SQLAlchemy-specific state in attributes named with `_sa`, - and those objects can't (and shouldn't be) serialized to JSON. - """ - ), - ] = True, -) -> Any: - """ - Convert any object to something that can be encoded in JSON. - - This is used internally by FastAPI to make sure anything you return can be - encoded as JSON before it is sent to the client. - - You can also use it yourself, for example to convert objects before saving them - in a database that supports only JSON. - - Read more about it in the - [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/). - """ - custom_encoder = custom_encoder or {} - if custom_encoder: - if type(obj) in custom_encoder: - return custom_encoder[type(obj)](obj) - else: - for encoder_type, encoder_instance in custom_encoder.items(): - if isinstance(obj, encoder_type): - return encoder_instance(obj) - if include is not None and not isinstance(include, (set, dict)): - include = set(include) - if exclude is not None and not isinstance(exclude, (set, dict)): - exclude = set(exclude) - if isinstance(obj, BaseModel): - obj_dict = obj.model_dump( - mode="json", - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - exclude_defaults=exclude_defaults, - ) - return jsonable_encoder( - obj_dict, - exclude_none=exclude_none, - exclude_defaults=exclude_defaults, - sqlalchemy_safe=sqlalchemy_safe, - ) - if dataclasses.is_dataclass(obj): - assert not isinstance(obj, type) - obj_dict = dataclasses.asdict(obj) - return jsonable_encoder( - obj_dict, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - if isinstance(obj, Enum): - return obj.value - if isinstance(obj, PurePath): - return str(obj) - if isinstance(obj, (str, int, float, type(None))): - return obj - if isinstance(obj, PydanticUndefinedType): - return None - if isinstance(obj, dict): - encoded_dict = {} - allowed_keys = set(obj.keys()) - if include is not None: - allowed_keys &= set(include) - if exclude is not None: - allowed_keys -= set(exclude) - for key, value in obj.items(): - if ( - ( - not sqlalchemy_safe - or (not isinstance(key, str)) - or (not key.startswith("_sa")) - ) - and (value is not None or not exclude_none) - and key in allowed_keys - ): - encoded_key = jsonable_encoder( - key, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - encoded_value = jsonable_encoder( - value, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - encoded_dict[encoded_key] = encoded_value - return encoded_dict - if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)): - encoded_list = [] - for item in obj: - encoded_list.append( - jsonable_encoder( - item, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) - ) - return encoded_list - - if type(obj) in ENCODERS_BY_TYPE: - return ENCODERS_BY_TYPE[type(obj)](obj) - for encoder, classes_tuple in encoders_by_class_tuples.items(): - if isinstance(obj, classes_tuple): - return encoder(obj) - if is_pydantic_v1_model_instance(obj): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" Please update the model {obj!r}." - ) - try: - data = dict(obj) - except Exception as e: - errors: list[Exception] = [] - errors.append(e) - try: - data = vars(obj) - except Exception as e: - errors.append(e) - raise ValueError(errors) from e - return jsonable_encoder( - data, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/exception_handlers.py b/backend/venv39/lib/python3.9/site-packages/fastapi/exception_handlers.py deleted file mode 100644 index 475dd7b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/exception_handlers.py +++ /dev/null @@ -1,34 +0,0 @@ -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError -from fastapi.utils import is_body_allowed_for_status_code -from fastapi.websockets import WebSocket -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.responses import JSONResponse, Response -from starlette.status import WS_1008_POLICY_VIOLATION - - -async def http_exception_handler(request: Request, exc: HTTPException) -> Response: - headers = getattr(exc, "headers", None) - if not is_body_allowed_for_status_code(exc.status_code): - return Response(status_code=exc.status_code, headers=headers) - return JSONResponse( - {"detail": exc.detail}, status_code=exc.status_code, headers=headers - ) - - -async def request_validation_exception_handler( - request: Request, exc: RequestValidationError -) -> JSONResponse: - return JSONResponse( - status_code=422, - content={"detail": jsonable_encoder(exc.errors())}, - ) - - -async def websocket_request_validation_exception_handler( - websocket: WebSocket, exc: WebSocketRequestValidationError -) -> None: - await websocket.close( - code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors()) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/exceptions.py b/backend/venv39/lib/python3.9/site-packages/fastapi/exceptions.py deleted file mode 100644 index 1a3abd8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/exceptions.py +++ /dev/null @@ -1,246 +0,0 @@ -from collections.abc import Sequence -from typing import Annotated, Any, Optional, TypedDict, Union - -from annotated_doc import Doc -from pydantic import BaseModel, create_model -from starlette.exceptions import HTTPException as StarletteHTTPException -from starlette.exceptions import WebSocketException as StarletteWebSocketException - - -class EndpointContext(TypedDict, total=False): - function: str - path: str - file: str - line: int - - -class HTTPException(StarletteHTTPException): - """ - An HTTP exception you can raise in your own code to show errors to the client. - - This is for client errors, invalid authentication, invalid data, etc. Not for server - errors in your code. - - Read more about it in the - [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). - - ## Example - - ```python - from fastapi import FastAPI, HTTPException - - app = FastAPI() - - items = {"foo": "The Foo Wrestlers"} - - - @app.get("/items/{item_id}") - async def read_item(item_id: str): - if item_id not in items: - raise HTTPException(status_code=404, detail="Item not found") - return {"item": items[item_id]} - ``` - """ - - def __init__( - self, - status_code: Annotated[ - int, - Doc( - """ - HTTP status code to send to the client. - """ - ), - ], - detail: Annotated[ - Any, - Doc( - """ - Any data to be sent to the client in the `detail` key of the JSON - response. - """ - ), - ] = None, - headers: Annotated[ - Optional[dict[str, str]], - Doc( - """ - Any headers to send to the client in the response. - """ - ), - ] = None, - ) -> None: - super().__init__(status_code=status_code, detail=detail, headers=headers) - - -class WebSocketException(StarletteWebSocketException): - """ - A WebSocket exception you can raise in your own code to show errors to the client. - - This is for client errors, invalid authentication, invalid data, etc. Not for server - errors in your code. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import ( - Cookie, - FastAPI, - WebSocket, - WebSocketException, - status, - ) - - app = FastAPI() - - @app.websocket("/items/{item_id}/ws") - async def websocket_endpoint( - *, - websocket: WebSocket, - session: Annotated[str | None, Cookie()] = None, - item_id: str, - ): - if session is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Session cookie is: {session}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") - ``` - """ - - def __init__( - self, - code: Annotated[ - int, - Doc( - """ - A closing code from the - [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1). - """ - ), - ], - reason: Annotated[ - Union[str, None], - Doc( - """ - The reason to close the WebSocket connection. - - It is UTF-8-encoded data. The interpretation of the reason is up to the - application, it is not specified by the WebSocket specification. - - It could contain text that could be human-readable or interpretable - by the client code, etc. - """ - ), - ] = None, - ) -> None: - super().__init__(code=code, reason=reason) - - -RequestErrorModel: type[BaseModel] = create_model("Request") -WebSocketErrorModel: type[BaseModel] = create_model("WebSocket") - - -class FastAPIError(RuntimeError): - """ - A generic, FastAPI-specific error. - """ - - -class DependencyScopeError(FastAPIError): - """ - A dependency declared that it depends on another dependency with an invalid - (narrower) scope. - """ - - -class ValidationException(Exception): - def __init__( - self, - errors: Sequence[Any], - *, - endpoint_ctx: Optional[EndpointContext] = None, - ) -> None: - self._errors = errors - self.endpoint_ctx = endpoint_ctx - - ctx = endpoint_ctx or {} - self.endpoint_function = ctx.get("function") - self.endpoint_path = ctx.get("path") - self.endpoint_file = ctx.get("file") - self.endpoint_line = ctx.get("line") - - def errors(self) -> Sequence[Any]: - return self._errors - - def _format_endpoint_context(self) -> str: - if not (self.endpoint_file and self.endpoint_line and self.endpoint_function): - if self.endpoint_path: - return f"\n Endpoint: {self.endpoint_path}" - return "" - - context = f'\n File "{self.endpoint_file}", line {self.endpoint_line}, in {self.endpoint_function}' - if self.endpoint_path: - context += f"\n {self.endpoint_path}" - return context - - def __str__(self) -> str: - message = f"{len(self._errors)} validation error{'s' if len(self._errors) != 1 else ''}:\n" - for err in self._errors: - message += f" {err}\n" - message += self._format_endpoint_context() - return message.rstrip() - - -class RequestValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - body: Any = None, - endpoint_ctx: Optional[EndpointContext] = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - self.body = body - - -class WebSocketRequestValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - endpoint_ctx: Optional[EndpointContext] = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - - -class ResponseValidationError(ValidationException): - def __init__( - self, - errors: Sequence[Any], - *, - body: Any = None, - endpoint_ctx: Optional[EndpointContext] = None, - ) -> None: - super().__init__(errors, endpoint_ctx=endpoint_ctx) - self.body = body - - -class PydanticV1NotSupportedError(FastAPIError): - """ - A pydantic.v1 model is used, which is no longer supported. - """ - - -class FastAPIDeprecationWarning(UserWarning): - """ - A custom deprecation warning as DeprecationWarning is ignored - Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries - """ diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/logger.py b/backend/venv39/lib/python3.9/site-packages/fastapi/logger.py deleted file mode 100644 index 5b2c4ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/logger.py +++ /dev/null @@ -1,3 +0,0 @@ -import logging - -logger = logging.getLogger("fastapi") diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/__init__.py deleted file mode 100644 index 620296d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware import Middleware as Middleware diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py deleted file mode 100644 index 4ce3f5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/asyncexitstack.py +++ /dev/null @@ -1,18 +0,0 @@ -from contextlib import AsyncExitStack - -from starlette.types import ASGIApp, Receive, Scope, Send - - -# Used mainly to close files after the request is done, dependencies are closed -# in their own AsyncExitStack -class AsyncExitStackMiddleware: - def __init__( - self, app: ASGIApp, context_name: str = "fastapi_middleware_astack" - ) -> None: - self.app = app - self.context_name = context_name - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - async with AsyncExitStack() as stack: - scope[self.context_name] = stack - await self.app(scope, receive, send) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/cors.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/cors.py deleted file mode 100644 index 8dfaad0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/cors.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/gzip.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/gzip.py deleted file mode 100644 index bbeb2cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/gzip.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/httpsredirect.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/httpsredirect.py deleted file mode 100644 index b7a3d8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/httpsredirect.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.middleware.httpsredirect import ( # noqa - HTTPSRedirectMiddleware as HTTPSRedirectMiddleware, -) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/trustedhost.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/trustedhost.py deleted file mode 100644 index 08d7e03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/trustedhost.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.middleware.trustedhost import ( # noqa - TrustedHostMiddleware as TrustedHostMiddleware, -) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/wsgi.py b/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/wsgi.py deleted file mode 100644 index c4c6a79..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/middleware/wsgi.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/constants.py b/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/constants.py deleted file mode 100644 index d724ee3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/constants.py +++ /dev/null @@ -1,3 +0,0 @@ -METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"} -REF_PREFIX = "#/components/schemas/" -REF_TEMPLATE = "#/components/schemas/{model}" diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/docs.py b/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/docs.py deleted file mode 100644 index 82380f8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/docs.py +++ /dev/null @@ -1,344 +0,0 @@ -import json -from typing import Annotated, Any, Optional - -from annotated_doc import Doc -from fastapi.encoders import jsonable_encoder -from starlette.responses import HTMLResponse - -swagger_ui_default_parameters: Annotated[ - dict[str, Any], - Doc( - """ - Default configurations for Swagger UI. - - You can use it as a template to add any other configurations needed. - """ - ), -] = { - "dom_id": "#swagger-ui", - "layout": "BaseLayout", - "deepLinking": True, - "showExtensions": True, - "showCommonExtensions": True, -} - - -def get_swagger_ui_html( - *, - openapi_url: Annotated[ - str, - Doc( - """ - The OpenAPI URL that Swagger UI should load and use. - - This is normally done automatically by FastAPI using the default URL - `/openapi.json`. - """ - ), - ], - title: Annotated[ - str, - Doc( - """ - The HTML `` content, normally shown in the browser tab. - """ - ), - ], - swagger_js_url: Annotated[ - str, - Doc( - """ - The URL to use to load the Swagger UI JavaScript. - - It is normally set to a CDN URL. - """ - ), - ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js", - swagger_css_url: Annotated[ - str, - Doc( - """ - The URL to use to load the Swagger UI CSS. - - It is normally set to a CDN URL. - """ - ), - ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css", - swagger_favicon_url: Annotated[ - str, - Doc( - """ - The URL of the favicon to use. It is normally shown in the browser tab. - """ - ), - ] = "https://fastapi.tiangolo.com/img/favicon.png", - oauth2_redirect_url: Annotated[ - Optional[str], - Doc( - """ - The OAuth2 redirect URL, it is normally automatically handled by FastAPI. - """ - ), - ] = None, - init_oauth: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - A dictionary with Swagger UI OAuth2 initialization configurations. - """ - ), - ] = None, - swagger_ui_parameters: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Configuration parameters for Swagger UI. - - It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters]. - """ - ), - ] = None, -) -> HTMLResponse: - """ - Generate and return the HTML that loads Swagger UI for the interactive - API docs (normally served at `/docs`). - - You would only call this function yourself if you needed to override some parts, - for example the URLs to use to load Swagger UI's JavaScript and CSS. - - Read more about it in the - [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/) - and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). - """ - current_swagger_ui_parameters = swagger_ui_default_parameters.copy() - if swagger_ui_parameters: - current_swagger_ui_parameters.update(swagger_ui_parameters) - - html = f""" - <!DOCTYPE html> - <html> - <head> - <link type="text/css" rel="stylesheet" href="{swagger_css_url}"> - <link rel="shortcut icon" href="{swagger_favicon_url}"> - <title>{title} - - -
    -
    - - - - - - """ - return HTMLResponse(html) - - -def get_redoc_html( - *, - openapi_url: Annotated[ - str, - Doc( - """ - The OpenAPI URL that ReDoc should load and use. - - This is normally done automatically by FastAPI using the default URL - `/openapi.json`. - """ - ), - ], - title: Annotated[ - str, - Doc( - """ - The HTML `` content, normally shown in the browser tab. - """ - ), - ], - redoc_js_url: Annotated[ - str, - Doc( - """ - The URL to use to load the ReDoc JavaScript. - - It is normally set to a CDN URL. - """ - ), - ] = "https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js", - redoc_favicon_url: Annotated[ - str, - Doc( - """ - The URL of the favicon to use. It is normally shown in the browser tab. - """ - ), - ] = "https://fastapi.tiangolo.com/img/favicon.png", - with_google_fonts: Annotated[ - bool, - Doc( - """ - Load and use Google Fonts. - """ - ), - ] = True, -) -> HTMLResponse: - """ - Generate and return the HTML response that loads ReDoc for the alternative - API docs (normally served at `/redoc`). - - You would only call this function yourself if you needed to override some parts, - for example the URLs to use to load ReDoc's JavaScript and CSS. - - Read more about it in the - [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). - """ - html = f""" - <!DOCTYPE html> - <html> - <head> - <title>{title} - - - - """ - if with_google_fonts: - html += """ - - """ - html += f""" - - - - - - - - - - - """ - return HTMLResponse(html) - - -def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse: - """ - Generate the HTML response with the OAuth2 redirection for Swagger UI. - - You normally don't need to use or change this. - """ - # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html - html = """ - - - - Swagger UI: OAuth2 Redirect - - - - - - """ - return HTMLResponse(content=html) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/models.py b/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/models.py deleted file mode 100644 index ac6a6d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/models.py +++ /dev/null @@ -1,438 +0,0 @@ -from collections.abc import Iterable, Mapping -from enum import Enum -from typing import Annotated, Any, Callable, Optional, Union - -from fastapi._compat import with_info_plain_validator_function -from fastapi.logger import logger -from pydantic import ( - AnyUrl, - BaseModel, - Field, - GetJsonSchemaHandler, -) -from typing_extensions import Literal, TypedDict -from typing_extensions import deprecated as typing_deprecated - -try: - import email_validator - - assert email_validator # make autoflake ignore the unused import - from pydantic import EmailStr -except ImportError: # pragma: no cover - - class EmailStr(str): # type: ignore - @classmethod - def __get_validators__(cls) -> Iterable[Callable[..., Any]]: - yield cls.validate - - @classmethod - def validate(cls, v: Any) -> str: - logger.warning( - "email-validator not installed, email fields will be treated as str.\n" - "To install, run: pip install email-validator" - ) - return str(v) - - @classmethod - def _validate(cls, __input_value: Any, _: Any) -> str: - logger.warning( - "email-validator not installed, email fields will be treated as str.\n" - "To install, run: pip install email-validator" - ) - return str(__input_value) - - @classmethod - def __get_pydantic_json_schema__( - cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler - ) -> dict[str, Any]: - return {"type": "string", "format": "email"} - - @classmethod - def __get_pydantic_core_schema__( - cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]] - ) -> Mapping[str, Any]: - return with_info_plain_validator_function(cls._validate) - - -class BaseModelWithConfig(BaseModel): - model_config = {"extra": "allow"} - - -class Contact(BaseModelWithConfig): - name: Optional[str] = None - url: Optional[AnyUrl] = None - email: Optional[EmailStr] = None - - -class License(BaseModelWithConfig): - name: str - identifier: Optional[str] = None - url: Optional[AnyUrl] = None - - -class Info(BaseModelWithConfig): - title: str - summary: Optional[str] = None - description: Optional[str] = None - termsOfService: Optional[str] = None - contact: Optional[Contact] = None - license: Optional[License] = None - version: str - - -class ServerVariable(BaseModelWithConfig): - enum: Annotated[Optional[list[str]], Field(min_length=1)] = None - default: str - description: Optional[str] = None - - -class Server(BaseModelWithConfig): - url: Union[AnyUrl, str] - description: Optional[str] = None - variables: Optional[dict[str, ServerVariable]] = None - - -class Reference(BaseModel): - ref: str = Field(alias="$ref") - - -class Discriminator(BaseModel): - propertyName: str - mapping: Optional[dict[str, str]] = None - - -class XML(BaseModelWithConfig): - name: Optional[str] = None - namespace: Optional[str] = None - prefix: Optional[str] = None - attribute: Optional[bool] = None - wrapped: Optional[bool] = None - - -class ExternalDocumentation(BaseModelWithConfig): - description: Optional[str] = None - url: AnyUrl - - -# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type -SchemaType = Literal[ - "array", "boolean", "integer", "null", "number", "object", "string" -] - - -class Schema(BaseModelWithConfig): - # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu - # Core Vocabulary - schema_: Optional[str] = Field(default=None, alias="$schema") - vocabulary: Optional[str] = Field(default=None, alias="$vocabulary") - id: Optional[str] = Field(default=None, alias="$id") - anchor: Optional[str] = Field(default=None, alias="$anchor") - dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") - ref: Optional[str] = Field(default=None, alias="$ref") - dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") - defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") - comment: Optional[str] = Field(default=None, alias="$comment") - # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s - # A Vocabulary for Applying Subschemas - allOf: Optional[list["SchemaOrBool"]] = None - anyOf: Optional[list["SchemaOrBool"]] = None - oneOf: Optional[list["SchemaOrBool"]] = None - not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") - if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") - then: Optional["SchemaOrBool"] = None - else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") - dependentSchemas: Optional[dict[str, "SchemaOrBool"]] = None - prefixItems: Optional[list["SchemaOrBool"]] = None - # TODO: uncomment and remove below when deprecating Pydantic v1 - # It generates a list of schemas for tuples, before prefixItems was available - # items: Optional["SchemaOrBool"] = None - items: Optional[Union["SchemaOrBool", list["SchemaOrBool"]]] = None - contains: Optional["SchemaOrBool"] = None - properties: Optional[dict[str, "SchemaOrBool"]] = None - patternProperties: Optional[dict[str, "SchemaOrBool"]] = None - additionalProperties: Optional["SchemaOrBool"] = None - propertyNames: Optional["SchemaOrBool"] = None - unevaluatedItems: Optional["SchemaOrBool"] = None - unevaluatedProperties: Optional["SchemaOrBool"] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural - # A Vocabulary for Structural Validation - type: Optional[Union[SchemaType, list[SchemaType]]] = None - enum: Optional[list[Any]] = None - const: Optional[Any] = None - multipleOf: Optional[float] = Field(default=None, gt=0) - maximum: Optional[float] = None - exclusiveMaximum: Optional[float] = None - minimum: Optional[float] = None - exclusiveMinimum: Optional[float] = None - maxLength: Optional[int] = Field(default=None, ge=0) - minLength: Optional[int] = Field(default=None, ge=0) - pattern: Optional[str] = None - maxItems: Optional[int] = Field(default=None, ge=0) - minItems: Optional[int] = Field(default=None, ge=0) - uniqueItems: Optional[bool] = None - maxContains: Optional[int] = Field(default=None, ge=0) - minContains: Optional[int] = Field(default=None, ge=0) - maxProperties: Optional[int] = Field(default=None, ge=0) - minProperties: Optional[int] = Field(default=None, ge=0) - required: Optional[list[str]] = None - dependentRequired: Optional[dict[str, set[str]]] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c - # Vocabularies for Semantic Content With "format" - format: Optional[str] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten - # A Vocabulary for the Contents of String-Encoded Data - contentEncoding: Optional[str] = None - contentMediaType: Optional[str] = None - contentSchema: Optional["SchemaOrBool"] = None - # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta - # A Vocabulary for Basic Meta-Data Annotations - title: Optional[str] = None - description: Optional[str] = None - default: Optional[Any] = None - deprecated: Optional[bool] = None - readOnly: Optional[bool] = None - writeOnly: Optional[bool] = None - examples: Optional[list[Any]] = None - # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object - # Schema Object - discriminator: Optional[Discriminator] = None - xml: Optional[XML] = None - externalDocs: Optional[ExternalDocumentation] = None - example: Annotated[ - Optional[Any], - typing_deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = None - - -# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents -# A JSON Schema MUST be an object or a boolean. -SchemaOrBool = Union[Schema, bool] - - -class Example(TypedDict, total=False): - summary: Optional[str] - description: Optional[str] - value: Optional[Any] - externalValue: Optional[AnyUrl] - - __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] - - -class ParameterInType(Enum): - query = "query" - header = "header" - path = "path" - cookie = "cookie" - - -class Encoding(BaseModelWithConfig): - contentType: Optional[str] = None - headers: Optional[dict[str, Union["Header", Reference]]] = None - style: Optional[str] = None - explode: Optional[bool] = None - allowReserved: Optional[bool] = None - - -class MediaType(BaseModelWithConfig): - schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") - example: Optional[Any] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None - encoding: Optional[dict[str, Encoding]] = None - - -class ParameterBase(BaseModelWithConfig): - description: Optional[str] = None - required: Optional[bool] = None - deprecated: Optional[bool] = None - # Serialization rules for simple scenarios - style: Optional[str] = None - explode: Optional[bool] = None - allowReserved: Optional[bool] = None - schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") - example: Optional[Any] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None - # Serialization rules for more complex scenarios - content: Optional[dict[str, MediaType]] = None - - -class Parameter(ParameterBase): - name: str - in_: ParameterInType = Field(alias="in") - - -class Header(ParameterBase): - pass - - -class RequestBody(BaseModelWithConfig): - description: Optional[str] = None - content: dict[str, MediaType] - required: Optional[bool] = None - - -class Link(BaseModelWithConfig): - operationRef: Optional[str] = None - operationId: Optional[str] = None - parameters: Optional[dict[str, Union[Any, str]]] = None - requestBody: Optional[Union[Any, str]] = None - description: Optional[str] = None - server: Optional[Server] = None - - -class Response(BaseModelWithConfig): - description: str - headers: Optional[dict[str, Union[Header, Reference]]] = None - content: Optional[dict[str, MediaType]] = None - links: Optional[dict[str, Union[Link, Reference]]] = None - - -class Operation(BaseModelWithConfig): - tags: Optional[list[str]] = None - summary: Optional[str] = None - description: Optional[str] = None - externalDocs: Optional[ExternalDocumentation] = None - operationId: Optional[str] = None - parameters: Optional[list[Union[Parameter, Reference]]] = None - requestBody: Optional[Union[RequestBody, Reference]] = None - # Using Any for Specification Extensions - responses: Optional[dict[str, Union[Response, Any]]] = None - callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None - deprecated: Optional[bool] = None - security: Optional[list[dict[str, list[str]]]] = None - servers: Optional[list[Server]] = None - - -class PathItem(BaseModelWithConfig): - ref: Optional[str] = Field(default=None, alias="$ref") - summary: Optional[str] = None - description: Optional[str] = None - get: Optional[Operation] = None - put: Optional[Operation] = None - post: Optional[Operation] = None - delete: Optional[Operation] = None - options: Optional[Operation] = None - head: Optional[Operation] = None - patch: Optional[Operation] = None - trace: Optional[Operation] = None - servers: Optional[list[Server]] = None - parameters: Optional[list[Union[Parameter, Reference]]] = None - - -class SecuritySchemeType(Enum): - apiKey = "apiKey" - http = "http" - oauth2 = "oauth2" - openIdConnect = "openIdConnect" - - -class SecurityBase(BaseModelWithConfig): - type_: SecuritySchemeType = Field(alias="type") - description: Optional[str] = None - - -class APIKeyIn(Enum): - query = "query" - header = "header" - cookie = "cookie" - - -class APIKey(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type") - in_: APIKeyIn = Field(alias="in") - name: str - - -class HTTPBase(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type") - scheme: str - - -class HTTPBearer(HTTPBase): - scheme: Literal["bearer"] = "bearer" - bearerFormat: Optional[str] = None - - -class OAuthFlow(BaseModelWithConfig): - refreshUrl: Optional[str] = None - scopes: dict[str, str] = {} - - -class OAuthFlowImplicit(OAuthFlow): - authorizationUrl: str - - -class OAuthFlowPassword(OAuthFlow): - tokenUrl: str - - -class OAuthFlowClientCredentials(OAuthFlow): - tokenUrl: str - - -class OAuthFlowAuthorizationCode(OAuthFlow): - authorizationUrl: str - tokenUrl: str - - -class OAuthFlows(BaseModelWithConfig): - implicit: Optional[OAuthFlowImplicit] = None - password: Optional[OAuthFlowPassword] = None - clientCredentials: Optional[OAuthFlowClientCredentials] = None - authorizationCode: Optional[OAuthFlowAuthorizationCode] = None - - -class OAuth2(SecurityBase): - type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type") - flows: OAuthFlows - - -class OpenIdConnect(SecurityBase): - type_: SecuritySchemeType = Field( - default=SecuritySchemeType.openIdConnect, alias="type" - ) - openIdConnectUrl: str - - -SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer] - - -class Components(BaseModelWithConfig): - schemas: Optional[dict[str, Union[Schema, Reference]]] = None - responses: Optional[dict[str, Union[Response, Reference]]] = None - parameters: Optional[dict[str, Union[Parameter, Reference]]] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None - requestBodies: Optional[dict[str, Union[RequestBody, Reference]]] = None - headers: Optional[dict[str, Union[Header, Reference]]] = None - securitySchemes: Optional[dict[str, Union[SecurityScheme, Reference]]] = None - links: Optional[dict[str, Union[Link, Reference]]] = None - # Using Any for Specification Extensions - callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None - pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None - - -class Tag(BaseModelWithConfig): - name: str - description: Optional[str] = None - externalDocs: Optional[ExternalDocumentation] = None - - -class OpenAPI(BaseModelWithConfig): - openapi: str - info: Info - jsonSchemaDialect: Optional[str] = None - servers: Optional[list[Server]] = None - # Using Any for Specification Extensions - paths: Optional[dict[str, Union[PathItem, Any]]] = None - webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None - components: Optional[Components] = None - security: Optional[list[dict[str, list[str]]]] = None - tags: Optional[list[Tag]] = None - externalDocs: Optional[ExternalDocumentation] = None - - -Schema.model_rebuild() -Operation.model_rebuild() -Encoding.model_rebuild() diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/utils.py b/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/utils.py deleted file mode 100644 index 75ff261..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/openapi/utils.py +++ /dev/null @@ -1,567 +0,0 @@ -import http.client -import inspect -import warnings -from collections.abc import Sequence -from typing import Any, Optional, Union, cast - -from fastapi import routing -from fastapi._compat import ( - ModelField, - Undefined, - get_compat_model_name_map, - get_definitions, - get_schema_from_model_field, - lenient_issubclass, -) -from fastapi.datastructures import DefaultPlaceholder -from fastapi.dependencies.models import Dependant -from fastapi.dependencies.utils import ( - _get_flat_fields_from_params, - get_flat_dependant, - get_flat_params, - get_validation_alias, -) -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import FastAPIDeprecationWarning -from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX -from fastapi.openapi.models import OpenAPI -from fastapi.params import Body, ParamTypes -from fastapi.responses import Response -from fastapi.types import ModelNameMap -from fastapi.utils import ( - deep_dict_update, - generate_operation_id_for_path, - is_body_allowed_for_status_code, -) -from pydantic import BaseModel -from starlette.responses import JSONResponse -from starlette.routing import BaseRoute -from typing_extensions import Literal - -validation_error_definition = { - "title": "ValidationError", - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - "required": ["loc", "msg", "type"], -} - -validation_error_response_definition = { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": REF_PREFIX + "ValidationError"}, - } - }, -} - -status_code_ranges: dict[str, str] = { - "1XX": "Information", - "2XX": "Success", - "3XX": "Redirection", - "4XX": "Client Error", - "5XX": "Server Error", - "DEFAULT": "Default Response", -} - - -def get_openapi_security_definitions( - flat_dependant: Dependant, -) -> tuple[dict[str, Any], list[dict[str, Any]]]: - security_definitions = {} - # Use a dict to merge scopes for same security scheme - operation_security_dict: dict[str, list[str]] = {} - for security_dependency in flat_dependant._security_dependencies: - security_definition = jsonable_encoder( - security_dependency._security_scheme.model, - by_alias=True, - exclude_none=True, - ) - security_name = security_dependency._security_scheme.scheme_name - security_definitions[security_name] = security_definition - # Merge scopes for the same security scheme - if security_name not in operation_security_dict: - operation_security_dict[security_name] = [] - for scope in security_dependency.oauth_scopes or []: - if scope not in operation_security_dict[security_name]: - operation_security_dict[security_name].append(scope) - operation_security = [ - {name: scopes} for name, scopes in operation_security_dict.items() - ] - return security_definitions, operation_security - - -def _get_openapi_operation_parameters( - *, - dependant: Dependant, - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> list[dict[str, Any]]: - parameters = [] - flat_dependant = get_flat_dependant(dependant, skip_repeats=True) - path_params = _get_flat_fields_from_params(flat_dependant.path_params) - query_params = _get_flat_fields_from_params(flat_dependant.query_params) - header_params = _get_flat_fields_from_params(flat_dependant.header_params) - cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params) - parameter_groups = [ - (ParamTypes.path, path_params), - (ParamTypes.query, query_params), - (ParamTypes.header, header_params), - (ParamTypes.cookie, cookie_params), - ] - default_convert_underscores = True - if len(flat_dependant.header_params) == 1: - first_field = flat_dependant.header_params[0] - if lenient_issubclass(first_field.type_, BaseModel): - default_convert_underscores = getattr( - first_field.field_info, "convert_underscores", True - ) - for param_type, param_group in parameter_groups: - for param in param_group: - field_info = param.field_info - # field_info = cast(Param, field_info) - if not getattr(field_info, "include_in_schema", True): - continue - param_schema = get_schema_from_model_field( - field=param, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - name = get_validation_alias(param) - convert_underscores = getattr( - param.field_info, - "convert_underscores", - default_convert_underscores, - ) - if ( - param_type == ParamTypes.header - and name == param.name - and convert_underscores - ): - name = param.name.replace("_", "-") - - parameter = { - "name": name, - "in": param_type.value, - "required": param.required, - "schema": param_schema, - } - if field_info.description: - parameter["description"] = field_info.description - openapi_examples = getattr(field_info, "openapi_examples", None) - example = getattr(field_info, "example", None) - if openapi_examples: - parameter["examples"] = jsonable_encoder(openapi_examples) - elif example != Undefined: - parameter["example"] = jsonable_encoder(example) - if getattr(field_info, "deprecated", None): - parameter["deprecated"] = True - parameters.append(parameter) - return parameters - - -def get_openapi_operation_request_body( - *, - body_field: Optional[ModelField], - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> Optional[dict[str, Any]]: - if not body_field: - return None - assert isinstance(body_field, ModelField) - body_schema = get_schema_from_model_field( - field=body_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - field_info = cast(Body, body_field.field_info) - request_media_type = field_info.media_type - required = body_field.required - request_body_oai: dict[str, Any] = {} - if required: - request_body_oai["required"] = required - request_media_content: dict[str, Any] = {"schema": body_schema} - if field_info.openapi_examples: - request_media_content["examples"] = jsonable_encoder( - field_info.openapi_examples - ) - elif field_info.example != Undefined: - request_media_content["example"] = jsonable_encoder(field_info.example) - request_body_oai["content"] = {request_media_type: request_media_content} - return request_body_oai - - -def generate_operation_id( - *, route: routing.APIRoute, method: str -) -> str: # pragma: nocover - warnings.warn( - message="fastapi.openapi.utils.generate_operation_id() was deprecated, " - "it is not used internally, and will be removed soon", - category=FastAPIDeprecationWarning, - stacklevel=2, - ) - if route.operation_id: - return route.operation_id - path: str = route.path_format - return generate_operation_id_for_path(name=route.name, path=path, method=method) - - -def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str: - if route.summary: - return route.summary - return route.name.replace("_", " ").title() - - -def get_openapi_operation_metadata( - *, route: routing.APIRoute, method: str, operation_ids: set[str] -) -> dict[str, Any]: - operation: dict[str, Any] = {} - if route.tags: - operation["tags"] = route.tags - operation["summary"] = generate_operation_summary(route=route, method=method) - if route.description: - operation["description"] = route.description - operation_id = route.operation_id or route.unique_id - if operation_id in operation_ids: - message = ( - f"Duplicate Operation ID {operation_id} for function " - + f"{route.endpoint.__name__}" - ) - file_name = getattr(route.endpoint, "__globals__", {}).get("__file__") - if file_name: - message += f" at {file_name}" - warnings.warn(message, stacklevel=1) - operation_ids.add(operation_id) - operation["operationId"] = operation_id - if route.deprecated: - operation["deprecated"] = route.deprecated - return operation - - -def get_openapi_path( - *, - route: routing.APIRoute, - operation_ids: set[str], - model_name_map: ModelNameMap, - field_mapping: dict[ - tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] - ], - separate_input_output_schemas: bool = True, -) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]: - path = {} - security_schemes: dict[str, Any] = {} - definitions: dict[str, Any] = {} - assert route.methods is not None, "Methods must be a list" - if isinstance(route.response_class, DefaultPlaceholder): - current_response_class: type[Response] = route.response_class.value - else: - current_response_class = route.response_class - assert current_response_class, "A response class is needed to generate OpenAPI" - route_response_media_type: Optional[str] = current_response_class.media_type - if route.include_in_schema: - for method in route.methods: - operation = get_openapi_operation_metadata( - route=route, method=method, operation_ids=operation_ids - ) - parameters: list[dict[str, Any]] = [] - flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True) - security_definitions, operation_security = get_openapi_security_definitions( - flat_dependant=flat_dependant - ) - if operation_security: - operation.setdefault("security", []).extend(operation_security) - if security_definitions: - security_schemes.update(security_definitions) - operation_parameters = _get_openapi_operation_parameters( - dependant=route.dependant, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - parameters.extend(operation_parameters) - if parameters: - all_parameters = { - (param["in"], param["name"]): param for param in parameters - } - required_parameters = { - (param["in"], param["name"]): param - for param in parameters - if param.get("required") - } - # Make sure required definitions of the same parameter take precedence - # over non-required definitions - all_parameters.update(required_parameters) - operation["parameters"] = list(all_parameters.values()) - if method in METHODS_WITH_BODY: - request_body_oai = get_openapi_operation_request_body( - body_field=route.body_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if request_body_oai: - operation["requestBody"] = request_body_oai - if route.callbacks: - callbacks = {} - for callback in route.callbacks: - if isinstance(callback, routing.APIRoute): - ( - cb_path, - cb_security_schemes, - cb_definitions, - ) = get_openapi_path( - route=callback, - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - callbacks[callback.name] = {callback.path: cb_path} - operation["callbacks"] = callbacks - if route.status_code is not None: - status_code = str(route.status_code) - else: - # It would probably make more sense for all response classes to have an - # explicit default status_code, and to extract it from them, instead of - # doing this inspection tricks, that would probably be in the future - # TODO: probably make status_code a default class attribute for all - # responses in Starlette - response_signature = inspect.signature(current_response_class.__init__) - status_code_param = response_signature.parameters.get("status_code") - if status_code_param is not None: - if isinstance(status_code_param.default, int): - status_code = str(status_code_param.default) - operation.setdefault("responses", {}).setdefault(status_code, {})[ - "description" - ] = route.response_description - if route_response_media_type and is_body_allowed_for_status_code( - route.status_code - ): - response_schema = {"type": "string"} - if lenient_issubclass(current_response_class, JSONResponse): - if route.response_field: - response_schema = get_schema_from_model_field( - field=route.response_field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - else: - response_schema = {} - operation.setdefault("responses", {}).setdefault( - status_code, {} - ).setdefault("content", {}).setdefault(route_response_media_type, {})[ - "schema" - ] = response_schema - if route.responses: - operation_responses = operation.setdefault("responses", {}) - for ( - additional_status_code, - additional_response, - ) in route.responses.items(): - process_response = additional_response.copy() - process_response.pop("model", None) - status_code_key = str(additional_status_code).upper() - if status_code_key == "DEFAULT": - status_code_key = "default" - openapi_response = operation_responses.setdefault( - status_code_key, {} - ) - assert isinstance(process_response, dict), ( - "An additional response must be a dict" - ) - field = route.response_fields.get(additional_status_code) - additional_field_schema: Optional[dict[str, Any]] = None - if field: - additional_field_schema = get_schema_from_model_field( - field=field, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - media_type = route_response_media_type or "application/json" - additional_schema = ( - process_response.setdefault("content", {}) - .setdefault(media_type, {}) - .setdefault("schema", {}) - ) - deep_dict_update(additional_schema, additional_field_schema) - status_text: Optional[str] = status_code_ranges.get( - str(additional_status_code).upper() - ) or http.client.responses.get(int(additional_status_code)) - description = ( - process_response.get("description") - or openapi_response.get("description") - or status_text - or "Additional Response" - ) - deep_dict_update(openapi_response, process_response) - openapi_response["description"] = description - http422 = "422" - all_route_params = get_flat_params(route.dependant) - if (all_route_params or route.body_field) and not any( - status in operation["responses"] - for status in [http422, "4XX", "default"] - ): - operation["responses"][http422] = { - "description": "Validation Error", - "content": { - "application/json": { - "schema": {"$ref": REF_PREFIX + "HTTPValidationError"} - } - }, - } - if "ValidationError" not in definitions: - definitions.update( - { - "ValidationError": validation_error_definition, - "HTTPValidationError": validation_error_response_definition, - } - ) - if route.openapi_extra: - deep_dict_update(operation, route.openapi_extra) - path[method.lower()] = operation - return path, security_schemes, definitions - - -def get_fields_from_routes( - routes: Sequence[BaseRoute], -) -> list[ModelField]: - body_fields_from_routes: list[ModelField] = [] - responses_from_routes: list[ModelField] = [] - request_fields_from_routes: list[ModelField] = [] - callback_flat_models: list[ModelField] = [] - for route in routes: - if getattr(route, "include_in_schema", None) and isinstance( - route, routing.APIRoute - ): - if route.body_field: - assert isinstance(route.body_field, ModelField), ( - "A request body must be a Pydantic Field" - ) - body_fields_from_routes.append(route.body_field) - if route.response_field: - responses_from_routes.append(route.response_field) - if route.response_fields: - responses_from_routes.extend(route.response_fields.values()) - if route.callbacks: - callback_flat_models.extend(get_fields_from_routes(route.callbacks)) - params = get_flat_params(route.dependant) - request_fields_from_routes.extend(params) - - flat_models = callback_flat_models + list( - body_fields_from_routes + responses_from_routes + request_fields_from_routes - ) - return flat_models - - -def get_openapi( - *, - title: str, - version: str, - openapi_version: str = "3.1.0", - summary: Optional[str] = None, - description: Optional[str] = None, - routes: Sequence[BaseRoute], - webhooks: Optional[Sequence[BaseRoute]] = None, - tags: Optional[list[dict[str, Any]]] = None, - servers: Optional[list[dict[str, Union[str, Any]]]] = None, - terms_of_service: Optional[str] = None, - contact: Optional[dict[str, Union[str, Any]]] = None, - license_info: Optional[dict[str, Union[str, Any]]] = None, - separate_input_output_schemas: bool = True, - external_docs: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - info: dict[str, Any] = {"title": title, "version": version} - if summary: - info["summary"] = summary - if description: - info["description"] = description - if terms_of_service: - info["termsOfService"] = terms_of_service - if contact: - info["contact"] = contact - if license_info: - info["license"] = license_info - output: dict[str, Any] = {"openapi": openapi_version, "info": info} - if servers: - output["servers"] = servers - components: dict[str, dict[str, Any]] = {} - paths: dict[str, dict[str, Any]] = {} - webhook_paths: dict[str, dict[str, Any]] = {} - operation_ids: set[str] = set() - all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or [])) - model_name_map = get_compat_model_name_map(all_fields) - field_mapping, definitions = get_definitions( - fields=all_fields, - model_name_map=model_name_map, - separate_input_output_schemas=separate_input_output_schemas, - ) - for route in routes or []: - if isinstance(route, routing.APIRoute): - result = get_openapi_path( - route=route, - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if result: - path, security_schemes, path_definitions = result - if path: - paths.setdefault(route.path_format, {}).update(path) - if security_schemes: - components.setdefault("securitySchemes", {}).update( - security_schemes - ) - if path_definitions: - definitions.update(path_definitions) - for webhook in webhooks or []: - if isinstance(webhook, routing.APIRoute): - result = get_openapi_path( - route=webhook, - operation_ids=operation_ids, - model_name_map=model_name_map, - field_mapping=field_mapping, - separate_input_output_schemas=separate_input_output_schemas, - ) - if result: - path, security_schemes, path_definitions = result - if path: - webhook_paths.setdefault(webhook.path_format, {}).update(path) - if security_schemes: - components.setdefault("securitySchemes", {}).update( - security_schemes - ) - if path_definitions: - definitions.update(path_definitions) - if definitions: - components["schemas"] = {k: definitions[k] for k in sorted(definitions)} - if components: - output["components"] = components - output["paths"] = paths - if webhook_paths: - output["webhooks"] = webhook_paths - if tags: - output["tags"] = tags - if external_docs: - output["externalDocs"] = external_docs - return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/param_functions.py b/backend/venv39/lib/python3.9/site-packages/fastapi/param_functions.py deleted file mode 100644 index 0834fd7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/param_functions.py +++ /dev/null @@ -1,2369 +0,0 @@ -from collections.abc import Sequence -from typing import Annotated, Any, Callable, Optional, Union - -from annotated_doc import Doc -from fastapi import params -from fastapi._compat import Undefined -from fastapi.openapi.models import Example -from pydantic import AliasChoices, AliasPath -from typing_extensions import Literal, deprecated - -_Unset: Any = Undefined - - -def Path( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = ..., - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - """ - Declare a path parameter for a *path operation*. - - Read more about it in the - [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/). - - ```python - from typing import Annotated - - from fastapi import FastAPI, Path - - app = FastAPI() - - - @app.get("/items/{item_id}") - async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], - ): - return {"item_id": item_id} - ``` - """ - return params.Path( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Query( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Query( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Header( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - convert_underscores: Annotated[ - bool, - Doc( - """ - Automatically convert underscores to hyphens in the parameter field name. - - Read more about it in the - [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion) - """ - ), - ] = True, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Header( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - convert_underscores=convert_underscores, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Cookie( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Cookie( - default=default, - default_factory=default_factory, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Body( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - embed: Annotated[ - Union[bool, None], - Doc( - """ - When `embed` is `True`, the parameter will be expected in a JSON body as a - key instead of being the JSON body itself. - - This happens automatically when more than one `Body` parameter is declared. - - Read more about it in the - [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter). - """ - ), - ] = None, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "application/json", - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Body( - default=default, - default_factory=default_factory, - embed=embed, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Form( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "application/x-www-form-urlencoded", - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.Form( - default=default, - default_factory=default_factory, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def File( # noqa: N802 - default: Annotated[ - Any, - Doc( - """ - Default value if the parameter field is not set. - """ - ), - ] = Undefined, - *, - default_factory: Annotated[ - Union[Callable[[], Any], None], - Doc( - """ - A callable to generate the default value. - - This doesn't affect `Path` parameters as the value is always required. - The parameter is available only for compatibility. - """ - ), - ] = _Unset, - media_type: Annotated[ - str, - Doc( - """ - The media type of this parameter field. Changing it would affect the - generated OpenAPI, but currently it doesn't affect the parsing of the data. - """ - ), - ] = "multipart/form-data", - alias: Annotated[ - Optional[str], - Doc( - """ - An alternative name for the parameter field. - - This will be used to extract the data and for the generated OpenAPI. - It is particularly useful when you can't use the name you want because it - is a Python reserved keyword or similar. - """ - ), - ] = None, - alias_priority: Annotated[ - Union[int, None], - Doc( - """ - Priority of the alias. This affects whether an alias generator is used. - """ - ), - ] = _Unset, - validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], - Doc( - """ - 'Whitelist' validation step. The parameter field will be the single one - allowed by the alias or set of aliases defined. - """ - ), - ] = None, - serialization_alias: Annotated[ - Union[str, None], - Doc( - """ - 'Blacklist' validation step. The vanilla parameter field will be the - single one of the alias' or set of aliases' fields and all the other - fields will be ignored at serialization time. - """ - ), - ] = None, - title: Annotated[ - Optional[str], - Doc( - """ - Human-readable title. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Human-readable description. - """ - ), - ] = None, - gt: Annotated[ - Optional[float], - Doc( - """ - Greater than. If set, value must be greater than this. Only applicable to - numbers. - """ - ), - ] = None, - ge: Annotated[ - Optional[float], - Doc( - """ - Greater than or equal. If set, value must be greater than or equal to - this. Only applicable to numbers. - """ - ), - ] = None, - lt: Annotated[ - Optional[float], - Doc( - """ - Less than. If set, value must be less than this. Only applicable to numbers. - """ - ), - ] = None, - le: Annotated[ - Optional[float], - Doc( - """ - Less than or equal. If set, value must be less than or equal to this. - Only applicable to numbers. - """ - ), - ] = None, - min_length: Annotated[ - Optional[int], - Doc( - """ - Minimum length for strings. - """ - ), - ] = None, - max_length: Annotated[ - Optional[int], - Doc( - """ - Maximum length for strings. - """ - ), - ] = None, - pattern: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - ] = None, - regex: Annotated[ - Optional[str], - Doc( - """ - RegEx pattern for strings. - """ - ), - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Annotated[ - Union[str, None], - Doc( - """ - Parameter field name for discriminating the type in a tagged union. - """ - ), - ] = None, - strict: Annotated[ - Union[bool, None], - Doc( - """ - If `True`, strict validation is applied to the field. - """ - ), - ] = _Unset, - multiple_of: Annotated[ - Union[float, None], - Doc( - """ - Value must be a multiple of this. Only applicable to numbers. - """ - ), - ] = _Unset, - allow_inf_nan: Annotated[ - Union[bool, None], - Doc( - """ - Allow `inf`, `-inf`, `nan`. Only applicable to numbers. - """ - ), - ] = _Unset, - max_digits: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of allow digits for strings. - """ - ), - ] = _Unset, - decimal_places: Annotated[ - Union[int, None], - Doc( - """ - Maximum number of decimal places allowed for numbers. - """ - ), - ] = _Unset, - examples: Annotated[ - Optional[list[Any]], - Doc( - """ - Example values for this field. - """ - ), - ] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Annotated[ - Optional[dict[str, Example]], - Doc( - """ - OpenAPI-specific examples. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Swagger UI (that provides the `/docs` interface) has better support for the - OpenAPI-specific examples than the JSON Schema `examples`, that's the main - use case for this. - - Read more about it in the - [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). - """ - ), - ] = None, - deprecated: Annotated[ - Union[deprecated, str, bool, None], - Doc( - """ - Mark this parameter field as deprecated. - - It will affect the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) this parameter field in the generated OpenAPI. - You probably don't need it, but it's available. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - json_schema_extra: Annotated[ - Union[dict[str, Any], None], - Doc( - """ - Any additional JSON schema data. - """ - ), - ] = None, - **extra: Annotated[ - Any, - Doc( - """ - Include extra fields used by the JSON Schema. - """ - ), - deprecated( - """ - The `extra` kwargs is deprecated. Use `json_schema_extra` instead. - """ - ), - ], -) -> Any: - return params.File( - default=default, - default_factory=default_factory, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - example=example, - examples=examples, - openapi_examples=openapi_examples, - deprecated=deprecated, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -def Depends( # noqa: N802 - dependency: Annotated[ - Optional[Callable[..., Any]], - Doc( - """ - A "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you, just pass the object - directly. - """ - ), - ] = None, - *, - use_cache: Annotated[ - bool, - Doc( - """ - By default, after a dependency is called the first time in a request, if - the dependency is declared again for the rest of the request (for example - if the dependency is needed by several dependencies), the value will be - re-used for the rest of the request. - - Set `use_cache` to `False` to disable this behavior and ensure the - dependency is called again (if declared more than once) in the same request. - """ - ), - ] = True, - scope: Annotated[ - Union[Literal["function", "request"], None], - Doc( - """ - Mainly for dependencies with `yield`, define when the dependency function - should start (the code before `yield`) and when it should end (the code - after `yield`). - - * `"function"`: start the dependency before the *path operation function* - that handles the request, end the dependency after the *path operation - function* ends, but **before** the response is sent back to the client. - So, the dependency function will be executed **around** the *path operation - **function***. - * `"request"`: start the dependency before the *path operation function* - that handles the request (similar to when using `"function"`), but end - **after** the response is sent back to the client. So, the dependency - function will be executed **around** the **request** and response cycle. - """ - ), - ] = None, -) -> Any: - """ - Declare a FastAPI dependency. - - It takes a single "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you. - - Read more about it in the - [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/). - - **Example** - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - - app = FastAPI() - - - async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100): - return {"q": q, "skip": skip, "limit": limit} - - - @app.get("/items/") - async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return commons - ``` - """ - return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope) - - -def Security( # noqa: N802 - dependency: Annotated[ - Optional[Callable[..., Any]], - Doc( - """ - A "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you, just pass the object - directly. - """ - ), - ] = None, - *, - scopes: Annotated[ - Optional[Sequence[str]], - Doc( - """ - OAuth2 scopes required for the *path operation* that uses this Security - dependency. - - The term "scope" comes from the OAuth2 specification, it seems to be - intentionally vague and interpretable. It normally refers to permissions, - in cases to roles. - - These scopes are integrated with OpenAPI (and the API docs at `/docs`). - So they are visible in the OpenAPI specification. - ) - """ - ), - ] = None, - use_cache: Annotated[ - bool, - Doc( - """ - By default, after a dependency is called the first time in a request, if - the dependency is declared again for the rest of the request (for example - if the dependency is needed by several dependencies), the value will be - re-used for the rest of the request. - - Set `use_cache` to `False` to disable this behavior and ensure the - dependency is called again (if declared more than once) in the same request. - """ - ), - ] = True, -) -> Any: - """ - Declare a FastAPI Security dependency. - - The only difference with a regular dependency is that it can declare OAuth2 - scopes that will be integrated with OpenAPI and the automatic UI docs (by default - at `/docs`). - - It takes a single "dependable" callable (like a function). - - Don't call it directly, FastAPI will call it for you. - - Read more about it in the - [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and - in the - [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). - - **Example** - - ```python - from typing import Annotated - - from fastapi import Security, FastAPI - - from .db import User - from .security import get_current_active_user - - app = FastAPI() - - @app.get("/users/me/items/") - async def read_own_items( - current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])] - ): - return [{"item_id": "Foo", "owner": current_user.username}] - ``` - """ - return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/params.py b/backend/venv39/lib/python3.9/site-packages/fastapi/params.py deleted file mode 100644 index 72e797f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/params.py +++ /dev/null @@ -1,755 +0,0 @@ -import warnings -from collections.abc import Sequence -from dataclasses import dataclass -from enum import Enum -from typing import Annotated, Any, Callable, Optional, Union - -from fastapi.exceptions import FastAPIDeprecationWarning -from fastapi.openapi.models import Example -from pydantic import AliasChoices, AliasPath -from pydantic.fields import FieldInfo -from typing_extensions import Literal, deprecated - -from ._compat import ( - Undefined, -) - -_Unset: Any = Undefined - - -class ParamTypes(Enum): - query = "query" - header = "header" - path = "path" - cookie = "cookie" - - -class Param(FieldInfo): # type: ignore[misc] - in_: ParamTypes - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - if example is not _Unset: - warnings.warn( - "`example` has been deprecated, please use `examples` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - self.example = example - self.include_in_schema = include_in_schema - self.openapi_examples = openapi_examples - kwargs = dict( - default=default, - default_factory=default_factory, - alias=alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - discriminator=discriminator, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - **extra, - ) - if examples is not None: - kwargs["examples"] = examples - if regex is not None: - warnings.warn( - "`regex` has been deprecated, please use `pattern` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - current_json_schema_extra = json_schema_extra or extra - kwargs["deprecated"] = deprecated - - if serialization_alias in (_Unset, None) and isinstance(alias, str): - serialization_alias = alias - if validation_alias in (_Unset, None): - validation_alias = alias - kwargs.update( - { - "annotation": annotation, - "alias_priority": alias_priority, - "validation_alias": validation_alias, - "serialization_alias": serialization_alias, - "strict": strict, - "json_schema_extra": current_json_schema_extra, - } - ) - kwargs["pattern"] = pattern or regex - - use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset} - - super().__init__(**use_kwargs) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.default})" - - -class Path(Param): # type: ignore[misc] - in_ = ParamTypes.path - - def __init__( - self, - default: Any = ..., - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - assert default is ..., "Path parameters cannot have a default value" - self.in_ = self.in_ - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Query(Param): # type: ignore[misc] - in_ = ParamTypes.query - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Header(Param): # type: ignore[misc] - in_ = ParamTypes.header - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - convert_underscores: bool = True, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - self.convert_underscores = convert_underscores - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Cookie(Param): # type: ignore[misc] - in_ = ParamTypes.cookie - - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class Body(FieldInfo): # type: ignore[misc] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - embed: Union[bool, None] = None, - media_type: str = "application/json", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - self.embed = embed - self.media_type = media_type - if example is not _Unset: - warnings.warn( - "`example` has been deprecated, please use `examples` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - self.example = example - self.include_in_schema = include_in_schema - self.openapi_examples = openapi_examples - kwargs = dict( - default=default, - default_factory=default_factory, - alias=alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - discriminator=discriminator, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - **extra, - ) - if examples is not None: - kwargs["examples"] = examples - if regex is not None: - warnings.warn( - "`regex` has been deprecated, please use `pattern` instead", - category=FastAPIDeprecationWarning, - stacklevel=4, - ) - current_json_schema_extra = json_schema_extra or extra - kwargs["deprecated"] = deprecated - if serialization_alias in (_Unset, None) and isinstance(alias, str): - serialization_alias = alias - if validation_alias in (_Unset, None): - validation_alias = alias - kwargs.update( - { - "annotation": annotation, - "alias_priority": alias_priority, - "validation_alias": validation_alias, - "serialization_alias": serialization_alias, - "strict": strict, - "json_schema_extra": current_json_schema_extra, - } - ) - kwargs["pattern"] = pattern or regex - - use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset} - - super().__init__(**use_kwargs) - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.default})" - - -class Form(Body): # type: ignore[misc] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - media_type: str = "application/x-www-form-urlencoded", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -class File(Form): # type: ignore[misc] - def __init__( - self, - default: Any = Undefined, - *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - media_type: str = "multipart/form-data", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, - regex: Annotated[ - Optional[str], - deprecated( - "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." - ), - ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, - example: Annotated[ - Optional[Any], - deprecated( - "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " - "although still supported. Use examples instead." - ), - ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, - include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, - **extra: Any, - ): - super().__init__( - default=default, - default_factory=default_factory, - annotation=annotation, - media_type=media_type, - alias=alias, - alias_priority=alias_priority, - validation_alias=validation_alias, - serialization_alias=serialization_alias, - title=title, - description=description, - gt=gt, - ge=ge, - lt=lt, - le=le, - min_length=min_length, - max_length=max_length, - pattern=pattern, - regex=regex, - discriminator=discriminator, - strict=strict, - multiple_of=multiple_of, - allow_inf_nan=allow_inf_nan, - max_digits=max_digits, - decimal_places=decimal_places, - deprecated=deprecated, - example=example, - examples=examples, - openapi_examples=openapi_examples, - include_in_schema=include_in_schema, - json_schema_extra=json_schema_extra, - **extra, - ) - - -@dataclass(frozen=True) -class Depends: - dependency: Optional[Callable[..., Any]] = None - use_cache: bool = True - scope: Union[Literal["function", "request"], None] = None - - -@dataclass(frozen=True) -class Security(Depends): - scopes: Optional[Sequence[str]] = None diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/py.typed b/backend/venv39/lib/python3.9/site-packages/fastapi/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/requests.py b/backend/venv39/lib/python3.9/site-packages/fastapi/requests.py deleted file mode 100644 index d16552c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/requests.py +++ /dev/null @@ -1,2 +0,0 @@ -from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401 -from starlette.requests import Request as Request # noqa: F401 diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/responses.py b/backend/venv39/lib/python3.9/site-packages/fastapi/responses.py deleted file mode 100644 index 6c8db6f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/responses.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import Any - -from starlette.responses import FileResponse as FileResponse # noqa -from starlette.responses import HTMLResponse as HTMLResponse # noqa -from starlette.responses import JSONResponse as JSONResponse # noqa -from starlette.responses import PlainTextResponse as PlainTextResponse # noqa -from starlette.responses import RedirectResponse as RedirectResponse # noqa -from starlette.responses import Response as Response # noqa -from starlette.responses import StreamingResponse as StreamingResponse # noqa - -try: - import ujson -except ImportError: # pragma: nocover - ujson = None # type: ignore - - -try: - import orjson -except ImportError: # pragma: nocover - orjson = None # type: ignore - - -class UJSONResponse(JSONResponse): - """ - JSON response using the high-performance ujson library to serialize data to JSON. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). - """ - - def render(self, content: Any) -> bytes: - assert ujson is not None, "ujson must be installed to use UJSONResponse" - return ujson.dumps(content, ensure_ascii=False).encode("utf-8") - - -class ORJSONResponse(JSONResponse): - """ - JSON response using the high-performance orjson library to serialize data to JSON. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). - """ - - def render(self, content: Any) -> bytes: - assert orjson is not None, "orjson must be installed to use ORJSONResponse" - return orjson.dumps( - content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY - ) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/routing.py b/backend/venv39/lib/python3.9/site-packages/fastapi/routing.py deleted file mode 100644 index 9ca2f46..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/routing.py +++ /dev/null @@ -1,4508 +0,0 @@ -import email.message -import functools -import inspect -import json -from collections.abc import ( - AsyncIterator, - Awaitable, - Collection, - Coroutine, - Mapping, - Sequence, -) -from contextlib import AsyncExitStack, asynccontextmanager -from enum import Enum, IntEnum -from typing import ( - Annotated, - Any, - Callable, - Optional, - Union, -) - -from annotated_doc import Doc -from fastapi import params -from fastapi._compat import ( - ModelField, - Undefined, - annotation_is_pydantic_v1, - lenient_issubclass, -) -from fastapi.datastructures import Default, DefaultPlaceholder -from fastapi.dependencies.models import Dependant -from fastapi.dependencies.utils import ( - _should_embed_body_fields, - get_body_field, - get_dependant, - get_flat_dependant, - get_parameterless_sub_dependant, - get_typed_return_annotation, - solve_dependencies, -) -from fastapi.encoders import jsonable_encoder -from fastapi.exceptions import ( - EndpointContext, - FastAPIError, - PydanticV1NotSupportedError, - RequestValidationError, - ResponseValidationError, - WebSocketRequestValidationError, -) -from fastapi.types import DecoratedCallable, IncEx -from fastapi.utils import ( - create_cloned_field, - create_model_field, - generate_unique_id, - get_value_or_default, - is_body_allowed_for_status_code, -) -from starlette import routing -from starlette._exception_handler import wrap_app_handling_exceptions -from starlette._utils import is_async_callable -from starlette.concurrency import run_in_threadpool -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.responses import JSONResponse, Response -from starlette.routing import ( - BaseRoute, - Match, - compile_path, - get_name, -) -from starlette.routing import Mount as Mount # noqa -from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send -from starlette.websockets import WebSocket -from typing_extensions import deprecated - - -# Copy of starlette.routing.request_response modified to include the -# dependencies' AsyncExitStack -def request_response( - func: Callable[[Request], Union[Awaitable[Response], Response]], -) -> ASGIApp: - """ - Takes a function or coroutine `func(request) -> response`, - and returns an ASGI application. - """ - f: Callable[[Request], Awaitable[Response]] = ( - func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore - ) - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - request = Request(scope, receive, send) - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - # Starts customization - response_awaited = False - async with AsyncExitStack() as request_stack: - scope["fastapi_inner_astack"] = request_stack - async with AsyncExitStack() as function_stack: - scope["fastapi_function_astack"] = function_stack - response = await f(request) - await response(scope, receive, send) - # Continues customization - response_awaited = True - if not response_awaited: - raise FastAPIError( - "Response not awaited. There's a high chance that the " - "application code is raising an exception and a dependency with yield " - "has a block with a bare except, or a block with except Exception, " - "and is not raising the exception again. Read more about it in the " - "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except" - ) - - # Same as in Starlette - await wrap_app_handling_exceptions(app, request)(scope, receive, send) - - return app - - -# Copy of starlette.routing.websocket_session modified to include the -# dependencies' AsyncExitStack -def websocket_session( - func: Callable[[WebSocket], Awaitable[None]], -) -> ASGIApp: - """ - Takes a coroutine `func(session)`, and returns an ASGI application. - """ - # assert asyncio.iscoroutinefunction(func), "WebSocket endpoints must be async" - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - session = WebSocket(scope, receive=receive, send=send) - - async def app(scope: Scope, receive: Receive, send: Send) -> None: - async with AsyncExitStack() as request_stack: - scope["fastapi_inner_astack"] = request_stack - async with AsyncExitStack() as function_stack: - scope["fastapi_function_astack"] = function_stack - await func(session) - - # Same as in Starlette - await wrap_app_handling_exceptions(app, session)(scope, receive, send) - - return app - - -def _merge_lifespan_context( - original_context: Lifespan[Any], nested_context: Lifespan[Any] -) -> Lifespan[Any]: - @asynccontextmanager - async def merged_lifespan( - app: AppType, - ) -> AsyncIterator[Optional[Mapping[str, Any]]]: - async with original_context(app) as maybe_original_state: - async with nested_context(app) as maybe_nested_state: - if maybe_nested_state is None and maybe_original_state is None: - yield None # old ASGI compatibility - else: - yield {**(maybe_nested_state or {}), **(maybe_original_state or {})} - - return merged_lifespan # type: ignore[return-value] - - -# Cache for endpoint context to avoid re-extracting on every request -_endpoint_context_cache: dict[int, EndpointContext] = {} - - -def _extract_endpoint_context(func: Any) -> EndpointContext: - """Extract endpoint context with caching to avoid repeated file I/O.""" - func_id = id(func) - - if func_id in _endpoint_context_cache: - return _endpoint_context_cache[func_id] - - try: - ctx: EndpointContext = {} - - if (source_file := inspect.getsourcefile(func)) is not None: - ctx["file"] = source_file - if (line_number := inspect.getsourcelines(func)[1]) is not None: - ctx["line"] = line_number - if (func_name := getattr(func, "__name__", None)) is not None: - ctx["function"] = func_name - except Exception: - ctx = EndpointContext() - - _endpoint_context_cache[func_id] = ctx - return ctx - - -async def serialize_response( - *, - field: Optional[ModelField] = None, - response_content: Any, - include: Optional[IncEx] = None, - exclude: Optional[IncEx] = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - is_coroutine: bool = True, - endpoint_ctx: Optional[EndpointContext] = None, -) -> Any: - if field: - errors = [] - if is_coroutine: - value, errors_ = field.validate(response_content, {}, loc=("response",)) - else: - value, errors_ = await run_in_threadpool( - field.validate, response_content, {}, loc=("response",) - ) - if isinstance(errors_, list): - errors.extend(errors_) - if errors: - ctx = endpoint_ctx or EndpointContext() - raise ResponseValidationError( - errors=errors, - body=response_content, - endpoint_ctx=ctx, - ) - - return field.serialize( - value, - include=include, - exclude=exclude, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - else: - return jsonable_encoder(response_content) - - -async def run_endpoint_function( - *, dependant: Dependant, values: dict[str, Any], is_coroutine: bool -) -> Any: - # Only called by get_request_handler. Has been split into its own function to - # facilitate profiling endpoints, since inner functions are harder to profile. - assert dependant.call is not None, "dependant.call must be a function" - - if is_coroutine: - return await dependant.call(**values) - else: - return await run_in_threadpool(dependant.call, **values) - - -def get_request_handler( - dependant: Dependant, - body_field: Optional[ModelField] = None, - status_code: Optional[int] = None, - response_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse), - response_field: Optional[ModelField] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - dependency_overrides_provider: Optional[Any] = None, - embed_body_fields: bool = False, -) -> Callable[[Request], Coroutine[Any, Any, Response]]: - assert dependant.call is not None, "dependant.call must be a function" - is_coroutine = dependant.is_coroutine_callable - is_body_form = body_field and isinstance(body_field.field_info, params.Form) - if isinstance(response_class, DefaultPlaceholder): - actual_response_class: type[Response] = response_class.value - else: - actual_response_class = response_class - - async def app(request: Request) -> Response: - response: Union[Response, None] = None - file_stack = request.scope.get("fastapi_middleware_astack") - assert isinstance(file_stack, AsyncExitStack), ( - "fastapi_middleware_astack not found in request scope" - ) - - # Extract endpoint context for error messages - endpoint_ctx = ( - _extract_endpoint_context(dependant.call) - if dependant.call - else EndpointContext() - ) - - if dependant.path: - # For mounted sub-apps, include the mount path prefix - mount_path = request.scope.get("root_path", "").rstrip("/") - endpoint_ctx["path"] = f"{request.method} {mount_path}{dependant.path}" - - # Read body and auto-close files - try: - body: Any = None - if body_field: - if is_body_form: - body = await request.form() - file_stack.push_async_callback(body.close) - else: - body_bytes = await request.body() - if body_bytes: - json_body: Any = Undefined - content_type_value = request.headers.get("content-type") - if not content_type_value: - json_body = await request.json() - else: - message = email.message.Message() - message["content-type"] = content_type_value - if message.get_content_maintype() == "application": - subtype = message.get_content_subtype() - if subtype == "json" or subtype.endswith("+json"): - json_body = await request.json() - if json_body != Undefined: - body = json_body - else: - body = body_bytes - except json.JSONDecodeError as e: - validation_error = RequestValidationError( - [ - { - "type": "json_invalid", - "loc": ("body", e.pos), - "msg": "JSON decode error", - "input": {}, - "ctx": {"error": e.msg}, - } - ], - body=e.doc, - endpoint_ctx=endpoint_ctx, - ) - raise validation_error from e - except HTTPException: - # If a middleware raises an HTTPException, it should be raised again - raise - except Exception as e: - http_error = HTTPException( - status_code=400, detail="There was an error parsing the body" - ) - raise http_error from e - - # Solve dependencies and run path operation function, auto-closing dependencies - errors: list[Any] = [] - async_exit_stack = request.scope.get("fastapi_inner_astack") - assert isinstance(async_exit_stack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - solved_result = await solve_dependencies( - request=request, - dependant=dependant, - body=body, - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - errors = solved_result.errors - if not errors: - raw_response = await run_endpoint_function( - dependant=dependant, - values=solved_result.values, - is_coroutine=is_coroutine, - ) - if isinstance(raw_response, Response): - if raw_response.background is None: - raw_response.background = solved_result.background_tasks - response = raw_response - else: - response_args: dict[str, Any] = { - "background": solved_result.background_tasks - } - # If status_code was set, use it, otherwise use the default from the - # response class, in the case of redirect it's 307 - current_status_code = ( - status_code if status_code else solved_result.response.status_code - ) - if current_status_code is not None: - response_args["status_code"] = current_status_code - if solved_result.response.status_code: - response_args["status_code"] = solved_result.response.status_code - content = await serialize_response( - field=response_field, - response_content=raw_response, - include=response_model_include, - exclude=response_model_exclude, - by_alias=response_model_by_alias, - exclude_unset=response_model_exclude_unset, - exclude_defaults=response_model_exclude_defaults, - exclude_none=response_model_exclude_none, - is_coroutine=is_coroutine, - endpoint_ctx=endpoint_ctx, - ) - response = actual_response_class(content, **response_args) - if not is_body_allowed_for_status_code(response.status_code): - response.body = b"" - response.headers.raw.extend(solved_result.response.headers.raw) - if errors: - validation_error = RequestValidationError( - errors, body=body, endpoint_ctx=endpoint_ctx - ) - raise validation_error - - # Return response - assert response - return response - - return app - - -def get_websocket_app( - dependant: Dependant, - dependency_overrides_provider: Optional[Any] = None, - embed_body_fields: bool = False, -) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]: - async def app(websocket: WebSocket) -> None: - endpoint_ctx = ( - _extract_endpoint_context(dependant.call) - if dependant.call - else EndpointContext() - ) - if dependant.path: - # For mounted sub-apps, include the mount path prefix - mount_path = websocket.scope.get("root_path", "").rstrip("/") - endpoint_ctx["path"] = f"WS {mount_path}{dependant.path}" - async_exit_stack = websocket.scope.get("fastapi_inner_astack") - assert isinstance(async_exit_stack, AsyncExitStack), ( - "fastapi_inner_astack not found in request scope" - ) - solved_result = await solve_dependencies( - request=websocket, - dependant=dependant, - dependency_overrides_provider=dependency_overrides_provider, - async_exit_stack=async_exit_stack, - embed_body_fields=embed_body_fields, - ) - if solved_result.errors: - raise WebSocketRequestValidationError( - solved_result.errors, - endpoint_ctx=endpoint_ctx, - ) - assert dependant.call is not None, "dependant.call must be a function" - await dependant.call(**solved_result.values) - - return app - - -class APIWebSocketRoute(routing.WebSocketRoute): - def __init__( - self, - path: str, - endpoint: Callable[..., Any], - *, - name: Optional[str] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - dependency_overrides_provider: Optional[Any] = None, - ) -> None: - self.path = path - self.endpoint = endpoint - self.name = get_name(endpoint) if name is None else name - self.dependencies = list(dependencies or []) - self.path_regex, self.path_format, self.param_convertors = compile_path(path) - self.dependant = get_dependant( - path=self.path_format, call=self.endpoint, scope="function" - ) - for depends in self.dependencies[::-1]: - self.dependant.dependencies.insert( - 0, - get_parameterless_sub_dependant(depends=depends, path=self.path_format), - ) - self._flat_dependant = get_flat_dependant(self.dependant) - self._embed_body_fields = _should_embed_body_fields( - self._flat_dependant.body_params - ) - self.app = websocket_session( - get_websocket_app( - dependant=self.dependant, - dependency_overrides_provider=dependency_overrides_provider, - embed_body_fields=self._embed_body_fields, - ) - ) - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - match, child_scope = super().matches(scope) - if match != Match.NONE: - child_scope["route"] = self - return match, child_scope - - -class APIRoute(routing.Route): - def __init__( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - name: Optional[str] = None, - methods: Optional[Union[set[str], list[str]]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - dependency_overrides_provider: Optional[Any] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Union[ - Callable[["APIRoute"], str], DefaultPlaceholder - ] = Default(generate_unique_id), - ) -> None: - self.path = path - self.endpoint = endpoint - if isinstance(response_model, DefaultPlaceholder): - return_annotation = get_typed_return_annotation(endpoint) - if lenient_issubclass(return_annotation, Response): - response_model = None - else: - response_model = return_annotation - self.response_model = response_model - self.summary = summary - self.response_description = response_description - self.deprecated = deprecated - self.operation_id = operation_id - self.response_model_include = response_model_include - self.response_model_exclude = response_model_exclude - self.response_model_by_alias = response_model_by_alias - self.response_model_exclude_unset = response_model_exclude_unset - self.response_model_exclude_defaults = response_model_exclude_defaults - self.response_model_exclude_none = response_model_exclude_none - self.include_in_schema = include_in_schema - self.response_class = response_class - self.dependency_overrides_provider = dependency_overrides_provider - self.callbacks = callbacks - self.openapi_extra = openapi_extra - self.generate_unique_id_function = generate_unique_id_function - self.tags = tags or [] - self.responses = responses or {} - self.name = get_name(endpoint) if name is None else name - self.path_regex, self.path_format, self.param_convertors = compile_path(path) - if methods is None: - methods = ["GET"] - self.methods: set[str] = {method.upper() for method in methods} - if isinstance(generate_unique_id_function, DefaultPlaceholder): - current_generate_unique_id: Callable[[APIRoute], str] = ( - generate_unique_id_function.value - ) - else: - current_generate_unique_id = generate_unique_id_function - self.unique_id = self.operation_id or current_generate_unique_id(self) - # normalize enums e.g. http.HTTPStatus - if isinstance(status_code, IntEnum): - status_code = int(status_code) - self.status_code = status_code - if self.response_model: - assert is_body_allowed_for_status_code(status_code), ( - f"Status code {status_code} must not have a response body" - ) - response_name = "Response_" + self.unique_id - if annotation_is_pydantic_v1(self.response_model): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" Please update the response model {self.response_model!r}." - ) - self.response_field = create_model_field( - name=response_name, - type_=self.response_model, - mode="serialization", - ) - # Create a clone of the field, so that a Pydantic submodel is not returned - # as is just because it's an instance of a subclass of a more limited class - # e.g. UserInDB (containing hashed_password) could be a subclass of User - # that doesn't have the hashed_password. But because it's a subclass, it - # would pass the validation and be returned as is. - # By being a new field, no inheritance will be passed as is. A new model - # will always be created. - # TODO: remove when deprecating Pydantic v1 - self.secure_cloned_response_field: Optional[ModelField] = ( - create_cloned_field(self.response_field) - ) - else: - self.response_field = None # type: ignore - self.secure_cloned_response_field = None - self.dependencies = list(dependencies or []) - self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "") - # if a "form feed" character (page break) is found in the description text, - # truncate description text to the content preceding the first "form feed" - self.description = self.description.split("\f")[0].strip() - response_fields = {} - for additional_status_code, response in self.responses.items(): - assert isinstance(response, dict), "An additional response must be a dict" - model = response.get("model") - if model: - assert is_body_allowed_for_status_code(additional_status_code), ( - f"Status code {additional_status_code} must not have a response body" - ) - response_name = f"Response_{additional_status_code}_{self.unique_id}" - if annotation_is_pydantic_v1(model): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" In responses={{}}, please update {model}." - ) - response_field = create_model_field( - name=response_name, type_=model, mode="serialization" - ) - response_fields[additional_status_code] = response_field - if response_fields: - self.response_fields: dict[Union[int, str], ModelField] = response_fields - else: - self.response_fields = {} - - assert callable(endpoint), "An endpoint must be a callable" - self.dependant = get_dependant( - path=self.path_format, call=self.endpoint, scope="function" - ) - for depends in self.dependencies[::-1]: - self.dependant.dependencies.insert( - 0, - get_parameterless_sub_dependant(depends=depends, path=self.path_format), - ) - self._flat_dependant = get_flat_dependant(self.dependant) - self._embed_body_fields = _should_embed_body_fields( - self._flat_dependant.body_params - ) - self.body_field = get_body_field( - flat_dependant=self._flat_dependant, - name=self.unique_id, - embed_body_fields=self._embed_body_fields, - ) - self.app = request_response(self.get_route_handler()) - - def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]: - return get_request_handler( - dependant=self.dependant, - body_field=self.body_field, - status_code=self.status_code, - response_class=self.response_class, - response_field=self.secure_cloned_response_field, - response_model_include=self.response_model_include, - response_model_exclude=self.response_model_exclude, - response_model_by_alias=self.response_model_by_alias, - response_model_exclude_unset=self.response_model_exclude_unset, - response_model_exclude_defaults=self.response_model_exclude_defaults, - response_model_exclude_none=self.response_model_exclude_none, - dependency_overrides_provider=self.dependency_overrides_provider, - embed_body_fields=self._embed_body_fields, - ) - - def matches(self, scope: Scope) -> tuple[Match, Scope]: - match, child_scope = super().matches(scope) - if match != Match.NONE: - child_scope["route"] = self - return match, child_scope - - -class APIRouter(routing.Router): - """ - `APIRouter` class, used to group *path operations*, for example to structure - an app in multiple files. It would then be included in the `FastAPI` app, or - in another `APIRouter` (ultimately included in the app). - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - - @router.get("/users/", tags=["users"]) - async def read_users(): - return [{"username": "Rick"}, {"username": "Morty"}] - - - app.include_router(router) - ``` - """ - - def __init__( - self, - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - """ - ), - ] = Default(JSONResponse), - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - OpenAPI callbacks that should apply to all *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - routes: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - **Note**: you probably shouldn't use this parameter, it is inherited - from Starlette and supported for compatibility. - - --- - - A list of routes to serve incoming HTTP and WebSocket requests. - """ - ), - deprecated( - """ - You normally wouldn't use this parameter with FastAPI, it is inherited - from Starlette and supported for compatibility. - - In FastAPI, you normally would use the *path operation methods*, - like `router.get()`, `router.post()`, etc. - """ - ), - ] = None, - redirect_slashes: Annotated[ - bool, - Doc( - """ - Whether to detect and redirect slashes in URLs when the client doesn't - use the same format. - """ - ), - ] = True, - default: Annotated[ - Optional[ASGIApp], - Doc( - """ - Default function handler for this router. Used to handle - 404 Not Found errors. - """ - ), - ] = None, - dependency_overrides_provider: Annotated[ - Optional[Any], - Doc( - """ - Only used internally by FastAPI to handle dependency overrides. - - You shouldn't need to use it. It normally points to the `FastAPI` app - object. - """ - ), - ] = None, - route_class: Annotated[ - type[APIRoute], - Doc( - """ - Custom route (*path operation*) class to be used by this router. - - Read more about it in the - [FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router). - """ - ), - ] = APIRoute, - on_startup: Annotated[ - Optional[Sequence[Callable[[], Any]]], - Doc( - """ - A list of startup event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - on_shutdown: Annotated[ - Optional[Sequence[Callable[[], Any]]], - Doc( - """ - A list of shutdown event handler functions. - - You should instead use the `lifespan` handlers. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - # the generic to Lifespan[AppType] is the type of the top level application - # which the router cannot know statically, so we use typing.Any - lifespan: Annotated[ - Optional[Lifespan[Any]], - Doc( - """ - A `Lifespan` context manager handler. This replaces `startup` and - `shutdown` functions with a single context manager. - - Read more in the - [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark all *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - To include (or not) all the *path operations* in this router in the - generated OpenAPI. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> None: - super().__init__( - routes=routes, - redirect_slashes=redirect_slashes, - default=default, - on_startup=on_startup, - on_shutdown=on_shutdown, - lifespan=lifespan, - ) - if prefix: - assert prefix.startswith("/"), "A path prefix must start with '/'" - assert not prefix.endswith("/"), ( - "A path prefix must not end with '/', as the routes will start with '/'" - ) - self.prefix = prefix - self.tags: list[Union[str, Enum]] = tags or [] - self.dependencies = list(dependencies or []) - self.deprecated = deprecated - self.include_in_schema = include_in_schema - self.responses = responses or {} - self.callbacks = callbacks or [] - self.dependency_overrides_provider = dependency_overrides_provider - self.route_class = route_class - self.default_response_class = default_response_class - self.generate_unique_id_function = generate_unique_id_function - - def route( - self, - path: str, - methods: Optional[Collection[str]] = None, - name: Optional[str] = None, - include_in_schema: bool = True, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_route( - path, - func, - methods=methods, - name=name, - include_in_schema=include_in_schema, - ) - return func - - return decorator - - def add_api_route( - self, - path: str, - endpoint: Callable[..., Any], - *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[Union[set[str], list[str]]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - name: Optional[str] = None, - route_class_override: Optional[type[APIRoute]] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Union[ - Callable[[APIRoute], str], DefaultPlaceholder - ] = Default(generate_unique_id), - ) -> None: - route_class = route_class_override or self.route_class - responses = responses or {} - combined_responses = {**self.responses, **responses} - current_response_class = get_value_or_default( - response_class, self.default_response_class - ) - current_tags = self.tags.copy() - if tags: - current_tags.extend(tags) - current_dependencies = self.dependencies.copy() - if dependencies: - current_dependencies.extend(dependencies) - current_callbacks = self.callbacks.copy() - if callbacks: - current_callbacks.extend(callbacks) - current_generate_unique_id = get_value_or_default( - generate_unique_id_function, self.generate_unique_id_function - ) - route = route_class( - self.prefix + path, - endpoint=endpoint, - response_model=response_model, - status_code=status_code, - tags=current_tags, - dependencies=current_dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=combined_responses, - deprecated=deprecated or self.deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema and self.include_in_schema, - response_class=current_response_class, - name=name, - dependency_overrides_provider=self.dependency_overrides_provider, - callbacks=current_callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=current_generate_unique_id, - ) - self.routes.append(route) - - def api_route( - self, - path: str, - *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_route( - path, - func, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=methods, - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - return func - - return decorator - - def add_api_websocket_route( - self, - path: str, - endpoint: Callable[..., Any], - name: Optional[str] = None, - *, - dependencies: Optional[Sequence[params.Depends]] = None, - ) -> None: - current_dependencies = self.dependencies.copy() - if dependencies: - current_dependencies.extend(dependencies) - - route = APIWebSocketRoute( - self.prefix + path, - endpoint=endpoint, - name=name, - dependencies=current_dependencies, - dependency_overrides_provider=self.dependency_overrides_provider, - ) - self.routes.append(route) - - def websocket( - self, - path: Annotated[ - str, - Doc( - """ - WebSocket path. - """ - ), - ], - name: Annotated[ - Optional[str], - Doc( - """ - A name for the WebSocket. Only used internally. - """ - ), - ] = None, - *, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be used for this - WebSocket. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - """ - ), - ] = None, - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Decorate a WebSocket function. - - Read more about it in the - [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). - - **Example** - - ## Example - - ```python - from fastapi import APIRouter, FastAPI, WebSocket - - app = FastAPI() - router = APIRouter() - - @router.websocket("/ws") - async def websocket_endpoint(websocket: WebSocket): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text(f"Message text was: {data}") - - app.include_router(router) - ``` - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_api_websocket_route( - path, func, name=name, dependencies=dependencies - ) - return func - - return decorator - - def websocket_route( - self, path: str, name: Union[str, None] = None - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_websocket_route(path, func, name=name) - return func - - return decorator - - def include_router( - self, - router: Annotated["APIRouter", Doc("The `APIRouter` to include.")], - *, - prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to all the *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to all the - *path operations* in this router. - - Read more about it in the - [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - default_response_class: Annotated[ - type[Response], - Doc( - """ - The default response class to be used. - - Read more in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). - """ - ), - ] = Default(JSONResponse), - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses to be shown in OpenAPI. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). - - And in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - OpenAPI callbacks that should apply to all *path operations* in this - router. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark all *path operations* in this router as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include (or not) all the *path operations* in this router in the - generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = True, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> None: - """ - Include another `APIRouter` in the same current `APIRouter`. - - Read more about it in the - [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - internal_router = APIRouter() - users_router = APIRouter() - - @users_router.get("/users/") - def read_users(): - return [{"name": "Rick"}, {"name": "Morty"}] - - internal_router.include_router(users_router) - app.include_router(internal_router) - ``` - """ - if prefix: - assert prefix.startswith("/"), "A path prefix must start with '/'" - assert not prefix.endswith("/"), ( - "A path prefix must not end with '/', as the routes will start with '/'" - ) - else: - for r in router.routes: - path = getattr(r, "path") # noqa: B009 - name = getattr(r, "name", "unknown") - if path is not None and not path: - raise FastAPIError( - f"Prefix and path cannot be both empty (path operation: {name})" - ) - if responses is None: - responses = {} - for route in router.routes: - if isinstance(route, APIRoute): - combined_responses = {**responses, **route.responses} - use_response_class = get_value_or_default( - route.response_class, - router.default_response_class, - default_response_class, - self.default_response_class, - ) - current_tags = [] - if tags: - current_tags.extend(tags) - if route.tags: - current_tags.extend(route.tags) - current_dependencies: list[params.Depends] = [] - if dependencies: - current_dependencies.extend(dependencies) - if route.dependencies: - current_dependencies.extend(route.dependencies) - current_callbacks = [] - if callbacks: - current_callbacks.extend(callbacks) - if route.callbacks: - current_callbacks.extend(route.callbacks) - current_generate_unique_id = get_value_or_default( - route.generate_unique_id_function, - router.generate_unique_id_function, - generate_unique_id_function, - self.generate_unique_id_function, - ) - self.add_api_route( - prefix + route.path, - route.endpoint, - response_model=route.response_model, - status_code=route.status_code, - tags=current_tags, - dependencies=current_dependencies, - summary=route.summary, - description=route.description, - response_description=route.response_description, - responses=combined_responses, - deprecated=route.deprecated or deprecated or self.deprecated, - methods=route.methods, - operation_id=route.operation_id, - response_model_include=route.response_model_include, - response_model_exclude=route.response_model_exclude, - response_model_by_alias=route.response_model_by_alias, - response_model_exclude_unset=route.response_model_exclude_unset, - response_model_exclude_defaults=route.response_model_exclude_defaults, - response_model_exclude_none=route.response_model_exclude_none, - include_in_schema=route.include_in_schema - and self.include_in_schema - and include_in_schema, - response_class=use_response_class, - name=route.name, - route_class_override=type(route), - callbacks=current_callbacks, - openapi_extra=route.openapi_extra, - generate_unique_id_function=current_generate_unique_id, - ) - elif isinstance(route, routing.Route): - methods = list(route.methods or []) - self.add_route( - prefix + route.path, - route.endpoint, - methods=methods, - include_in_schema=route.include_in_schema, - name=route.name, - ) - elif isinstance(route, APIWebSocketRoute): - current_dependencies = [] - if dependencies: - current_dependencies.extend(dependencies) - if route.dependencies: - current_dependencies.extend(route.dependencies) - self.add_api_websocket_route( - prefix + route.path, - route.endpoint, - dependencies=current_dependencies, - name=route.name, - ) - elif isinstance(route, routing.WebSocketRoute): - self.add_websocket_route( - prefix + route.path, route.endpoint, name=route.name - ) - for handler in router.on_startup: - self.add_event_handler("startup", handler) - for handler in router.on_shutdown: - self.add_event_handler("shutdown", handler) - self.lifespan_context = _merge_lifespan_context( - self.lifespan_context, - router.lifespan_context, - ) - - def get( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP GET operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.get("/items/") - def read_items(): - return [{"name": "Empanada"}, {"name": "Arepa"}] - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["GET"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def put( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PUT operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.put("/items/{item_id}") - def replace_item(item_id: str, item: Item): - return {"message": "Item replaced", "id": item_id} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["PUT"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def post( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP POST operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.post("/items/") - def create_item(item: Item): - return {"message": "Item created"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["POST"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def delete( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP DELETE operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.delete("/items/{item_id}") - def delete_item(item_id: str): - return {"message": "Item deleted"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["DELETE"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def options( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP OPTIONS operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - - app = FastAPI() - router = APIRouter() - - @router.options("/items/") - def get_item_options(): - return {"additions": ["Aji", "Guacamole"]} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["OPTIONS"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def head( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP HEAD operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.head("/items/", status_code=204) - def get_items_headers(response: Response): - response.headers["X-Cat-Dog"] = "Alone in the world" - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["HEAD"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def patch( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP PATCH operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.patch("/items/") - def update_item(item: Item): - return {"message": "Item updated in place"} - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["PATCH"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - def trace( - self, - path: Annotated[ - str, - Doc( - """ - The URL path to be used for this *path operation*. - - For example, in `http://example.com/items`, the path is `/items`. - """ - ), - ], - *, - response_model: Annotated[ - Any, - Doc( - """ - The type to use for the response. - - It could be any valid Pydantic *field* type. So, it doesn't have to - be a Pydantic model, it could be other things, like a `list`, `dict`, - etc. - - It will be used for: - - * Documentation: the generated OpenAPI (and the UI at `/docs`) will - show it as the response (JSON Schema). - * Serialization: you could return an arbitrary object and the - `response_model` would be used to serialize that object into the - corresponding JSON. - * Filtering: the JSON sent to the client will only contain the data - (fields) defined in the `response_model`. If you returned an object - that contains an attribute `password` but the `response_model` does - not include that field, the JSON sent to the client would not have - that `password`. - * Validation: whatever you return will be serialized with the - `response_model`, converting any data as necessary to generate the - corresponding JSON. But if the data in the object returned is not - valid, that would mean a violation of the contract with the client, - so it's an error from the API developer. So, FastAPI will raise an - error and return a 500 error code (Internal Server Error). - - Read more about it in the - [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). - """ - ), - ] = Default(None), - status_code: Annotated[ - Optional[int], - Doc( - """ - The default status code to be used for the response. - - You could override the status code by returning a response directly. - - Read more about it in the - [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). - """ - ), - ] = None, - tags: Annotated[ - Optional[list[Union[str, Enum]]], - Doc( - """ - A list of tags to be applied to the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). - """ - ), - ] = None, - dependencies: Annotated[ - Optional[Sequence[params.Depends]], - Doc( - """ - A list of dependencies (using `Depends()`) to be applied to the - *path operation*. - - Read more about it in the - [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). - """ - ), - ] = None, - summary: Annotated[ - Optional[str], - Doc( - """ - A summary for the *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - A description for the *path operation*. - - If not provided, it will be extracted automatically from the docstring - of the *path operation function*. - - It can contain Markdown. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). - """ - ), - ] = None, - response_description: Annotated[ - str, - Doc( - """ - The description for the default response. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = "Successful Response", - responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], - Doc( - """ - Additional responses that could be returned by this *path operation*. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - deprecated: Annotated[ - Optional[bool], - Doc( - """ - Mark this *path operation* as deprecated. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - operation_id: Annotated[ - Optional[str], - Doc( - """ - Custom operation ID to be used by this *path operation*. - - By default, it is generated automatically. - - If you provide a custom operation ID, you need to make sure it is - unique for the whole API. - - You can customize the - operation ID generation with the parameter - `generate_unique_id_function` in the `FastAPI` class. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = None, - response_model_include: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to include only certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_exclude: Annotated[ - Optional[IncEx], - Doc( - """ - Configuration passed to Pydantic to exclude certain fields in the - response data. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = None, - response_model_by_alias: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response model - should be serialized by alias when an alias is used. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). - """ - ), - ] = True, - response_model_exclude_unset: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that were not set and - have their default values. This is different from - `response_model_exclude_defaults` in that if the fields are set, - they will be included in the response, even if the value is the same - as the default. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_defaults: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data - should have all the fields, including the ones that have the same value - as the default. This is different from `response_model_exclude_unset` - in that if the fields are set but contain the same default values, - they will be excluded from the response. - - When `True`, default values are omitted from the response. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). - """ - ), - ] = False, - response_model_exclude_none: Annotated[ - bool, - Doc( - """ - Configuration passed to Pydantic to define if the response data should - exclude fields set to `None`. - - This is much simpler (less smart) than `response_model_exclude_unset` - and `response_model_exclude_defaults`. You probably want to use one of - those two instead of this one, as those allow returning `None` values - when it makes sense. - - Read more about it in the - [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). - """ - ), - ] = False, - include_in_schema: Annotated[ - bool, - Doc( - """ - Include this *path operation* in the generated OpenAPI schema. - - This affects the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). - """ - ), - ] = True, - response_class: Annotated[ - type[Response], - Doc( - """ - Response class to be used for this *path operation*. - - This will not be used if you return a response directly. - - Read more about it in the - [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). - """ - ), - ] = Default(JSONResponse), - name: Annotated[ - Optional[str], - Doc( - """ - Name for this *path operation*. Only used internally. - """ - ), - ] = None, - callbacks: Annotated[ - Optional[list[BaseRoute]], - Doc( - """ - List of *path operations* that will be used as OpenAPI callbacks. - - This is only for OpenAPI documentation, the callbacks won't be used - directly. - - It will be added to the generated OpenAPI (e.g. visible at `/docs`). - - Read more about it in the - [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). - """ - ), - ] = None, - openapi_extra: Annotated[ - Optional[dict[str, Any]], - Doc( - """ - Extra metadata to be included in the OpenAPI schema for this *path - operation*. - - Read more about it in the - [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). - """ - ), - ] = None, - generate_unique_id_function: Annotated[ - Callable[[APIRoute], str], - Doc( - """ - Customize the function used to generate unique IDs for the *path - operations* shown in the generated OpenAPI. - - This is particularly useful when automatically generating clients or - SDKs for your API. - - Read more about it in the - [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). - """ - ), - ] = Default(generate_unique_id), - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add a *path operation* using an HTTP TRACE operation. - - ## Example - - ```python - from fastapi import APIRouter, FastAPI - from pydantic import BaseModel - - class Item(BaseModel): - name: str - description: str | None = None - - app = FastAPI() - router = APIRouter() - - @router.trace("/items/{item_id}") - def trace_item(item_id: str): - return None - - app.include_router(router) - ``` - """ - return self.api_route( - path=path, - response_model=response_model, - status_code=status_code, - tags=tags, - dependencies=dependencies, - summary=summary, - description=description, - response_description=response_description, - responses=responses, - deprecated=deprecated, - methods=["TRACE"], - operation_id=operation_id, - response_model_include=response_model_include, - response_model_exclude=response_model_exclude, - response_model_by_alias=response_model_by_alias, - response_model_exclude_unset=response_model_exclude_unset, - response_model_exclude_defaults=response_model_exclude_defaults, - response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class, - name=name, - callbacks=callbacks, - openapi_extra=openapi_extra, - generate_unique_id_function=generate_unique_id_function, - ) - - @deprecated( - """ - on_event is deprecated, use lifespan event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). - """ - ) - def on_event( - self, - event_type: Annotated[ - str, - Doc( - """ - The type of event. `startup` or `shutdown`. - """ - ), - ], - ) -> Callable[[DecoratedCallable], DecoratedCallable]: - """ - Add an event handler for the router. - - `on_event` is deprecated, use `lifespan` event handlers instead. - - Read more about it in the - [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). - """ - - def decorator(func: DecoratedCallable) -> DecoratedCallable: - self.add_event_handler(event_type, func) - return func - - return decorator diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/__init__.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/__init__.py deleted file mode 100644 index 3aa6bf2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .api_key import APIKeyCookie as APIKeyCookie -from .api_key import APIKeyHeader as APIKeyHeader -from .api_key import APIKeyQuery as APIKeyQuery -from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials -from .http import HTTPBasic as HTTPBasic -from .http import HTTPBasicCredentials as HTTPBasicCredentials -from .http import HTTPBearer as HTTPBearer -from .http import HTTPDigest as HTTPDigest -from .oauth2 import OAuth2 as OAuth2 -from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer -from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer -from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm -from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict -from .oauth2 import SecurityScopes as SecurityScopes -from .open_id_connect_url import OpenIdConnect as OpenIdConnect diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/api_key.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/api_key.py deleted file mode 100644 index 18dfb8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/api_key.py +++ /dev/null @@ -1,318 +0,0 @@ -from typing import Annotated, Optional, Union - -from annotated_doc import Doc -from fastapi.openapi.models import APIKey, APIKeyIn -from fastapi.security.base import SecurityBase -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class APIKeyBase(SecurityBase): - def __init__( - self, - location: APIKeyIn, - name: str, - description: Union[str, None], - scheme_name: Union[str, None], - auto_error: bool, - ): - self.auto_error = auto_error - - self.model: APIKey = APIKey( - **{"in": location}, - name=name, - description=description, - ) - self.scheme_name = scheme_name or self.__class__.__name__ - - def make_not_authenticated_error(self) -> HTTPException: - """ - The WWW-Authenticate header is not standardized for API Key authentication but - the HTTP specification requires that an error of 401 "Unauthorized" must - include a WWW-Authenticate header. - - Ref: https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized - - For this, this method sends a custom challenge `APIKey`. - """ - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "APIKey"}, - ) - - def check_api_key(self, api_key: Optional[str]) -> Optional[str]: - if not api_key: - if self.auto_error: - raise self.make_not_authenticated_error() - return None - return api_key - - -class APIKeyQuery(APIKeyBase): - """ - API key authentication using a query parameter. - - This defines the name of the query parameter that should be provided in the request - with the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the query parameter automatically and provides it as the - dependency result. But it doesn't define how to send that API key to the client. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyQuery - - app = FastAPI() - - query_scheme = APIKeyQuery(name="api_key") - - - @app.get("/items/") - async def read_items(api_key: str = Depends(query_scheme)): - return {"api_key": api_key} - ``` - """ - - def __init__( - self, - *, - name: Annotated[ - str, - Doc("Query parameter name."), - ], - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the query parameter is not provided, `APIKeyQuery` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the query parameter is not - available, instead of erroring out, the dependency result will be - `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a query - parameter or in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.query, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> Optional[str]: - api_key = request.query_params.get(self.model.name) - return self.check_api_key(api_key) - - -class APIKeyHeader(APIKeyBase): - """ - API key authentication using a header. - - This defines the name of the header that should be provided in the request with - the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the header automatically and provides it as the dependency - result. But it doesn't define how to send that key to the client. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyHeader - - app = FastAPI() - - header_scheme = APIKeyHeader(name="x-key") - - - @app.get("/items/") - async def read_items(key: str = Depends(header_scheme)): - return {"key": key} - ``` - """ - - def __init__( - self, - *, - name: Annotated[str, Doc("Header name.")], - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the header is not provided, `APIKeyHeader` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the header is not available, - instead of erroring out, the dependency result will be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a header or - in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.header, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> Optional[str]: - api_key = request.headers.get(self.model.name) - return self.check_api_key(api_key) - - -class APIKeyCookie(APIKeyBase): - """ - API key authentication using a cookie. - - This defines the name of the cookie that should be provided in the request with - the API key and integrates that into the OpenAPI documentation. It extracts - the key value sent in the cookie automatically and provides it as the dependency - result. But it doesn't define how to set that cookie. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be a string containing the key value. - - ## Example - - ```python - from fastapi import Depends, FastAPI - from fastapi.security import APIKeyCookie - - app = FastAPI() - - cookie_scheme = APIKeyCookie(name="session") - - - @app.get("/items/") - async def read_items(session: str = Depends(cookie_scheme)): - return {"session": session} - ``` - """ - - def __init__( - self, - *, - name: Annotated[str, Doc("Cookie name.")], - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the cookie is not provided, `APIKeyCookie` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the cookie is not available, - instead of erroring out, the dependency result will be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in a cookie or - in an HTTP Bearer token). - """ - ), - ] = True, - ): - super().__init__( - location=APIKeyIn.cookie, - name=name, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> Optional[str]: - api_key = request.cookies.get(self.model.name) - return self.check_api_key(api_key) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/base.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/base.py deleted file mode 100644 index c43555d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/base.py +++ /dev/null @@ -1,6 +0,0 @@ -from fastapi.openapi.models import SecurityBase as SecurityBaseModel - - -class SecurityBase: - model: SecurityBaseModel - scheme_name: str diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/http.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/http.py deleted file mode 100644 index b4c3bc6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/http.py +++ /dev/null @@ -1,423 +0,0 @@ -import binascii -from base64 import b64decode -from typing import Annotated, Optional - -from annotated_doc import Doc -from fastapi.exceptions import HTTPException -from fastapi.openapi.models import HTTPBase as HTTPBaseModel -from fastapi.openapi.models import HTTPBearer as HTTPBearerModel -from fastapi.security.base import SecurityBase -from fastapi.security.utils import get_authorization_scheme_param -from pydantic import BaseModel -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class HTTPBasicCredentials(BaseModel): - """ - The HTTP Basic credentials given as the result of using `HTTPBasic` in a - dependency. - - Read more about it in the - [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). - """ - - username: Annotated[str, Doc("The HTTP Basic username.")] - password: Annotated[str, Doc("The HTTP Basic password.")] - - -class HTTPAuthorizationCredentials(BaseModel): - """ - The HTTP authorization credentials in the result of using `HTTPBearer` or - `HTTPDigest` in a dependency. - - The HTTP authorization header value is split by the first space. - - The first part is the `scheme`, the second part is the `credentials`. - - For example, in an HTTP Bearer token scheme, the client will send a header - like: - - ``` - Authorization: Bearer deadbeef12346 - ``` - - In this case: - - * `scheme` will have the value `"Bearer"` - * `credentials` will have the value `"deadbeef12346"` - """ - - scheme: Annotated[ - str, - Doc( - """ - The HTTP authorization scheme extracted from the header value. - """ - ), - ] - credentials: Annotated[ - str, - Doc( - """ - The HTTP authorization credentials extracted from the header value. - """ - ), - ] - - -class HTTPBase(SecurityBase): - def __init__( - self, - *, - scheme: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, - ): - self.model: HTTPBaseModel = HTTPBaseModel( - scheme=scheme, description=description - ) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_authenticate_headers(self) -> dict[str, str]: - return {"WWW-Authenticate": f"{self.model.scheme.title()}"} - - def make_not_authenticated_error(self) -> HTTPException: - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers=self.make_authenticate_headers(), - ) - - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) - - -class HTTPBasic(HTTPBase): - """ - HTTP Basic authentication. - - Ref: https://datatracker.ietf.org/doc/html/rfc7617 - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPBasicCredentials` object containing the - `username` and the `password`. - - Read more about it in the - [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPBasic, HTTPBasicCredentials - - app = FastAPI() - - security = HTTPBasic() - - - @app.get("/users/me") - def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): - return {"username": credentials.username, "password": credentials.password} - ``` - """ - - def __init__( - self, - *, - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - realm: Annotated[ - Optional[str], - Doc( - """ - HTTP Basic authentication realm. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Basic authentication is not provided (a - header), `HTTPBasic` will automatically cancel the request and send the - client an error. - - If `auto_error` is set to `False`, when the HTTP Basic authentication - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in HTTP Basic - authentication or in an HTTP Bearer token). - """ - ), - ] = True, - ): - self.model = HTTPBaseModel(scheme="basic", description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.realm = realm - self.auto_error = auto_error - - def make_authenticate_headers(self) -> dict[str, str]: - if self.realm: - return {"WWW-Authenticate": f'Basic realm="{self.realm}"'} - return {"WWW-Authenticate": "Basic"} - - async def __call__( # type: ignore - self, request: Request - ) -> Optional[HTTPBasicCredentials]: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "basic": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - try: - data = b64decode(param).decode("ascii") - except (ValueError, UnicodeDecodeError, binascii.Error) as e: - raise self.make_not_authenticated_error() from e - username, separator, password = data.partition(":") - if not separator: - raise self.make_not_authenticated_error() - return HTTPBasicCredentials(username=username, password=password) - - -class HTTPBearer(HTTPBase): - """ - HTTP Bearer token authentication. - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPAuthorizationCredentials` object containing - the `scheme` and the `credentials`. - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer - - app = FastAPI() - - security = HTTPBearer() - - - @app.get("/users/me") - def read_current_user( - credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] - ): - return {"scheme": credentials.scheme, "credentials": credentials.credentials} - ``` - """ - - def __init__( - self, - *, - bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None, - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Bearer token is not provided (in an - `Authorization` header), `HTTPBearer` will automatically cancel the - request and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Bearer token - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in an HTTP - Bearer token or in a cookie). - """ - ), - ] = True, - ): - self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - if scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) - - -class HTTPDigest(HTTPBase): - """ - HTTP Digest authentication. - - **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI, - but it doesn't implement the full Digest scheme, you would need to to subclass it - and implement it in your code. - - Ref: https://datatracker.ietf.org/doc/html/rfc7616 - - ## Usage - - Create an instance object and use that object as the dependency in `Depends()`. - - The dependency result will be an `HTTPAuthorizationCredentials` object containing - the `scheme` and the `credentials`. - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest - - app = FastAPI() - - security = HTTPDigest() - - - @app.get("/users/me") - def read_current_user( - credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] - ): - return {"scheme": credentials.scheme, "credentials": credentials.credentials} - ``` - """ - - def __init__( - self, - *, - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if the HTTP Digest is not provided, `HTTPDigest` will - automatically cancel the request and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Digest is not - available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, in HTTP - Digest or in a cookie). - """ - ), - ] = True, - ): - self.model = HTTPBaseModel(scheme="digest", description=description) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: - authorization = request.headers.get("Authorization") - scheme, credentials = get_authorization_scheme_param(authorization) - if not (authorization and scheme and credentials): - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - if scheme.lower() != "digest": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/oauth2.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/oauth2.py deleted file mode 100644 index fc49ba1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/oauth2.py +++ /dev/null @@ -1,663 +0,0 @@ -from typing import Annotated, Any, Optional, Union, cast - -from annotated_doc import Doc -from fastapi.exceptions import HTTPException -from fastapi.openapi.models import OAuth2 as OAuth2Model -from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel -from fastapi.param_functions import Form -from fastapi.security.base import SecurityBase -from fastapi.security.utils import get_authorization_scheme_param -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class OAuth2PasswordRequestForm: - """ - This is a dependency class to collect the `username` and `password` as form data - for an OAuth2 password flow. - - The OAuth2 specification dictates that for a password flow the data should be - collected using form data (instead of JSON) and that it should have the specific - fields `username` and `password`. - - All the initialization parameters are extracted from the request. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import OAuth2PasswordRequestForm - - app = FastAPI() - - - @app.post("/login") - def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): - data = {} - data["scopes"] = [] - for scope in form_data.scopes: - data["scopes"].append(scope) - if form_data.client_id: - data["client_id"] = form_data.client_id - if form_data.client_secret: - data["client_secret"] = form_data.client_secret - return data - ``` - - Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. - You could have custom internal logic to separate it by colon characters (`:`) or - similar, and get the two parts `items` and `read`. Many applications do that to - group and organize permissions, you could do it as well in your application, just - know that that it is application specific, it's not part of the specification. - """ - - def __init__( - self, - *, - grant_type: Annotated[ - Union[str, None], - Form(pattern="^password$"), - Doc( - """ - The OAuth2 spec says it is required and MUST be the fixed string - "password". Nevertheless, this dependency class is permissive and - allows not passing it. If you want to enforce it, use instead the - `OAuth2PasswordRequestFormStrict` dependency. - """ - ), - ] = None, - username: Annotated[ - str, - Form(), - Doc( - """ - `username` string. The OAuth2 spec requires the exact field name - `username`. - """ - ), - ], - password: Annotated[ - str, - Form(json_schema_extra={"format": "password"}), - Doc( - """ - `password` string. The OAuth2 spec requires the exact field name - `password`. - """ - ), - ], - scope: Annotated[ - str, - Form(), - Doc( - """ - A single string with actually several scopes separated by spaces. Each - scope is also a string. - - For example, a single string with: - - ```python - "items:read items:write users:read profile openid" - ```` - - would represent the scopes: - - * `items:read` - * `items:write` - * `users:read` - * `profile` - * `openid` - """ - ), - ] = "", - client_id: Annotated[ - Union[str, None], - Form(), - Doc( - """ - If there's a `client_id`, it can be sent as part of the form fields. - But the OAuth2 specification recommends sending the `client_id` and - `client_secret` (if any) using HTTP Basic auth. - """ - ), - ] = None, - client_secret: Annotated[ - Union[str, None], - Form(json_schema_extra={"format": "password"}), - Doc( - """ - If there's a `client_password` (and a `client_id`), they can be sent - as part of the form fields. But the OAuth2 specification recommends - sending the `client_id` and `client_secret` (if any) using HTTP Basic - auth. - """ - ), - ] = None, - ): - self.grant_type = grant_type - self.username = username - self.password = password - self.scopes = scope.split() - self.client_id = client_id - self.client_secret = client_secret - - -class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): - """ - This is a dependency class to collect the `username` and `password` as form data - for an OAuth2 password flow. - - The OAuth2 specification dictates that for a password flow the data should be - collected using form data (instead of JSON) and that it should have the specific - fields `username` and `password`. - - All the initialization parameters are extracted from the request. - - The only difference between `OAuth2PasswordRequestFormStrict` and - `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the - client to send the form field `grant_type` with the value `"password"`, which - is required in the OAuth2 specification (it seems that for no particular reason), - while for `OAuth2PasswordRequestForm` `grant_type` is optional. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - - ## Example - - ```python - from typing import Annotated - - from fastapi import Depends, FastAPI - from fastapi.security import OAuth2PasswordRequestForm - - app = FastAPI() - - - @app.post("/login") - def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]): - data = {} - data["scopes"] = [] - for scope in form_data.scopes: - data["scopes"].append(scope) - if form_data.client_id: - data["client_id"] = form_data.client_id - if form_data.client_secret: - data["client_secret"] = form_data.client_secret - return data - ``` - - Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. - You could have custom internal logic to separate it by colon characters (`:`) or - similar, and get the two parts `items` and `read`. Many applications do that to - group and organize permissions, you could do it as well in your application, just - know that that it is application specific, it's not part of the specification. - - - grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password". - This dependency is strict about it. If you want to be permissive, use instead the - OAuth2PasswordRequestForm dependency class. - username: username string. The OAuth2 spec requires the exact field name "username". - password: password string. The OAuth2 spec requires the exact field name "password". - scope: Optional string. Several scopes (each one a string) separated by spaces. E.g. - "items:read items:write users:read profile openid" - client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret - client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret - """ - - def __init__( - self, - grant_type: Annotated[ - str, - Form(pattern="^password$"), - Doc( - """ - The OAuth2 spec says it is required and MUST be the fixed string - "password". This dependency is strict about it. If you want to be - permissive, use instead the `OAuth2PasswordRequestForm` dependency - class. - """ - ), - ], - username: Annotated[ - str, - Form(), - Doc( - """ - `username` string. The OAuth2 spec requires the exact field name - `username`. - """ - ), - ], - password: Annotated[ - str, - Form(), - Doc( - """ - `password` string. The OAuth2 spec requires the exact field name - `password`. - """ - ), - ], - scope: Annotated[ - str, - Form(), - Doc( - """ - A single string with actually several scopes separated by spaces. Each - scope is also a string. - - For example, a single string with: - - ```python - "items:read items:write users:read profile openid" - ```` - - would represent the scopes: - - * `items:read` - * `items:write` - * `users:read` - * `profile` - * `openid` - """ - ), - ] = "", - client_id: Annotated[ - Union[str, None], - Form(), - Doc( - """ - If there's a `client_id`, it can be sent as part of the form fields. - But the OAuth2 specification recommends sending the `client_id` and - `client_secret` (if any) using HTTP Basic auth. - """ - ), - ] = None, - client_secret: Annotated[ - Union[str, None], - Form(), - Doc( - """ - If there's a `client_password` (and a `client_id`), they can be sent - as part of the form fields. But the OAuth2 specification recommends - sending the `client_id` and `client_secret` (if any) using HTTP Basic - auth. - """ - ), - ] = None, - ): - super().__init__( - grant_type=grant_type, - username=username, - password=password, - scope=scope, - client_id=client_id, - client_secret=client_secret, - ) - - -class OAuth2(SecurityBase): - """ - This is the base class for OAuth2 authentication, an instance of it would be used - as a dependency. All other OAuth2 classes inherit from it and customize it for - each OAuth2 flow. - - You normally would not create a new class inheriting from it but use one of the - existing subclasses, and maybe compose them if you want to support multiple flows. - - Read more about it in the - [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/). - """ - - def __init__( - self, - *, - flows: Annotated[ - Union[OAuthFlowsModel, dict[str, dict[str, Any]]], - Doc( - """ - The dictionary of OAuth2 flows. - """ - ), - ] = OAuthFlowsModel(), - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - ): - self.model = OAuth2Model( - flows=cast(OAuthFlowsModel, flows), description=description - ) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_not_authenticated_error(self) -> HTTPException: - """ - The OAuth 2 specification doesn't define the challenge that should be used, - because a `Bearer` token is not really the only option to authenticate. - - But declaring any other authentication challenge would be application-specific - as it's not defined in the specification. - - For practical reasons, this method uses the `Bearer` challenge by default, as - it's probably the most common one. - - If you are implementing an OAuth2 authentication scheme other than the provided - ones in FastAPI (based on bearer tokens), you might want to override this. - - Ref: https://datatracker.ietf.org/doc/html/rfc6749 - """ - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - - async def __call__(self, request: Request) -> Optional[str]: - authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return authorization - - -class OAuth2PasswordBearer(OAuth2): - """ - OAuth2 flow for authentication using a bearer token obtained with a password. - An instance of it would be used as a dependency. - - Read more about it in the - [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). - """ - - def __init__( - self, - tokenUrl: Annotated[ - str, - Doc( - """ - The URL to obtain the OAuth2 token. This would be the *path operation* - that has `OAuth2PasswordRequestForm` as a dependency. - """ - ), - ], - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - scopes: Annotated[ - Optional[dict[str, str]], - Doc( - """ - The OAuth2 scopes that would be required by the *path operations* that - use this dependency. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - refreshUrl: Annotated[ - Optional[str], - Doc( - """ - The URL to refresh the token and obtain a new one. - """ - ), - ] = None, - ): - if not scopes: - scopes = {} - flows = OAuthFlowsModel( - password=cast( - Any, - { - "tokenUrl": tokenUrl, - "refreshUrl": refreshUrl, - "scopes": scopes, - }, - ) - ) - super().__init__( - flows=flows, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> Optional[str]: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return param - - -class OAuth2AuthorizationCodeBearer(OAuth2): - """ - OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code - flow. An instance of it would be used as a dependency. - """ - - def __init__( - self, - authorizationUrl: str, - tokenUrl: Annotated[ - str, - Doc( - """ - The URL to obtain the OAuth2 token. - """ - ), - ], - refreshUrl: Annotated[ - Optional[str], - Doc( - """ - The URL to refresh the token and obtain a new one. - """ - ), - ] = None, - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - scopes: Annotated[ - Optional[dict[str, str]], - Doc( - """ - The OAuth2 scopes that would be required by the *path operations* that - use this dependency. - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OAuth2 authentication, it will automatically cancel the request and - send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OAuth2 - or in a cookie). - """ - ), - ] = True, - ): - if not scopes: - scopes = {} - flows = OAuthFlowsModel( - authorizationCode=cast( - Any, - { - "authorizationUrl": authorizationUrl, - "tokenUrl": tokenUrl, - "refreshUrl": refreshUrl, - "scopes": scopes, - }, - ) - ) - super().__init__( - flows=flows, - scheme_name=scheme_name, - description=description, - auto_error=auto_error, - ) - - async def __call__(self, request: Request) -> Optional[str]: - authorization = request.headers.get("Authorization") - scheme, param = get_authorization_scheme_param(authorization) - if not authorization or scheme.lower() != "bearer": - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None # pragma: nocover - return param - - -class SecurityScopes: - """ - This is a special class that you can define in a parameter in a dependency to - obtain the OAuth2 scopes required by all the dependencies in the same chain. - - This way, multiple dependencies can have different scopes, even when used in the - same *path operation*. And with this, you can access all the scopes required in - all those dependencies in a single place. - - Read more about it in the - [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). - """ - - def __init__( - self, - scopes: Annotated[ - Optional[list[str]], - Doc( - """ - This will be filled by FastAPI. - """ - ), - ] = None, - ): - self.scopes: Annotated[ - list[str], - Doc( - """ - The list of all the scopes required by dependencies. - """ - ), - ] = scopes or [] - self.scope_str: Annotated[ - str, - Doc( - """ - All the scopes required by all the dependencies in a single string - separated by spaces, as defined in the OAuth2 specification. - """ - ), - ] = " ".join(self.scopes) diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/open_id_connect_url.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/open_id_connect_url.py deleted file mode 100644 index f4d9533..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/open_id_connect_url.py +++ /dev/null @@ -1,94 +0,0 @@ -from typing import Annotated, Optional - -from annotated_doc import Doc -from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel -from fastapi.security.base import SecurityBase -from starlette.exceptions import HTTPException -from starlette.requests import Request -from starlette.status import HTTP_401_UNAUTHORIZED - - -class OpenIdConnect(SecurityBase): - """ - OpenID Connect authentication class. An instance of it would be used as a - dependency. - - **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI, - but it doesn't implement the full OpenIdConnect scheme, for example, it doesn't use - the OpenIDConnect URL. You would need to to subclass it and implement it in your - code. - """ - - def __init__( - self, - *, - openIdConnectUrl: Annotated[ - str, - Doc( - """ - The OpenID Connect URL. - """ - ), - ], - scheme_name: Annotated[ - Optional[str], - Doc( - """ - Security scheme name. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - description: Annotated[ - Optional[str], - Doc( - """ - Security scheme description. - - It will be included in the generated OpenAPI (e.g. visible at `/docs`). - """ - ), - ] = None, - auto_error: Annotated[ - bool, - Doc( - """ - By default, if no HTTP Authorization header is provided, required for - OpenID Connect authentication, it will automatically cancel the request - and send the client an error. - - If `auto_error` is set to `False`, when the HTTP Authorization header - is not available, instead of erroring out, the dependency result will - be `None`. - - This is useful when you want to have optional authentication. - - It is also useful when you want to have authentication that can be - provided in one of multiple optional ways (for example, with OpenID - Connect or in a cookie). - """ - ), - ] = True, - ): - self.model = OpenIdConnectModel( - openIdConnectUrl=openIdConnectUrl, description=description - ) - self.scheme_name = scheme_name or self.__class__.__name__ - self.auto_error = auto_error - - def make_not_authenticated_error(self) -> HTTPException: - return HTTPException( - status_code=HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - - async def __call__(self, request: Request) -> Optional[str]: - authorization = request.headers.get("Authorization") - if not authorization: - if self.auto_error: - raise self.make_not_authenticated_error() - else: - return None - return authorization diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/security/utils.py b/backend/venv39/lib/python3.9/site-packages/fastapi/security/utils.py deleted file mode 100644 index 002e68b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/security/utils.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Optional - - -def get_authorization_scheme_param( - authorization_header_value: Optional[str], -) -> tuple[str, str]: - if not authorization_header_value: - return "", "" - scheme, _, param = authorization_header_value.partition(" ") - return scheme, param diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/staticfiles.py b/backend/venv39/lib/python3.9/site-packages/fastapi/staticfiles.py deleted file mode 100644 index 299015d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/staticfiles.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.staticfiles import StaticFiles as StaticFiles # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/templating.py b/backend/venv39/lib/python3.9/site-packages/fastapi/templating.py deleted file mode 100644 index 0cb8684..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/templating.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.templating import Jinja2Templates as Jinja2Templates # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/testclient.py b/backend/venv39/lib/python3.9/site-packages/fastapi/testclient.py deleted file mode 100644 index 4012406..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/testclient.py +++ /dev/null @@ -1 +0,0 @@ -from starlette.testclient import TestClient as TestClient # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/types.py b/backend/venv39/lib/python3.9/site-packages/fastapi/types.py deleted file mode 100644 index d3e980c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/types.py +++ /dev/null @@ -1,11 +0,0 @@ -import types -from enum import Enum -from typing import Any, Callable, Optional, TypeVar, Union - -from pydantic import BaseModel - -DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any]) -UnionType = getattr(types, "UnionType", Union) -ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str] -IncEx = Union[set[int], set[str], dict[int, Any], dict[str, Any]] -DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str] diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/utils.py b/backend/venv39/lib/python3.9/site-packages/fastapi/utils.py deleted file mode 100644 index 78fdcbb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/utils.py +++ /dev/null @@ -1,164 +0,0 @@ -import re -import warnings -from collections.abc import MutableMapping -from typing import ( - TYPE_CHECKING, - Any, - Optional, - Union, -) -from weakref import WeakKeyDictionary - -import fastapi -from fastapi._compat import ( - BaseConfig, - ModelField, - PydanticSchemaGenerationError, - Undefined, - UndefinedType, - Validator, - annotation_is_pydantic_v1, -) -from fastapi.datastructures import DefaultPlaceholder, DefaultType -from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError -from pydantic import BaseModel -from pydantic.fields import FieldInfo -from typing_extensions import Literal - -from ._compat import v2 - -if TYPE_CHECKING: # pragma: nocover - from .routing import APIRoute - -# Cache for `create_cloned_field` -_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = ( - WeakKeyDictionary() -) - - -def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool: - if status_code is None: - return True - # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1 - if status_code in { - "default", - "1XX", - "2XX", - "3XX", - "4XX", - "5XX", - }: - return True - current_status_code = int(status_code) - return not (current_status_code < 200 or current_status_code in {204, 205, 304}) - - -def get_path_param_names(path: str) -> set[str]: - return set(re.findall("{(.*?)}", path)) - - -_invalid_args_message = ( - "Invalid args for response field! Hint: " - "check that {type_} is a valid Pydantic field type. " - "If you are using a return type annotation that is not a valid Pydantic " - "field (e.g. Union[Response, dict, None]) you can disable generating the " - "response model from the type annotation with the path operation decorator " - "parameter response_model=None. Read more: " - "https://fastapi.tiangolo.com/tutorial/response-model/" -) - - -def create_model_field( - name: str, - type_: Any, - class_validators: Optional[dict[str, Validator]] = None, - default: Optional[Any] = Undefined, - required: Union[bool, UndefinedType] = Undefined, - model_config: Union[type[BaseConfig], None] = None, - field_info: Optional[FieldInfo] = None, - alias: Optional[str] = None, - mode: Literal["validation", "serialization"] = "validation", - version: Literal["1", "auto"] = "auto", -) -> ModelField: - if annotation_is_pydantic_v1(type_): - raise PydanticV1NotSupportedError( - "pydantic.v1 models are no longer supported by FastAPI." - f" Please update the response model {type_!r}." - ) - class_validators = class_validators or {} - - field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias) - kwargs = {"mode": mode, "name": name, "field_info": field_info} - try: - return v2.ModelField(**kwargs) # type: ignore[return-value,arg-type] - except PydanticSchemaGenerationError: - raise fastapi.exceptions.FastAPIError( - _invalid_args_message.format(type_=type_) - ) from None - - -def create_cloned_field( - field: ModelField, - *, - cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None, -) -> ModelField: - return field - - -def generate_operation_id_for_path( - *, name: str, path: str, method: str -) -> str: # pragma: nocover - warnings.warn( - message="fastapi.utils.generate_operation_id_for_path() was deprecated, " - "it is not used internally, and will be removed soon", - category=FastAPIDeprecationWarning, - stacklevel=2, - ) - operation_id = f"{name}{path}" - operation_id = re.sub(r"\W", "_", operation_id) - operation_id = f"{operation_id}_{method.lower()}" - return operation_id - - -def generate_unique_id(route: "APIRoute") -> str: - operation_id = f"{route.name}{route.path_format}" - operation_id = re.sub(r"\W", "_", operation_id) - assert route.methods - operation_id = f"{operation_id}_{list(route.methods)[0].lower()}" - return operation_id - - -def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None: - for key, value in update_dict.items(): - if ( - key in main_dict - and isinstance(main_dict[key], dict) - and isinstance(value, dict) - ): - deep_dict_update(main_dict[key], value) - elif ( - key in main_dict - and isinstance(main_dict[key], list) - and isinstance(update_dict[key], list) - ): - main_dict[key] = main_dict[key] + update_dict[key] - else: - main_dict[key] = value - - -def get_value_or_default( - first_item: Union[DefaultPlaceholder, DefaultType], - *extra_items: Union[DefaultPlaceholder, DefaultType], -) -> Union[DefaultPlaceholder, DefaultType]: - """ - Pass items or `DefaultPlaceholder`s by descending priority. - - The first one to _not_ be a `DefaultPlaceholder` will be returned. - - Otherwise, the first item (a `DefaultPlaceholder`) will be returned. - """ - items = (first_item,) + extra_items - for item in items: - if not isinstance(item, DefaultPlaceholder): - return item - return first_item diff --git a/backend/venv39/lib/python3.9/site-packages/fastapi/websockets.py b/backend/venv39/lib/python3.9/site-packages/fastapi/websockets.py deleted file mode 100644 index 55a4ac4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/fastapi/websockets.py +++ /dev/null @@ -1,3 +0,0 @@ -from starlette.websockets import WebSocket as WebSocket # noqa -from starlette.websockets import WebSocketDisconnect as WebSocketDisconnect # noqa -from starlette.websockets import WebSocketState as WebSocketState # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA deleted file mode 100644 index 30d6653..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/METADATA +++ /dev/null @@ -1,672 +0,0 @@ -Metadata-Version: 2.4 -Name: frozenlist -Version: 1.8.0 -Summary: A list-like structure which implements collections.abc.MutableSequence -Home-page: https://github.com/aio-libs/frozenlist -Maintainer: aiohttp team -Maintainer-email: team@aiohttp.org -License: Apache-2.0 -Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org -Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org -Project-URL: CI: Github Actions, https://github.com/aio-libs/frozenlist/actions -Project-URL: Code of Conduct, https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/frozenlist -Project-URL: Docs: Changelog, https://github.com/aio-libs/frozenlist/blob/master/CHANGES.rst#changelog -Project-URL: Docs: RTD, https://frozenlist.aio-libs.org -Project-URL: GitHub: issues, https://github.com/aio-libs/frozenlist/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/frozenlist -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Operating System :: POSIX -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: Cython -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Dynamic: license-file - -frozenlist -========== - -.. image:: https://github.com/aio-libs/frozenlist/workflows/CI/badge.svg - :target: https://github.com/aio-libs/frozenlist/actions - :alt: GitHub status for master branch - -.. image:: https://codecov.io/gh/aio-libs/frozenlist/branch/master/graph/badge.svg?flag=pytest - :target: https://codecov.io/gh/aio-libs/frozenlist?flags[]=pytest - :alt: codecov.io status for master branch - -.. image:: https://img.shields.io/pypi/v/frozenlist.svg?logo=Python&logoColor=white - :target: https://pypi.org/project/frozenlist - :alt: frozenlist @ PyPI - -.. image:: https://readthedocs.org/projects/frozenlist/badge/?version=latest - :target: https://frozenlist.aio-libs.org - :alt: Read The Docs build status badge - -.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs:matrix.org - :alt: Matrix Room — #aio-libs:matrix.org - -.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs-space:matrix.org - :alt: Matrix Space — #aio-libs-space:matrix.org - -Introduction ------------- - -``frozenlist.FrozenList`` is a list-like structure which implements -``collections.abc.MutableSequence``. The list is *mutable* until ``FrozenList.freeze`` -is called, after which list modifications raise ``RuntimeError``: - - ->>> from frozenlist import FrozenList ->>> fl = FrozenList([17, 42]) ->>> fl.append('spam') ->>> fl.append('Vikings') ->>> fl - ->>> fl.freeze() ->>> fl - ->>> fl.frozen -True ->>> fl.append("Monty") -Traceback (most recent call last): - File "", line 1, in - File "frozenlist/_frozenlist.pyx", line 97, in frozenlist._frozenlist.FrozenList.append - self._check_frozen() - File "frozenlist/_frozenlist.pyx", line 19, in frozenlist._frozenlist.FrozenList._check_frozen - raise RuntimeError("Cannot modify frozen list.") -RuntimeError: Cannot modify frozen list. - - -FrozenList is also hashable, but only when frozen. Otherwise it also throws a RuntimeError: - - ->>> fl = FrozenList([17, 42, 'spam']) ->>> hash(fl) -Traceback (most recent call last): - File "", line 1, in - File "frozenlist/_frozenlist.pyx", line 111, in frozenlist._frozenlist.FrozenList.__hash__ - raise RuntimeError("Cannot hash unfrozen list.") -RuntimeError: Cannot hash unfrozen list. ->>> fl.freeze() ->>> hash(fl) -3713081631934410656 ->>> dictionary = {fl: 'Vikings'} # frozen fl can be a dict key ->>> dictionary -{: 'Vikings'} - - -Installation ------------- - -:: - - $ pip install frozenlist - - -Documentation -------------- - -https://frozenlist.aio-libs.org - -Communication channels ----------------------- - -We have a *Matrix Space* `#aio-libs-space:matrix.org -`_ which is -also accessible via Gitter. - -License -------- - -``frozenlist`` is offered under the Apache 2 license. - -Source code ------------ - -The project is hosted on GitHub_ - -Please file an issue in the `bug tracker -`_ if you have found a bug -or have some suggestions to improve the library. - -.. _GitHub: https://github.com/aio-libs/frozenlist - -========= -Changelog -========= - -.. - You should *NOT* be adding new change log entries to this file, this - file is managed by towncrier. You *may* edit previous change logs to - fix problems like typo corrections or such. - To add a new change log entry, please see - https://pip.pypa.io/en/latest/development/contributing/#news-entries - we named the news folder "changes". - - WARNING: Don't drop the next directive! - -.. towncrier release notes start - -v1.8.0 -====== - -*(2025-10-05)* - - -Contributor-facing changes --------------------------- - -- The ``reusable-cibuildwheel.yml`` workflow has been refactored to - be more generic and ``ci-cd.yml`` now holds all the configuration - toggles -- by `@webknjaz `__. - - *Related issues and pull requests on GitHub:* - `#668 `__. - -- When building wheels, the source distribution is now passed directly - to the ``cibuildwheel`` invocation -- by `@webknjaz `__. - - *Related issues and pull requests on GitHub:* - `#669 `__. - -- Builds and tests have been added to - ``ci-cd.yml`` for arm64 Windows wheels -- by `@finnagin `__. - - *Related issues and pull requests on GitHub:* - `#677 `__. - -- Started building wheels for CPython 3.14 -- by `@kumaraditya303 `__. - - *Related issues and pull requests on GitHub:* - `#681 `__, `#682 `__. - -- Removed ``--config-settings=pure-python=false`` from ``requirements/dev.txt``. - Developers on CPython still get accelerated builds by default. To explicitly build - a pure Python wheel, use ``pip install -e . --config-settings=pure-python=true`` - -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#687 `__. - - ----- - - -v1.7.0 -====== - -*(2025-06-09)* - - -Features --------- - -- Added deepcopy support to FrozenList -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#659 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Fixed an issue where ``frozenlist`` binary wheels would be built with debugging symbols and line tracing enabled, which significantly impacted performance. Line tracing is now disabled by default and can only be enabled explicitly -- by `@bdraco `__. - - This change ensures that production builds are optimized for performance. Developers who need line tracing for debugging purposes can still enable it by: - - 1. Setting the ``FROZENLIST_CYTHON_TRACING`` environment variable - 2. Using the ``--config-setting=with-cython-tracing=true`` option with pip - - *Related issues and pull requests on GitHub:* - `#660 `__. - -- Enabled ``PIP_CONSTRAINT`` environment variable in the build configuration to ensure the pinned Cython version from ``requirements/cython.txt`` is used during wheel builds. - - *Related issues and pull requests on GitHub:* - `#661 `__. - - ----- - - -v1.6.2 -====== - -*(2025-06-03)* - - -No significant changes. - - ----- - - -v1.6.1 -====== - -*(2025-06-02)* - - -Bug fixes ---------- - -- Correctly use ``cimport`` for including ``PyBool_FromLong`` -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#653 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Exclude ``_frozenlist.cpp`` from bdists/wheels -- by `@musicinmybrain `__. - - *Related issues and pull requests on GitHub:* - `#649 `__. - -- Updated to use Cython 3.1 universally across the build path -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#654 `__. - - ----- - - -v1.6.0 -====== - -*(2025-04-17)* - - -Bug fixes ---------- - -- Stopped implicitly allowing the use of Cython pre-release versions when - building the distribution package -- by `@ajsanchezsanz `__ and - `@markgreene74 `__. - - *Related commits on GitHub:* - `41591f2 `__. - - -Features --------- - -- Implemented support for the free-threaded build of CPython 3.13 -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#618 `__. - -- Started building armv7l wheels -- by `@bdraco `__. - - *Related issues and pull requests on GitHub:* - `#642 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- Stopped implicitly allowing the use of Cython pre-release versions when - building the distribution package -- by `@ajsanchezsanz `__ and - `@markgreene74 `__. - - *Related commits on GitHub:* - `41591f2 `__. - -- Started building wheels for the free-threaded build of CPython 3.13 -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#618 `__. - -- The packaging metadata switched to including an SPDX license identifier introduced in `PEP 639 `__ -- by `@cdce8p `__. - - *Related issues and pull requests on GitHub:* - `#639 `__. - - -Contributor-facing changes --------------------------- - -- GitHub Actions CI/CD is now configured to manage caching pip-ecosystem - dependencies using `re-actors/cache-python-deps`_ -- an action by - `@webknjaz `__ that takes into account ABI stability and the exact - version of Python runtime. - - .. _`re-actors/cache-python-deps`: - https://github.com/marketplace/actions/cache-python-deps - - *Related issues and pull requests on GitHub:* - `#633 `__. - -- Organized dependencies into test and lint dependencies so that no - unnecessary ones are installed during CI runs -- by `@lysnikolaou `__. - - *Related issues and pull requests on GitHub:* - `#636 `__. - - ----- - - -1.5.0 (2024-10-22) -================== - -Bug fixes ---------- - -- An incorrect signature of the ``__class_getitem__`` class method - has been fixed, adding a missing ``class_item`` argument under - Python 3.8 and older. - - This change also improves the code coverage of this method that - was previously missing -- by `@webknjaz `__. - - - *Related issues and pull requests on GitHub:* - `#567 `__, `#571 `__. - - -Improved documentation ----------------------- - -- Rendered issue, PR, and commit links now lead to - ``frozenlist``'s repo instead of ``yarl``'s repo. - - - *Related issues and pull requests on GitHub:* - `#573 `__. - -- On the ``Contributing docs`` page, - a link to the ``Towncrier philosophy`` has been fixed. - - - *Related issues and pull requests on GitHub:* - `#574 `__. - - -Packaging updates and notes for downstreams -------------------------------------------- - -- A name of a temporary building directory now reflects - that it's related to ``frozenlist``, not ``yarl``. - - - *Related issues and pull requests on GitHub:* - `#573 `__. - -- Declared Python 3.13 supported officially in the distribution package metadata. - - - *Related issues and pull requests on GitHub:* - `#595 `__. - - ----- - - -1.4.1 (2023-12-15) -================== - -Packaging updates and notes for downstreams -------------------------------------------- - -- Declared Python 3.12 and PyPy 3.8-3.10 supported officially - in the distribution package metadata. - - - *Related issues and pull requests on GitHub:* - `#553 `__. - -- Replaced the packaging is replaced from an old-fashioned ``setup.py`` to an - in-tree `PEP 517 `__ build backend -- by `@webknjaz `__. - - Whenever the end-users or downstream packagers need to build ``frozenlist`` - from source (a Git checkout or an sdist), they may pass a ``config_settings`` - flag ``pure-python``. If this flag is not set, a C-extension will be built - and included into the distribution. - - Here is how this can be done with ``pip``: - - .. code-block:: console - - $ python3 -m pip install . --config-settings=pure-python= - - This will also work with ``-e | --editable``. - - The same can be achieved via ``pypa/build``: - - .. code-block:: console - - $ python3 -m build --config-setting=pure-python= - - Adding ``-w | --wheel`` can force ``pypa/build`` produce a wheel from source - directly, as opposed to building an ``sdist`` and then building from it. - - - *Related issues and pull requests on GitHub:* - `#560 `__. - - -Contributor-facing changes --------------------------- - -- It is now possible to request line tracing in Cython builds using the - ``with-cython-tracing`` `PEP 517 `__ config setting - -- `@webknjaz `__. - - This can be used in CI and development environment to measure coverage - on Cython modules, but is not normally useful to the end-users or - downstream packagers. - - Here's a usage example: - - .. code-block:: console - - $ python3 -Im pip install . --config-settings=with-cython-tracing=true - - For editable installs, this setting is on by default. Otherwise, it's - off unless requested explicitly. - - The following produces C-files required for the Cython coverage - plugin to map the measurements back to the PYX-files: - - .. code-block:: console - - $ python -Im pip install -e . - - Alternatively, the ``FROZENLIST_CYTHON_TRACING=1`` environment variable - can be set to do the same as the `PEP 517 `__ config setting. - - - *Related issues and pull requests on GitHub:* - `#560 `__. - -- Coverage collection has been implemented for the Cython modules - -- by `@webknjaz `__. - - It will also be reported to Codecov from any non-release CI jobs. - - - *Related issues and pull requests on GitHub:* - `#561 `__. - -- A step-by-step ``Release Guide`` guide has - been added, describing how to release *frozenlist* -- by `@webknjaz `__. - - This is primarily targeting the maintainers. - - - *Related issues and pull requests on GitHub:* - `#563 `__. - -- Detailed ``Contributing Guidelines`` on - authoring the changelog fragments have been published in the - documentation -- by `@webknjaz `__. - - - *Related issues and pull requests on GitHub:* - `#564 `__. - - ----- - - -1.4.0 (2023-07-12) -================== - -The published source distribution package became buildable -under Python 3.12. - - ----- - - -Bugfixes --------- - -- Removed an unused ``typing.Tuple`` import - `#411 `_ - - -Deprecations and Removals -------------------------- - -- Dropped Python 3.7 support. - `#413 `_ - - -Misc ----- - -- `#410 `_, `#433 `_ - - ----- - - -1.3.3 (2022-11-08) -================== - -- Fixed CI runs when creating a new release, where new towncrier versions - fail when the current version section is already present. - - ----- - - -1.3.2 (2022-11-08) -================== - -Misc ----- - -- Updated the CI runs to better check for test results and to avoid deprecated syntax. `#327 `_ - - ----- - - -1.3.1 (2022-08-02) -================== - -The published source distribution package became buildable -under Python 3.11. - - ----- - - -1.3.0 (2022-01-18) -================== - -Bugfixes --------- - -- Do not install C sources with binary distributions. - `#250 `_ - - -Deprecations and Removals -------------------------- - -- Dropped Python 3.6 support - `#274 `_ - - ----- - - -1.2.0 (2021-10-16) -================== - -Features --------- - -- ``FrozenList`` now supports being used as a generic type as per PEP 585, e.g. ``frozen_int_list: FrozenList[int]`` (requires Python 3.9 or newer). - `#172 `_ -- Added support for Python 3.10. - `#227 `_ -- Started shipping platform-specific wheels with the ``musl`` tag targeting typical Alpine Linux runtimes. - `#227 `_ -- Started shipping platform-specific arm64 wheels for Apple Silicon. - `#227 `_ - - ----- - - -1.1.1 (2020-11-14) -================== - -Bugfixes --------- - -- Provide x86 Windows wheels. - `#169 `_ - - ----- - - -1.1.0 (2020-10-13) -================== - -Features --------- - -- Add support for hashing of a frozen list. - `#136 `_ - -- Support Python 3.8 and 3.9. - -- Provide wheels for ``aarch64``, ``i686``, ``ppc64le``, ``s390x`` architectures on - Linux as well as ``x86_64``. - - ----- - - -1.0.0 (2019-11-09) -================== - -Deprecations and Removals -------------------------- - -- Dropped support for Python 3.5; only 3.6, 3.7 and 3.8 are supported going forward. - `#24 `_ diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD deleted file mode 100644 index f82c953..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/RECORD +++ /dev/null @@ -1,12 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.cpython-39.pyc,, -frozenlist-1.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -frozenlist-1.8.0.dist-info/METADATA,sha256=lGwi3J9-LHby1pjwCkMG2-Sagg4rPxoOIv5ShsvsNfE,20333 -frozenlist-1.8.0.dist-info/RECORD,, -frozenlist-1.8.0.dist-info/WHEEL,sha256=bDWaFWigpG5bEpqw9IoRiyYs8MvmSFh0OhUAOoi_-KA,134 -frozenlist-1.8.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 -frozenlist-1.8.0.dist-info/top_level.txt,sha256=jivtxsPXA3nK3WBWW2LW5Mtu_GHt8UZA13NeCs2cKuA,11 -frozenlist/__init__.py,sha256=xAIE2u9ncAbjATGIPfno_OJfe8AQ-1h7z_uc73dYsEA,2108 -frozenlist/__init__.pyi,sha256=vMEoES1xGegPtVXoCi9XydEeHsyuIq-KdeXwP5PdsaA,1470 -frozenlist/_frozenlist.cpython-39-darwin.so,sha256=DqAR7Yal5aquSUYBHvyVKSNrfAlLSTkpuXMSIjAg57A,144176 -frozenlist/_frozenlist.pyx,sha256=t-aGjuEiVt_MZPBJ0RnraavVmPBK6arz3i48ZvXuYsU,3708 -frozenlist/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL deleted file mode 100644 index d7eb6c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_11_0_arm64 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE deleted file mode 100644 index 7082a2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2013-2019 Nikolay Kim and Andrew Svetlov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt deleted file mode 100644 index 52f13fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist-1.8.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -frozenlist diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.py b/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.py deleted file mode 100644 index 41c8595..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.py +++ /dev/null @@ -1,86 +0,0 @@ -import os -import types -from collections.abc import MutableSequence -from functools import total_ordering - -__version__ = "1.8.0" - -__all__ = ("FrozenList", "PyFrozenList") # type: Tuple[str, ...] - - -NO_EXTENSIONS = bool(os.environ.get("FROZENLIST_NO_EXTENSIONS")) # type: bool - - -@total_ordering -class FrozenList(MutableSequence): - __slots__ = ("_frozen", "_items") - __class_getitem__ = classmethod(types.GenericAlias) - - def __init__(self, items=None): - self._frozen = False - if items is not None: - items = list(items) - else: - items = [] - self._items = items - - @property - def frozen(self): - return self._frozen - - def freeze(self): - self._frozen = True - - def __getitem__(self, index): - return self._items[index] - - def __setitem__(self, index, value): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - self._items[index] = value - - def __delitem__(self, index): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - del self._items[index] - - def __len__(self): - return self._items.__len__() - - def __iter__(self): - return self._items.__iter__() - - def __reversed__(self): - return self._items.__reversed__() - - def __eq__(self, other): - return list(self) == other - - def __le__(self, other): - return list(self) <= other - - def insert(self, pos, item): - if self._frozen: - raise RuntimeError("Cannot modify frozen list.") - self._items.insert(pos, item) - - def __repr__(self): - return f"" - - def __hash__(self): - if self._frozen: - return hash(tuple(self)) - else: - raise RuntimeError("Cannot hash unfrozen list.") - - -PyFrozenList = FrozenList - - -if not NO_EXTENSIONS: - try: - from ._frozenlist import FrozenList as CFrozenList # type: ignore - except ImportError: # pragma: no cover - pass - else: - FrozenList = CFrozenList # type: ignore diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.pyi deleted file mode 100644 index ae803ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist/__init__.pyi +++ /dev/null @@ -1,47 +0,0 @@ -from typing import ( - Generic, - Iterable, - Iterator, - List, - MutableSequence, - Optional, - TypeVar, - Union, - overload, -) - -_T = TypeVar("_T") -_Arg = Union[List[_T], Iterable[_T]] - -class FrozenList(MutableSequence[_T], Generic[_T]): - def __init__(self, items: Optional[_Arg[_T]] = None) -> None: ... - @property - def frozen(self) -> bool: ... - def freeze(self) -> None: ... - @overload - def __getitem__(self, i: int) -> _T: ... - @overload - def __getitem__(self, s: slice) -> FrozenList[_T]: ... - @overload - def __setitem__(self, i: int, o: _T) -> None: ... - @overload - def __setitem__(self, s: slice, o: Iterable[_T]) -> None: ... - @overload - def __delitem__(self, i: int) -> None: ... - @overload - def __delitem__(self, i: slice) -> None: ... - def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T]: ... - def __reversed__(self) -> Iterator[_T]: ... - def __eq__(self, other: object) -> bool: ... - def __le__(self, other: FrozenList[_T]) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __lt__(self, other: FrozenList[_T]) -> bool: ... - def __ge__(self, other: FrozenList[_T]) -> bool: ... - def __gt__(self, other: FrozenList[_T]) -> bool: ... - def insert(self, pos: int, item: _T) -> None: ... - def __repr__(self) -> str: ... - def __hash__(self) -> int: ... - -# types for C accelerators are the same -CFrozenList = PyFrozenList = FrozenList diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-darwin.so deleted file mode 100755 index b2639e9..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx b/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx deleted file mode 100644 index a82d8c8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist/_frozenlist.pyx +++ /dev/null @@ -1,148 +0,0 @@ -# cython: freethreading_compatible = True -# distutils: language = c++ - -from cpython.bool cimport PyBool_FromLong -from libcpp.atomic cimport atomic - -import copy -import types -from collections.abc import MutableSequence - - -cdef class FrozenList: - __class_getitem__ = classmethod(types.GenericAlias) - - cdef atomic[bint] _frozen - cdef list _items - - def __init__(self, items=None): - self._frozen.store(False) - if items is not None: - items = list(items) - else: - items = [] - self._items = items - - @property - def frozen(self): - return PyBool_FromLong(self._frozen.load()) - - cdef object _check_frozen(self): - if self._frozen.load(): - raise RuntimeError("Cannot modify frozen list.") - - cdef inline object _fast_len(self): - return len(self._items) - - def freeze(self): - self._frozen.store(True) - - def __getitem__(self, index): - return self._items[index] - - def __setitem__(self, index, value): - self._check_frozen() - self._items[index] = value - - def __delitem__(self, index): - self._check_frozen() - del self._items[index] - - def __len__(self): - return self._fast_len() - - def __iter__(self): - return self._items.__iter__() - - def __reversed__(self): - return self._items.__reversed__() - - def __richcmp__(self, other, op): - if op == 0: # < - return list(self) < other - if op == 1: # <= - return list(self) <= other - if op == 2: # == - return list(self) == other - if op == 3: # != - return list(self) != other - if op == 4: # > - return list(self) > other - if op == 5: # => - return list(self) >= other - - def insert(self, pos, item): - self._check_frozen() - self._items.insert(pos, item) - - def __contains__(self, item): - return item in self._items - - def __iadd__(self, items): - self._check_frozen() - self._items += list(items) - return self - - def index(self, item): - return self._items.index(item) - - def remove(self, item): - self._check_frozen() - self._items.remove(item) - - def clear(self): - self._check_frozen() - self._items.clear() - - def extend(self, items): - self._check_frozen() - self._items += list(items) - - def reverse(self): - self._check_frozen() - self._items.reverse() - - def pop(self, index=-1): - self._check_frozen() - return self._items.pop(index) - - def append(self, item): - self._check_frozen() - return self._items.append(item) - - def count(self, item): - return self._items.count(item) - - def __repr__(self): - return ''.format(self._frozen.load(), - self._items) - - def __hash__(self): - if self._frozen.load(): - return hash(tuple(self._items)) - else: - raise RuntimeError("Cannot hash unfrozen list.") - - def __deepcopy__(self, memo): - cdef FrozenList new_list - obj_id = id(self) - - # Return existing copy if already processed (circular reference) - if obj_id in memo: - return memo[obj_id] - - # Create new instance and register immediately - new_list = self.__class__([]) - memo[obj_id] = new_list - - # Deep copy items - new_list._items[:] = [copy.deepcopy(item, memo) for item in self._items] - - # Preserve frozen state - if self._frozen.load(): - new_list.freeze() - - return new_list - - -MutableSequence.register(FrozenList) diff --git a/backend/venv39/lib/python3.9/site-packages/frozenlist/py.typed b/backend/venv39/lib/python3.9/site-packages/frozenlist/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/frozenlist/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA deleted file mode 100644 index 8a2f639..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/METADATA +++ /dev/null @@ -1,202 +0,0 @@ -Metadata-Version: 2.4 -Name: h11 -Version: 0.16.0 -Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 -Home-page: https://github.com/python-hyper/h11 -Author: Nathaniel J. Smith -Author-email: njs@pobox.com -License: MIT -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: System :: Networking -Requires-Python: >=3.8 -License-File: LICENSE.txt -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: requires-python -Dynamic: summary - -h11 -=== - -.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master - :target: https://travis-ci.org/python-hyper/h11 - :alt: Automated test status - -.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg - :target: https://codecov.io/gh/python-hyper/h11 - :alt: Test coverage - -.. image:: https://readthedocs.org/projects/h11/badge/?version=latest - :target: http://h11.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -This is a little HTTP/1.1 library written from scratch in Python, -heavily inspired by `hyper-h2 `_. - -It's a "bring-your-own-I/O" library; h11 contains no IO code -whatsoever. This means you can hook h11 up to your favorite network -API, and that could be anything you want: synchronous, threaded, -asynchronous, or your own implementation of `RFC 6214 -`_ -- h11 won't judge you. -(Compare this to the current state of the art, where every time a `new -network API `_ comes along then someone -gets to start over reimplementing the entire HTTP protocol from -scratch.) Cory Benfield made an `excellent blog post describing the -benefits of this approach -`_, or if you like video -then here's his `PyCon 2016 talk on the same theme -`_. - -This also means that h11 is not immediately useful out of the box: -it's a toolkit for building programs that speak HTTP, not something -that could directly replace ``requests`` or ``twisted.web`` or -whatever. But h11 makes it much easier to implement something like -``requests`` or ``twisted.web``. - -At a high level, working with h11 goes like this: - -1) First, create an ``h11.Connection`` object to track the state of a - single HTTP/1.1 connection. - -2) When you read data off the network, pass it to - ``conn.receive_data(...)``; you'll get back a list of objects - representing high-level HTTP "events". - -3) When you want to send a high-level HTTP event, create the - corresponding "event" object and pass it to ``conn.send(...)``; - this will give you back some bytes that you can then push out - through the network. - -For example, a client might instantiate and then send a -``h11.Request`` object, then zero or more ``h11.Data`` objects for the -request body (e.g., if this is a POST), and then a -``h11.EndOfMessage`` to indicate the end of the message. Then the -server would then send back a ``h11.Response``, some ``h11.Data``, and -its own ``h11.EndOfMessage``. If either side violates the protocol, -you'll get a ``h11.ProtocolError`` exception. - -h11 is suitable for implementing both servers and clients, and has a -pleasantly symmetric API: the events you send as a client are exactly -the ones that you receive as a server and vice-versa. - -`Here's an example of a tiny HTTP client -`_ - -It also has `a fine manual `_. - -FAQ ---- - -*Whyyyyy?* - -I wanted to play with HTTP in `Curio -`__ and `Trio -`__, which at the time didn't have any -HTTP libraries. So I thought, no big deal, Python has, like, a dozen -different implementations of HTTP, surely I can find one that's -reusable. I didn't find one, but I did find Cory's call-to-arms -blog-post. So I figured, well, fine, if I have to implement HTTP from -scratch, at least I can make sure no-one *else* has to ever again. - -*Should I use it?* - -Maybe. You should be aware that it's a very young project. But, it's -feature complete and has an exhaustive test-suite and complete docs, -so the next step is for people to try using it and see how it goes -:-). If you do then please let us know -- if nothing else we'll want -to talk to you before making any incompatible changes! - -*What are the features/limitations?* - -Roughly speaking, it's trying to be a robust, complete, and non-hacky -implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: -HTTP/1.1 Message Syntax and Routing -`_. That is, it mostly focuses on -implementing HTTP at the level of taking bytes on and off the wire, -and the headers related to that, and tries to be anal about spec -conformance. It doesn't know about higher-level concerns like URL -routing, conditional GETs, cross-origin cookie policies, or content -negotiation. But it does know how to take care of framing, -cross-version differences in keep-alive handling, and the "obsolete -line folding" rule, so you can focus your energies on the hard / -interesting parts for your application, and it tries to support the -full specification in the sense that any useful HTTP/1.1 conformant -application should be able to use h11. - -It's pure Python, and has no dependencies outside of the standard -library. - -It has a test suite with 100.0% coverage for both statements and -branches. - -Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3. -The last Python 2-compatible version was h11 0.11.x. -(Originally it had a Cython wrapper for `http-parser -`_ and a beautiful nested state -machine implemented with ``yield from`` to postprocess the output. But -I had to take these out -- the new *parser* needs fewer lines-of-code -than the old *parser wrapper*, is written in pure Python, uses no -exotic language syntax, and has more features. It's sad, really; that -old state machine was really slick. I just need a few sentences here -to mourn that.) - -I don't know how fast it is. I haven't benchmarked or profiled it yet, -so it's probably got a few pointless hot spots, and I've been trying -to err on the side of simplicity and robustness instead of -micro-optimization. But at the architectural level I tried hard to -avoid fundamentally bad decisions, e.g., I believe that all the -parsing algorithms remain linear-time even in the face of pathological -input like slowloris, and there are no byte-by-byte loops. (I also -believe that it maintains bounded memory usage in the face of -arbitrary/pathological input.) - -The whole library is ~800 lines-of-code. You can read and understand -the whole thing in less than an hour. Most of the energy invested in -this so far has been spent on trying to keep things simple by -minimizing special-cases and ad hoc state manipulation; even though it -is now quite small and simple, I'm still annoyed that I haven't -figured out how to make it even smaller and simpler. (Unfortunately, -HTTP does not lend itself to simplicity.) - -The API is ~feature complete and I don't expect the general outlines -to change much, but you can't judge an API's ergonomics until you -actually document and use it, so I'd expect some changes in the -details. - -*How do I try it?* - -.. code-block:: sh - - $ pip install h11 - $ git clone git@github.com:python-hyper/h11 - $ cd h11/examples - $ python basic-client.py - -and go from there. - -*License?* - -MIT - -*Code of conduct?* - -Contributors are requested to follow our `code of conduct -`_ in -all project spaces. diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD deleted file mode 100644 index d3da4d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/RECORD +++ /dev/null @@ -1,29 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_abnf.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_connection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_events.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_headers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_readers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_receivebuffer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_state.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_util.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_version.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/h11/_writers.cpython-39.pyc,, -h11-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348 -h11-0.16.0.dist-info/RECORD,, -h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91 -h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 -h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 -h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 -h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 -h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863 -h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792 -h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412 -h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590 -h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 -h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231 -h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 -h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686 -h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 -h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL deleted file mode 100644 index 1eb3c49..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (78.1.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 8f080ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Nathaniel J. Smith and other contributors - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt deleted file mode 100644 index 0d24def..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11-0.16.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -h11 diff --git a/backend/venv39/lib/python3.9/site-packages/h11/__init__.py b/backend/venv39/lib/python3.9/site-packages/h11/__init__.py deleted file mode 100644 index 989e92c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230), -# containing no networking code at all, loosely modelled on hyper-h2's generic -# implementation of HTTP/2 (and in particular the h2.connection.H2Connection -# class). There's still a bunch of subtle details you need to get right if you -# want to make this actually useful, because it doesn't implement all the -# semantics to check that what you're asking to write to the wire is sensible, -# but at least it gets you out of dealing with the wire itself. - -from h11._connection import Connection, NEED_DATA, PAUSED -from h11._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from h11._state import ( - CLIENT, - CLOSED, - DONE, - ERROR, - IDLE, - MIGHT_SWITCH_PROTOCOL, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, - SWITCHED_PROTOCOL, -) -from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError -from h11._version import __version__ - -PRODUCT_ID = "python-h11/" + __version__ - - -__all__ = ( - "Connection", - "NEED_DATA", - "PAUSED", - "ConnectionClosed", - "Data", - "EndOfMessage", - "Event", - "InformationalResponse", - "Request", - "Response", - "CLIENT", - "CLOSED", - "DONE", - "ERROR", - "IDLE", - "MUST_CLOSE", - "SEND_BODY", - "SEND_RESPONSE", - "SERVER", - "SWITCHED_PROTOCOL", - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", -) diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_abnf.py b/backend/venv39/lib/python3.9/site-packages/h11/_abnf.py deleted file mode 100644 index 933587f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_abnf.py +++ /dev/null @@ -1,132 +0,0 @@ -# We use native strings for all the re patterns, to take advantage of string -# formatting, and then convert to bytestrings when compiling the final re -# objects. - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#whitespace -# OWS = *( SP / HTAB ) -# ; optional whitespace -OWS = r"[ \t]*" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.token.separators -# token = 1*tchar -# -# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" -# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" -# / DIGIT / ALPHA -# ; any VCHAR, except delimiters -token = r"[-!#$%&'*+.^_`|~0-9a-zA-Z]+" - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#header.fields -# field-name = token -field_name = token - -# The standard says: -# -# field-value = *( field-content / obs-fold ) -# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] -# field-vchar = VCHAR / obs-text -# obs-fold = CRLF 1*( SP / HTAB ) -# ; obsolete line folding -# ; see Section 3.2.4 -# -# https://tools.ietf.org/html/rfc5234#appendix-B.1 -# -# VCHAR = %x21-7E -# ; visible (printing) characters -# -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.quoted-string -# obs-text = %x80-FF -# -# However, the standard definition of field-content is WRONG! It disallows -# fields containing a single visible character surrounded by whitespace, -# e.g. "foo a bar". -# -# See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 -# -# So our definition of field_content attempts to fix it up... -# -# Also, we allow lots of control characters, because apparently people assume -# that they're legal in practice (e.g., google analytics makes cookies with -# \x01 in them!): -# https://github.com/python-hyper/h11/issues/57 -# We still don't allow NUL or whitespace, because those are often treated as -# meta-characters and letting them through can lead to nasty issues like SSRF. -vchar = r"[\x21-\x7e]" -vchar_or_obs_text = r"[^\x00\s]" -field_vchar = vchar_or_obs_text -field_content = r"{field_vchar}+(?:[ \t]+{field_vchar}+)*".format(**globals()) - -# We handle obs-fold at a different level, and our fixed-up field_content -# already grows to swallow the whole value, so ? instead of * -field_value = r"({field_content})?".format(**globals()) - -# header-field = field-name ":" OWS field-value OWS -header_field = ( - r"(?P{field_name})" - r":" - r"{OWS}" - r"(?P{field_value})" - r"{OWS}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line -# -# request-line = method SP request-target SP HTTP-version CRLF -# method = token -# HTTP-version = HTTP-name "/" DIGIT "." DIGIT -# HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive -# -# request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full -# URL, host+port (for connect), or even "*", but in any case we are guaranteed -# that it contists of the visible printing characters. -method = token -request_target = r"{vchar}+".format(**globals()) -http_version = r"HTTP/(?P[0-9]\.[0-9])" -request_line = ( - r"(?P{method})" - r" " - r"(?P{request_target})" - r" " - r"{http_version}".format(**globals()) -) - -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line -# -# status-line = HTTP-version SP status-code SP reason-phrase CRLF -# status-code = 3DIGIT -# reason-phrase = *( HTAB / SP / VCHAR / obs-text ) -status_code = r"[0-9]{3}" -reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals()) -status_line = ( - r"{http_version}" - r" " - r"(?P{status_code})" - # However, there are apparently a few too many servers out there that just - # leave out the reason phrase: - # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036 - # https://github.com/seanmonstar/httparse/issues/29 - # so make it optional. ?: is a non-capturing group. - r"(?: (?P{reason_phrase}))?".format(**globals()) -) - -HEXDIG = r"[0-9A-Fa-f]" -# Actually -# -# chunk-size = 1*HEXDIG -# -# but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20 -chunk_size = r"({HEXDIG}){{1,20}}".format(**globals()) -# Actually -# -# chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) -# -# but we aren't parsing the things so we don't really care. -chunk_ext = r";.*" -chunk_header = ( - r"(?P{chunk_size})" - r"(?P{chunk_ext})?" - r"{OWS}\r\n".format( - **globals() - ) # Even though the specification does not allow for extra whitespaces, - # we are lenient with trailing whitespaces because some servers on the wild use it. -) diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_connection.py b/backend/venv39/lib/python3.9/site-packages/h11/_connection.py deleted file mode 100644 index e37d82a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_connection.py +++ /dev/null @@ -1,659 +0,0 @@ -# This contains the main Connection class. Everything in h11 revolves around -# this. -from typing import ( - Any, - Callable, - cast, - Dict, - List, - Optional, - overload, - Tuple, - Type, - Union, -) - -from ._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) -from ._headers import get_comma_header, has_expect_100_continue, set_comma_header -from ._readers import READERS, ReadersType -from ._receivebuffer import ReceiveBuffer -from ._state import ( - _SWITCH_CONNECT, - _SWITCH_UPGRADE, - CLIENT, - ConnectionState, - DONE, - ERROR, - MIGHT_SWITCH_PROTOCOL, - SEND_BODY, - SERVER, - SWITCHED_PROTOCOL, -) -from ._util import ( # Import the internal things we need - LocalProtocolError, - RemoteProtocolError, - Sentinel, -) -from ._writers import WRITERS, WritersType - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = ["Connection", "NEED_DATA", "PAUSED"] - - -class NEED_DATA(Sentinel, metaclass=Sentinel): - pass - - -class PAUSED(Sentinel, metaclass=Sentinel): - pass - - -# If we ever have this much buffered without it making a complete parseable -# event, we error out. The only time we really buffer is when reading the -# request/response line + headers together, so this is effectively the limit on -# the size of that. -# -# Some precedents for defaults: -# - node.js: 80 * 1024 -# - tomcat: 8 * 1024 -# - IIS: 16 * 1024 -# - Apache: <8 KiB per line> -DEFAULT_MAX_INCOMPLETE_EVENT_SIZE = 16 * 1024 - - -# RFC 7230's rules for connection lifecycles: -# - If either side says they want to close the connection, then the connection -# must close. -# - HTTP/1.1 defaults to keep-alive unless someone says Connection: close -# - HTTP/1.0 defaults to close unless both sides say Connection: keep-alive -# (and even this is a mess -- e.g. if you're implementing a proxy then -# sending Connection: keep-alive is forbidden). -# -# We simplify life by simply not supporting keep-alive with HTTP/1.0 peers. So -# our rule is: -# - If someone says Connection: close, we will close -# - If someone uses HTTP/1.0, we will close. -def _keep_alive(event: Union[Request, Response]) -> bool: - connection = get_comma_header(event.headers, b"connection") - if b"close" in connection: - return False - if getattr(event, "http_version", b"1.1") < b"1.1": - return False - return True - - -def _body_framing( - request_method: bytes, event: Union[Request, Response] -) -> Tuple[str, Union[Tuple[()], Tuple[int]]]: - # Called when we enter SEND_BODY to figure out framing information for - # this body. - # - # These are the only two events that can trigger a SEND_BODY state: - assert type(event) in (Request, Response) - # Returns one of: - # - # ("content-length", count) - # ("chunked", ()) - # ("http/1.0", ()) - # - # which are (lookup key, *args) for constructing body reader/writer - # objects. - # - # Reference: https://tools.ietf.org/html/rfc7230#section-3.3.3 - # - # Step 1: some responses always have an empty body, regardless of what the - # headers say. - if type(event) is Response: - if ( - event.status_code in (204, 304) - or request_method == b"HEAD" - or (request_method == b"CONNECT" and 200 <= event.status_code < 300) - ): - return ("content-length", (0,)) - # Section 3.3.3 also lists another case -- responses with status_code - # < 200. For us these are InformationalResponses, not Responses, so - # they can't get into this function in the first place. - assert event.status_code >= 200 - - # Step 2: check for Transfer-Encoding (T-E beats C-L): - transfer_encodings = get_comma_header(event.headers, b"transfer-encoding") - if transfer_encodings: - assert transfer_encodings == [b"chunked"] - return ("chunked", ()) - - # Step 3: check for Content-Length - content_lengths = get_comma_header(event.headers, b"content-length") - if content_lengths: - return ("content-length", (int(content_lengths[0]),)) - - # Step 4: no applicable headers; fallback/default depends on type - if type(event) is Request: - return ("content-length", (0,)) - else: - return ("http/1.0", ()) - - -################################################################ -# -# The main Connection class -# -################################################################ - - -class Connection: - """An object encapsulating the state of an HTTP connection. - - Args: - our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If - you're implementing a server, pass :data:`h11.SERVER`. - - max_incomplete_event_size (int): - The maximum number of bytes we're willing to buffer of an - incomplete event. In practice this mostly sets a limit on the - maximum size of the request/response line + headers. If this is - exceeded, then :meth:`next_event` will raise - :exc:`RemoteProtocolError`. - - """ - - def __init__( - self, - our_role: Type[Sentinel], - max_incomplete_event_size: int = DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, - ) -> None: - self._max_incomplete_event_size = max_incomplete_event_size - # State and role tracking - if our_role not in (CLIENT, SERVER): - raise ValueError(f"expected CLIENT or SERVER, not {our_role!r}") - self.our_role = our_role - self.their_role: Type[Sentinel] - if our_role is CLIENT: - self.their_role = SERVER - else: - self.their_role = CLIENT - self._cstate = ConnectionState() - - # Callables for converting data->events or vice-versa given the - # current state - self._writer = self._get_io_object(self.our_role, None, WRITERS) - self._reader = self._get_io_object(self.their_role, None, READERS) - - # Holds any unprocessed received data - self._receive_buffer = ReceiveBuffer() - # If this is true, then it indicates that the incoming connection was - # closed *after* the end of whatever's in self._receive_buffer: - self._receive_buffer_closed = False - - # Extra bits of state that don't fit into the state machine. - # - # These two are only used to interpret framing headers for figuring - # out how to read/write response bodies. their_http_version is also - # made available as a convenient public API. - self.their_http_version: Optional[bytes] = None - self._request_method: Optional[bytes] = None - # This is pure flow-control and doesn't at all affect the set of legal - # transitions, so no need to bother ConnectionState with it: - self.client_is_waiting_for_100_continue = False - - @property - def states(self) -> Dict[Type[Sentinel], Type[Sentinel]]: - """A dictionary like:: - - {CLIENT: , SERVER: } - - See :ref:`state-machine` for details. - - """ - return dict(self._cstate.states) - - @property - def our_state(self) -> Type[Sentinel]: - """The current state of whichever role we are playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.our_role] - - @property - def their_state(self) -> Type[Sentinel]: - """The current state of whichever role we are NOT playing. See - :ref:`state-machine` for details. - """ - return self._cstate.states[self.their_role] - - @property - def they_are_waiting_for_100_continue(self) -> bool: - return self.their_role is CLIENT and self.client_is_waiting_for_100_continue - - def start_next_cycle(self) -> None: - """Attempt to reset our connection state for a new request/response - cycle. - - If both client and server are in :data:`DONE` state, then resets them - both to :data:`IDLE` state in preparation for a new request/response - cycle on this same connection. Otherwise, raises a - :exc:`LocalProtocolError`. - - See :ref:`keepalive-and-pipelining`. - - """ - old_states = dict(self._cstate.states) - self._cstate.start_next_cycle() - self._request_method = None - # self.their_http_version gets left alone, since it presumably lasts - # beyond a single request/response cycle - assert not self.client_is_waiting_for_100_continue - self._respond_to_state_changes(old_states) - - def _process_error(self, role: Type[Sentinel]) -> None: - old_states = dict(self._cstate.states) - self._cstate.process_error(role) - self._respond_to_state_changes(old_states) - - def _server_switch_event(self, event: Event) -> Optional[Type[Sentinel]]: - if type(event) is InformationalResponse and event.status_code == 101: - return _SWITCH_UPGRADE - if type(event) is Response: - if ( - _SWITCH_CONNECT in self._cstate.pending_switch_proposals - and 200 <= event.status_code < 300 - ): - return _SWITCH_CONNECT - return None - - # All events go through here - def _process_event(self, role: Type[Sentinel], event: Event) -> None: - # First, pass the event through the state machine to make sure it - # succeeds. - old_states = dict(self._cstate.states) - if role is CLIENT and type(event) is Request: - if event.method == b"CONNECT": - self._cstate.process_client_switch_proposal(_SWITCH_CONNECT) - if get_comma_header(event.headers, b"upgrade"): - self._cstate.process_client_switch_proposal(_SWITCH_UPGRADE) - server_switch_event = None - if role is SERVER: - server_switch_event = self._server_switch_event(event) - self._cstate.process_event(role, type(event), server_switch_event) - - # Then perform the updates triggered by it. - - if type(event) is Request: - self._request_method = event.method - - if role is self.their_role and type(event) in ( - Request, - Response, - InformationalResponse, - ): - event = cast(Union[Request, Response, InformationalResponse], event) - self.their_http_version = event.http_version - - # Keep alive handling - # - # RFC 7230 doesn't really say what one should do if Connection: close - # shows up on a 1xx InformationalResponse. I think the idea is that - # this is not supposed to happen. In any case, if it does happen, we - # ignore it. - if type(event) in (Request, Response) and not _keep_alive( - cast(Union[Request, Response], event) - ): - self._cstate.process_keep_alive_disabled() - - # 100-continue - if type(event) is Request and has_expect_100_continue(event): - self.client_is_waiting_for_100_continue = True - if type(event) in (InformationalResponse, Response): - self.client_is_waiting_for_100_continue = False - if role is CLIENT and type(event) in (Data, EndOfMessage): - self.client_is_waiting_for_100_continue = False - - self._respond_to_state_changes(old_states, event) - - def _get_io_object( - self, - role: Type[Sentinel], - event: Optional[Event], - io_dict: Union[ReadersType, WritersType], - ) -> Optional[Callable[..., Any]]: - # event may be None; it's only used when entering SEND_BODY - state = self._cstate.states[role] - if state is SEND_BODY: - # Special case: the io_dict has a dict of reader/writer factories - # that depend on the request/response framing. - framing_type, args = _body_framing( - cast(bytes, self._request_method), cast(Union[Request, Response], event) - ) - return io_dict[SEND_BODY][framing_type](*args) # type: ignore[index] - else: - # General case: the io_dict just has the appropriate reader/writer - # for this state - return io_dict.get((role, state)) # type: ignore[return-value] - - # This must be called after any action that might have caused - # self._cstate.states to change. - def _respond_to_state_changes( - self, - old_states: Dict[Type[Sentinel], Type[Sentinel]], - event: Optional[Event] = None, - ) -> None: - # Update reader/writer - if self.our_state != old_states[self.our_role]: - self._writer = self._get_io_object(self.our_role, event, WRITERS) - if self.their_state != old_states[self.their_role]: - self._reader = self._get_io_object(self.their_role, event, READERS) - - @property - def trailing_data(self) -> Tuple[bytes, bool]: - """Data that has been received, but not yet processed, represented as - a tuple with two elements, where the first is a byte-string containing - the unprocessed data itself, and the second is a bool that is True if - the receive connection was closed. - - See :ref:`switching-protocols` for discussion of why you'd want this. - """ - return (bytes(self._receive_buffer), self._receive_buffer_closed) - - def receive_data(self, data: bytes) -> None: - """Add data to our internal receive buffer. - - This does not actually do any processing on the data, just stores - it. To trigger processing, you have to call :meth:`next_event`. - - Args: - data (:term:`bytes-like object`): - The new data that was just received. - - Special case: If *data* is an empty byte-string like ``b""``, - then this indicates that the remote side has closed the - connection (end of file). Normally this is convenient, because - standard Python APIs like :meth:`file.read` or - :meth:`socket.recv` use ``b""`` to indicate end-of-file, while - other failures to read are indicated using other mechanisms - like raising :exc:`TimeoutError`. When using such an API you - can just blindly pass through whatever you get from ``read`` - to :meth:`receive_data`, and everything will work. - - But, if you have an API where reading an empty string is a - valid non-EOF condition, then you need to be aware of this and - make sure to check for such strings and avoid passing them to - :meth:`receive_data`. - - Returns: - Nothing, but after calling this you should call :meth:`next_event` - to parse the newly received data. - - Raises: - RuntimeError: - Raised if you pass an empty *data*, indicating EOF, and then - pass a non-empty *data*, indicating more data that somehow - arrived after the EOF. - - (Calling ``receive_data(b"")`` multiple times is fine, - and equivalent to calling it once.) - - """ - if data: - if self._receive_buffer_closed: - raise RuntimeError("received close, then received more data?") - self._receive_buffer += data - else: - self._receive_buffer_closed = True - - def _extract_next_receive_event( - self, - ) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - state = self.their_state - # We don't pause immediately when they enter DONE, because even in - # DONE state we can still process a ConnectionClosed() event. But - # if we have data in our buffer, then we definitely aren't getting - # a ConnectionClosed() immediately and we need to pause. - if state is DONE and self._receive_buffer: - return PAUSED - if state is MIGHT_SWITCH_PROTOCOL or state is SWITCHED_PROTOCOL: - return PAUSED - assert self._reader is not None - event = self._reader(self._receive_buffer) - if event is None: - if not self._receive_buffer and self._receive_buffer_closed: - # In some unusual cases (basically just HTTP/1.0 bodies), EOF - # triggers an actual protocol event; in that case, we want to - # return that event, and then the state will change and we'll - # get called again to generate the actual ConnectionClosed(). - if hasattr(self._reader, "read_eof"): - event = self._reader.read_eof() - else: - event = ConnectionClosed() - if event is None: - event = NEED_DATA - return event # type: ignore[no-any-return] - - def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: - """Parse the next event out of our receive buffer, update our internal - state, and return it. - - This is a mutating operation -- think of it like calling :func:`next` - on an iterator. - - Returns: - : One of three things: - - 1) An event object -- see :ref:`events`. - - 2) The special constant :data:`NEED_DATA`, which indicates that - you need to read more data from your socket and pass it to - :meth:`receive_data` before this method will be able to return - any more events. - - 3) The special constant :data:`PAUSED`, which indicates that we - are not in a state where we can process incoming data (usually - because the peer has finished their part of the current - request/response cycle, and you have not yet called - :meth:`start_next_cycle`). See :ref:`flow-control` for details. - - Raises: - RemoteProtocolError: - The peer has misbehaved. You should close the connection - (possibly after sending some kind of 4xx response). - - Once this method returns :class:`ConnectionClosed` once, then all - subsequent calls will also return :class:`ConnectionClosed`. - - If this method raises any exception besides :exc:`RemoteProtocolError` - then that's a bug -- if it happens please file a bug report! - - If this method raises any exception then it also sets - :attr:`Connection.their_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - - if self.their_state is ERROR: - raise RemoteProtocolError("Can't receive data when peer state is ERROR") - try: - event = self._extract_next_receive_event() - if event not in [NEED_DATA, PAUSED]: - self._process_event(self.their_role, cast(Event, event)) - if event is NEED_DATA: - if len(self._receive_buffer) > self._max_incomplete_event_size: - # 431 is "Request header fields too large" which is pretty - # much the only situation where we can get here - raise RemoteProtocolError( - "Receive buffer too long", error_status_hint=431 - ) - if self._receive_buffer_closed: - # We're still trying to complete some event, but that's - # never going to happen because no more data is coming - raise RemoteProtocolError("peer unexpectedly closed connection") - return event - except BaseException as exc: - self._process_error(self.their_role) - if isinstance(exc, LocalProtocolError): - exc._reraise_as_remote_protocol_error() - else: - raise - - @overload - def send(self, event: ConnectionClosed) -> None: - ... - - @overload - def send( - self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] - ) -> bytes: - ... - - @overload - def send(self, event: Event) -> Optional[bytes]: - ... - - def send(self, event: Event) -> Optional[bytes]: - """Convert a high-level event into bytes that can be sent to the peer, - while updating our internal state machine. - - Args: - event: The :ref:`event ` to send. - - Returns: - If ``type(event) is ConnectionClosed``, then returns - ``None``. Otherwise, returns a :term:`bytes-like object`. - - Raises: - LocalProtocolError: - Sending this event at this time would violate our - understanding of the HTTP/1.1 protocol. - - If this method raises any exception then it also sets - :attr:`Connection.our_state` to :data:`ERROR` -- see - :ref:`error-handling` for discussion. - - """ - data_list = self.send_with_data_passthrough(event) - if data_list is None: - return None - else: - return b"".join(data_list) - - def send_with_data_passthrough(self, event: Event) -> Optional[List[bytes]]: - """Identical to :meth:`send`, except that in situations where - :meth:`send` returns a single :term:`bytes-like object`, this instead - returns a list of them -- and when sending a :class:`Data` event, this - list is guaranteed to contain the exact object you passed in as - :attr:`Data.data`. See :ref:`sendfile` for discussion. - - """ - if self.our_state is ERROR: - raise LocalProtocolError("Can't send data when our state is ERROR") - try: - if type(event) is Response: - event = self._clean_up_response_headers_for_sending(event) - # We want to call _process_event before calling the writer, - # because if someone tries to do something invalid then this will - # give a sensible error message, while our writers all just assume - # they will only receive valid events. But, _process_event might - # change self._writer. So we have to do a little dance: - writer = self._writer - self._process_event(self.our_role, event) - if type(event) is ConnectionClosed: - return None - else: - # In any situation where writer is None, process_event should - # have raised ProtocolError - assert writer is not None - data_list: List[bytes] = [] - writer(event, data_list.append) - return data_list - except: - self._process_error(self.our_role) - raise - - def send_failed(self) -> None: - """Notify the state machine that we failed to send the data it gave - us. - - This causes :attr:`Connection.our_state` to immediately become - :data:`ERROR` -- see :ref:`error-handling` for discussion. - - """ - self._process_error(self.our_role) - - # When sending a Response, we take responsibility for a few things: - # - # - Sometimes you MUST set Connection: close. We take care of those - # times. (You can also set it yourself if you want, and if you do then - # we'll respect that and close the connection at the right time. But you - # don't have to worry about that unless you want to.) - # - # - The user has to set Content-Length if they want it. Otherwise, for - # responses that have bodies (e.g. not HEAD), then we will automatically - # select the right mechanism for streaming a body of unknown length, - # which depends on depending on the peer's HTTP version. - # - # This function's *only* responsibility is making sure headers are set up - # right -- everything downstream just looks at the headers. There are no - # side channels. - def _clean_up_response_headers_for_sending(self, response: Response) -> Response: - assert type(response) is Response - - headers = response.headers - need_close = False - - # HEAD requests need some special handling: they always act like they - # have Content-Length: 0, and that's how _body_framing treats - # them. But their headers are supposed to match what we would send if - # the request was a GET. (Technically there is one deviation allowed: - # we're allowed to leave out the framing headers -- see - # https://tools.ietf.org/html/rfc7231#section-4.3.2 . But it's just as - # easy to get them right.) - method_for_choosing_headers = cast(bytes, self._request_method) - if method_for_choosing_headers == b"HEAD": - method_for_choosing_headers = b"GET" - framing_type, _ = _body_framing(method_for_choosing_headers, response) - if framing_type in ("chunked", "http/1.0"): - # This response has a body of unknown length. - # If our peer is HTTP/1.1, we use Transfer-Encoding: chunked - # If our peer is HTTP/1.0, we use no framing headers, and close the - # connection afterwards. - # - # Make sure to clear Content-Length (in principle user could have - # set both and then we ignored Content-Length b/c - # Transfer-Encoding overwrote it -- this would be naughty of them, - # but the HTTP spec says that if our peer does this then we have - # to fix it instead of erroring out, so we'll accord the user the - # same respect). - headers = set_comma_header(headers, b"content-length", []) - if self.their_http_version is None or self.their_http_version < b"1.1": - # Either we never got a valid request and are sending back an - # error (their_http_version is None), so we assume the worst; - # or else we did get a valid HTTP/1.0 request, so we know that - # they don't understand chunked encoding. - headers = set_comma_header(headers, b"transfer-encoding", []) - # This is actually redundant ATM, since currently we - # unconditionally disable keep-alive when talking to HTTP/1.0 - # peers. But let's be defensive just in case we add - # Connection: keep-alive support later: - if self._request_method != b"HEAD": - need_close = True - else: - headers = set_comma_header(headers, b"transfer-encoding", [b"chunked"]) - - if not self._cstate.keep_alive or need_close: - # Make sure Connection: close is set - connection = set(get_comma_header(headers, b"connection")) - connection.discard(b"keep-alive") - connection.add(b"close") - headers = set_comma_header(headers, b"connection", sorted(connection)) - - return Response( - headers=headers, - status_code=response.status_code, - http_version=response.http_version, - reason=response.reason, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_events.py b/backend/venv39/lib/python3.9/site-packages/h11/_events.py deleted file mode 100644 index ca1c3ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_events.py +++ /dev/null @@ -1,369 +0,0 @@ -# High level events that make up HTTP/1.1 conversations. Loosely inspired by -# the corresponding events in hyper-h2: -# -# http://python-hyper.org/h2/en/stable/api.html#events -# -# Don't subclass these. Stuff will break. - -import re -from abc import ABC -from dataclasses import dataclass -from typing import List, Tuple, Union - -from ._abnf import method, request_target -from ._headers import Headers, normalize_and_validate -from ._util import bytesify, LocalProtocolError, validate - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "Event", - "Request", - "InformationalResponse", - "Response", - "Data", - "EndOfMessage", - "ConnectionClosed", -] - -method_re = re.compile(method.encode("ascii")) -request_target_re = re.compile(request_target.encode("ascii")) - - -class Event(ABC): - """ - Base class for h11 events. - """ - - __slots__ = () - - -@dataclass(init=False, frozen=True) -class Request(Event): - """The beginning of an HTTP request. - - Fields: - - .. attribute:: method - - An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: target - - The target of an HTTP request, e.g. ``b"/index.html"``, or one of the - more exotic formats described in `RFC 7320, section 5.3 - `_. Always a byte - string. :term:`Bytes-like objects ` and native - strings containing only ascii characters will be automatically - converted to byte strings. - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - """ - - __slots__ = ("method", "headers", "target", "http_version") - - method: bytes - headers: Headers - target: bytes - http_version: bytes - - def __init__( - self, - *, - method: Union[bytes, str], - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - target: Union[bytes, str], - http_version: Union[bytes, str] = b"1.1", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "method", bytesify(method)) - object.__setattr__(self, "target", bytesify(target)) - object.__setattr__(self, "http_version", bytesify(http_version)) - else: - object.__setattr__(self, "method", method) - object.__setattr__(self, "target", target) - object.__setattr__(self, "http_version", http_version) - - # "A server MUST respond with a 400 (Bad Request) status code to any - # HTTP/1.1 request message that lacks a Host header field and to any - # request message that contains more than one Host header field or a - # Host header field with an invalid field-value." - # -- https://tools.ietf.org/html/rfc7230#section-5.4 - host_count = 0 - for name, value in self.headers: - if name == b"host": - host_count += 1 - if self.http_version == b"1.1" and host_count == 0: - raise LocalProtocolError("Missing mandatory Host: header") - if host_count > 1: - raise LocalProtocolError("Found multiple Host: headers") - - validate(method_re, self.method, "Illegal method characters") - validate(request_target_re, self.target, "Illegal target characters") - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class _ResponseBase(Event): - __slots__ = ("headers", "http_version", "reason", "status_code") - - headers: Headers - http_version: bytes - reason: bytes - status_code: int - - def __init__( - self, - *, - headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], - status_code: int, - http_version: Union[bytes, str] = b"1.1", - reason: Union[bytes, str] = b"", - _parsed: bool = False, - ) -> None: - super().__init__() - if isinstance(headers, Headers): - object.__setattr__(self, "headers", headers) - else: - object.__setattr__( - self, "headers", normalize_and_validate(headers, _parsed=_parsed) - ) - if not _parsed: - object.__setattr__(self, "reason", bytesify(reason)) - object.__setattr__(self, "http_version", bytesify(http_version)) - if not isinstance(status_code, int): - raise LocalProtocolError("status code must be integer") - # Because IntEnum objects are instances of int, but aren't - # duck-compatible (sigh), see gh-72. - object.__setattr__(self, "status_code", int(status_code)) - else: - object.__setattr__(self, "reason", reason) - object.__setattr__(self, "http_version", http_version) - object.__setattr__(self, "status_code", status_code) - - self.__post_init__() - - def __post_init__(self) -> None: - pass - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class InformationalResponse(_ResponseBase): - """An HTTP informational response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`InformationalResponse`, this is always in the range [100, - 200). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for - details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (100 <= self.status_code < 200): - raise LocalProtocolError( - "InformationalResponse status_code should be in range " - "[100, 200), not {}".format(self.status_code) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Response(_ResponseBase): - """The beginning of an HTTP response. - - Fields: - - .. attribute:: status_code - - The status code of this response, as an integer. For an - :class:`Response`, this is always in the range [200, - 1000). - - .. attribute:: headers - - Request headers, represented as a list of (name, value) pairs. See - :ref:`the header normalization rules ` for details. - - .. attribute:: http_version - - The HTTP protocol version, represented as a byte string like - ``b"1.1"``. See :ref:`the HTTP version normalization rules - ` for details. - - .. attribute:: reason - - The reason phrase of this response, as a byte string. For example: - ``b"OK"``, or ``b"Not Found"``. - - """ - - def __post_init__(self) -> None: - if not (200 <= self.status_code < 1000): - raise LocalProtocolError( - "Response status_code should be in range [200, 1000), not {}".format( - self.status_code - ) - ) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(init=False, frozen=True) -class Data(Event): - """Part of an HTTP message body. - - Fields: - - .. attribute:: data - - A :term:`bytes-like object` containing part of a message body. Or, if - using the ``combine=False`` argument to :meth:`Connection.send`, then - any object that your socket writing code knows what to do with, and for - which calling :func:`len` returns the number of bytes that will be - written -- see :ref:`sendfile` for details. - - .. attribute:: chunk_start - - A marker that indicates whether this data object is from the start of a - chunked transfer encoding chunk. This field is ignored when when a Data - event is provided to :meth:`Connection.send`: it is only valid on - events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - .. attribute:: chunk_end - - A marker that indicates whether this data object is the last for a - given chunked transfer encoding chunk. This field is ignored when when - a Data event is provided to :meth:`Connection.send`: it is only valid - on events emitted from :meth:`Connection.next_event`. You probably - shouldn't use this attribute at all; see - :ref:`chunk-delimiters-are-bad` for details. - - """ - - __slots__ = ("data", "chunk_start", "chunk_end") - - data: bytes - chunk_start: bool - chunk_end: bool - - def __init__( - self, data: bytes, chunk_start: bool = False, chunk_end: bool = False - ) -> None: - object.__setattr__(self, "data", data) - object.__setattr__(self, "chunk_start", chunk_start) - object.__setattr__(self, "chunk_end", chunk_end) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -# XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that -# are forbidden to be sent in a trailer, since processing them as if they were -# present in the header section might bypass external security filters." -# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part -# Unfortunately, the list of forbidden fields is long and vague :-/ -@dataclass(init=False, frozen=True) -class EndOfMessage(Event): - """The end of an HTTP message. - - Fields: - - .. attribute:: headers - - Default value: ``[]`` - - Any trailing headers attached to this message, represented as a list of - (name, value) pairs. See :ref:`the header normalization rules - ` for details. - - Must be empty unless ``Transfer-Encoding: chunked`` is in use. - - """ - - __slots__ = ("headers",) - - headers: Headers - - def __init__( - self, - *, - headers: Union[ - Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]], None - ] = None, - _parsed: bool = False, - ) -> None: - super().__init__() - if headers is None: - headers = Headers([]) - elif not isinstance(headers, Headers): - headers = normalize_and_validate(headers, _parsed=_parsed) - - object.__setattr__(self, "headers", headers) - - # This is an unhashable type. - __hash__ = None # type: ignore - - -@dataclass(frozen=True) -class ConnectionClosed(Event): - """This event indicates that the sender has closed their outgoing - connection. - - Note that this does not necessarily mean that they can't *receive* further - data, because TCP connections are composed to two one-way channels which - can be closed independently. See :ref:`closing` for details. - - No fields. - """ - - pass diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_headers.py b/backend/venv39/lib/python3.9/site-packages/h11/_headers.py deleted file mode 100644 index 31da3e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_headers.py +++ /dev/null @@ -1,282 +0,0 @@ -import re -from typing import AnyStr, cast, List, overload, Sequence, Tuple, TYPE_CHECKING, Union - -from ._abnf import field_name, field_value -from ._util import bytesify, LocalProtocolError, validate - -if TYPE_CHECKING: - from ._events import Request - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal # type: ignore - -CONTENT_LENGTH_MAX_DIGITS = 20 # allow up to 1 billion TB - 1 - - -# Facts -# ----- -# -# Headers are: -# keys: case-insensitive ascii -# values: mixture of ascii and raw bytes -# -# "Historically, HTTP has allowed field content with text in the ISO-8859-1 -# charset [ISO-8859-1], supporting other charsets only through use of -# [RFC2047] encoding. In practice, most HTTP header field values use only a -# subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD -# limit their field values to US-ASCII octets. A recipient SHOULD treat other -# octets in field content (obs-text) as opaque data." -# And it deprecates all non-ascii values -# -# Leading/trailing whitespace in header names is forbidden -# -# Values get leading/trailing whitespace stripped -# -# Content-Disposition actually needs to contain unicode semantically; to -# accomplish this it has a terrifically weird way of encoding the filename -# itself as ascii (and even this still has lots of cross-browser -# incompatibilities) -# -# Order is important: -# "a proxy MUST NOT change the order of these field values when forwarding a -# message" -# (and there are several headers where the order indicates a preference) -# -# Multiple occurences of the same header: -# "A sender MUST NOT generate multiple header fields with the same field name -# in a message unless either the entire field value for that header field is -# defined as a comma-separated list [or the header is Set-Cookie which gets a -# special exception]" - RFC 7230. (cookies are in RFC 6265) -# -# So every header aside from Set-Cookie can be merged by b", ".join if it -# occurs repeatedly. But, of course, they can't necessarily be split by -# .split(b","), because quoting. -# -# Given all this mess (case insensitive, duplicates allowed, order is -# important, ...), there doesn't appear to be any standard way to handle -# headers in Python -- they're almost like dicts, but... actually just -# aren't. For now we punt and just use a super simple representation: headers -# are a list of pairs -# -# [(name1, value1), (name2, value2), ...] -# -# where all entries are bytestrings, names are lowercase and have no -# leading/trailing whitespace, and values are bytestrings with no -# leading/trailing whitespace. Searching and updating are done via naive O(n) -# methods. -# -# Maybe a dict-of-lists would be better? - -_content_length_re = re.compile(rb"[0-9]+") -_field_name_re = re.compile(field_name.encode("ascii")) -_field_value_re = re.compile(field_value.encode("ascii")) - - -class Headers(Sequence[Tuple[bytes, bytes]]): - """ - A list-like interface that allows iterating over headers as byte-pairs - of (lowercased-name, value). - - Internally we actually store the representation as three-tuples, - including both the raw original casing, in order to preserve casing - over-the-wire, and the lowercased name, for case-insensitive comparisions. - - r = Request( - method="GET", - target="/", - headers=[("Host", "example.org"), ("Connection", "keep-alive")], - http_version="1.1", - ) - assert r.headers == [ - (b"host", b"example.org"), - (b"connection", b"keep-alive") - ] - assert r.headers.raw_items() == [ - (b"Host", b"example.org"), - (b"Connection", b"keep-alive") - ] - """ - - __slots__ = "_full_items" - - def __init__(self, full_items: List[Tuple[bytes, bytes, bytes]]) -> None: - self._full_items = full_items - - def __bool__(self) -> bool: - return bool(self._full_items) - - def __eq__(self, other: object) -> bool: - return list(self) == list(other) # type: ignore - - def __len__(self) -> int: - return len(self._full_items) - - def __repr__(self) -> str: - return "" % repr(list(self)) - - def __getitem__(self, idx: int) -> Tuple[bytes, bytes]: # type: ignore[override] - _, name, value = self._full_items[idx] - return (name, value) - - def raw_items(self) -> List[Tuple[bytes, bytes]]: - return [(raw_name, value) for raw_name, _, value in self._full_items] - - -HeaderTypes = Union[ - List[Tuple[bytes, bytes]], - List[Tuple[bytes, str]], - List[Tuple[str, bytes]], - List[Tuple[str, str]], -] - - -@overload -def normalize_and_validate(headers: Headers, _parsed: Literal[True]) -> Headers: - ... - - -@overload -def normalize_and_validate(headers: HeaderTypes, _parsed: Literal[False]) -> Headers: - ... - - -@overload -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - ... - - -def normalize_and_validate( - headers: Union[Headers, HeaderTypes], _parsed: bool = False -) -> Headers: - new_headers = [] - seen_content_length = None - saw_transfer_encoding = False - for name, value in headers: - # For headers coming out of the parser, we can safely skip some steps, - # because it always returns bytes and has already run these regexes - # over the data: - if not _parsed: - name = bytesify(name) - value = bytesify(value) - validate(_field_name_re, name, "Illegal header name {!r}", name) - validate(_field_value_re, value, "Illegal header value {!r}", value) - assert isinstance(name, bytes) - assert isinstance(value, bytes) - - raw_name = name - name = name.lower() - if name == b"content-length": - lengths = {length.strip() for length in value.split(b",")} - if len(lengths) != 1: - raise LocalProtocolError("conflicting Content-Length headers") - value = lengths.pop() - validate(_content_length_re, value, "bad Content-Length") - if len(value) > CONTENT_LENGTH_MAX_DIGITS: - raise LocalProtocolError("bad Content-Length") - if seen_content_length is None: - seen_content_length = value - new_headers.append((raw_name, name, value)) - elif seen_content_length != value: - raise LocalProtocolError("conflicting Content-Length headers") - elif name == b"transfer-encoding": - # "A server that receives a request message with a transfer coding - # it does not understand SHOULD respond with 501 (Not - # Implemented)." - # https://tools.ietf.org/html/rfc7230#section-3.3.1 - if saw_transfer_encoding: - raise LocalProtocolError( - "multiple Transfer-Encoding headers", error_status_hint=501 - ) - # "All transfer-coding names are case-insensitive" - # -- https://tools.ietf.org/html/rfc7230#section-4 - value = value.lower() - if value != b"chunked": - raise LocalProtocolError( - "Only Transfer-Encoding: chunked is supported", - error_status_hint=501, - ) - saw_transfer_encoding = True - new_headers.append((raw_name, name, value)) - else: - new_headers.append((raw_name, name, value)) - return Headers(new_headers) - - -def get_comma_header(headers: Headers, name: bytes) -> List[bytes]: - # Should only be used for headers whose value is a list of - # comma-separated, case-insensitive values. - # - # The header name `name` is expected to be lower-case bytes. - # - # Connection: meets these criteria (including cast insensitivity). - # - # Content-Length: technically is just a single value (1*DIGIT), but the - # standard makes reference to implementations that do multiple values, and - # using this doesn't hurt. Ditto, case insensitivity doesn't things either - # way. - # - # Transfer-Encoding: is more complex (allows for quoted strings), so - # splitting on , is actually wrong. For example, this is legal: - # - # Transfer-Encoding: foo; options="1,2", chunked - # - # and should be parsed as - # - # foo; options="1,2" - # chunked - # - # but this naive function will parse it as - # - # foo; options="1 - # 2" - # chunked - # - # However, this is okay because the only thing we are going to do with - # any Transfer-Encoding is reject ones that aren't just "chunked", so - # both of these will be treated the same anyway. - # - # Expect: the only legal value is the literal string - # "100-continue". Splitting on commas is harmless. Case insensitive. - # - out: List[bytes] = [] - for _, found_name, found_raw_value in headers._full_items: - if found_name == name: - found_raw_value = found_raw_value.lower() - for found_split_value in found_raw_value.split(b","): - found_split_value = found_split_value.strip() - if found_split_value: - out.append(found_split_value) - return out - - -def set_comma_header(headers: Headers, name: bytes, new_values: List[bytes]) -> Headers: - # The header name `name` is expected to be lower-case bytes. - # - # Note that when we store the header we use title casing for the header - # names, in order to match the conventional HTTP header style. - # - # Simply calling `.title()` is a blunt approach, but it's correct - # here given the cases where we're using `set_comma_header`... - # - # Connection, Content-Length, Transfer-Encoding. - new_headers: List[Tuple[bytes, bytes]] = [] - for found_raw_name, found_name, found_raw_value in headers._full_items: - if found_name != name: - new_headers.append((found_raw_name, found_raw_value)) - for new_value in new_values: - new_headers.append((name.title(), new_value)) - return normalize_and_validate(new_headers) - - -def has_expect_100_continue(request: "Request") -> bool: - # https://tools.ietf.org/html/rfc7231#section-5.1.1 - # "A server that receives a 100-continue expectation in an HTTP/1.0 request - # MUST ignore that expectation." - if request.http_version < b"1.1": - return False - expect = get_comma_header(request.headers, b"expect") - return b"100-continue" in expect diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_readers.py b/backend/venv39/lib/python3.9/site-packages/h11/_readers.py deleted file mode 100644 index 576804c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_readers.py +++ /dev/null @@ -1,250 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each reader is a callable which takes a ReceiveBuffer object, and -# either: -# 1) consumes some of it and returns an Event -# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() -# and it might raise a LocalProtocolError, so simpler just to always use -# this) -# 3) returns None, meaning "I need more data" -# -# If they have a .read_eof attribute, then this will be called if an EOF is -# received -- but this is optional. Either way, the actual ConnectionClosed -# event will be generated afterwards. -# -# READERS is a dict describing how to pick a reader. It maps states to either: -# - a reader -# - or, for body readers, a dict of per-framing reader factories - -import re -from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union - -from ._abnf import chunk_header, header_field, request_line, status_line -from ._events import Data, EndOfMessage, InformationalResponse, Request, Response -from ._receivebuffer import ReceiveBuffer -from ._state import ( - CLIENT, - CLOSED, - DONE, - IDLE, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, -) -from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate - -__all__ = ["READERS"] - -header_field_re = re.compile(header_field.encode("ascii")) -obs_fold_re = re.compile(rb"[ \t]+") - - -def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: - it = iter(lines) - last: Optional[bytes] = None - for line in it: - match = obs_fold_re.match(line) - if match: - if last is None: - raise LocalProtocolError("continuation line at start of headers") - if not isinstance(last, bytearray): - # Cast to a mutable type, avoiding copy on append to ensure O(n) time - last = bytearray(last) - last += b" " - last += line[match.end() :] - else: - if last is not None: - yield last - last = line - if last is not None: - yield last - - -def _decode_header_lines( - lines: Iterable[bytes], -) -> Iterable[Tuple[bytes, bytes]]: - for line in _obsolete_line_fold(lines): - matches = validate(header_field_re, line, "illegal header line: {!r}", line) - yield (matches["field_name"], matches["field_value"]) - - -request_line_re = re.compile(request_line.encode("ascii")) - - -def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no request line received") - matches = validate( - request_line_re, lines[0], "illegal request line: {!r}", lines[0] - ) - return Request( - headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches - ) - - -status_line_re = re.compile(status_line.encode("ascii")) - - -def maybe_read_from_SEND_RESPONSE_server( - buf: ReceiveBuffer, -) -> Union[InformationalResponse, Response, None]: - lines = buf.maybe_extract_lines() - if lines is None: - if buf.is_next_line_obviously_invalid_request_line(): - raise LocalProtocolError("illegal request line") - return None - if not lines: - raise LocalProtocolError("no response line received") - matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) - http_version = ( - b"1.1" if matches["http_version"] is None else matches["http_version"] - ) - reason = b"" if matches["reason"] is None else matches["reason"] - status_code = int(matches["status_code"]) - class_: Union[Type[InformationalResponse], Type[Response]] = ( - InformationalResponse if status_code < 200 else Response - ) - return class_( - headers=list(_decode_header_lines(lines[1:])), - _parsed=True, - status_code=status_code, - reason=reason, - http_version=http_version, - ) - - -class ContentLengthReader: - def __init__(self, length: int) -> None: - self._length = length - self._remaining = length - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._remaining == 0: - return EndOfMessage() - data = buf.maybe_extract_at_most(self._remaining) - if data is None: - return None - self._remaining -= len(data) - return Data(data=data) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(received {} bytes, expected {})".format( - self._length - self._remaining, self._length - ) - ) - - -chunk_header_re = re.compile(chunk_header.encode("ascii")) - - -class ChunkedReader: - def __init__(self) -> None: - self._bytes_in_chunk = 0 - # After reading a chunk, we have to throw away the trailing \r\n. - # This tracks the bytes that we need to match and throw away. - self._bytes_to_discard = b"" - self._reading_trailer = False - - def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: - if self._reading_trailer: - lines = buf.maybe_extract_lines() - if lines is None: - return None - return EndOfMessage(headers=list(_decode_header_lines(lines))) - if self._bytes_to_discard: - data = buf.maybe_extract_at_most(len(self._bytes_to_discard)) - if data is None: - return None - if data != self._bytes_to_discard[: len(data)]: - raise LocalProtocolError( - f"malformed chunk footer: {data!r} (expected {self._bytes_to_discard!r})" - ) - self._bytes_to_discard = self._bytes_to_discard[len(data) :] - if self._bytes_to_discard: - return None - # else, fall through and read some more - assert self._bytes_to_discard == b"" - if self._bytes_in_chunk == 0: - # We need to refill our chunk count - chunk_header = buf.maybe_extract_next_line() - if chunk_header is None: - return None - matches = validate( - chunk_header_re, - chunk_header, - "illegal chunk header: {!r}", - chunk_header, - ) - # XX FIXME: we discard chunk extensions. Does anyone care? - self._bytes_in_chunk = int(matches["chunk_size"], base=16) - if self._bytes_in_chunk == 0: - self._reading_trailer = True - return self(buf) - chunk_start = True - else: - chunk_start = False - assert self._bytes_in_chunk > 0 - data = buf.maybe_extract_at_most(self._bytes_in_chunk) - if data is None: - return None - self._bytes_in_chunk -= len(data) - if self._bytes_in_chunk == 0: - self._bytes_to_discard = b"\r\n" - chunk_end = True - else: - chunk_end = False - return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) - - def read_eof(self) -> NoReturn: - raise RemoteProtocolError( - "peer closed connection without sending complete message body " - "(incomplete chunked read)" - ) - - -class Http10Reader: - def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: - data = buf.maybe_extract_at_most(999999999) - if data is None: - return None - return Data(data=data) - - def read_eof(self) -> EndOfMessage: - return EndOfMessage() - - -def expect_nothing(buf: ReceiveBuffer) -> None: - if buf: - raise LocalProtocolError("Got data when expecting EOF") - return None - - -ReadersType = Dict[ - Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], - Union[Callable[..., Any], Dict[str, Callable[..., Any]]], -] - -READERS: ReadersType = { - (CLIENT, IDLE): maybe_read_from_IDLE_client, - (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, - (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, - (CLIENT, DONE): expect_nothing, - (CLIENT, MUST_CLOSE): expect_nothing, - (CLIENT, CLOSED): expect_nothing, - (SERVER, DONE): expect_nothing, - (SERVER, MUST_CLOSE): expect_nothing, - (SERVER, CLOSED): expect_nothing, - SEND_BODY: { - "chunked": ChunkedReader, - "content-length": ContentLengthReader, - "http/1.0": Http10Reader, - }, -} diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_receivebuffer.py b/backend/venv39/lib/python3.9/site-packages/h11/_receivebuffer.py deleted file mode 100644 index e5c4e08..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_receivebuffer.py +++ /dev/null @@ -1,153 +0,0 @@ -import re -import sys -from typing import List, Optional, Union - -__all__ = ["ReceiveBuffer"] - - -# Operations we want to support: -# - find next \r\n or \r\n\r\n (\n or \n\n are also acceptable), -# or wait until there is one -# - read at-most-N bytes -# Goals: -# - on average, do this fast -# - worst case, do this in O(n) where n is the number of bytes processed -# Plan: -# - store bytearray, offset, how far we've searched for a separator token -# - use the how-far-we've-searched data to avoid rescanning -# - while doing a stream of uninterrupted processing, advance offset instead -# of constantly copying -# WARNING: -# - I haven't benchmarked or profiled any of this yet. -# -# Note that starting in Python 3.4, deleting the initial n bytes from a -# bytearray is amortized O(n), thanks to some excellent work by Antoine -# Martin: -# -# https://bugs.python.org/issue19087 -# -# This means that if we only supported 3.4+, we could get rid of the code here -# involving self._start and self.compress, because it's doing exactly the same -# thing that bytearray now does internally. -# -# BUT unfortunately, we still support 2.7, and reading short segments out of a -# long buffer MUST be O(bytes read) to avoid DoS issues, so we can't actually -# delete this code. Yet: -# -# https://pythonclock.org/ -# -# (Two things to double-check first though: make sure PyPy also has the -# optimization, and benchmark to make sure it's a win, since we do have a -# slightly clever thing where we delay calling compress() until we've -# processed a whole event, which could in theory be slightly more efficient -# than the internal bytearray support.) -blank_line_regex = re.compile(b"\n\r?\n", re.MULTILINE) - - -class ReceiveBuffer: - def __init__(self) -> None: - self._data = bytearray() - self._next_line_search = 0 - self._multiple_lines_search = 0 - - def __iadd__(self, byteslike: Union[bytes, bytearray]) -> "ReceiveBuffer": - self._data += byteslike - return self - - def __bool__(self) -> bool: - return bool(len(self)) - - def __len__(self) -> int: - return len(self._data) - - # for @property unprocessed_data - def __bytes__(self) -> bytes: - return bytes(self._data) - - def _extract(self, count: int) -> bytearray: - # extracting an initial slice of the data buffer and return it - out = self._data[:count] - del self._data[:count] - - self._next_line_search = 0 - self._multiple_lines_search = 0 - - return out - - def maybe_extract_at_most(self, count: int) -> Optional[bytearray]: - """ - Extract a fixed number of bytes from the buffer. - """ - out = self._data[:count] - if not out: - return None - - return self._extract(count) - - def maybe_extract_next_line(self) -> Optional[bytearray]: - """ - Extract the first line, if it is completed in the buffer. - """ - # Only search in buffer space that we've not already looked at. - search_start_index = max(0, self._next_line_search - 1) - partial_idx = self._data.find(b"\r\n", search_start_index) - - if partial_idx == -1: - self._next_line_search = len(self._data) - return None - - # + 2 is to compensate len(b"\r\n") - idx = partial_idx + 2 - - return self._extract(idx) - - def maybe_extract_lines(self) -> Optional[List[bytearray]]: - """ - Extract everything up to the first blank line, and return a list of lines. - """ - # Handle the case where we have an immediate empty line. - if self._data[:1] == b"\n": - self._extract(1) - return [] - - if self._data[:2] == b"\r\n": - self._extract(2) - return [] - - # Only search in buffer space that we've not already looked at. - match = blank_line_regex.search(self._data, self._multiple_lines_search) - if match is None: - self._multiple_lines_search = max(0, len(self._data) - 2) - return None - - # Truncate the buffer and return it. - idx = match.span(0)[-1] - out = self._extract(idx) - lines = out.split(b"\n") - - for line in lines: - if line.endswith(b"\r"): - del line[-1] - - assert lines[-2] == lines[-1] == b"" - - del lines[-2:] - - return lines - - # In theory we should wait until `\r\n` before starting to validate - # incoming data. However it's interesting to detect (very) invalid data - # early given they might not even contain `\r\n` at all (hence only - # timeout will get rid of them). - # This is not a 100% effective detection but more of a cheap sanity check - # allowing for early abort in some useful cases. - # This is especially interesting when peer is messing up with HTTPS and - # sent us a TLS stream where we were expecting plain HTTP given all - # versions of TLS so far start handshake with a 0x16 message type code. - def is_next_line_obviously_invalid_request_line(self) -> bool: - try: - # HTTP header line must not contain non-printable characters - # and should not start with a space - return self._data[0] < 0x21 - except IndexError: - return False diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_state.py b/backend/venv39/lib/python3.9/site-packages/h11/_state.py deleted file mode 100644 index 3ad444b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_state.py +++ /dev/null @@ -1,365 +0,0 @@ -################################################################ -# The core state machine -################################################################ -# -# Rule 1: everything that affects the state machine and state transitions must -# live here in this file. As much as possible goes into the table-based -# representation, but for the bits that don't quite fit, the actual code and -# state must nonetheless live here. -# -# Rule 2: this file does not know about what role we're playing; it only knows -# about HTTP request/response cycles in the abstract. This ensures that we -# don't cheat and apply different rules to local and remote parties. -# -# -# Theory of operation -# =================== -# -# Possibly the simplest way to think about this is that we actually have 5 -# different state machines here. Yes, 5. These are: -# -# 1) The client state, with its complicated automaton (see the docs) -# 2) The server state, with its complicated automaton (see the docs) -# 3) The keep-alive state, with possible states {True, False} -# 4) The SWITCH_CONNECT state, with possible states {False, True} -# 5) The SWITCH_UPGRADE state, with possible states {False, True} -# -# For (3)-(5), the first state listed is the initial state. -# -# (1)-(3) are stored explicitly in member variables. The last -# two are stored implicitly in the pending_switch_proposals set as: -# (state of 4) == (_SWITCH_CONNECT in pending_switch_proposals) -# (state of 5) == (_SWITCH_UPGRADE in pending_switch_proposals) -# -# And each of these machines has two different kinds of transitions: -# -# a) Event-triggered -# b) State-triggered -# -# Event triggered is the obvious thing that you'd think it is: some event -# happens, and if it's the right event at the right time then a transition -# happens. But there are somewhat complicated rules for which machines can -# "see" which events. (As a rule of thumb, if a machine "sees" an event, this -# means two things: the event can affect the machine, and if the machine is -# not in a state where it expects that event then it's an error.) These rules -# are: -# -# 1) The client machine sees all h11.events objects emitted by the client. -# -# 2) The server machine sees all h11.events objects emitted by the server. -# -# It also sees the client's Request event. -# -# And sometimes, server events are annotated with a _SWITCH_* event. For -# example, we can have a (Response, _SWITCH_CONNECT) event, which is -# different from a regular Response event. -# -# 3) The keep-alive machine sees the process_keep_alive_disabled() event -# (which is derived from Request/Response events), and this event -# transitions it from True -> False, or from False -> False. There's no way -# to transition back. -# -# 4&5) The _SWITCH_* machines transition from False->True when we get a -# Request that proposes the relevant type of switch (via -# process_client_switch_proposals), and they go from True->False when we -# get a Response that has no _SWITCH_* annotation. -# -# So that's event-triggered transitions. -# -# State-triggered transitions are less standard. What they do here is couple -# the machines together. The way this works is, when certain *joint* -# configurations of states are achieved, then we automatically transition to a -# new *joint* state. So, for example, if we're ever in a joint state with -# -# client: DONE -# keep-alive: False -# -# then the client state immediately transitions to: -# -# client: MUST_CLOSE -# -# This is fundamentally different from an event-based transition, because it -# doesn't matter how we arrived at the {client: DONE, keep-alive: False} state -# -- maybe the client transitioned SEND_BODY -> DONE, or keep-alive -# transitioned True -> False. Either way, once this precondition is satisfied, -# this transition is immediately triggered. -# -# What if two conflicting state-based transitions get enabled at the same -# time? In practice there's only one case where this arises (client DONE -> -# MIGHT_SWITCH_PROTOCOL versus DONE -> MUST_CLOSE), and we resolve it by -# explicitly prioritizing the DONE -> MIGHT_SWITCH_PROTOCOL transition. -# -# Implementation -# -------------- -# -# The event-triggered transitions for the server and client machines are all -# stored explicitly in a table. Ditto for the state-triggered transitions that -# involve just the server and client state. -# -# The transitions for the other machines, and the state-triggered transitions -# that involve the other machines, are written out as explicit Python code. -# -# It'd be nice if there were some cleaner way to do all this. This isn't -# *too* terrible, but I feel like it could probably be better. -# -# WARNING -# ------- -# -# The script that generates the state machine diagrams for the docs knows how -# to read out the EVENT_TRIGGERED_TRANSITIONS and STATE_TRIGGERED_TRANSITIONS -# tables. But it can't automatically read the transitions that are written -# directly in Python code. So if you touch those, you need to also update the -# script to keep it in sync! -from typing import cast, Dict, Optional, Set, Tuple, Type, Union - -from ._events import * -from ._util import LocalProtocolError, Sentinel - -# Everything in __all__ gets re-exported as part of the h11 public API. -__all__ = [ - "CLIENT", - "SERVER", - "IDLE", - "SEND_RESPONSE", - "SEND_BODY", - "DONE", - "MUST_CLOSE", - "CLOSED", - "MIGHT_SWITCH_PROTOCOL", - "SWITCHED_PROTOCOL", - "ERROR", -] - - -class CLIENT(Sentinel, metaclass=Sentinel): - pass - - -class SERVER(Sentinel, metaclass=Sentinel): - pass - - -# States -class IDLE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_RESPONSE(Sentinel, metaclass=Sentinel): - pass - - -class SEND_BODY(Sentinel, metaclass=Sentinel): - pass - - -class DONE(Sentinel, metaclass=Sentinel): - pass - - -class MUST_CLOSE(Sentinel, metaclass=Sentinel): - pass - - -class CLOSED(Sentinel, metaclass=Sentinel): - pass - - -class ERROR(Sentinel, metaclass=Sentinel): - pass - - -# Switch types -class MIGHT_SWITCH_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class SWITCHED_PROTOCOL(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_UPGRADE(Sentinel, metaclass=Sentinel): - pass - - -class _SWITCH_CONNECT(Sentinel, metaclass=Sentinel): - pass - - -EventTransitionType = Dict[ - Type[Sentinel], - Dict[ - Type[Sentinel], - Dict[Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], Type[Sentinel]], - ], -] - -EVENT_TRIGGERED_TRANSITIONS: EventTransitionType = { - CLIENT: { - IDLE: {Request: SEND_BODY, ConnectionClosed: CLOSED}, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - MIGHT_SWITCH_PROTOCOL: {}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, - SERVER: { - IDLE: { - ConnectionClosed: CLOSED, - Response: SEND_BODY, - # Special case: server sees client Request events, in this form - (Request, CLIENT): SEND_RESPONSE, - }, - SEND_RESPONSE: { - InformationalResponse: SEND_RESPONSE, - Response: SEND_BODY, - (InformationalResponse, _SWITCH_UPGRADE): SWITCHED_PROTOCOL, - (Response, _SWITCH_CONNECT): SWITCHED_PROTOCOL, - }, - SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, - DONE: {ConnectionClosed: CLOSED}, - MUST_CLOSE: {ConnectionClosed: CLOSED}, - CLOSED: {ConnectionClosed: CLOSED}, - SWITCHED_PROTOCOL: {}, - ERROR: {}, - }, -} - -StateTransitionType = Dict[ - Tuple[Type[Sentinel], Type[Sentinel]], Dict[Type[Sentinel], Type[Sentinel]] -] - -# NB: there are also some special-case state-triggered transitions hard-coded -# into _fire_state_triggered_transitions below. -STATE_TRIGGERED_TRANSITIONS: StateTransitionType = { - # (Client state, Server state) -> new states - # Protocol negotiation - (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL}, - # Socket shutdown - (CLOSED, DONE): {SERVER: MUST_CLOSE}, - (CLOSED, IDLE): {SERVER: MUST_CLOSE}, - (ERROR, DONE): {SERVER: MUST_CLOSE}, - (DONE, CLOSED): {CLIENT: MUST_CLOSE}, - (IDLE, CLOSED): {CLIENT: MUST_CLOSE}, - (DONE, ERROR): {CLIENT: MUST_CLOSE}, -} - - -class ConnectionState: - def __init__(self) -> None: - # Extra bits of state that don't quite fit into the state model. - - # If this is False then it enables the automatic DONE -> MUST_CLOSE - # transition. Don't set this directly; call .keep_alive_disabled() - self.keep_alive = True - - # This is a subset of {UPGRADE, CONNECT}, containing the proposals - # made by the client for switching protocols. - self.pending_switch_proposals: Set[Type[Sentinel]] = set() - - self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE} - - def process_error(self, role: Type[Sentinel]) -> None: - self.states[role] = ERROR - self._fire_state_triggered_transitions() - - def process_keep_alive_disabled(self) -> None: - self.keep_alive = False - self._fire_state_triggered_transitions() - - def process_client_switch_proposal(self, switch_event: Type[Sentinel]) -> None: - self.pending_switch_proposals.add(switch_event) - self._fire_state_triggered_transitions() - - def process_event( - self, - role: Type[Sentinel], - event_type: Type[Event], - server_switch_event: Optional[Type[Sentinel]] = None, - ) -> None: - _event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]] = event_type - if server_switch_event is not None: - assert role is SERVER - if server_switch_event not in self.pending_switch_proposals: - raise LocalProtocolError( - "Received server _SWITCH_UPGRADE event without a pending proposal" - ) - _event_type = (event_type, server_switch_event) - if server_switch_event is None and _event_type is Response: - self.pending_switch_proposals = set() - self._fire_event_triggered_transitions(role, _event_type) - # Special case: the server state does get to see Request - # events. - if _event_type is Request: - assert role is CLIENT - self._fire_event_triggered_transitions(SERVER, (Request, CLIENT)) - self._fire_state_triggered_transitions() - - def _fire_event_triggered_transitions( - self, - role: Type[Sentinel], - event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], - ) -> None: - state = self.states[role] - try: - new_state = EVENT_TRIGGERED_TRANSITIONS[role][state][event_type] - except KeyError: - event_type = cast(Type[Event], event_type) - raise LocalProtocolError( - "can't handle event type {} when role={} and state={}".format( - event_type.__name__, role, self.states[role] - ) - ) from None - self.states[role] = new_state - - def _fire_state_triggered_transitions(self) -> None: - # We apply these rules repeatedly until converging on a fixed point - while True: - start_states = dict(self.states) - - # It could happen that both these special-case transitions are - # enabled at the same time: - # - # DONE -> MIGHT_SWITCH_PROTOCOL - # DONE -> MUST_CLOSE - # - # For example, this will always be true of a HTTP/1.0 client - # requesting CONNECT. If this happens, the protocol switch takes - # priority. From there the client will either go to - # SWITCHED_PROTOCOL, in which case it's none of our business when - # they close the connection, or else the server will deny the - # request, in which case the client will go back to DONE and then - # from there to MUST_CLOSE. - if self.pending_switch_proposals: - if self.states[CLIENT] is DONE: - self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL - - if not self.pending_switch_proposals: - if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL: - self.states[CLIENT] = DONE - - if not self.keep_alive: - for role in (CLIENT, SERVER): - if self.states[role] is DONE: - self.states[role] = MUST_CLOSE - - # Tabular state-triggered transitions - joint_state = (self.states[CLIENT], self.states[SERVER]) - changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {}) - self.states.update(changes) - - if self.states == start_states: - # Fixed point reached - return - - def start_next_cycle(self) -> None: - if self.states != {CLIENT: DONE, SERVER: DONE}: - raise LocalProtocolError( - f"not in a reusable state. self.states={self.states}" - ) - # Can't reach DONE/DONE with any of these active, but still, let's be - # sure. - assert self.keep_alive - assert not self.pending_switch_proposals - self.states = {CLIENT: IDLE, SERVER: IDLE} diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_util.py b/backend/venv39/lib/python3.9/site-packages/h11/_util.py deleted file mode 100644 index 6718445..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_util.py +++ /dev/null @@ -1,135 +0,0 @@ -from typing import Any, Dict, NoReturn, Pattern, Tuple, Type, TypeVar, Union - -__all__ = [ - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", - "validate", - "bytesify", -] - - -class ProtocolError(Exception): - """Exception indicating a violation of the HTTP/1.1 protocol. - - This as an abstract base class, with two concrete base classes: - :exc:`LocalProtocolError`, which indicates that you tried to do something - that HTTP/1.1 says is illegal, and :exc:`RemoteProtocolError`, which - indicates that the remote peer tried to do something that HTTP/1.1 says is - illegal. See :ref:`error-handling` for details. - - In addition to the normal :exc:`Exception` features, it has one attribute: - - .. attribute:: error_status_hint - - This gives a suggestion as to what status code a server might use if - this error occurred as part of a request. - - For a :exc:`RemoteProtocolError`, this is useful as a suggestion for - how you might want to respond to a misbehaving peer, if you're - implementing a server. - - For a :exc:`LocalProtocolError`, this can be taken as a suggestion for - how your peer might have responded to *you* if h11 had allowed you to - continue. - - The default is 400 Bad Request, a generic catch-all for protocol - violations. - - """ - - def __init__(self, msg: str, error_status_hint: int = 400) -> None: - if type(self) is ProtocolError: - raise TypeError("tried to directly instantiate ProtocolError") - Exception.__init__(self, msg) - self.error_status_hint = error_status_hint - - -# Strategy: there are a number of public APIs where a LocalProtocolError can -# be raised (send(), all the different event constructors, ...), and only one -# public API where RemoteProtocolError can be raised -# (receive_data()). Therefore we always raise LocalProtocolError internally, -# and then receive_data will translate this into a RemoteProtocolError. -# -# Internally: -# LocalProtocolError is the generic "ProtocolError". -# Externally: -# LocalProtocolError is for local errors and RemoteProtocolError is for -# remote errors. -class LocalProtocolError(ProtocolError): - def _reraise_as_remote_protocol_error(self) -> NoReturn: - # After catching a LocalProtocolError, use this method to re-raise it - # as a RemoteProtocolError. This method must be called from inside an - # except: block. - # - # An easy way to get an equivalent RemoteProtocolError is just to - # modify 'self' in place. - self.__class__ = RemoteProtocolError # type: ignore - # But the re-raising is somewhat non-trivial -- you might think that - # now that we've modified the in-flight exception object, that just - # doing 'raise' to re-raise it would be enough. But it turns out that - # this doesn't work, because Python tracks the exception type - # (exc_info[0]) separately from the exception object (exc_info[1]), - # and we only modified the latter. So we really do need to re-raise - # the new type explicitly. - # On py3, the traceback is part of the exception object, so our - # in-place modification preserved it and we can just re-raise: - raise self - - -class RemoteProtocolError(ProtocolError): - pass - - -def validate( - regex: Pattern[bytes], data: bytes, msg: str = "malformed data", *format_args: Any -) -> Dict[str, bytes]: - match = regex.fullmatch(data) - if not match: - if format_args: - msg = msg.format(*format_args) - raise LocalProtocolError(msg) - return match.groupdict() - - -# Sentinel values -# -# - Inherit identity-based comparison and hashing from object -# - Have a nice repr -# - Have a *bonus property*: type(sentinel) is sentinel -# -# The bonus property is useful if you want to take the return value from -# next_event() and do some sort of dispatch based on type(event). - -_T_Sentinel = TypeVar("_T_Sentinel", bound="Sentinel") - - -class Sentinel(type): - def __new__( - cls: Type[_T_Sentinel], - name: str, - bases: Tuple[type, ...], - namespace: Dict[str, Any], - **kwds: Any - ) -> _T_Sentinel: - assert bases == (Sentinel,) - v = super().__new__(cls, name, bases, namespace, **kwds) - v.__class__ = v # type: ignore - return v - - def __repr__(self) -> str: - return self.__name__ - - -# Used for methods, request targets, HTTP versions, header names, and header -# values. Accepts ascii-strings, or bytes/bytearray/memoryview/..., and always -# returns bytes. -def bytesify(s: Union[bytes, bytearray, memoryview, int, str]) -> bytes: - # Fast-path: - if type(s) is bytes: - return s - if isinstance(s, str): - s = s.encode("ascii") - if isinstance(s, int): - raise TypeError("expected bytes-like object, not int") - return bytes(s) diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_version.py b/backend/venv39/lib/python3.9/site-packages/h11/_version.py deleted file mode 100644 index 76e7327..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_version.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file must be kept very simple, because it is consumed from several -# places -- it is imported by h11/__init__.py, execfile'd by setup.py, etc. - -# We use a simple scheme: -# 1.0.0 -> 1.0.0+dev -> 1.1.0 -> 1.1.0+dev -# where the +dev versions are never released into the wild, they're just what -# we stick into the VCS in between releases. -# -# This is compatible with PEP 440: -# http://legacy.python.org/dev/peps/pep-0440/ -# via the use of the "local suffix" "+dev", which is disallowed on index -# servers and causes 1.0.0+dev to sort after plain 1.0.0, which is what we -# want. (Contrast with the special suffix 1.0.0.dev, which sorts *before* -# 1.0.0.) - -__version__ = "0.16.0" diff --git a/backend/venv39/lib/python3.9/site-packages/h11/_writers.py b/backend/venv39/lib/python3.9/site-packages/h11/_writers.py deleted file mode 100644 index 939cdb9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/_writers.py +++ /dev/null @@ -1,145 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each writer takes an event + a write-some-bytes function, which is -# calls. -# -# WRITERS is a dict describing how to pick a reader. It maps states to either: -# - a writer -# - or, for body writers, a dict of framin-dependent writer factories - -from typing import Any, Callable, Dict, List, Tuple, Type, Union - -from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response -from ._headers import Headers -from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER -from ._util import LocalProtocolError, Sentinel - -__all__ = ["WRITERS"] - -Writer = Callable[[bytes], Any] - - -def write_headers(headers: Headers, write: Writer) -> None: - # "Since the Host field-value is critical information for handling a - # request, a user agent SHOULD generate Host as the first header field - # following the request-line." - RFC 7230 - raw_items = headers._full_items - for raw_name, name, value in raw_items: - if name == b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - for raw_name, name, value in raw_items: - if name != b"host": - write(b"%s: %s\r\n" % (raw_name, value)) - write(b"\r\n") - - -def write_request(request: Request, write: Writer) -> None: - if request.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target)) - write_headers(request.headers, write) - - -# Shared between InformationalResponse and Response -def write_any_response( - response: Union[InformationalResponse, Response], write: Writer -) -> None: - if response.http_version != b"1.1": - raise LocalProtocolError("I only send HTTP/1.1") - status_bytes = str(response.status_code).encode("ascii") - # We don't bother sending ascii status messages like "OK"; they're - # optional and ignored by the protocol. (But the space after the numeric - # status code is mandatory.) - # - # XX FIXME: could at least make an effort to pull out the status message - # from stdlib's http.HTTPStatus table. Or maybe just steal their enums - # (either by import or copy/paste). We already accept them as status codes - # since they're of type IntEnum < int. - write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason)) - write_headers(response.headers, write) - - -class BodyWriter: - def __call__(self, event: Event, write: Writer) -> None: - if type(event) is Data: - self.send_data(event.data, write) - elif type(event) is EndOfMessage: - self.send_eom(event.headers, write) - else: # pragma: no cover - assert False - - def send_data(self, data: bytes, write: Writer) -> None: - pass - - def send_eom(self, headers: Headers, write: Writer) -> None: - pass - - -# -# These are all careful not to do anything to 'data' except call len(data) and -# write(data). This allows us to transparently pass-through funny objects, -# like placeholder objects referring to files on disk that will be sent via -# sendfile(2). -# -class ContentLengthWriter(BodyWriter): - def __init__(self, length: int) -> None: - self._length = length - - def send_data(self, data: bytes, write: Writer) -> None: - self._length -= len(data) - if self._length < 0: - raise LocalProtocolError("Too much data for declared Content-Length") - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if self._length != 0: - raise LocalProtocolError("Too little data for declared Content-Length") - if headers: - raise LocalProtocolError("Content-Length and trailers don't mix") - - -class ChunkedWriter(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - # if we encoded 0-length data in the naive way, it would look like an - # end-of-message. - if not data: - return - write(b"%x\r\n" % len(data)) - write(data) - write(b"\r\n") - - def send_eom(self, headers: Headers, write: Writer) -> None: - write(b"0\r\n") - write_headers(headers, write) - - -class Http10Writer(BodyWriter): - def send_data(self, data: bytes, write: Writer) -> None: - write(data) - - def send_eom(self, headers: Headers, write: Writer) -> None: - if headers: - raise LocalProtocolError("can't send trailers to HTTP/1.0 client") - # no need to close the socket ourselves, that will be taken care of by - # Connection: close machinery - - -WritersType = Dict[ - Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]], - Union[ - Dict[str, Type[BodyWriter]], - Callable[[Union[InformationalResponse, Response], Writer], None], - Callable[[Request, Writer], None], - ], -] - -WRITERS: WritersType = { - (CLIENT, IDLE): write_request, - (SERVER, IDLE): write_any_response, - (SERVER, SEND_RESPONSE): write_any_response, - SEND_BODY: { - "chunked": ChunkedWriter, - "content-length": ContentLengthWriter, - "http/1.0": Http10Writer, - }, -} diff --git a/backend/venv39/lib/python3.9/site-packages/h11/py.typed b/backend/venv39/lib/python3.9/site-packages/h11/py.typed deleted file mode 100644 index f5642f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/h11/py.typed +++ /dev/null @@ -1 +0,0 @@ -Marker diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/METADATA deleted file mode 100644 index 8056834..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/METADATA +++ /dev/null @@ -1,625 +0,0 @@ -Metadata-Version: 2.4 -Name: httpcore -Version: 1.0.9 -Summary: A minimal low-level HTTP client. -Project-URL: Documentation, https://www.encode.io/httpcore -Project-URL: Homepage, https://www.encode.io/httpcore/ -Project-URL: Source, https://github.com/encode/httpcore -Author-email: Tom Christie -License-Expression: BSD-3-Clause -License-File: LICENSE.md -Classifier: Development Status :: 3 - Alpha -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: Trio -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.8 -Requires-Dist: certifi -Requires-Dist: h11>=0.16 -Provides-Extra: asyncio -Requires-Dist: anyio<5.0,>=4.0; extra == 'asyncio' -Provides-Extra: http2 -Requires-Dist: h2<5,>=3; extra == 'http2' -Provides-Extra: socks -Requires-Dist: socksio==1.*; extra == 'socks' -Provides-Extra: trio -Requires-Dist: trio<1.0,>=0.22.0; extra == 'trio' -Description-Content-Type: text/markdown - -# HTTP Core - -[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions) -[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/) - -> *Do one thing, and do it well.* - -The HTTP Core package provides a minimal low-level HTTP client, which does -one thing only. Sending HTTP requests. - -It does not provide any high level model abstractions over the API, -does not handle redirects, multipart uploads, building authentication headers, -transparent HTTP caching, URL parsing, session cookie handling, -content or charset decoding, handling JSON, environment based configuration -defaults, or any of that Jazz. - -Some things HTTP Core does do: - -* Sending HTTP requests. -* Thread-safe / task-safe connection pooling. -* HTTP(S) proxy & SOCKS proxy support. -* Supports HTTP/1.1 and HTTP/2. -* Provides both sync and async interfaces. -* Async backend support for `asyncio` and `trio`. - -## Requirements - -Python 3.8+ - -## Installation - -For HTTP/1.1 only support, install with: - -```shell -$ pip install httpcore -``` - -There are also a number of optional extras available... - -```shell -$ pip install httpcore['asyncio,trio,http2,socks'] -``` - -## Sending requests - -Send an HTTP request: - -```python -import httpcore - -response = httpcore.request("GET", "https://www.example.com/") - -print(response) -# -print(response.status) -# 200 -print(response.headers) -# [(b'Accept-Ranges', b'bytes'), (b'Age', b'557328'), (b'Cache-Control', b'max-age=604800'), ...] -print(response.content) -# b'\n\n\nExample Domain\n\n\n ...' -``` - -The top-level `httpcore.request()` function is provided for convenience. In practice whenever you're working with `httpcore` you'll want to use the connection pooling functionality that it provides. - -```python -import httpcore - -http = httpcore.ConnectionPool() -response = http.request("GET", "https://www.example.com/") -``` - -Once you're ready to get going, [head over to the documentation](https://www.encode.io/httpcore/). - -## Motivation - -You *probably* don't want to be using HTTP Core directly. It might make sense if -you're writing something like a proxy service in Python, and you just want -something at the lowest possible level, but more typically you'll want to use -a higher level client library, such as `httpx`. - -The motivation for `httpcore` is: - -* To provide a reusable low-level client library, that other packages can then build on top of. -* To provide a *really clear interface split* between the networking code and client logic, - so that each is easier to understand and reason about in isolation. - -## Dependencies - -The `httpcore` package has the following dependencies... - -* `h11` -* `certifi` - -And the following optional extras... - -* `anyio` - Required by `pip install httpcore['asyncio']`. -* `trio` - Required by `pip install httpcore['trio']`. -* `h2` - Required by `pip install httpcore['http2']`. -* `socksio` - Required by `pip install httpcore['socks']`. - -## Versioning - -We use [SEMVER for our versioning policy](https://semver.org/). - -For changes between package versions please see our [project changelog](CHANGELOG.md). - -We recommend pinning your requirements either the most current major version, or a more specific version range: - -```python -pip install 'httpcore==1.*' -``` -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - -## Version 1.0.9 (April 24th, 2025) - -- Resolve https://github.com/advisories/GHSA-vqfr-h8mv-ghfj with h11 dependency update. (#1008) - -## Version 1.0.8 (April 11th, 2025) - -- Fix `AttributeError` when importing on Python 3.14. (#1005) - -## Version 1.0.7 (November 15th, 2024) - -- Support `proxy=…` configuration on `ConnectionPool()`. (#974) - -## Version 1.0.6 (October 1st, 2024) - -- Relax `trio` dependency pinning. (#956) -- Handle `trio` raising `NotImplementedError` on unsupported platforms. (#955) -- Handle mapping `ssl.SSLError` to `httpcore.ConnectError`. (#918) - -## 1.0.5 (March 27th, 2024) - -- Handle `EndOfStream` exception for anyio backend. (#899) -- Allow trio `0.25.*` series in package dependancies. (#903) - -## 1.0.4 (February 21st, 2024) - -- Add `target` request extension. (#888) -- Fix support for connection `Upgrade` and `CONNECT` when some data in the stream has been read. (#882) - -## 1.0.3 (February 13th, 2024) - -- Fix support for async cancellations. (#880) -- Fix trace extension when used with socks proxy. (#849) -- Fix SSL context for connections using the "wss" scheme (#869) - -## 1.0.2 (November 10th, 2023) - -- Fix `float("inf")` timeouts in `Event.wait` function. (#846) - -## 1.0.1 (November 3rd, 2023) - -- Fix pool timeout to account for the total time spent retrying. (#823) -- Raise a neater RuntimeError when the correct async deps are not installed. (#826) -- Add support for synchronous TLS-in-TLS streams. (#840) - -## 1.0.0 (October 6th, 2023) - -From version 1.0 our async support is now optional, as the package has minimal dependencies by default. - -For async support use either `pip install 'httpcore[asyncio]'` or `pip install 'httpcore[trio]'`. - -The project versioning policy is now explicitly governed by SEMVER. See https://semver.org/. - -- Async support becomes fully optional. (#809) -- Add support for Python 3.12. (#807) - -## 0.18.0 (September 8th, 2023) - -- Add support for HTTPS proxies. (#745, #786) -- Drop Python 3.7 support. (#727) -- Handle `sni_hostname` extension with SOCKS proxy. (#774) -- Handle HTTP/1.1 half-closed connections gracefully. (#641) -- Change the type of `Extensions` from `Mapping[Str, Any]` to `MutableMapping[Str, Any]`. (#762) - -## 0.17.3 (July 5th, 2023) - -- Support async cancellations, ensuring that the connection pool is left in a clean state when cancellations occur. (#726) -- The networking backend interface has [been added to the public API](https://www.encode.io/httpcore/network-backends). Some classes which were previously private implementation detail are now part of the top-level public API. (#699) -- Graceful handling of HTTP/2 GoAway frames, with requests being transparently retried on a new connection. (#730) -- Add exceptions when a synchronous `trace callback` is passed to an asynchronous request or an asynchronous `trace callback` is passed to a synchronous request. (#717) -- Drop Python 3.7 support. (#727) - -## 0.17.2 (May 23th, 2023) - -- Add `socket_options` argument to `ConnectionPool` and `HTTProxy` classes. (#668) -- Improve logging with per-module logger names. (#690) -- Add `sni_hostname` request extension. (#696) -- Resolve race condition during import of `anyio` package. (#692) -- Enable TCP_NODELAY for all synchronous sockets. (#651) - -## 0.17.1 (May 17th, 2023) - -- If 'retries' is set, then allow retries if an SSL handshake error occurs. (#669) -- Improve correctness of tracebacks on network exceptions, by raising properly chained exceptions. (#678) -- Prevent connection-hanging behaviour when HTTP/2 connections are closed by a server-sent 'GoAway' frame. (#679) -- Fix edge-case exception when removing requests from the connection pool. (#680) -- Fix pool timeout edge-case. (#688) - -## 0.17.0 (March 16th, 2023) - -- Add DEBUG level logging. (#648) -- Respect HTTP/2 max concurrent streams when settings updates are sent by server. (#652) -- Increase the allowable HTTP header size to 100kB. (#647) -- Add `retries` option to SOCKS proxy classes. (#643) - -## 0.16.3 (December 20th, 2022) - -- Allow `ws` and `wss` schemes. Allows us to properly support websocket upgrade connections. (#625) -- Forwarding HTTP proxies use a connection-per-remote-host. Required by some proxy implementations. (#637) -- Don't raise `RuntimeError` when closing a connection pool with active connections. Removes some error cases when cancellations are used. (#631) -- Lazy import `anyio`, so that it's no longer a hard dependancy, and isn't imported if unused. (#639) - -## 0.16.2 (November 25th, 2022) - -- Revert 'Fix async cancellation behaviour', which introduced race conditions. (#627) -- Raise `RuntimeError` if attempting to us UNIX domain sockets on Windows. (#619) - -## 0.16.1 (November 17th, 2022) - -- Fix HTTP/1.1 interim informational responses, such as "100 Continue". (#605) - -## 0.16.0 (October 11th, 2022) - -- Support HTTP/1.1 informational responses. (#581) -- Fix async cancellation behaviour. (#580) -- Support `h11` 0.14. (#579) - -## 0.15.0 (May 17th, 2022) - -- Drop Python 3.6 support (#535) -- Ensure HTTP proxy CONNECT requests include `timeout` configuration. (#506) -- Switch to explicit `typing.Optional` for type hints. (#513) -- For `trio` map OSError exceptions to `ConnectError`. (#543) - -## 0.14.7 (February 4th, 2022) - -- Requests which raise a PoolTimeout need to be removed from the pool queue. (#502) -- Fix AttributeError that happened when Socks5Connection were terminated. (#501) - -## 0.14.6 (February 1st, 2022) - -- Fix SOCKS support for `http://` URLs. (#492) -- Resolve race condition around exceptions during streaming a response. (#491) - -## 0.14.5 (January 18th, 2022) - -- SOCKS proxy support. (#478) -- Add proxy_auth argument to HTTPProxy. (#481) -- Improve error message on 'RemoteProtocolError' exception when server disconnects without sending a response. (#479) - -## 0.14.4 (January 5th, 2022) - -- Support HTTP/2 on HTTPS tunnelling proxies. (#468) -- Fix proxy headers missing on HTTP forwarding. (#456) -- Only instantiate SSL context if required. (#457) -- More robust HTTP/2 handling. (#253, #439, #440, #441) - -## 0.14.3 (November 17th, 2021) - -- Fix race condition when removing closed connections from the pool. (#437) - -## 0.14.2 (November 16th, 2021) - -- Failed connections no longer remain in the pool. (Pull #433) - -## 0.14.1 (November 12th, 2021) - -- `max_connections` becomes optional. (Pull #429) -- `certifi` is now included in the install dependancies. (Pull #428) -- `h2` is now strictly optional. (Pull #428) - -## 0.14.0 (November 11th, 2021) - -The 0.14 release is a complete reworking of `httpcore`, comprehensively addressing some underlying issues in the connection pooling, as well as substantially redesigning the API to be more user friendly. - -Some of the lower-level API design also makes the components more easily testable in isolation, and the package now has 100% test coverage. - -See [discussion #419](https://github.com/encode/httpcore/discussions/419) for a little more background. - -There's some other neat bits in there too, such as the "trace" extension, which gives a hook into inspecting the internal events that occur during the request/response cycle. This extension is needed for the HTTPX cli, in order to... - -* Log the point at which the connection is established, and the IP/port on which it is made. -* Determine if the outgoing request should log as HTTP/1.1 or HTTP/2, rather than having to assume it's HTTP/2 if the --http2 flag was passed. (Which may not actually be true.) -* Log SSL version info / certificate info. - -Note that `curio` support is not currently available in 0.14.0. If you're using `httpcore` with `curio` please get in touch, so we can assess if we ought to prioritize it as a feature or not. - -## 0.13.7 (September 13th, 2021) - -- Fix broken error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #403) - -## 0.13.6 (June 15th, 2021) - -### Fixed - -- Close sockets when read or write timeouts occur. (Pull #365) - -## 0.13.5 (June 14th, 2021) - -### Fixed - -- Resolved niggles with AnyIO EOF behaviours. (Pull #358, #362) - -## 0.13.4 (June 9th, 2021) - -### Added - -- Improved error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #354) - -### Fixed - -- Switched to `anyio` as the default backend implementation when running with `asyncio`. Resolves some awkward [TLS timeout issues](https://github.com/encode/httpx/discussions/1511). - -## 0.13.3 (May 6th, 2021) - -### Added - -- Support HTTP/2 prior knowledge, using `httpcore.SyncConnectionPool(http1=False)`. (Pull #333) - -### Fixed - -- Handle cases where environment does not provide `select.poll` support. (Pull #331) - -## 0.13.2 (April 29th, 2021) - -### Added - -- Improve error message for specific case of `RemoteProtocolError` where server disconnects without sending a response. (Pull #313) - -## 0.13.1 (April 28th, 2021) - -### Fixed - -- More resiliant testing for closed connections. (Pull #311) -- Don't raise exceptions on ungraceful connection closes. (Pull #310) - -## 0.13.0 (April 21st, 2021) - -The 0.13 release updates the core API in order to match the HTTPX Transport API, -introduced in HTTPX 0.18 onwards. - -An example of making requests with the new interface is: - -```python -with httpcore.SyncConnectionPool() as http: - status_code, headers, stream, extensions = http.handle_request( - method=b'GET', - url=(b'https', b'example.org', 443, b'/'), - headers=[(b'host', b'example.org'), (b'user-agent', b'httpcore')] - stream=httpcore.ByteStream(b''), - extensions={} - ) - body = stream.read() - print(status_code, body) -``` - -### Changed - -- The `.request()` method is now `handle_request()`. (Pull #296) -- The `.arequest()` method is now `.handle_async_request()`. (Pull #296) -- The `headers` argument is no longer optional. (Pull #296) -- The `stream` argument is no longer optional. (Pull #296) -- The `ext` argument is now named `extensions`, and is no longer optional. (Pull #296) -- The `"reason"` extension keyword is now named `"reason_phrase"`. (Pull #296) -- The `"reason_phrase"` and `"http_version"` extensions now use byte strings for their values. (Pull #296) -- The `httpcore.PlainByteStream()` class becomes `httpcore.ByteStream()`. (Pull #296) - -### Added - -- Streams now support a `.read()` interface. (Pull #296) - -### Fixed - -- Task cancellation no longer leaks connections from the connection pool. (Pull #305) - -## 0.12.3 (December 7th, 2020) - -### Fixed - -- Abort SSL connections on close rather than waiting for remote EOF when using `asyncio`. (Pull #167) -- Fix exception raised in case of connect timeouts when using the `anyio` backend. (Pull #236) -- Fix `Host` header precedence for `:authority` in HTTP/2. (Pull #241, #243) -- Handle extra edge case when detecting for socket readability when using `asyncio`. (Pull #242, #244) -- Fix `asyncio` SSL warning when using proxy tunneling. (Pull #249) - -## 0.12.2 (November 20th, 2020) - -### Fixed - -- Properly wrap connect errors on the asyncio backend. (Pull #235) -- Fix `ImportError` occurring on Python 3.9 when using the HTTP/1.1 sync client in a multithreaded context. (Pull #237) - -## 0.12.1 (November 7th, 2020) - -### Added - -- Add connect retries. (Pull #221) - -### Fixed - -- Tweak detection of dropped connections, resolving an issue with open files limits on Linux. (Pull #185) -- Avoid leaking connections when establishing an HTTP tunnel to a proxy has failed. (Pull #223) -- Properly wrap OS errors when using `trio`. (Pull #225) - -## 0.12.0 (October 6th, 2020) - -### Changed - -- HTTP header casing is now preserved, rather than always sent in lowercase. (#216 and python-hyper/h11#104) - -### Added - -- Add Python 3.9 to officially supported versions. - -### Fixed - -- Gracefully handle a stdlib asyncio bug when a connection is closed while it is in a paused-for-reading state. (#201) - -## 0.11.1 (September 28nd, 2020) - -### Fixed - -- Add await to async semaphore release() coroutine (#197) -- Drop incorrect curio classifier (#192) - -## 0.11.0 (September 22nd, 2020) - -The Transport API with 0.11.0 has a couple of significant changes. - -Firstly we've moved changed the request interface in order to allow extensions, which will later enable us to support features -such as trailing headers, HTTP/2 server push, and CONNECT/Upgrade connections. - -The interface changes from: - -```python -def request(method, url, headers, stream, timeout): - return (http_version, status_code, reason, headers, stream) -``` - -To instead including an optional dictionary of extensions on the request and response: - -```python -def request(method, url, headers, stream, ext): - return (status_code, headers, stream, ext) -``` - -Having an open-ended extensions point will allow us to add later support for various optional features, that wouldn't otherwise be supported without these API changes. - -In particular: - -* Trailing headers support. -* HTTP/2 Server Push -* sendfile. -* Exposing raw connection on CONNECT, Upgrade, HTTP/2 bi-di streaming. -* Exposing debug information out of the API, including template name, template context. - -Currently extensions are limited to: - -* request: `timeout` - Optional. Timeout dictionary. -* response: `http_version` - Optional. Include the HTTP version used on the response. -* response: `reason` - Optional. Include the reason phrase used on the response. Only valid with HTTP/1.*. - -See https://github.com/encode/httpx/issues/1274#issuecomment-694884553 for the history behind this. - -Secondly, the async version of `request` is now namespaced as `arequest`. - -This allows concrete transports to support both sync and async implementations on the same class. - -### Added - -- Add curio support. (Pull #168) -- Add anyio support, with `backend="anyio"`. (Pull #169) - -### Changed - -- Update the Transport API to use 'ext' for optional extensions. (Pull #190) -- Update the Transport API to use `.request` and `.arequest` so implementations can support both sync and async. (Pull #189) - -## 0.10.2 (August 20th, 2020) - -### Added - -- Added Unix Domain Socket support. (Pull #139) - -### Fixed - -- Always include the port on proxy CONNECT requests. (Pull #154) -- Fix `max_keepalive_connections` configuration. (Pull #153) -- Fixes behaviour in HTTP/1.1 where server disconnects can be used to signal the end of the response body. (Pull #164) - -## 0.10.1 (August 7th, 2020) - -- Include `max_keepalive_connections` on `AsyncHTTPProxy`/`SyncHTTPProxy` classes. - -## 0.10.0 (August 7th, 2020) - -The most notable change in the 0.10.0 release is that HTTP/2 support is now fully optional. - -Use either `pip install httpcore` for HTTP/1.1 support only, or `pip install httpcore[http2]` for HTTP/1.1 and HTTP/2 support. - -### Added - -- HTTP/2 support becomes optional. (Pull #121, #130) -- Add `local_address=...` support. (Pull #100, #134) -- Add `PlainByteStream`, `IteratorByteStream`, `AsyncIteratorByteStream`. The `AsyncByteSteam` and `SyncByteStream` classes are now pure interface classes. (#133) -- Add `LocalProtocolError`, `RemoteProtocolError` exceptions. (Pull #129) -- Add `UnsupportedProtocol` exception. (Pull #128) -- Add `.get_connection_info()` method. (Pull #102, #137) -- Add better TRACE logs. (Pull #101) - -### Changed - -- `max_keepalive` is deprecated in favour of `max_keepalive_connections`. (Pull #140) - -### Fixed - -- Improve handling of server disconnects. (Pull #112) - -## 0.9.1 (May 27th, 2020) - -### Fixed - -- Proper host resolution for sync case, including IPv6 support. (Pull #97) -- Close outstanding connections when connection pool is closed. (Pull #98) - -## 0.9.0 (May 21th, 2020) - -### Changed - -- URL port becomes an `Optional[int]` instead of `int`. (Pull #92) - -### Fixed - -- Honor HTTP/2 max concurrent streams settings. (Pull #89, #90) -- Remove incorrect debug log. (Pull #83) - -## 0.8.4 (May 11th, 2020) - -### Added - -- Logging via HTTPCORE_LOG_LEVEL and HTTPX_LOG_LEVEL environment variables -and TRACE level logging. (Pull #79) - -### Fixed - -- Reuse of connections on HTTP/2 in close concurrency situations. (Pull #81) - -## 0.8.3 (May 6rd, 2020) - -### Fixed - -- Include `Host` and `Accept` headers on proxy "CONNECT" requests. -- De-duplicate any headers also contained in proxy_headers. -- HTTP/2 flag not being passed down to proxy connections. - -## 0.8.2 (May 3rd, 2020) - -### Fixed - -- Fix connections using proxy forwarding requests not being added to the -connection pool properly. (Pull #70) - -## 0.8.1 (April 30th, 2020) - -### Changed - -- Allow inherintance of both `httpcore.AsyncByteStream`, `httpcore.SyncByteStream` without type conflicts. - -## 0.8.0 (April 30th, 2020) - -### Fixed - -- Fixed tunnel proxy support. - -### Added - -- New `TimeoutException` base class. - -## 0.7.0 (March 5th, 2020) - -- First integration with HTTPX. diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/RECORD deleted file mode 100644 index 75b1c91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/RECORD +++ /dev/null @@ -1,68 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection_pool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http11.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/interfaces.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_async/socks_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/anyio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/auto.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/mock.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/sync.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/trio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_ssl.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection_pool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http11.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/interfaces.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/socks_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_synchronization.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_trace.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpcore/_utils.cpython-39.pyc,, -httpcore-1.0.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -httpcore-1.0.9.dist-info/METADATA,sha256=_i1P2mGZEol4d54M8n88BFxTGGP83Zh-rMdPOhjUHCE,21529 -httpcore-1.0.9.dist-info/RECORD,, -httpcore-1.0.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 -httpcore-1.0.9.dist-info/licenses/LICENSE.md,sha256=_ctZFUx0y6uhahEkL3dAvqnyPW_rVUeRfYxflKgDkqU,1518 -httpcore/__init__.py,sha256=9kT_kqChCCJUTHww24ZmR_ezcdbpRYWksD-gYNzkZP8,3445 -httpcore/_api.py,sha256=unZmeDschBWCGCPCwkS3Wot9euK6bg_kKxLtGTxw214,3146 -httpcore/_async/__init__.py,sha256=EWdl2v4thnAHzJpqjU4h2a8DUiGAvNiWrkii9pfhTf0,1221 -httpcore/_async/connection.py,sha256=6OcPXqMEfc0BU38_-iHUNDd1vKSTc2UVT09XqNb_BOk,8449 -httpcore/_async/connection_pool.py,sha256=DOIQ2s2ZCf9qfwxhzMprTPLqCL8OxGXiKF6qRHxvVyY,17307 -httpcore/_async/http11.py,sha256=-qM9bV7PjSQF5vxs37-eUXOIFwbIjPcZbNliuX9TtBw,13880 -httpcore/_async/http2.py,sha256=azX1fcmtXaIwjputFlZ4vd92J8xwjGOa9ax9QIv4394,23936 -httpcore/_async/http_proxy.py,sha256=2zVkrlv-Ds-rWGaqaXlrhEJiAQFPo23BT3Gq_sWoBXU,14701 -httpcore/_async/interfaces.py,sha256=jTiaWL83pgpGC9ziv90ZfwaKNMmHwmOalzaKiuTxATo,4455 -httpcore/_async/socks_proxy.py,sha256=lLKgLlggPfhFlqi0ODeBkOWvt9CghBBUyqsnsU1tx6Q,13841 -httpcore/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -httpcore/_backends/anyio.py,sha256=x8PgEhXRC8bVqsdzk_YJx8Y6d9Tub06CuUSwnbmtqoY,5252 -httpcore/_backends/auto.py,sha256=zO136PKZmsaTDK-HRk84eA-MUg8_2wJf4NvmK432Aio,1662 -httpcore/_backends/base.py,sha256=aShgRdZnMmRhFWHetjumlM73f8Kz1YOAyCUP_4kHslA,3042 -httpcore/_backends/mock.py,sha256=er9T436uSe7NLrfiLa4x6Nuqg5ivQ693CxWYCWsgbH4,4077 -httpcore/_backends/sync.py,sha256=bhE4d9iK9Umxdsdsgm2EfKnXaBms2WggGYU-7jmUujU,7977 -httpcore/_backends/trio.py,sha256=LHu4_Mr5MswQmmT3yE4oLgf9b_JJfeVS4BjDxeJc7Ro,5996 -httpcore/_exceptions.py,sha256=looCKga3_YVYu3s-d3L9RMPRJyhsY7fiuuGxvkOD0c0,1184 -httpcore/_models.py,sha256=IO2CcXcdpovRcLTdGFGB6RyBZdEm2h_TOmoCc4rEKho,17623 -httpcore/_ssl.py,sha256=srqmSNU4iOUvWF-SrJvb8G_YEbHFELOXQOwdDIBTS9c,187 -httpcore/_sync/__init__.py,sha256=JBDIgXt5la1LCJ1sLQeKhjKFpLnpNr8Svs6z2ni3fgg,1141 -httpcore/_sync/connection.py,sha256=9exGOb3PB-Mp2T1-sckSeL2t-tJ_9-NXomV8ihmWCgU,8238 -httpcore/_sync/connection_pool.py,sha256=a-T8LTsUxc7r0Ww1atfHSDoWPjQ0fA8Ul7S3-F0Mj70,16955 -httpcore/_sync/http11.py,sha256=IFobD1Md5JFlJGKWnh1_Q3epikUryI8qo09v8MiJIEA,13476 -httpcore/_sync/http2.py,sha256=AxU4yhcq68Bn5vqdJYtiXKYUj7nvhYbxz3v4rT4xnvA,23400 -httpcore/_sync/http_proxy.py,sha256=_al_6crKuEZu2wyvu493RZImJdBJnj5oGKNjLOJL2Zo,14463 -httpcore/_sync/interfaces.py,sha256=snXON42vUDHO5JBJvo8D4VWk2Wat44z2OXXHDrjbl94,4344 -httpcore/_sync/socks_proxy.py,sha256=zegZW9Snqj2_992DFJa8_CppOVBkVL4AgwduRkStakQ,13614 -httpcore/_synchronization.py,sha256=zSi13mAColBnknjZBknUC6hKNDQT4C6ijnezZ-r0T2s,9434 -httpcore/_trace.py,sha256=ck6ZoIzYTkdNAIfq5MGeKqBXDtqjOX-qfYwmZFbrGco,3952 -httpcore/_utils.py,sha256=_RLgXYOAYC350ikALV59GZ68IJrdocRZxPs9PjmzdFY,1537 -httpcore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/WHEEL deleted file mode 100644 index 12228d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.27.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md b/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md deleted file mode 100644 index 311b2b5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -Copyright © 2020, [Encode OSS Ltd](https://www.encode.io/). -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpcore/__init__.py deleted file mode 100644 index 9a92dc4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/__init__.py +++ /dev/null @@ -1,141 +0,0 @@ -from ._api import request, stream -from ._async import ( - AsyncConnectionInterface, - AsyncConnectionPool, - AsyncHTTP2Connection, - AsyncHTTP11Connection, - AsyncHTTPConnection, - AsyncHTTPProxy, - AsyncSOCKSProxy, -) -from ._backends.base import ( - SOCKET_OPTION, - AsyncNetworkBackend, - AsyncNetworkStream, - NetworkBackend, - NetworkStream, -) -from ._backends.mock import AsyncMockBackend, AsyncMockStream, MockBackend, MockStream -from ._backends.sync import SyncBackend -from ._exceptions import ( - ConnectError, - ConnectionNotAvailable, - ConnectTimeout, - LocalProtocolError, - NetworkError, - PoolTimeout, - ProtocolError, - ProxyError, - ReadError, - ReadTimeout, - RemoteProtocolError, - TimeoutException, - UnsupportedProtocol, - WriteError, - WriteTimeout, -) -from ._models import URL, Origin, Proxy, Request, Response -from ._ssl import default_ssl_context -from ._sync import ( - ConnectionInterface, - ConnectionPool, - HTTP2Connection, - HTTP11Connection, - HTTPConnection, - HTTPProxy, - SOCKSProxy, -) - -# The 'httpcore.AnyIOBackend' class is conditional on 'anyio' being installed. -try: - from ._backends.anyio import AnyIOBackend -except ImportError: # pragma: nocover - - class AnyIOBackend: # type: ignore - def __init__(self, *args, **kwargs): # type: ignore - msg = ( - "Attempted to use 'httpcore.AnyIOBackend' but 'anyio' is not installed." - ) - raise RuntimeError(msg) - - -# The 'httpcore.TrioBackend' class is conditional on 'trio' being installed. -try: - from ._backends.trio import TrioBackend -except ImportError: # pragma: nocover - - class TrioBackend: # type: ignore - def __init__(self, *args, **kwargs): # type: ignore - msg = "Attempted to use 'httpcore.TrioBackend' but 'trio' is not installed." - raise RuntimeError(msg) - - -__all__ = [ - # top-level requests - "request", - "stream", - # models - "Origin", - "URL", - "Request", - "Response", - "Proxy", - # async - "AsyncHTTPConnection", - "AsyncConnectionPool", - "AsyncHTTPProxy", - "AsyncHTTP11Connection", - "AsyncHTTP2Connection", - "AsyncConnectionInterface", - "AsyncSOCKSProxy", - # sync - "HTTPConnection", - "ConnectionPool", - "HTTPProxy", - "HTTP11Connection", - "HTTP2Connection", - "ConnectionInterface", - "SOCKSProxy", - # network backends, implementations - "SyncBackend", - "AnyIOBackend", - "TrioBackend", - # network backends, mock implementations - "AsyncMockBackend", - "AsyncMockStream", - "MockBackend", - "MockStream", - # network backends, interface - "AsyncNetworkStream", - "AsyncNetworkBackend", - "NetworkStream", - "NetworkBackend", - # util - "default_ssl_context", - "SOCKET_OPTION", - # exceptions - "ConnectionNotAvailable", - "ProxyError", - "ProtocolError", - "LocalProtocolError", - "RemoteProtocolError", - "UnsupportedProtocol", - "TimeoutException", - "PoolTimeout", - "ConnectTimeout", - "ReadTimeout", - "WriteTimeout", - "NetworkError", - "ConnectError", - "ReadError", - "WriteError", -] - -__version__ = "1.0.9" - - -__locals = locals() -for __name in __all__: - # Exclude SOCKET_OPTION, it causes AttributeError on Python 3.14 - if not __name.startswith(("__", "SOCKET_OPTION")): - setattr(__locals[__name], "__module__", "httpcore") # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_api.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_api.py deleted file mode 100644 index 38b961d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_api.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from ._models import URL, Extensions, HeaderTypes, Response -from ._sync.connection_pool import ConnectionPool - - -def request( - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, -) -> Response: - """ - Sends an HTTP request, returning the response. - - ``` - response = httpcore.request("GET", "https://www.example.com/") - ``` - - Arguments: - method: The HTTP method for the request. Typically one of `"GET"`, - `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. - url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, - or as str/bytes. - headers: The HTTP request headers. Either as a dictionary of str/bytes, - or as a list of two-tuples of str/bytes. - content: The content of the request body. Either as bytes, - or as a bytes iterator. - extensions: A dictionary of optional extra information included on the request. - Possible keys include `"timeout"`. - - Returns: - An instance of `httpcore.Response`. - """ - with ConnectionPool() as pool: - return pool.request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - - -@contextlib.contextmanager -def stream( - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, -) -> typing.Iterator[Response]: - """ - Sends an HTTP request, returning the response within a content manager. - - ``` - with httpcore.stream("GET", "https://www.example.com/") as response: - ... - ``` - - When using the `stream()` function, the body of the response will not be - automatically read. If you want to access the response body you should - either use `content = response.read()`, or `for chunk in response.iter_content()`. - - Arguments: - method: The HTTP method for the request. Typically one of `"GET"`, - `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. - url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, - or as str/bytes. - headers: The HTTP request headers. Either as a dictionary of str/bytes, - or as a list of two-tuples of str/bytes. - content: The content of the request body. Either as bytes, - or as a bytes iterator. - extensions: A dictionary of optional extra information included on the request. - Possible keys include `"timeout"`. - - Returns: - An instance of `httpcore.Response`. - """ - with ConnectionPool() as pool: - with pool.stream( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) as response: - yield response diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/__init__.py deleted file mode 100644 index 88dc7f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -from .connection import AsyncHTTPConnection -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .http_proxy import AsyncHTTPProxy -from .interfaces import AsyncConnectionInterface - -try: - from .http2 import AsyncHTTP2Connection -except ImportError: # pragma: nocover - - class AsyncHTTP2Connection: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use http2 support, but the `h2` package is not " - "installed. Use 'pip install httpcore[http2]'." - ) - - -try: - from .socks_proxy import AsyncSOCKSProxy -except ImportError: # pragma: nocover - - class AsyncSOCKSProxy: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use SOCKS support, but the `socksio` package is not " - "installed. Use 'pip install httpcore[socks]'." - ) - - -__all__ = [ - "AsyncHTTPConnection", - "AsyncConnectionPool", - "AsyncHTTPProxy", - "AsyncHTTP11Connection", - "AsyncHTTP2Connection", - "AsyncConnectionInterface", - "AsyncSOCKSProxy", -] diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection.py deleted file mode 100644 index b42581d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection.py +++ /dev/null @@ -1,222 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import ssl -import types -import typing - -from .._backends.auto import AutoBackend -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream -from .._exceptions import ConnectError, ConnectTimeout -from .._models import Origin, Request, Response -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. - - -logger = logging.getLogger("httpcore.connection") - - -def exponential_backoff(factor: float) -> typing.Iterator[float]: - """ - Generate a geometric sequence that has a ratio of 2 and starts with 0. - - For example: - - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` - - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` - """ - yield 0 - for n in itertools.count(): - yield factor * 2**n - - -class AsyncHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - origin: Origin, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._origin = origin - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend: AsyncNetworkBackend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._connection: AsyncConnectionInterface | None = None - self._connect_failed: bool = False - self._request_lock = AsyncLock() - self._socket_options = socket_options - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection to {self._origin}" - ) - - try: - async with self._request_lock: - if self._connection is None: - stream = await self._connect(request) - - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except BaseException as exc: - self._connect_failed = True - raise exc - - return await self._connection.handle_async_request(request) - - async def _connect(self, request: Request) -> AsyncNetworkStream: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - retries_left = self._retries - delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) - - while True: - try: - if self._uds is None: - kwargs = { - "host": self._origin.host.decode("ascii"), - "port": self._origin.port, - "local_address": self._local_address, - "timeout": timeout, - "socket_options": self._socket_options, - } - async with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = await self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - else: - kwargs = { - "path": self._uds, - "timeout": timeout, - "socket_options": self._socket_options, - } - async with Trace( - "connect_unix_socket", logger, request, kwargs - ) as trace: - stream = await self._network_backend.connect_unix_socket( - **kwargs - ) - trace.return_value = stream - - if self._origin.scheme in (b"https", b"wss"): - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - return stream - except (ConnectError, ConnectTimeout): - if retries_left <= 0: - raise - retries_left -= 1 - delay = next(delays) - async with Trace("retry", logger, request, kwargs) as trace: - await self._network_backend.sleep(delay) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - async def aclose(self) -> None: - if self._connection is not None: - async with Trace("close", logger, None, {}): - await self._connection.aclose() - - def is_available(self) -> bool: - if self._connection is None: - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTPConnection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection_pool.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection_pool.py deleted file mode 100644 index 96e973d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/connection_pool.py +++ /dev/null @@ -1,420 +0,0 @@ -from __future__ import annotations - -import ssl -import sys -import types -import typing - -from .._backends.auto import AutoBackend -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol -from .._models import Origin, Proxy, Request, Response -from .._synchronization import AsyncEvent, AsyncShieldCancellation, AsyncThreadLock -from .connection import AsyncHTTPConnection -from .interfaces import AsyncConnectionInterface, AsyncRequestInterface - - -class AsyncPoolRequest: - def __init__(self, request: Request) -> None: - self.request = request - self.connection: AsyncConnectionInterface | None = None - self._connection_acquired = AsyncEvent() - - def assign_to_connection(self, connection: AsyncConnectionInterface | None) -> None: - self.connection = connection - self._connection_acquired.set() - - def clear_connection(self) -> None: - self.connection = None - self._connection_acquired = AsyncEvent() - - async def wait_for_connection( - self, timeout: float | None = None - ) -> AsyncConnectionInterface: - if self.connection is None: - await self._connection_acquired.wait(timeout=timeout) - assert self.connection is not None - return self.connection - - def is_queued(self) -> bool: - return self.connection is None - - -class AsyncConnectionPool(AsyncRequestInterface): - """ - A connection pool for making HTTP requests. - """ - - def __init__( - self, - ssl_context: ssl.SSLContext | None = None, - proxy: Proxy | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish a - connection. - local_address: Local address to connect from. Can also be used to connect - using a particular address family. Using `local_address="0.0.0.0"` - will connect using an `AF_INET` address (IPv4), while using - `local_address="::"` will connect using an `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - socket_options: Socket options that have to be included - in the TCP socket when the connection was established. - """ - self._ssl_context = ssl_context - self._proxy = proxy - self._max_connections = ( - sys.maxsize if max_connections is None else max_connections - ) - self._max_keepalive_connections = ( - sys.maxsize - if max_keepalive_connections is None - else max_keepalive_connections - ) - self._max_keepalive_connections = min( - self._max_connections, self._max_keepalive_connections - ) - - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._socket_options = socket_options - - # The mutable state on a connection pool is the queue of incoming requests, - # and the set of connections that are servicing those requests. - self._connections: list[AsyncConnectionInterface] = [] - self._requests: list[AsyncPoolRequest] = [] - - # We only mutate the state of the connection pool within an 'optional_thread_lock' - # context. This holds a threading lock unless we're running in async mode, - # in which case it is a no-op. - self._optional_thread_lock = AsyncThreadLock() - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - if self._proxy is not None: - if self._proxy.url.scheme in (b"socks5", b"socks5h"): - from .socks_proxy import AsyncSocks5Connection - - return AsyncSocks5Connection( - proxy_origin=self._proxy.url.origin, - proxy_auth=self._proxy.auth, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - elif origin.scheme == b"http": - from .http_proxy import AsyncForwardHTTPConnection - - return AsyncForwardHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - ) - from .http_proxy import AsyncTunnelHTTPConnection - - return AsyncTunnelHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - return AsyncHTTPConnection( - origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - retries=self._retries, - local_address=self._local_address, - uds=self._uds, - network_backend=self._network_backend, - socket_options=self._socket_options, - ) - - @property - def connections(self) -> list[AsyncConnectionInterface]: - """ - Return a list of the connections currently in the pool. - - For example: - - ```python - >>> pool.connections - [ - , - , - , - ] - ``` - """ - return list(self._connections) - - async def handle_async_request(self, request: Request) -> Response: - """ - Send an HTTP request, and return an HTTP response. - - This is the core implementation that is called into by `.request()` or `.stream()`. - """ - scheme = request.url.scheme.decode() - if scheme == "": - raise UnsupportedProtocol( - "Request URL is missing an 'http://' or 'https://' protocol." - ) - if scheme not in ("http", "https", "ws", "wss"): - raise UnsupportedProtocol( - f"Request URL has an unsupported protocol '{scheme}://'." - ) - - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) - - with self._optional_thread_lock: - # Add the incoming request to our request queue. - pool_request = AsyncPoolRequest(request) - self._requests.append(pool_request) - - try: - while True: - with self._optional_thread_lock: - # Assign incoming requests to available connections, - # closing or creating new connections as required. - closing = self._assign_requests_to_connections() - await self._close_connections(closing) - - # Wait until this request has an assigned connection. - connection = await pool_request.wait_for_connection(timeout=timeout) - - try: - # Send the request on the assigned connection. - response = await connection.handle_async_request( - pool_request.request - ) - except ConnectionNotAvailable: - # In some cases a connection may initially be available to - # handle a request, but then become unavailable. - # - # In this case we clear the connection and try again. - pool_request.clear_connection() - else: - break # pragma: nocover - - except BaseException as exc: - with self._optional_thread_lock: - # For any exception or cancellation we remove the request from - # the queue, and then re-assign requests to connections. - self._requests.remove(pool_request) - closing = self._assign_requests_to_connections() - - await self._close_connections(closing) - raise exc from None - - # Return the response. Note that in this case we still have to manage - # the point at which the response is closed. - assert isinstance(response.stream, typing.AsyncIterable) - return Response( - status=response.status, - headers=response.headers, - content=PoolByteStream( - stream=response.stream, pool_request=pool_request, pool=self - ), - extensions=response.extensions, - ) - - def _assign_requests_to_connections(self) -> list[AsyncConnectionInterface]: - """ - Manage the state of the connection pool, assigning incoming - requests to connections as available. - - Called whenever a new request is added or removed from the pool. - - Any closing connections are returned, allowing the I/O for closing - those connections to be handled seperately. - """ - closing_connections = [] - - # First we handle cleaning up any connections that are closed, - # have expired their keep-alive, or surplus idle connections. - for connection in list(self._connections): - if connection.is_closed(): - # log: "removing closed connection" - self._connections.remove(connection) - elif connection.has_expired(): - # log: "closing expired connection" - self._connections.remove(connection) - closing_connections.append(connection) - elif ( - connection.is_idle() - and len([connection.is_idle() for connection in self._connections]) - > self._max_keepalive_connections - ): - # log: "closing idle connection" - self._connections.remove(connection) - closing_connections.append(connection) - - # Assign queued requests to connections. - queued_requests = [request for request in self._requests if request.is_queued()] - for pool_request in queued_requests: - origin = pool_request.request.url.origin - available_connections = [ - connection - for connection in self._connections - if connection.can_handle_request(origin) and connection.is_available() - ] - idle_connections = [ - connection for connection in self._connections if connection.is_idle() - ] - - # There are three cases for how we may be able to handle the request: - # - # 1. There is an existing connection that can handle the request. - # 2. We can create a new connection to handle the request. - # 3. We can close an idle connection and then create a new connection - # to handle the request. - if available_connections: - # log: "reusing existing connection" - connection = available_connections[0] - pool_request.assign_to_connection(connection) - elif len(self._connections) < self._max_connections: - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - elif idle_connections: - # log: "closing idle connection" - connection = idle_connections[0] - self._connections.remove(connection) - closing_connections.append(connection) - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - - return closing_connections - - async def _close_connections(self, closing: list[AsyncConnectionInterface]) -> None: - # Close connections which have been removed from the pool. - with AsyncShieldCancellation(): - for connection in closing: - await connection.aclose() - - async def aclose(self) -> None: - # Explicitly close the connection pool. - # Clears all existing requests and connections. - with self._optional_thread_lock: - closing_connections = list(self._connections) - self._connections = [] - await self._close_connections(closing_connections) - - async def __aenter__(self) -> AsyncConnectionPool: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - with self._optional_thread_lock: - request_is_queued = [request.is_queued() for request in self._requests] - connection_is_idle = [ - connection.is_idle() for connection in self._connections - ] - - num_active_requests = request_is_queued.count(False) - num_queued_requests = request_is_queued.count(True) - num_active_connections = connection_is_idle.count(False) - num_idle_connections = connection_is_idle.count(True) - - requests_info = ( - f"Requests: {num_active_requests} active, {num_queued_requests} queued" - ) - connection_info = ( - f"Connections: {num_active_connections} active, {num_idle_connections} idle" - ) - - return f"<{class_name} [{requests_info} | {connection_info}]>" - - -class PoolByteStream: - def __init__( - self, - stream: typing.AsyncIterable[bytes], - pool_request: AsyncPoolRequest, - pool: AsyncConnectionPool, - ) -> None: - self._stream = stream - self._pool_request = pool_request - self._pool = pool - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - try: - async for part in self._stream: - yield part - except BaseException as exc: - await self.aclose() - raise exc from None - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - with AsyncShieldCancellation(): - if hasattr(self._stream, "aclose"): - await self._stream.aclose() - - with self._pool._optional_thread_lock: - self._pool._requests.remove(self._pool_request) - closing = self._pool._assign_requests_to_connections() - - await self._pool._close_connections(closing) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http11.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http11.py deleted file mode 100644 index e6d6d70..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http11.py +++ /dev/null @@ -1,379 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import ssl -import time -import types -import typing - -import h11 - -from .._backends.base import AsyncNetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, - WriteError, - map_exceptions, -) -from .._models import Origin, Request, Response -from .._synchronization import AsyncLock, AsyncShieldCancellation -from .._trace import Trace -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.http11") - - -# A subset of `h11.Event` types supported by `_send_event` -H11SendEvent = typing.Union[ - h11.Request, - h11.Data, - h11.EndOfMessage, -] - - -class HTTPConnectionState(enum.IntEnum): - NEW = 0 - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class AsyncHTTP11Connection(AsyncConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 - - def __init__( - self, - origin: Origin, - stream: AsyncNetworkStream, - keepalive_expiry: float | None = None, - ) -> None: - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._expire_at: float | None = None - self._state = HTTPConnectionState.NEW - self._state_lock = AsyncLock() - self._request_count = 0 - self._h11_state = h11.Connection( - our_role=h11.CLIENT, - max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, - ) - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - async with self._state_lock: - if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): - self._request_count += 1 - self._state = HTTPConnectionState.ACTIVE - self._expire_at = None - else: - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request} - try: - async with Trace( - "send_request_headers", logger, request, kwargs - ) as trace: - await self._send_request_headers(**kwargs) - async with Trace("send_request_body", logger, request, kwargs) as trace: - await self._send_request_body(**kwargs) - except WriteError: - # If we get a write error while we're writing the request, - # then we supress this error and move on to attempting to - # read the response. Servers can sometimes close the request - # pre-emptively and then respond with a well formed HTTP - # error response. - pass - - async with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - ( - http_version, - status, - reason_phrase, - headers, - trailing_data, - ) = await self._receive_response_headers(**kwargs) - trace.return_value = ( - http_version, - status, - reason_phrase, - headers, - ) - - network_stream = self._network_stream - - # CONNECT or Upgrade request - if (status == 101) or ( - (request.method == b"CONNECT") and (200 <= status < 300) - ): - network_stream = AsyncHTTP11UpgradeStream(network_stream, trailing_data) - - return Response( - status=status, - headers=headers, - content=HTTP11ConnectionByteStream(self, request), - extensions={ - "http_version": http_version, - "reason_phrase": reason_phrase, - "network_stream": network_stream, - }, - ) - except BaseException as exc: - with AsyncShieldCancellation(): - async with Trace("response_closed", logger, request) as trace: - await self._response_closed() - raise exc - - # Sending the request... - - async def _send_request_headers(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): - event = h11.Request( - method=request.method, - target=request.url.target, - headers=request.headers, - ) - await self._send_event(event, timeout=timeout) - - async def _send_request_body(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - assert isinstance(request.stream, typing.AsyncIterable) - async for chunk in request.stream: - event = h11.Data(data=chunk) - await self._send_event(event, timeout=timeout) - - await self._send_event(h11.EndOfMessage(), timeout=timeout) - - async def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: - bytes_to_send = self._h11_state.send(event) - if bytes_to_send is not None: - await self._network_stream.write(bytes_to_send, timeout=timeout) - - # Receiving the response... - - async def _receive_response_headers( - self, request: Request - ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = await self._receive_event(timeout=timeout) - if isinstance(event, h11.Response): - break - if ( - isinstance(event, h11.InformationalResponse) - and event.status_code == 101 - ): - break - - http_version = b"HTTP/" + event.http_version - - # h11 version 0.11+ supports a `raw_items` interface to get the - # raw header casing, rather than the enforced lowercase headers. - headers = event.headers.raw_items() - - trailing_data, _ = self._h11_state.trailing_data - - return http_version, event.status_code, event.reason, headers, trailing_data - - async def _receive_response_body( - self, request: Request - ) -> typing.AsyncIterator[bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = await self._receive_event(timeout=timeout) - if isinstance(event, h11.Data): - yield bytes(event.data) - elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): - break - - async def _receive_event( - self, timeout: float | None = None - ) -> h11.Event | type[h11.PAUSED]: - while True: - with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() - - if event is h11.NEED_DATA: - data = await self._network_stream.read( - self.READ_NUM_BYTES, timeout=timeout - ) - - # If we feed this case through h11 we'll raise an exception like: - # - # httpcore.RemoteProtocolError: can't handle event type - # ConnectionClosed when role=SERVER and state=SEND_RESPONSE - # - # Which is accurate, but not very informative from an end-user - # perspective. Instead we handle this case distinctly and treat - # it as a ConnectError. - if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: - msg = "Server disconnected without sending a response." - raise RemoteProtocolError(msg) - - self._h11_state.receive_data(data) - else: - # mypy fails to narrow the type in the above if statement above - return event # type: ignore[return-value] - - async def _response_closed(self) -> None: - async with self._state_lock: - if ( - self._h11_state.our_state is h11.DONE - and self._h11_state.their_state is h11.DONE - ): - self._state = HTTPConnectionState.IDLE - self._h11_state.start_next_cycle() - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - else: - await self.aclose() - - # Once the connection is no longer required... - - async def aclose(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._state = HTTPConnectionState.CLOSED - await self._network_stream.aclose() - - # The AsyncConnectionInterface methods provide information about the state of - # the connection, allowing for a connection pooling implementation to - # determine when to reuse and when to close the connection... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - # Note that HTTP/1.1 connections in the "NEW" state are not treated as - # being "available". The control flow which created the connection will - # be able to send an outgoing request, but the connection will not be - # acquired from the connection pool for any other request. - return self._state == HTTPConnectionState.IDLE - - def has_expired(self) -> bool: - now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/1.1, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTP11Connection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - -class HTTP11ConnectionByteStream: - def __init__(self, connection: AsyncHTTP11Connection, request: Request) -> None: - self._connection = connection - self._request = request - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - kwargs = {"request": self._request} - try: - async with Trace("receive_response_body", logger, self._request, kwargs): - async for chunk in self._connection._receive_response_body(**kwargs): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - async with Trace("response_closed", logger, self._request): - await self._connection._response_closed() - - -class AsyncHTTP11UpgradeStream(AsyncNetworkStream): - def __init__(self, stream: AsyncNetworkStream, leading_data: bytes) -> None: - self._stream = stream - self._leading_data = leading_data - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._leading_data: - buffer = self._leading_data[:max_bytes] - self._leading_data = self._leading_data[max_bytes:] - return buffer - else: - return await self._stream.read(max_bytes, timeout) - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - await self._stream.write(buffer, timeout) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - return await self._stream.start_tls(ssl_context, server_hostname, timeout) - - def get_extra_info(self, info: str) -> typing.Any: - return self._stream.get_extra_info(info) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http2.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http2.py deleted file mode 100644 index dbd0bee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http2.py +++ /dev/null @@ -1,592 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import time -import types -import typing - -import h2.config -import h2.connection -import h2.events -import h2.exceptions -import h2.settings - -from .._backends.base import AsyncNetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, -) -from .._models import Origin, Request, Response -from .._synchronization import AsyncLock, AsyncSemaphore, AsyncShieldCancellation -from .._trace import Trace -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.http2") - - -def has_body_headers(request: Request) -> bool: - return any( - k.lower() == b"content-length" or k.lower() == b"transfer-encoding" - for k, v in request.headers - ) - - -class HTTPConnectionState(enum.IntEnum): - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class AsyncHTTP2Connection(AsyncConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) - - def __init__( - self, - origin: Origin, - stream: AsyncNetworkStream, - keepalive_expiry: float | None = None, - ): - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._h2_state = h2.connection.H2Connection(config=self.CONFIG) - self._state = HTTPConnectionState.IDLE - self._expire_at: float | None = None - self._request_count = 0 - self._init_lock = AsyncLock() - self._state_lock = AsyncLock() - self._read_lock = AsyncLock() - self._write_lock = AsyncLock() - self._sent_connection_init = False - self._used_all_stream_ids = False - self._connection_error = False - - # Mapping from stream ID to response stream events. - self._events: dict[ - int, - list[ - h2.events.ResponseReceived - | h2.events.DataReceived - | h2.events.StreamEnded - | h2.events.StreamReset, - ], - ] = {} - - # Connection terminated events are stored as state since - # we need to handle them for all streams. - self._connection_terminated: h2.events.ConnectionTerminated | None = None - - self._read_exception: Exception | None = None - self._write_exception: Exception | None = None - - async def handle_async_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - # This cannot occur in normal operation, since the connection pool - # will only send requests on connections that handle them. - # It's in place simply for resilience as a guard against incorrect - # usage, for anyone working directly with httpcore connections. - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - async with self._state_lock: - if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): - self._request_count += 1 - self._expire_at = None - self._state = HTTPConnectionState.ACTIVE - else: - raise ConnectionNotAvailable() - - async with self._init_lock: - if not self._sent_connection_init: - try: - sci_kwargs = {"request": request} - async with Trace( - "send_connection_init", logger, request, sci_kwargs - ): - await self._send_connection_init(**sci_kwargs) - except BaseException as exc: - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - self._sent_connection_init = True - - # Initially start with just 1 until the remote server provides - # its max_concurrent_streams value - self._max_streams = 1 - - local_settings_max_streams = ( - self._h2_state.local_settings.max_concurrent_streams - ) - self._max_streams_semaphore = AsyncSemaphore(local_settings_max_streams) - - for _ in range(local_settings_max_streams - self._max_streams): - await self._max_streams_semaphore.acquire() - - await self._max_streams_semaphore.acquire() - - try: - stream_id = self._h2_state.get_next_available_stream_id() - self._events[stream_id] = [] - except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover - self._used_all_stream_ids = True - self._request_count -= 1 - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request, "stream_id": stream_id} - async with Trace("send_request_headers", logger, request, kwargs): - await self._send_request_headers(request=request, stream_id=stream_id) - async with Trace("send_request_body", logger, request, kwargs): - await self._send_request_body(request=request, stream_id=stream_id) - async with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - status, headers = await self._receive_response( - request=request, stream_id=stream_id - ) - trace.return_value = (status, headers) - - return Response( - status=status, - headers=headers, - content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), - extensions={ - "http_version": b"HTTP/2", - "network_stream": self._network_stream, - "stream_id": stream_id, - }, - ) - except BaseException as exc: # noqa: PIE786 - with AsyncShieldCancellation(): - kwargs = {"stream_id": stream_id} - async with Trace("response_closed", logger, request, kwargs): - await self._response_closed(stream_id=stream_id) - - if isinstance(exc, h2.exceptions.ProtocolError): - # One case where h2 can raise a protocol error is when a - # closed frame has been seen by the state machine. - # - # This happens when one stream is reading, and encounters - # a GOAWAY event. Other flows of control may then raise - # a protocol error at any point they interact with the 'h2_state'. - # - # In this case we'll have stored the event, and should raise - # it as a RemoteProtocolError. - if self._connection_terminated: # pragma: nocover - raise RemoteProtocolError(self._connection_terminated) - # If h2 raises a protocol error in some other state then we - # must somehow have made a protocol violation. - raise LocalProtocolError(exc) # pragma: nocover - - raise exc - - async def _send_connection_init(self, request: Request) -> None: - """ - The HTTP/2 connection requires some initial setup before we can start - using individual request/response streams on it. - """ - # Need to set these manually here instead of manipulating via - # __setitem__() otherwise the H2Connection will emit SettingsUpdate - # frames in addition to sending the undesired defaults. - self._h2_state.local_settings = h2.settings.Settings( - client=True, - initial_values={ - # Disable PUSH_PROMISE frames from the server since we don't do anything - # with them for now. Maybe when we support caching? - h2.settings.SettingCodes.ENABLE_PUSH: 0, - # These two are taken from h2 for safe defaults - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, - h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, - }, - ) - - # Some websites (*cough* Yahoo *cough*) balk at this setting being - # present in the initial handshake since it's not defined in the original - # RFC despite the RFC mandating ignoring settings you don't know about. - del self._h2_state.local_settings[ - h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL - ] - - self._h2_state.initiate_connection() - self._h2_state.increment_flow_control_window(2**24) - await self._write_outgoing_data(request) - - # Sending the request... - - async def _send_request_headers(self, request: Request, stream_id: int) -> None: - """ - Send the request headers to a given stream ID. - """ - end_stream = not has_body_headers(request) - - # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. - # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require - # HTTP/1.1 style headers, and map them appropriately if we end up on - # an HTTP/2 connection. - authority = [v for k, v in request.headers if k.lower() == b"host"][0] - - headers = [ - (b":method", request.method), - (b":authority", authority), - (b":scheme", request.url.scheme), - (b":path", request.url.target), - ] + [ - (k.lower(), v) - for k, v in request.headers - if k.lower() - not in ( - b"host", - b"transfer-encoding", - ) - ] - - self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) - self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) - await self._write_outgoing_data(request) - - async def _send_request_body(self, request: Request, stream_id: int) -> None: - """ - Iterate over the request body sending it to a given stream ID. - """ - if not has_body_headers(request): - return - - assert isinstance(request.stream, typing.AsyncIterable) - async for data in request.stream: - await self._send_stream_data(request, stream_id, data) - await self._send_end_stream(request, stream_id) - - async def _send_stream_data( - self, request: Request, stream_id: int, data: bytes - ) -> None: - """ - Send a single chunk of data in one or more data frames. - """ - while data: - max_flow = await self._wait_for_outgoing_flow(request, stream_id) - chunk_size = min(len(data), max_flow) - chunk, data = data[:chunk_size], data[chunk_size:] - self._h2_state.send_data(stream_id, chunk) - await self._write_outgoing_data(request) - - async def _send_end_stream(self, request: Request, stream_id: int) -> None: - """ - Send an empty data frame on on a given stream ID with the END_STREAM flag set. - """ - self._h2_state.end_stream(stream_id) - await self._write_outgoing_data(request) - - # Receiving the response... - - async def _receive_response( - self, request: Request, stream_id: int - ) -> tuple[int, list[tuple[bytes, bytes]]]: - """ - Return the response status code and headers for a given stream ID. - """ - while True: - event = await self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.ResponseReceived): - break - - status_code = 200 - headers = [] - assert event.headers is not None - for k, v in event.headers: - if k == b":status": - status_code = int(v.decode("ascii", errors="ignore")) - elif not k.startswith(b":"): - headers.append((k, v)) - - return (status_code, headers) - - async def _receive_response_body( - self, request: Request, stream_id: int - ) -> typing.AsyncIterator[bytes]: - """ - Iterator that returns the bytes of the response body for a given stream ID. - """ - while True: - event = await self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.DataReceived): - assert event.flow_controlled_length is not None - assert event.data is not None - amount = event.flow_controlled_length - self._h2_state.acknowledge_received_data(amount, stream_id) - await self._write_outgoing_data(request) - yield event.data - elif isinstance(event, h2.events.StreamEnded): - break - - async def _receive_stream_event( - self, request: Request, stream_id: int - ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: - """ - Return the next available event for a given stream ID. - - Will read more data from the network if required. - """ - while not self._events.get(stream_id): - await self._receive_events(request, stream_id) - event = self._events[stream_id].pop(0) - if isinstance(event, h2.events.StreamReset): - raise RemoteProtocolError(event) - return event - - async def _receive_events( - self, request: Request, stream_id: int | None = None - ) -> None: - """ - Read some data from the network until we see one or more events - for a given stream ID. - """ - async with self._read_lock: - if self._connection_terminated is not None: - last_stream_id = self._connection_terminated.last_stream_id - if stream_id and last_stream_id and stream_id > last_stream_id: - self._request_count -= 1 - raise ConnectionNotAvailable() - raise RemoteProtocolError(self._connection_terminated) - - # This conditional is a bit icky. We don't want to block reading if we've - # actually got an event to return for a given stream. We need to do that - # check *within* the atomic read lock. Though it also need to be optional, - # because when we call it from `_wait_for_outgoing_flow` we *do* want to - # block until we've available flow control, event when we have events - # pending for the stream ID we're attempting to send on. - if stream_id is None or not self._events.get(stream_id): - events = await self._read_incoming_data(request) - for event in events: - if isinstance(event, h2.events.RemoteSettingsChanged): - async with Trace( - "receive_remote_settings", logger, request - ) as trace: - await self._receive_remote_settings_change(event) - trace.return_value = event - - elif isinstance( - event, - ( - h2.events.ResponseReceived, - h2.events.DataReceived, - h2.events.StreamEnded, - h2.events.StreamReset, - ), - ): - if event.stream_id in self._events: - self._events[event.stream_id].append(event) - - elif isinstance(event, h2.events.ConnectionTerminated): - self._connection_terminated = event - - await self._write_outgoing_data(request) - - async def _receive_remote_settings_change( - self, event: h2.events.RemoteSettingsChanged - ) -> None: - max_concurrent_streams = event.changed_settings.get( - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS - ) - if max_concurrent_streams: - new_max_streams = min( - max_concurrent_streams.new_value, - self._h2_state.local_settings.max_concurrent_streams, - ) - if new_max_streams and new_max_streams != self._max_streams: - while new_max_streams > self._max_streams: - await self._max_streams_semaphore.release() - self._max_streams += 1 - while new_max_streams < self._max_streams: - await self._max_streams_semaphore.acquire() - self._max_streams -= 1 - - async def _response_closed(self, stream_id: int) -> None: - await self._max_streams_semaphore.release() - del self._events[stream_id] - async with self._state_lock: - if self._connection_terminated and not self._events: - await self.aclose() - - elif self._state == HTTPConnectionState.ACTIVE and not self._events: - self._state = HTTPConnectionState.IDLE - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - if self._used_all_stream_ids: # pragma: nocover - await self.aclose() - - async def aclose(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._h2_state.close_connection() - self._state = HTTPConnectionState.CLOSED - await self._network_stream.aclose() - - # Wrappers around network read/write operations... - - async def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - if self._read_exception is not None: - raise self._read_exception # pragma: nocover - - try: - data = await self._network_stream.read(self.READ_NUM_BYTES, timeout) - if data == b"": - raise RemoteProtocolError("Server disconnected") - except Exception as exc: - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future reads. - # (For example, this means that a single read timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._read_exception = exc - self._connection_error = True - raise exc - - events: list[h2.events.Event] = self._h2_state.receive_data(data) - - return events - - async def _write_outgoing_data(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - async with self._write_lock: - data_to_send = self._h2_state.data_to_send() - - if self._write_exception is not None: - raise self._write_exception # pragma: nocover - - try: - await self._network_stream.write(data_to_send, timeout) - except Exception as exc: # pragma: nocover - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future write. - # (For example, this means that a single write timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._write_exception = exc - self._connection_error = True - raise exc - - # Flow control... - - async def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: - """ - Returns the maximum allowable outgoing flow for a given stream. - - If the allowable flow is zero, then waits on the network until - WindowUpdated frames have increased the flow rate. - https://tools.ietf.org/html/rfc7540#section-6.9 - """ - local_flow: int = self._h2_state.local_flow_control_window(stream_id) - max_frame_size: int = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - while flow == 0: - await self._receive_events(request) - local_flow = self._h2_state.local_flow_control_window(stream_id) - max_frame_size = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - return flow - - # Interface for connection pooling... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - return ( - self._state != HTTPConnectionState.CLOSED - and not self._connection_error - and not self._used_all_stream_ids - and not ( - self._h2_state.state_machine.state - == h2.connection.ConnectionState.CLOSED - ) - ) - - def has_expired(self) -> bool: - now = time.monotonic() - return self._expire_at is not None and now > self._expire_at - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/2, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - async def __aenter__(self) -> AsyncHTTP2Connection: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - await self.aclose() - - -class HTTP2ConnectionByteStream: - def __init__( - self, connection: AsyncHTTP2Connection, request: Request, stream_id: int - ) -> None: - self._connection = connection - self._request = request - self._stream_id = stream_id - self._closed = False - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - kwargs = {"request": self._request, "stream_id": self._stream_id} - try: - async with Trace("receive_response_body", logger, self._request, kwargs): - async for chunk in self._connection._receive_response_body( - request=self._request, stream_id=self._stream_id - ): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with AsyncShieldCancellation(): - await self.aclose() - raise exc - - async def aclose(self) -> None: - if not self._closed: - self._closed = True - kwargs = {"stream_id": self._stream_id} - async with Trace("response_closed", logger, self._request, kwargs): - await self._connection._response_closed(stream_id=self._stream_id) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http_proxy.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http_proxy.py deleted file mode 100644 index cc9d920..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/http_proxy.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -import base64 -import logging -import ssl -import typing - -from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend -from .._exceptions import ProxyError -from .._models import ( - URL, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, -) -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .connection import AsyncHTTPConnection -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] - - -logger = logging.getLogger("httpcore.proxy") - - -def merge_headers( - default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, -) -> list[tuple[bytes, bytes]]: - """ - Append default_headers and override_headers, de-duplicating if a key exists - in both cases. - """ - default_headers = [] if default_headers is None else list(default_headers) - override_headers = [] if override_headers is None else list(override_headers) - has_override = set(key.lower() for key, value in override_headers) - default_headers = [ - (key, value) - for key, value in default_headers - if key.lower() not in has_override - ] - return default_headers + override_headers - - -class AsyncHTTPProxy(AsyncConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - proxy_auth: Any proxy authentication as a two-tuple of - (username, password). May be either bytes or ascii-only str. - proxy_headers: Any HTTP headers to use for the proxy requests. - For example `{"Proxy-Authorization": "Basic :"}`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - local_address=local_address, - uds=uds, - socket_options=socket_options, - ) - - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if ( - self._proxy_url.scheme == b"http" and proxy_ssl_context is not None - ): # pragma: no cover - raise RuntimeError( - "The `proxy_ssl_context` argument is not allowed for the http scheme" - ) - - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - if proxy_auth is not None: - username = enforce_bytes(proxy_auth[0], name="proxy_auth") - password = enforce_bytes(proxy_auth[1], name="proxy_auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self._proxy_headers = [ - (b"Proxy-Authorization", authorization) - ] + self._proxy_headers - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - if origin.scheme == b"http": - return AsyncForwardHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - proxy_ssl_context=self._proxy_ssl_context, - ) - return AsyncTunnelHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - ssl_context=self._ssl_context, - proxy_ssl_context=self._proxy_ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class AsyncForwardHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - keepalive_expiry: float | None = None, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - ) -> None: - self._connection = AsyncHTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._remote_origin = remote_origin - - async def handle_async_request(self, request: Request) -> Response: - headers = merge_headers(self._proxy_headers, request.headers) - url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=bytes(request.url), - ) - proxy_request = Request( - method=request.method, - url=url, - headers=headers, - content=request.stream, - extensions=request.extensions, - ) - return await self._connection.handle_async_request(proxy_request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - await self._connection.aclose() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - -class AsyncTunnelHTTPConnection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: AsyncNetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._connection: AsyncConnectionInterface = AsyncHTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._connect_lock = AsyncLock() - self._connected = False - - async def handle_async_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("connect", None) - - async with self._connect_lock: - if not self._connected: - target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) - - connect_url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=target, - ) - connect_headers = merge_headers( - [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers - ) - connect_request = Request( - method=b"CONNECT", - url=connect_url, - headers=connect_headers, - extensions=request.extensions, - ) - connect_response = await self._connection.handle_async_request( - connect_request - ) - - if connect_response.status < 200 or connect_response.status > 299: - reason_bytes = connect_response.extensions.get("reason_phrase", b"") - reason_str = reason_bytes.decode("ascii", errors="ignore") - msg = "%d %s" % (connect_response.status, reason_str) - await self._connection.aclose() - raise ProxyError(msg) - - stream = connect_response.extensions["network_stream"] - - # Upgrade the stream to SSL - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - - self._connected = True - return await self._connection.handle_async_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - await self._connection.aclose() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/interfaces.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/interfaces.py deleted file mode 100644 index 361583b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/interfaces.py +++ /dev/null @@ -1,137 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from .._models import ( - URL, - Extensions, - HeaderTypes, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, - include_request_headers, -) - - -class AsyncRequestInterface: - async def request( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.AsyncIterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> Response: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = await self.handle_async_request(request) - try: - await response.aread() - finally: - await response.aclose() - return response - - @contextlib.asynccontextmanager - async def stream( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.AsyncIterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> typing.AsyncIterator[Response]: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = await self.handle_async_request(request) - try: - yield response - finally: - await response.aclose() - - async def handle_async_request(self, request: Request) -> Response: - raise NotImplementedError() # pragma: nocover - - -class AsyncConnectionInterface(AsyncRequestInterface): - async def aclose(self) -> None: - raise NotImplementedError() # pragma: nocover - - def info(self) -> str: - raise NotImplementedError() # pragma: nocover - - def can_handle_request(self, origin: Origin) -> bool: - raise NotImplementedError() # pragma: nocover - - def is_available(self) -> bool: - """ - Return `True` if the connection is currently able to accept an - outgoing request. - - An HTTP/1.1 connection will only be available if it is currently idle. - - An HTTP/2 connection will be available so long as the stream ID space is - not yet exhausted, and the connection is not in an error state. - - While the connection is being established we may not yet know if it is going - to result in an HTTP/1.1 or HTTP/2 connection. The connection should be - treated as being available, but might ultimately raise `NewConnectionRequired` - required exceptions if multiple requests are attempted over a connection - that ends up being established as HTTP/1.1. - """ - raise NotImplementedError() # pragma: nocover - - def has_expired(self) -> bool: - """ - Return `True` if the connection is in a state where it should be closed. - - This either means that the connection is idle and it has passed the - expiry time on its keep-alive, or that server has sent an EOF. - """ - raise NotImplementedError() # pragma: nocover - - def is_idle(self) -> bool: - """ - Return `True` if the connection is currently idle. - """ - raise NotImplementedError() # pragma: nocover - - def is_closed(self) -> bool: - """ - Return `True` if the connection has been closed. - - Used when a response is closed to determine if the connection may be - returned to the connection pool or not. - """ - raise NotImplementedError() # pragma: nocover diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/socks_proxy.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_async/socks_proxy.py deleted file mode 100644 index b363f55..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_async/socks_proxy.py +++ /dev/null @@ -1,341 +0,0 @@ -from __future__ import annotations - -import logging -import ssl - -import socksio - -from .._backends.auto import AutoBackend -from .._backends.base import AsyncNetworkBackend, AsyncNetworkStream -from .._exceptions import ConnectionNotAvailable, ProxyError -from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url -from .._ssl import default_ssl_context -from .._synchronization import AsyncLock -from .._trace import Trace -from .connection_pool import AsyncConnectionPool -from .http11 import AsyncHTTP11Connection -from .interfaces import AsyncConnectionInterface - -logger = logging.getLogger("httpcore.socks") - - -AUTH_METHODS = { - b"\x00": "NO AUTHENTICATION REQUIRED", - b"\x01": "GSSAPI", - b"\x02": "USERNAME/PASSWORD", - b"\xff": "NO ACCEPTABLE METHODS", -} - -REPLY_CODES = { - b"\x00": "Succeeded", - b"\x01": "General SOCKS server failure", - b"\x02": "Connection not allowed by ruleset", - b"\x03": "Network unreachable", - b"\x04": "Host unreachable", - b"\x05": "Connection refused", - b"\x06": "TTL expired", - b"\x07": "Command not supported", - b"\x08": "Address type not supported", -} - - -async def _init_socks5_connection( - stream: AsyncNetworkStream, - *, - host: bytes, - port: int, - auth: tuple[bytes, bytes] | None = None, -) -> None: - conn = socksio.socks5.SOCKS5Connection() - - # Auth method request - auth_method = ( - socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED - if auth is None - else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD - ) - conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Auth method response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5AuthReply) - if response.method != auth_method: - requested = AUTH_METHODS.get(auth_method, "UNKNOWN") - responded = AUTH_METHODS.get(response.method, "UNKNOWN") - raise ProxyError( - f"Requested {requested} from proxy server, but got {responded}." - ) - - if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: - # Username/password request - assert auth is not None - username, password = auth - conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Username/password response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) - if not response.success: - raise ProxyError("Invalid username/password") - - # Connect request - conn.send( - socksio.socks5.SOCKS5CommandRequest.from_address( - socksio.socks5.SOCKS5Command.CONNECT, (host, port) - ) - ) - outgoing_bytes = conn.data_to_send() - await stream.write(outgoing_bytes) - - # Connect response - incoming_bytes = await stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5Reply) - if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: - reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") - raise ProxyError(f"Proxy Server could not connect: {reply_code}.") - - -class AsyncSOCKSProxy(AsyncConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - network_backend: AsyncNetworkBackend | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - ) - self._ssl_context = ssl_context - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if proxy_auth is not None: - username, password = proxy_auth - username_bytes = enforce_bytes(username, name="proxy_auth") - password_bytes = enforce_bytes(password, name="proxy_auth") - self._proxy_auth: tuple[bytes, bytes] | None = ( - username_bytes, - password_bytes, - ) - else: - self._proxy_auth = None - - def create_connection(self, origin: Origin) -> AsyncConnectionInterface: - return AsyncSocks5Connection( - proxy_origin=self._proxy_url.origin, - remote_origin=origin, - proxy_auth=self._proxy_auth, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class AsyncSocks5Connection(AsyncConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_auth: tuple[bytes, bytes] | None = None, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: AsyncNetworkBackend | None = None, - ) -> None: - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._proxy_auth = proxy_auth - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - - self._network_backend: AsyncNetworkBackend = ( - AutoBackend() if network_backend is None else network_backend - ) - self._connect_lock = AsyncLock() - self._connection: AsyncConnectionInterface | None = None - self._connect_failed = False - - async def handle_async_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - async with self._connect_lock: - if self._connection is None: - try: - # Connect to the proxy - kwargs = { - "host": self._proxy_origin.host.decode("ascii"), - "port": self._proxy_origin.port, - "timeout": timeout, - } - async with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = await self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - - # Connect to the remote host using socks5 - kwargs = { - "stream": stream, - "host": self._remote_origin.host.decode("ascii"), - "port": self._remote_origin.port, - "auth": self._proxy_auth, - } - async with Trace( - "setup_socks5_connection", logger, request, kwargs - ) as trace: - await _init_socks5_connection(**kwargs) - trace.return_value = stream - - # Upgrade the stream to SSL - if self._remote_origin.scheme == b"https": - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ( - ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ) - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - async with Trace("start_tls", logger, request, kwargs) as trace: - stream = await stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or ( - self._http2 and not self._http1 - ): # pragma: nocover - from .http2 import AsyncHTTP2Connection - - self._connection = AsyncHTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = AsyncHTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except Exception as exc: - self._connect_failed = True - raise exc - elif not self._connection.is_available(): # pragma: nocover - raise ConnectionNotAvailable() - - return await self._connection.handle_async_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - async def aclose(self) -> None: - if self._connection is not None: - await self._connection.aclose() - - def is_available(self) -> bool: - if self._connection is None: # pragma: nocover - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._remote_origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: # pragma: nocover - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/anyio.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/anyio.py deleted file mode 100644 index a140095..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/anyio.py +++ /dev/null @@ -1,146 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -import anyio - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .._utils import is_socket_readable -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class AnyIOStream(AsyncNetworkStream): - def __init__(self, stream: anyio.abc.ByteStream) -> None: - self._stream = stream - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map = { - TimeoutError: ReadTimeout, - anyio.BrokenResourceError: ReadError, - anyio.ClosedResourceError: ReadError, - anyio.EndOfStream: ReadError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - try: - return await self._stream.receive(max_bytes=max_bytes) - except anyio.EndOfStream: # pragma: nocover - return b"" - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - exc_map = { - TimeoutError: WriteTimeout, - anyio.BrokenResourceError: WriteError, - anyio.ClosedResourceError: WriteError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - await self._stream.send(item=buffer) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - exc_map = { - TimeoutError: ConnectTimeout, - anyio.BrokenResourceError: ConnectError, - anyio.EndOfStream: ConnectError, - ssl.SSLError: ConnectError, - } - with map_exceptions(exc_map): - try: - with anyio.fail_after(timeout): - ssl_stream = await anyio.streams.tls.TLSStream.wrap( - self._stream, - ssl_context=ssl_context, - hostname=server_hostname, - standard_compatible=False, - server_side=False, - ) - except Exception as exc: # pragma: nocover - await self.aclose() - raise exc - return AnyIOStream(ssl_stream) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object": - return self._stream.extra(anyio.streams.tls.TLSAttribute.ssl_object, None) - if info == "client_addr": - return self._stream.extra(anyio.abc.SocketAttribute.local_address, None) - if info == "server_addr": - return self._stream.extra(anyio.abc.SocketAttribute.remote_address, None) - if info == "socket": - return self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) - if info == "is_readable": - sock = self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) - return is_socket_readable(sock) - return None - - -class AnyIOBackend(AsyncNetworkBackend): - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - exc_map = { - TimeoutError: ConnectTimeout, - OSError: ConnectError, - anyio.BrokenResourceError: ConnectError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - stream: anyio.abc.ByteStream = await anyio.connect_tcp( - remote_host=host, - remote_port=port, - local_host=local_address, - ) - # By default TCP sockets opened in `asyncio` include TCP_NODELAY. - for option in socket_options: - stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return AnyIOStream(stream) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - exc_map = { - TimeoutError: ConnectTimeout, - OSError: ConnectError, - anyio.BrokenResourceError: ConnectError, - } - with map_exceptions(exc_map): - with anyio.fail_after(timeout): - stream: anyio.abc.ByteStream = await anyio.connect_unix(path) - for option in socket_options: - stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return AnyIOStream(stream) - - async def sleep(self, seconds: float) -> None: - await anyio.sleep(seconds) # pragma: nocover diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/auto.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/auto.py deleted file mode 100644 index 49f0e69..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/auto.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -import typing - -from .._synchronization import current_async_library -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class AutoBackend(AsyncNetworkBackend): - async def _init_backend(self) -> None: - if not (hasattr(self, "_backend")): - backend = current_async_library() - if backend == "trio": - from .trio import TrioBackend - - self._backend: AsyncNetworkBackend = TrioBackend() - else: - from .anyio import AnyIOBackend - - self._backend = AnyIOBackend() - - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - await self._init_backend() - return await self._backend.connect_tcp( - host, - port, - timeout=timeout, - local_address=local_address, - socket_options=socket_options, - ) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - await self._init_backend() - return await self._backend.connect_unix_socket( - path, timeout=timeout, socket_options=socket_options - ) - - async def sleep(self, seconds: float) -> None: # pragma: nocover - await self._init_backend() - return await self._backend.sleep(seconds) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/base.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/base.py deleted file mode 100644 index cf55c8b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/base.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import annotations - -import ssl -import time -import typing - -SOCKET_OPTION = typing.Union[ - typing.Tuple[int, int, int], - typing.Tuple[int, int, typing.Union[bytes, bytearray]], - typing.Tuple[int, int, None, int], -] - - -class NetworkStream: - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - raise NotImplementedError() # pragma: nocover - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - raise NotImplementedError() # pragma: nocover - - def close(self) -> None: - raise NotImplementedError() # pragma: nocover - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def get_extra_info(self, info: str) -> typing.Any: - return None # pragma: nocover - - -class NetworkBackend: - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - raise NotImplementedError() # pragma: nocover - - def sleep(self, seconds: float) -> None: - time.sleep(seconds) # pragma: nocover - - -class AsyncNetworkStream: - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - raise NotImplementedError() # pragma: nocover - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - raise NotImplementedError() # pragma: nocover - - async def aclose(self) -> None: - raise NotImplementedError() # pragma: nocover - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - def get_extra_info(self, info: str) -> typing.Any: - return None # pragma: nocover - - -class AsyncNetworkBackend: - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - raise NotImplementedError() # pragma: nocover - - async def sleep(self, seconds: float) -> None: - raise NotImplementedError() # pragma: nocover diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/mock.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/mock.py deleted file mode 100644 index 9b6edca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/mock.py +++ /dev/null @@ -1,143 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -from .._exceptions import ReadError -from .base import ( - SOCKET_OPTION, - AsyncNetworkBackend, - AsyncNetworkStream, - NetworkBackend, - NetworkStream, -) - - -class MockSSLObject: - def __init__(self, http2: bool): - self._http2 = http2 - - def selected_alpn_protocol(self) -> str: - return "h2" if self._http2 else "http/1.1" - - -class MockStream(NetworkStream): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - self._closed = False - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._closed: - raise ReadError("Connection closed") - if not self._buffer: - return b"" - return self._buffer.pop(0) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - pass - - def close(self) -> None: - self._closed = True - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - return self - - def get_extra_info(self, info: str) -> typing.Any: - return MockSSLObject(http2=self._http2) if info == "ssl_object" else None - - def __repr__(self) -> str: - return "" - - -class MockBackend(NetworkBackend): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - return MockStream(list(self._buffer), http2=self._http2) - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - return MockStream(list(self._buffer), http2=self._http2) - - def sleep(self, seconds: float) -> None: - pass - - -class AsyncMockStream(AsyncNetworkStream): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - self._closed = False - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._closed: - raise ReadError("Connection closed") - if not self._buffer: - return b"" - return self._buffer.pop(0) - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - pass - - async def aclose(self) -> None: - self._closed = True - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - return self - - def get_extra_info(self, info: str) -> typing.Any: - return MockSSLObject(http2=self._http2) if info == "ssl_object" else None - - def __repr__(self) -> str: - return "" - - -class AsyncMockBackend(AsyncNetworkBackend): - def __init__(self, buffer: list[bytes], http2: bool = False) -> None: - self._buffer = buffer - self._http2 = http2 - - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - return AsyncMockStream(list(self._buffer), http2=self._http2) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - return AsyncMockStream(list(self._buffer), http2=self._http2) - - async def sleep(self, seconds: float) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/sync.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/sync.py deleted file mode 100644 index 4018a09..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/sync.py +++ /dev/null @@ -1,241 +0,0 @@ -from __future__ import annotations - -import functools -import socket -import ssl -import sys -import typing - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ExceptionMapping, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .._utils import is_socket_readable -from .base import SOCKET_OPTION, NetworkBackend, NetworkStream - - -class TLSinTLSStream(NetworkStream): # pragma: no cover - """ - Because the standard `SSLContext.wrap_socket` method does - not work for `SSLSocket` objects, we need this class - to implement TLS stream using an underlying `SSLObject` - instance in order to support TLS on top of TLS. - """ - - # Defined in RFC 8449 - TLS_RECORD_SIZE = 16384 - - def __init__( - self, - sock: socket.socket, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ): - self._sock = sock - self._incoming = ssl.MemoryBIO() - self._outgoing = ssl.MemoryBIO() - - self.ssl_obj = ssl_context.wrap_bio( - incoming=self._incoming, - outgoing=self._outgoing, - server_hostname=server_hostname, - ) - - self._sock.settimeout(timeout) - self._perform_io(self.ssl_obj.do_handshake) - - def _perform_io( - self, - func: typing.Callable[..., typing.Any], - ) -> typing.Any: - ret = None - - while True: - errno = None - try: - ret = func() - except (ssl.SSLWantReadError, ssl.SSLWantWriteError) as e: - errno = e.errno - - self._sock.sendall(self._outgoing.read()) - - if errno == ssl.SSL_ERROR_WANT_READ: - buf = self._sock.recv(self.TLS_RECORD_SIZE) - - if buf: - self._incoming.write(buf) - else: - self._incoming.write_eof() - if errno is None: - return ret - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - return typing.cast( - bytes, self._perform_io(functools.partial(self.ssl_obj.read, max_bytes)) - ) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - while buffer: - nsent = self._perform_io(functools.partial(self.ssl_obj.write, buffer)) - buffer = buffer[nsent:] - - def close(self) -> None: - self._sock.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - raise NotImplementedError() - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object": - return self.ssl_obj - if info == "client_addr": - return self._sock.getsockname() - if info == "server_addr": - return self._sock.getpeername() - if info == "socket": - return self._sock - if info == "is_readable": - return is_socket_readable(self._sock) - return None - - -class SyncStream(NetworkStream): - def __init__(self, sock: socket.socket) -> None: - self._sock = sock - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} - with map_exceptions(exc_map): - self._sock.settimeout(timeout) - return self._sock.recv(max_bytes) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} - with map_exceptions(exc_map): - while buffer: - self._sock.settimeout(timeout) - n = self._sock.send(buffer) - buffer = buffer[n:] - - def close(self) -> None: - self._sock.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - with map_exceptions(exc_map): - try: - if isinstance(self._sock, ssl.SSLSocket): # pragma: no cover - # If the underlying socket has already been upgraded - # to the TLS layer (i.e. is an instance of SSLSocket), - # we need some additional smarts to support TLS-in-TLS. - return TLSinTLSStream( - self._sock, ssl_context, server_hostname, timeout - ) - else: - self._sock.settimeout(timeout) - sock = ssl_context.wrap_socket( - self._sock, server_hostname=server_hostname - ) - except Exception as exc: # pragma: nocover - self.close() - raise exc - return SyncStream(sock) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object" and isinstance(self._sock, ssl.SSLSocket): - return self._sock._sslobj # type: ignore - if info == "client_addr": - return self._sock.getsockname() - if info == "server_addr": - return self._sock.getpeername() - if info == "socket": - return self._sock - if info == "is_readable": - return is_socket_readable(self._sock) - return None - - -class SyncBackend(NetworkBackend): - def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: - # Note that we automatically include `TCP_NODELAY` - # in addition to any other custom socket options. - if socket_options is None: - socket_options = [] # pragma: no cover - address = (host, port) - source_address = None if local_address is None else (local_address, 0) - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - - with map_exceptions(exc_map): - sock = socket.create_connection( - address, - timeout, - source_address=source_address, - ) - for option in socket_options: - sock.setsockopt(*option) # pragma: no cover - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - return SyncStream(sock) - - def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> NetworkStream: # pragma: nocover - if sys.platform == "win32": - raise RuntimeError( - "Attempted to connect to a UNIX socket on a Windows system." - ) - if socket_options is None: - socket_options = [] - - exc_map: ExceptionMapping = { - socket.timeout: ConnectTimeout, - OSError: ConnectError, - } - with map_exceptions(exc_map): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - for option in socket_options: - sock.setsockopt(*option) - sock.settimeout(timeout) - sock.connect(path) - return SyncStream(sock) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/trio.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/trio.py deleted file mode 100644 index 6f53f5f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_backends/trio.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import annotations - -import ssl -import typing - -import trio - -from .._exceptions import ( - ConnectError, - ConnectTimeout, - ExceptionMapping, - ReadError, - ReadTimeout, - WriteError, - WriteTimeout, - map_exceptions, -) -from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream - - -class TrioStream(AsyncNetworkStream): - def __init__(self, stream: trio.abc.Stream) -> None: - self._stream = stream - - async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ReadTimeout, - trio.BrokenResourceError: ReadError, - trio.ClosedResourceError: ReadError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - data: bytes = await self._stream.receive_some(max_bytes=max_bytes) - return data - - async def write(self, buffer: bytes, timeout: float | None = None) -> None: - if not buffer: - return - - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: WriteTimeout, - trio.BrokenResourceError: WriteError, - trio.ClosedResourceError: WriteError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - await self._stream.send_all(data=buffer) - - async def aclose(self) -> None: - await self._stream.aclose() - - async def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> AsyncNetworkStream: - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - } - ssl_stream = trio.SSLStream( - self._stream, - ssl_context=ssl_context, - server_hostname=server_hostname, - https_compatible=True, - server_side=False, - ) - with map_exceptions(exc_map): - try: - with trio.fail_after(timeout_or_inf): - await ssl_stream.do_handshake() - except Exception as exc: # pragma: nocover - await self.aclose() - raise exc - return TrioStream(ssl_stream) - - def get_extra_info(self, info: str) -> typing.Any: - if info == "ssl_object" and isinstance(self._stream, trio.SSLStream): - # Type checkers cannot see `_ssl_object` attribute because trio._ssl.SSLStream uses __getattr__/__setattr__. - # Tracked at https://github.com/python-trio/trio/issues/542 - return self._stream._ssl_object # type: ignore[attr-defined] - if info == "client_addr": - return self._get_socket_stream().socket.getsockname() - if info == "server_addr": - return self._get_socket_stream().socket.getpeername() - if info == "socket": - stream = self._stream - while isinstance(stream, trio.SSLStream): - stream = stream.transport_stream - assert isinstance(stream, trio.SocketStream) - return stream.socket - if info == "is_readable": - socket = self.get_extra_info("socket") - return socket.is_readable() - return None - - def _get_socket_stream(self) -> trio.SocketStream: - stream = self._stream - while isinstance(stream, trio.SSLStream): - stream = stream.transport_stream - assert isinstance(stream, trio.SocketStream) - return stream - - -class TrioBackend(AsyncNetworkBackend): - async def connect_tcp( - self, - host: str, - port: int, - timeout: float | None = None, - local_address: str | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: - # By default for TCP sockets, trio enables TCP_NODELAY. - # https://trio.readthedocs.io/en/stable/reference-io.html#trio.SocketStream - if socket_options is None: - socket_options = [] # pragma: no cover - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - OSError: ConnectError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - stream: trio.abc.Stream = await trio.open_tcp_stream( - host=host, port=port, local_address=local_address - ) - for option in socket_options: - stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return TrioStream(stream) - - async def connect_unix_socket( - self, - path: str, - timeout: float | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> AsyncNetworkStream: # pragma: nocover - if socket_options is None: - socket_options = [] - timeout_or_inf = float("inf") if timeout is None else timeout - exc_map: ExceptionMapping = { - trio.TooSlowError: ConnectTimeout, - trio.BrokenResourceError: ConnectError, - OSError: ConnectError, - } - with map_exceptions(exc_map): - with trio.fail_after(timeout_or_inf): - stream: trio.abc.Stream = await trio.open_unix_socket(path) - for option in socket_options: - stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover - return TrioStream(stream) - - async def sleep(self, seconds: float) -> None: - await trio.sleep(seconds) # pragma: nocover diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_exceptions.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_exceptions.py deleted file mode 100644 index bc28d44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_exceptions.py +++ /dev/null @@ -1,81 +0,0 @@ -import contextlib -import typing - -ExceptionMapping = typing.Mapping[typing.Type[Exception], typing.Type[Exception]] - - -@contextlib.contextmanager -def map_exceptions(map: ExceptionMapping) -> typing.Iterator[None]: - try: - yield - except Exception as exc: # noqa: PIE786 - for from_exc, to_exc in map.items(): - if isinstance(exc, from_exc): - raise to_exc(exc) from exc - raise # pragma: nocover - - -class ConnectionNotAvailable(Exception): - pass - - -class ProxyError(Exception): - pass - - -class UnsupportedProtocol(Exception): - pass - - -class ProtocolError(Exception): - pass - - -class RemoteProtocolError(ProtocolError): - pass - - -class LocalProtocolError(ProtocolError): - pass - - -# Timeout errors - - -class TimeoutException(Exception): - pass - - -class PoolTimeout(TimeoutException): - pass - - -class ConnectTimeout(TimeoutException): - pass - - -class ReadTimeout(TimeoutException): - pass - - -class WriteTimeout(TimeoutException): - pass - - -# Network errors - - -class NetworkError(Exception): - pass - - -class ConnectError(NetworkError): - pass - - -class ReadError(NetworkError): - pass - - -class WriteError(NetworkError): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_models.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_models.py deleted file mode 100644 index 8a65f13..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_models.py +++ /dev/null @@ -1,516 +0,0 @@ -from __future__ import annotations - -import base64 -import ssl -import typing -import urllib.parse - -# Functions for typechecking... - - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] -HeaderTypes = typing.Union[HeadersAsSequence, HeadersAsMapping, None] - -Extensions = typing.MutableMapping[str, typing.Any] - - -def enforce_bytes(value: bytes | str, *, name: str) -> bytes: - """ - Any arguments that are ultimately represented as bytes can be specified - either as bytes or as strings. - - However we enforce that any string arguments must only contain characters in - the plain ASCII range. chr(0)...chr(127). If you need to use characters - outside that range then be precise, and use a byte-wise argument. - """ - if isinstance(value, str): - try: - return value.encode("ascii") - except UnicodeEncodeError: - raise TypeError(f"{name} strings may not include unicode characters.") - elif isinstance(value, bytes): - return value - - seen_type = type(value).__name__ - raise TypeError(f"{name} must be bytes or str, but got {seen_type}.") - - -def enforce_url(value: URL | bytes | str, *, name: str) -> URL: - """ - Type check for URL parameters. - """ - if isinstance(value, (bytes, str)): - return URL(value) - elif isinstance(value, URL): - return value - - seen_type = type(value).__name__ - raise TypeError(f"{name} must be a URL, bytes, or str, but got {seen_type}.") - - -def enforce_headers( - value: HeadersAsMapping | HeadersAsSequence | None = None, *, name: str -) -> list[tuple[bytes, bytes]]: - """ - Convienence function that ensure all items in request or response headers - are either bytes or strings in the plain ASCII range. - """ - if value is None: - return [] - elif isinstance(value, typing.Mapping): - return [ - ( - enforce_bytes(k, name="header name"), - enforce_bytes(v, name="header value"), - ) - for k, v in value.items() - ] - elif isinstance(value, typing.Sequence): - return [ - ( - enforce_bytes(k, name="header name"), - enforce_bytes(v, name="header value"), - ) - for k, v in value - ] - - seen_type = type(value).__name__ - raise TypeError( - f"{name} must be a mapping or sequence of two-tuples, but got {seen_type}." - ) - - -def enforce_stream( - value: bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None, - *, - name: str, -) -> typing.Iterable[bytes] | typing.AsyncIterable[bytes]: - if value is None: - return ByteStream(b"") - elif isinstance(value, bytes): - return ByteStream(value) - return value - - -# * https://tools.ietf.org/html/rfc3986#section-3.2.3 -# * https://url.spec.whatwg.org/#url-miscellaneous -# * https://url.spec.whatwg.org/#scheme-state -DEFAULT_PORTS = { - b"ftp": 21, - b"http": 80, - b"https": 443, - b"ws": 80, - b"wss": 443, -} - - -def include_request_headers( - headers: list[tuple[bytes, bytes]], - *, - url: "URL", - content: None | bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes], -) -> list[tuple[bytes, bytes]]: - headers_set = set(k.lower() for k, v in headers) - - if b"host" not in headers_set: - default_port = DEFAULT_PORTS.get(url.scheme) - if url.port is None or url.port == default_port: - header_value = url.host - else: - header_value = b"%b:%d" % (url.host, url.port) - headers = [(b"Host", header_value)] + headers - - if ( - content is not None - and b"content-length" not in headers_set - and b"transfer-encoding" not in headers_set - ): - if isinstance(content, bytes): - content_length = str(len(content)).encode("ascii") - headers += [(b"Content-Length", content_length)] - else: - headers += [(b"Transfer-Encoding", b"chunked")] # pragma: nocover - - return headers - - -# Interfaces for byte streams... - - -class ByteStream: - """ - A container for non-streaming content, and that supports both sync and async - stream iteration. - """ - - def __init__(self, content: bytes) -> None: - self._content = content - - def __iter__(self) -> typing.Iterator[bytes]: - yield self._content - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - yield self._content - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{len(self._content)} bytes]>" - - -class Origin: - def __init__(self, scheme: bytes, host: bytes, port: int) -> None: - self.scheme = scheme - self.host = host - self.port = port - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, Origin) - and self.scheme == other.scheme - and self.host == other.host - and self.port == other.port - ) - - def __str__(self) -> str: - scheme = self.scheme.decode("ascii") - host = self.host.decode("ascii") - port = str(self.port) - return f"{scheme}://{host}:{port}" - - -class URL: - """ - Represents the URL against which an HTTP request may be made. - - The URL may either be specified as a plain string, for convienence: - - ```python - url = httpcore.URL("https://www.example.com/") - ``` - - Or be constructed with explicitily pre-parsed components: - - ```python - url = httpcore.URL(scheme=b'https', host=b'www.example.com', port=None, target=b'/') - ``` - - Using this second more explicit style allows integrations that are using - `httpcore` to pass through URLs that have already been parsed in order to use - libraries such as `rfc-3986` rather than relying on the stdlib. It also ensures - that URL parsing is treated identically at both the networking level and at any - higher layers of abstraction. - - The four components are important here, as they allow the URL to be precisely - specified in a pre-parsed format. They also allow certain types of request to - be created that could not otherwise be expressed. - - For example, an HTTP request to `http://www.example.com/` forwarded via a proxy - at `http://localhost:8080`... - - ```python - # Constructs an HTTP request with a complete URL as the target: - # GET https://www.example.com/ HTTP/1.1 - url = httpcore.URL( - scheme=b'http', - host=b'localhost', - port=8080, - target=b'https://www.example.com/' - ) - request = httpcore.Request( - method="GET", - url=url - ) - ``` - - Another example is constructing an `OPTIONS *` request... - - ```python - # Constructs an 'OPTIONS *' HTTP request: - # OPTIONS * HTTP/1.1 - url = httpcore.URL(scheme=b'https', host=b'www.example.com', target=b'*') - request = httpcore.Request(method="OPTIONS", url=url) - ``` - - This kind of request is not possible to formulate with a URL string, - because the `/` delimiter is always used to demark the target from the - host/port portion of the URL. - - For convenience, string-like arguments may be specified either as strings or - as bytes. However, once a request is being issue over-the-wire, the URL - components are always ultimately required to be a bytewise representation. - - In order to avoid any ambiguity over character encodings, when strings are used - as arguments, they must be strictly limited to the ASCII range `chr(0)`-`chr(127)`. - If you require a bytewise representation that is outside this range you must - handle the character encoding directly, and pass a bytes instance. - """ - - def __init__( - self, - url: bytes | str = "", - *, - scheme: bytes | str = b"", - host: bytes | str = b"", - port: int | None = None, - target: bytes | str = b"", - ) -> None: - """ - Parameters: - url: The complete URL as a string or bytes. - scheme: The URL scheme as a string or bytes. - Typically either `"http"` or `"https"`. - host: The URL host as a string or bytes. Such as `"www.example.com"`. - port: The port to connect to. Either an integer or `None`. - target: The target of the HTTP request. Such as `"/items?search=red"`. - """ - if url: - parsed = urllib.parse.urlparse(enforce_bytes(url, name="url")) - self.scheme = parsed.scheme - self.host = parsed.hostname or b"" - self.port = parsed.port - self.target = (parsed.path or b"/") + ( - b"?" + parsed.query if parsed.query else b"" - ) - else: - self.scheme = enforce_bytes(scheme, name="scheme") - self.host = enforce_bytes(host, name="host") - self.port = port - self.target = enforce_bytes(target, name="target") - - @property - def origin(self) -> Origin: - default_port = { - b"http": 80, - b"https": 443, - b"ws": 80, - b"wss": 443, - b"socks5": 1080, - b"socks5h": 1080, - }[self.scheme] - return Origin( - scheme=self.scheme, host=self.host, port=self.port or default_port - ) - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, URL) - and other.scheme == self.scheme - and other.host == self.host - and other.port == self.port - and other.target == self.target - ) - - def __bytes__(self) -> bytes: - if self.port is None: - return b"%b://%b%b" % (self.scheme, self.host, self.target) - return b"%b://%b:%d%b" % (self.scheme, self.host, self.port, self.target) - - def __repr__(self) -> str: - return ( - f"{self.__class__.__name__}(scheme={self.scheme!r}, " - f"host={self.host!r}, port={self.port!r}, target={self.target!r})" - ) - - -class Request: - """ - An HTTP request. - """ - - def __init__( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes - | typing.Iterable[bytes] - | typing.AsyncIterable[bytes] - | None = None, - extensions: Extensions | None = None, - ) -> None: - """ - Parameters: - method: The HTTP request method, either as a string or bytes. - For example: `GET`. - url: The request URL, either as a `URL` instance, or as a string or bytes. - For example: `"https://www.example.com".` - headers: The HTTP request headers. - content: The content of the request body. - extensions: A dictionary of optional extra information included on - the request. Possible keys include `"timeout"`, and `"trace"`. - """ - self.method: bytes = enforce_bytes(method, name="method") - self.url: URL = enforce_url(url, name="url") - self.headers: list[tuple[bytes, bytes]] = enforce_headers( - headers, name="headers" - ) - self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( - enforce_stream(content, name="content") - ) - self.extensions = {} if extensions is None else extensions - - if "target" in self.extensions: - self.url = URL( - scheme=self.url.scheme, - host=self.url.host, - port=self.url.port, - target=self.extensions["target"], - ) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.method!r}]>" - - -class Response: - """ - An HTTP response. - """ - - def __init__( - self, - status: int, - *, - headers: HeaderTypes = None, - content: bytes - | typing.Iterable[bytes] - | typing.AsyncIterable[bytes] - | None = None, - extensions: Extensions | None = None, - ) -> None: - """ - Parameters: - status: The HTTP status code of the response. For example `200`. - headers: The HTTP response headers. - content: The content of the response body. - extensions: A dictionary of optional extra information included on - the responseself.Possible keys include `"http_version"`, - `"reason_phrase"`, and `"network_stream"`. - """ - self.status: int = status - self.headers: list[tuple[bytes, bytes]] = enforce_headers( - headers, name="headers" - ) - self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( - enforce_stream(content, name="content") - ) - self.extensions = {} if extensions is None else extensions - - self._stream_consumed = False - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - if isinstance(self.stream, typing.Iterable): - raise RuntimeError( - "Attempted to access 'response.content' on a streaming response. " - "Call 'response.read()' first." - ) - else: - raise RuntimeError( - "Attempted to access 'response.content' on a streaming response. " - "Call 'await response.aread()' first." - ) - return self._content - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.status}]>" - - # Sync interface... - - def read(self) -> bytes: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to read an asynchronous response using 'response.read()'. " - "You should use 'await response.aread()' instead." - ) - if not hasattr(self, "_content"): - self._content = b"".join([part for part in self.iter_stream()]) - return self._content - - def iter_stream(self) -> typing.Iterator[bytes]: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to stream an asynchronous response using 'for ... in " - "response.iter_stream()'. " - "You should use 'async for ... in response.aiter_stream()' instead." - ) - if self._stream_consumed: - raise RuntimeError( - "Attempted to call 'for ... in response.iter_stream()' more than once." - ) - self._stream_consumed = True - for chunk in self.stream: - yield chunk - - def close(self) -> None: - if not isinstance(self.stream, typing.Iterable): # pragma: nocover - raise RuntimeError( - "Attempted to close an asynchronous response using 'response.close()'. " - "You should use 'await response.aclose()' instead." - ) - if hasattr(self.stream, "close"): - self.stream.close() - - # Async interface... - - async def aread(self) -> bytes: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to read an synchronous response using " - "'await response.aread()'. " - "You should use 'response.read()' instead." - ) - if not hasattr(self, "_content"): - self._content = b"".join([part async for part in self.aiter_stream()]) - return self._content - - async def aiter_stream(self) -> typing.AsyncIterator[bytes]: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to stream an synchronous response using 'async for ... in " - "response.aiter_stream()'. " - "You should use 'for ... in response.iter_stream()' instead." - ) - if self._stream_consumed: - raise RuntimeError( - "Attempted to call 'async for ... in response.aiter_stream()' " - "more than once." - ) - self._stream_consumed = True - async for chunk in self.stream: - yield chunk - - async def aclose(self) -> None: - if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover - raise RuntimeError( - "Attempted to close a synchronous response using " - "'await response.aclose()'. " - "You should use 'response.close()' instead." - ) - if hasattr(self.stream, "aclose"): - await self.stream.aclose() - - -class Proxy: - def __init__( - self, - url: URL | bytes | str, - auth: tuple[bytes | str, bytes | str] | None = None, - headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - ): - self.url = enforce_url(url, name="url") - self.headers = enforce_headers(headers, name="headers") - self.ssl_context = ssl_context - - if auth is not None: - username = enforce_bytes(auth[0], name="auth") - password = enforce_bytes(auth[1], name="auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self.auth: tuple[bytes, bytes] | None = (username, password) - self.headers = [(b"Proxy-Authorization", authorization)] + self.headers - else: - self.auth = None diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_ssl.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_ssl.py deleted file mode 100644 index c99c5a6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_ssl.py +++ /dev/null @@ -1,9 +0,0 @@ -import ssl - -import certifi - - -def default_ssl_context() -> ssl.SSLContext: - context = ssl.create_default_context() - context.load_verify_locations(certifi.where()) - return context diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/__init__.py deleted file mode 100644 index b476d76..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -from .connection import HTTPConnection -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .http_proxy import HTTPProxy -from .interfaces import ConnectionInterface - -try: - from .http2 import HTTP2Connection -except ImportError: # pragma: nocover - - class HTTP2Connection: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use http2 support, but the `h2` package is not " - "installed. Use 'pip install httpcore[http2]'." - ) - - -try: - from .socks_proxy import SOCKSProxy -except ImportError: # pragma: nocover - - class SOCKSProxy: # type: ignore - def __init__(self, *args, **kwargs) -> None: # type: ignore - raise RuntimeError( - "Attempted to use SOCKS support, but the `socksio` package is not " - "installed. Use 'pip install httpcore[socks]'." - ) - - -__all__ = [ - "HTTPConnection", - "ConnectionPool", - "HTTPProxy", - "HTTP11Connection", - "HTTP2Connection", - "ConnectionInterface", - "SOCKSProxy", -] diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection.py deleted file mode 100644 index 363f8be..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection.py +++ /dev/null @@ -1,222 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import ssl -import types -import typing - -from .._backends.sync import SyncBackend -from .._backends.base import SOCKET_OPTION, NetworkBackend, NetworkStream -from .._exceptions import ConnectError, ConnectTimeout -from .._models import Origin, Request, Response -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. - - -logger = logging.getLogger("httpcore.connection") - - -def exponential_backoff(factor: float) -> typing.Iterator[float]: - """ - Generate a geometric sequence that has a ratio of 2 and starts with 0. - - For example: - - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` - - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` - """ - yield 0 - for n in itertools.count(): - yield factor * 2**n - - -class HTTPConnection(ConnectionInterface): - def __init__( - self, - origin: Origin, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._origin = origin - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend: NetworkBackend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._connection: ConnectionInterface | None = None - self._connect_failed: bool = False - self._request_lock = Lock() - self._socket_options = socket_options - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection to {self._origin}" - ) - - try: - with self._request_lock: - if self._connection is None: - stream = self._connect(request) - - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except BaseException as exc: - self._connect_failed = True - raise exc - - return self._connection.handle_request(request) - - def _connect(self, request: Request) -> NetworkStream: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - retries_left = self._retries - delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) - - while True: - try: - if self._uds is None: - kwargs = { - "host": self._origin.host.decode("ascii"), - "port": self._origin.port, - "local_address": self._local_address, - "timeout": timeout, - "socket_options": self._socket_options, - } - with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - else: - kwargs = { - "path": self._uds, - "timeout": timeout, - "socket_options": self._socket_options, - } - with Trace( - "connect_unix_socket", logger, request, kwargs - ) as trace: - stream = self._network_backend.connect_unix_socket( - **kwargs - ) - trace.return_value = stream - - if self._origin.scheme in (b"https", b"wss"): - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - return stream - except (ConnectError, ConnectTimeout): - if retries_left <= 0: - raise - retries_left -= 1 - delay = next(delays) - with Trace("retry", logger, request, kwargs) as trace: - self._network_backend.sleep(delay) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def close(self) -> None: - if self._connection is not None: - with Trace("close", logger, None, {}): - self._connection.close() - - def is_available(self) -> bool: - if self._connection is None: - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTPConnection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py deleted file mode 100644 index 9ccfa53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py +++ /dev/null @@ -1,420 +0,0 @@ -from __future__ import annotations - -import ssl -import sys -import types -import typing - -from .._backends.sync import SyncBackend -from .._backends.base import SOCKET_OPTION, NetworkBackend -from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol -from .._models import Origin, Proxy, Request, Response -from .._synchronization import Event, ShieldCancellation, ThreadLock -from .connection import HTTPConnection -from .interfaces import ConnectionInterface, RequestInterface - - -class PoolRequest: - def __init__(self, request: Request) -> None: - self.request = request - self.connection: ConnectionInterface | None = None - self._connection_acquired = Event() - - def assign_to_connection(self, connection: ConnectionInterface | None) -> None: - self.connection = connection - self._connection_acquired.set() - - def clear_connection(self) -> None: - self.connection = None - self._connection_acquired = Event() - - def wait_for_connection( - self, timeout: float | None = None - ) -> ConnectionInterface: - if self.connection is None: - self._connection_acquired.wait(timeout=timeout) - assert self.connection is not None - return self.connection - - def is_queued(self) -> bool: - return self.connection is None - - -class ConnectionPool(RequestInterface): - """ - A connection pool for making HTTP requests. - """ - - def __init__( - self, - ssl_context: ssl.SSLContext | None = None, - proxy: Proxy | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish a - connection. - local_address: Local address to connect from. Can also be used to connect - using a particular address family. Using `local_address="0.0.0.0"` - will connect using an `AF_INET` address (IPv4), while using - `local_address="::"` will connect using an `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - socket_options: Socket options that have to be included - in the TCP socket when the connection was established. - """ - self._ssl_context = ssl_context - self._proxy = proxy - self._max_connections = ( - sys.maxsize if max_connections is None else max_connections - ) - self._max_keepalive_connections = ( - sys.maxsize - if max_keepalive_connections is None - else max_keepalive_connections - ) - self._max_keepalive_connections = min( - self._max_connections, self._max_keepalive_connections - ) - - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._retries = retries - self._local_address = local_address - self._uds = uds - - self._network_backend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._socket_options = socket_options - - # The mutable state on a connection pool is the queue of incoming requests, - # and the set of connections that are servicing those requests. - self._connections: list[ConnectionInterface] = [] - self._requests: list[PoolRequest] = [] - - # We only mutate the state of the connection pool within an 'optional_thread_lock' - # context. This holds a threading lock unless we're running in async mode, - # in which case it is a no-op. - self._optional_thread_lock = ThreadLock() - - def create_connection(self, origin: Origin) -> ConnectionInterface: - if self._proxy is not None: - if self._proxy.url.scheme in (b"socks5", b"socks5h"): - from .socks_proxy import Socks5Connection - - return Socks5Connection( - proxy_origin=self._proxy.url.origin, - proxy_auth=self._proxy.auth, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - elif origin.scheme == b"http": - from .http_proxy import ForwardHTTPConnection - - return ForwardHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - ) - from .http_proxy import TunnelHTTPConnection - - return TunnelHTTPConnection( - proxy_origin=self._proxy.url.origin, - proxy_headers=self._proxy.headers, - proxy_ssl_context=self._proxy.ssl_context, - remote_origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - return HTTPConnection( - origin=origin, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - retries=self._retries, - local_address=self._local_address, - uds=self._uds, - network_backend=self._network_backend, - socket_options=self._socket_options, - ) - - @property - def connections(self) -> list[ConnectionInterface]: - """ - Return a list of the connections currently in the pool. - - For example: - - ```python - >>> pool.connections - [ - , - , - , - ] - ``` - """ - return list(self._connections) - - def handle_request(self, request: Request) -> Response: - """ - Send an HTTP request, and return an HTTP response. - - This is the core implementation that is called into by `.request()` or `.stream()`. - """ - scheme = request.url.scheme.decode() - if scheme == "": - raise UnsupportedProtocol( - "Request URL is missing an 'http://' or 'https://' protocol." - ) - if scheme not in ("http", "https", "ws", "wss"): - raise UnsupportedProtocol( - f"Request URL has an unsupported protocol '{scheme}://'." - ) - - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("pool", None) - - with self._optional_thread_lock: - # Add the incoming request to our request queue. - pool_request = PoolRequest(request) - self._requests.append(pool_request) - - try: - while True: - with self._optional_thread_lock: - # Assign incoming requests to available connections, - # closing or creating new connections as required. - closing = self._assign_requests_to_connections() - self._close_connections(closing) - - # Wait until this request has an assigned connection. - connection = pool_request.wait_for_connection(timeout=timeout) - - try: - # Send the request on the assigned connection. - response = connection.handle_request( - pool_request.request - ) - except ConnectionNotAvailable: - # In some cases a connection may initially be available to - # handle a request, but then become unavailable. - # - # In this case we clear the connection and try again. - pool_request.clear_connection() - else: - break # pragma: nocover - - except BaseException as exc: - with self._optional_thread_lock: - # For any exception or cancellation we remove the request from - # the queue, and then re-assign requests to connections. - self._requests.remove(pool_request) - closing = self._assign_requests_to_connections() - - self._close_connections(closing) - raise exc from None - - # Return the response. Note that in this case we still have to manage - # the point at which the response is closed. - assert isinstance(response.stream, typing.Iterable) - return Response( - status=response.status, - headers=response.headers, - content=PoolByteStream( - stream=response.stream, pool_request=pool_request, pool=self - ), - extensions=response.extensions, - ) - - def _assign_requests_to_connections(self) -> list[ConnectionInterface]: - """ - Manage the state of the connection pool, assigning incoming - requests to connections as available. - - Called whenever a new request is added or removed from the pool. - - Any closing connections are returned, allowing the I/O for closing - those connections to be handled seperately. - """ - closing_connections = [] - - # First we handle cleaning up any connections that are closed, - # have expired their keep-alive, or surplus idle connections. - for connection in list(self._connections): - if connection.is_closed(): - # log: "removing closed connection" - self._connections.remove(connection) - elif connection.has_expired(): - # log: "closing expired connection" - self._connections.remove(connection) - closing_connections.append(connection) - elif ( - connection.is_idle() - and len([connection.is_idle() for connection in self._connections]) - > self._max_keepalive_connections - ): - # log: "closing idle connection" - self._connections.remove(connection) - closing_connections.append(connection) - - # Assign queued requests to connections. - queued_requests = [request for request in self._requests if request.is_queued()] - for pool_request in queued_requests: - origin = pool_request.request.url.origin - available_connections = [ - connection - for connection in self._connections - if connection.can_handle_request(origin) and connection.is_available() - ] - idle_connections = [ - connection for connection in self._connections if connection.is_idle() - ] - - # There are three cases for how we may be able to handle the request: - # - # 1. There is an existing connection that can handle the request. - # 2. We can create a new connection to handle the request. - # 3. We can close an idle connection and then create a new connection - # to handle the request. - if available_connections: - # log: "reusing existing connection" - connection = available_connections[0] - pool_request.assign_to_connection(connection) - elif len(self._connections) < self._max_connections: - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - elif idle_connections: - # log: "closing idle connection" - connection = idle_connections[0] - self._connections.remove(connection) - closing_connections.append(connection) - # log: "creating new connection" - connection = self.create_connection(origin) - self._connections.append(connection) - pool_request.assign_to_connection(connection) - - return closing_connections - - def _close_connections(self, closing: list[ConnectionInterface]) -> None: - # Close connections which have been removed from the pool. - with ShieldCancellation(): - for connection in closing: - connection.close() - - def close(self) -> None: - # Explicitly close the connection pool. - # Clears all existing requests and connections. - with self._optional_thread_lock: - closing_connections = list(self._connections) - self._connections = [] - self._close_connections(closing_connections) - - def __enter__(self) -> ConnectionPool: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - with self._optional_thread_lock: - request_is_queued = [request.is_queued() for request in self._requests] - connection_is_idle = [ - connection.is_idle() for connection in self._connections - ] - - num_active_requests = request_is_queued.count(False) - num_queued_requests = request_is_queued.count(True) - num_active_connections = connection_is_idle.count(False) - num_idle_connections = connection_is_idle.count(True) - - requests_info = ( - f"Requests: {num_active_requests} active, {num_queued_requests} queued" - ) - connection_info = ( - f"Connections: {num_active_connections} active, {num_idle_connections} idle" - ) - - return f"<{class_name} [{requests_info} | {connection_info}]>" - - -class PoolByteStream: - def __init__( - self, - stream: typing.Iterable[bytes], - pool_request: PoolRequest, - pool: ConnectionPool, - ) -> None: - self._stream = stream - self._pool_request = pool_request - self._pool = pool - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - try: - for part in self._stream: - yield part - except BaseException as exc: - self.close() - raise exc from None - - def close(self) -> None: - if not self._closed: - self._closed = True - with ShieldCancellation(): - if hasattr(self._stream, "close"): - self._stream.close() - - with self._pool._optional_thread_lock: - self._pool._requests.remove(self._pool_request) - closing = self._pool._assign_requests_to_connections() - - self._pool._close_connections(closing) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http11.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http11.py deleted file mode 100644 index ebd3a97..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http11.py +++ /dev/null @@ -1,379 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import ssl -import time -import types -import typing - -import h11 - -from .._backends.base import NetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, - WriteError, - map_exceptions, -) -from .._models import Origin, Request, Response -from .._synchronization import Lock, ShieldCancellation -from .._trace import Trace -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.http11") - - -# A subset of `h11.Event` types supported by `_send_event` -H11SendEvent = typing.Union[ - h11.Request, - h11.Data, - h11.EndOfMessage, -] - - -class HTTPConnectionState(enum.IntEnum): - NEW = 0 - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class HTTP11Connection(ConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 - - def __init__( - self, - origin: Origin, - stream: NetworkStream, - keepalive_expiry: float | None = None, - ) -> None: - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._expire_at: float | None = None - self._state = HTTPConnectionState.NEW - self._state_lock = Lock() - self._request_count = 0 - self._h11_state = h11.Connection( - our_role=h11.CLIENT, - max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, - ) - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - with self._state_lock: - if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): - self._request_count += 1 - self._state = HTTPConnectionState.ACTIVE - self._expire_at = None - else: - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request} - try: - with Trace( - "send_request_headers", logger, request, kwargs - ) as trace: - self._send_request_headers(**kwargs) - with Trace("send_request_body", logger, request, kwargs) as trace: - self._send_request_body(**kwargs) - except WriteError: - # If we get a write error while we're writing the request, - # then we supress this error and move on to attempting to - # read the response. Servers can sometimes close the request - # pre-emptively and then respond with a well formed HTTP - # error response. - pass - - with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - ( - http_version, - status, - reason_phrase, - headers, - trailing_data, - ) = self._receive_response_headers(**kwargs) - trace.return_value = ( - http_version, - status, - reason_phrase, - headers, - ) - - network_stream = self._network_stream - - # CONNECT or Upgrade request - if (status == 101) or ( - (request.method == b"CONNECT") and (200 <= status < 300) - ): - network_stream = HTTP11UpgradeStream(network_stream, trailing_data) - - return Response( - status=status, - headers=headers, - content=HTTP11ConnectionByteStream(self, request), - extensions={ - "http_version": http_version, - "reason_phrase": reason_phrase, - "network_stream": network_stream, - }, - ) - except BaseException as exc: - with ShieldCancellation(): - with Trace("response_closed", logger, request) as trace: - self._response_closed() - raise exc - - # Sending the request... - - def _send_request_headers(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): - event = h11.Request( - method=request.method, - target=request.url.target, - headers=request.headers, - ) - self._send_event(event, timeout=timeout) - - def _send_request_body(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - assert isinstance(request.stream, typing.Iterable) - for chunk in request.stream: - event = h11.Data(data=chunk) - self._send_event(event, timeout=timeout) - - self._send_event(h11.EndOfMessage(), timeout=timeout) - - def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: - bytes_to_send = self._h11_state.send(event) - if bytes_to_send is not None: - self._network_stream.write(bytes_to_send, timeout=timeout) - - # Receiving the response... - - def _receive_response_headers( - self, request: Request - ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = self._receive_event(timeout=timeout) - if isinstance(event, h11.Response): - break - if ( - isinstance(event, h11.InformationalResponse) - and event.status_code == 101 - ): - break - - http_version = b"HTTP/" + event.http_version - - # h11 version 0.11+ supports a `raw_items` interface to get the - # raw header casing, rather than the enforced lowercase headers. - headers = event.headers.raw_items() - - trailing_data, _ = self._h11_state.trailing_data - - return http_version, event.status_code, event.reason, headers, trailing_data - - def _receive_response_body( - self, request: Request - ) -> typing.Iterator[bytes]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - while True: - event = self._receive_event(timeout=timeout) - if isinstance(event, h11.Data): - yield bytes(event.data) - elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): - break - - def _receive_event( - self, timeout: float | None = None - ) -> h11.Event | type[h11.PAUSED]: - while True: - with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() - - if event is h11.NEED_DATA: - data = self._network_stream.read( - self.READ_NUM_BYTES, timeout=timeout - ) - - # If we feed this case through h11 we'll raise an exception like: - # - # httpcore.RemoteProtocolError: can't handle event type - # ConnectionClosed when role=SERVER and state=SEND_RESPONSE - # - # Which is accurate, but not very informative from an end-user - # perspective. Instead we handle this case distinctly and treat - # it as a ConnectError. - if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: - msg = "Server disconnected without sending a response." - raise RemoteProtocolError(msg) - - self._h11_state.receive_data(data) - else: - # mypy fails to narrow the type in the above if statement above - return event # type: ignore[return-value] - - def _response_closed(self) -> None: - with self._state_lock: - if ( - self._h11_state.our_state is h11.DONE - and self._h11_state.their_state is h11.DONE - ): - self._state = HTTPConnectionState.IDLE - self._h11_state.start_next_cycle() - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - else: - self.close() - - # Once the connection is no longer required... - - def close(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._state = HTTPConnectionState.CLOSED - self._network_stream.close() - - # The ConnectionInterface methods provide information about the state of - # the connection, allowing for a connection pooling implementation to - # determine when to reuse and when to close the connection... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - # Note that HTTP/1.1 connections in the "NEW" state are not treated as - # being "available". The control flow which created the connection will - # be able to send an outgoing request, but the connection will not be - # acquired from the connection pool for any other request. - return self._state == HTTPConnectionState.IDLE - - def has_expired(self) -> bool: - now = time.monotonic() - keepalive_expired = self._expire_at is not None and now > self._expire_at - - # If the HTTP connection is idle but the socket is readable, then the - # only valid state is that the socket is about to return b"", indicating - # a server-initiated disconnect. - server_disconnected = ( - self._state == HTTPConnectionState.IDLE - and self._network_stream.get_extra_info("is_readable") - ) - - return keepalive_expired or server_disconnected - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/1.1, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTP11Connection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - -class HTTP11ConnectionByteStream: - def __init__(self, connection: HTTP11Connection, request: Request) -> None: - self._connection = connection - self._request = request - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - kwargs = {"request": self._request} - try: - with Trace("receive_response_body", logger, self._request, kwargs): - for chunk in self._connection._receive_response_body(**kwargs): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with ShieldCancellation(): - self.close() - raise exc - - def close(self) -> None: - if not self._closed: - self._closed = True - with Trace("response_closed", logger, self._request): - self._connection._response_closed() - - -class HTTP11UpgradeStream(NetworkStream): - def __init__(self, stream: NetworkStream, leading_data: bytes) -> None: - self._stream = stream - self._leading_data = leading_data - - def read(self, max_bytes: int, timeout: float | None = None) -> bytes: - if self._leading_data: - buffer = self._leading_data[:max_bytes] - self._leading_data = self._leading_data[max_bytes:] - return buffer - else: - return self._stream.read(max_bytes, timeout) - - def write(self, buffer: bytes, timeout: float | None = None) -> None: - self._stream.write(buffer, timeout) - - def close(self) -> None: - self._stream.close() - - def start_tls( - self, - ssl_context: ssl.SSLContext, - server_hostname: str | None = None, - timeout: float | None = None, - ) -> NetworkStream: - return self._stream.start_tls(ssl_context, server_hostname, timeout) - - def get_extra_info(self, info: str) -> typing.Any: - return self._stream.get_extra_info(info) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http2.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http2.py deleted file mode 100644 index ddcc189..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http2.py +++ /dev/null @@ -1,592 +0,0 @@ -from __future__ import annotations - -import enum -import logging -import time -import types -import typing - -import h2.config -import h2.connection -import h2.events -import h2.exceptions -import h2.settings - -from .._backends.base import NetworkStream -from .._exceptions import ( - ConnectionNotAvailable, - LocalProtocolError, - RemoteProtocolError, -) -from .._models import Origin, Request, Response -from .._synchronization import Lock, Semaphore, ShieldCancellation -from .._trace import Trace -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.http2") - - -def has_body_headers(request: Request) -> bool: - return any( - k.lower() == b"content-length" or k.lower() == b"transfer-encoding" - for k, v in request.headers - ) - - -class HTTPConnectionState(enum.IntEnum): - ACTIVE = 1 - IDLE = 2 - CLOSED = 3 - - -class HTTP2Connection(ConnectionInterface): - READ_NUM_BYTES = 64 * 1024 - CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) - - def __init__( - self, - origin: Origin, - stream: NetworkStream, - keepalive_expiry: float | None = None, - ): - self._origin = origin - self._network_stream = stream - self._keepalive_expiry: float | None = keepalive_expiry - self._h2_state = h2.connection.H2Connection(config=self.CONFIG) - self._state = HTTPConnectionState.IDLE - self._expire_at: float | None = None - self._request_count = 0 - self._init_lock = Lock() - self._state_lock = Lock() - self._read_lock = Lock() - self._write_lock = Lock() - self._sent_connection_init = False - self._used_all_stream_ids = False - self._connection_error = False - - # Mapping from stream ID to response stream events. - self._events: dict[ - int, - list[ - h2.events.ResponseReceived - | h2.events.DataReceived - | h2.events.StreamEnded - | h2.events.StreamReset, - ], - ] = {} - - # Connection terminated events are stored as state since - # we need to handle them for all streams. - self._connection_terminated: h2.events.ConnectionTerminated | None = None - - self._read_exception: Exception | None = None - self._write_exception: Exception | None = None - - def handle_request(self, request: Request) -> Response: - if not self.can_handle_request(request.url.origin): - # This cannot occur in normal operation, since the connection pool - # will only send requests on connections that handle them. - # It's in place simply for resilience as a guard against incorrect - # usage, for anyone working directly with httpcore connections. - raise RuntimeError( - f"Attempted to send request to {request.url.origin} on connection " - f"to {self._origin}" - ) - - with self._state_lock: - if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): - self._request_count += 1 - self._expire_at = None - self._state = HTTPConnectionState.ACTIVE - else: - raise ConnectionNotAvailable() - - with self._init_lock: - if not self._sent_connection_init: - try: - sci_kwargs = {"request": request} - with Trace( - "send_connection_init", logger, request, sci_kwargs - ): - self._send_connection_init(**sci_kwargs) - except BaseException as exc: - with ShieldCancellation(): - self.close() - raise exc - - self._sent_connection_init = True - - # Initially start with just 1 until the remote server provides - # its max_concurrent_streams value - self._max_streams = 1 - - local_settings_max_streams = ( - self._h2_state.local_settings.max_concurrent_streams - ) - self._max_streams_semaphore = Semaphore(local_settings_max_streams) - - for _ in range(local_settings_max_streams - self._max_streams): - self._max_streams_semaphore.acquire() - - self._max_streams_semaphore.acquire() - - try: - stream_id = self._h2_state.get_next_available_stream_id() - self._events[stream_id] = [] - except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover - self._used_all_stream_ids = True - self._request_count -= 1 - raise ConnectionNotAvailable() - - try: - kwargs = {"request": request, "stream_id": stream_id} - with Trace("send_request_headers", logger, request, kwargs): - self._send_request_headers(request=request, stream_id=stream_id) - with Trace("send_request_body", logger, request, kwargs): - self._send_request_body(request=request, stream_id=stream_id) - with Trace( - "receive_response_headers", logger, request, kwargs - ) as trace: - status, headers = self._receive_response( - request=request, stream_id=stream_id - ) - trace.return_value = (status, headers) - - return Response( - status=status, - headers=headers, - content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), - extensions={ - "http_version": b"HTTP/2", - "network_stream": self._network_stream, - "stream_id": stream_id, - }, - ) - except BaseException as exc: # noqa: PIE786 - with ShieldCancellation(): - kwargs = {"stream_id": stream_id} - with Trace("response_closed", logger, request, kwargs): - self._response_closed(stream_id=stream_id) - - if isinstance(exc, h2.exceptions.ProtocolError): - # One case where h2 can raise a protocol error is when a - # closed frame has been seen by the state machine. - # - # This happens when one stream is reading, and encounters - # a GOAWAY event. Other flows of control may then raise - # a protocol error at any point they interact with the 'h2_state'. - # - # In this case we'll have stored the event, and should raise - # it as a RemoteProtocolError. - if self._connection_terminated: # pragma: nocover - raise RemoteProtocolError(self._connection_terminated) - # If h2 raises a protocol error in some other state then we - # must somehow have made a protocol violation. - raise LocalProtocolError(exc) # pragma: nocover - - raise exc - - def _send_connection_init(self, request: Request) -> None: - """ - The HTTP/2 connection requires some initial setup before we can start - using individual request/response streams on it. - """ - # Need to set these manually here instead of manipulating via - # __setitem__() otherwise the H2Connection will emit SettingsUpdate - # frames in addition to sending the undesired defaults. - self._h2_state.local_settings = h2.settings.Settings( - client=True, - initial_values={ - # Disable PUSH_PROMISE frames from the server since we don't do anything - # with them for now. Maybe when we support caching? - h2.settings.SettingCodes.ENABLE_PUSH: 0, - # These two are taken from h2 for safe defaults - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, - h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, - }, - ) - - # Some websites (*cough* Yahoo *cough*) balk at this setting being - # present in the initial handshake since it's not defined in the original - # RFC despite the RFC mandating ignoring settings you don't know about. - del self._h2_state.local_settings[ - h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL - ] - - self._h2_state.initiate_connection() - self._h2_state.increment_flow_control_window(2**24) - self._write_outgoing_data(request) - - # Sending the request... - - def _send_request_headers(self, request: Request, stream_id: int) -> None: - """ - Send the request headers to a given stream ID. - """ - end_stream = not has_body_headers(request) - - # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. - # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require - # HTTP/1.1 style headers, and map them appropriately if we end up on - # an HTTP/2 connection. - authority = [v for k, v in request.headers if k.lower() == b"host"][0] - - headers = [ - (b":method", request.method), - (b":authority", authority), - (b":scheme", request.url.scheme), - (b":path", request.url.target), - ] + [ - (k.lower(), v) - for k, v in request.headers - if k.lower() - not in ( - b"host", - b"transfer-encoding", - ) - ] - - self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) - self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) - self._write_outgoing_data(request) - - def _send_request_body(self, request: Request, stream_id: int) -> None: - """ - Iterate over the request body sending it to a given stream ID. - """ - if not has_body_headers(request): - return - - assert isinstance(request.stream, typing.Iterable) - for data in request.stream: - self._send_stream_data(request, stream_id, data) - self._send_end_stream(request, stream_id) - - def _send_stream_data( - self, request: Request, stream_id: int, data: bytes - ) -> None: - """ - Send a single chunk of data in one or more data frames. - """ - while data: - max_flow = self._wait_for_outgoing_flow(request, stream_id) - chunk_size = min(len(data), max_flow) - chunk, data = data[:chunk_size], data[chunk_size:] - self._h2_state.send_data(stream_id, chunk) - self._write_outgoing_data(request) - - def _send_end_stream(self, request: Request, stream_id: int) -> None: - """ - Send an empty data frame on on a given stream ID with the END_STREAM flag set. - """ - self._h2_state.end_stream(stream_id) - self._write_outgoing_data(request) - - # Receiving the response... - - def _receive_response( - self, request: Request, stream_id: int - ) -> tuple[int, list[tuple[bytes, bytes]]]: - """ - Return the response status code and headers for a given stream ID. - """ - while True: - event = self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.ResponseReceived): - break - - status_code = 200 - headers = [] - assert event.headers is not None - for k, v in event.headers: - if k == b":status": - status_code = int(v.decode("ascii", errors="ignore")) - elif not k.startswith(b":"): - headers.append((k, v)) - - return (status_code, headers) - - def _receive_response_body( - self, request: Request, stream_id: int - ) -> typing.Iterator[bytes]: - """ - Iterator that returns the bytes of the response body for a given stream ID. - """ - while True: - event = self._receive_stream_event(request, stream_id) - if isinstance(event, h2.events.DataReceived): - assert event.flow_controlled_length is not None - assert event.data is not None - amount = event.flow_controlled_length - self._h2_state.acknowledge_received_data(amount, stream_id) - self._write_outgoing_data(request) - yield event.data - elif isinstance(event, h2.events.StreamEnded): - break - - def _receive_stream_event( - self, request: Request, stream_id: int - ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: - """ - Return the next available event for a given stream ID. - - Will read more data from the network if required. - """ - while not self._events.get(stream_id): - self._receive_events(request, stream_id) - event = self._events[stream_id].pop(0) - if isinstance(event, h2.events.StreamReset): - raise RemoteProtocolError(event) - return event - - def _receive_events( - self, request: Request, stream_id: int | None = None - ) -> None: - """ - Read some data from the network until we see one or more events - for a given stream ID. - """ - with self._read_lock: - if self._connection_terminated is not None: - last_stream_id = self._connection_terminated.last_stream_id - if stream_id and last_stream_id and stream_id > last_stream_id: - self._request_count -= 1 - raise ConnectionNotAvailable() - raise RemoteProtocolError(self._connection_terminated) - - # This conditional is a bit icky. We don't want to block reading if we've - # actually got an event to return for a given stream. We need to do that - # check *within* the atomic read lock. Though it also need to be optional, - # because when we call it from `_wait_for_outgoing_flow` we *do* want to - # block until we've available flow control, event when we have events - # pending for the stream ID we're attempting to send on. - if stream_id is None or not self._events.get(stream_id): - events = self._read_incoming_data(request) - for event in events: - if isinstance(event, h2.events.RemoteSettingsChanged): - with Trace( - "receive_remote_settings", logger, request - ) as trace: - self._receive_remote_settings_change(event) - trace.return_value = event - - elif isinstance( - event, - ( - h2.events.ResponseReceived, - h2.events.DataReceived, - h2.events.StreamEnded, - h2.events.StreamReset, - ), - ): - if event.stream_id in self._events: - self._events[event.stream_id].append(event) - - elif isinstance(event, h2.events.ConnectionTerminated): - self._connection_terminated = event - - self._write_outgoing_data(request) - - def _receive_remote_settings_change( - self, event: h2.events.RemoteSettingsChanged - ) -> None: - max_concurrent_streams = event.changed_settings.get( - h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS - ) - if max_concurrent_streams: - new_max_streams = min( - max_concurrent_streams.new_value, - self._h2_state.local_settings.max_concurrent_streams, - ) - if new_max_streams and new_max_streams != self._max_streams: - while new_max_streams > self._max_streams: - self._max_streams_semaphore.release() - self._max_streams += 1 - while new_max_streams < self._max_streams: - self._max_streams_semaphore.acquire() - self._max_streams -= 1 - - def _response_closed(self, stream_id: int) -> None: - self._max_streams_semaphore.release() - del self._events[stream_id] - with self._state_lock: - if self._connection_terminated and not self._events: - self.close() - - elif self._state == HTTPConnectionState.ACTIVE and not self._events: - self._state = HTTPConnectionState.IDLE - if self._keepalive_expiry is not None: - now = time.monotonic() - self._expire_at = now + self._keepalive_expiry - if self._used_all_stream_ids: # pragma: nocover - self.close() - - def close(self) -> None: - # Note that this method unilaterally closes the connection, and does - # not have any kind of locking in place around it. - self._h2_state.close_connection() - self._state = HTTPConnectionState.CLOSED - self._network_stream.close() - - # Wrappers around network read/write operations... - - def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("read", None) - - if self._read_exception is not None: - raise self._read_exception # pragma: nocover - - try: - data = self._network_stream.read(self.READ_NUM_BYTES, timeout) - if data == b"": - raise RemoteProtocolError("Server disconnected") - except Exception as exc: - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future reads. - # (For example, this means that a single read timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._read_exception = exc - self._connection_error = True - raise exc - - events: list[h2.events.Event] = self._h2_state.receive_data(data) - - return events - - def _write_outgoing_data(self, request: Request) -> None: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("write", None) - - with self._write_lock: - data_to_send = self._h2_state.data_to_send() - - if self._write_exception is not None: - raise self._write_exception # pragma: nocover - - try: - self._network_stream.write(data_to_send, timeout) - except Exception as exc: # pragma: nocover - # If we get a network error we should: - # - # 1. Save the exception and just raise it immediately on any future write. - # (For example, this means that a single write timeout or disconnect will - # immediately close all pending streams. Without requiring multiple - # sequential timeouts.) - # 2. Mark the connection as errored, so that we don't accept any other - # incoming requests. - self._write_exception = exc - self._connection_error = True - raise exc - - # Flow control... - - def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: - """ - Returns the maximum allowable outgoing flow for a given stream. - - If the allowable flow is zero, then waits on the network until - WindowUpdated frames have increased the flow rate. - https://tools.ietf.org/html/rfc7540#section-6.9 - """ - local_flow: int = self._h2_state.local_flow_control_window(stream_id) - max_frame_size: int = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - while flow == 0: - self._receive_events(request) - local_flow = self._h2_state.local_flow_control_window(stream_id) - max_frame_size = self._h2_state.max_outbound_frame_size - flow = min(local_flow, max_frame_size) - return flow - - # Interface for connection pooling... - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._origin - - def is_available(self) -> bool: - return ( - self._state != HTTPConnectionState.CLOSED - and not self._connection_error - and not self._used_all_stream_ids - and not ( - self._h2_state.state_machine.state - == h2.connection.ConnectionState.CLOSED - ) - ) - - def has_expired(self) -> bool: - now = time.monotonic() - return self._expire_at is not None and now > self._expire_at - - def is_idle(self) -> bool: - return self._state == HTTPConnectionState.IDLE - - def is_closed(self) -> bool: - return self._state == HTTPConnectionState.CLOSED - - def info(self) -> str: - origin = str(self._origin) - return ( - f"{origin!r}, HTTP/2, {self._state.name}, " - f"Request Count: {self._request_count}" - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - origin = str(self._origin) - return ( - f"<{class_name} [{origin!r}, {self._state.name}, " - f"Request Count: {self._request_count}]>" - ) - - # These context managers are not used in the standard flow, but are - # useful for testing or working with connection instances directly. - - def __enter__(self) -> HTTP2Connection: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self.close() - - -class HTTP2ConnectionByteStream: - def __init__( - self, connection: HTTP2Connection, request: Request, stream_id: int - ) -> None: - self._connection = connection - self._request = request - self._stream_id = stream_id - self._closed = False - - def __iter__(self) -> typing.Iterator[bytes]: - kwargs = {"request": self._request, "stream_id": self._stream_id} - try: - with Trace("receive_response_body", logger, self._request, kwargs): - for chunk in self._connection._receive_response_body( - request=self._request, stream_id=self._stream_id - ): - yield chunk - except BaseException as exc: - # If we get an exception while streaming the response, - # we want to close the response (and possibly the connection) - # before raising that exception. - with ShieldCancellation(): - self.close() - raise exc - - def close(self) -> None: - if not self._closed: - self._closed = True - kwargs = {"stream_id": self._stream_id} - with Trace("response_closed", logger, self._request, kwargs): - self._connection._response_closed(stream_id=self._stream_id) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http_proxy.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http_proxy.py deleted file mode 100644 index ecca88f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/http_proxy.py +++ /dev/null @@ -1,367 +0,0 @@ -from __future__ import annotations - -import base64 -import logging -import ssl -import typing - -from .._backends.base import SOCKET_OPTION, NetworkBackend -from .._exceptions import ProxyError -from .._models import ( - URL, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, -) -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .connection import HTTPConnection -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -ByteOrStr = typing.Union[bytes, str] -HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] -HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] - - -logger = logging.getLogger("httpcore.proxy") - - -def merge_headers( - default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, -) -> list[tuple[bytes, bytes]]: - """ - Append default_headers and override_headers, de-duplicating if a key exists - in both cases. - """ - default_headers = [] if default_headers is None else list(default_headers) - override_headers = [] if override_headers is None else list(override_headers) - has_override = set(key.lower() for key, value in override_headers) - default_headers = [ - (key, value) - for key, value in default_headers - if key.lower() not in has_override - ] - return default_headers + override_headers - - -class HTTPProxy(ConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - local_address: str | None = None, - uds: str | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - proxy_auth: Any proxy authentication as a two-tuple of - (username, password). May be either bytes or ascii-only str. - proxy_headers: Any HTTP headers to use for the proxy requests. - For example `{"Proxy-Authorization": "Basic :"}`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - local_address=local_address, - uds=uds, - socket_options=socket_options, - ) - - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if ( - self._proxy_url.scheme == b"http" and proxy_ssl_context is not None - ): # pragma: no cover - raise RuntimeError( - "The `proxy_ssl_context` argument is not allowed for the http scheme" - ) - - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - if proxy_auth is not None: - username = enforce_bytes(proxy_auth[0], name="proxy_auth") - password = enforce_bytes(proxy_auth[1], name="proxy_auth") - userpass = username + b":" + password - authorization = b"Basic " + base64.b64encode(userpass) - self._proxy_headers = [ - (b"Proxy-Authorization", authorization) - ] + self._proxy_headers - - def create_connection(self, origin: Origin) -> ConnectionInterface: - if origin.scheme == b"http": - return ForwardHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - keepalive_expiry=self._keepalive_expiry, - network_backend=self._network_backend, - proxy_ssl_context=self._proxy_ssl_context, - ) - return TunnelHTTPConnection( - proxy_origin=self._proxy_url.origin, - proxy_headers=self._proxy_headers, - remote_origin=origin, - ssl_context=self._ssl_context, - proxy_ssl_context=self._proxy_ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class ForwardHTTPConnection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, - keepalive_expiry: float | None = None, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - ) -> None: - self._connection = HTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._remote_origin = remote_origin - - def handle_request(self, request: Request) -> Response: - headers = merge_headers(self._proxy_headers, request.headers) - url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=bytes(request.url), - ) - proxy_request = Request( - method=request.method, - url=url, - headers=headers, - content=request.stream, - extensions=request.extensions, - ) - return self._connection.handle_request(proxy_request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - self._connection.close() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" - - -class TunnelHTTPConnection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - ssl_context: ssl.SSLContext | None = None, - proxy_ssl_context: ssl.SSLContext | None = None, - proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: NetworkBackend | None = None, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - self._connection: ConnectionInterface = HTTPConnection( - origin=proxy_origin, - keepalive_expiry=keepalive_expiry, - network_backend=network_backend, - socket_options=socket_options, - ssl_context=proxy_ssl_context, - ) - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._ssl_context = ssl_context - self._proxy_ssl_context = proxy_ssl_context - self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - self._connect_lock = Lock() - self._connected = False - - def handle_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - timeout = timeouts.get("connect", None) - - with self._connect_lock: - if not self._connected: - target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) - - connect_url = URL( - scheme=self._proxy_origin.scheme, - host=self._proxy_origin.host, - port=self._proxy_origin.port, - target=target, - ) - connect_headers = merge_headers( - [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers - ) - connect_request = Request( - method=b"CONNECT", - url=connect_url, - headers=connect_headers, - extensions=request.extensions, - ) - connect_response = self._connection.handle_request( - connect_request - ) - - if connect_response.status < 200 or connect_response.status > 299: - reason_bytes = connect_response.extensions.get("reason_phrase", b"") - reason_str = reason_bytes.decode("ascii", errors="ignore") - msg = "%d %s" % (connect_response.status, reason_str) - self._connection.close() - raise ProxyError(msg) - - stream = connect_response.extensions["network_stream"] - - # Upgrade the stream to SSL - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or (self._http2 and not self._http1): - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - - self._connected = True - return self._connection.handle_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - self._connection.close() - - def info(self) -> str: - return self._connection.info() - - def is_available(self) -> bool: - return self._connection.is_available() - - def has_expired(self) -> bool: - return self._connection.has_expired() - - def is_idle(self) -> bool: - return self._connection.is_idle() - - def is_closed(self) -> bool: - return self._connection.is_closed() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/interfaces.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/interfaces.py deleted file mode 100644 index e673d4c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/interfaces.py +++ /dev/null @@ -1,137 +0,0 @@ -from __future__ import annotations - -import contextlib -import typing - -from .._models import ( - URL, - Extensions, - HeaderTypes, - Origin, - Request, - Response, - enforce_bytes, - enforce_headers, - enforce_url, - include_request_headers, -) - - -class RequestInterface: - def request( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> Response: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = self.handle_request(request) - try: - response.read() - finally: - response.close() - return response - - @contextlib.contextmanager - def stream( - self, - method: bytes | str, - url: URL | bytes | str, - *, - headers: HeaderTypes = None, - content: bytes | typing.Iterator[bytes] | None = None, - extensions: Extensions | None = None, - ) -> typing.Iterator[Response]: - # Strict type checking on our parameters. - method = enforce_bytes(method, name="method") - url = enforce_url(url, name="url") - headers = enforce_headers(headers, name="headers") - - # Include Host header, and optionally Content-Length or Transfer-Encoding. - headers = include_request_headers(headers, url=url, content=content) - - request = Request( - method=method, - url=url, - headers=headers, - content=content, - extensions=extensions, - ) - response = self.handle_request(request) - try: - yield response - finally: - response.close() - - def handle_request(self, request: Request) -> Response: - raise NotImplementedError() # pragma: nocover - - -class ConnectionInterface(RequestInterface): - def close(self) -> None: - raise NotImplementedError() # pragma: nocover - - def info(self) -> str: - raise NotImplementedError() # pragma: nocover - - def can_handle_request(self, origin: Origin) -> bool: - raise NotImplementedError() # pragma: nocover - - def is_available(self) -> bool: - """ - Return `True` if the connection is currently able to accept an - outgoing request. - - An HTTP/1.1 connection will only be available if it is currently idle. - - An HTTP/2 connection will be available so long as the stream ID space is - not yet exhausted, and the connection is not in an error state. - - While the connection is being established we may not yet know if it is going - to result in an HTTP/1.1 or HTTP/2 connection. The connection should be - treated as being available, but might ultimately raise `NewConnectionRequired` - required exceptions if multiple requests are attempted over a connection - that ends up being established as HTTP/1.1. - """ - raise NotImplementedError() # pragma: nocover - - def has_expired(self) -> bool: - """ - Return `True` if the connection is in a state where it should be closed. - - This either means that the connection is idle and it has passed the - expiry time on its keep-alive, or that server has sent an EOF. - """ - raise NotImplementedError() # pragma: nocover - - def is_idle(self) -> bool: - """ - Return `True` if the connection is currently idle. - """ - raise NotImplementedError() # pragma: nocover - - def is_closed(self) -> bool: - """ - Return `True` if the connection has been closed. - - Used when a response is closed to determine if the connection may be - returned to the connection pool or not. - """ - raise NotImplementedError() # pragma: nocover diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/socks_proxy.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/socks_proxy.py deleted file mode 100644 index 0ca96dd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_sync/socks_proxy.py +++ /dev/null @@ -1,341 +0,0 @@ -from __future__ import annotations - -import logging -import ssl - -import socksio - -from .._backends.sync import SyncBackend -from .._backends.base import NetworkBackend, NetworkStream -from .._exceptions import ConnectionNotAvailable, ProxyError -from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url -from .._ssl import default_ssl_context -from .._synchronization import Lock -from .._trace import Trace -from .connection_pool import ConnectionPool -from .http11 import HTTP11Connection -from .interfaces import ConnectionInterface - -logger = logging.getLogger("httpcore.socks") - - -AUTH_METHODS = { - b"\x00": "NO AUTHENTICATION REQUIRED", - b"\x01": "GSSAPI", - b"\x02": "USERNAME/PASSWORD", - b"\xff": "NO ACCEPTABLE METHODS", -} - -REPLY_CODES = { - b"\x00": "Succeeded", - b"\x01": "General SOCKS server failure", - b"\x02": "Connection not allowed by ruleset", - b"\x03": "Network unreachable", - b"\x04": "Host unreachable", - b"\x05": "Connection refused", - b"\x06": "TTL expired", - b"\x07": "Command not supported", - b"\x08": "Address type not supported", -} - - -def _init_socks5_connection( - stream: NetworkStream, - *, - host: bytes, - port: int, - auth: tuple[bytes, bytes] | None = None, -) -> None: - conn = socksio.socks5.SOCKS5Connection() - - # Auth method request - auth_method = ( - socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED - if auth is None - else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD - ) - conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Auth method response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5AuthReply) - if response.method != auth_method: - requested = AUTH_METHODS.get(auth_method, "UNKNOWN") - responded = AUTH_METHODS.get(response.method, "UNKNOWN") - raise ProxyError( - f"Requested {requested} from proxy server, but got {responded}." - ) - - if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: - # Username/password request - assert auth is not None - username, password = auth - conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Username/password response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) - if not response.success: - raise ProxyError("Invalid username/password") - - # Connect request - conn.send( - socksio.socks5.SOCKS5CommandRequest.from_address( - socksio.socks5.SOCKS5Command.CONNECT, (host, port) - ) - ) - outgoing_bytes = conn.data_to_send() - stream.write(outgoing_bytes) - - # Connect response - incoming_bytes = stream.read(max_bytes=4096) - response = conn.receive_data(incoming_bytes) - assert isinstance(response, socksio.socks5.SOCKS5Reply) - if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: - reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") - raise ProxyError(f"Proxy Server could not connect: {reply_code}.") - - -class SOCKSProxy(ConnectionPool): # pragma: nocover - """ - A connection pool that sends requests via an HTTP proxy. - """ - - def __init__( - self, - proxy_url: URL | bytes | str, - proxy_auth: tuple[bytes | str, bytes | str] | None = None, - ssl_context: ssl.SSLContext | None = None, - max_connections: int | None = 10, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - retries: int = 0, - network_backend: NetworkBackend | None = None, - ) -> None: - """ - A connection pool for making HTTP requests. - - Parameters: - proxy_url: The URL to use when connecting to the proxy server. - For example `"http://127.0.0.1:8080/"`. - ssl_context: An SSL context to use for verifying connections. - If not specified, the default `httpcore.default_ssl_context()` - will be used. - max_connections: The maximum number of concurrent HTTP connections that - the pool should allow. Any attempt to send a request on a pool that - would exceed this amount will block until a connection is available. - max_keepalive_connections: The maximum number of idle HTTP connections - that will be maintained in the pool. - keepalive_expiry: The duration in seconds that an idle HTTP connection - may be maintained for before being expired from the pool. - http1: A boolean indicating if HTTP/1.1 requests should be supported - by the connection pool. Defaults to True. - http2: A boolean indicating if HTTP/2 requests should be supported by - the connection pool. Defaults to False. - retries: The maximum number of retries when trying to establish - a connection. - local_address: Local address to connect from. Can also be used to - connect using a particular address family. Using - `local_address="0.0.0.0"` will connect using an `AF_INET` address - (IPv4), while using `local_address="::"` will connect using an - `AF_INET6` address (IPv6). - uds: Path to a Unix Domain Socket to use instead of TCP sockets. - network_backend: A backend instance to use for handling network I/O. - """ - super().__init__( - ssl_context=ssl_context, - max_connections=max_connections, - max_keepalive_connections=max_keepalive_connections, - keepalive_expiry=keepalive_expiry, - http1=http1, - http2=http2, - network_backend=network_backend, - retries=retries, - ) - self._ssl_context = ssl_context - self._proxy_url = enforce_url(proxy_url, name="proxy_url") - if proxy_auth is not None: - username, password = proxy_auth - username_bytes = enforce_bytes(username, name="proxy_auth") - password_bytes = enforce_bytes(password, name="proxy_auth") - self._proxy_auth: tuple[bytes, bytes] | None = ( - username_bytes, - password_bytes, - ) - else: - self._proxy_auth = None - - def create_connection(self, origin: Origin) -> ConnectionInterface: - return Socks5Connection( - proxy_origin=self._proxy_url.origin, - remote_origin=origin, - proxy_auth=self._proxy_auth, - ssl_context=self._ssl_context, - keepalive_expiry=self._keepalive_expiry, - http1=self._http1, - http2=self._http2, - network_backend=self._network_backend, - ) - - -class Socks5Connection(ConnectionInterface): - def __init__( - self, - proxy_origin: Origin, - remote_origin: Origin, - proxy_auth: tuple[bytes, bytes] | None = None, - ssl_context: ssl.SSLContext | None = None, - keepalive_expiry: float | None = None, - http1: bool = True, - http2: bool = False, - network_backend: NetworkBackend | None = None, - ) -> None: - self._proxy_origin = proxy_origin - self._remote_origin = remote_origin - self._proxy_auth = proxy_auth - self._ssl_context = ssl_context - self._keepalive_expiry = keepalive_expiry - self._http1 = http1 - self._http2 = http2 - - self._network_backend: NetworkBackend = ( - SyncBackend() if network_backend is None else network_backend - ) - self._connect_lock = Lock() - self._connection: ConnectionInterface | None = None - self._connect_failed = False - - def handle_request(self, request: Request) -> Response: - timeouts = request.extensions.get("timeout", {}) - sni_hostname = request.extensions.get("sni_hostname", None) - timeout = timeouts.get("connect", None) - - with self._connect_lock: - if self._connection is None: - try: - # Connect to the proxy - kwargs = { - "host": self._proxy_origin.host.decode("ascii"), - "port": self._proxy_origin.port, - "timeout": timeout, - } - with Trace("connect_tcp", logger, request, kwargs) as trace: - stream = self._network_backend.connect_tcp(**kwargs) - trace.return_value = stream - - # Connect to the remote host using socks5 - kwargs = { - "stream": stream, - "host": self._remote_origin.host.decode("ascii"), - "port": self._remote_origin.port, - "auth": self._proxy_auth, - } - with Trace( - "setup_socks5_connection", logger, request, kwargs - ) as trace: - _init_socks5_connection(**kwargs) - trace.return_value = stream - - # Upgrade the stream to SSL - if self._remote_origin.scheme == b"https": - ssl_context = ( - default_ssl_context() - if self._ssl_context is None - else self._ssl_context - ) - alpn_protocols = ( - ["http/1.1", "h2"] if self._http2 else ["http/1.1"] - ) - ssl_context.set_alpn_protocols(alpn_protocols) - - kwargs = { - "ssl_context": ssl_context, - "server_hostname": sni_hostname - or self._remote_origin.host.decode("ascii"), - "timeout": timeout, - } - with Trace("start_tls", logger, request, kwargs) as trace: - stream = stream.start_tls(**kwargs) - trace.return_value = stream - - # Determine if we should be using HTTP/1.1 or HTTP/2 - ssl_object = stream.get_extra_info("ssl_object") - http2_negotiated = ( - ssl_object is not None - and ssl_object.selected_alpn_protocol() == "h2" - ) - - # Create the HTTP/1.1 or HTTP/2 connection - if http2_negotiated or ( - self._http2 and not self._http1 - ): # pragma: nocover - from .http2 import HTTP2Connection - - self._connection = HTTP2Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - else: - self._connection = HTTP11Connection( - origin=self._remote_origin, - stream=stream, - keepalive_expiry=self._keepalive_expiry, - ) - except Exception as exc: - self._connect_failed = True - raise exc - elif not self._connection.is_available(): # pragma: nocover - raise ConnectionNotAvailable() - - return self._connection.handle_request(request) - - def can_handle_request(self, origin: Origin) -> bool: - return origin == self._remote_origin - - def close(self) -> None: - if self._connection is not None: - self._connection.close() - - def is_available(self) -> bool: - if self._connection is None: # pragma: nocover - # If HTTP/2 support is enabled, and the resulting connection could - # end up as HTTP/2 then we should indicate the connection as being - # available to service multiple requests. - return ( - self._http2 - and (self._remote_origin.scheme == b"https" or not self._http1) - and not self._connect_failed - ) - return self._connection.is_available() - - def has_expired(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.has_expired() - - def is_idle(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_idle() - - def is_closed(self) -> bool: - if self._connection is None: # pragma: nocover - return self._connect_failed - return self._connection.is_closed() - - def info(self) -> str: - if self._connection is None: # pragma: nocover - return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" - return self._connection.info() - - def __repr__(self) -> str: - return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_synchronization.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_synchronization.py deleted file mode 100644 index 2ecc9e9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_synchronization.py +++ /dev/null @@ -1,318 +0,0 @@ -from __future__ import annotations - -import threading -import types - -from ._exceptions import ExceptionMapping, PoolTimeout, map_exceptions - -# Our async synchronization primatives use either 'anyio' or 'trio' depending -# on if they're running under asyncio or trio. - -try: - import trio -except (ImportError, NotImplementedError): # pragma: nocover - trio = None # type: ignore - -try: - import anyio -except ImportError: # pragma: nocover - anyio = None # type: ignore - - -def current_async_library() -> str: - # Determine if we're running under trio or asyncio. - # See https://sniffio.readthedocs.io/en/latest/ - try: - import sniffio - except ImportError: # pragma: nocover - environment = "asyncio" - else: - environment = sniffio.current_async_library() - - if environment not in ("asyncio", "trio"): # pragma: nocover - raise RuntimeError("Running under an unsupported async environment.") - - if environment == "asyncio" and anyio is None: # pragma: nocover - raise RuntimeError( - "Running with asyncio requires installation of 'httpcore[asyncio]'." - ) - - if environment == "trio" and trio is None: # pragma: nocover - raise RuntimeError( - "Running with trio requires installation of 'httpcore[trio]'." - ) - - return environment - - -class AsyncLock: - """ - This is a standard lock. - - In the sync case `Lock` provides thread locking. - In the async case `AsyncLock` provides async locking. - """ - - def __init__(self) -> None: - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a lock with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_lock = trio.Lock() - elif self._backend == "asyncio": - self._anyio_lock = anyio.Lock() - - async def __aenter__(self) -> AsyncLock: - if not self._backend: - self.setup() - - if self._backend == "trio": - await self._trio_lock.acquire() - elif self._backend == "asyncio": - await self._anyio_lock.acquire() - - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self._backend == "trio": - self._trio_lock.release() - elif self._backend == "asyncio": - self._anyio_lock.release() - - -class AsyncThreadLock: - """ - This is a threading-only lock for no-I/O contexts. - - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. - """ - - def __enter__(self) -> AsyncThreadLock: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - pass - - -class AsyncEvent: - def __init__(self) -> None: - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a lock with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_event = trio.Event() - elif self._backend == "asyncio": - self._anyio_event = anyio.Event() - - def set(self) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - self._trio_event.set() - elif self._backend == "asyncio": - self._anyio_event.set() - - async def wait(self, timeout: float | None = None) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout} - timeout_or_inf = float("inf") if timeout is None else timeout - with map_exceptions(trio_exc_map): - with trio.fail_after(timeout_or_inf): - await self._trio_event.wait() - elif self._backend == "asyncio": - anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout} - with map_exceptions(anyio_exc_map): - with anyio.fail_after(timeout): - await self._anyio_event.wait() - - -class AsyncSemaphore: - def __init__(self, bound: int) -> None: - self._bound = bound - self._backend = "" - - def setup(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a semaphore with the correct implementation. - """ - self._backend = current_async_library() - if self._backend == "trio": - self._trio_semaphore = trio.Semaphore( - initial_value=self._bound, max_value=self._bound - ) - elif self._backend == "asyncio": - self._anyio_semaphore = anyio.Semaphore( - initial_value=self._bound, max_value=self._bound - ) - - async def acquire(self) -> None: - if not self._backend: - self.setup() - - if self._backend == "trio": - await self._trio_semaphore.acquire() - elif self._backend == "asyncio": - await self._anyio_semaphore.acquire() - - async def release(self) -> None: - if self._backend == "trio": - self._trio_semaphore.release() - elif self._backend == "asyncio": - self._anyio_semaphore.release() - - -class AsyncShieldCancellation: - # For certain portions of our codebase where we're dealing with - # closing connections during exception handling we want to shield - # the operation from being cancelled. - # - # with AsyncShieldCancellation(): - # ... # clean-up operations, shielded from cancellation. - - def __init__(self) -> None: - """ - Detect if we're running under 'asyncio' or 'trio' and create - a shielded scope with the correct implementation. - """ - self._backend = current_async_library() - - if self._backend == "trio": - self._trio_shield = trio.CancelScope(shield=True) - elif self._backend == "asyncio": - self._anyio_shield = anyio.CancelScope(shield=True) - - def __enter__(self) -> AsyncShieldCancellation: - if self._backend == "trio": - self._trio_shield.__enter__() - elif self._backend == "asyncio": - self._anyio_shield.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self._backend == "trio": - self._trio_shield.__exit__(exc_type, exc_value, traceback) - elif self._backend == "asyncio": - self._anyio_shield.__exit__(exc_type, exc_value, traceback) - - -# Our thread-based synchronization primitives... - - -class Lock: - """ - This is a standard lock. - - In the sync case `Lock` provides thread locking. - In the async case `AsyncLock` provides async locking. - """ - - def __init__(self) -> None: - self._lock = threading.Lock() - - def __enter__(self) -> Lock: - self._lock.acquire() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self._lock.release() - - -class ThreadLock: - """ - This is a threading-only lock for no-I/O contexts. - - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. - """ - - def __init__(self) -> None: - self._lock = threading.Lock() - - def __enter__(self) -> ThreadLock: - self._lock.acquire() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - self._lock.release() - - -class Event: - def __init__(self) -> None: - self._event = threading.Event() - - def set(self) -> None: - self._event.set() - - def wait(self, timeout: float | None = None) -> None: - if timeout == float("inf"): # pragma: no cover - timeout = None - if not self._event.wait(timeout=timeout): - raise PoolTimeout() # pragma: nocover - - -class Semaphore: - def __init__(self, bound: int) -> None: - self._semaphore = threading.Semaphore(value=bound) - - def acquire(self) -> None: - self._semaphore.acquire() - - def release(self) -> None: - self._semaphore.release() - - -class ShieldCancellation: - # Thread-synchronous codebases don't support cancellation semantics. - # We have this class because we need to mirror the async and sync - # cases within our package, but it's just a no-op. - def __enter__(self) -> ShieldCancellation: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_trace.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_trace.py deleted file mode 100644 index 5f1cd7c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_trace.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import inspect -import logging -import types -import typing - -from ._models import Request - - -class Trace: - def __init__( - self, - name: str, - logger: logging.Logger, - request: Request | None = None, - kwargs: dict[str, typing.Any] | None = None, - ) -> None: - self.name = name - self.logger = logger - self.trace_extension = ( - None if request is None else request.extensions.get("trace") - ) - self.debug = self.logger.isEnabledFor(logging.DEBUG) - self.kwargs = kwargs or {} - self.return_value: typing.Any = None - self.should_trace = self.debug or self.trace_extension is not None - self.prefix = self.logger.name.split(".")[-1] - - def trace(self, name: str, info: dict[str, typing.Any]) -> None: - if self.trace_extension is not None: - prefix_and_name = f"{self.prefix}.{name}" - ret = self.trace_extension(prefix_and_name, info) - if inspect.iscoroutine(ret): # pragma: no cover - raise TypeError( - "If you are using a synchronous interface, " - "the callback of the `trace` extension should " - "be a normal function instead of an asynchronous function." - ) - - if self.debug: - if not info or "return_value" in info and info["return_value"] is None: - message = name - else: - args = " ".join([f"{key}={value!r}" for key, value in info.items()]) - message = f"{name} {args}" - self.logger.debug(message) - - def __enter__(self) -> Trace: - if self.should_trace: - info = self.kwargs - self.trace(f"{self.name}.started", info) - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self.should_trace: - if exc_value is None: - info = {"return_value": self.return_value} - self.trace(f"{self.name}.complete", info) - else: - info = {"exception": exc_value} - self.trace(f"{self.name}.failed", info) - - async def atrace(self, name: str, info: dict[str, typing.Any]) -> None: - if self.trace_extension is not None: - prefix_and_name = f"{self.prefix}.{name}" - coro = self.trace_extension(prefix_and_name, info) - if not inspect.iscoroutine(coro): # pragma: no cover - raise TypeError( - "If you're using an asynchronous interface, " - "the callback of the `trace` extension should " - "be an asynchronous function rather than a normal function." - ) - await coro - - if self.debug: - if not info or "return_value" in info and info["return_value"] is None: - message = name - else: - args = " ".join([f"{key}={value!r}" for key, value in info.items()]) - message = f"{name} {args}" - self.logger.debug(message) - - async def __aenter__(self) -> Trace: - if self.should_trace: - info = self.kwargs - await self.atrace(f"{self.name}.started", info) - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: types.TracebackType | None = None, - ) -> None: - if self.should_trace: - if exc_value is None: - info = {"return_value": self.return_value} - await self.atrace(f"{self.name}.complete", info) - else: - info = {"exception": exc_value} - await self.atrace(f"{self.name}.failed", info) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/_utils.py b/backend/venv39/lib/python3.9/site-packages/httpcore/_utils.py deleted file mode 100644 index c44ff93..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpcore/_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -import select -import socket -import sys - - -def is_socket_readable(sock: socket.socket | None) -> bool: - """ - Return whether a socket, as identifed by its file descriptor, is readable. - "A socket is readable" means that the read buffer isn't empty, i.e. that calling - .recv() on it would immediately return some data. - """ - # NOTE: we want check for readability without actually attempting to read, because - # we don't want to block forever if it's not readable. - - # In the case that the socket no longer exists, or cannot return a file - # descriptor, we treat it as being readable, as if it the next read operation - # on it is ready to return the terminating `b""`. - sock_fd = None if sock is None else sock.fileno() - if sock_fd is None or sock_fd < 0: # pragma: nocover - return True - - # The implementation below was stolen from: - # https://github.com/python-trio/trio/blob/20ee2b1b7376db637435d80e266212a35837ddcc/trio/_socket.py#L471-L478 - # See also: https://github.com/encode/httpcore/pull/193#issuecomment-703129316 - - # Use select.select on Windows, and when poll is unavailable and select.poll - # everywhere else. (E.g. When eventlet is in use. See #327) - if ( - sys.platform == "win32" or getattr(select, "poll", None) is None - ): # pragma: nocover - rready, _, _ = select.select([sock_fd], [], [], 0) - return bool(rready) - p = select.poll() - p.register(sock_fd, select.POLLIN) - return bool(p.poll(0)) diff --git a/backend/venv39/lib/python3.9/site-packages/httpcore/py.typed b/backend/venv39/lib/python3.9/site-packages/httpcore/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/METADATA deleted file mode 100644 index b0d2b19..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/METADATA +++ /dev/null @@ -1,203 +0,0 @@ -Metadata-Version: 2.3 -Name: httpx -Version: 0.28.1 -Summary: The next generation HTTP client. -Project-URL: Changelog, https://github.com/encode/httpx/blob/master/CHANGELOG.md -Project-URL: Documentation, https://www.python-httpx.org -Project-URL: Homepage, https://github.com/encode/httpx -Project-URL: Source, https://github.com/encode/httpx -Author-email: Tom Christie -License: BSD-3-Clause -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Web Environment -Classifier: Framework :: AsyncIO -Classifier: Framework :: Trio -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.8 -Requires-Dist: anyio -Requires-Dist: certifi -Requires-Dist: httpcore==1.* -Requires-Dist: idna -Provides-Extra: brotli -Requires-Dist: brotli; (platform_python_implementation == 'CPython') and extra == 'brotli' -Requires-Dist: brotlicffi; (platform_python_implementation != 'CPython') and extra == 'brotli' -Provides-Extra: cli -Requires-Dist: click==8.*; extra == 'cli' -Requires-Dist: pygments==2.*; extra == 'cli' -Requires-Dist: rich<14,>=10; extra == 'cli' -Provides-Extra: http2 -Requires-Dist: h2<5,>=3; extra == 'http2' -Provides-Extra: socks -Requires-Dist: socksio==1.*; extra == 'socks' -Provides-Extra: zstd -Requires-Dist: zstandard>=0.18.0; extra == 'zstd' -Description-Content-Type: text/markdown - -

    - HTTPX -

    - -

    HTTPX - A next-generation HTTP client for Python.

    - -

    - - Test Suite - - - Package version - -

    - -HTTPX is a fully featured HTTP client library for Python 3. It includes **an integrated command line client**, has support for both **HTTP/1.1 and HTTP/2**, and provides both **sync and async APIs**. - ---- - -Install HTTPX using pip: - -```shell -$ pip install httpx -``` - -Now, let's get started: - -```pycon ->>> import httpx ->>> r = httpx.get('https://www.example.org/') ->>> r - ->>> r.status_code -200 ->>> r.headers['content-type'] -'text/html; charset=UTF-8' ->>> r.text -'\n\n\nExample Domain...' -``` - -Or, using the command-line client. - -```shell -$ pip install 'httpx[cli]' # The command line client is an optional dependency. -``` - -Which now allows us to use HTTPX directly from the command-line... - -

    - httpx --help -

    - -Sending a request... - -

    - httpx http://httpbin.org/json -

    - -## Features - -HTTPX builds on the well-established usability of `requests`, and gives you: - -* A broadly [requests-compatible API](https://www.python-httpx.org/compatibility/). -* An integrated command-line client. -* HTTP/1.1 [and HTTP/2 support](https://www.python-httpx.org/http2/). -* Standard synchronous interface, but with [async support if you need it](https://www.python-httpx.org/async/). -* Ability to make requests directly to [WSGI applications](https://www.python-httpx.org/advanced/transports/#wsgi-transport) or [ASGI applications](https://www.python-httpx.org/advanced/transports/#asgi-transport). -* Strict timeouts everywhere. -* Fully type annotated. -* 100% test coverage. - -Plus all the standard features of `requests`... - -* International Domains and URLs -* Keep-Alive & Connection Pooling -* Sessions with Cookie Persistence -* Browser-style SSL Verification -* Basic/Digest Authentication -* Elegant Key/Value Cookies -* Automatic Decompression -* Automatic Content Decoding -* Unicode Response Bodies -* Multipart File Uploads -* HTTP(S) Proxy Support -* Connection Timeouts -* Streaming Downloads -* .netrc Support -* Chunked Requests - -## Installation - -Install with pip: - -```shell -$ pip install httpx -``` - -Or, to include the optional HTTP/2 support, use: - -```shell -$ pip install httpx[http2] -``` - -HTTPX requires Python 3.8+. - -## Documentation - -Project documentation is available at [https://www.python-httpx.org/](https://www.python-httpx.org/). - -For a run-through of all the basics, head over to the [QuickStart](https://www.python-httpx.org/quickstart/). - -For more advanced topics, see the [Advanced Usage](https://www.python-httpx.org/advanced/) section, the [async support](https://www.python-httpx.org/async/) section, or the [HTTP/2](https://www.python-httpx.org/http2/) section. - -The [Developer Interface](https://www.python-httpx.org/api/) provides a comprehensive API reference. - -To find out about tools that integrate with HTTPX, see [Third Party Packages](https://www.python-httpx.org/third_party_packages/). - -## Contribute - -If you want to contribute with HTTPX check out the [Contributing Guide](https://www.python-httpx.org/contributing/) to learn how to start. - -## Dependencies - -The HTTPX project relies on these excellent libraries: - -* `httpcore` - The underlying transport implementation for `httpx`. - * `h11` - HTTP/1.1 support. -* `certifi` - SSL certificates. -* `idna` - Internationalized domain name support. -* `sniffio` - Async library autodetection. - -As well as these optional installs: - -* `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)* -* `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)* -* `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)* -* `click` - Command line client support. *(Optional, with `httpx[cli]`)* -* `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx[brotli]`)* -* `zstandard` - Decoding for "zstd" compressed responses. *(Optional, with `httpx[zstd]`)* - -A huge amount of credit is due to `requests` for the API layout that -much of this work follows, as well as to `urllib3` for plenty of design -inspiration around the lower-level networking details. - ---- - -

    HTTPX is BSD licensed code.
    Designed & crafted with care.

    — 🦋 —

    - -## Release Information - -### Fixed - -* Reintroduced supposedly-private `URLTypes` shortcut. (#2673) - - ---- - -[Full changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/RECORD deleted file mode 100644 index 9e773c4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/RECORD +++ /dev/null @@ -1,55 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/__version__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_auth.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_client.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_decoders.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_main.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_multipart.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_status_codes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/asgi.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/default.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/mock.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_transports/wsgi.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_urlparse.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_urls.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/httpx/_utils.cpython-39.pyc,, -../../../bin/httpx,sha256=ArawVMqMB6jkmK5R4dLLMprDVvV0shJWXz1y0QFP1bo,258 -httpx-0.28.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -httpx-0.28.1.dist-info/METADATA,sha256=_rubD48-gNV8gZnDBPNcQzboWB0dGNeYPJJ2a4J5OyU,7052 -httpx-0.28.1.dist-info/RECORD,, -httpx-0.28.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -httpx-0.28.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87 -httpx-0.28.1.dist-info/entry_points.txt,sha256=2lVkdQmxLA1pNMgSN2eV89o90HCZezhmNwsy6ryKDSA,37 -httpx-0.28.1.dist-info/licenses/LICENSE.md,sha256=TsWdVE8StfU5o6cW_TIaxYzNgDC0ZSIfLIgCAM3yjY0,1508 -httpx/__init__.py,sha256=CsaZe6yZj0rHg6322AWKWHGTMVr9txgEfD5P3_Rrz60,2171 -httpx/__version__.py,sha256=LoUyYeOXTieGzuP_64UL0wxdtxjuu_QbOvE7NOg-IqU,108 -httpx/_api.py,sha256=r_Zgs4jIpcPJLqK5dbbSayqo_iVMKFaxZCd-oOHxLEs,11743 -httpx/_auth.py,sha256=Yr3QwaUSK17rGYx-7j-FdicFIzz4Y9FFV-1F4-7RXX4,11891 -httpx/_client.py,sha256=xD-UG67-WMkeltAAOeGGj-cZ2RRTAm19sWRxlFY7_40,65714 -httpx/_config.py,sha256=pPp2U-wicfcKsF-KYRE1LYdt3e6ERGeIoXZ8Gjo3LWc,8547 -httpx/_content.py,sha256=LGGzrJTR3OvN4Mb1GVVNLXkXJH-6oKlwAttO9p5w_yg,8161 -httpx/_decoders.py,sha256=p0dX8I0NEHexs3UGp4SsZutiMhsXrrWl6-GnqVb0iKM,12041 -httpx/_exceptions.py,sha256=bxW7fxzgVMAdNTbwT0Vnq04gJDW1_gI_GFiQPuMyjL0,8527 -httpx/_main.py,sha256=Cg9GMabiTT_swaDfUgIRitSwxLRMSwUDOm7LdSGqlA4,15626 -httpx/_models.py,sha256=4__Guyv1gLxuZChwim8kfQNiIOcJ9acreFOSurvZfms,44700 -httpx/_multipart.py,sha256=KOHEZZl6oohg9mPaKyyu345qq1rJLg35TUG3YAzXB3Y,9843 -httpx/_status_codes.py,sha256=DYn-2ufBgMeXy5s8x3_TB7wjAuAAMewTakPrm5rXEsc,5639 -httpx/_transports/__init__.py,sha256=GbUoBSAOp7z-l-9j5YhMhR3DMIcn6FVLhj072O3Nnno,275 -httpx/_transports/asgi.py,sha256=HRfiDYMPt4wQH2gFgHZg4c-i3sblo6bL5GTqcET-xz8,5501 -httpx/_transports/base.py,sha256=kZS_VMbViYfF570pogUCJ1bulz-ybfL51Pqs9yktebU,2523 -httpx/_transports/default.py,sha256=AzeaRUyVwCccTyyNJexDf0n1dFfzzydpdIQgvw7PLnk,13983 -httpx/_transports/mock.py,sha256=PTo0d567RITXxGrki6kN7_67wwAxfwiMDcuXJiZCjEo,1232 -httpx/_transports/wsgi.py,sha256=NcPX3Xap_EwCFZWO_OaSyQNuInCYx1QMNbO8GAei6jY,4825 -httpx/_types.py,sha256=Jyh41GQq7AOev8IOWKDAg7zCbvHAfufmW5g_PiTtErY,2965 -httpx/_urlparse.py,sha256=ZAmH47ONfkxrrj-PPYhGeiHjb6AjKCS-ANWIN4OL_KY,18546 -httpx/_urls.py,sha256=dX99VR1DSOHpgo9Aq7PzYO4FKdxqKjwyNp8grf8dHN0,21550 -httpx/_utils.py,sha256=_TVeqAKvxJkKHdz7dFeb4s0LZqQXgeFkXSgfiHBK_1o,8285 -httpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/WHEEL deleted file mode 100644 index 21aaa72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.26.3 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/entry_points.txt deleted file mode 100644 index 8ae9600..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -httpx = httpx:main diff --git a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md b/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md deleted file mode 100644 index ab79d16..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,12 +0,0 @@ -Copyright © 2019, [Encode OSS Ltd](https://www.encode.io/). -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpx/__init__.py deleted file mode 100644 index e9addde..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/__init__.py +++ /dev/null @@ -1,105 +0,0 @@ -from .__version__ import __description__, __title__, __version__ -from ._api import * -from ._auth import * -from ._client import * -from ._config import * -from ._content import * -from ._exceptions import * -from ._models import * -from ._status_codes import * -from ._transports import * -from ._types import * -from ._urls import * - -try: - from ._main import main -except ImportError: # pragma: no cover - - def main() -> None: # type: ignore - import sys - - print( - "The httpx command line client could not run because the required " - "dependencies were not installed.\nMake sure you've installed " - "everything with: pip install 'httpx[cli]'" - ) - sys.exit(1) - - -__all__ = [ - "__description__", - "__title__", - "__version__", - "ASGITransport", - "AsyncBaseTransport", - "AsyncByteStream", - "AsyncClient", - "AsyncHTTPTransport", - "Auth", - "BaseTransport", - "BasicAuth", - "ByteStream", - "Client", - "CloseError", - "codes", - "ConnectError", - "ConnectTimeout", - "CookieConflict", - "Cookies", - "create_ssl_context", - "DecodingError", - "delete", - "DigestAuth", - "get", - "head", - "Headers", - "HTTPError", - "HTTPStatusError", - "HTTPTransport", - "InvalidURL", - "Limits", - "LocalProtocolError", - "main", - "MockTransport", - "NetRCAuth", - "NetworkError", - "options", - "patch", - "PoolTimeout", - "post", - "ProtocolError", - "Proxy", - "ProxyError", - "put", - "QueryParams", - "ReadError", - "ReadTimeout", - "RemoteProtocolError", - "request", - "Request", - "RequestError", - "RequestNotRead", - "Response", - "ResponseNotRead", - "stream", - "StreamClosed", - "StreamConsumed", - "StreamError", - "SyncByteStream", - "Timeout", - "TimeoutException", - "TooManyRedirects", - "TransportError", - "UnsupportedProtocol", - "URL", - "USE_CLIENT_DEFAULT", - "WriteError", - "WriteTimeout", - "WSGITransport", -] - - -__locals = locals() -for __name in __all__: - if not __name.startswith("__"): - setattr(__locals[__name], "__module__", "httpx") # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/__version__.py b/backend/venv39/lib/python3.9/site-packages/httpx/__version__.py deleted file mode 100644 index 801bfac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/__version__.py +++ /dev/null @@ -1,3 +0,0 @@ -__title__ = "httpx" -__description__ = "A next generation HTTP client, for Python 3." -__version__ = "0.28.1" diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_api.py b/backend/venv39/lib/python3.9/site-packages/httpx/_api.py deleted file mode 100644 index c3cda1e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_api.py +++ /dev/null @@ -1,438 +0,0 @@ -from __future__ import annotations - -import typing -from contextlib import contextmanager - -from ._client import Client -from ._config import DEFAULT_TIMEOUT_CONFIG -from ._models import Response -from ._types import ( - AuthTypes, - CookieTypes, - HeaderTypes, - ProxyTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestFiles, - TimeoutTypes, -) -from ._urls import URL - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - - -__all__ = [ - "delete", - "get", - "head", - "options", - "patch", - "post", - "put", - "request", - "stream", -] - - -def request( - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> Response: - """ - Sends an HTTP request. - - **Parameters:** - - * **method** - HTTP method for the new `Request` object: `GET`, `OPTIONS`, - `HEAD`, `POST`, `PUT`, `PATCH`, or `DELETE`. - * **url** - URL for the new `Request` object. - * **params** - *(optional)* Query parameters to include in the URL, as a - string, dictionary, or sequence of two-tuples. - * **content** - *(optional)* Binary content to include in the body of the - request, as bytes or a byte iterator. - * **data** - *(optional)* Form data to include in the body of the request, - as a dictionary. - * **files** - *(optional)* A dictionary of upload files to include in the - body of the request. - * **json** - *(optional)* A JSON serializable object to include in the body - of the request. - * **headers** - *(optional)* Dictionary of HTTP headers to include in the - request. - * **cookies** - *(optional)* Dictionary of Cookie items to include in the - request. - * **auth** - *(optional)* An authentication class to use when sending the - request. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - the request. - * **follow_redirects** - *(optional)* Enables or disables HTTP redirects. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - - **Returns:** `Response` - - Usage: - - ``` - >>> import httpx - >>> response = httpx.request('GET', 'https://httpbin.org/get') - >>> response - - ``` - """ - with Client( - cookies=cookies, - proxy=proxy, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) as client: - return client.request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - auth=auth, - follow_redirects=follow_redirects, - ) - - -@contextmanager -def stream( - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> typing.Iterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - with Client( - cookies=cookies, - proxy=proxy, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) as client: - with client.stream( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - auth=auth, - follow_redirects=follow_redirects, - ) as response: - yield response - - -def get( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `GET` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `GET` requests should not include a request body. - """ - return request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def options( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `OPTIONS` requests should not include a request body. - """ - return request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def head( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `HEAD` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `HEAD` requests should not include a request body. - """ - return request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def post( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def put( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def patch( - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - verify: ssl.SSLContext | str | bool = True, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - trust_env: bool = True, -) -> Response: - """ - Sends a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) - - -def delete( - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | None = None, - proxy: ProxyTypes | None = None, - follow_redirects: bool = False, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - verify: ssl.SSLContext | str | bool = True, - trust_env: bool = True, -) -> Response: - """ - Sends a `DELETE` request. - - **Parameters**: See `httpx.request`. - - Note that the `data`, `files`, `json` and `content` parameters are not available - on this function, as `DELETE` requests should not include a request body. - """ - return request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - proxy=proxy, - follow_redirects=follow_redirects, - verify=verify, - timeout=timeout, - trust_env=trust_env, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_auth.py b/backend/venv39/lib/python3.9/site-packages/httpx/_auth.py deleted file mode 100644 index b03971a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_auth.py +++ /dev/null @@ -1,348 +0,0 @@ -from __future__ import annotations - -import hashlib -import os -import re -import time -import typing -from base64 import b64encode -from urllib.request import parse_http_list - -from ._exceptions import ProtocolError -from ._models import Cookies, Request, Response -from ._utils import to_bytes, to_str, unquote - -if typing.TYPE_CHECKING: # pragma: no cover - from hashlib import _Hash - - -__all__ = ["Auth", "BasicAuth", "DigestAuth", "NetRCAuth"] - - -class Auth: - """ - Base class for all authentication schemes. - - To implement a custom authentication scheme, subclass `Auth` and override - the `.auth_flow()` method. - - If the authentication scheme does I/O such as disk access or network calls, or uses - synchronization primitives such as locks, you should override `.sync_auth_flow()` - and/or `.async_auth_flow()` instead of `.auth_flow()` to provide specialized - implementations that will be used by `Client` and `AsyncClient` respectively. - """ - - requires_request_body = False - requires_response_body = False - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - """ - Execute the authentication flow. - - To dispatch a request, `yield` it: - - ``` - yield request - ``` - - The client will `.send()` the response back into the flow generator. You can - access it like so: - - ``` - response = yield request - ``` - - A `return` (or reaching the end of the generator) will result in the - client returning the last response obtained from the server. - - You can dispatch as many requests as is necessary. - """ - yield request - - def sync_auth_flow( - self, request: Request - ) -> typing.Generator[Request, Response, None]: - """ - Execute the authentication flow synchronously. - - By default, this defers to `.auth_flow()`. You should override this method - when the authentication scheme does I/O and/or uses concurrency primitives. - """ - if self.requires_request_body: - request.read() - - flow = self.auth_flow(request) - request = next(flow) - - while True: - response = yield request - if self.requires_response_body: - response.read() - - try: - request = flow.send(response) - except StopIteration: - break - - async def async_auth_flow( - self, request: Request - ) -> typing.AsyncGenerator[Request, Response]: - """ - Execute the authentication flow asynchronously. - - By default, this defers to `.auth_flow()`. You should override this method - when the authentication scheme does I/O and/or uses concurrency primitives. - """ - if self.requires_request_body: - await request.aread() - - flow = self.auth_flow(request) - request = next(flow) - - while True: - response = yield request - if self.requires_response_body: - await response.aread() - - try: - request = flow.send(response) - except StopIteration: - break - - -class FunctionAuth(Auth): - """ - Allows the 'auth' argument to be passed as a simple callable function, - that takes the request, and returns a new, modified request. - """ - - def __init__(self, func: typing.Callable[[Request], Request]) -> None: - self._func = func - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - yield self._func(request) - - -class BasicAuth(Auth): - """ - Allows the 'auth' argument to be passed as a (username, password) pair, - and uses HTTP Basic authentication. - """ - - def __init__(self, username: str | bytes, password: str | bytes) -> None: - self._auth_header = self._build_auth_header(username, password) - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - request.headers["Authorization"] = self._auth_header - yield request - - def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: - userpass = b":".join((to_bytes(username), to_bytes(password))) - token = b64encode(userpass).decode() - return f"Basic {token}" - - -class NetRCAuth(Auth): - """ - Use a 'netrc' file to lookup basic auth credentials based on the url host. - """ - - def __init__(self, file: str | None = None) -> None: - # Lazily import 'netrc'. - # There's no need for us to load this module unless 'NetRCAuth' is being used. - import netrc - - self._netrc_info = netrc.netrc(file) - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - auth_info = self._netrc_info.authenticators(request.url.host) - if auth_info is None or not auth_info[2]: - # The netrc file did not have authentication credentials for this host. - yield request - else: - # Build a basic auth header with credentials from the netrc file. - request.headers["Authorization"] = self._build_auth_header( - username=auth_info[0], password=auth_info[2] - ) - yield request - - def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: - userpass = b":".join((to_bytes(username), to_bytes(password))) - token = b64encode(userpass).decode() - return f"Basic {token}" - - -class DigestAuth(Auth): - _ALGORITHM_TO_HASH_FUNCTION: dict[str, typing.Callable[[bytes], _Hash]] = { - "MD5": hashlib.md5, - "MD5-SESS": hashlib.md5, - "SHA": hashlib.sha1, - "SHA-SESS": hashlib.sha1, - "SHA-256": hashlib.sha256, - "SHA-256-SESS": hashlib.sha256, - "SHA-512": hashlib.sha512, - "SHA-512-SESS": hashlib.sha512, - } - - def __init__(self, username: str | bytes, password: str | bytes) -> None: - self._username = to_bytes(username) - self._password = to_bytes(password) - self._last_challenge: _DigestAuthChallenge | None = None - self._nonce_count = 1 - - def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: - if self._last_challenge: - request.headers["Authorization"] = self._build_auth_header( - request, self._last_challenge - ) - - response = yield request - - if response.status_code != 401 or "www-authenticate" not in response.headers: - # If the response is not a 401 then we don't - # need to build an authenticated request. - return - - for auth_header in response.headers.get_list("www-authenticate"): - if auth_header.lower().startswith("digest "): - break - else: - # If the response does not include a 'WWW-Authenticate: Digest ...' - # header, then we don't need to build an authenticated request. - return - - self._last_challenge = self._parse_challenge(request, response, auth_header) - self._nonce_count = 1 - - request.headers["Authorization"] = self._build_auth_header( - request, self._last_challenge - ) - if response.cookies: - Cookies(response.cookies).set_cookie_header(request=request) - yield request - - def _parse_challenge( - self, request: Request, response: Response, auth_header: str - ) -> _DigestAuthChallenge: - """ - Returns a challenge from a Digest WWW-Authenticate header. - These take the form of: - `Digest realm="realm@host.com",qop="auth,auth-int",nonce="abc",opaque="xyz"` - """ - scheme, _, fields = auth_header.partition(" ") - - # This method should only ever have been called with a Digest auth header. - assert scheme.lower() == "digest" - - header_dict: dict[str, str] = {} - for field in parse_http_list(fields): - key, value = field.strip().split("=", 1) - header_dict[key] = unquote(value) - - try: - realm = header_dict["realm"].encode() - nonce = header_dict["nonce"].encode() - algorithm = header_dict.get("algorithm", "MD5") - opaque = header_dict["opaque"].encode() if "opaque" in header_dict else None - qop = header_dict["qop"].encode() if "qop" in header_dict else None - return _DigestAuthChallenge( - realm=realm, nonce=nonce, algorithm=algorithm, opaque=opaque, qop=qop - ) - except KeyError as exc: - message = "Malformed Digest WWW-Authenticate header" - raise ProtocolError(message, request=request) from exc - - def _build_auth_header( - self, request: Request, challenge: _DigestAuthChallenge - ) -> str: - hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()] - - def digest(data: bytes) -> bytes: - return hash_func(data).hexdigest().encode() - - A1 = b":".join((self._username, challenge.realm, self._password)) - - path = request.url.raw_path - A2 = b":".join((request.method.encode(), path)) - # TODO: implement auth-int - HA2 = digest(A2) - - nc_value = b"%08x" % self._nonce_count - cnonce = self._get_client_nonce(self._nonce_count, challenge.nonce) - self._nonce_count += 1 - - HA1 = digest(A1) - if challenge.algorithm.lower().endswith("-sess"): - HA1 = digest(b":".join((HA1, challenge.nonce, cnonce))) - - qop = self._resolve_qop(challenge.qop, request=request) - if qop is None: - # Following RFC 2069 - digest_data = [HA1, challenge.nonce, HA2] - else: - # Following RFC 2617/7616 - digest_data = [HA1, challenge.nonce, nc_value, cnonce, qop, HA2] - - format_args = { - "username": self._username, - "realm": challenge.realm, - "nonce": challenge.nonce, - "uri": path, - "response": digest(b":".join(digest_data)), - "algorithm": challenge.algorithm.encode(), - } - if challenge.opaque: - format_args["opaque"] = challenge.opaque - if qop: - format_args["qop"] = b"auth" - format_args["nc"] = nc_value - format_args["cnonce"] = cnonce - - return "Digest " + self._get_header_value(format_args) - - def _get_client_nonce(self, nonce_count: int, nonce: bytes) -> bytes: - s = str(nonce_count).encode() - s += nonce - s += time.ctime().encode() - s += os.urandom(8) - - return hashlib.sha1(s).hexdigest()[:16].encode() - - def _get_header_value(self, header_fields: dict[str, bytes]) -> str: - NON_QUOTED_FIELDS = ("algorithm", "qop", "nc") - QUOTED_TEMPLATE = '{}="{}"' - NON_QUOTED_TEMPLATE = "{}={}" - - header_value = "" - for i, (field, value) in enumerate(header_fields.items()): - if i > 0: - header_value += ", " - template = ( - QUOTED_TEMPLATE - if field not in NON_QUOTED_FIELDS - else NON_QUOTED_TEMPLATE - ) - header_value += template.format(field, to_str(value)) - - return header_value - - def _resolve_qop(self, qop: bytes | None, request: Request) -> bytes | None: - if qop is None: - return None - qops = re.split(b", ?", qop) - if b"auth" in qops: - return b"auth" - - if qops == [b"auth-int"]: - raise NotImplementedError("Digest auth-int support is not yet implemented") - - message = f'Unexpected qop value "{qop!r}" in digest auth' - raise ProtocolError(message, request=request) - - -class _DigestAuthChallenge(typing.NamedTuple): - realm: bytes - nonce: bytes - algorithm: str - opaque: bytes | None - qop: bytes | None diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_client.py b/backend/venv39/lib/python3.9/site-packages/httpx/_client.py deleted file mode 100644 index 2249231..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_client.py +++ /dev/null @@ -1,2019 +0,0 @@ -from __future__ import annotations - -import datetime -import enum -import logging -import time -import typing -import warnings -from contextlib import asynccontextmanager, contextmanager -from types import TracebackType - -from .__version__ import __version__ -from ._auth import Auth, BasicAuth, FunctionAuth -from ._config import ( - DEFAULT_LIMITS, - DEFAULT_MAX_REDIRECTS, - DEFAULT_TIMEOUT_CONFIG, - Limits, - Proxy, - Timeout, -) -from ._decoders import SUPPORTED_DECODERS -from ._exceptions import ( - InvalidURL, - RemoteProtocolError, - TooManyRedirects, - request_context, -) -from ._models import Cookies, Headers, Request, Response -from ._status_codes import codes -from ._transports.base import AsyncBaseTransport, BaseTransport -from ._transports.default import AsyncHTTPTransport, HTTPTransport -from ._types import ( - AsyncByteStream, - AuthTypes, - CertTypes, - CookieTypes, - HeaderTypes, - ProxyTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestExtensions, - RequestFiles, - SyncByteStream, - TimeoutTypes, -) -from ._urls import URL, QueryParams -from ._utils import URLPattern, get_environment_proxies - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - -__all__ = ["USE_CLIENT_DEFAULT", "AsyncClient", "Client"] - -# The type annotation for @classmethod and context managers here follows PEP 484 -# https://www.python.org/dev/peps/pep-0484/#annotating-instance-and-class-methods -T = typing.TypeVar("T", bound="Client") -U = typing.TypeVar("U", bound="AsyncClient") - - -def _is_https_redirect(url: URL, location: URL) -> bool: - """ - Return 'True' if 'location' is a HTTPS upgrade of 'url' - """ - if url.host != location.host: - return False - - return ( - url.scheme == "http" - and _port_or_default(url) == 80 - and location.scheme == "https" - and _port_or_default(location) == 443 - ) - - -def _port_or_default(url: URL) -> int | None: - if url.port is not None: - return url.port - return {"http": 80, "https": 443}.get(url.scheme) - - -def _same_origin(url: URL, other: URL) -> bool: - """ - Return 'True' if the given URLs share the same origin. - """ - return ( - url.scheme == other.scheme - and url.host == other.host - and _port_or_default(url) == _port_or_default(other) - ) - - -class UseClientDefault: - """ - For some parameters such as `auth=...` and `timeout=...` we need to be able - to indicate the default "unset" state, in a way that is distinctly different - to using `None`. - - The default "unset" state indicates that whatever default is set on the - client should be used. This is different to setting `None`, which - explicitly disables the parameter, possibly overriding a client default. - - For example we use `timeout=USE_CLIENT_DEFAULT` in the `request()` signature. - Omitting the `timeout` parameter will send a request using whatever default - timeout has been configured on the client. Including `timeout=None` will - ensure no timeout is used. - - Note that user code shouldn't need to use the `USE_CLIENT_DEFAULT` constant, - but it is used internally when a parameter is not included. - """ - - -USE_CLIENT_DEFAULT = UseClientDefault() - - -logger = logging.getLogger("httpx") - -USER_AGENT = f"python-httpx/{__version__}" -ACCEPT_ENCODING = ", ".join( - [key for key in SUPPORTED_DECODERS.keys() if key != "identity"] -) - - -class ClientState(enum.Enum): - # UNOPENED: - # The client has been instantiated, but has not been used to send a request, - # or been opened by entering the context of a `with` block. - UNOPENED = 1 - # OPENED: - # The client has either sent a request, or is within a `with` block. - OPENED = 2 - # CLOSED: - # The client has either exited the `with` block, or `close()` has - # been called explicitly. - CLOSED = 3 - - -class BoundSyncStream(SyncByteStream): - """ - A byte stream that is bound to a given response instance, and that - ensures the `response.elapsed` is set once the response is closed. - """ - - def __init__( - self, stream: SyncByteStream, response: Response, start: float - ) -> None: - self._stream = stream - self._response = response - self._start = start - - def __iter__(self) -> typing.Iterator[bytes]: - for chunk in self._stream: - yield chunk - - def close(self) -> None: - elapsed = time.perf_counter() - self._start - self._response.elapsed = datetime.timedelta(seconds=elapsed) - self._stream.close() - - -class BoundAsyncStream(AsyncByteStream): - """ - An async byte stream that is bound to a given response instance, and that - ensures the `response.elapsed` is set once the response is closed. - """ - - def __init__( - self, stream: AsyncByteStream, response: Response, start: float - ) -> None: - self._stream = stream - self._response = response - self._start = start - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - async for chunk in self._stream: - yield chunk - - async def aclose(self) -> None: - elapsed = time.perf_counter() - self._start - self._response.elapsed = datetime.timedelta(seconds=elapsed) - await self._stream.aclose() - - -EventHook = typing.Callable[..., typing.Any] - - -class BaseClient: - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - trust_env: bool = True, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - event_hooks = {} if event_hooks is None else event_hooks - - self._base_url = self._enforce_trailing_slash(URL(base_url)) - - self._auth = self._build_auth(auth) - self._params = QueryParams(params) - self.headers = Headers(headers) - self._cookies = Cookies(cookies) - self._timeout = Timeout(timeout) - self.follow_redirects = follow_redirects - self.max_redirects = max_redirects - self._event_hooks = { - "request": list(event_hooks.get("request", [])), - "response": list(event_hooks.get("response", [])), - } - self._trust_env = trust_env - self._default_encoding = default_encoding - self._state = ClientState.UNOPENED - - @property - def is_closed(self) -> bool: - """ - Check if the client being closed - """ - return self._state == ClientState.CLOSED - - @property - def trust_env(self) -> bool: - return self._trust_env - - def _enforce_trailing_slash(self, url: URL) -> URL: - if url.raw_path.endswith(b"/"): - return url - return url.copy_with(raw_path=url.raw_path + b"/") - - def _get_proxy_map( - self, proxy: ProxyTypes | None, allow_env_proxies: bool - ) -> dict[str, Proxy | None]: - if proxy is None: - if allow_env_proxies: - return { - key: None if url is None else Proxy(url=url) - for key, url in get_environment_proxies().items() - } - return {} - else: - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - return {"all://": proxy} - - @property - def timeout(self) -> Timeout: - return self._timeout - - @timeout.setter - def timeout(self, timeout: TimeoutTypes) -> None: - self._timeout = Timeout(timeout) - - @property - def event_hooks(self) -> dict[str, list[EventHook]]: - return self._event_hooks - - @event_hooks.setter - def event_hooks(self, event_hooks: dict[str, list[EventHook]]) -> None: - self._event_hooks = { - "request": list(event_hooks.get("request", [])), - "response": list(event_hooks.get("response", [])), - } - - @property - def auth(self) -> Auth | None: - """ - Authentication class used when none is passed at the request-level. - - See also [Authentication][0]. - - [0]: /quickstart/#authentication - """ - return self._auth - - @auth.setter - def auth(self, auth: AuthTypes) -> None: - self._auth = self._build_auth(auth) - - @property - def base_url(self) -> URL: - """ - Base URL to use when sending requests with relative URLs. - """ - return self._base_url - - @base_url.setter - def base_url(self, url: URL | str) -> None: - self._base_url = self._enforce_trailing_slash(URL(url)) - - @property - def headers(self) -> Headers: - """ - HTTP headers to include when sending requests. - """ - return self._headers - - @headers.setter - def headers(self, headers: HeaderTypes) -> None: - client_headers = Headers( - { - b"Accept": b"*/*", - b"Accept-Encoding": ACCEPT_ENCODING.encode("ascii"), - b"Connection": b"keep-alive", - b"User-Agent": USER_AGENT.encode("ascii"), - } - ) - client_headers.update(headers) - self._headers = client_headers - - @property - def cookies(self) -> Cookies: - """ - Cookie values to include when sending requests. - """ - return self._cookies - - @cookies.setter - def cookies(self, cookies: CookieTypes) -> None: - self._cookies = Cookies(cookies) - - @property - def params(self) -> QueryParams: - """ - Query parameters to include in the URL when sending requests. - """ - return self._params - - @params.setter - def params(self, params: QueryParamTypes) -> None: - self._params = QueryParams(params) - - def build_request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Request: - """ - Build and return a request instance. - - * The `params`, `headers` and `cookies` arguments - are merged with any values set on the client. - * The `url` argument is merged with any `base_url` set on the client. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - url = self._merge_url(url) - headers = self._merge_headers(headers) - cookies = self._merge_cookies(cookies) - params = self._merge_queryparams(params) - extensions = {} if extensions is None else extensions - if "timeout" not in extensions: - timeout = ( - self.timeout - if isinstance(timeout, UseClientDefault) - else Timeout(timeout) - ) - extensions = dict(**extensions, timeout=timeout.as_dict()) - return Request( - method, - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - extensions=extensions, - ) - - def _merge_url(self, url: URL | str) -> URL: - """ - Merge a URL argument together with any 'base_url' on the client, - to create the URL used for the outgoing request. - """ - merge_url = URL(url) - if merge_url.is_relative_url: - # To merge URLs we always append to the base URL. To get this - # behaviour correct we always ensure the base URL ends in a '/' - # separator, and strip any leading '/' from the merge URL. - # - # So, eg... - # - # >>> client = Client(base_url="https://www.example.com/subpath") - # >>> client.base_url - # URL('https://www.example.com/subpath/') - # >>> client.build_request("GET", "/path").url - # URL('https://www.example.com/subpath/path') - merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") - return self.base_url.copy_with(raw_path=merge_raw_path) - return merge_url - - def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None: - """ - Merge a cookies argument together with any cookies on the client, - to create the cookies used for the outgoing request. - """ - if cookies or self.cookies: - merged_cookies = Cookies(self.cookies) - merged_cookies.update(cookies) - return merged_cookies - return cookies - - def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None: - """ - Merge a headers argument together with any headers on the client, - to create the headers used for the outgoing request. - """ - merged_headers = Headers(self.headers) - merged_headers.update(headers) - return merged_headers - - def _merge_queryparams( - self, params: QueryParamTypes | None = None - ) -> QueryParamTypes | None: - """ - Merge a queryparams argument together with any queryparams on the client, - to create the queryparams used for the outgoing request. - """ - if params or self.params: - merged_queryparams = QueryParams(self.params) - return merged_queryparams.merge(params) - return params - - def _build_auth(self, auth: AuthTypes | None) -> Auth | None: - if auth is None: - return None - elif isinstance(auth, tuple): - return BasicAuth(username=auth[0], password=auth[1]) - elif isinstance(auth, Auth): - return auth - elif callable(auth): - return FunctionAuth(func=auth) - else: - raise TypeError(f'Invalid "auth" argument: {auth!r}') - - def _build_request_auth( - self, - request: Request, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - ) -> Auth: - auth = ( - self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth) - ) - - if auth is not None: - return auth - - username, password = request.url.username, request.url.password - if username or password: - return BasicAuth(username=username, password=password) - - return Auth() - - def _build_redirect_request(self, request: Request, response: Response) -> Request: - """ - Given a request and a redirect response, return a new request that - should be used to effect the redirect. - """ - method = self._redirect_method(request, response) - url = self._redirect_url(request, response) - headers = self._redirect_headers(request, url, method) - stream = self._redirect_stream(request, method) - cookies = Cookies(self.cookies) - return Request( - method=method, - url=url, - headers=headers, - cookies=cookies, - stream=stream, - extensions=request.extensions, - ) - - def _redirect_method(self, request: Request, response: Response) -> str: - """ - When being redirected we may want to change the method of the request - based on certain specs or browser behavior. - """ - method = request.method - - # https://tools.ietf.org/html/rfc7231#section-6.4.4 - if response.status_code == codes.SEE_OTHER and method != "HEAD": - method = "GET" - - # Do what the browsers do, despite standards... - # Turn 302s into GETs. - if response.status_code == codes.FOUND and method != "HEAD": - method = "GET" - - # If a POST is responded to with a 301, turn it into a GET. - # This bizarre behaviour is explained in 'requests' issue 1704. - if response.status_code == codes.MOVED_PERMANENTLY and method == "POST": - method = "GET" - - return method - - def _redirect_url(self, request: Request, response: Response) -> URL: - """ - Return the URL for the redirect to follow. - """ - location = response.headers["Location"] - - try: - url = URL(location) - except InvalidURL as exc: - raise RemoteProtocolError( - f"Invalid URL in location header: {exc}.", request=request - ) from None - - # Handle malformed 'Location' headers that are "absolute" form, have no host. - # See: https://github.com/encode/httpx/issues/771 - if url.scheme and not url.host: - url = url.copy_with(host=request.url.host) - - # Facilitate relative 'Location' headers, as allowed by RFC 7231. - # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') - if url.is_relative_url: - url = request.url.join(url) - - # Attach previous fragment if needed (RFC 7231 7.1.2) - if request.url.fragment and not url.fragment: - url = url.copy_with(fragment=request.url.fragment) - - return url - - def _redirect_headers(self, request: Request, url: URL, method: str) -> Headers: - """ - Return the headers that should be used for the redirect request. - """ - headers = Headers(request.headers) - - if not _same_origin(url, request.url): - if not _is_https_redirect(request.url, url): - # Strip Authorization headers when responses are redirected - # away from the origin. (Except for direct HTTP to HTTPS redirects.) - headers.pop("Authorization", None) - - # Update the Host header. - headers["Host"] = url.netloc.decode("ascii") - - if method != request.method and method == "GET": - # If we've switch to a 'GET' request, then strip any headers which - # are only relevant to the request body. - headers.pop("Content-Length", None) - headers.pop("Transfer-Encoding", None) - - # We should use the client cookie store to determine any cookie header, - # rather than whatever was on the original outgoing request. - headers.pop("Cookie", None) - - return headers - - def _redirect_stream( - self, request: Request, method: str - ) -> SyncByteStream | AsyncByteStream | None: - """ - Return the body that should be used for the redirect request. - """ - if method != request.method and method == "GET": - return None - - return request.stream - - def _set_timeout(self, request: Request) -> None: - if "timeout" not in request.extensions: - timeout = ( - self.timeout - if isinstance(self.timeout, UseClientDefault) - else Timeout(self.timeout) - ) - request.extensions = dict(**request.extensions, timeout=timeout.as_dict()) - - -class Client(BaseClient): - """ - An HTTP client, with connection pooling, HTTP/2, redirects, cookie persistence, etc. - - It can be shared between threads. - - Usage: - - ```python - >>> client = httpx.Client() - >>> response = client.get('https://example.org') - ``` - - **Parameters:** - - * **auth** - *(optional)* An authentication class to use when sending - requests. - * **params** - *(optional)* Query parameters to include in request URLs, as - a string, dictionary, or sequence of two-tuples. - * **headers** - *(optional)* Dictionary of HTTP headers to include when - sending requests. - * **cookies** - *(optional)* Dictionary of Cookie items to include when - sending requests. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be - enabled. Defaults to `False`. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - requests. - * **limits** - *(optional)* The limits configuration to use. - * **max_redirects** - *(optional)* The maximum number of redirect responses - that should be followed. - * **base_url** - *(optional)* A URL to use as the base when building - request URLs. - * **transport** - *(optional)* A transport class to use for sending requests - over the network. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - * **default_encoding** - *(optional)* The default encoding to use for decoding - response text, if no charset information is included in a response Content-Type - header. Set to a callable for automatic character set detection. Default: "utf-8". - """ - - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - proxy: ProxyTypes | None = None, - mounts: None | (typing.Mapping[str, BaseTransport | None]) = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - limits: Limits = DEFAULT_LIMITS, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - transport: BaseTransport | None = None, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - super().__init__( - auth=auth, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - follow_redirects=follow_redirects, - max_redirects=max_redirects, - event_hooks=event_hooks, - base_url=base_url, - trust_env=trust_env, - default_encoding=default_encoding, - ) - - if http2: - try: - import h2 # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using http2=True, but the 'h2' package is not installed. " - "Make sure to install httpx using `pip install httpx[http2]`." - ) from None - - allow_env_proxies = trust_env and transport is None - proxy_map = self._get_proxy_map(proxy, allow_env_proxies) - - self._transport = self._init_transport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - transport=transport, - ) - self._mounts: dict[URLPattern, BaseTransport | None] = { - URLPattern(key): None - if proxy is None - else self._init_proxy_transport( - proxy, - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - for key, proxy in proxy_map.items() - } - if mounts is not None: - self._mounts.update( - {URLPattern(key): transport for key, transport in mounts.items()} - ) - - self._mounts = dict(sorted(self._mounts.items())) - - def _init_transport( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - transport: BaseTransport | None = None, - ) -> BaseTransport: - if transport is not None: - return transport - - return HTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - - def _init_proxy_transport( - self, - proxy: Proxy, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - ) -> BaseTransport: - return HTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - proxy=proxy, - ) - - def _transport_for_url(self, url: URL) -> BaseTransport: - """ - Returns the transport instance that should be used for a given URL. - This will either be the standard connection pool, or a proxy. - """ - for pattern, transport in self._mounts.items(): - if pattern.matches(url): - return self._transport if transport is None else transport - - return self._transport - - def request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Build and send a request. - - Equivalent to: - - ```python - request = client.build_request(...) - response = client.send(request, ...) - ``` - - See `Client.build_request()`, `Client.send()` and - [Merging of configuration][0] for how the various parameters - are merged with client-level configuration. - - [0]: /advanced/clients/#merging-of-configuration - """ - if cookies is not None: - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning, stacklevel=2) - - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - return self.send(request, auth=auth, follow_redirects=follow_redirects) - - @contextmanager - def stream( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> typing.Iterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - response = self.send( - request=request, - auth=auth, - follow_redirects=follow_redirects, - stream=True, - ) - try: - yield response - finally: - response.close() - - def send( - self, - request: Request, - *, - stream: bool = False, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - ) -> Response: - """ - Send a request. - - The request is sent as-is, unmodified. - - Typically you'll want to build one with `Client.build_request()` - so that any client-level configuration is merged into the request, - but passing an explicit `httpx.Request()` is supported as well. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - if self._state == ClientState.CLOSED: - raise RuntimeError("Cannot send a request, as the client has been closed.") - - self._state = ClientState.OPENED - follow_redirects = ( - self.follow_redirects - if isinstance(follow_redirects, UseClientDefault) - else follow_redirects - ) - - self._set_timeout(request) - - auth = self._build_request_auth(request, auth) - - response = self._send_handling_auth( - request, - auth=auth, - follow_redirects=follow_redirects, - history=[], - ) - try: - if not stream: - response.read() - - return response - - except BaseException as exc: - response.close() - raise exc - - def _send_handling_auth( - self, - request: Request, - auth: Auth, - follow_redirects: bool, - history: list[Response], - ) -> Response: - auth_flow = auth.sync_auth_flow(request) - try: - request = next(auth_flow) - - while True: - response = self._send_handling_redirects( - request, - follow_redirects=follow_redirects, - history=history, - ) - try: - try: - next_request = auth_flow.send(response) - except StopIteration: - return response - - response.history = list(history) - response.read() - request = next_request - history.append(response) - - except BaseException as exc: - response.close() - raise exc - finally: - auth_flow.close() - - def _send_handling_redirects( - self, - request: Request, - follow_redirects: bool, - history: list[Response], - ) -> Response: - while True: - if len(history) > self.max_redirects: - raise TooManyRedirects( - "Exceeded maximum allowed redirects.", request=request - ) - - for hook in self._event_hooks["request"]: - hook(request) - - response = self._send_single_request(request) - try: - for hook in self._event_hooks["response"]: - hook(response) - response.history = list(history) - - if not response.has_redirect_location: - return response - - request = self._build_redirect_request(request, response) - history = history + [response] - - if follow_redirects: - response.read() - else: - response.next_request = request - return response - - except BaseException as exc: - response.close() - raise exc - - def _send_single_request(self, request: Request) -> Response: - """ - Sends a single request, without handling any redirections. - """ - transport = self._transport_for_url(request.url) - start = time.perf_counter() - - if not isinstance(request.stream, SyncByteStream): - raise RuntimeError( - "Attempted to send an async request with a sync Client instance." - ) - - with request_context(request=request): - response = transport.handle_request(request) - - assert isinstance(response.stream, SyncByteStream) - - response.request = request - response.stream = BoundSyncStream( - response.stream, response=response, start=start - ) - self.cookies.extract_cookies(response) - response.default_encoding = self._default_encoding - - logger.info( - 'HTTP Request: %s %s "%s %d %s"', - request.method, - request.url, - response.http_version, - response.status_code, - response.reason_phrase, - ) - - return response - - def get( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `GET` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def options( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def head( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `HEAD` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def post( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def put( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def patch( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def delete( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `DELETE` request. - - **Parameters**: See `httpx.request`. - """ - return self.request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - def close(self) -> None: - """ - Close transport and proxies. - """ - if self._state != ClientState.CLOSED: - self._state = ClientState.CLOSED - - self._transport.close() - for transport in self._mounts.values(): - if transport is not None: - transport.close() - - def __enter__(self: T) -> T: - if self._state != ClientState.UNOPENED: - msg = { - ClientState.OPENED: "Cannot open a client instance more than once.", - ClientState.CLOSED: ( - "Cannot reopen a client instance, once it has been closed." - ), - }[self._state] - raise RuntimeError(msg) - - self._state = ClientState.OPENED - - self._transport.__enter__() - for transport in self._mounts.values(): - if transport is not None: - transport.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self._state = ClientState.CLOSED - - self._transport.__exit__(exc_type, exc_value, traceback) - for transport in self._mounts.values(): - if transport is not None: - transport.__exit__(exc_type, exc_value, traceback) - - -class AsyncClient(BaseClient): - """ - An asynchronous HTTP client, with connection pooling, HTTP/2, redirects, - cookie persistence, etc. - - It can be shared between tasks. - - Usage: - - ```python - >>> async with httpx.AsyncClient() as client: - >>> response = await client.get('https://example.org') - ``` - - **Parameters:** - - * **auth** - *(optional)* An authentication class to use when sending - requests. - * **params** - *(optional)* Query parameters to include in request URLs, as - a string, dictionary, or sequence of two-tuples. - * **headers** - *(optional)* Dictionary of HTTP headers to include when - sending requests. - * **cookies** - *(optional)* Dictionary of Cookie items to include when - sending requests. - * **verify** - *(optional)* Either `True` to use an SSL context with the - default CA bundle, `False` to disable verification, or an instance of - `ssl.SSLContext` to use a custom context. - * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be - enabled. Defaults to `False`. - * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **timeout** - *(optional)* The timeout configuration to use when sending - requests. - * **limits** - *(optional)* The limits configuration to use. - * **max_redirects** - *(optional)* The maximum number of redirect responses - that should be followed. - * **base_url** - *(optional)* A URL to use as the base when building - request URLs. - * **transport** - *(optional)* A transport class to use for sending requests - over the network. - * **trust_env** - *(optional)* Enables or disables usage of environment - variables for configuration. - * **default_encoding** - *(optional)* The default encoding to use for decoding - response text, if no charset information is included in a response Content-Type - header. Set to a callable for automatic character set detection. Default: "utf-8". - """ - - def __init__( - self, - *, - auth: AuthTypes | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - http1: bool = True, - http2: bool = False, - proxy: ProxyTypes | None = None, - mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None, - timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, - follow_redirects: bool = False, - limits: Limits = DEFAULT_LIMITS, - max_redirects: int = DEFAULT_MAX_REDIRECTS, - event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, - base_url: URL | str = "", - transport: AsyncBaseTransport | None = None, - trust_env: bool = True, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - super().__init__( - auth=auth, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - follow_redirects=follow_redirects, - max_redirects=max_redirects, - event_hooks=event_hooks, - base_url=base_url, - trust_env=trust_env, - default_encoding=default_encoding, - ) - - if http2: - try: - import h2 # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using http2=True, but the 'h2' package is not installed. " - "Make sure to install httpx using `pip install httpx[http2]`." - ) from None - - allow_env_proxies = trust_env and transport is None - proxy_map = self._get_proxy_map(proxy, allow_env_proxies) - - self._transport = self._init_transport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - transport=transport, - ) - - self._mounts: dict[URLPattern, AsyncBaseTransport | None] = { - URLPattern(key): None - if proxy is None - else self._init_proxy_transport( - proxy, - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - for key, proxy in proxy_map.items() - } - if mounts is not None: - self._mounts.update( - {URLPattern(key): transport for key, transport in mounts.items()} - ) - self._mounts = dict(sorted(self._mounts.items())) - - def _init_transport( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - transport: AsyncBaseTransport | None = None, - ) -> AsyncBaseTransport: - if transport is not None: - return transport - - return AsyncHTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - ) - - def _init_proxy_transport( - self, - proxy: Proxy, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - ) -> AsyncBaseTransport: - return AsyncHTTPTransport( - verify=verify, - cert=cert, - trust_env=trust_env, - http1=http1, - http2=http2, - limits=limits, - proxy=proxy, - ) - - def _transport_for_url(self, url: URL) -> AsyncBaseTransport: - """ - Returns the transport instance that should be used for a given URL. - This will either be the standard connection pool, or a proxy. - """ - for pattern, transport in self._mounts.items(): - if pattern.matches(url): - return self._transport if transport is None else transport - - return self._transport - - async def request( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Build and send a request. - - Equivalent to: - - ```python - request = client.build_request(...) - response = await client.send(request, ...) - ``` - - See `AsyncClient.build_request()`, `AsyncClient.send()` - and [Merging of configuration][0] for how the various parameters - are merged with client-level configuration. - - [0]: /advanced/clients/#merging-of-configuration - """ - - if cookies is not None: # pragma: no cover - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning, stacklevel=2) - - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - return await self.send(request, auth=auth, follow_redirects=follow_redirects) - - @asynccontextmanager - async def stream( - self, - method: str, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> typing.AsyncIterator[Response]: - """ - Alternative to `httpx.request()` that streams the response body - instead of loading it into memory at once. - - **Parameters**: See `httpx.request`. - - See also: [Streaming Responses][0] - - [0]: /quickstart#streaming-responses - """ - request = self.build_request( - method=method, - url=url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - timeout=timeout, - extensions=extensions, - ) - response = await self.send( - request=request, - auth=auth, - follow_redirects=follow_redirects, - stream=True, - ) - try: - yield response - finally: - await response.aclose() - - async def send( - self, - request: Request, - *, - stream: bool = False, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - ) -> Response: - """ - Send a request. - - The request is sent as-is, unmodified. - - Typically you'll want to build one with `AsyncClient.build_request()` - so that any client-level configuration is merged into the request, - but passing an explicit `httpx.Request()` is supported as well. - - See also: [Request instances][0] - - [0]: /advanced/clients/#request-instances - """ - if self._state == ClientState.CLOSED: - raise RuntimeError("Cannot send a request, as the client has been closed.") - - self._state = ClientState.OPENED - follow_redirects = ( - self.follow_redirects - if isinstance(follow_redirects, UseClientDefault) - else follow_redirects - ) - - self._set_timeout(request) - - auth = self._build_request_auth(request, auth) - - response = await self._send_handling_auth( - request, - auth=auth, - follow_redirects=follow_redirects, - history=[], - ) - try: - if not stream: - await response.aread() - - return response - - except BaseException as exc: - await response.aclose() - raise exc - - async def _send_handling_auth( - self, - request: Request, - auth: Auth, - follow_redirects: bool, - history: list[Response], - ) -> Response: - auth_flow = auth.async_auth_flow(request) - try: - request = await auth_flow.__anext__() - - while True: - response = await self._send_handling_redirects( - request, - follow_redirects=follow_redirects, - history=history, - ) - try: - try: - next_request = await auth_flow.asend(response) - except StopAsyncIteration: - return response - - response.history = list(history) - await response.aread() - request = next_request - history.append(response) - - except BaseException as exc: - await response.aclose() - raise exc - finally: - await auth_flow.aclose() - - async def _send_handling_redirects( - self, - request: Request, - follow_redirects: bool, - history: list[Response], - ) -> Response: - while True: - if len(history) > self.max_redirects: - raise TooManyRedirects( - "Exceeded maximum allowed redirects.", request=request - ) - - for hook in self._event_hooks["request"]: - await hook(request) - - response = await self._send_single_request(request) - try: - for hook in self._event_hooks["response"]: - await hook(response) - - response.history = list(history) - - if not response.has_redirect_location: - return response - - request = self._build_redirect_request(request, response) - history = history + [response] - - if follow_redirects: - await response.aread() - else: - response.next_request = request - return response - - except BaseException as exc: - await response.aclose() - raise exc - - async def _send_single_request(self, request: Request) -> Response: - """ - Sends a single request, without handling any redirections. - """ - transport = self._transport_for_url(request.url) - start = time.perf_counter() - - if not isinstance(request.stream, AsyncByteStream): - raise RuntimeError( - "Attempted to send an sync request with an AsyncClient instance." - ) - - with request_context(request=request): - response = await transport.handle_async_request(request) - - assert isinstance(response.stream, AsyncByteStream) - response.request = request - response.stream = BoundAsyncStream( - response.stream, response=response, start=start - ) - self.cookies.extract_cookies(response) - response.default_encoding = self._default_encoding - - logger.info( - 'HTTP Request: %s %s "%s %d %s"', - request.method, - request.url, - response.http_version, - response.status_code, - response.reason_phrase, - ) - - return response - - async def get( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `GET` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "GET", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def options( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send an `OPTIONS` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "OPTIONS", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def head( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `HEAD` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "HEAD", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def post( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `POST` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "POST", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def put( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PUT` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "PUT", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def patch( - self, - url: URL | str, - *, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `PATCH` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "PATCH", - url, - content=content, - data=data, - files=files, - json=json, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def delete( - self, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, - follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, - timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, - extensions: RequestExtensions | None = None, - ) -> Response: - """ - Send a `DELETE` request. - - **Parameters**: See `httpx.request`. - """ - return await self.request( - "DELETE", - url, - params=params, - headers=headers, - cookies=cookies, - auth=auth, - follow_redirects=follow_redirects, - timeout=timeout, - extensions=extensions, - ) - - async def aclose(self) -> None: - """ - Close transport and proxies. - """ - if self._state != ClientState.CLOSED: - self._state = ClientState.CLOSED - - await self._transport.aclose() - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.aclose() - - async def __aenter__(self: U) -> U: - if self._state != ClientState.UNOPENED: - msg = { - ClientState.OPENED: "Cannot open a client instance more than once.", - ClientState.CLOSED: ( - "Cannot reopen a client instance, once it has been closed." - ), - }[self._state] - raise RuntimeError(msg) - - self._state = ClientState.OPENED - - await self._transport.__aenter__() - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self._state = ClientState.CLOSED - - await self._transport.__aexit__(exc_type, exc_value, traceback) - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.__aexit__(exc_type, exc_value, traceback) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_config.py b/backend/venv39/lib/python3.9/site-packages/httpx/_config.py deleted file mode 100644 index 467a6c9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_config.py +++ /dev/null @@ -1,248 +0,0 @@ -from __future__ import annotations - -import os -import typing - -from ._models import Headers -from ._types import CertTypes, HeaderTypes, TimeoutTypes -from ._urls import URL - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - -__all__ = ["Limits", "Proxy", "Timeout", "create_ssl_context"] - - -class UnsetType: - pass # pragma: no cover - - -UNSET = UnsetType() - - -def create_ssl_context( - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, -) -> ssl.SSLContext: - import ssl - import warnings - - import certifi - - if verify is True: - if trust_env and os.environ.get("SSL_CERT_FILE"): # pragma: nocover - ctx = ssl.create_default_context(cafile=os.environ["SSL_CERT_FILE"]) - elif trust_env and os.environ.get("SSL_CERT_DIR"): # pragma: nocover - ctx = ssl.create_default_context(capath=os.environ["SSL_CERT_DIR"]) - else: - # Default case... - ctx = ssl.create_default_context(cafile=certifi.where()) - elif verify is False: - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - elif isinstance(verify, str): # pragma: nocover - message = ( - "`verify=` is deprecated. " - "Use `verify=ssl.create_default_context(cafile=...)` " - "or `verify=ssl.create_default_context(capath=...)` instead." - ) - warnings.warn(message, DeprecationWarning) - if os.path.isdir(verify): - return ssl.create_default_context(capath=verify) - return ssl.create_default_context(cafile=verify) - else: - ctx = verify - - if cert: # pragma: nocover - message = ( - "`cert=...` is deprecated. Use `verify=` instead," - "with `.load_cert_chain()` to configure the certificate chain." - ) - warnings.warn(message, DeprecationWarning) - if isinstance(cert, str): - ctx.load_cert_chain(cert) - else: - ctx.load_cert_chain(*cert) - - return ctx - - -class Timeout: - """ - Timeout configuration. - - **Usage**: - - Timeout(None) # No timeouts. - Timeout(5.0) # 5s timeout on all operations. - Timeout(None, connect=5.0) # 5s timeout on connect, no other timeouts. - Timeout(5.0, connect=10.0) # 10s timeout on connect. 5s timeout elsewhere. - Timeout(5.0, pool=None) # No timeout on acquiring connection from pool. - # 5s timeout elsewhere. - """ - - def __init__( - self, - timeout: TimeoutTypes | UnsetType = UNSET, - *, - connect: None | float | UnsetType = UNSET, - read: None | float | UnsetType = UNSET, - write: None | float | UnsetType = UNSET, - pool: None | float | UnsetType = UNSET, - ) -> None: - if isinstance(timeout, Timeout): - # Passed as a single explicit Timeout. - assert connect is UNSET - assert read is UNSET - assert write is UNSET - assert pool is UNSET - self.connect = timeout.connect # type: typing.Optional[float] - self.read = timeout.read # type: typing.Optional[float] - self.write = timeout.write # type: typing.Optional[float] - self.pool = timeout.pool # type: typing.Optional[float] - elif isinstance(timeout, tuple): - # Passed as a tuple. - self.connect = timeout[0] - self.read = timeout[1] - self.write = None if len(timeout) < 3 else timeout[2] - self.pool = None if len(timeout) < 4 else timeout[3] - elif not ( - isinstance(connect, UnsetType) - or isinstance(read, UnsetType) - or isinstance(write, UnsetType) - or isinstance(pool, UnsetType) - ): - self.connect = connect - self.read = read - self.write = write - self.pool = pool - else: - if isinstance(timeout, UnsetType): - raise ValueError( - "httpx.Timeout must either include a default, or set all " - "four parameters explicitly." - ) - self.connect = timeout if isinstance(connect, UnsetType) else connect - self.read = timeout if isinstance(read, UnsetType) else read - self.write = timeout if isinstance(write, UnsetType) else write - self.pool = timeout if isinstance(pool, UnsetType) else pool - - def as_dict(self) -> dict[str, float | None]: - return { - "connect": self.connect, - "read": self.read, - "write": self.write, - "pool": self.pool, - } - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, self.__class__) - and self.connect == other.connect - and self.read == other.read - and self.write == other.write - and self.pool == other.pool - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - if len({self.connect, self.read, self.write, self.pool}) == 1: - return f"{class_name}(timeout={self.connect})" - return ( - f"{class_name}(connect={self.connect}, " - f"read={self.read}, write={self.write}, pool={self.pool})" - ) - - -class Limits: - """ - Configuration for limits to various client behaviors. - - **Parameters:** - - * **max_connections** - The maximum number of concurrent connections that may be - established. - * **max_keepalive_connections** - Allow the connection pool to maintain - keep-alive connections below this point. Should be less than or equal - to `max_connections`. - * **keepalive_expiry** - Time limit on idle keep-alive connections in seconds. - """ - - def __init__( - self, - *, - max_connections: int | None = None, - max_keepalive_connections: int | None = None, - keepalive_expiry: float | None = 5.0, - ) -> None: - self.max_connections = max_connections - self.max_keepalive_connections = max_keepalive_connections - self.keepalive_expiry = keepalive_expiry - - def __eq__(self, other: typing.Any) -> bool: - return ( - isinstance(other, self.__class__) - and self.max_connections == other.max_connections - and self.max_keepalive_connections == other.max_keepalive_connections - and self.keepalive_expiry == other.keepalive_expiry - ) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - return ( - f"{class_name}(max_connections={self.max_connections}, " - f"max_keepalive_connections={self.max_keepalive_connections}, " - f"keepalive_expiry={self.keepalive_expiry})" - ) - - -class Proxy: - def __init__( - self, - url: URL | str, - *, - ssl_context: ssl.SSLContext | None = None, - auth: tuple[str, str] | None = None, - headers: HeaderTypes | None = None, - ) -> None: - url = URL(url) - headers = Headers(headers) - - if url.scheme not in ("http", "https", "socks5", "socks5h"): - raise ValueError(f"Unknown scheme for proxy URL {url!r}") - - if url.username or url.password: - # Remove any auth credentials from the URL. - auth = (url.username, url.password) - url = url.copy_with(username=None, password=None) - - self.url = url - self.auth = auth - self.headers = headers - self.ssl_context = ssl_context - - @property - def raw_auth(self) -> tuple[bytes, bytes] | None: - # The proxy authentication as raw bytes. - return ( - None - if self.auth is None - else (self.auth[0].encode("utf-8"), self.auth[1].encode("utf-8")) - ) - - def __repr__(self) -> str: - # The authentication is represented with the password component masked. - auth = (self.auth[0], "********") if self.auth else None - - # Build a nice concise representation. - url_str = f"{str(self.url)!r}" - auth_str = f", auth={auth!r}" if auth else "" - headers_str = f", headers={dict(self.headers)!r}" if self.headers else "" - return f"Proxy({url_str}{auth_str}{headers_str})" - - -DEFAULT_TIMEOUT_CONFIG = Timeout(timeout=5.0) -DEFAULT_LIMITS = Limits(max_connections=100, max_keepalive_connections=20) -DEFAULT_MAX_REDIRECTS = 20 diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_content.py b/backend/venv39/lib/python3.9/site-packages/httpx/_content.py deleted file mode 100644 index 6f479a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_content.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import annotations - -import inspect -import warnings -from json import dumps as json_dumps -from typing import ( - Any, - AsyncIterable, - AsyncIterator, - Iterable, - Iterator, - Mapping, -) -from urllib.parse import urlencode - -from ._exceptions import StreamClosed, StreamConsumed -from ._multipart import MultipartStream -from ._types import ( - AsyncByteStream, - RequestContent, - RequestData, - RequestFiles, - ResponseContent, - SyncByteStream, -) -from ._utils import peek_filelike_length, primitive_value_to_str - -__all__ = ["ByteStream"] - - -class ByteStream(AsyncByteStream, SyncByteStream): - def __init__(self, stream: bytes) -> None: - self._stream = stream - - def __iter__(self) -> Iterator[bytes]: - yield self._stream - - async def __aiter__(self) -> AsyncIterator[bytes]: - yield self._stream - - -class IteratorByteStream(SyncByteStream): - CHUNK_SIZE = 65_536 - - def __init__(self, stream: Iterable[bytes]) -> None: - self._stream = stream - self._is_stream_consumed = False - self._is_generator = inspect.isgenerator(stream) - - def __iter__(self) -> Iterator[bytes]: - if self._is_stream_consumed and self._is_generator: - raise StreamConsumed() - - self._is_stream_consumed = True - if hasattr(self._stream, "read"): - # File-like interfaces should use 'read' directly. - chunk = self._stream.read(self.CHUNK_SIZE) - while chunk: - yield chunk - chunk = self._stream.read(self.CHUNK_SIZE) - else: - # Otherwise iterate. - for part in self._stream: - yield part - - -class AsyncIteratorByteStream(AsyncByteStream): - CHUNK_SIZE = 65_536 - - def __init__(self, stream: AsyncIterable[bytes]) -> None: - self._stream = stream - self._is_stream_consumed = False - self._is_generator = inspect.isasyncgen(stream) - - async def __aiter__(self) -> AsyncIterator[bytes]: - if self._is_stream_consumed and self._is_generator: - raise StreamConsumed() - - self._is_stream_consumed = True - if hasattr(self._stream, "aread"): - # File-like interfaces should use 'aread' directly. - chunk = await self._stream.aread(self.CHUNK_SIZE) - while chunk: - yield chunk - chunk = await self._stream.aread(self.CHUNK_SIZE) - else: - # Otherwise iterate. - async for part in self._stream: - yield part - - -class UnattachedStream(AsyncByteStream, SyncByteStream): - """ - If a request or response is serialized using pickle, then it is no longer - attached to a stream for I/O purposes. Any stream operations should result - in `httpx.StreamClosed`. - """ - - def __iter__(self) -> Iterator[bytes]: - raise StreamClosed() - - async def __aiter__(self) -> AsyncIterator[bytes]: - raise StreamClosed() - yield b"" # pragma: no cover - - -def encode_content( - content: str | bytes | Iterable[bytes] | AsyncIterable[bytes], -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - if isinstance(content, (bytes, str)): - body = content.encode("utf-8") if isinstance(content, str) else content - content_length = len(body) - headers = {"Content-Length": str(content_length)} if body else {} - return headers, ByteStream(body) - - elif isinstance(content, Iterable) and not isinstance(content, dict): - # `not isinstance(content, dict)` is a bit oddly specific, but it - # catches a case that's easy for users to make in error, and would - # otherwise pass through here, like any other bytes-iterable, - # because `dict` happens to be iterable. See issue #2491. - content_length_or_none = peek_filelike_length(content) - - if content_length_or_none is None: - headers = {"Transfer-Encoding": "chunked"} - else: - headers = {"Content-Length": str(content_length_or_none)} - return headers, IteratorByteStream(content) # type: ignore - - elif isinstance(content, AsyncIterable): - headers = {"Transfer-Encoding": "chunked"} - return headers, AsyncIteratorByteStream(content) - - raise TypeError(f"Unexpected type for 'content', {type(content)!r}") - - -def encode_urlencoded_data( - data: RequestData, -) -> tuple[dict[str, str], ByteStream]: - plain_data = [] - for key, value in data.items(): - if isinstance(value, (list, tuple)): - plain_data.extend([(key, primitive_value_to_str(item)) for item in value]) - else: - plain_data.append((key, primitive_value_to_str(value))) - body = urlencode(plain_data, doseq=True).encode("utf-8") - content_length = str(len(body)) - content_type = "application/x-www-form-urlencoded" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_multipart_data( - data: RequestData, files: RequestFiles, boundary: bytes | None -) -> tuple[dict[str, str], MultipartStream]: - multipart = MultipartStream(data=data, files=files, boundary=boundary) - headers = multipart.get_headers() - return headers, multipart - - -def encode_text(text: str) -> tuple[dict[str, str], ByteStream]: - body = text.encode("utf-8") - content_length = str(len(body)) - content_type = "text/plain; charset=utf-8" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_html(html: str) -> tuple[dict[str, str], ByteStream]: - body = html.encode("utf-8") - content_length = str(len(body)) - content_type = "text/html; charset=utf-8" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_json(json: Any) -> tuple[dict[str, str], ByteStream]: - body = json_dumps( - json, ensure_ascii=False, separators=(",", ":"), allow_nan=False - ).encode("utf-8") - content_length = str(len(body)) - content_type = "application/json" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, ByteStream(body) - - -def encode_request( - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: Any | None = None, - boundary: bytes | None = None, -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - """ - Handles encoding the given `content`, `data`, `files`, and `json`, - returning a two-tuple of (, ). - """ - if data is not None and not isinstance(data, Mapping): - # We prefer to separate `content=` - # for raw request content, and `data=
    ` for url encoded or - # multipart form content. - # - # However for compat with requests, we *do* still support - # `data=` usages. We deal with that case here, treating it - # as if `content=<...>` had been supplied instead. - message = "Use 'content=<...>' to upload raw bytes/text content." - warnings.warn(message, DeprecationWarning, stacklevel=2) - return encode_content(data) - - if content is not None: - return encode_content(content) - elif files: - return encode_multipart_data(data or {}, files, boundary) - elif data: - return encode_urlencoded_data(data) - elif json is not None: - return encode_json(json) - - return {}, ByteStream(b"") - - -def encode_response( - content: ResponseContent | None = None, - text: str | None = None, - html: str | None = None, - json: Any | None = None, -) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: - """ - Handles encoding the given `content`, returning a two-tuple of - (, ). - """ - if content is not None: - return encode_content(content) - elif text is not None: - return encode_text(text) - elif html is not None: - return encode_html(html) - elif json is not None: - return encode_json(json) - - return {}, ByteStream(b"") diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_decoders.py b/backend/venv39/lib/python3.9/site-packages/httpx/_decoders.py deleted file mode 100644 index 899dfad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_decoders.py +++ /dev/null @@ -1,393 +0,0 @@ -""" -Handlers for Content-Encoding. - -See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding -""" - -from __future__ import annotations - -import codecs -import io -import typing -import zlib - -from ._exceptions import DecodingError - -# Brotli support is optional -try: - # The C bindings in `brotli` are recommended for CPython. - import brotli -except ImportError: # pragma: no cover - try: - # The CFFI bindings in `brotlicffi` are recommended for PyPy - # and other environments. - import brotlicffi as brotli - except ImportError: - brotli = None - - -# Zstandard support is optional -try: - import zstandard -except ImportError: # pragma: no cover - zstandard = None # type: ignore - - -class ContentDecoder: - def decode(self, data: bytes) -> bytes: - raise NotImplementedError() # pragma: no cover - - def flush(self) -> bytes: - raise NotImplementedError() # pragma: no cover - - -class IdentityDecoder(ContentDecoder): - """ - Handle unencoded data. - """ - - def decode(self, data: bytes) -> bytes: - return data - - def flush(self) -> bytes: - return b"" - - -class DeflateDecoder(ContentDecoder): - """ - Handle 'deflate' decoding. - - See: https://stackoverflow.com/questions/1838699 - """ - - def __init__(self) -> None: - self.first_attempt = True - self.decompressor = zlib.decompressobj() - - def decode(self, data: bytes) -> bytes: - was_first_attempt = self.first_attempt - self.first_attempt = False - try: - return self.decompressor.decompress(data) - except zlib.error as exc: - if was_first_attempt: - self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS) - return self.decode(data) - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - try: - return self.decompressor.flush() - except zlib.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class GZipDecoder(ContentDecoder): - """ - Handle 'gzip' decoding. - - See: https://stackoverflow.com/questions/1838699 - """ - - def __init__(self) -> None: - self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16) - - def decode(self, data: bytes) -> bytes: - try: - return self.decompressor.decompress(data) - except zlib.error as exc: - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - try: - return self.decompressor.flush() - except zlib.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class BrotliDecoder(ContentDecoder): - """ - Handle 'brotli' decoding. - - Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/ - or `pip install brotli`. See https://github.com/google/brotli - Supports both 'brotlipy' and 'Brotli' packages since they share an import - name. The top branches are for 'brotlipy' and bottom branches for 'Brotli' - """ - - def __init__(self) -> None: - if brotli is None: # pragma: no cover - raise ImportError( - "Using 'BrotliDecoder', but neither of the 'brotlicffi' or 'brotli' " - "packages have been installed. " - "Make sure to install httpx using `pip install httpx[brotli]`." - ) from None - - self.decompressor = brotli.Decompressor() - self.seen_data = False - self._decompress: typing.Callable[[bytes], bytes] - if hasattr(self.decompressor, "decompress"): - # The 'brotlicffi' package. - self._decompress = self.decompressor.decompress # pragma: no cover - else: - # The 'brotli' package. - self._decompress = self.decompressor.process # pragma: no cover - - def decode(self, data: bytes) -> bytes: - if not data: - return b"" - self.seen_data = True - try: - return self._decompress(data) - except brotli.error as exc: - raise DecodingError(str(exc)) from exc - - def flush(self) -> bytes: - if not self.seen_data: - return b"" - try: - if hasattr(self.decompressor, "finish"): - # Only available in the 'brotlicffi' package. - - # As the decompressor decompresses eagerly, this - # will never actually emit any data. However, it will potentially throw - # errors if a truncated or damaged data stream has been used. - self.decompressor.finish() # pragma: no cover - return b"" - except brotli.error as exc: # pragma: no cover - raise DecodingError(str(exc)) from exc - - -class ZStandardDecoder(ContentDecoder): - """ - Handle 'zstd' RFC 8878 decoding. - - Requires `pip install zstandard`. - Can be installed as a dependency of httpx using `pip install httpx[zstd]`. - """ - - # inspired by the ZstdDecoder implementation in urllib3 - def __init__(self) -> None: - if zstandard is None: # pragma: no cover - raise ImportError( - "Using 'ZStandardDecoder', ..." - "Make sure to install httpx using `pip install httpx[zstd]`." - ) from None - - self.decompressor = zstandard.ZstdDecompressor().decompressobj() - self.seen_data = False - - def decode(self, data: bytes) -> bytes: - assert zstandard is not None - self.seen_data = True - output = io.BytesIO() - try: - output.write(self.decompressor.decompress(data)) - while self.decompressor.eof and self.decompressor.unused_data: - unused_data = self.decompressor.unused_data - self.decompressor = zstandard.ZstdDecompressor().decompressobj() - output.write(self.decompressor.decompress(unused_data)) - except zstandard.ZstdError as exc: - raise DecodingError(str(exc)) from exc - return output.getvalue() - - def flush(self) -> bytes: - if not self.seen_data: - return b"" - ret = self.decompressor.flush() # note: this is a no-op - if not self.decompressor.eof: - raise DecodingError("Zstandard data is incomplete") # pragma: no cover - return bytes(ret) - - -class MultiDecoder(ContentDecoder): - """ - Handle the case where multiple encodings have been applied. - """ - - def __init__(self, children: typing.Sequence[ContentDecoder]) -> None: - """ - 'children' should be a sequence of decoders in the order in which - each was applied. - """ - # Note that we reverse the order for decoding. - self.children = list(reversed(children)) - - def decode(self, data: bytes) -> bytes: - for child in self.children: - data = child.decode(data) - return data - - def flush(self) -> bytes: - data = b"" - for child in self.children: - data = child.decode(data) + child.flush() - return data - - -class ByteChunker: - """ - Handles returning byte content in fixed-size chunks. - """ - - def __init__(self, chunk_size: int | None = None) -> None: - self._buffer = io.BytesIO() - self._chunk_size = chunk_size - - def decode(self, content: bytes) -> list[bytes]: - if self._chunk_size is None: - return [content] if content else [] - - self._buffer.write(content) - if self._buffer.tell() >= self._chunk_size: - value = self._buffer.getvalue() - chunks = [ - value[i : i + self._chunk_size] - for i in range(0, len(value), self._chunk_size) - ] - if len(chunks[-1]) == self._chunk_size: - self._buffer.seek(0) - self._buffer.truncate() - return chunks - else: - self._buffer.seek(0) - self._buffer.write(chunks[-1]) - self._buffer.truncate() - return chunks[:-1] - else: - return [] - - def flush(self) -> list[bytes]: - value = self._buffer.getvalue() - self._buffer.seek(0) - self._buffer.truncate() - return [value] if value else [] - - -class TextChunker: - """ - Handles returning text content in fixed-size chunks. - """ - - def __init__(self, chunk_size: int | None = None) -> None: - self._buffer = io.StringIO() - self._chunk_size = chunk_size - - def decode(self, content: str) -> list[str]: - if self._chunk_size is None: - return [content] if content else [] - - self._buffer.write(content) - if self._buffer.tell() >= self._chunk_size: - value = self._buffer.getvalue() - chunks = [ - value[i : i + self._chunk_size] - for i in range(0, len(value), self._chunk_size) - ] - if len(chunks[-1]) == self._chunk_size: - self._buffer.seek(0) - self._buffer.truncate() - return chunks - else: - self._buffer.seek(0) - self._buffer.write(chunks[-1]) - self._buffer.truncate() - return chunks[:-1] - else: - return [] - - def flush(self) -> list[str]: - value = self._buffer.getvalue() - self._buffer.seek(0) - self._buffer.truncate() - return [value] if value else [] - - -class TextDecoder: - """ - Handles incrementally decoding bytes into text - """ - - def __init__(self, encoding: str = "utf-8") -> None: - self.decoder = codecs.getincrementaldecoder(encoding)(errors="replace") - - def decode(self, data: bytes) -> str: - return self.decoder.decode(data) - - def flush(self) -> str: - return self.decoder.decode(b"", True) - - -class LineDecoder: - """ - Handles incrementally reading lines from text. - - Has the same behaviour as the stdllib splitlines, - but handling the input iteratively. - """ - - def __init__(self) -> None: - self.buffer: list[str] = [] - self.trailing_cr: bool = False - - def decode(self, text: str) -> list[str]: - # See https://docs.python.org/3/library/stdtypes.html#str.splitlines - NEWLINE_CHARS = "\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029" - - # We always push a trailing `\r` into the next decode iteration. - if self.trailing_cr: - text = "\r" + text - self.trailing_cr = False - if text.endswith("\r"): - self.trailing_cr = True - text = text[:-1] - - if not text: - # NOTE: the edge case input of empty text doesn't occur in practice, - # because other httpx internals filter out this value - return [] # pragma: no cover - - trailing_newline = text[-1] in NEWLINE_CHARS - lines = text.splitlines() - - if len(lines) == 1 and not trailing_newline: - # No new lines, buffer the input and continue. - self.buffer.append(lines[0]) - return [] - - if self.buffer: - # Include any existing buffer in the first portion of the - # splitlines result. - lines = ["".join(self.buffer) + lines[0]] + lines[1:] - self.buffer = [] - - if not trailing_newline: - # If the last segment of splitlines is not newline terminated, - # then drop it from our output and start a new buffer. - self.buffer = [lines.pop()] - - return lines - - def flush(self) -> list[str]: - if not self.buffer and not self.trailing_cr: - return [] - - lines = ["".join(self.buffer)] - self.buffer = [] - self.trailing_cr = False - return lines - - -SUPPORTED_DECODERS = { - "identity": IdentityDecoder, - "gzip": GZipDecoder, - "deflate": DeflateDecoder, - "br": BrotliDecoder, - "zstd": ZStandardDecoder, -} - - -if brotli is None: - SUPPORTED_DECODERS.pop("br") # pragma: no cover -if zstandard is None: - SUPPORTED_DECODERS.pop("zstd") # pragma: no cover diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_exceptions.py b/backend/venv39/lib/python3.9/site-packages/httpx/_exceptions.py deleted file mode 100644 index 77f45a6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_exceptions.py +++ /dev/null @@ -1,379 +0,0 @@ -""" -Our exception hierarchy: - -* HTTPError - x RequestError - + TransportError - - TimeoutException - · ConnectTimeout - · ReadTimeout - · WriteTimeout - · PoolTimeout - - NetworkError - · ConnectError - · ReadError - · WriteError - · CloseError - - ProtocolError - · LocalProtocolError - · RemoteProtocolError - - ProxyError - - UnsupportedProtocol - + DecodingError - + TooManyRedirects - x HTTPStatusError -* InvalidURL -* CookieConflict -* StreamError - x StreamConsumed - x StreamClosed - x ResponseNotRead - x RequestNotRead -""" - -from __future__ import annotations - -import contextlib -import typing - -if typing.TYPE_CHECKING: - from ._models import Request, Response # pragma: no cover - -__all__ = [ - "CloseError", - "ConnectError", - "ConnectTimeout", - "CookieConflict", - "DecodingError", - "HTTPError", - "HTTPStatusError", - "InvalidURL", - "LocalProtocolError", - "NetworkError", - "PoolTimeout", - "ProtocolError", - "ProxyError", - "ReadError", - "ReadTimeout", - "RemoteProtocolError", - "RequestError", - "RequestNotRead", - "ResponseNotRead", - "StreamClosed", - "StreamConsumed", - "StreamError", - "TimeoutException", - "TooManyRedirects", - "TransportError", - "UnsupportedProtocol", - "WriteError", - "WriteTimeout", -] - - -class HTTPError(Exception): - """ - Base class for `RequestError` and `HTTPStatusError`. - - Useful for `try...except` blocks when issuing a request, - and then calling `.raise_for_status()`. - - For example: - - ``` - try: - response = httpx.get("https://www.example.com") - response.raise_for_status() - except httpx.HTTPError as exc: - print(f"HTTP Exception for {exc.request.url} - {exc}") - ``` - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - self._request: Request | None = None - - @property - def request(self) -> Request: - if self._request is None: - raise RuntimeError("The .request property has not been set.") - return self._request - - @request.setter - def request(self, request: Request) -> None: - self._request = request - - -class RequestError(HTTPError): - """ - Base class for all exceptions that may occur when issuing a `.request()`. - """ - - def __init__(self, message: str, *, request: Request | None = None) -> None: - super().__init__(message) - # At the point an exception is raised we won't typically have a request - # instance to associate it with. - # - # The 'request_context' context manager is used within the Client and - # Response methods in order to ensure that any raised exceptions - # have a `.request` property set on them. - self._request = request - - -class TransportError(RequestError): - """ - Base class for all exceptions that occur at the level of the Transport API. - """ - - -# Timeout exceptions... - - -class TimeoutException(TransportError): - """ - The base class for timeout errors. - - An operation has timed out. - """ - - -class ConnectTimeout(TimeoutException): - """ - Timed out while connecting to the host. - """ - - -class ReadTimeout(TimeoutException): - """ - Timed out while receiving data from the host. - """ - - -class WriteTimeout(TimeoutException): - """ - Timed out while sending data to the host. - """ - - -class PoolTimeout(TimeoutException): - """ - Timed out waiting to acquire a connection from the pool. - """ - - -# Core networking exceptions... - - -class NetworkError(TransportError): - """ - The base class for network-related errors. - - An error occurred while interacting with the network. - """ - - -class ReadError(NetworkError): - """ - Failed to receive data from the network. - """ - - -class WriteError(NetworkError): - """ - Failed to send data through the network. - """ - - -class ConnectError(NetworkError): - """ - Failed to establish a connection. - """ - - -class CloseError(NetworkError): - """ - Failed to close a connection. - """ - - -# Other transport exceptions... - - -class ProxyError(TransportError): - """ - An error occurred while establishing a proxy connection. - """ - - -class UnsupportedProtocol(TransportError): - """ - Attempted to make a request to an unsupported protocol. - - For example issuing a request to `ftp://www.example.com`. - """ - - -class ProtocolError(TransportError): - """ - The protocol was violated. - """ - - -class LocalProtocolError(ProtocolError): - """ - A protocol was violated by the client. - - For example if the user instantiated a `Request` instance explicitly, - failed to include the mandatory `Host:` header, and then issued it directly - using `client.send()`. - """ - - -class RemoteProtocolError(ProtocolError): - """ - The protocol was violated by the server. - - For example, returning malformed HTTP. - """ - - -# Other request exceptions... - - -class DecodingError(RequestError): - """ - Decoding of the response failed, due to a malformed encoding. - """ - - -class TooManyRedirects(RequestError): - """ - Too many redirects. - """ - - -# Client errors - - -class HTTPStatusError(HTTPError): - """ - The response had an error HTTP status of 4xx or 5xx. - - May be raised when calling `response.raise_for_status()` - """ - - def __init__(self, message: str, *, request: Request, response: Response) -> None: - super().__init__(message) - self.request = request - self.response = response - - -class InvalidURL(Exception): - """ - URL is improperly formed or cannot be parsed. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -class CookieConflict(Exception): - """ - Attempted to lookup a cookie by name, but multiple cookies existed. - - Can occur when calling `response.cookies.get(...)`. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -# Stream exceptions... - -# These may occur as the result of a programming error, by accessing -# the request/response stream in an invalid manner. - - -class StreamError(RuntimeError): - """ - The base class for stream exceptions. - - The developer made an error in accessing the request stream in - an invalid way. - """ - - def __init__(self, message: str) -> None: - super().__init__(message) - - -class StreamConsumed(StreamError): - """ - Attempted to read or stream content, but the content has already - been streamed. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream some content, but the content has " - "already been streamed. For requests, this could be due to passing " - "a generator as request content, and then receiving a redirect " - "response or a secondary request as part of an authentication flow." - "For responses, this could be due to attempting to stream the response " - "content more than once." - ) - super().__init__(message) - - -class StreamClosed(StreamError): - """ - Attempted to read or stream response content, but the request has been - closed. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream content, but the stream has " "been closed." - ) - super().__init__(message) - - -class ResponseNotRead(StreamError): - """ - Attempted to access streaming response content, without having called `read()`. - """ - - def __init__(self) -> None: - message = ( - "Attempted to access streaming response content," - " without having called `read()`." - ) - super().__init__(message) - - -class RequestNotRead(StreamError): - """ - Attempted to access streaming request content, without having called `read()`. - """ - - def __init__(self) -> None: - message = ( - "Attempted to access streaming request content," - " without having called `read()`." - ) - super().__init__(message) - - -@contextlib.contextmanager -def request_context( - request: Request | None = None, -) -> typing.Iterator[None]: - """ - A context manager that can be used to attach the given request context - to any `RequestError` exceptions that are raised within the block. - """ - try: - yield - except RequestError as exc: - if request is not None: - exc.request = request - raise exc diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_main.py b/backend/venv39/lib/python3.9/site-packages/httpx/_main.py deleted file mode 100644 index cffa4bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_main.py +++ /dev/null @@ -1,506 +0,0 @@ -from __future__ import annotations - -import functools -import json -import sys -import typing - -import click -import pygments.lexers -import pygments.util -import rich.console -import rich.markup -import rich.progress -import rich.syntax -import rich.table - -from ._client import Client -from ._exceptions import RequestError -from ._models import Response -from ._status_codes import codes - -if typing.TYPE_CHECKING: - import httpcore # pragma: no cover - - -def print_help() -> None: - console = rich.console.Console() - - console.print("[bold]HTTPX :butterfly:", justify="center") - console.print() - console.print("A next generation HTTP client.", justify="center") - console.print() - console.print( - "Usage: [bold]httpx[/bold] [cyan] [OPTIONS][/cyan] ", justify="left" - ) - console.print() - - table = rich.table.Table.grid(padding=1, pad_edge=True) - table.add_column("Parameter", no_wrap=True, justify="left", style="bold") - table.add_column("Description") - table.add_row( - "-m, --method [cyan]METHOD", - "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD.\n" - "[Default: GET, or POST if a request body is included]", - ) - table.add_row( - "-p, --params [cyan] ...", - "Query parameters to include in the request URL.", - ) - table.add_row( - "-c, --content [cyan]TEXT", "Byte content to include in the request body." - ) - table.add_row( - "-d, --data [cyan] ...", "Form data to include in the request body." - ) - table.add_row( - "-f, --files [cyan] ...", - "Form files to include in the request body.", - ) - table.add_row("-j, --json [cyan]TEXT", "JSON data to include in the request body.") - table.add_row( - "-h, --headers [cyan] ...", - "Include additional HTTP headers in the request.", - ) - table.add_row( - "--cookies [cyan] ...", "Cookies to include in the request." - ) - table.add_row( - "--auth [cyan]", - "Username and password to include in the request. Specify '-' for the password" - " to use a password prompt. Note that using --verbose/-v will expose" - " the Authorization header, including the password encoding" - " in a trivially reversible format.", - ) - - table.add_row( - "--proxy [cyan]URL", - "Send the request via a proxy. Should be the URL giving the proxy address.", - ) - - table.add_row( - "--timeout [cyan]FLOAT", - "Timeout value to use for network operations, such as establishing the" - " connection, reading some data, etc... [Default: 5.0]", - ) - - table.add_row("--follow-redirects", "Automatically follow redirects.") - table.add_row("--no-verify", "Disable SSL verification.") - table.add_row( - "--http2", "Send the request using HTTP/2, if the remote server supports it." - ) - - table.add_row( - "--download [cyan]FILE", - "Save the response content as a file, rather than displaying it.", - ) - - table.add_row("-v, --verbose", "Verbose output. Show request as well as response.") - table.add_row("--help", "Show this message and exit.") - console.print(table) - - -def get_lexer_for_response(response: Response) -> str: - content_type = response.headers.get("Content-Type") - if content_type is not None: - mime_type, _, _ = content_type.partition(";") - try: - return typing.cast( - str, pygments.lexers.get_lexer_for_mimetype(mime_type.strip()).name - ) - except pygments.util.ClassNotFound: # pragma: no cover - pass - return "" # pragma: no cover - - -def format_request_headers(request: httpcore.Request, http2: bool = False) -> str: - version = "HTTP/2" if http2 else "HTTP/1.1" - headers = [ - (name.lower() if http2 else name, value) for name, value in request.headers - ] - method = request.method.decode("ascii") - target = request.url.target.decode("ascii") - lines = [f"{method} {target} {version}"] + [ - f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers - ] - return "\n".join(lines) - - -def format_response_headers( - http_version: bytes, - status: int, - reason_phrase: bytes | None, - headers: list[tuple[bytes, bytes]], -) -> str: - version = http_version.decode("ascii") - reason = ( - codes.get_reason_phrase(status) - if reason_phrase is None - else reason_phrase.decode("ascii") - ) - lines = [f"{version} {status} {reason}"] + [ - f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers - ] - return "\n".join(lines) - - -def print_request_headers(request: httpcore.Request, http2: bool = False) -> None: - console = rich.console.Console() - http_text = format_request_headers(request, http2=http2) - syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - - -def print_response_headers( - http_version: bytes, - status: int, - reason_phrase: bytes | None, - headers: list[tuple[bytes, bytes]], -) -> None: - console = rich.console.Console() - http_text = format_response_headers(http_version, status, reason_phrase, headers) - syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) - console.print(syntax) - - -def print_response(response: Response) -> None: - console = rich.console.Console() - lexer_name = get_lexer_for_response(response) - if lexer_name: - if lexer_name.lower() == "json": - try: - data = response.json() - text = json.dumps(data, indent=4) - except ValueError: # pragma: no cover - text = response.text - else: - text = response.text - - syntax = rich.syntax.Syntax(text, lexer_name, theme="ansi_dark", word_wrap=True) - console.print(syntax) - else: - console.print(f"<{len(response.content)} bytes of binary data>") - - -_PCTRTT = typing.Tuple[typing.Tuple[str, str], ...] -_PCTRTTT = typing.Tuple[_PCTRTT, ...] -_PeerCertRetDictType = typing.Dict[str, typing.Union[str, _PCTRTTT, _PCTRTT]] - - -def format_certificate(cert: _PeerCertRetDictType) -> str: # pragma: no cover - lines = [] - for key, value in cert.items(): - if isinstance(value, (list, tuple)): - lines.append(f"* {key}:") - for item in value: - if key in ("subject", "issuer"): - for sub_item in item: - lines.append(f"* {sub_item[0]}: {sub_item[1]!r}") - elif isinstance(item, tuple) and len(item) == 2: - lines.append(f"* {item[0]}: {item[1]!r}") - else: - lines.append(f"* {item!r}") - else: - lines.append(f"* {key}: {value!r}") - return "\n".join(lines) - - -def trace( - name: str, info: typing.Mapping[str, typing.Any], verbose: bool = False -) -> None: - console = rich.console.Console() - if name == "connection.connect_tcp.started" and verbose: - host = info["host"] - console.print(f"* Connecting to {host!r}") - elif name == "connection.connect_tcp.complete" and verbose: - stream = info["return_value"] - server_addr = stream.get_extra_info("server_addr") - console.print(f"* Connected to {server_addr[0]!r} on port {server_addr[1]}") - elif name == "connection.start_tls.complete" and verbose: # pragma: no cover - stream = info["return_value"] - ssl_object = stream.get_extra_info("ssl_object") - version = ssl_object.version() - cipher = ssl_object.cipher() - server_cert = ssl_object.getpeercert() - alpn = ssl_object.selected_alpn_protocol() - console.print(f"* SSL established using {version!r} / {cipher[0]!r}") - console.print(f"* Selected ALPN protocol: {alpn!r}") - if server_cert: - console.print("* Server certificate:") - console.print(format_certificate(server_cert)) - elif name == "http11.send_request_headers.started" and verbose: - request = info["request"] - print_request_headers(request, http2=False) - elif name == "http2.send_request_headers.started" and verbose: # pragma: no cover - request = info["request"] - print_request_headers(request, http2=True) - elif name == "http11.receive_response_headers.complete": - http_version, status, reason_phrase, headers = info["return_value"] - print_response_headers(http_version, status, reason_phrase, headers) - elif name == "http2.receive_response_headers.complete": # pragma: no cover - status, headers = info["return_value"] - http_version = b"HTTP/2" - reason_phrase = None - print_response_headers(http_version, status, reason_phrase, headers) - - -def download_response(response: Response, download: typing.BinaryIO) -> None: - console = rich.console.Console() - console.print() - content_length = response.headers.get("Content-Length") - with rich.progress.Progress( - "[progress.description]{task.description}", - "[progress.percentage]{task.percentage:>3.0f}%", - rich.progress.BarColumn(bar_width=None), - rich.progress.DownloadColumn(), - rich.progress.TransferSpeedColumn(), - ) as progress: - description = f"Downloading [bold]{rich.markup.escape(download.name)}" - download_task = progress.add_task( - description, - total=int(content_length or 0), - start=content_length is not None, - ) - for chunk in response.iter_bytes(): - download.write(chunk) - progress.update(download_task, completed=response.num_bytes_downloaded) - - -def validate_json( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> typing.Any: - if value is None: - return None - - try: - return json.loads(value) - except json.JSONDecodeError: # pragma: no cover - raise click.BadParameter("Not valid JSON") - - -def validate_auth( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> typing.Any: - if value == (None, None): - return None - - username, password = value - if password == "-": # pragma: no cover - password = click.prompt("Password", hide_input=True) - return (username, password) - - -def handle_help( - ctx: click.Context, - param: click.Option | click.Parameter, - value: typing.Any, -) -> None: - if not value or ctx.resilient_parsing: - return - - print_help() - ctx.exit() - - -@click.command(add_help_option=False) -@click.argument("url", type=str) -@click.option( - "--method", - "-m", - "method", - type=str, - help=( - "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD. " - "[Default: GET, or POST if a request body is included]" - ), -) -@click.option( - "--params", - "-p", - "params", - type=(str, str), - multiple=True, - help="Query parameters to include in the request URL.", -) -@click.option( - "--content", - "-c", - "content", - type=str, - help="Byte content to include in the request body.", -) -@click.option( - "--data", - "-d", - "data", - type=(str, str), - multiple=True, - help="Form data to include in the request body.", -) -@click.option( - "--files", - "-f", - "files", - type=(str, click.File(mode="rb")), - multiple=True, - help="Form files to include in the request body.", -) -@click.option( - "--json", - "-j", - "json", - type=str, - callback=validate_json, - help="JSON data to include in the request body.", -) -@click.option( - "--headers", - "-h", - "headers", - type=(str, str), - multiple=True, - help="Include additional HTTP headers in the request.", -) -@click.option( - "--cookies", - "cookies", - type=(str, str), - multiple=True, - help="Cookies to include in the request.", -) -@click.option( - "--auth", - "auth", - type=(str, str), - default=(None, None), - callback=validate_auth, - help=( - "Username and password to include in the request. " - "Specify '-' for the password to use a password prompt. " - "Note that using --verbose/-v will expose the Authorization header, " - "including the password encoding in a trivially reversible format." - ), -) -@click.option( - "--proxy", - "proxy", - type=str, - default=None, - help="Send the request via a proxy. Should be the URL giving the proxy address.", -) -@click.option( - "--timeout", - "timeout", - type=float, - default=5.0, - help=( - "Timeout value to use for network operations, such as establishing the " - "connection, reading some data, etc... [Default: 5.0]" - ), -) -@click.option( - "--follow-redirects", - "follow_redirects", - is_flag=True, - default=False, - help="Automatically follow redirects.", -) -@click.option( - "--no-verify", - "verify", - is_flag=True, - default=True, - help="Disable SSL verification.", -) -@click.option( - "--http2", - "http2", - type=bool, - is_flag=True, - default=False, - help="Send the request using HTTP/2, if the remote server supports it.", -) -@click.option( - "--download", - type=click.File("wb"), - help="Save the response content as a file, rather than displaying it.", -) -@click.option( - "--verbose", - "-v", - type=bool, - is_flag=True, - default=False, - help="Verbose. Show request as well as response.", -) -@click.option( - "--help", - is_flag=True, - is_eager=True, - expose_value=False, - callback=handle_help, - help="Show this message and exit.", -) -def main( - url: str, - method: str, - params: list[tuple[str, str]], - content: str, - data: list[tuple[str, str]], - files: list[tuple[str, click.File]], - json: str, - headers: list[tuple[str, str]], - cookies: list[tuple[str, str]], - auth: tuple[str, str] | None, - proxy: str, - timeout: float, - follow_redirects: bool, - verify: bool, - http2: bool, - download: typing.BinaryIO | None, - verbose: bool, -) -> None: - """ - An HTTP command line client. - Sends a request and displays the response. - """ - if not method: - method = "POST" if content or data or files or json else "GET" - - try: - with Client(proxy=proxy, timeout=timeout, http2=http2, verify=verify) as client: - with client.stream( - method, - url, - params=list(params), - content=content, - data=dict(data), - files=files, # type: ignore - json=json, - headers=headers, - cookies=dict(cookies), - auth=auth, - follow_redirects=follow_redirects, - extensions={"trace": functools.partial(trace, verbose=verbose)}, - ) as response: - if download is not None: - download_response(response, download) - else: - response.read() - if response.content: - print_response(response) - - except RequestError as exc: - console = rich.console.Console() - console.print(f"[red]{type(exc).__name__}[/red]: {exc}") - sys.exit(1) - - sys.exit(0 if response.is_success else 1) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_models.py b/backend/venv39/lib/python3.9/site-packages/httpx/_models.py deleted file mode 100644 index 67d74bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_models.py +++ /dev/null @@ -1,1277 +0,0 @@ -from __future__ import annotations - -import codecs -import datetime -import email.message -import json as jsonlib -import re -import typing -import urllib.request -from collections.abc import Mapping -from http.cookiejar import Cookie, CookieJar - -from ._content import ByteStream, UnattachedStream, encode_request, encode_response -from ._decoders import ( - SUPPORTED_DECODERS, - ByteChunker, - ContentDecoder, - IdentityDecoder, - LineDecoder, - MultiDecoder, - TextChunker, - TextDecoder, -) -from ._exceptions import ( - CookieConflict, - HTTPStatusError, - RequestNotRead, - ResponseNotRead, - StreamClosed, - StreamConsumed, - request_context, -) -from ._multipart import get_multipart_boundary_from_content_type -from ._status_codes import codes -from ._types import ( - AsyncByteStream, - CookieTypes, - HeaderTypes, - QueryParamTypes, - RequestContent, - RequestData, - RequestExtensions, - RequestFiles, - ResponseContent, - ResponseExtensions, - SyncByteStream, -) -from ._urls import URL -from ._utils import to_bytes_or_str, to_str - -__all__ = ["Cookies", "Headers", "Request", "Response"] - -SENSITIVE_HEADERS = {"authorization", "proxy-authorization"} - - -def _is_known_encoding(encoding: str) -> bool: - """ - Return `True` if `encoding` is a known codec. - """ - try: - codecs.lookup(encoding) - except LookupError: - return False - return True - - -def _normalize_header_key(key: str | bytes, encoding: str | None = None) -> bytes: - """ - Coerce str/bytes into a strictly byte-wise HTTP header key. - """ - return key if isinstance(key, bytes) else key.encode(encoding or "ascii") - - -def _normalize_header_value(value: str | bytes, encoding: str | None = None) -> bytes: - """ - Coerce str/bytes into a strictly byte-wise HTTP header value. - """ - if isinstance(value, bytes): - return value - if not isinstance(value, str): - raise TypeError(f"Header value must be str or bytes, not {type(value)}") - return value.encode(encoding or "ascii") - - -def _parse_content_type_charset(content_type: str) -> str | None: - # We used to use `cgi.parse_header()` here, but `cgi` became a dead battery. - # See: https://peps.python.org/pep-0594/#cgi - msg = email.message.Message() - msg["content-type"] = content_type - return msg.get_content_charset(failobj=None) - - -def _parse_header_links(value: str) -> list[dict[str, str]]: - """ - Returns a list of parsed link headers, for more info see: - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link - The generic syntax of those is: - Link: < uri-reference >; param1=value1; param2="value2" - So for instance: - Link; '; type="image/jpeg",;' - would return - [ - {"url": "http:/.../front.jpeg", "type": "image/jpeg"}, - {"url": "http://.../back.jpeg"}, - ] - :param value: HTTP Link entity-header field - :return: list of parsed link headers - """ - links: list[dict[str, str]] = [] - replace_chars = " '\"" - value = value.strip(replace_chars) - if not value: - return links - for val in re.split(", *<", value): - try: - url, params = val.split(";", 1) - except ValueError: - url, params = val, "" - link = {"url": url.strip("<> '\"")} - for param in params.split(";"): - try: - key, value = param.split("=") - except ValueError: - break - link[key.strip(replace_chars)] = value.strip(replace_chars) - links.append(link) - return links - - -def _obfuscate_sensitive_headers( - items: typing.Iterable[tuple[typing.AnyStr, typing.AnyStr]], -) -> typing.Iterator[tuple[typing.AnyStr, typing.AnyStr]]: - for k, v in items: - if to_str(k.lower()) in SENSITIVE_HEADERS: - v = to_bytes_or_str("[secure]", match_type_of=v) - yield k, v - - -class Headers(typing.MutableMapping[str, str]): - """ - HTTP headers, as a case-insensitive multi-dict. - """ - - def __init__( - self, - headers: HeaderTypes | None = None, - encoding: str | None = None, - ) -> None: - self._list = [] # type: typing.List[typing.Tuple[bytes, bytes, bytes]] - - if isinstance(headers, Headers): - self._list = list(headers._list) - elif isinstance(headers, Mapping): - for k, v in headers.items(): - bytes_key = _normalize_header_key(k, encoding) - bytes_value = _normalize_header_value(v, encoding) - self._list.append((bytes_key, bytes_key.lower(), bytes_value)) - elif headers is not None: - for k, v in headers: - bytes_key = _normalize_header_key(k, encoding) - bytes_value = _normalize_header_value(v, encoding) - self._list.append((bytes_key, bytes_key.lower(), bytes_value)) - - self._encoding = encoding - - @property - def encoding(self) -> str: - """ - Header encoding is mandated as ascii, but we allow fallbacks to utf-8 - or iso-8859-1. - """ - if self._encoding is None: - for encoding in ["ascii", "utf-8"]: - for key, value in self.raw: - try: - key.decode(encoding) - value.decode(encoding) - except UnicodeDecodeError: - break - else: - # The else block runs if 'break' did not occur, meaning - # all values fitted the encoding. - self._encoding = encoding - break - else: - # The ISO-8859-1 encoding covers all 256 code points in a byte, - # so will never raise decode errors. - self._encoding = "iso-8859-1" - return self._encoding - - @encoding.setter - def encoding(self, value: str) -> None: - self._encoding = value - - @property - def raw(self) -> list[tuple[bytes, bytes]]: - """ - Returns a list of the raw header items, as byte pairs. - """ - return [(raw_key, value) for raw_key, _, value in self._list] - - def keys(self) -> typing.KeysView[str]: - return {key.decode(self.encoding): None for _, key, value in self._list}.keys() - - def values(self) -> typing.ValuesView[str]: - values_dict: dict[str, str] = {} - for _, key, value in self._list: - str_key = key.decode(self.encoding) - str_value = value.decode(self.encoding) - if str_key in values_dict: - values_dict[str_key] += f", {str_value}" - else: - values_dict[str_key] = str_value - return values_dict.values() - - def items(self) -> typing.ItemsView[str, str]: - """ - Return `(key, value)` items of headers. Concatenate headers - into a single comma separated value when a key occurs multiple times. - """ - values_dict: dict[str, str] = {} - for _, key, value in self._list: - str_key = key.decode(self.encoding) - str_value = value.decode(self.encoding) - if str_key in values_dict: - values_dict[str_key] += f", {str_value}" - else: - values_dict[str_key] = str_value - return values_dict.items() - - def multi_items(self) -> list[tuple[str, str]]: - """ - Return a list of `(key, value)` pairs of headers. Allow multiple - occurrences of the same key without concatenating into a single - comma separated value. - """ - return [ - (key.decode(self.encoding), value.decode(self.encoding)) - for _, key, value in self._list - ] - - def get(self, key: str, default: typing.Any = None) -> typing.Any: - """ - Return a header value. If multiple occurrences of the header occur - then concatenate them together with commas. - """ - try: - return self[key] - except KeyError: - return default - - def get_list(self, key: str, split_commas: bool = False) -> list[str]: - """ - Return a list of all header values for a given key. - If `split_commas=True` is passed, then any comma separated header - values are split into multiple return strings. - """ - get_header_key = key.lower().encode(self.encoding) - - values = [ - item_value.decode(self.encoding) - for _, item_key, item_value in self._list - if item_key.lower() == get_header_key - ] - - if not split_commas: - return values - - split_values = [] - for value in values: - split_values.extend([item.strip() for item in value.split(",")]) - return split_values - - def update(self, headers: HeaderTypes | None = None) -> None: # type: ignore - headers = Headers(headers) - for key in headers.keys(): - if key in self: - self.pop(key) - self._list.extend(headers._list) - - def copy(self) -> Headers: - return Headers(self, encoding=self.encoding) - - def __getitem__(self, key: str) -> str: - """ - Return a single header value. - - If there are multiple headers with the same key, then we concatenate - them with commas. See: https://tools.ietf.org/html/rfc7230#section-3.2.2 - """ - normalized_key = key.lower().encode(self.encoding) - - items = [ - header_value.decode(self.encoding) - for _, header_key, header_value in self._list - if header_key == normalized_key - ] - - if items: - return ", ".join(items) - - raise KeyError(key) - - def __setitem__(self, key: str, value: str) -> None: - """ - Set the header `key` to `value`, removing any duplicate entries. - Retains insertion order. - """ - set_key = key.encode(self._encoding or "utf-8") - set_value = value.encode(self._encoding or "utf-8") - lookup_key = set_key.lower() - - found_indexes = [ - idx - for idx, (_, item_key, _) in enumerate(self._list) - if item_key == lookup_key - ] - - for idx in reversed(found_indexes[1:]): - del self._list[idx] - - if found_indexes: - idx = found_indexes[0] - self._list[idx] = (set_key, lookup_key, set_value) - else: - self._list.append((set_key, lookup_key, set_value)) - - def __delitem__(self, key: str) -> None: - """ - Remove the header `key`. - """ - del_key = key.lower().encode(self.encoding) - - pop_indexes = [ - idx - for idx, (_, item_key, _) in enumerate(self._list) - if item_key.lower() == del_key - ] - - if not pop_indexes: - raise KeyError(key) - - for idx in reversed(pop_indexes): - del self._list[idx] - - def __contains__(self, key: typing.Any) -> bool: - header_key = key.lower().encode(self.encoding) - return header_key in [key for _, key, _ in self._list] - - def __iter__(self) -> typing.Iterator[typing.Any]: - return iter(self.keys()) - - def __len__(self) -> int: - return len(self._list) - - def __eq__(self, other: typing.Any) -> bool: - try: - other_headers = Headers(other) - except ValueError: - return False - - self_list = [(key, value) for _, key, value in self._list] - other_list = [(key, value) for _, key, value in other_headers._list] - return sorted(self_list) == sorted(other_list) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - - encoding_str = "" - if self.encoding != "ascii": - encoding_str = f", encoding={self.encoding!r}" - - as_list = list(_obfuscate_sensitive_headers(self.multi_items())) - as_dict = dict(as_list) - - no_duplicate_keys = len(as_dict) == len(as_list) - if no_duplicate_keys: - return f"{class_name}({as_dict!r}{encoding_str})" - return f"{class_name}({as_list!r}{encoding_str})" - - -class Request: - def __init__( - self, - method: str, - url: URL | str, - *, - params: QueryParamTypes | None = None, - headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, - content: RequestContent | None = None, - data: RequestData | None = None, - files: RequestFiles | None = None, - json: typing.Any | None = None, - stream: SyncByteStream | AsyncByteStream | None = None, - extensions: RequestExtensions | None = None, - ) -> None: - self.method = method.upper() - self.url = URL(url) if params is None else URL(url, params=params) - self.headers = Headers(headers) - self.extensions = {} if extensions is None else dict(extensions) - - if cookies: - Cookies(cookies).set_cookie_header(self) - - if stream is None: - content_type: str | None = self.headers.get("content-type") - headers, stream = encode_request( - content=content, - data=data, - files=files, - json=json, - boundary=get_multipart_boundary_from_content_type( - content_type=content_type.encode(self.headers.encoding) - if content_type - else None - ), - ) - self._prepare(headers) - self.stream = stream - # Load the request body, except for streaming content. - if isinstance(stream, ByteStream): - self.read() - else: - # There's an important distinction between `Request(content=...)`, - # and `Request(stream=...)`. - # - # Using `content=...` implies automatically populated `Host` and content - # headers, of either `Content-Length: ...` or `Transfer-Encoding: chunked`. - # - # Using `stream=...` will not automatically include *any* - # auto-populated headers. - # - # As an end-user you don't really need `stream=...`. It's only - # useful when: - # - # * Preserving the request stream when copying requests, eg for redirects. - # * Creating request instances on the *server-side* of the transport API. - self.stream = stream - - def _prepare(self, default_headers: dict[str, str]) -> None: - for key, value in default_headers.items(): - # Ignore Transfer-Encoding if the Content-Length has been set explicitly. - if key.lower() == "transfer-encoding" and "Content-Length" in self.headers: - continue - self.headers.setdefault(key, value) - - auto_headers: list[tuple[bytes, bytes]] = [] - - has_host = "Host" in self.headers - has_content_length = ( - "Content-Length" in self.headers or "Transfer-Encoding" in self.headers - ) - - if not has_host and self.url.host: - auto_headers.append((b"Host", self.url.netloc)) - if not has_content_length and self.method in ("POST", "PUT", "PATCH"): - auto_headers.append((b"Content-Length", b"0")) - - self.headers = Headers(auto_headers + self.headers.raw) - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - raise RequestNotRead() - return self._content - - def read(self) -> bytes: - """ - Read and return the request content. - """ - if not hasattr(self, "_content"): - assert isinstance(self.stream, typing.Iterable) - self._content = b"".join(self.stream) - if not isinstance(self.stream, ByteStream): - # If a streaming request has been read entirely into memory, then - # we can replace the stream with a raw bytes implementation, - # to ensure that any non-replayable streams can still be used. - self.stream = ByteStream(self._content) - return self._content - - async def aread(self) -> bytes: - """ - Read and return the request content. - """ - if not hasattr(self, "_content"): - assert isinstance(self.stream, typing.AsyncIterable) - self._content = b"".join([part async for part in self.stream]) - if not isinstance(self.stream, ByteStream): - # If a streaming request has been read entirely into memory, then - # we can replace the stream with a raw bytes implementation, - # to ensure that any non-replayable streams can still be used. - self.stream = ByteStream(self._content) - return self._content - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - url = str(self.url) - return f"<{class_name}({self.method!r}, {url!r})>" - - def __getstate__(self) -> dict[str, typing.Any]: - return { - name: value - for name, value in self.__dict__.items() - if name not in ["extensions", "stream"] - } - - def __setstate__(self, state: dict[str, typing.Any]) -> None: - for name, value in state.items(): - setattr(self, name, value) - self.extensions = {} - self.stream = UnattachedStream() - - -class Response: - def __init__( - self, - status_code: int, - *, - headers: HeaderTypes | None = None, - content: ResponseContent | None = None, - text: str | None = None, - html: str | None = None, - json: typing.Any = None, - stream: SyncByteStream | AsyncByteStream | None = None, - request: Request | None = None, - extensions: ResponseExtensions | None = None, - history: list[Response] | None = None, - default_encoding: str | typing.Callable[[bytes], str] = "utf-8", - ) -> None: - self.status_code = status_code - self.headers = Headers(headers) - - self._request: Request | None = request - - # When follow_redirects=False and a redirect is received, - # the client will set `response.next_request`. - self.next_request: Request | None = None - - self.extensions = {} if extensions is None else dict(extensions) - self.history = [] if history is None else list(history) - - self.is_closed = False - self.is_stream_consumed = False - - self.default_encoding = default_encoding - - if stream is None: - headers, stream = encode_response(content, text, html, json) - self._prepare(headers) - self.stream = stream - if isinstance(stream, ByteStream): - # Load the response body, except for streaming content. - self.read() - else: - # There's an important distinction between `Response(content=...)`, - # and `Response(stream=...)`. - # - # Using `content=...` implies automatically populated content headers, - # of either `Content-Length: ...` or `Transfer-Encoding: chunked`. - # - # Using `stream=...` will not automatically include any content headers. - # - # As an end-user you don't really need `stream=...`. It's only - # useful when creating response instances having received a stream - # from the transport API. - self.stream = stream - - self._num_bytes_downloaded = 0 - - def _prepare(self, default_headers: dict[str, str]) -> None: - for key, value in default_headers.items(): - # Ignore Transfer-Encoding if the Content-Length has been set explicitly. - if key.lower() == "transfer-encoding" and "content-length" in self.headers: - continue - self.headers.setdefault(key, value) - - @property - def elapsed(self) -> datetime.timedelta: - """ - Returns the time taken for the complete request/response - cycle to complete. - """ - if not hasattr(self, "_elapsed"): - raise RuntimeError( - "'.elapsed' may only be accessed after the response " - "has been read or closed." - ) - return self._elapsed - - @elapsed.setter - def elapsed(self, elapsed: datetime.timedelta) -> None: - self._elapsed = elapsed - - @property - def request(self) -> Request: - """ - Returns the request instance associated to the current response. - """ - if self._request is None: - raise RuntimeError( - "The request instance has not been set on this response." - ) - return self._request - - @request.setter - def request(self, value: Request) -> None: - self._request = value - - @property - def http_version(self) -> str: - try: - http_version: bytes = self.extensions["http_version"] - except KeyError: - return "HTTP/1.1" - else: - return http_version.decode("ascii", errors="ignore") - - @property - def reason_phrase(self) -> str: - try: - reason_phrase: bytes = self.extensions["reason_phrase"] - except KeyError: - return codes.get_reason_phrase(self.status_code) - else: - return reason_phrase.decode("ascii", errors="ignore") - - @property - def url(self) -> URL: - """ - Returns the URL for which the request was made. - """ - return self.request.url - - @property - def content(self) -> bytes: - if not hasattr(self, "_content"): - raise ResponseNotRead() - return self._content - - @property - def text(self) -> str: - if not hasattr(self, "_text"): - content = self.content - if not content: - self._text = "" - else: - decoder = TextDecoder(encoding=self.encoding or "utf-8") - self._text = "".join([decoder.decode(self.content), decoder.flush()]) - return self._text - - @property - def encoding(self) -> str | None: - """ - Return an encoding to use for decoding the byte content into text. - The priority for determining this is given by... - - * `.encoding = <>` has been set explicitly. - * The encoding as specified by the charset parameter in the Content-Type header. - * The encoding as determined by `default_encoding`, which may either be - a string like "utf-8" indicating the encoding to use, or may be a callable - which enables charset autodetection. - """ - if not hasattr(self, "_encoding"): - encoding = self.charset_encoding - if encoding is None or not _is_known_encoding(encoding): - if isinstance(self.default_encoding, str): - encoding = self.default_encoding - elif hasattr(self, "_content"): - encoding = self.default_encoding(self._content) - self._encoding = encoding or "utf-8" - return self._encoding - - @encoding.setter - def encoding(self, value: str) -> None: - """ - Set the encoding to use for decoding the byte content into text. - - If the `text` attribute has been accessed, attempting to set the - encoding will throw a ValueError. - """ - if hasattr(self, "_text"): - raise ValueError( - "Setting encoding after `text` has been accessed is not allowed." - ) - self._encoding = value - - @property - def charset_encoding(self) -> str | None: - """ - Return the encoding, as specified by the Content-Type header. - """ - content_type = self.headers.get("Content-Type") - if content_type is None: - return None - - return _parse_content_type_charset(content_type) - - def _get_content_decoder(self) -> ContentDecoder: - """ - Returns a decoder instance which can be used to decode the raw byte - content, depending on the Content-Encoding used in the response. - """ - if not hasattr(self, "_decoder"): - decoders: list[ContentDecoder] = [] - values = self.headers.get_list("content-encoding", split_commas=True) - for value in values: - value = value.strip().lower() - try: - decoder_cls = SUPPORTED_DECODERS[value] - decoders.append(decoder_cls()) - except KeyError: - continue - - if len(decoders) == 1: - self._decoder = decoders[0] - elif len(decoders) > 1: - self._decoder = MultiDecoder(children=decoders) - else: - self._decoder = IdentityDecoder() - - return self._decoder - - @property - def is_informational(self) -> bool: - """ - A property which is `True` for 1xx status codes, `False` otherwise. - """ - return codes.is_informational(self.status_code) - - @property - def is_success(self) -> bool: - """ - A property which is `True` for 2xx status codes, `False` otherwise. - """ - return codes.is_success(self.status_code) - - @property - def is_redirect(self) -> bool: - """ - A property which is `True` for 3xx status codes, `False` otherwise. - - Note that not all responses with a 3xx status code indicate a URL redirect. - - Use `response.has_redirect_location` to determine responses with a properly - formed URL redirection. - """ - return codes.is_redirect(self.status_code) - - @property - def is_client_error(self) -> bool: - """ - A property which is `True` for 4xx status codes, `False` otherwise. - """ - return codes.is_client_error(self.status_code) - - @property - def is_server_error(self) -> bool: - """ - A property which is `True` for 5xx status codes, `False` otherwise. - """ - return codes.is_server_error(self.status_code) - - @property - def is_error(self) -> bool: - """ - A property which is `True` for 4xx and 5xx status codes, `False` otherwise. - """ - return codes.is_error(self.status_code) - - @property - def has_redirect_location(self) -> bool: - """ - Returns True for 3xx responses with a properly formed URL redirection, - `False` otherwise. - """ - return ( - self.status_code - in ( - # 301 (Cacheable redirect. Method may change to GET.) - codes.MOVED_PERMANENTLY, - # 302 (Uncacheable redirect. Method may change to GET.) - codes.FOUND, - # 303 (Client should make a GET or HEAD request.) - codes.SEE_OTHER, - # 307 (Equiv. 302, but retain method) - codes.TEMPORARY_REDIRECT, - # 308 (Equiv. 301, but retain method) - codes.PERMANENT_REDIRECT, - ) - and "Location" in self.headers - ) - - def raise_for_status(self) -> Response: - """ - Raise the `HTTPStatusError` if one occurred. - """ - request = self._request - if request is None: - raise RuntimeError( - "Cannot call `raise_for_status` as the request " - "instance has not been set on this response." - ) - - if self.is_success: - return self - - if self.has_redirect_location: - message = ( - "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" - "Redirect location: '{0.headers[location]}'\n" - "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" - ) - else: - message = ( - "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" - "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" - ) - - status_class = self.status_code // 100 - error_types = { - 1: "Informational response", - 3: "Redirect response", - 4: "Client error", - 5: "Server error", - } - error_type = error_types.get(status_class, "Invalid status code") - message = message.format(self, error_type=error_type) - raise HTTPStatusError(message, request=request, response=self) - - def json(self, **kwargs: typing.Any) -> typing.Any: - return jsonlib.loads(self.content, **kwargs) - - @property - def cookies(self) -> Cookies: - if not hasattr(self, "_cookies"): - self._cookies = Cookies() - self._cookies.extract_cookies(self) - return self._cookies - - @property - def links(self) -> dict[str | None, dict[str, str]]: - """ - Returns the parsed header links of the response, if any - """ - header = self.headers.get("link") - if header is None: - return {} - - return { - (link.get("rel") or link.get("url")): link - for link in _parse_header_links(header) - } - - @property - def num_bytes_downloaded(self) -> int: - return self._num_bytes_downloaded - - def __repr__(self) -> str: - return f"" - - def __getstate__(self) -> dict[str, typing.Any]: - return { - name: value - for name, value in self.__dict__.items() - if name not in ["extensions", "stream", "is_closed", "_decoder"] - } - - def __setstate__(self, state: dict[str, typing.Any]) -> None: - for name, value in state.items(): - setattr(self, name, value) - self.is_closed = True - self.extensions = {} - self.stream = UnattachedStream() - - def read(self) -> bytes: - """ - Read and return the response content. - """ - if not hasattr(self, "_content"): - self._content = b"".join(self.iter_bytes()) - return self._content - - def iter_bytes(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, brotli, and zstd encoded responses. - """ - if hasattr(self, "_content"): - chunk_size = len(self._content) if chunk_size is None else chunk_size - for i in range(0, len(self._content), max(chunk_size, 1)): - yield self._content[i : i + chunk_size] - else: - decoder = self._get_content_decoder() - chunker = ByteChunker(chunk_size=chunk_size) - with request_context(request=self._request): - for raw_bytes in self.iter_raw(): - decoded = decoder.decode(raw_bytes) - for chunk in chunker.decode(decoded): - yield chunk - decoded = decoder.flush() - for chunk in chunker.decode(decoded): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - def iter_text(self, chunk_size: int | None = None) -> typing.Iterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - decoder = TextDecoder(encoding=self.encoding or "utf-8") - chunker = TextChunker(chunk_size=chunk_size) - with request_context(request=self._request): - for byte_content in self.iter_bytes(): - text_content = decoder.decode(byte_content) - for chunk in chunker.decode(text_content): - yield chunk - text_content = decoder.flush() - for chunk in chunker.decode(text_content): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - def iter_lines(self) -> typing.Iterator[str]: - decoder = LineDecoder() - with request_context(request=self._request): - for text in self.iter_text(): - for line in decoder.decode(text): - yield line - for line in decoder.flush(): - yield line - - def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - if self.is_stream_consumed: - raise StreamConsumed() - if self.is_closed: - raise StreamClosed() - if not isinstance(self.stream, SyncByteStream): - raise RuntimeError("Attempted to call a sync iterator on an async stream.") - - self.is_stream_consumed = True - self._num_bytes_downloaded = 0 - chunker = ByteChunker(chunk_size=chunk_size) - - with request_context(request=self._request): - for raw_stream_bytes in self.stream: - self._num_bytes_downloaded += len(raw_stream_bytes) - for chunk in chunker.decode(raw_stream_bytes): - yield chunk - - for chunk in chunker.flush(): - yield chunk - - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - if not isinstance(self.stream, SyncByteStream): - raise RuntimeError("Attempted to call an sync close on an async stream.") - - if not self.is_closed: - self.is_closed = True - with request_context(request=self._request): - self.stream.close() - - async def aread(self) -> bytes: - """ - Read and return the response content. - """ - if not hasattr(self, "_content"): - self._content = b"".join([part async for part in self.aiter_bytes()]) - return self._content - - async def aiter_bytes( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - This allows us to handle gzip, deflate, brotli, and zstd encoded responses. - """ - if hasattr(self, "_content"): - chunk_size = len(self._content) if chunk_size is None else chunk_size - for i in range(0, len(self._content), max(chunk_size, 1)): - yield self._content[i : i + chunk_size] - else: - decoder = self._get_content_decoder() - chunker = ByteChunker(chunk_size=chunk_size) - with request_context(request=self._request): - async for raw_bytes in self.aiter_raw(): - decoded = decoder.decode(raw_bytes) - for chunk in chunker.decode(decoded): - yield chunk - decoded = decoder.flush() - for chunk in chunker.decode(decoded): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - async def aiter_text( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[str]: - """ - A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - decoder = TextDecoder(encoding=self.encoding or "utf-8") - chunker = TextChunker(chunk_size=chunk_size) - with request_context(request=self._request): - async for byte_content in self.aiter_bytes(): - text_content = decoder.decode(byte_content) - for chunk in chunker.decode(text_content): - yield chunk - text_content = decoder.flush() - for chunk in chunker.decode(text_content): - yield chunk # pragma: no cover - for chunk in chunker.flush(): - yield chunk - - async def aiter_lines(self) -> typing.AsyncIterator[str]: - decoder = LineDecoder() - with request_context(request=self._request): - async for text in self.aiter_text(): - for line in decoder.decode(text): - yield line - for line in decoder.flush(): - yield line - - async def aiter_raw( - self, chunk_size: int | None = None - ) -> typing.AsyncIterator[bytes]: - """ - A byte-iterator over the raw response content. - """ - if self.is_stream_consumed: - raise StreamConsumed() - if self.is_closed: - raise StreamClosed() - if not isinstance(self.stream, AsyncByteStream): - raise RuntimeError("Attempted to call an async iterator on an sync stream.") - - self.is_stream_consumed = True - self._num_bytes_downloaded = 0 - chunker = ByteChunker(chunk_size=chunk_size) - - with request_context(request=self._request): - async for raw_stream_bytes in self.stream: - self._num_bytes_downloaded += len(raw_stream_bytes) - for chunk in chunker.decode(raw_stream_bytes): - yield chunk - - for chunk in chunker.flush(): - yield chunk - - await self.aclose() - - async def aclose(self) -> None: - """ - Close the response and release the connection. - Automatically called if the response body is read to completion. - """ - if not isinstance(self.stream, AsyncByteStream): - raise RuntimeError("Attempted to call an async close on an sync stream.") - - if not self.is_closed: - self.is_closed = True - with request_context(request=self._request): - await self.stream.aclose() - - -class Cookies(typing.MutableMapping[str, str]): - """ - HTTP Cookies, as a mutable mapping. - """ - - def __init__(self, cookies: CookieTypes | None = None) -> None: - if cookies is None or isinstance(cookies, dict): - self.jar = CookieJar() - if isinstance(cookies, dict): - for key, value in cookies.items(): - self.set(key, value) - elif isinstance(cookies, list): - self.jar = CookieJar() - for key, value in cookies: - self.set(key, value) - elif isinstance(cookies, Cookies): - self.jar = CookieJar() - for cookie in cookies.jar: - self.jar.set_cookie(cookie) - else: - self.jar = cookies - - def extract_cookies(self, response: Response) -> None: - """ - Loads any cookies based on the response `Set-Cookie` headers. - """ - urllib_response = self._CookieCompatResponse(response) - urllib_request = self._CookieCompatRequest(response.request) - - self.jar.extract_cookies(urllib_response, urllib_request) # type: ignore - - def set_cookie_header(self, request: Request) -> None: - """ - Sets an appropriate 'Cookie:' HTTP header on the `Request`. - """ - urllib_request = self._CookieCompatRequest(request) - self.jar.add_cookie_header(urllib_request) - - def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: - """ - Set a cookie value by name. May optionally include domain and path. - """ - kwargs = { - "version": 0, - "name": name, - "value": value, - "port": None, - "port_specified": False, - "domain": domain, - "domain_specified": bool(domain), - "domain_initial_dot": domain.startswith("."), - "path": path, - "path_specified": bool(path), - "secure": False, - "expires": None, - "discard": True, - "comment": None, - "comment_url": None, - "rest": {"HttpOnly": None}, - "rfc2109": False, - } - cookie = Cookie(**kwargs) # type: ignore - self.jar.set_cookie(cookie) - - def get( # type: ignore - self, - name: str, - default: str | None = None, - domain: str | None = None, - path: str | None = None, - ) -> str | None: - """ - Get a cookie by name. May optionally include domain and path - in order to specify exactly which cookie to retrieve. - """ - value = None - for cookie in self.jar: - if cookie.name == name: - if domain is None or cookie.domain == domain: - if path is None or cookie.path == path: - if value is not None: - message = f"Multiple cookies exist with name={name}" - raise CookieConflict(message) - value = cookie.value - - if value is None: - return default - return value - - def delete( - self, - name: str, - domain: str | None = None, - path: str | None = None, - ) -> None: - """ - Delete a cookie by name. May optionally include domain and path - in order to specify exactly which cookie to delete. - """ - if domain is not None and path is not None: - return self.jar.clear(domain, path, name) - - remove = [ - cookie - for cookie in self.jar - if cookie.name == name - and (domain is None or cookie.domain == domain) - and (path is None or cookie.path == path) - ] - - for cookie in remove: - self.jar.clear(cookie.domain, cookie.path, cookie.name) - - def clear(self, domain: str | None = None, path: str | None = None) -> None: - """ - Delete all cookies. Optionally include a domain and path in - order to only delete a subset of all the cookies. - """ - args = [] - if domain is not None: - args.append(domain) - if path is not None: - assert domain is not None - args.append(path) - self.jar.clear(*args) - - def update(self, cookies: CookieTypes | None = None) -> None: # type: ignore - cookies = Cookies(cookies) - for cookie in cookies.jar: - self.jar.set_cookie(cookie) - - def __setitem__(self, name: str, value: str) -> None: - return self.set(name, value) - - def __getitem__(self, name: str) -> str: - value = self.get(name) - if value is None: - raise KeyError(name) - return value - - def __delitem__(self, name: str) -> None: - return self.delete(name) - - def __len__(self) -> int: - return len(self.jar) - - def __iter__(self) -> typing.Iterator[str]: - return (cookie.name for cookie in self.jar) - - def __bool__(self) -> bool: - for _ in self.jar: - return True - return False - - def __repr__(self) -> str: - cookies_repr = ", ".join( - [ - f"" - for cookie in self.jar - ] - ) - - return f"" - - class _CookieCompatRequest(urllib.request.Request): - """ - Wraps a `Request` instance up in a compatibility interface suitable - for use with `CookieJar` operations. - """ - - def __init__(self, request: Request) -> None: - super().__init__( - url=str(request.url), - headers=dict(request.headers), - method=request.method, - ) - self.request = request - - def add_unredirected_header(self, key: str, value: str) -> None: - super().add_unredirected_header(key, value) - self.request.headers[key] = value - - class _CookieCompatResponse: - """ - Wraps a `Request` instance up in a compatibility interface suitable - for use with `CookieJar` operations. - """ - - def __init__(self, response: Response) -> None: - self.response = response - - def info(self) -> email.message.Message: - info = email.message.Message() - for key, value in self.response.headers.multi_items(): - # Note that setting `info[key]` here is an "append" operation, - # not a "replace" operation. - # https://docs.python.org/3/library/email.compat32-message.html#email.message.Message.__setitem__ - info[key] = value - return info diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_multipart.py b/backend/venv39/lib/python3.9/site-packages/httpx/_multipart.py deleted file mode 100644 index b4761af..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_multipart.py +++ /dev/null @@ -1,300 +0,0 @@ -from __future__ import annotations - -import io -import mimetypes -import os -import re -import typing -from pathlib import Path - -from ._types import ( - AsyncByteStream, - FileContent, - FileTypes, - RequestData, - RequestFiles, - SyncByteStream, -) -from ._utils import ( - peek_filelike_length, - primitive_value_to_str, - to_bytes, -) - -_HTML5_FORM_ENCODING_REPLACEMENTS = {'"': "%22", "\\": "\\\\"} -_HTML5_FORM_ENCODING_REPLACEMENTS.update( - {chr(c): "%{:02X}".format(c) for c in range(0x1F + 1) if c != 0x1B} -) -_HTML5_FORM_ENCODING_RE = re.compile( - r"|".join([re.escape(c) for c in _HTML5_FORM_ENCODING_REPLACEMENTS.keys()]) -) - - -def _format_form_param(name: str, value: str) -> bytes: - """ - Encode a name/value pair within a multipart form. - """ - - def replacer(match: typing.Match[str]) -> str: - return _HTML5_FORM_ENCODING_REPLACEMENTS[match.group(0)] - - value = _HTML5_FORM_ENCODING_RE.sub(replacer, value) - return f'{name}="{value}"'.encode() - - -def _guess_content_type(filename: str | None) -> str | None: - """ - Guesses the mimetype based on a filename. Defaults to `application/octet-stream`. - - Returns `None` if `filename` is `None` or empty. - """ - if filename: - return mimetypes.guess_type(filename)[0] or "application/octet-stream" - return None - - -def get_multipart_boundary_from_content_type( - content_type: bytes | None, -) -> bytes | None: - if not content_type or not content_type.startswith(b"multipart/form-data"): - return None - # parse boundary according to - # https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1 - if b";" in content_type: - for section in content_type.split(b";"): - if section.strip().lower().startswith(b"boundary="): - return section.strip()[len(b"boundary=") :].strip(b'"') - return None - - -class DataField: - """ - A single form field item, within a multipart form field. - """ - - def __init__(self, name: str, value: str | bytes | int | float | None) -> None: - if not isinstance(name, str): - raise TypeError( - f"Invalid type for name. Expected str, got {type(name)}: {name!r}" - ) - if value is not None and not isinstance(value, (str, bytes, int, float)): - raise TypeError( - "Invalid type for value. Expected primitive type," - f" got {type(value)}: {value!r}" - ) - self.name = name - self.value: str | bytes = ( - value if isinstance(value, bytes) else primitive_value_to_str(value) - ) - - def render_headers(self) -> bytes: - if not hasattr(self, "_headers"): - name = _format_form_param("name", self.name) - self._headers = b"".join( - [b"Content-Disposition: form-data; ", name, b"\r\n\r\n"] - ) - - return self._headers - - def render_data(self) -> bytes: - if not hasattr(self, "_data"): - self._data = to_bytes(self.value) - - return self._data - - def get_length(self) -> int: - headers = self.render_headers() - data = self.render_data() - return len(headers) + len(data) - - def render(self) -> typing.Iterator[bytes]: - yield self.render_headers() - yield self.render_data() - - -class FileField: - """ - A single file field item, within a multipart form field. - """ - - CHUNK_SIZE = 64 * 1024 - - def __init__(self, name: str, value: FileTypes) -> None: - self.name = name - - fileobj: FileContent - - headers: dict[str, str] = {} - content_type: str | None = None - - # This large tuple based API largely mirror's requests' API - # It would be good to think of better APIs for this that we could - # include in httpx 2.0 since variable length tuples(especially of 4 elements) - # are quite unwieldly - if isinstance(value, tuple): - if len(value) == 2: - # neither the 3rd parameter (content_type) nor the 4th (headers) - # was included - filename, fileobj = value - elif len(value) == 3: - filename, fileobj, content_type = value - else: - # all 4 parameters included - filename, fileobj, content_type, headers = value # type: ignore - else: - filename = Path(str(getattr(value, "name", "upload"))).name - fileobj = value - - if content_type is None: - content_type = _guess_content_type(filename) - - has_content_type_header = any("content-type" in key.lower() for key in headers) - if content_type is not None and not has_content_type_header: - # note that unlike requests, we ignore the content_type provided in the 3rd - # tuple element if it is also included in the headers requests does - # the opposite (it overwrites the headerwith the 3rd tuple element) - headers["Content-Type"] = content_type - - if isinstance(fileobj, io.StringIO): - raise TypeError( - "Multipart file uploads require 'io.BytesIO', not 'io.StringIO'." - ) - if isinstance(fileobj, io.TextIOBase): - raise TypeError( - "Multipart file uploads must be opened in binary mode, not text mode." - ) - - self.filename = filename - self.file = fileobj - self.headers = headers - - def get_length(self) -> int | None: - headers = self.render_headers() - - if isinstance(self.file, (str, bytes)): - return len(headers) + len(to_bytes(self.file)) - - file_length = peek_filelike_length(self.file) - - # If we can't determine the filesize without reading it into memory, - # then return `None` here, to indicate an unknown file length. - if file_length is None: - return None - - return len(headers) + file_length - - def render_headers(self) -> bytes: - if not hasattr(self, "_headers"): - parts = [ - b"Content-Disposition: form-data; ", - _format_form_param("name", self.name), - ] - if self.filename: - filename = _format_form_param("filename", self.filename) - parts.extend([b"; ", filename]) - for header_name, header_value in self.headers.items(): - key, val = f"\r\n{header_name}: ".encode(), header_value.encode() - parts.extend([key, val]) - parts.append(b"\r\n\r\n") - self._headers = b"".join(parts) - - return self._headers - - def render_data(self) -> typing.Iterator[bytes]: - if isinstance(self.file, (str, bytes)): - yield to_bytes(self.file) - return - - if hasattr(self.file, "seek"): - try: - self.file.seek(0) - except io.UnsupportedOperation: - pass - - chunk = self.file.read(self.CHUNK_SIZE) - while chunk: - yield to_bytes(chunk) - chunk = self.file.read(self.CHUNK_SIZE) - - def render(self) -> typing.Iterator[bytes]: - yield self.render_headers() - yield from self.render_data() - - -class MultipartStream(SyncByteStream, AsyncByteStream): - """ - Request content as streaming multipart encoded form data. - """ - - def __init__( - self, - data: RequestData, - files: RequestFiles, - boundary: bytes | None = None, - ) -> None: - if boundary is None: - boundary = os.urandom(16).hex().encode("ascii") - - self.boundary = boundary - self.content_type = "multipart/form-data; boundary=%s" % boundary.decode( - "ascii" - ) - self.fields = list(self._iter_fields(data, files)) - - def _iter_fields( - self, data: RequestData, files: RequestFiles - ) -> typing.Iterator[FileField | DataField]: - for name, value in data.items(): - if isinstance(value, (tuple, list)): - for item in value: - yield DataField(name=name, value=item) - else: - yield DataField(name=name, value=value) - - file_items = files.items() if isinstance(files, typing.Mapping) else files - for name, value in file_items: - yield FileField(name=name, value=value) - - def iter_chunks(self) -> typing.Iterator[bytes]: - for field in self.fields: - yield b"--%s\r\n" % self.boundary - yield from field.render() - yield b"\r\n" - yield b"--%s--\r\n" % self.boundary - - def get_content_length(self) -> int | None: - """ - Return the length of the multipart encoded content, or `None` if - any of the files have a length that cannot be determined upfront. - """ - boundary_length = len(self.boundary) - length = 0 - - for field in self.fields: - field_length = field.get_length() - if field_length is None: - return None - - length += 2 + boundary_length + 2 # b"--{boundary}\r\n" - length += field_length - length += 2 # b"\r\n" - - length += 2 + boundary_length + 4 # b"--{boundary}--\r\n" - return length - - # Content stream interface. - - def get_headers(self) -> dict[str, str]: - content_length = self.get_content_length() - content_type = self.content_type - if content_length is None: - return {"Transfer-Encoding": "chunked", "Content-Type": content_type} - return {"Content-Length": str(content_length), "Content-Type": content_type} - - def __iter__(self) -> typing.Iterator[bytes]: - for chunk in self.iter_chunks(): - yield chunk - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - for chunk in self.iter_chunks(): - yield chunk diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_status_codes.py b/backend/venv39/lib/python3.9/site-packages/httpx/_status_codes.py deleted file mode 100644 index 133a623..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_status_codes.py +++ /dev/null @@ -1,162 +0,0 @@ -from __future__ import annotations - -from enum import IntEnum - -__all__ = ["codes"] - - -class codes(IntEnum): - """HTTP status codes and reason phrases - - Status codes from the following RFCs are all observed: - - * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - * RFC 6585: Additional HTTP Status Codes - * RFC 3229: Delta encoding in HTTP - * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518 - * RFC 5842: Binding Extensions to WebDAV - * RFC 7238: Permanent Redirect - * RFC 2295: Transparent Content Negotiation in HTTP - * RFC 2774: An HTTP Extension Framework - * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2) - * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) - * RFC 7725: An HTTP Status Code to Report Legal Obstacles - * RFC 8297: An HTTP Status Code for Indicating Hints - * RFC 8470: Using Early Data in HTTP - """ - - def __new__(cls, value: int, phrase: str = "") -> codes: - obj = int.__new__(cls, value) - obj._value_ = value - - obj.phrase = phrase # type: ignore[attr-defined] - return obj - - def __str__(self) -> str: - return str(self.value) - - @classmethod - def get_reason_phrase(cls, value: int) -> str: - try: - return codes(value).phrase # type: ignore - except ValueError: - return "" - - @classmethod - def is_informational(cls, value: int) -> bool: - """ - Returns `True` for 1xx status codes, `False` otherwise. - """ - return 100 <= value <= 199 - - @classmethod - def is_success(cls, value: int) -> bool: - """ - Returns `True` for 2xx status codes, `False` otherwise. - """ - return 200 <= value <= 299 - - @classmethod - def is_redirect(cls, value: int) -> bool: - """ - Returns `True` for 3xx status codes, `False` otherwise. - """ - return 300 <= value <= 399 - - @classmethod - def is_client_error(cls, value: int) -> bool: - """ - Returns `True` for 4xx status codes, `False` otherwise. - """ - return 400 <= value <= 499 - - @classmethod - def is_server_error(cls, value: int) -> bool: - """ - Returns `True` for 5xx status codes, `False` otherwise. - """ - return 500 <= value <= 599 - - @classmethod - def is_error(cls, value: int) -> bool: - """ - Returns `True` for 4xx or 5xx status codes, `False` otherwise. - """ - return 400 <= value <= 599 - - # informational - CONTINUE = 100, "Continue" - SWITCHING_PROTOCOLS = 101, "Switching Protocols" - PROCESSING = 102, "Processing" - EARLY_HINTS = 103, "Early Hints" - - # success - OK = 200, "OK" - CREATED = 201, "Created" - ACCEPTED = 202, "Accepted" - NON_AUTHORITATIVE_INFORMATION = 203, "Non-Authoritative Information" - NO_CONTENT = 204, "No Content" - RESET_CONTENT = 205, "Reset Content" - PARTIAL_CONTENT = 206, "Partial Content" - MULTI_STATUS = 207, "Multi-Status" - ALREADY_REPORTED = 208, "Already Reported" - IM_USED = 226, "IM Used" - - # redirection - MULTIPLE_CHOICES = 300, "Multiple Choices" - MOVED_PERMANENTLY = 301, "Moved Permanently" - FOUND = 302, "Found" - SEE_OTHER = 303, "See Other" - NOT_MODIFIED = 304, "Not Modified" - USE_PROXY = 305, "Use Proxy" - TEMPORARY_REDIRECT = 307, "Temporary Redirect" - PERMANENT_REDIRECT = 308, "Permanent Redirect" - - # client error - BAD_REQUEST = 400, "Bad Request" - UNAUTHORIZED = 401, "Unauthorized" - PAYMENT_REQUIRED = 402, "Payment Required" - FORBIDDEN = 403, "Forbidden" - NOT_FOUND = 404, "Not Found" - METHOD_NOT_ALLOWED = 405, "Method Not Allowed" - NOT_ACCEPTABLE = 406, "Not Acceptable" - PROXY_AUTHENTICATION_REQUIRED = 407, "Proxy Authentication Required" - REQUEST_TIMEOUT = 408, "Request Timeout" - CONFLICT = 409, "Conflict" - GONE = 410, "Gone" - LENGTH_REQUIRED = 411, "Length Required" - PRECONDITION_FAILED = 412, "Precondition Failed" - REQUEST_ENTITY_TOO_LARGE = 413, "Request Entity Too Large" - REQUEST_URI_TOO_LONG = 414, "Request-URI Too Long" - UNSUPPORTED_MEDIA_TYPE = 415, "Unsupported Media Type" - REQUESTED_RANGE_NOT_SATISFIABLE = 416, "Requested Range Not Satisfiable" - EXPECTATION_FAILED = 417, "Expectation Failed" - IM_A_TEAPOT = 418, "I'm a teapot" - MISDIRECTED_REQUEST = 421, "Misdirected Request" - UNPROCESSABLE_ENTITY = 422, "Unprocessable Entity" - LOCKED = 423, "Locked" - FAILED_DEPENDENCY = 424, "Failed Dependency" - TOO_EARLY = 425, "Too Early" - UPGRADE_REQUIRED = 426, "Upgrade Required" - PRECONDITION_REQUIRED = 428, "Precondition Required" - TOO_MANY_REQUESTS = 429, "Too Many Requests" - REQUEST_HEADER_FIELDS_TOO_LARGE = 431, "Request Header Fields Too Large" - UNAVAILABLE_FOR_LEGAL_REASONS = 451, "Unavailable For Legal Reasons" - - # server errors - INTERNAL_SERVER_ERROR = 500, "Internal Server Error" - NOT_IMPLEMENTED = 501, "Not Implemented" - BAD_GATEWAY = 502, "Bad Gateway" - SERVICE_UNAVAILABLE = 503, "Service Unavailable" - GATEWAY_TIMEOUT = 504, "Gateway Timeout" - HTTP_VERSION_NOT_SUPPORTED = 505, "HTTP Version Not Supported" - VARIANT_ALSO_NEGOTIATES = 506, "Variant Also Negotiates" - INSUFFICIENT_STORAGE = 507, "Insufficient Storage" - LOOP_DETECTED = 508, "Loop Detected" - NOT_EXTENDED = 510, "Not Extended" - NETWORK_AUTHENTICATION_REQUIRED = 511, "Network Authentication Required" - - -# Include lower-case styles for `requests` compatibility. -for code in codes: - setattr(codes, code._name_.lower(), int(code)) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/__init__.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/__init__.py deleted file mode 100644 index 7a32105..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -from .asgi import * -from .base import * -from .default import * -from .mock import * -from .wsgi import * - -__all__ = [ - "ASGITransport", - "AsyncBaseTransport", - "BaseTransport", - "AsyncHTTPTransport", - "HTTPTransport", - "MockTransport", - "WSGITransport", -] diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/asgi.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/asgi.py deleted file mode 100644 index 2bc4efa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/asgi.py +++ /dev/null @@ -1,187 +0,0 @@ -from __future__ import annotations - -import typing - -from .._models import Request, Response -from .._types import AsyncByteStream -from .base import AsyncBaseTransport - -if typing.TYPE_CHECKING: # pragma: no cover - import asyncio - - import trio - - Event = typing.Union[asyncio.Event, trio.Event] - - -_Message = typing.MutableMapping[str, typing.Any] -_Receive = typing.Callable[[], typing.Awaitable[_Message]] -_Send = typing.Callable[ - [typing.MutableMapping[str, typing.Any]], typing.Awaitable[None] -] -_ASGIApp = typing.Callable[ - [typing.MutableMapping[str, typing.Any], _Receive, _Send], typing.Awaitable[None] -] - -__all__ = ["ASGITransport"] - - -def is_running_trio() -> bool: - try: - # sniffio is a dependency of trio. - - # See https://github.com/python-trio/trio/issues/2802 - import sniffio - - if sniffio.current_async_library() == "trio": - return True - except ImportError: # pragma: nocover - pass - - return False - - -def create_event() -> Event: - if is_running_trio(): - import trio - - return trio.Event() - - import asyncio - - return asyncio.Event() - - -class ASGIResponseStream(AsyncByteStream): - def __init__(self, body: list[bytes]) -> None: - self._body = body - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - yield b"".join(self._body) - - -class ASGITransport(AsyncBaseTransport): - """ - A custom AsyncTransport that handles sending requests directly to an ASGI app. - - ```python - transport = httpx.ASGITransport( - app=app, - root_path="/submount", - client=("1.2.3.4", 123) - ) - client = httpx.AsyncClient(transport=transport) - ``` - - Arguments: - - * `app` - The ASGI application. - * `raise_app_exceptions` - Boolean indicating if exceptions in the application - should be raised. Default to `True`. Can be set to `False` for use cases - such as testing the content of a client 500 response. - * `root_path` - The root path on which the ASGI application should be mounted. - * `client` - A two-tuple indicating the client IP and port of incoming requests. - ``` - """ - - def __init__( - self, - app: _ASGIApp, - raise_app_exceptions: bool = True, - root_path: str = "", - client: tuple[str, int] = ("127.0.0.1", 123), - ) -> None: - self.app = app - self.raise_app_exceptions = raise_app_exceptions - self.root_path = root_path - self.client = client - - async def handle_async_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, AsyncByteStream) - - # ASGI scope. - scope = { - "type": "http", - "asgi": {"version": "3.0"}, - "http_version": "1.1", - "method": request.method, - "headers": [(k.lower(), v) for (k, v) in request.headers.raw], - "scheme": request.url.scheme, - "path": request.url.path, - "raw_path": request.url.raw_path.split(b"?")[0], - "query_string": request.url.query, - "server": (request.url.host, request.url.port), - "client": self.client, - "root_path": self.root_path, - } - - # Request. - request_body_chunks = request.stream.__aiter__() - request_complete = False - - # Response. - status_code = None - response_headers = None - body_parts = [] - response_started = False - response_complete = create_event() - - # ASGI callables. - - async def receive() -> dict[str, typing.Any]: - nonlocal request_complete - - if request_complete: - await response_complete.wait() - return {"type": "http.disconnect"} - - try: - body = await request_body_chunks.__anext__() - except StopAsyncIteration: - request_complete = True - return {"type": "http.request", "body": b"", "more_body": False} - return {"type": "http.request", "body": body, "more_body": True} - - async def send(message: typing.MutableMapping[str, typing.Any]) -> None: - nonlocal status_code, response_headers, response_started - - if message["type"] == "http.response.start": - assert not response_started - - status_code = message["status"] - response_headers = message.get("headers", []) - response_started = True - - elif message["type"] == "http.response.body": - assert not response_complete.is_set() - body = message.get("body", b"") - more_body = message.get("more_body", False) - - if body and request.method != "HEAD": - body_parts.append(body) - - if not more_body: - response_complete.set() - - try: - await self.app(scope, receive, send) - except Exception: # noqa: PIE-786 - if self.raise_app_exceptions: - raise - - response_complete.set() - if status_code is None: - status_code = 500 - if response_headers is None: - response_headers = {} - - assert response_complete.is_set() - assert status_code is not None - assert response_headers is not None - - stream = ASGIResponseStream(body_parts) - - return Response(status_code, headers=response_headers, stream=stream) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/base.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/base.py deleted file mode 100644 index 66fd99d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/base.py +++ /dev/null @@ -1,86 +0,0 @@ -from __future__ import annotations - -import typing -from types import TracebackType - -from .._models import Request, Response - -T = typing.TypeVar("T", bound="BaseTransport") -A = typing.TypeVar("A", bound="AsyncBaseTransport") - -__all__ = ["AsyncBaseTransport", "BaseTransport"] - - -class BaseTransport: - def __enter__(self: T) -> T: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - self.close() - - def handle_request(self, request: Request) -> Response: - """ - Send a single HTTP request and return a response. - - Developers shouldn't typically ever need to call into this API directly, - since the Client class provides all the higher level user-facing API - niceties. - - In order to properly release any network resources, the response - stream should *either* be consumed immediately, with a call to - `response.stream.read()`, or else the `handle_request` call should - be followed with a try/finally block to ensuring the stream is - always closed. - - Example usage: - - with httpx.HTTPTransport() as transport: - req = httpx.Request( - method=b"GET", - url=(b"https", b"www.example.com", 443, b"/"), - headers=[(b"Host", b"www.example.com")], - ) - resp = transport.handle_request(req) - body = resp.stream.read() - print(resp.status_code, resp.headers, body) - - - Takes a `Request` instance as the only argument. - - Returns a `Response` instance. - """ - raise NotImplementedError( - "The 'handle_request' method must be implemented." - ) # pragma: no cover - - def close(self) -> None: - pass - - -class AsyncBaseTransport: - async def __aenter__(self: A) -> A: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - await self.aclose() - - async def handle_async_request( - self, - request: Request, - ) -> Response: - raise NotImplementedError( - "The 'handle_async_request' method must be implemented." - ) # pragma: no cover - - async def aclose(self) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/default.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/default.py deleted file mode 100644 index d5aa05f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/default.py +++ /dev/null @@ -1,406 +0,0 @@ -""" -Custom transports, with nicely configured defaults. - -The following additional keyword arguments are currently supported by httpcore... - -* uds: str -* local_address: str -* retries: int - -Example usages... - -# Disable HTTP/2 on a single specific domain. -mounts = { - "all://": httpx.HTTPTransport(http2=True), - "all://*example.org": httpx.HTTPTransport() -} - -# Using advanced httpcore configuration, with connection retries. -transport = httpx.HTTPTransport(retries=1) -client = httpx.Client(transport=transport) - -# Using advanced httpcore configuration, with unix domain sockets. -transport = httpx.HTTPTransport(uds="socket.uds") -client = httpx.Client(transport=transport) -""" - -from __future__ import annotations - -import contextlib -import typing -from types import TracebackType - -if typing.TYPE_CHECKING: - import ssl # pragma: no cover - - import httpx # pragma: no cover - -from .._config import DEFAULT_LIMITS, Limits, Proxy, create_ssl_context -from .._exceptions import ( - ConnectError, - ConnectTimeout, - LocalProtocolError, - NetworkError, - PoolTimeout, - ProtocolError, - ProxyError, - ReadError, - ReadTimeout, - RemoteProtocolError, - TimeoutException, - UnsupportedProtocol, - WriteError, - WriteTimeout, -) -from .._models import Request, Response -from .._types import AsyncByteStream, CertTypes, ProxyTypes, SyncByteStream -from .._urls import URL -from .base import AsyncBaseTransport, BaseTransport - -T = typing.TypeVar("T", bound="HTTPTransport") -A = typing.TypeVar("A", bound="AsyncHTTPTransport") - -SOCKET_OPTION = typing.Union[ - typing.Tuple[int, int, int], - typing.Tuple[int, int, typing.Union[bytes, bytearray]], - typing.Tuple[int, int, None, int], -] - -__all__ = ["AsyncHTTPTransport", "HTTPTransport"] - -HTTPCORE_EXC_MAP: dict[type[Exception], type[httpx.HTTPError]] = {} - - -def _load_httpcore_exceptions() -> dict[type[Exception], type[httpx.HTTPError]]: - import httpcore - - return { - httpcore.TimeoutException: TimeoutException, - httpcore.ConnectTimeout: ConnectTimeout, - httpcore.ReadTimeout: ReadTimeout, - httpcore.WriteTimeout: WriteTimeout, - httpcore.PoolTimeout: PoolTimeout, - httpcore.NetworkError: NetworkError, - httpcore.ConnectError: ConnectError, - httpcore.ReadError: ReadError, - httpcore.WriteError: WriteError, - httpcore.ProxyError: ProxyError, - httpcore.UnsupportedProtocol: UnsupportedProtocol, - httpcore.ProtocolError: ProtocolError, - httpcore.LocalProtocolError: LocalProtocolError, - httpcore.RemoteProtocolError: RemoteProtocolError, - } - - -@contextlib.contextmanager -def map_httpcore_exceptions() -> typing.Iterator[None]: - global HTTPCORE_EXC_MAP - if len(HTTPCORE_EXC_MAP) == 0: - HTTPCORE_EXC_MAP = _load_httpcore_exceptions() - try: - yield - except Exception as exc: - mapped_exc = None - - for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): - if not isinstance(exc, from_exc): - continue - # We want to map to the most specific exception we can find. - # Eg if `exc` is an `httpcore.ReadTimeout`, we want to map to - # `httpx.ReadTimeout`, not just `httpx.TimeoutException`. - if mapped_exc is None or issubclass(to_exc, mapped_exc): - mapped_exc = to_exc - - if mapped_exc is None: # pragma: no cover - raise - - message = str(exc) - raise mapped_exc(message) from exc - - -class ResponseStream(SyncByteStream): - def __init__(self, httpcore_stream: typing.Iterable[bytes]) -> None: - self._httpcore_stream = httpcore_stream - - def __iter__(self) -> typing.Iterator[bytes]: - with map_httpcore_exceptions(): - for part in self._httpcore_stream: - yield part - - def close(self) -> None: - if hasattr(self._httpcore_stream, "close"): - self._httpcore_stream.close() - - -class HTTPTransport(BaseTransport): - def __init__( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - proxy: ProxyTypes | None = None, - uds: str | None = None, - local_address: str | None = None, - retries: int = 0, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - import httpcore - - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) - - if proxy is None: - self._pool = httpcore.ConnectionPool( - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - uds=uds, - local_address=local_address, - retries=retries, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("http", "https"): - self._pool = httpcore.HTTPProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - proxy_headers=proxy.headers.raw, - ssl_context=ssl_context, - proxy_ssl_context=proxy.ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("socks5", "socks5h"): - try: - import socksio # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using SOCKS proxy, but the 'socksio' package is not installed. " - "Make sure to install httpx using `pip install httpx[socks]`." - ) from None - - self._pool = httpcore.SOCKSProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - ) - else: # pragma: no cover - raise ValueError( - "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," - f" but got {proxy.url.scheme!r}." - ) - - def __enter__(self: T) -> T: # Use generics for subclass support. - self._pool.__enter__() - return self - - def __exit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - with map_httpcore_exceptions(): - self._pool.__exit__(exc_type, exc_value, traceback) - - def handle_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, SyncByteStream) - import httpcore - - req = httpcore.Request( - method=request.method, - url=httpcore.URL( - scheme=request.url.raw_scheme, - host=request.url.raw_host, - port=request.url.port, - target=request.url.raw_path, - ), - headers=request.headers.raw, - content=request.stream, - extensions=request.extensions, - ) - with map_httpcore_exceptions(): - resp = self._pool.handle_request(req) - - assert isinstance(resp.stream, typing.Iterable) - - return Response( - status_code=resp.status, - headers=resp.headers, - stream=ResponseStream(resp.stream), - extensions=resp.extensions, - ) - - def close(self) -> None: - self._pool.close() - - -class AsyncResponseStream(AsyncByteStream): - def __init__(self, httpcore_stream: typing.AsyncIterable[bytes]) -> None: - self._httpcore_stream = httpcore_stream - - async def __aiter__(self) -> typing.AsyncIterator[bytes]: - with map_httpcore_exceptions(): - async for part in self._httpcore_stream: - yield part - - async def aclose(self) -> None: - if hasattr(self._httpcore_stream, "aclose"): - await self._httpcore_stream.aclose() - - -class AsyncHTTPTransport(AsyncBaseTransport): - def __init__( - self, - verify: ssl.SSLContext | str | bool = True, - cert: CertTypes | None = None, - trust_env: bool = True, - http1: bool = True, - http2: bool = False, - limits: Limits = DEFAULT_LIMITS, - proxy: ProxyTypes | None = None, - uds: str | None = None, - local_address: str | None = None, - retries: int = 0, - socket_options: typing.Iterable[SOCKET_OPTION] | None = None, - ) -> None: - import httpcore - - proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy - ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) - - if proxy is None: - self._pool = httpcore.AsyncConnectionPool( - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - uds=uds, - local_address=local_address, - retries=retries, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("http", "https"): - self._pool = httpcore.AsyncHTTPProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - proxy_headers=proxy.headers.raw, - proxy_ssl_context=proxy.ssl_context, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - socket_options=socket_options, - ) - elif proxy.url.scheme in ("socks5", "socks5h"): - try: - import socksio # noqa - except ImportError: # pragma: no cover - raise ImportError( - "Using SOCKS proxy, but the 'socksio' package is not installed. " - "Make sure to install httpx using `pip install httpx[socks]`." - ) from None - - self._pool = httpcore.AsyncSOCKSProxy( - proxy_url=httpcore.URL( - scheme=proxy.url.raw_scheme, - host=proxy.url.raw_host, - port=proxy.url.port, - target=proxy.url.raw_path, - ), - proxy_auth=proxy.raw_auth, - ssl_context=ssl_context, - max_connections=limits.max_connections, - max_keepalive_connections=limits.max_keepalive_connections, - keepalive_expiry=limits.keepalive_expiry, - http1=http1, - http2=http2, - ) - else: # pragma: no cover - raise ValueError( - "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," - " but got {proxy.url.scheme!r}." - ) - - async def __aenter__(self: A) -> A: # Use generics for subclass support. - await self._pool.__aenter__() - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None = None, - exc_value: BaseException | None = None, - traceback: TracebackType | None = None, - ) -> None: - with map_httpcore_exceptions(): - await self._pool.__aexit__(exc_type, exc_value, traceback) - - async def handle_async_request( - self, - request: Request, - ) -> Response: - assert isinstance(request.stream, AsyncByteStream) - import httpcore - - req = httpcore.Request( - method=request.method, - url=httpcore.URL( - scheme=request.url.raw_scheme, - host=request.url.raw_host, - port=request.url.port, - target=request.url.raw_path, - ), - headers=request.headers.raw, - content=request.stream, - extensions=request.extensions, - ) - with map_httpcore_exceptions(): - resp = await self._pool.handle_async_request(req) - - assert isinstance(resp.stream, typing.AsyncIterable) - - return Response( - status_code=resp.status, - headers=resp.headers, - stream=AsyncResponseStream(resp.stream), - extensions=resp.extensions, - ) - - async def aclose(self) -> None: - await self._pool.aclose() diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/mock.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/mock.py deleted file mode 100644 index 8c418f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/mock.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -import typing - -from .._models import Request, Response -from .base import AsyncBaseTransport, BaseTransport - -SyncHandler = typing.Callable[[Request], Response] -AsyncHandler = typing.Callable[[Request], typing.Coroutine[None, None, Response]] - - -__all__ = ["MockTransport"] - - -class MockTransport(AsyncBaseTransport, BaseTransport): - def __init__(self, handler: SyncHandler | AsyncHandler) -> None: - self.handler = handler - - def handle_request( - self, - request: Request, - ) -> Response: - request.read() - response = self.handler(request) - if not isinstance(response, Response): # pragma: no cover - raise TypeError("Cannot use an async handler in a sync Client") - return response - - async def handle_async_request( - self, - request: Request, - ) -> Response: - await request.aread() - response = self.handler(request) - - # Allow handler to *optionally* be an `async` function. - # If it is, then the `response` variable need to be awaited to actually - # return the result. - - if not isinstance(response, Response): - response = await response - - return response diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/wsgi.py b/backend/venv39/lib/python3.9/site-packages/httpx/_transports/wsgi.py deleted file mode 100644 index 8592ffe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_transports/wsgi.py +++ /dev/null @@ -1,149 +0,0 @@ -from __future__ import annotations - -import io -import itertools -import sys -import typing - -from .._models import Request, Response -from .._types import SyncByteStream -from .base import BaseTransport - -if typing.TYPE_CHECKING: - from _typeshed import OptExcInfo # pragma: no cover - from _typeshed.wsgi import WSGIApplication # pragma: no cover - -_T = typing.TypeVar("_T") - - -__all__ = ["WSGITransport"] - - -def _skip_leading_empty_chunks(body: typing.Iterable[_T]) -> typing.Iterable[_T]: - body = iter(body) - for chunk in body: - if chunk: - return itertools.chain([chunk], body) - return [] - - -class WSGIByteStream(SyncByteStream): - def __init__(self, result: typing.Iterable[bytes]) -> None: - self._close = getattr(result, "close", None) - self._result = _skip_leading_empty_chunks(result) - - def __iter__(self) -> typing.Iterator[bytes]: - for part in self._result: - yield part - - def close(self) -> None: - if self._close is not None: - self._close() - - -class WSGITransport(BaseTransport): - """ - A custom transport that handles sending requests directly to an WSGI app. - The simplest way to use this functionality is to use the `app` argument. - - ``` - client = httpx.Client(app=app) - ``` - - Alternatively, you can setup the transport instance explicitly. - This allows you to include any additional configuration arguments specific - to the WSGITransport class: - - ``` - transport = httpx.WSGITransport( - app=app, - script_name="/submount", - remote_addr="1.2.3.4" - ) - client = httpx.Client(transport=transport) - ``` - - Arguments: - - * `app` - The WSGI application. - * `raise_app_exceptions` - Boolean indicating if exceptions in the application - should be raised. Default to `True`. Can be set to `False` for use cases - such as testing the content of a client 500 response. - * `script_name` - The root path on which the WSGI application should be mounted. - * `remote_addr` - A string indicating the client IP of incoming requests. - ``` - """ - - def __init__( - self, - app: WSGIApplication, - raise_app_exceptions: bool = True, - script_name: str = "", - remote_addr: str = "127.0.0.1", - wsgi_errors: typing.TextIO | None = None, - ) -> None: - self.app = app - self.raise_app_exceptions = raise_app_exceptions - self.script_name = script_name - self.remote_addr = remote_addr - self.wsgi_errors = wsgi_errors - - def handle_request(self, request: Request) -> Response: - request.read() - wsgi_input = io.BytesIO(request.content) - - port = request.url.port or {"http": 80, "https": 443}[request.url.scheme] - environ = { - "wsgi.version": (1, 0), - "wsgi.url_scheme": request.url.scheme, - "wsgi.input": wsgi_input, - "wsgi.errors": self.wsgi_errors or sys.stderr, - "wsgi.multithread": True, - "wsgi.multiprocess": False, - "wsgi.run_once": False, - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": self.script_name, - "PATH_INFO": request.url.path, - "QUERY_STRING": request.url.query.decode("ascii"), - "SERVER_NAME": request.url.host, - "SERVER_PORT": str(port), - "SERVER_PROTOCOL": "HTTP/1.1", - "REMOTE_ADDR": self.remote_addr, - } - for header_key, header_value in request.headers.raw: - key = header_key.decode("ascii").upper().replace("-", "_") - if key not in ("CONTENT_TYPE", "CONTENT_LENGTH"): - key = "HTTP_" + key - environ[key] = header_value.decode("ascii") - - seen_status = None - seen_response_headers = None - seen_exc_info = None - - def start_response( - status: str, - response_headers: list[tuple[str, str]], - exc_info: OptExcInfo | None = None, - ) -> typing.Callable[[bytes], typing.Any]: - nonlocal seen_status, seen_response_headers, seen_exc_info - seen_status = status - seen_response_headers = response_headers - seen_exc_info = exc_info - return lambda _: None - - result = self.app(environ, start_response) - - stream = WSGIByteStream(result) - - assert seen_status is not None - assert seen_response_headers is not None - if seen_exc_info and seen_exc_info[0] and self.raise_app_exceptions: - raise seen_exc_info[1] - - status_code = int(seen_status.split()[0]) - headers = [ - (key.encode("ascii"), value.encode("ascii")) - for key, value in seen_response_headers - ] - - return Response(status_code, headers=headers, stream=stream) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_types.py b/backend/venv39/lib/python3.9/site-packages/httpx/_types.py deleted file mode 100644 index 704dfdf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_types.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -Type definitions for type checking purposes. -""" - -from http.cookiejar import CookieJar -from typing import ( - IO, - TYPE_CHECKING, - Any, - AsyncIterable, - AsyncIterator, - Callable, - Dict, - Iterable, - Iterator, - List, - Mapping, - Optional, - Sequence, - Tuple, - Union, -) - -if TYPE_CHECKING: # pragma: no cover - from ._auth import Auth # noqa: F401 - from ._config import Proxy, Timeout # noqa: F401 - from ._models import Cookies, Headers, Request # noqa: F401 - from ._urls import URL, QueryParams # noqa: F401 - - -PrimitiveData = Optional[Union[str, int, float, bool]] - -URLTypes = Union["URL", str] - -QueryParamTypes = Union[ - "QueryParams", - Mapping[str, Union[PrimitiveData, Sequence[PrimitiveData]]], - List[Tuple[str, PrimitiveData]], - Tuple[Tuple[str, PrimitiveData], ...], - str, - bytes, -] - -HeaderTypes = Union[ - "Headers", - Mapping[str, str], - Mapping[bytes, bytes], - Sequence[Tuple[str, str]], - Sequence[Tuple[bytes, bytes]], -] - -CookieTypes = Union["Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]] - -TimeoutTypes = Union[ - Optional[float], - Tuple[Optional[float], Optional[float], Optional[float], Optional[float]], - "Timeout", -] -ProxyTypes = Union["URL", str, "Proxy"] -CertTypes = Union[str, Tuple[str, str], Tuple[str, str, str]] - -AuthTypes = Union[ - Tuple[Union[str, bytes], Union[str, bytes]], - Callable[["Request"], "Request"], - "Auth", -] - -RequestContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] -ResponseContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] -ResponseExtensions = Mapping[str, Any] - -RequestData = Mapping[str, Any] - -FileContent = Union[IO[bytes], bytes, str] -FileTypes = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] - -RequestExtensions = Mapping[str, Any] - -__all__ = ["AsyncByteStream", "SyncByteStream"] - - -class SyncByteStream: - def __iter__(self) -> Iterator[bytes]: - raise NotImplementedError( - "The '__iter__' method must be implemented." - ) # pragma: no cover - yield b"" # pragma: no cover - - def close(self) -> None: - """ - Subclasses can override this method to release any network resources - after a request/response cycle is complete. - """ - - -class AsyncByteStream: - async def __aiter__(self) -> AsyncIterator[bytes]: - raise NotImplementedError( - "The '__aiter__' method must be implemented." - ) # pragma: no cover - yield b"" # pragma: no cover - - async def aclose(self) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_urlparse.py b/backend/venv39/lib/python3.9/site-packages/httpx/_urlparse.py deleted file mode 100644 index bf190fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_urlparse.py +++ /dev/null @@ -1,527 +0,0 @@ -""" -An implementation of `urlparse` that provides URL validation and normalization -as described by RFC3986. - -We rely on this implementation rather than the one in Python's stdlib, because: - -* It provides more complete URL validation. -* It properly differentiates between an empty querystring and an absent querystring, - to distinguish URLs with a trailing '?'. -* It handles scheme, hostname, port, and path normalization. -* It supports IDNA hostnames, normalizing them to their encoded form. -* The API supports passing individual components, as well as the complete URL string. - -Previously we relied on the excellent `rfc3986` package to handle URL parsing and -validation, but this module provides a simpler alternative, with less indirection -required. -""" - -from __future__ import annotations - -import ipaddress -import re -import typing - -import idna - -from ._exceptions import InvalidURL - -MAX_URL_LENGTH = 65536 - -# https://datatracker.ietf.org/doc/html/rfc3986.html#section-2.3 -UNRESERVED_CHARACTERS = ( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" -) -SUB_DELIMS = "!$&'()*+,;=" - -PERCENT_ENCODED_REGEX = re.compile("%[A-Fa-f0-9]{2}") - -# https://url.spec.whatwg.org/#percent-encoded-bytes - -# The fragment percent-encode set is the C0 control percent-encode set -# and U+0020 SPACE, U+0022 ("), U+003C (<), U+003E (>), and U+0060 (`). -FRAG_SAFE = "".join( - [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x3C, 0x3E, 0x60)] -) - -# The query percent-encode set is the C0 control percent-encode set -# and U+0020 SPACE, U+0022 ("), U+0023 (#), U+003C (<), and U+003E (>). -QUERY_SAFE = "".join( - [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E)] -) - -# The path percent-encode set is the query percent-encode set -# and U+003F (?), U+0060 (`), U+007B ({), and U+007D (}). -PATH_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + (0x3F, 0x60, 0x7B, 0x7D) - ] -) - -# The userinfo percent-encode set is the path percent-encode set -# and U+002F (/), U+003A (:), U+003B (;), U+003D (=), U+0040 (@), -# U+005B ([) to U+005E (^), inclusive, and U+007C (|). -USERNAME_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) -PASSWORD_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) -# Note... The terminology 'userinfo' percent-encode set in the WHATWG document -# is used for the username and password quoting. For the joint userinfo component -# we remove U+003A (:) from the safe set. -USERINFO_SAFE = "".join( - [ - chr(i) - for i in range(0x20, 0x7F) - if i - not in (0x20, 0x22, 0x23, 0x3C, 0x3E) - + (0x3F, 0x60, 0x7B, 0x7D) - + (0x2F, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) - ] -) - - -# {scheme}: (optional) -# //{authority} (optional) -# {path} -# ?{query} (optional) -# #{fragment} (optional) -URL_REGEX = re.compile( - ( - r"(?:(?P{scheme}):)?" - r"(?://(?P{authority}))?" - r"(?P{path})" - r"(?:\?(?P{query}))?" - r"(?:#(?P{fragment}))?" - ).format( - scheme="([a-zA-Z][a-zA-Z0-9+.-]*)?", - authority="[^/?#]*", - path="[^?#]*", - query="[^#]*", - fragment=".*", - ) -) - -# {userinfo}@ (optional) -# {host} -# :{port} (optional) -AUTHORITY_REGEX = re.compile( - ( - r"(?:(?P{userinfo})@)?" r"(?P{host})" r":?(?P{port})?" - ).format( - userinfo=".*", # Any character sequence. - host="(\\[.*\\]|[^:@]*)", # Either any character sequence excluding ':' or '@', - # or an IPv6 address enclosed within square brackets. - port=".*", # Any character sequence. - ) -) - - -# If we call urlparse with an individual component, then we need to regex -# validate that component individually. -# Note that we're duplicating the same strings as above. Shock! Horror!! -COMPONENT_REGEX = { - "scheme": re.compile("([a-zA-Z][a-zA-Z0-9+.-]*)?"), - "authority": re.compile("[^/?#]*"), - "path": re.compile("[^?#]*"), - "query": re.compile("[^#]*"), - "fragment": re.compile(".*"), - "userinfo": re.compile("[^@]*"), - "host": re.compile("(\\[.*\\]|[^:]*)"), - "port": re.compile(".*"), -} - - -# We use these simple regexs as a first pass before handing off to -# the stdlib 'ipaddress' module for IP address validation. -IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") -IPv6_STYLE_HOSTNAME = re.compile(r"^\[.*\]$") - - -class ParseResult(typing.NamedTuple): - scheme: str - userinfo: str - host: str - port: int | None - path: str - query: str | None - fragment: str | None - - @property - def authority(self) -> str: - return "".join( - [ - f"{self.userinfo}@" if self.userinfo else "", - f"[{self.host}]" if ":" in self.host else self.host, - f":{self.port}" if self.port is not None else "", - ] - ) - - @property - def netloc(self) -> str: - return "".join( - [ - f"[{self.host}]" if ":" in self.host else self.host, - f":{self.port}" if self.port is not None else "", - ] - ) - - def copy_with(self, **kwargs: str | None) -> ParseResult: - if not kwargs: - return self - - defaults = { - "scheme": self.scheme, - "authority": self.authority, - "path": self.path, - "query": self.query, - "fragment": self.fragment, - } - defaults.update(kwargs) - return urlparse("", **defaults) - - def __str__(self) -> str: - authority = self.authority - return "".join( - [ - f"{self.scheme}:" if self.scheme else "", - f"//{authority}" if authority else "", - self.path, - f"?{self.query}" if self.query is not None else "", - f"#{self.fragment}" if self.fragment is not None else "", - ] - ) - - -def urlparse(url: str = "", **kwargs: str | None) -> ParseResult: - # Initial basic checks on allowable URLs. - # --------------------------------------- - - # Hard limit the maximum allowable URL length. - if len(url) > MAX_URL_LENGTH: - raise InvalidURL("URL too long") - - # If a URL includes any ASCII control characters including \t, \r, \n, - # then treat it as invalid. - if any(char.isascii() and not char.isprintable() for char in url): - char = next(char for char in url if char.isascii() and not char.isprintable()) - idx = url.find(char) - error = ( - f"Invalid non-printable ASCII character in URL, {char!r} at position {idx}." - ) - raise InvalidURL(error) - - # Some keyword arguments require special handling. - # ------------------------------------------------ - - # Coerce "port" to a string, if it is provided as an integer. - if "port" in kwargs: - port = kwargs["port"] - kwargs["port"] = str(port) if isinstance(port, int) else port - - # Replace "netloc" with "host and "port". - if "netloc" in kwargs: - netloc = kwargs.pop("netloc") or "" - kwargs["host"], _, kwargs["port"] = netloc.partition(":") - - # Replace "username" and/or "password" with "userinfo". - if "username" in kwargs or "password" in kwargs: - username = quote(kwargs.pop("username", "") or "", safe=USERNAME_SAFE) - password = quote(kwargs.pop("password", "") or "", safe=PASSWORD_SAFE) - kwargs["userinfo"] = f"{username}:{password}" if password else username - - # Replace "raw_path" with "path" and "query". - if "raw_path" in kwargs: - raw_path = kwargs.pop("raw_path") or "" - kwargs["path"], seperator, kwargs["query"] = raw_path.partition("?") - if not seperator: - kwargs["query"] = None - - # Ensure that IPv6 "host" addresses are always escaped with "[...]". - if "host" in kwargs: - host = kwargs.get("host") or "" - if ":" in host and not (host.startswith("[") and host.endswith("]")): - kwargs["host"] = f"[{host}]" - - # If any keyword arguments are provided, ensure they are valid. - # ------------------------------------------------------------- - - for key, value in kwargs.items(): - if value is not None: - if len(value) > MAX_URL_LENGTH: - raise InvalidURL(f"URL component '{key}' too long") - - # If a component includes any ASCII control characters including \t, \r, \n, - # then treat it as invalid. - if any(char.isascii() and not char.isprintable() for char in value): - char = next( - char for char in value if char.isascii() and not char.isprintable() - ) - idx = value.find(char) - error = ( - f"Invalid non-printable ASCII character in URL {key} component, " - f"{char!r} at position {idx}." - ) - raise InvalidURL(error) - - # Ensure that keyword arguments match as a valid regex. - if not COMPONENT_REGEX[key].fullmatch(value): - raise InvalidURL(f"Invalid URL component '{key}'") - - # The URL_REGEX will always match, but may have empty components. - url_match = URL_REGEX.match(url) - assert url_match is not None - url_dict = url_match.groupdict() - - # * 'scheme', 'authority', and 'path' may be empty strings. - # * 'query' may be 'None', indicating no trailing "?" portion. - # Any string including the empty string, indicates a trailing "?". - # * 'fragment' may be 'None', indicating no trailing "#" portion. - # Any string including the empty string, indicates a trailing "#". - scheme = kwargs.get("scheme", url_dict["scheme"]) or "" - authority = kwargs.get("authority", url_dict["authority"]) or "" - path = kwargs.get("path", url_dict["path"]) or "" - query = kwargs.get("query", url_dict["query"]) - frag = kwargs.get("fragment", url_dict["fragment"]) - - # The AUTHORITY_REGEX will always match, but may have empty components. - authority_match = AUTHORITY_REGEX.match(authority) - assert authority_match is not None - authority_dict = authority_match.groupdict() - - # * 'userinfo' and 'host' may be empty strings. - # * 'port' may be 'None'. - userinfo = kwargs.get("userinfo", authority_dict["userinfo"]) or "" - host = kwargs.get("host", authority_dict["host"]) or "" - port = kwargs.get("port", authority_dict["port"]) - - # Normalize and validate each component. - # We end up with a parsed representation of the URL, - # with components that are plain ASCII bytestrings. - parsed_scheme: str = scheme.lower() - parsed_userinfo: str = quote(userinfo, safe=USERINFO_SAFE) - parsed_host: str = encode_host(host) - parsed_port: int | None = normalize_port(port, scheme) - - has_scheme = parsed_scheme != "" - has_authority = ( - parsed_userinfo != "" or parsed_host != "" or parsed_port is not None - ) - validate_path(path, has_scheme=has_scheme, has_authority=has_authority) - if has_scheme or has_authority: - path = normalize_path(path) - - parsed_path: str = quote(path, safe=PATH_SAFE) - parsed_query: str | None = None if query is None else quote(query, safe=QUERY_SAFE) - parsed_frag: str | None = None if frag is None else quote(frag, safe=FRAG_SAFE) - - # The parsed ASCII bytestrings are our canonical form. - # All properties of the URL are derived from these. - return ParseResult( - parsed_scheme, - parsed_userinfo, - parsed_host, - parsed_port, - parsed_path, - parsed_query, - parsed_frag, - ) - - -def encode_host(host: str) -> str: - if not host: - return "" - - elif IPv4_STYLE_HOSTNAME.match(host): - # Validate IPv4 hostnames like #.#.#.# - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet - try: - ipaddress.IPv4Address(host) - except ipaddress.AddressValueError: - raise InvalidURL(f"Invalid IPv4 address: {host!r}") - return host - - elif IPv6_STYLE_HOSTNAME.match(host): - # Validate IPv6 hostnames like [...] - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # "A host identified by an Internet Protocol literal address, version 6 - # [RFC3513] or later, is distinguished by enclosing the IP literal - # within square brackets ("[" and "]"). This is the only place where - # square bracket characters are allowed in the URI syntax." - try: - ipaddress.IPv6Address(host[1:-1]) - except ipaddress.AddressValueError: - raise InvalidURL(f"Invalid IPv6 address: {host!r}") - return host[1:-1] - - elif host.isascii(): - # Regular ASCII hostnames - # - # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 - # - # reg-name = *( unreserved / pct-encoded / sub-delims ) - WHATWG_SAFE = '"`{}%|\\' - return quote(host.lower(), safe=SUB_DELIMS + WHATWG_SAFE) - - # IDNA hostnames - try: - return idna.encode(host.lower()).decode("ascii") - except idna.IDNAError: - raise InvalidURL(f"Invalid IDNA hostname: {host!r}") - - -def normalize_port(port: str | int | None, scheme: str) -> int | None: - # From https://tools.ietf.org/html/rfc3986#section-3.2.3 - # - # "A scheme may define a default port. For example, the "http" scheme - # defines a default port of "80", corresponding to its reserved TCP - # port number. The type of port designated by the port number (e.g., - # TCP, UDP, SCTP) is defined by the URI scheme. URI producers and - # normalizers should omit the port component and its ":" delimiter if - # port is empty or if its value would be the same as that of the - # scheme's default." - if port is None or port == "": - return None - - try: - port_as_int = int(port) - except ValueError: - raise InvalidURL(f"Invalid port: {port!r}") - - # See https://url.spec.whatwg.org/#url-miscellaneous - default_port = {"ftp": 21, "http": 80, "https": 443, "ws": 80, "wss": 443}.get( - scheme - ) - if port_as_int == default_port: - return None - return port_as_int - - -def validate_path(path: str, has_scheme: bool, has_authority: bool) -> None: - """ - Path validation rules that depend on if the URL contains - a scheme or authority component. - - See https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3 - """ - if has_authority: - # If a URI contains an authority component, then the path component - # must either be empty or begin with a slash ("/") character." - if path and not path.startswith("/"): - raise InvalidURL("For absolute URLs, path must be empty or begin with '/'") - - if not has_scheme and not has_authority: - # If a URI does not contain an authority component, then the path cannot begin - # with two slash characters ("//"). - if path.startswith("//"): - raise InvalidURL("Relative URLs cannot have a path starting with '//'") - - # In addition, a URI reference (Section 4.1) may be a relative-path reference, - # in which case the first path segment cannot contain a colon (":") character. - if path.startswith(":"): - raise InvalidURL("Relative URLs cannot have a path starting with ':'") - - -def normalize_path(path: str) -> str: - """ - Drop "." and ".." segments from a URL path. - - For example: - - normalize_path("/path/./to/somewhere/..") == "/path/to" - """ - # Fast return when no '.' characters in the path. - if "." not in path: - return path - - components = path.split("/") - - # Fast return when no '.' or '..' components in the path. - if "." not in components and ".." not in components: - return path - - # https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 - output: list[str] = [] - for component in components: - if component == ".": - pass - elif component == "..": - if output and output != [""]: - output.pop() - else: - output.append(component) - return "/".join(output) - - -def PERCENT(string: str) -> str: - return "".join([f"%{byte:02X}" for byte in string.encode("utf-8")]) - - -def percent_encoded(string: str, safe: str) -> str: - """ - Use percent-encoding to quote a string. - """ - NON_ESCAPED_CHARS = UNRESERVED_CHARACTERS + safe - - # Fast path for strings that don't need escaping. - if not string.rstrip(NON_ESCAPED_CHARS): - return string - - return "".join( - [char if char in NON_ESCAPED_CHARS else PERCENT(char) for char in string] - ) - - -def quote(string: str, safe: str) -> str: - """ - Use percent-encoding to quote a string, omitting existing '%xx' escape sequences. - - See: https://www.rfc-editor.org/rfc/rfc3986#section-2.1 - - * `string`: The string to be percent-escaped. - * `safe`: A string containing characters that may be treated as safe, and do not - need to be escaped. Unreserved characters are always treated as safe. - See: https://www.rfc-editor.org/rfc/rfc3986#section-2.3 - """ - parts = [] - current_position = 0 - for match in re.finditer(PERCENT_ENCODED_REGEX, string): - start_position, end_position = match.start(), match.end() - matched_text = match.group(0) - # Add any text up to the '%xx' escape sequence. - if start_position != current_position: - leading_text = string[current_position:start_position] - parts.append(percent_encoded(leading_text, safe=safe)) - - # Add the '%xx' escape sequence. - parts.append(matched_text) - current_position = end_position - - # Add any text after the final '%xx' escape sequence. - if current_position != len(string): - trailing_text = string[current_position:] - parts.append(percent_encoded(trailing_text, safe=safe)) - - return "".join(parts) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_urls.py b/backend/venv39/lib/python3.9/site-packages/httpx/_urls.py deleted file mode 100644 index 147a8fa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_urls.py +++ /dev/null @@ -1,641 +0,0 @@ -from __future__ import annotations - -import typing -from urllib.parse import parse_qs, unquote, urlencode - -import idna - -from ._types import QueryParamTypes -from ._urlparse import urlparse -from ._utils import primitive_value_to_str - -__all__ = ["URL", "QueryParams"] - - -class URL: - """ - url = httpx.URL("HTTPS://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink") - - assert url.scheme == "https" - assert url.username == "jo@email.com" - assert url.password == "a secret" - assert url.userinfo == b"jo%40email.com:a%20secret" - assert url.host == "müller.de" - assert url.raw_host == b"xn--mller-kva.de" - assert url.port == 1234 - assert url.netloc == b"xn--mller-kva.de:1234" - assert url.path == "/pa th" - assert url.query == b"?search=ab" - assert url.raw_path == b"/pa%20th?search=ab" - assert url.fragment == "anchorlink" - - The components of a URL are broken down like this: - - https://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink - [scheme] [ username ] [password] [ host ][port][ path ] [ query ] [fragment] - [ userinfo ] [ netloc ][ raw_path ] - - Note that: - - * `url.scheme` is normalized to always be lowercased. - - * `url.host` is normalized to always be lowercased. Internationalized domain - names are represented in unicode, without IDNA encoding applied. For instance: - - url = httpx.URL("http://中国.icom.museum") - assert url.host == "中国.icom.museum" - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.host == "中国.icom.museum" - - * `url.raw_host` is normalized to always be lowercased, and is IDNA encoded. - - url = httpx.URL("http://中国.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - * `url.port` is either None or an integer. URLs that include the default port for - "http", "https", "ws", "wss", and "ftp" schemes have their port - normalized to `None`. - - assert httpx.URL("http://example.com") == httpx.URL("http://example.com:80") - assert httpx.URL("http://example.com").port is None - assert httpx.URL("http://example.com:80").port is None - - * `url.userinfo` is raw bytes, without URL escaping. Usually you'll want to work - with `url.username` and `url.password` instead, which handle the URL escaping. - - * `url.raw_path` is raw bytes of both the path and query, without URL escaping. - This portion is used as the target when constructing HTTP requests. Usually you'll - want to work with `url.path` instead. - - * `url.query` is raw bytes, without URL escaping. A URL query string portion can - only be properly URL escaped when decoding the parameter names and values - themselves. - """ - - def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None: - if kwargs: - allowed = { - "scheme": str, - "username": str, - "password": str, - "userinfo": bytes, - "host": str, - "port": int, - "netloc": bytes, - "path": str, - "query": bytes, - "raw_path": bytes, - "fragment": str, - "params": object, - } - - # Perform type checking for all supported keyword arguments. - for key, value in kwargs.items(): - if key not in allowed: - message = f"{key!r} is an invalid keyword argument for URL()" - raise TypeError(message) - if value is not None and not isinstance(value, allowed[key]): - expected = allowed[key].__name__ - seen = type(value).__name__ - message = f"Argument {key!r} must be {expected} but got {seen}" - raise TypeError(message) - if isinstance(value, bytes): - kwargs[key] = value.decode("ascii") - - if "params" in kwargs: - # Replace any "params" keyword with the raw "query" instead. - # - # Ensure that empty params use `kwargs["query"] = None` rather - # than `kwargs["query"] = ""`, so that generated URLs do not - # include an empty trailing "?". - params = kwargs.pop("params") - kwargs["query"] = None if not params else str(QueryParams(params)) - - if isinstance(url, str): - self._uri_reference = urlparse(url, **kwargs) - elif isinstance(url, URL): - self._uri_reference = url._uri_reference.copy_with(**kwargs) - else: - raise TypeError( - "Invalid type for url. Expected str or httpx.URL," - f" got {type(url)}: {url!r}" - ) - - @property - def scheme(self) -> str: - """ - The URL scheme, such as "http", "https". - Always normalised to lowercase. - """ - return self._uri_reference.scheme - - @property - def raw_scheme(self) -> bytes: - """ - The raw bytes representation of the URL scheme, such as b"http", b"https". - Always normalised to lowercase. - """ - return self._uri_reference.scheme.encode("ascii") - - @property - def userinfo(self) -> bytes: - """ - The URL userinfo as a raw bytestring. - For example: b"jo%40email.com:a%20secret". - """ - return self._uri_reference.userinfo.encode("ascii") - - @property - def username(self) -> str: - """ - The URL username as a string, with URL decoding applied. - For example: "jo@email.com" - """ - userinfo = self._uri_reference.userinfo - return unquote(userinfo.partition(":")[0]) - - @property - def password(self) -> str: - """ - The URL password as a string, with URL decoding applied. - For example: "a secret" - """ - userinfo = self._uri_reference.userinfo - return unquote(userinfo.partition(":")[2]) - - @property - def host(self) -> str: - """ - The URL host as a string. - Always normalized to lowercase, with IDNA hosts decoded into unicode. - - Examples: - - url = httpx.URL("http://www.EXAMPLE.org") - assert url.host == "www.example.org" - - url = httpx.URL("http://中国.icom.museum") - assert url.host == "中国.icom.museum" - - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.host == "中国.icom.museum" - - url = httpx.URL("https://[::ffff:192.168.0.1]") - assert url.host == "::ffff:192.168.0.1" - """ - host: str = self._uri_reference.host - - if host.startswith("xn--"): - host = idna.decode(host) - - return host - - @property - def raw_host(self) -> bytes: - """ - The raw bytes representation of the URL host. - Always normalized to lowercase, and IDNA encoded. - - Examples: - - url = httpx.URL("http://www.EXAMPLE.org") - assert url.raw_host == b"www.example.org" - - url = httpx.URL("http://中国.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - url = httpx.URL("http://xn--fiqs8s.icom.museum") - assert url.raw_host == b"xn--fiqs8s.icom.museum" - - url = httpx.URL("https://[::ffff:192.168.0.1]") - assert url.raw_host == b"::ffff:192.168.0.1" - """ - return self._uri_reference.host.encode("ascii") - - @property - def port(self) -> int | None: - """ - The URL port as an integer. - - Note that the URL class performs port normalization as per the WHATWG spec. - Default ports for "http", "https", "ws", "wss", and "ftp" schemes are always - treated as `None`. - - For example: - - assert httpx.URL("http://www.example.com") == httpx.URL("http://www.example.com:80") - assert httpx.URL("http://www.example.com:80").port is None - """ - return self._uri_reference.port - - @property - def netloc(self) -> bytes: - """ - Either `` or `:` as bytes. - Always normalized to lowercase, and IDNA encoded. - - This property may be used for generating the value of a request - "Host" header. - """ - return self._uri_reference.netloc.encode("ascii") - - @property - def path(self) -> str: - """ - The URL path as a string. Excluding the query string, and URL decoded. - - For example: - - url = httpx.URL("https://example.com/pa%20th") - assert url.path == "/pa th" - """ - path = self._uri_reference.path or "/" - return unquote(path) - - @property - def query(self) -> bytes: - """ - The URL query string, as raw bytes, excluding the leading b"?". - - This is necessarily a bytewise interface, because we cannot - perform URL decoding of this representation until we've parsed - the keys and values into a QueryParams instance. - - For example: - - url = httpx.URL("https://example.com/?filter=some%20search%20terms") - assert url.query == b"filter=some%20search%20terms" - """ - query = self._uri_reference.query or "" - return query.encode("ascii") - - @property - def params(self) -> QueryParams: - """ - The URL query parameters, neatly parsed and packaged into an immutable - multidict representation. - """ - return QueryParams(self._uri_reference.query) - - @property - def raw_path(self) -> bytes: - """ - The complete URL path and query string as raw bytes. - Used as the target when constructing HTTP requests. - - For example: - - GET /users?search=some%20text HTTP/1.1 - Host: www.example.org - Connection: close - """ - path = self._uri_reference.path or "/" - if self._uri_reference.query is not None: - path += "?" + self._uri_reference.query - return path.encode("ascii") - - @property - def fragment(self) -> str: - """ - The URL fragments, as used in HTML anchors. - As a string, without the leading '#'. - """ - return unquote(self._uri_reference.fragment or "") - - @property - def is_absolute_url(self) -> bool: - """ - Return `True` for absolute URLs such as 'http://example.com/path', - and `False` for relative URLs such as '/path'. - """ - # We don't use `.is_absolute` from `rfc3986` because it treats - # URLs with a fragment portion as not absolute. - # What we actually care about is if the URL provides - # a scheme and hostname to which connections should be made. - return bool(self._uri_reference.scheme and self._uri_reference.host) - - @property - def is_relative_url(self) -> bool: - """ - Return `False` for absolute URLs such as 'http://example.com/path', - and `True` for relative URLs such as '/path'. - """ - return not self.is_absolute_url - - def copy_with(self, **kwargs: typing.Any) -> URL: - """ - Copy this URL, returning a new URL with some components altered. - Accepts the same set of parameters as the components that are made - available via properties on the `URL` class. - - For example: - - url = httpx.URL("https://www.example.com").copy_with( - username="jo@gmail.com", password="a secret" - ) - assert url == "https://jo%40email.com:a%20secret@www.example.com" - """ - return URL(self, **kwargs) - - def copy_set_param(self, key: str, value: typing.Any = None) -> URL: - return self.copy_with(params=self.params.set(key, value)) - - def copy_add_param(self, key: str, value: typing.Any = None) -> URL: - return self.copy_with(params=self.params.add(key, value)) - - def copy_remove_param(self, key: str) -> URL: - return self.copy_with(params=self.params.remove(key)) - - def copy_merge_params(self, params: QueryParamTypes) -> URL: - return self.copy_with(params=self.params.merge(params)) - - def join(self, url: URL | str) -> URL: - """ - Return an absolute URL, using this URL as the base. - - Eg. - - url = httpx.URL("https://www.example.com/test") - url = url.join("/new/path") - assert url == "https://www.example.com/new/path" - """ - from urllib.parse import urljoin - - return URL(urljoin(str(self), str(URL(url)))) - - def __hash__(self) -> int: - return hash(str(self)) - - def __eq__(self, other: typing.Any) -> bool: - return isinstance(other, (URL, str)) and str(self) == str(URL(other)) - - def __str__(self) -> str: - return str(self._uri_reference) - - def __repr__(self) -> str: - scheme, userinfo, host, port, path, query, fragment = self._uri_reference - - if ":" in userinfo: - # Mask any password component. - userinfo = f'{userinfo.split(":")[0]}:[secure]' - - authority = "".join( - [ - f"{userinfo}@" if userinfo else "", - f"[{host}]" if ":" in host else host, - f":{port}" if port is not None else "", - ] - ) - url = "".join( - [ - f"{self.scheme}:" if scheme else "", - f"//{authority}" if authority else "", - path, - f"?{query}" if query is not None else "", - f"#{fragment}" if fragment is not None else "", - ] - ) - - return f"{self.__class__.__name__}({url!r})" - - @property - def raw(self) -> tuple[bytes, bytes, int, bytes]: # pragma: nocover - import collections - import warnings - - warnings.warn("URL.raw is deprecated.") - RawURL = collections.namedtuple( - "RawURL", ["raw_scheme", "raw_host", "port", "raw_path"] - ) - return RawURL( - raw_scheme=self.raw_scheme, - raw_host=self.raw_host, - port=self.port, - raw_path=self.raw_path, - ) - - -class QueryParams(typing.Mapping[str, str]): - """ - URL query parameters, as a multi-dict. - """ - - def __init__(self, *args: QueryParamTypes | None, **kwargs: typing.Any) -> None: - assert len(args) < 2, "Too many arguments." - assert not (args and kwargs), "Cannot mix named and unnamed arguments." - - value = args[0] if args else kwargs - - if value is None or isinstance(value, (str, bytes)): - value = value.decode("ascii") if isinstance(value, bytes) else value - self._dict = parse_qs(value, keep_blank_values=True) - elif isinstance(value, QueryParams): - self._dict = {k: list(v) for k, v in value._dict.items()} - else: - dict_value: dict[typing.Any, list[typing.Any]] = {} - if isinstance(value, (list, tuple)): - # Convert list inputs like: - # [("a", "123"), ("a", "456"), ("b", "789")] - # To a dict representation, like: - # {"a": ["123", "456"], "b": ["789"]} - for item in value: - dict_value.setdefault(item[0], []).append(item[1]) - else: - # Convert dict inputs like: - # {"a": "123", "b": ["456", "789"]} - # To dict inputs where values are always lists, like: - # {"a": ["123"], "b": ["456", "789"]} - dict_value = { - k: list(v) if isinstance(v, (list, tuple)) else [v] - for k, v in value.items() - } - - # Ensure that keys and values are neatly coerced to strings. - # We coerce values `True` and `False` to JSON-like "true" and "false" - # representations, and coerce `None` values to the empty string. - self._dict = { - str(k): [primitive_value_to_str(item) for item in v] - for k, v in dict_value.items() - } - - def keys(self) -> typing.KeysView[str]: - """ - Return all the keys in the query params. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.keys()) == ["a", "b"] - """ - return self._dict.keys() - - def values(self) -> typing.ValuesView[str]: - """ - Return all the values in the query params. If a key occurs more than once - only the first item for that key is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.values()) == ["123", "789"] - """ - return {k: v[0] for k, v in self._dict.items()}.values() - - def items(self) -> typing.ItemsView[str, str]: - """ - Return all items in the query params. If a key occurs more than once - only the first item for that key is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.items()) == [("a", "123"), ("b", "789")] - """ - return {k: v[0] for k, v in self._dict.items()}.items() - - def multi_items(self) -> list[tuple[str, str]]: - """ - Return all items in the query params. Allow duplicate keys to occur. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert list(q.multi_items()) == [("a", "123"), ("a", "456"), ("b", "789")] - """ - multi_items: list[tuple[str, str]] = [] - for k, v in self._dict.items(): - multi_items.extend([(k, i) for i in v]) - return multi_items - - def get(self, key: typing.Any, default: typing.Any = None) -> typing.Any: - """ - Get a value from the query param for a given key. If the key occurs - more than once, then only the first value is returned. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert q.get("a") == "123" - """ - if key in self._dict: - return self._dict[str(key)][0] - return default - - def get_list(self, key: str) -> list[str]: - """ - Get all values from the query param for a given key. - - Usage: - - q = httpx.QueryParams("a=123&a=456&b=789") - assert q.get_list("a") == ["123", "456"] - """ - return list(self._dict.get(str(key), [])) - - def set(self, key: str, value: typing.Any = None) -> QueryParams: - """ - Return a new QueryParams instance, setting the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.set("a", "456") - assert q == httpx.QueryParams("a=456") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict[str(key)] = [primitive_value_to_str(value)] - return q - - def add(self, key: str, value: typing.Any = None) -> QueryParams: - """ - Return a new QueryParams instance, setting or appending the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.add("a", "456") - assert q == httpx.QueryParams("a=123&a=456") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict[str(key)] = q.get_list(key) + [primitive_value_to_str(value)] - return q - - def remove(self, key: str) -> QueryParams: - """ - Return a new QueryParams instance, removing the value of a key. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.remove("a") - assert q == httpx.QueryParams("") - """ - q = QueryParams() - q._dict = dict(self._dict) - q._dict.pop(str(key), None) - return q - - def merge(self, params: QueryParamTypes | None = None) -> QueryParams: - """ - Return a new QueryParams instance, updated with. - - Usage: - - q = httpx.QueryParams("a=123") - q = q.merge({"b": "456"}) - assert q == httpx.QueryParams("a=123&b=456") - - q = httpx.QueryParams("a=123") - q = q.merge({"a": "456", "b": "789"}) - assert q == httpx.QueryParams("a=456&b=789") - """ - q = QueryParams(params) - q._dict = {**self._dict, **q._dict} - return q - - def __getitem__(self, key: typing.Any) -> str: - return self._dict[key][0] - - def __contains__(self, key: typing.Any) -> bool: - return key in self._dict - - def __iter__(self) -> typing.Iterator[typing.Any]: - return iter(self.keys()) - - def __len__(self) -> int: - return len(self._dict) - - def __bool__(self) -> bool: - return bool(self._dict) - - def __hash__(self) -> int: - return hash(str(self)) - - def __eq__(self, other: typing.Any) -> bool: - if not isinstance(other, self.__class__): - return False - return sorted(self.multi_items()) == sorted(other.multi_items()) - - def __str__(self) -> str: - return urlencode(self.multi_items()) - - def __repr__(self) -> str: - class_name = self.__class__.__name__ - query_string = str(self) - return f"{class_name}({query_string!r})" - - def update(self, params: QueryParamTypes | None = None) -> None: - raise RuntimeError( - "QueryParams are immutable since 0.18.0. " - "Use `q = q.merge(...)` to create an updated copy." - ) - - def __setitem__(self, key: str, value: str) -> None: - raise RuntimeError( - "QueryParams are immutable since 0.18.0. " - "Use `q = q.set(key, value)` to create an updated copy." - ) diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/_utils.py b/backend/venv39/lib/python3.9/site-packages/httpx/_utils.py deleted file mode 100644 index 7fe827d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/httpx/_utils.py +++ /dev/null @@ -1,242 +0,0 @@ -from __future__ import annotations - -import ipaddress -import os -import re -import typing -from urllib.request import getproxies - -from ._types import PrimitiveData - -if typing.TYPE_CHECKING: # pragma: no cover - from ._urls import URL - - -def primitive_value_to_str(value: PrimitiveData) -> str: - """ - Coerce a primitive data type into a string value. - - Note that we prefer JSON-style 'true'/'false' for boolean values here. - """ - if value is True: - return "true" - elif value is False: - return "false" - elif value is None: - return "" - return str(value) - - -def get_environment_proxies() -> dict[str, str | None]: - """Gets proxy information from the environment""" - - # urllib.request.getproxies() falls back on System - # Registry and Config for proxies on Windows and macOS. - # We don't want to propagate non-HTTP proxies into - # our configuration such as 'TRAVIS_APT_PROXY'. - proxy_info = getproxies() - mounts: dict[str, str | None] = {} - - for scheme in ("http", "https", "all"): - if proxy_info.get(scheme): - hostname = proxy_info[scheme] - mounts[f"{scheme}://"] = ( - hostname if "://" in hostname else f"http://{hostname}" - ) - - no_proxy_hosts = [host.strip() for host in proxy_info.get("no", "").split(",")] - for hostname in no_proxy_hosts: - # See https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html for details - # on how names in `NO_PROXY` are handled. - if hostname == "*": - # If NO_PROXY=* is used or if "*" occurs as any one of the comma - # separated hostnames, then we should just bypass any information - # from HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and always ignore - # proxies. - return {} - elif hostname: - # NO_PROXY=.google.com is marked as "all://*.google.com, - # which disables "www.google.com" but not "google.com" - # NO_PROXY=google.com is marked as "all://*google.com, - # which disables "www.google.com" and "google.com". - # (But not "wwwgoogle.com") - # NO_PROXY can include domains, IPv6, IPv4 addresses and "localhost" - # NO_PROXY=example.com,::1,localhost,192.168.0.0/16 - if "://" in hostname: - mounts[hostname] = None - elif is_ipv4_hostname(hostname): - mounts[f"all://{hostname}"] = None - elif is_ipv6_hostname(hostname): - mounts[f"all://[{hostname}]"] = None - elif hostname.lower() == "localhost": - mounts[f"all://{hostname}"] = None - else: - mounts[f"all://*{hostname}"] = None - - return mounts - - -def to_bytes(value: str | bytes, encoding: str = "utf-8") -> bytes: - return value.encode(encoding) if isinstance(value, str) else value - - -def to_str(value: str | bytes, encoding: str = "utf-8") -> str: - return value if isinstance(value, str) else value.decode(encoding) - - -def to_bytes_or_str(value: str, match_type_of: typing.AnyStr) -> typing.AnyStr: - return value if isinstance(match_type_of, str) else value.encode() - - -def unquote(value: str) -> str: - return value[1:-1] if value[0] == value[-1] == '"' else value - - -def peek_filelike_length(stream: typing.Any) -> int | None: - """ - Given a file-like stream object, return its length in number of bytes - without reading it into memory. - """ - try: - # Is it an actual file? - fd = stream.fileno() - # Yup, seems to be an actual file. - length = os.fstat(fd).st_size - except (AttributeError, OSError): - # No... Maybe it's something that supports random access, like `io.BytesIO`? - try: - # Assuming so, go to end of stream to figure out its length, - # then put it back in place. - offset = stream.tell() - length = stream.seek(0, os.SEEK_END) - stream.seek(offset) - except (AttributeError, OSError): - # Not even that? Sorry, we're doomed... - return None - - return length - - -class URLPattern: - """ - A utility class currently used for making lookups against proxy keys... - - # Wildcard matching... - >>> pattern = URLPattern("all://") - >>> pattern.matches(httpx.URL("http://example.com")) - True - - # Witch scheme matching... - >>> pattern = URLPattern("https://") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - False - - # With domain matching... - >>> pattern = URLPattern("https://example.com") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - False - >>> pattern.matches(httpx.URL("https://other.com")) - False - - # Wildcard scheme, with domain matching... - >>> pattern = URLPattern("all://example.com") - >>> pattern.matches(httpx.URL("https://example.com")) - True - >>> pattern.matches(httpx.URL("http://example.com")) - True - >>> pattern.matches(httpx.URL("https://other.com")) - False - - # With port matching... - >>> pattern = URLPattern("https://example.com:1234") - >>> pattern.matches(httpx.URL("https://example.com:1234")) - True - >>> pattern.matches(httpx.URL("https://example.com")) - False - """ - - def __init__(self, pattern: str) -> None: - from ._urls import URL - - if pattern and ":" not in pattern: - raise ValueError( - f"Proxy keys should use proper URL forms rather " - f"than plain scheme strings. " - f'Instead of "{pattern}", use "{pattern}://"' - ) - - url = URL(pattern) - self.pattern = pattern - self.scheme = "" if url.scheme == "all" else url.scheme - self.host = "" if url.host == "*" else url.host - self.port = url.port - if not url.host or url.host == "*": - self.host_regex: typing.Pattern[str] | None = None - elif url.host.startswith("*."): - # *.example.com should match "www.example.com", but not "example.com" - domain = re.escape(url.host[2:]) - self.host_regex = re.compile(f"^.+\\.{domain}$") - elif url.host.startswith("*"): - # *example.com should match "www.example.com" and "example.com" - domain = re.escape(url.host[1:]) - self.host_regex = re.compile(f"^(.+\\.)?{domain}$") - else: - # example.com should match "example.com" but not "www.example.com" - domain = re.escape(url.host) - self.host_regex = re.compile(f"^{domain}$") - - def matches(self, other: URL) -> bool: - if self.scheme and self.scheme != other.scheme: - return False - if ( - self.host - and self.host_regex is not None - and not self.host_regex.match(other.host) - ): - return False - if self.port is not None and self.port != other.port: - return False - return True - - @property - def priority(self) -> tuple[int, int, int]: - """ - The priority allows URLPattern instances to be sortable, so that - we can match from most specific to least specific. - """ - # URLs with a port should take priority over URLs without a port. - port_priority = 0 if self.port is not None else 1 - # Longer hostnames should match first. - host_priority = -len(self.host) - # Longer schemes should match first. - scheme_priority = -len(self.scheme) - return (port_priority, host_priority, scheme_priority) - - def __hash__(self) -> int: - return hash(self.pattern) - - def __lt__(self, other: URLPattern) -> bool: - return self.priority < other.priority - - def __eq__(self, other: typing.Any) -> bool: - return isinstance(other, URLPattern) and self.pattern == other.pattern - - -def is_ipv4_hostname(hostname: str) -> bool: - try: - ipaddress.IPv4Address(hostname.split("/")[0]) - except Exception: - return False - return True - - -def is_ipv6_hostname(hostname: str) -> bool: - try: - ipaddress.IPv6Address(hostname.split("/")[0]) - except Exception: - return False - return True diff --git a/backend/venv39/lib/python3.9/site-packages/httpx/py.typed b/backend/venv39/lib/python3.9/site-packages/httpx/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/METADATA deleted file mode 100644 index 7a4a4b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/METADATA +++ /dev/null @@ -1,209 +0,0 @@ -Metadata-Version: 2.4 -Name: idna -Version: 3.11 -Summary: Internationalized Domain Names in Applications (IDNA) -Author-email: Kim Davies -Requires-Python: >=3.8 -Description-Content-Type: text/x-rst -License-Expression: BSD-3-Clause -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: Name Service (DNS) -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Utilities -License-File: LICENSE.md -Requires-Dist: ruff >= 0.6.2 ; extra == "all" -Requires-Dist: mypy >= 1.11.2 ; extra == "all" -Requires-Dist: pytest >= 8.3.2 ; extra == "all" -Requires-Dist: flake8 >= 7.1.1 ; extra == "all" -Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst -Project-URL: Issue tracker, https://github.com/kjd/idna/issues -Project-URL: Source, https://github.com/kjd/idna -Provides-Extra: all - -Internationalized Domain Names in Applications (IDNA) -===================================================== - -Support for `Internationalized Domain Names in -Applications (IDNA) `_ -and `Unicode IDNA Compatibility Processing -`_. - -The latest versions of these standards supplied here provide -more comprehensive language coverage and reduce the potential of -allowing domains with known security vulnerabilities. This library -is a suitable replacement for the “encodings.idna” -module that comes with the Python standard library, but which -only supports an older superseded IDNA specification from 2003. - -Basic functions are simply executed: - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - - -Installation ------------- - -This package is available for installation from PyPI via the -typical mechanisms, such as: - -.. code-block:: bash - - $ python3 -m pip install idna - - -Usage ------ - -For typical usage, the ``encode`` and ``decode`` functions will take a -domain name argument and perform a conversion to ASCII compatible encoding -(known as A-labels), or to Unicode strings (known as U-labels) -respectively. - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - -Conversions can be applied at a per-label basis using the ``ulabel`` or -``alabel`` functions if necessary: - -.. code-block:: pycon - - >>> idna.alabel('测试') - b'xn--0zwm56d' - - -Compatibility Mapping (UTS #46) -+++++++++++++++++++++++++++++++ - -This library provides support for `Unicode IDNA Compatibility -Processing `_ which normalizes input from -different potential ways a user may input a domain prior to performing the IDNA -conversion operations. This functionality, known as a -`mapping `_, is considered by the -specification to be a local user-interface issue distinct from IDNA -conversion functionality. - -For example, “Königsgäßchen” is not a permissible label as *LATIN -CAPITAL LETTER K* is not allowed (nor are capital letters in general). -UTS 46 will convert this into lower case prior to applying the IDNA -conversion. - -.. code-block:: pycon - - >>> import idna - >>> idna.encode('Königsgäßchen') - ... - idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed - >>> idna.encode('Königsgäßchen', uts46=True) - b'xn--knigsgchen-b4a3dun' - >>> print(idna.decode('xn--knigsgchen-b4a3dun')) - königsgäßchen - - -Exceptions ----------- - -All errors raised during the conversion following the specification -should raise an exception derived from the ``idna.IDNAError`` base -class. - -More specific exceptions that may be generated as ``idna.IDNABidiError`` -when the error reflects an illegal combination of left-to-right and -right-to-left characters in a label; ``idna.InvalidCodepoint`` when -a specific codepoint is an illegal character in an IDN label (i.e. -INVALID); and ``idna.InvalidCodepointContext`` when the codepoint is -illegal based on its position in the string (i.e. it is CONTEXTO or CONTEXTJ -but the contextual requirements are not satisfied.) - -Building and Diagnostics ------------------------- - -The IDNA and UTS 46 functionality relies upon pre-calculated lookup -tables for performance. These tables are derived from computing against -eligibility criteria in the respective standards using the command-line -script ``tools/idna-data``. - -This tool will fetch relevant codepoint data from the Unicode repository -and perform the required calculations to identify eligibility. There are -three main modes: - -* ``idna-data make-libdata``. Generates ``idnadata.py`` and - ``uts46data.py``, the pre-calculated lookup tables used for IDNA and - UTS 46 conversions. Implementers who wish to track this library against - a different Unicode version may use this tool to manually generate a - different version of the ``idnadata.py`` and ``uts46data.py`` files. - -* ``idna-data make-table``. Generate a table of the IDNA disposition - (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix - B.1 of RFC 5892 and the pre-computed tables published by `IANA - `_. - -* ``idna-data U+0061``. Prints debugging output on the various - properties associated with an individual Unicode codepoint (in this - case, U+0061), that are used to assess the IDNA and UTS 46 status of a - codepoint. This is helpful in debugging or analysis. - -The tool accepts a number of arguments, described using ``idna-data --h``. Most notably, the ``--version`` argument allows the specification -of the version of Unicode to be used in computing the table data. For -example, ``idna-data --version 9.0.0 make-libdata`` will generate -library data against Unicode 9.0.0. - - -Additional Notes ----------------- - -* **Packages**. The latest tagged release version is published in the - `Python Package Index `_. - -* **Version support**. This library supports Python 3.8 and higher. - As this library serves as a low-level toolkit for a variety of - applications, many of which strive for broad compatibility with older - Python versions, there is no rush to remove older interpreter support. - Support for older versions are likely to be removed from new releases - as automated tests can no longer easily be run, i.e. once the Python - version is officially end-of-life. - -* **Testing**. The library has a test suite based on each rule of the - IDNA specification, as well as tests that are provided as part of the - Unicode Technical Standard 46, `Unicode IDNA Compatibility Processing - `_. - -* **Emoji**. It is an occasional request to support emoji domains in - this library. Encoding of symbols like emoji is expressly prohibited by - the technical standard IDNA 2008 and emoji domains are broadly phased - out across the domain industry due to associated security risks. For - now, applications that need to support these non-compliant labels - may wish to consider trying the encode/decode operation in this library - first, and then falling back to using `encodings.idna`. See `the Github - project `_ for more discussion. - -* **Transitional processing**. Unicode 16.0.0 removed transitional - processing so the `transitional` argument for the encode() method - no longer has any effect and will be removed at a later date. - diff --git a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/RECORD deleted file mode 100644 index e5d3088..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/RECORD +++ /dev/null @@ -1,22 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/codec.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/core.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/idnadata.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/intranges.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/package_data.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/idna/uts46data.cpython-39.pyc,, -idna-3.11.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -idna-3.11.dist-info/METADATA,sha256=fCwSww9SuiN8TIHllFSASUQCW55hAs8dzKnr9RaEEbA,8378 -idna-3.11.dist-info/RECORD,, -idna-3.11.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 -idna-3.11.dist-info/licenses/LICENSE.md,sha256=t6M2q_OwThgOwGXN0W5wXQeeHMehT5EKpukYfza5zYc,1541 -idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 -idna/codec.py,sha256=M2SGWN7cs_6B32QmKTyTN6xQGZeYQgQ2wiX3_DR6loE,3438 -idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316 -idna/core.py,sha256=P26_XVycuMTZ1R2mNK1ZREVzM5mvTzdabBXfyZVU1Lc,13246 -idna/idnadata.py,sha256=SG8jhaGE53iiD6B49pt2pwTv_UvClciWE-N54oR2p4U,79623 -idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898 -idna/package_data.py,sha256=_CUavOxobnbyNG2FLyHoN8QHP3QM9W1tKuw7eq9QwBk,21 -idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -idna/uts46data.py,sha256=H9J35VkD0F9L9mKOqjeNGd2A-Va6FlPoz6Jz4K7h-ps,243725 diff --git a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/WHEEL deleted file mode 100644 index d8b9936..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: flit 3.12.0 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/licenses/LICENSE.md b/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/licenses/LICENSE.md deleted file mode 100644 index 256ba90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna-3.11.dist-info/licenses/LICENSE.md +++ /dev/null @@ -1,31 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2013-2025, Kim Davies and contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/backend/venv39/lib/python3.9/site-packages/idna/__init__.py b/backend/venv39/lib/python3.9/site-packages/idna/__init__.py deleted file mode 100644 index cfdc030..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -from .core import ( - IDNABidiError, - IDNAError, - InvalidCodepoint, - InvalidCodepointContext, - alabel, - check_bidi, - check_hyphen_ok, - check_initial_combiner, - check_label, - check_nfc, - decode, - encode, - ulabel, - uts46_remap, - valid_contextj, - valid_contexto, - valid_label_length, - valid_string_length, -) -from .intranges import intranges_contain -from .package_data import __version__ - -__all__ = [ - "__version__", - "IDNABidiError", - "IDNAError", - "InvalidCodepoint", - "InvalidCodepointContext", - "alabel", - "check_bidi", - "check_hyphen_ok", - "check_initial_combiner", - "check_label", - "check_nfc", - "decode", - "encode", - "intranges_contain", - "ulabel", - "uts46_remap", - "valid_contextj", - "valid_contexto", - "valid_label_length", - "valid_string_length", -] diff --git a/backend/venv39/lib/python3.9/site-packages/idna/codec.py b/backend/venv39/lib/python3.9/site-packages/idna/codec.py deleted file mode 100644 index cbc2e4f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/codec.py +++ /dev/null @@ -1,122 +0,0 @@ -import codecs -import re -from typing import Any, Optional, Tuple - -from .core import IDNAError, alabel, decode, encode, ulabel - -_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") - - -class Codec(codecs.Codec): - def encode(self, data: str, errors: str = "strict") -> Tuple[bytes, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return b"", 0 - - return encode(data), len(data) - - def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return "", 0 - - return decode(data), len(data) - - -class IncrementalEncoder(codecs.BufferedIncrementalEncoder): - def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return b"", 0 - - labels = _unicode_dots_re.split(data) - trailing_dot = b"" - if labels: - if not labels[-1]: - trailing_dot = b"." - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = b"." - - result = [] - size = 0 - for label in labels: - result.append(alabel(label)) - if size: - size += 1 - size += len(label) - - # Join with U+002E - result_bytes = b".".join(result) + trailing_dot - size += len(trailing_dot) - return result_bytes, size - - -class IncrementalDecoder(codecs.BufferedIncrementalDecoder): - def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]: - if errors != "strict": - raise IDNAError('Unsupported error handling "{}"'.format(errors)) - - if not data: - return ("", 0) - - if not isinstance(data, str): - data = str(data, "ascii") - - labels = _unicode_dots_re.split(data) - trailing_dot = "" - if labels: - if not labels[-1]: - trailing_dot = "." - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = "." - - result = [] - size = 0 - for label in labels: - result.append(ulabel(label)) - if size: - size += 1 - size += len(label) - - result_str = ".".join(result) + trailing_dot - size += len(trailing_dot) - return (result_str, size) - - -class StreamWriter(Codec, codecs.StreamWriter): - pass - - -class StreamReader(Codec, codecs.StreamReader): - pass - - -def search_function(name: str) -> Optional[codecs.CodecInfo]: - if name != "idna2008": - return None - return codecs.CodecInfo( - name=name, - encode=Codec().encode, - decode=Codec().decode, # type: ignore - incrementalencoder=IncrementalEncoder, - incrementaldecoder=IncrementalDecoder, - streamwriter=StreamWriter, - streamreader=StreamReader, - ) - - -codecs.register(search_function) diff --git a/backend/venv39/lib/python3.9/site-packages/idna/compat.py b/backend/venv39/lib/python3.9/site-packages/idna/compat.py deleted file mode 100644 index 1df9f2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/compat.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, Union - -from .core import decode, encode - - -def ToASCII(label: str) -> bytes: - return encode(label) - - -def ToUnicode(label: Union[bytes, bytearray]) -> str: - return decode(label) - - -def nameprep(s: Any) -> None: - raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/backend/venv39/lib/python3.9/site-packages/idna/core.py b/backend/venv39/lib/python3.9/site-packages/idna/core.py deleted file mode 100644 index 8177bf7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/core.py +++ /dev/null @@ -1,437 +0,0 @@ -import bisect -import re -import unicodedata -from typing import Optional, Union - -from . import idnadata -from .intranges import intranges_contain - -_virama_combining_class = 9 -_alabel_prefix = b"xn--" -_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") - - -class IDNAError(UnicodeError): - """Base exception for all IDNA-encoding related problems""" - - pass - - -class IDNABidiError(IDNAError): - """Exception when bidirectional requirements are not satisfied""" - - pass - - -class InvalidCodepoint(IDNAError): - """Exception when a disallowed or unallocated codepoint is used""" - - pass - - -class InvalidCodepointContext(IDNAError): - """Exception when the codepoint is not valid in the context it is used""" - - pass - - -def _combining_class(cp: int) -> int: - v = unicodedata.combining(chr(cp)) - if v == 0: - if not unicodedata.name(chr(cp)): - raise ValueError("Unknown character in unicodedata") - return v - - -def _is_script(cp: str, script: str) -> bool: - return intranges_contain(ord(cp), idnadata.scripts[script]) - - -def _punycode(s: str) -> bytes: - return s.encode("punycode") - - -def _unot(s: int) -> str: - return "U+{:04X}".format(s) - - -def valid_label_length(label: Union[bytes, str]) -> bool: - if len(label) > 63: - return False - return True - - -def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool: - if len(label) > (254 if trailing_dot else 253): - return False - return True - - -def check_bidi(label: str, check_ltr: bool = False) -> bool: - # Bidi rules should only be applied if string contains RTL characters - bidi_label = False - for idx, cp in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - if direction == "": - # String likely comes from a newer version of Unicode - raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx)) - if direction in ["R", "AL", "AN"]: - bidi_label = True - if not bidi_label and not check_ltr: - return True - - # Bidi rule 1 - direction = unicodedata.bidirectional(label[0]) - if direction in ["R", "AL"]: - rtl = True - elif direction == "L": - rtl = False - else: - raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label))) - - valid_ending = False - number_type: Optional[str] = None - for idx, cp in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - - if rtl: - # Bidi rule 2 - if direction not in [ - "R", - "AL", - "AN", - "EN", - "ES", - "CS", - "ET", - "ON", - "BN", - "NSM", - ]: - raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx)) - # Bidi rule 3 - if direction in ["R", "AL", "EN", "AN"]: - valid_ending = True - elif direction != "NSM": - valid_ending = False - # Bidi rule 4 - if direction in ["AN", "EN"]: - if not number_type: - number_type = direction - else: - if number_type != direction: - raise IDNABidiError("Can not mix numeral types in a right-to-left label") - else: - # Bidi rule 5 - if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]: - raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx)) - # Bidi rule 6 - if direction in ["L", "EN"]: - valid_ending = True - elif direction != "NSM": - valid_ending = False - - if not valid_ending: - raise IDNABidiError("Label ends with illegal codepoint directionality") - - return True - - -def check_initial_combiner(label: str) -> bool: - if unicodedata.category(label[0])[0] == "M": - raise IDNAError("Label begins with an illegal combining character") - return True - - -def check_hyphen_ok(label: str) -> bool: - if label[2:4] == "--": - raise IDNAError("Label has disallowed hyphens in 3rd and 4th position") - if label[0] == "-" or label[-1] == "-": - raise IDNAError("Label must not start or end with a hyphen") - return True - - -def check_nfc(label: str) -> None: - if unicodedata.normalize("NFC", label) != label: - raise IDNAError("Label must be in Normalization Form C") - - -def valid_contextj(label: str, pos: int) -> bool: - cp_value = ord(label[pos]) - - if cp_value == 0x200C: - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - - ok = False - for i in range(pos - 1, -1, -1): - joining_type = idnadata.joining_types.get(ord(label[i])) - if joining_type == ord("T"): - continue - elif joining_type in [ord("L"), ord("D")]: - ok = True - break - else: - break - - if not ok: - return False - - ok = False - for i in range(pos + 1, len(label)): - joining_type = idnadata.joining_types.get(ord(label[i])) - if joining_type == ord("T"): - continue - elif joining_type in [ord("R"), ord("D")]: - ok = True - break - else: - break - return ok - - if cp_value == 0x200D: - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - return False - - else: - return False - - -def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: - cp_value = ord(label[pos]) - - if cp_value == 0x00B7: - if 0 < pos < len(label) - 1: - if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C: - return True - return False - - elif cp_value == 0x0375: - if pos < len(label) - 1 and len(label) > 1: - return _is_script(label[pos + 1], "Greek") - return False - - elif cp_value == 0x05F3 or cp_value == 0x05F4: - if pos > 0: - return _is_script(label[pos - 1], "Hebrew") - return False - - elif cp_value == 0x30FB: - for cp in label: - if cp == "\u30fb": - continue - if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): - return True - return False - - elif 0x660 <= cp_value <= 0x669: - for cp in label: - if 0x6F0 <= ord(cp) <= 0x06F9: - return False - return True - - elif 0x6F0 <= cp_value <= 0x6F9: - for cp in label: - if 0x660 <= ord(cp) <= 0x0669: - return False - return True - - return False - - -def check_label(label: Union[str, bytes, bytearray]) -> None: - if isinstance(label, (bytes, bytearray)): - label = label.decode("utf-8") - if len(label) == 0: - raise IDNAError("Empty Label") - - check_nfc(label) - check_hyphen_ok(label) - check_initial_combiner(label) - - for pos, cp in enumerate(label): - cp_value = ord(cp) - if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): - continue - elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): - try: - if not valid_contextj(label, pos): - raise InvalidCodepointContext( - "Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) - ) - except ValueError: - raise IDNAError( - "Unknown codepoint adjacent to joiner {} at position {} in {}".format( - _unot(cp_value), pos + 1, repr(label) - ) - ) - elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): - if not valid_contexto(label, pos): - raise InvalidCodepointContext( - "Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label)) - ) - else: - raise InvalidCodepoint( - "Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label)) - ) - - check_bidi(label) - - -def alabel(label: str) -> bytes: - try: - label_bytes = label.encode("ascii") - ulabel(label_bytes) - if not valid_label_length(label_bytes): - raise IDNAError("Label too long") - return label_bytes - except UnicodeEncodeError: - pass - - check_label(label) - label_bytes = _alabel_prefix + _punycode(label) - - if not valid_label_length(label_bytes): - raise IDNAError("Label too long") - - return label_bytes - - -def ulabel(label: Union[str, bytes, bytearray]) -> str: - if not isinstance(label, (bytes, bytearray)): - try: - label_bytes = label.encode("ascii") - except UnicodeEncodeError: - check_label(label) - return label - else: - label_bytes = bytes(label) - - label_bytes = label_bytes.lower() - if label_bytes.startswith(_alabel_prefix): - label_bytes = label_bytes[len(_alabel_prefix) :] - if not label_bytes: - raise IDNAError("Malformed A-label, no Punycode eligible content found") - if label_bytes.decode("ascii")[-1] == "-": - raise IDNAError("A-label must not end with a hyphen") - else: - check_label(label_bytes) - return label_bytes.decode("ascii") - - try: - label = label_bytes.decode("punycode") - except UnicodeError: - raise IDNAError("Invalid A-label") - check_label(label) - return label - - -def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: - """Re-map the characters in the string according to UTS46 processing.""" - from .uts46data import uts46data - - output = "" - - for pos, char in enumerate(domain): - code_point = ord(char) - try: - uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1] - status = uts46row[1] - replacement: Optional[str] = None - if len(uts46row) == 3: - replacement = uts46row[2] - if ( - status == "V" - or (status == "D" and not transitional) - or (status == "3" and not std3_rules and replacement is None) - ): - output += char - elif replacement is not None and ( - status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional) - ): - output += replacement - elif status != "I": - raise IndexError() - except IndexError: - raise InvalidCodepoint( - "Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain)) - ) - - return unicodedata.normalize("NFC", output) - - -def encode( - s: Union[str, bytes, bytearray], - strict: bool = False, - uts46: bool = False, - std3_rules: bool = False, - transitional: bool = False, -) -> bytes: - if not isinstance(s, str): - try: - s = str(s, "ascii") - except UnicodeDecodeError: - raise IDNAError("should pass a unicode string to the function rather than a byte string.") - if uts46: - s = uts46_remap(s, std3_rules, transitional) - trailing_dot = False - result = [] - if strict: - labels = s.split(".") - else: - labels = _unicode_dots_re.split(s) - if not labels or labels == [""]: - raise IDNAError("Empty domain") - if labels[-1] == "": - del labels[-1] - trailing_dot = True - for label in labels: - s = alabel(label) - if s: - result.append(s) - else: - raise IDNAError("Empty label") - if trailing_dot: - result.append(b"") - s = b".".join(result) - if not valid_string_length(s, trailing_dot): - raise IDNAError("Domain too long") - return s - - -def decode( - s: Union[str, bytes, bytearray], - strict: bool = False, - uts46: bool = False, - std3_rules: bool = False, -) -> str: - try: - if not isinstance(s, str): - s = str(s, "ascii") - except UnicodeDecodeError: - raise IDNAError("Invalid ASCII in A-label") - if uts46: - s = uts46_remap(s, std3_rules, False) - trailing_dot = False - result = [] - if not strict: - labels = _unicode_dots_re.split(s) - else: - labels = s.split(".") - if not labels or labels == [""]: - raise IDNAError("Empty domain") - if not labels[-1]: - del labels[-1] - trailing_dot = True - for label in labels: - s = ulabel(label) - if s: - result.append(s) - else: - raise IDNAError("Empty label") - if trailing_dot: - result.append("") - return ".".join(result) diff --git a/backend/venv39/lib/python3.9/site-packages/idna/idnadata.py b/backend/venv39/lib/python3.9/site-packages/idna/idnadata.py deleted file mode 100644 index ded47ca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/idnadata.py +++ /dev/null @@ -1,4309 +0,0 @@ -# This file is automatically generated by tools/idna-data - -__version__ = "16.0.0" - -scripts = { - "Greek": ( - 0x37000000374, - 0x37500000378, - 0x37A0000037E, - 0x37F00000380, - 0x38400000385, - 0x38600000387, - 0x3880000038B, - 0x38C0000038D, - 0x38E000003A2, - 0x3A3000003E2, - 0x3F000000400, - 0x1D2600001D2B, - 0x1D5D00001D62, - 0x1D6600001D6B, - 0x1DBF00001DC0, - 0x1F0000001F16, - 0x1F1800001F1E, - 0x1F2000001F46, - 0x1F4800001F4E, - 0x1F5000001F58, - 0x1F5900001F5A, - 0x1F5B00001F5C, - 0x1F5D00001F5E, - 0x1F5F00001F7E, - 0x1F8000001FB5, - 0x1FB600001FC5, - 0x1FC600001FD4, - 0x1FD600001FDC, - 0x1FDD00001FF0, - 0x1FF200001FF5, - 0x1FF600001FFF, - 0x212600002127, - 0xAB650000AB66, - 0x101400001018F, - 0x101A0000101A1, - 0x1D2000001D246, - ), - "Han": ( - 0x2E8000002E9A, - 0x2E9B00002EF4, - 0x2F0000002FD6, - 0x300500003006, - 0x300700003008, - 0x30210000302A, - 0x30380000303C, - 0x340000004DC0, - 0x4E000000A000, - 0xF9000000FA6E, - 0xFA700000FADA, - 0x16FE200016FE4, - 0x16FF000016FF2, - 0x200000002A6E0, - 0x2A7000002B73A, - 0x2B7400002B81E, - 0x2B8200002CEA2, - 0x2CEB00002EBE1, - 0x2EBF00002EE5E, - 0x2F8000002FA1E, - 0x300000003134B, - 0x31350000323B0, - ), - "Hebrew": ( - 0x591000005C8, - 0x5D0000005EB, - 0x5EF000005F5, - 0xFB1D0000FB37, - 0xFB380000FB3D, - 0xFB3E0000FB3F, - 0xFB400000FB42, - 0xFB430000FB45, - 0xFB460000FB50, - ), - "Hiragana": ( - 0x304100003097, - 0x309D000030A0, - 0x1B0010001B120, - 0x1B1320001B133, - 0x1B1500001B153, - 0x1F2000001F201, - ), - "Katakana": ( - 0x30A1000030FB, - 0x30FD00003100, - 0x31F000003200, - 0x32D0000032FF, - 0x330000003358, - 0xFF660000FF70, - 0xFF710000FF9E, - 0x1AFF00001AFF4, - 0x1AFF50001AFFC, - 0x1AFFD0001AFFF, - 0x1B0000001B001, - 0x1B1200001B123, - 0x1B1550001B156, - 0x1B1640001B168, - ), -} -joining_types = { - 0xAD: 84, - 0x300: 84, - 0x301: 84, - 0x302: 84, - 0x303: 84, - 0x304: 84, - 0x305: 84, - 0x306: 84, - 0x307: 84, - 0x308: 84, - 0x309: 84, - 0x30A: 84, - 0x30B: 84, - 0x30C: 84, - 0x30D: 84, - 0x30E: 84, - 0x30F: 84, - 0x310: 84, - 0x311: 84, - 0x312: 84, - 0x313: 84, - 0x314: 84, - 0x315: 84, - 0x316: 84, - 0x317: 84, - 0x318: 84, - 0x319: 84, - 0x31A: 84, - 0x31B: 84, - 0x31C: 84, - 0x31D: 84, - 0x31E: 84, - 0x31F: 84, - 0x320: 84, - 0x321: 84, - 0x322: 84, - 0x323: 84, - 0x324: 84, - 0x325: 84, - 0x326: 84, - 0x327: 84, - 0x328: 84, - 0x329: 84, - 0x32A: 84, - 0x32B: 84, - 0x32C: 84, - 0x32D: 84, - 0x32E: 84, - 0x32F: 84, - 0x330: 84, - 0x331: 84, - 0x332: 84, - 0x333: 84, - 0x334: 84, - 0x335: 84, - 0x336: 84, - 0x337: 84, - 0x338: 84, - 0x339: 84, - 0x33A: 84, - 0x33B: 84, - 0x33C: 84, - 0x33D: 84, - 0x33E: 84, - 0x33F: 84, - 0x340: 84, - 0x341: 84, - 0x342: 84, - 0x343: 84, - 0x344: 84, - 0x345: 84, - 0x346: 84, - 0x347: 84, - 0x348: 84, - 0x349: 84, - 0x34A: 84, - 0x34B: 84, - 0x34C: 84, - 0x34D: 84, - 0x34E: 84, - 0x34F: 84, - 0x350: 84, - 0x351: 84, - 0x352: 84, - 0x353: 84, - 0x354: 84, - 0x355: 84, - 0x356: 84, - 0x357: 84, - 0x358: 84, - 0x359: 84, - 0x35A: 84, - 0x35B: 84, - 0x35C: 84, - 0x35D: 84, - 0x35E: 84, - 0x35F: 84, - 0x360: 84, - 0x361: 84, - 0x362: 84, - 0x363: 84, - 0x364: 84, - 0x365: 84, - 0x366: 84, - 0x367: 84, - 0x368: 84, - 0x369: 84, - 0x36A: 84, - 0x36B: 84, - 0x36C: 84, - 0x36D: 84, - 0x36E: 84, - 0x36F: 84, - 0x483: 84, - 0x484: 84, - 0x485: 84, - 0x486: 84, - 0x487: 84, - 0x488: 84, - 0x489: 84, - 0x591: 84, - 0x592: 84, - 0x593: 84, - 0x594: 84, - 0x595: 84, - 0x596: 84, - 0x597: 84, - 0x598: 84, - 0x599: 84, - 0x59A: 84, - 0x59B: 84, - 0x59C: 84, - 0x59D: 84, - 0x59E: 84, - 0x59F: 84, - 0x5A0: 84, - 0x5A1: 84, - 0x5A2: 84, - 0x5A3: 84, - 0x5A4: 84, - 0x5A5: 84, - 0x5A6: 84, - 0x5A7: 84, - 0x5A8: 84, - 0x5A9: 84, - 0x5AA: 84, - 0x5AB: 84, - 0x5AC: 84, - 0x5AD: 84, - 0x5AE: 84, - 0x5AF: 84, - 0x5B0: 84, - 0x5B1: 84, - 0x5B2: 84, - 0x5B3: 84, - 0x5B4: 84, - 0x5B5: 84, - 0x5B6: 84, - 0x5B7: 84, - 0x5B8: 84, - 0x5B9: 84, - 0x5BA: 84, - 0x5BB: 84, - 0x5BC: 84, - 0x5BD: 84, - 0x5BF: 84, - 0x5C1: 84, - 0x5C2: 84, - 0x5C4: 84, - 0x5C5: 84, - 0x5C7: 84, - 0x610: 84, - 0x611: 84, - 0x612: 84, - 0x613: 84, - 0x614: 84, - 0x615: 84, - 0x616: 84, - 0x617: 84, - 0x618: 84, - 0x619: 84, - 0x61A: 84, - 0x61C: 84, - 0x620: 68, - 0x622: 82, - 0x623: 82, - 0x624: 82, - 0x625: 82, - 0x626: 68, - 0x627: 82, - 0x628: 68, - 0x629: 82, - 0x62A: 68, - 0x62B: 68, - 0x62C: 68, - 0x62D: 68, - 0x62E: 68, - 0x62F: 82, - 0x630: 82, - 0x631: 82, - 0x632: 82, - 0x633: 68, - 0x634: 68, - 0x635: 68, - 0x636: 68, - 0x637: 68, - 0x638: 68, - 0x639: 68, - 0x63A: 68, - 0x63B: 68, - 0x63C: 68, - 0x63D: 68, - 0x63E: 68, - 0x63F: 68, - 0x640: 67, - 0x641: 68, - 0x642: 68, - 0x643: 68, - 0x644: 68, - 0x645: 68, - 0x646: 68, - 0x647: 68, - 0x648: 82, - 0x649: 68, - 0x64A: 68, - 0x64B: 84, - 0x64C: 84, - 0x64D: 84, - 0x64E: 84, - 0x64F: 84, - 0x650: 84, - 0x651: 84, - 0x652: 84, - 0x653: 84, - 0x654: 84, - 0x655: 84, - 0x656: 84, - 0x657: 84, - 0x658: 84, - 0x659: 84, - 0x65A: 84, - 0x65B: 84, - 0x65C: 84, - 0x65D: 84, - 0x65E: 84, - 0x65F: 84, - 0x66E: 68, - 0x66F: 68, - 0x670: 84, - 0x671: 82, - 0x672: 82, - 0x673: 82, - 0x675: 82, - 0x676: 82, - 0x677: 82, - 0x678: 68, - 0x679: 68, - 0x67A: 68, - 0x67B: 68, - 0x67C: 68, - 0x67D: 68, - 0x67E: 68, - 0x67F: 68, - 0x680: 68, - 0x681: 68, - 0x682: 68, - 0x683: 68, - 0x684: 68, - 0x685: 68, - 0x686: 68, - 0x687: 68, - 0x688: 82, - 0x689: 82, - 0x68A: 82, - 0x68B: 82, - 0x68C: 82, - 0x68D: 82, - 0x68E: 82, - 0x68F: 82, - 0x690: 82, - 0x691: 82, - 0x692: 82, - 0x693: 82, - 0x694: 82, - 0x695: 82, - 0x696: 82, - 0x697: 82, - 0x698: 82, - 0x699: 82, - 0x69A: 68, - 0x69B: 68, - 0x69C: 68, - 0x69D: 68, - 0x69E: 68, - 0x69F: 68, - 0x6A0: 68, - 0x6A1: 68, - 0x6A2: 68, - 0x6A3: 68, - 0x6A4: 68, - 0x6A5: 68, - 0x6A6: 68, - 0x6A7: 68, - 0x6A8: 68, - 0x6A9: 68, - 0x6AA: 68, - 0x6AB: 68, - 0x6AC: 68, - 0x6AD: 68, - 0x6AE: 68, - 0x6AF: 68, - 0x6B0: 68, - 0x6B1: 68, - 0x6B2: 68, - 0x6B3: 68, - 0x6B4: 68, - 0x6B5: 68, - 0x6B6: 68, - 0x6B7: 68, - 0x6B8: 68, - 0x6B9: 68, - 0x6BA: 68, - 0x6BB: 68, - 0x6BC: 68, - 0x6BD: 68, - 0x6BE: 68, - 0x6BF: 68, - 0x6C0: 82, - 0x6C1: 68, - 0x6C2: 68, - 0x6C3: 82, - 0x6C4: 82, - 0x6C5: 82, - 0x6C6: 82, - 0x6C7: 82, - 0x6C8: 82, - 0x6C9: 82, - 0x6CA: 82, - 0x6CB: 82, - 0x6CC: 68, - 0x6CD: 82, - 0x6CE: 68, - 0x6CF: 82, - 0x6D0: 68, - 0x6D1: 68, - 0x6D2: 82, - 0x6D3: 82, - 0x6D5: 82, - 0x6D6: 84, - 0x6D7: 84, - 0x6D8: 84, - 0x6D9: 84, - 0x6DA: 84, - 0x6DB: 84, - 0x6DC: 84, - 0x6DF: 84, - 0x6E0: 84, - 0x6E1: 84, - 0x6E2: 84, - 0x6E3: 84, - 0x6E4: 84, - 0x6E7: 84, - 0x6E8: 84, - 0x6EA: 84, - 0x6EB: 84, - 0x6EC: 84, - 0x6ED: 84, - 0x6EE: 82, - 0x6EF: 82, - 0x6FA: 68, - 0x6FB: 68, - 0x6FC: 68, - 0x6FF: 68, - 0x70F: 84, - 0x710: 82, - 0x711: 84, - 0x712: 68, - 0x713: 68, - 0x714: 68, - 0x715: 82, - 0x716: 82, - 0x717: 82, - 0x718: 82, - 0x719: 82, - 0x71A: 68, - 0x71B: 68, - 0x71C: 68, - 0x71D: 68, - 0x71E: 82, - 0x71F: 68, - 0x720: 68, - 0x721: 68, - 0x722: 68, - 0x723: 68, - 0x724: 68, - 0x725: 68, - 0x726: 68, - 0x727: 68, - 0x728: 82, - 0x729: 68, - 0x72A: 82, - 0x72B: 68, - 0x72C: 82, - 0x72D: 68, - 0x72E: 68, - 0x72F: 82, - 0x730: 84, - 0x731: 84, - 0x732: 84, - 0x733: 84, - 0x734: 84, - 0x735: 84, - 0x736: 84, - 0x737: 84, - 0x738: 84, - 0x739: 84, - 0x73A: 84, - 0x73B: 84, - 0x73C: 84, - 0x73D: 84, - 0x73E: 84, - 0x73F: 84, - 0x740: 84, - 0x741: 84, - 0x742: 84, - 0x743: 84, - 0x744: 84, - 0x745: 84, - 0x746: 84, - 0x747: 84, - 0x748: 84, - 0x749: 84, - 0x74A: 84, - 0x74D: 82, - 0x74E: 68, - 0x74F: 68, - 0x750: 68, - 0x751: 68, - 0x752: 68, - 0x753: 68, - 0x754: 68, - 0x755: 68, - 0x756: 68, - 0x757: 68, - 0x758: 68, - 0x759: 82, - 0x75A: 82, - 0x75B: 82, - 0x75C: 68, - 0x75D: 68, - 0x75E: 68, - 0x75F: 68, - 0x760: 68, - 0x761: 68, - 0x762: 68, - 0x763: 68, - 0x764: 68, - 0x765: 68, - 0x766: 68, - 0x767: 68, - 0x768: 68, - 0x769: 68, - 0x76A: 68, - 0x76B: 82, - 0x76C: 82, - 0x76D: 68, - 0x76E: 68, - 0x76F: 68, - 0x770: 68, - 0x771: 82, - 0x772: 68, - 0x773: 82, - 0x774: 82, - 0x775: 68, - 0x776: 68, - 0x777: 68, - 0x778: 82, - 0x779: 82, - 0x77A: 68, - 0x77B: 68, - 0x77C: 68, - 0x77D: 68, - 0x77E: 68, - 0x77F: 68, - 0x7A6: 84, - 0x7A7: 84, - 0x7A8: 84, - 0x7A9: 84, - 0x7AA: 84, - 0x7AB: 84, - 0x7AC: 84, - 0x7AD: 84, - 0x7AE: 84, - 0x7AF: 84, - 0x7B0: 84, - 0x7CA: 68, - 0x7CB: 68, - 0x7CC: 68, - 0x7CD: 68, - 0x7CE: 68, - 0x7CF: 68, - 0x7D0: 68, - 0x7D1: 68, - 0x7D2: 68, - 0x7D3: 68, - 0x7D4: 68, - 0x7D5: 68, - 0x7D6: 68, - 0x7D7: 68, - 0x7D8: 68, - 0x7D9: 68, - 0x7DA: 68, - 0x7DB: 68, - 0x7DC: 68, - 0x7DD: 68, - 0x7DE: 68, - 0x7DF: 68, - 0x7E0: 68, - 0x7E1: 68, - 0x7E2: 68, - 0x7E3: 68, - 0x7E4: 68, - 0x7E5: 68, - 0x7E6: 68, - 0x7E7: 68, - 0x7E8: 68, - 0x7E9: 68, - 0x7EA: 68, - 0x7EB: 84, - 0x7EC: 84, - 0x7ED: 84, - 0x7EE: 84, - 0x7EF: 84, - 0x7F0: 84, - 0x7F1: 84, - 0x7F2: 84, - 0x7F3: 84, - 0x7FA: 67, - 0x7FD: 84, - 0x816: 84, - 0x817: 84, - 0x818: 84, - 0x819: 84, - 0x81B: 84, - 0x81C: 84, - 0x81D: 84, - 0x81E: 84, - 0x81F: 84, - 0x820: 84, - 0x821: 84, - 0x822: 84, - 0x823: 84, - 0x825: 84, - 0x826: 84, - 0x827: 84, - 0x829: 84, - 0x82A: 84, - 0x82B: 84, - 0x82C: 84, - 0x82D: 84, - 0x840: 82, - 0x841: 68, - 0x842: 68, - 0x843: 68, - 0x844: 68, - 0x845: 68, - 0x846: 82, - 0x847: 82, - 0x848: 68, - 0x849: 82, - 0x84A: 68, - 0x84B: 68, - 0x84C: 68, - 0x84D: 68, - 0x84E: 68, - 0x84F: 68, - 0x850: 68, - 0x851: 68, - 0x852: 68, - 0x853: 68, - 0x854: 82, - 0x855: 68, - 0x856: 82, - 0x857: 82, - 0x858: 82, - 0x859: 84, - 0x85A: 84, - 0x85B: 84, - 0x860: 68, - 0x862: 68, - 0x863: 68, - 0x864: 68, - 0x865: 68, - 0x867: 82, - 0x868: 68, - 0x869: 82, - 0x86A: 82, - 0x870: 82, - 0x871: 82, - 0x872: 82, - 0x873: 82, - 0x874: 82, - 0x875: 82, - 0x876: 82, - 0x877: 82, - 0x878: 82, - 0x879: 82, - 0x87A: 82, - 0x87B: 82, - 0x87C: 82, - 0x87D: 82, - 0x87E: 82, - 0x87F: 82, - 0x880: 82, - 0x881: 82, - 0x882: 82, - 0x883: 67, - 0x884: 67, - 0x885: 67, - 0x886: 68, - 0x889: 68, - 0x88A: 68, - 0x88B: 68, - 0x88C: 68, - 0x88D: 68, - 0x88E: 82, - 0x897: 84, - 0x898: 84, - 0x899: 84, - 0x89A: 84, - 0x89B: 84, - 0x89C: 84, - 0x89D: 84, - 0x89E: 84, - 0x89F: 84, - 0x8A0: 68, - 0x8A1: 68, - 0x8A2: 68, - 0x8A3: 68, - 0x8A4: 68, - 0x8A5: 68, - 0x8A6: 68, - 0x8A7: 68, - 0x8A8: 68, - 0x8A9: 68, - 0x8AA: 82, - 0x8AB: 82, - 0x8AC: 82, - 0x8AE: 82, - 0x8AF: 68, - 0x8B0: 68, - 0x8B1: 82, - 0x8B2: 82, - 0x8B3: 68, - 0x8B4: 68, - 0x8B5: 68, - 0x8B6: 68, - 0x8B7: 68, - 0x8B8: 68, - 0x8B9: 82, - 0x8BA: 68, - 0x8BB: 68, - 0x8BC: 68, - 0x8BD: 68, - 0x8BE: 68, - 0x8BF: 68, - 0x8C0: 68, - 0x8C1: 68, - 0x8C2: 68, - 0x8C3: 68, - 0x8C4: 68, - 0x8C5: 68, - 0x8C6: 68, - 0x8C7: 68, - 0x8C8: 68, - 0x8CA: 84, - 0x8CB: 84, - 0x8CC: 84, - 0x8CD: 84, - 0x8CE: 84, - 0x8CF: 84, - 0x8D0: 84, - 0x8D1: 84, - 0x8D2: 84, - 0x8D3: 84, - 0x8D4: 84, - 0x8D5: 84, - 0x8D6: 84, - 0x8D7: 84, - 0x8D8: 84, - 0x8D9: 84, - 0x8DA: 84, - 0x8DB: 84, - 0x8DC: 84, - 0x8DD: 84, - 0x8DE: 84, - 0x8DF: 84, - 0x8E0: 84, - 0x8E1: 84, - 0x8E3: 84, - 0x8E4: 84, - 0x8E5: 84, - 0x8E6: 84, - 0x8E7: 84, - 0x8E8: 84, - 0x8E9: 84, - 0x8EA: 84, - 0x8EB: 84, - 0x8EC: 84, - 0x8ED: 84, - 0x8EE: 84, - 0x8EF: 84, - 0x8F0: 84, - 0x8F1: 84, - 0x8F2: 84, - 0x8F3: 84, - 0x8F4: 84, - 0x8F5: 84, - 0x8F6: 84, - 0x8F7: 84, - 0x8F8: 84, - 0x8F9: 84, - 0x8FA: 84, - 0x8FB: 84, - 0x8FC: 84, - 0x8FD: 84, - 0x8FE: 84, - 0x8FF: 84, - 0x900: 84, - 0x901: 84, - 0x902: 84, - 0x93A: 84, - 0x93C: 84, - 0x941: 84, - 0x942: 84, - 0x943: 84, - 0x944: 84, - 0x945: 84, - 0x946: 84, - 0x947: 84, - 0x948: 84, - 0x94D: 84, - 0x951: 84, - 0x952: 84, - 0x953: 84, - 0x954: 84, - 0x955: 84, - 0x956: 84, - 0x957: 84, - 0x962: 84, - 0x963: 84, - 0x981: 84, - 0x9BC: 84, - 0x9C1: 84, - 0x9C2: 84, - 0x9C3: 84, - 0x9C4: 84, - 0x9CD: 84, - 0x9E2: 84, - 0x9E3: 84, - 0x9FE: 84, - 0xA01: 84, - 0xA02: 84, - 0xA3C: 84, - 0xA41: 84, - 0xA42: 84, - 0xA47: 84, - 0xA48: 84, - 0xA4B: 84, - 0xA4C: 84, - 0xA4D: 84, - 0xA51: 84, - 0xA70: 84, - 0xA71: 84, - 0xA75: 84, - 0xA81: 84, - 0xA82: 84, - 0xABC: 84, - 0xAC1: 84, - 0xAC2: 84, - 0xAC3: 84, - 0xAC4: 84, - 0xAC5: 84, - 0xAC7: 84, - 0xAC8: 84, - 0xACD: 84, - 0xAE2: 84, - 0xAE3: 84, - 0xAFA: 84, - 0xAFB: 84, - 0xAFC: 84, - 0xAFD: 84, - 0xAFE: 84, - 0xAFF: 84, - 0xB01: 84, - 0xB3C: 84, - 0xB3F: 84, - 0xB41: 84, - 0xB42: 84, - 0xB43: 84, - 0xB44: 84, - 0xB4D: 84, - 0xB55: 84, - 0xB56: 84, - 0xB62: 84, - 0xB63: 84, - 0xB82: 84, - 0xBC0: 84, - 0xBCD: 84, - 0xC00: 84, - 0xC04: 84, - 0xC3C: 84, - 0xC3E: 84, - 0xC3F: 84, - 0xC40: 84, - 0xC46: 84, - 0xC47: 84, - 0xC48: 84, - 0xC4A: 84, - 0xC4B: 84, - 0xC4C: 84, - 0xC4D: 84, - 0xC55: 84, - 0xC56: 84, - 0xC62: 84, - 0xC63: 84, - 0xC81: 84, - 0xCBC: 84, - 0xCBF: 84, - 0xCC6: 84, - 0xCCC: 84, - 0xCCD: 84, - 0xCE2: 84, - 0xCE3: 84, - 0xD00: 84, - 0xD01: 84, - 0xD3B: 84, - 0xD3C: 84, - 0xD41: 84, - 0xD42: 84, - 0xD43: 84, - 0xD44: 84, - 0xD4D: 84, - 0xD62: 84, - 0xD63: 84, - 0xD81: 84, - 0xDCA: 84, - 0xDD2: 84, - 0xDD3: 84, - 0xDD4: 84, - 0xDD6: 84, - 0xE31: 84, - 0xE34: 84, - 0xE35: 84, - 0xE36: 84, - 0xE37: 84, - 0xE38: 84, - 0xE39: 84, - 0xE3A: 84, - 0xE47: 84, - 0xE48: 84, - 0xE49: 84, - 0xE4A: 84, - 0xE4B: 84, - 0xE4C: 84, - 0xE4D: 84, - 0xE4E: 84, - 0xEB1: 84, - 0xEB4: 84, - 0xEB5: 84, - 0xEB6: 84, - 0xEB7: 84, - 0xEB8: 84, - 0xEB9: 84, - 0xEBA: 84, - 0xEBB: 84, - 0xEBC: 84, - 0xEC8: 84, - 0xEC9: 84, - 0xECA: 84, - 0xECB: 84, - 0xECC: 84, - 0xECD: 84, - 0xECE: 84, - 0xF18: 84, - 0xF19: 84, - 0xF35: 84, - 0xF37: 84, - 0xF39: 84, - 0xF71: 84, - 0xF72: 84, - 0xF73: 84, - 0xF74: 84, - 0xF75: 84, - 0xF76: 84, - 0xF77: 84, - 0xF78: 84, - 0xF79: 84, - 0xF7A: 84, - 0xF7B: 84, - 0xF7C: 84, - 0xF7D: 84, - 0xF7E: 84, - 0xF80: 84, - 0xF81: 84, - 0xF82: 84, - 0xF83: 84, - 0xF84: 84, - 0xF86: 84, - 0xF87: 84, - 0xF8D: 84, - 0xF8E: 84, - 0xF8F: 84, - 0xF90: 84, - 0xF91: 84, - 0xF92: 84, - 0xF93: 84, - 0xF94: 84, - 0xF95: 84, - 0xF96: 84, - 0xF97: 84, - 0xF99: 84, - 0xF9A: 84, - 0xF9B: 84, - 0xF9C: 84, - 0xF9D: 84, - 0xF9E: 84, - 0xF9F: 84, - 0xFA0: 84, - 0xFA1: 84, - 0xFA2: 84, - 0xFA3: 84, - 0xFA4: 84, - 0xFA5: 84, - 0xFA6: 84, - 0xFA7: 84, - 0xFA8: 84, - 0xFA9: 84, - 0xFAA: 84, - 0xFAB: 84, - 0xFAC: 84, - 0xFAD: 84, - 0xFAE: 84, - 0xFAF: 84, - 0xFB0: 84, - 0xFB1: 84, - 0xFB2: 84, - 0xFB3: 84, - 0xFB4: 84, - 0xFB5: 84, - 0xFB6: 84, - 0xFB7: 84, - 0xFB8: 84, - 0xFB9: 84, - 0xFBA: 84, - 0xFBB: 84, - 0xFBC: 84, - 0xFC6: 84, - 0x102D: 84, - 0x102E: 84, - 0x102F: 84, - 0x1030: 84, - 0x1032: 84, - 0x1033: 84, - 0x1034: 84, - 0x1035: 84, - 0x1036: 84, - 0x1037: 84, - 0x1039: 84, - 0x103A: 84, - 0x103D: 84, - 0x103E: 84, - 0x1058: 84, - 0x1059: 84, - 0x105E: 84, - 0x105F: 84, - 0x1060: 84, - 0x1071: 84, - 0x1072: 84, - 0x1073: 84, - 0x1074: 84, - 0x1082: 84, - 0x1085: 84, - 0x1086: 84, - 0x108D: 84, - 0x109D: 84, - 0x135D: 84, - 0x135E: 84, - 0x135F: 84, - 0x1712: 84, - 0x1713: 84, - 0x1714: 84, - 0x1732: 84, - 0x1733: 84, - 0x1752: 84, - 0x1753: 84, - 0x1772: 84, - 0x1773: 84, - 0x17B4: 84, - 0x17B5: 84, - 0x17B7: 84, - 0x17B8: 84, - 0x17B9: 84, - 0x17BA: 84, - 0x17BB: 84, - 0x17BC: 84, - 0x17BD: 84, - 0x17C6: 84, - 0x17C9: 84, - 0x17CA: 84, - 0x17CB: 84, - 0x17CC: 84, - 0x17CD: 84, - 0x17CE: 84, - 0x17CF: 84, - 0x17D0: 84, - 0x17D1: 84, - 0x17D2: 84, - 0x17D3: 84, - 0x17DD: 84, - 0x1807: 68, - 0x180A: 67, - 0x180B: 84, - 0x180C: 84, - 0x180D: 84, - 0x180F: 84, - 0x1820: 68, - 0x1821: 68, - 0x1822: 68, - 0x1823: 68, - 0x1824: 68, - 0x1825: 68, - 0x1826: 68, - 0x1827: 68, - 0x1828: 68, - 0x1829: 68, - 0x182A: 68, - 0x182B: 68, - 0x182C: 68, - 0x182D: 68, - 0x182E: 68, - 0x182F: 68, - 0x1830: 68, - 0x1831: 68, - 0x1832: 68, - 0x1833: 68, - 0x1834: 68, - 0x1835: 68, - 0x1836: 68, - 0x1837: 68, - 0x1838: 68, - 0x1839: 68, - 0x183A: 68, - 0x183B: 68, - 0x183C: 68, - 0x183D: 68, - 0x183E: 68, - 0x183F: 68, - 0x1840: 68, - 0x1841: 68, - 0x1842: 68, - 0x1843: 68, - 0x1844: 68, - 0x1845: 68, - 0x1846: 68, - 0x1847: 68, - 0x1848: 68, - 0x1849: 68, - 0x184A: 68, - 0x184B: 68, - 0x184C: 68, - 0x184D: 68, - 0x184E: 68, - 0x184F: 68, - 0x1850: 68, - 0x1851: 68, - 0x1852: 68, - 0x1853: 68, - 0x1854: 68, - 0x1855: 68, - 0x1856: 68, - 0x1857: 68, - 0x1858: 68, - 0x1859: 68, - 0x185A: 68, - 0x185B: 68, - 0x185C: 68, - 0x185D: 68, - 0x185E: 68, - 0x185F: 68, - 0x1860: 68, - 0x1861: 68, - 0x1862: 68, - 0x1863: 68, - 0x1864: 68, - 0x1865: 68, - 0x1866: 68, - 0x1867: 68, - 0x1868: 68, - 0x1869: 68, - 0x186A: 68, - 0x186B: 68, - 0x186C: 68, - 0x186D: 68, - 0x186E: 68, - 0x186F: 68, - 0x1870: 68, - 0x1871: 68, - 0x1872: 68, - 0x1873: 68, - 0x1874: 68, - 0x1875: 68, - 0x1876: 68, - 0x1877: 68, - 0x1878: 68, - 0x1885: 84, - 0x1886: 84, - 0x1887: 68, - 0x1888: 68, - 0x1889: 68, - 0x188A: 68, - 0x188B: 68, - 0x188C: 68, - 0x188D: 68, - 0x188E: 68, - 0x188F: 68, - 0x1890: 68, - 0x1891: 68, - 0x1892: 68, - 0x1893: 68, - 0x1894: 68, - 0x1895: 68, - 0x1896: 68, - 0x1897: 68, - 0x1898: 68, - 0x1899: 68, - 0x189A: 68, - 0x189B: 68, - 0x189C: 68, - 0x189D: 68, - 0x189E: 68, - 0x189F: 68, - 0x18A0: 68, - 0x18A1: 68, - 0x18A2: 68, - 0x18A3: 68, - 0x18A4: 68, - 0x18A5: 68, - 0x18A6: 68, - 0x18A7: 68, - 0x18A8: 68, - 0x18A9: 84, - 0x18AA: 68, - 0x1920: 84, - 0x1921: 84, - 0x1922: 84, - 0x1927: 84, - 0x1928: 84, - 0x1932: 84, - 0x1939: 84, - 0x193A: 84, - 0x193B: 84, - 0x1A17: 84, - 0x1A18: 84, - 0x1A1B: 84, - 0x1A56: 84, - 0x1A58: 84, - 0x1A59: 84, - 0x1A5A: 84, - 0x1A5B: 84, - 0x1A5C: 84, - 0x1A5D: 84, - 0x1A5E: 84, - 0x1A60: 84, - 0x1A62: 84, - 0x1A65: 84, - 0x1A66: 84, - 0x1A67: 84, - 0x1A68: 84, - 0x1A69: 84, - 0x1A6A: 84, - 0x1A6B: 84, - 0x1A6C: 84, - 0x1A73: 84, - 0x1A74: 84, - 0x1A75: 84, - 0x1A76: 84, - 0x1A77: 84, - 0x1A78: 84, - 0x1A79: 84, - 0x1A7A: 84, - 0x1A7B: 84, - 0x1A7C: 84, - 0x1A7F: 84, - 0x1AB0: 84, - 0x1AB1: 84, - 0x1AB2: 84, - 0x1AB3: 84, - 0x1AB4: 84, - 0x1AB5: 84, - 0x1AB6: 84, - 0x1AB7: 84, - 0x1AB8: 84, - 0x1AB9: 84, - 0x1ABA: 84, - 0x1ABB: 84, - 0x1ABC: 84, - 0x1ABD: 84, - 0x1ABE: 84, - 0x1ABF: 84, - 0x1AC0: 84, - 0x1AC1: 84, - 0x1AC2: 84, - 0x1AC3: 84, - 0x1AC4: 84, - 0x1AC5: 84, - 0x1AC6: 84, - 0x1AC7: 84, - 0x1AC8: 84, - 0x1AC9: 84, - 0x1ACA: 84, - 0x1ACB: 84, - 0x1ACC: 84, - 0x1ACD: 84, - 0x1ACE: 84, - 0x1B00: 84, - 0x1B01: 84, - 0x1B02: 84, - 0x1B03: 84, - 0x1B34: 84, - 0x1B36: 84, - 0x1B37: 84, - 0x1B38: 84, - 0x1B39: 84, - 0x1B3A: 84, - 0x1B3C: 84, - 0x1B42: 84, - 0x1B6B: 84, - 0x1B6C: 84, - 0x1B6D: 84, - 0x1B6E: 84, - 0x1B6F: 84, - 0x1B70: 84, - 0x1B71: 84, - 0x1B72: 84, - 0x1B73: 84, - 0x1B80: 84, - 0x1B81: 84, - 0x1BA2: 84, - 0x1BA3: 84, - 0x1BA4: 84, - 0x1BA5: 84, - 0x1BA8: 84, - 0x1BA9: 84, - 0x1BAB: 84, - 0x1BAC: 84, - 0x1BAD: 84, - 0x1BE6: 84, - 0x1BE8: 84, - 0x1BE9: 84, - 0x1BED: 84, - 0x1BEF: 84, - 0x1BF0: 84, - 0x1BF1: 84, - 0x1C2C: 84, - 0x1C2D: 84, - 0x1C2E: 84, - 0x1C2F: 84, - 0x1C30: 84, - 0x1C31: 84, - 0x1C32: 84, - 0x1C33: 84, - 0x1C36: 84, - 0x1C37: 84, - 0x1CD0: 84, - 0x1CD1: 84, - 0x1CD2: 84, - 0x1CD4: 84, - 0x1CD5: 84, - 0x1CD6: 84, - 0x1CD7: 84, - 0x1CD8: 84, - 0x1CD9: 84, - 0x1CDA: 84, - 0x1CDB: 84, - 0x1CDC: 84, - 0x1CDD: 84, - 0x1CDE: 84, - 0x1CDF: 84, - 0x1CE0: 84, - 0x1CE2: 84, - 0x1CE3: 84, - 0x1CE4: 84, - 0x1CE5: 84, - 0x1CE6: 84, - 0x1CE7: 84, - 0x1CE8: 84, - 0x1CED: 84, - 0x1CF4: 84, - 0x1CF8: 84, - 0x1CF9: 84, - 0x1DC0: 84, - 0x1DC1: 84, - 0x1DC2: 84, - 0x1DC3: 84, - 0x1DC4: 84, - 0x1DC5: 84, - 0x1DC6: 84, - 0x1DC7: 84, - 0x1DC8: 84, - 0x1DC9: 84, - 0x1DCA: 84, - 0x1DCB: 84, - 0x1DCC: 84, - 0x1DCD: 84, - 0x1DCE: 84, - 0x1DCF: 84, - 0x1DD0: 84, - 0x1DD1: 84, - 0x1DD2: 84, - 0x1DD3: 84, - 0x1DD4: 84, - 0x1DD5: 84, - 0x1DD6: 84, - 0x1DD7: 84, - 0x1DD8: 84, - 0x1DD9: 84, - 0x1DDA: 84, - 0x1DDB: 84, - 0x1DDC: 84, - 0x1DDD: 84, - 0x1DDE: 84, - 0x1DDF: 84, - 0x1DE0: 84, - 0x1DE1: 84, - 0x1DE2: 84, - 0x1DE3: 84, - 0x1DE4: 84, - 0x1DE5: 84, - 0x1DE6: 84, - 0x1DE7: 84, - 0x1DE8: 84, - 0x1DE9: 84, - 0x1DEA: 84, - 0x1DEB: 84, - 0x1DEC: 84, - 0x1DED: 84, - 0x1DEE: 84, - 0x1DEF: 84, - 0x1DF0: 84, - 0x1DF1: 84, - 0x1DF2: 84, - 0x1DF3: 84, - 0x1DF4: 84, - 0x1DF5: 84, - 0x1DF6: 84, - 0x1DF7: 84, - 0x1DF8: 84, - 0x1DF9: 84, - 0x1DFA: 84, - 0x1DFB: 84, - 0x1DFC: 84, - 0x1DFD: 84, - 0x1DFE: 84, - 0x1DFF: 84, - 0x200B: 84, - 0x200D: 67, - 0x200E: 84, - 0x200F: 84, - 0x202A: 84, - 0x202B: 84, - 0x202C: 84, - 0x202D: 84, - 0x202E: 84, - 0x2060: 84, - 0x2061: 84, - 0x2062: 84, - 0x2063: 84, - 0x2064: 84, - 0x206A: 84, - 0x206B: 84, - 0x206C: 84, - 0x206D: 84, - 0x206E: 84, - 0x206F: 84, - 0x20D0: 84, - 0x20D1: 84, - 0x20D2: 84, - 0x20D3: 84, - 0x20D4: 84, - 0x20D5: 84, - 0x20D6: 84, - 0x20D7: 84, - 0x20D8: 84, - 0x20D9: 84, - 0x20DA: 84, - 0x20DB: 84, - 0x20DC: 84, - 0x20DD: 84, - 0x20DE: 84, - 0x20DF: 84, - 0x20E0: 84, - 0x20E1: 84, - 0x20E2: 84, - 0x20E3: 84, - 0x20E4: 84, - 0x20E5: 84, - 0x20E6: 84, - 0x20E7: 84, - 0x20E8: 84, - 0x20E9: 84, - 0x20EA: 84, - 0x20EB: 84, - 0x20EC: 84, - 0x20ED: 84, - 0x20EE: 84, - 0x20EF: 84, - 0x20F0: 84, - 0x2CEF: 84, - 0x2CF0: 84, - 0x2CF1: 84, - 0x2D7F: 84, - 0x2DE0: 84, - 0x2DE1: 84, - 0x2DE2: 84, - 0x2DE3: 84, - 0x2DE4: 84, - 0x2DE5: 84, - 0x2DE6: 84, - 0x2DE7: 84, - 0x2DE8: 84, - 0x2DE9: 84, - 0x2DEA: 84, - 0x2DEB: 84, - 0x2DEC: 84, - 0x2DED: 84, - 0x2DEE: 84, - 0x2DEF: 84, - 0x2DF0: 84, - 0x2DF1: 84, - 0x2DF2: 84, - 0x2DF3: 84, - 0x2DF4: 84, - 0x2DF5: 84, - 0x2DF6: 84, - 0x2DF7: 84, - 0x2DF8: 84, - 0x2DF9: 84, - 0x2DFA: 84, - 0x2DFB: 84, - 0x2DFC: 84, - 0x2DFD: 84, - 0x2DFE: 84, - 0x2DFF: 84, - 0x302A: 84, - 0x302B: 84, - 0x302C: 84, - 0x302D: 84, - 0x3099: 84, - 0x309A: 84, - 0xA66F: 84, - 0xA670: 84, - 0xA671: 84, - 0xA672: 84, - 0xA674: 84, - 0xA675: 84, - 0xA676: 84, - 0xA677: 84, - 0xA678: 84, - 0xA679: 84, - 0xA67A: 84, - 0xA67B: 84, - 0xA67C: 84, - 0xA67D: 84, - 0xA69E: 84, - 0xA69F: 84, - 0xA6F0: 84, - 0xA6F1: 84, - 0xA802: 84, - 0xA806: 84, - 0xA80B: 84, - 0xA825: 84, - 0xA826: 84, - 0xA82C: 84, - 0xA840: 68, - 0xA841: 68, - 0xA842: 68, - 0xA843: 68, - 0xA844: 68, - 0xA845: 68, - 0xA846: 68, - 0xA847: 68, - 0xA848: 68, - 0xA849: 68, - 0xA84A: 68, - 0xA84B: 68, - 0xA84C: 68, - 0xA84D: 68, - 0xA84E: 68, - 0xA84F: 68, - 0xA850: 68, - 0xA851: 68, - 0xA852: 68, - 0xA853: 68, - 0xA854: 68, - 0xA855: 68, - 0xA856: 68, - 0xA857: 68, - 0xA858: 68, - 0xA859: 68, - 0xA85A: 68, - 0xA85B: 68, - 0xA85C: 68, - 0xA85D: 68, - 0xA85E: 68, - 0xA85F: 68, - 0xA860: 68, - 0xA861: 68, - 0xA862: 68, - 0xA863: 68, - 0xA864: 68, - 0xA865: 68, - 0xA866: 68, - 0xA867: 68, - 0xA868: 68, - 0xA869: 68, - 0xA86A: 68, - 0xA86B: 68, - 0xA86C: 68, - 0xA86D: 68, - 0xA86E: 68, - 0xA86F: 68, - 0xA870: 68, - 0xA871: 68, - 0xA872: 76, - 0xA8C4: 84, - 0xA8C5: 84, - 0xA8E0: 84, - 0xA8E1: 84, - 0xA8E2: 84, - 0xA8E3: 84, - 0xA8E4: 84, - 0xA8E5: 84, - 0xA8E6: 84, - 0xA8E7: 84, - 0xA8E8: 84, - 0xA8E9: 84, - 0xA8EA: 84, - 0xA8EB: 84, - 0xA8EC: 84, - 0xA8ED: 84, - 0xA8EE: 84, - 0xA8EF: 84, - 0xA8F0: 84, - 0xA8F1: 84, - 0xA8FF: 84, - 0xA926: 84, - 0xA927: 84, - 0xA928: 84, - 0xA929: 84, - 0xA92A: 84, - 0xA92B: 84, - 0xA92C: 84, - 0xA92D: 84, - 0xA947: 84, - 0xA948: 84, - 0xA949: 84, - 0xA94A: 84, - 0xA94B: 84, - 0xA94C: 84, - 0xA94D: 84, - 0xA94E: 84, - 0xA94F: 84, - 0xA950: 84, - 0xA951: 84, - 0xA980: 84, - 0xA981: 84, - 0xA982: 84, - 0xA9B3: 84, - 0xA9B6: 84, - 0xA9B7: 84, - 0xA9B8: 84, - 0xA9B9: 84, - 0xA9BC: 84, - 0xA9BD: 84, - 0xA9E5: 84, - 0xAA29: 84, - 0xAA2A: 84, - 0xAA2B: 84, - 0xAA2C: 84, - 0xAA2D: 84, - 0xAA2E: 84, - 0xAA31: 84, - 0xAA32: 84, - 0xAA35: 84, - 0xAA36: 84, - 0xAA43: 84, - 0xAA4C: 84, - 0xAA7C: 84, - 0xAAB0: 84, - 0xAAB2: 84, - 0xAAB3: 84, - 0xAAB4: 84, - 0xAAB7: 84, - 0xAAB8: 84, - 0xAABE: 84, - 0xAABF: 84, - 0xAAC1: 84, - 0xAAEC: 84, - 0xAAED: 84, - 0xAAF6: 84, - 0xABE5: 84, - 0xABE8: 84, - 0xABED: 84, - 0xFB1E: 84, - 0xFE00: 84, - 0xFE01: 84, - 0xFE02: 84, - 0xFE03: 84, - 0xFE04: 84, - 0xFE05: 84, - 0xFE06: 84, - 0xFE07: 84, - 0xFE08: 84, - 0xFE09: 84, - 0xFE0A: 84, - 0xFE0B: 84, - 0xFE0C: 84, - 0xFE0D: 84, - 0xFE0E: 84, - 0xFE0F: 84, - 0xFE20: 84, - 0xFE21: 84, - 0xFE22: 84, - 0xFE23: 84, - 0xFE24: 84, - 0xFE25: 84, - 0xFE26: 84, - 0xFE27: 84, - 0xFE28: 84, - 0xFE29: 84, - 0xFE2A: 84, - 0xFE2B: 84, - 0xFE2C: 84, - 0xFE2D: 84, - 0xFE2E: 84, - 0xFE2F: 84, - 0xFEFF: 84, - 0xFFF9: 84, - 0xFFFA: 84, - 0xFFFB: 84, - 0x101FD: 84, - 0x102E0: 84, - 0x10376: 84, - 0x10377: 84, - 0x10378: 84, - 0x10379: 84, - 0x1037A: 84, - 0x10A01: 84, - 0x10A02: 84, - 0x10A03: 84, - 0x10A05: 84, - 0x10A06: 84, - 0x10A0C: 84, - 0x10A0D: 84, - 0x10A0E: 84, - 0x10A0F: 84, - 0x10A38: 84, - 0x10A39: 84, - 0x10A3A: 84, - 0x10A3F: 84, - 0x10AC0: 68, - 0x10AC1: 68, - 0x10AC2: 68, - 0x10AC3: 68, - 0x10AC4: 68, - 0x10AC5: 82, - 0x10AC7: 82, - 0x10AC9: 82, - 0x10ACA: 82, - 0x10ACD: 76, - 0x10ACE: 82, - 0x10ACF: 82, - 0x10AD0: 82, - 0x10AD1: 82, - 0x10AD2: 82, - 0x10AD3: 68, - 0x10AD4: 68, - 0x10AD5: 68, - 0x10AD6: 68, - 0x10AD7: 76, - 0x10AD8: 68, - 0x10AD9: 68, - 0x10ADA: 68, - 0x10ADB: 68, - 0x10ADC: 68, - 0x10ADD: 82, - 0x10ADE: 68, - 0x10ADF: 68, - 0x10AE0: 68, - 0x10AE1: 82, - 0x10AE4: 82, - 0x10AE5: 84, - 0x10AE6: 84, - 0x10AEB: 68, - 0x10AEC: 68, - 0x10AED: 68, - 0x10AEE: 68, - 0x10AEF: 82, - 0x10B80: 68, - 0x10B81: 82, - 0x10B82: 68, - 0x10B83: 82, - 0x10B84: 82, - 0x10B85: 82, - 0x10B86: 68, - 0x10B87: 68, - 0x10B88: 68, - 0x10B89: 82, - 0x10B8A: 68, - 0x10B8B: 68, - 0x10B8C: 82, - 0x10B8D: 68, - 0x10B8E: 82, - 0x10B8F: 82, - 0x10B90: 68, - 0x10B91: 82, - 0x10BA9: 82, - 0x10BAA: 82, - 0x10BAB: 82, - 0x10BAC: 82, - 0x10BAD: 68, - 0x10BAE: 68, - 0x10D00: 76, - 0x10D01: 68, - 0x10D02: 68, - 0x10D03: 68, - 0x10D04: 68, - 0x10D05: 68, - 0x10D06: 68, - 0x10D07: 68, - 0x10D08: 68, - 0x10D09: 68, - 0x10D0A: 68, - 0x10D0B: 68, - 0x10D0C: 68, - 0x10D0D: 68, - 0x10D0E: 68, - 0x10D0F: 68, - 0x10D10: 68, - 0x10D11: 68, - 0x10D12: 68, - 0x10D13: 68, - 0x10D14: 68, - 0x10D15: 68, - 0x10D16: 68, - 0x10D17: 68, - 0x10D18: 68, - 0x10D19: 68, - 0x10D1A: 68, - 0x10D1B: 68, - 0x10D1C: 68, - 0x10D1D: 68, - 0x10D1E: 68, - 0x10D1F: 68, - 0x10D20: 68, - 0x10D21: 68, - 0x10D22: 82, - 0x10D23: 68, - 0x10D24: 84, - 0x10D25: 84, - 0x10D26: 84, - 0x10D27: 84, - 0x10D69: 84, - 0x10D6A: 84, - 0x10D6B: 84, - 0x10D6C: 84, - 0x10D6D: 84, - 0x10EAB: 84, - 0x10EAC: 84, - 0x10EC2: 82, - 0x10EC3: 68, - 0x10EC4: 68, - 0x10EFC: 84, - 0x10EFD: 84, - 0x10EFE: 84, - 0x10EFF: 84, - 0x10F30: 68, - 0x10F31: 68, - 0x10F32: 68, - 0x10F33: 82, - 0x10F34: 68, - 0x10F35: 68, - 0x10F36: 68, - 0x10F37: 68, - 0x10F38: 68, - 0x10F39: 68, - 0x10F3A: 68, - 0x10F3B: 68, - 0x10F3C: 68, - 0x10F3D: 68, - 0x10F3E: 68, - 0x10F3F: 68, - 0x10F40: 68, - 0x10F41: 68, - 0x10F42: 68, - 0x10F43: 68, - 0x10F44: 68, - 0x10F46: 84, - 0x10F47: 84, - 0x10F48: 84, - 0x10F49: 84, - 0x10F4A: 84, - 0x10F4B: 84, - 0x10F4C: 84, - 0x10F4D: 84, - 0x10F4E: 84, - 0x10F4F: 84, - 0x10F50: 84, - 0x10F51: 68, - 0x10F52: 68, - 0x10F53: 68, - 0x10F54: 82, - 0x10F70: 68, - 0x10F71: 68, - 0x10F72: 68, - 0x10F73: 68, - 0x10F74: 82, - 0x10F75: 82, - 0x10F76: 68, - 0x10F77: 68, - 0x10F78: 68, - 0x10F79: 68, - 0x10F7A: 68, - 0x10F7B: 68, - 0x10F7C: 68, - 0x10F7D: 68, - 0x10F7E: 68, - 0x10F7F: 68, - 0x10F80: 68, - 0x10F81: 68, - 0x10F82: 84, - 0x10F83: 84, - 0x10F84: 84, - 0x10F85: 84, - 0x10FB0: 68, - 0x10FB2: 68, - 0x10FB3: 68, - 0x10FB4: 82, - 0x10FB5: 82, - 0x10FB6: 82, - 0x10FB8: 68, - 0x10FB9: 82, - 0x10FBA: 82, - 0x10FBB: 68, - 0x10FBC: 68, - 0x10FBD: 82, - 0x10FBE: 68, - 0x10FBF: 68, - 0x10FC1: 68, - 0x10FC2: 82, - 0x10FC3: 82, - 0x10FC4: 68, - 0x10FC9: 82, - 0x10FCA: 68, - 0x10FCB: 76, - 0x11001: 84, - 0x11038: 84, - 0x11039: 84, - 0x1103A: 84, - 0x1103B: 84, - 0x1103C: 84, - 0x1103D: 84, - 0x1103E: 84, - 0x1103F: 84, - 0x11040: 84, - 0x11041: 84, - 0x11042: 84, - 0x11043: 84, - 0x11044: 84, - 0x11045: 84, - 0x11046: 84, - 0x11070: 84, - 0x11073: 84, - 0x11074: 84, - 0x1107F: 84, - 0x11080: 84, - 0x11081: 84, - 0x110B3: 84, - 0x110B4: 84, - 0x110B5: 84, - 0x110B6: 84, - 0x110B9: 84, - 0x110BA: 84, - 0x110C2: 84, - 0x11100: 84, - 0x11101: 84, - 0x11102: 84, - 0x11127: 84, - 0x11128: 84, - 0x11129: 84, - 0x1112A: 84, - 0x1112B: 84, - 0x1112D: 84, - 0x1112E: 84, - 0x1112F: 84, - 0x11130: 84, - 0x11131: 84, - 0x11132: 84, - 0x11133: 84, - 0x11134: 84, - 0x11173: 84, - 0x11180: 84, - 0x11181: 84, - 0x111B6: 84, - 0x111B7: 84, - 0x111B8: 84, - 0x111B9: 84, - 0x111BA: 84, - 0x111BB: 84, - 0x111BC: 84, - 0x111BD: 84, - 0x111BE: 84, - 0x111C9: 84, - 0x111CA: 84, - 0x111CB: 84, - 0x111CC: 84, - 0x111CF: 84, - 0x1122F: 84, - 0x11230: 84, - 0x11231: 84, - 0x11234: 84, - 0x11236: 84, - 0x11237: 84, - 0x1123E: 84, - 0x11241: 84, - 0x112DF: 84, - 0x112E3: 84, - 0x112E4: 84, - 0x112E5: 84, - 0x112E6: 84, - 0x112E7: 84, - 0x112E8: 84, - 0x112E9: 84, - 0x112EA: 84, - 0x11300: 84, - 0x11301: 84, - 0x1133B: 84, - 0x1133C: 84, - 0x11340: 84, - 0x11366: 84, - 0x11367: 84, - 0x11368: 84, - 0x11369: 84, - 0x1136A: 84, - 0x1136B: 84, - 0x1136C: 84, - 0x11370: 84, - 0x11371: 84, - 0x11372: 84, - 0x11373: 84, - 0x11374: 84, - 0x113BB: 84, - 0x113BC: 84, - 0x113BD: 84, - 0x113BE: 84, - 0x113BF: 84, - 0x113C0: 84, - 0x113CE: 84, - 0x113D0: 84, - 0x113D2: 84, - 0x113E1: 84, - 0x113E2: 84, - 0x11438: 84, - 0x11439: 84, - 0x1143A: 84, - 0x1143B: 84, - 0x1143C: 84, - 0x1143D: 84, - 0x1143E: 84, - 0x1143F: 84, - 0x11442: 84, - 0x11443: 84, - 0x11444: 84, - 0x11446: 84, - 0x1145E: 84, - 0x114B3: 84, - 0x114B4: 84, - 0x114B5: 84, - 0x114B6: 84, - 0x114B7: 84, - 0x114B8: 84, - 0x114BA: 84, - 0x114BF: 84, - 0x114C0: 84, - 0x114C2: 84, - 0x114C3: 84, - 0x115B2: 84, - 0x115B3: 84, - 0x115B4: 84, - 0x115B5: 84, - 0x115BC: 84, - 0x115BD: 84, - 0x115BF: 84, - 0x115C0: 84, - 0x115DC: 84, - 0x115DD: 84, - 0x11633: 84, - 0x11634: 84, - 0x11635: 84, - 0x11636: 84, - 0x11637: 84, - 0x11638: 84, - 0x11639: 84, - 0x1163A: 84, - 0x1163D: 84, - 0x1163F: 84, - 0x11640: 84, - 0x116AB: 84, - 0x116AD: 84, - 0x116B0: 84, - 0x116B1: 84, - 0x116B2: 84, - 0x116B3: 84, - 0x116B4: 84, - 0x116B5: 84, - 0x116B7: 84, - 0x1171D: 84, - 0x1171F: 84, - 0x11722: 84, - 0x11723: 84, - 0x11724: 84, - 0x11725: 84, - 0x11727: 84, - 0x11728: 84, - 0x11729: 84, - 0x1172A: 84, - 0x1172B: 84, - 0x1182F: 84, - 0x11830: 84, - 0x11831: 84, - 0x11832: 84, - 0x11833: 84, - 0x11834: 84, - 0x11835: 84, - 0x11836: 84, - 0x11837: 84, - 0x11839: 84, - 0x1183A: 84, - 0x1193B: 84, - 0x1193C: 84, - 0x1193E: 84, - 0x11943: 84, - 0x119D4: 84, - 0x119D5: 84, - 0x119D6: 84, - 0x119D7: 84, - 0x119DA: 84, - 0x119DB: 84, - 0x119E0: 84, - 0x11A01: 84, - 0x11A02: 84, - 0x11A03: 84, - 0x11A04: 84, - 0x11A05: 84, - 0x11A06: 84, - 0x11A07: 84, - 0x11A08: 84, - 0x11A09: 84, - 0x11A0A: 84, - 0x11A33: 84, - 0x11A34: 84, - 0x11A35: 84, - 0x11A36: 84, - 0x11A37: 84, - 0x11A38: 84, - 0x11A3B: 84, - 0x11A3C: 84, - 0x11A3D: 84, - 0x11A3E: 84, - 0x11A47: 84, - 0x11A51: 84, - 0x11A52: 84, - 0x11A53: 84, - 0x11A54: 84, - 0x11A55: 84, - 0x11A56: 84, - 0x11A59: 84, - 0x11A5A: 84, - 0x11A5B: 84, - 0x11A8A: 84, - 0x11A8B: 84, - 0x11A8C: 84, - 0x11A8D: 84, - 0x11A8E: 84, - 0x11A8F: 84, - 0x11A90: 84, - 0x11A91: 84, - 0x11A92: 84, - 0x11A93: 84, - 0x11A94: 84, - 0x11A95: 84, - 0x11A96: 84, - 0x11A98: 84, - 0x11A99: 84, - 0x11C30: 84, - 0x11C31: 84, - 0x11C32: 84, - 0x11C33: 84, - 0x11C34: 84, - 0x11C35: 84, - 0x11C36: 84, - 0x11C38: 84, - 0x11C39: 84, - 0x11C3A: 84, - 0x11C3B: 84, - 0x11C3C: 84, - 0x11C3D: 84, - 0x11C3F: 84, - 0x11C92: 84, - 0x11C93: 84, - 0x11C94: 84, - 0x11C95: 84, - 0x11C96: 84, - 0x11C97: 84, - 0x11C98: 84, - 0x11C99: 84, - 0x11C9A: 84, - 0x11C9B: 84, - 0x11C9C: 84, - 0x11C9D: 84, - 0x11C9E: 84, - 0x11C9F: 84, - 0x11CA0: 84, - 0x11CA1: 84, - 0x11CA2: 84, - 0x11CA3: 84, - 0x11CA4: 84, - 0x11CA5: 84, - 0x11CA6: 84, - 0x11CA7: 84, - 0x11CAA: 84, - 0x11CAB: 84, - 0x11CAC: 84, - 0x11CAD: 84, - 0x11CAE: 84, - 0x11CAF: 84, - 0x11CB0: 84, - 0x11CB2: 84, - 0x11CB3: 84, - 0x11CB5: 84, - 0x11CB6: 84, - 0x11D31: 84, - 0x11D32: 84, - 0x11D33: 84, - 0x11D34: 84, - 0x11D35: 84, - 0x11D36: 84, - 0x11D3A: 84, - 0x11D3C: 84, - 0x11D3D: 84, - 0x11D3F: 84, - 0x11D40: 84, - 0x11D41: 84, - 0x11D42: 84, - 0x11D43: 84, - 0x11D44: 84, - 0x11D45: 84, - 0x11D47: 84, - 0x11D90: 84, - 0x11D91: 84, - 0x11D95: 84, - 0x11D97: 84, - 0x11EF3: 84, - 0x11EF4: 84, - 0x11F00: 84, - 0x11F01: 84, - 0x11F36: 84, - 0x11F37: 84, - 0x11F38: 84, - 0x11F39: 84, - 0x11F3A: 84, - 0x11F40: 84, - 0x11F42: 84, - 0x11F5A: 84, - 0x13430: 84, - 0x13431: 84, - 0x13432: 84, - 0x13433: 84, - 0x13434: 84, - 0x13435: 84, - 0x13436: 84, - 0x13437: 84, - 0x13438: 84, - 0x13439: 84, - 0x1343A: 84, - 0x1343B: 84, - 0x1343C: 84, - 0x1343D: 84, - 0x1343E: 84, - 0x1343F: 84, - 0x13440: 84, - 0x13447: 84, - 0x13448: 84, - 0x13449: 84, - 0x1344A: 84, - 0x1344B: 84, - 0x1344C: 84, - 0x1344D: 84, - 0x1344E: 84, - 0x1344F: 84, - 0x13450: 84, - 0x13451: 84, - 0x13452: 84, - 0x13453: 84, - 0x13454: 84, - 0x13455: 84, - 0x1611E: 84, - 0x1611F: 84, - 0x16120: 84, - 0x16121: 84, - 0x16122: 84, - 0x16123: 84, - 0x16124: 84, - 0x16125: 84, - 0x16126: 84, - 0x16127: 84, - 0x16128: 84, - 0x16129: 84, - 0x1612D: 84, - 0x1612E: 84, - 0x1612F: 84, - 0x16AF0: 84, - 0x16AF1: 84, - 0x16AF2: 84, - 0x16AF3: 84, - 0x16AF4: 84, - 0x16B30: 84, - 0x16B31: 84, - 0x16B32: 84, - 0x16B33: 84, - 0x16B34: 84, - 0x16B35: 84, - 0x16B36: 84, - 0x16F4F: 84, - 0x16F8F: 84, - 0x16F90: 84, - 0x16F91: 84, - 0x16F92: 84, - 0x16FE4: 84, - 0x1BC9D: 84, - 0x1BC9E: 84, - 0x1BCA0: 84, - 0x1BCA1: 84, - 0x1BCA2: 84, - 0x1BCA3: 84, - 0x1CF00: 84, - 0x1CF01: 84, - 0x1CF02: 84, - 0x1CF03: 84, - 0x1CF04: 84, - 0x1CF05: 84, - 0x1CF06: 84, - 0x1CF07: 84, - 0x1CF08: 84, - 0x1CF09: 84, - 0x1CF0A: 84, - 0x1CF0B: 84, - 0x1CF0C: 84, - 0x1CF0D: 84, - 0x1CF0E: 84, - 0x1CF0F: 84, - 0x1CF10: 84, - 0x1CF11: 84, - 0x1CF12: 84, - 0x1CF13: 84, - 0x1CF14: 84, - 0x1CF15: 84, - 0x1CF16: 84, - 0x1CF17: 84, - 0x1CF18: 84, - 0x1CF19: 84, - 0x1CF1A: 84, - 0x1CF1B: 84, - 0x1CF1C: 84, - 0x1CF1D: 84, - 0x1CF1E: 84, - 0x1CF1F: 84, - 0x1CF20: 84, - 0x1CF21: 84, - 0x1CF22: 84, - 0x1CF23: 84, - 0x1CF24: 84, - 0x1CF25: 84, - 0x1CF26: 84, - 0x1CF27: 84, - 0x1CF28: 84, - 0x1CF29: 84, - 0x1CF2A: 84, - 0x1CF2B: 84, - 0x1CF2C: 84, - 0x1CF2D: 84, - 0x1CF30: 84, - 0x1CF31: 84, - 0x1CF32: 84, - 0x1CF33: 84, - 0x1CF34: 84, - 0x1CF35: 84, - 0x1CF36: 84, - 0x1CF37: 84, - 0x1CF38: 84, - 0x1CF39: 84, - 0x1CF3A: 84, - 0x1CF3B: 84, - 0x1CF3C: 84, - 0x1CF3D: 84, - 0x1CF3E: 84, - 0x1CF3F: 84, - 0x1CF40: 84, - 0x1CF41: 84, - 0x1CF42: 84, - 0x1CF43: 84, - 0x1CF44: 84, - 0x1CF45: 84, - 0x1CF46: 84, - 0x1D167: 84, - 0x1D168: 84, - 0x1D169: 84, - 0x1D173: 84, - 0x1D174: 84, - 0x1D175: 84, - 0x1D176: 84, - 0x1D177: 84, - 0x1D178: 84, - 0x1D179: 84, - 0x1D17A: 84, - 0x1D17B: 84, - 0x1D17C: 84, - 0x1D17D: 84, - 0x1D17E: 84, - 0x1D17F: 84, - 0x1D180: 84, - 0x1D181: 84, - 0x1D182: 84, - 0x1D185: 84, - 0x1D186: 84, - 0x1D187: 84, - 0x1D188: 84, - 0x1D189: 84, - 0x1D18A: 84, - 0x1D18B: 84, - 0x1D1AA: 84, - 0x1D1AB: 84, - 0x1D1AC: 84, - 0x1D1AD: 84, - 0x1D242: 84, - 0x1D243: 84, - 0x1D244: 84, - 0x1DA00: 84, - 0x1DA01: 84, - 0x1DA02: 84, - 0x1DA03: 84, - 0x1DA04: 84, - 0x1DA05: 84, - 0x1DA06: 84, - 0x1DA07: 84, - 0x1DA08: 84, - 0x1DA09: 84, - 0x1DA0A: 84, - 0x1DA0B: 84, - 0x1DA0C: 84, - 0x1DA0D: 84, - 0x1DA0E: 84, - 0x1DA0F: 84, - 0x1DA10: 84, - 0x1DA11: 84, - 0x1DA12: 84, - 0x1DA13: 84, - 0x1DA14: 84, - 0x1DA15: 84, - 0x1DA16: 84, - 0x1DA17: 84, - 0x1DA18: 84, - 0x1DA19: 84, - 0x1DA1A: 84, - 0x1DA1B: 84, - 0x1DA1C: 84, - 0x1DA1D: 84, - 0x1DA1E: 84, - 0x1DA1F: 84, - 0x1DA20: 84, - 0x1DA21: 84, - 0x1DA22: 84, - 0x1DA23: 84, - 0x1DA24: 84, - 0x1DA25: 84, - 0x1DA26: 84, - 0x1DA27: 84, - 0x1DA28: 84, - 0x1DA29: 84, - 0x1DA2A: 84, - 0x1DA2B: 84, - 0x1DA2C: 84, - 0x1DA2D: 84, - 0x1DA2E: 84, - 0x1DA2F: 84, - 0x1DA30: 84, - 0x1DA31: 84, - 0x1DA32: 84, - 0x1DA33: 84, - 0x1DA34: 84, - 0x1DA35: 84, - 0x1DA36: 84, - 0x1DA3B: 84, - 0x1DA3C: 84, - 0x1DA3D: 84, - 0x1DA3E: 84, - 0x1DA3F: 84, - 0x1DA40: 84, - 0x1DA41: 84, - 0x1DA42: 84, - 0x1DA43: 84, - 0x1DA44: 84, - 0x1DA45: 84, - 0x1DA46: 84, - 0x1DA47: 84, - 0x1DA48: 84, - 0x1DA49: 84, - 0x1DA4A: 84, - 0x1DA4B: 84, - 0x1DA4C: 84, - 0x1DA4D: 84, - 0x1DA4E: 84, - 0x1DA4F: 84, - 0x1DA50: 84, - 0x1DA51: 84, - 0x1DA52: 84, - 0x1DA53: 84, - 0x1DA54: 84, - 0x1DA55: 84, - 0x1DA56: 84, - 0x1DA57: 84, - 0x1DA58: 84, - 0x1DA59: 84, - 0x1DA5A: 84, - 0x1DA5B: 84, - 0x1DA5C: 84, - 0x1DA5D: 84, - 0x1DA5E: 84, - 0x1DA5F: 84, - 0x1DA60: 84, - 0x1DA61: 84, - 0x1DA62: 84, - 0x1DA63: 84, - 0x1DA64: 84, - 0x1DA65: 84, - 0x1DA66: 84, - 0x1DA67: 84, - 0x1DA68: 84, - 0x1DA69: 84, - 0x1DA6A: 84, - 0x1DA6B: 84, - 0x1DA6C: 84, - 0x1DA75: 84, - 0x1DA84: 84, - 0x1DA9B: 84, - 0x1DA9C: 84, - 0x1DA9D: 84, - 0x1DA9E: 84, - 0x1DA9F: 84, - 0x1DAA1: 84, - 0x1DAA2: 84, - 0x1DAA3: 84, - 0x1DAA4: 84, - 0x1DAA5: 84, - 0x1DAA6: 84, - 0x1DAA7: 84, - 0x1DAA8: 84, - 0x1DAA9: 84, - 0x1DAAA: 84, - 0x1DAAB: 84, - 0x1DAAC: 84, - 0x1DAAD: 84, - 0x1DAAE: 84, - 0x1DAAF: 84, - 0x1E000: 84, - 0x1E001: 84, - 0x1E002: 84, - 0x1E003: 84, - 0x1E004: 84, - 0x1E005: 84, - 0x1E006: 84, - 0x1E008: 84, - 0x1E009: 84, - 0x1E00A: 84, - 0x1E00B: 84, - 0x1E00C: 84, - 0x1E00D: 84, - 0x1E00E: 84, - 0x1E00F: 84, - 0x1E010: 84, - 0x1E011: 84, - 0x1E012: 84, - 0x1E013: 84, - 0x1E014: 84, - 0x1E015: 84, - 0x1E016: 84, - 0x1E017: 84, - 0x1E018: 84, - 0x1E01B: 84, - 0x1E01C: 84, - 0x1E01D: 84, - 0x1E01E: 84, - 0x1E01F: 84, - 0x1E020: 84, - 0x1E021: 84, - 0x1E023: 84, - 0x1E024: 84, - 0x1E026: 84, - 0x1E027: 84, - 0x1E028: 84, - 0x1E029: 84, - 0x1E02A: 84, - 0x1E08F: 84, - 0x1E130: 84, - 0x1E131: 84, - 0x1E132: 84, - 0x1E133: 84, - 0x1E134: 84, - 0x1E135: 84, - 0x1E136: 84, - 0x1E2AE: 84, - 0x1E2EC: 84, - 0x1E2ED: 84, - 0x1E2EE: 84, - 0x1E2EF: 84, - 0x1E4EC: 84, - 0x1E4ED: 84, - 0x1E4EE: 84, - 0x1E4EF: 84, - 0x1E5EE: 84, - 0x1E5EF: 84, - 0x1E8D0: 84, - 0x1E8D1: 84, - 0x1E8D2: 84, - 0x1E8D3: 84, - 0x1E8D4: 84, - 0x1E8D5: 84, - 0x1E8D6: 84, - 0x1E900: 68, - 0x1E901: 68, - 0x1E902: 68, - 0x1E903: 68, - 0x1E904: 68, - 0x1E905: 68, - 0x1E906: 68, - 0x1E907: 68, - 0x1E908: 68, - 0x1E909: 68, - 0x1E90A: 68, - 0x1E90B: 68, - 0x1E90C: 68, - 0x1E90D: 68, - 0x1E90E: 68, - 0x1E90F: 68, - 0x1E910: 68, - 0x1E911: 68, - 0x1E912: 68, - 0x1E913: 68, - 0x1E914: 68, - 0x1E915: 68, - 0x1E916: 68, - 0x1E917: 68, - 0x1E918: 68, - 0x1E919: 68, - 0x1E91A: 68, - 0x1E91B: 68, - 0x1E91C: 68, - 0x1E91D: 68, - 0x1E91E: 68, - 0x1E91F: 68, - 0x1E920: 68, - 0x1E921: 68, - 0x1E922: 68, - 0x1E923: 68, - 0x1E924: 68, - 0x1E925: 68, - 0x1E926: 68, - 0x1E927: 68, - 0x1E928: 68, - 0x1E929: 68, - 0x1E92A: 68, - 0x1E92B: 68, - 0x1E92C: 68, - 0x1E92D: 68, - 0x1E92E: 68, - 0x1E92F: 68, - 0x1E930: 68, - 0x1E931: 68, - 0x1E932: 68, - 0x1E933: 68, - 0x1E934: 68, - 0x1E935: 68, - 0x1E936: 68, - 0x1E937: 68, - 0x1E938: 68, - 0x1E939: 68, - 0x1E93A: 68, - 0x1E93B: 68, - 0x1E93C: 68, - 0x1E93D: 68, - 0x1E93E: 68, - 0x1E93F: 68, - 0x1E940: 68, - 0x1E941: 68, - 0x1E942: 68, - 0x1E943: 68, - 0x1E944: 84, - 0x1E945: 84, - 0x1E946: 84, - 0x1E947: 84, - 0x1E948: 84, - 0x1E949: 84, - 0x1E94A: 84, - 0x1E94B: 84, - 0xE0001: 84, - 0xE0020: 84, - 0xE0021: 84, - 0xE0022: 84, - 0xE0023: 84, - 0xE0024: 84, - 0xE0025: 84, - 0xE0026: 84, - 0xE0027: 84, - 0xE0028: 84, - 0xE0029: 84, - 0xE002A: 84, - 0xE002B: 84, - 0xE002C: 84, - 0xE002D: 84, - 0xE002E: 84, - 0xE002F: 84, - 0xE0030: 84, - 0xE0031: 84, - 0xE0032: 84, - 0xE0033: 84, - 0xE0034: 84, - 0xE0035: 84, - 0xE0036: 84, - 0xE0037: 84, - 0xE0038: 84, - 0xE0039: 84, - 0xE003A: 84, - 0xE003B: 84, - 0xE003C: 84, - 0xE003D: 84, - 0xE003E: 84, - 0xE003F: 84, - 0xE0040: 84, - 0xE0041: 84, - 0xE0042: 84, - 0xE0043: 84, - 0xE0044: 84, - 0xE0045: 84, - 0xE0046: 84, - 0xE0047: 84, - 0xE0048: 84, - 0xE0049: 84, - 0xE004A: 84, - 0xE004B: 84, - 0xE004C: 84, - 0xE004D: 84, - 0xE004E: 84, - 0xE004F: 84, - 0xE0050: 84, - 0xE0051: 84, - 0xE0052: 84, - 0xE0053: 84, - 0xE0054: 84, - 0xE0055: 84, - 0xE0056: 84, - 0xE0057: 84, - 0xE0058: 84, - 0xE0059: 84, - 0xE005A: 84, - 0xE005B: 84, - 0xE005C: 84, - 0xE005D: 84, - 0xE005E: 84, - 0xE005F: 84, - 0xE0060: 84, - 0xE0061: 84, - 0xE0062: 84, - 0xE0063: 84, - 0xE0064: 84, - 0xE0065: 84, - 0xE0066: 84, - 0xE0067: 84, - 0xE0068: 84, - 0xE0069: 84, - 0xE006A: 84, - 0xE006B: 84, - 0xE006C: 84, - 0xE006D: 84, - 0xE006E: 84, - 0xE006F: 84, - 0xE0070: 84, - 0xE0071: 84, - 0xE0072: 84, - 0xE0073: 84, - 0xE0074: 84, - 0xE0075: 84, - 0xE0076: 84, - 0xE0077: 84, - 0xE0078: 84, - 0xE0079: 84, - 0xE007A: 84, - 0xE007B: 84, - 0xE007C: 84, - 0xE007D: 84, - 0xE007E: 84, - 0xE007F: 84, - 0xE0100: 84, - 0xE0101: 84, - 0xE0102: 84, - 0xE0103: 84, - 0xE0104: 84, - 0xE0105: 84, - 0xE0106: 84, - 0xE0107: 84, - 0xE0108: 84, - 0xE0109: 84, - 0xE010A: 84, - 0xE010B: 84, - 0xE010C: 84, - 0xE010D: 84, - 0xE010E: 84, - 0xE010F: 84, - 0xE0110: 84, - 0xE0111: 84, - 0xE0112: 84, - 0xE0113: 84, - 0xE0114: 84, - 0xE0115: 84, - 0xE0116: 84, - 0xE0117: 84, - 0xE0118: 84, - 0xE0119: 84, - 0xE011A: 84, - 0xE011B: 84, - 0xE011C: 84, - 0xE011D: 84, - 0xE011E: 84, - 0xE011F: 84, - 0xE0120: 84, - 0xE0121: 84, - 0xE0122: 84, - 0xE0123: 84, - 0xE0124: 84, - 0xE0125: 84, - 0xE0126: 84, - 0xE0127: 84, - 0xE0128: 84, - 0xE0129: 84, - 0xE012A: 84, - 0xE012B: 84, - 0xE012C: 84, - 0xE012D: 84, - 0xE012E: 84, - 0xE012F: 84, - 0xE0130: 84, - 0xE0131: 84, - 0xE0132: 84, - 0xE0133: 84, - 0xE0134: 84, - 0xE0135: 84, - 0xE0136: 84, - 0xE0137: 84, - 0xE0138: 84, - 0xE0139: 84, - 0xE013A: 84, - 0xE013B: 84, - 0xE013C: 84, - 0xE013D: 84, - 0xE013E: 84, - 0xE013F: 84, - 0xE0140: 84, - 0xE0141: 84, - 0xE0142: 84, - 0xE0143: 84, - 0xE0144: 84, - 0xE0145: 84, - 0xE0146: 84, - 0xE0147: 84, - 0xE0148: 84, - 0xE0149: 84, - 0xE014A: 84, - 0xE014B: 84, - 0xE014C: 84, - 0xE014D: 84, - 0xE014E: 84, - 0xE014F: 84, - 0xE0150: 84, - 0xE0151: 84, - 0xE0152: 84, - 0xE0153: 84, - 0xE0154: 84, - 0xE0155: 84, - 0xE0156: 84, - 0xE0157: 84, - 0xE0158: 84, - 0xE0159: 84, - 0xE015A: 84, - 0xE015B: 84, - 0xE015C: 84, - 0xE015D: 84, - 0xE015E: 84, - 0xE015F: 84, - 0xE0160: 84, - 0xE0161: 84, - 0xE0162: 84, - 0xE0163: 84, - 0xE0164: 84, - 0xE0165: 84, - 0xE0166: 84, - 0xE0167: 84, - 0xE0168: 84, - 0xE0169: 84, - 0xE016A: 84, - 0xE016B: 84, - 0xE016C: 84, - 0xE016D: 84, - 0xE016E: 84, - 0xE016F: 84, - 0xE0170: 84, - 0xE0171: 84, - 0xE0172: 84, - 0xE0173: 84, - 0xE0174: 84, - 0xE0175: 84, - 0xE0176: 84, - 0xE0177: 84, - 0xE0178: 84, - 0xE0179: 84, - 0xE017A: 84, - 0xE017B: 84, - 0xE017C: 84, - 0xE017D: 84, - 0xE017E: 84, - 0xE017F: 84, - 0xE0180: 84, - 0xE0181: 84, - 0xE0182: 84, - 0xE0183: 84, - 0xE0184: 84, - 0xE0185: 84, - 0xE0186: 84, - 0xE0187: 84, - 0xE0188: 84, - 0xE0189: 84, - 0xE018A: 84, - 0xE018B: 84, - 0xE018C: 84, - 0xE018D: 84, - 0xE018E: 84, - 0xE018F: 84, - 0xE0190: 84, - 0xE0191: 84, - 0xE0192: 84, - 0xE0193: 84, - 0xE0194: 84, - 0xE0195: 84, - 0xE0196: 84, - 0xE0197: 84, - 0xE0198: 84, - 0xE0199: 84, - 0xE019A: 84, - 0xE019B: 84, - 0xE019C: 84, - 0xE019D: 84, - 0xE019E: 84, - 0xE019F: 84, - 0xE01A0: 84, - 0xE01A1: 84, - 0xE01A2: 84, - 0xE01A3: 84, - 0xE01A4: 84, - 0xE01A5: 84, - 0xE01A6: 84, - 0xE01A7: 84, - 0xE01A8: 84, - 0xE01A9: 84, - 0xE01AA: 84, - 0xE01AB: 84, - 0xE01AC: 84, - 0xE01AD: 84, - 0xE01AE: 84, - 0xE01AF: 84, - 0xE01B0: 84, - 0xE01B1: 84, - 0xE01B2: 84, - 0xE01B3: 84, - 0xE01B4: 84, - 0xE01B5: 84, - 0xE01B6: 84, - 0xE01B7: 84, - 0xE01B8: 84, - 0xE01B9: 84, - 0xE01BA: 84, - 0xE01BB: 84, - 0xE01BC: 84, - 0xE01BD: 84, - 0xE01BE: 84, - 0xE01BF: 84, - 0xE01C0: 84, - 0xE01C1: 84, - 0xE01C2: 84, - 0xE01C3: 84, - 0xE01C4: 84, - 0xE01C5: 84, - 0xE01C6: 84, - 0xE01C7: 84, - 0xE01C8: 84, - 0xE01C9: 84, - 0xE01CA: 84, - 0xE01CB: 84, - 0xE01CC: 84, - 0xE01CD: 84, - 0xE01CE: 84, - 0xE01CF: 84, - 0xE01D0: 84, - 0xE01D1: 84, - 0xE01D2: 84, - 0xE01D3: 84, - 0xE01D4: 84, - 0xE01D5: 84, - 0xE01D6: 84, - 0xE01D7: 84, - 0xE01D8: 84, - 0xE01D9: 84, - 0xE01DA: 84, - 0xE01DB: 84, - 0xE01DC: 84, - 0xE01DD: 84, - 0xE01DE: 84, - 0xE01DF: 84, - 0xE01E0: 84, - 0xE01E1: 84, - 0xE01E2: 84, - 0xE01E3: 84, - 0xE01E4: 84, - 0xE01E5: 84, - 0xE01E6: 84, - 0xE01E7: 84, - 0xE01E8: 84, - 0xE01E9: 84, - 0xE01EA: 84, - 0xE01EB: 84, - 0xE01EC: 84, - 0xE01ED: 84, - 0xE01EE: 84, - 0xE01EF: 84, -} -codepoint_classes = { - "PVALID": ( - 0x2D0000002E, - 0x300000003A, - 0x610000007B, - 0xDF000000F7, - 0xF800000100, - 0x10100000102, - 0x10300000104, - 0x10500000106, - 0x10700000108, - 0x1090000010A, - 0x10B0000010C, - 0x10D0000010E, - 0x10F00000110, - 0x11100000112, - 0x11300000114, - 0x11500000116, - 0x11700000118, - 0x1190000011A, - 0x11B0000011C, - 0x11D0000011E, - 0x11F00000120, - 0x12100000122, - 0x12300000124, - 0x12500000126, - 0x12700000128, - 0x1290000012A, - 0x12B0000012C, - 0x12D0000012E, - 0x12F00000130, - 0x13100000132, - 0x13500000136, - 0x13700000139, - 0x13A0000013B, - 0x13C0000013D, - 0x13E0000013F, - 0x14200000143, - 0x14400000145, - 0x14600000147, - 0x14800000149, - 0x14B0000014C, - 0x14D0000014E, - 0x14F00000150, - 0x15100000152, - 0x15300000154, - 0x15500000156, - 0x15700000158, - 0x1590000015A, - 0x15B0000015C, - 0x15D0000015E, - 0x15F00000160, - 0x16100000162, - 0x16300000164, - 0x16500000166, - 0x16700000168, - 0x1690000016A, - 0x16B0000016C, - 0x16D0000016E, - 0x16F00000170, - 0x17100000172, - 0x17300000174, - 0x17500000176, - 0x17700000178, - 0x17A0000017B, - 0x17C0000017D, - 0x17E0000017F, - 0x18000000181, - 0x18300000184, - 0x18500000186, - 0x18800000189, - 0x18C0000018E, - 0x19200000193, - 0x19500000196, - 0x1990000019C, - 0x19E0000019F, - 0x1A1000001A2, - 0x1A3000001A4, - 0x1A5000001A6, - 0x1A8000001A9, - 0x1AA000001AC, - 0x1AD000001AE, - 0x1B0000001B1, - 0x1B4000001B5, - 0x1B6000001B7, - 0x1B9000001BC, - 0x1BD000001C4, - 0x1CE000001CF, - 0x1D0000001D1, - 0x1D2000001D3, - 0x1D4000001D5, - 0x1D6000001D7, - 0x1D8000001D9, - 0x1DA000001DB, - 0x1DC000001DE, - 0x1DF000001E0, - 0x1E1000001E2, - 0x1E3000001E4, - 0x1E5000001E6, - 0x1E7000001E8, - 0x1E9000001EA, - 0x1EB000001EC, - 0x1ED000001EE, - 0x1EF000001F1, - 0x1F5000001F6, - 0x1F9000001FA, - 0x1FB000001FC, - 0x1FD000001FE, - 0x1FF00000200, - 0x20100000202, - 0x20300000204, - 0x20500000206, - 0x20700000208, - 0x2090000020A, - 0x20B0000020C, - 0x20D0000020E, - 0x20F00000210, - 0x21100000212, - 0x21300000214, - 0x21500000216, - 0x21700000218, - 0x2190000021A, - 0x21B0000021C, - 0x21D0000021E, - 0x21F00000220, - 0x22100000222, - 0x22300000224, - 0x22500000226, - 0x22700000228, - 0x2290000022A, - 0x22B0000022C, - 0x22D0000022E, - 0x22F00000230, - 0x23100000232, - 0x2330000023A, - 0x23C0000023D, - 0x23F00000241, - 0x24200000243, - 0x24700000248, - 0x2490000024A, - 0x24B0000024C, - 0x24D0000024E, - 0x24F000002B0, - 0x2B9000002C2, - 0x2C6000002D2, - 0x2EC000002ED, - 0x2EE000002EF, - 0x30000000340, - 0x34200000343, - 0x3460000034F, - 0x35000000370, - 0x37100000372, - 0x37300000374, - 0x37700000378, - 0x37B0000037E, - 0x39000000391, - 0x3AC000003CF, - 0x3D7000003D8, - 0x3D9000003DA, - 0x3DB000003DC, - 0x3DD000003DE, - 0x3DF000003E0, - 0x3E1000003E2, - 0x3E3000003E4, - 0x3E5000003E6, - 0x3E7000003E8, - 0x3E9000003EA, - 0x3EB000003EC, - 0x3ED000003EE, - 0x3EF000003F0, - 0x3F3000003F4, - 0x3F8000003F9, - 0x3FB000003FD, - 0x43000000460, - 0x46100000462, - 0x46300000464, - 0x46500000466, - 0x46700000468, - 0x4690000046A, - 0x46B0000046C, - 0x46D0000046E, - 0x46F00000470, - 0x47100000472, - 0x47300000474, - 0x47500000476, - 0x47700000478, - 0x4790000047A, - 0x47B0000047C, - 0x47D0000047E, - 0x47F00000480, - 0x48100000482, - 0x48300000488, - 0x48B0000048C, - 0x48D0000048E, - 0x48F00000490, - 0x49100000492, - 0x49300000494, - 0x49500000496, - 0x49700000498, - 0x4990000049A, - 0x49B0000049C, - 0x49D0000049E, - 0x49F000004A0, - 0x4A1000004A2, - 0x4A3000004A4, - 0x4A5000004A6, - 0x4A7000004A8, - 0x4A9000004AA, - 0x4AB000004AC, - 0x4AD000004AE, - 0x4AF000004B0, - 0x4B1000004B2, - 0x4B3000004B4, - 0x4B5000004B6, - 0x4B7000004B8, - 0x4B9000004BA, - 0x4BB000004BC, - 0x4BD000004BE, - 0x4BF000004C0, - 0x4C2000004C3, - 0x4C4000004C5, - 0x4C6000004C7, - 0x4C8000004C9, - 0x4CA000004CB, - 0x4CC000004CD, - 0x4CE000004D0, - 0x4D1000004D2, - 0x4D3000004D4, - 0x4D5000004D6, - 0x4D7000004D8, - 0x4D9000004DA, - 0x4DB000004DC, - 0x4DD000004DE, - 0x4DF000004E0, - 0x4E1000004E2, - 0x4E3000004E4, - 0x4E5000004E6, - 0x4E7000004E8, - 0x4E9000004EA, - 0x4EB000004EC, - 0x4ED000004EE, - 0x4EF000004F0, - 0x4F1000004F2, - 0x4F3000004F4, - 0x4F5000004F6, - 0x4F7000004F8, - 0x4F9000004FA, - 0x4FB000004FC, - 0x4FD000004FE, - 0x4FF00000500, - 0x50100000502, - 0x50300000504, - 0x50500000506, - 0x50700000508, - 0x5090000050A, - 0x50B0000050C, - 0x50D0000050E, - 0x50F00000510, - 0x51100000512, - 0x51300000514, - 0x51500000516, - 0x51700000518, - 0x5190000051A, - 0x51B0000051C, - 0x51D0000051E, - 0x51F00000520, - 0x52100000522, - 0x52300000524, - 0x52500000526, - 0x52700000528, - 0x5290000052A, - 0x52B0000052C, - 0x52D0000052E, - 0x52F00000530, - 0x5590000055A, - 0x56000000587, - 0x58800000589, - 0x591000005BE, - 0x5BF000005C0, - 0x5C1000005C3, - 0x5C4000005C6, - 0x5C7000005C8, - 0x5D0000005EB, - 0x5EF000005F3, - 0x6100000061B, - 0x62000000640, - 0x64100000660, - 0x66E00000675, - 0x679000006D4, - 0x6D5000006DD, - 0x6DF000006E9, - 0x6EA000006F0, - 0x6FA00000700, - 0x7100000074B, - 0x74D000007B2, - 0x7C0000007F6, - 0x7FD000007FE, - 0x8000000082E, - 0x8400000085C, - 0x8600000086B, - 0x87000000888, - 0x8890000088F, - 0x897000008E2, - 0x8E300000958, - 0x96000000964, - 0x96600000970, - 0x97100000984, - 0x9850000098D, - 0x98F00000991, - 0x993000009A9, - 0x9AA000009B1, - 0x9B2000009B3, - 0x9B6000009BA, - 0x9BC000009C5, - 0x9C7000009C9, - 0x9CB000009CF, - 0x9D7000009D8, - 0x9E0000009E4, - 0x9E6000009F2, - 0x9FC000009FD, - 0x9FE000009FF, - 0xA0100000A04, - 0xA0500000A0B, - 0xA0F00000A11, - 0xA1300000A29, - 0xA2A00000A31, - 0xA3200000A33, - 0xA3500000A36, - 0xA3800000A3A, - 0xA3C00000A3D, - 0xA3E00000A43, - 0xA4700000A49, - 0xA4B00000A4E, - 0xA5100000A52, - 0xA5C00000A5D, - 0xA6600000A76, - 0xA8100000A84, - 0xA8500000A8E, - 0xA8F00000A92, - 0xA9300000AA9, - 0xAAA00000AB1, - 0xAB200000AB4, - 0xAB500000ABA, - 0xABC00000AC6, - 0xAC700000ACA, - 0xACB00000ACE, - 0xAD000000AD1, - 0xAE000000AE4, - 0xAE600000AF0, - 0xAF900000B00, - 0xB0100000B04, - 0xB0500000B0D, - 0xB0F00000B11, - 0xB1300000B29, - 0xB2A00000B31, - 0xB3200000B34, - 0xB3500000B3A, - 0xB3C00000B45, - 0xB4700000B49, - 0xB4B00000B4E, - 0xB5500000B58, - 0xB5F00000B64, - 0xB6600000B70, - 0xB7100000B72, - 0xB8200000B84, - 0xB8500000B8B, - 0xB8E00000B91, - 0xB9200000B96, - 0xB9900000B9B, - 0xB9C00000B9D, - 0xB9E00000BA0, - 0xBA300000BA5, - 0xBA800000BAB, - 0xBAE00000BBA, - 0xBBE00000BC3, - 0xBC600000BC9, - 0xBCA00000BCE, - 0xBD000000BD1, - 0xBD700000BD8, - 0xBE600000BF0, - 0xC0000000C0D, - 0xC0E00000C11, - 0xC1200000C29, - 0xC2A00000C3A, - 0xC3C00000C45, - 0xC4600000C49, - 0xC4A00000C4E, - 0xC5500000C57, - 0xC5800000C5B, - 0xC5D00000C5E, - 0xC6000000C64, - 0xC6600000C70, - 0xC8000000C84, - 0xC8500000C8D, - 0xC8E00000C91, - 0xC9200000CA9, - 0xCAA00000CB4, - 0xCB500000CBA, - 0xCBC00000CC5, - 0xCC600000CC9, - 0xCCA00000CCE, - 0xCD500000CD7, - 0xCDD00000CDF, - 0xCE000000CE4, - 0xCE600000CF0, - 0xCF100000CF4, - 0xD0000000D0D, - 0xD0E00000D11, - 0xD1200000D45, - 0xD4600000D49, - 0xD4A00000D4F, - 0xD5400000D58, - 0xD5F00000D64, - 0xD6600000D70, - 0xD7A00000D80, - 0xD8100000D84, - 0xD8500000D97, - 0xD9A00000DB2, - 0xDB300000DBC, - 0xDBD00000DBE, - 0xDC000000DC7, - 0xDCA00000DCB, - 0xDCF00000DD5, - 0xDD600000DD7, - 0xDD800000DE0, - 0xDE600000DF0, - 0xDF200000DF4, - 0xE0100000E33, - 0xE3400000E3B, - 0xE4000000E4F, - 0xE5000000E5A, - 0xE8100000E83, - 0xE8400000E85, - 0xE8600000E8B, - 0xE8C00000EA4, - 0xEA500000EA6, - 0xEA700000EB3, - 0xEB400000EBE, - 0xEC000000EC5, - 0xEC600000EC7, - 0xEC800000ECF, - 0xED000000EDA, - 0xEDE00000EE0, - 0xF0000000F01, - 0xF0B00000F0C, - 0xF1800000F1A, - 0xF2000000F2A, - 0xF3500000F36, - 0xF3700000F38, - 0xF3900000F3A, - 0xF3E00000F43, - 0xF4400000F48, - 0xF4900000F4D, - 0xF4E00000F52, - 0xF5300000F57, - 0xF5800000F5C, - 0xF5D00000F69, - 0xF6A00000F6D, - 0xF7100000F73, - 0xF7400000F75, - 0xF7A00000F81, - 0xF8200000F85, - 0xF8600000F93, - 0xF9400000F98, - 0xF9900000F9D, - 0xF9E00000FA2, - 0xFA300000FA7, - 0xFA800000FAC, - 0xFAD00000FB9, - 0xFBA00000FBD, - 0xFC600000FC7, - 0x10000000104A, - 0x10500000109E, - 0x10D0000010FB, - 0x10FD00001100, - 0x120000001249, - 0x124A0000124E, - 0x125000001257, - 0x125800001259, - 0x125A0000125E, - 0x126000001289, - 0x128A0000128E, - 0x1290000012B1, - 0x12B2000012B6, - 0x12B8000012BF, - 0x12C0000012C1, - 0x12C2000012C6, - 0x12C8000012D7, - 0x12D800001311, - 0x131200001316, - 0x13180000135B, - 0x135D00001360, - 0x138000001390, - 0x13A0000013F6, - 0x14010000166D, - 0x166F00001680, - 0x16810000169B, - 0x16A0000016EB, - 0x16F1000016F9, - 0x170000001716, - 0x171F00001735, - 0x174000001754, - 0x17600000176D, - 0x176E00001771, - 0x177200001774, - 0x1780000017B4, - 0x17B6000017D4, - 0x17D7000017D8, - 0x17DC000017DE, - 0x17E0000017EA, - 0x18100000181A, - 0x182000001879, - 0x1880000018AB, - 0x18B0000018F6, - 0x19000000191F, - 0x19200000192C, - 0x19300000193C, - 0x19460000196E, - 0x197000001975, - 0x1980000019AC, - 0x19B0000019CA, - 0x19D0000019DA, - 0x1A0000001A1C, - 0x1A2000001A5F, - 0x1A6000001A7D, - 0x1A7F00001A8A, - 0x1A9000001A9A, - 0x1AA700001AA8, - 0x1AB000001ABE, - 0x1ABF00001ACF, - 0x1B0000001B4D, - 0x1B5000001B5A, - 0x1B6B00001B74, - 0x1B8000001BF4, - 0x1C0000001C38, - 0x1C4000001C4A, - 0x1C4D00001C7E, - 0x1C8A00001C8B, - 0x1CD000001CD3, - 0x1CD400001CFB, - 0x1D0000001D2C, - 0x1D2F00001D30, - 0x1D3B00001D3C, - 0x1D4E00001D4F, - 0x1D6B00001D78, - 0x1D7900001D9B, - 0x1DC000001E00, - 0x1E0100001E02, - 0x1E0300001E04, - 0x1E0500001E06, - 0x1E0700001E08, - 0x1E0900001E0A, - 0x1E0B00001E0C, - 0x1E0D00001E0E, - 0x1E0F00001E10, - 0x1E1100001E12, - 0x1E1300001E14, - 0x1E1500001E16, - 0x1E1700001E18, - 0x1E1900001E1A, - 0x1E1B00001E1C, - 0x1E1D00001E1E, - 0x1E1F00001E20, - 0x1E2100001E22, - 0x1E2300001E24, - 0x1E2500001E26, - 0x1E2700001E28, - 0x1E2900001E2A, - 0x1E2B00001E2C, - 0x1E2D00001E2E, - 0x1E2F00001E30, - 0x1E3100001E32, - 0x1E3300001E34, - 0x1E3500001E36, - 0x1E3700001E38, - 0x1E3900001E3A, - 0x1E3B00001E3C, - 0x1E3D00001E3E, - 0x1E3F00001E40, - 0x1E4100001E42, - 0x1E4300001E44, - 0x1E4500001E46, - 0x1E4700001E48, - 0x1E4900001E4A, - 0x1E4B00001E4C, - 0x1E4D00001E4E, - 0x1E4F00001E50, - 0x1E5100001E52, - 0x1E5300001E54, - 0x1E5500001E56, - 0x1E5700001E58, - 0x1E5900001E5A, - 0x1E5B00001E5C, - 0x1E5D00001E5E, - 0x1E5F00001E60, - 0x1E6100001E62, - 0x1E6300001E64, - 0x1E6500001E66, - 0x1E6700001E68, - 0x1E6900001E6A, - 0x1E6B00001E6C, - 0x1E6D00001E6E, - 0x1E6F00001E70, - 0x1E7100001E72, - 0x1E7300001E74, - 0x1E7500001E76, - 0x1E7700001E78, - 0x1E7900001E7A, - 0x1E7B00001E7C, - 0x1E7D00001E7E, - 0x1E7F00001E80, - 0x1E8100001E82, - 0x1E8300001E84, - 0x1E8500001E86, - 0x1E8700001E88, - 0x1E8900001E8A, - 0x1E8B00001E8C, - 0x1E8D00001E8E, - 0x1E8F00001E90, - 0x1E9100001E92, - 0x1E9300001E94, - 0x1E9500001E9A, - 0x1E9C00001E9E, - 0x1E9F00001EA0, - 0x1EA100001EA2, - 0x1EA300001EA4, - 0x1EA500001EA6, - 0x1EA700001EA8, - 0x1EA900001EAA, - 0x1EAB00001EAC, - 0x1EAD00001EAE, - 0x1EAF00001EB0, - 0x1EB100001EB2, - 0x1EB300001EB4, - 0x1EB500001EB6, - 0x1EB700001EB8, - 0x1EB900001EBA, - 0x1EBB00001EBC, - 0x1EBD00001EBE, - 0x1EBF00001EC0, - 0x1EC100001EC2, - 0x1EC300001EC4, - 0x1EC500001EC6, - 0x1EC700001EC8, - 0x1EC900001ECA, - 0x1ECB00001ECC, - 0x1ECD00001ECE, - 0x1ECF00001ED0, - 0x1ED100001ED2, - 0x1ED300001ED4, - 0x1ED500001ED6, - 0x1ED700001ED8, - 0x1ED900001EDA, - 0x1EDB00001EDC, - 0x1EDD00001EDE, - 0x1EDF00001EE0, - 0x1EE100001EE2, - 0x1EE300001EE4, - 0x1EE500001EE6, - 0x1EE700001EE8, - 0x1EE900001EEA, - 0x1EEB00001EEC, - 0x1EED00001EEE, - 0x1EEF00001EF0, - 0x1EF100001EF2, - 0x1EF300001EF4, - 0x1EF500001EF6, - 0x1EF700001EF8, - 0x1EF900001EFA, - 0x1EFB00001EFC, - 0x1EFD00001EFE, - 0x1EFF00001F08, - 0x1F1000001F16, - 0x1F2000001F28, - 0x1F3000001F38, - 0x1F4000001F46, - 0x1F5000001F58, - 0x1F6000001F68, - 0x1F7000001F71, - 0x1F7200001F73, - 0x1F7400001F75, - 0x1F7600001F77, - 0x1F7800001F79, - 0x1F7A00001F7B, - 0x1F7C00001F7D, - 0x1FB000001FB2, - 0x1FB600001FB7, - 0x1FC600001FC7, - 0x1FD000001FD3, - 0x1FD600001FD8, - 0x1FE000001FE3, - 0x1FE400001FE8, - 0x1FF600001FF7, - 0x214E0000214F, - 0x218400002185, - 0x2C3000002C60, - 0x2C6100002C62, - 0x2C6500002C67, - 0x2C6800002C69, - 0x2C6A00002C6B, - 0x2C6C00002C6D, - 0x2C7100002C72, - 0x2C7300002C75, - 0x2C7600002C7C, - 0x2C8100002C82, - 0x2C8300002C84, - 0x2C8500002C86, - 0x2C8700002C88, - 0x2C8900002C8A, - 0x2C8B00002C8C, - 0x2C8D00002C8E, - 0x2C8F00002C90, - 0x2C9100002C92, - 0x2C9300002C94, - 0x2C9500002C96, - 0x2C9700002C98, - 0x2C9900002C9A, - 0x2C9B00002C9C, - 0x2C9D00002C9E, - 0x2C9F00002CA0, - 0x2CA100002CA2, - 0x2CA300002CA4, - 0x2CA500002CA6, - 0x2CA700002CA8, - 0x2CA900002CAA, - 0x2CAB00002CAC, - 0x2CAD00002CAE, - 0x2CAF00002CB0, - 0x2CB100002CB2, - 0x2CB300002CB4, - 0x2CB500002CB6, - 0x2CB700002CB8, - 0x2CB900002CBA, - 0x2CBB00002CBC, - 0x2CBD00002CBE, - 0x2CBF00002CC0, - 0x2CC100002CC2, - 0x2CC300002CC4, - 0x2CC500002CC6, - 0x2CC700002CC8, - 0x2CC900002CCA, - 0x2CCB00002CCC, - 0x2CCD00002CCE, - 0x2CCF00002CD0, - 0x2CD100002CD2, - 0x2CD300002CD4, - 0x2CD500002CD6, - 0x2CD700002CD8, - 0x2CD900002CDA, - 0x2CDB00002CDC, - 0x2CDD00002CDE, - 0x2CDF00002CE0, - 0x2CE100002CE2, - 0x2CE300002CE5, - 0x2CEC00002CED, - 0x2CEE00002CF2, - 0x2CF300002CF4, - 0x2D0000002D26, - 0x2D2700002D28, - 0x2D2D00002D2E, - 0x2D3000002D68, - 0x2D7F00002D97, - 0x2DA000002DA7, - 0x2DA800002DAF, - 0x2DB000002DB7, - 0x2DB800002DBF, - 0x2DC000002DC7, - 0x2DC800002DCF, - 0x2DD000002DD7, - 0x2DD800002DDF, - 0x2DE000002E00, - 0x2E2F00002E30, - 0x300500003008, - 0x302A0000302E, - 0x303C0000303D, - 0x304100003097, - 0x30990000309B, - 0x309D0000309F, - 0x30A1000030FB, - 0x30FC000030FF, - 0x310500003130, - 0x31A0000031C0, - 0x31F000003200, - 0x340000004DC0, - 0x4E000000A48D, - 0xA4D00000A4FE, - 0xA5000000A60D, - 0xA6100000A62C, - 0xA6410000A642, - 0xA6430000A644, - 0xA6450000A646, - 0xA6470000A648, - 0xA6490000A64A, - 0xA64B0000A64C, - 0xA64D0000A64E, - 0xA64F0000A650, - 0xA6510000A652, - 0xA6530000A654, - 0xA6550000A656, - 0xA6570000A658, - 0xA6590000A65A, - 0xA65B0000A65C, - 0xA65D0000A65E, - 0xA65F0000A660, - 0xA6610000A662, - 0xA6630000A664, - 0xA6650000A666, - 0xA6670000A668, - 0xA6690000A66A, - 0xA66B0000A66C, - 0xA66D0000A670, - 0xA6740000A67E, - 0xA67F0000A680, - 0xA6810000A682, - 0xA6830000A684, - 0xA6850000A686, - 0xA6870000A688, - 0xA6890000A68A, - 0xA68B0000A68C, - 0xA68D0000A68E, - 0xA68F0000A690, - 0xA6910000A692, - 0xA6930000A694, - 0xA6950000A696, - 0xA6970000A698, - 0xA6990000A69A, - 0xA69B0000A69C, - 0xA69E0000A6E6, - 0xA6F00000A6F2, - 0xA7170000A720, - 0xA7230000A724, - 0xA7250000A726, - 0xA7270000A728, - 0xA7290000A72A, - 0xA72B0000A72C, - 0xA72D0000A72E, - 0xA72F0000A732, - 0xA7330000A734, - 0xA7350000A736, - 0xA7370000A738, - 0xA7390000A73A, - 0xA73B0000A73C, - 0xA73D0000A73E, - 0xA73F0000A740, - 0xA7410000A742, - 0xA7430000A744, - 0xA7450000A746, - 0xA7470000A748, - 0xA7490000A74A, - 0xA74B0000A74C, - 0xA74D0000A74E, - 0xA74F0000A750, - 0xA7510000A752, - 0xA7530000A754, - 0xA7550000A756, - 0xA7570000A758, - 0xA7590000A75A, - 0xA75B0000A75C, - 0xA75D0000A75E, - 0xA75F0000A760, - 0xA7610000A762, - 0xA7630000A764, - 0xA7650000A766, - 0xA7670000A768, - 0xA7690000A76A, - 0xA76B0000A76C, - 0xA76D0000A76E, - 0xA76F0000A770, - 0xA7710000A779, - 0xA77A0000A77B, - 0xA77C0000A77D, - 0xA77F0000A780, - 0xA7810000A782, - 0xA7830000A784, - 0xA7850000A786, - 0xA7870000A789, - 0xA78C0000A78D, - 0xA78E0000A790, - 0xA7910000A792, - 0xA7930000A796, - 0xA7970000A798, - 0xA7990000A79A, - 0xA79B0000A79C, - 0xA79D0000A79E, - 0xA79F0000A7A0, - 0xA7A10000A7A2, - 0xA7A30000A7A4, - 0xA7A50000A7A6, - 0xA7A70000A7A8, - 0xA7A90000A7AA, - 0xA7AF0000A7B0, - 0xA7B50000A7B6, - 0xA7B70000A7B8, - 0xA7B90000A7BA, - 0xA7BB0000A7BC, - 0xA7BD0000A7BE, - 0xA7BF0000A7C0, - 0xA7C10000A7C2, - 0xA7C30000A7C4, - 0xA7C80000A7C9, - 0xA7CA0000A7CB, - 0xA7CD0000A7CE, - 0xA7D10000A7D2, - 0xA7D30000A7D4, - 0xA7D50000A7D6, - 0xA7D70000A7D8, - 0xA7D90000A7DA, - 0xA7DB0000A7DC, - 0xA7F60000A7F8, - 0xA7FA0000A828, - 0xA82C0000A82D, - 0xA8400000A874, - 0xA8800000A8C6, - 0xA8D00000A8DA, - 0xA8E00000A8F8, - 0xA8FB0000A8FC, - 0xA8FD0000A92E, - 0xA9300000A954, - 0xA9800000A9C1, - 0xA9CF0000A9DA, - 0xA9E00000A9FF, - 0xAA000000AA37, - 0xAA400000AA4E, - 0xAA500000AA5A, - 0xAA600000AA77, - 0xAA7A0000AAC3, - 0xAADB0000AADE, - 0xAAE00000AAF0, - 0xAAF20000AAF7, - 0xAB010000AB07, - 0xAB090000AB0F, - 0xAB110000AB17, - 0xAB200000AB27, - 0xAB280000AB2F, - 0xAB300000AB5B, - 0xAB600000AB69, - 0xABC00000ABEB, - 0xABEC0000ABEE, - 0xABF00000ABFA, - 0xAC000000D7A4, - 0xFA0E0000FA10, - 0xFA110000FA12, - 0xFA130000FA15, - 0xFA1F0000FA20, - 0xFA210000FA22, - 0xFA230000FA25, - 0xFA270000FA2A, - 0xFB1E0000FB1F, - 0xFE200000FE30, - 0xFE730000FE74, - 0x100000001000C, - 0x1000D00010027, - 0x100280001003B, - 0x1003C0001003E, - 0x1003F0001004E, - 0x100500001005E, - 0x10080000100FB, - 0x101FD000101FE, - 0x102800001029D, - 0x102A0000102D1, - 0x102E0000102E1, - 0x1030000010320, - 0x1032D00010341, - 0x103420001034A, - 0x103500001037B, - 0x103800001039E, - 0x103A0000103C4, - 0x103C8000103D0, - 0x104280001049E, - 0x104A0000104AA, - 0x104D8000104FC, - 0x1050000010528, - 0x1053000010564, - 0x10597000105A2, - 0x105A3000105B2, - 0x105B3000105BA, - 0x105BB000105BD, - 0x105C0000105F4, - 0x1060000010737, - 0x1074000010756, - 0x1076000010768, - 0x1078000010781, - 0x1080000010806, - 0x1080800010809, - 0x1080A00010836, - 0x1083700010839, - 0x1083C0001083D, - 0x1083F00010856, - 0x1086000010877, - 0x108800001089F, - 0x108E0000108F3, - 0x108F4000108F6, - 0x1090000010916, - 0x109200001093A, - 0x10980000109B8, - 0x109BE000109C0, - 0x10A0000010A04, - 0x10A0500010A07, - 0x10A0C00010A14, - 0x10A1500010A18, - 0x10A1900010A36, - 0x10A3800010A3B, - 0x10A3F00010A40, - 0x10A6000010A7D, - 0x10A8000010A9D, - 0x10AC000010AC8, - 0x10AC900010AE7, - 0x10B0000010B36, - 0x10B4000010B56, - 0x10B6000010B73, - 0x10B8000010B92, - 0x10C0000010C49, - 0x10CC000010CF3, - 0x10D0000010D28, - 0x10D3000010D3A, - 0x10D4000010D50, - 0x10D6900010D6E, - 0x10D6F00010D86, - 0x10E8000010EAA, - 0x10EAB00010EAD, - 0x10EB000010EB2, - 0x10EC200010EC5, - 0x10EFC00010F1D, - 0x10F2700010F28, - 0x10F3000010F51, - 0x10F7000010F86, - 0x10FB000010FC5, - 0x10FE000010FF7, - 0x1100000011047, - 0x1106600011076, - 0x1107F000110BB, - 0x110C2000110C3, - 0x110D0000110E9, - 0x110F0000110FA, - 0x1110000011135, - 0x1113600011140, - 0x1114400011148, - 0x1115000011174, - 0x1117600011177, - 0x11180000111C5, - 0x111C9000111CD, - 0x111CE000111DB, - 0x111DC000111DD, - 0x1120000011212, - 0x1121300011238, - 0x1123E00011242, - 0x1128000011287, - 0x1128800011289, - 0x1128A0001128E, - 0x1128F0001129E, - 0x1129F000112A9, - 0x112B0000112EB, - 0x112F0000112FA, - 0x1130000011304, - 0x113050001130D, - 0x1130F00011311, - 0x1131300011329, - 0x1132A00011331, - 0x1133200011334, - 0x113350001133A, - 0x1133B00011345, - 0x1134700011349, - 0x1134B0001134E, - 0x1135000011351, - 0x1135700011358, - 0x1135D00011364, - 0x113660001136D, - 0x1137000011375, - 0x113800001138A, - 0x1138B0001138C, - 0x1138E0001138F, - 0x11390000113B6, - 0x113B7000113C1, - 0x113C2000113C3, - 0x113C5000113C6, - 0x113C7000113CB, - 0x113CC000113D4, - 0x113E1000113E3, - 0x114000001144B, - 0x114500001145A, - 0x1145E00011462, - 0x11480000114C6, - 0x114C7000114C8, - 0x114D0000114DA, - 0x11580000115B6, - 0x115B8000115C1, - 0x115D8000115DE, - 0x1160000011641, - 0x1164400011645, - 0x116500001165A, - 0x11680000116B9, - 0x116C0000116CA, - 0x116D0000116E4, - 0x117000001171B, - 0x1171D0001172C, - 0x117300001173A, - 0x1174000011747, - 0x118000001183B, - 0x118C0000118EA, - 0x118FF00011907, - 0x119090001190A, - 0x1190C00011914, - 0x1191500011917, - 0x1191800011936, - 0x1193700011939, - 0x1193B00011944, - 0x119500001195A, - 0x119A0000119A8, - 0x119AA000119D8, - 0x119DA000119E2, - 0x119E3000119E5, - 0x11A0000011A3F, - 0x11A4700011A48, - 0x11A5000011A9A, - 0x11A9D00011A9E, - 0x11AB000011AF9, - 0x11BC000011BE1, - 0x11BF000011BFA, - 0x11C0000011C09, - 0x11C0A00011C37, - 0x11C3800011C41, - 0x11C5000011C5A, - 0x11C7200011C90, - 0x11C9200011CA8, - 0x11CA900011CB7, - 0x11D0000011D07, - 0x11D0800011D0A, - 0x11D0B00011D37, - 0x11D3A00011D3B, - 0x11D3C00011D3E, - 0x11D3F00011D48, - 0x11D5000011D5A, - 0x11D6000011D66, - 0x11D6700011D69, - 0x11D6A00011D8F, - 0x11D9000011D92, - 0x11D9300011D99, - 0x11DA000011DAA, - 0x11EE000011EF7, - 0x11F0000011F11, - 0x11F1200011F3B, - 0x11F3E00011F43, - 0x11F5000011F5B, - 0x11FB000011FB1, - 0x120000001239A, - 0x1248000012544, - 0x12F9000012FF1, - 0x1300000013430, - 0x1344000013456, - 0x13460000143FB, - 0x1440000014647, - 0x161000001613A, - 0x1680000016A39, - 0x16A4000016A5F, - 0x16A6000016A6A, - 0x16A7000016ABF, - 0x16AC000016ACA, - 0x16AD000016AEE, - 0x16AF000016AF5, - 0x16B0000016B37, - 0x16B4000016B44, - 0x16B5000016B5A, - 0x16B6300016B78, - 0x16B7D00016B90, - 0x16D4000016D6D, - 0x16D7000016D7A, - 0x16E6000016E80, - 0x16F0000016F4B, - 0x16F4F00016F88, - 0x16F8F00016FA0, - 0x16FE000016FE2, - 0x16FE300016FE5, - 0x16FF000016FF2, - 0x17000000187F8, - 0x1880000018CD6, - 0x18CFF00018D09, - 0x1AFF00001AFF4, - 0x1AFF50001AFFC, - 0x1AFFD0001AFFF, - 0x1B0000001B123, - 0x1B1320001B133, - 0x1B1500001B153, - 0x1B1550001B156, - 0x1B1640001B168, - 0x1B1700001B2FC, - 0x1BC000001BC6B, - 0x1BC700001BC7D, - 0x1BC800001BC89, - 0x1BC900001BC9A, - 0x1BC9D0001BC9F, - 0x1CCF00001CCFA, - 0x1CF000001CF2E, - 0x1CF300001CF47, - 0x1DA000001DA37, - 0x1DA3B0001DA6D, - 0x1DA750001DA76, - 0x1DA840001DA85, - 0x1DA9B0001DAA0, - 0x1DAA10001DAB0, - 0x1DF000001DF1F, - 0x1DF250001DF2B, - 0x1E0000001E007, - 0x1E0080001E019, - 0x1E01B0001E022, - 0x1E0230001E025, - 0x1E0260001E02B, - 0x1E08F0001E090, - 0x1E1000001E12D, - 0x1E1300001E13E, - 0x1E1400001E14A, - 0x1E14E0001E14F, - 0x1E2900001E2AF, - 0x1E2C00001E2FA, - 0x1E4D00001E4FA, - 0x1E5D00001E5FB, - 0x1E7E00001E7E7, - 0x1E7E80001E7EC, - 0x1E7ED0001E7EF, - 0x1E7F00001E7FF, - 0x1E8000001E8C5, - 0x1E8D00001E8D7, - 0x1E9220001E94C, - 0x1E9500001E95A, - 0x200000002A6E0, - 0x2A7000002B73A, - 0x2B7400002B81E, - 0x2B8200002CEA2, - 0x2CEB00002EBE1, - 0x2EBF00002EE5E, - 0x300000003134B, - 0x31350000323B0, - ), - "CONTEXTJ": (0x200C0000200E,), - "CONTEXTO": ( - 0xB7000000B8, - 0x37500000376, - 0x5F3000005F5, - 0x6600000066A, - 0x6F0000006FA, - 0x30FB000030FC, - ), -} diff --git a/backend/venv39/lib/python3.9/site-packages/idna/intranges.py b/backend/venv39/lib/python3.9/site-packages/idna/intranges.py deleted file mode 100644 index 7bfaa8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/intranges.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Given a list of integers, made up of (hopefully) a small number of long runs -of consecutive integers, compute a representation of the form -((start1, end1), (start2, end2) ...). Then answer the question "was x present -in the original list?" in time O(log(# runs)). -""" - -import bisect -from typing import List, Tuple - - -def intranges_from_list(list_: List[int]) -> Tuple[int, ...]: - """Represent a list of integers as a sequence of ranges: - ((start_0, end_0), (start_1, end_1), ...), such that the original - integers are exactly those x such that start_i <= x < end_i for some i. - - Ranges are encoded as single integers (start << 32 | end), not as tuples. - """ - - sorted_list = sorted(list_) - ranges = [] - last_write = -1 - for i in range(len(sorted_list)): - if i + 1 < len(sorted_list): - if sorted_list[i] == sorted_list[i + 1] - 1: - continue - current_range = sorted_list[last_write + 1 : i + 1] - ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) - last_write = i - - return tuple(ranges) - - -def _encode_range(start: int, end: int) -> int: - return (start << 32) | end - - -def _decode_range(r: int) -> Tuple[int, int]: - return (r >> 32), (r & ((1 << 32) - 1)) - - -def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool: - """Determine if `int_` falls into one of the ranges in `ranges`.""" - tuple_ = _encode_range(int_, 0) - pos = bisect.bisect_left(ranges, tuple_) - # we could be immediately ahead of a tuple (start, end) - # with start < int_ <= end - if pos > 0: - left, right = _decode_range(ranges[pos - 1]) - if left <= int_ < right: - return True - # or we could be immediately behind a tuple (int_, end) - if pos < len(ranges): - left, _ = _decode_range(ranges[pos]) - if left == int_: - return True - return False diff --git a/backend/venv39/lib/python3.9/site-packages/idna/package_data.py b/backend/venv39/lib/python3.9/site-packages/idna/package_data.py deleted file mode 100644 index 7272c8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/package_data.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "3.11" diff --git a/backend/venv39/lib/python3.9/site-packages/idna/py.typed b/backend/venv39/lib/python3.9/site-packages/idna/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/idna/uts46data.py b/backend/venv39/lib/python3.9/site-packages/idna/uts46data.py deleted file mode 100644 index 4610b71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/idna/uts46data.py +++ /dev/null @@ -1,8841 +0,0 @@ -# This file is automatically generated by tools/idna-data -# vim: set fileencoding=utf-8 : - -from typing import List, Tuple, Union - -"""IDNA Mapping Table from UTS46.""" - - -__version__ = "16.0.0" - - -def _seg_0() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x0, "V"), - (0x1, "V"), - (0x2, "V"), - (0x3, "V"), - (0x4, "V"), - (0x5, "V"), - (0x6, "V"), - (0x7, "V"), - (0x8, "V"), - (0x9, "V"), - (0xA, "V"), - (0xB, "V"), - (0xC, "V"), - (0xD, "V"), - (0xE, "V"), - (0xF, "V"), - (0x10, "V"), - (0x11, "V"), - (0x12, "V"), - (0x13, "V"), - (0x14, "V"), - (0x15, "V"), - (0x16, "V"), - (0x17, "V"), - (0x18, "V"), - (0x19, "V"), - (0x1A, "V"), - (0x1B, "V"), - (0x1C, "V"), - (0x1D, "V"), - (0x1E, "V"), - (0x1F, "V"), - (0x20, "V"), - (0x21, "V"), - (0x22, "V"), - (0x23, "V"), - (0x24, "V"), - (0x25, "V"), - (0x26, "V"), - (0x27, "V"), - (0x28, "V"), - (0x29, "V"), - (0x2A, "V"), - (0x2B, "V"), - (0x2C, "V"), - (0x2D, "V"), - (0x2E, "V"), - (0x2F, "V"), - (0x30, "V"), - (0x31, "V"), - (0x32, "V"), - (0x33, "V"), - (0x34, "V"), - (0x35, "V"), - (0x36, "V"), - (0x37, "V"), - (0x38, "V"), - (0x39, "V"), - (0x3A, "V"), - (0x3B, "V"), - (0x3C, "V"), - (0x3D, "V"), - (0x3E, "V"), - (0x3F, "V"), - (0x40, "V"), - (0x41, "M", "a"), - (0x42, "M", "b"), - (0x43, "M", "c"), - (0x44, "M", "d"), - (0x45, "M", "e"), - (0x46, "M", "f"), - (0x47, "M", "g"), - (0x48, "M", "h"), - (0x49, "M", "i"), - (0x4A, "M", "j"), - (0x4B, "M", "k"), - (0x4C, "M", "l"), - (0x4D, "M", "m"), - (0x4E, "M", "n"), - (0x4F, "M", "o"), - (0x50, "M", "p"), - (0x51, "M", "q"), - (0x52, "M", "r"), - (0x53, "M", "s"), - (0x54, "M", "t"), - (0x55, "M", "u"), - (0x56, "M", "v"), - (0x57, "M", "w"), - (0x58, "M", "x"), - (0x59, "M", "y"), - (0x5A, "M", "z"), - (0x5B, "V"), - (0x5C, "V"), - (0x5D, "V"), - (0x5E, "V"), - (0x5F, "V"), - (0x60, "V"), - (0x61, "V"), - (0x62, "V"), - (0x63, "V"), - ] - - -def _seg_1() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x64, "V"), - (0x65, "V"), - (0x66, "V"), - (0x67, "V"), - (0x68, "V"), - (0x69, "V"), - (0x6A, "V"), - (0x6B, "V"), - (0x6C, "V"), - (0x6D, "V"), - (0x6E, "V"), - (0x6F, "V"), - (0x70, "V"), - (0x71, "V"), - (0x72, "V"), - (0x73, "V"), - (0x74, "V"), - (0x75, "V"), - (0x76, "V"), - (0x77, "V"), - (0x78, "V"), - (0x79, "V"), - (0x7A, "V"), - (0x7B, "V"), - (0x7C, "V"), - (0x7D, "V"), - (0x7E, "V"), - (0x7F, "V"), - (0x80, "X"), - (0x81, "X"), - (0x82, "X"), - (0x83, "X"), - (0x84, "X"), - (0x85, "X"), - (0x86, "X"), - (0x87, "X"), - (0x88, "X"), - (0x89, "X"), - (0x8A, "X"), - (0x8B, "X"), - (0x8C, "X"), - (0x8D, "X"), - (0x8E, "X"), - (0x8F, "X"), - (0x90, "X"), - (0x91, "X"), - (0x92, "X"), - (0x93, "X"), - (0x94, "X"), - (0x95, "X"), - (0x96, "X"), - (0x97, "X"), - (0x98, "X"), - (0x99, "X"), - (0x9A, "X"), - (0x9B, "X"), - (0x9C, "X"), - (0x9D, "X"), - (0x9E, "X"), - (0x9F, "X"), - (0xA0, "M", " "), - (0xA1, "V"), - (0xA2, "V"), - (0xA3, "V"), - (0xA4, "V"), - (0xA5, "V"), - (0xA6, "V"), - (0xA7, "V"), - (0xA8, "M", " ̈"), - (0xA9, "V"), - (0xAA, "M", "a"), - (0xAB, "V"), - (0xAC, "V"), - (0xAD, "I"), - (0xAE, "V"), - (0xAF, "M", " ̄"), - (0xB0, "V"), - (0xB1, "V"), - (0xB2, "M", "2"), - (0xB3, "M", "3"), - (0xB4, "M", " ́"), - (0xB5, "M", "μ"), - (0xB6, "V"), - (0xB7, "V"), - (0xB8, "M", " ̧"), - (0xB9, "M", "1"), - (0xBA, "M", "o"), - (0xBB, "V"), - (0xBC, "M", "1⁄4"), - (0xBD, "M", "1⁄2"), - (0xBE, "M", "3⁄4"), - (0xBF, "V"), - (0xC0, "M", "à"), - (0xC1, "M", "á"), - (0xC2, "M", "â"), - (0xC3, "M", "ã"), - (0xC4, "M", "ä"), - (0xC5, "M", "å"), - (0xC6, "M", "æ"), - (0xC7, "M", "ç"), - ] - - -def _seg_2() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xC8, "M", "è"), - (0xC9, "M", "é"), - (0xCA, "M", "ê"), - (0xCB, "M", "ë"), - (0xCC, "M", "ì"), - (0xCD, "M", "í"), - (0xCE, "M", "î"), - (0xCF, "M", "ï"), - (0xD0, "M", "ð"), - (0xD1, "M", "ñ"), - (0xD2, "M", "ò"), - (0xD3, "M", "ó"), - (0xD4, "M", "ô"), - (0xD5, "M", "õ"), - (0xD6, "M", "ö"), - (0xD7, "V"), - (0xD8, "M", "ø"), - (0xD9, "M", "ù"), - (0xDA, "M", "ú"), - (0xDB, "M", "û"), - (0xDC, "M", "ü"), - (0xDD, "M", "ý"), - (0xDE, "M", "þ"), - (0xDF, "D", "ss"), - (0xE0, "V"), - (0xE1, "V"), - (0xE2, "V"), - (0xE3, "V"), - (0xE4, "V"), - (0xE5, "V"), - (0xE6, "V"), - (0xE7, "V"), - (0xE8, "V"), - (0xE9, "V"), - (0xEA, "V"), - (0xEB, "V"), - (0xEC, "V"), - (0xED, "V"), - (0xEE, "V"), - (0xEF, "V"), - (0xF0, "V"), - (0xF1, "V"), - (0xF2, "V"), - (0xF3, "V"), - (0xF4, "V"), - (0xF5, "V"), - (0xF6, "V"), - (0xF7, "V"), - (0xF8, "V"), - (0xF9, "V"), - (0xFA, "V"), - (0xFB, "V"), - (0xFC, "V"), - (0xFD, "V"), - (0xFE, "V"), - (0xFF, "V"), - (0x100, "M", "ā"), - (0x101, "V"), - (0x102, "M", "ă"), - (0x103, "V"), - (0x104, "M", "ą"), - (0x105, "V"), - (0x106, "M", "ć"), - (0x107, "V"), - (0x108, "M", "ĉ"), - (0x109, "V"), - (0x10A, "M", "ċ"), - (0x10B, "V"), - (0x10C, "M", "č"), - (0x10D, "V"), - (0x10E, "M", "ď"), - (0x10F, "V"), - (0x110, "M", "đ"), - (0x111, "V"), - (0x112, "M", "ē"), - (0x113, "V"), - (0x114, "M", "ĕ"), - (0x115, "V"), - (0x116, "M", "ė"), - (0x117, "V"), - (0x118, "M", "ę"), - (0x119, "V"), - (0x11A, "M", "ě"), - (0x11B, "V"), - (0x11C, "M", "ĝ"), - (0x11D, "V"), - (0x11E, "M", "ğ"), - (0x11F, "V"), - (0x120, "M", "ġ"), - (0x121, "V"), - (0x122, "M", "ģ"), - (0x123, "V"), - (0x124, "M", "ĥ"), - (0x125, "V"), - (0x126, "M", "ħ"), - (0x127, "V"), - (0x128, "M", "ĩ"), - (0x129, "V"), - (0x12A, "M", "ī"), - (0x12B, "V"), - ] - - -def _seg_3() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x12C, "M", "ĭ"), - (0x12D, "V"), - (0x12E, "M", "į"), - (0x12F, "V"), - (0x130, "M", "i̇"), - (0x131, "V"), - (0x132, "M", "ij"), - (0x134, "M", "ĵ"), - (0x135, "V"), - (0x136, "M", "ķ"), - (0x137, "V"), - (0x139, "M", "ĺ"), - (0x13A, "V"), - (0x13B, "M", "ļ"), - (0x13C, "V"), - (0x13D, "M", "ľ"), - (0x13E, "V"), - (0x13F, "M", "l·"), - (0x141, "M", "ł"), - (0x142, "V"), - (0x143, "M", "ń"), - (0x144, "V"), - (0x145, "M", "ņ"), - (0x146, "V"), - (0x147, "M", "ň"), - (0x148, "V"), - (0x149, "M", "ʼn"), - (0x14A, "M", "ŋ"), - (0x14B, "V"), - (0x14C, "M", "ō"), - (0x14D, "V"), - (0x14E, "M", "ŏ"), - (0x14F, "V"), - (0x150, "M", "ő"), - (0x151, "V"), - (0x152, "M", "œ"), - (0x153, "V"), - (0x154, "M", "ŕ"), - (0x155, "V"), - (0x156, "M", "ŗ"), - (0x157, "V"), - (0x158, "M", "ř"), - (0x159, "V"), - (0x15A, "M", "ś"), - (0x15B, "V"), - (0x15C, "M", "ŝ"), - (0x15D, "V"), - (0x15E, "M", "ş"), - (0x15F, "V"), - (0x160, "M", "š"), - (0x161, "V"), - (0x162, "M", "ţ"), - (0x163, "V"), - (0x164, "M", "ť"), - (0x165, "V"), - (0x166, "M", "ŧ"), - (0x167, "V"), - (0x168, "M", "ũ"), - (0x169, "V"), - (0x16A, "M", "ū"), - (0x16B, "V"), - (0x16C, "M", "ŭ"), - (0x16D, "V"), - (0x16E, "M", "ů"), - (0x16F, "V"), - (0x170, "M", "ű"), - (0x171, "V"), - (0x172, "M", "ų"), - (0x173, "V"), - (0x174, "M", "ŵ"), - (0x175, "V"), - (0x176, "M", "ŷ"), - (0x177, "V"), - (0x178, "M", "ÿ"), - (0x179, "M", "ź"), - (0x17A, "V"), - (0x17B, "M", "ż"), - (0x17C, "V"), - (0x17D, "M", "ž"), - (0x17E, "V"), - (0x17F, "M", "s"), - (0x180, "V"), - (0x181, "M", "ɓ"), - (0x182, "M", "ƃ"), - (0x183, "V"), - (0x184, "M", "ƅ"), - (0x185, "V"), - (0x186, "M", "ɔ"), - (0x187, "M", "ƈ"), - (0x188, "V"), - (0x189, "M", "ɖ"), - (0x18A, "M", "ɗ"), - (0x18B, "M", "ƌ"), - (0x18C, "V"), - (0x18E, "M", "ǝ"), - (0x18F, "M", "ə"), - (0x190, "M", "ɛ"), - (0x191, "M", "ƒ"), - (0x192, "V"), - (0x193, "M", "ɠ"), - ] - - -def _seg_4() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x194, "M", "ɣ"), - (0x195, "V"), - (0x196, "M", "ɩ"), - (0x197, "M", "ɨ"), - (0x198, "M", "ƙ"), - (0x199, "V"), - (0x19C, "M", "ɯ"), - (0x19D, "M", "ɲ"), - (0x19E, "V"), - (0x19F, "M", "ɵ"), - (0x1A0, "M", "ơ"), - (0x1A1, "V"), - (0x1A2, "M", "ƣ"), - (0x1A3, "V"), - (0x1A4, "M", "ƥ"), - (0x1A5, "V"), - (0x1A6, "M", "ʀ"), - (0x1A7, "M", "ƨ"), - (0x1A8, "V"), - (0x1A9, "M", "ʃ"), - (0x1AA, "V"), - (0x1AC, "M", "ƭ"), - (0x1AD, "V"), - (0x1AE, "M", "ʈ"), - (0x1AF, "M", "ư"), - (0x1B0, "V"), - (0x1B1, "M", "ʊ"), - (0x1B2, "M", "ʋ"), - (0x1B3, "M", "ƴ"), - (0x1B4, "V"), - (0x1B5, "M", "ƶ"), - (0x1B6, "V"), - (0x1B7, "M", "ʒ"), - (0x1B8, "M", "ƹ"), - (0x1B9, "V"), - (0x1BC, "M", "ƽ"), - (0x1BD, "V"), - (0x1C4, "M", "dž"), - (0x1C7, "M", "lj"), - (0x1CA, "M", "nj"), - (0x1CD, "M", "ǎ"), - (0x1CE, "V"), - (0x1CF, "M", "ǐ"), - (0x1D0, "V"), - (0x1D1, "M", "ǒ"), - (0x1D2, "V"), - (0x1D3, "M", "ǔ"), - (0x1D4, "V"), - (0x1D5, "M", "ǖ"), - (0x1D6, "V"), - (0x1D7, "M", "ǘ"), - (0x1D8, "V"), - (0x1D9, "M", "ǚ"), - (0x1DA, "V"), - (0x1DB, "M", "ǜ"), - (0x1DC, "V"), - (0x1DE, "M", "ǟ"), - (0x1DF, "V"), - (0x1E0, "M", "ǡ"), - (0x1E1, "V"), - (0x1E2, "M", "ǣ"), - (0x1E3, "V"), - (0x1E4, "M", "ǥ"), - (0x1E5, "V"), - (0x1E6, "M", "ǧ"), - (0x1E7, "V"), - (0x1E8, "M", "ǩ"), - (0x1E9, "V"), - (0x1EA, "M", "ǫ"), - (0x1EB, "V"), - (0x1EC, "M", "ǭ"), - (0x1ED, "V"), - (0x1EE, "M", "ǯ"), - (0x1EF, "V"), - (0x1F1, "M", "dz"), - (0x1F4, "M", "ǵ"), - (0x1F5, "V"), - (0x1F6, "M", "ƕ"), - (0x1F7, "M", "ƿ"), - (0x1F8, "M", "ǹ"), - (0x1F9, "V"), - (0x1FA, "M", "ǻ"), - (0x1FB, "V"), - (0x1FC, "M", "ǽ"), - (0x1FD, "V"), - (0x1FE, "M", "ǿ"), - (0x1FF, "V"), - (0x200, "M", "ȁ"), - (0x201, "V"), - (0x202, "M", "ȃ"), - (0x203, "V"), - (0x204, "M", "ȅ"), - (0x205, "V"), - (0x206, "M", "ȇ"), - (0x207, "V"), - (0x208, "M", "ȉ"), - (0x209, "V"), - (0x20A, "M", "ȋ"), - (0x20B, "V"), - (0x20C, "M", "ȍ"), - ] - - -def _seg_5() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x20D, "V"), - (0x20E, "M", "ȏ"), - (0x20F, "V"), - (0x210, "M", "ȑ"), - (0x211, "V"), - (0x212, "M", "ȓ"), - (0x213, "V"), - (0x214, "M", "ȕ"), - (0x215, "V"), - (0x216, "M", "ȗ"), - (0x217, "V"), - (0x218, "M", "ș"), - (0x219, "V"), - (0x21A, "M", "ț"), - (0x21B, "V"), - (0x21C, "M", "ȝ"), - (0x21D, "V"), - (0x21E, "M", "ȟ"), - (0x21F, "V"), - (0x220, "M", "ƞ"), - (0x221, "V"), - (0x222, "M", "ȣ"), - (0x223, "V"), - (0x224, "M", "ȥ"), - (0x225, "V"), - (0x226, "M", "ȧ"), - (0x227, "V"), - (0x228, "M", "ȩ"), - (0x229, "V"), - (0x22A, "M", "ȫ"), - (0x22B, "V"), - (0x22C, "M", "ȭ"), - (0x22D, "V"), - (0x22E, "M", "ȯ"), - (0x22F, "V"), - (0x230, "M", "ȱ"), - (0x231, "V"), - (0x232, "M", "ȳ"), - (0x233, "V"), - (0x23A, "M", "ⱥ"), - (0x23B, "M", "ȼ"), - (0x23C, "V"), - (0x23D, "M", "ƚ"), - (0x23E, "M", "ⱦ"), - (0x23F, "V"), - (0x241, "M", "ɂ"), - (0x242, "V"), - (0x243, "M", "ƀ"), - (0x244, "M", "ʉ"), - (0x245, "M", "ʌ"), - (0x246, "M", "ɇ"), - (0x247, "V"), - (0x248, "M", "ɉ"), - (0x249, "V"), - (0x24A, "M", "ɋ"), - (0x24B, "V"), - (0x24C, "M", "ɍ"), - (0x24D, "V"), - (0x24E, "M", "ɏ"), - (0x24F, "V"), - (0x2B0, "M", "h"), - (0x2B1, "M", "ɦ"), - (0x2B2, "M", "j"), - (0x2B3, "M", "r"), - (0x2B4, "M", "ɹ"), - (0x2B5, "M", "ɻ"), - (0x2B6, "M", "ʁ"), - (0x2B7, "M", "w"), - (0x2B8, "M", "y"), - (0x2B9, "V"), - (0x2D8, "M", " ̆"), - (0x2D9, "M", " ̇"), - (0x2DA, "M", " ̊"), - (0x2DB, "M", " ̨"), - (0x2DC, "M", " ̃"), - (0x2DD, "M", " ̋"), - (0x2DE, "V"), - (0x2E0, "M", "ɣ"), - (0x2E1, "M", "l"), - (0x2E2, "M", "s"), - (0x2E3, "M", "x"), - (0x2E4, "M", "ʕ"), - (0x2E5, "V"), - (0x340, "M", "̀"), - (0x341, "M", "́"), - (0x342, "V"), - (0x343, "M", "̓"), - (0x344, "M", "̈́"), - (0x345, "M", "ι"), - (0x346, "V"), - (0x34F, "I"), - (0x350, "V"), - (0x370, "M", "ͱ"), - (0x371, "V"), - (0x372, "M", "ͳ"), - (0x373, "V"), - (0x374, "M", "ʹ"), - (0x375, "V"), - (0x376, "M", "ͷ"), - (0x377, "V"), - ] - - -def _seg_6() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x378, "X"), - (0x37A, "M", " ι"), - (0x37B, "V"), - (0x37E, "M", ";"), - (0x37F, "M", "ϳ"), - (0x380, "X"), - (0x384, "M", " ́"), - (0x385, "M", " ̈́"), - (0x386, "M", "ά"), - (0x387, "M", "·"), - (0x388, "M", "έ"), - (0x389, "M", "ή"), - (0x38A, "M", "ί"), - (0x38B, "X"), - (0x38C, "M", "ό"), - (0x38D, "X"), - (0x38E, "M", "ύ"), - (0x38F, "M", "ώ"), - (0x390, "V"), - (0x391, "M", "α"), - (0x392, "M", "β"), - (0x393, "M", "γ"), - (0x394, "M", "δ"), - (0x395, "M", "ε"), - (0x396, "M", "ζ"), - (0x397, "M", "η"), - (0x398, "M", "θ"), - (0x399, "M", "ι"), - (0x39A, "M", "κ"), - (0x39B, "M", "λ"), - (0x39C, "M", "μ"), - (0x39D, "M", "ν"), - (0x39E, "M", "ξ"), - (0x39F, "M", "ο"), - (0x3A0, "M", "π"), - (0x3A1, "M", "ρ"), - (0x3A2, "X"), - (0x3A3, "M", "σ"), - (0x3A4, "M", "τ"), - (0x3A5, "M", "υ"), - (0x3A6, "M", "φ"), - (0x3A7, "M", "χ"), - (0x3A8, "M", "ψ"), - (0x3A9, "M", "ω"), - (0x3AA, "M", "ϊ"), - (0x3AB, "M", "ϋ"), - (0x3AC, "V"), - (0x3C2, "D", "σ"), - (0x3C3, "V"), - (0x3CF, "M", "ϗ"), - (0x3D0, "M", "β"), - (0x3D1, "M", "θ"), - (0x3D2, "M", "υ"), - (0x3D3, "M", "ύ"), - (0x3D4, "M", "ϋ"), - (0x3D5, "M", "φ"), - (0x3D6, "M", "π"), - (0x3D7, "V"), - (0x3D8, "M", "ϙ"), - (0x3D9, "V"), - (0x3DA, "M", "ϛ"), - (0x3DB, "V"), - (0x3DC, "M", "ϝ"), - (0x3DD, "V"), - (0x3DE, "M", "ϟ"), - (0x3DF, "V"), - (0x3E0, "M", "ϡ"), - (0x3E1, "V"), - (0x3E2, "M", "ϣ"), - (0x3E3, "V"), - (0x3E4, "M", "ϥ"), - (0x3E5, "V"), - (0x3E6, "M", "ϧ"), - (0x3E7, "V"), - (0x3E8, "M", "ϩ"), - (0x3E9, "V"), - (0x3EA, "M", "ϫ"), - (0x3EB, "V"), - (0x3EC, "M", "ϭ"), - (0x3ED, "V"), - (0x3EE, "M", "ϯ"), - (0x3EF, "V"), - (0x3F0, "M", "κ"), - (0x3F1, "M", "ρ"), - (0x3F2, "M", "σ"), - (0x3F3, "V"), - (0x3F4, "M", "θ"), - (0x3F5, "M", "ε"), - (0x3F6, "V"), - (0x3F7, "M", "ϸ"), - (0x3F8, "V"), - (0x3F9, "M", "σ"), - (0x3FA, "M", "ϻ"), - (0x3FB, "V"), - (0x3FD, "M", "ͻ"), - (0x3FE, "M", "ͼ"), - (0x3FF, "M", "ͽ"), - (0x400, "M", "ѐ"), - (0x401, "M", "ё"), - (0x402, "M", "ђ"), - ] - - -def _seg_7() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x403, "M", "ѓ"), - (0x404, "M", "є"), - (0x405, "M", "ѕ"), - (0x406, "M", "і"), - (0x407, "M", "ї"), - (0x408, "M", "ј"), - (0x409, "M", "љ"), - (0x40A, "M", "њ"), - (0x40B, "M", "ћ"), - (0x40C, "M", "ќ"), - (0x40D, "M", "ѝ"), - (0x40E, "M", "ў"), - (0x40F, "M", "џ"), - (0x410, "M", "а"), - (0x411, "M", "б"), - (0x412, "M", "в"), - (0x413, "M", "г"), - (0x414, "M", "д"), - (0x415, "M", "е"), - (0x416, "M", "ж"), - (0x417, "M", "з"), - (0x418, "M", "и"), - (0x419, "M", "й"), - (0x41A, "M", "к"), - (0x41B, "M", "л"), - (0x41C, "M", "м"), - (0x41D, "M", "н"), - (0x41E, "M", "о"), - (0x41F, "M", "п"), - (0x420, "M", "р"), - (0x421, "M", "с"), - (0x422, "M", "т"), - (0x423, "M", "у"), - (0x424, "M", "ф"), - (0x425, "M", "х"), - (0x426, "M", "ц"), - (0x427, "M", "ч"), - (0x428, "M", "ш"), - (0x429, "M", "щ"), - (0x42A, "M", "ъ"), - (0x42B, "M", "ы"), - (0x42C, "M", "ь"), - (0x42D, "M", "э"), - (0x42E, "M", "ю"), - (0x42F, "M", "я"), - (0x430, "V"), - (0x460, "M", "ѡ"), - (0x461, "V"), - (0x462, "M", "ѣ"), - (0x463, "V"), - (0x464, "M", "ѥ"), - (0x465, "V"), - (0x466, "M", "ѧ"), - (0x467, "V"), - (0x468, "M", "ѩ"), - (0x469, "V"), - (0x46A, "M", "ѫ"), - (0x46B, "V"), - (0x46C, "M", "ѭ"), - (0x46D, "V"), - (0x46E, "M", "ѯ"), - (0x46F, "V"), - (0x470, "M", "ѱ"), - (0x471, "V"), - (0x472, "M", "ѳ"), - (0x473, "V"), - (0x474, "M", "ѵ"), - (0x475, "V"), - (0x476, "M", "ѷ"), - (0x477, "V"), - (0x478, "M", "ѹ"), - (0x479, "V"), - (0x47A, "M", "ѻ"), - (0x47B, "V"), - (0x47C, "M", "ѽ"), - (0x47D, "V"), - (0x47E, "M", "ѿ"), - (0x47F, "V"), - (0x480, "M", "ҁ"), - (0x481, "V"), - (0x48A, "M", "ҋ"), - (0x48B, "V"), - (0x48C, "M", "ҍ"), - (0x48D, "V"), - (0x48E, "M", "ҏ"), - (0x48F, "V"), - (0x490, "M", "ґ"), - (0x491, "V"), - (0x492, "M", "ғ"), - (0x493, "V"), - (0x494, "M", "ҕ"), - (0x495, "V"), - (0x496, "M", "җ"), - (0x497, "V"), - (0x498, "M", "ҙ"), - (0x499, "V"), - (0x49A, "M", "қ"), - (0x49B, "V"), - (0x49C, "M", "ҝ"), - (0x49D, "V"), - ] - - -def _seg_8() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x49E, "M", "ҟ"), - (0x49F, "V"), - (0x4A0, "M", "ҡ"), - (0x4A1, "V"), - (0x4A2, "M", "ң"), - (0x4A3, "V"), - (0x4A4, "M", "ҥ"), - (0x4A5, "V"), - (0x4A6, "M", "ҧ"), - (0x4A7, "V"), - (0x4A8, "M", "ҩ"), - (0x4A9, "V"), - (0x4AA, "M", "ҫ"), - (0x4AB, "V"), - (0x4AC, "M", "ҭ"), - (0x4AD, "V"), - (0x4AE, "M", "ү"), - (0x4AF, "V"), - (0x4B0, "M", "ұ"), - (0x4B1, "V"), - (0x4B2, "M", "ҳ"), - (0x4B3, "V"), - (0x4B4, "M", "ҵ"), - (0x4B5, "V"), - (0x4B6, "M", "ҷ"), - (0x4B7, "V"), - (0x4B8, "M", "ҹ"), - (0x4B9, "V"), - (0x4BA, "M", "һ"), - (0x4BB, "V"), - (0x4BC, "M", "ҽ"), - (0x4BD, "V"), - (0x4BE, "M", "ҿ"), - (0x4BF, "V"), - (0x4C0, "M", "ӏ"), - (0x4C1, "M", "ӂ"), - (0x4C2, "V"), - (0x4C3, "M", "ӄ"), - (0x4C4, "V"), - (0x4C5, "M", "ӆ"), - (0x4C6, "V"), - (0x4C7, "M", "ӈ"), - (0x4C8, "V"), - (0x4C9, "M", "ӊ"), - (0x4CA, "V"), - (0x4CB, "M", "ӌ"), - (0x4CC, "V"), - (0x4CD, "M", "ӎ"), - (0x4CE, "V"), - (0x4D0, "M", "ӑ"), - (0x4D1, "V"), - (0x4D2, "M", "ӓ"), - (0x4D3, "V"), - (0x4D4, "M", "ӕ"), - (0x4D5, "V"), - (0x4D6, "M", "ӗ"), - (0x4D7, "V"), - (0x4D8, "M", "ә"), - (0x4D9, "V"), - (0x4DA, "M", "ӛ"), - (0x4DB, "V"), - (0x4DC, "M", "ӝ"), - (0x4DD, "V"), - (0x4DE, "M", "ӟ"), - (0x4DF, "V"), - (0x4E0, "M", "ӡ"), - (0x4E1, "V"), - (0x4E2, "M", "ӣ"), - (0x4E3, "V"), - (0x4E4, "M", "ӥ"), - (0x4E5, "V"), - (0x4E6, "M", "ӧ"), - (0x4E7, "V"), - (0x4E8, "M", "ө"), - (0x4E9, "V"), - (0x4EA, "M", "ӫ"), - (0x4EB, "V"), - (0x4EC, "M", "ӭ"), - (0x4ED, "V"), - (0x4EE, "M", "ӯ"), - (0x4EF, "V"), - (0x4F0, "M", "ӱ"), - (0x4F1, "V"), - (0x4F2, "M", "ӳ"), - (0x4F3, "V"), - (0x4F4, "M", "ӵ"), - (0x4F5, "V"), - (0x4F6, "M", "ӷ"), - (0x4F7, "V"), - (0x4F8, "M", "ӹ"), - (0x4F9, "V"), - (0x4FA, "M", "ӻ"), - (0x4FB, "V"), - (0x4FC, "M", "ӽ"), - (0x4FD, "V"), - (0x4FE, "M", "ӿ"), - (0x4FF, "V"), - (0x500, "M", "ԁ"), - (0x501, "V"), - (0x502, "M", "ԃ"), - ] - - -def _seg_9() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x503, "V"), - (0x504, "M", "ԅ"), - (0x505, "V"), - (0x506, "M", "ԇ"), - (0x507, "V"), - (0x508, "M", "ԉ"), - (0x509, "V"), - (0x50A, "M", "ԋ"), - (0x50B, "V"), - (0x50C, "M", "ԍ"), - (0x50D, "V"), - (0x50E, "M", "ԏ"), - (0x50F, "V"), - (0x510, "M", "ԑ"), - (0x511, "V"), - (0x512, "M", "ԓ"), - (0x513, "V"), - (0x514, "M", "ԕ"), - (0x515, "V"), - (0x516, "M", "ԗ"), - (0x517, "V"), - (0x518, "M", "ԙ"), - (0x519, "V"), - (0x51A, "M", "ԛ"), - (0x51B, "V"), - (0x51C, "M", "ԝ"), - (0x51D, "V"), - (0x51E, "M", "ԟ"), - (0x51F, "V"), - (0x520, "M", "ԡ"), - (0x521, "V"), - (0x522, "M", "ԣ"), - (0x523, "V"), - (0x524, "M", "ԥ"), - (0x525, "V"), - (0x526, "M", "ԧ"), - (0x527, "V"), - (0x528, "M", "ԩ"), - (0x529, "V"), - (0x52A, "M", "ԫ"), - (0x52B, "V"), - (0x52C, "M", "ԭ"), - (0x52D, "V"), - (0x52E, "M", "ԯ"), - (0x52F, "V"), - (0x530, "X"), - (0x531, "M", "ա"), - (0x532, "M", "բ"), - (0x533, "M", "գ"), - (0x534, "M", "դ"), - (0x535, "M", "ե"), - (0x536, "M", "զ"), - (0x537, "M", "է"), - (0x538, "M", "ը"), - (0x539, "M", "թ"), - (0x53A, "M", "ժ"), - (0x53B, "M", "ի"), - (0x53C, "M", "լ"), - (0x53D, "M", "խ"), - (0x53E, "M", "ծ"), - (0x53F, "M", "կ"), - (0x540, "M", "հ"), - (0x541, "M", "ձ"), - (0x542, "M", "ղ"), - (0x543, "M", "ճ"), - (0x544, "M", "մ"), - (0x545, "M", "յ"), - (0x546, "M", "ն"), - (0x547, "M", "շ"), - (0x548, "M", "ո"), - (0x549, "M", "չ"), - (0x54A, "M", "պ"), - (0x54B, "M", "ջ"), - (0x54C, "M", "ռ"), - (0x54D, "M", "ս"), - (0x54E, "M", "վ"), - (0x54F, "M", "տ"), - (0x550, "M", "ր"), - (0x551, "M", "ց"), - (0x552, "M", "ւ"), - (0x553, "M", "փ"), - (0x554, "M", "ք"), - (0x555, "M", "օ"), - (0x556, "M", "ֆ"), - (0x557, "X"), - (0x559, "V"), - (0x587, "M", "եւ"), - (0x588, "V"), - (0x58B, "X"), - (0x58D, "V"), - (0x590, "X"), - (0x591, "V"), - (0x5C8, "X"), - (0x5D0, "V"), - (0x5EB, "X"), - (0x5EF, "V"), - (0x5F5, "X"), - (0x606, "V"), - (0x61C, "X"), - (0x61D, "V"), - ] - - -def _seg_10() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x675, "M", "اٴ"), - (0x676, "M", "وٴ"), - (0x677, "M", "ۇٴ"), - (0x678, "M", "يٴ"), - (0x679, "V"), - (0x6DD, "X"), - (0x6DE, "V"), - (0x70E, "X"), - (0x710, "V"), - (0x74B, "X"), - (0x74D, "V"), - (0x7B2, "X"), - (0x7C0, "V"), - (0x7FB, "X"), - (0x7FD, "V"), - (0x82E, "X"), - (0x830, "V"), - (0x83F, "X"), - (0x840, "V"), - (0x85C, "X"), - (0x85E, "V"), - (0x85F, "X"), - (0x860, "V"), - (0x86B, "X"), - (0x870, "V"), - (0x88F, "X"), - (0x897, "V"), - (0x8E2, "X"), - (0x8E3, "V"), - (0x958, "M", "क़"), - (0x959, "M", "ख़"), - (0x95A, "M", "ग़"), - (0x95B, "M", "ज़"), - (0x95C, "M", "ड़"), - (0x95D, "M", "ढ़"), - (0x95E, "M", "फ़"), - (0x95F, "M", "य़"), - (0x960, "V"), - (0x984, "X"), - (0x985, "V"), - (0x98D, "X"), - (0x98F, "V"), - (0x991, "X"), - (0x993, "V"), - (0x9A9, "X"), - (0x9AA, "V"), - (0x9B1, "X"), - (0x9B2, "V"), - (0x9B3, "X"), - (0x9B6, "V"), - (0x9BA, "X"), - (0x9BC, "V"), - (0x9C5, "X"), - (0x9C7, "V"), - (0x9C9, "X"), - (0x9CB, "V"), - (0x9CF, "X"), - (0x9D7, "V"), - (0x9D8, "X"), - (0x9DC, "M", "ড়"), - (0x9DD, "M", "ঢ়"), - (0x9DE, "X"), - (0x9DF, "M", "য়"), - (0x9E0, "V"), - (0x9E4, "X"), - (0x9E6, "V"), - (0x9FF, "X"), - (0xA01, "V"), - (0xA04, "X"), - (0xA05, "V"), - (0xA0B, "X"), - (0xA0F, "V"), - (0xA11, "X"), - (0xA13, "V"), - (0xA29, "X"), - (0xA2A, "V"), - (0xA31, "X"), - (0xA32, "V"), - (0xA33, "M", "ਲ਼"), - (0xA34, "X"), - (0xA35, "V"), - (0xA36, "M", "ਸ਼"), - (0xA37, "X"), - (0xA38, "V"), - (0xA3A, "X"), - (0xA3C, "V"), - (0xA3D, "X"), - (0xA3E, "V"), - (0xA43, "X"), - (0xA47, "V"), - (0xA49, "X"), - (0xA4B, "V"), - (0xA4E, "X"), - (0xA51, "V"), - (0xA52, "X"), - (0xA59, "M", "ਖ਼"), - (0xA5A, "M", "ਗ਼"), - (0xA5B, "M", "ਜ਼"), - (0xA5C, "V"), - (0xA5D, "X"), - ] - - -def _seg_11() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xA5E, "M", "ਫ਼"), - (0xA5F, "X"), - (0xA66, "V"), - (0xA77, "X"), - (0xA81, "V"), - (0xA84, "X"), - (0xA85, "V"), - (0xA8E, "X"), - (0xA8F, "V"), - (0xA92, "X"), - (0xA93, "V"), - (0xAA9, "X"), - (0xAAA, "V"), - (0xAB1, "X"), - (0xAB2, "V"), - (0xAB4, "X"), - (0xAB5, "V"), - (0xABA, "X"), - (0xABC, "V"), - (0xAC6, "X"), - (0xAC7, "V"), - (0xACA, "X"), - (0xACB, "V"), - (0xACE, "X"), - (0xAD0, "V"), - (0xAD1, "X"), - (0xAE0, "V"), - (0xAE4, "X"), - (0xAE6, "V"), - (0xAF2, "X"), - (0xAF9, "V"), - (0xB00, "X"), - (0xB01, "V"), - (0xB04, "X"), - (0xB05, "V"), - (0xB0D, "X"), - (0xB0F, "V"), - (0xB11, "X"), - (0xB13, "V"), - (0xB29, "X"), - (0xB2A, "V"), - (0xB31, "X"), - (0xB32, "V"), - (0xB34, "X"), - (0xB35, "V"), - (0xB3A, "X"), - (0xB3C, "V"), - (0xB45, "X"), - (0xB47, "V"), - (0xB49, "X"), - (0xB4B, "V"), - (0xB4E, "X"), - (0xB55, "V"), - (0xB58, "X"), - (0xB5C, "M", "ଡ଼"), - (0xB5D, "M", "ଢ଼"), - (0xB5E, "X"), - (0xB5F, "V"), - (0xB64, "X"), - (0xB66, "V"), - (0xB78, "X"), - (0xB82, "V"), - (0xB84, "X"), - (0xB85, "V"), - (0xB8B, "X"), - (0xB8E, "V"), - (0xB91, "X"), - (0xB92, "V"), - (0xB96, "X"), - (0xB99, "V"), - (0xB9B, "X"), - (0xB9C, "V"), - (0xB9D, "X"), - (0xB9E, "V"), - (0xBA0, "X"), - (0xBA3, "V"), - (0xBA5, "X"), - (0xBA8, "V"), - (0xBAB, "X"), - (0xBAE, "V"), - (0xBBA, "X"), - (0xBBE, "V"), - (0xBC3, "X"), - (0xBC6, "V"), - (0xBC9, "X"), - (0xBCA, "V"), - (0xBCE, "X"), - (0xBD0, "V"), - (0xBD1, "X"), - (0xBD7, "V"), - (0xBD8, "X"), - (0xBE6, "V"), - (0xBFB, "X"), - (0xC00, "V"), - (0xC0D, "X"), - (0xC0E, "V"), - (0xC11, "X"), - (0xC12, "V"), - (0xC29, "X"), - (0xC2A, "V"), - ] - - -def _seg_12() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xC3A, "X"), - (0xC3C, "V"), - (0xC45, "X"), - (0xC46, "V"), - (0xC49, "X"), - (0xC4A, "V"), - (0xC4E, "X"), - (0xC55, "V"), - (0xC57, "X"), - (0xC58, "V"), - (0xC5B, "X"), - (0xC5D, "V"), - (0xC5E, "X"), - (0xC60, "V"), - (0xC64, "X"), - (0xC66, "V"), - (0xC70, "X"), - (0xC77, "V"), - (0xC8D, "X"), - (0xC8E, "V"), - (0xC91, "X"), - (0xC92, "V"), - (0xCA9, "X"), - (0xCAA, "V"), - (0xCB4, "X"), - (0xCB5, "V"), - (0xCBA, "X"), - (0xCBC, "V"), - (0xCC5, "X"), - (0xCC6, "V"), - (0xCC9, "X"), - (0xCCA, "V"), - (0xCCE, "X"), - (0xCD5, "V"), - (0xCD7, "X"), - (0xCDD, "V"), - (0xCDF, "X"), - (0xCE0, "V"), - (0xCE4, "X"), - (0xCE6, "V"), - (0xCF0, "X"), - (0xCF1, "V"), - (0xCF4, "X"), - (0xD00, "V"), - (0xD0D, "X"), - (0xD0E, "V"), - (0xD11, "X"), - (0xD12, "V"), - (0xD45, "X"), - (0xD46, "V"), - (0xD49, "X"), - (0xD4A, "V"), - (0xD50, "X"), - (0xD54, "V"), - (0xD64, "X"), - (0xD66, "V"), - (0xD80, "X"), - (0xD81, "V"), - (0xD84, "X"), - (0xD85, "V"), - (0xD97, "X"), - (0xD9A, "V"), - (0xDB2, "X"), - (0xDB3, "V"), - (0xDBC, "X"), - (0xDBD, "V"), - (0xDBE, "X"), - (0xDC0, "V"), - (0xDC7, "X"), - (0xDCA, "V"), - (0xDCB, "X"), - (0xDCF, "V"), - (0xDD5, "X"), - (0xDD6, "V"), - (0xDD7, "X"), - (0xDD8, "V"), - (0xDE0, "X"), - (0xDE6, "V"), - (0xDF0, "X"), - (0xDF2, "V"), - (0xDF5, "X"), - (0xE01, "V"), - (0xE33, "M", "ํา"), - (0xE34, "V"), - (0xE3B, "X"), - (0xE3F, "V"), - (0xE5C, "X"), - (0xE81, "V"), - (0xE83, "X"), - (0xE84, "V"), - (0xE85, "X"), - (0xE86, "V"), - (0xE8B, "X"), - (0xE8C, "V"), - (0xEA4, "X"), - (0xEA5, "V"), - (0xEA6, "X"), - (0xEA7, "V"), - (0xEB3, "M", "ໍາ"), - (0xEB4, "V"), - ] - - -def _seg_13() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xEBE, "X"), - (0xEC0, "V"), - (0xEC5, "X"), - (0xEC6, "V"), - (0xEC7, "X"), - (0xEC8, "V"), - (0xECF, "X"), - (0xED0, "V"), - (0xEDA, "X"), - (0xEDC, "M", "ຫນ"), - (0xEDD, "M", "ຫມ"), - (0xEDE, "V"), - (0xEE0, "X"), - (0xF00, "V"), - (0xF0C, "M", "་"), - (0xF0D, "V"), - (0xF43, "M", "གྷ"), - (0xF44, "V"), - (0xF48, "X"), - (0xF49, "V"), - (0xF4D, "M", "ཌྷ"), - (0xF4E, "V"), - (0xF52, "M", "དྷ"), - (0xF53, "V"), - (0xF57, "M", "བྷ"), - (0xF58, "V"), - (0xF5C, "M", "ཛྷ"), - (0xF5D, "V"), - (0xF69, "M", "ཀྵ"), - (0xF6A, "V"), - (0xF6D, "X"), - (0xF71, "V"), - (0xF73, "M", "ཱི"), - (0xF74, "V"), - (0xF75, "M", "ཱུ"), - (0xF76, "M", "ྲྀ"), - (0xF77, "M", "ྲཱྀ"), - (0xF78, "M", "ླྀ"), - (0xF79, "M", "ླཱྀ"), - (0xF7A, "V"), - (0xF81, "M", "ཱྀ"), - (0xF82, "V"), - (0xF93, "M", "ྒྷ"), - (0xF94, "V"), - (0xF98, "X"), - (0xF99, "V"), - (0xF9D, "M", "ྜྷ"), - (0xF9E, "V"), - (0xFA2, "M", "ྡྷ"), - (0xFA3, "V"), - (0xFA7, "M", "ྦྷ"), - (0xFA8, "V"), - (0xFAC, "M", "ྫྷ"), - (0xFAD, "V"), - (0xFB9, "M", "ྐྵ"), - (0xFBA, "V"), - (0xFBD, "X"), - (0xFBE, "V"), - (0xFCD, "X"), - (0xFCE, "V"), - (0xFDB, "X"), - (0x1000, "V"), - (0x10A0, "M", "ⴀ"), - (0x10A1, "M", "ⴁ"), - (0x10A2, "M", "ⴂ"), - (0x10A3, "M", "ⴃ"), - (0x10A4, "M", "ⴄ"), - (0x10A5, "M", "ⴅ"), - (0x10A6, "M", "ⴆ"), - (0x10A7, "M", "ⴇ"), - (0x10A8, "M", "ⴈ"), - (0x10A9, "M", "ⴉ"), - (0x10AA, "M", "ⴊ"), - (0x10AB, "M", "ⴋ"), - (0x10AC, "M", "ⴌ"), - (0x10AD, "M", "ⴍ"), - (0x10AE, "M", "ⴎ"), - (0x10AF, "M", "ⴏ"), - (0x10B0, "M", "ⴐ"), - (0x10B1, "M", "ⴑ"), - (0x10B2, "M", "ⴒ"), - (0x10B3, "M", "ⴓ"), - (0x10B4, "M", "ⴔ"), - (0x10B5, "M", "ⴕ"), - (0x10B6, "M", "ⴖ"), - (0x10B7, "M", "ⴗ"), - (0x10B8, "M", "ⴘ"), - (0x10B9, "M", "ⴙ"), - (0x10BA, "M", "ⴚ"), - (0x10BB, "M", "ⴛ"), - (0x10BC, "M", "ⴜ"), - (0x10BD, "M", "ⴝ"), - (0x10BE, "M", "ⴞ"), - (0x10BF, "M", "ⴟ"), - (0x10C0, "M", "ⴠ"), - (0x10C1, "M", "ⴡ"), - (0x10C2, "M", "ⴢ"), - (0x10C3, "M", "ⴣ"), - (0x10C4, "M", "ⴤ"), - (0x10C5, "M", "ⴥ"), - ] - - -def _seg_14() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x10C6, "X"), - (0x10C7, "M", "ⴧ"), - (0x10C8, "X"), - (0x10CD, "M", "ⴭ"), - (0x10CE, "X"), - (0x10D0, "V"), - (0x10FC, "M", "ნ"), - (0x10FD, "V"), - (0x115F, "I"), - (0x1161, "V"), - (0x1249, "X"), - (0x124A, "V"), - (0x124E, "X"), - (0x1250, "V"), - (0x1257, "X"), - (0x1258, "V"), - (0x1259, "X"), - (0x125A, "V"), - (0x125E, "X"), - (0x1260, "V"), - (0x1289, "X"), - (0x128A, "V"), - (0x128E, "X"), - (0x1290, "V"), - (0x12B1, "X"), - (0x12B2, "V"), - (0x12B6, "X"), - (0x12B8, "V"), - (0x12BF, "X"), - (0x12C0, "V"), - (0x12C1, "X"), - (0x12C2, "V"), - (0x12C6, "X"), - (0x12C8, "V"), - (0x12D7, "X"), - (0x12D8, "V"), - (0x1311, "X"), - (0x1312, "V"), - (0x1316, "X"), - (0x1318, "V"), - (0x135B, "X"), - (0x135D, "V"), - (0x137D, "X"), - (0x1380, "V"), - (0x139A, "X"), - (0x13A0, "V"), - (0x13F6, "X"), - (0x13F8, "M", "Ᏸ"), - (0x13F9, "M", "Ᏹ"), - (0x13FA, "M", "Ᏺ"), - (0x13FB, "M", "Ᏻ"), - (0x13FC, "M", "Ᏼ"), - (0x13FD, "M", "Ᏽ"), - (0x13FE, "X"), - (0x1400, "V"), - (0x1680, "X"), - (0x1681, "V"), - (0x169D, "X"), - (0x16A0, "V"), - (0x16F9, "X"), - (0x1700, "V"), - (0x1716, "X"), - (0x171F, "V"), - (0x1737, "X"), - (0x1740, "V"), - (0x1754, "X"), - (0x1760, "V"), - (0x176D, "X"), - (0x176E, "V"), - (0x1771, "X"), - (0x1772, "V"), - (0x1774, "X"), - (0x1780, "V"), - (0x17B4, "I"), - (0x17B6, "V"), - (0x17DE, "X"), - (0x17E0, "V"), - (0x17EA, "X"), - (0x17F0, "V"), - (0x17FA, "X"), - (0x1800, "V"), - (0x180B, "I"), - (0x1810, "V"), - (0x181A, "X"), - (0x1820, "V"), - (0x1879, "X"), - (0x1880, "V"), - (0x18AB, "X"), - (0x18B0, "V"), - (0x18F6, "X"), - (0x1900, "V"), - (0x191F, "X"), - (0x1920, "V"), - (0x192C, "X"), - (0x1930, "V"), - (0x193C, "X"), - (0x1940, "V"), - (0x1941, "X"), - (0x1944, "V"), - (0x196E, "X"), - ] - - -def _seg_15() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1970, "V"), - (0x1975, "X"), - (0x1980, "V"), - (0x19AC, "X"), - (0x19B0, "V"), - (0x19CA, "X"), - (0x19D0, "V"), - (0x19DB, "X"), - (0x19DE, "V"), - (0x1A1C, "X"), - (0x1A1E, "V"), - (0x1A5F, "X"), - (0x1A60, "V"), - (0x1A7D, "X"), - (0x1A7F, "V"), - (0x1A8A, "X"), - (0x1A90, "V"), - (0x1A9A, "X"), - (0x1AA0, "V"), - (0x1AAE, "X"), - (0x1AB0, "V"), - (0x1ACF, "X"), - (0x1B00, "V"), - (0x1B4D, "X"), - (0x1B4E, "V"), - (0x1BF4, "X"), - (0x1BFC, "V"), - (0x1C38, "X"), - (0x1C3B, "V"), - (0x1C4A, "X"), - (0x1C4D, "V"), - (0x1C80, "M", "в"), - (0x1C81, "M", "д"), - (0x1C82, "M", "о"), - (0x1C83, "M", "с"), - (0x1C84, "M", "т"), - (0x1C86, "M", "ъ"), - (0x1C87, "M", "ѣ"), - (0x1C88, "M", "ꙋ"), - (0x1C89, "M", "ᲊ"), - (0x1C8A, "V"), - (0x1C8B, "X"), - (0x1C90, "M", "ა"), - (0x1C91, "M", "ბ"), - (0x1C92, "M", "გ"), - (0x1C93, "M", "დ"), - (0x1C94, "M", "ე"), - (0x1C95, "M", "ვ"), - (0x1C96, "M", "ზ"), - (0x1C97, "M", "თ"), - (0x1C98, "M", "ი"), - (0x1C99, "M", "კ"), - (0x1C9A, "M", "ლ"), - (0x1C9B, "M", "მ"), - (0x1C9C, "M", "ნ"), - (0x1C9D, "M", "ო"), - (0x1C9E, "M", "პ"), - (0x1C9F, "M", "ჟ"), - (0x1CA0, "M", "რ"), - (0x1CA1, "M", "ს"), - (0x1CA2, "M", "ტ"), - (0x1CA3, "M", "უ"), - (0x1CA4, "M", "ფ"), - (0x1CA5, "M", "ქ"), - (0x1CA6, "M", "ღ"), - (0x1CA7, "M", "ყ"), - (0x1CA8, "M", "შ"), - (0x1CA9, "M", "ჩ"), - (0x1CAA, "M", "ც"), - (0x1CAB, "M", "ძ"), - (0x1CAC, "M", "წ"), - (0x1CAD, "M", "ჭ"), - (0x1CAE, "M", "ხ"), - (0x1CAF, "M", "ჯ"), - (0x1CB0, "M", "ჰ"), - (0x1CB1, "M", "ჱ"), - (0x1CB2, "M", "ჲ"), - (0x1CB3, "M", "ჳ"), - (0x1CB4, "M", "ჴ"), - (0x1CB5, "M", "ჵ"), - (0x1CB6, "M", "ჶ"), - (0x1CB7, "M", "ჷ"), - (0x1CB8, "M", "ჸ"), - (0x1CB9, "M", "ჹ"), - (0x1CBA, "M", "ჺ"), - (0x1CBB, "X"), - (0x1CBD, "M", "ჽ"), - (0x1CBE, "M", "ჾ"), - (0x1CBF, "M", "ჿ"), - (0x1CC0, "V"), - (0x1CC8, "X"), - (0x1CD0, "V"), - (0x1CFB, "X"), - (0x1D00, "V"), - (0x1D2C, "M", "a"), - (0x1D2D, "M", "æ"), - (0x1D2E, "M", "b"), - (0x1D2F, "V"), - (0x1D30, "M", "d"), - (0x1D31, "M", "e"), - ] - - -def _seg_16() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D32, "M", "ǝ"), - (0x1D33, "M", "g"), - (0x1D34, "M", "h"), - (0x1D35, "M", "i"), - (0x1D36, "M", "j"), - (0x1D37, "M", "k"), - (0x1D38, "M", "l"), - (0x1D39, "M", "m"), - (0x1D3A, "M", "n"), - (0x1D3B, "V"), - (0x1D3C, "M", "o"), - (0x1D3D, "M", "ȣ"), - (0x1D3E, "M", "p"), - (0x1D3F, "M", "r"), - (0x1D40, "M", "t"), - (0x1D41, "M", "u"), - (0x1D42, "M", "w"), - (0x1D43, "M", "a"), - (0x1D44, "M", "ɐ"), - (0x1D45, "M", "ɑ"), - (0x1D46, "M", "ᴂ"), - (0x1D47, "M", "b"), - (0x1D48, "M", "d"), - (0x1D49, "M", "e"), - (0x1D4A, "M", "ə"), - (0x1D4B, "M", "ɛ"), - (0x1D4C, "M", "ɜ"), - (0x1D4D, "M", "g"), - (0x1D4E, "V"), - (0x1D4F, "M", "k"), - (0x1D50, "M", "m"), - (0x1D51, "M", "ŋ"), - (0x1D52, "M", "o"), - (0x1D53, "M", "ɔ"), - (0x1D54, "M", "ᴖ"), - (0x1D55, "M", "ᴗ"), - (0x1D56, "M", "p"), - (0x1D57, "M", "t"), - (0x1D58, "M", "u"), - (0x1D59, "M", "ᴝ"), - (0x1D5A, "M", "ɯ"), - (0x1D5B, "M", "v"), - (0x1D5C, "M", "ᴥ"), - (0x1D5D, "M", "β"), - (0x1D5E, "M", "γ"), - (0x1D5F, "M", "δ"), - (0x1D60, "M", "φ"), - (0x1D61, "M", "χ"), - (0x1D62, "M", "i"), - (0x1D63, "M", "r"), - (0x1D64, "M", "u"), - (0x1D65, "M", "v"), - (0x1D66, "M", "β"), - (0x1D67, "M", "γ"), - (0x1D68, "M", "ρ"), - (0x1D69, "M", "φ"), - (0x1D6A, "M", "χ"), - (0x1D6B, "V"), - (0x1D78, "M", "н"), - (0x1D79, "V"), - (0x1D9B, "M", "ɒ"), - (0x1D9C, "M", "c"), - (0x1D9D, "M", "ɕ"), - (0x1D9E, "M", "ð"), - (0x1D9F, "M", "ɜ"), - (0x1DA0, "M", "f"), - (0x1DA1, "M", "ɟ"), - (0x1DA2, "M", "ɡ"), - (0x1DA3, "M", "ɥ"), - (0x1DA4, "M", "ɨ"), - (0x1DA5, "M", "ɩ"), - (0x1DA6, "M", "ɪ"), - (0x1DA7, "M", "ᵻ"), - (0x1DA8, "M", "ʝ"), - (0x1DA9, "M", "ɭ"), - (0x1DAA, "M", "ᶅ"), - (0x1DAB, "M", "ʟ"), - (0x1DAC, "M", "ɱ"), - (0x1DAD, "M", "ɰ"), - (0x1DAE, "M", "ɲ"), - (0x1DAF, "M", "ɳ"), - (0x1DB0, "M", "ɴ"), - (0x1DB1, "M", "ɵ"), - (0x1DB2, "M", "ɸ"), - (0x1DB3, "M", "ʂ"), - (0x1DB4, "M", "ʃ"), - (0x1DB5, "M", "ƫ"), - (0x1DB6, "M", "ʉ"), - (0x1DB7, "M", "ʊ"), - (0x1DB8, "M", "ᴜ"), - (0x1DB9, "M", "ʋ"), - (0x1DBA, "M", "ʌ"), - (0x1DBB, "M", "z"), - (0x1DBC, "M", "ʐ"), - (0x1DBD, "M", "ʑ"), - (0x1DBE, "M", "ʒ"), - (0x1DBF, "M", "θ"), - (0x1DC0, "V"), - (0x1E00, "M", "ḁ"), - (0x1E01, "V"), - ] - - -def _seg_17() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1E02, "M", "ḃ"), - (0x1E03, "V"), - (0x1E04, "M", "ḅ"), - (0x1E05, "V"), - (0x1E06, "M", "ḇ"), - (0x1E07, "V"), - (0x1E08, "M", "ḉ"), - (0x1E09, "V"), - (0x1E0A, "M", "ḋ"), - (0x1E0B, "V"), - (0x1E0C, "M", "ḍ"), - (0x1E0D, "V"), - (0x1E0E, "M", "ḏ"), - (0x1E0F, "V"), - (0x1E10, "M", "ḑ"), - (0x1E11, "V"), - (0x1E12, "M", "ḓ"), - (0x1E13, "V"), - (0x1E14, "M", "ḕ"), - (0x1E15, "V"), - (0x1E16, "M", "ḗ"), - (0x1E17, "V"), - (0x1E18, "M", "ḙ"), - (0x1E19, "V"), - (0x1E1A, "M", "ḛ"), - (0x1E1B, "V"), - (0x1E1C, "M", "ḝ"), - (0x1E1D, "V"), - (0x1E1E, "M", "ḟ"), - (0x1E1F, "V"), - (0x1E20, "M", "ḡ"), - (0x1E21, "V"), - (0x1E22, "M", "ḣ"), - (0x1E23, "V"), - (0x1E24, "M", "ḥ"), - (0x1E25, "V"), - (0x1E26, "M", "ḧ"), - (0x1E27, "V"), - (0x1E28, "M", "ḩ"), - (0x1E29, "V"), - (0x1E2A, "M", "ḫ"), - (0x1E2B, "V"), - (0x1E2C, "M", "ḭ"), - (0x1E2D, "V"), - (0x1E2E, "M", "ḯ"), - (0x1E2F, "V"), - (0x1E30, "M", "ḱ"), - (0x1E31, "V"), - (0x1E32, "M", "ḳ"), - (0x1E33, "V"), - (0x1E34, "M", "ḵ"), - (0x1E35, "V"), - (0x1E36, "M", "ḷ"), - (0x1E37, "V"), - (0x1E38, "M", "ḹ"), - (0x1E39, "V"), - (0x1E3A, "M", "ḻ"), - (0x1E3B, "V"), - (0x1E3C, "M", "ḽ"), - (0x1E3D, "V"), - (0x1E3E, "M", "ḿ"), - (0x1E3F, "V"), - (0x1E40, "M", "ṁ"), - (0x1E41, "V"), - (0x1E42, "M", "ṃ"), - (0x1E43, "V"), - (0x1E44, "M", "ṅ"), - (0x1E45, "V"), - (0x1E46, "M", "ṇ"), - (0x1E47, "V"), - (0x1E48, "M", "ṉ"), - (0x1E49, "V"), - (0x1E4A, "M", "ṋ"), - (0x1E4B, "V"), - (0x1E4C, "M", "ṍ"), - (0x1E4D, "V"), - (0x1E4E, "M", "ṏ"), - (0x1E4F, "V"), - (0x1E50, "M", "ṑ"), - (0x1E51, "V"), - (0x1E52, "M", "ṓ"), - (0x1E53, "V"), - (0x1E54, "M", "ṕ"), - (0x1E55, "V"), - (0x1E56, "M", "ṗ"), - (0x1E57, "V"), - (0x1E58, "M", "ṙ"), - (0x1E59, "V"), - (0x1E5A, "M", "ṛ"), - (0x1E5B, "V"), - (0x1E5C, "M", "ṝ"), - (0x1E5D, "V"), - (0x1E5E, "M", "ṟ"), - (0x1E5F, "V"), - (0x1E60, "M", "ṡ"), - (0x1E61, "V"), - (0x1E62, "M", "ṣ"), - (0x1E63, "V"), - (0x1E64, "M", "ṥ"), - (0x1E65, "V"), - ] - - -def _seg_18() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1E66, "M", "ṧ"), - (0x1E67, "V"), - (0x1E68, "M", "ṩ"), - (0x1E69, "V"), - (0x1E6A, "M", "ṫ"), - (0x1E6B, "V"), - (0x1E6C, "M", "ṭ"), - (0x1E6D, "V"), - (0x1E6E, "M", "ṯ"), - (0x1E6F, "V"), - (0x1E70, "M", "ṱ"), - (0x1E71, "V"), - (0x1E72, "M", "ṳ"), - (0x1E73, "V"), - (0x1E74, "M", "ṵ"), - (0x1E75, "V"), - (0x1E76, "M", "ṷ"), - (0x1E77, "V"), - (0x1E78, "M", "ṹ"), - (0x1E79, "V"), - (0x1E7A, "M", "ṻ"), - (0x1E7B, "V"), - (0x1E7C, "M", "ṽ"), - (0x1E7D, "V"), - (0x1E7E, "M", "ṿ"), - (0x1E7F, "V"), - (0x1E80, "M", "ẁ"), - (0x1E81, "V"), - (0x1E82, "M", "ẃ"), - (0x1E83, "V"), - (0x1E84, "M", "ẅ"), - (0x1E85, "V"), - (0x1E86, "M", "ẇ"), - (0x1E87, "V"), - (0x1E88, "M", "ẉ"), - (0x1E89, "V"), - (0x1E8A, "M", "ẋ"), - (0x1E8B, "V"), - (0x1E8C, "M", "ẍ"), - (0x1E8D, "V"), - (0x1E8E, "M", "ẏ"), - (0x1E8F, "V"), - (0x1E90, "M", "ẑ"), - (0x1E91, "V"), - (0x1E92, "M", "ẓ"), - (0x1E93, "V"), - (0x1E94, "M", "ẕ"), - (0x1E95, "V"), - (0x1E9A, "M", "aʾ"), - (0x1E9B, "M", "ṡ"), - (0x1E9C, "V"), - (0x1E9E, "M", "ß"), - (0x1E9F, "V"), - (0x1EA0, "M", "ạ"), - (0x1EA1, "V"), - (0x1EA2, "M", "ả"), - (0x1EA3, "V"), - (0x1EA4, "M", "ấ"), - (0x1EA5, "V"), - (0x1EA6, "M", "ầ"), - (0x1EA7, "V"), - (0x1EA8, "M", "ẩ"), - (0x1EA9, "V"), - (0x1EAA, "M", "ẫ"), - (0x1EAB, "V"), - (0x1EAC, "M", "ậ"), - (0x1EAD, "V"), - (0x1EAE, "M", "ắ"), - (0x1EAF, "V"), - (0x1EB0, "M", "ằ"), - (0x1EB1, "V"), - (0x1EB2, "M", "ẳ"), - (0x1EB3, "V"), - (0x1EB4, "M", "ẵ"), - (0x1EB5, "V"), - (0x1EB6, "M", "ặ"), - (0x1EB7, "V"), - (0x1EB8, "M", "ẹ"), - (0x1EB9, "V"), - (0x1EBA, "M", "ẻ"), - (0x1EBB, "V"), - (0x1EBC, "M", "ẽ"), - (0x1EBD, "V"), - (0x1EBE, "M", "ế"), - (0x1EBF, "V"), - (0x1EC0, "M", "ề"), - (0x1EC1, "V"), - (0x1EC2, "M", "ể"), - (0x1EC3, "V"), - (0x1EC4, "M", "ễ"), - (0x1EC5, "V"), - (0x1EC6, "M", "ệ"), - (0x1EC7, "V"), - (0x1EC8, "M", "ỉ"), - (0x1EC9, "V"), - (0x1ECA, "M", "ị"), - (0x1ECB, "V"), - (0x1ECC, "M", "ọ"), - (0x1ECD, "V"), - (0x1ECE, "M", "ỏ"), - ] - - -def _seg_19() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1ECF, "V"), - (0x1ED0, "M", "ố"), - (0x1ED1, "V"), - (0x1ED2, "M", "ồ"), - (0x1ED3, "V"), - (0x1ED4, "M", "ổ"), - (0x1ED5, "V"), - (0x1ED6, "M", "ỗ"), - (0x1ED7, "V"), - (0x1ED8, "M", "ộ"), - (0x1ED9, "V"), - (0x1EDA, "M", "ớ"), - (0x1EDB, "V"), - (0x1EDC, "M", "ờ"), - (0x1EDD, "V"), - (0x1EDE, "M", "ở"), - (0x1EDF, "V"), - (0x1EE0, "M", "ỡ"), - (0x1EE1, "V"), - (0x1EE2, "M", "ợ"), - (0x1EE3, "V"), - (0x1EE4, "M", "ụ"), - (0x1EE5, "V"), - (0x1EE6, "M", "ủ"), - (0x1EE7, "V"), - (0x1EE8, "M", "ứ"), - (0x1EE9, "V"), - (0x1EEA, "M", "ừ"), - (0x1EEB, "V"), - (0x1EEC, "M", "ử"), - (0x1EED, "V"), - (0x1EEE, "M", "ữ"), - (0x1EEF, "V"), - (0x1EF0, "M", "ự"), - (0x1EF1, "V"), - (0x1EF2, "M", "ỳ"), - (0x1EF3, "V"), - (0x1EF4, "M", "ỵ"), - (0x1EF5, "V"), - (0x1EF6, "M", "ỷ"), - (0x1EF7, "V"), - (0x1EF8, "M", "ỹ"), - (0x1EF9, "V"), - (0x1EFA, "M", "ỻ"), - (0x1EFB, "V"), - (0x1EFC, "M", "ỽ"), - (0x1EFD, "V"), - (0x1EFE, "M", "ỿ"), - (0x1EFF, "V"), - (0x1F08, "M", "ἀ"), - (0x1F09, "M", "ἁ"), - (0x1F0A, "M", "ἂ"), - (0x1F0B, "M", "ἃ"), - (0x1F0C, "M", "ἄ"), - (0x1F0D, "M", "ἅ"), - (0x1F0E, "M", "ἆ"), - (0x1F0F, "M", "ἇ"), - (0x1F10, "V"), - (0x1F16, "X"), - (0x1F18, "M", "ἐ"), - (0x1F19, "M", "ἑ"), - (0x1F1A, "M", "ἒ"), - (0x1F1B, "M", "ἓ"), - (0x1F1C, "M", "ἔ"), - (0x1F1D, "M", "ἕ"), - (0x1F1E, "X"), - (0x1F20, "V"), - (0x1F28, "M", "ἠ"), - (0x1F29, "M", "ἡ"), - (0x1F2A, "M", "ἢ"), - (0x1F2B, "M", "ἣ"), - (0x1F2C, "M", "ἤ"), - (0x1F2D, "M", "ἥ"), - (0x1F2E, "M", "ἦ"), - (0x1F2F, "M", "ἧ"), - (0x1F30, "V"), - (0x1F38, "M", "ἰ"), - (0x1F39, "M", "ἱ"), - (0x1F3A, "M", "ἲ"), - (0x1F3B, "M", "ἳ"), - (0x1F3C, "M", "ἴ"), - (0x1F3D, "M", "ἵ"), - (0x1F3E, "M", "ἶ"), - (0x1F3F, "M", "ἷ"), - (0x1F40, "V"), - (0x1F46, "X"), - (0x1F48, "M", "ὀ"), - (0x1F49, "M", "ὁ"), - (0x1F4A, "M", "ὂ"), - (0x1F4B, "M", "ὃ"), - (0x1F4C, "M", "ὄ"), - (0x1F4D, "M", "ὅ"), - (0x1F4E, "X"), - (0x1F50, "V"), - (0x1F58, "X"), - (0x1F59, "M", "ὑ"), - (0x1F5A, "X"), - (0x1F5B, "M", "ὓ"), - (0x1F5C, "X"), - (0x1F5D, "M", "ὕ"), - ] - - -def _seg_20() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1F5E, "X"), - (0x1F5F, "M", "ὗ"), - (0x1F60, "V"), - (0x1F68, "M", "ὠ"), - (0x1F69, "M", "ὡ"), - (0x1F6A, "M", "ὢ"), - (0x1F6B, "M", "ὣ"), - (0x1F6C, "M", "ὤ"), - (0x1F6D, "M", "ὥ"), - (0x1F6E, "M", "ὦ"), - (0x1F6F, "M", "ὧ"), - (0x1F70, "V"), - (0x1F71, "M", "ά"), - (0x1F72, "V"), - (0x1F73, "M", "έ"), - (0x1F74, "V"), - (0x1F75, "M", "ή"), - (0x1F76, "V"), - (0x1F77, "M", "ί"), - (0x1F78, "V"), - (0x1F79, "M", "ό"), - (0x1F7A, "V"), - (0x1F7B, "M", "ύ"), - (0x1F7C, "V"), - (0x1F7D, "M", "ώ"), - (0x1F7E, "X"), - (0x1F80, "M", "ἀι"), - (0x1F81, "M", "ἁι"), - (0x1F82, "M", "ἂι"), - (0x1F83, "M", "ἃι"), - (0x1F84, "M", "ἄι"), - (0x1F85, "M", "ἅι"), - (0x1F86, "M", "ἆι"), - (0x1F87, "M", "ἇι"), - (0x1F88, "M", "ἀι"), - (0x1F89, "M", "ἁι"), - (0x1F8A, "M", "ἂι"), - (0x1F8B, "M", "ἃι"), - (0x1F8C, "M", "ἄι"), - (0x1F8D, "M", "ἅι"), - (0x1F8E, "M", "ἆι"), - (0x1F8F, "M", "ἇι"), - (0x1F90, "M", "ἠι"), - (0x1F91, "M", "ἡι"), - (0x1F92, "M", "ἢι"), - (0x1F93, "M", "ἣι"), - (0x1F94, "M", "ἤι"), - (0x1F95, "M", "ἥι"), - (0x1F96, "M", "ἦι"), - (0x1F97, "M", "ἧι"), - (0x1F98, "M", "ἠι"), - (0x1F99, "M", "ἡι"), - (0x1F9A, "M", "ἢι"), - (0x1F9B, "M", "ἣι"), - (0x1F9C, "M", "ἤι"), - (0x1F9D, "M", "ἥι"), - (0x1F9E, "M", "ἦι"), - (0x1F9F, "M", "ἧι"), - (0x1FA0, "M", "ὠι"), - (0x1FA1, "M", "ὡι"), - (0x1FA2, "M", "ὢι"), - (0x1FA3, "M", "ὣι"), - (0x1FA4, "M", "ὤι"), - (0x1FA5, "M", "ὥι"), - (0x1FA6, "M", "ὦι"), - (0x1FA7, "M", "ὧι"), - (0x1FA8, "M", "ὠι"), - (0x1FA9, "M", "ὡι"), - (0x1FAA, "M", "ὢι"), - (0x1FAB, "M", "ὣι"), - (0x1FAC, "M", "ὤι"), - (0x1FAD, "M", "ὥι"), - (0x1FAE, "M", "ὦι"), - (0x1FAF, "M", "ὧι"), - (0x1FB0, "V"), - (0x1FB2, "M", "ὰι"), - (0x1FB3, "M", "αι"), - (0x1FB4, "M", "άι"), - (0x1FB5, "X"), - (0x1FB6, "V"), - (0x1FB7, "M", "ᾶι"), - (0x1FB8, "M", "ᾰ"), - (0x1FB9, "M", "ᾱ"), - (0x1FBA, "M", "ὰ"), - (0x1FBB, "M", "ά"), - (0x1FBC, "M", "αι"), - (0x1FBD, "M", " ̓"), - (0x1FBE, "M", "ι"), - (0x1FBF, "M", " ̓"), - (0x1FC0, "M", " ͂"), - (0x1FC1, "M", " ̈͂"), - (0x1FC2, "M", "ὴι"), - (0x1FC3, "M", "ηι"), - (0x1FC4, "M", "ήι"), - (0x1FC5, "X"), - (0x1FC6, "V"), - (0x1FC7, "M", "ῆι"), - (0x1FC8, "M", "ὲ"), - (0x1FC9, "M", "έ"), - (0x1FCA, "M", "ὴ"), - ] - - -def _seg_21() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1FCB, "M", "ή"), - (0x1FCC, "M", "ηι"), - (0x1FCD, "M", " ̓̀"), - (0x1FCE, "M", " ̓́"), - (0x1FCF, "M", " ̓͂"), - (0x1FD0, "V"), - (0x1FD3, "M", "ΐ"), - (0x1FD4, "X"), - (0x1FD6, "V"), - (0x1FD8, "M", "ῐ"), - (0x1FD9, "M", "ῑ"), - (0x1FDA, "M", "ὶ"), - (0x1FDB, "M", "ί"), - (0x1FDC, "X"), - (0x1FDD, "M", " ̔̀"), - (0x1FDE, "M", " ̔́"), - (0x1FDF, "M", " ̔͂"), - (0x1FE0, "V"), - (0x1FE3, "M", "ΰ"), - (0x1FE4, "V"), - (0x1FE8, "M", "ῠ"), - (0x1FE9, "M", "ῡ"), - (0x1FEA, "M", "ὺ"), - (0x1FEB, "M", "ύ"), - (0x1FEC, "M", "ῥ"), - (0x1FED, "M", " ̈̀"), - (0x1FEE, "M", " ̈́"), - (0x1FEF, "M", "`"), - (0x1FF0, "X"), - (0x1FF2, "M", "ὼι"), - (0x1FF3, "M", "ωι"), - (0x1FF4, "M", "ώι"), - (0x1FF5, "X"), - (0x1FF6, "V"), - (0x1FF7, "M", "ῶι"), - (0x1FF8, "M", "ὸ"), - (0x1FF9, "M", "ό"), - (0x1FFA, "M", "ὼ"), - (0x1FFB, "M", "ώ"), - (0x1FFC, "M", "ωι"), - (0x1FFD, "M", " ́"), - (0x1FFE, "M", " ̔"), - (0x1FFF, "X"), - (0x2000, "M", " "), - (0x200B, "I"), - (0x200C, "D", ""), - (0x200E, "X"), - (0x2010, "V"), - (0x2011, "M", "‐"), - (0x2012, "V"), - (0x2017, "M", " ̳"), - (0x2018, "V"), - (0x2024, "X"), - (0x2027, "V"), - (0x2028, "X"), - (0x202F, "M", " "), - (0x2030, "V"), - (0x2033, "M", "′′"), - (0x2034, "M", "′′′"), - (0x2035, "V"), - (0x2036, "M", "‵‵"), - (0x2037, "M", "‵‵‵"), - (0x2038, "V"), - (0x203C, "M", "!!"), - (0x203D, "V"), - (0x203E, "M", " ̅"), - (0x203F, "V"), - (0x2047, "M", "??"), - (0x2048, "M", "?!"), - (0x2049, "M", "!?"), - (0x204A, "V"), - (0x2057, "M", "′′′′"), - (0x2058, "V"), - (0x205F, "M", " "), - (0x2060, "I"), - (0x2065, "X"), - (0x206A, "I"), - (0x2070, "M", "0"), - (0x2071, "M", "i"), - (0x2072, "X"), - (0x2074, "M", "4"), - (0x2075, "M", "5"), - (0x2076, "M", "6"), - (0x2077, "M", "7"), - (0x2078, "M", "8"), - (0x2079, "M", "9"), - (0x207A, "M", "+"), - (0x207B, "M", "−"), - (0x207C, "M", "="), - (0x207D, "M", "("), - (0x207E, "M", ")"), - (0x207F, "M", "n"), - (0x2080, "M", "0"), - (0x2081, "M", "1"), - (0x2082, "M", "2"), - (0x2083, "M", "3"), - (0x2084, "M", "4"), - (0x2085, "M", "5"), - (0x2086, "M", "6"), - (0x2087, "M", "7"), - ] - - -def _seg_22() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2088, "M", "8"), - (0x2089, "M", "9"), - (0x208A, "M", "+"), - (0x208B, "M", "−"), - (0x208C, "M", "="), - (0x208D, "M", "("), - (0x208E, "M", ")"), - (0x208F, "X"), - (0x2090, "M", "a"), - (0x2091, "M", "e"), - (0x2092, "M", "o"), - (0x2093, "M", "x"), - (0x2094, "M", "ə"), - (0x2095, "M", "h"), - (0x2096, "M", "k"), - (0x2097, "M", "l"), - (0x2098, "M", "m"), - (0x2099, "M", "n"), - (0x209A, "M", "p"), - (0x209B, "M", "s"), - (0x209C, "M", "t"), - (0x209D, "X"), - (0x20A0, "V"), - (0x20A8, "M", "rs"), - (0x20A9, "V"), - (0x20C1, "X"), - (0x20D0, "V"), - (0x20F1, "X"), - (0x2100, "M", "a/c"), - (0x2101, "M", "a/s"), - (0x2102, "M", "c"), - (0x2103, "M", "°c"), - (0x2104, "V"), - (0x2105, "M", "c/o"), - (0x2106, "M", "c/u"), - (0x2107, "M", "ɛ"), - (0x2108, "V"), - (0x2109, "M", "°f"), - (0x210A, "M", "g"), - (0x210B, "M", "h"), - (0x210F, "M", "ħ"), - (0x2110, "M", "i"), - (0x2112, "M", "l"), - (0x2114, "V"), - (0x2115, "M", "n"), - (0x2116, "M", "no"), - (0x2117, "V"), - (0x2119, "M", "p"), - (0x211A, "M", "q"), - (0x211B, "M", "r"), - (0x211E, "V"), - (0x2120, "M", "sm"), - (0x2121, "M", "tel"), - (0x2122, "M", "tm"), - (0x2123, "V"), - (0x2124, "M", "z"), - (0x2125, "V"), - (0x2126, "M", "ω"), - (0x2127, "V"), - (0x2128, "M", "z"), - (0x2129, "V"), - (0x212A, "M", "k"), - (0x212B, "M", "å"), - (0x212C, "M", "b"), - (0x212D, "M", "c"), - (0x212E, "V"), - (0x212F, "M", "e"), - (0x2131, "M", "f"), - (0x2132, "M", "ⅎ"), - (0x2133, "M", "m"), - (0x2134, "M", "o"), - (0x2135, "M", "א"), - (0x2136, "M", "ב"), - (0x2137, "M", "ג"), - (0x2138, "M", "ד"), - (0x2139, "M", "i"), - (0x213A, "V"), - (0x213B, "M", "fax"), - (0x213C, "M", "π"), - (0x213D, "M", "γ"), - (0x213F, "M", "π"), - (0x2140, "M", "∑"), - (0x2141, "V"), - (0x2145, "M", "d"), - (0x2147, "M", "e"), - (0x2148, "M", "i"), - (0x2149, "M", "j"), - (0x214A, "V"), - (0x2150, "M", "1⁄7"), - (0x2151, "M", "1⁄9"), - (0x2152, "M", "1⁄10"), - (0x2153, "M", "1⁄3"), - (0x2154, "M", "2⁄3"), - (0x2155, "M", "1⁄5"), - (0x2156, "M", "2⁄5"), - (0x2157, "M", "3⁄5"), - (0x2158, "M", "4⁄5"), - (0x2159, "M", "1⁄6"), - (0x215A, "M", "5⁄6"), - (0x215B, "M", "1⁄8"), - ] - - -def _seg_23() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x215C, "M", "3⁄8"), - (0x215D, "M", "5⁄8"), - (0x215E, "M", "7⁄8"), - (0x215F, "M", "1⁄"), - (0x2160, "M", "i"), - (0x2161, "M", "ii"), - (0x2162, "M", "iii"), - (0x2163, "M", "iv"), - (0x2164, "M", "v"), - (0x2165, "M", "vi"), - (0x2166, "M", "vii"), - (0x2167, "M", "viii"), - (0x2168, "M", "ix"), - (0x2169, "M", "x"), - (0x216A, "M", "xi"), - (0x216B, "M", "xii"), - (0x216C, "M", "l"), - (0x216D, "M", "c"), - (0x216E, "M", "d"), - (0x216F, "M", "m"), - (0x2170, "M", "i"), - (0x2171, "M", "ii"), - (0x2172, "M", "iii"), - (0x2173, "M", "iv"), - (0x2174, "M", "v"), - (0x2175, "M", "vi"), - (0x2176, "M", "vii"), - (0x2177, "M", "viii"), - (0x2178, "M", "ix"), - (0x2179, "M", "x"), - (0x217A, "M", "xi"), - (0x217B, "M", "xii"), - (0x217C, "M", "l"), - (0x217D, "M", "c"), - (0x217E, "M", "d"), - (0x217F, "M", "m"), - (0x2180, "V"), - (0x2183, "M", "ↄ"), - (0x2184, "V"), - (0x2189, "M", "0⁄3"), - (0x218A, "V"), - (0x218C, "X"), - (0x2190, "V"), - (0x222C, "M", "∫∫"), - (0x222D, "M", "∫∫∫"), - (0x222E, "V"), - (0x222F, "M", "∮∮"), - (0x2230, "M", "∮∮∮"), - (0x2231, "V"), - (0x2329, "M", "〈"), - (0x232A, "M", "〉"), - (0x232B, "V"), - (0x242A, "X"), - (0x2440, "V"), - (0x244B, "X"), - (0x2460, "M", "1"), - (0x2461, "M", "2"), - (0x2462, "M", "3"), - (0x2463, "M", "4"), - (0x2464, "M", "5"), - (0x2465, "M", "6"), - (0x2466, "M", "7"), - (0x2467, "M", "8"), - (0x2468, "M", "9"), - (0x2469, "M", "10"), - (0x246A, "M", "11"), - (0x246B, "M", "12"), - (0x246C, "M", "13"), - (0x246D, "M", "14"), - (0x246E, "M", "15"), - (0x246F, "M", "16"), - (0x2470, "M", "17"), - (0x2471, "M", "18"), - (0x2472, "M", "19"), - (0x2473, "M", "20"), - (0x2474, "M", "(1)"), - (0x2475, "M", "(2)"), - (0x2476, "M", "(3)"), - (0x2477, "M", "(4)"), - (0x2478, "M", "(5)"), - (0x2479, "M", "(6)"), - (0x247A, "M", "(7)"), - (0x247B, "M", "(8)"), - (0x247C, "M", "(9)"), - (0x247D, "M", "(10)"), - (0x247E, "M", "(11)"), - (0x247F, "M", "(12)"), - (0x2480, "M", "(13)"), - (0x2481, "M", "(14)"), - (0x2482, "M", "(15)"), - (0x2483, "M", "(16)"), - (0x2484, "M", "(17)"), - (0x2485, "M", "(18)"), - (0x2486, "M", "(19)"), - (0x2487, "M", "(20)"), - (0x2488, "X"), - (0x249C, "M", "(a)"), - (0x249D, "M", "(b)"), - (0x249E, "M", "(c)"), - (0x249F, "M", "(d)"), - ] - - -def _seg_24() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x24A0, "M", "(e)"), - (0x24A1, "M", "(f)"), - (0x24A2, "M", "(g)"), - (0x24A3, "M", "(h)"), - (0x24A4, "M", "(i)"), - (0x24A5, "M", "(j)"), - (0x24A6, "M", "(k)"), - (0x24A7, "M", "(l)"), - (0x24A8, "M", "(m)"), - (0x24A9, "M", "(n)"), - (0x24AA, "M", "(o)"), - (0x24AB, "M", "(p)"), - (0x24AC, "M", "(q)"), - (0x24AD, "M", "(r)"), - (0x24AE, "M", "(s)"), - (0x24AF, "M", "(t)"), - (0x24B0, "M", "(u)"), - (0x24B1, "M", "(v)"), - (0x24B2, "M", "(w)"), - (0x24B3, "M", "(x)"), - (0x24B4, "M", "(y)"), - (0x24B5, "M", "(z)"), - (0x24B6, "M", "a"), - (0x24B7, "M", "b"), - (0x24B8, "M", "c"), - (0x24B9, "M", "d"), - (0x24BA, "M", "e"), - (0x24BB, "M", "f"), - (0x24BC, "M", "g"), - (0x24BD, "M", "h"), - (0x24BE, "M", "i"), - (0x24BF, "M", "j"), - (0x24C0, "M", "k"), - (0x24C1, "M", "l"), - (0x24C2, "M", "m"), - (0x24C3, "M", "n"), - (0x24C4, "M", "o"), - (0x24C5, "M", "p"), - (0x24C6, "M", "q"), - (0x24C7, "M", "r"), - (0x24C8, "M", "s"), - (0x24C9, "M", "t"), - (0x24CA, "M", "u"), - (0x24CB, "M", "v"), - (0x24CC, "M", "w"), - (0x24CD, "M", "x"), - (0x24CE, "M", "y"), - (0x24CF, "M", "z"), - (0x24D0, "M", "a"), - (0x24D1, "M", "b"), - (0x24D2, "M", "c"), - (0x24D3, "M", "d"), - (0x24D4, "M", "e"), - (0x24D5, "M", "f"), - (0x24D6, "M", "g"), - (0x24D7, "M", "h"), - (0x24D8, "M", "i"), - (0x24D9, "M", "j"), - (0x24DA, "M", "k"), - (0x24DB, "M", "l"), - (0x24DC, "M", "m"), - (0x24DD, "M", "n"), - (0x24DE, "M", "o"), - (0x24DF, "M", "p"), - (0x24E0, "M", "q"), - (0x24E1, "M", "r"), - (0x24E2, "M", "s"), - (0x24E3, "M", "t"), - (0x24E4, "M", "u"), - (0x24E5, "M", "v"), - (0x24E6, "M", "w"), - (0x24E7, "M", "x"), - (0x24E8, "M", "y"), - (0x24E9, "M", "z"), - (0x24EA, "M", "0"), - (0x24EB, "V"), - (0x2A0C, "M", "∫∫∫∫"), - (0x2A0D, "V"), - (0x2A74, "M", "::="), - (0x2A75, "M", "=="), - (0x2A76, "M", "==="), - (0x2A77, "V"), - (0x2ADC, "M", "⫝̸"), - (0x2ADD, "V"), - (0x2B74, "X"), - (0x2B76, "V"), - (0x2B96, "X"), - (0x2B97, "V"), - (0x2C00, "M", "ⰰ"), - (0x2C01, "M", "ⰱ"), - (0x2C02, "M", "ⰲ"), - (0x2C03, "M", "ⰳ"), - (0x2C04, "M", "ⰴ"), - (0x2C05, "M", "ⰵ"), - (0x2C06, "M", "ⰶ"), - (0x2C07, "M", "ⰷ"), - (0x2C08, "M", "ⰸ"), - (0x2C09, "M", "ⰹ"), - (0x2C0A, "M", "ⰺ"), - (0x2C0B, "M", "ⰻ"), - ] - - -def _seg_25() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2C0C, "M", "ⰼ"), - (0x2C0D, "M", "ⰽ"), - (0x2C0E, "M", "ⰾ"), - (0x2C0F, "M", "ⰿ"), - (0x2C10, "M", "ⱀ"), - (0x2C11, "M", "ⱁ"), - (0x2C12, "M", "ⱂ"), - (0x2C13, "M", "ⱃ"), - (0x2C14, "M", "ⱄ"), - (0x2C15, "M", "ⱅ"), - (0x2C16, "M", "ⱆ"), - (0x2C17, "M", "ⱇ"), - (0x2C18, "M", "ⱈ"), - (0x2C19, "M", "ⱉ"), - (0x2C1A, "M", "ⱊ"), - (0x2C1B, "M", "ⱋ"), - (0x2C1C, "M", "ⱌ"), - (0x2C1D, "M", "ⱍ"), - (0x2C1E, "M", "ⱎ"), - (0x2C1F, "M", "ⱏ"), - (0x2C20, "M", "ⱐ"), - (0x2C21, "M", "ⱑ"), - (0x2C22, "M", "ⱒ"), - (0x2C23, "M", "ⱓ"), - (0x2C24, "M", "ⱔ"), - (0x2C25, "M", "ⱕ"), - (0x2C26, "M", "ⱖ"), - (0x2C27, "M", "ⱗ"), - (0x2C28, "M", "ⱘ"), - (0x2C29, "M", "ⱙ"), - (0x2C2A, "M", "ⱚ"), - (0x2C2B, "M", "ⱛ"), - (0x2C2C, "M", "ⱜ"), - (0x2C2D, "M", "ⱝ"), - (0x2C2E, "M", "ⱞ"), - (0x2C2F, "M", "ⱟ"), - (0x2C30, "V"), - (0x2C60, "M", "ⱡ"), - (0x2C61, "V"), - (0x2C62, "M", "ɫ"), - (0x2C63, "M", "ᵽ"), - (0x2C64, "M", "ɽ"), - (0x2C65, "V"), - (0x2C67, "M", "ⱨ"), - (0x2C68, "V"), - (0x2C69, "M", "ⱪ"), - (0x2C6A, "V"), - (0x2C6B, "M", "ⱬ"), - (0x2C6C, "V"), - (0x2C6D, "M", "ɑ"), - (0x2C6E, "M", "ɱ"), - (0x2C6F, "M", "ɐ"), - (0x2C70, "M", "ɒ"), - (0x2C71, "V"), - (0x2C72, "M", "ⱳ"), - (0x2C73, "V"), - (0x2C75, "M", "ⱶ"), - (0x2C76, "V"), - (0x2C7C, "M", "j"), - (0x2C7D, "M", "v"), - (0x2C7E, "M", "ȿ"), - (0x2C7F, "M", "ɀ"), - (0x2C80, "M", "ⲁ"), - (0x2C81, "V"), - (0x2C82, "M", "ⲃ"), - (0x2C83, "V"), - (0x2C84, "M", "ⲅ"), - (0x2C85, "V"), - (0x2C86, "M", "ⲇ"), - (0x2C87, "V"), - (0x2C88, "M", "ⲉ"), - (0x2C89, "V"), - (0x2C8A, "M", "ⲋ"), - (0x2C8B, "V"), - (0x2C8C, "M", "ⲍ"), - (0x2C8D, "V"), - (0x2C8E, "M", "ⲏ"), - (0x2C8F, "V"), - (0x2C90, "M", "ⲑ"), - (0x2C91, "V"), - (0x2C92, "M", "ⲓ"), - (0x2C93, "V"), - (0x2C94, "M", "ⲕ"), - (0x2C95, "V"), - (0x2C96, "M", "ⲗ"), - (0x2C97, "V"), - (0x2C98, "M", "ⲙ"), - (0x2C99, "V"), - (0x2C9A, "M", "ⲛ"), - (0x2C9B, "V"), - (0x2C9C, "M", "ⲝ"), - (0x2C9D, "V"), - (0x2C9E, "M", "ⲟ"), - (0x2C9F, "V"), - (0x2CA0, "M", "ⲡ"), - (0x2CA1, "V"), - (0x2CA2, "M", "ⲣ"), - (0x2CA3, "V"), - (0x2CA4, "M", "ⲥ"), - (0x2CA5, "V"), - ] - - -def _seg_26() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2CA6, "M", "ⲧ"), - (0x2CA7, "V"), - (0x2CA8, "M", "ⲩ"), - (0x2CA9, "V"), - (0x2CAA, "M", "ⲫ"), - (0x2CAB, "V"), - (0x2CAC, "M", "ⲭ"), - (0x2CAD, "V"), - (0x2CAE, "M", "ⲯ"), - (0x2CAF, "V"), - (0x2CB0, "M", "ⲱ"), - (0x2CB1, "V"), - (0x2CB2, "M", "ⲳ"), - (0x2CB3, "V"), - (0x2CB4, "M", "ⲵ"), - (0x2CB5, "V"), - (0x2CB6, "M", "ⲷ"), - (0x2CB7, "V"), - (0x2CB8, "M", "ⲹ"), - (0x2CB9, "V"), - (0x2CBA, "M", "ⲻ"), - (0x2CBB, "V"), - (0x2CBC, "M", "ⲽ"), - (0x2CBD, "V"), - (0x2CBE, "M", "ⲿ"), - (0x2CBF, "V"), - (0x2CC0, "M", "ⳁ"), - (0x2CC1, "V"), - (0x2CC2, "M", "ⳃ"), - (0x2CC3, "V"), - (0x2CC4, "M", "ⳅ"), - (0x2CC5, "V"), - (0x2CC6, "M", "ⳇ"), - (0x2CC7, "V"), - (0x2CC8, "M", "ⳉ"), - (0x2CC9, "V"), - (0x2CCA, "M", "ⳋ"), - (0x2CCB, "V"), - (0x2CCC, "M", "ⳍ"), - (0x2CCD, "V"), - (0x2CCE, "M", "ⳏ"), - (0x2CCF, "V"), - (0x2CD0, "M", "ⳑ"), - (0x2CD1, "V"), - (0x2CD2, "M", "ⳓ"), - (0x2CD3, "V"), - (0x2CD4, "M", "ⳕ"), - (0x2CD5, "V"), - (0x2CD6, "M", "ⳗ"), - (0x2CD7, "V"), - (0x2CD8, "M", "ⳙ"), - (0x2CD9, "V"), - (0x2CDA, "M", "ⳛ"), - (0x2CDB, "V"), - (0x2CDC, "M", "ⳝ"), - (0x2CDD, "V"), - (0x2CDE, "M", "ⳟ"), - (0x2CDF, "V"), - (0x2CE0, "M", "ⳡ"), - (0x2CE1, "V"), - (0x2CE2, "M", "ⳣ"), - (0x2CE3, "V"), - (0x2CEB, "M", "ⳬ"), - (0x2CEC, "V"), - (0x2CED, "M", "ⳮ"), - (0x2CEE, "V"), - (0x2CF2, "M", "ⳳ"), - (0x2CF3, "V"), - (0x2CF4, "X"), - (0x2CF9, "V"), - (0x2D26, "X"), - (0x2D27, "V"), - (0x2D28, "X"), - (0x2D2D, "V"), - (0x2D2E, "X"), - (0x2D30, "V"), - (0x2D68, "X"), - (0x2D6F, "M", "ⵡ"), - (0x2D70, "V"), - (0x2D71, "X"), - (0x2D7F, "V"), - (0x2D97, "X"), - (0x2DA0, "V"), - (0x2DA7, "X"), - (0x2DA8, "V"), - (0x2DAF, "X"), - (0x2DB0, "V"), - (0x2DB7, "X"), - (0x2DB8, "V"), - (0x2DBF, "X"), - (0x2DC0, "V"), - (0x2DC7, "X"), - (0x2DC8, "V"), - (0x2DCF, "X"), - (0x2DD0, "V"), - (0x2DD7, "X"), - (0x2DD8, "V"), - (0x2DDF, "X"), - (0x2DE0, "V"), - (0x2E5E, "X"), - ] - - -def _seg_27() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2E80, "V"), - (0x2E9A, "X"), - (0x2E9B, "V"), - (0x2E9F, "M", "母"), - (0x2EA0, "V"), - (0x2EF3, "M", "龟"), - (0x2EF4, "X"), - (0x2F00, "M", "一"), - (0x2F01, "M", "丨"), - (0x2F02, "M", "丶"), - (0x2F03, "M", "丿"), - (0x2F04, "M", "乙"), - (0x2F05, "M", "亅"), - (0x2F06, "M", "二"), - (0x2F07, "M", "亠"), - (0x2F08, "M", "人"), - (0x2F09, "M", "儿"), - (0x2F0A, "M", "入"), - (0x2F0B, "M", "八"), - (0x2F0C, "M", "冂"), - (0x2F0D, "M", "冖"), - (0x2F0E, "M", "冫"), - (0x2F0F, "M", "几"), - (0x2F10, "M", "凵"), - (0x2F11, "M", "刀"), - (0x2F12, "M", "力"), - (0x2F13, "M", "勹"), - (0x2F14, "M", "匕"), - (0x2F15, "M", "匚"), - (0x2F16, "M", "匸"), - (0x2F17, "M", "十"), - (0x2F18, "M", "卜"), - (0x2F19, "M", "卩"), - (0x2F1A, "M", "厂"), - (0x2F1B, "M", "厶"), - (0x2F1C, "M", "又"), - (0x2F1D, "M", "口"), - (0x2F1E, "M", "囗"), - (0x2F1F, "M", "土"), - (0x2F20, "M", "士"), - (0x2F21, "M", "夂"), - (0x2F22, "M", "夊"), - (0x2F23, "M", "夕"), - (0x2F24, "M", "大"), - (0x2F25, "M", "女"), - (0x2F26, "M", "子"), - (0x2F27, "M", "宀"), - (0x2F28, "M", "寸"), - (0x2F29, "M", "小"), - (0x2F2A, "M", "尢"), - (0x2F2B, "M", "尸"), - (0x2F2C, "M", "屮"), - (0x2F2D, "M", "山"), - (0x2F2E, "M", "巛"), - (0x2F2F, "M", "工"), - (0x2F30, "M", "己"), - (0x2F31, "M", "巾"), - (0x2F32, "M", "干"), - (0x2F33, "M", "幺"), - (0x2F34, "M", "广"), - (0x2F35, "M", "廴"), - (0x2F36, "M", "廾"), - (0x2F37, "M", "弋"), - (0x2F38, "M", "弓"), - (0x2F39, "M", "彐"), - (0x2F3A, "M", "彡"), - (0x2F3B, "M", "彳"), - (0x2F3C, "M", "心"), - (0x2F3D, "M", "戈"), - (0x2F3E, "M", "戶"), - (0x2F3F, "M", "手"), - (0x2F40, "M", "支"), - (0x2F41, "M", "攴"), - (0x2F42, "M", "文"), - (0x2F43, "M", "斗"), - (0x2F44, "M", "斤"), - (0x2F45, "M", "方"), - (0x2F46, "M", "无"), - (0x2F47, "M", "日"), - (0x2F48, "M", "曰"), - (0x2F49, "M", "月"), - (0x2F4A, "M", "木"), - (0x2F4B, "M", "欠"), - (0x2F4C, "M", "止"), - (0x2F4D, "M", "歹"), - (0x2F4E, "M", "殳"), - (0x2F4F, "M", "毋"), - (0x2F50, "M", "比"), - (0x2F51, "M", "毛"), - (0x2F52, "M", "氏"), - (0x2F53, "M", "气"), - (0x2F54, "M", "水"), - (0x2F55, "M", "火"), - (0x2F56, "M", "爪"), - (0x2F57, "M", "父"), - (0x2F58, "M", "爻"), - (0x2F59, "M", "爿"), - (0x2F5A, "M", "片"), - (0x2F5B, "M", "牙"), - (0x2F5C, "M", "牛"), - ] - - -def _seg_28() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F5D, "M", "犬"), - (0x2F5E, "M", "玄"), - (0x2F5F, "M", "玉"), - (0x2F60, "M", "瓜"), - (0x2F61, "M", "瓦"), - (0x2F62, "M", "甘"), - (0x2F63, "M", "生"), - (0x2F64, "M", "用"), - (0x2F65, "M", "田"), - (0x2F66, "M", "疋"), - (0x2F67, "M", "疒"), - (0x2F68, "M", "癶"), - (0x2F69, "M", "白"), - (0x2F6A, "M", "皮"), - (0x2F6B, "M", "皿"), - (0x2F6C, "M", "目"), - (0x2F6D, "M", "矛"), - (0x2F6E, "M", "矢"), - (0x2F6F, "M", "石"), - (0x2F70, "M", "示"), - (0x2F71, "M", "禸"), - (0x2F72, "M", "禾"), - (0x2F73, "M", "穴"), - (0x2F74, "M", "立"), - (0x2F75, "M", "竹"), - (0x2F76, "M", "米"), - (0x2F77, "M", "糸"), - (0x2F78, "M", "缶"), - (0x2F79, "M", "网"), - (0x2F7A, "M", "羊"), - (0x2F7B, "M", "羽"), - (0x2F7C, "M", "老"), - (0x2F7D, "M", "而"), - (0x2F7E, "M", "耒"), - (0x2F7F, "M", "耳"), - (0x2F80, "M", "聿"), - (0x2F81, "M", "肉"), - (0x2F82, "M", "臣"), - (0x2F83, "M", "自"), - (0x2F84, "M", "至"), - (0x2F85, "M", "臼"), - (0x2F86, "M", "舌"), - (0x2F87, "M", "舛"), - (0x2F88, "M", "舟"), - (0x2F89, "M", "艮"), - (0x2F8A, "M", "色"), - (0x2F8B, "M", "艸"), - (0x2F8C, "M", "虍"), - (0x2F8D, "M", "虫"), - (0x2F8E, "M", "血"), - (0x2F8F, "M", "行"), - (0x2F90, "M", "衣"), - (0x2F91, "M", "襾"), - (0x2F92, "M", "見"), - (0x2F93, "M", "角"), - (0x2F94, "M", "言"), - (0x2F95, "M", "谷"), - (0x2F96, "M", "豆"), - (0x2F97, "M", "豕"), - (0x2F98, "M", "豸"), - (0x2F99, "M", "貝"), - (0x2F9A, "M", "赤"), - (0x2F9B, "M", "走"), - (0x2F9C, "M", "足"), - (0x2F9D, "M", "身"), - (0x2F9E, "M", "車"), - (0x2F9F, "M", "辛"), - (0x2FA0, "M", "辰"), - (0x2FA1, "M", "辵"), - (0x2FA2, "M", "邑"), - (0x2FA3, "M", "酉"), - (0x2FA4, "M", "釆"), - (0x2FA5, "M", "里"), - (0x2FA6, "M", "金"), - (0x2FA7, "M", "長"), - (0x2FA8, "M", "門"), - (0x2FA9, "M", "阜"), - (0x2FAA, "M", "隶"), - (0x2FAB, "M", "隹"), - (0x2FAC, "M", "雨"), - (0x2FAD, "M", "靑"), - (0x2FAE, "M", "非"), - (0x2FAF, "M", "面"), - (0x2FB0, "M", "革"), - (0x2FB1, "M", "韋"), - (0x2FB2, "M", "韭"), - (0x2FB3, "M", "音"), - (0x2FB4, "M", "頁"), - (0x2FB5, "M", "風"), - (0x2FB6, "M", "飛"), - (0x2FB7, "M", "食"), - (0x2FB8, "M", "首"), - (0x2FB9, "M", "香"), - (0x2FBA, "M", "馬"), - (0x2FBB, "M", "骨"), - (0x2FBC, "M", "高"), - (0x2FBD, "M", "髟"), - (0x2FBE, "M", "鬥"), - (0x2FBF, "M", "鬯"), - (0x2FC0, "M", "鬲"), - ] - - -def _seg_29() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2FC1, "M", "鬼"), - (0x2FC2, "M", "魚"), - (0x2FC3, "M", "鳥"), - (0x2FC4, "M", "鹵"), - (0x2FC5, "M", "鹿"), - (0x2FC6, "M", "麥"), - (0x2FC7, "M", "麻"), - (0x2FC8, "M", "黃"), - (0x2FC9, "M", "黍"), - (0x2FCA, "M", "黑"), - (0x2FCB, "M", "黹"), - (0x2FCC, "M", "黽"), - (0x2FCD, "M", "鼎"), - (0x2FCE, "M", "鼓"), - (0x2FCF, "M", "鼠"), - (0x2FD0, "M", "鼻"), - (0x2FD1, "M", "齊"), - (0x2FD2, "M", "齒"), - (0x2FD3, "M", "龍"), - (0x2FD4, "M", "龜"), - (0x2FD5, "M", "龠"), - (0x2FD6, "X"), - (0x3000, "M", " "), - (0x3001, "V"), - (0x3002, "M", "."), - (0x3003, "V"), - (0x3036, "M", "〒"), - (0x3037, "V"), - (0x3038, "M", "十"), - (0x3039, "M", "卄"), - (0x303A, "M", "卅"), - (0x303B, "V"), - (0x3040, "X"), - (0x3041, "V"), - (0x3097, "X"), - (0x3099, "V"), - (0x309B, "M", " ゙"), - (0x309C, "M", " ゚"), - (0x309D, "V"), - (0x309F, "M", "より"), - (0x30A0, "V"), - (0x30FF, "M", "コト"), - (0x3100, "X"), - (0x3105, "V"), - (0x3130, "X"), - (0x3131, "M", "ᄀ"), - (0x3132, "M", "ᄁ"), - (0x3133, "M", "ᆪ"), - (0x3134, "M", "ᄂ"), - (0x3135, "M", "ᆬ"), - (0x3136, "M", "ᆭ"), - (0x3137, "M", "ᄃ"), - (0x3138, "M", "ᄄ"), - (0x3139, "M", "ᄅ"), - (0x313A, "M", "ᆰ"), - (0x313B, "M", "ᆱ"), - (0x313C, "M", "ᆲ"), - (0x313D, "M", "ᆳ"), - (0x313E, "M", "ᆴ"), - (0x313F, "M", "ᆵ"), - (0x3140, "M", "ᄚ"), - (0x3141, "M", "ᄆ"), - (0x3142, "M", "ᄇ"), - (0x3143, "M", "ᄈ"), - (0x3144, "M", "ᄡ"), - (0x3145, "M", "ᄉ"), - (0x3146, "M", "ᄊ"), - (0x3147, "M", "ᄋ"), - (0x3148, "M", "ᄌ"), - (0x3149, "M", "ᄍ"), - (0x314A, "M", "ᄎ"), - (0x314B, "M", "ᄏ"), - (0x314C, "M", "ᄐ"), - (0x314D, "M", "ᄑ"), - (0x314E, "M", "ᄒ"), - (0x314F, "M", "ᅡ"), - (0x3150, "M", "ᅢ"), - (0x3151, "M", "ᅣ"), - (0x3152, "M", "ᅤ"), - (0x3153, "M", "ᅥ"), - (0x3154, "M", "ᅦ"), - (0x3155, "M", "ᅧ"), - (0x3156, "M", "ᅨ"), - (0x3157, "M", "ᅩ"), - (0x3158, "M", "ᅪ"), - (0x3159, "M", "ᅫ"), - (0x315A, "M", "ᅬ"), - (0x315B, "M", "ᅭ"), - (0x315C, "M", "ᅮ"), - (0x315D, "M", "ᅯ"), - (0x315E, "M", "ᅰ"), - (0x315F, "M", "ᅱ"), - (0x3160, "M", "ᅲ"), - (0x3161, "M", "ᅳ"), - (0x3162, "M", "ᅴ"), - (0x3163, "M", "ᅵ"), - (0x3164, "I"), - (0x3165, "M", "ᄔ"), - (0x3166, "M", "ᄕ"), - (0x3167, "M", "ᇇ"), - ] - - -def _seg_30() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x3168, "M", "ᇈ"), - (0x3169, "M", "ᇌ"), - (0x316A, "M", "ᇎ"), - (0x316B, "M", "ᇓ"), - (0x316C, "M", "ᇗ"), - (0x316D, "M", "ᇙ"), - (0x316E, "M", "ᄜ"), - (0x316F, "M", "ᇝ"), - (0x3170, "M", "ᇟ"), - (0x3171, "M", "ᄝ"), - (0x3172, "M", "ᄞ"), - (0x3173, "M", "ᄠ"), - (0x3174, "M", "ᄢ"), - (0x3175, "M", "ᄣ"), - (0x3176, "M", "ᄧ"), - (0x3177, "M", "ᄩ"), - (0x3178, "M", "ᄫ"), - (0x3179, "M", "ᄬ"), - (0x317A, "M", "ᄭ"), - (0x317B, "M", "ᄮ"), - (0x317C, "M", "ᄯ"), - (0x317D, "M", "ᄲ"), - (0x317E, "M", "ᄶ"), - (0x317F, "M", "ᅀ"), - (0x3180, "M", "ᅇ"), - (0x3181, "M", "ᅌ"), - (0x3182, "M", "ᇱ"), - (0x3183, "M", "ᇲ"), - (0x3184, "M", "ᅗ"), - (0x3185, "M", "ᅘ"), - (0x3186, "M", "ᅙ"), - (0x3187, "M", "ᆄ"), - (0x3188, "M", "ᆅ"), - (0x3189, "M", "ᆈ"), - (0x318A, "M", "ᆑ"), - (0x318B, "M", "ᆒ"), - (0x318C, "M", "ᆔ"), - (0x318D, "M", "ᆞ"), - (0x318E, "M", "ᆡ"), - (0x318F, "X"), - (0x3190, "V"), - (0x3192, "M", "一"), - (0x3193, "M", "二"), - (0x3194, "M", "三"), - (0x3195, "M", "四"), - (0x3196, "M", "上"), - (0x3197, "M", "中"), - (0x3198, "M", "下"), - (0x3199, "M", "甲"), - (0x319A, "M", "乙"), - (0x319B, "M", "丙"), - (0x319C, "M", "丁"), - (0x319D, "M", "天"), - (0x319E, "M", "地"), - (0x319F, "M", "人"), - (0x31A0, "V"), - (0x31E6, "X"), - (0x31F0, "V"), - (0x3200, "M", "(ᄀ)"), - (0x3201, "M", "(ᄂ)"), - (0x3202, "M", "(ᄃ)"), - (0x3203, "M", "(ᄅ)"), - (0x3204, "M", "(ᄆ)"), - (0x3205, "M", "(ᄇ)"), - (0x3206, "M", "(ᄉ)"), - (0x3207, "M", "(ᄋ)"), - (0x3208, "M", "(ᄌ)"), - (0x3209, "M", "(ᄎ)"), - (0x320A, "M", "(ᄏ)"), - (0x320B, "M", "(ᄐ)"), - (0x320C, "M", "(ᄑ)"), - (0x320D, "M", "(ᄒ)"), - (0x320E, "M", "(가)"), - (0x320F, "M", "(나)"), - (0x3210, "M", "(다)"), - (0x3211, "M", "(라)"), - (0x3212, "M", "(마)"), - (0x3213, "M", "(바)"), - (0x3214, "M", "(사)"), - (0x3215, "M", "(아)"), - (0x3216, "M", "(자)"), - (0x3217, "M", "(차)"), - (0x3218, "M", "(카)"), - (0x3219, "M", "(타)"), - (0x321A, "M", "(파)"), - (0x321B, "M", "(하)"), - (0x321C, "M", "(주)"), - (0x321D, "M", "(오전)"), - (0x321E, "M", "(오후)"), - (0x321F, "X"), - (0x3220, "M", "(一)"), - (0x3221, "M", "(二)"), - (0x3222, "M", "(三)"), - (0x3223, "M", "(四)"), - (0x3224, "M", "(五)"), - (0x3225, "M", "(六)"), - (0x3226, "M", "(七)"), - (0x3227, "M", "(八)"), - (0x3228, "M", "(九)"), - (0x3229, "M", "(十)"), - ] - - -def _seg_31() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x322A, "M", "(月)"), - (0x322B, "M", "(火)"), - (0x322C, "M", "(水)"), - (0x322D, "M", "(木)"), - (0x322E, "M", "(金)"), - (0x322F, "M", "(土)"), - (0x3230, "M", "(日)"), - (0x3231, "M", "(株)"), - (0x3232, "M", "(有)"), - (0x3233, "M", "(社)"), - (0x3234, "M", "(名)"), - (0x3235, "M", "(特)"), - (0x3236, "M", "(財)"), - (0x3237, "M", "(祝)"), - (0x3238, "M", "(労)"), - (0x3239, "M", "(代)"), - (0x323A, "M", "(呼)"), - (0x323B, "M", "(学)"), - (0x323C, "M", "(監)"), - (0x323D, "M", "(企)"), - (0x323E, "M", "(資)"), - (0x323F, "M", "(協)"), - (0x3240, "M", "(祭)"), - (0x3241, "M", "(休)"), - (0x3242, "M", "(自)"), - (0x3243, "M", "(至)"), - (0x3244, "M", "問"), - (0x3245, "M", "幼"), - (0x3246, "M", "文"), - (0x3247, "M", "箏"), - (0x3248, "V"), - (0x3250, "M", "pte"), - (0x3251, "M", "21"), - (0x3252, "M", "22"), - (0x3253, "M", "23"), - (0x3254, "M", "24"), - (0x3255, "M", "25"), - (0x3256, "M", "26"), - (0x3257, "M", "27"), - (0x3258, "M", "28"), - (0x3259, "M", "29"), - (0x325A, "M", "30"), - (0x325B, "M", "31"), - (0x325C, "M", "32"), - (0x325D, "M", "33"), - (0x325E, "M", "34"), - (0x325F, "M", "35"), - (0x3260, "M", "ᄀ"), - (0x3261, "M", "ᄂ"), - (0x3262, "M", "ᄃ"), - (0x3263, "M", "ᄅ"), - (0x3264, "M", "ᄆ"), - (0x3265, "M", "ᄇ"), - (0x3266, "M", "ᄉ"), - (0x3267, "M", "ᄋ"), - (0x3268, "M", "ᄌ"), - (0x3269, "M", "ᄎ"), - (0x326A, "M", "ᄏ"), - (0x326B, "M", "ᄐ"), - (0x326C, "M", "ᄑ"), - (0x326D, "M", "ᄒ"), - (0x326E, "M", "가"), - (0x326F, "M", "나"), - (0x3270, "M", "다"), - (0x3271, "M", "라"), - (0x3272, "M", "마"), - (0x3273, "M", "바"), - (0x3274, "M", "사"), - (0x3275, "M", "아"), - (0x3276, "M", "자"), - (0x3277, "M", "차"), - (0x3278, "M", "카"), - (0x3279, "M", "타"), - (0x327A, "M", "파"), - (0x327B, "M", "하"), - (0x327C, "M", "참고"), - (0x327D, "M", "주의"), - (0x327E, "M", "우"), - (0x327F, "V"), - (0x3280, "M", "一"), - (0x3281, "M", "二"), - (0x3282, "M", "三"), - (0x3283, "M", "四"), - (0x3284, "M", "五"), - (0x3285, "M", "六"), - (0x3286, "M", "七"), - (0x3287, "M", "八"), - (0x3288, "M", "九"), - (0x3289, "M", "十"), - (0x328A, "M", "月"), - (0x328B, "M", "火"), - (0x328C, "M", "水"), - (0x328D, "M", "木"), - (0x328E, "M", "金"), - (0x328F, "M", "土"), - (0x3290, "M", "日"), - (0x3291, "M", "株"), - (0x3292, "M", "有"), - (0x3293, "M", "社"), - (0x3294, "M", "名"), - ] - - -def _seg_32() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x3295, "M", "特"), - (0x3296, "M", "財"), - (0x3297, "M", "祝"), - (0x3298, "M", "労"), - (0x3299, "M", "秘"), - (0x329A, "M", "男"), - (0x329B, "M", "女"), - (0x329C, "M", "適"), - (0x329D, "M", "優"), - (0x329E, "M", "印"), - (0x329F, "M", "注"), - (0x32A0, "M", "項"), - (0x32A1, "M", "休"), - (0x32A2, "M", "写"), - (0x32A3, "M", "正"), - (0x32A4, "M", "上"), - (0x32A5, "M", "中"), - (0x32A6, "M", "下"), - (0x32A7, "M", "左"), - (0x32A8, "M", "右"), - (0x32A9, "M", "医"), - (0x32AA, "M", "宗"), - (0x32AB, "M", "学"), - (0x32AC, "M", "監"), - (0x32AD, "M", "企"), - (0x32AE, "M", "資"), - (0x32AF, "M", "協"), - (0x32B0, "M", "夜"), - (0x32B1, "M", "36"), - (0x32B2, "M", "37"), - (0x32B3, "M", "38"), - (0x32B4, "M", "39"), - (0x32B5, "M", "40"), - (0x32B6, "M", "41"), - (0x32B7, "M", "42"), - (0x32B8, "M", "43"), - (0x32B9, "M", "44"), - (0x32BA, "M", "45"), - (0x32BB, "M", "46"), - (0x32BC, "M", "47"), - (0x32BD, "M", "48"), - (0x32BE, "M", "49"), - (0x32BF, "M", "50"), - (0x32C0, "M", "1月"), - (0x32C1, "M", "2月"), - (0x32C2, "M", "3月"), - (0x32C3, "M", "4月"), - (0x32C4, "M", "5月"), - (0x32C5, "M", "6月"), - (0x32C6, "M", "7月"), - (0x32C7, "M", "8月"), - (0x32C8, "M", "9月"), - (0x32C9, "M", "10月"), - (0x32CA, "M", "11月"), - (0x32CB, "M", "12月"), - (0x32CC, "M", "hg"), - (0x32CD, "M", "erg"), - (0x32CE, "M", "ev"), - (0x32CF, "M", "ltd"), - (0x32D0, "M", "ア"), - (0x32D1, "M", "イ"), - (0x32D2, "M", "ウ"), - (0x32D3, "M", "エ"), - (0x32D4, "M", "オ"), - (0x32D5, "M", "カ"), - (0x32D6, "M", "キ"), - (0x32D7, "M", "ク"), - (0x32D8, "M", "ケ"), - (0x32D9, "M", "コ"), - (0x32DA, "M", "サ"), - (0x32DB, "M", "シ"), - (0x32DC, "M", "ス"), - (0x32DD, "M", "セ"), - (0x32DE, "M", "ソ"), - (0x32DF, "M", "タ"), - (0x32E0, "M", "チ"), - (0x32E1, "M", "ツ"), - (0x32E2, "M", "テ"), - (0x32E3, "M", "ト"), - (0x32E4, "M", "ナ"), - (0x32E5, "M", "ニ"), - (0x32E6, "M", "ヌ"), - (0x32E7, "M", "ネ"), - (0x32E8, "M", "ノ"), - (0x32E9, "M", "ハ"), - (0x32EA, "M", "ヒ"), - (0x32EB, "M", "フ"), - (0x32EC, "M", "ヘ"), - (0x32ED, "M", "ホ"), - (0x32EE, "M", "マ"), - (0x32EF, "M", "ミ"), - (0x32F0, "M", "ム"), - (0x32F1, "M", "メ"), - (0x32F2, "M", "モ"), - (0x32F3, "M", "ヤ"), - (0x32F4, "M", "ユ"), - (0x32F5, "M", "ヨ"), - (0x32F6, "M", "ラ"), - (0x32F7, "M", "リ"), - (0x32F8, "M", "ル"), - ] - - -def _seg_33() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x32F9, "M", "レ"), - (0x32FA, "M", "ロ"), - (0x32FB, "M", "ワ"), - (0x32FC, "M", "ヰ"), - (0x32FD, "M", "ヱ"), - (0x32FE, "M", "ヲ"), - (0x32FF, "M", "令和"), - (0x3300, "M", "アパート"), - (0x3301, "M", "アルファ"), - (0x3302, "M", "アンペア"), - (0x3303, "M", "アール"), - (0x3304, "M", "イニング"), - (0x3305, "M", "インチ"), - (0x3306, "M", "ウォン"), - (0x3307, "M", "エスクード"), - (0x3308, "M", "エーカー"), - (0x3309, "M", "オンス"), - (0x330A, "M", "オーム"), - (0x330B, "M", "カイリ"), - (0x330C, "M", "カラット"), - (0x330D, "M", "カロリー"), - (0x330E, "M", "ガロン"), - (0x330F, "M", "ガンマ"), - (0x3310, "M", "ギガ"), - (0x3311, "M", "ギニー"), - (0x3312, "M", "キュリー"), - (0x3313, "M", "ギルダー"), - (0x3314, "M", "キロ"), - (0x3315, "M", "キログラム"), - (0x3316, "M", "キロメートル"), - (0x3317, "M", "キロワット"), - (0x3318, "M", "グラム"), - (0x3319, "M", "グラムトン"), - (0x331A, "M", "クルゼイロ"), - (0x331B, "M", "クローネ"), - (0x331C, "M", "ケース"), - (0x331D, "M", "コルナ"), - (0x331E, "M", "コーポ"), - (0x331F, "M", "サイクル"), - (0x3320, "M", "サンチーム"), - (0x3321, "M", "シリング"), - (0x3322, "M", "センチ"), - (0x3323, "M", "セント"), - (0x3324, "M", "ダース"), - (0x3325, "M", "デシ"), - (0x3326, "M", "ドル"), - (0x3327, "M", "トン"), - (0x3328, "M", "ナノ"), - (0x3329, "M", "ノット"), - (0x332A, "M", "ハイツ"), - (0x332B, "M", "パーセント"), - (0x332C, "M", "パーツ"), - (0x332D, "M", "バーレル"), - (0x332E, "M", "ピアストル"), - (0x332F, "M", "ピクル"), - (0x3330, "M", "ピコ"), - (0x3331, "M", "ビル"), - (0x3332, "M", "ファラッド"), - (0x3333, "M", "フィート"), - (0x3334, "M", "ブッシェル"), - (0x3335, "M", "フラン"), - (0x3336, "M", "ヘクタール"), - (0x3337, "M", "ペソ"), - (0x3338, "M", "ペニヒ"), - (0x3339, "M", "ヘルツ"), - (0x333A, "M", "ペンス"), - (0x333B, "M", "ページ"), - (0x333C, "M", "ベータ"), - (0x333D, "M", "ポイント"), - (0x333E, "M", "ボルト"), - (0x333F, "M", "ホン"), - (0x3340, "M", "ポンド"), - (0x3341, "M", "ホール"), - (0x3342, "M", "ホーン"), - (0x3343, "M", "マイクロ"), - (0x3344, "M", "マイル"), - (0x3345, "M", "マッハ"), - (0x3346, "M", "マルク"), - (0x3347, "M", "マンション"), - (0x3348, "M", "ミクロン"), - (0x3349, "M", "ミリ"), - (0x334A, "M", "ミリバール"), - (0x334B, "M", "メガ"), - (0x334C, "M", "メガトン"), - (0x334D, "M", "メートル"), - (0x334E, "M", "ヤード"), - (0x334F, "M", "ヤール"), - (0x3350, "M", "ユアン"), - (0x3351, "M", "リットル"), - (0x3352, "M", "リラ"), - (0x3353, "M", "ルピー"), - (0x3354, "M", "ルーブル"), - (0x3355, "M", "レム"), - (0x3356, "M", "レントゲン"), - (0x3357, "M", "ワット"), - (0x3358, "M", "0点"), - (0x3359, "M", "1点"), - (0x335A, "M", "2点"), - (0x335B, "M", "3点"), - (0x335C, "M", "4点"), - ] - - -def _seg_34() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x335D, "M", "5点"), - (0x335E, "M", "6点"), - (0x335F, "M", "7点"), - (0x3360, "M", "8点"), - (0x3361, "M", "9点"), - (0x3362, "M", "10点"), - (0x3363, "M", "11点"), - (0x3364, "M", "12点"), - (0x3365, "M", "13点"), - (0x3366, "M", "14点"), - (0x3367, "M", "15点"), - (0x3368, "M", "16点"), - (0x3369, "M", "17点"), - (0x336A, "M", "18点"), - (0x336B, "M", "19点"), - (0x336C, "M", "20点"), - (0x336D, "M", "21点"), - (0x336E, "M", "22点"), - (0x336F, "M", "23点"), - (0x3370, "M", "24点"), - (0x3371, "M", "hpa"), - (0x3372, "M", "da"), - (0x3373, "M", "au"), - (0x3374, "M", "bar"), - (0x3375, "M", "ov"), - (0x3376, "M", "pc"), - (0x3377, "M", "dm"), - (0x3378, "M", "dm2"), - (0x3379, "M", "dm3"), - (0x337A, "M", "iu"), - (0x337B, "M", "平成"), - (0x337C, "M", "昭和"), - (0x337D, "M", "大正"), - (0x337E, "M", "明治"), - (0x337F, "M", "株式会社"), - (0x3380, "M", "pa"), - (0x3381, "M", "na"), - (0x3382, "M", "μa"), - (0x3383, "M", "ma"), - (0x3384, "M", "ka"), - (0x3385, "M", "kb"), - (0x3386, "M", "mb"), - (0x3387, "M", "gb"), - (0x3388, "M", "cal"), - (0x3389, "M", "kcal"), - (0x338A, "M", "pf"), - (0x338B, "M", "nf"), - (0x338C, "M", "μf"), - (0x338D, "M", "μg"), - (0x338E, "M", "mg"), - (0x338F, "M", "kg"), - (0x3390, "M", "hz"), - (0x3391, "M", "khz"), - (0x3392, "M", "mhz"), - (0x3393, "M", "ghz"), - (0x3394, "M", "thz"), - (0x3395, "M", "μl"), - (0x3396, "M", "ml"), - (0x3397, "M", "dl"), - (0x3398, "M", "kl"), - (0x3399, "M", "fm"), - (0x339A, "M", "nm"), - (0x339B, "M", "μm"), - (0x339C, "M", "mm"), - (0x339D, "M", "cm"), - (0x339E, "M", "km"), - (0x339F, "M", "mm2"), - (0x33A0, "M", "cm2"), - (0x33A1, "M", "m2"), - (0x33A2, "M", "km2"), - (0x33A3, "M", "mm3"), - (0x33A4, "M", "cm3"), - (0x33A5, "M", "m3"), - (0x33A6, "M", "km3"), - (0x33A7, "M", "m∕s"), - (0x33A8, "M", "m∕s2"), - (0x33A9, "M", "pa"), - (0x33AA, "M", "kpa"), - (0x33AB, "M", "mpa"), - (0x33AC, "M", "gpa"), - (0x33AD, "M", "rad"), - (0x33AE, "M", "rad∕s"), - (0x33AF, "M", "rad∕s2"), - (0x33B0, "M", "ps"), - (0x33B1, "M", "ns"), - (0x33B2, "M", "μs"), - (0x33B3, "M", "ms"), - (0x33B4, "M", "pv"), - (0x33B5, "M", "nv"), - (0x33B6, "M", "μv"), - (0x33B7, "M", "mv"), - (0x33B8, "M", "kv"), - (0x33B9, "M", "mv"), - (0x33BA, "M", "pw"), - (0x33BB, "M", "nw"), - (0x33BC, "M", "μw"), - (0x33BD, "M", "mw"), - (0x33BE, "M", "kw"), - (0x33BF, "M", "mw"), - (0x33C0, "M", "kω"), - ] - - -def _seg_35() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x33C1, "M", "mω"), - (0x33C2, "X"), - (0x33C3, "M", "bq"), - (0x33C4, "M", "cc"), - (0x33C5, "M", "cd"), - (0x33C6, "M", "c∕kg"), - (0x33C7, "X"), - (0x33C8, "M", "db"), - (0x33C9, "M", "gy"), - (0x33CA, "M", "ha"), - (0x33CB, "M", "hp"), - (0x33CC, "M", "in"), - (0x33CD, "M", "kk"), - (0x33CE, "M", "km"), - (0x33CF, "M", "kt"), - (0x33D0, "M", "lm"), - (0x33D1, "M", "ln"), - (0x33D2, "M", "log"), - (0x33D3, "M", "lx"), - (0x33D4, "M", "mb"), - (0x33D5, "M", "mil"), - (0x33D6, "M", "mol"), - (0x33D7, "M", "ph"), - (0x33D8, "X"), - (0x33D9, "M", "ppm"), - (0x33DA, "M", "pr"), - (0x33DB, "M", "sr"), - (0x33DC, "M", "sv"), - (0x33DD, "M", "wb"), - (0x33DE, "M", "v∕m"), - (0x33DF, "M", "a∕m"), - (0x33E0, "M", "1日"), - (0x33E1, "M", "2日"), - (0x33E2, "M", "3日"), - (0x33E3, "M", "4日"), - (0x33E4, "M", "5日"), - (0x33E5, "M", "6日"), - (0x33E6, "M", "7日"), - (0x33E7, "M", "8日"), - (0x33E8, "M", "9日"), - (0x33E9, "M", "10日"), - (0x33EA, "M", "11日"), - (0x33EB, "M", "12日"), - (0x33EC, "M", "13日"), - (0x33ED, "M", "14日"), - (0x33EE, "M", "15日"), - (0x33EF, "M", "16日"), - (0x33F0, "M", "17日"), - (0x33F1, "M", "18日"), - (0x33F2, "M", "19日"), - (0x33F3, "M", "20日"), - (0x33F4, "M", "21日"), - (0x33F5, "M", "22日"), - (0x33F6, "M", "23日"), - (0x33F7, "M", "24日"), - (0x33F8, "M", "25日"), - (0x33F9, "M", "26日"), - (0x33FA, "M", "27日"), - (0x33FB, "M", "28日"), - (0x33FC, "M", "29日"), - (0x33FD, "M", "30日"), - (0x33FE, "M", "31日"), - (0x33FF, "M", "gal"), - (0x3400, "V"), - (0xA48D, "X"), - (0xA490, "V"), - (0xA4C7, "X"), - (0xA4D0, "V"), - (0xA62C, "X"), - (0xA640, "M", "ꙁ"), - (0xA641, "V"), - (0xA642, "M", "ꙃ"), - (0xA643, "V"), - (0xA644, "M", "ꙅ"), - (0xA645, "V"), - (0xA646, "M", "ꙇ"), - (0xA647, "V"), - (0xA648, "M", "ꙉ"), - (0xA649, "V"), - (0xA64A, "M", "ꙋ"), - (0xA64B, "V"), - (0xA64C, "M", "ꙍ"), - (0xA64D, "V"), - (0xA64E, "M", "ꙏ"), - (0xA64F, "V"), - (0xA650, "M", "ꙑ"), - (0xA651, "V"), - (0xA652, "M", "ꙓ"), - (0xA653, "V"), - (0xA654, "M", "ꙕ"), - (0xA655, "V"), - (0xA656, "M", "ꙗ"), - (0xA657, "V"), - (0xA658, "M", "ꙙ"), - (0xA659, "V"), - (0xA65A, "M", "ꙛ"), - (0xA65B, "V"), - (0xA65C, "M", "ꙝ"), - (0xA65D, "V"), - (0xA65E, "M", "ꙟ"), - ] - - -def _seg_36() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xA65F, "V"), - (0xA660, "M", "ꙡ"), - (0xA661, "V"), - (0xA662, "M", "ꙣ"), - (0xA663, "V"), - (0xA664, "M", "ꙥ"), - (0xA665, "V"), - (0xA666, "M", "ꙧ"), - (0xA667, "V"), - (0xA668, "M", "ꙩ"), - (0xA669, "V"), - (0xA66A, "M", "ꙫ"), - (0xA66B, "V"), - (0xA66C, "M", "ꙭ"), - (0xA66D, "V"), - (0xA680, "M", "ꚁ"), - (0xA681, "V"), - (0xA682, "M", "ꚃ"), - (0xA683, "V"), - (0xA684, "M", "ꚅ"), - (0xA685, "V"), - (0xA686, "M", "ꚇ"), - (0xA687, "V"), - (0xA688, "M", "ꚉ"), - (0xA689, "V"), - (0xA68A, "M", "ꚋ"), - (0xA68B, "V"), - (0xA68C, "M", "ꚍ"), - (0xA68D, "V"), - (0xA68E, "M", "ꚏ"), - (0xA68F, "V"), - (0xA690, "M", "ꚑ"), - (0xA691, "V"), - (0xA692, "M", "ꚓ"), - (0xA693, "V"), - (0xA694, "M", "ꚕ"), - (0xA695, "V"), - (0xA696, "M", "ꚗ"), - (0xA697, "V"), - (0xA698, "M", "ꚙ"), - (0xA699, "V"), - (0xA69A, "M", "ꚛ"), - (0xA69B, "V"), - (0xA69C, "M", "ъ"), - (0xA69D, "M", "ь"), - (0xA69E, "V"), - (0xA6F8, "X"), - (0xA700, "V"), - (0xA722, "M", "ꜣ"), - (0xA723, "V"), - (0xA724, "M", "ꜥ"), - (0xA725, "V"), - (0xA726, "M", "ꜧ"), - (0xA727, "V"), - (0xA728, "M", "ꜩ"), - (0xA729, "V"), - (0xA72A, "M", "ꜫ"), - (0xA72B, "V"), - (0xA72C, "M", "ꜭ"), - (0xA72D, "V"), - (0xA72E, "M", "ꜯ"), - (0xA72F, "V"), - (0xA732, "M", "ꜳ"), - (0xA733, "V"), - (0xA734, "M", "ꜵ"), - (0xA735, "V"), - (0xA736, "M", "ꜷ"), - (0xA737, "V"), - (0xA738, "M", "ꜹ"), - (0xA739, "V"), - (0xA73A, "M", "ꜻ"), - (0xA73B, "V"), - (0xA73C, "M", "ꜽ"), - (0xA73D, "V"), - (0xA73E, "M", "ꜿ"), - (0xA73F, "V"), - (0xA740, "M", "ꝁ"), - (0xA741, "V"), - (0xA742, "M", "ꝃ"), - (0xA743, "V"), - (0xA744, "M", "ꝅ"), - (0xA745, "V"), - (0xA746, "M", "ꝇ"), - (0xA747, "V"), - (0xA748, "M", "ꝉ"), - (0xA749, "V"), - (0xA74A, "M", "ꝋ"), - (0xA74B, "V"), - (0xA74C, "M", "ꝍ"), - (0xA74D, "V"), - (0xA74E, "M", "ꝏ"), - (0xA74F, "V"), - (0xA750, "M", "ꝑ"), - (0xA751, "V"), - (0xA752, "M", "ꝓ"), - (0xA753, "V"), - (0xA754, "M", "ꝕ"), - (0xA755, "V"), - (0xA756, "M", "ꝗ"), - (0xA757, "V"), - ] - - -def _seg_37() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xA758, "M", "ꝙ"), - (0xA759, "V"), - (0xA75A, "M", "ꝛ"), - (0xA75B, "V"), - (0xA75C, "M", "ꝝ"), - (0xA75D, "V"), - (0xA75E, "M", "ꝟ"), - (0xA75F, "V"), - (0xA760, "M", "ꝡ"), - (0xA761, "V"), - (0xA762, "M", "ꝣ"), - (0xA763, "V"), - (0xA764, "M", "ꝥ"), - (0xA765, "V"), - (0xA766, "M", "ꝧ"), - (0xA767, "V"), - (0xA768, "M", "ꝩ"), - (0xA769, "V"), - (0xA76A, "M", "ꝫ"), - (0xA76B, "V"), - (0xA76C, "M", "ꝭ"), - (0xA76D, "V"), - (0xA76E, "M", "ꝯ"), - (0xA76F, "V"), - (0xA770, "M", "ꝯ"), - (0xA771, "V"), - (0xA779, "M", "ꝺ"), - (0xA77A, "V"), - (0xA77B, "M", "ꝼ"), - (0xA77C, "V"), - (0xA77D, "M", "ᵹ"), - (0xA77E, "M", "ꝿ"), - (0xA77F, "V"), - (0xA780, "M", "ꞁ"), - (0xA781, "V"), - (0xA782, "M", "ꞃ"), - (0xA783, "V"), - (0xA784, "M", "ꞅ"), - (0xA785, "V"), - (0xA786, "M", "ꞇ"), - (0xA787, "V"), - (0xA78B, "M", "ꞌ"), - (0xA78C, "V"), - (0xA78D, "M", "ɥ"), - (0xA78E, "V"), - (0xA790, "M", "ꞑ"), - (0xA791, "V"), - (0xA792, "M", "ꞓ"), - (0xA793, "V"), - (0xA796, "M", "ꞗ"), - (0xA797, "V"), - (0xA798, "M", "ꞙ"), - (0xA799, "V"), - (0xA79A, "M", "ꞛ"), - (0xA79B, "V"), - (0xA79C, "M", "ꞝ"), - (0xA79D, "V"), - (0xA79E, "M", "ꞟ"), - (0xA79F, "V"), - (0xA7A0, "M", "ꞡ"), - (0xA7A1, "V"), - (0xA7A2, "M", "ꞣ"), - (0xA7A3, "V"), - (0xA7A4, "M", "ꞥ"), - (0xA7A5, "V"), - (0xA7A6, "M", "ꞧ"), - (0xA7A7, "V"), - (0xA7A8, "M", "ꞩ"), - (0xA7A9, "V"), - (0xA7AA, "M", "ɦ"), - (0xA7AB, "M", "ɜ"), - (0xA7AC, "M", "ɡ"), - (0xA7AD, "M", "ɬ"), - (0xA7AE, "M", "ɪ"), - (0xA7AF, "V"), - (0xA7B0, "M", "ʞ"), - (0xA7B1, "M", "ʇ"), - (0xA7B2, "M", "ʝ"), - (0xA7B3, "M", "ꭓ"), - (0xA7B4, "M", "ꞵ"), - (0xA7B5, "V"), - (0xA7B6, "M", "ꞷ"), - (0xA7B7, "V"), - (0xA7B8, "M", "ꞹ"), - (0xA7B9, "V"), - (0xA7BA, "M", "ꞻ"), - (0xA7BB, "V"), - (0xA7BC, "M", "ꞽ"), - (0xA7BD, "V"), - (0xA7BE, "M", "ꞿ"), - (0xA7BF, "V"), - (0xA7C0, "M", "ꟁ"), - (0xA7C1, "V"), - (0xA7C2, "M", "ꟃ"), - (0xA7C3, "V"), - (0xA7C4, "M", "ꞔ"), - (0xA7C5, "M", "ʂ"), - (0xA7C6, "M", "ᶎ"), - (0xA7C7, "M", "ꟈ"), - (0xA7C8, "V"), - ] - - -def _seg_38() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xA7C9, "M", "ꟊ"), - (0xA7CA, "V"), - (0xA7CB, "M", "ɤ"), - (0xA7CC, "M", "ꟍ"), - (0xA7CD, "V"), - (0xA7CE, "X"), - (0xA7D0, "M", "ꟑ"), - (0xA7D1, "V"), - (0xA7D2, "X"), - (0xA7D3, "V"), - (0xA7D4, "X"), - (0xA7D5, "V"), - (0xA7D6, "M", "ꟗ"), - (0xA7D7, "V"), - (0xA7D8, "M", "ꟙ"), - (0xA7D9, "V"), - (0xA7DA, "M", "ꟛ"), - (0xA7DB, "V"), - (0xA7DC, "M", "ƛ"), - (0xA7DD, "X"), - (0xA7F2, "M", "c"), - (0xA7F3, "M", "f"), - (0xA7F4, "M", "q"), - (0xA7F5, "M", "ꟶ"), - (0xA7F6, "V"), - (0xA7F8, "M", "ħ"), - (0xA7F9, "M", "œ"), - (0xA7FA, "V"), - (0xA82D, "X"), - (0xA830, "V"), - (0xA83A, "X"), - (0xA840, "V"), - (0xA878, "X"), - (0xA880, "V"), - (0xA8C6, "X"), - (0xA8CE, "V"), - (0xA8DA, "X"), - (0xA8E0, "V"), - (0xA954, "X"), - (0xA95F, "V"), - (0xA97D, "X"), - (0xA980, "V"), - (0xA9CE, "X"), - (0xA9CF, "V"), - (0xA9DA, "X"), - (0xA9DE, "V"), - (0xA9FF, "X"), - (0xAA00, "V"), - (0xAA37, "X"), - (0xAA40, "V"), - (0xAA4E, "X"), - (0xAA50, "V"), - (0xAA5A, "X"), - (0xAA5C, "V"), - (0xAAC3, "X"), - (0xAADB, "V"), - (0xAAF7, "X"), - (0xAB01, "V"), - (0xAB07, "X"), - (0xAB09, "V"), - (0xAB0F, "X"), - (0xAB11, "V"), - (0xAB17, "X"), - (0xAB20, "V"), - (0xAB27, "X"), - (0xAB28, "V"), - (0xAB2F, "X"), - (0xAB30, "V"), - (0xAB5C, "M", "ꜧ"), - (0xAB5D, "M", "ꬷ"), - (0xAB5E, "M", "ɫ"), - (0xAB5F, "M", "ꭒ"), - (0xAB60, "V"), - (0xAB69, "M", "ʍ"), - (0xAB6A, "V"), - (0xAB6C, "X"), - (0xAB70, "M", "Ꭰ"), - (0xAB71, "M", "Ꭱ"), - (0xAB72, "M", "Ꭲ"), - (0xAB73, "M", "Ꭳ"), - (0xAB74, "M", "Ꭴ"), - (0xAB75, "M", "Ꭵ"), - (0xAB76, "M", "Ꭶ"), - (0xAB77, "M", "Ꭷ"), - (0xAB78, "M", "Ꭸ"), - (0xAB79, "M", "Ꭹ"), - (0xAB7A, "M", "Ꭺ"), - (0xAB7B, "M", "Ꭻ"), - (0xAB7C, "M", "Ꭼ"), - (0xAB7D, "M", "Ꭽ"), - (0xAB7E, "M", "Ꭾ"), - (0xAB7F, "M", "Ꭿ"), - (0xAB80, "M", "Ꮀ"), - (0xAB81, "M", "Ꮁ"), - (0xAB82, "M", "Ꮂ"), - (0xAB83, "M", "Ꮃ"), - (0xAB84, "M", "Ꮄ"), - (0xAB85, "M", "Ꮅ"), - (0xAB86, "M", "Ꮆ"), - (0xAB87, "M", "Ꮇ"), - ] - - -def _seg_39() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xAB88, "M", "Ꮈ"), - (0xAB89, "M", "Ꮉ"), - (0xAB8A, "M", "Ꮊ"), - (0xAB8B, "M", "Ꮋ"), - (0xAB8C, "M", "Ꮌ"), - (0xAB8D, "M", "Ꮍ"), - (0xAB8E, "M", "Ꮎ"), - (0xAB8F, "M", "Ꮏ"), - (0xAB90, "M", "Ꮐ"), - (0xAB91, "M", "Ꮑ"), - (0xAB92, "M", "Ꮒ"), - (0xAB93, "M", "Ꮓ"), - (0xAB94, "M", "Ꮔ"), - (0xAB95, "M", "Ꮕ"), - (0xAB96, "M", "Ꮖ"), - (0xAB97, "M", "Ꮗ"), - (0xAB98, "M", "Ꮘ"), - (0xAB99, "M", "Ꮙ"), - (0xAB9A, "M", "Ꮚ"), - (0xAB9B, "M", "Ꮛ"), - (0xAB9C, "M", "Ꮜ"), - (0xAB9D, "M", "Ꮝ"), - (0xAB9E, "M", "Ꮞ"), - (0xAB9F, "M", "Ꮟ"), - (0xABA0, "M", "Ꮠ"), - (0xABA1, "M", "Ꮡ"), - (0xABA2, "M", "Ꮢ"), - (0xABA3, "M", "Ꮣ"), - (0xABA4, "M", "Ꮤ"), - (0xABA5, "M", "Ꮥ"), - (0xABA6, "M", "Ꮦ"), - (0xABA7, "M", "Ꮧ"), - (0xABA8, "M", "Ꮨ"), - (0xABA9, "M", "Ꮩ"), - (0xABAA, "M", "Ꮪ"), - (0xABAB, "M", "Ꮫ"), - (0xABAC, "M", "Ꮬ"), - (0xABAD, "M", "Ꮭ"), - (0xABAE, "M", "Ꮮ"), - (0xABAF, "M", "Ꮯ"), - (0xABB0, "M", "Ꮰ"), - (0xABB1, "M", "Ꮱ"), - (0xABB2, "M", "Ꮲ"), - (0xABB3, "M", "Ꮳ"), - (0xABB4, "M", "Ꮴ"), - (0xABB5, "M", "Ꮵ"), - (0xABB6, "M", "Ꮶ"), - (0xABB7, "M", "Ꮷ"), - (0xABB8, "M", "Ꮸ"), - (0xABB9, "M", "Ꮹ"), - (0xABBA, "M", "Ꮺ"), - (0xABBB, "M", "Ꮻ"), - (0xABBC, "M", "Ꮼ"), - (0xABBD, "M", "Ꮽ"), - (0xABBE, "M", "Ꮾ"), - (0xABBF, "M", "Ꮿ"), - (0xABC0, "V"), - (0xABEE, "X"), - (0xABF0, "V"), - (0xABFA, "X"), - (0xAC00, "V"), - (0xD7A4, "X"), - (0xD7B0, "V"), - (0xD7C7, "X"), - (0xD7CB, "V"), - (0xD7FC, "X"), - (0xF900, "M", "豈"), - (0xF901, "M", "更"), - (0xF902, "M", "車"), - (0xF903, "M", "賈"), - (0xF904, "M", "滑"), - (0xF905, "M", "串"), - (0xF906, "M", "句"), - (0xF907, "M", "龜"), - (0xF909, "M", "契"), - (0xF90A, "M", "金"), - (0xF90B, "M", "喇"), - (0xF90C, "M", "奈"), - (0xF90D, "M", "懶"), - (0xF90E, "M", "癩"), - (0xF90F, "M", "羅"), - (0xF910, "M", "蘿"), - (0xF911, "M", "螺"), - (0xF912, "M", "裸"), - (0xF913, "M", "邏"), - (0xF914, "M", "樂"), - (0xF915, "M", "洛"), - (0xF916, "M", "烙"), - (0xF917, "M", "珞"), - (0xF918, "M", "落"), - (0xF919, "M", "酪"), - (0xF91A, "M", "駱"), - (0xF91B, "M", "亂"), - (0xF91C, "M", "卵"), - (0xF91D, "M", "欄"), - (0xF91E, "M", "爛"), - (0xF91F, "M", "蘭"), - (0xF920, "M", "鸞"), - (0xF921, "M", "嵐"), - (0xF922, "M", "濫"), - ] - - -def _seg_40() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xF923, "M", "藍"), - (0xF924, "M", "襤"), - (0xF925, "M", "拉"), - (0xF926, "M", "臘"), - (0xF927, "M", "蠟"), - (0xF928, "M", "廊"), - (0xF929, "M", "朗"), - (0xF92A, "M", "浪"), - (0xF92B, "M", "狼"), - (0xF92C, "M", "郎"), - (0xF92D, "M", "來"), - (0xF92E, "M", "冷"), - (0xF92F, "M", "勞"), - (0xF930, "M", "擄"), - (0xF931, "M", "櫓"), - (0xF932, "M", "爐"), - (0xF933, "M", "盧"), - (0xF934, "M", "老"), - (0xF935, "M", "蘆"), - (0xF936, "M", "虜"), - (0xF937, "M", "路"), - (0xF938, "M", "露"), - (0xF939, "M", "魯"), - (0xF93A, "M", "鷺"), - (0xF93B, "M", "碌"), - (0xF93C, "M", "祿"), - (0xF93D, "M", "綠"), - (0xF93E, "M", "菉"), - (0xF93F, "M", "錄"), - (0xF940, "M", "鹿"), - (0xF941, "M", "論"), - (0xF942, "M", "壟"), - (0xF943, "M", "弄"), - (0xF944, "M", "籠"), - (0xF945, "M", "聾"), - (0xF946, "M", "牢"), - (0xF947, "M", "磊"), - (0xF948, "M", "賂"), - (0xF949, "M", "雷"), - (0xF94A, "M", "壘"), - (0xF94B, "M", "屢"), - (0xF94C, "M", "樓"), - (0xF94D, "M", "淚"), - (0xF94E, "M", "漏"), - (0xF94F, "M", "累"), - (0xF950, "M", "縷"), - (0xF951, "M", "陋"), - (0xF952, "M", "勒"), - (0xF953, "M", "肋"), - (0xF954, "M", "凜"), - (0xF955, "M", "凌"), - (0xF956, "M", "稜"), - (0xF957, "M", "綾"), - (0xF958, "M", "菱"), - (0xF959, "M", "陵"), - (0xF95A, "M", "讀"), - (0xF95B, "M", "拏"), - (0xF95C, "M", "樂"), - (0xF95D, "M", "諾"), - (0xF95E, "M", "丹"), - (0xF95F, "M", "寧"), - (0xF960, "M", "怒"), - (0xF961, "M", "率"), - (0xF962, "M", "異"), - (0xF963, "M", "北"), - (0xF964, "M", "磻"), - (0xF965, "M", "便"), - (0xF966, "M", "復"), - (0xF967, "M", "不"), - (0xF968, "M", "泌"), - (0xF969, "M", "數"), - (0xF96A, "M", "索"), - (0xF96B, "M", "參"), - (0xF96C, "M", "塞"), - (0xF96D, "M", "省"), - (0xF96E, "M", "葉"), - (0xF96F, "M", "說"), - (0xF970, "M", "殺"), - (0xF971, "M", "辰"), - (0xF972, "M", "沈"), - (0xF973, "M", "拾"), - (0xF974, "M", "若"), - (0xF975, "M", "掠"), - (0xF976, "M", "略"), - (0xF977, "M", "亮"), - (0xF978, "M", "兩"), - (0xF979, "M", "凉"), - (0xF97A, "M", "梁"), - (0xF97B, "M", "糧"), - (0xF97C, "M", "良"), - (0xF97D, "M", "諒"), - (0xF97E, "M", "量"), - (0xF97F, "M", "勵"), - (0xF980, "M", "呂"), - (0xF981, "M", "女"), - (0xF982, "M", "廬"), - (0xF983, "M", "旅"), - (0xF984, "M", "濾"), - (0xF985, "M", "礪"), - (0xF986, "M", "閭"), - ] - - -def _seg_41() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xF987, "M", "驪"), - (0xF988, "M", "麗"), - (0xF989, "M", "黎"), - (0xF98A, "M", "力"), - (0xF98B, "M", "曆"), - (0xF98C, "M", "歷"), - (0xF98D, "M", "轢"), - (0xF98E, "M", "年"), - (0xF98F, "M", "憐"), - (0xF990, "M", "戀"), - (0xF991, "M", "撚"), - (0xF992, "M", "漣"), - (0xF993, "M", "煉"), - (0xF994, "M", "璉"), - (0xF995, "M", "秊"), - (0xF996, "M", "練"), - (0xF997, "M", "聯"), - (0xF998, "M", "輦"), - (0xF999, "M", "蓮"), - (0xF99A, "M", "連"), - (0xF99B, "M", "鍊"), - (0xF99C, "M", "列"), - (0xF99D, "M", "劣"), - (0xF99E, "M", "咽"), - (0xF99F, "M", "烈"), - (0xF9A0, "M", "裂"), - (0xF9A1, "M", "說"), - (0xF9A2, "M", "廉"), - (0xF9A3, "M", "念"), - (0xF9A4, "M", "捻"), - (0xF9A5, "M", "殮"), - (0xF9A6, "M", "簾"), - (0xF9A7, "M", "獵"), - (0xF9A8, "M", "令"), - (0xF9A9, "M", "囹"), - (0xF9AA, "M", "寧"), - (0xF9AB, "M", "嶺"), - (0xF9AC, "M", "怜"), - (0xF9AD, "M", "玲"), - (0xF9AE, "M", "瑩"), - (0xF9AF, "M", "羚"), - (0xF9B0, "M", "聆"), - (0xF9B1, "M", "鈴"), - (0xF9B2, "M", "零"), - (0xF9B3, "M", "靈"), - (0xF9B4, "M", "領"), - (0xF9B5, "M", "例"), - (0xF9B6, "M", "禮"), - (0xF9B7, "M", "醴"), - (0xF9B8, "M", "隸"), - (0xF9B9, "M", "惡"), - (0xF9BA, "M", "了"), - (0xF9BB, "M", "僚"), - (0xF9BC, "M", "寮"), - (0xF9BD, "M", "尿"), - (0xF9BE, "M", "料"), - (0xF9BF, "M", "樂"), - (0xF9C0, "M", "燎"), - (0xF9C1, "M", "療"), - (0xF9C2, "M", "蓼"), - (0xF9C3, "M", "遼"), - (0xF9C4, "M", "龍"), - (0xF9C5, "M", "暈"), - (0xF9C6, "M", "阮"), - (0xF9C7, "M", "劉"), - (0xF9C8, "M", "杻"), - (0xF9C9, "M", "柳"), - (0xF9CA, "M", "流"), - (0xF9CB, "M", "溜"), - (0xF9CC, "M", "琉"), - (0xF9CD, "M", "留"), - (0xF9CE, "M", "硫"), - (0xF9CF, "M", "紐"), - (0xF9D0, "M", "類"), - (0xF9D1, "M", "六"), - (0xF9D2, "M", "戮"), - (0xF9D3, "M", "陸"), - (0xF9D4, "M", "倫"), - (0xF9D5, "M", "崙"), - (0xF9D6, "M", "淪"), - (0xF9D7, "M", "輪"), - (0xF9D8, "M", "律"), - (0xF9D9, "M", "慄"), - (0xF9DA, "M", "栗"), - (0xF9DB, "M", "率"), - (0xF9DC, "M", "隆"), - (0xF9DD, "M", "利"), - (0xF9DE, "M", "吏"), - (0xF9DF, "M", "履"), - (0xF9E0, "M", "易"), - (0xF9E1, "M", "李"), - (0xF9E2, "M", "梨"), - (0xF9E3, "M", "泥"), - (0xF9E4, "M", "理"), - (0xF9E5, "M", "痢"), - (0xF9E6, "M", "罹"), - (0xF9E7, "M", "裏"), - (0xF9E8, "M", "裡"), - (0xF9E9, "M", "里"), - (0xF9EA, "M", "離"), - ] - - -def _seg_42() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xF9EB, "M", "匿"), - (0xF9EC, "M", "溺"), - (0xF9ED, "M", "吝"), - (0xF9EE, "M", "燐"), - (0xF9EF, "M", "璘"), - (0xF9F0, "M", "藺"), - (0xF9F1, "M", "隣"), - (0xF9F2, "M", "鱗"), - (0xF9F3, "M", "麟"), - (0xF9F4, "M", "林"), - (0xF9F5, "M", "淋"), - (0xF9F6, "M", "臨"), - (0xF9F7, "M", "立"), - (0xF9F8, "M", "笠"), - (0xF9F9, "M", "粒"), - (0xF9FA, "M", "狀"), - (0xF9FB, "M", "炙"), - (0xF9FC, "M", "識"), - (0xF9FD, "M", "什"), - (0xF9FE, "M", "茶"), - (0xF9FF, "M", "刺"), - (0xFA00, "M", "切"), - (0xFA01, "M", "度"), - (0xFA02, "M", "拓"), - (0xFA03, "M", "糖"), - (0xFA04, "M", "宅"), - (0xFA05, "M", "洞"), - (0xFA06, "M", "暴"), - (0xFA07, "M", "輻"), - (0xFA08, "M", "行"), - (0xFA09, "M", "降"), - (0xFA0A, "M", "見"), - (0xFA0B, "M", "廓"), - (0xFA0C, "M", "兀"), - (0xFA0D, "M", "嗀"), - (0xFA0E, "V"), - (0xFA10, "M", "塚"), - (0xFA11, "V"), - (0xFA12, "M", "晴"), - (0xFA13, "V"), - (0xFA15, "M", "凞"), - (0xFA16, "M", "猪"), - (0xFA17, "M", "益"), - (0xFA18, "M", "礼"), - (0xFA19, "M", "神"), - (0xFA1A, "M", "祥"), - (0xFA1B, "M", "福"), - (0xFA1C, "M", "靖"), - (0xFA1D, "M", "精"), - (0xFA1E, "M", "羽"), - (0xFA1F, "V"), - (0xFA20, "M", "蘒"), - (0xFA21, "V"), - (0xFA22, "M", "諸"), - (0xFA23, "V"), - (0xFA25, "M", "逸"), - (0xFA26, "M", "都"), - (0xFA27, "V"), - (0xFA2A, "M", "飯"), - (0xFA2B, "M", "飼"), - (0xFA2C, "M", "館"), - (0xFA2D, "M", "鶴"), - (0xFA2E, "M", "郞"), - (0xFA2F, "M", "隷"), - (0xFA30, "M", "侮"), - (0xFA31, "M", "僧"), - (0xFA32, "M", "免"), - (0xFA33, "M", "勉"), - (0xFA34, "M", "勤"), - (0xFA35, "M", "卑"), - (0xFA36, "M", "喝"), - (0xFA37, "M", "嘆"), - (0xFA38, "M", "器"), - (0xFA39, "M", "塀"), - (0xFA3A, "M", "墨"), - (0xFA3B, "M", "層"), - (0xFA3C, "M", "屮"), - (0xFA3D, "M", "悔"), - (0xFA3E, "M", "慨"), - (0xFA3F, "M", "憎"), - (0xFA40, "M", "懲"), - (0xFA41, "M", "敏"), - (0xFA42, "M", "既"), - (0xFA43, "M", "暑"), - (0xFA44, "M", "梅"), - (0xFA45, "M", "海"), - (0xFA46, "M", "渚"), - (0xFA47, "M", "漢"), - (0xFA48, "M", "煮"), - (0xFA49, "M", "爫"), - (0xFA4A, "M", "琢"), - (0xFA4B, "M", "碑"), - (0xFA4C, "M", "社"), - (0xFA4D, "M", "祉"), - (0xFA4E, "M", "祈"), - (0xFA4F, "M", "祐"), - (0xFA50, "M", "祖"), - (0xFA51, "M", "祝"), - (0xFA52, "M", "禍"), - (0xFA53, "M", "禎"), - ] - - -def _seg_43() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFA54, "M", "穀"), - (0xFA55, "M", "突"), - (0xFA56, "M", "節"), - (0xFA57, "M", "練"), - (0xFA58, "M", "縉"), - (0xFA59, "M", "繁"), - (0xFA5A, "M", "署"), - (0xFA5B, "M", "者"), - (0xFA5C, "M", "臭"), - (0xFA5D, "M", "艹"), - (0xFA5F, "M", "著"), - (0xFA60, "M", "褐"), - (0xFA61, "M", "視"), - (0xFA62, "M", "謁"), - (0xFA63, "M", "謹"), - (0xFA64, "M", "賓"), - (0xFA65, "M", "贈"), - (0xFA66, "M", "辶"), - (0xFA67, "M", "逸"), - (0xFA68, "M", "難"), - (0xFA69, "M", "響"), - (0xFA6A, "M", "頻"), - (0xFA6B, "M", "恵"), - (0xFA6C, "M", "𤋮"), - (0xFA6D, "M", "舘"), - (0xFA6E, "X"), - (0xFA70, "M", "並"), - (0xFA71, "M", "况"), - (0xFA72, "M", "全"), - (0xFA73, "M", "侀"), - (0xFA74, "M", "充"), - (0xFA75, "M", "冀"), - (0xFA76, "M", "勇"), - (0xFA77, "M", "勺"), - (0xFA78, "M", "喝"), - (0xFA79, "M", "啕"), - (0xFA7A, "M", "喙"), - (0xFA7B, "M", "嗢"), - (0xFA7C, "M", "塚"), - (0xFA7D, "M", "墳"), - (0xFA7E, "M", "奄"), - (0xFA7F, "M", "奔"), - (0xFA80, "M", "婢"), - (0xFA81, "M", "嬨"), - (0xFA82, "M", "廒"), - (0xFA83, "M", "廙"), - (0xFA84, "M", "彩"), - (0xFA85, "M", "徭"), - (0xFA86, "M", "惘"), - (0xFA87, "M", "慎"), - (0xFA88, "M", "愈"), - (0xFA89, "M", "憎"), - (0xFA8A, "M", "慠"), - (0xFA8B, "M", "懲"), - (0xFA8C, "M", "戴"), - (0xFA8D, "M", "揄"), - (0xFA8E, "M", "搜"), - (0xFA8F, "M", "摒"), - (0xFA90, "M", "敖"), - (0xFA91, "M", "晴"), - (0xFA92, "M", "朗"), - (0xFA93, "M", "望"), - (0xFA94, "M", "杖"), - (0xFA95, "M", "歹"), - (0xFA96, "M", "殺"), - (0xFA97, "M", "流"), - (0xFA98, "M", "滛"), - (0xFA99, "M", "滋"), - (0xFA9A, "M", "漢"), - (0xFA9B, "M", "瀞"), - (0xFA9C, "M", "煮"), - (0xFA9D, "M", "瞧"), - (0xFA9E, "M", "爵"), - (0xFA9F, "M", "犯"), - (0xFAA0, "M", "猪"), - (0xFAA1, "M", "瑱"), - (0xFAA2, "M", "甆"), - (0xFAA3, "M", "画"), - (0xFAA4, "M", "瘝"), - (0xFAA5, "M", "瘟"), - (0xFAA6, "M", "益"), - (0xFAA7, "M", "盛"), - (0xFAA8, "M", "直"), - (0xFAA9, "M", "睊"), - (0xFAAA, "M", "着"), - (0xFAAB, "M", "磌"), - (0xFAAC, "M", "窱"), - (0xFAAD, "M", "節"), - (0xFAAE, "M", "类"), - (0xFAAF, "M", "絛"), - (0xFAB0, "M", "練"), - (0xFAB1, "M", "缾"), - (0xFAB2, "M", "者"), - (0xFAB3, "M", "荒"), - (0xFAB4, "M", "華"), - (0xFAB5, "M", "蝹"), - (0xFAB6, "M", "襁"), - (0xFAB7, "M", "覆"), - (0xFAB8, "M", "視"), - (0xFAB9, "M", "調"), - ] - - -def _seg_44() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFABA, "M", "諸"), - (0xFABB, "M", "請"), - (0xFABC, "M", "謁"), - (0xFABD, "M", "諾"), - (0xFABE, "M", "諭"), - (0xFABF, "M", "謹"), - (0xFAC0, "M", "變"), - (0xFAC1, "M", "贈"), - (0xFAC2, "M", "輸"), - (0xFAC3, "M", "遲"), - (0xFAC4, "M", "醙"), - (0xFAC5, "M", "鉶"), - (0xFAC6, "M", "陼"), - (0xFAC7, "M", "難"), - (0xFAC8, "M", "靖"), - (0xFAC9, "M", "韛"), - (0xFACA, "M", "響"), - (0xFACB, "M", "頋"), - (0xFACC, "M", "頻"), - (0xFACD, "M", "鬒"), - (0xFACE, "M", "龜"), - (0xFACF, "M", "𢡊"), - (0xFAD0, "M", "𢡄"), - (0xFAD1, "M", "𣏕"), - (0xFAD2, "M", "㮝"), - (0xFAD3, "M", "䀘"), - (0xFAD4, "M", "䀹"), - (0xFAD5, "M", "𥉉"), - (0xFAD6, "M", "𥳐"), - (0xFAD7, "M", "𧻓"), - (0xFAD8, "M", "齃"), - (0xFAD9, "M", "龎"), - (0xFADA, "X"), - (0xFB00, "M", "ff"), - (0xFB01, "M", "fi"), - (0xFB02, "M", "fl"), - (0xFB03, "M", "ffi"), - (0xFB04, "M", "ffl"), - (0xFB05, "M", "st"), - (0xFB07, "X"), - (0xFB13, "M", "մն"), - (0xFB14, "M", "մե"), - (0xFB15, "M", "մի"), - (0xFB16, "M", "վն"), - (0xFB17, "M", "մխ"), - (0xFB18, "X"), - (0xFB1D, "M", "יִ"), - (0xFB1E, "V"), - (0xFB1F, "M", "ײַ"), - (0xFB20, "M", "ע"), - (0xFB21, "M", "א"), - (0xFB22, "M", "ד"), - (0xFB23, "M", "ה"), - (0xFB24, "M", "כ"), - (0xFB25, "M", "ל"), - (0xFB26, "M", "ם"), - (0xFB27, "M", "ר"), - (0xFB28, "M", "ת"), - (0xFB29, "M", "+"), - (0xFB2A, "M", "שׁ"), - (0xFB2B, "M", "שׂ"), - (0xFB2C, "M", "שּׁ"), - (0xFB2D, "M", "שּׂ"), - (0xFB2E, "M", "אַ"), - (0xFB2F, "M", "אָ"), - (0xFB30, "M", "אּ"), - (0xFB31, "M", "בּ"), - (0xFB32, "M", "גּ"), - (0xFB33, "M", "דּ"), - (0xFB34, "M", "הּ"), - (0xFB35, "M", "וּ"), - (0xFB36, "M", "זּ"), - (0xFB37, "X"), - (0xFB38, "M", "טּ"), - (0xFB39, "M", "יּ"), - (0xFB3A, "M", "ךּ"), - (0xFB3B, "M", "כּ"), - (0xFB3C, "M", "לּ"), - (0xFB3D, "X"), - (0xFB3E, "M", "מּ"), - (0xFB3F, "X"), - (0xFB40, "M", "נּ"), - (0xFB41, "M", "סּ"), - (0xFB42, "X"), - (0xFB43, "M", "ףּ"), - (0xFB44, "M", "פּ"), - (0xFB45, "X"), - (0xFB46, "M", "צּ"), - (0xFB47, "M", "קּ"), - (0xFB48, "M", "רּ"), - (0xFB49, "M", "שּ"), - (0xFB4A, "M", "תּ"), - (0xFB4B, "M", "וֹ"), - (0xFB4C, "M", "בֿ"), - (0xFB4D, "M", "כֿ"), - (0xFB4E, "M", "פֿ"), - (0xFB4F, "M", "אל"), - (0xFB50, "M", "ٱ"), - (0xFB52, "M", "ٻ"), - (0xFB56, "M", "پ"), - ] - - -def _seg_45() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFB5A, "M", "ڀ"), - (0xFB5E, "M", "ٺ"), - (0xFB62, "M", "ٿ"), - (0xFB66, "M", "ٹ"), - (0xFB6A, "M", "ڤ"), - (0xFB6E, "M", "ڦ"), - (0xFB72, "M", "ڄ"), - (0xFB76, "M", "ڃ"), - (0xFB7A, "M", "چ"), - (0xFB7E, "M", "ڇ"), - (0xFB82, "M", "ڍ"), - (0xFB84, "M", "ڌ"), - (0xFB86, "M", "ڎ"), - (0xFB88, "M", "ڈ"), - (0xFB8A, "M", "ژ"), - (0xFB8C, "M", "ڑ"), - (0xFB8E, "M", "ک"), - (0xFB92, "M", "گ"), - (0xFB96, "M", "ڳ"), - (0xFB9A, "M", "ڱ"), - (0xFB9E, "M", "ں"), - (0xFBA0, "M", "ڻ"), - (0xFBA4, "M", "ۀ"), - (0xFBA6, "M", "ہ"), - (0xFBAA, "M", "ھ"), - (0xFBAE, "M", "ے"), - (0xFBB0, "M", "ۓ"), - (0xFBB2, "V"), - (0xFBC3, "X"), - (0xFBD3, "M", "ڭ"), - (0xFBD7, "M", "ۇ"), - (0xFBD9, "M", "ۆ"), - (0xFBDB, "M", "ۈ"), - (0xFBDD, "M", "ۇٴ"), - (0xFBDE, "M", "ۋ"), - (0xFBE0, "M", "ۅ"), - (0xFBE2, "M", "ۉ"), - (0xFBE4, "M", "ې"), - (0xFBE8, "M", "ى"), - (0xFBEA, "M", "ئا"), - (0xFBEC, "M", "ئە"), - (0xFBEE, "M", "ئو"), - (0xFBF0, "M", "ئۇ"), - (0xFBF2, "M", "ئۆ"), - (0xFBF4, "M", "ئۈ"), - (0xFBF6, "M", "ئې"), - (0xFBF9, "M", "ئى"), - (0xFBFC, "M", "ی"), - (0xFC00, "M", "ئج"), - (0xFC01, "M", "ئح"), - (0xFC02, "M", "ئم"), - (0xFC03, "M", "ئى"), - (0xFC04, "M", "ئي"), - (0xFC05, "M", "بج"), - (0xFC06, "M", "بح"), - (0xFC07, "M", "بخ"), - (0xFC08, "M", "بم"), - (0xFC09, "M", "بى"), - (0xFC0A, "M", "بي"), - (0xFC0B, "M", "تج"), - (0xFC0C, "M", "تح"), - (0xFC0D, "M", "تخ"), - (0xFC0E, "M", "تم"), - (0xFC0F, "M", "تى"), - (0xFC10, "M", "تي"), - (0xFC11, "M", "ثج"), - (0xFC12, "M", "ثم"), - (0xFC13, "M", "ثى"), - (0xFC14, "M", "ثي"), - (0xFC15, "M", "جح"), - (0xFC16, "M", "جم"), - (0xFC17, "M", "حج"), - (0xFC18, "M", "حم"), - (0xFC19, "M", "خج"), - (0xFC1A, "M", "خح"), - (0xFC1B, "M", "خم"), - (0xFC1C, "M", "سج"), - (0xFC1D, "M", "سح"), - (0xFC1E, "M", "سخ"), - (0xFC1F, "M", "سم"), - (0xFC20, "M", "صح"), - (0xFC21, "M", "صم"), - (0xFC22, "M", "ضج"), - (0xFC23, "M", "ضح"), - (0xFC24, "M", "ضخ"), - (0xFC25, "M", "ضم"), - (0xFC26, "M", "طح"), - (0xFC27, "M", "طم"), - (0xFC28, "M", "ظم"), - (0xFC29, "M", "عج"), - (0xFC2A, "M", "عم"), - (0xFC2B, "M", "غج"), - (0xFC2C, "M", "غم"), - (0xFC2D, "M", "فج"), - (0xFC2E, "M", "فح"), - (0xFC2F, "M", "فخ"), - (0xFC30, "M", "فم"), - (0xFC31, "M", "فى"), - (0xFC32, "M", "في"), - (0xFC33, "M", "قح"), - ] - - -def _seg_46() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFC34, "M", "قم"), - (0xFC35, "M", "قى"), - (0xFC36, "M", "قي"), - (0xFC37, "M", "كا"), - (0xFC38, "M", "كج"), - (0xFC39, "M", "كح"), - (0xFC3A, "M", "كخ"), - (0xFC3B, "M", "كل"), - (0xFC3C, "M", "كم"), - (0xFC3D, "M", "كى"), - (0xFC3E, "M", "كي"), - (0xFC3F, "M", "لج"), - (0xFC40, "M", "لح"), - (0xFC41, "M", "لخ"), - (0xFC42, "M", "لم"), - (0xFC43, "M", "لى"), - (0xFC44, "M", "لي"), - (0xFC45, "M", "مج"), - (0xFC46, "M", "مح"), - (0xFC47, "M", "مخ"), - (0xFC48, "M", "مم"), - (0xFC49, "M", "مى"), - (0xFC4A, "M", "مي"), - (0xFC4B, "M", "نج"), - (0xFC4C, "M", "نح"), - (0xFC4D, "M", "نخ"), - (0xFC4E, "M", "نم"), - (0xFC4F, "M", "نى"), - (0xFC50, "M", "ني"), - (0xFC51, "M", "هج"), - (0xFC52, "M", "هم"), - (0xFC53, "M", "هى"), - (0xFC54, "M", "هي"), - (0xFC55, "M", "يج"), - (0xFC56, "M", "يح"), - (0xFC57, "M", "يخ"), - (0xFC58, "M", "يم"), - (0xFC59, "M", "يى"), - (0xFC5A, "M", "يي"), - (0xFC5B, "M", "ذٰ"), - (0xFC5C, "M", "رٰ"), - (0xFC5D, "M", "ىٰ"), - (0xFC5E, "M", " ٌّ"), - (0xFC5F, "M", " ٍّ"), - (0xFC60, "M", " َّ"), - (0xFC61, "M", " ُّ"), - (0xFC62, "M", " ِّ"), - (0xFC63, "M", " ّٰ"), - (0xFC64, "M", "ئر"), - (0xFC65, "M", "ئز"), - (0xFC66, "M", "ئم"), - (0xFC67, "M", "ئن"), - (0xFC68, "M", "ئى"), - (0xFC69, "M", "ئي"), - (0xFC6A, "M", "بر"), - (0xFC6B, "M", "بز"), - (0xFC6C, "M", "بم"), - (0xFC6D, "M", "بن"), - (0xFC6E, "M", "بى"), - (0xFC6F, "M", "بي"), - (0xFC70, "M", "تر"), - (0xFC71, "M", "تز"), - (0xFC72, "M", "تم"), - (0xFC73, "M", "تن"), - (0xFC74, "M", "تى"), - (0xFC75, "M", "تي"), - (0xFC76, "M", "ثر"), - (0xFC77, "M", "ثز"), - (0xFC78, "M", "ثم"), - (0xFC79, "M", "ثن"), - (0xFC7A, "M", "ثى"), - (0xFC7B, "M", "ثي"), - (0xFC7C, "M", "فى"), - (0xFC7D, "M", "في"), - (0xFC7E, "M", "قى"), - (0xFC7F, "M", "قي"), - (0xFC80, "M", "كا"), - (0xFC81, "M", "كل"), - (0xFC82, "M", "كم"), - (0xFC83, "M", "كى"), - (0xFC84, "M", "كي"), - (0xFC85, "M", "لم"), - (0xFC86, "M", "لى"), - (0xFC87, "M", "لي"), - (0xFC88, "M", "ما"), - (0xFC89, "M", "مم"), - (0xFC8A, "M", "نر"), - (0xFC8B, "M", "نز"), - (0xFC8C, "M", "نم"), - (0xFC8D, "M", "نن"), - (0xFC8E, "M", "نى"), - (0xFC8F, "M", "ني"), - (0xFC90, "M", "ىٰ"), - (0xFC91, "M", "ير"), - (0xFC92, "M", "يز"), - (0xFC93, "M", "يم"), - (0xFC94, "M", "ين"), - (0xFC95, "M", "يى"), - (0xFC96, "M", "يي"), - (0xFC97, "M", "ئج"), - ] - - -def _seg_47() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFC98, "M", "ئح"), - (0xFC99, "M", "ئخ"), - (0xFC9A, "M", "ئم"), - (0xFC9B, "M", "ئه"), - (0xFC9C, "M", "بج"), - (0xFC9D, "M", "بح"), - (0xFC9E, "M", "بخ"), - (0xFC9F, "M", "بم"), - (0xFCA0, "M", "به"), - (0xFCA1, "M", "تج"), - (0xFCA2, "M", "تح"), - (0xFCA3, "M", "تخ"), - (0xFCA4, "M", "تم"), - (0xFCA5, "M", "ته"), - (0xFCA6, "M", "ثم"), - (0xFCA7, "M", "جح"), - (0xFCA8, "M", "جم"), - (0xFCA9, "M", "حج"), - (0xFCAA, "M", "حم"), - (0xFCAB, "M", "خج"), - (0xFCAC, "M", "خم"), - (0xFCAD, "M", "سج"), - (0xFCAE, "M", "سح"), - (0xFCAF, "M", "سخ"), - (0xFCB0, "M", "سم"), - (0xFCB1, "M", "صح"), - (0xFCB2, "M", "صخ"), - (0xFCB3, "M", "صم"), - (0xFCB4, "M", "ضج"), - (0xFCB5, "M", "ضح"), - (0xFCB6, "M", "ضخ"), - (0xFCB7, "M", "ضم"), - (0xFCB8, "M", "طح"), - (0xFCB9, "M", "ظم"), - (0xFCBA, "M", "عج"), - (0xFCBB, "M", "عم"), - (0xFCBC, "M", "غج"), - (0xFCBD, "M", "غم"), - (0xFCBE, "M", "فج"), - (0xFCBF, "M", "فح"), - (0xFCC0, "M", "فخ"), - (0xFCC1, "M", "فم"), - (0xFCC2, "M", "قح"), - (0xFCC3, "M", "قم"), - (0xFCC4, "M", "كج"), - (0xFCC5, "M", "كح"), - (0xFCC6, "M", "كخ"), - (0xFCC7, "M", "كل"), - (0xFCC8, "M", "كم"), - (0xFCC9, "M", "لج"), - (0xFCCA, "M", "لح"), - (0xFCCB, "M", "لخ"), - (0xFCCC, "M", "لم"), - (0xFCCD, "M", "له"), - (0xFCCE, "M", "مج"), - (0xFCCF, "M", "مح"), - (0xFCD0, "M", "مخ"), - (0xFCD1, "M", "مم"), - (0xFCD2, "M", "نج"), - (0xFCD3, "M", "نح"), - (0xFCD4, "M", "نخ"), - (0xFCD5, "M", "نم"), - (0xFCD6, "M", "نه"), - (0xFCD7, "M", "هج"), - (0xFCD8, "M", "هم"), - (0xFCD9, "M", "هٰ"), - (0xFCDA, "M", "يج"), - (0xFCDB, "M", "يح"), - (0xFCDC, "M", "يخ"), - (0xFCDD, "M", "يم"), - (0xFCDE, "M", "يه"), - (0xFCDF, "M", "ئم"), - (0xFCE0, "M", "ئه"), - (0xFCE1, "M", "بم"), - (0xFCE2, "M", "به"), - (0xFCE3, "M", "تم"), - (0xFCE4, "M", "ته"), - (0xFCE5, "M", "ثم"), - (0xFCE6, "M", "ثه"), - (0xFCE7, "M", "سم"), - (0xFCE8, "M", "سه"), - (0xFCE9, "M", "شم"), - (0xFCEA, "M", "شه"), - (0xFCEB, "M", "كل"), - (0xFCEC, "M", "كم"), - (0xFCED, "M", "لم"), - (0xFCEE, "M", "نم"), - (0xFCEF, "M", "نه"), - (0xFCF0, "M", "يم"), - (0xFCF1, "M", "يه"), - (0xFCF2, "M", "ـَّ"), - (0xFCF3, "M", "ـُّ"), - (0xFCF4, "M", "ـِّ"), - (0xFCF5, "M", "طى"), - (0xFCF6, "M", "طي"), - (0xFCF7, "M", "عى"), - (0xFCF8, "M", "عي"), - (0xFCF9, "M", "غى"), - (0xFCFA, "M", "غي"), - (0xFCFB, "M", "سى"), - ] - - -def _seg_48() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFCFC, "M", "سي"), - (0xFCFD, "M", "شى"), - (0xFCFE, "M", "شي"), - (0xFCFF, "M", "حى"), - (0xFD00, "M", "حي"), - (0xFD01, "M", "جى"), - (0xFD02, "M", "جي"), - (0xFD03, "M", "خى"), - (0xFD04, "M", "خي"), - (0xFD05, "M", "صى"), - (0xFD06, "M", "صي"), - (0xFD07, "M", "ضى"), - (0xFD08, "M", "ضي"), - (0xFD09, "M", "شج"), - (0xFD0A, "M", "شح"), - (0xFD0B, "M", "شخ"), - (0xFD0C, "M", "شم"), - (0xFD0D, "M", "شر"), - (0xFD0E, "M", "سر"), - (0xFD0F, "M", "صر"), - (0xFD10, "M", "ضر"), - (0xFD11, "M", "طى"), - (0xFD12, "M", "طي"), - (0xFD13, "M", "عى"), - (0xFD14, "M", "عي"), - (0xFD15, "M", "غى"), - (0xFD16, "M", "غي"), - (0xFD17, "M", "سى"), - (0xFD18, "M", "سي"), - (0xFD19, "M", "شى"), - (0xFD1A, "M", "شي"), - (0xFD1B, "M", "حى"), - (0xFD1C, "M", "حي"), - (0xFD1D, "M", "جى"), - (0xFD1E, "M", "جي"), - (0xFD1F, "M", "خى"), - (0xFD20, "M", "خي"), - (0xFD21, "M", "صى"), - (0xFD22, "M", "صي"), - (0xFD23, "M", "ضى"), - (0xFD24, "M", "ضي"), - (0xFD25, "M", "شج"), - (0xFD26, "M", "شح"), - (0xFD27, "M", "شخ"), - (0xFD28, "M", "شم"), - (0xFD29, "M", "شر"), - (0xFD2A, "M", "سر"), - (0xFD2B, "M", "صر"), - (0xFD2C, "M", "ضر"), - (0xFD2D, "M", "شج"), - (0xFD2E, "M", "شح"), - (0xFD2F, "M", "شخ"), - (0xFD30, "M", "شم"), - (0xFD31, "M", "سه"), - (0xFD32, "M", "شه"), - (0xFD33, "M", "طم"), - (0xFD34, "M", "سج"), - (0xFD35, "M", "سح"), - (0xFD36, "M", "سخ"), - (0xFD37, "M", "شج"), - (0xFD38, "M", "شح"), - (0xFD39, "M", "شخ"), - (0xFD3A, "M", "طم"), - (0xFD3B, "M", "ظم"), - (0xFD3C, "M", "اً"), - (0xFD3E, "V"), - (0xFD50, "M", "تجم"), - (0xFD51, "M", "تحج"), - (0xFD53, "M", "تحم"), - (0xFD54, "M", "تخم"), - (0xFD55, "M", "تمج"), - (0xFD56, "M", "تمح"), - (0xFD57, "M", "تمخ"), - (0xFD58, "M", "جمح"), - (0xFD5A, "M", "حمي"), - (0xFD5B, "M", "حمى"), - (0xFD5C, "M", "سحج"), - (0xFD5D, "M", "سجح"), - (0xFD5E, "M", "سجى"), - (0xFD5F, "M", "سمح"), - (0xFD61, "M", "سمج"), - (0xFD62, "M", "سمم"), - (0xFD64, "M", "صحح"), - (0xFD66, "M", "صمم"), - (0xFD67, "M", "شحم"), - (0xFD69, "M", "شجي"), - (0xFD6A, "M", "شمخ"), - (0xFD6C, "M", "شمم"), - (0xFD6E, "M", "ضحى"), - (0xFD6F, "M", "ضخم"), - (0xFD71, "M", "طمح"), - (0xFD73, "M", "طمم"), - (0xFD74, "M", "طمي"), - (0xFD75, "M", "عجم"), - (0xFD76, "M", "عمم"), - (0xFD78, "M", "عمى"), - (0xFD79, "M", "غمم"), - (0xFD7A, "M", "غمي"), - (0xFD7B, "M", "غمى"), - (0xFD7C, "M", "فخم"), - ] - - -def _seg_49() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFD7E, "M", "قمح"), - (0xFD7F, "M", "قمم"), - (0xFD80, "M", "لحم"), - (0xFD81, "M", "لحي"), - (0xFD82, "M", "لحى"), - (0xFD83, "M", "لجج"), - (0xFD85, "M", "لخم"), - (0xFD87, "M", "لمح"), - (0xFD89, "M", "محج"), - (0xFD8A, "M", "محم"), - (0xFD8B, "M", "محي"), - (0xFD8C, "M", "مجح"), - (0xFD8D, "M", "مجم"), - (0xFD8E, "M", "مخج"), - (0xFD8F, "M", "مخم"), - (0xFD90, "X"), - (0xFD92, "M", "مجخ"), - (0xFD93, "M", "همج"), - (0xFD94, "M", "همم"), - (0xFD95, "M", "نحم"), - (0xFD96, "M", "نحى"), - (0xFD97, "M", "نجم"), - (0xFD99, "M", "نجى"), - (0xFD9A, "M", "نمي"), - (0xFD9B, "M", "نمى"), - (0xFD9C, "M", "يمم"), - (0xFD9E, "M", "بخي"), - (0xFD9F, "M", "تجي"), - (0xFDA0, "M", "تجى"), - (0xFDA1, "M", "تخي"), - (0xFDA2, "M", "تخى"), - (0xFDA3, "M", "تمي"), - (0xFDA4, "M", "تمى"), - (0xFDA5, "M", "جمي"), - (0xFDA6, "M", "جحى"), - (0xFDA7, "M", "جمى"), - (0xFDA8, "M", "سخى"), - (0xFDA9, "M", "صحي"), - (0xFDAA, "M", "شحي"), - (0xFDAB, "M", "ضحي"), - (0xFDAC, "M", "لجي"), - (0xFDAD, "M", "لمي"), - (0xFDAE, "M", "يحي"), - (0xFDAF, "M", "يجي"), - (0xFDB0, "M", "يمي"), - (0xFDB1, "M", "ممي"), - (0xFDB2, "M", "قمي"), - (0xFDB3, "M", "نحي"), - (0xFDB4, "M", "قمح"), - (0xFDB5, "M", "لحم"), - (0xFDB6, "M", "عمي"), - (0xFDB7, "M", "كمي"), - (0xFDB8, "M", "نجح"), - (0xFDB9, "M", "مخي"), - (0xFDBA, "M", "لجم"), - (0xFDBB, "M", "كمم"), - (0xFDBC, "M", "لجم"), - (0xFDBD, "M", "نجح"), - (0xFDBE, "M", "جحي"), - (0xFDBF, "M", "حجي"), - (0xFDC0, "M", "مجي"), - (0xFDC1, "M", "فمي"), - (0xFDC2, "M", "بحي"), - (0xFDC3, "M", "كمم"), - (0xFDC4, "M", "عجم"), - (0xFDC5, "M", "صمم"), - (0xFDC6, "M", "سخي"), - (0xFDC7, "M", "نجي"), - (0xFDC8, "X"), - (0xFDCF, "V"), - (0xFDD0, "X"), - (0xFDF0, "M", "صلے"), - (0xFDF1, "M", "قلے"), - (0xFDF2, "M", "الله"), - (0xFDF3, "M", "اكبر"), - (0xFDF4, "M", "محمد"), - (0xFDF5, "M", "صلعم"), - (0xFDF6, "M", "رسول"), - (0xFDF7, "M", "عليه"), - (0xFDF8, "M", "وسلم"), - (0xFDF9, "M", "صلى"), - (0xFDFA, "M", "صلى الله عليه وسلم"), - (0xFDFB, "M", "جل جلاله"), - (0xFDFC, "M", "ریال"), - (0xFDFD, "V"), - (0xFE00, "I"), - (0xFE10, "M", ","), - (0xFE11, "M", "、"), - (0xFE12, "X"), - (0xFE13, "M", ":"), - (0xFE14, "M", ";"), - (0xFE15, "M", "!"), - (0xFE16, "M", "?"), - (0xFE17, "M", "〖"), - (0xFE18, "M", "〗"), - (0xFE19, "X"), - (0xFE20, "V"), - (0xFE30, "X"), - (0xFE31, "M", "—"), - (0xFE32, "M", "–"), - ] - - -def _seg_50() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFE33, "M", "_"), - (0xFE35, "M", "("), - (0xFE36, "M", ")"), - (0xFE37, "M", "{"), - (0xFE38, "M", "}"), - (0xFE39, "M", "〔"), - (0xFE3A, "M", "〕"), - (0xFE3B, "M", "【"), - (0xFE3C, "M", "】"), - (0xFE3D, "M", "《"), - (0xFE3E, "M", "》"), - (0xFE3F, "M", "〈"), - (0xFE40, "M", "〉"), - (0xFE41, "M", "「"), - (0xFE42, "M", "」"), - (0xFE43, "M", "『"), - (0xFE44, "M", "』"), - (0xFE45, "V"), - (0xFE47, "M", "["), - (0xFE48, "M", "]"), - (0xFE49, "M", " ̅"), - (0xFE4D, "M", "_"), - (0xFE50, "M", ","), - (0xFE51, "M", "、"), - (0xFE52, "X"), - (0xFE54, "M", ";"), - (0xFE55, "M", ":"), - (0xFE56, "M", "?"), - (0xFE57, "M", "!"), - (0xFE58, "M", "—"), - (0xFE59, "M", "("), - (0xFE5A, "M", ")"), - (0xFE5B, "M", "{"), - (0xFE5C, "M", "}"), - (0xFE5D, "M", "〔"), - (0xFE5E, "M", "〕"), - (0xFE5F, "M", "#"), - (0xFE60, "M", "&"), - (0xFE61, "M", "*"), - (0xFE62, "M", "+"), - (0xFE63, "M", "-"), - (0xFE64, "M", "<"), - (0xFE65, "M", ">"), - (0xFE66, "M", "="), - (0xFE67, "X"), - (0xFE68, "M", "\\"), - (0xFE69, "M", "$"), - (0xFE6A, "M", "%"), - (0xFE6B, "M", "@"), - (0xFE6C, "X"), - (0xFE70, "M", " ً"), - (0xFE71, "M", "ـً"), - (0xFE72, "M", " ٌ"), - (0xFE73, "V"), - (0xFE74, "M", " ٍ"), - (0xFE75, "X"), - (0xFE76, "M", " َ"), - (0xFE77, "M", "ـَ"), - (0xFE78, "M", " ُ"), - (0xFE79, "M", "ـُ"), - (0xFE7A, "M", " ِ"), - (0xFE7B, "M", "ـِ"), - (0xFE7C, "M", " ّ"), - (0xFE7D, "M", "ـّ"), - (0xFE7E, "M", " ْ"), - (0xFE7F, "M", "ـْ"), - (0xFE80, "M", "ء"), - (0xFE81, "M", "آ"), - (0xFE83, "M", "أ"), - (0xFE85, "M", "ؤ"), - (0xFE87, "M", "إ"), - (0xFE89, "M", "ئ"), - (0xFE8D, "M", "ا"), - (0xFE8F, "M", "ب"), - (0xFE93, "M", "ة"), - (0xFE95, "M", "ت"), - (0xFE99, "M", "ث"), - (0xFE9D, "M", "ج"), - (0xFEA1, "M", "ح"), - (0xFEA5, "M", "خ"), - (0xFEA9, "M", "د"), - (0xFEAB, "M", "ذ"), - (0xFEAD, "M", "ر"), - (0xFEAF, "M", "ز"), - (0xFEB1, "M", "س"), - (0xFEB5, "M", "ش"), - (0xFEB9, "M", "ص"), - (0xFEBD, "M", "ض"), - (0xFEC1, "M", "ط"), - (0xFEC5, "M", "ظ"), - (0xFEC9, "M", "ع"), - (0xFECD, "M", "غ"), - (0xFED1, "M", "ف"), - (0xFED5, "M", "ق"), - (0xFED9, "M", "ك"), - (0xFEDD, "M", "ل"), - (0xFEE1, "M", "م"), - (0xFEE5, "M", "ن"), - (0xFEE9, "M", "ه"), - (0xFEED, "M", "و"), - ] - - -def _seg_51() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFEEF, "M", "ى"), - (0xFEF1, "M", "ي"), - (0xFEF5, "M", "لآ"), - (0xFEF7, "M", "لأ"), - (0xFEF9, "M", "لإ"), - (0xFEFB, "M", "لا"), - (0xFEFD, "X"), - (0xFEFF, "I"), - (0xFF00, "X"), - (0xFF01, "M", "!"), - (0xFF02, "M", '"'), - (0xFF03, "M", "#"), - (0xFF04, "M", "$"), - (0xFF05, "M", "%"), - (0xFF06, "M", "&"), - (0xFF07, "M", "'"), - (0xFF08, "M", "("), - (0xFF09, "M", ")"), - (0xFF0A, "M", "*"), - (0xFF0B, "M", "+"), - (0xFF0C, "M", ","), - (0xFF0D, "M", "-"), - (0xFF0E, "M", "."), - (0xFF0F, "M", "/"), - (0xFF10, "M", "0"), - (0xFF11, "M", "1"), - (0xFF12, "M", "2"), - (0xFF13, "M", "3"), - (0xFF14, "M", "4"), - (0xFF15, "M", "5"), - (0xFF16, "M", "6"), - (0xFF17, "M", "7"), - (0xFF18, "M", "8"), - (0xFF19, "M", "9"), - (0xFF1A, "M", ":"), - (0xFF1B, "M", ";"), - (0xFF1C, "M", "<"), - (0xFF1D, "M", "="), - (0xFF1E, "M", ">"), - (0xFF1F, "M", "?"), - (0xFF20, "M", "@"), - (0xFF21, "M", "a"), - (0xFF22, "M", "b"), - (0xFF23, "M", "c"), - (0xFF24, "M", "d"), - (0xFF25, "M", "e"), - (0xFF26, "M", "f"), - (0xFF27, "M", "g"), - (0xFF28, "M", "h"), - (0xFF29, "M", "i"), - (0xFF2A, "M", "j"), - (0xFF2B, "M", "k"), - (0xFF2C, "M", "l"), - (0xFF2D, "M", "m"), - (0xFF2E, "M", "n"), - (0xFF2F, "M", "o"), - (0xFF30, "M", "p"), - (0xFF31, "M", "q"), - (0xFF32, "M", "r"), - (0xFF33, "M", "s"), - (0xFF34, "M", "t"), - (0xFF35, "M", "u"), - (0xFF36, "M", "v"), - (0xFF37, "M", "w"), - (0xFF38, "M", "x"), - (0xFF39, "M", "y"), - (0xFF3A, "M", "z"), - (0xFF3B, "M", "["), - (0xFF3C, "M", "\\"), - (0xFF3D, "M", "]"), - (0xFF3E, "M", "^"), - (0xFF3F, "M", "_"), - (0xFF40, "M", "`"), - (0xFF41, "M", "a"), - (0xFF42, "M", "b"), - (0xFF43, "M", "c"), - (0xFF44, "M", "d"), - (0xFF45, "M", "e"), - (0xFF46, "M", "f"), - (0xFF47, "M", "g"), - (0xFF48, "M", "h"), - (0xFF49, "M", "i"), - (0xFF4A, "M", "j"), - (0xFF4B, "M", "k"), - (0xFF4C, "M", "l"), - (0xFF4D, "M", "m"), - (0xFF4E, "M", "n"), - (0xFF4F, "M", "o"), - (0xFF50, "M", "p"), - (0xFF51, "M", "q"), - (0xFF52, "M", "r"), - (0xFF53, "M", "s"), - (0xFF54, "M", "t"), - (0xFF55, "M", "u"), - (0xFF56, "M", "v"), - (0xFF57, "M", "w"), - (0xFF58, "M", "x"), - (0xFF59, "M", "y"), - (0xFF5A, "M", "z"), - (0xFF5B, "M", "{"), - ] - - -def _seg_52() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFF5C, "M", "|"), - (0xFF5D, "M", "}"), - (0xFF5E, "M", "~"), - (0xFF5F, "M", "⦅"), - (0xFF60, "M", "⦆"), - (0xFF61, "M", "."), - (0xFF62, "M", "「"), - (0xFF63, "M", "」"), - (0xFF64, "M", "、"), - (0xFF65, "M", "・"), - (0xFF66, "M", "ヲ"), - (0xFF67, "M", "ァ"), - (0xFF68, "M", "ィ"), - (0xFF69, "M", "ゥ"), - (0xFF6A, "M", "ェ"), - (0xFF6B, "M", "ォ"), - (0xFF6C, "M", "ャ"), - (0xFF6D, "M", "ュ"), - (0xFF6E, "M", "ョ"), - (0xFF6F, "M", "ッ"), - (0xFF70, "M", "ー"), - (0xFF71, "M", "ア"), - (0xFF72, "M", "イ"), - (0xFF73, "M", "ウ"), - (0xFF74, "M", "エ"), - (0xFF75, "M", "オ"), - (0xFF76, "M", "カ"), - (0xFF77, "M", "キ"), - (0xFF78, "M", "ク"), - (0xFF79, "M", "ケ"), - (0xFF7A, "M", "コ"), - (0xFF7B, "M", "サ"), - (0xFF7C, "M", "シ"), - (0xFF7D, "M", "ス"), - (0xFF7E, "M", "セ"), - (0xFF7F, "M", "ソ"), - (0xFF80, "M", "タ"), - (0xFF81, "M", "チ"), - (0xFF82, "M", "ツ"), - (0xFF83, "M", "テ"), - (0xFF84, "M", "ト"), - (0xFF85, "M", "ナ"), - (0xFF86, "M", "ニ"), - (0xFF87, "M", "ヌ"), - (0xFF88, "M", "ネ"), - (0xFF89, "M", "ノ"), - (0xFF8A, "M", "ハ"), - (0xFF8B, "M", "ヒ"), - (0xFF8C, "M", "フ"), - (0xFF8D, "M", "ヘ"), - (0xFF8E, "M", "ホ"), - (0xFF8F, "M", "マ"), - (0xFF90, "M", "ミ"), - (0xFF91, "M", "ム"), - (0xFF92, "M", "メ"), - (0xFF93, "M", "モ"), - (0xFF94, "M", "ヤ"), - (0xFF95, "M", "ユ"), - (0xFF96, "M", "ヨ"), - (0xFF97, "M", "ラ"), - (0xFF98, "M", "リ"), - (0xFF99, "M", "ル"), - (0xFF9A, "M", "レ"), - (0xFF9B, "M", "ロ"), - (0xFF9C, "M", "ワ"), - (0xFF9D, "M", "ン"), - (0xFF9E, "M", "゙"), - (0xFF9F, "M", "゚"), - (0xFFA0, "I"), - (0xFFA1, "M", "ᄀ"), - (0xFFA2, "M", "ᄁ"), - (0xFFA3, "M", "ᆪ"), - (0xFFA4, "M", "ᄂ"), - (0xFFA5, "M", "ᆬ"), - (0xFFA6, "M", "ᆭ"), - (0xFFA7, "M", "ᄃ"), - (0xFFA8, "M", "ᄄ"), - (0xFFA9, "M", "ᄅ"), - (0xFFAA, "M", "ᆰ"), - (0xFFAB, "M", "ᆱ"), - (0xFFAC, "M", "ᆲ"), - (0xFFAD, "M", "ᆳ"), - (0xFFAE, "M", "ᆴ"), - (0xFFAF, "M", "ᆵ"), - (0xFFB0, "M", "ᄚ"), - (0xFFB1, "M", "ᄆ"), - (0xFFB2, "M", "ᄇ"), - (0xFFB3, "M", "ᄈ"), - (0xFFB4, "M", "ᄡ"), - (0xFFB5, "M", "ᄉ"), - (0xFFB6, "M", "ᄊ"), - (0xFFB7, "M", "ᄋ"), - (0xFFB8, "M", "ᄌ"), - (0xFFB9, "M", "ᄍ"), - (0xFFBA, "M", "ᄎ"), - (0xFFBB, "M", "ᄏ"), - (0xFFBC, "M", "ᄐ"), - (0xFFBD, "M", "ᄑ"), - (0xFFBE, "M", "ᄒ"), - (0xFFBF, "X"), - ] - - -def _seg_53() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0xFFC2, "M", "ᅡ"), - (0xFFC3, "M", "ᅢ"), - (0xFFC4, "M", "ᅣ"), - (0xFFC5, "M", "ᅤ"), - (0xFFC6, "M", "ᅥ"), - (0xFFC7, "M", "ᅦ"), - (0xFFC8, "X"), - (0xFFCA, "M", "ᅧ"), - (0xFFCB, "M", "ᅨ"), - (0xFFCC, "M", "ᅩ"), - (0xFFCD, "M", "ᅪ"), - (0xFFCE, "M", "ᅫ"), - (0xFFCF, "M", "ᅬ"), - (0xFFD0, "X"), - (0xFFD2, "M", "ᅭ"), - (0xFFD3, "M", "ᅮ"), - (0xFFD4, "M", "ᅯ"), - (0xFFD5, "M", "ᅰ"), - (0xFFD6, "M", "ᅱ"), - (0xFFD7, "M", "ᅲ"), - (0xFFD8, "X"), - (0xFFDA, "M", "ᅳ"), - (0xFFDB, "M", "ᅴ"), - (0xFFDC, "M", "ᅵ"), - (0xFFDD, "X"), - (0xFFE0, "M", "¢"), - (0xFFE1, "M", "£"), - (0xFFE2, "M", "¬"), - (0xFFE3, "M", " ̄"), - (0xFFE4, "M", "¦"), - (0xFFE5, "M", "¥"), - (0xFFE6, "M", "₩"), - (0xFFE7, "X"), - (0xFFE8, "M", "│"), - (0xFFE9, "M", "←"), - (0xFFEA, "M", "↑"), - (0xFFEB, "M", "→"), - (0xFFEC, "M", "↓"), - (0xFFED, "M", "■"), - (0xFFEE, "M", "○"), - (0xFFEF, "X"), - (0x10000, "V"), - (0x1000C, "X"), - (0x1000D, "V"), - (0x10027, "X"), - (0x10028, "V"), - (0x1003B, "X"), - (0x1003C, "V"), - (0x1003E, "X"), - (0x1003F, "V"), - (0x1004E, "X"), - (0x10050, "V"), - (0x1005E, "X"), - (0x10080, "V"), - (0x100FB, "X"), - (0x10100, "V"), - (0x10103, "X"), - (0x10107, "V"), - (0x10134, "X"), - (0x10137, "V"), - (0x1018F, "X"), - (0x10190, "V"), - (0x1019D, "X"), - (0x101A0, "V"), - (0x101A1, "X"), - (0x101D0, "V"), - (0x101FE, "X"), - (0x10280, "V"), - (0x1029D, "X"), - (0x102A0, "V"), - (0x102D1, "X"), - (0x102E0, "V"), - (0x102FC, "X"), - (0x10300, "V"), - (0x10324, "X"), - (0x1032D, "V"), - (0x1034B, "X"), - (0x10350, "V"), - (0x1037B, "X"), - (0x10380, "V"), - (0x1039E, "X"), - (0x1039F, "V"), - (0x103C4, "X"), - (0x103C8, "V"), - (0x103D6, "X"), - (0x10400, "M", "𐐨"), - (0x10401, "M", "𐐩"), - (0x10402, "M", "𐐪"), - (0x10403, "M", "𐐫"), - (0x10404, "M", "𐐬"), - (0x10405, "M", "𐐭"), - (0x10406, "M", "𐐮"), - (0x10407, "M", "𐐯"), - (0x10408, "M", "𐐰"), - (0x10409, "M", "𐐱"), - (0x1040A, "M", "𐐲"), - (0x1040B, "M", "𐐳"), - (0x1040C, "M", "𐐴"), - (0x1040D, "M", "𐐵"), - (0x1040E, "M", "𐐶"), - ] - - -def _seg_54() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1040F, "M", "𐐷"), - (0x10410, "M", "𐐸"), - (0x10411, "M", "𐐹"), - (0x10412, "M", "𐐺"), - (0x10413, "M", "𐐻"), - (0x10414, "M", "𐐼"), - (0x10415, "M", "𐐽"), - (0x10416, "M", "𐐾"), - (0x10417, "M", "𐐿"), - (0x10418, "M", "𐑀"), - (0x10419, "M", "𐑁"), - (0x1041A, "M", "𐑂"), - (0x1041B, "M", "𐑃"), - (0x1041C, "M", "𐑄"), - (0x1041D, "M", "𐑅"), - (0x1041E, "M", "𐑆"), - (0x1041F, "M", "𐑇"), - (0x10420, "M", "𐑈"), - (0x10421, "M", "𐑉"), - (0x10422, "M", "𐑊"), - (0x10423, "M", "𐑋"), - (0x10424, "M", "𐑌"), - (0x10425, "M", "𐑍"), - (0x10426, "M", "𐑎"), - (0x10427, "M", "𐑏"), - (0x10428, "V"), - (0x1049E, "X"), - (0x104A0, "V"), - (0x104AA, "X"), - (0x104B0, "M", "𐓘"), - (0x104B1, "M", "𐓙"), - (0x104B2, "M", "𐓚"), - (0x104B3, "M", "𐓛"), - (0x104B4, "M", "𐓜"), - (0x104B5, "M", "𐓝"), - (0x104B6, "M", "𐓞"), - (0x104B7, "M", "𐓟"), - (0x104B8, "M", "𐓠"), - (0x104B9, "M", "𐓡"), - (0x104BA, "M", "𐓢"), - (0x104BB, "M", "𐓣"), - (0x104BC, "M", "𐓤"), - (0x104BD, "M", "𐓥"), - (0x104BE, "M", "𐓦"), - (0x104BF, "M", "𐓧"), - (0x104C0, "M", "𐓨"), - (0x104C1, "M", "𐓩"), - (0x104C2, "M", "𐓪"), - (0x104C3, "M", "𐓫"), - (0x104C4, "M", "𐓬"), - (0x104C5, "M", "𐓭"), - (0x104C6, "M", "𐓮"), - (0x104C7, "M", "𐓯"), - (0x104C8, "M", "𐓰"), - (0x104C9, "M", "𐓱"), - (0x104CA, "M", "𐓲"), - (0x104CB, "M", "𐓳"), - (0x104CC, "M", "𐓴"), - (0x104CD, "M", "𐓵"), - (0x104CE, "M", "𐓶"), - (0x104CF, "M", "𐓷"), - (0x104D0, "M", "𐓸"), - (0x104D1, "M", "𐓹"), - (0x104D2, "M", "𐓺"), - (0x104D3, "M", "𐓻"), - (0x104D4, "X"), - (0x104D8, "V"), - (0x104FC, "X"), - (0x10500, "V"), - (0x10528, "X"), - (0x10530, "V"), - (0x10564, "X"), - (0x1056F, "V"), - (0x10570, "M", "𐖗"), - (0x10571, "M", "𐖘"), - (0x10572, "M", "𐖙"), - (0x10573, "M", "𐖚"), - (0x10574, "M", "𐖛"), - (0x10575, "M", "𐖜"), - (0x10576, "M", "𐖝"), - (0x10577, "M", "𐖞"), - (0x10578, "M", "𐖟"), - (0x10579, "M", "𐖠"), - (0x1057A, "M", "𐖡"), - (0x1057B, "X"), - (0x1057C, "M", "𐖣"), - (0x1057D, "M", "𐖤"), - (0x1057E, "M", "𐖥"), - (0x1057F, "M", "𐖦"), - (0x10580, "M", "𐖧"), - (0x10581, "M", "𐖨"), - (0x10582, "M", "𐖩"), - (0x10583, "M", "𐖪"), - (0x10584, "M", "𐖫"), - (0x10585, "M", "𐖬"), - (0x10586, "M", "𐖭"), - (0x10587, "M", "𐖮"), - (0x10588, "M", "𐖯"), - (0x10589, "M", "𐖰"), - (0x1058A, "M", "𐖱"), - ] - - -def _seg_55() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1058B, "X"), - (0x1058C, "M", "𐖳"), - (0x1058D, "M", "𐖴"), - (0x1058E, "M", "𐖵"), - (0x1058F, "M", "𐖶"), - (0x10590, "M", "𐖷"), - (0x10591, "M", "𐖸"), - (0x10592, "M", "𐖹"), - (0x10593, "X"), - (0x10594, "M", "𐖻"), - (0x10595, "M", "𐖼"), - (0x10596, "X"), - (0x10597, "V"), - (0x105A2, "X"), - (0x105A3, "V"), - (0x105B2, "X"), - (0x105B3, "V"), - (0x105BA, "X"), - (0x105BB, "V"), - (0x105BD, "X"), - (0x105C0, "V"), - (0x105F4, "X"), - (0x10600, "V"), - (0x10737, "X"), - (0x10740, "V"), - (0x10756, "X"), - (0x10760, "V"), - (0x10768, "X"), - (0x10780, "V"), - (0x10781, "M", "ː"), - (0x10782, "M", "ˑ"), - (0x10783, "M", "æ"), - (0x10784, "M", "ʙ"), - (0x10785, "M", "ɓ"), - (0x10786, "X"), - (0x10787, "M", "ʣ"), - (0x10788, "M", "ꭦ"), - (0x10789, "M", "ʥ"), - (0x1078A, "M", "ʤ"), - (0x1078B, "M", "ɖ"), - (0x1078C, "M", "ɗ"), - (0x1078D, "M", "ᶑ"), - (0x1078E, "M", "ɘ"), - (0x1078F, "M", "ɞ"), - (0x10790, "M", "ʩ"), - (0x10791, "M", "ɤ"), - (0x10792, "M", "ɢ"), - (0x10793, "M", "ɠ"), - (0x10794, "M", "ʛ"), - (0x10795, "M", "ħ"), - (0x10796, "M", "ʜ"), - (0x10797, "M", "ɧ"), - (0x10798, "M", "ʄ"), - (0x10799, "M", "ʪ"), - (0x1079A, "M", "ʫ"), - (0x1079B, "M", "ɬ"), - (0x1079C, "M", "𝼄"), - (0x1079D, "M", "ꞎ"), - (0x1079E, "M", "ɮ"), - (0x1079F, "M", "𝼅"), - (0x107A0, "M", "ʎ"), - (0x107A1, "M", "𝼆"), - (0x107A2, "M", "ø"), - (0x107A3, "M", "ɶ"), - (0x107A4, "M", "ɷ"), - (0x107A5, "M", "q"), - (0x107A6, "M", "ɺ"), - (0x107A7, "M", "𝼈"), - (0x107A8, "M", "ɽ"), - (0x107A9, "M", "ɾ"), - (0x107AA, "M", "ʀ"), - (0x107AB, "M", "ʨ"), - (0x107AC, "M", "ʦ"), - (0x107AD, "M", "ꭧ"), - (0x107AE, "M", "ʧ"), - (0x107AF, "M", "ʈ"), - (0x107B0, "M", "ⱱ"), - (0x107B1, "X"), - (0x107B2, "M", "ʏ"), - (0x107B3, "M", "ʡ"), - (0x107B4, "M", "ʢ"), - (0x107B5, "M", "ʘ"), - (0x107B6, "M", "ǀ"), - (0x107B7, "M", "ǁ"), - (0x107B8, "M", "ǂ"), - (0x107B9, "M", "𝼊"), - (0x107BA, "M", "𝼞"), - (0x107BB, "X"), - (0x10800, "V"), - (0x10806, "X"), - (0x10808, "V"), - (0x10809, "X"), - (0x1080A, "V"), - (0x10836, "X"), - (0x10837, "V"), - (0x10839, "X"), - (0x1083C, "V"), - (0x1083D, "X"), - (0x1083F, "V"), - (0x10856, "X"), - ] - - -def _seg_56() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x10857, "V"), - (0x1089F, "X"), - (0x108A7, "V"), - (0x108B0, "X"), - (0x108E0, "V"), - (0x108F3, "X"), - (0x108F4, "V"), - (0x108F6, "X"), - (0x108FB, "V"), - (0x1091C, "X"), - (0x1091F, "V"), - (0x1093A, "X"), - (0x1093F, "V"), - (0x10940, "X"), - (0x10980, "V"), - (0x109B8, "X"), - (0x109BC, "V"), - (0x109D0, "X"), - (0x109D2, "V"), - (0x10A04, "X"), - (0x10A05, "V"), - (0x10A07, "X"), - (0x10A0C, "V"), - (0x10A14, "X"), - (0x10A15, "V"), - (0x10A18, "X"), - (0x10A19, "V"), - (0x10A36, "X"), - (0x10A38, "V"), - (0x10A3B, "X"), - (0x10A3F, "V"), - (0x10A49, "X"), - (0x10A50, "V"), - (0x10A59, "X"), - (0x10A60, "V"), - (0x10AA0, "X"), - (0x10AC0, "V"), - (0x10AE7, "X"), - (0x10AEB, "V"), - (0x10AF7, "X"), - (0x10B00, "V"), - (0x10B36, "X"), - (0x10B39, "V"), - (0x10B56, "X"), - (0x10B58, "V"), - (0x10B73, "X"), - (0x10B78, "V"), - (0x10B92, "X"), - (0x10B99, "V"), - (0x10B9D, "X"), - (0x10BA9, "V"), - (0x10BB0, "X"), - (0x10C00, "V"), - (0x10C49, "X"), - (0x10C80, "M", "𐳀"), - (0x10C81, "M", "𐳁"), - (0x10C82, "M", "𐳂"), - (0x10C83, "M", "𐳃"), - (0x10C84, "M", "𐳄"), - (0x10C85, "M", "𐳅"), - (0x10C86, "M", "𐳆"), - (0x10C87, "M", "𐳇"), - (0x10C88, "M", "𐳈"), - (0x10C89, "M", "𐳉"), - (0x10C8A, "M", "𐳊"), - (0x10C8B, "M", "𐳋"), - (0x10C8C, "M", "𐳌"), - (0x10C8D, "M", "𐳍"), - (0x10C8E, "M", "𐳎"), - (0x10C8F, "M", "𐳏"), - (0x10C90, "M", "𐳐"), - (0x10C91, "M", "𐳑"), - (0x10C92, "M", "𐳒"), - (0x10C93, "M", "𐳓"), - (0x10C94, "M", "𐳔"), - (0x10C95, "M", "𐳕"), - (0x10C96, "M", "𐳖"), - (0x10C97, "M", "𐳗"), - (0x10C98, "M", "𐳘"), - (0x10C99, "M", "𐳙"), - (0x10C9A, "M", "𐳚"), - (0x10C9B, "M", "𐳛"), - (0x10C9C, "M", "𐳜"), - (0x10C9D, "M", "𐳝"), - (0x10C9E, "M", "𐳞"), - (0x10C9F, "M", "𐳟"), - (0x10CA0, "M", "𐳠"), - (0x10CA1, "M", "𐳡"), - (0x10CA2, "M", "𐳢"), - (0x10CA3, "M", "𐳣"), - (0x10CA4, "M", "𐳤"), - (0x10CA5, "M", "𐳥"), - (0x10CA6, "M", "𐳦"), - (0x10CA7, "M", "𐳧"), - (0x10CA8, "M", "𐳨"), - (0x10CA9, "M", "𐳩"), - (0x10CAA, "M", "𐳪"), - (0x10CAB, "M", "𐳫"), - (0x10CAC, "M", "𐳬"), - (0x10CAD, "M", "𐳭"), - ] - - -def _seg_57() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x10CAE, "M", "𐳮"), - (0x10CAF, "M", "𐳯"), - (0x10CB0, "M", "𐳰"), - (0x10CB1, "M", "𐳱"), - (0x10CB2, "M", "𐳲"), - (0x10CB3, "X"), - (0x10CC0, "V"), - (0x10CF3, "X"), - (0x10CFA, "V"), - (0x10D28, "X"), - (0x10D30, "V"), - (0x10D3A, "X"), - (0x10D40, "V"), - (0x10D50, "M", "𐵰"), - (0x10D51, "M", "𐵱"), - (0x10D52, "M", "𐵲"), - (0x10D53, "M", "𐵳"), - (0x10D54, "M", "𐵴"), - (0x10D55, "M", "𐵵"), - (0x10D56, "M", "𐵶"), - (0x10D57, "M", "𐵷"), - (0x10D58, "M", "𐵸"), - (0x10D59, "M", "𐵹"), - (0x10D5A, "M", "𐵺"), - (0x10D5B, "M", "𐵻"), - (0x10D5C, "M", "𐵼"), - (0x10D5D, "M", "𐵽"), - (0x10D5E, "M", "𐵾"), - (0x10D5F, "M", "𐵿"), - (0x10D60, "M", "𐶀"), - (0x10D61, "M", "𐶁"), - (0x10D62, "M", "𐶂"), - (0x10D63, "M", "𐶃"), - (0x10D64, "M", "𐶄"), - (0x10D65, "M", "𐶅"), - (0x10D66, "X"), - (0x10D69, "V"), - (0x10D86, "X"), - (0x10D8E, "V"), - (0x10D90, "X"), - (0x10E60, "V"), - (0x10E7F, "X"), - (0x10E80, "V"), - (0x10EAA, "X"), - (0x10EAB, "V"), - (0x10EAE, "X"), - (0x10EB0, "V"), - (0x10EB2, "X"), - (0x10EC2, "V"), - (0x10EC5, "X"), - (0x10EFC, "V"), - (0x10F28, "X"), - (0x10F30, "V"), - (0x10F5A, "X"), - (0x10F70, "V"), - (0x10F8A, "X"), - (0x10FB0, "V"), - (0x10FCC, "X"), - (0x10FE0, "V"), - (0x10FF7, "X"), - (0x11000, "V"), - (0x1104E, "X"), - (0x11052, "V"), - (0x11076, "X"), - (0x1107F, "V"), - (0x110BD, "X"), - (0x110BE, "V"), - (0x110C3, "X"), - (0x110D0, "V"), - (0x110E9, "X"), - (0x110F0, "V"), - (0x110FA, "X"), - (0x11100, "V"), - (0x11135, "X"), - (0x11136, "V"), - (0x11148, "X"), - (0x11150, "V"), - (0x11177, "X"), - (0x11180, "V"), - (0x111E0, "X"), - (0x111E1, "V"), - (0x111F5, "X"), - (0x11200, "V"), - (0x11212, "X"), - (0x11213, "V"), - (0x11242, "X"), - (0x11280, "V"), - (0x11287, "X"), - (0x11288, "V"), - (0x11289, "X"), - (0x1128A, "V"), - (0x1128E, "X"), - (0x1128F, "V"), - (0x1129E, "X"), - (0x1129F, "V"), - (0x112AA, "X"), - (0x112B0, "V"), - (0x112EB, "X"), - (0x112F0, "V"), - (0x112FA, "X"), - ] - - -def _seg_58() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x11300, "V"), - (0x11304, "X"), - (0x11305, "V"), - (0x1130D, "X"), - (0x1130F, "V"), - (0x11311, "X"), - (0x11313, "V"), - (0x11329, "X"), - (0x1132A, "V"), - (0x11331, "X"), - (0x11332, "V"), - (0x11334, "X"), - (0x11335, "V"), - (0x1133A, "X"), - (0x1133B, "V"), - (0x11345, "X"), - (0x11347, "V"), - (0x11349, "X"), - (0x1134B, "V"), - (0x1134E, "X"), - (0x11350, "V"), - (0x11351, "X"), - (0x11357, "V"), - (0x11358, "X"), - (0x1135D, "V"), - (0x11364, "X"), - (0x11366, "V"), - (0x1136D, "X"), - (0x11370, "V"), - (0x11375, "X"), - (0x11380, "V"), - (0x1138A, "X"), - (0x1138B, "V"), - (0x1138C, "X"), - (0x1138E, "V"), - (0x1138F, "X"), - (0x11390, "V"), - (0x113B6, "X"), - (0x113B7, "V"), - (0x113C1, "X"), - (0x113C2, "V"), - (0x113C3, "X"), - (0x113C5, "V"), - (0x113C6, "X"), - (0x113C7, "V"), - (0x113CB, "X"), - (0x113CC, "V"), - (0x113D6, "X"), - (0x113D7, "V"), - (0x113D9, "X"), - (0x113E1, "V"), - (0x113E3, "X"), - (0x11400, "V"), - (0x1145C, "X"), - (0x1145D, "V"), - (0x11462, "X"), - (0x11480, "V"), - (0x114C8, "X"), - (0x114D0, "V"), - (0x114DA, "X"), - (0x11580, "V"), - (0x115B6, "X"), - (0x115B8, "V"), - (0x115DE, "X"), - (0x11600, "V"), - (0x11645, "X"), - (0x11650, "V"), - (0x1165A, "X"), - (0x11660, "V"), - (0x1166D, "X"), - (0x11680, "V"), - (0x116BA, "X"), - (0x116C0, "V"), - (0x116CA, "X"), - (0x116D0, "V"), - (0x116E4, "X"), - (0x11700, "V"), - (0x1171B, "X"), - (0x1171D, "V"), - (0x1172C, "X"), - (0x11730, "V"), - (0x11747, "X"), - (0x11800, "V"), - (0x1183C, "X"), - (0x118A0, "M", "𑣀"), - (0x118A1, "M", "𑣁"), - (0x118A2, "M", "𑣂"), - (0x118A3, "M", "𑣃"), - (0x118A4, "M", "𑣄"), - (0x118A5, "M", "𑣅"), - (0x118A6, "M", "𑣆"), - (0x118A7, "M", "𑣇"), - (0x118A8, "M", "𑣈"), - (0x118A9, "M", "𑣉"), - (0x118AA, "M", "𑣊"), - (0x118AB, "M", "𑣋"), - (0x118AC, "M", "𑣌"), - (0x118AD, "M", "𑣍"), - (0x118AE, "M", "𑣎"), - (0x118AF, "M", "𑣏"), - ] - - -def _seg_59() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x118B0, "M", "𑣐"), - (0x118B1, "M", "𑣑"), - (0x118B2, "M", "𑣒"), - (0x118B3, "M", "𑣓"), - (0x118B4, "M", "𑣔"), - (0x118B5, "M", "𑣕"), - (0x118B6, "M", "𑣖"), - (0x118B7, "M", "𑣗"), - (0x118B8, "M", "𑣘"), - (0x118B9, "M", "𑣙"), - (0x118BA, "M", "𑣚"), - (0x118BB, "M", "𑣛"), - (0x118BC, "M", "𑣜"), - (0x118BD, "M", "𑣝"), - (0x118BE, "M", "𑣞"), - (0x118BF, "M", "𑣟"), - (0x118C0, "V"), - (0x118F3, "X"), - (0x118FF, "V"), - (0x11907, "X"), - (0x11909, "V"), - (0x1190A, "X"), - (0x1190C, "V"), - (0x11914, "X"), - (0x11915, "V"), - (0x11917, "X"), - (0x11918, "V"), - (0x11936, "X"), - (0x11937, "V"), - (0x11939, "X"), - (0x1193B, "V"), - (0x11947, "X"), - (0x11950, "V"), - (0x1195A, "X"), - (0x119A0, "V"), - (0x119A8, "X"), - (0x119AA, "V"), - (0x119D8, "X"), - (0x119DA, "V"), - (0x119E5, "X"), - (0x11A00, "V"), - (0x11A48, "X"), - (0x11A50, "V"), - (0x11AA3, "X"), - (0x11AB0, "V"), - (0x11AF9, "X"), - (0x11B00, "V"), - (0x11B0A, "X"), - (0x11BC0, "V"), - (0x11BE2, "X"), - (0x11BF0, "V"), - (0x11BFA, "X"), - (0x11C00, "V"), - (0x11C09, "X"), - (0x11C0A, "V"), - (0x11C37, "X"), - (0x11C38, "V"), - (0x11C46, "X"), - (0x11C50, "V"), - (0x11C6D, "X"), - (0x11C70, "V"), - (0x11C90, "X"), - (0x11C92, "V"), - (0x11CA8, "X"), - (0x11CA9, "V"), - (0x11CB7, "X"), - (0x11D00, "V"), - (0x11D07, "X"), - (0x11D08, "V"), - (0x11D0A, "X"), - (0x11D0B, "V"), - (0x11D37, "X"), - (0x11D3A, "V"), - (0x11D3B, "X"), - (0x11D3C, "V"), - (0x11D3E, "X"), - (0x11D3F, "V"), - (0x11D48, "X"), - (0x11D50, "V"), - (0x11D5A, "X"), - (0x11D60, "V"), - (0x11D66, "X"), - (0x11D67, "V"), - (0x11D69, "X"), - (0x11D6A, "V"), - (0x11D8F, "X"), - (0x11D90, "V"), - (0x11D92, "X"), - (0x11D93, "V"), - (0x11D99, "X"), - (0x11DA0, "V"), - (0x11DAA, "X"), - (0x11EE0, "V"), - (0x11EF9, "X"), - (0x11F00, "V"), - (0x11F11, "X"), - (0x11F12, "V"), - (0x11F3B, "X"), - (0x11F3E, "V"), - (0x11F5B, "X"), - ] - - -def _seg_60() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x11FB0, "V"), - (0x11FB1, "X"), - (0x11FC0, "V"), - (0x11FF2, "X"), - (0x11FFF, "V"), - (0x1239A, "X"), - (0x12400, "V"), - (0x1246F, "X"), - (0x12470, "V"), - (0x12475, "X"), - (0x12480, "V"), - (0x12544, "X"), - (0x12F90, "V"), - (0x12FF3, "X"), - (0x13000, "V"), - (0x13430, "X"), - (0x13440, "V"), - (0x13456, "X"), - (0x13460, "V"), - (0x143FB, "X"), - (0x14400, "V"), - (0x14647, "X"), - (0x16100, "V"), - (0x1613A, "X"), - (0x16800, "V"), - (0x16A39, "X"), - (0x16A40, "V"), - (0x16A5F, "X"), - (0x16A60, "V"), - (0x16A6A, "X"), - (0x16A6E, "V"), - (0x16ABF, "X"), - (0x16AC0, "V"), - (0x16ACA, "X"), - (0x16AD0, "V"), - (0x16AEE, "X"), - (0x16AF0, "V"), - (0x16AF6, "X"), - (0x16B00, "V"), - (0x16B46, "X"), - (0x16B50, "V"), - (0x16B5A, "X"), - (0x16B5B, "V"), - (0x16B62, "X"), - (0x16B63, "V"), - (0x16B78, "X"), - (0x16B7D, "V"), - (0x16B90, "X"), - (0x16D40, "V"), - (0x16D7A, "X"), - (0x16E40, "M", "𖹠"), - (0x16E41, "M", "𖹡"), - (0x16E42, "M", "𖹢"), - (0x16E43, "M", "𖹣"), - (0x16E44, "M", "𖹤"), - (0x16E45, "M", "𖹥"), - (0x16E46, "M", "𖹦"), - (0x16E47, "M", "𖹧"), - (0x16E48, "M", "𖹨"), - (0x16E49, "M", "𖹩"), - (0x16E4A, "M", "𖹪"), - (0x16E4B, "M", "𖹫"), - (0x16E4C, "M", "𖹬"), - (0x16E4D, "M", "𖹭"), - (0x16E4E, "M", "𖹮"), - (0x16E4F, "M", "𖹯"), - (0x16E50, "M", "𖹰"), - (0x16E51, "M", "𖹱"), - (0x16E52, "M", "𖹲"), - (0x16E53, "M", "𖹳"), - (0x16E54, "M", "𖹴"), - (0x16E55, "M", "𖹵"), - (0x16E56, "M", "𖹶"), - (0x16E57, "M", "𖹷"), - (0x16E58, "M", "𖹸"), - (0x16E59, "M", "𖹹"), - (0x16E5A, "M", "𖹺"), - (0x16E5B, "M", "𖹻"), - (0x16E5C, "M", "𖹼"), - (0x16E5D, "M", "𖹽"), - (0x16E5E, "M", "𖹾"), - (0x16E5F, "M", "𖹿"), - (0x16E60, "V"), - (0x16E9B, "X"), - (0x16F00, "V"), - (0x16F4B, "X"), - (0x16F4F, "V"), - (0x16F88, "X"), - (0x16F8F, "V"), - (0x16FA0, "X"), - (0x16FE0, "V"), - (0x16FE5, "X"), - (0x16FF0, "V"), - (0x16FF2, "X"), - (0x17000, "V"), - (0x187F8, "X"), - (0x18800, "V"), - (0x18CD6, "X"), - (0x18CFF, "V"), - (0x18D09, "X"), - ] - - -def _seg_61() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1AFF0, "V"), - (0x1AFF4, "X"), - (0x1AFF5, "V"), - (0x1AFFC, "X"), - (0x1AFFD, "V"), - (0x1AFFF, "X"), - (0x1B000, "V"), - (0x1B123, "X"), - (0x1B132, "V"), - (0x1B133, "X"), - (0x1B150, "V"), - (0x1B153, "X"), - (0x1B155, "V"), - (0x1B156, "X"), - (0x1B164, "V"), - (0x1B168, "X"), - (0x1B170, "V"), - (0x1B2FC, "X"), - (0x1BC00, "V"), - (0x1BC6B, "X"), - (0x1BC70, "V"), - (0x1BC7D, "X"), - (0x1BC80, "V"), - (0x1BC89, "X"), - (0x1BC90, "V"), - (0x1BC9A, "X"), - (0x1BC9C, "V"), - (0x1BCA0, "I"), - (0x1BCA4, "X"), - (0x1CC00, "V"), - (0x1CCD6, "M", "a"), - (0x1CCD7, "M", "b"), - (0x1CCD8, "M", "c"), - (0x1CCD9, "M", "d"), - (0x1CCDA, "M", "e"), - (0x1CCDB, "M", "f"), - (0x1CCDC, "M", "g"), - (0x1CCDD, "M", "h"), - (0x1CCDE, "M", "i"), - (0x1CCDF, "M", "j"), - (0x1CCE0, "M", "k"), - (0x1CCE1, "M", "l"), - (0x1CCE2, "M", "m"), - (0x1CCE3, "M", "n"), - (0x1CCE4, "M", "o"), - (0x1CCE5, "M", "p"), - (0x1CCE6, "M", "q"), - (0x1CCE7, "M", "r"), - (0x1CCE8, "M", "s"), - (0x1CCE9, "M", "t"), - (0x1CCEA, "M", "u"), - (0x1CCEB, "M", "v"), - (0x1CCEC, "M", "w"), - (0x1CCED, "M", "x"), - (0x1CCEE, "M", "y"), - (0x1CCEF, "M", "z"), - (0x1CCF0, "M", "0"), - (0x1CCF1, "M", "1"), - (0x1CCF2, "M", "2"), - (0x1CCF3, "M", "3"), - (0x1CCF4, "M", "4"), - (0x1CCF5, "M", "5"), - (0x1CCF6, "M", "6"), - (0x1CCF7, "M", "7"), - (0x1CCF8, "M", "8"), - (0x1CCF9, "M", "9"), - (0x1CCFA, "X"), - (0x1CD00, "V"), - (0x1CEB4, "X"), - (0x1CF00, "V"), - (0x1CF2E, "X"), - (0x1CF30, "V"), - (0x1CF47, "X"), - (0x1CF50, "V"), - (0x1CFC4, "X"), - (0x1D000, "V"), - (0x1D0F6, "X"), - (0x1D100, "V"), - (0x1D127, "X"), - (0x1D129, "V"), - (0x1D15E, "M", "𝅗𝅥"), - (0x1D15F, "M", "𝅘𝅥"), - (0x1D160, "M", "𝅘𝅥𝅮"), - (0x1D161, "M", "𝅘𝅥𝅯"), - (0x1D162, "M", "𝅘𝅥𝅰"), - (0x1D163, "M", "𝅘𝅥𝅱"), - (0x1D164, "M", "𝅘𝅥𝅲"), - (0x1D165, "V"), - (0x1D173, "I"), - (0x1D17B, "V"), - (0x1D1BB, "M", "𝆹𝅥"), - (0x1D1BC, "M", "𝆺𝅥"), - (0x1D1BD, "M", "𝆹𝅥𝅮"), - (0x1D1BE, "M", "𝆺𝅥𝅮"), - (0x1D1BF, "M", "𝆹𝅥𝅯"), - (0x1D1C0, "M", "𝆺𝅥𝅯"), - (0x1D1C1, "V"), - (0x1D1EB, "X"), - (0x1D200, "V"), - (0x1D246, "X"), - ] - - -def _seg_62() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D2C0, "V"), - (0x1D2D4, "X"), - (0x1D2E0, "V"), - (0x1D2F4, "X"), - (0x1D300, "V"), - (0x1D357, "X"), - (0x1D360, "V"), - (0x1D379, "X"), - (0x1D400, "M", "a"), - (0x1D401, "M", "b"), - (0x1D402, "M", "c"), - (0x1D403, "M", "d"), - (0x1D404, "M", "e"), - (0x1D405, "M", "f"), - (0x1D406, "M", "g"), - (0x1D407, "M", "h"), - (0x1D408, "M", "i"), - (0x1D409, "M", "j"), - (0x1D40A, "M", "k"), - (0x1D40B, "M", "l"), - (0x1D40C, "M", "m"), - (0x1D40D, "M", "n"), - (0x1D40E, "M", "o"), - (0x1D40F, "M", "p"), - (0x1D410, "M", "q"), - (0x1D411, "M", "r"), - (0x1D412, "M", "s"), - (0x1D413, "M", "t"), - (0x1D414, "M", "u"), - (0x1D415, "M", "v"), - (0x1D416, "M", "w"), - (0x1D417, "M", "x"), - (0x1D418, "M", "y"), - (0x1D419, "M", "z"), - (0x1D41A, "M", "a"), - (0x1D41B, "M", "b"), - (0x1D41C, "M", "c"), - (0x1D41D, "M", "d"), - (0x1D41E, "M", "e"), - (0x1D41F, "M", "f"), - (0x1D420, "M", "g"), - (0x1D421, "M", "h"), - (0x1D422, "M", "i"), - (0x1D423, "M", "j"), - (0x1D424, "M", "k"), - (0x1D425, "M", "l"), - (0x1D426, "M", "m"), - (0x1D427, "M", "n"), - (0x1D428, "M", "o"), - (0x1D429, "M", "p"), - (0x1D42A, "M", "q"), - (0x1D42B, "M", "r"), - (0x1D42C, "M", "s"), - (0x1D42D, "M", "t"), - (0x1D42E, "M", "u"), - (0x1D42F, "M", "v"), - (0x1D430, "M", "w"), - (0x1D431, "M", "x"), - (0x1D432, "M", "y"), - (0x1D433, "M", "z"), - (0x1D434, "M", "a"), - (0x1D435, "M", "b"), - (0x1D436, "M", "c"), - (0x1D437, "M", "d"), - (0x1D438, "M", "e"), - (0x1D439, "M", "f"), - (0x1D43A, "M", "g"), - (0x1D43B, "M", "h"), - (0x1D43C, "M", "i"), - (0x1D43D, "M", "j"), - (0x1D43E, "M", "k"), - (0x1D43F, "M", "l"), - (0x1D440, "M", "m"), - (0x1D441, "M", "n"), - (0x1D442, "M", "o"), - (0x1D443, "M", "p"), - (0x1D444, "M", "q"), - (0x1D445, "M", "r"), - (0x1D446, "M", "s"), - (0x1D447, "M", "t"), - (0x1D448, "M", "u"), - (0x1D449, "M", "v"), - (0x1D44A, "M", "w"), - (0x1D44B, "M", "x"), - (0x1D44C, "M", "y"), - (0x1D44D, "M", "z"), - (0x1D44E, "M", "a"), - (0x1D44F, "M", "b"), - (0x1D450, "M", "c"), - (0x1D451, "M", "d"), - (0x1D452, "M", "e"), - (0x1D453, "M", "f"), - (0x1D454, "M", "g"), - (0x1D455, "X"), - (0x1D456, "M", "i"), - (0x1D457, "M", "j"), - (0x1D458, "M", "k"), - (0x1D459, "M", "l"), - (0x1D45A, "M", "m"), - (0x1D45B, "M", "n"), - ] - - -def _seg_63() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D45C, "M", "o"), - (0x1D45D, "M", "p"), - (0x1D45E, "M", "q"), - (0x1D45F, "M", "r"), - (0x1D460, "M", "s"), - (0x1D461, "M", "t"), - (0x1D462, "M", "u"), - (0x1D463, "M", "v"), - (0x1D464, "M", "w"), - (0x1D465, "M", "x"), - (0x1D466, "M", "y"), - (0x1D467, "M", "z"), - (0x1D468, "M", "a"), - (0x1D469, "M", "b"), - (0x1D46A, "M", "c"), - (0x1D46B, "M", "d"), - (0x1D46C, "M", "e"), - (0x1D46D, "M", "f"), - (0x1D46E, "M", "g"), - (0x1D46F, "M", "h"), - (0x1D470, "M", "i"), - (0x1D471, "M", "j"), - (0x1D472, "M", "k"), - (0x1D473, "M", "l"), - (0x1D474, "M", "m"), - (0x1D475, "M", "n"), - (0x1D476, "M", "o"), - (0x1D477, "M", "p"), - (0x1D478, "M", "q"), - (0x1D479, "M", "r"), - (0x1D47A, "M", "s"), - (0x1D47B, "M", "t"), - (0x1D47C, "M", "u"), - (0x1D47D, "M", "v"), - (0x1D47E, "M", "w"), - (0x1D47F, "M", "x"), - (0x1D480, "M", "y"), - (0x1D481, "M", "z"), - (0x1D482, "M", "a"), - (0x1D483, "M", "b"), - (0x1D484, "M", "c"), - (0x1D485, "M", "d"), - (0x1D486, "M", "e"), - (0x1D487, "M", "f"), - (0x1D488, "M", "g"), - (0x1D489, "M", "h"), - (0x1D48A, "M", "i"), - (0x1D48B, "M", "j"), - (0x1D48C, "M", "k"), - (0x1D48D, "M", "l"), - (0x1D48E, "M", "m"), - (0x1D48F, "M", "n"), - (0x1D490, "M", "o"), - (0x1D491, "M", "p"), - (0x1D492, "M", "q"), - (0x1D493, "M", "r"), - (0x1D494, "M", "s"), - (0x1D495, "M", "t"), - (0x1D496, "M", "u"), - (0x1D497, "M", "v"), - (0x1D498, "M", "w"), - (0x1D499, "M", "x"), - (0x1D49A, "M", "y"), - (0x1D49B, "M", "z"), - (0x1D49C, "M", "a"), - (0x1D49D, "X"), - (0x1D49E, "M", "c"), - (0x1D49F, "M", "d"), - (0x1D4A0, "X"), - (0x1D4A2, "M", "g"), - (0x1D4A3, "X"), - (0x1D4A5, "M", "j"), - (0x1D4A6, "M", "k"), - (0x1D4A7, "X"), - (0x1D4A9, "M", "n"), - (0x1D4AA, "M", "o"), - (0x1D4AB, "M", "p"), - (0x1D4AC, "M", "q"), - (0x1D4AD, "X"), - (0x1D4AE, "M", "s"), - (0x1D4AF, "M", "t"), - (0x1D4B0, "M", "u"), - (0x1D4B1, "M", "v"), - (0x1D4B2, "M", "w"), - (0x1D4B3, "M", "x"), - (0x1D4B4, "M", "y"), - (0x1D4B5, "M", "z"), - (0x1D4B6, "M", "a"), - (0x1D4B7, "M", "b"), - (0x1D4B8, "M", "c"), - (0x1D4B9, "M", "d"), - (0x1D4BA, "X"), - (0x1D4BB, "M", "f"), - (0x1D4BC, "X"), - (0x1D4BD, "M", "h"), - (0x1D4BE, "M", "i"), - (0x1D4BF, "M", "j"), - (0x1D4C0, "M", "k"), - (0x1D4C1, "M", "l"), - (0x1D4C2, "M", "m"), - ] - - -def _seg_64() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D4C3, "M", "n"), - (0x1D4C4, "X"), - (0x1D4C5, "M", "p"), - (0x1D4C6, "M", "q"), - (0x1D4C7, "M", "r"), - (0x1D4C8, "M", "s"), - (0x1D4C9, "M", "t"), - (0x1D4CA, "M", "u"), - (0x1D4CB, "M", "v"), - (0x1D4CC, "M", "w"), - (0x1D4CD, "M", "x"), - (0x1D4CE, "M", "y"), - (0x1D4CF, "M", "z"), - (0x1D4D0, "M", "a"), - (0x1D4D1, "M", "b"), - (0x1D4D2, "M", "c"), - (0x1D4D3, "M", "d"), - (0x1D4D4, "M", "e"), - (0x1D4D5, "M", "f"), - (0x1D4D6, "M", "g"), - (0x1D4D7, "M", "h"), - (0x1D4D8, "M", "i"), - (0x1D4D9, "M", "j"), - (0x1D4DA, "M", "k"), - (0x1D4DB, "M", "l"), - (0x1D4DC, "M", "m"), - (0x1D4DD, "M", "n"), - (0x1D4DE, "M", "o"), - (0x1D4DF, "M", "p"), - (0x1D4E0, "M", "q"), - (0x1D4E1, "M", "r"), - (0x1D4E2, "M", "s"), - (0x1D4E3, "M", "t"), - (0x1D4E4, "M", "u"), - (0x1D4E5, "M", "v"), - (0x1D4E6, "M", "w"), - (0x1D4E7, "M", "x"), - (0x1D4E8, "M", "y"), - (0x1D4E9, "M", "z"), - (0x1D4EA, "M", "a"), - (0x1D4EB, "M", "b"), - (0x1D4EC, "M", "c"), - (0x1D4ED, "M", "d"), - (0x1D4EE, "M", "e"), - (0x1D4EF, "M", "f"), - (0x1D4F0, "M", "g"), - (0x1D4F1, "M", "h"), - (0x1D4F2, "M", "i"), - (0x1D4F3, "M", "j"), - (0x1D4F4, "M", "k"), - (0x1D4F5, "M", "l"), - (0x1D4F6, "M", "m"), - (0x1D4F7, "M", "n"), - (0x1D4F8, "M", "o"), - (0x1D4F9, "M", "p"), - (0x1D4FA, "M", "q"), - (0x1D4FB, "M", "r"), - (0x1D4FC, "M", "s"), - (0x1D4FD, "M", "t"), - (0x1D4FE, "M", "u"), - (0x1D4FF, "M", "v"), - (0x1D500, "M", "w"), - (0x1D501, "M", "x"), - (0x1D502, "M", "y"), - (0x1D503, "M", "z"), - (0x1D504, "M", "a"), - (0x1D505, "M", "b"), - (0x1D506, "X"), - (0x1D507, "M", "d"), - (0x1D508, "M", "e"), - (0x1D509, "M", "f"), - (0x1D50A, "M", "g"), - (0x1D50B, "X"), - (0x1D50D, "M", "j"), - (0x1D50E, "M", "k"), - (0x1D50F, "M", "l"), - (0x1D510, "M", "m"), - (0x1D511, "M", "n"), - (0x1D512, "M", "o"), - (0x1D513, "M", "p"), - (0x1D514, "M", "q"), - (0x1D515, "X"), - (0x1D516, "M", "s"), - (0x1D517, "M", "t"), - (0x1D518, "M", "u"), - (0x1D519, "M", "v"), - (0x1D51A, "M", "w"), - (0x1D51B, "M", "x"), - (0x1D51C, "M", "y"), - (0x1D51D, "X"), - (0x1D51E, "M", "a"), - (0x1D51F, "M", "b"), - (0x1D520, "M", "c"), - (0x1D521, "M", "d"), - (0x1D522, "M", "e"), - (0x1D523, "M", "f"), - (0x1D524, "M", "g"), - (0x1D525, "M", "h"), - (0x1D526, "M", "i"), - (0x1D527, "M", "j"), - ] - - -def _seg_65() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D528, "M", "k"), - (0x1D529, "M", "l"), - (0x1D52A, "M", "m"), - (0x1D52B, "M", "n"), - (0x1D52C, "M", "o"), - (0x1D52D, "M", "p"), - (0x1D52E, "M", "q"), - (0x1D52F, "M", "r"), - (0x1D530, "M", "s"), - (0x1D531, "M", "t"), - (0x1D532, "M", "u"), - (0x1D533, "M", "v"), - (0x1D534, "M", "w"), - (0x1D535, "M", "x"), - (0x1D536, "M", "y"), - (0x1D537, "M", "z"), - (0x1D538, "M", "a"), - (0x1D539, "M", "b"), - (0x1D53A, "X"), - (0x1D53B, "M", "d"), - (0x1D53C, "M", "e"), - (0x1D53D, "M", "f"), - (0x1D53E, "M", "g"), - (0x1D53F, "X"), - (0x1D540, "M", "i"), - (0x1D541, "M", "j"), - (0x1D542, "M", "k"), - (0x1D543, "M", "l"), - (0x1D544, "M", "m"), - (0x1D545, "X"), - (0x1D546, "M", "o"), - (0x1D547, "X"), - (0x1D54A, "M", "s"), - (0x1D54B, "M", "t"), - (0x1D54C, "M", "u"), - (0x1D54D, "M", "v"), - (0x1D54E, "M", "w"), - (0x1D54F, "M", "x"), - (0x1D550, "M", "y"), - (0x1D551, "X"), - (0x1D552, "M", "a"), - (0x1D553, "M", "b"), - (0x1D554, "M", "c"), - (0x1D555, "M", "d"), - (0x1D556, "M", "e"), - (0x1D557, "M", "f"), - (0x1D558, "M", "g"), - (0x1D559, "M", "h"), - (0x1D55A, "M", "i"), - (0x1D55B, "M", "j"), - (0x1D55C, "M", "k"), - (0x1D55D, "M", "l"), - (0x1D55E, "M", "m"), - (0x1D55F, "M", "n"), - (0x1D560, "M", "o"), - (0x1D561, "M", "p"), - (0x1D562, "M", "q"), - (0x1D563, "M", "r"), - (0x1D564, "M", "s"), - (0x1D565, "M", "t"), - (0x1D566, "M", "u"), - (0x1D567, "M", "v"), - (0x1D568, "M", "w"), - (0x1D569, "M", "x"), - (0x1D56A, "M", "y"), - (0x1D56B, "M", "z"), - (0x1D56C, "M", "a"), - (0x1D56D, "M", "b"), - (0x1D56E, "M", "c"), - (0x1D56F, "M", "d"), - (0x1D570, "M", "e"), - (0x1D571, "M", "f"), - (0x1D572, "M", "g"), - (0x1D573, "M", "h"), - (0x1D574, "M", "i"), - (0x1D575, "M", "j"), - (0x1D576, "M", "k"), - (0x1D577, "M", "l"), - (0x1D578, "M", "m"), - (0x1D579, "M", "n"), - (0x1D57A, "M", "o"), - (0x1D57B, "M", "p"), - (0x1D57C, "M", "q"), - (0x1D57D, "M", "r"), - (0x1D57E, "M", "s"), - (0x1D57F, "M", "t"), - (0x1D580, "M", "u"), - (0x1D581, "M", "v"), - (0x1D582, "M", "w"), - (0x1D583, "M", "x"), - (0x1D584, "M", "y"), - (0x1D585, "M", "z"), - (0x1D586, "M", "a"), - (0x1D587, "M", "b"), - (0x1D588, "M", "c"), - (0x1D589, "M", "d"), - (0x1D58A, "M", "e"), - (0x1D58B, "M", "f"), - (0x1D58C, "M", "g"), - (0x1D58D, "M", "h"), - ] - - -def _seg_66() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D58E, "M", "i"), - (0x1D58F, "M", "j"), - (0x1D590, "M", "k"), - (0x1D591, "M", "l"), - (0x1D592, "M", "m"), - (0x1D593, "M", "n"), - (0x1D594, "M", "o"), - (0x1D595, "M", "p"), - (0x1D596, "M", "q"), - (0x1D597, "M", "r"), - (0x1D598, "M", "s"), - (0x1D599, "M", "t"), - (0x1D59A, "M", "u"), - (0x1D59B, "M", "v"), - (0x1D59C, "M", "w"), - (0x1D59D, "M", "x"), - (0x1D59E, "M", "y"), - (0x1D59F, "M", "z"), - (0x1D5A0, "M", "a"), - (0x1D5A1, "M", "b"), - (0x1D5A2, "M", "c"), - (0x1D5A3, "M", "d"), - (0x1D5A4, "M", "e"), - (0x1D5A5, "M", "f"), - (0x1D5A6, "M", "g"), - (0x1D5A7, "M", "h"), - (0x1D5A8, "M", "i"), - (0x1D5A9, "M", "j"), - (0x1D5AA, "M", "k"), - (0x1D5AB, "M", "l"), - (0x1D5AC, "M", "m"), - (0x1D5AD, "M", "n"), - (0x1D5AE, "M", "o"), - (0x1D5AF, "M", "p"), - (0x1D5B0, "M", "q"), - (0x1D5B1, "M", "r"), - (0x1D5B2, "M", "s"), - (0x1D5B3, "M", "t"), - (0x1D5B4, "M", "u"), - (0x1D5B5, "M", "v"), - (0x1D5B6, "M", "w"), - (0x1D5B7, "M", "x"), - (0x1D5B8, "M", "y"), - (0x1D5B9, "M", "z"), - (0x1D5BA, "M", "a"), - (0x1D5BB, "M", "b"), - (0x1D5BC, "M", "c"), - (0x1D5BD, "M", "d"), - (0x1D5BE, "M", "e"), - (0x1D5BF, "M", "f"), - (0x1D5C0, "M", "g"), - (0x1D5C1, "M", "h"), - (0x1D5C2, "M", "i"), - (0x1D5C3, "M", "j"), - (0x1D5C4, "M", "k"), - (0x1D5C5, "M", "l"), - (0x1D5C6, "M", "m"), - (0x1D5C7, "M", "n"), - (0x1D5C8, "M", "o"), - (0x1D5C9, "M", "p"), - (0x1D5CA, "M", "q"), - (0x1D5CB, "M", "r"), - (0x1D5CC, "M", "s"), - (0x1D5CD, "M", "t"), - (0x1D5CE, "M", "u"), - (0x1D5CF, "M", "v"), - (0x1D5D0, "M", "w"), - (0x1D5D1, "M", "x"), - (0x1D5D2, "M", "y"), - (0x1D5D3, "M", "z"), - (0x1D5D4, "M", "a"), - (0x1D5D5, "M", "b"), - (0x1D5D6, "M", "c"), - (0x1D5D7, "M", "d"), - (0x1D5D8, "M", "e"), - (0x1D5D9, "M", "f"), - (0x1D5DA, "M", "g"), - (0x1D5DB, "M", "h"), - (0x1D5DC, "M", "i"), - (0x1D5DD, "M", "j"), - (0x1D5DE, "M", "k"), - (0x1D5DF, "M", "l"), - (0x1D5E0, "M", "m"), - (0x1D5E1, "M", "n"), - (0x1D5E2, "M", "o"), - (0x1D5E3, "M", "p"), - (0x1D5E4, "M", "q"), - (0x1D5E5, "M", "r"), - (0x1D5E6, "M", "s"), - (0x1D5E7, "M", "t"), - (0x1D5E8, "M", "u"), - (0x1D5E9, "M", "v"), - (0x1D5EA, "M", "w"), - (0x1D5EB, "M", "x"), - (0x1D5EC, "M", "y"), - (0x1D5ED, "M", "z"), - (0x1D5EE, "M", "a"), - (0x1D5EF, "M", "b"), - (0x1D5F0, "M", "c"), - (0x1D5F1, "M", "d"), - ] - - -def _seg_67() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D5F2, "M", "e"), - (0x1D5F3, "M", "f"), - (0x1D5F4, "M", "g"), - (0x1D5F5, "M", "h"), - (0x1D5F6, "M", "i"), - (0x1D5F7, "M", "j"), - (0x1D5F8, "M", "k"), - (0x1D5F9, "M", "l"), - (0x1D5FA, "M", "m"), - (0x1D5FB, "M", "n"), - (0x1D5FC, "M", "o"), - (0x1D5FD, "M", "p"), - (0x1D5FE, "M", "q"), - (0x1D5FF, "M", "r"), - (0x1D600, "M", "s"), - (0x1D601, "M", "t"), - (0x1D602, "M", "u"), - (0x1D603, "M", "v"), - (0x1D604, "M", "w"), - (0x1D605, "M", "x"), - (0x1D606, "M", "y"), - (0x1D607, "M", "z"), - (0x1D608, "M", "a"), - (0x1D609, "M", "b"), - (0x1D60A, "M", "c"), - (0x1D60B, "M", "d"), - (0x1D60C, "M", "e"), - (0x1D60D, "M", "f"), - (0x1D60E, "M", "g"), - (0x1D60F, "M", "h"), - (0x1D610, "M", "i"), - (0x1D611, "M", "j"), - (0x1D612, "M", "k"), - (0x1D613, "M", "l"), - (0x1D614, "M", "m"), - (0x1D615, "M", "n"), - (0x1D616, "M", "o"), - (0x1D617, "M", "p"), - (0x1D618, "M", "q"), - (0x1D619, "M", "r"), - (0x1D61A, "M", "s"), - (0x1D61B, "M", "t"), - (0x1D61C, "M", "u"), - (0x1D61D, "M", "v"), - (0x1D61E, "M", "w"), - (0x1D61F, "M", "x"), - (0x1D620, "M", "y"), - (0x1D621, "M", "z"), - (0x1D622, "M", "a"), - (0x1D623, "M", "b"), - (0x1D624, "M", "c"), - (0x1D625, "M", "d"), - (0x1D626, "M", "e"), - (0x1D627, "M", "f"), - (0x1D628, "M", "g"), - (0x1D629, "M", "h"), - (0x1D62A, "M", "i"), - (0x1D62B, "M", "j"), - (0x1D62C, "M", "k"), - (0x1D62D, "M", "l"), - (0x1D62E, "M", "m"), - (0x1D62F, "M", "n"), - (0x1D630, "M", "o"), - (0x1D631, "M", "p"), - (0x1D632, "M", "q"), - (0x1D633, "M", "r"), - (0x1D634, "M", "s"), - (0x1D635, "M", "t"), - (0x1D636, "M", "u"), - (0x1D637, "M", "v"), - (0x1D638, "M", "w"), - (0x1D639, "M", "x"), - (0x1D63A, "M", "y"), - (0x1D63B, "M", "z"), - (0x1D63C, "M", "a"), - (0x1D63D, "M", "b"), - (0x1D63E, "M", "c"), - (0x1D63F, "M", "d"), - (0x1D640, "M", "e"), - (0x1D641, "M", "f"), - (0x1D642, "M", "g"), - (0x1D643, "M", "h"), - (0x1D644, "M", "i"), - (0x1D645, "M", "j"), - (0x1D646, "M", "k"), - (0x1D647, "M", "l"), - (0x1D648, "M", "m"), - (0x1D649, "M", "n"), - (0x1D64A, "M", "o"), - (0x1D64B, "M", "p"), - (0x1D64C, "M", "q"), - (0x1D64D, "M", "r"), - (0x1D64E, "M", "s"), - (0x1D64F, "M", "t"), - (0x1D650, "M", "u"), - (0x1D651, "M", "v"), - (0x1D652, "M", "w"), - (0x1D653, "M", "x"), - (0x1D654, "M", "y"), - (0x1D655, "M", "z"), - ] - - -def _seg_68() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D656, "M", "a"), - (0x1D657, "M", "b"), - (0x1D658, "M", "c"), - (0x1D659, "M", "d"), - (0x1D65A, "M", "e"), - (0x1D65B, "M", "f"), - (0x1D65C, "M", "g"), - (0x1D65D, "M", "h"), - (0x1D65E, "M", "i"), - (0x1D65F, "M", "j"), - (0x1D660, "M", "k"), - (0x1D661, "M", "l"), - (0x1D662, "M", "m"), - (0x1D663, "M", "n"), - (0x1D664, "M", "o"), - (0x1D665, "M", "p"), - (0x1D666, "M", "q"), - (0x1D667, "M", "r"), - (0x1D668, "M", "s"), - (0x1D669, "M", "t"), - (0x1D66A, "M", "u"), - (0x1D66B, "M", "v"), - (0x1D66C, "M", "w"), - (0x1D66D, "M", "x"), - (0x1D66E, "M", "y"), - (0x1D66F, "M", "z"), - (0x1D670, "M", "a"), - (0x1D671, "M", "b"), - (0x1D672, "M", "c"), - (0x1D673, "M", "d"), - (0x1D674, "M", "e"), - (0x1D675, "M", "f"), - (0x1D676, "M", "g"), - (0x1D677, "M", "h"), - (0x1D678, "M", "i"), - (0x1D679, "M", "j"), - (0x1D67A, "M", "k"), - (0x1D67B, "M", "l"), - (0x1D67C, "M", "m"), - (0x1D67D, "M", "n"), - (0x1D67E, "M", "o"), - (0x1D67F, "M", "p"), - (0x1D680, "M", "q"), - (0x1D681, "M", "r"), - (0x1D682, "M", "s"), - (0x1D683, "M", "t"), - (0x1D684, "M", "u"), - (0x1D685, "M", "v"), - (0x1D686, "M", "w"), - (0x1D687, "M", "x"), - (0x1D688, "M", "y"), - (0x1D689, "M", "z"), - (0x1D68A, "M", "a"), - (0x1D68B, "M", "b"), - (0x1D68C, "M", "c"), - (0x1D68D, "M", "d"), - (0x1D68E, "M", "e"), - (0x1D68F, "M", "f"), - (0x1D690, "M", "g"), - (0x1D691, "M", "h"), - (0x1D692, "M", "i"), - (0x1D693, "M", "j"), - (0x1D694, "M", "k"), - (0x1D695, "M", "l"), - (0x1D696, "M", "m"), - (0x1D697, "M", "n"), - (0x1D698, "M", "o"), - (0x1D699, "M", "p"), - (0x1D69A, "M", "q"), - (0x1D69B, "M", "r"), - (0x1D69C, "M", "s"), - (0x1D69D, "M", "t"), - (0x1D69E, "M", "u"), - (0x1D69F, "M", "v"), - (0x1D6A0, "M", "w"), - (0x1D6A1, "M", "x"), - (0x1D6A2, "M", "y"), - (0x1D6A3, "M", "z"), - (0x1D6A4, "M", "ı"), - (0x1D6A5, "M", "ȷ"), - (0x1D6A6, "X"), - (0x1D6A8, "M", "α"), - (0x1D6A9, "M", "β"), - (0x1D6AA, "M", "γ"), - (0x1D6AB, "M", "δ"), - (0x1D6AC, "M", "ε"), - (0x1D6AD, "M", "ζ"), - (0x1D6AE, "M", "η"), - (0x1D6AF, "M", "θ"), - (0x1D6B0, "M", "ι"), - (0x1D6B1, "M", "κ"), - (0x1D6B2, "M", "λ"), - (0x1D6B3, "M", "μ"), - (0x1D6B4, "M", "ν"), - (0x1D6B5, "M", "ξ"), - (0x1D6B6, "M", "ο"), - (0x1D6B7, "M", "π"), - (0x1D6B8, "M", "ρ"), - (0x1D6B9, "M", "θ"), - (0x1D6BA, "M", "σ"), - ] - - -def _seg_69() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D6BB, "M", "τ"), - (0x1D6BC, "M", "υ"), - (0x1D6BD, "M", "φ"), - (0x1D6BE, "M", "χ"), - (0x1D6BF, "M", "ψ"), - (0x1D6C0, "M", "ω"), - (0x1D6C1, "M", "∇"), - (0x1D6C2, "M", "α"), - (0x1D6C3, "M", "β"), - (0x1D6C4, "M", "γ"), - (0x1D6C5, "M", "δ"), - (0x1D6C6, "M", "ε"), - (0x1D6C7, "M", "ζ"), - (0x1D6C8, "M", "η"), - (0x1D6C9, "M", "θ"), - (0x1D6CA, "M", "ι"), - (0x1D6CB, "M", "κ"), - (0x1D6CC, "M", "λ"), - (0x1D6CD, "M", "μ"), - (0x1D6CE, "M", "ν"), - (0x1D6CF, "M", "ξ"), - (0x1D6D0, "M", "ο"), - (0x1D6D1, "M", "π"), - (0x1D6D2, "M", "ρ"), - (0x1D6D3, "M", "σ"), - (0x1D6D5, "M", "τ"), - (0x1D6D6, "M", "υ"), - (0x1D6D7, "M", "φ"), - (0x1D6D8, "M", "χ"), - (0x1D6D9, "M", "ψ"), - (0x1D6DA, "M", "ω"), - (0x1D6DB, "M", "∂"), - (0x1D6DC, "M", "ε"), - (0x1D6DD, "M", "θ"), - (0x1D6DE, "M", "κ"), - (0x1D6DF, "M", "φ"), - (0x1D6E0, "M", "ρ"), - (0x1D6E1, "M", "π"), - (0x1D6E2, "M", "α"), - (0x1D6E3, "M", "β"), - (0x1D6E4, "M", "γ"), - (0x1D6E5, "M", "δ"), - (0x1D6E6, "M", "ε"), - (0x1D6E7, "M", "ζ"), - (0x1D6E8, "M", "η"), - (0x1D6E9, "M", "θ"), - (0x1D6EA, "M", "ι"), - (0x1D6EB, "M", "κ"), - (0x1D6EC, "M", "λ"), - (0x1D6ED, "M", "μ"), - (0x1D6EE, "M", "ν"), - (0x1D6EF, "M", "ξ"), - (0x1D6F0, "M", "ο"), - (0x1D6F1, "M", "π"), - (0x1D6F2, "M", "ρ"), - (0x1D6F3, "M", "θ"), - (0x1D6F4, "M", "σ"), - (0x1D6F5, "M", "τ"), - (0x1D6F6, "M", "υ"), - (0x1D6F7, "M", "φ"), - (0x1D6F8, "M", "χ"), - (0x1D6F9, "M", "ψ"), - (0x1D6FA, "M", "ω"), - (0x1D6FB, "M", "∇"), - (0x1D6FC, "M", "α"), - (0x1D6FD, "M", "β"), - (0x1D6FE, "M", "γ"), - (0x1D6FF, "M", "δ"), - (0x1D700, "M", "ε"), - (0x1D701, "M", "ζ"), - (0x1D702, "M", "η"), - (0x1D703, "M", "θ"), - (0x1D704, "M", "ι"), - (0x1D705, "M", "κ"), - (0x1D706, "M", "λ"), - (0x1D707, "M", "μ"), - (0x1D708, "M", "ν"), - (0x1D709, "M", "ξ"), - (0x1D70A, "M", "ο"), - (0x1D70B, "M", "π"), - (0x1D70C, "M", "ρ"), - (0x1D70D, "M", "σ"), - (0x1D70F, "M", "τ"), - (0x1D710, "M", "υ"), - (0x1D711, "M", "φ"), - (0x1D712, "M", "χ"), - (0x1D713, "M", "ψ"), - (0x1D714, "M", "ω"), - (0x1D715, "M", "∂"), - (0x1D716, "M", "ε"), - (0x1D717, "M", "θ"), - (0x1D718, "M", "κ"), - (0x1D719, "M", "φ"), - (0x1D71A, "M", "ρ"), - (0x1D71B, "M", "π"), - (0x1D71C, "M", "α"), - (0x1D71D, "M", "β"), - (0x1D71E, "M", "γ"), - (0x1D71F, "M", "δ"), - (0x1D720, "M", "ε"), - ] - - -def _seg_70() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D721, "M", "ζ"), - (0x1D722, "M", "η"), - (0x1D723, "M", "θ"), - (0x1D724, "M", "ι"), - (0x1D725, "M", "κ"), - (0x1D726, "M", "λ"), - (0x1D727, "M", "μ"), - (0x1D728, "M", "ν"), - (0x1D729, "M", "ξ"), - (0x1D72A, "M", "ο"), - (0x1D72B, "M", "π"), - (0x1D72C, "M", "ρ"), - (0x1D72D, "M", "θ"), - (0x1D72E, "M", "σ"), - (0x1D72F, "M", "τ"), - (0x1D730, "M", "υ"), - (0x1D731, "M", "φ"), - (0x1D732, "M", "χ"), - (0x1D733, "M", "ψ"), - (0x1D734, "M", "ω"), - (0x1D735, "M", "∇"), - (0x1D736, "M", "α"), - (0x1D737, "M", "β"), - (0x1D738, "M", "γ"), - (0x1D739, "M", "δ"), - (0x1D73A, "M", "ε"), - (0x1D73B, "M", "ζ"), - (0x1D73C, "M", "η"), - (0x1D73D, "M", "θ"), - (0x1D73E, "M", "ι"), - (0x1D73F, "M", "κ"), - (0x1D740, "M", "λ"), - (0x1D741, "M", "μ"), - (0x1D742, "M", "ν"), - (0x1D743, "M", "ξ"), - (0x1D744, "M", "ο"), - (0x1D745, "M", "π"), - (0x1D746, "M", "ρ"), - (0x1D747, "M", "σ"), - (0x1D749, "M", "τ"), - (0x1D74A, "M", "υ"), - (0x1D74B, "M", "φ"), - (0x1D74C, "M", "χ"), - (0x1D74D, "M", "ψ"), - (0x1D74E, "M", "ω"), - (0x1D74F, "M", "∂"), - (0x1D750, "M", "ε"), - (0x1D751, "M", "θ"), - (0x1D752, "M", "κ"), - (0x1D753, "M", "φ"), - (0x1D754, "M", "ρ"), - (0x1D755, "M", "π"), - (0x1D756, "M", "α"), - (0x1D757, "M", "β"), - (0x1D758, "M", "γ"), - (0x1D759, "M", "δ"), - (0x1D75A, "M", "ε"), - (0x1D75B, "M", "ζ"), - (0x1D75C, "M", "η"), - (0x1D75D, "M", "θ"), - (0x1D75E, "M", "ι"), - (0x1D75F, "M", "κ"), - (0x1D760, "M", "λ"), - (0x1D761, "M", "μ"), - (0x1D762, "M", "ν"), - (0x1D763, "M", "ξ"), - (0x1D764, "M", "ο"), - (0x1D765, "M", "π"), - (0x1D766, "M", "ρ"), - (0x1D767, "M", "θ"), - (0x1D768, "M", "σ"), - (0x1D769, "M", "τ"), - (0x1D76A, "M", "υ"), - (0x1D76B, "M", "φ"), - (0x1D76C, "M", "χ"), - (0x1D76D, "M", "ψ"), - (0x1D76E, "M", "ω"), - (0x1D76F, "M", "∇"), - (0x1D770, "M", "α"), - (0x1D771, "M", "β"), - (0x1D772, "M", "γ"), - (0x1D773, "M", "δ"), - (0x1D774, "M", "ε"), - (0x1D775, "M", "ζ"), - (0x1D776, "M", "η"), - (0x1D777, "M", "θ"), - (0x1D778, "M", "ι"), - (0x1D779, "M", "κ"), - (0x1D77A, "M", "λ"), - (0x1D77B, "M", "μ"), - (0x1D77C, "M", "ν"), - (0x1D77D, "M", "ξ"), - (0x1D77E, "M", "ο"), - (0x1D77F, "M", "π"), - (0x1D780, "M", "ρ"), - (0x1D781, "M", "σ"), - (0x1D783, "M", "τ"), - (0x1D784, "M", "υ"), - (0x1D785, "M", "φ"), - (0x1D786, "M", "χ"), - ] - - -def _seg_71() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D787, "M", "ψ"), - (0x1D788, "M", "ω"), - (0x1D789, "M", "∂"), - (0x1D78A, "M", "ε"), - (0x1D78B, "M", "θ"), - (0x1D78C, "M", "κ"), - (0x1D78D, "M", "φ"), - (0x1D78E, "M", "ρ"), - (0x1D78F, "M", "π"), - (0x1D790, "M", "α"), - (0x1D791, "M", "β"), - (0x1D792, "M", "γ"), - (0x1D793, "M", "δ"), - (0x1D794, "M", "ε"), - (0x1D795, "M", "ζ"), - (0x1D796, "M", "η"), - (0x1D797, "M", "θ"), - (0x1D798, "M", "ι"), - (0x1D799, "M", "κ"), - (0x1D79A, "M", "λ"), - (0x1D79B, "M", "μ"), - (0x1D79C, "M", "ν"), - (0x1D79D, "M", "ξ"), - (0x1D79E, "M", "ο"), - (0x1D79F, "M", "π"), - (0x1D7A0, "M", "ρ"), - (0x1D7A1, "M", "θ"), - (0x1D7A2, "M", "σ"), - (0x1D7A3, "M", "τ"), - (0x1D7A4, "M", "υ"), - (0x1D7A5, "M", "φ"), - (0x1D7A6, "M", "χ"), - (0x1D7A7, "M", "ψ"), - (0x1D7A8, "M", "ω"), - (0x1D7A9, "M", "∇"), - (0x1D7AA, "M", "α"), - (0x1D7AB, "M", "β"), - (0x1D7AC, "M", "γ"), - (0x1D7AD, "M", "δ"), - (0x1D7AE, "M", "ε"), - (0x1D7AF, "M", "ζ"), - (0x1D7B0, "M", "η"), - (0x1D7B1, "M", "θ"), - (0x1D7B2, "M", "ι"), - (0x1D7B3, "M", "κ"), - (0x1D7B4, "M", "λ"), - (0x1D7B5, "M", "μ"), - (0x1D7B6, "M", "ν"), - (0x1D7B7, "M", "ξ"), - (0x1D7B8, "M", "ο"), - (0x1D7B9, "M", "π"), - (0x1D7BA, "M", "ρ"), - (0x1D7BB, "M", "σ"), - (0x1D7BD, "M", "τ"), - (0x1D7BE, "M", "υ"), - (0x1D7BF, "M", "φ"), - (0x1D7C0, "M", "χ"), - (0x1D7C1, "M", "ψ"), - (0x1D7C2, "M", "ω"), - (0x1D7C3, "M", "∂"), - (0x1D7C4, "M", "ε"), - (0x1D7C5, "M", "θ"), - (0x1D7C6, "M", "κ"), - (0x1D7C7, "M", "φ"), - (0x1D7C8, "M", "ρ"), - (0x1D7C9, "M", "π"), - (0x1D7CA, "M", "ϝ"), - (0x1D7CC, "X"), - (0x1D7CE, "M", "0"), - (0x1D7CF, "M", "1"), - (0x1D7D0, "M", "2"), - (0x1D7D1, "M", "3"), - (0x1D7D2, "M", "4"), - (0x1D7D3, "M", "5"), - (0x1D7D4, "M", "6"), - (0x1D7D5, "M", "7"), - (0x1D7D6, "M", "8"), - (0x1D7D7, "M", "9"), - (0x1D7D8, "M", "0"), - (0x1D7D9, "M", "1"), - (0x1D7DA, "M", "2"), - (0x1D7DB, "M", "3"), - (0x1D7DC, "M", "4"), - (0x1D7DD, "M", "5"), - (0x1D7DE, "M", "6"), - (0x1D7DF, "M", "7"), - (0x1D7E0, "M", "8"), - (0x1D7E1, "M", "9"), - (0x1D7E2, "M", "0"), - (0x1D7E3, "M", "1"), - (0x1D7E4, "M", "2"), - (0x1D7E5, "M", "3"), - (0x1D7E6, "M", "4"), - (0x1D7E7, "M", "5"), - (0x1D7E8, "M", "6"), - (0x1D7E9, "M", "7"), - (0x1D7EA, "M", "8"), - (0x1D7EB, "M", "9"), - (0x1D7EC, "M", "0"), - (0x1D7ED, "M", "1"), - ] - - -def _seg_72() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1D7EE, "M", "2"), - (0x1D7EF, "M", "3"), - (0x1D7F0, "M", "4"), - (0x1D7F1, "M", "5"), - (0x1D7F2, "M", "6"), - (0x1D7F3, "M", "7"), - (0x1D7F4, "M", "8"), - (0x1D7F5, "M", "9"), - (0x1D7F6, "M", "0"), - (0x1D7F7, "M", "1"), - (0x1D7F8, "M", "2"), - (0x1D7F9, "M", "3"), - (0x1D7FA, "M", "4"), - (0x1D7FB, "M", "5"), - (0x1D7FC, "M", "6"), - (0x1D7FD, "M", "7"), - (0x1D7FE, "M", "8"), - (0x1D7FF, "M", "9"), - (0x1D800, "V"), - (0x1DA8C, "X"), - (0x1DA9B, "V"), - (0x1DAA0, "X"), - (0x1DAA1, "V"), - (0x1DAB0, "X"), - (0x1DF00, "V"), - (0x1DF1F, "X"), - (0x1DF25, "V"), - (0x1DF2B, "X"), - (0x1E000, "V"), - (0x1E007, "X"), - (0x1E008, "V"), - (0x1E019, "X"), - (0x1E01B, "V"), - (0x1E022, "X"), - (0x1E023, "V"), - (0x1E025, "X"), - (0x1E026, "V"), - (0x1E02B, "X"), - (0x1E030, "M", "а"), - (0x1E031, "M", "б"), - (0x1E032, "M", "в"), - (0x1E033, "M", "г"), - (0x1E034, "M", "д"), - (0x1E035, "M", "е"), - (0x1E036, "M", "ж"), - (0x1E037, "M", "з"), - (0x1E038, "M", "и"), - (0x1E039, "M", "к"), - (0x1E03A, "M", "л"), - (0x1E03B, "M", "м"), - (0x1E03C, "M", "о"), - (0x1E03D, "M", "п"), - (0x1E03E, "M", "р"), - (0x1E03F, "M", "с"), - (0x1E040, "M", "т"), - (0x1E041, "M", "у"), - (0x1E042, "M", "ф"), - (0x1E043, "M", "х"), - (0x1E044, "M", "ц"), - (0x1E045, "M", "ч"), - (0x1E046, "M", "ш"), - (0x1E047, "M", "ы"), - (0x1E048, "M", "э"), - (0x1E049, "M", "ю"), - (0x1E04A, "M", "ꚉ"), - (0x1E04B, "M", "ә"), - (0x1E04C, "M", "і"), - (0x1E04D, "M", "ј"), - (0x1E04E, "M", "ө"), - (0x1E04F, "M", "ү"), - (0x1E050, "M", "ӏ"), - (0x1E051, "M", "а"), - (0x1E052, "M", "б"), - (0x1E053, "M", "в"), - (0x1E054, "M", "г"), - (0x1E055, "M", "д"), - (0x1E056, "M", "е"), - (0x1E057, "M", "ж"), - (0x1E058, "M", "з"), - (0x1E059, "M", "и"), - (0x1E05A, "M", "к"), - (0x1E05B, "M", "л"), - (0x1E05C, "M", "о"), - (0x1E05D, "M", "п"), - (0x1E05E, "M", "с"), - (0x1E05F, "M", "у"), - (0x1E060, "M", "ф"), - (0x1E061, "M", "х"), - (0x1E062, "M", "ц"), - (0x1E063, "M", "ч"), - (0x1E064, "M", "ш"), - (0x1E065, "M", "ъ"), - (0x1E066, "M", "ы"), - (0x1E067, "M", "ґ"), - (0x1E068, "M", "і"), - (0x1E069, "M", "ѕ"), - (0x1E06A, "M", "џ"), - (0x1E06B, "M", "ҫ"), - (0x1E06C, "M", "ꙑ"), - (0x1E06D, "M", "ұ"), - ] - - -def _seg_73() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1E06E, "X"), - (0x1E08F, "V"), - (0x1E090, "X"), - (0x1E100, "V"), - (0x1E12D, "X"), - (0x1E130, "V"), - (0x1E13E, "X"), - (0x1E140, "V"), - (0x1E14A, "X"), - (0x1E14E, "V"), - (0x1E150, "X"), - (0x1E290, "V"), - (0x1E2AF, "X"), - (0x1E2C0, "V"), - (0x1E2FA, "X"), - (0x1E2FF, "V"), - (0x1E300, "X"), - (0x1E4D0, "V"), - (0x1E4FA, "X"), - (0x1E5D0, "V"), - (0x1E5FB, "X"), - (0x1E5FF, "V"), - (0x1E600, "X"), - (0x1E7E0, "V"), - (0x1E7E7, "X"), - (0x1E7E8, "V"), - (0x1E7EC, "X"), - (0x1E7ED, "V"), - (0x1E7EF, "X"), - (0x1E7F0, "V"), - (0x1E7FF, "X"), - (0x1E800, "V"), - (0x1E8C5, "X"), - (0x1E8C7, "V"), - (0x1E8D7, "X"), - (0x1E900, "M", "𞤢"), - (0x1E901, "M", "𞤣"), - (0x1E902, "M", "𞤤"), - (0x1E903, "M", "𞤥"), - (0x1E904, "M", "𞤦"), - (0x1E905, "M", "𞤧"), - (0x1E906, "M", "𞤨"), - (0x1E907, "M", "𞤩"), - (0x1E908, "M", "𞤪"), - (0x1E909, "M", "𞤫"), - (0x1E90A, "M", "𞤬"), - (0x1E90B, "M", "𞤭"), - (0x1E90C, "M", "𞤮"), - (0x1E90D, "M", "𞤯"), - (0x1E90E, "M", "𞤰"), - (0x1E90F, "M", "𞤱"), - (0x1E910, "M", "𞤲"), - (0x1E911, "M", "𞤳"), - (0x1E912, "M", "𞤴"), - (0x1E913, "M", "𞤵"), - (0x1E914, "M", "𞤶"), - (0x1E915, "M", "𞤷"), - (0x1E916, "M", "𞤸"), - (0x1E917, "M", "𞤹"), - (0x1E918, "M", "𞤺"), - (0x1E919, "M", "𞤻"), - (0x1E91A, "M", "𞤼"), - (0x1E91B, "M", "𞤽"), - (0x1E91C, "M", "𞤾"), - (0x1E91D, "M", "𞤿"), - (0x1E91E, "M", "𞥀"), - (0x1E91F, "M", "𞥁"), - (0x1E920, "M", "𞥂"), - (0x1E921, "M", "𞥃"), - (0x1E922, "V"), - (0x1E94C, "X"), - (0x1E950, "V"), - (0x1E95A, "X"), - (0x1E95E, "V"), - (0x1E960, "X"), - (0x1EC71, "V"), - (0x1ECB5, "X"), - (0x1ED01, "V"), - (0x1ED3E, "X"), - (0x1EE00, "M", "ا"), - (0x1EE01, "M", "ب"), - (0x1EE02, "M", "ج"), - (0x1EE03, "M", "د"), - (0x1EE04, "X"), - (0x1EE05, "M", "و"), - (0x1EE06, "M", "ز"), - (0x1EE07, "M", "ح"), - (0x1EE08, "M", "ط"), - (0x1EE09, "M", "ي"), - (0x1EE0A, "M", "ك"), - (0x1EE0B, "M", "ل"), - (0x1EE0C, "M", "م"), - (0x1EE0D, "M", "ن"), - (0x1EE0E, "M", "س"), - (0x1EE0F, "M", "ع"), - (0x1EE10, "M", "ف"), - (0x1EE11, "M", "ص"), - (0x1EE12, "M", "ق"), - (0x1EE13, "M", "ر"), - (0x1EE14, "M", "ش"), - ] - - -def _seg_74() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1EE15, "M", "ت"), - (0x1EE16, "M", "ث"), - (0x1EE17, "M", "خ"), - (0x1EE18, "M", "ذ"), - (0x1EE19, "M", "ض"), - (0x1EE1A, "M", "ظ"), - (0x1EE1B, "M", "غ"), - (0x1EE1C, "M", "ٮ"), - (0x1EE1D, "M", "ں"), - (0x1EE1E, "M", "ڡ"), - (0x1EE1F, "M", "ٯ"), - (0x1EE20, "X"), - (0x1EE21, "M", "ب"), - (0x1EE22, "M", "ج"), - (0x1EE23, "X"), - (0x1EE24, "M", "ه"), - (0x1EE25, "X"), - (0x1EE27, "M", "ح"), - (0x1EE28, "X"), - (0x1EE29, "M", "ي"), - (0x1EE2A, "M", "ك"), - (0x1EE2B, "M", "ل"), - (0x1EE2C, "M", "م"), - (0x1EE2D, "M", "ن"), - (0x1EE2E, "M", "س"), - (0x1EE2F, "M", "ع"), - (0x1EE30, "M", "ف"), - (0x1EE31, "M", "ص"), - (0x1EE32, "M", "ق"), - (0x1EE33, "X"), - (0x1EE34, "M", "ش"), - (0x1EE35, "M", "ت"), - (0x1EE36, "M", "ث"), - (0x1EE37, "M", "خ"), - (0x1EE38, "X"), - (0x1EE39, "M", "ض"), - (0x1EE3A, "X"), - (0x1EE3B, "M", "غ"), - (0x1EE3C, "X"), - (0x1EE42, "M", "ج"), - (0x1EE43, "X"), - (0x1EE47, "M", "ح"), - (0x1EE48, "X"), - (0x1EE49, "M", "ي"), - (0x1EE4A, "X"), - (0x1EE4B, "M", "ل"), - (0x1EE4C, "X"), - (0x1EE4D, "M", "ن"), - (0x1EE4E, "M", "س"), - (0x1EE4F, "M", "ع"), - (0x1EE50, "X"), - (0x1EE51, "M", "ص"), - (0x1EE52, "M", "ق"), - (0x1EE53, "X"), - (0x1EE54, "M", "ش"), - (0x1EE55, "X"), - (0x1EE57, "M", "خ"), - (0x1EE58, "X"), - (0x1EE59, "M", "ض"), - (0x1EE5A, "X"), - (0x1EE5B, "M", "غ"), - (0x1EE5C, "X"), - (0x1EE5D, "M", "ں"), - (0x1EE5E, "X"), - (0x1EE5F, "M", "ٯ"), - (0x1EE60, "X"), - (0x1EE61, "M", "ب"), - (0x1EE62, "M", "ج"), - (0x1EE63, "X"), - (0x1EE64, "M", "ه"), - (0x1EE65, "X"), - (0x1EE67, "M", "ح"), - (0x1EE68, "M", "ط"), - (0x1EE69, "M", "ي"), - (0x1EE6A, "M", "ك"), - (0x1EE6B, "X"), - (0x1EE6C, "M", "م"), - (0x1EE6D, "M", "ن"), - (0x1EE6E, "M", "س"), - (0x1EE6F, "M", "ع"), - (0x1EE70, "M", "ف"), - (0x1EE71, "M", "ص"), - (0x1EE72, "M", "ق"), - (0x1EE73, "X"), - (0x1EE74, "M", "ش"), - (0x1EE75, "M", "ت"), - (0x1EE76, "M", "ث"), - (0x1EE77, "M", "خ"), - (0x1EE78, "X"), - (0x1EE79, "M", "ض"), - (0x1EE7A, "M", "ظ"), - (0x1EE7B, "M", "غ"), - (0x1EE7C, "M", "ٮ"), - (0x1EE7D, "X"), - (0x1EE7E, "M", "ڡ"), - (0x1EE7F, "X"), - (0x1EE80, "M", "ا"), - (0x1EE81, "M", "ب"), - (0x1EE82, "M", "ج"), - (0x1EE83, "M", "د"), - ] - - -def _seg_75() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1EE84, "M", "ه"), - (0x1EE85, "M", "و"), - (0x1EE86, "M", "ز"), - (0x1EE87, "M", "ح"), - (0x1EE88, "M", "ط"), - (0x1EE89, "M", "ي"), - (0x1EE8A, "X"), - (0x1EE8B, "M", "ل"), - (0x1EE8C, "M", "م"), - (0x1EE8D, "M", "ن"), - (0x1EE8E, "M", "س"), - (0x1EE8F, "M", "ع"), - (0x1EE90, "M", "ف"), - (0x1EE91, "M", "ص"), - (0x1EE92, "M", "ق"), - (0x1EE93, "M", "ر"), - (0x1EE94, "M", "ش"), - (0x1EE95, "M", "ت"), - (0x1EE96, "M", "ث"), - (0x1EE97, "M", "خ"), - (0x1EE98, "M", "ذ"), - (0x1EE99, "M", "ض"), - (0x1EE9A, "M", "ظ"), - (0x1EE9B, "M", "غ"), - (0x1EE9C, "X"), - (0x1EEA1, "M", "ب"), - (0x1EEA2, "M", "ج"), - (0x1EEA3, "M", "د"), - (0x1EEA4, "X"), - (0x1EEA5, "M", "و"), - (0x1EEA6, "M", "ز"), - (0x1EEA7, "M", "ح"), - (0x1EEA8, "M", "ط"), - (0x1EEA9, "M", "ي"), - (0x1EEAA, "X"), - (0x1EEAB, "M", "ل"), - (0x1EEAC, "M", "م"), - (0x1EEAD, "M", "ن"), - (0x1EEAE, "M", "س"), - (0x1EEAF, "M", "ع"), - (0x1EEB0, "M", "ف"), - (0x1EEB1, "M", "ص"), - (0x1EEB2, "M", "ق"), - (0x1EEB3, "M", "ر"), - (0x1EEB4, "M", "ش"), - (0x1EEB5, "M", "ت"), - (0x1EEB6, "M", "ث"), - (0x1EEB7, "M", "خ"), - (0x1EEB8, "M", "ذ"), - (0x1EEB9, "M", "ض"), - (0x1EEBA, "M", "ظ"), - (0x1EEBB, "M", "غ"), - (0x1EEBC, "X"), - (0x1EEF0, "V"), - (0x1EEF2, "X"), - (0x1F000, "V"), - (0x1F02C, "X"), - (0x1F030, "V"), - (0x1F094, "X"), - (0x1F0A0, "V"), - (0x1F0AF, "X"), - (0x1F0B1, "V"), - (0x1F0C0, "X"), - (0x1F0C1, "V"), - (0x1F0D0, "X"), - (0x1F0D1, "V"), - (0x1F0F6, "X"), - (0x1F101, "M", "0,"), - (0x1F102, "M", "1,"), - (0x1F103, "M", "2,"), - (0x1F104, "M", "3,"), - (0x1F105, "M", "4,"), - (0x1F106, "M", "5,"), - (0x1F107, "M", "6,"), - (0x1F108, "M", "7,"), - (0x1F109, "M", "8,"), - (0x1F10A, "M", "9,"), - (0x1F10B, "V"), - (0x1F110, "M", "(a)"), - (0x1F111, "M", "(b)"), - (0x1F112, "M", "(c)"), - (0x1F113, "M", "(d)"), - (0x1F114, "M", "(e)"), - (0x1F115, "M", "(f)"), - (0x1F116, "M", "(g)"), - (0x1F117, "M", "(h)"), - (0x1F118, "M", "(i)"), - (0x1F119, "M", "(j)"), - (0x1F11A, "M", "(k)"), - (0x1F11B, "M", "(l)"), - (0x1F11C, "M", "(m)"), - (0x1F11D, "M", "(n)"), - (0x1F11E, "M", "(o)"), - (0x1F11F, "M", "(p)"), - (0x1F120, "M", "(q)"), - (0x1F121, "M", "(r)"), - (0x1F122, "M", "(s)"), - (0x1F123, "M", "(t)"), - (0x1F124, "M", "(u)"), - (0x1F125, "M", "(v)"), - ] - - -def _seg_76() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1F126, "M", "(w)"), - (0x1F127, "M", "(x)"), - (0x1F128, "M", "(y)"), - (0x1F129, "M", "(z)"), - (0x1F12A, "M", "〔s〕"), - (0x1F12B, "M", "c"), - (0x1F12C, "M", "r"), - (0x1F12D, "M", "cd"), - (0x1F12E, "M", "wz"), - (0x1F12F, "V"), - (0x1F130, "M", "a"), - (0x1F131, "M", "b"), - (0x1F132, "M", "c"), - (0x1F133, "M", "d"), - (0x1F134, "M", "e"), - (0x1F135, "M", "f"), - (0x1F136, "M", "g"), - (0x1F137, "M", "h"), - (0x1F138, "M", "i"), - (0x1F139, "M", "j"), - (0x1F13A, "M", "k"), - (0x1F13B, "M", "l"), - (0x1F13C, "M", "m"), - (0x1F13D, "M", "n"), - (0x1F13E, "M", "o"), - (0x1F13F, "M", "p"), - (0x1F140, "M", "q"), - (0x1F141, "M", "r"), - (0x1F142, "M", "s"), - (0x1F143, "M", "t"), - (0x1F144, "M", "u"), - (0x1F145, "M", "v"), - (0x1F146, "M", "w"), - (0x1F147, "M", "x"), - (0x1F148, "M", "y"), - (0x1F149, "M", "z"), - (0x1F14A, "M", "hv"), - (0x1F14B, "M", "mv"), - (0x1F14C, "M", "sd"), - (0x1F14D, "M", "ss"), - (0x1F14E, "M", "ppv"), - (0x1F14F, "M", "wc"), - (0x1F150, "V"), - (0x1F16A, "M", "mc"), - (0x1F16B, "M", "md"), - (0x1F16C, "M", "mr"), - (0x1F16D, "V"), - (0x1F190, "M", "dj"), - (0x1F191, "V"), - (0x1F1AE, "X"), - (0x1F1E6, "V"), - (0x1F200, "M", "ほか"), - (0x1F201, "M", "ココ"), - (0x1F202, "M", "サ"), - (0x1F203, "X"), - (0x1F210, "M", "手"), - (0x1F211, "M", "字"), - (0x1F212, "M", "双"), - (0x1F213, "M", "デ"), - (0x1F214, "M", "二"), - (0x1F215, "M", "多"), - (0x1F216, "M", "解"), - (0x1F217, "M", "天"), - (0x1F218, "M", "交"), - (0x1F219, "M", "映"), - (0x1F21A, "M", "無"), - (0x1F21B, "M", "料"), - (0x1F21C, "M", "前"), - (0x1F21D, "M", "後"), - (0x1F21E, "M", "再"), - (0x1F21F, "M", "新"), - (0x1F220, "M", "初"), - (0x1F221, "M", "終"), - (0x1F222, "M", "生"), - (0x1F223, "M", "販"), - (0x1F224, "M", "声"), - (0x1F225, "M", "吹"), - (0x1F226, "M", "演"), - (0x1F227, "M", "投"), - (0x1F228, "M", "捕"), - (0x1F229, "M", "一"), - (0x1F22A, "M", "三"), - (0x1F22B, "M", "遊"), - (0x1F22C, "M", "左"), - (0x1F22D, "M", "中"), - (0x1F22E, "M", "右"), - (0x1F22F, "M", "指"), - (0x1F230, "M", "走"), - (0x1F231, "M", "打"), - (0x1F232, "M", "禁"), - (0x1F233, "M", "空"), - (0x1F234, "M", "合"), - (0x1F235, "M", "満"), - (0x1F236, "M", "有"), - (0x1F237, "M", "月"), - (0x1F238, "M", "申"), - (0x1F239, "M", "割"), - (0x1F23A, "M", "営"), - (0x1F23B, "M", "配"), - (0x1F23C, "X"), - ] - - -def _seg_77() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x1F240, "M", "〔本〕"), - (0x1F241, "M", "〔三〕"), - (0x1F242, "M", "〔二〕"), - (0x1F243, "M", "〔安〕"), - (0x1F244, "M", "〔点〕"), - (0x1F245, "M", "〔打〕"), - (0x1F246, "M", "〔盗〕"), - (0x1F247, "M", "〔勝〕"), - (0x1F248, "M", "〔敗〕"), - (0x1F249, "X"), - (0x1F250, "M", "得"), - (0x1F251, "M", "可"), - (0x1F252, "X"), - (0x1F260, "V"), - (0x1F266, "X"), - (0x1F300, "V"), - (0x1F6D8, "X"), - (0x1F6DC, "V"), - (0x1F6ED, "X"), - (0x1F6F0, "V"), - (0x1F6FD, "X"), - (0x1F700, "V"), - (0x1F777, "X"), - (0x1F77B, "V"), - (0x1F7DA, "X"), - (0x1F7E0, "V"), - (0x1F7EC, "X"), - (0x1F7F0, "V"), - (0x1F7F1, "X"), - (0x1F800, "V"), - (0x1F80C, "X"), - (0x1F810, "V"), - (0x1F848, "X"), - (0x1F850, "V"), - (0x1F85A, "X"), - (0x1F860, "V"), - (0x1F888, "X"), - (0x1F890, "V"), - (0x1F8AE, "X"), - (0x1F8B0, "V"), - (0x1F8BC, "X"), - (0x1F8C0, "V"), - (0x1F8C2, "X"), - (0x1F900, "V"), - (0x1FA54, "X"), - (0x1FA60, "V"), - (0x1FA6E, "X"), - (0x1FA70, "V"), - (0x1FA7D, "X"), - (0x1FA80, "V"), - (0x1FA8A, "X"), - (0x1FA8F, "V"), - (0x1FAC7, "X"), - (0x1FACE, "V"), - (0x1FADD, "X"), - (0x1FADF, "V"), - (0x1FAEA, "X"), - (0x1FAF0, "V"), - (0x1FAF9, "X"), - (0x1FB00, "V"), - (0x1FB93, "X"), - (0x1FB94, "V"), - (0x1FBF0, "M", "0"), - (0x1FBF1, "M", "1"), - (0x1FBF2, "M", "2"), - (0x1FBF3, "M", "3"), - (0x1FBF4, "M", "4"), - (0x1FBF5, "M", "5"), - (0x1FBF6, "M", "6"), - (0x1FBF7, "M", "7"), - (0x1FBF8, "M", "8"), - (0x1FBF9, "M", "9"), - (0x1FBFA, "X"), - (0x20000, "V"), - (0x2A6E0, "X"), - (0x2A700, "V"), - (0x2B73A, "X"), - (0x2B740, "V"), - (0x2B81E, "X"), - (0x2B820, "V"), - (0x2CEA2, "X"), - (0x2CEB0, "V"), - (0x2EBE1, "X"), - (0x2EBF0, "V"), - (0x2EE5E, "X"), - (0x2F800, "M", "丽"), - (0x2F801, "M", "丸"), - (0x2F802, "M", "乁"), - (0x2F803, "M", "𠄢"), - (0x2F804, "M", "你"), - (0x2F805, "M", "侮"), - (0x2F806, "M", "侻"), - (0x2F807, "M", "倂"), - (0x2F808, "M", "偺"), - (0x2F809, "M", "備"), - (0x2F80A, "M", "僧"), - (0x2F80B, "M", "像"), - (0x2F80C, "M", "㒞"), - (0x2F80D, "M", "𠘺"), - (0x2F80E, "M", "免"), - ] - - -def _seg_78() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F80F, "M", "兔"), - (0x2F810, "M", "兤"), - (0x2F811, "M", "具"), - (0x2F812, "M", "𠔜"), - (0x2F813, "M", "㒹"), - (0x2F814, "M", "內"), - (0x2F815, "M", "再"), - (0x2F816, "M", "𠕋"), - (0x2F817, "M", "冗"), - (0x2F818, "M", "冤"), - (0x2F819, "M", "仌"), - (0x2F81A, "M", "冬"), - (0x2F81B, "M", "况"), - (0x2F81C, "M", "𩇟"), - (0x2F81D, "M", "凵"), - (0x2F81E, "M", "刃"), - (0x2F81F, "M", "㓟"), - (0x2F820, "M", "刻"), - (0x2F821, "M", "剆"), - (0x2F822, "M", "割"), - (0x2F823, "M", "剷"), - (0x2F824, "M", "㔕"), - (0x2F825, "M", "勇"), - (0x2F826, "M", "勉"), - (0x2F827, "M", "勤"), - (0x2F828, "M", "勺"), - (0x2F829, "M", "包"), - (0x2F82A, "M", "匆"), - (0x2F82B, "M", "北"), - (0x2F82C, "M", "卉"), - (0x2F82D, "M", "卑"), - (0x2F82E, "M", "博"), - (0x2F82F, "M", "即"), - (0x2F830, "M", "卽"), - (0x2F831, "M", "卿"), - (0x2F834, "M", "𠨬"), - (0x2F835, "M", "灰"), - (0x2F836, "M", "及"), - (0x2F837, "M", "叟"), - (0x2F838, "M", "𠭣"), - (0x2F839, "M", "叫"), - (0x2F83A, "M", "叱"), - (0x2F83B, "M", "吆"), - (0x2F83C, "M", "咞"), - (0x2F83D, "M", "吸"), - (0x2F83E, "M", "呈"), - (0x2F83F, "M", "周"), - (0x2F840, "M", "咢"), - (0x2F841, "M", "哶"), - (0x2F842, "M", "唐"), - (0x2F843, "M", "啓"), - (0x2F844, "M", "啣"), - (0x2F845, "M", "善"), - (0x2F847, "M", "喙"), - (0x2F848, "M", "喫"), - (0x2F849, "M", "喳"), - (0x2F84A, "M", "嗂"), - (0x2F84B, "M", "圖"), - (0x2F84C, "M", "嘆"), - (0x2F84D, "M", "圗"), - (0x2F84E, "M", "噑"), - (0x2F84F, "M", "噴"), - (0x2F850, "M", "切"), - (0x2F851, "M", "壮"), - (0x2F852, "M", "城"), - (0x2F853, "M", "埴"), - (0x2F854, "M", "堍"), - (0x2F855, "M", "型"), - (0x2F856, "M", "堲"), - (0x2F857, "M", "報"), - (0x2F858, "M", "墬"), - (0x2F859, "M", "𡓤"), - (0x2F85A, "M", "売"), - (0x2F85B, "M", "壷"), - (0x2F85C, "M", "夆"), - (0x2F85D, "M", "多"), - (0x2F85E, "M", "夢"), - (0x2F85F, "M", "奢"), - (0x2F860, "M", "𡚨"), - (0x2F861, "M", "𡛪"), - (0x2F862, "M", "姬"), - (0x2F863, "M", "娛"), - (0x2F864, "M", "娧"), - (0x2F865, "M", "姘"), - (0x2F866, "M", "婦"), - (0x2F867, "M", "㛮"), - (0x2F868, "M", "㛼"), - (0x2F869, "M", "嬈"), - (0x2F86A, "M", "嬾"), - (0x2F86C, "M", "𡧈"), - (0x2F86D, "M", "寃"), - (0x2F86E, "M", "寘"), - (0x2F86F, "M", "寧"), - (0x2F870, "M", "寳"), - (0x2F871, "M", "𡬘"), - (0x2F872, "M", "寿"), - (0x2F873, "M", "将"), - (0x2F874, "M", "当"), - (0x2F875, "M", "尢"), - (0x2F876, "M", "㞁"), - ] - - -def _seg_79() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F877, "M", "屠"), - (0x2F878, "M", "屮"), - (0x2F879, "M", "峀"), - (0x2F87A, "M", "岍"), - (0x2F87B, "M", "𡷤"), - (0x2F87C, "M", "嵃"), - (0x2F87D, "M", "𡷦"), - (0x2F87E, "M", "嵮"), - (0x2F87F, "M", "嵫"), - (0x2F880, "M", "嵼"), - (0x2F881, "M", "巡"), - (0x2F882, "M", "巢"), - (0x2F883, "M", "㠯"), - (0x2F884, "M", "巽"), - (0x2F885, "M", "帨"), - (0x2F886, "M", "帽"), - (0x2F887, "M", "幩"), - (0x2F888, "M", "㡢"), - (0x2F889, "M", "𢆃"), - (0x2F88A, "M", "㡼"), - (0x2F88B, "M", "庰"), - (0x2F88C, "M", "庳"), - (0x2F88D, "M", "庶"), - (0x2F88E, "M", "廊"), - (0x2F88F, "M", "𪎒"), - (0x2F890, "M", "廾"), - (0x2F891, "M", "𢌱"), - (0x2F893, "M", "舁"), - (0x2F894, "M", "弢"), - (0x2F896, "M", "㣇"), - (0x2F897, "M", "𣊸"), - (0x2F898, "M", "𦇚"), - (0x2F899, "M", "形"), - (0x2F89A, "M", "彫"), - (0x2F89B, "M", "㣣"), - (0x2F89C, "M", "徚"), - (0x2F89D, "M", "忍"), - (0x2F89E, "M", "志"), - (0x2F89F, "M", "忹"), - (0x2F8A0, "M", "悁"), - (0x2F8A1, "M", "㤺"), - (0x2F8A2, "M", "㤜"), - (0x2F8A3, "M", "悔"), - (0x2F8A4, "M", "𢛔"), - (0x2F8A5, "M", "惇"), - (0x2F8A6, "M", "慈"), - (0x2F8A7, "M", "慌"), - (0x2F8A8, "M", "慎"), - (0x2F8A9, "M", "慌"), - (0x2F8AA, "M", "慺"), - (0x2F8AB, "M", "憎"), - (0x2F8AC, "M", "憲"), - (0x2F8AD, "M", "憤"), - (0x2F8AE, "M", "憯"), - (0x2F8AF, "M", "懞"), - (0x2F8B0, "M", "懲"), - (0x2F8B1, "M", "懶"), - (0x2F8B2, "M", "成"), - (0x2F8B3, "M", "戛"), - (0x2F8B4, "M", "扝"), - (0x2F8B5, "M", "抱"), - (0x2F8B6, "M", "拔"), - (0x2F8B7, "M", "捐"), - (0x2F8B8, "M", "𢬌"), - (0x2F8B9, "M", "挽"), - (0x2F8BA, "M", "拼"), - (0x2F8BB, "M", "捨"), - (0x2F8BC, "M", "掃"), - (0x2F8BD, "M", "揤"), - (0x2F8BE, "M", "𢯱"), - (0x2F8BF, "M", "搢"), - (0x2F8C0, "M", "揅"), - (0x2F8C1, "M", "掩"), - (0x2F8C2, "M", "㨮"), - (0x2F8C3, "M", "摩"), - (0x2F8C4, "M", "摾"), - (0x2F8C5, "M", "撝"), - (0x2F8C6, "M", "摷"), - (0x2F8C7, "M", "㩬"), - (0x2F8C8, "M", "敏"), - (0x2F8C9, "M", "敬"), - (0x2F8CA, "M", "𣀊"), - (0x2F8CB, "M", "旣"), - (0x2F8CC, "M", "書"), - (0x2F8CD, "M", "晉"), - (0x2F8CE, "M", "㬙"), - (0x2F8CF, "M", "暑"), - (0x2F8D0, "M", "㬈"), - (0x2F8D1, "M", "㫤"), - (0x2F8D2, "M", "冒"), - (0x2F8D3, "M", "冕"), - (0x2F8D4, "M", "最"), - (0x2F8D5, "M", "暜"), - (0x2F8D6, "M", "肭"), - (0x2F8D7, "M", "䏙"), - (0x2F8D8, "M", "朗"), - (0x2F8D9, "M", "望"), - (0x2F8DA, "M", "朡"), - (0x2F8DB, "M", "杞"), - (0x2F8DC, "M", "杓"), - ] - - -def _seg_80() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F8DD, "M", "𣏃"), - (0x2F8DE, "M", "㭉"), - (0x2F8DF, "M", "柺"), - (0x2F8E0, "M", "枅"), - (0x2F8E1, "M", "桒"), - (0x2F8E2, "M", "梅"), - (0x2F8E3, "M", "𣑭"), - (0x2F8E4, "M", "梎"), - (0x2F8E5, "M", "栟"), - (0x2F8E6, "M", "椔"), - (0x2F8E7, "M", "㮝"), - (0x2F8E8, "M", "楂"), - (0x2F8E9, "M", "榣"), - (0x2F8EA, "M", "槪"), - (0x2F8EB, "M", "檨"), - (0x2F8EC, "M", "𣚣"), - (0x2F8ED, "M", "櫛"), - (0x2F8EE, "M", "㰘"), - (0x2F8EF, "M", "次"), - (0x2F8F0, "M", "𣢧"), - (0x2F8F1, "M", "歔"), - (0x2F8F2, "M", "㱎"), - (0x2F8F3, "M", "歲"), - (0x2F8F4, "M", "殟"), - (0x2F8F5, "M", "殺"), - (0x2F8F6, "M", "殻"), - (0x2F8F7, "M", "𣪍"), - (0x2F8F8, "M", "𡴋"), - (0x2F8F9, "M", "𣫺"), - (0x2F8FA, "M", "汎"), - (0x2F8FB, "M", "𣲼"), - (0x2F8FC, "M", "沿"), - (0x2F8FD, "M", "泍"), - (0x2F8FE, "M", "汧"), - (0x2F8FF, "M", "洖"), - (0x2F900, "M", "派"), - (0x2F901, "M", "海"), - (0x2F902, "M", "流"), - (0x2F903, "M", "浩"), - (0x2F904, "M", "浸"), - (0x2F905, "M", "涅"), - (0x2F906, "M", "𣴞"), - (0x2F907, "M", "洴"), - (0x2F908, "M", "港"), - (0x2F909, "M", "湮"), - (0x2F90A, "M", "㴳"), - (0x2F90B, "M", "滋"), - (0x2F90C, "M", "滇"), - (0x2F90D, "M", "𣻑"), - (0x2F90E, "M", "淹"), - (0x2F90F, "M", "潮"), - (0x2F910, "M", "𣽞"), - (0x2F911, "M", "𣾎"), - (0x2F912, "M", "濆"), - (0x2F913, "M", "瀹"), - (0x2F914, "M", "瀞"), - (0x2F915, "M", "瀛"), - (0x2F916, "M", "㶖"), - (0x2F917, "M", "灊"), - (0x2F918, "M", "災"), - (0x2F919, "M", "灷"), - (0x2F91A, "M", "炭"), - (0x2F91B, "M", "𠔥"), - (0x2F91C, "M", "煅"), - (0x2F91D, "M", "𤉣"), - (0x2F91E, "M", "熜"), - (0x2F91F, "M", "𤎫"), - (0x2F920, "M", "爨"), - (0x2F921, "M", "爵"), - (0x2F922, "M", "牐"), - (0x2F923, "M", "𤘈"), - (0x2F924, "M", "犀"), - (0x2F925, "M", "犕"), - (0x2F926, "M", "𤜵"), - (0x2F927, "M", "𤠔"), - (0x2F928, "M", "獺"), - (0x2F929, "M", "王"), - (0x2F92A, "M", "㺬"), - (0x2F92B, "M", "玥"), - (0x2F92C, "M", "㺸"), - (0x2F92E, "M", "瑇"), - (0x2F92F, "M", "瑜"), - (0x2F930, "M", "瑱"), - (0x2F931, "M", "璅"), - (0x2F932, "M", "瓊"), - (0x2F933, "M", "㼛"), - (0x2F934, "M", "甤"), - (0x2F935, "M", "𤰶"), - (0x2F936, "M", "甾"), - (0x2F937, "M", "𤲒"), - (0x2F938, "M", "異"), - (0x2F939, "M", "𢆟"), - (0x2F93A, "M", "瘐"), - (0x2F93B, "M", "𤾡"), - (0x2F93C, "M", "𤾸"), - (0x2F93D, "M", "𥁄"), - (0x2F93E, "M", "㿼"), - (0x2F93F, "M", "䀈"), - (0x2F940, "M", "直"), - (0x2F941, "M", "𥃳"), - ] - - -def _seg_81() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F942, "M", "𥃲"), - (0x2F943, "M", "𥄙"), - (0x2F944, "M", "𥄳"), - (0x2F945, "M", "眞"), - (0x2F946, "M", "真"), - (0x2F948, "M", "睊"), - (0x2F949, "M", "䀹"), - (0x2F94A, "M", "瞋"), - (0x2F94B, "M", "䁆"), - (0x2F94C, "M", "䂖"), - (0x2F94D, "M", "𥐝"), - (0x2F94E, "M", "硎"), - (0x2F94F, "M", "碌"), - (0x2F950, "M", "磌"), - (0x2F951, "M", "䃣"), - (0x2F952, "M", "𥘦"), - (0x2F953, "M", "祖"), - (0x2F954, "M", "𥚚"), - (0x2F955, "M", "𥛅"), - (0x2F956, "M", "福"), - (0x2F957, "M", "秫"), - (0x2F958, "M", "䄯"), - (0x2F959, "M", "穀"), - (0x2F95A, "M", "穊"), - (0x2F95B, "M", "穏"), - (0x2F95C, "M", "𥥼"), - (0x2F95D, "M", "𥪧"), - (0x2F95F, "M", "竮"), - (0x2F960, "M", "䈂"), - (0x2F961, "M", "𥮫"), - (0x2F962, "M", "篆"), - (0x2F963, "M", "築"), - (0x2F964, "M", "䈧"), - (0x2F965, "M", "𥲀"), - (0x2F966, "M", "糒"), - (0x2F967, "M", "䊠"), - (0x2F968, "M", "糨"), - (0x2F969, "M", "糣"), - (0x2F96A, "M", "紀"), - (0x2F96B, "M", "𥾆"), - (0x2F96C, "M", "絣"), - (0x2F96D, "M", "䌁"), - (0x2F96E, "M", "緇"), - (0x2F96F, "M", "縂"), - (0x2F970, "M", "繅"), - (0x2F971, "M", "䌴"), - (0x2F972, "M", "𦈨"), - (0x2F973, "M", "𦉇"), - (0x2F974, "M", "䍙"), - (0x2F975, "M", "𦋙"), - (0x2F976, "M", "罺"), - (0x2F977, "M", "𦌾"), - (0x2F978, "M", "羕"), - (0x2F979, "M", "翺"), - (0x2F97A, "M", "者"), - (0x2F97B, "M", "𦓚"), - (0x2F97C, "M", "𦔣"), - (0x2F97D, "M", "聠"), - (0x2F97E, "M", "𦖨"), - (0x2F97F, "M", "聰"), - (0x2F980, "M", "𣍟"), - (0x2F981, "M", "䏕"), - (0x2F982, "M", "育"), - (0x2F983, "M", "脃"), - (0x2F984, "M", "䐋"), - (0x2F985, "M", "脾"), - (0x2F986, "M", "媵"), - (0x2F987, "M", "𦞧"), - (0x2F988, "M", "𦞵"), - (0x2F989, "M", "𣎓"), - (0x2F98A, "M", "𣎜"), - (0x2F98B, "M", "舁"), - (0x2F98C, "M", "舄"), - (0x2F98D, "M", "辞"), - (0x2F98E, "M", "䑫"), - (0x2F98F, "M", "芑"), - (0x2F990, "M", "芋"), - (0x2F991, "M", "芝"), - (0x2F992, "M", "劳"), - (0x2F993, "M", "花"), - (0x2F994, "M", "芳"), - (0x2F995, "M", "芽"), - (0x2F996, "M", "苦"), - (0x2F997, "M", "𦬼"), - (0x2F998, "M", "若"), - (0x2F999, "M", "茝"), - (0x2F99A, "M", "荣"), - (0x2F99B, "M", "莭"), - (0x2F99C, "M", "茣"), - (0x2F99D, "M", "莽"), - (0x2F99E, "M", "菧"), - (0x2F99F, "M", "著"), - (0x2F9A0, "M", "荓"), - (0x2F9A1, "M", "菊"), - (0x2F9A2, "M", "菌"), - (0x2F9A3, "M", "菜"), - (0x2F9A4, "M", "𦰶"), - (0x2F9A5, "M", "𦵫"), - (0x2F9A6, "M", "𦳕"), - (0x2F9A7, "M", "䔫"), - ] - - -def _seg_82() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2F9A8, "M", "蓱"), - (0x2F9A9, "M", "蓳"), - (0x2F9AA, "M", "蔖"), - (0x2F9AB, "M", "𧏊"), - (0x2F9AC, "M", "蕤"), - (0x2F9AD, "M", "𦼬"), - (0x2F9AE, "M", "䕝"), - (0x2F9AF, "M", "䕡"), - (0x2F9B0, "M", "𦾱"), - (0x2F9B1, "M", "𧃒"), - (0x2F9B2, "M", "䕫"), - (0x2F9B3, "M", "虐"), - (0x2F9B4, "M", "虜"), - (0x2F9B5, "M", "虧"), - (0x2F9B6, "M", "虩"), - (0x2F9B7, "M", "蚩"), - (0x2F9B8, "M", "蚈"), - (0x2F9B9, "M", "蜎"), - (0x2F9BA, "M", "蛢"), - (0x2F9BB, "M", "蝹"), - (0x2F9BC, "M", "蜨"), - (0x2F9BD, "M", "蝫"), - (0x2F9BE, "M", "螆"), - (0x2F9BF, "M", "䗗"), - (0x2F9C0, "M", "蟡"), - (0x2F9C1, "M", "蠁"), - (0x2F9C2, "M", "䗹"), - (0x2F9C3, "M", "衠"), - (0x2F9C4, "M", "衣"), - (0x2F9C5, "M", "𧙧"), - (0x2F9C6, "M", "裗"), - (0x2F9C7, "M", "裞"), - (0x2F9C8, "M", "䘵"), - (0x2F9C9, "M", "裺"), - (0x2F9CA, "M", "㒻"), - (0x2F9CB, "M", "𧢮"), - (0x2F9CC, "M", "𧥦"), - (0x2F9CD, "M", "䚾"), - (0x2F9CE, "M", "䛇"), - (0x2F9CF, "M", "誠"), - (0x2F9D0, "M", "諭"), - (0x2F9D1, "M", "變"), - (0x2F9D2, "M", "豕"), - (0x2F9D3, "M", "𧲨"), - (0x2F9D4, "M", "貫"), - (0x2F9D5, "M", "賁"), - (0x2F9D6, "M", "贛"), - (0x2F9D7, "M", "起"), - (0x2F9D8, "M", "𧼯"), - (0x2F9D9, "M", "𠠄"), - (0x2F9DA, "M", "跋"), - (0x2F9DB, "M", "趼"), - (0x2F9DC, "M", "跰"), - (0x2F9DD, "M", "𠣞"), - (0x2F9DE, "M", "軔"), - (0x2F9DF, "M", "輸"), - (0x2F9E0, "M", "𨗒"), - (0x2F9E1, "M", "𨗭"), - (0x2F9E2, "M", "邔"), - (0x2F9E3, "M", "郱"), - (0x2F9E4, "M", "鄑"), - (0x2F9E5, "M", "𨜮"), - (0x2F9E6, "M", "鄛"), - (0x2F9E7, "M", "鈸"), - (0x2F9E8, "M", "鋗"), - (0x2F9E9, "M", "鋘"), - (0x2F9EA, "M", "鉼"), - (0x2F9EB, "M", "鏹"), - (0x2F9EC, "M", "鐕"), - (0x2F9ED, "M", "𨯺"), - (0x2F9EE, "M", "開"), - (0x2F9EF, "M", "䦕"), - (0x2F9F0, "M", "閷"), - (0x2F9F1, "M", "𨵷"), - (0x2F9F2, "M", "䧦"), - (0x2F9F3, "M", "雃"), - (0x2F9F4, "M", "嶲"), - (0x2F9F5, "M", "霣"), - (0x2F9F6, "M", "𩅅"), - (0x2F9F7, "M", "𩈚"), - (0x2F9F8, "M", "䩮"), - (0x2F9F9, "M", "䩶"), - (0x2F9FA, "M", "韠"), - (0x2F9FB, "M", "𩐊"), - (0x2F9FC, "M", "䪲"), - (0x2F9FD, "M", "𩒖"), - (0x2F9FE, "M", "頋"), - (0x2FA00, "M", "頩"), - (0x2FA01, "M", "𩖶"), - (0x2FA02, "M", "飢"), - (0x2FA03, "M", "䬳"), - (0x2FA04, "M", "餩"), - (0x2FA05, "M", "馧"), - (0x2FA06, "M", "駂"), - (0x2FA07, "M", "駾"), - (0x2FA08, "M", "䯎"), - (0x2FA09, "M", "𩬰"), - (0x2FA0A, "M", "鬒"), - (0x2FA0B, "M", "鱀"), - (0x2FA0C, "M", "鳽"), - ] - - -def _seg_83() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]: - return [ - (0x2FA0D, "M", "䳎"), - (0x2FA0E, "M", "䳭"), - (0x2FA0F, "M", "鵧"), - (0x2FA10, "M", "𪃎"), - (0x2FA11, "M", "䳸"), - (0x2FA12, "M", "𪄅"), - (0x2FA13, "M", "𪈎"), - (0x2FA14, "M", "𪊑"), - (0x2FA15, "M", "麻"), - (0x2FA16, "M", "䵖"), - (0x2FA17, "M", "黹"), - (0x2FA18, "M", "黾"), - (0x2FA19, "M", "鼅"), - (0x2FA1A, "M", "鼏"), - (0x2FA1B, "M", "鼖"), - (0x2FA1C, "M", "鼻"), - (0x2FA1D, "M", "𪘀"), - (0x2FA1E, "X"), - (0x30000, "V"), - (0x3134B, "X"), - (0x31350, "V"), - (0x323B0, "X"), - (0xE0100, "I"), - (0xE01F0, "X"), - ] - - -uts46data = tuple( - _seg_0() - + _seg_1() - + _seg_2() - + _seg_3() - + _seg_4() - + _seg_5() - + _seg_6() - + _seg_7() - + _seg_8() - + _seg_9() - + _seg_10() - + _seg_11() - + _seg_12() - + _seg_13() - + _seg_14() - + _seg_15() - + _seg_16() - + _seg_17() - + _seg_18() - + _seg_19() - + _seg_20() - + _seg_21() - + _seg_22() - + _seg_23() - + _seg_24() - + _seg_25() - + _seg_26() - + _seg_27() - + _seg_28() - + _seg_29() - + _seg_30() - + _seg_31() - + _seg_32() - + _seg_33() - + _seg_34() - + _seg_35() - + _seg_36() - + _seg_37() - + _seg_38() - + _seg_39() - + _seg_40() - + _seg_41() - + _seg_42() - + _seg_43() - + _seg_44() - + _seg_45() - + _seg_46() - + _seg_47() - + _seg_48() - + _seg_49() - + _seg_50() - + _seg_51() - + _seg_52() - + _seg_53() - + _seg_54() - + _seg_55() - + _seg_56() - + _seg_57() - + _seg_58() - + _seg_59() - + _seg_60() - + _seg_61() - + _seg_62() - + _seg_63() - + _seg_64() - + _seg_65() - + _seg_66() - + _seg_67() - + _seg_68() - + _seg_69() - + _seg_70() - + _seg_71() - + _seg_72() - + _seg_73() - + _seg_74() - + _seg_75() - + _seg_76() - + _seg_77() - + _seg_78() - + _seg_79() - + _seg_80() - + _seg_81() - + _seg_82() - + _seg_83() -) # type: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...] diff --git a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/METADATA deleted file mode 100644 index 2664347..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/METADATA +++ /dev/null @@ -1,145 +0,0 @@ -Metadata-Version: 2.4 -Name: jiter -Version: 0.12.0 -Classifier: Development Status :: 4 - Beta -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: GraalPy -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: Unix -Classifier: Operating System :: POSIX :: Linux -Classifier: Environment :: Console -Classifier: Environment :: MacOS X -Classifier: Topic :: File Formats :: JSON -Classifier: Framework :: Pydantic :: 2 -License-File: LICENSE -Summary: Fast iterable JSON parser. -Home-Page: https://github.com/pydantic/jiter/ -Author-email: Samuel Colvin -Requires-Python: >=3.9 -Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM - -# jiter - -[![CI](https://github.com/pydantic/jiter/workflows/CI/badge.svg?event=push)](https://github.com/pydantic/jiter/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) -[![pypi](https://img.shields.io/pypi/v/jiter.svg)](https://pypi.python.org/pypi/jiter) -[![versions](https://img.shields.io/pypi/pyversions/jiter.svg)](https://github.com/pydantic/jiter) -[![license](https://img.shields.io/github/license/pydantic/jiter.svg)](https://github.com/pydantic/jiter/blob/main/LICENSE) - -This is a standalone version of the JSON parser used in `pydantic-core`. The recommendation is to only use this package directly if you do not use `pydantic`. - -The API is extremely minimal: - -```python -def from_json( - json_data: bytes, - /, - *, - allow_inf_nan: bool = True, - cache_mode: Literal[True, False, "all", "keys", "none"] = "all", - partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False, - catch_duplicate_keys: bool = False, - float_mode: Literal["float", "decimal", "lossless-float"] = "float", -) -> Any: - """ - Parse input bytes into a JSON object. - - Arguments: - json_data: The JSON data to parse - allow_inf_nan: Whether to allow infinity (`Infinity` an `-Infinity`) and `NaN` values to float fields. - Defaults to True. - cache_mode: cache Python strings to improve performance at the cost of some memory usage - - True / 'all' - cache all strings - - 'keys' - cache only object keys - - False / 'none' - cache nothing - partial_mode: How to handle incomplete strings: - - False / 'off' - raise an exception if the input is incomplete - - True / 'on' - allow incomplete JSON but discard the last string if it is incomplete - - 'trailing-strings' - allow incomplete JSON, and include the last incomplete string in the output - catch_duplicate_keys: if True, raise an exception if objects contain the same key multiple times - float_mode: How to return floats: as a `float`, `Decimal` or `LosslessFloat` - - Returns: - Python object built from the JSON input. - """ - -def cache_clear() -> None: - """ - Reset the string cache. - """ - -def cache_usage() -> int: - """ - get the size of the string cache. - - Returns: - Size of the string cache in bytes. - """ -``` -## Examples - -The main function provided by Jiter is `from_json()`, which accepts a bytes object containing JSON and returns a Python dictionary, list or other value. - -```python -import jiter - -json_data = b'{"name": "John", "age": 30}' -parsed_data = jiter.from_json(json_data) -print(parsed_data) # Output: {'name': 'John', 'age': 30} -``` - -### Handling Partial JSON - -Incomplete JSON objects can be parsed using the `partial_mode=` parameter. - -```python -import jiter - -partial_json = b'{"name": "John", "age": 30, "city": "New Yor' - -# Raise error on incomplete JSON -try: - jiter.from_json(partial_json, partial_mode=False) -except ValueError as e: - print(f"Error: {e}") - -# Parse incomplete JSON, discarding incomplete last field -result = jiter.from_json(partial_json, partial_mode=True) -print(result) # Output: {'name': 'John', 'age': 30} - -# Parse incomplete JSON, including incomplete last field -result = jiter.from_json(partial_json, partial_mode='trailing-strings') -print(result) # Output: {'name': 'John', 'age': 30, 'city': 'New Yor'} -``` - -### Catching Duplicate Keys - -The `catch_duplicate_keys=True` option can be used to raise a `ValueError` if an object contains duplicate keys. - -```python -import jiter - -json_with_dupes = b'{"foo": 1, "foo": 2}' - -# Default behavior (last value wins) -result = jiter.from_json(json_with_dupes) -print(result) # Output: {'foo': 2} - -# Catch duplicate keys -try: - jiter.from_json(json_with_dupes, catch_duplicate_keys=True) -except ValueError as e: - print(f"Error: {e}") -``` - diff --git a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/RECORD deleted file mode 100644 index 635754d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/jiter/__init__.cpython-39.pyc,, -jiter-0.12.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -jiter-0.12.0.dist-info/METADATA,sha256=10Z_sFkT8XSgEEhYVlpuKSg-UcSVuOx_BeLi7CqhaWA,5236 -jiter-0.12.0.dist-info/RECORD,, -jiter-0.12.0.dist-info/WHEEL,sha256=h9rAUYPeg3gmvhtRVJK2olpWoMu_nXm2QhP6XS97iM8,102 -jiter-0.12.0.dist-info/licenses/LICENSE,sha256=fHE0ufe5eMA_yodVF885jbkfGbu4EJtmhedCqj9XRo4,1091 -jiter/__init__.py,sha256=Fp9HkOixiYYDSiC_80vmiJ_sCoCGT8OAh48yltm0lP0,103 -jiter/__init__.pyi,sha256=IXJ5QM8oWahamu-erWyWfk4hDX-K7ZJvyoZi8jLV0nQ,2365 -jiter/jiter.cpython-39-darwin.so,sha256=pkrwIloBd7m0YLdrgSC9yDTEzRHf39vuk6Id5jVCJfM,783104 -jiter/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/WHEEL deleted file mode 100644 index 7e9b051..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.9.6) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_11_0_arm64 diff --git a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/licenses/LICENSE deleted file mode 100644 index 47de40d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter-0.12.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2022 to present Samuel Colvin - -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. diff --git a/backend/venv39/lib/python3.9/site-packages/jiter/__init__.py b/backend/venv39/lib/python3.9/site-packages/jiter/__init__.py deleted file mode 100644 index 3d17192..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .jiter import * - -__doc__ = jiter.__doc__ -if hasattr(jiter, "__all__"): - __all__ = jiter.__all__ \ No newline at end of file diff --git a/backend/venv39/lib/python3.9/site-packages/jiter/__init__.pyi b/backend/venv39/lib/python3.9/site-packages/jiter/__init__.pyi deleted file mode 100644 index ab488b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jiter/__init__.pyi +++ /dev/null @@ -1,70 +0,0 @@ -import decimal -from typing import Any, Literal - -def from_json( - json_data: bytes, - /, - *, - allow_inf_nan: bool = True, - cache_mode: Literal[True, False, "all", "keys", "none"] = "all", - partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False, - catch_duplicate_keys: bool = False, - float_mode: Literal["float", "decimal", "lossless-float"] = "float", -) -> Any: - """ - Parse input bytes into a JSON object. - - Arguments: - json_data: The JSON data to parse - allow_inf_nan: Whether to allow infinity (`Infinity` an `-Infinity`) and `NaN` values to float fields. - Defaults to True. - cache_mode: cache Python strings to improve performance at the cost of some memory usage - - True / 'all' - cache all strings - - 'keys' - cache only object keys - - False / 'none' - cache nothing - partial_mode: How to handle incomplete strings: - - False / 'off' - raise an exception if the input is incomplete - - True / 'on' - allow incomplete JSON but discard the last string if it is incomplete - - 'trailing-strings' - allow incomplete JSON, and include the last incomplete string in the output - catch_duplicate_keys: if True, raise an exception if objects contain the same key multiple times - float_mode: How to return floats: as a `float`, `Decimal` or `LosslessFloat` - - Returns: - Python object built from the JSON input. - """ - -def cache_clear() -> None: - """ - Reset the string cache. - """ - -def cache_usage() -> int: - """ - get the size of the string cache. - - Returns: - Size of the string cache in bytes. - """ - - -class LosslessFloat: - """ - Represents a float from JSON, by holding the underlying bytes representing a float from JSON. - """ - def __init__(self, json_float: bytes): - """Construct a LosslessFloat object from a JSON bytes slice""" - - def as_decimal(self) -> decimal.Decimal: - """Construct a Python Decimal from the JSON bytes slice""" - - def __float__(self) -> float: - """Construct a Python float from the JSON bytes slice""" - - def __bytes__(self) -> bytes: - """Return the JSON bytes slice as bytes""" - - def __str__(self): - """Return the JSON bytes slice as a string""" - - def __repr__(self): - ... diff --git a/backend/venv39/lib/python3.9/site-packages/jiter/jiter.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/jiter/jiter.cpython-39-darwin.so deleted file mode 100755 index 7850d94..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/jiter/jiter.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/jiter/py.typed b/backend/venv39/lib/python3.9/site-packages/jiter/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/jose/__init__.py b/backend/venv39/lib/python3.9/site-packages/jose/__init__.py deleted file mode 100644 index 7e53b60..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -__version__ = "3.5.0" -__author__ = "Michael Davis" -__license__ = "MIT" -__copyright__ = "Copyright 2016 Michael Davis" - - -from .exceptions import ExpiredSignatureError # noqa: F401 -from .exceptions import JOSEError # noqa: F401 -from .exceptions import JWSError # noqa: F401 -from .exceptions import JWTError # noqa: F401 diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/__init__.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/__init__.py deleted file mode 100644 index 9918969..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -from jose.backends.native import get_random_bytes # noqa: F401 - -try: - from jose.backends.cryptography_backend import CryptographyRSAKey as RSAKey # noqa: F401 -except ImportError: - try: - from jose.backends.rsa_backend import RSAKey # noqa: F401 - except ImportError: - RSAKey = None - -try: - from jose.backends.cryptography_backend import CryptographyECKey as ECKey # noqa: F401 -except ImportError: - from jose.backends.ecdsa_backend import ECDSAECKey as ECKey # noqa: F401 - -try: - from jose.backends.cryptography_backend import CryptographyAESKey as AESKey # noqa: F401 -except ImportError: - AESKey = None - -try: - from jose.backends.cryptography_backend import CryptographyHMACKey as HMACKey # noqa: F401 -except ImportError: - from jose.backends.native import HMACKey # noqa: F401 - -from .base import DIRKey # noqa: F401 diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/_asn1.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/_asn1.py deleted file mode 100644 index 87e3df1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/_asn1.py +++ /dev/null @@ -1,84 +0,0 @@ -"""ASN1 encoding helpers for converting between PKCS1 and PKCS8. - -Required by rsa_backend but not cryptography_backend. -""" - -from pyasn1.codec.der import decoder, encoder -from pyasn1.type import namedtype, univ - -RSA_ENCRYPTION_ASN1_OID = "1.2.840.113549.1.1.1" - - -class RsaAlgorithmIdentifier(univ.Sequence): - """ASN1 structure for recording RSA PrivateKeyAlgorithm identifiers.""" - - componentType = namedtype.NamedTypes( - namedtype.NamedType("rsaEncryption", univ.ObjectIdentifier()), namedtype.NamedType("parameters", univ.Null()) - ) - - -class PKCS8PrivateKey(univ.Sequence): - """ASN1 structure for recording PKCS8 private keys.""" - - componentType = namedtype.NamedTypes( - namedtype.NamedType("version", univ.Integer()), - namedtype.NamedType("privateKeyAlgorithm", RsaAlgorithmIdentifier()), - namedtype.NamedType("privateKey", univ.OctetString()), - ) - - -class PublicKeyInfo(univ.Sequence): - """ASN1 structure for recording PKCS8 public keys.""" - - componentType = namedtype.NamedTypes( - namedtype.NamedType("algorithm", RsaAlgorithmIdentifier()), namedtype.NamedType("publicKey", univ.BitString()) - ) - - -def rsa_private_key_pkcs8_to_pkcs1(pkcs8_key): - """Convert a PKCS8-encoded RSA private key to PKCS1.""" - decoded_values = decoder.decode(pkcs8_key, asn1Spec=PKCS8PrivateKey()) - - try: - decoded_key = decoded_values[0] - except IndexError: - raise ValueError("Invalid private key encoding") - - return decoded_key["privateKey"] - - -def rsa_private_key_pkcs1_to_pkcs8(pkcs1_key): - """Convert a PKCS1-encoded RSA private key to PKCS8.""" - algorithm = RsaAlgorithmIdentifier() - algorithm["rsaEncryption"] = RSA_ENCRYPTION_ASN1_OID - - pkcs8_key = PKCS8PrivateKey() - pkcs8_key["version"] = 0 - pkcs8_key["privateKeyAlgorithm"] = algorithm - pkcs8_key["privateKey"] = pkcs1_key - - return encoder.encode(pkcs8_key) - - -def rsa_public_key_pkcs1_to_pkcs8(pkcs1_key): - """Convert a PKCS1-encoded RSA private key to PKCS8.""" - algorithm = RsaAlgorithmIdentifier() - algorithm["rsaEncryption"] = RSA_ENCRYPTION_ASN1_OID - - pkcs8_key = PublicKeyInfo() - pkcs8_key["algorithm"] = algorithm - pkcs8_key["publicKey"] = univ.BitString.fromOctetString(pkcs1_key) - - return encoder.encode(pkcs8_key) - - -def rsa_public_key_pkcs8_to_pkcs1(pkcs8_key): - """Convert a PKCS8-encoded RSA private key to PKCS1.""" - decoded_values = decoder.decode(pkcs8_key, asn1Spec=PublicKeyInfo()) - - try: - decoded_key = decoded_values[0] - except IndexError: - raise ValueError("Invalid public key encoding.") - - return decoded_key["publicKey"].asOctets() diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/base.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/base.py deleted file mode 100644 index b000a52..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/base.py +++ /dev/null @@ -1,89 +0,0 @@ -from ..utils import base64url_encode, ensure_binary - - -class Key: - """ - A simple interface for implementing JWK keys. - """ - - def __init__(self, key, algorithm): - pass - - def sign(self, msg): - raise NotImplementedError() - - def verify(self, msg, sig): - raise NotImplementedError() - - def public_key(self): - raise NotImplementedError() - - def to_pem(self): - raise NotImplementedError() - - def to_dict(self): - raise NotImplementedError() - - def encrypt(self, plain_text, aad=None): - """ - Encrypt the plain text and generate an auth tag if appropriate - - Args: - plain_text (bytes): Data to encrypt - aad (bytes, optional): Authenticated Additional Data if key's algorithm supports auth mode - - Returns: - (bytes, bytes, bytes): IV, cipher text, and auth tag - """ - raise NotImplementedError() - - def decrypt(self, cipher_text, iv=None, aad=None, tag=None): - """ - Decrypt the cipher text and validate the auth tag if present - Args: - cipher_text (bytes): Cipher text to decrypt - iv (bytes): IV if block mode - aad (bytes): Additional Authenticated Data to verify if auth mode - tag (bytes): Authentication tag if auth mode - - Returns: - bytes: Decrypted value - """ - raise NotImplementedError() - - def wrap_key(self, key_data): - """ - Wrap the the plain text key data - - Args: - key_data (bytes): Key data to wrap - - Returns: - bytes: Wrapped key - """ - raise NotImplementedError() - - def unwrap_key(self, wrapped_key): - """ - Unwrap the the wrapped key data - - Args: - wrapped_key (bytes): Wrapped key data to unwrap - - Returns: - bytes: Unwrapped key - """ - raise NotImplementedError() - - -class DIRKey(Key): - def __init__(self, key_data, algorithm): - self._key = ensure_binary(key_data) - self._alg = algorithm - - def to_dict(self): - return { - "alg": self._alg, - "kty": "oct", - "k": base64url_encode(self._key), - } diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/cryptography_backend.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/cryptography_backend.py deleted file mode 100644 index ec836b4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/cryptography_backend.py +++ /dev/null @@ -1,586 +0,0 @@ -import math -import warnings - -from cryptography.exceptions import InvalidSignature, InvalidTag -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes, hmac, serialization -from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa -from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature, encode_dss_signature -from cryptography.hazmat.primitives.ciphers import Cipher, aead, algorithms, modes -from cryptography.hazmat.primitives.keywrap import InvalidUnwrap, aes_key_unwrap, aes_key_wrap -from cryptography.hazmat.primitives.padding import PKCS7 -from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key -from cryptography.utils import int_to_bytes -from cryptography.x509 import load_pem_x509_certificate - -from ..constants import ALGORITHMS -from ..exceptions import JWEError, JWKError -from ..utils import ( - base64_to_long, - base64url_decode, - base64url_encode, - ensure_binary, - is_pem_format, - is_ssh_key, - long_to_base64, -) -from . import get_random_bytes -from .base import Key - -_binding = None - - -class CryptographyECKey(Key): - SHA256 = hashes.SHA256 - SHA384 = hashes.SHA384 - SHA512 = hashes.SHA512 - - def __init__(self, key, algorithm, cryptography_backend=default_backend): - if algorithm not in ALGORITHMS.EC: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - - self.hash_alg = { - ALGORITHMS.ES256: self.SHA256, - ALGORITHMS.ES384: self.SHA384, - ALGORITHMS.ES512: self.SHA512, - }.get(algorithm) - self._algorithm = algorithm - - self.cryptography_backend = cryptography_backend - - if hasattr(key, "public_bytes") or hasattr(key, "private_bytes"): - self.prepared_key = key - return - - if hasattr(key, "to_pem"): - # convert to PEM and let cryptography below load it as PEM - key = key.to_pem().decode("utf-8") - - if isinstance(key, dict): - self.prepared_key = self._process_jwk(key) - return - - if isinstance(key, str): - key = key.encode("utf-8") - - if isinstance(key, bytes): - # Attempt to load key. We don't know if it's - # a Public Key or a Private Key, so we try - # the Public Key first. - try: - try: - key = load_pem_public_key(key, self.cryptography_backend()) - except ValueError: - key = load_pem_private_key(key, password=None, backend=self.cryptography_backend()) - except Exception as e: - raise JWKError(e) - - self.prepared_key = key - return - - raise JWKError("Unable to parse an ECKey from key: %s" % key) - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "EC": - raise JWKError("Incorrect key type. Expected: 'EC', Received: %s" % jwk_dict.get("kty")) - - if not all(k in jwk_dict for k in ["x", "y", "crv"]): - raise JWKError("Mandatory parameters are missing") - - x = base64_to_long(jwk_dict.get("x")) - y = base64_to_long(jwk_dict.get("y")) - curve = { - "P-256": ec.SECP256R1, - "P-384": ec.SECP384R1, - "P-521": ec.SECP521R1, - }[jwk_dict["crv"]] - - public = ec.EllipticCurvePublicNumbers(x, y, curve()) - - if "d" in jwk_dict: - d = base64_to_long(jwk_dict.get("d")) - private = ec.EllipticCurvePrivateNumbers(d, public) - - return private.private_key(self.cryptography_backend()) - else: - return public.public_key(self.cryptography_backend()) - - def _sig_component_length(self): - """Determine the correct serialization length for an encoded signature component. - - This is the number of bytes required to encode the maximum key value. - """ - return int(math.ceil(self.prepared_key.key_size / 8.0)) - - def _der_to_raw(self, der_signature): - """Convert signature from DER encoding to RAW encoding.""" - r, s = decode_dss_signature(der_signature) - component_length = self._sig_component_length() - return int_to_bytes(r, component_length) + int_to_bytes(s, component_length) - - def _raw_to_der(self, raw_signature): - """Convert signature from RAW encoding to DER encoding.""" - component_length = self._sig_component_length() - if len(raw_signature) != int(2 * component_length): - raise ValueError("Invalid signature") - - r_bytes = raw_signature[:component_length] - s_bytes = raw_signature[component_length:] - r = int.from_bytes(r_bytes, "big") - s = int.from_bytes(s_bytes, "big") - return encode_dss_signature(r, s) - - def sign(self, msg): - if self.hash_alg.digest_size * 8 > self.prepared_key.curve.key_size: - raise TypeError( - "this curve (%s) is too short " - "for your digest (%d)" % (self.prepared_key.curve.name, 8 * self.hash_alg.digest_size) - ) - signature = self.prepared_key.sign(msg, ec.ECDSA(self.hash_alg())) - return self._der_to_raw(signature) - - def verify(self, msg, sig): - try: - signature = self._raw_to_der(sig) - self.prepared_key.verify(signature, msg, ec.ECDSA(self.hash_alg())) - return True - except Exception: - return False - - def is_public(self): - return hasattr(self.prepared_key, "public_bytes") - - def public_key(self): - if self.is_public(): - return self - return self.__class__(self.prepared_key.public_key(), self._algorithm) - - def to_pem(self): - if self.is_public(): - pem = self.prepared_key.public_bytes( - encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo - ) - return pem - pem = self.prepared_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.NoEncryption(), - ) - return pem - - def to_dict(self): - if not self.is_public(): - public_key = self.prepared_key.public_key() - else: - public_key = self.prepared_key - - crv = { - "secp256r1": "P-256", - "secp384r1": "P-384", - "secp521r1": "P-521", - }[self.prepared_key.curve.name] - - # Calculate the key size in bytes. Section 6.2.1.2 and 6.2.1.3 of - # RFC7518 prescribes that the 'x', 'y' and 'd' parameters of the curve - # points must be encoded as octed-strings of this length. - key_size = (self.prepared_key.curve.key_size + 7) // 8 - - data = { - "alg": self._algorithm, - "kty": "EC", - "crv": crv, - "x": long_to_base64(public_key.public_numbers().x, size=key_size).decode("ASCII"), - "y": long_to_base64(public_key.public_numbers().y, size=key_size).decode("ASCII"), - } - - if not self.is_public(): - private_value = self.prepared_key.private_numbers().private_value - data["d"] = long_to_base64(private_value, size=key_size).decode("ASCII") - - return data - - -class CryptographyRSAKey(Key): - SHA256 = hashes.SHA256 - SHA384 = hashes.SHA384 - SHA512 = hashes.SHA512 - - RSA1_5 = padding.PKCS1v15() - RSA_OAEP = padding.OAEP(padding.MGF1(hashes.SHA1()), hashes.SHA1(), None) - RSA_OAEP_256 = padding.OAEP(padding.MGF1(hashes.SHA256()), hashes.SHA256(), None) - - def __init__(self, key, algorithm, cryptography_backend=default_backend): - if algorithm not in ALGORITHMS.RSA: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - - self.hash_alg = { - ALGORITHMS.RS256: self.SHA256, - ALGORITHMS.RS384: self.SHA384, - ALGORITHMS.RS512: self.SHA512, - }.get(algorithm) - self._algorithm = algorithm - - self.padding = { - ALGORITHMS.RSA1_5: self.RSA1_5, - ALGORITHMS.RSA_OAEP: self.RSA_OAEP, - ALGORITHMS.RSA_OAEP_256: self.RSA_OAEP_256, - }.get(algorithm) - - self.cryptography_backend = cryptography_backend - - # if it conforms to RSAPublicKey or RSAPrivateKey interface - if (hasattr(key, "public_bytes") and hasattr(key, "public_numbers")) or hasattr(key, "private_bytes"): - self.prepared_key = key - return - - if isinstance(key, dict): - self.prepared_key = self._process_jwk(key) - return - - if isinstance(key, str): - key = key.encode("utf-8") - - if isinstance(key, bytes): - try: - if key.startswith(b"-----BEGIN CERTIFICATE-----"): - self._process_cert(key) - return - - try: - self.prepared_key = load_pem_public_key(key, self.cryptography_backend()) - except ValueError: - self.prepared_key = load_pem_private_key(key, password=None, backend=self.cryptography_backend()) - except Exception as e: - raise JWKError(e) - return - - raise JWKError("Unable to parse an RSA_JWK from key: %s" % key) - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "RSA": - raise JWKError("Incorrect key type. Expected: 'RSA', Received: %s" % jwk_dict.get("kty")) - - e = base64_to_long(jwk_dict.get("e", 256)) - n = base64_to_long(jwk_dict.get("n")) - public = rsa.RSAPublicNumbers(e, n) - - if "d" not in jwk_dict: - return public.public_key(self.cryptography_backend()) - else: - # This is a private key. - d = base64_to_long(jwk_dict.get("d")) - - extra_params = ["p", "q", "dp", "dq", "qi"] - - if any(k in jwk_dict for k in extra_params): - # Precomputed private key parameters are available. - if not all(k in jwk_dict for k in extra_params): - # These values must be present when 'p' is according to - # Section 6.3.2 of RFC7518, so if they are not we raise - # an error. - raise JWKError("Precomputed private key parameters are incomplete.") - - p = base64_to_long(jwk_dict["p"]) - q = base64_to_long(jwk_dict["q"]) - dp = base64_to_long(jwk_dict["dp"]) - dq = base64_to_long(jwk_dict["dq"]) - qi = base64_to_long(jwk_dict["qi"]) - else: - # The precomputed private key parameters are not available, - # so we use cryptography's API to fill them in. - p, q = rsa.rsa_recover_prime_factors(n, e, d) - dp = rsa.rsa_crt_dmp1(d, p) - dq = rsa.rsa_crt_dmq1(d, q) - qi = rsa.rsa_crt_iqmp(p, q) - - private = rsa.RSAPrivateNumbers(p, q, d, dp, dq, qi, public) - - return private.private_key(self.cryptography_backend()) - - def _process_cert(self, key): - key = load_pem_x509_certificate(key, self.cryptography_backend()) - self.prepared_key = key.public_key() - - def sign(self, msg): - try: - signature = self.prepared_key.sign(msg, padding.PKCS1v15(), self.hash_alg()) - except Exception as e: - raise JWKError(e) - return signature - - def verify(self, msg, sig): - if not self.is_public(): - warnings.warn("Attempting to verify a message with a private key. " "This is not recommended.") - - try: - self.public_key().prepared_key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg()) - return True - except InvalidSignature: - return False - - def is_public(self): - return hasattr(self.prepared_key, "public_bytes") - - def public_key(self): - if self.is_public(): - return self - return self.__class__(self.prepared_key.public_key(), self._algorithm) - - def to_pem(self, pem_format="PKCS8"): - if self.is_public(): - if pem_format == "PKCS8": - fmt = serialization.PublicFormat.SubjectPublicKeyInfo - elif pem_format == "PKCS1": - fmt = serialization.PublicFormat.PKCS1 - else: - raise ValueError("Invalid format specified: %r" % pem_format) - pem = self.prepared_key.public_bytes(encoding=serialization.Encoding.PEM, format=fmt) - return pem - - if pem_format == "PKCS8": - fmt = serialization.PrivateFormat.PKCS8 - elif pem_format == "PKCS1": - fmt = serialization.PrivateFormat.TraditionalOpenSSL - else: - raise ValueError("Invalid format specified: %r" % pem_format) - - return self.prepared_key.private_bytes( - encoding=serialization.Encoding.PEM, format=fmt, encryption_algorithm=serialization.NoEncryption() - ) - - def to_dict(self): - if not self.is_public(): - public_key = self.prepared_key.public_key() - else: - public_key = self.prepared_key - - data = { - "alg": self._algorithm, - "kty": "RSA", - "n": long_to_base64(public_key.public_numbers().n).decode("ASCII"), - "e": long_to_base64(public_key.public_numbers().e).decode("ASCII"), - } - - if not self.is_public(): - data.update( - { - "d": long_to_base64(self.prepared_key.private_numbers().d).decode("ASCII"), - "p": long_to_base64(self.prepared_key.private_numbers().p).decode("ASCII"), - "q": long_to_base64(self.prepared_key.private_numbers().q).decode("ASCII"), - "dp": long_to_base64(self.prepared_key.private_numbers().dmp1).decode("ASCII"), - "dq": long_to_base64(self.prepared_key.private_numbers().dmq1).decode("ASCII"), - "qi": long_to_base64(self.prepared_key.private_numbers().iqmp).decode("ASCII"), - } - ) - - return data - - def wrap_key(self, key_data): - try: - wrapped_key = self.prepared_key.encrypt(key_data, self.padding) - except Exception as e: - raise JWEError(e) - - return wrapped_key - - def unwrap_key(self, wrapped_key): - try: - unwrapped_key = self.prepared_key.decrypt(wrapped_key, self.padding) - return unwrapped_key - except Exception as e: - raise JWEError(e) - - -class CryptographyAESKey(Key): - KEY_128 = (ALGORITHMS.A128GCM, ALGORITHMS.A128GCMKW, ALGORITHMS.A128KW, ALGORITHMS.A128CBC) - KEY_192 = (ALGORITHMS.A192GCM, ALGORITHMS.A192GCMKW, ALGORITHMS.A192KW, ALGORITHMS.A192CBC) - KEY_256 = ( - ALGORITHMS.A256GCM, - ALGORITHMS.A256GCMKW, - ALGORITHMS.A256KW, - ALGORITHMS.A128CBC_HS256, - ALGORITHMS.A256CBC, - ) - KEY_384 = (ALGORITHMS.A192CBC_HS384,) - KEY_512 = (ALGORITHMS.A256CBC_HS512,) - - AES_KW_ALGS = (ALGORITHMS.A128KW, ALGORITHMS.A192KW, ALGORITHMS.A256KW) - - MODES = { - ALGORITHMS.A128GCM: modes.GCM, - ALGORITHMS.A192GCM: modes.GCM, - ALGORITHMS.A256GCM: modes.GCM, - ALGORITHMS.A128CBC_HS256: modes.CBC, - ALGORITHMS.A192CBC_HS384: modes.CBC, - ALGORITHMS.A256CBC_HS512: modes.CBC, - ALGORITHMS.A128CBC: modes.CBC, - ALGORITHMS.A192CBC: modes.CBC, - ALGORITHMS.A256CBC: modes.CBC, - ALGORITHMS.A128GCMKW: modes.GCM, - ALGORITHMS.A192GCMKW: modes.GCM, - ALGORITHMS.A256GCMKW: modes.GCM, - ALGORITHMS.A128KW: None, - ALGORITHMS.A192KW: None, - ALGORITHMS.A256KW: None, - } - - IV_BYTE_LENGTH_MODE_MAP = {"CBC": algorithms.AES.block_size // 8, "GCM": 96 // 8} - - def __init__(self, key, algorithm): - if algorithm not in ALGORITHMS.AES: - raise JWKError("%s is not a valid AES algorithm" % algorithm) - if algorithm not in ALGORITHMS.SUPPORTED.union(ALGORITHMS.AES_PSEUDO): - raise JWKError("%s is not a supported algorithm" % algorithm) - - self._algorithm = algorithm - self._mode = self.MODES.get(self._algorithm) - - if algorithm in self.KEY_128 and len(key) != 16: - raise JWKError(f"Key must be 128 bit for alg {algorithm}") - elif algorithm in self.KEY_192 and len(key) != 24: - raise JWKError(f"Key must be 192 bit for alg {algorithm}") - elif algorithm in self.KEY_256 and len(key) != 32: - raise JWKError(f"Key must be 256 bit for alg {algorithm}") - elif algorithm in self.KEY_384 and len(key) != 48: - raise JWKError(f"Key must be 384 bit for alg {algorithm}") - elif algorithm in self.KEY_512 and len(key) != 64: - raise JWKError(f"Key must be 512 bit for alg {algorithm}") - - self._key = key - - def to_dict(self): - data = {"alg": self._algorithm, "kty": "oct", "k": base64url_encode(self._key)} - return data - - def encrypt(self, plain_text, aad=None): - plain_text = ensure_binary(plain_text) - try: - iv_byte_length = self.IV_BYTE_LENGTH_MODE_MAP.get(self._mode.name, algorithms.AES.block_size) - iv = get_random_bytes(iv_byte_length) - mode = self._mode(iv) - if mode.name == "GCM": - cipher = aead.AESGCM(self._key) - cipher_text_and_tag = cipher.encrypt(iv, plain_text, aad) - cipher_text = cipher_text_and_tag[: len(cipher_text_and_tag) - 16] - auth_tag = cipher_text_and_tag[-16:] - else: - cipher = Cipher(algorithms.AES(self._key), mode, backend=default_backend()) - encryptor = cipher.encryptor() - padder = PKCS7(algorithms.AES.block_size).padder() - padded_data = padder.update(plain_text) - padded_data += padder.finalize() - cipher_text = encryptor.update(padded_data) + encryptor.finalize() - auth_tag = None - return iv, cipher_text, auth_tag - except Exception as e: - raise JWEError(e) - - def decrypt(self, cipher_text, iv=None, aad=None, tag=None): - cipher_text = ensure_binary(cipher_text) - try: - iv = ensure_binary(iv) - mode = self._mode(iv) - if mode.name == "GCM": - if tag is None: - raise ValueError("tag cannot be None") - cipher = aead.AESGCM(self._key) - cipher_text_and_tag = cipher_text + tag - try: - plain_text = cipher.decrypt(iv, cipher_text_and_tag, aad) - except InvalidTag: - raise JWEError("Invalid JWE Auth Tag") - else: - cipher = Cipher(algorithms.AES(self._key), mode, backend=default_backend()) - decryptor = cipher.decryptor() - padded_plain_text = decryptor.update(cipher_text) - padded_plain_text += decryptor.finalize() - unpadder = PKCS7(algorithms.AES.block_size).unpadder() - plain_text = unpadder.update(padded_plain_text) - plain_text += unpadder.finalize() - - return plain_text - except Exception as e: - raise JWEError(e) - - def wrap_key(self, key_data): - key_data = ensure_binary(key_data) - cipher_text = aes_key_wrap(self._key, key_data, default_backend()) - return cipher_text # IV, cipher text, auth tag - - def unwrap_key(self, wrapped_key): - wrapped_key = ensure_binary(wrapped_key) - try: - plain_text = aes_key_unwrap(self._key, wrapped_key, default_backend()) - except InvalidUnwrap as cause: - raise JWEError(cause) - return plain_text - - -class CryptographyHMACKey(Key): - """ - Performs signing and verification operations using HMAC - and the specified hash function. - """ - - ALG_MAP = {ALGORITHMS.HS256: hashes.SHA256(), ALGORITHMS.HS384: hashes.SHA384(), ALGORITHMS.HS512: hashes.SHA512()} - - def __init__(self, key, algorithm): - if algorithm not in ALGORITHMS.HMAC: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - self._algorithm = algorithm - self._hash_alg = self.ALG_MAP.get(algorithm) - - if isinstance(key, dict): - self.prepared_key = self._process_jwk(key) - return - - if not isinstance(key, str) and not isinstance(key, bytes): - raise JWKError("Expecting a string- or bytes-formatted key.") - - if isinstance(key, str): - key = key.encode("utf-8") - - if is_pem_format(key) or is_ssh_key(key): - raise JWKError( - "The specified key is an asymmetric key or x509 certificate and" - " should not be used as an HMAC secret." - ) - - self.prepared_key = key - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "oct": - raise JWKError("Incorrect key type. Expected: 'oct', Received: %s" % jwk_dict.get("kty")) - - k = jwk_dict.get("k") - k = k.encode("utf-8") - k = bytes(k) - k = base64url_decode(k) - - return k - - def to_dict(self): - return { - "alg": self._algorithm, - "kty": "oct", - "k": base64url_encode(self.prepared_key).decode("ASCII"), - } - - def sign(self, msg): - msg = ensure_binary(msg) - h = hmac.HMAC(self.prepared_key, self._hash_alg, backend=default_backend()) - h.update(msg) - signature = h.finalize() - return signature - - def verify(self, msg, sig): - msg = ensure_binary(msg) - sig = ensure_binary(sig) - h = hmac.HMAC(self.prepared_key, self._hash_alg, backend=default_backend()) - h.update(msg) - try: - h.verify(sig) - verified = True - except InvalidSignature: - verified = False - return verified diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/ecdsa_backend.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/ecdsa_backend.py deleted file mode 100644 index 756c7ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/ecdsa_backend.py +++ /dev/null @@ -1,150 +0,0 @@ -import hashlib - -import ecdsa - -from jose.backends.base import Key -from jose.constants import ALGORITHMS -from jose.exceptions import JWKError -from jose.utils import base64_to_long, long_to_base64 - - -class ECDSAECKey(Key): - """ - Performs signing and verification operations using - ECDSA and the specified hash function - - This class requires the ecdsa package to be installed. - - This is based off of the implementation in PyJWT 0.3.2 - """ - - SHA256 = hashlib.sha256 - SHA384 = hashlib.sha384 - SHA512 = hashlib.sha512 - - CURVE_MAP = { - SHA256: ecdsa.curves.NIST256p, - SHA384: ecdsa.curves.NIST384p, - SHA512: ecdsa.curves.NIST521p, - } - CURVE_NAMES = ( - (ecdsa.curves.NIST256p, "P-256"), - (ecdsa.curves.NIST384p, "P-384"), - (ecdsa.curves.NIST521p, "P-521"), - ) - - def __init__(self, key, algorithm): - if algorithm not in ALGORITHMS.EC: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - - self.hash_alg = { - ALGORITHMS.ES256: self.SHA256, - ALGORITHMS.ES384: self.SHA384, - ALGORITHMS.ES512: self.SHA512, - }.get(algorithm) - self._algorithm = algorithm - - self.curve = self.CURVE_MAP.get(self.hash_alg) - - if isinstance(key, (ecdsa.SigningKey, ecdsa.VerifyingKey)): - self.prepared_key = key - return - - if isinstance(key, dict): - self.prepared_key = self._process_jwk(key) - return - - if isinstance(key, str): - key = key.encode("utf-8") - - if isinstance(key, bytes): - # Attempt to load key. We don't know if it's - # a Signing Key or a Verifying Key, so we try - # the Verifying Key first. - try: - key = ecdsa.VerifyingKey.from_pem(key) - except ecdsa.der.UnexpectedDER: - key = ecdsa.SigningKey.from_pem(key) - except Exception as e: - raise JWKError(e) - - self.prepared_key = key - return - - raise JWKError("Unable to parse an ECKey from key: %s" % key) - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "EC": - raise JWKError("Incorrect key type. Expected: 'EC', Received: %s" % jwk_dict.get("kty")) - - if not all(k in jwk_dict for k in ["x", "y", "crv"]): - raise JWKError("Mandatory parameters are missing") - - if "d" in jwk_dict: - # We are dealing with a private key; the secret exponent is enough - # to create an ecdsa key. - d = base64_to_long(jwk_dict.get("d")) - return ecdsa.keys.SigningKey.from_secret_exponent(d, self.curve) - else: - x = base64_to_long(jwk_dict.get("x")) - y = base64_to_long(jwk_dict.get("y")) - - if not ecdsa.ecdsa.point_is_valid(self.curve.generator, x, y): - raise JWKError(f"Point: {x}, {y} is not a valid point") - - point = ecdsa.ellipticcurve.Point(self.curve.curve, x, y, self.curve.order) - return ecdsa.keys.VerifyingKey.from_public_point(point, self.curve) - - def sign(self, msg): - return self.prepared_key.sign( - msg, hashfunc=self.hash_alg, sigencode=ecdsa.util.sigencode_string, allow_truncate=False - ) - - def verify(self, msg, sig): - try: - return self.prepared_key.verify( - sig, msg, hashfunc=self.hash_alg, sigdecode=ecdsa.util.sigdecode_string, allow_truncate=False - ) - except Exception: - return False - - def is_public(self): - return isinstance(self.prepared_key, ecdsa.VerifyingKey) - - def public_key(self): - if self.is_public(): - return self - return self.__class__(self.prepared_key.get_verifying_key(), self._algorithm) - - def to_pem(self): - return self.prepared_key.to_pem() - - def to_dict(self): - if not self.is_public(): - public_key = self.prepared_key.get_verifying_key() - else: - public_key = self.prepared_key - crv = None - for key, value in self.CURVE_NAMES: - if key == self.prepared_key.curve: - crv = value - if not crv: - raise KeyError(f"Can't match {self.prepared_key.curve}") - - # Calculate the key size in bytes. Section 6.2.1.2 and 6.2.1.3 of - # RFC7518 prescribes that the 'x', 'y' and 'd' parameters of the curve - # points must be encoded as octed-strings of this length. - key_size = self.prepared_key.curve.baselen - - data = { - "alg": self._algorithm, - "kty": "EC", - "crv": crv, - "x": long_to_base64(public_key.pubkey.point.x(), size=key_size).decode("ASCII"), - "y": long_to_base64(public_key.pubkey.point.y(), size=key_size).decode("ASCII"), - } - - if not self.is_public(): - data["d"] = long_to_base64(self.prepared_key.privkey.secret_multiplier, size=key_size).decode("ASCII") - - return data diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/native.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/native.py deleted file mode 100644 index 8cc77da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/native.py +++ /dev/null @@ -1,69 +0,0 @@ -import hashlib -import hmac -import os - -from jose.backends.base import Key -from jose.constants import ALGORITHMS -from jose.exceptions import JWKError -from jose.utils import base64url_decode, base64url_encode, is_pem_format, is_ssh_key - - -def get_random_bytes(num_bytes): - return bytes(os.urandom(num_bytes)) - - -class HMACKey(Key): - """ - Performs signing and verification operations using HMAC - and the specified hash function. - """ - - HASHES = {ALGORITHMS.HS256: hashlib.sha256, ALGORITHMS.HS384: hashlib.sha384, ALGORITHMS.HS512: hashlib.sha512} - - def __init__(self, key, algorithm): - if algorithm not in ALGORITHMS.HMAC: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - self._algorithm = algorithm - self._hash_alg = self.HASHES.get(algorithm) - - if isinstance(key, dict): - self.prepared_key = self._process_jwk(key) - return - - if not isinstance(key, str) and not isinstance(key, bytes): - raise JWKError("Expecting a string- or bytes-formatted key.") - - if isinstance(key, str): - key = key.encode("utf-8") - - if is_pem_format(key) or is_ssh_key(key): - raise JWKError( - "The specified key is an asymmetric key or x509 certificate and" - " should not be used as an HMAC secret." - ) - - self.prepared_key = key - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "oct": - raise JWKError("Incorrect key type. Expected: 'oct', Received: %s" % jwk_dict.get("kty")) - - k = jwk_dict.get("k") - k = k.encode("utf-8") - k = bytes(k) - k = base64url_decode(k) - - return k - - def sign(self, msg): - return hmac.new(self.prepared_key, msg, self._hash_alg).digest() - - def verify(self, msg, sig): - return hmac.compare_digest(sig, self.sign(msg)) - - def to_dict(self): - return { - "alg": self._algorithm, - "kty": "oct", - "k": base64url_encode(self.prepared_key).decode("ASCII"), - } diff --git a/backend/venv39/lib/python3.9/site-packages/jose/backends/rsa_backend.py b/backend/venv39/lib/python3.9/site-packages/jose/backends/rsa_backend.py deleted file mode 100644 index 8139d69..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/backends/rsa_backend.py +++ /dev/null @@ -1,283 +0,0 @@ -import binascii -import warnings - -import rsa as pyrsa -import rsa.pem as pyrsa_pem -from pyasn1.error import PyAsn1Error -from rsa import DecryptionError - -from jose.backends._asn1 import ( - rsa_private_key_pkcs1_to_pkcs8, - rsa_private_key_pkcs8_to_pkcs1, - rsa_public_key_pkcs1_to_pkcs8, -) -from jose.backends.base import Key -from jose.constants import ALGORITHMS -from jose.exceptions import JWEError, JWKError -from jose.utils import base64_to_long, long_to_base64 - -ALGORITHMS.SUPPORTED.remove(ALGORITHMS.RSA_OAEP) # RSA OAEP not supported - -LEGACY_INVALID_PKCS8_RSA_HEADER = binascii.unhexlify( - "30" # sequence - "8204BD" # DER-encoded sequence contents length of 1213 bytes -- INCORRECT STATIC LENGTH - "020100" # integer: 0 -- Version - "30" # sequence - "0D" # DER-encoded sequence contents length of 13 bytes -- PrivateKeyAlgorithmIdentifier - "06092A864886F70D010101" # OID -- rsaEncryption - "0500" # NULL -- parameters -) -ASN1_SEQUENCE_ID = binascii.unhexlify("30") -RSA_ENCRYPTION_ASN1_OID = "1.2.840.113549.1.1.1" - -# Functions gcd and rsa_recover_prime_factors were copied from cryptography 1.9 -# to enable pure python rsa module to be in compliance with section 6.3.1 of RFC7518 -# which requires only private exponent (d) for private key. - - -def _gcd(a, b): - """Calculate the Greatest Common Divisor of a and b. - - Unless b==0, the result will have the same sign as b (so that when - b is divided by it, the result comes out positive). - """ - while b: - a, b = b, (a % b) - return a - - -# Controls the number of iterations rsa_recover_prime_factors will perform -# to obtain the prime factors. Each iteration increments by 2 so the actual -# maximum attempts is half this number. -_MAX_RECOVERY_ATTEMPTS = 1000 - - -def _rsa_recover_prime_factors(n, e, d): - """ - Compute factors p and q from the private exponent d. We assume that n has - no more than two factors. This function is adapted from code in PyCrypto. - """ - # See 8.2.2(i) in Handbook of Applied Cryptography. - ktot = d * e - 1 - # The quantity d*e-1 is a multiple of phi(n), even, - # and can be represented as t*2^s. - t = ktot - while t % 2 == 0: - t = t // 2 - # Cycle through all multiplicative inverses in Zn. - # The algorithm is non-deterministic, but there is a 50% chance - # any candidate a leads to successful factoring. - # See "Digitalized Signatures and Public Key Functions as Intractable - # as Factorization", M. Rabin, 1979 - spotted = False - a = 2 - while not spotted and a < _MAX_RECOVERY_ATTEMPTS: - k = t - # Cycle through all values a^{t*2^i}=a^k - while k < ktot: - cand = pow(a, k, n) - # Check if a^k is a non-trivial root of unity (mod n) - if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: - # We have found a number such that (cand-1)(cand+1)=0 (mod n). - # Either of the terms divides n. - p = _gcd(cand + 1, n) - spotted = True - break - k *= 2 - # This value was not any good... let's try another! - a += 2 - if not spotted: - raise ValueError("Unable to compute factors p and q from exponent d.") - # Found ! - q, r = divmod(n, p) - assert r == 0 - p, q = sorted((p, q), reverse=True) - return (p, q) - - -def pem_to_spki(pem, fmt="PKCS8"): - key = RSAKey(pem, ALGORITHMS.RS256) - return key.to_pem(fmt) - - -def _legacy_private_key_pkcs8_to_pkcs1(pkcs8_key): - """Legacy RSA private key PKCS8-to-PKCS1 conversion. - - .. warning:: - - This is incorrect parsing and only works because the legacy PKCS1-to-PKCS8 - encoding was also incorrect. - """ - # Only allow this processing if the prefix matches - # AND the following byte indicates an ASN1 sequence, - # as we would expect with the legacy encoding. - if not pkcs8_key.startswith(LEGACY_INVALID_PKCS8_RSA_HEADER + ASN1_SEQUENCE_ID): - raise ValueError("Invalid private key encoding") - - return pkcs8_key[len(LEGACY_INVALID_PKCS8_RSA_HEADER) :] - - -class RSAKey(Key): - SHA256 = "SHA-256" - SHA384 = "SHA-384" - SHA512 = "SHA-512" - - def __init__(self, key, algorithm): - if algorithm not in ALGORITHMS.RSA: - raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm) - - if algorithm in ALGORITHMS.RSA_KW and algorithm != ALGORITHMS.RSA1_5: - raise JWKError("alg: %s is not supported by the RSA backend" % algorithm) - - self.hash_alg = { - ALGORITHMS.RS256: self.SHA256, - ALGORITHMS.RS384: self.SHA384, - ALGORITHMS.RS512: self.SHA512, - }.get(algorithm) - self._algorithm = algorithm - - if isinstance(key, dict): - self._prepared_key = self._process_jwk(key) - return - - if isinstance(key, (pyrsa.PublicKey, pyrsa.PrivateKey)): - self._prepared_key = key - return - - if isinstance(key, str): - key = key.encode("utf-8") - - if isinstance(key, bytes): - try: - self._prepared_key = pyrsa.PublicKey.load_pkcs1(key) - except ValueError: - try: - self._prepared_key = pyrsa.PublicKey.load_pkcs1_openssl_pem(key) - except ValueError: - try: - self._prepared_key = pyrsa.PrivateKey.load_pkcs1(key) - except ValueError: - try: - der = pyrsa_pem.load_pem(key, b"PRIVATE KEY") - try: - pkcs1_key = rsa_private_key_pkcs8_to_pkcs1(der) - except PyAsn1Error: - # If the key was encoded using the old, invalid, - # encoding then pyasn1 will throw an error attempting - # to parse the key. - pkcs1_key = _legacy_private_key_pkcs8_to_pkcs1(der) - self._prepared_key = pyrsa.PrivateKey.load_pkcs1(pkcs1_key, format="DER") - except ValueError as e: - raise JWKError(e) - return - raise JWKError("Unable to parse an RSA_JWK from key: %s" % key) - - def _process_jwk(self, jwk_dict): - if not jwk_dict.get("kty") == "RSA": - raise JWKError("Incorrect key type. Expected: 'RSA', Received: %s" % jwk_dict.get("kty")) - - e = base64_to_long(jwk_dict.get("e")) - n = base64_to_long(jwk_dict.get("n")) - - if "d" not in jwk_dict: - return pyrsa.PublicKey(e=e, n=n) - else: - d = base64_to_long(jwk_dict.get("d")) - extra_params = ["p", "q", "dp", "dq", "qi"] - - if any(k in jwk_dict for k in extra_params): - # Precomputed private key parameters are available. - if not all(k in jwk_dict for k in extra_params): - # These values must be present when 'p' is according to - # Section 6.3.2 of RFC7518, so if they are not we raise - # an error. - raise JWKError("Precomputed private key parameters are incomplete.") - - p = base64_to_long(jwk_dict["p"]) - q = base64_to_long(jwk_dict["q"]) - return pyrsa.PrivateKey(e=e, n=n, d=d, p=p, q=q) - else: - p, q = _rsa_recover_prime_factors(n, e, d) - return pyrsa.PrivateKey(n=n, e=e, d=d, p=p, q=q) - - def sign(self, msg): - return pyrsa.sign(msg, self._prepared_key, self.hash_alg) - - def verify(self, msg, sig): - if not self.is_public(): - warnings.warn("Attempting to verify a message with a private key. " "This is not recommended.") - try: - pyrsa.verify(msg, sig, self._prepared_key) - return True - except pyrsa.pkcs1.VerificationError: - return False - - def is_public(self): - return isinstance(self._prepared_key, pyrsa.PublicKey) - - def public_key(self): - if isinstance(self._prepared_key, pyrsa.PublicKey): - return self - return self.__class__(pyrsa.PublicKey(n=self._prepared_key.n, e=self._prepared_key.e), self._algorithm) - - def to_pem(self, pem_format="PKCS8"): - if isinstance(self._prepared_key, pyrsa.PrivateKey): - der = self._prepared_key.save_pkcs1(format="DER") - if pem_format == "PKCS8": - pkcs8_der = rsa_private_key_pkcs1_to_pkcs8(der) - pem = pyrsa_pem.save_pem(pkcs8_der, pem_marker="PRIVATE KEY") - elif pem_format == "PKCS1": - pem = pyrsa_pem.save_pem(der, pem_marker="RSA PRIVATE KEY") - else: - raise ValueError(f"Invalid pem format specified: {pem_format!r}") - else: - if pem_format == "PKCS8": - pkcs1_der = self._prepared_key.save_pkcs1(format="DER") - pkcs8_der = rsa_public_key_pkcs1_to_pkcs8(pkcs1_der) - pem = pyrsa_pem.save_pem(pkcs8_der, pem_marker="PUBLIC KEY") - elif pem_format == "PKCS1": - der = self._prepared_key.save_pkcs1(format="DER") - pem = pyrsa_pem.save_pem(der, pem_marker="RSA PUBLIC KEY") - else: - raise ValueError(f"Invalid pem format specified: {pem_format!r}") - return pem - - def to_dict(self): - if not self.is_public(): - public_key = self.public_key()._prepared_key - else: - public_key = self._prepared_key - - data = { - "alg": self._algorithm, - "kty": "RSA", - "n": long_to_base64(public_key.n).decode("ASCII"), - "e": long_to_base64(public_key.e).decode("ASCII"), - } - - if not self.is_public(): - data.update( - { - "d": long_to_base64(self._prepared_key.d).decode("ASCII"), - "p": long_to_base64(self._prepared_key.p).decode("ASCII"), - "q": long_to_base64(self._prepared_key.q).decode("ASCII"), - "dp": long_to_base64(self._prepared_key.exp1).decode("ASCII"), - "dq": long_to_base64(self._prepared_key.exp2).decode("ASCII"), - "qi": long_to_base64(self._prepared_key.coef).decode("ASCII"), - } - ) - - return data - - def wrap_key(self, key_data): - if not self.is_public(): - warnings.warn("Attempting to encrypt a message with a private key." " This is not recommended.") - wrapped_key = pyrsa.encrypt(key_data, self._prepared_key) - return wrapped_key - - def unwrap_key(self, wrapped_key): - try: - unwrapped_key = pyrsa.decrypt(wrapped_key, self._prepared_key) - except DecryptionError as e: - raise JWEError(e) - return unwrapped_key diff --git a/backend/venv39/lib/python3.9/site-packages/jose/constants.py b/backend/venv39/lib/python3.9/site-packages/jose/constants.py deleted file mode 100644 index 58787d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/constants.py +++ /dev/null @@ -1,100 +0,0 @@ -import hashlib - - -class Algorithms: - # DS Algorithms - NONE = "none" - HS256 = "HS256" - HS384 = "HS384" - HS512 = "HS512" - RS256 = "RS256" - RS384 = "RS384" - RS512 = "RS512" - ES256 = "ES256" - ES384 = "ES384" - ES512 = "ES512" - - # Content Encryption Algorithms - A128CBC_HS256 = "A128CBC-HS256" - A192CBC_HS384 = "A192CBC-HS384" - A256CBC_HS512 = "A256CBC-HS512" - A128GCM = "A128GCM" - A192GCM = "A192GCM" - A256GCM = "A256GCM" - - # Pseudo algorithm for encryption - A128CBC = "A128CBC" - A192CBC = "A192CBC" - A256CBC = "A256CBC" - - # CEK Encryption Algorithms - DIR = "dir" - RSA1_5 = "RSA1_5" - RSA_OAEP = "RSA-OAEP" - RSA_OAEP_256 = "RSA-OAEP-256" - A128KW = "A128KW" - A192KW = "A192KW" - A256KW = "A256KW" - ECDH_ES = "ECDH-ES" - ECDH_ES_A128KW = "ECDH-ES+A128KW" - ECDH_ES_A192KW = "ECDH-ES+A192KW" - ECDH_ES_A256KW = "ECDH-ES+A256KW" - A128GCMKW = "A128GCMKW" - A192GCMKW = "A192GCMKW" - A256GCMKW = "A256GCMKW" - PBES2_HS256_A128KW = "PBES2-HS256+A128KW" - PBES2_HS384_A192KW = "PBES2-HS384+A192KW" - PBES2_HS512_A256KW = "PBES2-HS512+A256KW" - - # Compression Algorithms - DEF = "DEF" - - HMAC = {HS256, HS384, HS512} - RSA_DS = {RS256, RS384, RS512} - RSA_KW = {RSA1_5, RSA_OAEP, RSA_OAEP_256} - RSA = RSA_DS.union(RSA_KW) - EC_DS = {ES256, ES384, ES512} - EC_KW = {ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW} - EC = EC_DS.union(EC_KW) - AES_PSEUDO = {A128CBC, A192CBC, A256CBC, A128GCM, A192GCM, A256GCM} - AES_JWE_ENC = {A128CBC_HS256, A192CBC_HS384, A256CBC_HS512, A128GCM, A192GCM, A256GCM} - AES_ENC = AES_JWE_ENC.union(AES_PSEUDO) - AES_KW = {A128KW, A192KW, A256KW} - AEC_GCM_KW = {A128GCMKW, A192GCMKW, A256GCMKW} - AES = AES_ENC.union(AES_KW) - PBES2_KW = {PBES2_HS256_A128KW, PBES2_HS384_A192KW, PBES2_HS512_A256KW} - - HMAC_AUTH_TAG = {A128CBC_HS256, A192CBC_HS384, A256CBC_HS512} - GCM = {A128GCM, A192GCM, A256GCM} - - SUPPORTED = HMAC.union(RSA_DS).union(EC_DS).union([DIR]).union(AES_JWE_ENC).union(RSA_KW).union(AES_KW) - - ALL = SUPPORTED.union([NONE]).union(AEC_GCM_KW).union(EC_KW).union(PBES2_KW) - - HASHES = { - HS256: hashlib.sha256, - HS384: hashlib.sha384, - HS512: hashlib.sha512, - RS256: hashlib.sha256, - RS384: hashlib.sha384, - RS512: hashlib.sha512, - ES256: hashlib.sha256, - ES384: hashlib.sha384, - ES512: hashlib.sha512, - } - - KEYS = {} - - -ALGORITHMS = Algorithms() - - -class Zips: - DEF = "DEF" - NONE = None - SUPPORTED = {DEF, NONE} - - -ZIPS = Zips() - -JWE_SIZE_LIMIT = 250 * 1024 diff --git a/backend/venv39/lib/python3.9/site-packages/jose/exceptions.py b/backend/venv39/lib/python3.9/site-packages/jose/exceptions.py deleted file mode 100644 index e8edc3b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/exceptions.py +++ /dev/null @@ -1,59 +0,0 @@ -class JOSEError(Exception): - pass - - -class JWSError(JOSEError): - pass - - -class JWSSignatureError(JWSError): - pass - - -class JWSAlgorithmError(JWSError): - pass - - -class JWTError(JOSEError): - pass - - -class JWTClaimsError(JWTError): - pass - - -class ExpiredSignatureError(JWTError): - pass - - -class JWKError(JOSEError): - pass - - -class JWEError(JOSEError): - """Base error for all JWE errors""" - - pass - - -class JWEParseError(JWEError): - """Could not parse the JWE string provided""" - - pass - - -class JWEInvalidAuth(JWEError): - """ - The authentication tag did not match the protected sections of the - JWE string provided - """ - - pass - - -class JWEAlgorithmUnsupportedError(JWEError): - """ - The JWE algorithm is not supported by the backend - """ - - pass diff --git a/backend/venv39/lib/python3.9/site-packages/jose/jwe.py b/backend/venv39/lib/python3.9/site-packages/jose/jwe.py deleted file mode 100644 index 09e5c32..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/jwe.py +++ /dev/null @@ -1,619 +0,0 @@ -import binascii -import json -import zlib -from collections.abc import Mapping -from struct import pack - -from . import jwk -from .backends import get_random_bytes -from .constants import ALGORITHMS, JWE_SIZE_LIMIT, ZIPS -from .exceptions import JWEError, JWEParseError -from .utils import base64url_decode, base64url_encode, ensure_binary - - -def encrypt(plaintext, key, encryption=ALGORITHMS.A256GCM, algorithm=ALGORITHMS.DIR, zip=None, cty=None, kid=None): - """Encrypts plaintext and returns a JWE compact serialization string. - - Args: - plaintext (bytes): A bytes object to encrypt - key (str or dict): The key(s) to use for encrypting the content. Can be - individual JWK or JWK set. - encryption (str, optional): The content encryption algorithm used to - perform authenticated encryption on the plaintext to produce the - ciphertext and the Authentication Tag. Defaults to A256GCM. - algorithm (str, optional): The cryptographic algorithm used - to encrypt or determine the value of the CEK. Defaults to dir. - zip (str, optional): The compression algorithm) applied to the - plaintext before encryption. Defaults to None. - cty (str, optional): The media type for the secured content. - See http://www.iana.org/assignments/media-types/media-types.xhtml - kid (str, optional): Key ID for the provided key - - Returns: - bytes: The string representation of the header, encrypted key, - initialization vector, ciphertext, and authentication tag. - - Raises: - JWEError: If there is an error signing the token. - - Examples: - >>> from jose import jwe - >>> jwe.encrypt('Hello, World!', 'asecret128bitkey', algorithm='dir', encryption='A128GCM') - 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..McILMB3dYsNJSuhcDzQshA.OfX9H_mcUpHDeRM4IA.CcnTWqaqxNsjT4eCaUABSg' - - """ - plaintext = ensure_binary(plaintext) # Make sure it's bytes - if algorithm not in ALGORITHMS.SUPPORTED: - raise JWEError("Algorithm %s not supported." % algorithm) - if encryption not in ALGORITHMS.SUPPORTED: - raise JWEError("Algorithm %s not supported." % encryption) - key = jwk.construct(key, algorithm) - encoded_header = _encoded_header(algorithm, encryption, zip, cty, kid) - - plaintext = _compress(zip, plaintext) - enc_cek, iv, cipher_text, auth_tag = _encrypt_and_auth(key, algorithm, encryption, zip, plaintext, encoded_header) - - jwe_string = _jwe_compact_serialize(encoded_header, enc_cek, iv, cipher_text, auth_tag) - return jwe_string - - -def decrypt(jwe_str, key): - """Decrypts a JWE compact serialized string and returns the plaintext. - - Args: - jwe_str (str): A JWE to be decrypt. - key (str or dict): A key to attempt to decrypt the payload with. Can be - individual JWK or JWK set. - - Returns: - bytes: The plaintext bytes, assuming the authentication tag is valid. - - Raises: - JWEError: If there is an exception verifying the token. - - Examples: - >>> from jose import jwe - >>> jwe.decrypt(jwe_string, 'asecret128bitkey') - 'Hello, World!' - """ - - # Limit the token size - if the data is compressed then decompressing the - # data could lead to large memory usage. This helps address This addresses - # CVE-2024-33664. Also see _decompress() - if len(jwe_str) > JWE_SIZE_LIMIT: - raise JWEError(f"JWE string {len(jwe_str)} bytes exceeds {JWE_SIZE_LIMIT} bytes") - - header, encoded_header, encrypted_key, iv, cipher_text, auth_tag = _jwe_compact_deserialize(jwe_str) - - # Verify that the implementation understands and can process all - # fields that it is required to support, whether required by this - # specification, by the algorithms being used, or by the "crit" - # Header Parameter value, and that the values of those parameters - # are also understood and supported. - - try: - # Determine the Key Management Mode employed by the algorithm - # specified by the "alg" (algorithm) Header Parameter. - alg = header["alg"] - enc = header["enc"] - if alg not in ALGORITHMS.SUPPORTED: - raise JWEError("Algorithm %s not supported." % alg) - if enc not in ALGORITHMS.SUPPORTED: - raise JWEError("Algorithm %s not supported." % enc) - - except KeyError: - raise JWEParseError("alg and enc headers are required!") - - # Verify that the JWE uses a key known to the recipient. - key = jwk.construct(key, alg) - - # When Direct Key Agreement or Key Agreement with Key Wrapping are - # employed, use the key agreement algorithm to compute the value - # of the agreed upon key. When Direct Key Agreement is employed, - # let the CEK be the agreed upon key. When Key Agreement with Key - # Wrapping is employed, the agreed upon key will be used to - # decrypt the JWE Encrypted Key. - # - # When Key Wrapping, Key Encryption, or Key Agreement with Key - # Wrapping are employed, decrypt the JWE Encrypted Key to produce - # the CEK. The CEK MUST have a length equal to that required for - # the content encryption algorithm. Note that when there are - # multiple recipients, each recipient will only be able to decrypt - # JWE Encrypted Key values that were encrypted to a key in that - # recipient's possession. It is therefore normal to only be able - # to decrypt one of the per-recipient JWE Encrypted Key values to - # obtain the CEK value. Also, see Section 11.5 for security - # considerations on mitigating timing attacks. - if alg == ALGORITHMS.DIR: - # When Direct Key Agreement or Direct Encryption are employed, - # verify that the JWE Encrypted Key value is an empty octet - # sequence. - - # Record whether the CEK could be successfully determined for this - # recipient or not. - cek_valid = encrypted_key == b"" - - # When Direct Encryption is employed, let the CEK be the shared - # symmetric key. - cek_bytes = _get_key_bytes_from_key(key) - else: - try: - cek_bytes = key.unwrap_key(encrypted_key) - - # Record whether the CEK could be successfully determined for this - # recipient or not. - cek_valid = True - except NotImplementedError: - raise JWEError(f"alg {alg} is not implemented") - except Exception: - # Record whether the CEK could be successfully determined for this - # recipient or not. - cek_valid = False - - # To mitigate the attacks described in RFC 3218 [RFC3218], the - # recipient MUST NOT distinguish between format, padding, and length - # errors of encrypted keys. It is strongly recommended, in the event - # of receiving an improperly formatted key, that the recipient - # substitute a randomly generated CEK and proceed to the next step, to - # mitigate timing attacks. - cek_bytes = _get_random_cek_bytes_for_enc(enc) - - # Compute the Encoded Protected Header value BASE64URL(UTF8(JWE - # Protected Header)). If the JWE Protected Header is not present - # (which can only happen when using the JWE JSON Serialization and - # no "protected" member is present), let this value be the empty - # string. - protected_header = encoded_header - - # Let the Additional Authenticated Data encryption parameter be - # ASCII(Encoded Protected Header). However, if a JWE AAD value is - # present (which can only be the case when using the JWE JSON - # Serialization), instead let the Additional Authenticated Data - # encryption parameter be ASCII(Encoded Protected Header || '.' || - # BASE64URL(JWE AAD)). - aad = protected_header - - # Decrypt the JWE Ciphertext using the CEK, the JWE Initialization - # Vector, the Additional Authenticated Data value, and the JWE - # Authentication Tag (which is the Authentication Tag input to the - # calculation) using the specified content encryption algorithm, - # returning the decrypted plaintext and validating the JWE - # Authentication Tag in the manner specified for the algorithm, - # rejecting the input without emitting any decrypted output if the - # JWE Authentication Tag is incorrect. - try: - plain_text = _decrypt_and_auth(cek_bytes, enc, cipher_text, iv, aad, auth_tag) - except NotImplementedError: - raise JWEError(f"enc {enc} is not implemented") - except Exception as e: - raise JWEError(e) - - # If a "zip" parameter was included, uncompress the decrypted - # plaintext using the specified compression algorithm. - if plain_text is not None: - plain_text = _decompress(header.get("zip"), plain_text) - - return plain_text if cek_valid else None - - -def get_unverified_header(jwe_str): - """Returns the decoded headers without verification of any kind. - - Args: - jwe_str (str): A compact serialized JWE to decode the headers from. - - Returns: - dict: The dict representation of the JWE headers. - - Raises: - JWEError: If there is an exception decoding the JWE. - """ - header = _jwe_compact_deserialize(jwe_str)[0] - return header - - -def _decrypt_and_auth(cek_bytes, enc, cipher_text, iv, aad, auth_tag): - """ - Decrypt and verify the data - - Args: - cek_bytes (bytes): cek to derive encryption and possible auth key to - verify the auth tag - cipher_text (bytes): Encrypted data - iv (bytes): Initialization vector (iv) used to encrypt data - aad (bytes): Additional Authenticated Data used to verify the data - auth_tag (bytes): Authentication ntag to verify the data - - Returns: - (bytes): Decrypted data - """ - # Decrypt the JWE Ciphertext using the CEK, the JWE Initialization - # Vector, the Additional Authenticated Data value, and the JWE - # Authentication Tag (which is the Authentication Tag input to the - # calculation) using the specified content encryption algorithm, - # returning the decrypted plaintext - # and validating the JWE - # Authentication Tag in the manner specified for the algorithm, - if enc in ALGORITHMS.HMAC_AUTH_TAG: - encryption_key, mac_key, key_len = _get_encryption_key_mac_key_and_key_length_from_cek(cek_bytes, enc) - auth_tag_check = _auth_tag(cipher_text, iv, aad, mac_key, key_len) - elif enc in ALGORITHMS.GCM: - encryption_key = jwk.construct(cek_bytes, enc) - auth_tag_check = auth_tag # GCM check auth on decrypt - else: - raise NotImplementedError(f"enc {enc} is not implemented!") - - plaintext = encryption_key.decrypt(cipher_text, iv, aad, auth_tag) - if auth_tag != auth_tag_check: - raise JWEError("Invalid JWE Auth Tag") - - return plaintext - - -def _get_encryption_key_mac_key_and_key_length_from_cek(cek_bytes, enc): - derived_key_len = len(cek_bytes) // 2 - mac_key_bytes = cek_bytes[0:derived_key_len] - mac_key = _get_hmac_key(enc, mac_key_bytes) - encryption_key_bytes = cek_bytes[-derived_key_len:] - encryption_alg, _ = enc.split("-") - encryption_key = jwk.construct(encryption_key_bytes, encryption_alg) - return encryption_key, mac_key, derived_key_len - - -def _jwe_compact_deserialize(jwe_bytes): - """ - Deserialize and verify the header and segments are appropriate. - - Args: - jwe_bytes (bytes): The compact serialized JWE - Returns: - (dict, bytes, bytes, bytes, bytes, bytes) - """ - - # Base64url decode the encoded representations of the JWE - # Protected Header, the JWE Encrypted Key, the JWE Initialization - # Vector, the JWE Ciphertext, the JWE Authentication Tag, and the - # JWE AAD, following the restriction that no line breaks, - # whitespace, or other additional characters have been used. - jwe_bytes = ensure_binary(jwe_bytes) - try: - header_segment, encrypted_key_segment, iv_segment, cipher_text_segment, auth_tag_segment = jwe_bytes.split( - b".", 4 - ) - header_data = base64url_decode(header_segment) - except ValueError: - raise JWEParseError("Not enough segments") - except (TypeError, binascii.Error): - raise JWEParseError("Invalid header") - - # Verify that the octet sequence resulting from decoding the - # encoded JWE Protected Header is a UTF-8-encoded representation - # of a completely valid JSON object conforming to RFC 7159 - # [RFC7159]; let the JWE Protected Header be this JSON object. - # - # If using the JWE Compact Serialization, let the JOSE Header be - # the JWE Protected Header. Otherwise, when using the JWE JSON - # Serialization, let the JOSE Header be the union of the members - # of the JWE Protected Header, the JWE Shared Unprotected Header - # and the corresponding JWE Per-Recipient Unprotected Header, all - # of which must be completely valid JSON objects. During this - # step, verify that the resulting JOSE Header does not contain - # duplicate Header Parameter names. When using the JWE JSON - # Serialization, this restriction includes that the same Header - # Parameter name also MUST NOT occur in distinct JSON object - # values that together comprise the JOSE Header. - - try: - header = json.loads(header_data) - except ValueError as e: - raise JWEParseError(f"Invalid header string: {e}") - - if not isinstance(header, Mapping): - raise JWEParseError("Invalid header string: must be a json object") - - try: - encrypted_key = base64url_decode(encrypted_key_segment) - except (TypeError, binascii.Error): - raise JWEParseError("Invalid encrypted key") - - try: - iv = base64url_decode(iv_segment) - except (TypeError, binascii.Error): - raise JWEParseError("Invalid IV") - - try: - ciphertext = base64url_decode(cipher_text_segment) - except (TypeError, binascii.Error): - raise JWEParseError("Invalid cyphertext") - - try: - auth_tag = base64url_decode(auth_tag_segment) - except (TypeError, binascii.Error): - raise JWEParseError("Invalid auth tag") - - return header, header_segment, encrypted_key, iv, ciphertext, auth_tag - - -def _encoded_header(alg, enc, zip, cty, kid): - """ - Generate an appropriate JOSE header based on the values provided - Args: - alg (str): Key wrap/negotiation algorithm - enc (str): Encryption algorithm - zip (str): Compression method - cty (str): Content type of the encrypted data - kid (str): ID for the key used for the operation - - Returns: - bytes: JSON object of header based on input - """ - header = {"alg": alg, "enc": enc} - if zip: - header["zip"] = zip - if cty: - header["cty"] = cty - if kid: - header["kid"] = kid - json_header = json.dumps( - header, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - return base64url_encode(json_header) - - -def _big_endian(int_val): - return pack("!Q", int_val) - - -def _encrypt_and_auth(key, alg, enc, zip, plaintext, aad): - """ - Generate a content encryption key (cek) and initialization - vector (iv) based on enc and alg, compress the plaintext based on zip, - encrypt the compressed plaintext using the cek and iv based on enc - - Args: - key (Key): The key provided for encryption - alg (str): The algorithm use for key wrap/negotiation - enc (str): The encryption algorithm with which to encrypt the plaintext - zip (str): The compression algorithm with which to compress the plaintext - plaintext (bytes): The data to encrypt - aad (str): Additional authentication data utilized for generating an - auth tag - - Returns: - (bytes, bytes, bytes, bytes): A tuple of the following data - (key wrapped cek, iv, cipher text, auth tag) - """ - try: - cek_bytes, kw_cek = _get_cek(enc, alg, key) - except NotImplementedError: - raise JWEError(f"alg {alg} is not implemented") - - if enc in ALGORITHMS.HMAC_AUTH_TAG: - encryption_key, mac_key, key_len = _get_encryption_key_mac_key_and_key_length_from_cek(cek_bytes, enc) - iv, ciphertext, tag = encryption_key.encrypt(plaintext, aad) - auth_tag = _auth_tag(ciphertext, iv, aad, mac_key, key_len) - elif enc in ALGORITHMS.GCM: - encryption_key = jwk.construct(cek_bytes, enc) - iv, ciphertext, auth_tag = encryption_key.encrypt(plaintext, aad) - else: - raise NotImplementedError(f"enc {enc} is not implemented!") - - return kw_cek, iv, ciphertext, auth_tag - - -def _get_hmac_key(enc, mac_key_bytes): - """ - Get an HMACKey for the provided encryption algorithm and key bytes - - Args: - enc (str): Encryption algorithm - mac_key_bytes (bytes): vytes for the HMAC key - - Returns: - (HMACKey): The key to perform HMAC actions - """ - _, hash_alg = enc.split("-") - mac_key = jwk.construct(mac_key_bytes, hash_alg) - return mac_key - - -def _compress(zip, plaintext): - """ - Compress the plaintext based on the algorithm supplied - - Args: - zip (str): Compression Algorithm - plaintext (bytes): plaintext to compress - - Returns: - (bytes): Compressed plaintext - """ - if zip not in ZIPS.SUPPORTED: - raise NotImplementedError(f"ZIP {zip} is not supported!") - if zip is None: - compressed = plaintext - elif zip == ZIPS.DEF: - compressed = zlib.compress(plaintext) - else: - raise NotImplementedError(f"ZIP {zip} is not implemented!") - return compressed - - -def _decompress(zip, compressed): - """ - Decompress the plaintext based on the algorithm supplied - - Args: - zip (str): Compression Algorithm - plaintext (bytes): plaintext to decompress - - Returns: - (bytes): Compressed plaintext - """ - if zip not in ZIPS.SUPPORTED: - raise NotImplementedError(f"ZIP {zip} is not supported!") - if zip is None: - decompressed = compressed - elif zip == ZIPS.DEF: - # If, during decompression, there is more data than expected, the - # decompression halts and raise an error. This addresses CVE-2024-33664 - decompressor = zlib.decompressobj() - decompressed = decompressor.decompress(compressed, max_length=JWE_SIZE_LIMIT) - if decompressor.unconsumed_tail: - raise JWEError(f"Decompressed JWE string exceeds {JWE_SIZE_LIMIT} bytes") - else: - raise NotImplementedError(f"ZIP {zip} is not implemented!") - return decompressed - - -def _get_cek(enc, alg, key): - """ - Get the content encryption key - - Args: - enc (str): Encryption algorithm - alg (str): kwy wrap/negotiation algorithm - key (Key): Key provided to encryption method - - Return: - (bytes, bytes): Tuple of (cek bytes and wrapped cek) - """ - if alg == ALGORITHMS.DIR: - cek, wrapped_cek = _get_direct_key_wrap_cek(key) - else: - cek, wrapped_cek = _get_key_wrap_cek(enc, key) - - return cek, wrapped_cek - - -def _get_direct_key_wrap_cek(key): - """ - Get the cek and wrapped cek from the encryption key direct - - Args: - key (Key): Key provided to encryption method - - Return: - (Key, bytes): Tuple of (cek Key object and wrapped cek) - """ - # Get the JWK data to determine how to derive the cek - jwk_data = key.to_dict() - if jwk_data["kty"] == "oct": - # Get the last half of an octal key as the cek - cek_bytes = _get_key_bytes_from_key(key) - wrapped_cek = b"" - else: - raise NotImplementedError("JWK type {} not supported!".format(jwk_data["kty"])) - return cek_bytes, wrapped_cek - - -def _get_key_bytes_from_key(key): - """ - Get the raw key bytes from a Key object - - Args: - key (Key): Key from which to extract the raw key bytes - Returns: - (bytes) key data - """ - jwk_data = key.to_dict() - encoded_key = jwk_data["k"] - cek_bytes = base64url_decode(encoded_key) - return cek_bytes - - -def _get_key_wrap_cek(enc, key): - """_get_rsa_key_wrap_cek - Get the content encryption key for RSA key wrap - - Args: - enc (str): Encryption algorithm - key (Key): Key provided to encryption method - - Returns: - (Key, bytes): Tuple of (cek Key object and wrapped cek) - """ - cek_bytes = _get_random_cek_bytes_for_enc(enc) - wrapped_cek = key.wrap_key(cek_bytes) - return cek_bytes, wrapped_cek - - -def _get_random_cek_bytes_for_enc(enc): - """ - Get the random cek bytes based on the encryption algorithm - - Args: - enc (str): Encryption algorithm - - Returns: - (bytes) random bytes for cek key - """ - if enc == ALGORITHMS.A128GCM: - num_bits = 128 - elif enc == ALGORITHMS.A192GCM: - num_bits = 192 - elif enc in (ALGORITHMS.A128CBC_HS256, ALGORITHMS.A256GCM): - num_bits = 256 - elif enc == ALGORITHMS.A192CBC_HS384: - num_bits = 384 - elif enc == ALGORITHMS.A256CBC_HS512: - num_bits = 512 - else: - raise NotImplementedError(f"{enc} not supported") - cek_bytes = get_random_bytes(num_bits // 8) - return cek_bytes - - -def _auth_tag(ciphertext, iv, aad, mac_key, tag_length): - """ - Get ann auth tag from the provided data - - Args: - ciphertext (bytes): Encrypted value - iv (bytes): Initialization vector - aad (bytes): Additional Authenticated Data - mac_key (bytes): Key to use in generating the MAC - tag_length (int): How log the tag should be - - Returns: - (bytes) Auth tag - """ - al = _big_endian(len(aad) * 8) - auth_tag_input = aad + iv + ciphertext + al - signature = mac_key.sign(auth_tag_input) - auth_tag = signature[0:tag_length] - return auth_tag - - -def _jwe_compact_serialize(encoded_header, encrypted_cek, iv, cipher_text, auth_tag): - """ - Generate a compact serialized JWE - - Args: - encoded_header (bytes): Base64 URL Encoded JWE header JSON - encrypted_cek (bytes): Encrypted content encryption key (cek) - iv (bytes): Initialization vector (IV) - cipher_text (bytes): Cipher text - auth_tag (bytes): JWE Auth Tag - - Returns: - (str): JWE compact serialized string - """ - cipher_text = ensure_binary(cipher_text) - encoded_encrypted_cek = base64url_encode(encrypted_cek) - encoded_iv = base64url_encode(iv) - encoded_cipher_text = base64url_encode(cipher_text) - encoded_auth_tag = base64url_encode(auth_tag) - return ( - encoded_header - + b"." - + encoded_encrypted_cek - + b"." - + encoded_iv - + b"." - + encoded_cipher_text - + b"." - + encoded_auth_tag - ) diff --git a/backend/venv39/lib/python3.9/site-packages/jose/jwk.py b/backend/venv39/lib/python3.9/site-packages/jose/jwk.py deleted file mode 100644 index 2a31847..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/jwk.py +++ /dev/null @@ -1,79 +0,0 @@ -from jose.backends.base import Key -from jose.constants import ALGORITHMS -from jose.exceptions import JWKError - -try: - from jose.backends import RSAKey # noqa: F401 -except ImportError: - pass - -try: - from jose.backends import ECKey # noqa: F401 -except ImportError: - pass - -try: - from jose.backends import AESKey # noqa: F401 -except ImportError: - pass - -try: - from jose.backends import DIRKey # noqa: F401 -except ImportError: - pass - -try: - from jose.backends import HMACKey # noqa: F401 -except ImportError: - pass - - -def get_key(algorithm): - if algorithm in ALGORITHMS.KEYS: - return ALGORITHMS.KEYS[algorithm] - elif algorithm in ALGORITHMS.HMAC: # noqa: F811 - return HMACKey - elif algorithm in ALGORITHMS.RSA: - from jose.backends import RSAKey # noqa: F811 - - return RSAKey - elif algorithm in ALGORITHMS.EC: - from jose.backends import ECKey # noqa: F811 - - return ECKey - elif algorithm in ALGORITHMS.AES: - from jose.backends import AESKey # noqa: F811 - - return AESKey - elif algorithm == ALGORITHMS.DIR: - from jose.backends import DIRKey # noqa: F811 - - return DIRKey - return None - - -def register_key(algorithm, key_class): - if not issubclass(key_class, Key): - raise TypeError("Key class is not a subclass of jwk.Key") - ALGORITHMS.KEYS[algorithm] = key_class - ALGORITHMS.SUPPORTED.add(algorithm) - return True - - -def construct(key_data, algorithm=None): - """ - Construct a Key object for the given algorithm with the given - key_data. - """ - - # Allow for pulling the algorithm off of the passed in jwk. - if not algorithm and isinstance(key_data, dict): - algorithm = key_data.get("alg", None) - - if not algorithm: - raise JWKError("Unable to find an algorithm for key") - - key_class = get_key(algorithm) - if not key_class: - raise JWKError("Unable to find an algorithm for key") - return key_class(key_data, algorithm) diff --git a/backend/venv39/lib/python3.9/site-packages/jose/jws.py b/backend/venv39/lib/python3.9/site-packages/jose/jws.py deleted file mode 100644 index 27f6b79..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/jws.py +++ /dev/null @@ -1,268 +0,0 @@ -import binascii -import json - -try: - from collections.abc import Iterable, Mapping -except ImportError: - from collections import Mapping, Iterable - -from jose import jwk -from jose.backends.base import Key -from jose.constants import ALGORITHMS -from jose.exceptions import JWSError, JWSSignatureError -from jose.utils import base64url_decode, base64url_encode - - -def sign(payload, key, headers=None, algorithm=ALGORITHMS.HS256): - """Signs a claims set and returns a JWS string. - - Args: - payload (str or dict): A string to sign - key (str or dict): The key to use for signing the claim set. Can be - individual JWK or JWK set. - headers (dict, optional): A set of headers that will be added to - the default headers. Any headers that are added as additional - headers will override the default headers. - algorithm (str, optional): The algorithm to use for signing the - the claims. Defaults to HS256. - - Returns: - str: The string representation of the header, claims, and signature. - - Raises: - JWSError: If there is an error signing the token. - - Examples: - - >>> jws.sign({'a': 'b'}, 'secret', algorithm='HS256') - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' - - """ - - if algorithm not in ALGORITHMS.SUPPORTED: - raise JWSError("Algorithm %s not supported." % algorithm) - - encoded_header = _encode_header(algorithm, additional_headers=headers) - encoded_payload = _encode_payload(payload) - signed_output = _sign_header_and_claims(encoded_header, encoded_payload, algorithm, key) - - return signed_output - - -def verify(token, key, algorithms, verify=True): - """Verifies a JWS string's signature. - - Args: - token (str): A signed JWS to be verified. - key (str or dict): A key to attempt to verify the payload with. Can be - individual JWK or JWK set. - algorithms (str or list): Valid algorithms that should be used to verify the JWS. - - Returns: - str: The str representation of the payload, assuming the signature is valid. - - Raises: - JWSError: If there is an exception verifying a token. - - Examples: - - >>> token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' - >>> jws.verify(token, 'secret', algorithms='HS256') - - """ - - header, payload, signing_input, signature = _load(token) - - if verify: - _verify_signature(signing_input, header, signature, key, algorithms) - - return payload - - -def get_unverified_header(token): - """Returns the decoded headers without verification of any kind. - - Args: - token (str): A signed JWS to decode the headers from. - - Returns: - dict: The dict representation of the token headers. - - Raises: - JWSError: If there is an exception decoding the token. - """ - header, claims, signing_input, signature = _load(token) - return header - - -def get_unverified_headers(token): - """Returns the decoded headers without verification of any kind. - - This is simply a wrapper of get_unverified_header() for backwards - compatibility. - - Args: - token (str): A signed JWS to decode the headers from. - - Returns: - dict: The dict representation of the token headers. - - Raises: - JWSError: If there is an exception decoding the token. - """ - return get_unverified_header(token) - - -def get_unverified_claims(token): - """Returns the decoded claims without verification of any kind. - - Args: - token (str): A signed JWS to decode the headers from. - - Returns: - str: The str representation of the token claims. - - Raises: - JWSError: If there is an exception decoding the token. - """ - header, claims, signing_input, signature = _load(token) - return claims - - -def _encode_header(algorithm, additional_headers=None): - header = {"typ": "JWT", "alg": algorithm} - - if additional_headers: - header.update(additional_headers) - - json_header = json.dumps( - header, - separators=(",", ":"), - sort_keys=True, - ).encode("utf-8") - - return base64url_encode(json_header) - - -def _encode_payload(payload): - if isinstance(payload, Mapping): - try: - payload = json.dumps( - payload, - separators=(",", ":"), - ).encode("utf-8") - except ValueError: - pass - - return base64url_encode(payload) - - -def _sign_header_and_claims(encoded_header, encoded_claims, algorithm, key): - signing_input = b".".join([encoded_header, encoded_claims]) - try: - if not isinstance(key, Key): - key = jwk.construct(key, algorithm) - signature = key.sign(signing_input) - except Exception as e: - raise JWSError(e) - - encoded_signature = base64url_encode(signature) - - encoded_string = b".".join([encoded_header, encoded_claims, encoded_signature]) - - return encoded_string.decode("utf-8") - - -def _load(jwt): - if isinstance(jwt, str): - jwt = jwt.encode("utf-8") - try: - signing_input, crypto_segment = jwt.rsplit(b".", 1) - header_segment, claims_segment = signing_input.split(b".", 1) - header_data = base64url_decode(header_segment) - except ValueError: - raise JWSError("Not enough segments") - except (TypeError, binascii.Error): - raise JWSError("Invalid header padding") - - try: - header = json.loads(header_data.decode("utf-8")) - except ValueError as e: - raise JWSError("Invalid header string: %s" % e) - - if not isinstance(header, Mapping): - raise JWSError("Invalid header string: must be a json object") - - try: - payload = base64url_decode(claims_segment) - except (TypeError, binascii.Error): - raise JWSError("Invalid payload padding") - - try: - signature = base64url_decode(crypto_segment) - except (TypeError, binascii.Error): - raise JWSError("Invalid crypto padding") - - return (header, payload, signing_input, signature) - - -def _sig_matches_keys(keys, signing_input, signature, alg): - for key in keys: - if not isinstance(key, Key): - key = jwk.construct(key, alg) - try: - if key.verify(signing_input, signature): - return True - except Exception: - pass - return False - - -def _get_keys(key): - if isinstance(key, Key): - return (key,) - - try: - key = json.loads(key, parse_int=str, parse_float=str) - except Exception: - pass - - if isinstance(key, Mapping): - if "keys" in key: - # JWK Set per RFC 7517 - return key["keys"] - elif "kty" in key: - # Individual JWK per RFC 7517 - return (key,) - else: - # Some other mapping. Firebase uses just dict of kid, cert pairs - values = key.values() - if values: - return values - return (key,) - - # Iterable but not text or mapping => list- or tuple-like - elif isinstance(key, Iterable) and not (isinstance(key, str) or isinstance(key, bytes)): - return key - - # Scalar value, wrap in tuple. - else: - return (key,) - - -def _verify_signature(signing_input, header, signature, key="", algorithms=None): - alg = header.get("alg") - if not alg: - raise JWSError("No algorithm was specified in the JWS header.") - - if algorithms is not None and alg not in algorithms: - raise JWSError("The specified alg value is not allowed") - - keys = _get_keys(key) - try: - if not _sig_matches_keys(keys, signing_input, signature, alg): - raise JWSSignatureError() - except JWSSignatureError: - raise JWSError("Signature verification failed.") - except JWSError: - raise JWSError("Invalid or unsupported algorithm: %s" % alg) diff --git a/backend/venv39/lib/python3.9/site-packages/jose/jwt.py b/backend/venv39/lib/python3.9/site-packages/jose/jwt.py deleted file mode 100644 index f47e4dd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/jwt.py +++ /dev/null @@ -1,512 +0,0 @@ -import json -from calendar import timegm -from datetime import datetime, timedelta - -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping - -try: - from datetime import UTC # Preferred in Python 3.13+ -except ImportError: - from datetime import timezone - - UTC = timezone.utc # Preferred in Python 3.12 and below - -from jose import jws - -from .constants import ALGORITHMS -from .exceptions import ExpiredSignatureError, JWSError, JWTClaimsError, JWTError -from .utils import calculate_at_hash, timedelta_total_seconds - - -def encode(claims, key, algorithm=ALGORITHMS.HS256, headers=None, access_token=None): - """Encodes a claims set and returns a JWT string. - - JWTs are JWS signed objects with a few reserved claims. - - Args: - claims (dict): A claims set to sign - key (str or dict): The key to use for signing the claim set. Can be - individual JWK or JWK set. - algorithm (str, optional): The algorithm to use for signing the - the claims. Defaults to HS256. - headers (dict, optional): A set of headers that will be added to - the default headers. Any headers that are added as additional - headers will override the default headers. - access_token (str, optional): If present, the 'at_hash' claim will - be calculated and added to the claims present in the 'claims' - parameter. - - Returns: - str: The string representation of the header, claims, and signature. - - Raises: - JWTError: If there is an error encoding the claims. - - Examples: - - >>> jwt.encode({'a': 'b'}, 'secret', algorithm='HS256') - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' - - """ - - for time_claim in ["exp", "iat", "nbf"]: - # Convert datetime to a intDate value in known time-format claims - if isinstance(claims.get(time_claim), datetime): - claims[time_claim] = timegm(claims[time_claim].utctimetuple()) - - if access_token: - claims["at_hash"] = calculate_at_hash(access_token, ALGORITHMS.HASHES[algorithm]) - - return jws.sign(claims, key, headers=headers, algorithm=algorithm) - - -def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None): - """Verifies a JWT string's signature and validates reserved claims. - - Args: - token (str): A signed JWS to be verified. - key (str or iterable): A key to attempt to verify the payload with. - This can be simple string with an individual key (e.g. "a1234"), - a tuple or list of keys (e.g. ("a1234...", "b3579"), - a JSON string, (e.g. '["a1234", "b3579"]'), - a dict with the 'keys' key that gives a tuple or list of keys (e.g {'keys': [...]} ) or - a dict or JSON string for a JWK set as defined by RFC 7517 (e.g. - {'keys': [{'kty': 'oct', 'k': 'YTEyMzQ'}, {'kty': 'oct', 'k':'YjM1Nzk'}]} or - '{"keys": [{"kty":"oct","k":"YTEyMzQ"},{"kty":"oct","k":"YjM1Nzk"}]}' - ) in which case the keys must be base64 url safe encoded (with optional padding). - algorithms (str or list): Valid algorithms that should be used to verify the JWS. - audience (str): The intended audience of the token. If the "aud" claim is - included in the claim set, then the audience must be included and must equal - the provided claim. - issuer (str or iterable): Acceptable value(s) for the issuer of the token. - If the "iss" claim is included in the claim set, then the issuer must be - given and the claim in the token must be among the acceptable values. - subject (str): The subject of the token. If the "sub" claim is - included in the claim set, then the subject must be included and must equal - the provided claim. - access_token (str): An access token string. If the "at_hash" claim is included in the - claim set, then the access_token must be included, and it must match - the "at_hash" claim. - options (dict): A dictionary of options for skipping validation steps. - - defaults = { - 'verify_signature': True, - 'verify_aud': True, - 'verify_iat': True, - 'verify_exp': True, - 'verify_nbf': True, - 'verify_iss': True, - 'verify_sub': True, - 'verify_jti': True, - 'verify_at_hash': True, - 'require_aud': False, - 'require_iat': False, - 'require_exp': False, - 'require_nbf': False, - 'require_iss': False, - 'require_sub': False, - 'require_jti': False, - 'require_at_hash': False, - 'leeway': 0, - } - - Returns: - dict: The dict representation of the claims set, assuming the signature is valid - and all requested data validation passes. - - Raises: - JWTError: If the signature is invalid in any way. - ExpiredSignatureError: If the signature has expired. - JWTClaimsError: If any claim is invalid in any way. - - Examples: - - >>> payload = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' - >>> jwt.decode(payload, 'secret', algorithms='HS256') - - """ - - defaults = { - "verify_signature": True, - "verify_aud": True, - "verify_iat": True, - "verify_exp": True, - "verify_nbf": True, - "verify_iss": True, - "verify_sub": True, - "verify_jti": True, - "verify_at_hash": True, - "require_aud": False, - "require_iat": False, - "require_exp": False, - "require_nbf": False, - "require_iss": False, - "require_sub": False, - "require_jti": False, - "require_at_hash": False, - "leeway": 0, - } - - if options: - defaults.update(options) - - verify_signature = defaults.get("verify_signature", True) - - try: - payload = jws.verify(token, key, algorithms, verify=verify_signature) - except JWSError as e: - raise JWTError(e) - - # Needed for at_hash verification - algorithm = jws.get_unverified_header(token)["alg"] - - try: - claims = json.loads(payload.decode("utf-8")) - except ValueError as e: - raise JWTError("Invalid payload string: %s" % e) - - if not isinstance(claims, Mapping): - raise JWTError("Invalid payload string: must be a json object") - - _validate_claims( - claims, - audience=audience, - issuer=issuer, - subject=subject, - algorithm=algorithm, - access_token=access_token, - options=defaults, - ) - - return claims - - -def get_unverified_header(token): - """Returns the decoded headers without verification of any kind. - - Args: - token (str): A signed JWT to decode the headers from. - - Returns: - dict: The dict representation of the token headers. - - Raises: - JWTError: If there is an exception decoding the token. - """ - try: - headers = jws.get_unverified_headers(token) - except Exception: - raise JWTError("Error decoding token headers.") - - return headers - - -def get_unverified_headers(token): - """Returns the decoded headers without verification of any kind. - - This is simply a wrapper of get_unverified_header() for backwards - compatibility. - - Args: - token (str): A signed JWT to decode the headers from. - - Returns: - dict: The dict representation of the token headers. - - Raises: - JWTError: If there is an exception decoding the token. - """ - return get_unverified_header(token) - - -def get_unverified_claims(token): - """Returns the decoded claims without verification of any kind. - - Args: - token (str): A signed JWT to decode the headers from. - - Returns: - dict: The dict representation of the token claims. - - Raises: - JWTError: If there is an exception decoding the token. - """ - try: - claims = jws.get_unverified_claims(token) - except Exception: - raise JWTError("Error decoding token claims.") - - try: - claims = json.loads(claims.decode("utf-8")) - except ValueError as e: - raise JWTError("Invalid claims string: %s" % e) - - if not isinstance(claims, Mapping): - raise JWTError("Invalid claims string: must be a json object") - - return claims - - -def _validate_iat(claims): - """Validates that the 'iat' claim is valid. - - The "iat" (issued at) claim identifies the time at which the JWT was - issued. This claim can be used to determine the age of the JWT. Its - value MUST be a number containing a NumericDate value. Use of this - claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - """ - - if "iat" not in claims: - return - - try: - int(claims["iat"]) - except ValueError: - raise JWTClaimsError("Issued At claim (iat) must be an integer.") - - -def _validate_nbf(claims, leeway=0): - """Validates that the 'nbf' claim is valid. - - The "nbf" (not before) claim identifies the time before which the JWT - MUST NOT be accepted for processing. The processing of the "nbf" - claim requires that the current date/time MUST be after or equal to - the not-before date/time listed in the "nbf" claim. Implementers MAY - provide for some small leeway, usually no more than a few minutes, to - account for clock skew. Its value MUST be a number containing a - NumericDate value. Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - leeway (int): The number of seconds of skew that is allowed. - """ - - if "nbf" not in claims: - return - - try: - nbf = int(claims["nbf"]) - except ValueError: - raise JWTClaimsError("Not Before claim (nbf) must be an integer.") - - now = timegm(datetime.now(UTC).utctimetuple()) - - if nbf > (now + leeway): - raise JWTClaimsError("The token is not yet valid (nbf)") - - -def _validate_exp(claims, leeway=0): - """Validates that the 'exp' claim is valid. - - The "exp" (expiration time) claim identifies the expiration time on - or after which the JWT MUST NOT be accepted for processing. The - processing of the "exp" claim requires that the current date/time - MUST be before the expiration date/time listed in the "exp" claim. - Implementers MAY provide for some small leeway, usually no more than - a few minutes, to account for clock skew. Its value MUST be a number - containing a NumericDate value. Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - leeway (int): The number of seconds of skew that is allowed. - """ - - if "exp" not in claims: - return - - try: - exp = int(claims["exp"]) - except ValueError: - raise JWTClaimsError("Expiration Time claim (exp) must be an integer.") - - now = timegm(datetime.now(UTC).utctimetuple()) - - if exp < (now - leeway): - raise ExpiredSignatureError("Signature has expired.") - - -def _validate_aud(claims, audience=None): - """Validates that the 'aud' claim is valid. - - The "aud" (audience) claim identifies the recipients that the JWT is - intended for. Each principal intended to process the JWT MUST - identify itself with a value in the audience claim. If the principal - processing the claim does not identify itself with a value in the - "aud" claim when this claim is present, then the JWT MUST be - rejected. In the general case, the "aud" value is an array of case- - sensitive strings, each containing a StringOrURI value. In the - special case when the JWT has one audience, the "aud" value MAY be a - single case-sensitive string containing a StringOrURI value. The - interpretation of audience values is generally application specific. - Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - audience (str): The audience that is verifying the token. - """ - - if "aud" not in claims: - # if audience: - # raise JWTError('Audience claim expected, but not in claims') - return - - audience_claims = claims["aud"] - if isinstance(audience_claims, str): - audience_claims = [audience_claims] - if not isinstance(audience_claims, list): - raise JWTClaimsError("Invalid claim format in token") - if any(not isinstance(c, str) for c in audience_claims): - raise JWTClaimsError("Invalid claim format in token") - if audience not in audience_claims: - raise JWTClaimsError("Invalid audience") - - -def _validate_iss(claims, issuer=None): - """Validates that the 'iss' claim is valid. - - The "iss" (issuer) claim identifies the principal that issued the - JWT. The processing of this claim is generally application specific. - The "iss" value is a case-sensitive string containing a StringOrURI - value. Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - issuer (str or iterable): Acceptable value(s) for the issuer that - signed the token. - """ - - if issuer is not None: - if isinstance(issuer, str): - issuer = (issuer,) - if claims.get("iss") not in issuer: - raise JWTClaimsError("Invalid issuer") - - -def _validate_sub(claims, subject=None): - """Validates that the 'sub' claim is valid. - - The "sub" (subject) claim identifies the principal that is the - subject of the JWT. The claims in a JWT are normally statements - about the subject. The subject value MUST either be scoped to be - locally unique in the context of the issuer or be globally unique. - The processing of this claim is generally application specific. The - "sub" value is a case-sensitive string containing a StringOrURI - value. Use of this claim is OPTIONAL. - - Arg - claims (dict): The claims dictionary to validate. - subject (str): The subject of the token. - """ - - if "sub" not in claims: - return - - if not isinstance(claims["sub"], str): - raise JWTClaimsError("Subject must be a string.") - - if subject is not None: - if claims.get("sub") != subject: - raise JWTClaimsError("Invalid subject") - - -def _validate_jti(claims): - """Validates that the 'jti' claim is valid. - - The "jti" (JWT ID) claim provides a unique identifier for the JWT. - The identifier value MUST be assigned in a manner that ensures that - there is a negligible probability that the same value will be - accidentally assigned to a different data object; if the application - uses multiple issuers, collisions MUST be prevented among values - produced by different issuers as well. The "jti" claim can be used - to prevent the JWT from being replayed. The "jti" value is a case- - sensitive string. Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - """ - if "jti" not in claims: - return - - if not isinstance(claims["jti"], str): - raise JWTClaimsError("JWT ID must be a string.") - - -def _validate_at_hash(claims, access_token, algorithm): - """ - Validates that the 'at_hash' is valid. - - Its value is the base64url encoding of the left-most half of the hash - of the octets of the ASCII representation of the access_token value, - where the hash algorithm used is the hash algorithm used in the alg - Header Parameter of the ID Token's JOSE Header. For instance, if the - alg is RS256, hash the access_token value with SHA-256, then take the - left-most 128 bits and base64url encode them. The at_hash value is a - case sensitive string. Use of this claim is OPTIONAL. - - Args: - claims (dict): The claims dictionary to validate. - access_token (str): The access token returned by the OpenID Provider. - algorithm (str): The algorithm used to sign the JWT, as specified by - the token headers. - """ - if "at_hash" not in claims: - return - - if not access_token: - msg = "No access_token provided to compare against at_hash claim." - raise JWTClaimsError(msg) - - try: - expected_hash = calculate_at_hash(access_token, ALGORITHMS.HASHES[algorithm]) - except (TypeError, ValueError): - msg = "Unable to calculate at_hash to verify against token claims." - raise JWTClaimsError(msg) - - if claims["at_hash"] != expected_hash: - raise JWTClaimsError("at_hash claim does not match access_token.") - - -def _validate_claims(claims, audience=None, issuer=None, subject=None, algorithm=None, access_token=None, options=None): - leeway = options.get("leeway", 0) - - if isinstance(leeway, timedelta): - leeway = timedelta_total_seconds(leeway) - required_claims = [e[len("require_") :] for e in options.keys() if e.startswith("require_") and options[e]] - for require_claim in required_claims: - if require_claim not in claims: - raise JWTError('missing required key "%s" among claims' % require_claim) - else: - options["verify_" + require_claim] = True # override verify when required - - if not isinstance(audience, ((str,), type(None))): - raise JWTError("audience must be a string or None") - - if options.get("verify_iat"): - _validate_iat(claims) - - if options.get("verify_nbf"): - _validate_nbf(claims, leeway=leeway) - - if options.get("verify_exp"): - _validate_exp(claims, leeway=leeway) - - if options.get("verify_aud"): - _validate_aud(claims, audience=audience) - - if options.get("verify_iss"): - _validate_iss(claims, issuer=issuer) - - if options.get("verify_sub"): - _validate_sub(claims, subject=subject) - - if options.get("verify_jti"): - _validate_jti(claims) - - if options.get("verify_at_hash"): - _validate_at_hash(claims, access_token, algorithm) diff --git a/backend/venv39/lib/python3.9/site-packages/jose/utils.py b/backend/venv39/lib/python3.9/site-packages/jose/utils.py deleted file mode 100644 index d62cafb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/jose/utils.py +++ /dev/null @@ -1,165 +0,0 @@ -import base64 -import re -import struct - -# Piggyback of the backends implementation of the function that converts a long -# to a bytes stream. Some plumbing is necessary to have the signatures match. -try: - from cryptography.utils import int_to_bytes as _long_to_bytes - - def long_to_bytes(n, blocksize=0): - return _long_to_bytes(n, blocksize or None) - -except ImportError: - from ecdsa.ecdsa import int_to_string as _long_to_bytes - - def long_to_bytes(n, blocksize=0): - ret = _long_to_bytes(n) - if blocksize == 0: - return ret - else: - assert len(ret) <= blocksize - padding = blocksize - len(ret) - return b"\x00" * padding + ret - - -def long_to_base64(data, size=0): - return base64.urlsafe_b64encode(long_to_bytes(data, size)).strip(b"=") - - -def int_arr_to_long(arr): - return int("".join(["%02x" % byte for byte in arr]), 16) - - -def base64_to_long(data): - if isinstance(data, str): - data = data.encode("ascii") - - # urlsafe_b64decode will happily convert b64encoded data - _d = base64.urlsafe_b64decode(bytes(data) + b"==") - return int_arr_to_long(struct.unpack("%sB" % len(_d), _d)) - - -def calculate_at_hash(access_token, hash_alg): - """Helper method for calculating an access token - hash, as described in http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken - - Its value is the base64url encoding of the left-most half of the hash of the octets - of the ASCII representation of the access_token value, where the hash algorithm - used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE - Header. For instance, if the alg is RS256, hash the access_token value with SHA-256, - then take the left-most 128 bits and base64url encode them. The at_hash value is a - case sensitive string. - - Args: - access_token (str): An access token string. - hash_alg (callable): A callable returning a hash object, e.g. hashlib.sha256 - - """ - hash_digest = hash_alg(access_token.encode("utf-8")).digest() - cut_at = int(len(hash_digest) / 2) - truncated = hash_digest[:cut_at] - at_hash = base64url_encode(truncated) - return at_hash.decode("utf-8") - - -def base64url_decode(input): - """Helper method to base64url_decode a string. - - Args: - input (bytes): A base64url_encoded string (bytes) to decode. - - """ - rem = len(input) % 4 - - if rem > 0: - input += b"=" * (4 - rem) - - return base64.urlsafe_b64decode(input) - - -def base64url_encode(input): - """Helper method to base64url_encode a string. - - Args: - input (bytes): A base64url_encoded string (bytes) to encode. - - """ - return base64.urlsafe_b64encode(input).replace(b"=", b"") - - -def timedelta_total_seconds(delta): - """Helper method to determine the total number of seconds - from a timedelta. - - Args: - delta (timedelta): A timedelta to convert to seconds. - """ - return delta.days * 24 * 60 * 60 + delta.seconds - - -def ensure_binary(s): - """Coerce **s** to bytes.""" - - if isinstance(s, bytes): - return s - if isinstance(s, str): - return s.encode("utf-8", "strict") - raise TypeError(f"not expecting type '{type(s)}'") - - -# The following was copied from PyJWT: -# https://github.com/jpadilla/pyjwt/commit/9c528670c455b8d948aff95ed50e22940d1ad3fc -# Based on: -# https://github.com/hynek/pem/blob/7ad94db26b0bc21d10953f5dbad3acfdfacf57aa/src/pem/_core.py#L224-L252 -_PEMS = { - b"CERTIFICATE", - b"TRUSTED CERTIFICATE", - b"PRIVATE KEY", - b"PUBLIC KEY", - b"ENCRYPTED PRIVATE KEY", - b"OPENSSH PRIVATE KEY", - b"DSA PRIVATE KEY", - b"RSA PRIVATE KEY", - b"RSA PUBLIC KEY", - b"EC PRIVATE KEY", - b"DH PARAMETERS", - b"NEW CERTIFICATE REQUEST", - b"CERTIFICATE REQUEST", - b"SSH2 PUBLIC KEY", - b"SSH2 ENCRYPTED PRIVATE KEY", - b"X509 CRL", -} -_PEM_RE = re.compile( - b"----[- ]BEGIN (" + b"|".join(re.escape(pem) for pem in _PEMS) + b")[- ]----", -) - - -def is_pem_format(key: bytes) -> bool: - return bool(_PEM_RE.search(key)) - - -# Based on -# https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b -# /src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 -_CERT_SUFFIX = b"-cert-v01@openssh.com" -_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") -_SSH_KEY_FORMATS = [ - b"ssh-ed25519", - b"ssh-rsa", - b"ssh-dss", - b"ecdsa-sha2-nistp256", - b"ecdsa-sha2-nistp384", - b"ecdsa-sha2-nistp521", -] - - -def is_ssh_key(key: bytes) -> bool: - if any(string_value in key for string_value in _SSH_KEY_FORMATS): - return True - ssh_pubkey_match = _SSH_PUBKEY_RC.match(key) - if ssh_pubkey_match: - key_type = ssh_pubkey_match.group(1) - if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]: - return True - return False diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/LICENSE deleted file mode 100644 index 8f71f43..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/METADATA deleted file mode 100644 index 6b3cc45..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/METADATA +++ /dev/null @@ -1,186 +0,0 @@ -Metadata-Version: 2.1 -Name: minio -Version: 7.2.20 -Summary: MinIO Python SDK for Amazon S3 Compatible Cloud Storage -Home-page: https://github.com/minio/minio-py -Download-URL: https://github.com/minio/minio-py/releases -Author: MinIO, Inc. -Author-email: dev@min.io -License: Apache-2.0 -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -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 :: 3.13 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.9 -Description-Content-Type: text/markdown -License-File: LICENSE -License-File: NOTICE -Requires-Dist: argon2-cffi -Requires-Dist: certifi -Requires-Dist: pycryptodome -Requires-Dist: typing-extensions -Requires-Dist: urllib3 - -# MinIO Python Client SDK for Amazon S3 Compatible Cloud Storage [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/minio/minio-py/blob/master/LICENSE) - -The MinIO Python Client SDK provides high level APIs to access any MinIO Object Storage or other Amazon S3 compatible service. - -This Quickstart Guide covers how to install the MinIO client SDK, connect to the object storage service, and create a sample file uploader. - -The example below uses: -- [Python version 3.7+](https://www.python.org/downloads/) -- The [MinIO `mc` command line tool](https://min.io/docs/minio/linux/reference/minio-mc.html) -- The MinIO `play` test server - -The `play` server is a public MinIO cluster located at [https://play.min.io](https://play.min.io). -This cluster runs the latest stable version of MinIO and may be used for testing and development. -The access credentials in the example are open to the public and all data uploaded to `play` should be considered public and world-readable. - -For a complete list of APIs and examples, see the [Python Client API Reference](https://min.io/docs/minio/linux/developers/python/API.html) - -## Install the MinIO Python SDK - -The Python SDK requires Python version 3.7+. -You can install the SDK with `pip` or from the [`minio/minio-py` GitHub repository](https://github.com/minio/minio-py): - -### Using `pip` - -```sh -pip3 install minio -``` - -### Using Source From GitHub - -```sh -git clone https://github.com/minio/minio-py -cd minio-py -python setup.py install -``` - -## Create a MinIO Client - -To connect to the target service, create a MinIO client using the `Minio()` method with the following required parameters: - -| Parameter | Description | -|--------------|--------------------------------------------------------| -| `endpoint` | URL of the target service. | -| `access_key` | Access key (user ID) of a user account in the service. | -| `secret_key` | Secret key (password) for the user account. | - -For example: - -```py -from minio import Minio - -client = Minio("play.min.io", - access_key="Q3AM3UQ867SPQQA43P2F", - secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", -) -``` - -## Example - File Uploader - -This example does the following: - -- Connects to the MinIO `play` server using the provided credentials. -- Creates a bucket named `python-test-bucket` if it does not already exist. -- Uploads a file named `test-file.txt` from `/tmp`, renaming it `my-test-file.txt`. -- Verifies the file was created using [`mc ls`](https://min.io/docs/minio/linux/reference/minio-mc/mc-ls.html). - -### `file_uploader.py` - -```py -# file_uploader.py MinIO Python SDK example -from minio import Minio -from minio.error import S3Error - -def main(): - # Create a client with the MinIO server playground, its access key - # and secret key. - client = Minio("play.min.io", - access_key="Q3AM3UQ867SPQQA43P2F", - secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", - ) - - # The file to upload, change this path if needed - source_file = "/tmp/test-file.txt" - - # The destination bucket and filename on the MinIO server - bucket_name = "python-test-bucket" - destination_file = "my-test-file.txt" - - # Make the bucket if it doesn't exist. - found = client.bucket_exists(bucket_name) - if not found: - client.make_bucket(bucket_name) - print("Created bucket", bucket_name) - else: - print("Bucket", bucket_name, "already exists") - - # Upload the file, renaming it in the process - client.fput_object( - bucket_name, destination_file, source_file, - ) - print( - source_file, "successfully uploaded as object", - destination_file, "to bucket", bucket_name, - ) - -if __name__ == "__main__": - try: - main() - except S3Error as exc: - print("error occurred.", exc) -``` - -To run this example: - -1. Create a file in `/tmp` named `test-file.txt`. - To use a different path or filename, modify the value of `source_file`. - -2. Run `file_uploader.py` with the following command: - -```sh -python file_uploader.py -``` - -If the bucket does not exist on the server, the output resembles the following: - -```sh -Created bucket python-test-bucket -/tmp/test-file.txt successfully uploaded as object my-test-file.txt to bucket python-test-bucket -``` - -3. Verify the uploaded file with `mc ls`: - -```sh -mc ls play/python-test-bucket -[2023-11-03 22:18:54 UTC] 20KiB STANDARD my-test-file.txt -``` - -## More References - -* [Python Client API Reference](https://min.io/docs/minio/linux/developers/python/API.html) -* [Examples](https://github.com/minio/minio-py/tree/master/examples) - -## Explore Further - -* [Complete Documentation](https://min.io/docs/minio/kubernetes/upstream/index.html) - -## Contribute - -[Contributors Guide](https://github.com/minio/minio-py/blob/master/CONTRIBUTING.md) - -## License - -This SDK is distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), see [LICENSE](https://github.com/minio/minio-py/blob/master/LICENSE) and [NOTICE](https://github.com/minio/minio-go/blob/master/NOTICE) for more information. - -[![PYPI](https://img.shields.io/pypi/v/minio.svg)](https://pypi.python.org/pypi/minio) diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/NOTICE b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/NOTICE deleted file mode 100644 index a4d9534..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/NOTICE +++ /dev/null @@ -1,9 +0,0 @@ -MinIO Cloud Storage, (C) 2014-2023 MinIO, Inc. - -This product includes software developed at MinIO, Inc. -(https://min.io/). - -The MinIO project contains unmodified/modified subcomponents too with -separate copyright notices and license terms. Your use of the source -code for these subcomponents is subject to the terms and conditions -of Apache License Version 2.0 diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/RECORD deleted file mode 100644 index 74a8c1c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/RECORD +++ /dev/null @@ -1,61 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/commonconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/credentials/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/credentials/credentials.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/credentials/providers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/crypto.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/datatypes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/deleteobjects.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/helpers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/legalhold.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/lifecycleconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/minioadmin.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/notificationconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/objectlockconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/replicationconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/retention.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/select.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/signer.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/sse.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/sseconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/tagging.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/time.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/versioningconfig.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/minio/xml.cpython-39.pyc,, -minio-7.2.20.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -minio-7.2.20.dist-info/LICENSE,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358 -minio-7.2.20.dist-info/METADATA,sha256=cmyDnnBYtCBTXQ5oYkbc9w3pJzYtAtHEnusjG8GGqcM,6469 -minio-7.2.20.dist-info/NOTICE,sha256=MnO8F01j4TNa1aGzx57kfJ0pPSDjJ4TPFccpijyHn24,361 -minio-7.2.20.dist-info/RECORD,, -minio-7.2.20.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -minio-7.2.20.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 -minio-7.2.20.dist-info/top_level.txt,sha256=_QXRsuP8oCC8KBltwzOB_UiqpowlXBG6VWD2zo5gY9k,6 -minio/__init__.py,sha256=jDrpU2rPldnuJ6unP2CFiho04g72gs7nOuL1g3G2o4w,1623 -minio/api.py,sha256=awN0vwJgnVR6UJCTT_Sz28JBcSKMl_hiH_QPzC7W06I,125713 -minio/commonconfig.py,sha256=wiGjfhYqODc2MZbDTNm-JMp2hdow3AtYvRkCEw4kNfg,15763 -minio/credentials/__init__.py,sha256=sie66xdSi-fRTN_i-Ja3YG0UYWDUGEULy8mzPUXLDCI,1149 -minio/credentials/credentials.py,sha256=mCGOdyPy_8_3GsCWSdZrxLyRwUJ13YPDWDByh69QJTU,1783 -minio/credentials/providers.py,sha256=4x_dF7BIsFbG8wOshTgQdRNz9rj_PdFd8iFAGtKUfDI,26719 -minio/crypto.py,sha256=HjkFIjJruXD5KMZ5Q5x6jcQzcjIjkcWK-5Qg19mKiQU,7516 -minio/datatypes.py,sha256=TBd9h4NnedPh273QapzREyCMs3PA_hDuzFYxcaEywng,27017 -minio/deleteobjects.py,sha256=6aySqhK2c8jqbOj6cAhcpb34ETb6oASHu_QmSlDjOmE,4211 -minio/error.py,sha256=1_NnxGlqHMa3lMOkwn_OQFONp3nA7GuxDXYMeeFOagU,7335 -minio/helpers.py,sha256=JDcea93E0POxfTSlTXGxbLAkltgiC_Jtvw9Iix5ogCw,28147 -minio/legalhold.py,sha256=kSY5vSF3mdRDZQeJsZOqK0z0NBBQcJbJKPMEtynO0o4,1556 -minio/lifecycleconfig.py,sha256=2nPQqt0SiZM5WRJnJqOdqcSrtH0At1mP3xAd2XQV6LE,12378 -minio/minioadmin.py,sha256=O8bzWwmKjv-F40svAamwr6P7LO-XdddsDXPkswaohzc,35575 -minio/notificationconfig.py,sha256=iL8p7g3nhiota8emfi_S3MQ_uiF4RvtDoEn5SeIPjuU,9544 -minio/objectlockconfig.py,sha256=9Q0cibUEYxgQRK7z2mqcUx6CiMvcpKgTLIhGDc9f4nY,3394 -minio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -minio/replicationconfig.py,sha256=ICaVIIFSGr-gUZJrRI4d-7grXjUISIjpggcEjZKA0_I,14518 -minio/retention.py,sha256=L2JtaJW7pXJYlL5XI7uo4Q9pVcByBidOpFBMfneYWvw,2351 -minio/select.py,sha256=7DEfY7D2bG6k6VjVEUBm8M_24m17AKZ3_ofdgvs56Ew,13137 -minio/signer.py,sha256=NP1715aeFrdXyxIlHHunPrBmglvw4xdRYMofjkYAFzc,9871 -minio/sse.py,sha256=hHTLOywGg-CDBMxGHL7WBMNOQrMr9wcuUqXQp2cW-jo,3491 -minio/sseconfig.py,sha256=JdrA3mFxuipH8ei3KKbSa5HA04cOE11GENDcJJT1L50,3251 -minio/tagging.py,sha256=rgtmZpM03Iyk3JZcyPamPNs2c4qUsTfzEEE5ym4mpcg,1677 -minio/time.py,sha256=q1HHxUydz4m1L_q8QZ1i2mEiNTfA8QATbgYXqYpDRiQ,4099 -minio/versioningconfig.py,sha256=WcUDj3MGhnCyGoq80pqYbg0QWqG-mJS08jflPgNhiHQ,3227 -minio/xml.py,sha256=Bd5etwkapvz2VUAZe-Z9owqSdAiYOw26CZHR4b5duMg,3935 diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/WHEEL deleted file mode 100644 index 98c0d20..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.42.0) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/top_level.txt deleted file mode 100644 index 36f9d86..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio-7.2.20.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -minio diff --git a/backend/venv39/lib/python3.9/site-packages/minio/__init__.py b/backend/venv39/lib/python3.9/site-packages/minio/__init__.py deleted file mode 100644 index 99facfb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2015, 2016, 2017 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -minio - MinIO Python SDK for Amazon S3 Compatible Cloud Storage - - >>> from minio import Minio - >>> client = Minio( - ... "play.min.io", - ... access_key="Q3AM3UQ867SPQQA43P2F", - ... secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", - ... ) - >>> buckets = client.list_buckets() - >>> for bucket in buckets: - ... print(bucket.name, bucket.creation_date) - -:copyright: (C) 2015-2020 MinIO, Inc. -:license: Apache 2.0, see LICENSE for more details. -""" - -__title__ = "minio-py" -__author__ = "MinIO, Inc." -__version__ = "7.2.20" -__license__ = "Apache 2.0" -__copyright__ = "Copyright 2015, 2016, 2017, 2018, 2019, 2020 MinIO, Inc." - -# pylint: disable=unused-import,useless-import-alias -from .api import Minio as Minio -from .error import InvalidResponseError as InvalidResponseError -from .error import S3Error as S3Error -from .error import ServerError as ServerError -from .minioadmin import MinioAdmin as MinioAdmin diff --git a/backend/venv39/lib/python3.9/site-packages/minio/api.py b/backend/venv39/lib/python3.9/site-packages/minio/api.py deleted file mode 100644 index b7424cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/api.py +++ /dev/null @@ -1,3443 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2015, 2016, 2017 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=too-many-arguments -# pylint: disable=too-many-branches -# pylint: disable=too-many-function-args -# pylint: disable=too-many-lines -# pylint: disable=too-many-public-methods -# pylint: disable=too-many-statements -# pylint: disable=too-many-locals -# pylint: disable=too-many-positional-arguments - -""" -Simple Storage Service (aka S3) client to perform bucket and object operations. -""" - -from __future__ import absolute_import, annotations - -import itertools -import json -import os -import tarfile -from collections.abc import Iterable -from datetime import datetime, timedelta -from io import BytesIO -from random import random -from typing import (Any, BinaryIO, Iterator, Optional, TextIO, Tuple, Union, - cast) -from urllib.parse import urlunsplit -from xml.etree import ElementTree as ET - -import certifi -import urllib3 -from urllib3 import Retry -from urllib3._collections import HTTPHeaderDict - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -from urllib3.util import Timeout - -from . import time -from .commonconfig import (COPY, REPLACE, ComposeSource, CopySource, - SnowballObject, Tags) -from .credentials import Credentials, StaticProvider -from .credentials.providers import Provider -from .datatypes import (Bucket, CompleteMultipartUploadResult, EventIterable, - ListAllMyBucketsResult, ListMultipartUploadsResult, - ListPartsResult, Object, Part, PostPolicy, - parse_copy_object, parse_list_objects) -from .deleteobjects import (DeleteError, DeleteObject, DeleteRequest, - DeleteResult) -from .error import InvalidResponseError, S3Error, ServerError -from .helpers import (_DEFAULT_USER_AGENT, MAX_MULTIPART_COUNT, - MAX_MULTIPART_OBJECT_SIZE, MAX_PART_SIZE, MIN_PART_SIZE, - BaseURL, DictType, ObjectWriteResult, ProgressType, - ThreadPool, check_bucket_name, check_object_name, - check_sse, check_ssec, genheaders, get_part_info, - headers_to_strings, is_valid_policy_type, makedirs, - md5sum_hash, queryencode, read_part_data, sha256_hash) -from .legalhold import LegalHold -from .lifecycleconfig import LifecycleConfig -from .notificationconfig import NotificationConfig -from .objectlockconfig import ObjectLockConfig -from .replicationconfig import ReplicationConfig -from .retention import Retention -from .select import SelectObjectReader, SelectRequest -from .signer import presign_v4, sign_v4_s3 -from .sse import Sse, SseCustomerKey -from .sseconfig import SSEConfig -from .tagging import Tagging -from .versioningconfig import VersioningConfig -from .xml import Element, SubElement, findtext, getbytes, marshal, unmarshal - - -class Minio: - """ - Simple Storage Service (aka S3) client to perform bucket and object - operations. - - :param endpoint: Hostname of a S3 service. - :param access_key: Access key (aka user ID) of your account in S3 service. - :param secret_key: Secret Key (aka password) of your account in S3 service. - :param session_token: Session token of your account in S3 service. - :param secure: Flag to indicate to use secure (TLS) connection to S3 - service or not. - :param region: Region name of buckets in S3 service. - :param http_client: Customized HTTP client. - :param credentials: Credentials provider of your account in S3 service. - :param cert_check: Flag to indicate to verify SSL certificate or not. - :return: :class:`Minio ` object - - Example:: - # Create client with anonymous access. - client = Minio("play.min.io") - - # Create client with access and secret key. - client = Minio("s3.amazonaws.com", "ACCESS-KEY", "SECRET-KEY") - - # Create client with access key and secret key with specific region. - client = Minio( - "play.minio.io:9000", - access_key="Q3AM3UQ867SPQQA43P2F", - secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", - region="my-region", - ) - - **NOTE on concurrent usage:** `Minio` object is thread safe when using - the Python `threading` library. Specifically, it is **NOT** safe to share - it between multiple processes, for example when using - `multiprocessing.Pool`. The solution is simply to create a new `Minio` - object in each process, and not share it between processes. - - """ - _region_map: dict[str, str] - _base_url: BaseURL - _user_agent: str - _trace_stream: Optional[TextIO] - _provider: Optional[Provider] - _http: urllib3.PoolManager - - def __init__( - self, - endpoint: str, - access_key: Optional[str] = None, - secret_key: Optional[str] = None, - session_token: Optional[str] = None, - secure: bool = True, - region: Optional[str] = None, - http_client: Optional[urllib3.PoolManager] = None, - credentials: Optional[Provider] = None, - cert_check: bool = True, - ): - # Validate http client has correct base class. - if http_client and not isinstance(http_client, urllib3.PoolManager): - raise ValueError( - "HTTP client should be instance of `urllib3.PoolManager`" - ) - - self._region_map = {} - self._base_url = BaseURL( - ("https://" if secure else "http://") + endpoint, - region, - ) - self._user_agent = _DEFAULT_USER_AGENT - self._trace_stream = None - if access_key: - if secret_key is None: - raise ValueError("secret key must be provided with access key") - credentials = StaticProvider(access_key, secret_key, session_token) - self._provider = credentials - - # Load CA certificates from SSL_CERT_FILE file if set - timeout = timedelta(minutes=5).seconds - self._http = http_client or urllib3.PoolManager( - timeout=Timeout(connect=timeout, read=timeout), - maxsize=10, - cert_reqs='CERT_REQUIRED' if cert_check else 'CERT_NONE', - ca_certs=os.environ.get('SSL_CERT_FILE') or certifi.where(), - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504] - ) - ) - - def __del__(self): - if hasattr(self, "_http"): # Only required for unit test run - self._http.clear() - - def _handle_redirect_response( - self, - method: str, - response: BaseHTTPResponse, - bucket_name: Optional[str] = None, - retry: bool = False, - ) -> tuple[Optional[str], Optional[str]]: - """ - Handle redirect response indicates whether retry HEAD request - on failure. - """ - code, message = { - 301: ("PermanentRedirect", "Moved Permanently"), - 307: ("Redirect", "Temporary redirect"), - 400: ("BadRequest", "Bad request"), - }.get(response.status, (None, None)) - region = response.headers.get("x-amz-bucket-region") - if message and region: - message += "; use region " + region - - if ( - retry and region and method == "HEAD" and bucket_name and - self._region_map.get(bucket_name) - ): - code, message = ("RetryHead", None) - - return code, message - - def _build_headers( - self, - host: str, - headers: Optional[DictType] = None, - body: Optional[bytes] = None, - creds: Optional[Credentials] = None, - ) -> tuple[DictType, datetime]: - """Build headers with given parameters.""" - headers = headers or {} - md5sum_added = headers.get("Content-MD5") - headers["Host"] = host - headers["User-Agent"] = self._user_agent - sha256 = None - md5sum = None - - if body: - headers["Content-Length"] = str(len(body)) - if creds: - if self._base_url.is_https: - sha256 = "UNSIGNED-PAYLOAD" - md5sum = None if md5sum_added else md5sum_hash(body) - else: - sha256 = sha256_hash(body) - else: - md5sum = None if md5sum_added else md5sum_hash(body) - if md5sum: - headers["Content-MD5"] = md5sum - if sha256: - headers["x-amz-content-sha256"] = sha256 - if creds and creds.session_token: - headers["X-Amz-Security-Token"] = creds.session_token - date = time.utcnow() - headers["x-amz-date"] = time.to_amz_date(date) - return headers, date - - def _url_open( - self, - method: str, - region: str, - bucket_name: Optional[str] = None, - object_name: Optional[str] = None, - body: Optional[bytes] = None, - headers: Optional[DictType] = None, - query_params: Optional[DictType] = None, - preload_content: bool = True, - no_body_trace: bool = False, - ) -> BaseHTTPResponse: - """Execute HTTP request.""" - creds = self._provider.retrieve() if self._provider else None - url = self._base_url.build( - method=method, - region=region, - bucket_name=bucket_name, - object_name=object_name, - query_params=query_params, - ) - headers, date = self._build_headers(url.netloc, headers, body, creds) - if creds: - headers = sign_v4_s3( - method=method, - url=url, - region=region, - headers=headers, - credentials=creds, - content_sha256=cast(str, headers.get("x-amz-content-sha256")), - date=date, - ) - - if self._trace_stream: - self._trace_stream.write("---------START-HTTP---------\n") - query = ("?" + url.query) if url.query else "" - self._trace_stream.write(f"{method} {url.path}{query} HTTP/1.1\n") - self._trace_stream.write( - headers_to_strings(headers, titled_key=True), - ) - self._trace_stream.write("\n") - if not no_body_trace and body is not None: - self._trace_stream.write("\n") - self._trace_stream.write( - body.decode() if isinstance(body, bytes) else str(body), - ) - self._trace_stream.write("\n") - self._trace_stream.write("\n") - - http_headers = HTTPHeaderDict() - for key, value in (headers or {}).items(): - if isinstance(value, (list, tuple)): - for val in value: - http_headers.add(key, val) - else: - http_headers.add(key, value) - - response = self._http.urlopen( - method, - urlunsplit(url), - body=body, - headers=http_headers, - preload_content=preload_content, - ) - - if self._trace_stream: - self._trace_stream.write(f"HTTP/1.1 {response.status}\n") - self._trace_stream.write( - headers_to_strings(response.headers), - ) - self._trace_stream.write("\n") - - if response.status in [200, 204, 206]: - if self._trace_stream: - if preload_content: - self._trace_stream.write("\n") - self._trace_stream.write(response.data.decode()) - self._trace_stream.write("\n") - self._trace_stream.write("----------END-HTTP----------\n") - return response - - response.read(cache_content=True) - if not preload_content: - response.release_conn() - - if self._trace_stream and method != "HEAD" and response.data: - self._trace_stream.write(response.data.decode()) - self._trace_stream.write("\n") - - if ( - method != "HEAD" and - "application/xml" not in response.headers.get( - "content-type", "", - ).split(";") - ): - if self._trace_stream: - self._trace_stream.write("----------END-HTTP----------\n") - if response.status == 304 and not response.data: - raise ServerError( - f"server failed with HTTP status code {response.status}", - response.status, - ) - raise InvalidResponseError( - response.status, - cast(str, response.headers.get("content-type")), - response.data.decode() if response.data else None, - ) - - if not response.data and method != "HEAD": - if self._trace_stream: - self._trace_stream.write("----------END-HTTP----------\n") - raise InvalidResponseError( - response.status, - response.headers.get("content-type"), - None, - ) - - response_error = S3Error.fromxml(response) if response.data else None - - if self._trace_stream: - self._trace_stream.write("----------END-HTTP----------\n") - - error_map = { - 301: lambda: self._handle_redirect_response( - method, response, bucket_name, True, - ), - 307: lambda: self._handle_redirect_response( - method, response, bucket_name, True, - ), - 400: lambda: self._handle_redirect_response( - method, response, bucket_name, True, - ), - 403: lambda: ("AccessDenied", "Access denied"), - 404: lambda: ( - ("NoSuchKey", "Object does not exist") - if object_name - else ("NoSuchBucket", "Bucket does not exist") - if bucket_name - else ("ResourceNotFound", "Request resource not found") - ), - 405: lambda: ( - "MethodNotAllowed", - "The specified method is not allowed against this resource", - ), - 409: lambda: ( - ("NoSuchBucket", "Bucket does not exist") - if bucket_name - else ("ResourceConflict", "Request resource conflicts"), - ), - 501: lambda: ( - "MethodNotAllowed", - "The specified method is not allowed against this resource", - ), - } - - if not response_error: - func = error_map.get(response.status) - code, message = func() if func else (None, None) - if not code: - raise ServerError( - f"server failed with HTTP status code {response.status}", - response.status, - ) - response_error = S3Error( - response=response, - code=cast(str, code), - message=cast(Union[str, None], message), - resource=url.path, - request_id=response.headers.get("x-amz-request-id"), - host_id=response.headers.get("x-amz-id-2"), - bucket_name=bucket_name, - object_name=object_name, - ) - - if response_error.code in ["NoSuchBucket", "RetryHead"]: - if bucket_name is not None: - self._region_map.pop(bucket_name, None) - - raise response_error - - def _execute( - self, - method: str, - bucket_name: Optional[str] = None, - object_name: Optional[str] = None, - body: Optional[bytes] = None, - headers: Optional[DictType] = None, - query_params: Optional[DictType] = None, - preload_content: bool = True, - no_body_trace: bool = False, - ) -> BaseHTTPResponse: - """Execute HTTP request.""" - region = self._get_region(bucket_name) - - try: - return self._url_open( - method, - region, - bucket_name=bucket_name, - object_name=object_name, - body=body, - headers=headers, - query_params=query_params, - preload_content=preload_content, - no_body_trace=no_body_trace, - ) - except S3Error as exc: - if exc.code != "RetryHead": - raise - - # Retry only once on RetryHead error. - try: - return self._url_open( - method, - region, - bucket_name=bucket_name, - object_name=object_name, - body=body, - headers=headers, - query_params=query_params, - preload_content=preload_content, - no_body_trace=no_body_trace, - ) - except S3Error as exc: - if exc.code != "RetryHead": - raise - - code, message = self._handle_redirect_response( - method, exc.response, bucket_name, - ) - raise exc.copy(cast(str, code), cast(str, message)) - - def _get_region(self, bucket_name: Optional[str] = None) -> str: - """ - Return region of given bucket either from region cache or set in - constructor. - """ - - if self._base_url.region: - return self._base_url.region - - if not bucket_name or not self._provider: - return "us-east-1" - - region = self._region_map.get(bucket_name) - if region: - return region - - # Execute GetBucketLocation REST API to get region of the bucket. - response = self._url_open( - "GET", - "us-east-1", - bucket_name=bucket_name, - query_params={"location": ""}, - ) - - element = ET.fromstring(response.data.decode()) - if not element.text: - region = "us-east-1" - elif element.text == "EU" and self._base_url.is_aws_host: - region = "eu-west-1" - else: - region = element.text - - self._region_map[bucket_name] = region - return region - - def set_app_info(self, app_name: str, app_version: str): - """ - Set your application name and version to user agent header. - - :param app_name: Application name. - :param app_version: Application version. - - Example:: - client.set_app_info('my_app', '1.0.2') - """ - if not (app_name and app_version): - raise ValueError("Application name/version cannot be empty.") - self._user_agent = f"{_DEFAULT_USER_AGENT} {app_name}/{app_version}" - - def trace_on(self, stream: TextIO): - """ - Enable http trace. - - :param stream: Stream for writing HTTP call tracing. - """ - if not stream: - raise ValueError('Input stream for trace output is invalid.') - # Save new output stream. - self._trace_stream = stream - - def trace_off(self): - """ - Disable HTTP trace. - """ - self._trace_stream = None - - def enable_accelerate_endpoint(self): - """Enables accelerate endpoint for Amazon S3 endpoint.""" - self._base_url.accelerate_host_flag = True - - def disable_accelerate_endpoint(self): - """Disables accelerate endpoint for Amazon S3 endpoint.""" - self._base_url.accelerate_host_flag = False - - def enable_dualstack_endpoint(self): - """Enables dualstack endpoint for Amazon S3 endpoint.""" - self._base_url.dualstack_host_flag = True - - def disable_dualstack_endpoint(self): - """Disables dualstack endpoint for Amazon S3 endpoint.""" - self._base_url.dualstack_host_flag = False - - def enable_virtual_style_endpoint(self): - """Enables virtual style endpoint.""" - self._base_url.virtual_style_flag = True - - def disable_virtual_style_endpoint(self): - """Disables virtual style endpoint.""" - self._base_url.virtual_style_flag = False - - def select_object_content( - self, - bucket_name: str, - object_name: str, - request: SelectRequest, - ) -> SelectObjectReader: - """ - Select content of an object by SQL expression. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param request: :class:`SelectRequest ` object. - :return: A reader contains requested records and progress information. - - Example:: - with client.select_object_content( - "my-bucket", - "my-object.csv", - SelectRequest( - "select * from S3Object", - CSVInputSerialization(), - CSVOutputSerialization(), - request_progress=True, - ), - ) as result: - for data in result.stream(): - print(data.decode()) - print(result.stats()) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if not isinstance(request, SelectRequest): - raise ValueError("request must be SelectRequest type") - body = marshal(request) - response = self._execute( - "POST", - bucket_name=bucket_name, - object_name=object_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"select": "", "select-type": "2"}, - preload_content=False, - ) - return SelectObjectReader(response) - - def make_bucket( - self, - bucket_name: str, - location: Optional[str] = None, - object_lock: bool = False, - ): - """ - Create a bucket with region and object lock. - - :param bucket_name: Name of the bucket. - :param location: Region in which the bucket will be created. - :param object_lock: Flag to set object-lock feature. - - Examples:: - # Create bucket. - client.make_bucket("my-bucket") - - # Create bucket on specific region. - client.make_bucket("my-bucket", "us-west-1") - - # Create bucket with object-lock feature on specific region. - client.make_bucket("my-bucket", "eu-west-2", object_lock=True) - """ - check_bucket_name(bucket_name, True, - s3_check=self._base_url.is_aws_host) - if self._base_url.region: - # Error out if region does not match with region passed via - # constructor. - if location and self._base_url.region != location: - raise ValueError( - f"region must be {self._base_url.region}, " - f"but passed {location}" - ) - location = self._base_url.region or location or "us-east-1" - headers: Optional[DictType] = ( - {"x-amz-bucket-object-lock-enabled": "true"} - if object_lock else None - ) - - body = None - if location != "us-east-1": - element = Element("CreateBucketConfiguration") - SubElement(element, "LocationConstraint", location) - body = getbytes(element) - self._url_open( - "PUT", - location, - bucket_name=bucket_name, - body=body, - headers=headers, - ) - self._region_map[bucket_name] = location - - def list_buckets(self) -> list[Bucket]: - """ - List information of all accessible buckets. - - :return: List of :class:`Bucket ` object. - - Example:: - buckets = client.list_buckets() - for bucket in buckets: - print(bucket.name, bucket.creation_date) - """ - - response = self._execute("GET") - result = unmarshal(ListAllMyBucketsResult, response.data.decode()) - return result.buckets - - def bucket_exists(self, bucket_name: str) -> bool: - """ - Check if a bucket exists. - - :param bucket_name: Name of the bucket. - :return: True if the bucket exists. - - Example:: - if client.bucket_exists("my-bucket"): - print("my-bucket exists") - else: - print("my-bucket does not exist") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - self._execute("HEAD", bucket_name) - return True - except S3Error as exc: - if exc.code != "NoSuchBucket": - raise - return False - - def remove_bucket(self, bucket_name: str): - """ - Remove an empty bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.remove_bucket("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - self._execute("DELETE", bucket_name) - self._region_map.pop(bucket_name, None) - - def get_bucket_policy(self, bucket_name: str) -> str: - """ - Get bucket policy configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: Bucket policy configuration as JSON string. - - Example:: - policy = client.get_bucket_policy("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - response = self._execute( - "GET", bucket_name, query_params={"policy": ""}, - ) - return response.data.decode() - - def delete_bucket_policy(self, bucket_name: str): - """ - Delete bucket policy configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_policy("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - self._execute("DELETE", bucket_name, query_params={"policy": ""}) - - def set_bucket_policy(self, bucket_name: str, policy: str | bytes): - """ - Set bucket policy configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param policy: Bucket policy configuration as JSON string. - - Example:: - client.set_bucket_policy("my-bucket", policy) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - is_valid_policy_type(policy) - self._execute( - "PUT", - bucket_name, - body=policy if isinstance(policy, bytes) else policy.encode(), - headers={"Content-MD5": cast(str, md5sum_hash(policy))}, - query_params={"policy": ""}, - ) - - def get_bucket_notification(self, bucket_name: str) -> NotificationConfig: - """ - Get notification configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`NotificationConfig ` object. - - Example:: - config = client.get_bucket_notification("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - response = self._execute( - "GET", bucket_name, query_params={"notification": ""}, - ) - return unmarshal(NotificationConfig, response.data.decode()) - - def set_bucket_notification( - self, - bucket_name: str, - config: NotificationConfig, - ): - """ - Set notification configuration of a bucket. - - :param bucket_name: Name of the bucket. - :param config: class:`NotificationConfig ` object. - - Example:: - config = NotificationConfig( - queue_config_list=[ - QueueConfig( - "QUEUE-ARN-OF-THIS-BUCKET", - ["s3:ObjectCreated:*"], - config_id="1", - prefix_filter_rule=PrefixFilterRule("abc"), - ), - ], - ) - client.set_bucket_notification("my-bucket", config) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, NotificationConfig): - raise ValueError("config must be NotificationConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"notification": ""}, - ) - - def delete_bucket_notification(self, bucket_name: str): - """ - Delete notification configuration of a bucket. On success, S3 service - stops notification of events previously set of the bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_notification("my-bucket") - """ - self.set_bucket_notification(bucket_name, NotificationConfig()) - - def set_bucket_encryption(self, bucket_name: str, config: SSEConfig): - """ - Set encryption configuration of a bucket. - - :param bucket_name: Name of the bucket. - :param config: :class:`SSEConfig ` object. - - Example:: - client.set_bucket_encryption( - "my-bucket", SSEConfig(Rule.new_sse_s3_rule()), - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, SSEConfig): - raise ValueError("config must be SSEConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"encryption": ""}, - ) - - def get_bucket_encryption(self, bucket_name: str) -> Optional[SSEConfig]: - """ - Get encryption configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`SSEConfig ` object. - - Example:: - config = client.get_bucket_encryption("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - response = self._execute( - "GET", - bucket_name, - query_params={"encryption": ""}, - ) - return unmarshal(SSEConfig, response.data.decode()) - except S3Error as exc: - if exc.code != "ServerSideEncryptionConfigurationNotFoundError": - raise - return None - - def delete_bucket_encryption(self, bucket_name: str): - """ - Delete encryption configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_encryption("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - self._execute( - "DELETE", - bucket_name, - query_params={"encryption": ""}, - ) - except S3Error as exc: - if exc.code != "ServerSideEncryptionConfigurationNotFoundError": - raise - - def listen_bucket_notification( - self, - bucket_name: str, - prefix: str = "", - suffix: str = "", - events: tuple[str, ...] = ('s3:ObjectCreated:*', - 's3:ObjectRemoved:*', - 's3:ObjectAccessed:*'), - ) -> EventIterable: - """ - Listen events of object prefix and suffix of a bucket. Caller should - iterate returned iterator to read new events. - - :param bucket_name: Name of the bucket. - :param prefix: Listen events of object starts with prefix. - :param suffix: Listen events of object ends with suffix. - :param events: Events to listen. - :return: Iterator of event records as :dict:. - - Example:: - with client.listen_bucket_notification( - "my-bucket", - prefix="my-prefix/", - events=["s3:ObjectCreated:*", "s3:ObjectRemoved:*"], - ) as events: - for event in events: - print(event) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if self._base_url.is_aws_host: - raise ValueError( - "ListenBucketNotification API is not supported in Amazon S3", - ) - - return EventIterable( - lambda: self._execute( - "GET", - bucket_name, - query_params={ - "prefix": prefix or "", - "suffix": suffix or "", - "events": cast(Tuple[str], events), - }, - preload_content=False, - ), - ) - - def set_bucket_versioning( - self, - bucket_name: str, - config: VersioningConfig, - ): - """ - Set versioning configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param config: :class:`VersioningConfig `. - - Example:: - client.set_bucket_versioning( - "my-bucket", VersioningConfig(ENABLED), - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, VersioningConfig): - raise ValueError("config must be VersioningConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"versioning": ""}, - ) - - def get_bucket_versioning(self, bucket_name: str) -> VersioningConfig: - """ - Get versioning configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`VersioningConfig `. - - Example:: - config = client.get_bucket_versioning("my-bucket") - print(config.status) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - response = self._execute( - "GET", - bucket_name, - query_params={"versioning": ""}, - ) - return unmarshal(VersioningConfig, response.data.decode()) - - def fput_object( - self, - bucket_name: str, - object_name: str, - file_path: str, - content_type: str = "application/octet-stream", - metadata: Optional[DictType] = None, - sse: Optional[Sse] = None, - progress: Optional[ProgressType] = None, - part_size: int = 0, - num_parallel_uploads: int = 3, - tags: Optional[Tags] = None, - retention: Optional[Retention] = None, - legal_hold: bool = False, - ) -> ObjectWriteResult: - """ - Uploads data from a file to an object in a bucket. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param file_path: Name of file to upload. - :param content_type: Content type of the object. - :param metadata: Any additional metadata to be uploaded along - with your PUT request. - :param sse: Server-side encryption. - :param progress: A progress object - :param part_size: Multipart part size - :param num_parallel_uploads: Number of parallel uploads. - :param tags: :class:`Tags` for the object. - :param retention: :class:`Retention` configuration object. - :param legal_hold: Flag to set legal hold for the object. - :return: :class:`ObjectWriteResult` object. - - Example:: - # Upload data. - result = client.fput_object( - "my-bucket", "my-object", "my-filename", - ) - - # Upload data with metadata. - result = client.fput_object( - "my-bucket", "my-object", "my-filename", - metadata={"My-Project": "one"}, - ) - - # Upload data with tags, retention and legal-hold. - date = datetime.utcnow().replace( - hour=0, minute=0, second=0, microsecond=0, - ) + timedelta(days=30) - tags = Tags(for_object=True) - tags["User"] = "jsmith" - result = client.fput_object( - "my-bucket", "my-object", "my-filename", - tags=tags, - retention=Retention(GOVERNANCE, date), - legal_hold=True, - ) - """ - - file_size = os.stat(file_path).st_size - with open(file_path, "rb") as file_data: - return self.put_object( - bucket_name, - object_name, - file_data, - file_size, - content_type=content_type, - metadata=cast(Union[DictType, None], metadata), - sse=sse, - progress=progress, - part_size=part_size, - num_parallel_uploads=num_parallel_uploads, - tags=tags, - retention=retention, - legal_hold=legal_hold, - ) - - def fget_object( - self, - bucket_name: str, - object_name: str, - file_path: str, - request_headers: Optional[DictType] = None, - ssec: Optional[SseCustomerKey] = None, - version_id: Optional[str] = None, - extra_query_params: Optional[DictType] = None, - tmp_file_path: Optional[str] = None, - progress: Optional[ProgressType] = None, - ): - """ - Downloads data of an object to file. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param file_path: Name of file to download. - :param request_headers: Any additional headers to be added with GET - request. - :param ssec: Server-side encryption customer key. - :param version_id: Version-ID of the object. - :param extra_query_params: Extra query parameters for advanced usage. - :param tmp_file_path: Path to a temporary file. - :param progress: A progress object - :return: Object information. - - Example:: - # Download data of an object. - client.fget_object("my-bucket", "my-object", "my-filename") - - # Download data of an object of version-ID. - client.fget_object( - "my-bucket", "my-object", "my-filename", - version_id="dfbd25b3-abec-4184-a4e8-5a35a5c1174d", - ) - - # Download data of an SSE-C encrypted object. - client.fget_object( - "my-bucket", "my-object", "my-filename", - ssec=SseCustomerKey(b"32byteslongsecretkeymustprovided"), - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - - if os.path.isdir(file_path): - raise ValueError(f"file {file_path} is a directory") - - # Create top level directory if needed. - makedirs(os.path.dirname(file_path)) - - stat = self.stat_object( - bucket_name, - object_name, - ssec, - version_id=version_id, - extra_headers=request_headers, - ) - - etag = queryencode(cast(str, stat.etag)) - # Write to a temporary file "file_path.part.minio" before saving. - tmp_file_path = ( - tmp_file_path or f"{file_path}.{etag}.part.minio" - ) - - response = None - try: - response = self.get_object( - bucket_name, - object_name, - request_headers=request_headers, - ssec=ssec, - version_id=version_id, - extra_query_params=extra_query_params, - ) - - if progress: - # Set progress bar length and object name before upload - length = int(response.headers.get('content-length', 0)) - progress.set_meta(object_name=object_name, total_length=length) - - with open(tmp_file_path, "wb") as tmp_file: - for data in response.stream(amt=1024 * 1024): - size = tmp_file.write(data) - if progress: - progress.update(size) - if os.path.exists(file_path): - os.remove(file_path) # For windows compatibility. - os.rename(tmp_file_path, file_path) - return stat - finally: - if response: - response.close() - response.release_conn() - - def get_object( - self, - bucket_name: str, - object_name: str, - offset: int = 0, - length: int = 0, - request_headers: Optional[DictType] = None, - ssec: Optional[SseCustomerKey] = None, - version_id: Optional[str] = None, - extra_query_params: Optional[DictType] = None, - ) -> BaseHTTPResponse: - """ - Get data of an object. Returned response should be closed after use to - release network resources. To reuse the connection, it's required to - call `response.release_conn()` explicitly. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param offset: Start byte position of object data. - :param length: Number of bytes of object data from offset. - :param request_headers: Any additional headers to be added with GET - request. - :param ssec: Server-side encryption customer key. - :param version_id: Version-ID of the object. - :param extra_query_params: Extra query parameters for advanced usage. - :return: :class:`urllib3.response.BaseHTTPResponse` object. - - Example:: - # Get data of an object. - response = None - try: - response = client.get_object("my-bucket", "my-object") - # Read data from response. - finally: - if response: - response.close() - response.release_conn() - - # Get data of an object of version-ID. - response = None - try: - response = client.get_object( - "my-bucket", "my-object", - version_id="dfbd25b3-abec-4184-a4e8-5a35a5c1174d", - ) - # Read data from response. - finally: - if response: - response.close() - response.release_conn() - - # Get data of an object from offset and length. - response = None - try: - response = client.get_object( - "my-bucket", "my-object", offset=512, length=1024, - ) - # Read data from response. - finally: - if response: - response.close() - response.release_conn() - - # Get data of an SSE-C encrypted object. - response = None - try: - response = client.get_object( - "my-bucket", "my-object", - ssec=SseCustomerKey(b"32byteslongsecretkeymustprovided"), - ) - # Read data from response. - finally: - if response: - response.close() - response.release_conn() - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - check_ssec(ssec) - - headers = cast(DictType, ssec.headers() if ssec else {}) - headers.update(request_headers or {}) - - if offset or length: - end = (offset + length - 1) if length else "" - headers['Range'] = f"bytes={offset}-{end}" - - if version_id: - extra_query_params = extra_query_params or {} - extra_query_params["versionId"] = version_id - - return self._execute( - "GET", - bucket_name, - object_name, - headers=cast(DictType, headers), - query_params=extra_query_params, - preload_content=False, - ) - - def prompt_object( - self, - bucket_name: str, - object_name: str, - prompt: str, - lambda_arn: Optional[str] = None, - request_headers: Optional[DictType] = None, - ssec: Optional[SseCustomerKey] = None, - version_id: Optional[str] = None, - **kwargs: Optional[Any], - ) -> BaseHTTPResponse: - """ - Prompt an object using natural language. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param prompt: Prompt the Object to interact with the AI model. - request. - :param lambda_arn: Lambda ARN to use for prompt. - :param request_headers: Any additional headers to be added with POST - :param ssec: Server-side encryption customer key. - :param version_id: Version-ID of the object. - :param kwargs: Extra parameters for advanced usage. - :return: :class:`urllib3.response.BaseHTTPResponse` object. - - Example:: - # prompt an object. - response = None - try: - response = client.get_object( - "my-bucket", "my-object", - "Describe the object for me") - # Read data from response. - finally: - if response: - response.close() - response.release_conn() - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - check_ssec(ssec) - - headers = cast(DictType, ssec.headers() if ssec else {}) - headers.update(request_headers or {}) - - extra_query_params = {"lambdaArn": lambda_arn or ""} - - if version_id: - extra_query_params["versionId"] = version_id - - prompt_body = kwargs - prompt_body["prompt"] = prompt - - body = json.dumps(prompt_body) - return self._execute( - "POST", - bucket_name, - object_name, - headers=cast(DictType, headers), - query_params=cast(DictType, extra_query_params), - body=body.encode(), - preload_content=False, - ) - - def copy_object( - self, - bucket_name: str, - object_name: str, - source: CopySource, - sse: Optional[Sse] = None, - metadata: Optional[DictType] = None, - tags: Optional[Tags] = None, - retention: Optional[Retention] = None, - legal_hold: bool = False, - metadata_directive: Optional[str] = None, - tagging_directive: Optional[str] = None, - ) -> ObjectWriteResult: - """ - Create an object by server-side copying data from another object. - In this API maximum supported source object size is 5GiB. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param source: :class:`CopySource` object. - :param sse: Server-side encryption of destination object. - :param metadata: Any user-defined metadata to be copied along with - destination object. - :param tags: Tags for destination object. - :param retention: :class:`Retention` configuration object. - :param legal_hold: Flag to set legal hold for destination object. - :param metadata_directive: Directive used to handle user metadata for - destination object. - :param tagging_directive: Directive used to handle tags for destination - object. - :return: :class:`ObjectWriteResult ` object. - - Example:: - # copy an object from a bucket to another. - result = client.copy_object( - "my-bucket", - "my-object", - CopySource("my-sourcebucket", "my-sourceobject"), - ) - print(result.object_name, result.version_id) - - # copy an object with condition. - result = client.copy_object( - "my-bucket", - "my-object", - CopySource( - "my-sourcebucket", - "my-sourceobject", - modified_since=datetime(2014, 4, 1, tzinfo=timezone.utc), - ), - ) - print(result.object_name, result.version_id) - - # copy an object from a bucket with replacing metadata. - metadata = {"test_meta_key": "test_meta_value"} - result = client.copy_object( - "my-bucket", - "my-object", - CopySource("my-sourcebucket", "my-sourceobject"), - metadata=metadata, - metadata_directive=REPLACE, - ) - print(result.object_name, result.version_id) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if not isinstance(source, CopySource): - raise ValueError("source must be CopySource type") - check_sse(sse) - if tags is not None and not isinstance(tags, Tags): - raise ValueError("tags must be Tags type") - if retention is not None and not isinstance(retention, Retention): - raise ValueError("retention must be Retention type") - if ( - metadata_directive is not None and - metadata_directive not in [COPY, REPLACE] - ): - raise ValueError(f"metadata directive must be {COPY} or {REPLACE}") - if ( - tagging_directive is not None and - tagging_directive not in [COPY, REPLACE] - ): - raise ValueError(f"tagging directive must be {COPY} or {REPLACE}") - - size = -1 - if source.offset is None and source.length is None: - stat = self.stat_object( - source.bucket_name, - source.object_name, - version_id=source.version_id, - ssec=source.ssec, - ) - size = cast(int, stat.size) - - if ( - source.offset is not None or - source.length is not None or - size > MAX_PART_SIZE - ): - if metadata_directive == COPY: - raise ValueError( - "COPY metadata directive is not applicable to source " - "object size greater than 5 GiB", - ) - if tagging_directive == COPY: - raise ValueError( - "COPY tagging directive is not applicable to source " - "object size greater than 5 GiB" - ) - return self.compose_object( - bucket_name, object_name, [ComposeSource.of(source)], - sse=sse, metadata=metadata, tags=tags, retention=retention, - legal_hold=legal_hold, - ) - - headers = genheaders( - metadata, - sse, - tags, - retention, - legal_hold, - ) - if metadata_directive: - headers["x-amz-metadata-directive"] = metadata_directive - if tagging_directive: - headers["x-amz-tagging-directive"] = tagging_directive - headers.update(source.gen_copy_headers()) - response = self._execute( - "PUT", - bucket_name, - object_name=object_name, - headers=headers, - ) - etag, last_modified = parse_copy_object(response) - return ObjectWriteResult( - bucket_name, - object_name, - response.headers.get("x-amz-version-id"), - etag, - response.headers, - last_modified=last_modified, - ) - - def _calc_part_count(self, sources: list[ComposeSource]) -> int: - """Calculate part count.""" - object_size = 0 - part_count = 0 - i = 0 - for src in sources: - i += 1 - stat = self.stat_object( - src.bucket_name, - src.object_name, - version_id=src.version_id, - ssec=src.ssec, - ) - src.build_headers(cast(int, stat.size), cast(str, stat.etag)) - size = cast(int, stat.size) - if src.length is not None: - size = src.length - elif src.offset is not None: - size -= src.offset - - if ( - size < MIN_PART_SIZE and - len(sources) != 1 and - i != len(sources) - ): - raise ValueError( - f"source {src.bucket_name}/{src.object_name}: size {size} " - f"must be greater than {MIN_PART_SIZE}" - ) - - object_size += size - if object_size > MAX_MULTIPART_OBJECT_SIZE: - raise ValueError( - f"destination object size must be less than " - f"{MAX_MULTIPART_OBJECT_SIZE}" - ) - - if size > MAX_PART_SIZE: - count = int(size / MAX_PART_SIZE) - last_part_size = size - (count * MAX_PART_SIZE) - if last_part_size > 0: - count += 1 - else: - last_part_size = MAX_PART_SIZE - if ( - last_part_size < MIN_PART_SIZE and - len(sources) != 1 and - i != len(sources) - ): - raise ValueError( - f"source {src.bucket_name}/{src.object_name}: " - f"for multipart split upload of {size}, " - f"last part size is less than {MIN_PART_SIZE}" - ) - part_count += count - else: - part_count += 1 - - if part_count > MAX_MULTIPART_COUNT: - raise ValueError( - f"Compose sources create more than allowed multipart " - f"count {MAX_MULTIPART_COUNT}" - ) - return part_count - - def _upload_part_copy( - self, - bucket_name: str, - object_name: str, - upload_id: str, - part_number: int, - headers: DictType, - ) -> tuple[str, Optional[datetime]]: - """Execute UploadPartCopy S3 API.""" - response = self._execute( - "PUT", - bucket_name, - object_name, - headers=headers, - query_params={ - "partNumber": str(part_number), - "uploadId": upload_id, - }, - ) - return parse_copy_object(response) - - def compose_object( - self, - bucket_name: str, - object_name: str, - sources: list[ComposeSource], - sse: Optional[Sse] = None, - metadata: Optional[DictType] = None, - tags: Optional[Tags] = None, - retention: Optional[Retention] = None, - legal_hold: bool = False, - ) -> ObjectWriteResult: - """ - Create an object by combining data from different source objects using - server-side copy. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param sources: List of :class:`ComposeSource` object. - :param sse: Server-side encryption of destination object. - :param metadata: Any user-defined metadata to be copied along with - destination object. - :param tags: Tags for destination object. - :param retention: :class:`Retention` configuration object. - :param legal_hold: Flag to set legal hold for destination object. - :return: :class:`ObjectWriteResult ` object. - - Example:: - sources = [ - ComposeSource("my-job-bucket", "my-object-part-one"), - ComposeSource("my-job-bucket", "my-object-part-two"), - ComposeSource("my-job-bucket", "my-object-part-three"), - ] - - # Create my-bucket/my-object by combining source object - # list. - result = client.compose_object("my-bucket", "my-object", sources) - print(result.object_name, result.version_id) - - # Create my-bucket/my-object with user metadata by combining - # source object list. - result = client.compose_object( - "my-bucket", - "my-object", - sources, - metadata={"test_meta_key": "test_meta_value"}, - ) - print(result.object_name, result.version_id) - - # Create my-bucket/my-object with user metadata and - # server-side encryption by combining source object list. - client.compose_object( - "my-bucket", "my-object", sources, sse=SseS3(), - ) - print(result.object_name, result.version_id) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if not isinstance(sources, (list, tuple)) or not sources: - raise ValueError("sources must be non-empty list or tuple type") - i = 0 - for src in sources: - if not isinstance(src, ComposeSource): - raise ValueError(f"sources[{i}] must be ComposeSource type") - i += 1 - check_sse(sse) - if tags is not None and not isinstance(tags, Tags): - raise ValueError("tags must be Tags type") - if retention is not None and not isinstance(retention, Retention): - raise ValueError("retention must be Retention type") - - part_count = self._calc_part_count(sources) - if ( - part_count == 1 and - sources[0].offset is None and - sources[0].length is None - ): - return self.copy_object( - bucket_name, object_name, CopySource.of(sources[0]), - sse=sse, metadata=metadata, tags=tags, retention=retention, - legal_hold=legal_hold, - metadata_directive=REPLACE if metadata else None, - tagging_directive=REPLACE if tags else None, - ) - - headers = genheaders(metadata, sse, tags, retention, legal_hold) - upload_id = self._create_multipart_upload( - bucket_name, object_name, headers, - ) - ssec_headers = sse.headers() if isinstance(sse, SseCustomerKey) else {} - try: - part_number = 0 - total_parts = [] - for src in sources: - size = cast(int, src.object_size) - if src.length is not None: - size = src.length - elif src.offset is not None: - size -= src.offset - offset = src.offset or 0 - headers = cast(DictType, src.headers) - headers.update(ssec_headers) - if size <= MAX_PART_SIZE: - part_number += 1 - if src.length is not None: - headers["x-amz-copy-source-range"] = ( - f"bytes={offset}-{offset + src.length - 1}" - ) - elif src.offset is not None: - headers["x-amz-copy-source-range"] = ( - f"bytes={offset}-{offset + size - 1}" - ) - etag, _ = self._upload_part_copy( - bucket_name, - object_name, - upload_id, - part_number, - headers, - ) - total_parts.append(Part(part_number, etag)) - continue - while size > 0: - part_number += 1 - length = size if size < MAX_PART_SIZE else MAX_PART_SIZE - end_bytes = offset + length - 1 - headers_copy = headers.copy() - headers_copy["x-amz-copy-source-range"] = ( - f"bytes={offset}-{end_bytes}" - ) - etag, _ = self._upload_part_copy( - bucket_name, - object_name, - upload_id, - part_number, - headers_copy, - ) - total_parts.append(Part(part_number, etag)) - offset += length - size -= length - result = self._complete_multipart_upload( - bucket_name, object_name, upload_id, total_parts, - sse if isinstance(sse, SseCustomerKey) else None, - ) - return ObjectWriteResult( - cast(str, result.bucket_name), - cast(str, result.object_name), - result.version_id, - result.etag, - result.http_headers, - location=result.location, - ) - except Exception as exc: - if upload_id: - self._abort_multipart_upload( - bucket_name, object_name, upload_id, - ) - raise exc - - def _abort_multipart_upload( - self, - bucket_name: str, - object_name: str, - upload_id: str, - ): - """Execute AbortMultipartUpload S3 API.""" - self._execute( - "DELETE", - bucket_name, - object_name, - query_params={'uploadId': upload_id}, - ) - - def _complete_multipart_upload( - self, - bucket_name: str, - object_name: str, - upload_id: str, - parts: list[Part], - ssec: Optional[SseCustomerKey] = None, - ) -> CompleteMultipartUploadResult: - """Execute CompleteMultipartUpload S3 API.""" - element = Element("CompleteMultipartUpload") - for part in parts: - tag = SubElement(element, "Part") - SubElement(tag, "PartNumber", str(part.part_number)) - SubElement(tag, "ETag", '"' + part.etag + '"') - body = getbytes(element) - headers: DictType = { - "Content-Type": 'application/xml', - "Content-MD5": cast(str, md5sum_hash(body)), - } - if ssec: - headers.update(ssec.headers()) - response = self._execute( - "POST", - bucket_name, - object_name, - body=body, - headers=headers, - query_params={'uploadId': upload_id}, - ) - return CompleteMultipartUploadResult(response) - - def _create_multipart_upload( - self, - bucket_name: str, - object_name: str, - headers: DictType, - ) -> str: - """Execute CreateMultipartUpload S3 API.""" - if not headers.get("Content-Type"): - headers["Content-Type"] = "application/octet-stream" - response = self._execute( - "POST", - bucket_name, - object_name, - headers=headers, - query_params={"uploads": ""}, - ) - element = ET.fromstring(response.data.decode()) - return cast(str, findtext(element, "UploadId", True)) - - def _put_object( - self, - bucket_name: str, - object_name: str, - data: bytes, - headers: Optional[DictType] = None, - query_params: Optional[DictType] = None, - ) -> ObjectWriteResult: - """Execute PutObject S3 API.""" - response = self._execute( - "PUT", - bucket_name, - object_name, - body=data, - headers=headers, - query_params=query_params, - no_body_trace=True, - ) - return ObjectWriteResult( - bucket_name, - object_name, - response.headers.get("x-amz-version-id"), - response.headers.get("etag", "").replace('"', ""), - response.headers, - ) - - def _upload_part( - self, - bucket_name: str, - object_name: str, - data: bytes, - headers: Optional[DictType], - upload_id: str, - part_number: int, - ) -> str: - """Execute UploadPart S3 API.""" - result = self._put_object( - bucket_name, - object_name, - data, - headers, - query_params={ - "partNumber": str(part_number), - "uploadId": upload_id, - }, - ) - return cast(str, result.etag) - - def _upload_part_task(self, args): - """Upload_part task for ThreadPool.""" - return args[5], self._upload_part(*args) - - def put_object( - self, - bucket_name: str, - object_name: str, - data: BinaryIO, - length: int, - content_type: str = "application/octet-stream", - metadata: Optional[DictType] = None, - sse: Optional[Sse] = None, - progress: Optional[ProgressType] = None, - part_size: int = 0, - num_parallel_uploads: int = 3, - tags: Optional[Tags] = None, - retention: Optional[Retention] = None, - legal_hold: bool = False, - write_offset: Optional[int] = None, - ) -> ObjectWriteResult: - """ - Uploads data from a stream to an object in a bucket. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param data: An object having callable read() returning bytes object. - :param length: Data size; -1 for unknown size and set valid part_size. - :param content_type: Content type of the object. - :param metadata: Any additional metadata to be uploaded along - with your PUT request. - :param sse: Server-side encryption. - :param progress: A progress object; - :param part_size: Multipart part size. - :param num_parallel_uploads: Number of parallel uploads. - :param tags: :class:`Tags` for the object. - :param retention: :class:`Retention` configuration object. - :param legal_hold: Flag to set legal hold for the object. - :param write_offset: Offset byte for appending data to existing object. - :return: :class:`ObjectWriteResult` object. - - Example:: - # Upload data. - result = client.put_object( - "my-bucket", "my-object", io.BytesIO(b"hello"), 5, - ) - - # Upload data with metadata. - result = client.put_object( - "my-bucket", "my-object", io.BytesIO(b"hello"), 5, - metadata={"My-Project": "one"}, - ) - - # Upload data with tags, retention and legal-hold. - date = datetime.utcnow().replace( - hour=0, minute=0, second=0, microsecond=0, - ) + timedelta(days=30) - tags = Tags(for_object=True) - tags["User"] = "jsmith" - result = client.put_object( - "my-bucket", "my-object", io.BytesIO(b"hello"), 5, - tags=tags, - retention=Retention(GOVERNANCE, date), - legal_hold=True, - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - check_sse(sse) - if tags is not None and not isinstance(tags, Tags): - raise ValueError("tags must be Tags type") - if retention is not None and not isinstance(retention, Retention): - raise ValueError("retention must be Retention type") - if not callable(getattr(data, "read")): - raise ValueError("input data must have callable read()") - if write_offset is not None: - if write_offset < 0: - raise ValueError("write offset should not be negative") - if length < 0: - raise ValueError("length must be provided for write offset") - part_size = length if length > MIN_PART_SIZE else MIN_PART_SIZE - part_size, part_count = get_part_info(length, part_size) - if progress: - # Set progress bar length and object name before upload - progress.set_meta(object_name=object_name, total_length=length) - - headers = genheaders(metadata, sse, tags, retention, legal_hold) - headers["Content-Type"] = content_type or "application/octet-stream" - if write_offset: - headers["x-amz-write-offset-bytes"] = str(write_offset) - - object_size = length - uploaded_size = 0 - part_number = 0 - one_byte = b"" - stop = False - upload_id = None - parts: list[Part] = [] - pool: Optional[ThreadPool] = None - - try: - while not stop: - part_number += 1 - if part_count > 0: - if part_number == part_count: - part_size = object_size - uploaded_size - stop = True - part_data = read_part_data( - data, part_size, progress=progress, - ) - if len(part_data) != part_size: - raise IOError( - f"stream having not enough data;" - f"expected: {part_size}, " - f"got: {len(part_data)} bytes" - ) - else: - part_data = read_part_data( - data, part_size + 1, one_byte, progress=progress, - ) - # If part_data_size is less or equal to part_size, - # then we have reached last part. - if len(part_data) <= part_size: - part_count = part_number - stop = True - else: - one_byte = part_data[-1:] - part_data = part_data[:-1] - - uploaded_size += len(part_data) - - if part_count == 1: - return self._put_object( - bucket_name, object_name, part_data, headers, - ) - - if not upload_id: - upload_id = self._create_multipart_upload( - bucket_name, object_name, headers, - ) - if num_parallel_uploads and num_parallel_uploads > 1: - pool = ThreadPool(num_parallel_uploads) - pool.start_parallel() - - args = ( - bucket_name, - object_name, - part_data, - ( - cast(DictType, sse.headers()) - if isinstance(sse, SseCustomerKey) else None - ), - upload_id, - part_number, - ) - if num_parallel_uploads > 1: - cast(ThreadPool, pool).add_task( - self._upload_part_task, args, - ) - else: - etag = self._upload_part(*args) - parts.append(Part(part_number, etag)) - - if pool: - result = pool.result() - parts = [Part(0, "")] * part_count - while not result.empty(): - part_number, etag = result.get() - parts[part_number - 1] = Part(part_number, etag) - - upload_result = self._complete_multipart_upload( - bucket_name, object_name, cast(str, upload_id), parts, - sse if isinstance(sse, SseCustomerKey) else None, - ) - return ObjectWriteResult( - cast(str, upload_result.bucket_name), - cast(str, upload_result.object_name), - upload_result.version_id, - upload_result.etag, - upload_result.http_headers, - location=upload_result.location, - ) - except Exception as exc: - if upload_id: - self._abort_multipart_upload( - bucket_name, object_name, upload_id, - ) - raise exc - - def append_object( - self, - bucket_name: str, - object_name: str, - data: BinaryIO, - length: int, - chunk_size: Optional[int] = None, - progress: Optional[ProgressType] = None, - extra_headers: Optional[DictType] = None, - ) -> ObjectWriteResult: - """ - Appends from a stream to existing object in a bucket. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param data: An object having callable read() returning bytes object. - :param length: Data size; -1 for unknown size. - :param chunk_size: Chunk size to optimize uploads. - :return: :class:`ObjectWriteResult` object. - - Example:: - # Append data. - result = client.append_object( - "my-bucket", "my-object", io.BytesIO(b"world"), 5, - ) - print(f"appended {result.object_name} object; etag: {result.etag}") - - # Append data in chunks. - data = urlopen( - "https://www.kernel.org/pub/linux/kernel/v6.x/" - "linux-6.13.12.tar.xz", - ) - result = client.append_object( - "my-bucket", "my-object", data, 148611164, 5*1024*1024, - ) - print(f"appended {result.object_name} object; etag: {result.etag}") - - # Append unknown sized data. - data = urlopen( - "https://www.kernel.org/pub/linux/kernel/v6.x/" - "linux-6.14.3.tar.xz", - ) - result = client.append_object( - "my-bucket", "my-object", data, 149426584, 5*1024*1024, - ) - print(f"appended {result.object_name} object; etag: {result.etag}") - """ - if length == 0: - raise ValueError("length should not be zero") - if chunk_size is not None: - if chunk_size < MIN_PART_SIZE: - raise ValueError("chunk size must be minimum of 5 MiB") - if chunk_size > MAX_PART_SIZE: - raise ValueError("chunk size must be less than 5 GiB") - else: - chunk_size = length if length > MIN_PART_SIZE else MIN_PART_SIZE - - chunk_count = -1 - if length > 0: - chunk_count = int(length / chunk_size) - if (chunk_count * chunk_size) < length: - chunk_count += 1 - chunk_count = chunk_count or 1 - - object_size = length - uploaded_size = 0 - chunk_number = 0 - one_byte = b"" - stop = False - - stat = self.stat_object(bucket_name, object_name) - write_offset = cast(int, stat.size) - - while not stop: - chunk_number += 1 - if chunk_count > 0: - if chunk_number == chunk_count: - chunk_size = object_size - uploaded_size - stop = True - chunk_data = read_part_data( - data, chunk_size, progress=progress, - ) - if len(chunk_data) != chunk_size: - raise IOError( - f"stream having not enough data;" - f"expected: {chunk_size}, " - f"got: {len(chunk_data)} bytes" - ) - else: - chunk_data = read_part_data( - data, chunk_size + 1, one_byte, progress=progress, - ) - # If chunk_data_size is less or equal to chunk_size, - # then we have reached last chunk. - if len(chunk_data) <= chunk_size: - chunk_count = chunk_number - stop = True - else: - one_byte = chunk_data[-1:] - chunk_data = chunk_data[:-1] - - uploaded_size += len(chunk_data) - - headers = extra_headers or {} - headers["x-amz-write-offset-bytes"] = str(write_offset) - upload_result = self._put_object( - bucket_name, object_name, chunk_data, headers=headers, - ) - write_offset += len(chunk_data) - return ObjectWriteResult( - cast(str, upload_result.bucket_name), - cast(str, upload_result.object_name), - upload_result.version_id, - upload_result.etag, - upload_result.http_headers, - location=upload_result.location, - ) - - def list_objects( - self, - bucket_name: str, - prefix: Optional[str] = None, - recursive: bool = False, - start_after: Optional[str] = None, - include_user_meta: bool = False, - include_version: bool = False, - use_api_v1: bool = False, - use_url_encoding_type: bool = True, - fetch_owner: bool = False, - extra_headers: Optional[DictType] = None, - extra_query_params: Optional[DictType] = None, - ): - """ - Lists object information of a bucket. - - :param bucket_name: Name of the bucket. - :param prefix: Object name starts with prefix. - :param recursive: List recursively than directory structure emulation. - :param start_after: List objects after this key name. - :param include_user_meta: MinIO specific flag to control to include - user metadata. - :param include_version: Flag to control whether include object - versions. - :param use_api_v1: Flag to control to use ListObjectV1 S3 API or not. - :param use_url_encoding_type: Flag to control whether URL encoding type - to be used or not. - :param extra_headers: Extra HTTP headers for advanced usage. - :param extra_query_params: Extra query parameters for advanced usage. - :return: Iterator of :class:`Object `. - - Example:: - # List objects information. - objects = client.list_objects("my-bucket") - for obj in objects: - print(obj) - - # List objects information whose names starts with "my/prefix/". - objects = client.list_objects("my-bucket", prefix="my/prefix/") - for obj in objects: - print(obj) - - # List objects information recursively. - objects = client.list_objects("my-bucket", recursive=True) - for obj in objects: - print(obj) - - # List objects information recursively whose names starts with - # "my/prefix/". - objects = client.list_objects( - "my-bucket", prefix="my/prefix/", recursive=True, - ) - for obj in objects: - print(obj) - - # List objects information recursively after object name - # "my/prefix/world/1". - objects = client.list_objects( - "my-bucket", recursive=True, start_after="my/prefix/world/1", - ) - for obj in objects: - print(obj) - """ - return self._list_objects( - bucket_name, - delimiter=None if recursive else "/", - include_user_meta=include_user_meta, - prefix=prefix, - start_after=start_after, - use_api_v1=use_api_v1, - include_version=include_version, - encoding_type="url" if use_url_encoding_type else None, - fetch_owner=fetch_owner, - extra_headers=extra_headers, - extra_query_params=extra_query_params, - ) - - def stat_object( - self, - bucket_name: str, - object_name: str, - ssec: Optional[SseCustomerKey] = None, - version_id: Optional[str] = None, - extra_headers: Optional[DictType] = None, - extra_query_params: Optional[DictType] = None, - ) -> Object: - """ - Get object information and metadata of an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param ssec: Server-side encryption customer key. - :param version_id: Version ID of the object. - :param extra_headers: Extra HTTP headers for advanced usage. - :param extra_query_params: Extra query parameters for advanced usage. - :return: :class:`Object `. - - Example:: - # Get object information. - result = client.stat_object("my-bucket", "my-object") - - # Get object information of version-ID. - result = client.stat_object( - "my-bucket", "my-object", - version_id="dfbd25b3-abec-4184-a4e8-5a35a5c1174d", - ) - - # Get SSE-C encrypted object information. - result = client.stat_object( - "my-bucket", "my-object", - ssec=SseCustomerKey(b"32byteslongsecretkeymustprovided"), - ) - """ - - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - check_ssec(ssec) - - headers = cast(DictType, ssec.headers() if ssec else {}) - if extra_headers: - headers.update(extra_headers) - - query_params = extra_query_params or {} - query_params.update({"versionId": version_id} if version_id else {}) - response = self._execute( - "HEAD", - bucket_name, - object_name, - headers=headers, - query_params=query_params, - ) - - value = response.headers.get("last-modified") - if value is not None: - last_modified = time.from_http_header(value) - else: - last_modified = None - - return Object( - bucket_name, - object_name, - last_modified=last_modified, - etag=response.headers.get("etag", "").replace('"', ""), - size=int(response.headers.get("content-length", "0")), - content_type=response.headers.get("content-type"), - metadata=response.headers, - version_id=response.headers.get("x-amz-version-id"), - ) - - def remove_object( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None - ): - """ - Remove an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - - Example:: - # Remove object. - client.remove_object("my-bucket", "my-object") - - # Remove version of an object. - client.remove_object( - "my-bucket", "my-object", - version_id="dfbd25b3-abec-4184-a4e8-5a35a5c1174d", - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - self._execute( - "DELETE", - bucket_name, - object_name, - query_params={"versionId": version_id} if version_id else None, - ) - - def _delete_objects( - self, - bucket_name: str, - delete_object_list: list[DeleteObject], - quiet: bool = False, - bypass_governance_mode: bool = False, - ) -> DeleteResult: - """ - Delete multiple objects. - - :param bucket_name: Name of the bucket. - :param delete_object_list: List of maximum 1000 - :class:`DeleteObject ` object. - :param quiet: quiet flag. - :param bypass_governance_mode: Bypass Governance retention mode. - :return: :class:`DeleteResult ` object. - """ - body = marshal(DeleteRequest(delete_object_list, quiet=quiet)) - headers: DictType = { - "Content-MD5": cast(str, md5sum_hash(body)), - } - if bypass_governance_mode: - headers["x-amz-bypass-governance-retention"] = "true" - response = self._execute( - "POST", - bucket_name, - body=body, - headers=headers, - query_params={"delete": ""}, - ) - - element = ET.fromstring(response.data.decode()) - return ( - DeleteResult([], [DeleteError.fromxml(element)]) - if element.tag.endswith("Error") - else unmarshal(DeleteResult, response.data.decode()) - ) - - def remove_objects( - self, - bucket_name: str, - delete_object_list: Iterable[DeleteObject], - bypass_governance_mode: bool = False, - ) -> Iterator[DeleteError]: - """ - Remove multiple objects. - - :param bucket_name: Name of the bucket. - :param delete_object_list: An iterable containing - :class:`DeleteObject ` object. - :param bypass_governance_mode: Bypass Governance retention mode. - :return: An iterator containing :class:`DeleteError ` - object. - - Example:: - # Remove list of objects. - errors = client.remove_objects( - "my-bucket", - [ - DeleteObject("my-object1"), - DeleteObject("my-object2"), - DeleteObject( - "my-object3", "13f88b18-8dcd-4c83-88f2-8631fdb6250c", - ), - ], - ) - for error in errors: - print("error occurred when deleting object", error) - - # Remove a prefix recursively. - delete_object_list = list( - map( - lambda x: DeleteObject(x.object_name), - client.list_objects( - "my-bucket", - "my/prefix/", - recursive=True, - ), - ) - ) - errors = client.remove_objects("my-bucket", delete_object_list) - for error in errors: - print("error occurred when deleting object", error) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - - # turn list like objects into an iterator. - delete_object_list = itertools.chain(delete_object_list) - - while True: - # get 1000 entries or whatever available. - objects = [ - delete_object for _, delete_object in zip( - range(1000), delete_object_list, - ) - ] - - if not objects: - break - - result = self._delete_objects( - bucket_name, - objects, - quiet=True, - bypass_governance_mode=bypass_governance_mode, - ) - - for error in result.error_list: - # AWS S3 returns "NoSuchVersion" error when - # version doesn't exist ignore this error - # yield all errors otherwise - if error.code != "NoSuchVersion": - yield error - - def get_presigned_url( - self, - method: str, - bucket_name: str, - object_name: str, - expires: timedelta = timedelta(days=7), - response_headers: Optional[DictType] = None, - request_date: Optional[datetime] = None, - version_id: Optional[str] = None, - extra_query_params: Optional[DictType] = None, - ) -> str: - """ - Get presigned URL of an object for HTTP method, expiry time and custom - request parameters. - - :param method: HTTP method. - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param expires: Expiry in seconds; defaults to 7 days. - :param response_headers: Optional response_headers argument to - specify response fields like date, size, - type of file, data about server, etc. - :param request_date: Optional request_date argument to - specify a different request date. Default is - current date. - :param version_id: Version ID of the object. - :param extra_query_params: Extra query parameters for advanced usage. - :return: URL string. - - Example:: - # Get presigned URL string to delete 'my-object' in - # 'my-bucket' with one day expiry. - url = client.get_presigned_url( - "DELETE", - "my-bucket", - "my-object", - expires=timedelta(days=1), - ) - print(url) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if expires.total_seconds() < 1 or expires.total_seconds() > 604800: - raise ValueError("expires must be between 1 second to 7 days") - - region = self._get_region(bucket_name) - query_params = extra_query_params or {} - query_params.update({"versionId": version_id} if version_id else {}) - query_params.update(response_headers or {}) - creds = self._provider.retrieve() if self._provider else None - if creds and creds.session_token: - query_params["X-Amz-Security-Token"] = creds.session_token - url = self._base_url.build( - method=method, - region=region, - bucket_name=bucket_name, - object_name=object_name, - query_params=query_params, - ) - - if creds: - url = presign_v4( - method=method, - url=url, - region=region, - credentials=creds, - date=request_date or time.utcnow(), - expires=int(expires.total_seconds()), - ) - return urlunsplit(url) - - def presigned_get_object( - self, - bucket_name: str, - object_name: str, - expires: timedelta = timedelta(days=7), - response_headers: Optional[DictType] = None, - request_date: Optional[datetime] = None, - version_id: Optional[str] = None, - extra_query_params: Optional[DictType] = None, - ) -> str: - """ - Get presigned URL of an object to download its data with expiry time - and custom request parameters. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param expires: Expiry in seconds; defaults to 7 days. - :param response_headers: Optional response_headers argument to - specify response fields like date, size, - type of file, data about server, etc. - :param request_date: Optional request_date argument to - specify a different request date. Default is - current date. - :param version_id: Version ID of the object. - :param extra_query_params: Extra query parameters for advanced usage. - :return: URL string. - - Example:: - # Get presigned URL string to download 'my-object' in - # 'my-bucket' with default expiry (i.e. 7 days). - url = client.presigned_get_object("my-bucket", "my-object") - print(url) - - # Get presigned URL string to download 'my-object' in - # 'my-bucket' with two hours expiry. - url = client.presigned_get_object( - "my-bucket", "my-object", expires=timedelta(hours=2), - ) - print(url) - """ - return self.get_presigned_url( - "GET", - bucket_name, - object_name, - expires, - response_headers=response_headers, - request_date=request_date, - version_id=version_id, - extra_query_params=extra_query_params, - ) - - def presigned_put_object( - self, - bucket_name: str, - object_name: str, - expires: timedelta = timedelta(days=7), - ) -> str: - """ - Get presigned URL of an object to upload data with expiry time and - custom request parameters. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param expires: Expiry in seconds; defaults to 7 days. - :return: URL string. - - Example:: - # Get presigned URL string to upload data to 'my-object' in - # 'my-bucket' with default expiry (i.e. 7 days). - url = client.presigned_put_object("my-bucket", "my-object") - print(url) - - # Get presigned URL string to upload data to 'my-object' in - # 'my-bucket' with two hours expiry. - url = client.presigned_put_object( - "my-bucket", "my-object", expires=timedelta(hours=2), - ) - print(url) - """ - return self.get_presigned_url( - "PUT", bucket_name, object_name, expires, - ) - - def presigned_post_policy(self, policy: PostPolicy) -> dict[str, str]: - """ - Get form-data of PostPolicy of an object to upload its data using POST - method. - - :param policy: :class:`PostPolicy `. - :return: :dict: contains form-data. - - Example:: - policy = PostPolicy( - "my-bucket", datetime.utcnow() + timedelta(days=10), - ) - policy.add_starts_with_condition("key", "my/object/prefix/") - policy.add_content_length_range_condition( - 1*1024*1024, 10*1024*1024, - ) - form_data = client.presigned_post_policy(policy) - """ - if not isinstance(policy, PostPolicy): - raise ValueError("policy must be PostPolicy type") - if not self._provider: - raise ValueError( - "anonymous access does not require presigned post form-data", - ) - check_bucket_name( - policy.bucket_name, s3_check=self._base_url.is_aws_host) - return policy.form_data( - self._provider.retrieve(), - self._get_region(policy.bucket_name), - ) - - def delete_bucket_replication(self, bucket_name: str): - """ - Delete replication configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_replication("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - self._execute("DELETE", bucket_name, query_params={"replication": ""}) - - def get_bucket_replication( - self, - bucket_name: str, - ) -> Optional[ReplicationConfig]: - """ - Get bucket replication configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`ReplicationConfig ` object. - - Example:: - config = client.get_bucket_replication("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - response = self._execute( - "GET", bucket_name, query_params={"replication": ""}, - ) - return unmarshal(ReplicationConfig, response.data.decode()) - except S3Error as exc: - if exc.code != "ReplicationConfigurationNotFoundError": - raise - return None - - def set_bucket_replication( - self, - bucket_name: str, - config: ReplicationConfig, - ): - """ - Set bucket replication configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param config: :class:`ReplicationConfig ` object. - - Example:: - config = ReplicationConfig( - "REPLACE-WITH-ACTUAL-ROLE", - [ - Rule( - Destination( - "REPLACE-WITH-ACTUAL-DESTINATION-BUCKET-ARN", - ), - ENABLED, - delete_marker_replication=DeleteMarkerReplication( - DISABLED, - ), - rule_filter=Filter( - AndOperator( - "TaxDocs", - {"key1": "value1", "key2": "value2"}, - ), - ), - rule_id="rule1", - priority=1, - ), - ], - ) - client.set_bucket_replication("my-bucket", config) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, ReplicationConfig): - raise ValueError("config must be ReplicationConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"replication": ""}, - ) - - def delete_bucket_lifecycle(self, bucket_name: str): - """ - Delete notification configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_lifecycle("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - self._execute("DELETE", bucket_name, query_params={"lifecycle": ""}) - - def get_bucket_lifecycle( - self, - bucket_name: str, - ) -> Optional[LifecycleConfig]: - """ - Get bucket lifecycle configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`LifecycleConfig ` object. - - Example:: - config = client.get_bucket_lifecycle("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - response = self._execute( - "GET", bucket_name, query_params={"lifecycle": ""}, - ) - return unmarshal(LifecycleConfig, response.data.decode()) - except S3Error as exc: - if exc.code != "NoSuchLifecycleConfiguration": - raise - return None - - def set_bucket_lifecycle( - self, - bucket_name: str, - config: LifecycleConfig, - ): - """ - Set bucket lifecycle configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param config: :class:`LifecycleConfig ` object. - - Example:: - config = LifecycleConfig( - [ - Rule( - ENABLED, - rule_filter=Filter(prefix="documents/"), - rule_id="rule1", - transition=Transition( - days=30, storage_class="GLACIER", - ), - ), - Rule( - ENABLED, - rule_filter=Filter(prefix="logs/"), - rule_id="rule2", - expiration=Expiration(days=365), - ), - ], - ) - client.set_bucket_lifecycle("my-bucket", config) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, LifecycleConfig): - raise ValueError("config must be LifecycleConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"lifecycle": ""}, - ) - - def delete_bucket_tags(self, bucket_name: str): - """ - Delete tags configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_bucket_tags("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - self._execute("DELETE", bucket_name, query_params={"tagging": ""}) - - def get_bucket_tags(self, bucket_name: str) -> Optional[Tags]: - """ - Get tags configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`Tags ` object. - - Example:: - tags = client.get_bucket_tags("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - try: - response = self._execute( - "GET", bucket_name, query_params={"tagging": ""}, - ) - tagging = unmarshal(Tagging, response.data.decode()) - return tagging.tags - except S3Error as exc: - if exc.code != "NoSuchTagSet": - raise - return None - - def set_bucket_tags(self, bucket_name: str, tags: Tags): - """ - Set tags configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param tags: :class:`Tags ` object. - - Example:: - tags = Tags.new_bucket_tags() - tags["Project"] = "Project One" - tags["User"] = "jsmith" - client.set_bucket_tags("my-bucket", tags) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(tags, Tags): - raise ValueError("tags must be Tags type") - body = marshal(Tagging(tags)) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"tagging": ""}, - ) - - def delete_object_tags( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ): - """ - Delete tags configuration of an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the Object. - - Example:: - client.delete_object_tags("my-bucket", "my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - query_params = {"versionId": version_id} if version_id else {} - query_params["tagging"] = "" - self._execute( - "DELETE", - bucket_name, - object_name=object_name, - query_params=cast(DictType, query_params), - ) - - def get_object_tags( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ) -> Optional[Tags]: - """ - Get tags configuration of a object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the Object. - :return: :class:`Tags ` object. - - Example:: - tags = client.get_object_tags("my-bucket", "my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - query_params = {"versionId": version_id} if version_id else {} - query_params["tagging"] = "" - try: - response = self._execute( - "GET", - bucket_name, - object_name=object_name, - query_params=cast(DictType, query_params), - ) - tagging = unmarshal(Tagging, response.data.decode()) - return tagging.tags - except S3Error as exc: - if exc.code != "NoSuchTagSet": - raise - return None - - def set_object_tags( - self, - bucket_name: str, - object_name: str, - tags: Tags, - version_id: Optional[str] = None, - ): - """ - Set tags configuration to an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the Object. - :param tags: :class:`Tags ` object. - - Example:: - tags = Tags.new_object_tags() - tags["Project"] = "Project One" - tags["User"] = "jsmith" - client.set_object_tags("my-bucket", "my-object", tags) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if not isinstance(tags, Tags): - raise ValueError("tags must be Tags type") - body = marshal(Tagging(tags)) - query_params = {"versionId": version_id} if version_id else {} - query_params["tagging"] = "" - self._execute( - "PUT", - bucket_name, - object_name=object_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params=cast(DictType, query_params), - ) - - def enable_object_legal_hold( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ): - """ - Enable legal hold on an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - - Example:: - client.enable_object_legal_hold("my-bucket", "my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - body = marshal(LegalHold(True)) - query_params = {"versionId": version_id} if version_id else {} - query_params["legal-hold"] = "" - self._execute( - "PUT", - bucket_name, - object_name=object_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params=cast(DictType, query_params), - ) - - def disable_object_legal_hold( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ): - """ - Disable legal hold on an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - - Example:: - client.disable_object_legal_hold("my-bucket", "my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - body = marshal(LegalHold(False)) - query_params = {"versionId": version_id} if version_id else {} - query_params["legal-hold"] = "" - self._execute( - "PUT", - bucket_name, - object_name=object_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params=cast(DictType, query_params), - ) - - def is_object_legal_hold_enabled( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ) -> bool: - """ - Returns true if legal hold is enabled on an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - - Example:: - if client.is_object_legal_hold_enabled("my-bucket", "my-object"): - print("legal hold is enabled on my-object") - else: - print("legal hold is not enabled on my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - query_params = {"versionId": version_id} if version_id else {} - query_params["legal-hold"] = "" - try: - response = self._execute( - "GET", - bucket_name, - object_name=object_name, - query_params=cast(DictType, query_params), - ) - legal_hold = unmarshal(LegalHold, response.data.decode()) - return legal_hold.status - except S3Error as exc: - if exc.code != "NoSuchObjectLockConfiguration": - raise - return False - - def delete_object_lock_config(self, bucket_name: str): - """ - Delete object-lock configuration of a bucket. - - :param bucket_name: Name of the bucket. - - Example:: - client.delete_object_lock_config("my-bucket") - """ - self.set_object_lock_config( - bucket_name, ObjectLockConfig(None, None, None) - ) - - def get_object_lock_config(self, bucket_name: str) -> ObjectLockConfig: - """ - Get object-lock configuration of a bucket. - - :param bucket_name: Name of the bucket. - :return: :class:`ObjectLockConfig ` object. - - Example:: - config = client.get_object_lock_config("my-bucket") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - response = self._execute( - "GET", bucket_name, query_params={"object-lock": ""}, - ) - return unmarshal(ObjectLockConfig, response.data.decode()) - - def set_object_lock_config( - self, - bucket_name: str, - config: ObjectLockConfig, - ): - """ - Set object-lock configuration to a bucket. - - :param bucket_name: Name of the bucket. - :param config: :class:`ObjectLockConfig ` object. - - Example:: - config = ObjectLockConfig(GOVERNANCE, 15, DAYS) - client.set_object_lock_config("my-bucket", config) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - if not isinstance(config, ObjectLockConfig): - raise ValueError("config must be ObjectLockConfig type") - body = marshal(config) - self._execute( - "PUT", - bucket_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params={"object-lock": ""}, - ) - - def get_object_retention( - self, - bucket_name: str, - object_name: str, - version_id: Optional[str] = None, - ) -> Optional[Retention]: - """ - Get retention configuration of an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - :return: :class:`Retention ` object. - - Example:: - config = client.get_object_retention("my-bucket", "my-object") - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - query_params = {"versionId": version_id} if version_id else {} - query_params["retention"] = "" - try: - response = self._execute( - "GET", - bucket_name, - object_name=object_name, - query_params=cast(DictType, query_params), - ) - return unmarshal(Retention, response.data.decode()) - except S3Error as exc: - if exc.code != "NoSuchObjectLockConfiguration": - raise - return None - - def set_object_retention( - self, - bucket_name: str, - object_name: str, - config: Retention, - version_id: Optional[str] = None, - ): - """ - Set retention configuration on an object. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param version_id: Version ID of the object. - :param config: :class:`Retention ` object. - - Example:: - config = Retention( - GOVERNANCE, datetime.utcnow() + timedelta(days=10), - ) - client.set_object_retention("my-bucket", "my-object", config) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - check_object_name(object_name) - if not isinstance(config, Retention): - raise ValueError("config must be Retention type") - body = marshal(config) - query_params = {"versionId": version_id} if version_id else {} - query_params["retention"] = "" - self._execute( - "PUT", - bucket_name, - object_name=object_name, - body=body, - headers={"Content-MD5": cast(str, md5sum_hash(body))}, - query_params=cast(DictType, query_params), - ) - - def upload_snowball_objects( - self, - bucket_name: str, - object_list: Iterable[SnowballObject], - metadata: Optional[DictType] = None, - sse: Optional[Sse] = None, - tags: Optional[Tags] = None, - retention: Optional[Retention] = None, - legal_hold: bool = False, - staging_filename: Optional[str] = None, - compression: bool = False, - ) -> ObjectWriteResult: - """ - Uploads multiple objects in a single put call. It is done by creating - intermediate TAR file optionally compressed which is uploaded to S3 - service. - - :param bucket_name: Name of the bucket. - :param object_list: An iterable containing - :class:`SnowballObject ` object. - :param metadata: Any additional metadata to be uploaded along - with your PUT request. - :param sse: Server-side encryption. - :param tags: :class:`Tags` for the object. - :param retention: :class:`Retention` configuration object. - :param legal_hold: Flag to set legal hold for the object. - :param staging_filename: A staging filename to create intermediate - tarball. - :param compression: Flag to compress TAR ball. - :return: :class:`ObjectWriteResult` object. - - Example:: - # Upload snowball object. - result = client.upload_snowball_objects( - "my-bucket", - [ - SnowballObject("my-object1", filename="/etc/hostname"), - SnowballObject( - "my-object2", data=io.BytesIO("hello"), length=5, - ), - SnowballObject( - "my-object3", data=io.BytesIO("world"), length=5, - mod_time=datetime.now(), - ), - ], - ) - """ - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - - object_name = f"snowball.{random()}.tar" - - # turn list like objects into an iterator. - object_list = itertools.chain(object_list) - - metadata = metadata or {} - metadata["X-Amz-Meta-Snowball-Auto-Extract"] = "true" - - name = staging_filename - fileobj = None if name else BytesIO() - with tarfile.open( - name=name, mode="w:gz" if compression else "w", fileobj=fileobj, - ) as tar: - for obj in object_list: - if obj.filename: - tar.add(obj.filename, obj.object_name) - else: - info = tarfile.TarInfo(obj.object_name) - info.size = cast(int, obj.length) - info.mtime = int( - time.to_float(obj.mod_time or time.utcnow()), - ) - tar.addfile(info, obj.data) - - if not name: - length = cast(BytesIO, fileobj).tell() - cast(BytesIO, fileobj).seek(0) - else: - length = os.stat(name).st_size - - part_size = 0 if length < MIN_PART_SIZE else length - - if name: - return self.fput_object( - bucket_name, - object_name, - cast(str, staging_filename), - metadata=metadata, - sse=sse, - tags=tags, - retention=retention, - legal_hold=legal_hold, - part_size=part_size, - ) - return self.put_object( - bucket_name, - object_name, - cast(BinaryIO, fileobj), - length, - metadata=cast(Union[DictType, None], metadata), - sse=sse, - tags=tags, - retention=retention, - legal_hold=legal_hold, - part_size=part_size, - ) - - def _list_objects( - self, - bucket_name: str, - continuation_token: Optional[str] = None, # listV2 only - delimiter: Optional[str] = None, # all - encoding_type: Optional[str] = None, # all - fetch_owner: Optional[bool] = None, # listV2 only - include_user_meta: bool = False, # MinIO specific listV2. - max_keys: Optional[int] = None, # all - prefix: Optional[str] = None, # all - start_after: Optional[str] = None, - # all: v1:marker, versioned:key_marker - version_id_marker: Optional[str] = None, # versioned - use_api_v1: bool = False, - include_version: bool = False, - extra_headers: Optional[DictType] = None, - extra_query_params: Optional[DictType] = None, - ) -> Iterator[Object]: - """ - List objects optionally including versions. - Note: Its required to send empty values to delimiter/prefix and 1000 to - max-keys when not provided for server-side bucket policy evaluation to - succeed; otherwise AccessDenied error will be returned for such - policies. - """ - - check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host) - - if version_id_marker: - include_version = True - - is_truncated = True - while is_truncated: - query = extra_query_params or {} - if include_version: - query["versions"] = "" - elif not use_api_v1: - query["list-type"] = "2" - - if not include_version and not use_api_v1: - if continuation_token: - query["continuation-token"] = continuation_token - if fetch_owner: - query["fetch-owner"] = "true" - if include_user_meta: - query["metadata"] = "true" - query["delimiter"] = delimiter or "" - if encoding_type: - query["encoding-type"] = encoding_type - query["max-keys"] = str(max_keys or 1000) - query["prefix"] = prefix or "" - if start_after: - if include_version: - query["key-marker"] = start_after - elif use_api_v1: - query["marker"] = start_after - else: - query["start-after"] = start_after - if version_id_marker: - query["version-id-marker"] = version_id_marker - - response = self._execute( - "GET", - bucket_name, - query_params=cast(DictType, query), - headers=extra_headers, - ) - - objects, is_truncated, start_after, version_id_marker = ( - parse_list_objects(response) - ) - - if not include_version: - version_id_marker = None - if not use_api_v1: - continuation_token = start_after - - yield from objects - - def _list_multipart_uploads( - self, - bucket_name: str, - delimiter: Optional[str] = None, - encoding_type: Optional[str] = None, - key_marker: Optional[str] = None, - max_uploads: Optional[int] = None, - prefix: Optional[str] = None, - upload_id_marker: Optional[str] = None, - extra_headers: Optional[DictType] = None, - extra_query_params: Optional[DictType] = None, - ) -> ListMultipartUploadsResult: - """ - Execute ListMultipartUploads S3 API. - - :param bucket_name: Name of the bucket. - :param delimiter: (Optional) Delimiter on listing. - :param encoding_type: (Optional) Encoding type. - :param key_marker: (Optional) Key marker. - :param max_uploads: (Optional) Maximum upload information to fetch. - :param prefix: (Optional) Prefix on listing. - :param upload_id_marker: (Optional) Upload ID marker. - :param extra_headers: (Optional) Extra headers for advanced usage. - :param extra_query_params: (Optional) Extra query parameters for - advanced usage. - :return: - :class:`ListMultipartUploadsResult ` - object - """ - - query_params = extra_query_params or {} - query_params.update( - { - "uploads": "", - "delimiter": delimiter or "", - "max-uploads": str(max_uploads or 1000), - "prefix": prefix or "", - "encoding-type": "url", - }, - ) - if encoding_type: - query_params["encoding-type"] = encoding_type - if key_marker: - query_params["key-marker"] = key_marker - if upload_id_marker: - query_params["upload-id-marker"] = upload_id_marker - - response = self._execute( - "GET", - bucket_name, - query_params=cast(DictType, query_params), - headers=cast(Union[DictType, None], extra_headers), - ) - return ListMultipartUploadsResult(response) - - def _list_parts( - self, - bucket_name: str, - object_name: str, - upload_id: str, - max_parts: Optional[int] = None, - part_number_marker: Optional[str] = None, - extra_headers: Optional[DictType] = None, - extra_query_params: Optional[DictType] = None, - ) -> ListPartsResult: - """ - Execute ListParts S3 API. - - :param bucket_name: Name of the bucket. - :param object_name: Object name in the bucket. - :param upload_id: Upload ID. - :param max_parts: (Optional) Maximum parts information to fetch. - :param part_number_marker: (Optional) Part number marker. - :param extra_headers: (Optional) Extra headers for advanced usage. - :param extra_query_params: (Optional) Extra query parameters for - advanced usage. - :return: :class:`ListPartsResult ` object - """ - - query_params = extra_query_params or {} - query_params.update( - { - "uploadId": upload_id, - "max-parts": str(max_parts or 1000), - }, - ) - if part_number_marker: - query_params["part-number-marker"] = part_number_marker - - response = self._execute( - "GET", - bucket_name, - object_name=object_name, - query_params=cast(DictType, query_params), - headers=cast(Union[DictType, None], extra_headers), - ) - return ListPartsResult(response) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/commonconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/commonconfig.py deleted file mode 100644 index 9514c72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/commonconfig.py +++ /dev/null @@ -1,457 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Common request/response configuration of S3 APIs.""" -# pylint: disable=invalid-name - -from __future__ import absolute_import, annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass, field -from datetime import datetime -from typing import IO, Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .error import MinioException -from .helpers import quote -from .sse import SseCustomerKey -from .time import to_http_header -from .xml import SubElement, find, findall, findtext - -COPY = "COPY" -REPLACE = "REPLACE" -DISABLED = "Disabled" -ENABLED = "Enabled" -GOVERNANCE = "GOVERNANCE" -COMPLIANCE = "COMPLIANCE" -_MAX_KEY_LENGTH = 128 -_MAX_VALUE_LENGTH = 256 -_MAX_OBJECT_TAG_COUNT = 10 -_MAX_TAG_COUNT = 50 - -A = TypeVar("A", bound="Tags") - - -class Tags(dict): - """dict extended to bucket/object tags.""" - - def __init__(self, for_object: bool = False): - self._for_object = for_object - super().__init__() - - def __setitem__(self, key: str, value: str): - limit = _MAX_OBJECT_TAG_COUNT if self._for_object else _MAX_TAG_COUNT - if len(self) == limit: - tag_type = "object" if self._for_object else "bucket" - raise ValueError(f"only {limit} {tag_type} tags are allowed") - if not key or len(key) > _MAX_KEY_LENGTH or "&" in key: - raise ValueError(f"invalid tag key '{key}'") - if value is None or len(value) > _MAX_VALUE_LENGTH or "&" in value: - raise ValueError(f"invalid tag value '{value}'") - super().__setitem__(key, value) - - @classmethod - def new_bucket_tags(cls: Type[A]) -> A: - """Create new bucket tags.""" - return cls() - - @classmethod - def new_object_tags(cls: Type[A]) -> A: - """Create new object tags.""" - return cls(True) - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - elements = findall(element, "Tag") - obj = cls() - for tag in elements: - key = cast(str, findtext(tag, "Key", True)) - value = cast(str, findtext(tag, "Value", True)) - obj[key] = value - return obj - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - for key, value in self.items(): - tag = SubElement(element, "Tag") - SubElement(tag, "Key", key) - SubElement(tag, "Value", value) - return element - - -B = TypeVar("B", bound="Tag") - - -@dataclass(frozen=True) -class Tag: - """Tag.""" - - key: str - value: str - - def __post_init__(self): - if not self.key: - raise ValueError("key must be provided") - if self.value is None: - raise ValueError("value must be provided") - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Tag", True)) - key = cast(str, findtext(element, "Key", True)) - value = cast(str, findtext(element, "Value", True)) - return cls(key, value) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Tag") - SubElement(element, "Key", self.key) - SubElement(element, "Value", self.value) - return element - - -C = TypeVar("C", bound="AndOperator") - - -@dataclass(frozen=True) -class AndOperator: - """AND operator.""" - - prefix: Optional[str] = None - tags: Optional[Tags] = None - - def __post_init__(self): - if self.prefix is None and not self.tags: - raise ValueError("at least prefix or tags must be provided") - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "And", True)) - prefix = findtext(element, "Prefix") - tags = ( - None if find(element, "Tag") is None - else Tags.fromxml(element) - ) - return cls(prefix, tags) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "And") - if self.prefix is not None: - SubElement(element, "Prefix", self.prefix) - if self.tags is not None: - self.tags.toxml(element) - return element - - -D = TypeVar("D", bound="Filter") - - -@dataclass(frozen=True) -class Filter: - """Lifecycle rule filter.""" - - and_operator: Optional[AndOperator] = None - prefix: Optional[str] = None - tag: Optional[Tag] = None - - def __post_init__(self): - valid = ( - (self.and_operator is not None) ^ - (self.prefix is not None) ^ - (self.tag is not None) - ) - if not valid: - raise ValueError("only one of and, prefix or tag must be provided") - - @classmethod - def fromxml(cls: Type[D], element: ET.Element) -> D: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Filter", True)) - and_operator = ( - None if find(element, "And") is None - else AndOperator.fromxml(element) - ) - prefix = findtext(element, "Prefix") - tag = None if find(element, "Tag") is None else Tag.fromxml(element) - return cls(and_operator, prefix, tag) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Filter") - if self.and_operator: - self.and_operator.toxml(element) - if self.prefix is not None: - SubElement(element, "Prefix", self.prefix) - if self.tag is not None: - self.tag.toxml(element) - return element - - -@dataclass(frozen=True) -class BaseRule(ABC): - """Base rule class for Replication and Lifecycle.""" - status: str - rule_filter: Optional[Filter] = None - rule_id: Optional[str] = None - - def __post_init__(self): - check_status(self.status) - if self.rule_id is not None: - self.rule_id = self.rule_id.strip() - if not self.rule_id: - raise ValueError("rule ID must be non-empty string") - if len(self.rule_id) > 255: - raise ValueError("rule ID must not exceed 255 characters") - - @abstractmethod - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - @staticmethod - def parsexml( - element: ET.Element, - ) -> tuple[str, Optional[Filter], Optional[str]]: - """Parse XML and return filter and ID.""" - return ( - cast(str, findtext(element, "Status", True)), - ( - None if find(element, "Filter") is None - else Filter.fromxml(element) - ), - findtext(element, "ID"), - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - SubElement(element, "Status", self.status) - if self.rule_filter: - self.rule_filter.toxml(element) - if self.rule_id is not None: - SubElement(element, "ID", self.rule_id) - return element - - -def check_status(status: str): - """Validate status.""" - if status not in [ENABLED, DISABLED]: - raise ValueError("status must be 'Enabled' or 'Disabled'") - - -@dataclass -class ObjectConditionalReadArgs(ABC): - """Base argument class holds condition properties for reading object.""" - bucket_name: str - object_name: str - region: Optional[str] = None - version_id: Optional[str] = None - ssec: Optional[SseCustomerKey] = None - offset: Optional[int] = None - length: Optional[int] = None - match_etag: Optional[str] = None - not_match_etag: Optional[str] = None - modified_since: Optional[datetime] = None - unmodified_since: Optional[datetime] = None - - def __post_init__(self): - if ( - self.ssec is not None and - not isinstance(self.ssec, SseCustomerKey) - ): - raise ValueError("ssec must be SseCustomerKey type") - if self.offset is not None and self.offset < 0: - raise ValueError("offset should be zero or greater") - if self.length is not None and self.length <= 0: - raise ValueError("length should be greater than zero") - if self.match_etag is not None and self.match_etag == "": - raise ValueError("match_etag must not be empty") - if self.not_match_etag is not None and self.not_match_etag == "": - raise ValueError("not_match_etag must not be empty") - if ( - self.modified_since is not None and - not isinstance(self.modified_since, datetime) - ): - raise ValueError("modified_since must be datetime type") - if ( - self.unmodified_since is not None and - not isinstance(self.unmodified_since, datetime) - ): - raise ValueError("unmodified_since must be datetime type") - - @abstractmethod - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - def gen_copy_headers(self) -> dict[str, str]: - """Generate copy source headers.""" - copy_source = quote("/" + self.bucket_name + "/" + self.object_name) - if self.version_id: - copy_source += "?versionId=" + quote(self.version_id) - - headers = {"x-amz-copy-source": copy_source} - if self.ssec: - headers.update(self.ssec.copy_headers()) - if self.match_etag: - headers["x-amz-copy-source-if-match"] = self.match_etag - if self.not_match_etag: - headers["x-amz-copy-source-if-none-match"] = self.not_match_etag - if self.modified_since: - headers["x-amz-copy-source-if-modified-since"] = ( - to_http_header(self.modified_since) - ) - if self.unmodified_since: - headers["x-amz-copy-source-if-unmodified-since"] = ( - to_http_header(self.unmodified_since) - ) - return headers - - -E = TypeVar("E", bound="CopySource") - - -@dataclass -class CopySource(ObjectConditionalReadArgs): - """A source object definition for copy_object method.""" - - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - @classmethod - def of(cls: Type[E], src: ObjectConditionalReadArgs) -> E: - """Create CopySource from another source.""" - return cls( - bucket_name=src.bucket_name, - object_name=src.object_name, - region=src.region, - version_id=src.version_id, - ssec=src.ssec, - offset=src.offset, - length=src.length, - match_etag=src.match_etag, - not_match_etag=src.not_match_etag, - modified_since=src.modified_since, - unmodified_since=src.unmodified_since, - ) - - -F = TypeVar("F", bound="ComposeSource") - - -@dataclass -class ComposeSource(ObjectConditionalReadArgs): - """A source object definition for compose_object method.""" - _object_size: Optional[int] = field(default=None, init=False) - _headers: Optional[dict[str, str]] = field(default=None, init=False) - - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - def _validate_size(self, object_size: int): - """Validate object size with offset and length.""" - def make_error(name, value): - ver = ("?versionId="+self.version_id) if self.version_id else "" - return ValueError( - f"Source {self.bucket_name}/{self.object_name}{ver}: " - f"{name} {value} is beyond object size {object_size}" - ) - - if self.offset is not None and self.offset >= object_size: - raise make_error("offset", self.offset) - if self.length is not None: - if self.length > object_size: - raise make_error("length", self.length) - offset = self.offset or 0 - if offset+self.length > object_size: - raise make_error("compose size", offset+self.length) - - def build_headers(self, object_size: int, etag: str): - """Build headers.""" - self._validate_size(object_size) - self._object_size = object_size - headers = self.gen_copy_headers() - headers["x-amz-copy-source-if-match"] = self.match_etag or etag - self._headers = headers - - @property - def object_size(self) -> Optional[int]: - """Get object size.""" - if self._object_size is None: - raise MinioException( - "build_headers() must be called prior to " - "this method invocation", - ) - return self._object_size - - @property - def headers(self) -> dict[str, str]: - """Get headers.""" - if self._headers is None: - raise MinioException( - "build_headers() must be called prior to " - "this method invocation", - ) - return self._headers.copy() - - @classmethod - def of(cls: Type[F], src: ObjectConditionalReadArgs) -> F: - """Create ComposeSource from another source.""" - return cls( - bucket_name=src.bucket_name, - object_name=src.object_name, - region=src.region, - version_id=src.version_id, - ssec=src.ssec, - offset=src.offset, - length=src.length, - match_etag=src.match_etag, - not_match_etag=src.not_match_etag, - modified_since=src.modified_since, - unmodified_since=src.unmodified_since, - ) - - -@dataclass(frozen=True) -class SnowballObject: - """A source object definition for upload_snowball_objects method.""" - object_name: str - filename: Optional[str] = None - data: Optional[IO[bytes]] = None - length: Optional[int] = None - mod_time: Optional[datetime] = None - - def __post_init__(self): - if not (self.filename is not None) ^ (self.data is not None): - raise ValueError("only one of filename or data must be provided") - if self.data is not None and self.length is None: - raise ValueError("length must be provided for data") - if ( - self.mod_time is not None and - not isinstance(self.mod_time, datetime) - ): - raise ValueError("mod_time must be datetime type") diff --git a/backend/venv39/lib/python3.9/site-packages/minio/credentials/__init__.py b/backend/venv39/lib/python3.9/site-packages/minio/credentials/__init__.py deleted file mode 100644 index 4adc1ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/credentials/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Credential module.""" - -# pylint: disable=unused-import -from .credentials import Credentials -from .providers import (AssumeRoleProvider, AWSConfigProvider, - CertificateIdentityProvider, ChainedProvider, - ClientGrantsProvider, EnvAWSProvider, EnvMinioProvider, - IamAwsProvider, LdapIdentityProvider, - MinioClientConfigProvider, Provider, StaticProvider, - WebIdentityProvider) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/credentials/credentials.py b/backend/venv39/lib/python3.9/site-packages/minio/credentials/credentials.py deleted file mode 100644 index deac5ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/credentials/credentials.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Credential definitions to access S3 service.""" -from __future__ import annotations - -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from typing import Optional - - -@dataclass(frozen=True) -class Credentials: - """ - Represents credentials access key, secret key and session token. - """ - - access_key: str - secret_key: str - session_token: Optional[str] = None - expiration: Optional[datetime] = None - - def __post_init__(self): - if not self.access_key: - raise ValueError("Access key must not be empty") - - if not self.secret_key: - raise ValueError("Secret key must not be empty") - - if self.expiration and self.expiration.tzinfo: - object.__setattr__( - self, "expiration", - self.expiration.astimezone(timezone.utc).replace(tzinfo=None), - ) - - def is_expired(self) -> bool: - """Check whether this credentials expired or not.""" - return ( - self.expiration < (datetime.utcnow() + timedelta(seconds=10)) - if self.expiration else False - ) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/credentials/providers.py b/backend/venv39/lib/python3.9/site-packages/minio/credentials/providers.py deleted file mode 100644 index 00e3e03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/credentials/providers.py +++ /dev/null @@ -1,803 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=too-many-branches - -"""Credential providers.""" - -from __future__ import annotations - -import configparser -import ipaddress -import json -import os -import re -import socket -import sys -import time -from abc import ABC, abstractmethod -from datetime import timedelta -from pathlib import Path -from typing import Callable, Optional, cast -from urllib.parse import urlencode, urlsplit, urlunsplit -from xml.etree import ElementTree as ET - -import certifi -from urllib3.poolmanager import PoolManager - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -from urllib3.util import Retry, parse_url - -from minio.helpers import sha256_hash, url_replace -from minio.signer import sign_v4_sts -from minio.time import from_iso8601utc, to_amz_date, utcnow -from minio.xml import find, findtext - -from .credentials import Credentials - -_MIN_DURATION_SECONDS = int(timedelta(minutes=15).total_seconds()) -_MAX_DURATION_SECONDS = int(timedelta(days=7).total_seconds()) -_DEFAULT_DURATION_SECONDS = int(timedelta(hours=1).total_seconds()) - - -def _parse_credentials(data: str, name: str) -> Credentials: - """Parse data containing credentials XML.""" - element = ET.fromstring(data) - element = cast(ET.Element, find(element, name, True)) - element = cast(ET.Element, find(element, "Credentials", True)) - expiration = from_iso8601utc(findtext(element, "Expiration", True)) - return Credentials( - access_key=cast(str, findtext(element, "AccessKeyId", True)), - secret_key=cast(str, findtext(element, "SecretAccessKey", True)), - session_token=findtext(element, "SessionToken", True), - expiration=expiration, - ) - - -def _urlopen( - http_client: PoolManager, - method: str, - url: str, - body: Optional[str | bytes] = None, - headers: Optional[dict[str, str | list[str] | tuple[str]]] = None, -) -> BaseHTTPResponse: - """Wrapper of urlopen() handles HTTP status code.""" - res = http_client.urlopen(method, url, body=body, headers=headers) - if res.status not in [200, 204, 206]: - safe_url = re.sub( - r"LDAPPassword=([^&]+)", "LDAPPassword=*REDACTED*", url, - ) - raise ValueError( - f"{safe_url} failed with HTTP status code {res.status}", - ) - return res - - -def _user_home_dir() -> str: - """Return current user home folder.""" - return ( - os.environ.get("HOME") or - os.environ.get("UserProfile") or - str(Path.home()) - ) - - -class Provider(ABC): # pylint: disable=too-few-public-methods - """Credential retriever.""" - - @abstractmethod - def retrieve(self) -> Credentials: - """Retrieve credentials and its expiry if available.""" - - -class AssumeRoleProvider(Provider): - """Assume-role credential provider.""" - - def __init__( - self, - *, - sts_endpoint: str, - access_key: str, - secret_key: str, - duration_seconds: int = 0, - policy: Optional[str] = None, - region: Optional[str] = None, - role_arn: Optional[str] = None, - role_session_name: Optional[str] = None, - external_id: Optional[str] = None, - http_client: Optional[PoolManager] = None, - ): - self._sts_endpoint = sts_endpoint - self._access_key = access_key - self._secret_key = secret_key - self._region = region or "" - self._http_client = http_client or PoolManager( - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504], - ), - ) - - query_params = { - "Action": "AssumeRole", - "Version": "2011-06-15", - "DurationSeconds": str( - duration_seconds - if duration_seconds > _DEFAULT_DURATION_SECONDS - else _DEFAULT_DURATION_SECONDS - ), - } - - if role_arn: - query_params["RoleArn"] = role_arn - if role_session_name: - query_params["RoleSessionName"] = role_session_name - if policy: - query_params["Policy"] = policy - if external_id: - query_params["ExternalId"] = external_id - - self._body = urlencode(query_params) - self._content_sha256 = sha256_hash(self._body) - url = urlsplit(sts_endpoint) - self._url = url - self._host = url.netloc - if ( - (url.scheme == "http" and url.port == 80) or - (url.scheme == "https" and url.port == 443) - ): - self._host = cast(str, url.hostname) - self._credentials: Optional[Credentials] = None - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - utctime = utcnow() - headers = sign_v4_sts( - method="POST", - url=self._url, - region=self._region, - headers={ - "Content-Type": "application/x-www-form-urlencoded", - "Host": self._host, - "X-Amz-Date": to_amz_date(utctime), - }, - credentials=Credentials( - access_key=self._access_key, - secret_key=self._secret_key, - ), - content_sha256=self._content_sha256, - date=utctime, - ) - - res = _urlopen( - self._http_client, - "POST", - self._sts_endpoint, - body=self._body, - headers=headers, - ) - - self._credentials = _parse_credentials( - res.data.decode(), "AssumeRoleResult", - ) - - return self._credentials - - -class ChainedProvider(Provider): - """Chained credential provider.""" - - def __init__(self, providers: list[Provider]): - self._providers = providers - self._provider: Optional[Provider] = None - self._credentials: Optional[Credentials] = None - - def retrieve(self) -> Credentials: - """Retrieve credentials from one of available provider.""" - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - if self._provider: - try: - self._credentials = self._provider.retrieve() - return self._credentials - except ValueError: - # Ignore this error and iterate other providers. - pass - - for provider in self._providers: - try: - self._credentials = provider.retrieve() - self._provider = provider - return self._credentials - except ValueError: - # Ignore this error and iterate other providers. - pass - - raise ValueError("All providers fail to fetch credentials") - - -class EnvAWSProvider(Provider): - """Credential provider from AWS environment variables.""" - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - return Credentials( - access_key=( - cast( - str, - os.environ.get("AWS_ACCESS_KEY_ID") or - os.environ.get("AWS_ACCESS_KEY"), - ) - ), - secret_key=( - cast( - str, - os.environ.get("AWS_SECRET_ACCESS_KEY") or - os.environ.get("AWS_SECRET_KEY"), - ) - ), - session_token=os.environ.get("AWS_SESSION_TOKEN"), - ) - - -class EnvMinioProvider(Provider): - """Credential provider from MinIO environment variables.""" - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - return Credentials( - access_key=os.environ.get("MINIO_ACCESS_KEY") or "", - secret_key=os.environ.get("MINIO_SECRET_KEY") or "", - ) - - -class AWSConfigProvider(Provider): - """Credential provider from AWS credential file.""" - - def __init__( - self, - filename: Optional[str] = None, - profile: Optional[str] = None, - ): - self._filename = ( - filename or - os.environ.get("AWS_SHARED_CREDENTIALS_FILE") or - os.path.join(_user_home_dir(), ".aws", "credentials") - ) - self._profile = profile or os.environ.get("AWS_PROFILE") or "default" - - def retrieve(self) -> Credentials: - """Retrieve credentials from AWS configuration file.""" - parser = configparser.ConfigParser() - parser.read(self._filename) - access_key = parser.get( - self._profile, - "aws_access_key_id", - fallback=None, - ) - secret_key = parser.get( - self._profile, - "aws_secret_access_key", - fallback=None, - ) - session_token = parser.get( - self._profile, - "aws_session_token", - fallback=None, - ) - - if not access_key: - raise ValueError( - f"access key does not exist in profile " - f"{self._profile} in AWS credential file {self._filename}" - ) - - if not secret_key: - raise ValueError( - f"secret key does not exist in profile " - f"{self._profile} in AWS credential file {self._filename}" - ) - - return Credentials( - access_key, - secret_key, - session_token=session_token, - ) - - -class MinioClientConfigProvider(Provider): - """Credential provider from MinIO Client configuration file.""" - - def __init__( - self, - filename: Optional[str] = None, - alias: Optional[str] = None, - ): - self._filename = ( - filename or - os.path.join( - _user_home_dir(), - "mc" if sys.platform == "win32" else ".mc", - "config.json", - ) - ) - self._alias = alias or os.environ.get("MINIO_ALIAS") or "s3" - - def retrieve(self) -> Credentials: - """Retrieve credential value from MinIO client configuration file.""" - try: - with open(self._filename, encoding="utf-8") as conf_file: - config = json.load(conf_file) - aliases = config.get("hosts") or config.get("aliases") - if not aliases: - raise ValueError( - f"invalid configuration in file {self._filename}", - ) - creds = aliases.get(self._alias) - if not creds: - raise ValueError( - f"alias {self._alias} not found in MinIO client" - f"configuration file {self._filename}" - ) - return Credentials(creds.get("accessKey"), creds.get("secretKey")) - except (IOError, OSError) as exc: - raise ValueError( - f"error in reading file {self._filename}", - ) from exc - - -def _check_loopback_host(url: str): - """Check whether host in url points only to localhost.""" - host = cast(str, parse_url(url).host) - try: - addrs = set(info[4][0] for info in socket.getaddrinfo(host, None)) - for addr in addrs: - if not ipaddress.ip_address(addr).is_loopback: - raise ValueError(host + " is not loopback only host") - except socket.gaierror as exc: - raise ValueError("Host " + host + " is not loopback address") from exc - - -def _get_jwt_token(token_file: str) -> dict[str, str]: - """Read and return content of token file. """ - try: - with open(token_file, encoding="utf-8") as file: - return {"access_token": file.read(), "expires_in": "0"} - except (IOError, OSError) as exc: - raise ValueError(f"error in reading file {token_file}") from exc - - -class IamAwsProvider(Provider): - """Credential provider using IAM roles for Amazon EC2/ECS.""" - - def __init__( - self, - *, - custom_endpoint: Optional[str] = None, - http_client: Optional[PoolManager] = None, - auth_token: Optional[str] = None, - relative_uri: Optional[str] = None, - full_uri: Optional[str] = None, - token_file: Optional[str] = None, - role_arn: Optional[str] = None, - role_session_name: Optional[str] = None, - region: Optional[str] = None, - ): - self._custom_endpoint = custom_endpoint - self._http_client = http_client or PoolManager( - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504], - ), - ) - self._token = ( - os.environ.get("AWS_CONTAINER_AUTHORIZATION_TOKEN") or - auth_token - ) - self._token_file = ( - os.environ.get("AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE") or - auth_token - ) - self._identity_file = ( - os.environ.get("AWS_WEB_IDENTITY_TOKEN_FILE") or token_file - ) - self._aws_region = os.environ.get("AWS_REGION") or region - self._role_arn = os.environ.get("AWS_ROLE_ARN") or role_arn - self._role_session_name = ( - os.environ.get("AWS_ROLE_SESSION_NAME") or role_session_name - ) - self._relative_uri = ( - os.environ.get("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") or - relative_uri - ) - if self._relative_uri and not self._relative_uri.startswith("/"): - self._relative_uri = "/" + self._relative_uri - self._full_uri = ( - os.environ.get("AWS_CONTAINER_CREDENTIALS_FULL_URI") or - full_uri - ) - self._credentials: Optional[Credentials] = None - - def fetch( - self, - url: str, - headers: Optional[dict[str, str | list[str] | tuple[str]]] = None, - ) -> Credentials: - """Fetch credentials from EC2/ECS.""" - res = _urlopen(self._http_client, "GET", url, headers=headers) - data = json.loads(res.data) - if data.get("Code", "Success") != "Success": - raise ValueError( - f"{url} failed with code {data['Code']} " - f"message {data.get('Message')}" - ) - data["Expiration"] = from_iso8601utc(data["Expiration"]) - - return Credentials( - data["AccessKeyId"], - data["SecretAccessKey"], - data["Token"], - data["Expiration"], - ) - - def retrieve(self) -> Credentials: - """Retrieve credentials from WebIdentity/EC2/ECS.""" - - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - url = self._custom_endpoint - if self._identity_file: - if not url: - url = "https://sts.amazonaws.com" - if self._aws_region: - url = f"https://sts.{self._aws_region}.amazonaws.com" - if self._aws_region.startswith("cn-"): - url += ".cn" - - provider = WebIdentityProvider( - jwt_provider_func=lambda: _get_jwt_token( - cast(str, self._identity_file), - ), - sts_endpoint=url, - role_arn=self._role_arn, - role_session_name=self._role_session_name, - http_client=self._http_client, - ) - self._credentials = provider.retrieve() - return cast(Credentials, self._credentials) - - headers: Optional[dict[str, str | list[str] | tuple[str]]] = None - if self._relative_uri: - if not url: - url = "http://169.254.170.2" + self._relative_uri - headers = {"Authorization": self._token} if self._token else None - elif self._full_uri: - token = self._token - if self._token_file: - url = self._full_uri - with open(self._token_file, encoding="utf-8") as file: - token = file.read() - else: - if not url: - url = self._full_uri - _check_loopback_host(url) - headers = {"Authorization": token} if token else None - else: - if not url: - url = "http://169.254.169.254" - - # Get IMDS Token - res = _urlopen( - self._http_client, - "PUT", - url+"/latest/api/token", - headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"}, - ) - token = res.data.decode("utf-8") - headers = {"X-aws-ec2-metadata-token": token} if token else None - - # Get role name - url = urlunsplit( - url_replace( - url=urlsplit(url), - path="/latest/meta-data/iam/security-credentials/", - ), - ) - res = _urlopen(self._http_client, "GET", url, headers=headers) - role_names = res.data.decode("utf-8").split("\n") - if not role_names: - raise ValueError(f"no IAM roles attached to EC2 service {url}") - url += role_names[0].strip("\r") - if not url: - raise ValueError("url is empty; this should not happen") - self._credentials = self.fetch(url, headers=headers) - return self._credentials - - -class LdapIdentityProvider(Provider): - """Credential provider using AssumeRoleWithLDAPIdentity API.""" - - def __init__( # pylint: disable=too-many-positional-arguments - self, - sts_endpoint: str, - ldap_username: str, - ldap_password: str, - duration_seconds: Optional[int] = None, - policy: Optional[str] = None, - token_revoke_type: Optional[str] = None, - http_client: Optional[PoolManager] = None, - ): - query_params = { - "Action": "AssumeRoleWithLDAPIdentity", - "Version": "2011-06-15", - "LDAPUsername": ldap_username, - "LDAPPassword": ldap_password, - } - if duration_seconds: - query_params["DurationSeconds"] = str(duration_seconds) - if policy: - query_params["Policy"] = policy - if token_revoke_type: - query_params["TokenRevokeType"] = token_revoke_type - - self._sts_endpoint = sts_endpoint + "?" + urlencode(query_params) - self._http_client = http_client or PoolManager( - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504], - ), - ) - self._credentials: Optional[Credentials] = None - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - res = _urlopen( - self._http_client, - "POST", - self._sts_endpoint, - ) - - self._credentials = _parse_credentials( - res.data.decode(), "AssumeRoleWithLDAPIdentityResult", - ) - - return self._credentials - - -class StaticProvider(Provider): - """Fixed credential provider.""" - - def __init__( - self, - access_key: str, - secret_key: str, - session_token: Optional[str] = None, - ): - self._credentials = Credentials(access_key, secret_key, session_token) - - def retrieve(self) -> Credentials: - """Return passed credentials.""" - return self._credentials - - -class WebIdentityClientGrantsProvider(Provider, ABC): - """Base class for WebIdentity and ClientGrants credentials provider.""" - - def __init__( - self, - *, - jwt_provider_func: Callable[[], dict[str, str]], - sts_endpoint: str, - duration_seconds: int = 0, - policy: Optional[str] = None, - role_arn: Optional[str] = None, - role_session_name: Optional[str] = None, - http_client: Optional[PoolManager] = None, - ): - self._jwt_provider_func = jwt_provider_func - self._sts_endpoint = sts_endpoint - self._duration_seconds = duration_seconds - self._policy = policy - self._role_arn = role_arn - self._role_session_name = role_session_name - self._http_client = http_client or PoolManager( - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504], - ), - ) - self._credentials: Optional[Credentials] = None - - @abstractmethod - def _is_web_identity(self) -> bool: - """Check if derived class deal with WebIdentity.""" - - def _get_duration_seconds(self, expiry: int) -> int: - """Get DurationSeconds optimal value.""" - - if self._duration_seconds: - expiry = self._duration_seconds - - if expiry > _MAX_DURATION_SECONDS: - return _MAX_DURATION_SECONDS - - if expiry <= 0: - return expiry - - return ( - _MIN_DURATION_SECONDS if expiry < _MIN_DURATION_SECONDS else expiry - ) - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - jwt = self._jwt_provider_func() - - query_params = {"Version": "2011-06-15"} - duration_seconds = self._get_duration_seconds( - int(jwt.get("expires_in", "0")), - ) - if duration_seconds: - query_params["DurationSeconds"] = str(duration_seconds) - if self._policy: - query_params["Policy"] = self._policy - - access_token = jwt.get("access_token") or jwt.get("id_token", "") - if self._is_web_identity(): - query_params["Action"] = "AssumeRoleWithWebIdentity" - query_params["WebIdentityToken"] = access_token - if self._role_arn: - query_params["RoleArn"] = self._role_arn - query_params["RoleSessionName"] = ( - self._role_session_name - if self._role_session_name - else str(time.time()).replace(".", "") - ) - else: - query_params["Action"] = "AssumeRoleWithClientGrants" - query_params["Token"] = access_token - - url = self._sts_endpoint + "?" + urlencode(query_params) - res = _urlopen(self._http_client, "POST", url) - - self._credentials = _parse_credentials( - res.data.decode(), - ( - "AssumeRoleWithWebIdentityResult" - if self._is_web_identity() - else "AssumeRoleWithClientGrantsResult" - ), - ) - - return self._credentials - - -class ClientGrantsProvider(WebIdentityClientGrantsProvider): - """Credential provider using AssumeRoleWithClientGrants API.""" - - def __init__( - self, - *, - jwt_provider_func: Callable[[], dict[str, str]], - sts_endpoint: str, - duration_seconds: int = 0, - policy: Optional[str] = None, - http_client: Optional[PoolManager] = None, - ): - super().__init__( - jwt_provider_func=jwt_provider_func, - sts_endpoint=sts_endpoint, - duration_seconds=duration_seconds, - policy=policy, - http_client=http_client, - ) - - def _is_web_identity(self) -> bool: - return False - - -class WebIdentityProvider(WebIdentityClientGrantsProvider): - """Credential provider using AssumeRoleWithWebIdentity API.""" - - def _is_web_identity(self) -> bool: - return True - - -class CertificateIdentityProvider(Provider): - """Credential provider using AssumeRoleWithCertificate API.""" - - def __init__( - self, - *, - sts_endpoint: str, - cert_file: Optional[str] = None, - key_file: Optional[str] = None, - key_password: Optional[str] = None, - ca_certs: Optional[str] = None, - duration_seconds: int = 0, - http_client: Optional[PoolManager] = None, - ): - if urlsplit(sts_endpoint).scheme != "https": - raise ValueError("STS endpoint scheme must be HTTPS") - - if not bool(http_client) != (cert_file and key_file): - raise ValueError( - "either cert/key file or custom http_client must be provided", - ) - - self._sts_endpoint = sts_endpoint + "?" + urlencode( - { - "Action": "AssumeRoleWithCertificate", - "Version": "2011-06-15", - "DurationSeconds": str( - duration_seconds - if duration_seconds > _DEFAULT_DURATION_SECONDS - else _DEFAULT_DURATION_SECONDS - ), - }, - ) - self._http_client = http_client or PoolManager( - maxsize=10, - cert_file=cert_file, - cert_reqs='CERT_REQUIRED', - key_file=key_file, - key_password=key_password, - ca_certs=ca_certs or certifi.where(), - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504], - ), - ) - self._credentials: Optional[Credentials] = None - - def retrieve(self) -> Credentials: - """Retrieve credentials.""" - - if self._credentials and not self._credentials.is_expired(): - return self._credentials - - res = _urlopen( - self._http_client, - "POST", - self._sts_endpoint, - ) - - self._credentials = _parse_credentials( - res.data.decode(), "AssumeRoleWithCertificateResult", - ) - - return self._credentials diff --git a/backend/venv39/lib/python3.9/site-packages/minio/crypto.py b/backend/venv39/lib/python3.9/site-packages/minio/crypto.py deleted file mode 100644 index 614f856..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/crypto.py +++ /dev/null @@ -1,251 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2015, 2016, 2017 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Cryptography to read and write encrypted MinIO Admin payload""" - -from __future__ import absolute_import, annotations - -import os - -from argon2.low_level import Type, hash_secret_raw -from Crypto.Cipher import AES, ChaCha20_Poly1305 -from Crypto.Cipher._mode_gcm import GcmMode -from Crypto.Cipher.ChaCha20_Poly1305 import ChaCha20Poly1305Cipher - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -# -# Encrypted Message Format: -# -# | 41 bytes HEADER | -# |-------------------------| -# | 16 KiB encrypted chunk | -# | + 16 bytes TAG | -# |-------------------------| -# | .... | -# |-------------------------| -# | ~16 KiB encrypted chunk | -# | + 16 bytes TAG | -# |-------------------------| -# -# HEADER: -# -# | 32 bytes salt | -# |----------------| -# | 1 byte AEAD ID | -# |----------------| -# | 8 bytes NONCE | -# |----------------| -# - - -_TAG_LEN = 16 -_CHUNK_SIZE = 16 * 1024 -_MAX_CHUNK_SIZE = _TAG_LEN + _CHUNK_SIZE -_SALT_LEN = 32 -_NONCE_LEN = 8 - - -def _get_cipher( - aead_id: int, - key: bytes, - nonce: bytes, -) -> GcmMode | ChaCha20Poly1305Cipher: - """Get cipher for AEAD ID.""" - if aead_id == 0: - return AES.new(key, AES.MODE_GCM, nonce) - if aead_id == 1: - return ChaCha20_Poly1305.new(key=key, nonce=nonce) - raise ValueError(f"Unknown AEAD ID {aead_id}") - - -def _generate_key(secret: bytes, salt: bytes) -> bytes: - """Generate 256-bit Argon2ID key""" - return hash_secret_raw( - secret=secret, - salt=salt, - time_cost=1, - memory_cost=65536, - parallelism=4, - hash_len=32, - type=Type.ID, - version=19, - ) - - -def _generate_additional_data( - aead_id: int, key: bytes, padded_nonce: bytes -) -> bytes: - """Generate additional data""" - cipher = _get_cipher(aead_id, key, padded_nonce) - return b"\x00" + cipher.digest() - - -def _mark_as_last(additional_data: bytes) -> bytes: - """Mark additional data as the last in the sequence""" - return b'\x80' + additional_data[1:] - - -def _update_nonce_id(nonce: bytes, idx: int) -> bytes: - """Set nonce id (4 last bytes)""" - return nonce + idx.to_bytes(4, byteorder="little") - - -def encrypt(payload: bytes, password: str) -> bytes: - """Encrypt given payload.""" - nonce = os.urandom(_NONCE_LEN) - salt = os.urandom(_SALT_LEN) - key = _generate_key(password.encode(), salt) - aead_id = b"\x00" - padded_nonce = nonce + b"\x00\x00\x00\x00" - additional_data = _generate_additional_data(aead_id[0], key, padded_nonce) - - indices = range(0, len(payload), _CHUNK_SIZE) - nonce_id = 0 - result = salt + aead_id + nonce - for i in indices: - nonce_id += 1 - if i == indices[-1]: - additional_data = _mark_as_last(additional_data) - padded_nonce = _update_nonce_id(nonce, nonce_id) - cipher = _get_cipher(aead_id[0], key, padded_nonce) - cipher.update(additional_data) - encrypted_data, hmac_tag = cipher.encrypt_and_digest( - payload[i:i+_CHUNK_SIZE], - ) - - result += encrypted_data - result += hmac_tag - - return result - - -class DecryptReader: - """ - BufferedIOBase compatible reader represents decrypted data of MinioAdmin - APIs. - """ - - def __init__(self, response: BaseHTTPResponse, secret: bytes): - self._response = response - self._secret = secret - self._payload = None - - header = self._response.read(41) - if len(header) != 41: - raise IOError("insufficient data") - self._salt = header[:32] - self._aead_id = header[32] - self._nonce = header[33:] - self._key = _generate_key(self._secret, self._salt) - padded_nonce = self._nonce + b"\x00\x00\x00\x00" - self._additional_data = _generate_additional_data( - self._aead_id, self._key, padded_nonce - ) - self._chunk = b"" - self._count = 0 - self._is_closed = False - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_traceback): - return self.close() - - def readable(self): # pylint: disable=no-self-use - """Return this is readable.""" - return True - - def writeable(self): # pylint: disable=no-self-use - """Return this is not writeable.""" - return False - - def close(self): - """Close response and release network resources.""" - self._response.close() - self._response.release_conn() - - def _decrypt(self, payload: bytes, last_chunk: bool = False) -> bytes: - """Decrypt given payload.""" - self._count += 1 - if last_chunk: - self._additional_data = _mark_as_last(self._additional_data) - - padded_nonce = _update_nonce_id(self._nonce, self._count) - cipher = _get_cipher(self._aead_id, self._key, padded_nonce) - cipher.update(self._additional_data) - - hmac_tag = payload[-_TAG_LEN:] - encrypted_data = payload[:-_TAG_LEN] - decrypted_data = cipher.decrypt_and_verify(encrypted_data, hmac_tag) - return decrypted_data - - def _read_chunk(self) -> bool: - """Read a chunk at least one byte more than chunk size.""" - if self._is_closed: - return True - - while len(self._chunk) != (1 + _MAX_CHUNK_SIZE): - chunk = self._response.read(1 + _MAX_CHUNK_SIZE - len(self._chunk)) - self._chunk += chunk - if len(chunk) == 0: - self._is_closed = True - return True - - return False - - def _read(self) -> bytes: - """Read and decrypt response.""" - stop = self._read_chunk() - - if len(self._chunk) == 0: - return self._chunk - - length = _MAX_CHUNK_SIZE - if len(self._chunk) < length: - length = len(self._chunk) - stop = True - payload = self._chunk[:length] - self._chunk = self._chunk[length:] - return self._decrypt(payload, stop) - - def stream(self, num_bytes=32*1024): - """ - Stream extracted payload from response data. Upon completion, caller - should call self.close() to release network resources. - """ - while True: - data = self._read() - if not data: - break - while data: - result = data - if num_bytes < len(data): - result = data[:num_bytes] - data = data[len(result):] - yield result - - -def decrypt(response: BaseHTTPResponse, secret_key: str) -> bytes: - """Decrypt response data.""" - result = b"" - with DecryptReader(response, secret_key.encode()) as reader: - for data in reader.stream(): - result += data - return result diff --git a/backend/venv39/lib/python3.9/site-packages/minio/datatypes.py b/backend/venv39/lib/python3.9/site-packages/minio/datatypes.py deleted file mode 100644 index 0b6f030..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/datatypes.py +++ /dev/null @@ -1,799 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=too-many-lines - -""" -Response of ListBuckets, ListObjects, ListObjectsV2 and ListObjectVersions API. -""" - -from __future__ import absolute_import, annotations - -import base64 -import json -from collections import OrderedDict -from dataclasses import dataclass, field -from datetime import datetime -from enum import Enum -from typing import Any, List, Optional, Tuple, Type, TypeVar, Union, cast -from urllib.parse import unquote_plus -from xml.etree import ElementTree as ET - -from urllib3._collections import HTTPHeaderDict - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -from .commonconfig import Tags -from .credentials import Credentials -from .helpers import check_bucket_name -from .signer import get_credential_string, post_presign_v4 -from .time import from_iso8601utc, to_amz_date, to_iso8601utc -from .xml import find, findall, findtext - -JSONDecodeError: type[ValueError] -try: - from json.decoder import JSONDecodeError -except ImportError: - JSONDecodeError = ValueError - - -@dataclass(frozen=True) -class Bucket: - """Bucket information.""" - name: str - creation_date: Optional[datetime] - - -A = TypeVar("A", bound="ListAllMyBucketsResult") - - -@dataclass(frozen=True) -class ListAllMyBucketsResult: - """LissBuckets API result.""" - buckets: list[Bucket] - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Buckets", True)) - buckets = [] - elements = findall(element, "Bucket") - for bucket in elements: - name = cast(str, findtext(bucket, "Name", True)) - creation_date = findtext(bucket, "CreationDate") - buckets.append(Bucket( - name, - from_iso8601utc(creation_date) if creation_date else None, - )) - return cls(buckets) - - -B = TypeVar("B", bound="Object") - - -@dataclass(frozen=True) -class Object: - """Object information.""" - bucket_name: str - object_name: Optional[str] - last_modified: Optional[datetime] = None - etag: Optional[str] = None - size: Optional[int] = None - metadata: Optional[Union[dict[str, str], HTTPHeaderDict]] = None - version_id: Optional[str] = None - is_latest: Optional[str] = None - storage_class: Optional[str] = None - owner_id: Optional[str] = None - owner_name: Optional[str] = None - content_type: Optional[str] = None - is_delete_marker: bool = False - tags: Optional[Tags] = None - is_dir: bool = field(default=False, init=False) - - def __post_init__(self): - object.__setattr__( - self, - "is_dir", - bool(self.object_name and self.object_name.endswith("/")), - ) - - @classmethod - def fromxml( - cls: Type[B], - element: ET.Element, - bucket_name: str, - is_delete_marker: bool = False, - encoding_type: Optional[str] = None, - ) -> B: - """Create new object with values from XML element.""" - tag = findtext(element, "LastModified") - last_modified = None if tag is None else from_iso8601utc(tag) - - tag = findtext(element, "ETag") - etag = None if tag is None else tag.replace('"', "") - - tag = findtext(element, "Size") - size = None if tag is None else int(tag) - - elem = find(element, "Owner") - owner_id, owner_name = ( - (None, None) if elem is None - else (findtext(elem, "ID"), findtext(elem, "DisplayName")) - ) - - elems: ET.Element | list = find(element, "UserMetadata") or [] - metadata: dict[str, str] = {} - for child in elems: - key = child.tag.split("}")[1] if "}" in child.tag else child.tag - metadata[key] = child.text or "" - - object_name = cast(str, findtext(element, "Key", True)) - if encoding_type == "url": - object_name = unquote_plus(object_name) - - tags_text = findtext(element, "UserTags") - tags: Optional[Tags] = None - if tags_text: - tags = Tags.new_object_tags() - tags.update( - cast( - List[Tuple[Any, Any]], - [tokens.split("=") for tokens in tags_text.split("&")], - ), - ) - - return cls( - bucket_name=bucket_name, - object_name=object_name, - last_modified=last_modified, - etag=etag, - size=size, - version_id=findtext(element, "VersionId"), - is_latest=findtext(element, "IsLatest"), - storage_class=findtext(element, "StorageClass"), - owner_id=owner_id, - owner_name=owner_name, - metadata=metadata, - is_delete_marker=is_delete_marker, - tags=tags - ) - - -def parse_list_objects( - response: BaseHTTPResponse, - bucket_name: Optional[str] = None, -) -> tuple[list[Object], bool, Optional[str], Optional[str]]: - """Parse ListObjects/ListObjectsV2/ListObjectVersions response.""" - element = ET.fromstring(response.data.decode()) - bucket_name = cast(str, findtext(element, "Name", True)) - encoding_type = findtext(element, "EncodingType") - elements = findall(element, "Contents") - objects = [ - Object.fromxml(tag, bucket_name, encoding_type=encoding_type) - for tag in elements - ] - marker = objects[-1].object_name if objects else None - - elements = findall(element, "Version") - objects += [ - Object.fromxml(tag, bucket_name, encoding_type=encoding_type) - for tag in elements - ] - - elements = findall(element, "CommonPrefixes") - objects += [ - Object( - bucket_name, unquote_plus(findtext(tag, "Prefix", True) or "") - if encoding_type == "url" else findtext(tag, "Prefix", True) - ) for tag in elements - ] - - elements = findall(element, "DeleteMarker") - objects += [ - Object.fromxml(tag, bucket_name, is_delete_marker=True, - encoding_type=encoding_type) - for tag in elements - ] - - is_truncated = (findtext(element, "IsTruncated") or "").lower() == "true" - key_marker = findtext(element, "NextKeyMarker") - if key_marker and encoding_type == "url": - key_marker = unquote_plus(key_marker) - version_id_marker = findtext(element, "NextVersionIdMarker") - continuation_token = findtext(element, "NextContinuationToken") - if key_marker is not None: - continuation_token = key_marker - if continuation_token is None: - continuation_token = findtext(element, "NextMarker") - if continuation_token and encoding_type == "url": - continuation_token = unquote_plus(continuation_token) - if continuation_token is None and is_truncated: - continuation_token = marker - return objects, is_truncated, continuation_token, version_id_marker - - -@dataclass(frozen=True) -class CompleteMultipartUploadResult: - """CompleteMultipartUpload API result.""" - - http_headers: HTTPHeaderDict - bucket_name: Optional[str] = None - object_name: Optional[str] = None - location: Optional[str] = None - etag: Optional[str] = None - version_id: Optional[str] = None - - def __init__(self, response: BaseHTTPResponse): - object.__setattr__(self, "http_headers", response.headers) - element = ET.fromstring(response.data.decode()) - object.__setattr__(self, "bucket_name", findtext(element, "Bucket")) - object.__setattr__(self, "object_name", findtext(element, "Key")) - object.__setattr__(self, "location", findtext(element, "Location")) - etag = findtext(element, "ETag") - if etag: - object.__setattr__( - self, - "etag", - cast(str, etag).replace('"', ""), - ) - object.__setattr__( - self, - "version_id", - response.headers.get("x-amz-version-id"), - ) - - -C = TypeVar("C", bound="Part") - - -@dataclass(frozen=True) -class Part: - """Part information of a multipart upload.""" - part_number: int - etag: str - last_modified: Optional[datetime] = None - size: Optional[int] = None - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - part_number = int(cast(str, findtext(element, "PartNumber", True))) - etag = cast(str, findtext(element, "ETag", True)) - etag = etag.replace('"', "") - tag = findtext(element, "LastModified") - last_modified = None if tag is None else from_iso8601utc(tag) - size = findtext(element, "Size") - return cls( - part_number=part_number, - etag=etag, - last_modified=last_modified, - size=int(size) if size else None, - ) - - -@dataclass(frozen=True) -class ListPartsResult: - """ListParts API result.""" - - bucket_name: Optional[str] = None - object_name: Optional[str] = None - initiator_id: Optional[str] = None - initiator_name: Optional[str] = None - owner_id: Optional[str] = None - owner_name: Optional[str] = None - storage_class: Optional[str] = None - part_number_marker: Optional[str] = None - next_part_number_marker: Optional[str] = None - max_parts: Optional[int] = None - is_truncated: bool = False - parts: list[Part] = field(default_factory=list) - - def __init__(self, response: BaseHTTPResponse): - element = ET.fromstring(response.data.decode()) - object.__setattr__(self, "bucket_name", findtext(element, "Bucket")) - object.__setattr__(self, "object_name", findtext(element, "Key")) - tag = find(element, "Initiator") - object.__setattr__( - self, - "initiator_id", - None if tag is None else findtext(tag, "ID"), - ) - object.__setattr__( - self, - "initiator_name", - None if tag is None else findtext(tag, "DisplayName"), - ) - tag = find(element, "Owner") - object.__setattr__( - self, - "owner_id", - None if tag is None else findtext(tag, "ID") - ) - object.__setattr__( - self, - "owner_name", - None if tag is None else findtext(tag, "DisplayName"), - ) - object.__setattr__( - self, - "storage_class", - findtext(element, "StorageClass"), - ) - object.__setattr__( - self, - "part_number_marker", - findtext(element, "PartNumberMarker"), - ) - object.__setattr__( - self, - "next_part_number_marker", - findtext(element, "NextPartNumberMarker"), - ) - max_parts = findtext(element, "MaxParts") - object.__setattr__( - self, - "max_parts", - int(max_parts) if max_parts else None, - ) - is_truncated = findtext(element, "IsTruncated") - object.__setattr__( - self, - "is_truncated", - is_truncated is not None and is_truncated.lower() == "true", - ) - object.__setattr__( - self, - "parts", - [Part.fromxml(tag) for tag in findall(element, "Part")], - ) - - -@dataclass(frozen=True) -class Upload: - """ Upload information of a multipart upload.""" - - object_name: str - encoding_type: Optional[str] = None - upload_id: Optional[str] = None - initiator_id: Optional[str] = None - initiator_name: Optional[str] = None - owner_id: Optional[str] = None - owner_name: Optional[str] = None - storage_class: Optional[str] = None - initiated_time: Optional[datetime] = None - - def __init__( - self, element: ET.Element, encoding_type: Optional[str] = None, - ): - object_name = cast(str, findtext(element, "Key", True)) - object.__setattr__( - self, - "object_name", - unquote_plus(object_name) if encoding_type == "url" - else object_name, - ) - object.__setattr__(self, "encoding_type", encoding_type) - object.__setattr__(self, "upload_id", findtext(element, "UploadId")) - tag = find(element, "Initiator") - object.__setattr__( - self, - "initiator_id", - None if tag is None else findtext(tag, "ID"), - ) - object.__setattr__( - self, - "initiator_name", - None if tag is None else findtext(tag, "DisplayName"), - ) - tag = find(element, "Owner") - object.__setattr__( - self, - "owner_id", - None if tag is None else findtext(tag, "ID"), - ) - object.__setattr__( - self, - "owner_name", - None if tag is None else findtext(tag, "DisplayName"), - ) - object.__setattr__( - self, - "storage_class", - findtext(element, "StorageClass"), - ) - initiated_time = findtext(element, "Initiated") - object.__setattr__( - self, - "initiated_time", - from_iso8601utc(initiated_time) if initiated_time else None, - ) - - -@dataclass(frozen=True) -class ListMultipartUploadsResult: - """ListMultipartUploads API result.""" - - encoding_type: Optional[str] = None - bucket_name: Optional[str] = None - key_marker: Optional[str] = None - upload_id_marker: Optional[str] = None - next_key_marker: Optional[str] = None - next_upload_id_marker: Optional[str] = None - max_uploads: Optional[int] = None - is_truncated: bool = False - uploads: list[Upload] = field(default_factory=list) - - def __init__(self, response: BaseHTTPResponse): - element = ET.fromstring(response.data.decode()) - encoding_type = findtext(element, "EncodingType") - object.__setattr__(self, "encoding_type", encoding_type) - object.__setattr__( - self, - "bucket_name", - findtext(element, "Bucket"), - ) - value = findtext(element, "KeyMarker") - if value is not None and encoding_type == "url": - value = unquote_plus(value) - object.__setattr__(self, "key_marker", value) - object.__setattr__( - self, - "upload_id_marker", - findtext(element, "UploadIdMarker"), - ) - value = findtext(element, "NextKeyMarker") - if value is not None and encoding_type == "url": - value = unquote_plus(value) - object.__setattr__(self, "next_key_marker", value) - object.__setattr__( - self, - "self._next_upload_id_marker", - findtext(element, "NextUploadIdMarker"), - ) - max_uploads = findtext(element, "MaxUploads") - object.__setattr__( - self, - "max_uploads", - int(max_uploads) if max_uploads else None, - ) - is_truncated = findtext(element, "IsTruncated") - object.__setattr__( - self, - "is_truncated", - is_truncated is not None and is_truncated.lower() == "true", - ) - object.__setattr__( - self, - "uploads", - [ - Upload(tag, encoding_type) - for tag in findall(element, "Upload") - ], - ) - - -_RESERVED_ELEMENTS = ( - "bucket", - "x-amz-algorithm", - "x-amz-credential", - "x-amz-date", - "policy", - "x-amz-signature", -) -_EQ = "eq" -_STARTS_WITH = "starts-with" -_ALGORITHM = "AWS4-HMAC-SHA256" - - -def _trim_dollar(value: str) -> str: - """Trim dollar character if present.""" - return value[1:] if value.startswith("$") else value - - -class PostPolicy: - """ - Post policy information to be used to generate presigned post policy - form-data. Condition elements and respective condition for Post policy - is available at - https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions - """ - - def __init__(self, bucket_name: str, expiration: datetime): - check_bucket_name(bucket_name) - if not isinstance(expiration, datetime): - raise ValueError("expiration must be datetime type") - self._bucket_name = bucket_name - self._expiration = expiration - self._conditions: OrderedDict = OrderedDict() - self._conditions[_EQ] = OrderedDict() - self._conditions[_STARTS_WITH] = OrderedDict() - self._lower_limit: Optional[int] = None - self._upper_limit: Optional[int] = None - - def add_equals_condition(self, element: str, value: str): - """Add equals condition of an element and value.""" - if not element: - raise ValueError("condition element cannot be empty") - element = _trim_dollar(element) - if ( - element in [ - "success_action_redirect", - "redirect", - "content-length-range", - ] - ): - raise ValueError(element + " is unsupported for equals condition") - if element in _RESERVED_ELEMENTS: - raise ValueError(element + " cannot be set") - self._conditions[_EQ][element] = value - - def remove_equals_condition(self, element: str): - """Remove previously set equals condition of an element.""" - if not element: - raise ValueError("condition element cannot be empty") - self._conditions[_EQ].pop(element) - - def add_starts_with_condition(self, element: str, value: str): - """ - Add starts-with condition of an element and value. Value set to empty - string does matching any content condition. - """ - if not element: - raise ValueError("condition element cannot be empty") - element = _trim_dollar(element) - if ( - element in ["success_action_status", "content-length-range"] or - ( - element.startswith("x-amz-") and - not element.startswith("x-amz-meta-") - ) - ): - raise ValueError( - f"{element} is unsupported for starts-with condition", - ) - if element in _RESERVED_ELEMENTS: - raise ValueError(element + " cannot be set") - self._conditions[_STARTS_WITH][element] = value - - def remove_starts_with_condition(self, element: str): - """Remove previously set starts-with condition of an element.""" - if not element: - raise ValueError("condition element cannot be empty") - self._conditions[_STARTS_WITH].pop(element) - - def add_content_length_range_condition( # pylint: disable=invalid-name - self, lower_limit: int, upper_limit: int): - """Add content-length-range condition with lower and upper limits.""" - if lower_limit < 0: - raise ValueError("lower limit cannot be negative number") - if upper_limit < 0: - raise ValueError("upper limit cannot be negative number") - if lower_limit > upper_limit: - raise ValueError("lower limit cannot be greater than upper limit") - self._lower_limit = lower_limit - self._upper_limit = upper_limit - - def remove_content_length_range_condition( # pylint: disable=invalid-name - self): - """Remove previously set content-length-range condition.""" - self._lower_limit = None - self._upper_limit = None - - def form_data(self, creds: Credentials, region: str): - """ - Return form-data of this post policy. The returned dict contains - x-amz-algorithm, x-amz-credential, x-amz-security-token, x-amz-date, - policy and x-amz-signature. - """ - if not isinstance(creds, Credentials): - raise ValueError("credentials must be Credentials type") - if not region: - raise ValueError("region cannot be empty") - if ( - "key" not in self._conditions[_EQ] and - "key" not in self._conditions[_STARTS_WITH] - ): - raise ValueError("key condition must be set") - - policy: OrderedDict = OrderedDict() - policy["expiration"] = to_iso8601utc(self._expiration) - policy["conditions"] = [[_EQ, "$bucket", self._bucket_name]] - for cond_key, conditions in self._conditions.items(): - for key, value in conditions.items(): - policy["conditions"].append([cond_key, "$"+key, value]) - if self._lower_limit is not None and self._upper_limit is not None: - policy["conditions"].append( - ["content-length-range", self._lower_limit, self._upper_limit], - ) - utcnow = datetime.utcnow() - credential = get_credential_string(creds.access_key, utcnow, region) - amz_date = to_amz_date(utcnow) - policy["conditions"].append([_EQ, "$x-amz-algorithm", _ALGORITHM]) - policy["conditions"].append([_EQ, "$x-amz-credential", credential]) - if creds.session_token: - policy["conditions"].append( - [_EQ, "$x-amz-security-token", creds.session_token], - ) - policy["conditions"].append([_EQ, "$x-amz-date", amz_date]) - - policy_encoded = base64.b64encode( - json.dumps(policy).encode(), - ).decode("utf-8") - signature = post_presign_v4( - policy_encoded, creds.secret_key, utcnow, region, - ) - form_data = { - "x-amz-algorithm": _ALGORITHM, - "x-amz-credential": credential, - "x-amz-date": amz_date, - "policy": policy_encoded, - "x-amz-signature": signature, - } - if creds.session_token: - form_data["x-amz-security-token"] = creds.session_token - return form_data - - @property - def bucket_name(self) -> str: - """Get bucket name.""" - return self._bucket_name - - -def parse_copy_object( - response: BaseHTTPResponse, -) -> tuple[str, Optional[datetime]]: - """Parse CopyObject/UploadPartCopy response.""" - element = ET.fromstring(response.data.decode()) - etag = cast(str, findtext(element, "ETag", True)).replace('"', "") - last_modified = findtext(element, "LastModified") - return etag, from_iso8601utc(last_modified) if last_modified else None - - -class EventIterable: - """Context manager friendly event iterable.""" - - def __init__(self, func): - self._func = func - self._response = None - - def _close_response(self): - """Close response.""" - if self._response: - self._response.close() - self._response.release_conn() - self._response = None - - def __iter__(self): - return self - - def _get_records(self): - """Get event records from response stream.""" - try: - line = self._response.readline().strip() - if not line: - return None - if hasattr(line, 'decode'): - line = line.decode() - event = json.loads(line) - if event['Records']: - return event - except (StopIteration, JSONDecodeError): - self._close_response() - return None - - def __next__(self): - records = None - while not records: - if not self._response or self._response.closed: - self._response = self._func() - records = self._get_records() - return records - - def __enter__(self): - return self - - def __exit__(self, exc_type, value, traceback): - self._close_response() - - -@dataclass(frozen=True) -class PeerSite: - """Represents a cluster/site to be added to the set of replicated sites.""" - name: str - endpoint: str - access_key: str - secret_key: str - - def to_dict(self) -> dict[str, str]: - """Convert to dictionary.""" - return { - "name": self.name, - "endpoints": self.endpoint, - "accessKey": self.access_key, - "secretKey": self.secret_key, - } - - -@dataclass(frozen=True) -class SiteReplicationStatusOptions: - """Represents site replication status options.""" - ENTITY_TYPE = Enum( - "ENTITY_TYPE", - { - "BUCKET": "bucket", - "POLICY": "policy", - "USER": "user", - "GROUP": "group", - }, - ) - buckets: bool = False - policies: bool = False - users: bool = False - groups: bool = False - metrics: bool = False - show_deleted: bool = False - entity: Optional[str] = None - entity_value: Optional[str] = None - - def to_query_params(self) -> dict[str, str]: - """Convert this options to query parameters.""" - params = { - "buckets": str(self.buckets).lower(), - "policies": str(self.policies).lower(), - "users": str(self.users).lower(), - "groups": str(self.groups).lower(), - "metrics": str(self.metrics).lower(), - "showDeleted": str(self.show_deleted).lower(), - } - if self.entity and self.entity_value: - params["entity"] = self.entity - params["entityvalue"] = self.entity_value - return params - - -@dataclass(frozen=True) -class PeerInfo: - """Site replication peer information.""" - deployment_id: str - endpoint: str - bucket_bandwidth_limit: str - bucket_bandwidth_set: str - name: Optional[str] = None - sync_status: Optional[str] = None - bucket_bandwidth_updated_at: Optional[datetime] = None - - def to_dict(self): - """Converts peer information to dictionary.""" - data = { - "endpoint": self.endpoint, - "deploymentID": self.deployment_id, - "defaultbandwidth": { - "bandwidthLimitPerBucket": self.bucket_bandwidth_limit, - "set": self.bucket_bandwidth_set, - }, - } - if self.name: - data["name"] = self.name - if self.sync_status is not None: - data["sync"] = "enable" if self.sync_status else "disable" - if self.bucket_bandwidth_updated_at: - data["defaultbandwidth"]["updatedAt"] = to_iso8601utc( - self.bucket_bandwidth_updated_at, - ) - return data diff --git a/backend/venv39/lib/python3.9/site-packages/minio/deleteobjects.py b/backend/venv39/lib/python3.9/site-packages/minio/deleteobjects.py deleted file mode 100644 index d323631..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/deleteobjects.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of DeleteObjects API.""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .xml import Element, SubElement, findall, findtext - - -@dataclass(frozen=True) -class DeleteObject: - """Delete object request information.""" - - name: str - version_id: Optional[str] = None - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Object") - SubElement(element, "Key", self.name) - if self.version_id is not None: - SubElement(element, "VersionId", self.version_id) - return element - - -@dataclass(frozen=True) -class DeleteRequest: - """Delete object request.""" - - object_list: list[DeleteObject] - quiet: bool = False - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("Delete") - if self.quiet: - SubElement(element, "Quiet", "true") - for obj in self.object_list: - obj.toxml(element) - return element - - -A = TypeVar("A", bound="DeletedObject") - - -@dataclass(frozen=True) -class DeletedObject: - """Deleted object information.""" - - name: str - version_id: Optional[str] - delete_marker: bool - delete_marker_version_id: Optional[str] - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - name = cast(str, findtext(element, "Key", True)) - version_id = findtext(element, "VersionId") - delete_marker = findtext(element, "DeleteMarker") - delete_marker_version_id = findtext(element, "DeleteMarkerVersionId") - return cls( - name=name, - version_id=version_id, - delete_marker=( - delete_marker is not None and delete_marker.title() == "True" - ), - delete_marker_version_id=delete_marker_version_id, - ) - - -B = TypeVar("B", bound="DeleteError") - - -@dataclass(frozen=True) -class DeleteError: - """Delete error information.""" - - code: str - message: Optional[str] - name: Optional[str] - version_id: Optional[str] - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - code = cast(str, findtext(element, "Code", True)) - message = findtext(element, "Message") - name = findtext(element, "Key") - version_id = findtext(element, "VersionId") - return cls( - code=code, - message=message, - name=name, - version_id=version_id, - ) - - -C = TypeVar("C", bound="DeleteResult") - - -@dataclass(frozen=True) -class DeleteResult: - """Delete object result.""" - - object_list: list[DeletedObject] - error_list: list[DeleteError] - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - elements = findall(element, "Deleted") - object_list = [] - for tag in elements: - object_list.append(DeletedObject.fromxml(tag)) - elements = findall(element, "Error") - error_list = [] - for tag in elements: - error_list.append(DeleteError.fromxml(tag)) - return cls(object_list=object_list, error_list=error_list) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/error.py b/backend/venv39/lib/python3.9/site-packages/minio/error.py deleted file mode 100644 index fd169be..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/error.py +++ /dev/null @@ -1,226 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2015-2019 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=too-many-lines - -""" -minio.error -~~~~~~~~~~~~~~~~~~~ - -This module provides custom exception classes for MinIO library -and API specific errors. - -:copyright: (c) 2015, 2016, 2017 by MinIO, Inc. -:license: Apache 2.0, see LICENSE for more details. - -""" - -from __future__ import absolute_import, annotations - -from typing import Optional, Type, TypeVar -from xml.etree import ElementTree as ET - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -from .xml import findtext - - -class MinioException(Exception): - """Base Minio exception.""" - - -class InvalidResponseError(MinioException): - """Raised to indicate that non-xml response from server.""" - - def __init__( - self, code: int, content_type: Optional[str], body: Optional[str], - ): - self._code = code - self._content_type = content_type - self._body = body - super().__init__( - f"non-XML response from server; Response code: {code}, " - f"Content-Type: {content_type}, Body: {body}" - ) - - def __reduce__(self): - return type(self), (self._code, self._content_type, self._body) - - -class ServerError(MinioException): - """Raised to indicate that S3 service returning HTTP server error.""" - - def __init__(self, message: str, status_code: int): - self._status_code = status_code - super().__init__(message) - - @property - def status_code(self) -> int: - """Get HTTP status code.""" - return self._status_code - - -A = TypeVar("A", bound="S3Error") - - -class S3Error(MinioException): - """ - Raised to indicate that error response is received - when executing S3 operation. - """ - response: BaseHTTPResponse - code: Optional[str] - message: Optional[str] - resource: Optional[str] - request_id: Optional[str] - host_id: Optional[str] - bucket_name: Optional[str] - object_name: Optional[str] - - _EXC_MUTABLES = {"__traceback__", "__context__", "__cause__"} - - def __init__( # pylint: disable=too-many-positional-arguments - self, - response: BaseHTTPResponse, - code: Optional[str], - message: Optional[str], - resource: Optional[str], - request_id: Optional[str], - host_id: Optional[str], - bucket_name: Optional[str] = None, - object_name: Optional[str] = None, - ): - object.__setattr__(self, "response", response) - object.__setattr__(self, "code", code) - object.__setattr__(self, "message", message) - object.__setattr__(self, "resource", resource) - object.__setattr__(self, "request_id", request_id) - object.__setattr__(self, "host_id", host_id) - object.__setattr__(self, "bucket_name", bucket_name) - object.__setattr__(self, "object_name", object_name) - - bucket_message = f", bucket_name: {bucket_name}" if bucket_name else "" - object_message = f", object_name: {object_name}" if object_name else "" - - super().__init__( - f"S3 operation failed; code: {code}, message: {message}, " - f"resource: {resource}, request_id: {request_id}, " - f"host_id: {host_id}{bucket_message}{object_message}" - ) - - # freeze after init - object.__setattr__(self, "_is_frozen", True) - - def __setattr__(self, name, value): - if name in self._EXC_MUTABLES: - object.__setattr__(self, name, value) - return - if getattr(self, "_is_frozen", False): - raise AttributeError( - f"{self.__class__.__name__} is frozen and " - "does not allow attribute assignment" - ) - object.__setattr__(self, name, value) - - def __delattr__(self, name): - if name in self._EXC_MUTABLES: - object.__delattr__(self, name) - return - if getattr(self, "_is_frozen", False): - raise AttributeError( - f"{self.__class__.__name__} is frozen and " - "does not allow attribute deletion" - ) - object.__delattr__(self, name) - - @classmethod - def fromxml(cls: Type[A], response: BaseHTTPResponse) -> A: - """Create new object with values from XML element.""" - element = ET.fromstring(response.data.decode()) - return cls( - response=response, - code=findtext(element, "Code"), - message=findtext(element, "Message"), - resource=findtext(element, "Resource"), - request_id=findtext(element, "RequestId"), - host_id=findtext(element, "HostId"), - bucket_name=findtext(element, "BucketName"), - object_name=findtext(element, "Key"), - ) - - def copy(self, code: str, message: str) -> S3Error: - """Make a copy with replaced code and message.""" - return S3Error( - response=self.response, - code=code, - message=message, - resource=self.resource, - request_id=self.request_id, - host_id=self.host_id, - bucket_name=self.bucket_name, - object_name=self.object_name, - ) - - def __repr__(self): - return ( - f"S3Error(code={self.code!r}, message={self.message!r}, " - f"resource={self.resource!r}, request_id={self.request_id!r}, " - f"host_id={self.host_id!r}, bucket_name={self.bucket_name!r}, " - f"object_name={self.object_name!r})" - ) - - def __eq__(self, other): - if not isinstance(other, S3Error): - return NotImplemented - return ( - self.code == other.code - and self.message == other.message - and self.resource == other.resource - and self.request_id == other.request_id - and self.host_id == other.host_id - and self.bucket_name == other.bucket_name - and self.object_name == other.object_name - ) - - def __hash__(self): - return hash( - ( - self.code, - self.message, - self.resource, - self.request_id, - self.host_id, - self.bucket_name, - self.object_name, - ) - ) - - -class MinioAdminException(Exception): - """Raised to indicate admin API execution error.""" - - def __init__(self, code: str, body: str): - self._code = code - self._body = body - super().__init__( - f"admin request failed; Status: {code}, Body: {body}", - ) - - def __reduce__(self): - return type(self), (self._code, self._body) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/helpers.py b/backend/venv39/lib/python3.9/site-packages/minio/helpers.py deleted file mode 100644 index 15d60c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/helpers.py +++ /dev/null @@ -1,860 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2015, 2016, 2017 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Helper functions.""" - -from __future__ import absolute_import, annotations, division, unicode_literals - -import base64 -import errno -import hashlib -import math -import os -import platform -import re -import urllib.parse -from dataclasses import dataclass -from datetime import datetime -from queue import Queue -from threading import BoundedSemaphore, Thread -from typing import BinaryIO, Dict, List, Mapping, Optional, Tuple, Union - -from typing_extensions import Protocol -from urllib3._collections import HTTPHeaderDict - -from . import __title__, __version__ -from .sse import Sse, SseCustomerKey -from .time import to_iso8601utc - -_DEFAULT_USER_AGENT = ( - f"MinIO ({platform.system()}; {platform.machine()}) " - f"{__title__}/{__version__}" -) - -MAX_MULTIPART_COUNT = 10000 # 10000 parts -MAX_MULTIPART_OBJECT_SIZE = 5 * 1024 * 1024 * 1024 * 1024 # 5TiB -MAX_PART_SIZE = 5 * 1024 * 1024 * 1024 # 5GiB -MIN_PART_SIZE = 5 * 1024 * 1024 # 5MiB - -_AWS_S3_PREFIX = (r'^(((bucket\.|accesspoint\.)' - r'vpce(-(?!_)[a-z_\d]+(? str: - """ - Wrapper to urllib.parse.quote() replacing back to '~' for older python - versions. - """ - return urllib.parse.quote( - resource, - safe=safe, - encoding=encoding, - errors=errors, - ).replace("%7E", "~") - - -def queryencode( - query: str, - safe: str = "", - encoding: Optional[str] = None, - errors: Optional[str] = None, -) -> str: - """Encode query parameter value.""" - return quote(query, safe, encoding, errors) - - -def headers_to_strings( - headers: Mapping[str, str | list[str] | tuple[str]], - titled_key: bool = False, -) -> str: - """Convert HTTP headers to multi-line string.""" - values = [] - for key, value in headers.items(): - key = key.title() if titled_key else key - for item in value if isinstance(value, (list, tuple)) else [value]: - item = re.sub( - r"Credential=([^/]+)", - "Credential=*REDACTED*", - re.sub(r"Signature=([0-9a-f]+)", "Signature=*REDACTED*", item), - ) if titled_key else item - values.append(f"{key}: {item}") - return "\n".join(values) - - -def _validate_sizes(object_size: int, part_size: int): - """Validate object and part size.""" - if part_size > 0: - if part_size < MIN_PART_SIZE: - raise ValueError( - f"part size {part_size} is not supported; minimum allowed 5MiB" - ) - if part_size > MAX_PART_SIZE: - raise ValueError( - f"part size {part_size} is not supported; maximum allowed 5GiB" - ) - - if object_size >= 0: - if object_size > MAX_MULTIPART_OBJECT_SIZE: - raise ValueError( - f"object size {object_size} is not supported; " - f"maximum allowed 5TiB" - ) - elif part_size <= 0: - raise ValueError( - "valid part size must be provided when object size is unknown", - ) - - -def _get_part_info(object_size: int, part_size: int): - """Compute part information for object and part size.""" - _validate_sizes(object_size, part_size) - - if object_size < 0: - return part_size, -1 - - if part_size > 0: - part_size = min(part_size, object_size) - return part_size, math.ceil(object_size / part_size) if part_size else 1 - - part_size = math.ceil( - math.ceil(object_size / MAX_MULTIPART_COUNT) / MIN_PART_SIZE, - ) * MIN_PART_SIZE - return part_size, math.ceil(object_size / part_size) if part_size else 1 - - -def get_part_info(object_size: int, part_size: int) -> tuple[int, int]: - """Compute part information for object and part size.""" - part_size, part_count = _get_part_info(object_size, part_size) - if part_count > MAX_MULTIPART_COUNT: - raise ValueError( - f"object size {object_size} and part size {part_size} " - f"make more than {MAX_MULTIPART_COUNT} parts for upload" - ) - return part_size, part_count - - -class ProgressType(Protocol): - """typing stub for Put/Get object progress.""" - - def set_meta(self, object_name: str, total_length: int): - """Set process meta information.""" - - def update(self, length: int): - """Set current progress length.""" - - -def read_part_data( - stream: BinaryIO, - size: int, - part_data: bytes = b"", - progress: Optional[ProgressType] = None, -) -> bytes: - """Read part data of given size from stream.""" - size -= len(part_data) - while size: - data = stream.read(size) - if not data: - break # EOF reached - if not isinstance(data, bytes): - raise ValueError("read() must return 'bytes' object") - part_data += data - size -= len(data) - if progress: - progress.update(len(data)) - return part_data - - -def makedirs(path: str): - """Wrapper of os.makedirs() ignores errno.EEXIST.""" - try: - if path: - os.makedirs(path) - except OSError as exc: # Python >2.5 - if exc.errno != errno.EEXIST: - raise - - if not os.path.isdir(path): - raise ValueError(f"path {path} is not a directory") from exc - - -def check_bucket_name( - bucket_name: str, - strict: bool = False, - s3_check: bool = False, -): - """Check whether bucket name is valid optional with strict check or not.""" - - if strict: - if not _BUCKET_NAME_REGEX.match(bucket_name): - raise ValueError(f'invalid bucket name {bucket_name}') - else: - if not _OLD_BUCKET_NAME_REGEX.match(bucket_name): - raise ValueError(f'invalid bucket name {bucket_name}') - - if _IPV4_REGEX.match(bucket_name): - raise ValueError(f'bucket name {bucket_name} must not be formatted ' - 'as an IP address') - - unallowed_successive_chars = ['..', '.-', '-.'] - if any(x in bucket_name for x in unallowed_successive_chars): - raise ValueError(f'bucket name {bucket_name} contains invalid ' - 'successive characters') - - if ( - s3_check and - bucket_name.startswith("xn--") or - bucket_name.endswith("-s3alias") or - bucket_name.endswith("--ol-s3") - ): - raise ValueError(f"bucket name {bucket_name} must not start with " - "'xn--' and must not end with '--s3alias' or " - "'--ol-s3'") - - -def check_non_empty_string(string: str | bytes): - """Check whether given string is not empty.""" - try: - if not string.strip(): - raise ValueError() - except AttributeError as exc: - raise TypeError() from exc - - -def check_object_name(object_name: str): - """Check whether given object name is valid.""" - check_non_empty_string(object_name) - tokens = object_name.split("/") - if "." in tokens or ".." in tokens: - raise ValueError( - "object name with '.' or '..' path segment is not supported", - ) - - -def is_valid_policy_type(policy: str | bytes): - """ - Validate if policy is type str - - :param policy: S3 style Bucket policy. - :return: True if policy parameter is of a valid type, 'string'. - Raise :exc:`TypeError` otherwise. - """ - if not isinstance(policy, (str, bytes)): - raise TypeError("policy must be str or bytes type") - - check_non_empty_string(policy) - - return True - - -def check_ssec(sse: Optional[SseCustomerKey]): - """Check sse is SseCustomerKey type or not.""" - if sse and not isinstance(sse, SseCustomerKey): - raise ValueError("SseCustomerKey type is required") - - -def check_sse(sse: Optional[Sse]): - """Check sse is Sse type or not.""" - if sse and not isinstance(sse, Sse): - raise ValueError("Sse type is required") - - -def md5sum_hash(data: Optional[str | bytes]) -> Optional[str]: - """Compute MD5 of data and return hash as Base64 encoded value.""" - if data is None: - return None - - # indicate md5 hashing algorithm is not used in a security context. - # Refer https://bugs.python.org/issue9216 for more information. - hasher = hashlib.new( # type: ignore[call-arg] - "md5", - usedforsecurity=False, - ) - hasher.update(data.encode() if isinstance(data, str) else data) - md5sum = base64.b64encode(hasher.digest()) - return md5sum.decode() if isinstance(md5sum, bytes) else md5sum - - -def sha256_hash(data: Optional[str | bytes]) -> str: - """Compute SHA-256 of data and return hash as hex encoded value.""" - data = data or b"" - hasher = hashlib.sha256() - hasher.update(data.encode() if isinstance(data, str) else data) - sha256sum = hasher.hexdigest() - if isinstance(sha256sum, bytes): - return sha256sum.decode() - return sha256sum - - -def url_replace( - *, - url: urllib.parse.SplitResult, - scheme: Optional[str] = None, - netloc: Optional[str] = None, - path: Optional[str] = None, - query: Optional[str] = None, - fragment: Optional[str] = None, -) -> urllib.parse.SplitResult: - """Return new URL with replaced properties in given URL.""" - return urllib.parse.SplitResult( - scheme if scheme is not None else url.scheme, - netloc if netloc is not None else url.netloc, - path if path is not None else url.path, - query if query is not None else url.query, - fragment if fragment is not None else url.fragment, - ) - - -def _metadata_to_headers(metadata: DictType) -> dict[str, list[str]]: - """Convert user metadata to headers.""" - def normalize_key(key: str) -> str: - if not key.lower().startswith("x-amz-meta-"): - key = "X-Amz-Meta-" + key - return key - - def to_string(value) -> str: - value = str(value) - try: - value.encode("us-ascii") - except UnicodeEncodeError as exc: - raise ValueError( - f"unsupported metadata value {value}; " - f"only US-ASCII encoded characters are supported" - ) from exc - return value - - def normalize_value(values: str | list[str] | tuple[str]) -> list[str]: - if not isinstance(values, (list, tuple)): - values = [values] - return [to_string(value) for value in values] - - return { - normalize_key(key): normalize_value(value) - for key, value in (metadata or {}).items() - } - - -def normalize_headers(headers: Optional[DictType]) -> DictType: - """Normalize headers by prefixing 'X-Amz-Meta-' for user metadata.""" - headers = {str(key): value for key, value in (headers or {}).items()} - - def guess_user_metadata(key: str) -> bool: - key = key.lower() - return not ( - key.startswith("x-amz-") or - key in [ - "cache-control", - "content-encoding", - "content-type", - "content-disposition", - "content-language", - ] - ) - - user_metadata = { - key: value for key, value in headers.items() - if guess_user_metadata(key) - } - - # Remove guessed user metadata. - _ = [headers.pop(key) for key in user_metadata] - - headers.update(_metadata_to_headers(user_metadata)) - return headers - - -def genheaders( - headers: Optional[DictType], - sse: Optional[Sse], - tags: Optional[dict[str, str]], - retention, - legal_hold: bool, -) -> DictType: - """Generate headers for given parameters.""" - headers = normalize_headers(headers) - headers.update(sse.headers() if sse else {}) - tagging = "&".join( - [ - queryencode(key) + "=" + queryencode(value) - for key, value in (tags or {}).items() - ], - ) - if tagging: - headers["x-amz-tagging"] = tagging - if retention and retention.mode: - headers["x-amz-object-lock-mode"] = retention.mode - headers["x-amz-object-lock-retain-until-date"] = ( - to_iso8601utc(retention.retain_until_date) or "" - ) - if legal_hold: - headers["x-amz-object-lock-legal-hold"] = "ON" - return headers - - -def _get_aws_info( - host: str, - https: bool, - region: Optional[str], -) -> tuple[Optional[dict], Optional[str]]: - """Extract AWS domain information. """ - - if not _HOSTNAME_REGEX.match(host): - return (None, None) - - if _AWS_ELB_ENDPOINT_REGEX.match(host): - region_in_host = host.split(".elb.amazonaws.com", 1)[0].split(".")[-1] - return (None, region or region_in_host) - - if not _AWS_ENDPOINT_REGEX.match(host): - return (None, None) - - if host.startswith("ec2-"): - return (None, None) - - if not _AWS_S3_ENDPOINT_REGEX.match(host): - raise ValueError(f"invalid Amazon AWS host {host}") - - matcher = _AWS_S3_PREFIX_REGEX.match(host) - end = matcher.end() if matcher else 0 - aws_s3_prefix = host[:end] - - if "s3-accesspoint" in aws_s3_prefix and not https: - raise ValueError(f"use HTTPS scheme for host {host}") - - tokens = host[end:].split(".") - dualstack = tokens[0] == "dualstack" - if dualstack: - tokens = tokens[1:] - region_in_host = "" - if tokens[0] not in ["vpce", "amazonaws"]: - region_in_host = tokens[0] - tokens = tokens[1:] - aws_domain_suffix = ".".join(tokens) - - if host in "s3-external-1.amazonaws.com": - region_in_host = "us-east-1" - - if host in ["s3-us-gov-west-1.amazonaws.com", - "s3-fips-us-gov-west-1.amazonaws.com"]: - region_in_host = "us-gov-west-1" - - if (aws_domain_suffix.endswith(".cn") and - not aws_s3_prefix.endswith("s3-accelerate.") and - not region_in_host and - not region): - raise ValueError( - f"region missing in Amazon S3 China endpoint {host}", - ) - - return ({"s3_prefix": aws_s3_prefix, - "domain_suffix": aws_domain_suffix, - "region": region or region_in_host, - "dualstack": dualstack}, None) - - -def _parse_url(endpoint: str) -> urllib.parse.SplitResult: - """Parse url string.""" - - url = urllib.parse.urlsplit(endpoint) - host = url.hostname - - if url.scheme.lower() not in ["http", "https"]: - raise ValueError("scheme in endpoint must be http or https") - - url = url_replace(url=url, scheme=url.scheme.lower()) - - if url.path and url.path != "/": - raise ValueError("path in endpoint is not allowed") - - url = url_replace(url=url, path="") - - if url.query: - raise ValueError("query in endpoint is not allowed") - - if url.fragment: - raise ValueError("fragment in endpoint is not allowed") - - try: - url.port - except ValueError as exc: - raise ValueError("invalid port") from exc - - if url.username: - raise ValueError("username in endpoint is not allowed") - - if url.password: - raise ValueError("password in endpoint is not allowed") - - if ( - (url.scheme == "http" and url.port == 80) or - (url.scheme == "https" and url.port == 443) - ): - url = url_replace(url=url, netloc=host) - - return url - - -class BaseURL: - """Base URL of S3 endpoint.""" - _aws_info: Optional[dict] - _virtual_style_flag: bool - _url: urllib.parse.SplitResult - _region: Optional[str] - _accelerate_host_flag: bool - - def __init__(self, endpoint: str, region: Optional[str]): - url = _parse_url(endpoint) - - if region and not _REGION_REGEX.match(region): - raise ValueError(f"invalid region {region}") - - hostname = url.hostname or "" - self._aws_info, region_in_host = _get_aws_info( - hostname, url.scheme == "https", region) - self._virtual_style_flag = ( - self._aws_info is not None or hostname.endswith("aliyuncs.com") - ) - self._url = url - self._region = region or region_in_host - self._accelerate_host_flag = False - if self._aws_info: - self._region = self._aws_info["region"] - self._accelerate_host_flag = ( - self._aws_info["s3_prefix"].endswith("s3-accelerate.") - ) - - @property - def region(self) -> Optional[str]: - """Get region.""" - return self._region - - @property - def is_https(self) -> bool: - """Check if scheme is HTTPS.""" - return self._url.scheme == "https" - - @property - def host(self) -> str: - """Get hostname.""" - return self._url.netloc - - @property - def is_aws_host(self) -> bool: - """Check if URL points to AWS host.""" - return self._aws_info is not None - - @property - def aws_s3_prefix(self) -> Optional[str]: - """Get AWS S3 domain prefix.""" - return self._aws_info["s3_prefix"] if self._aws_info else None - - @aws_s3_prefix.setter - def aws_s3_prefix(self, s3_prefix: str): - """Set AWS s3 domain prefix.""" - if not _AWS_S3_PREFIX_REGEX.match(s3_prefix): - raise ValueError(f"invalid AWS S3 domain prefix {s3_prefix}") - if self._aws_info: - self._aws_info["s3_prefix"] = s3_prefix - - @property - def accelerate_host_flag(self) -> bool: - """Get AWS accelerate host flag.""" - return self._accelerate_host_flag - - @accelerate_host_flag.setter - def accelerate_host_flag(self, flag: bool): - """Set AWS accelerate host flag.""" - self._accelerate_host_flag = flag - - @property - def dualstack_host_flag(self) -> bool: - """Check if URL points to AWS dualstack host.""" - return self._aws_info["dualstack"] if self._aws_info else False - - @dualstack_host_flag.setter - def dualstack_host_flag(self, flag: bool): - """Set AWS dualstack host.""" - if self._aws_info: - self._aws_info["dualstack"] = flag - - @property - def virtual_style_flag(self) -> bool: - """Check to use virtual style or not.""" - return self._virtual_style_flag - - @virtual_style_flag.setter - def virtual_style_flag(self, flag: bool): - """Check to use virtual style or not.""" - self._virtual_style_flag = flag - - @classmethod - def _build_aws_url( - cls, - *, - aws_info: dict, - url: urllib.parse.SplitResult, - bucket_name: Optional[str], - enforce_path_style: bool, - region: str, - ) -> urllib.parse.SplitResult: - """Build URL for given information.""" - s3_prefix = aws_info["s3_prefix"] - domain_suffix = aws_info["domain_suffix"] - - host = f"{s3_prefix}{domain_suffix}" - if host in ["s3-external-1.amazonaws.com", - "s3-us-gov-west-1.amazonaws.com", - "s3-fips-us-gov-west-1.amazonaws.com"]: - return url_replace(url=url, netloc=host) - - netloc = s3_prefix - if "s3-accelerate" in s3_prefix: - if "." in (bucket_name or ""): - raise ValueError( - f"bucket name '{bucket_name}' with '.' is not allowed " - f"for accelerate endpoint" - ) - if enforce_path_style: - netloc = netloc.replace("-accelerate", "", 1) - - if aws_info["dualstack"]: - netloc += "dualstack." - if "s3-accelerate" not in s3_prefix: - netloc += region + "." - netloc += domain_suffix - - return url_replace(url=url, netloc=netloc) - - def _build_list_buckets_url( - self, - url: urllib.parse.SplitResult, - region: Optional[str], - ) -> urllib.parse.SplitResult: - """Build URL for ListBuckets API.""" - if not self._aws_info: - return url - - s3_prefix = self._aws_info["s3_prefix"] - domain_suffix = self._aws_info["domain_suffix"] - - host = f"{s3_prefix}{domain_suffix}" - if host in ["s3-external-1.amazonaws.com", - "s3-us-gov-west-1.amazonaws.com", - "s3-fips-us-gov-west-1.amazonaws.com"]: - return url_replace(url=url, netloc=host) - - if s3_prefix.startswith("s3.") or s3_prefix.startswith("s3-"): - s3_prefix = "s3." - cn_suffix = ".cn" if domain_suffix.endswith(".cn") else "" - domain_suffix = f"amazonaws.com{cn_suffix}" - return url_replace( - url=url, - netloc=f"{s3_prefix}{region}.{domain_suffix}", - ) - - def build( - self, - *, - method: str, - region: str, - bucket_name: Optional[str] = None, - object_name: Optional[str] = None, - query_params: Optional[DictType] = None, - ) -> urllib.parse.SplitResult: - """Build URL for given information.""" - if not bucket_name and object_name: - raise ValueError( - f"empty bucket name for object name {object_name}", - ) - - url = url_replace(url=self._url, path="/") - - query = [] - for key, values in sorted((query_params or {}).items()): - values = values if isinstance(values, (list, tuple)) else [values] - query += [ - f"{queryencode(key)}={queryencode(value)}" - for value in sorted(values) - ] - url = url_replace(url=url, query="&".join(query)) - - if not bucket_name: - return self._build_list_buckets_url(url, region) - - enforce_path_style = ( - # CreateBucket API requires path style in Amazon AWS S3. - (method == "PUT" and not object_name and not query_params) or - - # GetBucketLocation API requires path style in Amazon AWS S3. - (query_params and "location" in query_params) or - - # Use path style for bucket name containing '.' which causes - # SSL certificate validation error. - ("." in bucket_name and self._url.scheme == "https") - ) - - if self._aws_info: - url = BaseURL._build_aws_url( - aws_info=self._aws_info, - url=url, - bucket_name=bucket_name, - enforce_path_style=enforce_path_style, - region=region, - ) - - netloc = url.netloc - path = "/" - - if enforce_path_style or not self._virtual_style_flag: - path = f"/{bucket_name}" - else: - netloc = f"{bucket_name}.{netloc}" - if object_name: - path += ("" if path.endswith("/") else "/") + quote(object_name) - - return url_replace(url=url, netloc=netloc, path=path) - - -@dataclass(frozen=True) -class ObjectWriteResult: - """Result class of any APIs doing object creation.""" - bucket_name: str - object_name: str - version_id: Optional[str] - etag: Optional[str] - http_headers: HTTPHeaderDict - last_modified: Optional[datetime] = None - location: Optional[str] = None - - -class Worker(Thread): - """ Thread executing tasks from a given tasks queue """ - - def __init__( - self, - tasks_queue: Queue, - results_queue: Queue, - exceptions_queue: Queue, - ): - Thread.__init__(self, daemon=True) - self._tasks_queue = tasks_queue - self._results_queue = results_queue - self._exceptions_queue = exceptions_queue - self.start() - - def run(self): - """ Continuously receive tasks and execute them """ - while True: - task = self._tasks_queue.get() - if not task: - self._tasks_queue.task_done() - break - func, args, kargs, cleanup_func = task - # No exception detected in any thread, - # continue the execution. - if self._exceptions_queue.empty(): - try: - result = func(*args, **kargs) - self._results_queue.put(result) - except Exception as ex: # pylint: disable=broad-except - self._exceptions_queue.put(ex) - - # call cleanup i.e. Semaphore.release irrespective of task - # execution to avoid race condition. - cleanup_func() - # Mark this task as done, whether an exception happened or not - self._tasks_queue.task_done() - - -class ThreadPool: - """ Pool of threads consuming tasks from a queue """ - _results_queue: Queue - _exceptions_queue: Queue - _tasks_queue: Queue - _sem: BoundedSemaphore - _num_threads: int - - def __init__(self, num_threads: int): - self._results_queue = Queue() - self._exceptions_queue = Queue() - self._tasks_queue = Queue() - self._sem = BoundedSemaphore(num_threads) - self._num_threads = num_threads - - def add_task(self, func, *args, **kargs): - """ - Add a task to the queue. Calling this function can block - until workers have a room for processing new tasks. Blocking - the caller also prevents the latter from allocating a lot of - memory while workers are still busy running their assigned tasks. - """ - self._sem.acquire() # pylint: disable=consider-using-with - cleanup_func = self._sem.release - self._tasks_queue.put((func, args, kargs, cleanup_func)) - - def start_parallel(self): - """ Prepare threads to run tasks""" - for _ in range(self._num_threads): - Worker( - self._tasks_queue, self._results_queue, self._exceptions_queue, - ) - - def result(self) -> Queue: - """ Stop threads and return the result of all called tasks """ - # Send None to all threads to cleanly stop them - for _ in range(self._num_threads): - self._tasks_queue.put(None) - # Wait for completion of all the tasks in the queue - self._tasks_queue.join() - # Check if one of the thread raised an exception, if yes - # raise it here in the function - if not self._exceptions_queue.empty(): - raise self._exceptions_queue.get() - return self._results_queue diff --git a/backend/venv39/lib/python3.9/site-packages/minio/legalhold.py b/backend/venv39/lib/python3.9/site-packages/minio/legalhold.py deleted file mode 100644 index a5bb0d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/legalhold.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of PutObjectLegalHold and GetObjectLegalHold S3 APIs.""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from typing import Optional, Type, TypeVar -from xml.etree import ElementTree as ET - -from .xml import Element, SubElement, findtext - -A = TypeVar("A", bound="LegalHold") - - -@dataclass(frozen=True) -class LegalHold: - """Legal hold configuration.""" - - status: bool = False - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - status = findtext(element, "Status") - return cls(status=status == "ON") - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("LegalHold") - SubElement(element, "Status", "ON" if self.status is True else "OFF") - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/lifecycleconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/lifecycleconfig.py deleted file mode 100644 index 054287b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/lifecycleconfig.py +++ /dev/null @@ -1,344 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2015, 2016, 2017, 2018, 2019 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Request/response of PutBucketLifecycleConfiguration and -GetBucketLifecycleConfiguration APIs. -""" -# pylint: disable=invalid-name - -from __future__ import absolute_import, annotations - -from abc import ABC -from dataclasses import dataclass -from datetime import datetime -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .commonconfig import BaseRule -from .time import from_iso8601utc, to_iso8601utc -from .xml import Element, SubElement, find, findall, findtext - - -@dataclass(frozen=True) -class DateDays(ABC): - """Base class holds date and days of Transition and Expiration.""" - date: Optional[datetime] = None - days: Optional[int] = None - - @staticmethod - def parsexml( - element: ET.Element) -> tuple[Optional[datetime], Optional[int]]: - """Parse XML to date and days.""" - date = from_iso8601utc(findtext(element, "Date")) - days = findtext(element, "Days") - return date, int(days) if days else None - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - if self.date is not None: - SubElement( - element, "Date", to_iso8601utc(self.date), - ) - if self.days: - SubElement(element, "Days", str(self.days)) - return element - - -A = TypeVar("A", bound="Transition") - - -@dataclass(frozen=True) -class Transition(DateDays): - """Transition.""" - storage_class: Optional[str] = None - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Transition", True)) - date, days = cls.parsexml(element) - return cls(date, days, findtext(element, "StorageClass")) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Transition") - super().toxml(element) - if self.storage_class: - SubElement(element, "StorageClass", self.storage_class) - return element - - -B = TypeVar("B", bound="NoncurrentVersionTransition") - - -@dataclass(frozen=True) -class NoncurrentVersionTransition: - """Noncurrent version transition.""" - noncurrent_days: Optional[int] = None - storage_class: Optional[str] = None - newer_noncurrent_versions: Optional[int] = None - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "NoncurrentVersionTransition", True), - ) - noncurrent_days = findtext(element, "NoncurrentDays") - versions = findtext(element, "NewerNoncurrentVersions") - return cls( - int(noncurrent_days) if noncurrent_days else None, - findtext(element, "StorageClass"), - int(versions) if versions else None, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "NoncurrentVersionTransition") - if self.noncurrent_days: - SubElement(element, "NoncurrentDays", str(self.noncurrent_days)) - if self.storage_class: - SubElement(element, "StorageClass", self.storage_class) - if self.newer_noncurrent_versions: - SubElement(element, "NewerNoncurrentVersions", - str(self.newer_noncurrent_versions)) - return element - - -C = TypeVar("C", bound="NoncurrentVersionExpiration") - - -@dataclass(frozen=True) -class NoncurrentVersionExpiration: - """Noncurrent version expiration.""" - noncurrent_days: Optional[int] = None - newer_noncurrent_versions: Optional[int] = None - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "NoncurrentVersionExpiration", True), - ) - noncurrent_days = findtext(element, "NoncurrentDays") - versions = findtext(element, "NewerNoncurrentVersions") - return cls(int(noncurrent_days) if noncurrent_days else None, - int(versions) if versions else None) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "NoncurrentVersionExpiration") - if self.noncurrent_days: - SubElement(element, "NoncurrentDays", str(self.noncurrent_days)) - if self.newer_noncurrent_versions: - SubElement(element, "NewerNoncurrentVersions", - str(self.newer_noncurrent_versions)) - return element - - -D = TypeVar("D", bound="Expiration") - - -@dataclass(frozen=True) -class Expiration(DateDays): - """Expiration.""" - expired_object_delete_marker: Optional[bool] = None - - @classmethod - def fromxml(cls: Type[D], element: ET.Element) -> D: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Expiration", True)) - date, days = cls.parsexml(element) - expired_object_delete_marker = findtext( - element, "ExpiredObjectDeleteMarker", - ) - if expired_object_delete_marker is None: - return cls(date, days, None) - - if expired_object_delete_marker.title() not in ["False", "True"]: - raise ValueError( - "value of ExpiredObjectDeleteMarker must be " - "'True' or 'False'", - ) - return cls(date, days, expired_object_delete_marker.title() == "True") - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Expiration") - super().toxml(element) - if self.expired_object_delete_marker is not None: - SubElement( - element, - "ExpiredObjectDeleteMarker", - str(self.expired_object_delete_marker).lower(), - ) - return element - - -E = TypeVar("E", bound="AbortIncompleteMultipartUpload") - - -@dataclass(frozen=True) -class AbortIncompleteMultipartUpload: - """Abort incomplete multipart upload.""" - days_after_initiation: Optional[int] = None - - @classmethod - def fromxml(cls: Type[E], element: ET.Element) -> E: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "AbortIncompleteMultipartUpload", True), - ) - days_after_initiation = findtext(element, "DaysAfterInitiation") - return cls( - int(days_after_initiation) if days_after_initiation else None, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "AbortIncompleteMultipartUpload") - if self.days_after_initiation: - SubElement( - element, - "DaysAfterInitiation", - str(self.days_after_initiation), - ) - return element - - -F = TypeVar("F", bound="Rule") - - -@dataclass(frozen=True) -class Rule(BaseRule): - """Lifecycle rule. """ - abort_incomplete_multipart_upload: Optional[ - AbortIncompleteMultipartUpload] = None - expiration: Optional[Expiration] = None - noncurrent_version_expiration: Optional[NoncurrentVersionExpiration] = None - noncurrent_version_transition: Optional[NoncurrentVersionTransition] = None - transition: Optional[Transition] = None - - def __post_init__(self): - if (not self.abort_incomplete_multipart_upload and not self.expiration - and not self.noncurrent_version_expiration - and not self.noncurrent_version_transition - and not self.transition): - raise ValueError( - "at least one of action (AbortIncompleteMultipartUpload, " - "Expiration, NoncurrentVersionExpiration, " - "NoncurrentVersionTransition or Transition) must be specified " - "in a rule") - - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - @classmethod - def fromxml(cls: Type[F], element: ET.Element) -> F: - """Create new object with values from XML element.""" - status, rule_filter, rule_id = cls.parsexml(element) - abort_incomplete_multipart_upload = ( - None if find(element, "AbortIncompleteMultipartUpload") is None - else AbortIncompleteMultipartUpload.fromxml(element) - ) - expiration = ( - None if find(element, "Expiration") is None - else Expiration.fromxml(element) - ) - noncurrent_version_expiration = ( - None if find(element, "NoncurrentVersionExpiration") is None - else NoncurrentVersionExpiration.fromxml(element) - ) - noncurrent_version_transition = ( - None if find(element, "NoncurrentVersionTransition") is None - else NoncurrentVersionTransition.fromxml(element) - ) - transition = ( - None if find(element, "Transition") is None - else Transition.fromxml(element) - ) - - return cls( - status=status, - rule_filter=rule_filter, - rule_id=rule_id, - abort_incomplete_multipart_upload=( - abort_incomplete_multipart_upload - ), - expiration=expiration, - noncurrent_version_expiration=noncurrent_version_expiration, - noncurrent_version_transition=noncurrent_version_transition, - transition=transition, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Rule") - super().toxml(element) - if self.abort_incomplete_multipart_upload: - self.abort_incomplete_multipart_upload.toxml(element) - if self.expiration: - self.expiration.toxml(element) - if self.noncurrent_version_expiration: - self.noncurrent_version_expiration.toxml(element) - if self.noncurrent_version_transition: - self.noncurrent_version_transition.toxml(element) - if self.transition: - self.transition.toxml(element) - return element - - -G = TypeVar("G", bound="LifecycleConfig") - - -@dataclass(frozen=True) -class LifecycleConfig: - """Lifecycle configuration.""" - rules: list[Rule] - - @classmethod - def fromxml(cls: Type[G], element: ET.Element) -> G: - """Create new object with values from XML element.""" - elements = findall(element, "Rule") - rules = [] - for tag in elements: - rules.append(Rule.fromxml(tag)) - return cls(rules) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("LifecycleConfiguration") - for rule in self.rules: - rule.toxml(element) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/minioadmin.py b/backend/venv39/lib/python3.9/site-packages/minio/minioadmin.py deleted file mode 100644 index 9469ce1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/minioadmin.py +++ /dev/null @@ -1,1016 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2021 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# pylint: disable=too-many-public-methods -# pylint: disable=too-many-lines - -"""MinIO Admin Client to perform MinIO administration operations.""" - -from __future__ import absolute_import, annotations - -import json -import os -from datetime import timedelta -from enum import Enum, unique -from typing import Any, Optional, TextIO, Tuple, cast -from urllib.parse import urlunsplit - -import certifi -from urllib3 import Retry -from urllib3._collections import HTTPHeaderDict -from urllib3.poolmanager import PoolManager - -try: - from urllib3.response import BaseHTTPResponse # type: ignore[attr-defined] -except ImportError: - from urllib3.response import HTTPResponse as BaseHTTPResponse - -from urllib3.util import Timeout - -from . import time -from .credentials import Provider -from .crypto import decrypt, encrypt -from .datatypes import PeerInfo, PeerSite, SiteReplicationStatusOptions -from .error import MinioAdminException -from .helpers import (_DEFAULT_USER_AGENT, _REGION_REGEX, DictType, _parse_url, - headers_to_strings, queryencode, sha256_hash, - url_replace) -from .signer import sign_v4_s3 - - -@unique -class _COMMAND(Enum): - """Admin Command enumerations.""" - ACCOUNT_INFO = "accountinfo" - ADD_USER = "add-user" - USER_INFO = "user-info" - LIST_USERS = "list-users" - REMOVE_USER = "remove-user" - SET_USER_STATUS = "set-user-status" - ADD_CANNED_POLICY = "add-canned-policy" - SET_USER_OR_GROUP_POLICY = "set-user-or-group-policy" - LIST_CANNED_POLICIES = "list-canned-policies" - REMOVE_CANNED_POLICY = "remove-canned-policy" - CANNED_POLICY_INFO = "info-canned-policy" - SET_BUCKET_QUOTA = "set-bucket-quota" - GET_BUCKET_QUOTA = "get-bucket-quota" - DATA_USAGE_INFO = "datausageinfo" - ADD_UPDATE_REMOVE_GROUP = "update-group-members" - SET_GROUP_STATUS = "set-group-status" - GROUP_INFO = "group" - LIST_GROUPS = "groups" - INFO = "info" - SERVICE = "service" - UPDATE = "update" - TOP_LOCKS = "top/locks" - HELP_CONFIG = "help-config-kv" - GET_CONFIG = "get-config-kv" - SET_CONFIG = "set-config-kv" - DELETE_CONFIG = "del-config-kv" - LIST_CONFIG_HISTORY = "list-config-history-kv" - RESOTRE_CONFIG_HISTORY = "restore-config-history-kv" - START_PROFILE = "profile" - CREATE_KMS_KEY = "kms/key/create" - GET_KMS_KEY_STATUS = "kms/key/status" - SITE_REPLICATION_ADD = "site-replication/add" - SITE_REPLICATION_INFO = "site-replication/info" - SITE_REPLICATION_STATUS = "site-replication/status" - SITE_REPLICATION_EDIT = "site-replication/edit" - SITE_REPLICATION_REMOVE = "site-replication/remove" - SERVICE_ACCOUNT_INFO = "info-service-account" - SERVICE_ACCOUNT_LIST = "list-service-accounts" - SERVICE_ACCOUNT_ADD = "add-service-account" - SERVICE_ACCOUNT_UPDATE = "update-service-account" - SERVICE_ACCOUNT_DELETE = "delete-service-account" - IDP_LDAP_POLICY_ATTACH = "idp/ldap/policy/attach" - IDP_LDAP_POLICY_DETACH = "idp/ldap/policy/detach" - IDP_LDAP_LIST_ACCESS_KEYS = "idp/ldap/list-access-keys" - IDP_LDAP_LIST_ACCESS_KEYS_BULK = "idp/ldap/list-access-keys-bulk" - IDP_BUILTIN_POLICY_ATTACH = "idp/builtin/policy/attach" - IDP_BUILTIN_POLICY_DETACH = "idp/builtin/policy/detach" - IDP_BUILTIN_POLICY_ENTITIES = "idp/builtin/policy-entities" - - -def _safe_str(value: Any) -> str: - """Convert to string safely""" - try: - return value.decode() if isinstance(value, bytes) else str(value) - except UnicodeDecodeError: - return value.hex() - - -class MinioAdmin: - """Client to perform MinIO administration operations.""" - - def __init__( - self, - *, - endpoint: str, - credentials: Provider, - region: str = "", - secure: bool = True, - cert_check: bool = True, - http_client: Optional[PoolManager] = None, - ): - url = _parse_url(("https://" if secure else "http://") + endpoint) - if not isinstance(credentials, Provider): - raise ValueError("valid credentials must be provided") - if region and not _REGION_REGEX.match(region): - raise ValueError(f"invalid region {region}") - if http_client: - if not isinstance(http_client, PoolManager): - raise ValueError( - "HTTP client should be instance of " - "`urllib3.poolmanager.PoolManager`" - ) - else: - timeout = timedelta(minutes=5).seconds - http_client = PoolManager( - timeout=Timeout(connect=timeout, read=timeout), - maxsize=10, - cert_reqs='CERT_REQUIRED' if cert_check else 'CERT_NONE', - ca_certs=os.environ.get('SSL_CERT_FILE') or certifi.where(), - retries=Retry( - total=5, - backoff_factor=0.2, - status_forcelist=[500, 502, 503, 504] - ) - ) - - self._url = url - self._provider = credentials - self._region = region - self._secure = secure - self._cert_check = cert_check - self._http = http_client - self._user_agent = _DEFAULT_USER_AGENT - self._trace_stream: Optional[TextIO] = None - - def __del__(self): - self._http.clear() - - def _url_open( - self, - *, - method: str, - command: _COMMAND, - query_params: Optional[DictType] = None, - body: Optional[bytes] = None, - preload_content: bool = True, - ) -> BaseHTTPResponse: - """Execute HTTP request.""" - creds = self._provider.retrieve() - - url = url_replace(url=self._url, path="/minio/admin/v3/"+command.value) - query = [] - for key, values in sorted((query_params or {}).items()): - values = values if isinstance(values, (list, tuple)) else [values] - query += [ - f"{queryencode(key)}={queryencode(value)}" - for value in sorted(values) - ] - url = url_replace(url=url, query="&".join(query)) - - content_sha256 = sha256_hash(body) - date = time.utcnow() - headers: DictType = { - "Host": url.netloc, - "User-Agent": self._user_agent, - "x-amz-date": time.to_amz_date(date), - "x-amz-content-sha256": content_sha256, - "Content-Type": "application/octet-stream" - } - if creds.session_token: - headers["X-Amz-Security-Token"] = creds.session_token - if body: - headers["Content-Length"] = str(len(body)) - - headers = sign_v4_s3( - method=method, - url=url, - region=self._region, - headers=headers, - credentials=creds, - content_sha256=content_sha256, - date=date, - ) - - if self._trace_stream: - self._trace_stream.write("---------START-HTTP---------\n") - query_string = ("?" + url.query) if url.query else "" - self._trace_stream.write( - f"{method} {url.path}{query_string} HTTP/1.1\n", - ) - self._trace_stream.write( - headers_to_strings(headers, titled_key=True), - ) - self._trace_stream.write("\n") - if body is not None: - self._trace_stream.write("\n") - self._trace_stream.write(_safe_str(body)) - self._trace_stream.write("\n") - self._trace_stream.write("\n") - - http_headers = HTTPHeaderDict() - for key, value in headers.items(): - if isinstance(value, (list, tuple)): - for val in value: - http_headers.add(key, val) - else: - http_headers.add(key, value) - - response = self._http.urlopen( - method, - urlunsplit(url), - body=body, - headers=http_headers, - preload_content=preload_content, - ) - - if self._trace_stream: - self._trace_stream.write(f"HTTP/1.1 {response.status}\n") - self._trace_stream.write( - headers_to_strings(response.headers), - ) - self._trace_stream.write("\n") - if preload_content: - self._trace_stream.write("\n") - self._trace_stream.write(_safe_str(response.data)) - self._trace_stream.write("\n") - self._trace_stream.write("----------END-HTTP----------\n") - - if response.status in [200, 204, 206]: - return response - - raise MinioAdminException( - str(response.status), - _safe_str(response.data), - ) - - def set_app_info(self, app_name: str, app_version: str): - """ - Set your application name and version to user agent header. - - :param app_name: Application name. - :param app_version: Application version. - - Example:: - client.set_app_info('my_app', '1.0.2') - """ - if not (app_name and app_version): - raise ValueError("Application name/version cannot be empty.") - self._user_agent = f"{_DEFAULT_USER_AGENT} {app_name}/{app_version}" - - def trace_on(self, stream: TextIO): - """ - Enable http trace. - - :param stream: Stream for writing HTTP call tracing. - """ - if not stream: - raise ValueError('Input stream for trace output is invalid.') - # Save new output stream. - self._trace_stream = stream - - def trace_off(self): - """ - Disable HTTP trace. - """ - self._trace_stream = None - - def service_restart(self) -> str: - """Restart MinIO service.""" - response = self._url_open( - method="POST", - command=_COMMAND.SERVICE, - query_params={"action": "restart"} - ) - return response.data.decode() - - def service_stop(self) -> str: - """Stop MinIO service.""" - response = self._url_open( - method="POST", - command=_COMMAND.SERVICE, - query_params={"action": "stop"} - ) - return response.data.decode() - - def update(self) -> str: - """Update MinIO.""" - response = self._url_open( - method="POST", - command=_COMMAND.UPDATE, - query_params={"updateURL": ""} - ) - return response.data.decode() - - def info(self) -> str: - """Get MinIO server information.""" - response = self._url_open( - method="GET", - command=_COMMAND.INFO, - ) - return response.data.decode() - - def account_info(self, prefix_usage: bool = False) -> str: - """Get usage information for the authenticating account""" - response = self._url_open( - method="GET", - command=_COMMAND.ACCOUNT_INFO, - query_params={"prefix-usage": "true"} if prefix_usage else None, - ) - return response.data.decode() - - def user_add(self, access_key: str, secret_key: str) -> str: - """Create user with access and secret keys""" - body = json.dumps( - {"status": "enabled", "secretKey": secret_key}).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.ADD_USER, - query_params={"accessKey": access_key}, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def user_disable(self, access_key: str) -> str: - """Disable user.""" - response = self._url_open( - method="PUT", - command=_COMMAND.SET_USER_STATUS, - query_params={"accessKey": access_key, "status": "disabled"} - ) - return response.data.decode() - - def user_enable(self, access_key: str) -> str: - """Enable user.""" - response = self._url_open( - method="PUT", - command=_COMMAND.SET_USER_STATUS, - query_params={"accessKey": access_key, "status": "enabled"} - ) - return response.data.decode() - - def user_remove(self, access_key: str) -> str: - """Delete user""" - response = self._url_open( - method="DELETE", - command=_COMMAND.REMOVE_USER, - query_params={"accessKey": access_key}, - ) - return response.data.decode() - - def user_info(self, access_key: str) -> str: - """Get information about user""" - response = self._url_open( - method="GET", - command=_COMMAND.USER_INFO, - query_params={"accessKey": access_key}, - ) - return response.data.decode() - - def user_list(self) -> str: - """List all users""" - response = self._url_open( - method="GET", - command=_COMMAND.LIST_USERS, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def group_add(self, group_name: str, members: str) -> str: - """Add users a new or existing group.""" - body = json.dumps({ - "group": group_name, - "members": members, - "isRemove": False - }).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.ADD_UPDATE_REMOVE_GROUP, - body=body, - ) - return response.data.decode() - - def group_disable(self, group_name: str) -> str: - """Disable group.""" - response = self._url_open( - method="PUT", - command=_COMMAND.SET_GROUP_STATUS, - query_params={"group": group_name, "status": "disabled"} - ) - return response.data.decode() - - def group_enable(self, group_name: str) -> str: - """Enable group.""" - response = self._url_open( - method="PUT", - command=_COMMAND.SET_GROUP_STATUS, - query_params={"group": group_name, "status": "enabled"} - ) - return response.data.decode() - - def group_remove( - self, - group_name: str, - members: Optional[str] = None, - ) -> str: - """Remove group or members from a group.""" - data = { - "group": group_name, - "isRemove": True - } - if members is not None: - data["members"] = members - - response = self._url_open( - method="PUT", - command=_COMMAND.ADD_UPDATE_REMOVE_GROUP, - body=json.dumps(data).encode(), - ) - return response.data.decode() - - def group_info(self, group_name: str) -> str: - """Get group information.""" - response = self._url_open( - method="GET", - command=_COMMAND.GROUP_INFO, - query_params={"group": group_name}, - ) - return response.data.decode() - - def group_list(self) -> str: - """List groups.""" - response = self._url_open( - method="GET", - command=_COMMAND.LIST_GROUPS, - ) - return response.data.decode() - - def policy_add(self, - policy_name: str, - policy_file: Optional[str | os.PathLike] = None, - policy: Optional[dict] = None) -> str: - """Add new policy.""" - if not (policy_file is not None) ^ (policy is not None): - raise ValueError("either policy_file or policy must be provided") - if policy_file: - with open(policy_file, encoding='utf-8') as file: - body = file.read().encode() - else: - body = json.dumps(policy).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.ADD_CANNED_POLICY, - query_params={"name": policy_name}, - body=body, - ) - return response.data.decode() - - def policy_remove(self, policy_name: str) -> str: - """Remove policy.""" - response = self._url_open( - method="DELETE", - command=_COMMAND.REMOVE_CANNED_POLICY, - query_params={"name": policy_name}, - ) - return response.data.decode() - - def policy_info(self, policy_name: str) -> str: - """Get policy information.""" - response = self._url_open( - method="GET", - command=_COMMAND.CANNED_POLICY_INFO, - query_params={"name": policy_name}, - ) - return response.data.decode() - - def policy_list(self) -> str: - """List policies.""" - response = self._url_open( - method="GET", - command=_COMMAND.LIST_CANNED_POLICIES, - ) - return response.data.decode() - - def policy_set( - self, - policy_name: str, - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Set IAM policy on a user or group.""" - if (user is not None) ^ (group is not None): - response = self._url_open( - method="PUT", - command=_COMMAND.SET_USER_OR_GROUP_POLICY, - query_params={"userOrGroup": cast(str, user or group), - "isGroup": "true" if group else "false", - "policyName": policy_name}, - ) - return response.data.decode() - raise ValueError("either user or group must be set") - - def policy_unset( - self, - policy_name: str | list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Unset an IAM policy for a user or group.""" - return self.detach_policy( - policy_name if isinstance(policy_name, list) else [policy_name], - user, group) - - def config_get(self, key: Optional[str] = None) -> str: - """Get configuration parameters.""" - try: - response = self._url_open( - method="GET", - command=_COMMAND.GET_CONFIG, - query_params={"key": key or "", "subSys": ""}, - preload_content=False, - ) - if key is None: - return response.read().decode() - return decrypt( - response, self._provider.retrieve().secret_key, - ).decode() - finally: - if response: - response.close() - response.release_conn() - - def config_set( - self, - key: str, - config: Optional[dict[str, str]] = None, - ) -> str: - """Set configuration parameters.""" - data = [key] - if config: - data += [f"{name}={value}" for name, value in config.items()] - body = " ".join(data).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SET_CONFIG, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def config_reset(self, key: str, name: Optional[str] = None) -> str: - """Reset configuration parameters.""" - if name: - key += ":" + name - body = key.encode() - response = self._url_open( - method="DELETE", - command=_COMMAND.DELETE_CONFIG, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def config_history(self) -> str: - """Get historic configuration changes.""" - try: - response = self._url_open( - method="GET", - command=_COMMAND.LIST_CONFIG_HISTORY, - query_params={"count": "10"}, - preload_content=False, - ) - plain_text = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_text.decode() - finally: - if response: - response.close() - response.release_conn() - - def config_restore(self, restore_id: str) -> str: - """Restore to a specific configuration history.""" - response = self._url_open( - method="PUT", - command=_COMMAND.RESOTRE_CONFIG_HISTORY, - query_params={"restoreId": restore_id} - ) - return response.data.decode() - - def profile_start( - self, - profilers: tuple[str] = cast(Tuple[str], ()), - ) -> str: - """Runs a system profile""" - response = self._url_open( - method="POST", - command=_COMMAND.START_PROFILE, - query_params={"profilerType;": ",".join(profilers)}, - ) - return response.data.decode() - - def top_locks(self) -> str: - """Get a list of the 10 oldest locks on a MinIO cluster.""" - response = self._url_open( - method="GET", - command=_COMMAND.TOP_LOCKS, - ) - return response.data.decode() - - def kms_key_create(self, key: Optional[str] = None) -> str: - """Create a new KMS master key.""" - response = self._url_open( - method="POST", - command=_COMMAND.CREATE_KMS_KEY, - query_params={"key-id": key or ""}, - ) - return response.data.decode() - - def kms_key_status(self, key: Optional[str] = None) -> str: - """Get status information of a KMS master key.""" - response = self._url_open( - method="GET", - command=_COMMAND.GET_KMS_KEY_STATUS, - query_params={"key-id": key or ""} - ) - return response.data.decode() - - def add_site_replication(self, peer_sites: list[PeerSite]) -> str: - """Add peer sites to site replication.""" - body = json.dumps( - [peer_site.to_dict() for peer_site in peer_sites]).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SITE_REPLICATION_ADD, - query_params={"api-version": "1"}, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def get_site_replication_info(self) -> str: - """Get site replication information.""" - response = self._url_open( - method="GET", - command=_COMMAND.SITE_REPLICATION_INFO, - ) - return response.data.decode() - - def get_site_replication_status( - self, - options: SiteReplicationStatusOptions, - ) -> str: - """Get site replication information.""" - response = self._url_open( - method="GET", - command=_COMMAND.SITE_REPLICATION_STATUS, - query_params=cast(DictType, options.to_query_params()), - ) - return response.data.decode() - - def edit_site_replication(self, peer_info: PeerInfo) -> str: - """Edit site replication with given peer information.""" - body = json.dumps(peer_info.to_dict()).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SITE_REPLICATION_EDIT, - query_params={"api-version": "1"}, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def remove_site_replication( - self, - sites: Optional[str] = None, - all_sites: bool = False, - ) -> str: - """Remove given sites or all sites from site replication.""" - data = {} - if all_sites: - data.update({"all": "True"}) - elif sites: - data.update({"sites": sites or ""}) - else: - raise ValueError("either sites or all flag must be given") - body = json.dumps(data).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SITE_REPLICATION_REMOVE, - query_params={"api-version": "1"}, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def bucket_quota_set(self, bucket: str, size: int) -> str: - """Set bucket quota configuration.""" - body = json.dumps({"quota": size, "quotatype": "hard"}).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SET_BUCKET_QUOTA, - query_params={"bucket": bucket}, - body=body - ) - return response.data.decode() - - def bucket_quota_clear(self, bucket: str) -> str: - """Clear bucket quota configuration.""" - return self.bucket_quota_set(bucket, 0) - - def bucket_quota_get(self, bucket: str) -> str: - """Get bucket quota configuration.""" - response = self._url_open( - method="GET", - command=_COMMAND.GET_BUCKET_QUOTA, - query_params={"bucket": bucket} - ) - return response.data.decode() - - def get_data_usage_info(self): - """Get data usage info""" - response = self._url_open( - method="GET", - command=_COMMAND.DATA_USAGE_INFO, - ) - return response.data.decode() - - def get_service_account(self, access_key: str) -> str: - """Get information about service account""" - response = self._url_open( - method="GET", - command=_COMMAND.SERVICE_ACCOUNT_INFO, - query_params={"accessKey": access_key}, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def list_service_account(self, user: str) -> str: - """List service accounts of user""" - response = self._url_open( - method="GET", - command=_COMMAND.SERVICE_ACCOUNT_LIST, - query_params={"user": user}, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def add_service_account(self, - *, - access_key: Optional[str] = None, - secret_key: Optional[str] = None, - name: Optional[str] = None, - description: Optional[str] = None, - policy: Optional[dict] = None, - policy_file: Optional[str | os.PathLike] = None, - expiration: Optional[str] = None, - status: Optional[str] = None) -> str: - """ - Add a new service account with the given access key and secret key - """ - if (access_key is None) ^ (secret_key is None): - raise ValueError("both access key and secret key must be provided") - if access_key == "" or secret_key == "": - raise ValueError("access key or secret key must not be empty") - if policy_file is not None and policy is not None: - raise ValueError("either policy_file or policy must be provided") - data: dict[str, Any] = { - "status": "enabled", - "accessKey": access_key, - "secretKey": secret_key, - } - if name: - data["name"] = name - if description: - data["description"] = description - if policy_file: - with open(policy_file, encoding="utf-8") as file: - data["policy"] = json.load(file) - if policy: - data["policy"] = policy - if expiration: - data["expiration"] = expiration - if status: - data["status"] = status - - body = json.dumps(data).encode() - response = self._url_open( - method="PUT", - command=_COMMAND.SERVICE_ACCOUNT_ADD, - body=encrypt(body, self._provider.retrieve().secret_key), - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def update_service_account(self, - *, - access_key: str, - secret_key: Optional[str] = None, - name: Optional[str] = None, - description: Optional[str] = None, - policy_file: Optional[str | os.PathLike] = None, - policy: Optional[dict] = None, - expiration: Optional[str] = None, - status: Optional[str] = None) -> str: - """Update an existing service account""" - args = [secret_key, name, description, - policy_file, policy, expiration, status] - if not any(arg for arg in args): - raise ValueError("at least one of secret_key, name, description, " - "policy_file, policy, expiration or status must " - "be specified") - if policy_file is not None and policy is not None: - raise ValueError("either policy_file or policy must be provided") - data: dict[str, Any] = {} - if secret_key: - data["newSecretKey"] = secret_key - if name: - data["newName"] = name - if description: - data["newDescription"] = description - if policy_file: - with open(policy_file, encoding="utf-8") as file: - data["newPolicy"] = json.load(file) - if policy: - data["newPolicy"] = policy - if expiration: - data["newExpiration"] = expiration - if status: - data["newStatus"] = status - - body = json.dumps(data).encode() - response = self._url_open( - method="POST", - command=_COMMAND.SERVICE_ACCOUNT_UPDATE, - query_params={"accessKey": access_key}, - body=encrypt(body, self._provider.retrieve().secret_key), - ) - return response.data.decode() - - def delete_service_account(self, access_key: str) -> str: - """Delete a service account""" - response = self._url_open( - method="DELETE", - command=_COMMAND.SERVICE_ACCOUNT_DELETE, - query_params={"accessKey": access_key}, - ) - return response.data.decode() - - def _attach_detach_policy( - self, - command: _COMMAND, - policies: list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Attach or detach policies for builtin or LDAP.""" - if (user is not None) ^ (group is not None): - key = "user" if user else "group" - body = json.dumps( - {"policies": policies, - key: cast(str, user or group)}, - ).encode() - response = self._url_open( - method="POST", - command=command, - body=encrypt(body, self._provider.retrieve().secret_key), - preload_content=False, - ) - if ( - command in [ - _COMMAND.IDP_BUILTIN_POLICY_ATTACH, - _COMMAND.IDP_BUILTIN_POLICY_DETACH, - ] and - response.status in [201, 204] - ): - # Older MinIO servers do not return response. - response.close() - response.release_conn() - return "" - data = decrypt(response, self._provider.retrieve().secret_key) - return data.decode() - raise ValueError("either user or group must be set") - - def attach_policy_ldap( - self, - policies: list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Attach policies for LDAP.""" - return self._attach_detach_policy( - _COMMAND.IDP_LDAP_POLICY_ATTACH, policies, user, group, - ) - - def detach_policy_ldap( - self, - policies: list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Detach policies for LDAP.""" - return self._attach_detach_policy( - _COMMAND.IDP_LDAP_POLICY_DETACH, policies, user, group, - ) - - def list_access_keys_ldap( - self, - user_dn: str, - list_type: str, - ) -> str: - """List service accounts belonging to the specified user.""" - response = self._url_open( - method="GET", - command=_COMMAND.IDP_LDAP_LIST_ACCESS_KEYS, - query_params={"userDN": user_dn, "listType": list_type}, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def list_access_keys_ldap_bulk( - self, - users: list[str], - list_type: str, - all_users: bool, - ) -> str: - """List access keys belonging to the given users or all users.""" - if len(users) != 0 and all_users: - raise ValueError("both users and all_users are not permitted") - - key, value = ("all", "true") if all_users else ("userDNs", users) - response = self._url_open( - method="GET", - command=_COMMAND.IDP_LDAP_LIST_ACCESS_KEYS_BULK, - query_params={"listType": list_type, key: value}, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() - - def attach_policy( - self, - policies: list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Attach builtin policies.""" - return self._attach_detach_policy( - _COMMAND.IDP_BUILTIN_POLICY_ATTACH, policies, user, group, - ) - - def detach_policy( - self, - policies: list[str], - user: Optional[str] = None, - group: Optional[str] = None, - ) -> str: - """Detach builtin policies.""" - return self._attach_detach_policy( - _COMMAND.IDP_BUILTIN_POLICY_DETACH, policies, user, group, - ) - - def get_policy_entities( - self, - users: list[str], - groups: list[str], - policies: list[str], - ) -> str: - """Get builtin policy entities.""" - response = self._url_open( - method="GET", - command=_COMMAND.IDP_BUILTIN_POLICY_ENTITIES, - query_params={"user": users, "group": groups, "policy": policies}, - preload_content=False, - ) - plain_data = decrypt( - response, self._provider.retrieve().secret_key, - ) - return plain_data.decode() diff --git a/backend/venv39/lib/python3.9/site-packages/minio/notificationconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/notificationconfig.py deleted file mode 100644 index bdf6ee1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/notificationconfig.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Request/response of PutBucketNotificationConfiguration and -GetBucketNotiicationConfiguration APIs. -""" - -from __future__ import absolute_import, annotations - -from abc import ABC -from dataclasses import dataclass, field -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .xml import Element, SubElement, find, findall, findtext - -A = TypeVar("A", bound="FilterRule") - - -@dataclass(frozen=True) -class FilterRule(ABC): - """Filter rule.""" - - name: str - value: str - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - name = cast(str, findtext(element, "Name", True)) - value = cast(str, findtext(element, "Value", True)) - return cls(name, value) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "FilterRule") - SubElement(element, "Name", self.name) - SubElement(element, "Value", self.value) - return element - - -@dataclass(frozen=True) -class PrefixFilterRule(FilterRule): - """Prefix filter rule.""" - - def __init__(self, value: str): - super().__init__(name="prefix", value=value) - - -@dataclass(frozen=True) -class SuffixFilterRule(FilterRule): - """Suffix filter rule.""" - - def __init__(self, value: str): - super().__init__(name="suffix", value=value) - - -@dataclass(frozen=True) -class CommonConfig(ABC): - """Common for cloud-function/queue/topic configuration.""" - - events: list[str] - config_id: Optional[str] = None - prefix_filter_rule: Optional[PrefixFilterRule] = None - suffix_filter_rule: Optional[SuffixFilterRule] = None - - def __post_init__(self): - if not self.events: - raise ValueError("events must be provided") - - @staticmethod - def parsexml( - element: ET.Element, - ) -> tuple[ - list[str], - Optional[str], - Optional[PrefixFilterRule], - Optional[SuffixFilterRule], - ]: - """Parse XML.""" - elements = findall(element, "Event") - events = [] - for tag in elements: - if tag.text is None: - raise ValueError("missing value in XML tag 'Event'") - events.append(tag.text) - config_id = findtext(element, "Id") - elem = find(element, "Filter") - if elem is None: - return events, config_id, None, None - prefix_filter_rule = None - suffix_filter_rule = None - elem = cast(ET.Element, find(elem, "S3Key", True)) - elements = findall(elem, "FilterRule") - for tag in elements: - filter_rule = FilterRule.fromxml(tag) - if filter_rule.name == "prefix": - prefix_filter_rule = PrefixFilterRule(filter_rule.value) - else: - suffix_filter_rule = SuffixFilterRule(filter_rule.value) - return events, config_id, prefix_filter_rule, suffix_filter_rule - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - for event in self.events: - SubElement(element, "Event", event) - if self.config_id is not None: - SubElement(element, "Id", self.config_id) - if self.prefix_filter_rule or self.suffix_filter_rule: - rule = SubElement(element, "Filter") - rule = SubElement(rule, "S3Key") - if self.prefix_filter_rule: - self.prefix_filter_rule.toxml(rule) - if self.suffix_filter_rule: - self.suffix_filter_rule.toxml(rule) - return element - - -B = TypeVar("B", bound="CloudFuncConfig") - - -@dataclass(frozen=True) -class CloudFuncConfig(CommonConfig): - """Cloud function configuration.""" - cloud_func: Optional[str] = None - - def __post_init__(self): - if not self.cloud_func: - raise ValueError("cloud function must be provided") - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - cloud_func = cast(str, findtext(element, "CloudFunction", True)) - (events, config_id, prefix_filter_rule, - suffix_filter_rule) = cls.parsexml(element) - return cls( - cloud_func=cloud_func, - events=events, - config_id=config_id, - prefix_filter_rule=prefix_filter_rule, - suffix_filter_rule=suffix_filter_rule, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "CloudFunctionConfiguration") - SubElement(element, "CloudFunction", self.cloud_func) - super().toxml(element) - return element - - -C = TypeVar("C", bound="QueueConfig") - - -@dataclass(frozen=True) -class QueueConfig(CommonConfig): - """Queue configuration.""" - queue: Optional[str] = None - - def __post_init__(self): - if not self.queue: - raise ValueError("queue must be provided") - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - queue = cast(str, findtext(element, "Queue", True)) - (events, config_id, prefix_filter_rule, - suffix_filter_rule) = cls.parsexml(element) - return cls( - queue=queue, - events=events, - config_id=config_id, - prefix_filter_rule=prefix_filter_rule, - suffix_filter_rule=suffix_filter_rule, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "QueueConfiguration") - SubElement(element, "Queue", self.queue) - super().toxml(element) - return element - - -D = TypeVar("D", bound="TopicConfig") - - -@dataclass(frozen=True) -class TopicConfig(CommonConfig): - """Get topic configuration.""" - topic: Optional[str] = None - - def __post_init__(self): - if not self.topic: - raise ValueError("topic must be provided") - - @classmethod - def fromxml(cls: Type[D], element: ET.Element) -> D: - """Create new object with values from XML element.""" - topic = cast(str, findtext(element, "Topic", True)) - (events, config_id, prefix_filter_rule, - suffix_filter_rule) = cls.parsexml(element) - return cls( - topic=topic, - events=events, - config_id=config_id, - prefix_filter_rule=prefix_filter_rule, - suffix_filter_rule=suffix_filter_rule, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "TopicConfiguration") - SubElement(element, "Topic", self.topic) - super().toxml(element) - return element - - -E = TypeVar("E", bound="NotificationConfig") - - -@dataclass(frozen=True) -class NotificationConfig: - """Notification configuration.""" - cloud_func_config_list: list[CloudFuncConfig] = field(default_factory=list) - queue_config_list: list[QueueConfig] = field(default_factory=list) - topic_config_list: list[TopicConfig] = field(default_factory=list) - - @classmethod - def fromxml(cls: Type[E], element: ET.Element) -> E: - """Create new object with values from XML element.""" - elements = findall(element, "CloudFunctionConfiguration") - cloud_func_config_list = [] - for tag in elements: - cloud_func_config_list.append(CloudFuncConfig.fromxml(tag)) - elements = findall(element, "QueueConfiguration") - queue_config_list = [] - for tag in elements: - queue_config_list.append(QueueConfig.fromxml(tag)) - elements = findall(element, "TopicConfiguration") - topic_config_list = [] - for tag in elements: - topic_config_list.append(TopicConfig.fromxml(tag)) - return cls( - cloud_func_config_list, queue_config_list, topic_config_list, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("NotificationConfiguration") - for cloud_func_config in self.cloud_func_config_list: - cloud_func_config.toxml(element) - for queue_config in self.queue_config_list: - queue_config.toxml(element) - for config in self.topic_config_list: - config.toxml(element) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/objectlockconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/objectlockconfig.py deleted file mode 100644 index 3da29bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/objectlockconfig.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Request/response of PutObjectLockConfiguration and GetObjectLockConfiguration -APIs. -""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .commonconfig import COMPLIANCE, ENABLED, GOVERNANCE -from .xml import Element, SubElement, find, findtext - -DAYS = "Days" -YEARS = "Years" - -A = TypeVar("A", bound="ObjectLockConfig") - - -@dataclass(frozen=True) -class ObjectLockConfig: - """Object lock configuration.""" - - mode: Optional[str] - duration: Optional[int] - duration_unit: Optional[str] - - def __post_init__(self): - if (self.mode is not None) ^ (self.duration is not None): - if self.mode is None: - raise ValueError("mode must be provided") - raise ValueError("duration must be provided") - if self.mode is not None and self.mode not in [GOVERNANCE, COMPLIANCE]: - raise ValueError(f"mode must be {GOVERNANCE} or {COMPLIANCE}") - if ( - self.duration is not None and - self.duration_unit not in [DAYS, YEARS] - ): - raise ValueError(f"duration unit must be {DAYS} or {YEARS}") - if self.duration_unit: - object.__setattr__( - self, "duration_unit", self.duration_unit.title(), - ) - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - elem = find(element, "Rule") - if elem is None: - return cls(None, None, None) - elem = cast(ET.Element, find(elem, "DefaultRetention", True)) - mode = findtext(elem, "Mode") - duration_unit = DAYS - duration = findtext(elem, duration_unit) - if not duration: - duration_unit = YEARS - duration = findtext(elem, duration_unit) - if not duration: - raise ValueError(f"XML element <{DAYS}> or <{YEARS}> not found") - return cls( - mode=mode, - duration=int(duration), - duration_unit=duration_unit, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("ObjectLockConfiguration") - SubElement(element, "ObjectLockEnabled", ENABLED) - if self.mode: - rule = SubElement(element, "Rule") - retention = SubElement(rule, "DefaultRetention") - SubElement(retention, "Mode", self.mode) - if not self.duration_unit: - raise ValueError("duration unit must be provided") - SubElement(retention, self.duration_unit, str(self.duration)) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/py.typed b/backend/venv39/lib/python3.9/site-packages/minio/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/minio/replicationconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/replicationconfig.py deleted file mode 100644 index 885f04e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/replicationconfig.py +++ /dev/null @@ -1,437 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of PutBucketReplication and GetBucketReplication APIs.""" - -from __future__ import absolute_import, annotations - -from abc import ABC -from dataclasses import dataclass -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .commonconfig import DISABLED, BaseRule, Filter, check_status -from .xml import Element, SubElement, find, findall, findtext - -A = TypeVar("A", bound="Status") - - -@dataclass(frozen=True) -class Status(ABC): - """Status.""" - - status: str - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, cls.__name__, True)) - status = cast(str, findtext(element, "Status", True)) - return cls(status) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, self.__class__.__name__) - SubElement(element, "Status", self.status) - return element - - -@dataclass(frozen=True) -class SseKmsEncryptedObjects(Status): - """SSE KMS encrypted objects.""" - - -B = TypeVar("B", bound="SourceSelectionCriteria") - - -@dataclass(frozen=True) -class SourceSelectionCriteria: - """Source selection criteria.""" - - sse_kms_encrypted_objects: Optional[SseKmsEncryptedObjects] = None - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "SourceSelectionCriteria", True), - ) - return cls( - None if find(element, "SseKmsEncryptedObjects") is None - else SseKmsEncryptedObjects.fromxml(element) - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "SourceSelectionCriteria") - if self.sse_kms_encrypted_objects: - self.sse_kms_encrypted_objects.toxml(element) - return element - - -@dataclass(frozen=True) -class ExistingObjectReplication(Status): - """Existing object replication.""" - - -@dataclass(frozen=True) -class DeleteMarkerReplication(Status): - """Delete marker replication.""" - - def __init__(self, status=DISABLED): - super().__init__(status) - - -C = TypeVar("C", bound="ReplicationTimeValue") - - -@dataclass(frozen=True) -class ReplicationTimeValue(ABC): - """Replication time value.""" - - minutes: Optional[int] = 15 - - @classmethod - def fromxml(cls: Type[C], element: ET.Element) -> C: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, cls.__name__, True)) - minutes = findtext(element, "Minutes") - return cls(int(minutes) if minutes else None) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, self.__class__.__name__) - if self.minutes is not None: - SubElement(element, "Minutes", str(self.minutes)) - return element - - -@dataclass(frozen=True) -class Time(ReplicationTimeValue): - """Time.""" - - -D = TypeVar("D", bound="ReplicationTime") - - -@dataclass(frozen=True) -class ReplicationTime: - """Replication time.""" - - time: Time - status: str - - def __post_init__(self,): - if not self.time: - raise ValueError("time must be provided") - check_status(self.status) - - @classmethod - def fromxml(cls: Type[D], element: ET.Element) -> D: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "ReplicationTime", True)) - time = Time.fromxml(element) - status = cast(str, findtext(element, "Status", True)) - return cls(time, status) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "ReplicationTime") - self.time.toxml(element) - SubElement(element, "Status", self.status) - return element - - -@dataclass(frozen=True) -class EventThreshold(ReplicationTimeValue): - """Event threshold.""" - - -E = TypeVar("E", bound="Metrics") - - -@dataclass(frozen=True) -class Metrics: - """Metrics.""" - - event_threshold: EventThreshold - status: str - - def __post_init__(self): - if not self.event_threshold: - raise ValueError("event threshold must be provided") - check_status(self.status) - - @classmethod - def fromxml(cls: Type[E], element: ET.Element) -> E: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Metrics", True)) - event_threshold = EventThreshold.fromxml(element) - status = cast(str, findtext(element, "Status", True)) - return cls(event_threshold, status) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Metrics") - self.event_threshold.toxml(element) - SubElement(element, "Status", self.status) - return element - - -F = TypeVar("F", bound="EncryptionConfig") - - -@dataclass(frozen=True) -class EncryptionConfig: - """Encryption configuration.""" - - replica_kms_key_id: Optional[str] = None - - @classmethod - def fromxml(cls: Type[F], element: ET.Element) -> F: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "EncryptionConfiguration", True), - ) - return cls(findtext(element, "ReplicaKmsKeyID")) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "EncryptionConfiguration") - SubElement(element, "ReplicaKmsKeyID", self.replica_kms_key_id) - return element - - -G = TypeVar("G", bound="AccessControlTranslation") - - -@dataclass(frozen=True) -class AccessControlTranslation: - """Access control translation.""" - - owner: str = "Destination" - - def __post_init__(self): - if not self.owner: - raise ValueError("owner must be provided") - - @classmethod - def fromxml(cls: Type[G], element: ET.Element) -> G: - """Create new object with values from XML element.""" - element = cast( - ET.Element, find(element, "AccessControlTranslation", True), - ) - owner = cast(str, findtext(element, "Owner", True)) - return cls(owner) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "AccessControlTranslation") - SubElement(element, "Owner", self.owner) - return element - - -H = TypeVar("H", bound="Destination") - - -@dataclass(frozen=True) -class Destination: - """Replication destination.""" - - bucket_arn: str - access_control_translation: Optional[AccessControlTranslation] = None - account: Optional[str] = None - encryption_config: Optional[EncryptionConfig] = None - metrics: Optional[Metrics] = None - replication_time: Optional[ReplicationTime] = None - storage_class: Optional[str] = None - - def __post_init__(self): - if not self.bucket_arn: - raise ValueError("bucket ARN must be provided") - - @classmethod - def fromxml(cls: Type[H], element: ET.Element) -> H: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Destination", True)) - access_control_translation = ( - None if find(element, "AccessControlTranslation") is None - else AccessControlTranslation.fromxml(element) - ) - account = findtext(element, "Account") - bucket_arn = cast(str, findtext(element, "Bucket", True)) - encryption_config = ( - None if find(element, "EncryptionConfiguration") is None - else EncryptionConfig.fromxml(element) - ) - metrics = ( - None if find(element, "Metrics") is None - else Metrics.fromxml(element) - ) - replication_time = ( - None if find(element, "ReplicationTime") is None - else ReplicationTime.fromxml(element) - ) - storage_class = findtext(element, "StorageClass") - return cls(bucket_arn, access_control_translation, account, - encryption_config, metrics, replication_time, storage_class) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Destination") - if self.access_control_translation: - self.access_control_translation.toxml(element) - if self.account is not None: - SubElement(element, "Account", self.account) - SubElement(element, "Bucket", self.bucket_arn) - if self.encryption_config: - self.encryption_config.toxml(element) - if self.metrics: - self.metrics.toxml(element) - if self.replication_time: - self.replication_time.toxml(element) - if self.storage_class: - SubElement(element, "StorageClass", self.storage_class) - return element - - -I = TypeVar("I", bound="Rule") - - -@dataclass(frozen=True) -class Rule(BaseRule): - """Replication rule. """ - - destination: Optional[Destination] = None - delete_marker_replication: Optional[DeleteMarkerReplication] = None - existing_object_replication: Optional[ExistingObjectReplication] = None - rule_filter: Optional[Filter] = None - rule_id: Optional[str] = None - prefix: Optional[str] = None - priority: Optional[int] = None - source_selection_criteria: Optional[SourceSelectionCriteria] = None - - def __post_init__(self): - if not self.destination: - raise ValueError("destination must be provided") - - def _require_subclass_implementation(self) -> None: - """Dummy abstract method to enforce abstract class behavior.""" - - @classmethod - def fromxml(cls: Type[I], element: ET.Element) -> I: - """Create new object with values from XML element.""" - status, rule_filter, rule_id = cls.parsexml(element) - delete_marker_replication = ( - None if find(element, "DeleteMarkerReplication") is None - else DeleteMarkerReplication.fromxml(element) - ) - destination = Destination.fromxml(element) - existing_object_replication = ( - None if find(element, "ExistingObjectReplication") is None - else ExistingObjectReplication.fromxml(element) - ) - prefix = findtext(element, "Prefix") - priority = findtext(element, "Priority") - source_selection_criteria = ( - None if find(element, "SourceSelectionCriteria") is None - else SourceSelectionCriteria.fromxml(element) - ) - - return cls( - status=status, - rule_filter=rule_filter, - rule_id=rule_id, - destination=destination, - delete_marker_replication=delete_marker_replication, - existing_object_replication=existing_object_replication, - prefix=prefix, - priority=int(priority) if priority else None, - source_selection_criteria=source_selection_criteria, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Rule") - super().toxml(element) - if self.delete_marker_replication: - self.delete_marker_replication.toxml(element) - if self.destination: - self.destination.toxml(element) - if self.existing_object_replication: - self.existing_object_replication.toxml(element) - if self.prefix is not None: - SubElement(element, "Prefix", self.prefix) - if self.priority is not None: - SubElement(element, "Priority", str(self.priority)) - if self.source_selection_criteria: - self.source_selection_criteria.toxml(element) - return element - - -J = TypeVar("J", bound="ReplicationConfig") - - -@dataclass(frozen=True) -class ReplicationConfig: - """Replication configuration.""" - - role: str - rules: list[Rule] - - def __post_init__(self): - if not self.rules: - raise ValueError("rules must be provided") - if len(self.rules) > 1000: - raise ValueError("more than 1000 rules are not supported") - - @classmethod - def fromxml(cls: Type[J], element: ET.Element) -> J: - """Create new object with values from XML element.""" - role = cast(str, findtext(element, "Role", True)) - elements = findall(element, "Rule") - rules = [] - for tag in elements: - rules.append(Rule.fromxml(tag)) - return cls(role, rules) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("ReplicationConfiguration") - SubElement(element, "Role", self.role) - for rule in self.rules: - rule.toxml(element) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/retention.py b/backend/venv39/lib/python3.9/site-packages/minio/retention.py deleted file mode 100644 index d7c5f08..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/retention.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of PutObjectRetention and GetObjectRetention APIs.""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from datetime import datetime -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .commonconfig import COMPLIANCE, GOVERNANCE -from .time import from_iso8601utc, to_iso8601utc -from .xml import Element, SubElement, findtext - -A = TypeVar("A", bound="Retention") - - -@dataclass(frozen=True) -class Retention: - """Retention configuration.""" - - mode: str - retain_until_date: datetime - - def __post_init__(self): - if self.mode not in [GOVERNANCE, COMPLIANCE]: - raise ValueError(f"mode must be {GOVERNANCE} or {COMPLIANCE}") - if not isinstance(self.retain_until_date, datetime): - raise ValueError( - "retain until date must be datetime type", - ) - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - mode = cast(str, findtext(element, "Mode", True)) - retain_until_date = cast( - datetime, - from_iso8601utc( - cast(str, findtext(element, "RetainUntilDate", True)), - ), - ) - return cls(mode=mode, retain_until_date=retain_until_date) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("Retention") - SubElement(element, "Mode", self.mode) - SubElement( - element, - "RetainUntilDate", - to_iso8601utc(self.retain_until_date), - ) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/select.py b/backend/venv39/lib/python3.9/site-packages/minio/select.py deleted file mode 100644 index 9f25fd8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/select.py +++ /dev/null @@ -1,417 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of SelectObjectContent API.""" - -from __future__ import absolute_import - -from abc import ABC, abstractmethod -from binascii import crc32 -from dataclasses import dataclass -from io import BytesIO -from typing import Optional -from xml.etree import ElementTree as ET - -from .error import MinioException -from .xml import Element, SubElement, findtext - -COMPRESSION_TYPE_NONE = "NONE" -COMPRESSION_TYPE_GZIP = "GZIP" -COMPRESSION_TYPE_BZIP2 = "BZIP2" - -FILE_HEADER_INFO_USE = "USE" -FILE_HEADER_INFO_IGNORE = "IGNORE" -FILE_HEADER_INFO_NONE = "NONE" - -JSON_TYPE_DOCUMENT = "DOCUMENT" -JSON_TYPE_LINES = "LINES" - -QUOTE_FIELDS_ALWAYS = "ALWAYS" -QUOTE_FIELDS_ASNEEDED = "ASNEEDED" - - -@dataclass(frozen=True) -class InputSerialization(ABC): - """Input serialization.""" - - compression_type: Optional[str] = None - - def __post_init__(self): - if ( - self.compression_type is not None and - self.compression_type not in [ - COMPRESSION_TYPE_NONE, - COMPRESSION_TYPE_GZIP, - COMPRESSION_TYPE_BZIP2, - ] - ): - raise ValueError( - f"compression type must be {COMPRESSION_TYPE_NONE}, " - f"{COMPRESSION_TYPE_GZIP} or {COMPRESSION_TYPE_BZIP2}" - ) - - def toxml(self, element): - """Convert to XML.""" - if self.compression_type is not None: - SubElement(element, "CompressionType", self.compression_type) - return element - - -@dataclass(frozen=True) -class CSVInputSerialization(InputSerialization): - """CSV input serialization.""" - - allow_quoted_record_delimiter: Optional[str] = None - comments: Optional[str] = None - field_delimiter: Optional[str] = None - file_header_info: Optional[str] = None - quote_character: Optional[str] = None - quote_escape_character: Optional[str] = None - record_delimiter: Optional[str] = None - - def __post_init__(self): - if ( - self.file_header_info is not None and - self.file_header_info not in [ - FILE_HEADER_INFO_USE, - FILE_HEADER_INFO_IGNORE, - FILE_HEADER_INFO_NONE, - ] - ): - raise ValueError( - f"file header info must be {FILE_HEADER_INFO_USE}, " - f"{FILE_HEADER_INFO_IGNORE} or {FILE_HEADER_INFO_NONE}" - ) - - def toxml(self, element): - """Convert to XML.""" - super().toxml(element) - element = SubElement(element, "CSV") - if self.allow_quoted_record_delimiter is not None: - SubElement( - element, - "AllowQuotedRecordDelimiter", - self.allow_quoted_record_delimiter, - ) - if self.comments is not None: - SubElement(element, "Comments", self.comments) - if self.field_delimiter is not None: - SubElement(element, "FieldDelimiter", self.field_delimiter) - if self.file_header_info is not None: - SubElement(element, "FileHeaderInfo", self.file_header_info) - if self.quote_character is not None: - SubElement(element, "QuoteCharacter", self.quote_character) - if self.quote_escape_character is not None: - SubElement( - element, - "QuoteEscapeCharacter", - self.quote_escape_character, - ) - if self.record_delimiter is not None: - SubElement(element, "RecordDelimiter", self.record_delimiter) - - -@dataclass(frozen=True) -class JSONInputSerialization(InputSerialization): - """JSON input serialization.""" - - json_type: Optional[str] = None - - def __post_init__(self): - if ( - self.json_type is not None and - self.json_type not in [JSON_TYPE_DOCUMENT, JSON_TYPE_LINES] - ): - raise ValueError( - f"json type must be {JSON_TYPE_DOCUMENT} or {JSON_TYPE_LINES}" - ) - - def toxml(self, element): - """Convert to XML.""" - super().toxml(element) - element = SubElement(element, "JSON") - if self.json_type is not None: - SubElement(element, "Type", self.json_type) - - -@dataclass(frozen=True) -class ParquetInputSerialization(InputSerialization): - """Parquet input serialization.""" - - def toxml(self, element): - """Convert to XML.""" - super().toxml(element) - return SubElement(element, "Parquet") - - -@dataclass(frozen=True) -class OutputSerialization(ABC): - """Output serialization.""" - - @abstractmethod - def toxml(self, element): - """Convert to XML.""" - - -@dataclass(frozen=True) -class CSVOutputSerialization(OutputSerialization): - """CSV output serialization.""" - - field_delimiter: Optional[str] = None - quote_character: Optional[str] = None - quote_escape_character: Optional[str] = None - quote_fields: Optional[str] = None - record_delimiter: Optional[str] = None - - def __post_init__(self): - if ( - self.quote_fields is not None and - self.quote_fields not in [ - QUOTE_FIELDS_ALWAYS, QUOTE_FIELDS_ASNEEDED, - ] - ): - raise ValueError( - f"quote fields must be {QUOTE_FIELDS_ALWAYS} or " - f"{QUOTE_FIELDS_ASNEEDED}" - ) - - def toxml(self, element): - """Convert to XML.""" - element = SubElement(element, "CSV") - if self.field_delimiter is not None: - SubElement(element, "FieldDelimiter", self.field_delimiter) - if self.quote_character is not None: - SubElement(element, "QuoteCharacter", self.quote_character) - if self.quote_escape_character is not None: - SubElement( - element, - "QuoteEscapeCharacter", - self.quote_escape_character, - ) - if self.quote_fields is not None: - SubElement(element, "QuoteFields", self.quote_fields) - if self.record_delimiter is not None: - SubElement(element, "RecordDelimiter", self.record_delimiter) - - -@dataclass(frozen=True) -class JSONOutputSerialization(OutputSerialization): - """JSON output serialization.""" - - record_delimiter: Optional[str] = None - - def toxml(self, element): - """Convert to XML.""" - element = SubElement(element, "JSON") - if self.record_delimiter is not None: - SubElement(element, "RecordDelimiter", self.record_delimiter) - - -@dataclass(frozen=True) -class SelectRequest: - """Select object content request.""" - - expression: str - input_serialization: InputSerialization - output_serialization: OutputSerialization - request_progress: bool = False - scan_start_range: Optional[int] = None - scan_end_range: Optional[int] = None - - def toxml(self, element): - """Convert to XML.""" - element = Element("SelectObjectContentRequest") - SubElement(element, "Expression", self.expression) - SubElement(element, "ExpressionType", "SQL") - self.input_serialization.toxml( - SubElement(element, "InputSerialization"), - ) - self.output_serialization.toxml( - SubElement(element, "OutputSerialization"), - ) - if self.request_progress: - SubElement( - SubElement(element, "RequestProgress"), "Enabled", "true", - ) - if self.scan_start_range or self.scan_end_range: - tag = SubElement(element, "ScanRange") - if self.scan_start_range: - SubElement(tag, "Start", self.scan_start_range) - if self.scan_end_range: - SubElement(tag, "End", self.scan_end_range) - return element - - -def _read(reader, size): - """Wrapper to RawIOBase.read() to error out on short reads.""" - data = reader.read(size) - if len(data) != size: - raise IOError("insufficient data") - return data - - -def _int(data): - """Convert byte data to big-endian int.""" - return int.from_bytes(data, byteorder="big") - - -def _crc32(data): - """Wrapper to binascii.crc32().""" - return crc32(data) & 0xffffffff - - -def _decode_header(data): - """Decode header data.""" - reader = BytesIO(data) - headers = {} - while True: - length = reader.read(1) - if not length: - break - name = _read(reader, _int(length)) - if _int(_read(reader, 1)) != 7: - raise IOError("header value type is not 7") - value = _read(reader, _int(_read(reader, 2))) - headers[name.decode()] = value.decode() - return headers - - -@dataclass(frozen=True) -class Stats: - """Progress/Stats information.""" - - bytes_scanned: Optional[str] = None - bytes_processed: Optional[str] = None - bytes_returned: Optional[str] = None - - def __init__(self, data): - element = ET.fromstring(data.decode()) - object.__setattr__( - self, - "bytes_scanned", - findtext(element, "BytesScanned"), - ) - object.__setattr__( - self, - "bytes_processed", - findtext(element, "BytesProcessed"), - ) - object.__setattr__( - self, - "bytes_returned", - findtext(element, "BytesReturned"), - ) - - -class SelectObjectReader: - """ - BufferedIOBase compatible reader represents response data of - Minio.select_object_content() API. - """ - - def __init__(self, response): - self._response = response - self._stats = None - self._payload = None - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_traceback): - return self.close() - - def readable(self): # pylint: disable=no-self-use - """Return this is readable.""" - return True - - def writeable(self): # pylint: disable=no-self-use - """Return this is not writeable.""" - return False - - def close(self): - """Close response and release network resources.""" - self._response.close() - self._response.release_conn() - - def stats(self): - """Get stats information.""" - return self._stats - - def _read(self): - """Read and decode response.""" - if self._response.isclosed(): - return 0 - - prelude = _read(self._response, 8) - prelude_crc = _read(self._response, 4) - if _crc32(prelude) != _int(prelude_crc): - raise IOError( - f"prelude CRC mismatch; expected: {_crc32(prelude)}, " - f"got: {_int(prelude_crc)}" - ) - - total_length = _int(prelude[:4]) - data = _read(self._response, total_length - 8 - 4 - 4) - message_crc = _int(_read(self._response, 4)) - if _crc32(prelude + prelude_crc + data) != message_crc: - raise IOError( - f"message CRC mismatch; " - f"expected: {_crc32(prelude + prelude_crc + data)}, " - f"got: {message_crc}" - ) - - header_length = _int(prelude[4:]) - headers = _decode_header(data[:header_length]) - - if headers.get(":message-type") == "error": - raise MinioException( - f"{headers.get(':error-code')}: " - f"{headers.get(':error-message')}" - ) - - if headers.get(":event-type") == "End": - return 0 - - payload_length = total_length - header_length - 16 - if headers.get(":event-type") == "Cont" or payload_length < 1: - return self._read() - - payload = data[header_length:header_length+payload_length] - - if headers.get(":event-type") in ["Progress", "Stats"]: - self._stats = Stats(payload) - return self._read() - - if headers.get(":event-type") == "Records": - self._payload = payload - return len(payload) - - raise MinioException( - f"unknown event-type {headers.get(':event-type')}", - ) - - def stream(self, num_bytes=32*1024): - """ - Stream extracted payload from response data. Upon completion, caller - should call self.close() to release network resources. - """ - while self._read() > 0: - while self._payload: - result = self._payload - if num_bytes < len(self._payload): - result = self._payload[:num_bytes] - self._payload = self._payload[len(result):] - yield result diff --git a/backend/venv39/lib/python3.9/site-packages/minio/signer.py b/backend/venv39/lib/python3.9/site-packages/minio/signer.py deleted file mode 100644 index 58b0dbc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/signer.py +++ /dev/null @@ -1,354 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2015-2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -""" -minio.signer -~~~~~~~~~~~~~~~ - -This module implements all helpers for AWS Signature version '4' support. - -:copyright: (c) 2015 by MinIO, Inc. -:license: Apache 2.0, see LICENSE for more details. - -""" - -from __future__ import absolute_import, annotations - -import hashlib -import hmac -import re -from collections import OrderedDict -from datetime import datetime -from typing import Mapping, cast -from urllib.parse import SplitResult - -from . import time -from .credentials import Credentials -from .helpers import DictType, queryencode, sha256_hash - -SIGN_V4_ALGORITHM = 'AWS4-HMAC-SHA256' -_MULTI_SPACE_REGEX = re.compile(r"( +)") - - -def _hmac_hash( - key: bytes, - data: bytes, - hexdigest: bool = False, -) -> bytes | str: - """Return HMacSHA256 digest of given key and data.""" - - hasher = hmac.new(key, data, hashlib.sha256) - return hasher.hexdigest() if hexdigest else hasher.digest() - - -def _get_scope(date: datetime, region: str, service_name: str) -> str: - """Get scope string.""" - return f"{time.to_signer_date(date)}/{region}/{service_name}/aws4_request" - - -def _get_canonical_headers( - headers: Mapping[str, str | list[str] | tuple[str]], -) -> tuple[str, str]: - """Get canonical headers.""" - - ordered_headers = {} - for key, values in headers.items(): - key = key.lower() - if key not in ( - "authorization", - "user-agent", - ): - values = values if isinstance(values, (list, tuple)) else [values] - ordered_headers[key] = ",".join([ - _MULTI_SPACE_REGEX.sub(" ", value).strip() for value in values - ]) - - ordered_headers = OrderedDict(sorted(ordered_headers.items())) - signed_headers = ";".join(ordered_headers.keys()) - canonical_headers = "\n".join( - [f"{key}:{value}" for key, value in ordered_headers.items()], - ) - return canonical_headers, signed_headers - - -def _get_canonical_query_string(query: str) -> str: - """Get canonical query string.""" - - query = query or "" - return "&".join( - [ - "=".join(pair) for pair in sorted( - [params.split("=") for params in query.split("&")], - ) - ], - ) - - -def _get_canonical_request_hash( - method: str, - url: SplitResult, - headers: Mapping[str, str | list[str] | tuple[str]], - content_sha256: str, -) -> tuple[str, str]: - """Get canonical request hash.""" - canonical_headers, signed_headers = _get_canonical_headers(headers) - canonical_query_string = _get_canonical_query_string(url.query) - - # CanonicalRequest = - # HTTPRequestMethod + '\n' + - # CanonicalURI + '\n' + - # CanonicalQueryString + '\n' + - # CanonicalHeaders + '\n\n' + - # SignedHeaders + '\n' + - # HexEncode(Hash(RequestPayload)) - canonical_request = ( - f"{method}\n" - f"{url.path or '/'}\n" - f"{canonical_query_string}\n" - f"{canonical_headers}\n\n" - f"{signed_headers}\n" - f"{content_sha256}" - ) - return sha256_hash(canonical_request), signed_headers - - -def _get_string_to_sign( - date: datetime, - scope: str, - canonical_request_hash: str, -) -> str: - """Get string-to-sign.""" - return ( - f"AWS4-HMAC-SHA256\n{time.to_amz_date(date)}\n{scope}\n" - f"{canonical_request_hash}" - ) - - -def _get_signing_key( - secret_key: str, - date: datetime, - region: str, - service_name: str, -) -> bytes: - """Get signing key.""" - - date_key = cast( - bytes, - _hmac_hash( - ("AWS4" + secret_key).encode(), - time.to_signer_date(date).encode(), - ), - ) - date_region_key = cast(bytes, _hmac_hash(date_key, region.encode())) - date_region_service_key = cast( - bytes, - _hmac_hash(date_region_key, service_name.encode()), - ) - return cast( - bytes, - _hmac_hash(date_region_service_key, b"aws4_request"), - ) - - -def _get_signature(signing_key: bytes, string_to_sign: str) -> str: - """Get signature.""" - - return cast( - str, - _hmac_hash(signing_key, string_to_sign.encode(), hexdigest=True), - ) - - -def _get_authorization( - access_key: str, - scope: str, - signed_headers: str, - signature: str, -) -> str: - """Get authorization.""" - return ( - f"AWS4-HMAC-SHA256 Credential={access_key}/{scope}, " - f"SignedHeaders={signed_headers}, Signature={signature}" - ) - - -def _sign_v4( - *, - service_name: str, - method: str, - url: SplitResult, - region: str, - headers: DictType, - credentials: Credentials, - content_sha256: str, - date: datetime, -) -> DictType: - """Do signature V4 of given request for given service name.""" - - scope = _get_scope(date, region, service_name) - canonical_request_hash, signed_headers = _get_canonical_request_hash( - method, url, headers, content_sha256, - ) - string_to_sign = _get_string_to_sign(date, scope, canonical_request_hash) - signing_key = _get_signing_key( - credentials.secret_key, date, region, service_name, - ) - signature = _get_signature(signing_key, string_to_sign) - authorization = _get_authorization( - credentials.access_key, scope, signed_headers, signature, - ) - headers["Authorization"] = authorization - return headers - - -def sign_v4_s3( - *, - method: str, - url: SplitResult, - region: str, - headers: DictType, - credentials: Credentials, - content_sha256: str, - date: datetime, -) -> DictType: - """Do signature V4 of given request for S3 service.""" - return _sign_v4( - service_name="s3", - method=method, - url=url, - region=region, - headers=headers, - credentials=credentials, - content_sha256=content_sha256, - date=date, - ) - - -def sign_v4_sts( - *, - method: str, - url: SplitResult, - region: str, - headers: DictType, - credentials: Credentials, - content_sha256: str, - date: datetime, -) -> DictType: - """Do signature V4 of given request for STS service.""" - return _sign_v4( - service_name="sts", - method=method, - url=url, - region=region, - headers=headers, - credentials=credentials, - content_sha256=content_sha256, - date=date, - ) - - -def _get_presign_canonical_request_hash( # pylint: disable=invalid-name - *, - method: str, - url: SplitResult, - access_key: str, - scope: str, - date: datetime, - expires: int, -) -> tuple[str, SplitResult]: - """Get canonical request hash for presign request.""" - x_amz_credential = queryencode(access_key + "/" + scope) - canonical_headers, signed_headers = "host:" + url.netloc, "host" - - query = url.query+"&" if url.query else "" - query += ( - f"X-Amz-Algorithm=AWS4-HMAC-SHA256" - f"&X-Amz-Credential={x_amz_credential}" - f"&X-Amz-Date={time.to_amz_date(date)}" - f"&X-Amz-Expires={expires}" - f"&X-Amz-SignedHeaders={signed_headers}" - ) - parts = list(url) - parts[3] = query - url = SplitResult(*parts) - - canonical_query_string = _get_canonical_query_string(query) - - # CanonicalRequest = - # HTTPRequestMethod + '\n' + - # CanonicalURI + '\n' + - # CanonicalQueryString + '\n' + - # CanonicalHeaders + '\n\n' + - # SignedHeaders + '\n' + - # HexEncode(Hash(RequestPayload)) - canonical_request = ( - f"{method}\n" - f"{url.path or '/'}\n" - f"{canonical_query_string}\n" - f"{canonical_headers}\n\n" - f"{signed_headers}\n" - f"UNSIGNED-PAYLOAD" - ) - return sha256_hash(canonical_request), url - - -def presign_v4( - *, - method: str, - url: SplitResult, - region: str, - credentials: Credentials, - date: datetime, - expires: int, -) -> SplitResult: - """Do signature V4 of given presign request.""" - - scope = _get_scope(date, region, "s3") - canonical_request_hash, url = _get_presign_canonical_request_hash( - method=method, - url=url, - access_key=credentials.access_key, - scope=scope, - date=date, - expires=expires, - ) - string_to_sign = _get_string_to_sign(date, scope, canonical_request_hash) - signing_key = _get_signing_key(credentials.secret_key, date, region, "s3") - signature = _get_signature(signing_key, string_to_sign) - - parts = list(url) - parts[3] = url.query + "&X-Amz-Signature=" + queryencode(signature) - url = SplitResult(*parts) - return url - - -def get_credential_string(access_key: str, date: datetime, region: str) -> str: - """Get credential string of given access key, date and region.""" - return f"{access_key}/{time.to_signer_date(date)}/{region}/s3/aws4_request" - - -def post_presign_v4( - data: str, - secret_key: str, - date: datetime, - region: str, -) -> str: - """Do signature V4 of given presign POST form-data.""" - return _get_signature( - _get_signing_key(secret_key, date, region, "s3"), - data, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/minio/sse.py b/backend/venv39/lib/python3.9/site-packages/minio/sse.py deleted file mode 100644 index e65843d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/sse.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, -# (C) 2018 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -minio.sse -~~~~~~~~~~~~~~~~~~~ - -This module contains core API parsers. - -:copyright: (c) 2018 by MinIO, Inc. -:license: Apache 2.0, see LICENSE for more details. - -""" -from __future__ import absolute_import, annotations - -import base64 -import json -from abc import ABC, abstractmethod -from typing import Any, cast - - -class Sse(ABC): - """Server-side encryption base class.""" - - @abstractmethod - def headers(self) -> dict[str, str]: - """Return headers.""" - - def tls_required(self) -> bool: # pylint: disable=no-self-use - """Return TLS required to use this server-side encryption.""" - return True - - def copy_headers(self) -> dict[str, str]: # pylint: disable=no-self-use - """Return copy headers.""" - return {} - - -class SseCustomerKey(Sse): - """ Server-side encryption - customer key type.""" - - def __init__(self, key: bytes): - if len(key) != 32: - raise ValueError( - "SSE-C keys must be exactly 256 bits (32 bytes) long. " - "Pass raw bytes, not the base64 encoded value.", - ) - b64key = base64.b64encode(key).decode() - from .helpers import \ - md5sum_hash # pylint: disable=import-outside-toplevel - md5key = cast(str, md5sum_hash(key)) - self._headers: dict[str, str] = { - "X-Amz-Server-Side-Encryption-Customer-Algorithm": "AES256", - "X-Amz-Server-Side-Encryption-Customer-Key": b64key, - "X-Amz-Server-Side-Encryption-Customer-Key-MD5": md5key, - } - self._copy_headers: dict[str, str] = { - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": - "AES256", - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": b64key, - "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-MD5": - md5key, - } - - def headers(self) -> dict[str, str]: - return self._headers.copy() - - def copy_headers(self) -> dict[str, str]: - return self._copy_headers.copy() - - -class SseKMS(Sse): - """Server-side encryption - KMS type.""" - - def __init__(self, key: str, context: dict[str, Any]): - self._headers = { - "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": key, - "X-Amz-Server-Side-Encryption": "aws:kms" - } - if context: - data = bytes(json.dumps(context), "utf-8") - self._headers["X-Amz-Server-Side-Encryption-Context"] = ( - base64.b64encode(data).decode() - ) - - def headers(self) -> dict[str, str]: - return self._headers.copy() - - -class SseS3(Sse): - """Server-side encryption - S3 type.""" - - def headers(self) -> dict[str, str]: - return { - "X-Amz-Server-Side-Encryption": "AES256" - } - - def tls_required(self) -> bool: - return False diff --git a/backend/venv39/lib/python3.9/site-packages/minio/sseconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/sseconfig.py deleted file mode 100644 index 09f7118..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/sseconfig.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of PutBucketEncryption and GetBucketEncryption APIs.""" - -from __future__ import absolute_import, annotations - -from abc import ABC -from dataclasses import dataclass -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .xml import Element, SubElement, find, findtext - -AES256 = "AES256" -AWS_KMS = "aws:kms" - -A = TypeVar("A", bound="Rule") - - -@dataclass(frozen=True) -class Rule(ABC): - """Server-side encryption rule. """ - - sse_algorithm: str - kms_master_key_id: Optional[str] = None - - @classmethod - def new_sse_s3_rule(cls: Type[A]) -> A: - """Create SSE-S3 rule.""" - return cls(sse_algorithm=AES256) - - @classmethod - def new_sse_kms_rule( - cls: Type[A], - kms_master_key_id: Optional[str] = None, - ) -> A: - """Create new SSE-KMS rule.""" - return cls(sse_algorithm=AWS_KMS, kms_master_key_id=kms_master_key_id) - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - element = cast( - ET.Element, - find(element, "ApplyServerSideEncryptionByDefault", True), - ) - return cls( - sse_algorithm=cast(str, findtext(element, "SSEAlgorithm", True)), - kms_master_key_id=findtext(element, "KMSMasterKeyID"), - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - if element is None: - raise ValueError("element must be provided") - element = SubElement(element, "Rule") - tag = SubElement(element, "ApplyServerSideEncryptionByDefault") - SubElement(tag, "SSEAlgorithm", self.sse_algorithm) - if self.kms_master_key_id is not None: - SubElement(tag, "KMSMasterKeyID", self.kms_master_key_id) - return element - - -B = TypeVar("B", bound="SSEConfig") - - -@dataclass(frozen=True) -class SSEConfig: - """server-side encryption configuration.""" - - rule: Rule - - def __post_init__(self): - if not self.rule: - raise ValueError("rule must be provided") - - @classmethod - def fromxml(cls: Type[B], element: ET.Element) -> B: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "Rule", True)) - return cls(Rule.fromxml(element)) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("ServerSideEncryptionConfiguration") - self.rule.toxml(element) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/tagging.py b/backend/venv39/lib/python3.9/site-packages/minio/tagging.py deleted file mode 100644 index efe0f03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/tagging.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Tagging for bucket and object.""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from typing import Optional, Type, TypeVar, cast -from xml.etree import ElementTree as ET - -from .commonconfig import Tags -from .xml import Element, SubElement, find - -A = TypeVar("A", bound="Tagging") - - -@dataclass(frozen=True) -class Tagging: - """Tagging for buckets and objects.""" - - tags: Optional[Tags] - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - element = cast(ET.Element, find(element, "TagSet", True)) - tags = ( - None if find(element, "Tag") is None - else Tags.fromxml(element) - ) - return cls(tags=tags) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("Tagging") - if self.tags: - self.tags.toxml(SubElement(element, "TagSet")) - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/time.py b/backend/venv39/lib/python3.9/site-packages/minio/time.py deleted file mode 100644 index 2fa794d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/time.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Time formatter for S3 APIs.""" - -from __future__ import absolute_import, annotations - -import time as ctime -from datetime import datetime, timezone - -try: - from datetime import UTC # type: ignore[attr-defined] - _UTC_IMPORTED = True -except ImportError: - _UTC_IMPORTED = False - -from typing import Optional - -_WEEK_DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] -_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", - "Nov", "Dec"] - - -def _to_utc(value: datetime) -> datetime: - """Convert to UTC time if value is not naive.""" - return ( - value.astimezone(timezone.utc).replace(tzinfo=None) - if value.tzinfo else value - ) - - -def from_iso8601utc(value: Optional[str]) -> Optional[datetime]: - """Parse UTC ISO-8601 formatted string to datetime.""" - if value is None: - return None - - try: - time = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ") - except ValueError: - time = datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ") - return time.replace(tzinfo=timezone.utc) - - -def to_iso8601utc(value: Optional[datetime]) -> Optional[str]: - """Format datetime into UTC ISO-8601 formatted string.""" - if value is None: - return None - - value = _to_utc(value) - return ( - value.strftime("%Y-%m-%dT%H:%M:%S.") + value.strftime("%f")[:3] + "Z" - ) - - -def from_http_header(value: str) -> datetime: - """Parse HTTP header date formatted string to datetime.""" - if len(value) != 29: - raise ValueError( - f"time data {value} does not match HTTP header format") - - if value[0:3] not in _WEEK_DAYS or value[3] != ",": - raise ValueError( - f"time data {value} does not match HTTP header format") - weekday = _WEEK_DAYS.index(value[0:3]) - - if value[4] != " " or value[7] != " ": - raise ValueError( - f"time data {value} does not match HTTP header format" - ) - day = int(value[5:7]) - - if value[8:11] not in _MONTHS: - raise ValueError( - f"time data {value} does not match HTTP header format") - month = _MONTHS.index(value[8:11]) - - time = datetime.strptime(value[11:], " %Y %H:%M:%S GMT") - time = time.replace(day=day, month=month+1, tzinfo=timezone.utc) - - if weekday != time.weekday(): - raise ValueError( - f"time data {value} does not match HTTP header format") - - return time - - -def to_http_header(value: datetime) -> str: - """Format datatime into HTTP header date formatted string.""" - value = _to_utc(value) - weekday = _WEEK_DAYS[value.weekday()] - day = value.strftime(" %d ") - month = _MONTHS[value.month - 1] - suffix = value.strftime(" %Y %H:%M:%S GMT") - return f"{weekday},{day}{month}{suffix}" - - -def to_amz_date(value: datetime) -> str: - """Format datetime into AMZ date formatted string.""" - return _to_utc(value).strftime("%Y%m%dT%H%M%SZ") - - -def utcnow() -> datetime: - """Timezone-aware wrapper to datetime.utcnow().""" - if _UTC_IMPORTED: - return datetime.now(UTC).replace(tzinfo=timezone.utc) - return datetime.utcnow().replace(tzinfo=timezone.utc) - - -def to_signer_date(value: datetime) -> str: - """Format datetime into SignatureV4 date formatted string.""" - return _to_utc(value).strftime("%Y%m%d") - - -def to_float(value: datetime) -> float: - """Convert datetime into float value.""" - return ctime.mktime(value.timetuple()) + value.microsecond * 1e-6 diff --git a/backend/venv39/lib/python3.9/site-packages/minio/versioningconfig.py b/backend/venv39/lib/python3.9/site-packages/minio/versioningconfig.py deleted file mode 100644 index 41b223e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/versioningconfig.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Request/response of PutBucketVersioning and GetBucketVersioning APIs.""" - -from __future__ import absolute_import, annotations - -from dataclasses import dataclass -from typing import List, Optional, Type, TypeVar, Union, cast -from xml.etree import ElementTree as ET - -from .commonconfig import DISABLED, ENABLED -from .xml import Element, SubElement, findall, findtext - -OFF = "Off" -SUSPENDED = "Suspended" - -A = TypeVar("A", bound="VersioningConfig") - - -@dataclass(frozen=True) -class VersioningConfig: - """Versioning configuration.""" - - status: Optional[str] = None - mfa_delete: Optional[str] = None - excluded_prefixes: Optional[list[str]] = None - exclude_folders: bool = False - - def __post_init__(self): - if self.status is not None and self.status not in [ENABLED, SUSPENDED]: - raise ValueError(f"status must be {ENABLED} or {SUSPENDED}") - if ( - self.mfa_delete is not None and - self.mfa_delete not in [ENABLED, DISABLED] - ): - raise ValueError(f"MFA delete must be {ENABLED} or {DISABLED}") - - @property - def status_string(self) -> str: - """Convert status to status string. """ - return OFF if self.status is None else self.status - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create new object with values from XML element.""" - status = findtext(element, "Status") - mfa_delete = findtext(element, "MFADelete") - excluded_prefixes = [ - prefix.text - for prefix in findall( - element, - "ExcludedPrefixes/Prefix", - ) - ] - exclude_folders = findtext(element, "ExcludeFolders") == "true" - return cls( - status=status, - mfa_delete=mfa_delete, - excluded_prefixes=cast(Union[List[str], None], excluded_prefixes), - exclude_folders=exclude_folders, - ) - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert to XML.""" - element = Element("VersioningConfiguration") - if self.status: - SubElement(element, "Status", self.status) - if self.mfa_delete: - SubElement(element, "MFADelete", self.mfa_delete) - for prefix in self.excluded_prefixes or []: - SubElement( - SubElement(element, "ExcludedPrefixes"), - "Prefix", - prefix, - ) - if self.exclude_folders: - SubElement(element, "ExcludeFolders", "true") - return element diff --git a/backend/venv39/lib/python3.9/site-packages/minio/xml.py b/backend/venv39/lib/python3.9/site-packages/minio/xml.py deleted file mode 100644 index 7dbe051..0000000 --- a/backend/venv39/lib/python3.9/site-packages/minio/xml.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8 -*- -# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C) -# 2020 MinIO, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""XML utility module.""" - -from __future__ import absolute_import, annotations - -import io -from typing import Optional, Type, TypeVar -from xml.etree import ElementTree as ET - -from typing_extensions import Protocol - -_S3_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/" - - -def Element( # pylint: disable=invalid-name - tag: str, - namespace: str = _S3_NAMESPACE, -) -> ET.Element: - """Create ElementTree.Element with tag and namespace.""" - return ET.Element(tag, {"xmlns": namespace} if namespace else {}) - - -def SubElement( # pylint: disable=invalid-name - parent: ET.Element, tag: str, text: Optional[str] = None -) -> ET.Element: - """Create ElementTree.SubElement on parent with tag and text.""" - element = ET.SubElement(parent, tag) - if text is not None: - element.text = text - return element - - -def _get_namespace(element: ET.Element) -> str: - """Exact namespace if found.""" - start = element.tag.find("{") - if start < 0: - return "" - start += 1 - end = element.tag.find("}") - if end < 0: - return "" - return element.tag[start:end] - - -def findall(element: ET.Element, name: str) -> list[ET.Element]: - """Namespace aware ElementTree.Element.findall().""" - namespace = _get_namespace(element) - if namespace: - name = "/".join(["ns:" + token for token in name.split("/")]) - return element.findall(name, {"ns": namespace} if namespace else {}) - - -def find( - element: ET.Element, - name: str, - strict: bool = False, -) -> Optional[ET.Element]: - """Namespace aware ElementTree.Element.find().""" - namespace = _get_namespace(element) - elem = element.find( - "ns:" + name if namespace else name, - {"ns": namespace} if namespace else {}, - ) - if strict and elem is None: - raise ValueError(f"XML element <{name}> not found") - return elem - - -def findtext( - element: ET.Element, - name: str, - strict: bool = False, -) -> Optional[str]: - """ - Namespace aware ElementTree.Element.findtext() with strict flag - raises ValueError if element name not exist. - """ - elem = find(element, name, strict=strict) - return None if elem is None else (elem.text or "") - - -A = TypeVar("A") - - -class FromXmlType(Protocol): - """typing stub for class with `fromxml` method""" - - @classmethod - def fromxml(cls: Type[A], element: ET.Element) -> A: - """Create python object with values from XML element.""" - - -B = TypeVar("B", bound=FromXmlType) - - -def unmarshal(cls: Type[B], xmlstring: str) -> B: - """Unmarshal given XML string to an object of passed class.""" - return cls.fromxml(ET.fromstring(xmlstring)) - - -def getbytes(element: ET.Element) -> bytes: - """Convert ElementTree.Element to bytes.""" - with io.BytesIO() as data: - ET.ElementTree(element).write( - data, - encoding=None, - xml_declaration=False, - ) - return data.getvalue() - - -class ToXmlType(Protocol): - """typing stub for class with `toxml` method""" - - def toxml(self, element: Optional[ET.Element]) -> ET.Element: - """Convert python object to ElementTree.Element.""" - - -def marshal(obj: ToXmlType) -> bytes: - """Get XML data as bytes of ElementTree.Element.""" - return getbytes(obj.toxml(None)) diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/METADATA deleted file mode 100644 index 1ab8dd6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/METADATA +++ /dev/null @@ -1,149 +0,0 @@ -Metadata-Version: 2.4 -Name: multidict -Version: 6.7.0 -Summary: multidict implementation -Home-page: https://github.com/aio-libs/multidict -Author: Andrew Svetlov -Author-email: andrew.svetlov@gmail.com -License: Apache License 2.0 -Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org -Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org -Project-URL: CI: GitHub, https://github.com/aio-libs/multidict/actions -Project-URL: Code of Conduct, https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md -Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/multidict -Project-URL: Docs: Changelog, https://multidict.aio-libs.org/en/latest/changes/ -Project-URL: Docs: RTD, https://multidict.aio-libs.org -Project-URL: GitHub: issues, https://github.com/aio-libs/multidict/issues -Project-URL: GitHub: repo, https://github.com/aio-libs/multidict -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Requires-Python: >=3.9 -Description-Content-Type: text/x-rst -License-File: LICENSE -Requires-Dist: typing-extensions>=4.1.0; python_version < "3.11" -Dynamic: license-file - -========= -multidict -========= - -.. image:: https://github.com/aio-libs/multidict/actions/workflows/ci-cd.yml/badge.svg - :target: https://github.com/aio-libs/multidict/actions - :alt: GitHub status for master branch - -.. image:: https://codecov.io/gh/aio-libs/multidict/branch/master/graph/badge.svg?flag=pytest - :target: https://codecov.io/gh/aio-libs/multidict?flags[]=pytest - :alt: Coverage metrics - -.. image:: https://img.shields.io/pypi/v/multidict.svg - :target: https://pypi.org/project/multidict - :alt: PyPI - -.. image:: https://readthedocs.org/projects/multidict/badge/?version=latest - :target: https://multidict.aio-libs.org - :alt: Read The Docs build status badge - -.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json - :target: https://codspeed.io/aio-libs/multidict - :alt: CodSpeed - -.. image:: https://img.shields.io/pypi/pyversions/multidict.svg - :target: https://pypi.org/project/multidict - :alt: Python versions - -.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs:matrix.org - :alt: Matrix Room — #aio-libs:matrix.org - -.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat - :target: https://matrix.to/#/%23aio-libs-space:matrix.org - :alt: Matrix Space — #aio-libs-space:matrix.org - -Multidict is dict-like collection of *key-value pairs* where key -might occur more than once in the container. - -Introduction ------------- - -*HTTP Headers* and *URL query string* require specific data structure: -*multidict*. It behaves mostly like a regular ``dict`` but it may have -several *values* for the same *key* and *preserves insertion ordering*. - -The *key* is ``str`` (or ``istr`` for case-insensitive dictionaries). - -``multidict`` has four multidict classes: -``MultiDict``, ``MultiDictProxy``, ``CIMultiDict`` -and ``CIMultiDictProxy``. - -Immutable proxies (``MultiDictProxy`` and -``CIMultiDictProxy``) provide a dynamic view for the -proxied multidict, the view reflects underlying collection changes. They -implement the ``collections.abc.Mapping`` interface. - -Regular mutable (``MultiDict`` and ``CIMultiDict``) classes -implement ``collections.abc.MutableMapping`` and allows them to change -their own content. - - -*Case insensitive* (``CIMultiDict`` and -``CIMultiDictProxy``) assume the *keys* are case -insensitive, e.g.:: - - >>> dct = CIMultiDict(key='val') - >>> 'Key' in dct - True - >>> dct['Key'] - 'val' - -*Keys* should be ``str`` or ``istr`` instances. - -The library has optional C Extensions for speed. - - -License -------- - -Apache 2 - -Library Installation --------------------- - -.. code-block:: bash - - $ pip install multidict - -The library is Python 3 only! - -PyPI contains binary wheels for Linux, Windows and MacOS. If you want to install -``multidict`` on another operating system (or *Alpine Linux* inside a Docker) the -tarball will be used to compile the library from source. It requires a C compiler and -Python headers to be installed. - -To skip the compilation, please use the `MULTIDICT_NO_EXTENSIONS` environment variable, -e.g.: - -.. code-block:: bash - - $ MULTIDICT_NO_EXTENSIONS=1 pip install multidict - -Please note, the pure Python (uncompiled) version is about 20-50 times slower depending on -the usage scenario!!! - -For extension development, set the ``MULTIDICT_DEBUG_BUILD`` environment variable to compile -the extensions in debug mode: - -.. code-block:: console - - $ MULTIDICT_DEBUG_BUILD=1 pip install multidict - -Changelog ---------- -See `RTD page `_. diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/RECORD deleted file mode 100644 index bce2e8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/RECORD +++ /dev/null @@ -1,16 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/multidict/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/multidict/_abc.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/multidict/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/multidict/_multidict_py.cpython-39.pyc,, -multidict-6.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -multidict-6.7.0.dist-info/METADATA,sha256=q_zO5zLDpLVGLHpjw8BHBRhNX7yuB6_RlehDOZPYrZQ,5321 -multidict-6.7.0.dist-info/RECORD,, -multidict-6.7.0.dist-info/WHEEL,sha256=bDWaFWigpG5bEpqw9IoRiyYs8MvmSFh0OhUAOoi_-KA,134 -multidict-6.7.0.dist-info/licenses/LICENSE,sha256=k9Ealo4vDzY3PECBH_bSDhc_WMPKtYhM1mF7v9eVSSo,611 -multidict-6.7.0.dist-info/top_level.txt,sha256=-euDElkk5_qkmfIJ7WiqCab02ZlSFZWynejKg59qZQQ,10 -multidict/__init__.py,sha256=vrqM7ruZH18zqUQumAaWtGekJFYb_oWvThnAdNuAxg4,1228 -multidict/_abc.py,sha256=e_0JDJi7E6LWS0A3gUJ17SkgDLlmg8ffjfylTu_vboc,2402 -multidict/_compat.py,sha256=TcRjCStk2iIY1_DwDNj8kNpJRQ9rtLj92Xvk1z2G_ak,422 -multidict/_multidict.cpython-39-darwin.so,sha256=TsEEbw1BMFAbMGNaIFTxzlQwVS0MPnnj_vx0ytdgm1o,121792 -multidict/_multidict_py.py,sha256=VGQ58P7VOd6lRf3WVAinb62aD16DPdAWRt68qmiJMXE,39955 -multidict/py.typed,sha256=e9bmbH3UFxsabQrnNFPG9qxIXztwbcM6IKDYnvZwprY,15 diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/WHEEL deleted file mode 100644 index d7eb6c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_11_0_arm64 -Generator: delocate 0.13.0 - diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/licenses/LICENSE deleted file mode 100644 index 8727172..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - Copyright 2016 Andrew Svetlov and aio-libs contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/top_level.txt deleted file mode 100644 index afcecdf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict-6.7.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -multidict diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/__init__.py b/backend/venv39/lib/python3.9/site-packages/multidict/__init__.py deleted file mode 100644 index a688932..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Multidict implementation. - -HTTP Headers and URL query string require specific data structure: -multidict. It behaves mostly like a dict but it can have -several values for the same key. -""" - -from typing import TYPE_CHECKING - -from ._abc import MultiMapping, MutableMultiMapping -from ._compat import USE_EXTENSIONS - -__all__ = ( - "CIMultiDict", - "CIMultiDictProxy", - "MultiDict", - "MultiDictProxy", - "MultiMapping", - "MutableMultiMapping", - "getversion", - "istr", - "upstr", -) - -__version__ = "6.7.0" - - -if TYPE_CHECKING or not USE_EXTENSIONS: - from ._multidict_py import ( - CIMultiDict, - CIMultiDictProxy, - MultiDict, - MultiDictProxy, - getversion, - istr, - ) -else: - from collections.abc import ItemsView, KeysView, ValuesView - - from ._multidict import ( - CIMultiDict, - CIMultiDictProxy, - MultiDict, - MultiDictProxy, - _ItemsView, - _KeysView, - _ValuesView, - getversion, - istr, - ) - - MultiMapping.register(MultiDictProxy) - MutableMultiMapping.register(MultiDict) - KeysView.register(_KeysView) - ItemsView.register(_ItemsView) - ValuesView.register(_ValuesView) - - -upstr = istr diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/_abc.py b/backend/venv39/lib/python3.9/site-packages/multidict/_abc.py deleted file mode 100644 index 54253e9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict/_abc.py +++ /dev/null @@ -1,73 +0,0 @@ -import abc -from collections.abc import Iterable, Mapping, MutableMapping -from typing import TYPE_CHECKING, Protocol, TypeVar, Union, overload - -if TYPE_CHECKING: - from ._multidict_py import istr -else: - istr = str - -_V = TypeVar("_V") -_V_co = TypeVar("_V_co", covariant=True) -_T = TypeVar("_T") - - -class SupportsKeys(Protocol[_V_co]): - def keys(self) -> Iterable[str]: ... - def __getitem__(self, key: str, /) -> _V_co: ... - - -class SupportsIKeys(Protocol[_V_co]): - def keys(self) -> Iterable[istr]: ... - def __getitem__(self, key: istr, /) -> _V_co: ... - - -MDArg = Union[SupportsKeys[_V], SupportsIKeys[_V], Iterable[tuple[str, _V]], None] - - -class MultiMapping(Mapping[str, _V_co]): - @overload - def getall(self, key: str) -> list[_V_co]: ... - @overload - def getall(self, key: str, default: _T) -> Union[list[_V_co], _T]: ... - @abc.abstractmethod - def getall(self, key: str, default: _T = ...) -> Union[list[_V_co], _T]: - """Return all values for key.""" - - @overload - def getone(self, key: str) -> _V_co: ... - @overload - def getone(self, key: str, default: _T) -> Union[_V_co, _T]: ... - @abc.abstractmethod - def getone(self, key: str, default: _T = ...) -> Union[_V_co, _T]: - """Return first value for key.""" - - -class MutableMultiMapping(MultiMapping[_V], MutableMapping[str, _V]): - @abc.abstractmethod - def add(self, key: str, value: _V) -> None: - """Add value to list.""" - - @abc.abstractmethod - def extend(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None: - """Add everything from arg and kwargs to the mapping.""" - - @abc.abstractmethod - def merge(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None: - """Merge into the mapping, adding non-existing keys.""" - - @overload - def popone(self, key: str) -> _V: ... - @overload - def popone(self, key: str, default: _T) -> Union[_V, _T]: ... - @abc.abstractmethod - def popone(self, key: str, default: _T = ...) -> Union[_V, _T]: - """Remove specified key and return the corresponding value.""" - - @overload - def popall(self, key: str) -> list[_V]: ... - @overload - def popall(self, key: str, default: _T) -> Union[list[_V], _T]: ... - @abc.abstractmethod - def popall(self, key: str, default: _T = ...) -> Union[list[_V], _T]: - """Remove all occurrences of key and return the list of corresponding values.""" diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/_compat.py b/backend/venv39/lib/python3.9/site-packages/multidict/_compat.py deleted file mode 100644 index 264d327..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict/_compat.py +++ /dev/null @@ -1,15 +0,0 @@ -import os -import platform - -NO_EXTENSIONS = bool(os.environ.get("MULTIDICT_NO_EXTENSIONS")) - -PYPY = platform.python_implementation() == "PyPy" - -USE_EXTENSIONS = not NO_EXTENSIONS and not PYPY - -if USE_EXTENSIONS: - try: - from . import _multidict # type: ignore[attr-defined] # noqa: F401 - except ImportError: # pragma: no cover - # FIXME: Refactor for coverage. See #837. - USE_EXTENSIONS = False diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/_multidict.cpython-39-darwin.so b/backend/venv39/lib/python3.9/site-packages/multidict/_multidict.cpython-39-darwin.so deleted file mode 100755 index c289002..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/multidict/_multidict.cpython-39-darwin.so and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/_multidict_py.py b/backend/venv39/lib/python3.9/site-packages/multidict/_multidict_py.py deleted file mode 100644 index 6b68d52..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict/_multidict_py.py +++ /dev/null @@ -1,1242 +0,0 @@ -import enum -import functools -import reprlib -import sys -from array import array -from collections.abc import ( - ItemsView, - Iterable, - Iterator, - KeysView, - Mapping, - ValuesView, -) -from dataclasses import dataclass -from typing import ( - TYPE_CHECKING, - Any, - ClassVar, - Generic, - NoReturn, - Optional, - TypeVar, - Union, - cast, - overload, -) - -from ._abc import MDArg, MultiMapping, MutableMultiMapping, SupportsKeys - -if sys.version_info >= (3, 11): - from typing import Self -else: - from typing_extensions import Self - - -class istr(str): - """Case insensitive str.""" - - __is_istr__ = True - __istr_identity__: Optional[str] = None - - -_V = TypeVar("_V") -_T = TypeVar("_T") - -_SENTINEL = enum.Enum("_SENTINEL", "sentinel") -sentinel = _SENTINEL.sentinel - -_version = array("Q", [0]) - - -class _Iter(Generic[_T]): - __slots__ = ("_size", "_iter") - - def __init__(self, size: int, iterator: Iterator[_T]): - self._size = size - self._iter = iterator - - def __iter__(self) -> Self: - return self - - def __next__(self) -> _T: - return next(self._iter) - - def __length_hint__(self) -> int: - return self._size - - -class _ViewBase(Generic[_V]): - def __init__( - self, - md: "MultiDict[_V]", - ): - self._md = md - - def __len__(self) -> int: - return len(self._md) - - -class _ItemsView(_ViewBase[_V], ItemsView[str, _V]): - def __contains__(self, item: object) -> bool: - if not isinstance(item, (tuple, list)) or len(item) != 2: - return False - key, value = item - try: - identity = self._md._identity(key) - except TypeError: - return False - hash_ = hash(identity) - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity and value == e.value: - return True - return False - - def __iter__(self) -> _Iter[tuple[str, _V]]: - return _Iter(len(self), self._iter(self._md._version)) - - def _iter(self, version: int) -> Iterator[tuple[str, _V]]: - for e in self._md._keys.iter_entries(): - if version != self._md._version: - raise RuntimeError("Dictionary changed during iteration") - yield self._md._key(e.key), e.value - - @reprlib.recursive_repr() - def __repr__(self) -> str: - lst = [] - for e in self._md._keys.iter_entries(): - lst.append(f"'{e.key}': {e.value!r}") - body = ", ".join(lst) - return f"<{self.__class__.__name__}({body})>" - - def _parse_item( - self, arg: Union[tuple[str, _V], _T] - ) -> Optional[tuple[int, str, str, _V]]: - if not isinstance(arg, tuple): - return None - if len(arg) != 2: - return None - try: - identity = self._md._identity(arg[0]) - return (hash(identity), identity, arg[0], arg[1]) - except TypeError: - return None - - def _tmp_set(self, it: Iterable[_T]) -> set[tuple[str, _V]]: - tmp = set() - for arg in it: - item = self._parse_item(arg) - if item is None: - continue - else: - tmp.add((item[1], item[3])) - return tmp - - def __and__(self, other: Iterable[Any]) -> set[tuple[str, _V]]: - ret = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - for arg in it: - item = self._parse_item(arg) - if item is None: - continue - hash_, identity, key, value = item - for slot, idx, e in self._md._keys.iter_hash(hash_): - e.hash = -1 - if e.identity == identity and e.value == value: - ret.add((e.key, e.value)) - self._md._keys.restore_hash(hash_) - return ret - - def __rand__(self, other: Iterable[_T]) -> set[_T]: - ret = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - for arg in it: - item = self._parse_item(arg) - if item is None: - continue - hash_, identity, key, value = item - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity and e.value == value: - ret.add(arg) - break - return ret - - def __or__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: - ret: set[Union[tuple[str, _V], _T]] = set(self) - try: - it = iter(other) - except TypeError: - return NotImplemented - for arg in it: - item: Optional[tuple[int, str, str, _V]] = self._parse_item(arg) - if item is None: - ret.add(arg) - continue - hash_, identity, key, value = item - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity and e.value == value: # pragma: no branch - break - else: - ret.add(arg) - return ret - - def __ror__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: - try: - ret: set[Union[tuple[str, _V], _T]] = set(other) - except TypeError: - return NotImplemented - tmp = self._tmp_set(ret) - - for e in self._md._keys.iter_entries(): - if (e.identity, e.value) not in tmp: - ret.add((e.key, e.value)) - return ret - - def __sub__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: - ret: set[Union[tuple[str, _V], _T]] = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - tmp = self._tmp_set(it) - - for e in self._md._keys.iter_entries(): - if (e.identity, e.value) not in tmp: - ret.add((e.key, e.value)) - - return ret - - def __rsub__(self, other: Iterable[_T]) -> set[_T]: - ret: set[_T] = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - for arg in it: - item = self._parse_item(arg) - if item is None: - ret.add(arg) - continue - - hash_, identity, key, value = item - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity and e.value == value: # pragma: no branch - break - else: - ret.add(arg) - return ret - - def __xor__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]: - try: - rgt = set(other) - except TypeError: - return NotImplemented - ret: set[Union[tuple[str, _V], _T]] = self - rgt - ret |= rgt - self - return ret - - __rxor__ = __xor__ - - def isdisjoint(self, other: Iterable[tuple[str, _V]]) -> bool: - for arg in other: - item = self._parse_item(arg) - if item is None: - continue - - hash_, identity, key, value = item - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity and e.value == value: # pragma: no branch - return False - return True - - -class _ValuesView(_ViewBase[_V], ValuesView[_V]): - def __contains__(self, value: object) -> bool: - for e in self._md._keys.iter_entries(): - if e.value == value: - return True - return False - - def __iter__(self) -> _Iter[_V]: - return _Iter(len(self), self._iter(self._md._version)) - - def _iter(self, version: int) -> Iterator[_V]: - for e in self._md._keys.iter_entries(): - if version != self._md._version: - raise RuntimeError("Dictionary changed during iteration") - yield e.value - - @reprlib.recursive_repr() - def __repr__(self) -> str: - lst = [] - for e in self._md._keys.iter_entries(): - lst.append(repr(e.value)) - body = ", ".join(lst) - return f"<{self.__class__.__name__}({body})>" - - -class _KeysView(_ViewBase[_V], KeysView[str]): - def __contains__(self, key: object) -> bool: - if not isinstance(key, str): - return False - identity = self._md._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - return True - return False - - def __iter__(self) -> _Iter[str]: - return _Iter(len(self), self._iter(self._md._version)) - - def _iter(self, version: int) -> Iterator[str]: - for e in self._md._keys.iter_entries(): - if version != self._md._version: - raise RuntimeError("Dictionary changed during iteration") - yield self._md._key(e.key) - - def __repr__(self) -> str: - lst = [] - for e in self._md._keys.iter_entries(): - lst.append(f"'{e.key}'") - body = ", ".join(lst) - return f"<{self.__class__.__name__}({body})>" - - def __and__(self, other: Iterable[object]) -> set[str]: - ret = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - for key in it: - if not isinstance(key, str): - continue - identity = self._md._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - ret.add(e.key) - break - return ret - - def __rand__(self, other: Iterable[_T]) -> set[_T]: - ret = set() - try: - it = iter(other) - except TypeError: - return NotImplemented - for key in it: - if not isinstance(key, str): - continue - if key in self._md: - ret.add(key) - return cast(set[_T], ret) - - def __or__(self, other: Iterable[_T]) -> set[Union[str, _T]]: - ret: set[Union[str, _T]] = set(self) - try: - it = iter(other) - except TypeError: - return NotImplemented - for key in it: - if not isinstance(key, str): - ret.add(key) - continue - if key not in self._md: - ret.add(key) - return ret - - def __ror__(self, other: Iterable[_T]) -> set[Union[str, _T]]: - try: - ret: set[Union[str, _T]] = set(other) - except TypeError: - return NotImplemented - - tmp = set() - for key in ret: - if not isinstance(key, str): - continue - identity = self._md._identity(key) - tmp.add(identity) - - for e in self._md._keys.iter_entries(): - if e.identity not in tmp: - ret.add(e.key) - return ret - - def __sub__(self, other: Iterable[object]) -> set[str]: - ret = set(self) - try: - it = iter(other) - except TypeError: - return NotImplemented - for key in it: - if not isinstance(key, str): - continue - identity = self._md._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._md._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - ret.discard(e.key) - break - return ret - - def __rsub__(self, other: Iterable[_T]) -> set[_T]: - try: - ret: set[_T] = set(other) - except TypeError: - return NotImplemented - for key in other: - if not isinstance(key, str): - continue - if key in self._md: - ret.discard(key) # type: ignore[arg-type] - return ret - - def __xor__(self, other: Iterable[_T]) -> set[Union[str, _T]]: - try: - rgt = set(other) - except TypeError: - return NotImplemented - ret: set[Union[str, _T]] = self - rgt # type: ignore[assignment] - ret |= rgt - self - return ret - - __rxor__ = __xor__ - - def isdisjoint(self, other: Iterable[object]) -> bool: - for key in other: - if not isinstance(key, str): - continue - if key in self._md: - return False - return True - - -class _CSMixin: - _ci: ClassVar[bool] = False - - def _key(self, key: str) -> str: - return key - - def _identity(self, key: str) -> str: - if isinstance(key, str): - return key - else: - raise TypeError("MultiDict keys should be either str or subclasses of str") - - -class _CIMixin: - _ci: ClassVar[bool] = True - - def _key(self, key: str) -> str: - if type(key) is istr: - return key - else: - return istr(key) - - def _identity(self, key: str) -> str: - if isinstance(key, istr): - ret = key.__istr_identity__ - if ret is None: - ret = key.lower() - key.__istr_identity__ = ret - return ret - if isinstance(key, str): - return key.lower() - else: - raise TypeError("MultiDict keys should be either str or subclasses of str") - - -def estimate_log2_keysize(n: int) -> int: - # 7 == HT_MINSIZE - 1 - return (((n * 3 + 1) // 2) | 7).bit_length() - - -@dataclass -class _Entry(Generic[_V]): - hash: int - identity: str - key: str - value: _V - - -@dataclass -class _HtKeys(Generic[_V]): # type: ignore[misc] - LOG_MINSIZE: ClassVar[int] = 3 - MINSIZE: ClassVar[int] = 8 - PREALLOCATED_INDICES: ClassVar[dict[int, array]] = { # type: ignore[type-arg] - log2_size: array( - "b" if log2_size < 8 else "h", (-1 for i in range(1 << log2_size)) - ) - for log2_size in range(3, 10) - } - - log2_size: int - usable: int - - indices: array # type: ignore[type-arg] # in py3.9 array is not generic - entries: list[Optional[_Entry[_V]]] - - @functools.cached_property - def nslots(self) -> int: - return 1 << self.log2_size - - @functools.cached_property - def mask(self) -> int: - return self.nslots - 1 - - if sys.implementation.name != "pypy": - - def __sizeof__(self) -> int: - return ( - object.__sizeof__(self) - + sys.getsizeof(self.indices) - + sys.getsizeof(self.entries) - ) - - @classmethod - def new(cls, log2_size: int, entries: list[Optional[_Entry[_V]]]) -> Self: - size = 1 << log2_size - usable = (size << 1) // 3 - if log2_size < 10: - indices = cls.PREALLOCATED_INDICES[log2_size].__copy__() - elif log2_size < 16: - indices = array("h", (-1 for i in range(size))) - elif log2_size < 32: - indices = array("l", (-1 for i in range(size))) - else: # pragma: no cover # don't test huge multidicts - indices = array("q", (-1 for i in range(size))) - ret = cls( - log2_size=log2_size, - usable=usable, - indices=indices, - entries=entries, - ) - return ret - - def clone(self) -> "_HtKeys[_V]": - entries = [ - _Entry(e.hash, e.identity, e.key, e.value) if e is not None else None - for e in self.entries - ] - - return _HtKeys( - log2_size=self.log2_size, - usable=self.usable, - indices=self.indices.__copy__(), - entries=entries, - ) - - def build_indices(self, update: bool) -> None: - mask = self.mask - indices = self.indices - for idx, e in enumerate(self.entries): - assert e is not None - hash_ = e.hash - if update: - if hash_ == -1: - hash_ = hash(e.identity) - else: - assert hash_ != -1 - i = hash_ & mask - perturb = hash_ & sys.maxsize - while indices[i] != -1: - perturb >>= 5 - i = mask & (i * 5 + perturb + 1) - indices[i] = idx - - def find_empty_slot(self, hash_: int) -> int: - mask = self.mask - indices = self.indices - i = hash_ & mask - perturb = hash_ & sys.maxsize - ix = indices[i] - while ix != -1: - perturb >>= 5 - i = (i * 5 + perturb + 1) & mask - ix = indices[i] - return i - - def iter_hash(self, hash_: int) -> Iterator[tuple[int, int, _Entry[_V]]]: - mask = self.mask - indices = self.indices - entries = self.entries - i = hash_ & mask - perturb = hash_ & sys.maxsize - ix = indices[i] - while ix != -1: - if ix != -2: - e = entries[ix] - if e.hash == hash_: - yield i, ix, e - perturb >>= 5 - i = (i * 5 + perturb + 1) & mask - ix = indices[i] - - def del_idx(self, hash_: int, idx: int) -> None: - mask = self.mask - indices = self.indices - i = hash_ & mask - perturb = hash_ & sys.maxsize - ix = indices[i] - while ix != idx: - perturb >>= 5 - i = (i * 5 + perturb + 1) & mask - ix = indices[i] - indices[i] = -2 - - def iter_entries(self) -> Iterator[_Entry[_V]]: - return filter(None, self.entries) - - def restore_hash(self, hash_: int) -> None: - mask = self.mask - indices = self.indices - entries = self.entries - i = hash_ & mask - perturb = hash_ & sys.maxsize - ix = indices[i] - while ix != -1: - if ix != -2: - entry = entries[ix] - if entry.hash == -1: - entry.hash = hash_ - perturb >>= 5 - i = (i * 5 + perturb + 1) & mask - ix = indices[i] - - -class MultiDict(_CSMixin, MutableMultiMapping[_V]): - """Dictionary with the support for duplicate keys.""" - - __slots__ = ("_keys", "_used", "_version") - - def __init__(self, arg: MDArg[_V] = None, /, **kwargs: _V): - self._used = 0 - v = _version - v[0] += 1 - self._version = v[0] - if not kwargs: - md = None - if isinstance(arg, MultiDictProxy): - md = arg._md - elif isinstance(arg, MultiDict): - md = arg - if md is not None and md._ci is self._ci: - self._from_md(md) - return - - it = self._parse_args(arg, kwargs) - log2_size = estimate_log2_keysize(cast(int, next(it))) - if log2_size > 17: # pragma: no cover - # Don't overallocate really huge keys space in init - log2_size = 17 - self._keys: _HtKeys[_V] = _HtKeys.new(log2_size, []) - self._extend_items(cast(Iterator[_Entry[_V]], it)) - - def _from_md(self, md: "MultiDict[_V]") -> None: - # Copy everything as-is without compacting the new multidict, - # otherwise it requires reindexing - self._keys = md._keys.clone() - self._used = md._used - - @overload - def getall(self, key: str) -> list[_V]: ... - @overload - def getall(self, key: str, default: _T) -> Union[list[_V], _T]: ... - def getall( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[list[_V], _T]: - """Return a list of all values matching the key.""" - identity = self._identity(key) - hash_ = hash(identity) - res = [] - restore = [] - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - res.append(e.value) - e.hash = -1 - restore.append(idx) - - if res: - entries = self._keys.entries - for idx in restore: - entries[idx].hash = hash_ # type: ignore[union-attr] - return res - if not res and default is not sentinel: - return default - raise KeyError("Key not found: %r" % key) - - @overload - def getone(self, key: str) -> _V: ... - @overload - def getone(self, key: str, default: _T) -> Union[_V, _T]: ... - def getone( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[_V, _T]: - """Get first value matching the key. - - Raises KeyError if the key is not found and no default is provided. - """ - identity = self._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - return e.value - if default is not sentinel: - return default - raise KeyError("Key not found: %r" % key) - - # Mapping interface # - - def __getitem__(self, key: str) -> _V: - return self.getone(key) - - @overload - def get(self, key: str, /) -> Union[_V, None]: ... - @overload - def get(self, key: str, /, default: _T) -> Union[_V, _T]: ... - def get(self, key: str, default: Union[_T, None] = None) -> Union[_V, _T, None]: - """Get first value matching the key. - - If the key is not found, returns the default (or None if no default is provided) - """ - return self.getone(key, default) - - def __iter__(self) -> Iterator[str]: - return iter(self.keys()) - - def __len__(self) -> int: - return self._used - - def keys(self) -> KeysView[str]: - """Return a new view of the dictionary's keys.""" - return _KeysView(self) - - def items(self) -> ItemsView[str, _V]: - """Return a new view of the dictionary's items *(key, value) pairs).""" - return _ItemsView(self) - - def values(self) -> _ValuesView[_V]: - """Return a new view of the dictionary's values.""" - return _ValuesView(self) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Mapping): - return NotImplemented - if isinstance(other, MultiDictProxy): - return self == other._md - if isinstance(other, MultiDict): - lft = self._keys - rht = other._keys - if self._used != other._used: - return False - for e1, e2 in zip(lft.iter_entries(), rht.iter_entries()): - if e1.identity != e2.identity or e1.value != e2.value: - return False - return True - if self._used != len(other): - return False - for k, v in self.items(): - nv = other.get(k, sentinel) - if v != nv: - return False - return True - - def __contains__(self, key: object) -> bool: - if not isinstance(key, str): - return False - identity = self._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - return True - return False - - @reprlib.recursive_repr() - def __repr__(self) -> str: - body = ", ".join(f"'{e.key}': {e.value!r}" for e in self._keys.iter_entries()) - return f"<{self.__class__.__name__}({body})>" - - if sys.implementation.name != "pypy": - - def __sizeof__(self) -> int: - return object.__sizeof__(self) + sys.getsizeof(self._keys) - - def __reduce__(self) -> tuple[type[Self], tuple[list[tuple[str, _V]]]]: - return (self.__class__, (list(self.items()),)) - - def add(self, key: str, value: _V) -> None: - identity = self._identity(key) - hash_ = hash(identity) - self._add_with_hash(_Entry(hash_, identity, key, value)) - self._incr_version() - - def copy(self) -> Self: - """Return a copy of itself.""" - cls = self.__class__ - return cls(self) - - __copy__ = copy - - def extend(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None: - """Extend current MultiDict with more values. - - This method must be used instead of update. - """ - it = self._parse_args(arg, kwargs) - newsize = self._used + cast(int, next(it)) - self._resize(estimate_log2_keysize(newsize), False) - self._extend_items(cast(Iterator[_Entry[_V]], it)) - - def _parse_args( - self, - arg: MDArg[_V], - kwargs: Mapping[str, _V], - ) -> Iterator[Union[int, _Entry[_V]]]: - identity_func = self._identity - if arg: - if isinstance(arg, MultiDictProxy): - arg = arg._md - if isinstance(arg, MultiDict): - yield len(arg) + len(kwargs) - if self._ci is not arg._ci: - for e in arg._keys.iter_entries(): - identity = identity_func(e.key) - yield _Entry(hash(identity), identity, e.key, e.value) - else: - for e in arg._keys.iter_entries(): - yield _Entry(e.hash, e.identity, e.key, e.value) - if kwargs: - for key, value in kwargs.items(): - identity = identity_func(key) - yield _Entry(hash(identity), identity, key, value) - else: - if hasattr(arg, "keys"): - arg = cast(SupportsKeys[_V], arg) - arg = [(k, arg[k]) for k in arg.keys()] - if kwargs: - arg = list(arg) - arg.extend(list(kwargs.items())) - try: - yield len(arg) + len(kwargs) # type: ignore[arg-type] - except TypeError: - yield 0 - for pos, item in enumerate(arg): - if not len(item) == 2: - raise ValueError( - f"multidict update sequence element #{pos}" - f"has length {len(item)}; 2 is required" - ) - identity = identity_func(item[0]) - yield _Entry(hash(identity), identity, item[0], item[1]) - else: - yield len(kwargs) - for key, value in kwargs.items(): - identity = identity_func(key) - yield _Entry(hash(identity), identity, key, value) - - def _extend_items(self, items: Iterable[_Entry[_V]]) -> None: - for e in items: - self._add_with_hash(e) - self._incr_version() - - def clear(self) -> None: - """Remove all items from MultiDict.""" - self._used = 0 - self._keys = _HtKeys.new(_HtKeys.LOG_MINSIZE, []) - self._incr_version() - - # Mapping interface # - - def __setitem__(self, key: str, value: _V) -> None: - identity = self._identity(key) - hash_ = hash(identity) - found = False - - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - if not found: - e.key = key - e.value = value - e.hash = -1 - found = True - self._incr_version() - elif e.hash != -1: # pragma: no branch - self._del_at(slot, idx) - - if not found: - self._add_with_hash(_Entry(hash_, identity, key, value)) - else: - self._keys.restore_hash(hash_) - - def __delitem__(self, key: str) -> None: - found = False - identity = self._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - self._del_at(slot, idx) - found = True - if not found: - raise KeyError(key) - else: - self._incr_version() - - @overload - def setdefault( - self: "MultiDict[Union[_T, None]]", key: str, default: None = None - ) -> Union[_T, None]: ... - @overload - def setdefault(self, key: str, default: _V) -> _V: ... - def setdefault(self, key: str, default: Union[_V, None] = None) -> Union[_V, None]: # type: ignore[misc] - """Return value for key, set value to default if key is not present.""" - identity = self._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - return e.value - self.add(key, default) # type: ignore[arg-type] - return default - - @overload - def popone(self, key: str) -> _V: ... - @overload - def popone(self, key: str, default: _T) -> Union[_V, _T]: ... - def popone( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[_V, _T]: - """Remove specified key and return the corresponding value. - - If key is not found, d is returned if given, otherwise - KeyError is raised. - - """ - identity = self._identity(key) - hash_ = hash(identity) - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - value = e.value - self._del_at(slot, idx) - self._incr_version() - return value - if default is sentinel: - raise KeyError(key) - else: - return default - - # Type checking will inherit signature for pop() if we don't confuse it here. - if not TYPE_CHECKING: - pop = popone - - @overload - def popall(self, key: str) -> list[_V]: ... - @overload - def popall(self, key: str, default: _T) -> Union[list[_V], _T]: ... - def popall( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[list[_V], _T]: - """Remove all occurrences of key and return the list of corresponding - values. - - If key is not found, default is returned if given, otherwise - KeyError is raised. - - """ - found = False - identity = self._identity(key) - hash_ = hash(identity) - ret = [] - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - found = True - ret.append(e.value) - self._del_at(slot, idx) - self._incr_version() - - if not found: - if default is sentinel: - raise KeyError(key) - else: - return default - else: - return ret - - def popitem(self) -> tuple[str, _V]: - """Remove and return an arbitrary (key, value) pair.""" - if self._used <= 0: - raise KeyError("empty multidict") - - pos = len(self._keys.entries) - 1 - entry = self._keys.entries.pop() - - while entry is None: - pos -= 1 - entry = self._keys.entries.pop() - - ret = self._key(entry.key), entry.value - self._keys.del_idx(entry.hash, pos) - self._used -= 1 - self._incr_version() - return ret - - def update(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None: - """Update the dictionary, overwriting existing keys.""" - it = self._parse_args(arg, kwargs) - newsize = self._used + cast(int, next(it)) - log2_size = estimate_log2_keysize(newsize) - if log2_size > 17: # pragma: no cover - # Don't overallocate really huge keys space in update, - # duplicate keys could reduce the resulting anount of entries - log2_size = 17 - if log2_size > self._keys.log2_size: - self._resize(log2_size, False) - try: - self._update_items(cast(Iterator[_Entry[_V]], it)) - finally: - self._post_update() - - def _update_items(self, items: Iterator[_Entry[_V]]) -> None: - for entry in items: - found = False - hash_ = entry.hash - identity = entry.identity - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - if not found: - found = True - e.key = entry.key - e.value = entry.value - e.hash = -1 - else: - self._del_at_for_upd(e) - if not found: - self._add_with_hash_for_upd(entry) - - def _post_update(self) -> None: - keys = self._keys - indices = keys.indices - entries = keys.entries - for slot in range(keys.nslots): - idx = indices[slot] - if idx >= 0: - e2 = entries[idx] - assert e2 is not None - if e2.key is None: - entries[idx] = None - indices[slot] = -2 - self._used -= 1 - if e2.hash == -1: - e2.hash = hash(e2.identity) - - self._incr_version() - - def merge(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None: - """Merge into the dictionary, adding non-existing keys.""" - it = self._parse_args(arg, kwargs) - newsize = self._used + cast(int, next(it)) - log2_size = estimate_log2_keysize(newsize) - if log2_size > 17: # pragma: no cover - # Don't overallocate really huge keys space in update, - # duplicate keys could reduce the resulting anount of entries - log2_size = 17 - if log2_size > self._keys.log2_size: - self._resize(log2_size, False) - try: - self._merge_items(cast(Iterator[_Entry[_V]], it)) - finally: - self._post_update() - - def _merge_items(self, items: Iterator[_Entry[_V]]) -> None: - for entry in items: - hash_ = entry.hash - identity = entry.identity - for slot, idx, e in self._keys.iter_hash(hash_): - if e.identity == identity: # pragma: no branch - break - else: - self._add_with_hash_for_upd(entry) - - def _incr_version(self) -> None: - v = _version - v[0] += 1 - self._version = v[0] - - def _resize(self, log2_newsize: int, update: bool) -> None: - oldkeys = self._keys - newentries = self._used - - if len(oldkeys.entries) == newentries: - entries = oldkeys.entries - else: - entries = [e for e in oldkeys.entries if e is not None] - newkeys: _HtKeys[_V] = _HtKeys.new(log2_newsize, entries) - newkeys.usable -= newentries - newkeys.build_indices(update) - self._keys = newkeys - - def _add_with_hash(self, entry: _Entry[_V]) -> None: - if self._keys.usable <= 0: - self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), False) - keys = self._keys - slot = keys.find_empty_slot(entry.hash) - keys.indices[slot] = len(keys.entries) - keys.entries.append(entry) - self._incr_version() - self._used += 1 - keys.usable -= 1 - - def _add_with_hash_for_upd(self, entry: _Entry[_V]) -> None: - if self._keys.usable <= 0: - self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), True) - keys = self._keys - slot = keys.find_empty_slot(entry.hash) - keys.indices[slot] = len(keys.entries) - entry.hash = -1 - keys.entries.append(entry) - self._incr_version() - self._used += 1 - keys.usable -= 1 - - def _del_at(self, slot: int, idx: int) -> None: - self._keys.entries[idx] = None - self._keys.indices[slot] = -2 - self._used -= 1 - - def _del_at_for_upd(self, entry: _Entry[_V]) -> None: - entry.key = None # type: ignore[assignment] - entry.value = None # type: ignore[assignment] - - -class CIMultiDict(_CIMixin, MultiDict[_V]): - """Dictionary with the support for duplicate case-insensitive keys.""" - - -class MultiDictProxy(_CSMixin, MultiMapping[_V]): - """Read-only proxy for MultiDict instance.""" - - __slots__ = ("_md",) - - _md: MultiDict[_V] - - def __init__(self, arg: Union[MultiDict[_V], "MultiDictProxy[_V]"]): - if not isinstance(arg, (MultiDict, MultiDictProxy)): - raise TypeError( - f"ctor requires MultiDict or MultiDictProxy instance, not {type(arg)}" - ) - if isinstance(arg, MultiDictProxy): - self._md = arg._md - else: - self._md = arg - - def __reduce__(self) -> NoReturn: - raise TypeError(f"can't pickle {self.__class__.__name__} objects") - - @overload - def getall(self, key: str) -> list[_V]: ... - @overload - def getall(self, key: str, default: _T) -> Union[list[_V], _T]: ... - def getall( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[list[_V], _T]: - """Return a list of all values matching the key.""" - if default is not sentinel: - return self._md.getall(key, default) - else: - return self._md.getall(key) - - @overload - def getone(self, key: str) -> _V: ... - @overload - def getone(self, key: str, default: _T) -> Union[_V, _T]: ... - def getone( - self, key: str, default: Union[_T, _SENTINEL] = sentinel - ) -> Union[_V, _T]: - """Get first value matching the key. - - Raises KeyError if the key is not found and no default is provided. - """ - if default is not sentinel: - return self._md.getone(key, default) - else: - return self._md.getone(key) - - # Mapping interface # - - def __getitem__(self, key: str) -> _V: - return self.getone(key) - - @overload - def get(self, key: str, /) -> Union[_V, None]: ... - @overload - def get(self, key: str, /, default: _T) -> Union[_V, _T]: ... - def get(self, key: str, default: Union[_T, None] = None) -> Union[_V, _T, None]: - """Get first value matching the key. - - If the key is not found, returns the default (or None if no default is provided) - """ - return self._md.getone(key, default) - - def __iter__(self) -> Iterator[str]: - return iter(self._md.keys()) - - def __len__(self) -> int: - return len(self._md) - - def keys(self) -> KeysView[str]: - """Return a new view of the dictionary's keys.""" - return self._md.keys() - - def items(self) -> ItemsView[str, _V]: - """Return a new view of the dictionary's items *(key, value) pairs).""" - return self._md.items() - - def values(self) -> _ValuesView[_V]: - """Return a new view of the dictionary's values.""" - return self._md.values() - - def __eq__(self, other: object) -> bool: - return self._md == other - - def __contains__(self, key: object) -> bool: - return key in self._md - - @reprlib.recursive_repr() - def __repr__(self) -> str: - body = ", ".join(f"'{k}': {v!r}" for k, v in self.items()) - return f"<{self.__class__.__name__}({body})>" - - def copy(self) -> MultiDict[_V]: - """Return a copy of itself.""" - return MultiDict(self._md) - - -class CIMultiDictProxy(_CIMixin, MultiDictProxy[_V]): - """Read-only proxy for CIMultiDict instance.""" - - def __init__(self, arg: Union[MultiDict[_V], MultiDictProxy[_V]]): - if not isinstance(arg, (CIMultiDict, CIMultiDictProxy)): - raise TypeError( - "ctor requires CIMultiDict or CIMultiDictProxy instance" - f", not {type(arg)}" - ) - - super().__init__(arg) - - def copy(self) -> CIMultiDict[_V]: - """Return a copy of itself.""" - return CIMultiDict(self._md) - - -def getversion(md: Union[MultiDict[object], MultiDictProxy[object]]) -> int: - if isinstance(md, MultiDictProxy): - md = md._md - elif not isinstance(md, MultiDict): - raise TypeError("Parameter should be multidict or proxy") - return md._version diff --git a/backend/venv39/lib/python3.9/site-packages/multidict/py.typed b/backend/venv39/lib/python3.9/site-packages/multidict/py.typed deleted file mode 100644 index dfe8cc0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multidict/py.typed +++ /dev/null @@ -1 +0,0 @@ -PEP-561 marker. \ No newline at end of file diff --git a/backend/venv39/lib/python3.9/site-packages/multipart/__init__.py b/backend/venv39/lib/python3.9/site-packages/multipart/__init__.py deleted file mode 100644 index 67f0e5b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multipart/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# This only works if using a file system, other loaders not implemented. - -import importlib.util -import sys -import warnings -from pathlib import Path - -for p in sys.path: - file_path = Path(p, "multipart.py") - try: - if file_path.is_file(): - spec = importlib.util.spec_from_file_location("multipart", file_path) - assert spec is not None, f"{file_path} found but not loadable!" - module = importlib.util.module_from_spec(spec) - sys.modules["multipart"] = module - assert spec.loader is not None, f"{file_path} must be loadable!" - spec.loader.exec_module(module) - break - except PermissionError: - pass -else: - warnings.warn("Please use `import python_multipart` instead.", PendingDeprecationWarning, stacklevel=2) - from python_multipart import * - from python_multipart import __all__, __author__, __copyright__, __license__, __version__ diff --git a/backend/venv39/lib/python3.9/site-packages/multipart/decoders.py b/backend/venv39/lib/python3.9/site-packages/multipart/decoders.py deleted file mode 100644 index 31acdfb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multipart/decoders.py +++ /dev/null @@ -1 +0,0 @@ -from python_multipart.decoders import * diff --git a/backend/venv39/lib/python3.9/site-packages/multipart/exceptions.py b/backend/venv39/lib/python3.9/site-packages/multipart/exceptions.py deleted file mode 100644 index 36815d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multipart/exceptions.py +++ /dev/null @@ -1 +0,0 @@ -from python_multipart.exceptions import * diff --git a/backend/venv39/lib/python3.9/site-packages/multipart/multipart.py b/backend/venv39/lib/python3.9/site-packages/multipart/multipart.py deleted file mode 100644 index 7bf567d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/multipart/multipart.py +++ /dev/null @@ -1 +0,0 @@ -from python_multipart.multipart import * diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/METADATA deleted file mode 100644 index 0df49d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/METADATA +++ /dev/null @@ -1,908 +0,0 @@ -Metadata-Version: 2.3 -Name: openai -Version: 2.15.0 -Summary: The official Python library for the openai API -Project-URL: Homepage, https://github.com/openai/openai-python -Project-URL: Repository, https://github.com/openai/openai-python -Author-email: OpenAI -License: Apache-2.0 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: MacOS -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: OS Independent -Classifier: Operating System :: POSIX -Classifier: Operating System :: POSIX :: Linux -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 :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Typing :: Typed -Requires-Python: >=3.9 -Requires-Dist: anyio<5,>=3.5.0 -Requires-Dist: distro<2,>=1.7.0 -Requires-Dist: httpx<1,>=0.23.0 -Requires-Dist: jiter<1,>=0.10.0 -Requires-Dist: pydantic<3,>=1.9.0 -Requires-Dist: sniffio -Requires-Dist: tqdm>4 -Requires-Dist: typing-extensions<5,>=4.11 -Provides-Extra: aiohttp -Requires-Dist: aiohttp; extra == 'aiohttp' -Requires-Dist: httpx-aiohttp>=0.1.9; extra == 'aiohttp' -Provides-Extra: datalib -Requires-Dist: numpy>=1; extra == 'datalib' -Requires-Dist: pandas-stubs>=1.1.0.11; extra == 'datalib' -Requires-Dist: pandas>=1.2.3; extra == 'datalib' -Provides-Extra: realtime -Requires-Dist: websockets<16,>=13; extra == 'realtime' -Provides-Extra: voice-helpers -Requires-Dist: numpy>=2.0.2; extra == 'voice-helpers' -Requires-Dist: sounddevice>=0.5.1; extra == 'voice-helpers' -Description-Content-Type: text/markdown - -# OpenAI Python API library - - -[![PyPI version](https://img.shields.io/pypi/v/openai.svg?label=pypi%20(stable))](https://pypi.org/project/openai/) - -The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.9+ -application. The library includes type definitions for all request params and response fields, -and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). - -It is generated from our [OpenAPI specification](https://github.com/openai/openai-openapi) with [Stainless](https://stainlessapi.com/). - -## Documentation - -The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs/api-reference). The full API of this library can be found in [api.md](https://github.com/openai/openai-python/tree/main/api.md). - -## Installation - -```sh -# install from PyPI -pip install openai -``` - -## Usage - -The full API of this library can be found in [api.md](https://github.com/openai/openai-python/tree/main/api.md). - -The primary API for interacting with OpenAI models is the [Responses API](https://platform.openai.com/docs/api-reference/responses). You can generate text from the model with the code below. - -```python -import os -from openai import OpenAI - -client = OpenAI( - # This is the default and can be omitted - api_key=os.environ.get("OPENAI_API_KEY"), -) - -response = client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", -) - -print(response.output_text) -``` - -The previous standard (supported indefinitely) for generating text is the [Chat Completions API](https://platform.openai.com/docs/api-reference/chat). You can use that API to generate text from the model with the code below. - -```python -from openai import OpenAI - -client = OpenAI() - -completion = client.chat.completions.create( - model="gpt-4o", - messages=[ - {"role": "developer", "content": "Talk like a pirate."}, - { - "role": "user", - "content": "How do I check if a Python object is an instance of a class?", - }, - ], -) - -print(completion.choices[0].message.content) -``` - -While you can provide an `api_key` keyword argument, -we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -to add `OPENAI_API_KEY="My API Key"` to your `.env` file -so that your API key is not stored in source control. -[Get an API key here](https://platform.openai.com/settings/organization/api-keys). - -### Vision - -With an image URL: - -```python -prompt = "What is in this image?" -img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg" - -response = client.responses.create( - model="gpt-4o-mini", - input=[ - { - "role": "user", - "content": [ - {"type": "input_text", "text": prompt}, - {"type": "input_image", "image_url": f"{img_url}"}, - ], - } - ], -) -``` - -With the image as a base64 encoded string: - -```python -import base64 -from openai import OpenAI - -client = OpenAI() - -prompt = "What is in this image?" -with open("path/to/image.png", "rb") as image_file: - b64_image = base64.b64encode(image_file.read()).decode("utf-8") - -response = client.responses.create( - model="gpt-4o-mini", - input=[ - { - "role": "user", - "content": [ - {"type": "input_text", "text": prompt}, - {"type": "input_image", "image_url": f"data:image/png;base64,{b64_image}"}, - ], - } - ], -) -``` - -## Async usage - -Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call: - -```python -import os -import asyncio -from openai import AsyncOpenAI - -client = AsyncOpenAI( - # This is the default and can be omitted - api_key=os.environ.get("OPENAI_API_KEY"), -) - - -async def main() -> None: - response = await client.responses.create( - model="gpt-4o", input="Explain disestablishmentarianism to a smart five year old." - ) - print(response.output_text) - - -asyncio.run(main()) -``` - -Functionality between the synchronous and asynchronous clients is otherwise identical. - -### With aiohttp - -By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. - -You can enable this by installing `aiohttp`: - -```sh -# install from PyPI -pip install openai[aiohttp] -``` - -Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: - -```python -import os -import asyncio -from openai import DefaultAioHttpClient -from openai import AsyncOpenAI - - -async def main() -> None: - async with AsyncOpenAI( - api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted - http_client=DefaultAioHttpClient(), - ) as client: - chat_completion = await client.chat.completions.create( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", - ) - - -asyncio.run(main()) -``` - -## Streaming responses - -We provide support for streaming responses using Server Side Events (SSE). - -```python -from openai import OpenAI - -client = OpenAI() - -stream = client.responses.create( - model="gpt-4o", - input="Write a one-sentence bedtime story about a unicorn.", - stream=True, -) - -for event in stream: - print(event) -``` - -The async client uses the exact same interface. - -```python -import asyncio -from openai import AsyncOpenAI - -client = AsyncOpenAI() - - -async def main(): - stream = await client.responses.create( - model="gpt-4o", - input="Write a one-sentence bedtime story about a unicorn.", - stream=True, - ) - - async for event in stream: - print(event) - - -asyncio.run(main()) -``` - -## Realtime API - -The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a WebSocket connection. - -Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections. - -The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](https://platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime). - -Basic text based example: - -```py -import asyncio -from openai import AsyncOpenAI - -async def main(): - client = AsyncOpenAI() - - async with client.realtime.connect(model="gpt-realtime") as connection: - await connection.session.update( - session={"type": "realtime", "output_modalities": ["text"]} - ) - - await connection.conversation.item.create( - item={ - "type": "message", - "role": "user", - "content": [{"type": "input_text", "text": "Say hello!"}], - } - ) - await connection.response.create() - - async for event in connection: - if event.type == "response.output_text.delta": - print(event.delta, flush=True, end="") - - elif event.type == "response.output_text.done": - print() - - elif event.type == "response.done": - break - -asyncio.run(main()) -``` - -However the real magic of the Realtime API is handling audio inputs / outputs, see this example [TUI script](https://github.com/openai/openai-python/blob/main/examples/realtime/push_to_talk_app.py) for a fully fledged example. - -### Realtime error handling - -Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling) and the connection will stay open and remain usable. This means you need to handle it yourself, as _no errors are raised directly_ by the SDK when an `error` event comes in. - -```py -client = AsyncOpenAI() - -async with client.realtime.connect(model="gpt-realtime") as connection: - ... - async for event in connection: - if event.type == 'error': - print(event.error.type) - print(event.error.code) - print(event.error.event_id) - print(event.error.message) -``` - -## Using types - -Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: - -- Serializing back into JSON, `model.to_json()` -- Converting to a dictionary, `model.to_dict()` - -Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. - -## Pagination - -List methods in the OpenAI API are paginated. - -This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: - -```python -from openai import OpenAI - -client = OpenAI() - -all_jobs = [] -# Automatically fetches more pages as needed. -for job in client.fine_tuning.jobs.list( - limit=20, -): - # Do something with job here - all_jobs.append(job) -print(all_jobs) -``` - -Or, asynchronously: - -```python -import asyncio -from openai import AsyncOpenAI - -client = AsyncOpenAI() - - -async def main() -> None: - all_jobs = [] - # Iterate through items across all pages, issuing requests as needed. - async for job in client.fine_tuning.jobs.list( - limit=20, - ): - all_jobs.append(job) - print(all_jobs) - - -asyncio.run(main()) -``` - -Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: - -```python -first_page = await client.fine_tuning.jobs.list( - limit=20, -) -if first_page.has_next_page(): - print(f"will fetch next page using these details: {first_page.next_page_info()}") - next_page = await first_page.get_next_page() - print(f"number of items we just fetched: {len(next_page.data)}") - -# Remove `await` for non-async usage. -``` - -Or just work directly with the returned data: - -```python -first_page = await client.fine_tuning.jobs.list( - limit=20, -) - -print(f"next page cursor: {first_page.after}") # => "next page cursor: ..." -for job in first_page.data: - print(job.id) - -# Remove `await` for non-async usage. -``` - -## Nested params - -Nested parameters are dictionaries, typed using `TypedDict`, for example: - -```python -from openai import OpenAI - -client = OpenAI() - -response = client.chat.responses.create( - input=[ - { - "role": "user", - "content": "How much ?", - } - ], - model="gpt-4o", - response_format={"type": "json_object"}, -) -``` - -## File uploads - -Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. - -```python -from pathlib import Path -from openai import OpenAI - -client = OpenAI() - -client.files.create( - file=Path("input.jsonl"), - purpose="fine-tune", -) -``` - -The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. - -## Webhook Verification - -Verifying webhook signatures is _optional but encouraged_. - -For more information about webhooks, see [the API docs](https://platform.openai.com/docs/guides/webhooks). - -### Parsing webhook payloads - -For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.webhooks.unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will raise an error if the signature is invalid. - -Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). The `.unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from OpenAI. - -```python -from openai import OpenAI -from flask import Flask, request - -app = Flask(__name__) -client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default - - -@app.route("/webhook", methods=["POST"]) -def webhook(): - request_body = request.get_data(as_text=True) - - try: - event = client.webhooks.unwrap(request_body, request.headers) - - if event.type == "response.completed": - print("Response completed:", event.data) - elif event.type == "response.failed": - print("Response failed:", event.data) - else: - print("Unhandled event type:", event.type) - - return "ok" - except Exception as e: - print("Invalid signature:", e) - return "Invalid signature", 400 - - -if __name__ == "__main__": - app.run(port=8000) -``` - -### Verifying webhook payloads directly - -In some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.webhooks.verify_signature()` to _only verify_ the signature of a webhook request. Like `.unwrap()`, this method will raise an error if the signature is invalid. - -Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). You will then need to parse the body after verifying the signature. - -```python -import json -from openai import OpenAI -from flask import Flask, request - -app = Flask(__name__) -client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default - - -@app.route("/webhook", methods=["POST"]) -def webhook(): - request_body = request.get_data(as_text=True) - - try: - client.webhooks.verify_signature(request_body, request.headers) - - # Parse the body after verification - event = json.loads(request_body) - print("Verified event:", event) - - return "ok" - except Exception as e: - print("Invalid signature:", e) - return "Invalid signature", 400 - - -if __name__ == "__main__": - app.run(port=8000) -``` - -## Handling errors - -When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `openai.APIConnectionError` is raised. - -When the API returns a non-success status code (that is, 4xx or 5xx -response), a subclass of `openai.APIStatusError` is raised, containing `status_code` and `response` properties. - -All errors inherit from `openai.APIError`. - -```python -import openai -from openai import OpenAI - -client = OpenAI() - -try: - client.fine_tuning.jobs.create( - model="gpt-4o", - training_file="file-abc123", - ) -except openai.APIConnectionError as e: - print("The server could not be reached") - print(e.__cause__) # an underlying Exception, likely raised within httpx. -except openai.RateLimitError as e: - print("A 429 status code was received; we should back off a bit.") -except openai.APIStatusError as e: - print("Another non-200-range status code was received") - print(e.status_code) - print(e.response) -``` - -Error codes are as follows: - -| Status Code | Error Type | -| ----------- | -------------------------- | -| 400 | `BadRequestError` | -| 401 | `AuthenticationError` | -| 403 | `PermissionDeniedError` | -| 404 | `NotFoundError` | -| 422 | `UnprocessableEntityError` | -| 429 | `RateLimitError` | -| >=500 | `InternalServerError` | -| N/A | `APIConnectionError` | - -## Request IDs - -> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests) - -All object responses in the SDK provide a `_request_id` property which is added from the `x-request-id` response header so that you can quickly log failing requests and report them back to OpenAI. - -```python -response = await client.responses.create( - model="gpt-4o-mini", - input="Say 'this is a test'.", -) -print(response._request_id) # req_123 -``` - -Note that unlike other properties that use an `_` prefix, the `_request_id` property -_is_ public. Unless documented otherwise, _all_ other `_` prefix properties, -methods and modules are _private_. - -> [!IMPORTANT] -> If you need to access request IDs for failed requests you must catch the `APIStatusError` exception - -```python -import openai - -try: - completion = await client.chat.completions.create( - messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4" - ) -except openai.APIStatusError as exc: - print(exc.request_id) # req_123 - raise exc -``` - -## Retries - -Certain errors are automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors are all retried by default. - -You can use the `max_retries` option to configure or disable retry settings: - -```python -from openai import OpenAI - -# Configure the default for all requests: -client = OpenAI( - # default is 2 - max_retries=0, -) - -# Or, configure per-request: -client.with_options(max_retries=5).chat.completions.create( - messages=[ - { - "role": "user", - "content": "How can I get the name of the current day in JavaScript?", - } - ], - model="gpt-4o", -) -``` - -## Timeouts - -By default requests time out after 10 minutes. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: - -```python -from openai import OpenAI - -# Configure the default for all requests: -client = OpenAI( - # 20 seconds (default is 10 minutes) - timeout=20.0, -) - -# More granular control: -client = OpenAI( - timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), -) - -# Override per-request: -client.with_options(timeout=5.0).chat.completions.create( - messages=[ - { - "role": "user", - "content": "How can I list all files in a directory using Python?", - } - ], - model="gpt-4o", -) -``` - -On timeout, an `APITimeoutError` is thrown. - -Note that requests that time out are [retried twice by default](https://github.com/openai/openai-python/tree/main/#retries). - -## Advanced - -### Logging - -We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. - -You can enable logging by setting the environment variable `OPENAI_LOG` to `info`. - -```shell -$ export OPENAI_LOG=info -``` - -Or to `debug` for more verbose logging. - -### How to tell whether `None` means `null` or missing - -In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: - -```py -if response.my_field is None: - if 'my_field' not in response.model_fields_set: - print('Got json like {}, without a "my_field" key present at all.') - else: - print('Got json like {"my_field": null}.') -``` - -### Accessing raw response data (e.g. headers) - -The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., - -```py -from openai import OpenAI - -client = OpenAI() -response = client.chat.completions.with_raw_response.create( - messages=[{ - "role": "user", - "content": "Say this is a test", - }], - model="gpt-4o", -) -print(response.headers.get('X-My-Header')) - -completion = response.parse() # get the object that `chat.completions.create()` would have returned -print(completion) -``` - -These methods return a [`LegacyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version. - -For the sync client this will mostly be the same with the exception -of `content` & `text` will be methods instead of properties. In the -async client, all methods will be async. - -A migration script will be provided & the migration in general should -be smooth. - -#### `.with_streaming_response` - -The above interface eagerly reads the full response body when you make the request, which may not always be what you want. - -To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. - -As such, `.with_streaming_response` methods return a different [`APIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_response.py) object, and the async client returns an [`AsyncAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_response.py) object. - -```python -with client.chat.completions.with_streaming_response.create( - messages=[ - { - "role": "user", - "content": "Say this is a test", - } - ], - model="gpt-4o", -) as response: - print(response.headers.get("X-My-Header")) - - for line in response.iter_lines(): - print(line) -``` - -The context manager is required so that the response will reliably be closed. - -### Making custom/undocumented requests - -This library is typed for convenient access to the documented API. - -If you need to access undocumented endpoints, params, or response properties, the library can still be used. - -#### Undocumented endpoints - -To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client will be respected (such as retries) when making this request. - -```py -import httpx - -response = client.post( - "/foo", - cast_to=httpx.Response, - body={"my_param": True}, -) - -print(response.headers.get("x-foo")) -``` - -#### Undocumented request params - -If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request -options. - -#### Undocumented response properties - -To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You -can also get all the extra fields on the Pydantic model as a dict with -[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). - -### Configuring the HTTP client - -You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: - -- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) -- Custom [transports](https://www.python-httpx.org/advanced/transports/) -- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality - -```python -import httpx -from openai import OpenAI, DefaultHttpxClient - -client = OpenAI( - # Or use the `OPENAI_BASE_URL` env var - base_url="http://my.test.server.example.com:8083/v1", - http_client=DefaultHttpxClient( - proxy="http://my.test.proxy.example.com", - transport=httpx.HTTPTransport(local_address="0.0.0.0"), - ), -) -``` - -You can also customize the client on a per-request basis by using `with_options()`: - -```python -client.with_options(http_client=DefaultHttpxClient(...)) -``` - -### Managing HTTP resources - -By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. - -```py -from openai import OpenAI - -with OpenAI() as client: - # make requests here - ... - -# HTTP client is now closed -``` - -## Microsoft Azure OpenAI - -To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI` -class instead of the `OpenAI` class. - -> [!IMPORTANT] -> The Azure API shape differs from the core API shape which means that the static types for responses / params -> won't always be correct. - -```py -from openai import AzureOpenAI - -# gets the API Key from environment variable AZURE_OPENAI_API_KEY -client = AzureOpenAI( - # https://learn.microsoft.com/azure/ai-services/openai/reference#rest-api-versioning - api_version="2023-07-01-preview", - # https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource - azure_endpoint="https://example-endpoint.openai.azure.com", -) - -completion = client.chat.completions.create( - model="deployment-name", # e.g. gpt-35-instant - messages=[ - { - "role": "user", - "content": "How do I output all files in a directory using Python?", - }, - ], -) -print(completion.to_json()) -``` - -In addition to the options provided in the base `OpenAI` client, the following options are provided: - -- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable) -- `azure_deployment` -- `api_version` (or the `OPENAI_API_VERSION` environment variable) -- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable) -- `azure_ad_token_provider` - -An example of using the client with Microsoft Entra ID (formerly known as Azure Active Directory) can be found [here](https://github.com/openai/openai-python/blob/main/examples/azure_ad.py). - -## Versioning - -This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: - -1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ -3. Changes that we do not expect to impact the vast majority of users in practice. - -We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. - -We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions. - -### Determining the installed version - -If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. - -You can determine the version that is being used at runtime with: - -```py -import openai -print(openai.__version__) -``` - -## Requirements - -Python 3.9 or higher. - -## Contributing - -See [the contributing documentation](https://github.com/openai/openai-python/tree/main/./CONTRIBUTING.md). diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/RECORD deleted file mode 100644 index f9b7afd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/RECORD +++ /dev/null @@ -1,2010 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_base_client.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_client.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_constants.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_exceptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_extras/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_extras/_common.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_extras/numpy_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_extras/pandas_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_extras/sounddevice_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_legacy_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_module_client.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_qs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_resource.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_streaming.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_compat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_datetime_parse.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_logs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_reflection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_resources_proxy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_streams.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_sync.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_transform.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_typing.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_utils/_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/_version.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/_main.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/audio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/jobs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/image.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_cli.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_errors.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_progress.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/_main.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/fine_tunes.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/migrate.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/cli/_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/helpers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/helpers/local_audio_player.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/helpers/microphone.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_old_api.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_responses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_pydantic.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_realtime.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_tools.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/_validators.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/azure.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_assistants.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_deltas.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_events.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_events.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_responses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/pagination.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/audio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/speech.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/transcriptions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/translations.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/batches.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/assistants.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/beta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/chatkit.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/sessions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/threads.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/realtime.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/sessions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/transcription_sessions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/messages.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/runs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/steps.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/threads.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/chat.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/messages.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/completions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/containers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/conversations.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/items.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/embeddings.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/evals.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/output_items.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/runs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/alpha.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/graders.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/checkpoints.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/permissions.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/fine_tuning.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/checkpoints.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/jobs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/images.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/moderations.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/calls.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/client_secrets.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/realtime.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_items.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_tokens.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/responses.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/parts.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/uploads.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/file_batches.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/vector_stores.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/videos.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/resources/webhooks.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized_segment.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_include.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_segment.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_stream_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_segment_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_verbose.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_word.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_verbose.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/audio_response_format.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/auto_file_chunking_strategy_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch_request_counts.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/batch_usage.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_stream_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_automatic_thread_titling.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_expires_after_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_file_upload.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_history.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_status.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_workflow_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_attachment.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_response_output_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_item_list.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_user_message_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_widget_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/session_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_delete_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_items_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit_workflow.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_deleted_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/error_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_cleared_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_committed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_started_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/rate_limits_updated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_connect_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_status.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_usage.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_server_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_updated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_updated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_and_run_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_annotation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_delta_annotation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_annotation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_delta_annotation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_part_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_content_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_delta_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/required_action_function_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_status.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_submit_tool_outputs_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_logs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_output_image.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/message_creation_step_details.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_message_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_include.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_retrieve_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_calls_step_details.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta_block.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tool_choice_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tools_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_assistant_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_chunk.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_input_audio_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_refusal_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_custom_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_developer_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_call_option_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_union_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_modality.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_custom_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_prediction_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_reasoning_effort.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_role.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_store_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_stream_options_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_system_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_token_logprob.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_choice_option_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_union_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_user_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/message_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_chat_completion.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_function_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/chat_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/completion.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/completion_choice.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/completion_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/completion_usage.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/container_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/containers/files/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/computer_screenshot_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_deleted_resource.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item_list.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_retrieve_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/summary_text_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/text_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/create_embedding_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/embedding.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_custom_data_source_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_delete_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_stored_completions_data_source_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/eval_api_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_cancel_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_delete_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/file_purpose.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_delete_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_integration.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_events_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/checkpoint_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_create_variation_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_partial_image_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_stream_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_partial_image_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_stream_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_generate_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/image_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/images_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/model_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_image_url_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_multi_modal_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_text_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/other_file_chunking_strategy_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_accept_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_refer_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_reject_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_added.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_deleted_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_done.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_segment.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_cleared_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_committed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_started_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_stopped_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_timeout_triggered.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/log_prob_properties.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_completed.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_failed.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_in_progress.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/noise_reduction_type.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/rate_limits_updated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_connect_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_status.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_input_token_details.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_output_token_details.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_server_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_client_secret.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_turn_detection.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_delta.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_done.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_completed.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_failed.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_in_progress.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_updated_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/compacted_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_item_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/parsed_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_interpreting_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compact_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_conversation_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_created_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_failed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_searching_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call_output.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_output_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_generating_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_partial_image_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_includable.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_incomplete_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item_list.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_failed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_failed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_annotation_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_queued_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_added_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_retrieve_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_status.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_stream_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_delta_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_done_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_usage.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_completed_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_in_progress_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_searching_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_options.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/all_models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/chat_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/comparison_filter.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/compound_filter.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/custom_tool_input_format.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/error_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_definition.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_parameters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/metadata.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning_effort.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_schema.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_grammar.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_python.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared/responses_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/chat_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/comparison_filter.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/compound_filter.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/custom_tool_input_format.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_definition.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_parameters.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/metadata.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning_effort.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_schema.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_text.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/responses_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/upload.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/upload_complete_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/upload_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/part_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/upload_part.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_list_files_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_content_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_update_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_batch.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_deleted.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_error.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_delete_response.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_download_content_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_list_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_model.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_model_param.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_remix_params.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_seconds.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/video_size.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_cancelled_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_completed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_expired_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_failed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_canceled_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_failed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_succeeded_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_failed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/realtime_call_incoming_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_cancelled_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_completed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_failed_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_incomplete_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/unwrap_webhook_event.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/types/websocket_connection_options.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/openai/version.cpython-39.pyc,, -../../../bin/openai,sha256=HOVlhgtQVtliUp5td6AztaqvVh7RTfdiFHCm47LNd6k,263 -openai-2.15.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -openai-2.15.0.dist-info/METADATA,sha256=_n7k1ybc9yaSpwS3IgtfMgTOQcmqnI9Kfv1CLKxcuuU,29166 -openai-2.15.0.dist-info/RECORD,, -openai-2.15.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -openai-2.15.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87 -openai-2.15.0.dist-info/entry_points.txt,sha256=kAYhQEmziJwsKs5raYAIOvJ2LWmbz5dulEXOzsY71ro,43 -openai-2.15.0.dist-info/licenses/LICENSE,sha256=Y263152pu21RWks_1BeqJmees88WOW3atLxV-nTmFuQ,11336 -openai/__init__.py,sha256=Fvc0dwOoaIZDN_s3iV62jlxeU5d7qn-Q8eQIaPIdD8g,11196 -openai/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 -openai/_base_client.py,sha256=OW9qrEk10REsVox0zmqmeKpUNxNkfrnB6BX-IgDBe0U,68437 -openai/_client.py,sha256=uZlue35miO_zv84wqaCRvqchb6WH3UaKPbZGIvIs0Gw,44645 -openai/_compat.py,sha256=k2XpUhYfgp5ZXkZkQAftJHt_UWFjUct1Sm2ye2kPBXo,6964 -openai/_constants.py,sha256=WmCwgT4tGmFsSrltb26f3bM8ftUyFYkzh32Ny5yl-So,467 -openai/_exceptions.py,sha256=TYcCxnfT7fln5duvVnCVJ0znuUHXSAbCT5sAMnaeKjU,5008 -openai/_extras/__init__.py,sha256=sainrYWujCxIyL24wNpKfMVr-ZyBPlnSZfqXcg2S6Xg,165 -openai/_extras/_common.py,sha256=NWWtgbdJsO3hQGQxaXGfVk0LjeIE5AFZ8VS_795hhMc,364 -openai/_extras/numpy_proxy.py,sha256=LyTZkKDdnjz0h1SKLsphrhmXyUsJ_xEUhTFMrCf7k7g,805 -openai/_extras/pandas_proxy.py,sha256=NCEt1Dqwc_0H85YdsWPDE3lPDJtYnBT8G-gJE_BCeEc,637 -openai/_extras/sounddevice_proxy.py,sha256=xDoE21YGu13dSAJJkiOM9Qdb7uOIv5zskaJRX6xciEg,725 -openai/_files.py,sha256=cQOoF0UFpnyH5JMIdu_EvGpj_dGzH1ojtJvyX7Xwqn0,3612 -openai/_legacy_response.py,sha256=fx9I0IInZY1zr2bUmpqW2ZUcL9JW2xS6S4NqFuwhdPM,16237 -openai/_models.py,sha256=8lIzsvSKDk4wGqwt69jpFblwC97f1Sgog87gBFBpYZk,33577 -openai/_module_client.py,sha256=33fORSMWHuxqpvlROvYVMEIvaWUishUpSeaqpsOjWuI,5033 -openai/_qs.py,sha256=craIKyvPktJ94cvf9zn8j8ekG9dWJzhWv0ob34lIOv4,4828 -openai/_resource.py,sha256=IQihFzFLhGOiGSlT2dO1ESWSTg2XypgbtAldtGdTOqU,1100 -openai/_response.py,sha256=zLVaMPYE1o2Tz1eS5_bnJNGMikRN1byMpMcVpW1tgIU,29510 -openai/_streaming.py,sha256=dPO6F5Klse8Nax72QfB_R3VGLoPzJwsw1Yrj0sgEo2Y,13769 -openai/_types.py,sha256=AnW8T0dYOmUDVn4ZqXw0DOwy5tExvUZa4YFpabUPvpE,7423 -openai/_utils/__init__.py,sha256=qiOG_n0G-sP5r5jNvD4OUaeaVLFEw5s-h7h7b0nD7Nk,2465 -openai/_utils/_compat.py,sha256=D8gtAvjJQrDWt9upS0XaG9Rr5l1QhiAx_I_1utT_tt0,1195 -openai/_utils/_datetime_parse.py,sha256=bABTs0Bc6rabdFvnIwXjEhWL15TcRgWZ_6XGTqN8xUk,4204 -openai/_utils/_logs.py,sha256=IC5iwPflwelNpJEpWsvK3up-pol5hR8k_VL9fSukk_Y,1351 -openai/_utils/_proxy.py,sha256=aglnj2yBTDyGX9Akk2crZHrl10oqRmceUy2Zp008XEs,1975 -openai/_utils/_reflection.py,sha256=aTXm-W0Kww4PJo5LPkUnQ92N-2UvrK1-D67cJVBlIgw,1426 -openai/_utils/_resources_proxy.py,sha256=AHHZCOgv-2CRqB4B52dB7ySlE5q6QCWj0bsTqNmzikw,589 -openai/_utils/_streams.py,sha256=SMC90diFFecpEg_zgDRVbdR3hSEIgVVij4taD-noMLM,289 -openai/_utils/_sync.py,sha256=HBnZkkBnzxtwOZe0212C4EyoRvxhTVtTrLFDz2_xVCg,1589 -openai/_utils/_transform.py,sha256=hzILp2ijV9J7D-uoEDmadtyCmzMK6DprJP8IlwEg0ZY,15999 -openai/_utils/_typing.py,sha256=N_5PPuFNsaygbtA_npZd98SVN1LQQvFTKL6bkWPBZGU,4786 -openai/_utils/_utils.py,sha256=Z2y9rNbK-worRedH9Ub9tO_FSIjl0SH2AV9Tdgz9LUA,12667 -openai/_version.py,sha256=94MRTH0M96CpuYgTYEBbXq6gdXEsEPy6ePoF06t16fI,159 -openai/cli/__init__.py,sha256=soGgtqyomgddl92H0KJRqHqGuaXIaghq86qkzLuVp7U,31 -openai/cli/_api/__init__.py,sha256=cj92MZq-9_1PQM8A4TQVsqKn5mcTDAGxHllJ0UvJOPE,58 -openai/cli/_api/_main.py,sha256=3xVyycq-4HEYMBdMDJFk893PTXpr8yvkGL3eCiuSx8E,501 -openai/cli/_api/audio.py,sha256=0GU49a-XurLlyVEy2V9IZ_pDmjL1XEBI7Jp7fQfJ5Sk,3757 -openai/cli/_api/chat/__init__.py,sha256=MhFUQH9F6QCtbPMlbsU_DWTd7wc5DSCZ7Wy3FBGVij0,300 -openai/cli/_api/chat/completions.py,sha256=GyfAo3B2w2ySV0dK9D2IIVA4fOb0zqJZadQ-Yc8a_yU,5536 -openai/cli/_api/completions.py,sha256=Jy1rlQqw__12ZfbTrnZJgoGBbDKJ58kOUAT-vkLr5kE,6334 -openai/cli/_api/files.py,sha256=6nKXFnsC2QE0bGnVUAG7BTLSu6K1_MhPE0ZJACmzgRY,2345 -openai/cli/_api/fine_tuning/__init__.py,sha256=hZeWhTZtIRAl1xgSbznjpCYy9lnUUXngh8uEIbVn__Y,286 -openai/cli/_api/fine_tuning/jobs.py,sha256=4wj9DPfw3343fJQW9j52Q-ga4jYa1haOTn4yYsH_zqk,5311 -openai/cli/_api/image.py,sha256=3UDZ1R8SjYh4IOhhdJqf20FPqPgPdhpRxqu3eo5BKhU,5014 -openai/cli/_api/models.py,sha256=pGmIGZToj3raGGpKvPSq_EVUR-dqg4Vi0PNfZH98D2E,1295 -openai/cli/_cli.py,sha256=42j_eI8PPdFbVjufluregmNYTdwrw3yQtsHtTzyNvcQ,6779 -openai/cli/_errors.py,sha256=nejlu1HnOyAIr2n7uqpFtWn8XclWj_9N8FwgfT3BPK8,471 -openai/cli/_models.py,sha256=_budygMbXh3Fv-w-TDfWecZNiKfox6f0lliCUytxE1Q,491 -openai/cli/_progress.py,sha256=aMLssU9jh-LoqRYH3608jNos7r6vZKnHTRlHxFznzv4,1406 -openai/cli/_tools/__init__.py,sha256=cj92MZq-9_1PQM8A4TQVsqKn5mcTDAGxHllJ0UvJOPE,58 -openai/cli/_tools/_main.py,sha256=pakjEXHRHqYlTml-RxV7fNrRtRXzmZBinoPi1AJipFY,467 -openai/cli/_tools/fine_tunes.py,sha256=RQgYMzifk6S7Y1I1K6huqco2QxmXa7gVUlHl6SrKTSU,1543 -openai/cli/_tools/migrate.py,sha256=o-iomzhtC6N6X5H5GDlgQ_QOaIovE2YA9oHc_tIAUj8,4497 -openai/cli/_utils.py,sha256=oiTc9MnxQh_zxAZ1OIHPkoDpCll0NF9ZgkdFHz4T-Bs,848 -openai/helpers/__init__.py,sha256=F0x_Pguq1XC2KXZYbfxUG-G_FxJ3mlsi7HaFZ1x-g9A,130 -openai/helpers/local_audio_player.py,sha256=7MWwt1BYEh579z1brnQ2mUEB0Ble4UoGMHDKusOfZJQ,5852 -openai/helpers/microphone.py,sha256=6tIHWZGpRA5XvUoer-nPBvHbrmxK7CWx3_Ta-qp1H54,3341 -openai/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224 -openai/lib/__init__.py,sha256=BMTfMnlbugMgDA1STDIAlx4bI4t4l_8bQmJxd0th0n8,126 -openai/lib/_old_api.py,sha256=XZnXBrEKuTd70iJirj5mGW35fZoqruJobbBTq6bvg10,1947 -openai/lib/_parsing/__init__.py,sha256=wS3BYvMGj9TqiPqOe3rO1sleaAJqHVuCaQuCE5rZIUw,539 -openai/lib/_parsing/_completions.py,sha256=3vihFrFWJIrToaWYjJMqn42gTyNmrQhXvi2vr5Wduo8,10629 -openai/lib/_parsing/_responses.py,sha256=g47-6Vbw4cAjkUrHRAG_PAeJzJlwSxngiezog5UUYwI,6246 -openai/lib/_pydantic.py,sha256=Cf0vGwuWdNEuIUg8WNREjWRGApMObgl8DjdLU4f5jAc,5623 -openai/lib/_realtime.py,sha256=DyFqSff1XlgJdD1I5tJXdleQP2WiDT8ISeYbpHHih6c,3974 -openai/lib/_tools.py,sha256=Dc4U2TXKvfAvVUvDS30SDeftrwgGM2vZ85t5ojLHiEg,1969 -openai/lib/_validators.py,sha256=cXJXFuaAl7jeJcYHXXnFa4NHGtHs-_zt3Zs1VVCmQo4,35288 -openai/lib/azure.py,sha256=dLzUXTXUOnfarLdDyO6dVzp8wY2vTMFFHUJZLuFznWY,26537 -openai/lib/streaming/__init__.py,sha256=kD3LpjsqU7caDQDhB-YjTUl9qqbb5sPnGGSI2yQYC70,379 -openai/lib/streaming/_assistants.py,sha256=LUWSinmYopQIkQ5xSg73b6BWbkRkQS5JvX62w_V9xSw,40692 -openai/lib/streaming/_deltas.py,sha256=I7B_AznXZwlBmE8Puau7ayTQUx6hMIEVE8FYTQm2fjs,2502 -openai/lib/streaming/chat/__init__.py,sha256=7krL_atOvvpQkY_byWSglSfDsMs5hdoxHmz4Ulq7lcc,1305 -openai/lib/streaming/chat/_completions.py,sha256=4PDLu_1-wQOrAwHY-Gz8NIQ8UnJ9gshwrmxuMDesFp8,30775 -openai/lib/streaming/chat/_events.py,sha256=lstVmM6YR2Cs9drikzrY9JCZn9Nbfym0aKIPtNpxL6w,2618 -openai/lib/streaming/chat/_types.py,sha256=-SYVBNhGkOUoJ-8dotxpCRqPJpfyOQ8hwR2_HrsQCRI,739 -openai/lib/streaming/responses/__init__.py,sha256=MwE1Oc3OIiXjtuRFsuP_k5Ra8pNiqKpc1GZum-8ZRJM,543 -openai/lib/streaming/responses/_events.py,sha256=3UWmeYgg23E3XTkYVlrpXJPnhBM2kmQFoXh3WiT9CrE,5576 -openai/lib/streaming/responses/_responses.py,sha256=Myeo4so-aMFrzEyNCjX0ypYWTWvY5uDelhe2ygC93lY,13614 -openai/lib/streaming/responses/_types.py,sha256=msq1KWj3e3BLn7NKu5j2kzHgj9kShuoitgXEyTmQxus,276 -openai/pagination.py,sha256=dtPji3wApb_0rkvYDwh50rl8cjxT3i6EUS6PfTXwhQI,4770 -openai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -openai/resources/__init__.py,sha256=YDrG7nC0vTf4xk-JCSs0132OA5XWmqAMtjWu4wypnB4,6067 -openai/resources/audio/__init__.py,sha256=YM7FHvPKVlj_v6EIgfpUQsb6q4hS2hVQ3gfkgic0sP0,1687 -openai/resources/audio/audio.py,sha256=nEIB4q7a1MSYdQkcYH2O6jB-_rNCMDCBJyUuqOL67CI,5491 -openai/resources/audio/speech.py,sha256=OT6cTwSeQWx_9zBu4eeCGnJ2KoBcK82WoNXM2d7dsXQ,10316 -openai/resources/audio/transcriptions.py,sha256=SHB5wio25FMIxL12_ErjuGCtuQ3fRpkT2Zo0aDFthAY,52213 -openai/resources/audio/translations.py,sha256=IsPiYZtr9BLS7pgAWAneU7yNq1E9igDCa-QXN12PhZM,15505 -openai/resources/batches.py,sha256=kdQbfxnHMZ7sB8Z5ZQriwxYE2u9_6_Z4LM4wxulYwjA,21002 -openai/resources/beta/__init__.py,sha256=chKjkpkqNxO1Dbl9OsCJNXVC1AbDcvTrvfvvAIh5B5I,1570 -openai/resources/beta/assistants.py,sha256=TWnvp9cylF4Vl3rlb6940e8NCK9fvukr0KpfP8gdkaU,47949 -openai/resources/beta/beta.py,sha256=Lrsu8f9haXb4bZphmw9wgHzn8uZUBUUC11mZa3XRbr0,5725 -openai/resources/beta/chatkit/__init__.py,sha256=lJAQpi-JogtnSAlOegSae6WfCfgRLMd8rpPBuT9_2FE,1216 -openai/resources/beta/chatkit/chatkit.py,sha256=CleguF_80H_gAsyX_tLoGxFTD7YItZPshRAZ2QAqfzY,4333 -openai/resources/beta/chatkit/sessions.py,sha256=H8oIyd8V553LruOilYuTnXwU8Mh_z5xOjuu7GunaGIc,11837 -openai/resources/beta/chatkit/threads.py,sha256=kqngETyzx9uRBKtgfq9r9WrtOXpNfnHej4PkrVfnklo,20077 -openai/resources/beta/realtime/__init__.py,sha256=dOXRjPiDqRJXIFoGKSVjzKh3IwSXnLbwHx4ND5OdnVs,1412 -openai/resources/beta/realtime/realtime.py,sha256=tuiq_0PdFmC2p-LNOfQNrVuDEMlLAHKEgeAsPsHLUHU,43694 -openai/resources/beta/realtime/sessions.py,sha256=EQva_qI71CgS35qkK9TGxuibviHwUQ6VzErIzunP4gU,22098 -openai/resources/beta/realtime/transcription_sessions.py,sha256=uTDGEat50lojdD0N8slnZu2RVzMP96rlicpDp4tpl34,14124 -openai/resources/beta/threads/__init__.py,sha256=fQ_qdUVSfouVS5h47DlTb5mamChT4K-v-siPuuAB6do,1177 -openai/resources/beta/threads/messages.py,sha256=a8HEG-QKIgG8r4XtE0M7ixRBikAmdQEUDWUDf1gkaSg,30794 -openai/resources/beta/threads/runs/__init__.py,sha256=2FfDaqwmJJCd-IVpY_CrzWcFvw0KFyQ3cm5jnTfI-DQ,771 -openai/resources/beta/threads/runs/runs.py,sha256=JQ5LaI33KcXLumleh-TxyTTJWYkbeQhTh8FxhHNmYzg,155523 -openai/resources/beta/threads/runs/steps.py,sha256=YkoPMeMXEzoL09AWF7Eh1lNaJocykV1igmcsZpXKw5Y,16981 -openai/resources/beta/threads/threads.py,sha256=3C3OzlgL0S1mDdnRBowU14Di8W7T81C2BEGFm5Mx42Y,97651 -openai/resources/chat/__init__.py,sha256=8Q9ODRo1wIpFa34VaNwuaWFmxqFxagDtUhIAkQNvxEU,849 -openai/resources/chat/chat.py,sha256=HjcasSCmt-g3-J-RkZQ9HRj_-hPfImakFxdUvvk5mCg,3364 -openai/resources/chat/completions/__init__.py,sha256=KOi8blzNyHWD7nKgcoW3CxZ4428IcNVP0gCU74HySf8,901 -openai/resources/chat/completions/completions.py,sha256=r5M4ICb-GHJUsbrokxXvQizh_iBsygiRX-kho_X78JQ,164608 -openai/resources/chat/completions/messages.py,sha256=AYVwQ24jPQGs2Y-vE6Yjl5nbCECtuw-HpcBEEpCgC-0,8010 -openai/resources/completions.py,sha256=wO39_sLxmSzTI6Mp13KzjqaxMgFZw4l-t0_9xxDbX_4,59201 -openai/resources/containers/__init__.py,sha256=7VzY-TFwG3x5D_kUCs_iAQaaCKAswt1Jk70KpmnU8Do,849 -openai/resources/containers/containers.py,sha256=IjkEbXITLjCMt0rpZpvocfBro_M0ZEB4rF5fYEfLWs8,19650 -openai/resources/containers/files/__init__.py,sha256=nDhg0wY7eHRMO-xOErno0mV0Ya_ynlmKAp-4a3nj-us,810 -openai/resources/containers/files/content.py,sha256=-jupriq97X2kq_yCdYihZ1h2qCx-IMbaaR10M4lz6TA,6491 -openai/resources/containers/files/files.py,sha256=jjiRGS489CzoOXb3nvsD-i3qTSINE9CrAo2jZPWxyLI,21042 -openai/resources/conversations/__init__.py,sha256=Uslb4pakT8pQJGQ29CvoiN-SvN2AgMum-TeIDyYTzQE,888 -openai/resources/conversations/conversations.py,sha256=IjnSvilsJG_yK4IoRP86R6_5MFlHSpZt6lWxgpbGP-Y,19151 -openai/resources/conversations/items.py,sha256=q3XbPsh09Gb9qYisb6BEa9BExX4HF5oMu-Z0khdAFlY,23969 -openai/resources/embeddings.py,sha256=GYA_sI2h5auPwyHKm44-brPxRxqvcQaH0JQMZW13bMA,12374 -openai/resources/evals/__init__.py,sha256=DXhYb6mCKKY2bDdS3s4raH1SvwPUyaBFvdHgPEbwRWY,771 -openai/resources/evals/evals.py,sha256=goQ9ek2_xI34SG7GkwpqKhXO2hZouq5bxS26EejY-cI,25904 -openai/resources/evals/runs/__init__.py,sha256=7EtKZ43tGlmAOYyDdyFXy80tk2X8AmXb5taTWRRXBXE,850 -openai/resources/evals/runs/output_items.py,sha256=7pcGpGc61Df4jQIgxRYLX-27wz_8qc0Ux-ni_EfVvwA,12530 -openai/resources/evals/runs/runs.py,sha256=228Vf9S8_dz0tZAWCh2ehECQYg_Z4JXNV5MRuvUtDh4,24359 -openai/resources/files.py,sha256=R8gZj_H63NYWjQ3cxkJyidCyyVzSQHbb33wWzlWLJRM,30436 -openai/resources/fine_tuning/__init__.py,sha256=RQPC5QfqE-ByhRQbJK-j7ooUrkBO9s9bKt5xkzOL8ls,1597 -openai/resources/fine_tuning/alpha/__init__.py,sha256=QKAYZscx1Fw3GLD8cVdZAYG9L_i6MnPGeifn8GgcztU,810 -openai/resources/fine_tuning/alpha/alpha.py,sha256=P-zLOHpI-Aa0jUUWspkanL7WpUtfjwIGDH8KTGDNeHY,3274 -openai/resources/fine_tuning/alpha/graders.py,sha256=TA39PsdXWjxsts6p_UjPhyTwE4a1O7nQOkUC0V2ZHbU,10758 -openai/resources/fine_tuning/checkpoints/__init__.py,sha256=rvsbut5FCQNAr-VjvL-14GFT3Tld49FlFuBJDpfxBug,940 -openai/resources/fine_tuning/checkpoints/checkpoints.py,sha256=njpz496JifeZ8RXjoYUb1Tj9tBItuXRxGJHW2jrrfwo,3606 -openai/resources/fine_tuning/checkpoints/permissions.py,sha256=A9SfSQk7o0gbqhu2NMZTW53Tq5c3zbBDSgL_0K0t1WQ,17103 -openai/resources/fine_tuning/fine_tuning.py,sha256=UL4MXoUqEnbSZ5e4dnbUPTtd4tE-1p2L7Hh_0CQ_0s0,5410 -openai/resources/fine_tuning/jobs/__init__.py,sha256=_smlrwijZOCcsDWqKnofLxQM2QLucZzXgboL9zJBPHw,849 -openai/resources/fine_tuning/jobs/checkpoints.py,sha256=-QQNOZJplnCJyHCFTFO-DMN-AWc1Dp8p9Hifffgz5a0,7442 -openai/resources/fine_tuning/jobs/jobs.py,sha256=jIXuCijf7v9ufH3SqgWBrQAFg5uqPKAuyXgNDmLEXK4,37033 -openai/resources/images.py,sha256=CbfPekwgHdib4TZH7Wj3nKd_JaUggcX4ot9wjVjrLKI,97665 -openai/resources/models.py,sha256=1PDMpmdtaGiNHZNWPL-sI_I-SDOjuK-yfm2oq7mKiGI,11232 -openai/resources/moderations.py,sha256=8BWoTw8QHsSUbgByBlLxHHYEeeozFsY8n3j-ah13YdI,7808 -openai/resources/realtime/__init__.py,sha256=5v7pt2NQKz1j-X1z4bTqupmE3G8O5_G4PYCyw3F3-eo,1269 -openai/resources/realtime/calls.py,sha256=DIwWlEkd_6IYYnXptYeiuBpEJpP1cDrGoSwXc-G-s9A,33417 -openai/resources/realtime/client_secrets.py,sha256=Z8NmSg2GGN3we3w89Un26jWp5OO9lxOi8oS4lSYMrUg,7700 -openai/resources/realtime/realtime.py,sha256=ISKvDwqzbHeBM8OHlOW3L7oO1NwyrUM5joj_g9EH2aY,44876 -openai/resources/responses/__init__.py,sha256=9LkjQomOIh6B5Qg1HbdCgjMRoCzIBzyRaYNyt3moA38,1322 -openai/resources/responses/input_items.py,sha256=tzg31yUowcCMqU32TBHI18YzRjqNs_EGwKdpSU8bSTs,8774 -openai/resources/responses/input_tokens.py,sha256=cQvZuYjdhAf6fcmXsDavpuhA-LBjmpQkm2KgaOD5iSk,14208 -openai/resources/responses/responses.py,sha256=2O-bCqpqw952DXPcngyh11C8f-B9BmpVAQpxe45YXGQ,173163 -openai/resources/uploads/__init__.py,sha256=HmY3WQgvUI2bN3CjfWHWQOk7UUC6Ozna97_lHhrrRSA,810 -openai/resources/uploads/parts.py,sha256=2Vov0reg5wdOSGSJ7hhs9pqsIofkhqjoUoE_AgXHLZM,8121 -openai/resources/uploads/uploads.py,sha256=OeCCAEK1W1ICTfraOBbYRrBclnzroEOaAOpuT05Fyvg,25443 -openai/resources/vector_stores/__init__.py,sha256=11Xn1vhgndWiI0defJHv31vmbtbDgh2GwZT3gX8GgHk,1296 -openai/resources/vector_stores/file_batches.py,sha256=eSrMBeNf-bKsHu40HHyKkejo8BNoFAE32LnG119FxIs,34196 -openai/resources/vector_stores/files.py,sha256=xJStwcbKIzVzqIXK7G-Mfll61wbt154SObua945XXEI,39703 -openai/resources/vector_stores/vector_stores.py,sha256=L1vifq5tiw7EnBuxYREA_VPMzyRcePiQG4QLQL5vd18,35451 -openai/resources/videos.py,sha256=FGyEsn-h57V6guzhUEZuls5JWx0RzFXXRn74-Nvlx88,32017 -openai/resources/webhooks.py,sha256=wz3filqxxUEhhW5RSa-1LiN10MzafKXJPl5-Wb1mCew,7820 -openai/types/__init__.py,sha256=S82oA2tM4b7YnQ7R8xFqxViIUOy5bFzoRUAFA2efN2I,7630 -openai/types/audio/__init__.py,sha256=8DwArrrSRwIemWLhWLItaV3F_EgXgtVPSu4yUIf8iyM,1723 -openai/types/audio/speech_create_params.py,sha256=HReviZr1BsD038PCmbw_NlhJqb-5V7IN4ezr1iPfqnw,1838 -openai/types/audio/speech_model.py,sha256=swuN1lLQxGSuYj_X_OeQuUx5abIUpEfZZqNjDES7kU0,267 -openai/types/audio/transcription.py,sha256=7q7nfUTe-GDMpicrWOugFU4bSBIyqhQkndnKCTD1X2M,2407 -openai/types/audio/transcription_create_params.py,sha256=Mxl-LoHCiEkO41fGUcsSmN35fOtNWXYDgMa-nP90DNg,6977 -openai/types/audio/transcription_create_response.py,sha256=-x20GMKDHrHzl_37fsGjpPlJC91ZNGwrD_5-AkZgnOw,459 -openai/types/audio/transcription_diarized.py,sha256=fYKkV0B5Rjcx9GC-6TfJP4TjSWUbbIdvle1Sb3DQp2I,2374 -openai/types/audio/transcription_diarized_segment.py,sha256=s63ItoQlqLqxi17vUniZagifOw8Y-nVR17-SwQUWW8Y,931 -openai/types/audio/transcription_include.py,sha256=mclUP_50njW7TG4d9m_E6zSjAFW8djPJ6ZTYub71kq0,227 -openai/types/audio/transcription_segment.py,sha256=-pPAGolwIIXUBMic-H5U7aR0u_Aq-pipSA4xTtn_viA,1153 -openai/types/audio/transcription_stream_event.py,sha256=MJNeIqgrVJekLGA3KSzE7lHK3dyhrvvhGLIwgQsZDPE,648 -openai/types/audio/transcription_text_delta_event.py,sha256=JH09I9eYFZLZKAJcSMc3-4owS9CtTpTmNajXgAlcQ7c,1551 -openai/types/audio/transcription_text_done_event.py,sha256=AtXZflObQVBwETQlVcUqN4h-SFiiod4oAH9f7UHZ39g,2341 -openai/types/audio/transcription_text_segment_event.py,sha256=amH-qLV2l1Y4d2bnZrWplsz41_LzYvmyOdHv1rlXEtE,990 -openai/types/audio/transcription_verbose.py,sha256=vI30MetsMh3yT2hTCUGdKxjHNZ0wkM2mJ-yhu2opGuM,1303 -openai/types/audio/transcription_word.py,sha256=s2aWssAgHjMOZHhiihs1m4gYWQpjBP2rkI1DE5eZBXc,367 -openai/types/audio/translation.py,sha256=Dlu9YMo0cc44NSCAtLfZnEugkM7VBA6zw2v9bfrLMh0,193 -openai/types/audio/translation_create_params.py,sha256=ejrom_64QOe47gZtrYmDAQkb65wLaZL4-iU-mKVTVq0,1572 -openai/types/audio/translation_create_response.py,sha256=x6H0yjTbZR3vd3d7LdABcn9nrMDNdeMjepcjW1oUfVc,362 -openai/types/audio/translation_verbose.py,sha256=lGB5FqkV-ne__aaGbMTFbEciJ-Sl3wBhlKmETmtROT8,615 -openai/types/audio_model.py,sha256=U5nv4NKBd3A5k3mDw0BmK0PiSc0VQADOkirXnKsC-eo,344 -openai/types/audio_response_format.py,sha256=67QSPDpT9_yYhxFYYd15N3nukwKrHJ7f8pvVQiVOQuk,276 -openai/types/auto_file_chunking_strategy_param.py,sha256=wvFMNI7RvIPLBoGZpdRMgVa-VlQkovurGi1aypefqwg,495 -openai/types/batch.py,sha256=o8ADxSZQe7F_1VTGSC5_RDUajU03SbWvN1wPiH98dVQ,3517 -openai/types/batch_create_params.py,sha256=XDHXPpI1PFDpTr3HXYecAgYPA8XAckyBY0xbMKnb3jo,2627 -openai/types/batch_error.py,sha256=Xxl-gYm0jerpYyI-mKSSVxRMQRubkoLUiOP9U3v72EM,622 -openai/types/batch_list_params.py,sha256=X1_sfRspuIMSDyXWVh0YnJ9vJLeOOH66TrvgEHueC84,705 -openai/types/batch_request_counts.py,sha256=iIPVKk4s5FcHlfLvLYetuXb_RxGPUvCGhRGYTryszV8,479 -openai/types/batch_usage.py,sha256=myAsCyOT7xWiZ_GDznGptUHeJVYx_Mg7c1cEtBMKmEc,1260 -openai/types/beta/__init__.py,sha256=kl4wEKnYF_urBLZV6wZ6ZCTwaLhlNYSOfFR64jO-Adc,2393 -openai/types/beta/assistant.py,sha256=K97cr0lg4fiZuLO6zNqIZVuUBjMFxtRtoszjyNI70DA,5394 -openai/types/beta/assistant_create_params.py,sha256=3q29vKotDs9f_oGs5HDmfBVBUYAW8dZqevw9GKaVH2g,8863 -openai/types/beta/assistant_deleted.py,sha256=bTTUl5FPHTBI5nRm7d0sGuR9VCSBDZ-IbOn9G_IpmJQ,301 -openai/types/beta/assistant_list_params.py,sha256=yW-lj6AUkG0IRZQKre0veEr9p4VMN-9YdELFMYs74Cw,1222 -openai/types/beta/assistant_response_format_option.py,sha256=yNeoAWxM-_8Sjmwqu8exqyKRFhVZIKeTypetPY55VFA,561 -openai/types/beta/assistant_response_format_option_param.py,sha256=dyPMhwRSLBZ0ltpxiD7KM-9X6BzWnbGeG-nT_3SenuQ,628 -openai/types/beta/assistant_stream_event.py,sha256=FDkbgQcmL64ExC2Q3mrPD73pYdGFcIMPt-wboshBWHg,10055 -openai/types/beta/assistant_tool.py,sha256=_0FC7Db4Ctq_0yLaKJ93zNTB5HthuJWEAHx3fadDRlw,506 -openai/types/beta/assistant_tool_choice.py,sha256=QXy2nQ2-_JLh3aU_BRZ3K17uZJUxrHC1cygqUMnr0U4,652 -openai/types/beta/assistant_tool_choice_function.py,sha256=p5YEbTnED_kZpPfj5fMQqWSgLXAUEajsDd0LXGdlENU,269 -openai/types/beta/assistant_tool_choice_function_param.py,sha256=-O38277LhSaqOVhTp0haHP0ZnVTLpEBvcLJa5MRo7wE,355 -openai/types/beta/assistant_tool_choice_option.py,sha256=jrXMd_IYIQ1pt8Lkc-KrPd4CR3lR8sFV4m7_lpG8A4Y,362 -openai/types/beta/assistant_tool_choice_option_param.py,sha256=VcatO5Nej9e5eqfrwetG4uM1vFoewnBEcFz47IxAK2E,424 -openai/types/beta/assistant_tool_choice_param.py,sha256=vB7bLafOjDZ4Ww3GMT_CXzcpFtVUtH6nYvHXpVjg_xA,680 -openai/types/beta/assistant_tool_param.py,sha256=6DcaU3nMjurur2VkVIYcCaRAY1QLQscXXjCd0ZHHGho,501 -openai/types/beta/assistant_update_params.py,sha256=sveL8Z489CV1SemVlQzGlNPjDy6JINfDLYoGgCFdrsg,7417 -openai/types/beta/chat/__init__.py,sha256=OKfJYcKb4NObdiRObqJV_dOyDQ8feXekDUge2o_4pXQ,122 -openai/types/beta/chatkit/__init__.py,sha256=K4Q3JL1OSz8tRSJyUoReRkBKsksw5QZdBy4HBvuBjZ4,2116 -openai/types/beta/chatkit/chat_session.py,sha256=NjVT5SQUWNroXynit10bwKsj8mntUSLouST46C9sBhM,1401 -openai/types/beta/chatkit/chat_session_automatic_thread_titling.py,sha256=R0PpWfBT5VMZp--Xxn082UjWbha7U5K9lJeSa4Cbhuk,360 -openai/types/beta/chatkit/chat_session_chatkit_configuration.py,sha256=-ailkIhSj6W2rHS3xPNc7XJ0duVG0fTmJaaVqqoE9RE,739 -openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py,sha256=4_3sCd7BIeNsy-kArfNgDO1jHjaUn703ib4_CHbsuZQ,2178 -openai/types/beta/chatkit/chat_session_expires_after_param.py,sha256=E9IcLvoz0FIIxE73sOF-WuqySbMpk5E9jvMj28_mDdo,597 -openai/types/beta/chatkit/chat_session_file_upload.py,sha256=ruKpNTM8zhXZfXgBZDYOGgRDT4Y3J4IjeMSnEwdlFTI,558 -openai/types/beta/chatkit/chat_session_history.py,sha256=XuxpwdFgpfCuw8Uc_TFB7H33683fSAfqhfIRdJoLQ6U,534 -openai/types/beta/chatkit/chat_session_rate_limits.py,sha256=irV4fZrQs6e6GbBT7rPsjsJBlheq3rz9tBsGq_fnb9k,353 -openai/types/beta/chatkit/chat_session_rate_limits_param.py,sha256=n8aeeakdT7L6liR6I5umF9BHABInNx7rL2WhmFWx0jQ,446 -openai/types/beta/chatkit/chat_session_status.py,sha256=l-SGwIDV4EFdX13Wjl2t-EipKFyYw7mckp9gxJhydqI,243 -openai/types/beta/chatkit/chat_session_workflow_param.py,sha256=bP2hQ-PXLLC1c8gjDjOh_fVLRPOFVSj7WV2-RrT9rfE,1202 -openai/types/beta/chatkit/chatkit_attachment.py,sha256=ZQPepId3dMRd-Jrzc0gCatbsXqYoj51-3S2XbPfAOmE,665 -openai/types/beta/chatkit/chatkit_response_output_text.py,sha256=e3rNmV2eTU0msEh67TaZRvE58wduZdaeN30wXpf39I0,1882 -openai/types/beta/chatkit/chatkit_thread.py,sha256=JAqb28gFwoGHgF6QPy0brlUc1jCzV1BFoiRikKrJ-IM,1918 -openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py,sha256=va96N80NNiHFRYEArjBNYlwFilbqZXvOtlHR0Dxec5o,941 -openai/types/beta/chatkit/chatkit_thread_item_list.py,sha256=2Qv0iPKkvIANfWQpIZh7iqZYBz51tgBAYtcSh3M8eaw,4302 -openai/types/beta/chatkit/chatkit_thread_user_message_item.py,sha256=pcpYEqmODoV-1MWgQsElSS8rcEbsp9OYRLKkr9SceqA,2505 -openai/types/beta/chatkit/chatkit_widget_item.py,sha256=d6l-XTELPMSLCizd2d6gnzBnYocDkaaFPei9WWhKggk,774 -openai/types/beta/chatkit/session_create_params.py,sha256=OUWYjVEXdYa8Y7mMKjR8CwZCAKI9QMZ1aqM8N1JDcQw,1274 -openai/types/beta/chatkit/thread_delete_response.py,sha256=laKdWnyeplfi0Tos0ps-izneu2ZGEnst7FJn87BS8pU,549 -openai/types/beta/chatkit/thread_list_items_params.py,sha256=9WerQ8VLMzWFSGJDnmg82bRNZy-YT7S6OjESDN9a9vU,697 -openai/types/beta/chatkit/thread_list_params.py,sha256=IHHdXtlMoV7a19YJg8dFLYzVgSzEUnSgMW2kQc_RE9Y,812 -openai/types/beta/chatkit_workflow.py,sha256=TCG5iL_5j9Lq_EsRx7HKrUYWhz9SFIJbHrYlYkXnSAg,961 -openai/types/beta/code_interpreter_tool.py,sha256=7mgQc9OtD_ZUnZeNhoobMFcmmvtZPFCNYGB-PEnNnfs,333 -openai/types/beta/code_interpreter_tool_param.py,sha256=X6mwzFyZx1RCKEYbBCPs4kh_tZkxFxydPMK4yFNJkLs,389 -openai/types/beta/file_search_tool.py,sha256=1r_kHrJYPD8HJ2lCg_npyXvG-BSydlOyo4dpnEI3w0o,2136 -openai/types/beta/file_search_tool_param.py,sha256=LZYlCZoHFOzqQnE7y55Oq5k20R9S0ZHJrtBpGnhYr_I,2132 -openai/types/beta/function_tool.py,sha256=oYGJfcfPpUohKw2ikgshDjOI1HXCK-5pAWyegYNezeU,397 -openai/types/beta/function_tool_param.py,sha256=hCclpGO4Re-TxiGy_QxX75g1kcN6_ElubicO6SdJ_YI,471 -openai/types/beta/realtime/__init__.py,sha256=trJb-lqh3vHHMYdohrgiU2cHwReFZyw4cXM-Xj8Dwq8,7364 -openai/types/beta/realtime/conversation_created_event.py,sha256=U4-nesN8rAep2_25E2DrkXUMafQejj3NE_0llXKj5Y8,752 -openai/types/beta/realtime/conversation_item.py,sha256=eIFg9zl3qzEijcQZvCnkvVLpSZgvEdubasgxGsQuFM4,2327 -openai/types/beta/realtime/conversation_item_content.py,sha256=KWZY8EUkjAi6K_IkWVjjrNZLG3KK2vGCy2_O30CEhzY,1050 -openai/types/beta/realtime/conversation_item_content_param.py,sha256=CrGi3XKwnfJdQGs-kJaGCsn53omdJF6_je0GWnVXhjQ,972 -openai/types/beta/realtime/conversation_item_create_event.py,sha256=jYXYdmqJh_znzcAgDuCxJXo5shf-t_DwmsyFkaDVnAE,1081 -openai/types/beta/realtime/conversation_item_create_event_param.py,sha256=vxTag6TrOLu1bf46F3mUmRkl5dd1Kb6bUp65gBDVmhM,1101 -openai/types/beta/realtime/conversation_item_created_event.py,sha256=cZBm_uKk5dkQXLlbF0Aetg4NJge3Ftz9kwRu2kCI3m4,817 -openai/types/beta/realtime/conversation_item_delete_event.py,sha256=p-O6R1Ku5pxZvaxhSi4YTPqLXS1SHhdLGgJuPQyPcHY,549 -openai/types/beta/realtime/conversation_item_delete_event_param.py,sha256=a17h8Hd8MxUbXT6NQg8YpTr1ICt1ztRecpfukHw4g34,569 -openai/types/beta/realtime/conversation_item_deleted_event.py,sha256=uWHSqX5ig550romSdhtROwrdQmdeN31Oz1Vpr9IuQFI,492 -openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py,sha256=FwZHHO4ZGMKoeQ80snCh_S-7anNUQtRLOhGjb8ScGOQ,2538 -openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py,sha256=5kjLmnRJug7L5fHxSSWWbhB70jGwNaMwbdENEwz9Xek,1143 -openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py,sha256=xYNSBIyERQJ4P-5YoFF1VptfPa8JnJ0sWaH6LGsPow0,1077 -openai/types/beta/realtime/conversation_item_param.py,sha256=HMB7MFR6WkztV1vMCFdIYNv8qOY4jzI2MIDtr9y8nEo,2207 -openai/types/beta/realtime/conversation_item_retrieve_event.py,sha256=5Cc7f0fM8ujwER0eIcQRwz0rmc6hdCUrAqiAvRNn9Zc,559 -openai/types/beta/realtime/conversation_item_retrieve_event_param.py,sha256=TRYaZ3btNaywRPaMOVRzK5VT7wh4taIGjbUdhkZ7gFc,579 -openai/types/beta/realtime/conversation_item_truncate_event.py,sha256=1c2_BamaTkgD26eyGZJU5xwbz7lRHupqU2HqcK0VniI,943 -openai/types/beta/realtime/conversation_item_truncate_event_param.py,sha256=hSnVOSMMtLf16nn4ISHkevYCfEsiN9kNcgxXRtHa8Kc,983 -openai/types/beta/realtime/conversation_item_truncated_event.py,sha256=K4S35U85J-UNRba9nkm-7G1ReZu8gA8Sa1z0-Vlozc0,704 -openai/types/beta/realtime/conversation_item_with_reference.py,sha256=NDMfbnG0YKLqWJskFSHRIMkN2ISs8yNRxP6d6sZshws,3288 -openai/types/beta/realtime/conversation_item_with_reference_param.py,sha256=X0iEdjijFkoGtZtp0viB8bAFqMn4fNNSvJiCZbgJ-3Q,3079 -openai/types/beta/realtime/error_event.py,sha256=goNkorKXUHKiYVsVunEsnaRa6_3dsDKVtrxXQtzZCmk,877 -openai/types/beta/realtime/input_audio_buffer_append_event.py,sha256=lTKWd_WFbtDAy6AdaCjeQYBV0dgHuVNNt_PbrtPB8tg,662 -openai/types/beta/realtime/input_audio_buffer_append_event_param.py,sha256=XmN2bE6jBRrkKGVPJdnPjJql5dqMPqwbmFnxo-z22JE,682 -openai/types/beta/realtime/input_audio_buffer_clear_event.py,sha256=7AfCQfMxZQ-UoQXF9edYKw5GcTELPcfvvJWWpuLS41c,489 -openai/types/beta/realtime/input_audio_buffer_clear_event_param.py,sha256=y-zfWqJsh1n6r2i0MgLDpnNC4g1dq3GCS66Twfkng38,499 -openai/types/beta/realtime/input_audio_buffer_cleared_event.py,sha256=j9gpm7aGVmrUt48wqtvBMN8NOgtvqHciegjXjOnWm7A,429 -openai/types/beta/realtime/input_audio_buffer_commit_event.py,sha256=SLZR2xxRd6uO3IQL6-LuozkjROXiGyblKoHYQjwXk4I,493 -openai/types/beta/realtime/input_audio_buffer_commit_event_param.py,sha256=B8agXC-rUl-D-RijJ5MeTLgw43qVYzmf2_2oAVokhLY,503 -openai/types/beta/realtime/input_audio_buffer_committed_event.py,sha256=76XHl3ETfG5YiYce2OCUsv0wNfSiaabLzYVjGtBwux0,733 -openai/types/beta/realtime/input_audio_buffer_speech_started_event.py,sha256=NVp60RUsLFtte9Ilknmu_5lRk2dZp_1fXCgGHd4EvSM,861 -openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py,sha256=gszRuYQtAW8upIhd7CJZ7pxboDk-K7sqidjqxgf47q4,779 -openai/types/beta/realtime/rate_limits_updated_event.py,sha256=kBnf_p-49Q_LNdJsj0R1Szi8R4TGYAAJ_KifLuuyFZw,949 -openai/types/beta/realtime/realtime_client_event.py,sha256=0c48JcJH5yruF52zl0Sanm_dd2W5ZHV5GocRG0Xm6m4,1839 -openai/types/beta/realtime/realtime_client_event_param.py,sha256=xBeZ60Q-OWuZxstPQaoqE0DUTDOPOwrL8LWMmDJI2rM,1887 -openai/types/beta/realtime/realtime_connect_params.py,sha256=AvTypkFCYmDn9qMeektVqij6cqzgovr3PpgpMalJoJ4,290 -openai/types/beta/realtime/realtime_response.py,sha256=iUOItlPQv6-okCuiTsloe0LDVyJ0MUQ64ug8ZaLePnw,3567 -openai/types/beta/realtime/realtime_response_status.py,sha256=gU-59Pr_58TRfMZqFzdCloc53e1qOnU4aaHY3yURUK8,1326 -openai/types/beta/realtime/realtime_response_usage.py,sha256=6XOFjCjPWioHoICZ0Q8KXuUzktQugx6WuTz0O5UvzZg,1541 -openai/types/beta/realtime/realtime_server_event.py,sha256=-PpqZpg-DL_C_wseLMRQHWdBvxnVGRAfOF7x13Qr34E,5408 -openai/types/beta/realtime/response_audio_delta_event.py,sha256=UjbnK4u_WSNTOColZj8SmJgHnAc2H8iRXD76ZnPbz7E,742 -openai/types/beta/realtime/response_audio_done_event.py,sha256=1XEWBPh1JiOgyr6V03mRt_3sLm0YFUq5ft1AhfFlNEg,679 -openai/types/beta/realtime/response_audio_transcript_delta_event.py,sha256=HEVNQ_R2_Nyo6BvNvsliMnN__b17eVd2Jx5udRHg0Hg,773 -openai/types/beta/realtime/response_audio_transcript_done_event.py,sha256=Cn5l4mJnKK3LeSN9qFL4LLqs1WOWg4kt1SaYThB-5c0,787 -openai/types/beta/realtime/response_cancel_event.py,sha256=EKx8IZUISJHdl-_3tCdHtz2BINQ85Tq_ocadnsEGPSk,637 -openai/types/beta/realtime/response_cancel_event_param.py,sha256=nidzBL83liHwyImiNGiz9Ad0V34EtFAQDw1utqcF6ns,630 -openai/types/beta/realtime/response_content_part_added_event.py,sha256=a8-rm1NAwX685fk7GdT6Xi0Yr-JfeAkyUr94-RoFe34,1232 -openai/types/beta/realtime/response_content_part_done_event.py,sha256=jO2TZygxPabbnEG9E1AfNP-JYJv1QtCMnCzgcZ_3n18,1190 -openai/types/beta/realtime/response_create_event.py,sha256=46i-O9wwvhr1CzHNMDzhs2SGVwHiFJDOkQfOZZRfAWo,4763 -openai/types/beta/realtime/response_create_event_param.py,sha256=IPJlTWH0HzsknpSRrFgrQ3bfxsFZVRdQ6IYEsiGSZOk,4619 -openai/types/beta/realtime/response_created_event.py,sha256=zZtHx-1YjehXxX6aNE88SFINDaKOBzpzejo6sTNjq9g,506 -openai/types/beta/realtime/response_done_event.py,sha256=_yUPoECCli89iHLtV3NQkXQOW6Lc1JlxVPFw04ziBGY,494 -openai/types/beta/realtime/response_function_call_arguments_delta_event.py,sha256=Yh2mQZDucfnTLiO8LRyG9r7zeS1sjwLcMF1JPMdTFJc,793 -openai/types/beta/realtime/response_function_call_arguments_done_event.py,sha256=kxSPK6nbNWL6pxveY7zaNGgCkCXqyBFJPVYJrw9cbOw,793 -openai/types/beta/realtime/response_output_item_added_event.py,sha256=-_BZjvAqcgv3NIz-EMhvYMxIwvcXTt68FVNp0pw09dI,713 -openai/types/beta/realtime/response_output_item_done_event.py,sha256=0ClNVMZmeIxKghlEid9VGoWiZ97wp00hIdNnev4qBD8,709 -openai/types/beta/realtime/response_text_delta_event.py,sha256=B1yyuc6iMOMoG5Wh6W5KoQNYtVD1vEm2cKqHnl2CuFQ,721 -openai/types/beta/realtime/response_text_done_event.py,sha256=mPgVG6nWxwkZ3aZOX-JkVF7CpaWP5-bvtbxFrr4fK7g,724 -openai/types/beta/realtime/session.py,sha256=RZMR4d09k0erHFefzbYwQNyw0V6M5ESEPJ0qoO90lCU,10183 -openai/types/beta/realtime/session_create_params.py,sha256=PTFBt7w7fTrz2KWZIz5GjJqLoQkyv7qEIspFscs6zy8,10251 -openai/types/beta/realtime/session_create_response.py,sha256=HfCFE46q3IEfvLFEdU06DAg5GKIPlJjaU9DtKzKcr2U,6574 -openai/types/beta/realtime/session_created_event.py,sha256=rTElnBlE7z1htmkdmpdPN4q_dUYS6Su4BkmsqO65hUc,489 -openai/types/beta/realtime/session_update_event.py,sha256=w4SVhFjcoasgL1yyyNfykarnD-BzmxDt_0kED8pN8pw,11237 -openai/types/beta/realtime/session_update_event_param.py,sha256=Wu_4oa0R1YUTyI6_7AtOwy07qJf1YSCUZpdqO8CKkd0,10749 -openai/types/beta/realtime/session_updated_event.py,sha256=HyR-Pz3U9finVO-bUCvnmeqsANw-fceNvVqEIF6ey10,489 -openai/types/beta/realtime/transcription_session.py,sha256=Soo2LuEMJtkUD2oPJ1E23GUcoUrYBiSu_UtbLUKemfw,3184 -openai/types/beta/realtime/transcription_session_create_params.py,sha256=BVwSY41UX2njXAJpWynMJtC5XuKv6sNs7kp2Y8KSjnk,5976 -openai/types/beta/realtime/transcription_session_update.py,sha256=YMP9OB9P5FaSwaicXtYELjm4hD1gDSvKFq9YtF2sq64,6694 -openai/types/beta/realtime/transcription_session_update_param.py,sha256=b99v4yKnB2lC_cnYGiaxKnQuHB4eUW-v3eKT2UDsamk,6453 -openai/types/beta/realtime/transcription_session_updated_event.py,sha256=CKAS98QL7CuOVEWF6qGcC9qhTktdG2CPPJXbrW75GIM,833 -openai/types/beta/thread.py,sha256=bVlpfXpyA_tApIDBNAWJCgusLEiE-7xR-ptcIq1obg4,2545 -openai/types/beta/thread_create_and_run_params.py,sha256=PYD9furmj02jdHoET7O9D4QZn9DArGzR0L_YZGFGmiA,15853 -openai/types/beta/thread_create_params.py,sha256=BKzfwUsYNcGuIZluOAdqpUqFvoQ2tAkAEpGC-zD9EsA,6994 -openai/types/beta/thread_deleted.py,sha256=MaYG_jZIjSiB9h_ZBiTtpMsRSwFKkCY83ziM5GO_oUk,292 -openai/types/beta/thread_update_params.py,sha256=oPdEz_th3PNmWB9jMA3ZdkOPalaCfMEVminirac7Cas,2217 -openai/types/beta/threads/__init__.py,sha256=0WsJo0tXp08CgayozR7Tqc3b8sqzotWzvBun19CEIWc,3066 -openai/types/beta/threads/annotation.py,sha256=Ce3Y0mSodmYRkoqyhtyIdep6WfWew6KJJgtrENOnfek,462 -openai/types/beta/threads/annotation_delta.py,sha256=iNsE-1Gn1yU0TlTHoxqKbOvPRUxWuXsF72qY_mMnWGY,510 -openai/types/beta/threads/file_citation_annotation.py,sha256=BNpkIVngBZKLi8Db-yrJP52Kz4Q3z4Zv4JPjGsyxHqo,819 -openai/types/beta/threads/file_citation_delta_annotation.py,sha256=1of3IGGzEDTclj2uYID5rS4yZeymFRuzYKmIKfr5aO0,1097 -openai/types/beta/threads/file_path_annotation.py,sha256=1bI1P-utzhQMbNWPKFFCM5ELMH82qrJ1WsqErmrjhB0,681 -openai/types/beta/threads/file_path_delta_annotation.py,sha256=jhEbT7AinewxqTDiBdriy9KIc085VV2HjUpsVUwFHIM,884 -openai/types/beta/threads/image_file.py,sha256=QVXLiplb-CigZqdMZtXlmebXKt6tF74kI-3vHxe_qUE,707 -openai/types/beta/threads/image_file_content_block.py,sha256=f2QUOVbfBCakboLwIf416C2LOR-Tz4KT5AZf6vbE32A,494 -openai/types/beta/threads/image_file_content_block_param.py,sha256=ErMMN4cM5D1fac1kBsrKtDRc3mUFD64qnaFhLPaAIBc,576 -openai/types/beta/threads/image_file_delta.py,sha256=nUJoSuP-3YyqqwBsmPJ0AqiQydz2FymVDCXQVkNYwOk,734 -openai/types/beta/threads/image_file_delta_block.py,sha256=G6UI6p4Cl0HLph3tXHU2uxA5PsEdfPyVN93nrOzFDw8,623 -openai/types/beta/threads/image_file_param.py,sha256=BaKD31JPxQ5CjRfZ_0RcOG3lDTZeW_k85XCvwyctD54,717 -openai/types/beta/threads/image_url.py,sha256=EzEK-CYoO0YyqFmejIPu7pMfTEgMmp5NFscsRd2pCos,592 -openai/types/beta/threads/image_url_content_block.py,sha256=AhYYI0pe55gEKM8FQT7jr7Z02NueszB7pvzLV_FuXdA,429 -openai/types/beta/threads/image_url_content_block_param.py,sha256=XBPXiRqqLAkAnK5H6zKiZ9v5eQ4IOcEctsdQn0P6ikI,511 -openai/types/beta/threads/image_url_delta.py,sha256=MXCp-OmuNT4njbWA9DWAbocP7pD3VpdcUy2wgeOjwm4,582 -openai/types/beta/threads/image_url_delta_block.py,sha256=7ufBlfrXXY8ACIi8M_u-ytH-4ZXew_ytKbwf__z-cLg,548 -openai/types/beta/threads/image_url_param.py,sha256=VRLaxZf-wxnvAOcKGwyF_o6KEvwktBfE3B6KmYE5LZo,602 -openai/types/beta/threads/message.py,sha256=0Xt_yrqhmLhVoDXRbW0YeXJx9BtlLjX8MNPG-B-ySyg,3613 -openai/types/beta/threads/message_content.py,sha256=b8IC_EG28hcXk28z09EABfJwPkYZ7U-lTp_9ykdoxvU,630 -openai/types/beta/threads/message_content_delta.py,sha256=o4Edlx9BtdH2Z4OMwGWWXex8wiijknNRihJ-wu8PDUQ,615 -openai/types/beta/threads/message_content_part_param.py,sha256=RXrnoDP2-UMQHoR2jJvaT3JHrCeffLi6WzXzH05cDGI,550 -openai/types/beta/threads/message_create_params.py,sha256=7fXlNyqy7tzuLgMsCYfJegL2sZcjKwYNLihwteODyg0,2083 -openai/types/beta/threads/message_deleted.py,sha256=DNnrSfGZ3kWEazmo4mVTdLhiKlIHxs-D8Ef5sNdHY1o,303 -openai/types/beta/threads/message_delta.py,sha256=1lh0FTbyqpcLVL8XqwTiAkZy03teJYIAYm_Zj8dbnY8,647 -openai/types/beta/threads/message_delta_event.py,sha256=Rg7g-1taxc2vTowD1J8ykXXRBeQJeTmTxxkZ8e95r1U,682 -openai/types/beta/threads/message_list_params.py,sha256=iuwzDccnViooUxHlq-WoE1FEJArNy5-zrYCoaNgVS8k,1296 -openai/types/beta/threads/message_update_params.py,sha256=XNCSLfRkk531F8mNbUB9bRYcCzJfW8NiFQ9c0Aq75Dk,757 -openai/types/beta/threads/refusal_content_block.py,sha256=C5ORJo34aPdqi-7rviVDUnzi6nneUersczpNM7KPDds,369 -openai/types/beta/threads/refusal_delta_block.py,sha256=F2EWI_H7aUpySDO2xhZTMkICMj1aaM-XwXMzsx7Klhg,481 -openai/types/beta/threads/required_action_function_tool_call.py,sha256=1RWejiSE3wAM7bXWB5q3H_bVkRX2SKXwQ09SEJHOM98,953 -openai/types/beta/threads/run.py,sha256=MLn7qaAPJLijjQ3D-M0ftrbRD4WEQdzDMHC0XPSJcpU,9141 -openai/types/beta/threads/run_create_params.py,sha256=WdjVbHlKhCh2g7uIh-_9YyY8t29UKHk0hd_LHSTKKo8,10956 -openai/types/beta/threads/run_list_params.py,sha256=TgepSLrupUUtuQV2kbVcoGH1YA0FVUX9ESkszKuwyHY,1210 -openai/types/beta/threads/run_status.py,sha256=OU1hzoyYXaRJ3lupX4YcZ-HZkTpctNE4tzAcp6X8Q9U,351 -openai/types/beta/threads/run_submit_tool_outputs_params.py,sha256=cKiyD374BsZN_Oih5o5n5gOf_DYsxErVrbgxveNhmPI,1643 -openai/types/beta/threads/run_update_params.py,sha256=sVjkl6ayjU75Tk8t69r6xgIg80OlTikyRdS0sa2Gavg,749 -openai/types/beta/threads/runs/__init__.py,sha256=mg_roY9yL1bClJ8isizkQgHOAkN17iSdVr2m65iyBrs,1653 -openai/types/beta/threads/runs/code_interpreter_logs.py,sha256=UhfSrLKN3NSIOTYGCZhJCv1s_d_8_gTdppFIbBPdgSk,564 -openai/types/beta/threads/runs/code_interpreter_output_image.py,sha256=8o99k0ZHMHpqH0taXkOkYR9WaDUpCN-G0Ifd5XsJpb8,613 -openai/types/beta/threads/runs/code_interpreter_tool_call.py,sha256=u8htH0HfF8Yxc4cBOr6QgBSS1Q465rKz5z0L0bYBz-s,2029 -openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py,sha256=qGBFdfYB0GUWNJpfvh_x387zCUxLrkQtSSOL9EV4K0g,1616 -openai/types/beta/threads/runs/file_search_tool_call.py,sha256=6R27ipmR0J4qc8qjBak00Leov8L_zWLNP6tplXLcfgY,2127 -openai/types/beta/threads/runs/file_search_tool_call_delta.py,sha256=Gx8c7GSgGYuOvGadcAr3ZIspEFMZS3e2OY7vBo_MYnM,655 -openai/types/beta/threads/runs/function_tool_call.py,sha256=V0-x41j1lAY_JBZ0jzd7olIY8HN-IPzzLz_oYTIgb30,979 -openai/types/beta/threads/runs/function_tool_call_delta.py,sha256=DxCHC0yHmryCfkwon1z5LMV-hGaBwacMoP74Pzwed0s,1135 -openai/types/beta/threads/runs/message_creation_step_details.py,sha256=Bfeq7HnLcQjHer0zen013YuU087_ZEitbEurEQS6xds,566 -openai/types/beta/threads/runs/run_step.py,sha256=oU0Rj1XfidZWiWZnY_koSBI56vnoRciMEDQC-sMLeLw,3882 -openai/types/beta/threads/runs/run_step_delta.py,sha256=YpcPvXnwBvlp6tlMhcWGGjCgNsKfiOJVzGhs-tyKe2U,741 -openai/types/beta/threads/runs/run_step_delta_event.py,sha256=f21Eb0e9Syf938ehZM2lh_tzy_T7CVpJTIOQoW35jfs,690 -openai/types/beta/threads/runs/run_step_delta_message_delta.py,sha256=JCbaG1UIrVT1mDtjgdVw4vD68dQkzst5eSjuTqdX_vE,624 -openai/types/beta/threads/runs/run_step_include.py,sha256=u-9Cw1hruRiWr70f_hw4XG0w1cwOAYfRJYKva2dEacs,264 -openai/types/beta/threads/runs/step_list_params.py,sha256=zorF5juogCzLMsZLjzMZTs_iIBcPj9WUur5HcrXuH8M,1752 -openai/types/beta/threads/runs/step_retrieve_params.py,sha256=aJ7l8RDJLPyEmqjfO4XsTV54VZOOqyb_gKSUvqp33ZI,815 -openai/types/beta/threads/runs/tool_call.py,sha256=1rwq4IbLgjQAQ-ORXYkNpmJyi9SREDnqA57nJbj_NiU,537 -openai/types/beta/threads/runs/tool_call_delta.py,sha256=t5wF8ndW3z99lHF981FL-IN5xXBS9p7eonH9bxvKu_c,600 -openai/types/beta/threads/runs/tool_call_delta_object.py,sha256=GsemUuIbB-0arodq5YBBqJjH4LtrGWXi8Fql4-v3f9c,652 -openai/types/beta/threads/runs/tool_calls_step_details.py,sha256=gpNk7AUCm3ND1z2O2ETSZiXqXqkhHpZ2GzxzXAuQXTs,611 -openai/types/beta/threads/text.py,sha256=9gjmDCqoptnxQ8Jhym87pECyd6m1lB3daCxKNzSFp4Y,319 -openai/types/beta/threads/text_content_block.py,sha256=sE7JQpaQDPFfnDRegY8rOqem1vhaL4GOologyT8FenU,374 -openai/types/beta/threads/text_content_block_param.py,sha256=PQ8yKhUp2REWA5opa-83JCYmCCjppkt72sMX57Ys_Ms,462 -openai/types/beta/threads/text_delta.py,sha256=2EFeQCkg_cc8nYEJ6BtYAA3_TqgMTbmEXoMvLjzaB34,389 -openai/types/beta/threads/text_delta_block.py,sha256=cyGoOBssDwxWn0YDKx8p665-v4AB9M3TWZUfgXgT_MM,503 -openai/types/chat/__init__.py,sha256=wyA0EWb0utj19dX0tCeGh4Jg5GrO3TGjmfQkR9HVxxE,6102 -openai/types/chat/chat_completion.py,sha256=rPTJBRPwYAvISXFRhupNZjBZtr6UEHRgIWBJkgJQj3o,3650 -openai/types/chat/chat_completion_allowed_tool_choice_param.py,sha256=iBicIuMGQ8vj-LNdat4huVSoalJuWfG3d4qzFyomOK8,713 -openai/types/chat/chat_completion_allowed_tools_param.py,sha256=Ya6LVup7cF69D0_vs-Xfk74L40i6_mz_0JSxVNxPpF0,1087 -openai/types/chat/chat_completion_assistant_message_param.py,sha256=TxOgyqhTYK5Q5pusSKqgEE1qqjkprbUZb9zuzHBASI0,2797 -openai/types/chat/chat_completion_audio.py,sha256=wOZxqzRU4G8TEm5e1syagWtILAEvgIY_Zyo-7MEktGY,851 -openai/types/chat/chat_completion_audio_param.py,sha256=0fxKAeYxliX8N7wTsJw895qYhlwU9TPlbHQ3NYFMs6s,1023 -openai/types/chat/chat_completion_chunk.py,sha256=rq8dljAql3jIRC10Qc9h0kBuKhb_Ju7DXBw6CWM3onA,6498 -openai/types/chat/chat_completion_content_part_image.py,sha256=9OD-MwO3od5471z5Il_w6EEunuuOAkKQQo25438KKyU,840 -openai/types/chat/chat_completion_content_part_image_param.py,sha256=U_HLJUD9WlpBuoX6Jg3YmS6MXdQG4ZWAbSonTNYLidM,884 -openai/types/chat/chat_completion_content_part_input_audio_param.py,sha256=0m6GBd4EPLddC29tkmB6kNfYNCqIyqzqi7FoNflc-gI,790 -openai/types/chat/chat_completion_content_part_param.py,sha256=J5ZhUW-SZvuEsKPGUytYLuEUdKgcdfQ68j5IJi6vvVk,1373 -openai/types/chat/chat_completion_content_part_refusal_param.py,sha256=TV1vu-IgrvKa5IBlPSIdBxUaW8g1zDhMOOBOEmhU2w0,467 -openai/types/chat/chat_completion_content_part_text.py,sha256=qgeE0bvOzD_BE4BdvEuFjBj1kWF74RhYQD7eSk7VCo8,468 -openai/types/chat/chat_completion_content_part_text_param.py,sha256=OR0mct4BbfJnDw6PAShySI8CsDxKBtr3wMwowJph40w,534 -openai/types/chat/chat_completion_custom_tool_param.py,sha256=5IU-XnMLDcCHleEjPebg6tNiY9gXvrKaH_hyQhkW-bk,1867 -openai/types/chat/chat_completion_deleted.py,sha256=O7oRuPI6YDa_h7uKnEubsjtw8raTcyVmVk95hoDfo74,470 -openai/types/chat/chat_completion_developer_message_param.py,sha256=XkL5kaXoSeAlvBMr7etkm1Ony6Z26gNakwfS3ch2Hq8,1049 -openai/types/chat/chat_completion_function_call_option_param.py,sha256=_Lii1uFcSbXO0blmJn3VHkYXuXKO2cRT-Z-JikD2mrA,489 -openai/types/chat/chat_completion_function_message_param.py,sha256=jIaZbBHHbt4v4xHCIyvYtYLst_X4jOznRjYNcTf0MF0,591 -openai/types/chat/chat_completion_function_tool.py,sha256=IGZSLdIbxJFgF-P0DTZeEanGFcf5iUdj5sAYd-6EbRI,513 -openai/types/chat/chat_completion_function_tool_param.py,sha256=085qkwOGKX3M-Laf66N3KBfalXbUQb3lp76wWRi68B8,587 -openai/types/chat/chat_completion_message.py,sha256=xtsA62BEMKI-06xRbiZo-ljpyq0FtHEsgr8BXJ1AqsM,2829 -openai/types/chat/chat_completion_message_custom_tool_call.py,sha256=dGX_nKX-qj4Yup44mov1rFPGPxhfarHf17wGHE4jB4g,750 -openai/types/chat/chat_completion_message_custom_tool_call_param.py,sha256=A2d2BTzl1-XrXhWmLyAPdqzwzQwTLfaA_M9ObIpIJeE,859 -openai/types/chat/chat_completion_message_function_tool_call.py,sha256=2kd0tKE_NUfvsR4nep1yap7D0TRzzD9yuSvn5wcyouo,1022 -openai/types/chat/chat_completion_message_function_tool_call_param.py,sha256=6FjTlBTsoFFBGcF2fFs6Uq3CoAnvY-9Jvs4dxHlepqY,1131 -openai/types/chat/chat_completion_message_param.py,sha256=aLrz_cX_CYymFdW9cMIPZpv0Z4zM50RECV3SH6QNZsc,1019 -openai/types/chat/chat_completion_message_tool_call.py,sha256=aWpKcV6NZZfx_-aGEwPz99IDWNCdRuwoYpUChs0Uvvc,738 -openai/types/chat/chat_completion_message_tool_call_param.py,sha256=rE_TbdN3N6JGzHecykgdFHZgI66p2lsl0loPpz5TxW0,458 -openai/types/chat/chat_completion_message_tool_call_union_param.py,sha256=L8IoSHXgIFxYyHSfXQJNN7FJlp31ez8X4l5eSPKGmYM,602 -openai/types/chat/chat_completion_modality.py,sha256=8Ga0kruwJc43WD2OIqNudn7KrVRTPDQaalVkh_8bp9I,236 -openai/types/chat/chat_completion_named_tool_choice_custom_param.py,sha256=yxPaDdBK71bQ4vHu-a4nSbvNLdxuOoT8utOJcCK9Ja4,680 -openai/types/chat/chat_completion_named_tool_choice_param.py,sha256=z8G5YhuzuTQwUGmRWu2jK5BDeJW5cuY14rpOa9DTJ6c,671 -openai/types/chat/chat_completion_prediction_content_param.py,sha256=7jK3nMFFPbxLx6-F6Y7u2kBygDm4IQbtEej5BeQ5KBg,988 -openai/types/chat/chat_completion_reasoning_effort.py,sha256=9sAGlM21dgRNOQRSsL_znZf9ruXcmvVriWeex0fRgMk,235 -openai/types/chat/chat_completion_role.py,sha256=LW6-tqXaqpD7H53PiSXrjvIo6g4RfHhWityDm6Nfvig,275 -openai/types/chat/chat_completion_store_message.py,sha256=JUcit8AUnUzrEJIokS15nssCZ_7g-dcEeXE9Fejb6Sg,977 -openai/types/chat/chat_completion_stream_options_param.py,sha256=pwt3pqOZNIzmeESTT2hzouRCNJ5cQHRZ1ZQ1as2vzSg,1397 -openai/types/chat/chat_completion_system_message_param.py,sha256=14_Nq02KOYn6bd9BYJ1pzUPcYG8lOZCuDFNcyrfiEZw,1024 -openai/types/chat/chat_completion_token_logprob.py,sha256=6-ipUFfsXMf5L7FDFi127NaVkDtmEooVgGBF6Ts965A,1769 -openai/types/chat/chat_completion_tool_choice_option_param.py,sha256=wPIjU-eeybPjRFr28mx8Njp2OCrKw3Xpu0231z4Kz1A,758 -openai/types/chat/chat_completion_tool_message_param.py,sha256=5K7jfKpwTuKNi1PTFabq_LHH-7wun8CUsLDh90U8zQE,730 -openai/types/chat/chat_completion_tool_param.py,sha256=5hFt0Izat_o50JMJzspCYeB0gubilRDB3a6yIfGHoN8,431 -openai/types/chat/chat_completion_tool_union_param.py,sha256=smpIoekwuuXKQx9jRRB2cqc3L7_fmN5lB4IIJHlKhys,504 -openai/types/chat/chat_completion_user_message_param.py,sha256=znqcR_CPZX8YxQpFq1xNQISVR3dM8hj5rjN33b00KHo,901 -openai/types/chat/completion_create_params.py,sha256=67j_HV9PRg6d5MQetiHAyivSozbdnUX92hLVRuvAKfY,18433 -openai/types/chat/completion_list_params.py,sha256=jOAiZ6vYSrxyD-3qzIXvXofJkejl6bet9_yNsC9p5ws,1154 -openai/types/chat/completion_update_params.py,sha256=VRDF28qoonjrveHhw8BT4Yo_NlLsV2Qzd_KUUQ6AEG8,742 -openai/types/chat/completions/__init__.py,sha256=nmKlohYbZmr7Pzv1qCDMSDbthcH6ySPFIgvXpHZtxK8,195 -openai/types/chat/completions/message_list_params.py,sha256=IArlye40xGlMVIDHxsK9RX_5usPL71wXPMgdwI7_wYU,583 -openai/types/chat/parsed_chat_completion.py,sha256=KwcwCtj0yexl6gB7yuOnyETRW-uUvNRYbVzPMkwCe5Q,1437 -openai/types/chat/parsed_function_tool_call.py,sha256=JDWYo1XhTDQ8CxssbgjpzBhUw8jeXAmEd5Tr_CqFrVA,945 -openai/types/chat_model.py,sha256=yFvzwm6VJXCn6jN21FS-utN6bcBBzRIpKYk1VTP8sdo,177 -openai/types/completion.py,sha256=mwIFVtTYVKOmvIQJz6M6jQS1r48_rvbVvOztDp0C9Wo,1347 -openai/types/completion_choice.py,sha256=PUk77T3Cp34UJSXoMfSzTKGWDK0rQQwq84X_PSlOUJo,965 -openai/types/completion_create_params.py,sha256=UqgYjUpYbQYPdYETVxhkwgbGRKTQCBoyeSFtrB8iuAo,7652 -openai/types/completion_usage.py,sha256=siq8f0jlCP3GYFHQr8Zzflf-BYxOggE_OjtsGs9ur4A,1895 -openai/types/container_create_params.py,sha256=AhtgxFOFr8vIayvK8pTJq0G9j_Mgnze1UlhIGb4P6ik,1015 -openai/types/container_create_response.py,sha256=4yCPrrUA9tIvgU64kNwVEtLrSBGwLYee1Uo1HYCbxis,1589 -openai/types/container_list_params.py,sha256=7RiUMBOEJj9QH9LYtPiwUrIufx8czF6kk2JcfO_LP_s,893 -openai/types/container_list_response.py,sha256=jnoI1Fyem9m8D7eVhDAhir1R6P3kWOO8SfhJmxYrHAA,1585 -openai/types/container_retrieve_response.py,sha256=wFYvtDPJzAxCZNAZFo82WOX7M6NEirorHJUH38i-ugE,1593 -openai/types/containers/__init__.py,sha256=SCdMa4GNxw-I23CwW03iVOoHRfDybyKEMmpDkdVuUcI,480 -openai/types/containers/file_create_params.py,sha256=KXoZNG4DpiD7NDeQixdKJsuOv-iCZAlSN4sz7AQm49k,412 -openai/types/containers/file_create_response.py,sha256=Dh1OWf86XNMfmvVwfRGezfihdDuuAcdiQxT_3iefBzw,722 -openai/types/containers/file_list_params.py,sha256=9bU7uKeXPk7adFzwvKHFitFOV4phnIbbfFx5u6n1OFY,883 -openai/types/containers/file_list_response.py,sha256=xwvdMIUafkHSXJGQT1_mxt6T_8nJo-isp9M_5YTq-J8,718 -openai/types/containers/file_retrieve_response.py,sha256=wGPU9o5SKkg8s4aUJXhwC38u8KfTFKmIUk1ItUdYxJg,726 -openai/types/containers/files/__init__.py,sha256=OKfJYcKb4NObdiRObqJV_dOyDQ8feXekDUge2o_4pXQ,122 -openai/types/conversations/__init__.py,sha256=N7GRumNq1KeGR4X9STSKWLM1axUntyaMI_OwPihZmjI,1854 -openai/types/conversations/computer_screenshot_content.py,sha256=Q-YXldRA9F_NiDRpDEu7w8IDI86HvUCLc9EDH9ElS-c,671 -openai/types/conversations/conversation.py,sha256=BVpec4hLHle_8iRf6v5y4CPYHtMhEntP0m8PDG_5GSY,886 -openai/types/conversations/conversation_create_params.py,sha256=dtgIXlZj1yKP3oJUYdFCb2MKIk6BH8e4QbKIPPGjHf8,976 -openai/types/conversations/conversation_deleted_resource.py,sha256=HagMTsOrDL7QYQSeZqMbBMfRzhWAgnrxtinGT5uhog4,326 -openai/types/conversations/conversation_item.py,sha256=BfsUtqxwdYKTyi2eL-gpSgHiE1iduphQbxAv7gNoMQc,7672 -openai/types/conversations/conversation_item_list.py,sha256=bFXSZFmB1H9-IwjDRTCGtszxt57B3RAbHGZaL08gcYA,708 -openai/types/conversations/conversation_update_params.py,sha256=YMyThjw2ObnqY-dhI4iy2pqf0cZW7rNV0TcxpBMs1bs,746 -openai/types/conversations/input_file_content.py,sha256=xxG8_PMhnjH1F6jXs6vZyj_T1HdO--48fTYFrvWCPzk,219 -openai/types/conversations/input_file_content_param.py,sha256=ATFOU1VRdw8SDRvwdC1KEamfAMna-mIfpER5bLpGIeg,244 -openai/types/conversations/input_image_content.py,sha256=LKKWx1y5Gi0nu34a8CFbDUaXUWQACeQ80lwJtukOx3U,224 -openai/types/conversations/input_image_content_param.py,sha256=AceRCBW-WuXG5rI4uDF2w0n_eaa8DzpCmbdWm3ofVMg,248 -openai/types/conversations/input_text_content.py,sha256=G5L4ln3tkWqSzaZlAkFuzkFOpjYqPVnE3QyXafiA6YU,219 -openai/types/conversations/input_text_content_param.py,sha256=HPl92LQHoA3_2azNJcVF1FD6OTJY200uwbCodF7_xPg,244 -openai/types/conversations/item_create_params.py,sha256=TRAsvDuMBjLeL5DzqC-WyqmorZTnu4qZRt9eE13SJ8E,874 -openai/types/conversations/item_list_params.py,sha256=nMzeK_XkVTWsa5pMQDGDuRPfGwiXFBDcdZ4NYwYV7H4,1896 -openai/types/conversations/item_retrieve_params.py,sha256=lHK-Sqbd7DXWQKuXGRBUvu_a7LxYNAT_tBQqLP-OC5A,690 -openai/types/conversations/message.py,sha256=Zbg75g2Nduq2_tbFvRbWe-SBmtwo6RSuqXaXaWRgCz4,2118 -openai/types/conversations/output_text_content.py,sha256=bFDVfODBGMwRLcKeo0OZzZumZdZwHzHkG1B_Bw43vWA,224 -openai/types/conversations/output_text_content_param.py,sha256=8NlazI-VuJ9DgQ-ZGt9xJ8su2-CZ1mb_ebI9O19YC7Q,248 -openai/types/conversations/refusal_content.py,sha256=ThoHeemlqaKlUf7oVYOTUwnHuqph-4RXS4Ud_kGbGg0,227 -openai/types/conversations/refusal_content_param.py,sha256=hWb2AoU0oTKCNLRZs5kzxY2Uk7HkeHhEy5leL29Uy64,254 -openai/types/conversations/summary_text_content.py,sha256=TuGepAPiMlauu9CdEwkQdkLwErBjx6kNXlIG-CSb-4g,447 -openai/types/conversations/text_content.py,sha256=eya3kB6nXl0KEGlvpH_LlE8CIPzD5GVg5r851-oWR0g,286 -openai/types/create_embedding_response.py,sha256=S_HDPpkr_2us12j1M8NsXTrTg6RJT2rgI3zAsZpMSZg,848 -openai/types/embedding.py,sha256=PDZAZRp7mzlvz5R2FMMf50vRIphHNCgyST2gbo2NdA4,711 -openai/types/embedding_create_params.py,sha256=asahWWNcMvXGDfbTMz4uDy7DU9g6OJ9wowqZByghzw8,2039 -openai/types/embedding_model.py,sha256=0dDL87len4vZ4DR6eCp7JZJCJpgwWphRmJhMK3Se8f4,281 -openai/types/eval_create_params.py,sha256=QW52PWt7EhyNdYJ976ZpZiAolzoFdfa7zoXPUZWj4lc,8239 -openai/types/eval_create_response.py,sha256=MRZlHRJrtyGS5JN3GLR6UzjTa3Fjt0v-cGFAaGD4wHE,4468 -openai/types/eval_custom_data_source_config.py,sha256=XmGu1MzqE9poFFH65qMpw0W_C89DJdP8cwgpTvNYuPU,876 -openai/types/eval_delete_response.py,sha256=iCMGN0JG5kFIYNPSCOMSWlTu0FDkd2lbAw1VLO73-bQ,245 -openai/types/eval_list_params.py,sha256=WmIJa3O9wyuDKXXwE3tSnQv1XOTe1hngttSvvhbtf28,754 -openai/types/eval_list_response.py,sha256=H35sv5yCN_ROUNb0pBO1RkXHC8kEQMPxEtpMVhJ5MNg,4464 -openai/types/eval_retrieve_response.py,sha256=tOpjCP4ww5XYZrniUh9CphrWaltfTKhTdAXPiEhz3Ts,4472 -openai/types/eval_stored_completions_data_source_config.py,sha256=OGMNipFZes_EaeTi5ediozfUHAeLoTZTISIQRGaQDCI,1137 -openai/types/eval_update_params.py,sha256=Wooz-3SDznbC3ihrhOs-10y9cxpTKGQgobDLfZ-23c0,757 -openai/types/eval_update_response.py,sha256=ZH82tSoBv64c_4VUXKOcGBLJQ6xSersZz8gnGzbvjw8,4468 -openai/types/evals/__init__.py,sha256=wiXRqdkT-SkjE0Sgv6MixeECZjF0xaoCPdSGFEh0rEs,1193 -openai/types/evals/create_eval_completions_run_data_source.py,sha256=91mh923L-jJ2AyqzA3dh87hJR0KPDvaKaKr3OuH-4yY,9127 -openai/types/evals/create_eval_completions_run_data_source_param.py,sha256=Qa7TlKjpsJlUkVsxuI8q4pyBgyI-XWQKvQVqOnUIo6c,9210 -openai/types/evals/create_eval_jsonl_run_data_source.py,sha256=4BsR_n4iiFNoQ2-_Y8X0O2BONcSqCNY4Vav4RQPHX78,1323 -openai/types/evals/create_eval_jsonl_run_data_source_param.py,sha256=n0l8GC_RE89kcT4-WUE8tCpoOYbaW18b8XEgXQULqcc,1389 -openai/types/evals/eval_api_error.py,sha256=mBaebr3g8M0-mHtZQAg0QuCj3TDeXHeGLCBsHI5A7mA,339 -openai/types/evals/run_cancel_response.py,sha256=jF_JPZITqR3277nk4bh7ZpJvhZT5-LiL5mWir7YFsT8,15905 -openai/types/evals/run_create_params.py,sha256=caeqpTzX8grnYQ-JNa6iNk3EdosMA63PZT8MPXQbpkY,14849 -openai/types/evals/run_create_response.py,sha256=zh8DTmxlgUFEnUCfmITZuJFevYWSV4bq3GK8VA0bAj4,15905 -openai/types/evals/run_delete_response.py,sha256=WSQpOlZu53eWBCXSRGkthFn_Yz5rDCcSomqoa4HpUrk,323 -openai/types/evals/run_list_params.py,sha256=vgbJMYybzCep7e9rxUVHlWy_o4GNy4tJyGTwNu4n4ys,758 -openai/types/evals/run_list_response.py,sha256=VOCF7XSR3bloPGQR1froYWqmcJpEPb6vjmfzkQsyJ2g,15901 -openai/types/evals/run_retrieve_response.py,sha256=ImzKvC_ZMA_YaesVYfuHm1TZnWQ6-3OkpWZIJFX7qug,15909 -openai/types/evals/runs/__init__.py,sha256=sltNV1VwseIVr09gQ5E4IKbRKJuWJSLY1xUvAuC97Ec,393 -openai/types/evals/runs/output_item_list_params.py,sha256=Lp1OQV1qXeEUwMS90_-BpOnO1jICwJOo9QgNC9OGJ2U,821 -openai/types/evals/runs/output_item_list_response.py,sha256=YWkB3RtLae4hl0xs6gQvllYOcTwViR806LA_W3n9Kyg,4120 -openai/types/evals/runs/output_item_retrieve_response.py,sha256=CG3oTPKn9OOyHMLa3A-EAmo09mb_j2mJz6zw9hJ2C00,4128 -openai/types/file_chunking_strategy.py,sha256=oT5tAbwt3wJsFqSj2sjDPBcisegNwJOecxS_V7M4EdA,559 -openai/types/file_chunking_strategy_param.py,sha256=mOFh18BKAGkzVTrWv_3Iphzbs-EbT6hq-jChCA4HgAE,517 -openai/types/file_content.py,sha256=qLlM4J8kgu1BfrtlmYftPsQVCJu4VqYeiS1T28u8EQ8,184 -openai/types/file_create_params.py,sha256=nybdMeqDGmXYEjx4ffaWakU086QUqZCMR-pI3a9dsp8,1576 -openai/types/file_deleted.py,sha256=H_r9U7XthT5xHAo_4ay1EGGkc21eURt8MkkIBRYiQcw,277 -openai/types/file_list_params.py,sha256=TmmqvM7droAJ49YlgpeFzrhPv5uVkSZDxqlG6hhumPo,960 -openai/types/file_object.py,sha256=s0hqehIWHSMHbiIRTrURTi4iiCu2PXmEGrd4tUB8lW8,1589 -openai/types/file_purpose.py,sha256=aNd8G-GC1UVCL9bvTgtL4kfkiF0uEjfiimRS-eh8VrY,265 -openai/types/fine_tuning/__init__.py,sha256=f8GH2rKGcIU1Kjrfjw5J0QoqlsC4jRmH96bU6axGD64,1832 -openai/types/fine_tuning/alpha/__init__.py,sha256=e_Evj3xLs7o_SONlqoXDM75oZMbxuGWhxBW-azsXD_w,429 -openai/types/fine_tuning/alpha/grader_run_params.py,sha256=ECVczgghTZ8J9xfqAbNc_VvAHfhOpkaVzQw_wUmE4r8,1414 -openai/types/fine_tuning/alpha/grader_run_response.py,sha256=So-fvQMRvpccsSYb0jfKGQ_MNWdqqS71OcE9GbeLASs,1556 -openai/types/fine_tuning/alpha/grader_validate_params.py,sha256=Jd6m3DjIZAUNY-PlLUWDbH3ojm8ztnfjHmPjKw2DrLM,875 -openai/types/fine_tuning/alpha/grader_validate_response.py,sha256=nLldMLyNG-ICS3HwykDWdKuAPKu4gR2A2I0C79C4khs,773 -openai/types/fine_tuning/checkpoints/__init__.py,sha256=xA69SYwf79pe8QIq9u9vXPjjCw7lf3ZW2arzg9c_bus,588 -openai/types/fine_tuning/checkpoints/permission_create_params.py,sha256=TI90xY-4dv8vDKKZ0FBdbly9JTCrw4FgXkcXz_gTUlk,407 -openai/types/fine_tuning/checkpoints/permission_create_response.py,sha256=ATIeO4fFBTtaylBYdC6Id-wvirln4lKh2tRLMaJW01Y,751 -openai/types/fine_tuning/checkpoints/permission_delete_response.py,sha256=X_RuOvxa6i3wGLP5joHixv4tNLUpuK-2umiUf6P7Ha8,558 -openai/types/fine_tuning/checkpoints/permission_retrieve_params.py,sha256=3zVCOq1676MizKhKSba2OLmBSPlBx6Az2ZdxyVl580o,610 -openai/types/fine_tuning/checkpoints/permission_retrieve_response.py,sha256=o8wXyRWH80oA8o80crPkaGDyPIwuQZysRK1ic6mPqj8,963 -openai/types/fine_tuning/dpo_hyperparameters.py,sha256=Kkylxhw94kImWo6-SS_7Jq66nftP0Hy0bbRxtcrChXM,1129 -openai/types/fine_tuning/dpo_hyperparameters_param.py,sha256=mXJJXLhC_6E-7IYqDOlYGTWLLxx5Fs2l4_fmVvRs9RM,1113 -openai/types/fine_tuning/dpo_method.py,sha256=pQVpzKu0WGMQkL1itgY2Wrec85u5QHHROa0FInGdVhw,434 -openai/types/fine_tuning/dpo_method_param.py,sha256=cYBljFPSCtdDoNmyJ4s8OcgU08vCdQK8sxTJ7JX7nEA,471 -openai/types/fine_tuning/fine_tuning_job.py,sha256=DFd9yrwcrh4Jmpjf4HBgUTw7FLu-EkBWmhSkXTyuHS4,5662 -openai/types/fine_tuning/fine_tuning_job_event.py,sha256=T_ESNL8qLk25Z9MHbLqTZtj-nR_LyAS4FHuHTsU-KAI,894 -openai/types/fine_tuning/fine_tuning_job_integration.py,sha256=uNFfuBV87nUHQORNGVLP_HbotooR_e37Bgd0dyZ4nUM,241 -openai/types/fine_tuning/fine_tuning_job_wandb_integration.py,sha256=WUCywzpaj6ZVg_ZZKZxRqt_XS1A22mMasdSGxlOQsbU,1343 -openai/types/fine_tuning/fine_tuning_job_wandb_integration_object.py,sha256=7vEc2uEV2c_DENBjhq0Qy5X8B-rzxsKvGECjnvF1Wdw,804 -openai/types/fine_tuning/job_create_params.py,sha256=-79Le_1QQI0c8W5M1NWLKlmRs9Wt8soE7Y_2wGLfxds,6719 -openai/types/fine_tuning/job_list_events_params.py,sha256=4xOED4H2ky2mI9sIDytjmfJz5bNAdNWb70WIb_0bBWs,400 -openai/types/fine_tuning/job_list_params.py,sha256=wUGXsQ4UDCKvAjHDZAZ-JDU6XAouiTGThb0Jo_9XX08,623 -openai/types/fine_tuning/jobs/__init__.py,sha256=nuWhOUsmsoVKTKMU35kknmr8sfpTF-kkIzyuOlRbJj0,295 -openai/types/fine_tuning/jobs/checkpoint_list_params.py,sha256=XoDLkkKCWmf5an5rnoVEpNK8mtQHq1fHw9EqmezfrXM,415 -openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py,sha256=UG9keznPmpRFAM4ivkMJ8KlBbojdF3m2bSmiftBCnT8,1548 -openai/types/fine_tuning/reinforcement_hyperparameters.py,sha256=DwLBbYDa4QDJQup7aeg_KUu5wwC4tSLDpp60axNsmC0,1501 -openai/types/fine_tuning/reinforcement_hyperparameters_param.py,sha256=t91X4q0WocQ9PcjGJ8yu1w8vOdPvCFthTD-zrZuCNTs,1432 -openai/types/fine_tuning/reinforcement_method.py,sha256=vKEmXkRWUdd5GeLNxzZsqfQ8kG5GR3EXLCqaXy-DOoM,1025 -openai/types/fine_tuning/reinforcement_method_param.py,sha256=rjE_b2IY7Zkaf6UpMuGNrvizor2mhrUrMC-cZFFDmlQ,1157 -openai/types/fine_tuning/supervised_hyperparameters.py,sha256=Y9h3_iGD5drhkAdMjR4Szb00BZqQ43ka1FFUSgKrzJI,926 -openai/types/fine_tuning/supervised_hyperparameters_param.py,sha256=9nnnvgvHbT-x1adrP2yTBCtU19CGrjcQ5AQvXb2wkZ0,923 -openai/types/fine_tuning/supervised_method.py,sha256=sGXoTMI_r3BN53I7FA45dz_JU9d_7eQlPXHvRSswgfY,472 -openai/types/fine_tuning/supervised_method_param.py,sha256=GKw3VgMuZ6V0B0NKwHh_lrHRSM4gYp0dPBPoamYPze8,509 -openai/types/graders/__init__.py,sha256=y-002SPDfVfefLY1hTugtFHv74beH51tCTXi6dZrCDk,1147 -openai/types/graders/grader_inputs.py,sha256=rboj5sT1i5dwbXH3gGw6NgACSchjECaFeNg9a4Iq4dc,1299 -openai/types/graders/grader_inputs_param.py,sha256=-kXE-BoLSannXeqP0SSdcU9x6ssRu0xxMdgnmffMxCA,1494 -openai/types/graders/label_model_grader.py,sha256=UwzUzamECdsrNpyAnKYfFqTmE_R-ORzIKDIvtJmFCSU,2765 -openai/types/graders/label_model_grader_param.py,sha256=w7tWVs69B7IiM0BzfBEvZ-DKNQqbO-IIZ0csIt-94QI,3061 -openai/types/graders/multi_grader.py,sha256=JULSGQyLMw8aUX35xiKVr_hoqaVn2vkHG2VAjSV0GbI,1127 -openai/types/graders/multi_grader_param.py,sha256=BMnqlkcSYAKjLjjWvqj9FHVUQTFseHvs9MXaX_iDcrc,1300 -openai/types/graders/python_grader.py,sha256=xM2ClJoMlai_VqVDs_7HCwBj7bGwQurq8Y2zsMV2gQU,607 -openai/types/graders/python_grader_param.py,sha256=uNRp2JEkNSdTFDVpo0BcrQ8oyEgLeYodyFzxsT7miWs,638 -openai/types/graders/score_model_grader.py,sha256=iBAl6DjyKoHLD8x-CRGzIXtbFHO4ahSyKoNfDcTREww,4412 -openai/types/graders/score_model_grader_param.py,sha256=0wQcPE-nbrNmYHKpJ_nfVvWc0YcrBC48yK_mohefncE,4589 -openai/types/graders/string_check_grader.py,sha256=xQwwSyqZT0JRwLOiBW5bo_AdAAa9nAntJwkwfYGwBcQ,814 -openai/types/graders/string_check_grader_param.py,sha256=HLFE2vMYtN42p3whZw7snhwlt8hb55UphGhmzOYRKKM,910 -openai/types/graders/text_similarity_grader.py,sha256=ye43c3vEbWeSoABRURyd1j3EVRACVENRqn9Qx7YzU_Y,975 -openai/types/graders/text_similarity_grader_param.py,sha256=KW-fjo4H3S7mdZbFMXj7N0R0iWT7C5FsUrjCe2zIStw,1133 -openai/types/image.py,sha256=21v1I9bcjq7p-rw20iSNxW0CQG7OLUB1VP3d3zTjID4,872 -openai/types/image_create_variation_params.py,sha256=Xeka4vp5V0o8R_6vnLsqiQhWH5O6tUSCyO3FKGVmAeU,1426 -openai/types/image_edit_completed_event.py,sha256=u8Rj9eW4C7htO0jl59OP0u4CKEhO0TcTL1dqLGN2JQU,2024 -openai/types/image_edit_params.py,sha256=jWwiZhG3m1ZzU2PTPfAF_gtaBGduDw3ziuEX5BH5qN8,5500 -openai/types/image_edit_partial_image_event.py,sha256=tJR59-lg3QQfoDNsItBoScAMhS-IdOHDon655vRz0CA,1180 -openai/types/image_edit_stream_event.py,sha256=GtHKc8VdumW5RnQtIiyMqhwIIaqYogKXZF1QNuq9Bd4,516 -openai/types/image_gen_completed_event.py,sha256=rpjnocJQ5imYRrHHxEz5yDzWppi9W6sxxHYX1dKamQg,2036 -openai/types/image_gen_partial_image_event.py,sha256=5VJhxTf6ZgjVFbQn72iOkolIHCMAa4LExMhXhq35NRw,1165 -openai/types/image_gen_stream_event.py,sha256=gVzdE6qzBPpK3kEFM7EdoUzBa4DgCaS3AdF9gjd0pUs,508 -openai/types/image_generate_params.py,sha256=-G3-zsmpaaKtFnCbD42Tc_g_i45WiDVT72E7pVOYlDo,5469 -openai/types/image_model.py,sha256=LXjOC6iPeoDDrrZcUcKS6R4CpdL16DL3OkwhGTJUNys,271 -openai/types/images_response.py,sha256=GyUSpxaUXJfr0qHdabXdeYn15MXv1vD2SziISO01Qdg,2574 -openai/types/model.py,sha256=cmrjNhjHXnJUfgp3al0B2s4O-PvFD-nHni7h8h2p6FM,609 -openai/types/model_deleted.py,sha256=ntKUfq9nnKB6esFmLBla1hYU29KjmFElr_i14IcWIUA,228 -openai/types/moderation.py,sha256=epjd2oQqw5uSaBGXVSu0hCUaDITvfMgwJe9cNjCjvTc,7099 -openai/types/moderation_create_params.py,sha256=bv5qr2y_MQ1MYBhWWUiCET2L18ypWtQpaIKzYTrl9xs,1032 -openai/types/moderation_create_response.py,sha256=mNPnXzdTgyVarKDENlkgud35yoK9CqWpKtcpC1bV_ds,552 -openai/types/moderation_image_url_input_param.py,sha256=AZhp5qCmWjuaZbDO3Y0MMXMRYv_cEK45PP5I7VYn-F4,758 -openai/types/moderation_model.py,sha256=BFeqSyel2My2WKC6MCa_mAIHJx4uXU3-p8UNudJANeM,319 -openai/types/moderation_multi_modal_input_param.py,sha256=RFdiEPsakWIscutX896ir5_rnEA2TLX5xQkjO5QR2vs,483 -openai/types/moderation_text_input_param.py,sha256=4egKHVxB5niYopwD6j3DRU1fIq3vcG2Q7utGQj24kGM,456 -openai/types/other_file_chunking_strategy_object.py,sha256=h4JKlz4p__U1vbZeXKO9v4DrPsDLIE5IilYdNrrnhFs,501 -openai/types/realtime/__init__.py,sha256=hnjSirz0039Qais1VXg42nRrZNClsrmLGWYW-6SQP8Y,17085 -openai/types/realtime/audio_transcription.py,sha256=E0x4I29kjvVbJOvsjNMSUQP8iIofodsWjwuGdbPynN4,1513 -openai/types/realtime/audio_transcription_param.py,sha256=ecAesrI27A1iH01YyPXPx0G0bB7GwYxd8eS7WRouJkE,1484 -openai/types/realtime/call_accept_params.py,sha256=KSB7hkvjWTU-ooaKXqJRa2rpSIuTHU52P97212W_jlQ,5267 -openai/types/realtime/call_create_params.py,sha256=r0vyhcjvDAKZF8DSbLP7bEQAVh92hgzNBnXBQWJ56no,544 -openai/types/realtime/call_refer_params.py,sha256=Zhy_H0Jv0leRL6HS_WH7Oca7HUlZ0feINePxN-hms0s,422 -openai/types/realtime/call_reject_params.py,sha256=cyz55zIN5DzSL74uhzeKQOSecl4V0UkpySt7zykoGIA,374 -openai/types/realtime/client_secret_create_params.py,sha256=12Guwuw4txjO_cW2GnrPT67UO-AVBaOg7LTEPAFuuLQ,1989 -openai/types/realtime/client_secret_create_response.py,sha256=ZUDhhR8vzMZRdHkfc9hpl80T4bUbDk4QNeLV8QlcQlc,1016 -openai/types/realtime/conversation_created_event.py,sha256=kVZE5Y1ZRDQq-x0vqbuYAl-VIRj5is_zC4pjHKwKZjw,879 -openai/types/realtime/conversation_item.py,sha256=BGqZp9UpybVbEyr6enYqdleryy4NMbXpzkUPX03cvoI,1437 -openai/types/realtime/conversation_item_added.py,sha256=SaE8tAlIbS1hgv_F6p3BWMmfwkdrPQU18UnTxfoJ29U,1516 -openai/types/realtime/conversation_item_create_event.py,sha256=92M22K5X8Ggo0kQQH2uESira3JrbwU-MnORKj7lYc0A,1550 -openai/types/realtime/conversation_item_create_event_param.py,sha256=H40KgUXokcoOmdb613QNiKLgZxYgl4fn8m5WmzX2GQY,1571 -openai/types/realtime/conversation_item_created_event.py,sha256=hSqqRT281uXGKYPCaIImzYcWtzJLGp_fTkhIX3fQx3c,1474 -openai/types/realtime/conversation_item_delete_event.py,sha256=gDbD3qPFSxSYj3zjGUuVn5L1KLQDEyiDqPaGwMZeUAY,840 -openai/types/realtime/conversation_item_delete_event_param.py,sha256=sMZ5WeOkLHCV8bh9-06i2EUFD2V_-bA9DMkGX67W82I,861 -openai/types/realtime/conversation_item_deleted_event.py,sha256=VwTgV7HhBNOIBwSJfAtO9C0LP0pFers83ORnggEpbOQ,741 -openai/types/realtime/conversation_item_done.py,sha256=TjLuup27QloMnHgXemjpknACqV9N3A2-alX2_msK-1I,969 -openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py,sha256=ZemU0mTZAdxe8O1u5ZdLpelVd-UksKrIKFPnf0_Eg1I,3281 -openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py,sha256=KGr9MvmKDXnbAsQU-PbHethJ09I_MQ4KfQgUJlhF8Tk,1495 -openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py,sha256=Qugv24nmNkYqJFmsTMlDH-P38r50dPVSyt8-43Nmmr0,1364 -openai/types/realtime/conversation_item_input_audio_transcription_segment.py,sha256=JC_QW5z_TFmCPjRUm6k2qnWUEnoIK3IHXGlE88J2YP0,1079 -openai/types/realtime/conversation_item_param.py,sha256=yrtdTZDIfAsJGwSXDY7v-_e9GtOPqRNXQAM2LWjxOOI,1483 -openai/types/realtime/conversation_item_retrieve_event.py,sha256=YuRUzjV3VWdfMchkeyWBNkZdMjtboRaHiBz3PpXGVZc,975 -openai/types/realtime/conversation_item_retrieve_event_param.py,sha256=NG4pq3JXYIG44-vu5apNfa6iEO8y9Pn1Ypa8AqKQWjE,996 -openai/types/realtime/conversation_item_truncate_event.py,sha256=3OUHG_uqYOQgH6LX0vtZJ4WFjVDAv9FrSb8ZLAtZcSw,1560 -openai/types/realtime/conversation_item_truncate_event_param.py,sha256=OiSiFZ0KyUYN5AyhCKf7HKIyOxj-uW3psdtMN6PI5Yk,1601 -openai/types/realtime/conversation_item_truncated_event.py,sha256=KXuLWI1Ozcq0bR44T92cleAd6bvZRLQhD1XvaJBHLNM,1124 -openai/types/realtime/input_audio_buffer_append_event.py,sha256=VS09zVCzDrXJ2OXxkzBQORqfWuwwxRrUibsLkPyVxCs,1591 -openai/types/realtime/input_audio_buffer_append_event_param.py,sha256=U7EcpuHlmMwI6MJm5aWSg-OQs19T5IDycNSrosMFTgY,1612 -openai/types/realtime/input_audio_buffer_clear_event.py,sha256=2MJ3ypmN8SyOYkNjYTvdPp0Sz5UtvGumqOa8tCH1O3Y,637 -openai/types/realtime/input_audio_buffer_clear_event_param.py,sha256=MTQMjN6RACt7J9tSnzglNNOfGL-_MgzxWCYWltbko0k,648 -openai/types/realtime/input_audio_buffer_cleared_event.py,sha256=iClRNb-MTR86VkuZSbmwJii8iP9j0Ox0QlbCyt2G85w,556 -openai/types/realtime/input_audio_buffer_commit_event.py,sha256=Nluuq9h5G3hxy5PmmWGStxiS7-t-Dy4lsOKBIudMy14,1068 -openai/types/realtime/input_audio_buffer_commit_event_param.py,sha256=oflH-u7iSqqF-eriFHDWrqO-8G7iW0n-VfUUWcF2thQ,1079 -openai/types/realtime/input_audio_buffer_committed_event.py,sha256=M3MAPO5XwuFmOnfC_0_GcuYQ12aKILiEgEGdPAWzOlU,1027 -openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py,sha256=JUq_t7Q5E4241M1JTqTcRUwsmgZNmJmiUdn_LKcYP84,889 -openai/types/realtime/input_audio_buffer_speech_started_event.py,sha256=GjjkLM3MOoW8wJ6KKdUz-3yLpkK4VtrQu8NKC1BwQBg,1567 -openai/types/realtime/input_audio_buffer_speech_stopped_event.py,sha256=l0CmVlUxcGpthG37Hxtdf9ydypFKQxR0a_z7fz131kY,1029 -openai/types/realtime/input_audio_buffer_timeout_triggered.py,sha256=lLraokk0TW03UNyjpeVpHlyCoupNLQaRCsH7NofvYdI,1898 -openai/types/realtime/log_prob_properties.py,sha256=78jAqS9O2wwM5JhpV8Cdwpy8xgET0ceXclW4BcyPoCY,489 -openai/types/realtime/mcp_list_tools_completed.py,sha256=zKMP0fwchYZMbdJERmFBhIALlrNuz6npH4Gn0cMjbto,543 -openai/types/realtime/mcp_list_tools_failed.py,sha256=1En1gz6mxUhaYy0RoTBKxLk6grL1_kfaYWGRmX2Lkrs,528 -openai/types/realtime/mcp_list_tools_in_progress.py,sha256=xC1hb9qODkB-dAJPeNf40gQOi4q1cYNU1LivPPgMaIg,550 -openai/types/realtime/noise_reduction_type.py,sha256=lrAb7YhMM-anRYzzOha8hcVloNJR_zWuFrO2SccrcIo,238 -openai/types/realtime/output_audio_buffer_clear_event.py,sha256=w4xRRkTcCtGdYDspgkLnD6LlzavmjxUNiF0lOzVF2ow,934 -openai/types/realtime/output_audio_buffer_clear_event_param.py,sha256=-zmYI1KaCgiGFnYeLl9_tutNFuHHrbeKeXt94-ZmLhk,945 -openai/types/realtime/rate_limits_updated_event.py,sha256=rsYK1Yc0WrtMFG8shtaYQv5uEd59foHBTJs4XoA1l-s,1255 -openai/types/realtime/realtime_audio_config.py,sha256=CFWqdebuucyHyL4gqIZTuh78PME5cQPLmeq1VsD9Z3Y,520 -openai/types/realtime/realtime_audio_config_input.py,sha256=eQohrH7bIyaHA7W4qIerP61cUO_FAd9Cb-X36ZmNjd0,3248 -openai/types/realtime/realtime_audio_config_input_param.py,sha256=mdQg38uNnx9dOck83iWhsmdafe_OXLTtH9K8oLtq3LY,3300 -openai/types/realtime/realtime_audio_config_output.py,sha256=JgABZNG00eseAgYVZiJF_mf32iK3n7BsxwyI3Y5nAfw,1393 -openai/types/realtime/realtime_audio_config_output_param.py,sha256=m1Z2NNR2jWprIF94sLq5j1uwilleezSm51L1rb6u3As,1375 -openai/types/realtime/realtime_audio_config_param.py,sha256=d5gwlXPsJIc53Nh1A9QYefyHd5YJ-E1VRRfuK2IOafk,556 -openai/types/realtime/realtime_audio_formats.py,sha256=QZTTihJeSWCwEFUK2kjf4nvaZNXWnFfCKSXZee-Xa-Q,1069 -openai/types/realtime/realtime_audio_formats_param.py,sha256=N0NFD1pbh6ZlcbENKv10Np-K2QVPWIpFsLzl0koPirs,960 -openai/types/realtime/realtime_audio_input_turn_detection.py,sha256=mZB4mr8AaT5TtogXLwxzjM_Q5W-x5o4T1tPFFnyiMmU,4260 -openai/types/realtime/realtime_audio_input_turn_detection_param.py,sha256=ItL4MBzCTPYUScMQwgxdrbyIsbgbcNVoTuAF7Zk9oG8,4091 -openai/types/realtime/realtime_client_event.py,sha256=4_lYEyK-wj25VTh8GTaV0mZ0t17KhkfJrQ0yUF0mCYU,1473 -openai/types/realtime/realtime_client_event_param.py,sha256=YPveu8tNyKmZkK24qEJv8js5l5NNygDyAcsza2iOmKw,1543 -openai/types/realtime/realtime_connect_params.py,sha256=Zd5FnP-6nEzAPiWTckSdVGQsA_8GqhwELCpQXt22J8A,288 -openai/types/realtime/realtime_conversation_item_assistant_message.py,sha256=up0WdL75VVd6rK11nBjRCcIRn3Qj-6dFv3podahi78E,1780 -openai/types/realtime/realtime_conversation_item_assistant_message_param.py,sha256=agNl8DdxAJPV1NeGgTkti3V8QKg_WQTlZFbXYR931bI,1748 -openai/types/realtime/realtime_conversation_item_function_call.py,sha256=uT0NfedSzOpneh3Bqbx_oKSb-Cj0aFUd4b-sJ7QSIvQ,1262 -openai/types/realtime/realtime_conversation_item_function_call_output.py,sha256=aXHbpueTQ3lUri3oXA7B8m6S9Tcq8xQqFurzS8kNhdk,1170 -openai/types/realtime/realtime_conversation_item_function_call_output_param.py,sha256=yRdBH7iqCLqtKxgylFYK5c9moNuefrW6OQAWR0g0De0,1167 -openai/types/realtime/realtime_conversation_item_function_call_param.py,sha256=Et9Qisj41TwOgu6YweMUXm4hGDD6q4FGyoTEN5n8fWE,1242 -openai/types/realtime/realtime_conversation_item_system_message.py,sha256=vxOmlQODp5RtxCObbTj5_E-C82HjWJA2SiBIZYTuycE,1695 -openai/types/realtime/realtime_conversation_item_system_message_param.py,sha256=nbvAmVDzYD6HflURqkbrugVshOXpRvFxnnxFuQjc744,1697 -openai/types/realtime/realtime_conversation_item_user_message.py,sha256=Ud0ijIPDq8BALQsAjHyJqHjywzq7yl37dv28Ru7Ilvg,2170 -openai/types/realtime/realtime_conversation_item_user_message_param.py,sha256=bIEMwkqvS9iDpt7X1KofesZaTi0sZYVo6IJj-CWtXCc,2104 -openai/types/realtime/realtime_error.py,sha256=V33P7DvMTFyEI2rhVkCnoD5zbt6wndDYyr_eZQ29BJo,658 -openai/types/realtime/realtime_error_event.py,sha256=FGyefJO5-GSjwyrsXBq-Ezp6qYZEcQsN1J_5sWBlyiA,714 -openai/types/realtime/realtime_function_tool.py,sha256=3CDiCZCM0A1VLRxOFdG4teFXr8dx0JFU94KbSn-JgGc,734 -openai/types/realtime/realtime_function_tool_param.py,sha256=-vDBSmMWNdbABC8dxVckkNeRdEujAKeff6icJvYrM0I,674 -openai/types/realtime/realtime_mcp_approval_request.py,sha256=n88sEpgRYFAIPe_jqmlYa0KsBDv03kkBstpp90GSvhY,696 -openai/types/realtime/realtime_mcp_approval_request_param.py,sha256=GIdxqx9wz5cRBU0iT1_DtlZlyNgehKhrsaqMEfRl624,792 -openai/types/realtime/realtime_mcp_approval_response.py,sha256=HOiVoqZwfA8WAZIyN3fPwUsceepQq6OWkkLaZGqJDXM,742 -openai/types/realtime/realtime_mcp_approval_response_param.py,sha256=ysEMT5pSKOo8-scsMSoW_vutKX14MDTsKc_jEHQsPoc,821 -openai/types/realtime/realtime_mcp_list_tools.py,sha256=LrgWdG30hgwmoFHC92aONFReZzWaI24SDQaH78yyGsc,1004 -openai/types/realtime/realtime_mcp_list_tools_param.py,sha256=SEiFMWl6ig6xjzUAx9fnN8ap_88kVUQEy3Ia8zWPiSg,1090 -openai/types/realtime/realtime_mcp_protocol_error.py,sha256=4jqkfl6h7tFT5kQy40VW24LrokpKe6X4VROYlNmOHDQ,313 -openai/types/realtime/realtime_mcp_protocol_error_param.py,sha256=jlufPTMU_9JuYtqzQGTmb0o978gDiOFxkNx0yJAvwx8,389 -openai/types/realtime/realtime_mcp_tool_call.py,sha256=C3FP8y_xqmFjBcO64I6phXMiuFC1sRt-8JZypczbQ4k,1407 -openai/types/realtime/realtime_mcp_tool_call_param.py,sha256=lsbewyAWR1wH4rj3znPeJ3twMSV1EaP6p0Faq2s5JXM,1421 -openai/types/realtime/realtime_mcp_tool_execution_error.py,sha256=swcOrTKO5cx1kkfGS_5PhBPEQx_Vf_ZW04HbA5eRa0g,314 -openai/types/realtime/realtime_mcp_tool_execution_error_param.py,sha256=3IuPmvy52n_VByGYqfCr87kciEQdJMTcwGWj4__PiX8,380 -openai/types/realtime/realtime_mcphttp_error.py,sha256=-Zqz0xr2gPs6peG_wC3S8qVgtEUJNrZm4Mm5BIvmZw0,301 -openai/types/realtime/realtime_mcphttp_error_param.py,sha256=GcmAMBvZVNrN9p_tneHPu_pyN7D8wCytaAKruFtMfwI,377 -openai/types/realtime/realtime_response.py,sha256=zaUF7moDzT5foAYhiqg1zALpA-4pxUCvy1ImIFprD6g,3903 -openai/types/realtime/realtime_response_create_audio_output.py,sha256=HSSmi2e3Xg5Cp5ONpBVtwVvCchSy0xyK6voM4LN-Xc4,1006 -openai/types/realtime/realtime_response_create_audio_output_param.py,sha256=ioIoPVwiTweGns-5sdJLOS-X7sPjhYSY5KsLRVwNSv4,1001 -openai/types/realtime/realtime_response_create_mcp_tool.py,sha256=lUpF8l6G9q2sMcxHY7LyQ9pzoZMmGygFtXhP_NT9vBM,5076 -openai/types/realtime/realtime_response_create_mcp_tool_param.py,sha256=HJ3UYYO-saxPWzfz4v9TvZCFNMu_gCGQ0OxDl6OC-rM,4979 -openai/types/realtime/realtime_response_create_params.py,sha256=kQ1B1iLiK7IS4ACTMtUvbj-toYGJ0d4yi-EoV6piXNQ,4348 -openai/types/realtime/realtime_response_create_params_param.py,sha256=J3ch3svShqtnVCeDcPF0hV7o1WbwjSIZP7WtV7PHEgw,4380 -openai/types/realtime/realtime_response_status.py,sha256=QjUdgjUKfX8tHVk-qRofl33vnjdoYzwTFhlk6knUGCo,1500 -openai/types/realtime/realtime_response_usage.py,sha256=atuMmLvzmTtH46RcOE7k3Br730ObjnkVBFL6x1BXWYg,1727 -openai/types/realtime/realtime_response_usage_input_token_details.py,sha256=Pt38MhRPUUhNGVN6nRShH750heUbbAlrYbKLPXcHHe8,1635 -openai/types/realtime/realtime_response_usage_output_token_details.py,sha256=3K2DIIvd92aJe9X38tSALn_t_-OyU4ivG3ckBXspkng,524 -openai/types/realtime/realtime_server_event.py,sha256=WkL6yNqJXjKbkhegGZr00_Uw84NVITGhV-zPlQdLGeA,8248 -openai/types/realtime/realtime_session_client_secret.py,sha256=oIOEWToHr1J_6e5VsDYA6xl7klWCaVoqWvoWVr4YDRs,629 -openai/types/realtime/realtime_session_create_request.py,sha256=ZrXWm3Vn7huXn52G_ctxSYNX99sSlqA0GejzQ863d7U,5365 -openai/types/realtime/realtime_session_create_request_param.py,sha256=toIWRT0Q2IV2cPYjNzKEeeiSbM49lvJH9qtmYv_Up0A,5351 -openai/types/realtime/realtime_session_create_response.py,sha256=P4MEjrOSicIGv2MmUbK4j8__noih8qxwZyIkT9eW43A,19935 -openai/types/realtime/realtime_tool_choice_config.py,sha256=DV0uuyfK59paj5NC9adQskUF2km5TRSiHAlMDu1Fmdo,472 -openai/types/realtime/realtime_tool_choice_config_param.py,sha256=0vqYNM4MkU5d8GXfitT6AoE9AubKeLZOSHGOH8q73QU,550 -openai/types/realtime/realtime_tools_config.py,sha256=JSxehiQnA_tJUeXvi2h9H6wlYsnhhtRWB_o5S20V-oQ,318 -openai/types/realtime/realtime_tools_config_param.py,sha256=ux7AlLllQQozenBmkr5dzGOhdUp3b_LD9TN_StFxtfM,5272 -openai/types/realtime/realtime_tools_config_union.py,sha256=u_ss-JAdDLzZ4qsF0BumBXi3s_0LOlTjLCEszdsdpVk,5333 -openai/types/realtime/realtime_tools_config_union_param.py,sha256=B6LRLV6jkDeeQAp5UtAi0QwFDTTKxZHZR2LrwM31Ubc,5159 -openai/types/realtime/realtime_tracing_config.py,sha256=gkG557bdUH4-kAoyH9TEFp12VJFwQkGfQkPDc4ESh-E,918 -openai/types/realtime/realtime_tracing_config_param.py,sha256=fo2An_bdLxQrCLhZ6d34vcxiDAHTj2BoxsTqoyT6yjw,887 -openai/types/realtime/realtime_transcription_session_audio.py,sha256=cUETz-wzN-6qaupdCF06nmLmgH846dp7zu_wGOyl-Ho,467 -openai/types/realtime/realtime_transcription_session_audio_input.py,sha256=Wd8Kzuu5dU7V4RSMj4rvnuIk0nBt0tCrlyQfYs7f6Y4,3377 -openai/types/realtime/realtime_transcription_session_audio_input_param.py,sha256=2Lbur4VMABLAZ8LDqiAWMTJUf4rlWEUXLiki18gG_iI,3429 -openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py,sha256=1j9-uzpvv-dt4D1jAqH-nbIIx7RwoZ3VnF6Kw4cXoIw,4300 -openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py,sha256=kmDzDtQAU8U6t9mmIMNz2pw5Mle06RMcpxACtCpnfw4,4131 -openai/types/realtime/realtime_transcription_session_audio_param.py,sha256=Jia_0_l0wqhrZDvY2WkR3koSHY2lL25z9ZlHcytXdFU,504 -openai/types/realtime/realtime_transcription_session_create_request.py,sha256=a2sXjIAJYePFHZ0SqC5Obi0EWO-YAgEW85vQqCK5Mkc,963 -openai/types/realtime/realtime_transcription_session_create_request_param.py,sha256=fRfSPuKXdxYJQbUT8woqTUReDUvQNVwXLsbMRH8NwiA,992 -openai/types/realtime/realtime_transcription_session_create_response.py,sha256=TAuRl80bsI_snH8ZkqCAGVTQC-WbgBLPpQ493onEjp0,2616 -openai/types/realtime/realtime_transcription_session_turn_detection.py,sha256=0eoBc3mWERrAO3coDqlMwDbfplCZ6pXJN_lRR_wSkmA,1270 -openai/types/realtime/realtime_truncation.py,sha256=lnr1Uq9kSs6OfJb_TcvQrs7jx92UuSKaIhGNvwUK-qU,380 -openai/types/realtime/realtime_truncation_param.py,sha256=wBXHiAPS_HA6MWBqhRGEtqZxu6RdIrgnTVRYgUljwq4,442 -openai/types/realtime/realtime_truncation_retention_ratio.py,sha256=EfcvUfo8Ul7EgqWpDsTpUTlZrmZXIO1LroTLhgOfibw,1749 -openai/types/realtime/realtime_truncation_retention_ratio_param.py,sha256=t6qlpaEmtc0g4PvyXH2wz8PewNmnI_WyeYSCkYVkiXQ,1766 -openai/types/realtime/response_audio_delta_event.py,sha256=1tXOxDJqpshq4EP7R62Fnhy1u2Wwqflzru8N5MlPaNQ,818 -openai/types/realtime/response_audio_done_event.py,sha256=9fdpuN-G0dQGsSfWJRXftoA9vY2JCQ4kGEbw0VNFo3w,837 -openai/types/realtime/response_audio_transcript_delta_event.py,sha256=fk3wI07iou7q7dTIDuJsP1kjPfHvj_5E_pUct70_TWM,873 -openai/types/realtime/response_audio_transcript_done_event.py,sha256=fLcAV1ckIpDJ-SxukAeLZvuhaZrzid1AU4EUItVmLWM,983 -openai/types/realtime/response_cancel_event.py,sha256=VEQcxB2cTEmItz_o5ubbrWbvxWjrH8DB9UkKeTSrYV0,1031 -openai/types/realtime/response_cancel_event_param.py,sha256=Uh6zrwrw0xxKQULpYj6kGAOysR48JYp-yUlJDoFyRok,1025 -openai/types/realtime/response_content_part_added_event.py,sha256=SBtIynUx0WKuuHgrhDfwfejRZe0Rb3oe_eC_mBMj0p0,1399 -openai/types/realtime/response_content_part_done_event.py,sha256=Y27ee1ZRzf9WYwsny6J0SS-Su9DH-YfG7dEGK_Ooc9U,1404 -openai/types/realtime/response_create_event.py,sha256=mn__Lnv3Fuf4_aF6ZPEzHIHIZoXX_jzTRHbxEqnrnto,2085 -openai/types/realtime/response_create_event_param.py,sha256=3hLwSZv8ROLu11eU17YgdR2A8XE5P6XVFbBMO5PjY40,2096 -openai/types/realtime/response_created_event.py,sha256=02IS6XqoTnQr9gvPhUimQ0bchMW3LmjtYbL7V6H6Xlw,669 -openai/types/realtime/response_done_event.py,sha256=Vt88mKQS72w7ysbkcU3yMxkIoYV4AoDyWqxeth1rJj0,1053 -openai/types/realtime/response_function_call_arguments_delta_event.py,sha256=hceOwsJTdQ_vW8wMPebwj6tkt0nDPYbwCpWPs76nmrQ,874 -openai/types/realtime/response_function_call_arguments_done_event.py,sha256=orgPc3_ACCQhqXihyZwi04t27D4l8Llz_fuyZABu7TY,966 -openai/types/realtime/response_mcp_call_arguments_delta.py,sha256=STwpfYmz3P6m-IwlUkHbI9rfauQn2HrmwNprY5NMaP4,920 -openai/types/realtime/response_mcp_call_arguments_done.py,sha256=3nZoOA7m2Bj1JyMPTwhiqIvsLwb8UBnFUVGZ5KviNmg,799 -openai/types/realtime/response_mcp_call_completed.py,sha256=8SfUc0zoVadfToShvtxw_wQ-wdh1q0aw68TSdS07fAE,633 -openai/types/realtime/response_mcp_call_failed.py,sha256=--MvtTO4ZANb5uYa-L9aC-PCdttglgUWyfzVvUlAqjU,605 -openai/types/realtime/response_mcp_call_in_progress.py,sha256=MK2m5lYcsKStDptN0fhVxQAn2hHZwSBD7KgzdIv0RJM,643 -openai/types/realtime/response_output_item_added_event.py,sha256=Wnbnn423eTc8iY1vFMGPghz88VCt7WfmTBIM3ErrD1U,796 -openai/types/realtime/response_output_item_done_event.py,sha256=foWLMOSv67skqeGLfOmuYGgABmMQnoLNGiT5ZmmmGIY,854 -openai/types/realtime/response_text_delta_event.py,sha256=1I5yu-_1ifZaNWvW9qzyMtOowUYjUyFt_JDIRSJGl1U,819 -openai/types/realtime/response_text_done_event.py,sha256=55fRkCAPSocN9iadkJeowE2-3laFjAAZwLa9WCNsXJA,914 -openai/types/realtime/session_created_event.py,sha256=vcxq7m7QFXsoLHiNRB6_Oh6zzxTUyfpB7ogqAUo4Lzo,980 -openai/types/realtime/session_update_event.py,sha256=R5YvfGKxhk0E4b02kQbYbg9MenVbUf-q-ZEHL8Gf5m4,1735 -openai/types/realtime/session_update_event_param.py,sha256=uSxqGmfwGW0raKiTkMFwBuPkTxEsDu-L8I1IR53530M,1807 -openai/types/realtime/session_updated_event.py,sha256=Zp9HaAopCZ1mdpt8BGp8t7JA5J4o3Cm_FbIobqvJhpM,887 -openai/types/responses/__init__.py,sha256=DOdOxzHyOleFM6lEY18XMz1hbskIXwEjuQnmApXJJ3M,18173 -openai/types/responses/apply_patch_tool.py,sha256=gO_CtGczaXdBPe8zSW-aEqV_dVJhn22GAh9AE4-xEq4,399 -openai/types/responses/apply_patch_tool_param.py,sha256=k3kqGLeZ_f9vyXh7ZMmYVeQ-xcVUbGmo4ZAqM9HhgzI,455 -openai/types/responses/compacted_response.py,sha256=qlkdM6GmpFWCcqU11xODEMqD16DinPF0W-o70Hg5VOk,934 -openai/types/responses/computer_tool.py,sha256=ExJaomK4IFKSprXIaQju1nGVi2CWNXV6QvDyrvNV7Pk,767 -openai/types/responses/computer_tool_param.py,sha256=SvgG7R0e63WUd20qbImia5VnEbJKjYPW7YF4F4G26QM,853 -openai/types/responses/custom_tool.py,sha256=3T6L-3w8A7TyPFcsw5_zYXNraP4nPbShg6lnoVt3K40,923 -openai/types/responses/custom_tool_param.py,sha256=hdnZol_ta8KGMlolyBsTY9RuwYBf4NyxDr1QK5MJwiA,935 -openai/types/responses/easy_input_message.py,sha256=VDVZoLHoRrgfSgBNlQM6rmdqFjzSD8I7n6325sQdmFo,1168 -openai/types/responses/easy_input_message_param.py,sha256=uK5_Oo_8iTJbUG9w8-hujQmfsH5lfepCpTNUgcpcU0c,1224 -openai/types/responses/file_search_tool.py,sha256=HpPWubu_JTVOxtRefDRDZkhTtWfoekHCqiL6B702j9w,2259 -openai/types/responses/file_search_tool_param.py,sha256=CvxYOB2DFpRC18WWa05En3heqTNd9Lv2SCZ7uP-ZOG8,2329 -openai/types/responses/function_shell_tool.py,sha256=nkYhOasTJYmE2CCJ8la94cadqThV4EdgVrB5-Fr3ecs,378 -openai/types/responses/function_shell_tool_param.py,sha256=wBsstq7T75MJRucaLjvHpTBdy7H5Ex-ExmoSyAugKCc,434 -openai/types/responses/function_tool.py,sha256=XatrZMskh15WXVnDmYF8WcxrMnt9Di6u-W5z_tS8Las,978 -openai/types/responses/function_tool_param.py,sha256=YnvnWFZijbVnEeoaruUBGidPEPhLRnNXnpZ8Pp3yrnU,1043 -openai/types/responses/input_item_list_params.py,sha256=wazm2tELpbpBWdAQrXGBq88Bm5RsxWXmlVJAV3f_k-I,964 -openai/types/responses/input_token_count_params.py,sha256=s_KKPE-q6j4KU_0DoIi7hVHQNQoykxdP7MaJYW0EB-U,5668 -openai/types/responses/input_token_count_response.py,sha256=w8LogkiqiItGuty0-bXts8xy1Ug-bbSYKEm7DDKmoP0,310 -openai/types/responses/parsed_response.py,sha256=65aPRFaHpbX81f23JesWawUZcK3uGsY2N0DRbn3_rSk,3846 -openai/types/responses/response.py,sha256=yehCZVZjB_DKbaSdSpChPbNNfOVwYhb-HU4D4ZgCThA,12591 -openai/types/responses/response_apply_patch_tool_call.py,sha256=dmqjz9eTdk5WNkxxWhuJayZ-ALygsPXTosRW6B9r4oQ,2217 -openai/types/responses/response_apply_patch_tool_call_output.py,sha256=Y3ZxBSHXFAv1yaUfpf_XOFZwvAgSKiBB6Bw8fOYEsvw,1024 -openai/types/responses/response_audio_delta_event.py,sha256=JWICz6tC6Zs-8Ax3y3hkUahWE2vxwJLLVguhDQJWzhk,574 -openai/types/responses/response_audio_done_event.py,sha256=8wQI1KQcdEBSC7_IGWGVgHfjEWSaEEwTdOglsyj8dWo,470 -openai/types/responses/response_audio_transcript_delta_event.py,sha256=ekRu3IEU7rZRzoSFu2K98btqFDm_vz1aunOl5Q_WvtA,597 -openai/types/responses/response_audio_transcript_done_event.py,sha256=mP_kZAh8gDCQ01ekkygstR6F5oD-s-8Ycfb1ZRGo_v4,521 -openai/types/responses/response_code_interpreter_call_code_delta_event.py,sha256=nxweCYi0ARKFednUF9Hya8lyuLqc1VqKquYbB4fRqvY,924 -openai/types/responses/response_code_interpreter_call_code_done_event.py,sha256=dZl7A5ZEdN-fyJG-d7XbBdkQ-cLrlcEaZ5f5nzwPGu0,885 -openai/types/responses/response_code_interpreter_call_completed_event.py,sha256=rUQ3-3KER-MRvNgUPuUyv5q6o7KsWqsQWZrjFzDscmE,823 -openai/types/responses/response_code_interpreter_call_in_progress_event.py,sha256=gC-u3RAQ08IcD9p2imVX27goYwH-HvukhScwLVORMfU,831 -openai/types/responses/response_code_interpreter_call_interpreting_event.py,sha256=gOWRUvIgcMVrp-KcmtAttp8PbeVknhmCmfgYg04-2K4,862 -openai/types/responses/response_code_interpreter_tool_call.py,sha256=r1NjHpBWawfNwy5-2gVoJjc1rjrHk2jJjlGsoAIU55I,1795 -openai/types/responses/response_code_interpreter_tool_call_param.py,sha256=uaywHPXN7U5uh9b7bi5xFL6xvXRM7lTJihYdZbi84Zw,1868 -openai/types/responses/response_compact_params.py,sha256=vO8L88q5sVvGe9tfbVxholqvnfflsHV0Im-QUFTYyIY,4783 -openai/types/responses/response_compaction_item.py,sha256=FevR74gnDtJkGYJKhwaPHUMqDXkHxpPojBBgip93NK4,758 -openai/types/responses/response_compaction_item_param.py,sha256=cCRvAVU1LSLWhryYp54lU2j00wwHiaogpDcXBULI3PQ,673 -openai/types/responses/response_compaction_item_param_param.py,sha256=UYpgNuwAxAd11LxXJJ-EPHGLWR3TDP00lylHxytE6K4,732 -openai/types/responses/response_completed_event.py,sha256=fe5mGXdeFLkozUpasDitkCHe7Qv22xKUesRDNFcXazY,573 -openai/types/responses/response_computer_tool_call.py,sha256=PwgncJ5PbXv8PfNDYT5F1xP7sWDPaPQrEKKjDllE1Ew,5276 -openai/types/responses/response_computer_tool_call_output_item.py,sha256=4ezZAGHMVIe88MQRCVprLbhzOFvVv7mu7eQ2NLukEew,1584 -openai/types/responses/response_computer_tool_call_output_screenshot.py,sha256=rhc-E2ECWZOqpvIFcVo7fi-j9rS94AwXU_1xuVyUYKc,734 -openai/types/responses/response_computer_tool_call_output_screenshot_param.py,sha256=iRdRiNE-wpwaNhBfnilJ4GaouMGh-oWn121LkSzDBA4,728 -openai/types/responses/response_computer_tool_call_param.py,sha256=O2IdaoOcDAsETrNu5D6n-ue_WKVLBJnJoCr9i4u6sjs,5687 -openai/types/responses/response_content_part_added_event.py,sha256=lpdjp8MXrniMjY5aEchgOXAYx9nCRzqsGcm10A7k9oA,1432 -openai/types/responses/response_content_part_done_event.py,sha256=QHR1gB9E8AeAxL30xp2pTVr8YQxEojwozkZqJ-s_45E,1419 -openai/types/responses/response_conversation_param.py,sha256=diMeoJm5-D3AideV9XtPNfd1gdRTyAEnYz0HeRXvzPE,399 -openai/types/responses/response_create_params.py,sha256=yPNDnw9d4oDPKSMI7RQp6fVO1hCQPm7lQoTmkvzkOlM,14008 -openai/types/responses/response_created_event.py,sha256=3q0JhFTkp3vgkkJdjFzgLG690GfDFFfnpXrsjl81ES8,566 -openai/types/responses/response_custom_tool_call.py,sha256=DhCtiuQYuyNm1c2DxSxLnqrDqiexmL4hsjCf7zXhRQY,787 -openai/types/responses/response_custom_tool_call_input_delta_event.py,sha256=70JVIwG8KfTnW2zzovAdDv-qIyvJU8cY2aQcxHiDPKw,786 -openai/types/responses/response_custom_tool_call_input_done_event.py,sha256=QQ8V5TNyMOdLRSQ1hxCCw2_LjxERccGqvXjjnUrvc_8,756 -openai/types/responses/response_custom_tool_call_output.py,sha256=w2yJcnkB48PfpBvLikpUx_Iz8ryKuS7WtqyqsECr0ps,1307 -openai/types/responses/response_custom_tool_call_output_param.py,sha256=Nr6hV5PHkOeDRR3INuiyPtpk3ybd4zwLbMKYEfkv1Hw,1314 -openai/types/responses/response_custom_tool_call_param.py,sha256=8baPSm1t7KXm8ABHUgdjw68vDf6yoNLY7scZyR1BX_I,828 -openai/types/responses/response_error.py,sha256=AszYOuu1LOWaglgKy9tX9zO9q7Yid9alJc2cKINk9ro,996 -openai/types/responses/response_error_event.py,sha256=fjB964eSWEh0ciSk5s64TQGJyTsYjtNT8duSqztjhW0,617 -openai/types/responses/response_failed_event.py,sha256=FG812T2EKLJwrSyO8KPbs-QSpsg1e4n8YHpXiANlb04,551 -openai/types/responses/response_file_search_call_completed_event.py,sha256=gE4Zju0_edN_9zfOc07K7BepToGCjdOIBvqQx-jwfqM,744 -openai/types/responses/response_file_search_call_in_progress_event.py,sha256=0SKVai4oBjI9ayOjSZw4HlX5Alsm1QOUEe_UEM8EedE,734 -openai/types/responses/response_file_search_call_searching_event.py,sha256=h39eY-lBOJiN-9M1xKdbsij8nVe7CoJHRq1ncE4Djog,733 -openai/types/responses/response_file_search_tool_call.py,sha256=kz4aytPWtfajEkJjtxW395Gy_IZC90uSQr0gcFOqqPw,1838 -openai/types/responses/response_file_search_tool_call_param.py,sha256=rnHg_KmMbyduAwzE1iC6QcenZSMtAmrNq1r9hojH75M,1911 -openai/types/responses/response_format_text_config.py,sha256=Z1uv9YytZAXaMtD_faYD6SL9Q8kOjSvRQXFkSZc0_hY,647 -openai/types/responses/response_format_text_config_param.py,sha256=T6cMHds5NYojK9fZMMldWYBypWwVmywIIbkRm5e4pMc,625 -openai/types/responses/response_format_text_json_schema_config.py,sha256=qjE8Yx2p7fT2KUoEtlwEbgqqV11FwdWdmXdrEsEUAP0,1611 -openai/types/responses/response_format_text_json_schema_config_param.py,sha256=kmkEvymu058oqJngIz5ir0XKTDGbfRbc6G2GKJWa5SA,1593 -openai/types/responses/response_function_call_arguments_delta_event.py,sha256=EKF5hkCH9qMKFzVhIxatJJiXrcyG8HGByep0hi5h-w4,866 -openai/types/responses/response_function_call_arguments_done_event.py,sha256=483jGS7xNW-VSivfrgFCox5WI9AXakYRN3KaTVZ5Zzk,702 -openai/types/responses/response_function_call_output_item.py,sha256=mkRJ2mCmrrmjRbvijxt-zHw9eLU6-aLjM6___SmTiTw,633 -openai/types/responses/response_function_call_output_item_list.py,sha256=5NYWEt_FNPCyQVRMiIJDJt4fYV6GWUwbW9S8hCucIpw,367 -openai/types/responses/response_function_call_output_item_list_param.py,sha256=y6vpVbdTGurYpDVbg0UFp4GhSMtwYRium9Z5bbiyyuE,774 -openai/types/responses/response_function_call_output_item_param.py,sha256=VEe_wQ8z9PN0qJbLuCwfg9n4Lwe5-WNljzmNJ-fqnwM,629 -openai/types/responses/response_function_shell_call_output_content.py,sha256=QZlIb_3DHE9BX5W6HmdDEY14Vwy5c295707BzgH1Z_Q,1260 -openai/types/responses/response_function_shell_call_output_content_param.py,sha256=e8nFAciWLudLRQxr-CNH8U_9Nge65cZ6M1d-ZqE_h8g,1299 -openai/types/responses/response_function_shell_tool_call.py,sha256=0kGBz7g4SZOnSAoU3-yjMeOXM681abrTQ4EFRs02quY,1395 -openai/types/responses/response_function_shell_tool_call_output.py,sha256=rj1An1t8_Wz39jDqIGt7mzko8D4CX99qg1r-x4TKZuQ,2263 -openai/types/responses/response_function_tool_call.py,sha256=Rf1IGPksyVcGFSOMPJuj5h0h7oJs5UQEKiwRYZ-R0Sc,1086 -openai/types/responses/response_function_tool_call_item.py,sha256=aiw34m4uKx8J_Lk33SZ_oqENRKm3m72q-8qiVrgNykk,509 -openai/types/responses/response_function_tool_call_output_item.py,sha256=F8lyiugcU6q6tG9kJUpTnF-g_xGBWgIje6mTYMErXL4,1394 -openai/types/responses/response_function_tool_call_param.py,sha256=L6T3MtKCuaiUDzK8YaJZRysMEADbuWBrqJrUpSgoSAk,1110 -openai/types/responses/response_function_web_search.py,sha256=LtyQ1svmci8bRs36fexPL9aFq008zuH-LBwAap0s0Jc,2307 -openai/types/responses/response_function_web_search_param.py,sha256=QjDva_BhIuapFyCnuOYdefVAGvrGm0g0_78ByQ3NWEs,2481 -openai/types/responses/response_image_gen_call_completed_event.py,sha256=4EVne_sRTbCxuPTTdt7YMRBblpH8nR3in4PkzzrHxBE,783 -openai/types/responses/response_image_gen_call_generating_event.py,sha256=Xu-lJZAHRZTDbiOGRVOBLCmXnAbHFQBYNRmPab2pFug,824 -openai/types/responses/response_image_gen_call_in_progress_event.py,sha256=LvCFXfC7VNqmZegn_b4xy021H-qO08SzGOspvK-6Wew,778 -openai/types/responses/response_image_gen_call_partial_image_event.py,sha256=Iss5tU9uBlv9qdnLMsnRh2g0rRJL5BDW04TTUHD8Shc,1059 -openai/types/responses/response_in_progress_event.py,sha256=oi8YtsItiH0TloP7rbkm0-XOY1-FKTV4o6Ia_y4pS6Q,571 -openai/types/responses/response_includable.py,sha256=tkia-hgFh4ttgy53H5lJtoBWsSQh6G2DzCXj-14o8Ko,505 -openai/types/responses/response_incomplete_event.py,sha256=WGBjWI-kwdaQpGBqzrIKfTehJ4Phzxsn2fvfDYoTV6w,592 -openai/types/responses/response_input_audio.py,sha256=CLnaiuQjjF11emjSxbVBLL0yF_kONznqXgIB6m8lric,614 -openai/types/responses/response_input_audio_param.py,sha256=MXXWtLXdToypWHQYLSpfUXtC2U_PllaffzJLMy5LNYY,713 -openai/types/responses/response_input_content.py,sha256=MaZ-MNnZvhM2stSUKdhofXrdM9BzFjSJQal7UDVAQaI,542 -openai/types/responses/response_input_content_param.py,sha256=1q_4oG8Q0DAGnQlS-OBNZxMD7k69jfra7AnXkkqfyr4,537 -openai/types/responses/response_input_file.py,sha256=lgoRiDEn_dPiga4dgHZsHcjgbzEAftmhwSnloBVTQuo,755 -openai/types/responses/response_input_file_content.py,sha256=SdUicUGXlg_OICLMdySuJLTmmU0WDTywjRIWFVEYOwg,781 -openai/types/responses/response_input_file_content_param.py,sha256=F2cwpQbEZtgt4p4dxs7zl_2mM7rB9OsNjbbLMRq8WV4,809 -openai/types/responses/response_input_file_param.py,sha256=TFYJQXKEOWB3cdiAIVkRrMgeO_-ZjqNUAidCl7KKwK0,753 -openai/types/responses/response_input_image.py,sha256=djDER2-m43vk1YaX3GXF5dNg9W-vYF26Itto5kQtNYs,904 -openai/types/responses/response_input_image_content.py,sha256=0fVlJtV-LnTYP51zwqcBkKyyDdCq7OZQZkFcbeQihjY,934 -openai/types/responses/response_input_image_content_param.py,sha256=Lf0hJTLtG0CRvtKt6Yb_ldtbcUge5IP-wK-_UjoCdn4,969 -openai/types/responses/response_input_image_param.py,sha256=lxWoE5udEUHohLRw9KtfNTcwMuabydqQy1gxZ7oAtqk,956 -openai/types/responses/response_input_item.py,sha256=LmxxV68vNIfspCf0l13pnRnZI8lXMtsfpjddxiT4t1c,15925 -openai/types/responses/response_input_item_param.py,sha256=BaA20QXJmRpcXSxVd5Z9bMVD_GI9R4KZ6pUoodzbPRI,16693 -openai/types/responses/response_input_message_content_list.py,sha256=LEaQ_x6dRt3w5Sl7R-Ewu89KlLyGFhMf31OHAHPD3U8,329 -openai/types/responses/response_input_message_content_list_param.py,sha256=cbbqvs4PcK8CRsNCQqoA4w6stJCRNOQSiJozwC18urs,666 -openai/types/responses/response_input_message_item.py,sha256=_zXthGtO0zstLvIHg9XesNAme6yNa8JOejkBYLwXm70,1029 -openai/types/responses/response_input_param.py,sha256=EgiARo-Co4lsATiwFkntXs1OrGV8IQ_RNhYRbCr2Ndg,16787 -openai/types/responses/response_input_text.py,sha256=uCT-nKv5EEjOHmTyBlKJ01gLSCGue8lcjrBwzwWzPrE,413 -openai/types/responses/response_input_text_content.py,sha256=UPb4d4KHkbgN0rS6wkvoaTPZVGN_2aYo-VbL-zwMkpU,427 -openai/types/responses/response_input_text_content_param.py,sha256=nAOZRT6FsZqPr0va99wAFVB1lz5W8cinZ-9iEuAHgN0,493 -openai/types/responses/response_input_text_param.py,sha256=9DbrdxWlak_wHmcPhw9BIVlyWkBnuAfmYC4TDtM_Lqo,479 -openai/types/responses/response_item.py,sha256=hGxb4N8Ue0bXbnDQ9Oqf2TStEhboo8_Cbiga2Ve93QE,7357 -openai/types/responses/response_item_list.py,sha256=JclJxBBJda7fjXVbeLfYeVUH8A_swQN24LWpUjIsuus,702 -openai/types/responses/response_mcp_call_arguments_delta_event.py,sha256=EUCaFYd-EgZS9zikqlXi8xqUzeC94MzVx2qrhUgm4a0,884 -openai/types/responses/response_mcp_call_arguments_done_event.py,sha256=LWMaw5HKV8AgiYNJxTB-14kmCcFc_T22tSCdqJjlp3Y,826 -openai/types/responses/response_mcp_call_completed_event.py,sha256=MFjkI21vxzlTzvEAvmRjntJ3vGCeDTViMFek6AIyQXM,670 -openai/types/responses/response_mcp_call_failed_event.py,sha256=bhC0gZ4b2qZPrux4Le6_ZDthm22Ck1wGZ6G5Mf0wsPQ,636 -openai/types/responses/response_mcp_call_in_progress_event.py,sha256=oTLlZyhdLsnnkZj4Fr3WYF2QRnupgdT6_4FIVl8gjUg,696 -openai/types/responses/response_mcp_list_tools_completed_event.py,sha256=3OdrqmMVVUgVTwl2nOf5vQ-4VVcbfS6VoF3G7z5DOjU,726 -openai/types/responses/response_mcp_list_tools_failed_event.py,sha256=9nvFQ-02kRXV6nOf_4o5aQhYw7-tSzppLbN-C7a2zHE,680 -openai/types/responses/response_mcp_list_tools_in_progress_event.py,sha256=V9IqBnh-oLKqtthuGA3LDNveWzx10kd2N6x3MpzATzM,756 -openai/types/responses/response_output_item.py,sha256=mYMzKnpJLEQqIQCEZp2FU29QhdWecQHVGsOM3h1Gvig,6101 -openai/types/responses/response_output_item_added_event.py,sha256=6rIwK1Dtgu2K0t1R2ForK1C70CUpcnihqMpWqlM0jtg,696 -openai/types/responses/response_output_item_done_event.py,sha256=n-T9NinnYm0xhOmPfDhqKso0JQYVhfs0IXa1MhkA2cc,707 -openai/types/responses/response_output_message.py,sha256=OkOnbst0qUMmnFDOwKgPbK4Ii7JLxoKYV-9aLOrYNHI,1149 -openai/types/responses/response_output_message_param.py,sha256=YwLkQ0QRwWyon_RMzA09uQbqLO949cIpQZwlUQUIWpY,1193 -openai/types/responses/response_output_refusal.py,sha256=VkWPvAhqWz3mZ_7X8CZA4CPjgCfkWpAsrUL_EEAp3mY,425 -openai/types/responses/response_output_refusal_param.py,sha256=RO2CI71fbzQPwsr3URyR-EP20oRNMaWAmLj9dMDeu1o,491 -openai/types/responses/response_output_text.py,sha256=LPESiPQE6UcQFa1bHRFr-Dxsvbyqc6UoCDsauGDAev0,3157 -openai/types/responses/response_output_text_annotation_added_event.py,sha256=Eg-nDtkqOX51T-kJOjUFVd_2vnnk6Ah1rE3lCdYe3f0,1034 -openai/types/responses/response_output_text_param.py,sha256=3G84IlzqWmex9echpQUFApOWLra_oWvwbBiweX6NFtU,3460 -openai/types/responses/response_prompt.py,sha256=YYeJIp7WbLKe8Y1EieKpNgRHSIqArcx9OdSBeAInPRk,1107 -openai/types/responses/response_prompt_param.py,sha256=n0Kh9RsuVkgfFlll_fwaSPmQ91iJoJXDEX2yQw97eEg,1198 -openai/types/responses/response_queued_event.py,sha256=yr1KhJ27RjkFrKFmTx1uncSpR5t5-RHEXOBTyFaazUc,582 -openai/types/responses/response_reasoning_item.py,sha256=Rxg9gZDFhwR_eswynvNae2NCa0BYGCqB0OkijLwfl8A,1843 -openai/types/responses/response_reasoning_item_param.py,sha256=rKLmJVQdld2ZNlo6VylJmeyScXGE3aRPF9gUiYj5UbE,1956 -openai/types/responses/response_reasoning_summary_part_added_event.py,sha256=z6fdUEOQYdkbM2Kbv-qR39uqLScYWHozlZc43AaUy_U,1113 -openai/types/responses/response_reasoning_summary_part_done_event.py,sha256=IVAfLcKqV0tN5DlcHoWj-7kgHPCJIZuRO2tjautGVag,1099 -openai/types/responses/response_reasoning_summary_text_delta_event.py,sha256=dtVBDqeHnL6rqfKkqS9S48iEG40XeL7HPHedYvAtPfo,916 -openai/types/responses/response_reasoning_summary_text_done_event.py,sha256=mKK-nrU1DChaUyRYLw0hKChMvYovs6e19ZChJDuW69I,896 -openai/types/responses/response_reasoning_text_delta_event.py,sha256=3_UV-GjQdCNjqpmABpDrxovTKqQIyJa_K5fKemPcezA,903 -openai/types/responses/response_reasoning_text_done_event.py,sha256=M9AZZ7cHvXj4NthBIsYEbY2h_RzFcn2YJ37_mXd_Q9M,843 -openai/types/responses/response_refusal_delta_event.py,sha256=nqAEXShLQDV84Qd2pr7po-UnzW3aJxgXCNNivmJHQOQ,827 -openai/types/responses/response_refusal_done_event.py,sha256=y-Dtjpa0CCA0hqqC8O_m5tRqKoSJayhYpTTBFDXOvK0,826 -openai/types/responses/response_retrieve_params.py,sha256=Y_4UacCQ7xUYXc7_QTCJt-zLzIuv-PWocNQ1k0RnPsw,2372 -openai/types/responses/response_status.py,sha256=289NTnFcyk0195A2E15KDILXNLpHbfo6q4tcvezYWgs,278 -openai/types/responses/response_stream_event.py,sha256=uPEbNTxXOaiEFRVt_PbdeecyfS9rgjaYU7m15NIvSbo,6916 -openai/types/responses/response_text_config.py,sha256=8mk0TYDQB9VNJxKAazvCHy3WIzOpPgmn95qLkwToK6o,1655 -openai/types/responses/response_text_config_param.py,sha256=Wq9RvKd2ZlOBRsTaUxWRmSekcQxH8mMoYJZGp2QHY30,1684 -openai/types/responses/response_text_delta_event.py,sha256=fdEVcZTuoTzxIhFwcp48YPUTdEHXwI4ocSwDM2kfcEM,1689 -openai/types/responses/response_text_done_event.py,sha256=KbaXsGeQvNJTGN8vOpEaA-_mGBSr6Viv-9rEAFrY6zw,1687 -openai/types/responses/response_usage.py,sha256=g1YqV35FbWEsFkDyXyQ95gK1CPT2vXaEj7dx35Nyllo,1204 -openai/types/responses/response_web_search_call_completed_event.py,sha256=huESBkfYVrHZUHUHeRknBgw7bMrIYEsVryEZrXHMiGc,754 -openai/types/responses/response_web_search_call_in_progress_event.py,sha256=MQIZTtd3LqdX4C46cG-vOSeNaLxQFvM2FaCfiDwUits,760 -openai/types/responses/response_web_search_call_searching_event.py,sha256=UucDvOvM6VjzBgCkwVO-UvRbttfidcBVCQdvgw-NUJk,754 -openai/types/responses/tool.py,sha256=UtSKlLaCHSaHCEj8KIgqzgnxZZSgaHG55zRmF7hkJqk,9895 -openai/types/responses/tool_choice_allowed.py,sha256=Mq18Us-Yd-59WZppbXaWYjBPtUqSbHHE48IWCHdLFCI,1100 -openai/types/responses/tool_choice_allowed_param.py,sha256=6Yk0zOe8QGzTyrReDIEy56o3opFvPbS0FeuBN6DW8CM,1184 -openai/types/responses/tool_choice_apply_patch.py,sha256=zUFufN0Okg40AkOM3QmzUxtRX4DQKwR52fYQYdQDECk,404 -openai/types/responses/tool_choice_apply_patch_param.py,sha256=DVgCdqmlWw1hMyDigUfUU8O7R7nQahuPqEYL6rq2y24,460 -openai/types/responses/tool_choice_custom.py,sha256=W-rAidO4Rf7Hf-EE-K_hIJwjPiiASxo5Vt7t8wQCFSA,460 -openai/types/responses/tool_choice_custom_param.py,sha256=SygHwvYJsXDSPAVjsxWqioSZd0Gc1oayMlbZUcR5BlA,526 -openai/types/responses/tool_choice_function.py,sha256=ZmF4VEQWTEcLrj7IEBqVX8kQv5Mf_sf0FJDffs0uIog,459 -openai/types/responses/tool_choice_function_param.py,sha256=RfRfJNf27JsZBNYjabLnFgksPFZJIrkdy3ouVGdNrF8,525 -openai/types/responses/tool_choice_mcp.py,sha256=z3k0i7zbJyp4DBvKs-OsvWdMOFrm0CNSgCyB0nEqnBE,585 -openai/types/responses/tool_choice_mcp_param.py,sha256=-cnA3zk3wMmx93CkCwwOBiw3CROD2UanAmdQm__Gow0,644 -openai/types/responses/tool_choice_options.py,sha256=gJHrNT72mRECrN7hQKRHAOA-OS0JJo51YnXvUcMfqMQ,237 -openai/types/responses/tool_choice_shell.py,sha256=5k4381juLRA_qZc_h4x0DGtnW6wkSKAogWfnYLMEPxk,378 -openai/types/responses/tool_choice_shell_param.py,sha256=Qy0ySbnh_0eDYPJwzn5iHoHHuo79HAHwkk8zRhNYtdY,434 -openai/types/responses/tool_choice_types.py,sha256=djkzycVSxYunU9WIGeRbS6nZa-tjEsSEtI2r1MwzMG0,923 -openai/types/responses/tool_choice_types_param.py,sha256=tuaS5Azelo0hDgpjBjZprfwjZKfmAcFT9zLq2QIIBik,1021 -openai/types/responses/tool_param.py,sha256=U6cO_JJY9YxrHdMou1yxDqOWX16zMif8rFUuf_vyW7w,9870 -openai/types/responses/web_search_preview_tool.py,sha256=jJkDvIC9p9aS5TAoLFhP5oW0sVVZ0m2FOqs-Bv_r_zA,1690 -openai/types/responses/web_search_preview_tool_param.py,sha256=Nmk4AtPCKWMXFNwQCfSh6yfT1JT46xTWAsCodri2BVE,1717 -openai/types/responses/web_search_tool.py,sha256=rsN2LrO25vAvIVEl3sKCiLS5pAqvwxJyam0Cgys419g,2083 -openai/types/responses/web_search_tool_param.py,sha256=pXX6qVRcsVNBDhy91nHM0svtpzvKVoAPIg7ciOXmctg,2124 -openai/types/shared/__init__.py,sha256=EVk-X1P3R7YWmlYmrbpMrjAeZEfVfudF-Tw7fbOC90o,1267 -openai/types/shared/all_models.py,sha256=OggdrF27d8_oCWAsE-LyQQmtjflAesmOyogIvi-atAs,716 -openai/types/shared/chat_model.py,sha256=sMmuHjOzYGegtDSqONSt2HXKYLuG66ncZRMFmeXuCTI,1957 -openai/types/shared/comparison_filter.py,sha256=9mpikD4dkjYTWni13i7VBKnfGUWJMIcug4PFWGaMGfc,981 -openai/types/shared/compound_filter.py,sha256=Dk2EVAI9kgojEKyeaXnIsu93rz8kKPERW0y5Y9LpdzY,638 -openai/types/shared/custom_tool_input_format.py,sha256=qgYtTA-5KQssG4TCdI2V2s83GcNQHhHczjSQVj4oIhg,856 -openai/types/shared/error_object.py,sha256=G7SGPZ9Qw3gewTKbi3fK69eM6L2Ur0C2D57N8iEapJA,305 -openai/types/shared/function_definition.py,sha256=2F07J5Q7r2Iwg74dC5rarhwWTnt579Y5LUrNc8OdqSc,1475 -openai/types/shared/function_parameters.py,sha256=Dkc_pm98zCKyouQmYrl934cK8ZWX7heY_IIyunW8x7c,236 -openai/types/shared/metadata.py,sha256=DC0SFof2EeVvFK0EsmQH8W5b_HnpI_bdp47s51E5LKw,213 -openai/types/shared/reasoning.py,sha256=SnHlaG2jXpvgvUQ_d7Gp0WPcC8tG3AtGGfP7B357rt0,2011 -openai/types/shared/reasoning_effort.py,sha256=1t5QFutihQBbHg0rbwsCCmfLs1wTT7TPDyH5iUIvVSo,296 -openai/types/shared/response_format_json_object.py,sha256=XXcdZ9Sx6o6gTrF73MayEITLmCtnnwo-HjjI7dbnzOg,624 -openai/types/shared/response_format_json_schema.py,sha256=Dujs9kHbLPk1dVIcMEerJ54OLyDC3svF_aXaX5SaRec,1843 -openai/types/shared/response_format_text.py,sha256=klc3lCY1T1M-lX6Dd6MnMUuNZH2sxoZqZcRymDrahlM,395 -openai/types/shared/response_format_text_grammar.py,sha256=zjIlUfFTCfAyLCc4fmiV3IA-q1Rjcjzui97bCSVV2NY,606 -openai/types/shared/response_format_text_python.py,sha256=hWrzEgdP1hUAX80Slc-UddodqFE3HDEWM8w0T0tADr0,525 -openai/types/shared/responses_model.py,sha256=Ot5_u8itwSMhVUhZ8rHnt5Bdj2eI_Ux76WHQ8xKHt7E,726 -openai/types/shared_params/__init__.py,sha256=Jtx94DUXqIaXTb7Sgsx3MPoB9nViBlYEy0DlQ3VcOJU,976 -openai/types/shared_params/chat_model.py,sha256=EcH6f6e8-ylkT206MlIK-nrk1NbfbIkirDYuMKR6gWE,1993 -openai/types/shared_params/comparison_filter.py,sha256=xtHLwK5uBnkRyecsqrbjYXnlHPoB66uf3wJyGUjR3DY,1089 -openai/types/shared_params/compound_filter.py,sha256=kpjER_a7NZT4rvAHxEj3hd6CgF_JHgBFl5WI9-HBzkY,703 -openai/types/shared_params/custom_tool_input_format.py,sha256=uv6tIPrdbzJ3_erNTbz7bDjVbMzAi8o22QG2wOhpRGQ,852 -openai/types/shared_params/function_definition.py,sha256=6JjuRmXIofTv76GCC4XFssqgZw-iKbBazjWqKerfq6Q,1510 -openai/types/shared_params/function_parameters.py,sha256=UvxKz_3b9b5ECwWr8RFrIH511htbU2JZsp9Z9BMkF-o,272 -openai/types/shared_params/metadata.py,sha256=YCb9eFyy17EuLwtVHjUBUjW2FU8SbWp4NV-aEr_it54,249 -openai/types/shared_params/reasoning.py,sha256=wXoF46cFeHImN8acwAJ8DRzsPzuI_2zqteLW47OdZIY,2025 -openai/types/shared_params/reasoning_effort.py,sha256=CjSzyuVxoslnEBq_vQt2WWsVVgPe4jGjoHYu6chpGx0,332 -openai/types/shared_params/response_format_json_object.py,sha256=eEG54vILrwf5es7h1vja1zlyKOQiRy9zstuQicW2NLg,670 -openai/types/shared_params/response_format_json_schema.py,sha256=Rx2m7tbaMVWO0FQABF0B7jc8Cxo8_EmTq_tQwCX9XqU,1804 -openai/types/shared_params/response_format_text.py,sha256=zCKpz3Fl_w-EICrTTrarsBhxea_LvzaKG6J864zjF1c,441 -openai/types/shared_params/responses_model.py,sha256=r1tGQ9j25cW84o01POd2p74wb18DdSBe2OeBTJhVOc8,770 -openai/types/static_file_chunking_strategy.py,sha256=JmAzT2-9eaG9ZTH8X0jS1IVCOE3Jgi1PzE11oMST3Fc,595 -openai/types/static_file_chunking_strategy_object.py,sha256=MTwQ1olGZHoC26xxCKw0U0RvWORIJLgWzNWRQ1V0KmA,424 -openai/types/static_file_chunking_strategy_object_param.py,sha256=tUsAYwR07qefkjFgt_qNwdUDbo2Rd-k9Xgu9OvtK9EE,597 -openai/types/static_file_chunking_strategy_param.py,sha256=kCMmgyOxO0XIF2wjCWjUXtyn9S6q_7mNmyUCauqrjsg,692 -openai/types/upload.py,sha256=_ePK_A-Hxr0bctSI3PfiAiJh22YRZwWXsBt0xdEQIk4,1281 -openai/types/upload_complete_params.py,sha256=PW5mCxJt7eg7F5sttX5LCE43m9FX8oZs3P5i9HvjRoU,527 -openai/types/upload_create_params.py,sha256=uOXPb_sdZhCqoR3gSSvpb4RpZ5K_Ppl1oAmJGbIAT3Y,1689 -openai/types/uploads/__init__.py,sha256=fDsmd3L0nIWbFldbViOLvcQavsFA4SL3jsXDfAueAck,242 -openai/types/uploads/part_create_params.py,sha256=pBByUzngaj70ov1knoSo_gpeBjaWP9D5EdiHwiG4G7U,362 -openai/types/uploads/upload_part.py,sha256=A_6PT8ptLJtR-jbU1b11jlpnVNLE10Kwoh1U985j9Y4,677 -openai/types/vector_store.py,sha256=rbjldzgYE-1TsFvAeBQYSOJqSiSWISrhYpmnkJTVsL0,2633 -openai/types/vector_store_create_params.py,sha256=nMpX4sfgUug_D67MDA1bNSNKgc4tP26_SNp2aca8iD4,1947 -openai/types/vector_store_deleted.py,sha256=BbtnlZ0Z5f4ncDyHLKrEfmY6Uuc0xOg3WBxvMoR8Wxk,307 -openai/types/vector_store_list_params.py,sha256=KeSeQaEdqO2EiPEVtq1Nun-uRRdkfwW0P8aHeCmL5zA,1226 -openai/types/vector_store_search_params.py,sha256=Uglni3jSE8d8-4c7eKRlxxEsxFNnhzuGBlUBnYPiJvA,1301 -openai/types/vector_store_search_response.py,sha256=qlhdAjqLPZg_JQmsqQCzAgT2Pxc2C-vGZmh64kR8y-M,1156 -openai/types/vector_store_update_params.py,sha256=-RQr2LnJzmpI8iFx-cGSZK8hg-24mYx9c497xtN_36k,1293 -openai/types/vector_stores/__init__.py,sha256=F_DyW6EqxOJTBPKE5LUSzgTibcZM6axMo-irysr52ro,818 -openai/types/vector_stores/file_batch_create_params.py,sha256=rHysxuqX1vfxUqsIfaLYJMi4CkmMSJEmDWBjTb_ntdg,2707 -openai/types/vector_stores/file_batch_list_files_params.py,sha256=FPpQvCQI2skyLB8YCuwdCj7RbO9ba1UjaHAtvrWxAbs,1451 -openai/types/vector_stores/file_content_response.py,sha256=uAFvFDE_NVRzg0xm1fLJ2zEd62qzq8rPYko7xpDjbaU,367 -openai/types/vector_stores/file_create_params.py,sha256=nTHWG0OMqqLRjWFH2qbif89fpCJQCzGGdXDjCqPbq1Y,1229 -openai/types/vector_stores/file_list_params.py,sha256=AIzmNH1oFuy-qlpRhj9eXu9yyTA-2z_IppLYFclMtZw,1385 -openai/types/vector_stores/file_update_params.py,sha256=NGah01luDW_W3psfsYa3ShlswH8pAhC_EebLMvd925I,781 -openai/types/vector_stores/vector_store_file.py,sha256=uHAXG0fdkbeJHS21gWmXourPYlc4GyyXkdam-EENwtU,2431 -openai/types/vector_stores/vector_store_file_batch.py,sha256=W1VoZE_PaiiOxRKG3empVJfr22oc7bE14dL9jheMG14,1512 -openai/types/vector_stores/vector_store_file_deleted.py,sha256=sOds3FSmDBFhe25zoSAz2vHsmG2bo4s2PASgB_M6UU0,321 -openai/types/video.py,sha256=3jT9tcZYJDAA93XgdKxpMT2WgpzwYcxKmVj9pJweWec,1698 -openai/types/video_create_error.py,sha256=DZpLbIAIOXOaZDNZk1dyVYMZHuxu81xB34krRLF6ddU,415 -openai/types/video_create_params.py,sha256=xe09Ac0l_M_PsKFIAdw90jJfZIs2QePxu_x5Qw1oUvU,1015 -openai/types/video_delete_response.py,sha256=eiD7lHgtxXIl0sY-JzhrKzWfRFdiGne24LfPZ9tQIho,529 -openai/types/video_download_content_params.py,sha256=MXcSQOL67hzODH__CRf7g6i74hjXJG9I0zPIqqBjnlU,405 -openai/types/video_list_params.py,sha256=pa8Nd6-hrc2fF8ZQRf4udebbMXpMDEKDrAAH9niSlgk,550 -openai/types/video_model.py,sha256=fkUBLAJ37g6TOBcXZGUgAMUhNNCDtSYCoEeMWiw0iJc,329 -openai/types/video_model_param.py,sha256=TeQQgBVyDxOuVo5qibiJIS9qJObnCtjbHGZEuam-SZc,375 -openai/types/video_remix_params.py,sha256=cFh9Tuaa1HH-cWyScfHPlw7N8nU-fg_AW0BL7S1yjR4,346 -openai/types/video_seconds.py,sha256=HyRb-NR4sVEGe2DoYZIQGig4kOrbbFfRYiqVejAgFbg,215 -openai/types/video_size.py,sha256=H1o0EhMbmicXdvaTC3wL-DnghhXzB7EkBChHL-gqdbI,243 -openai/types/webhooks/__init__.py,sha256=T8XC8KrJNXiNUPevxpO4PJi__C-HZgd0TMg7D2bRPh4,1828 -openai/types/webhooks/batch_cancelled_webhook_event.py,sha256=1iE0xOSTWzU8FJD5ruqgZazkOdCjmBZ_PB9_4Gmif7Y,862 -openai/types/webhooks/batch_completed_webhook_event.py,sha256=XCFcMnvn5xosPWdUwp3sO8wi4zYNefHWc_z6btzdGAE,862 -openai/types/webhooks/batch_expired_webhook_event.py,sha256=wNL76DW5xg9Jm8hqpPP-X5GHz3_wajmoNwc0jufgXtI,841 -openai/types/webhooks/batch_failed_webhook_event.py,sha256=_GpPkiVIL7N4bySS74Px97-niWeDM3hdzcDCViL6j1k,835 -openai/types/webhooks/eval_run_canceled_webhook_event.py,sha256=ZJkU4lAyr05OB-9t12njluzBmel81MbvhbSnOO2-L2M,840 -openai/types/webhooks/eval_run_failed_webhook_event.py,sha256=SbvytOgYKaIM33ud9pFLPjafUmRNAWF1juqAa-PLisI,819 -openai/types/webhooks/eval_run_succeeded_webhook_event.py,sha256=-ZZ3cfwXa4r2uyTrwPLvUxIQUZ4sjqTwdF6R2WE6fok,837 -openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py,sha256=IDUIOsMJqJTqE9AHOx2VNextcyWFkQcP2xTZ09bAAlk,892 -openai/types/webhooks/fine_tuning_job_failed_webhook_event.py,sha256=B2341NT-mry_Rv9kuQL-HQrRT6cyIidPR-vdlm3CCrE,865 -openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py,sha256=qxt7SsRh0bT0CSpEmRQhdoBpzCedzXZ06qaV2AiA3JI,883 -openai/types/webhooks/realtime_call_incoming_webhook_event.py,sha256=44kdeD1WbPjaqpf5S8EIfxtrSudjlpaaz74_9-rIzrw,1155 -openai/types/webhooks/response_cancelled_webhook_event.py,sha256=gmAVs2WIUoF1_HLbZ4whmTl6WPzEAsWzKFq6WiZsku8,870 -openai/types/webhooks/response_completed_webhook_event.py,sha256=mwNAM5x1-uqL39j_gCXPGSPLjzuPZoYwBZ-uo3ia5Dw,870 -openai/types/webhooks/response_failed_webhook_event.py,sha256=ka3VuDmBV7d9hxoFWktSZFXmtQrd4vrL4OinnMriyvQ,843 -openai/types/webhooks/response_incomplete_webhook_event.py,sha256=egeszUAnZW5j7-JBYXqNNUPNcDJc_Rl_shR2Lyz3iLM,878 -openai/types/webhooks/unwrap_webhook_event.py,sha256=KrfVL0-NsOuWHtRGiJfGMYwI8blUr09vUqUVJdZNpDQ,2039 -openai/types/websocket_connection_options.py,sha256=4cAWpv1KKp_9pvnez7pGYzO3s8zh1WvX2xpBhpe-96k,1840 -openai/version.py,sha256=cjbXKO8Ut3aiv4YlQnugff7AdC48MpSndcx96q88Yb8,62 diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/WHEEL deleted file mode 100644 index 21aaa72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: hatchling 1.26.3 -Root-Is-Purelib: true -Tag: py3-none-any diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/entry_points.txt b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/entry_points.txt deleted file mode 100644 index 9899939..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/entry_points.txt +++ /dev/null @@ -1,2 +0,0 @@ -[console_scripts] -openai = openai.cli:main diff --git a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/licenses/LICENSE b/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/licenses/LICENSE deleted file mode 100644 index cbb5bb2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai-2.15.0.dist-info/licenses/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2026 OpenAI - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/backend/venv39/lib/python3.9/site-packages/openai/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/__init__.py deleted file mode 100644 index e7411b3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/__init__.py +++ /dev/null @@ -1,395 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os as _os -import typing as _t -from typing_extensions import override - -from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given -from ._utils import file_from_path -from ._client import Client, OpenAI, Stream, Timeout, Transport, AsyncClient, AsyncOpenAI, AsyncStream, RequestOptions -from ._models import BaseModel -from ._version import __title__, __version__ -from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse -from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS -from ._exceptions import ( - APIError, - OpenAIError, - ConflictError, - NotFoundError, - APIStatusError, - RateLimitError, - APITimeoutError, - BadRequestError, - APIConnectionError, - AuthenticationError, - InternalServerError, - PermissionDeniedError, - LengthFinishReasonError, - UnprocessableEntityError, - APIResponseValidationError, - InvalidWebhookSignatureError, - ContentFilterFinishReasonError, -) -from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient -from ._utils._logs import setup_logging as _setup_logging -from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent - -__all__ = [ - "types", - "__version__", - "__title__", - "NoneType", - "Transport", - "ProxiesTypes", - "NotGiven", - "NOT_GIVEN", - "not_given", - "Omit", - "omit", - "OpenAIError", - "APIError", - "APIStatusError", - "APITimeoutError", - "APIConnectionError", - "APIResponseValidationError", - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", - "LengthFinishReasonError", - "ContentFilterFinishReasonError", - "InvalidWebhookSignatureError", - "Timeout", - "RequestOptions", - "Client", - "AsyncClient", - "Stream", - "AsyncStream", - "OpenAI", - "AsyncOpenAI", - "file_from_path", - "BaseModel", - "DEFAULT_TIMEOUT", - "DEFAULT_MAX_RETRIES", - "DEFAULT_CONNECTION_LIMITS", - "DefaultHttpxClient", - "DefaultAsyncHttpxClient", - "DefaultAioHttpClient", -] - -if not _t.TYPE_CHECKING: - from ._utils._resources_proxy import resources as resources - -from .lib import azure as _azure, pydantic_function_tool as pydantic_function_tool -from .version import VERSION as VERSION -from .lib.azure import AzureOpenAI as AzureOpenAI, AsyncAzureOpenAI as AsyncAzureOpenAI -from .lib._old_api import * -from .lib.streaming import ( - AssistantEventHandler as AssistantEventHandler, - AsyncAssistantEventHandler as AsyncAssistantEventHandler, -) - -_setup_logging() - -# Update the __module__ attribute for exported symbols so that -# error messages point to this module instead of the module -# it was originally defined in, e.g. -# openai._exceptions.NotFoundError -> openai.NotFoundError -__locals = locals() -for __name in __all__: - if not __name.startswith("__"): - try: - __locals[__name].__module__ = "openai" - except (TypeError, AttributeError): - # Some of our exported symbols are builtins which we can't set attributes for. - pass - -# ------ Module level client ------ -import typing as _t -import typing_extensions as _te - -import httpx as _httpx - -from ._base_client import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES - -api_key: str | None = None - -organization: str | None = None - -project: str | None = None - -webhook_secret: str | None = None - -base_url: str | _httpx.URL | None = None - -timeout: float | Timeout | None = DEFAULT_TIMEOUT - -max_retries: int = DEFAULT_MAX_RETRIES - -default_headers: _t.Mapping[str, str] | None = None - -default_query: _t.Mapping[str, object] | None = None - -http_client: _httpx.Client | None = None - -_ApiType = _te.Literal["openai", "azure"] - -api_type: _ApiType | None = _t.cast(_ApiType, _os.environ.get("OPENAI_API_TYPE")) - -api_version: str | None = _os.environ.get("OPENAI_API_VERSION") - -azure_endpoint: str | None = _os.environ.get("AZURE_OPENAI_ENDPOINT") - -azure_ad_token: str | None = _os.environ.get("AZURE_OPENAI_AD_TOKEN") - -azure_ad_token_provider: _azure.AzureADTokenProvider | None = None - - -class _ModuleClient(OpenAI): - # Note: we have to use type: ignores here as overriding class members - # with properties is technically unsafe but it is fine for our use case - - @property # type: ignore - @override - def api_key(self) -> str | None: - return api_key - - @api_key.setter # type: ignore - def api_key(self, value: str | None) -> None: # type: ignore - global api_key - - api_key = value - - @property # type: ignore - @override - def organization(self) -> str | None: - return organization - - @organization.setter # type: ignore - def organization(self, value: str | None) -> None: # type: ignore - global organization - - organization = value - - @property # type: ignore - @override - def project(self) -> str | None: - return project - - @project.setter # type: ignore - def project(self, value: str | None) -> None: # type: ignore - global project - - project = value - - @property # type: ignore - @override - def webhook_secret(self) -> str | None: - return webhook_secret - - @webhook_secret.setter # type: ignore - def webhook_secret(self, value: str | None) -> None: # type: ignore - global webhook_secret - - webhook_secret = value - - @property - @override - def base_url(self) -> _httpx.URL: - if base_url is not None: - return _httpx.URL(base_url) - - return super().base_url - - @base_url.setter - def base_url(self, url: _httpx.URL | str) -> None: - super().base_url = url # type: ignore[misc] - - @property # type: ignore - @override - def timeout(self) -> float | Timeout | None: - return timeout - - @timeout.setter # type: ignore - def timeout(self, value: float | Timeout | None) -> None: # type: ignore - global timeout - - timeout = value - - @property # type: ignore - @override - def max_retries(self) -> int: - return max_retries - - @max_retries.setter # type: ignore - def max_retries(self, value: int) -> None: # type: ignore - global max_retries - - max_retries = value - - @property # type: ignore - @override - def _custom_headers(self) -> _t.Mapping[str, str] | None: - return default_headers - - @_custom_headers.setter # type: ignore - def _custom_headers(self, value: _t.Mapping[str, str] | None) -> None: # type: ignore - global default_headers - - default_headers = value - - @property # type: ignore - @override - def _custom_query(self) -> _t.Mapping[str, object] | None: - return default_query - - @_custom_query.setter # type: ignore - def _custom_query(self, value: _t.Mapping[str, object] | None) -> None: # type: ignore - global default_query - - default_query = value - - @property # type: ignore - @override - def _client(self) -> _httpx.Client: - return http_client or super()._client - - @_client.setter # type: ignore - def _client(self, value: _httpx.Client) -> None: # type: ignore - global http_client - - http_client = value - - -class _AzureModuleClient(_ModuleClient, AzureOpenAI): # type: ignore - ... - - -class _AmbiguousModuleClientUsageError(OpenAIError): - def __init__(self) -> None: - super().__init__( - "Ambiguous use of module client; please set `openai.api_type` or the `OPENAI_API_TYPE` environment variable to `openai` or `azure`" - ) - - -def _has_openai_credentials() -> bool: - return _os.environ.get("OPENAI_API_KEY") is not None - - -def _has_azure_credentials() -> bool: - return azure_endpoint is not None or _os.environ.get("AZURE_OPENAI_API_KEY") is not None - - -def _has_azure_ad_credentials() -> bool: - return ( - _os.environ.get("AZURE_OPENAI_AD_TOKEN") is not None - or azure_ad_token is not None - or azure_ad_token_provider is not None - ) - - -_client: OpenAI | None = None - - -def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] - global _client - - if _client is None: - global api_type, azure_endpoint, azure_ad_token, api_version - - if azure_endpoint is None: - azure_endpoint = _os.environ.get("AZURE_OPENAI_ENDPOINT") - - if azure_ad_token is None: - azure_ad_token = _os.environ.get("AZURE_OPENAI_AD_TOKEN") - - if api_version is None: - api_version = _os.environ.get("OPENAI_API_VERSION") - - if api_type is None: - has_openai = _has_openai_credentials() - has_azure = _has_azure_credentials() - has_azure_ad = _has_azure_ad_credentials() - - if has_openai and (has_azure or has_azure_ad): - raise _AmbiguousModuleClientUsageError() - - if (azure_ad_token is not None or azure_ad_token_provider is not None) and _os.environ.get( - "AZURE_OPENAI_API_KEY" - ) is not None: - raise _AmbiguousModuleClientUsageError() - - if has_azure or has_azure_ad: - api_type = "azure" - else: - api_type = "openai" - - if api_type == "azure": - _client = _AzureModuleClient( # type: ignore - api_version=api_version, - azure_endpoint=azure_endpoint, - api_key=api_key, - azure_ad_token=azure_ad_token, - azure_ad_token_provider=azure_ad_token_provider, - organization=organization, - base_url=base_url, - timeout=timeout, - max_retries=max_retries, - default_headers=default_headers, - default_query=default_query, - http_client=http_client, - ) - return _client - - _client = _ModuleClient( - api_key=api_key, - organization=organization, - project=project, - webhook_secret=webhook_secret, - base_url=base_url, - timeout=timeout, - max_retries=max_retries, - default_headers=default_headers, - default_query=default_query, - http_client=http_client, - ) - return _client - - return _client - - -def _reset_client() -> None: # type: ignore[reportUnusedFunction] - global _client - - _client = None - - -from ._module_client import ( - beta as beta, - chat as chat, - audio as audio, - evals as evals, - files as files, - images as images, - models as models, - videos as videos, - batches as batches, - uploads as uploads, - realtime as realtime, - webhooks as webhooks, - responses as responses, - containers as containers, - embeddings as embeddings, - completions as completions, - fine_tuning as fine_tuning, - moderations as moderations, - conversations as conversations, - vector_stores as vector_stores, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/__main__.py b/backend/venv39/lib/python3.9/site-packages/openai/__main__.py deleted file mode 100644 index 4e28416..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .cli import main - -main() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_base_client.py b/backend/venv39/lib/python3.9/site-packages/openai/_base_client.py deleted file mode 100644 index 9e53641..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_base_client.py +++ /dev/null @@ -1,2033 +0,0 @@ -from __future__ import annotations - -import sys -import json -import time -import uuid -import email -import asyncio -import inspect -import logging -import platform -import email.utils -from types import TracebackType -from random import random -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Type, - Union, - Generic, - Mapping, - TypeVar, - Iterable, - Iterator, - Optional, - Generator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Literal, override, get_origin - -import anyio -import httpx -import distro -import pydantic -from httpx import URL -from pydantic import PrivateAttr - -from . import _exceptions -from ._qs import Querystring -from ._files import to_httpx_files, async_to_httpx_files -from ._types import ( - Body, - Omit, - Query, - Headers, - Timeout, - NotGiven, - ResponseT, - AnyMapping, - PostParser, - RequestFiles, - HttpxSendArgs, - RequestOptions, - HttpxRequestFiles, - ModelBuilderProtocol, - not_given, -) -from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V1, model_copy, model_dump -from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type -from ._response import ( - APIResponse, - BaseAPIResponse, - AsyncAPIResponse, - extract_response_type, -) -from ._constants import ( - DEFAULT_TIMEOUT, - MAX_RETRY_DELAY, - DEFAULT_MAX_RETRIES, - INITIAL_RETRY_DELAY, - RAW_RESPONSE_HEADER, - OVERRIDE_CAST_TO_HEADER, - DEFAULT_CONNECTION_LIMITS, -) -from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder -from ._exceptions import ( - APIStatusError, - APITimeoutError, - APIConnectionError, - APIResponseValidationError, -) -from ._legacy_response import LegacyAPIResponse - -log: logging.Logger = logging.getLogger(__name__) -log.addFilter(SensitiveHeadersFilter()) - -# TODO: make base page type vars covariant -SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") -AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") - - -_T = TypeVar("_T") -_T_co = TypeVar("_T_co", covariant=True) - -_StreamT = TypeVar("_StreamT", bound=Stream[Any]) -_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) - -if TYPE_CHECKING: - from httpx._config import ( - DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] - ) - - HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG -else: - try: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT - except ImportError: - # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 - HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) - - -class PageInfo: - """Stores the necessary information to build the request to retrieve the next page. - - Either `url` or `params` must be set. - """ - - url: URL | NotGiven - params: Query | NotGiven - json: Body | NotGiven - - @overload - def __init__( - self, - *, - url: URL, - ) -> None: ... - - @overload - def __init__( - self, - *, - params: Query, - ) -> None: ... - - @overload - def __init__( - self, - *, - json: Body, - ) -> None: ... - - def __init__( - self, - *, - url: URL | NotGiven = not_given, - json: Body | NotGiven = not_given, - params: Query | NotGiven = not_given, - ) -> None: - self.url = url - self.json = json - self.params = params - - @override - def __repr__(self) -> str: - if self.url: - return f"{self.__class__.__name__}(url={self.url})" - if self.json: - return f"{self.__class__.__name__}(json={self.json})" - return f"{self.__class__.__name__}(params={self.params})" - - -class BasePage(GenericModel, Generic[_T]): - """ - Defines the core interface for pagination. - - Type Args: - ModelT: The pydantic model that represents an item in the response. - - Methods: - has_next_page(): Check if there is another page available - next_page_info(): Get the necessary information to make a request for the next page - """ - - _options: FinalRequestOptions = PrivateAttr() - _model: Type[_T] = PrivateAttr() - - def has_next_page(self) -> bool: - items = self._get_page_items() - if not items: - return False - return self.next_page_info() is not None - - def next_page_info(self) -> Optional[PageInfo]: ... - - def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] - ... - - def _params_from_url(self, url: URL) -> httpx.QueryParams: - # TODO: do we have to preprocess params here? - return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) - - def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: - options = model_copy(self._options) - options._strip_raw_response_header() - - if not isinstance(info.params, NotGiven): - options.params = {**options.params, **info.params} - return options - - if not isinstance(info.url, NotGiven): - params = self._params_from_url(info.url) - url = info.url.copy_with(params=params) - options.params = dict(url.params) - options.url = str(url) - return options - - if not isinstance(info.json, NotGiven): - if not is_mapping(info.json): - raise TypeError("Pagination is only supported with mappings") - - if not options.json_data: - options.json_data = {**info.json} - else: - if not is_mapping(options.json_data): - raise TypeError("Pagination is only supported with mappings") - - options.json_data = {**options.json_data, **info.json} - return options - - raise ValueError("Unexpected PageInfo state") - - -class BaseSyncPage(BasePage[_T], Generic[_T]): - _client: SyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - client: SyncAPIClient, - model: Type[_T], - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - # Pydantic uses a custom `__iter__` method to support casting BaseModels - # to dictionaries. e.g. dict(model). - # As we want to support `for item in page`, this is inherently incompatible - # with the default pydantic behaviour. It is not possible to support both - # use cases at once. Fortunately, this is not a big deal as all other pydantic - # methods should continue to work as expected as there is an alternative method - # to cast a model to a dictionary, model.dict(), which is used internally - # by pydantic. - def __iter__(self) -> Iterator[_T]: # type: ignore - for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = page.get_next_page() - else: - return - - def get_next_page(self: SyncPageT) -> SyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return self._client._request_api_list(self._model, page=self.__class__, options=options) - - -class AsyncPaginator(Generic[_T, AsyncPageT]): - def __init__( - self, - client: AsyncAPIClient, - options: FinalRequestOptions, - page_cls: Type[AsyncPageT], - model: Type[_T], - ) -> None: - self._model = model - self._client = client - self._options = options - self._page_cls = page_cls - - def __await__(self) -> Generator[Any, None, AsyncPageT]: - return self._get_page().__await__() - - async def _get_page(self) -> AsyncPageT: - def _parser(resp: AsyncPageT) -> AsyncPageT: - resp._set_private_attributes( - model=self._model, - options=self._options, - client=self._client, - ) - return resp - - self._options.post_parser = _parser - - return await self._client.request(self._page_cls, self._options) - - async def __aiter__(self) -> AsyncIterator[_T]: - # https://github.com/microsoft/pyright/issues/3464 - page = cast( - AsyncPageT, - await self, # type: ignore - ) - async for item in page: - yield item - - -class BaseAsyncPage(BasePage[_T], Generic[_T]): - _client: AsyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - model: Type[_T], - client: AsyncAPIClient, - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - async def __aiter__(self) -> AsyncIterator[_T]: - async for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = await page.get_next_page() - else: - return - - async def get_next_page(self: AsyncPageT) -> AsyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return await self._client._request_api_list(self._model, page=self.__class__, options=options) - - -_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) -_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) - - -class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): - _client: _HttpxClientT - _version: str - _base_url: URL - max_retries: int - timeout: Union[float, Timeout, None] - _strict_response_validation: bool - _idempotency_header: str | None - _default_stream_cls: type[_DefaultStreamT] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None = DEFAULT_TIMEOUT, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - self._version = version - self._base_url = self._enforce_trailing_slash(URL(base_url)) - self.max_retries = max_retries - self.timeout = timeout - self._custom_headers = custom_headers or {} - self._custom_query = custom_query or {} - self._strict_response_validation = _strict_response_validation - self._idempotency_header = None - self._platform: Platform | None = None - - if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] - raise TypeError( - "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `openai.DEFAULT_MAX_RETRIES`" - ) - - def _enforce_trailing_slash(self, url: URL) -> URL: - if url.raw_path.endswith(b"/"): - return url - return url.copy_with(raw_path=url.raw_path + b"/") - - def _make_status_error_from_response( - self, - response: httpx.Response, - ) -> APIStatusError: - if response.is_closed and not response.is_stream_consumed: - # We can't read the response body as it has been closed - # before it was read. This can happen if an event hook - # raises a status error. - body = None - err_msg = f"Error code: {response.status_code}" - else: - err_text = response.text.strip() - body = err_text - - try: - body = json.loads(err_text) - err_msg = f"Error code: {response.status_code} - {body}" - except Exception: - err_msg = err_text or f"Error code: {response.status_code}" - - return self._make_status_error(err_msg, body=body, response=response) - - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> _exceptions.APIStatusError: - raise NotImplementedError() - - def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: - custom_headers = options.headers or {} - headers_dict = _merge_mappings(self.default_headers, custom_headers) - self._validate_headers(headers_dict, custom_headers) - - # headers are case-insensitive while dictionaries are not. - headers = httpx.Headers(headers_dict) - - idempotency_header = self._idempotency_header - if idempotency_header and options.idempotency_key and idempotency_header not in headers: - headers[idempotency_header] = options.idempotency_key - - # Don't set these headers if they were already set or removed by the caller. We check - # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. - lower_custom_headers = [header.lower() for header in custom_headers] - if "x-stainless-retry-count" not in lower_custom_headers: - headers["x-stainless-retry-count"] = str(retries_taken) - if "x-stainless-read-timeout" not in lower_custom_headers: - timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout - if isinstance(timeout, Timeout): - timeout = timeout.read - if timeout is not None: - headers["x-stainless-read-timeout"] = str(timeout) - - return headers - - def _prepare_url(self, url: str) -> URL: - """ - Merge a URL argument together with any 'base_url' on the client, - to create the URL used for the outgoing request. - """ - # Copied from httpx's `_merge_url` method. - merge_url = URL(url) - if merge_url.is_relative_url: - merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") - return self.base_url.copy_with(raw_path=merge_raw_path) - - return merge_url - - def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: - return SSEDecoder() - - def _build_request( - self, - options: FinalRequestOptions, - *, - retries_taken: int = 0, - ) -> httpx.Request: - if log.isEnabledFor(logging.DEBUG): - log.debug("Request options: %s", model_dump(options, exclude_unset=True)) - - kwargs: dict[str, Any] = {} - - json_data = options.json_data - if options.extra_json is not None: - if json_data is None: - json_data = cast(Body, options.extra_json) - elif is_mapping(json_data): - json_data = _merge_mappings(json_data, options.extra_json) - else: - raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - - headers = self._build_headers(options, retries_taken=retries_taken) - params = _merge_mappings(self.default_query, options.params) - content_type = headers.get("Content-Type") - files = options.files - - # If the given Content-Type header is multipart/form-data then it - # has to be removed so that httpx can generate the header with - # additional information for us as it has to be in this form - # for the server to be able to correctly parse the request: - # multipart/form-data; boundary=---abc-- - if content_type is not None and content_type.startswith("multipart/form-data"): - if "boundary" not in content_type: - # only remove the header if the boundary hasn't been explicitly set - # as the caller doesn't want httpx to come up with their own boundary - headers.pop("Content-Type") - - # As we are now sending multipart/form-data instead of application/json - # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding - if json_data: - if not is_dict(json_data): - raise TypeError( - f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." - ) - kwargs["data"] = self._serialize_multipartform(json_data) - - # httpx determines whether or not to send a "multipart/form-data" - # request based on the truthiness of the "files" argument. - # This gets around that issue by generating a dict value that - # evaluates to true. - # - # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 - if not files: - files = cast(HttpxRequestFiles, ForceMultipartDict()) - - prepared_url = self._prepare_url(options.url) - if "_" in prepared_url.host: - # work around https://github.com/encode/httpx/discussions/2880 - kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} - - is_body_allowed = options.method.lower() != "get" - - if is_body_allowed: - if isinstance(json_data, bytes): - kwargs["content"] = json_data - else: - kwargs["json"] = json_data if is_given(json_data) else None - kwargs["files"] = files - else: - headers.pop("Content-Type", None) - kwargs.pop("data", None) - - # TODO: report this error to httpx - return self._client.build_request( # pyright: ignore[reportUnknownMemberType] - headers=headers, - timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, - method=options.method, - url=prepared_url, - # the `Query` type that we use is incompatible with qs' - # `Params` type as it needs to be typed as `Mapping[str, object]` - # so that passing a `TypedDict` doesn't cause an error. - # https://github.com/microsoft/pyright/issues/3526#event-6715453066 - params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - **kwargs, - ) - - def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: - items = self.qs.stringify_items( - # TODO: type ignore is required as stringify_items is well typed but we can't be - # well typed without heavy validation. - data, # type: ignore - array_format="brackets", - ) - serialized: dict[str, object] = {} - for key, value in items: - existing = serialized.get(key) - - if not existing: - serialized[key] = value - continue - - # If a value has already been set for this key then that - # means we're sending data like `array[]=[1, 2, 3]` and we - # need to tell httpx that we want to send multiple values with - # the same key which is done by using a list or a tuple. - # - # Note: 2d arrays should never result in the same key at both - # levels so it's safe to assume that if the value is a list, - # it was because we changed it to be a list. - if is_list(existing): - existing.append(value) - else: - serialized[key] = [existing, value] - - return serialized - - def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: - if not is_given(options.headers): - return cast_to - - # make a copy of the headers so we don't mutate user-input - headers = dict(options.headers) - - # we internally support defining a temporary header to override the - # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` - # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) - if is_given(override_cast_to): - options.headers = headers - return cast(Type[ResponseT], override_cast_to) - - return cast_to - - def _should_stream_response_body(self, request: httpx.Request) -> bool: - return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] - - def _process_response_data( - self, - *, - data: object, - cast_to: type[ResponseT], - response: httpx.Response, - ) -> ResponseT: - if data is None: - return cast(ResponseT, None) - - if cast_to is object: - return cast(ResponseT, data) - - try: - if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): - return cast(ResponseT, cast_to.build(response=response, data=data)) - - if self._strict_response_validation: - return cast(ResponseT, validate_type(type_=cast_to, value=data)) - - return cast(ResponseT, construct_type(type_=cast_to, value=data)) - except pydantic.ValidationError as err: - raise APIResponseValidationError(response=response, body=data) from err - - @property - def qs(self) -> Querystring: - return Querystring() - - @property - def custom_auth(self) -> httpx.Auth | None: - return None - - @property - def auth_headers(self) -> dict[str, str]: - return {} - - @property - def default_headers(self) -> dict[str, str | Omit]: - return { - "Accept": "application/json", - "Content-Type": "application/json", - "User-Agent": self.user_agent, - **self.platform_headers(), - **self.auth_headers, - **self._custom_headers, - } - - @property - def default_query(self) -> dict[str, object]: - return { - **self._custom_query, - } - - def _validate_headers( - self, - headers: Headers, # noqa: ARG002 - custom_headers: Headers, # noqa: ARG002 - ) -> None: - """Validate the given default headers and custom headers. - - Does nothing by default. - """ - return - - @property - def user_agent(self) -> str: - return f"{self.__class__.__name__}/Python {self._version}" - - @property - def base_url(self) -> URL: - return self._base_url - - @base_url.setter - def base_url(self, url: URL | str) -> None: - self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) - - def platform_headers(self) -> Dict[str, str]: - # the actual implementation is in a separate `lru_cache` decorated - # function because adding `lru_cache` to methods will leak memory - # https://github.com/python/cpython/issues/88476 - return platform_headers(self._version, platform=self._platform) - - def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: - """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. - - About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After - See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax - """ - if response_headers is None: - return None - - # First, try the non-standard `retry-after-ms` header for milliseconds, - # which is more precise than integer-seconds `retry-after` - try: - retry_ms_header = response_headers.get("retry-after-ms", None) - return float(retry_ms_header) / 1000 - except (TypeError, ValueError): - pass - - # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). - retry_header = response_headers.get("retry-after") - try: - # note: the spec indicates that this should only ever be an integer - # but if someone sends a float there's no reason for us to not respect it - return float(retry_header) - except (TypeError, ValueError): - pass - - # Last, try parsing `retry-after` as a date. - retry_date_tuple = email.utils.parsedate_tz(retry_header) - if retry_date_tuple is None: - return None - - retry_date = email.utils.mktime_tz(retry_date_tuple) - return float(retry_date - time.time()) - - def _calculate_retry_timeout( - self, - remaining_retries: int, - options: FinalRequestOptions, - response_headers: Optional[httpx.Headers] = None, - ) -> float: - max_retries = options.get_max_retries(self.max_retries) - - # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. - retry_after = self._parse_retry_after_header(response_headers) - if retry_after is not None and 0 < retry_after <= 60: - return retry_after - - # Also cap retry count to 1000 to avoid any potential overflows with `pow` - nb_retries = min(max_retries - remaining_retries, 1000) - - # Apply exponential backoff, but not more than the max. - sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) - - # Apply some jitter, plus-or-minus half a second. - jitter = 1 - 0.25 * random() - timeout = sleep_seconds * jitter - return timeout if timeout >= 0 else 0 - - def _should_retry(self, response: httpx.Response) -> bool: - # Note: this is not a standard header - should_retry_header = response.headers.get("x-should-retry") - - # If the server explicitly says whether or not to retry, obey. - if should_retry_header == "true": - log.debug("Retrying as header `x-should-retry` is set to `true`") - return True - if should_retry_header == "false": - log.debug("Not retrying as header `x-should-retry` is set to `false`") - return False - - # Retry on request timeouts. - if response.status_code == 408: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on lock timeouts. - if response.status_code == 409: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on rate limits. - if response.status_code == 429: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry internal errors. - if response.status_code >= 500: - log.debug("Retrying due to status code %i", response.status_code) - return True - - log.debug("Not retrying") - return False - - def _idempotency_key(self) -> str: - return f"stainless-python-retry-{uuid.uuid4()}" - - -class _DefaultHttpxClient(httpx.Client): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultHttpxClient = httpx.Client - """An alias to `httpx.Client` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.Client` will result in httpx's defaults being used, not ours. - """ -else: - DefaultHttpxClient = _DefaultHttpxClient - - -class SyncHttpxClientWrapper(DefaultHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - self.close() - except Exception: - pass - - -class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): - _client: httpx.Client - _default_stream_cls: type[Stream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - _strict_response_validation: bool, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" - ) - - super().__init__( - version=version, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - base_url=base_url, - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or SyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - # If an error is thrown while constructing a client, self._client - # may not be present - if hasattr(self, "_client"): - self._client.close() - - def __enter__(self: _T) -> _T: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: Type[_StreamT], - ) -> _StreamT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: Type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - log.debug("request_id: %s", response.headers.get("x-request-id")) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - err.response.close() - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - err.response.read() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - time.sleep(timeout) - - def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": - return cast( - ResponseT, - LegacyAPIResponse( - raw=response, - client=self, - cast_to=cast_to, - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, APIResponse): - raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - ResponseT, - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = APIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return api_response.parse() - - def _request_api_list( - self, - model: Type[object], - page: Type[SyncPageT], - options: FinalRequestOptions, - ) -> SyncPageT: - def _parser(resp: SyncPageT) -> SyncPageT: - resp._set_private_attributes( - client=self, - model=model, - options=options, - ) - return resp - - options.post_parser = _parser - - return self.request(page, options, stream=False) - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - # cast is required because mypy complains about returning Any even though - # it understands the type variables - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=to_httpx_files(files), **options - ) - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) - return self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[object], - page: Type[SyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> SyncPageT: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -class _DefaultAsyncHttpxClient(httpx.AsyncClient): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -try: - import httpx_aiohttp -except ImportError: - - class _DefaultAioHttpClient(httpx.AsyncClient): - def __init__(self, **_kwargs: Any) -> None: - raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") -else: - - class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultAsyncHttpxClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.AsyncClient` will result in httpx's defaults being used, not ours. - """ - - DefaultAioHttpClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" -else: - DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient - DefaultAioHttpClient = _DefaultAioHttpClient - - -class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - # TODO(someday): support non asyncio runtimes here - asyncio.get_running_loop().create_task(self.aclose()) - except Exception: - pass - - -class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): - _client: httpx.AsyncClient - _default_stream_cls: type[AsyncStream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" - ) - - super().__init__( - version=version, - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or AsyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - async def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - await self._client.aclose() - - async def __aenter__(self: _T) -> _T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - async def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - if self._platform is None: - # `get_platform` can make blocking IO calls so we - # execute it earlier while we are in an async context - self._platform = await asyncify(get_platform)() - - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = await self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - await self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = await self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - log.debug("request_id: %s", response.headers.get("x-request-id")) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - await err.response.aclose() - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - await err.response.aread() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return await self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - async def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - await anyio.sleep(timeout) - - async def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - if response.request.headers.get(RAW_RESPONSE_HEADER) == "true": - return cast( - ResponseT, - LegacyAPIResponse( - raw=response, - client=self, - cast_to=cast_to, - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, AsyncAPIResponse): - raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - "ResponseT", - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = AsyncAPIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return await api_response.parse() - - def _request_api_list( - self, - model: Type[_T], - page: Type[AsyncPageT], - options: FinalRequestOptions, - ) -> AsyncPaginator[_T, AsyncPageT]: - return AsyncPaginator(client=self, options=options, page_cls=page, model=model) - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - async def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts) - - async def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts) - - async def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) - return await self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[_T], - page: Type[AsyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> AsyncPaginator[_T, AsyncPageT]: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -def make_request_options( - *, - query: Query | None = None, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - post_parser: PostParser | NotGiven = not_given, -) -> RequestOptions: - """Create a dict of type RequestOptions without keys of NotGiven values.""" - options: RequestOptions = {} - if extra_headers is not None: - options["headers"] = extra_headers - - if extra_body is not None: - options["extra_json"] = cast(AnyMapping, extra_body) - - if query is not None: - options["params"] = query - - if extra_query is not None: - options["params"] = {**options.get("params", {}), **extra_query} - - if not isinstance(timeout, NotGiven): - options["timeout"] = timeout - - if idempotency_key is not None: - options["idempotency_key"] = idempotency_key - - if is_given(post_parser): - # internal - options["post_parser"] = post_parser # type: ignore - - return options - - -class ForceMultipartDict(Dict[str, None]): - def __bool__(self) -> bool: - return True - - -class OtherPlatform: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"Other:{self.name}" - - -Platform = Union[ - OtherPlatform, - Literal[ - "MacOS", - "Linux", - "Windows", - "FreeBSD", - "OpenBSD", - "iOS", - "Android", - "Unknown", - ], -] - - -def get_platform() -> Platform: - try: - system = platform.system().lower() - platform_name = platform.platform().lower() - except Exception: - return "Unknown" - - if "iphone" in platform_name or "ipad" in platform_name: - # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 - # system is Darwin and platform_name is a string like: - # - Darwin-21.6.0-iPhone12,1-64bit - # - Darwin-21.6.0-iPad7,11-64bit - return "iOS" - - if system == "darwin": - return "MacOS" - - if system == "windows": - return "Windows" - - if "android" in platform_name: - # Tested using Pydroid 3 - # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' - return "Android" - - if system == "linux": - # https://distro.readthedocs.io/en/latest/#distro.id - distro_id = distro.id() - if distro_id == "freebsd": - return "FreeBSD" - - if distro_id == "openbsd": - return "OpenBSD" - - return "Linux" - - if platform_name: - return OtherPlatform(platform_name) - - return "Unknown" - - -@lru_cache(maxsize=None) -def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: - return { - "X-Stainless-Lang": "python", - "X-Stainless-Package-Version": version, - "X-Stainless-OS": str(platform or get_platform()), - "X-Stainless-Arch": str(get_architecture()), - "X-Stainless-Runtime": get_python_runtime(), - "X-Stainless-Runtime-Version": get_python_version(), - } - - -class OtherArch: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"other:{self.name}" - - -Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] - - -def get_python_runtime() -> str: - try: - return platform.python_implementation() - except Exception: - return "unknown" - - -def get_python_version() -> str: - try: - return platform.python_version() - except Exception: - return "unknown" - - -def get_architecture() -> Arch: - try: - machine = platform.machine().lower() - except Exception: - return "unknown" - - if machine in ("arm64", "aarch64"): - return "arm64" - - # TODO: untested - if machine == "arm": - return "arm" - - if machine == "x86_64": - return "x64" - - # TODO: untested - if sys.maxsize <= 2**32: - return "x32" - - if machine: - return OtherArch(machine) - - return "unknown" - - -def _merge_mappings( - obj1: Mapping[_T_co, Union[_T, Omit]], - obj2: Mapping[_T_co, Union[_T, Omit]], -) -> Dict[_T_co, _T]: - """Merge two mappings of the same type, removing any values that are instances of `Omit`. - - In cases with duplicate keys the second mapping takes precedence. - """ - merged = {**obj1, **obj2} - return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_client.py b/backend/venv39/lib/python3.9/site-packages/openai/_client.py deleted file mode 100644 index a3b01b2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_client.py +++ /dev/null @@ -1,1272 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import TYPE_CHECKING, Any, Mapping, Callable, Awaitable -from typing_extensions import Self, override - -import httpx - -from . import _exceptions -from ._qs import Querystring -from ._types import ( - Omit, - Timeout, - NotGiven, - Transport, - ProxiesTypes, - RequestOptions, - not_given, -) -from ._utils import ( - is_given, - is_mapping, - get_async_library, -) -from ._compat import cached_property -from ._models import FinalRequestOptions -from ._version import __version__ -from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import OpenAIError, APIStatusError -from ._base_client import ( - DEFAULT_MAX_RETRIES, - SyncAPIClient, - AsyncAPIClient, -) - -if TYPE_CHECKING: - from .resources import ( - beta, - chat, - audio, - evals, - files, - images, - models, - videos, - batches, - uploads, - realtime, - responses, - containers, - embeddings, - completions, - fine_tuning, - moderations, - conversations, - vector_stores, - ) - from .resources.files import Files, AsyncFiles - from .resources.images import Images, AsyncImages - from .resources.models import Models, AsyncModels - from .resources.videos import Videos, AsyncVideos - from .resources.batches import Batches, AsyncBatches - from .resources.webhooks import Webhooks, AsyncWebhooks - from .resources.beta.beta import Beta, AsyncBeta - from .resources.chat.chat import Chat, AsyncChat - from .resources.embeddings import Embeddings, AsyncEmbeddings - from .resources.audio.audio import Audio, AsyncAudio - from .resources.completions import Completions, AsyncCompletions - from .resources.evals.evals import Evals, AsyncEvals - from .resources.moderations import Moderations, AsyncModerations - from .resources.uploads.uploads import Uploads, AsyncUploads - from .resources.realtime.realtime import Realtime, AsyncRealtime - from .resources.responses.responses import Responses, AsyncResponses - from .resources.containers.containers import Containers, AsyncContainers - from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning - from .resources.conversations.conversations import Conversations, AsyncConversations - from .resources.vector_stores.vector_stores import VectorStores, AsyncVectorStores - -__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "OpenAI", "AsyncOpenAI", "Client", "AsyncClient"] - - -class OpenAI(SyncAPIClient): - # client options - api_key: str - organization: str | None - project: str | None - webhook_secret: str | None - - websocket_base_url: str | httpx.URL | None - """Base URL for WebSocket connections. - - If not specified, the default base URL will be used, with 'wss://' replacing the - 'http://' or 'https://' scheme. For example: 'http://example.com' becomes - 'wss://example.com' - """ - - def __init__( - self, - *, - api_key: str | None | Callable[[], str] = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. - http_client: httpx.Client | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new synchronous OpenAI client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `api_key` from `OPENAI_API_KEY` - - `organization` from `OPENAI_ORG_ID` - - `project` from `OPENAI_PROJECT_ID` - - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` - """ - if api_key is None: - api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" - ) - if callable(api_key): - self.api_key = "" - self._api_key_provider: Callable[[], str] | None = api_key - else: - self.api_key = api_key - self._api_key_provider = None - - if organization is None: - organization = os.environ.get("OPENAI_ORG_ID") - self.organization = organization - - if project is None: - project = os.environ.get("OPENAI_PROJECT_ID") - self.project = project - - if webhook_secret is None: - webhook_secret = os.environ.get("OPENAI_WEBHOOK_SECRET") - self.webhook_secret = webhook_secret - - self.websocket_base_url = websocket_base_url - - if base_url is None: - base_url = os.environ.get("OPENAI_BASE_URL") - if base_url is None: - base_url = f"https://api.openai.com/v1" - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - self._default_stream_cls = Stream - - @cached_property - def completions(self) -> Completions: - from .resources.completions import Completions - - return Completions(self) - - @cached_property - def chat(self) -> Chat: - from .resources.chat import Chat - - return Chat(self) - - @cached_property - def embeddings(self) -> Embeddings: - from .resources.embeddings import Embeddings - - return Embeddings(self) - - @cached_property - def files(self) -> Files: - from .resources.files import Files - - return Files(self) - - @cached_property - def images(self) -> Images: - from .resources.images import Images - - return Images(self) - - @cached_property - def audio(self) -> Audio: - from .resources.audio import Audio - - return Audio(self) - - @cached_property - def moderations(self) -> Moderations: - from .resources.moderations import Moderations - - return Moderations(self) - - @cached_property - def models(self) -> Models: - from .resources.models import Models - - return Models(self) - - @cached_property - def fine_tuning(self) -> FineTuning: - from .resources.fine_tuning import FineTuning - - return FineTuning(self) - - @cached_property - def vector_stores(self) -> VectorStores: - from .resources.vector_stores import VectorStores - - return VectorStores(self) - - @cached_property - def webhooks(self) -> Webhooks: - from .resources.webhooks import Webhooks - - return Webhooks(self) - - @cached_property - def beta(self) -> Beta: - from .resources.beta import Beta - - return Beta(self) - - @cached_property - def batches(self) -> Batches: - from .resources.batches import Batches - - return Batches(self) - - @cached_property - def uploads(self) -> Uploads: - from .resources.uploads import Uploads - - return Uploads(self) - - @cached_property - def responses(self) -> Responses: - from .resources.responses import Responses - - return Responses(self) - - @cached_property - def realtime(self) -> Realtime: - from .resources.realtime import Realtime - - return Realtime(self) - - @cached_property - def conversations(self) -> Conversations: - from .resources.conversations import Conversations - - return Conversations(self) - - @cached_property - def evals(self) -> Evals: - from .resources.evals import Evals - - return Evals(self) - - @cached_property - def containers(self) -> Containers: - from .resources.containers import Containers - - return Containers(self) - - @cached_property - def videos(self) -> Videos: - from .resources.videos import Videos - - return Videos(self) - - @cached_property - def with_raw_response(self) -> OpenAIWithRawResponse: - return OpenAIWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> OpenAIWithStreamedResponse: - return OpenAIWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="brackets") - - def _refresh_api_key(self) -> None: - if self._api_key_provider: - self.api_key = self._api_key_provider() - - @override - def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - self._refresh_api_key() - return super()._prepare_options(options) - - @property - @override - def auth_headers(self) -> dict[str, str]: - api_key = self.api_key - if not api_key: - # if the api key is an empty string, encoding the header will fail - return {} - return {"Authorization": f"Bearer {api_key}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": "false", - "OpenAI-Organization": self.organization if self.organization is not None else Omit(), - "OpenAI-Project": self.project if self.project is not None else Omit(), - **self._custom_headers, - } - - def copy( - self, - *, - api_key: str | Callable[[], str] | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - api_key=api_key or self._api_key_provider or self.api_key, - organization=organization or self.organization, - project=project or self.project, - webhook_secret=webhook_secret or self.webhook_secret, - websocket_base_url=websocket_base_url or self.websocket_base_url, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - data = body.get("error", body) if is_mapping(body) else body - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=data) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=data) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=data) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=data) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=data) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=data) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=data) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=data) - return APIStatusError(err_msg, response=response, body=data) - - -class AsyncOpenAI(AsyncAPIClient): - # client options - api_key: str - organization: str | None - project: str | None - webhook_secret: str | None - - websocket_base_url: str | httpx.URL | None - """Base URL for WebSocket connections. - - If not specified, the default base URL will be used, with 'wss://' replacing the - 'http://' or 'https://' scheme. For example: 'http://example.com' becomes - 'wss://example.com' - """ - - def __init__( - self, - *, - api_key: str | Callable[[], Awaitable[str]] | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. - http_client: httpx.AsyncClient | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new async AsyncOpenAI client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `api_key` from `OPENAI_API_KEY` - - `organization` from `OPENAI_ORG_ID` - - `project` from `OPENAI_PROJECT_ID` - - `webhook_secret` from `OPENAI_WEBHOOK_SECRET` - """ - if api_key is None: - api_key = os.environ.get("OPENAI_API_KEY") - if api_key is None: - raise OpenAIError( - "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" - ) - if callable(api_key): - self.api_key = "" - self._api_key_provider: Callable[[], Awaitable[str]] | None = api_key - else: - self.api_key = api_key - self._api_key_provider = None - - if organization is None: - organization = os.environ.get("OPENAI_ORG_ID") - self.organization = organization - - if project is None: - project = os.environ.get("OPENAI_PROJECT_ID") - self.project = project - - if webhook_secret is None: - webhook_secret = os.environ.get("OPENAI_WEBHOOK_SECRET") - self.webhook_secret = webhook_secret - - self.websocket_base_url = websocket_base_url - - if base_url is None: - base_url = os.environ.get("OPENAI_BASE_URL") - if base_url is None: - base_url = f"https://api.openai.com/v1" - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - self._default_stream_cls = AsyncStream - - @cached_property - def completions(self) -> AsyncCompletions: - from .resources.completions import AsyncCompletions - - return AsyncCompletions(self) - - @cached_property - def chat(self) -> AsyncChat: - from .resources.chat import AsyncChat - - return AsyncChat(self) - - @cached_property - def embeddings(self) -> AsyncEmbeddings: - from .resources.embeddings import AsyncEmbeddings - - return AsyncEmbeddings(self) - - @cached_property - def files(self) -> AsyncFiles: - from .resources.files import AsyncFiles - - return AsyncFiles(self) - - @cached_property - def images(self) -> AsyncImages: - from .resources.images import AsyncImages - - return AsyncImages(self) - - @cached_property - def audio(self) -> AsyncAudio: - from .resources.audio import AsyncAudio - - return AsyncAudio(self) - - @cached_property - def moderations(self) -> AsyncModerations: - from .resources.moderations import AsyncModerations - - return AsyncModerations(self) - - @cached_property - def models(self) -> AsyncModels: - from .resources.models import AsyncModels - - return AsyncModels(self) - - @cached_property - def fine_tuning(self) -> AsyncFineTuning: - from .resources.fine_tuning import AsyncFineTuning - - return AsyncFineTuning(self) - - @cached_property - def vector_stores(self) -> AsyncVectorStores: - from .resources.vector_stores import AsyncVectorStores - - return AsyncVectorStores(self) - - @cached_property - def webhooks(self) -> AsyncWebhooks: - from .resources.webhooks import AsyncWebhooks - - return AsyncWebhooks(self) - - @cached_property - def beta(self) -> AsyncBeta: - from .resources.beta import AsyncBeta - - return AsyncBeta(self) - - @cached_property - def batches(self) -> AsyncBatches: - from .resources.batches import AsyncBatches - - return AsyncBatches(self) - - @cached_property - def uploads(self) -> AsyncUploads: - from .resources.uploads import AsyncUploads - - return AsyncUploads(self) - - @cached_property - def responses(self) -> AsyncResponses: - from .resources.responses import AsyncResponses - - return AsyncResponses(self) - - @cached_property - def realtime(self) -> AsyncRealtime: - from .resources.realtime import AsyncRealtime - - return AsyncRealtime(self) - - @cached_property - def conversations(self) -> AsyncConversations: - from .resources.conversations import AsyncConversations - - return AsyncConversations(self) - - @cached_property - def evals(self) -> AsyncEvals: - from .resources.evals import AsyncEvals - - return AsyncEvals(self) - - @cached_property - def containers(self) -> AsyncContainers: - from .resources.containers import AsyncContainers - - return AsyncContainers(self) - - @cached_property - def videos(self) -> AsyncVideos: - from .resources.videos import AsyncVideos - - return AsyncVideos(self) - - @cached_property - def with_raw_response(self) -> AsyncOpenAIWithRawResponse: - return AsyncOpenAIWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncOpenAIWithStreamedResponse: - return AsyncOpenAIWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="brackets") - - async def _refresh_api_key(self) -> None: - if self._api_key_provider: - self.api_key = await self._api_key_provider() - - @override - async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - await self._refresh_api_key() - return await super()._prepare_options(options) - - @property - @override - def auth_headers(self) -> dict[str, str]: - api_key = self.api_key - if not api_key: - # if the api key is an empty string, encoding the header will fail - return {} - return {"Authorization": f"Bearer {api_key}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": f"async:{get_async_library()}", - "OpenAI-Organization": self.organization if self.organization is not None else Omit(), - "OpenAI-Project": self.project if self.project is not None else Omit(), - **self._custom_headers, - } - - def copy( - self, - *, - api_key: str | Callable[[], Awaitable[str]] | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - api_key=api_key or self._api_key_provider or self.api_key, - organization=organization or self.organization, - project=project or self.project, - webhook_secret=webhook_secret or self.webhook_secret, - websocket_base_url=websocket_base_url or self.websocket_base_url, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - data = body.get("error", body) if is_mapping(body) else body - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=data) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=data) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=data) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=data) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=data) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=data) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=data) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=data) - return APIStatusError(err_msg, response=response, body=data) - - -class OpenAIWithRawResponse: - _client: OpenAI - - def __init__(self, client: OpenAI) -> None: - self._client = client - - @cached_property - def completions(self) -> completions.CompletionsWithRawResponse: - from .resources.completions import CompletionsWithRawResponse - - return CompletionsWithRawResponse(self._client.completions) - - @cached_property - def chat(self) -> chat.ChatWithRawResponse: - from .resources.chat import ChatWithRawResponse - - return ChatWithRawResponse(self._client.chat) - - @cached_property - def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: - from .resources.embeddings import EmbeddingsWithRawResponse - - return EmbeddingsWithRawResponse(self._client.embeddings) - - @cached_property - def files(self) -> files.FilesWithRawResponse: - from .resources.files import FilesWithRawResponse - - return FilesWithRawResponse(self._client.files) - - @cached_property - def images(self) -> images.ImagesWithRawResponse: - from .resources.images import ImagesWithRawResponse - - return ImagesWithRawResponse(self._client.images) - - @cached_property - def audio(self) -> audio.AudioWithRawResponse: - from .resources.audio import AudioWithRawResponse - - return AudioWithRawResponse(self._client.audio) - - @cached_property - def moderations(self) -> moderations.ModerationsWithRawResponse: - from .resources.moderations import ModerationsWithRawResponse - - return ModerationsWithRawResponse(self._client.moderations) - - @cached_property - def models(self) -> models.ModelsWithRawResponse: - from .resources.models import ModelsWithRawResponse - - return ModelsWithRawResponse(self._client.models) - - @cached_property - def fine_tuning(self) -> fine_tuning.FineTuningWithRawResponse: - from .resources.fine_tuning import FineTuningWithRawResponse - - return FineTuningWithRawResponse(self._client.fine_tuning) - - @cached_property - def vector_stores(self) -> vector_stores.VectorStoresWithRawResponse: - from .resources.vector_stores import VectorStoresWithRawResponse - - return VectorStoresWithRawResponse(self._client.vector_stores) - - @cached_property - def beta(self) -> beta.BetaWithRawResponse: - from .resources.beta import BetaWithRawResponse - - return BetaWithRawResponse(self._client.beta) - - @cached_property - def batches(self) -> batches.BatchesWithRawResponse: - from .resources.batches import BatchesWithRawResponse - - return BatchesWithRawResponse(self._client.batches) - - @cached_property - def uploads(self) -> uploads.UploadsWithRawResponse: - from .resources.uploads import UploadsWithRawResponse - - return UploadsWithRawResponse(self._client.uploads) - - @cached_property - def responses(self) -> responses.ResponsesWithRawResponse: - from .resources.responses import ResponsesWithRawResponse - - return ResponsesWithRawResponse(self._client.responses) - - @cached_property - def realtime(self) -> realtime.RealtimeWithRawResponse: - from .resources.realtime import RealtimeWithRawResponse - - return RealtimeWithRawResponse(self._client.realtime) - - @cached_property - def conversations(self) -> conversations.ConversationsWithRawResponse: - from .resources.conversations import ConversationsWithRawResponse - - return ConversationsWithRawResponse(self._client.conversations) - - @cached_property - def evals(self) -> evals.EvalsWithRawResponse: - from .resources.evals import EvalsWithRawResponse - - return EvalsWithRawResponse(self._client.evals) - - @cached_property - def containers(self) -> containers.ContainersWithRawResponse: - from .resources.containers import ContainersWithRawResponse - - return ContainersWithRawResponse(self._client.containers) - - @cached_property - def videos(self) -> videos.VideosWithRawResponse: - from .resources.videos import VideosWithRawResponse - - return VideosWithRawResponse(self._client.videos) - - -class AsyncOpenAIWithRawResponse: - _client: AsyncOpenAI - - def __init__(self, client: AsyncOpenAI) -> None: - self._client = client - - @cached_property - def completions(self) -> completions.AsyncCompletionsWithRawResponse: - from .resources.completions import AsyncCompletionsWithRawResponse - - return AsyncCompletionsWithRawResponse(self._client.completions) - - @cached_property - def chat(self) -> chat.AsyncChatWithRawResponse: - from .resources.chat import AsyncChatWithRawResponse - - return AsyncChatWithRawResponse(self._client.chat) - - @cached_property - def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: - from .resources.embeddings import AsyncEmbeddingsWithRawResponse - - return AsyncEmbeddingsWithRawResponse(self._client.embeddings) - - @cached_property - def files(self) -> files.AsyncFilesWithRawResponse: - from .resources.files import AsyncFilesWithRawResponse - - return AsyncFilesWithRawResponse(self._client.files) - - @cached_property - def images(self) -> images.AsyncImagesWithRawResponse: - from .resources.images import AsyncImagesWithRawResponse - - return AsyncImagesWithRawResponse(self._client.images) - - @cached_property - def audio(self) -> audio.AsyncAudioWithRawResponse: - from .resources.audio import AsyncAudioWithRawResponse - - return AsyncAudioWithRawResponse(self._client.audio) - - @cached_property - def moderations(self) -> moderations.AsyncModerationsWithRawResponse: - from .resources.moderations import AsyncModerationsWithRawResponse - - return AsyncModerationsWithRawResponse(self._client.moderations) - - @cached_property - def models(self) -> models.AsyncModelsWithRawResponse: - from .resources.models import AsyncModelsWithRawResponse - - return AsyncModelsWithRawResponse(self._client.models) - - @cached_property - def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithRawResponse: - from .resources.fine_tuning import AsyncFineTuningWithRawResponse - - return AsyncFineTuningWithRawResponse(self._client.fine_tuning) - - @cached_property - def vector_stores(self) -> vector_stores.AsyncVectorStoresWithRawResponse: - from .resources.vector_stores import AsyncVectorStoresWithRawResponse - - return AsyncVectorStoresWithRawResponse(self._client.vector_stores) - - @cached_property - def beta(self) -> beta.AsyncBetaWithRawResponse: - from .resources.beta import AsyncBetaWithRawResponse - - return AsyncBetaWithRawResponse(self._client.beta) - - @cached_property - def batches(self) -> batches.AsyncBatchesWithRawResponse: - from .resources.batches import AsyncBatchesWithRawResponse - - return AsyncBatchesWithRawResponse(self._client.batches) - - @cached_property - def uploads(self) -> uploads.AsyncUploadsWithRawResponse: - from .resources.uploads import AsyncUploadsWithRawResponse - - return AsyncUploadsWithRawResponse(self._client.uploads) - - @cached_property - def responses(self) -> responses.AsyncResponsesWithRawResponse: - from .resources.responses import AsyncResponsesWithRawResponse - - return AsyncResponsesWithRawResponse(self._client.responses) - - @cached_property - def realtime(self) -> realtime.AsyncRealtimeWithRawResponse: - from .resources.realtime import AsyncRealtimeWithRawResponse - - return AsyncRealtimeWithRawResponse(self._client.realtime) - - @cached_property - def conversations(self) -> conversations.AsyncConversationsWithRawResponse: - from .resources.conversations import AsyncConversationsWithRawResponse - - return AsyncConversationsWithRawResponse(self._client.conversations) - - @cached_property - def evals(self) -> evals.AsyncEvalsWithRawResponse: - from .resources.evals import AsyncEvalsWithRawResponse - - return AsyncEvalsWithRawResponse(self._client.evals) - - @cached_property - def containers(self) -> containers.AsyncContainersWithRawResponse: - from .resources.containers import AsyncContainersWithRawResponse - - return AsyncContainersWithRawResponse(self._client.containers) - - @cached_property - def videos(self) -> videos.AsyncVideosWithRawResponse: - from .resources.videos import AsyncVideosWithRawResponse - - return AsyncVideosWithRawResponse(self._client.videos) - - -class OpenAIWithStreamedResponse: - _client: OpenAI - - def __init__(self, client: OpenAI) -> None: - self._client = client - - @cached_property - def completions(self) -> completions.CompletionsWithStreamingResponse: - from .resources.completions import CompletionsWithStreamingResponse - - return CompletionsWithStreamingResponse(self._client.completions) - - @cached_property - def chat(self) -> chat.ChatWithStreamingResponse: - from .resources.chat import ChatWithStreamingResponse - - return ChatWithStreamingResponse(self._client.chat) - - @cached_property - def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: - from .resources.embeddings import EmbeddingsWithStreamingResponse - - return EmbeddingsWithStreamingResponse(self._client.embeddings) - - @cached_property - def files(self) -> files.FilesWithStreamingResponse: - from .resources.files import FilesWithStreamingResponse - - return FilesWithStreamingResponse(self._client.files) - - @cached_property - def images(self) -> images.ImagesWithStreamingResponse: - from .resources.images import ImagesWithStreamingResponse - - return ImagesWithStreamingResponse(self._client.images) - - @cached_property - def audio(self) -> audio.AudioWithStreamingResponse: - from .resources.audio import AudioWithStreamingResponse - - return AudioWithStreamingResponse(self._client.audio) - - @cached_property - def moderations(self) -> moderations.ModerationsWithStreamingResponse: - from .resources.moderations import ModerationsWithStreamingResponse - - return ModerationsWithStreamingResponse(self._client.moderations) - - @cached_property - def models(self) -> models.ModelsWithStreamingResponse: - from .resources.models import ModelsWithStreamingResponse - - return ModelsWithStreamingResponse(self._client.models) - - @cached_property - def fine_tuning(self) -> fine_tuning.FineTuningWithStreamingResponse: - from .resources.fine_tuning import FineTuningWithStreamingResponse - - return FineTuningWithStreamingResponse(self._client.fine_tuning) - - @cached_property - def vector_stores(self) -> vector_stores.VectorStoresWithStreamingResponse: - from .resources.vector_stores import VectorStoresWithStreamingResponse - - return VectorStoresWithStreamingResponse(self._client.vector_stores) - - @cached_property - def beta(self) -> beta.BetaWithStreamingResponse: - from .resources.beta import BetaWithStreamingResponse - - return BetaWithStreamingResponse(self._client.beta) - - @cached_property - def batches(self) -> batches.BatchesWithStreamingResponse: - from .resources.batches import BatchesWithStreamingResponse - - return BatchesWithStreamingResponse(self._client.batches) - - @cached_property - def uploads(self) -> uploads.UploadsWithStreamingResponse: - from .resources.uploads import UploadsWithStreamingResponse - - return UploadsWithStreamingResponse(self._client.uploads) - - @cached_property - def responses(self) -> responses.ResponsesWithStreamingResponse: - from .resources.responses import ResponsesWithStreamingResponse - - return ResponsesWithStreamingResponse(self._client.responses) - - @cached_property - def realtime(self) -> realtime.RealtimeWithStreamingResponse: - from .resources.realtime import RealtimeWithStreamingResponse - - return RealtimeWithStreamingResponse(self._client.realtime) - - @cached_property - def conversations(self) -> conversations.ConversationsWithStreamingResponse: - from .resources.conversations import ConversationsWithStreamingResponse - - return ConversationsWithStreamingResponse(self._client.conversations) - - @cached_property - def evals(self) -> evals.EvalsWithStreamingResponse: - from .resources.evals import EvalsWithStreamingResponse - - return EvalsWithStreamingResponse(self._client.evals) - - @cached_property - def containers(self) -> containers.ContainersWithStreamingResponse: - from .resources.containers import ContainersWithStreamingResponse - - return ContainersWithStreamingResponse(self._client.containers) - - @cached_property - def videos(self) -> videos.VideosWithStreamingResponse: - from .resources.videos import VideosWithStreamingResponse - - return VideosWithStreamingResponse(self._client.videos) - - -class AsyncOpenAIWithStreamedResponse: - _client: AsyncOpenAI - - def __init__(self, client: AsyncOpenAI) -> None: - self._client = client - - @cached_property - def completions(self) -> completions.AsyncCompletionsWithStreamingResponse: - from .resources.completions import AsyncCompletionsWithStreamingResponse - - return AsyncCompletionsWithStreamingResponse(self._client.completions) - - @cached_property - def chat(self) -> chat.AsyncChatWithStreamingResponse: - from .resources.chat import AsyncChatWithStreamingResponse - - return AsyncChatWithStreamingResponse(self._client.chat) - - @cached_property - def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: - from .resources.embeddings import AsyncEmbeddingsWithStreamingResponse - - return AsyncEmbeddingsWithStreamingResponse(self._client.embeddings) - - @cached_property - def files(self) -> files.AsyncFilesWithStreamingResponse: - from .resources.files import AsyncFilesWithStreamingResponse - - return AsyncFilesWithStreamingResponse(self._client.files) - - @cached_property - def images(self) -> images.AsyncImagesWithStreamingResponse: - from .resources.images import AsyncImagesWithStreamingResponse - - return AsyncImagesWithStreamingResponse(self._client.images) - - @cached_property - def audio(self) -> audio.AsyncAudioWithStreamingResponse: - from .resources.audio import AsyncAudioWithStreamingResponse - - return AsyncAudioWithStreamingResponse(self._client.audio) - - @cached_property - def moderations(self) -> moderations.AsyncModerationsWithStreamingResponse: - from .resources.moderations import AsyncModerationsWithStreamingResponse - - return AsyncModerationsWithStreamingResponse(self._client.moderations) - - @cached_property - def models(self) -> models.AsyncModelsWithStreamingResponse: - from .resources.models import AsyncModelsWithStreamingResponse - - return AsyncModelsWithStreamingResponse(self._client.models) - - @cached_property - def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithStreamingResponse: - from .resources.fine_tuning import AsyncFineTuningWithStreamingResponse - - return AsyncFineTuningWithStreamingResponse(self._client.fine_tuning) - - @cached_property - def vector_stores(self) -> vector_stores.AsyncVectorStoresWithStreamingResponse: - from .resources.vector_stores import AsyncVectorStoresWithStreamingResponse - - return AsyncVectorStoresWithStreamingResponse(self._client.vector_stores) - - @cached_property - def beta(self) -> beta.AsyncBetaWithStreamingResponse: - from .resources.beta import AsyncBetaWithStreamingResponse - - return AsyncBetaWithStreamingResponse(self._client.beta) - - @cached_property - def batches(self) -> batches.AsyncBatchesWithStreamingResponse: - from .resources.batches import AsyncBatchesWithStreamingResponse - - return AsyncBatchesWithStreamingResponse(self._client.batches) - - @cached_property - def uploads(self) -> uploads.AsyncUploadsWithStreamingResponse: - from .resources.uploads import AsyncUploadsWithStreamingResponse - - return AsyncUploadsWithStreamingResponse(self._client.uploads) - - @cached_property - def responses(self) -> responses.AsyncResponsesWithStreamingResponse: - from .resources.responses import AsyncResponsesWithStreamingResponse - - return AsyncResponsesWithStreamingResponse(self._client.responses) - - @cached_property - def realtime(self) -> realtime.AsyncRealtimeWithStreamingResponse: - from .resources.realtime import AsyncRealtimeWithStreamingResponse - - return AsyncRealtimeWithStreamingResponse(self._client.realtime) - - @cached_property - def conversations(self) -> conversations.AsyncConversationsWithStreamingResponse: - from .resources.conversations import AsyncConversationsWithStreamingResponse - - return AsyncConversationsWithStreamingResponse(self._client.conversations) - - @cached_property - def evals(self) -> evals.AsyncEvalsWithStreamingResponse: - from .resources.evals import AsyncEvalsWithStreamingResponse - - return AsyncEvalsWithStreamingResponse(self._client.evals) - - @cached_property - def containers(self) -> containers.AsyncContainersWithStreamingResponse: - from .resources.containers import AsyncContainersWithStreamingResponse - - return AsyncContainersWithStreamingResponse(self._client.containers) - - @cached_property - def videos(self) -> videos.AsyncVideosWithStreamingResponse: - from .resources.videos import AsyncVideosWithStreamingResponse - - return AsyncVideosWithStreamingResponse(self._client.videos) - - -Client = OpenAI - -AsyncClient = AsyncOpenAI diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_compat.py b/backend/venv39/lib/python3.9/site-packages/openai/_compat.py deleted file mode 100644 index 73a1f3e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_compat.py +++ /dev/null @@ -1,231 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload -from datetime import date, datetime -from typing_extensions import Self, Literal - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import IncEx, StrBytesIntFloat - -_T = TypeVar("_T") -_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) - -# --------------- Pydantic v2, v3 compatibility --------------- - -# Pyright incorrectly reports some of our functions as overriding a method when they don't -# pyright: reportIncompatibleMethodOverride=false - -PYDANTIC_V1 = pydantic.VERSION.startswith("1.") - -if TYPE_CHECKING: - - def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 - ... - - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 - ... - - def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 - ... - - def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 - ... - - def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 - ... - - def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 - ... - - def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 - ... - -else: - # v1 re-exports - if PYDANTIC_V1: - from pydantic.typing import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, - ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime - else: - from ._utils import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - parse_date as parse_date, - is_typeddict as is_typeddict, - parse_datetime as parse_datetime, - is_literal_type as is_literal_type, - ) - - -# refactored config -if TYPE_CHECKING: - from pydantic import ConfigDict as ConfigDict -else: - if PYDANTIC_V1: - # TODO: provide an error message here? - ConfigDict = None - else: - from pydantic import ConfigDict as ConfigDict - - -# renamed methods / properties -def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V1: - return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - else: - return model.model_validate(value) - - -def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V1: - return field.required # type: ignore - return field.is_required() - - -def field_get_default(field: FieldInfo) -> Any: - value = field.get_default() - if PYDANTIC_V1: - return value - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None - return value - - -def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V1: - return field.outer_type_ # type: ignore - return field.annotation - - -def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V1: - return model.__config__ # type: ignore - return model.model_config - - -def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V1: - return model.__fields__ # type: ignore - return model.model_fields - - -def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V1: - return model.copy(deep=deep) # type: ignore - return model.model_copy(deep=deep) - - -def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V1: - return model.json(indent=indent) # type: ignore - return model.model_dump_json(indent=indent) - - -def model_dump( - model: pydantic.BaseModel, - *, - exclude: IncEx | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - warnings: bool = True, - mode: Literal["json", "python"] = "python", -) -> dict[str, Any]: - if (not PYDANTIC_V1) or hasattr(model, "model_dump"): - return model.model_dump( - mode=mode, - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - # warnings are not supported in Pydantic v1 - warnings=True if PYDANTIC_V1 else warnings, - ) - return cast( - "dict[str, Any]", - model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - ), - ) - - -def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V1: - return model.parse_obj(data) # pyright: ignore[reportDeprecated] - return model.model_validate(data) - - -def model_parse_json(model: type[_ModelT], data: str | bytes) -> _ModelT: - if PYDANTIC_V1: - return model.parse_raw(data) # pyright: ignore[reportDeprecated] - return model.model_validate_json(data) - - -def model_json_schema(model: type[_ModelT]) -> dict[str, Any]: - if PYDANTIC_V1: - return model.schema() # pyright: ignore[reportDeprecated] - return model.model_json_schema() - - -# generic models -if TYPE_CHECKING: - - class GenericModel(pydantic.BaseModel): ... - -else: - if PYDANTIC_V1: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - else: - # there no longer needs to be a distinction in v2 but - # we still have to create our own subclass to avoid - # inconsistent MRO ordering errors - class GenericModel(pydantic.BaseModel): ... - - -# cached properties -if TYPE_CHECKING: - cached_property = property - - # we define a separate type (copied from typeshed) - # that represents that `cached_property` is `set`able - # at runtime, which differs from `@property`. - # - # this is a separate type as editors likely special case - # `@property` and we don't want to cause issues just to have - # more helpful internal types. - - class typed_cached_property(Generic[_T]): - func: Callable[[Any], _T] - attrname: str | None - - def __init__(self, func: Callable[[Any], _T]) -> None: ... - - @overload - def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... - - @overload - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... - - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: - raise NotImplementedError() - - def __set_name__(self, owner: type[Any], name: str) -> None: ... - - # __set__ is not defined at runtime, but @cached_property is designed to be settable - def __set__(self, instance: object, value: _T) -> None: ... -else: - from functools import cached_property as cached_property - - typed_cached_property = cached_property diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_constants.py b/backend/venv39/lib/python3.9/site-packages/openai/_constants.py deleted file mode 100644 index 7029dc7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_constants.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import httpx - -RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" -OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" - -# default timeout is 10 minutes -DEFAULT_TIMEOUT = httpx.Timeout(timeout=600, connect=5.0) -DEFAULT_MAX_RETRIES = 2 -DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=1000, max_keepalive_connections=100) - -INITIAL_RETRY_DELAY = 0.5 -MAX_RETRY_DELAY = 8.0 diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_exceptions.py b/backend/venv39/lib/python3.9/site-packages/openai/_exceptions.py deleted file mode 100644 index 09016df..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_exceptions.py +++ /dev/null @@ -1,161 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Optional, cast -from typing_extensions import Literal - -import httpx - -from ._utils import is_dict -from ._models import construct_type - -if TYPE_CHECKING: - from .types.chat import ChatCompletion - -__all__ = [ - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", - "LengthFinishReasonError", - "ContentFilterFinishReasonError", - "InvalidWebhookSignatureError", -] - - -class OpenAIError(Exception): - pass - - -class APIError(OpenAIError): - message: str - request: httpx.Request - - body: object | None - """The API response body. - - If the API responded with a valid JSON structure then this property will be the - decoded result. - - If it isn't a valid JSON structure then this will be the raw response. - - If there was no response associated with this error then it will be `None`. - """ - - code: Optional[str] = None - param: Optional[str] = None - type: Optional[str] - - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: - super().__init__(message) - self.request = request - self.message = message - self.body = body - - if is_dict(body): - self.code = cast(Any, construct_type(type_=Optional[str], value=body.get("code"))) - self.param = cast(Any, construct_type(type_=Optional[str], value=body.get("param"))) - self.type = cast(Any, construct_type(type_=str, value=body.get("type"))) - else: - self.code = None - self.param = None - self.type = None - - -class APIResponseValidationError(APIError): - response: httpx.Response - status_code: int - - def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: - super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) - self.response = response - self.status_code = response.status_code - - -class APIStatusError(APIError): - """Raised when an API response has a status code of 4xx or 5xx.""" - - response: httpx.Response - status_code: int - request_id: str | None - - def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: - super().__init__(message, response.request, body=body) - self.response = response - self.status_code = response.status_code - self.request_id = response.headers.get("x-request-id") - - -class APIConnectionError(APIError): - def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: - super().__init__(message, request, body=None) - - -class APITimeoutError(APIConnectionError): - def __init__(self, request: httpx.Request) -> None: - super().__init__(message="Request timed out.", request=request) - - -class BadRequestError(APIStatusError): - status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] - - -class AuthenticationError(APIStatusError): - status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] - - -class PermissionDeniedError(APIStatusError): - status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] - - -class NotFoundError(APIStatusError): - status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] - - -class ConflictError(APIStatusError): - status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] - - -class UnprocessableEntityError(APIStatusError): - status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] - - -class RateLimitError(APIStatusError): - status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] - - -class InternalServerError(APIStatusError): - pass - - -class LengthFinishReasonError(OpenAIError): - completion: ChatCompletion - """The completion that caused this error. - - Note: this will *not* be a complete `ChatCompletion` object when streaming as `usage` - will not be included. - """ - - def __init__(self, *, completion: ChatCompletion) -> None: - msg = "Could not parse response content as the length limit was reached" - if completion.usage: - msg += f" - {completion.usage}" - - super().__init__(msg) - self.completion = completion - - -class ContentFilterFinishReasonError(OpenAIError): - def __init__(self) -> None: - super().__init__( - f"Could not parse response content as the request was rejected by the content filter", - ) - - -class InvalidWebhookSignatureError(ValueError): - """Raised when a webhook signature is invalid, meaning the computed signature does not match the expected signature.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_extras/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/_extras/__init__.py deleted file mode 100644 index 692de24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_extras/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .numpy_proxy import numpy as numpy, has_numpy as has_numpy -from .pandas_proxy import pandas as pandas -from .sounddevice_proxy import sounddevice as sounddevice diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_extras/_common.py b/backend/venv39/lib/python3.9/site-packages/openai/_extras/_common.py deleted file mode 100644 index 6e71720..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_extras/_common.py +++ /dev/null @@ -1,21 +0,0 @@ -from .._exceptions import OpenAIError - -INSTRUCTIONS = """ - -OpenAI error: - - missing `{library}` - -This feature requires additional dependencies: - - $ pip install openai[{extra}] - -""" - - -def format_instructions(*, library: str, extra: str) -> str: - return INSTRUCTIONS.format(library=library, extra=extra) - - -class MissingDependencyError(OpenAIError): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_extras/numpy_proxy.py b/backend/venv39/lib/python3.9/site-packages/openai/_extras/numpy_proxy.py deleted file mode 100644 index 2b06695..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_extras/numpy_proxy.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from typing_extensions import override - -from .._utils import LazyProxy -from ._common import MissingDependencyError, format_instructions - -if TYPE_CHECKING: - import numpy as numpy - - -NUMPY_INSTRUCTIONS = format_instructions(library="numpy", extra="voice_helpers") - - -class NumpyProxy(LazyProxy[Any]): - @override - def __load__(self) -> Any: - try: - import numpy - except ImportError as err: - raise MissingDependencyError(NUMPY_INSTRUCTIONS) from err - - return numpy - - -if not TYPE_CHECKING: - numpy = NumpyProxy() - - -def has_numpy() -> bool: - try: - import numpy # noqa: F401 # pyright: ignore[reportUnusedImport] - except ImportError: - return False - - return True diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_extras/pandas_proxy.py b/backend/venv39/lib/python3.9/site-packages/openai/_extras/pandas_proxy.py deleted file mode 100644 index 686377b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_extras/pandas_proxy.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from typing_extensions import override - -from .._utils import LazyProxy -from ._common import MissingDependencyError, format_instructions - -if TYPE_CHECKING: - import pandas as pandas - - -PANDAS_INSTRUCTIONS = format_instructions(library="pandas", extra="datalib") - - -class PandasProxy(LazyProxy[Any]): - @override - def __load__(self) -> Any: - try: - import pandas - except ImportError as err: - raise MissingDependencyError(PANDAS_INSTRUCTIONS) from err - - return pandas - - -if not TYPE_CHECKING: - pandas = PandasProxy() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_extras/sounddevice_proxy.py b/backend/venv39/lib/python3.9/site-packages/openai/_extras/sounddevice_proxy.py deleted file mode 100644 index 482d4c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_extras/sounddevice_proxy.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from typing_extensions import override - -from .._utils import LazyProxy -from ._common import MissingDependencyError, format_instructions - -if TYPE_CHECKING: - import sounddevice as sounddevice # type: ignore - - -SOUNDDEVICE_INSTRUCTIONS = format_instructions(library="sounddevice", extra="voice_helpers") - - -class SounddeviceProxy(LazyProxy[Any]): - @override - def __load__(self) -> Any: - try: - import sounddevice # type: ignore - except ImportError as err: - raise MissingDependencyError(SOUNDDEVICE_INSTRUCTIONS) from err - - return sounddevice - - -if not TYPE_CHECKING: - sounddevice = SounddeviceProxy() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_files.py b/backend/venv39/lib/python3.9/site-packages/openai/_files.py deleted file mode 100644 index 7b23ca0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_files.py +++ /dev/null @@ -1,123 +0,0 @@ -from __future__ import annotations - -import io -import os -import pathlib -from typing import overload -from typing_extensions import TypeGuard - -import anyio - -from ._types import ( - FileTypes, - FileContent, - RequestFiles, - HttpxFileTypes, - Base64FileInput, - HttpxFileContent, - HttpxRequestFiles, -) -from ._utils import is_tuple_t, is_mapping_t, is_sequence_t - - -def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: - return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - - -def is_file_content(obj: object) -> TypeGuard[FileContent]: - return ( - isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - ) - - -def assert_is_file_content(obj: object, *, key: str | None = None) -> None: - if not is_file_content(obj): - prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" - raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/openai/openai-python/tree/main#file-uploads" - ) from None - - -@overload -def to_httpx_files(files: None) -> None: ... - - -@overload -def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: _transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, _transform_file(file)) for key, file in files] - else: - raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -def _transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = pathlib.Path(file) - return (path.name, path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -def read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return pathlib.Path(file).read_bytes() - return file - - -@overload -async def async_to_httpx_files(files: None) -> None: ... - - -@overload -async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: await _async_transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, await _async_transform_file(file)) for key, file in files] - else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = anyio.Path(file) - return (path.name, await path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], await async_read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -async def async_read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return await anyio.Path(file).read_bytes() - - return file diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_legacy_response.py b/backend/venv39/lib/python3.9/site-packages/openai/_legacy_response.py deleted file mode 100644 index cfabaa2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_legacy_response.py +++ /dev/null @@ -1,488 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import logging -import datetime -import functools -from typing import ( - TYPE_CHECKING, - Any, - Union, - Generic, - TypeVar, - Callable, - Iterator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Awaitable, ParamSpec, override, deprecated, get_origin - -import anyio -import httpx -import pydantic - -from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type -from ._models import BaseModel, is_basemodel, add_request_id -from ._constants import RAW_RESPONSE_HEADER -from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type -from ._exceptions import APIResponseValidationError - -if TYPE_CHECKING: - from ._models import FinalRequestOptions - from ._base_client import BaseClient - - -P = ParamSpec("P") -R = TypeVar("R") -_T = TypeVar("_T") - -log: logging.Logger = logging.getLogger(__name__) - - -class LegacyAPIResponse(Generic[R]): - """This is a legacy class as it will be replaced by `APIResponse` - and `AsyncAPIResponse` in the `_response.py` file in the next major - release. - - For the sync client this will mostly be the same with the exception - of `content` & `text` will be methods instead of properties. In the - async client, all methods will be async. - - A migration script will be provided & the migration in general should - be smooth. - """ - - _cast_to: type[R] - _client: BaseClient[Any, Any] - _parsed_by_type: dict[type[Any], Any] - _stream: bool - _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None - _options: FinalRequestOptions - - http_response: httpx.Response - - retries_taken: int - """The number of retries made. If no retries happened this will be `0`""" - - def __init__( - self, - *, - raw: httpx.Response, - cast_to: type[R], - client: BaseClient[Any, Any], - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - options: FinalRequestOptions, - retries_taken: int = 0, - ) -> None: - self._cast_to = cast_to - self._client = client - self._parsed_by_type = {} - self._stream = stream - self._stream_cls = stream_cls - self._options = options - self.http_response = raw - self.retries_taken = retries_taken - - @property - def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] - - @overload - def parse(self, *, to: type[_T]) -> _T: ... - - @overload - def parse(self) -> R: ... - - def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - NOTE: For the async client: this will become a coroutine in the next major version. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from openai import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `int` - - `float` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - if isinstance(parsed, BaseModel): - add_request_id(parsed, self.request_id) - - self._parsed_by_type[cache_key] = parsed - return cast(R, parsed) - - @property - def headers(self) -> httpx.Headers: - return self.http_response.headers - - @property - def http_request(self) -> httpx.Request: - return self.http_response.request - - @property - def status_code(self) -> int: - return self.http_response.status_code - - @property - def url(self) -> httpx.URL: - return self.http_response.url - - @property - def method(self) -> str: - return self.http_request.method - - @property - def content(self) -> bytes: - """Return the binary response content. - - NOTE: this will be removed in favour of `.read()` in the - next major version. - """ - return self.http_response.content - - @property - def text(self) -> str: - """Return the decoded response content. - - NOTE: this will be turned into a method in the next major version. - """ - return self.http_response.text - - @property - def http_version(self) -> str: - return self.http_response.http_version - - @property - def is_closed(self) -> bool: - return self.http_response.is_closed - - @property - def elapsed(self) -> datetime.timedelta: - """The time taken for the complete request/response cycle to complete.""" - return self.http_response.elapsed - - def _parse(self, *, to: type[_T] | None = None) -> R | _T: - cast_to = to if to is not None else self._cast_to - - # unwrap `TypeAlias('Name', T)` -> `T` - if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if cast_to and is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - - origin = get_origin(cast_to) or cast_to - - if self._stream: - if to: - if not is_stream_class_type(to): - raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") - - return cast( - _T, - to( - cast_to=extract_stream_chunk_type( - to, - failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", - ), - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - if self._stream_cls: - return cast( - R, - self._stream_cls( - cast_to=extract_stream_chunk_type(self._stream_cls), - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) - if stream_cls is None: - raise MissingStreamClassError() - - return cast( - R, - stream_cls( - cast_to=cast_to, - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - if cast_to is NoneType: - return cast(R, None) - - response = self.http_response - if cast_to == str: - return cast(R, response.text) - - if cast_to == int: - return cast(R, int(response.text)) - - if cast_to == float: - return cast(R, float(response.text)) - - if cast_to == bool: - return cast(R, response.text.lower() == "true") - - if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): - return cast(R, cast_to(response)) # type: ignore - - if origin == LegacyAPIResponse: - raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - - if inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) and issubclass(origin, httpx.Response): - # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response - # and pass that class to our request functions. We cannot change the variance to be either - # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct - # the response class ourselves but that is something that should be supported directly in httpx - # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. - if cast_to != httpx.Response: - raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") - return cast(R, response) - - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): - raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") - - if ( - cast_to is not object - and not origin is list - and not origin is dict - and not origin is Union - and not issubclass(origin, BaseModel) - ): - raise RuntimeError( - f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." - ) - - # split is required to handle cases where additional information is included - # in the response, e.g. application/json; charset=utf-8 - content_type, *_ = response.headers.get("content-type", "*").split(";") - if not content_type.endswith("json"): - if is_basemodel(cast_to): - try: - data = response.json() - except Exception as exc: - log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) - else: - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - if self._client._strict_response_validation: - raise APIResponseValidationError( - response=response, - message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", - body=response.text, - ) - - # If the API responds with content that isn't JSON then we just return - # the (decoded) text without performing any parsing so that you can still - # handle the response however you need to. - return response.text # type: ignore - - data = response.json() - - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - @override - def __repr__(self) -> str: - return f"" - - -class MissingStreamClassError(TypeError): - def __init__(self) -> None: - super().__init__( - "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `openai._streaming` for reference", - ) - - -def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, LegacyAPIResponse[R]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "true" - - kwargs["extra_headers"] = extra_headers - - return cast(LegacyAPIResponse[R], func(*args, **kwargs)) - - return wrapped - - -def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[LegacyAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - async def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "true" - - kwargs["extra_headers"] = extra_headers - - return cast(LegacyAPIResponse[R], await func(*args, **kwargs)) - - return wrapped - - -class HttpxBinaryResponseContent: - response: httpx.Response - - def __init__(self, response: httpx.Response) -> None: - self.response = response - - @property - def content(self) -> bytes: - return self.response.content - - @property - def text(self) -> str: - return self.response.text - - @property - def encoding(self) -> str | None: - return self.response.encoding - - @property - def charset_encoding(self) -> str | None: - return self.response.charset_encoding - - def json(self, **kwargs: Any) -> Any: - return self.response.json(**kwargs) - - def read(self) -> bytes: - return self.response.read() - - def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: - return self.response.iter_bytes(chunk_size) - - def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: - return self.response.iter_text(chunk_size) - - def iter_lines(self) -> Iterator[str]: - return self.response.iter_lines() - - def iter_raw(self, chunk_size: int | None = None) -> Iterator[bytes]: - return self.response.iter_raw(chunk_size) - - def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `client.with_streaming_response.foo().stream_to_file('my_filename.txt')` - """ - with open(file, mode="wb") as f: - for data in self.response.iter_bytes(): - f.write(data) - - @deprecated( - "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead" - ) - def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - with open(file, mode="wb") as f: - for data in self.response.iter_bytes(chunk_size): - f.write(data) - - def close(self) -> None: - return self.response.close() - - async def aread(self) -> bytes: - return await self.response.aread() - - async def aiter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: - return self.response.aiter_bytes(chunk_size) - - async def aiter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: - return self.response.aiter_text(chunk_size) - - async def aiter_lines(self) -> AsyncIterator[str]: - return self.response.aiter_lines() - - async def aiter_raw(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: - return self.response.aiter_raw(chunk_size) - - @deprecated( - "Due to a bug, this method doesn't actually stream the response content, `.with_streaming_response.method()` should be used instead" - ) - async def astream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.response.aiter_bytes(chunk_size): - await f.write(data) - - async def aclose(self) -> None: - return await self.response.aclose() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_models.py b/backend/venv39/lib/python3.9/site-packages/openai/_models.py deleted file mode 100644 index fac59c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_models.py +++ /dev/null @@ -1,897 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import weakref -from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast -from datetime import date, datetime -from typing_extensions import ( - List, - Unpack, - Literal, - ClassVar, - Protocol, - Required, - Sequence, - ParamSpec, - TypedDict, - TypeGuard, - final, - override, - runtime_checkable, -) - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import ( - Body, - IncEx, - Query, - ModelT, - Headers, - Timeout, - NotGiven, - AnyMapping, - HttpxRequestFiles, -) -from ._utils import ( - PropertyInfo, - is_list, - is_given, - json_safe, - lru_cache, - is_mapping, - parse_date, - coerce_boolean, - parse_datetime, - strip_not_given, - extract_type_arg, - is_annotated_type, - is_type_alias_type, - strip_annotated_type, -) -from ._compat import ( - PYDANTIC_V1, - ConfigDict, - GenericModel as BaseGenericModel, - get_args, - is_union, - parse_obj, - get_origin, - is_literal_type, - get_model_config, - get_model_fields, - field_get_default, -) -from ._constants import RAW_RESPONSE_HEADER - -if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema - -__all__ = ["BaseModel", "GenericModel"] - -_T = TypeVar("_T") -_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") - -P = ParamSpec("P") - -ReprArgs = Sequence[Tuple[Optional[str], Any]] - - -@runtime_checkable -class _ConfigProtocol(Protocol): - allow_population_by_field_name: bool - - -class BaseModel(pydantic.BaseModel): - if PYDANTIC_V1: - - @property - @override - def model_fields_set(self) -> set[str]: - # a forwards-compat shim for pydantic v2 - return self.__fields_set__ # type: ignore - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = pydantic.Extra.allow # type: ignore - - @override - def __repr_args__(self) -> ReprArgs: - # we don't want these attributes to be included when something like `rich.print` is used - return [arg for arg in super().__repr_args__() if arg[0] not in {"_request_id", "__exclude_fields__"}] - else: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - - if TYPE_CHECKING: - _request_id: Optional[str] = None - """The ID of the request, returned via the X-Request-ID header. Useful for debugging requests and reporting issues to OpenAI. - - This will **only** be set for the top-level response object, it will not be defined for nested objects. For example: - - ```py - completion = await client.chat.completions.create(...) - completion._request_id # req_id_xxx - completion.usage._request_id # raises `AttributeError` - ``` - - Note: unlike other properties that use an `_` prefix, this property - *is* public. Unless documented otherwise, all other `_` prefix properties, - methods and modules are *private*. - """ - - def to_dict( - self, - *, - mode: Literal["json", "python"] = "python", - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> dict[str, object]: - """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - mode: - If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. - If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` - - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. - """ - return self.model_dump( - mode=mode, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - def to_json( - self, - *, - indent: int | None = 2, - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> str: - """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. - """ - return self.model_dump_json( - indent=indent, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - @override - def __str__(self) -> str: - # mypy complains about an invalid self arg - return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] - - # Override the 'construct' method in a way that supports recursive parsing without validation. - # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. - @classmethod - @override - def construct( # pyright: ignore[reportIncompatibleMethodOverride] - __cls: Type[ModelT], - _fields_set: set[str] | None = None, - **values: object, - ) -> ModelT: - m = __cls.__new__(__cls) - fields_values: dict[str, object] = {} - - config = get_model_config(__cls) - populate_by_name = ( - config.allow_population_by_field_name - if isinstance(config, _ConfigProtocol) - else config.get("populate_by_name") - ) - - if _fields_set is None: - _fields_set = set() - - model_fields = get_model_fields(__cls) - for name, field in model_fields.items(): - key = field.alias - if key is None or (key not in values and populate_by_name): - key = name - - if key in values: - fields_values[name] = _construct_field(value=values[key], field=field, key=key) - _fields_set.add(name) - else: - fields_values[name] = field_get_default(field) - - extra_field_type = _get_extra_fields_type(__cls) - - _extra = {} - for key, value in values.items(): - if key not in model_fields: - parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value - - if PYDANTIC_V1: - _fields_set.add(key) - fields_values[key] = parsed - else: - _extra[key] = parsed - - object.__setattr__(m, "__dict__", fields_values) - - if PYDANTIC_V1: - # init_private_attributes() does not exist in v2 - m._init_private_attributes() # type: ignore - - # copied from Pydantic v1's `construct()` method - object.__setattr__(m, "__fields_set__", _fields_set) - else: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - - return m - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - # because the type signatures are technically different - # although not in practice - model_construct = construct - - if PYDANTIC_V1: - # we define aliases for some of the new pydantic v2 methods so - # that we can just document these methods without having to specify - # a specific pydantic version as some users may not know which - # pydantic version they are currently using - - @override - def model_dump( - self, - *, - mode: Literal["json", "python"] | str = "python", - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> dict[str, Any]: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump - - Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - Args: - mode: The mode in which `to_python` should run. - If mode is 'json', the output will only contain JSON serializable types. - If mode is 'python', the output may contain non-JSON-serializable Python objects. - include: A set of fields to include in the output. - exclude: A set of fields to exclude from the output. - context: Additional context to pass to the serializer. - by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value. - exclude_none: Whether to exclude fields that have a value of `None`. - exclude_computed_fields: Whether to exclude computed fields. - While this can be useful for round-tripping, it is usually recommended to use the dedicated - `round_trip` parameter instead. - round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. - warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, - "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. - fallback: A function to call when an unknown value is encountered. If not provided, - a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. - serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. - - Returns: - A dictionary representation of the model. - """ - if mode not in {"json", "python"}: - raise ValueError("mode must be either 'json' or 'python'") - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - dumped = super().dict( # pyright: ignore[reportDeprecated] - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped - - @override - def model_dump_json( - self, - *, - indent: int | None = None, - ensure_ascii: bool = False, - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> str: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json - - Generates a JSON representation of the model using Pydantic's `to_json` method. - - Args: - indent: Indentation to use in the JSON output. If None is passed, the output will be compact. - include: Field(s) to include in the JSON output. Can take either a string or set of strings. - exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. - by_alias: Whether to serialize using field aliases. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - round_trip: Whether to use serialization/deserialization between JSON and class instance. - warnings: Whether to show any warnings that occurred during serialization. - - Returns: - A JSON string representation of the model. - """ - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if ensure_ascii != False: - raise ValueError("ensure_ascii is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - return super().json( # type: ignore[reportDeprecated] - indent=indent, - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - -def _construct_field(value: object, field: FieldInfo, key: str) -> object: - if value is None: - return field_get_default(field) - - if PYDANTIC_V1: - type_ = cast(type, field.outer_type_) # type: ignore - else: - type_ = field.annotation # type: ignore - - if type_ is None: - raise RuntimeError(f"Unexpected field type is None for {key}") - - return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) - - -def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if PYDANTIC_V1: - # TODO - return None - - schema = cls.__pydantic_core_schema__ - if schema["type"] == "model": - fields = schema["schema"] - if fields["type"] == "model-fields": - extras = fields.get("extras_schema") - if extras and "cls" in extras: - # mypy can't narrow the type - return extras["cls"] # type: ignore[no-any-return] - - return None - - -def is_basemodel(type_: type) -> bool: - """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" - if is_union(type_): - for variant in get_args(type_): - if is_basemodel(variant): - return True - - return False - - return is_basemodel_type(type_) - - -def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: - origin = get_origin(type_) or type_ - if not inspect.isclass(origin): - return False - return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) - - -def build( - base_model_cls: Callable[P, _BaseModelT], - *args: P.args, - **kwargs: P.kwargs, -) -> _BaseModelT: - """Construct a BaseModel class without validation. - - This is useful for cases where you need to instantiate a `BaseModel` - from an API response as this provides type-safe params which isn't supported - by helpers like `construct_type()`. - - ```py - build(MyModel, my_field_a="foo", my_field_b=123) - ``` - """ - if args: - raise TypeError( - "Received positional arguments which are not supported; Keyword arguments must be used instead", - ) - - return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) - - -def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: - """Loose coercion to the expected type with construction of nested values. - - Note: the returned value from this function is not guaranteed to match the - given type. - """ - return cast(_T, construct_type(value=value, type_=type_)) - - -def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: - """Loose coercion to the expected type with construction of nested values. - - If the given value does not match the expected type then it is returned as-is. - """ - - # store a reference to the original type we were given before we extract any inner - # types so that we can properly resolve forward references in `TypeAliasType` annotations - original_type = None - - # we allow `object` as the input type because otherwise, passing things like - # `Literal['value']` will be reported as a type error by type checkers - type_ = cast("type[object]", type_) - if is_type_alias_type(type_): - original_type = type_ # type: ignore[unreachable] - type_ = type_.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None and len(metadata) > 0: - meta: tuple[Any, ...] = tuple(metadata) - elif is_annotated_type(type_): - meta = get_args(type_)[1:] - type_ = extract_type_arg(type_, 0) - else: - meta = tuple() - - # we need to use the origin class for any types that are subscripted generics - # e.g. Dict[str, object] - origin = get_origin(type_) or type_ - args = get_args(type_) - - if is_union(origin): - try: - return validate_type(type_=cast("type[object]", original_type or type_), value=value) - except Exception: - pass - - # if the type is a discriminated union then we want to construct the right variant - # in the union, even if the data doesn't match exactly, otherwise we'd break code - # that relies on the constructed class types, e.g. - # - # class FooType: - # kind: Literal['foo'] - # value: str - # - # class BarType: - # kind: Literal['bar'] - # value: int - # - # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then - # we'd end up constructing `FooType` when it should be `BarType`. - discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) - if discriminator and is_mapping(value): - variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) - if variant_value and isinstance(variant_value, str): - variant_type = discriminator.mapping.get(variant_value) - if variant_type: - return construct_type(type_=variant_type, value=value) - - # if the data is not valid, use the first variant that doesn't fail while deserializing - for variant in args: - try: - return construct_type(value=value, type_=variant) - except Exception: - continue - - raise RuntimeError(f"Could not convert data into a valid instance of {type_}") - - if origin == dict: - if not is_mapping(value): - return value - - _, items_type = get_args(type_) # Dict[_, items_type] - return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - - if ( - not is_literal_type(type_) - and inspect.isclass(origin) - and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) - ): - if is_list(value): - return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] - - if is_mapping(value): - if issubclass(type_, BaseModel): - return type_.construct(**value) # type: ignore[arg-type] - - return cast(Any, type_).construct(**value) - - if origin == list: - if not is_list(value): - return value - - inner_type = args[0] # List[inner_type] - return [construct_type(value=entry, type_=inner_type) for entry in value] - - if origin == float: - if isinstance(value, int): - coerced = float(value) - if coerced != value: - return value - return coerced - - return value - - if type_ == datetime: - try: - return parse_datetime(value) # type: ignore - except Exception: - return value - - if type_ == date: - try: - return parse_date(value) # type: ignore - except Exception: - return value - - return value - - -@runtime_checkable -class CachedDiscriminatorType(Protocol): - __discriminator__: DiscriminatorDetails - - -DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() - - -class DiscriminatorDetails: - field_name: str - """The name of the discriminator field in the variant class, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] - ``` - - Will result in field_name='type' - """ - - field_alias_from: str | None - """The name of the discriminator field in the API response, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] = Field(alias='type_from_api') - ``` - - Will result in field_alias_from='type_from_api' - """ - - mapping: dict[str, type] - """Mapping of discriminator value to variant type, e.g. - - {'foo': FooVariant, 'bar': BarVariant} - """ - - def __init__( - self, - *, - mapping: dict[str, type], - discriminator_field: str, - discriminator_alias: str | None, - ) -> None: - self.mapping = mapping - self.field_name = discriminator_field - self.field_alias_from = discriminator_alias - - -def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - cached = DISCRIMINATOR_CACHE.get(union) - if cached is not None: - return cached - - discriminator_field_name: str | None = None - - for annotation in meta_annotations: - if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: - discriminator_field_name = annotation.discriminator - break - - if not discriminator_field_name: - return None - - mapping: dict[str, type] = {} - discriminator_alias: str | None = None - - for variant in get_args(union): - variant = strip_annotated_type(variant) - if is_basemodel_type(variant): - if PYDANTIC_V1: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias - - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): - if isinstance(entry, str): - mapping[entry] = variant - else: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] - - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: - if isinstance(entry, str): - mapping[entry] = variant - - if not mapping: - return None - - details = DiscriminatorDetails( - mapping=mapping, - discriminator_field=discriminator_field_name, - discriminator_alias=discriminator_alias, - ) - DISCRIMINATOR_CACHE.setdefault(union, details) - return details - - -def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: - schema = model.__pydantic_core_schema__ - if schema["type"] == "definitions": - schema = schema["schema"] - - if schema["type"] != "model": - return None - - schema = cast("ModelSchema", schema) - fields_schema = schema["schema"] - if fields_schema["type"] != "model-fields": - return None - - fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) - if not field: - return None - - return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] - - -def validate_type(*, type_: type[_T], value: object) -> _T: - """Strict validation that the given value matches the expected type""" - if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): - return cast(_T, parse_obj(type_, value)) - - return cast(_T, _validate_non_model_type(type_=type_, value=value)) - - -def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: - """Add a pydantic config for the given type. - - Note: this is a no-op on Pydantic v1. - """ - setattr(typ, "__pydantic_config__", config) # noqa: B010 - - -def add_request_id(obj: BaseModel, request_id: str | None) -> None: - obj._request_id = request_id - - # in Pydantic v1, using setattr like we do above causes the attribute - # to be included when serializing the model which we don't want in this - # case so we need to explicitly exclude it - if PYDANTIC_V1: - try: - exclude_fields = obj.__exclude_fields__ # type: ignore - except AttributeError: - cast(Any, obj).__exclude_fields__ = {"_request_id", "__exclude_fields__"} - else: - cast(Any, obj).__exclude_fields__ = {*(exclude_fields or {}), "_request_id", "__exclude_fields__"} - - -# our use of subclassing here causes weirdness for type checkers, -# so we just pretend that we don't subclass -if TYPE_CHECKING: - GenericModel = BaseModel -else: - - class GenericModel(BaseGenericModel, BaseModel): - pass - - -if not PYDANTIC_V1: - from pydantic import TypeAdapter as _TypeAdapter - - _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) - - if TYPE_CHECKING: - from pydantic import TypeAdapter - else: - TypeAdapter = _CachedTypeAdapter - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - return TypeAdapter(type_).validate_python(value) - -elif not TYPE_CHECKING: # TODO: condition is weird - - class RootModel(GenericModel, Generic[_T]): - """Used as a placeholder to easily convert runtime types to a Pydantic format - to provide validation. - - For example: - ```py - validated = RootModel[int](__root__="5").__root__ - # validated: 5 - ``` - """ - - __root__: _T - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - model = _create_pydantic_model(type_).validate(value) - return cast(_T, model.__root__) - - def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: - return RootModel[type_] # type: ignore - - -class FinalRequestOptionsInput(TypedDict, total=False): - method: Required[str] - url: Required[str] - params: Query - headers: Headers - max_retries: int - timeout: float | Timeout | None - files: HttpxRequestFiles | None - idempotency_key: str - json_data: Body - extra_json: AnyMapping - follow_redirects: bool - - -@final -class FinalRequestOptions(pydantic.BaseModel): - method: str - url: str - params: Query = {} - headers: Union[Headers, NotGiven] = NotGiven() - max_retries: Union[int, NotGiven] = NotGiven() - timeout: Union[float, Timeout, None, NotGiven] = NotGiven() - files: Union[HttpxRequestFiles, None] = None - idempotency_key: Union[str, None] = None - post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() - follow_redirects: Union[bool, None] = None - - # It should be noted that we cannot use `json` here as that would override - # a BaseModel method in an incompatible fashion. - json_data: Union[Body, None] = None - extra_json: Union[AnyMapping, None] = None - - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - arbitrary_types_allowed: bool = True - else: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - - def get_max_retries(self, max_retries: int) -> int: - if isinstance(self.max_retries, NotGiven): - return max_retries - return self.max_retries - - def _strip_raw_response_header(self) -> None: - if not is_given(self.headers): - return - - if self.headers.get(RAW_RESPONSE_HEADER): - self.headers = {**self.headers} - self.headers.pop(RAW_RESPONSE_HEADER) - - # override the `construct` method so that we can run custom transformations. - # this is necessary as we don't want to do any actual runtime type checking - # (which means we can't use validators) but we do want to ensure that `NotGiven` - # values are not present - # - # type ignore required because we're adding explicit types to `**values` - @classmethod - def construct( # type: ignore - cls, - _fields_set: set[str] | None = None, - **values: Unpack[FinalRequestOptionsInput], - ) -> FinalRequestOptions: - kwargs: dict[str, Any] = { - # we unconditionally call `strip_not_given` on any value - # as it will just ignore any non-mapping types - key: strip_not_given(value) - for key, value in values.items() - } - if PYDANTIC_V1: - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] - return super().model_construct(_fields_set, **kwargs) - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - model_construct = construct diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_module_client.py b/backend/venv39/lib/python3.9/site-packages/openai/_module_client.py deleted file mode 100644 index d0d7218..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_module_client.py +++ /dev/null @@ -1,173 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING -from typing_extensions import override - -if TYPE_CHECKING: - from .resources.files import Files - from .resources.images import Images - from .resources.models import Models - from .resources.videos import Videos - from .resources.batches import Batches - from .resources.webhooks import Webhooks - from .resources.beta.beta import Beta - from .resources.chat.chat import Chat - from .resources.embeddings import Embeddings - from .resources.audio.audio import Audio - from .resources.completions import Completions - from .resources.evals.evals import Evals - from .resources.moderations import Moderations - from .resources.uploads.uploads import Uploads - from .resources.realtime.realtime import Realtime - from .resources.responses.responses import Responses - from .resources.containers.containers import Containers - from .resources.fine_tuning.fine_tuning import FineTuning - from .resources.conversations.conversations import Conversations - from .resources.vector_stores.vector_stores import VectorStores - -from . import _load_client -from ._utils import LazyProxy - - -class ChatProxy(LazyProxy["Chat"]): - @override - def __load__(self) -> Chat: - return _load_client().chat - - -class BetaProxy(LazyProxy["Beta"]): - @override - def __load__(self) -> Beta: - return _load_client().beta - - -class FilesProxy(LazyProxy["Files"]): - @override - def __load__(self) -> Files: - return _load_client().files - - -class AudioProxy(LazyProxy["Audio"]): - @override - def __load__(self) -> Audio: - return _load_client().audio - - -class EvalsProxy(LazyProxy["Evals"]): - @override - def __load__(self) -> Evals: - return _load_client().evals - - -class ImagesProxy(LazyProxy["Images"]): - @override - def __load__(self) -> Images: - return _load_client().images - - -class ModelsProxy(LazyProxy["Models"]): - @override - def __load__(self) -> Models: - return _load_client().models - - -class VideosProxy(LazyProxy["Videos"]): - @override - def __load__(self) -> Videos: - return _load_client().videos - - -class BatchesProxy(LazyProxy["Batches"]): - @override - def __load__(self) -> Batches: - return _load_client().batches - - -class UploadsProxy(LazyProxy["Uploads"]): - @override - def __load__(self) -> Uploads: - return _load_client().uploads - - -class WebhooksProxy(LazyProxy["Webhooks"]): - @override - def __load__(self) -> Webhooks: - return _load_client().webhooks - - -class RealtimeProxy(LazyProxy["Realtime"]): - @override - def __load__(self) -> Realtime: - return _load_client().realtime - - -class ResponsesProxy(LazyProxy["Responses"]): - @override - def __load__(self) -> Responses: - return _load_client().responses - - -class EmbeddingsProxy(LazyProxy["Embeddings"]): - @override - def __load__(self) -> Embeddings: - return _load_client().embeddings - - -class ContainersProxy(LazyProxy["Containers"]): - @override - def __load__(self) -> Containers: - return _load_client().containers - - -class CompletionsProxy(LazyProxy["Completions"]): - @override - def __load__(self) -> Completions: - return _load_client().completions - - -class ModerationsProxy(LazyProxy["Moderations"]): - @override - def __load__(self) -> Moderations: - return _load_client().moderations - - -class FineTuningProxy(LazyProxy["FineTuning"]): - @override - def __load__(self) -> FineTuning: - return _load_client().fine_tuning - - -class VectorStoresProxy(LazyProxy["VectorStores"]): - @override - def __load__(self) -> VectorStores: - return _load_client().vector_stores - - -class ConversationsProxy(LazyProxy["Conversations"]): - @override - def __load__(self) -> Conversations: - return _load_client().conversations - - -chat: Chat = ChatProxy().__as_proxied__() -beta: Beta = BetaProxy().__as_proxied__() -files: Files = FilesProxy().__as_proxied__() -audio: Audio = AudioProxy().__as_proxied__() -evals: Evals = EvalsProxy().__as_proxied__() -images: Images = ImagesProxy().__as_proxied__() -models: Models = ModelsProxy().__as_proxied__() -videos: Videos = VideosProxy().__as_proxied__() -batches: Batches = BatchesProxy().__as_proxied__() -uploads: Uploads = UploadsProxy().__as_proxied__() -webhooks: Webhooks = WebhooksProxy().__as_proxied__() -realtime: Realtime = RealtimeProxy().__as_proxied__() -responses: Responses = ResponsesProxy().__as_proxied__() -embeddings: Embeddings = EmbeddingsProxy().__as_proxied__() -containers: Containers = ContainersProxy().__as_proxied__() -completions: Completions = CompletionsProxy().__as_proxied__() -moderations: Moderations = ModerationsProxy().__as_proxied__() -fine_tuning: FineTuning = FineTuningProxy().__as_proxied__() -vector_stores: VectorStores = VectorStoresProxy().__as_proxied__() -conversations: Conversations = ConversationsProxy().__as_proxied__() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_qs.py b/backend/venv39/lib/python3.9/site-packages/openai/_qs.py deleted file mode 100644 index ada6fd3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_qs.py +++ /dev/null @@ -1,150 +0,0 @@ -from __future__ import annotations - -from typing import Any, List, Tuple, Union, Mapping, TypeVar -from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args - -from ._types import NotGiven, not_given -from ._utils import flatten - -_T = TypeVar("_T") - - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - -PrimitiveData = Union[str, int, float, bool, None] -# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] -# https://github.com/microsoft/pyright/issues/3555 -Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] -Params = Mapping[str, Data] - - -class Querystring: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - *, - array_format: ArrayFormat = "repeat", - nested_format: NestedFormat = "brackets", - ) -> None: - self.array_format = array_format - self.nested_format = nested_format - - def parse(self, query: str) -> Mapping[str, object]: - # Note: custom format syntax is not supported yet - return parse_qs(query) - - def stringify( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> str: - return urlencode( - self.stringify_items( - params, - array_format=array_format, - nested_format=nested_format, - ) - ) - - def stringify_items( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> list[tuple[str, str]]: - opts = Options( - qs=self, - array_format=array_format, - nested_format=nested_format, - ) - return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) - - def _stringify_item( - self, - key: str, - value: Data, - opts: Options, - ) -> list[tuple[str, str]]: - if isinstance(value, Mapping): - items: list[tuple[str, str]] = [] - nested_format = opts.nested_format - for subkey, subvalue in value.items(): - items.extend( - self._stringify_item( - # TODO: error if unknown format - f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", - subvalue, - opts, - ) - ) - return items - - if isinstance(value, (list, tuple)): - array_format = opts.array_format - if array_format == "comma": - return [ - ( - key, - ",".join(self._primitive_value_to_str(item) for item in value if item is not None), - ), - ] - elif array_format == "repeat": - items = [] - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") - elif array_format == "brackets": - items = [] - key = key + "[]" - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - else: - raise NotImplementedError( - f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" - ) - - serialised = self._primitive_value_to_str(value) - if not serialised: - return [] - return [(key, serialised)] - - def _primitive_value_to_str(self, value: PrimitiveData) -> str: - # copied from httpx - if value is True: - return "true" - elif value is False: - return "false" - elif value is None: - return "" - return str(value) - - -_qs = Querystring() -parse = _qs.parse -stringify = _qs.stringify -stringify_items = _qs.stringify_items - - -class Options: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - qs: Querystring = _qs, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> None: - self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format - self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_resource.py b/backend/venv39/lib/python3.9/site-packages/openai/_resource.py deleted file mode 100644 index fff9ba1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_resource.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING - -import anyio - -if TYPE_CHECKING: - from ._client import OpenAI, AsyncOpenAI - - -class SyncAPIResource: - _client: OpenAI - - def __init__(self, client: OpenAI) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - def _sleep(self, seconds: float) -> None: - time.sleep(seconds) - - -class AsyncAPIResource: - _client: AsyncOpenAI - - def __init__(self, client: AsyncOpenAI) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - async def _sleep(self, seconds: float) -> None: - await anyio.sleep(seconds) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_response.py b/backend/venv39/lib/python3.9/site-packages/openai/_response.py deleted file mode 100644 index 350da38..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_response.py +++ /dev/null @@ -1,848 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import logging -import datetime -import functools -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Union, - Generic, - TypeVar, - Callable, - Iterator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Awaitable, ParamSpec, override, get_origin - -import anyio -import httpx -import pydantic - -from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base -from ._models import BaseModel, is_basemodel, add_request_id -from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER -from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type -from ._exceptions import OpenAIError, APIResponseValidationError - -if TYPE_CHECKING: - from ._models import FinalRequestOptions - from ._base_client import BaseClient - - -P = ParamSpec("P") -R = TypeVar("R") -_T = TypeVar("_T") -_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") -_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") - -log: logging.Logger = logging.getLogger(__name__) - - -class BaseAPIResponse(Generic[R]): - _cast_to: type[R] - _client: BaseClient[Any, Any] - _parsed_by_type: dict[type[Any], Any] - _is_sse_stream: bool - _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None - _options: FinalRequestOptions - - http_response: httpx.Response - - retries_taken: int - """The number of retries made. If no retries happened this will be `0`""" - - def __init__( - self, - *, - raw: httpx.Response, - cast_to: type[R], - client: BaseClient[Any, Any], - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - options: FinalRequestOptions, - retries_taken: int = 0, - ) -> None: - self._cast_to = cast_to - self._client = client - self._parsed_by_type = {} - self._is_sse_stream = stream - self._stream_cls = stream_cls - self._options = options - self.http_response = raw - self.retries_taken = retries_taken - - @property - def headers(self) -> httpx.Headers: - return self.http_response.headers - - @property - def http_request(self) -> httpx.Request: - """Returns the httpx Request instance associated with the current response.""" - return self.http_response.request - - @property - def status_code(self) -> int: - return self.http_response.status_code - - @property - def url(self) -> httpx.URL: - """Returns the URL for which the request was made.""" - return self.http_response.url - - @property - def method(self) -> str: - return self.http_request.method - - @property - def http_version(self) -> str: - return self.http_response.http_version - - @property - def elapsed(self) -> datetime.timedelta: - """The time taken for the complete request/response cycle to complete.""" - return self.http_response.elapsed - - @property - def is_closed(self) -> bool: - """Whether or not the response body has been closed. - - If this is False then there is response data that has not been read yet. - You must either fully consume the response body or call `.close()` - before discarding the response to prevent resource leaks. - """ - return self.http_response.is_closed - - @override - def __repr__(self) -> str: - return ( - f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" - ) - - def _parse(self, *, to: type[_T] | None = None) -> R | _T: - cast_to = to if to is not None else self._cast_to - - # unwrap `TypeAlias('Name', T)` -> `T` - if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if cast_to and is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - - origin = get_origin(cast_to) or cast_to - - if self._is_sse_stream: - if to: - if not is_stream_class_type(to): - raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") - - return cast( - _T, - to( - cast_to=extract_stream_chunk_type( - to, - failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", - ), - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - if self._stream_cls: - return cast( - R, - self._stream_cls( - cast_to=extract_stream_chunk_type(self._stream_cls), - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) - if stream_cls is None: - raise MissingStreamClassError() - - return cast( - R, - stream_cls( - cast_to=cast_to, - response=self.http_response, - client=cast(Any, self._client), - ), - ) - - if cast_to is NoneType: - return cast(R, None) - - response = self.http_response - if cast_to == str: - return cast(R, response.text) - - if cast_to == bytes: - return cast(R, response.content) - - if cast_to == int: - return cast(R, int(response.text)) - - if cast_to == float: - return cast(R, float(response.text)) - - if cast_to == bool: - return cast(R, response.text.lower() == "true") - - # handle the legacy binary response case - if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": - return cast(R, cast_to(response)) # type: ignore - - if origin == APIResponse: - raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - - if inspect.isclass(origin) and issubclass(origin, httpx.Response): - # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response - # and pass that class to our request functions. We cannot change the variance to be either - # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct - # the response class ourselves but that is something that should be supported directly in httpx - # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. - if cast_to != httpx.Response: - raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") - return cast(R, response) - - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): - raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") - - if ( - cast_to is not object - and not origin is list - and not origin is dict - and not origin is Union - and not issubclass(origin, BaseModel) - ): - raise RuntimeError( - f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." - ) - - # split is required to handle cases where additional information is included - # in the response, e.g. application/json; charset=utf-8 - content_type, *_ = response.headers.get("content-type", "*").split(";") - if not content_type.endswith("json"): - if is_basemodel(cast_to): - try: - data = response.json() - except Exception as exc: - log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) - else: - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - if self._client._strict_response_validation: - raise APIResponseValidationError( - response=response, - message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", - body=response.text, - ) - - # If the API responds with content that isn't JSON then we just return - # the (decoded) text without performing any parsing so that you can still - # handle the response however you need to. - return response.text # type: ignore - - data = response.json() - - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - -class APIResponse(BaseAPIResponse[R]): - @property - def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] - - @overload - def parse(self, *, to: type[_T]) -> _T: ... - - @overload - def parse(self) -> R: ... - - def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from openai import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `int` - - `float` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - if isinstance(parsed, BaseModel): - add_request_id(parsed, self.request_id) - - self._parsed_by_type[cache_key] = parsed - return cast(R, parsed) - - def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return self.http_response.read() - except httpx.StreamConsumed as exc: - # The default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message. - raise StreamAlreadyConsumed() from exc - - def text(self) -> str: - """Read and decode the response content into a string.""" - self.read() - return self.http_response.text - - def json(self) -> object: - """Read and decode the JSON response content.""" - self.read() - return self.http_response.json() - - def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.http_response.close() - - def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - for chunk in self.http_response.iter_bytes(chunk_size): - yield chunk - - def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - for chunk in self.http_response.iter_text(chunk_size): - yield chunk - - def iter_lines(self) -> Iterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - for chunk in self.http_response.iter_lines(): - yield chunk - - -class AsyncAPIResponse(BaseAPIResponse[R]): - @property - def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] - - @overload - async def parse(self, *, to: type[_T]) -> _T: ... - - @overload - async def parse(self) -> R: ... - - async def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from openai import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - await self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - if isinstance(parsed, BaseModel): - add_request_id(parsed, self.request_id) - - self._parsed_by_type[cache_key] = parsed - return cast(R, parsed) - - async def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return await self.http_response.aread() - except httpx.StreamConsumed as exc: - # the default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message - raise StreamAlreadyConsumed() from exc - - async def text(self) -> str: - """Read and decode the response content into a string.""" - await self.read() - return self.http_response.text - - async def json(self) -> object: - """Read and decode the JSON response content.""" - await self.read() - return self.http_response.json() - - async def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.http_response.aclose() - - async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - async for chunk in self.http_response.aiter_bytes(chunk_size): - yield chunk - - async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - async for chunk in self.http_response.aiter_text(chunk_size): - yield chunk - - async def iter_lines(self) -> AsyncIterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - async for chunk in self.http_response.aiter_lines(): - yield chunk - - -class BinaryAPIResponse(APIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(): - f.write(data) - - -class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - async def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(): - await f.write(data) - - -class StreamedBinaryAPIResponse(APIResponse[bytes]): - def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(chunk_size): - f.write(data) - - -class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): - async def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(chunk_size): - await f.write(data) - - -class MissingStreamClassError(TypeError): - def __init__(self) -> None: - super().__init__( - "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `openai._streaming` for reference", - ) - - -class StreamAlreadyConsumed(OpenAIError): - """ - Attempted to read or stream content, but the content has already - been streamed. - - This can happen if you use a method like `.iter_lines()` and then attempt - to read th entire response body afterwards, e.g. - - ```py - response = await client.post(...) - async for line in response.iter_lines(): - ... # do something with `line` - - content = await response.read() - # ^ error - ``` - - If you want this behaviour you'll need to either manually accumulate the response - content or call `await response.read()` before iterating over the stream. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream some content, but the content has " - "already been streamed. " - "This could be due to attempting to stream the response " - "content more than once." - "\n\n" - "You can fix this by manually accumulating the response content while streaming " - "or by calling `.read()` before starting to stream." - ) - super().__init__(message) - - -class ResponseContextManager(Generic[_APIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: - self._request_func = request_func - self.__response: _APIResponseT | None = None - - def __enter__(self) -> _APIResponseT: - self.__response = self._request_func() - return self.__response - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - self.__response.close() - - -class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: - self._api_request = api_request - self.__response: _AsyncAPIResponseT | None = None - - async def __aenter__(self) -> _AsyncAPIResponseT: - self.__response = await self._api_request - return self.__response - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - await self.__response.close() - - -def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) - - return wrapped - - -def async_to_streamed_response_wrapper( - func: Callable[P, Awaitable[R]], -) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) - - return wrapped - - -def to_custom_streamed_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, ResponseContextManager[_APIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) - - return wrapped - - -def async_to_custom_streamed_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) - - return wrapped - - -def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(APIResponse[R], func(*args, **kwargs)) - - return wrapped - - -def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) - - return wrapped - - -def to_custom_raw_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, _APIResponseT]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(_APIResponseT, func(*args, **kwargs)) - - return wrapped - - -def async_to_custom_raw_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) - - return wrapped - - -def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: - """Given a type like `APIResponse[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(APIResponse[bytes]): - ... - - extract_response_type(MyResponse) -> bytes - ``` - """ - return extract_type_var_from_base( - typ, - generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), - index=0, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_streaming.py b/backend/venv39/lib/python3.9/site-packages/openai/_streaming.py deleted file mode 100644 index 61a7426..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_streaming.py +++ /dev/null @@ -1,412 +0,0 @@ -# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py -from __future__ import annotations - -import json -import inspect -from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast -from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable - -import httpx - -from ._utils import is_mapping, extract_type_var_from_base -from ._exceptions import APIError - -if TYPE_CHECKING: - from ._client import OpenAI, AsyncOpenAI - - -_T = TypeVar("_T") - - -class Stream(Generic[_T]): - """Provides the core interface to iterate over a synchronous stream response.""" - - response: httpx.Response - - _decoder: SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: OpenAI, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - def __next__(self) -> _T: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[_T]: - for item in self._iterator: - yield item - - def _iter_events(self) -> Iterator[ServerSentEvent]: - yield from self._decoder.iter_bytes(self.response.iter_bytes()) - - def __stream__(self) -> Iterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - for sse in iterator: - if sse.data.startswith("[DONE]"): - break - - # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data - if sse.event and sse.event.startswith("thread."): - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - else: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) - - finally: - # Ensure the response is closed even if the consumer doesn't read all data - response.close() - - def __enter__(self) -> Self: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.response.close() - - -class AsyncStream(Generic[_T]): - """Provides the core interface to iterate over an asynchronous stream response.""" - - response: httpx.Response - - _decoder: SSEDecoder | SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: AsyncOpenAI, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - async def __anext__(self) -> _T: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[_T]: - async for item in self._iterator: - yield item - - async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: - async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): - yield sse - - async def __stream__(self) -> AsyncIterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - async for sse in iterator: - if sse.data.startswith("[DONE]"): - break - - # we have to special case the Assistants `thread.` events since we won't have an "event" key in the data - if sse.event and sse.event.startswith("thread."): - data = sse.json() - - if sse.event == "error" and is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response) - else: - data = sse.json() - if is_mapping(data) and data.get("error"): - message = None - error = data.get("error") - if is_mapping(error): - message = error.get("message") - if not message or not isinstance(message, str): - message = "An error occurred during streaming" - - raise APIError( - message=message, - request=self.response.request, - body=data["error"], - ) - - yield process_data(data=data, cast_to=cast_to, response=response) - - finally: - # Ensure the response is closed even if the consumer doesn't read all data - await response.aclose() - - async def __aenter__(self) -> Self: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.response.aclose() - - -class ServerSentEvent: - def __init__( - self, - *, - event: str | None = None, - data: str | None = None, - id: str | None = None, - retry: int | None = None, - ) -> None: - if data is None: - data = "" - - self._id = id - self._data = data - self._event = event or None - self._retry = retry - - @property - def event(self) -> str | None: - return self._event - - @property - def id(self) -> str | None: - return self._id - - @property - def retry(self) -> int | None: - return self._retry - - @property - def data(self) -> str: - return self._data - - def json(self) -> Any: - return json.loads(self.data) - - @override - def __repr__(self) -> str: - return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" - - -class SSEDecoder: - _data: list[str] - _event: str | None - _retry: int | None - _last_event_id: str | None - - def __init__(self) -> None: - self._event = None - self._data = [] - self._last_event_id = None - self._retry = None - - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - for chunk in self._iter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - async for chunk in self._aiter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - async for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - def decode(self, line: str) -> ServerSentEvent | None: - # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 - - if not line: - if not self._event and not self._data and not self._last_event_id and self._retry is None: - return None - - sse = ServerSentEvent( - event=self._event, - data="\n".join(self._data), - id=self._last_event_id, - retry=self._retry, - ) - - # NOTE: as per the SSE spec, do not reset last_event_id. - self._event = None - self._data = [] - self._retry = None - - return sse - - if line.startswith(":"): - return None - - fieldname, _, value = line.partition(":") - - if value.startswith(" "): - value = value[1:] - - if fieldname == "event": - self._event = value - elif fieldname == "data": - self._data.append(value) - elif fieldname == "id": - if "\0" in value: - pass - else: - self._last_event_id = value - elif fieldname == "retry": - try: - self._retry = int(value) - except (TypeError, ValueError): - pass - else: - pass # Field is ignored. - - return None - - -@runtime_checkable -class SSEBytesDecoder(Protocol): - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - -def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: - """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" - origin = get_origin(typ) or typ - return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) - - -def extract_stream_chunk_type( - stream_cls: type, - *, - failure_message: str | None = None, -) -> type: - """Given a type like `Stream[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyStream(Stream[bytes]): - ... - - extract_stream_chunk_type(MyStream) -> bytes - ``` - """ - from ._base_client import Stream, AsyncStream - - return extract_type_var_from_base( - stream_cls, - index=0, - generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), - failure_message=failure_message, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_types.py b/backend/venv39/lib/python3.9/site-packages/openai/_types.py deleted file mode 100644 index d7e2eaa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_types.py +++ /dev/null @@ -1,265 +0,0 @@ -from __future__ import annotations - -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - List, - Type, - Tuple, - Union, - Mapping, - TypeVar, - Callable, - Iterator, - Optional, - Sequence, -) -from typing_extensions import ( - Set, - Literal, - Protocol, - TypeAlias, - TypedDict, - SupportsIndex, - overload, - override, - runtime_checkable, -) - -import httpx -import pydantic -from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport - -if TYPE_CHECKING: - from ._models import BaseModel - from ._response import APIResponse, AsyncAPIResponse - from ._legacy_response import HttpxBinaryResponseContent - -Transport = BaseTransport -AsyncTransport = AsyncBaseTransport -Query = Mapping[str, object] -Body = object -AnyMapping = Mapping[str, object] -ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) -_T = TypeVar("_T") - - -# Approximates httpx internal ProxiesTypes and RequestFiles types -# while adding support for `PathLike` instances -ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] -ProxiesTypes = Union[str, Proxy, ProxiesDict] -if TYPE_CHECKING: - Base64FileInput = Union[IO[bytes], PathLike[str]] - FileContent = Union[IO[bytes], bytes, PathLike[str]] -else: - Base64FileInput = Union[IO[bytes], PathLike] - FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. -FileTypes = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] - -# duplicate of the above but without our custom file support -HttpxFileContent = Union[IO[bytes], bytes] -HttpxFileTypes = Union[ - # file (or bytes) - HttpxFileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], HttpxFileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], HttpxFileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], -] -HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] - -# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT -# where ResponseT includes `None`. In order to support directly -# passing `None`, overloads would have to be defined for every -# method that uses `ResponseT` which would lead to an unacceptable -# amount of code duplication and make it unreadable. See _base_client.py -# for example usage. -# -# This unfortunately means that you will either have -# to import this type and pass it explicitly: -# -# from openai import NoneType -# client.get('/foo', cast_to=NoneType) -# -# or build it yourself: -# -# client.get('/foo', cast_to=type(None)) -if TYPE_CHECKING: - NoneType: Type[None] -else: - NoneType = type(None) - - -class RequestOptions(TypedDict, total=False): - headers: Headers - max_retries: int - timeout: float | Timeout | None - params: Query - extra_json: AnyMapping - idempotency_key: str - follow_redirects: bool - - -# Sentinel class used until PEP 0661 is accepted -class NotGiven: - """ - For parameters with a meaningful None value, we need to distinguish between - the user explicitly passing None, and the user not passing the parameter at - all. - - User code shouldn't need to use not_given directly. - - For example: - - ```py - def create(timeout: Timeout | None | NotGiven = not_given): ... - - - create(timeout=1) # 1s timeout - create(timeout=None) # No timeout - create() # Default timeout behavior - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - @override - def __repr__(self) -> str: - return "NOT_GIVEN" - - -not_given = NotGiven() -# for backwards compatibility: -NOT_GIVEN = NotGiven() - - -class Omit: - """ - To explicitly omit something from being sent in a request, use `omit`. - - ```py - # as the default `Content-Type` header is `application/json` that will be sent - client.post("/upload/files", files={"file": b"my raw file content"}) - - # you can't explicitly override the header as it has to be dynamically generated - # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' - client.post(..., headers={"Content-Type": "multipart/form-data"}) - - # instead you can remove the default `application/json` header by passing omit - client.post(..., headers={"Content-Type": omit}) - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - -omit = Omit() - -Omittable = Union[_T, Omit] - - -@runtime_checkable -class ModelBuilderProtocol(Protocol): - @classmethod - def build( - cls: type[_T], - *, - response: Response, - data: object, - ) -> _T: ... - - -Headers = Mapping[str, Union[str, Omit]] - - -class HeadersLikeProtocol(Protocol): - def get(self, __key: str) -> str | None: ... - - -HeadersLike = Union[Headers, HeadersLikeProtocol] - -ResponseT = TypeVar( - "ResponseT", - bound=Union[ - object, - str, - None, - "BaseModel", - List[Any], - Dict[str, Any], - Response, - ModelBuilderProtocol, - "APIResponse[Any]", - "AsyncAPIResponse[Any]", - "HttpxBinaryResponseContent", - ], -) - -StrBytesIntFloat = Union[str, bytes, int, float] - -# Note: copied from Pydantic -# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 -IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] - -PostParser = Callable[[Any], Any] - - -@runtime_checkable -class InheritsGeneric(Protocol): - """Represents a type that has inherited from `Generic` - - The `__orig_bases__` property can be used to determine the resolved - type variable for a given base class. - """ - - __orig_bases__: tuple[_GenericAlias] - - -class _GenericAlias(Protocol): - __origin__: type[object] - - -class HttpxSendArgs(TypedDict, total=False): - auth: httpx.Auth - follow_redirects: bool - - -_T_co = TypeVar("_T_co", covariant=True) - - -if TYPE_CHECKING: - # This works because str.__contains__ does not accept object (either in typeshed or at runtime) - # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 - # - # Note: index() and count() methods are intentionally omitted to allow pyright to properly - # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. - class SequenceNotStr(Protocol[_T_co]): - @overload - def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... - @overload - def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... - def __contains__(self, value: object, /) -> bool: ... - def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T_co]: ... - def __reversed__(self) -> Iterator[_T_co]: ... -else: - # just point this to a normal `Sequence` at runtime to avoid having to special case - # deserializing our custom sequence type - SequenceNotStr = Sequence diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/__init__.py deleted file mode 100644 index 963c83b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/__init__.py +++ /dev/null @@ -1,67 +0,0 @@ -from ._logs import SensitiveHeadersFilter as SensitiveHeadersFilter -from ._sync import asyncify as asyncify -from ._proxy import LazyProxy as LazyProxy -from ._utils import ( - flatten as flatten, - is_dict as is_dict, - is_list as is_list, - is_given as is_given, - is_tuple as is_tuple, - json_safe as json_safe, - lru_cache as lru_cache, - is_mapping as is_mapping, - is_tuple_t as is_tuple_t, - is_iterable as is_iterable, - is_sequence as is_sequence, - coerce_float as coerce_float, - is_mapping_t as is_mapping_t, - removeprefix as removeprefix, - removesuffix as removesuffix, - extract_files as extract_files, - is_sequence_t as is_sequence_t, - required_args as required_args, - coerce_boolean as coerce_boolean, - coerce_integer as coerce_integer, - file_from_path as file_from_path, - is_azure_client as is_azure_client, - strip_not_given as strip_not_given, - deepcopy_minimal as deepcopy_minimal, - get_async_library as get_async_library, - maybe_coerce_float as maybe_coerce_float, - get_required_header as get_required_header, - maybe_coerce_boolean as maybe_coerce_boolean, - maybe_coerce_integer as maybe_coerce_integer, - is_async_azure_client as is_async_azure_client, -) -from ._compat import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, -) -from ._typing import ( - is_list_type as is_list_type, - is_union_type as is_union_type, - extract_type_arg as extract_type_arg, - is_iterable_type as is_iterable_type, - is_required_type as is_required_type, - is_sequence_type as is_sequence_type, - is_annotated_type as is_annotated_type, - is_type_alias_type as is_type_alias_type, - strip_annotated_type as strip_annotated_type, - extract_type_var_from_base as extract_type_var_from_base, -) -from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator -from ._transform import ( - PropertyInfo as PropertyInfo, - transform as transform, - async_transform as async_transform, - maybe_transform as maybe_transform, - async_maybe_transform as async_maybe_transform, -) -from ._reflection import ( - function_has_argument as function_has_argument, - assert_signatures_in_sync as assert_signatures_in_sync, -) -from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_compat.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_compat.py deleted file mode 100644 index dd70323..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_compat.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import sys -import typing_extensions -from typing import Any, Type, Union, Literal, Optional -from datetime import date, datetime -from typing_extensions import get_args as _get_args, get_origin as _get_origin - -from .._types import StrBytesIntFloat -from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime - -_LITERAL_TYPES = {Literal, typing_extensions.Literal} - - -def get_args(tp: type[Any]) -> tuple[Any, ...]: - return _get_args(tp) - - -def get_origin(tp: type[Any]) -> type[Any] | None: - return _get_origin(tp) - - -def is_union(tp: Optional[Type[Any]]) -> bool: - if sys.version_info < (3, 10): - return tp is Union # type: ignore[comparison-overlap] - else: - import types - - return tp is Union or tp is types.UnionType - - -def is_typeddict(tp: Type[Any]) -> bool: - return typing_extensions.is_typeddict(tp) - - -def is_literal_type(tp: Type[Any]) -> bool: - return get_origin(tp) in _LITERAL_TYPES - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - return _parse_date(value) - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - return _parse_datetime(value) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_datetime_parse.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_datetime_parse.py deleted file mode 100644 index 7cb9d9e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_datetime_parse.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py -without the Pydantic v1 specific errors. -""" - -from __future__ import annotations - -import re -from typing import Dict, Union, Optional -from datetime import date, datetime, timezone, timedelta - -from .._types import StrBytesIntFloat - -date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" -time_expr = ( - r"(?P\d{1,2}):(?P\d{1,2})" - r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" - r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" -) - -date_re = re.compile(f"{date_expr}$") -datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") - - -EPOCH = datetime(1970, 1, 1) -# if greater than this, the number is in ms, if less than or equal it's in seconds -# (in seconds this is 11th October 2603, in ms it's 20th August 1970) -MS_WATERSHED = int(2e10) -# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 -MAX_NUMBER = int(3e20) - - -def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: - if isinstance(value, (int, float)): - return value - try: - return float(value) - except ValueError: - return None - except TypeError: - raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None - - -def _from_unix_seconds(seconds: Union[int, float]) -> datetime: - if seconds > MAX_NUMBER: - return datetime.max - elif seconds < -MAX_NUMBER: - return datetime.min - - while abs(seconds) > MS_WATERSHED: - seconds /= 1000 - dt = EPOCH + timedelta(seconds=seconds) - return dt.replace(tzinfo=timezone.utc) - - -def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: - if value == "Z": - return timezone.utc - elif value is not None: - offset_mins = int(value[-2:]) if len(value) > 3 else 0 - offset = 60 * int(value[1:3]) + offset_mins - if value[0] == "-": - offset = -offset - return timezone(timedelta(minutes=offset)) - else: - return None - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - """ - Parse a datetime/int/float/string and return a datetime.datetime. - - This function supports time zone offsets. When the input contains one, - the output uses a timezone with a fixed offset from UTC. - - Raise ValueError if the input is well formatted but not a valid datetime. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, datetime): - return value - - number = _get_numeric(value, "datetime") - if number is not None: - return _from_unix_seconds(number) - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - - match = datetime_re.match(value) - if match is None: - raise ValueError("invalid datetime format") - - kw = match.groupdict() - if kw["microsecond"]: - kw["microsecond"] = kw["microsecond"].ljust(6, "0") - - tzinfo = _parse_timezone(kw.pop("tzinfo")) - kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} - kw_["tzinfo"] = tzinfo - - return datetime(**kw_) # type: ignore - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - """ - Parse a date/int/float/string and return a datetime.date. - - Raise ValueError if the input is well formatted but not a valid date. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, date): - if isinstance(value, datetime): - return value.date() - else: - return value - - number = _get_numeric(value, "date") - if number is not None: - return _from_unix_seconds(number).date() - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - match = date_re.match(value) - if match is None: - raise ValueError("invalid date format") - - kw = {k: int(v) for k, v in match.groupdict().items()} - - try: - return date(**kw) - except ValueError: - raise ValueError("invalid date format") from None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_logs.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_logs.py deleted file mode 100644 index 3769469..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_logs.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -import logging -from typing_extensions import override - -from ._utils import is_dict - -logger: logging.Logger = logging.getLogger("openai") -httpx_logger: logging.Logger = logging.getLogger("httpx") - - -SENSITIVE_HEADERS = {"api-key", "authorization"} - - -def _basic_config() -> None: - # e.g. [2023-10-05 14:12:26 - openai._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" - logging.basicConfig( - format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - - -def setup_logging() -> None: - env = os.environ.get("OPENAI_LOG") - if env == "debug": - _basic_config() - logger.setLevel(logging.DEBUG) - httpx_logger.setLevel(logging.DEBUG) - elif env == "info": - _basic_config() - logger.setLevel(logging.INFO) - httpx_logger.setLevel(logging.INFO) - - -class SensitiveHeadersFilter(logging.Filter): - @override - def filter(self, record: logging.LogRecord) -> bool: - if is_dict(record.args) and "headers" in record.args and is_dict(record.args["headers"]): - headers = record.args["headers"] = {**record.args["headers"]} - for header in headers: - if str(header).lower() in SENSITIVE_HEADERS: - headers[header] = "" - return True diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_proxy.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_proxy.py deleted file mode 100644 index 0f239a3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_proxy.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Generic, TypeVar, Iterable, cast -from typing_extensions import override - -T = TypeVar("T") - - -class LazyProxy(Generic[T], ABC): - """Implements data methods to pretend that an instance is another instance. - - This includes forwarding attribute access and other methods. - """ - - # Note: we have to special case proxies that themselves return proxies - # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` - - def __getattr__(self, attr: str) -> object: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied # pyright: ignore - return getattr(proxied, attr) - - @override - def __repr__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return repr(self.__get_proxied__()) - - @override - def __str__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return str(proxied) - - @override - def __dir__(self) -> Iterable[str]: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return [] - return proxied.__dir__() - - @property # type: ignore - @override - def __class__(self) -> type: # pyright: ignore - try: - proxied = self.__get_proxied__() - except Exception: - return type(self) - if issubclass(type(proxied), LazyProxy): - return type(proxied) - return proxied.__class__ - - def __get_proxied__(self) -> T: - return self.__load__() - - def __as_proxied__(self) -> T: - """Helper method that returns the current proxy, typed as the loaded object""" - return cast(T, self) - - @abstractmethod - def __load__(self) -> T: ... diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_reflection.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_reflection.py deleted file mode 100644 index bdaca29..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_reflection.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import inspect -from typing import Any, Callable - - -def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: - """Returns whether or not the given function has a specific parameter""" - sig = inspect.signature(func) - return arg_name in sig.parameters - - -def assert_signatures_in_sync( - source_func: Callable[..., Any], - check_func: Callable[..., Any], - *, - exclude_params: set[str] = set(), - description: str = "", -) -> None: - """Ensure that the signature of the second function matches the first.""" - - check_sig = inspect.signature(check_func) - source_sig = inspect.signature(source_func) - - errors: list[str] = [] - - for name, source_param in source_sig.parameters.items(): - if name in exclude_params: - continue - - custom_param = check_sig.parameters.get(name) - if not custom_param: - errors.append(f"the `{name}` param is missing") - continue - - if custom_param.annotation != source_param.annotation: - errors.append( - f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" - ) - continue - - if errors: - raise AssertionError( - f"{len(errors)} errors encountered when comparing signatures{description}:\n\n" + "\n\n".join(errors) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_resources_proxy.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_resources_proxy.py deleted file mode 100644 index e5b9ec7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_resources_proxy.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import annotations - -from typing import Any -from typing_extensions import override - -from ._proxy import LazyProxy - - -class ResourcesProxy(LazyProxy[Any]): - """A proxy for the `openai.resources` module. - - This is used so that we can lazily import `openai.resources` only when - needed *and* so that users can just import `openai` and reference `openai.resources` - """ - - @override - def __load__(self) -> Any: - import importlib - - mod = importlib.import_module("openai.resources") - return mod - - -resources = ResourcesProxy().__as_proxied__() diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_streams.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_streams.py deleted file mode 100644 index f4a0208..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_streams.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Any -from typing_extensions import Iterator, AsyncIterator - - -def consume_sync_iterator(iterator: Iterator[Any]) -> None: - for _ in iterator: - ... - - -async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: - async for _ in iterator: - ... diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_sync.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_sync.py deleted file mode 100644 index f6027c1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_sync.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -import asyncio -import functools -from typing import TypeVar, Callable, Awaitable -from typing_extensions import ParamSpec - -import anyio -import sniffio -import anyio.to_thread - -T_Retval = TypeVar("T_Retval") -T_ParamSpec = ParamSpec("T_ParamSpec") - - -async def to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs -) -> T_Retval: - if sniffio.current_async_library() == "asyncio": - return await asyncio.to_thread(func, *args, **kwargs) - - return await anyio.to_thread.run_sync( - functools.partial(func, *args, **kwargs), - ) - - -# inspired by `asyncer`, https://github.com/tiangolo/asyncer -def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: - """ - Take a blocking function and create an async one that receives the same - positional and keyword arguments. - - Usage: - - ```python - def blocking_func(arg1, arg2, kwarg1=None): - # blocking code - return result - - - result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) - ``` - - ## Arguments - - `function`: a blocking regular callable (e.g. a function) - - ## Return - - An async function that takes the same positional and keyword arguments as the - original one, that when called runs the same original function in a thread worker - and returns the result. - """ - - async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - return await to_thread(function, *args, **kwargs) - - return wrapper diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_transform.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_transform.py deleted file mode 100644 index 414f38c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_transform.py +++ /dev/null @@ -1,457 +0,0 @@ -from __future__ import annotations - -import io -import base64 -import pathlib -from typing import Any, Mapping, TypeVar, cast -from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints - -import anyio -import pydantic - -from ._utils import ( - is_list, - is_given, - lru_cache, - is_mapping, - is_iterable, - is_sequence, -) -from .._files import is_base64_file_input -from ._compat import get_origin, is_typeddict -from ._typing import ( - is_list_type, - is_union_type, - extract_type_arg, - is_iterable_type, - is_required_type, - is_sequence_type, - is_annotated_type, - strip_annotated_type, -) - -_T = TypeVar("_T") - - -# TODO: support for drilling globals() and locals() -# TODO: ensure works correctly with forward references in all cases - - -PropertyFormat = Literal["iso8601", "base64", "custom"] - - -class PropertyInfo: - """Metadata class to be used in Annotated types to provide information about a given type. - - For example: - - class MyParams(TypedDict): - account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] - - This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. - """ - - alias: str | None - format: PropertyFormat | None - format_template: str | None - discriminator: str | None - - def __init__( - self, - *, - alias: str | None = None, - format: PropertyFormat | None = None, - format_template: str | None = None, - discriminator: str | None = None, - ) -> None: - self.alias = alias - self.format = format - self.format_template = format_template - self.discriminator = discriminator - - @override - def __repr__(self) -> str: - return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" - - -def maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `transform()` that allows `None` to be passed. - - See `transform()` for more details. - """ - if data is None: - return None - return transform(data, expected_type) - - -# Wrapper over _transform_recursive providing fake types -def transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = _transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -@lru_cache(maxsize=8096) -def _get_annotated_type(type_: type) -> type | None: - """If the given type is an `Annotated` type then it is returned, if not `None` is returned. - - This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` - """ - if is_required_type(type_): - # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` - type_ = get_args(type_)[0] - - if is_annotated_type(type_): - return type_ - - return None - - -def _maybe_transform_key(key: str, type_: type) -> str: - """Transform the given `data` based on the annotations provided in `type_`. - - Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. - """ - annotated_type = _get_annotated_type(type_) - if annotated_type is None: - # no `Annotated` definition for this type, no transformation needed - return key - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.alias is not None: - return annotation.alias - - return key - - -def _no_transform_needed(annotation: type) -> bool: - return annotation == float or annotation == int - - -def _transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return _transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = _transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json", exclude=getattr(data, "__api_exclude__", None)) - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return _format_data(data, annotation.format, annotation.format_template) - - return data - - -def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - return data.isoformat() - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = data.read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -def _transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) - return result - - -async def async_maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `async_transform()` that allows `None` to be passed. - - See `async_transform()` for more details. - """ - if data is None: - return None - return await async_transform(data, expected_type) - - -async def async_transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -async def _async_transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return await _async_transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return await _async_format_data(data, annotation.format, annotation.format_template) - - return data - - -async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - return data.isoformat() - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = await anyio.Path(data).read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -async def _async_transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) - return result - - -@lru_cache(maxsize=8096) -def get_type_hints( - obj: Any, - globalns: dict[str, Any] | None = None, - localns: Mapping[str, Any] | None = None, - include_extras: bool = False, -) -> dict[str, Any]: - return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_typing.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_typing.py deleted file mode 100644 index 193109f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_typing.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import sys -import typing -import typing_extensions -from typing import Any, TypeVar, Iterable, cast -from collections import abc as _c_abc -from typing_extensions import ( - TypeIs, - Required, - Annotated, - get_args, - get_origin, -) - -from ._utils import lru_cache -from .._types import InheritsGeneric -from ._compat import is_union as _is_union - - -def is_annotated_type(typ: type) -> bool: - return get_origin(typ) == Annotated - - -def is_list_type(typ: type) -> bool: - return (get_origin(typ) or typ) == list - - -def is_sequence_type(typ: type) -> bool: - origin = get_origin(typ) or typ - return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence - - -def is_iterable_type(typ: type) -> bool: - """If the given type is `typing.Iterable[T]`""" - origin = get_origin(typ) or typ - return origin == Iterable or origin == _c_abc.Iterable - - -def is_union_type(typ: type) -> bool: - return _is_union(get_origin(typ)) - - -def is_required_type(typ: type) -> bool: - return get_origin(typ) == Required - - -def is_typevar(typ: type) -> bool: - # type ignore is required because type checkers - # think this expression will always return False - return type(typ) == TypeVar # type: ignore - - -_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) -if sys.version_info >= (3, 12): - _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) - - -def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: - """Return whether the provided argument is an instance of `TypeAliasType`. - - ```python - type Int = int - is_type_alias_type(Int) - # > True - Str = TypeAliasType("Str", str) - is_type_alias_type(Str) - # > True - ``` - """ - return isinstance(tp, _TYPE_ALIAS_TYPES) - - -# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] -@lru_cache(maxsize=8096) -def strip_annotated_type(typ: type) -> type: - if is_required_type(typ) or is_annotated_type(typ): - return strip_annotated_type(cast(type, get_args(typ)[0])) - - return typ - - -def extract_type_arg(typ: type, index: int) -> type: - args = get_args(typ) - try: - return cast(type, args[index]) - except IndexError as err: - raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err - - -def extract_type_var_from_base( - typ: type, - *, - generic_bases: tuple[type, ...], - index: int, - failure_message: str | None = None, -) -> type: - """Given a type like `Foo[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(Foo[bytes]): - ... - - extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes - ``` - - And where a generic subclass is given: - ```py - _T = TypeVar('_T') - class MyResponse(Foo[_T]): - ... - - extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes - ``` - """ - cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] - # we're given the class directly - return extract_type_arg(typ, index) - - # if a subclass is given - # --- - # this is needed as __orig_bases__ is not present in the typeshed stubs - # because it is intended to be for internal use only, however there does - # not seem to be a way to resolve generic TypeVars for inherited subclasses - # without using it. - if isinstance(cls, InheritsGeneric): - target_base_class: Any | None = None - for base in cls.__orig_bases__: - if base.__origin__ in generic_bases: - target_base_class = base - break - - if target_base_class is None: - raise RuntimeError( - "Could not find the generic base class;\n" - "This should never happen;\n" - f"Does {cls} inherit from one of {generic_bases} ?" - ) - - extracted = extract_type_arg(target_base_class, index) - if is_typevar(extracted): - # If the extracted type argument is itself a type variable - # then that means the subclass itself is generic, so we have - # to resolve the type argument from the class itself, not - # the base class. - # - # Note: if there is more than 1 type argument, the subclass could - # change the ordering of the type arguments, this is not currently - # supported. - return extract_type_arg(typ, index) - - return extracted - - raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_utils.py b/backend/venv39/lib/python3.9/site-packages/openai/_utils/_utils.py deleted file mode 100644 index 9049474..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_utils/_utils.py +++ /dev/null @@ -1,437 +0,0 @@ -from __future__ import annotations - -import os -import re -import inspect -import functools -from typing import ( - TYPE_CHECKING, - Any, - Tuple, - Mapping, - TypeVar, - Callable, - Iterable, - Sequence, - cast, - overload, -) -from pathlib import Path -from datetime import date, datetime -from typing_extensions import TypeGuard - -import sniffio - -from .._types import Omit, NotGiven, FileTypes, HeadersLike - -_T = TypeVar("_T") -_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) -_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) -_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) -CallableT = TypeVar("CallableT", bound=Callable[..., Any]) - -if TYPE_CHECKING: - from ..lib.azure import AzureOpenAI, AsyncAzureOpenAI - - -def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: - return [item for sublist in t for item in sublist] - - -def extract_files( - # TODO: this needs to take Dict but variance issues..... - # create protocol type ? - query: Mapping[str, object], - *, - paths: Sequence[Sequence[str]], -) -> list[tuple[str, FileTypes]]: - """Recursively extract files from the given dictionary based on specified paths. - - A path may look like this ['foo', 'files', '', 'data']. - - Note: this mutates the given dictionary. - """ - files: list[tuple[str, FileTypes]] = [] - for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) - return files - - -def _extract_items( - obj: object, - path: Sequence[str], - *, - index: int, - flattened_key: str | None, -) -> list[tuple[str, FileTypes]]: - try: - key = path[index] - except IndexError: - if not is_given(obj): - # no value was provided - we can safely ignore - return [] - - # cyclical import - from .._files import assert_is_file_content - - # We have exhausted the path, return the entry we found. - assert flattened_key is not None - - if is_list(obj): - files: list[tuple[str, FileTypes]] = [] - for entry in obj: - assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") - files.append((flattened_key + "[]", cast(FileTypes, entry))) - return files - - assert_is_file_content(obj, key=flattened_key) - return [(flattened_key, cast(FileTypes, obj))] - - index += 1 - if is_dict(obj): - try: - # We are at the last entry in the path so we must remove the field - if (len(path)) == index: - item = obj.pop(key) - else: - item = obj[key] - except KeyError: - # Key was not present in the dictionary, this is not indicative of an error - # as the given path may not point to a required field. We also do not want - # to enforce required fields as the API may differ from the spec in some cases. - return [] - if flattened_key is None: - flattened_key = key - else: - flattened_key += f"[{key}]" - return _extract_items( - item, - path, - index=index, - flattened_key=flattened_key, - ) - elif is_list(obj): - if key != "": - return [] - - return flatten( - [ - _extract_items( - item, - path, - index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", - ) - for item in obj - ] - ) - - # Something unexpected was passed, just ignore it. - return [] - - -def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) - - -# Type safe methods for narrowing types with TypeVars. -# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], -# however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in its place. -# -# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. -# `is_*` is for when you're dealing with an unknown input -# `is_*_t` is for when you're narrowing a known union type to a specific subset - - -def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: - return isinstance(obj, tuple) - - -def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: - return isinstance(obj, tuple) - - -def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: - return isinstance(obj, Sequence) - - -def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: - return isinstance(obj, Sequence) - - -def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: - return isinstance(obj, Mapping) - - -def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: - return isinstance(obj, Mapping) - - -def is_dict(obj: object) -> TypeGuard[dict[object, object]]: - return isinstance(obj, dict) - - -def is_list(obj: object) -> TypeGuard[list[object]]: - return isinstance(obj, list) - - -def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: - return isinstance(obj, Iterable) - - -def deepcopy_minimal(item: _T) -> _T: - """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: - - - mappings, e.g. `dict` - - list - - This is done for performance reasons. - """ - if is_mapping(item): - return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) - if is_list(item): - return cast(_T, [deepcopy_minimal(entry) for entry in item]) - return item - - -# copied from https://github.com/Rapptz/RoboDanny -def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: - size = len(seq) - if size == 0: - return "" - - if size == 1: - return seq[0] - - if size == 2: - return f"{seq[0]} {final} {seq[1]}" - - return delim.join(seq[:-1]) + f" {final} {seq[-1]}" - - -def quote(string: str) -> str: - """Add single quotation marks around the given string. Does *not* do any escaping.""" - return f"'{string}'" - - -def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: - """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. - - Useful for enforcing runtime validation of overloaded functions. - - Example usage: - ```py - @overload - def foo(*, a: str) -> str: ... - - - @overload - def foo(*, b: bool) -> str: ... - - - # This enforces the same constraints that a static type checker would - # i.e. that either a or b must be passed to the function - @required_args(["a"], ["b"]) - def foo(*, a: str | None = None, b: bool | None = None) -> str: ... - ``` - """ - - def inner(func: CallableT) -> CallableT: - params = inspect.signature(func).parameters - positional = [ - name - for name, param in params.items() - if param.kind - in { - param.POSITIONAL_ONLY, - param.POSITIONAL_OR_KEYWORD, - } - ] - - @functools.wraps(func) - def wrapper(*args: object, **kwargs: object) -> object: - given_params: set[str] = set() - for i, _ in enumerate(args): - try: - given_params.add(positional[i]) - except IndexError: - raise TypeError( - f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" - ) from None - - for key in kwargs.keys(): - given_params.add(key) - - for variant in variants: - matches = all((param in given_params for param in variant)) - if matches: - break - else: # no break - if len(variants) > 1: - variations = human_join( - ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] - ) - msg = f"Missing required arguments; Expected either {variations} arguments to be given" - else: - assert len(variants) > 0 - - # TODO: this error message is not deterministic - missing = list(set(variants[0]) - given_params) - if len(missing) > 1: - msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" - else: - msg = f"Missing required argument: {quote(missing[0])}" - raise TypeError(msg) - return func(*args, **kwargs) - - return wrapper # type: ignore - - return inner - - -_K = TypeVar("_K") -_V = TypeVar("_V") - - -@overload -def strip_not_given(obj: None) -> None: ... - - -@overload -def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... - - -@overload -def strip_not_given(obj: object) -> object: ... - - -def strip_not_given(obj: object | None) -> object: - """Remove all top-level keys where their values are instances of `NotGiven`""" - if obj is None: - return None - - if not is_mapping(obj): - return obj - - return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} - - -def coerce_integer(val: str) -> int: - return int(val, base=10) - - -def coerce_float(val: str) -> float: - return float(val) - - -def coerce_boolean(val: str) -> bool: - return val == "true" or val == "1" or val == "on" - - -def maybe_coerce_integer(val: str | None) -> int | None: - if val is None: - return None - return coerce_integer(val) - - -def maybe_coerce_float(val: str | None) -> float | None: - if val is None: - return None - return coerce_float(val) - - -def maybe_coerce_boolean(val: str | None) -> bool | None: - if val is None: - return None - return coerce_boolean(val) - - -def removeprefix(string: str, prefix: str) -> str: - """Remove a prefix from a string. - - Backport of `str.removeprefix` for Python < 3.9 - """ - if string.startswith(prefix): - return string[len(prefix) :] - return string - - -def removesuffix(string: str, suffix: str) -> str: - """Remove a suffix from a string. - - Backport of `str.removesuffix` for Python < 3.9 - """ - if string.endswith(suffix): - return string[: -len(suffix)] - return string - - -def file_from_path(path: str) -> FileTypes: - contents = Path(path).read_bytes() - file_name = os.path.basename(path) - return (file_name, contents) - - -def get_required_header(headers: HeadersLike, header: str) -> str: - lower_header = header.lower() - if is_mapping_t(headers): - # mypy doesn't understand the type narrowing here - for k, v in headers.items(): # type: ignore - if k.lower() == lower_header and isinstance(v, str): - return v - - # to deal with the case where the header looks like Stainless-Event-Id - intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) - - for normalized_header in [header, lower_header, header.upper(), intercaps_header]: - value = headers.get(normalized_header) - if value: - return value - - raise ValueError(f"Could not find {header} header") - - -def get_async_library() -> str: - try: - return sniffio.current_async_library() - except Exception: - return "false" - - -def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: - """A version of functools.lru_cache that retains the type signature - for the wrapped function arguments. - """ - wrapper = functools.lru_cache( # noqa: TID251 - maxsize=maxsize, - ) - return cast(Any, wrapper) # type: ignore[no-any-return] - - -def json_safe(data: object) -> object: - """Translates a mapping / sequence recursively in the same fashion - as `pydantic` v2's `model_dump(mode="json")`. - """ - if is_mapping(data): - return {json_safe(key): json_safe(value) for key, value in data.items()} - - if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): - return [json_safe(item) for item in data] - - if isinstance(data, (datetime, date)): - return data.isoformat() - - return data - - -def is_azure_client(client: object) -> TypeGuard[AzureOpenAI]: - from ..lib.azure import AzureOpenAI - - return isinstance(client, AzureOpenAI) - - -def is_async_azure_client(client: object) -> TypeGuard[AsyncAzureOpenAI]: - from ..lib.azure import AsyncAzureOpenAI - - return isinstance(client, AsyncAzureOpenAI) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/_version.py b/backend/venv39/lib/python3.9/site-packages/openai/_version.py deleted file mode 100644 index 6f0ccf7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/_version.py +++ /dev/null @@ -1,4 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -__title__ = "openai" -__version__ = "2.15.0" # x-release-please-version diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/__init__.py deleted file mode 100644 index d453d5e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._cli import main as main diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/__init__.py deleted file mode 100644 index 56a0260..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._main import register_commands as register_commands diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/_main.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/_main.py deleted file mode 100644 index b04a3e5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/_main.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from argparse import ArgumentParser - -from . import chat, audio, files, image, models, completions, fine_tuning - - -def register_commands(parser: ArgumentParser) -> None: - subparsers = parser.add_subparsers(help="All API subcommands") - - chat.register(subparsers) - image.register(subparsers) - audio.register(subparsers) - files.register(subparsers) - models.register(subparsers) - completions.register(subparsers) - fine_tuning.register(subparsers) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/audio.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/audio.py deleted file mode 100644 index e7c3734..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/audio.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, Any, Optional, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from ..._types import omit -from .._models import BaseModel -from .._progress import BufferReader -from ...types.audio import Transcription - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - # transcriptions - sub = subparser.add_parser("audio.transcriptions.create") - - # Required - sub.add_argument("-m", "--model", type=str, default="whisper-1") - sub.add_argument("-f", "--file", type=str, required=True) - # Optional - sub.add_argument("--response-format", type=str) - sub.add_argument("--language", type=str) - sub.add_argument("-t", "--temperature", type=float) - sub.add_argument("--prompt", type=str) - sub.set_defaults(func=CLIAudio.transcribe, args_model=CLITranscribeArgs) - - # translations - sub = subparser.add_parser("audio.translations.create") - - # Required - sub.add_argument("-f", "--file", type=str, required=True) - # Optional - sub.add_argument("-m", "--model", type=str, default="whisper-1") - sub.add_argument("--response-format", type=str) - # TODO: doesn't seem to be supported by the API - # sub.add_argument("--language", type=str) - sub.add_argument("-t", "--temperature", type=float) - sub.add_argument("--prompt", type=str) - sub.set_defaults(func=CLIAudio.translate, args_model=CLITranslationArgs) - - -class CLITranscribeArgs(BaseModel): - model: str - file: str - response_format: Optional[str] = None - language: Optional[str] = None - temperature: Optional[float] = None - prompt: Optional[str] = None - - -class CLITranslationArgs(BaseModel): - model: str - file: str - response_format: Optional[str] = None - language: Optional[str] = None - temperature: Optional[float] = None - prompt: Optional[str] = None - - -class CLIAudio: - @staticmethod - def transcribe(args: CLITranscribeArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - model = cast( - "Transcription | str", - get_client().audio.transcriptions.create( - file=(args.file, buffer_reader), - model=args.model, - language=args.language or omit, - temperature=args.temperature or omit, - prompt=args.prompt or omit, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - response_format=cast(Any, args.response_format), - ), - ) - if isinstance(model, str): - sys.stdout.write(model + "\n") - else: - print_model(model) - - @staticmethod - def translate(args: CLITranslationArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - model = cast( - "Transcription | str", - get_client().audio.translations.create( - file=(args.file, buffer_reader), - model=args.model, - temperature=args.temperature or omit, - prompt=args.prompt or omit, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - response_format=cast(Any, args.response_format), - ), - ) - if isinstance(model, str): - sys.stdout.write(model + "\n") - else: - print_model(model) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/__init__.py deleted file mode 100644 index 87d9716..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import completions - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - completions.register(subparser) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/completions.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/completions.py deleted file mode 100644 index 344eeff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/chat/completions.py +++ /dev/null @@ -1,160 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, List, Optional, cast -from argparse import ArgumentParser -from typing_extensions import Literal, NamedTuple - -from ..._utils import get_client -from ..._models import BaseModel -from ...._streaming import Stream -from ....types.chat import ( - ChatCompletionRole, - ChatCompletionChunk, - CompletionCreateParams, -) -from ....types.chat.completion_create_params import ( - CompletionCreateParamsStreaming, - CompletionCreateParamsNonStreaming, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("chat.completions.create") - - sub._action_groups.pop() - req = sub.add_argument_group("required arguments") - opt = sub.add_argument_group("optional arguments") - - req.add_argument( - "-g", - "--message", - action="append", - nargs=2, - metavar=("ROLE", "CONTENT"), - help="A message in `{role} {content}` format. Use this argument multiple times to add multiple messages.", - required=True, - ) - req.add_argument( - "-m", - "--model", - help="The model to use.", - required=True, - ) - - opt.add_argument( - "-n", - "--n", - help="How many completions to generate for the conversation.", - type=int, - ) - opt.add_argument("-M", "--max-tokens", help="The maximum number of tokens to generate.", type=int) - opt.add_argument( - "-t", - "--temperature", - help="""What sampling temperature to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. - -Mutually exclusive with `top_p`.""", - type=float, - ) - opt.add_argument( - "-P", - "--top_p", - help="""An alternative to sampling with temperature, called nucleus sampling, where the considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10%% probability mass are considered. - - Mutually exclusive with `temperature`.""", - type=float, - ) - opt.add_argument( - "--stop", - help="A stop sequence at which to stop generating tokens for the message.", - ) - opt.add_argument("--stream", help="Stream messages as they're ready.", action="store_true") - sub.set_defaults(func=CLIChatCompletion.create, args_model=CLIChatCompletionCreateArgs) - - -class CLIMessage(NamedTuple): - role: ChatCompletionRole - content: str - - -class CLIChatCompletionCreateArgs(BaseModel): - message: List[CLIMessage] - model: str - n: Optional[int] = None - max_tokens: Optional[int] = None - temperature: Optional[float] = None - top_p: Optional[float] = None - stop: Optional[str] = None - stream: bool = False - - -class CLIChatCompletion: - @staticmethod - def create(args: CLIChatCompletionCreateArgs) -> None: - params: CompletionCreateParams = { - "model": args.model, - "messages": [ - {"role": cast(Literal["user"], message.role), "content": message.content} for message in args.message - ], - # type checkers are not good at inferring union types so we have to set stream afterwards - "stream": False, - } - if args.temperature is not None: - params["temperature"] = args.temperature - if args.stop is not None: - params["stop"] = args.stop - if args.top_p is not None: - params["top_p"] = args.top_p - if args.n is not None: - params["n"] = args.n - if args.stream: - params["stream"] = args.stream # type: ignore - if args.max_tokens is not None: - params["max_tokens"] = args.max_tokens - - if args.stream: - return CLIChatCompletion._stream_create(cast(CompletionCreateParamsStreaming, params)) - - return CLIChatCompletion._create(cast(CompletionCreateParamsNonStreaming, params)) - - @staticmethod - def _create(params: CompletionCreateParamsNonStreaming) -> None: - completion = get_client().chat.completions.create(**params) - should_print_header = len(completion.choices) > 1 - for choice in completion.choices: - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - content = choice.message.content if choice.message.content is not None else "None" - sys.stdout.write(content) - - if should_print_header or not content.endswith("\n"): - sys.stdout.write("\n") - - sys.stdout.flush() - - @staticmethod - def _stream_create(params: CompletionCreateParamsStreaming) -> None: - # cast is required for mypy - stream = cast( # pyright: ignore[reportUnnecessaryCast] - Stream[ChatCompletionChunk], get_client().chat.completions.create(**params) - ) - for chunk in stream: - should_print_header = len(chunk.choices) > 1 - for choice in chunk.choices: - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - content = choice.delta.content or "" - sys.stdout.write(content) - - if should_print_header: - sys.stdout.write("\n") - - sys.stdout.flush() - - sys.stdout.write("\n") diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/completions.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/completions.py deleted file mode 100644 index b22ecde..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/completions.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING, Optional, cast -from argparse import ArgumentParser -from functools import partial - -from openai.types.completion import Completion - -from .._utils import get_client -from ..._types import Omittable, omit -from ..._utils import is_given -from .._errors import CLIError -from .._models import BaseModel -from ..._streaming import Stream - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("completions.create") - - # Required - sub.add_argument( - "-m", - "--model", - help="The model to use", - required=True, - ) - - # Optional - sub.add_argument("-p", "--prompt", help="An optional prompt to complete from") - sub.add_argument("--stream", help="Stream tokens as they're ready.", action="store_true") - sub.add_argument("-M", "--max-tokens", help="The maximum number of tokens to generate", type=int) - sub.add_argument( - "-t", - "--temperature", - help="""What sampling temperature to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. - -Mutually exclusive with `top_p`.""", - type=float, - ) - sub.add_argument( - "-P", - "--top_p", - help="""An alternative to sampling with temperature, called nucleus sampling, where the considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10%% probability mass are considered. - - Mutually exclusive with `temperature`.""", - type=float, - ) - sub.add_argument( - "-n", - "--n", - help="How many sub-completions to generate for each prompt.", - type=int, - ) - sub.add_argument( - "--logprobs", - help="Include the log probabilities on the `logprobs` most likely tokens, as well the chosen tokens. So for example, if `logprobs` is 10, the API will return a list of the 10 most likely tokens. If `logprobs` is 0, only the chosen tokens will have logprobs returned.", - type=int, - ) - sub.add_argument( - "--best_of", - help="Generates `best_of` completions server-side and returns the 'best' (the one with the highest log probability per token). Results cannot be streamed.", - type=int, - ) - sub.add_argument( - "--echo", - help="Echo back the prompt in addition to the completion", - action="store_true", - ) - sub.add_argument( - "--frequency_penalty", - help="Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.", - type=float, - ) - sub.add_argument( - "--presence_penalty", - help="Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.", - type=float, - ) - sub.add_argument("--suffix", help="The suffix that comes after a completion of inserted text.") - sub.add_argument("--stop", help="A stop sequence at which to stop generating tokens.") - sub.add_argument( - "--user", - help="A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.", - ) - # TODO: add support for logit_bias - sub.set_defaults(func=CLICompletions.create, args_model=CLICompletionCreateArgs) - - -class CLICompletionCreateArgs(BaseModel): - model: str - stream: bool = False - - prompt: Optional[str] = None - n: Omittable[int] = omit - stop: Omittable[str] = omit - user: Omittable[str] = omit - echo: Omittable[bool] = omit - suffix: Omittable[str] = omit - best_of: Omittable[int] = omit - top_p: Omittable[float] = omit - logprobs: Omittable[int] = omit - max_tokens: Omittable[int] = omit - temperature: Omittable[float] = omit - presence_penalty: Omittable[float] = omit - frequency_penalty: Omittable[float] = omit - - -class CLICompletions: - @staticmethod - def create(args: CLICompletionCreateArgs) -> None: - if is_given(args.n) and args.n > 1 and args.stream: - raise CLIError("Can't stream completions with n>1 with the current CLI") - - make_request = partial( - get_client().completions.create, - n=args.n, - echo=args.echo, - stop=args.stop, - user=args.user, - model=args.model, - top_p=args.top_p, - prompt=args.prompt, - suffix=args.suffix, - best_of=args.best_of, - logprobs=args.logprobs, - max_tokens=args.max_tokens, - temperature=args.temperature, - presence_penalty=args.presence_penalty, - frequency_penalty=args.frequency_penalty, - ) - - if args.stream: - return CLICompletions._stream_create( - # mypy doesn't understand the `partial` function but pyright does - cast(Stream[Completion], make_request(stream=True)) # pyright: ignore[reportUnnecessaryCast] - ) - - return CLICompletions._create(make_request()) - - @staticmethod - def _create(completion: Completion) -> None: - should_print_header = len(completion.choices) > 1 - for choice in completion.choices: - if should_print_header: - sys.stdout.write("===== Completion {} =====\n".format(choice.index)) - - sys.stdout.write(choice.text) - - if should_print_header or not choice.text.endswith("\n"): - sys.stdout.write("\n") - - sys.stdout.flush() - - @staticmethod - def _stream_create(stream: Stream[Completion]) -> None: - for completion in stream: - should_print_header = len(completion.choices) > 1 - for choice in sorted(completion.choices, key=lambda c: c.index): - if should_print_header: - sys.stdout.write("===== Chat Completion {} =====\n".format(choice.index)) - - sys.stdout.write(choice.text) - - if should_print_header: - sys.stdout.write("\n") - - sys.stdout.flush() - - sys.stdout.write("\n") diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/files.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/files.py deleted file mode 100644 index 5f3631b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/files.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from .._models import BaseModel -from .._progress import BufferReader - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("files.create") - - sub.add_argument( - "-f", - "--file", - required=True, - help="File to upload", - ) - sub.add_argument( - "-p", - "--purpose", - help="Why are you uploading this file? (see https://platform.openai.com/docs/api-reference/ for purposes)", - required=True, - ) - sub.set_defaults(func=CLIFile.create, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.retrieve") - sub.add_argument("-i", "--id", required=True, help="The files ID") - sub.set_defaults(func=CLIFile.get, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.delete") - sub.add_argument("-i", "--id", required=True, help="The files ID") - sub.set_defaults(func=CLIFile.delete, args_model=CLIFileCreateArgs) - - sub = subparser.add_parser("files.list") - sub.set_defaults(func=CLIFile.list) - - -class CLIFileIDArgs(BaseModel): - id: str - - -class CLIFileCreateArgs(BaseModel): - file: str - purpose: str - - -class CLIFile: - @staticmethod - def create(args: CLIFileCreateArgs) -> None: - with open(args.file, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - file = get_client().files.create( - file=(args.file, buffer_reader), - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - purpose=cast(Any, args.purpose), - ) - print_model(file) - - @staticmethod - def get(args: CLIFileIDArgs) -> None: - file = get_client().files.retrieve(file_id=args.id) - print_model(file) - - @staticmethod - def delete(args: CLIFileIDArgs) -> None: - file = get_client().files.delete(file_id=args.id) - print_model(file) - - @staticmethod - def list() -> None: - files = get_client().files.list() - for file in files: - print_model(file) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/__init__.py deleted file mode 100644 index 11a2dfc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import jobs - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - jobs.register(subparser) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/jobs.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/jobs.py deleted file mode 100644 index a4e4291..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/fine_tuning/jobs.py +++ /dev/null @@ -1,170 +0,0 @@ -from __future__ import annotations - -import json -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from ..._utils import get_client, print_model -from ...._types import Omittable, omit -from ...._utils import is_given -from ..._models import BaseModel -from ....pagination import SyncCursorPage -from ....types.fine_tuning import ( - FineTuningJob, - FineTuningJobEvent, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("fine_tuning.jobs.create") - sub.add_argument( - "-m", - "--model", - help="The model to fine-tune.", - required=True, - ) - sub.add_argument( - "-F", - "--training-file", - help="The training file to fine-tune the model on.", - required=True, - ) - sub.add_argument( - "-H", - "--hyperparameters", - help="JSON string of hyperparameters to use for fine-tuning.", - type=str, - ) - sub.add_argument( - "-s", - "--suffix", - help="A suffix to add to the fine-tuned model name.", - ) - sub.add_argument( - "-V", - "--validation-file", - help="The validation file to use for fine-tuning.", - ) - sub.set_defaults(func=CLIFineTuningJobs.create, args_model=CLIFineTuningJobsCreateArgs) - - sub = subparser.add_parser("fine_tuning.jobs.retrieve") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to retrieve.", - required=True, - ) - sub.set_defaults(func=CLIFineTuningJobs.retrieve, args_model=CLIFineTuningJobsRetrieveArgs) - - sub = subparser.add_parser("fine_tuning.jobs.list") - sub.add_argument( - "-a", - "--after", - help="Identifier for the last job from the previous pagination request. If provided, only jobs created after this job will be returned.", - ) - sub.add_argument( - "-l", - "--limit", - help="Number of fine-tuning jobs to retrieve.", - type=int, - ) - sub.set_defaults(func=CLIFineTuningJobs.list, args_model=CLIFineTuningJobsListArgs) - - sub = subparser.add_parser("fine_tuning.jobs.cancel") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to cancel.", - required=True, - ) - sub.set_defaults(func=CLIFineTuningJobs.cancel, args_model=CLIFineTuningJobsCancelArgs) - - sub = subparser.add_parser("fine_tuning.jobs.list_events") - sub.add_argument( - "-i", - "--id", - help="The ID of the fine-tuning job to list events for.", - required=True, - ) - sub.add_argument( - "-a", - "--after", - help="Identifier for the last event from the previous pagination request. If provided, only events created after this event will be returned.", - ) - sub.add_argument( - "-l", - "--limit", - help="Number of fine-tuning job events to retrieve.", - type=int, - ) - sub.set_defaults(func=CLIFineTuningJobs.list_events, args_model=CLIFineTuningJobsListEventsArgs) - - -class CLIFineTuningJobsCreateArgs(BaseModel): - model: str - training_file: str - hyperparameters: Omittable[str] = omit - suffix: Omittable[str] = omit - validation_file: Omittable[str] = omit - - -class CLIFineTuningJobsRetrieveArgs(BaseModel): - id: str - - -class CLIFineTuningJobsListArgs(BaseModel): - after: Omittable[str] = omit - limit: Omittable[int] = omit - - -class CLIFineTuningJobsCancelArgs(BaseModel): - id: str - - -class CLIFineTuningJobsListEventsArgs(BaseModel): - id: str - after: Omittable[str] = omit - limit: Omittable[int] = omit - - -class CLIFineTuningJobs: - @staticmethod - def create(args: CLIFineTuningJobsCreateArgs) -> None: - hyperparameters = json.loads(str(args.hyperparameters)) if is_given(args.hyperparameters) else omit - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.create( - model=args.model, - training_file=args.training_file, - hyperparameters=hyperparameters, - suffix=args.suffix, - validation_file=args.validation_file, - ) - print_model(fine_tuning_job) - - @staticmethod - def retrieve(args: CLIFineTuningJobsRetrieveArgs) -> None: - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.retrieve(fine_tuning_job_id=args.id) - print_model(fine_tuning_job) - - @staticmethod - def list(args: CLIFineTuningJobsListArgs) -> None: - fine_tuning_jobs: SyncCursorPage[FineTuningJob] = get_client().fine_tuning.jobs.list( - after=args.after or omit, limit=args.limit or omit - ) - print_model(fine_tuning_jobs) - - @staticmethod - def cancel(args: CLIFineTuningJobsCancelArgs) -> None: - fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.cancel(fine_tuning_job_id=args.id) - print_model(fine_tuning_job) - - @staticmethod - def list_events(args: CLIFineTuningJobsListEventsArgs) -> None: - fine_tuning_job_events: SyncCursorPage[FineTuningJobEvent] = get_client().fine_tuning.jobs.list_events( - fine_tuning_job_id=args.id, - after=args.after or omit, - limit=args.limit or omit, - ) - print_model(fine_tuning_job_events) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/image.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/image.py deleted file mode 100644 index 1d0cf81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/image.py +++ /dev/null @@ -1,139 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, cast -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from ..._types import Omit, Omittable, omit -from .._models import BaseModel -from .._progress import BufferReader - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("images.generate") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-p", "--prompt", type=str, required=True) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.set_defaults(func=CLIImage.create, args_model=CLIImageCreateArgs) - - sub = subparser.add_parser("images.edit") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-p", "--prompt", type=str, required=True) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument( - "-I", - "--image", - type=str, - required=True, - help="Image to modify. Should be a local path and a PNG encoded image.", - ) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.add_argument( - "-M", - "--mask", - type=str, - required=False, - help="Path to a mask image. It should be the same size as the image you're editing and a RGBA PNG image. The Alpha channel acts as the mask.", - ) - sub.set_defaults(func=CLIImage.edit, args_model=CLIImageEditArgs) - - sub = subparser.add_parser("images.create_variation") - sub.add_argument("-m", "--model", type=str) - sub.add_argument("-n", "--num-images", type=int, default=1) - sub.add_argument( - "-I", - "--image", - type=str, - required=True, - help="Image to modify. Should be a local path and a PNG encoded image.", - ) - sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image") - sub.add_argument("--response-format", type=str, default="url") - sub.set_defaults(func=CLIImage.create_variation, args_model=CLIImageCreateVariationArgs) - - -class CLIImageCreateArgs(BaseModel): - prompt: str - num_images: int - size: str - response_format: str - model: Omittable[str] = omit - - -class CLIImageCreateVariationArgs(BaseModel): - image: str - num_images: int - size: str - response_format: str - model: Omittable[str] = omit - - -class CLIImageEditArgs(BaseModel): - image: str - num_images: int - size: str - response_format: str - prompt: str - mask: Omittable[str] = omit - model: Omittable[str] = omit - - -class CLIImage: - @staticmethod - def create(args: CLIImageCreateArgs) -> None: - image = get_client().images.generate( - model=args.model, - prompt=args.prompt, - n=args.num_images, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) - - @staticmethod - def create_variation(args: CLIImageCreateVariationArgs) -> None: - with open(args.image, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Upload progress") - - image = get_client().images.create_variation( - model=args.model, - image=("image", buffer_reader), - n=args.num_images, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) - - @staticmethod - def edit(args: CLIImageEditArgs) -> None: - with open(args.image, "rb") as file_reader: - buffer_reader = BufferReader(file_reader.read(), desc="Image upload progress") - - if isinstance(args.mask, Omit): - mask: Omittable[BufferReader] = omit - else: - with open(args.mask, "rb") as file_reader: - mask = BufferReader(file_reader.read(), desc="Mask progress") - - image = get_client().images.edit( - model=args.model, - prompt=args.prompt, - image=("image", buffer_reader), - n=args.num_images, - mask=("mask", mask) if not isinstance(mask, Omit) else mask, - # casts required because the API is typed for enums - # but we don't want to validate that here for forwards-compat - size=cast(Any, args.size), - response_format=cast(Any, args.response_format), - ) - print_model(image) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/models.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/models.py deleted file mode 100644 index 017218f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_api/models.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from .._utils import get_client, print_model -from .._models import BaseModel - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("models.list") - sub.set_defaults(func=CLIModels.list) - - sub = subparser.add_parser("models.retrieve") - sub.add_argument("-i", "--id", required=True, help="The model ID") - sub.set_defaults(func=CLIModels.get, args_model=CLIModelIDArgs) - - sub = subparser.add_parser("models.delete") - sub.add_argument("-i", "--id", required=True, help="The model ID") - sub.set_defaults(func=CLIModels.delete, args_model=CLIModelIDArgs) - - -class CLIModelIDArgs(BaseModel): - id: str - - -class CLIModels: - @staticmethod - def get(args: CLIModelIDArgs) -> None: - model = get_client().models.retrieve(model=args.id) - print_model(model) - - @staticmethod - def delete(args: CLIModelIDArgs) -> None: - model = get_client().models.delete(model=args.id) - print_model(model) - - @staticmethod - def list() -> None: - models = get_client().models.list() - for model in models: - print_model(model) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_cli.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_cli.py deleted file mode 100644 index d31196d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_cli.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import annotations - -import sys -import logging -import argparse -from typing import Any, List, Type, Optional -from typing_extensions import ClassVar - -import httpx -import pydantic - -import openai - -from . import _tools -from .. import _ApiType, __version__ -from ._api import register_commands -from ._utils import can_use_http2 -from ._errors import CLIError, display_error -from .._compat import PYDANTIC_V1, ConfigDict, model_parse -from .._models import BaseModel -from .._exceptions import APIError - -logger = logging.getLogger() -formatter = logging.Formatter("[%(asctime)s] %(message)s") -handler = logging.StreamHandler(sys.stderr) -handler.setFormatter(formatter) -logger.addHandler(handler) - - -class Arguments(BaseModel): - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # type: ignore - extra: Any = pydantic.Extra.ignore # type: ignore - else: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="ignore", - ) - - verbosity: int - version: Optional[str] = None - - api_key: Optional[str] - api_base: Optional[str] - organization: Optional[str] - proxy: Optional[List[str]] - api_type: Optional[_ApiType] = None - api_version: Optional[str] = None - - # azure - azure_endpoint: Optional[str] = None - azure_ad_token: Optional[str] = None - - # internal, set by subparsers to parse their specific args - args_model: Optional[Type[BaseModel]] = None - - # internal, used so that subparsers can forward unknown arguments - unknown_args: List[str] = [] - allow_unknown_args: bool = False - - -def _build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser(description=None, prog="openai") - parser.add_argument( - "-v", - "--verbose", - action="count", - dest="verbosity", - default=0, - help="Set verbosity.", - ) - parser.add_argument("-b", "--api-base", help="What API base url to use.") - parser.add_argument("-k", "--api-key", help="What API key to use.") - parser.add_argument("-p", "--proxy", nargs="+", help="What proxy to use.") - parser.add_argument( - "-o", - "--organization", - help="Which organization to run as (will use your default organization if not specified)", - ) - parser.add_argument( - "-t", - "--api-type", - type=str, - choices=("openai", "azure"), - help="The backend API to call, must be `openai` or `azure`", - ) - parser.add_argument( - "--api-version", - help="The Azure API version, e.g. 'https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning'", - ) - - # azure - parser.add_argument( - "--azure-endpoint", - help="The Azure endpoint, e.g. 'https://endpoint.openai.azure.com'", - ) - parser.add_argument( - "--azure-ad-token", - help="A token from Azure Active Directory, https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id", - ) - - # prints the package version - parser.add_argument( - "-V", - "--version", - action="version", - version="%(prog)s " + __version__, - ) - - def help() -> None: - parser.print_help() - - parser.set_defaults(func=help) - - subparsers = parser.add_subparsers() - sub_api = subparsers.add_parser("api", help="Direct API calls") - - register_commands(sub_api) - - sub_tools = subparsers.add_parser("tools", help="Client side tools for convenience") - _tools.register_commands(sub_tools, subparsers) - - return parser - - -def main() -> int: - try: - _main() - except (APIError, CLIError, pydantic.ValidationError) as err: - display_error(err) - return 1 - except KeyboardInterrupt: - sys.stderr.write("\n") - return 1 - return 0 - - -def _parse_args(parser: argparse.ArgumentParser) -> tuple[argparse.Namespace, Arguments, list[str]]: - # argparse by default will strip out the `--` but we want to keep it for unknown arguments - if "--" in sys.argv: - idx = sys.argv.index("--") - known_args = sys.argv[1:idx] - unknown_args = sys.argv[idx:] - else: - known_args = sys.argv[1:] - unknown_args = [] - - parsed, remaining_unknown = parser.parse_known_args(known_args) - - # append any remaining unknown arguments from the initial parsing - remaining_unknown.extend(unknown_args) - - args = model_parse(Arguments, vars(parsed)) - if not args.allow_unknown_args: - # we have to parse twice to ensure any unknown arguments - # result in an error if that behaviour is desired - parser.parse_args() - - return parsed, args, remaining_unknown - - -def _main() -> None: - parser = _build_parser() - parsed, args, unknown = _parse_args(parser) - - if args.verbosity != 0: - sys.stderr.write("Warning: --verbosity isn't supported yet\n") - - proxies: dict[str, httpx.BaseTransport] = {} - if args.proxy is not None: - for proxy in args.proxy: - key = "https://" if proxy.startswith("https") else "http://" - if key in proxies: - raise CLIError(f"Multiple {key} proxies given - only the last one would be used") - - proxies[key] = httpx.HTTPTransport(proxy=httpx.Proxy(httpx.URL(proxy))) - - http_client = httpx.Client( - mounts=proxies or None, - http2=can_use_http2(), - ) - openai.http_client = http_client - - if args.organization: - openai.organization = args.organization - - if args.api_key: - openai.api_key = args.api_key - - if args.api_base: - openai.base_url = args.api_base - - # azure - if args.api_type is not None: - openai.api_type = args.api_type - - if args.azure_endpoint is not None: - openai.azure_endpoint = args.azure_endpoint - - if args.api_version is not None: - openai.api_version = args.api_version - - if args.azure_ad_token is not None: - openai.azure_ad_token = args.azure_ad_token - - try: - if args.args_model: - parsed.func( - model_parse( - args.args_model, - { - **{ - # we omit None values so that they can be defaulted to `NotGiven` - # and we'll strip it from the API request - key: value - for key, value in vars(parsed).items() - if value is not None - }, - "unknown_args": unknown, - }, - ) - ) - else: - parsed.func() - finally: - try: - http_client.close() - except Exception: - pass - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_errors.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_errors.py deleted file mode 100644 index 7d0292d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_errors.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import annotations - -import sys - -import pydantic - -from ._utils import Colors, organization_info -from .._exceptions import APIError, OpenAIError - - -class CLIError(OpenAIError): ... - - -class SilentCLIError(CLIError): ... - - -def display_error(err: CLIError | APIError | pydantic.ValidationError) -> None: - if isinstance(err, SilentCLIError): - return - - sys.stderr.write("{}{}Error:{} {}\n".format(organization_info(), Colors.FAIL, Colors.ENDC, err)) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_models.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_models.py deleted file mode 100644 index a886089..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_models.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Any -from typing_extensions import ClassVar - -import pydantic - -from .. import _models -from .._compat import PYDANTIC_V1, ConfigDict - - -class BaseModel(_models.BaseModel): - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # type: ignore - extra: Any = pydantic.Extra.ignore # type: ignore - arbitrary_types_allowed: bool = True - else: - model_config: ClassVar[ConfigDict] = ConfigDict(extra="ignore", arbitrary_types_allowed=True) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_progress.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_progress.py deleted file mode 100644 index 8a7f252..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_progress.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -import io -from typing import Callable -from typing_extensions import override - - -class CancelledError(Exception): - def __init__(self, msg: str) -> None: - self.msg = msg - super().__init__(msg) - - @override - def __str__(self) -> str: - return self.msg - - __repr__ = __str__ - - -class BufferReader(io.BytesIO): - def __init__(self, buf: bytes = b"", desc: str | None = None) -> None: - super().__init__(buf) - self._len = len(buf) - self._progress = 0 - self._callback = progress(len(buf), desc=desc) - - def __len__(self) -> int: - return self._len - - @override - def read(self, n: int | None = -1) -> bytes: - chunk = io.BytesIO.read(self, n) - self._progress += len(chunk) - - try: - self._callback(self._progress) - except Exception as e: # catches exception from the callback - raise CancelledError("The upload was cancelled: {}".format(e)) from e - - return chunk - - -def progress(total: float, desc: str | None) -> Callable[[float], None]: - import tqdm - - meter = tqdm.tqdm(total=total, unit_scale=True, desc=desc) - - def incr(progress: float) -> None: - meter.n = progress - if progress == total: - meter.close() - else: - meter.refresh() - - return incr - - -def MB(i: int) -> int: - return int(i // 1024**2) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/__init__.py deleted file mode 100644 index 56a0260..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from ._main import register_commands as register_commands diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/_main.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/_main.py deleted file mode 100644 index bd6cda4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/_main.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from . import migrate, fine_tunes - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register_commands(parser: ArgumentParser, subparser: _SubParsersAction[ArgumentParser]) -> None: - migrate.register(subparser) - - namespaced = parser.add_subparsers(title="Tools", help="Convenience client side tools") - - fine_tunes.register(namespaced) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/fine_tunes.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/fine_tunes.py deleted file mode 100644 index 2128b88..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/fine_tunes.py +++ /dev/null @@ -1,63 +0,0 @@ -from __future__ import annotations - -import sys -from typing import TYPE_CHECKING -from argparse import ArgumentParser - -from .._models import BaseModel -from ...lib._validators import ( - get_validators, - write_out_file, - read_any_format, - apply_validators, - apply_necessary_remediation, -) - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("fine_tunes.prepare_data") - sub.add_argument( - "-f", - "--file", - required=True, - help="JSONL, JSON, CSV, TSV, TXT or XLSX file containing prompt-completion examples to be analyzed." - "This should be the local file path.", - ) - sub.add_argument( - "-q", - "--quiet", - required=False, - action="store_true", - help="Auto accepts all suggestions, without asking for user input. To be used within scripts.", - ) - sub.set_defaults(func=prepare_data, args_model=PrepareDataArgs) - - -class PrepareDataArgs(BaseModel): - file: str - - quiet: bool - - -def prepare_data(args: PrepareDataArgs) -> None: - sys.stdout.write("Analyzing...\n") - fname = args.file - auto_accept = args.quiet - df, remediation = read_any_format(fname) - apply_necessary_remediation(None, remediation) - - validators = get_validators() - - assert df is not None - - apply_validators( - df, - fname, - remediation, - validators, - auto_accept, - write_out_file_func=write_out_file, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/migrate.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/migrate.py deleted file mode 100644 index 841b777..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_tools/migrate.py +++ /dev/null @@ -1,164 +0,0 @@ -from __future__ import annotations - -import os -import sys -import shutil -import tarfile -import platform -import subprocess -from typing import TYPE_CHECKING, List -from pathlib import Path -from argparse import ArgumentParser - -import httpx - -from .._errors import CLIError, SilentCLIError -from .._models import BaseModel - -if TYPE_CHECKING: - from argparse import _SubParsersAction - - -def register(subparser: _SubParsersAction[ArgumentParser]) -> None: - sub = subparser.add_parser("migrate") - sub.set_defaults(func=migrate, args_model=MigrateArgs, allow_unknown_args=True) - - sub = subparser.add_parser("grit") - sub.set_defaults(func=grit, args_model=GritArgs, allow_unknown_args=True) - - -class GritArgs(BaseModel): - # internal - unknown_args: List[str] = [] - - -def grit(args: GritArgs) -> None: - grit_path = install() - - try: - subprocess.check_call([grit_path, *args.unknown_args]) - except subprocess.CalledProcessError: - # stdout and stderr are forwarded by subprocess so an error will already - # have been displayed - raise SilentCLIError() from None - - -class MigrateArgs(BaseModel): - # internal - unknown_args: List[str] = [] - - -def migrate(args: MigrateArgs) -> None: - grit_path = install() - - try: - subprocess.check_call([grit_path, "apply", "openai", *args.unknown_args]) - except subprocess.CalledProcessError: - # stdout and stderr are forwarded by subprocess so an error will already - # have been displayed - raise SilentCLIError() from None - - -# handles downloading the Grit CLI until they provide their own PyPi package - -KEYGEN_ACCOUNT = "custodian-dev" - - -def _cache_dir() -> Path: - xdg = os.environ.get("XDG_CACHE_HOME") - if xdg is not None: - return Path(xdg) - - return Path.home() / ".cache" - - -def _debug(message: str) -> None: - if not os.environ.get("DEBUG"): - return - - sys.stdout.write(f"[DEBUG]: {message}\n") - - -def install() -> Path: - """Installs the Grit CLI and returns the location of the binary""" - if sys.platform == "win32": - raise CLIError("Windows is not supported yet in the migration CLI") - - _debug("Using Grit installer from GitHub") - - platform = "apple-darwin" if sys.platform == "darwin" else "unknown-linux-gnu" - - dir_name = _cache_dir() / "openai-python" - install_dir = dir_name / ".install" - target_dir = install_dir / "bin" - - target_path = target_dir / "grit" - temp_file = target_dir / "grit.tmp" - - if target_path.exists(): - _debug(f"{target_path} already exists") - sys.stdout.flush() - return target_path - - _debug(f"Using Grit CLI path: {target_path}") - - target_dir.mkdir(parents=True, exist_ok=True) - - if temp_file.exists(): - temp_file.unlink() - - arch = _get_arch() - _debug(f"Using architecture {arch}") - - file_name = f"grit-{arch}-{platform}" - download_url = f"https://github.com/getgrit/gritql/releases/latest/download/{file_name}.tar.gz" - - sys.stdout.write(f"Downloading Grit CLI from {download_url}\n") - with httpx.Client() as client: - download_response = client.get(download_url, follow_redirects=True) - if download_response.status_code != 200: - raise CLIError(f"Failed to download Grit CLI from {download_url}") - with open(temp_file, "wb") as file: - for chunk in download_response.iter_bytes(): - file.write(chunk) - - unpacked_dir = target_dir / "cli-bin" - unpacked_dir.mkdir(parents=True, exist_ok=True) - - with tarfile.open(temp_file, "r:gz") as archive: - if sys.version_info >= (3, 12): - archive.extractall(unpacked_dir, filter="data") - else: - archive.extractall(unpacked_dir) - - _move_files_recursively(unpacked_dir, target_dir) - - shutil.rmtree(unpacked_dir) - os.remove(temp_file) - os.chmod(target_path, 0o755) - - sys.stdout.flush() - - return target_path - - -def _move_files_recursively(source_dir: Path, target_dir: Path) -> None: - for item in source_dir.iterdir(): - if item.is_file(): - item.rename(target_dir / item.name) - elif item.is_dir(): - _move_files_recursively(item, target_dir) - - -def _get_arch() -> str: - architecture = platform.machine().lower() - - # Map the architecture names to Grit equivalents - arch_map = { - "x86_64": "x86_64", - "amd64": "x86_64", - "armv7l": "aarch64", - "arm64": "aarch64", - } - - return arch_map.get(architecture, architecture) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/cli/_utils.py b/backend/venv39/lib/python3.9/site-packages/openai/cli/_utils.py deleted file mode 100644 index 673eed6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/cli/_utils.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import sys - -import openai - -from .. import OpenAI, _load_client -from .._compat import model_json -from .._models import BaseModel - - -class Colors: - HEADER = "\033[95m" - OKBLUE = "\033[94m" - OKGREEN = "\033[92m" - WARNING = "\033[93m" - FAIL = "\033[91m" - ENDC = "\033[0m" - BOLD = "\033[1m" - UNDERLINE = "\033[4m" - - -def get_client() -> OpenAI: - return _load_client() - - -def organization_info() -> str: - organization = openai.organization - if organization is not None: - return "[organization={}] ".format(organization) - - return "" - - -def print_model(model: BaseModel) -> None: - sys.stdout.write(model_json(model, indent=2) + "\n") - - -def can_use_http2() -> bool: - try: - import h2 # type: ignore # noqa - except ImportError: - return False - - return True diff --git a/backend/venv39/lib/python3.9/site-packages/openai/helpers/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/helpers/__init__.py deleted file mode 100644 index ab3044d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/helpers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .microphone import Microphone -from .local_audio_player import LocalAudioPlayer - -__all__ = ["Microphone", "LocalAudioPlayer"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/helpers/local_audio_player.py b/backend/venv39/lib/python3.9/site-packages/openai/helpers/local_audio_player.py deleted file mode 100644 index 8f12c27..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/helpers/local_audio_player.py +++ /dev/null @@ -1,165 +0,0 @@ -# mypy: ignore-errors -from __future__ import annotations - -import queue -import asyncio -from typing import Any, Union, Callable, AsyncGenerator, cast -from typing_extensions import TYPE_CHECKING - -from .. import _legacy_response -from .._extras import numpy as np, sounddevice as sd -from .._response import StreamedBinaryAPIResponse, AsyncStreamedBinaryAPIResponse - -if TYPE_CHECKING: - import numpy.typing as npt - -SAMPLE_RATE = 24000 - - -class LocalAudioPlayer: - def __init__( - self, - should_stop: Union[Callable[[], bool], None] = None, - ): - self.channels = 1 - self.dtype = np.float32 - self.should_stop = should_stop - - async def _tts_response_to_buffer( - self, - response: Union[ - _legacy_response.HttpxBinaryResponseContent, - AsyncStreamedBinaryAPIResponse, - StreamedBinaryAPIResponse, - ], - ) -> npt.NDArray[np.float32]: - chunks: list[bytes] = [] - if isinstance(response, _legacy_response.HttpxBinaryResponseContent) or isinstance( - response, StreamedBinaryAPIResponse - ): - for chunk in response.iter_bytes(chunk_size=1024): - if chunk: - chunks.append(chunk) - else: - async for chunk in response.iter_bytes(chunk_size=1024): - if chunk: - chunks.append(chunk) - - audio_bytes = b"".join(chunks) - audio_np = np.frombuffer(audio_bytes, dtype=np.int16).astype(np.float32) / 32767.0 - audio_np = audio_np.reshape(-1, 1) - return audio_np - - async def play( - self, - input: Union[ - npt.NDArray[np.int16], - npt.NDArray[np.float32], - _legacy_response.HttpxBinaryResponseContent, - AsyncStreamedBinaryAPIResponse, - StreamedBinaryAPIResponse, - ], - ) -> None: - audio_content: npt.NDArray[np.float32] - if isinstance(input, np.ndarray): - if input.dtype == np.int16 and self.dtype == np.float32: - audio_content = (input.astype(np.float32) / 32767.0).reshape(-1, self.channels) - elif input.dtype == np.float32: - audio_content = cast("npt.NDArray[np.float32]", input) - else: - raise ValueError(f"Unsupported dtype: {input.dtype}") - else: - audio_content = await self._tts_response_to_buffer(input) - - loop = asyncio.get_event_loop() - event = asyncio.Event() - idx = 0 - - def callback( - outdata: npt.NDArray[np.float32], - frame_count: int, - _time_info: Any, - _status: Any, - ): - nonlocal idx - - remainder = len(audio_content) - idx - if remainder == 0 or (callable(self.should_stop) and self.should_stop()): - loop.call_soon_threadsafe(event.set) - raise sd.CallbackStop - valid_frames = frame_count if remainder >= frame_count else remainder - outdata[:valid_frames] = audio_content[idx : idx + valid_frames] - outdata[valid_frames:] = 0 - idx += valid_frames - - stream = sd.OutputStream( - samplerate=SAMPLE_RATE, - callback=callback, - dtype=audio_content.dtype, - channels=audio_content.shape[1], - ) - with stream: - await event.wait() - - async def play_stream( - self, - buffer_stream: AsyncGenerator[Union[npt.NDArray[np.float32], npt.NDArray[np.int16], None], None], - ) -> None: - loop = asyncio.get_event_loop() - event = asyncio.Event() - buffer_queue: queue.Queue[Union[npt.NDArray[np.float32], npt.NDArray[np.int16], None]] = queue.Queue(maxsize=50) - - async def buffer_producer(): - async for buffer in buffer_stream: - if buffer is None: - break - await loop.run_in_executor(None, buffer_queue.put, buffer) - await loop.run_in_executor(None, buffer_queue.put, None) # Signal completion - - def callback( - outdata: npt.NDArray[np.float32], - frame_count: int, - _time_info: Any, - _status: Any, - ): - nonlocal current_buffer, buffer_pos - - frames_written = 0 - while frames_written < frame_count: - if current_buffer is None or buffer_pos >= len(current_buffer): - try: - current_buffer = buffer_queue.get(timeout=0.1) - if current_buffer is None: - loop.call_soon_threadsafe(event.set) - raise sd.CallbackStop - buffer_pos = 0 - - if current_buffer.dtype == np.int16 and self.dtype == np.float32: - current_buffer = (current_buffer.astype(np.float32) / 32767.0).reshape(-1, self.channels) - - except queue.Empty: - outdata[frames_written:] = 0 - return - - remaining_frames = len(current_buffer) - buffer_pos - frames_to_write = min(frame_count - frames_written, remaining_frames) - outdata[frames_written : frames_written + frames_to_write] = current_buffer[ - buffer_pos : buffer_pos + frames_to_write - ] - buffer_pos += frames_to_write - frames_written += frames_to_write - - current_buffer = None - buffer_pos = 0 - - producer_task = asyncio.create_task(buffer_producer()) - - with sd.OutputStream( - samplerate=SAMPLE_RATE, - channels=self.channels, - dtype=self.dtype, - callback=callback, - ): - await event.wait() - - await producer_task diff --git a/backend/venv39/lib/python3.9/site-packages/openai/helpers/microphone.py b/backend/venv39/lib/python3.9/site-packages/openai/helpers/microphone.py deleted file mode 100644 index 62a6d8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/helpers/microphone.py +++ /dev/null @@ -1,100 +0,0 @@ -# mypy: ignore-errors -from __future__ import annotations - -import io -import time -import wave -import asyncio -from typing import Any, Type, Union, Generic, TypeVar, Callable, overload -from typing_extensions import TYPE_CHECKING, Literal - -from .._types import FileTypes, FileContent -from .._extras import numpy as np, sounddevice as sd - -if TYPE_CHECKING: - import numpy.typing as npt - -SAMPLE_RATE = 24000 - -DType = TypeVar("DType", bound=np.generic) - - -class Microphone(Generic[DType]): - def __init__( - self, - channels: int = 1, - dtype: Type[DType] = np.int16, - should_record: Union[Callable[[], bool], None] = None, - timeout: Union[float, None] = None, - ): - self.channels = channels - self.dtype = dtype - self.should_record = should_record - self.buffer_chunks = [] - self.timeout = timeout - self.has_record_function = callable(should_record) - - def _ndarray_to_wav(self, audio_data: npt.NDArray[DType]) -> FileTypes: - buffer: FileContent = io.BytesIO() - with wave.open(buffer, "w") as wav_file: - wav_file.setnchannels(self.channels) - wav_file.setsampwidth(np.dtype(self.dtype).itemsize) - wav_file.setframerate(SAMPLE_RATE) - wav_file.writeframes(audio_data.tobytes()) - buffer.seek(0) - return ("audio.wav", buffer, "audio/wav") - - @overload - async def record(self, return_ndarray: Literal[True]) -> npt.NDArray[DType]: ... - - @overload - async def record(self, return_ndarray: Literal[False]) -> FileTypes: ... - - @overload - async def record(self, return_ndarray: None = ...) -> FileTypes: ... - - async def record(self, return_ndarray: Union[bool, None] = False) -> Union[npt.NDArray[DType], FileTypes]: - loop = asyncio.get_event_loop() - event = asyncio.Event() - self.buffer_chunks: list[npt.NDArray[DType]] = [] - start_time = time.perf_counter() - - def callback( - indata: npt.NDArray[DType], - _frame_count: int, - _time_info: Any, - _status: Any, - ): - execution_time = time.perf_counter() - start_time - reached_recording_timeout = execution_time > self.timeout if self.timeout is not None else False - if reached_recording_timeout: - loop.call_soon_threadsafe(event.set) - raise sd.CallbackStop - - should_be_recording = self.should_record() if callable(self.should_record) else True - if not should_be_recording: - loop.call_soon_threadsafe(event.set) - raise sd.CallbackStop - - self.buffer_chunks.append(indata.copy()) - - stream = sd.InputStream( - callback=callback, - dtype=self.dtype, - samplerate=SAMPLE_RATE, - channels=self.channels, - ) - with stream: - await event.wait() - - # Concatenate all chunks into a single buffer, handle empty case - concatenated_chunks: npt.NDArray[DType] = ( - np.concatenate(self.buffer_chunks, axis=0) - if len(self.buffer_chunks) > 0 - else np.array([], dtype=self.dtype) - ) - - if return_ndarray: - return concatenated_chunks - else: - return self._ndarray_to_wav(concatenated_chunks) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/.keep b/backend/venv39/lib/python3.9/site-packages/openai/lib/.keep deleted file mode 100644 index 5e2c99f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/.keep +++ /dev/null @@ -1,4 +0,0 @@ -File generated from our OpenAPI spec by Stainless. - -This directory can be used to store custom files to expand the SDK. -It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/__init__.py deleted file mode 100644 index 5c6cb78..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from ._tools import pydantic_function_tool as pydantic_function_tool -from ._parsing import ResponseFormatT as ResponseFormatT diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_old_api.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_old_api.py deleted file mode 100644 index 929c87e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_old_api.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any -from typing_extensions import override - -from .._utils import LazyProxy -from .._exceptions import OpenAIError - -INSTRUCTIONS = """ - -You tried to access openai.{symbol}, but this is no longer supported in openai>=1.0.0 - see the README at https://github.com/openai/openai-python for the API. - -You can run `openai migrate` to automatically upgrade your codebase to use the 1.0.0 interface. - -Alternatively, you can pin your installation to the old version, e.g. `pip install openai==0.28` - -A detailed migration guide is available here: https://github.com/openai/openai-python/discussions/742 -""" - - -class APIRemovedInV1(OpenAIError): - def __init__(self, *, symbol: str) -> None: - super().__init__(INSTRUCTIONS.format(symbol=symbol)) - - -class APIRemovedInV1Proxy(LazyProxy[Any]): - def __init__(self, *, symbol: str) -> None: - super().__init__() - self._symbol = symbol - - @override - def __load__(self) -> Any: - # return the proxy until it is eventually called so that - # we don't break people that are just checking the attributes - # of a module - return self - - def __call__(self, *_args: Any, **_kwargs: Any) -> Any: - raise APIRemovedInV1(symbol=self._symbol) - - -SYMBOLS = [ - "Edit", - "File", - "Audio", - "Image", - "Model", - "Engine", - "Customer", - "FineTune", - "Embedding", - "Completion", - "Deployment", - "Moderation", - "ErrorObject", - "FineTuningJob", - "ChatCompletion", -] - -# we explicitly tell type checkers that nothing is exported -# from this file so that when we re-export the old symbols -# in `openai/__init__.py` they aren't added to the auto-complete -# suggestions given by editors -if TYPE_CHECKING: - __all__: list[str] = [] -else: - __all__ = SYMBOLS - - -__locals = locals() -for symbol in SYMBOLS: - __locals[symbol] = APIRemovedInV1Proxy(symbol=symbol) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/__init__.py deleted file mode 100644 index 4d454c3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from ._completions import ( - ResponseFormatT as ResponseFormatT, - has_parseable_input, - has_parseable_input as has_parseable_input, - maybe_parse_content as maybe_parse_content, - validate_input_tools as validate_input_tools, - parse_chat_completion as parse_chat_completion, - get_input_tool_by_name as get_input_tool_by_name, - solve_response_format_t as solve_response_format_t, - parse_function_tool_arguments as parse_function_tool_arguments, - type_to_response_format_param as type_to_response_format_param, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_completions.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_completions.py deleted file mode 100644 index 7903732..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_completions.py +++ /dev/null @@ -1,305 +0,0 @@ -from __future__ import annotations - -import json -import logging -from typing import TYPE_CHECKING, Any, Iterable, cast -from typing_extensions import TypeVar, TypeGuard, assert_never - -import pydantic - -from .._tools import PydanticFunctionTool -from ..._types import Omit, omit -from ..._utils import is_dict, is_given -from ..._compat import PYDANTIC_V1, model_parse_json -from ..._models import construct_type_unchecked -from .._pydantic import is_basemodel_type, to_strict_json_schema, is_dataclass_like_type -from ...types.chat import ( - ParsedChoice, - ChatCompletion, - ParsedFunction, - ParsedChatCompletion, - ChatCompletionMessage, - ParsedFunctionToolCall, - ParsedChatCompletionMessage, - ChatCompletionToolUnionParam, - ChatCompletionFunctionToolParam, - completion_create_params, -) -from ..._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError -from ...types.shared_params import FunctionDefinition -from ...types.chat.completion_create_params import ResponseFormat as ResponseFormatParam -from ...types.chat.chat_completion_message_function_tool_call import Function - -ResponseFormatT = TypeVar( - "ResponseFormatT", - # if it isn't given then we don't do any parsing - default=None, -) -_default_response_format: None = None - -log: logging.Logger = logging.getLogger("openai.lib.parsing") - - -def is_strict_chat_completion_tool_param( - tool: ChatCompletionToolUnionParam, -) -> TypeGuard[ChatCompletionFunctionToolParam]: - """Check if the given tool is a strict ChatCompletionFunctionToolParam.""" - if not tool["type"] == "function": - return False - if tool["function"].get("strict") is not True: - return False - - return True - - -def select_strict_chat_completion_tools( - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, -) -> Iterable[ChatCompletionFunctionToolParam] | Omit: - """Select only the strict ChatCompletionFunctionToolParams from the given tools.""" - if not is_given(tools): - return omit - - return [t for t in tools if is_strict_chat_completion_tool_param(t)] - - -def validate_input_tools( - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, -) -> Iterable[ChatCompletionFunctionToolParam] | Omit: - if not is_given(tools): - return omit - - for tool in tools: - if tool["type"] != "function": - raise ValueError( - f"Currently only `function` tool types support auto-parsing; Received `{tool['type']}`", - ) - - strict = tool["function"].get("strict") - if strict is not True: - raise ValueError( - f"`{tool['function']['name']}` is not strict. Only `strict` function tools can be auto-parsed" - ) - - return cast(Iterable[ChatCompletionFunctionToolParam], tools) - - -def parse_chat_completion( - *, - response_format: type[ResponseFormatT] | completion_create_params.ResponseFormat | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, - chat_completion: ChatCompletion | ParsedChatCompletion[object], -) -> ParsedChatCompletion[ResponseFormatT]: - if is_given(input_tools): - input_tools = [t for t in input_tools] - else: - input_tools = [] - - choices: list[ParsedChoice[ResponseFormatT]] = [] - for choice in chat_completion.choices: - if choice.finish_reason == "length": - raise LengthFinishReasonError(completion=chat_completion) - - if choice.finish_reason == "content_filter": - raise ContentFilterFinishReasonError() - - message = choice.message - - tool_calls: list[ParsedFunctionToolCall] = [] - if message.tool_calls: - for tool_call in message.tool_calls: - if tool_call.type == "function": - tool_call_dict = tool_call.to_dict() - tool_calls.append( - construct_type_unchecked( - value={ - **tool_call_dict, - "function": { - **cast(Any, tool_call_dict["function"]), - "parsed_arguments": parse_function_tool_arguments( - input_tools=input_tools, function=tool_call.function - ), - }, - }, - type_=ParsedFunctionToolCall, - ) - ) - elif tool_call.type == "custom": - # warn user that custom tool calls are not callable here - log.warning( - "Custom tool calls are not callable. Ignoring tool call: %s - %s", - tool_call.id, - tool_call.custom.name, - stacklevel=2, - ) - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(tool_call) - else: - tool_calls.append(tool_call) - - choices.append( - construct_type_unchecked( - type_=cast(Any, ParsedChoice)[solve_response_format_t(response_format)], - value={ - **choice.to_dict(), - "message": { - **message.to_dict(), - "parsed": maybe_parse_content( - response_format=response_format, - message=message, - ), - "tool_calls": tool_calls if tool_calls else None, - }, - }, - ) - ) - - return cast( - ParsedChatCompletion[ResponseFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedChatCompletion)[solve_response_format_t(response_format)], - value={ - **chat_completion.to_dict(), - "choices": choices, - }, - ), - ) - - -def get_input_tool_by_name( - *, input_tools: list[ChatCompletionToolUnionParam], name: str -) -> ChatCompletionFunctionToolParam | None: - return next((t for t in input_tools if t["type"] == "function" and t.get("function", {}).get("name") == name), None) - - -def parse_function_tool_arguments( - *, input_tools: list[ChatCompletionToolUnionParam], function: Function | ParsedFunction -) -> object | None: - input_tool = get_input_tool_by_name(input_tools=input_tools, name=function.name) - if not input_tool: - return None - - input_fn = cast(object, input_tool.get("function")) - if isinstance(input_fn, PydanticFunctionTool): - return model_parse_json(input_fn.model, function.arguments) - - input_fn = cast(FunctionDefinition, input_fn) - - if not input_fn.get("strict"): - return None - - return json.loads(function.arguments) # type: ignore[no-any-return] - - -def maybe_parse_content( - *, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - message: ChatCompletionMessage | ParsedChatCompletionMessage[object], -) -> ResponseFormatT | None: - if has_rich_response_format(response_format) and message.content and not message.refusal: - return _parse_content(response_format, message.content) - - return None - - -def solve_response_format_t( - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, -) -> type[ResponseFormatT]: - """Return the runtime type for the given response format. - - If no response format is given, or if we won't auto-parse the response format - then we default to `None`. - """ - if has_rich_response_format(response_format): - return response_format - - return cast("type[ResponseFormatT]", _default_response_format) - - -def has_parseable_input( - *, - response_format: type | ResponseFormatParam | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, -) -> bool: - if has_rich_response_format(response_format): - return True - - for input_tool in input_tools or []: - if is_parseable_tool(input_tool): - return True - - return False - - -def has_rich_response_format( - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, -) -> TypeGuard[type[ResponseFormatT]]: - if not is_given(response_format): - return False - - if is_response_format_param(response_format): - return False - - return True - - -def is_response_format_param(response_format: object) -> TypeGuard[ResponseFormatParam]: - return is_dict(response_format) - - -def is_parseable_tool(input_tool: ChatCompletionToolUnionParam) -> bool: - if input_tool["type"] != "function": - return False - - input_fn = cast(object, input_tool.get("function")) - if isinstance(input_fn, PydanticFunctionTool): - return True - - return cast(FunctionDefinition, input_fn).get("strict") or False - - -def _parse_content(response_format: type[ResponseFormatT], content: str) -> ResponseFormatT: - if is_basemodel_type(response_format): - return cast(ResponseFormatT, model_parse_json(response_format, content)) - - if is_dataclass_like_type(response_format): - if PYDANTIC_V1: - raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {response_format}") - - return pydantic.TypeAdapter(response_format).validate_json(content) - - raise TypeError(f"Unable to automatically parse response format type {response_format}") - - -def type_to_response_format_param( - response_format: type | completion_create_params.ResponseFormat | Omit, -) -> ResponseFormatParam | Omit: - if not is_given(response_format): - return omit - - if is_response_format_param(response_format): - return response_format - - # type checkers don't narrow the negation of a `TypeGuard` as it isn't - # a safe default behaviour but we know that at this point the `response_format` - # can only be a `type` - response_format = cast(type, response_format) - - json_schema_type: type[pydantic.BaseModel] | pydantic.TypeAdapter[Any] | None = None - - if is_basemodel_type(response_format): - name = response_format.__name__ - json_schema_type = response_format - elif is_dataclass_like_type(response_format): - name = response_format.__name__ - json_schema_type = pydantic.TypeAdapter(response_format) - else: - raise TypeError(f"Unsupported response_format type - {response_format}") - - return { - "type": "json_schema", - "json_schema": { - "schema": to_strict_json_schema(json_schema_type), - "name": name, - "strict": True, - }, - } diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_responses.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_responses.py deleted file mode 100644 index 4bed171..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_parsing/_responses.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import annotations - -import json -from typing import TYPE_CHECKING, Any, List, Iterable, cast -from typing_extensions import TypeVar, assert_never - -import pydantic - -from .._tools import ResponsesPydanticFunctionTool -from ..._types import Omit -from ..._utils import is_given -from ..._compat import PYDANTIC_V1, model_parse_json -from ..._models import construct_type_unchecked -from .._pydantic import is_basemodel_type, is_dataclass_like_type -from ._completions import solve_response_format_t, type_to_response_format_param -from ...types.responses import ( - Response, - ToolParam, - ParsedContent, - ParsedResponse, - FunctionToolParam, - ParsedResponseOutputItem, - ParsedResponseOutputText, - ResponseFunctionToolCall, - ParsedResponseOutputMessage, - ResponseFormatTextConfigParam, - ParsedResponseFunctionToolCall, -) -from ...types.chat.completion_create_params import ResponseFormat - -TextFormatT = TypeVar( - "TextFormatT", - # if it isn't given then we don't do any parsing - default=None, -) - - -def type_to_text_format_param(type_: type) -> ResponseFormatTextConfigParam: - response_format_dict = type_to_response_format_param(type_) - assert is_given(response_format_dict) - response_format_dict = cast(ResponseFormat, response_format_dict) # pyright: ignore[reportUnnecessaryCast] - assert response_format_dict["type"] == "json_schema" - assert "schema" in response_format_dict["json_schema"] - - return { - "type": "json_schema", - "strict": True, - "name": response_format_dict["json_schema"]["name"], - "schema": response_format_dict["json_schema"]["schema"], - } - - -def parse_response( - *, - text_format: type[TextFormatT] | Omit, - input_tools: Iterable[ToolParam] | Omit | None, - response: Response | ParsedResponse[object], -) -> ParsedResponse[TextFormatT]: - solved_t = solve_response_format_t(text_format) - output_list: List[ParsedResponseOutputItem[TextFormatT]] = [] - - for output in response.output: - if output.type == "message": - content_list: List[ParsedContent[TextFormatT]] = [] - for item in output.content: - if item.type != "output_text": - content_list.append(item) - continue - - content_list.append( - construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputText)[solved_t], - value={ - **item.to_dict(), - "parsed": parse_text(item.text, text_format=text_format), - }, - ) - ) - - output_list.append( - construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputMessage)[solved_t], - value={ - **output.to_dict(), - "content": content_list, - }, - ) - ) - elif output.type == "function_call": - output_list.append( - construct_type_unchecked( - type_=ParsedResponseFunctionToolCall, - value={ - **output.to_dict(), - "parsed_arguments": parse_function_tool_arguments( - input_tools=input_tools, function_call=output - ), - }, - ) - ) - elif ( - output.type == "computer_call" - or output.type == "file_search_call" - or output.type == "web_search_call" - or output.type == "reasoning" - or output.type == "compaction" - or output.type == "mcp_call" - or output.type == "mcp_approval_request" - or output.type == "image_generation_call" - or output.type == "code_interpreter_call" - or output.type == "local_shell_call" - or output.type == "shell_call" - or output.type == "shell_call_output" - or output.type == "apply_patch_call" - or output.type == "apply_patch_call_output" - or output.type == "mcp_list_tools" - or output.type == "exec" - or output.type == "custom_tool_call" - ): - output_list.append(output) - elif TYPE_CHECKING: # type: ignore - assert_never(output) - else: - output_list.append(output) - - return cast( - ParsedResponse[TextFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedResponse)[solved_t], - value={ - **response.to_dict(), - "output": output_list, - }, - ), - ) - - -def parse_text(text: str, text_format: type[TextFormatT] | Omit) -> TextFormatT | None: - if not is_given(text_format): - return None - - if is_basemodel_type(text_format): - return cast(TextFormatT, model_parse_json(text_format, text)) - - if is_dataclass_like_type(text_format): - if PYDANTIC_V1: - raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {text_format}") - - return pydantic.TypeAdapter(text_format).validate_json(text) - - raise TypeError(f"Unable to automatically parse response format type {text_format}") - - -def get_input_tool_by_name(*, input_tools: Iterable[ToolParam], name: str) -> FunctionToolParam | None: - for tool in input_tools: - if tool["type"] == "function" and tool.get("name") == name: - return tool - - return None - - -def parse_function_tool_arguments( - *, - input_tools: Iterable[ToolParam] | Omit | None, - function_call: ParsedResponseFunctionToolCall | ResponseFunctionToolCall, -) -> object: - if input_tools is None or not is_given(input_tools): - return None - - input_tool = get_input_tool_by_name(input_tools=input_tools, name=function_call.name) - if not input_tool: - return None - - tool = cast(object, input_tool) - if isinstance(tool, ResponsesPydanticFunctionTool): - return model_parse_json(tool.model, function_call.arguments) - - if not input_tool.get("strict"): - return None - - return json.loads(function_call.arguments) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_pydantic.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_pydantic.py deleted file mode 100644 index 3cfe224..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_pydantic.py +++ /dev/null @@ -1,155 +0,0 @@ -from __future__ import annotations - -import inspect -from typing import Any, TypeVar -from typing_extensions import TypeGuard - -import pydantic - -from .._types import NOT_GIVEN -from .._utils import is_dict as _is_dict, is_list -from .._compat import PYDANTIC_V1, model_json_schema - -_T = TypeVar("_T") - - -def to_strict_json_schema(model: type[pydantic.BaseModel] | pydantic.TypeAdapter[Any]) -> dict[str, Any]: - if inspect.isclass(model) and is_basemodel_type(model): - schema = model_json_schema(model) - elif (not PYDANTIC_V1) and isinstance(model, pydantic.TypeAdapter): - schema = model.json_schema() - else: - raise TypeError(f"Non BaseModel types are only supported with Pydantic v2 - {model}") - - return _ensure_strict_json_schema(schema, path=(), root=schema) - - -def _ensure_strict_json_schema( - json_schema: object, - *, - path: tuple[str, ...], - root: dict[str, object], -) -> dict[str, Any]: - """Mutates the given JSON schema to ensure it conforms to the `strict` standard - that the API expects. - """ - if not is_dict(json_schema): - raise TypeError(f"Expected {json_schema} to be a dictionary; path={path}") - - defs = json_schema.get("$defs") - if is_dict(defs): - for def_name, def_schema in defs.items(): - _ensure_strict_json_schema(def_schema, path=(*path, "$defs", def_name), root=root) - - definitions = json_schema.get("definitions") - if is_dict(definitions): - for definition_name, definition_schema in definitions.items(): - _ensure_strict_json_schema(definition_schema, path=(*path, "definitions", definition_name), root=root) - - typ = json_schema.get("type") - if typ == "object" and "additionalProperties" not in json_schema: - json_schema["additionalProperties"] = False - - # object types - # { 'type': 'object', 'properties': { 'a': {...} } } - properties = json_schema.get("properties") - if is_dict(properties): - json_schema["required"] = [prop for prop in properties.keys()] - json_schema["properties"] = { - key: _ensure_strict_json_schema(prop_schema, path=(*path, "properties", key), root=root) - for key, prop_schema in properties.items() - } - - # arrays - # { 'type': 'array', 'items': {...} } - items = json_schema.get("items") - if is_dict(items): - json_schema["items"] = _ensure_strict_json_schema(items, path=(*path, "items"), root=root) - - # unions - any_of = json_schema.get("anyOf") - if is_list(any_of): - json_schema["anyOf"] = [ - _ensure_strict_json_schema(variant, path=(*path, "anyOf", str(i)), root=root) - for i, variant in enumerate(any_of) - ] - - # intersections - all_of = json_schema.get("allOf") - if is_list(all_of): - if len(all_of) == 1: - json_schema.update(_ensure_strict_json_schema(all_of[0], path=(*path, "allOf", "0"), root=root)) - json_schema.pop("allOf") - else: - json_schema["allOf"] = [ - _ensure_strict_json_schema(entry, path=(*path, "allOf", str(i)), root=root) - for i, entry in enumerate(all_of) - ] - - # strip `None` defaults as there's no meaningful distinction here - # the schema will still be `nullable` and the model will default - # to using `None` anyway - if json_schema.get("default", NOT_GIVEN) is None: - json_schema.pop("default") - - # we can't use `$ref`s if there are also other properties defined, e.g. - # `{"$ref": "...", "description": "my description"}` - # - # so we unravel the ref - # `{"type": "string", "description": "my description"}` - ref = json_schema.get("$ref") - if ref and has_more_than_n_keys(json_schema, 1): - assert isinstance(ref, str), f"Received non-string $ref - {ref}" - - resolved = resolve_ref(root=root, ref=ref) - if not is_dict(resolved): - raise ValueError(f"Expected `$ref: {ref}` to resolved to a dictionary but got {resolved}") - - # properties from the json schema take priority over the ones on the `$ref` - json_schema.update({**resolved, **json_schema}) - json_schema.pop("$ref") - # Since the schema expanded from `$ref` might not have `additionalProperties: false` applied, - # we call `_ensure_strict_json_schema` again to fix the inlined schema and ensure it's valid. - return _ensure_strict_json_schema(json_schema, path=path, root=root) - - return json_schema - - -def resolve_ref(*, root: dict[str, object], ref: str) -> object: - if not ref.startswith("#/"): - raise ValueError(f"Unexpected $ref format {ref!r}; Does not start with #/") - - path = ref[2:].split("/") - resolved = root - for key in path: - value = resolved[key] - assert is_dict(value), f"encountered non-dictionary entry while resolving {ref} - {resolved}" - resolved = value - - return resolved - - -def is_basemodel_type(typ: type) -> TypeGuard[type[pydantic.BaseModel]]: - if not inspect.isclass(typ): - return False - return issubclass(typ, pydantic.BaseModel) - - -def is_dataclass_like_type(typ: type) -> bool: - """Returns True if the given type likely used `@pydantic.dataclass`""" - return hasattr(typ, "__pydantic_config__") - - -def is_dict(obj: object) -> TypeGuard[dict[str, object]]: - # just pretend that we know there are only `str` keys - # as that check is not worth the performance cost - return _is_dict(obj) - - -def has_more_than_n_keys(obj: dict[str, object], n: int) -> bool: - i = 0 - for _ in obj.keys(): - i += 1 - if i > n: - return True - return False diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_realtime.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_realtime.py deleted file mode 100644 index 999d1e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_realtime.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import annotations - -import json -from typing_extensions import override - -import httpx - -from openai import _legacy_response -from openai._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from openai._utils import maybe_transform, async_maybe_transform -from openai._base_client import make_request_options -from openai.resources.realtime.calls import Calls, AsyncCalls -from openai.types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam - -__all__ = ["_Calls", "_AsyncCalls"] - - -# Custom code to override the `create` method to have correct behavior with -# application/sdp and multipart/form-data. -# Ideally we can cutover to the generated code this overrides eventually and remove this. -class _Calls(Calls): - @override - def create( - self, - *, - sdp: str, - session: RealtimeSessionCreateRequestParam | Omit = omit, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - if session is omit: - extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} - return self._post( - "/realtime/calls", - body=sdp.encode("utf-8"), - options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - extra_headers = {"Accept": "application/sdp", "Content-Type": "multipart/form-data", **(extra_headers or {})} - session_payload = maybe_transform(session, RealtimeSessionCreateRequestParam) - files = [ - ("sdp", (None, sdp.encode("utf-8"), "application/sdp")), - ("session", (None, json.dumps(session_payload).encode("utf-8"), "application/json")), - ] - return self._post( - "/realtime/calls", - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - -class _AsyncCalls(AsyncCalls): - @override - async def create( - self, - *, - sdp: str, - session: RealtimeSessionCreateRequestParam | Omit = omit, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - if session is omit: - extra_headers = {"Accept": "application/sdp", "Content-Type": "application/sdp", **(extra_headers or {})} - return await self._post( - "/realtime/calls", - body=sdp.encode("utf-8"), - options=make_request_options(extra_headers=extra_headers, extra_query=extra_query, timeout=timeout), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - extra_headers = {"Accept": "application/sdp", "Content-Type": "multipart/form-data", **(extra_headers or {})} - session_payload = await async_maybe_transform(session, RealtimeSessionCreateRequestParam) - files = [ - ("sdp", (None, sdp.encode("utf-8"), "application/sdp")), - ("session", (None, json.dumps(session_payload).encode("utf-8"), "application/json")), - ] - return await self._post( - "/realtime/calls", - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_tools.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_tools.py deleted file mode 100644 index 4070ad6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_tools.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -from typing import Any, Dict, cast - -import pydantic - -from ._pydantic import to_strict_json_schema -from ..types.chat import ChatCompletionFunctionToolParam -from ..types.shared_params import FunctionDefinition -from ..types.responses.function_tool_param import FunctionToolParam as ResponsesFunctionToolParam - - -class PydanticFunctionTool(Dict[str, Any]): - """Dictionary wrapper so we can pass the given base model - throughout the entire request stack without having to special - case it. - """ - - model: type[pydantic.BaseModel] - - def __init__(self, defn: FunctionDefinition, model: type[pydantic.BaseModel]) -> None: - super().__init__(defn) - self.model = model - - def cast(self) -> FunctionDefinition: - return cast(FunctionDefinition, self) - - -class ResponsesPydanticFunctionTool(Dict[str, Any]): - model: type[pydantic.BaseModel] - - def __init__(self, tool: ResponsesFunctionToolParam, model: type[pydantic.BaseModel]) -> None: - super().__init__(tool) - self.model = model - - def cast(self) -> ResponsesFunctionToolParam: - return cast(ResponsesFunctionToolParam, self) - - -def pydantic_function_tool( - model: type[pydantic.BaseModel], - *, - name: str | None = None, # inferred from class name by default - description: str | None = None, # inferred from class docstring by default -) -> ChatCompletionFunctionToolParam: - if description is None: - # note: we intentionally don't use `.getdoc()` to avoid - # including pydantic's docstrings - description = model.__doc__ - - function = PydanticFunctionTool( - { - "name": name or model.__name__, - "strict": True, - "parameters": to_strict_json_schema(model), - }, - model, - ).cast() - - if description is not None: - function["description"] = description - - return { - "type": "function", - "function": function, - } diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/_validators.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/_validators.py deleted file mode 100644 index cf24cd2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/_validators.py +++ /dev/null @@ -1,809 +0,0 @@ -# pyright: basic -from __future__ import annotations - -import os -import sys -from typing import Any, TypeVar, Callable, Optional, NamedTuple -from typing_extensions import TypeAlias - -from .._extras import pandas as pd - - -class Remediation(NamedTuple): - name: str - immediate_msg: Optional[str] = None - necessary_msg: Optional[str] = None - necessary_fn: Optional[Callable[[Any], Any]] = None - optional_msg: Optional[str] = None - optional_fn: Optional[Callable[[Any], Any]] = None - error_msg: Optional[str] = None - - -OptionalDataFrameT = TypeVar("OptionalDataFrameT", bound="Optional[pd.DataFrame]") - - -def num_examples_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will only print out the number of examples and recommend to the user to increase the number of examples if less than 100. - """ - MIN_EXAMPLES = 100 - optional_suggestion = ( - "" - if len(df) >= MIN_EXAMPLES - else ". In general, we recommend having at least a few hundred examples. We've found that performance tends to linearly increase for every doubling of the number of examples" - ) - immediate_msg = f"\n- Your file contains {len(df)} prompt-completion pairs{optional_suggestion}" - return Remediation(name="num_examples", immediate_msg=immediate_msg) - - -def necessary_column_validator(df: pd.DataFrame, necessary_column: str) -> Remediation: - """ - This validator will ensure that the necessary column is present in the dataframe. - """ - - def lower_case_column(df: pd.DataFrame, column: Any) -> pd.DataFrame: - cols = [c for c in df.columns if str(c).lower() == column] - df.rename(columns={cols[0]: column.lower()}, inplace=True) - return df - - immediate_msg = None - necessary_fn = None - necessary_msg = None - error_msg = None - - if necessary_column not in df.columns: - if necessary_column in [str(c).lower() for c in df.columns]: - - def lower_case_column_creator(df: pd.DataFrame) -> pd.DataFrame: - return lower_case_column(df, necessary_column) - - necessary_fn = lower_case_column_creator - immediate_msg = f"\n- The `{necessary_column}` column/key should be lowercase" - necessary_msg = f"Lower case column name to `{necessary_column}`" - else: - error_msg = f"`{necessary_column}` column/key is missing. Please make sure you name your columns/keys appropriately, then retry" - - return Remediation( - name="necessary_column", - immediate_msg=immediate_msg, - necessary_msg=necessary_msg, - necessary_fn=necessary_fn, - error_msg=error_msg, - ) - - -def additional_column_validator(df: pd.DataFrame, fields: list[str] = ["prompt", "completion"]) -> Remediation: - """ - This validator will remove additional columns from the dataframe. - """ - additional_columns = [] - necessary_msg = None - immediate_msg = None - necessary_fn = None # type: ignore - - if len(df.columns) > 2: - additional_columns = [c for c in df.columns if c not in fields] - warn_message = "" - for ac in additional_columns: - dups = [c for c in additional_columns if ac in c] - if len(dups) > 0: - warn_message += f"\n WARNING: Some of the additional columns/keys contain `{ac}` in their name. These will be ignored, and the column/key `{ac}` will be used instead. This could also result from a duplicate column/key in the provided file." - immediate_msg = f"\n- The input file should contain exactly two columns/keys per row. Additional columns/keys present are: {additional_columns}{warn_message}" - necessary_msg = f"Remove additional columns/keys: {additional_columns}" - - def necessary_fn(x: Any) -> Any: - return x[fields] - - return Remediation( - name="additional_column", - immediate_msg=immediate_msg, - necessary_msg=necessary_msg, - necessary_fn=necessary_fn, - ) - - -def non_empty_field_validator(df: pd.DataFrame, field: str = "completion") -> Remediation: - """ - This validator will ensure that no completion is empty. - """ - necessary_msg = None - necessary_fn = None # type: ignore - immediate_msg = None - - if df[field].apply(lambda x: x == "").any() or df[field].isnull().any(): - empty_rows = (df[field] == "") | (df[field].isnull()) - empty_indexes = df.reset_index().index[empty_rows].tolist() - immediate_msg = f"\n- `{field}` column/key should not contain empty strings. These are rows: {empty_indexes}" - - def necessary_fn(x: Any) -> Any: - return x[x[field] != ""].dropna(subset=[field]) - - necessary_msg = f"Remove {len(empty_indexes)} rows with empty {field}s" - - return Remediation( - name=f"empty_{field}", - immediate_msg=immediate_msg, - necessary_msg=necessary_msg, - necessary_fn=necessary_fn, - ) - - -def duplicated_rows_validator(df: pd.DataFrame, fields: list[str] = ["prompt", "completion"]) -> Remediation: - """ - This validator will suggest to the user to remove duplicate rows if they exist. - """ - duplicated_rows = df.duplicated(subset=fields) - duplicated_indexes = df.reset_index().index[duplicated_rows].tolist() - immediate_msg = None - optional_msg = None - optional_fn = None # type: ignore - - if len(duplicated_indexes) > 0: - immediate_msg = f"\n- There are {len(duplicated_indexes)} duplicated {'-'.join(fields)} sets. These are rows: {duplicated_indexes}" - optional_msg = f"Remove {len(duplicated_indexes)} duplicate rows" - - def optional_fn(x: Any) -> Any: - return x.drop_duplicates(subset=fields) - - return Remediation( - name="duplicated_rows", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - ) - - -def long_examples_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to the user to remove examples that are too long. - """ - immediate_msg = None - optional_msg = None - optional_fn = None # type: ignore - - ft_type = infer_task_type(df) - if ft_type != "open-ended generation": - - def get_long_indexes(d: pd.DataFrame) -> Any: - long_examples = d.apply(lambda x: len(x.prompt) + len(x.completion) > 10000, axis=1) - return d.reset_index().index[long_examples].tolist() - - long_indexes = get_long_indexes(df) - - if len(long_indexes) > 0: - immediate_msg = f"\n- There are {len(long_indexes)} examples that are very long. These are rows: {long_indexes}\nFor conditional generation, and for classification the examples shouldn't be longer than 2048 tokens." - optional_msg = f"Remove {len(long_indexes)} long examples" - - def optional_fn(x: Any) -> Any: - long_indexes_to_drop = get_long_indexes(x) - if long_indexes != long_indexes_to_drop: - sys.stdout.write( - f"The indices of the long examples has changed as a result of a previously applied recommendation.\nThe {len(long_indexes_to_drop)} long examples to be dropped are now at the following indices: {long_indexes_to_drop}\n" - ) - return x.drop(long_indexes_to_drop) - - return Remediation( - name="long_examples", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - ) - - -def common_prompt_suffix_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to add a common suffix to the prompt if one doesn't already exist in case of classification or conditional generation. - """ - error_msg = None - immediate_msg = None - optional_msg = None - optional_fn = None # type: ignore - - # Find a suffix which is not contained within the prompt otherwise - suggested_suffix = "\n\n### =>\n\n" - suffix_options = [ - " ->", - "\n\n###\n\n", - "\n\n===\n\n", - "\n\n---\n\n", - "\n\n===>\n\n", - "\n\n--->\n\n", - ] - for suffix_option in suffix_options: - if suffix_option == " ->": - if df.prompt.str.contains("\n").any(): - continue - if df.prompt.str.contains(suffix_option, regex=False).any(): - continue - suggested_suffix = suffix_option - break - display_suggested_suffix = suggested_suffix.replace("\n", "\\n") - - ft_type = infer_task_type(df) - if ft_type == "open-ended generation": - return Remediation(name="common_suffix") - - def add_suffix(x: Any, suffix: Any) -> Any: - x["prompt"] += suffix - return x - - common_suffix = get_common_xfix(df.prompt, xfix="suffix") - if (df.prompt == common_suffix).all(): - error_msg = f"All prompts are identical: `{common_suffix}`\nConsider leaving the prompts blank if you want to do open-ended generation, otherwise ensure prompts are different" - return Remediation(name="common_suffix", error_msg=error_msg) - - if common_suffix != "": - common_suffix_new_line_handled = common_suffix.replace("\n", "\\n") - immediate_msg = f"\n- All prompts end with suffix `{common_suffix_new_line_handled}`" - if len(common_suffix) > 10: - immediate_msg += f". This suffix seems very long. Consider replacing with a shorter suffix, such as `{display_suggested_suffix}`" - if df.prompt.str[: -len(common_suffix)].str.contains(common_suffix, regex=False).any(): - immediate_msg += f"\n WARNING: Some of your prompts contain the suffix `{common_suffix}` more than once. We strongly suggest that you review your prompts and add a unique suffix" - - else: - immediate_msg = "\n- Your data does not contain a common separator at the end of your prompts. Having a separator string appended to the end of the prompt makes it clearer to the fine-tuned model where the completion should begin. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more detail and examples. If you intend to do open-ended generation, then you should leave the prompts empty" - - if common_suffix == "": - optional_msg = f"Add a suffix separator `{display_suggested_suffix}` to all prompts" - - def optional_fn(x: Any) -> Any: - return add_suffix(x, suggested_suffix) - - return Remediation( - name="common_completion_suffix", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - error_msg=error_msg, - ) - - -def common_prompt_prefix_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to remove a common prefix from the prompt if a long one exist. - """ - MAX_PREFIX_LEN = 12 - - immediate_msg = None - optional_msg = None - optional_fn = None # type: ignore - - common_prefix = get_common_xfix(df.prompt, xfix="prefix") - if common_prefix == "": - return Remediation(name="common_prefix") - - def remove_common_prefix(x: Any, prefix: Any) -> Any: - x["prompt"] = x["prompt"].str[len(prefix) :] - return x - - if (df.prompt == common_prefix).all(): - # already handled by common_suffix_validator - return Remediation(name="common_prefix") - - if common_prefix != "": - immediate_msg = f"\n- All prompts start with prefix `{common_prefix}`" - if MAX_PREFIX_LEN < len(common_prefix): - immediate_msg += ". Fine-tuning doesn't require the instruction specifying the task, or a few-shot example scenario. Most of the time you should only add the input data into the prompt, and the desired output into the completion" - optional_msg = f"Remove prefix `{common_prefix}` from all prompts" - - def optional_fn(x: Any) -> Any: - return remove_common_prefix(x, common_prefix) - - return Remediation( - name="common_prompt_prefix", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - ) - - -def common_completion_prefix_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to remove a common prefix from the completion if a long one exist. - """ - MAX_PREFIX_LEN = 5 - - common_prefix = get_common_xfix(df.completion, xfix="prefix") - ws_prefix = len(common_prefix) > 0 and common_prefix[0] == " " - if len(common_prefix) < MAX_PREFIX_LEN: - return Remediation(name="common_prefix") - - def remove_common_prefix(x: Any, prefix: Any, ws_prefix: Any) -> Any: - x["completion"] = x["completion"].str[len(prefix) :] - if ws_prefix: - # keep the single whitespace as prefix - x["completion"] = f" {x['completion']}" - return x - - if (df.completion == common_prefix).all(): - # already handled by common_suffix_validator - return Remediation(name="common_prefix") - - immediate_msg = f"\n- All completions start with prefix `{common_prefix}`. Most of the time you should only add the output data into the completion, without any prefix" - optional_msg = f"Remove prefix `{common_prefix}` from all completions" - - def optional_fn(x: Any) -> Any: - return remove_common_prefix(x, common_prefix, ws_prefix) - - return Remediation( - name="common_completion_prefix", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - ) - - -def common_completion_suffix_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to add a common suffix to the completion if one doesn't already exist in case of classification or conditional generation. - """ - error_msg = None - immediate_msg = None - optional_msg = None - optional_fn = None # type: ignore - - ft_type = infer_task_type(df) - if ft_type == "open-ended generation" or ft_type == "classification": - return Remediation(name="common_suffix") - - common_suffix = get_common_xfix(df.completion, xfix="suffix") - if (df.completion == common_suffix).all(): - error_msg = f"All completions are identical: `{common_suffix}`\nEnsure completions are different, otherwise the model will just repeat `{common_suffix}`" - return Remediation(name="common_suffix", error_msg=error_msg) - - # Find a suffix which is not contained within the completion otherwise - suggested_suffix = " [END]" - suffix_options = [ - "\n", - ".", - " END", - "***", - "+++", - "&&&", - "$$$", - "@@@", - "%%%", - ] - for suffix_option in suffix_options: - if df.completion.str.contains(suffix_option, regex=False).any(): - continue - suggested_suffix = suffix_option - break - display_suggested_suffix = suggested_suffix.replace("\n", "\\n") - - def add_suffix(x: Any, suffix: Any) -> Any: - x["completion"] += suffix - return x - - if common_suffix != "": - common_suffix_new_line_handled = common_suffix.replace("\n", "\\n") - immediate_msg = f"\n- All completions end with suffix `{common_suffix_new_line_handled}`" - if len(common_suffix) > 10: - immediate_msg += f". This suffix seems very long. Consider replacing with a shorter suffix, such as `{display_suggested_suffix}`" - if df.completion.str[: -len(common_suffix)].str.contains(common_suffix, regex=False).any(): - immediate_msg += f"\n WARNING: Some of your completions contain the suffix `{common_suffix}` more than once. We suggest that you review your completions and add a unique ending" - - else: - immediate_msg = "\n- Your data does not contain a common ending at the end of your completions. Having a common ending string appended to the end of the completion makes it clearer to the fine-tuned model where the completion should end. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more detail and examples." - - if common_suffix == "": - optional_msg = f"Add a suffix ending `{display_suggested_suffix}` to all completions" - - def optional_fn(x: Any) -> Any: - return add_suffix(x, suggested_suffix) - - return Remediation( - name="common_completion_suffix", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - error_msg=error_msg, - ) - - -def completions_space_start_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will suggest to add a space at the start of the completion if it doesn't already exist. This helps with tokenization. - """ - - def add_space_start(x: Any) -> Any: - x["completion"] = x["completion"].apply(lambda s: ("" if s.startswith(" ") else " ") + s) - return x - - optional_msg = None - optional_fn = None - immediate_msg = None - - if df.completion.str[:1].nunique() != 1 or df.completion.values[0][0] != " ": - immediate_msg = "\n- The completion should start with a whitespace character (` `). This tends to produce better results due to the tokenization we use. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details" - optional_msg = "Add a whitespace character to the beginning of the completion" - optional_fn = add_space_start - return Remediation( - name="completion_space_start", - immediate_msg=immediate_msg, - optional_msg=optional_msg, - optional_fn=optional_fn, - ) - - -def lower_case_validator(df: pd.DataFrame, column: Any) -> Remediation | None: - """ - This validator will suggest to lowercase the column values, if more than a third of letters are uppercase. - """ - - def lower_case(x: Any) -> Any: - x[column] = x[column].str.lower() - return x - - count_upper = df[column].apply(lambda x: sum(1 for c in x if c.isalpha() and c.isupper())).sum() - count_lower = df[column].apply(lambda x: sum(1 for c in x if c.isalpha() and c.islower())).sum() - - if count_upper * 2 > count_lower: - return Remediation( - name="lower_case", - immediate_msg=f"\n- More than a third of your `{column}` column/key is uppercase. Uppercase {column}s tends to perform worse than a mixture of case encountered in normal language. We recommend to lower case the data if that makes sense in your domain. See https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details", - optional_msg=f"Lowercase all your data in column/key `{column}`", - optional_fn=lower_case, - ) - return None - - -def read_any_format( - fname: str, fields: list[str] = ["prompt", "completion"] -) -> tuple[pd.DataFrame | None, Remediation]: - """ - This function will read a file saved in .csv, .json, .txt, .xlsx or .tsv format using pandas. - - for .xlsx it will read the first sheet - - for .txt it will assume completions and split on newline - """ - remediation = None - necessary_msg = None - immediate_msg = None - error_msg = None - df = None - - if os.path.isfile(fname): - try: - if fname.lower().endswith(".csv") or fname.lower().endswith(".tsv"): - file_extension_str, separator = ("CSV", ",") if fname.lower().endswith(".csv") else ("TSV", "\t") - immediate_msg = ( - f"\n- Based on your file extension, your file is formatted as a {file_extension_str} file" - ) - necessary_msg = f"Your format `{file_extension_str}` will be converted to `JSONL`" - df = pd.read_csv(fname, sep=separator, dtype=str).fillna("") - elif fname.lower().endswith(".xlsx"): - immediate_msg = "\n- Based on your file extension, your file is formatted as an Excel file" - necessary_msg = "Your format `XLSX` will be converted to `JSONL`" - xls = pd.ExcelFile(fname) - sheets = xls.sheet_names - if len(sheets) > 1: - immediate_msg += "\n- Your Excel file contains more than one sheet. Please either save as csv or ensure all data is present in the first sheet. WARNING: Reading only the first sheet..." - df = pd.read_excel(fname, dtype=str).fillna("") - elif fname.lower().endswith(".txt"): - immediate_msg = "\n- Based on your file extension, you provided a text file" - necessary_msg = "Your format `TXT` will be converted to `JSONL`" - with open(fname, "r") as f: - content = f.read() - df = pd.DataFrame( - [["", line] for line in content.split("\n")], - columns=fields, - dtype=str, - ).fillna("") - elif fname.lower().endswith(".jsonl"): - df = pd.read_json(fname, lines=True, dtype=str).fillna("") # type: ignore - if len(df) == 1: # type: ignore - # this is NOT what we expect for a .jsonl file - immediate_msg = "\n- Your JSONL file appears to be in a JSON format. Your file will be converted to JSONL format" - necessary_msg = "Your format `JSON` will be converted to `JSONL`" - df = pd.read_json(fname, dtype=str).fillna("") # type: ignore - else: - pass # this is what we expect for a .jsonl file - elif fname.lower().endswith(".json"): - try: - # to handle case where .json file is actually a .jsonl file - df = pd.read_json(fname, lines=True, dtype=str).fillna("") # type: ignore - if len(df) == 1: # type: ignore - # this code path corresponds to a .json file that has one line - df = pd.read_json(fname, dtype=str).fillna("") # type: ignore - else: - # this is NOT what we expect for a .json file - immediate_msg = "\n- Your JSON file appears to be in a JSONL format. Your file will be converted to JSONL format" - necessary_msg = "Your format `JSON` will be converted to `JSONL`" - except ValueError: - # this code path corresponds to a .json file that has multiple lines (i.e. it is indented) - df = pd.read_json(fname, dtype=str).fillna("") # type: ignore - else: - error_msg = ( - "Your file must have one of the following extensions: .CSV, .TSV, .XLSX, .TXT, .JSON or .JSONL" - ) - if "." in fname: - error_msg += f" Your file `{fname}` ends with the extension `.{fname.split('.')[-1]}` which is not supported." - else: - error_msg += f" Your file `{fname}` is missing a file extension." - - except (ValueError, TypeError): - file_extension_str = fname.split(".")[-1].upper() - error_msg = f"Your file `{fname}` does not appear to be in valid {file_extension_str} format. Please ensure your file is formatted as a valid {file_extension_str} file." - - else: - error_msg = f"File {fname} does not exist." - - remediation = Remediation( - name="read_any_format", - necessary_msg=necessary_msg, - immediate_msg=immediate_msg, - error_msg=error_msg, - ) - return df, remediation - - -def format_inferrer_validator(df: pd.DataFrame) -> Remediation: - """ - This validator will infer the likely fine-tuning format of the data, and display it to the user if it is classification. - It will also suggest to use ada and explain train/validation split benefits. - """ - ft_type = infer_task_type(df) - immediate_msg = None - if ft_type == "classification": - immediate_msg = f"\n- Based on your data it seems like you're trying to fine-tune a model for {ft_type}\n- For classification, we recommend you try one of the faster and cheaper models, such as `ada`\n- For classification, you can estimate the expected model performance by keeping a held out dataset, which is not used for training" - return Remediation(name="num_examples", immediate_msg=immediate_msg) - - -def apply_necessary_remediation(df: OptionalDataFrameT, remediation: Remediation) -> OptionalDataFrameT: - """ - This function will apply a necessary remediation to a dataframe, or print an error message if one exists. - """ - if remediation.error_msg is not None: - sys.stderr.write(f"\n\nERROR in {remediation.name} validator: {remediation.error_msg}\n\nAborting...") - sys.exit(1) - if remediation.immediate_msg is not None: - sys.stdout.write(remediation.immediate_msg) - if remediation.necessary_fn is not None: - df = remediation.necessary_fn(df) - return df - - -def accept_suggestion(input_text: str, auto_accept: bool) -> bool: - sys.stdout.write(input_text) - if auto_accept: - sys.stdout.write("Y\n") - return True - return input().lower() != "n" - - -def apply_optional_remediation( - df: pd.DataFrame, remediation: Remediation, auto_accept: bool -) -> tuple[pd.DataFrame, bool]: - """ - This function will apply an optional remediation to a dataframe, based on the user input. - """ - optional_applied = False - input_text = f"- [Recommended] {remediation.optional_msg} [Y/n]: " - if remediation.optional_msg is not None: - if accept_suggestion(input_text, auto_accept): - assert remediation.optional_fn is not None - df = remediation.optional_fn(df) - optional_applied = True - if remediation.necessary_msg is not None: - sys.stdout.write(f"- [Necessary] {remediation.necessary_msg}\n") - return df, optional_applied - - -def estimate_fine_tuning_time(df: pd.DataFrame) -> None: - """ - Estimate the time it'll take to fine-tune the dataset - """ - ft_format = infer_task_type(df) - expected_time = 1.0 - if ft_format == "classification": - num_examples = len(df) - expected_time = num_examples * 1.44 - else: - size = df.memory_usage(index=True).sum() - expected_time = size * 0.0515 - - def format_time(time: float) -> str: - if time < 60: - return f"{round(time, 2)} seconds" - elif time < 3600: - return f"{round(time / 60, 2)} minutes" - elif time < 86400: - return f"{round(time / 3600, 2)} hours" - else: - return f"{round(time / 86400, 2)} days" - - time_string = format_time(expected_time + 140) - sys.stdout.write( - f"Once your model starts training, it'll approximately take {time_string} to train a `curie` model, and less for `ada` and `babbage`. Queue will approximately take half an hour per job ahead of you.\n" - ) - - -def get_outfnames(fname: str, split: bool) -> list[str]: - suffixes = ["_train", "_valid"] if split else [""] - i = 0 - while True: - index_suffix = f" ({i})" if i > 0 else "" - candidate_fnames = [f"{os.path.splitext(fname)[0]}_prepared{suffix}{index_suffix}.jsonl" for suffix in suffixes] - if not any(os.path.isfile(f) for f in candidate_fnames): - return candidate_fnames - i += 1 - - -def get_classification_hyperparams(df: pd.DataFrame) -> tuple[int, object]: - n_classes = df.completion.nunique() - pos_class = None - if n_classes == 2: - pos_class = df.completion.value_counts().index[0] - return n_classes, pos_class - - -def write_out_file(df: pd.DataFrame, fname: str, any_remediations: bool, auto_accept: bool) -> None: - """ - This function will write out a dataframe to a file, if the user would like to proceed, and also offer a fine-tuning command with the newly created file. - For classification it will optionally ask the user if they would like to split the data into train/valid files, and modify the suggested command to include the valid set. - """ - ft_format = infer_task_type(df) - common_prompt_suffix = get_common_xfix(df.prompt, xfix="suffix") - common_completion_suffix = get_common_xfix(df.completion, xfix="suffix") - - split = False - input_text = "- [Recommended] Would you like to split into training and validation set? [Y/n]: " - if ft_format == "classification": - if accept_suggestion(input_text, auto_accept): - split = True - - additional_params = "" - common_prompt_suffix_new_line_handled = common_prompt_suffix.replace("\n", "\\n") - common_completion_suffix_new_line_handled = common_completion_suffix.replace("\n", "\\n") - optional_ending_string = ( - f' Make sure to include `stop=["{common_completion_suffix_new_line_handled}"]` so that the generated texts ends at the expected place.' - if len(common_completion_suffix_new_line_handled) > 0 - else "" - ) - - input_text = "\n\nYour data will be written to a new JSONL file. Proceed [Y/n]: " - - if not any_remediations and not split: - sys.stdout.write( - f'\nYou can use your file for fine-tuning:\n> openai api fine_tunes.create -t "{fname}"{additional_params}\n\nAfter you’ve fine-tuned a model, remember that your prompt has to end with the indicator string `{common_prompt_suffix_new_line_handled}` for the model to start generating completions, rather than continuing with the prompt.{optional_ending_string}\n' - ) - estimate_fine_tuning_time(df) - - elif accept_suggestion(input_text, auto_accept): - fnames = get_outfnames(fname, split) - if split: - assert len(fnames) == 2 and "train" in fnames[0] and "valid" in fnames[1] - MAX_VALID_EXAMPLES = 1000 - n_train = max(len(df) - MAX_VALID_EXAMPLES, int(len(df) * 0.8)) - df_train = df.sample(n=n_train, random_state=42) - df_valid = df.drop(df_train.index) - df_train[["prompt", "completion"]].to_json( # type: ignore - fnames[0], lines=True, orient="records", force_ascii=False, indent=None - ) - df_valid[["prompt", "completion"]].to_json( - fnames[1], lines=True, orient="records", force_ascii=False, indent=None - ) - - n_classes, pos_class = get_classification_hyperparams(df) - additional_params += " --compute_classification_metrics" - if n_classes == 2: - additional_params += f' --classification_positive_class "{pos_class}"' - else: - additional_params += f" --classification_n_classes {n_classes}" - else: - assert len(fnames) == 1 - df[["prompt", "completion"]].to_json( - fnames[0], lines=True, orient="records", force_ascii=False, indent=None - ) - - # Add -v VALID_FILE if we split the file into train / valid - files_string = ("s" if split else "") + " to `" + ("` and `".join(fnames)) - valid_string = f' -v "{fnames[1]}"' if split else "" - separator_reminder = ( - "" - if len(common_prompt_suffix_new_line_handled) == 0 - else f"After you’ve fine-tuned a model, remember that your prompt has to end with the indicator string `{common_prompt_suffix_new_line_handled}` for the model to start generating completions, rather than continuing with the prompt." - ) - sys.stdout.write( - f'\nWrote modified file{files_string}`\nFeel free to take a look!\n\nNow use that file when fine-tuning:\n> openai api fine_tunes.create -t "{fnames[0]}"{valid_string}{additional_params}\n\n{separator_reminder}{optional_ending_string}\n' - ) - estimate_fine_tuning_time(df) - else: - sys.stdout.write("Aborting... did not write the file\n") - - -def infer_task_type(df: pd.DataFrame) -> str: - """ - Infer the likely fine-tuning task type from the data - """ - CLASSIFICATION_THRESHOLD = 3 # min_average instances of each class - if sum(df.prompt.str.len()) == 0: - return "open-ended generation" - - if len(df.completion.unique()) < len(df) / CLASSIFICATION_THRESHOLD: - return "classification" - - return "conditional generation" - - -def get_common_xfix(series: Any, xfix: str = "suffix") -> str: - """ - Finds the longest common suffix or prefix of all the values in a series - """ - common_xfix = "" - while True: - common_xfixes = ( - series.str[-(len(common_xfix) + 1) :] if xfix == "suffix" else series.str[: len(common_xfix) + 1] - ) # first few or last few characters - if common_xfixes.nunique() != 1: # we found the character at which we don't have a unique xfix anymore - break - elif common_xfix == common_xfixes.values[0]: # the entire first row is a prefix of every other row - break - else: # the first or last few characters are still common across all rows - let's try to add one more - common_xfix = common_xfixes.values[0] - return common_xfix - - -Validator: TypeAlias = "Callable[[pd.DataFrame], Remediation | None]" - - -def get_validators() -> list[Validator]: - return [ - num_examples_validator, - lambda x: necessary_column_validator(x, "prompt"), - lambda x: necessary_column_validator(x, "completion"), - additional_column_validator, - non_empty_field_validator, - format_inferrer_validator, - duplicated_rows_validator, - long_examples_validator, - lambda x: lower_case_validator(x, "prompt"), - lambda x: lower_case_validator(x, "completion"), - common_prompt_suffix_validator, - common_prompt_prefix_validator, - common_completion_prefix_validator, - common_completion_suffix_validator, - completions_space_start_validator, - ] - - -def apply_validators( - df: pd.DataFrame, - fname: str, - remediation: Remediation | None, - validators: list[Validator], - auto_accept: bool, - write_out_file_func: Callable[..., Any], -) -> None: - optional_remediations: list[Remediation] = [] - if remediation is not None: - optional_remediations.append(remediation) - for validator in validators: - remediation = validator(df) - if remediation is not None: - optional_remediations.append(remediation) - df = apply_necessary_remediation(df, remediation) - - any_optional_or_necessary_remediations = any( - [ - remediation - for remediation in optional_remediations - if remediation.optional_msg is not None or remediation.necessary_msg is not None - ] - ) - any_necessary_applied = any( - [remediation for remediation in optional_remediations if remediation.necessary_msg is not None] - ) - any_optional_applied = False - - if any_optional_or_necessary_remediations: - sys.stdout.write("\n\nBased on the analysis we will perform the following actions:\n") - for remediation in optional_remediations: - df, optional_applied = apply_optional_remediation(df, remediation, auto_accept) - any_optional_applied = any_optional_applied or optional_applied - else: - sys.stdout.write("\n\nNo remediations found.\n") - - any_optional_or_necessary_applied = any_optional_applied or any_necessary_applied - - write_out_file_func(df, fname, any_optional_or_necessary_applied, auto_accept) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/azure.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/azure.py deleted file mode 100644 index ad64707..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/azure.py +++ /dev/null @@ -1,647 +0,0 @@ -from __future__ import annotations - -import os -import inspect -from typing import Any, Union, Mapping, TypeVar, Callable, Awaitable, cast, overload -from typing_extensions import Self, override - -import httpx - -from .._types import NOT_GIVEN, Omit, Query, Timeout, NotGiven -from .._utils import is_given, is_mapping -from .._client import OpenAI, AsyncOpenAI -from .._compat import model_copy -from .._models import FinalRequestOptions -from .._streaming import Stream, AsyncStream -from .._exceptions import OpenAIError -from .._base_client import DEFAULT_MAX_RETRIES, BaseClient - -_deployments_endpoints = set( - [ - "/completions", - "/chat/completions", - "/embeddings", - "/audio/transcriptions", - "/audio/translations", - "/audio/speech", - "/images/generations", - "/images/edits", - ] -) - - -AzureADTokenProvider = Callable[[], str] -AsyncAzureADTokenProvider = Callable[[], "str | Awaitable[str]"] -_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) -_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) - - -# we need to use a sentinel API key value for Azure AD -# as we don't want to make the `api_key` in the main client Optional -# and Azure AD tokens may be retrieved on a per-request basis -API_KEY_SENTINEL = "".join(["<", "missing API key", ">"]) - - -class MutuallyExclusiveAuthError(OpenAIError): - def __init__(self) -> None: - super().__init__( - "The `api_key`, `azure_ad_token` and `azure_ad_token_provider` arguments are mutually exclusive; Only one can be passed at a time" - ) - - -class BaseAzureClient(BaseClient[_HttpxClientT, _DefaultStreamT]): - _azure_endpoint: httpx.URL | None - _azure_deployment: str | None - - @override - def _build_request( - self, - options: FinalRequestOptions, - *, - retries_taken: int = 0, - ) -> httpx.Request: - if options.url in _deployments_endpoints and is_mapping(options.json_data): - model = options.json_data.get("model") - if model is not None and "/deployments" not in str(self.base_url.path): - options.url = f"/deployments/{model}{options.url}" - - return super()._build_request(options, retries_taken=retries_taken) - - @override - def _prepare_url(self, url: str) -> httpx.URL: - """Adjust the URL if the client was configured with an Azure endpoint + deployment - and the API feature being called is **not** a deployments-based endpoint - (i.e. requires /deployments/deployment-name in the URL path). - """ - if self._azure_deployment and self._azure_endpoint and url not in _deployments_endpoints: - merge_url = httpx.URL(url) - if merge_url.is_relative_url: - merge_raw_path = ( - self._azure_endpoint.raw_path.rstrip(b"/") + b"/openai/" + merge_url.raw_path.lstrip(b"/") - ) - return self._azure_endpoint.copy_with(raw_path=merge_raw_path) - - return merge_url - - return super()._prepare_url(url) - - -class AzureOpenAI(BaseAzureClient[httpx.Client, Stream[Any]], OpenAI): - @overload - def __init__( - self, - *, - azure_endpoint: str, - azure_deployment: str | None = None, - api_version: str | None = None, - api_key: str | Callable[[], str] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AzureADTokenProvider | None = None, - organization: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.Client | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - @overload - def __init__( - self, - *, - azure_deployment: str | None = None, - api_version: str | None = None, - api_key: str | Callable[[], str] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AzureADTokenProvider | None = None, - organization: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.Client | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - @overload - def __init__( - self, - *, - base_url: str, - api_version: str | None = None, - api_key: str | Callable[[], str] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AzureADTokenProvider | None = None, - organization: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.Client | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - def __init__( - self, - *, - api_version: str | None = None, - azure_endpoint: str | None = None, - azure_deployment: str | None = None, - api_key: str | Callable[[], str] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AzureADTokenProvider | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - base_url: str | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.Client | None = None, - _strict_response_validation: bool = False, - ) -> None: - """Construct a new synchronous azure openai client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `api_key` from `AZURE_OPENAI_API_KEY` - - `organization` from `OPENAI_ORG_ID` - - `project` from `OPENAI_PROJECT_ID` - - `azure_ad_token` from `AZURE_OPENAI_AD_TOKEN` - - `api_version` from `OPENAI_API_VERSION` - - `azure_endpoint` from `AZURE_OPENAI_ENDPOINT` - - Args: - azure_endpoint: Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` - - azure_ad_token: Your Azure Active Directory token, https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id - - azure_ad_token_provider: A function that returns an Azure Active Directory token, will be invoked on every request. - - azure_deployment: A model deployment, if given with `azure_endpoint`, sets the base client URL to include `/deployments/{azure_deployment}`. - Not supported with Assistants APIs. - """ - if api_key is None: - api_key = os.environ.get("AZURE_OPENAI_API_KEY") - - if azure_ad_token is None: - azure_ad_token = os.environ.get("AZURE_OPENAI_AD_TOKEN") - - if api_key is None and azure_ad_token is None and azure_ad_token_provider is None: - raise OpenAIError( - "Missing credentials. Please pass one of `api_key`, `azure_ad_token`, `azure_ad_token_provider`, or the `AZURE_OPENAI_API_KEY` or `AZURE_OPENAI_AD_TOKEN` environment variables." - ) - - if api_version is None: - api_version = os.environ.get("OPENAI_API_VERSION") - - if api_version is None: - raise ValueError( - "Must provide either the `api_version` argument or the `OPENAI_API_VERSION` environment variable" - ) - - if default_query is None: - default_query = {"api-version": api_version} - else: - default_query = {**default_query, "api-version": api_version} - - if base_url is None: - if azure_endpoint is None: - azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") - - if azure_endpoint is None: - raise ValueError( - "Must provide one of the `base_url` or `azure_endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable" - ) - - if azure_deployment is not None: - base_url = f"{azure_endpoint.rstrip('/')}/openai/deployments/{azure_deployment}" - else: - base_url = f"{azure_endpoint.rstrip('/')}/openai" - else: - if azure_endpoint is not None: - raise ValueError("base_url and azure_endpoint are mutually exclusive") - - if api_key is None: - # define a sentinel value to avoid any typing issues - api_key = API_KEY_SENTINEL - - super().__init__( - api_key=api_key, - organization=organization, - project=project, - webhook_secret=webhook_secret, - base_url=base_url, - timeout=timeout, - max_retries=max_retries, - default_headers=default_headers, - default_query=default_query, - http_client=http_client, - websocket_base_url=websocket_base_url, - _strict_response_validation=_strict_response_validation, - ) - self._api_version = api_version - self._azure_ad_token = azure_ad_token - self._azure_ad_token_provider = azure_ad_token_provider - self._azure_deployment = azure_deployment if azure_endpoint else None - self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None - - @override - def copy( - self, - *, - api_key: str | Callable[[], str] | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - api_version: str | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AzureADTokenProvider | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - http_client: httpx.Client | None = None, - max_retries: int | NotGiven = NOT_GIVEN, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - return super().copy( - api_key=api_key, - organization=organization, - project=project, - webhook_secret=webhook_secret, - websocket_base_url=websocket_base_url, - base_url=base_url, - timeout=timeout, - http_client=http_client, - max_retries=max_retries, - default_headers=default_headers, - set_default_headers=set_default_headers, - default_query=default_query, - set_default_query=set_default_query, - _extra_kwargs={ - "api_version": api_version or self._api_version, - "azure_ad_token": azure_ad_token or self._azure_ad_token, - "azure_ad_token_provider": azure_ad_token_provider or self._azure_ad_token_provider, - **_extra_kwargs, - }, - ) - - with_options = copy - - def _get_azure_ad_token(self) -> str | None: - if self._azure_ad_token is not None: - return self._azure_ad_token - - provider = self._azure_ad_token_provider - if provider is not None: - token = provider() - if not token or not isinstance(token, str): # pyright: ignore[reportUnnecessaryIsInstance] - raise ValueError( - f"Expected `azure_ad_token_provider` argument to return a string but it returned {token}", - ) - return token - - return None - - @override - def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - headers: dict[str, str | Omit] = {**options.headers} if is_given(options.headers) else {} - - options = model_copy(options) - options.headers = headers - - azure_ad_token = self._get_azure_ad_token() - if azure_ad_token is not None: - if headers.get("Authorization") is None: - headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not API_KEY_SENTINEL: - if headers.get("api-key") is None: - headers["api-key"] = self.api_key - else: - # should never be hit - raise ValueError("Unable to handle auth") - - return options - - def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]: - auth_headers = {} - query = { - **extra_query, - "api-version": self._api_version, - "deployment": self._azure_deployment or model, - } - if self.api_key and self.api_key != "": - auth_headers = {"api-key": self.api_key} - else: - token = self._get_azure_ad_token() - if token: - auth_headers = {"Authorization": f"Bearer {token}"} - - if self.websocket_base_url is not None: - base_url = httpx.URL(self.websocket_base_url) - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - realtime_url = base_url.copy_with(raw_path=merge_raw_path) - else: - base_url = self._prepare_url("/realtime") - realtime_url = base_url.copy_with(scheme="wss") - - url = realtime_url.copy_with(params={**query}) - return url, auth_headers - - -class AsyncAzureOpenAI(BaseAzureClient[httpx.AsyncClient, AsyncStream[Any]], AsyncOpenAI): - @overload - def __init__( - self, - *, - azure_endpoint: str, - azure_deployment: str | None = None, - api_version: str | None = None, - api_key: str | Callable[[], Awaitable[str]] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.AsyncClient | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - @overload - def __init__( - self, - *, - azure_deployment: str | None = None, - api_version: str | None = None, - api_key: str | Callable[[], Awaitable[str]] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.AsyncClient | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - @overload - def __init__( - self, - *, - base_url: str, - api_version: str | None = None, - api_key: str | Callable[[], Awaitable[str]] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.AsyncClient | None = None, - _strict_response_validation: bool = False, - ) -> None: ... - - def __init__( - self, - *, - azure_endpoint: str | None = None, - azure_deployment: str | None = None, - api_version: str | None = None, - api_key: str | Callable[[], Awaitable[str]] | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - base_url: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - http_client: httpx.AsyncClient | None = None, - _strict_response_validation: bool = False, - ) -> None: - """Construct a new asynchronous azure openai client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `api_key` from `AZURE_OPENAI_API_KEY` - - `organization` from `OPENAI_ORG_ID` - - `project` from `OPENAI_PROJECT_ID` - - `azure_ad_token` from `AZURE_OPENAI_AD_TOKEN` - - `api_version` from `OPENAI_API_VERSION` - - `azure_endpoint` from `AZURE_OPENAI_ENDPOINT` - - Args: - azure_endpoint: Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` - - azure_ad_token: Your Azure Active Directory token, https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id - - azure_ad_token_provider: A function that returns an Azure Active Directory token, will be invoked on every request. - - azure_deployment: A model deployment, if given with `azure_endpoint`, sets the base client URL to include `/deployments/{azure_deployment}`. - Not supported with Assistants APIs. - """ - if api_key is None: - api_key = os.environ.get("AZURE_OPENAI_API_KEY") - - if azure_ad_token is None: - azure_ad_token = os.environ.get("AZURE_OPENAI_AD_TOKEN") - - if api_key is None and azure_ad_token is None and azure_ad_token_provider is None: - raise OpenAIError( - "Missing credentials. Please pass one of `api_key`, `azure_ad_token`, `azure_ad_token_provider`, or the `AZURE_OPENAI_API_KEY` or `AZURE_OPENAI_AD_TOKEN` environment variables." - ) - - if api_version is None: - api_version = os.environ.get("OPENAI_API_VERSION") - - if api_version is None: - raise ValueError( - "Must provide either the `api_version` argument or the `OPENAI_API_VERSION` environment variable" - ) - - if default_query is None: - default_query = {"api-version": api_version} - else: - default_query = {**default_query, "api-version": api_version} - - if base_url is None: - if azure_endpoint is None: - azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") - - if azure_endpoint is None: - raise ValueError( - "Must provide one of the `base_url` or `azure_endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable" - ) - - if azure_deployment is not None: - base_url = f"{azure_endpoint.rstrip('/')}/openai/deployments/{azure_deployment}" - else: - base_url = f"{azure_endpoint.rstrip('/')}/openai" - else: - if azure_endpoint is not None: - raise ValueError("base_url and azure_endpoint are mutually exclusive") - - if api_key is None: - # define a sentinel value to avoid any typing issues - api_key = API_KEY_SENTINEL - - super().__init__( - api_key=api_key, - organization=organization, - project=project, - webhook_secret=webhook_secret, - base_url=base_url, - timeout=timeout, - max_retries=max_retries, - default_headers=default_headers, - default_query=default_query, - http_client=http_client, - websocket_base_url=websocket_base_url, - _strict_response_validation=_strict_response_validation, - ) - self._api_version = api_version - self._azure_ad_token = azure_ad_token - self._azure_ad_token_provider = azure_ad_token_provider - self._azure_deployment = azure_deployment if azure_endpoint else None - self._azure_endpoint = httpx.URL(azure_endpoint) if azure_endpoint else None - - @override - def copy( - self, - *, - api_key: str | Callable[[], Awaitable[str]] | None = None, - organization: str | None = None, - project: str | None = None, - webhook_secret: str | None = None, - websocket_base_url: str | httpx.URL | None = None, - api_version: str | None = None, - azure_ad_token: str | None = None, - azure_ad_token_provider: AsyncAzureADTokenProvider | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, - http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = NOT_GIVEN, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - return super().copy( - api_key=api_key, - organization=organization, - project=project, - webhook_secret=webhook_secret, - websocket_base_url=websocket_base_url, - base_url=base_url, - timeout=timeout, - http_client=http_client, - max_retries=max_retries, - default_headers=default_headers, - set_default_headers=set_default_headers, - default_query=default_query, - set_default_query=set_default_query, - _extra_kwargs={ - "api_version": api_version or self._api_version, - "azure_ad_token": azure_ad_token or self._azure_ad_token, - "azure_ad_token_provider": azure_ad_token_provider or self._azure_ad_token_provider, - **_extra_kwargs, - }, - ) - - with_options = copy - - async def _get_azure_ad_token(self) -> str | None: - if self._azure_ad_token is not None: - return self._azure_ad_token - - provider = self._azure_ad_token_provider - if provider is not None: - token = provider() - if inspect.isawaitable(token): - token = await token - if not token or not isinstance(cast(Any, token), str): - raise ValueError( - f"Expected `azure_ad_token_provider` argument to return a string but it returned {token}", - ) - return str(token) - - return None - - @override - async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - headers: dict[str, str | Omit] = {**options.headers} if is_given(options.headers) else {} - - options = model_copy(options) - options.headers = headers - - azure_ad_token = await self._get_azure_ad_token() - if azure_ad_token is not None: - if headers.get("Authorization") is None: - headers["Authorization"] = f"Bearer {azure_ad_token}" - elif self.api_key is not API_KEY_SENTINEL: - if headers.get("api-key") is None: - headers["api-key"] = self.api_key - else: - # should never be hit - raise ValueError("Unable to handle auth") - - return options - - async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[httpx.URL, dict[str, str]]: - auth_headers = {} - query = { - **extra_query, - "api-version": self._api_version, - "deployment": self._azure_deployment or model, - } - if self.api_key and self.api_key != "": - auth_headers = {"api-key": self.api_key} - else: - token = await self._get_azure_ad_token() - if token: - auth_headers = {"Authorization": f"Bearer {token}"} - - if self.websocket_base_url is not None: - base_url = httpx.URL(self.websocket_base_url) - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - realtime_url = base_url.copy_with(raw_path=merge_raw_path) - else: - base_url = self._prepare_url("/realtime") - realtime_url = base_url.copy_with(scheme="wss") - - url = realtime_url.copy_with(params={**query}) - return url, auth_headers diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/__init__.py deleted file mode 100644 index eb378d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from ._assistants import ( - AssistantEventHandler as AssistantEventHandler, - AssistantEventHandlerT as AssistantEventHandlerT, - AssistantStreamManager as AssistantStreamManager, - AsyncAssistantEventHandler as AsyncAssistantEventHandler, - AsyncAssistantEventHandlerT as AsyncAssistantEventHandlerT, - AsyncAssistantStreamManager as AsyncAssistantStreamManager, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_assistants.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_assistants.py deleted file mode 100644 index 6efb3ca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_assistants.py +++ /dev/null @@ -1,1038 +0,0 @@ -from __future__ import annotations - -import asyncio -from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Callable, Iterable, Iterator, cast -from typing_extensions import Awaitable, AsyncIterable, AsyncIterator, assert_never - -import httpx - -from ..._utils import is_dict, is_list, consume_sync_iterator, consume_async_iterator -from ..._compat import model_dump -from ..._models import construct_type -from ..._streaming import Stream, AsyncStream -from ...types.beta import AssistantStreamEvent -from ...types.beta.threads import ( - Run, - Text, - Message, - ImageFile, - TextDelta, - MessageDelta, - MessageContent, - MessageContentDelta, -) -from ...types.beta.threads.runs import RunStep, ToolCall, RunStepDelta, ToolCallDelta - - -class AssistantEventHandler: - text_deltas: Iterable[str] - """Iterator over just the text deltas in the stream. - - This corresponds to the `thread.message.delta` event - in the API. - - ```py - for text in stream.text_deltas: - print(text, end="", flush=True) - print() - ``` - """ - - def __init__(self) -> None: - self._current_event: AssistantStreamEvent | None = None - self._current_message_content_index: int | None = None - self._current_message_content: MessageContent | None = None - self._current_tool_call_index: int | None = None - self._current_tool_call: ToolCall | None = None - self.__current_run_step_id: str | None = None - self.__current_run: Run | None = None - self.__run_step_snapshots: dict[str, RunStep] = {} - self.__message_snapshots: dict[str, Message] = {} - self.__current_message_snapshot: Message | None = None - - self.text_deltas = self.__text_deltas__() - self._iterator = self.__stream__() - self.__stream: Stream[AssistantStreamEvent] | None = None - - def _init(self, stream: Stream[AssistantStreamEvent]) -> None: - if self.__stream: - raise RuntimeError( - "A single event handler cannot be shared between multiple streams; You will need to construct a new event handler instance" - ) - - self.__stream = stream - - def __next__(self) -> AssistantStreamEvent: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[AssistantStreamEvent]: - for item in self._iterator: - yield item - - @property - def current_event(self) -> AssistantStreamEvent | None: - return self._current_event - - @property - def current_run(self) -> Run | None: - return self.__current_run - - @property - def current_run_step_snapshot(self) -> RunStep | None: - if not self.__current_run_step_id: - return None - - return self.__run_step_snapshots[self.__current_run_step_id] - - @property - def current_message_snapshot(self) -> Message | None: - return self.__current_message_snapshot - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called when the context manager exits. - """ - if self.__stream: - self.__stream.close() - - def until_done(self) -> None: - """Waits until the stream has been consumed""" - consume_sync_iterator(self) - - def get_final_run(self) -> Run: - """Wait for the stream to finish and returns the completed Run object""" - self.until_done() - - if not self.__current_run: - raise RuntimeError("No final run object found") - - return self.__current_run - - def get_final_run_steps(self) -> list[RunStep]: - """Wait for the stream to finish and returns the steps taken in this run""" - self.until_done() - - if not self.__run_step_snapshots: - raise RuntimeError("No run steps found") - - return [step for step in self.__run_step_snapshots.values()] - - def get_final_messages(self) -> list[Message]: - """Wait for the stream to finish and returns the messages emitted in this run""" - self.until_done() - - if not self.__message_snapshots: - raise RuntimeError("No messages found") - - return [message for message in self.__message_snapshots.values()] - - def __text_deltas__(self) -> Iterator[str]: - for event in self: - if event.event != "thread.message.delta": - continue - - for content_delta in event.data.delta.content or []: - if content_delta.type == "text" and content_delta.text and content_delta.text.value: - yield content_delta.text.value - - # event handlers - - def on_end(self) -> None: - """Fires when the stream has finished. - - This happens if the stream is read to completion - or if an exception occurs during iteration. - """ - - def on_event(self, event: AssistantStreamEvent) -> None: - """Callback that is fired for every Server-Sent-Event""" - - def on_run_step_created(self, run_step: RunStep) -> None: - """Callback that is fired when a run step is created""" - - def on_run_step_delta(self, delta: RunStepDelta, snapshot: RunStep) -> None: - """Callback that is fired whenever a run step delta is returned from the API - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the run step. For example, a tool calls event may - look like this: - - # delta - tool_calls=[ - RunStepDeltaToolCallsCodeInterpreter( - index=0, - type='code_interpreter', - id=None, - code_interpreter=CodeInterpreter(input=' sympy', outputs=None) - ) - ] - # snapshot - tool_calls=[ - CodeToolCall( - id='call_wKayJlcYV12NiadiZuJXxcfx', - code_interpreter=CodeInterpreter(input='from sympy', outputs=[]), - type='code_interpreter', - index=0 - ) - ], - """ - - def on_run_step_done(self, run_step: RunStep) -> None: - """Callback that is fired when a run step is completed""" - - def on_tool_call_created(self, tool_call: ToolCall) -> None: - """Callback that is fired when a tool call is created""" - - def on_tool_call_delta(self, delta: ToolCallDelta, snapshot: ToolCall) -> None: - """Callback that is fired when a tool call delta is encountered""" - - def on_tool_call_done(self, tool_call: ToolCall) -> None: - """Callback that is fired when a tool call delta is encountered""" - - def on_exception(self, exception: Exception) -> None: - """Fired whenever an exception happens during streaming""" - - def on_timeout(self) -> None: - """Fires if the request times out""" - - def on_message_created(self, message: Message) -> None: - """Callback that is fired when a message is created""" - - def on_message_delta(self, delta: MessageDelta, snapshot: Message) -> None: - """Callback that is fired whenever a message delta is returned from the API - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the message. For example, a text content event may - look like this: - - # delta - MessageDeltaText( - index=0, - type='text', - text=Text( - value=' Jane' - ), - ) - # snapshot - MessageContentText( - index=0, - type='text', - text=Text( - value='Certainly, Jane' - ), - ) - """ - - def on_message_done(self, message: Message) -> None: - """Callback that is fired when a message is completed""" - - def on_text_created(self, text: Text) -> None: - """Callback that is fired when a text content block is created""" - - def on_text_delta(self, delta: TextDelta, snapshot: Text) -> None: - """Callback that is fired whenever a text content delta is returned - by the API. - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the text. For example: - - on_text_delta(TextDelta(value="The"), Text(value="The")), - on_text_delta(TextDelta(value=" solution"), Text(value="The solution")), - on_text_delta(TextDelta(value=" to"), Text(value="The solution to")), - on_text_delta(TextDelta(value=" the"), Text(value="The solution to the")), - on_text_delta(TextDelta(value=" equation"), Text(value="The solution to the equation")), - """ - - def on_text_done(self, text: Text) -> None: - """Callback that is fired when a text content block is finished""" - - def on_image_file_done(self, image_file: ImageFile) -> None: - """Callback that is fired when an image file block is finished""" - - def _emit_sse_event(self, event: AssistantStreamEvent) -> None: - self._current_event = event - self.on_event(event) - - self.__current_message_snapshot, new_content = accumulate_event( - event=event, - current_message_snapshot=self.__current_message_snapshot, - ) - if self.__current_message_snapshot is not None: - self.__message_snapshots[self.__current_message_snapshot.id] = self.__current_message_snapshot - - accumulate_run_step( - event=event, - run_step_snapshots=self.__run_step_snapshots, - ) - - for content_delta in new_content: - assert self.__current_message_snapshot is not None - - block = self.__current_message_snapshot.content[content_delta.index] - if block.type == "text": - self.on_text_created(block.text) - - if ( - event.event == "thread.run.completed" - or event.event == "thread.run.cancelled" - or event.event == "thread.run.expired" - or event.event == "thread.run.failed" - or event.event == "thread.run.requires_action" - or event.event == "thread.run.incomplete" - ): - self.__current_run = event.data - if self._current_tool_call: - self.on_tool_call_done(self._current_tool_call) - elif ( - event.event == "thread.run.created" - or event.event == "thread.run.in_progress" - or event.event == "thread.run.cancelling" - or event.event == "thread.run.queued" - ): - self.__current_run = event.data - elif event.event == "thread.message.created": - self.on_message_created(event.data) - elif event.event == "thread.message.delta": - snapshot = self.__current_message_snapshot - assert snapshot is not None - - message_delta = event.data.delta - if message_delta.content is not None: - for content_delta in message_delta.content: - if content_delta.type == "text" and content_delta.text: - snapshot_content = snapshot.content[content_delta.index] - assert snapshot_content.type == "text" - self.on_text_delta(content_delta.text, snapshot_content.text) - - # If the delta is for a new message content: - # - emit on_text_done/on_image_file_done for the previous message content - # - emit on_text_created/on_image_created for the new message content - if content_delta.index != self._current_message_content_index: - if self._current_message_content is not None: - if self._current_message_content.type == "text": - self.on_text_done(self._current_message_content.text) - elif self._current_message_content.type == "image_file": - self.on_image_file_done(self._current_message_content.image_file) - - self._current_message_content_index = content_delta.index - self._current_message_content = snapshot.content[content_delta.index] - - # Update the current_message_content (delta event is correctly emitted already) - self._current_message_content = snapshot.content[content_delta.index] - - self.on_message_delta(event.data.delta, snapshot) - elif event.event == "thread.message.completed" or event.event == "thread.message.incomplete": - self.__current_message_snapshot = event.data - self.__message_snapshots[event.data.id] = event.data - - if self._current_message_content_index is not None: - content = event.data.content[self._current_message_content_index] - if content.type == "text": - self.on_text_done(content.text) - elif content.type == "image_file": - self.on_image_file_done(content.image_file) - - self.on_message_done(event.data) - elif event.event == "thread.run.step.created": - self.__current_run_step_id = event.data.id - self.on_run_step_created(event.data) - elif event.event == "thread.run.step.in_progress": - self.__current_run_step_id = event.data.id - elif event.event == "thread.run.step.delta": - step_snapshot = self.__run_step_snapshots[event.data.id] - - run_step_delta = event.data.delta - if ( - run_step_delta.step_details - and run_step_delta.step_details.type == "tool_calls" - and run_step_delta.step_details.tool_calls is not None - ): - assert step_snapshot.step_details.type == "tool_calls" - for tool_call_delta in run_step_delta.step_details.tool_calls: - if tool_call_delta.index == self._current_tool_call_index: - self.on_tool_call_delta( - tool_call_delta, - step_snapshot.step_details.tool_calls[tool_call_delta.index], - ) - - # If the delta is for a new tool call: - # - emit on_tool_call_done for the previous tool_call - # - emit on_tool_call_created for the new tool_call - if tool_call_delta.index != self._current_tool_call_index: - if self._current_tool_call is not None: - self.on_tool_call_done(self._current_tool_call) - - self._current_tool_call_index = tool_call_delta.index - self._current_tool_call = step_snapshot.step_details.tool_calls[tool_call_delta.index] - self.on_tool_call_created(self._current_tool_call) - - # Update the current_tool_call (delta event is correctly emitted already) - self._current_tool_call = step_snapshot.step_details.tool_calls[tool_call_delta.index] - - self.on_run_step_delta( - event.data.delta, - step_snapshot, - ) - elif ( - event.event == "thread.run.step.completed" - or event.event == "thread.run.step.cancelled" - or event.event == "thread.run.step.expired" - or event.event == "thread.run.step.failed" - ): - if self._current_tool_call: - self.on_tool_call_done(self._current_tool_call) - - self.on_run_step_done(event.data) - self.__current_run_step_id = None - elif event.event == "thread.created" or event.event == "thread.message.in_progress" or event.event == "error": - # currently no special handling - ... - else: - # we only want to error at build-time - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(event) - - self._current_event = None - - def __stream__(self) -> Iterator[AssistantStreamEvent]: - stream = self.__stream - if not stream: - raise RuntimeError("Stream has not been started yet") - - try: - for event in stream: - self._emit_sse_event(event) - - yield event - except (httpx.TimeoutException, asyncio.TimeoutError) as exc: - self.on_timeout() - self.on_exception(exc) - raise - except Exception as exc: - self.on_exception(exc) - raise - finally: - self.on_end() - - -AssistantEventHandlerT = TypeVar("AssistantEventHandlerT", bound=AssistantEventHandler) - - -class AssistantStreamManager(Generic[AssistantEventHandlerT]): - """Wrapper over AssistantStreamEventHandler that is returned by `.stream()` - so that a context manager can be used. - - ```py - with client.threads.create_and_run_stream(...) as stream: - for event in stream: - ... - ``` - """ - - def __init__( - self, - api_request: Callable[[], Stream[AssistantStreamEvent]], - *, - event_handler: AssistantEventHandlerT, - ) -> None: - self.__stream: Stream[AssistantStreamEvent] | None = None - self.__event_handler = event_handler - self.__api_request = api_request - - def __enter__(self) -> AssistantEventHandlerT: - self.__stream = self.__api_request() - self.__event_handler._init(self.__stream) - return self.__event_handler - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - self.__stream.close() - - -class AsyncAssistantEventHandler: - text_deltas: AsyncIterable[str] - """Iterator over just the text deltas in the stream. - - This corresponds to the `thread.message.delta` event - in the API. - - ```py - async for text in stream.text_deltas: - print(text, end="", flush=True) - print() - ``` - """ - - def __init__(self) -> None: - self._current_event: AssistantStreamEvent | None = None - self._current_message_content_index: int | None = None - self._current_message_content: MessageContent | None = None - self._current_tool_call_index: int | None = None - self._current_tool_call: ToolCall | None = None - self.__current_run_step_id: str | None = None - self.__current_run: Run | None = None - self.__run_step_snapshots: dict[str, RunStep] = {} - self.__message_snapshots: dict[str, Message] = {} - self.__current_message_snapshot: Message | None = None - - self.text_deltas = self.__text_deltas__() - self._iterator = self.__stream__() - self.__stream: AsyncStream[AssistantStreamEvent] | None = None - - def _init(self, stream: AsyncStream[AssistantStreamEvent]) -> None: - if self.__stream: - raise RuntimeError( - "A single event handler cannot be shared between multiple streams; You will need to construct a new event handler instance" - ) - - self.__stream = stream - - async def __anext__(self) -> AssistantStreamEvent: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[AssistantStreamEvent]: - async for item in self._iterator: - yield item - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called when the context manager exits. - """ - if self.__stream: - await self.__stream.close() - - @property - def current_event(self) -> AssistantStreamEvent | None: - return self._current_event - - @property - def current_run(self) -> Run | None: - return self.__current_run - - @property - def current_run_step_snapshot(self) -> RunStep | None: - if not self.__current_run_step_id: - return None - - return self.__run_step_snapshots[self.__current_run_step_id] - - @property - def current_message_snapshot(self) -> Message | None: - return self.__current_message_snapshot - - async def until_done(self) -> None: - """Waits until the stream has been consumed""" - await consume_async_iterator(self) - - async def get_final_run(self) -> Run: - """Wait for the stream to finish and returns the completed Run object""" - await self.until_done() - - if not self.__current_run: - raise RuntimeError("No final run object found") - - return self.__current_run - - async def get_final_run_steps(self) -> list[RunStep]: - """Wait for the stream to finish and returns the steps taken in this run""" - await self.until_done() - - if not self.__run_step_snapshots: - raise RuntimeError("No run steps found") - - return [step for step in self.__run_step_snapshots.values()] - - async def get_final_messages(self) -> list[Message]: - """Wait for the stream to finish and returns the messages emitted in this run""" - await self.until_done() - - if not self.__message_snapshots: - raise RuntimeError("No messages found") - - return [message for message in self.__message_snapshots.values()] - - async def __text_deltas__(self) -> AsyncIterator[str]: - async for event in self: - if event.event != "thread.message.delta": - continue - - for content_delta in event.data.delta.content or []: - if content_delta.type == "text" and content_delta.text and content_delta.text.value: - yield content_delta.text.value - - # event handlers - - async def on_end(self) -> None: - """Fires when the stream has finished. - - This happens if the stream is read to completion - or if an exception occurs during iteration. - """ - - async def on_event(self, event: AssistantStreamEvent) -> None: - """Callback that is fired for every Server-Sent-Event""" - - async def on_run_step_created(self, run_step: RunStep) -> None: - """Callback that is fired when a run step is created""" - - async def on_run_step_delta(self, delta: RunStepDelta, snapshot: RunStep) -> None: - """Callback that is fired whenever a run step delta is returned from the API - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the run step. For example, a tool calls event may - look like this: - - # delta - tool_calls=[ - RunStepDeltaToolCallsCodeInterpreter( - index=0, - type='code_interpreter', - id=None, - code_interpreter=CodeInterpreter(input=' sympy', outputs=None) - ) - ] - # snapshot - tool_calls=[ - CodeToolCall( - id='call_wKayJlcYV12NiadiZuJXxcfx', - code_interpreter=CodeInterpreter(input='from sympy', outputs=[]), - type='code_interpreter', - index=0 - ) - ], - """ - - async def on_run_step_done(self, run_step: RunStep) -> None: - """Callback that is fired when a run step is completed""" - - async def on_tool_call_created(self, tool_call: ToolCall) -> None: - """Callback that is fired when a tool call is created""" - - async def on_tool_call_delta(self, delta: ToolCallDelta, snapshot: ToolCall) -> None: - """Callback that is fired when a tool call delta is encountered""" - - async def on_tool_call_done(self, tool_call: ToolCall) -> None: - """Callback that is fired when a tool call delta is encountered""" - - async def on_exception(self, exception: Exception) -> None: - """Fired whenever an exception happens during streaming""" - - async def on_timeout(self) -> None: - """Fires if the request times out""" - - async def on_message_created(self, message: Message) -> None: - """Callback that is fired when a message is created""" - - async def on_message_delta(self, delta: MessageDelta, snapshot: Message) -> None: - """Callback that is fired whenever a message delta is returned from the API - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the message. For example, a text content event may - look like this: - - # delta - MessageDeltaText( - index=0, - type='text', - text=Text( - value=' Jane' - ), - ) - # snapshot - MessageContentText( - index=0, - type='text', - text=Text( - value='Certainly, Jane' - ), - ) - """ - - async def on_message_done(self, message: Message) -> None: - """Callback that is fired when a message is completed""" - - async def on_text_created(self, text: Text) -> None: - """Callback that is fired when a text content block is created""" - - async def on_text_delta(self, delta: TextDelta, snapshot: Text) -> None: - """Callback that is fired whenever a text content delta is returned - by the API. - - The first argument is just the delta as sent by the API and the second argument - is the accumulated snapshot of the text. For example: - - on_text_delta(TextDelta(value="The"), Text(value="The")), - on_text_delta(TextDelta(value=" solution"), Text(value="The solution")), - on_text_delta(TextDelta(value=" to"), Text(value="The solution to")), - on_text_delta(TextDelta(value=" the"), Text(value="The solution to the")), - on_text_delta(TextDelta(value=" equation"), Text(value="The solution to the equivalent")), - """ - - async def on_text_done(self, text: Text) -> None: - """Callback that is fired when a text content block is finished""" - - async def on_image_file_done(self, image_file: ImageFile) -> None: - """Callback that is fired when an image file block is finished""" - - async def _emit_sse_event(self, event: AssistantStreamEvent) -> None: - self._current_event = event - await self.on_event(event) - - self.__current_message_snapshot, new_content = accumulate_event( - event=event, - current_message_snapshot=self.__current_message_snapshot, - ) - if self.__current_message_snapshot is not None: - self.__message_snapshots[self.__current_message_snapshot.id] = self.__current_message_snapshot - - accumulate_run_step( - event=event, - run_step_snapshots=self.__run_step_snapshots, - ) - - for content_delta in new_content: - assert self.__current_message_snapshot is not None - - block = self.__current_message_snapshot.content[content_delta.index] - if block.type == "text": - await self.on_text_created(block.text) - - if ( - event.event == "thread.run.completed" - or event.event == "thread.run.cancelled" - or event.event == "thread.run.expired" - or event.event == "thread.run.failed" - or event.event == "thread.run.requires_action" - or event.event == "thread.run.incomplete" - ): - self.__current_run = event.data - if self._current_tool_call: - await self.on_tool_call_done(self._current_tool_call) - elif ( - event.event == "thread.run.created" - or event.event == "thread.run.in_progress" - or event.event == "thread.run.cancelling" - or event.event == "thread.run.queued" - ): - self.__current_run = event.data - elif event.event == "thread.message.created": - await self.on_message_created(event.data) - elif event.event == "thread.message.delta": - snapshot = self.__current_message_snapshot - assert snapshot is not None - - message_delta = event.data.delta - if message_delta.content is not None: - for content_delta in message_delta.content: - if content_delta.type == "text" and content_delta.text: - snapshot_content = snapshot.content[content_delta.index] - assert snapshot_content.type == "text" - await self.on_text_delta(content_delta.text, snapshot_content.text) - - # If the delta is for a new message content: - # - emit on_text_done/on_image_file_done for the previous message content - # - emit on_text_created/on_image_created for the new message content - if content_delta.index != self._current_message_content_index: - if self._current_message_content is not None: - if self._current_message_content.type == "text": - await self.on_text_done(self._current_message_content.text) - elif self._current_message_content.type == "image_file": - await self.on_image_file_done(self._current_message_content.image_file) - - self._current_message_content_index = content_delta.index - self._current_message_content = snapshot.content[content_delta.index] - - # Update the current_message_content (delta event is correctly emitted already) - self._current_message_content = snapshot.content[content_delta.index] - - await self.on_message_delta(event.data.delta, snapshot) - elif event.event == "thread.message.completed" or event.event == "thread.message.incomplete": - self.__current_message_snapshot = event.data - self.__message_snapshots[event.data.id] = event.data - - if self._current_message_content_index is not None: - content = event.data.content[self._current_message_content_index] - if content.type == "text": - await self.on_text_done(content.text) - elif content.type == "image_file": - await self.on_image_file_done(content.image_file) - - await self.on_message_done(event.data) - elif event.event == "thread.run.step.created": - self.__current_run_step_id = event.data.id - await self.on_run_step_created(event.data) - elif event.event == "thread.run.step.in_progress": - self.__current_run_step_id = event.data.id - elif event.event == "thread.run.step.delta": - step_snapshot = self.__run_step_snapshots[event.data.id] - - run_step_delta = event.data.delta - if ( - run_step_delta.step_details - and run_step_delta.step_details.type == "tool_calls" - and run_step_delta.step_details.tool_calls is not None - ): - assert step_snapshot.step_details.type == "tool_calls" - for tool_call_delta in run_step_delta.step_details.tool_calls: - if tool_call_delta.index == self._current_tool_call_index: - await self.on_tool_call_delta( - tool_call_delta, - step_snapshot.step_details.tool_calls[tool_call_delta.index], - ) - - # If the delta is for a new tool call: - # - emit on_tool_call_done for the previous tool_call - # - emit on_tool_call_created for the new tool_call - if tool_call_delta.index != self._current_tool_call_index: - if self._current_tool_call is not None: - await self.on_tool_call_done(self._current_tool_call) - - self._current_tool_call_index = tool_call_delta.index - self._current_tool_call = step_snapshot.step_details.tool_calls[tool_call_delta.index] - await self.on_tool_call_created(self._current_tool_call) - - # Update the current_tool_call (delta event is correctly emitted already) - self._current_tool_call = step_snapshot.step_details.tool_calls[tool_call_delta.index] - - await self.on_run_step_delta( - event.data.delta, - step_snapshot, - ) - elif ( - event.event == "thread.run.step.completed" - or event.event == "thread.run.step.cancelled" - or event.event == "thread.run.step.expired" - or event.event == "thread.run.step.failed" - ): - if self._current_tool_call: - await self.on_tool_call_done(self._current_tool_call) - - await self.on_run_step_done(event.data) - self.__current_run_step_id = None - elif event.event == "thread.created" or event.event == "thread.message.in_progress" or event.event == "error": - # currently no special handling - ... - else: - # we only want to error at build-time - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(event) - - self._current_event = None - - async def __stream__(self) -> AsyncIterator[AssistantStreamEvent]: - stream = self.__stream - if not stream: - raise RuntimeError("Stream has not been started yet") - - try: - async for event in stream: - await self._emit_sse_event(event) - - yield event - except (httpx.TimeoutException, asyncio.TimeoutError) as exc: - await self.on_timeout() - await self.on_exception(exc) - raise - except Exception as exc: - await self.on_exception(exc) - raise - finally: - await self.on_end() - - -AsyncAssistantEventHandlerT = TypeVar("AsyncAssistantEventHandlerT", bound=AsyncAssistantEventHandler) - - -class AsyncAssistantStreamManager(Generic[AsyncAssistantEventHandlerT]): - """Wrapper over AsyncAssistantStreamEventHandler that is returned by `.stream()` - so that an async context manager can be used without `await`ing the - original client call. - - ```py - async with client.threads.create_and_run_stream(...) as stream: - async for event in stream: - ... - ``` - """ - - def __init__( - self, - api_request: Awaitable[AsyncStream[AssistantStreamEvent]], - *, - event_handler: AsyncAssistantEventHandlerT, - ) -> None: - self.__stream: AsyncStream[AssistantStreamEvent] | None = None - self.__event_handler = event_handler - self.__api_request = api_request - - async def __aenter__(self) -> AsyncAssistantEventHandlerT: - self.__stream = await self.__api_request - self.__event_handler._init(self.__stream) - return self.__event_handler - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - await self.__stream.close() - - -def accumulate_run_step( - *, - event: AssistantStreamEvent, - run_step_snapshots: dict[str, RunStep], -) -> None: - if event.event == "thread.run.step.created": - run_step_snapshots[event.data.id] = event.data - return - - if event.event == "thread.run.step.delta": - data = event.data - snapshot = run_step_snapshots[data.id] - - if data.delta: - merged = accumulate_delta( - cast( - "dict[object, object]", - model_dump(snapshot, exclude_unset=True, warnings=False), - ), - cast( - "dict[object, object]", - model_dump(data.delta, exclude_unset=True, warnings=False), - ), - ) - run_step_snapshots[snapshot.id] = cast(RunStep, construct_type(type_=RunStep, value=merged)) - - return None - - -def accumulate_event( - *, - event: AssistantStreamEvent, - current_message_snapshot: Message | None, -) -> tuple[Message | None, list[MessageContentDelta]]: - """Returns a tuple of message snapshot and newly created text message deltas""" - if event.event == "thread.message.created": - return event.data, [] - - new_content: list[MessageContentDelta] = [] - - if event.event != "thread.message.delta": - return current_message_snapshot, [] - - if not current_message_snapshot: - raise RuntimeError("Encountered a message delta with no previous snapshot") - - data = event.data - if data.delta.content: - for content_delta in data.delta.content: - try: - block = current_message_snapshot.content[content_delta.index] - except IndexError: - current_message_snapshot.content.insert( - content_delta.index, - cast( - MessageContent, - construct_type( - # mypy doesn't allow Content for some reason - type_=cast(Any, MessageContent), - value=model_dump(content_delta, exclude_unset=True, warnings=False), - ), - ), - ) - new_content.append(content_delta) - else: - merged = accumulate_delta( - cast( - "dict[object, object]", - model_dump(block, exclude_unset=True, warnings=False), - ), - cast( - "dict[object, object]", - model_dump(content_delta, exclude_unset=True, warnings=False), - ), - ) - current_message_snapshot.content[content_delta.index] = cast( - MessageContent, - construct_type( - # mypy doesn't allow Content for some reason - type_=cast(Any, MessageContent), - value=merged, - ), - ) - - return current_message_snapshot, new_content - - -def accumulate_delta(acc: dict[object, object], delta: dict[object, object]) -> dict[object, object]: - for key, delta_value in delta.items(): - if key not in acc: - acc[key] = delta_value - continue - - acc_value = acc[key] - if acc_value is None: - acc[key] = delta_value - continue - - # the `index` property is used in arrays of objects so it should - # not be accumulated like other values e.g. - # [{'foo': 'bar', 'index': 0}] - # - # the same applies to `type` properties as they're used for - # discriminated unions - if key == "index" or key == "type": - acc[key] = delta_value - continue - - if isinstance(acc_value, str) and isinstance(delta_value, str): - acc_value += delta_value - elif isinstance(acc_value, (int, float)) and isinstance(delta_value, (int, float)): - acc_value += delta_value - elif is_dict(acc_value) and is_dict(delta_value): - acc_value = accumulate_delta(acc_value, delta_value) - elif is_list(acc_value) and is_list(delta_value): - # for lists of non-dictionary items we'll only ever get new entries - # in the array, existing entries will never be changed - if all(isinstance(x, (str, int, float)) for x in acc_value): - acc_value.extend(delta_value) - continue - - for delta_entry in delta_value: - if not is_dict(delta_entry): - raise TypeError(f"Unexpected list delta entry is not a dictionary: {delta_entry}") - - try: - index = delta_entry["index"] - except KeyError as exc: - raise RuntimeError(f"Expected list delta entry to have an `index` key; {delta_entry}") from exc - - if not isinstance(index, int): - raise TypeError(f"Unexpected, list delta entry `index` value is not an integer; {index}") - - try: - acc_entry = acc_value[index] - except IndexError: - acc_value.insert(index, delta_entry) - else: - if not is_dict(acc_entry): - raise TypeError("not handled yet") - - acc_value[index] = accumulate_delta(acc_entry, delta_entry) - - acc[key] = acc_value - - return acc diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_deltas.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_deltas.py deleted file mode 100644 index a5e1317..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/_deltas.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -from ..._utils import is_dict, is_list - - -def accumulate_delta(acc: dict[object, object], delta: dict[object, object]) -> dict[object, object]: - for key, delta_value in delta.items(): - if key not in acc: - acc[key] = delta_value - continue - - acc_value = acc[key] - if acc_value is None: - acc[key] = delta_value - continue - - # the `index` property is used in arrays of objects so it should - # not be accumulated like other values e.g. - # [{'foo': 'bar', 'index': 0}] - # - # the same applies to `type` properties as they're used for - # discriminated unions - if key == "index" or key == "type": - acc[key] = delta_value - continue - - if isinstance(acc_value, str) and isinstance(delta_value, str): - acc_value += delta_value - elif isinstance(acc_value, (int, float)) and isinstance(delta_value, (int, float)): - acc_value += delta_value - elif is_dict(acc_value) and is_dict(delta_value): - acc_value = accumulate_delta(acc_value, delta_value) - elif is_list(acc_value) and is_list(delta_value): - # for lists of non-dictionary items we'll only ever get new entries - # in the array, existing entries will never be changed - if all(isinstance(x, (str, int, float)) for x in acc_value): - acc_value.extend(delta_value) - continue - - for delta_entry in delta_value: - if not is_dict(delta_entry): - raise TypeError(f"Unexpected list delta entry is not a dictionary: {delta_entry}") - - try: - index = delta_entry["index"] - except KeyError as exc: - raise RuntimeError(f"Expected list delta entry to have an `index` key; {delta_entry}") from exc - - if not isinstance(index, int): - raise TypeError(f"Unexpected, list delta entry `index` value is not an integer; {index}") - - try: - acc_entry = acc_value[index] - except IndexError: - acc_value.insert(index, delta_entry) - else: - if not is_dict(acc_entry): - raise TypeError("not handled yet") - - acc_value[index] = accumulate_delta(acc_entry, delta_entry) - - acc[key] = acc_value - - return acc diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/__init__.py deleted file mode 100644 index dfa3f3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -from ._types import ( - ParsedChoiceSnapshot as ParsedChoiceSnapshot, - ParsedChatCompletionSnapshot as ParsedChatCompletionSnapshot, - ParsedChatCompletionMessageSnapshot as ParsedChatCompletionMessageSnapshot, -) -from ._events import ( - ChunkEvent as ChunkEvent, - ContentDoneEvent as ContentDoneEvent, - RefusalDoneEvent as RefusalDoneEvent, - ContentDeltaEvent as ContentDeltaEvent, - RefusalDeltaEvent as RefusalDeltaEvent, - LogprobsContentDoneEvent as LogprobsContentDoneEvent, - LogprobsRefusalDoneEvent as LogprobsRefusalDoneEvent, - ChatCompletionStreamEvent as ChatCompletionStreamEvent, - LogprobsContentDeltaEvent as LogprobsContentDeltaEvent, - LogprobsRefusalDeltaEvent as LogprobsRefusalDeltaEvent, - ParsedChatCompletionSnapshot as ParsedChatCompletionSnapshot, - FunctionToolCallArgumentsDoneEvent as FunctionToolCallArgumentsDoneEvent, - FunctionToolCallArgumentsDeltaEvent as FunctionToolCallArgumentsDeltaEvent, -) -from ._completions import ( - ChatCompletionStream as ChatCompletionStream, - AsyncChatCompletionStream as AsyncChatCompletionStream, - ChatCompletionStreamState as ChatCompletionStreamState, - ChatCompletionStreamManager as ChatCompletionStreamManager, - AsyncChatCompletionStreamManager as AsyncChatCompletionStreamManager, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_completions.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_completions.py deleted file mode 100644 index c4610e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_completions.py +++ /dev/null @@ -1,770 +0,0 @@ -from __future__ import annotations - -import inspect -from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, Callable, Iterable, Awaitable, AsyncIterator, cast -from typing_extensions import Self, Iterator, assert_never - -from jiter import from_json - -from ._types import ParsedChoiceSnapshot, ParsedChatCompletionSnapshot, ParsedChatCompletionMessageSnapshot -from ._events import ( - ChunkEvent, - ContentDoneEvent, - RefusalDoneEvent, - ContentDeltaEvent, - RefusalDeltaEvent, - LogprobsContentDoneEvent, - LogprobsRefusalDoneEvent, - ChatCompletionStreamEvent, - LogprobsContentDeltaEvent, - LogprobsRefusalDeltaEvent, - FunctionToolCallArgumentsDoneEvent, - FunctionToolCallArgumentsDeltaEvent, -) -from .._deltas import accumulate_delta -from ...._types import Omit, IncEx, omit -from ...._utils import is_given, consume_sync_iterator, consume_async_iterator -from ...._compat import model_dump -from ...._models import build, construct_type -from ..._parsing import ( - ResponseFormatT, - has_parseable_input, - maybe_parse_content, - parse_chat_completion, - get_input_tool_by_name, - solve_response_format_t, - parse_function_tool_arguments, -) -from ...._streaming import Stream, AsyncStream -from ....types.chat import ChatCompletionChunk, ParsedChatCompletion, ChatCompletionToolUnionParam -from ...._exceptions import LengthFinishReasonError, ContentFilterFinishReasonError -from ....types.chat.chat_completion import ChoiceLogprobs -from ....types.chat.chat_completion_chunk import Choice as ChoiceChunk -from ....types.chat.completion_create_params import ResponseFormat as ResponseFormatParam - - -class ChatCompletionStream(Generic[ResponseFormatT]): - """Wrapper over the Chat Completions streaming API that adds helpful - events such as `content.done`, supports automatically parsing - responses & tool calls and accumulates a `ChatCompletion` object - from each individual chunk. - - https://platform.openai.com/docs/api-reference/streaming - """ - - def __init__( - self, - *, - raw_stream: Stream[ChatCompletionChunk], - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, - ) -> None: - self._raw_stream = raw_stream - self._response = raw_stream.response - self._iterator = self.__stream__() - self._state = ChatCompletionStreamState(response_format=response_format, input_tools=input_tools) - - def __next__(self) -> ChatCompletionStreamEvent[ResponseFormatT]: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[ChatCompletionStreamEvent[ResponseFormatT]]: - for item in self._iterator: - yield item - - def __enter__(self) -> Self: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self._response.close() - - def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: - """Waits until the stream has been read to completion and returns - the accumulated `ParsedChatCompletion` object. - - If you passed a class type to `.stream()`, the `completion.choices[0].message.parsed` - property will be the content deserialised into that class, if there was any content returned - by the API. - """ - self.until_done() - return self._state.get_final_completion() - - def until_done(self) -> Self: - """Blocks until the stream has been consumed.""" - consume_sync_iterator(self) - return self - - @property - def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: - return self._state.current_completion_snapshot - - def __stream__(self) -> Iterator[ChatCompletionStreamEvent[ResponseFormatT]]: - for sse_event in self._raw_stream: - if not _is_valid_chat_completion_chunk_weak(sse_event): - continue - events_to_fire = self._state.handle_chunk(sse_event) - for event in events_to_fire: - yield event - - -class ChatCompletionStreamManager(Generic[ResponseFormatT]): - """Context manager over a `ChatCompletionStream` that is returned by `.stream()`. - - This context manager ensures the response cannot be leaked if you don't read - the stream to completion. - - Usage: - ```py - with client.chat.completions.stream(...) as stream: - for event in stream: - ... - ``` - """ - - def __init__( - self, - api_request: Callable[[], Stream[ChatCompletionChunk]], - *, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, - ) -> None: - self.__stream: ChatCompletionStream[ResponseFormatT] | None = None - self.__api_request = api_request - self.__response_format = response_format - self.__input_tools = input_tools - - def __enter__(self) -> ChatCompletionStream[ResponseFormatT]: - raw_stream = self.__api_request() - - self.__stream = ChatCompletionStream( - raw_stream=raw_stream, - response_format=self.__response_format, - input_tools=self.__input_tools, - ) - - return self.__stream - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - self.__stream.close() - - -class AsyncChatCompletionStream(Generic[ResponseFormatT]): - """Wrapper over the Chat Completions streaming API that adds helpful - events such as `content.done`, supports automatically parsing - responses & tool calls and accumulates a `ChatCompletion` object - from each individual chunk. - - https://platform.openai.com/docs/api-reference/streaming - """ - - def __init__( - self, - *, - raw_stream: AsyncStream[ChatCompletionChunk], - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, - ) -> None: - self._raw_stream = raw_stream - self._response = raw_stream.response - self._iterator = self.__stream__() - self._state = ChatCompletionStreamState(response_format=response_format, input_tools=input_tools) - - async def __anext__(self) -> ChatCompletionStreamEvent[ResponseFormatT]: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[ChatCompletionStreamEvent[ResponseFormatT]]: - async for item in self._iterator: - yield item - - async def __aenter__(self) -> Self: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self._response.aclose() - - async def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: - """Waits until the stream has been read to completion and returns - the accumulated `ParsedChatCompletion` object. - - If you passed a class type to `.stream()`, the `completion.choices[0].message.parsed` - property will be the content deserialised into that class, if there was any content returned - by the API. - """ - await self.until_done() - return self._state.get_final_completion() - - async def until_done(self) -> Self: - """Blocks until the stream has been consumed.""" - await consume_async_iterator(self) - return self - - @property - def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: - return self._state.current_completion_snapshot - - async def __stream__(self) -> AsyncIterator[ChatCompletionStreamEvent[ResponseFormatT]]: - async for sse_event in self._raw_stream: - if not _is_valid_chat_completion_chunk_weak(sse_event): - continue - events_to_fire = self._state.handle_chunk(sse_event) - for event in events_to_fire: - yield event - - -class AsyncChatCompletionStreamManager(Generic[ResponseFormatT]): - """Context manager over a `AsyncChatCompletionStream` that is returned by `.stream()`. - - This context manager ensures the response cannot be leaked if you don't read - the stream to completion. - - Usage: - ```py - async with client.chat.completions.stream(...) as stream: - for event in stream: - ... - ``` - """ - - def __init__( - self, - api_request: Awaitable[AsyncStream[ChatCompletionChunk]], - *, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit, - ) -> None: - self.__stream: AsyncChatCompletionStream[ResponseFormatT] | None = None - self.__api_request = api_request - self.__response_format = response_format - self.__input_tools = input_tools - - async def __aenter__(self) -> AsyncChatCompletionStream[ResponseFormatT]: - raw_stream = await self.__api_request - - self.__stream = AsyncChatCompletionStream( - raw_stream=raw_stream, - response_format=self.__response_format, - input_tools=self.__input_tools, - ) - - return self.__stream - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - await self.__stream.close() - - -class ChatCompletionStreamState(Generic[ResponseFormatT]): - """Helper class for manually accumulating `ChatCompletionChunk`s into a final `ChatCompletion` object. - - This is useful in cases where you can't always use the `.stream()` method, e.g. - - ```py - from openai.lib.streaming.chat import ChatCompletionStreamState - - state = ChatCompletionStreamState() - - stream = client.chat.completions.create(..., stream=True) - for chunk in response: - state.handle_chunk(chunk) - - # can also access the accumulated `ChatCompletion` mid-stream - state.current_completion_snapshot - - print(state.get_final_completion()) - ``` - """ - - def __init__( - self, - *, - input_tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit = omit, - ) -> None: - self.__current_completion_snapshot: ParsedChatCompletionSnapshot | None = None - self.__choice_event_states: list[ChoiceEventState] = [] - - self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] - self._response_format = response_format - self._rich_response_format: type | Omit = response_format if inspect.isclass(response_format) else omit - - def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: - """Parse the final completion object. - - Note this does not provide any guarantees that the stream has actually finished, you must - only call this method when the stream is finished. - """ - return parse_chat_completion( - chat_completion=self.current_completion_snapshot, - response_format=self._rich_response_format, - input_tools=self._input_tools, - ) - - @property - def current_completion_snapshot(self) -> ParsedChatCompletionSnapshot: - assert self.__current_completion_snapshot is not None - return self.__current_completion_snapshot - - def handle_chunk(self, chunk: ChatCompletionChunk) -> Iterable[ChatCompletionStreamEvent[ResponseFormatT]]: - """Accumulate a new chunk into the snapshot and returns an iterable of events to yield.""" - self.__current_completion_snapshot = self._accumulate_chunk(chunk) - - return self._build_events( - chunk=chunk, - completion_snapshot=self.__current_completion_snapshot, - ) - - def _get_choice_state(self, choice: ChoiceChunk) -> ChoiceEventState: - try: - return self.__choice_event_states[choice.index] - except IndexError: - choice_state = ChoiceEventState(input_tools=self._input_tools) - self.__choice_event_states.append(choice_state) - return choice_state - - def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionSnapshot: - completion_snapshot = self.__current_completion_snapshot - - if completion_snapshot is None: - return _convert_initial_chunk_into_snapshot(chunk) - - for choice in chunk.choices: - try: - choice_snapshot = completion_snapshot.choices[choice.index] - previous_tool_calls = choice_snapshot.message.tool_calls or [] - - choice_snapshot.message = cast( - ParsedChatCompletionMessageSnapshot, - construct_type( - type_=ParsedChatCompletionMessageSnapshot, - value=accumulate_delta( - cast( - "dict[object, object]", - model_dump( - choice_snapshot.message, - # we don't want to serialise / deserialise our custom properties - # as they won't appear in the delta and we don't want to have to - # continuosly reparse the content - exclude=cast( - # cast required as mypy isn't smart enough to infer `True` here to `Literal[True]` - IncEx, - { - "parsed": True, - "tool_calls": { - idx: {"function": {"parsed_arguments": True}} - for idx, _ in enumerate(choice_snapshot.message.tool_calls or []) - }, - }, - ), - ), - ), - cast("dict[object, object]", choice.delta.to_dict()), - ), - ), - ) - - # ensure tools that have already been parsed are added back into the newly - # constructed message snapshot - for tool_index, prev_tool in enumerate(previous_tool_calls): - new_tool = (choice_snapshot.message.tool_calls or [])[tool_index] - - if prev_tool.type == "function": - assert new_tool.type == "function" - new_tool.function.parsed_arguments = prev_tool.function.parsed_arguments - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(prev_tool) - except IndexError: - choice_snapshot = cast( - ParsedChoiceSnapshot, - construct_type( - type_=ParsedChoiceSnapshot, - value={ - **choice.model_dump(exclude_unset=True, exclude={"delta"}), - "message": choice.delta.to_dict(), - }, - ), - ) - completion_snapshot.choices.append(choice_snapshot) - - if choice.finish_reason: - choice_snapshot.finish_reason = choice.finish_reason - - if has_parseable_input(response_format=self._response_format, input_tools=self._input_tools): - if choice.finish_reason == "length": - # at the time of writing, `.usage` will always be `None` but - # we include it here in case that is changed in the future - raise LengthFinishReasonError(completion=completion_snapshot) - - if choice.finish_reason == "content_filter": - raise ContentFilterFinishReasonError() - - if ( - choice_snapshot.message.content - and not choice_snapshot.message.refusal - and is_given(self._rich_response_format) - # partial parsing fails on white-space - and choice_snapshot.message.content.lstrip() - ): - choice_snapshot.message.parsed = from_json( - bytes(choice_snapshot.message.content, "utf-8"), - partial_mode=True, - ) - - for tool_call_chunk in choice.delta.tool_calls or []: - tool_call_snapshot = (choice_snapshot.message.tool_calls or [])[tool_call_chunk.index] - - if tool_call_snapshot.type == "function": - input_tool = get_input_tool_by_name( - input_tools=self._input_tools, name=tool_call_snapshot.function.name - ) - - if ( - input_tool - and input_tool.get("function", {}).get("strict") - and tool_call_snapshot.function.arguments - ): - tool_call_snapshot.function.parsed_arguments = from_json( - bytes(tool_call_snapshot.function.arguments, "utf-8"), - partial_mode=True, - ) - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(tool_call_snapshot) - - if choice.logprobs is not None: - if choice_snapshot.logprobs is None: - choice_snapshot.logprobs = build( - ChoiceLogprobs, - content=choice.logprobs.content, - refusal=choice.logprobs.refusal, - ) - else: - if choice.logprobs.content: - if choice_snapshot.logprobs.content is None: - choice_snapshot.logprobs.content = [] - - choice_snapshot.logprobs.content.extend(choice.logprobs.content) - - if choice.logprobs.refusal: - if choice_snapshot.logprobs.refusal is None: - choice_snapshot.logprobs.refusal = [] - - choice_snapshot.logprobs.refusal.extend(choice.logprobs.refusal) - - completion_snapshot.usage = chunk.usage - completion_snapshot.system_fingerprint = chunk.system_fingerprint - - return completion_snapshot - - def _build_events( - self, - *, - chunk: ChatCompletionChunk, - completion_snapshot: ParsedChatCompletionSnapshot, - ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: - events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] - - events_to_fire.append( - build(ChunkEvent, type="chunk", chunk=chunk, snapshot=completion_snapshot), - ) - - for choice in chunk.choices: - choice_state = self._get_choice_state(choice) - choice_snapshot = completion_snapshot.choices[choice.index] - - if choice.delta.content is not None and choice_snapshot.message.content is not None: - events_to_fire.append( - build( - ContentDeltaEvent, - type="content.delta", - delta=choice.delta.content, - snapshot=choice_snapshot.message.content, - parsed=choice_snapshot.message.parsed, - ) - ) - - if choice.delta.refusal is not None and choice_snapshot.message.refusal is not None: - events_to_fire.append( - build( - RefusalDeltaEvent, - type="refusal.delta", - delta=choice.delta.refusal, - snapshot=choice_snapshot.message.refusal, - ) - ) - - if choice.delta.tool_calls: - tool_calls = choice_snapshot.message.tool_calls - assert tool_calls is not None - - for tool_call_delta in choice.delta.tool_calls: - tool_call = tool_calls[tool_call_delta.index] - - if tool_call.type == "function": - assert tool_call_delta.function is not None - events_to_fire.append( - build( - FunctionToolCallArgumentsDeltaEvent, - type="tool_calls.function.arguments.delta", - name=tool_call.function.name, - index=tool_call_delta.index, - arguments=tool_call.function.arguments, - parsed_arguments=tool_call.function.parsed_arguments, - arguments_delta=tool_call_delta.function.arguments or "", - ) - ) - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(tool_call) - - if choice.logprobs is not None and choice_snapshot.logprobs is not None: - if choice.logprobs.content and choice_snapshot.logprobs.content: - events_to_fire.append( - build( - LogprobsContentDeltaEvent, - type="logprobs.content.delta", - content=choice.logprobs.content, - snapshot=choice_snapshot.logprobs.content, - ), - ) - - if choice.logprobs.refusal and choice_snapshot.logprobs.refusal: - events_to_fire.append( - build( - LogprobsRefusalDeltaEvent, - type="logprobs.refusal.delta", - refusal=choice.logprobs.refusal, - snapshot=choice_snapshot.logprobs.refusal, - ), - ) - - events_to_fire.extend( - choice_state.get_done_events( - choice_chunk=choice, - choice_snapshot=choice_snapshot, - response_format=self._response_format, - ) - ) - - return events_to_fire - - -class ChoiceEventState: - def __init__(self, *, input_tools: list[ChatCompletionToolUnionParam]) -> None: - self._input_tools = input_tools - - self._content_done = False - self._refusal_done = False - self._logprobs_content_done = False - self._logprobs_refusal_done = False - self._done_tool_calls: set[int] = set() - self.__current_tool_call_index: int | None = None - - def get_done_events( - self, - *, - choice_chunk: ChoiceChunk, - choice_snapshot: ParsedChoiceSnapshot, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: - events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] - - if choice_snapshot.finish_reason: - events_to_fire.extend( - self._content_done_events(choice_snapshot=choice_snapshot, response_format=response_format) - ) - - if ( - self.__current_tool_call_index is not None - and self.__current_tool_call_index not in self._done_tool_calls - ): - self._add_tool_done_event( - events_to_fire=events_to_fire, - choice_snapshot=choice_snapshot, - tool_index=self.__current_tool_call_index, - ) - - for tool_call in choice_chunk.delta.tool_calls or []: - if self.__current_tool_call_index != tool_call.index: - events_to_fire.extend( - self._content_done_events(choice_snapshot=choice_snapshot, response_format=response_format) - ) - - if self.__current_tool_call_index is not None: - self._add_tool_done_event( - events_to_fire=events_to_fire, - choice_snapshot=choice_snapshot, - tool_index=self.__current_tool_call_index, - ) - - self.__current_tool_call_index = tool_call.index - - return events_to_fire - - def _content_done_events( - self, - *, - choice_snapshot: ParsedChoiceSnapshot, - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, - ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: - events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] - - if choice_snapshot.message.content and not self._content_done: - self._content_done = True - - parsed = maybe_parse_content( - response_format=response_format, - message=choice_snapshot.message, - ) - - # update the parsed content to now use the richer `response_format` - # as opposed to the raw JSON-parsed object as the content is now - # complete and can be fully validated. - choice_snapshot.message.parsed = parsed - - events_to_fire.append( - build( - # we do this dance so that when the `ContentDoneEvent` instance - # is printed at runtime the class name will include the solved - # type variable, e.g. `ContentDoneEvent[MyModelType]` - cast( # pyright: ignore[reportUnnecessaryCast] - "type[ContentDoneEvent[ResponseFormatT]]", - cast(Any, ContentDoneEvent)[solve_response_format_t(response_format)], - ), - type="content.done", - content=choice_snapshot.message.content, - parsed=parsed, - ), - ) - - if choice_snapshot.message.refusal is not None and not self._refusal_done: - self._refusal_done = True - events_to_fire.append( - build(RefusalDoneEvent, type="refusal.done", refusal=choice_snapshot.message.refusal), - ) - - if ( - choice_snapshot.logprobs is not None - and choice_snapshot.logprobs.content is not None - and not self._logprobs_content_done - ): - self._logprobs_content_done = True - events_to_fire.append( - build(LogprobsContentDoneEvent, type="logprobs.content.done", content=choice_snapshot.logprobs.content), - ) - - if ( - choice_snapshot.logprobs is not None - and choice_snapshot.logprobs.refusal is not None - and not self._logprobs_refusal_done - ): - self._logprobs_refusal_done = True - events_to_fire.append( - build(LogprobsRefusalDoneEvent, type="logprobs.refusal.done", refusal=choice_snapshot.logprobs.refusal), - ) - - return events_to_fire - - def _add_tool_done_event( - self, - *, - events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]], - choice_snapshot: ParsedChoiceSnapshot, - tool_index: int, - ) -> None: - if tool_index in self._done_tool_calls: - return - - self._done_tool_calls.add(tool_index) - - assert choice_snapshot.message.tool_calls is not None - tool_call_snapshot = choice_snapshot.message.tool_calls[tool_index] - - if tool_call_snapshot.type == "function": - parsed_arguments = parse_function_tool_arguments( - input_tools=self._input_tools, function=tool_call_snapshot.function - ) - - # update the parsed content to potentially use a richer type - # as opposed to the raw JSON-parsed object as the content is now - # complete and can be fully validated. - tool_call_snapshot.function.parsed_arguments = parsed_arguments - - events_to_fire.append( - build( - FunctionToolCallArgumentsDoneEvent, - type="tool_calls.function.arguments.done", - index=tool_index, - name=tool_call_snapshot.function.name, - arguments=tool_call_snapshot.function.arguments, - parsed_arguments=parsed_arguments, - ) - ) - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(tool_call_snapshot) - - -def _convert_initial_chunk_into_snapshot(chunk: ChatCompletionChunk) -> ParsedChatCompletionSnapshot: - data = chunk.to_dict() - choices = cast("list[object]", data["choices"]) - - for choice in chunk.choices: - choices[choice.index] = { - **choice.model_dump(exclude_unset=True, exclude={"delta"}), - "message": choice.delta.to_dict(), - } - - return cast( - ParsedChatCompletionSnapshot, - construct_type( - type_=ParsedChatCompletionSnapshot, - value={ - "system_fingerprint": None, - **data, - "object": "chat.completion", - }, - ), - ) - - -def _is_valid_chat_completion_chunk_weak(sse_event: ChatCompletionChunk) -> bool: - # Although the _raw_stream is always supposed to contain only objects adhering to ChatCompletionChunk schema, - # this is broken by the Azure OpenAI in case of Asynchronous Filter enabled. - # An easy filter is to check for the "object" property: - # - should be "chat.completion.chunk" for a ChatCompletionChunk; - # - is an empty string for Asynchronous Filter events. - return sse_event.object == "chat.completion.chunk" # type: ignore # pylance reports this as a useless check diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_events.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_events.py deleted file mode 100644 index d4c1f28..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_events.py +++ /dev/null @@ -1,123 +0,0 @@ -from typing import List, Union, Generic, Optional -from typing_extensions import Literal - -from ._types import ParsedChatCompletionSnapshot -from ...._models import BaseModel, GenericModel -from ..._parsing import ResponseFormatT -from ....types.chat import ChatCompletionChunk, ChatCompletionTokenLogprob - - -class ChunkEvent(BaseModel): - type: Literal["chunk"] - - chunk: ChatCompletionChunk - - snapshot: ParsedChatCompletionSnapshot - - -class ContentDeltaEvent(BaseModel): - """This event is yielded for every chunk with `choice.delta.content` data.""" - - type: Literal["content.delta"] - - delta: str - - snapshot: str - - parsed: Optional[object] = None - - -class ContentDoneEvent(GenericModel, Generic[ResponseFormatT]): - type: Literal["content.done"] - - content: str - - parsed: Optional[ResponseFormatT] = None - - -class RefusalDeltaEvent(BaseModel): - type: Literal["refusal.delta"] - - delta: str - - snapshot: str - - -class RefusalDoneEvent(BaseModel): - type: Literal["refusal.done"] - - refusal: str - - -class FunctionToolCallArgumentsDeltaEvent(BaseModel): - type: Literal["tool_calls.function.arguments.delta"] - - name: str - - index: int - - arguments: str - """Accumulated raw JSON string""" - - parsed_arguments: object - """The parsed arguments so far""" - - arguments_delta: str - """The JSON string delta""" - - -class FunctionToolCallArgumentsDoneEvent(BaseModel): - type: Literal["tool_calls.function.arguments.done"] - - name: str - - index: int - - arguments: str - """Accumulated raw JSON string""" - - parsed_arguments: object - """The parsed arguments""" - - -class LogprobsContentDeltaEvent(BaseModel): - type: Literal["logprobs.content.delta"] - - content: List[ChatCompletionTokenLogprob] - - snapshot: List[ChatCompletionTokenLogprob] - - -class LogprobsContentDoneEvent(BaseModel): - type: Literal["logprobs.content.done"] - - content: List[ChatCompletionTokenLogprob] - - -class LogprobsRefusalDeltaEvent(BaseModel): - type: Literal["logprobs.refusal.delta"] - - refusal: List[ChatCompletionTokenLogprob] - - snapshot: List[ChatCompletionTokenLogprob] - - -class LogprobsRefusalDoneEvent(BaseModel): - type: Literal["logprobs.refusal.done"] - - refusal: List[ChatCompletionTokenLogprob] - - -ChatCompletionStreamEvent = Union[ - ChunkEvent, - ContentDeltaEvent, - ContentDoneEvent[ResponseFormatT], - RefusalDeltaEvent, - RefusalDoneEvent, - FunctionToolCallArgumentsDeltaEvent, - FunctionToolCallArgumentsDoneEvent, - LogprobsContentDeltaEvent, - LogprobsContentDoneEvent, - LogprobsRefusalDeltaEvent, - LogprobsRefusalDoneEvent, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_types.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_types.py deleted file mode 100644 index 4255289..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/chat/_types.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -from typing_extensions import TypeAlias - -from ....types.chat import ParsedChoice, ParsedChatCompletion, ParsedChatCompletionMessage - -ParsedChatCompletionSnapshot: TypeAlias = ParsedChatCompletion[object] -"""Snapshot type representing an in-progress accumulation of -a `ParsedChatCompletion` object. -""" - -ParsedChatCompletionMessageSnapshot: TypeAlias = ParsedChatCompletionMessage[object] -"""Snapshot type representing an in-progress accumulation of -a `ParsedChatCompletionMessage` object. - -If the content has been fully accumulated, the `.parsed` content will be -the `response_format` instance, otherwise it'll be the raw JSON parsed version. -""" - -ParsedChoiceSnapshot: TypeAlias = ParsedChoice[object] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/__init__.py deleted file mode 100644 index ff07363..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from ._events import ( - ResponseTextDoneEvent as ResponseTextDoneEvent, - ResponseTextDeltaEvent as ResponseTextDeltaEvent, - ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, -) -from ._responses import ( - ResponseStream as ResponseStream, - AsyncResponseStream as AsyncResponseStream, - ResponseStreamEvent as ResponseStreamEvent, - ResponseStreamState as ResponseStreamState, - ResponseStreamManager as ResponseStreamManager, - AsyncResponseStreamManager as AsyncResponseStreamManager, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_events.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_events.py deleted file mode 100644 index bdc47b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_events.py +++ /dev/null @@ -1,148 +0,0 @@ -from __future__ import annotations - -from typing import Optional -from typing_extensions import Union, Generic, TypeVar, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._compat import GenericModel -from ....types.responses import ( - ParsedResponse, - ResponseErrorEvent, - ResponseFailedEvent, - ResponseQueuedEvent, - ResponseCreatedEvent, - ResponseTextDoneEvent as RawResponseTextDoneEvent, - ResponseAudioDoneEvent, - ResponseCompletedEvent as RawResponseCompletedEvent, - ResponseTextDeltaEvent as RawResponseTextDeltaEvent, - ResponseAudioDeltaEvent, - ResponseIncompleteEvent, - ResponseInProgressEvent, - ResponseRefusalDoneEvent, - ResponseRefusalDeltaEvent, - ResponseMcpCallFailedEvent, - ResponseOutputItemDoneEvent, - ResponseContentPartDoneEvent, - ResponseOutputItemAddedEvent, - ResponseContentPartAddedEvent, - ResponseMcpCallCompletedEvent, - ResponseMcpCallInProgressEvent, - ResponseMcpListToolsFailedEvent, - ResponseAudioTranscriptDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseMcpCallArgumentsDoneEvent, - ResponseImageGenCallCompletedEvent, - ResponseMcpCallArgumentsDeltaEvent, - ResponseMcpListToolsCompletedEvent, - ResponseImageGenCallGeneratingEvent, - ResponseImageGenCallInProgressEvent, - ResponseMcpListToolsInProgressEvent, - ResponseWebSearchCallCompletedEvent, - ResponseWebSearchCallSearchingEvent, - ResponseCustomToolCallInputDoneEvent, - ResponseFileSearchCallCompletedEvent, - ResponseFileSearchCallSearchingEvent, - ResponseWebSearchCallInProgressEvent, - ResponseCustomToolCallInputDeltaEvent, - ResponseFileSearchCallInProgressEvent, - ResponseImageGenCallPartialImageEvent, - ResponseReasoningSummaryPartDoneEvent, - ResponseReasoningSummaryTextDoneEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseOutputTextAnnotationAddedEvent, - ResponseReasoningSummaryPartAddedEvent, - ResponseReasoningSummaryTextDeltaEvent, - ResponseFunctionCallArgumentsDeltaEvent as RawResponseFunctionCallArgumentsDeltaEvent, - ResponseCodeInterpreterCallCodeDoneEvent, - ResponseCodeInterpreterCallCodeDeltaEvent, - ResponseCodeInterpreterCallCompletedEvent, - ResponseCodeInterpreterCallInProgressEvent, - ResponseCodeInterpreterCallInterpretingEvent, -) -from ....types.responses.response_reasoning_text_done_event import ResponseReasoningTextDoneEvent -from ....types.responses.response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent - -TextFormatT = TypeVar( - "TextFormatT", - # if it isn't given then we don't do any parsing - default=None, -) - - -class ResponseTextDeltaEvent(RawResponseTextDeltaEvent): - snapshot: str - - -class ResponseTextDoneEvent(RawResponseTextDoneEvent, GenericModel, Generic[TextFormatT]): - parsed: Optional[TextFormatT] = None - - -class ResponseFunctionCallArgumentsDeltaEvent(RawResponseFunctionCallArgumentsDeltaEvent): - snapshot: str - - -class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[TextFormatT]): - response: ParsedResponse[TextFormatT] # type: ignore[assignment] - - -ResponseStreamEvent: TypeAlias = Annotated[ - Union[ - # wrappers with snapshots added on - ResponseTextDeltaEvent, - ResponseTextDoneEvent[TextFormatT], - ResponseFunctionCallArgumentsDeltaEvent, - ResponseCompletedEvent[TextFormatT], - # the same as the non-accumulated API - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCodeInterpreterCallCodeDeltaEvent, - ResponseCodeInterpreterCallCodeDoneEvent, - ResponseCodeInterpreterCallCompletedEvent, - ResponseCodeInterpreterCallInProgressEvent, - ResponseCodeInterpreterCallInterpretingEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreatedEvent, - ResponseErrorEvent, - ResponseFileSearchCallCompletedEvent, - ResponseFileSearchCallInProgressEvent, - ResponseFileSearchCallSearchingEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseInProgressEvent, - ResponseFailedEvent, - ResponseIncompleteEvent, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseRefusalDeltaEvent, - ResponseRefusalDoneEvent, - ResponseTextDoneEvent, - ResponseWebSearchCallCompletedEvent, - ResponseWebSearchCallInProgressEvent, - ResponseWebSearchCallSearchingEvent, - ResponseReasoningSummaryPartAddedEvent, - ResponseReasoningSummaryPartDoneEvent, - ResponseReasoningSummaryTextDeltaEvent, - ResponseReasoningSummaryTextDoneEvent, - ResponseImageGenCallCompletedEvent, - ResponseImageGenCallInProgressEvent, - ResponseImageGenCallGeneratingEvent, - ResponseImageGenCallPartialImageEvent, - ResponseMcpCallCompletedEvent, - ResponseMcpCallArgumentsDeltaEvent, - ResponseMcpCallArgumentsDoneEvent, - ResponseMcpCallFailedEvent, - ResponseMcpCallInProgressEvent, - ResponseMcpListToolsCompletedEvent, - ResponseMcpListToolsFailedEvent, - ResponseMcpListToolsInProgressEvent, - ResponseOutputTextAnnotationAddedEvent, - ResponseQueuedEvent, - ResponseReasoningTextDeltaEvent, - ResponseReasoningTextDoneEvent, - ResponseCustomToolCallInputDeltaEvent, - ResponseCustomToolCallInputDoneEvent, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_responses.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_responses.py deleted file mode 100644 index 6975a92..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_responses.py +++ /dev/null @@ -1,372 +0,0 @@ -from __future__ import annotations - -import inspect -from types import TracebackType -from typing import Any, List, Generic, Iterable, Awaitable, cast -from typing_extensions import Self, Callable, Iterator, AsyncIterator - -from ._types import ParsedResponseSnapshot -from ._events import ( - ResponseStreamEvent, - ResponseTextDoneEvent, - ResponseCompletedEvent, - ResponseTextDeltaEvent, - ResponseFunctionCallArgumentsDeltaEvent, -) -from ...._types import Omit, omit -from ...._utils import is_given, consume_sync_iterator, consume_async_iterator -from ...._models import build, construct_type_unchecked -from ...._streaming import Stream, AsyncStream -from ....types.responses import ParsedResponse, ResponseStreamEvent as RawResponseStreamEvent -from ..._parsing._responses import TextFormatT, parse_text, parse_response -from ....types.responses.tool_param import ToolParam -from ....types.responses.parsed_response import ( - ParsedContent, - ParsedResponseOutputMessage, - ParsedResponseFunctionToolCall, -) - - -class ResponseStream(Generic[TextFormatT]): - def __init__( - self, - *, - raw_stream: Stream[RawResponseStreamEvent], - text_format: type[TextFormatT] | Omit, - input_tools: Iterable[ToolParam] | Omit, - starting_after: int | None, - ) -> None: - self._raw_stream = raw_stream - self._response = raw_stream.response - self._iterator = self.__stream__() - self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) - self._starting_after = starting_after - - def __next__(self) -> ResponseStreamEvent[TextFormatT]: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[ResponseStreamEvent[TextFormatT]]: - for item in self._iterator: - yield item - - def __enter__(self) -> Self: - return self - - def __stream__(self) -> Iterator[ResponseStreamEvent[TextFormatT]]: - for sse_event in self._raw_stream: - events_to_fire = self._state.handle_event(sse_event) - for event in events_to_fire: - if self._starting_after is None or event.sequence_number > self._starting_after: - yield event - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self._response.close() - - def get_final_response(self) -> ParsedResponse[TextFormatT]: - """Waits until the stream has been read to completion and returns - the accumulated `ParsedResponse` object. - """ - self.until_done() - response = self._state._completed_response - if not response: - raise RuntimeError("Didn't receive a `response.completed` event.") - - return response - - def until_done(self) -> Self: - """Blocks until the stream has been consumed.""" - consume_sync_iterator(self) - return self - - -class ResponseStreamManager(Generic[TextFormatT]): - def __init__( - self, - api_request: Callable[[], Stream[RawResponseStreamEvent]], - *, - text_format: type[TextFormatT] | Omit, - input_tools: Iterable[ToolParam] | Omit, - starting_after: int | None, - ) -> None: - self.__stream: ResponseStream[TextFormatT] | None = None - self.__api_request = api_request - self.__text_format = text_format - self.__input_tools = input_tools - self.__starting_after = starting_after - - def __enter__(self) -> ResponseStream[TextFormatT]: - raw_stream = self.__api_request() - - self.__stream = ResponseStream( - raw_stream=raw_stream, - text_format=self.__text_format, - input_tools=self.__input_tools, - starting_after=self.__starting_after, - ) - - return self.__stream - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - self.__stream.close() - - -class AsyncResponseStream(Generic[TextFormatT]): - def __init__( - self, - *, - raw_stream: AsyncStream[RawResponseStreamEvent], - text_format: type[TextFormatT] | Omit, - input_tools: Iterable[ToolParam] | Omit, - starting_after: int | None, - ) -> None: - self._raw_stream = raw_stream - self._response = raw_stream.response - self._iterator = self.__stream__() - self._state = ResponseStreamState(text_format=text_format, input_tools=input_tools) - self._starting_after = starting_after - - async def __anext__(self) -> ResponseStreamEvent[TextFormatT]: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[ResponseStreamEvent[TextFormatT]]: - async for item in self._iterator: - yield item - - async def __stream__(self) -> AsyncIterator[ResponseStreamEvent[TextFormatT]]: - async for sse_event in self._raw_stream: - events_to_fire = self._state.handle_event(sse_event) - for event in events_to_fire: - if self._starting_after is None or event.sequence_number > self._starting_after: - yield event - - async def __aenter__(self) -> Self: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self._response.aclose() - - async def get_final_response(self) -> ParsedResponse[TextFormatT]: - """Waits until the stream has been read to completion and returns - the accumulated `ParsedResponse` object. - """ - await self.until_done() - response = self._state._completed_response - if not response: - raise RuntimeError("Didn't receive a `response.completed` event.") - - return response - - async def until_done(self) -> Self: - """Blocks until the stream has been consumed.""" - await consume_async_iterator(self) - return self - - -class AsyncResponseStreamManager(Generic[TextFormatT]): - def __init__( - self, - api_request: Awaitable[AsyncStream[RawResponseStreamEvent]], - *, - text_format: type[TextFormatT] | Omit, - input_tools: Iterable[ToolParam] | Omit, - starting_after: int | None, - ) -> None: - self.__stream: AsyncResponseStream[TextFormatT] | None = None - self.__api_request = api_request - self.__text_format = text_format - self.__input_tools = input_tools - self.__starting_after = starting_after - - async def __aenter__(self) -> AsyncResponseStream[TextFormatT]: - raw_stream = await self.__api_request - - self.__stream = AsyncResponseStream( - raw_stream=raw_stream, - text_format=self.__text_format, - input_tools=self.__input_tools, - starting_after=self.__starting_after, - ) - - return self.__stream - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__stream is not None: - await self.__stream.close() - - -class ResponseStreamState(Generic[TextFormatT]): - def __init__( - self, - *, - input_tools: Iterable[ToolParam] | Omit, - text_format: type[TextFormatT] | Omit, - ) -> None: - self.__current_snapshot: ParsedResponseSnapshot | None = None - self._completed_response: ParsedResponse[TextFormatT] | None = None - self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] - self._text_format = text_format - self._rich_text_format: type | Omit = text_format if inspect.isclass(text_format) else omit - - def handle_event(self, event: RawResponseStreamEvent) -> List[ResponseStreamEvent[TextFormatT]]: - self.__current_snapshot = snapshot = self.accumulate_event(event) - - events: List[ResponseStreamEvent[TextFormatT]] = [] - - if event.type == "response.output_text.delta": - output = snapshot.output[event.output_index] - assert output.type == "message" - - content = output.content[event.content_index] - assert content.type == "output_text" - - events.append( - build( - ResponseTextDeltaEvent, - content_index=event.content_index, - delta=event.delta, - item_id=event.item_id, - output_index=event.output_index, - sequence_number=event.sequence_number, - logprobs=event.logprobs, - type="response.output_text.delta", - snapshot=content.text, - ) - ) - elif event.type == "response.output_text.done": - output = snapshot.output[event.output_index] - assert output.type == "message" - - content = output.content[event.content_index] - assert content.type == "output_text" - - events.append( - build( - ResponseTextDoneEvent[TextFormatT], - content_index=event.content_index, - item_id=event.item_id, - output_index=event.output_index, - sequence_number=event.sequence_number, - logprobs=event.logprobs, - type="response.output_text.done", - text=event.text, - parsed=parse_text(event.text, text_format=self._text_format), - ) - ) - elif event.type == "response.function_call_arguments.delta": - output = snapshot.output[event.output_index] - assert output.type == "function_call" - - events.append( - build( - ResponseFunctionCallArgumentsDeltaEvent, - delta=event.delta, - item_id=event.item_id, - output_index=event.output_index, - sequence_number=event.sequence_number, - type="response.function_call_arguments.delta", - snapshot=output.arguments, - ) - ) - - elif event.type == "response.completed": - response = self._completed_response - assert response is not None - - events.append( - build( - ResponseCompletedEvent, - sequence_number=event.sequence_number, - type="response.completed", - response=response, - ) - ) - else: - events.append(event) - - return events - - def accumulate_event(self, event: RawResponseStreamEvent) -> ParsedResponseSnapshot: - snapshot = self.__current_snapshot - if snapshot is None: - return self._create_initial_response(event) - - if event.type == "response.output_item.added": - if event.item.type == "function_call": - snapshot.output.append( - construct_type_unchecked( - type_=cast(Any, ParsedResponseFunctionToolCall), value=event.item.to_dict() - ) - ) - elif event.item.type == "message": - snapshot.output.append( - construct_type_unchecked(type_=cast(Any, ParsedResponseOutputMessage), value=event.item.to_dict()) - ) - else: - snapshot.output.append(event.item) - elif event.type == "response.content_part.added": - output = snapshot.output[event.output_index] - if output.type == "message": - output.content.append( - construct_type_unchecked(type_=cast(Any, ParsedContent), value=event.part.to_dict()) - ) - elif event.type == "response.output_text.delta": - output = snapshot.output[event.output_index] - if output.type == "message": - content = output.content[event.content_index] - assert content.type == "output_text" - content.text += event.delta - elif event.type == "response.function_call_arguments.delta": - output = snapshot.output[event.output_index] - if output.type == "function_call": - output.arguments += event.delta - elif event.type == "response.completed": - self._completed_response = parse_response( - text_format=self._text_format, - response=event.response, - input_tools=self._input_tools, - ) - - return snapshot - - def _create_initial_response(self, event: RawResponseStreamEvent) -> ParsedResponseSnapshot: - if event.type != "response.created": - raise RuntimeError(f"Expected to have received `response.created` before `{event.type}`") - - return construct_type_unchecked(type_=ParsedResponseSnapshot, value=event.response.to_dict()) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_types.py b/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_types.py deleted file mode 100644 index 6d3fd90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/lib/streaming/responses/_types.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import annotations - -from typing_extensions import TypeAlias - -from ....types.responses import ParsedResponse - -ParsedResponseSnapshot: TypeAlias = ParsedResponse[object] -"""Snapshot type representing an in-progress accumulation of -a `ParsedResponse` object. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/pagination.py b/backend/venv39/lib/python3.9/site-packages/openai/pagination.py deleted file mode 100644 index 4dd3788..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/pagination.py +++ /dev/null @@ -1,190 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Any, List, Generic, TypeVar, Optional, cast -from typing_extensions import Protocol, override, runtime_checkable - -from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage - -__all__ = [ - "SyncPage", - "AsyncPage", - "SyncCursorPage", - "AsyncCursorPage", - "SyncConversationCursorPage", - "AsyncConversationCursorPage", -] - -_T = TypeVar("_T") - - -@runtime_checkable -class CursorPageItem(Protocol): - id: Optional[str] - - -class SyncPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - """Note: no pagination actually occurs yet, this is for forwards-compatibility.""" - - data: List[_T] - object: str - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def next_page_info(self) -> None: - """ - This page represents a response that isn't actually paginated at the API level - so there will never be a next page. - """ - return None - - -class AsyncPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - """Note: no pagination actually occurs yet, this is for forwards-compatibility.""" - - data: List[_T] - object: str - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def next_page_info(self) -> None: - """ - This page represents a response that isn't actually paginated at the API level - so there will never be a next page. - """ - return None - - -class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - data: List[_T] - has_more: Optional[bool] = None - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - has_more = self.has_more - if has_more is not None and has_more is False: - return False - - return super().has_next_page() - - @override - def next_page_info(self) -> Optional[PageInfo]: - data = self.data - if not data: - return None - - item = cast(Any, data[-1]) - if not isinstance(item, CursorPageItem) or item.id is None: - # TODO emit warning log - return None - - return PageInfo(params={"after": item.id}) - - -class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - data: List[_T] - has_more: Optional[bool] = None - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - has_more = self.has_more - if has_more is not None and has_more is False: - return False - - return super().has_next_page() - - @override - def next_page_info(self) -> Optional[PageInfo]: - data = self.data - if not data: - return None - - item = cast(Any, data[-1]) - if not isinstance(item, CursorPageItem) or item.id is None: - # TODO emit warning log - return None - - return PageInfo(params={"after": item.id}) - - -class SyncConversationCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - data: List[_T] - has_more: Optional[bool] = None - last_id: Optional[str] = None - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - has_more = self.has_more - if has_more is not None and has_more is False: - return False - - return super().has_next_page() - - @override - def next_page_info(self) -> Optional[PageInfo]: - last_id = self.last_id - if not last_id: - return None - - return PageInfo(params={"after": last_id}) - - -class AsyncConversationCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - data: List[_T] - has_more: Optional[bool] = None - last_id: Optional[str] = None - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - has_more = self.has_more - if has_more is not None and has_more is False: - return False - - return super().has_next_page() - - @override - def next_page_info(self) -> Optional[PageInfo]: - last_id = self.last_id - if not last_id: - return None - - return PageInfo(params={"after": last_id}) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/py.typed b/backend/venv39/lib/python3.9/site-packages/openai/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/__init__.py deleted file mode 100644 index b793fbc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/__init__.py +++ /dev/null @@ -1,229 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .beta import ( - Beta, - AsyncBeta, - BetaWithRawResponse, - AsyncBetaWithRawResponse, - BetaWithStreamingResponse, - AsyncBetaWithStreamingResponse, -) -from .chat import ( - Chat, - AsyncChat, - ChatWithRawResponse, - AsyncChatWithRawResponse, - ChatWithStreamingResponse, - AsyncChatWithStreamingResponse, -) -from .audio import ( - Audio, - AsyncAudio, - AudioWithRawResponse, - AsyncAudioWithRawResponse, - AudioWithStreamingResponse, - AsyncAudioWithStreamingResponse, -) -from .evals import ( - Evals, - AsyncEvals, - EvalsWithRawResponse, - AsyncEvalsWithRawResponse, - EvalsWithStreamingResponse, - AsyncEvalsWithStreamingResponse, -) -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .images import ( - Images, - AsyncImages, - ImagesWithRawResponse, - AsyncImagesWithRawResponse, - ImagesWithStreamingResponse, - AsyncImagesWithStreamingResponse, -) -from .models import ( - Models, - AsyncModels, - ModelsWithRawResponse, - AsyncModelsWithRawResponse, - ModelsWithStreamingResponse, - AsyncModelsWithStreamingResponse, -) -from .videos import ( - Videos, - AsyncVideos, - VideosWithRawResponse, - AsyncVideosWithRawResponse, - VideosWithStreamingResponse, - AsyncVideosWithStreamingResponse, -) -from .batches import ( - Batches, - AsyncBatches, - BatchesWithRawResponse, - AsyncBatchesWithRawResponse, - BatchesWithStreamingResponse, - AsyncBatchesWithStreamingResponse, -) -from .uploads import ( - Uploads, - AsyncUploads, - UploadsWithRawResponse, - AsyncUploadsWithRawResponse, - UploadsWithStreamingResponse, - AsyncUploadsWithStreamingResponse, -) -from .containers import ( - Containers, - AsyncContainers, - ContainersWithRawResponse, - AsyncContainersWithRawResponse, - ContainersWithStreamingResponse, - AsyncContainersWithStreamingResponse, -) -from .embeddings import ( - Embeddings, - AsyncEmbeddings, - EmbeddingsWithRawResponse, - AsyncEmbeddingsWithRawResponse, - EmbeddingsWithStreamingResponse, - AsyncEmbeddingsWithStreamingResponse, -) -from .completions import ( - Completions, - AsyncCompletions, - CompletionsWithRawResponse, - AsyncCompletionsWithRawResponse, - CompletionsWithStreamingResponse, - AsyncCompletionsWithStreamingResponse, -) -from .fine_tuning import ( - FineTuning, - AsyncFineTuning, - FineTuningWithRawResponse, - AsyncFineTuningWithRawResponse, - FineTuningWithStreamingResponse, - AsyncFineTuningWithStreamingResponse, -) -from .moderations import ( - Moderations, - AsyncModerations, - ModerationsWithRawResponse, - AsyncModerationsWithRawResponse, - ModerationsWithStreamingResponse, - AsyncModerationsWithStreamingResponse, -) -from .vector_stores import ( - VectorStores, - AsyncVectorStores, - VectorStoresWithRawResponse, - AsyncVectorStoresWithRawResponse, - VectorStoresWithStreamingResponse, - AsyncVectorStoresWithStreamingResponse, -) - -__all__ = [ - "Completions", - "AsyncCompletions", - "CompletionsWithRawResponse", - "AsyncCompletionsWithRawResponse", - "CompletionsWithStreamingResponse", - "AsyncCompletionsWithStreamingResponse", - "Chat", - "AsyncChat", - "ChatWithRawResponse", - "AsyncChatWithRawResponse", - "ChatWithStreamingResponse", - "AsyncChatWithStreamingResponse", - "Embeddings", - "AsyncEmbeddings", - "EmbeddingsWithRawResponse", - "AsyncEmbeddingsWithRawResponse", - "EmbeddingsWithStreamingResponse", - "AsyncEmbeddingsWithStreamingResponse", - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", - "Images", - "AsyncImages", - "ImagesWithRawResponse", - "AsyncImagesWithRawResponse", - "ImagesWithStreamingResponse", - "AsyncImagesWithStreamingResponse", - "Audio", - "AsyncAudio", - "AudioWithRawResponse", - "AsyncAudioWithRawResponse", - "AudioWithStreamingResponse", - "AsyncAudioWithStreamingResponse", - "Moderations", - "AsyncModerations", - "ModerationsWithRawResponse", - "AsyncModerationsWithRawResponse", - "ModerationsWithStreamingResponse", - "AsyncModerationsWithStreamingResponse", - "Models", - "AsyncModels", - "ModelsWithRawResponse", - "AsyncModelsWithRawResponse", - "ModelsWithStreamingResponse", - "AsyncModelsWithStreamingResponse", - "FineTuning", - "AsyncFineTuning", - "FineTuningWithRawResponse", - "AsyncFineTuningWithRawResponse", - "FineTuningWithStreamingResponse", - "AsyncFineTuningWithStreamingResponse", - "VectorStores", - "AsyncVectorStores", - "VectorStoresWithRawResponse", - "AsyncVectorStoresWithRawResponse", - "VectorStoresWithStreamingResponse", - "AsyncVectorStoresWithStreamingResponse", - "Beta", - "AsyncBeta", - "BetaWithRawResponse", - "AsyncBetaWithRawResponse", - "BetaWithStreamingResponse", - "AsyncBetaWithStreamingResponse", - "Batches", - "AsyncBatches", - "BatchesWithRawResponse", - "AsyncBatchesWithRawResponse", - "BatchesWithStreamingResponse", - "AsyncBatchesWithStreamingResponse", - "Uploads", - "AsyncUploads", - "UploadsWithRawResponse", - "AsyncUploadsWithRawResponse", - "UploadsWithStreamingResponse", - "AsyncUploadsWithStreamingResponse", - "Evals", - "AsyncEvals", - "EvalsWithRawResponse", - "AsyncEvalsWithRawResponse", - "EvalsWithStreamingResponse", - "AsyncEvalsWithStreamingResponse", - "Containers", - "AsyncContainers", - "ContainersWithRawResponse", - "AsyncContainersWithRawResponse", - "ContainersWithStreamingResponse", - "AsyncContainersWithStreamingResponse", - "Videos", - "AsyncVideos", - "VideosWithRawResponse", - "AsyncVideosWithRawResponse", - "VideosWithStreamingResponse", - "AsyncVideosWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/__init__.py deleted file mode 100644 index 7da1d2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .audio import ( - Audio, - AsyncAudio, - AudioWithRawResponse, - AsyncAudioWithRawResponse, - AudioWithStreamingResponse, - AsyncAudioWithStreamingResponse, -) -from .speech import ( - Speech, - AsyncSpeech, - SpeechWithRawResponse, - AsyncSpeechWithRawResponse, - SpeechWithStreamingResponse, - AsyncSpeechWithStreamingResponse, -) -from .translations import ( - Translations, - AsyncTranslations, - TranslationsWithRawResponse, - AsyncTranslationsWithRawResponse, - TranslationsWithStreamingResponse, - AsyncTranslationsWithStreamingResponse, -) -from .transcriptions import ( - Transcriptions, - AsyncTranscriptions, - TranscriptionsWithRawResponse, - AsyncTranscriptionsWithRawResponse, - TranscriptionsWithStreamingResponse, - AsyncTranscriptionsWithStreamingResponse, -) - -__all__ = [ - "Transcriptions", - "AsyncTranscriptions", - "TranscriptionsWithRawResponse", - "AsyncTranscriptionsWithRawResponse", - "TranscriptionsWithStreamingResponse", - "AsyncTranscriptionsWithStreamingResponse", - "Translations", - "AsyncTranslations", - "TranslationsWithRawResponse", - "AsyncTranslationsWithRawResponse", - "TranslationsWithStreamingResponse", - "AsyncTranslationsWithStreamingResponse", - "Speech", - "AsyncSpeech", - "SpeechWithRawResponse", - "AsyncSpeechWithRawResponse", - "SpeechWithStreamingResponse", - "AsyncSpeechWithStreamingResponse", - "Audio", - "AsyncAudio", - "AudioWithRawResponse", - "AsyncAudioWithRawResponse", - "AudioWithStreamingResponse", - "AsyncAudioWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/audio.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/audio.py deleted file mode 100644 index 383b707..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/audio.py +++ /dev/null @@ -1,166 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .speech import ( - Speech, - AsyncSpeech, - SpeechWithRawResponse, - AsyncSpeechWithRawResponse, - SpeechWithStreamingResponse, - AsyncSpeechWithStreamingResponse, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from .translations import ( - Translations, - AsyncTranslations, - TranslationsWithRawResponse, - AsyncTranslationsWithRawResponse, - TranslationsWithStreamingResponse, - AsyncTranslationsWithStreamingResponse, -) -from .transcriptions import ( - Transcriptions, - AsyncTranscriptions, - TranscriptionsWithRawResponse, - AsyncTranscriptionsWithRawResponse, - TranscriptionsWithStreamingResponse, - AsyncTranscriptionsWithStreamingResponse, -) - -__all__ = ["Audio", "AsyncAudio"] - - -class Audio(SyncAPIResource): - @cached_property - def transcriptions(self) -> Transcriptions: - return Transcriptions(self._client) - - @cached_property - def translations(self) -> Translations: - return Translations(self._client) - - @cached_property - def speech(self) -> Speech: - return Speech(self._client) - - @cached_property - def with_raw_response(self) -> AudioWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AudioWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AudioWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AudioWithStreamingResponse(self) - - -class AsyncAudio(AsyncAPIResource): - @cached_property - def transcriptions(self) -> AsyncTranscriptions: - return AsyncTranscriptions(self._client) - - @cached_property - def translations(self) -> AsyncTranslations: - return AsyncTranslations(self._client) - - @cached_property - def speech(self) -> AsyncSpeech: - return AsyncSpeech(self._client) - - @cached_property - def with_raw_response(self) -> AsyncAudioWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncAudioWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAudioWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncAudioWithStreamingResponse(self) - - -class AudioWithRawResponse: - def __init__(self, audio: Audio) -> None: - self._audio = audio - - @cached_property - def transcriptions(self) -> TranscriptionsWithRawResponse: - return TranscriptionsWithRawResponse(self._audio.transcriptions) - - @cached_property - def translations(self) -> TranslationsWithRawResponse: - return TranslationsWithRawResponse(self._audio.translations) - - @cached_property - def speech(self) -> SpeechWithRawResponse: - return SpeechWithRawResponse(self._audio.speech) - - -class AsyncAudioWithRawResponse: - def __init__(self, audio: AsyncAudio) -> None: - self._audio = audio - - @cached_property - def transcriptions(self) -> AsyncTranscriptionsWithRawResponse: - return AsyncTranscriptionsWithRawResponse(self._audio.transcriptions) - - @cached_property - def translations(self) -> AsyncTranslationsWithRawResponse: - return AsyncTranslationsWithRawResponse(self._audio.translations) - - @cached_property - def speech(self) -> AsyncSpeechWithRawResponse: - return AsyncSpeechWithRawResponse(self._audio.speech) - - -class AudioWithStreamingResponse: - def __init__(self, audio: Audio) -> None: - self._audio = audio - - @cached_property - def transcriptions(self) -> TranscriptionsWithStreamingResponse: - return TranscriptionsWithStreamingResponse(self._audio.transcriptions) - - @cached_property - def translations(self) -> TranslationsWithStreamingResponse: - return TranslationsWithStreamingResponse(self._audio.translations) - - @cached_property - def speech(self) -> SpeechWithStreamingResponse: - return SpeechWithStreamingResponse(self._audio.speech) - - -class AsyncAudioWithStreamingResponse: - def __init__(self, audio: AsyncAudio) -> None: - self._audio = audio - - @cached_property - def transcriptions(self) -> AsyncTranscriptionsWithStreamingResponse: - return AsyncTranscriptionsWithStreamingResponse(self._audio.transcriptions) - - @cached_property - def translations(self) -> AsyncTranslationsWithStreamingResponse: - return AsyncTranslationsWithStreamingResponse(self._audio.translations) - - @cached_property - def speech(self) -> AsyncSpeechWithStreamingResponse: - return AsyncSpeechWithStreamingResponse(self._audio.speech) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/speech.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/speech.py deleted file mode 100644 index f2c8d63..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/speech.py +++ /dev/null @@ -1,257 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_custom_streamed_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ...types.audio import speech_create_params -from ..._base_client import make_request_options -from ...types.audio.speech_model import SpeechModel - -__all__ = ["Speech", "AsyncSpeech"] - - -class Speech(SyncAPIResource): - @cached_property - def with_raw_response(self) -> SpeechWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return SpeechWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SpeechWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return SpeechWithStreamingResponse(self) - - def create( - self, - *, - input: str, - model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] - ], - instructions: str | Omit = omit, - response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, - speed: float | Omit = omit, - stream_format: Literal["sse", "audio"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Generates audio from the input text. - - Args: - input: The text to generate audio for. The maximum length is 4096 characters. - - model: - One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. - - voice: The voice to use when generating the audio. Supported built-in voices are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available - in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). - - instructions: Control the voice of your generated audio with additional instructions. Does not - work with `tts-1` or `tts-1-hd`. - - response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, - `wav`, and `pcm`. - - speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. - - stream_format: The format to stream the audio in. Supported formats are `sse` and `audio`. - `sse` is not supported for `tts-1` or `tts-1-hd`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} - return self._post( - "/audio/speech", - body=maybe_transform( - { - "input": input, - "model": model, - "voice": voice, - "instructions": instructions, - "response_format": response_format, - "speed": speed, - "stream_format": stream_format, - }, - speech_create_params.SpeechCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - -class AsyncSpeech(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncSpeechWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncSpeechWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSpeechWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncSpeechWithStreamingResponse(self) - - async def create( - self, - *, - input: str, - model: Union[str, SpeechModel], - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"] - ], - instructions: str | Omit = omit, - response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit, - speed: float | Omit = omit, - stream_format: Literal["sse", "audio"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Generates audio from the input text. - - Args: - input: The text to generate audio for. The maximum length is 4096 characters. - - model: - One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. - - voice: The voice to use when generating the audio. Supported built-in voices are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available - in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). - - instructions: Control the voice of your generated audio with additional instructions. Does not - work with `tts-1` or `tts-1-hd`. - - response_format: The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, - `wav`, and `pcm`. - - speed: The speed of the generated audio. Select a value from `0.25` to `4.0`. `1.0` is - the default. - - stream_format: The format to stream the audio in. Supported formats are `sse` and `audio`. - `sse` is not supported for `tts-1` or `tts-1-hd`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} - return await self._post( - "/audio/speech", - body=await async_maybe_transform( - { - "input": input, - "model": model, - "voice": voice, - "instructions": instructions, - "response_format": response_format, - "speed": speed, - "stream_format": stream_format, - }, - speech_create_params.SpeechCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - -class SpeechWithRawResponse: - def __init__(self, speech: Speech) -> None: - self._speech = speech - - self.create = _legacy_response.to_raw_response_wrapper( - speech.create, - ) - - -class AsyncSpeechWithRawResponse: - def __init__(self, speech: AsyncSpeech) -> None: - self._speech = speech - - self.create = _legacy_response.async_to_raw_response_wrapper( - speech.create, - ) - - -class SpeechWithStreamingResponse: - def __init__(self, speech: Speech) -> None: - self._speech = speech - - self.create = to_custom_streamed_response_wrapper( - speech.create, - StreamedBinaryAPIResponse, - ) - - -class AsyncSpeechWithStreamingResponse: - def __init__(self, speech: AsyncSpeech) -> None: - self._speech = speech - - self.create = async_to_custom_streamed_response_wrapper( - speech.create, - AsyncStreamedBinaryAPIResponse, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/transcriptions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/transcriptions.py deleted file mode 100644 index 5995348..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/transcriptions.py +++ /dev/null @@ -1,987 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import logging -from typing import TYPE_CHECKING, List, Union, Mapping, Optional, cast -from typing_extensions import Literal, overload, assert_never - -import httpx - -from ... import _legacy_response -from ..._types import ( - Body, - Omit, - Query, - Headers, - NotGiven, - FileTypes, - SequenceNotStr, - omit, - not_given, -) -from ..._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._streaming import Stream, AsyncStream -from ...types.audio import transcription_create_params -from ..._base_client import make_request_options -from ...types.audio_model import AudioModel -from ...types.audio.transcription import Transcription -from ...types.audio_response_format import AudioResponseFormat -from ...types.audio.transcription_include import TranscriptionInclude -from ...types.audio.transcription_verbose import TranscriptionVerbose -from ...types.audio.transcription_diarized import TranscriptionDiarized -from ...types.audio.transcription_stream_event import TranscriptionStreamEvent -from ...types.audio.transcription_create_response import TranscriptionCreateResponse - -__all__ = ["Transcriptions", "AsyncTranscriptions"] - -log: logging.Logger = logging.getLogger("openai.audio.transcriptions") - - -class Transcriptions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TranscriptionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return TranscriptionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TranscriptionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return TranscriptionsWithStreamingResponse(self) - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[Literal["json"], Omit] = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Transcription: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, - the only supported format is `json`. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - """ - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - response_format: Literal["verbose_json"], - language: str | Omit = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionVerbose: ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - response_format: Literal["text", "srt", "vtt"], - include: List[TranscriptionInclude] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - response_format: Literal["diarized_json"], - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionDiarized: ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - stream: Literal[True], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[TranscriptionStreamEvent]: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 - seconds. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - stream: bool, - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionCreateResponse | Stream[TranscriptionStreamEvent]: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 - seconds. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["file", "model"], ["file", "model", "stream"]) - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str | Transcription | TranscriptionDiarized | TranscriptionVerbose | Stream[TranscriptionStreamEvent]: - body = deepcopy_minimal( - { - "file": file, - "model": model, - "chunking_strategy": chunking_strategy, - "include": include, - "known_speaker_names": known_speaker_names, - "known_speaker_references": known_speaker_references, - "language": language, - "prompt": prompt, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "timestamp_granularities": timestamp_granularities, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( # type: ignore[return-value] - "/audio/transcriptions", - body=maybe_transform( - body, - transcription_create_params.TranscriptionCreateParamsStreaming - if stream - else transcription_create_params.TranscriptionCreateParamsNonStreaming, - ), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_get_response_format_type(response_format), - stream=stream or False, - stream_cls=Stream[TranscriptionStreamEvent], - ) - - -class AsyncTranscriptions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTranscriptionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncTranscriptionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTranscriptionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncTranscriptionsWithStreamingResponse(self) - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[Literal["json"], Omit] = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionCreateResponse: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 - seconds. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - """ - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - response_format: Literal["verbose_json"], - language: str | Omit = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionVerbose: ... - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - response_format: Literal["text", "srt", "vtt"], - language: str | Omit = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: ... - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - stream: Literal[True], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[TranscriptionStreamEvent]: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 - seconds. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - stream: bool, - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranscriptionCreateResponse | AsyncStream[TranscriptionStreamEvent]: - """ - Transcribes audio into the input language. - - Args: - file: - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. The options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` - (which is powered by our open source Whisper V2 model), and - `gpt-4o-transcribe-diarize`. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - - chunking_strategy: Controls how the audio is cut into chunks. When set to `"auto"`, the server - first normalizes loudness and then uses voice activity detection (VAD) to choose - boundaries. `server_vad` object can be provided to tweak VAD detection - parameters manually. If unset, the audio is transcribed as a single block. - Required when using `gpt-4o-transcribe-diarize` for inputs longer than 30 - seconds. - - include: Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - - known_speaker_names: Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - - known_speaker_references: Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - - language: The language of the input audio. Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - timestamp_granularities: The timestamp granularities to populate for this transcription. - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["file", "model"], ["file", "model", "stream"]) - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - chunking_strategy: Optional[transcription_create_params.ChunkingStrategy] | Omit = omit, - include: List[TranscriptionInclude] | Omit = omit, - known_speaker_names: SequenceNotStr[str] | Omit = omit, - known_speaker_references: SequenceNotStr[str] | Omit = omit, - language: str | Omit = omit, - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: float | Omit = omit, - timestamp_granularities: List[Literal["word", "segment"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Transcription | TranscriptionVerbose | TranscriptionDiarized | str | AsyncStream[TranscriptionStreamEvent]: - body = deepcopy_minimal( - { - "file": file, - "model": model, - "chunking_strategy": chunking_strategy, - "include": include, - "known_speaker_names": known_speaker_names, - "known_speaker_references": known_speaker_references, - "language": language, - "prompt": prompt, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "timestamp_granularities": timestamp_granularities, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/audio/transcriptions", - body=await async_maybe_transform( - body, - transcription_create_params.TranscriptionCreateParamsStreaming - if stream - else transcription_create_params.TranscriptionCreateParamsNonStreaming, - ), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_get_response_format_type(response_format), - stream=stream or False, - stream_cls=AsyncStream[TranscriptionStreamEvent], - ) - - -class TranscriptionsWithRawResponse: - def __init__(self, transcriptions: Transcriptions) -> None: - self._transcriptions = transcriptions - - self.create = _legacy_response.to_raw_response_wrapper( - transcriptions.create, - ) - - -class AsyncTranscriptionsWithRawResponse: - def __init__(self, transcriptions: AsyncTranscriptions) -> None: - self._transcriptions = transcriptions - - self.create = _legacy_response.async_to_raw_response_wrapper( - transcriptions.create, - ) - - -class TranscriptionsWithStreamingResponse: - def __init__(self, transcriptions: Transcriptions) -> None: - self._transcriptions = transcriptions - - self.create = to_streamed_response_wrapper( - transcriptions.create, - ) - - -class AsyncTranscriptionsWithStreamingResponse: - def __init__(self, transcriptions: AsyncTranscriptions) -> None: - self._transcriptions = transcriptions - - self.create = async_to_streamed_response_wrapper( - transcriptions.create, - ) - - -def _get_response_format_type( - response_format: AudioResponseFormat | Omit, -) -> type[Transcription | TranscriptionVerbose | TranscriptionDiarized | str]: - if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] - return Transcription - - if response_format == "json": - return Transcription - elif response_format == "verbose_json": - return TranscriptionVerbose - elif response_format == "diarized_json": - return TranscriptionDiarized - elif response_format == "srt" or response_format == "text" or response_format == "vtt": - return str - elif TYPE_CHECKING: # type: ignore[unreachable] - assert_never(response_format) - else: - log.warn("Unexpected audio response format: %s", response_format) - return Transcription diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/translations.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/translations.py deleted file mode 100644 index 310f901..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/audio/translations.py +++ /dev/null @@ -1,367 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import logging -from typing import TYPE_CHECKING, Union, Mapping, cast -from typing_extensions import Literal, overload, assert_never - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...types.audio import translation_create_params -from ..._base_client import make_request_options -from ...types.audio_model import AudioModel -from ...types.audio.translation import Translation -from ...types.audio_response_format import AudioResponseFormat -from ...types.audio.translation_verbose import TranslationVerbose - -__all__ = ["Translations", "AsyncTranslations"] - -log: logging.Logger = logging.getLogger("openai.audio.transcriptions") - - -class Translations(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TranslationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return TranslationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TranslationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return TranslationsWithStreamingResponse(self) - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Union[Literal["json"], Omit] = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Translation: ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Literal["verbose_json"], - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranslationVerbose: ... - - @overload - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Literal["text", "srt", "vtt"], - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: ... - - def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - prompt: str | Omit = omit, - response_format: Union[Literal["json", "text", "srt", "verbose_json", "vtt"], Omit] = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Translation | TranslationVerbose | str: - """ - Translates audio into English. - - Args: - file: The audio file object (not file name) translate, in one of these formats: flac, - mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. Only `whisper-1` (which is powered by our open source - Whisper V2 model) is currently available. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should be in English. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "file": file, - "model": model, - "prompt": prompt, - "response_format": response_format, - "temperature": temperature, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( # type: ignore[return-value] - "/audio/translations", - body=maybe_transform(body, translation_create_params.TranslationCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_get_response_format_type(response_format), - ) - - -class AsyncTranslations(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTranslationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncTranslationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTranslationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncTranslationsWithStreamingResponse(self) - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Union[Literal["json"], Omit] = omit, - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Translation: ... - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Literal["verbose_json"], - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TranslationVerbose: ... - - @overload - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - response_format: Literal["text", "srt", "vtt"], - prompt: str | Omit = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: ... - - async def create( - self, - *, - file: FileTypes, - model: Union[str, AudioModel], - prompt: str | Omit = omit, - response_format: Union[AudioResponseFormat, Omit] = omit, - temperature: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Translation | TranslationVerbose | str: - """ - Translates audio into English. - - Args: - file: The audio file object (not file name) translate, in one of these formats: flac, - mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - - model: ID of the model to use. Only `whisper-1` (which is powered by our open source - Whisper V2 model) is currently available. - - prompt: An optional text to guide the model's style or continue a previous audio - segment. The - [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should be in English. - - response_format: The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. - - temperature: The sampling temperature, between 0 and 1. Higher values like 0.8 will make the - output more random, while lower values like 0.2 will make it more focused and - deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "file": file, - "model": model, - "prompt": prompt, - "response_format": response_format, - "temperature": temperature, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/audio/translations", - body=await async_maybe_transform(body, translation_create_params.TranslationCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_get_response_format_type(response_format), - ) - - -class TranslationsWithRawResponse: - def __init__(self, translations: Translations) -> None: - self._translations = translations - - self.create = _legacy_response.to_raw_response_wrapper( - translations.create, - ) - - -class AsyncTranslationsWithRawResponse: - def __init__(self, translations: AsyncTranslations) -> None: - self._translations = translations - - self.create = _legacy_response.async_to_raw_response_wrapper( - translations.create, - ) - - -class TranslationsWithStreamingResponse: - def __init__(self, translations: Translations) -> None: - self._translations = translations - - self.create = to_streamed_response_wrapper( - translations.create, - ) - - -class AsyncTranslationsWithStreamingResponse: - def __init__(self, translations: AsyncTranslations) -> None: - self._translations = translations - - self.create = async_to_streamed_response_wrapper( - translations.create, - ) - - -def _get_response_format_type( - response_format: AudioResponseFormat | Omit, -) -> type[Translation | TranslationVerbose | str]: - if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] - return Translation - - if response_format == "json": - return Translation - elif response_format == "verbose_json": - return TranslationVerbose - elif response_format == "srt" or response_format == "text" or response_format == "vtt": - return str - elif TYPE_CHECKING and response_format != "diarized_json": # type: ignore[unreachable] - assert_never(response_format) - else: - log.warning("Unexpected audio response format: %s", response_format) - return Translation diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/batches.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/batches.py deleted file mode 100644 index 8040083..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/batches.py +++ /dev/null @@ -1,530 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal - -import httpx - -from .. import _legacy_response -from ..types import batch_list_params, batch_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..pagination import SyncCursorPage, AsyncCursorPage -from ..types.batch import Batch -from .._base_client import AsyncPaginator, make_request_options -from ..types.shared_params.metadata import Metadata - -__all__ = ["Batches", "AsyncBatches"] - - -class Batches(SyncAPIResource): - @cached_property - def with_raw_response(self) -> BatchesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return BatchesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BatchesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return BatchesWithStreamingResponse(self) - - def create( - self, - *, - completion_window: Literal["24h"], - endpoint: Literal[ - "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" - ], - input_file_id: str, - metadata: Optional[Metadata] | Omit = omit, - output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """ - Creates and executes a batch from an uploaded file of requests - - Args: - completion_window: The time frame within which the batch should be processed. Currently only `24h` - is supported. - - endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. - - input_file_id: The ID of an uploaded file that contains requests for the new batch. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your input file must be formatted as a - [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), - and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 200 MB in size. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - output_expires_after: The expiration policy for the output and/or error file that are generated for a - batch. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/batches", - body=maybe_transform( - { - "completion_window": completion_window, - "endpoint": endpoint, - "input_file_id": input_file_id, - "metadata": metadata, - "output_expires_after": output_expires_after, - }, - batch_create_params.BatchCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - def retrieve( - self, - batch_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """ - Retrieves a batch. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - return self._get( - f"/batches/{batch_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Batch]: - """List your organization's batches. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/batches", - page=SyncCursorPage[Batch], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - batch_list_params.BatchListParams, - ), - ), - model=Batch, - ) - - def cancel( - self, - batch_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """Cancels an in-progress batch. - - The batch will be in status `cancelling` for up to - 10 minutes, before changing to `cancelled`, where it will have partial results - (if any) available in the output file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - return self._post( - f"/batches/{batch_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - -class AsyncBatches(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncBatchesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncBatchesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBatchesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncBatchesWithStreamingResponse(self) - - async def create( - self, - *, - completion_window: Literal["24h"], - endpoint: Literal[ - "/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations" - ], - input_file_id: str, - metadata: Optional[Metadata] | Omit = omit, - output_expires_after: batch_create_params.OutputExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """ - Creates and executes a batch from an uploaded file of requests - - Args: - completion_window: The time frame within which the batch should be processed. Currently only `24h` - is supported. - - endpoint: The endpoint to be used for all requests in the batch. Currently - `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/completions`, - and `/v1/moderations` are supported. Note that `/v1/embeddings` batches are also - restricted to a maximum of 50,000 embedding inputs across all requests in the - batch. - - input_file_id: The ID of an uploaded file that contains requests for the new batch. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your input file must be formatted as a - [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), - and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 200 MB in size. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - output_expires_after: The expiration policy for the output and/or error file that are generated for a - batch. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/batches", - body=await async_maybe_transform( - { - "completion_window": completion_window, - "endpoint": endpoint, - "input_file_id": input_file_id, - "metadata": metadata, - "output_expires_after": output_expires_after, - }, - batch_create_params.BatchCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - async def retrieve( - self, - batch_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """ - Retrieves a batch. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - return await self._get( - f"/batches/{batch_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Batch, AsyncCursorPage[Batch]]: - """List your organization's batches. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/batches", - page=AsyncCursorPage[Batch], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - batch_list_params.BatchListParams, - ), - ), - model=Batch, - ) - - async def cancel( - self, - batch_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Batch: - """Cancels an in-progress batch. - - The batch will be in status `cancelling` for up to - 10 minutes, before changing to `cancelled`, where it will have partial results - (if any) available in the output file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - return await self._post( - f"/batches/{batch_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Batch, - ) - - -class BatchesWithRawResponse: - def __init__(self, batches: Batches) -> None: - self._batches = batches - - self.create = _legacy_response.to_raw_response_wrapper( - batches.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - batches.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - batches.list, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - batches.cancel, - ) - - -class AsyncBatchesWithRawResponse: - def __init__(self, batches: AsyncBatches) -> None: - self._batches = batches - - self.create = _legacy_response.async_to_raw_response_wrapper( - batches.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - batches.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - batches.list, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - batches.cancel, - ) - - -class BatchesWithStreamingResponse: - def __init__(self, batches: Batches) -> None: - self._batches = batches - - self.create = to_streamed_response_wrapper( - batches.create, - ) - self.retrieve = to_streamed_response_wrapper( - batches.retrieve, - ) - self.list = to_streamed_response_wrapper( - batches.list, - ) - self.cancel = to_streamed_response_wrapper( - batches.cancel, - ) - - -class AsyncBatchesWithStreamingResponse: - def __init__(self, batches: AsyncBatches) -> None: - self._batches = batches - - self.create = async_to_streamed_response_wrapper( - batches.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - batches.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - batches.list, - ) - self.cancel = async_to_streamed_response_wrapper( - batches.cancel, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/__init__.py deleted file mode 100644 index 6d6f538..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .beta import ( - Beta, - AsyncBeta, - BetaWithRawResponse, - AsyncBetaWithRawResponse, - BetaWithStreamingResponse, - AsyncBetaWithStreamingResponse, -) -from .chatkit import ( - ChatKit, - AsyncChatKit, - ChatKitWithRawResponse, - AsyncChatKitWithRawResponse, - ChatKitWithStreamingResponse, - AsyncChatKitWithStreamingResponse, -) -from .threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) -from .assistants import ( - Assistants, - AsyncAssistants, - AssistantsWithRawResponse, - AsyncAssistantsWithRawResponse, - AssistantsWithStreamingResponse, - AsyncAssistantsWithStreamingResponse, -) - -__all__ = [ - "ChatKit", - "AsyncChatKit", - "ChatKitWithRawResponse", - "AsyncChatKitWithRawResponse", - "ChatKitWithStreamingResponse", - "AsyncChatKitWithStreamingResponse", - "Assistants", - "AsyncAssistants", - "AssistantsWithRawResponse", - "AsyncAssistantsWithRawResponse", - "AssistantsWithStreamingResponse", - "AsyncAssistantsWithStreamingResponse", - "Threads", - "AsyncThreads", - "ThreadsWithRawResponse", - "AsyncThreadsWithRawResponse", - "ThreadsWithStreamingResponse", - "AsyncThreadsWithStreamingResponse", - "Beta", - "AsyncBeta", - "BetaWithRawResponse", - "AsyncBetaWithRawResponse", - "BetaWithStreamingResponse", - "AsyncBetaWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/assistants.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/assistants.py deleted file mode 100644 index ab0947a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/assistants.py +++ /dev/null @@ -1,1053 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncCursorPage, AsyncCursorPage -from ...types.beta import ( - assistant_list_params, - assistant_create_params, - assistant_update_params, -) -from ..._base_client import AsyncPaginator, make_request_options -from ...types.beta.assistant import Assistant -from ...types.shared.chat_model import ChatModel -from ...types.beta.assistant_deleted import AssistantDeleted -from ...types.shared_params.metadata import Metadata -from ...types.shared.reasoning_effort import ReasoningEffort -from ...types.beta.assistant_tool_param import AssistantToolParam -from ...types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = ["Assistants", "AsyncAssistants"] - - -class Assistants(SyncAPIResource): - @cached_property - def with_raw_response(self) -> AssistantsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AssistantsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AssistantsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AssistantsWithStreamingResponse(self) - - def create( - self, - *, - model: Union[str, ChatModel], - description: Optional[str] | Omit = omit, - instructions: Optional[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: Optional[str] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_resources: Optional[assistant_create_params.ToolResources] | Omit = omit, - tools: Iterable[AssistantToolParam] | Omit = omit, - top_p: Optional[float] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """ - Create an assistant with a model and instructions. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - description: The description of the assistant. The maximum length is 512 characters. - - instructions: The system instructions that the assistant uses. The maximum length is 256,000 - characters. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the assistant. The maximum length is 256 characters. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `file_search`, or - `function`. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/assistants", - body=maybe_transform( - { - "model": model, - "description": description, - "instructions": instructions, - "metadata": metadata, - "name": name, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "temperature": temperature, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - }, - assistant_create_params.AssistantCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - def retrieve( - self, - assistant_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """ - Retrieves an assistant. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/assistants/{assistant_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - def update( - self, - assistant_id: str, - *, - description: Optional[str] | Omit = omit, - instructions: Optional[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[ - str, - Literal[ - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - ], - ] - | Omit = omit, - name: Optional[str] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_resources: Optional[assistant_update_params.ToolResources] | Omit = omit, - tools: Iterable[AssistantToolParam] | Omit = omit, - top_p: Optional[float] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """Modifies an assistant. - - Args: - description: The description of the assistant. - - The maximum length is 512 characters. - - instructions: The system instructions that the assistant uses. The maximum length is 256,000 - characters. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - name: The name of the assistant. The maximum length is 256 characters. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `file_search`, or - `function`. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/assistants/{assistant_id}", - body=maybe_transform( - { - "description": description, - "instructions": instructions, - "metadata": metadata, - "model": model, - "name": name, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "temperature": temperature, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - }, - assistant_update_params.AssistantUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Assistant]: - """Returns a list of assistants. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - "/assistants", - page=SyncCursorPage[Assistant], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - assistant_list_params.AssistantListParams, - ), - ), - model=Assistant, - ) - - def delete( - self, - assistant_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AssistantDeleted: - """ - Delete an assistant. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._delete( - f"/assistants/{assistant_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AssistantDeleted, - ) - - -class AsyncAssistants(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncAssistantsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncAssistantsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAssistantsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncAssistantsWithStreamingResponse(self) - - async def create( - self, - *, - model: Union[str, ChatModel], - description: Optional[str] | Omit = omit, - instructions: Optional[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: Optional[str] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_resources: Optional[assistant_create_params.ToolResources] | Omit = omit, - tools: Iterable[AssistantToolParam] | Omit = omit, - top_p: Optional[float] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """ - Create an assistant with a model and instructions. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - description: The description of the assistant. The maximum length is 512 characters. - - instructions: The system instructions that the assistant uses. The maximum length is 256,000 - characters. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the assistant. The maximum length is 256 characters. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `file_search`, or - `function`. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/assistants", - body=await async_maybe_transform( - { - "model": model, - "description": description, - "instructions": instructions, - "metadata": metadata, - "name": name, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "temperature": temperature, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - }, - assistant_create_params.AssistantCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - async def retrieve( - self, - assistant_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """ - Retrieves an assistant. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/assistants/{assistant_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - async def update( - self, - assistant_id: str, - *, - description: Optional[str] | Omit = omit, - instructions: Optional[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[ - str, - Literal[ - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - ], - ] - | Omit = omit, - name: Optional[str] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_resources: Optional[assistant_update_params.ToolResources] | Omit = omit, - tools: Iterable[AssistantToolParam] | Omit = omit, - top_p: Optional[float] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Assistant: - """Modifies an assistant. - - Args: - description: The description of the assistant. - - The maximum length is 512 characters. - - instructions: The system instructions that the assistant uses. The maximum length is 256,000 - characters. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - name: The name of the assistant. The maximum length is 256 characters. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `file_search`, or - `function`. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/assistants/{assistant_id}", - body=await async_maybe_transform( - { - "description": description, - "instructions": instructions, - "metadata": metadata, - "model": model, - "name": name, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "temperature": temperature, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - }, - assistant_update_params.AssistantUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Assistant, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Assistant, AsyncCursorPage[Assistant]]: - """Returns a list of assistants. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - "/assistants", - page=AsyncCursorPage[Assistant], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - assistant_list_params.AssistantListParams, - ), - ), - model=Assistant, - ) - - async def delete( - self, - assistant_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AssistantDeleted: - """ - Delete an assistant. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._delete( - f"/assistants/{assistant_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AssistantDeleted, - ) - - -class AssistantsWithRawResponse: - def __init__(self, assistants: Assistants) -> None: - self._assistants = assistants - - self.create = _legacy_response.to_raw_response_wrapper( - assistants.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - assistants.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - assistants.update, - ) - self.list = _legacy_response.to_raw_response_wrapper( - assistants.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - assistants.delete, - ) - - -class AsyncAssistantsWithRawResponse: - def __init__(self, assistants: AsyncAssistants) -> None: - self._assistants = assistants - - self.create = _legacy_response.async_to_raw_response_wrapper( - assistants.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - assistants.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - assistants.update, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - assistants.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - assistants.delete, - ) - - -class AssistantsWithStreamingResponse: - def __init__(self, assistants: Assistants) -> None: - self._assistants = assistants - - self.create = to_streamed_response_wrapper( - assistants.create, - ) - self.retrieve = to_streamed_response_wrapper( - assistants.retrieve, - ) - self.update = to_streamed_response_wrapper( - assistants.update, - ) - self.list = to_streamed_response_wrapper( - assistants.list, - ) - self.delete = to_streamed_response_wrapper( - assistants.delete, - ) - - -class AsyncAssistantsWithStreamingResponse: - def __init__(self, assistants: AsyncAssistants) -> None: - self._assistants = assistants - - self.create = async_to_streamed_response_wrapper( - assistants.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - assistants.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - assistants.update, - ) - self.list = async_to_streamed_response_wrapper( - assistants.list, - ) - self.delete = async_to_streamed_response_wrapper( - assistants.delete, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/beta.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/beta.py deleted file mode 100644 index 5ee3639..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/beta.py +++ /dev/null @@ -1,187 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..._compat import cached_property -from .assistants import ( - Assistants, - AsyncAssistants, - AssistantsWithRawResponse, - AsyncAssistantsWithRawResponse, - AssistantsWithStreamingResponse, - AsyncAssistantsWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from .chatkit.chatkit import ( - ChatKit, - AsyncChatKit, - ChatKitWithRawResponse, - AsyncChatKitWithRawResponse, - ChatKitWithStreamingResponse, - AsyncChatKitWithStreamingResponse, -) -from .threads.threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) -from ...resources.chat import Chat, AsyncChat -from .realtime.realtime import ( - Realtime, - AsyncRealtime, -) - -__all__ = ["Beta", "AsyncBeta"] - - -class Beta(SyncAPIResource): - @cached_property - def chat(self) -> Chat: - return Chat(self._client) - - @cached_property - def realtime(self) -> Realtime: - return Realtime(self._client) - - @cached_property - def chatkit(self) -> ChatKit: - return ChatKit(self._client) - - @cached_property - def assistants(self) -> Assistants: - return Assistants(self._client) - - @cached_property - def threads(self) -> Threads: - return Threads(self._client) - - @cached_property - def with_raw_response(self) -> BetaWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return BetaWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BetaWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return BetaWithStreamingResponse(self) - - -class AsyncBeta(AsyncAPIResource): - @cached_property - def chat(self) -> AsyncChat: - return AsyncChat(self._client) - - @cached_property - def realtime(self) -> AsyncRealtime: - return AsyncRealtime(self._client) - - @cached_property - def chatkit(self) -> AsyncChatKit: - return AsyncChatKit(self._client) - - @cached_property - def assistants(self) -> AsyncAssistants: - return AsyncAssistants(self._client) - - @cached_property - def threads(self) -> AsyncThreads: - return AsyncThreads(self._client) - - @cached_property - def with_raw_response(self) -> AsyncBetaWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncBetaWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBetaWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncBetaWithStreamingResponse(self) - - -class BetaWithRawResponse: - def __init__(self, beta: Beta) -> None: - self._beta = beta - - @cached_property - def chatkit(self) -> ChatKitWithRawResponse: - return ChatKitWithRawResponse(self._beta.chatkit) - - @cached_property - def assistants(self) -> AssistantsWithRawResponse: - return AssistantsWithRawResponse(self._beta.assistants) - - @cached_property - def threads(self) -> ThreadsWithRawResponse: - return ThreadsWithRawResponse(self._beta.threads) - - -class AsyncBetaWithRawResponse: - def __init__(self, beta: AsyncBeta) -> None: - self._beta = beta - - @cached_property - def chatkit(self) -> AsyncChatKitWithRawResponse: - return AsyncChatKitWithRawResponse(self._beta.chatkit) - - @cached_property - def assistants(self) -> AsyncAssistantsWithRawResponse: - return AsyncAssistantsWithRawResponse(self._beta.assistants) - - @cached_property - def threads(self) -> AsyncThreadsWithRawResponse: - return AsyncThreadsWithRawResponse(self._beta.threads) - - -class BetaWithStreamingResponse: - def __init__(self, beta: Beta) -> None: - self._beta = beta - - @cached_property - def chatkit(self) -> ChatKitWithStreamingResponse: - return ChatKitWithStreamingResponse(self._beta.chatkit) - - @cached_property - def assistants(self) -> AssistantsWithStreamingResponse: - return AssistantsWithStreamingResponse(self._beta.assistants) - - @cached_property - def threads(self) -> ThreadsWithStreamingResponse: - return ThreadsWithStreamingResponse(self._beta.threads) - - -class AsyncBetaWithStreamingResponse: - def __init__(self, beta: AsyncBeta) -> None: - self._beta = beta - - @cached_property - def chatkit(self) -> AsyncChatKitWithStreamingResponse: - return AsyncChatKitWithStreamingResponse(self._beta.chatkit) - - @cached_property - def assistants(self) -> AsyncAssistantsWithStreamingResponse: - return AsyncAssistantsWithStreamingResponse(self._beta.assistants) - - @cached_property - def threads(self) -> AsyncThreadsWithStreamingResponse: - return AsyncThreadsWithStreamingResponse(self._beta.threads) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/__init__.py deleted file mode 100644 index 05f24d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .chatkit import ( - ChatKit, - AsyncChatKit, - ChatKitWithRawResponse, - AsyncChatKitWithRawResponse, - ChatKitWithStreamingResponse, - AsyncChatKitWithStreamingResponse, -) -from .threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) -from .sessions import ( - Sessions, - AsyncSessions, - SessionsWithRawResponse, - AsyncSessionsWithRawResponse, - SessionsWithStreamingResponse, - AsyncSessionsWithStreamingResponse, -) - -__all__ = [ - "Sessions", - "AsyncSessions", - "SessionsWithRawResponse", - "AsyncSessionsWithRawResponse", - "SessionsWithStreamingResponse", - "AsyncSessionsWithStreamingResponse", - "Threads", - "AsyncThreads", - "ThreadsWithRawResponse", - "AsyncThreadsWithRawResponse", - "ThreadsWithStreamingResponse", - "AsyncThreadsWithStreamingResponse", - "ChatKit", - "AsyncChatKit", - "ChatKitWithRawResponse", - "AsyncChatKitWithRawResponse", - "ChatKitWithStreamingResponse", - "AsyncChatKitWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/chatkit.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/chatkit.py deleted file mode 100644 index 5a10a39..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/chatkit.py +++ /dev/null @@ -1,134 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) -from .sessions import ( - Sessions, - AsyncSessions, - SessionsWithRawResponse, - AsyncSessionsWithRawResponse, - SessionsWithStreamingResponse, - AsyncSessionsWithStreamingResponse, -) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["ChatKit", "AsyncChatKit"] - - -class ChatKit(SyncAPIResource): - @cached_property - def sessions(self) -> Sessions: - return Sessions(self._client) - - @cached_property - def threads(self) -> Threads: - return Threads(self._client) - - @cached_property - def with_raw_response(self) -> ChatKitWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ChatKitWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ChatKitWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ChatKitWithStreamingResponse(self) - - -class AsyncChatKit(AsyncAPIResource): - @cached_property - def sessions(self) -> AsyncSessions: - return AsyncSessions(self._client) - - @cached_property - def threads(self) -> AsyncThreads: - return AsyncThreads(self._client) - - @cached_property - def with_raw_response(self) -> AsyncChatKitWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncChatKitWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncChatKitWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncChatKitWithStreamingResponse(self) - - -class ChatKitWithRawResponse: - def __init__(self, chatkit: ChatKit) -> None: - self._chatkit = chatkit - - @cached_property - def sessions(self) -> SessionsWithRawResponse: - return SessionsWithRawResponse(self._chatkit.sessions) - - @cached_property - def threads(self) -> ThreadsWithRawResponse: - return ThreadsWithRawResponse(self._chatkit.threads) - - -class AsyncChatKitWithRawResponse: - def __init__(self, chatkit: AsyncChatKit) -> None: - self._chatkit = chatkit - - @cached_property - def sessions(self) -> AsyncSessionsWithRawResponse: - return AsyncSessionsWithRawResponse(self._chatkit.sessions) - - @cached_property - def threads(self) -> AsyncThreadsWithRawResponse: - return AsyncThreadsWithRawResponse(self._chatkit.threads) - - -class ChatKitWithStreamingResponse: - def __init__(self, chatkit: ChatKit) -> None: - self._chatkit = chatkit - - @cached_property - def sessions(self) -> SessionsWithStreamingResponse: - return SessionsWithStreamingResponse(self._chatkit.sessions) - - @cached_property - def threads(self) -> ThreadsWithStreamingResponse: - return ThreadsWithStreamingResponse(self._chatkit.threads) - - -class AsyncChatKitWithStreamingResponse: - def __init__(self, chatkit: AsyncChatKit) -> None: - self._chatkit = chatkit - - @cached_property - def sessions(self) -> AsyncSessionsWithStreamingResponse: - return AsyncSessionsWithStreamingResponse(self._chatkit.sessions) - - @cached_property - def threads(self) -> AsyncThreadsWithStreamingResponse: - return AsyncThreadsWithStreamingResponse(self._chatkit.threads) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/sessions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/sessions.py deleted file mode 100644 index a814f10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/sessions.py +++ /dev/null @@ -1,301 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._base_client import make_request_options -from ....types.beta.chatkit import ( - ChatSessionWorkflowParam, - ChatSessionRateLimitsParam, - ChatSessionExpiresAfterParam, - ChatSessionChatKitConfigurationParam, - session_create_params, -) -from ....types.beta.chatkit.chat_session import ChatSession -from ....types.beta.chatkit.chat_session_workflow_param import ChatSessionWorkflowParam -from ....types.beta.chatkit.chat_session_rate_limits_param import ChatSessionRateLimitsParam -from ....types.beta.chatkit.chat_session_expires_after_param import ChatSessionExpiresAfterParam -from ....types.beta.chatkit.chat_session_chatkit_configuration_param import ChatSessionChatKitConfigurationParam - -__all__ = ["Sessions", "AsyncSessions"] - - -class Sessions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> SessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return SessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return SessionsWithStreamingResponse(self) - - def create( - self, - *, - user: str, - workflow: ChatSessionWorkflowParam, - chatkit_configuration: ChatSessionChatKitConfigurationParam | Omit = omit, - expires_after: ChatSessionExpiresAfterParam | Omit = omit, - rate_limits: ChatSessionRateLimitsParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatSession: - """ - Create a ChatKit session - - Args: - user: A free-form string that identifies your end user; ensures this Session can - access other objects that have the same `user` scope. - - workflow: Workflow that powers the session. - - chatkit_configuration: Optional overrides for ChatKit runtime configuration features - - expires_after: Optional override for session expiration timing in seconds from creation. - Defaults to 10 minutes. - - rate_limits: Optional override for per-minute request limits. When omitted, defaults to 10. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._post( - "/chatkit/sessions", - body=maybe_transform( - { - "user": user, - "workflow": workflow, - "chatkit_configuration": chatkit_configuration, - "expires_after": expires_after, - "rate_limits": rate_limits, - }, - session_create_params.SessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatSession, - ) - - def cancel( - self, - session_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatSession: - """ - Cancel a ChatKit session - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not session_id: - raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._post( - f"/chatkit/sessions/{session_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatSession, - ) - - -class AsyncSessions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncSessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncSessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncSessionsWithStreamingResponse(self) - - async def create( - self, - *, - user: str, - workflow: ChatSessionWorkflowParam, - chatkit_configuration: ChatSessionChatKitConfigurationParam | Omit = omit, - expires_after: ChatSessionExpiresAfterParam | Omit = omit, - rate_limits: ChatSessionRateLimitsParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatSession: - """ - Create a ChatKit session - - Args: - user: A free-form string that identifies your end user; ensures this Session can - access other objects that have the same `user` scope. - - workflow: Workflow that powers the session. - - chatkit_configuration: Optional overrides for ChatKit runtime configuration features - - expires_after: Optional override for session expiration timing in seconds from creation. - Defaults to 10 minutes. - - rate_limits: Optional override for per-minute request limits. When omitted, defaults to 10. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return await self._post( - "/chatkit/sessions", - body=await async_maybe_transform( - { - "user": user, - "workflow": workflow, - "chatkit_configuration": chatkit_configuration, - "expires_after": expires_after, - "rate_limits": rate_limits, - }, - session_create_params.SessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatSession, - ) - - async def cancel( - self, - session_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatSession: - """ - Cancel a ChatKit session - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not session_id: - raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return await self._post( - f"/chatkit/sessions/{session_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatSession, - ) - - -class SessionsWithRawResponse: - def __init__(self, sessions: Sessions) -> None: - self._sessions = sessions - - self.create = _legacy_response.to_raw_response_wrapper( - sessions.create, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - sessions.cancel, - ) - - -class AsyncSessionsWithRawResponse: - def __init__(self, sessions: AsyncSessions) -> None: - self._sessions = sessions - - self.create = _legacy_response.async_to_raw_response_wrapper( - sessions.create, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - sessions.cancel, - ) - - -class SessionsWithStreamingResponse: - def __init__(self, sessions: Sessions) -> None: - self._sessions = sessions - - self.create = to_streamed_response_wrapper( - sessions.create, - ) - self.cancel = to_streamed_response_wrapper( - sessions.cancel, - ) - - -class AsyncSessionsWithStreamingResponse: - def __init__(self, sessions: AsyncSessions) -> None: - self._sessions = sessions - - self.create = async_to_streamed_response_wrapper( - sessions.create, - ) - self.cancel = async_to_streamed_response_wrapper( - sessions.cancel, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/threads.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/threads.py deleted file mode 100644 index 37cd572..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/chatkit/threads.py +++ /dev/null @@ -1,521 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, cast -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncConversationCursorPage, AsyncConversationCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.beta.chatkit import thread_list_params, thread_list_items_params -from ....types.beta.chatkit.chatkit_thread import ChatKitThread -from ....types.beta.chatkit.thread_delete_response import ThreadDeleteResponse -from ....types.beta.chatkit.chatkit_thread_item_list import Data - -__all__ = ["Threads", "AsyncThreads"] - - -class Threads(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ThreadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ThreadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ThreadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ThreadsWithStreamingResponse(self) - - def retrieve( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatKitThread: - """ - Retrieve a ChatKit thread - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._get( - f"/chatkit/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatKitThread, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[ChatKitThread]: - """ - List ChatKit threads - - Args: - after: List items created after this thread item ID. Defaults to null for the first - page. - - before: List items created before this thread item ID. Defaults to null for the newest - results. - - limit: Maximum number of thread items to return. Defaults to 20. - - order: Sort order for results by creation time. Defaults to `desc`. - - user: Filter threads that belong to this user identifier. Defaults to null to return - all users. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._get_api_list( - "/chatkit/threads", - page=SyncConversationCursorPage[ChatKitThread], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - "user": user, - }, - thread_list_params.ThreadListParams, - ), - ), - model=ChatKitThread, - ) - - def delete( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ThreadDeleteResponse: - """ - Delete a ChatKit thread - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._delete( - f"/chatkit/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ThreadDeleteResponse, - ) - - def list_items( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[Data]: - """ - List ChatKit thread items - - Args: - after: List items created after this thread item ID. Defaults to null for the first - page. - - before: List items created before this thread item ID. Defaults to null for the newest - results. - - limit: Maximum number of thread items to return. Defaults to 20. - - order: Sort order for results by creation time. Defaults to `desc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", - page=SyncConversationCursorPage[Data], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - thread_list_items_params.ThreadListItemsParams, - ), - ), - model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system - ) - - -class AsyncThreads(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncThreadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncThreadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncThreadsWithStreamingResponse(self) - - async def retrieve( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatKitThread: - """ - Retrieve a ChatKit thread - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return await self._get( - f"/chatkit/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatKitThread, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ChatKitThread, AsyncConversationCursorPage[ChatKitThread]]: - """ - List ChatKit threads - - Args: - after: List items created after this thread item ID. Defaults to null for the first - page. - - before: List items created before this thread item ID. Defaults to null for the newest - results. - - limit: Maximum number of thread items to return. Defaults to 20. - - order: Sort order for results by creation time. Defaults to `desc`. - - user: Filter threads that belong to this user identifier. Defaults to null to return - all users. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._get_api_list( - "/chatkit/threads", - page=AsyncConversationCursorPage[ChatKitThread], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - "user": user, - }, - thread_list_params.ThreadListParams, - ), - ), - model=ChatKitThread, - ) - - async def delete( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ThreadDeleteResponse: - """ - Delete a ChatKit thread - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return await self._delete( - f"/chatkit/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ThreadDeleteResponse, - ) - - def list_items( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Data, AsyncConversationCursorPage[Data]]: - """ - List ChatKit thread items - - Args: - after: List items created after this thread item ID. Defaults to null for the first - page. - - before: List items created before this thread item ID. Defaults to null for the newest - results. - - limit: Maximum number of thread items to return. Defaults to 20. - - order: Sort order for results by creation time. Defaults to `desc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} - return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", - page=AsyncConversationCursorPage[Data], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - thread_list_items_params.ThreadListItemsParams, - ), - ), - model=cast(Any, Data), # Union types cannot be passed in as arguments in the type system - ) - - -class ThreadsWithRawResponse: - def __init__(self, threads: Threads) -> None: - self._threads = threads - - self.retrieve = _legacy_response.to_raw_response_wrapper( - threads.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - threads.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - threads.delete, - ) - self.list_items = _legacy_response.to_raw_response_wrapper( - threads.list_items, - ) - - -class AsyncThreadsWithRawResponse: - def __init__(self, threads: AsyncThreads) -> None: - self._threads = threads - - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - threads.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - threads.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - threads.delete, - ) - self.list_items = _legacy_response.async_to_raw_response_wrapper( - threads.list_items, - ) - - -class ThreadsWithStreamingResponse: - def __init__(self, threads: Threads) -> None: - self._threads = threads - - self.retrieve = to_streamed_response_wrapper( - threads.retrieve, - ) - self.list = to_streamed_response_wrapper( - threads.list, - ) - self.delete = to_streamed_response_wrapper( - threads.delete, - ) - self.list_items = to_streamed_response_wrapper( - threads.list_items, - ) - - -class AsyncThreadsWithStreamingResponse: - def __init__(self, threads: AsyncThreads) -> None: - self._threads = threads - - self.retrieve = async_to_streamed_response_wrapper( - threads.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - threads.list, - ) - self.delete = async_to_streamed_response_wrapper( - threads.delete, - ) - self.list_items = async_to_streamed_response_wrapper( - threads.list_items, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/__init__.py deleted file mode 100644 index 7ab3d99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .realtime import ( - Realtime, - AsyncRealtime, - RealtimeWithRawResponse, - AsyncRealtimeWithRawResponse, - RealtimeWithStreamingResponse, - AsyncRealtimeWithStreamingResponse, -) -from .sessions import ( - Sessions, - AsyncSessions, - SessionsWithRawResponse, - AsyncSessionsWithRawResponse, - SessionsWithStreamingResponse, - AsyncSessionsWithStreamingResponse, -) -from .transcription_sessions import ( - TranscriptionSessions, - AsyncTranscriptionSessions, - TranscriptionSessionsWithRawResponse, - AsyncTranscriptionSessionsWithRawResponse, - TranscriptionSessionsWithStreamingResponse, - AsyncTranscriptionSessionsWithStreamingResponse, -) - -__all__ = [ - "Sessions", - "AsyncSessions", - "SessionsWithRawResponse", - "AsyncSessionsWithRawResponse", - "SessionsWithStreamingResponse", - "AsyncSessionsWithStreamingResponse", - "TranscriptionSessions", - "AsyncTranscriptionSessions", - "TranscriptionSessionsWithRawResponse", - "AsyncTranscriptionSessionsWithRawResponse", - "TranscriptionSessionsWithStreamingResponse", - "AsyncTranscriptionSessionsWithStreamingResponse", - "Realtime", - "AsyncRealtime", - "RealtimeWithRawResponse", - "AsyncRealtimeWithRawResponse", - "RealtimeWithStreamingResponse", - "AsyncRealtimeWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/realtime.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/realtime.py deleted file mode 100644 index 4fa3596..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/realtime.py +++ /dev/null @@ -1,1094 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import json -import logging -from types import TracebackType -from typing import TYPE_CHECKING, Any, Iterator, cast -from typing_extensions import AsyncIterator - -import httpx -from pydantic import BaseModel - -from .sessions import ( - Sessions, - AsyncSessions, - SessionsWithRawResponse, - AsyncSessionsWithRawResponse, - SessionsWithStreamingResponse, - AsyncSessionsWithStreamingResponse, -) -from ...._types import NOT_GIVEN, Query, Headers, NotGiven -from ...._utils import ( - is_azure_client, - maybe_transform, - strip_not_given, - async_maybe_transform, - is_async_azure_client, -) -from ...._compat import cached_property -from ...._models import construct_type_unchecked -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._exceptions import OpenAIError -from ...._base_client import _merge_mappings -from ....types.beta.realtime import ( - session_update_event_param, - response_create_event_param, - transcription_session_update_param, -) -from .transcription_sessions import ( - TranscriptionSessions, - AsyncTranscriptionSessions, - TranscriptionSessionsWithRawResponse, - AsyncTranscriptionSessionsWithRawResponse, - TranscriptionSessionsWithStreamingResponse, - AsyncTranscriptionSessionsWithStreamingResponse, -) -from ....types.websocket_connection_options import WebsocketConnectionOptions -from ....types.beta.realtime.realtime_client_event import RealtimeClientEvent -from ....types.beta.realtime.realtime_server_event import RealtimeServerEvent -from ....types.beta.realtime.conversation_item_param import ConversationItemParam -from ....types.beta.realtime.realtime_client_event_param import RealtimeClientEventParam - -if TYPE_CHECKING: - from websockets.sync.client import ClientConnection as WebsocketConnection - from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection - - from ...._client import OpenAI, AsyncOpenAI - -__all__ = ["Realtime", "AsyncRealtime"] - -log: logging.Logger = logging.getLogger(__name__) - - -class Realtime(SyncAPIResource): - @cached_property - def sessions(self) -> Sessions: - return Sessions(self._client) - - @cached_property - def transcription_sessions(self) -> TranscriptionSessions: - return TranscriptionSessions(self._client) - - @cached_property - def with_raw_response(self) -> RealtimeWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return RealtimeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RealtimeWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return RealtimeWithStreamingResponse(self) - - def connect( - self, - *, - model: str, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, - ) -> RealtimeConnectionManager: - """ - The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. - - Some notable benefits of the API include: - - - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. - - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. - - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. - - The Realtime API is a stateful, event-based API that communicates over a WebSocket. - """ - return RealtimeConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - model=model, - ) - - -class AsyncRealtime(AsyncAPIResource): - @cached_property - def sessions(self) -> AsyncSessions: - return AsyncSessions(self._client) - - @cached_property - def transcription_sessions(self) -> AsyncTranscriptionSessions: - return AsyncTranscriptionSessions(self._client) - - @cached_property - def with_raw_response(self) -> AsyncRealtimeWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncRealtimeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncRealtimeWithStreamingResponse(self) - - def connect( - self, - *, - model: str, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, - ) -> AsyncRealtimeConnectionManager: - """ - The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. - - Some notable benefits of the API include: - - - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. - - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. - - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. - - The Realtime API is a stateful, event-based API that communicates over a WebSocket. - """ - return AsyncRealtimeConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - model=model, - ) - - -class RealtimeWithRawResponse: - def __init__(self, realtime: Realtime) -> None: - self._realtime = realtime - - @cached_property - def sessions(self) -> SessionsWithRawResponse: - return SessionsWithRawResponse(self._realtime.sessions) - - @cached_property - def transcription_sessions(self) -> TranscriptionSessionsWithRawResponse: - return TranscriptionSessionsWithRawResponse(self._realtime.transcription_sessions) - - -class AsyncRealtimeWithRawResponse: - def __init__(self, realtime: AsyncRealtime) -> None: - self._realtime = realtime - - @cached_property - def sessions(self) -> AsyncSessionsWithRawResponse: - return AsyncSessionsWithRawResponse(self._realtime.sessions) - - @cached_property - def transcription_sessions(self) -> AsyncTranscriptionSessionsWithRawResponse: - return AsyncTranscriptionSessionsWithRawResponse(self._realtime.transcription_sessions) - - -class RealtimeWithStreamingResponse: - def __init__(self, realtime: Realtime) -> None: - self._realtime = realtime - - @cached_property - def sessions(self) -> SessionsWithStreamingResponse: - return SessionsWithStreamingResponse(self._realtime.sessions) - - @cached_property - def transcription_sessions(self) -> TranscriptionSessionsWithStreamingResponse: - return TranscriptionSessionsWithStreamingResponse(self._realtime.transcription_sessions) - - -class AsyncRealtimeWithStreamingResponse: - def __init__(self, realtime: AsyncRealtime) -> None: - self._realtime = realtime - - @cached_property - def sessions(self) -> AsyncSessionsWithStreamingResponse: - return AsyncSessionsWithStreamingResponse(self._realtime.sessions) - - @cached_property - def transcription_sessions(self) -> AsyncTranscriptionSessionsWithStreamingResponse: - return AsyncTranscriptionSessionsWithStreamingResponse(self._realtime.transcription_sessions) - - -class AsyncRealtimeConnection: - """Represents a live websocket connection to the Realtime API""" - - session: AsyncRealtimeSessionResource - response: AsyncRealtimeResponseResource - input_audio_buffer: AsyncRealtimeInputAudioBufferResource - conversation: AsyncRealtimeConversationResource - output_audio_buffer: AsyncRealtimeOutputAudioBufferResource - transcription_session: AsyncRealtimeTranscriptionSessionResource - - _connection: AsyncWebsocketConnection - - def __init__(self, connection: AsyncWebsocketConnection) -> None: - self._connection = connection - - self.session = AsyncRealtimeSessionResource(self) - self.response = AsyncRealtimeResponseResource(self) - self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) - self.conversation = AsyncRealtimeConversationResource(self) - self.output_audio_buffer = AsyncRealtimeOutputAudioBufferResource(self) - self.transcription_session = AsyncRealtimeTranscriptionSessionResource(self) - - async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK - - try: - while True: - yield await self.recv() - except ConnectionClosedOK: - return - - async def recv(self) -> RealtimeServerEvent: - """ - Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(await self.recv_bytes()) - - async def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = await self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) - return message - - async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(await async_maybe_transform(event, RealtimeClientEventParam)) - ) - await self._connection.send(data) - - async def close(self, *, code: int = 1000, reason: str = "") -> None: - await self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> RealtimeServerEvent: - """ - Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) - ) - - -class AsyncRealtimeConnectionManager: - """ - Context manager over a `AsyncRealtimeConnection` that is returned by `beta.realtime.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.beta.realtime.connect(...).enter() - # ... - await connection.close() - ``` - """ - - def __init__( - self, - *, - client: AsyncOpenAI, - model: str, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, - ) -> None: - self.__client = client - self.__model = model - self.__connection: AsyncRealtimeConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - - async def __aenter__(self) -> AsyncRealtimeConnection: - """ - 👋 If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.beta.realtime.connect(...).enter() - # ... - await connection.close() - ``` - """ - try: - from websockets.asyncio.client import connect - except ImportError as exc: - raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - - extra_query = self.__extra_query - await self.__client._refresh_api_key() - auth_headers = self.__client.auth_headers - if is_async_azure_client(self.__client): - url, auth_headers = await self.__client._configure_realtime(self.__model, extra_query) - else: - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - "model": self.__model, - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - self.__connection = AsyncRealtimeConnection( - await connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - "OpenAI-Beta": "realtime=v1", - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) - ) - - return self.__connection - - enter = __aenter__ - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - base_url = self.__client._base_url.copy_with(scheme="wss") - - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - return base_url.copy_with(raw_path=merge_raw_path) - - async def __aexit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - await self.__connection.close() - - -class RealtimeConnection: - """Represents a live websocket connection to the Realtime API""" - - session: RealtimeSessionResource - response: RealtimeResponseResource - input_audio_buffer: RealtimeInputAudioBufferResource - conversation: RealtimeConversationResource - output_audio_buffer: RealtimeOutputAudioBufferResource - transcription_session: RealtimeTranscriptionSessionResource - - _connection: WebsocketConnection - - def __init__(self, connection: WebsocketConnection) -> None: - self._connection = connection - - self.session = RealtimeSessionResource(self) - self.response = RealtimeResponseResource(self) - self.input_audio_buffer = RealtimeInputAudioBufferResource(self) - self.conversation = RealtimeConversationResource(self) - self.output_audio_buffer = RealtimeOutputAudioBufferResource(self) - self.transcription_session = RealtimeTranscriptionSessionResource(self) - - def __iter__(self) -> Iterator[RealtimeServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK - - try: - while True: - yield self.recv() - except ConnectionClosedOK: - return - - def recv(self) -> RealtimeServerEvent: - """ - Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(self.recv_bytes()) - - def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) - return message - - def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(maybe_transform(event, RealtimeClientEventParam)) - ) - self._connection.send(data) - - def close(self, *, code: int = 1000, reason: str = "") -> None: - self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> RealtimeServerEvent: - """ - Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) - ) - - -class RealtimeConnectionManager: - """ - Context manager over a `RealtimeConnection` that is returned by `beta.realtime.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.beta.realtime.connect(...).enter() - # ... - connection.close() - ``` - """ - - def __init__( - self, - *, - client: OpenAI, - model: str, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, - ) -> None: - self.__client = client - self.__model = model - self.__connection: RealtimeConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - - def __enter__(self) -> RealtimeConnection: - """ - 👋 If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.beta.realtime.connect(...).enter() - # ... - connection.close() - ``` - """ - try: - from websockets.sync.client import connect - except ImportError as exc: - raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - - extra_query = self.__extra_query - self.__client._refresh_api_key() - auth_headers = self.__client.auth_headers - if is_azure_client(self.__client): - url, auth_headers = self.__client._configure_realtime(self.__model, extra_query) - else: - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - "model": self.__model, - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - self.__connection = RealtimeConnection( - connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - "OpenAI-Beta": "realtime=v1", - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) - ) - - return self.__connection - - enter = __enter__ - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - base_url = self.__client._base_url.copy_with(scheme="wss") - - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - return base_url.copy_with(raw_path=merge_raw_path) - - def __exit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - self.__connection.close() - - -class BaseRealtimeConnectionResource: - def __init__(self, connection: RealtimeConnection) -> None: - self._connection = connection - - -class RealtimeSessionResource(BaseRealtimeConnectionResource): - def update(self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event to update the session’s default configuration. - The client may send this event at any time to update any field, - except for `voice`. However, note that once a session has been - initialized with a particular `model`, it can’t be changed to - another model using `session.update`. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present are updated. To clear a field like - `instructions`, pass an empty string. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), - ) - ) - - -class RealtimeResponseResource(BaseRealtimeConnectionResource): - def create( - self, - *, - event_id: str | NotGiven = NOT_GIVEN, - response: response_create_event_param.Response | NotGiven = NOT_GIVEN, - ) -> None: - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions`, and `temperature`. These fields will override the Session's - configuration for this Response only. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), - ) - ) - - def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - - -class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. - - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) - ) - - def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will - not send a confirmation response to this event. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), - ) - ) - - -class RealtimeConversationResource(BaseRealtimeConnectionResource): - @cached_property - def item(self) -> RealtimeConversationItemResource: - return RealtimeConversationItemResource(self._connection) - - -class RealtimeConversationItemResource(BaseRealtimeConnectionResource): - def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), - ) - ) - - def create( - self, - *, - item: ConversationItemParam, - event_id: str | NotGiven = NOT_GIVEN, - previous_item_id: str | NotGiven = NOT_GIVEN, - ) -> None: - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.create", - "item": item, - "event_id": event_id, - "previous_item_id": previous_item_id, - } - ), - ) - ) - - def truncate( - self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.truncate", - "audio_end_ms": audio_end_ms, - "content_index": content_index, - "item_id": item_id, - "event_id": event_id, - } - ), - ) - ) - - def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), - ) - ) - - -class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """**WebRTC Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) - ) - - -class RealtimeTranscriptionSessionResource(BaseRealtimeConnectionResource): - def update( - self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to update a transcription session.""" - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), - ) - ) - - -class BaseAsyncRealtimeConnectionResource: - def __init__(self, connection: AsyncRealtimeConnection) -> None: - self._connection = connection - - -class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): - async def update( - self, *, session: session_update_event_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """ - Send this event to update the session’s default configuration. - The client may send this event at any time to update any field, - except for `voice`. However, note that once a session has been - initialized with a particular `model`, it can’t be changed to - another model using `session.update`. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present are updated. To clear a field like - `instructions`, pass an empty string. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): - async def create( - self, - *, - event_id: str | NotGiven = NOT_GIVEN, - response: response_create_event_param.Response | NotGiven = NOT_GIVEN, - ) -> None: - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions`, and `temperature`. These fields will override the Session's - configuration for this Response only. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), - ) - ) - - async def cancel(self, *, event_id: str | NotGiven = NOT_GIVEN, response_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - - -class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - async def commit(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event to commit the user input audio buffer, which will create a - new user message item in the conversation. This event will produce an error - if the input audio buffer is empty. When in Server VAD mode, the client does - not need to send this event, the server will commit the audio buffer - automatically. - - Committing the input audio buffer will trigger input audio transcription - (if enabled in session configuration), but it will not create a response - from the model. The server will respond with an `input_audio_buffer.committed` - event. - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) - ) - - async def append(self, *, audio: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. In Server VAD - mode, the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike made other client events, the server will - not send a confirmation response to this event. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeConversationResource(BaseAsyncRealtimeConnectionResource): - @cached_property - def item(self) -> AsyncRealtimeConversationItemResource: - return AsyncRealtimeConversationItemResource(self._connection) - - -class AsyncRealtimeConversationItemResource(BaseAsyncRealtimeConnectionResource): - async def delete(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), - ) - ) - - async def create( - self, - *, - item: ConversationItemParam, - event_id: str | NotGiven = NOT_GIVEN, - previous_item_id: str | NotGiven = NOT_GIVEN, - ) -> None: - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.create", - "item": item, - "event_id": event_id, - "previous_item_id": previous_item_id, - } - ), - ) - ) - - async def truncate( - self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.truncate", - "audio_end_ms": audio_end_ms, - "content_index": content_index, - "item_id": item_id, - "event_id": event_id, - } - ), - ) - ) - - async def retrieve(self, *, item_id: str, event_id: str | NotGiven = NOT_GIVEN) -> None: - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | NotGiven = NOT_GIVEN) -> None: - """**WebRTC Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) - ) - - -class AsyncRealtimeTranscriptionSessionResource(BaseAsyncRealtimeConnectionResource): - async def update( - self, *, session: transcription_session_update_param.Session, event_id: str | NotGiven = NOT_GIVEN - ) -> None: - """Send this event to update a transcription session.""" - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "transcription_session.update", "session": session, "event_id": event_id}), - ) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/sessions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/sessions.py deleted file mode 100644 index 9b85e02..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/sessions.py +++ /dev/null @@ -1,424 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._base_client import make_request_options -from ....types.beta.realtime import session_create_params -from ....types.beta.realtime.session_create_response import SessionCreateResponse - -__all__ = ["Sessions", "AsyncSessions"] - - -class Sessions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> SessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return SessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return SessionsWithStreamingResponse(self) - - def create( - self, - *, - client_secret: session_create_params.ClientSecret | NotGiven = NOT_GIVEN, - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, - input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - instructions: str | NotGiven = NOT_GIVEN, - max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, - model: Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - | NotGiven = NOT_GIVEN, - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - speed: float | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - tool_choice: str | NotGiven = NOT_GIVEN, - tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, - tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, - turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] - | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SessionCreateResponse: - """ - Create an ephemeral API token for use in client-side applications with the - Realtime API. Can be configured with the same session parameters as the - `session.update` client event. - - It responds with a session object, plus a `client_secret` key which contains a - usable ephemeral API token that can be used to authenticate browser clients for - the Realtime API. - - Args: - client_secret: Configuration options for the generated client secret. - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For - `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel - (mono), and little-endian byte order. - - input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn - off. Noise reduction filters audio added to the input audio buffer before it is - sent to VAD and the model. Filtering the audio can improve VAD and turn - detection accuracy (reducing false positives) and model performance by improving - perception of the input audio. - - input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - - instructions: The default system instructions (i.e. system message) prepended to model calls. - This field allows the client to guide the model on desired responses. The model - can be instructed on response content and format, (e.g. "be extremely succinct", - "act friendly", "here are examples of good responses") and on audio behavior - (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The - instructions are not guaranteed to be followed by the model, but they provide - guidance to the model on the desired behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - - max_response_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - - modalities: The set of modalities the model can respond with. To disable audio, set this to - ["text"]. - - model: The Realtime model used for this session. - - output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. - For `pcm16`, output audio is sampled at a rate of 24kHz. - - speed: The speed of the model's spoken response. 1.0 is the default speed. 0.25 is the - minimum speed. 1.5 is the maximum speed. This value can only be changed in - between model turns, not while a response is in progress. - - temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a - temperature of 0.8 is highly recommended for best performance. - - tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify - a function. - - tools: Tools (functions) available to the model. - - tracing: Configuration options for tracing. Set to null to disable tracing. Once tracing - is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - - turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be - set to `null` to turn off, in which case the client must manually trigger model - response. Server VAD means that the model will detect the start and end of - speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjunction with VAD) to - semantically estimate whether the user has finished speaking, then dynamically - sets a timeout based on this probability. For example, if user audio trails off - with "uhhm", the model will score a low probability of turn end and wait longer - for the user to continue speaking. This can be useful for more natural - conversations, but may have a higher latency. - - voice: The voice the model uses to respond. Voice cannot be changed during the session - once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/realtime/sessions", - body=maybe_transform( - { - "client_secret": client_secret, - "input_audio_format": input_audio_format, - "input_audio_noise_reduction": input_audio_noise_reduction, - "input_audio_transcription": input_audio_transcription, - "instructions": instructions, - "max_response_output_tokens": max_response_output_tokens, - "modalities": modalities, - "model": model, - "output_audio_format": output_audio_format, - "speed": speed, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "tracing": tracing, - "turn_detection": turn_detection, - "voice": voice, - }, - session_create_params.SessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SessionCreateResponse, - ) - - -class AsyncSessions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncSessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncSessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncSessionsWithStreamingResponse(self) - - async def create( - self, - *, - client_secret: session_create_params.ClientSecret | NotGiven = NOT_GIVEN, - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_noise_reduction: session_create_params.InputAudioNoiseReduction | NotGiven = NOT_GIVEN, - input_audio_transcription: session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - instructions: str | NotGiven = NOT_GIVEN, - max_response_output_tokens: Union[int, Literal["inf"]] | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, - model: Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - | NotGiven = NOT_GIVEN, - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - speed: float | NotGiven = NOT_GIVEN, - temperature: float | NotGiven = NOT_GIVEN, - tool_choice: str | NotGiven = NOT_GIVEN, - tools: Iterable[session_create_params.Tool] | NotGiven = NOT_GIVEN, - tracing: session_create_params.Tracing | NotGiven = NOT_GIVEN, - turn_detection: session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] - | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SessionCreateResponse: - """ - Create an ephemeral API token for use in client-side applications with the - Realtime API. Can be configured with the same session parameters as the - `session.update` client event. - - It responds with a session object, plus a `client_secret` key which contains a - usable ephemeral API token that can be used to authenticate browser clients for - the Realtime API. - - Args: - client_secret: Configuration options for the generated client secret. - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For - `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel - (mono), and little-endian byte order. - - input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn - off. Noise reduction filters audio added to the input audio buffer before it is - sent to VAD and the model. Filtering the audio can improve VAD and turn - detection accuracy (reducing false positives) and model performance by improving - perception of the input audio. - - input_audio_transcription: Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - - instructions: The default system instructions (i.e. system message) prepended to model calls. - This field allows the client to guide the model on desired responses. The model - can be instructed on response content and format, (e.g. "be extremely succinct", - "act friendly", "here are examples of good responses") and on audio behavior - (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The - instructions are not guaranteed to be followed by the model, but they provide - guidance to the model on the desired behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - - max_response_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - - modalities: The set of modalities the model can respond with. To disable audio, set this to - ["text"]. - - model: The Realtime model used for this session. - - output_audio_format: The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. - For `pcm16`, output audio is sampled at a rate of 24kHz. - - speed: The speed of the model's spoken response. 1.0 is the default speed. 0.25 is the - minimum speed. 1.5 is the maximum speed. This value can only be changed in - between model turns, not while a response is in progress. - - temperature: Sampling temperature for the model, limited to [0.6, 1.2]. For audio models a - temperature of 0.8 is highly recommended for best performance. - - tool_choice: How the model chooses tools. Options are `auto`, `none`, `required`, or specify - a function. - - tools: Tools (functions) available to the model. - - tracing: Configuration options for tracing. Set to null to disable tracing. Once tracing - is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - - turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be - set to `null` to turn off, in which case the client must manually trigger model - response. Server VAD means that the model will detect the start and end of - speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjunction with VAD) to - semantically estimate whether the user has finished speaking, then dynamically - sets a timeout based on this probability. For example, if user audio trails off - with "uhhm", the model will score a low probability of turn end and wait longer - for the user to continue speaking. This can be useful for more natural - conversations, but may have a higher latency. - - voice: The voice the model uses to respond. Voice cannot be changed during the session - once the model has responded with audio at least once. Current voice options are - `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/realtime/sessions", - body=await async_maybe_transform( - { - "client_secret": client_secret, - "input_audio_format": input_audio_format, - "input_audio_noise_reduction": input_audio_noise_reduction, - "input_audio_transcription": input_audio_transcription, - "instructions": instructions, - "max_response_output_tokens": max_response_output_tokens, - "modalities": modalities, - "model": model, - "output_audio_format": output_audio_format, - "speed": speed, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "tracing": tracing, - "turn_detection": turn_detection, - "voice": voice, - }, - session_create_params.SessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SessionCreateResponse, - ) - - -class SessionsWithRawResponse: - def __init__(self, sessions: Sessions) -> None: - self._sessions = sessions - - self.create = _legacy_response.to_raw_response_wrapper( - sessions.create, - ) - - -class AsyncSessionsWithRawResponse: - def __init__(self, sessions: AsyncSessions) -> None: - self._sessions = sessions - - self.create = _legacy_response.async_to_raw_response_wrapper( - sessions.create, - ) - - -class SessionsWithStreamingResponse: - def __init__(self, sessions: Sessions) -> None: - self._sessions = sessions - - self.create = to_streamed_response_wrapper( - sessions.create, - ) - - -class AsyncSessionsWithStreamingResponse: - def __init__(self, sessions: AsyncSessions) -> None: - self._sessions = sessions - - self.create = async_to_streamed_response_wrapper( - sessions.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/transcription_sessions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/transcription_sessions.py deleted file mode 100644 index 54fe7d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/realtime/transcription_sessions.py +++ /dev/null @@ -1,282 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._base_client import make_request_options -from ....types.beta.realtime import transcription_session_create_params -from ....types.beta.realtime.transcription_session import TranscriptionSession - -__all__ = ["TranscriptionSessions", "AsyncTranscriptionSessions"] - - -class TranscriptionSessions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TranscriptionSessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return TranscriptionSessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TranscriptionSessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return TranscriptionSessionsWithStreamingResponse(self) - - def create( - self, - *, - client_secret: transcription_session_create_params.ClientSecret | NotGiven = NOT_GIVEN, - include: List[str] | NotGiven = NOT_GIVEN, - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction - | NotGiven = NOT_GIVEN, - input_audio_transcription: transcription_session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, - turn_detection: transcription_session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TranscriptionSession: - """ - Create an ephemeral API token for use in client-side applications with the - Realtime API specifically for realtime transcriptions. Can be configured with - the same session parameters as the `transcription_session.update` client event. - - It responds with a session object, plus a `client_secret` key which contains a - usable ephemeral API token that can be used to authenticate browser clients for - the Realtime API. - - Args: - client_secret: Configuration options for the generated client secret. - - include: - The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For - `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel - (mono), and little-endian byte order. - - input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn - off. Noise reduction filters audio added to the input audio buffer before it is - sent to VAD and the model. Filtering the audio can improve VAD and turn - detection accuracy (reducing false positives) and model performance by improving - perception of the input audio. - - input_audio_transcription: Configuration for input audio transcription. The client can optionally set the - language and prompt for transcription, these offer additional guidance to the - transcription service. - - modalities: The set of modalities the model can respond with. To disable audio, set this to - ["text"]. - - turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be - set to `null` to turn off, in which case the client must manually trigger model - response. Server VAD means that the model will detect the start and end of - speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjunction with VAD) to - semantically estimate whether the user has finished speaking, then dynamically - sets a timeout based on this probability. For example, if user audio trails off - with "uhhm", the model will score a low probability of turn end and wait longer - for the user to continue speaking. This can be useful for more natural - conversations, but may have a higher latency. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/realtime/transcription_sessions", - body=maybe_transform( - { - "client_secret": client_secret, - "include": include, - "input_audio_format": input_audio_format, - "input_audio_noise_reduction": input_audio_noise_reduction, - "input_audio_transcription": input_audio_transcription, - "modalities": modalities, - "turn_detection": turn_detection, - }, - transcription_session_create_params.TranscriptionSessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TranscriptionSession, - ) - - -class AsyncTranscriptionSessions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTranscriptionSessionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncTranscriptionSessionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTranscriptionSessionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncTranscriptionSessionsWithStreamingResponse(self) - - async def create( - self, - *, - client_secret: transcription_session_create_params.ClientSecret | NotGiven = NOT_GIVEN, - include: List[str] | NotGiven = NOT_GIVEN, - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] | NotGiven = NOT_GIVEN, - input_audio_noise_reduction: transcription_session_create_params.InputAudioNoiseReduction - | NotGiven = NOT_GIVEN, - input_audio_transcription: transcription_session_create_params.InputAudioTranscription | NotGiven = NOT_GIVEN, - modalities: List[Literal["text", "audio"]] | NotGiven = NOT_GIVEN, - turn_detection: transcription_session_create_params.TurnDetection | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TranscriptionSession: - """ - Create an ephemeral API token for use in client-side applications with the - Realtime API specifically for realtime transcriptions. Can be configured with - the same session parameters as the `transcription_session.update` client event. - - It responds with a session object, plus a `client_secret` key which contains a - usable ephemeral API token that can be used to authenticate browser clients for - the Realtime API. - - Args: - client_secret: Configuration options for the generated client secret. - - include: - The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - - input_audio_format: The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For - `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel - (mono), and little-endian byte order. - - input_audio_noise_reduction: Configuration for input audio noise reduction. This can be set to `null` to turn - off. Noise reduction filters audio added to the input audio buffer before it is - sent to VAD and the model. Filtering the audio can improve VAD and turn - detection accuracy (reducing false positives) and model performance by improving - perception of the input audio. - - input_audio_transcription: Configuration for input audio transcription. The client can optionally set the - language and prompt for transcription, these offer additional guidance to the - transcription service. - - modalities: The set of modalities the model can respond with. To disable audio, set this to - ["text"]. - - turn_detection: Configuration for turn detection, ether Server VAD or Semantic VAD. This can be - set to `null` to turn off, in which case the client must manually trigger model - response. Server VAD means that the model will detect the start and end of - speech based on audio volume and respond at the end of user speech. Semantic VAD - is more advanced and uses a turn detection model (in conjunction with VAD) to - semantically estimate whether the user has finished speaking, then dynamically - sets a timeout based on this probability. For example, if user audio trails off - with "uhhm", the model will score a low probability of turn end and wait longer - for the user to continue speaking. This can be useful for more natural - conversations, but may have a higher latency. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/realtime/transcription_sessions", - body=await async_maybe_transform( - { - "client_secret": client_secret, - "include": include, - "input_audio_format": input_audio_format, - "input_audio_noise_reduction": input_audio_noise_reduction, - "input_audio_transcription": input_audio_transcription, - "modalities": modalities, - "turn_detection": turn_detection, - }, - transcription_session_create_params.TranscriptionSessionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TranscriptionSession, - ) - - -class TranscriptionSessionsWithRawResponse: - def __init__(self, transcription_sessions: TranscriptionSessions) -> None: - self._transcription_sessions = transcription_sessions - - self.create = _legacy_response.to_raw_response_wrapper( - transcription_sessions.create, - ) - - -class AsyncTranscriptionSessionsWithRawResponse: - def __init__(self, transcription_sessions: AsyncTranscriptionSessions) -> None: - self._transcription_sessions = transcription_sessions - - self.create = _legacy_response.async_to_raw_response_wrapper( - transcription_sessions.create, - ) - - -class TranscriptionSessionsWithStreamingResponse: - def __init__(self, transcription_sessions: TranscriptionSessions) -> None: - self._transcription_sessions = transcription_sessions - - self.create = to_streamed_response_wrapper( - transcription_sessions.create, - ) - - -class AsyncTranscriptionSessionsWithStreamingResponse: - def __init__(self, transcription_sessions: AsyncTranscriptionSessions) -> None: - self._transcription_sessions = transcription_sessions - - self.create = async_to_streamed_response_wrapper( - transcription_sessions.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/__init__.py deleted file mode 100644 index a66e445..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from .threads import ( - Threads, - AsyncThreads, - ThreadsWithRawResponse, - AsyncThreadsWithRawResponse, - ThreadsWithStreamingResponse, - AsyncThreadsWithStreamingResponse, -) -from .messages import ( - Messages, - AsyncMessages, - MessagesWithRawResponse, - AsyncMessagesWithRawResponse, - MessagesWithStreamingResponse, - AsyncMessagesWithStreamingResponse, -) - -__all__ = [ - "Runs", - "AsyncRuns", - "RunsWithRawResponse", - "AsyncRunsWithRawResponse", - "RunsWithStreamingResponse", - "AsyncRunsWithStreamingResponse", - "Messages", - "AsyncMessages", - "MessagesWithRawResponse", - "AsyncMessagesWithRawResponse", - "MessagesWithStreamingResponse", - "AsyncMessagesWithStreamingResponse", - "Threads", - "AsyncThreads", - "ThreadsWithRawResponse", - "AsyncThreadsWithRawResponse", - "ThreadsWithStreamingResponse", - "AsyncThreadsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/messages.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/messages.py deleted file mode 100644 index d94ecca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/messages.py +++ /dev/null @@ -1,718 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import typing_extensions -from typing import Union, Iterable, Optional -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) -from ....types.beta.threads import message_list_params, message_create_params, message_update_params -from ....types.beta.threads.message import Message -from ....types.shared_params.metadata import Metadata -from ....types.beta.threads.message_deleted import MessageDeleted -from ....types.beta.threads.message_content_part_param import MessageContentPartParam - -__all__ = ["Messages", "AsyncMessages"] - - -class Messages(SyncAPIResource): - @cached_property - def with_raw_response(self) -> MessagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return MessagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> MessagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return MessagesWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create( - self, - thread_id: str, - *, - content: Union[str, Iterable[MessageContentPartParam]], - role: Literal["user", "assistant"], - attachments: Optional[Iterable[message_create_params.Attachment]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Create a message. - - Args: - content: The text contents of the message. - - role: - The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - - attachments: A list of files attached to the message, and the tools they should be added to. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/messages", - body=maybe_transform( - { - "content": content, - "role": role, - "attachments": attachments, - "metadata": metadata, - }, - message_create_params.MessageCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def retrieve( - self, - message_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Retrieve a message. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/threads/{thread_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def update( - self, - message_id: str, - *, - thread_id: str, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Modifies a message. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/messages/{message_id}", - body=maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - run_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Message]: - """ - Returns a list of messages for a given thread. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - run_id: Filter messages by the run ID that generated them. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/messages", - page=SyncCursorPage[Message], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - "run_id": run_id, - }, - message_list_params.MessageListParams, - ), - ), - model=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def delete( - self, - message_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MessageDeleted: - """ - Deletes a message. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._delete( - f"/threads/{thread_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageDeleted, - ) - - -class AsyncMessages(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncMessagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncMessagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncMessagesWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - thread_id: str, - *, - content: Union[str, Iterable[MessageContentPartParam]], - role: Literal["user", "assistant"], - attachments: Optional[Iterable[message_create_params.Attachment]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Create a message. - - Args: - content: The text contents of the message. - - role: - The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - - attachments: A list of files attached to the message, and the tools they should be added to. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/messages", - body=await async_maybe_transform( - { - "content": content, - "role": role, - "attachments": attachments, - "metadata": metadata, - }, - message_create_params.MessageCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def retrieve( - self, - message_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Retrieve a message. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/threads/{thread_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def update( - self, - message_id: str, - *, - thread_id: str, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Message: - """ - Modifies a message. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/messages/{message_id}", - body=await async_maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - run_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Message, AsyncCursorPage[Message]]: - """ - Returns a list of messages for a given thread. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - run_id: Filter messages by the run ID that generated them. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/messages", - page=AsyncCursorPage[Message], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - "run_id": run_id, - }, - message_list_params.MessageListParams, - ), - ), - model=Message, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def delete( - self, - message_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MessageDeleted: - """ - Deletes a message. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._delete( - f"/threads/{thread_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageDeleted, - ) - - -class MessagesWithRawResponse: - def __init__(self, messages: Messages) -> None: - self._messages = messages - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncMessagesWithRawResponse: - def __init__(self, messages: AsyncMessages) -> None: - self._messages = messages - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) - ) - - -class MessagesWithStreamingResponse: - def __init__(self, messages: Messages) -> None: - self._messages = messages - - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncMessagesWithStreamingResponse: - def __init__(self, messages: AsyncMessages) -> None: - self._messages = messages - - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/__init__.py deleted file mode 100644 index 50aa9fa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from .steps import ( - Steps, - AsyncSteps, - StepsWithRawResponse, - AsyncStepsWithRawResponse, - StepsWithStreamingResponse, - AsyncStepsWithStreamingResponse, -) - -__all__ = [ - "Steps", - "AsyncSteps", - "StepsWithRawResponse", - "AsyncStepsWithRawResponse", - "StepsWithStreamingResponse", - "AsyncStepsWithStreamingResponse", - "Runs", - "AsyncRuns", - "RunsWithRawResponse", - "AsyncRunsWithRawResponse", - "RunsWithStreamingResponse", - "AsyncRunsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/runs.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/runs.py deleted file mode 100644 index 8a58e91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/runs.py +++ /dev/null @@ -1,3128 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import typing_extensions -from typing import List, Union, Iterable, Optional -from functools import partial -from typing_extensions import Literal, overload - -import httpx - -from ..... import _legacy_response -from .steps import ( - Steps, - AsyncSteps, - StepsWithRawResponse, - AsyncStepsWithRawResponse, - StepsWithStreamingResponse, - AsyncStepsWithStreamingResponse, -) -from ....._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import ( - is_given, - required_args, - maybe_transform, - async_maybe_transform, -) -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....._streaming import Stream, AsyncStream -from .....pagination import SyncCursorPage, AsyncCursorPage -from ....._base_client import AsyncPaginator, make_request_options -from .....lib.streaming import ( - AssistantEventHandler, - AssistantEventHandlerT, - AssistantStreamManager, - AsyncAssistantEventHandler, - AsyncAssistantEventHandlerT, - AsyncAssistantStreamManager, -) -from .....types.beta.threads import ( - run_list_params, - run_create_params, - run_update_params, - run_submit_tool_outputs_params, -) -from .....types.beta.threads.run import Run -from .....types.shared.chat_model import ChatModel -from .....types.shared_params.metadata import Metadata -from .....types.shared.reasoning_effort import ReasoningEffort -from .....types.beta.assistant_tool_param import AssistantToolParam -from .....types.beta.assistant_stream_event import AssistantStreamEvent -from .....types.beta.threads.runs.run_step_include import RunStepInclude -from .....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam -from .....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = ["Runs", "AsyncRuns"] - - -class Runs(SyncAPIResource): - @cached_property - def steps(self) -> Steps: - return Steps(self._client) - - @cached_property - def with_raw_response(self) -> RunsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return RunsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RunsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return RunsWithStreamingResponse(self) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create( - self, - thread_id: str, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create( - self, - thread_id: str, - *, - assistant_id: str, - stream: Literal[True], - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[AssistantStreamEvent]: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create( - self, - thread_id: str, - *, - assistant_id: str, - stream: bool, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["assistant_id"], ["assistant_id", "stream"]) - def create( - self, - thread_id: str, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation_strategy": truncation_strategy, - }, - run_create_params.RunCreateParamsStreaming if stream else run_create_params.RunCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, run_create_params.RunCreateParams), - ), - cast_to=Run, - stream=stream or False, - stream_cls=Stream[AssistantStreamEvent], - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def retrieve( - self, - run_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Retrieves a run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/threads/{thread_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def update( - self, - run_id: str, - *, - thread_id: str, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Modifies a run. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/runs/{run_id}", - body=maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Run]: - """ - Returns a list of runs belonging to a thread. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/runs", - page=SyncCursorPage[Run], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - run_list_params.RunListParams, - ), - ), - model=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def cancel( - self, - run_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Cancels a run that is `in_progress`. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create_and_poll( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - poll_interval_ms: int | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to create a run an poll for a terminal state. More information on Run - lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = self.create( # pyright: ignore[reportDeprecated] - thread_id=thread_id, - assistant_id=assistant_id, - include=include, - additional_instructions=additional_instructions, - additional_messages=additional_messages, - instructions=instructions, - max_completion_tokens=max_completion_tokens, - max_prompt_tokens=max_prompt_tokens, - metadata=metadata, - model=model, - response_format=response_format, - temperature=temperature, - tool_choice=tool_choice, - parallel_tool_calls=parallel_tool_calls, - reasoning_effort=reasoning_effort, - # We assume we are not streaming when polling - stream=False, - tools=tools, - truncation_strategy=truncation_strategy, - top_p=top_p, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return self.poll( # pyright: ignore[reportDeprecated] - run.id, - thread_id=thread_id, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - poll_interval_ms=poll_interval_ms, - timeout=timeout, - ) - - @overload - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler]: - """Create a Run stream""" - ... - - @overload - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandlerT]: - """Create a Run stream""" - ... - - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]: - """Create a Run stream""" - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - make_request = partial( - self._post, - f"/threads/{thread_id}/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "tools": tools, - "truncation_strategy": truncation_strategy, - "parallel_tool_calls": parallel_tool_calls, - "reasoning_effort": reasoning_effort, - "top_p": top_p, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=Stream[AssistantStreamEvent], - ) - return AssistantStreamManager(make_request, event_handler=event_handler or AssistantEventHandler()) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def poll( - self, - run_id: str, - thread_id: str, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - poll_interval_ms: int | Omit = omit, - ) -> Run: - """ - A helper to poll a run status until it reaches a terminal state. More - information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - extra_headers = {"X-Stainless-Poll-Helper": "true", **(extra_headers or {})} - - if is_given(poll_interval_ms): - extra_headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} - while True: - response = self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] - thread_id=thread_id, - run_id=run_id, - extra_headers=extra_headers, - extra_body=extra_body, - extra_query=extra_query, - timeout=timeout, - ) - - run = response.parse() - # Return if we reached a terminal state - if run.status in terminal_states: - return run - - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - self._sleep(poll_interval_ms / 1000) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler]: - """Create a Run stream""" - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandlerT]: - """Create a Run stream""" - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]: - """Create a Run stream""" - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - make_request = partial( - self._post, - f"/threads/{thread_id}/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "tools": tools, - "parallel_tool_calls": parallel_tool_calls, - "reasoning_effort": reasoning_effort, - "truncation_strategy": truncation_strategy, - "top_p": top_p, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, run_create_params.RunCreateParams), - ), - cast_to=Run, - stream=True, - stream_cls=Stream[AssistantStreamEvent], - ) - return AssistantStreamManager(make_request, event_handler=event_handler or AssistantEventHandler()) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - tool_outputs: A list of tools for which the outputs are being submitted. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - stream: Literal[True], - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[AssistantStreamEvent]: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - tool_outputs: A list of tools for which the outputs are being submitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - stream: bool, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - tool_outputs: A list of tools for which the outputs are being submitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["thread_id", "tool_outputs"], ["thread_id", "stream", "tool_outputs"]) - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", - body=maybe_transform( - { - "tool_outputs": tool_outputs, - "stream": stream, - }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParamsStreaming - if stream - else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=stream or False, - stream_cls=Stream[AssistantStreamEvent], - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_and_poll( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to submit a tool output to a run and poll for a terminal run state. - More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = self.submit_tool_outputs( # pyright: ignore[reportDeprecated] - run_id=run_id, - thread_id=thread_id, - tool_outputs=tool_outputs, - stream=False, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return self.poll( # pyright: ignore[reportDeprecated] - run_id=run.id, - thread_id=thread_id, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - poll_interval_ms=poll_interval_ms, - ) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler]: - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - event_handler: AssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandlerT]: - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - event_handler: AssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]: - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.submit_tool_outputs_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - request = partial( - self._post, - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", - body=maybe_transform( - { - "tool_outputs": tool_outputs, - "stream": True, - }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=Stream[AssistantStreamEvent], - ) - return AssistantStreamManager(request, event_handler=event_handler or AssistantEventHandler()) - - -class AsyncRuns(AsyncAPIResource): - @cached_property - def steps(self) -> AsyncSteps: - return AsyncSteps(self._client) - - @cached_property - def with_raw_response(self) -> AsyncRunsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncRunsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRunsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncRunsWithStreamingResponse(self) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - thread_id: str, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - thread_id: str, - *, - assistant_id: str, - stream: Literal[True], - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[AssistantStreamEvent]: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - thread_id: str, - *, - assistant_id: str, - stream: bool, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - """ - Create a run. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - additional_instructions: Appends additional instructions at the end of the instructions for the run. This - is useful for modifying the behavior on a per-run basis without overriding other - instructions. - - additional_messages: Adds additional messages to the thread before creating the run. - - instructions: Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["assistant_id"], ["assistant_id", "stream"]) - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - thread_id: str, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/runs", - body=await async_maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_p": top_p, - "truncation_strategy": truncation_strategy, - }, - run_create_params.RunCreateParamsStreaming if stream else run_create_params.RunCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"include": include}, run_create_params.RunCreateParams), - ), - cast_to=Run, - stream=stream or False, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def retrieve( - self, - run_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Retrieves a run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/threads/{thread_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def update( - self, - run_id: str, - *, - thread_id: str, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Modifies a run. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/runs/{run_id}", - body=await async_maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - thread_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Run, AsyncCursorPage[Run]]: - """ - Returns a list of runs belonging to a thread. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/runs", - page=AsyncCursorPage[Run], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - run_list_params.RunListParams, - ), - ), - model=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def cancel( - self, - run_id: str, - *, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Cancels a run that is `in_progress`. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create_and_poll( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - poll_interval_ms: int | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to create a run an poll for a terminal state. More information on Run - lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = await self.create( # pyright: ignore[reportDeprecated] - thread_id=thread_id, - assistant_id=assistant_id, - include=include, - additional_instructions=additional_instructions, - additional_messages=additional_messages, - instructions=instructions, - max_completion_tokens=max_completion_tokens, - max_prompt_tokens=max_prompt_tokens, - metadata=metadata, - model=model, - response_format=response_format, - temperature=temperature, - tool_choice=tool_choice, - parallel_tool_calls=parallel_tool_calls, - reasoning_effort=reasoning_effort, - # We assume we are not streaming when polling - stream=False, - tools=tools, - truncation_strategy=truncation_strategy, - top_p=top_p, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return await self.poll( # pyright: ignore[reportDeprecated] - run.id, - thread_id=thread_id, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - poll_interval_ms=poll_interval_ms, - timeout=timeout, - ) - - @overload - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]: - """Create a Run stream""" - ... - - @overload - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]: - """Create a Run stream""" - ... - - @typing_extensions.deprecated("use `stream` instead") - def create_and_stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ( - AsyncAssistantStreamManager[AsyncAssistantEventHandler] - | AsyncAssistantStreamManager[AsyncAssistantEventHandlerT] - ): - """Create a Run stream""" - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - request = self._post( - f"/threads/{thread_id}/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "tools": tools, - "truncation_strategy": truncation_strategy, - "top_p": top_p, - "parallel_tool_calls": parallel_tool_calls, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def poll( - self, - run_id: str, - thread_id: str, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - poll_interval_ms: int | Omit = omit, - ) -> Run: - """ - A helper to poll a run status until it reaches a terminal state. More - information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - extra_headers = {"X-Stainless-Poll-Helper": "true", **(extra_headers or {})} - - if is_given(poll_interval_ms): - extra_headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} - while True: - response = await self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] - thread_id=thread_id, - run_id=run_id, - extra_headers=extra_headers, - extra_body=extra_body, - extra_query=extra_query, - timeout=timeout, - ) - - run = response.parse() - # Return if we reached a terminal state - if run.status in terminal_states: - return run - - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - await self._sleep(poll_interval_ms / 1000) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]: - """Create a Run stream""" - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]: - """Create a Run stream""" - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def stream( - self, - *, - assistant_id: str, - include: List[RunStepInclude] | Omit = omit, - additional_instructions: Optional[str] | Omit = omit, - additional_messages: Optional[Iterable[run_create_params.AdditionalMessage]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[run_create_params.TruncationStrategy] | Omit = omit, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ( - AsyncAssistantStreamManager[AsyncAssistantEventHandler] - | AsyncAssistantStreamManager[AsyncAssistantEventHandlerT] - ): - """Create a Run stream""" - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - request = self._post( - f"/threads/{thread_id}/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "additional_instructions": additional_instructions, - "additional_messages": additional_messages, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "tools": tools, - "parallel_tool_calls": parallel_tool_calls, - "reasoning_effort": reasoning_effort, - "truncation_strategy": truncation_strategy, - "top_p": top_p, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, run_create_params.RunCreateParams), - ), - cast_to=Run, - stream=True, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - tool_outputs: A list of tools for which the outputs are being submitted. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - stream: Literal[True], - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[AssistantStreamEvent]: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - tool_outputs: A list of tools for which the outputs are being submitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - stream: bool, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - """ - When a run has the `status: "requires_action"` and `required_action.type` is - `submit_tool_outputs`, this endpoint can be used to submit the outputs from the - tool calls once they're all completed. All outputs must be submitted in a single - request. - - Args: - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - tool_outputs: A list of tools for which the outputs are being submitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["thread_id", "tool_outputs"], ["thread_id", "stream", "tool_outputs"]) - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def submit_tool_outputs( - self, - run_id: str, - *, - thread_id: str, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", - body=await async_maybe_transform( - { - "tool_outputs": tool_outputs, - "stream": stream, - }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParamsStreaming - if stream - else run_submit_tool_outputs_params.RunSubmitToolOutputsParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=stream or False, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def submit_tool_outputs_and_poll( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to submit a tool output to a run and poll for a terminal run state. - More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = await self.submit_tool_outputs( # pyright: ignore[reportDeprecated] - run_id=run_id, - thread_id=thread_id, - tool_outputs=tool_outputs, - stream=False, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return await self.poll( # pyright: ignore[reportDeprecated] - run_id=run.id, - thread_id=thread_id, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - poll_interval_ms=poll_interval_ms, - ) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]: - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]: - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def submit_tool_outputs_stream( - self, - *, - tool_outputs: Iterable[run_submit_tool_outputs_params.ToolOutput], - run_id: str, - thread_id: str, - event_handler: AsyncAssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ( - AsyncAssistantStreamManager[AsyncAssistantEventHandler] - | AsyncAssistantStreamManager[AsyncAssistantEventHandlerT] - ): - """ - Submit the tool outputs from a previous run and stream the run to a terminal - state. More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.runs.submit_tool_outputs_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - request = self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", - body=maybe_transform( - { - "tool_outputs": tool_outputs, - "stream": True, - }, - run_submit_tool_outputs_params.RunSubmitToolOutputsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) - - -class RunsWithRawResponse: - def __init__(self, runs: Runs) -> None: - self._runs = runs - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) - ) - self.cancel = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) - ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def steps(self) -> StepsWithRawResponse: - return StepsWithRawResponse(self._runs.steps) - - -class AsyncRunsWithRawResponse: - def __init__(self, runs: AsyncRuns) -> None: - self._runs = runs - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) - ) - self.cancel = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) - ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def steps(self) -> AsyncStepsWithRawResponse: - return AsyncStepsWithRawResponse(self._runs.steps) - - -class RunsWithStreamingResponse: - def __init__(self, runs: Runs) -> None: - self._runs = runs - - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) - ) - self.cancel = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) - ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def steps(self) -> StepsWithStreamingResponse: - return StepsWithStreamingResponse(self._runs.steps) - - -class AsyncRunsWithStreamingResponse: - def __init__(self, runs: AsyncRuns) -> None: - self._runs = runs - - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) - ) - self.cancel = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) - ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def steps(self) -> AsyncStepsWithStreamingResponse: - return AsyncStepsWithStreamingResponse(self._runs.steps) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/steps.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/steps.py deleted file mode 100644 index 254a944..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/runs/steps.py +++ /dev/null @@ -1,399 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import typing_extensions -from typing import List -from typing_extensions import Literal - -import httpx - -from ..... import _legacy_response -from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .....pagination import SyncCursorPage, AsyncCursorPage -from ....._base_client import AsyncPaginator, make_request_options -from .....types.beta.threads.runs import step_list_params, step_retrieve_params -from .....types.beta.threads.runs.run_step import RunStep -from .....types.beta.threads.runs.run_step_include import RunStepInclude - -__all__ = ["Steps", "AsyncSteps"] - - -class Steps(SyncAPIResource): - @cached_property - def with_raw_response(self) -> StepsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return StepsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> StepsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return StepsWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def retrieve( - self, - step_id: str, - *, - thread_id: str, - run_id: str, - include: List[RunStepInclude] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunStep: - """ - Retrieves a run step. - - Args: - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - if not step_id: - raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, step_retrieve_params.StepRetrieveParams), - ), - cast_to=RunStep, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - run_id: str, - *, - thread_id: str, - after: str | Omit = omit, - before: str | Omit = omit, - include: List[RunStepInclude] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RunStep]: - """ - Returns a list of run steps belonging to a run. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", - page=SyncCursorPage[RunStep], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "include": include, - "limit": limit, - "order": order, - }, - step_list_params.StepListParams, - ), - ), - model=RunStep, - ) - - -class AsyncSteps(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncStepsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncStepsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncStepsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncStepsWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def retrieve( - self, - step_id: str, - *, - thread_id: str, - run_id: str, - include: List[RunStepInclude] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunStep: - """ - Retrieves a run step. - - Args: - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - if not step_id: - raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"include": include}, step_retrieve_params.StepRetrieveParams), - ), - cast_to=RunStep, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def list( - self, - run_id: str, - *, - thread_id: str, - after: str | Omit = omit, - before: str | Omit = omit, - include: List[RunStepInclude] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RunStep, AsyncCursorPage[RunStep]]: - """ - Returns a list of run steps belonging to a run. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - include: A list of additional fields to include in the response. Currently the only - supported value is `step_details.tool_calls[*].file_search.results[*].content` - to fetch the file search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", - page=AsyncCursorPage[RunStep], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "include": include, - "limit": limit, - "order": order, - }, - step_list_params.StepListParams, - ), - ), - model=RunStep, - ) - - -class StepsWithRawResponse: - def __init__(self, steps: Steps) -> None: - self._steps = steps - - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncStepsWithRawResponse: - def __init__(self, steps: AsyncSteps) -> None: - self._steps = steps - - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) - ) - - -class StepsWithStreamingResponse: - def __init__(self, steps: Steps) -> None: - self._steps = steps - - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncStepsWithStreamingResponse: - def __init__(self, steps: AsyncSteps) -> None: - self._steps = steps - - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/threads.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/threads.py deleted file mode 100644 index 681d3c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/beta/threads/threads.py +++ /dev/null @@ -1,1935 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import typing_extensions -from typing import Union, Iterable, Optional -from functools import partial -from typing_extensions import Literal, overload - -import httpx - -from .... import _legacy_response -from .messages import ( - Messages, - AsyncMessages, - MessagesWithRawResponse, - AsyncMessagesWithRawResponse, - MessagesWithStreamingResponse, - AsyncMessagesWithStreamingResponse, -) -from ...._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform -from .runs.runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._streaming import Stream, AsyncStream -from ....types.beta import ( - thread_create_params, - thread_update_params, - thread_create_and_run_params, -) -from ...._base_client import make_request_options -from ....lib.streaming import ( - AssistantEventHandler, - AssistantEventHandlerT, - AssistantStreamManager, - AsyncAssistantEventHandler, - AsyncAssistantEventHandlerT, - AsyncAssistantStreamManager, -) -from ....types.beta.thread import Thread -from ....types.beta.threads.run import Run -from ....types.shared.chat_model import ChatModel -from ....types.beta.thread_deleted import ThreadDeleted -from ....types.shared_params.metadata import Metadata -from ....types.beta.assistant_tool_param import AssistantToolParam -from ....types.beta.assistant_stream_event import AssistantStreamEvent -from ....types.beta.assistant_tool_choice_option_param import AssistantToolChoiceOptionParam -from ....types.beta.assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = ["Threads", "AsyncThreads"] - - -class Threads(SyncAPIResource): - @cached_property - def runs(self) -> Runs: - return Runs(self._client) - - @cached_property - def messages(self) -> Messages: - return Messages(self._client) - - @cached_property - def with_raw_response(self) -> ThreadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ThreadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ThreadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ThreadsWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create( - self, - *, - messages: Iterable[thread_create_params.Message] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - tool_resources: Optional[thread_create_params.ToolResources] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Create a thread. - - Args: - messages: A list of [messages](https://platform.openai.com/docs/api-reference/messages) to - start the thread with. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - tool_resources: A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/threads", - body=maybe_transform( - { - "messages": messages, - "metadata": metadata, - "tool_resources": tool_resources, - }, - thread_create_params.ThreadCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def retrieve( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Retrieves a thread. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def update( - self, - thread_id: str, - *, - metadata: Optional[Metadata] | Omit = omit, - tool_resources: Optional[thread_update_params.ToolResources] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Modifies a thread. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - tool_resources: A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/threads/{thread_id}", - body=maybe_transform( - { - "metadata": metadata, - "tool_resources": tool_resources, - }, - thread_update_params.ThreadUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def delete( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ThreadDeleted: - """ - Delete a thread. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._delete( - f"/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ThreadDeleted, - ) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create_and_run( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create_and_run( - self, - *, - assistant_id: str, - stream: Literal[True], - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[AssistantStreamEvent]: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create_and_run( - self, - *, - assistant_id: str, - stream: bool, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["assistant_id"], ["assistant_id", "stream"]) - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - def create_and_run( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | Stream[AssistantStreamEvent]: - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/threads/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "thread": thread, - "tool_choice": tool_choice, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - "truncation_strategy": truncation_strategy, - }, - thread_create_and_run_params.ThreadCreateAndRunParamsStreaming - if stream - else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=stream or False, - stream_cls=Stream[AssistantStreamEvent], - ) - - def create_and_run_poll( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to create a thread, start a run and then poll for a terminal state. - More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = self.create_and_run( # pyright: ignore[reportDeprecated] - assistant_id=assistant_id, - instructions=instructions, - max_completion_tokens=max_completion_tokens, - max_prompt_tokens=max_prompt_tokens, - metadata=metadata, - model=model, - parallel_tool_calls=parallel_tool_calls, - response_format=response_format, - temperature=temperature, - stream=False, - thread=thread, - tool_resources=tool_resources, - tool_choice=tool_choice, - truncation_strategy=truncation_strategy, - top_p=top_p, - tools=tools, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return self.runs.poll(run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms) # pyright: ignore[reportDeprecated] - - @overload - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler]: - """Create a thread and stream the run back""" - ... - - @overload - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - event_handler: AssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandlerT]: - """Create a thread and stream the run back""" - ... - - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - event_handler: AssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]: - """Create a thread and stream the run back""" - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.create_and_run_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - make_request = partial( - self._post, - "/threads/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "thread": thread, - "tools": tools, - "tool_resources": tool_resources, - "truncation_strategy": truncation_strategy, - "top_p": top_p, - }, - thread_create_and_run_params.ThreadCreateAndRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=Stream[AssistantStreamEvent], - ) - return AssistantStreamManager(make_request, event_handler=event_handler or AssistantEventHandler()) - - -class AsyncThreads(AsyncAPIResource): - @cached_property - def runs(self) -> AsyncRuns: - return AsyncRuns(self._client) - - @cached_property - def messages(self) -> AsyncMessages: - return AsyncMessages(self._client) - - @cached_property - def with_raw_response(self) -> AsyncThreadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncThreadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncThreadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncThreadsWithStreamingResponse(self) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create( - self, - *, - messages: Iterable[thread_create_params.Message] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - tool_resources: Optional[thread_create_params.ToolResources] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Create a thread. - - Args: - messages: A list of [messages](https://platform.openai.com/docs/api-reference/messages) to - start the thread with. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - tool_resources: A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/threads", - body=await async_maybe_transform( - { - "messages": messages, - "metadata": metadata, - "tool_resources": tool_resources, - }, - thread_create_params.ThreadCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def retrieve( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Retrieves a thread. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def update( - self, - thread_id: str, - *, - metadata: Optional[Metadata] | Omit = omit, - tool_resources: Optional[thread_update_params.ToolResources] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Thread: - """ - Modifies a thread. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - tool_resources: A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/threads/{thread_id}", - body=await async_maybe_transform( - { - "metadata": metadata, - "tool_resources": tool_resources, - }, - thread_update_params.ThreadUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Thread, - ) - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def delete( - self, - thread_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ThreadDeleted: - """ - Delete a thread. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._delete( - f"/threads/{thread_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ThreadDeleted, - ) - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create_and_run( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create_and_run( - self, - *, - assistant_id: str, - stream: Literal[True], - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[AssistantStreamEvent]: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create_and_run( - self, - *, - assistant_id: str, - stream: bool, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - """ - Create a thread and run it in one request. - - Args: - assistant_id: The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - - stream: If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - - instructions: Override the default system message of the assistant. This is useful for - modifying the behavior on a per-run basis. - - max_completion_tokens: The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - response_format: Specifies the format that the model must output. Compatible with - [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - thread: Options to create a new thread. If no thread is provided when running a request, - an empty thread will be created. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - tool_resources: A set of resources that are used by the assistant's tools. The resources are - specific to the type of tool. For example, the `code_interpreter` tool requires - a list of file IDs, while the `file_search` tool requires a list of vector store - IDs. - - tools: Override the tools the assistant can use for this run. This is useful for - modifying the behavior on a per-run basis. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - - truncation_strategy: Controls for how a thread will be truncated prior to the run. Use this to - control the initial context window of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - @required_args(["assistant_id"], ["assistant_id", "stream"]) - @typing_extensions.deprecated("The Assistants API is deprecated in favor of the Responses API") - async def create_and_run( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Run | AsyncStream[AssistantStreamEvent]: - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/threads/runs", - body=await async_maybe_transform( - { - "assistant_id": assistant_id, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "response_format": response_format, - "stream": stream, - "temperature": temperature, - "thread": thread, - "tool_choice": tool_choice, - "tool_resources": tool_resources, - "tools": tools, - "top_p": top_p, - "truncation_strategy": truncation_strategy, - }, - thread_create_and_run_params.ThreadCreateAndRunParamsStreaming - if stream - else thread_create_and_run_params.ThreadCreateAndRunParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=stream or False, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - - async def create_and_run_poll( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Run: - """ - A helper to create a thread, start a run and then poll for a terminal state. - More information on Run lifecycles can be found here: - https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps - """ - run = await self.create_and_run( # pyright: ignore[reportDeprecated] - assistant_id=assistant_id, - instructions=instructions, - max_completion_tokens=max_completion_tokens, - max_prompt_tokens=max_prompt_tokens, - metadata=metadata, - model=model, - parallel_tool_calls=parallel_tool_calls, - response_format=response_format, - temperature=temperature, - stream=False, - thread=thread, - tool_resources=tool_resources, - tool_choice=tool_choice, - truncation_strategy=truncation_strategy, - top_p=top_p, - tools=tools, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return await self.runs.poll( # pyright: ignore[reportDeprecated] - run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms - ) - - @overload - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandler]: - """Create a thread and stream the run back""" - ... - - @overload - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - event_handler: AsyncAssistantEventHandlerT, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncAssistantStreamManager[AsyncAssistantEventHandlerT]: - """Create a thread and stream the run back""" - ... - - def create_and_run_stream( - self, - *, - assistant_id: str, - instructions: Optional[str] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_prompt_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: Union[str, ChatModel, None] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - response_format: Optional[AssistantResponseFormatOptionParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - thread: thread_create_and_run_params.Thread | Omit = omit, - tool_choice: Optional[AssistantToolChoiceOptionParam] | Omit = omit, - tool_resources: Optional[thread_create_and_run_params.ToolResources] | Omit = omit, - tools: Optional[Iterable[AssistantToolParam]] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation_strategy: Optional[thread_create_and_run_params.TruncationStrategy] | Omit = omit, - event_handler: AsyncAssistantEventHandlerT | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ( - AsyncAssistantStreamManager[AsyncAssistantEventHandler] - | AsyncAssistantStreamManager[AsyncAssistantEventHandlerT] - ): - """Create a thread and stream the run back""" - extra_headers = { - "OpenAI-Beta": "assistants=v2", - "X-Stainless-Stream-Helper": "threads.create_and_run_stream", - "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", - **(extra_headers or {}), - } - request = self._post( - "/threads/runs", - body=maybe_transform( - { - "assistant_id": assistant_id, - "instructions": instructions, - "max_completion_tokens": max_completion_tokens, - "max_prompt_tokens": max_prompt_tokens, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "response_format": response_format, - "temperature": temperature, - "tool_choice": tool_choice, - "stream": True, - "thread": thread, - "tools": tools, - "tool_resources": tool_resources, - "truncation_strategy": truncation_strategy, - "top_p": top_p, - }, - thread_create_and_run_params.ThreadCreateAndRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Run, - stream=True, - stream_cls=AsyncStream[AssistantStreamEvent], - ) - return AsyncAssistantStreamManager(request, event_handler=event_handler or AsyncAssistantEventHandler()) - - -class ThreadsWithRawResponse: - def __init__(self, threads: Threads) -> None: - self._threads = threads - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) - ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def runs(self) -> RunsWithRawResponse: - return RunsWithRawResponse(self._threads.runs) - - @cached_property - def messages(self) -> MessagesWithRawResponse: - return MessagesWithRawResponse(self._threads.messages) - - -class AsyncThreadsWithRawResponse: - def __init__(self, threads: AsyncThreads) -> None: - self._threads = threads - - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) - ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def runs(self) -> AsyncRunsWithRawResponse: - return AsyncRunsWithRawResponse(self._threads.runs) - - @cached_property - def messages(self) -> AsyncMessagesWithRawResponse: - return AsyncMessagesWithRawResponse(self._threads.messages) - - -class ThreadsWithStreamingResponse: - def __init__(self, threads: Threads) -> None: - self._threads = threads - - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) - ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def runs(self) -> RunsWithStreamingResponse: - return RunsWithStreamingResponse(self._threads.runs) - - @cached_property - def messages(self) -> MessagesWithStreamingResponse: - return MessagesWithStreamingResponse(self._threads.messages) - - -class AsyncThreadsWithStreamingResponse: - def __init__(self, threads: AsyncThreads) -> None: - self._threads = threads - - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) - ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) - ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) - ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) - ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) - ) - - @cached_property - def runs(self) -> AsyncRunsWithStreamingResponse: - return AsyncRunsWithStreamingResponse(self._threads.runs) - - @cached_property - def messages(self) -> AsyncMessagesWithStreamingResponse: - return AsyncMessagesWithStreamingResponse(self._threads.messages) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/__init__.py deleted file mode 100644 index 52dfdce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .chat import ( - Chat, - AsyncChat, - ChatWithRawResponse, - AsyncChatWithRawResponse, - ChatWithStreamingResponse, - AsyncChatWithStreamingResponse, -) -from .completions import ( - Completions, - AsyncCompletions, - CompletionsWithRawResponse, - AsyncCompletionsWithRawResponse, - CompletionsWithStreamingResponse, - AsyncCompletionsWithStreamingResponse, -) - -__all__ = [ - "Completions", - "AsyncCompletions", - "CompletionsWithRawResponse", - "AsyncCompletionsWithRawResponse", - "CompletionsWithStreamingResponse", - "AsyncCompletionsWithStreamingResponse", - "Chat", - "AsyncChat", - "ChatWithRawResponse", - "AsyncChatWithRawResponse", - "ChatWithStreamingResponse", - "AsyncChatWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/chat.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/chat.py deleted file mode 100644 index 14f9224..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/chat.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from .completions.completions import ( - Completions, - AsyncCompletions, - CompletionsWithRawResponse, - AsyncCompletionsWithRawResponse, - CompletionsWithStreamingResponse, - AsyncCompletionsWithStreamingResponse, -) - -__all__ = ["Chat", "AsyncChat"] - - -class Chat(SyncAPIResource): - @cached_property - def completions(self) -> Completions: - return Completions(self._client) - - @cached_property - def with_raw_response(self) -> ChatWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ChatWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ChatWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ChatWithStreamingResponse(self) - - -class AsyncChat(AsyncAPIResource): - @cached_property - def completions(self) -> AsyncCompletions: - return AsyncCompletions(self._client) - - @cached_property - def with_raw_response(self) -> AsyncChatWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncChatWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncChatWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncChatWithStreamingResponse(self) - - -class ChatWithRawResponse: - def __init__(self, chat: Chat) -> None: - self._chat = chat - - @cached_property - def completions(self) -> CompletionsWithRawResponse: - return CompletionsWithRawResponse(self._chat.completions) - - -class AsyncChatWithRawResponse: - def __init__(self, chat: AsyncChat) -> None: - self._chat = chat - - @cached_property - def completions(self) -> AsyncCompletionsWithRawResponse: - return AsyncCompletionsWithRawResponse(self._chat.completions) - - -class ChatWithStreamingResponse: - def __init__(self, chat: Chat) -> None: - self._chat = chat - - @cached_property - def completions(self) -> CompletionsWithStreamingResponse: - return CompletionsWithStreamingResponse(self._chat.completions) - - -class AsyncChatWithStreamingResponse: - def __init__(self, chat: AsyncChat) -> None: - self._chat = chat - - @cached_property - def completions(self) -> AsyncCompletionsWithStreamingResponse: - return AsyncCompletionsWithStreamingResponse(self._chat.completions) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/__init__.py deleted file mode 100644 index 12d3b3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .messages import ( - Messages, - AsyncMessages, - MessagesWithRawResponse, - AsyncMessagesWithRawResponse, - MessagesWithStreamingResponse, - AsyncMessagesWithStreamingResponse, -) -from .completions import ( - Completions, - AsyncCompletions, - CompletionsWithRawResponse, - AsyncCompletionsWithRawResponse, - CompletionsWithStreamingResponse, - AsyncCompletionsWithStreamingResponse, -) - -__all__ = [ - "Messages", - "AsyncMessages", - "MessagesWithRawResponse", - "AsyncMessagesWithRawResponse", - "MessagesWithStreamingResponse", - "AsyncMessagesWithStreamingResponse", - "Completions", - "AsyncCompletions", - "CompletionsWithRawResponse", - "AsyncCompletionsWithRawResponse", - "CompletionsWithStreamingResponse", - "AsyncCompletionsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/completions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/completions.py deleted file mode 100644 index 9c0b74b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/completions.py +++ /dev/null @@ -1,3149 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import inspect -from typing import Dict, List, Type, Union, Iterable, Optional, cast -from functools import partial -from typing_extensions import Literal, overload - -import httpx -import pydantic - -from .... import _legacy_response -from .messages import ( - Messages, - AsyncMessages, - MessagesWithRawResponse, - AsyncMessagesWithRawResponse, - MessagesWithStreamingResponse, - AsyncMessagesWithStreamingResponse, -) -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._streaming import Stream, AsyncStream -from ....pagination import SyncCursorPage, AsyncCursorPage -from ....types.chat import ( - ChatCompletionAudioParam, - completion_list_params, - completion_create_params, - completion_update_params, -) -from ...._base_client import AsyncPaginator, make_request_options -from ....lib._parsing import ( - ResponseFormatT, - validate_input_tools as _validate_input_tools, - parse_chat_completion as _parse_chat_completion, - type_to_response_format_param as _type_to_response_format, -) -from ....lib.streaming.chat import ChatCompletionStreamManager, AsyncChatCompletionStreamManager -from ....types.shared.chat_model import ChatModel -from ....types.chat.chat_completion import ChatCompletion -from ....types.shared_params.metadata import Metadata -from ....types.shared.reasoning_effort import ReasoningEffort -from ....types.chat.chat_completion_chunk import ChatCompletionChunk -from ....types.chat.parsed_chat_completion import ParsedChatCompletion -from ....types.chat.chat_completion_deleted import ChatCompletionDeleted -from ....types.chat.chat_completion_audio_param import ChatCompletionAudioParam -from ....types.chat.chat_completion_message_param import ChatCompletionMessageParam -from ....types.chat.chat_completion_tool_union_param import ChatCompletionToolUnionParam -from ....types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam -from ....types.chat.chat_completion_prediction_content_param import ChatCompletionPredictionContentParam -from ....types.chat.chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam - -__all__ = ["Completions", "AsyncCompletions"] - - -class Completions(SyncAPIResource): - @cached_property - def messages(self) -> Messages: - return Messages(self._client) - - @cached_property - def with_raw_response(self) -> CompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CompletionsWithStreamingResponse(self) - - def parse( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - response_format: type[ResponseFormatT] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ParsedChatCompletion[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types - & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. - - You can pass a pydantic model to this method and it will automatically convert the model - into a JSON schema, send it to the API and parse the response content back into the given model. - - This method will also automatically parse `function` tool calls if: - - You use the `openai.pydantic_function_tool()` helper method - - You mark your tool schema with `"strict": True` - - Example usage: - ```py - from pydantic import BaseModel - from openai import OpenAI - - - class Step(BaseModel): - explanation: str - output: str - - - class MathResponse(BaseModel): - steps: List[Step] - final_answer: str - - - client = OpenAI() - completion = client.chat.completions.parse( - model="gpt-4o-2024-08-06", - messages=[ - {"role": "system", "content": "You are a helpful math tutor."}, - {"role": "user", "content": "solve 8x + 31 = 2"}, - ], - response_format=MathResponse, - ) - - message = completion.choices[0].message - if message.parsed: - print(message.parsed.steps) - print("answer: ", message.parsed.final_answer) - ``` - """ - chat_completion_tools = _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "chat.completions.parse", - **(extra_headers or {}), - } - - def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=chat_completion_tools, - ) - - return self._post( - "/chat/completions", - body=maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning_effort": reasoning_effort, - "response_format": _type_to_response_format(response_format), - "safety_identifier": safety_identifier, - "seed": seed, - "service_tier": service_tier, - "stop": stop, - "store": store, - "stream": False, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "verbosity": verbosity, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` - # in the `parser` function above - cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), - stream=False, - ) - - @overload - def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - stream: Literal[True], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[ChatCompletionChunk]: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - stream: bool, - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion | Stream[ChatCompletionChunk]: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["messages", "model"], ["messages", "model", "stream"]) - def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion | Stream[ChatCompletionChunk]: - validate_response_format(response_format) - return self._post( - "/chat/completions", - body=maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "safety_identifier": safety_identifier, - "seed": seed, - "service_tier": service_tier, - "stop": stop, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "verbosity": verbosity, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParamsStreaming - if stream - else completion_create_params.CompletionCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - stream=stream or False, - stream_cls=Stream[ChatCompletionChunk], - ) - - def retrieve( - self, - completion_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """Get a stored chat completion. - - Only Chat Completions that have been created with - the `store` parameter set to `true` will be returned. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return self._get( - f"/chat/completions/{completion_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - ) - - def update( - self, - completion_id: str, - *, - metadata: Optional[Metadata], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """Modify a stored chat completion. - - Only Chat Completions that have been created - with the `store` parameter set to `true` can be modified. Currently, the only - supported modification is to update the `metadata` field. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return self._post( - f"/chat/completions/{completion_id}", - body=maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: str | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ChatCompletion]: - """List stored Chat Completions. - - Only Chat Completions that have been stored with - the `store` parameter set to `true` will be returned. - - Args: - after: Identifier for the last chat completion from the previous pagination request. - - limit: Number of Chat Completions to retrieve. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The model used to generate the Chat Completions. - - order: Sort order for Chat Completions by timestamp. Use `asc` for ascending order or - `desc` for descending order. Defaults to `asc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/chat/completions", - page=SyncCursorPage[ChatCompletion], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "metadata": metadata, - "model": model, - "order": order, - }, - completion_list_params.CompletionListParams, - ), - ), - model=ChatCompletion, - ) - - def delete( - self, - completion_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletionDeleted: - """Delete a stored chat completion. - - Only Chat Completions that have been created - with the `store` parameter set to `true` can be deleted. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return self._delete( - f"/chat/completions/{completion_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletionDeleted, - ) - - def stream( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletionStreamManager[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API - and automatic accumulation of each delta. - - This also supports all of the parsing utilities that `.parse()` does. - - Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: - - ```py - with client.chat.completions.stream( - model="gpt-4o-2024-08-06", - messages=[...], - ) as stream: - for event in stream: - if event.type == "content.delta": - print(event.delta, flush=True, end="") - ``` - - When the context manager is entered, a `ChatCompletionStream` instance is returned which, like `.create(stream=True)` is an iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). - - When the context manager exits, the response will be closed, however the `stream` instance is still available outside - the context manager. - """ - extra_headers = { - "X-Stainless-Helper-Method": "chat.completions.stream", - **(extra_headers or {}), - } - - api_request: partial[Stream[ChatCompletionChunk]] = partial( - self.create, - messages=messages, - model=model, - audio=audio, - stream=True, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - metadata=metadata, - modalities=modalities, - n=n, - parallel_tool_calls=parallel_tool_calls, - prediction=prediction, - presence_penalty=presence_penalty, - prompt_cache_key=prompt_cache_key, - prompt_cache_retention=prompt_cache_retention, - reasoning_effort=reasoning_effort, - safety_identifier=safety_identifier, - seed=seed, - service_tier=service_tier, - store=store, - stop=stop, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - verbosity=verbosity, - web_search_options=web_search_options, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return ChatCompletionStreamManager( - api_request, - response_format=response_format, - input_tools=tools, - ) - - -class AsyncCompletions(AsyncAPIResource): - @cached_property - def messages(self) -> AsyncMessages: - return AsyncMessages(self._client) - - @cached_property - def with_raw_response(self) -> AsyncCompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCompletionsWithStreamingResponse(self) - - async def parse( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - response_format: type[ResponseFormatT] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ParsedChatCompletion[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create()` method that provides richer integrations with Python specific types - & returns a `ParsedChatCompletion` object, which is a subclass of the standard `ChatCompletion` class. - - You can pass a pydantic model to this method and it will automatically convert the model - into a JSON schema, send it to the API and parse the response content back into the given model. - - This method will also automatically parse `function` tool calls if: - - You use the `openai.pydantic_function_tool()` helper method - - You mark your tool schema with `"strict": True` - - Example usage: - ```py - from pydantic import BaseModel - from openai import AsyncOpenAI - - - class Step(BaseModel): - explanation: str - output: str - - - class MathResponse(BaseModel): - steps: List[Step] - final_answer: str - - - client = AsyncOpenAI() - completion = await client.chat.completions.parse( - model="gpt-4o-2024-08-06", - messages=[ - {"role": "system", "content": "You are a helpful math tutor."}, - {"role": "user", "content": "solve 8x + 31 = 2"}, - ], - response_format=MathResponse, - ) - - message = completion.choices[0].message - if message.parsed: - print(message.parsed.steps) - print("answer: ", message.parsed.final_answer) - ``` - """ - _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "chat.completions.parse", - **(extra_headers or {}), - } - - def parser(raw_completion: ChatCompletion) -> ParsedChatCompletion[ResponseFormatT]: - return _parse_chat_completion( - response_format=response_format, - chat_completion=raw_completion, - input_tools=tools, - ) - - return await self._post( - "/chat/completions", - body=await async_maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning_effort": reasoning_effort, - "response_format": _type_to_response_format(response_format), - "safety_identifier": safety_identifier, - "seed": seed, - "service_tier": service_tier, - "store": store, - "stop": stop, - "stream": False, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "verbosity": verbosity, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `ChatCompletion` instance into a `ParsedChatCompletion` - # in the `parser` function above - cast_to=cast(Type[ParsedChatCompletion[ResponseFormatT]], ChatCompletion), - stream=False, - ) - - @overload - async def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - stream: Literal[True], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[ChatCompletionChunk]: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - stream: bool, - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: - """ - **Starting a new project?** We recommend trying - [Responses](https://platform.openai.com/docs/api-reference/responses) to take - advantage of the latest OpenAI platform features. Compare - [Chat Completions with Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions?api-mode=responses). - - --- - - Creates a model response for the given chat conversation. Learn more in the - [text generation](https://platform.openai.com/docs/guides/text-generation), - [vision](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio) guides. - - Parameter support can differ depending on the model used to generate the - response, particularly for newer reasoning models. Parameters that are only - supported for reasoning models are noted below. For the current state of - unsupported parameters in reasoning models, - [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - - Args: - messages: A list of messages comprising the conversation so far. Depending on the - [model](https://platform.openai.com/docs/models) you use, different message - types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - - audio: Parameters for audio output. Required when audio output is requested with - `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - function_call: Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - - functions: Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - - logprobs: Whether to return log probabilities of the output tokens or not. If true, - returns the log probabilities of each output token returned in the `content` of - `message`. - - max_completion_tokens: An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - modalities: Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - - n: How many chat completion choices to generate for each input message. Note that - you will be charged based on the number of generated tokens across all of the - choices. Keep `n` as `1` to minimize costs. - - parallel_tool_calls: Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - - prediction: Static predicted output content, such as the content of a text file that is - being regenerated. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning_effort: Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - - response_format: An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - seed: This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - store: Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - tool_choice: Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - - tools: A list of tools the model may call. You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - verbosity: Constrains the verbosity of the model's response. Lower values will result in - more concise responses, while higher values will result in more verbose - responses. Currently supported values are `low`, `medium`, and `high`. - - web_search_options: This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["messages", "model"], ["messages", "model", "stream"]) - async def create( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - response_format: completion_create_params.ResponseFormat | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: - validate_response_format(response_format) - return await self._post( - "/chat/completions", - body=await async_maybe_transform( - { - "messages": messages, - "model": model, - "audio": audio, - "frequency_penalty": frequency_penalty, - "function_call": function_call, - "functions": functions, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_completion_tokens": max_completion_tokens, - "max_tokens": max_tokens, - "metadata": metadata, - "modalities": modalities, - "n": n, - "parallel_tool_calls": parallel_tool_calls, - "prediction": prediction, - "presence_penalty": presence_penalty, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning_effort": reasoning_effort, - "response_format": response_format, - "safety_identifier": safety_identifier, - "seed": seed, - "service_tier": service_tier, - "stop": stop, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "user": user, - "verbosity": verbosity, - "web_search_options": web_search_options, - }, - completion_create_params.CompletionCreateParamsStreaming - if stream - else completion_create_params.CompletionCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - stream=stream or False, - stream_cls=AsyncStream[ChatCompletionChunk], - ) - - async def retrieve( - self, - completion_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """Get a stored chat completion. - - Only Chat Completions that have been created with - the `store` parameter set to `true` will be returned. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return await self._get( - f"/chat/completions/{completion_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - ) - - async def update( - self, - completion_id: str, - *, - metadata: Optional[Metadata], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletion: - """Modify a stored chat completion. - - Only Chat Completions that have been created - with the `store` parameter set to `true` can be modified. Currently, the only - supported modification is to update the `metadata` field. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return await self._post( - f"/chat/completions/{completion_id}", - body=await async_maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletion, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: str | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ChatCompletion, AsyncCursorPage[ChatCompletion]]: - """List stored Chat Completions. - - Only Chat Completions that have been stored with - the `store` parameter set to `true` will be returned. - - Args: - after: Identifier for the last chat completion from the previous pagination request. - - limit: Number of Chat Completions to retrieve. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: The model used to generate the Chat Completions. - - order: Sort order for Chat Completions by timestamp. Use `asc` for ascending order or - `desc` for descending order. Defaults to `asc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/chat/completions", - page=AsyncCursorPage[ChatCompletion], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "metadata": metadata, - "model": model, - "order": order, - }, - completion_list_params.CompletionListParams, - ), - ), - model=ChatCompletion, - ) - - async def delete( - self, - completion_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ChatCompletionDeleted: - """Delete a stored chat completion. - - Only Chat Completions that have been created - with the `store` parameter set to `true` can be deleted. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return await self._delete( - f"/chat/completions/{completion_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatCompletionDeleted, - ) - - def stream( - self, - *, - messages: Iterable[ChatCompletionMessageParam], - model: Union[str, ChatModel], - audio: Optional[ChatCompletionAudioParam] | Omit = omit, - response_format: completion_create_params.ResponseFormat | type[ResponseFormatT] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - function_call: completion_create_params.FunctionCall | Omit = omit, - functions: Iterable[completion_create_params.Function] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[bool] | Omit = omit, - max_completion_tokens: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - modalities: Optional[List[Literal["text", "audio"]]] | Omit = omit, - n: Optional[int] | Omit = omit, - parallel_tool_calls: bool | Omit = omit, - prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning_effort: Optional[ReasoningEffort] | Omit = omit, - safety_identifier: str | Omit = omit, - seed: Optional[int] | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - temperature: Optional[float] | Omit = omit, - tool_choice: ChatCompletionToolChoiceOptionParam | Omit = omit, - tools: Iterable[ChatCompletionToolUnionParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - web_search_options: completion_create_params.WebSearchOptions | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncChatCompletionStreamManager[ResponseFormatT]: - """Wrapper over the `client.chat.completions.create(stream=True)` method that provides a more granular event API - and automatic accumulation of each delta. - - This also supports all of the parsing utilities that `.parse()` does. - - Unlike `.create(stream=True)`, the `.stream()` method requires usage within a context manager to prevent accidental leakage of the response: - - ```py - async with client.chat.completions.stream( - model="gpt-4o-2024-08-06", - messages=[...], - ) as stream: - async for event in stream: - if event.type == "content.delta": - print(event.delta, flush=True, end="") - ``` - - When the context manager is entered, an `AsyncChatCompletionStream` instance is returned which, like `.create(stream=True)` is an async iterator. The full list of events that are yielded by the iterator are outlined in [these docs](https://github.com/openai/openai-python/blob/main/helpers.md#chat-completions-events). - - When the context manager exits, the response will be closed, however the `stream` instance is still available outside - the context manager. - """ - _validate_input_tools(tools) - - extra_headers = { - "X-Stainless-Helper-Method": "chat.completions.stream", - **(extra_headers or {}), - } - - api_request = self.create( - messages=messages, - model=model, - audio=audio, - stream=True, - response_format=_type_to_response_format(response_format), - frequency_penalty=frequency_penalty, - function_call=function_call, - functions=functions, - logit_bias=logit_bias, - logprobs=logprobs, - max_completion_tokens=max_completion_tokens, - max_tokens=max_tokens, - metadata=metadata, - modalities=modalities, - n=n, - parallel_tool_calls=parallel_tool_calls, - prediction=prediction, - presence_penalty=presence_penalty, - prompt_cache_key=prompt_cache_key, - prompt_cache_retention=prompt_cache_retention, - reasoning_effort=reasoning_effort, - safety_identifier=safety_identifier, - seed=seed, - service_tier=service_tier, - stop=stop, - store=store, - stream_options=stream_options, - temperature=temperature, - tool_choice=tool_choice, - tools=tools, - top_logprobs=top_logprobs, - top_p=top_p, - user=user, - verbosity=verbosity, - web_search_options=web_search_options, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return AsyncChatCompletionStreamManager( - api_request, - response_format=response_format, - input_tools=tools, - ) - - -class CompletionsWithRawResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.parse = _legacy_response.to_raw_response_wrapper( - completions.parse, - ) - self.create = _legacy_response.to_raw_response_wrapper( - completions.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - completions.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - completions.update, - ) - self.list = _legacy_response.to_raw_response_wrapper( - completions.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - completions.delete, - ) - - @cached_property - def messages(self) -> MessagesWithRawResponse: - return MessagesWithRawResponse(self._completions.messages) - - -class AsyncCompletionsWithRawResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.parse = _legacy_response.async_to_raw_response_wrapper( - completions.parse, - ) - self.create = _legacy_response.async_to_raw_response_wrapper( - completions.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - completions.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - completions.update, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - completions.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - completions.delete, - ) - - @cached_property - def messages(self) -> AsyncMessagesWithRawResponse: - return AsyncMessagesWithRawResponse(self._completions.messages) - - -class CompletionsWithStreamingResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.parse = to_streamed_response_wrapper( - completions.parse, - ) - self.create = to_streamed_response_wrapper( - completions.create, - ) - self.retrieve = to_streamed_response_wrapper( - completions.retrieve, - ) - self.update = to_streamed_response_wrapper( - completions.update, - ) - self.list = to_streamed_response_wrapper( - completions.list, - ) - self.delete = to_streamed_response_wrapper( - completions.delete, - ) - - @cached_property - def messages(self) -> MessagesWithStreamingResponse: - return MessagesWithStreamingResponse(self._completions.messages) - - -class AsyncCompletionsWithStreamingResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.parse = async_to_streamed_response_wrapper( - completions.parse, - ) - self.create = async_to_streamed_response_wrapper( - completions.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - completions.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - completions.update, - ) - self.list = async_to_streamed_response_wrapper( - completions.list, - ) - self.delete = async_to_streamed_response_wrapper( - completions.delete, - ) - - @cached_property - def messages(self) -> AsyncMessagesWithStreamingResponse: - return AsyncMessagesWithStreamingResponse(self._completions.messages) - - -def validate_response_format(response_format: object) -> None: - if inspect.isclass(response_format) and issubclass(response_format, pydantic.BaseModel): - raise TypeError( - "You tried to pass a `BaseModel` class to `chat.completions.create()`; You must use `chat.completions.parse()` instead" - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/messages.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/messages.py deleted file mode 100644 index 3d6dc79..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/chat/completions/messages.py +++ /dev/null @@ -1,212 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.chat.completions import message_list_params -from ....types.chat.chat_completion_store_message import ChatCompletionStoreMessage - -__all__ = ["Messages", "AsyncMessages"] - - -class Messages(SyncAPIResource): - @cached_property - def with_raw_response(self) -> MessagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return MessagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> MessagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return MessagesWithStreamingResponse(self) - - def list( - self, - completion_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ChatCompletionStoreMessage]: - """Get the messages in a stored chat completion. - - Only Chat Completions that have - been created with the `store` parameter set to `true` will be returned. - - Args: - after: Identifier for the last message from the previous pagination request. - - limit: Number of messages to retrieve. - - order: Sort order for messages by timestamp. Use `asc` for ascending order or `desc` - for descending order. Defaults to `asc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return self._get_api_list( - f"/chat/completions/{completion_id}/messages", - page=SyncCursorPage[ChatCompletionStoreMessage], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - message_list_params.MessageListParams, - ), - ), - model=ChatCompletionStoreMessage, - ) - - -class AsyncMessages(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncMessagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncMessagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncMessagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncMessagesWithStreamingResponse(self) - - def list( - self, - completion_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ChatCompletionStoreMessage, AsyncCursorPage[ChatCompletionStoreMessage]]: - """Get the messages in a stored chat completion. - - Only Chat Completions that have - been created with the `store` parameter set to `true` will be returned. - - Args: - after: Identifier for the last message from the previous pagination request. - - limit: Number of messages to retrieve. - - order: Sort order for messages by timestamp. Use `asc` for ascending order or `desc` - for descending order. Defaults to `asc`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not completion_id: - raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") - return self._get_api_list( - f"/chat/completions/{completion_id}/messages", - page=AsyncCursorPage[ChatCompletionStoreMessage], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - message_list_params.MessageListParams, - ), - ), - model=ChatCompletionStoreMessage, - ) - - -class MessagesWithRawResponse: - def __init__(self, messages: Messages) -> None: - self._messages = messages - - self.list = _legacy_response.to_raw_response_wrapper( - messages.list, - ) - - -class AsyncMessagesWithRawResponse: - def __init__(self, messages: AsyncMessages) -> None: - self._messages = messages - - self.list = _legacy_response.async_to_raw_response_wrapper( - messages.list, - ) - - -class MessagesWithStreamingResponse: - def __init__(self, messages: Messages) -> None: - self._messages = messages - - self.list = to_streamed_response_wrapper( - messages.list, - ) - - -class AsyncMessagesWithStreamingResponse: - def __init__(self, messages: AsyncMessages) -> None: - self._messages = messages - - self.list = async_to_streamed_response_wrapper( - messages.list, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/completions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/completions.py deleted file mode 100644 index 2f2284a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/completions.py +++ /dev/null @@ -1,1160 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, overload - -import httpx - -from .. import _legacy_response -from ..types import completion_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from .._utils import required_args, maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .._streaming import Stream, AsyncStream -from .._base_client import ( - make_request_options, -) -from ..types.completion import Completion -from ..types.chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam - -__all__ = ["Completions", "AsyncCompletions"] - - -class Completions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> CompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CompletionsWithStreamingResponse(self) - - @overload - def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - stream: Literal[True], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[Completion]: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - stream: bool, - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion | Stream[Completion]: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["model", "prompt"], ["model", "prompt", "stream"]) - def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion | Stream[Completion]: - return self._post( - "/completions", - body=maybe_transform( - { - "model": model, - "prompt": prompt, - "best_of": best_of, - "echo": echo, - "frequency_penalty": frequency_penalty, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_tokens": max_tokens, - "n": n, - "presence_penalty": presence_penalty, - "seed": seed, - "stop": stop, - "stream": stream, - "stream_options": stream_options, - "suffix": suffix, - "temperature": temperature, - "top_p": top_p, - "user": user, - }, - completion_create_params.CompletionCreateParamsStreaming - if stream - else completion_create_params.CompletionCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Completion, - stream=stream or False, - stream_cls=Stream[Completion], - ) - - -class AsyncCompletions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncCompletionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCompletionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCompletionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCompletionsWithStreamingResponse(self) - - @overload - async def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - stream: Literal[True], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[Completion]: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - stream: bool, - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion | AsyncStream[Completion]: - """ - Creates a completion for the provided prompt and parameters. - - Args: - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - prompt: The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - - stream: Whether to stream back partial progress. If set, tokens will be sent as - data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - - best_of: Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - echo: Echo back the prompt in addition to the completion - - frequency_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on their - existing frequency in the text so far, decreasing the model's likelihood to - repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - logit_bias: Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - - logprobs: Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - - max_tokens: The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - - n: How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - - presence_penalty: Number between -2.0 and 2.0. Positive values penalize new tokens based on - whether they appear in the text so far, increasing the model's likelihood to - talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - - seed: If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - - stop: Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - - stream_options: Options for streaming response. Only set this when you set `stream: true`. - - suffix: The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["model", "prompt"], ["model", "prompt", "stream"]) - async def create( - self, - *, - model: Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]], - prompt: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None], - best_of: Optional[int] | Omit = omit, - echo: Optional[bool] | Omit = omit, - frequency_penalty: Optional[float] | Omit = omit, - logit_bias: Optional[Dict[str, int]] | Omit = omit, - logprobs: Optional[int] | Omit = omit, - max_tokens: Optional[int] | Omit = omit, - n: Optional[int] | Omit = omit, - presence_penalty: Optional[float] | Omit = omit, - seed: Optional[int] | Omit = omit, - stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[ChatCompletionStreamOptionsParam] | Omit = omit, - suffix: Optional[str] | Omit = omit, - temperature: Optional[float] | Omit = omit, - top_p: Optional[float] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Completion | AsyncStream[Completion]: - return await self._post( - "/completions", - body=await async_maybe_transform( - { - "model": model, - "prompt": prompt, - "best_of": best_of, - "echo": echo, - "frequency_penalty": frequency_penalty, - "logit_bias": logit_bias, - "logprobs": logprobs, - "max_tokens": max_tokens, - "n": n, - "presence_penalty": presence_penalty, - "seed": seed, - "stop": stop, - "stream": stream, - "stream_options": stream_options, - "suffix": suffix, - "temperature": temperature, - "top_p": top_p, - "user": user, - }, - completion_create_params.CompletionCreateParamsStreaming - if stream - else completion_create_params.CompletionCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Completion, - stream=stream or False, - stream_cls=AsyncStream[Completion], - ) - - -class CompletionsWithRawResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.create = _legacy_response.to_raw_response_wrapper( - completions.create, - ) - - -class AsyncCompletionsWithRawResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.create = _legacy_response.async_to_raw_response_wrapper( - completions.create, - ) - - -class CompletionsWithStreamingResponse: - def __init__(self, completions: Completions) -> None: - self._completions = completions - - self.create = to_streamed_response_wrapper( - completions.create, - ) - - -class AsyncCompletionsWithStreamingResponse: - def __init__(self, completions: AsyncCompletions) -> None: - self._completions = completions - - self.create = async_to_streamed_response_wrapper( - completions.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/__init__.py deleted file mode 100644 index dc19367..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .containers import ( - Containers, - AsyncContainers, - ContainersWithRawResponse, - AsyncContainersWithRawResponse, - ContainersWithStreamingResponse, - AsyncContainersWithStreamingResponse, -) - -__all__ = [ - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", - "Containers", - "AsyncContainers", - "ContainersWithRawResponse", - "AsyncContainersWithRawResponse", - "ContainersWithStreamingResponse", - "AsyncContainersWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/containers.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/containers.py deleted file mode 100644 index 0cbb400..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/containers.py +++ /dev/null @@ -1,518 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ...types import container_list_params, container_create_params -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .files.files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.container_list_response import ContainerListResponse -from ...types.container_create_response import ContainerCreateResponse -from ...types.container_retrieve_response import ContainerRetrieveResponse - -__all__ = ["Containers", "AsyncContainers"] - - -class Containers(SyncAPIResource): - @cached_property - def files(self) -> Files: - return Files(self._client) - - @cached_property - def with_raw_response(self) -> ContainersWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ContainersWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ContainersWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ContainersWithStreamingResponse(self) - - def create( - self, - *, - name: str, - expires_after: container_create_params.ExpiresAfter | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContainerCreateResponse: - """ - Create Container - - Args: - name: Name of the container to create. - - expires_after: Container expiration time in seconds relative to the 'anchor' time. - - file_ids: IDs of files to copy to the container. - - memory_limit: Optional memory limit for the container. Defaults to "1g". - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/containers", - body=maybe_transform( - { - "name": name, - "expires_after": expires_after, - "file_ids": file_ids, - "memory_limit": memory_limit, - }, - container_create_params.ContainerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContainerCreateResponse, - ) - - def retrieve( - self, - container_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContainerRetrieveResponse: - """ - Retrieve Container - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - return self._get( - f"/containers/{container_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContainerRetrieveResponse, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ContainerListResponse]: - """List Containers - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/containers", - page=SyncCursorPage[ContainerListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - container_list_params.ContainerListParams, - ), - ), - model=ContainerListResponse, - ) - - def delete( - self, - container_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Delete Container - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/containers/{container_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncContainers(AsyncAPIResource): - @cached_property - def files(self) -> AsyncFiles: - return AsyncFiles(self._client) - - @cached_property - def with_raw_response(self) -> AsyncContainersWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncContainersWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncContainersWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncContainersWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - expires_after: container_create_params.ExpiresAfter | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContainerCreateResponse: - """ - Create Container - - Args: - name: Name of the container to create. - - expires_after: Container expiration time in seconds relative to the 'anchor' time. - - file_ids: IDs of files to copy to the container. - - memory_limit: Optional memory limit for the container. Defaults to "1g". - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/containers", - body=await async_maybe_transform( - { - "name": name, - "expires_after": expires_after, - "file_ids": file_ids, - "memory_limit": memory_limit, - }, - container_create_params.ContainerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContainerCreateResponse, - ) - - async def retrieve( - self, - container_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContainerRetrieveResponse: - """ - Retrieve Container - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - return await self._get( - f"/containers/{container_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContainerRetrieveResponse, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ContainerListResponse, AsyncCursorPage[ContainerListResponse]]: - """List Containers - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/containers", - page=AsyncCursorPage[ContainerListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - container_list_params.ContainerListParams, - ), - ), - model=ContainerListResponse, - ) - - async def delete( - self, - container_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Delete Container - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/containers/{container_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class ContainersWithRawResponse: - def __init__(self, containers: Containers) -> None: - self._containers = containers - - self.create = _legacy_response.to_raw_response_wrapper( - containers.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - containers.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - containers.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - containers.delete, - ) - - @cached_property - def files(self) -> FilesWithRawResponse: - return FilesWithRawResponse(self._containers.files) - - -class AsyncContainersWithRawResponse: - def __init__(self, containers: AsyncContainers) -> None: - self._containers = containers - - self.create = _legacy_response.async_to_raw_response_wrapper( - containers.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - containers.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - containers.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - containers.delete, - ) - - @cached_property - def files(self) -> AsyncFilesWithRawResponse: - return AsyncFilesWithRawResponse(self._containers.files) - - -class ContainersWithStreamingResponse: - def __init__(self, containers: Containers) -> None: - self._containers = containers - - self.create = to_streamed_response_wrapper( - containers.create, - ) - self.retrieve = to_streamed_response_wrapper( - containers.retrieve, - ) - self.list = to_streamed_response_wrapper( - containers.list, - ) - self.delete = to_streamed_response_wrapper( - containers.delete, - ) - - @cached_property - def files(self) -> FilesWithStreamingResponse: - return FilesWithStreamingResponse(self._containers.files) - - -class AsyncContainersWithStreamingResponse: - def __init__(self, containers: AsyncContainers) -> None: - self._containers = containers - - self.create = async_to_streamed_response_wrapper( - containers.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - containers.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - containers.list, - ) - self.delete = async_to_streamed_response_wrapper( - containers.delete, - ) - - @cached_property - def files(self) -> AsyncFilesWithStreamingResponse: - return AsyncFilesWithStreamingResponse(self._containers.files) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/__init__.py deleted file mode 100644 index f71f7db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .content import ( - Content, - AsyncContent, - ContentWithRawResponse, - AsyncContentWithRawResponse, - ContentWithStreamingResponse, - AsyncContentWithStreamingResponse, -) - -__all__ = [ - "Content", - "AsyncContent", - "ContentWithRawResponse", - "AsyncContentWithRawResponse", - "ContentWithStreamingResponse", - "AsyncContentWithStreamingResponse", - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/content.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/content.py deleted file mode 100644 index a3dbd0e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/content.py +++ /dev/null @@ -1,173 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .... import _legacy_response -from ...._types import Body, Query, Headers, NotGiven, not_given -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_custom_streamed_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ...._base_client import make_request_options - -__all__ = ["Content", "AsyncContent"] - - -class Content(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ContentWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ContentWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ContentWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ContentWithStreamingResponse(self) - - def retrieve( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Retrieve Container File Content - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return self._get( - f"/containers/{container_id}/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - -class AsyncContent(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncContentWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncContentWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncContentWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncContentWithStreamingResponse(self) - - async def retrieve( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Retrieve Container File Content - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return await self._get( - f"/containers/{container_id}/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - -class ContentWithRawResponse: - def __init__(self, content: Content) -> None: - self._content = content - - self.retrieve = _legacy_response.to_raw_response_wrapper( - content.retrieve, - ) - - -class AsyncContentWithRawResponse: - def __init__(self, content: AsyncContent) -> None: - self._content = content - - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - content.retrieve, - ) - - -class ContentWithStreamingResponse: - def __init__(self, content: Content) -> None: - self._content = content - - self.retrieve = to_custom_streamed_response_wrapper( - content.retrieve, - StreamedBinaryAPIResponse, - ) - - -class AsyncContentWithStreamingResponse: - def __init__(self, content: AsyncContent) -> None: - self._content = content - - self.retrieve = async_to_custom_streamed_response_wrapper( - content.retrieve, - AsyncStreamedBinaryAPIResponse, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/files.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/files.py deleted file mode 100644 index a472cfc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/containers/files/files.py +++ /dev/null @@ -1,545 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Mapping, cast -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from .content import ( - Content, - AsyncContent, - ContentWithRawResponse, - AsyncContentWithRawResponse, - ContentWithStreamingResponse, - AsyncContentWithStreamingResponse, -) -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.containers import file_list_params, file_create_params -from ....types.containers.file_list_response import FileListResponse -from ....types.containers.file_create_response import FileCreateResponse -from ....types.containers.file_retrieve_response import FileRetrieveResponse - -__all__ = ["Files", "AsyncFiles"] - - -class Files(SyncAPIResource): - @cached_property - def content(self) -> Content: - return Content(self._client) - - @cached_property - def with_raw_response(self) -> FilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return FilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return FilesWithStreamingResponse(self) - - def create( - self, - container_id: str, - *, - file: FileTypes | Omit = omit, - file_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileCreateResponse: - """ - Create a Container File - - You can send either a multipart/form-data request with the raw file content, or - a JSON request with a file ID. - - Args: - file: The File object (not file name) to be uploaded. - - file_id: Name of the file to create. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - body = deepcopy_minimal( - { - "file": file, - "file_id": file_id, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - f"/containers/{container_id}/files", - body=maybe_transform(body, file_create_params.FileCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileCreateResponse, - ) - - def retrieve( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileRetrieveResponse: - """ - Retrieve Container File - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return self._get( - f"/containers/{container_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileRetrieveResponse, - ) - - def list( - self, - container_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[FileListResponse]: - """List Container files - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - return self._get_api_list( - f"/containers/{container_id}/files", - page=SyncCursorPage[FileListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - file_list_params.FileListParams, - ), - ), - model=FileListResponse, - ) - - def delete( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Delete Container File - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/containers/{container_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncFiles(AsyncAPIResource): - @cached_property - def content(self) -> AsyncContent: - return AsyncContent(self._client) - - @cached_property - def with_raw_response(self) -> AsyncFilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncFilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncFilesWithStreamingResponse(self) - - async def create( - self, - container_id: str, - *, - file: FileTypes | Omit = omit, - file_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileCreateResponse: - """ - Create a Container File - - You can send either a multipart/form-data request with the raw file content, or - a JSON request with a file ID. - - Args: - file: The File object (not file name) to be uploaded. - - file_id: Name of the file to create. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - body = deepcopy_minimal( - { - "file": file, - "file_id": file_id, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - f"/containers/{container_id}/files", - body=await async_maybe_transform(body, file_create_params.FileCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileCreateResponse, - ) - - async def retrieve( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileRetrieveResponse: - """ - Retrieve Container File - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return await self._get( - f"/containers/{container_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileRetrieveResponse, - ) - - def list( - self, - container_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FileListResponse, AsyncCursorPage[FileListResponse]]: - """List Container files - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - return self._get_api_list( - f"/containers/{container_id}/files", - page=AsyncCursorPage[FileListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - file_list_params.FileListParams, - ), - ), - model=FileListResponse, - ) - - async def delete( - self, - file_id: str, - *, - container_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Delete Container File - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not container_id: - raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/containers/{container_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class FilesWithRawResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = _legacy_response.to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - files.delete, - ) - - @cached_property - def content(self) -> ContentWithRawResponse: - return ContentWithRawResponse(self._files.content) - - -class AsyncFilesWithRawResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = _legacy_response.async_to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - files.delete, - ) - - @cached_property - def content(self) -> AsyncContentWithRawResponse: - return AsyncContentWithRawResponse(self._files.content) - - -class FilesWithStreamingResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = to_streamed_response_wrapper( - files.create, - ) - self.retrieve = to_streamed_response_wrapper( - files.retrieve, - ) - self.list = to_streamed_response_wrapper( - files.list, - ) - self.delete = to_streamed_response_wrapper( - files.delete, - ) - - @cached_property - def content(self) -> ContentWithStreamingResponse: - return ContentWithStreamingResponse(self._files.content) - - -class AsyncFilesWithStreamingResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = async_to_streamed_response_wrapper( - files.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - files.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - files.list, - ) - self.delete = async_to_streamed_response_wrapper( - files.delete, - ) - - @cached_property - def content(self) -> AsyncContentWithStreamingResponse: - return AsyncContentWithStreamingResponse(self._files.content) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/__init__.py deleted file mode 100644 index c6c4fd6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .items import ( - Items, - AsyncItems, - ItemsWithRawResponse, - AsyncItemsWithRawResponse, - ItemsWithStreamingResponse, - AsyncItemsWithStreamingResponse, -) -from .conversations import ( - Conversations, - AsyncConversations, - ConversationsWithRawResponse, - AsyncConversationsWithRawResponse, - ConversationsWithStreamingResponse, - AsyncConversationsWithStreamingResponse, -) - -__all__ = [ - "Items", - "AsyncItems", - "ItemsWithRawResponse", - "AsyncItemsWithRawResponse", - "ItemsWithStreamingResponse", - "AsyncItemsWithStreamingResponse", - "Conversations", - "AsyncConversations", - "ConversationsWithRawResponse", - "AsyncConversationsWithRawResponse", - "ConversationsWithStreamingResponse", - "AsyncConversationsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/conversations.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/conversations.py deleted file mode 100644 index da037a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/conversations.py +++ /dev/null @@ -1,486 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional - -import httpx - -from ... import _legacy_response -from .items import ( - Items, - AsyncItems, - ItemsWithRawResponse, - AsyncItemsWithRawResponse, - ItemsWithStreamingResponse, - AsyncItemsWithStreamingResponse, -) -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._base_client import make_request_options -from ...types.conversations import conversation_create_params, conversation_update_params -from ...types.shared_params.metadata import Metadata -from ...types.conversations.conversation import Conversation -from ...types.responses.response_input_item_param import ResponseInputItemParam -from ...types.conversations.conversation_deleted_resource import ConversationDeletedResource - -__all__ = ["Conversations", "AsyncConversations"] - - -class Conversations(SyncAPIResource): - @cached_property - def items(self) -> Items: - return Items(self._client) - - @cached_property - def with_raw_response(self) -> ConversationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ConversationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ConversationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ConversationsWithStreamingResponse(self) - - def create( - self, - *, - items: Optional[Iterable[ResponseInputItemParam]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Create a conversation. - - Args: - items: Initial items to include in the conversation context. You may add up to 20 items - at a time. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/conversations", - body=maybe_transform( - { - "items": items, - "metadata": metadata, - }, - conversation_create_params.ConversationCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - def retrieve( - self, - conversation_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Get a conversation - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._get( - f"/conversations/{conversation_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - def update( - self, - conversation_id: str, - *, - metadata: Optional[Metadata], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Update a conversation - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._post( - f"/conversations/{conversation_id}", - body=maybe_transform({"metadata": metadata}, conversation_update_params.ConversationUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - def delete( - self, - conversation_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationDeletedResource: - """Delete a conversation. - - Items in the conversation will not be deleted. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._delete( - f"/conversations/{conversation_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ConversationDeletedResource, - ) - - -class AsyncConversations(AsyncAPIResource): - @cached_property - def items(self) -> AsyncItems: - return AsyncItems(self._client) - - @cached_property - def with_raw_response(self) -> AsyncConversationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncConversationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncConversationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncConversationsWithStreamingResponse(self) - - async def create( - self, - *, - items: Optional[Iterable[ResponseInputItemParam]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Create a conversation. - - Args: - items: Initial items to include in the conversation context. You may add up to 20 items - at a time. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/conversations", - body=await async_maybe_transform( - { - "items": items, - "metadata": metadata, - }, - conversation_create_params.ConversationCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - async def retrieve( - self, - conversation_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Get a conversation - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return await self._get( - f"/conversations/{conversation_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - async def update( - self, - conversation_id: str, - *, - metadata: Optional[Metadata], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Update a conversation - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return await self._post( - f"/conversations/{conversation_id}", - body=await async_maybe_transform( - {"metadata": metadata}, conversation_update_params.ConversationUpdateParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - async def delete( - self, - conversation_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationDeletedResource: - """Delete a conversation. - - Items in the conversation will not be deleted. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return await self._delete( - f"/conversations/{conversation_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ConversationDeletedResource, - ) - - -class ConversationsWithRawResponse: - def __init__(self, conversations: Conversations) -> None: - self._conversations = conversations - - self.create = _legacy_response.to_raw_response_wrapper( - conversations.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - conversations.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - conversations.update, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - conversations.delete, - ) - - @cached_property - def items(self) -> ItemsWithRawResponse: - return ItemsWithRawResponse(self._conversations.items) - - -class AsyncConversationsWithRawResponse: - def __init__(self, conversations: AsyncConversations) -> None: - self._conversations = conversations - - self.create = _legacy_response.async_to_raw_response_wrapper( - conversations.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - conversations.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - conversations.update, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - conversations.delete, - ) - - @cached_property - def items(self) -> AsyncItemsWithRawResponse: - return AsyncItemsWithRawResponse(self._conversations.items) - - -class ConversationsWithStreamingResponse: - def __init__(self, conversations: Conversations) -> None: - self._conversations = conversations - - self.create = to_streamed_response_wrapper( - conversations.create, - ) - self.retrieve = to_streamed_response_wrapper( - conversations.retrieve, - ) - self.update = to_streamed_response_wrapper( - conversations.update, - ) - self.delete = to_streamed_response_wrapper( - conversations.delete, - ) - - @cached_property - def items(self) -> ItemsWithStreamingResponse: - return ItemsWithStreamingResponse(self._conversations.items) - - -class AsyncConversationsWithStreamingResponse: - def __init__(self, conversations: AsyncConversations) -> None: - self._conversations = conversations - - self.create = async_to_streamed_response_wrapper( - conversations.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - conversations.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - conversations.update, - ) - self.delete = async_to_streamed_response_wrapper( - conversations.delete, - ) - - @cached_property - def items(self) -> AsyncItemsWithStreamingResponse: - return AsyncItemsWithStreamingResponse(self._conversations.items) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/items.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/items.py deleted file mode 100644 index 3dba144..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/conversations/items.py +++ /dev/null @@ -1,557 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, List, Iterable, cast -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncConversationCursorPage, AsyncConversationCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.conversations import item_list_params, item_create_params, item_retrieve_params -from ...types.conversations.conversation import Conversation -from ...types.responses.response_includable import ResponseIncludable -from ...types.conversations.conversation_item import ConversationItem -from ...types.responses.response_input_item_param import ResponseInputItemParam -from ...types.conversations.conversation_item_list import ConversationItemList - -__all__ = ["Items", "AsyncItems"] - - -class Items(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ItemsWithStreamingResponse(self) - - def create( - self, - conversation_id: str, - *, - items: Iterable[ResponseInputItemParam], - include: List[ResponseIncludable] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationItemList: - """ - Create items in a conversation with the given ID. - - Args: - items: The items to add to the conversation. You may add up to 20 items at a time. - - include: Additional fields to include in the response. See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._post( - f"/conversations/{conversation_id}/items", - body=maybe_transform({"items": items}, item_create_params.ItemCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, item_create_params.ItemCreateParams), - ), - cast_to=ConversationItemList, - ) - - def retrieve( - self, - item_id: str, - *, - conversation_id: str, - include: List[ResponseIncludable] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationItem: - """ - Get a single item from a conversation with the given IDs. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - if not item_id: - raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") - return cast( - ConversationItem, - self._get( - f"/conversations/{conversation_id}/items/{item_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), - ), - cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system - ), - ) - - def list( - self, - conversation_id: str, - *, - after: str | Omit = omit, - include: List[ResponseIncludable] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[ConversationItem]: - """ - List all items for a conversation with the given ID. - - Args: - after: An item ID to list items after, used in pagination. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._get_api_list( - f"/conversations/{conversation_id}/items", - page=SyncConversationCursorPage[ConversationItem], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "include": include, - "limit": limit, - "order": order, - }, - item_list_params.ItemListParams, - ), - ), - model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system - ) - - def delete( - self, - item_id: str, - *, - conversation_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Delete an item from a conversation with the given IDs. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - if not item_id: - raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") - return self._delete( - f"/conversations/{conversation_id}/items/{item_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - -class AsyncItems(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncItemsWithStreamingResponse(self) - - async def create( - self, - conversation_id: str, - *, - items: Iterable[ResponseInputItemParam], - include: List[ResponseIncludable] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationItemList: - """ - Create items in a conversation with the given ID. - - Args: - items: The items to add to the conversation. You may add up to 20 items at a time. - - include: Additional fields to include in the response. See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return await self._post( - f"/conversations/{conversation_id}/items", - body=await async_maybe_transform({"items": items}, item_create_params.ItemCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"include": include}, item_create_params.ItemCreateParams), - ), - cast_to=ConversationItemList, - ) - - async def retrieve( - self, - item_id: str, - *, - conversation_id: str, - include: List[ResponseIncludable] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ConversationItem: - """ - Get a single item from a conversation with the given IDs. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - if not item_id: - raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") - return cast( - ConversationItem, - await self._get( - f"/conversations/{conversation_id}/items/{item_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"include": include}, item_retrieve_params.ItemRetrieveParams), - ), - cast_to=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system - ), - ) - - def list( - self, - conversation_id: str, - *, - after: str | Omit = omit, - include: List[ResponseIncludable] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ConversationItem, AsyncConversationCursorPage[ConversationItem]]: - """ - List all items for a conversation with the given ID. - - Args: - after: An item ID to list items after, used in pagination. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - return self._get_api_list( - f"/conversations/{conversation_id}/items", - page=AsyncConversationCursorPage[ConversationItem], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "include": include, - "limit": limit, - "order": order, - }, - item_list_params.ItemListParams, - ), - ), - model=cast(Any, ConversationItem), # Union types cannot be passed in as arguments in the type system - ) - - async def delete( - self, - item_id: str, - *, - conversation_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Conversation: - """ - Delete an item from a conversation with the given IDs. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not conversation_id: - raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") - if not item_id: - raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") - return await self._delete( - f"/conversations/{conversation_id}/items/{item_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Conversation, - ) - - -class ItemsWithRawResponse: - def __init__(self, items: Items) -> None: - self._items = items - - self.create = _legacy_response.to_raw_response_wrapper( - items.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - items.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - items.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - items.delete, - ) - - -class AsyncItemsWithRawResponse: - def __init__(self, items: AsyncItems) -> None: - self._items = items - - self.create = _legacy_response.async_to_raw_response_wrapper( - items.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - items.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - items.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - items.delete, - ) - - -class ItemsWithStreamingResponse: - def __init__(self, items: Items) -> None: - self._items = items - - self.create = to_streamed_response_wrapper( - items.create, - ) - self.retrieve = to_streamed_response_wrapper( - items.retrieve, - ) - self.list = to_streamed_response_wrapper( - items.list, - ) - self.delete = to_streamed_response_wrapper( - items.delete, - ) - - -class AsyncItemsWithStreamingResponse: - def __init__(self, items: AsyncItems) -> None: - self._items = items - - self.create = async_to_streamed_response_wrapper( - items.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - items.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - items.list, - ) - self.delete = async_to_streamed_response_wrapper( - items.delete, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/embeddings.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/embeddings.py deleted file mode 100644 index 5dc3dfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/embeddings.py +++ /dev/null @@ -1,298 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import array -import base64 -from typing import Union, Iterable, cast -from typing_extensions import Literal - -import httpx - -from .. import _legacy_response -from ..types import embedding_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from .._utils import is_given, maybe_transform -from .._compat import cached_property -from .._extras import numpy as np, has_numpy -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .._base_client import make_request_options -from ..types.embedding_model import EmbeddingModel -from ..types.create_embedding_response import CreateEmbeddingResponse - -__all__ = ["Embeddings", "AsyncEmbeddings"] - - -class Embeddings(SyncAPIResource): - @cached_property - def with_raw_response(self) -> EmbeddingsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return EmbeddingsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> EmbeddingsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return EmbeddingsWithStreamingResponse(self) - - def create( - self, - *, - input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], - model: Union[str, EmbeddingModel], - dimensions: int | Omit = omit, - encoding_format: Literal["float", "base64"] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreateEmbeddingResponse: - """ - Creates an embedding vector representing the input text. - - Args: - input: Input text to embed, encoded as a string or array of tokens. To embed multiple - inputs in a single request, pass an array of strings or array of token arrays. - The input must not exceed the max input tokens for the model (8192 tokens for - all embedding models), cannot be an empty string, and any array must be 2048 - dimensions or less. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. In addition to the per-input token limit, all embedding - models enforce a maximum of 300,000 tokens summed across all inputs in a single - request. - - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - dimensions: The number of dimensions the resulting output embeddings should have. Only - supported in `text-embedding-3` and later models. - - encoding_format: The format to return the embeddings in. Can be either `float` or - [`base64`](https://pypi.org/project/pybase64/). - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - params = { - "input": input, - "model": model, - "user": user, - "dimensions": dimensions, - "encoding_format": encoding_format, - } - if not is_given(encoding_format): - params["encoding_format"] = "base64" - - def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: - if is_given(encoding_format): - # don't modify the response object if a user explicitly asked for a format - return obj - - if not obj.data: - raise ValueError("No embedding data received") - - for embedding in obj.data: - data = cast(object, embedding.embedding) - if not isinstance(data, str): - continue - if not has_numpy(): - # use array for base64 optimisation - embedding.embedding = array.array("f", base64.b64decode(data)).tolist() - else: - embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] - base64.b64decode(data), dtype="float32" - ).tolist() - - return obj - - return self._post( - "/embeddings", - body=maybe_transform(params, embedding_create_params.EmbeddingCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - cast_to=CreateEmbeddingResponse, - ) - - -class AsyncEmbeddings(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncEmbeddingsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncEmbeddingsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncEmbeddingsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncEmbeddingsWithStreamingResponse(self) - - async def create( - self, - *, - input: Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]], - model: Union[str, EmbeddingModel], - dimensions: int | Omit = omit, - encoding_format: Literal["float", "base64"] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreateEmbeddingResponse: - """ - Creates an embedding vector representing the input text. - - Args: - input: Input text to embed, encoded as a string or array of tokens. To embed multiple - inputs in a single request, pass an array of strings or array of token arrays. - The input must not exceed the max input tokens for the model (8192 tokens for - all embedding models), cannot be an empty string, and any array must be 2048 - dimensions or less. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. In addition to the per-input token limit, all embedding - models enforce a maximum of 300,000 tokens summed across all inputs in a single - request. - - model: ID of the model to use. You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - - dimensions: The number of dimensions the resulting output embeddings should have. Only - supported in `text-embedding-3` and later models. - - encoding_format: The format to return the embeddings in. Can be either `float` or - [`base64`](https://pypi.org/project/pybase64/). - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - params = { - "input": input, - "model": model, - "user": user, - "dimensions": dimensions, - "encoding_format": encoding_format, - } - if not is_given(encoding_format): - params["encoding_format"] = "base64" - - def parser(obj: CreateEmbeddingResponse) -> CreateEmbeddingResponse: - if is_given(encoding_format): - # don't modify the response object if a user explicitly asked for a format - return obj - - if not obj.data: - raise ValueError("No embedding data received") - - for embedding in obj.data: - data = cast(object, embedding.embedding) - if not isinstance(data, str): - continue - if not has_numpy(): - # use array for base64 optimisation - embedding.embedding = array.array("f", base64.b64decode(data)).tolist() - else: - embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] - base64.b64decode(data), dtype="float32" - ).tolist() - - return obj - - return await self._post( - "/embeddings", - body=maybe_transform(params, embedding_create_params.EmbeddingCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - cast_to=CreateEmbeddingResponse, - ) - - -class EmbeddingsWithRawResponse: - def __init__(self, embeddings: Embeddings) -> None: - self._embeddings = embeddings - - self.create = _legacy_response.to_raw_response_wrapper( - embeddings.create, - ) - - -class AsyncEmbeddingsWithRawResponse: - def __init__(self, embeddings: AsyncEmbeddings) -> None: - self._embeddings = embeddings - - self.create = _legacy_response.async_to_raw_response_wrapper( - embeddings.create, - ) - - -class EmbeddingsWithStreamingResponse: - def __init__(self, embeddings: Embeddings) -> None: - self._embeddings = embeddings - - self.create = to_streamed_response_wrapper( - embeddings.create, - ) - - -class AsyncEmbeddingsWithStreamingResponse: - def __init__(self, embeddings: AsyncEmbeddings) -> None: - self._embeddings = embeddings - - self.create = async_to_streamed_response_wrapper( - embeddings.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/__init__.py deleted file mode 100644 index 84f7075..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from .evals import ( - Evals, - AsyncEvals, - EvalsWithRawResponse, - AsyncEvalsWithRawResponse, - EvalsWithStreamingResponse, - AsyncEvalsWithStreamingResponse, -) - -__all__ = [ - "Runs", - "AsyncRuns", - "RunsWithRawResponse", - "AsyncRunsWithRawResponse", - "RunsWithStreamingResponse", - "AsyncRunsWithStreamingResponse", - "Evals", - "AsyncEvals", - "EvalsWithRawResponse", - "AsyncEvalsWithRawResponse", - "EvalsWithStreamingResponse", - "AsyncEvalsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/evals.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/evals.py deleted file mode 100644 index 40c4a3e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/evals.py +++ /dev/null @@ -1,662 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ...types import eval_list_params, eval_create_params, eval_update_params -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from .runs.runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.eval_list_response import EvalListResponse -from ...types.eval_create_response import EvalCreateResponse -from ...types.eval_delete_response import EvalDeleteResponse -from ...types.eval_update_response import EvalUpdateResponse -from ...types.eval_retrieve_response import EvalRetrieveResponse -from ...types.shared_params.metadata import Metadata - -__all__ = ["Evals", "AsyncEvals"] - - -class Evals(SyncAPIResource): - @cached_property - def runs(self) -> Runs: - return Runs(self._client) - - @cached_property - def with_raw_response(self) -> EvalsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return EvalsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> EvalsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return EvalsWithStreamingResponse(self) - - def create( - self, - *, - data_source_config: eval_create_params.DataSourceConfig, - testing_criteria: Iterable[eval_create_params.TestingCriterion], - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalCreateResponse: - """ - Create the structure of an evaluation that can be used to test a model's - performance. An evaluation is a set of testing criteria and the config for a - data source, which dictates the schema of the data used in the evaluation. After - creating an evaluation, you can run it on different models and model parameters. - We support several types of graders and datasources. For more information, see - the [Evals guide](https://platform.openai.com/docs/guides/evals). - - Args: - data_source_config: The configuration for the data source used for the evaluation runs. Dictates the - schema of the data used in the evaluation. - - testing_criteria: A list of graders for all eval runs in this group. Graders can reference - variables in the data source using double curly braces notation, like - `{{item.variable_name}}`. To reference the model's output, use the `sample` - namespace (ie, `{{sample.output_text}}`). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the evaluation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/evals", - body=maybe_transform( - { - "data_source_config": data_source_config, - "testing_criteria": testing_criteria, - "metadata": metadata, - "name": name, - }, - eval_create_params.EvalCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalCreateResponse, - ) - - def retrieve( - self, - eval_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalRetrieveResponse: - """ - Get an evaluation by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._get( - f"/evals/{eval_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalRetrieveResponse, - ) - - def update( - self, - eval_id: str, - *, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalUpdateResponse: - """ - Update certain properties of an evaluation. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: Rename the evaluation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._post( - f"/evals/{eval_id}", - body=maybe_transform( - { - "metadata": metadata, - "name": name, - }, - eval_update_params.EvalUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalUpdateResponse, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - order_by: Literal["created_at", "updated_at"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[EvalListResponse]: - """ - List evaluations for a project. - - Args: - after: Identifier for the last eval from the previous pagination request. - - limit: Number of evals to retrieve. - - order: Sort order for evals by timestamp. Use `asc` for ascending order or `desc` for - descending order. - - order_by: Evals can be ordered by creation time or last updated time. Use `created_at` for - creation time or `updated_at` for last updated time. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/evals", - page=SyncCursorPage[EvalListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "order_by": order_by, - }, - eval_list_params.EvalListParams, - ), - ), - model=EvalListResponse, - ) - - def delete( - self, - eval_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalDeleteResponse: - """ - Delete an evaluation. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._delete( - f"/evals/{eval_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalDeleteResponse, - ) - - -class AsyncEvals(AsyncAPIResource): - @cached_property - def runs(self) -> AsyncRuns: - return AsyncRuns(self._client) - - @cached_property - def with_raw_response(self) -> AsyncEvalsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncEvalsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncEvalsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncEvalsWithStreamingResponse(self) - - async def create( - self, - *, - data_source_config: eval_create_params.DataSourceConfig, - testing_criteria: Iterable[eval_create_params.TestingCriterion], - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalCreateResponse: - """ - Create the structure of an evaluation that can be used to test a model's - performance. An evaluation is a set of testing criteria and the config for a - data source, which dictates the schema of the data used in the evaluation. After - creating an evaluation, you can run it on different models and model parameters. - We support several types of graders and datasources. For more information, see - the [Evals guide](https://platform.openai.com/docs/guides/evals). - - Args: - data_source_config: The configuration for the data source used for the evaluation runs. Dictates the - schema of the data used in the evaluation. - - testing_criteria: A list of graders for all eval runs in this group. Graders can reference - variables in the data source using double curly braces notation, like - `{{item.variable_name}}`. To reference the model's output, use the `sample` - namespace (ie, `{{sample.output_text}}`). - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the evaluation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/evals", - body=await async_maybe_transform( - { - "data_source_config": data_source_config, - "testing_criteria": testing_criteria, - "metadata": metadata, - "name": name, - }, - eval_create_params.EvalCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalCreateResponse, - ) - - async def retrieve( - self, - eval_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalRetrieveResponse: - """ - Get an evaluation by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return await self._get( - f"/evals/{eval_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalRetrieveResponse, - ) - - async def update( - self, - eval_id: str, - *, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalUpdateResponse: - """ - Update certain properties of an evaluation. - - Args: - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: Rename the evaluation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return await self._post( - f"/evals/{eval_id}", - body=await async_maybe_transform( - { - "metadata": metadata, - "name": name, - }, - eval_update_params.EvalUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalUpdateResponse, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - order_by: Literal["created_at", "updated_at"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[EvalListResponse, AsyncCursorPage[EvalListResponse]]: - """ - List evaluations for a project. - - Args: - after: Identifier for the last eval from the previous pagination request. - - limit: Number of evals to retrieve. - - order: Sort order for evals by timestamp. Use `asc` for ascending order or `desc` for - descending order. - - order_by: Evals can be ordered by creation time or last updated time. Use `created_at` for - creation time or `updated_at` for last updated time. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/evals", - page=AsyncCursorPage[EvalListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "order_by": order_by, - }, - eval_list_params.EvalListParams, - ), - ), - model=EvalListResponse, - ) - - async def delete( - self, - eval_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> EvalDeleteResponse: - """ - Delete an evaluation. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return await self._delete( - f"/evals/{eval_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EvalDeleteResponse, - ) - - -class EvalsWithRawResponse: - def __init__(self, evals: Evals) -> None: - self._evals = evals - - self.create = _legacy_response.to_raw_response_wrapper( - evals.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - evals.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - evals.update, - ) - self.list = _legacy_response.to_raw_response_wrapper( - evals.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - evals.delete, - ) - - @cached_property - def runs(self) -> RunsWithRawResponse: - return RunsWithRawResponse(self._evals.runs) - - -class AsyncEvalsWithRawResponse: - def __init__(self, evals: AsyncEvals) -> None: - self._evals = evals - - self.create = _legacy_response.async_to_raw_response_wrapper( - evals.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - evals.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - evals.update, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - evals.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - evals.delete, - ) - - @cached_property - def runs(self) -> AsyncRunsWithRawResponse: - return AsyncRunsWithRawResponse(self._evals.runs) - - -class EvalsWithStreamingResponse: - def __init__(self, evals: Evals) -> None: - self._evals = evals - - self.create = to_streamed_response_wrapper( - evals.create, - ) - self.retrieve = to_streamed_response_wrapper( - evals.retrieve, - ) - self.update = to_streamed_response_wrapper( - evals.update, - ) - self.list = to_streamed_response_wrapper( - evals.list, - ) - self.delete = to_streamed_response_wrapper( - evals.delete, - ) - - @cached_property - def runs(self) -> RunsWithStreamingResponse: - return RunsWithStreamingResponse(self._evals.runs) - - -class AsyncEvalsWithStreamingResponse: - def __init__(self, evals: AsyncEvals) -> None: - self._evals = evals - - self.create = async_to_streamed_response_wrapper( - evals.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - evals.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - evals.update, - ) - self.list = async_to_streamed_response_wrapper( - evals.list, - ) - self.delete = async_to_streamed_response_wrapper( - evals.delete, - ) - - @cached_property - def runs(self) -> AsyncRunsWithStreamingResponse: - return AsyncRunsWithStreamingResponse(self._evals.runs) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/__init__.py deleted file mode 100644 index d189f16..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .runs import ( - Runs, - AsyncRuns, - RunsWithRawResponse, - AsyncRunsWithRawResponse, - RunsWithStreamingResponse, - AsyncRunsWithStreamingResponse, -) -from .output_items import ( - OutputItems, - AsyncOutputItems, - OutputItemsWithRawResponse, - AsyncOutputItemsWithRawResponse, - OutputItemsWithStreamingResponse, - AsyncOutputItemsWithStreamingResponse, -) - -__all__ = [ - "OutputItems", - "AsyncOutputItems", - "OutputItemsWithRawResponse", - "AsyncOutputItemsWithRawResponse", - "OutputItemsWithStreamingResponse", - "AsyncOutputItemsWithStreamingResponse", - "Runs", - "AsyncRuns", - "RunsWithRawResponse", - "AsyncRunsWithRawResponse", - "RunsWithStreamingResponse", - "AsyncRunsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/output_items.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/output_items.py deleted file mode 100644 index c2dee72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/output_items.py +++ /dev/null @@ -1,315 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.evals.runs import output_item_list_params -from ....types.evals.runs.output_item_list_response import OutputItemListResponse -from ....types.evals.runs.output_item_retrieve_response import OutputItemRetrieveResponse - -__all__ = ["OutputItems", "AsyncOutputItems"] - - -class OutputItems(SyncAPIResource): - @cached_property - def with_raw_response(self) -> OutputItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return OutputItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> OutputItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return OutputItemsWithStreamingResponse(self) - - def retrieve( - self, - output_item_id: str, - *, - eval_id: str, - run_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> OutputItemRetrieveResponse: - """ - Get an evaluation run output item by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - if not output_item_id: - raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") - return self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=OutputItemRetrieveResponse, - ) - - def list( - self, - run_id: str, - *, - eval_id: str, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - status: Literal["fail", "pass"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[OutputItemListResponse]: - """ - Get a list of output items for an evaluation run. - - Args: - after: Identifier for the last output item from the previous pagination request. - - limit: Number of output items to retrieve. - - order: Sort order for output items by timestamp. Use `asc` for ascending order or - `desc` for descending order. Defaults to `asc`. - - status: Filter output items by status. Use `failed` to filter by failed output items or - `pass` to filter by passed output items. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", - page=SyncCursorPage[OutputItemListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "status": status, - }, - output_item_list_params.OutputItemListParams, - ), - ), - model=OutputItemListResponse, - ) - - -class AsyncOutputItems(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncOutputItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncOutputItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncOutputItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncOutputItemsWithStreamingResponse(self) - - async def retrieve( - self, - output_item_id: str, - *, - eval_id: str, - run_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> OutputItemRetrieveResponse: - """ - Get an evaluation run output item by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - if not output_item_id: - raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") - return await self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=OutputItemRetrieveResponse, - ) - - def list( - self, - run_id: str, - *, - eval_id: str, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - status: Literal["fail", "pass"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[OutputItemListResponse, AsyncCursorPage[OutputItemListResponse]]: - """ - Get a list of output items for an evaluation run. - - Args: - after: Identifier for the last output item from the previous pagination request. - - limit: Number of output items to retrieve. - - order: Sort order for output items by timestamp. Use `asc` for ascending order or - `desc` for descending order. Defaults to `asc`. - - status: Filter output items by status. Use `failed` to filter by failed output items or - `pass` to filter by passed output items. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", - page=AsyncCursorPage[OutputItemListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "status": status, - }, - output_item_list_params.OutputItemListParams, - ), - ), - model=OutputItemListResponse, - ) - - -class OutputItemsWithRawResponse: - def __init__(self, output_items: OutputItems) -> None: - self._output_items = output_items - - self.retrieve = _legacy_response.to_raw_response_wrapper( - output_items.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - output_items.list, - ) - - -class AsyncOutputItemsWithRawResponse: - def __init__(self, output_items: AsyncOutputItems) -> None: - self._output_items = output_items - - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - output_items.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - output_items.list, - ) - - -class OutputItemsWithStreamingResponse: - def __init__(self, output_items: OutputItems) -> None: - self._output_items = output_items - - self.retrieve = to_streamed_response_wrapper( - output_items.retrieve, - ) - self.list = to_streamed_response_wrapper( - output_items.list, - ) - - -class AsyncOutputItemsWithStreamingResponse: - def __init__(self, output_items: AsyncOutputItems) -> None: - self._output_items = output_items - - self.retrieve = async_to_streamed_response_wrapper( - output_items.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - output_items.list, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/runs.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/runs.py deleted file mode 100644 index b747b19..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/evals/runs/runs.py +++ /dev/null @@ -1,634 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .output_items import ( - OutputItems, - AsyncOutputItems, - OutputItemsWithRawResponse, - AsyncOutputItemsWithRawResponse, - OutputItemsWithStreamingResponse, - AsyncOutputItemsWithStreamingResponse, -) -from ....pagination import SyncCursorPage, AsyncCursorPage -from ....types.evals import run_list_params, run_create_params -from ...._base_client import AsyncPaginator, make_request_options -from ....types.shared_params.metadata import Metadata -from ....types.evals.run_list_response import RunListResponse -from ....types.evals.run_cancel_response import RunCancelResponse -from ....types.evals.run_create_response import RunCreateResponse -from ....types.evals.run_delete_response import RunDeleteResponse -from ....types.evals.run_retrieve_response import RunRetrieveResponse - -__all__ = ["Runs", "AsyncRuns"] - - -class Runs(SyncAPIResource): - @cached_property - def output_items(self) -> OutputItems: - return OutputItems(self._client) - - @cached_property - def with_raw_response(self) -> RunsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return RunsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RunsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return RunsWithStreamingResponse(self) - - def create( - self, - eval_id: str, - *, - data_source: run_create_params.DataSource, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCreateResponse: - """ - Kicks off a new run for a given evaluation, specifying the data source, and what - model configuration to use to test. The datasource will be validated against the - schema specified in the config of the evaluation. - - Args: - data_source: Details about the run's data source. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._post( - f"/evals/{eval_id}/runs", - body=maybe_transform( - { - "data_source": data_source, - "metadata": metadata, - "name": name, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunCreateResponse, - ) - - def retrieve( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunRetrieveResponse: - """ - Get an evaluation run by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._get( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunRetrieveResponse, - ) - - def list( - self, - eval_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RunListResponse]: - """ - Get a list of runs for an evaluation. - - Args: - after: Identifier for the last run from the previous pagination request. - - limit: Number of runs to retrieve. - - order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for - descending order. Defaults to `asc`. - - status: Filter runs by status. One of `queued` | `in_progress` | `failed` | `completed` - | `canceled`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._get_api_list( - f"/evals/{eval_id}/runs", - page=SyncCursorPage[RunListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "status": status, - }, - run_list_params.RunListParams, - ), - ), - model=RunListResponse, - ) - - def delete( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunDeleteResponse: - """ - Delete an eval run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._delete( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunDeleteResponse, - ) - - def cancel( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCancelResponse: - """ - Cancel an ongoing evaluation run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return self._post( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunCancelResponse, - ) - - -class AsyncRuns(AsyncAPIResource): - @cached_property - def output_items(self) -> AsyncOutputItems: - return AsyncOutputItems(self._client) - - @cached_property - def with_raw_response(self) -> AsyncRunsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncRunsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRunsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncRunsWithStreamingResponse(self) - - async def create( - self, - eval_id: str, - *, - data_source: run_create_params.DataSource, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCreateResponse: - """ - Kicks off a new run for a given evaluation, specifying the data source, and what - model configuration to use to test. The datasource will be validated against the - schema specified in the config of the evaluation. - - Args: - data_source: Details about the run's data source. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the run. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return await self._post( - f"/evals/{eval_id}/runs", - body=await async_maybe_transform( - { - "data_source": data_source, - "metadata": metadata, - "name": name, - }, - run_create_params.RunCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunCreateResponse, - ) - - async def retrieve( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunRetrieveResponse: - """ - Get an evaluation run by ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._get( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunRetrieveResponse, - ) - - def list( - self, - eval_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - status: Literal["queued", "in_progress", "completed", "canceled", "failed"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RunListResponse, AsyncCursorPage[RunListResponse]]: - """ - Get a list of runs for an evaluation. - - Args: - after: Identifier for the last run from the previous pagination request. - - limit: Number of runs to retrieve. - - order: Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for - descending order. Defaults to `asc`. - - status: Filter runs by status. One of `queued` | `in_progress` | `failed` | `completed` - | `canceled`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - return self._get_api_list( - f"/evals/{eval_id}/runs", - page=AsyncCursorPage[RunListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "status": status, - }, - run_list_params.RunListParams, - ), - ), - model=RunListResponse, - ) - - async def delete( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunDeleteResponse: - """ - Delete an eval run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._delete( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunDeleteResponse, - ) - - async def cancel( - self, - run_id: str, - *, - eval_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCancelResponse: - """ - Cancel an ongoing evaluation run. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not eval_id: - raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") - if not run_id: - raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - return await self._post( - f"/evals/{eval_id}/runs/{run_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RunCancelResponse, - ) - - -class RunsWithRawResponse: - def __init__(self, runs: Runs) -> None: - self._runs = runs - - self.create = _legacy_response.to_raw_response_wrapper( - runs.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - runs.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - runs.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - runs.delete, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - runs.cancel, - ) - - @cached_property - def output_items(self) -> OutputItemsWithRawResponse: - return OutputItemsWithRawResponse(self._runs.output_items) - - -class AsyncRunsWithRawResponse: - def __init__(self, runs: AsyncRuns) -> None: - self._runs = runs - - self.create = _legacy_response.async_to_raw_response_wrapper( - runs.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - runs.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - runs.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - runs.delete, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - runs.cancel, - ) - - @cached_property - def output_items(self) -> AsyncOutputItemsWithRawResponse: - return AsyncOutputItemsWithRawResponse(self._runs.output_items) - - -class RunsWithStreamingResponse: - def __init__(self, runs: Runs) -> None: - self._runs = runs - - self.create = to_streamed_response_wrapper( - runs.create, - ) - self.retrieve = to_streamed_response_wrapper( - runs.retrieve, - ) - self.list = to_streamed_response_wrapper( - runs.list, - ) - self.delete = to_streamed_response_wrapper( - runs.delete, - ) - self.cancel = to_streamed_response_wrapper( - runs.cancel, - ) - - @cached_property - def output_items(self) -> OutputItemsWithStreamingResponse: - return OutputItemsWithStreamingResponse(self._runs.output_items) - - -class AsyncRunsWithStreamingResponse: - def __init__(self, runs: AsyncRuns) -> None: - self._runs = runs - - self.create = async_to_streamed_response_wrapper( - runs.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - runs.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - runs.list, - ) - self.delete = async_to_streamed_response_wrapper( - runs.delete, - ) - self.cancel = async_to_streamed_response_wrapper( - runs.cancel, - ) - - @cached_property - def output_items(self) -> AsyncOutputItemsWithStreamingResponse: - return AsyncOutputItemsWithStreamingResponse(self._runs.output_items) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/files.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/files.py deleted file mode 100644 index cc117e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/files.py +++ /dev/null @@ -1,770 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import time -import typing_extensions -from typing import Mapping, cast -from typing_extensions import Literal - -import httpx - -from .. import _legacy_response -from ..types import FilePurpose, file_list_params, file_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_streamed_response_wrapper, - async_to_streamed_response_wrapper, - to_custom_streamed_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ..pagination import SyncCursorPage, AsyncCursorPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.file_object import FileObject -from ..types.file_deleted import FileDeleted -from ..types.file_purpose import FilePurpose - -__all__ = ["Files", "AsyncFiles"] - - -class Files(SyncAPIResource): - @cached_property - def with_raw_response(self) -> FilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return FilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return FilesWithStreamingResponse(self) - - def create( - self, - *, - file: FileTypes, - purpose: FilePurpose, - expires_after: file_create_params.ExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileObject: - """Upload a file that can be used across various endpoints. - - Individual files can be - up to 512 MB, and the size of all files uploaded by one organization can be up - to 1 TB. - - - The Assistants API supports files up to 2 million tokens and of specific file - types. See the - [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) - for details. - - The Fine-tuning API only supports `.jsonl` files. The input also has certain - required formats for fine-tuning - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) - or - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - models. - - The Batch API only supports `.jsonl` files up to 200 MB in size. The input - also has a specific required - [format](https://platform.openai.com/docs/api-reference/batch/request-input). - - Please [contact us](https://help.openai.com/) if you need to increase these - storage limits. - - Args: - file: The File object (not file name) to be uploaded. - - purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the - Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for - fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: - Flexible file type for any purpose - `evals`: Used for eval data sets - - expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire - after 30 days and all other files are persisted until they are manually deleted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "file": file, - "purpose": purpose, - "expires_after": expires_after, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - "/files", - body=maybe_transform(body, file_create_params.FileCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileObject, - ) - - def retrieve( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileObject: - """ - Returns information about a specific file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return self._get( - f"/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileObject, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - purpose: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[FileObject]: - """Returns a list of files. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 10,000, and the default is 10,000. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - purpose: Only return files with the given purpose. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/files", - page=SyncCursorPage[FileObject], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "purpose": purpose, - }, - file_list_params.FileListParams, - ), - ), - model=FileObject, - ) - - def delete( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileDeleted: - """ - Delete a file and remove it from all vector stores. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return self._delete( - f"/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileDeleted, - ) - - def content( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Returns the contents of the specified file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return self._get( - f"/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - @typing_extensions.deprecated("The `.content()` method should be used instead") - def retrieve_content( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: - """ - Returns the contents of the specified file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return self._get( - f"/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=str, - ) - - def wait_for_processing( - self, - id: str, - *, - poll_interval: float = 5.0, - max_wait_seconds: float = 30 * 60, - ) -> FileObject: - """Waits for the given file to be processed, default timeout is 30 mins.""" - TERMINAL_STATES = {"processed", "error", "deleted"} - - start = time.time() - file = self.retrieve(id) - while file.status not in TERMINAL_STATES: - self._sleep(poll_interval) - - file = self.retrieve(id) - if time.time() - start > max_wait_seconds: - raise RuntimeError( - f"Giving up on waiting for file {id} to finish processing after {max_wait_seconds} seconds." - ) - - return file - - -class AsyncFiles(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncFilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncFilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncFilesWithStreamingResponse(self) - - async def create( - self, - *, - file: FileTypes, - purpose: FilePurpose, - expires_after: file_create_params.ExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileObject: - """Upload a file that can be used across various endpoints. - - Individual files can be - up to 512 MB, and the size of all files uploaded by one organization can be up - to 1 TB. - - - The Assistants API supports files up to 2 million tokens and of specific file - types. See the - [Assistants Tools guide](https://platform.openai.com/docs/assistants/tools) - for details. - - The Fine-tuning API only supports `.jsonl` files. The input also has certain - required formats for fine-tuning - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input) - or - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - models. - - The Batch API only supports `.jsonl` files up to 200 MB in size. The input - also has a specific required - [format](https://platform.openai.com/docs/api-reference/batch/request-input). - - Please [contact us](https://help.openai.com/) if you need to increase these - storage limits. - - Args: - file: The File object (not file name) to be uploaded. - - purpose: The intended purpose of the uploaded file. One of: - `assistants`: Used in the - Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for - fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: - Flexible file type for any purpose - `evals`: Used for eval data sets - - expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire - after 30 days and all other files are persisted until they are manually deleted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "file": file, - "purpose": purpose, - "expires_after": expires_after, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/files", - body=await async_maybe_transform(body, file_create_params.FileCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileObject, - ) - - async def retrieve( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileObject: - """ - Returns information about a specific file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return await self._get( - f"/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileObject, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - purpose: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FileObject, AsyncCursorPage[FileObject]]: - """Returns a list of files. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 10,000, and the default is 10,000. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - purpose: Only return files with the given purpose. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/files", - page=AsyncCursorPage[FileObject], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "purpose": purpose, - }, - file_list_params.FileListParams, - ), - ), - model=FileObject, - ) - - async def delete( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FileDeleted: - """ - Delete a file and remove it from all vector stores. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return await self._delete( - f"/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FileDeleted, - ) - - async def content( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Returns the contents of the specified file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return await self._get( - f"/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - @typing_extensions.deprecated("The `.content()` method should be used instead") - async def retrieve_content( - self, - file_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: - """ - Returns the contents of the specified file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - return await self._get( - f"/files/{file_id}/content", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=str, - ) - - async def wait_for_processing( - self, - id: str, - *, - poll_interval: float = 5.0, - max_wait_seconds: float = 30 * 60, - ) -> FileObject: - """Waits for the given file to be processed, default timeout is 30 mins.""" - TERMINAL_STATES = {"processed", "error", "deleted"} - - start = time.time() - file = await self.retrieve(id) - while file.status not in TERMINAL_STATES: - await self._sleep(poll_interval) - - file = await self.retrieve(id) - if time.time() - start > max_wait_seconds: - raise RuntimeError( - f"Giving up on waiting for file {id} to finish processing after {max_wait_seconds} seconds." - ) - - return file - - -class FilesWithRawResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = _legacy_response.to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - files.delete, - ) - self.content = _legacy_response.to_raw_response_wrapper( - files.content, - ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncFilesWithRawResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = _legacy_response.async_to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - files.delete, - ) - self.content = _legacy_response.async_to_raw_response_wrapper( - files.content, - ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) - ) - - -class FilesWithStreamingResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = to_streamed_response_wrapper( - files.create, - ) - self.retrieve = to_streamed_response_wrapper( - files.retrieve, - ) - self.list = to_streamed_response_wrapper( - files.list, - ) - self.delete = to_streamed_response_wrapper( - files.delete, - ) - self.content = to_custom_streamed_response_wrapper( - files.content, - StreamedBinaryAPIResponse, - ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) - ) - - -class AsyncFilesWithStreamingResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = async_to_streamed_response_wrapper( - files.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - files.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - files.list, - ) - self.delete = async_to_streamed_response_wrapper( - files.delete, - ) - self.content = async_to_custom_streamed_response_wrapper( - files.content, - AsyncStreamedBinaryAPIResponse, - ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/__init__.py deleted file mode 100644 index c76af83..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .jobs import ( - Jobs, - AsyncJobs, - JobsWithRawResponse, - AsyncJobsWithRawResponse, - JobsWithStreamingResponse, - AsyncJobsWithStreamingResponse, -) -from .alpha import ( - Alpha, - AsyncAlpha, - AlphaWithRawResponse, - AsyncAlphaWithRawResponse, - AlphaWithStreamingResponse, - AsyncAlphaWithStreamingResponse, -) -from .checkpoints import ( - Checkpoints, - AsyncCheckpoints, - CheckpointsWithRawResponse, - AsyncCheckpointsWithRawResponse, - CheckpointsWithStreamingResponse, - AsyncCheckpointsWithStreamingResponse, -) -from .fine_tuning import ( - FineTuning, - AsyncFineTuning, - FineTuningWithRawResponse, - AsyncFineTuningWithRawResponse, - FineTuningWithStreamingResponse, - AsyncFineTuningWithStreamingResponse, -) - -__all__ = [ - "Jobs", - "AsyncJobs", - "JobsWithRawResponse", - "AsyncJobsWithRawResponse", - "JobsWithStreamingResponse", - "AsyncJobsWithStreamingResponse", - "Checkpoints", - "AsyncCheckpoints", - "CheckpointsWithRawResponse", - "AsyncCheckpointsWithRawResponse", - "CheckpointsWithStreamingResponse", - "AsyncCheckpointsWithStreamingResponse", - "Alpha", - "AsyncAlpha", - "AlphaWithRawResponse", - "AsyncAlphaWithRawResponse", - "AlphaWithStreamingResponse", - "AsyncAlphaWithStreamingResponse", - "FineTuning", - "AsyncFineTuning", - "FineTuningWithRawResponse", - "AsyncFineTuningWithRawResponse", - "FineTuningWithStreamingResponse", - "AsyncFineTuningWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/__init__.py deleted file mode 100644 index 8bed8af..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .alpha import ( - Alpha, - AsyncAlpha, - AlphaWithRawResponse, - AsyncAlphaWithRawResponse, - AlphaWithStreamingResponse, - AsyncAlphaWithStreamingResponse, -) -from .graders import ( - Graders, - AsyncGraders, - GradersWithRawResponse, - AsyncGradersWithRawResponse, - GradersWithStreamingResponse, - AsyncGradersWithStreamingResponse, -) - -__all__ = [ - "Graders", - "AsyncGraders", - "GradersWithRawResponse", - "AsyncGradersWithRawResponse", - "GradersWithStreamingResponse", - "AsyncGradersWithStreamingResponse", - "Alpha", - "AsyncAlpha", - "AlphaWithRawResponse", - "AsyncAlphaWithRawResponse", - "AlphaWithStreamingResponse", - "AsyncAlphaWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/alpha.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/alpha.py deleted file mode 100644 index 54c05fa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/alpha.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .graders import ( - Graders, - AsyncGraders, - GradersWithRawResponse, - AsyncGradersWithRawResponse, - GradersWithStreamingResponse, - AsyncGradersWithStreamingResponse, -) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["Alpha", "AsyncAlpha"] - - -class Alpha(SyncAPIResource): - @cached_property - def graders(self) -> Graders: - return Graders(self._client) - - @cached_property - def with_raw_response(self) -> AlphaWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AlphaWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AlphaWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AlphaWithStreamingResponse(self) - - -class AsyncAlpha(AsyncAPIResource): - @cached_property - def graders(self) -> AsyncGraders: - return AsyncGraders(self._client) - - @cached_property - def with_raw_response(self) -> AsyncAlphaWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncAlphaWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAlphaWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncAlphaWithStreamingResponse(self) - - -class AlphaWithRawResponse: - def __init__(self, alpha: Alpha) -> None: - self._alpha = alpha - - @cached_property - def graders(self) -> GradersWithRawResponse: - return GradersWithRawResponse(self._alpha.graders) - - -class AsyncAlphaWithRawResponse: - def __init__(self, alpha: AsyncAlpha) -> None: - self._alpha = alpha - - @cached_property - def graders(self) -> AsyncGradersWithRawResponse: - return AsyncGradersWithRawResponse(self._alpha.graders) - - -class AlphaWithStreamingResponse: - def __init__(self, alpha: Alpha) -> None: - self._alpha = alpha - - @cached_property - def graders(self) -> GradersWithStreamingResponse: - return GradersWithStreamingResponse(self._alpha.graders) - - -class AsyncAlphaWithStreamingResponse: - def __init__(self, alpha: AsyncAlpha) -> None: - self._alpha = alpha - - @cached_property - def graders(self) -> AsyncGradersWithStreamingResponse: - return AsyncGradersWithStreamingResponse(self._alpha.graders) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/graders.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/graders.py deleted file mode 100644 index e7a9b92..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/alpha/graders.py +++ /dev/null @@ -1,282 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...._base_client import make_request_options -from ....types.fine_tuning.alpha import grader_run_params, grader_validate_params -from ....types.fine_tuning.alpha.grader_run_response import GraderRunResponse -from ....types.fine_tuning.alpha.grader_validate_response import GraderValidateResponse - -__all__ = ["Graders", "AsyncGraders"] - - -class Graders(SyncAPIResource): - @cached_property - def with_raw_response(self) -> GradersWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return GradersWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> GradersWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return GradersWithStreamingResponse(self) - - def run( - self, - *, - grader: grader_run_params.Grader, - model_sample: str, - item: object | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraderRunResponse: - """ - Run a grader. - - Args: - grader: The grader used for the fine-tuning job. - - model_sample: The model sample to be evaluated. This value will be used to populate the - `sample` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - The `output_json` variable will be populated if the model sample is a valid JSON - string. - - item: The dataset item provided to the grader. This will be used to populate the - `item` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/fine_tuning/alpha/graders/run", - body=maybe_transform( - { - "grader": grader, - "model_sample": model_sample, - "item": item, - }, - grader_run_params.GraderRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=GraderRunResponse, - ) - - def validate( - self, - *, - grader: grader_validate_params.Grader, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraderValidateResponse: - """ - Validate a grader. - - Args: - grader: The grader used for the fine-tuning job. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/fine_tuning/alpha/graders/validate", - body=maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=GraderValidateResponse, - ) - - -class AsyncGraders(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncGradersWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncGradersWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncGradersWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncGradersWithStreamingResponse(self) - - async def run( - self, - *, - grader: grader_run_params.Grader, - model_sample: str, - item: object | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraderRunResponse: - """ - Run a grader. - - Args: - grader: The grader used for the fine-tuning job. - - model_sample: The model sample to be evaluated. This value will be used to populate the - `sample` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - The `output_json` variable will be populated if the model sample is a valid JSON - string. - - item: The dataset item provided to the grader. This will be used to populate the - `item` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/fine_tuning/alpha/graders/run", - body=await async_maybe_transform( - { - "grader": grader, - "model_sample": model_sample, - "item": item, - }, - grader_run_params.GraderRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=GraderRunResponse, - ) - - async def validate( - self, - *, - grader: grader_validate_params.Grader, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraderValidateResponse: - """ - Validate a grader. - - Args: - grader: The grader used for the fine-tuning job. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/fine_tuning/alpha/graders/validate", - body=await async_maybe_transform({"grader": grader}, grader_validate_params.GraderValidateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=GraderValidateResponse, - ) - - -class GradersWithRawResponse: - def __init__(self, graders: Graders) -> None: - self._graders = graders - - self.run = _legacy_response.to_raw_response_wrapper( - graders.run, - ) - self.validate = _legacy_response.to_raw_response_wrapper( - graders.validate, - ) - - -class AsyncGradersWithRawResponse: - def __init__(self, graders: AsyncGraders) -> None: - self._graders = graders - - self.run = _legacy_response.async_to_raw_response_wrapper( - graders.run, - ) - self.validate = _legacy_response.async_to_raw_response_wrapper( - graders.validate, - ) - - -class GradersWithStreamingResponse: - def __init__(self, graders: Graders) -> None: - self._graders = graders - - self.run = to_streamed_response_wrapper( - graders.run, - ) - self.validate = to_streamed_response_wrapper( - graders.validate, - ) - - -class AsyncGradersWithStreamingResponse: - def __init__(self, graders: AsyncGraders) -> None: - self._graders = graders - - self.run = async_to_streamed_response_wrapper( - graders.run, - ) - self.validate = async_to_streamed_response_wrapper( - graders.validate, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/__init__.py deleted file mode 100644 index fdc3794..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .checkpoints import ( - Checkpoints, - AsyncCheckpoints, - CheckpointsWithRawResponse, - AsyncCheckpointsWithRawResponse, - CheckpointsWithStreamingResponse, - AsyncCheckpointsWithStreamingResponse, -) -from .permissions import ( - Permissions, - AsyncPermissions, - PermissionsWithRawResponse, - AsyncPermissionsWithRawResponse, - PermissionsWithStreamingResponse, - AsyncPermissionsWithStreamingResponse, -) - -__all__ = [ - "Permissions", - "AsyncPermissions", - "PermissionsWithRawResponse", - "AsyncPermissionsWithRawResponse", - "PermissionsWithStreamingResponse", - "AsyncPermissionsWithStreamingResponse", - "Checkpoints", - "AsyncCheckpoints", - "CheckpointsWithRawResponse", - "AsyncCheckpointsWithRawResponse", - "CheckpointsWithStreamingResponse", - "AsyncCheckpointsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/checkpoints.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/checkpoints.py deleted file mode 100644 index f59976a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/checkpoints.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ...._compat import cached_property -from .permissions import ( - Permissions, - AsyncPermissions, - PermissionsWithRawResponse, - AsyncPermissionsWithRawResponse, - PermissionsWithStreamingResponse, - AsyncPermissionsWithStreamingResponse, -) -from ...._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["Checkpoints", "AsyncCheckpoints"] - - -class Checkpoints(SyncAPIResource): - @cached_property - def permissions(self) -> Permissions: - return Permissions(self._client) - - @cached_property - def with_raw_response(self) -> CheckpointsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CheckpointsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CheckpointsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CheckpointsWithStreamingResponse(self) - - -class AsyncCheckpoints(AsyncAPIResource): - @cached_property - def permissions(self) -> AsyncPermissions: - return AsyncPermissions(self._client) - - @cached_property - def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCheckpointsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCheckpointsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCheckpointsWithStreamingResponse(self) - - -class CheckpointsWithRawResponse: - def __init__(self, checkpoints: Checkpoints) -> None: - self._checkpoints = checkpoints - - @cached_property - def permissions(self) -> PermissionsWithRawResponse: - return PermissionsWithRawResponse(self._checkpoints.permissions) - - -class AsyncCheckpointsWithRawResponse: - def __init__(self, checkpoints: AsyncCheckpoints) -> None: - self._checkpoints = checkpoints - - @cached_property - def permissions(self) -> AsyncPermissionsWithRawResponse: - return AsyncPermissionsWithRawResponse(self._checkpoints.permissions) - - -class CheckpointsWithStreamingResponse: - def __init__(self, checkpoints: Checkpoints) -> None: - self._checkpoints = checkpoints - - @cached_property - def permissions(self) -> PermissionsWithStreamingResponse: - return PermissionsWithStreamingResponse(self._checkpoints.permissions) - - -class AsyncCheckpointsWithStreamingResponse: - def __init__(self, checkpoints: AsyncCheckpoints) -> None: - self._checkpoints = checkpoints - - @cached_property - def permissions(self) -> AsyncPermissionsWithStreamingResponse: - return AsyncPermissionsWithStreamingResponse(self._checkpoints.permissions) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/permissions.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/permissions.py deleted file mode 100644 index e7f55b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/checkpoints/permissions.py +++ /dev/null @@ -1,418 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncPage, AsyncPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.fine_tuning.checkpoints import permission_create_params, permission_retrieve_params -from ....types.fine_tuning.checkpoints.permission_create_response import PermissionCreateResponse -from ....types.fine_tuning.checkpoints.permission_delete_response import PermissionDeleteResponse -from ....types.fine_tuning.checkpoints.permission_retrieve_response import PermissionRetrieveResponse - -__all__ = ["Permissions", "AsyncPermissions"] - - -class Permissions(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PermissionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return PermissionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PermissionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return PermissionsWithStreamingResponse(self) - - def create( - self, - fine_tuned_model_checkpoint: str, - *, - project_ids: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[PermissionCreateResponse]: - """ - **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). - - This enables organization owners to share fine-tuned models with other projects - in their organization. - - Args: - project_ids: The project identifiers to grant access to. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - page=SyncPage[PermissionCreateResponse], - body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=PermissionCreateResponse, - method="post", - ) - - def retrieve( - self, - fine_tuned_model_checkpoint: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["ascending", "descending"] | Omit = omit, - project_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PermissionRetrieveResponse: - """ - **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). - - Organization owners can use this endpoint to view all permissions for a - fine-tuned model checkpoint. - - Args: - after: Identifier for the last permission ID from the previous pagination request. - - limit: Number of permissions to retrieve. - - order: The order in which to retrieve permissions. - - project_id: The ID of the project to get permissions for. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - return self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "project_id": project_id, - }, - permission_retrieve_params.PermissionRetrieveParams, - ), - ), - cast_to=PermissionRetrieveResponse, - ) - - def delete( - self, - permission_id: str, - *, - fine_tuned_model_checkpoint: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PermissionDeleteResponse: - """ - **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). - - Organization owners can use this endpoint to delete a permission for a - fine-tuned model checkpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - if not permission_id: - raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") - return self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PermissionDeleteResponse, - ) - - -class AsyncPermissions(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPermissionsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncPermissionsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPermissionsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncPermissionsWithStreamingResponse(self) - - def create( - self, - fine_tuned_model_checkpoint: str, - *, - project_ids: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PermissionCreateResponse, AsyncPage[PermissionCreateResponse]]: - """ - **NOTE:** Calling this endpoint requires an [admin API key](../admin-api-keys). - - This enables organization owners to share fine-tuned models with other projects - in their organization. - - Args: - project_ids: The project identifiers to grant access to. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - page=AsyncPage[PermissionCreateResponse], - body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=PermissionCreateResponse, - method="post", - ) - - async def retrieve( - self, - fine_tuned_model_checkpoint: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["ascending", "descending"] | Omit = omit, - project_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PermissionRetrieveResponse: - """ - **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). - - Organization owners can use this endpoint to view all permissions for a - fine-tuned model checkpoint. - - Args: - after: Identifier for the last permission ID from the previous pagination request. - - limit: Number of permissions to retrieve. - - order: The order in which to retrieve permissions. - - project_id: The ID of the project to get permissions for. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - return await self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - "project_id": project_id, - }, - permission_retrieve_params.PermissionRetrieveParams, - ), - ), - cast_to=PermissionRetrieveResponse, - ) - - async def delete( - self, - permission_id: str, - *, - fine_tuned_model_checkpoint: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PermissionDeleteResponse: - """ - **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). - - Organization owners can use this endpoint to delete a permission for a - fine-tuned model checkpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuned_model_checkpoint: - raise ValueError( - f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" - ) - if not permission_id: - raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") - return await self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PermissionDeleteResponse, - ) - - -class PermissionsWithRawResponse: - def __init__(self, permissions: Permissions) -> None: - self._permissions = permissions - - self.create = _legacy_response.to_raw_response_wrapper( - permissions.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - permissions.retrieve, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - permissions.delete, - ) - - -class AsyncPermissionsWithRawResponse: - def __init__(self, permissions: AsyncPermissions) -> None: - self._permissions = permissions - - self.create = _legacy_response.async_to_raw_response_wrapper( - permissions.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - permissions.retrieve, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - permissions.delete, - ) - - -class PermissionsWithStreamingResponse: - def __init__(self, permissions: Permissions) -> None: - self._permissions = permissions - - self.create = to_streamed_response_wrapper( - permissions.create, - ) - self.retrieve = to_streamed_response_wrapper( - permissions.retrieve, - ) - self.delete = to_streamed_response_wrapper( - permissions.delete, - ) - - -class AsyncPermissionsWithStreamingResponse: - def __init__(self, permissions: AsyncPermissions) -> None: - self._permissions = permissions - - self.create = async_to_streamed_response_wrapper( - permissions.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - permissions.retrieve, - ) - self.delete = async_to_streamed_response_wrapper( - permissions.delete, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/fine_tuning.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/fine_tuning.py deleted file mode 100644 index 25ae3e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/fine_tuning.py +++ /dev/null @@ -1,166 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..._compat import cached_property -from .jobs.jobs import ( - Jobs, - AsyncJobs, - JobsWithRawResponse, - AsyncJobsWithRawResponse, - JobsWithStreamingResponse, - AsyncJobsWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from .alpha.alpha import ( - Alpha, - AsyncAlpha, - AlphaWithRawResponse, - AsyncAlphaWithRawResponse, - AlphaWithStreamingResponse, - AsyncAlphaWithStreamingResponse, -) -from .checkpoints.checkpoints import ( - Checkpoints, - AsyncCheckpoints, - CheckpointsWithRawResponse, - AsyncCheckpointsWithRawResponse, - CheckpointsWithStreamingResponse, - AsyncCheckpointsWithStreamingResponse, -) - -__all__ = ["FineTuning", "AsyncFineTuning"] - - -class FineTuning(SyncAPIResource): - @cached_property - def jobs(self) -> Jobs: - return Jobs(self._client) - - @cached_property - def checkpoints(self) -> Checkpoints: - return Checkpoints(self._client) - - @cached_property - def alpha(self) -> Alpha: - return Alpha(self._client) - - @cached_property - def with_raw_response(self) -> FineTuningWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return FineTuningWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FineTuningWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return FineTuningWithStreamingResponse(self) - - -class AsyncFineTuning(AsyncAPIResource): - @cached_property - def jobs(self) -> AsyncJobs: - return AsyncJobs(self._client) - - @cached_property - def checkpoints(self) -> AsyncCheckpoints: - return AsyncCheckpoints(self._client) - - @cached_property - def alpha(self) -> AsyncAlpha: - return AsyncAlpha(self._client) - - @cached_property - def with_raw_response(self) -> AsyncFineTuningWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncFineTuningWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFineTuningWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncFineTuningWithStreamingResponse(self) - - -class FineTuningWithRawResponse: - def __init__(self, fine_tuning: FineTuning) -> None: - self._fine_tuning = fine_tuning - - @cached_property - def jobs(self) -> JobsWithRawResponse: - return JobsWithRawResponse(self._fine_tuning.jobs) - - @cached_property - def checkpoints(self) -> CheckpointsWithRawResponse: - return CheckpointsWithRawResponse(self._fine_tuning.checkpoints) - - @cached_property - def alpha(self) -> AlphaWithRawResponse: - return AlphaWithRawResponse(self._fine_tuning.alpha) - - -class AsyncFineTuningWithRawResponse: - def __init__(self, fine_tuning: AsyncFineTuning) -> None: - self._fine_tuning = fine_tuning - - @cached_property - def jobs(self) -> AsyncJobsWithRawResponse: - return AsyncJobsWithRawResponse(self._fine_tuning.jobs) - - @cached_property - def checkpoints(self) -> AsyncCheckpointsWithRawResponse: - return AsyncCheckpointsWithRawResponse(self._fine_tuning.checkpoints) - - @cached_property - def alpha(self) -> AsyncAlphaWithRawResponse: - return AsyncAlphaWithRawResponse(self._fine_tuning.alpha) - - -class FineTuningWithStreamingResponse: - def __init__(self, fine_tuning: FineTuning) -> None: - self._fine_tuning = fine_tuning - - @cached_property - def jobs(self) -> JobsWithStreamingResponse: - return JobsWithStreamingResponse(self._fine_tuning.jobs) - - @cached_property - def checkpoints(self) -> CheckpointsWithStreamingResponse: - return CheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) - - @cached_property - def alpha(self) -> AlphaWithStreamingResponse: - return AlphaWithStreamingResponse(self._fine_tuning.alpha) - - -class AsyncFineTuningWithStreamingResponse: - def __init__(self, fine_tuning: AsyncFineTuning) -> None: - self._fine_tuning = fine_tuning - - @cached_property - def jobs(self) -> AsyncJobsWithStreamingResponse: - return AsyncJobsWithStreamingResponse(self._fine_tuning.jobs) - - @cached_property - def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: - return AsyncCheckpointsWithStreamingResponse(self._fine_tuning.checkpoints) - - @cached_property - def alpha(self) -> AsyncAlphaWithStreamingResponse: - return AsyncAlphaWithStreamingResponse(self._fine_tuning.alpha) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/__init__.py deleted file mode 100644 index 94cd1fb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .jobs import ( - Jobs, - AsyncJobs, - JobsWithRawResponse, - AsyncJobsWithRawResponse, - JobsWithStreamingResponse, - AsyncJobsWithStreamingResponse, -) -from .checkpoints import ( - Checkpoints, - AsyncCheckpoints, - CheckpointsWithRawResponse, - AsyncCheckpointsWithRawResponse, - CheckpointsWithStreamingResponse, - AsyncCheckpointsWithStreamingResponse, -) - -__all__ = [ - "Checkpoints", - "AsyncCheckpoints", - "CheckpointsWithRawResponse", - "AsyncCheckpointsWithRawResponse", - "CheckpointsWithStreamingResponse", - "AsyncCheckpointsWithStreamingResponse", - "Jobs", - "AsyncJobs", - "JobsWithRawResponse", - "AsyncJobsWithRawResponse", - "JobsWithStreamingResponse", - "AsyncJobsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/checkpoints.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/checkpoints.py deleted file mode 100644 index f65856f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/checkpoints.py +++ /dev/null @@ -1,199 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) -from ....types.fine_tuning.jobs import checkpoint_list_params -from ....types.fine_tuning.jobs.fine_tuning_job_checkpoint import FineTuningJobCheckpoint - -__all__ = ["Checkpoints", "AsyncCheckpoints"] - - -class Checkpoints(SyncAPIResource): - @cached_property - def with_raw_response(self) -> CheckpointsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CheckpointsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CheckpointsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CheckpointsWithStreamingResponse(self) - - def list( - self, - fine_tuning_job_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[FineTuningJobCheckpoint]: - """ - List checkpoints for a fine-tuning job. - - Args: - after: Identifier for the last checkpoint ID from the previous pagination request. - - limit: Number of checkpoints to retrieve. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", - page=SyncCursorPage[FineTuningJobCheckpoint], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - checkpoint_list_params.CheckpointListParams, - ), - ), - model=FineTuningJobCheckpoint, - ) - - -class AsyncCheckpoints(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncCheckpointsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCheckpointsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCheckpointsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCheckpointsWithStreamingResponse(self) - - def list( - self, - fine_tuning_job_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FineTuningJobCheckpoint, AsyncCursorPage[FineTuningJobCheckpoint]]: - """ - List checkpoints for a fine-tuning job. - - Args: - after: Identifier for the last checkpoint ID from the previous pagination request. - - limit: Number of checkpoints to retrieve. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", - page=AsyncCursorPage[FineTuningJobCheckpoint], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - checkpoint_list_params.CheckpointListParams, - ), - ), - model=FineTuningJobCheckpoint, - ) - - -class CheckpointsWithRawResponse: - def __init__(self, checkpoints: Checkpoints) -> None: - self._checkpoints = checkpoints - - self.list = _legacy_response.to_raw_response_wrapper( - checkpoints.list, - ) - - -class AsyncCheckpointsWithRawResponse: - def __init__(self, checkpoints: AsyncCheckpoints) -> None: - self._checkpoints = checkpoints - - self.list = _legacy_response.async_to_raw_response_wrapper( - checkpoints.list, - ) - - -class CheckpointsWithStreamingResponse: - def __init__(self, checkpoints: Checkpoints) -> None: - self._checkpoints = checkpoints - - self.list = to_streamed_response_wrapper( - checkpoints.list, - ) - - -class AsyncCheckpointsWithStreamingResponse: - def __init__(self, checkpoints: AsyncCheckpoints) -> None: - self._checkpoints = checkpoints - - self.list = async_to_streamed_response_wrapper( - checkpoints.list, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/jobs.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/jobs.py deleted file mode 100644 index b292e05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/fine_tuning/jobs/jobs.py +++ /dev/null @@ -1,918 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal - -import httpx - -from .... import _legacy_response -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from .checkpoints import ( - Checkpoints, - AsyncCheckpoints, - CheckpointsWithRawResponse, - AsyncCheckpointsWithRawResponse, - CheckpointsWithStreamingResponse, - AsyncCheckpointsWithStreamingResponse, -) -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import ( - AsyncPaginator, - make_request_options, -) -from ....types.fine_tuning import job_list_params, job_create_params, job_list_events_params -from ....types.shared_params.metadata import Metadata -from ....types.fine_tuning.fine_tuning_job import FineTuningJob -from ....types.fine_tuning.fine_tuning_job_event import FineTuningJobEvent - -__all__ = ["Jobs", "AsyncJobs"] - - -class Jobs(SyncAPIResource): - @cached_property - def checkpoints(self) -> Checkpoints: - return Checkpoints(self._client) - - @cached_property - def with_raw_response(self) -> JobsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return JobsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> JobsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return JobsWithStreamingResponse(self) - - def create( - self, - *, - model: Union[str, Literal["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]], - training_file: str, - hyperparameters: job_create_params.Hyperparameters | Omit = omit, - integrations: Optional[Iterable[job_create_params.Integration]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - method: job_create_params.Method | Omit = omit, - seed: Optional[int] | Omit = omit, - suffix: Optional[str] | Omit = omit, - validation_file: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Creates a fine-tuning job which begins the process of creating a new model from - a given dataset. - - Response includes details of the enqueued job including job status and the name - of the fine-tuned models once complete. - - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) - - Args: - model: The name of the model to fine-tune. You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). - - training_file: The ID of an uploaded file that contains training data. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your dataset must be formatted as a JSONL file. Additionally, you must upload - your file with the purpose `fine-tune`. - - The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - format, or if the fine-tuning method uses the - [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) - format. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - - hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated - in favor of `method`, and should be passed in under the `method` parameter. - - integrations: A list of integrations to enable for your fine-tuning job. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - method: The method used for fine-tuning. - - seed: The seed controls the reproducibility of the job. Passing in the same seed and - job parameters should produce the same results, but may differ in rare cases. If - a seed is not specified, one will be generated for you. - - suffix: A string of up to 64 characters that will be added to your fine-tuned model - name. - - For example, a `suffix` of "custom-model-name" would produce a model name like - `ft:gpt-4o-mini:openai:custom-model-name:7p4lURel`. - - validation_file: The ID of an uploaded file that contains validation data. - - If you provide this file, the data is used to generate validation metrics - periodically during fine-tuning. These metrics can be viewed in the fine-tuning - results file. The same data should not be present in both train and validation - files. - - Your dataset must be formatted as a JSONL file. You must upload your file with - the purpose `fine-tune`. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/fine_tuning/jobs", - body=maybe_transform( - { - "model": model, - "training_file": training_file, - "hyperparameters": hyperparameters, - "integrations": integrations, - "metadata": metadata, - "method": method, - "seed": seed, - "suffix": suffix, - "validation_file": validation_file, - }, - job_create_params.JobCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def retrieve( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Get info about a fine-tuning job. - - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - metadata: Optional[Dict[str, str]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[FineTuningJob]: - """ - List your organization's fine-tuning jobs - - Args: - after: Identifier for the last job from the previous pagination request. - - limit: Number of fine-tuning jobs to retrieve. - - metadata: Optional metadata filter. To filter, use the syntax `metadata[k]=v`. - Alternatively, set `metadata=null` to indicate no metadata. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/fine_tuning/jobs", - page=SyncCursorPage[FineTuningJob], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "metadata": metadata, - }, - job_list_params.JobListParams, - ), - ), - model=FineTuningJob, - ) - - def cancel( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Immediately cancel a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def list_events( - self, - fine_tuning_job_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[FineTuningJobEvent]: - """ - Get status updates for a fine-tuning job. - - Args: - after: Identifier for the last event from the previous pagination request. - - limit: Number of events to retrieve. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", - page=SyncCursorPage[FineTuningJobEvent], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - job_list_events_params.JobListEventsParams, - ), - ), - model=FineTuningJobEvent, - ) - - def pause( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Pause a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def resume( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Resume a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - -class AsyncJobs(AsyncAPIResource): - @cached_property - def checkpoints(self) -> AsyncCheckpoints: - return AsyncCheckpoints(self._client) - - @cached_property - def with_raw_response(self) -> AsyncJobsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncJobsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncJobsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncJobsWithStreamingResponse(self) - - async def create( - self, - *, - model: Union[str, Literal["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]], - training_file: str, - hyperparameters: job_create_params.Hyperparameters | Omit = omit, - integrations: Optional[Iterable[job_create_params.Integration]] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - method: job_create_params.Method | Omit = omit, - seed: Optional[int] | Omit = omit, - suffix: Optional[str] | Omit = omit, - validation_file: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Creates a fine-tuning job which begins the process of creating a new model from - a given dataset. - - Response includes details of the enqueued job including job status and the name - of the fine-tuned models once complete. - - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) - - Args: - model: The name of the model to fine-tune. You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). - - training_file: The ID of an uploaded file that contains training data. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your dataset must be formatted as a JSONL file. Additionally, you must upload - your file with the purpose `fine-tune`. - - The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - format, or if the fine-tuning method uses the - [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) - format. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - - hyperparameters: The hyperparameters used for the fine-tuning job. This value is now deprecated - in favor of `method`, and should be passed in under the `method` parameter. - - integrations: A list of integrations to enable for your fine-tuning job. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - method: The method used for fine-tuning. - - seed: The seed controls the reproducibility of the job. Passing in the same seed and - job parameters should produce the same results, but may differ in rare cases. If - a seed is not specified, one will be generated for you. - - suffix: A string of up to 64 characters that will be added to your fine-tuned model - name. - - For example, a `suffix` of "custom-model-name" would produce a model name like - `ft:gpt-4o-mini:openai:custom-model-name:7p4lURel`. - - validation_file: The ID of an uploaded file that contains validation data. - - If you provide this file, the data is used to generate validation metrics - periodically during fine-tuning. These metrics can be viewed in the fine-tuning - results file. The same data should not be present in both train and validation - files. - - Your dataset must be formatted as a JSONL file. You must upload your file with - the purpose `fine-tune`. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/fine_tuning/jobs", - body=await async_maybe_transform( - { - "model": model, - "training_file": training_file, - "hyperparameters": hyperparameters, - "integrations": integrations, - "metadata": metadata, - "method": method, - "seed": seed, - "suffix": suffix, - "validation_file": validation_file, - }, - job_create_params.JobCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - async def retrieve( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Get info about a fine-tuning job. - - [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return await self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - metadata: Optional[Dict[str, str]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FineTuningJob, AsyncCursorPage[FineTuningJob]]: - """ - List your organization's fine-tuning jobs - - Args: - after: Identifier for the last job from the previous pagination request. - - limit: Number of fine-tuning jobs to retrieve. - - metadata: Optional metadata filter. To filter, use the syntax `metadata[k]=v`. - Alternatively, set `metadata=null` to indicate no metadata. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/fine_tuning/jobs", - page=AsyncCursorPage[FineTuningJob], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "metadata": metadata, - }, - job_list_params.JobListParams, - ), - ), - model=FineTuningJob, - ) - - async def cancel( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Immediately cancel a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - def list_events( - self, - fine_tuning_job_id: str, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FineTuningJobEvent, AsyncCursorPage[FineTuningJobEvent]]: - """ - Get status updates for a fine-tuning job. - - Args: - after: Identifier for the last event from the previous pagination request. - - limit: Number of events to retrieve. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", - page=AsyncCursorPage[FineTuningJobEvent], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - }, - job_list_events_params.JobListEventsParams, - ), - ), - model=FineTuningJobEvent, - ) - - async def pause( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Pause a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - async def resume( - self, - fine_tuning_job_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningJob: - """ - Resume a fine-tune job. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not fine_tuning_job_id: - raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") - return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningJob, - ) - - -class JobsWithRawResponse: - def __init__(self, jobs: Jobs) -> None: - self._jobs = jobs - - self.create = _legacy_response.to_raw_response_wrapper( - jobs.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - jobs.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - jobs.list, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - jobs.cancel, - ) - self.list_events = _legacy_response.to_raw_response_wrapper( - jobs.list_events, - ) - self.pause = _legacy_response.to_raw_response_wrapper( - jobs.pause, - ) - self.resume = _legacy_response.to_raw_response_wrapper( - jobs.resume, - ) - - @cached_property - def checkpoints(self) -> CheckpointsWithRawResponse: - return CheckpointsWithRawResponse(self._jobs.checkpoints) - - -class AsyncJobsWithRawResponse: - def __init__(self, jobs: AsyncJobs) -> None: - self._jobs = jobs - - self.create = _legacy_response.async_to_raw_response_wrapper( - jobs.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - jobs.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - jobs.list, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - jobs.cancel, - ) - self.list_events = _legacy_response.async_to_raw_response_wrapper( - jobs.list_events, - ) - self.pause = _legacy_response.async_to_raw_response_wrapper( - jobs.pause, - ) - self.resume = _legacy_response.async_to_raw_response_wrapper( - jobs.resume, - ) - - @cached_property - def checkpoints(self) -> AsyncCheckpointsWithRawResponse: - return AsyncCheckpointsWithRawResponse(self._jobs.checkpoints) - - -class JobsWithStreamingResponse: - def __init__(self, jobs: Jobs) -> None: - self._jobs = jobs - - self.create = to_streamed_response_wrapper( - jobs.create, - ) - self.retrieve = to_streamed_response_wrapper( - jobs.retrieve, - ) - self.list = to_streamed_response_wrapper( - jobs.list, - ) - self.cancel = to_streamed_response_wrapper( - jobs.cancel, - ) - self.list_events = to_streamed_response_wrapper( - jobs.list_events, - ) - self.pause = to_streamed_response_wrapper( - jobs.pause, - ) - self.resume = to_streamed_response_wrapper( - jobs.resume, - ) - - @cached_property - def checkpoints(self) -> CheckpointsWithStreamingResponse: - return CheckpointsWithStreamingResponse(self._jobs.checkpoints) - - -class AsyncJobsWithStreamingResponse: - def __init__(self, jobs: AsyncJobs) -> None: - self._jobs = jobs - - self.create = async_to_streamed_response_wrapper( - jobs.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - jobs.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - jobs.list, - ) - self.cancel = async_to_streamed_response_wrapper( - jobs.cancel, - ) - self.list_events = async_to_streamed_response_wrapper( - jobs.list_events, - ) - self.pause = async_to_streamed_response_wrapper( - jobs.pause, - ) - self.resume = async_to_streamed_response_wrapper( - jobs.resume, - ) - - @cached_property - def checkpoints(self) -> AsyncCheckpointsWithStreamingResponse: - return AsyncCheckpointsWithStreamingResponse(self._jobs.checkpoints) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/images.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/images.py deleted file mode 100644 index 8058284..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/images.py +++ /dev/null @@ -1,1876 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Mapping, Optional, cast -from typing_extensions import Literal, overload - -import httpx - -from .. import _legacy_response -from ..types import image_edit_params, image_generate_params, image_create_variation_params -from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given -from .._utils import extract_files, required_args, maybe_transform, deepcopy_minimal, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .._streaming import Stream, AsyncStream -from .._base_client import make_request_options -from ..types.image_model import ImageModel -from ..types.images_response import ImagesResponse -from ..types.image_gen_stream_event import ImageGenStreamEvent -from ..types.image_edit_stream_event import ImageEditStreamEvent - -__all__ = ["Images", "AsyncImages"] - - -class Images(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ImagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ImagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ImagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ImagesWithStreamingResponse(self) - - def create_variation( - self, - *, - image: FileTypes, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """Creates a variation of a given image. - - This endpoint only supports `dall-e-2`. - - Args: - image: The image to use as the basis for the variation(s). Must be a valid PNG file, - less than 4MB, and square. - - model: The model to use for image generation. Only `dall-e-2` is supported at this - time. - - n: The number of images to generate. Must be between 1 and 10. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. - - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "image": image, - "model": model, - "n": n, - "response_format": response_format, - "size": size, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - "/images/variations", - body=maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - ) - - @overload - def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[ImageEditStreamEvent]: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | Stream[ImageEditStreamEvent]: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["image", "prompt"], ["image", "prompt", "stream"]) - def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | Stream[ImageEditStreamEvent]: - body = deepcopy_minimal( - { - "image": image, - "prompt": prompt, - "background": background, - "input_fidelity": input_fidelity, - "mask": mask, - "model": model, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "partial_images": partial_images, - "quality": quality, - "response_format": response_format, - "size": size, - "stream": stream, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - "/images/edits", - body=maybe_transform( - body, - image_edit_params.ImageEditParamsStreaming if stream else image_edit_params.ImageEditParamsNonStreaming, - ), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - stream=stream or False, - stream_cls=Stream[ImageEditStreamEvent], - ) - - @overload - def generate( - self, - *, - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def generate( - self, - *, - prompt: str, - stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[ImageGenStreamEvent]: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def generate( - self, - *, - prompt: str, - stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | Stream[ImageGenStreamEvent]: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["prompt"], ["prompt", "stream"]) - def generate( - self, - *, - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | Stream[ImageGenStreamEvent]: - return self._post( - "/images/generations", - body=maybe_transform( - { - "prompt": prompt, - "background": background, - "model": model, - "moderation": moderation, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "partial_images": partial_images, - "quality": quality, - "response_format": response_format, - "size": size, - "stream": stream, - "style": style, - "user": user, - }, - image_generate_params.ImageGenerateParamsStreaming - if stream - else image_generate_params.ImageGenerateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - stream=stream or False, - stream_cls=Stream[ImageGenStreamEvent], - ) - - -class AsyncImages(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncImagesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncImagesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncImagesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncImagesWithStreamingResponse(self) - - async def create_variation( - self, - *, - image: FileTypes, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """Creates a variation of a given image. - - This endpoint only supports `dall-e-2`. - - Args: - image: The image to use as the basis for the variation(s). Must be a valid PNG file, - less than 4MB, and square. - - model: The model to use for image generation. Only `dall-e-2` is supported at this - time. - - n: The number of images to generate. Must be between 1 and 10. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. - - size: The size of the generated images. Must be one of `256x256`, `512x512`, or - `1024x1024`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "image": image, - "model": model, - "n": n, - "response_format": response_format, - "size": size, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/images/variations", - body=await async_maybe_transform(body, image_create_variation_params.ImageCreateVariationParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - ) - - @overload - async def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[ImageEditStreamEvent]: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: - """Creates an edited or extended image given one or more source images and a - prompt. - - This endpoint supports GPT Image models (`gpt-image-1.5`, `gpt-image-1`, - and `gpt-image-1-mini`) and `dall-e-2`. - - Args: - image: The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - - prompt: A text description of the desired image(s). The maximum length is 1000 - characters for `dall-e-2`, and 32000 characters for the GPT image models. - - stream: Edit the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - input_fidelity: Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - - mask: An additional image whose fully transparent areas (e.g. where alpha is zero) - indicate where `image` should be edited. If there are multiple images provided, - the mask will be applied on the first image. Must be a valid PNG file, less than - 4MB, and have the same dimensions as `image`. - - model: The model to use for image generation. Only `dall-e-2` and the GPT image models - are supported. Defaults to `dall-e-2` unless a parameter specific to the GPT - image models is used. - - n: The number of images to generate. Must be between 1 and 10. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. The - default value is `png`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. `high`, `medium` and `low` are - only supported for the GPT image models. `dall-e-2` only supports `standard` - quality. Defaults to `auto`. - - response_format: The format in which the generated images are returned. Must be one of `url` or - `b64_json`. URLs are only valid for 60 minutes after the image has been - generated. This parameter is only supported for `dall-e-2`, as the GPT image - models always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["image", "prompt"], ["image", "prompt", "stream"]) - async def edit( - self, - *, - image: Union[FileTypes, SequenceNotStr[FileTypes]], - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - input_fidelity: Optional[Literal["high", "low"]] | Omit = omit, - mask: FileTypes | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | AsyncStream[ImageEditStreamEvent]: - body = deepcopy_minimal( - { - "image": image, - "prompt": prompt, - "background": background, - "input_fidelity": input_fidelity, - "mask": mask, - "model": model, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "partial_images": partial_images, - "quality": quality, - "response_format": response_format, - "size": size, - "stream": stream, - "user": user, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["image"], ["image", ""], ["mask"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/images/edits", - body=await async_maybe_transform( - body, - image_edit_params.ImageEditParamsStreaming if stream else image_edit_params.ImageEditParamsNonStreaming, - ), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - stream=stream or False, - stream_cls=AsyncStream[ImageEditStreamEvent], - ) - - @overload - async def generate( - self, - *, - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def generate( - self, - *, - prompt: str, - stream: Literal[True], - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[ImageGenStreamEvent]: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def generate( - self, - *, - prompt: str, - stream: bool, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: - """ - Creates an image given a prompt. - [Learn more](https://platform.openai.com/docs/guides/images). - - Args: - prompt: A text description of the desired image(s). The maximum length is 32000 - characters for the GPT image models, 1000 characters for `dall-e-2` and 4000 - characters for `dall-e-3`. - - stream: Generate the image in streaming mode. Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - - background: Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - - model: The model to use for image generation. One of `dall-e-2`, `dall-e-3`, or a GPT - image model (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to - `dall-e-2` unless a parameter specific to the GPT image models is used. - - moderation: Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - - n: The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only - `n=1` is supported. - - output_compression: The compression level (0-100%) for the generated images. This parameter is only - supported for the GPT image models with the `webp` or `jpeg` output formats, and - defaults to 100. - - output_format: The format in which the generated images are returned. This parameter is only - supported for the GPT image models. Must be one of `png`, `jpeg`, or `webp`. - - partial_images: The number of partial images to generate. This parameter is used for streaming - responses that return partial images. Value must be between 0 and 3. When set to - 0, the response will be a single image sent in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - - quality: The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - - response_format: The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes - after the image has been generated. This parameter isn't supported for the GPT - image models, which always return base64-encoded images. - - size: The size of the generated images. Must be one of `1024x1024`, `1536x1024` - (landscape), `1024x1536` (portrait), or `auto` (default value) for the GPT image - models, one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of - `1024x1024`, `1792x1024`, or `1024x1792` for `dall-e-3`. - - style: The style of the generated images. This parameter is only supported for - `dall-e-3`. Must be one of `vivid` or `natural`. Vivid causes the model to lean - towards generating hyper-real and dramatic images. Natural causes the model to - produce more natural, less hyper-real looking images. - - user: A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["prompt"], ["prompt", "stream"]) - async def generate( - self, - *, - prompt: str, - background: Optional[Literal["transparent", "opaque", "auto"]] | Omit = omit, - model: Union[str, ImageModel, None] | Omit = omit, - moderation: Optional[Literal["low", "auto"]] | Omit = omit, - n: Optional[int] | Omit = omit, - output_compression: Optional[int] | Omit = omit, - output_format: Optional[Literal["png", "jpeg", "webp"]] | Omit = omit, - partial_images: Optional[int] | Omit = omit, - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] | Omit = omit, - response_format: Optional[Literal["url", "b64_json"]] | Omit = omit, - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - style: Optional[Literal["vivid", "natural"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ImagesResponse | AsyncStream[ImageGenStreamEvent]: - return await self._post( - "/images/generations", - body=await async_maybe_transform( - { - "prompt": prompt, - "background": background, - "model": model, - "moderation": moderation, - "n": n, - "output_compression": output_compression, - "output_format": output_format, - "partial_images": partial_images, - "quality": quality, - "response_format": response_format, - "size": size, - "stream": stream, - "style": style, - "user": user, - }, - image_generate_params.ImageGenerateParamsStreaming - if stream - else image_generate_params.ImageGenerateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ImagesResponse, - stream=stream or False, - stream_cls=AsyncStream[ImageGenStreamEvent], - ) - - -class ImagesWithRawResponse: - def __init__(self, images: Images) -> None: - self._images = images - - self.create_variation = _legacy_response.to_raw_response_wrapper( - images.create_variation, - ) - self.edit = _legacy_response.to_raw_response_wrapper( - images.edit, - ) - self.generate = _legacy_response.to_raw_response_wrapper( - images.generate, - ) - - -class AsyncImagesWithRawResponse: - def __init__(self, images: AsyncImages) -> None: - self._images = images - - self.create_variation = _legacy_response.async_to_raw_response_wrapper( - images.create_variation, - ) - self.edit = _legacy_response.async_to_raw_response_wrapper( - images.edit, - ) - self.generate = _legacy_response.async_to_raw_response_wrapper( - images.generate, - ) - - -class ImagesWithStreamingResponse: - def __init__(self, images: Images) -> None: - self._images = images - - self.create_variation = to_streamed_response_wrapper( - images.create_variation, - ) - self.edit = to_streamed_response_wrapper( - images.edit, - ) - self.generate = to_streamed_response_wrapper( - images.generate, - ) - - -class AsyncImagesWithStreamingResponse: - def __init__(self, images: AsyncImages) -> None: - self._images = images - - self.create_variation = async_to_streamed_response_wrapper( - images.create_variation, - ) - self.edit = async_to_streamed_response_wrapper( - images.edit, - ) - self.generate = async_to_streamed_response_wrapper( - images.generate, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/models.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/models.py deleted file mode 100644 index a8f7691..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/models.py +++ /dev/null @@ -1,306 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .. import _legacy_response -from .._types import Body, Query, Headers, NotGiven, not_given -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..pagination import SyncPage, AsyncPage -from ..types.model import Model -from .._base_client import ( - AsyncPaginator, - make_request_options, -) -from ..types.model_deleted import ModelDeleted - -__all__ = ["Models", "AsyncModels"] - - -class Models(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ModelsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ModelsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ModelsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ModelsWithStreamingResponse(self) - - def retrieve( - self, - model: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Model: - """ - Retrieves a model instance, providing basic information about the model such as - the owner and permissioning. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not model: - raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") - return self._get( - f"/models/{model}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Model, - ) - - def list( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[Model]: - """ - Lists the currently available models, and provides basic information about each - one such as the owner and availability. - """ - return self._get_api_list( - "/models", - page=SyncPage[Model], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Model, - ) - - def delete( - self, - model: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ModelDeleted: - """Delete a fine-tuned model. - - You must have the Owner role in your organization to - delete a model. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not model: - raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") - return self._delete( - f"/models/{model}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ModelDeleted, - ) - - -class AsyncModels(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncModelsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncModelsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncModelsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncModelsWithStreamingResponse(self) - - async def retrieve( - self, - model: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Model: - """ - Retrieves a model instance, providing basic information about the model such as - the owner and permissioning. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not model: - raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") - return await self._get( - f"/models/{model}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Model, - ) - - def list( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Model, AsyncPage[Model]]: - """ - Lists the currently available models, and provides basic information about each - one such as the owner and availability. - """ - return self._get_api_list( - "/models", - page=AsyncPage[Model], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Model, - ) - - async def delete( - self, - model: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ModelDeleted: - """Delete a fine-tuned model. - - You must have the Owner role in your organization to - delete a model. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not model: - raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") - return await self._delete( - f"/models/{model}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ModelDeleted, - ) - - -class ModelsWithRawResponse: - def __init__(self, models: Models) -> None: - self._models = models - - self.retrieve = _legacy_response.to_raw_response_wrapper( - models.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - models.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - models.delete, - ) - - -class AsyncModelsWithRawResponse: - def __init__(self, models: AsyncModels) -> None: - self._models = models - - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - models.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - models.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - models.delete, - ) - - -class ModelsWithStreamingResponse: - def __init__(self, models: Models) -> None: - self._models = models - - self.retrieve = to_streamed_response_wrapper( - models.retrieve, - ) - self.list = to_streamed_response_wrapper( - models.list, - ) - self.delete = to_streamed_response_wrapper( - models.delete, - ) - - -class AsyncModelsWithStreamingResponse: - def __init__(self, models: AsyncModels) -> None: - self._models = models - - self.retrieve = async_to_streamed_response_wrapper( - models.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - models.list, - ) - self.delete = async_to_streamed_response_wrapper( - models.delete, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/moderations.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/moderations.py deleted file mode 100644 index 5f378f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/moderations.py +++ /dev/null @@ -1,197 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable - -import httpx - -from .. import _legacy_response -from ..types import moderation_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .._base_client import make_request_options -from ..types.moderation_model import ModerationModel -from ..types.moderation_create_response import ModerationCreateResponse -from ..types.moderation_multi_modal_input_param import ModerationMultiModalInputParam - -__all__ = ["Moderations", "AsyncModerations"] - - -class Moderations(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ModerationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ModerationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ModerationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ModerationsWithStreamingResponse(self) - - def create( - self, - *, - input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], - model: Union[str, ModerationModel] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ModerationCreateResponse: - """Classifies if text and/or image inputs are potentially harmful. - - Learn more in - the [moderation guide](https://platform.openai.com/docs/guides/moderation). - - Args: - input: Input (or inputs) to classify. Can be a single string, an array of strings, or - an array of multi-modal input objects similar to other models. - - model: The content moderation model you would like to use. Learn more in - [the moderation guide](https://platform.openai.com/docs/guides/moderation), and - learn about available models - [here](https://platform.openai.com/docs/models#moderation). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/moderations", - body=maybe_transform( - { - "input": input, - "model": model, - }, - moderation_create_params.ModerationCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ModerationCreateResponse, - ) - - -class AsyncModerations(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncModerationsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncModerationsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncModerationsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncModerationsWithStreamingResponse(self) - - async def create( - self, - *, - input: Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]], - model: Union[str, ModerationModel] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ModerationCreateResponse: - """Classifies if text and/or image inputs are potentially harmful. - - Learn more in - the [moderation guide](https://platform.openai.com/docs/guides/moderation). - - Args: - input: Input (or inputs) to classify. Can be a single string, an array of strings, or - an array of multi-modal input objects similar to other models. - - model: The content moderation model you would like to use. Learn more in - [the moderation guide](https://platform.openai.com/docs/guides/moderation), and - learn about available models - [here](https://platform.openai.com/docs/models#moderation). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/moderations", - body=await async_maybe_transform( - { - "input": input, - "model": model, - }, - moderation_create_params.ModerationCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ModerationCreateResponse, - ) - - -class ModerationsWithRawResponse: - def __init__(self, moderations: Moderations) -> None: - self._moderations = moderations - - self.create = _legacy_response.to_raw_response_wrapper( - moderations.create, - ) - - -class AsyncModerationsWithRawResponse: - def __init__(self, moderations: AsyncModerations) -> None: - self._moderations = moderations - - self.create = _legacy_response.async_to_raw_response_wrapper( - moderations.create, - ) - - -class ModerationsWithStreamingResponse: - def __init__(self, moderations: Moderations) -> None: - self._moderations = moderations - - self.create = to_streamed_response_wrapper( - moderations.create, - ) - - -class AsyncModerationsWithStreamingResponse: - def __init__(self, moderations: AsyncModerations) -> None: - self._moderations = moderations - - self.create = async_to_streamed_response_wrapper( - moderations.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/__init__.py deleted file mode 100644 index c118410..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .calls import ( - Calls, - AsyncCalls, - CallsWithRawResponse, - AsyncCallsWithRawResponse, - CallsWithStreamingResponse, - AsyncCallsWithStreamingResponse, -) -from .realtime import ( - Realtime, - AsyncRealtime, - RealtimeWithRawResponse, - AsyncRealtimeWithRawResponse, - RealtimeWithStreamingResponse, - AsyncRealtimeWithStreamingResponse, -) -from .client_secrets import ( - ClientSecrets, - AsyncClientSecrets, - ClientSecretsWithRawResponse, - AsyncClientSecretsWithRawResponse, - ClientSecretsWithStreamingResponse, - AsyncClientSecretsWithStreamingResponse, -) - -__all__ = [ - "ClientSecrets", - "AsyncClientSecrets", - "ClientSecretsWithRawResponse", - "AsyncClientSecretsWithRawResponse", - "ClientSecretsWithStreamingResponse", - "AsyncClientSecretsWithStreamingResponse", - "Calls", - "AsyncCalls", - "CallsWithRawResponse", - "AsyncCallsWithRawResponse", - "CallsWithStreamingResponse", - "AsyncCallsWithStreamingResponse", - "Realtime", - "AsyncRealtime", - "RealtimeWithRawResponse", - "AsyncRealtimeWithRawResponse", - "RealtimeWithStreamingResponse", - "AsyncRealtimeWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/calls.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/calls.py deleted file mode 100644 index 20a22fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/calls.py +++ /dev/null @@ -1,778 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Optional -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_streamed_response_wrapper, - async_to_streamed_response_wrapper, - to_custom_streamed_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.realtime import ( - call_refer_params, - call_accept_params, - call_create_params, - call_reject_params, -) -from ...types.responses.response_prompt_param import ResponsePromptParam -from ...types.realtime.realtime_truncation_param import RealtimeTruncationParam -from ...types.realtime.realtime_audio_config_param import RealtimeAudioConfigParam -from ...types.realtime.realtime_tools_config_param import RealtimeToolsConfigParam -from ...types.realtime.realtime_tracing_config_param import RealtimeTracingConfigParam -from ...types.realtime.realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam -from ...types.realtime.realtime_session_create_request_param import RealtimeSessionCreateRequestParam - -__all__ = ["Calls", "AsyncCalls"] - - -class Calls(SyncAPIResource): - @cached_property - def with_raw_response(self) -> CallsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return CallsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CallsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return CallsWithStreamingResponse(self) - - def create( - self, - *, - sdp: str, - session: RealtimeSessionCreateRequestParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Create a new Realtime API call over WebRTC and receive the SDP answer needed to - complete the peer connection. - - Args: - sdp: WebRTC Session Description Protocol (SDP) offer generated by the caller. - - session: Realtime session object configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "application/sdp", **(extra_headers or {})} - return self._post( - "/realtime/calls", - body=maybe_transform( - { - "sdp": sdp, - "session": session, - }, - call_create_params.CallCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - def accept( - self, - call_id: str, - *, - type: Literal["realtime"], - audio: RealtimeAudioConfigParam | Omit = omit, - include: List[Literal["item.input_audio_transcription.logprobs"]] | Omit = omit, - instructions: str | Omit = omit, - max_output_tokens: Union[int, Literal["inf"]] | Omit = omit, - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - ] - | Omit = omit, - output_modalities: List[Literal["text", "audio"]] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, - tools: RealtimeToolsConfigParam | Omit = omit, - tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, - truncation: RealtimeTruncationParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Accept an incoming SIP call and configure the realtime session that will handle - it. - - Args: - type: The type of session to create. Always `realtime` for the Realtime API. - - audio: Configuration for input and output audio. - - include: Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - - instructions: The default system instructions (i.e. system message) prepended to model calls. - This field allows the client to guide the model on desired responses. The model - can be instructed on response content and format, (e.g. "be extremely succinct", - "act friendly", "here are examples of good responses") and on audio behavior - (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The - instructions are not guaranteed to be followed by the model, but they provide - guidance to the model on the desired behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - - max_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - - model: The Realtime model used for this session. - - output_modalities: The set of modalities the model can respond with. It defaults to `["audio"]`, - indicating that the model will respond with audio plus a transcript. `["text"]` - can be used to make the model respond with text only. It is not possible to - request both `text` and `audio` at the same time. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - tool_choice: How the model chooses tools. Provide one of the string modes or force a specific - function/MCP tool. - - tools: Tools available to the model. - - tracing: Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - - truncation: When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/realtime/calls/{call_id}/accept", - body=maybe_transform( - { - "type": type, - "audio": audio, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "model": model, - "output_modalities": output_modalities, - "prompt": prompt, - "tool_choice": tool_choice, - "tools": tools, - "tracing": tracing, - "truncation": truncation, - }, - call_accept_params.CallAcceptParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def hangup( - self, - call_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - End an active Realtime API call, whether it was initiated over SIP or WebRTC. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/realtime/calls/{call_id}/hangup", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def refer( - self, - call_id: str, - *, - target_uri: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Transfer an active SIP call to a new destination using the SIP REFER verb. - - Args: - target_uri: URI that should appear in the SIP Refer-To header. Supports values like - `tel:+14155550123` or `sip:agent@example.com`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/realtime/calls/{call_id}/refer", - body=maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def reject( - self, - call_id: str, - *, - status_code: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Decline an incoming SIP call by returning a SIP status code to the caller. - - Args: - status_code: SIP response code to send back to the caller. Defaults to `603` (Decline) when - omitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/realtime/calls/{call_id}/reject", - body=maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncCalls(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncCallsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncCallsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCallsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncCallsWithStreamingResponse(self) - - async def create( - self, - *, - sdp: str, - session: RealtimeSessionCreateRequestParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """ - Create a new Realtime API call over WebRTC and receive the SDP answer needed to - complete the peer connection. - - Args: - sdp: WebRTC Session Description Protocol (SDP) offer generated by the caller. - - session: Realtime session object configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "application/sdp", **(extra_headers or {})} - return await self._post( - "/realtime/calls", - body=await async_maybe_transform( - { - "sdp": sdp, - "session": session, - }, - call_create_params.CallCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - async def accept( - self, - call_id: str, - *, - type: Literal["realtime"], - audio: RealtimeAudioConfigParam | Omit = omit, - include: List[Literal["item.input_audio_transcription.logprobs"]] | Omit = omit, - instructions: str | Omit = omit, - max_output_tokens: Union[int, Literal["inf"]] | Omit = omit, - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - ] - | Omit = omit, - output_modalities: List[Literal["text", "audio"]] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - tool_choice: RealtimeToolChoiceConfigParam | Omit = omit, - tools: RealtimeToolsConfigParam | Omit = omit, - tracing: Optional[RealtimeTracingConfigParam] | Omit = omit, - truncation: RealtimeTruncationParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Accept an incoming SIP call and configure the realtime session that will handle - it. - - Args: - type: The type of session to create. Always `realtime` for the Realtime API. - - audio: Configuration for input and output audio. - - include: Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - - instructions: The default system instructions (i.e. system message) prepended to model calls. - This field allows the client to guide the model on desired responses. The model - can be instructed on response content and format, (e.g. "be extremely succinct", - "act friendly", "here are examples of good responses") and on audio behavior - (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The - instructions are not guaranteed to be followed by the model, but they provide - guidance to the model on the desired behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - - max_output_tokens: Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - - model: The Realtime model used for this session. - - output_modalities: The set of modalities the model can respond with. It defaults to `["audio"]`, - indicating that the model will respond with audio plus a transcript. `["text"]` - can be used to make the model respond with text only. It is not possible to - request both `text` and `audio` at the same time. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - tool_choice: How the model chooses tools. Provide one of the string modes or force a specific - function/MCP tool. - - tools: Tools available to the model. - - tracing: Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - - truncation: When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/realtime/calls/{call_id}/accept", - body=await async_maybe_transform( - { - "type": type, - "audio": audio, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "model": model, - "output_modalities": output_modalities, - "prompt": prompt, - "tool_choice": tool_choice, - "tools": tools, - "tracing": tracing, - "truncation": truncation, - }, - call_accept_params.CallAcceptParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def hangup( - self, - call_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - End an active Realtime API call, whether it was initiated over SIP or WebRTC. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/realtime/calls/{call_id}/hangup", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def refer( - self, - call_id: str, - *, - target_uri: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Transfer an active SIP call to a new destination using the SIP REFER verb. - - Args: - target_uri: URI that should appear in the SIP Refer-To header. Supports values like - `tel:+14155550123` or `sip:agent@example.com`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/realtime/calls/{call_id}/refer", - body=await async_maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def reject( - self, - call_id: str, - *, - status_code: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Decline an incoming SIP call by returning a SIP status code to the caller. - - Args: - status_code: SIP response code to send back to the caller. Defaults to `603` (Decline) when - omitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not call_id: - raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/realtime/calls/{call_id}/reject", - body=await async_maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class CallsWithRawResponse: - def __init__(self, calls: Calls) -> None: - self._calls = calls - - self.create = _legacy_response.to_raw_response_wrapper( - calls.create, - ) - self.accept = _legacy_response.to_raw_response_wrapper( - calls.accept, - ) - self.hangup = _legacy_response.to_raw_response_wrapper( - calls.hangup, - ) - self.refer = _legacy_response.to_raw_response_wrapper( - calls.refer, - ) - self.reject = _legacy_response.to_raw_response_wrapper( - calls.reject, - ) - - -class AsyncCallsWithRawResponse: - def __init__(self, calls: AsyncCalls) -> None: - self._calls = calls - - self.create = _legacy_response.async_to_raw_response_wrapper( - calls.create, - ) - self.accept = _legacy_response.async_to_raw_response_wrapper( - calls.accept, - ) - self.hangup = _legacy_response.async_to_raw_response_wrapper( - calls.hangup, - ) - self.refer = _legacy_response.async_to_raw_response_wrapper( - calls.refer, - ) - self.reject = _legacy_response.async_to_raw_response_wrapper( - calls.reject, - ) - - -class CallsWithStreamingResponse: - def __init__(self, calls: Calls) -> None: - self._calls = calls - - self.create = to_custom_streamed_response_wrapper( - calls.create, - StreamedBinaryAPIResponse, - ) - self.accept = to_streamed_response_wrapper( - calls.accept, - ) - self.hangup = to_streamed_response_wrapper( - calls.hangup, - ) - self.refer = to_streamed_response_wrapper( - calls.refer, - ) - self.reject = to_streamed_response_wrapper( - calls.reject, - ) - - -class AsyncCallsWithStreamingResponse: - def __init__(self, calls: AsyncCalls) -> None: - self._calls = calls - - self.create = async_to_custom_streamed_response_wrapper( - calls.create, - AsyncStreamedBinaryAPIResponse, - ) - self.accept = async_to_streamed_response_wrapper( - calls.accept, - ) - self.hangup = async_to_streamed_response_wrapper( - calls.hangup, - ) - self.refer = async_to_streamed_response_wrapper( - calls.refer, - ) - self.reject = async_to_streamed_response_wrapper( - calls.reject, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/client_secrets.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/client_secrets.py deleted file mode 100644 index 5ceba7b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/client_secrets.py +++ /dev/null @@ -1,189 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._base_client import make_request_options -from ...types.realtime import client_secret_create_params -from ...types.realtime.client_secret_create_response import ClientSecretCreateResponse - -__all__ = ["ClientSecrets", "AsyncClientSecrets"] - - -class ClientSecrets(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ClientSecretsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ClientSecretsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ClientSecretsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ClientSecretsWithStreamingResponse(self) - - def create( - self, - *, - expires_after: client_secret_create_params.ExpiresAfter | Omit = omit, - session: client_secret_create_params.Session | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ClientSecretCreateResponse: - """ - Create a Realtime client secret with an associated session configuration. - - Args: - expires_after: Configuration for the client secret expiration. Expiration refers to the time - after which a client secret will no longer be valid for creating sessions. The - session itself may continue after that time once started. A secret can be used - to create multiple sessions until it expires. - - session: Session configuration to use for the client secret. Choose either a realtime - session or a transcription session. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/realtime/client_secrets", - body=maybe_transform( - { - "expires_after": expires_after, - "session": session, - }, - client_secret_create_params.ClientSecretCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ClientSecretCreateResponse, - ) - - -class AsyncClientSecrets(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncClientSecretsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncClientSecretsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncClientSecretsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncClientSecretsWithStreamingResponse(self) - - async def create( - self, - *, - expires_after: client_secret_create_params.ExpiresAfter | Omit = omit, - session: client_secret_create_params.Session | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ClientSecretCreateResponse: - """ - Create a Realtime client secret with an associated session configuration. - - Args: - expires_after: Configuration for the client secret expiration. Expiration refers to the time - after which a client secret will no longer be valid for creating sessions. The - session itself may continue after that time once started. A secret can be used - to create multiple sessions until it expires. - - session: Session configuration to use for the client secret. Choose either a realtime - session or a transcription session. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/realtime/client_secrets", - body=await async_maybe_transform( - { - "expires_after": expires_after, - "session": session, - }, - client_secret_create_params.ClientSecretCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ClientSecretCreateResponse, - ) - - -class ClientSecretsWithRawResponse: - def __init__(self, client_secrets: ClientSecrets) -> None: - self._client_secrets = client_secrets - - self.create = _legacy_response.to_raw_response_wrapper( - client_secrets.create, - ) - - -class AsyncClientSecretsWithRawResponse: - def __init__(self, client_secrets: AsyncClientSecrets) -> None: - self._client_secrets = client_secrets - - self.create = _legacy_response.async_to_raw_response_wrapper( - client_secrets.create, - ) - - -class ClientSecretsWithStreamingResponse: - def __init__(self, client_secrets: ClientSecrets) -> None: - self._client_secrets = client_secrets - - self.create = to_streamed_response_wrapper( - client_secrets.create, - ) - - -class AsyncClientSecretsWithStreamingResponse: - def __init__(self, client_secrets: AsyncClientSecrets) -> None: - self._client_secrets = client_secrets - - self.create = async_to_streamed_response_wrapper( - client_secrets.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/realtime.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/realtime.py deleted file mode 100644 index 44f14cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/realtime/realtime.py +++ /dev/null @@ -1,1079 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import json -import logging -from types import TracebackType -from typing import TYPE_CHECKING, Any, Iterator, cast -from typing_extensions import AsyncIterator - -import httpx -from pydantic import BaseModel - -from .calls import ( - Calls, - AsyncCalls, - CallsWithRawResponse, - AsyncCallsWithRawResponse, - CallsWithStreamingResponse, - AsyncCallsWithStreamingResponse, -) -from ..._types import Omit, Query, Headers, omit -from ..._utils import ( - is_azure_client, - maybe_transform, - strip_not_given, - async_maybe_transform, - is_async_azure_client, -) -from ..._compat import cached_property -from ..._models import construct_type_unchecked -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._exceptions import OpenAIError -from ..._base_client import _merge_mappings -from .client_secrets import ( - ClientSecrets, - AsyncClientSecrets, - ClientSecretsWithRawResponse, - AsyncClientSecretsWithRawResponse, - ClientSecretsWithStreamingResponse, - AsyncClientSecretsWithStreamingResponse, -) -from ...types.realtime import session_update_event_param -from ...types.websocket_connection_options import WebsocketConnectionOptions -from ...types.realtime.realtime_client_event import RealtimeClientEvent -from ...types.realtime.realtime_server_event import RealtimeServerEvent -from ...types.realtime.conversation_item_param import ConversationItemParam -from ...types.realtime.realtime_client_event_param import RealtimeClientEventParam -from ...types.realtime.realtime_response_create_params_param import RealtimeResponseCreateParamsParam - -if TYPE_CHECKING: - from websockets.sync.client import ClientConnection as WebsocketConnection - from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection - - from ..._client import OpenAI, AsyncOpenAI - -__all__ = ["Realtime", "AsyncRealtime"] - -log: logging.Logger = logging.getLogger(__name__) - - -class Realtime(SyncAPIResource): - @cached_property - def client_secrets(self) -> ClientSecrets: - return ClientSecrets(self._client) - - @cached_property - def calls(self) -> Calls: - from ...lib._realtime import _Calls - - return _Calls(self._client) - - @cached_property - def with_raw_response(self) -> RealtimeWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return RealtimeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RealtimeWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return RealtimeWithStreamingResponse(self) - - def connect( - self, - *, - call_id: str | Omit = omit, - model: str | Omit = omit, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, - ) -> RealtimeConnectionManager: - """ - The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. - - Some notable benefits of the API include: - - - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. - - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. - - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. - - The Realtime API is a stateful, event-based API that communicates over a WebSocket. - """ - return RealtimeConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - call_id=call_id, - model=model, - ) - - -class AsyncRealtime(AsyncAPIResource): - @cached_property - def client_secrets(self) -> AsyncClientSecrets: - return AsyncClientSecrets(self._client) - - @cached_property - def calls(self) -> AsyncCalls: - from ...lib._realtime import _AsyncCalls - - return _AsyncCalls(self._client) - - @cached_property - def with_raw_response(self) -> AsyncRealtimeWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncRealtimeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRealtimeWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncRealtimeWithStreamingResponse(self) - - def connect( - self, - *, - call_id: str | Omit = omit, - model: str | Omit = omit, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebsocketConnectionOptions = {}, - ) -> AsyncRealtimeConnectionManager: - """ - The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as function calling. - - Some notable benefits of the API include: - - - Native speech-to-speech: Skipping an intermediate text format means low latency and nuanced output. - - Natural, steerable voices: The models have natural inflection and can laugh, whisper, and adhere to tone direction. - - Simultaneous multimodal output: Text is useful for moderation; faster-than-realtime audio ensures stable playback. - - The Realtime API is a stateful, event-based API that communicates over a WebSocket. - """ - return AsyncRealtimeConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - call_id=call_id, - model=model, - ) - - -class RealtimeWithRawResponse: - def __init__(self, realtime: Realtime) -> None: - self._realtime = realtime - - @cached_property - def client_secrets(self) -> ClientSecretsWithRawResponse: - return ClientSecretsWithRawResponse(self._realtime.client_secrets) - - @cached_property - def calls(self) -> CallsWithRawResponse: - return CallsWithRawResponse(self._realtime.calls) - - -class AsyncRealtimeWithRawResponse: - def __init__(self, realtime: AsyncRealtime) -> None: - self._realtime = realtime - - @cached_property - def client_secrets(self) -> AsyncClientSecretsWithRawResponse: - return AsyncClientSecretsWithRawResponse(self._realtime.client_secrets) - - @cached_property - def calls(self) -> AsyncCallsWithRawResponse: - return AsyncCallsWithRawResponse(self._realtime.calls) - - -class RealtimeWithStreamingResponse: - def __init__(self, realtime: Realtime) -> None: - self._realtime = realtime - - @cached_property - def client_secrets(self) -> ClientSecretsWithStreamingResponse: - return ClientSecretsWithStreamingResponse(self._realtime.client_secrets) - - @cached_property - def calls(self) -> CallsWithStreamingResponse: - return CallsWithStreamingResponse(self._realtime.calls) - - -class AsyncRealtimeWithStreamingResponse: - def __init__(self, realtime: AsyncRealtime) -> None: - self._realtime = realtime - - @cached_property - def client_secrets(self) -> AsyncClientSecretsWithStreamingResponse: - return AsyncClientSecretsWithStreamingResponse(self._realtime.client_secrets) - - @cached_property - def calls(self) -> AsyncCallsWithStreamingResponse: - return AsyncCallsWithStreamingResponse(self._realtime.calls) - - -class AsyncRealtimeConnection: - """Represents a live WebSocket connection to the Realtime API""" - - session: AsyncRealtimeSessionResource - response: AsyncRealtimeResponseResource - input_audio_buffer: AsyncRealtimeInputAudioBufferResource - conversation: AsyncRealtimeConversationResource - output_audio_buffer: AsyncRealtimeOutputAudioBufferResource - - _connection: AsyncWebsocketConnection - - def __init__(self, connection: AsyncWebsocketConnection) -> None: - self._connection = connection - - self.session = AsyncRealtimeSessionResource(self) - self.response = AsyncRealtimeResponseResource(self) - self.input_audio_buffer = AsyncRealtimeInputAudioBufferResource(self) - self.conversation = AsyncRealtimeConversationResource(self) - self.output_audio_buffer = AsyncRealtimeOutputAudioBufferResource(self) - - async def __aiter__(self) -> AsyncIterator[RealtimeServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK - - try: - while True: - yield await self.recv() - except ConnectionClosedOK: - return - - async def recv(self) -> RealtimeServerEvent: - """ - Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(await self.recv_bytes()) - - async def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = await self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) - return message - - async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(await async_maybe_transform(event, RealtimeClientEventParam)) - ) - await self._connection.send(data) - - async def close(self, *, code: int = 1000, reason: str = "") -> None: - await self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> RealtimeServerEvent: - """ - Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) - ) - - -class AsyncRealtimeConnectionManager: - """ - Context manager over a `AsyncRealtimeConnection` that is returned by `realtime.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.realtime.connect(...).enter() - # ... - await connection.close() - ``` - """ - - def __init__( - self, - *, - client: AsyncOpenAI, - call_id: str | Omit = omit, - model: str | Omit = omit, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, - ) -> None: - self.__client = client - self.__call_id = call_id - self.__model = model - self.__connection: AsyncRealtimeConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - - async def __aenter__(self) -> AsyncRealtimeConnection: - """ - 👋 If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.realtime.connect(...).enter() - # ... - await connection.close() - ``` - """ - try: - from websockets.asyncio.client import connect - except ImportError as exc: - raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - - extra_query = self.__extra_query - await self.__client._refresh_api_key() - auth_headers = self.__client.auth_headers - extra_query = self.__extra_query - if self.__call_id is not omit: - extra_query = {**extra_query, "call_id": self.__call_id} - if is_async_azure_client(self.__client): - model = self.__model - if not model: - raise OpenAIError("`model` is required for Azure Realtime API") - else: - url, auth_headers = await self.__client._configure_realtime(model, extra_query) - else: - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - **({"model": self.__model} if self.__model is not omit else {}), - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - self.__connection = AsyncRealtimeConnection( - await connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) - ) - - return self.__connection - - enter = __aenter__ - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - base_url = self.__client._base_url.copy_with(scheme="wss") - - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - return base_url.copy_with(raw_path=merge_raw_path) - - async def __aexit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - await self.__connection.close() - - -class RealtimeConnection: - """Represents a live WebSocket connection to the Realtime API""" - - session: RealtimeSessionResource - response: RealtimeResponseResource - input_audio_buffer: RealtimeInputAudioBufferResource - conversation: RealtimeConversationResource - output_audio_buffer: RealtimeOutputAudioBufferResource - - _connection: WebsocketConnection - - def __init__(self, connection: WebsocketConnection) -> None: - self._connection = connection - - self.session = RealtimeSessionResource(self) - self.response = RealtimeResponseResource(self) - self.input_audio_buffer = RealtimeInputAudioBufferResource(self) - self.conversation = RealtimeConversationResource(self) - self.output_audio_buffer = RealtimeOutputAudioBufferResource(self) - - def __iter__(self) -> Iterator[RealtimeServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK - - try: - while True: - yield self.recv() - except ConnectionClosedOK: - return - - def recv(self) -> RealtimeServerEvent: - """ - Receive the next message from the connection and parses it into a `RealtimeServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(self.recv_bytes()) - - def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `RealtimeServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = self._connection.recv(decode=False) - log.debug(f"Received websocket message: %s", message) - return message - - def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(maybe_transform(event, RealtimeClientEventParam)) - ) - self._connection.send(data) - - def close(self, *, code: int = 1000, reason: str = "") -> None: - self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> RealtimeServerEvent: - """ - Converts a raw `str` or `bytes` message into a `RealtimeServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - RealtimeServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, RealtimeServerEvent)) - ) - - -class RealtimeConnectionManager: - """ - Context manager over a `RealtimeConnection` that is returned by `realtime.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.realtime.connect(...).enter() - # ... - connection.close() - ``` - """ - - def __init__( - self, - *, - client: OpenAI, - call_id: str | Omit = omit, - model: str | Omit = omit, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebsocketConnectionOptions, - ) -> None: - self.__client = client - self.__call_id = call_id - self.__model = model - self.__connection: RealtimeConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - - def __enter__(self) -> RealtimeConnection: - """ - 👋 If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.realtime.connect(...).enter() - # ... - connection.close() - ``` - """ - try: - from websockets.sync.client import connect - except ImportError as exc: - raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc - - extra_query = self.__extra_query - self.__client._refresh_api_key() - auth_headers = self.__client.auth_headers - extra_query = self.__extra_query - if self.__call_id is not omit: - extra_query = {**extra_query, "call_id": self.__call_id} - if is_azure_client(self.__client): - model = self.__model - if not model: - raise OpenAIError("`model` is required for Azure Realtime API") - else: - url, auth_headers = self.__client._configure_realtime(model, extra_query) - else: - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - **({"model": self.__model} if self.__model is not omit else {}), - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - self.__connection = RealtimeConnection( - connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **auth_headers, - }, - self.__extra_headers, - ), - **self.__websocket_connection_options, - ) - ) - - return self.__connection - - enter = __enter__ - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - base_url = self.__client._base_url.copy_with(scheme="wss") - - merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime" - return base_url.copy_with(raw_path=merge_raw_path) - - def __exit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - self.__connection.close() - - -class BaseRealtimeConnectionResource: - def __init__(self, connection: RealtimeConnection) -> None: - self._connection = connection - - -class RealtimeSessionResource(BaseRealtimeConnectionResource): - def update(self, *, session: session_update_event_param.Session, event_id: str | Omit = omit) -> None: - """ - Send this event to update the session’s configuration. - The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present in the `session.update` are updated. To clear a field like - `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. - To clear a field like `turn_detection`, pass `null`. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), - ) - ) - - -class RealtimeResponseResource(BaseRealtimeConnectionResource): - def create(self, *, event_id: str | Omit = omit, response: RealtimeResponseCreateParamsParam | Omit = omit) -> None: - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history by default. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions` and `tools`. If these are set, they will override the Session's - configuration for this Response only. - - Responses can be created out-of-band of the default Conversation, meaning that they can - have arbitrary input, and it's possible to disable writing the output to the Conversation. - Only one Response can write to the default Conversation at a time, but otherwise multiple - Responses can be created in parallel. The `metadata` field is a good way to disambiguate - multiple simultaneous Responses. - - Clients can set `conversation` to `none` to create a Response that does not write to the default - Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting - raw Items and references to existing Items. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), - ) - ) - - def cancel(self, *, event_id: str | Omit = omit, response_id: str | Omit = omit) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. It's safe - to call `response.cancel` even if no response is in progress, an error will be - returned the session will remain unaffected. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - - -class RealtimeInputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | Omit = omit) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - def commit(self, *, event_id: str | Omit = omit) -> None: - """ - Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - - Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) - ) - - def append(self, *, audio: str, event_id: str | Omit = omit) -> None: - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. A "commit" will create a new - user message item in the conversation history from the buffer content and clear the buffer. - Input audio transcription (if enabled) will be generated when the buffer is committed. - - If VAD is enabled the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. Input audio noise reduction operates on writes to the audio buffer. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike most other client events, the server will - not send a confirmation response to this event. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), - ) - ) - - -class RealtimeConversationResource(BaseRealtimeConnectionResource): - @cached_property - def item(self) -> RealtimeConversationItemResource: - return RealtimeConversationItemResource(self._connection) - - -class RealtimeConversationItemResource(BaseRealtimeConnectionResource): - def delete(self, *, item_id: str, event_id: str | Omit = omit) -> None: - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), - ) - ) - - def create( - self, *, item: ConversationItemParam, event_id: str | Omit = omit, previous_item_id: str | Omit = omit - ) -> None: - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.create", - "item": item, - "event_id": event_id, - "previous_item_id": previous_item_id, - } - ), - ) - ) - - def truncate(self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | Omit = omit) -> None: - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.truncate", - "audio_end_ms": audio_end_ms, - "content_index": content_index, - "item_id": item_id, - "event_id": event_id, - } - ), - ) - ) - - def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), - ) - ) - - -class RealtimeOutputAudioBufferResource(BaseRealtimeConnectionResource): - def clear(self, *, event_id: str | Omit = omit) -> None: - """**WebRTC/SIP Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) - ) - - -class BaseAsyncRealtimeConnectionResource: - def __init__(self, connection: AsyncRealtimeConnection) -> None: - self._connection = connection - - -class AsyncRealtimeSessionResource(BaseAsyncRealtimeConnectionResource): - async def update(self, *, session: session_update_event_param.Session, event_id: str | Omit = omit) -> None: - """ - Send this event to update the session’s configuration. - The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present in the `session.update` are updated. To clear a field like - `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. - To clear a field like `turn_detection`, pass `null`. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "session.update", "session": session, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeResponseResource(BaseAsyncRealtimeConnectionResource): - async def create( - self, *, event_id: str | Omit = omit, response: RealtimeResponseCreateParamsParam | Omit = omit - ) -> None: - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history by default. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions` and `tools`. If these are set, they will override the Session's - configuration for this Response only. - - Responses can be created out-of-band of the default Conversation, meaning that they can - have arbitrary input, and it's possible to disable writing the output to the Conversation. - Only one Response can write to the default Conversation at a time, but otherwise multiple - Responses can be created in parallel. The `metadata` field is a good way to disambiguate - multiple simultaneous Responses. - - Clients can set `conversation` to `none` to create a Response that does not write to the default - Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting - raw Items and references to existing Items. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.create", "event_id": event_id, "response": response}), - ) - ) - - async def cancel(self, *, event_id: str | Omit = omit, response_id: str | Omit = omit) -> None: - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. It's safe - to call `response.cancel` even if no response is in progress, an error will be - returned the session will remain unaffected. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "response.cancel", "event_id": event_id, "response_id": response_id}), - ) - ) - - -class AsyncRealtimeInputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | Omit = omit) -> None: - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.clear", "event_id": event_id})) - ) - - async def commit(self, *, event_id: str | Omit = omit) -> None: - """ - Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - - Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "input_audio_buffer.commit", "event_id": event_id})) - ) - - async def append(self, *, audio: str, event_id: str | Omit = omit) -> None: - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. A "commit" will create a new - user message item in the conversation history from the buffer content and clear the buffer. - Input audio transcription (if enabled) will be generated when the buffer is committed. - - If VAD is enabled the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. Input audio noise reduction operates on writes to the audio buffer. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike most other client events, the server will - not send a confirmation response to this event. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "input_audio_buffer.append", "audio": audio, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeConversationResource(BaseAsyncRealtimeConnectionResource): - @cached_property - def item(self) -> AsyncRealtimeConversationItemResource: - return AsyncRealtimeConversationItemResource(self._connection) - - -class AsyncRealtimeConversationItemResource(BaseAsyncRealtimeConnectionResource): - async def delete(self, *, item_id: str, event_id: str | Omit = omit) -> None: - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.delete", "item_id": item_id, "event_id": event_id}), - ) - ) - - async def create( - self, *, item: ConversationItemParam, event_id: str | Omit = omit, previous_item_id: str | Omit = omit - ) -> None: - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.create", - "item": item, - "event_id": event_id, - "previous_item_id": previous_item_id, - } - ), - ) - ) - - async def truncate( - self, *, audio_end_ms: int, content_index: int, item_id: str, event_id: str | Omit = omit - ) -> None: - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given( - { - "type": "conversation.item.truncate", - "audio_end_ms": audio_end_ms, - "content_index": content_index, - "item_id": item_id, - "event_id": event_id, - } - ), - ) - ) - - async def retrieve(self, *, item_id: str, event_id: str | Omit = omit) -> None: - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - await self._connection.send( - cast( - RealtimeClientEventParam, - strip_not_given({"type": "conversation.item.retrieve", "item_id": item_id, "event_id": event_id}), - ) - ) - - -class AsyncRealtimeOutputAudioBufferResource(BaseAsyncRealtimeConnectionResource): - async def clear(self, *, event_id: str | Omit = omit) -> None: - """**WebRTC/SIP Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - await self._connection.send( - cast(RealtimeClientEventParam, strip_not_given({"type": "output_audio_buffer.clear", "event_id": event_id})) - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/__init__.py deleted file mode 100644 index 51d318a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .responses import ( - Responses, - AsyncResponses, - ResponsesWithRawResponse, - AsyncResponsesWithRawResponse, - ResponsesWithStreamingResponse, - AsyncResponsesWithStreamingResponse, -) -from .input_items import ( - InputItems, - AsyncInputItems, - InputItemsWithRawResponse, - AsyncInputItemsWithRawResponse, - InputItemsWithStreamingResponse, - AsyncInputItemsWithStreamingResponse, -) -from .input_tokens import ( - InputTokens, - AsyncInputTokens, - InputTokensWithRawResponse, - AsyncInputTokensWithRawResponse, - InputTokensWithStreamingResponse, - AsyncInputTokensWithStreamingResponse, -) - -__all__ = [ - "InputItems", - "AsyncInputItems", - "InputItemsWithRawResponse", - "AsyncInputItemsWithRawResponse", - "InputItemsWithStreamingResponse", - "AsyncInputItemsWithStreamingResponse", - "InputTokens", - "AsyncInputTokens", - "InputTokensWithRawResponse", - "AsyncInputTokensWithRawResponse", - "InputTokensWithStreamingResponse", - "AsyncInputTokensWithStreamingResponse", - "Responses", - "AsyncResponses", - "ResponsesWithRawResponse", - "AsyncResponsesWithRawResponse", - "ResponsesWithStreamingResponse", - "AsyncResponsesWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_items.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_items.py deleted file mode 100644 index 3311bfe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_items.py +++ /dev/null @@ -1,226 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, List, cast -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.responses import input_item_list_params -from ...types.responses.response_item import ResponseItem -from ...types.responses.response_includable import ResponseIncludable - -__all__ = ["InputItems", "AsyncInputItems"] - - -class InputItems(SyncAPIResource): - @cached_property - def with_raw_response(self) -> InputItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return InputItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InputItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return InputItemsWithStreamingResponse(self) - - def list( - self, - response_id: str, - *, - after: str | Omit = omit, - include: List[ResponseIncludable] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ResponseItem]: - """ - Returns a list of input items for a given response. - - Args: - after: An item ID to list items after, used in pagination. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return self._get_api_list( - f"/responses/{response_id}/input_items", - page=SyncCursorPage[ResponseItem], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "include": include, - "limit": limit, - "order": order, - }, - input_item_list_params.InputItemListParams, - ), - ), - model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system - ) - - -class AsyncInputItems(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncInputItemsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncInputItemsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInputItemsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncInputItemsWithStreamingResponse(self) - - def list( - self, - response_id: str, - *, - after: str | Omit = omit, - include: List[ResponseIncludable] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ResponseItem, AsyncCursorPage[ResponseItem]]: - """ - Returns a list of input items for a given response. - - Args: - after: An item ID to list items after, used in pagination. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return self._get_api_list( - f"/responses/{response_id}/input_items", - page=AsyncCursorPage[ResponseItem], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "include": include, - "limit": limit, - "order": order, - }, - input_item_list_params.InputItemListParams, - ), - ), - model=cast(Any, ResponseItem), # Union types cannot be passed in as arguments in the type system - ) - - -class InputItemsWithRawResponse: - def __init__(self, input_items: InputItems) -> None: - self._input_items = input_items - - self.list = _legacy_response.to_raw_response_wrapper( - input_items.list, - ) - - -class AsyncInputItemsWithRawResponse: - def __init__(self, input_items: AsyncInputItems) -> None: - self._input_items = input_items - - self.list = _legacy_response.async_to_raw_response_wrapper( - input_items.list, - ) - - -class InputItemsWithStreamingResponse: - def __init__(self, input_items: InputItems) -> None: - self._input_items = input_items - - self.list = to_streamed_response_wrapper( - input_items.list, - ) - - -class AsyncInputItemsWithStreamingResponse: - def __init__(self, input_items: AsyncInputItems) -> None: - self._input_items = input_items - - self.list = async_to_streamed_response_wrapper( - input_items.list, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_tokens.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_tokens.py deleted file mode 100644 index 8664164..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/input_tokens.py +++ /dev/null @@ -1,305 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._base_client import make_request_options -from ...types.responses import input_token_count_params -from ...types.responses.tool_param import ToolParam -from ...types.shared_params.reasoning import Reasoning -from ...types.responses.response_input_item_param import ResponseInputItemParam -from ...types.responses.input_token_count_response import InputTokenCountResponse - -__all__ = ["InputTokens", "AsyncInputTokens"] - - -class InputTokens(SyncAPIResource): - @cached_property - def with_raw_response(self) -> InputTokensWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return InputTokensWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InputTokensWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return InputTokensWithStreamingResponse(self) - - def count( - self, - *, - conversation: Optional[input_token_count_params.Conversation] | Omit = omit, - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, - model: Optional[str] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - text: Optional[input_token_count_params.Text] | Omit = omit, - tool_choice: Optional[input_token_count_params.ToolChoice] | Omit = omit, - tools: Optional[Iterable[ToolParam]] | Omit = omit, - truncation: Literal["auto", "disabled"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InputTokenCountResponse: - """ - Get input token counts - - Args: - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - input: Text, image, or file inputs to the model, used to generate a response - - instructions: A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - reasoning: **gpt-5 and o-series models only** Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: Controls which tool the model should use, if any. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - truncation: The truncation strategy to use for the model response. - `auto`: If the input to - this Response exceeds the model's context window size, the model will truncate - the response to fit the context window by dropping items from the beginning of - the conversation. - `disabled` (default): If the input size will exceed the - context window size for a model, the request will fail with a 400 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/responses/input_tokens", - body=maybe_transform( - { - "conversation": conversation, - "input": input, - "instructions": instructions, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "truncation": truncation, - }, - input_token_count_params.InputTokenCountParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InputTokenCountResponse, - ) - - -class AsyncInputTokens(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncInputTokensWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncInputTokensWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInputTokensWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncInputTokensWithStreamingResponse(self) - - async def count( - self, - *, - conversation: Optional[input_token_count_params.Conversation] | Omit = omit, - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, - model: Optional[str] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - text: Optional[input_token_count_params.Text] | Omit = omit, - tool_choice: Optional[input_token_count_params.ToolChoice] | Omit = omit, - tools: Optional[Iterable[ToolParam]] | Omit = omit, - truncation: Literal["auto", "disabled"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InputTokenCountResponse: - """ - Get input token counts - - Args: - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - input: Text, image, or file inputs to the model, used to generate a response - - instructions: A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - reasoning: **gpt-5 and o-series models only** Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: Controls which tool the model should use, if any. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - truncation: The truncation strategy to use for the model response. - `auto`: If the input to - this Response exceeds the model's context window size, the model will truncate - the response to fit the context window by dropping items from the beginning of - the conversation. - `disabled` (default): If the input size will exceed the - context window size for a model, the request will fail with a 400 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/responses/input_tokens", - body=await async_maybe_transform( - { - "conversation": conversation, - "input": input, - "instructions": instructions, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "reasoning": reasoning, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "truncation": truncation, - }, - input_token_count_params.InputTokenCountParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InputTokenCountResponse, - ) - - -class InputTokensWithRawResponse: - def __init__(self, input_tokens: InputTokens) -> None: - self._input_tokens = input_tokens - - self.count = _legacy_response.to_raw_response_wrapper( - input_tokens.count, - ) - - -class AsyncInputTokensWithRawResponse: - def __init__(self, input_tokens: AsyncInputTokens) -> None: - self._input_tokens = input_tokens - - self.count = _legacy_response.async_to_raw_response_wrapper( - input_tokens.count, - ) - - -class InputTokensWithStreamingResponse: - def __init__(self, input_tokens: InputTokens) -> None: - self._input_tokens = input_tokens - - self.count = to_streamed_response_wrapper( - input_tokens.count, - ) - - -class AsyncInputTokensWithStreamingResponse: - def __init__(self, input_tokens: AsyncInputTokens) -> None: - self._input_tokens = input_tokens - - self.count = async_to_streamed_response_wrapper( - input_tokens.count, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/responses.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/responses.py deleted file mode 100644 index 8e80f67..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/responses/responses.py +++ /dev/null @@ -1,3454 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from copy import copy -from typing import Any, List, Type, Union, Iterable, Optional, cast -from functools import partial -from typing_extensions import Literal, overload - -import httpx - -from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from .input_items import ( - InputItems, - AsyncInputItems, - InputItemsWithRawResponse, - AsyncInputItemsWithRawResponse, - InputItemsWithStreamingResponse, - AsyncInputItemsWithStreamingResponse, -) -from ..._streaming import Stream, AsyncStream -from ...lib._tools import PydanticFunctionTool, ResponsesPydanticFunctionTool -from .input_tokens import ( - InputTokens, - AsyncInputTokens, - InputTokensWithRawResponse, - AsyncInputTokensWithRawResponse, - InputTokensWithStreamingResponse, - AsyncInputTokensWithStreamingResponse, -) -from ..._base_client import make_request_options -from ...types.responses import ( - response_create_params, - response_compact_params, - response_retrieve_params, -) -from ...lib._parsing._responses import ( - TextFormatT, - parse_response, - type_to_text_format_param as _type_to_text_format_param, -) -from ...types.responses.response import Response -from ...types.responses.tool_param import ToolParam, ParseableToolParam -from ...types.shared_params.metadata import Metadata -from ...types.shared_params.reasoning import Reasoning -from ...types.responses.parsed_response import ParsedResponse -from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager -from ...types.responses.compacted_response import CompactedResponse -from ...types.responses.response_includable import ResponseIncludable -from ...types.shared_params.responses_model import ResponsesModel -from ...types.responses.response_input_param import ResponseInputParam -from ...types.responses.response_prompt_param import ResponsePromptParam -from ...types.responses.response_stream_event import ResponseStreamEvent -from ...types.responses.response_input_item_param import ResponseInputItemParam -from ...types.responses.response_text_config_param import ResponseTextConfigParam - -__all__ = ["Responses", "AsyncResponses"] - - -class Responses(SyncAPIResource): - @cached_property - def input_items(self) -> InputItems: - return InputItems(self._client) - - @cached_property - def input_tokens(self) -> InputTokens: - return InputTokens(self._client) - - @cached_property - def with_raw_response(self) -> ResponsesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return ResponsesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ResponsesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return ResponsesWithStreamingResponse(self) - - @overload - def create( - self, - *, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - stream: Literal[True], - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - stream: bool, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | Stream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - def create( - self, - *, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | Stream[ResponseStreamEvent]: - return self._post( - "/responses", - body=maybe_transform( - { - "background": background, - "conversation": conversation, - "include": include, - "input": input, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParamsStreaming - if stream - else response_create_params.ResponseCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - stream=stream or False, - stream_cls=Stream[ResponseStreamEvent], - ) - - @overload - def stream( - self, - *, - response_id: str, - text_format: type[TextFormatT] | Omit = omit, - starting_after: int | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ResponseStreamManager[TextFormatT]: ... - - @overload - def stream( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - background: Optional[bool] | Omit = omit, - text_format: type[TextFormatT] | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ResponseStreamManager[TextFormatT]: ... - - def stream( - self, - *, - response_id: str | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - model: ResponsesModel | Omit = omit, - background: Optional[bool] | Omit = omit, - text_format: type[TextFormatT] | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ResponseStreamManager[TextFormatT]: - new_response_args = { - "input": input, - "model": model, - "conversation": conversation, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - "background": background, - } - new_response_args_names = [k for k, v in new_response_args.items() if is_given(v)] - - if (is_given(response_id) or is_given(starting_after)) and len(new_response_args_names) > 0: - raise ValueError( - "Cannot provide both response_id/starting_after can't be provided together with " - + ", ".join(new_response_args_names) - ) - tools = _make_tools(tools) - if len(new_response_args_names) > 0: - if not is_given(input): - raise ValueError("input must be provided when creating a new response") - - if not is_given(model): - raise ValueError("model must be provided when creating a new response") - - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - - text = copy(text) - text["format"] = _type_to_text_format_param(text_format) - - api_request: partial[Stream[ResponseStreamEvent]] = partial( - self.create, - input=input, - model=model, - tools=tools, - conversation=conversation, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - max_tool_calls=max_tool_calls, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - prompt=prompt, - prompt_cache_key=prompt_cache_key, - prompt_cache_retention=prompt_cache_retention, - store=store, - stream_options=stream_options, - stream=True, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - safety_identifier=safety_identifier, - service_tier=service_tier, - top_logprobs=top_logprobs, - top_p=top_p, - truncation=truncation, - user=user, - background=background, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return ResponseStreamManager(api_request, text_format=text_format, input_tools=tools, starting_after=None) - else: - if not is_given(response_id): - raise ValueError("id must be provided when streaming an existing response") - - return ResponseStreamManager( - lambda: self.retrieve( - response_id=response_id, - stream=True, - include=include or [], - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - starting_after=omit, - timeout=timeout, - ), - text_format=text_format, - input_tools=tools, - starting_after=starting_after if is_given(starting_after) else None, - ) - - def parse( - self, - *, - text_format: type[TextFormatT] | Omit = omit, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedResponse[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - text = copy(text) - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: - return parse_response( - input_tools=tools, - text_format=text_format, - response=raw_response, - ) - - return self._post( - "/responses", - body=maybe_transform( - { - "background": background, - "conversation": conversation, - "include": include, - "input": input, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - "verbosity": verbosity, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `Response` instance into a `ParsedResponse` - # in the `parser` function above - cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), - ) - - @overload - def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - stream: Literal[False] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: ... - - @overload - def retrieve( - self, - response_id: str, - *, - stream: Literal[True], - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Stream[ResponseStreamEvent]: ... - - @overload - def retrieve( - self, - response_id: str, - *, - stream: bool, - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | Stream[ResponseStreamEvent]: ... - - @overload - def retrieve( - self, - response_id: str, - *, - stream: bool = False, - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | Stream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def retrieve( - self, - response_id: str, - *, - stream: Literal[True], - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def retrieve( - self, - response_id: str, - *, - stream: bool, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | Stream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | Stream[ResponseStreamEvent]: - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return self._get( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include": include, - "include_obfuscation": include_obfuscation, - "starting_after": starting_after, - "stream": stream, - }, - response_retrieve_params.ResponseRetrieveParams, - ), - ), - cast_to=Response, - stream=stream or False, - stream_cls=Stream[ResponseStreamEvent], - ) - - def delete( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Deletes a model response with the given ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def cancel( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: - """Cancels a model response with the given ID. - - Only responses created with the - `background` parameter set to `true` can be cancelled. - [Learn more](https://platform.openai.com/docs/guides/background). - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return self._post( - f"/responses/{response_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - ) - - def compact( - self, - *, - model: Union[ - Literal[ - "gpt-5.2", - "gpt-5.2-2025-12-11", - "gpt-5.2-chat-latest", - "gpt-5.2-pro", - "gpt-5.2-pro-2025-12-11", - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], - str, - None, - ], - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CompactedResponse: - """ - Compact conversation - - Args: - model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - input: Text, image, or file inputs to the model, used to generate a response - - instructions: A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/responses/compact", - body=maybe_transform( - { - "model": model, - "input": input, - "instructions": instructions, - "previous_response_id": previous_response_id, - }, - response_compact_params.ResponseCompactParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CompactedResponse, - ) - - -class AsyncResponses(AsyncAPIResource): - @cached_property - def input_items(self) -> AsyncInputItems: - return AsyncInputItems(self._client) - - @cached_property - def input_tokens(self) -> AsyncInputTokens: - return AsyncInputTokens(self._client) - - @cached_property - def with_raw_response(self) -> AsyncResponsesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncResponsesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncResponsesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncResponsesWithStreamingResponse(self) - - @overload - async def create( - self, - *, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - stream: Literal[True], - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - stream: bool, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | AsyncStream[ResponseStreamEvent]: - """Creates a model response. - - Provide - [text](https://platform.openai.com/docs/guides/text) or - [image](https://platform.openai.com/docs/guides/images) inputs to generate - [text](https://platform.openai.com/docs/guides/text) or - [JSON](https://platform.openai.com/docs/guides/structured-outputs) outputs. Have - the model call your own - [custom code](https://platform.openai.com/docs/guides/function-calling) or use - built-in [tools](https://platform.openai.com/docs/guides/tools) like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search) to use - your own data as input for the model's response. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - background: Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - - conversation: The conversation that this response belongs to. Items from this conversation are - prepended to `input_items` for this response request. Input items and output - items from this response are automatically added to this conversation after this - response completes. - - include: Specify additional output data to include in the model response. Currently - supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - - input: Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - - instructions: A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - - max_output_tokens: An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - - max_tool_calls: The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - model: Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - parallel_tool_calls: Whether to allow the model to run tool calls in parallel. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - prompt: Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - - prompt_cache_key: Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - - prompt_cache_retention: The retention policy for the prompt cache. Set to `24h` to enable extended - prompt caching, which keeps cached prefixes active for longer, up to a maximum - of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - - reasoning: **gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - - safety_identifier: A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - service_tier: Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - - store: Whether to store the generated model response for later retrieval via API. - - stream_options: Options for streaming responses. Only set this when you set `stream: true`. - - temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - make the output more random, while lower values like 0.2 will make it more - focused and deterministic. We generally recommend altering this or `top_p` but - not both. - - text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - - tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - - tools: An array of tools the model may call while generating a response. You can - specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - - top_logprobs: An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - - top_p: An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - - truncation: The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - - user: This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use - `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - async def create( - self, - *, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | AsyncStream[ResponseStreamEvent]: - return await self._post( - "/responses", - body=await async_maybe_transform( - { - "background": background, - "conversation": conversation, - "include": include, - "input": input, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - }, - response_create_params.ResponseCreateParamsStreaming - if stream - else response_create_params.ResponseCreateParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - stream=stream or False, - stream_cls=AsyncStream[ResponseStreamEvent], - ) - - @overload - def stream( - self, - *, - response_id: str, - text_format: type[TextFormatT] | Omit = omit, - starting_after: int | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncResponseStreamManager[TextFormatT]: ... - - @overload - def stream( - self, - *, - input: Union[str, ResponseInputParam], - model: ResponsesModel, - background: Optional[bool] | Omit = omit, - text_format: type[TextFormatT] | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncResponseStreamManager[TextFormatT]: ... - - def stream( - self, - *, - response_id: str | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - model: ResponsesModel | Omit = omit, - background: Optional[bool] | Omit = omit, - text_format: type[TextFormatT] | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncResponseStreamManager[TextFormatT]: - new_response_args = { - "input": input, - "model": model, - "conversation": conversation, - "include": include, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - "background": background, - } - new_response_args_names = [k for k, v in new_response_args.items() if is_given(v)] - - if (is_given(response_id) or is_given(starting_after)) and len(new_response_args_names) > 0: - raise ValueError( - "Cannot provide both response_id/starting_after can't be provided together with " - + ", ".join(new_response_args_names) - ) - - tools = _make_tools(tools) - if len(new_response_args_names) > 0: - if isinstance(input, NotGiven): - raise ValueError("input must be provided when creating a new response") - - if not is_given(model): - raise ValueError("model must be provided when creating a new response") - - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - text = copy(text) - text["format"] = _type_to_text_format_param(text_format) - - api_request = self.create( - input=input, - model=model, - stream=True, - tools=tools, - conversation=conversation, - include=include, - instructions=instructions, - max_output_tokens=max_output_tokens, - max_tool_calls=max_tool_calls, - metadata=metadata, - parallel_tool_calls=parallel_tool_calls, - previous_response_id=previous_response_id, - prompt=prompt, - prompt_cache_key=prompt_cache_key, - prompt_cache_retention=prompt_cache_retention, - store=store, - stream_options=stream_options, - temperature=temperature, - text=text, - tool_choice=tool_choice, - reasoning=reasoning, - safety_identifier=safety_identifier, - service_tier=service_tier, - top_logprobs=top_logprobs, - top_p=top_p, - truncation=truncation, - user=user, - background=background, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return AsyncResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - starting_after=None, - ) - else: - if isinstance(response_id, Omit): - raise ValueError("response_id must be provided when streaming an existing response") - - api_request = self.retrieve( - response_id, - stream=True, - include=include or [], - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - return AsyncResponseStreamManager( - api_request, - text_format=text_format, - input_tools=tools, - starting_after=starting_after if is_given(starting_after) else None, - ) - - async def parse( - self, - *, - text_format: type[TextFormatT] | Omit = omit, - background: Optional[bool] | Omit = omit, - conversation: Optional[response_create_params.Conversation] | Omit = omit, - include: Optional[List[ResponseIncludable]] | Omit = omit, - input: Union[str, ResponseInputParam] | Omit = omit, - instructions: Optional[str] | Omit = omit, - max_output_tokens: Optional[int] | Omit = omit, - max_tool_calls: Optional[int] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - model: ResponsesModel | Omit = omit, - parallel_tool_calls: Optional[bool] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - prompt: Optional[ResponsePromptParam] | Omit = omit, - prompt_cache_key: str | Omit = omit, - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] | Omit = omit, - reasoning: Optional[Reasoning] | Omit = omit, - safety_identifier: str | Omit = omit, - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit, - store: Optional[bool] | Omit = omit, - stream: Optional[Literal[False]] | Literal[True] | Omit = omit, - stream_options: Optional[response_create_params.StreamOptions] | Omit = omit, - temperature: Optional[float] | Omit = omit, - text: ResponseTextConfigParam | Omit = omit, - tool_choice: response_create_params.ToolChoice | Omit = omit, - tools: Iterable[ParseableToolParam] | Omit = omit, - top_logprobs: Optional[int] | Omit = omit, - top_p: Optional[float] | Omit = omit, - truncation: Optional[Literal["auto", "disabled"]] | Omit = omit, - user: str | Omit = omit, - verbosity: Optional[Literal["low", "medium", "high"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ParsedResponse[TextFormatT]: - if is_given(text_format): - if not text: - text = {} - - if "format" in text: - raise TypeError("Cannot mix and match text.format with text_format") - text = copy(text) - text["format"] = _type_to_text_format_param(text_format) - - tools = _make_tools(tools) - - def parser(raw_response: Response) -> ParsedResponse[TextFormatT]: - return parse_response( - input_tools=tools, - text_format=text_format, - response=raw_response, - ) - - return await self._post( - "/responses", - body=maybe_transform( - { - "background": background, - "conversation": conversation, - "include": include, - "input": input, - "instructions": instructions, - "max_output_tokens": max_output_tokens, - "max_tool_calls": max_tool_calls, - "metadata": metadata, - "model": model, - "parallel_tool_calls": parallel_tool_calls, - "previous_response_id": previous_response_id, - "prompt": prompt, - "prompt_cache_key": prompt_cache_key, - "prompt_cache_retention": prompt_cache_retention, - "reasoning": reasoning, - "safety_identifier": safety_identifier, - "service_tier": service_tier, - "store": store, - "stream": stream, - "stream_options": stream_options, - "temperature": temperature, - "text": text, - "tool_choice": tool_choice, - "tools": tools, - "top_logprobs": top_logprobs, - "top_p": top_p, - "truncation": truncation, - "user": user, - "verbosity": verbosity, - }, - response_create_params.ResponseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=parser, - ), - # we turn the `Response` instance into a `ParsedResponse` - # in the `parser` function above - cast_to=cast(Type[ParsedResponse[TextFormatT]], Response), - ) - - @overload - async def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - stream: Literal[False] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: ... - - @overload - async def retrieve( - self, - response_id: str, - *, - stream: Literal[True], - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncStream[ResponseStreamEvent]: ... - - @overload - async def retrieve( - self, - response_id: str, - *, - stream: bool, - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | AsyncStream[ResponseStreamEvent]: ... - - @overload - async def retrieve( - self, - response_id: str, - *, - stream: bool = False, - include: List[ResponseIncludable] | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Response | AsyncStream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def retrieve( - self, - response_id: str, - *, - stream: Literal[True], - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def retrieve( - self, - response_id: str, - *, - stream: bool, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | AsyncStream[ResponseStreamEvent]: - """ - Retrieves a model response with the given ID. - - Args: - stream: If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - - include: Additional fields to include in the response. See the `include` parameter for - Response creation above for more information. - - include_obfuscation: When true, stream obfuscation will be enabled. Stream obfuscation adds random - characters to an `obfuscation` field on streaming delta events to normalize - payload sizes as a mitigation to certain side-channel attacks. These obfuscation - fields are included by default, but add a small amount of overhead to the data - stream. You can set `include_obfuscation` to false to optimize for bandwidth if - you trust the network links between your application and the OpenAI API. - - starting_after: The sequence number of the event after which to start streaming. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - async def retrieve( - self, - response_id: str, - *, - include: List[ResponseIncludable] | Omit = omit, - include_obfuscation: bool | Omit = omit, - starting_after: int | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response | AsyncStream[ResponseStreamEvent]: - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return await self._get( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "include": include, - "include_obfuscation": include_obfuscation, - "starting_after": starting_after, - "stream": stream, - }, - response_retrieve_params.ResponseRetrieveParams, - ), - ), - cast_to=Response, - stream=stream or False, - stream_cls=AsyncStream[ResponseStreamEvent], - ) - - async def delete( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Deletes a model response with the given ID. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/responses/{response_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def cancel( - self, - response_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Response: - """Cancels a model response with the given ID. - - Only responses created with the - `background` parameter set to `true` can be cancelled. - [Learn more](https://platform.openai.com/docs/guides/background). - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not response_id: - raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") - return await self._post( - f"/responses/{response_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Response, - ) - - async def compact( - self, - *, - model: Union[ - Literal[ - "gpt-5.2", - "gpt-5.2-2025-12-11", - "gpt-5.2-chat-latest", - "gpt-5.2-pro", - "gpt-5.2-pro-2025-12-11", - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], - str, - None, - ], - input: Union[str, Iterable[ResponseInputItemParam], None] | Omit = omit, - instructions: Optional[str] | Omit = omit, - previous_response_id: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CompactedResponse: - """ - Compact conversation - - Args: - model: Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a - wide range of models with different capabilities, performance characteristics, - and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - - input: Text, image, or file inputs to the model, used to generate a response - - instructions: A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - - previous_response_id: The unique ID of the previous response to the model. Use this to create - multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/responses/compact", - body=await async_maybe_transform( - { - "model": model, - "input": input, - "instructions": instructions, - "previous_response_id": previous_response_id, - }, - response_compact_params.ResponseCompactParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CompactedResponse, - ) - - -class ResponsesWithRawResponse: - def __init__(self, responses: Responses) -> None: - self._responses = responses - - self.create = _legacy_response.to_raw_response_wrapper( - responses.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - responses.retrieve, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - responses.delete, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - responses.cancel, - ) - self.compact = _legacy_response.to_raw_response_wrapper( - responses.compact, - ) - self.parse = _legacy_response.to_raw_response_wrapper( - responses.parse, - ) - - @cached_property - def input_items(self) -> InputItemsWithRawResponse: - return InputItemsWithRawResponse(self._responses.input_items) - - @cached_property - def input_tokens(self) -> InputTokensWithRawResponse: - return InputTokensWithRawResponse(self._responses.input_tokens) - - -class AsyncResponsesWithRawResponse: - def __init__(self, responses: AsyncResponses) -> None: - self._responses = responses - - self.create = _legacy_response.async_to_raw_response_wrapper( - responses.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - responses.retrieve, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - responses.delete, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - responses.cancel, - ) - self.compact = _legacy_response.async_to_raw_response_wrapper( - responses.compact, - ) - self.parse = _legacy_response.async_to_raw_response_wrapper( - responses.parse, - ) - - @cached_property - def input_items(self) -> AsyncInputItemsWithRawResponse: - return AsyncInputItemsWithRawResponse(self._responses.input_items) - - @cached_property - def input_tokens(self) -> AsyncInputTokensWithRawResponse: - return AsyncInputTokensWithRawResponse(self._responses.input_tokens) - - -class ResponsesWithStreamingResponse: - def __init__(self, responses: Responses) -> None: - self._responses = responses - - self.create = to_streamed_response_wrapper( - responses.create, - ) - self.retrieve = to_streamed_response_wrapper( - responses.retrieve, - ) - self.delete = to_streamed_response_wrapper( - responses.delete, - ) - self.cancel = to_streamed_response_wrapper( - responses.cancel, - ) - self.compact = to_streamed_response_wrapper( - responses.compact, - ) - - @cached_property - def input_items(self) -> InputItemsWithStreamingResponse: - return InputItemsWithStreamingResponse(self._responses.input_items) - - @cached_property - def input_tokens(self) -> InputTokensWithStreamingResponse: - return InputTokensWithStreamingResponse(self._responses.input_tokens) - - -class AsyncResponsesWithStreamingResponse: - def __init__(self, responses: AsyncResponses) -> None: - self._responses = responses - - self.create = async_to_streamed_response_wrapper( - responses.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - responses.retrieve, - ) - self.delete = async_to_streamed_response_wrapper( - responses.delete, - ) - self.cancel = async_to_streamed_response_wrapper( - responses.cancel, - ) - self.compact = async_to_streamed_response_wrapper( - responses.compact, - ) - - @cached_property - def input_items(self) -> AsyncInputItemsWithStreamingResponse: - return AsyncInputItemsWithStreamingResponse(self._responses.input_items) - - @cached_property - def input_tokens(self) -> AsyncInputTokensWithStreamingResponse: - return AsyncInputTokensWithStreamingResponse(self._responses.input_tokens) - - -def _make_tools(tools: Iterable[ParseableToolParam] | Omit) -> List[ToolParam] | Omit: - if not is_given(tools): - return omit - - converted_tools: List[ToolParam] = [] - for tool in tools: - if tool["type"] != "function": - converted_tools.append(tool) - continue - - if "function" not in tool: - # standard Responses API case - converted_tools.append(tool) - continue - - function = cast(Any, tool)["function"] # pyright: ignore[reportUnnecessaryCast] - if not isinstance(function, PydanticFunctionTool): - raise Exception( - "Expected Chat Completions function tool shape to be created using `openai.pydantic_function_tool()`" - ) - - assert "parameters" in function - new_tool = ResponsesPydanticFunctionTool( - { - "type": "function", - "name": function["name"], - "description": function.get("description"), - "parameters": function["parameters"], - "strict": function.get("strict") or False, - }, - function.model, - ) - - converted_tools.append(new_tool.cast()) - - return converted_tools diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/__init__.py deleted file mode 100644 index 12d1056..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .parts import ( - Parts, - AsyncParts, - PartsWithRawResponse, - AsyncPartsWithRawResponse, - PartsWithStreamingResponse, - AsyncPartsWithStreamingResponse, -) -from .uploads import ( - Uploads, - AsyncUploads, - UploadsWithRawResponse, - AsyncUploadsWithRawResponse, - UploadsWithStreamingResponse, - AsyncUploadsWithStreamingResponse, -) - -__all__ = [ - "Parts", - "AsyncParts", - "PartsWithRawResponse", - "AsyncPartsWithRawResponse", - "PartsWithStreamingResponse", - "AsyncPartsWithStreamingResponse", - "Uploads", - "AsyncUploads", - "UploadsWithRawResponse", - "AsyncUploadsWithRawResponse", - "UploadsWithStreamingResponse", - "AsyncUploadsWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/parts.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/parts.py deleted file mode 100644 index 73eabd4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/parts.py +++ /dev/null @@ -1,205 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Mapping, cast - -import httpx - -from ... import _legacy_response -from ..._types import Body, Query, Headers, NotGiven, FileTypes, not_given -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._base_client import make_request_options -from ...types.uploads import part_create_params -from ...types.uploads.upload_part import UploadPart - -__all__ = ["Parts", "AsyncParts"] - - -class Parts(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PartsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return PartsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PartsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return PartsWithStreamingResponse(self) - - def create( - self, - upload_id: str, - *, - data: FileTypes, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> UploadPart: - """ - Adds a - [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an - [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object. - A Part represents a chunk of bytes from the file you are trying to upload. - - Each Part can be at most 64 MB, and you can add Parts until you hit the Upload - maximum of 8 GB. - - It is possible to add multiple Parts in parallel. You can decide the intended - order of the Parts when you - [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). - - Args: - data: The chunk of bytes for this Part. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - body = deepcopy_minimal({"data": data}) - files = extract_files(cast(Mapping[str, object], body), paths=[["data"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - f"/uploads/{upload_id}/parts", - body=maybe_transform(body, part_create_params.PartCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=UploadPart, - ) - - -class AsyncParts(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPartsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncPartsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPartsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncPartsWithStreamingResponse(self) - - async def create( - self, - upload_id: str, - *, - data: FileTypes, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> UploadPart: - """ - Adds a - [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an - [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object. - A Part represents a chunk of bytes from the file you are trying to upload. - - Each Part can be at most 64 MB, and you can add Parts until you hit the Upload - maximum of 8 GB. - - It is possible to add multiple Parts in parallel. You can decide the intended - order of the Parts when you - [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). - - Args: - data: The chunk of bytes for this Part. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - body = deepcopy_minimal({"data": data}) - files = extract_files(cast(Mapping[str, object], body), paths=[["data"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - f"/uploads/{upload_id}/parts", - body=await async_maybe_transform(body, part_create_params.PartCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=UploadPart, - ) - - -class PartsWithRawResponse: - def __init__(self, parts: Parts) -> None: - self._parts = parts - - self.create = _legacy_response.to_raw_response_wrapper( - parts.create, - ) - - -class AsyncPartsWithRawResponse: - def __init__(self, parts: AsyncParts) -> None: - self._parts = parts - - self.create = _legacy_response.async_to_raw_response_wrapper( - parts.create, - ) - - -class PartsWithStreamingResponse: - def __init__(self, parts: Parts) -> None: - self._parts = parts - - self.create = to_streamed_response_wrapper( - parts.create, - ) - - -class AsyncPartsWithStreamingResponse: - def __init__(self, parts: AsyncParts) -> None: - self._parts = parts - - self.create = async_to_streamed_response_wrapper( - parts.create, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/uploads.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/uploads.py deleted file mode 100644 index e8c047b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/uploads/uploads.py +++ /dev/null @@ -1,719 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import io -import os -import logging -import builtins -from typing import overload -from pathlib import Path - -import anyio -import httpx - -from ... import _legacy_response -from .parts import ( - Parts, - AsyncParts, - PartsWithRawResponse, - AsyncPartsWithRawResponse, - PartsWithStreamingResponse, - AsyncPartsWithStreamingResponse, -) -from ...types import FilePurpose, upload_create_params, upload_complete_params -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ..._base_client import make_request_options -from ...types.upload import Upload -from ...types.file_purpose import FilePurpose - -__all__ = ["Uploads", "AsyncUploads"] - - -# 64MB -DEFAULT_PART_SIZE = 64 * 1024 * 1024 - -log: logging.Logger = logging.getLogger(__name__) - - -class Uploads(SyncAPIResource): - @cached_property - def parts(self) -> Parts: - return Parts(self._client) - - @cached_property - def with_raw_response(self) -> UploadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return UploadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> UploadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return UploadsWithStreamingResponse(self) - - @overload - def upload_file_chunked( - self, - *, - file: os.PathLike[str], - mime_type: str, - purpose: FilePurpose, - bytes: int | None = None, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits a file into multiple 64MB parts and uploads them sequentially.""" - - @overload - def upload_file_chunked( - self, - *, - file: bytes, - filename: str, - bytes: int, - mime_type: str, - purpose: FilePurpose, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits an in-memory file into multiple 64MB parts and uploads them sequentially.""" - - def upload_file_chunked( - self, - *, - file: os.PathLike[str] | bytes, - mime_type: str, - purpose: FilePurpose, - filename: str | None = None, - bytes: int | None = None, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits the given file into multiple parts and uploads them sequentially. - - ```py - from pathlib import Path - - client.uploads.upload_file( - file=Path("my-paper.pdf"), - mime_type="pdf", - purpose="assistants", - ) - ``` - """ - if isinstance(file, builtins.bytes): - if filename is None: - raise TypeError("The `filename` argument must be given for in-memory files") - - if bytes is None: - raise TypeError("The `bytes` argument must be given for in-memory files") - else: - if not isinstance(file, Path): - file = Path(file) - - if not filename: - filename = file.name - - if bytes is None: - bytes = file.stat().st_size - - upload = self.create( - bytes=bytes, - filename=filename, - mime_type=mime_type, - purpose=purpose, - ) - - part_ids: list[str] = [] - - if part_size is None: - part_size = DEFAULT_PART_SIZE - - if isinstance(file, builtins.bytes): - buf: io.FileIO | io.BytesIO = io.BytesIO(file) - else: - buf = io.FileIO(file) - - try: - while True: - data = buf.read(part_size) - if not data: - # EOF - break - - part = self.parts.create(upload_id=upload.id, data=data) - log.info("Uploaded part %s for upload %s", part.id, upload.id) - part_ids.append(part.id) - finally: - buf.close() - - return self.complete(upload_id=upload.id, part_ids=part_ids, md5=md5) - - def create( - self, - *, - bytes: int, - filename: str, - mime_type: str, - purpose: FilePurpose, - expires_after: upload_create_params.ExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """ - Creates an intermediate - [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object - that you can add - [Parts](https://platform.openai.com/docs/api-reference/uploads/part-object) to. - Currently, an Upload can accept at most 8 GB in total and expires after an hour - after you create it. - - Once you complete the Upload, we will create a - [File](https://platform.openai.com/docs/api-reference/files/object) object that - contains all the parts you uploaded. This File is usable in the rest of our - platform as a regular File object. - - For certain `purpose` values, the correct `mime_type` must be specified. Please - refer to documentation for the - [supported MIME types for your use case](https://platform.openai.com/docs/assistants/tools/file-search#supported-files). - - For guidance on the proper filename extensions for each purpose, please follow - the documentation on - [creating a File](https://platform.openai.com/docs/api-reference/files/create). - - Args: - bytes: The number of bytes in the file you are uploading. - - filename: The name of the file to upload. - - mime_type: The MIME type of the file. - - This must fall within the supported MIME types for your file purpose. See the - supported MIME types for assistants and vision. - - purpose: The intended purpose of the uploaded file. - - See the - [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). - - expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire - after 30 days and all other files are persisted until they are manually deleted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/uploads", - body=maybe_transform( - { - "bytes": bytes, - "filename": filename, - "mime_type": mime_type, - "purpose": purpose, - "expires_after": expires_after, - }, - upload_create_params.UploadCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - def cancel( - self, - upload_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """Cancels the Upload. - - No Parts may be added after an Upload is cancelled. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - return self._post( - f"/uploads/{upload_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - def complete( - self, - upload_id: str, - *, - part_ids: SequenceNotStr[str], - md5: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """ - Completes the - [Upload](https://platform.openai.com/docs/api-reference/uploads/object). - - Within the returned Upload object, there is a nested - [File](https://platform.openai.com/docs/api-reference/files/object) object that - is ready to use in the rest of the platform. - - You can specify the order of the Parts by passing in an ordered list of the Part - IDs. - - The number of bytes uploaded upon completion must match the number of bytes - initially specified when creating the Upload object. No Parts may be added after - an Upload is completed. - - Args: - part_ids: The ordered list of Part IDs. - - md5: The optional md5 checksum for the file contents to verify if the bytes uploaded - matches what you expect. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - return self._post( - f"/uploads/{upload_id}/complete", - body=maybe_transform( - { - "part_ids": part_ids, - "md5": md5, - }, - upload_complete_params.UploadCompleteParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - -class AsyncUploads(AsyncAPIResource): - @cached_property - def parts(self) -> AsyncParts: - return AsyncParts(self._client) - - @cached_property - def with_raw_response(self) -> AsyncUploadsWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncUploadsWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncUploadsWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncUploadsWithStreamingResponse(self) - - @overload - async def upload_file_chunked( - self, - *, - file: os.PathLike[str], - mime_type: str, - purpose: FilePurpose, - bytes: int | None = None, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits a file into multiple 64MB parts and uploads them sequentially.""" - - @overload - async def upload_file_chunked( - self, - *, - file: bytes, - filename: str, - bytes: int, - mime_type: str, - purpose: FilePurpose, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits an in-memory file into multiple 64MB parts and uploads them sequentially.""" - - async def upload_file_chunked( - self, - *, - file: os.PathLike[str] | bytes, - mime_type: str, - purpose: FilePurpose, - filename: str | None = None, - bytes: int | None = None, - part_size: int | None = None, - md5: str | Omit = omit, - ) -> Upload: - """Splits the given file into multiple parts and uploads them sequentially. - - ```py - from pathlib import Path - - client.uploads.upload_file( - file=Path("my-paper.pdf"), - mime_type="pdf", - purpose="assistants", - ) - ``` - """ - if isinstance(file, builtins.bytes): - if filename is None: - raise TypeError("The `filename` argument must be given for in-memory files") - - if bytes is None: - raise TypeError("The `bytes` argument must be given for in-memory files") - else: - if not isinstance(file, anyio.Path): - file = anyio.Path(file) - - if not filename: - filename = file.name - - if bytes is None: - stat = await file.stat() - bytes = stat.st_size - - upload = await self.create( - bytes=bytes, - filename=filename, - mime_type=mime_type, - purpose=purpose, - ) - - part_ids: list[str] = [] - - if part_size is None: - part_size = DEFAULT_PART_SIZE - - if isinstance(file, anyio.Path): - fd = await file.open("rb") - async with fd: - while True: - data = await fd.read(part_size) - if not data: - # EOF - break - - part = await self.parts.create(upload_id=upload.id, data=data) - log.info("Uploaded part %s for upload %s", part.id, upload.id) - part_ids.append(part.id) - else: - buf = io.BytesIO(file) - - try: - while True: - data = buf.read(part_size) - if not data: - # EOF - break - - part = await self.parts.create(upload_id=upload.id, data=data) - log.info("Uploaded part %s for upload %s", part.id, upload.id) - part_ids.append(part.id) - finally: - buf.close() - - return await self.complete(upload_id=upload.id, part_ids=part_ids, md5=md5) - - async def create( - self, - *, - bytes: int, - filename: str, - mime_type: str, - purpose: FilePurpose, - expires_after: upload_create_params.ExpiresAfter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """ - Creates an intermediate - [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object - that you can add - [Parts](https://platform.openai.com/docs/api-reference/uploads/part-object) to. - Currently, an Upload can accept at most 8 GB in total and expires after an hour - after you create it. - - Once you complete the Upload, we will create a - [File](https://platform.openai.com/docs/api-reference/files/object) object that - contains all the parts you uploaded. This File is usable in the rest of our - platform as a regular File object. - - For certain `purpose` values, the correct `mime_type` must be specified. Please - refer to documentation for the - [supported MIME types for your use case](https://platform.openai.com/docs/assistants/tools/file-search#supported-files). - - For guidance on the proper filename extensions for each purpose, please follow - the documentation on - [creating a File](https://platform.openai.com/docs/api-reference/files/create). - - Args: - bytes: The number of bytes in the file you are uploading. - - filename: The name of the file to upload. - - mime_type: The MIME type of the file. - - This must fall within the supported MIME types for your file purpose. See the - supported MIME types for assistants and vision. - - purpose: The intended purpose of the uploaded file. - - See the - [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). - - expires_after: The expiration policy for a file. By default, files with `purpose=batch` expire - after 30 days and all other files are persisted until they are manually deleted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/uploads", - body=await async_maybe_transform( - { - "bytes": bytes, - "filename": filename, - "mime_type": mime_type, - "purpose": purpose, - "expires_after": expires_after, - }, - upload_create_params.UploadCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - async def cancel( - self, - upload_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """Cancels the Upload. - - No Parts may be added after an Upload is cancelled. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - return await self._post( - f"/uploads/{upload_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - async def complete( - self, - upload_id: str, - *, - part_ids: SequenceNotStr[str], - md5: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Upload: - """ - Completes the - [Upload](https://platform.openai.com/docs/api-reference/uploads/object). - - Within the returned Upload object, there is a nested - [File](https://platform.openai.com/docs/api-reference/files/object) object that - is ready to use in the rest of the platform. - - You can specify the order of the Parts by passing in an ordered list of the Part - IDs. - - The number of bytes uploaded upon completion must match the number of bytes - initially specified when creating the Upload object. No Parts may be added after - an Upload is completed. - - Args: - part_ids: The ordered list of Part IDs. - - md5: The optional md5 checksum for the file contents to verify if the bytes uploaded - matches what you expect. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not upload_id: - raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") - return await self._post( - f"/uploads/{upload_id}/complete", - body=await async_maybe_transform( - { - "part_ids": part_ids, - "md5": md5, - }, - upload_complete_params.UploadCompleteParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Upload, - ) - - -class UploadsWithRawResponse: - def __init__(self, uploads: Uploads) -> None: - self._uploads = uploads - - self.create = _legacy_response.to_raw_response_wrapper( - uploads.create, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - uploads.cancel, - ) - self.complete = _legacy_response.to_raw_response_wrapper( - uploads.complete, - ) - - @cached_property - def parts(self) -> PartsWithRawResponse: - return PartsWithRawResponse(self._uploads.parts) - - -class AsyncUploadsWithRawResponse: - def __init__(self, uploads: AsyncUploads) -> None: - self._uploads = uploads - - self.create = _legacy_response.async_to_raw_response_wrapper( - uploads.create, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - uploads.cancel, - ) - self.complete = _legacy_response.async_to_raw_response_wrapper( - uploads.complete, - ) - - @cached_property - def parts(self) -> AsyncPartsWithRawResponse: - return AsyncPartsWithRawResponse(self._uploads.parts) - - -class UploadsWithStreamingResponse: - def __init__(self, uploads: Uploads) -> None: - self._uploads = uploads - - self.create = to_streamed_response_wrapper( - uploads.create, - ) - self.cancel = to_streamed_response_wrapper( - uploads.cancel, - ) - self.complete = to_streamed_response_wrapper( - uploads.complete, - ) - - @cached_property - def parts(self) -> PartsWithStreamingResponse: - return PartsWithStreamingResponse(self._uploads.parts) - - -class AsyncUploadsWithStreamingResponse: - def __init__(self, uploads: AsyncUploads) -> None: - self._uploads = uploads - - self.create = async_to_streamed_response_wrapper( - uploads.create, - ) - self.cancel = async_to_streamed_response_wrapper( - uploads.cancel, - ) - self.complete = async_to_streamed_response_wrapper( - uploads.complete, - ) - - @cached_property - def parts(self) -> AsyncPartsWithStreamingResponse: - return AsyncPartsWithStreamingResponse(self._uploads.parts) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/__init__.py deleted file mode 100644 index 96ae16c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .file_batches import ( - FileBatches, - AsyncFileBatches, - FileBatchesWithRawResponse, - AsyncFileBatchesWithRawResponse, - FileBatchesWithStreamingResponse, - AsyncFileBatchesWithStreamingResponse, -) -from .vector_stores import ( - VectorStores, - AsyncVectorStores, - VectorStoresWithRawResponse, - AsyncVectorStoresWithRawResponse, - VectorStoresWithStreamingResponse, - AsyncVectorStoresWithStreamingResponse, -) - -__all__ = [ - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", - "FileBatches", - "AsyncFileBatches", - "FileBatchesWithRawResponse", - "AsyncFileBatchesWithRawResponse", - "FileBatchesWithStreamingResponse", - "AsyncFileBatchesWithStreamingResponse", - "VectorStores", - "AsyncVectorStores", - "VectorStoresWithRawResponse", - "AsyncVectorStoresWithRawResponse", - "VectorStoresWithStreamingResponse", - "AsyncVectorStoresWithStreamingResponse", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/file_batches.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/file_batches.py deleted file mode 100644 index d31fb59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/file_batches.py +++ /dev/null @@ -1,813 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import asyncio -from typing import Dict, Iterable, Optional -from typing_extensions import Union, Literal -from concurrent.futures import Future, ThreadPoolExecutor, as_completed - -import httpx -import sniffio - -from ... import _legacy_response -from ...types import FileChunkingStrategyParam -from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.file_object import FileObject -from ...types.vector_stores import file_batch_create_params, file_batch_list_files_params -from ...types.file_chunking_strategy_param import FileChunkingStrategyParam -from ...types.vector_stores.vector_store_file import VectorStoreFile -from ...types.vector_stores.vector_store_file_batch import VectorStoreFileBatch - -__all__ = ["FileBatches", "AsyncFileBatches"] - - -class FileBatches(SyncAPIResource): - @cached_property - def with_raw_response(self) -> FileBatchesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return FileBatchesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FileBatchesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return FileBatchesWithStreamingResponse(self) - - def create( - self, - vector_store_id: str, - *, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - files: Iterable[file_batch_create_params.File] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """ - Create a vector store file batch. - - Args: - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. - - files: A list of objects that each include a `file_id` plus optional `attributes` or - `chunking_strategy`. Use this when you need to override metadata for specific - files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/vector_stores/{vector_store_id}/file_batches", - body=maybe_transform( - { - "attributes": attributes, - "chunking_strategy": chunking_strategy, - "file_ids": file_ids, - "files": files, - }, - file_batch_create_params.FileBatchCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - def retrieve( - self, - batch_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """ - Retrieves a vector store file batch. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - def cancel( - self, - batch_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """Cancel a vector store file batch. - - This attempts to cancel the processing of - files in this batch as soon as possible. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - def create_and_poll( - self, - vector_store_id: str, - *, - file_ids: SequenceNotStr[str], - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFileBatch: - """Create a vector store batch and poll until all files have been processed.""" - batch = self.create( - vector_store_id=vector_store_id, - file_ids=file_ids, - chunking_strategy=chunking_strategy, - ) - # TODO: don't poll unless necessary?? - return self.poll( - batch.id, - vector_store_id=vector_store_id, - poll_interval_ms=poll_interval_ms, - ) - - def list_files( - self, - batch_id: str, - *, - vector_store_id: str, - after: str | Omit = omit, - before: str | Omit = omit, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[VectorStoreFile]: - """ - Returns a list of vector store files in a batch. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", - page=SyncCursorPage[VectorStoreFile], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "filter": filter, - "limit": limit, - "order": order, - }, - file_batch_list_files_params.FileBatchListFilesParams, - ), - ), - model=VectorStoreFile, - ) - - def poll( - self, - batch_id: str, - *, - vector_store_id: str, - poll_interval_ms: int | Omit = omit, - ) -> VectorStoreFileBatch: - """Wait for the given file batch to be processed. - - Note: this will return even if one of the files failed to process, you need to - check batch.file_counts.failed_count to handle this case. - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = self.with_raw_response.retrieve( - batch_id, - vector_store_id=vector_store_id, - extra_headers=headers, - ) - - batch = response.parse() - if batch.file_counts.in_progress > 0: - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - self._sleep(poll_interval_ms / 1000) - continue - - return batch - - def upload_and_poll( - self, - vector_store_id: str, - *, - files: Iterable[FileTypes], - max_concurrency: int = 5, - file_ids: SequenceNotStr[str] = [], - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFileBatch: - """Uploads the given files concurrently and then creates a vector store file batch. - - If you've already uploaded certain files that you want to include in this batch - then you can pass their IDs through the `file_ids` argument. - - By default, if any file upload fails then an exception will be eagerly raised. - - The number of concurrency uploads is configurable using the `max_concurrency` - parameter. - - Note: this method only supports `asyncio` or `trio` as the backing async - runtime. - """ - results: list[FileObject] = [] - - with ThreadPoolExecutor(max_workers=max_concurrency) as executor: - futures: list[Future[FileObject]] = [ - executor.submit( - self._client.files.create, - file=file, - purpose="assistants", - ) - for file in files - ] - - for future in as_completed(futures): - exc = future.exception() - if exc: - raise exc - - results.append(future.result()) - - batch = self.create_and_poll( - vector_store_id=vector_store_id, - file_ids=[*file_ids, *(f.id for f in results)], - poll_interval_ms=poll_interval_ms, - chunking_strategy=chunking_strategy, - ) - return batch - - -class AsyncFileBatches(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncFileBatchesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncFileBatchesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFileBatchesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncFileBatchesWithStreamingResponse(self) - - async def create( - self, - vector_store_id: str, - *, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - files: Iterable[file_batch_create_params.File] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """ - Create a vector store file batch. - - Args: - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. - - files: A list of objects that each include a `file_id` plus optional `attributes` or - `chunking_strategy`. Use this when you need to override metadata for specific - files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/vector_stores/{vector_store_id}/file_batches", - body=await async_maybe_transform( - { - "attributes": attributes, - "chunking_strategy": chunking_strategy, - "file_ids": file_ids, - "files": files, - }, - file_batch_create_params.FileBatchCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - async def retrieve( - self, - batch_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """ - Retrieves a vector store file batch. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - async def cancel( - self, - batch_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileBatch: - """Cancel a vector store file batch. - - This attempts to cancel the processing of - files in this batch as soon as possible. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileBatch, - ) - - async def create_and_poll( - self, - vector_store_id: str, - *, - file_ids: SequenceNotStr[str], - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFileBatch: - """Create a vector store batch and poll until all files have been processed.""" - batch = await self.create( - vector_store_id=vector_store_id, - file_ids=file_ids, - chunking_strategy=chunking_strategy, - ) - # TODO: don't poll unless necessary?? - return await self.poll( - batch.id, - vector_store_id=vector_store_id, - poll_interval_ms=poll_interval_ms, - ) - - def list_files( - self, - batch_id: str, - *, - vector_store_id: str, - after: str | Omit = omit, - before: str | Omit = omit, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: - """ - Returns a list of vector store files in a batch. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not batch_id: - raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", - page=AsyncCursorPage[VectorStoreFile], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "filter": filter, - "limit": limit, - "order": order, - }, - file_batch_list_files_params.FileBatchListFilesParams, - ), - ), - model=VectorStoreFile, - ) - - async def poll( - self, - batch_id: str, - *, - vector_store_id: str, - poll_interval_ms: int | Omit = omit, - ) -> VectorStoreFileBatch: - """Wait for the given file batch to be processed. - - Note: this will return even if one of the files failed to process, you need to - check batch.file_counts.failed_count to handle this case. - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = await self.with_raw_response.retrieve( - batch_id, - vector_store_id=vector_store_id, - extra_headers=headers, - ) - - batch = response.parse() - if batch.file_counts.in_progress > 0: - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - await self._sleep(poll_interval_ms / 1000) - continue - - return batch - - async def upload_and_poll( - self, - vector_store_id: str, - *, - files: Iterable[FileTypes], - max_concurrency: int = 5, - file_ids: SequenceNotStr[str] = [], - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFileBatch: - """Uploads the given files concurrently and then creates a vector store file batch. - - If you've already uploaded certain files that you want to include in this batch - then you can pass their IDs through the `file_ids` argument. - - By default, if any file upload fails then an exception will be eagerly raised. - - The number of concurrency uploads is configurable using the `max_concurrency` - parameter. - - Note: this method only supports `asyncio` or `trio` as the backing async - runtime. - """ - uploaded_files: list[FileObject] = [] - - async_library = sniffio.current_async_library() - - if async_library == "asyncio": - - async def asyncio_upload_file(semaphore: asyncio.Semaphore, file: FileTypes) -> None: - async with semaphore: - file_obj = await self._client.files.create( - file=file, - purpose="assistants", - ) - uploaded_files.append(file_obj) - - semaphore = asyncio.Semaphore(max_concurrency) - - tasks = [asyncio_upload_file(semaphore, file) for file in files] - - await asyncio.gather(*tasks) - elif async_library == "trio": - # We only import if the library is being used. - # We support Python 3.7 so are using an older version of trio that does not have type information - import trio # type: ignore # pyright: ignore[reportMissingTypeStubs] - - async def trio_upload_file(limiter: trio.CapacityLimiter, file: FileTypes) -> None: - async with limiter: - file_obj = await self._client.files.create( - file=file, - purpose="assistants", - ) - uploaded_files.append(file_obj) - - limiter = trio.CapacityLimiter(max_concurrency) - - async with trio.open_nursery() as nursery: - for file in files: - nursery.start_soon(trio_upload_file, limiter, file) # pyright: ignore [reportUnknownMemberType] - else: - raise RuntimeError( - f"Async runtime {async_library} is not supported yet. Only asyncio or trio is supported", - ) - - batch = await self.create_and_poll( - vector_store_id=vector_store_id, - file_ids=[*file_ids, *(f.id for f in uploaded_files)], - poll_interval_ms=poll_interval_ms, - chunking_strategy=chunking_strategy, - ) - return batch - - -class FileBatchesWithRawResponse: - def __init__(self, file_batches: FileBatches) -> None: - self._file_batches = file_batches - - self.create = _legacy_response.to_raw_response_wrapper( - file_batches.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - file_batches.retrieve, - ) - self.cancel = _legacy_response.to_raw_response_wrapper( - file_batches.cancel, - ) - self.list_files = _legacy_response.to_raw_response_wrapper( - file_batches.list_files, - ) - - -class AsyncFileBatchesWithRawResponse: - def __init__(self, file_batches: AsyncFileBatches) -> None: - self._file_batches = file_batches - - self.create = _legacy_response.async_to_raw_response_wrapper( - file_batches.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - file_batches.retrieve, - ) - self.cancel = _legacy_response.async_to_raw_response_wrapper( - file_batches.cancel, - ) - self.list_files = _legacy_response.async_to_raw_response_wrapper( - file_batches.list_files, - ) - - -class FileBatchesWithStreamingResponse: - def __init__(self, file_batches: FileBatches) -> None: - self._file_batches = file_batches - - self.create = to_streamed_response_wrapper( - file_batches.create, - ) - self.retrieve = to_streamed_response_wrapper( - file_batches.retrieve, - ) - self.cancel = to_streamed_response_wrapper( - file_batches.cancel, - ) - self.list_files = to_streamed_response_wrapper( - file_batches.list_files, - ) - - -class AsyncFileBatchesWithStreamingResponse: - def __init__(self, file_batches: AsyncFileBatches) -> None: - self._file_batches = file_batches - - self.create = async_to_streamed_response_wrapper( - file_batches.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - file_batches.retrieve, - ) - self.cancel = async_to_streamed_response_wrapper( - file_batches.cancel, - ) - self.list_files = async_to_streamed_response_wrapper( - file_batches.list_files, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/files.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/files.py deleted file mode 100644 index d2eb4e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/files.py +++ /dev/null @@ -1,939 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING, Dict, Union, Optional -from typing_extensions import Literal, assert_never - -import httpx - -from ... import _legacy_response -from ...types import FileChunkingStrategyParam -from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.vector_stores import file_list_params, file_create_params, file_update_params -from ...types.file_chunking_strategy_param import FileChunkingStrategyParam -from ...types.vector_stores.vector_store_file import VectorStoreFile -from ...types.vector_stores.file_content_response import FileContentResponse -from ...types.vector_stores.vector_store_file_deleted import VectorStoreFileDeleted - -__all__ = ["Files", "AsyncFiles"] - - -class Files(SyncAPIResource): - @cached_property - def with_raw_response(self) -> FilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return FilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return FilesWithStreamingResponse(self) - - def create( - self, - vector_store_id: str, - *, - file_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Create a vector store file by attaching a - [File](https://platform.openai.com/docs/api-reference/files) to a - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). - - Args: - file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID that the - vector store should use. Useful for tools like `file_search` that can access - files. - - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/vector_stores/{vector_store_id}/files", - body=maybe_transform( - { - "file_id": file_id, - "attributes": attributes, - "chunking_strategy": chunking_strategy, - }, - file_create_params.FileCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - def retrieve( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Retrieves a vector store file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - def update( - self, - file_id: str, - *, - vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Update attributes on a vector store file. - - Args: - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", - body=maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - def list( - self, - vector_store_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[VectorStoreFile]: - """ - Returns a list of vector store files. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", - page=SyncCursorPage[VectorStoreFile], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "filter": filter, - "limit": limit, - "order": order, - }, - file_list_params.FileListParams, - ), - ), - model=VectorStoreFile, - ) - - def delete( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileDeleted: - """Delete a vector store file. - - This will remove the file from the vector store but - the file itself will not be deleted. To delete the file, use the - [delete file](https://platform.openai.com/docs/api-reference/files/delete) - endpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileDeleted, - ) - - def create_and_poll( - self, - file_id: str, - *, - vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Attach a file to the given vector store and wait for it to be processed.""" - self.create( - vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes - ) - - return self.poll( - file_id, - vector_store_id=vector_store_id, - poll_interval_ms=poll_interval_ms, - ) - - def poll( - self, - file_id: str, - *, - vector_store_id: str, - poll_interval_ms: int | Omit = omit, - ) -> VectorStoreFile: - """Wait for the vector store file to finish processing. - - Note: this will return even if the file failed to process, you need to check - file.last_error and file.status to handle these cases - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = self.with_raw_response.retrieve( - file_id, - vector_store_id=vector_store_id, - extra_headers=headers, - ) - - file = response.parse() - if file.status == "in_progress": - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - self._sleep(poll_interval_ms / 1000) - elif file.status == "cancelled" or file.status == "completed" or file.status == "failed": - return file - else: - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(file.status) - else: - return file - - def upload( - self, - *, - vector_store_id: str, - file: FileTypes, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Upload a file to the `files` API and then attach it to the given vector store. - - Note the file will be asynchronously processed (you can use the alternative - polling helper method to wait for processing to complete). - """ - file_obj = self._client.files.create(file=file, purpose="assistants") - return self.create(vector_store_id=vector_store_id, file_id=file_obj.id, chunking_strategy=chunking_strategy) - - def upload_and_poll( - self, - *, - vector_store_id: str, - file: FileTypes, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Add a file to a vector store and poll until processing is complete.""" - file_obj = self._client.files.create(file=file, purpose="assistants") - return self.create_and_poll( - vector_store_id=vector_store_id, - file_id=file_obj.id, - chunking_strategy=chunking_strategy, - poll_interval_ms=poll_interval_ms, - attributes=attributes, - ) - - def content( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[FileContentResponse]: - """ - Retrieve the parsed contents of a vector store file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", - page=SyncPage[FileContentResponse], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=FileContentResponse, - ) - - -class AsyncFiles(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncFilesWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncFilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncFilesWithStreamingResponse(self) - - async def create( - self, - vector_store_id: str, - *, - file_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Create a vector store file by attaching a - [File](https://platform.openai.com/docs/api-reference/files) to a - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). - - Args: - file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID that the - vector store should use. Useful for tools like `file_search` that can access - files. - - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/vector_stores/{vector_store_id}/files", - body=await async_maybe_transform( - { - "file_id": file_id, - "attributes": attributes, - "chunking_strategy": chunking_strategy, - }, - file_create_params.FileCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - async def retrieve( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Retrieves a vector store file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - async def update( - self, - file_id: str, - *, - vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFile: - """ - Update attributes on a vector store file. - - Args: - attributes: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. Keys are strings with a maximum - length of 64 characters. Values are strings with a maximum length of 512 - characters, booleans, or numbers. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", - body=await async_maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFile, - ) - - def list( - self, - vector_store_id: str, - *, - after: str | Omit = omit, - before: str | Omit = omit, - filter: Literal["in_progress", "completed", "failed", "cancelled"] | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: - """ - Returns a list of vector store files. - - Args: - after: A cursor for use in pagination. `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - filter: Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", - page=AsyncCursorPage[VectorStoreFile], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "filter": filter, - "limit": limit, - "order": order, - }, - file_list_params.FileListParams, - ), - ), - model=VectorStoreFile, - ) - - async def delete( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreFileDeleted: - """Delete a vector store file. - - This will remove the file from the vector store but - the file itself will not be deleted. To delete the file, use the - [delete file](https://platform.openai.com/docs/api-reference/files/delete) - endpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreFileDeleted, - ) - - async def create_and_poll( - self, - file_id: str, - *, - vector_store_id: str, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Attach a file to the given vector store and wait for it to be processed.""" - await self.create( - vector_store_id=vector_store_id, file_id=file_id, chunking_strategy=chunking_strategy, attributes=attributes - ) - - return await self.poll( - file_id, - vector_store_id=vector_store_id, - poll_interval_ms=poll_interval_ms, - ) - - async def poll( - self, - file_id: str, - *, - vector_store_id: str, - poll_interval_ms: int | Omit = omit, - ) -> VectorStoreFile: - """Wait for the vector store file to finish processing. - - Note: this will return even if the file failed to process, you need to check - file.last_error and file.status to handle these cases - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = await self.with_raw_response.retrieve( - file_id, - vector_store_id=vector_store_id, - extra_headers=headers, - ) - - file = response.parse() - if file.status == "in_progress": - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - await self._sleep(poll_interval_ms / 1000) - elif file.status == "cancelled" or file.status == "completed" or file.status == "failed": - return file - else: - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(file.status) - else: - return file - - async def upload( - self, - *, - vector_store_id: str, - file: FileTypes, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Upload a file to the `files` API and then attach it to the given vector store. - - Note the file will be asynchronously processed (you can use the alternative - polling helper method to wait for processing to complete). - """ - file_obj = await self._client.files.create(file=file, purpose="assistants") - return await self.create( - vector_store_id=vector_store_id, file_id=file_obj.id, chunking_strategy=chunking_strategy - ) - - async def upload_and_poll( - self, - *, - vector_store_id: str, - file: FileTypes, - attributes: Optional[Dict[str, Union[str, float, bool]]] | Omit = omit, - poll_interval_ms: int | Omit = omit, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - ) -> VectorStoreFile: - """Add a file to a vector store and poll until processing is complete.""" - file_obj = await self._client.files.create(file=file, purpose="assistants") - return await self.create_and_poll( - vector_store_id=vector_store_id, - file_id=file_obj.id, - poll_interval_ms=poll_interval_ms, - chunking_strategy=chunking_strategy, - attributes=attributes, - ) - - def content( - self, - file_id: str, - *, - vector_store_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[FileContentResponse, AsyncPage[FileContentResponse]]: - """ - Retrieve the parsed contents of a vector store file. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - if not file_id: - raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", - page=AsyncPage[FileContentResponse], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=FileContentResponse, - ) - - -class FilesWithRawResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = _legacy_response.to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - files.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - files.update, - ) - self.list = _legacy_response.to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - files.delete, - ) - self.content = _legacy_response.to_raw_response_wrapper( - files.content, - ) - - -class AsyncFilesWithRawResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = _legacy_response.async_to_raw_response_wrapper( - files.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - files.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - files.update, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - files.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - files.delete, - ) - self.content = _legacy_response.async_to_raw_response_wrapper( - files.content, - ) - - -class FilesWithStreamingResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.create = to_streamed_response_wrapper( - files.create, - ) - self.retrieve = to_streamed_response_wrapper( - files.retrieve, - ) - self.update = to_streamed_response_wrapper( - files.update, - ) - self.list = to_streamed_response_wrapper( - files.list, - ) - self.delete = to_streamed_response_wrapper( - files.delete, - ) - self.content = to_streamed_response_wrapper( - files.content, - ) - - -class AsyncFilesWithStreamingResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.create = async_to_streamed_response_wrapper( - files.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - files.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - files.update, - ) - self.list = async_to_streamed_response_wrapper( - files.list, - ) - self.delete = async_to_streamed_response_wrapper( - files.delete, - ) - self.content = async_to_streamed_response_wrapper( - files.content, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/vector_stores.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/vector_stores.py deleted file mode 100644 index 490e3e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/vector_stores/vector_stores.py +++ /dev/null @@ -1,875 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal - -import httpx - -from ... import _legacy_response -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from ...types import ( - FileChunkingStrategyParam, - vector_store_list_params, - vector_store_create_params, - vector_store_search_params, - vector_store_update_params, -) -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper -from ...pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage -from .file_batches import ( - FileBatches, - AsyncFileBatches, - FileBatchesWithRawResponse, - AsyncFileBatchesWithRawResponse, - FileBatchesWithStreamingResponse, - AsyncFileBatchesWithStreamingResponse, -) -from ..._base_client import AsyncPaginator, make_request_options -from ...types.vector_store import VectorStore -from ...types.vector_store_deleted import VectorStoreDeleted -from ...types.shared_params.metadata import Metadata -from ...types.file_chunking_strategy_param import FileChunkingStrategyParam -from ...types.vector_store_search_response import VectorStoreSearchResponse - -__all__ = ["VectorStores", "AsyncVectorStores"] - - -class VectorStores(SyncAPIResource): - @cached_property - def files(self) -> Files: - return Files(self._client) - - @cached_property - def file_batches(self) -> FileBatches: - return FileBatches(self._client) - - @cached_property - def with_raw_response(self) -> VectorStoresWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return VectorStoresWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> VectorStoresWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return VectorStoresWithStreamingResponse(self) - - def create( - self, - *, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - description: str | Omit = omit, - expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Create a vector store. - - Args: - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - description: A description for the vector store. Can be used to describe the vector store's - purpose. - - expires_after: The expiration policy for a vector store. - - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the vector store. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - "/vector_stores", - body=maybe_transform( - { - "chunking_strategy": chunking_strategy, - "description": description, - "expires_after": expires_after, - "file_ids": file_ids, - "metadata": metadata, - "name": name, - }, - vector_store_create_params.VectorStoreCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - def retrieve( - self, - vector_store_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Retrieves a vector store. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get( - f"/vector_stores/{vector_store_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - def update( - self, - vector_store_id: str, - *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Modifies a vector store. - - Args: - expires_after: The expiration policy for a vector store. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the vector store. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._post( - f"/vector_stores/{vector_store_id}", - body=maybe_transform( - { - "expires_after": expires_after, - "metadata": metadata, - "name": name, - }, - vector_store_update_params.VectorStoreUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[VectorStore]: - """Returns a list of vector stores. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - "/vector_stores", - page=SyncCursorPage[VectorStore], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - vector_store_list_params.VectorStoreListParams, - ), - ), - model=VectorStore, - ) - - def delete( - self, - vector_store_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreDeleted: - """ - Delete a vector store. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._delete( - f"/vector_stores/{vector_store_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreDeleted, - ) - - def search( - self, - vector_store_id: str, - *, - query: Union[str, SequenceNotStr[str]], - filters: vector_store_search_params.Filters | Omit = omit, - max_num_results: int | Omit = omit, - ranking_options: vector_store_search_params.RankingOptions | Omit = omit, - rewrite_query: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncPage[VectorStoreSearchResponse]: - """ - Search a vector store for relevant chunks based on a query and file attributes - filter. - - Args: - query: A query string for a search - - filters: A filter to apply based on file attributes. - - max_num_results: The maximum number of results to return. This number should be between 1 and 50 - inclusive. - - ranking_options: Ranking options for search. - - rewrite_query: Whether to rewrite the natural language query for vector search. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", - page=SyncPage[VectorStoreSearchResponse], - body=maybe_transform( - { - "query": query, - "filters": filters, - "max_num_results": max_num_results, - "ranking_options": ranking_options, - "rewrite_query": rewrite_query, - }, - vector_store_search_params.VectorStoreSearchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=VectorStoreSearchResponse, - method="post", - ) - - -class AsyncVectorStores(AsyncAPIResource): - @cached_property - def files(self) -> AsyncFiles: - return AsyncFiles(self._client) - - @cached_property - def file_batches(self) -> AsyncFileBatches: - return AsyncFileBatches(self._client) - - @cached_property - def with_raw_response(self) -> AsyncVectorStoresWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncVectorStoresWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncVectorStoresWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncVectorStoresWithStreamingResponse(self) - - async def create( - self, - *, - chunking_strategy: FileChunkingStrategyParam | Omit = omit, - description: str | Omit = omit, - expires_after: vector_store_create_params.ExpiresAfter | Omit = omit, - file_ids: SequenceNotStr[str] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Create a vector store. - - Args: - chunking_strategy: The chunking strategy used to chunk the file(s). If not set, will use the `auto` - strategy. Only applicable if `file_ids` is non-empty. - - description: A description for the vector store. Can be used to describe the vector store's - purpose. - - expires_after: The expiration policy for a vector store. - - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the vector store. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - "/vector_stores", - body=await async_maybe_transform( - { - "chunking_strategy": chunking_strategy, - "description": description, - "expires_after": expires_after, - "file_ids": file_ids, - "metadata": metadata, - "name": name, - }, - vector_store_create_params.VectorStoreCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - async def retrieve( - self, - vector_store_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Retrieves a vector store. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._get( - f"/vector_stores/{vector_store_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - async def update( - self, - vector_store_id: str, - *, - expires_after: Optional[vector_store_update_params.ExpiresAfter] | Omit = omit, - metadata: Optional[Metadata] | Omit = omit, - name: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStore: - """ - Modifies a vector store. - - Args: - expires_after: The expiration policy for a vector store. - - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - - name: The name of the vector store. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._post( - f"/vector_stores/{vector_store_id}", - body=await async_maybe_transform( - { - "expires_after": expires_after, - "metadata": metadata, - "name": name, - }, - vector_store_update_params.VectorStoreUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStore, - ) - - def list( - self, - *, - after: str | Omit = omit, - before: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[VectorStore, AsyncCursorPage[VectorStore]]: - """Returns a list of vector stores. - - Args: - after: A cursor for use in pagination. - - `after` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - ending with obj_foo, your subsequent call can include after=obj_foo in order to - fetch the next page of the list. - - before: A cursor for use in pagination. `before` is an object ID that defines your place - in the list. For instance, if you make a list request and receive 100 objects, - starting with obj_foo, your subsequent call can include before=obj_foo in order - to fetch the previous page of the list. - - limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. - - order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending - order and `desc` for descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - "/vector_stores", - page=AsyncCursorPage[VectorStore], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "before": before, - "limit": limit, - "order": order, - }, - vector_store_list_params.VectorStoreListParams, - ), - ), - model=VectorStore, - ) - - async def delete( - self, - vector_store_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VectorStoreDeleted: - """ - Delete a vector store. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return await self._delete( - f"/vector_stores/{vector_store_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VectorStoreDeleted, - ) - - def search( - self, - vector_store_id: str, - *, - query: Union[str, SequenceNotStr[str]], - filters: vector_store_search_params.Filters | Omit = omit, - max_num_results: int | Omit = omit, - ranking_options: vector_store_search_params.RankingOptions | Omit = omit, - rewrite_query: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[VectorStoreSearchResponse, AsyncPage[VectorStoreSearchResponse]]: - """ - Search a vector store for relevant chunks based on a query and file attributes - filter. - - Args: - query: A query string for a search - - filters: A filter to apply based on file attributes. - - max_num_results: The maximum number of results to return. This number should be between 1 and 50 - inclusive. - - ranking_options: Ranking options for search. - - rewrite_query: Whether to rewrite the natural language query for vector search. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not vector_store_id: - raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} - return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", - page=AsyncPage[VectorStoreSearchResponse], - body=maybe_transform( - { - "query": query, - "filters": filters, - "max_num_results": max_num_results, - "ranking_options": ranking_options, - "rewrite_query": rewrite_query, - }, - vector_store_search_params.VectorStoreSearchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=VectorStoreSearchResponse, - method="post", - ) - - -class VectorStoresWithRawResponse: - def __init__(self, vector_stores: VectorStores) -> None: - self._vector_stores = vector_stores - - self.create = _legacy_response.to_raw_response_wrapper( - vector_stores.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - vector_stores.retrieve, - ) - self.update = _legacy_response.to_raw_response_wrapper( - vector_stores.update, - ) - self.list = _legacy_response.to_raw_response_wrapper( - vector_stores.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - vector_stores.delete, - ) - self.search = _legacy_response.to_raw_response_wrapper( - vector_stores.search, - ) - - @cached_property - def files(self) -> FilesWithRawResponse: - return FilesWithRawResponse(self._vector_stores.files) - - @cached_property - def file_batches(self) -> FileBatchesWithRawResponse: - return FileBatchesWithRawResponse(self._vector_stores.file_batches) - - -class AsyncVectorStoresWithRawResponse: - def __init__(self, vector_stores: AsyncVectorStores) -> None: - self._vector_stores = vector_stores - - self.create = _legacy_response.async_to_raw_response_wrapper( - vector_stores.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - vector_stores.retrieve, - ) - self.update = _legacy_response.async_to_raw_response_wrapper( - vector_stores.update, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - vector_stores.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - vector_stores.delete, - ) - self.search = _legacy_response.async_to_raw_response_wrapper( - vector_stores.search, - ) - - @cached_property - def files(self) -> AsyncFilesWithRawResponse: - return AsyncFilesWithRawResponse(self._vector_stores.files) - - @cached_property - def file_batches(self) -> AsyncFileBatchesWithRawResponse: - return AsyncFileBatchesWithRawResponse(self._vector_stores.file_batches) - - -class VectorStoresWithStreamingResponse: - def __init__(self, vector_stores: VectorStores) -> None: - self._vector_stores = vector_stores - - self.create = to_streamed_response_wrapper( - vector_stores.create, - ) - self.retrieve = to_streamed_response_wrapper( - vector_stores.retrieve, - ) - self.update = to_streamed_response_wrapper( - vector_stores.update, - ) - self.list = to_streamed_response_wrapper( - vector_stores.list, - ) - self.delete = to_streamed_response_wrapper( - vector_stores.delete, - ) - self.search = to_streamed_response_wrapper( - vector_stores.search, - ) - - @cached_property - def files(self) -> FilesWithStreamingResponse: - return FilesWithStreamingResponse(self._vector_stores.files) - - @cached_property - def file_batches(self) -> FileBatchesWithStreamingResponse: - return FileBatchesWithStreamingResponse(self._vector_stores.file_batches) - - -class AsyncVectorStoresWithStreamingResponse: - def __init__(self, vector_stores: AsyncVectorStores) -> None: - self._vector_stores = vector_stores - - self.create = async_to_streamed_response_wrapper( - vector_stores.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - vector_stores.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - vector_stores.update, - ) - self.list = async_to_streamed_response_wrapper( - vector_stores.list, - ) - self.delete = async_to_streamed_response_wrapper( - vector_stores.delete, - ) - self.search = async_to_streamed_response_wrapper( - vector_stores.search, - ) - - @cached_property - def files(self) -> AsyncFilesWithStreamingResponse: - return AsyncFilesWithStreamingResponse(self._vector_stores.files) - - @cached_property - def file_batches(self) -> AsyncFileBatchesWithStreamingResponse: - return AsyncFileBatchesWithStreamingResponse(self._vector_stores.file_batches) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/videos.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/videos.py deleted file mode 100644 index 9f74c94..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/videos.py +++ /dev/null @@ -1,850 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING, Mapping, cast -from typing_extensions import Literal, assert_never - -import httpx - -from .. import _legacy_response -from ..types import ( - VideoSize, - VideoSeconds, - video_list_params, - video_remix_params, - video_create_params, - video_download_content_params, -) -from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_streamed_response_wrapper, - async_to_streamed_response_wrapper, - to_custom_streamed_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ..pagination import SyncConversationCursorPage, AsyncConversationCursorPage -from ..types.video import Video -from .._base_client import AsyncPaginator, make_request_options -from .._utils._utils import is_given -from ..types.video_size import VideoSize -from ..types.video_seconds import VideoSeconds -from ..types.video_model_param import VideoModelParam -from ..types.video_delete_response import VideoDeleteResponse - -__all__ = ["Videos", "AsyncVideos"] - - -class Videos(SyncAPIResource): - @cached_property - def with_raw_response(self) -> VideosWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return VideosWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> VideosWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return VideosWithStreamingResponse(self) - - def create( - self, - *, - prompt: str, - input_reference: FileTypes | Omit = omit, - model: VideoModelParam | Omit = omit, - seconds: VideoSeconds | Omit = omit, - size: VideoSize | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Create a video - - Args: - prompt: Text prompt that describes the video to generate. - - input_reference: Optional image reference that guides generation. - - model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults - to `sora-2`. - - seconds: Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds. - - size: Output resolution formatted as width x height (allowed values: 720x1280, - 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "prompt": prompt, - "input_reference": input_reference, - "model": model, - "seconds": seconds, - "size": size, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return self._post( - "/videos", - body=maybe_transform(body, video_create_params.VideoCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - def create_and_poll( - self, - *, - prompt: str, - input_reference: FileTypes | Omit = omit, - model: VideoModelParam | Omit = omit, - seconds: VideoSeconds | Omit = omit, - size: VideoSize | Omit = omit, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """Create a video and wait for it to be processed.""" - video = self.create( - model=model, - prompt=prompt, - input_reference=input_reference, - seconds=seconds, - size=size, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return self.poll( - video.id, - poll_interval_ms=poll_interval_ms, - ) - - def poll( - self, - video_id: str, - *, - poll_interval_ms: int | Omit = omit, - ) -> Video: - """Wait for the vector store file to finish processing. - - Note: this will return even if the file failed to process, you need to check - file.last_error and file.status to handle these cases - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = self.with_raw_response.retrieve( - video_id, - extra_headers=headers, - ) - - video = response.parse() - if video.status == "in_progress" or video.status == "queued": - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - self._sleep(poll_interval_ms / 1000) - elif video.status == "completed" or video.status == "failed": - return video - else: - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(video.status) - else: - return video - - def retrieve( - self, - video_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Retrieve a video - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return self._get( - f"/videos/{video_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncConversationCursorPage[Video]: - """ - List videos - - Args: - after: Identifier for the last item from the previous pagination request - - limit: Number of items to retrieve - - order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for - descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/videos", - page=SyncConversationCursorPage[Video], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - video_list_params.VideoListParams, - ), - ), - model=Video, - ) - - def delete( - self, - video_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VideoDeleteResponse: - """ - Delete a video - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return self._delete( - f"/videos/{video_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VideoDeleteResponse, - ) - - def download_content( - self, - video_id: str, - *, - variant: Literal["video", "thumbnail", "spritesheet"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """Download video content - - Args: - variant: Which downloadable asset to return. - - Defaults to the MP4 video. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return self._get( - f"/videos/{video_id}/content", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"variant": variant}, video_download_content_params.VideoDownloadContentParams), - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - def remix( - self, - video_id: str, - *, - prompt: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Create a video remix - - Args: - prompt: Updated text prompt that directs the remix generation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return self._post( - f"/videos/{video_id}/remix", - body=maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - -class AsyncVideos(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncVideosWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers - """ - return AsyncVideosWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncVideosWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/openai/openai-python#with_streaming_response - """ - return AsyncVideosWithStreamingResponse(self) - - async def create( - self, - *, - prompt: str, - input_reference: FileTypes | Omit = omit, - model: VideoModelParam | Omit = omit, - seconds: VideoSeconds | Omit = omit, - size: VideoSize | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Create a video - - Args: - prompt: Text prompt that describes the video to generate. - - input_reference: Optional image reference that guides generation. - - model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults - to `sora-2`. - - seconds: Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds. - - size: Output resolution formatted as width x height (allowed values: 720x1280, - 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - body = deepcopy_minimal( - { - "prompt": prompt, - "input_reference": input_reference, - "model": model, - "seconds": seconds, - "size": size, - } - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]]) - if files: - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} - return await self._post( - "/videos", - body=await async_maybe_transform(body, video_create_params.VideoCreateParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - async def create_and_poll( - self, - *, - prompt: str, - input_reference: FileTypes | Omit = omit, - model: VideoModelParam | Omit = omit, - seconds: VideoSeconds | Omit = omit, - size: VideoSize | Omit = omit, - poll_interval_ms: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """Create a video and wait for it to be processed.""" - video = await self.create( - model=model, - prompt=prompt, - input_reference=input_reference, - seconds=seconds, - size=size, - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - ) - - return await self.poll( - video.id, - poll_interval_ms=poll_interval_ms, - ) - - async def poll( - self, - video_id: str, - *, - poll_interval_ms: int | Omit = omit, - ) -> Video: - """Wait for the vector store file to finish processing. - - Note: this will return even if the file failed to process, you need to check - file.last_error and file.status to handle these cases - """ - headers: dict[str, str] = {"X-Stainless-Poll-Helper": "true"} - if is_given(poll_interval_ms): - headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) - - while True: - response = await self.with_raw_response.retrieve( - video_id, - extra_headers=headers, - ) - - video = response.parse() - if video.status == "in_progress" or video.status == "queued": - if not is_given(poll_interval_ms): - from_header = response.headers.get("openai-poll-after-ms") - if from_header is not None: - poll_interval_ms = int(from_header) - else: - poll_interval_ms = 1000 - - await self._sleep(poll_interval_ms / 1000) - elif video.status == "completed" or video.status == "failed": - return video - else: - if TYPE_CHECKING: # type: ignore[unreachable] - assert_never(video.status) - else: - return video - - async def retrieve( - self, - video_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Retrieve a video - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return await self._get( - f"/videos/{video_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - def list( - self, - *, - after: str | Omit = omit, - limit: int | Omit = omit, - order: Literal["asc", "desc"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Video, AsyncConversationCursorPage[Video]]: - """ - List videos - - Args: - after: Identifier for the last item from the previous pagination request - - limit: Number of items to retrieve - - order: Sort order of results by timestamp. Use `asc` for ascending order or `desc` for - descending order. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/videos", - page=AsyncConversationCursorPage[Video], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "after": after, - "limit": limit, - "order": order, - }, - video_list_params.VideoListParams, - ), - ), - model=Video, - ) - - async def delete( - self, - video_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> VideoDeleteResponse: - """ - Delete a video - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return await self._delete( - f"/videos/{video_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=VideoDeleteResponse, - ) - - async def download_content( - self, - video_id: str, - *, - variant: Literal["video", "thumbnail", "spritesheet"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> _legacy_response.HttpxBinaryResponseContent: - """Download video content - - Args: - variant: Which downloadable asset to return. - - Defaults to the MP4 video. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - extra_headers = {"Accept": "application/binary", **(extra_headers or {})} - return await self._get( - f"/videos/{video_id}/content", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"variant": variant}, video_download_content_params.VideoDownloadContentParams - ), - ), - cast_to=_legacy_response.HttpxBinaryResponseContent, - ) - - async def remix( - self, - video_id: str, - *, - prompt: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Video: - """ - Create a video remix - - Args: - prompt: Updated text prompt that directs the remix generation. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not video_id: - raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") - return await self._post( - f"/videos/{video_id}/remix", - body=await async_maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Video, - ) - - -class VideosWithRawResponse: - def __init__(self, videos: Videos) -> None: - self._videos = videos - - self.create = _legacy_response.to_raw_response_wrapper( - videos.create, - ) - self.retrieve = _legacy_response.to_raw_response_wrapper( - videos.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - videos.list, - ) - self.delete = _legacy_response.to_raw_response_wrapper( - videos.delete, - ) - self.download_content = _legacy_response.to_raw_response_wrapper( - videos.download_content, - ) - self.remix = _legacy_response.to_raw_response_wrapper( - videos.remix, - ) - - -class AsyncVideosWithRawResponse: - def __init__(self, videos: AsyncVideos) -> None: - self._videos = videos - - self.create = _legacy_response.async_to_raw_response_wrapper( - videos.create, - ) - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - videos.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - videos.list, - ) - self.delete = _legacy_response.async_to_raw_response_wrapper( - videos.delete, - ) - self.download_content = _legacy_response.async_to_raw_response_wrapper( - videos.download_content, - ) - self.remix = _legacy_response.async_to_raw_response_wrapper( - videos.remix, - ) - - -class VideosWithStreamingResponse: - def __init__(self, videos: Videos) -> None: - self._videos = videos - - self.create = to_streamed_response_wrapper( - videos.create, - ) - self.retrieve = to_streamed_response_wrapper( - videos.retrieve, - ) - self.list = to_streamed_response_wrapper( - videos.list, - ) - self.delete = to_streamed_response_wrapper( - videos.delete, - ) - self.download_content = to_custom_streamed_response_wrapper( - videos.download_content, - StreamedBinaryAPIResponse, - ) - self.remix = to_streamed_response_wrapper( - videos.remix, - ) - - -class AsyncVideosWithStreamingResponse: - def __init__(self, videos: AsyncVideos) -> None: - self._videos = videos - - self.create = async_to_streamed_response_wrapper( - videos.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - videos.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - videos.list, - ) - self.delete = async_to_streamed_response_wrapper( - videos.delete, - ) - self.download_content = async_to_custom_streamed_response_wrapper( - videos.download_content, - AsyncStreamedBinaryAPIResponse, - ) - self.remix = async_to_streamed_response_wrapper( - videos.remix, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/resources/webhooks.py b/backend/venv39/lib/python3.9/site-packages/openai/resources/webhooks.py deleted file mode 100644 index 3e13d3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/resources/webhooks.py +++ /dev/null @@ -1,210 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import hmac -import json -import time -import base64 -import hashlib -from typing import cast - -from .._types import HeadersLike -from .._utils import get_required_header -from .._models import construct_type -from .._resource import SyncAPIResource, AsyncAPIResource -from .._exceptions import InvalidWebhookSignatureError -from ..types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent - -__all__ = ["Webhooks", "AsyncWebhooks"] - - -class Webhooks(SyncAPIResource): - def unwrap( - self, - payload: str | bytes, - headers: HeadersLike, - *, - secret: str | None = None, - ) -> UnwrapWebhookEvent: - """Validates that the given payload was sent by OpenAI and parses the payload.""" - if secret is None: - secret = self._client.webhook_secret - - self.verify_signature(payload=payload, headers=headers, secret=secret) - - return cast( - UnwrapWebhookEvent, - construct_type( - type_=UnwrapWebhookEvent, - value=json.loads(payload), - ), - ) - - def verify_signature( - self, - payload: str | bytes, - headers: HeadersLike, - *, - secret: str | None = None, - tolerance: int = 300, - ) -> None: - """Validates whether or not the webhook payload was sent by OpenAI. - - Args: - payload: The webhook payload - headers: The webhook headers - secret: The webhook secret (optional, will use client secret if not provided) - tolerance: Maximum age of the webhook in seconds (default: 300 = 5 minutes) - """ - if secret is None: - secret = self._client.webhook_secret - - if secret is None: - raise ValueError( - "The webhook secret must either be set using the env var, OPENAI_WEBHOOK_SECRET, " - "on the client class, OpenAI(webhook_secret='123'), or passed to this function" - ) - - signature_header = get_required_header(headers, "webhook-signature") - timestamp = get_required_header(headers, "webhook-timestamp") - webhook_id = get_required_header(headers, "webhook-id") - - # Validate timestamp to prevent replay attacks - try: - timestamp_seconds = int(timestamp) - except ValueError: - raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None - - now = int(time.time()) - - if now - timestamp_seconds > tolerance: - raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None - - if timestamp_seconds > now + tolerance: - raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None - - # Extract signatures from v1, format - # The signature header can have multiple values, separated by spaces. - # Each value is in the format v1,. We should accept if any match. - signatures: list[str] = [] - for part in signature_header.split(): - if part.startswith("v1,"): - signatures.append(part[3:]) - else: - signatures.append(part) - - # Decode the secret if it starts with whsec_ - if secret.startswith("whsec_"): - decoded_secret = base64.b64decode(secret[6:]) - else: - decoded_secret = secret.encode() - - body = payload.decode("utf-8") if isinstance(payload, bytes) else payload - - # Prepare the signed payload (OpenAI uses webhookId.timestamp.payload format) - signed_payload = f"{webhook_id}.{timestamp}.{body}" - expected_signature = base64.b64encode( - hmac.new(decoded_secret, signed_payload.encode(), hashlib.sha256).digest() - ).decode() - - # Accept if any signature matches - if not any(hmac.compare_digest(expected_signature, sig) for sig in signatures): - raise InvalidWebhookSignatureError( - "The given webhook signature does not match the expected signature" - ) from None - - -class AsyncWebhooks(AsyncAPIResource): - def unwrap( - self, - payload: str | bytes, - headers: HeadersLike, - *, - secret: str | None = None, - ) -> UnwrapWebhookEvent: - """Validates that the given payload was sent by OpenAI and parses the payload.""" - if secret is None: - secret = self._client.webhook_secret - - self.verify_signature(payload=payload, headers=headers, secret=secret) - - body = payload.decode("utf-8") if isinstance(payload, bytes) else payload - return cast( - UnwrapWebhookEvent, - construct_type( - type_=UnwrapWebhookEvent, - value=json.loads(body), - ), - ) - - def verify_signature( - self, - payload: str | bytes, - headers: HeadersLike, - *, - secret: str | None = None, - tolerance: int = 300, - ) -> None: - """Validates whether or not the webhook payload was sent by OpenAI. - - Args: - payload: The webhook payload - headers: The webhook headers - secret: The webhook secret (optional, will use client secret if not provided) - tolerance: Maximum age of the webhook in seconds (default: 300 = 5 minutes) - """ - if secret is None: - secret = self._client.webhook_secret - - if secret is None: - raise ValueError( - "The webhook secret must either be set using the env var, OPENAI_WEBHOOK_SECRET, " - "on the client class, OpenAI(webhook_secret='123'), or passed to this function" - ) from None - - signature_header = get_required_header(headers, "webhook-signature") - timestamp = get_required_header(headers, "webhook-timestamp") - webhook_id = get_required_header(headers, "webhook-id") - - # Validate timestamp to prevent replay attacks - try: - timestamp_seconds = int(timestamp) - except ValueError: - raise InvalidWebhookSignatureError("Invalid webhook timestamp format") from None - - now = int(time.time()) - - if now - timestamp_seconds > tolerance: - raise InvalidWebhookSignatureError("Webhook timestamp is too old") from None - - if timestamp_seconds > now + tolerance: - raise InvalidWebhookSignatureError("Webhook timestamp is too new") from None - - # Extract signatures from v1, format - # The signature header can have multiple values, separated by spaces. - # Each value is in the format v1,. We should accept if any match. - signatures: list[str] = [] - for part in signature_header.split(): - if part.startswith("v1,"): - signatures.append(part[3:]) - else: - signatures.append(part) - - # Decode the secret if it starts with whsec_ - if secret.startswith("whsec_"): - decoded_secret = base64.b64decode(secret[6:]) - else: - decoded_secret = secret.encode() - - body = payload.decode("utf-8") if isinstance(payload, bytes) else payload - - # Prepare the signed payload (OpenAI uses webhookId.timestamp.payload format) - signed_payload = f"{webhook_id}.{timestamp}.{body}" - expected_signature = base64.b64encode( - hmac.new(decoded_secret, signed_payload.encode(), hashlib.sha256).digest() - ).decode() - - # Accept if any signature matches - if not any(hmac.compare_digest(expected_signature, sig) for sig in signatures): - raise InvalidWebhookSignatureError("The given webhook signature does not match the expected signature") diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/__init__.py deleted file mode 100644 index 5eb267e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/__init__.py +++ /dev/null @@ -1,116 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .batch import Batch as Batch -from .image import Image as Image -from .model import Model as Model -from .video import Video as Video -from .shared import ( - Metadata as Metadata, - AllModels as AllModels, - ChatModel as ChatModel, - Reasoning as Reasoning, - ErrorObject as ErrorObject, - CompoundFilter as CompoundFilter, - ResponsesModel as ResponsesModel, - ReasoningEffort as ReasoningEffort, - ComparisonFilter as ComparisonFilter, - FunctionDefinition as FunctionDefinition, - FunctionParameters as FunctionParameters, - ResponseFormatText as ResponseFormatText, - CustomToolInputFormat as CustomToolInputFormat, - ResponseFormatJSONObject as ResponseFormatJSONObject, - ResponseFormatJSONSchema as ResponseFormatJSONSchema, - ResponseFormatTextPython as ResponseFormatTextPython, - ResponseFormatTextGrammar as ResponseFormatTextGrammar, -) -from .upload import Upload as Upload -from .embedding import Embedding as Embedding -from .chat_model import ChatModel as ChatModel -from .completion import Completion as Completion -from .moderation import Moderation as Moderation -from .video_size import VideoSize as VideoSize -from .audio_model import AudioModel as AudioModel -from .batch_error import BatchError as BatchError -from .batch_usage import BatchUsage as BatchUsage -from .file_object import FileObject as FileObject -from .image_model import ImageModel as ImageModel -from .video_model import VideoModel as VideoModel -from .file_content import FileContent as FileContent -from .file_deleted import FileDeleted as FileDeleted -from .file_purpose import FilePurpose as FilePurpose -from .vector_store import VectorStore as VectorStore -from .model_deleted import ModelDeleted as ModelDeleted -from .video_seconds import VideoSeconds as VideoSeconds -from .embedding_model import EmbeddingModel as EmbeddingModel -from .images_response import ImagesResponse as ImagesResponse -from .completion_usage import CompletionUsage as CompletionUsage -from .eval_list_params import EvalListParams as EvalListParams -from .file_list_params import FileListParams as FileListParams -from .moderation_model import ModerationModel as ModerationModel -from .batch_list_params import BatchListParams as BatchListParams -from .completion_choice import CompletionChoice as CompletionChoice -from .image_edit_params import ImageEditParams as ImageEditParams -from .video_list_params import VideoListParams as VideoListParams -from .video_model_param import VideoModelParam as VideoModelParam -from .eval_create_params import EvalCreateParams as EvalCreateParams -from .eval_list_response import EvalListResponse as EvalListResponse -from .eval_update_params import EvalUpdateParams as EvalUpdateParams -from .file_create_params import FileCreateParams as FileCreateParams -from .video_create_error import VideoCreateError as VideoCreateError -from .video_remix_params import VideoRemixParams as VideoRemixParams -from .batch_create_params import BatchCreateParams as BatchCreateParams -from .video_create_params import VideoCreateParams as VideoCreateParams -from .batch_request_counts import BatchRequestCounts as BatchRequestCounts -from .eval_create_response import EvalCreateResponse as EvalCreateResponse -from .eval_delete_response import EvalDeleteResponse as EvalDeleteResponse -from .eval_update_response import EvalUpdateResponse as EvalUpdateResponse -from .upload_create_params import UploadCreateParams as UploadCreateParams -from .vector_store_deleted import VectorStoreDeleted as VectorStoreDeleted -from .audio_response_format import AudioResponseFormat as AudioResponseFormat -from .container_list_params import ContainerListParams as ContainerListParams -from .image_generate_params import ImageGenerateParams as ImageGenerateParams -from .video_delete_response import VideoDeleteResponse as VideoDeleteResponse -from .eval_retrieve_response import EvalRetrieveResponse as EvalRetrieveResponse -from .file_chunking_strategy import FileChunkingStrategy as FileChunkingStrategy -from .image_gen_stream_event import ImageGenStreamEvent as ImageGenStreamEvent -from .upload_complete_params import UploadCompleteParams as UploadCompleteParams -from .container_create_params import ContainerCreateParams as ContainerCreateParams -from .container_list_response import ContainerListResponse as ContainerListResponse -from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams -from .image_edit_stream_event import ImageEditStreamEvent as ImageEditStreamEvent -from .completion_create_params import CompletionCreateParams as CompletionCreateParams -from .moderation_create_params import ModerationCreateParams as ModerationCreateParams -from .vector_store_list_params import VectorStoreListParams as VectorStoreListParams -from .container_create_response import ContainerCreateResponse as ContainerCreateResponse -from .create_embedding_response import CreateEmbeddingResponse as CreateEmbeddingResponse -from .image_gen_completed_event import ImageGenCompletedEvent as ImageGenCompletedEvent -from .image_edit_completed_event import ImageEditCompletedEvent as ImageEditCompletedEvent -from .moderation_create_response import ModerationCreateResponse as ModerationCreateResponse -from .vector_store_create_params import VectorStoreCreateParams as VectorStoreCreateParams -from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams -from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams -from .container_retrieve_response import ContainerRetrieveResponse as ContainerRetrieveResponse -from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam -from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam -from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse -from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions -from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams -from .image_gen_partial_image_event import ImageGenPartialImageEvent as ImageGenPartialImageEvent -from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy -from .video_download_content_params import VideoDownloadContentParams as VideoDownloadContentParams -from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig -from .image_edit_partial_image_event import ImageEditPartialImageEvent as ImageEditPartialImageEvent -from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam -from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam -from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam -from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject -from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam -from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject -from .eval_stored_completions_data_source_config import ( - EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, -) -from .static_file_chunking_strategy_object_param import ( - StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/__init__.py deleted file mode 100644 index 2ff2b81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .translation import Translation as Translation -from .speech_model import SpeechModel as SpeechModel -from .transcription import Transcription as Transcription -from .transcription_word import TranscriptionWord as TranscriptionWord -from .translation_verbose import TranslationVerbose as TranslationVerbose -from .speech_create_params import SpeechCreateParams as SpeechCreateParams -from .transcription_include import TranscriptionInclude as TranscriptionInclude -from .transcription_segment import TranscriptionSegment as TranscriptionSegment -from .transcription_verbose import TranscriptionVerbose as TranscriptionVerbose -from .transcription_diarized import TranscriptionDiarized as TranscriptionDiarized -from .translation_create_params import TranslationCreateParams as TranslationCreateParams -from .transcription_stream_event import TranscriptionStreamEvent as TranscriptionStreamEvent -from .transcription_create_params import TranscriptionCreateParams as TranscriptionCreateParams -from .translation_create_response import TranslationCreateResponse as TranslationCreateResponse -from .transcription_create_response import TranscriptionCreateResponse as TranscriptionCreateResponse -from .transcription_text_done_event import TranscriptionTextDoneEvent as TranscriptionTextDoneEvent -from .transcription_diarized_segment import TranscriptionDiarizedSegment as TranscriptionDiarizedSegment -from .transcription_text_delta_event import TranscriptionTextDeltaEvent as TranscriptionTextDeltaEvent -from .transcription_text_segment_event import TranscriptionTextSegmentEvent as TranscriptionTextSegmentEvent diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_create_params.py deleted file mode 100644 index 417df5b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_create_params.py +++ /dev/null @@ -1,57 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -from .speech_model import SpeechModel - -__all__ = ["SpeechCreateParams"] - - -class SpeechCreateParams(TypedDict, total=False): - input: Required[str] - """The text to generate audio for. The maximum length is 4096 characters.""" - - model: Required[Union[str, SpeechModel]] - """ - One of the available [TTS models](https://platform.openai.com/docs/models#tts): - `tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`. - """ - - voice: Required[ - Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - ] - """The voice to use when generating the audio. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, - `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. - Previews of the voices are available in the - [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). - """ - - instructions: str - """Control the voice of your generated audio with additional instructions. - - Does not work with `tts-1` or `tts-1-hd`. - """ - - response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] - """The format to audio in. - - Supported formats are `mp3`, `opus`, `aac`, `flac`, `wav`, and `pcm`. - """ - - speed: float - """The speed of the generated audio. - - Select a value from `0.25` to `4.0`. `1.0` is the default. - """ - - stream_format: Literal["sse", "audio"] - """The format to stream the audio in. - - Supported formats are `sse` and `audio`. `sse` is not supported for `tts-1` or - `tts-1-hd`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_model.py deleted file mode 100644 index 31294a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/speech_model.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["SpeechModel"] - -SpeechModel: TypeAlias = Literal["tts-1", "tts-1-hd", "gpt-4o-mini-tts", "gpt-4o-mini-tts-2025-12-15"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription.py deleted file mode 100644 index cbae8bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription.py +++ /dev/null @@ -1,81 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["Transcription", "Logprob", "Usage", "UsageTokens", "UsageTokensInputTokenDetails", "UsageDuration"] - - -class Logprob(BaseModel): - token: Optional[str] = None - """The token in the transcription.""" - - bytes: Optional[List[float]] = None - """The bytes of the token.""" - - logprob: Optional[float] = None - """The log probability of the token.""" - - -class UsageTokensInputTokenDetails(BaseModel): - """Details about the input tokens billed for this request.""" - - audio_tokens: Optional[int] = None - """Number of audio tokens billed for this request.""" - - text_tokens: Optional[int] = None - """Number of text tokens billed for this request.""" - - -class UsageTokens(BaseModel): - """Usage statistics for models billed by token usage.""" - - input_tokens: int - """Number of input tokens billed for this request.""" - - output_tokens: int - """Number of output tokens generated.""" - - total_tokens: int - """Total number of tokens used (input + output).""" - - type: Literal["tokens"] - """The type of the usage object. Always `tokens` for this variant.""" - - input_token_details: Optional[UsageTokensInputTokenDetails] = None - """Details about the input tokens billed for this request.""" - - -class UsageDuration(BaseModel): - """Usage statistics for models billed by audio input duration.""" - - seconds: float - """Duration of the input audio in seconds.""" - - type: Literal["duration"] - """The type of the usage object. Always `duration` for this variant.""" - - -Usage: TypeAlias = Annotated[Union[UsageTokens, UsageDuration], PropertyInfo(discriminator="type")] - - -class Transcription(BaseModel): - """ - Represents a transcription response returned by model, based on the provided input. - """ - - text: str - """The transcribed text.""" - - logprobs: Optional[List[Logprob]] = None - """The log probabilities of the tokens in the transcription. - - Only returned with the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe` - if `logprobs` is added to the `include` array. - """ - - usage: Optional[Usage] = None - """Token usage statistics for the request.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_params.py deleted file mode 100644 index 15540fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_params.py +++ /dev/null @@ -1,172 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import FileTypes, SequenceNotStr -from ..audio_model import AudioModel -from .transcription_include import TranscriptionInclude -from ..audio_response_format import AudioResponseFormat - -__all__ = [ - "TranscriptionCreateParamsBase", - "ChunkingStrategy", - "ChunkingStrategyVadConfig", - "TranscriptionCreateParamsNonStreaming", - "TranscriptionCreateParamsStreaming", -] - - -class TranscriptionCreateParamsBase(TypedDict, total=False): - file: Required[FileTypes] - """ - The audio file object (not file name) to transcribe, in one of these formats: - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - """ - - model: Required[Union[str, AudioModel]] - """ID of the model to use. - - The options are `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, - `gpt-4o-mini-transcribe-2025-12-15`, `whisper-1` (which is powered by our open - source Whisper V2 model), and `gpt-4o-transcribe-diarize`. - """ - - chunking_strategy: Optional[ChunkingStrategy] - """Controls how the audio is cut into chunks. - - When set to `"auto"`, the server first normalizes loudness and then uses voice - activity detection (VAD) to choose boundaries. `server_vad` object can be - provided to tweak VAD detection parameters manually. If unset, the audio is - transcribed as a single block. Required when using `gpt-4o-transcribe-diarize` - for inputs longer than 30 seconds. - """ - - include: List[TranscriptionInclude] - """ - Additional information to include in the transcription response. `logprobs` will - return the log probabilities of the tokens in the response to understand the - model's confidence in the transcription. `logprobs` only works with - response_format set to `json` and only with the models `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `gpt-4o-mini-transcribe-2025-12-15`. This field is - not supported when using `gpt-4o-transcribe-diarize`. - """ - - known_speaker_names: SequenceNotStr[str] - """ - Optional list of speaker names that correspond to the audio samples provided in - `known_speaker_references[]`. Each entry should be a short identifier (for - example `customer` or `agent`). Up to 4 speakers are supported. - """ - - known_speaker_references: SequenceNotStr[str] - """ - Optional list of audio samples (as - [data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)) - that contain known speaker references matching `known_speaker_names[]`. Each - sample must be between 2 and 10 seconds, and can use any of the same input audio - formats supported by `file`. - """ - - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - prompt: str - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. This field is not supported when using - `gpt-4o-transcribe-diarize`. - """ - - response_format: AudioResponseFormat - """ - The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, `vtt`, or `diarized_json`. For `gpt-4o-transcribe` and - `gpt-4o-mini-transcribe`, the only supported format is `json`. For - `gpt-4o-transcribe-diarize`, the supported formats are `json`, `text`, and - `diarized_json`, with `diarized_json` required to receive speaker annotations. - """ - - temperature: float - """The sampling temperature, between 0 and 1. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - """ - - timestamp_granularities: List[Literal["word", "segment"]] - """The timestamp granularities to populate for this transcription. - - `response_format` must be set `verbose_json` to use timestamp granularities. - Either or both of these options are supported: `word`, or `segment`. Note: There - is no additional latency for segment timestamps, but generating word timestamps - incurs additional latency. This option is not available for - `gpt-4o-transcribe-diarize`. - """ - - -class ChunkingStrategyVadConfig(TypedDict, total=False): - type: Required[Literal["server_vad"]] - """Must be set to `server_vad` to enable manual chunking using server side VAD.""" - - prefix_padding_ms: int - """Amount of audio to include before the VAD detected speech (in milliseconds).""" - - silence_duration_ms: int - """ - Duration of silence to detect speech stop (in milliseconds). With shorter values - the model will respond more quickly, but may jump in on short pauses from the - user. - """ - - threshold: float - """Sensitivity threshold (0.0 to 1.0) for voice activity detection. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - -ChunkingStrategy: TypeAlias = Union[Literal["auto"], ChunkingStrategyVadConfig] - - -class TranscriptionCreateParamsNonStreaming(TranscriptionCreateParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - """ - - -class TranscriptionCreateParamsStreaming(TranscriptionCreateParamsBase): - stream: Required[Literal[True]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section of the Speech-to-Text guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions) - for more information. - - Note: Streaming is not supported for the `whisper-1` model and will be ignored. - """ - - -TranscriptionCreateParams = Union[TranscriptionCreateParamsNonStreaming, TranscriptionCreateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_response.py deleted file mode 100644 index 5717a3e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_create_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from .transcription import Transcription -from .transcription_verbose import TranscriptionVerbose -from .transcription_diarized import TranscriptionDiarized - -__all__ = ["TranscriptionCreateResponse"] - -TranscriptionCreateResponse: TypeAlias = Union[Transcription, TranscriptionDiarized, TranscriptionVerbose] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized.py deleted file mode 100644 index 07585fe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .transcription_diarized_segment import TranscriptionDiarizedSegment - -__all__ = ["TranscriptionDiarized", "Usage", "UsageTokens", "UsageTokensInputTokenDetails", "UsageDuration"] - - -class UsageTokensInputTokenDetails(BaseModel): - """Details about the input tokens billed for this request.""" - - audio_tokens: Optional[int] = None - """Number of audio tokens billed for this request.""" - - text_tokens: Optional[int] = None - """Number of text tokens billed for this request.""" - - -class UsageTokens(BaseModel): - """Usage statistics for models billed by token usage.""" - - input_tokens: int - """Number of input tokens billed for this request.""" - - output_tokens: int - """Number of output tokens generated.""" - - total_tokens: int - """Total number of tokens used (input + output).""" - - type: Literal["tokens"] - """The type of the usage object. Always `tokens` for this variant.""" - - input_token_details: Optional[UsageTokensInputTokenDetails] = None - """Details about the input tokens billed for this request.""" - - -class UsageDuration(BaseModel): - """Usage statistics for models billed by audio input duration.""" - - seconds: float - """Duration of the input audio in seconds.""" - - type: Literal["duration"] - """The type of the usage object. Always `duration` for this variant.""" - - -Usage: TypeAlias = Annotated[Union[UsageTokens, UsageDuration], PropertyInfo(discriminator="type")] - - -class TranscriptionDiarized(BaseModel): - """ - Represents a diarized transcription response returned by the model, including the combined transcript and speaker-segment annotations. - """ - - duration: float - """Duration of the input audio in seconds.""" - - segments: List[TranscriptionDiarizedSegment] - """Segments of the transcript annotated with timestamps and speaker labels.""" - - task: Literal["transcribe"] - """The type of task that was run. Always `transcribe`.""" - - text: str - """The concatenated transcript text for the entire audio input.""" - - usage: Optional[Usage] = None - """Token or duration usage statistics for the request.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized_segment.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized_segment.py deleted file mode 100644 index fcfdb36..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_diarized_segment.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TranscriptionDiarizedSegment"] - - -class TranscriptionDiarizedSegment(BaseModel): - """A segment of diarized transcript text with speaker metadata.""" - - id: str - """Unique identifier for the segment.""" - - end: float - """End timestamp of the segment in seconds.""" - - speaker: str - """Speaker label for this segment. - - When known speakers are provided, the label matches `known_speaker_names[]`. - Otherwise speakers are labeled sequentially using capital letters (`A`, `B`, - ...). - """ - - start: float - """Start timestamp of the segment in seconds.""" - - text: str - """Transcript text for this segment.""" - - type: Literal["transcript.text.segment"] - """The type of the segment. Always `transcript.text.segment`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_include.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_include.py deleted file mode 100644 index 0e464ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_include.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["TranscriptionInclude"] - -TranscriptionInclude: TypeAlias = Literal["logprobs"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_segment.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_segment.py deleted file mode 100644 index 522c401..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_segment.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["TranscriptionSegment"] - - -class TranscriptionSegment(BaseModel): - id: int - """Unique identifier of the segment.""" - - avg_logprob: float - """Average logprob of the segment. - - If the value is lower than -1, consider the logprobs failed. - """ - - compression_ratio: float - """Compression ratio of the segment. - - If the value is greater than 2.4, consider the compression failed. - """ - - end: float - """End time of the segment in seconds.""" - - no_speech_prob: float - """Probability of no speech in the segment. - - If the value is higher than 1.0 and the `avg_logprob` is below -1, consider this - segment silent. - """ - - seek: int - """Seek offset of the segment.""" - - start: float - """Start time of the segment in seconds.""" - - temperature: float - """Temperature parameter used for generating the segment.""" - - text: str - """Text content of the segment.""" - - tokens: List[int] - """Array of token IDs for the text content.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_stream_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_stream_event.py deleted file mode 100644 index 77d3a3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_stream_event.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .transcription_text_done_event import TranscriptionTextDoneEvent -from .transcription_text_delta_event import TranscriptionTextDeltaEvent -from .transcription_text_segment_event import TranscriptionTextSegmentEvent - -__all__ = ["TranscriptionStreamEvent"] - -TranscriptionStreamEvent: TypeAlias = Annotated[ - Union[TranscriptionTextSegmentEvent, TranscriptionTextDeltaEvent, TranscriptionTextDoneEvent], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_delta_event.py deleted file mode 100644 index a6e8313..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_delta_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TranscriptionTextDeltaEvent", "Logprob"] - - -class Logprob(BaseModel): - token: Optional[str] = None - """The token that was used to generate the log probability.""" - - bytes: Optional[List[int]] = None - """The bytes that were used to generate the log probability.""" - - logprob: Optional[float] = None - """The log probability of the token.""" - - -class TranscriptionTextDeltaEvent(BaseModel): - """Emitted when there is an additional text delta. - - This is also the first event emitted when the transcription starts. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`. - """ - - delta: str - """The text delta that was additionally transcribed.""" - - type: Literal["transcript.text.delta"] - """The type of the event. Always `transcript.text.delta`.""" - - logprobs: Optional[List[Logprob]] = None - """The log probabilities of the delta. - - Only included if you - [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) - with the `include[]` parameter set to `logprobs`. - """ - - segment_id: Optional[str] = None - """Identifier of the diarized segment that this delta belongs to. - - Only present when using `gpt-4o-transcribe-diarize`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_done_event.py deleted file mode 100644 index c8f7fc0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_done_event.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TranscriptionTextDoneEvent", "Logprob", "Usage", "UsageInputTokenDetails"] - - -class Logprob(BaseModel): - token: Optional[str] = None - """The token that was used to generate the log probability.""" - - bytes: Optional[List[int]] = None - """The bytes that were used to generate the log probability.""" - - logprob: Optional[float] = None - """The log probability of the token.""" - - -class UsageInputTokenDetails(BaseModel): - """Details about the input tokens billed for this request.""" - - audio_tokens: Optional[int] = None - """Number of audio tokens billed for this request.""" - - text_tokens: Optional[int] = None - """Number of text tokens billed for this request.""" - - -class Usage(BaseModel): - """Usage statistics for models billed by token usage.""" - - input_tokens: int - """Number of input tokens billed for this request.""" - - output_tokens: int - """Number of output tokens generated.""" - - total_tokens: int - """Total number of tokens used (input + output).""" - - type: Literal["tokens"] - """The type of the usage object. Always `tokens` for this variant.""" - - input_token_details: Optional[UsageInputTokenDetails] = None - """Details about the input tokens billed for this request.""" - - -class TranscriptionTextDoneEvent(BaseModel): - """Emitted when the transcription is complete. - - Contains the complete transcription text. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with the `Stream` parameter set to `true`. - """ - - text: str - """The text that was transcribed.""" - - type: Literal["transcript.text.done"] - """The type of the event. Always `transcript.text.done`.""" - - logprobs: Optional[List[Logprob]] = None - """The log probabilities of the individual tokens in the transcription. - - Only included if you - [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) - with the `include[]` parameter set to `logprobs`. - """ - - usage: Optional[Usage] = None - """Usage statistics for models billed by token usage.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_segment_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_segment_event.py deleted file mode 100644 index e95472e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_text_segment_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TranscriptionTextSegmentEvent"] - - -class TranscriptionTextSegmentEvent(BaseModel): - """ - Emitted when a diarized transcription returns a completed segment with speaker information. Only emitted when you [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription) with `stream` set to `true` and `response_format` set to `diarized_json`. - """ - - id: str - """Unique identifier for the segment.""" - - end: float - """End timestamp of the segment in seconds.""" - - speaker: str - """Speaker label for this segment.""" - - start: float - """Start timestamp of the segment in seconds.""" - - text: str - """Transcript text for this segment.""" - - type: Literal["transcript.text.segment"] - """The type of the event. Always `transcript.text.segment`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_verbose.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_verbose.py deleted file mode 100644 index b1a95e9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_verbose.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .transcription_word import TranscriptionWord -from .transcription_segment import TranscriptionSegment - -__all__ = ["TranscriptionVerbose", "Usage"] - - -class Usage(BaseModel): - """Usage statistics for models billed by audio input duration.""" - - seconds: float - """Duration of the input audio in seconds.""" - - type: Literal["duration"] - """The type of the usage object. Always `duration` for this variant.""" - - -class TranscriptionVerbose(BaseModel): - """ - Represents a verbose json transcription response returned by model, based on the provided input. - """ - - duration: float - """The duration of the input audio.""" - - language: str - """The language of the input audio.""" - - text: str - """The transcribed text.""" - - segments: Optional[List[TranscriptionSegment]] = None - """Segments of the transcribed text and their corresponding details.""" - - usage: Optional[Usage] = None - """Usage statistics for models billed by audio input duration.""" - - words: Optional[List[TranscriptionWord]] = None - """Extracted words and their corresponding timestamps.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_word.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_word.py deleted file mode 100644 index 2ce682f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/transcription_word.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["TranscriptionWord"] - - -class TranscriptionWord(BaseModel): - end: float - """End time of the word in seconds.""" - - start: float - """Start time of the word in seconds.""" - - word: str - """The text content of the word.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation.py deleted file mode 100644 index efc56f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["Translation"] - - -class Translation(BaseModel): - text: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_params.py deleted file mode 100644 index b23a185..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_params.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -from ..._types import FileTypes -from ..audio_model import AudioModel - -__all__ = ["TranslationCreateParams"] - - -class TranslationCreateParams(TypedDict, total=False): - file: Required[FileTypes] - """ - The audio file object (not file name) translate, in one of these formats: flac, - mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. - """ - - model: Required[Union[str, AudioModel]] - """ID of the model to use. - - Only `whisper-1` (which is powered by our open source Whisper V2 model) is - currently available. - """ - - prompt: str - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should be in English. - """ - - response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] - """ - The format of the output, in one of these options: `json`, `text`, `srt`, - `verbose_json`, or `vtt`. - """ - - temperature: float - """The sampling temperature, between 0 and 1. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. If set to 0, the model will use - [log probability](https://en.wikipedia.org/wiki/Log_probability) to - automatically increase the temperature until certain thresholds are hit. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_response.py deleted file mode 100644 index 9953813..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_create_response.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from .translation import Translation -from .translation_verbose import TranslationVerbose - -__all__ = ["TranslationCreateResponse"] - -TranslationCreateResponse: TypeAlias = Union[Translation, TranslationVerbose] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_verbose.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_verbose.py deleted file mode 100644 index 27cb02d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio/translation_verbose.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .transcription_segment import TranscriptionSegment - -__all__ = ["TranslationVerbose"] - - -class TranslationVerbose(BaseModel): - duration: float - """The duration of the input audio.""" - - language: str - """The language of the output translation (always `english`).""" - - text: str - """The translated text.""" - - segments: Optional[List[TranscriptionSegment]] = None - """Segments of the translated text and their corresponding details.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio_model.py deleted file mode 100644 index 8acada6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio_model.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["AudioModel"] - -AudioModel: TypeAlias = Literal[ - "whisper-1", - "gpt-4o-transcribe", - "gpt-4o-mini-transcribe", - "gpt-4o-mini-transcribe-2025-12-15", - "gpt-4o-transcribe-diarize", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/audio_response_format.py b/backend/venv39/lib/python3.9/site-packages/openai/types/audio_response_format.py deleted file mode 100644 index 1897aaf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/audio_response_format.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["AudioResponseFormat"] - -AudioResponseFormat: TypeAlias = Literal["json", "text", "srt", "verbose_json", "vtt", "diarized_json"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/auto_file_chunking_strategy_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/auto_file_chunking_strategy_param.py deleted file mode 100644 index db7cbf5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/auto_file_chunking_strategy_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["AutoFileChunkingStrategyParam"] - - -class AutoFileChunkingStrategyParam(TypedDict, total=False): - """The default strategy. - - This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. - """ - - type: Required[Literal["auto"]] - """Always `auto`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch.py deleted file mode 100644 index ece0513..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch.py +++ /dev/null @@ -1,104 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .batch_error import BatchError -from .batch_usage import BatchUsage -from .shared.metadata import Metadata -from .batch_request_counts import BatchRequestCounts - -__all__ = ["Batch", "Errors"] - - -class Errors(BaseModel): - data: Optional[List[BatchError]] = None - - object: Optional[str] = None - """The object type, which is always `list`.""" - - -class Batch(BaseModel): - id: str - - completion_window: str - """The time frame within which the batch should be processed.""" - - created_at: int - """The Unix timestamp (in seconds) for when the batch was created.""" - - endpoint: str - """The OpenAI API endpoint used by the batch.""" - - input_file_id: str - """The ID of the input file for the batch.""" - - object: Literal["batch"] - """The object type, which is always `batch`.""" - - status: Literal[ - "validating", "failed", "in_progress", "finalizing", "completed", "expired", "cancelling", "cancelled" - ] - """The current status of the batch.""" - - cancelled_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch was cancelled.""" - - cancelling_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch started cancelling.""" - - completed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch was completed.""" - - error_file_id: Optional[str] = None - """The ID of the file containing the outputs of requests with errors.""" - - errors: Optional[Errors] = None - - expired_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch expired.""" - - expires_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch will expire.""" - - failed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch failed.""" - - finalizing_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch started finalizing.""" - - in_progress_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the batch started processing.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Optional[str] = None - """Model ID used to process the batch, like `gpt-5-2025-08-07`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - output_file_id: Optional[str] = None - """The ID of the file containing the outputs of successfully executed requests.""" - - request_counts: Optional[BatchRequestCounts] = None - """The request counts for different statuses within the batch.""" - - usage: Optional[BatchUsage] = None - """ - Represents token usage details including input tokens, output tokens, a - breakdown of output tokens, and the total tokens used. Only populated on batches - created after September 7, 2025. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch_create_params.py deleted file mode 100644 index 1088aab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_create_params.py +++ /dev/null @@ -1,76 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -from .shared_params.metadata import Metadata - -__all__ = ["BatchCreateParams", "OutputExpiresAfter"] - - -class BatchCreateParams(TypedDict, total=False): - completion_window: Required[Literal["24h"]] - """The time frame within which the batch should be processed. - - Currently only `24h` is supported. - """ - - endpoint: Required[ - Literal["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations"] - ] - """The endpoint to be used for all requests in the batch. - - Currently `/v1/responses`, `/v1/chat/completions`, `/v1/embeddings`, - `/v1/completions`, and `/v1/moderations` are supported. Note that - `/v1/embeddings` batches are also restricted to a maximum of 50,000 embedding - inputs across all requests in the batch. - """ - - input_file_id: Required[str] - """The ID of an uploaded file that contains requests for the new batch. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your input file must be formatted as a - [JSONL file](https://platform.openai.com/docs/api-reference/batch/request-input), - and must be uploaded with the purpose `batch`. The file can contain up to 50,000 - requests, and can be up to 200 MB in size. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - output_expires_after: OutputExpiresAfter - """ - The expiration policy for the output and/or error file that are generated for a - batch. - """ - - -class OutputExpiresAfter(TypedDict, total=False): - """ - The expiration policy for the output and/or error file that are generated for a batch. - """ - - anchor: Required[Literal["created_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `created_at`. Note that the anchor is the file creation time, - not the time the batch is created. - """ - - seconds: Required[int] - """The number of seconds after the anchor time that the file will expire. - - Must be between 3600 (1 hour) and 2592000 (30 days). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch_error.py deleted file mode 100644 index 1cdd808..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_error.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["BatchError"] - - -class BatchError(BaseModel): - code: Optional[str] = None - """An error code identifying the error type.""" - - line: Optional[int] = None - """The line number of the input file where the error occurred, if applicable.""" - - message: Optional[str] = None - """A human-readable message providing more details about the error.""" - - param: Optional[str] = None - """The name of the parameter that caused the error, if applicable.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch_list_params.py deleted file mode 100644 index ef5e966..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_list_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["BatchListParams"] - - -class BatchListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_request_counts.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch_request_counts.py deleted file mode 100644 index 64a5707..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_request_counts.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["BatchRequestCounts"] - - -class BatchRequestCounts(BaseModel): - """The request counts for different statuses within the batch.""" - - completed: int - """Number of requests that have been completed successfully.""" - - failed: int - """Number of requests that have failed.""" - - total: int - """Total number of requests in the batch.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_usage.py b/backend/venv39/lib/python3.9/site-packages/openai/types/batch_usage.py deleted file mode 100644 index d68d711..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/batch_usage.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["BatchUsage", "InputTokensDetails", "OutputTokensDetails"] - - -class InputTokensDetails(BaseModel): - """A detailed breakdown of the input tokens.""" - - cached_tokens: int - """The number of tokens that were retrieved from the cache. - - [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching). - """ - - -class OutputTokensDetails(BaseModel): - """A detailed breakdown of the output tokens.""" - - reasoning_tokens: int - """The number of reasoning tokens.""" - - -class BatchUsage(BaseModel): - """ - Represents token usage details including input tokens, output tokens, a - breakdown of output tokens, and the total tokens used. Only populated on - batches created after September 7, 2025. - """ - - input_tokens: int - """The number of input tokens.""" - - input_tokens_details: InputTokensDetails - """A detailed breakdown of the input tokens.""" - - output_tokens: int - """The number of output tokens.""" - - output_tokens_details: OutputTokensDetails - """A detailed breakdown of the output tokens.""" - - total_tokens: int - """The total number of tokens used.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/__init__.py deleted file mode 100644 index deb2369..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .thread import Thread as Thread -from .assistant import Assistant as Assistant -from .function_tool import FunctionTool as FunctionTool -from .assistant_tool import AssistantTool as AssistantTool -from .thread_deleted import ThreadDeleted as ThreadDeleted -from .chatkit_workflow import ChatKitWorkflow as ChatKitWorkflow -from .file_search_tool import FileSearchTool as FileSearchTool -from .assistant_deleted import AssistantDeleted as AssistantDeleted -from .function_tool_param import FunctionToolParam as FunctionToolParam -from .assistant_tool_param import AssistantToolParam as AssistantToolParam -from .thread_create_params import ThreadCreateParams as ThreadCreateParams -from .thread_update_params import ThreadUpdateParams as ThreadUpdateParams -from .assistant_list_params import AssistantListParams as AssistantListParams -from .assistant_tool_choice import AssistantToolChoice as AssistantToolChoice -from .code_interpreter_tool import CodeInterpreterTool as CodeInterpreterTool -from .assistant_stream_event import AssistantStreamEvent as AssistantStreamEvent -from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam -from .assistant_create_params import AssistantCreateParams as AssistantCreateParams -from .assistant_update_params import AssistantUpdateParams as AssistantUpdateParams -from .assistant_tool_choice_param import AssistantToolChoiceParam as AssistantToolChoiceParam -from .code_interpreter_tool_param import CodeInterpreterToolParam as CodeInterpreterToolParam -from .assistant_tool_choice_option import AssistantToolChoiceOption as AssistantToolChoiceOption -from .thread_create_and_run_params import ThreadCreateAndRunParams as ThreadCreateAndRunParams -from .assistant_tool_choice_function import AssistantToolChoiceFunction as AssistantToolChoiceFunction -from .assistant_response_format_option import AssistantResponseFormatOption as AssistantResponseFormatOption -from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam as AssistantToolChoiceOptionParam -from .assistant_tool_choice_function_param import AssistantToolChoiceFunctionParam as AssistantToolChoiceFunctionParam -from .assistant_response_format_option_param import ( - AssistantResponseFormatOptionParam as AssistantResponseFormatOptionParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant.py deleted file mode 100644 index 61344f8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant.py +++ /dev/null @@ -1,141 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .assistant_tool import AssistantTool -from ..shared.metadata import Metadata -from .assistant_response_format_option import AssistantResponseFormatOption - -__all__ = ["Assistant", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] - - -class ToolResourcesCodeInterpreter(BaseModel): - file_ids: Optional[List[str]] = None - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter`` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearch(BaseModel): - vector_store_ids: Optional[List[str]] = None - """ - The ID of the - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this assistant. There can be a maximum of 1 vector store attached to - the assistant. - """ - - -class ToolResources(BaseModel): - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: Optional[ToolResourcesCodeInterpreter] = None - - file_search: Optional[ToolResourcesFileSearch] = None - - -class Assistant(BaseModel): - """Represents an `assistant` that can call the model and use tools.""" - - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the assistant was created.""" - - description: Optional[str] = None - """The description of the assistant. The maximum length is 512 characters.""" - - instructions: Optional[str] = None - """The system instructions that the assistant uses. - - The maximum length is 256,000 characters. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """ID of the model to use. - - You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - """ - - name: Optional[str] = None - """The name of the assistant. The maximum length is 256 characters.""" - - object: Literal["assistant"] - """The object type, which is always `assistant`.""" - - tools: List[AssistantTool] - """A list of tool enabled on the assistant. - - There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `file_search`, or `function`. - """ - - response_format: Optional[AssistantResponseFormatOption] = None - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - temperature: Optional[float] = None - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - """ - - tool_resources: Optional[ToolResources] = None - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - top_p: Optional[float] = None - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_create_params.py deleted file mode 100644 index 461d871..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_create_params.py +++ /dev/null @@ -1,231 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..shared.chat_model import ChatModel -from .assistant_tool_param import AssistantToolParam -from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from .assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = [ - "AssistantCreateParams", - "ToolResources", - "ToolResourcesCodeInterpreter", - "ToolResourcesFileSearch", - "ToolResourcesFileSearchVectorStore", - "ToolResourcesFileSearchVectorStoreChunkingStrategy", - "ToolResourcesFileSearchVectorStoreChunkingStrategyAuto", - "ToolResourcesFileSearchVectorStoreChunkingStrategyStatic", - "ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", -] - - -class AssistantCreateParams(TypedDict, total=False): - model: Required[Union[str, ChatModel]] - """ID of the model to use. - - You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - """ - - description: Optional[str] - """The description of the assistant. The maximum length is 512 characters.""" - - instructions: Optional[str] - """The system instructions that the assistant uses. - - The maximum length is 256,000 characters. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: Optional[str] - """The name of the assistant. The maximum length is 256 characters.""" - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: Optional[AssistantResponseFormatOptionParam] - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - """ - - tool_resources: Optional[ToolResources] - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - tools: Iterable[AssistantToolParam] - """A list of tool enabled on the assistant. - - There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `file_search`, or `function`. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - """ - - -class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): - """The default strategy. - - This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. - """ - - type: Required[Literal["auto"]] - """Always `auto`.""" - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): - chunk_overlap_tokens: Required[int] - """The number of tokens that overlap between chunks. The default value is `400`. - - Note that the overlap must not exceed half of `max_chunk_size_tokens`. - """ - - max_chunk_size_tokens: Required[int] - """The maximum number of tokens in each chunk. - - The default value is `800`. The minimum value is `100` and the maximum value is - `4096`. - """ - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): - static: Required[ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] - - type: Required[Literal["static"]] - """Always `static`.""" - - -ToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ - ToolResourcesFileSearchVectorStoreChunkingStrategyAuto, ToolResourcesFileSearchVectorStoreChunkingStrategyStatic -] - - -class ToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: ToolResourcesFileSearchVectorStoreChunkingStrategy - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. - """ - - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - The - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this assistant. There can be a maximum of 1 vector store attached to - the assistant. - """ - - vector_stores: Iterable[ToolResourcesFileSearchVectorStore] - """ - A helper to create a - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - with file_ids and attach it to this assistant. There can be a maximum of 1 - vector store attached to the assistant. - """ - - -class ToolResources(TypedDict, total=False): - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ToolResourcesCodeInterpreter - - file_search: ToolResourcesFileSearch diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_deleted.py deleted file mode 100644 index 3be40cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["AssistantDeleted"] - - -class AssistantDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["assistant.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_list_params.py deleted file mode 100644 index 834ffbc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_list_params.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["AssistantListParams"] - - -class AssistantListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option.py deleted file mode 100644 index 6f06a34..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..shared.response_format_text import ResponseFormatText -from ..shared.response_format_json_object import ResponseFormatJSONObject -from ..shared.response_format_json_schema import ResponseFormatJSONSchema - -__all__ = ["AssistantResponseFormatOption"] - -AssistantResponseFormatOption: TypeAlias = Union[ - Literal["auto"], ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option_param.py deleted file mode 100644 index 5e724a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_response_format_option_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..shared_params.response_format_text import ResponseFormatText -from ..shared_params.response_format_json_object import ResponseFormatJSONObject -from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema - -__all__ = ["AssistantResponseFormatOptionParam"] - -AssistantResponseFormatOptionParam: TypeAlias = Union[ - Literal["auto"], ResponseFormatText, ResponseFormatJSONObject, ResponseFormatJSONSchema -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_stream_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_stream_event.py deleted file mode 100644 index 87620a1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_stream_event.py +++ /dev/null @@ -1,390 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .thread import Thread -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .threads.run import Run -from .threads.message import Message -from ..shared.error_object import ErrorObject -from .threads.runs.run_step import RunStep -from .threads.message_delta_event import MessageDeltaEvent -from .threads.runs.run_step_delta_event import RunStepDeltaEvent - -__all__ = [ - "AssistantStreamEvent", - "ThreadCreated", - "ThreadRunCreated", - "ThreadRunQueued", - "ThreadRunInProgress", - "ThreadRunRequiresAction", - "ThreadRunCompleted", - "ThreadRunIncomplete", - "ThreadRunFailed", - "ThreadRunCancelling", - "ThreadRunCancelled", - "ThreadRunExpired", - "ThreadRunStepCreated", - "ThreadRunStepInProgress", - "ThreadRunStepDelta", - "ThreadRunStepCompleted", - "ThreadRunStepFailed", - "ThreadRunStepCancelled", - "ThreadRunStepExpired", - "ThreadMessageCreated", - "ThreadMessageInProgress", - "ThreadMessageDelta", - "ThreadMessageCompleted", - "ThreadMessageIncomplete", - "ErrorEvent", -] - - -class ThreadCreated(BaseModel): - """ - Occurs when a new [thread](https://platform.openai.com/docs/api-reference/threads/object) is created. - """ - - data: Thread - """ - Represents a thread that contains - [messages](https://platform.openai.com/docs/api-reference/messages). - """ - - event: Literal["thread.created"] - - enabled: Optional[bool] = None - """Whether to enable input audio transcription.""" - - -class ThreadRunCreated(BaseModel): - """ - Occurs when a new [run](https://platform.openai.com/docs/api-reference/runs/object) is created. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.created"] - - -class ThreadRunQueued(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `queued` status. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.queued"] - - -class ThreadRunInProgress(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to an `in_progress` status. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.in_progress"] - - -class ThreadRunRequiresAction(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `requires_action` status. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.requires_action"] - - -class ThreadRunCompleted(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) is completed. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.completed"] - - -class ThreadRunIncomplete(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) ends with status `incomplete`. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.incomplete"] - - -class ThreadRunFailed(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) fails. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.failed"] - - -class ThreadRunCancelling(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) moves to a `cancelling` status. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.cancelling"] - - -class ThreadRunCancelled(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) is cancelled. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.cancelled"] - - -class ThreadRunExpired(BaseModel): - """ - Occurs when a [run](https://platform.openai.com/docs/api-reference/runs/object) expires. - """ - - data: Run - """ - Represents an execution run on a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.run.expired"] - - -class ThreadRunStepCreated(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is created. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.created"] - - -class ThreadRunStepInProgress(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) moves to an `in_progress` state. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.in_progress"] - - -class ThreadRunStepDelta(BaseModel): - """ - Occurs when parts of a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) are being streamed. - """ - - data: RunStepDeltaEvent - """Represents a run step delta i.e. - - any changed fields on a run step during streaming. - """ - - event: Literal["thread.run.step.delta"] - - -class ThreadRunStepCompleted(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is completed. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.completed"] - - -class ThreadRunStepFailed(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) fails. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.failed"] - - -class ThreadRunStepCancelled(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) is cancelled. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.cancelled"] - - -class ThreadRunStepExpired(BaseModel): - """ - Occurs when a [run step](https://platform.openai.com/docs/api-reference/run-steps/step-object) expires. - """ - - data: RunStep - """Represents a step in execution of a run.""" - - event: Literal["thread.run.step.expired"] - - -class ThreadMessageCreated(BaseModel): - """ - Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) is created. - """ - - data: Message - """ - Represents a message within a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.message.created"] - - -class ThreadMessageInProgress(BaseModel): - """ - Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) moves to an `in_progress` state. - """ - - data: Message - """ - Represents a message within a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.message.in_progress"] - - -class ThreadMessageDelta(BaseModel): - """ - Occurs when parts of a [Message](https://platform.openai.com/docs/api-reference/messages/object) are being streamed. - """ - - data: MessageDeltaEvent - """Represents a message delta i.e. - - any changed fields on a message during streaming. - """ - - event: Literal["thread.message.delta"] - - -class ThreadMessageCompleted(BaseModel): - """ - Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) is completed. - """ - - data: Message - """ - Represents a message within a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.message.completed"] - - -class ThreadMessageIncomplete(BaseModel): - """ - Occurs when a [message](https://platform.openai.com/docs/api-reference/messages/object) ends before it is completed. - """ - - data: Message - """ - Represents a message within a - [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - event: Literal["thread.message.incomplete"] - - -class ErrorEvent(BaseModel): - """ - Occurs when an [error](https://platform.openai.com/docs/guides/error-codes#api-errors) occurs. This can happen due to an internal server error or a timeout. - """ - - data: ErrorObject - - event: Literal["error"] - - -AssistantStreamEvent: TypeAlias = Annotated[ - Union[ - ThreadCreated, - ThreadRunCreated, - ThreadRunQueued, - ThreadRunInProgress, - ThreadRunRequiresAction, - ThreadRunCompleted, - ThreadRunIncomplete, - ThreadRunFailed, - ThreadRunCancelling, - ThreadRunCancelled, - ThreadRunExpired, - ThreadRunStepCreated, - ThreadRunStepInProgress, - ThreadRunStepDelta, - ThreadRunStepCompleted, - ThreadRunStepFailed, - ThreadRunStepCancelled, - ThreadRunStepExpired, - ThreadMessageCreated, - ThreadMessageInProgress, - ThreadMessageDelta, - ThreadMessageCompleted, - ThreadMessageIncomplete, - ErrorEvent, - ], - PropertyInfo(discriminator="event"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool.py deleted file mode 100644 index 1bde685..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .function_tool import FunctionTool -from .file_search_tool import FileSearchTool -from .code_interpreter_tool import CodeInterpreterTool - -__all__ = ["AssistantTool"] - -AssistantTool: TypeAlias = Annotated[ - Union[CodeInterpreterTool, FileSearchTool, FunctionTool], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice.py deleted file mode 100644 index cabded0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .assistant_tool_choice_function import AssistantToolChoiceFunction - -__all__ = ["AssistantToolChoice"] - - -class AssistantToolChoice(BaseModel): - """Specifies a tool the model should use. - - Use to force the model to call a specific tool. - """ - - type: Literal["function", "code_interpreter", "file_search"] - """The type of the tool. If type is `function`, the function name must be set""" - - function: Optional[AssistantToolChoiceFunction] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function.py deleted file mode 100644 index 87f3831..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["AssistantToolChoiceFunction"] - - -class AssistantToolChoiceFunction(BaseModel): - name: str - """The name of the function to call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function_param.py deleted file mode 100644 index 428857d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_function_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["AssistantToolChoiceFunctionParam"] - - -class AssistantToolChoiceFunctionParam(TypedDict, total=False): - name: Required[str] - """The name of the function to call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option.py deleted file mode 100644 index e57c327..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .assistant_tool_choice import AssistantToolChoice - -__all__ = ["AssistantToolChoiceOption"] - -AssistantToolChoiceOption: TypeAlias = Union[Literal["none", "auto", "required"], AssistantToolChoice] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option_param.py deleted file mode 100644 index cc0053d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_option_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .assistant_tool_choice_param import AssistantToolChoiceParam - -__all__ = ["AssistantToolChoiceOptionParam"] - -AssistantToolChoiceOptionParam: TypeAlias = Union[Literal["none", "auto", "required"], AssistantToolChoiceParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_param.py deleted file mode 100644 index 05916bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_choice_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .assistant_tool_choice_function_param import AssistantToolChoiceFunctionParam - -__all__ = ["AssistantToolChoiceParam"] - - -class AssistantToolChoiceParam(TypedDict, total=False): - """Specifies a tool the model should use. - - Use to force the model to call a specific tool. - """ - - type: Required[Literal["function", "code_interpreter", "file_search"]] - """The type of the tool. If type is `function`, the function name must be set""" - - function: AssistantToolChoiceFunctionParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_param.py deleted file mode 100644 index 321c4b1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_tool_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .function_tool_param import FunctionToolParam -from .file_search_tool_param import FileSearchToolParam -from .code_interpreter_tool_param import CodeInterpreterToolParam - -__all__ = ["AssistantToolParam"] - -AssistantToolParam: TypeAlias = Union[CodeInterpreterToolParam, FileSearchToolParam, FunctionToolParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_update_params.py deleted file mode 100644 index 7896fcd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/assistant_update_params.py +++ /dev/null @@ -1,197 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, TypedDict - -from ..._types import SequenceNotStr -from .assistant_tool_param import AssistantToolParam -from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from .assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = ["AssistantUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] - - -class AssistantUpdateParams(TypedDict, total=False): - description: Optional[str] - """The description of the assistant. The maximum length is 512 characters.""" - - instructions: Optional[str] - """The system instructions that the assistant uses. - - The maximum length is 256,000 characters. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Union[ - str, - Literal[ - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4.5-preview", - "gpt-4.5-preview-2025-02-27", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - ], - ] - """ID of the model to use. - - You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - """ - - name: Optional[str] - """The name of the assistant. The maximum length is 256 characters.""" - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: Optional[AssistantResponseFormatOptionParam] - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - """ - - tool_resources: Optional[ToolResources] - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - tools: Iterable[AssistantToolParam] - """A list of tool enabled on the assistant. - - There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `file_search`, or `function`. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - """ - - -class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - Overrides the list of - [file](https://platform.openai.com/docs/api-reference/files) IDs made available - to the `code_interpreter` tool. There can be a maximum of 20 files associated - with the tool. - """ - - -class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - Overrides the - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this assistant. There can be a maximum of 1 vector store attached to - the assistant. - """ - - -class ToolResources(TypedDict, total=False): - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ToolResourcesCodeInterpreter - - file_search: ToolResourcesFileSearch diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chat/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chat/__init__.py deleted file mode 100644 index f8ee8b1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chat/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/__init__.py deleted file mode 100644 index eafed9d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .chat_session import ChatSession as ChatSession -from .chatkit_thread import ChatKitThread as ChatKitThread -from .chatkit_attachment import ChatKitAttachment as ChatKitAttachment -from .thread_list_params import ThreadListParams as ThreadListParams -from .chat_session_status import ChatSessionStatus as ChatSessionStatus -from .chatkit_widget_item import ChatKitWidgetItem as ChatKitWidgetItem -from .chat_session_history import ChatSessionHistory as ChatSessionHistory -from .session_create_params import SessionCreateParams as SessionCreateParams -from .thread_delete_response import ThreadDeleteResponse as ThreadDeleteResponse -from .chat_session_file_upload import ChatSessionFileUpload as ChatSessionFileUpload -from .chat_session_rate_limits import ChatSessionRateLimits as ChatSessionRateLimits -from .chatkit_thread_item_list import ChatKitThreadItemList as ChatKitThreadItemList -from .thread_list_items_params import ThreadListItemsParams as ThreadListItemsParams -from .chat_session_workflow_param import ChatSessionWorkflowParam as ChatSessionWorkflowParam -from .chatkit_response_output_text import ChatKitResponseOutputText as ChatKitResponseOutputText -from .chat_session_rate_limits_param import ChatSessionRateLimitsParam as ChatSessionRateLimitsParam -from .chat_session_expires_after_param import ChatSessionExpiresAfterParam as ChatSessionExpiresAfterParam -from .chatkit_thread_user_message_item import ChatKitThreadUserMessageItem as ChatKitThreadUserMessageItem -from .chat_session_chatkit_configuration import ChatSessionChatKitConfiguration as ChatSessionChatKitConfiguration -from .chat_session_automatic_thread_titling import ( - ChatSessionAutomaticThreadTitling as ChatSessionAutomaticThreadTitling, -) -from .chatkit_thread_assistant_message_item import ( - ChatKitThreadAssistantMessageItem as ChatKitThreadAssistantMessageItem, -) -from .chat_session_chatkit_configuration_param import ( - ChatSessionChatKitConfigurationParam as ChatSessionChatKitConfigurationParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session.py deleted file mode 100644 index 9db9fc9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from ..chatkit_workflow import ChatKitWorkflow -from .chat_session_status import ChatSessionStatus -from .chat_session_rate_limits import ChatSessionRateLimits -from .chat_session_chatkit_configuration import ChatSessionChatKitConfiguration - -__all__ = ["ChatSession"] - - -class ChatSession(BaseModel): - """Represents a ChatKit session and its resolved configuration.""" - - id: str - """Identifier for the ChatKit session.""" - - chatkit_configuration: ChatSessionChatKitConfiguration - """Resolved ChatKit feature configuration for the session.""" - - client_secret: str - """Ephemeral client secret that authenticates session requests.""" - - expires_at: int - """Unix timestamp (in seconds) for when the session expires.""" - - max_requests_per_1_minute: int - """Convenience copy of the per-minute request limit.""" - - object: Literal["chatkit.session"] - """Type discriminator that is always `chatkit.session`.""" - - rate_limits: ChatSessionRateLimits - """Resolved rate limit values.""" - - status: ChatSessionStatus - """Current lifecycle state of the session.""" - - user: str - """User identifier associated with the session.""" - - workflow: ChatKitWorkflow - """Workflow metadata for the session.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py deleted file mode 100644 index 1d95255..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_automatic_thread_titling.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["ChatSessionAutomaticThreadTitling"] - - -class ChatSessionAutomaticThreadTitling(BaseModel): - """Automatic thread title preferences for the session.""" - - enabled: bool - """Whether automatic thread titling is enabled.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration.py deleted file mode 100644 index f9fa0ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from .chat_session_history import ChatSessionHistory -from .chat_session_file_upload import ChatSessionFileUpload -from .chat_session_automatic_thread_titling import ChatSessionAutomaticThreadTitling - -__all__ = ["ChatSessionChatKitConfiguration"] - - -class ChatSessionChatKitConfiguration(BaseModel): - """ChatKit configuration for the session.""" - - automatic_thread_titling: ChatSessionAutomaticThreadTitling - """Automatic thread titling preferences.""" - - file_upload: ChatSessionFileUpload - """Upload settings for the session.""" - - history: ChatSessionHistory - """History retention configuration.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py deleted file mode 100644 index 834de71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_chatkit_configuration_param.py +++ /dev/null @@ -1,76 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["ChatSessionChatKitConfigurationParam", "AutomaticThreadTitling", "FileUpload", "History"] - - -class AutomaticThreadTitling(TypedDict, total=False): - """Configuration for automatic thread titling. - - When omitted, automatic thread titling is enabled by default. - """ - - enabled: bool - """Enable automatic thread title generation. Defaults to true.""" - - -class FileUpload(TypedDict, total=False): - """Configuration for upload enablement and limits. - - When omitted, uploads are disabled by default (max_files 10, max_file_size 512 MB). - """ - - enabled: bool - """Enable uploads for this session. Defaults to false.""" - - max_file_size: int - """Maximum size in megabytes for each uploaded file. - - Defaults to 512 MB, which is the maximum allowable size. - """ - - max_files: int - """Maximum number of files that can be uploaded to the session. Defaults to 10.""" - - -class History(TypedDict, total=False): - """Configuration for chat history retention. - - When omitted, history is enabled by default with no limit on recent_threads (null). - """ - - enabled: bool - """Enables chat users to access previous ChatKit threads. Defaults to true.""" - - recent_threads: int - """Number of recent ChatKit threads users have access to. - - Defaults to unlimited when unset. - """ - - -class ChatSessionChatKitConfigurationParam(TypedDict, total=False): - """Optional per-session configuration settings for ChatKit behavior.""" - - automatic_thread_titling: AutomaticThreadTitling - """Configuration for automatic thread titling. - - When omitted, automatic thread titling is enabled by default. - """ - - file_upload: FileUpload - """Configuration for upload enablement and limits. - - When omitted, uploads are disabled by default (max_files 10, max_file_size 512 - MB). - """ - - history: History - """Configuration for chat history retention. - - When omitted, history is enabled by default with no limit on recent_threads - (null). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_expires_after_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_expires_after_param.py deleted file mode 100644 index c1de8a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_expires_after_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatSessionExpiresAfterParam"] - - -class ChatSessionExpiresAfterParam(TypedDict, total=False): - """Controls when the session expires relative to an anchor timestamp.""" - - anchor: Required[Literal["created_at"]] - """Base timestamp used to calculate expiration. Currently fixed to `created_at`.""" - - seconds: Required[int] - """Number of seconds after the anchor when the session expires.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_file_upload.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_file_upload.py deleted file mode 100644 index 0275859..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_file_upload.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ...._models import BaseModel - -__all__ = ["ChatSessionFileUpload"] - - -class ChatSessionFileUpload(BaseModel): - """Upload permissions and limits applied to the session.""" - - enabled: bool - """Indicates if uploads are enabled for the session.""" - - max_file_size: Optional[int] = None - """Maximum upload size in megabytes.""" - - max_files: Optional[int] = None - """Maximum number of uploads allowed during the session.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_history.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_history.py deleted file mode 100644 index 5469000..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_history.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ...._models import BaseModel - -__all__ = ["ChatSessionHistory"] - - -class ChatSessionHistory(BaseModel): - """History retention preferences returned for the session.""" - - enabled: bool - """Indicates if chat history is persisted for the session.""" - - recent_threads: Optional[int] = None - """Number of prior threads surfaced in history views. - - Defaults to null when all history is retained. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits.py deleted file mode 100644 index 7c5bd94..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["ChatSessionRateLimits"] - - -class ChatSessionRateLimits(BaseModel): - """Active per-minute request limit for the session.""" - - max_requests_per_1_minute: int - """Maximum allowed requests per one-minute window.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits_param.py deleted file mode 100644 index 578f20b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_rate_limits_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["ChatSessionRateLimitsParam"] - - -class ChatSessionRateLimitsParam(TypedDict, total=False): - """Controls request rate limits for the session.""" - - max_requests_per_1_minute: int - """Maximum number of requests allowed per minute for the session. Defaults to 10.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_status.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_status.py deleted file mode 100644 index a483099..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ChatSessionStatus"] - -ChatSessionStatus: TypeAlias = Literal["active", "expired", "cancelled"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_workflow_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_workflow_param.py deleted file mode 100644 index abf52de..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chat_session_workflow_param.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union -from typing_extensions import Required, TypedDict - -__all__ = ["ChatSessionWorkflowParam", "Tracing"] - - -class Tracing(TypedDict, total=False): - """Optional tracing overrides for the workflow invocation. - - When omitted, tracing is enabled by default. - """ - - enabled: bool - """Whether tracing is enabled during the session. Defaults to true.""" - - -class ChatSessionWorkflowParam(TypedDict, total=False): - """Workflow reference and overrides applied to the chat session.""" - - id: Required[str] - """Identifier for the workflow invoked by the session.""" - - state_variables: Dict[str, Union[str, bool, float]] - """State variables forwarded to the workflow. - - Keys may be up to 64 characters, values must be primitive types, and the map - defaults to an empty object. - """ - - tracing: Tracing - """Optional tracing overrides for the workflow invocation. - - When omitted, tracing is enabled by default. - """ - - version: str - """Specific workflow version to run. Defaults to the latest deployed version.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_attachment.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_attachment.py deleted file mode 100644 index 7750925..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_attachment.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ChatKitAttachment"] - - -class ChatKitAttachment(BaseModel): - """Attachment metadata included on thread items.""" - - id: str - """Identifier for the attachment.""" - - mime_type: str - """MIME type of the attachment.""" - - name: str - """Original display name for the attachment.""" - - preview_url: Optional[str] = None - """Preview URL for rendering the attachment inline.""" - - type: Literal["image", "file"] - """Attachment discriminator.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_response_output_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_response_output_text.py deleted file mode 100644 index 1348fed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_response_output_text.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel - -__all__ = [ - "ChatKitResponseOutputText", - "Annotation", - "AnnotationFile", - "AnnotationFileSource", - "AnnotationURL", - "AnnotationURLSource", -] - - -class AnnotationFileSource(BaseModel): - """File attachment referenced by the annotation.""" - - filename: str - """Filename referenced by the annotation.""" - - type: Literal["file"] - """Type discriminator that is always `file`.""" - - -class AnnotationFile(BaseModel): - """Annotation that references an uploaded file.""" - - source: AnnotationFileSource - """File attachment referenced by the annotation.""" - - type: Literal["file"] - """Type discriminator that is always `file` for this annotation.""" - - -class AnnotationURLSource(BaseModel): - """URL referenced by the annotation.""" - - type: Literal["url"] - """Type discriminator that is always `url`.""" - - url: str - """URL referenced by the annotation.""" - - -class AnnotationURL(BaseModel): - """Annotation that references a URL.""" - - source: AnnotationURLSource - """URL referenced by the annotation.""" - - type: Literal["url"] - """Type discriminator that is always `url` for this annotation.""" - - -Annotation: TypeAlias = Annotated[Union[AnnotationFile, AnnotationURL], PropertyInfo(discriminator="type")] - - -class ChatKitResponseOutputText(BaseModel): - """Assistant response text accompanied by optional annotations.""" - - annotations: List[Annotation] - """Ordered list of annotations attached to the response text.""" - - text: str - """Assistant generated text.""" - - type: Literal["output_text"] - """Type discriminator that is always `output_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread.py deleted file mode 100644 index 3207523..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread.py +++ /dev/null @@ -1,64 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel - -__all__ = ["ChatKitThread", "Status", "StatusActive", "StatusLocked", "StatusClosed"] - - -class StatusActive(BaseModel): - """Indicates that a thread is active.""" - - type: Literal["active"] - """Status discriminator that is always `active`.""" - - -class StatusLocked(BaseModel): - """Indicates that a thread is locked and cannot accept new input.""" - - reason: Optional[str] = None - """Reason that the thread was locked. Defaults to null when no reason is recorded.""" - - type: Literal["locked"] - """Status discriminator that is always `locked`.""" - - -class StatusClosed(BaseModel): - """Indicates that a thread has been closed.""" - - reason: Optional[str] = None - """Reason that the thread was closed. Defaults to null when no reason is recorded.""" - - type: Literal["closed"] - """Status discriminator that is always `closed`.""" - - -Status: TypeAlias = Annotated[Union[StatusActive, StatusLocked, StatusClosed], PropertyInfo(discriminator="type")] - - -class ChatKitThread(BaseModel): - """Represents a ChatKit thread and its current status.""" - - id: str - """Identifier of the thread.""" - - created_at: int - """Unix timestamp (in seconds) for when the thread was created.""" - - object: Literal["chatkit.thread"] - """Type discriminator that is always `chatkit.thread`.""" - - status: Status - """Current status for the thread. Defaults to `active` for newly created threads.""" - - title: Optional[str] = None - """Optional human-readable title for the thread. - - Defaults to null when no title has been generated. - """ - - user: str - """Free-form string that identifies your end user who owns the thread.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py deleted file mode 100644 index 337f53a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_assistant_message_item.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from ...._models import BaseModel -from .chatkit_response_output_text import ChatKitResponseOutputText - -__all__ = ["ChatKitThreadAssistantMessageItem"] - - -class ChatKitThreadAssistantMessageItem(BaseModel): - """Assistant-authored message within a thread.""" - - id: str - """Identifier of the thread item.""" - - content: List[ChatKitResponseOutputText] - """Ordered assistant response segments.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.assistant_message"] - """Type discriminator that is always `chatkit.assistant_message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_item_list.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_item_list.py deleted file mode 100644 index 049ca54..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_item_list.py +++ /dev/null @@ -1,154 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel -from .chatkit_widget_item import ChatKitWidgetItem -from .chatkit_thread_user_message_item import ChatKitThreadUserMessageItem -from .chatkit_thread_assistant_message_item import ChatKitThreadAssistantMessageItem - -__all__ = [ - "ChatKitThreadItemList", - "Data", - "DataChatKitClientToolCall", - "DataChatKitTask", - "DataChatKitTaskGroup", - "DataChatKitTaskGroupTask", -] - - -class DataChatKitClientToolCall(BaseModel): - """Record of a client side tool invocation initiated by the assistant.""" - - id: str - """Identifier of the thread item.""" - - arguments: str - """JSON-encoded arguments that were sent to the tool.""" - - call_id: str - """Identifier for the client tool call.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - name: str - """Tool name that was invoked.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - output: Optional[str] = None - """JSON-encoded output captured from the tool. - - Defaults to null while execution is in progress. - """ - - status: Literal["in_progress", "completed"] - """Execution status for the tool call.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.client_tool_call"] - """Type discriminator that is always `chatkit.client_tool_call`.""" - - -class DataChatKitTask(BaseModel): - """Task emitted by the workflow to show progress and status updates.""" - - id: str - """Identifier of the thread item.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - heading: Optional[str] = None - """Optional heading for the task. Defaults to null when not provided.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - summary: Optional[str] = None - """Optional summary that describes the task. Defaults to null when omitted.""" - - task_type: Literal["custom", "thought"] - """Subtype for the task.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.task"] - """Type discriminator that is always `chatkit.task`.""" - - -class DataChatKitTaskGroupTask(BaseModel): - """Task entry that appears within a TaskGroup.""" - - heading: Optional[str] = None - """Optional heading for the grouped task. Defaults to null when not provided.""" - - summary: Optional[str] = None - """Optional summary that describes the grouped task. - - Defaults to null when omitted. - """ - - type: Literal["custom", "thought"] - """Subtype for the grouped task.""" - - -class DataChatKitTaskGroup(BaseModel): - """Collection of workflow tasks grouped together in the thread.""" - - id: str - """Identifier of the thread item.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - tasks: List[DataChatKitTaskGroupTask] - """Tasks included in the group.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.task_group"] - """Type discriminator that is always `chatkit.task_group`.""" - - -Data: TypeAlias = Annotated[ - Union[ - ChatKitThreadUserMessageItem, - ChatKitThreadAssistantMessageItem, - ChatKitWidgetItem, - DataChatKitClientToolCall, - DataChatKitTask, - DataChatKitTaskGroup, - ], - PropertyInfo(discriminator="type"), -] - - -class ChatKitThreadItemList(BaseModel): - """A paginated list of thread items rendered for the ChatKit API.""" - - data: List[Data] - """A list of items""" - - first_id: Optional[str] = None - """The ID of the first item in the list.""" - - has_more: bool - """Whether there are more items available.""" - - last_id: Optional[str] = None - """The ID of the last item in the list.""" - - object: Literal["list"] - """The type of object returned, must be `list`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_user_message_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_user_message_item.py deleted file mode 100644 index d7552c4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_thread_user_message_item.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel -from .chatkit_attachment import ChatKitAttachment - -__all__ = [ - "ChatKitThreadUserMessageItem", - "Content", - "ContentInputText", - "ContentQuotedText", - "InferenceOptions", - "InferenceOptionsToolChoice", -] - - -class ContentInputText(BaseModel): - """Text block that a user contributed to the thread.""" - - text: str - """Plain-text content supplied by the user.""" - - type: Literal["input_text"] - """Type discriminator that is always `input_text`.""" - - -class ContentQuotedText(BaseModel): - """Quoted snippet that the user referenced in their message.""" - - text: str - """Quoted text content.""" - - type: Literal["quoted_text"] - """Type discriminator that is always `quoted_text`.""" - - -Content: TypeAlias = Annotated[Union[ContentInputText, ContentQuotedText], PropertyInfo(discriminator="type")] - - -class InferenceOptionsToolChoice(BaseModel): - """Preferred tool to invoke. Defaults to null when ChatKit should auto-select.""" - - id: str - """Identifier of the requested tool.""" - - -class InferenceOptions(BaseModel): - """Inference overrides applied to the message. Defaults to null when unset.""" - - model: Optional[str] = None - """Model name that generated the response. - - Defaults to null when using the session default. - """ - - tool_choice: Optional[InferenceOptionsToolChoice] = None - """Preferred tool to invoke. Defaults to null when ChatKit should auto-select.""" - - -class ChatKitThreadUserMessageItem(BaseModel): - """User-authored messages within a thread.""" - - id: str - """Identifier of the thread item.""" - - attachments: List[ChatKitAttachment] - """Attachments associated with the user message. Defaults to an empty list.""" - - content: List[Content] - """Ordered content elements supplied by the user.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - inference_options: Optional[InferenceOptions] = None - """Inference overrides applied to the message. Defaults to null when unset.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.user_message"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_widget_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_widget_item.py deleted file mode 100644 index a269c73..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/chatkit_widget_item.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ChatKitWidgetItem"] - - -class ChatKitWidgetItem(BaseModel): - """Thread item that renders a widget payload.""" - - id: str - """Identifier of the thread item.""" - - created_at: int - """Unix timestamp (in seconds) for when the item was created.""" - - object: Literal["chatkit.thread_item"] - """Type discriminator that is always `chatkit.thread_item`.""" - - thread_id: str - """Identifier of the parent thread.""" - - type: Literal["chatkit.widget"] - """Type discriminator that is always `chatkit.widget`.""" - - widget: str - """Serialized widget payload rendered in the UI.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/session_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/session_create_params.py deleted file mode 100644 index 1803d18..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/session_create_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .chat_session_workflow_param import ChatSessionWorkflowParam -from .chat_session_rate_limits_param import ChatSessionRateLimitsParam -from .chat_session_expires_after_param import ChatSessionExpiresAfterParam -from .chat_session_chatkit_configuration_param import ChatSessionChatKitConfigurationParam - -__all__ = ["SessionCreateParams"] - - -class SessionCreateParams(TypedDict, total=False): - user: Required[str] - """ - A free-form string that identifies your end user; ensures this Session can - access other objects that have the same `user` scope. - """ - - workflow: Required[ChatSessionWorkflowParam] - """Workflow that powers the session.""" - - chatkit_configuration: ChatSessionChatKitConfigurationParam - """Optional overrides for ChatKit runtime configuration features""" - - expires_after: ChatSessionExpiresAfterParam - """Optional override for session expiration timing in seconds from creation. - - Defaults to 10 minutes. - """ - - rate_limits: ChatSessionRateLimitsParam - """Optional override for per-minute request limits. When omitted, defaults to 10.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_delete_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_delete_response.py deleted file mode 100644 index 45b686b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_delete_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ThreadDeleteResponse"] - - -class ThreadDeleteResponse(BaseModel): - """Confirmation payload returned after deleting a thread.""" - - id: str - """Identifier of the deleted thread.""" - - deleted: bool - """Indicates that the thread has been deleted.""" - - object: Literal["chatkit.thread.deleted"] - """Type discriminator that is always `chatkit.thread.deleted`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_items_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_items_params.py deleted file mode 100644 index 95c959d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_items_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ThreadListItemsParams"] - - -class ThreadListItemsParams(TypedDict, total=False): - after: str - """List items created after this thread item ID. - - Defaults to null for the first page. - """ - - before: str - """List items created before this thread item ID. - - Defaults to null for the newest results. - """ - - limit: int - """Maximum number of thread items to return. Defaults to 20.""" - - order: Literal["asc", "desc"] - """Sort order for results by creation time. Defaults to `desc`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_params.py deleted file mode 100644 index bb759c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit/thread_list_params.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ThreadListParams"] - - -class ThreadListParams(TypedDict, total=False): - after: str - """List items created after this thread item ID. - - Defaults to null for the first page. - """ - - before: str - """List items created before this thread item ID. - - Defaults to null for the newest results. - """ - - limit: int - """Maximum number of thread items to return. Defaults to 20.""" - - order: Literal["asc", "desc"] - """Sort order for results by creation time. Defaults to `desc`.""" - - user: str - """Filter threads that belong to this user identifier. - - Defaults to null to return all users. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit_workflow.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit_workflow.py deleted file mode 100644 index b6f5b55..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/chatkit_workflow.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Union, Optional - -from ..._models import BaseModel - -__all__ = ["ChatKitWorkflow", "Tracing"] - - -class Tracing(BaseModel): - """Tracing settings applied to the workflow.""" - - enabled: bool - """Indicates whether tracing is enabled.""" - - -class ChatKitWorkflow(BaseModel): - """Workflow metadata and state returned for the session.""" - - id: str - """Identifier of the workflow backing the session.""" - - state_variables: Optional[Dict[str, Union[str, bool, float]]] = None - """State variable key-value pairs applied when invoking the workflow. - - Defaults to null when no overrides were provided. - """ - - tracing: Tracing - """Tracing settings applied to the workflow.""" - - version: Optional[str] = None - """Specific workflow version used for the session. - - Defaults to null when using the latest deployment. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool.py deleted file mode 100644 index 17ab3de..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["CodeInterpreterTool"] - - -class CodeInterpreterTool(BaseModel): - type: Literal["code_interpreter"] - """The type of tool being defined: `code_interpreter`""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool_param.py deleted file mode 100644 index 4f6916d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/code_interpreter_tool_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CodeInterpreterToolParam"] - - -class CodeInterpreterToolParam(TypedDict, total=False): - type: Required[Literal["code_interpreter"]] - """The type of tool being defined: `code_interpreter`""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool.py deleted file mode 100644 index 9e33249..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool.py +++ /dev/null @@ -1,64 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FileSearchTool", "FileSearch", "FileSearchRankingOptions"] - - -class FileSearchRankingOptions(BaseModel): - """The ranking options for the file search. - - If not specified, the file search tool will use the `auto` ranker and a score_threshold of 0. - - See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. - """ - - score_threshold: float - """The score threshold for the file search. - - All values must be a floating point number between 0 and 1. - """ - - ranker: Optional[Literal["auto", "default_2024_08_21"]] = None - """The ranker to use for the file search. - - If not specified will use the `auto` ranker. - """ - - -class FileSearch(BaseModel): - """Overrides for the file search tool.""" - - max_num_results: Optional[int] = None - """The maximum number of results the file search tool should output. - - The default is 20 for `gpt-4*` models and 5 for `gpt-3.5-turbo`. This number - should be between 1 and 50 inclusive. - - Note that the file search tool may output fewer than `max_num_results` results. - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - ranking_options: Optional[FileSearchRankingOptions] = None - """The ranking options for the file search. - - If not specified, the file search tool will use the `auto` ranker and a - score_threshold of 0. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - -class FileSearchTool(BaseModel): - type: Literal["file_search"] - """The type of tool being defined: `file_search`""" - - file_search: Optional[FileSearch] = None - """Overrides for the file search tool.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool_param.py deleted file mode 100644 index 9906b4b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/file_search_tool_param.py +++ /dev/null @@ -1,63 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FileSearchToolParam", "FileSearch", "FileSearchRankingOptions"] - - -class FileSearchRankingOptions(TypedDict, total=False): - """The ranking options for the file search. - - If not specified, the file search tool will use the `auto` ranker and a score_threshold of 0. - - See the [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) for more information. - """ - - score_threshold: Required[float] - """The score threshold for the file search. - - All values must be a floating point number between 0 and 1. - """ - - ranker: Literal["auto", "default_2024_08_21"] - """The ranker to use for the file search. - - If not specified will use the `auto` ranker. - """ - - -class FileSearch(TypedDict, total=False): - """Overrides for the file search tool.""" - - max_num_results: int - """The maximum number of results the file search tool should output. - - The default is 20 for `gpt-4*` models and 5 for `gpt-3.5-turbo`. This number - should be between 1 and 50 inclusive. - - Note that the file search tool may output fewer than `max_num_results` results. - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - ranking_options: FileSearchRankingOptions - """The ranking options for the file search. - - If not specified, the file search tool will use the `auto` ranker and a - score_threshold of 0. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - -class FileSearchToolParam(TypedDict, total=False): - type: Required[Literal["file_search"]] - """The type of tool being defined: `file_search`""" - - file_search: FileSearch - """Overrides for the file search tool.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool.py deleted file mode 100644 index f922767..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.function_definition import FunctionDefinition - -__all__ = ["FunctionTool"] - - -class FunctionTool(BaseModel): - function: FunctionDefinition - - type: Literal["function"] - """The type of tool being defined: `function`""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool_param.py deleted file mode 100644 index d906e02..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/function_tool_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ..shared_params.function_definition import FunctionDefinition - -__all__ = ["FunctionToolParam"] - - -class FunctionToolParam(TypedDict, total=False): - function: Required[FunctionDefinition] - - type: Required[Literal["function"]] - """The type of tool being defined: `function`""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/__init__.py deleted file mode 100644 index 0374b9b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .session import Session as Session -from .error_event import ErrorEvent as ErrorEvent -from .conversation_item import ConversationItem as ConversationItem -from .realtime_response import RealtimeResponse as RealtimeResponse -from .response_done_event import ResponseDoneEvent as ResponseDoneEvent -from .session_update_event import SessionUpdateEvent as SessionUpdateEvent -from .realtime_client_event import RealtimeClientEvent as RealtimeClientEvent -from .realtime_server_event import RealtimeServerEvent as RealtimeServerEvent -from .response_cancel_event import ResponseCancelEvent as ResponseCancelEvent -from .response_create_event import ResponseCreateEvent as ResponseCreateEvent -from .session_create_params import SessionCreateParams as SessionCreateParams -from .session_created_event import SessionCreatedEvent as SessionCreatedEvent -from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent -from .transcription_session import TranscriptionSession as TranscriptionSession -from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent -from .conversation_item_param import ConversationItemParam as ConversationItemParam -from .realtime_connect_params import RealtimeConnectParams as RealtimeConnectParams -from .realtime_response_usage import RealtimeResponseUsage as RealtimeResponseUsage -from .session_create_response import SessionCreateResponse as SessionCreateResponse -from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus -from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent -from .conversation_item_content import ConversationItemContent as ConversationItemContent -from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent -from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent -from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent -from .conversation_created_event import ConversationCreatedEvent as ConversationCreatedEvent -from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent -from .session_update_event_param import SessionUpdateEventParam as SessionUpdateEventParam -from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam -from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam -from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam -from .transcription_session_update import TranscriptionSessionUpdate as TranscriptionSessionUpdate -from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent -from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent -from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent -from .conversation_item_content_param import ConversationItemContentParam as ConversationItemContentParam -from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent -from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent -from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent -from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent -from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent -from .conversation_item_retrieve_event import ConversationItemRetrieveEvent as ConversationItemRetrieveEvent -from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent -from .conversation_item_with_reference import ConversationItemWithReference as ConversationItemWithReference -from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent -from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent -from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent -from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent -from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent -from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent -from .transcription_session_update_param import TranscriptionSessionUpdateParam as TranscriptionSessionUpdateParam -from .transcription_session_create_params import TranscriptionSessionCreateParams as TranscriptionSessionCreateParams -from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent -from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam -from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam -from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent -from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam as InputAudioBufferAppendEventParam -from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam as InputAudioBufferCommitEventParam -from .response_audio_transcript_delta_event import ( - ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, -) -from .conversation_item_retrieve_event_param import ( - ConversationItemRetrieveEventParam as ConversationItemRetrieveEventParam, -) -from .conversation_item_truncate_event_param import ( - ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, -) -from .conversation_item_with_reference_param import ( - ConversationItemWithReferenceParam as ConversationItemWithReferenceParam, -) -from .input_audio_buffer_speech_started_event import ( - InputAudioBufferSpeechStartedEvent as InputAudioBufferSpeechStartedEvent, -) -from .input_audio_buffer_speech_stopped_event import ( - InputAudioBufferSpeechStoppedEvent as InputAudioBufferSpeechStoppedEvent, -) -from .response_function_call_arguments_done_event import ( - ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, -) -from .response_function_call_arguments_delta_event import ( - ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, -) -from .conversation_item_input_audio_transcription_delta_event import ( - ConversationItemInputAudioTranscriptionDeltaEvent as ConversationItemInputAudioTranscriptionDeltaEvent, -) -from .conversation_item_input_audio_transcription_failed_event import ( - ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, -) -from .conversation_item_input_audio_transcription_completed_event import ( - ConversationItemInputAudioTranscriptionCompletedEvent as ConversationItemInputAudioTranscriptionCompletedEvent, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_created_event.py deleted file mode 100644 index 4ba0540..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_created_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationCreatedEvent", "Conversation"] - - -class Conversation(BaseModel): - id: Optional[str] = None - """The unique ID of the conversation.""" - - object: Optional[Literal["realtime.conversation"]] = None - """The object type, must be `realtime.conversation`.""" - - -class ConversationCreatedEvent(BaseModel): - conversation: Conversation - """The conversation resource.""" - - event_id: str - """The unique ID of the server event.""" - - type: Literal["conversation.created"] - """The event type, must be `conversation.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item.py deleted file mode 100644 index 21b7a8a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .conversation_item_content import ConversationItemContent - -__all__ = ["ConversationItem"] - - -class ConversationItem(BaseModel): - id: Optional[str] = None - """ - The unique ID of the item, this can be generated by the client to help manage - server-side context, but is not required because the server will generate one if - not provided. - """ - - arguments: Optional[str] = None - """The arguments of the function call (for `function_call` items).""" - - call_id: Optional[str] = None - """ - The ID of the function call (for `function_call` and `function_call_output` - items). If passed on a `function_call_output` item, the server will check that a - `function_call` item with the same ID exists in the conversation history. - """ - - content: Optional[List[ConversationItemContent]] = None - """The content of the message, applicable for `message` items. - - - Message items of role `system` support only `input_text` content - - Message items of role `user` support `input_text` and `input_audio` content - - Message items of role `assistant` support `text` content. - """ - - name: Optional[str] = None - """The name of the function being called (for `function_call` items).""" - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" - - output: Optional[str] = None - """The output of the function call (for `function_call_output` items).""" - - role: Optional[Literal["user", "assistant", "system"]] = None - """ - The role of the message sender (`user`, `assistant`, `system`), only applicable - for `message` items. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item (`completed`, `incomplete`, `in_progress`). - - These have no effect on the conversation, but are accepted for consistency with - the `conversation.item.created` event. - """ - - type: Optional[Literal["message", "function_call", "function_call_output"]] = None - """The type of the item (`message`, `function_call`, `function_call_output`).""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content.py deleted file mode 100644 index fe9cef8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemContent"] - - -class ConversationItemContent(BaseModel): - id: Optional[str] = None - """ - ID of a previous conversation item to reference (for `item_reference` content - types in `response.create` events). These can reference both client and server - created items. - """ - - audio: Optional[str] = None - """Base64-encoded audio bytes, used for `input_audio` content type.""" - - text: Optional[str] = None - """The text content, used for `input_text` and `text` content types.""" - - transcript: Optional[str] = None - """The transcript of the audio, used for `input_audio` and `audio` content types.""" - - type: Optional[Literal["input_text", "input_audio", "item_reference", "text", "audio"]] = None - """ - The content type (`input_text`, `input_audio`, `item_reference`, `text`, - `audio`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content_param.py deleted file mode 100644 index 6042e7f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_content_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ConversationItemContentParam"] - - -class ConversationItemContentParam(TypedDict, total=False): - id: str - """ - ID of a previous conversation item to reference (for `item_reference` content - types in `response.create` events). These can reference both client and server - created items. - """ - - audio: str - """Base64-encoded audio bytes, used for `input_audio` content type.""" - - text: str - """The text content, used for `input_text` and `text` content types.""" - - transcript: str - """The transcript of the audio, used for `input_audio` and `audio` content types.""" - - type: Literal["input_text", "input_audio", "item_reference", "text", "audio"] - """ - The content type (`input_text`, `input_audio`, `item_reference`, `text`, - `audio`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event.py deleted file mode 100644 index f19d552..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemCreateEvent"] - - -class ConversationItemCreateEvent(BaseModel): - item: ConversationItem - """The item to add to the conversation.""" - - type: Literal["conversation.item.create"] - """The event type, must be `conversation.item.create`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - previous_item_id: Optional[str] = None - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event_param.py deleted file mode 100644 index 693d0fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_create_event_param.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .conversation_item_param import ConversationItemParam - -__all__ = ["ConversationItemCreateEventParam"] - - -class ConversationItemCreateEventParam(TypedDict, total=False): - item: Required[ConversationItemParam] - """The item to add to the conversation.""" - - type: Required[Literal["conversation.item.create"]] - """The event type, must be `conversation.item.create`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - previous_item_id: str - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_created_event.py deleted file mode 100644 index aea7ad5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_created_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemCreatedEvent"] - - -class ConversationItemCreatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """The item to add to the conversation.""" - - type: Literal["conversation.item.created"] - """The event type, must be `conversation.item.created`.""" - - previous_item_id: Optional[str] = None - """ - The ID of the preceding item in the Conversation context, allows the client to - understand the order of the conversation. Can be `null` if the item has no - predecessor. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event.py deleted file mode 100644 index 02ca825..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemDeleteEvent"] - - -class ConversationItemDeleteEvent(BaseModel): - item_id: str - """The ID of the item to delete.""" - - type: Literal["conversation.item.delete"] - """The event type, must be `conversation.item.delete`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event_param.py deleted file mode 100644 index c3f88d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_delete_event_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemDeleteEventParam"] - - -class ConversationItemDeleteEventParam(TypedDict, total=False): - item_id: Required[str] - """The ID of the item to delete.""" - - type: Required[Literal["conversation.item.delete"]] - """The event type, must be `conversation.item.delete`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_deleted_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_deleted_event.py deleted file mode 100644 index a35a978..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_deleted_event.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemDeletedEvent"] - - -class ConversationItemDeletedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item that was deleted.""" - - type: Literal["conversation.item.deleted"] - """The event type, must be `conversation.item.deleted`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py deleted file mode 100644 index e7c457d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_completed_event.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ...._models import BaseModel - -__all__ = [ - "ConversationItemInputAudioTranscriptionCompletedEvent", - "Usage", - "UsageTranscriptTextUsageTokens", - "UsageTranscriptTextUsageTokensInputTokenDetails", - "UsageTranscriptTextUsageDuration", - "Logprob", -] - - -class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): - audio_tokens: Optional[int] = None - """Number of audio tokens billed for this request.""" - - text_tokens: Optional[int] = None - """Number of text tokens billed for this request.""" - - -class UsageTranscriptTextUsageTokens(BaseModel): - input_tokens: int - """Number of input tokens billed for this request.""" - - output_tokens: int - """Number of output tokens generated.""" - - total_tokens: int - """Total number of tokens used (input + output).""" - - type: Literal["tokens"] - """The type of the usage object. Always `tokens` for this variant.""" - - input_token_details: Optional[UsageTranscriptTextUsageTokensInputTokenDetails] = None - """Details about the input tokens billed for this request.""" - - -class UsageTranscriptTextUsageDuration(BaseModel): - seconds: float - """Duration of the input audio in seconds.""" - - type: Literal["duration"] - """The type of the usage object. Always `duration` for this variant.""" - - -Usage: TypeAlias = Union[UsageTranscriptTextUsageTokens, UsageTranscriptTextUsageDuration] - - -class Logprob(BaseModel): - token: str - """The token that was used to generate the log probability.""" - - bytes: List[int] - """The bytes that were used to generate the log probability.""" - - logprob: float - """The log probability of the token.""" - - -class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): - content_index: int - """The index of the content part containing the audio.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item containing the audio.""" - - transcript: str - """The transcribed text.""" - - type: Literal["conversation.item.input_audio_transcription.completed"] - """ - The event type, must be `conversation.item.input_audio_transcription.completed`. - """ - - usage: Usage - """Usage statistics for the transcription.""" - - logprobs: Optional[List[Logprob]] = None - """The log probabilities of the transcription.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py deleted file mode 100644 index 924d06d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_delta_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemInputAudioTranscriptionDeltaEvent", "Logprob"] - - -class Logprob(BaseModel): - token: str - """The token that was used to generate the log probability.""" - - bytes: List[int] - """The bytes that were used to generate the log probability.""" - - logprob: float - """The log probability of the token.""" - - -class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - type: Literal["conversation.item.input_audio_transcription.delta"] - """The event type, must be `conversation.item.input_audio_transcription.delta`.""" - - content_index: Optional[int] = None - """The index of the content part in the item's content array.""" - - delta: Optional[str] = None - """The text delta.""" - - logprobs: Optional[List[Logprob]] = None - """The log probabilities of the transcription.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py deleted file mode 100644 index cecac93..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_input_audio_transcription_failed_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemInputAudioTranscriptionFailedEvent", "Error"] - - -class Error(BaseModel): - code: Optional[str] = None - """Error code, if any.""" - - message: Optional[str] = None - """A human-readable error message.""" - - param: Optional[str] = None - """Parameter related to the error, if any.""" - - type: Optional[str] = None - """The type of error.""" - - -class ConversationItemInputAudioTranscriptionFailedEvent(BaseModel): - content_index: int - """The index of the content part containing the audio.""" - - error: Error - """Details of the transcription error.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item.""" - - type: Literal["conversation.item.input_audio_transcription.failed"] - """The event type, must be `conversation.item.input_audio_transcription.failed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_param.py deleted file mode 100644 index 8bbd539..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_param.py +++ /dev/null @@ -1,62 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, TypedDict - -from .conversation_item_content_param import ConversationItemContentParam - -__all__ = ["ConversationItemParam"] - - -class ConversationItemParam(TypedDict, total=False): - id: str - """ - The unique ID of the item, this can be generated by the client to help manage - server-side context, but is not required because the server will generate one if - not provided. - """ - - arguments: str - """The arguments of the function call (for `function_call` items).""" - - call_id: str - """ - The ID of the function call (for `function_call` and `function_call_output` - items). If passed on a `function_call_output` item, the server will check that a - `function_call` item with the same ID exists in the conversation history. - """ - - content: Iterable[ConversationItemContentParam] - """The content of the message, applicable for `message` items. - - - Message items of role `system` support only `input_text` content - - Message items of role `user` support `input_text` and `input_audio` content - - Message items of role `assistant` support `text` content. - """ - - name: str - """The name of the function being called (for `function_call` items).""" - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" - - output: str - """The output of the function call (for `function_call_output` items).""" - - role: Literal["user", "assistant", "system"] - """ - The role of the message sender (`user`, `assistant`, `system`), only applicable - for `message` items. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item (`completed`, `incomplete`, `in_progress`). - - These have no effect on the conversation, but are accepted for consistency with - the `conversation.item.created` event. - """ - - type: Literal["message", "function_call", "function_call_output"] - """The type of the item (`message`, `function_call`, `function_call_output`).""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event.py deleted file mode 100644 index 8223860..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemRetrieveEvent"] - - -class ConversationItemRetrieveEvent(BaseModel): - item_id: str - """The ID of the item to retrieve.""" - - type: Literal["conversation.item.retrieve"] - """The event type, must be `conversation.item.retrieve`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event_param.py deleted file mode 100644 index 71b3ffa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_retrieve_event_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemRetrieveEventParam"] - - -class ConversationItemRetrieveEventParam(TypedDict, total=False): - item_id: Required[str] - """The ID of the item to retrieve.""" - - type: Required[Literal["conversation.item.retrieve"]] - """The event type, must be `conversation.item.retrieve`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event.py deleted file mode 100644 index cb336bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemTruncateEvent"] - - -class ConversationItemTruncateEvent(BaseModel): - audio_end_ms: int - """Inclusive duration up to which audio is truncated, in milliseconds. - - If the audio_end_ms is greater than the actual audio duration, the server will - respond with an error. - """ - - content_index: int - """The index of the content part to truncate. Set this to 0.""" - - item_id: str - """The ID of the assistant message item to truncate. - - Only assistant message items can be truncated. - """ - - type: Literal["conversation.item.truncate"] - """The event type, must be `conversation.item.truncate`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event_param.py deleted file mode 100644 index d3ad1e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncate_event_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemTruncateEventParam"] - - -class ConversationItemTruncateEventParam(TypedDict, total=False): - audio_end_ms: Required[int] - """Inclusive duration up to which audio is truncated, in milliseconds. - - If the audio_end_ms is greater than the actual audio duration, the server will - respond with an error. - """ - - content_index: Required[int] - """The index of the content part to truncate. Set this to 0.""" - - item_id: Required[str] - """The ID of the assistant message item to truncate. - - Only assistant message items can be truncated. - """ - - type: Required[Literal["conversation.item.truncate"]] - """The event type, must be `conversation.item.truncate`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncated_event.py deleted file mode 100644 index 36368fa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_truncated_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemTruncatedEvent"] - - -class ConversationItemTruncatedEvent(BaseModel): - audio_end_ms: int - """The duration up to which the audio was truncated, in milliseconds.""" - - content_index: int - """The index of the content part that was truncated.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the assistant message item that was truncated.""" - - type: Literal["conversation.item.truncated"] - """The event type, must be `conversation.item.truncated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference.py deleted file mode 100644 index 0edcfc7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ConversationItemWithReference", "Content"] - - -class Content(BaseModel): - id: Optional[str] = None - """ - ID of a previous conversation item to reference (for `item_reference` content - types in `response.create` events). These can reference both client and server - created items. - """ - - audio: Optional[str] = None - """Base64-encoded audio bytes, used for `input_audio` content type.""" - - text: Optional[str] = None - """The text content, used for `input_text` and `text` content types.""" - - transcript: Optional[str] = None - """The transcript of the audio, used for `input_audio` content type.""" - - type: Optional[Literal["input_text", "input_audio", "item_reference", "text"]] = None - """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" - - -class ConversationItemWithReference(BaseModel): - id: Optional[str] = None - """ - For an item of type (`message` | `function_call` | `function_call_output`) this - field allows the client to assign the unique ID of the item. It is not required - because the server will generate one if not provided. - - For an item of type `item_reference`, this field is required and is a reference - to any item that has previously existed in the conversation. - """ - - arguments: Optional[str] = None - """The arguments of the function call (for `function_call` items).""" - - call_id: Optional[str] = None - """ - The ID of the function call (for `function_call` and `function_call_output` - items). If passed on a `function_call_output` item, the server will check that a - `function_call` item with the same ID exists in the conversation history. - """ - - content: Optional[List[Content]] = None - """The content of the message, applicable for `message` items. - - - Message items of role `system` support only `input_text` content - - Message items of role `user` support `input_text` and `input_audio` content - - Message items of role `assistant` support `text` content. - """ - - name: Optional[str] = None - """The name of the function being called (for `function_call` items).""" - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`.""" - - output: Optional[str] = None - """The output of the function call (for `function_call_output` items).""" - - role: Optional[Literal["user", "assistant", "system"]] = None - """ - The role of the message sender (`user`, `assistant`, `system`), only applicable - for `message` items. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item (`completed`, `incomplete`, `in_progress`). - - These have no effect on the conversation, but are accepted for consistency with - the `conversation.item.created` event. - """ - - type: Optional[Literal["message", "function_call", "function_call_output", "item_reference"]] = None - """ - The type of the item (`message`, `function_call`, `function_call_output`, - `item_reference`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference_param.py deleted file mode 100644 index c83dc92..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/conversation_item_with_reference_param.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, TypedDict - -__all__ = ["ConversationItemWithReferenceParam", "Content"] - - -class Content(TypedDict, total=False): - id: str - """ - ID of a previous conversation item to reference (for `item_reference` content - types in `response.create` events). These can reference both client and server - created items. - """ - - audio: str - """Base64-encoded audio bytes, used for `input_audio` content type.""" - - text: str - """The text content, used for `input_text` and `text` content types.""" - - transcript: str - """The transcript of the audio, used for `input_audio` content type.""" - - type: Literal["input_text", "input_audio", "item_reference", "text"] - """The content type (`input_text`, `input_audio`, `item_reference`, `text`).""" - - -class ConversationItemWithReferenceParam(TypedDict, total=False): - id: str - """ - For an item of type (`message` | `function_call` | `function_call_output`) this - field allows the client to assign the unique ID of the item. It is not required - because the server will generate one if not provided. - - For an item of type `item_reference`, this field is required and is a reference - to any item that has previously existed in the conversation. - """ - - arguments: str - """The arguments of the function call (for `function_call` items).""" - - call_id: str - """ - The ID of the function call (for `function_call` and `function_call_output` - items). If passed on a `function_call_output` item, the server will check that a - `function_call` item with the same ID exists in the conversation history. - """ - - content: Iterable[Content] - """The content of the message, applicable for `message` items. - - - Message items of role `system` support only `input_text` content - - Message items of role `user` support `input_text` and `input_audio` content - - Message items of role `assistant` support `text` content. - """ - - name: str - """The name of the function being called (for `function_call` items).""" - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`.""" - - output: str - """The output of the function call (for `function_call_output` items).""" - - role: Literal["user", "assistant", "system"] - """ - The role of the message sender (`user`, `assistant`, `system`), only applicable - for `message` items. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item (`completed`, `incomplete`, `in_progress`). - - These have no effect on the conversation, but are accepted for consistency with - the `conversation.item.created` event. - """ - - type: Literal["message", "function_call", "function_call_output", "item_reference"] - """ - The type of the item (`message`, `function_call`, `function_call_output`, - `item_reference`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/error_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/error_event.py deleted file mode 100644 index e020fc3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/error_event.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ErrorEvent", "Error"] - - -class Error(BaseModel): - message: str - """A human-readable error message.""" - - type: str - """The type of error (e.g., "invalid_request_error", "server_error").""" - - code: Optional[str] = None - """Error code, if any.""" - - event_id: Optional[str] = None - """The event_id of the client event that caused the error, if applicable.""" - - param: Optional[str] = None - """Parameter related to the error, if any.""" - - -class ErrorEvent(BaseModel): - error: Error - """Details of the error.""" - - event_id: str - """The unique ID of the server event.""" - - type: Literal["error"] - """The event type, must be `error`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event.py deleted file mode 100644 index a253a64..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferAppendEvent"] - - -class InputAudioBufferAppendEvent(BaseModel): - audio: str - """Base64-encoded audio bytes. - - This must be in the format specified by the `input_audio_format` field in the - session configuration. - """ - - type: Literal["input_audio_buffer.append"] - """The event type, must be `input_audio_buffer.append`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event_param.py deleted file mode 100644 index 3ad0bc7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_append_event_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferAppendEventParam"] - - -class InputAudioBufferAppendEventParam(TypedDict, total=False): - audio: Required[str] - """Base64-encoded audio bytes. - - This must be in the format specified by the `input_audio_format` field in the - session configuration. - """ - - type: Required[Literal["input_audio_buffer.append"]] - """The event type, must be `input_audio_buffer.append`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event.py deleted file mode 100644 index b0624d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferClearEvent"] - - -class InputAudioBufferClearEvent(BaseModel): - type: Literal["input_audio_buffer.clear"] - """The event type, must be `input_audio_buffer.clear`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py deleted file mode 100644 index 2bd6bc5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_clear_event_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferClearEventParam"] - - -class InputAudioBufferClearEventParam(TypedDict, total=False): - type: Required[Literal["input_audio_buffer.clear"]] - """The event type, must be `input_audio_buffer.clear`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_cleared_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_cleared_event.py deleted file mode 100644 index 632e1b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_cleared_event.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferClearedEvent"] - - -class InputAudioBufferClearedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - type: Literal["input_audio_buffer.cleared"] - """The event type, must be `input_audio_buffer.cleared`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event.py deleted file mode 100644 index 7b6f5e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferCommitEvent"] - - -class InputAudioBufferCommitEvent(BaseModel): - type: Literal["input_audio_buffer.commit"] - """The event type, must be `input_audio_buffer.commit`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py deleted file mode 100644 index c9c927a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_commit_event_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferCommitEventParam"] - - -class InputAudioBufferCommitEventParam(TypedDict, total=False): - type: Required[Literal["input_audio_buffer.commit"]] - """The event type, must be `input_audio_buffer.commit`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_committed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_committed_event.py deleted file mode 100644 index 22eb53b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_committed_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferCommittedEvent"] - - -class InputAudioBufferCommittedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created.""" - - type: Literal["input_audio_buffer.committed"] - """The event type, must be `input_audio_buffer.committed`.""" - - previous_item_id: Optional[str] = None - """ - The ID of the preceding item after which the new item will be inserted. Can be - `null` if the item has no predecessor. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py deleted file mode 100644 index 4f3ab08..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_started_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferSpeechStartedEvent"] - - -class InputAudioBufferSpeechStartedEvent(BaseModel): - audio_start_ms: int - """ - Milliseconds from the start of all audio written to the buffer during the - session when speech was first detected. This will correspond to the beginning of - audio sent to the model, and thus includes the `prefix_padding_ms` configured in - the Session. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created when speech stops.""" - - type: Literal["input_audio_buffer.speech_started"] - """The event type, must be `input_audio_buffer.speech_started`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py deleted file mode 100644 index 4056817..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/input_audio_buffer_speech_stopped_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["InputAudioBufferSpeechStoppedEvent"] - - -class InputAudioBufferSpeechStoppedEvent(BaseModel): - audio_end_ms: int - """Milliseconds since the session started when speech stopped. - - This will correspond to the end of audio sent to the model, and thus includes - the `min_silence_duration_ms` configured in the Session. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created.""" - - type: Literal["input_audio_buffer.speech_stopped"] - """The event type, must be `input_audio_buffer.speech_stopped`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/rate_limits_updated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/rate_limits_updated_event.py deleted file mode 100644 index 7e12283..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/rate_limits_updated_event.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RateLimitsUpdatedEvent", "RateLimit"] - - -class RateLimit(BaseModel): - limit: Optional[int] = None - """The maximum allowed value for the rate limit.""" - - name: Optional[Literal["requests", "tokens"]] = None - """The name of the rate limit (`requests`, `tokens`).""" - - remaining: Optional[int] = None - """The remaining value before the limit is reached.""" - - reset_seconds: Optional[float] = None - """Seconds until the rate limit resets.""" - - -class RateLimitsUpdatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - rate_limits: List[RateLimit] - """List of rate limit information.""" - - type: Literal["rate_limits.updated"] - """The event type, must be `rate_limits.updated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event.py deleted file mode 100644 index 5f4858d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel -from .session_update_event import SessionUpdateEvent -from .response_cancel_event import ResponseCancelEvent -from .response_create_event import ResponseCreateEvent -from .transcription_session_update import TranscriptionSessionUpdate -from .conversation_item_create_event import ConversationItemCreateEvent -from .conversation_item_delete_event import ConversationItemDeleteEvent -from .input_audio_buffer_clear_event import InputAudioBufferClearEvent -from .input_audio_buffer_append_event import InputAudioBufferAppendEvent -from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent -from .conversation_item_retrieve_event import ConversationItemRetrieveEvent -from .conversation_item_truncate_event import ConversationItemTruncateEvent - -__all__ = ["RealtimeClientEvent", "OutputAudioBufferClear"] - - -class OutputAudioBufferClear(BaseModel): - type: Literal["output_audio_buffer.clear"] - """The event type, must be `output_audio_buffer.clear`.""" - - event_id: Optional[str] = None - """The unique ID of the client event used for error handling.""" - - -RealtimeClientEvent: TypeAlias = Annotated[ - Union[ - ConversationItemCreateEvent, - ConversationItemDeleteEvent, - ConversationItemRetrieveEvent, - ConversationItemTruncateEvent, - InputAudioBufferAppendEvent, - InputAudioBufferClearEvent, - OutputAudioBufferClear, - InputAudioBufferCommitEvent, - ResponseCancelEvent, - ResponseCreateEvent, - SessionUpdateEvent, - TranscriptionSessionUpdate, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event_param.py deleted file mode 100644 index e7dfba2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_client_event_param.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .session_update_event_param import SessionUpdateEventParam -from .response_cancel_event_param import ResponseCancelEventParam -from .response_create_event_param import ResponseCreateEventParam -from .transcription_session_update_param import TranscriptionSessionUpdateParam -from .conversation_item_create_event_param import ConversationItemCreateEventParam -from .conversation_item_delete_event_param import ConversationItemDeleteEventParam -from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam -from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam -from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam -from .conversation_item_retrieve_event_param import ConversationItemRetrieveEventParam -from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam - -__all__ = ["RealtimeClientEventParam", "OutputAudioBufferClear"] - - -class OutputAudioBufferClear(TypedDict, total=False): - type: Required[Literal["output_audio_buffer.clear"]] - """The event type, must be `output_audio_buffer.clear`.""" - - event_id: str - """The unique ID of the client event used for error handling.""" - - -RealtimeClientEventParam: TypeAlias = Union[ - ConversationItemCreateEventParam, - ConversationItemDeleteEventParam, - ConversationItemRetrieveEventParam, - ConversationItemTruncateEventParam, - InputAudioBufferAppendEventParam, - InputAudioBufferClearEventParam, - OutputAudioBufferClear, - InputAudioBufferCommitEventParam, - ResponseCancelEventParam, - ResponseCreateEventParam, - SessionUpdateEventParam, - TranscriptionSessionUpdateParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_connect_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_connect_params.py deleted file mode 100644 index 76474f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_connect_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["RealtimeConnectParams"] - - -class RealtimeConnectParams(TypedDict, total=False): - model: Required[str] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response.py deleted file mode 100644 index ccc97c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from ...shared.metadata import Metadata -from .conversation_item import ConversationItem -from .realtime_response_usage import RealtimeResponseUsage -from .realtime_response_status import RealtimeResponseStatus - -__all__ = ["RealtimeResponse"] - - -class RealtimeResponse(BaseModel): - id: Optional[str] = None - """The unique ID of the response.""" - - conversation_id: Optional[str] = None - """ - Which conversation the response is added to, determined by the `conversation` - field in the `response.create` event. If `auto`, the response will be added to - the default conversation and the value of `conversation_id` will be an id like - `conv_1234`. If `none`, the response will not be added to any conversation and - the value of `conversation_id` will be `null`. If responses are being triggered - by server VAD, the response will be added to the default conversation, thus the - `conversation_id` will be an id like `conv_1234`. - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls, that was used in this response. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model used to respond. - - If there are multiple modalities, the model will pick one, for example if - `modalities` is `["text", "audio"]`, the model could be responding in either - text or audio. - """ - - object: Optional[Literal["realtime.response"]] = None - """The object type, must be `realtime.response`.""" - - output: Optional[List[ConversationItem]] = None - """The list of output items generated by the response.""" - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - status: Optional[Literal["completed", "cancelled", "failed", "incomplete", "in_progress"]] = None - """ - The final status of the response (`completed`, `cancelled`, `failed`, or - `incomplete`, `in_progress`). - """ - - status_details: Optional[RealtimeResponseStatus] = None - """Additional details about the status.""" - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - usage: Optional[RealtimeResponseUsage] = None - """Usage statistics for the Response, this will correspond to billing. - - A Realtime API session will maintain a conversation context and append new Items - to the Conversation, thus output from previous turns (text and audio tokens) - will become the input for later turns. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None - """ - The voice the model used to respond. Current voice options are `alloy`, `ash`, - `ballad`, `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_status.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_status.py deleted file mode 100644 index 7189cd5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_status.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RealtimeResponseStatus", "Error"] - - -class Error(BaseModel): - code: Optional[str] = None - """Error code, if any.""" - - type: Optional[str] = None - """The type of error.""" - - -class RealtimeResponseStatus(BaseModel): - error: Optional[Error] = None - """ - A description of the error that caused the response to fail, populated when the - `status` is `failed`. - """ - - reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None - """The reason the Response did not complete. - - For a `cancelled` Response, one of `turn_detected` (the server VAD detected a - new start of speech) or `client_cancelled` (the client sent a cancel event). For - an `incomplete` Response, one of `max_output_tokens` or `content_filter` (the - server-side safety filter activated and cut off the response). - """ - - type: Optional[Literal["completed", "cancelled", "incomplete", "failed"]] = None - """ - The type of error that caused the response to fail, corresponding with the - `status` field (`completed`, `cancelled`, `incomplete`, `failed`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_usage.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_usage.py deleted file mode 100644 index 7ca822e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_response_usage.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ...._models import BaseModel - -__all__ = ["RealtimeResponseUsage", "InputTokenDetails", "OutputTokenDetails"] - - -class InputTokenDetails(BaseModel): - audio_tokens: Optional[int] = None - """The number of audio tokens used in the Response.""" - - cached_tokens: Optional[int] = None - """The number of cached tokens used in the Response.""" - - text_tokens: Optional[int] = None - """The number of text tokens used in the Response.""" - - -class OutputTokenDetails(BaseModel): - audio_tokens: Optional[int] = None - """The number of audio tokens used in the Response.""" - - text_tokens: Optional[int] = None - """The number of text tokens used in the Response.""" - - -class RealtimeResponseUsage(BaseModel): - input_token_details: Optional[InputTokenDetails] = None - """Details about the input tokens used in the Response.""" - - input_tokens: Optional[int] = None - """ - The number of input tokens used in the Response, including text and audio - tokens. - """ - - output_token_details: Optional[OutputTokenDetails] = None - """Details about the output tokens used in the Response.""" - - output_tokens: Optional[int] = None - """ - The number of output tokens sent in the Response, including text and audio - tokens. - """ - - total_tokens: Optional[int] = None - """ - The total number of tokens in the Response including input and output text and - audio tokens. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_server_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_server_event.py deleted file mode 100644 index c12f5df..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/realtime_server_event.py +++ /dev/null @@ -1,133 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ...._utils import PropertyInfo -from ...._models import BaseModel -from .error_event import ErrorEvent -from .conversation_item import ConversationItem -from .response_done_event import ResponseDoneEvent -from .session_created_event import SessionCreatedEvent -from .session_updated_event import SessionUpdatedEvent -from .response_created_event import ResponseCreatedEvent -from .response_text_done_event import ResponseTextDoneEvent -from .rate_limits_updated_event import RateLimitsUpdatedEvent -from .response_audio_done_event import ResponseAudioDoneEvent -from .response_text_delta_event import ResponseTextDeltaEvent -from .conversation_created_event import ConversationCreatedEvent -from .response_audio_delta_event import ResponseAudioDeltaEvent -from .conversation_item_created_event import ConversationItemCreatedEvent -from .conversation_item_deleted_event import ConversationItemDeletedEvent -from .response_output_item_done_event import ResponseOutputItemDoneEvent -from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent -from .response_content_part_done_event import ResponseContentPartDoneEvent -from .response_output_item_added_event import ResponseOutputItemAddedEvent -from .conversation_item_truncated_event import ConversationItemTruncatedEvent -from .response_content_part_added_event import ResponseContentPartAddedEvent -from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent -from .transcription_session_updated_event import TranscriptionSessionUpdatedEvent -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent -from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent -from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent -from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent -from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent -from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent -from .conversation_item_input_audio_transcription_delta_event import ConversationItemInputAudioTranscriptionDeltaEvent -from .conversation_item_input_audio_transcription_failed_event import ConversationItemInputAudioTranscriptionFailedEvent -from .conversation_item_input_audio_transcription_completed_event import ( - ConversationItemInputAudioTranscriptionCompletedEvent, -) - -__all__ = [ - "RealtimeServerEvent", - "ConversationItemRetrieved", - "OutputAudioBufferStarted", - "OutputAudioBufferStopped", - "OutputAudioBufferCleared", -] - - -class ConversationItemRetrieved(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """The item to add to the conversation.""" - - type: Literal["conversation.item.retrieved"] - """The event type, must be `conversation.item.retrieved`.""" - - -class OutputAudioBufferStarted(BaseModel): - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.started"] - """The event type, must be `output_audio_buffer.started`.""" - - -class OutputAudioBufferStopped(BaseModel): - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.stopped"] - """The event type, must be `output_audio_buffer.stopped`.""" - - -class OutputAudioBufferCleared(BaseModel): - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.cleared"] - """The event type, must be `output_audio_buffer.cleared`.""" - - -RealtimeServerEvent: TypeAlias = Annotated[ - Union[ - ConversationCreatedEvent, - ConversationItemCreatedEvent, - ConversationItemDeletedEvent, - ConversationItemInputAudioTranscriptionCompletedEvent, - ConversationItemInputAudioTranscriptionDeltaEvent, - ConversationItemInputAudioTranscriptionFailedEvent, - ConversationItemRetrieved, - ConversationItemTruncatedEvent, - ErrorEvent, - InputAudioBufferClearedEvent, - InputAudioBufferCommittedEvent, - InputAudioBufferSpeechStartedEvent, - InputAudioBufferSpeechStoppedEvent, - RateLimitsUpdatedEvent, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreatedEvent, - ResponseDoneEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - SessionCreatedEvent, - SessionUpdatedEvent, - TranscriptionSessionUpdatedEvent, - OutputAudioBufferStarted, - OutputAudioBufferStopped, - OutputAudioBufferCleared, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_delta_event.py deleted file mode 100644 index 8e0128d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_delta_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseAudioDeltaEvent"] - - -class ResponseAudioDeltaEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """Base64-encoded audio data delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.audio.delta"] - """The event type, must be `response.audio.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_done_event.py deleted file mode 100644 index 68e78bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_done_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseAudioDoneEvent"] - - -class ResponseAudioDoneEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.audio.done"] - """The event type, must be `response.audio.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_delta_event.py deleted file mode 100644 index 3609948..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_delta_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDeltaEvent"] - - -class ResponseAudioTranscriptDeltaEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """The transcript delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.audio_transcript.delta"] - """The event type, must be `response.audio_transcript.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_done_event.py deleted file mode 100644 index 4e4436a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_audio_transcript_done_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDoneEvent"] - - -class ResponseAudioTranscriptDoneEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - transcript: str - """The final transcript of the audio.""" - - type: Literal["response.audio_transcript.done"] - """The event type, must be `response.audio_transcript.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event.py deleted file mode 100644 index c5ff991..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseCancelEvent"] - - -class ResponseCancelEvent(BaseModel): - type: Literal["response.cancel"] - """The event type, must be `response.cancel`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - response_id: Optional[str] = None - """ - A specific response ID to cancel - if not provided, will cancel an in-progress - response in the default conversation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event_param.py deleted file mode 100644 index f337407..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_cancel_event_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseCancelEventParam"] - - -class ResponseCancelEventParam(TypedDict, total=False): - type: Required[Literal["response.cancel"]] - """The event type, must be `response.cancel`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - response_id: str - """ - A specific response ID to cancel - if not provided, will cancel an in-progress - response in the default conversation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_added_event.py deleted file mode 100644 index 45c8f20..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_added_event.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseContentPartAddedEvent", "Part"] - - -class Part(BaseModel): - audio: Optional[str] = None - """Base64-encoded audio data (if type is "audio").""" - - text: Optional[str] = None - """The text content (if type is "text").""" - - transcript: Optional[str] = None - """The transcript of the audio (if type is "audio").""" - - type: Optional[Literal["text", "audio"]] = None - """The content type ("text", "audio").""" - - -class ResponseContentPartAddedEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item to which the content part was added.""" - - output_index: int - """The index of the output item in the response.""" - - part: Part - """The content part that was added.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.content_part.added"] - """The event type, must be `response.content_part.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_done_event.py deleted file mode 100644 index 3d16116..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_content_part_done_event.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseContentPartDoneEvent", "Part"] - - -class Part(BaseModel): - audio: Optional[str] = None - """Base64-encoded audio data (if type is "audio").""" - - text: Optional[str] = None - """The text content (if type is "text").""" - - transcript: Optional[str] = None - """The transcript of the audio (if type is "audio").""" - - type: Optional[Literal["text", "audio"]] = None - """The content type ("text", "audio").""" - - -class ResponseContentPartDoneEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - part: Part - """The content part that is done.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.content_part.done"] - """The event type, must be `response.content_part.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event.py deleted file mode 100644 index 7219ced..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event.py +++ /dev/null @@ -1,121 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from ...shared.metadata import Metadata -from .conversation_item_with_reference import ConversationItemWithReference - -__all__ = ["ResponseCreateEvent", "Response", "ResponseTool"] - - -class ResponseTool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class Response(BaseModel): - conversation: Union[str, Literal["auto", "none"], None] = None - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Optional[List[ConversationItemWithReference]] = None - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items from the default - conversation. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - tool_choice: Optional[str] = None - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function, like - `{"type": "function", "function": {"name": "my_function"}}`. - """ - - tools: Optional[List[ResponseTool]] = None - """Tools (functions) available to the model.""" - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ - - -class ResponseCreateEvent(BaseModel): - type: Literal["response.create"] - """The event type, must be `response.create`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - response: Optional[Response] = None - """Create a new Realtime response with these parameters""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event_param.py deleted file mode 100644 index b4d54bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_create_event_param.py +++ /dev/null @@ -1,122 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -from ...shared_params.metadata import Metadata -from .conversation_item_with_reference_param import ConversationItemWithReferenceParam - -__all__ = ["ResponseCreateEventParam", "Response", "ResponseTool"] - - -class ResponseTool(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - -class Response(TypedDict, total=False): - conversation: Union[str, Literal["auto", "none"]] - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Iterable[ConversationItemWithReferenceParam] - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items from the default - conversation. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - tool_choice: str - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function, like - `{"type": "function", "function": {"name": "my_function"}}`. - """ - - tools: Iterable[ResponseTool] - """Tools (functions) available to the model.""" - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ - - -class ResponseCreateEventParam(TypedDict, total=False): - type: Required[Literal["response.create"]] - """The event type, must be `response.create`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - response: Response - """Create a new Realtime response with these parameters""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_created_event.py deleted file mode 100644 index a4990cf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_created_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .realtime_response import RealtimeResponse - -__all__ = ["ResponseCreatedEvent"] - - -class ResponseCreatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - response: RealtimeResponse - """The response resource.""" - - type: Literal["response.created"] - """The event type, must be `response.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_done_event.py deleted file mode 100644 index 9e65518..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_done_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .realtime_response import RealtimeResponse - -__all__ = ["ResponseDoneEvent"] - - -class ResponseDoneEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - response: RealtimeResponse - """The response resource.""" - - type: Literal["response.done"] - """The event type, must be `response.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_delta_event.py deleted file mode 100644 index cdbb64e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_delta_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] - - -class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): - call_id: str - """The ID of the function call.""" - - delta: str - """The arguments delta as a JSON string.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the function call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.function_call_arguments.delta"] - """The event type, must be `response.function_call_arguments.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_done_event.py deleted file mode 100644 index 0a5db53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_function_call_arguments_done_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] - - -class ResponseFunctionCallArgumentsDoneEvent(BaseModel): - arguments: str - """The final arguments as a JSON string.""" - - call_id: str - """The ID of the function call.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the function call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.function_call_arguments.done"] - """The event type, must be `response.function_call_arguments.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_added_event.py deleted file mode 100644 index c89bfdc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_added_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ResponseOutputItemAddedEvent"] - - -class ResponseOutputItemAddedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """The item to add to the conversation.""" - - output_index: int - """The index of the output item in the Response.""" - - response_id: str - """The ID of the Response to which the item belongs.""" - - type: Literal["response.output_item.added"] - """The event type, must be `response.output_item.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_done_event.py deleted file mode 100644 index b5910e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_output_item_done_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ResponseOutputItemDoneEvent"] - - -class ResponseOutputItemDoneEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """The item to add to the conversation.""" - - output_index: int - """The index of the output item in the Response.""" - - response_id: str - """The ID of the Response to which the item belongs.""" - - type: Literal["response.output_item.done"] - """The event type, must be `response.output_item.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_delta_event.py deleted file mode 100644 index c463b3c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_delta_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseTextDeltaEvent"] - - -class ResponseTextDeltaEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """The text delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.text.delta"] - """The event type, must be `response.text.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_done_event.py deleted file mode 100644 index 020ff41..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/response_text_done_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ResponseTextDoneEvent"] - - -class ResponseTextDoneEvent(BaseModel): - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - text: str - """The final text content.""" - - type: Literal["response.text.done"] - """The event type, must be `response.text.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session.py deleted file mode 100644 index 2e099a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session.py +++ /dev/null @@ -1,279 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ...._models import BaseModel - -__all__ = [ - "Session", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "Tool", - "Tracing", - "TracingTracingConfiguration", - "TurnDetection", -] - - -class InputAudioNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[str] = None - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class Tool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class TracingTracingConfiguration(BaseModel): - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] - - -class TurnDetection(BaseModel): - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" - - -class Session(BaseModel): - id: Optional[str] = None - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[InputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[InputAudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - model: Optional[ - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - ] = None - """The Realtime model used for this session.""" - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: Optional[float] = None - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - - tool_choice: Optional[str] = None - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Optional[List[Tool]] = None - """Tools (functions) available to the model.""" - - tracing: Optional[Tracing] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_params.py deleted file mode 100644 index 38465a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_params.py +++ /dev/null @@ -1,298 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = [ - "SessionCreateParams", - "ClientSecret", - "ClientSecretExpiresAfter", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "Tool", - "Tracing", - "TracingTracingConfiguration", - "TurnDetection", -] - - -class SessionCreateParams(TypedDict, total=False): - client_secret: ClientSecret - """Configuration options for the generated client secret.""" - - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: InputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: InputAudioTranscription - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - model: Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - """The Realtime model used for this session.""" - - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: float - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - - tool_choice: str - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Iterable[Tool] - """Tools (functions) available to the model.""" - - tracing: Tracing - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: TurnDetection - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ - - -class ClientSecretExpiresAfter(TypedDict, total=False): - anchor: Required[Literal["created_at"]] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class ClientSecret(TypedDict, total=False): - expires_after: ClientSecretExpiresAfter - """Configuration for the ephemeral token expiration.""" - - -class InputAudioNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: str - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class Tool(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - -class TracingTracingConfiguration(TypedDict, total=False): - group_id: str - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: object - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: str - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] - - -class TurnDetection(TypedDict, total=False): - create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_response.py deleted file mode 100644 index 471da03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_create_response.py +++ /dev/null @@ -1,196 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ...._models import BaseModel - -__all__ = [ - "SessionCreateResponse", - "ClientSecret", - "InputAudioTranscription", - "Tool", - "Tracing", - "TracingTracingConfiguration", - "TurnDetection", -] - - -class ClientSecret(BaseModel): - expires_at: int - """Timestamp for when the token expires. - - Currently, all tokens expire after one minute. - """ - - value: str - """ - Ephemeral key usable in client environments to authenticate connections to the - Realtime API. Use this in client-side environments rather than a standard API - token, which should only be used server-side. - """ - - -class InputAudioTranscription(BaseModel): - model: Optional[str] = None - """The model to use for transcription.""" - - -class Tool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class TracingTracingConfiguration(BaseModel): - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration] - - -class TurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" - - -class SessionCreateResponse(BaseModel): - client_secret: ClientSecret - """Ephemeral key returned by the API.""" - - input_audio_format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - input_audio_transcription: Optional[InputAudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously and should be treated as rough guidance rather than the - representation understood by the model. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - output_audio_format: Optional[str] = None - """The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - speed: Optional[float] = None - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8.""" - - tool_choice: Optional[str] = None - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Optional[List[Tool]] = None - """Tools (functions) available to the model.""" - - tracing: Optional[Tracing] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_created_event.py deleted file mode 100644 index baf6af3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_created_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .session import Session -from ...._models import BaseModel - -__all__ = ["SessionCreatedEvent"] - - -class SessionCreatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - session: Session - """Realtime session object configuration.""" - - type: Literal["session.created"] - """The event type, must be `session.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event.py deleted file mode 100644 index 78d2e4b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event.py +++ /dev/null @@ -1,312 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ...._models import BaseModel - -__all__ = [ - "SessionUpdateEvent", - "Session", - "SessionClientSecret", - "SessionClientSecretExpiresAfter", - "SessionInputAudioNoiseReduction", - "SessionInputAudioTranscription", - "SessionTool", - "SessionTracing", - "SessionTracingTracingConfiguration", - "SessionTurnDetection", -] - - -class SessionClientSecretExpiresAfter(BaseModel): - anchor: Literal["created_at"] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: Optional[int] = None - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class SessionClientSecret(BaseModel): - expires_after: Optional[SessionClientSecretExpiresAfter] = None - """Configuration for the ephemeral token expiration.""" - - -class SessionInputAudioNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionInputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[str] = None - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class SessionTool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" - - -class SessionTracingTracingConfiguration(BaseModel): - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -SessionTracing: TypeAlias = Union[Literal["auto"], SessionTracingTracingConfiguration] - - -class SessionTurnDetection(BaseModel): - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" - - -class Session(BaseModel): - client_secret: Optional[SessionClientSecret] = None - """Configuration options for the generated client secret.""" - - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[SessionInputAudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - model: Optional[ - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - ] = None - """The Realtime model used for this session.""" - - output_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: Optional[float] = None - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: Optional[float] = None - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - - tool_choice: Optional[str] = None - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Optional[List[SessionTool]] = None - """Tools (functions) available to the model.""" - - tracing: Optional[SessionTracing] = None - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: Optional[SessionTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"], None] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ - - -class SessionUpdateEvent(BaseModel): - session: Session - """Realtime session object configuration.""" - - type: Literal["session.update"] - """The event type, must be `session.update`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event_param.py deleted file mode 100644 index c58b202..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_update_event_param.py +++ /dev/null @@ -1,310 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = [ - "SessionUpdateEventParam", - "Session", - "SessionClientSecret", - "SessionClientSecretExpiresAfter", - "SessionInputAudioNoiseReduction", - "SessionInputAudioTranscription", - "SessionTool", - "SessionTracing", - "SessionTracingTracingConfiguration", - "SessionTurnDetection", -] - - -class SessionClientSecretExpiresAfter(TypedDict, total=False): - anchor: Required[Literal["created_at"]] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class SessionClientSecret(TypedDict, total=False): - expires_after: SessionClientSecretExpiresAfter - """Configuration for the ephemeral token expiration.""" - - -class SessionInputAudioNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionInputAudioTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: str - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class SessionTool(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" - - -class SessionTracingTracingConfiguration(TypedDict, total=False): - group_id: str - """ - The group id to attach to this trace to enable filtering and grouping in the - traces dashboard. - """ - - metadata: object - """ - The arbitrary metadata to attach to this trace to enable filtering in the traces - dashboard. - """ - - workflow_name: str - """The name of the workflow to attach to this trace. - - This is used to name the trace in the traces dashboard. - """ - - -SessionTracing: TypeAlias = Union[Literal["auto"], SessionTracingTracingConfiguration] - - -class SessionTurnDetection(TypedDict, total=False): - create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" - - -class Session(TypedDict, total=False): - client_secret: SessionClientSecret - """Configuration options for the generated client secret.""" - - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: SessionInputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: SessionInputAudioTranscription - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_response_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - model: Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - ] - """The Realtime model used for this session.""" - - output_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of output audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, output audio is - sampled at a rate of 24kHz. - """ - - speed: float - """The speed of the model's spoken response. - - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - """ - - temperature: float - """Sampling temperature for the model, limited to [0.6, 1.2]. - - For audio models a temperature of 0.8 is highly recommended for best - performance. - """ - - tool_choice: str - """How the model chooses tools. - - Options are `auto`, `none`, `required`, or specify a function. - """ - - tools: Iterable[SessionTool] - """Tools (functions) available to the model.""" - - tracing: SessionTracing - """Configuration options for tracing. - - Set to null to disable tracing. Once tracing is enabled for a session, the - configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - turn_detection: SessionTurnDetection - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse"]] - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, and `verse`. - """ - - -class SessionUpdateEventParam(TypedDict, total=False): - session: Required[Session] - """Realtime session object configuration.""" - - type: Required[Literal["session.update"]] - """The event type, must be `session.update`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_updated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_updated_event.py deleted file mode 100644 index b9b6488..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/session_updated_event.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .session import Session -from ...._models import BaseModel - -__all__ = ["SessionUpdatedEvent"] - - -class SessionUpdatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - session: Session - """Realtime session object configuration.""" - - type: Literal["session.updated"] - """The event type, must be `session.updated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session.py deleted file mode 100644 index 7c7abf3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session.py +++ /dev/null @@ -1,100 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["TranscriptionSession", "ClientSecret", "InputAudioTranscription", "TurnDetection"] - - -class ClientSecret(BaseModel): - expires_at: int - """Timestamp for when the token expires. - - Currently, all tokens expire after one minute. - """ - - value: str - """ - Ephemeral key usable in client environments to authenticate connections to the - Realtime API. Use this in client-side environments rather than a standard API - token, which should only be used server-side. - """ - - -class InputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """The model to use for transcription. - - Can be `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. - """ - - prompt: Optional[str] = None - """An optional text to guide the model's style or continue a previous audio - segment. - - The [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) - should match the audio language. - """ - - -class TurnDetection(BaseModel): - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" - - -class TranscriptionSession(BaseModel): - client_secret: ClientSecret - """Ephemeral key returned by the API. - - Only present when the session is created on the server via REST API. - """ - - input_audio_format: Optional[str] = None - """The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`.""" - - input_audio_transcription: Optional[InputAudioTranscription] = None - """Configuration of the transcription model.""" - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - turn_detection: Optional[TurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_create_params.py deleted file mode 100644 index 3ac3af4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_create_params.py +++ /dev/null @@ -1,173 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, TypedDict - -__all__ = [ - "TranscriptionSessionCreateParams", - "ClientSecret", - "ClientSecretExpiresAt", - "InputAudioNoiseReduction", - "InputAudioTranscription", - "TurnDetection", -] - - -class TranscriptionSessionCreateParams(TypedDict, total=False): - client_secret: ClientSecret - """Configuration options for the generated client secret.""" - - include: List[str] - """The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - """ - - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: InputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: InputAudioTranscription - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - turn_detection: TurnDetection - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class ClientSecretExpiresAt(TypedDict, total=False): - anchor: Literal["created_at"] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class ClientSecret(TypedDict, total=False): - expires_at: ClientSecretExpiresAt - """Configuration for the ephemeral token expiration.""" - - -class InputAudioNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class InputAudioTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class TurnDetection(TypedDict, total=False): - create_response: bool - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - Not available for transcription sessions. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. Not available for transcription sessions. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update.py deleted file mode 100644 index 5ae1ad2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update.py +++ /dev/null @@ -1,185 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "TranscriptionSessionUpdate", - "Session", - "SessionClientSecret", - "SessionClientSecretExpiresAt", - "SessionInputAudioNoiseReduction", - "SessionInputAudioTranscription", - "SessionTurnDetection", -] - - -class SessionClientSecretExpiresAt(BaseModel): - anchor: Optional[Literal["created_at"]] = None - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: Optional[int] = None - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class SessionClientSecret(BaseModel): - expires_at: Optional[SessionClientSecretExpiresAt] = None - """Configuration for the ephemeral token expiration.""" - - -class SessionInputAudioNoiseReduction(BaseModel): - type: Optional[Literal["near_field", "far_field"]] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionInputAudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Optional[Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"]] = None - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class SessionTurnDetection(BaseModel): - create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - Not available for transcription sessions. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. Not available for transcription sessions. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Optional[Literal["server_vad", "semantic_vad"]] = None - """Type of turn detection.""" - - -class Session(BaseModel): - client_secret: Optional[SessionClientSecret] = None - """Configuration options for the generated client secret.""" - - include: Optional[List[str]] = None - """The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - """ - - input_audio_format: Optional[Literal["pcm16", "g711_ulaw", "g711_alaw"]] = None - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: Optional[SessionInputAudioNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: Optional[SessionInputAudioTranscription] = None - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - turn_detection: Optional[SessionTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class TranscriptionSessionUpdate(BaseModel): - session: Session - """Realtime transcription session object configuration.""" - - type: Literal["transcription_session.update"] - """The event type, must be `transcription_session.update`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update_param.py deleted file mode 100644 index d7065f6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_update_param.py +++ /dev/null @@ -1,185 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, Required, TypedDict - -__all__ = [ - "TranscriptionSessionUpdateParam", - "Session", - "SessionClientSecret", - "SessionClientSecretExpiresAt", - "SessionInputAudioNoiseReduction", - "SessionInputAudioTranscription", - "SessionTurnDetection", -] - - -class SessionClientSecretExpiresAt(TypedDict, total=False): - anchor: Literal["created_at"] - """The anchor point for the ephemeral token expiration. - - Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200`. - """ - - -class SessionClientSecret(TypedDict, total=False): - expires_at: SessionClientSecretExpiresAt - """Configuration for the ephemeral token expiration.""" - - -class SessionInputAudioNoiseReduction(TypedDict, total=False): - type: Literal["near_field", "far_field"] - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class SessionInputAudioTranscription(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Literal["gpt-4o-transcribe", "gpt-4o-mini-transcribe", "whisper-1"] - """ - The model to use for transcription, current options are `gpt-4o-transcribe`, - `gpt-4o-mini-transcribe`, and `whisper-1`. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models, the prompt is a free text string, for example - "expect words related to technology". - """ - - -class SessionTurnDetection(TypedDict, total=False): - create_response: bool - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - Not available for transcription sessions. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. Not available for transcription sessions. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - type: Literal["server_vad", "semantic_vad"] - """Type of turn detection.""" - - -class Session(TypedDict, total=False): - client_secret: SessionClientSecret - """Configuration options for the generated client secret.""" - - include: List[str] - """The set of items to include in the transcription. Current available items are: - - - `item.input_audio_transcription.logprobs` - """ - - input_audio_format: Literal["pcm16", "g711_ulaw", "g711_alaw"] - """The format of input audio. - - Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For `pcm16`, input audio must - be 16-bit PCM at a 24kHz sample rate, single channel (mono), and little-endian - byte order. - """ - - input_audio_noise_reduction: SessionInputAudioNoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - input_audio_transcription: SessionInputAudioTranscription - """Configuration for input audio transcription. - - The client can optionally set the language and prompt for transcription, these - offer additional guidance to the transcription service. - """ - - modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - To disable audio, set this to ["text"]. - """ - - turn_detection: SessionTurnDetection - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. Server VAD means that the model will detect the start - and end of speech based on audio volume and respond at the end of user speech. - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class TranscriptionSessionUpdateParam(TypedDict, total=False): - session: Required[Session] - """Realtime transcription session object configuration.""" - - type: Required[Literal["transcription_session.update"]] - """The event type, must be `transcription_session.update`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_updated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_updated_event.py deleted file mode 100644 index 1f1fbda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/realtime/transcription_session_updated_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .transcription_session import TranscriptionSession - -__all__ = ["TranscriptionSessionUpdatedEvent"] - - -class TranscriptionSessionUpdatedEvent(BaseModel): - event_id: str - """The unique ID of the server event.""" - - session: TranscriptionSession - """A new Realtime transcription session configuration. - - When a session is created on the server via REST API, the session object also - contains an ephemeral key. Default TTL for keys is 10 minutes. This property is - not present when a session is updated via the WebSocket API. - """ - - type: Literal["transcription_session.updated"] - """The event type, must be `transcription_session.updated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread.py deleted file mode 100644 index 83d9055..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread.py +++ /dev/null @@ -1,71 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.metadata import Metadata - -__all__ = ["Thread", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] - - -class ToolResourcesCodeInterpreter(BaseModel): - file_ids: Optional[List[str]] = None - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearch(BaseModel): - vector_store_ids: Optional[List[str]] = None - """ - The - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this thread. There can be a maximum of 1 vector store attached to - the thread. - """ - - -class ToolResources(BaseModel): - """ - A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: Optional[ToolResourcesCodeInterpreter] = None - - file_search: Optional[ToolResourcesFileSearch] = None - - -class Thread(BaseModel): - """ - Represents a thread that contains [messages](https://platform.openai.com/docs/api-reference/messages). - """ - - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the thread was created.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - object: Literal["thread"] - """The object type, which is always `thread`.""" - - tool_resources: Optional[ToolResources] = None - """ - A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_and_run_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_and_run_params.py deleted file mode 100644 index c0aee3e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_and_run_params.py +++ /dev/null @@ -1,422 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..shared.chat_model import ChatModel -from .assistant_tool_param import AssistantToolParam -from ..shared_params.metadata import Metadata -from .code_interpreter_tool_param import CodeInterpreterToolParam -from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam -from .threads.message_content_part_param import MessageContentPartParam -from .assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = [ - "ThreadCreateAndRunParamsBase", - "Thread", - "ThreadMessage", - "ThreadMessageAttachment", - "ThreadMessageAttachmentTool", - "ThreadMessageAttachmentToolFileSearch", - "ThreadToolResources", - "ThreadToolResourcesCodeInterpreter", - "ThreadToolResourcesFileSearch", - "ThreadToolResourcesFileSearchVectorStore", - "ThreadToolResourcesFileSearchVectorStoreChunkingStrategy", - "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto", - "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic", - "ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", - "ToolResources", - "ToolResourcesCodeInterpreter", - "ToolResourcesFileSearch", - "TruncationStrategy", - "ThreadCreateAndRunParamsNonStreaming", - "ThreadCreateAndRunParamsStreaming", -] - - -class ThreadCreateAndRunParamsBase(TypedDict, total=False): - assistant_id: Required[str] - """ - The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - """ - - instructions: Optional[str] - """Override the default system message of the assistant. - - This is useful for modifying the behavior on a per-run basis. - """ - - max_completion_tokens: Optional[int] - """ - The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - """ - - max_prompt_tokens: Optional[int] - """The maximum number of prompt tokens that may be used over the course of the run. - - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Union[str, ChatModel, None] - """ - The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - """ - - parallel_tool_calls: bool - """ - Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - """ - - response_format: Optional[AssistantResponseFormatOptionParam] - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - """ - - thread: Thread - """Options to create a new thread. - - If no thread is provided when running a request, an empty thread will be - created. - """ - - tool_choice: Optional[AssistantToolChoiceOptionParam] - """ - Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - """ - - tool_resources: Optional[ToolResources] - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - tools: Optional[Iterable[AssistantToolParam]] - """Override the tools the assistant can use for this run. - - This is useful for modifying the behavior on a per-run basis. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - """ - - truncation_strategy: Optional[TruncationStrategy] - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - -class ThreadMessageAttachmentToolFileSearch(TypedDict, total=False): - type: Required[Literal["file_search"]] - """The type of tool being defined: `file_search`""" - - -ThreadMessageAttachmentTool: TypeAlias = Union[CodeInterpreterToolParam, ThreadMessageAttachmentToolFileSearch] - - -class ThreadMessageAttachment(TypedDict, total=False): - file_id: str - """The ID of the file to attach to the message.""" - - tools: Iterable[ThreadMessageAttachmentTool] - """The tools to add this file to.""" - - -class ThreadMessage(TypedDict, total=False): - content: Required[Union[str, Iterable[MessageContentPartParam]]] - """The text contents of the message.""" - - role: Required[Literal["user", "assistant"]] - """The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - """ - - attachments: Optional[Iterable[ThreadMessageAttachment]] - """A list of files attached to the message, and the tools they should be added to.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class ThreadToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): - """The default strategy. - - This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. - """ - - type: Required[Literal["auto"]] - """Always `auto`.""" - - -class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): - chunk_overlap_tokens: Required[int] - """The number of tokens that overlap between chunks. The default value is `400`. - - Note that the overlap must not exceed half of `max_chunk_size_tokens`. - """ - - max_chunk_size_tokens: Required[int] - """The maximum number of tokens in each chunk. - - The default value is `800`. The minimum value is `100` and the maximum value is - `4096`. - """ - - -class ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): - static: Required[ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] - - type: Required[Literal["static"]] - """Always `static`.""" - - -ThreadToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ - ThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto, - ThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic, -] - - -class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: ThreadToolResourcesFileSearchVectorStoreChunkingStrategy - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. - """ - - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class ThreadToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - The - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this thread. There can be a maximum of 1 vector store attached to - the thread. - """ - - vector_stores: Iterable[ThreadToolResourcesFileSearchVectorStore] - """ - A helper to create a - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - with file_ids and attach it to this thread. There can be a maximum of 1 vector - store attached to the thread. - """ - - -class ThreadToolResources(TypedDict, total=False): - """ - A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ThreadToolResourcesCodeInterpreter - - file_search: ThreadToolResourcesFileSearch - - -class Thread(TypedDict, total=False): - """Options to create a new thread. - - If no thread is provided when running a - request, an empty thread will be created. - """ - - messages: Iterable[ThreadMessage] - """ - A list of [messages](https://platform.openai.com/docs/api-reference/messages) to - start the thread with. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - tool_resources: Optional[ThreadToolResources] - """ - A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - -class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - The ID of the - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this assistant. There can be a maximum of 1 vector store attached to - the assistant. - """ - - -class ToolResources(TypedDict, total=False): - """A set of resources that are used by the assistant's tools. - - The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ToolResourcesCodeInterpreter - - file_search: ToolResourcesFileSearch - - -class TruncationStrategy(TypedDict, total=False): - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - type: Required[Literal["auto", "last_messages"]] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - -class ThreadCreateAndRunParamsNonStreaming(ThreadCreateAndRunParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -class ThreadCreateAndRunParamsStreaming(ThreadCreateAndRunParamsBase): - stream: Required[Literal[True]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -ThreadCreateAndRunParams = Union[ThreadCreateAndRunParamsNonStreaming, ThreadCreateAndRunParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_params.py deleted file mode 100644 index ef83e3d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_create_params.py +++ /dev/null @@ -1,195 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..shared_params.metadata import Metadata -from .code_interpreter_tool_param import CodeInterpreterToolParam -from .threads.message_content_part_param import MessageContentPartParam - -__all__ = [ - "ThreadCreateParams", - "Message", - "MessageAttachment", - "MessageAttachmentTool", - "MessageAttachmentToolFileSearch", - "ToolResources", - "ToolResourcesCodeInterpreter", - "ToolResourcesFileSearch", - "ToolResourcesFileSearchVectorStore", - "ToolResourcesFileSearchVectorStoreChunkingStrategy", - "ToolResourcesFileSearchVectorStoreChunkingStrategyAuto", - "ToolResourcesFileSearchVectorStoreChunkingStrategyStatic", - "ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic", -] - - -class ThreadCreateParams(TypedDict, total=False): - messages: Iterable[Message] - """ - A list of [messages](https://platform.openai.com/docs/api-reference/messages) to - start the thread with. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - tool_resources: Optional[ToolResources] - """ - A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - -class MessageAttachmentToolFileSearch(TypedDict, total=False): - type: Required[Literal["file_search"]] - """The type of tool being defined: `file_search`""" - - -MessageAttachmentTool: TypeAlias = Union[CodeInterpreterToolParam, MessageAttachmentToolFileSearch] - - -class MessageAttachment(TypedDict, total=False): - file_id: str - """The ID of the file to attach to the message.""" - - tools: Iterable[MessageAttachmentTool] - """The tools to add this file to.""" - - -class Message(TypedDict, total=False): - content: Required[Union[str, Iterable[MessageContentPartParam]]] - """The text contents of the message.""" - - role: Required[Literal["user", "assistant"]] - """The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - """ - - attachments: Optional[Iterable[MessageAttachment]] - """A list of files attached to the message, and the tools they should be added to.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyAuto(TypedDict, total=False): - """The default strategy. - - This strategy currently uses a `max_chunk_size_tokens` of `800` and `chunk_overlap_tokens` of `400`. - """ - - type: Required[Literal["auto"]] - """Always `auto`.""" - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic(TypedDict, total=False): - chunk_overlap_tokens: Required[int] - """The number of tokens that overlap between chunks. The default value is `400`. - - Note that the overlap must not exceed half of `max_chunk_size_tokens`. - """ - - max_chunk_size_tokens: Required[int] - """The maximum number of tokens in each chunk. - - The default value is `800`. The minimum value is `100` and the maximum value is - `4096`. - """ - - -class ToolResourcesFileSearchVectorStoreChunkingStrategyStatic(TypedDict, total=False): - static: Required[ToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic] - - type: Required[Literal["static"]] - """Always `static`.""" - - -ToolResourcesFileSearchVectorStoreChunkingStrategy: TypeAlias = Union[ - ToolResourcesFileSearchVectorStoreChunkingStrategyAuto, ToolResourcesFileSearchVectorStoreChunkingStrategyStatic -] - - -class ToolResourcesFileSearchVectorStore(TypedDict, total=False): - chunking_strategy: ToolResourcesFileSearchVectorStoreChunkingStrategy - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. - """ - - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - add to the vector store. There can be a maximum of 10000 files in a vector - store. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - The - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this thread. There can be a maximum of 1 vector store attached to - the thread. - """ - - vector_stores: Iterable[ToolResourcesFileSearchVectorStore] - """ - A helper to create a - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - with file_ids and attach it to this thread. There can be a maximum of 1 vector - store attached to the thread. - """ - - -class ToolResources(TypedDict, total=False): - """ - A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ToolResourcesCodeInterpreter - - file_search: ToolResourcesFileSearch diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_deleted.py deleted file mode 100644 index d385626..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ThreadDeleted"] - - -class ThreadDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["thread.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_update_params.py deleted file mode 100644 index e000edc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/thread_update_params.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -from ..._types import SequenceNotStr -from ..shared_params.metadata import Metadata - -__all__ = ["ThreadUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] - - -class ThreadUpdateParams(TypedDict, total=False): - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - tool_resources: Optional[ToolResources] - """ - A set of resources that are made available to the assistant's tools in this - thread. The resources are specific to the type of tool. For example, the - `code_interpreter` tool requires a list of file IDs, while the `file_search` - tool requires a list of vector store IDs. - """ - - -class ToolResourcesCodeInterpreter(TypedDict, total=False): - file_ids: SequenceNotStr[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - available to the `code_interpreter` tool. There can be a maximum of 20 files - associated with the tool. - """ - - -class ToolResourcesFileSearch(TypedDict, total=False): - vector_store_ids: SequenceNotStr[str] - """ - The - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - attached to this thread. There can be a maximum of 1 vector store attached to - the thread. - """ - - -class ToolResources(TypedDict, total=False): - """ - A set of resources that are made available to the assistant's tools in this thread. The resources are specific to the type of tool. For example, the `code_interpreter` tool requires a list of file IDs, while the `file_search` tool requires a list of vector store IDs. - """ - - code_interpreter: ToolResourcesCodeInterpreter - - file_search: ToolResourcesFileSearch diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/__init__.py deleted file mode 100644 index 7085317..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .run import Run as Run -from .text import Text as Text -from .message import Message as Message -from .image_url import ImageURL as ImageURL -from .annotation import Annotation as Annotation -from .image_file import ImageFile as ImageFile -from .run_status import RunStatus as RunStatus -from .text_delta import TextDelta as TextDelta -from .message_delta import MessageDelta as MessageDelta -from .image_url_delta import ImageURLDelta as ImageURLDelta -from .image_url_param import ImageURLParam as ImageURLParam -from .message_content import MessageContent as MessageContent -from .message_deleted import MessageDeleted as MessageDeleted -from .run_list_params import RunListParams as RunListParams -from .annotation_delta import AnnotationDelta as AnnotationDelta -from .image_file_delta import ImageFileDelta as ImageFileDelta -from .image_file_param import ImageFileParam as ImageFileParam -from .text_delta_block import TextDeltaBlock as TextDeltaBlock -from .run_create_params import RunCreateParams as RunCreateParams -from .run_update_params import RunUpdateParams as RunUpdateParams -from .text_content_block import TextContentBlock as TextContentBlock -from .message_delta_event import MessageDeltaEvent as MessageDeltaEvent -from .message_list_params import MessageListParams as MessageListParams -from .refusal_delta_block import RefusalDeltaBlock as RefusalDeltaBlock -from .file_path_annotation import FilePathAnnotation as FilePathAnnotation -from .image_url_delta_block import ImageURLDeltaBlock as ImageURLDeltaBlock -from .message_content_delta import MessageContentDelta as MessageContentDelta -from .message_create_params import MessageCreateParams as MessageCreateParams -from .message_update_params import MessageUpdateParams as MessageUpdateParams -from .refusal_content_block import RefusalContentBlock as RefusalContentBlock -from .image_file_delta_block import ImageFileDeltaBlock as ImageFileDeltaBlock -from .image_url_content_block import ImageURLContentBlock as ImageURLContentBlock -from .file_citation_annotation import FileCitationAnnotation as FileCitationAnnotation -from .image_file_content_block import ImageFileContentBlock as ImageFileContentBlock -from .text_content_block_param import TextContentBlockParam as TextContentBlockParam -from .file_path_delta_annotation import FilePathDeltaAnnotation as FilePathDeltaAnnotation -from .message_content_part_param import MessageContentPartParam as MessageContentPartParam -from .image_url_content_block_param import ImageURLContentBlockParam as ImageURLContentBlockParam -from .file_citation_delta_annotation import FileCitationDeltaAnnotation as FileCitationDeltaAnnotation -from .image_file_content_block_param import ImageFileContentBlockParam as ImageFileContentBlockParam -from .run_submit_tool_outputs_params import RunSubmitToolOutputsParams as RunSubmitToolOutputsParams -from .required_action_function_tool_call import RequiredActionFunctionToolCall as RequiredActionFunctionToolCall diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation.py deleted file mode 100644 index 13c10ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ...._utils import PropertyInfo -from .file_path_annotation import FilePathAnnotation -from .file_citation_annotation import FileCitationAnnotation - -__all__ = ["Annotation"] - -Annotation: TypeAlias = Annotated[Union[FileCitationAnnotation, FilePathAnnotation], PropertyInfo(discriminator="type")] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation_delta.py deleted file mode 100644 index c7c6c89..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/annotation_delta.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ...._utils import PropertyInfo -from .file_path_delta_annotation import FilePathDeltaAnnotation -from .file_citation_delta_annotation import FileCitationDeltaAnnotation - -__all__ = ["AnnotationDelta"] - -AnnotationDelta: TypeAlias = Annotated[ - Union[FileCitationDeltaAnnotation, FilePathDeltaAnnotation], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_annotation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_annotation.py deleted file mode 100644 index 929da0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_annotation.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["FileCitationAnnotation", "FileCitation"] - - -class FileCitation(BaseModel): - file_id: str - """The ID of the specific File the citation is from.""" - - -class FileCitationAnnotation(BaseModel): - """ - A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files. - """ - - end_index: int - - file_citation: FileCitation - - start_index: int - - text: str - """The text in the message content that needs to be replaced.""" - - type: Literal["file_citation"] - """Always `file_citation`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_delta_annotation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_delta_annotation.py deleted file mode 100644 index 591e322..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_citation_delta_annotation.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["FileCitationDeltaAnnotation", "FileCitation"] - - -class FileCitation(BaseModel): - file_id: Optional[str] = None - """The ID of the specific File the citation is from.""" - - quote: Optional[str] = None - """The specific quote in the file.""" - - -class FileCitationDeltaAnnotation(BaseModel): - """ - A citation within the message that points to a specific quote from a specific File associated with the assistant or the message. Generated when the assistant uses the "file_search" tool to search files. - """ - - index: int - """The index of the annotation in the text content part.""" - - type: Literal["file_citation"] - """Always `file_citation`.""" - - end_index: Optional[int] = None - - file_citation: Optional[FileCitation] = None - - start_index: Optional[int] = None - - text: Optional[str] = None - """The text in the message content that needs to be replaced.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_annotation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_annotation.py deleted file mode 100644 index d3c144c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_annotation.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["FilePathAnnotation", "FilePath"] - - -class FilePath(BaseModel): - file_id: str - """The ID of the file that was generated.""" - - -class FilePathAnnotation(BaseModel): - """ - A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file. - """ - - end_index: int - - file_path: FilePath - - start_index: int - - text: str - """The text in the message content that needs to be replaced.""" - - type: Literal["file_path"] - """Always `file_path`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_delta_annotation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_delta_annotation.py deleted file mode 100644 index 5416874..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/file_path_delta_annotation.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["FilePathDeltaAnnotation", "FilePath"] - - -class FilePath(BaseModel): - file_id: Optional[str] = None - """The ID of the file that was generated.""" - - -class FilePathDeltaAnnotation(BaseModel): - """ - A URL for the file that's generated when the assistant used the `code_interpreter` tool to generate a file. - """ - - index: int - """The index of the annotation in the text content part.""" - - type: Literal["file_path"] - """Always `file_path`.""" - - end_index: Optional[int] = None - - file_path: Optional[FilePath] = None - - start_index: Optional[int] = None - - text: Optional[str] = None - """The text in the message content that needs to be replaced.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file.py deleted file mode 100644 index 6000d97..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ImageFile"] - - -class ImageFile(BaseModel): - file_id: str - """ - The [File](https://platform.openai.com/docs/api-reference/files) ID of the image - in the message content. Set `purpose="vision"` when uploading the File if you - need to later display the file content. - """ - - detail: Optional[Literal["auto", "low", "high"]] = None - """Specifies the detail level of the image if specified by the user. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block.py deleted file mode 100644 index 5a082cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .image_file import ImageFile - -__all__ = ["ImageFileContentBlock"] - - -class ImageFileContentBlock(BaseModel): - """ - References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. - """ - - image_file: ImageFile - - type: Literal["image_file"] - """Always `image_file`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block_param.py deleted file mode 100644 index da095a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_content_block_param.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .image_file_param import ImageFileParam - -__all__ = ["ImageFileContentBlockParam"] - - -class ImageFileContentBlockParam(TypedDict, total=False): - """ - References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. - """ - - image_file: Required[ImageFileParam] - - type: Required[Literal["image_file"]] - """Always `image_file`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta.py deleted file mode 100644 index 4581184..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ImageFileDelta"] - - -class ImageFileDelta(BaseModel): - detail: Optional[Literal["auto", "low", "high"]] = None - """Specifies the detail level of the image if specified by the user. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. - """ - - file_id: Optional[str] = None - """ - The [File](https://platform.openai.com/docs/api-reference/files) ID of the image - in the message content. Set `purpose="vision"` when uploading the File if you - need to later display the file content. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta_block.py deleted file mode 100644 index ed17f7f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_delta_block.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .image_file_delta import ImageFileDelta - -__all__ = ["ImageFileDeltaBlock"] - - -class ImageFileDeltaBlock(BaseModel): - """ - References an image [File](https://platform.openai.com/docs/api-reference/files) in the content of a message. - """ - - index: int - """The index of the content part in the message.""" - - type: Literal["image_file"] - """Always `image_file`.""" - - image_file: Optional[ImageFileDelta] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_param.py deleted file mode 100644 index e4a8535..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_file_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ImageFileParam"] - - -class ImageFileParam(TypedDict, total=False): - file_id: Required[str] - """ - The [File](https://platform.openai.com/docs/api-reference/files) ID of the image - in the message content. Set `purpose="vision"` when uploading the File if you - need to later display the file content. - """ - - detail: Literal["auto", "low", "high"] - """Specifies the detail level of the image if specified by the user. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url.py deleted file mode 100644 index d1fac14..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ImageURL"] - - -class ImageURL(BaseModel): - url: str - """ - The external URL of the image, must be a supported image types: jpeg, jpg, png, - gif, webp. - """ - - detail: Optional[Literal["auto", "low", "high"]] = None - """Specifies the detail level of the image. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. Default - value is `auto` - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block.py deleted file mode 100644 index 8dc1f16..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .image_url import ImageURL -from ...._models import BaseModel - -__all__ = ["ImageURLContentBlock"] - - -class ImageURLContentBlock(BaseModel): - """References an image URL in the content of a message.""" - - image_url: ImageURL - - type: Literal["image_url"] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block_param.py deleted file mode 100644 index a5c59e0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_content_block_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .image_url_param import ImageURLParam - -__all__ = ["ImageURLContentBlockParam"] - - -class ImageURLContentBlockParam(TypedDict, total=False): - """References an image URL in the content of a message.""" - - image_url: Required[ImageURLParam] - - type: Required[Literal["image_url"]] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta.py deleted file mode 100644 index e402671..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["ImageURLDelta"] - - -class ImageURLDelta(BaseModel): - detail: Optional[Literal["auto", "low", "high"]] = None - """Specifies the detail level of the image. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. - """ - - url: Optional[str] = None - """ - The URL of the image, must be a supported image types: jpeg, jpg, png, gif, - webp. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta_block.py deleted file mode 100644 index 3128d8e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_delta_block.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .image_url_delta import ImageURLDelta - -__all__ = ["ImageURLDeltaBlock"] - - -class ImageURLDeltaBlock(BaseModel): - """References an image URL in the content of a message.""" - - index: int - """The index of the content part in the message.""" - - type: Literal["image_url"] - """Always `image_url`.""" - - image_url: Optional[ImageURLDelta] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_param.py deleted file mode 100644 index 6b7e427..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/image_url_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ImageURLParam"] - - -class ImageURLParam(TypedDict, total=False): - url: Required[str] - """ - The external URL of the image, must be a supported image types: jpeg, jpg, png, - gif, webp. - """ - - detail: Literal["auto", "low", "high"] - """Specifies the detail level of the image. - - `low` uses fewer tokens, you can opt in to high resolution using `high`. Default - value is `auto` - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message.py deleted file mode 100644 index fc7f73f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message.py +++ /dev/null @@ -1,109 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ...._models import BaseModel -from .message_content import MessageContent -from ...shared.metadata import Metadata -from ..code_interpreter_tool import CodeInterpreterTool - -__all__ = [ - "Message", - "Attachment", - "AttachmentTool", - "AttachmentToolAssistantToolsFileSearchTypeOnly", - "IncompleteDetails", -] - - -class AttachmentToolAssistantToolsFileSearchTypeOnly(BaseModel): - type: Literal["file_search"] - """The type of tool being defined: `file_search`""" - - -AttachmentTool: TypeAlias = Union[CodeInterpreterTool, AttachmentToolAssistantToolsFileSearchTypeOnly] - - -class Attachment(BaseModel): - file_id: Optional[str] = None - """The ID of the file to attach to the message.""" - - tools: Optional[List[AttachmentTool]] = None - """The tools to add this file to.""" - - -class IncompleteDetails(BaseModel): - """On an incomplete message, details about why the message is incomplete.""" - - reason: Literal["content_filter", "max_tokens", "run_cancelled", "run_expired", "run_failed"] - """The reason the message is incomplete.""" - - -class Message(BaseModel): - """ - Represents a message within a [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - id: str - """The identifier, which can be referenced in API endpoints.""" - - assistant_id: Optional[str] = None - """ - If applicable, the ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) that - authored this message. - """ - - attachments: Optional[List[Attachment]] = None - """A list of files attached to the message, and the tools they were added to.""" - - completed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the message was completed.""" - - content: List[MessageContent] - """The content of the message in array of text and/or images.""" - - created_at: int - """The Unix timestamp (in seconds) for when the message was created.""" - - incomplete_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the message was marked as incomplete.""" - - incomplete_details: Optional[IncompleteDetails] = None - """On an incomplete message, details about why the message is incomplete.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - object: Literal["thread.message"] - """The object type, which is always `thread.message`.""" - - role: Literal["user", "assistant"] - """The entity that produced the message. One of `user` or `assistant`.""" - - run_id: Optional[str] = None - """ - The ID of the [run](https://platform.openai.com/docs/api-reference/runs) - associated with the creation of this message. Value is `null` when messages are - created manually using the create message or create thread endpoints. - """ - - status: Literal["in_progress", "incomplete", "completed"] - """ - The status of the message, which can be either `in_progress`, `incomplete`, or - `completed`. - """ - - thread_id: str - """ - The [thread](https://platform.openai.com/docs/api-reference/threads) ID that - this message belongs to. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content.py deleted file mode 100644 index 9523c1e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ...._utils import PropertyInfo -from .text_content_block import TextContentBlock -from .refusal_content_block import RefusalContentBlock -from .image_url_content_block import ImageURLContentBlock -from .image_file_content_block import ImageFileContentBlock - -__all__ = ["MessageContent"] - - -MessageContent: TypeAlias = Annotated[ - Union[ImageFileContentBlock, ImageURLContentBlock, TextContentBlock, RefusalContentBlock], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_delta.py deleted file mode 100644 index b6e7dfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_delta.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ...._utils import PropertyInfo -from .text_delta_block import TextDeltaBlock -from .refusal_delta_block import RefusalDeltaBlock -from .image_url_delta_block import ImageURLDeltaBlock -from .image_file_delta_block import ImageFileDeltaBlock - -__all__ = ["MessageContentDelta"] - -MessageContentDelta: TypeAlias = Annotated[ - Union[ImageFileDeltaBlock, TextDeltaBlock, RefusalDeltaBlock, ImageURLDeltaBlock], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_part_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_part_param.py deleted file mode 100644 index dc09a01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_content_part_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .text_content_block_param import TextContentBlockParam -from .image_url_content_block_param import ImageURLContentBlockParam -from .image_file_content_block_param import ImageFileContentBlockParam - -__all__ = ["MessageContentPartParam"] - -MessageContentPartParam: TypeAlias = Union[ImageFileContentBlockParam, ImageURLContentBlockParam, TextContentBlockParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_create_params.py deleted file mode 100644 index b523868..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_create_params.py +++ /dev/null @@ -1,55 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ...shared_params.metadata import Metadata -from .message_content_part_param import MessageContentPartParam -from ..code_interpreter_tool_param import CodeInterpreterToolParam - -__all__ = ["MessageCreateParams", "Attachment", "AttachmentTool", "AttachmentToolFileSearch"] - - -class MessageCreateParams(TypedDict, total=False): - content: Required[Union[str, Iterable[MessageContentPartParam]]] - """The text contents of the message.""" - - role: Required[Literal["user", "assistant"]] - """The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - """ - - attachments: Optional[Iterable[Attachment]] - """A list of files attached to the message, and the tools they should be added to.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class AttachmentToolFileSearch(TypedDict, total=False): - type: Required[Literal["file_search"]] - """The type of tool being defined: `file_search`""" - - -AttachmentTool: TypeAlias = Union[CodeInterpreterToolParam, AttachmentToolFileSearch] - - -class Attachment(TypedDict, total=False): - file_id: str - """The ID of the file to attach to the message.""" - - tools: Iterable[AttachmentTool] - """The tools to add this file to.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_deleted.py deleted file mode 100644 index 4821077..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["MessageDeleted"] - - -class MessageDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["thread.message.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta.py deleted file mode 100644 index fdeebb3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .message_content_delta import MessageContentDelta - -__all__ = ["MessageDelta"] - - -class MessageDelta(BaseModel): - """The delta containing the fields that have changed on the Message.""" - - content: Optional[List[MessageContentDelta]] = None - """The content of the message in array of text and/or images.""" - - role: Optional[Literal["user", "assistant"]] = None - """The entity that produced the message. One of `user` or `assistant`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta_event.py deleted file mode 100644 index d5ba1e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_delta_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel -from .message_delta import MessageDelta - -__all__ = ["MessageDeltaEvent"] - - -class MessageDeltaEvent(BaseModel): - """Represents a message delta i.e. - - any changed fields on a message during streaming. - """ - - id: str - """The identifier of the message, which can be referenced in API endpoints.""" - - delta: MessageDelta - """The delta containing the fields that have changed on the Message.""" - - object: Literal["thread.message.delta"] - """The object type, which is always `thread.message.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_list_params.py deleted file mode 100644 index a7c22a6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_list_params.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["MessageListParams"] - - -class MessageListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ - - run_id: str - """Filter messages by the run ID that generated them.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_update_params.py deleted file mode 100644 index bb07828..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/message_update_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from ...shared_params.metadata import Metadata - -__all__ = ["MessageUpdateParams"] - - -class MessageUpdateParams(TypedDict, total=False): - thread_id: Required[str] - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_content_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_content_block.py deleted file mode 100644 index b4512b3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_content_block.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RefusalContentBlock"] - - -class RefusalContentBlock(BaseModel): - """The refusal content generated by the assistant.""" - - refusal: str - - type: Literal["refusal"] - """Always `refusal`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_delta_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_delta_block.py deleted file mode 100644 index 85a1f08..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/refusal_delta_block.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RefusalDeltaBlock"] - - -class RefusalDeltaBlock(BaseModel): - """The refusal content that is part of a message.""" - - index: int - """The index of the refusal part in the message.""" - - type: Literal["refusal"] - """Always `refusal`.""" - - refusal: Optional[str] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/required_action_function_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/required_action_function_tool_call.py deleted file mode 100644 index 3cec851..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/required_action_function_tool_call.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RequiredActionFunctionToolCall", "Function"] - - -class Function(BaseModel): - """The function definition.""" - - arguments: str - """The arguments that the model expects you to pass to the function.""" - - name: str - """The name of the function.""" - - -class RequiredActionFunctionToolCall(BaseModel): - """Tool call objects""" - - id: str - """The ID of the tool call. - - This ID must be referenced when you submit the tool outputs in using the - [Submit tool outputs to run](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs) - endpoint. - """ - - function: Function - """The function definition.""" - - type: Literal["function"] - """The type of tool call the output is required for. - - For now, this is always `function`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run.py deleted file mode 100644 index 8a88fa1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run.py +++ /dev/null @@ -1,273 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .run_status import RunStatus -from ..assistant_tool import AssistantTool -from ...shared.metadata import Metadata -from ..assistant_tool_choice_option import AssistantToolChoiceOption -from ..assistant_response_format_option import AssistantResponseFormatOption -from .required_action_function_tool_call import RequiredActionFunctionToolCall - -__all__ = [ - "Run", - "IncompleteDetails", - "LastError", - "RequiredAction", - "RequiredActionSubmitToolOutputs", - "TruncationStrategy", - "Usage", -] - - -class IncompleteDetails(BaseModel): - """Details on why the run is incomplete. - - Will be `null` if the run is not incomplete. - """ - - reason: Optional[Literal["max_completion_tokens", "max_prompt_tokens"]] = None - """The reason why the run is incomplete. - - This will point to which specific token limit was reached over the course of the - run. - """ - - -class LastError(BaseModel): - """The last error associated with this run. Will be `null` if there are no errors.""" - - code: Literal["server_error", "rate_limit_exceeded", "invalid_prompt"] - """One of `server_error`, `rate_limit_exceeded`, or `invalid_prompt`.""" - - message: str - """A human-readable description of the error.""" - - -class RequiredActionSubmitToolOutputs(BaseModel): - """Details on the tool outputs needed for this run to continue.""" - - tool_calls: List[RequiredActionFunctionToolCall] - """A list of the relevant tool calls.""" - - -class RequiredAction(BaseModel): - """Details on the action required to continue the run. - - Will be `null` if no action is required. - """ - - submit_tool_outputs: RequiredActionSubmitToolOutputs - """Details on the tool outputs needed for this run to continue.""" - - type: Literal["submit_tool_outputs"] - """For now, this is always `submit_tool_outputs`.""" - - -class TruncationStrategy(BaseModel): - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - type: Literal["auto", "last_messages"] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] = None - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - -class Usage(BaseModel): - """Usage statistics related to the run. - - This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.). - """ - - completion_tokens: int - """Number of completion tokens used over the course of the run.""" - - prompt_tokens: int - """Number of prompt tokens used over the course of the run.""" - - total_tokens: int - """Total number of tokens used (prompt + completion).""" - - -class Run(BaseModel): - """ - Represents an execution run on a [thread](https://platform.openai.com/docs/api-reference/threads). - """ - - id: str - """The identifier, which can be referenced in API endpoints.""" - - assistant_id: str - """ - The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) used for - execution of this run. - """ - - cancelled_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run was cancelled.""" - - completed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run was completed.""" - - created_at: int - """The Unix timestamp (in seconds) for when the run was created.""" - - expires_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run will expire.""" - - failed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run failed.""" - - incomplete_details: Optional[IncompleteDetails] = None - """Details on why the run is incomplete. - - Will be `null` if the run is not incomplete. - """ - - instructions: str - """ - The instructions that the - [assistant](https://platform.openai.com/docs/api-reference/assistants) used for - this run. - """ - - last_error: Optional[LastError] = None - """The last error associated with this run. Will be `null` if there are no errors.""" - - max_completion_tokens: Optional[int] = None - """ - The maximum number of completion tokens specified to have been used over the - course of the run. - """ - - max_prompt_tokens: Optional[int] = None - """ - The maximum number of prompt tokens specified to have been used over the course - of the run. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """ - The model that the - [assistant](https://platform.openai.com/docs/api-reference/assistants) used for - this run. - """ - - object: Literal["thread.run"] - """The object type, which is always `thread.run`.""" - - parallel_tool_calls: bool - """ - Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - """ - - required_action: Optional[RequiredAction] = None - """Details on the action required to continue the run. - - Will be `null` if no action is required. - """ - - response_format: Optional[AssistantResponseFormatOption] = None - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - started_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run was started.""" - - status: RunStatus - """ - The status of the run, which can be either `queued`, `in_progress`, - `requires_action`, `cancelling`, `cancelled`, `failed`, `completed`, - `incomplete`, or `expired`. - """ - - thread_id: str - """ - The ID of the [thread](https://platform.openai.com/docs/api-reference/threads) - that was executed on as a part of this run. - """ - - tool_choice: Optional[AssistantToolChoiceOption] = None - """ - Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - """ - - tools: List[AssistantTool] - """ - The list of tools that the - [assistant](https://platform.openai.com/docs/api-reference/assistants) used for - this run. - """ - - truncation_strategy: Optional[TruncationStrategy] = None - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - usage: Optional[Usage] = None - """Usage statistics related to the run. - - This value will be `null` if the run is not in a terminal state (i.e. - `in_progress`, `queued`, etc.). - """ - - temperature: Optional[float] = None - """The sampling temperature used for this run. If not set, defaults to 1.""" - - top_p: Optional[float] = None - """The nucleus sampling value used for this run. If not set, defaults to 1.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_create_params.py deleted file mode 100644 index 376afc9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_create_params.py +++ /dev/null @@ -1,274 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ...shared.chat_model import ChatModel -from ..assistant_tool_param import AssistantToolParam -from .runs.run_step_include import RunStepInclude -from ...shared_params.metadata import Metadata -from ...shared.reasoning_effort import ReasoningEffort -from .message_content_part_param import MessageContentPartParam -from ..code_interpreter_tool_param import CodeInterpreterToolParam -from ..assistant_tool_choice_option_param import AssistantToolChoiceOptionParam -from ..assistant_response_format_option_param import AssistantResponseFormatOptionParam - -__all__ = [ - "RunCreateParamsBase", - "AdditionalMessage", - "AdditionalMessageAttachment", - "AdditionalMessageAttachmentTool", - "AdditionalMessageAttachmentToolFileSearch", - "TruncationStrategy", - "RunCreateParamsNonStreaming", - "RunCreateParamsStreaming", -] - - -class RunCreateParamsBase(TypedDict, total=False): - assistant_id: Required[str] - """ - The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - execute this run. - """ - - include: List[RunStepInclude] - """A list of additional fields to include in the response. - - Currently the only supported value is - `step_details.tool_calls[*].file_search.results[*].content` to fetch the file - search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - additional_instructions: Optional[str] - """Appends additional instructions at the end of the instructions for the run. - - This is useful for modifying the behavior on a per-run basis without overriding - other instructions. - """ - - additional_messages: Optional[Iterable[AdditionalMessage]] - """Adds additional messages to the thread before creating the run.""" - - instructions: Optional[str] - """ - Overrides the - [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - of the assistant. This is useful for modifying the behavior on a per-run basis. - """ - - max_completion_tokens: Optional[int] - """ - The maximum number of completion tokens that may be used over the course of the - run. The run will make a best effort to use only the number of completion tokens - specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - """ - - max_prompt_tokens: Optional[int] - """The maximum number of prompt tokens that may be used over the course of the run. - - The run will make a best effort to use only the number of prompt tokens - specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `incomplete`. See - `incomplete_details` for more info. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Union[str, ChatModel, None] - """ - The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - be used to execute this run. If a value is provided here, it will override the - model associated with the assistant. If not, the model associated with the - assistant will be used. - """ - - parallel_tool_calls: bool - """ - Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - """ - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: Optional[AssistantResponseFormatOptionParam] - """Specifies the format that the model must output. - - Compatible with [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), - [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4), - and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - message the model generates is valid JSON. - - **Important:** when using JSON mode, you **must** also instruct the model to - produce JSON yourself via a system or user message. Without this, the model may - generate an unending stream of whitespace until the generation reaches the token - limit, resulting in a long-running and seemingly "stuck" request. Also note that - the message content may be partially cut off if `finish_reason="length"`, which - indicates the generation exceeded `max_tokens` or the conversation exceeded the - max context length. - """ - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - """ - - tool_choice: Optional[AssistantToolChoiceOptionParam] - """ - Controls which (if any) tool is called by the model. `none` means the model will - not call any tools and instead generates a message. `auto` is the default value - and means the model can pick between generating a message or calling one or more - tools. `required` means the model must call one or more tools before responding - to the user. Specifying a particular tool like `{"type": "file_search"}` or - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - """ - - tools: Optional[Iterable[AssistantToolParam]] - """Override the tools the assistant can use for this run. - - This is useful for modifying the behavior on a per-run basis. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or temperature but not both. - """ - - truncation_strategy: Optional[TruncationStrategy] - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - -class AdditionalMessageAttachmentToolFileSearch(TypedDict, total=False): - type: Required[Literal["file_search"]] - """The type of tool being defined: `file_search`""" - - -AdditionalMessageAttachmentTool: TypeAlias = Union[CodeInterpreterToolParam, AdditionalMessageAttachmentToolFileSearch] - - -class AdditionalMessageAttachment(TypedDict, total=False): - file_id: str - """The ID of the file to attach to the message.""" - - tools: Iterable[AdditionalMessageAttachmentTool] - """The tools to add this file to.""" - - -class AdditionalMessage(TypedDict, total=False): - content: Required[Union[str, Iterable[MessageContentPartParam]]] - """The text contents of the message.""" - - role: Required[Literal["user", "assistant"]] - """The role of the entity that is creating the message. Allowed values include: - - - `user`: Indicates the message is sent by an actual user and should be used in - most cases to represent user-generated messages. - - `assistant`: Indicates the message is generated by the assistant. Use this - value to insert messages from the assistant into the conversation. - """ - - attachments: Optional[Iterable[AdditionalMessageAttachment]] - """A list of files attached to the message, and the tools they should be added to.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -class TruncationStrategy(TypedDict, total=False): - """Controls for how a thread will be truncated prior to the run. - - Use this to control the initial context window of the run. - """ - - type: Required[Literal["auto", "last_messages"]] - """The truncation strategy to use for the thread. - - The default is `auto`. If set to `last_messages`, the thread will be truncated - to the n most recent messages in the thread. When set to `auto`, messages in the - middle of the thread will be dropped to fit the context length of the model, - `max_prompt_tokens`. - """ - - last_messages: Optional[int] - """ - The number of most recent messages from the thread when constructing the context - for the run. - """ - - -class RunCreateParamsNonStreaming(RunCreateParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -class RunCreateParamsStreaming(RunCreateParamsBase): - stream: Required[Literal[True]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -RunCreateParams = Union[RunCreateParamsNonStreaming, RunCreateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_list_params.py deleted file mode 100644 index fbea54f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_list_params.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["RunListParams"] - - -class RunListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_status.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_status.py deleted file mode 100644 index 47c7cbd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_status.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["RunStatus"] - -RunStatus: TypeAlias = Literal[ - "queued", - "in_progress", - "requires_action", - "cancelling", - "cancelled", - "failed", - "completed", - "incomplete", - "expired", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_submit_tool_outputs_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_submit_tool_outputs_params.py deleted file mode 100644 index 1477286..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_submit_tool_outputs_params.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = [ - "RunSubmitToolOutputsParamsBase", - "ToolOutput", - "RunSubmitToolOutputsParamsNonStreaming", - "RunSubmitToolOutputsParamsStreaming", -] - - -class RunSubmitToolOutputsParamsBase(TypedDict, total=False): - thread_id: Required[str] - - tool_outputs: Required[Iterable[ToolOutput]] - """A list of tools for which the outputs are being submitted.""" - - -class ToolOutput(TypedDict, total=False): - output: str - """The output of the tool call to be submitted to continue the run.""" - - tool_call_id: str - """ - The ID of the tool call in the `required_action` object within the run object - the output is being submitted for. - """ - - -class RunSubmitToolOutputsParamsNonStreaming(RunSubmitToolOutputsParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -class RunSubmitToolOutputsParamsStreaming(RunSubmitToolOutputsParamsBase): - stream: Required[Literal[True]] - """ - If `true`, returns a stream of events that happen during the Run as server-sent - events, terminating when the Run enters a terminal state with a `data: [DONE]` - message. - """ - - -RunSubmitToolOutputsParams = Union[RunSubmitToolOutputsParamsNonStreaming, RunSubmitToolOutputsParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_update_params.py deleted file mode 100644 index fbcbd3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/run_update_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from ...shared_params.metadata import Metadata - -__all__ = ["RunUpdateParams"] - - -class RunUpdateParams(TypedDict, total=False): - thread_id: Required[str] - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/__init__.py deleted file mode 100644 index 467d5d7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .run_step import RunStep as RunStep -from .tool_call import ToolCall as ToolCall -from .run_step_delta import RunStepDelta as RunStepDelta -from .tool_call_delta import ToolCallDelta as ToolCallDelta -from .run_step_include import RunStepInclude as RunStepInclude -from .step_list_params import StepListParams as StepListParams -from .function_tool_call import FunctionToolCall as FunctionToolCall -from .run_step_delta_event import RunStepDeltaEvent as RunStepDeltaEvent -from .step_retrieve_params import StepRetrieveParams as StepRetrieveParams -from .code_interpreter_logs import CodeInterpreterLogs as CodeInterpreterLogs -from .file_search_tool_call import FileSearchToolCall as FileSearchToolCall -from .tool_call_delta_object import ToolCallDeltaObject as ToolCallDeltaObject -from .tool_calls_step_details import ToolCallsStepDetails as ToolCallsStepDetails -from .function_tool_call_delta import FunctionToolCallDelta as FunctionToolCallDelta -from .code_interpreter_tool_call import CodeInterpreterToolCall as CodeInterpreterToolCall -from .file_search_tool_call_delta import FileSearchToolCallDelta as FileSearchToolCallDelta -from .run_step_delta_message_delta import RunStepDeltaMessageDelta as RunStepDeltaMessageDelta -from .code_interpreter_output_image import CodeInterpreterOutputImage as CodeInterpreterOutputImage -from .message_creation_step_details import MessageCreationStepDetails as MessageCreationStepDetails -from .code_interpreter_tool_call_delta import CodeInterpreterToolCallDelta as CodeInterpreterToolCallDelta diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_logs.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_logs.py deleted file mode 100644 index 722fd2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_logs.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["CodeInterpreterLogs"] - - -class CodeInterpreterLogs(BaseModel): - """Text output from the Code Interpreter tool call as part of a run step.""" - - index: int - """The index of the output in the outputs array.""" - - type: Literal["logs"] - """Always `logs`.""" - - logs: Optional[str] = None - """The text output from the Code Interpreter tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_output_image.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_output_image.py deleted file mode 100644 index 2257f37..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_output_image.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["CodeInterpreterOutputImage", "Image"] - - -class Image(BaseModel): - file_id: Optional[str] = None - """ - The [file](https://platform.openai.com/docs/api-reference/files) ID of the - image. - """ - - -class CodeInterpreterOutputImage(BaseModel): - index: int - """The index of the output in the outputs array.""" - - type: Literal["image"] - """Always `image`.""" - - image: Optional[Image] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call.py deleted file mode 100644 index bc78b5f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call.py +++ /dev/null @@ -1,76 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ....._utils import PropertyInfo -from ....._models import BaseModel - -__all__ = [ - "CodeInterpreterToolCall", - "CodeInterpreter", - "CodeInterpreterOutput", - "CodeInterpreterOutputLogs", - "CodeInterpreterOutputImage", - "CodeInterpreterOutputImageImage", -] - - -class CodeInterpreterOutputLogs(BaseModel): - """Text output from the Code Interpreter tool call as part of a run step.""" - - logs: str - """The text output from the Code Interpreter tool call.""" - - type: Literal["logs"] - """Always `logs`.""" - - -class CodeInterpreterOutputImageImage(BaseModel): - file_id: str - """ - The [file](https://platform.openai.com/docs/api-reference/files) ID of the - image. - """ - - -class CodeInterpreterOutputImage(BaseModel): - image: CodeInterpreterOutputImageImage - - type: Literal["image"] - """Always `image`.""" - - -CodeInterpreterOutput: TypeAlias = Annotated[ - Union[CodeInterpreterOutputLogs, CodeInterpreterOutputImage], PropertyInfo(discriminator="type") -] - - -class CodeInterpreter(BaseModel): - """The Code Interpreter tool call definition.""" - - input: str - """The input to the Code Interpreter tool call.""" - - outputs: List[CodeInterpreterOutput] - """The outputs from the Code Interpreter tool call. - - Code Interpreter can output one or more items, including text (`logs`) or images - (`image`). Each of these are represented by a different object type. - """ - - -class CodeInterpreterToolCall(BaseModel): - """Details of the Code Interpreter tool call the run step was involved in.""" - - id: str - """The ID of the tool call.""" - - code_interpreter: CodeInterpreter - """The Code Interpreter tool call definition.""" - - type: Literal["code_interpreter"] - """The type of tool call. - - This is always going to be `code_interpreter` for this type of tool call. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py deleted file mode 100644 index efedac7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/code_interpreter_tool_call_delta.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ....._utils import PropertyInfo -from ....._models import BaseModel -from .code_interpreter_logs import CodeInterpreterLogs -from .code_interpreter_output_image import CodeInterpreterOutputImage - -__all__ = ["CodeInterpreterToolCallDelta", "CodeInterpreter", "CodeInterpreterOutput"] - -CodeInterpreterOutput: TypeAlias = Annotated[ - Union[CodeInterpreterLogs, CodeInterpreterOutputImage], PropertyInfo(discriminator="type") -] - - -class CodeInterpreter(BaseModel): - """The Code Interpreter tool call definition.""" - - input: Optional[str] = None - """The input to the Code Interpreter tool call.""" - - outputs: Optional[List[CodeInterpreterOutput]] = None - """The outputs from the Code Interpreter tool call. - - Code Interpreter can output one or more items, including text (`logs`) or images - (`image`). Each of these are represented by a different object type. - """ - - -class CodeInterpreterToolCallDelta(BaseModel): - """Details of the Code Interpreter tool call the run step was involved in.""" - - index: int - """The index of the tool call in the tool calls array.""" - - type: Literal["code_interpreter"] - """The type of tool call. - - This is always going to be `code_interpreter` for this type of tool call. - """ - - id: Optional[str] = None - """The ID of the tool call.""" - - code_interpreter: Optional[CodeInterpreter] = None - """The Code Interpreter tool call definition.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call.py deleted file mode 100644 index 291a93e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call.py +++ /dev/null @@ -1,84 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = [ - "FileSearchToolCall", - "FileSearch", - "FileSearchRankingOptions", - "FileSearchResult", - "FileSearchResultContent", -] - - -class FileSearchRankingOptions(BaseModel): - """The ranking options for the file search.""" - - ranker: Literal["auto", "default_2024_08_21"] - """The ranker to use for the file search. - - If not specified will use the `auto` ranker. - """ - - score_threshold: float - """The score threshold for the file search. - - All values must be a floating point number between 0 and 1. - """ - - -class FileSearchResultContent(BaseModel): - text: Optional[str] = None - """The text content of the file.""" - - type: Optional[Literal["text"]] = None - """The type of the content.""" - - -class FileSearchResult(BaseModel): - """A result instance of the file search.""" - - file_id: str - """The ID of the file that result was found in.""" - - file_name: str - """The name of the file that result was found in.""" - - score: float - """The score of the result. - - All values must be a floating point number between 0 and 1. - """ - - content: Optional[List[FileSearchResultContent]] = None - """The content of the result that was found. - - The content is only included if requested via the include query parameter. - """ - - -class FileSearch(BaseModel): - """For now, this is always going to be an empty object.""" - - ranking_options: Optional[FileSearchRankingOptions] = None - """The ranking options for the file search.""" - - results: Optional[List[FileSearchResult]] = None - """The results of the file search.""" - - -class FileSearchToolCall(BaseModel): - id: str - """The ID of the tool call object.""" - - file_search: FileSearch - """For now, this is always going to be an empty object.""" - - type: Literal["file_search"] - """The type of tool call. - - This is always going to be `file_search` for this type of tool call. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call_delta.py deleted file mode 100644 index df5ac21..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/file_search_tool_call_delta.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["FileSearchToolCallDelta"] - - -class FileSearchToolCallDelta(BaseModel): - file_search: object - """For now, this is always going to be an empty object.""" - - index: int - """The index of the tool call in the tool calls array.""" - - type: Literal["file_search"] - """The type of tool call. - - This is always going to be `file_search` for this type of tool call. - """ - - id: Optional[str] = None - """The ID of the tool call object.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call.py deleted file mode 100644 index dd0e22c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["FunctionToolCall", "Function"] - - -class Function(BaseModel): - """The definition of the function that was called.""" - - arguments: str - """The arguments passed to the function.""" - - name: str - """The name of the function.""" - - output: Optional[str] = None - """The output of the function. - - This will be `null` if the outputs have not been - [submitted](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs) - yet. - """ - - -class FunctionToolCall(BaseModel): - id: str - """The ID of the tool call object.""" - - function: Function - """The definition of the function that was called.""" - - type: Literal["function"] - """The type of tool call. - - This is always going to be `function` for this type of tool call. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call_delta.py deleted file mode 100644 index 4107e1b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/function_tool_call_delta.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["FunctionToolCallDelta", "Function"] - - -class Function(BaseModel): - """The definition of the function that was called.""" - - arguments: Optional[str] = None - """The arguments passed to the function.""" - - name: Optional[str] = None - """The name of the function.""" - - output: Optional[str] = None - """The output of the function. - - This will be `null` if the outputs have not been - [submitted](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs) - yet. - """ - - -class FunctionToolCallDelta(BaseModel): - index: int - """The index of the tool call in the tool calls array.""" - - type: Literal["function"] - """The type of tool call. - - This is always going to be `function` for this type of tool call. - """ - - id: Optional[str] = None - """The ID of the tool call object.""" - - function: Optional[Function] = None - """The definition of the function that was called.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/message_creation_step_details.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/message_creation_step_details.py deleted file mode 100644 index cd925b5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/message_creation_step_details.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["MessageCreationStepDetails", "MessageCreation"] - - -class MessageCreation(BaseModel): - message_id: str - """The ID of the message that was created by this run step.""" - - -class MessageCreationStepDetails(BaseModel): - """Details of the message creation by the run step.""" - - message_creation: MessageCreation - - type: Literal["message_creation"] - """Always `message_creation`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step.py deleted file mode 100644 index 9745122..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step.py +++ /dev/null @@ -1,127 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ....._utils import PropertyInfo -from ....._models import BaseModel -from ....shared.metadata import Metadata -from .tool_calls_step_details import ToolCallsStepDetails -from .message_creation_step_details import MessageCreationStepDetails - -__all__ = ["RunStep", "LastError", "StepDetails", "Usage"] - - -class LastError(BaseModel): - """The last error associated with this run step. - - Will be `null` if there are no errors. - """ - - code: Literal["server_error", "rate_limit_exceeded"] - """One of `server_error` or `rate_limit_exceeded`.""" - - message: str - """A human-readable description of the error.""" - - -StepDetails: TypeAlias = Annotated[ - Union[MessageCreationStepDetails, ToolCallsStepDetails], PropertyInfo(discriminator="type") -] - - -class Usage(BaseModel): - """Usage statistics related to the run step. - - This value will be `null` while the run step's status is `in_progress`. - """ - - completion_tokens: int - """Number of completion tokens used over the course of the run step.""" - - prompt_tokens: int - """Number of prompt tokens used over the course of the run step.""" - - total_tokens: int - """Total number of tokens used (prompt + completion).""" - - -class RunStep(BaseModel): - """Represents a step in execution of a run.""" - - id: str - """The identifier of the run step, which can be referenced in API endpoints.""" - - assistant_id: str - """ - The ID of the - [assistant](https://platform.openai.com/docs/api-reference/assistants) - associated with the run step. - """ - - cancelled_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run step was cancelled.""" - - completed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run step completed.""" - - created_at: int - """The Unix timestamp (in seconds) for when the run step was created.""" - - expired_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run step expired. - - A step is considered expired if the parent run is expired. - """ - - failed_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the run step failed.""" - - last_error: Optional[LastError] = None - """The last error associated with this run step. - - Will be `null` if there are no errors. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - object: Literal["thread.run.step"] - """The object type, which is always `thread.run.step`.""" - - run_id: str - """ - The ID of the [run](https://platform.openai.com/docs/api-reference/runs) that - this run step is a part of. - """ - - status: Literal["in_progress", "cancelled", "failed", "completed", "expired"] - """ - The status of the run step, which can be either `in_progress`, `cancelled`, - `failed`, `completed`, or `expired`. - """ - - step_details: StepDetails - """The details of the run step.""" - - thread_id: str - """ - The ID of the [thread](https://platform.openai.com/docs/api-reference/threads) - that was run. - """ - - type: Literal["message_creation", "tool_calls"] - """The type of run step, which can be either `message_creation` or `tool_calls`.""" - - usage: Optional[Usage] = None - """Usage statistics related to the run step. - - This value will be `null` while the run step's status is `in_progress`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta.py deleted file mode 100644 index 2ccb770..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Annotated, TypeAlias - -from ....._utils import PropertyInfo -from ....._models import BaseModel -from .tool_call_delta_object import ToolCallDeltaObject -from .run_step_delta_message_delta import RunStepDeltaMessageDelta - -__all__ = ["RunStepDelta", "StepDetails"] - -StepDetails: TypeAlias = Annotated[ - Union[RunStepDeltaMessageDelta, ToolCallDeltaObject], PropertyInfo(discriminator="type") -] - - -class RunStepDelta(BaseModel): - """The delta containing the fields that have changed on the run step.""" - - step_details: Optional[StepDetails] = None - """The details of the run step.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_event.py deleted file mode 100644 index 8f1c095..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ....._models import BaseModel -from .run_step_delta import RunStepDelta - -__all__ = ["RunStepDeltaEvent"] - - -class RunStepDeltaEvent(BaseModel): - """Represents a run step delta i.e. - - any changed fields on a run step during streaming. - """ - - id: str - """The identifier of the run step, which can be referenced in API endpoints.""" - - delta: RunStepDelta - """The delta containing the fields that have changed on the run step.""" - - object: Literal["thread.run.step.delta"] - """The object type, which is always `thread.run.step.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_message_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_message_delta.py deleted file mode 100644 index 4b18277..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_delta_message_delta.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ....._models import BaseModel - -__all__ = ["RunStepDeltaMessageDelta", "MessageCreation"] - - -class MessageCreation(BaseModel): - message_id: Optional[str] = None - """The ID of the message that was created by this run step.""" - - -class RunStepDeltaMessageDelta(BaseModel): - """Details of the message creation by the run step.""" - - type: Literal["message_creation"] - """Always `message_creation`.""" - - message_creation: Optional[MessageCreation] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_include.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_include.py deleted file mode 100644 index 8e76c1b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/run_step_include.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["RunStepInclude"] - -RunStepInclude: TypeAlias = Literal["step_details.tool_calls[*].file_search.results[*].content"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_list_params.py deleted file mode 100644 index a6be771..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_list_params.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, Required, TypedDict - -from .run_step_include import RunStepInclude - -__all__ = ["StepListParams"] - - -class StepListParams(TypedDict, total=False): - thread_id: Required[str] - - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - include: List[RunStepInclude] - """A list of additional fields to include in the response. - - Currently the only supported value is - `step_details.tool_calls[*].file_search.results[*].content` to fetch the file - search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_retrieve_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_retrieve_params.py deleted file mode 100644 index ecbb72e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/step_retrieve_params.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Required, TypedDict - -from .run_step_include import RunStepInclude - -__all__ = ["StepRetrieveParams"] - - -class StepRetrieveParams(TypedDict, total=False): - thread_id: Required[str] - - run_id: Required[str] - - include: List[RunStepInclude] - """A list of additional fields to include in the response. - - Currently the only supported value is - `step_details.tool_calls[*].file_search.results[*].content` to fetch the file - search result content. - - See the - [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) - for more information. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call.py deleted file mode 100644 index 565e310..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ....._utils import PropertyInfo -from .function_tool_call import FunctionToolCall -from .file_search_tool_call import FileSearchToolCall -from .code_interpreter_tool_call import CodeInterpreterToolCall - -__all__ = ["ToolCall"] - -ToolCall: TypeAlias = Annotated[ - Union[CodeInterpreterToolCall, FileSearchToolCall, FunctionToolCall], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta.py deleted file mode 100644 index f0b8070..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ....._utils import PropertyInfo -from .function_tool_call_delta import FunctionToolCallDelta -from .file_search_tool_call_delta import FileSearchToolCallDelta -from .code_interpreter_tool_call_delta import CodeInterpreterToolCallDelta - -__all__ = ["ToolCallDelta"] - -ToolCallDelta: TypeAlias = Annotated[ - Union[CodeInterpreterToolCallDelta, FileSearchToolCallDelta, FunctionToolCallDelta], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta_object.py deleted file mode 100644 index dbd1096..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_call_delta_object.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ....._models import BaseModel -from .tool_call_delta import ToolCallDelta - -__all__ = ["ToolCallDeltaObject"] - - -class ToolCallDeltaObject(BaseModel): - """Details of the tool call.""" - - type: Literal["tool_calls"] - """Always `tool_calls`.""" - - tool_calls: Optional[List[ToolCallDelta]] = None - """An array of tool calls the run step was involved in. - - These can be associated with one of three types of tools: `code_interpreter`, - `file_search`, or `function`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_calls_step_details.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_calls_step_details.py deleted file mode 100644 index 1f54a6a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/runs/tool_calls_step_details.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from .tool_call import ToolCall -from ....._models import BaseModel - -__all__ = ["ToolCallsStepDetails"] - - -class ToolCallsStepDetails(BaseModel): - """Details of the tool call.""" - - tool_calls: List[ToolCall] - """An array of tool calls the run step was involved in. - - These can be associated with one of three types of tools: `code_interpreter`, - `file_search`, or `function`. - """ - - type: Literal["tool_calls"] - """Always `tool_calls`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text.py deleted file mode 100644 index 853bec2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ...._models import BaseModel -from .annotation import Annotation - -__all__ = ["Text"] - - -class Text(BaseModel): - annotations: List[Annotation] - - value: str - """The data that makes up the text.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block.py deleted file mode 100644 index b9b1368..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .text import Text -from ...._models import BaseModel - -__all__ = ["TextContentBlock"] - - -class TextContentBlock(BaseModel): - """The text content that is part of a message.""" - - text: Text - - type: Literal["text"] - """Always `text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block_param.py deleted file mode 100644 index 22c8644..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_content_block_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TextContentBlockParam"] - - -class TextContentBlockParam(TypedDict, total=False): - """The text content that is part of a message.""" - - text: Required[str] - """Text content to be sent to the model""" - - type: Required[Literal["text"]] - """Always `text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta.py deleted file mode 100644 index 09cd357..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ...._models import BaseModel -from .annotation_delta import AnnotationDelta - -__all__ = ["TextDelta"] - - -class TextDelta(BaseModel): - annotations: Optional[List[AnnotationDelta]] = None - - value: Optional[str] = None - """The data that makes up the text.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta_block.py b/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta_block.py deleted file mode 100644 index a3d339c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/beta/threads/text_delta_block.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel -from .text_delta import TextDelta - -__all__ = ["TextDeltaBlock"] - - -class TextDeltaBlock(BaseModel): - """The text content that is part of a message.""" - - index: int - """The index of the content part in the message.""" - - type: Literal["text"] - """Always `text`.""" - - text: Optional[TextDelta] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/__init__.py deleted file mode 100644 index 50bdac7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/__init__.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .chat_completion import ChatCompletion as ChatCompletion -from .chat_completion_role import ChatCompletionRole as ChatCompletionRole -from .chat_completion_audio import ChatCompletionAudio as ChatCompletionAudio -from .chat_completion_chunk import ChatCompletionChunk as ChatCompletionChunk -from .completion_list_params import CompletionListParams as CompletionListParams -from .parsed_chat_completion import ( - ParsedChoice as ParsedChoice, - ParsedChatCompletion as ParsedChatCompletion, - ParsedChatCompletionMessage as ParsedChatCompletionMessage, -) -from .chat_completion_deleted import ChatCompletionDeleted as ChatCompletionDeleted -from .chat_completion_message import ChatCompletionMessage as ChatCompletionMessage -from .chat_completion_modality import ChatCompletionModality as ChatCompletionModality -from .completion_create_params import CompletionCreateParams as CompletionCreateParams -from .completion_update_params import CompletionUpdateParams as CompletionUpdateParams -from .parsed_function_tool_call import ( - ParsedFunction as ParsedFunction, - ParsedFunctionToolCall as ParsedFunctionToolCall, -) -from .chat_completion_tool_param import ChatCompletionToolParam as ChatCompletionToolParam -from .chat_completion_audio_param import ChatCompletionAudioParam as ChatCompletionAudioParam -from .chat_completion_function_tool import ChatCompletionFunctionTool as ChatCompletionFunctionTool -from .chat_completion_message_param import ChatCompletionMessageParam as ChatCompletionMessageParam -from .chat_completion_store_message import ChatCompletionStoreMessage as ChatCompletionStoreMessage -from .chat_completion_token_logprob import ChatCompletionTokenLogprob as ChatCompletionTokenLogprob -from .chat_completion_reasoning_effort import ChatCompletionReasoningEffort as ChatCompletionReasoningEffort -from .chat_completion_tool_union_param import ChatCompletionToolUnionParam as ChatCompletionToolUnionParam -from .chat_completion_content_part_text import ChatCompletionContentPartText as ChatCompletionContentPartText -from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam as ChatCompletionCustomToolParam -from .chat_completion_message_tool_call import ( - ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, - ChatCompletionMessageToolCallUnion as ChatCompletionMessageToolCallUnion, -) -from .chat_completion_content_part_image import ChatCompletionContentPartImage as ChatCompletionContentPartImage -from .chat_completion_content_part_param import ChatCompletionContentPartParam as ChatCompletionContentPartParam -from .chat_completion_tool_message_param import ChatCompletionToolMessageParam as ChatCompletionToolMessageParam -from .chat_completion_user_message_param import ChatCompletionUserMessageParam as ChatCompletionUserMessageParam -from .chat_completion_allowed_tools_param import ChatCompletionAllowedToolsParam as ChatCompletionAllowedToolsParam -from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam as ChatCompletionFunctionToolParam -from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam as ChatCompletionStreamOptionsParam -from .chat_completion_system_message_param import ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam -from .chat_completion_function_message_param import ( - ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, -) -from .chat_completion_assistant_message_param import ( - ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, -) -from .chat_completion_content_part_text_param import ( - ChatCompletionContentPartTextParam as ChatCompletionContentPartTextParam, -) -from .chat_completion_developer_message_param import ( - ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, -) -from .chat_completion_message_tool_call_param import ( - ChatCompletionMessageToolCallParam as ChatCompletionMessageToolCallParam, -) -from .chat_completion_named_tool_choice_param import ( - ChatCompletionNamedToolChoiceParam as ChatCompletionNamedToolChoiceParam, -) -from .chat_completion_content_part_image_param import ( - ChatCompletionContentPartImageParam as ChatCompletionContentPartImageParam, -) -from .chat_completion_message_custom_tool_call import ( - ChatCompletionMessageCustomToolCall as ChatCompletionMessageCustomToolCall, -) -from .chat_completion_prediction_content_param import ( - ChatCompletionPredictionContentParam as ChatCompletionPredictionContentParam, -) -from .chat_completion_tool_choice_option_param import ( - ChatCompletionToolChoiceOptionParam as ChatCompletionToolChoiceOptionParam, -) -from .chat_completion_allowed_tool_choice_param import ( - ChatCompletionAllowedToolChoiceParam as ChatCompletionAllowedToolChoiceParam, -) -from .chat_completion_content_part_refusal_param import ( - ChatCompletionContentPartRefusalParam as ChatCompletionContentPartRefusalParam, -) -from .chat_completion_function_call_option_param import ( - ChatCompletionFunctionCallOptionParam as ChatCompletionFunctionCallOptionParam, -) -from .chat_completion_message_function_tool_call import ( - ChatCompletionMessageFunctionToolCall as ChatCompletionMessageFunctionToolCall, -) -from .chat_completion_message_tool_call_union_param import ( - ChatCompletionMessageToolCallUnionParam as ChatCompletionMessageToolCallUnionParam, -) -from .chat_completion_content_part_input_audio_param import ( - ChatCompletionContentPartInputAudioParam as ChatCompletionContentPartInputAudioParam, -) -from .chat_completion_message_custom_tool_call_param import ( - ChatCompletionMessageCustomToolCallParam as ChatCompletionMessageCustomToolCallParam, -) -from .chat_completion_named_tool_choice_custom_param import ( - ChatCompletionNamedToolChoiceCustomParam as ChatCompletionNamedToolChoiceCustomParam, -) -from .chat_completion_message_function_tool_call_param import ( - ChatCompletionMessageFunctionToolCallParam as ChatCompletionMessageFunctionToolCallParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion.py deleted file mode 100644 index 31219aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion.py +++ /dev/null @@ -1,95 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..completion_usage import CompletionUsage -from .chat_completion_message import ChatCompletionMessage -from .chat_completion_token_logprob import ChatCompletionTokenLogprob - -__all__ = ["ChatCompletion", "Choice", "ChoiceLogprobs"] - - -class ChoiceLogprobs(BaseModel): - """Log probability information for the choice.""" - - content: Optional[List[ChatCompletionTokenLogprob]] = None - """A list of message content tokens with log probability information.""" - - refusal: Optional[List[ChatCompletionTokenLogprob]] = None - """A list of message refusal tokens with log probability information.""" - - -class Choice(BaseModel): - finish_reason: Literal["stop", "length", "tool_calls", "content_filter", "function_call"] - """The reason the model stopped generating tokens. - - This will be `stop` if the model hit a natural stop point or a provided stop - sequence, `length` if the maximum number of tokens specified in the request was - reached, `content_filter` if content was omitted due to a flag from our content - filters, `tool_calls` if the model called a tool, or `function_call` - (deprecated) if the model called a function. - """ - - index: int - """The index of the choice in the list of choices.""" - - logprobs: Optional[ChoiceLogprobs] = None - """Log probability information for the choice.""" - - message: ChatCompletionMessage - """A chat completion message generated by the model.""" - - -class ChatCompletion(BaseModel): - """ - Represents a chat completion response returned by model, based on the provided input. - """ - - id: str - """A unique identifier for the chat completion.""" - - choices: List[Choice] - """A list of chat completion choices. - - Can be more than one if `n` is greater than 1. - """ - - created: int - """The Unix timestamp (in seconds) of when the chat completion was created.""" - - model: str - """The model used for the chat completion.""" - - object: Literal["chat.completion"] - """The object type, which is always `chat.completion`.""" - - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None - """Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - """ - - system_fingerprint: Optional[str] = None - """This fingerprint represents the backend configuration that the model runs with. - - Can be used in conjunction with the `seed` request parameter to understand when - backend changes have been made that might impact determinism. - """ - - usage: Optional[CompletionUsage] = None - """Usage statistics for the completion request.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tool_choice_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tool_choice_param.py deleted file mode 100644 index c5ba216..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tool_choice_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_allowed_tools_param import ChatCompletionAllowedToolsParam - -__all__ = ["ChatCompletionAllowedToolChoiceParam"] - - -class ChatCompletionAllowedToolChoiceParam(TypedDict, total=False): - """Constrains the tools available to the model to a pre-defined set.""" - - allowed_tools: Required[ChatCompletionAllowedToolsParam] - """Constrains the tools available to the model to a pre-defined set.""" - - type: Required[Literal["allowed_tools"]] - """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tools_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tools_param.py deleted file mode 100644 index ac31fcb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_allowed_tools_param.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionAllowedToolsParam"] - - -class ChatCompletionAllowedToolsParam(TypedDict, total=False): - """Constrains the tools available to the model to a pre-defined set.""" - - mode: Required[Literal["auto", "required"]] - """Constrains the tools available to the model to a pre-defined set. - - `auto` allows the model to pick from among the allowed tools and generate a - message. - - `required` requires the model to call one or more of the allowed tools. - """ - - tools: Required[Iterable[Dict[str, object]]] - """A list of tool definitions that the model should be allowed to call. - - For the Chat Completions API, the list of tool definitions might look like: - - ```json - [ - { "type": "function", "function": { "name": "get_weather" } }, - { "type": "function", "function": { "name": "get_time" } } - ] - ``` - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_assistant_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_assistant_message_param.py deleted file mode 100644 index 16a2184..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_assistant_message_param.py +++ /dev/null @@ -1,82 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam -from .chat_completion_content_part_refusal_param import ChatCompletionContentPartRefusalParam -from .chat_completion_message_tool_call_union_param import ChatCompletionMessageToolCallUnionParam - -__all__ = ["ChatCompletionAssistantMessageParam", "Audio", "ContentArrayOfContentPart", "FunctionCall"] - - -class Audio(TypedDict, total=False): - """ - Data about a previous audio response from the model. - [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - id: Required[str] - """Unique identifier for a previous audio response from the model.""" - - -ContentArrayOfContentPart: TypeAlias = Union[ChatCompletionContentPartTextParam, ChatCompletionContentPartRefusalParam] - - -class FunctionCall(TypedDict, total=False): - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the model. - """ - - arguments: Required[str] - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: Required[str] - """The name of the function to call.""" - - -class ChatCompletionAssistantMessageParam(TypedDict, total=False): - """Messages sent by the model in response to user messages.""" - - role: Required[Literal["assistant"]] - """The role of the messages author, in this case `assistant`.""" - - audio: Optional[Audio] - """ - Data about a previous audio response from the model. - [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - content: Union[str, Iterable[ContentArrayOfContentPart], None] - """The contents of the assistant message. - - Required unless `tool_calls` or `function_call` is specified. - """ - - function_call: Optional[FunctionCall] - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the - model. - """ - - name: str - """An optional name for the participant. - - Provides the model information to differentiate between participants of the same - role. - """ - - refusal: Optional[str] - """The refusal message by the assistant.""" - - tool_calls: Iterable[ChatCompletionMessageToolCallUnionParam] - """The tool calls generated by the model, such as function calls.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio.py deleted file mode 100644 index df346d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["ChatCompletionAudio"] - - -class ChatCompletionAudio(BaseModel): - """ - If the audio output modality is requested, this object contains data - about the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - id: str - """Unique identifier for this audio response.""" - - data: str - """ - Base64 encoded audio bytes generated by the model, in the format specified in - the request. - """ - - expires_at: int - """ - The Unix timestamp (in seconds) for when this audio response will no longer be - accessible on the server for use in multi-turn conversations. - """ - - transcript: str - """Transcript of the audio generated by the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio_param.py deleted file mode 100644 index 1a73bb0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_audio_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionAudioParam"] - - -class ChatCompletionAudioParam(TypedDict, total=False): - """Parameters for audio output. - - Required when audio output is requested with - `modalities: ["audio"]`. [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - format: Required[Literal["wav", "aac", "mp3", "flac", "opus", "pcm16"]] - """Specifies the output audio format. - - Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`. - """ - - voice: Required[ - Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - ] - """The voice the model uses to respond. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, - `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_chunk.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_chunk.py deleted file mode 100644 index ecbfd0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_chunk.py +++ /dev/null @@ -1,181 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..completion_usage import CompletionUsage -from .chat_completion_token_logprob import ChatCompletionTokenLogprob - -__all__ = [ - "ChatCompletionChunk", - "Choice", - "ChoiceDelta", - "ChoiceDeltaFunctionCall", - "ChoiceDeltaToolCall", - "ChoiceDeltaToolCallFunction", - "ChoiceLogprobs", -] - - -class ChoiceDeltaFunctionCall(BaseModel): - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the model. - """ - - arguments: Optional[str] = None - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: Optional[str] = None - """The name of the function to call.""" - - -class ChoiceDeltaToolCallFunction(BaseModel): - arguments: Optional[str] = None - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: Optional[str] = None - """The name of the function to call.""" - - -class ChoiceDeltaToolCall(BaseModel): - index: int - - id: Optional[str] = None - """The ID of the tool call.""" - - function: Optional[ChoiceDeltaToolCallFunction] = None - - type: Optional[Literal["function"]] = None - """The type of the tool. Currently, only `function` is supported.""" - - -class ChoiceDelta(BaseModel): - """A chat completion delta generated by streamed model responses.""" - - content: Optional[str] = None - """The contents of the chunk message.""" - - function_call: Optional[ChoiceDeltaFunctionCall] = None - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the - model. - """ - - refusal: Optional[str] = None - """The refusal message generated by the model.""" - - role: Optional[Literal["developer", "system", "user", "assistant", "tool"]] = None - """The role of the author of this message.""" - - tool_calls: Optional[List[ChoiceDeltaToolCall]] = None - - -class ChoiceLogprobs(BaseModel): - """Log probability information for the choice.""" - - content: Optional[List[ChatCompletionTokenLogprob]] = None - """A list of message content tokens with log probability information.""" - - refusal: Optional[List[ChatCompletionTokenLogprob]] = None - """A list of message refusal tokens with log probability information.""" - - -class Choice(BaseModel): - delta: ChoiceDelta - """A chat completion delta generated by streamed model responses.""" - - finish_reason: Optional[Literal["stop", "length", "tool_calls", "content_filter", "function_call"]] = None - """The reason the model stopped generating tokens. - - This will be `stop` if the model hit a natural stop point or a provided stop - sequence, `length` if the maximum number of tokens specified in the request was - reached, `content_filter` if content was omitted due to a flag from our content - filters, `tool_calls` if the model called a tool, or `function_call` - (deprecated) if the model called a function. - """ - - index: int - """The index of the choice in the list of choices.""" - - logprobs: Optional[ChoiceLogprobs] = None - """Log probability information for the choice.""" - - -class ChatCompletionChunk(BaseModel): - """ - Represents a streamed chunk of a chat completion response returned - by the model, based on the provided input. - [Learn more](https://platform.openai.com/docs/guides/streaming-responses). - """ - - id: str - """A unique identifier for the chat completion. Each chunk has the same ID.""" - - choices: List[Choice] - """A list of chat completion choices. - - Can contain more than one elements if `n` is greater than 1. Can also be empty - for the last chunk if you set `stream_options: {"include_usage": true}`. - """ - - created: int - """The Unix timestamp (in seconds) of when the chat completion was created. - - Each chunk has the same timestamp. - """ - - model: str - """The model to generate the completion.""" - - object: Literal["chat.completion.chunk"] - """The object type, which is always `chat.completion.chunk`.""" - - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None - """Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - """ - - system_fingerprint: Optional[str] = None - """ - This fingerprint represents the backend configuration that the model runs with. - Can be used in conjunction with the `seed` request parameter to understand when - backend changes have been made that might impact determinism. - """ - - usage: Optional[CompletionUsage] = None - """ - An optional field that will only be present when you set - `stream_options: {"include_usage": true}` in your request. When present, it - contains a null value **except for the last chunk** which contains the token - usage statistics for the entire request. - - **NOTE:** If the stream is interrupted or cancelled, you may not receive the - final usage chunk which contains the total token usage for the request. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image.py deleted file mode 100644 index a636c51..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ChatCompletionContentPartImage", "ImageURL"] - - -class ImageURL(BaseModel): - url: str - """Either a URL of the image or the base64 encoded image data.""" - - detail: Optional[Literal["auto", "low", "high"]] = None - """Specifies the detail level of the image. - - Learn more in the - [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). - """ - - -class ChatCompletionContentPartImage(BaseModel): - """Learn about [image inputs](https://platform.openai.com/docs/guides/vision).""" - - image_url: ImageURL - - type: Literal["image_url"] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image_param.py deleted file mode 100644 index a230a34..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_image_param.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionContentPartImageParam", "ImageURL"] - - -class ImageURL(TypedDict, total=False): - url: Required[str] - """Either a URL of the image or the base64 encoded image data.""" - - detail: Literal["auto", "low", "high"] - """Specifies the detail level of the image. - - Learn more in the - [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). - """ - - -class ChatCompletionContentPartImageParam(TypedDict, total=False): - """Learn about [image inputs](https://platform.openai.com/docs/guides/vision).""" - - image_url: Required[ImageURL] - - type: Required[Literal["image_url"]] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_input_audio_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_input_audio_param.py deleted file mode 100644 index 98d9e3c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_input_audio_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionContentPartInputAudioParam", "InputAudio"] - - -class InputAudio(TypedDict, total=False): - data: Required[str] - """Base64 encoded audio data.""" - - format: Required[Literal["wav", "mp3"]] - """The format of the encoded audio data. Currently supports "wav" and "mp3".""" - - -class ChatCompletionContentPartInputAudioParam(TypedDict, total=False): - """Learn about [audio inputs](https://platform.openai.com/docs/guides/audio).""" - - input_audio: Required[InputAudio] - - type: Required[Literal["input_audio"]] - """The type of the content part. Always `input_audio`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_param.py deleted file mode 100644 index b8c710a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_param.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam -from .chat_completion_content_part_image_param import ChatCompletionContentPartImageParam -from .chat_completion_content_part_input_audio_param import ChatCompletionContentPartInputAudioParam - -__all__ = ["ChatCompletionContentPartParam", "File", "FileFile"] - - -class FileFile(TypedDict, total=False): - file_data: str - """ - The base64 encoded file data, used when passing the file to the model as a - string. - """ - - file_id: str - """The ID of an uploaded file to use as input.""" - - filename: str - """The name of the file, used when passing the file to the model as a string.""" - - -class File(TypedDict, total=False): - """ - Learn about [file inputs](https://platform.openai.com/docs/guides/text) for text generation. - """ - - file: Required[FileFile] - - type: Required[Literal["file"]] - """The type of the content part. Always `file`.""" - - -ChatCompletionContentPartParam: TypeAlias = Union[ - ChatCompletionContentPartTextParam, - ChatCompletionContentPartImageParam, - ChatCompletionContentPartInputAudioParam, - File, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_refusal_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_refusal_param.py deleted file mode 100644 index c18c7db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_refusal_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionContentPartRefusalParam"] - - -class ChatCompletionContentPartRefusalParam(TypedDict, total=False): - refusal: Required[str] - """The refusal message generated by the model.""" - - type: Required[Literal["refusal"]] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text.py deleted file mode 100644 index e6d1bf1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ChatCompletionContentPartText"] - - -class ChatCompletionContentPartText(BaseModel): - """ - Learn about [text inputs](https://platform.openai.com/docs/guides/text-generation). - """ - - text: str - """The text content.""" - - type: Literal["text"] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text_param.py deleted file mode 100644 index be69bf6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_content_part_text_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionContentPartTextParam"] - - -class ChatCompletionContentPartTextParam(TypedDict, total=False): - """ - Learn about [text inputs](https://platform.openai.com/docs/guides/text-generation). - """ - - text: Required[str] - """The text content.""" - - type: Required[Literal["text"]] - """The type of the content part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_custom_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_custom_tool_param.py deleted file mode 100644 index d4f21ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_custom_tool_param.py +++ /dev/null @@ -1,68 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = [ - "ChatCompletionCustomToolParam", - "Custom", - "CustomFormat", - "CustomFormatText", - "CustomFormatGrammar", - "CustomFormatGrammarGrammar", -] - - -class CustomFormatText(TypedDict, total=False): - """Unconstrained free-form text.""" - - type: Required[Literal["text"]] - """Unconstrained text format. Always `text`.""" - - -class CustomFormatGrammarGrammar(TypedDict, total=False): - """Your chosen grammar.""" - - definition: Required[str] - """The grammar definition.""" - - syntax: Required[Literal["lark", "regex"]] - """The syntax of the grammar definition. One of `lark` or `regex`.""" - - -class CustomFormatGrammar(TypedDict, total=False): - """A grammar defined by the user.""" - - grammar: Required[CustomFormatGrammarGrammar] - """Your chosen grammar.""" - - type: Required[Literal["grammar"]] - """Grammar format. Always `grammar`.""" - - -CustomFormat: TypeAlias = Union[CustomFormatText, CustomFormatGrammar] - - -class Custom(TypedDict, total=False): - """Properties of the custom tool.""" - - name: Required[str] - """The name of the custom tool, used to identify it in tool calls.""" - - description: str - """Optional description of the custom tool, used to provide more context.""" - - format: CustomFormat - """The input format for the custom tool. Default is unconstrained text.""" - - -class ChatCompletionCustomToolParam(TypedDict, total=False): - """A custom tool that processes input using a specified format.""" - - custom: Required[Custom] - """Properties of the custom tool.""" - - type: Required[Literal["custom"]] - """The type of the custom tool. Always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_deleted.py deleted file mode 100644 index 0a541cb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_deleted.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ChatCompletionDeleted"] - - -class ChatCompletionDeleted(BaseModel): - id: str - """The ID of the chat completion that was deleted.""" - - deleted: bool - """Whether the chat completion was deleted.""" - - object: Literal["chat.completion.deleted"] - """The type of object being deleted.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_developer_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_developer_message_param.py deleted file mode 100644 index 94fb335..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_developer_message_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam - -__all__ = ["ChatCompletionDeveloperMessageParam"] - - -class ChatCompletionDeveloperMessageParam(TypedDict, total=False): - """ - Developer-provided instructions that the model should follow, regardless of - messages sent by the user. With o1 models and newer, `developer` messages - replace the previous `system` messages. - """ - - content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] - """The contents of the developer message.""" - - role: Required[Literal["developer"]] - """The role of the messages author, in this case `developer`.""" - - name: str - """An optional name for the participant. - - Provides the model information to differentiate between participants of the same - role. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_call_option_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_call_option_param.py deleted file mode 100644 index b1ca37b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_call_option_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ChatCompletionFunctionCallOptionParam"] - - -class ChatCompletionFunctionCallOptionParam(TypedDict, total=False): - """ - Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. - """ - - name: Required[str] - """The name of the function to call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_message_param.py deleted file mode 100644 index 5af12bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_message_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionFunctionMessageParam"] - - -class ChatCompletionFunctionMessageParam(TypedDict, total=False): - content: Required[Optional[str]] - """The contents of the function message.""" - - name: Required[str] - """The name of the function to call.""" - - role: Required[Literal["function"]] - """The role of the messages author, in this case `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool.py deleted file mode 100644 index 5d43a1e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.function_definition import FunctionDefinition - -__all__ = ["ChatCompletionFunctionTool"] - - -class ChatCompletionFunctionTool(BaseModel): - """A function tool that can be used to generate a response.""" - - function: FunctionDefinition - - type: Literal["function"] - """The type of the tool. Currently, only `function` is supported.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool_param.py deleted file mode 100644 index d336e8c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_function_tool_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ..shared_params.function_definition import FunctionDefinition - -__all__ = ["ChatCompletionFunctionToolParam"] - - -class ChatCompletionFunctionToolParam(TypedDict, total=False): - """A function tool that can be used to generate a response.""" - - function: Required[FunctionDefinition] - - type: Required[Literal["function"]] - """The type of the tool. Currently, only `function` is supported.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message.py deleted file mode 100644 index 3f88f77..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message.py +++ /dev/null @@ -1,90 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .chat_completion_audio import ChatCompletionAudio -from .chat_completion_message_tool_call import ChatCompletionMessageToolCallUnion - -__all__ = ["ChatCompletionMessage", "Annotation", "AnnotationURLCitation", "FunctionCall"] - - -class AnnotationURLCitation(BaseModel): - """A URL citation when using web search.""" - - end_index: int - """The index of the last character of the URL citation in the message.""" - - start_index: int - """The index of the first character of the URL citation in the message.""" - - title: str - """The title of the web resource.""" - - url: str - """The URL of the web resource.""" - - -class Annotation(BaseModel): - """A URL citation when using web search.""" - - type: Literal["url_citation"] - """The type of the URL citation. Always `url_citation`.""" - - url_citation: AnnotationURLCitation - """A URL citation when using web search.""" - - -class FunctionCall(BaseModel): - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the model. - """ - - arguments: str - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: str - """The name of the function to call.""" - - -class ChatCompletionMessage(BaseModel): - """A chat completion message generated by the model.""" - - content: Optional[str] = None - """The contents of the message.""" - - refusal: Optional[str] = None - """The refusal message generated by the model.""" - - role: Literal["assistant"] - """The role of the author of this message.""" - - annotations: Optional[List[Annotation]] = None - """ - Annotations for the message, when applicable, as when using the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - """ - - audio: Optional[ChatCompletionAudio] = None - """ - If the audio output modality is requested, this object contains data about the - audio response from the model. - [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - function_call: Optional[FunctionCall] = None - """Deprecated and replaced by `tool_calls`. - - The name and arguments of a function that should be called, as generated by the - model. - """ - - tool_calls: Optional[List[ChatCompletionMessageToolCallUnion]] = None - """The tool calls generated by the model, such as function calls.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call.py deleted file mode 100644 index 9542d8b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ChatCompletionMessageCustomToolCall", "Custom"] - - -class Custom(BaseModel): - """The custom tool that the model called.""" - - input: str - """The input for the custom tool call generated by the model.""" - - name: str - """The name of the custom tool to call.""" - - -class ChatCompletionMessageCustomToolCall(BaseModel): - """A call to a custom tool created by the model.""" - - id: str - """The ID of the tool call.""" - - custom: Custom - """The custom tool that the model called.""" - - type: Literal["custom"] - """The type of the tool. Always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call_param.py deleted file mode 100644 index 3d03f0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_custom_tool_call_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionMessageCustomToolCallParam", "Custom"] - - -class Custom(TypedDict, total=False): - """The custom tool that the model called.""" - - input: Required[str] - """The input for the custom tool call generated by the model.""" - - name: Required[str] - """The name of the custom tool to call.""" - - -class ChatCompletionMessageCustomToolCallParam(TypedDict, total=False): - """A call to a custom tool created by the model.""" - - id: Required[str] - """The ID of the tool call.""" - - custom: Required[Custom] - """The custom tool that the model called.""" - - type: Required[Literal["custom"]] - """The type of the tool. Always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call.py deleted file mode 100644 index e7278b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ChatCompletionMessageFunctionToolCall", "Function"] - - -class Function(BaseModel): - """The function that the model called.""" - - arguments: str - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: str - """The name of the function to call.""" - - -class ChatCompletionMessageFunctionToolCall(BaseModel): - """A call to a function tool created by the model.""" - - id: str - """The ID of the tool call.""" - - function: Function - """The function that the model called.""" - - type: Literal["function"] - """The type of the tool. Currently, only `function` is supported.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call_param.py deleted file mode 100644 index a8094ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_function_tool_call_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionMessageFunctionToolCallParam", "Function"] - - -class Function(TypedDict, total=False): - """The function that the model called.""" - - arguments: Required[str] - """ - The arguments to call the function with, as generated by the model in JSON - format. Note that the model does not always generate valid JSON, and may - hallucinate parameters not defined by your function schema. Validate the - arguments in your code before calling your function. - """ - - name: Required[str] - """The name of the function to call.""" - - -class ChatCompletionMessageFunctionToolCallParam(TypedDict, total=False): - """A call to a function tool created by the model.""" - - id: Required[str] - """The ID of the tool call.""" - - function: Required[Function] - """The function that the model called.""" - - type: Required[Literal["function"]] - """The type of the tool. Currently, only `function` is supported.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_param.py deleted file mode 100644 index 942da24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .chat_completion_tool_message_param import ChatCompletionToolMessageParam -from .chat_completion_user_message_param import ChatCompletionUserMessageParam -from .chat_completion_system_message_param import ChatCompletionSystemMessageParam -from .chat_completion_function_message_param import ChatCompletionFunctionMessageParam -from .chat_completion_assistant_message_param import ChatCompletionAssistantMessageParam -from .chat_completion_developer_message_param import ChatCompletionDeveloperMessageParam - -__all__ = ["ChatCompletionMessageParam"] - -ChatCompletionMessageParam: TypeAlias = Union[ - ChatCompletionDeveloperMessageParam, - ChatCompletionSystemMessageParam, - ChatCompletionUserMessageParam, - ChatCompletionAssistantMessageParam, - ChatCompletionToolMessageParam, - ChatCompletionFunctionMessageParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call.py deleted file mode 100644 index 71ac63f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .chat_completion_message_custom_tool_call import ChatCompletionMessageCustomToolCall -from .chat_completion_message_function_tool_call import Function as Function, ChatCompletionMessageFunctionToolCall - -__all__ = ["Function", "ChatCompletionMessageToolCallUnion"] - -ChatCompletionMessageToolCallUnion: TypeAlias = Annotated[ - Union[ChatCompletionMessageFunctionToolCall, ChatCompletionMessageCustomToolCall], - PropertyInfo(discriminator="type"), -] - -ChatCompletionMessageToolCall: TypeAlias = ChatCompletionMessageFunctionToolCall diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_param.py deleted file mode 100644 index 6baa1b5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypeAlias - -from .chat_completion_message_function_tool_call_param import ( - Function as Function, - ChatCompletionMessageFunctionToolCallParam, -) - -__all__ = ["ChatCompletionMessageToolCallParam", "Function"] - -ChatCompletionMessageToolCallParam: TypeAlias = ChatCompletionMessageFunctionToolCallParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_union_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_union_param.py deleted file mode 100644 index fcca9bb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_message_tool_call_union_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .chat_completion_message_custom_tool_call_param import ChatCompletionMessageCustomToolCallParam -from .chat_completion_message_function_tool_call_param import ChatCompletionMessageFunctionToolCallParam - -__all__ = ["ChatCompletionMessageToolCallUnionParam"] - -ChatCompletionMessageToolCallUnionParam: TypeAlias = Union[ - ChatCompletionMessageFunctionToolCallParam, ChatCompletionMessageCustomToolCallParam -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_modality.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_modality.py deleted file mode 100644 index 8e3c145..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_modality.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ChatCompletionModality"] - -ChatCompletionModality: TypeAlias = Literal["text", "audio"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_custom_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_custom_param.py deleted file mode 100644 index 147fb87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_custom_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionNamedToolChoiceCustomParam", "Custom"] - - -class Custom(TypedDict, total=False): - name: Required[str] - """The name of the custom tool to call.""" - - -class ChatCompletionNamedToolChoiceCustomParam(TypedDict, total=False): - """Specifies a tool the model should use. - - Use to force the model to call a specific custom tool. - """ - - custom: Required[Custom] - - type: Required[Literal["custom"]] - """For custom tool calling, the type is always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_param.py deleted file mode 100644 index f684fce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_named_tool_choice_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ChatCompletionNamedToolChoiceParam", "Function"] - - -class Function(TypedDict, total=False): - name: Required[str] - """The name of the function to call.""" - - -class ChatCompletionNamedToolChoiceParam(TypedDict, total=False): - """Specifies a tool the model should use. - - Use to force the model to call a specific function. - """ - - function: Required[Function] - - type: Required[Literal["function"]] - """For function calling, the type is always `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_prediction_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_prediction_content_param.py deleted file mode 100644 index 6184a31..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_prediction_content_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam - -__all__ = ["ChatCompletionPredictionContentParam"] - - -class ChatCompletionPredictionContentParam(TypedDict, total=False): - """ - Static predicted output content, such as the content of a text file that is - being regenerated. - """ - - content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] - """ - The content that should be matched when generating a model response. If - generated tokens would match this content, the entire model response can be - returned much more quickly. - """ - - type: Required[Literal["content"]] - """The type of the predicted content you want to provide. - - This type is currently always `content`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_reasoning_effort.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_reasoning_effort.py deleted file mode 100644 index 42a980c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_reasoning_effort.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..shared.reasoning_effort import ReasoningEffort - -__all__ = ["ChatCompletionReasoningEffort"] - -ChatCompletionReasoningEffort = ReasoningEffort diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_role.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_role.py deleted file mode 100644 index 3ec5e9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_role.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ChatCompletionRole"] - -ChatCompletionRole: TypeAlias = Literal["developer", "system", "user", "assistant", "tool", "function"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_store_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_store_message.py deleted file mode 100644 index 6a805cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_store_message.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import TypeAlias - -from .chat_completion_message import ChatCompletionMessage -from .chat_completion_content_part_text import ChatCompletionContentPartText -from .chat_completion_content_part_image import ChatCompletionContentPartImage - -__all__ = ["ChatCompletionStoreMessage", "ChatCompletionStoreMessageContentPart"] - -ChatCompletionStoreMessageContentPart: TypeAlias = Union[ChatCompletionContentPartText, ChatCompletionContentPartImage] - - -class ChatCompletionStoreMessage(ChatCompletionMessage): - """A chat completion message generated by the model.""" - - id: str - """The identifier of the chat message.""" - - content_parts: Optional[List[ChatCompletionStoreMessageContentPart]] = None - """ - If a content parts array was provided, this is an array of `text` and - `image_url` parts. Otherwise, null. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_stream_options_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_stream_options_param.py deleted file mode 100644 index 9b881ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_stream_options_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["ChatCompletionStreamOptionsParam"] - - -class ChatCompletionStreamOptionsParam(TypedDict, total=False): - """Options for streaming response. Only set this when you set `stream: true`.""" - - include_obfuscation: bool - """When true, stream obfuscation will be enabled. - - Stream obfuscation adds random characters to an `obfuscation` field on streaming - delta events to normalize payload sizes as a mitigation to certain side-channel - attacks. These obfuscation fields are included by default, but add a small - amount of overhead to the data stream. You can set `include_obfuscation` to - false to optimize for bandwidth if you trust the network links between your - application and the OpenAI API. - """ - - include_usage: bool - """If set, an additional chunk will be streamed before the `data: [DONE]` message. - - The `usage` field on this chunk shows the token usage statistics for the entire - request, and the `choices` field will always be an empty array. - - All other chunks will also include a `usage` field, but with a null value. - **NOTE:** If the stream is interrupted, you may not receive the final usage - chunk which contains the total token usage for the request. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_system_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_system_message_param.py deleted file mode 100644 index 9dcc5e0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_system_message_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam - -__all__ = ["ChatCompletionSystemMessageParam"] - - -class ChatCompletionSystemMessageParam(TypedDict, total=False): - """ - Developer-provided instructions that the model should follow, regardless of - messages sent by the user. With o1 models and newer, use `developer` messages - for this purpose instead. - """ - - content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] - """The contents of the system message.""" - - role: Required[Literal["system"]] - """The role of the messages author, in this case `system`.""" - - name: str - """An optional name for the participant. - - Provides the model information to differentiate between participants of the same - role. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_token_logprob.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_token_logprob.py deleted file mode 100644 index c69e258..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_token_logprob.py +++ /dev/null @@ -1,57 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel - -__all__ = ["ChatCompletionTokenLogprob", "TopLogprob"] - - -class TopLogprob(BaseModel): - token: str - """The token.""" - - bytes: Optional[List[int]] = None - """A list of integers representing the UTF-8 bytes representation of the token. - - Useful in instances where characters are represented by multiple tokens and - their byte representations must be combined to generate the correct text - representation. Can be `null` if there is no bytes representation for the token. - """ - - logprob: float - """The log probability of this token, if it is within the top 20 most likely - tokens. - - Otherwise, the value `-9999.0` is used to signify that the token is very - unlikely. - """ - - -class ChatCompletionTokenLogprob(BaseModel): - token: str - """The token.""" - - bytes: Optional[List[int]] = None - """A list of integers representing the UTF-8 bytes representation of the token. - - Useful in instances where characters are represented by multiple tokens and - their byte representations must be combined to generate the correct text - representation. Can be `null` if there is no bytes representation for the token. - """ - - logprob: float - """The log probability of this token, if it is within the top 20 most likely - tokens. - - Otherwise, the value `-9999.0` is used to signify that the token is very - unlikely. - """ - - top_logprobs: List[TopLogprob] - """List of the most likely tokens and their log probability, at this token - position. - - In rare cases, there may be fewer than the number of requested `top_logprobs` - returned. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_choice_option_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_choice_option_param.py deleted file mode 100644 index f3bb0a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_choice_option_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .chat_completion_named_tool_choice_param import ChatCompletionNamedToolChoiceParam -from .chat_completion_allowed_tool_choice_param import ChatCompletionAllowedToolChoiceParam -from .chat_completion_named_tool_choice_custom_param import ChatCompletionNamedToolChoiceCustomParam - -__all__ = ["ChatCompletionToolChoiceOptionParam"] - -ChatCompletionToolChoiceOptionParam: TypeAlias = Union[ - Literal["none", "auto", "required"], - ChatCompletionAllowedToolChoiceParam, - ChatCompletionNamedToolChoiceParam, - ChatCompletionNamedToolChoiceCustomParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_message_param.py deleted file mode 100644 index eb5e270..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_message_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_content_part_text_param import ChatCompletionContentPartTextParam - -__all__ = ["ChatCompletionToolMessageParam"] - - -class ChatCompletionToolMessageParam(TypedDict, total=False): - content: Required[Union[str, Iterable[ChatCompletionContentPartTextParam]]] - """The contents of the tool message.""" - - role: Required[Literal["tool"]] - """The role of the messages author, in this case `tool`.""" - - tool_call_id: Required[str] - """Tool call that this message is responding to.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_param.py deleted file mode 100644 index a18b13b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypeAlias - -from .chat_completion_function_tool_param import ( - FunctionDefinition as FunctionDefinition, - ChatCompletionFunctionToolParam, -) - -__all__ = ["ChatCompletionToolParam", "FunctionDefinition"] - -ChatCompletionToolParam: TypeAlias = ChatCompletionFunctionToolParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_union_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_union_param.py deleted file mode 100644 index 0f8bf7b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_tool_union_param.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .chat_completion_custom_tool_param import ChatCompletionCustomToolParam -from .chat_completion_function_tool_param import ChatCompletionFunctionToolParam - -__all__ = ["ChatCompletionToolUnionParam"] - -ChatCompletionToolUnionParam: TypeAlias = Union[ChatCompletionFunctionToolParam, ChatCompletionCustomToolParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_user_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_user_message_param.py deleted file mode 100644 index c97ba53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/chat_completion_user_message_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .chat_completion_content_part_param import ChatCompletionContentPartParam - -__all__ = ["ChatCompletionUserMessageParam"] - - -class ChatCompletionUserMessageParam(TypedDict, total=False): - """ - Messages sent by an end user, containing prompts or additional context - information. - """ - - content: Required[Union[str, Iterable[ChatCompletionContentPartParam]]] - """The contents of the user message.""" - - role: Required[Literal["user"]] - """The role of the messages author, in this case `user`.""" - - name: str - """An optional name for the participant. - - Provides the model information to differentiate between participants of the same - role. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_create_params.py deleted file mode 100644 index 49cefb9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_create_params.py +++ /dev/null @@ -1,460 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..shared.chat_model import ChatModel -from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from .chat_completion_audio_param import ChatCompletionAudioParam -from .chat_completion_message_param import ChatCompletionMessageParam -from .chat_completion_tool_union_param import ChatCompletionToolUnionParam -from ..shared_params.function_parameters import FunctionParameters -from ..shared_params.response_format_text import ResponseFormatText -from .chat_completion_stream_options_param import ChatCompletionStreamOptionsParam -from .chat_completion_prediction_content_param import ChatCompletionPredictionContentParam -from .chat_completion_tool_choice_option_param import ChatCompletionToolChoiceOptionParam -from ..shared_params.response_format_json_object import ResponseFormatJSONObject -from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema -from .chat_completion_function_call_option_param import ChatCompletionFunctionCallOptionParam - -__all__ = [ - "CompletionCreateParamsBase", - "FunctionCall", - "Function", - "ResponseFormat", - "WebSearchOptions", - "WebSearchOptionsUserLocation", - "WebSearchOptionsUserLocationApproximate", - "CompletionCreateParamsNonStreaming", - "CompletionCreateParamsStreaming", -] - - -class CompletionCreateParamsBase(TypedDict, total=False): - messages: Required[Iterable[ChatCompletionMessageParam]] - """A list of messages comprising the conversation so far. - - Depending on the [model](https://platform.openai.com/docs/models) you use, - different message types (modalities) are supported, like - [text](https://platform.openai.com/docs/guides/text-generation), - [images](https://platform.openai.com/docs/guides/vision), and - [audio](https://platform.openai.com/docs/guides/audio). - """ - - model: Required[Union[str, ChatModel]] - """Model ID used to generate the response, like `gpt-4o` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - audio: Optional[ChatCompletionAudioParam] - """Parameters for audio output. - - Required when audio output is requested with `modalities: ["audio"]`. - [Learn more](https://platform.openai.com/docs/guides/audio). - """ - - frequency_penalty: Optional[float] - """Number between -2.0 and 2.0. - - Positive values penalize new tokens based on their existing frequency in the - text so far, decreasing the model's likelihood to repeat the same line verbatim. - """ - - function_call: FunctionCall - """Deprecated in favor of `tool_choice`. - - Controls which (if any) function is called by the model. - - `none` means the model will not call a function and instead generates a message. - - `auto` means the model can pick between generating a message or calling a - function. - - Specifying a particular function via `{"name": "my_function"}` forces the model - to call that function. - - `none` is the default when no functions are present. `auto` is the default if - functions are present. - """ - - functions: Iterable[Function] - """Deprecated in favor of `tools`. - - A list of functions the model may generate JSON inputs for. - """ - - logit_bias: Optional[Dict[str, int]] - """Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the - tokenizer) to an associated bias value from -100 to 100. Mathematically, the - bias is added to the logits generated by the model prior to sampling. The exact - effect will vary per model, but values between -1 and 1 should decrease or - increase likelihood of selection; values like -100 or 100 should result in a ban - or exclusive selection of the relevant token. - """ - - logprobs: Optional[bool] - """Whether to return log probabilities of the output tokens or not. - - If true, returns the log probabilities of each output token returned in the - `content` of `message`. - """ - - max_completion_tokens: Optional[int] - """ - An upper bound for the number of tokens that can be generated for a completion, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - """ - - max_tokens: Optional[int] - """ - The maximum number of [tokens](/tokenizer) that can be generated in the chat - completion. This value can be used to control - [costs](https://openai.com/api/pricing/) for text generated via API. - - This value is now deprecated in favor of `max_completion_tokens`, and is not - compatible with - [o-series models](https://platform.openai.com/docs/guides/reasoning). - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - modalities: Optional[List[Literal["text", "audio"]]] - """ - Output types that you would like the model to generate. Most models are capable - of generating text, which is the default: - - `["text"]` - - The `gpt-4o-audio-preview` model can also be used to - [generate audio](https://platform.openai.com/docs/guides/audio). To request that - this model generate both text and audio responses, you can use: - - `["text", "audio"]` - """ - - n: Optional[int] - """How many chat completion choices to generate for each input message. - - Note that you will be charged based on the number of generated tokens across all - of the choices. Keep `n` as `1` to minimize costs. - """ - - parallel_tool_calls: bool - """ - Whether to enable - [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - during tool use. - """ - - prediction: Optional[ChatCompletionPredictionContentParam] - """ - Static predicted output content, such as the content of a text file that is - being regenerated. - """ - - presence_penalty: Optional[float] - """Number between -2.0 and 2.0. - - Positive values penalize new tokens based on whether they appear in the text so - far, increasing the model's likelihood to talk about new topics. - """ - - prompt_cache_key: str - """ - Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - """ - - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] - """The retention policy for the prompt cache. - - Set to `24h` to enable extended prompt caching, which keeps cached prefixes - active for longer, up to a maximum of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - """ - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: ResponseFormat - """An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - safety_identifier: str - """ - A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - seed: Optional[int] - """ - This feature is in Beta. If specified, our system will make a best effort to - sample deterministically, such that repeated requests with the same `seed` and - parameters should return the same result. Determinism is not guaranteed, and you - should refer to the `system_fingerprint` response parameter to monitor changes - in the backend. - """ - - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] - """Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - """ - - stop: Union[Optional[str], SequenceNotStr[str], None] - """Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - """ - - store: Optional[bool] - """ - Whether or not to store the output of this chat completion request for use in - our [model distillation](https://platform.openai.com/docs/guides/distillation) - or [evals](https://platform.openai.com/docs/guides/evals) products. - - Supports text and image inputs. Note: image inputs over 8MB will be dropped. - """ - - stream_options: Optional[ChatCompletionStreamOptionsParam] - """Options for streaming response. Only set this when you set `stream: true`.""" - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. We generally recommend altering - this or `top_p` but not both. - """ - - tool_choice: ChatCompletionToolChoiceOptionParam - """ - Controls which (if any) tool is called by the model. `none` means the model will - not call any tool and instead generates a message. `auto` means the model can - pick between generating a message or calling one or more tools. `required` means - the model must call one or more tools. Specifying a particular tool via - `{"type": "function", "function": {"name": "my_function"}}` forces the model to - call that tool. - - `none` is the default when no tools are present. `auto` is the default if tools - are present. - """ - - tools: Iterable[ChatCompletionToolUnionParam] - """A list of tools the model may call. - - You can provide either - [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - or [function tools](https://platform.openai.com/docs/guides/function-calling). - """ - - top_logprobs: Optional[int] - """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - `logprobs` must be set to `true` if this parameter is used. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - """ - - user: str - """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - - Use `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - - web_search_options: WebSearchOptions - """ - This tool searches the web for relevant results to use in a response. Learn more - about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - """ - - -FunctionCall: TypeAlias = Union[Literal["none", "auto"], ChatCompletionFunctionCallOptionParam] - - -class Function(TypedDict, total=False): - name: Required[str] - """The name of the function to be called. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - description: str - """ - A description of what the function does, used by the model to choose when and - how to call the function. - """ - - parameters: FunctionParameters - """The parameters the functions accepts, described as a JSON Schema object. - - See the [guide](https://platform.openai.com/docs/guides/function-calling) for - examples, and the - [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for - documentation about the format. - - Omitting `parameters` defines a function with an empty parameter list. - """ - - -ResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] - - -class WebSearchOptionsUserLocationApproximate(TypedDict, total=False): - """Approximate location parameters for the search.""" - - city: str - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: str - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: str - """Free text input for the region of the user, e.g. `California`.""" - - timezone: str - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - -class WebSearchOptionsUserLocation(TypedDict, total=False): - """Approximate location parameters for the search.""" - - approximate: Required[WebSearchOptionsUserLocationApproximate] - """Approximate location parameters for the search.""" - - type: Required[Literal["approximate"]] - """The type of location approximation. Always `approximate`.""" - - -class WebSearchOptions(TypedDict, total=False): - """ - This tool searches the web for relevant results to use in a response. - Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat). - """ - - search_context_size: Literal["low", "medium", "high"] - """ - High level guidance for the amount of context window space to use for the - search. One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[WebSearchOptionsUserLocation] - """Approximate location parameters for the search.""" - - -class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - """ - - -class CompletionCreateParamsStreaming(CompletionCreateParamsBase): - stream: Required[Literal[True]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/chat/streaming) - for more information, along with the - [streaming responses](https://platform.openai.com/docs/guides/streaming-responses) - guide for more information on how to handle the streaming events. - """ - - -CompletionCreateParams = Union[CompletionCreateParamsNonStreaming, CompletionCreateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_list_params.py deleted file mode 100644 index 32bd3f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_list_params.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, TypedDict - -from ..shared_params.metadata import Metadata - -__all__ = ["CompletionListParams"] - - -class CompletionListParams(TypedDict, total=False): - after: str - """Identifier for the last chat completion from the previous pagination request.""" - - limit: int - """Number of Chat Completions to retrieve.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """The model used to generate the Chat Completions.""" - - order: Literal["asc", "desc"] - """Sort order for Chat Completions by timestamp. - - Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_update_params.py deleted file mode 100644 index fc71733..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completion_update_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from ..shared_params.metadata import Metadata - -__all__ = ["CompletionUpdateParams"] - - -class CompletionUpdateParams(TypedDict, total=False): - metadata: Required[Optional[Metadata]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/__init__.py deleted file mode 100644 index b8e62d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .message_list_params import MessageListParams as MessageListParams diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/message_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/message_list_params.py deleted file mode 100644 index 4e694e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/completions/message_list_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["MessageListParams"] - - -class MessageListParams(TypedDict, total=False): - after: str - """Identifier for the last message from the previous pagination request.""" - - limit: int - """Number of messages to retrieve.""" - - order: Literal["asc", "desc"] - """Sort order for messages by timestamp. - - Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_chat_completion.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_chat_completion.py deleted file mode 100644 index 4b11dac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_chat_completion.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Generic, TypeVar, Optional - -from ..._models import GenericModel -from .chat_completion import Choice, ChatCompletion -from .chat_completion_message import ChatCompletionMessage -from .parsed_function_tool_call import ParsedFunctionToolCall - -__all__ = ["ParsedChatCompletion", "ParsedChoice"] - - -ContentType = TypeVar("ContentType") - - -# we need to disable this check because we're overriding properties -# with subclasses of their types which is technically unsound as -# properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false - - -class ParsedChatCompletionMessage(ChatCompletionMessage, GenericModel, Generic[ContentType]): - parsed: Optional[ContentType] = None - """The auto-parsed message contents""" - - tool_calls: Optional[List[ParsedFunctionToolCall]] = None # type: ignore[assignment] - """The tool calls generated by the model, such as function calls.""" - - -class ParsedChoice(Choice, GenericModel, Generic[ContentType]): - message: ParsedChatCompletionMessage[ContentType] - """A chat completion message generated by the model.""" - - -class ParsedChatCompletion(ChatCompletion, GenericModel, Generic[ContentType]): - choices: List[ParsedChoice[ContentType]] # type: ignore[assignment] - """A list of chat completion choices. - - Can be more than one if `n` is greater than 1. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_function_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_function_tool_call.py deleted file mode 100644 index e06b354..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat/parsed_function_tool_call.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .chat_completion_message_function_tool_call import Function, ChatCompletionMessageFunctionToolCall - -__all__ = ["ParsedFunctionToolCall", "ParsedFunction"] - -# we need to disable this check because we're overriding properties -# with subclasses of their types which is technically unsound as -# properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false - - -class ParsedFunction(Function): - parsed_arguments: Optional[object] = None - """ - The arguments to call the function with. - - If you used `openai.pydantic_function_tool()` then this will be an - instance of the given `BaseModel`. - - Otherwise, this will be the parsed JSON arguments. - """ - - -class ParsedFunctionToolCall(ChatCompletionMessageFunctionToolCall): - function: ParsedFunction - """The function that the model called.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/chat_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/chat_model.py deleted file mode 100644 index f3b0e31..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/chat_model.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .shared import chat_model - -__all__ = ["ChatModel"] - -ChatModel = chat_model.ChatModel diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/completion.py b/backend/venv39/lib/python3.9/site-packages/openai/types/completion.py deleted file mode 100644 index ee59b2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/completion.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .completion_usage import CompletionUsage -from .completion_choice import CompletionChoice - -__all__ = ["Completion"] - - -class Completion(BaseModel): - """Represents a completion response from the API. - - Note: both the streamed and non-streamed response objects share the same shape (unlike the chat endpoint). - """ - - id: str - """A unique identifier for the completion.""" - - choices: List[CompletionChoice] - """The list of completion choices the model generated for the input prompt.""" - - created: int - """The Unix timestamp (in seconds) of when the completion was created.""" - - model: str - """The model used for completion.""" - - object: Literal["text_completion"] - """The object type, which is always "text_completion" """ - - system_fingerprint: Optional[str] = None - """This fingerprint represents the backend configuration that the model runs with. - - Can be used in conjunction with the `seed` request parameter to understand when - backend changes have been made that might impact determinism. - """ - - usage: Optional[CompletionUsage] = None - """Usage statistics for the completion request.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_choice.py b/backend/venv39/lib/python3.9/site-packages/openai/types/completion_choice.py deleted file mode 100644 index d948ebc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_choice.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["CompletionChoice", "Logprobs"] - - -class Logprobs(BaseModel): - text_offset: Optional[List[int]] = None - - token_logprobs: Optional[List[float]] = None - - tokens: Optional[List[str]] = None - - top_logprobs: Optional[List[Dict[str, float]]] = None - - -class CompletionChoice(BaseModel): - finish_reason: Literal["stop", "length", "content_filter"] - """The reason the model stopped generating tokens. - - This will be `stop` if the model hit a natural stop point or a provided stop - sequence, `length` if the maximum number of tokens specified in the request was - reached, or `content_filter` if content was omitted due to a flag from our - content filters. - """ - - index: int - - logprobs: Optional[Logprobs] = None - - text: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/completion_create_params.py deleted file mode 100644 index f9beb9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_create_params.py +++ /dev/null @@ -1,189 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -from .._types import SequenceNotStr -from .chat.chat_completion_stream_options_param import ChatCompletionStreamOptionsParam - -__all__ = ["CompletionCreateParamsBase", "CompletionCreateParamsNonStreaming", "CompletionCreateParamsStreaming"] - - -class CompletionCreateParamsBase(TypedDict, total=False): - model: Required[Union[str, Literal["gpt-3.5-turbo-instruct", "davinci-002", "babbage-002"]]] - """ID of the model to use. - - You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - """ - - prompt: Required[Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]], None]] - """ - The prompt(s) to generate completions for, encoded as a string, array of - strings, array of tokens, or array of token arrays. - - Note that <|endoftext|> is the document separator that the model sees during - training, so if a prompt is not specified the model will generate as if from the - beginning of a new document. - """ - - best_of: Optional[int] - """ - Generates `best_of` completions server-side and returns the "best" (the one with - the highest log probability per token). Results cannot be streamed. - - When used with `n`, `best_of` controls the number of candidate completions and - `n` specifies how many to return – `best_of` must be greater than `n`. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - """ - - echo: Optional[bool] - """Echo back the prompt in addition to the completion""" - - frequency_penalty: Optional[float] - """Number between -2.0 and 2.0. - - Positive values penalize new tokens based on their existing frequency in the - text so far, decreasing the model's likelihood to repeat the same line verbatim. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - """ - - logit_bias: Optional[Dict[str, int]] - """Modify the likelihood of specified tokens appearing in the completion. - - Accepts a JSON object that maps tokens (specified by their token ID in the GPT - tokenizer) to an associated bias value from -100 to 100. You can use this - [tokenizer tool](/tokenizer?view=bpe) to convert text to token IDs. - Mathematically, the bias is added to the logits generated by the model prior to - sampling. The exact effect will vary per model, but values between -1 and 1 - should decrease or increase likelihood of selection; values like -100 or 100 - should result in a ban or exclusive selection of the relevant token. - - As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token - from being generated. - """ - - logprobs: Optional[int] - """ - Include the log probabilities on the `logprobs` most likely output tokens, as - well the chosen tokens. For example, if `logprobs` is 5, the API will return a - list of the 5 most likely tokens. The API will always return the `logprob` of - the sampled token, so there may be up to `logprobs+1` elements in the response. - - The maximum value for `logprobs` is 5. - """ - - max_tokens: Optional[int] - """ - The maximum number of [tokens](/tokenizer) that can be generated in the - completion. - - The token count of your prompt plus `max_tokens` cannot exceed the model's - context length. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. - """ - - n: Optional[int] - """How many completions to generate for each prompt. - - **Note:** Because this parameter generates many completions, it can quickly - consume your token quota. Use carefully and ensure that you have reasonable - settings for `max_tokens` and `stop`. - """ - - presence_penalty: Optional[float] - """Number between -2.0 and 2.0. - - Positive values penalize new tokens based on whether they appear in the text so - far, increasing the model's likelihood to talk about new topics. - - [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/text-generation) - """ - - seed: Optional[int] - """ - If specified, our system will make a best effort to sample deterministically, - such that repeated requests with the same `seed` and parameters should return - the same result. - - Determinism is not guaranteed, and you should refer to the `system_fingerprint` - response parameter to monitor changes in the backend. - """ - - stop: Union[Optional[str], SequenceNotStr[str], None] - """Not supported with latest reasoning models `o3` and `o4-mini`. - - Up to 4 sequences where the API will stop generating further tokens. The - returned text will not contain the stop sequence. - """ - - stream_options: Optional[ChatCompletionStreamOptionsParam] - """Options for streaming response. Only set this when you set `stream: true`.""" - - suffix: Optional[str] - """The suffix that comes after a completion of inserted text. - - This parameter is only supported for `gpt-3.5-turbo-instruct`. - """ - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. - - We generally recommend altering this or `top_p` but not both. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - """ - - user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - """ - - -class CompletionCreateParamsNonStreaming(CompletionCreateParamsBase, total=False): - stream: Optional[Literal[False]] - """Whether to stream back partial progress. - - If set, tokens will be sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - """ - - -class CompletionCreateParamsStreaming(CompletionCreateParamsBase): - stream: Required[Literal[True]] - """Whether to stream back partial progress. - - If set, tokens will be sent as data-only - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - as they become available, with the stream terminated by a `data: [DONE]` - message. - [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - """ - - -CompletionCreateParams = Union[CompletionCreateParamsNonStreaming, CompletionCreateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_usage.py b/backend/venv39/lib/python3.9/site-packages/openai/types/completion_usage.py deleted file mode 100644 index 9b5202d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/completion_usage.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["CompletionUsage", "CompletionTokensDetails", "PromptTokensDetails"] - - -class CompletionTokensDetails(BaseModel): - """Breakdown of tokens used in a completion.""" - - accepted_prediction_tokens: Optional[int] = None - """ - When using Predicted Outputs, the number of tokens in the prediction that - appeared in the completion. - """ - - audio_tokens: Optional[int] = None - """Audio input tokens generated by the model.""" - - reasoning_tokens: Optional[int] = None - """Tokens generated by the model for reasoning.""" - - rejected_prediction_tokens: Optional[int] = None - """ - When using Predicted Outputs, the number of tokens in the prediction that did - not appear in the completion. However, like reasoning tokens, these tokens are - still counted in the total completion tokens for purposes of billing, output, - and context window limits. - """ - - -class PromptTokensDetails(BaseModel): - """Breakdown of tokens used in the prompt.""" - - audio_tokens: Optional[int] = None - """Audio input tokens present in the prompt.""" - - cached_tokens: Optional[int] = None - """Cached tokens present in the prompt.""" - - -class CompletionUsage(BaseModel): - """Usage statistics for the completion request.""" - - completion_tokens: int - """Number of tokens in the generated completion.""" - - prompt_tokens: int - """Number of tokens in the prompt.""" - - total_tokens: int - """Total number of tokens used in the request (prompt + completion).""" - - completion_tokens_details: Optional[CompletionTokensDetails] = None - """Breakdown of tokens used in a completion.""" - - prompt_tokens_details: Optional[PromptTokensDetails] = None - """Breakdown of tokens used in the prompt.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_params.py deleted file mode 100644 index 47101ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .._types import SequenceNotStr - -__all__ = ["ContainerCreateParams", "ExpiresAfter"] - - -class ContainerCreateParams(TypedDict, total=False): - name: Required[str] - """Name of the container to create.""" - - expires_after: ExpiresAfter - """Container expiration time in seconds relative to the 'anchor' time.""" - - file_ids: SequenceNotStr[str] - """IDs of files to copy to the container.""" - - memory_limit: Literal["1g", "4g", "16g", "64g"] - """Optional memory limit for the container. Defaults to "1g".""" - - -class ExpiresAfter(TypedDict, total=False): - """Container expiration time in seconds relative to the 'anchor' time.""" - - anchor: Required[Literal["last_active_at"]] - """Time anchor for the expiration time. - - Currently only 'last_active_at' is supported. - """ - - minutes: Required[int] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_response.py deleted file mode 100644 index 0ebcc04..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/container_create_response.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ContainerCreateResponse", "ExpiresAfter"] - - -class ExpiresAfter(BaseModel): - """ - The container will expire after this time period. - The anchor is the reference point for the expiration. - The minutes is the number of minutes after the anchor before the container expires. - """ - - anchor: Optional[Literal["last_active_at"]] = None - """The reference point for the expiration.""" - - minutes: Optional[int] = None - """The number of minutes after the anchor before the container expires.""" - - -class ContainerCreateResponse(BaseModel): - id: str - """Unique identifier for the container.""" - - created_at: int - """Unix timestamp (in seconds) when the container was created.""" - - name: str - """Name of the container.""" - - object: str - """The type of this object.""" - - status: str - """Status of the container (e.g., active, deleted).""" - - expires_after: Optional[ExpiresAfter] = None - """ - The container will expire after this time period. The anchor is the reference - point for the expiration. The minutes is the number of minutes after the anchor - before the container expires. - """ - - last_active_at: Optional[int] = None - """Unix timestamp (in seconds) when the container was last active.""" - - memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None - """The memory limit configured for the container.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_params.py deleted file mode 100644 index 4821a87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_params.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ContainerListParams"] - - -class ContainerListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_response.py deleted file mode 100644 index 8f39548..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/container_list_response.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ContainerListResponse", "ExpiresAfter"] - - -class ExpiresAfter(BaseModel): - """ - The container will expire after this time period. - The anchor is the reference point for the expiration. - The minutes is the number of minutes after the anchor before the container expires. - """ - - anchor: Optional[Literal["last_active_at"]] = None - """The reference point for the expiration.""" - - minutes: Optional[int] = None - """The number of minutes after the anchor before the container expires.""" - - -class ContainerListResponse(BaseModel): - id: str - """Unique identifier for the container.""" - - created_at: int - """Unix timestamp (in seconds) when the container was created.""" - - name: str - """Name of the container.""" - - object: str - """The type of this object.""" - - status: str - """Status of the container (e.g., active, deleted).""" - - expires_after: Optional[ExpiresAfter] = None - """ - The container will expire after this time period. The anchor is the reference - point for the expiration. The minutes is the number of minutes after the anchor - before the container expires. - """ - - last_active_at: Optional[int] = None - """Unix timestamp (in seconds) when the container was last active.""" - - memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None - """The memory limit configured for the container.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/container_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/container_retrieve_response.py deleted file mode 100644 index 9ba3e18..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/container_retrieve_response.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ContainerRetrieveResponse", "ExpiresAfter"] - - -class ExpiresAfter(BaseModel): - """ - The container will expire after this time period. - The anchor is the reference point for the expiration. - The minutes is the number of minutes after the anchor before the container expires. - """ - - anchor: Optional[Literal["last_active_at"]] = None - """The reference point for the expiration.""" - - minutes: Optional[int] = None - """The number of minutes after the anchor before the container expires.""" - - -class ContainerRetrieveResponse(BaseModel): - id: str - """Unique identifier for the container.""" - - created_at: int - """Unix timestamp (in seconds) when the container was created.""" - - name: str - """Name of the container.""" - - object: str - """The type of this object.""" - - status: str - """Status of the container (e.g., active, deleted).""" - - expires_after: Optional[ExpiresAfter] = None - """ - The container will expire after this time period. The anchor is the reference - point for the expiration. The minutes is the number of minutes after the anchor - before the container expires. - """ - - last_active_at: Optional[int] = None - """Unix timestamp (in seconds) when the container was last active.""" - - memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None - """The memory limit configured for the container.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/__init__.py deleted file mode 100644 index 7d555ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .file_list_params import FileListParams as FileListParams -from .file_create_params import FileCreateParams as FileCreateParams -from .file_list_response import FileListResponse as FileListResponse -from .file_create_response import FileCreateResponse as FileCreateResponse -from .file_retrieve_response import FileRetrieveResponse as FileRetrieveResponse diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_params.py deleted file mode 100644 index 1e41330..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from ..._types import FileTypes - -__all__ = ["FileCreateParams"] - - -class FileCreateParams(TypedDict, total=False): - file: FileTypes - """The File object (not file name) to be uploaded.""" - - file_id: str - """Name of the file to create.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_response.py deleted file mode 100644 index 4a65248..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_create_response.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FileCreateResponse"] - - -class FileCreateResponse(BaseModel): - id: str - """Unique identifier for the file.""" - - bytes: int - """Size of the file in bytes.""" - - container_id: str - """The container this file belongs to.""" - - created_at: int - """Unix timestamp (in seconds) when the file was created.""" - - object: Literal["container.file"] - """The type of this object (`container.file`).""" - - path: str - """Path of the file in the container.""" - - source: str - """Source of the file (e.g., `user`, `assistant`).""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_params.py deleted file mode 100644 index 3565aca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_params.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["FileListParams"] - - -class FileListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_response.py deleted file mode 100644 index e5eee38..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_list_response.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FileListResponse"] - - -class FileListResponse(BaseModel): - id: str - """Unique identifier for the file.""" - - bytes: int - """Size of the file in bytes.""" - - container_id: str - """The container this file belongs to.""" - - created_at: int - """Unix timestamp (in seconds) when the file was created.""" - - object: Literal["container.file"] - """The type of this object (`container.file`).""" - - path: str - """Path of the file in the container.""" - - source: str - """Source of the file (e.g., `user`, `assistant`).""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_retrieve_response.py deleted file mode 100644 index 37fb0e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/file_retrieve_response.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FileRetrieveResponse"] - - -class FileRetrieveResponse(BaseModel): - id: str - """Unique identifier for the file.""" - - bytes: int - """Size of the file in bytes.""" - - container_id: str - """The container this file belongs to.""" - - created_at: int - """Unix timestamp (in seconds) when the file was created.""" - - object: Literal["container.file"] - """The type of this object (`container.file`).""" - - path: str - """Path of the file in the container.""" - - source: str - """Source of the file (e.g., `user`, `assistant`).""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/files/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/containers/files/__init__.py deleted file mode 100644 index f8ee8b1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/containers/files/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/__init__.py deleted file mode 100644 index 9dec848..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .message import Message as Message -from .conversation import Conversation as Conversation -from .text_content import TextContent as TextContent -from .refusal_content import RefusalContent as RefusalContent -from .item_list_params import ItemListParams as ItemListParams -from .conversation_item import ConversationItem as ConversationItem -from .input_file_content import InputFileContent as InputFileContent -from .input_text_content import InputTextContent as InputTextContent -from .item_create_params import ItemCreateParams as ItemCreateParams -from .input_image_content import InputImageContent as InputImageContent -from .output_text_content import OutputTextContent as OutputTextContent -from .item_retrieve_params import ItemRetrieveParams as ItemRetrieveParams -from .summary_text_content import SummaryTextContent as SummaryTextContent -from .refusal_content_param import RefusalContentParam as RefusalContentParam -from .conversation_item_list import ConversationItemList as ConversationItemList -from .input_file_content_param import InputFileContentParam as InputFileContentParam -from .input_text_content_param import InputTextContentParam as InputTextContentParam -from .input_image_content_param import InputImageContentParam as InputImageContentParam -from .output_text_content_param import OutputTextContentParam as OutputTextContentParam -from .conversation_create_params import ConversationCreateParams as ConversationCreateParams -from .conversation_update_params import ConversationUpdateParams as ConversationUpdateParams -from .computer_screenshot_content import ComputerScreenshotContent as ComputerScreenshotContent -from .conversation_deleted_resource import ConversationDeletedResource as ConversationDeletedResource diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/computer_screenshot_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/computer_screenshot_content.py deleted file mode 100644 index e42096e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/computer_screenshot_content.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ComputerScreenshotContent"] - - -class ComputerScreenshotContent(BaseModel): - """A screenshot of a computer.""" - - file_id: Optional[str] = None - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: Optional[str] = None - """The URL of the screenshot image.""" - - type: Literal["computer_screenshot"] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation.py deleted file mode 100644 index ed63d40..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["Conversation"] - - -class Conversation(BaseModel): - id: str - """The unique ID of the conversation.""" - - created_at: int - """ - The time at which the conversation was created, measured in seconds since the - Unix epoch. - """ - - metadata: object - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters. - """ - - object: Literal["conversation"] - """The object type, which is always `conversation`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_create_params.py deleted file mode 100644 index 5f38d2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_create_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional -from typing_extensions import TypedDict - -from ..shared_params.metadata import Metadata -from ..responses.response_input_item_param import ResponseInputItemParam - -__all__ = ["ConversationCreateParams"] - - -class ConversationCreateParams(TypedDict, total=False): - items: Optional[Iterable[ResponseInputItemParam]] - """Initial items to include in the conversation context. - - You may add up to 20 items at a time. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_deleted_resource.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_deleted_resource.py deleted file mode 100644 index 7abcb24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_deleted_resource.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationDeletedResource"] - - -class ConversationDeletedResource(BaseModel): - id: str - - deleted: bool - - object: Literal["conversation.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item.py deleted file mode 100644 index 46268d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item.py +++ /dev/null @@ -1,248 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .message import Message -from ..._utils import PropertyInfo -from ..._models import BaseModel -from ..responses.response_reasoning_item import ResponseReasoningItem -from ..responses.response_custom_tool_call import ResponseCustomToolCall -from ..responses.response_computer_tool_call import ResponseComputerToolCall -from ..responses.response_function_web_search import ResponseFunctionWebSearch -from ..responses.response_apply_patch_tool_call import ResponseApplyPatchToolCall -from ..responses.response_file_search_tool_call import ResponseFileSearchToolCall -from ..responses.response_custom_tool_call_output import ResponseCustomToolCallOutput -from ..responses.response_function_tool_call_item import ResponseFunctionToolCallItem -from ..responses.response_function_shell_tool_call import ResponseFunctionShellToolCall -from ..responses.response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall -from ..responses.response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput -from ..responses.response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem -from ..responses.response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem -from ..responses.response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput - -__all__ = [ - "ConversationItem", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "LocalShellCallOutput", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", - "McpApprovalResponse", - "McpCall", -] - - -class ImageGenerationCall(BaseModel): - """An image generation request made by the model.""" - - id: str - """The unique ID of the image generation call.""" - - result: Optional[str] = None - """The generated image encoded in base64.""" - - status: Literal["in_progress", "completed", "generating", "failed"] - """The status of the image generation call.""" - - type: Literal["image_generation_call"] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(BaseModel): - """Execute a shell command on the server.""" - - command: List[str] - """The command to run.""" - - env: Dict[str, str] - """Environment variables to set for the command.""" - - type: Literal["exec"] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] = None - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] = None - """Optional user to run the command as.""" - - working_directory: Optional[str] = None - """Optional working directory to run the command in.""" - - -class LocalShellCall(BaseModel): - """A tool call to run a command on the local shell.""" - - id: str - """The unique ID of the local shell call.""" - - action: LocalShellCallAction - """Execute a shell command on the server.""" - - call_id: str - """The unique ID of the local shell tool call generated by the model.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the local shell call.""" - - type: Literal["local_shell_call"] - """The type of the local shell call. Always `local_shell_call`.""" - - -class LocalShellCallOutput(BaseModel): - """The output of a local shell tool call.""" - - id: str - """The unique ID of the local shell tool call generated by the model.""" - - output: str - """A JSON string of the output of the local shell tool call.""" - - type: Literal["local_shell_call_output"] - """The type of the local shell tool call output. Always `local_shell_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" - - -class McpListToolsTool(BaseModel): - """A tool available on an MCP server.""" - - input_schema: object - """The JSON schema describing the tool's input.""" - - name: str - """The name of the tool.""" - - annotations: Optional[object] = None - """Additional annotations about the tool.""" - - description: Optional[str] = None - """The description of the tool.""" - - -class McpListTools(BaseModel): - """A list of tools available on an MCP server.""" - - id: str - """The unique ID of the list.""" - - server_label: str - """The label of the MCP server.""" - - tools: List[McpListToolsTool] - """The tools available on the server.""" - - type: Literal["mcp_list_tools"] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] = None - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(BaseModel): - """A request for human approval of a tool invocation.""" - - id: str - """The unique ID of the approval request.""" - - arguments: str - """A JSON string of arguments for the tool.""" - - name: str - """The name of the tool to run.""" - - server_label: str - """The label of the MCP server making the request.""" - - type: Literal["mcp_approval_request"] - """The type of the item. Always `mcp_approval_request`.""" - - -class McpApprovalResponse(BaseModel): - """A response to an MCP approval request.""" - - id: str - """The unique ID of the approval response""" - - approval_request_id: str - """The ID of the approval request being answered.""" - - approve: bool - """Whether the request was approved.""" - - type: Literal["mcp_approval_response"] - """The type of the item. Always `mcp_approval_response`.""" - - reason: Optional[str] = None - """Optional reason for the decision.""" - - -class McpCall(BaseModel): - """An invocation of a tool on an MCP server.""" - - id: str - """The unique ID of the tool call.""" - - arguments: str - """A JSON string of the arguments passed to the tool.""" - - name: str - """The name of the tool that was run.""" - - server_label: str - """The label of the MCP server running the tool.""" - - type: Literal["mcp_call"] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] = None - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] = None - """The error from the tool call, if any.""" - - output: Optional[str] = None - """The output from the tool call.""" - - status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -ConversationItem: TypeAlias = Annotated[ - Union[ - Message, - ResponseFunctionToolCallItem, - ResponseFunctionToolCallOutputItem, - ResponseFileSearchToolCall, - ResponseFunctionWebSearch, - ImageGenerationCall, - ResponseComputerToolCall, - ResponseComputerToolCallOutputItem, - ResponseReasoningItem, - ResponseCodeInterpreterToolCall, - LocalShellCall, - LocalShellCallOutput, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - McpListTools, - McpApprovalRequest, - McpApprovalResponse, - McpCall, - ResponseCustomToolCall, - ResponseCustomToolCallOutput, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item_list.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item_list.py deleted file mode 100644 index 74d945d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_item_list.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemList"] - - -class ConversationItemList(BaseModel): - """A list of Conversation items.""" - - data: List[ConversationItem] - """A list of conversation items.""" - - first_id: str - """The ID of the first item in the list.""" - - has_more: bool - """Whether there are more items available.""" - - last_id: str - """The ID of the last item in the list.""" - - object: Literal["list"] - """The type of object returned, must be `list`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_update_params.py deleted file mode 100644 index 1f0dd09..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/conversation_update_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from ..shared_params.metadata import Metadata - -__all__ = ["ConversationUpdateParams"] - - -class ConversationUpdateParams(TypedDict, total=False): - metadata: Required[Optional[Metadata]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content.py deleted file mode 100644 index ca555d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..responses.response_input_file import ResponseInputFile - -__all__ = ["InputFileContent"] - -InputFileContent = ResponseInputFile diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content_param.py deleted file mode 100644 index 1ed8b8b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_file_content_param.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..responses.response_input_file_param import ResponseInputFileParam - -InputFileContentParam = ResponseInputFileParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content.py deleted file mode 100644 index 4304323..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..responses.response_input_image import ResponseInputImage - -__all__ = ["InputImageContent"] - -InputImageContent = ResponseInputImage diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content_param.py deleted file mode 100644 index a0ef9f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_image_content_param.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..responses.response_input_image_param import ResponseInputImageParam - -InputImageContentParam = ResponseInputImageParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content.py deleted file mode 100644 index cab8b26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..responses.response_input_text import ResponseInputText - -__all__ = ["InputTextContent"] - -InputTextContent = ResponseInputText diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content_param.py deleted file mode 100644 index b1fd9a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/input_text_content_param.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..responses.response_input_text_param import ResponseInputTextParam - -InputTextContentParam = ResponseInputTextParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_create_params.py deleted file mode 100644 index 9158b71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_create_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable -from typing_extensions import Required, TypedDict - -from ..responses.response_includable import ResponseIncludable -from ..responses.response_input_item_param import ResponseInputItemParam - -__all__ = ["ItemCreateParams"] - - -class ItemCreateParams(TypedDict, total=False): - items: Required[Iterable[ResponseInputItemParam]] - """The items to add to the conversation. You may add up to 20 items at a time.""" - - include: List[ResponseIncludable] - """Additional fields to include in the response. - - See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_list_params.py deleted file mode 100644 index a4dd61f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_list_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, TypedDict - -from ..responses.response_includable import ResponseIncludable - -__all__ = ["ItemListParams"] - - -class ItemListParams(TypedDict, total=False): - after: str - """An item ID to list items after, used in pagination.""" - - include: List[ResponseIncludable] - """Specify additional output data to include in the model response. - - Currently supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_retrieve_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_retrieve_params.py deleted file mode 100644 index 8c5db1e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/item_retrieve_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Required, TypedDict - -from ..responses.response_includable import ResponseIncludable - -__all__ = ["ItemRetrieveParams"] - - -class ItemRetrieveParams(TypedDict, total=False): - conversation_id: Required[str] - - include: List[ResponseIncludable] - """Additional fields to include in the response. - - See the `include` parameter for - [listing Conversation items above](https://platform.openai.com/docs/api-reference/conversations/list-items#conversations_list_items-include) - for more information. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/message.py deleted file mode 100644 index 86c8860..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/message.py +++ /dev/null @@ -1,70 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .text_content import TextContent -from .summary_text_content import SummaryTextContent -from .computer_screenshot_content import ComputerScreenshotContent -from ..responses.response_input_file import ResponseInputFile -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_image import ResponseInputImage -from ..responses.response_output_text import ResponseOutputText -from ..responses.response_output_refusal import ResponseOutputRefusal - -__all__ = ["Message", "Content", "ContentReasoningText"] - - -class ContentReasoningText(BaseModel): - """Reasoning text from the model.""" - - text: str - """The reasoning text from the model.""" - - type: Literal["reasoning_text"] - """The type of the reasoning text. Always `reasoning_text`.""" - - -Content: TypeAlias = Annotated[ - Union[ - ResponseInputText, - ResponseOutputText, - TextContent, - SummaryTextContent, - ContentReasoningText, - ResponseOutputRefusal, - ResponseInputImage, - ComputerScreenshotContent, - ResponseInputFile, - ], - PropertyInfo(discriminator="type"), -] - - -class Message(BaseModel): - """A message to or from the model.""" - - id: str - """The unique ID of the message.""" - - content: List[Content] - """The content of the message""" - - role: Literal["unknown", "user", "assistant", "system", "critic", "discriminator", "developer", "tool"] - """The role of the message. - - One of `unknown`, `user`, `assistant`, `system`, `critic`, `discriminator`, - `developer`, or `tool`. - """ - - status: Literal["in_progress", "completed", "incomplete"] - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Literal["message"] - """The type of the message. Always set to `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content.py deleted file mode 100644 index cfe9307..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..responses.response_output_text import ResponseOutputText - -__all__ = ["OutputTextContent"] - -OutputTextContent = ResponseOutputText diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content_param.py deleted file mode 100644 index dc3e202..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/output_text_content_param.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..responses.response_output_text_param import ResponseOutputTextParam - -OutputTextContentParam = ResponseOutputTextParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content.py deleted file mode 100644 index 6206c26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..responses.response_output_refusal import ResponseOutputRefusal - -__all__ = ["RefusalContent"] - -RefusalContent = ResponseOutputRefusal diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content_param.py deleted file mode 100644 index 9b83da5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/refusal_content_param.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..responses.response_output_refusal_param import ResponseOutputRefusalParam - -RefusalContentParam = ResponseOutputRefusalParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/summary_text_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/summary_text_content.py deleted file mode 100644 index 6464a36..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/summary_text_content.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["SummaryTextContent"] - - -class SummaryTextContent(BaseModel): - """A summary text from the model.""" - - text: str - """A summary of the reasoning output from the model so far.""" - - type: Literal["summary_text"] - """The type of the object. Always `summary_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/text_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/text_content.py deleted file mode 100644 index e602466..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/conversations/text_content.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TextContent"] - - -class TextContent(BaseModel): - """A text content.""" - - text: str - - type: Literal["text"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/create_embedding_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/create_embedding_response.py deleted file mode 100644 index 314a7f9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/create_embedding_response.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from .._models import BaseModel -from .embedding import Embedding - -__all__ = ["CreateEmbeddingResponse", "Usage"] - - -class Usage(BaseModel): - """The usage information for the request.""" - - prompt_tokens: int - """The number of tokens used by the prompt.""" - - total_tokens: int - """The total number of tokens used by the request.""" - - -class CreateEmbeddingResponse(BaseModel): - data: List[Embedding] - """The list of embeddings generated by the model.""" - - model: str - """The name of the model used to generate the embedding.""" - - object: Literal["list"] - """The object type, which is always "list".""" - - usage: Usage - """The usage information for the request.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding.py b/backend/venv39/lib/python3.9/site-packages/openai/types/embedding.py deleted file mode 100644 index fbffec0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["Embedding"] - - -class Embedding(BaseModel): - """Represents an embedding vector returned by embedding endpoint.""" - - embedding: List[float] - """The embedding vector, which is a list of floats. - - The length of vector depends on the model as listed in the - [embedding guide](https://platform.openai.com/docs/guides/embeddings). - """ - - index: int - """The index of the embedding in the list of embeddings.""" - - object: Literal["embedding"] - """The object type, which is always "embedding".""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_create_params.py deleted file mode 100644 index ab3e877..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_create_params.py +++ /dev/null @@ -1,55 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypedDict - -from .._types import SequenceNotStr -from .embedding_model import EmbeddingModel - -__all__ = ["EmbeddingCreateParams"] - - -class EmbeddingCreateParams(TypedDict, total=False): - input: Required[Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]]] - """Input text to embed, encoded as a string or array of tokens. - - To embed multiple inputs in a single request, pass an array of strings or array - of token arrays. The input must not exceed the max input tokens for the model - (8192 tokens for all embedding models), cannot be an empty string, and any array - must be 2048 dimensions or less. - [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - for counting tokens. In addition to the per-input token limit, all embedding - models enforce a maximum of 300,000 tokens summed across all inputs in a single - request. - """ - - model: Required[Union[str, EmbeddingModel]] - """ID of the model to use. - - You can use the - [List models](https://platform.openai.com/docs/api-reference/models/list) API to - see all of your available models, or see our - [Model overview](https://platform.openai.com/docs/models) for descriptions of - them. - """ - - dimensions: int - """The number of dimensions the resulting output embeddings should have. - - Only supported in `text-embedding-3` and later models. - """ - - encoding_format: Literal["float", "base64"] - """The format to return the embeddings in. - - Can be either `float` or [`base64`](https://pypi.org/project/pybase64/). - """ - - user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_model.py deleted file mode 100644 index 075ff97..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/embedding_model.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["EmbeddingModel"] - -EmbeddingModel: TypeAlias = Literal["text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_params.py deleted file mode 100644 index a1d5ea5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_params.py +++ /dev/null @@ -1,244 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .._types import SequenceNotStr -from .shared_params.metadata import Metadata -from .graders.grader_inputs_param import GraderInputsParam -from .graders.python_grader_param import PythonGraderParam -from .graders.score_model_grader_param import ScoreModelGraderParam -from .graders.string_check_grader_param import StringCheckGraderParam -from .responses.response_input_text_param import ResponseInputTextParam -from .graders.text_similarity_grader_param import TextSimilarityGraderParam -from .responses.response_input_audio_param import ResponseInputAudioParam - -__all__ = [ - "EvalCreateParams", - "DataSourceConfig", - "DataSourceConfigCustom", - "DataSourceConfigLogs", - "DataSourceConfigStoredCompletions", - "TestingCriterion", - "TestingCriterionLabelModel", - "TestingCriterionLabelModelInput", - "TestingCriterionLabelModelInputSimpleInputMessage", - "TestingCriterionLabelModelInputEvalItem", - "TestingCriterionLabelModelInputEvalItemContent", - "TestingCriterionLabelModelInputEvalItemContentOutputText", - "TestingCriterionLabelModelInputEvalItemContentInputImage", - "TestingCriterionTextSimilarity", - "TestingCriterionPython", - "TestingCriterionScoreModel", -] - - -class EvalCreateParams(TypedDict, total=False): - data_source_config: Required[DataSourceConfig] - """The configuration for the data source used for the evaluation runs. - - Dictates the schema of the data used in the evaluation. - """ - - testing_criteria: Required[Iterable[TestingCriterion]] - """A list of graders for all eval runs in this group. - - Graders can reference variables in the data source using double curly braces - notation, like `{{item.variable_name}}`. To reference the model's output, use - the `sample` namespace (ie, `{{sample.output_text}}`). - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the evaluation.""" - - -class DataSourceConfigCustom(TypedDict, total=False): - """ - A CustomDataSourceConfig object that defines the schema for the data source used for the evaluation runs. - This schema is used to define the shape of the data that will be: - - Used to define your testing criteria and - - What data is required when creating a run - """ - - item_schema: Required[Dict[str, object]] - """The json schema for each row in the data source.""" - - type: Required[Literal["custom"]] - """The type of data source. Always `custom`.""" - - include_sample_schema: bool - """ - Whether the eval should expect you to populate the sample namespace (ie, by - generating responses off of your data source) - """ - - -class DataSourceConfigLogs(TypedDict, total=False): - """ - A data source config which specifies the metadata property of your logs query. - This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. - """ - - type: Required[Literal["logs"]] - """The type of data source. Always `logs`.""" - - metadata: Dict[str, object] - """Metadata filters for the logs data source.""" - - -class DataSourceConfigStoredCompletions(TypedDict, total=False): - """Deprecated in favor of LogsDataSourceConfig.""" - - type: Required[Literal["stored_completions"]] - """The type of data source. Always `stored_completions`.""" - - metadata: Dict[str, object] - """Metadata filters for the stored completions data source.""" - - -DataSourceConfig: TypeAlias = Union[DataSourceConfigCustom, DataSourceConfigLogs, DataSourceConfigStoredCompletions] - - -class TestingCriterionLabelModelInputSimpleInputMessage(TypedDict, total=False): - content: Required[str] - """The content of the message.""" - - role: Required[str] - """The role of the message (e.g. "system", "assistant", "user").""" - - -class TestingCriterionLabelModelInputEvalItemContentOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class TestingCriterionLabelModelInputEvalItemContentInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -TestingCriterionLabelModelInputEvalItemContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - TestingCriterionLabelModelInputEvalItemContentOutputText, - TestingCriterionLabelModelInputEvalItemContentInputImage, - ResponseInputAudioParam, - GraderInputsParam, -] - - -class TestingCriterionLabelModelInputEvalItem(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[TestingCriterionLabelModelInputEvalItemContent] - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -TestingCriterionLabelModelInput: TypeAlias = Union[ - TestingCriterionLabelModelInputSimpleInputMessage, TestingCriterionLabelModelInputEvalItem -] - - -class TestingCriterionLabelModel(TypedDict, total=False): - """ - A LabelModelGrader object which uses a model to assign labels to each item - in the evaluation. - """ - - input: Required[Iterable[TestingCriterionLabelModelInput]] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - labels: Required[SequenceNotStr[str]] - """The labels to classify to each item in the evaluation.""" - - model: Required[str] - """The model to use for the evaluation. Must support structured outputs.""" - - name: Required[str] - """The name of the grader.""" - - passing_labels: Required[SequenceNotStr[str]] - """The labels that indicate a passing result. Must be a subset of labels.""" - - type: Required[Literal["label_model"]] - """The object type, which is always `label_model`.""" - - -class TestingCriterionTextSimilarity(TextSimilarityGraderParam, total=False): - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - - pass_threshold: Required[float] - """The threshold for the score.""" - - -class TestingCriterionPython(PythonGraderParam, total=False): - """A PythonGrader object that runs a python script on the input.""" - - pass_threshold: float - """The threshold for the score.""" - - -class TestingCriterionScoreModel(ScoreModelGraderParam, total=False): - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - - pass_threshold: float - """The threshold for the score.""" - - -TestingCriterion: TypeAlias = Union[ - TestingCriterionLabelModel, - StringCheckGraderParam, - TestingCriterionTextSimilarity, - TestingCriterionPython, - TestingCriterionScoreModel, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_response.py deleted file mode 100644 index f316642..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_create_response.py +++ /dev/null @@ -1,130 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel -from .shared.metadata import Metadata -from .graders.python_grader import PythonGrader -from .graders.label_model_grader import LabelModelGrader -from .graders.score_model_grader import ScoreModelGrader -from .graders.string_check_grader import StringCheckGrader -from .eval_custom_data_source_config import EvalCustomDataSourceConfig -from .graders.text_similarity_grader import TextSimilarityGrader -from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig - -__all__ = [ - "EvalCreateResponse", - "DataSourceConfig", - "DataSourceConfigLogs", - "TestingCriterion", - "TestingCriterionEvalGraderTextSimilarity", - "TestingCriterionEvalGraderPython", - "TestingCriterionEvalGraderScoreModel", -] - - -class DataSourceConfigLogs(BaseModel): - """ - A LogsDataSourceConfig which specifies the metadata property of your logs query. - This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. - The schema returned by this data source config is used to defined what variables are available in your evals. - `item` and `sample` are both defined when using this data source config. - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["logs"] - """The type of data source. Always `logs`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], - PropertyInfo(discriminator="type"), -] - - -class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): - __test__ = False - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - pass_threshold: float - """The threshold for the score.""" - - -class TestingCriterionEvalGraderPython(PythonGrader): - __test__ = False - """A PythonGrader object that runs a python script on the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): - __test__ = False - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -TestingCriterion: TypeAlias = Union[ - LabelModelGrader, - StringCheckGrader, - TestingCriterionEvalGraderTextSimilarity, - TestingCriterionEvalGraderPython, - TestingCriterionEvalGraderScoreModel, -] - - -class EvalCreateResponse(BaseModel): - """ - An Eval object with a data source config and testing criteria. - An Eval represents a task to be done for your LLM integration. - Like: - - Improve the quality of my chatbot - - See how well my chatbot handles customer support - - Check if o4-mini is better at my usecase than gpt-4o - """ - - id: str - """Unique identifier for the evaluation.""" - - created_at: int - """The Unix timestamp (in seconds) for when the eval was created.""" - - data_source_config: DataSourceConfig - """Configuration of data sources used in runs of the evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the evaluation.""" - - object: Literal["eval"] - """The object type.""" - - testing_criteria: List[TestingCriterion] - """A list of testing criteria.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_custom_data_source_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_custom_data_source_config.py deleted file mode 100644 index 6234c4f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_custom_data_source_config.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EvalCustomDataSourceConfig"] - - -class EvalCustomDataSourceConfig(BaseModel): - """ - A CustomDataSourceConfig which specifies the schema of your `item` and optionally `sample` namespaces. - The response schema defines the shape of the data that will be: - - Used to define your testing criteria and - - What data is required when creating a run - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["custom"] - """The type of data source. Always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_delete_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_delete_response.py deleted file mode 100644 index a27261e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_delete_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["EvalDeleteResponse"] - - -class EvalDeleteResponse(BaseModel): - deleted: bool - - eval_id: str - - object: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_params.py deleted file mode 100644 index d9a12d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["EvalListParams"] - - -class EvalListParams(TypedDict, total=False): - after: str - """Identifier for the last eval from the previous pagination request.""" - - limit: int - """Number of evals to retrieve.""" - - order: Literal["asc", "desc"] - """Sort order for evals by timestamp. - - Use `asc` for ascending order or `desc` for descending order. - """ - - order_by: Literal["created_at", "updated_at"] - """Evals can be ordered by creation time or last updated time. - - Use `created_at` for creation time or `updated_at` for last updated time. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_response.py deleted file mode 100644 index 7cd92c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_list_response.py +++ /dev/null @@ -1,130 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel -from .shared.metadata import Metadata -from .graders.python_grader import PythonGrader -from .graders.label_model_grader import LabelModelGrader -from .graders.score_model_grader import ScoreModelGrader -from .graders.string_check_grader import StringCheckGrader -from .eval_custom_data_source_config import EvalCustomDataSourceConfig -from .graders.text_similarity_grader import TextSimilarityGrader -from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig - -__all__ = [ - "EvalListResponse", - "DataSourceConfig", - "DataSourceConfigLogs", - "TestingCriterion", - "TestingCriterionEvalGraderTextSimilarity", - "TestingCriterionEvalGraderPython", - "TestingCriterionEvalGraderScoreModel", -] - - -class DataSourceConfigLogs(BaseModel): - """ - A LogsDataSourceConfig which specifies the metadata property of your logs query. - This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. - The schema returned by this data source config is used to defined what variables are available in your evals. - `item` and `sample` are both defined when using this data source config. - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["logs"] - """The type of data source. Always `logs`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], - PropertyInfo(discriminator="type"), -] - - -class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): - __test__ = False - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - pass_threshold: float - """The threshold for the score.""" - - -class TestingCriterionEvalGraderPython(PythonGrader): - __test__ = False - """A PythonGrader object that runs a python script on the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): - __test__ = False - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -TestingCriterion: TypeAlias = Union[ - LabelModelGrader, - StringCheckGrader, - TestingCriterionEvalGraderTextSimilarity, - TestingCriterionEvalGraderPython, - TestingCriterionEvalGraderScoreModel, -] - - -class EvalListResponse(BaseModel): - """ - An Eval object with a data source config and testing criteria. - An Eval represents a task to be done for your LLM integration. - Like: - - Improve the quality of my chatbot - - See how well my chatbot handles customer support - - Check if o4-mini is better at my usecase than gpt-4o - """ - - id: str - """Unique identifier for the evaluation.""" - - created_at: int - """The Unix timestamp (in seconds) for when the eval was created.""" - - data_source_config: DataSourceConfig - """Configuration of data sources used in runs of the evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the evaluation.""" - - object: Literal["eval"] - """The object type.""" - - testing_criteria: List[TestingCriterion] - """A list of testing criteria.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_retrieve_response.py deleted file mode 100644 index 56db7d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_retrieve_response.py +++ /dev/null @@ -1,130 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel -from .shared.metadata import Metadata -from .graders.python_grader import PythonGrader -from .graders.label_model_grader import LabelModelGrader -from .graders.score_model_grader import ScoreModelGrader -from .graders.string_check_grader import StringCheckGrader -from .eval_custom_data_source_config import EvalCustomDataSourceConfig -from .graders.text_similarity_grader import TextSimilarityGrader -from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig - -__all__ = [ - "EvalRetrieveResponse", - "DataSourceConfig", - "DataSourceConfigLogs", - "TestingCriterion", - "TestingCriterionEvalGraderTextSimilarity", - "TestingCriterionEvalGraderPython", - "TestingCriterionEvalGraderScoreModel", -] - - -class DataSourceConfigLogs(BaseModel): - """ - A LogsDataSourceConfig which specifies the metadata property of your logs query. - This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. - The schema returned by this data source config is used to defined what variables are available in your evals. - `item` and `sample` are both defined when using this data source config. - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["logs"] - """The type of data source. Always `logs`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], - PropertyInfo(discriminator="type"), -] - - -class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): - __test__ = False - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - pass_threshold: float - """The threshold for the score.""" - - -class TestingCriterionEvalGraderPython(PythonGrader): - __test__ = False - """A PythonGrader object that runs a python script on the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): - __test__ = False - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -TestingCriterion: TypeAlias = Union[ - LabelModelGrader, - StringCheckGrader, - TestingCriterionEvalGraderTextSimilarity, - TestingCriterionEvalGraderPython, - TestingCriterionEvalGraderScoreModel, -] - - -class EvalRetrieveResponse(BaseModel): - """ - An Eval object with a data source config and testing criteria. - An Eval represents a task to be done for your LLM integration. - Like: - - Improve the quality of my chatbot - - See how well my chatbot handles customer support - - Check if o4-mini is better at my usecase than gpt-4o - """ - - id: str - """Unique identifier for the evaluation.""" - - created_at: int - """The Unix timestamp (in seconds) for when the eval was created.""" - - data_source_config: DataSourceConfig - """Configuration of data sources used in runs of the evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the evaluation.""" - - object: Literal["eval"] - """The object type.""" - - testing_criteria: List[TestingCriterion] - """A list of testing criteria.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_stored_completions_data_source_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_stored_completions_data_source_config.py deleted file mode 100644 index d11f6ae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_stored_completions_data_source_config.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .shared.metadata import Metadata - -__all__ = ["EvalStoredCompletionsDataSourceConfig"] - - -class EvalStoredCompletionsDataSourceConfig(BaseModel): - """Deprecated in favor of LogsDataSourceConfig.""" - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["stored_completions"] - """The type of data source. Always `stored_completions`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_params.py deleted file mode 100644 index 042db29..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -from .shared_params.metadata import Metadata - -__all__ = ["EvalUpdateParams"] - - -class EvalUpdateParams(TypedDict, total=False): - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """Rename the evaluation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_response.py deleted file mode 100644 index 30d4dbc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/eval_update_response.py +++ /dev/null @@ -1,130 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel -from .shared.metadata import Metadata -from .graders.python_grader import PythonGrader -from .graders.label_model_grader import LabelModelGrader -from .graders.score_model_grader import ScoreModelGrader -from .graders.string_check_grader import StringCheckGrader -from .eval_custom_data_source_config import EvalCustomDataSourceConfig -from .graders.text_similarity_grader import TextSimilarityGrader -from .eval_stored_completions_data_source_config import EvalStoredCompletionsDataSourceConfig - -__all__ = [ - "EvalUpdateResponse", - "DataSourceConfig", - "DataSourceConfigLogs", - "TestingCriterion", - "TestingCriterionEvalGraderTextSimilarity", - "TestingCriterionEvalGraderPython", - "TestingCriterionEvalGraderScoreModel", -] - - -class DataSourceConfigLogs(BaseModel): - """ - A LogsDataSourceConfig which specifies the metadata property of your logs query. - This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. - The schema returned by this data source config is used to defined what variables are available in your evals. - `item` and `sample` are both defined when using this data source config. - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The json schema for the run data source items. Learn how to build JSON schemas - [here](https://json-schema.org/). - """ - - type: Literal["logs"] - """The type of data source. Always `logs`.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - -DataSourceConfig: TypeAlias = Annotated[ - Union[EvalCustomDataSourceConfig, DataSourceConfigLogs, EvalStoredCompletionsDataSourceConfig], - PropertyInfo(discriminator="type"), -] - - -class TestingCriterionEvalGraderTextSimilarity(TextSimilarityGrader): - __test__ = False - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - pass_threshold: float - """The threshold for the score.""" - - -class TestingCriterionEvalGraderPython(PythonGrader): - __test__ = False - """A PythonGrader object that runs a python script on the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -class TestingCriterionEvalGraderScoreModel(ScoreModelGrader): - __test__ = False - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - pass_threshold: Optional[float] = None - """The threshold for the score.""" - - -TestingCriterion: TypeAlias = Union[ - LabelModelGrader, - StringCheckGrader, - TestingCriterionEvalGraderTextSimilarity, - TestingCriterionEvalGraderPython, - TestingCriterionEvalGraderScoreModel, -] - - -class EvalUpdateResponse(BaseModel): - """ - An Eval object with a data source config and testing criteria. - An Eval represents a task to be done for your LLM integration. - Like: - - Improve the quality of my chatbot - - See how well my chatbot handles customer support - - Check if o4-mini is better at my usecase than gpt-4o - """ - - id: str - """Unique identifier for the evaluation.""" - - created_at: int - """The Unix timestamp (in seconds) for when the eval was created.""" - - data_source_config: DataSourceConfig - """Configuration of data sources used in runs of the evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the evaluation.""" - - object: Literal["eval"] - """The object type.""" - - testing_criteria: List[TestingCriterion] - """A list of testing criteria.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/__init__.py deleted file mode 100644 index ebf84c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .eval_api_error import EvalAPIError as EvalAPIError -from .run_list_params import RunListParams as RunListParams -from .run_create_params import RunCreateParams as RunCreateParams -from .run_list_response import RunListResponse as RunListResponse -from .run_cancel_response import RunCancelResponse as RunCancelResponse -from .run_create_response import RunCreateResponse as RunCreateResponse -from .run_delete_response import RunDeleteResponse as RunDeleteResponse -from .run_retrieve_response import RunRetrieveResponse as RunRetrieveResponse -from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource as CreateEvalJSONLRunDataSource -from .create_eval_completions_run_data_source import ( - CreateEvalCompletionsRunDataSource as CreateEvalCompletionsRunDataSource, -) -from .create_eval_jsonl_run_data_source_param import ( - CreateEvalJSONLRunDataSourceParam as CreateEvalJSONLRunDataSourceParam, -) -from .create_eval_completions_run_data_source_param import ( - CreateEvalCompletionsRunDataSourceParam as CreateEvalCompletionsRunDataSourceParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source.py deleted file mode 100644 index 726ae6a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source.py +++ /dev/null @@ -1,258 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from ..shared.metadata import Metadata -from ..graders.grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..shared.response_format_text import ResponseFormatText -from ..responses.easy_input_message import EasyInputMessage -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio -from ..chat.chat_completion_function_tool import ChatCompletionFunctionTool -from ..shared.response_format_json_object import ResponseFormatJSONObject -from ..shared.response_format_json_schema import ResponseFormatJSONSchema - -__all__ = [ - "CreateEvalCompletionsRunDataSource", - "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", - "SourceStoredCompletions", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateEvalItem", - "InputMessagesTemplateTemplateEvalItemContent", - "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentInputImage", - "InputMessagesItemReference", - "SamplingParams", - "SamplingParamsResponseFormat", -] - - -class SourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class SourceFileContent(BaseModel): - content: List[SourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class SourceStoredCompletions(BaseModel): - """A StoredCompletionsRunDataSource configuration describing a set of filters""" - - type: Literal["stored_completions"] - """The type of source. Always `stored_completions`.""" - - created_after: Optional[int] = None - """An optional Unix timestamp to filter items created after this time.""" - - created_before: Optional[int] = None - """An optional Unix timestamp to filter items created before this time.""" - - limit: Optional[int] = None - """An optional maximum number of items to return.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Optional[str] = None - """An optional model to filter by (e.g., 'gpt-4o').""" - - -Source: TypeAlias = Annotated[ - Union[SourceFileContent, SourceFileID, SourceStoredCompletions], PropertyInfo(discriminator="type") -] - - -class InputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputText, - InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudio, - GraderInputs, -] - - -class InputMessagesTemplateTemplateEvalItem(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: InputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessage, InputMessagesTemplateTemplateEvalItem] - - -class InputMessagesTemplate(BaseModel): - template: List[InputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the `item` namespace. Ie, "item.input_trajectory" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Annotated[ - Union[InputMessagesTemplate, InputMessagesItemReference], PropertyInfo(discriminator="type") -] - -SamplingParamsResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] - - -class SamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: Optional[SamplingParamsResponseFormat] = None - """An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - tools: Optional[List[ChatCompletionFunctionTool]] = None - """A list of tools the model may call. - - Currently, only functions are supported as a tool. Use this to provide a list of - functions the model may generate JSON inputs for. A max of 128 functions are - supported. - """ - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class CreateEvalCompletionsRunDataSource(BaseModel): - """A CompletionsRunDataSource object describing a model sampling configuration.""" - - source: Source - """Determines what populates the `item` namespace in this run's data source.""" - - type: Literal["completions"] - """The type of run data source. Always `completions`.""" - - input_messages: Optional[InputMessages] = None - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[SamplingParams] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source_param.py deleted file mode 100644 index 6842f84..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_completions_run_data_source_param.py +++ /dev/null @@ -1,254 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..graders.grader_inputs_param import GraderInputsParam -from ..responses.easy_input_message_param import EasyInputMessageParam -from ..shared_params.response_format_text import ResponseFormatText -from ..responses.response_input_text_param import ResponseInputTextParam -from ..responses.response_input_audio_param import ResponseInputAudioParam -from ..chat.chat_completion_function_tool_param import ChatCompletionFunctionToolParam -from ..shared_params.response_format_json_object import ResponseFormatJSONObject -from ..shared_params.response_format_json_schema import ResponseFormatJSONSchema - -__all__ = [ - "CreateEvalCompletionsRunDataSourceParam", - "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", - "SourceStoredCompletions", - "InputMessages", - "InputMessagesTemplate", - "InputMessagesTemplateTemplate", - "InputMessagesTemplateTemplateEvalItem", - "InputMessagesTemplateTemplateEvalItemContent", - "InputMessagesTemplateTemplateEvalItemContentOutputText", - "InputMessagesTemplateTemplateEvalItemContentInputImage", - "InputMessagesItemReference", - "SamplingParams", - "SamplingParamsResponseFormat", -] - - -class SourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class SourceFileContent(TypedDict, total=False): - content: Required[Iterable[SourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - -class SourceStoredCompletions(TypedDict, total=False): - """A StoredCompletionsRunDataSource configuration describing a set of filters""" - - type: Required[Literal["stored_completions"]] - """The type of source. Always `stored_completions`.""" - - created_after: Optional[int] - """An optional Unix timestamp to filter items created after this time.""" - - created_before: Optional[int] - """An optional Unix timestamp to filter items created before this time.""" - - limit: Optional[int] - """An optional maximum number of items to return.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: Optional[str] - """An optional model to filter by (e.g., 'gpt-4o').""" - - -Source: TypeAlias = Union[SourceFileContent, SourceFileID, SourceStoredCompletions] - - -class InputMessagesTemplateTemplateEvalItemContentOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputMessagesTemplateTemplateEvalItemContentInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputMessagesTemplateTemplateEvalItemContentOutputText, - InputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudioParam, - GraderInputsParam, -] - - -class InputMessagesTemplateTemplateEvalItem(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[InputMessagesTemplateTemplateEvalItemContent] - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -InputMessagesTemplateTemplate: TypeAlias = Union[EasyInputMessageParam, InputMessagesTemplateTemplateEvalItem] - - -class InputMessagesTemplate(TypedDict, total=False): - template: Required[Iterable[InputMessagesTemplateTemplate]] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Required[Literal["template"]] - """The type of input messages. Always `template`.""" - - -class InputMessagesItemReference(TypedDict, total=False): - item_reference: Required[str] - """A reference to a variable in the `item` namespace. Ie, "item.input_trajectory" """ - - type: Required[Literal["item_reference"]] - """The type of input messages. Always `item_reference`.""" - - -InputMessages: TypeAlias = Union[InputMessagesTemplate, InputMessagesItemReference] - -SamplingParamsResponseFormat: TypeAlias = Union[ResponseFormatText, ResponseFormatJSONSchema, ResponseFormatJSONObject] - - -class SamplingParams(TypedDict, total=False): - max_completion_tokens: int - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - response_format: SamplingParamsResponseFormat - """An object specifying the format that the model must output. - - Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - Outputs which ensures the model will match your supplied JSON schema. Learn more - in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - seed: int - """A seed value to initialize the randomness, during sampling.""" - - temperature: float - """A higher temperature increases randomness in the outputs.""" - - tools: Iterable[ChatCompletionFunctionToolParam] - """A list of tools the model may call. - - Currently, only functions are supported as a tool. Use this to provide a list of - functions the model may generate JSON inputs for. A max of 128 functions are - supported. - """ - - top_p: float - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class CreateEvalCompletionsRunDataSourceParam(TypedDict, total=False): - """A CompletionsRunDataSource object describing a model sampling configuration.""" - - source: Required[Source] - """Determines what populates the `item` namespace in this run's data source.""" - - type: Required[Literal["completions"]] - """The type of run data source. Always `completions`.""" - - input_messages: InputMessages - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: str - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: SamplingParams diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source.py deleted file mode 100644 index 36ede2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["CreateEvalJSONLRunDataSource", "Source", "SourceFileContent", "SourceFileContentContent", "SourceFileID"] - - -class SourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class SourceFileContent(BaseModel): - content: List[SourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -Source: TypeAlias = Annotated[Union[SourceFileContent, SourceFileID], PropertyInfo(discriminator="type")] - - -class CreateEvalJSONLRunDataSource(BaseModel): - """ - A JsonlRunDataSource object with that specifies a JSONL file that matches the eval - """ - - source: Source - """Determines what populates the `item` namespace in the data source.""" - - type: Literal["jsonl"] - """The type of data source. Always `jsonl`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source_param.py deleted file mode 100644 index b87ba9c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/create_eval_jsonl_run_data_source_param.py +++ /dev/null @@ -1,51 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = [ - "CreateEvalJSONLRunDataSourceParam", - "Source", - "SourceFileContent", - "SourceFileContentContent", - "SourceFileID", -] - - -class SourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class SourceFileContent(TypedDict, total=False): - content: Required[Iterable[SourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class SourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - -Source: TypeAlias = Union[SourceFileContent, SourceFileID] - - -class CreateEvalJSONLRunDataSourceParam(TypedDict, total=False): - """ - A JsonlRunDataSource object with that specifies a JSONL file that matches the eval - """ - - source: Required[Source] - """Determines what populates the `item` namespace in the data source.""" - - type: Required[Literal["jsonl"]] - """The type of data source. Always `jsonl`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/eval_api_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/eval_api_error.py deleted file mode 100644 index 9b2c187..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/eval_api_error.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["EvalAPIError"] - - -class EvalAPIError(BaseModel): - """An object representing an error response from the Eval API.""" - - code: str - """The error code.""" - - message: str - """The error message.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_cancel_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_cancel_response.py deleted file mode 100644 index ea4797e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_cancel_response.py +++ /dev/null @@ -1,452 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .eval_api_error import EvalAPIError -from ..responses.tool import Tool -from ..shared.metadata import Metadata -from ..graders.grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio -from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from ..responses.response_format_text_config import ResponseFormatTextConfig -from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource - -__all__ = [ - "RunCancelResponse", - "DataSource", - "DataSourceResponses", - "DataSourceResponsesSource", - "DataSourceResponsesSourceFileContent", - "DataSourceResponsesSourceFileContentContent", - "DataSourceResponsesSourceFileID", - "DataSourceResponsesSourceResponses", - "DataSourceResponsesInputMessages", - "DataSourceResponsesInputMessagesTemplate", - "DataSourceResponsesInputMessagesTemplateTemplate", - "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", - "DataSourceResponsesInputMessagesItemReference", - "DataSourceResponsesSamplingParams", - "DataSourceResponsesSamplingParamsText", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceResponsesSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceResponsesSourceFileContent(BaseModel): - content: List[DataSourceResponsesSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceResponsesSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceResponsesSourceResponses(BaseModel): - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] = None - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceResponsesSource: TypeAlias = Annotated[ - Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudio, - GraderInputs, -] - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceResponsesInputMessagesTemplateTemplateChatMessage, - DataSourceResponsesInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceResponsesInputMessagesTemplate(BaseModel): - template: List[DataSourceResponsesInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceResponsesInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the `item` namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceResponsesInputMessages: TypeAlias = Annotated[ - Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesSamplingParamsText(BaseModel): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - -class DataSourceResponsesSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - text: Optional[DataSourceResponsesSamplingParamsText] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tools: Optional[List[Tool]] = None - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceResponses(BaseModel): - """A ResponsesRunDataSource object describing a model sampling configuration.""" - - source: DataSourceResponsesSource - """Determines what populates the `item` namespace in this run's data source.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - input_messages: Optional[DataSourceResponsesInputMessages] = None - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceResponsesSamplingParams] = None - - -DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class PerModelUsage(BaseModel): - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - invocation_count: int - """The number of invocations.""" - - run_model_name: str = FieldInfo(alias="model_name") - """The name of the model.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class PerTestingCriteriaResult(BaseModel): - failed: int - """Number of tests failed for this criteria.""" - - passed: int - """Number of tests passed for this criteria.""" - - testing_criteria: str - """A description of the testing criteria.""" - - -class ResultCounts(BaseModel): - """Counters summarizing the outcomes of the evaluation run.""" - - errored: int - """Number of output items that resulted in an error.""" - - failed: int - """Number of output items that failed to pass the evaluation.""" - - passed: int - """Number of output items that passed the evaluation.""" - - total: int - """Total number of executed output items.""" - - -class RunCancelResponse(BaseModel): - """A schema representing an evaluation run.""" - - id: str - """Unique identifier for the evaluation run.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - data_source: DataSource - """Information about the run's data source.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - eval_id: str - """The identifier of the associated evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """The model that is evaluated, if applicable.""" - - name: str - """The name of the evaluation run.""" - - object: Literal["eval.run"] - """The type of the object. Always "eval.run".""" - - per_model_usage: List[PerModelUsage] - """Usage statistics for each model during the evaluation run.""" - - per_testing_criteria_results: List[PerTestingCriteriaResult] - """Results per testing criteria applied during the evaluation run.""" - - report_url: str - """The URL to the rendered evaluation run report on the UI dashboard.""" - - result_counts: ResultCounts - """Counters summarizing the outcomes of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_params.py deleted file mode 100644 index 02804c3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_params.py +++ /dev/null @@ -1,371 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..responses.tool_param import ToolParam -from ..shared_params.metadata import Metadata -from ..shared.reasoning_effort import ReasoningEffort -from ..graders.grader_inputs_param import GraderInputsParam -from ..responses.response_input_text_param import ResponseInputTextParam -from ..responses.response_input_audio_param import ResponseInputAudioParam -from .create_eval_jsonl_run_data_source_param import CreateEvalJSONLRunDataSourceParam -from ..responses.response_format_text_config_param import ResponseFormatTextConfigParam -from .create_eval_completions_run_data_source_param import CreateEvalCompletionsRunDataSourceParam - -__all__ = [ - "RunCreateParams", - "DataSource", - "DataSourceCreateEvalResponsesRunDataSource", - "DataSourceCreateEvalResponsesRunDataSourceSource", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileContent", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent", - "DataSourceCreateEvalResponsesRunDataSourceSourceFileID", - "DataSourceCreateEvalResponsesRunDataSourceSourceResponses", - "DataSourceCreateEvalResponsesRunDataSourceInputMessages", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage", - "DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference", - "DataSourceCreateEvalResponsesRunDataSourceSamplingParams", - "DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText", -] - - -class RunCreateParams(TypedDict, total=False): - data_source: Required[DataSource] - """Details about the run's data source.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the run.""" - - -class DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent(TypedDict, total=False): - item: Required[Dict[str, object]] - - sample: Dict[str, object] - - -class DataSourceCreateEvalResponsesRunDataSourceSourceFileContent(TypedDict, total=False): - content: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceSourceFileContentContent]] - """The content of the jsonl file.""" - - type: Required[Literal["file_content"]] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceSourceFileID(TypedDict, total=False): - id: Required[str] - """The identifier of the file.""" - - type: Required[Literal["file_id"]] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceSourceResponses(TypedDict, total=False): - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Required[Literal["responses"]] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - temperature: Optional[float] - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[SequenceNotStr[str]] - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[SequenceNotStr[str]] - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceCreateEvalResponsesRunDataSourceSource: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceSourceFileContent, - DataSourceCreateEvalResponsesRunDataSourceSourceFileID, - DataSourceCreateEvalResponsesRunDataSourceSourceResponses, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage(TypedDict, total=False): - content: Required[str] - """The content of the message.""" - - role: Required[str] - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText( - TypedDict, total=False -): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage( - TypedDict, total=False -): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudioParam, - GraderInputsParam, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItemContent] - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateChatMessage, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate(TypedDict, total=False): - template: Required[Iterable[DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplateTemplate]] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Required[Literal["template"]] - """The type of input messages. Always `template`.""" - - -class DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference(TypedDict, total=False): - item_reference: Required[str] - """A reference to a variable in the `item` namespace. Ie, "item.name" """ - - type: Required[Literal["item_reference"]] - """The type of input messages. Always `item_reference`.""" - - -DataSourceCreateEvalResponsesRunDataSourceInputMessages: TypeAlias = Union[ - DataSourceCreateEvalResponsesRunDataSourceInputMessagesTemplate, - DataSourceCreateEvalResponsesRunDataSourceInputMessagesItemReference, -] - - -class DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText(TypedDict, total=False): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: ResponseFormatTextConfigParam - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - -class DataSourceCreateEvalResponsesRunDataSourceSamplingParams(TypedDict, total=False): - max_completion_tokens: int - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: int - """A seed value to initialize the randomness, during sampling.""" - - temperature: float - """A higher temperature increases randomness in the outputs.""" - - text: DataSourceCreateEvalResponsesRunDataSourceSamplingParamsText - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tools: Iterable[ToolParam] - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - top_p: float - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceCreateEvalResponsesRunDataSource(TypedDict, total=False): - """A ResponsesRunDataSource object describing a model sampling configuration.""" - - source: Required[DataSourceCreateEvalResponsesRunDataSourceSource] - """Determines what populates the `item` namespace in this run's data source.""" - - type: Required[Literal["responses"]] - """The type of run data source. Always `responses`.""" - - input_messages: DataSourceCreateEvalResponsesRunDataSourceInputMessages - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: str - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: DataSourceCreateEvalResponsesRunDataSourceSamplingParams - - -DataSource: TypeAlias = Union[ - CreateEvalJSONLRunDataSourceParam, - CreateEvalCompletionsRunDataSourceParam, - DataSourceCreateEvalResponsesRunDataSource, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_response.py deleted file mode 100644 index 2cb856d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_create_response.py +++ /dev/null @@ -1,452 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .eval_api_error import EvalAPIError -from ..responses.tool import Tool -from ..shared.metadata import Metadata -from ..graders.grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio -from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from ..responses.response_format_text_config import ResponseFormatTextConfig -from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource - -__all__ = [ - "RunCreateResponse", - "DataSource", - "DataSourceResponses", - "DataSourceResponsesSource", - "DataSourceResponsesSourceFileContent", - "DataSourceResponsesSourceFileContentContent", - "DataSourceResponsesSourceFileID", - "DataSourceResponsesSourceResponses", - "DataSourceResponsesInputMessages", - "DataSourceResponsesInputMessagesTemplate", - "DataSourceResponsesInputMessagesTemplateTemplate", - "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", - "DataSourceResponsesInputMessagesItemReference", - "DataSourceResponsesSamplingParams", - "DataSourceResponsesSamplingParamsText", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceResponsesSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceResponsesSourceFileContent(BaseModel): - content: List[DataSourceResponsesSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceResponsesSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceResponsesSourceResponses(BaseModel): - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] = None - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceResponsesSource: TypeAlias = Annotated[ - Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudio, - GraderInputs, -] - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceResponsesInputMessagesTemplateTemplateChatMessage, - DataSourceResponsesInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceResponsesInputMessagesTemplate(BaseModel): - template: List[DataSourceResponsesInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceResponsesInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the `item` namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceResponsesInputMessages: TypeAlias = Annotated[ - Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesSamplingParamsText(BaseModel): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - -class DataSourceResponsesSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - text: Optional[DataSourceResponsesSamplingParamsText] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tools: Optional[List[Tool]] = None - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceResponses(BaseModel): - """A ResponsesRunDataSource object describing a model sampling configuration.""" - - source: DataSourceResponsesSource - """Determines what populates the `item` namespace in this run's data source.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - input_messages: Optional[DataSourceResponsesInputMessages] = None - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceResponsesSamplingParams] = None - - -DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class PerModelUsage(BaseModel): - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - invocation_count: int - """The number of invocations.""" - - run_model_name: str = FieldInfo(alias="model_name") - """The name of the model.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class PerTestingCriteriaResult(BaseModel): - failed: int - """Number of tests failed for this criteria.""" - - passed: int - """Number of tests passed for this criteria.""" - - testing_criteria: str - """A description of the testing criteria.""" - - -class ResultCounts(BaseModel): - """Counters summarizing the outcomes of the evaluation run.""" - - errored: int - """Number of output items that resulted in an error.""" - - failed: int - """Number of output items that failed to pass the evaluation.""" - - passed: int - """Number of output items that passed the evaluation.""" - - total: int - """Total number of executed output items.""" - - -class RunCreateResponse(BaseModel): - """A schema representing an evaluation run.""" - - id: str - """Unique identifier for the evaluation run.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - data_source: DataSource - """Information about the run's data source.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - eval_id: str - """The identifier of the associated evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """The model that is evaluated, if applicable.""" - - name: str - """The name of the evaluation run.""" - - object: Literal["eval.run"] - """The type of the object. Always "eval.run".""" - - per_model_usage: List[PerModelUsage] - """Usage statistics for each model during the evaluation run.""" - - per_testing_criteria_results: List[PerTestingCriteriaResult] - """Results per testing criteria applied during the evaluation run.""" - - report_url: str - """The URL to the rendered evaluation run report on the UI dashboard.""" - - result_counts: ResultCounts - """Counters summarizing the outcomes of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_delete_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_delete_response.py deleted file mode 100644 index d48d01f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_delete_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["RunDeleteResponse"] - - -class RunDeleteResponse(BaseModel): - deleted: Optional[bool] = None - - object: Optional[str] = None - - run_id: Optional[str] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_params.py deleted file mode 100644 index 383b89d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["RunListParams"] - - -class RunListParams(TypedDict, total=False): - after: str - """Identifier for the last run from the previous pagination request.""" - - limit: int - """Number of runs to retrieve.""" - - order: Literal["asc", "desc"] - """Sort order for runs by timestamp. - - Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - """ - - status: Literal["queued", "in_progress", "completed", "canceled", "failed"] - """Filter runs by status. - - One of `queued` | `in_progress` | `failed` | `completed` | `canceled`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_response.py deleted file mode 100644 index defd4aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_list_response.py +++ /dev/null @@ -1,452 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .eval_api_error import EvalAPIError -from ..responses.tool import Tool -from ..shared.metadata import Metadata -from ..graders.grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio -from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from ..responses.response_format_text_config import ResponseFormatTextConfig -from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource - -__all__ = [ - "RunListResponse", - "DataSource", - "DataSourceResponses", - "DataSourceResponsesSource", - "DataSourceResponsesSourceFileContent", - "DataSourceResponsesSourceFileContentContent", - "DataSourceResponsesSourceFileID", - "DataSourceResponsesSourceResponses", - "DataSourceResponsesInputMessages", - "DataSourceResponsesInputMessagesTemplate", - "DataSourceResponsesInputMessagesTemplateTemplate", - "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", - "DataSourceResponsesInputMessagesItemReference", - "DataSourceResponsesSamplingParams", - "DataSourceResponsesSamplingParamsText", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceResponsesSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceResponsesSourceFileContent(BaseModel): - content: List[DataSourceResponsesSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceResponsesSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceResponsesSourceResponses(BaseModel): - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] = None - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceResponsesSource: TypeAlias = Annotated[ - Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudio, - GraderInputs, -] - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceResponsesInputMessagesTemplateTemplateChatMessage, - DataSourceResponsesInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceResponsesInputMessagesTemplate(BaseModel): - template: List[DataSourceResponsesInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceResponsesInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the `item` namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceResponsesInputMessages: TypeAlias = Annotated[ - Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesSamplingParamsText(BaseModel): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - -class DataSourceResponsesSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - text: Optional[DataSourceResponsesSamplingParamsText] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tools: Optional[List[Tool]] = None - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceResponses(BaseModel): - """A ResponsesRunDataSource object describing a model sampling configuration.""" - - source: DataSourceResponsesSource - """Determines what populates the `item` namespace in this run's data source.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - input_messages: Optional[DataSourceResponsesInputMessages] = None - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceResponsesSamplingParams] = None - - -DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class PerModelUsage(BaseModel): - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - invocation_count: int - """The number of invocations.""" - - run_model_name: str = FieldInfo(alias="model_name") - """The name of the model.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class PerTestingCriteriaResult(BaseModel): - failed: int - """Number of tests failed for this criteria.""" - - passed: int - """Number of tests passed for this criteria.""" - - testing_criteria: str - """A description of the testing criteria.""" - - -class ResultCounts(BaseModel): - """Counters summarizing the outcomes of the evaluation run.""" - - errored: int - """Number of output items that resulted in an error.""" - - failed: int - """Number of output items that failed to pass the evaluation.""" - - passed: int - """Number of output items that passed the evaluation.""" - - total: int - """Total number of executed output items.""" - - -class RunListResponse(BaseModel): - """A schema representing an evaluation run.""" - - id: str - """Unique identifier for the evaluation run.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - data_source: DataSource - """Information about the run's data source.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - eval_id: str - """The identifier of the associated evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """The model that is evaluated, if applicable.""" - - name: str - """The name of the evaluation run.""" - - object: Literal["eval.run"] - """The type of the object. Always "eval.run".""" - - per_model_usage: List[PerModelUsage] - """Usage statistics for each model during the evaluation run.""" - - per_testing_criteria_results: List[PerTestingCriteriaResult] - """Results per testing criteria applied during the evaluation run.""" - - report_url: str - """The URL to the rendered evaluation run report on the UI dashboard.""" - - result_counts: ResultCounts - """Counters summarizing the outcomes of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_retrieve_response.py deleted file mode 100644 index 4c218a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/run_retrieve_response.py +++ /dev/null @@ -1,452 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .eval_api_error import EvalAPIError -from ..responses.tool import Tool -from ..shared.metadata import Metadata -from ..graders.grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio -from .create_eval_jsonl_run_data_source import CreateEvalJSONLRunDataSource -from ..responses.response_format_text_config import ResponseFormatTextConfig -from .create_eval_completions_run_data_source import CreateEvalCompletionsRunDataSource - -__all__ = [ - "RunRetrieveResponse", - "DataSource", - "DataSourceResponses", - "DataSourceResponsesSource", - "DataSourceResponsesSourceFileContent", - "DataSourceResponsesSourceFileContentContent", - "DataSourceResponsesSourceFileID", - "DataSourceResponsesSourceResponses", - "DataSourceResponsesInputMessages", - "DataSourceResponsesInputMessagesTemplate", - "DataSourceResponsesInputMessagesTemplateTemplate", - "DataSourceResponsesInputMessagesTemplateTemplateChatMessage", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItem", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText", - "DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage", - "DataSourceResponsesInputMessagesItemReference", - "DataSourceResponsesSamplingParams", - "DataSourceResponsesSamplingParamsText", - "PerModelUsage", - "PerTestingCriteriaResult", - "ResultCounts", -] - - -class DataSourceResponsesSourceFileContentContent(BaseModel): - item: Dict[str, object] - - sample: Optional[Dict[str, object]] = None - - -class DataSourceResponsesSourceFileContent(BaseModel): - content: List[DataSourceResponsesSourceFileContentContent] - """The content of the jsonl file.""" - - type: Literal["file_content"] - """The type of jsonl source. Always `file_content`.""" - - -class DataSourceResponsesSourceFileID(BaseModel): - id: str - """The identifier of the file.""" - - type: Literal["file_id"] - """The type of jsonl source. Always `file_id`.""" - - -class DataSourceResponsesSourceResponses(BaseModel): - """A EvalResponsesSource object describing a run data source configuration.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - created_after: Optional[int] = None - """Only include items created after this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - created_before: Optional[int] = None - """Only include items created before this timestamp (inclusive). - - This is a query parameter used to select responses. - """ - - instructions_search: Optional[str] = None - """Optional string to search the 'instructions' field. - - This is a query parameter used to select responses. - """ - - metadata: Optional[object] = None - """Metadata filter for the responses. - - This is a query parameter used to select responses. - """ - - model: Optional[str] = None - """The name of the model to find responses for. - - This is a query parameter used to select responses. - """ - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - temperature: Optional[float] = None - """Sampling temperature. This is a query parameter used to select responses.""" - - tools: Optional[List[str]] = None - """List of tool names. This is a query parameter used to select responses.""" - - top_p: Optional[float] = None - """Nucleus sampling parameter. This is a query parameter used to select responses.""" - - users: Optional[List[str]] = None - """List of user identifiers. This is a query parameter used to select responses.""" - - -DataSourceResponsesSource: TypeAlias = Annotated[ - Union[DataSourceResponsesSourceFileContent, DataSourceResponsesSourceFileID, DataSourceResponsesSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesInputMessagesTemplateTemplateChatMessage(BaseModel): - content: str - """The content of the message.""" - - role: str - """The role of the message (e.g. "system", "assistant", "user").""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent: TypeAlias = Union[ - str, - ResponseInputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentOutputText, - DataSourceResponsesInputMessagesTemplateTemplateEvalItemContentInputImage, - ResponseInputAudio, - GraderInputs, -] - - -class DataSourceResponsesInputMessagesTemplateTemplateEvalItem(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: DataSourceResponsesInputMessagesTemplateTemplateEvalItemContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -DataSourceResponsesInputMessagesTemplateTemplate: TypeAlias = Union[ - DataSourceResponsesInputMessagesTemplateTemplateChatMessage, - DataSourceResponsesInputMessagesTemplateTemplateEvalItem, -] - - -class DataSourceResponsesInputMessagesTemplate(BaseModel): - template: List[DataSourceResponsesInputMessagesTemplateTemplate] - """A list of chat messages forming the prompt or context. - - May include variable references to the `item` namespace, ie {{item.name}}. - """ - - type: Literal["template"] - """The type of input messages. Always `template`.""" - - -class DataSourceResponsesInputMessagesItemReference(BaseModel): - item_reference: str - """A reference to a variable in the `item` namespace. Ie, "item.name" """ - - type: Literal["item_reference"] - """The type of input messages. Always `item_reference`.""" - - -DataSourceResponsesInputMessages: TypeAlias = Annotated[ - Union[DataSourceResponsesInputMessagesTemplate, DataSourceResponsesInputMessagesItemReference], - PropertyInfo(discriminator="type"), -] - - -class DataSourceResponsesSamplingParamsText(BaseModel): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - -class DataSourceResponsesSamplingParams(BaseModel): - max_completion_tokens: Optional[int] = None - """The maximum number of tokens in the generated output.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - text: Optional[DataSourceResponsesSamplingParamsText] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tools: Optional[List[Tool]] = None - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - The two categories of tools you can provide the model are: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code. Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class DataSourceResponses(BaseModel): - """A ResponsesRunDataSource object describing a model sampling configuration.""" - - source: DataSourceResponsesSource - """Determines what populates the `item` namespace in this run's data source.""" - - type: Literal["responses"] - """The type of run data source. Always `responses`.""" - - input_messages: Optional[DataSourceResponsesInputMessages] = None - """Used when sampling from a model. - - Dictates the structure of the messages passed into the model. Can either be a - reference to a prebuilt trajectory (ie, `item.input_trajectory`), or a template - with variable references to the `item` namespace. - """ - - model: Optional[str] = None - """The name of the model to use for generating completions (e.g. "o3-mini").""" - - sampling_params: Optional[DataSourceResponsesSamplingParams] = None - - -DataSource: TypeAlias = Annotated[ - Union[CreateEvalJSONLRunDataSource, CreateEvalCompletionsRunDataSource, DataSourceResponses], - PropertyInfo(discriminator="type"), -] - - -class PerModelUsage(BaseModel): - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - invocation_count: int - """The number of invocations.""" - - run_model_name: str = FieldInfo(alias="model_name") - """The name of the model.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class PerTestingCriteriaResult(BaseModel): - failed: int - """Number of tests failed for this criteria.""" - - passed: int - """Number of tests passed for this criteria.""" - - testing_criteria: str - """A description of the testing criteria.""" - - -class ResultCounts(BaseModel): - """Counters summarizing the outcomes of the evaluation run.""" - - errored: int - """Number of output items that resulted in an error.""" - - failed: int - """Number of output items that failed to pass the evaluation.""" - - passed: int - """Number of output items that passed the evaluation.""" - - total: int - """Total number of executed output items.""" - - -class RunRetrieveResponse(BaseModel): - """A schema representing an evaluation run.""" - - id: str - """Unique identifier for the evaluation run.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - data_source: DataSource - """Information about the run's data source.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - eval_id: str - """The identifier of the associated evaluation.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: str - """The model that is evaluated, if applicable.""" - - name: str - """The name of the evaluation run.""" - - object: Literal["eval.run"] - """The type of the object. Always "eval.run".""" - - per_model_usage: List[PerModelUsage] - """Usage statistics for each model during the evaluation run.""" - - per_testing_criteria_results: List[PerTestingCriteriaResult] - """Results per testing criteria applied during the evaluation run.""" - - report_url: str - """The URL to the rendered evaluation run report on the UI dashboard.""" - - result_counts: ResultCounts - """Counters summarizing the outcomes of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/__init__.py deleted file mode 100644 index b77cbb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .output_item_list_params import OutputItemListParams as OutputItemListParams -from .output_item_list_response import OutputItemListResponse as OutputItemListResponse -from .output_item_retrieve_response import OutputItemRetrieveResponse as OutputItemRetrieveResponse diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_params.py deleted file mode 100644 index 073bfc6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_params.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["OutputItemListParams"] - - -class OutputItemListParams(TypedDict, total=False): - eval_id: Required[str] - - after: str - """Identifier for the last output item from the previous pagination request.""" - - limit: int - """Number of output items to retrieve.""" - - order: Literal["asc", "desc"] - """Sort order for output items by timestamp. - - Use `asc` for ascending order or `desc` for descending order. Defaults to `asc`. - """ - - status: Literal["fail", "pass"] - """Filter output items by status. - - Use `failed` to filter by failed output items or `pass` to filter by passed - output items. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_response.py deleted file mode 100644 index a906a29..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_list_response.py +++ /dev/null @@ -1,144 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import TYPE_CHECKING, Dict, List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel -from ..eval_api_error import EvalAPIError - -__all__ = ["OutputItemListResponse", "Result", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] - - -class Result(BaseModel): - """A single grader result for an evaluation run output item.""" - - name: str - """The name of the grader.""" - - passed: bool - """Whether the grader considered the output a pass.""" - - score: float - """The numeric score produced by the grader.""" - - sample: Optional[Dict[str, object]] = None - """Optional sample or intermediate data produced by the grader.""" - - type: Optional[str] = None - """The grader type (for example, "string-check-grader").""" - - if TYPE_CHECKING: - # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a - # value to this field, so for compatibility we avoid doing it at runtime. - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] - - # Stub to indicate that arbitrary properties are accepted. - # To access properties that are not valid identifiers you can use `getattr`, e.g. - # `getattr(obj, '$type')` - def __getattr__(self, attr: str) -> object: ... - else: - __pydantic_extra__: Dict[str, object] - - -class SampleInput(BaseModel): - """An input message.""" - - content: str - """The content of the message.""" - - role: str - """The role of the message sender (e.g., system, user, developer).""" - - -class SampleOutput(BaseModel): - content: Optional[str] = None - """The content of the message.""" - - role: Optional[str] = None - """The role of the message (e.g. "system", "assistant", "user").""" - - -class SampleUsage(BaseModel): - """Token usage details for the sample.""" - - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class Sample(BaseModel): - """A sample containing the input and output of the evaluation run.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - finish_reason: str - """The reason why the sample generation was finished.""" - - input: List[SampleInput] - """An array of input messages.""" - - max_completion_tokens: int - """The maximum number of tokens allowed for completion.""" - - model: str - """The model used for generating the sample.""" - - output: List[SampleOutput] - """An array of output messages.""" - - seed: int - """The seed used for generating the sample.""" - - temperature: float - """The sampling temperature used.""" - - top_p: float - """The top_p value used for sampling.""" - - usage: SampleUsage - """Token usage details for the sample.""" - - -class OutputItemListResponse(BaseModel): - """A schema representing an evaluation run output item.""" - - id: str - """Unique identifier for the evaluation run output item.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - datasource_item: Dict[str, object] - """Details of the input data source item.""" - - datasource_item_id: int - """The identifier for the data source item.""" - - eval_id: str - """The identifier of the evaluation group.""" - - object: Literal["eval.run.output_item"] - """The type of the object. Always "eval.run.output_item".""" - - results: List[Result] - """A list of grader results for this output item.""" - - run_id: str - """The identifier of the evaluation run associated with this output item.""" - - sample: Sample - """A sample containing the input and output of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_retrieve_response.py deleted file mode 100644 index 42ba4b2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/evals/runs/output_item_retrieve_response.py +++ /dev/null @@ -1,144 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import TYPE_CHECKING, Dict, List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel -from ..eval_api_error import EvalAPIError - -__all__ = ["OutputItemRetrieveResponse", "Result", "Sample", "SampleInput", "SampleOutput", "SampleUsage"] - - -class Result(BaseModel): - """A single grader result for an evaluation run output item.""" - - name: str - """The name of the grader.""" - - passed: bool - """Whether the grader considered the output a pass.""" - - score: float - """The numeric score produced by the grader.""" - - sample: Optional[Dict[str, object]] = None - """Optional sample or intermediate data produced by the grader.""" - - type: Optional[str] = None - """The grader type (for example, "string-check-grader").""" - - if TYPE_CHECKING: - # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a - # value to this field, so for compatibility we avoid doing it at runtime. - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] - - # Stub to indicate that arbitrary properties are accepted. - # To access properties that are not valid identifiers you can use `getattr`, e.g. - # `getattr(obj, '$type')` - def __getattr__(self, attr: str) -> object: ... - else: - __pydantic_extra__: Dict[str, object] - - -class SampleInput(BaseModel): - """An input message.""" - - content: str - """The content of the message.""" - - role: str - """The role of the message sender (e.g., system, user, developer).""" - - -class SampleOutput(BaseModel): - content: Optional[str] = None - """The content of the message.""" - - role: Optional[str] = None - """The role of the message (e.g. "system", "assistant", "user").""" - - -class SampleUsage(BaseModel): - """Token usage details for the sample.""" - - cached_tokens: int - """The number of tokens retrieved from cache.""" - - completion_tokens: int - """The number of completion tokens generated.""" - - prompt_tokens: int - """The number of prompt tokens used.""" - - total_tokens: int - """The total number of tokens used.""" - - -class Sample(BaseModel): - """A sample containing the input and output of the evaluation run.""" - - error: EvalAPIError - """An object representing an error response from the Eval API.""" - - finish_reason: str - """The reason why the sample generation was finished.""" - - input: List[SampleInput] - """An array of input messages.""" - - max_completion_tokens: int - """The maximum number of tokens allowed for completion.""" - - model: str - """The model used for generating the sample.""" - - output: List[SampleOutput] - """An array of output messages.""" - - seed: int - """The seed used for generating the sample.""" - - temperature: float - """The sampling temperature used.""" - - top_p: float - """The top_p value used for sampling.""" - - usage: SampleUsage - """Token usage details for the sample.""" - - -class OutputItemRetrieveResponse(BaseModel): - """A schema representing an evaluation run output item.""" - - id: str - """Unique identifier for the evaluation run output item.""" - - created_at: int - """Unix timestamp (in seconds) when the evaluation run was created.""" - - datasource_item: Dict[str, object] - """Details of the input data source item.""" - - datasource_item_id: int - """The identifier for the data source item.""" - - eval_id: str - """The identifier of the evaluation group.""" - - object: Literal["eval.run.output_item"] - """The type of the object. Always "eval.run.output_item".""" - - results: List[Result] - """A list of grader results for this output item.""" - - run_id: str - """The identifier of the evaluation run associated with this output item.""" - - sample: Sample - """A sample containing the input and output of the evaluation run.""" - - status: str - """The status of the evaluation run.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy.py deleted file mode 100644 index ee96bd7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .other_file_chunking_strategy_object import OtherFileChunkingStrategyObject -from .static_file_chunking_strategy_object import StaticFileChunkingStrategyObject - -__all__ = ["FileChunkingStrategy"] - -FileChunkingStrategy: TypeAlias = Annotated[ - Union[StaticFileChunkingStrategyObject, OtherFileChunkingStrategyObject], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy_param.py deleted file mode 100644 index 25d9428..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_chunking_strategy_param.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam -from .static_file_chunking_strategy_object_param import StaticFileChunkingStrategyObjectParam - -__all__ = ["FileChunkingStrategyParam"] - -FileChunkingStrategyParam: TypeAlias = Union[AutoFileChunkingStrategyParam, StaticFileChunkingStrategyObjectParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_content.py deleted file mode 100644 index d89eee6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_content.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import TypeAlias - -__all__ = ["FileContent"] - -FileContent: TypeAlias = str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_create_params.py deleted file mode 100644 index f4367f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_create_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .._types import FileTypes -from .file_purpose import FilePurpose - -__all__ = ["FileCreateParams", "ExpiresAfter"] - - -class FileCreateParams(TypedDict, total=False): - file: Required[FileTypes] - """The File object (not file name) to be uploaded.""" - - purpose: Required[FilePurpose] - """The intended purpose of the uploaded file. - - One of: - `assistants`: Used in the Assistants API - `batch`: Used in the Batch - API - `fine-tune`: Used for fine-tuning - `vision`: Images used for vision - fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used - for eval data sets - """ - - expires_after: ExpiresAfter - """The expiration policy for a file. - - By default, files with `purpose=batch` expire after 30 days and all other files - are persisted until they are manually deleted. - """ - - -class ExpiresAfter(TypedDict, total=False): - """The expiration policy for a file. - - By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. - """ - - anchor: Required[Literal["created_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `created_at`. - """ - - seconds: Required[int] - """The number of seconds after the anchor time that the file will expire. - - Must be between 3600 (1 hour) and 2592000 (30 days). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_deleted.py deleted file mode 100644 index f25fa87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FileDeleted"] - - -class FileDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["file"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_list_params.py deleted file mode 100644 index 058d874..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_list_params.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["FileListParams"] - - -class FileListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 10,000, and the default is 10,000. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ - - purpose: str - """Only return files with the given purpose.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_object.py deleted file mode 100644 index 4a9901f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_object.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FileObject"] - - -class FileObject(BaseModel): - """The `File` object represents a document that has been uploaded to OpenAI.""" - - id: str - """The file identifier, which can be referenced in the API endpoints.""" - - bytes: int - """The size of the file, in bytes.""" - - created_at: int - """The Unix timestamp (in seconds) for when the file was created.""" - - filename: str - """The name of the file.""" - - object: Literal["file"] - """The object type, which is always `file`.""" - - purpose: Literal[ - "assistants", - "assistants_output", - "batch", - "batch_output", - "fine-tune", - "fine-tune-results", - "vision", - "user_data", - ] - """The intended purpose of the file. - - Supported values are `assistants`, `assistants_output`, `batch`, `batch_output`, - `fine-tune`, `fine-tune-results`, `vision`, and `user_data`. - """ - - status: Literal["uploaded", "processed", "error"] - """Deprecated. - - The current status of the file, which can be either `uploaded`, `processed`, or - `error`. - """ - - expires_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the file will expire.""" - - status_details: Optional[str] = None - """Deprecated. - - For details on why a fine-tuning training file failed validation, see the - `error` field on `fine_tuning.job`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/file_purpose.py b/backend/venv39/lib/python3.9/site-packages/openai/types/file_purpose.py deleted file mode 100644 index b2c2d5f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/file_purpose.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["FilePurpose"] - -FilePurpose: TypeAlias = Literal["assistants", "batch", "fine-tune", "vision", "user_data", "evals"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/__init__.py deleted file mode 100644 index cc664ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .dpo_method import DpoMethod as DpoMethod -from .fine_tuning_job import FineTuningJob as FineTuningJob -from .job_list_params import JobListParams as JobListParams -from .dpo_method_param import DpoMethodParam as DpoMethodParam -from .job_create_params import JobCreateParams as JobCreateParams -from .supervised_method import SupervisedMethod as SupervisedMethod -from .dpo_hyperparameters import DpoHyperparameters as DpoHyperparameters -from .reinforcement_method import ReinforcementMethod as ReinforcementMethod -from .fine_tuning_job_event import FineTuningJobEvent as FineTuningJobEvent -from .job_list_events_params import JobListEventsParams as JobListEventsParams -from .supervised_method_param import SupervisedMethodParam as SupervisedMethodParam -from .dpo_hyperparameters_param import DpoHyperparametersParam as DpoHyperparametersParam -from .reinforcement_method_param import ReinforcementMethodParam as ReinforcementMethodParam -from .supervised_hyperparameters import SupervisedHyperparameters as SupervisedHyperparameters -from .fine_tuning_job_integration import FineTuningJobIntegration as FineTuningJobIntegration -from .reinforcement_hyperparameters import ReinforcementHyperparameters as ReinforcementHyperparameters -from .supervised_hyperparameters_param import SupervisedHyperparametersParam as SupervisedHyperparametersParam -from .fine_tuning_job_wandb_integration import FineTuningJobWandbIntegration as FineTuningJobWandbIntegration -from .reinforcement_hyperparameters_param import ReinforcementHyperparametersParam as ReinforcementHyperparametersParam -from .fine_tuning_job_wandb_integration_object import ( - FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/__init__.py deleted file mode 100644 index 6394961..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .grader_run_params import GraderRunParams as GraderRunParams -from .grader_run_response import GraderRunResponse as GraderRunResponse -from .grader_validate_params import GraderValidateParams as GraderValidateParams -from .grader_validate_response import GraderValidateResponse as GraderValidateResponse diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_params.py deleted file mode 100644 index 646407f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_params.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Required, TypeAlias, TypedDict - -from ...graders.multi_grader_param import MultiGraderParam -from ...graders.python_grader_param import PythonGraderParam -from ...graders.score_model_grader_param import ScoreModelGraderParam -from ...graders.string_check_grader_param import StringCheckGraderParam -from ...graders.text_similarity_grader_param import TextSimilarityGraderParam - -__all__ = ["GraderRunParams", "Grader"] - - -class GraderRunParams(TypedDict, total=False): - grader: Required[Grader] - """The grader used for the fine-tuning job.""" - - model_sample: Required[str] - """The model sample to be evaluated. - - This value will be used to populate the `sample` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - The `output_json` variable will be populated if the model sample is a valid JSON - string. - """ - - item: object - """The dataset item provided to the grader. - - This will be used to populate the `item` namespace. See - [the guide](https://platform.openai.com/docs/guides/graders) for more details. - """ - - -Grader: TypeAlias = Union[ - StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_response.py deleted file mode 100644 index 8ef046d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_run_response.py +++ /dev/null @@ -1,67 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["GraderRunResponse", "Metadata", "MetadataErrors"] - - -class MetadataErrors(BaseModel): - formula_parse_error: bool - - invalid_variable_error: bool - - api_model_grader_parse_error: bool = FieldInfo(alias="model_grader_parse_error") - - api_model_grader_refusal_error: bool = FieldInfo(alias="model_grader_refusal_error") - - api_model_grader_server_error: bool = FieldInfo(alias="model_grader_server_error") - - api_model_grader_server_error_details: Optional[str] = FieldInfo( - alias="model_grader_server_error_details", default=None - ) - - other_error: bool - - python_grader_runtime_error: bool - - python_grader_runtime_error_details: Optional[str] = None - - python_grader_server_error: bool - - python_grader_server_error_type: Optional[str] = None - - sample_parse_error: bool - - truncated_observation_error: bool - - unresponsive_reward_error: bool - - -class Metadata(BaseModel): - errors: MetadataErrors - - execution_time: float - - name: str - - sampled_model_name: Optional[str] = None - - scores: Dict[str, object] - - token_usage: Optional[int] = None - - type: str - - -class GraderRunResponse(BaseModel): - metadata: Metadata - - api_model_grader_token_usage_per_model: Dict[str, object] = FieldInfo(alias="model_grader_token_usage_per_model") - - reward: float - - sub_rewards: Dict[str, object] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_params.py deleted file mode 100644 index fe9eb44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Required, TypeAlias, TypedDict - -from ...graders.multi_grader_param import MultiGraderParam -from ...graders.python_grader_param import PythonGraderParam -from ...graders.score_model_grader_param import ScoreModelGraderParam -from ...graders.string_check_grader_param import StringCheckGraderParam -from ...graders.text_similarity_grader_param import TextSimilarityGraderParam - -__all__ = ["GraderValidateParams", "Grader"] - - -class GraderValidateParams(TypedDict, total=False): - grader: Required[Grader] - """The grader used for the fine-tuning job.""" - - -Grader: TypeAlias = Union[ - StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_response.py deleted file mode 100644 index b373292..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/alpha/grader_validate_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import TypeAlias - -from ...._models import BaseModel -from ...graders.multi_grader import MultiGrader -from ...graders.python_grader import PythonGrader -from ...graders.score_model_grader import ScoreModelGrader -from ...graders.string_check_grader import StringCheckGrader -from ...graders.text_similarity_grader import TextSimilarityGrader - -__all__ = ["GraderValidateResponse", "Grader"] - -Grader: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, MultiGrader] - - -class GraderValidateResponse(BaseModel): - grader: Optional[Grader] = None - """The grader used for the fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/__init__.py deleted file mode 100644 index 2947b33..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .permission_create_params import PermissionCreateParams as PermissionCreateParams -from .permission_create_response import PermissionCreateResponse as PermissionCreateResponse -from .permission_delete_response import PermissionDeleteResponse as PermissionDeleteResponse -from .permission_retrieve_params import PermissionRetrieveParams as PermissionRetrieveParams -from .permission_retrieve_response import PermissionRetrieveResponse as PermissionRetrieveResponse diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_params.py deleted file mode 100644 index e7cf4e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_params.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ...._types import SequenceNotStr - -__all__ = ["PermissionCreateParams"] - - -class PermissionCreateParams(TypedDict, total=False): - project_ids: Required[SequenceNotStr[str]] - """The project identifiers to grant access to.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_response.py deleted file mode 100644 index 459fa9d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_create_response.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["PermissionCreateResponse"] - - -class PermissionCreateResponse(BaseModel): - """ - The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint. - """ - - id: str - """The permission identifier, which can be referenced in the API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the permission was created.""" - - object: Literal["checkpoint.permission"] - """The object type, which is always "checkpoint.permission".""" - - project_id: str - """The project identifier that the permission is for.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_delete_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_delete_response.py deleted file mode 100644 index 1a92d91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_delete_response.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["PermissionDeleteResponse"] - - -class PermissionDeleteResponse(BaseModel): - id: str - """The ID of the fine-tuned model checkpoint permission that was deleted.""" - - deleted: bool - """Whether the fine-tuned model checkpoint permission was successfully deleted.""" - - object: Literal["checkpoint.permission"] - """The object type, which is always "checkpoint.permission".""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py deleted file mode 100644 index 6e66a86..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["PermissionRetrieveParams"] - - -class PermissionRetrieveParams(TypedDict, total=False): - after: str - """Identifier for the last permission ID from the previous pagination request.""" - - limit: int - """Number of permissions to retrieve.""" - - order: Literal["ascending", "descending"] - """The order in which to retrieve permissions.""" - - project_id: str - """The ID of the project to get permissions for.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py deleted file mode 100644 index 3420895..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/checkpoints/permission_retrieve_response.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["PermissionRetrieveResponse", "Data"] - - -class Data(BaseModel): - """ - The `checkpoint.permission` object represents a permission for a fine-tuned model checkpoint. - """ - - id: str - """The permission identifier, which can be referenced in the API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the permission was created.""" - - object: Literal["checkpoint.permission"] - """The object type, which is always "checkpoint.permission".""" - - project_id: str - """The project identifier that the permission is for.""" - - -class PermissionRetrieveResponse(BaseModel): - data: List[Data] - - has_more: bool - - object: Literal["list"] - - first_id: Optional[str] = None - - last_id: Optional[str] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters.py deleted file mode 100644 index cd39f30..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["DpoHyperparameters"] - - -class DpoHyperparameters(BaseModel): - """The hyperparameters used for the DPO fine-tuning job.""" - - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - beta: Union[Literal["auto"], float, None] = None - """The beta value for the DPO method. - - A higher beta value will increase the weight of the penalty between the policy - and reference model. - """ - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters_param.py deleted file mode 100644 index 12b2c41..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_hyperparameters_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -__all__ = ["DpoHyperparametersParam"] - - -class DpoHyperparametersParam(TypedDict, total=False): - """The hyperparameters used for the DPO fine-tuning job.""" - - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - beta: Union[Literal["auto"], float] - """The beta value for the DPO method. - - A higher beta value will increase the weight of the penalty between the policy - and reference model. - """ - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method.py deleted file mode 100644 index 452c182..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .dpo_hyperparameters import DpoHyperparameters - -__all__ = ["DpoMethod"] - - -class DpoMethod(BaseModel): - """Configuration for the DPO fine-tuning method.""" - - hyperparameters: Optional[DpoHyperparameters] = None - """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method_param.py deleted file mode 100644 index 6bd74d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/dpo_method_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .dpo_hyperparameters_param import DpoHyperparametersParam - -__all__ = ["DpoMethodParam"] - - -class DpoMethodParam(TypedDict, total=False): - """Configuration for the DPO fine-tuning method.""" - - hyperparameters: DpoHyperparametersParam - """The hyperparameters used for the DPO fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job.py deleted file mode 100644 index bb8a4d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job.py +++ /dev/null @@ -1,176 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .dpo_method import DpoMethod -from ..shared.metadata import Metadata -from .supervised_method import SupervisedMethod -from .reinforcement_method import ReinforcementMethod -from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject - -__all__ = ["FineTuningJob", "Error", "Hyperparameters", "Method"] - - -class Error(BaseModel): - """ - For fine-tuning jobs that have `failed`, this will contain more information on the cause of the failure. - """ - - code: str - """A machine-readable error code.""" - - message: str - """A human-readable error message.""" - - param: Optional[str] = None - """The parameter that was invalid, usually `training_file` or `validation_file`. - - This field will be null if the failure was not parameter-specific. - """ - - -class Hyperparameters(BaseModel): - """The hyperparameters used for the fine-tuning job. - - This value will only be returned when running `supervised` jobs. - """ - - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class Method(BaseModel): - """The method used for fine-tuning.""" - - type: Literal["supervised", "dpo", "reinforcement"] - """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" - - dpo: Optional[DpoMethod] = None - """Configuration for the DPO fine-tuning method.""" - - reinforcement: Optional[ReinforcementMethod] = None - """Configuration for the reinforcement fine-tuning method.""" - - supervised: Optional[SupervisedMethod] = None - """Configuration for the supervised fine-tuning method.""" - - -class FineTuningJob(BaseModel): - """ - The `fine_tuning.job` object represents a fine-tuning job that has been created through the API. - """ - - id: str - """The object identifier, which can be referenced in the API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the fine-tuning job was created.""" - - error: Optional[Error] = None - """ - For fine-tuning jobs that have `failed`, this will contain more information on - the cause of the failure. - """ - - fine_tuned_model: Optional[str] = None - """The name of the fine-tuned model that is being created. - - The value will be null if the fine-tuning job is still running. - """ - - finished_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the fine-tuning job was finished. - - The value will be null if the fine-tuning job is still running. - """ - - hyperparameters: Hyperparameters - """The hyperparameters used for the fine-tuning job. - - This value will only be returned when running `supervised` jobs. - """ - - model: str - """The base model that is being fine-tuned.""" - - object: Literal["fine_tuning.job"] - """The object type, which is always "fine_tuning.job".""" - - organization_id: str - """The organization that owns the fine-tuning job.""" - - result_files: List[str] - """The compiled results file ID(s) for the fine-tuning job. - - You can retrieve the results with the - [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents). - """ - - seed: int - """The seed used for the fine-tuning job.""" - - status: Literal["validating_files", "queued", "running", "succeeded", "failed", "cancelled"] - """ - The current status of the fine-tuning job, which can be either - `validating_files`, `queued`, `running`, `succeeded`, `failed`, or `cancelled`. - """ - - trained_tokens: Optional[int] = None - """The total number of billable tokens processed by this fine-tuning job. - - The value will be null if the fine-tuning job is still running. - """ - - training_file: str - """The file ID used for training. - - You can retrieve the training data with the - [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents). - """ - - validation_file: Optional[str] = None - """The file ID used for validation. - - You can retrieve the validation results with the - [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents). - """ - - estimated_finish: Optional[int] = None - """ - The Unix timestamp (in seconds) for when the fine-tuning job is estimated to - finish. The value will be null if the fine-tuning job is not running. - """ - - integrations: Optional[List[FineTuningJobWandbIntegrationObject]] = None - """A list of integrations to enable for this fine-tuning job.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - method: Optional[Method] = None - """The method used for fine-tuning.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_event.py deleted file mode 100644 index 7452b81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import builtins -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FineTuningJobEvent"] - - -class FineTuningJobEvent(BaseModel): - """Fine-tuning job event object""" - - id: str - """The object identifier.""" - - created_at: int - """The Unix timestamp (in seconds) for when the fine-tuning job was created.""" - - level: Literal["info", "warn", "error"] - """The log level of the event.""" - - message: str - """The message of the event.""" - - object: Literal["fine_tuning.job.event"] - """The object type, which is always "fine_tuning.job.event".""" - - data: Optional[builtins.object] = None - """The data associated with the event.""" - - type: Optional[Literal["message", "metrics"]] = None - """The type of event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_integration.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_integration.py deleted file mode 100644 index 2af73fb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_integration.py +++ /dev/null @@ -1,5 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .fine_tuning_job_wandb_integration_object import FineTuningJobWandbIntegrationObject - -FineTuningJobIntegration = FineTuningJobWandbIntegrationObject diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py deleted file mode 100644 index 0e33aa8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel - -__all__ = ["FineTuningJobWandbIntegration"] - - -class FineTuningJobWandbIntegration(BaseModel): - """The settings for your integration with Weights and Biases. - - This payload specifies the project that - metrics will be sent to. Optionally, you can set an explicit display name for your run, add tags - to your run, and set a default entity (team, username, etc) to be associated with your run. - """ - - project: str - """The name of the project that the new run will be created under.""" - - entity: Optional[str] = None - """The entity to use for the run. - - This allows you to set the team or username of the WandB user that you would - like associated with the run. If not set, the default entity for the registered - WandB API key is used. - """ - - name: Optional[str] = None - """A display name to set for the run. - - If not set, we will use the Job ID as the name. - """ - - tags: Optional[List[str]] = None - """A list of tags to be attached to the newly created run. - - These tags are passed through directly to WandB. Some default tags are generated - by OpenAI: "openai/finetune", "openai/{base-model}", "openai/{ftjob-abcdef}". - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration_object.py deleted file mode 100644 index 5b94354..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/fine_tuning_job_wandb_integration_object.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .fine_tuning_job_wandb_integration import FineTuningJobWandbIntegration - -__all__ = ["FineTuningJobWandbIntegrationObject"] - - -class FineTuningJobWandbIntegrationObject(BaseModel): - type: Literal["wandb"] - """The type of the integration being enabled for the fine-tuning job""" - - wandb: FineTuningJobWandbIntegration - """The settings for your integration with Weights and Biases. - - This payload specifies the project that metrics will be sent to. Optionally, you - can set an explicit display name for your run, add tags to your run, and set a - default entity (team, username, etc) to be associated with your run. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_create_params.py deleted file mode 100644 index 181bede..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_create_params.py +++ /dev/null @@ -1,190 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr -from .dpo_method_param import DpoMethodParam -from ..shared_params.metadata import Metadata -from .supervised_method_param import SupervisedMethodParam -from .reinforcement_method_param import ReinforcementMethodParam - -__all__ = ["JobCreateParams", "Hyperparameters", "Integration", "IntegrationWandb", "Method"] - - -class JobCreateParams(TypedDict, total=False): - model: Required[Union[str, Literal["babbage-002", "davinci-002", "gpt-3.5-turbo", "gpt-4o-mini"]]] - """The name of the model to fine-tune. - - You can select one of the - [supported models](https://platform.openai.com/docs/guides/fine-tuning#which-models-can-be-fine-tuned). - """ - - training_file: Required[str] - """The ID of an uploaded file that contains training data. - - See [upload file](https://platform.openai.com/docs/api-reference/files/create) - for how to upload a file. - - Your dataset must be formatted as a JSONL file. Additionally, you must upload - your file with the purpose `fine-tune`. - - The contents of the file should differ depending on if the model uses the - [chat](https://platform.openai.com/docs/api-reference/fine-tuning/chat-input), - [completions](https://platform.openai.com/docs/api-reference/fine-tuning/completions-input) - format, or if the fine-tuning method uses the - [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input) - format. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - """ - - hyperparameters: Hyperparameters - """ - The hyperparameters used for the fine-tuning job. This value is now deprecated - in favor of `method`, and should be passed in under the `method` parameter. - """ - - integrations: Optional[Iterable[Integration]] - """A list of integrations to enable for your fine-tuning job.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - method: Method - """The method used for fine-tuning.""" - - seed: Optional[int] - """The seed controls the reproducibility of the job. - - Passing in the same seed and job parameters should produce the same results, but - may differ in rare cases. If a seed is not specified, one will be generated for - you. - """ - - suffix: Optional[str] - """ - A string of up to 64 characters that will be added to your fine-tuned model - name. - - For example, a `suffix` of "custom-model-name" would produce a model name like - `ft:gpt-4o-mini:openai:custom-model-name:7p4lURel`. - """ - - validation_file: Optional[str] - """The ID of an uploaded file that contains validation data. - - If you provide this file, the data is used to generate validation metrics - periodically during fine-tuning. These metrics can be viewed in the fine-tuning - results file. The same data should not be present in both train and validation - files. - - Your dataset must be formatted as a JSONL file. You must upload your file with - the purpose `fine-tune`. - - See the - [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization) - for more details. - """ - - -class Hyperparameters(TypedDict, total=False): - """ - The hyperparameters used for the fine-tuning job. - This value is now deprecated in favor of `method`, and should be passed in under the `method` parameter. - """ - - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - -class IntegrationWandb(TypedDict, total=False): - """The settings for your integration with Weights and Biases. - - This payload specifies the project that - metrics will be sent to. Optionally, you can set an explicit display name for your run, add tags - to your run, and set a default entity (team, username, etc) to be associated with your run. - """ - - project: Required[str] - """The name of the project that the new run will be created under.""" - - entity: Optional[str] - """The entity to use for the run. - - This allows you to set the team or username of the WandB user that you would - like associated with the run. If not set, the default entity for the registered - WandB API key is used. - """ - - name: Optional[str] - """A display name to set for the run. - - If not set, we will use the Job ID as the name. - """ - - tags: SequenceNotStr[str] - """A list of tags to be attached to the newly created run. - - These tags are passed through directly to WandB. Some default tags are generated - by OpenAI: "openai/finetune", "openai/{base-model}", "openai/{ftjob-abcdef}". - """ - - -class Integration(TypedDict, total=False): - type: Required[Literal["wandb"]] - """The type of integration to enable. - - Currently, only "wandb" (Weights and Biases) is supported. - """ - - wandb: Required[IntegrationWandb] - """The settings for your integration with Weights and Biases. - - This payload specifies the project that metrics will be sent to. Optionally, you - can set an explicit display name for your run, add tags to your run, and set a - default entity (team, username, etc) to be associated with your run. - """ - - -class Method(TypedDict, total=False): - """The method used for fine-tuning.""" - - type: Required[Literal["supervised", "dpo", "reinforcement"]] - """The type of method. Is either `supervised`, `dpo`, or `reinforcement`.""" - - dpo: DpoMethodParam - """Configuration for the DPO fine-tuning method.""" - - reinforcement: ReinforcementMethodParam - """Configuration for the reinforcement fine-tuning method.""" - - supervised: SupervisedMethodParam - """Configuration for the supervised fine-tuning method.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_events_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_events_params.py deleted file mode 100644 index e1c9a64..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_events_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["JobListEventsParams"] - - -class JobListEventsParams(TypedDict, total=False): - after: str - """Identifier for the last event from the previous pagination request.""" - - limit: int - """Number of events to retrieve.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_params.py deleted file mode 100644 index b79f3ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/job_list_params.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import TypedDict - -__all__ = ["JobListParams"] - - -class JobListParams(TypedDict, total=False): - after: str - """Identifier for the last job from the previous pagination request.""" - - limit: int - """Number of fine-tuning jobs to retrieve.""" - - metadata: Optional[Dict[str, str]] - """Optional metadata filter. - - To filter, use the syntax `metadata[k]=v`. Alternatively, set `metadata=null` to - indicate no metadata. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/__init__.py deleted file mode 100644 index 6c93da1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .checkpoint_list_params import CheckpointListParams as CheckpointListParams -from .fine_tuning_job_checkpoint import FineTuningJobCheckpoint as FineTuningJobCheckpoint diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/checkpoint_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/checkpoint_list_params.py deleted file mode 100644 index adceb3b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/checkpoint_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["CheckpointListParams"] - - -class CheckpointListParams(TypedDict, total=False): - after: str - """Identifier for the last checkpoint ID from the previous pagination request.""" - - limit: int - """Number of checkpoints to retrieve.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py deleted file mode 100644 index f8a04b6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/jobs/fine_tuning_job_checkpoint.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["FineTuningJobCheckpoint", "Metrics"] - - -class Metrics(BaseModel): - """Metrics at the step number during the fine-tuning job.""" - - full_valid_loss: Optional[float] = None - - full_valid_mean_token_accuracy: Optional[float] = None - - step: Optional[float] = None - - train_loss: Optional[float] = None - - train_mean_token_accuracy: Optional[float] = None - - valid_loss: Optional[float] = None - - valid_mean_token_accuracy: Optional[float] = None - - -class FineTuningJobCheckpoint(BaseModel): - """ - The `fine_tuning.job.checkpoint` object represents a model checkpoint for a fine-tuning job that is ready to use. - """ - - id: str - """The checkpoint identifier, which can be referenced in the API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the checkpoint was created.""" - - fine_tuned_model_checkpoint: str - """The name of the fine-tuned checkpoint model that is created.""" - - fine_tuning_job_id: str - """The name of the fine-tuning job that this checkpoint was created from.""" - - metrics: Metrics - """Metrics at the step number during the fine-tuning job.""" - - object: Literal["fine_tuning.job.checkpoint"] - """The object type, which is always "fine_tuning.job.checkpoint".""" - - step_number: int - """The step number that the checkpoint was created at.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters.py deleted file mode 100644 index 4c289fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ReinforcementHyperparameters"] - - -class ReinforcementHyperparameters(BaseModel): - """The hyperparameters used for the reinforcement fine-tuning job.""" - - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - compute_multiplier: Union[Literal["auto"], float, None] = None - """ - Multiplier on amount of compute used for exploring search space during training. - """ - - eval_interval: Union[Literal["auto"], int, None] = None - """The number of training steps between evaluation runs.""" - - eval_samples: Union[Literal["auto"], int, None] = None - """Number of evaluation samples to generate per training step.""" - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - reasoning_effort: Optional[Literal["default", "low", "medium", "high"]] = None - """Level of reasoning effort.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters_param.py deleted file mode 100644 index 7be716f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_hyperparameters_param.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -__all__ = ["ReinforcementHyperparametersParam"] - - -class ReinforcementHyperparametersParam(TypedDict, total=False): - """The hyperparameters used for the reinforcement fine-tuning job.""" - - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - compute_multiplier: Union[Literal["auto"], float] - """ - Multiplier on amount of compute used for exploring search space during training. - """ - - eval_interval: Union[Literal["auto"], int] - """The number of training steps between evaluation runs.""" - - eval_samples: Union[Literal["auto"], int] - """Number of evaluation samples to generate per training step.""" - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ - - reasoning_effort: Literal["default", "low", "medium", "high"] - """Level of reasoning effort.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method.py deleted file mode 100644 index a8a3685..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import TypeAlias - -from ..._models import BaseModel -from ..graders.multi_grader import MultiGrader -from ..graders.python_grader import PythonGrader -from ..graders.score_model_grader import ScoreModelGrader -from ..graders.string_check_grader import StringCheckGrader -from .reinforcement_hyperparameters import ReinforcementHyperparameters -from ..graders.text_similarity_grader import TextSimilarityGrader - -__all__ = ["ReinforcementMethod", "Grader"] - -Grader: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, MultiGrader] - - -class ReinforcementMethod(BaseModel): - """Configuration for the reinforcement fine-tuning method.""" - - grader: Grader - """The grader used for the fine-tuning job.""" - - hyperparameters: Optional[ReinforcementHyperparameters] = None - """The hyperparameters used for the reinforcement fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method_param.py deleted file mode 100644 index ea75bfe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/reinforcement_method_param.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Required, TypeAlias, TypedDict - -from ..graders.multi_grader_param import MultiGraderParam -from ..graders.python_grader_param import PythonGraderParam -from ..graders.score_model_grader_param import ScoreModelGraderParam -from ..graders.string_check_grader_param import StringCheckGraderParam -from .reinforcement_hyperparameters_param import ReinforcementHyperparametersParam -from ..graders.text_similarity_grader_param import TextSimilarityGraderParam - -__all__ = ["ReinforcementMethodParam", "Grader"] - -Grader: TypeAlias = Union[ - StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, MultiGraderParam -] - - -class ReinforcementMethodParam(TypedDict, total=False): - """Configuration for the reinforcement fine-tuning method.""" - - grader: Required[Grader] - """The grader used for the fine-tuning job.""" - - hyperparameters: ReinforcementHyperparametersParam - """The hyperparameters used for the reinforcement fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters.py deleted file mode 100644 index 1231bbd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["SupervisedHyperparameters"] - - -class SupervisedHyperparameters(BaseModel): - """The hyperparameters used for the fine-tuning job.""" - - batch_size: Union[Literal["auto"], int, None] = None - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float, None] = None - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int, None] = None - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters_param.py deleted file mode 100644 index de0e021..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_hyperparameters_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -__all__ = ["SupervisedHyperparametersParam"] - - -class SupervisedHyperparametersParam(TypedDict, total=False): - """The hyperparameters used for the fine-tuning job.""" - - batch_size: Union[Literal["auto"], int] - """Number of examples in each batch. - - A larger batch size means that model parameters are updated less frequently, but - with lower variance. - """ - - learning_rate_multiplier: Union[Literal["auto"], float] - """Scaling factor for the learning rate. - - A smaller learning rate may be useful to avoid overfitting. - """ - - n_epochs: Union[Literal["auto"], int] - """The number of epochs to train the model for. - - An epoch refers to one full cycle through the training dataset. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method.py deleted file mode 100644 index 96e1025..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .supervised_hyperparameters import SupervisedHyperparameters - -__all__ = ["SupervisedMethod"] - - -class SupervisedMethod(BaseModel): - """Configuration for the supervised fine-tuning method.""" - - hyperparameters: Optional[SupervisedHyperparameters] = None - """The hyperparameters used for the fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method_param.py deleted file mode 100644 index 4381cd1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/fine_tuning/supervised_method_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .supervised_hyperparameters_param import SupervisedHyperparametersParam - -__all__ = ["SupervisedMethodParam"] - - -class SupervisedMethodParam(TypedDict, total=False): - """Configuration for the supervised fine-tuning method.""" - - hyperparameters: SupervisedHyperparametersParam - """The hyperparameters used for the fine-tuning job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/__init__.py deleted file mode 100644 index 4f70eb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .multi_grader import MultiGrader as MultiGrader -from .grader_inputs import GraderInputs as GraderInputs -from .python_grader import PythonGrader as PythonGrader -from .label_model_grader import LabelModelGrader as LabelModelGrader -from .multi_grader_param import MultiGraderParam as MultiGraderParam -from .score_model_grader import ScoreModelGrader as ScoreModelGrader -from .grader_inputs_param import GraderInputsParam as GraderInputsParam -from .python_grader_param import PythonGraderParam as PythonGraderParam -from .string_check_grader import StringCheckGrader as StringCheckGrader -from .text_similarity_grader import TextSimilarityGrader as TextSimilarityGrader -from .label_model_grader_param import LabelModelGraderParam as LabelModelGraderParam -from .score_model_grader_param import ScoreModelGraderParam as ScoreModelGraderParam -from .string_check_grader_param import StringCheckGraderParam as StringCheckGraderParam -from .text_similarity_grader_param import TextSimilarityGraderParam as TextSimilarityGraderParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs.py deleted file mode 100644 index edc966d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio - -__all__ = ["GraderInputs", "GraderInputItem", "GraderInputItemOutputText", "GraderInputItemInputImage"] - - -class GraderInputItemOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class GraderInputItemInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -GraderInputItem: TypeAlias = Union[ - str, ResponseInputText, GraderInputItemOutputText, GraderInputItemInputImage, ResponseInputAudio -] - -GraderInputs: TypeAlias = List[GraderInputItem] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs_param.py deleted file mode 100644 index 7d8341e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/grader_inputs_param.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..responses.response_input_text_param import ResponseInputTextParam -from ..responses.response_input_audio_param import ResponseInputAudioParam - -__all__ = [ - "GraderInputsParam", - "GraderInputsParamItem", - "GraderInputsParamItemOutputText", - "GraderInputsParamItemInputImage", -] - - -class GraderInputsParamItemOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class GraderInputsParamItemInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -GraderInputsParamItem: TypeAlias = Union[ - str, - ResponseInputTextParam, - GraderInputsParamItemOutputText, - GraderInputsParamItemInputImage, - ResponseInputAudioParam, -] - -GraderInputsParam: TypeAlias = List[GraderInputsParamItem] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader.py deleted file mode 100644 index d3c9422..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader.py +++ /dev/null @@ -1,92 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .grader_inputs import GraderInputs -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio - -__all__ = ["LabelModelGrader", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] - - -class InputContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContent: TypeAlias = Union[ - str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, GraderInputs -] - - -class Input(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: InputContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -class LabelModelGrader(BaseModel): - """ - A LabelModelGrader object which uses a model to assign labels to each item - in the evaluation. - """ - - input: List[Input] - - labels: List[str] - """The labels to assign to each item in the evaluation.""" - - model: str - """The model to use for the evaluation. Must support structured outputs.""" - - name: str - """The name of the grader.""" - - passing_labels: List[str] - """The labels that indicate a passing result. Must be a subset of labels.""" - - type: Literal["label_model"] - """The object type, which is always `label_model`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader_param.py deleted file mode 100644 index a5b6959..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/label_model_grader_param.py +++ /dev/null @@ -1,99 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from .grader_inputs_param import GraderInputsParam -from ..responses.response_input_text_param import ResponseInputTextParam -from ..responses.response_input_audio_param import ResponseInputAudioParam - -__all__ = ["LabelModelGraderParam", "Input", "InputContent", "InputContentOutputText", "InputContentInputImage"] - - -class InputContentOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputContentInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputContentOutputText, - InputContentInputImage, - ResponseInputAudioParam, - GraderInputsParam, -] - - -class Input(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[InputContent] - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -class LabelModelGraderParam(TypedDict, total=False): - """ - A LabelModelGrader object which uses a model to assign labels to each item - in the evaluation. - """ - - input: Required[Iterable[Input]] - - labels: Required[SequenceNotStr[str]] - """The labels to assign to each item in the evaluation.""" - - model: Required[str] - """The model to use for the evaluation. Must support structured outputs.""" - - name: Required[str] - """The name of the grader.""" - - passing_labels: Required[SequenceNotStr[str]] - """The labels that indicate a passing result. Must be a subset of labels.""" - - type: Required[Literal["label_model"]] - """The object type, which is always `label_model`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader.py deleted file mode 100644 index 022ddb4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .python_grader import PythonGrader -from .label_model_grader import LabelModelGrader -from .score_model_grader import ScoreModelGrader -from .string_check_grader import StringCheckGrader -from .text_similarity_grader import TextSimilarityGrader - -__all__ = ["MultiGrader", "Graders"] - -Graders: TypeAlias = Union[StringCheckGrader, TextSimilarityGrader, PythonGrader, ScoreModelGrader, LabelModelGrader] - - -class MultiGrader(BaseModel): - """ - A MultiGrader object combines the output of multiple graders to produce a single score. - """ - - calculate_output: str - """A formula to calculate the output based on grader results.""" - - graders: Graders - """ - A StringCheckGrader object that performs a string comparison between input and - reference using a specified operation. - """ - - name: str - """The name of the grader.""" - - type: Literal["multi"] - """The object type, which is always `multi`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader_param.py deleted file mode 100644 index 064267a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/multi_grader_param.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .python_grader_param import PythonGraderParam -from .label_model_grader_param import LabelModelGraderParam -from .score_model_grader_param import ScoreModelGraderParam -from .string_check_grader_param import StringCheckGraderParam -from .text_similarity_grader_param import TextSimilarityGraderParam - -__all__ = ["MultiGraderParam", "Graders"] - -Graders: TypeAlias = Union[ - StringCheckGraderParam, TextSimilarityGraderParam, PythonGraderParam, ScoreModelGraderParam, LabelModelGraderParam -] - - -class MultiGraderParam(TypedDict, total=False): - """ - A MultiGrader object combines the output of multiple graders to produce a single score. - """ - - calculate_output: Required[str] - """A formula to calculate the output based on grader results.""" - - graders: Required[Graders] - """ - A StringCheckGrader object that performs a string comparison between input and - reference using a specified operation. - """ - - name: Required[str] - """The name of the grader.""" - - type: Required[Literal["multi"]] - """The object type, which is always `multi`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader.py deleted file mode 100644 index 81aafda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["PythonGrader"] - - -class PythonGrader(BaseModel): - """A PythonGrader object that runs a python script on the input.""" - - name: str - """The name of the grader.""" - - source: str - """The source code of the python script.""" - - type: Literal["python"] - """The object type, which is always `python`.""" - - image_tag: Optional[str] = None - """The image tag to use for the python script.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader_param.py deleted file mode 100644 index 3be7bab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/python_grader_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PythonGraderParam"] - - -class PythonGraderParam(TypedDict, total=False): - """A PythonGrader object that runs a python script on the input.""" - - name: Required[str] - """The name of the grader.""" - - source: Required[str] - """The source code of the python script.""" - - type: Required[Literal["python"]] - """The object type, which is always `python`.""" - - image_tag: str - """The image tag to use for the python script.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader.py deleted file mode 100644 index 85d11e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader.py +++ /dev/null @@ -1,135 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .grader_inputs import GraderInputs -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text import ResponseInputText -from ..responses.response_input_audio import ResponseInputAudio - -__all__ = [ - "ScoreModelGrader", - "Input", - "InputContent", - "InputContentOutputText", - "InputContentInputImage", - "SamplingParams", -] - - -class InputContentOutputText(BaseModel): - """A text output from the model.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - -class InputContentInputImage(BaseModel): - """An image input block used within EvalItem content arrays.""" - - image_url: str - """The URL of the image input.""" - - type: Literal["input_image"] - """The type of the image input. Always `input_image`.""" - - detail: Optional[str] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContent: TypeAlias = Union[ - str, ResponseInputText, InputContentOutputText, InputContentInputImage, ResponseInputAudio, GraderInputs -] - - -class Input(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: InputContent - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" - - -class SamplingParams(BaseModel): - """The sampling parameters for the model.""" - - max_completions_tokens: Optional[int] = None - """The maximum number of tokens the grader model may generate in its response.""" - - reasoning_effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] = None - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] = None - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] = None - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class ScoreModelGrader(BaseModel): - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - - input: List[Input] - """The input messages evaluated by the grader. - - Supports text, output text, input image, and input audio content blocks, and may - include template strings. - """ - - model: str - """The model to use for the evaluation.""" - - name: str - """The name of the grader.""" - - type: Literal["score_model"] - """The object type, which is always `score_model`.""" - - range: Optional[List[float]] = None - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: Optional[SamplingParams] = None - """The sampling parameters for the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader_param.py deleted file mode 100644 index 9f1c42e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/score_model_grader_param.py +++ /dev/null @@ -1,141 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .grader_inputs_param import GraderInputsParam -from ..shared.reasoning_effort import ReasoningEffort -from ..responses.response_input_text_param import ResponseInputTextParam -from ..responses.response_input_audio_param import ResponseInputAudioParam - -__all__ = [ - "ScoreModelGraderParam", - "Input", - "InputContent", - "InputContentOutputText", - "InputContentInputImage", - "SamplingParams", -] - - -class InputContentOutputText(TypedDict, total=False): - """A text output from the model.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - -class InputContentInputImage(TypedDict, total=False): - """An image input block used within EvalItem content arrays.""" - - image_url: Required[str] - """The URL of the image input.""" - - type: Required[Literal["input_image"]] - """The type of the image input. Always `input_image`.""" - - detail: str - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - -InputContent: TypeAlias = Union[ - str, - ResponseInputTextParam, - InputContentOutputText, - InputContentInputImage, - ResponseInputAudioParam, - GraderInputsParam, -] - - -class Input(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[InputContent] - """Inputs to the model - can contain template strings. - - Supports text, output text, input images, and input audio, either as a single - item or an array of items. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" - - -class SamplingParams(TypedDict, total=False): - """The sampling parameters for the model.""" - - max_completions_tokens: Optional[int] - """The maximum number of tokens the grader model may generate in its response.""" - - reasoning_effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - seed: Optional[int] - """A seed value to initialize the randomness, during sampling.""" - - temperature: Optional[float] - """A higher temperature increases randomness in the outputs.""" - - top_p: Optional[float] - """An alternative to temperature for nucleus sampling; 1.0 includes all tokens.""" - - -class ScoreModelGraderParam(TypedDict, total=False): - """A ScoreModelGrader object that uses a model to assign a score to the input.""" - - input: Required[Iterable[Input]] - """The input messages evaluated by the grader. - - Supports text, output text, input image, and input audio content blocks, and may - include template strings. - """ - - model: Required[str] - """The model to use for the evaluation.""" - - name: Required[str] - """The name of the grader.""" - - type: Required[Literal["score_model"]] - """The object type, which is always `score_model`.""" - - range: Iterable[float] - """The range of the score. Defaults to `[0, 1]`.""" - - sampling_params: SamplingParams - """The sampling parameters for the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader.py deleted file mode 100644 index efd3679..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["StringCheckGrader"] - - -class StringCheckGrader(BaseModel): - """ - A StringCheckGrader object that performs a string comparison between input and reference using a specified operation. - """ - - input: str - """The input text. This may include template strings.""" - - name: str - """The name of the grader.""" - - operation: Literal["eq", "ne", "like", "ilike"] - """The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`.""" - - reference: str - """The reference text. This may include template strings.""" - - type: Literal["string_check"] - """The object type, which is always `string_check`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader_param.py deleted file mode 100644 index da9e961..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/string_check_grader_param.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["StringCheckGraderParam"] - - -class StringCheckGraderParam(TypedDict, total=False): - """ - A StringCheckGrader object that performs a string comparison between input and reference using a specified operation. - """ - - input: Required[str] - """The input text. This may include template strings.""" - - name: Required[str] - """The name of the grader.""" - - operation: Required[Literal["eq", "ne", "like", "ilike"]] - """The string check operation to perform. One of `eq`, `ne`, `like`, or `ilike`.""" - - reference: Required[str] - """The reference text. This may include template strings.""" - - type: Required[Literal["string_check"]] - """The object type, which is always `string_check`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader.py deleted file mode 100644 index a9d39a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TextSimilarityGrader"] - - -class TextSimilarityGrader(BaseModel): - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - - evaluation_metric: Literal[ - "cosine", - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - ] - """The evaluation metric to use. - - One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, - `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. - """ - - input: str - """The text being graded.""" - - name: str - """The name of the grader.""" - - reference: str - """The text being graded against.""" - - type: Literal["text_similarity"] - """The type of grader.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader_param.py deleted file mode 100644 index 0907c3c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/graders/text_similarity_grader_param.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TextSimilarityGraderParam"] - - -class TextSimilarityGraderParam(TypedDict, total=False): - """A TextSimilarityGrader object which grades text based on similarity metrics.""" - - evaluation_metric: Required[ - Literal[ - "cosine", - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - ] - ] - """The evaluation metric to use. - - One of `cosine`, `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, `rouge_2`, - `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. - """ - - input: Required[str] - """The text being graded.""" - - name: Required[str] - """The name of the grader.""" - - reference: Required[str] - """The text being graded against.""" - - type: Required[Literal["text_similarity"]] - """The type of grader.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image.py deleted file mode 100644 index dcbdb2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["Image"] - - -class Image(BaseModel): - """Represents the content or the URL of an image generated by the OpenAI API.""" - - b64_json: Optional[str] = None - """The base64-encoded JSON of the generated image. - - Returned by default for the GPT image models, and only present if - `response_format` is set to `b64_json` for `dall-e-2` and `dall-e-3`. - """ - - revised_prompt: Optional[str] = None - """For `dall-e-3` only, the revised prompt that was used to generate the image.""" - - url: Optional[str] = None - """ - When using `dall-e-2` or `dall-e-3`, the URL of the generated image if - `response_format` is set to `url` (default value). Unsupported for the GPT image - models. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_create_variation_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_create_variation_params.py deleted file mode 100644 index d10b74b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_create_variation_params.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypedDict - -from .._types import FileTypes -from .image_model import ImageModel - -__all__ = ["ImageCreateVariationParams"] - - -class ImageCreateVariationParams(TypedDict, total=False): - image: Required[FileTypes] - """The image to use as the basis for the variation(s). - - Must be a valid PNG file, less than 4MB, and square. - """ - - model: Union[str, ImageModel, None] - """The model to use for image generation. - - Only `dall-e-2` is supported at this time. - """ - - n: Optional[int] - """The number of images to generate. Must be between 1 and 10.""" - - response_format: Optional[Literal["url", "b64_json"]] - """The format in which the generated images are returned. - - Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. - """ - - size: Optional[Literal["256x256", "512x512", "1024x1024"]] - """The size of the generated images. - - Must be one of `256x256`, `512x512`, or `1024x1024`. - """ - - user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_completed_event.py deleted file mode 100644 index e2e1934..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_completed_event.py +++ /dev/null @@ -1,66 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageEditCompletedEvent", "Usage", "UsageInputTokensDetails"] - - -class UsageInputTokensDetails(BaseModel): - """The input tokens detailed information for the image generation.""" - - image_tokens: int - """The number of image tokens in the input prompt.""" - - text_tokens: int - """The number of text tokens in the input prompt.""" - - -class Usage(BaseModel): - """ - For the GPT image models only, the token usage information for the image generation. - """ - - input_tokens: int - """The number of tokens (images and text) in the input prompt.""" - - input_tokens_details: UsageInputTokensDetails - """The input tokens detailed information for the image generation.""" - - output_tokens: int - """The number of image tokens in the output image.""" - - total_tokens: int - """The total number of tokens (images and text) used for the image generation.""" - - -class ImageEditCompletedEvent(BaseModel): - """Emitted when image editing has completed and the final image is available.""" - - b64_json: str - """Base64-encoded final edited image data, suitable for rendering as an image.""" - - background: Literal["transparent", "opaque", "auto"] - """The background setting for the edited image.""" - - created_at: int - """The Unix timestamp when the event was created.""" - - output_format: Literal["png", "webp", "jpeg"] - """The output format for the edited image.""" - - quality: Literal["low", "medium", "high", "auto"] - """The quality setting for the edited image.""" - - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the edited image.""" - - type: Literal["image_edit.completed"] - """The type of the event. Always `image_edit.completed`.""" - - usage: Usage - """ - For the GPT image models only, the token usage information for the image - generation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_params.py deleted file mode 100644 index 0bd5f39..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_params.py +++ /dev/null @@ -1,146 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypedDict - -from .._types import FileTypes, SequenceNotStr -from .image_model import ImageModel - -__all__ = ["ImageEditParamsBase", "ImageEditParamsNonStreaming", "ImageEditParamsStreaming"] - - -class ImageEditParamsBase(TypedDict, total=False): - image: Required[Union[FileTypes, SequenceNotStr[FileTypes]]] - """The image(s) to edit. Must be a supported image file or an array of images. - - For the GPT image models (`gpt-image-1`, `gpt-image-1-mini`, and - `gpt-image-1.5`), each image should be a `png`, `webp`, or `jpg` file less than - 50MB. You can provide up to 16 images. - - For `dall-e-2`, you can only provide one image, and it should be a square `png` - file less than 4MB. - """ - - prompt: Required[str] - """A text description of the desired image(s). - - The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for - the GPT image models. - """ - - background: Optional[Literal["transparent", "opaque", "auto"]] - """ - Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - """ - - input_fidelity: Optional[Literal["high", "low"]] - """ - Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - """ - - mask: FileTypes - """An additional image whose fully transparent areas (e.g. - - where alpha is zero) indicate where `image` should be edited. If there are - multiple images provided, the mask will be applied on the first image. Must be a - valid PNG file, less than 4MB, and have the same dimensions as `image`. - """ - - model: Union[str, ImageModel, None] - """The model to use for image generation. - - Only `dall-e-2` and the GPT image models are supported. Defaults to `dall-e-2` - unless a parameter specific to the GPT image models is used. - """ - - n: Optional[int] - """The number of images to generate. Must be between 1 and 10.""" - - output_compression: Optional[int] - """The compression level (0-100%) for the generated images. - - This parameter is only supported for the GPT image models with the `webp` or - `jpeg` output formats, and defaults to 100. - """ - - output_format: Optional[Literal["png", "jpeg", "webp"]] - """The format in which the generated images are returned. - - This parameter is only supported for the GPT image models. Must be one of `png`, - `jpeg`, or `webp`. The default value is `png`. - """ - - partial_images: Optional[int] - """The number of partial images to generate. - - This parameter is used for streaming responses that return partial images. Value - must be between 0 and 3. When set to 0, the response will be a single image sent - in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - """ - - quality: Optional[Literal["standard", "low", "medium", "high", "auto"]] - """The quality of the image that will be generated. - - `high`, `medium` and `low` are only supported for the GPT image models. - `dall-e-2` only supports `standard` quality. Defaults to `auto`. - """ - - response_format: Optional[Literal["url", "b64_json"]] - """The format in which the generated images are returned. - - Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. This parameter is only supported for `dall-e-2`, as - the GPT image models always return base64-encoded images. - """ - - size: Optional[Literal["256x256", "512x512", "1024x1024", "1536x1024", "1024x1536", "auto"]] - """The size of the generated images. - - Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for the GPT image models, and one of `256x256`, - `512x512`, or `1024x1024` for `dall-e-2`. - """ - - user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - """ - - -class ImageEditParamsNonStreaming(ImageEditParamsBase, total=False): - stream: Optional[Literal[False]] - """Edit the image in streaming mode. - - Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - """ - - -class ImageEditParamsStreaming(ImageEditParamsBase): - stream: Required[Literal[True]] - """Edit the image in streaming mode. - - Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. - """ - - -ImageEditParams = Union[ImageEditParamsNonStreaming, ImageEditParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_partial_image_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_partial_image_event.py deleted file mode 100644 index 7bbd8c9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_partial_image_event.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageEditPartialImageEvent"] - - -class ImageEditPartialImageEvent(BaseModel): - """Emitted when a partial image is available during image editing streaming.""" - - b64_json: str - """Base64-encoded partial image data, suitable for rendering as an image.""" - - background: Literal["transparent", "opaque", "auto"] - """The background setting for the requested edited image.""" - - created_at: int - """The Unix timestamp when the event was created.""" - - output_format: Literal["png", "webp", "jpeg"] - """The output format for the requested edited image.""" - - partial_image_index: int - """0-based index for the partial image (streaming).""" - - quality: Literal["low", "medium", "high", "auto"] - """The quality setting for the requested edited image.""" - - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the requested edited image.""" - - type: Literal["image_edit.partial_image"] - """The type of the event. Always `image_edit.partial_image`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_stream_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_stream_event.py deleted file mode 100644 index 759f6c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_edit_stream_event.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .image_edit_completed_event import ImageEditCompletedEvent -from .image_edit_partial_image_event import ImageEditPartialImageEvent - -__all__ = ["ImageEditStreamEvent"] - -ImageEditStreamEvent: TypeAlias = Annotated[ - Union[ImageEditPartialImageEvent, ImageEditCompletedEvent], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_completed_event.py deleted file mode 100644 index 813ed88..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_completed_event.py +++ /dev/null @@ -1,66 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageGenCompletedEvent", "Usage", "UsageInputTokensDetails"] - - -class UsageInputTokensDetails(BaseModel): - """The input tokens detailed information for the image generation.""" - - image_tokens: int - """The number of image tokens in the input prompt.""" - - text_tokens: int - """The number of text tokens in the input prompt.""" - - -class Usage(BaseModel): - """ - For the GPT image models only, the token usage information for the image generation. - """ - - input_tokens: int - """The number of tokens (images and text) in the input prompt.""" - - input_tokens_details: UsageInputTokensDetails - """The input tokens detailed information for the image generation.""" - - output_tokens: int - """The number of image tokens in the output image.""" - - total_tokens: int - """The total number of tokens (images and text) used for the image generation.""" - - -class ImageGenCompletedEvent(BaseModel): - """Emitted when image generation has completed and the final image is available.""" - - b64_json: str - """Base64-encoded image data, suitable for rendering as an image.""" - - background: Literal["transparent", "opaque", "auto"] - """The background setting for the generated image.""" - - created_at: int - """The Unix timestamp when the event was created.""" - - output_format: Literal["png", "webp", "jpeg"] - """The output format for the generated image.""" - - quality: Literal["low", "medium", "high", "auto"] - """The quality setting for the generated image.""" - - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the generated image.""" - - type: Literal["image_generation.completed"] - """The type of the event. Always `image_generation.completed`.""" - - usage: Usage - """ - For the GPT image models only, the token usage information for the image - generation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_partial_image_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_partial_image_event.py deleted file mode 100644 index df29c00..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_partial_image_event.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageGenPartialImageEvent"] - - -class ImageGenPartialImageEvent(BaseModel): - """Emitted when a partial image is available during image generation streaming.""" - - b64_json: str - """Base64-encoded partial image data, suitable for rendering as an image.""" - - background: Literal["transparent", "opaque", "auto"] - """The background setting for the requested image.""" - - created_at: int - """The Unix timestamp when the event was created.""" - - output_format: Literal["png", "webp", "jpeg"] - """The output format for the requested image.""" - - partial_image_index: int - """0-based index for the partial image (streaming).""" - - quality: Literal["low", "medium", "high", "auto"] - """The quality setting for the requested image.""" - - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the requested image.""" - - type: Literal["image_generation.partial_image"] - """The type of the event. Always `image_generation.partial_image`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_stream_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_stream_event.py deleted file mode 100644 index 7dde5d5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_gen_stream_event.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .image_gen_completed_event import ImageGenCompletedEvent -from .image_gen_partial_image_event import ImageGenPartialImageEvent - -__all__ = ["ImageGenStreamEvent"] - -ImageGenStreamEvent: TypeAlias = Annotated[ - Union[ImageGenPartialImageEvent, ImageGenCompletedEvent], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_generate_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_generate_params.py deleted file mode 100644 index 7a95b3d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_generate_params.py +++ /dev/null @@ -1,145 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypedDict - -from .image_model import ImageModel - -__all__ = ["ImageGenerateParamsBase", "ImageGenerateParamsNonStreaming", "ImageGenerateParamsStreaming"] - - -class ImageGenerateParamsBase(TypedDict, total=False): - prompt: Required[str] - """A text description of the desired image(s). - - The maximum length is 32000 characters for the GPT image models, 1000 characters - for `dall-e-2` and 4000 characters for `dall-e-3`. - """ - - background: Optional[Literal["transparent", "opaque", "auto"]] - """ - Allows to set transparency for the background of the generated image(s). This - parameter is only supported for the GPT image models. Must be one of - `transparent`, `opaque` or `auto` (default value). When `auto` is used, the - model will automatically determine the best background for the image. - - If `transparent`, the output format needs to support transparency, so it should - be set to either `png` (default value) or `webp`. - """ - - model: Union[str, ImageModel, None] - """The model to use for image generation. - - One of `dall-e-2`, `dall-e-3`, or a GPT image model (`gpt-image-1`, - `gpt-image-1-mini`, `gpt-image-1.5`). Defaults to `dall-e-2` unless a parameter - specific to the GPT image models is used. - """ - - moderation: Optional[Literal["low", "auto"]] - """ - Control the content-moderation level for images generated by the GPT image - models. Must be either `low` for less restrictive filtering or `auto` (default - value). - """ - - n: Optional[int] - """The number of images to generate. - - Must be between 1 and 10. For `dall-e-3`, only `n=1` is supported. - """ - - output_compression: Optional[int] - """The compression level (0-100%) for the generated images. - - This parameter is only supported for the GPT image models with the `webp` or - `jpeg` output formats, and defaults to 100. - """ - - output_format: Optional[Literal["png", "jpeg", "webp"]] - """The format in which the generated images are returned. - - This parameter is only supported for the GPT image models. Must be one of `png`, - `jpeg`, or `webp`. - """ - - partial_images: Optional[int] - """The number of partial images to generate. - - This parameter is used for streaming responses that return partial images. Value - must be between 0 and 3. When set to 0, the response will be a single image sent - in one streaming event. - - Note that the final image may be sent before the full number of partial images - are generated if the full image is generated more quickly. - """ - - quality: Optional[Literal["standard", "hd", "low", "medium", "high", "auto"]] - """The quality of the image that will be generated. - - - `auto` (default value) will automatically select the best quality for the - given model. - - `high`, `medium` and `low` are supported for the GPT image models. - - `hd` and `standard` are supported for `dall-e-3`. - - `standard` is the only option for `dall-e-2`. - """ - - response_format: Optional[Literal["url", "b64_json"]] - """The format in which generated images with `dall-e-2` and `dall-e-3` are - returned. - - Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the - image has been generated. This parameter isn't supported for the GPT image - models, which always return base64-encoded images. - """ - - size: Optional[ - Literal["auto", "1024x1024", "1536x1024", "1024x1536", "256x256", "512x512", "1792x1024", "1024x1792"] - ] - """The size of the generated images. - - Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or - `auto` (default value) for the GPT image models, one of `256x256`, `512x512`, or - `1024x1024` for `dall-e-2`, and one of `1024x1024`, `1792x1024`, or `1024x1792` - for `dall-e-3`. - """ - - style: Optional[Literal["vivid", "natural"]] - """The style of the generated images. - - This parameter is only supported for `dall-e-3`. Must be one of `vivid` or - `natural`. Vivid causes the model to lean towards generating hyper-real and - dramatic images. Natural causes the model to produce more natural, less - hyper-real looking images. - """ - - user: str - """ - A unique identifier representing your end-user, which can help OpenAI to monitor - and detect abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - """ - - -class ImageGenerateParamsNonStreaming(ImageGenerateParamsBase, total=False): - stream: Optional[Literal[False]] - """Generate the image in streaming mode. - - Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - """ - - -class ImageGenerateParamsStreaming(ImageGenerateParamsBase): - stream: Required[Literal[True]] - """Generate the image in streaming mode. - - Defaults to `false`. See the - [Image generation guide](https://platform.openai.com/docs/guides/image-generation) - for more information. This parameter is only supported for the GPT image models. - """ - - -ImageGenerateParams = Union[ImageGenerateParamsNonStreaming, ImageGenerateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/image_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/image_model.py deleted file mode 100644 index 8ea486f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/image_model.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ImageModel"] - -ImageModel: TypeAlias = Literal["gpt-image-1.5", "dall-e-2", "dall-e-3", "gpt-image-1", "gpt-image-1-mini"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/images_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/images_response.py deleted file mode 100644 index 3e832aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/images_response.py +++ /dev/null @@ -1,79 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .image import Image -from .._models import BaseModel - -__all__ = ["ImagesResponse", "Usage", "UsageInputTokensDetails", "UsageOutputTokensDetails"] - - -class UsageInputTokensDetails(BaseModel): - """The input tokens detailed information for the image generation.""" - - image_tokens: int - """The number of image tokens in the input prompt.""" - - text_tokens: int - """The number of text tokens in the input prompt.""" - - -class UsageOutputTokensDetails(BaseModel): - """The output token details for the image generation.""" - - image_tokens: int - """The number of image output tokens generated by the model.""" - - text_tokens: int - """The number of text output tokens generated by the model.""" - - -class Usage(BaseModel): - """For `gpt-image-1` only, the token usage information for the image generation.""" - - input_tokens: int - """The number of tokens (images and text) in the input prompt.""" - - input_tokens_details: UsageInputTokensDetails - """The input tokens detailed information for the image generation.""" - - output_tokens: int - """The number of output tokens generated by the model.""" - - total_tokens: int - """The total number of tokens (images and text) used for the image generation.""" - - output_tokens_details: Optional[UsageOutputTokensDetails] = None - """The output token details for the image generation.""" - - -class ImagesResponse(BaseModel): - """The response from the image generation endpoint.""" - - created: int - """The Unix timestamp (in seconds) of when the image was created.""" - - background: Optional[Literal["transparent", "opaque"]] = None - """The background parameter used for the image generation. - - Either `transparent` or `opaque`. - """ - - data: Optional[List[Image]] = None - """The list of generated images.""" - - output_format: Optional[Literal["png", "webp", "jpeg"]] = None - """The output format of the image generation. Either `png`, `webp`, or `jpeg`.""" - - quality: Optional[Literal["low", "medium", "high"]] = None - """The quality of the image generated. Either `low`, `medium`, or `high`.""" - - size: Optional[Literal["1024x1024", "1024x1536", "1536x1024"]] = None - """The size of the image generated. - - Either `1024x1024`, `1024x1536`, or `1536x1024`. - """ - - usage: Optional[Usage] = None - """For `gpt-image-1` only, the token usage information for the image generation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/model.py deleted file mode 100644 index 6506224..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/model.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["Model"] - - -class Model(BaseModel): - """Describes an OpenAI model offering that can be used with the API.""" - - id: str - """The model identifier, which can be referenced in the API endpoints.""" - - created: int - """The Unix timestamp (in seconds) when the model was created.""" - - object: Literal["model"] - """The object type, which is always "model".""" - - owned_by: str - """The organization that owns the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/model_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/model_deleted.py deleted file mode 100644 index e7601f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/model_deleted.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["ModelDeleted"] - - -class ModelDeleted(BaseModel): - id: str - - deleted: bool - - object: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation.py deleted file mode 100644 index a6acc26..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation.py +++ /dev/null @@ -1,194 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["Moderation", "Categories", "CategoryAppliedInputTypes", "CategoryScores"] - - -class Categories(BaseModel): - """A list of the categories, and whether they are flagged or not.""" - - harassment: bool - """ - Content that expresses, incites, or promotes harassing language towards any - target. - """ - - harassment_threatening: bool = FieldInfo(alias="harassment/threatening") - """ - Harassment content that also includes violence or serious harm towards any - target. - """ - - hate: bool - """ - Content that expresses, incites, or promotes hate based on race, gender, - ethnicity, religion, nationality, sexual orientation, disability status, or - caste. Hateful content aimed at non-protected groups (e.g., chess players) is - harassment. - """ - - hate_threatening: bool = FieldInfo(alias="hate/threatening") - """ - Hateful content that also includes violence or serious harm towards the targeted - group based on race, gender, ethnicity, religion, nationality, sexual - orientation, disability status, or caste. - """ - - illicit: Optional[bool] = None - """ - Content that includes instructions or advice that facilitate the planning or - execution of wrongdoing, or that gives advice or instruction on how to commit - illicit acts. For example, "how to shoplift" would fit this category. - """ - - illicit_violent: Optional[bool] = FieldInfo(alias="illicit/violent", default=None) - """ - Content that includes instructions or advice that facilitate the planning or - execution of wrongdoing that also includes violence, or that gives advice or - instruction on the procurement of any weapon. - """ - - self_harm: bool = FieldInfo(alias="self-harm") - """ - Content that promotes, encourages, or depicts acts of self-harm, such as - suicide, cutting, and eating disorders. - """ - - self_harm_instructions: bool = FieldInfo(alias="self-harm/instructions") - """ - Content that encourages performing acts of self-harm, such as suicide, cutting, - and eating disorders, or that gives instructions or advice on how to commit such - acts. - """ - - self_harm_intent: bool = FieldInfo(alias="self-harm/intent") - """ - Content where the speaker expresses that they are engaging or intend to engage - in acts of self-harm, such as suicide, cutting, and eating disorders. - """ - - sexual: bool - """ - Content meant to arouse sexual excitement, such as the description of sexual - activity, or that promotes sexual services (excluding sex education and - wellness). - """ - - sexual_minors: bool = FieldInfo(alias="sexual/minors") - """Sexual content that includes an individual who is under 18 years old.""" - - violence: bool - """Content that depicts death, violence, or physical injury.""" - - violence_graphic: bool = FieldInfo(alias="violence/graphic") - """Content that depicts death, violence, or physical injury in graphic detail.""" - - -class CategoryAppliedInputTypes(BaseModel): - """ - A list of the categories along with the input type(s) that the score applies to. - """ - - harassment: List[Literal["text"]] - """The applied input type(s) for the category 'harassment'.""" - - harassment_threatening: List[Literal["text"]] = FieldInfo(alias="harassment/threatening") - """The applied input type(s) for the category 'harassment/threatening'.""" - - hate: List[Literal["text"]] - """The applied input type(s) for the category 'hate'.""" - - hate_threatening: List[Literal["text"]] = FieldInfo(alias="hate/threatening") - """The applied input type(s) for the category 'hate/threatening'.""" - - illicit: List[Literal["text"]] - """The applied input type(s) for the category 'illicit'.""" - - illicit_violent: List[Literal["text"]] = FieldInfo(alias="illicit/violent") - """The applied input type(s) for the category 'illicit/violent'.""" - - self_harm: List[Literal["text", "image"]] = FieldInfo(alias="self-harm") - """The applied input type(s) for the category 'self-harm'.""" - - self_harm_instructions: List[Literal["text", "image"]] = FieldInfo(alias="self-harm/instructions") - """The applied input type(s) for the category 'self-harm/instructions'.""" - - self_harm_intent: List[Literal["text", "image"]] = FieldInfo(alias="self-harm/intent") - """The applied input type(s) for the category 'self-harm/intent'.""" - - sexual: List[Literal["text", "image"]] - """The applied input type(s) for the category 'sexual'.""" - - sexual_minors: List[Literal["text"]] = FieldInfo(alias="sexual/minors") - """The applied input type(s) for the category 'sexual/minors'.""" - - violence: List[Literal["text", "image"]] - """The applied input type(s) for the category 'violence'.""" - - violence_graphic: List[Literal["text", "image"]] = FieldInfo(alias="violence/graphic") - """The applied input type(s) for the category 'violence/graphic'.""" - - -class CategoryScores(BaseModel): - """A list of the categories along with their scores as predicted by model.""" - - harassment: float - """The score for the category 'harassment'.""" - - harassment_threatening: float = FieldInfo(alias="harassment/threatening") - """The score for the category 'harassment/threatening'.""" - - hate: float - """The score for the category 'hate'.""" - - hate_threatening: float = FieldInfo(alias="hate/threatening") - """The score for the category 'hate/threatening'.""" - - illicit: float - """The score for the category 'illicit'.""" - - illicit_violent: float = FieldInfo(alias="illicit/violent") - """The score for the category 'illicit/violent'.""" - - self_harm: float = FieldInfo(alias="self-harm") - """The score for the category 'self-harm'.""" - - self_harm_instructions: float = FieldInfo(alias="self-harm/instructions") - """The score for the category 'self-harm/instructions'.""" - - self_harm_intent: float = FieldInfo(alias="self-harm/intent") - """The score for the category 'self-harm/intent'.""" - - sexual: float - """The score for the category 'sexual'.""" - - sexual_minors: float = FieldInfo(alias="sexual/minors") - """The score for the category 'sexual/minors'.""" - - violence: float - """The score for the category 'violence'.""" - - violence_graphic: float = FieldInfo(alias="violence/graphic") - """The score for the category 'violence/graphic'.""" - - -class Moderation(BaseModel): - categories: Categories - """A list of the categories, and whether they are flagged or not.""" - - category_applied_input_types: CategoryAppliedInputTypes - """ - A list of the categories along with the input type(s) that the score applies to. - """ - - category_scores: CategoryScores - """A list of the categories along with their scores as predicted by model.""" - - flagged: bool - """Whether any of the below categories are flagged.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_params.py deleted file mode 100644 index 65d9b7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_params.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Required, TypedDict - -from .._types import SequenceNotStr -from .moderation_model import ModerationModel -from .moderation_multi_modal_input_param import ModerationMultiModalInputParam - -__all__ = ["ModerationCreateParams"] - - -class ModerationCreateParams(TypedDict, total=False): - input: Required[Union[str, SequenceNotStr[str], Iterable[ModerationMultiModalInputParam]]] - """Input (or inputs) to classify. - - Can be a single string, an array of strings, or an array of multi-modal input - objects similar to other models. - """ - - model: Union[str, ModerationModel] - """The content moderation model you would like to use. - - Learn more in - [the moderation guide](https://platform.openai.com/docs/guides/moderation), and - learn about available models - [here](https://platform.openai.com/docs/models#moderation). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_response.py deleted file mode 100644 index 23c0387..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_create_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from .._models import BaseModel -from .moderation import Moderation - -__all__ = ["ModerationCreateResponse"] - - -class ModerationCreateResponse(BaseModel): - """Represents if a given text input is potentially harmful.""" - - id: str - """The unique identifier for the moderation request.""" - - model: str - """The model used to generate the moderation results.""" - - results: List[Moderation] - """A list of moderation objects.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_image_url_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_image_url_input_param.py deleted file mode 100644 index 9c0fe25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_image_url_input_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ModerationImageURLInputParam", "ImageURL"] - - -class ImageURL(TypedDict, total=False): - """Contains either an image URL or a data URL for a base64 encoded image.""" - - url: Required[str] - """Either a URL of the image or the base64 encoded image data.""" - - -class ModerationImageURLInputParam(TypedDict, total=False): - """An object describing an image to classify.""" - - image_url: Required[ImageURL] - """Contains either an image URL or a data URL for a base64 encoded image.""" - - type: Required[Literal["image_url"]] - """Always `image_url`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_model.py deleted file mode 100644 index 64954c4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_model.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ModerationModel"] - -ModerationModel: TypeAlias = Literal[ - "omni-moderation-latest", "omni-moderation-2024-09-26", "text-moderation-latest", "text-moderation-stable" -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_multi_modal_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_multi_modal_input_param.py deleted file mode 100644 index 4314e7b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_multi_modal_input_param.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .moderation_text_input_param import ModerationTextInputParam -from .moderation_image_url_input_param import ModerationImageURLInputParam - -__all__ = ["ModerationMultiModalInputParam"] - -ModerationMultiModalInputParam: TypeAlias = Union[ModerationImageURLInputParam, ModerationTextInputParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_text_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_text_input_param.py deleted file mode 100644 index 786ecbe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/moderation_text_input_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ModerationTextInputParam"] - - -class ModerationTextInputParam(TypedDict, total=False): - """An object describing text to classify.""" - - text: Required[str] - """A string of text to classify.""" - - type: Required[Literal["text"]] - """Always `text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/other_file_chunking_strategy_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/other_file_chunking_strategy_object.py deleted file mode 100644 index a537142..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/other_file_chunking_strategy_object.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["OtherFileChunkingStrategyObject"] - - -class OtherFileChunkingStrategyObject(BaseModel): - """This is returned when the chunking strategy is unknown. - - Typically, this is because the file was indexed before the `chunking_strategy` concept was introduced in the API. - """ - - type: Literal["other"] - """Always `other`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/__init__.py deleted file mode 100644 index c2a141d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/__init__.py +++ /dev/null @@ -1,240 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .realtime_error import RealtimeError as RealtimeError -from .call_refer_params import CallReferParams as CallReferParams -from .conversation_item import ConversationItem as ConversationItem -from .realtime_response import RealtimeResponse as RealtimeResponse -from .call_accept_params import CallAcceptParams as CallAcceptParams -from .call_create_params import CallCreateParams as CallCreateParams -from .call_reject_params import CallRejectParams as CallRejectParams -from .audio_transcription import AudioTranscription as AudioTranscription -from .log_prob_properties import LogProbProperties as LogProbProperties -from .realtime_truncation import RealtimeTruncation as RealtimeTruncation -from .response_done_event import ResponseDoneEvent as ResponseDoneEvent -from .noise_reduction_type import NoiseReductionType as NoiseReductionType -from .realtime_error_event import RealtimeErrorEvent as RealtimeErrorEvent -from .session_update_event import SessionUpdateEvent as SessionUpdateEvent -from .mcp_list_tools_failed import McpListToolsFailed as McpListToolsFailed -from .realtime_audio_config import RealtimeAudioConfig as RealtimeAudioConfig -from .realtime_client_event import RealtimeClientEvent as RealtimeClientEvent -from .realtime_server_event import RealtimeServerEvent as RealtimeServerEvent -from .realtime_tools_config import RealtimeToolsConfig as RealtimeToolsConfig -from .response_cancel_event import ResponseCancelEvent as ResponseCancelEvent -from .response_create_event import ResponseCreateEvent as ResponseCreateEvent -from .session_created_event import SessionCreatedEvent as SessionCreatedEvent -from .session_updated_event import SessionUpdatedEvent as SessionUpdatedEvent -from .conversation_item_done import ConversationItemDone as ConversationItemDone -from .realtime_audio_formats import RealtimeAudioFormats as RealtimeAudioFormats -from .realtime_function_tool import RealtimeFunctionTool as RealtimeFunctionTool -from .realtime_mcp_tool_call import RealtimeMcpToolCall as RealtimeMcpToolCall -from .realtime_mcphttp_error import RealtimeMcphttpError as RealtimeMcphttpError -from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent -from .conversation_item_added import ConversationItemAdded as ConversationItemAdded -from .conversation_item_param import ConversationItemParam as ConversationItemParam -from .realtime_connect_params import RealtimeConnectParams as RealtimeConnectParams -from .realtime_mcp_list_tools import RealtimeMcpListTools as RealtimeMcpListTools -from .realtime_response_usage import RealtimeResponseUsage as RealtimeResponseUsage -from .realtime_tracing_config import RealtimeTracingConfig as RealtimeTracingConfig -from .mcp_list_tools_completed import McpListToolsCompleted as McpListToolsCompleted -from .realtime_response_status import RealtimeResponseStatus as RealtimeResponseStatus -from .response_mcp_call_failed import ResponseMcpCallFailed as ResponseMcpCallFailed -from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent -from .audio_transcription_param import AudioTranscriptionParam as AudioTranscriptionParam -from .rate_limits_updated_event import RateLimitsUpdatedEvent as RateLimitsUpdatedEvent -from .realtime_truncation_param import RealtimeTruncationParam as RealtimeTruncationParam -from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent -from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent -from .conversation_created_event import ConversationCreatedEvent as ConversationCreatedEvent -from .mcp_list_tools_in_progress import McpListToolsInProgress as McpListToolsInProgress -from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent -from .session_update_event_param import SessionUpdateEventParam as SessionUpdateEventParam -from .client_secret_create_params import ClientSecretCreateParams as ClientSecretCreateParams -from .realtime_audio_config_input import RealtimeAudioConfigInput as RealtimeAudioConfigInput -from .realtime_audio_config_param import RealtimeAudioConfigParam as RealtimeAudioConfigParam -from .realtime_client_event_param import RealtimeClientEventParam as RealtimeClientEventParam -from .realtime_mcp_protocol_error import RealtimeMcpProtocolError as RealtimeMcpProtocolError -from .realtime_tool_choice_config import RealtimeToolChoiceConfig as RealtimeToolChoiceConfig -from .realtime_tools_config_param import RealtimeToolsConfigParam as RealtimeToolsConfigParam -from .realtime_tools_config_union import RealtimeToolsConfigUnion as RealtimeToolsConfigUnion -from .response_cancel_event_param import ResponseCancelEventParam as ResponseCancelEventParam -from .response_create_event_param import ResponseCreateEventParam as ResponseCreateEventParam -from .response_mcp_call_completed import ResponseMcpCallCompleted as ResponseMcpCallCompleted -from .realtime_audio_config_output import RealtimeAudioConfigOutput as RealtimeAudioConfigOutput -from .realtime_audio_formats_param import RealtimeAudioFormatsParam as RealtimeAudioFormatsParam -from .realtime_function_tool_param import RealtimeFunctionToolParam as RealtimeFunctionToolParam -from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam as RealtimeMcpToolCallParam -from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam as RealtimeMcphttpErrorParam -from .client_secret_create_response import ClientSecretCreateResponse as ClientSecretCreateResponse -from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest as RealtimeMcpApprovalRequest -from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam as RealtimeMcpListToolsParam -from .realtime_tracing_config_param import RealtimeTracingConfigParam as RealtimeTracingConfigParam -from .response_mcp_call_in_progress import ResponseMcpCallInProgress as ResponseMcpCallInProgress -from .conversation_item_create_event import ConversationItemCreateEvent as ConversationItemCreateEvent -from .conversation_item_delete_event import ConversationItemDeleteEvent as ConversationItemDeleteEvent -from .input_audio_buffer_clear_event import InputAudioBufferClearEvent as InputAudioBufferClearEvent -from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse as RealtimeMcpApprovalResponse -from .realtime_session_client_secret import RealtimeSessionClientSecret as RealtimeSessionClientSecret -from .conversation_item_created_event import ConversationItemCreatedEvent as ConversationItemCreatedEvent -from .conversation_item_deleted_event import ConversationItemDeletedEvent as ConversationItemDeletedEvent -from .input_audio_buffer_append_event import InputAudioBufferAppendEvent as InputAudioBufferAppendEvent -from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent as InputAudioBufferCommitEvent -from .output_audio_buffer_clear_event import OutputAudioBufferClearEvent as OutputAudioBufferClearEvent -from .realtime_response_create_params import RealtimeResponseCreateParams as RealtimeResponseCreateParams -from .realtime_session_create_request import RealtimeSessionCreateRequest as RealtimeSessionCreateRequest -from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent -from .conversation_item_retrieve_event import ConversationItemRetrieveEvent as ConversationItemRetrieveEvent -from .conversation_item_truncate_event import ConversationItemTruncateEvent as ConversationItemTruncateEvent -from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent as InputAudioBufferClearedEvent -from .realtime_session_create_response import RealtimeSessionCreateResponse as RealtimeSessionCreateResponse -from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent -from .response_mcp_call_arguments_done import ResponseMcpCallArgumentsDone as ResponseMcpCallArgumentsDone -from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent -from .conversation_item_truncated_event import ConversationItemTruncatedEvent as ConversationItemTruncatedEvent -from .realtime_audio_config_input_param import RealtimeAudioConfigInputParam as RealtimeAudioConfigInputParam -from .realtime_mcp_protocol_error_param import RealtimeMcpProtocolErrorParam as RealtimeMcpProtocolErrorParam -from .realtime_mcp_tool_execution_error import RealtimeMcpToolExecutionError as RealtimeMcpToolExecutionError -from .realtime_response_create_mcp_tool import RealtimeResponseCreateMcpTool as RealtimeResponseCreateMcpTool -from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam as RealtimeToolChoiceConfigParam -from .realtime_tools_config_union_param import RealtimeToolsConfigUnionParam as RealtimeToolsConfigUnionParam -from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent -from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta as ResponseMcpCallArgumentsDelta -from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent as InputAudioBufferCommittedEvent -from .realtime_audio_config_output_param import RealtimeAudioConfigOutputParam as RealtimeAudioConfigOutputParam -from .realtime_audio_input_turn_detection import RealtimeAudioInputTurnDetection as RealtimeAudioInputTurnDetection -from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam as RealtimeMcpApprovalRequestParam -from .realtime_truncation_retention_ratio import RealtimeTruncationRetentionRatio as RealtimeTruncationRetentionRatio -from .conversation_item_create_event_param import ConversationItemCreateEventParam as ConversationItemCreateEventParam -from .conversation_item_delete_event_param import ConversationItemDeleteEventParam as ConversationItemDeleteEventParam -from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam as InputAudioBufferClearEventParam -from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered as InputAudioBufferTimeoutTriggered -from .realtime_mcp_approval_response_param import RealtimeMcpApprovalResponseParam as RealtimeMcpApprovalResponseParam -from .realtime_transcription_session_audio import RealtimeTranscriptionSessionAudio as RealtimeTranscriptionSessionAudio -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent -from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam as InputAudioBufferAppendEventParam -from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam as InputAudioBufferCommitEventParam -from .output_audio_buffer_clear_event_param import OutputAudioBufferClearEventParam as OutputAudioBufferClearEventParam -from .realtime_response_create_audio_output import ( - RealtimeResponseCreateAudioOutput as RealtimeResponseCreateAudioOutput, -) -from .realtime_response_create_params_param import ( - RealtimeResponseCreateParamsParam as RealtimeResponseCreateParamsParam, -) -from .realtime_session_create_request_param import ( - RealtimeSessionCreateRequestParam as RealtimeSessionCreateRequestParam, -) -from .response_audio_transcript_delta_event import ( - ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, -) -from .conversation_item_retrieve_event_param import ( - ConversationItemRetrieveEventParam as ConversationItemRetrieveEventParam, -) -from .conversation_item_truncate_event_param import ( - ConversationItemTruncateEventParam as ConversationItemTruncateEventParam, -) -from .input_audio_buffer_speech_started_event import ( - InputAudioBufferSpeechStartedEvent as InputAudioBufferSpeechStartedEvent, -) -from .input_audio_buffer_speech_stopped_event import ( - InputAudioBufferSpeechStoppedEvent as InputAudioBufferSpeechStoppedEvent, -) -from .realtime_conversation_item_user_message import ( - RealtimeConversationItemUserMessage as RealtimeConversationItemUserMessage, -) -from .realtime_mcp_tool_execution_error_param import ( - RealtimeMcpToolExecutionErrorParam as RealtimeMcpToolExecutionErrorParam, -) -from .realtime_response_create_mcp_tool_param import ( - RealtimeResponseCreateMcpToolParam as RealtimeResponseCreateMcpToolParam, -) -from .realtime_conversation_item_function_call import ( - RealtimeConversationItemFunctionCall as RealtimeConversationItemFunctionCall, -) -from .realtime_audio_input_turn_detection_param import ( - RealtimeAudioInputTurnDetectionParam as RealtimeAudioInputTurnDetectionParam, -) -from .realtime_conversation_item_system_message import ( - RealtimeConversationItemSystemMessage as RealtimeConversationItemSystemMessage, -) -from .realtime_truncation_retention_ratio_param import ( - RealtimeTruncationRetentionRatioParam as RealtimeTruncationRetentionRatioParam, -) -from .realtime_transcription_session_audio_input import ( - RealtimeTranscriptionSessionAudioInput as RealtimeTranscriptionSessionAudioInput, -) -from .realtime_transcription_session_audio_param import ( - RealtimeTranscriptionSessionAudioParam as RealtimeTranscriptionSessionAudioParam, -) -from .realtime_response_create_audio_output_param import ( - RealtimeResponseCreateAudioOutputParam as RealtimeResponseCreateAudioOutputParam, -) -from .realtime_response_usage_input_token_details import ( - RealtimeResponseUsageInputTokenDetails as RealtimeResponseUsageInputTokenDetails, -) -from .response_function_call_arguments_done_event import ( - ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, -) -from .input_audio_buffer_dtmf_event_received_event import ( - InputAudioBufferDtmfEventReceivedEvent as InputAudioBufferDtmfEventReceivedEvent, -) -from .realtime_conversation_item_assistant_message import ( - RealtimeConversationItemAssistantMessage as RealtimeConversationItemAssistantMessage, -) -from .realtime_response_usage_output_token_details import ( - RealtimeResponseUsageOutputTokenDetails as RealtimeResponseUsageOutputTokenDetails, -) -from .response_function_call_arguments_delta_event import ( - ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, -) -from .realtime_conversation_item_user_message_param import ( - RealtimeConversationItemUserMessageParam as RealtimeConversationItemUserMessageParam, -) -from .realtime_transcription_session_create_request import ( - RealtimeTranscriptionSessionCreateRequest as RealtimeTranscriptionSessionCreateRequest, -) -from .realtime_transcription_session_turn_detection import ( - RealtimeTranscriptionSessionTurnDetection as RealtimeTranscriptionSessionTurnDetection, -) -from .realtime_conversation_item_function_call_param import ( - RealtimeConversationItemFunctionCallParam as RealtimeConversationItemFunctionCallParam, -) -from .realtime_transcription_session_create_response import ( - RealtimeTranscriptionSessionCreateResponse as RealtimeTranscriptionSessionCreateResponse, -) -from .realtime_conversation_item_function_call_output import ( - RealtimeConversationItemFunctionCallOutput as RealtimeConversationItemFunctionCallOutput, -) -from .realtime_conversation_item_system_message_param import ( - RealtimeConversationItemSystemMessageParam as RealtimeConversationItemSystemMessageParam, -) -from .realtime_transcription_session_audio_input_param import ( - RealtimeTranscriptionSessionAudioInputParam as RealtimeTranscriptionSessionAudioInputParam, -) -from .realtime_conversation_item_assistant_message_param import ( - RealtimeConversationItemAssistantMessageParam as RealtimeConversationItemAssistantMessageParam, -) -from .conversation_item_input_audio_transcription_segment import ( - ConversationItemInputAudioTranscriptionSegment as ConversationItemInputAudioTranscriptionSegment, -) -from .realtime_transcription_session_create_request_param import ( - RealtimeTranscriptionSessionCreateRequestParam as RealtimeTranscriptionSessionCreateRequestParam, -) -from .realtime_conversation_item_function_call_output_param import ( - RealtimeConversationItemFunctionCallOutputParam as RealtimeConversationItemFunctionCallOutputParam, -) -from .conversation_item_input_audio_transcription_delta_event import ( - ConversationItemInputAudioTranscriptionDeltaEvent as ConversationItemInputAudioTranscriptionDeltaEvent, -) -from .conversation_item_input_audio_transcription_failed_event import ( - ConversationItemInputAudioTranscriptionFailedEvent as ConversationItemInputAudioTranscriptionFailedEvent, -) -from .realtime_transcription_session_audio_input_turn_detection import ( - RealtimeTranscriptionSessionAudioInputTurnDetection as RealtimeTranscriptionSessionAudioInputTurnDetection, -) -from .conversation_item_input_audio_transcription_completed_event import ( - ConversationItemInputAudioTranscriptionCompletedEvent as ConversationItemInputAudioTranscriptionCompletedEvent, -) -from .realtime_transcription_session_audio_input_turn_detection_param import ( - RealtimeTranscriptionSessionAudioInputTurnDetectionParam as RealtimeTranscriptionSessionAudioInputTurnDetectionParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription.py deleted file mode 100644 index 0a8c137..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["AudioTranscription"] - - -class AudioTranscription(BaseModel): - language: Optional[str] = None - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Union[ - str, - Literal[ - "whisper-1", - "gpt-4o-mini-transcribe", - "gpt-4o-mini-transcribe-2025-12-15", - "gpt-4o-transcribe", - "gpt-4o-transcribe-diarize", - ], - None, - ] = None - """The model to use for transcription. - - Current options are `whisper-1`, `gpt-4o-mini-transcribe`, - `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and - `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need - diarization with speaker labels. - """ - - prompt: Optional[str] = None - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the - prompt is a free text string, for example "expect words related to technology". - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription_param.py deleted file mode 100644 index 7e60a00..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/audio_transcription_param.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -__all__ = ["AudioTranscriptionParam"] - - -class AudioTranscriptionParam(TypedDict, total=False): - language: str - """The language of the input audio. - - Supplying the input language in - [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) - format will improve accuracy and latency. - """ - - model: Union[ - str, - Literal[ - "whisper-1", - "gpt-4o-mini-transcribe", - "gpt-4o-mini-transcribe-2025-12-15", - "gpt-4o-transcribe", - "gpt-4o-transcribe-diarize", - ], - ] - """The model to use for transcription. - - Current options are `whisper-1`, `gpt-4o-mini-transcribe`, - `gpt-4o-mini-transcribe-2025-12-15`, `gpt-4o-transcribe`, and - `gpt-4o-transcribe-diarize`. Use `gpt-4o-transcribe-diarize` when you need - diarization with speaker labels. - """ - - prompt: str - """ - An optional text to guide the model's style or continue a previous audio - segment. For `whisper-1`, the - [prompt is a list of keywords](https://platform.openai.com/docs/guides/speech-to-text#prompting). - For `gpt-4o-transcribe` models (excluding `gpt-4o-transcribe-diarize`), the - prompt is a free text string, for example "expect words related to technology". - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_accept_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_accept_params.py deleted file mode 100644 index d950f59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_accept_params.py +++ /dev/null @@ -1,129 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Optional -from typing_extensions import Literal, Required, TypedDict - -from .realtime_truncation_param import RealtimeTruncationParam -from .realtime_audio_config_param import RealtimeAudioConfigParam -from .realtime_tools_config_param import RealtimeToolsConfigParam -from .realtime_tracing_config_param import RealtimeTracingConfigParam -from ..responses.response_prompt_param import ResponsePromptParam -from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam - -__all__ = ["CallAcceptParams"] - - -class CallAcceptParams(TypedDict, total=False): - type: Required[Literal["realtime"]] - """The type of session to create. Always `realtime` for the Realtime API.""" - - audio: RealtimeAudioConfigParam - """Configuration for input and output audio.""" - - include: List[Literal["item.input_audio_transcription.logprobs"]] - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - ] - """The Realtime model used for this session.""" - - output_modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - It defaults to `["audio"]`, indicating that the model will respond with audio - plus a transcript. `["text"]` can be used to make the model respond with text - only. It is not possible to request both `text` and `audio` at the same time. - """ - - prompt: Optional[ResponsePromptParam] - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: RealtimeToolChoiceConfigParam - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: RealtimeToolsConfigParam - """Tools available to the model.""" - - tracing: Optional[RealtimeTracingConfigParam] - """ - Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - truncation: RealtimeTruncationParam - """ - When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_create_params.py deleted file mode 100644 index a378092..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_create_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam - -__all__ = ["CallCreateParams"] - - -class CallCreateParams(TypedDict, total=False): - sdp: Required[str] - """WebRTC Session Description Protocol (SDP) offer generated by the caller.""" - - session: RealtimeSessionCreateRequestParam - """Realtime session object configuration.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_refer_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_refer_params.py deleted file mode 100644 index 3d86238..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_refer_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CallReferParams"] - - -class CallReferParams(TypedDict, total=False): - target_uri: Required[str] - """URI that should appear in the SIP Refer-To header. - - Supports values like `tel:+14155550123` or `sip:agent@example.com`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_reject_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_reject_params.py deleted file mode 100644 index f12222c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/call_reject_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["CallRejectParams"] - - -class CallRejectParams(TypedDict, total=False): - status_code: int - """SIP response code to send back to the caller. - - Defaults to `603` (Decline) when omitted. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_params.py deleted file mode 100644 index 2297f3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_params.py +++ /dev/null @@ -1,54 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias, TypedDict - -from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam -from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam - -__all__ = ["ClientSecretCreateParams", "ExpiresAfter", "Session"] - - -class ClientSecretCreateParams(TypedDict, total=False): - expires_after: ExpiresAfter - """Configuration for the client secret expiration. - - Expiration refers to the time after which a client secret will no longer be - valid for creating sessions. The session itself may continue after that time - once started. A secret can be used to create multiple sessions until it expires. - """ - - session: Session - """Session configuration to use for the client secret. - - Choose either a realtime session or a transcription session. - """ - - -class ExpiresAfter(TypedDict, total=False): - """Configuration for the client secret expiration. - - Expiration refers to the time after which - a client secret will no longer be valid for creating sessions. The session itself may - continue after that time once started. A secret can be used to create multiple sessions - until it expires. - """ - - anchor: Literal["created_at"] - """ - The anchor point for the client secret expiration, meaning that `seconds` will - be added to the `created_at` time of the client secret to produce an expiration - timestamp. Only `created_at` is currently supported. - """ - - seconds: int - """The number of seconds from the anchor point to the expiration. - - Select a value between `10` and `7200` (2 hours). This default to 600 seconds - (10 minutes) if not specified. - """ - - -Session: TypeAlias = Union[RealtimeSessionCreateRequestParam, RealtimeTranscriptionSessionCreateRequestParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_response.py deleted file mode 100644 index 3a30b10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/client_secret_create_response.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .realtime_session_create_response import RealtimeSessionCreateResponse -from .realtime_transcription_session_create_response import RealtimeTranscriptionSessionCreateResponse - -__all__ = ["ClientSecretCreateResponse", "Session"] - -Session: TypeAlias = Annotated[ - Union[RealtimeSessionCreateResponse, RealtimeTranscriptionSessionCreateResponse], PropertyInfo(discriminator="type") -] - - -class ClientSecretCreateResponse(BaseModel): - """Response from creating a session and client secret for the Realtime API.""" - - expires_at: int - """Expiration timestamp for the client secret, in seconds since epoch.""" - - session: Session - """The session configuration for either a realtime or transcription session.""" - - value: str - """The generated client secret value.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_created_event.py deleted file mode 100644 index 3026322..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_created_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationCreatedEvent", "Conversation"] - - -class Conversation(BaseModel): - """The conversation resource.""" - - id: Optional[str] = None - """The unique ID of the conversation.""" - - object: Optional[Literal["realtime.conversation"]] = None - """The object type, must be `realtime.conversation`.""" - - -class ConversationCreatedEvent(BaseModel): - """Returned when a conversation is created. Emitted right after session creation.""" - - conversation: Conversation - """The conversation resource.""" - - event_id: str - """The unique ID of the server event.""" - - type: Literal["conversation.created"] - """The event type, must be `conversation.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item.py deleted file mode 100644 index be02152..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .realtime_mcp_tool_call import RealtimeMcpToolCall -from .realtime_mcp_list_tools import RealtimeMcpListTools -from .realtime_mcp_approval_request import RealtimeMcpApprovalRequest -from .realtime_mcp_approval_response import RealtimeMcpApprovalResponse -from .realtime_conversation_item_user_message import RealtimeConversationItemUserMessage -from .realtime_conversation_item_function_call import RealtimeConversationItemFunctionCall -from .realtime_conversation_item_system_message import RealtimeConversationItemSystemMessage -from .realtime_conversation_item_assistant_message import RealtimeConversationItemAssistantMessage -from .realtime_conversation_item_function_call_output import RealtimeConversationItemFunctionCallOutput - -__all__ = ["ConversationItem"] - -ConversationItem: TypeAlias = Annotated[ - Union[ - RealtimeConversationItemSystemMessage, - RealtimeConversationItemUserMessage, - RealtimeConversationItemAssistantMessage, - RealtimeConversationItemFunctionCall, - RealtimeConversationItemFunctionCallOutput, - RealtimeMcpApprovalResponse, - RealtimeMcpListTools, - RealtimeMcpToolCall, - RealtimeMcpApprovalRequest, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_added.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_added.py deleted file mode 100644 index 0e336a9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_added.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemAdded"] - - -class ConversationItemAdded(BaseModel): - """Sent by the server when an Item is added to the default Conversation. - - This can happen in several cases: - - When the client sends a `conversation.item.create` event. - - When the input audio buffer is committed. In this case the item will be a user message containing the audio from the buffer. - - When the model is generating a Response. In this case the `conversation.item.added` event will be sent when the model starts generating a specific Item, and thus it will not yet have any content (and `status` will be `in_progress`). - - The event will include the full content of the Item (except when model is generating a Response) except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if necessary. - """ - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - type: Literal["conversation.item.added"] - """The event type, must be `conversation.item.added`.""" - - previous_item_id: Optional[str] = None - """The ID of the item that precedes this one, if any. - - This is used to maintain ordering when items are inserted. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event.py deleted file mode 100644 index bf2d129..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemCreateEvent"] - - -class ConversationItemCreateEvent(BaseModel): - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - - item: ConversationItem - """A single item within a Realtime conversation.""" - - type: Literal["conversation.item.create"] - """The event type, must be `conversation.item.create`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - previous_item_id: Optional[str] = None - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event_param.py deleted file mode 100644 index be7f0ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_create_event_param.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .conversation_item_param import ConversationItemParam - -__all__ = ["ConversationItemCreateEventParam"] - - -class ConversationItemCreateEventParam(TypedDict, total=False): - """ - Add a new Item to the Conversation's context, including messages, function - calls, and function call responses. This event can be used both to populate a - "history" of the conversation and to add new items mid-stream, but has the - current limitation that it cannot populate assistant audio messages. - - If successful, the server will respond with a `conversation.item.created` - event, otherwise an `error` event will be sent. - """ - - item: Required[ConversationItemParam] - """A single item within a Realtime conversation.""" - - type: Required[Literal["conversation.item.create"]] - """The event type, must be `conversation.item.create`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - previous_item_id: str - """The ID of the preceding item after which the new item will be inserted. - - If not set, the new item will be appended to the end of the conversation. If set - to `root`, the new item will be added to the beginning of the conversation. If - set to an existing ID, it allows an item to be inserted mid-conversation. If the - ID cannot be found, an error will be returned and the item will not be added. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_created_event.py deleted file mode 100644 index 6ae6f05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_created_event.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemCreatedEvent"] - - -class ConversationItemCreatedEvent(BaseModel): - """Returned when a conversation item is created. - - There are several scenarios that produce this event: - - The server is generating a Response, which if successful will produce - either one or two Items, which will be of type `message` - (role `assistant`) or type `function_call`. - - The input audio buffer has been committed, either by the client or the - server (in `server_vad` mode). The server will take the content of the - input audio buffer and add it to a new user message Item. - - The client has sent a `conversation.item.create` event to add a new Item - to the Conversation. - """ - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - type: Literal["conversation.item.created"] - """The event type, must be `conversation.item.created`.""" - - previous_item_id: Optional[str] = None - """ - The ID of the preceding item in the Conversation context, allows the client to - understand the order of the conversation. Can be `null` if the item has no - predecessor. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event.py deleted file mode 100644 index c662f38..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemDeleteEvent"] - - -class ConversationItemDeleteEvent(BaseModel): - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - - item_id: str - """The ID of the item to delete.""" - - type: Literal["conversation.item.delete"] - """The event type, must be `conversation.item.delete`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event_param.py deleted file mode 100644 index e79bb68..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_delete_event_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemDeleteEventParam"] - - -class ConversationItemDeleteEventParam(TypedDict, total=False): - """Send this event when you want to remove any item from the conversation - history. - - The server will respond with a `conversation.item.deleted` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - - item_id: Required[str] - """The ID of the item to delete.""" - - type: Required[Literal["conversation.item.delete"]] - """The event type, must be `conversation.item.delete`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_deleted_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_deleted_event.py deleted file mode 100644 index 9826289..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_deleted_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemDeletedEvent"] - - -class ConversationItemDeletedEvent(BaseModel): - """ - Returned when an item in the conversation is deleted by the client with a - `conversation.item.delete` event. This event is used to synchronize the - server's understanding of the conversation history with the client's view. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item that was deleted.""" - - type: Literal["conversation.item.deleted"] - """The event type, must be `conversation.item.deleted`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_done.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_done.py deleted file mode 100644 index 6a823c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_done.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ConversationItemDone"] - - -class ConversationItemDone(BaseModel): - """Returned when a conversation item is finalized. - - The event will include the full content of the Item except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if needed. - """ - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - type: Literal["conversation.item.done"] - """The event type, must be `conversation.item.done`.""" - - previous_item_id: Optional[str] = None - """The ID of the item that precedes this one, if any. - - This is used to maintain ordering when items are inserted. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py deleted file mode 100644 index 3304233..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_completed_event.py +++ /dev/null @@ -1,98 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .log_prob_properties import LogProbProperties - -__all__ = [ - "ConversationItemInputAudioTranscriptionCompletedEvent", - "Usage", - "UsageTranscriptTextUsageTokens", - "UsageTranscriptTextUsageTokensInputTokenDetails", - "UsageTranscriptTextUsageDuration", -] - - -class UsageTranscriptTextUsageTokensInputTokenDetails(BaseModel): - """Details about the input tokens billed for this request.""" - - audio_tokens: Optional[int] = None - """Number of audio tokens billed for this request.""" - - text_tokens: Optional[int] = None - """Number of text tokens billed for this request.""" - - -class UsageTranscriptTextUsageTokens(BaseModel): - """Usage statistics for models billed by token usage.""" - - input_tokens: int - """Number of input tokens billed for this request.""" - - output_tokens: int - """Number of output tokens generated.""" - - total_tokens: int - """Total number of tokens used (input + output).""" - - type: Literal["tokens"] - """The type of the usage object. Always `tokens` for this variant.""" - - input_token_details: Optional[UsageTranscriptTextUsageTokensInputTokenDetails] = None - """Details about the input tokens billed for this request.""" - - -class UsageTranscriptTextUsageDuration(BaseModel): - """Usage statistics for models billed by audio input duration.""" - - seconds: float - """Duration of the input audio in seconds.""" - - type: Literal["duration"] - """The type of the usage object. Always `duration` for this variant.""" - - -Usage: TypeAlias = Union[UsageTranscriptTextUsageTokens, UsageTranscriptTextUsageDuration] - - -class ConversationItemInputAudioTranscriptionCompletedEvent(BaseModel): - """ - This event is the output of audio transcription for user audio written to the - user audio buffer. Transcription begins when the input audio buffer is - committed by the client or server (when VAD is enabled). Transcription runs - asynchronously with Response creation, so this event may come before or after - the Response events. - - Realtime API models accept audio natively, and thus input transcription is a - separate process run on a separate ASR (Automatic Speech Recognition) model. - The transcript may diverge somewhat from the model's interpretation, and - should be treated as a rough guide. - """ - - content_index: int - """The index of the content part containing the audio.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item containing the audio that is being transcribed.""" - - transcript: str - """The transcribed text.""" - - type: Literal["conversation.item.input_audio_transcription.completed"] - """ - The event type, must be `conversation.item.input_audio_transcription.completed`. - """ - - usage: Usage - """ - Usage statistics for the transcription, this is billed according to the ASR - model's pricing rather than the realtime model's pricing. - """ - - logprobs: Optional[List[LogProbProperties]] = None - """The log probabilities of the transcription.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py deleted file mode 100644 index 5f3f548..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .log_prob_properties import LogProbProperties - -__all__ = ["ConversationItemInputAudioTranscriptionDeltaEvent"] - - -class ConversationItemInputAudioTranscriptionDeltaEvent(BaseModel): - """ - Returned when the text value of an input audio transcription content part is updated with incremental transcription results. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item containing the audio that is being transcribed.""" - - type: Literal["conversation.item.input_audio_transcription.delta"] - """The event type, must be `conversation.item.input_audio_transcription.delta`.""" - - content_index: Optional[int] = None - """The index of the content part in the item's content array.""" - - delta: Optional[str] = None - """The text delta.""" - - logprobs: Optional[List[LogProbProperties]] = None - """The log probabilities of the transcription. - - These can be enabled by configurating the session with - `"include": ["item.input_audio_transcription.logprobs"]`. Each entry in the - array corresponds a log probability of which token would be selected for this - chunk of transcription. This can help to identify if it was possible there were - multiple valid options for a given chunk of transcription. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py deleted file mode 100644 index e8ad05e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_failed_event.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemInputAudioTranscriptionFailedEvent", "Error"] - - -class Error(BaseModel): - """Details of the transcription error.""" - - code: Optional[str] = None - """Error code, if any.""" - - message: Optional[str] = None - """A human-readable error message.""" - - param: Optional[str] = None - """Parameter related to the error, if any.""" - - type: Optional[str] = None - """The type of error.""" - - -class ConversationItemInputAudioTranscriptionFailedEvent(BaseModel): - """ - Returned when input audio transcription is configured, and a transcription - request for a user message failed. These events are separate from other - `error` events so that the client can identify the related Item. - """ - - content_index: int - """The index of the content part containing the audio.""" - - error: Error - """Details of the transcription error.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item.""" - - type: Literal["conversation.item.input_audio_transcription.failed"] - """The event type, must be `conversation.item.input_audio_transcription.failed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_segment.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_segment.py deleted file mode 100644 index dcc4916..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_input_audio_transcription_segment.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemInputAudioTranscriptionSegment"] - - -class ConversationItemInputAudioTranscriptionSegment(BaseModel): - """Returned when an input audio transcription segment is identified for an item.""" - - id: str - """The segment identifier.""" - - content_index: int - """The index of the input audio content part within the item.""" - - end: float - """End time of the segment in seconds.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item containing the input audio content.""" - - speaker: str - """The detected speaker label for this segment.""" - - start: float - """Start time of the segment in seconds.""" - - text: str - """The text for this segment.""" - - type: Literal["conversation.item.input_audio_transcription.segment"] - """The event type, must be `conversation.item.input_audio_transcription.segment`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_param.py deleted file mode 100644 index c8b442e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .realtime_mcp_tool_call_param import RealtimeMcpToolCallParam -from .realtime_mcp_list_tools_param import RealtimeMcpListToolsParam -from .realtime_mcp_approval_request_param import RealtimeMcpApprovalRequestParam -from .realtime_mcp_approval_response_param import RealtimeMcpApprovalResponseParam -from .realtime_conversation_item_user_message_param import RealtimeConversationItemUserMessageParam -from .realtime_conversation_item_function_call_param import RealtimeConversationItemFunctionCallParam -from .realtime_conversation_item_system_message_param import RealtimeConversationItemSystemMessageParam -from .realtime_conversation_item_assistant_message_param import RealtimeConversationItemAssistantMessageParam -from .realtime_conversation_item_function_call_output_param import RealtimeConversationItemFunctionCallOutputParam - -__all__ = ["ConversationItemParam"] - -ConversationItemParam: TypeAlias = Union[ - RealtimeConversationItemSystemMessageParam, - RealtimeConversationItemUserMessageParam, - RealtimeConversationItemAssistantMessageParam, - RealtimeConversationItemFunctionCallParam, - RealtimeConversationItemFunctionCallOutputParam, - RealtimeMcpApprovalResponseParam, - RealtimeMcpListToolsParam, - RealtimeMcpToolCallParam, - RealtimeMcpApprovalRequestParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event.py deleted file mode 100644 index e7d8eb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemRetrieveEvent"] - - -class ConversationItemRetrieveEvent(BaseModel): - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - - item_id: str - """The ID of the item to retrieve.""" - - type: Literal["conversation.item.retrieve"] - """The event type, must be `conversation.item.retrieve`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event_param.py deleted file mode 100644 index 59fdb6f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_retrieve_event_param.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemRetrieveEventParam"] - - -class ConversationItemRetrieveEventParam(TypedDict, total=False): - """ - Send this event when you want to retrieve the server's representation of a specific item in the conversation history. This is useful, for example, to inspect user audio after noise cancellation and VAD. - The server will respond with a `conversation.item.retrieved` event, - unless the item does not exist in the conversation history, in which case the - server will respond with an error. - """ - - item_id: Required[str] - """The ID of the item to retrieve.""" - - type: Required[Literal["conversation.item.retrieve"]] - """The event type, must be `conversation.item.retrieve`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event.py deleted file mode 100644 index 16c8218..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemTruncateEvent"] - - -class ConversationItemTruncateEvent(BaseModel): - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - - audio_end_ms: int - """Inclusive duration up to which audio is truncated, in milliseconds. - - If the audio_end_ms is greater than the actual audio duration, the server will - respond with an error. - """ - - content_index: int - """The index of the content part to truncate. Set this to `0`.""" - - item_id: str - """The ID of the assistant message item to truncate. - - Only assistant message items can be truncated. - """ - - type: Literal["conversation.item.truncate"] - """The event type, must be `conversation.item.truncate`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event_param.py deleted file mode 100644 index e9b41fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncate_event_param.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ConversationItemTruncateEventParam"] - - -class ConversationItemTruncateEventParam(TypedDict, total=False): - """Send this event to truncate a previous assistant message’s audio. - - The server - will produce audio faster than realtime, so this event is useful when the user - interrupts to truncate audio that has already been sent to the client but not - yet played. This will synchronize the server's understanding of the audio with - the client's playback. - - Truncating audio will delete the server-side text transcript to ensure there - is not text in the context that hasn't been heard by the user. - - If successful, the server will respond with a `conversation.item.truncated` - event. - """ - - audio_end_ms: Required[int] - """Inclusive duration up to which audio is truncated, in milliseconds. - - If the audio_end_ms is greater than the actual audio duration, the server will - respond with an error. - """ - - content_index: Required[int] - """The index of the content part to truncate. Set this to `0`.""" - - item_id: Required[str] - """The ID of the assistant message item to truncate. - - Only assistant message items can be truncated. - """ - - type: Required[Literal["conversation.item.truncate"]] - """The event type, must be `conversation.item.truncate`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncated_event.py deleted file mode 100644 index c78a776..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/conversation_item_truncated_event.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ConversationItemTruncatedEvent"] - - -class ConversationItemTruncatedEvent(BaseModel): - """ - Returned when an earlier assistant audio message item is truncated by the - client with a `conversation.item.truncate` event. This event is used to - synchronize the server's understanding of the audio with the client's playback. - - This action will truncate the audio and remove the server-side text transcript - to ensure there is no text in the context that hasn't been heard by the user. - """ - - audio_end_ms: int - """The duration up to which the audio was truncated, in milliseconds.""" - - content_index: int - """The index of the content part that was truncated.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the assistant message item that was truncated.""" - - type: Literal["conversation.item.truncated"] - """The event type, must be `conversation.item.truncated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event.py deleted file mode 100644 index 4c9e9a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferAppendEvent"] - - -class InputAudioBufferAppendEvent(BaseModel): - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. A "commit" will create a new - user message item in the conversation history from the buffer content and clear the buffer. - Input audio transcription (if enabled) will be generated when the buffer is committed. - - If VAD is enabled the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. Input audio noise reduction operates on writes to the audio buffer. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike most other client events, the server will - not send a confirmation response to this event. - """ - - audio: str - """Base64-encoded audio bytes. - - This must be in the format specified by the `input_audio_format` field in the - session configuration. - """ - - type: Literal["input_audio_buffer.append"] - """The event type, must be `input_audio_buffer.append`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event_param.py deleted file mode 100644 index a0d308e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_append_event_param.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferAppendEventParam"] - - -class InputAudioBufferAppendEventParam(TypedDict, total=False): - """Send this event to append audio bytes to the input audio buffer. - - The audio - buffer is temporary storage you can write to and later commit. A "commit" will create a new - user message item in the conversation history from the buffer content and clear the buffer. - Input audio transcription (if enabled) will be generated when the buffer is committed. - - If VAD is enabled the audio buffer is used to detect speech and the server will decide - when to commit. When Server VAD is disabled, you must commit the audio buffer - manually. Input audio noise reduction operates on writes to the audio buffer. - - The client may choose how much audio to place in each event up to a maximum - of 15 MiB, for example streaming smaller chunks from the client may allow the - VAD to be more responsive. Unlike most other client events, the server will - not send a confirmation response to this event. - """ - - audio: Required[str] - """Base64-encoded audio bytes. - - This must be in the format specified by the `input_audio_format` field in the - session configuration. - """ - - type: Required[Literal["input_audio_buffer.append"]] - """The event type, must be `input_audio_buffer.append`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event.py deleted file mode 100644 index 5526bcb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferClearEvent"] - - -class InputAudioBufferClearEvent(BaseModel): - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - - type: Literal["input_audio_buffer.clear"] - """The event type, must be `input_audio_buffer.clear`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event_param.py deleted file mode 100644 index 8e0e9c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_clear_event_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferClearEventParam"] - - -class InputAudioBufferClearEventParam(TypedDict, total=False): - """Send this event to clear the audio bytes in the buffer. - - The server will - respond with an `input_audio_buffer.cleared` event. - """ - - type: Required[Literal["input_audio_buffer.clear"]] - """The event type, must be `input_audio_buffer.clear`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_cleared_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_cleared_event.py deleted file mode 100644 index e477556..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_cleared_event.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferClearedEvent"] - - -class InputAudioBufferClearedEvent(BaseModel): - """ - Returned when the input audio buffer is cleared by the client with a - `input_audio_buffer.clear` event. - """ - - event_id: str - """The unique ID of the server event.""" - - type: Literal["input_audio_buffer.cleared"] - """The event type, must be `input_audio_buffer.cleared`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event.py deleted file mode 100644 index fe2ec01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferCommitEvent"] - - -class InputAudioBufferCommitEvent(BaseModel): - """ - Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - - Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. - """ - - type: Literal["input_audio_buffer.commit"] - """The event type, must be `input_audio_buffer.commit`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event_param.py deleted file mode 100644 index 2034279..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_commit_event_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InputAudioBufferCommitEventParam"] - - -class InputAudioBufferCommitEventParam(TypedDict, total=False): - """ - Send this event to commit the user input audio buffer, which will create a new user message item in the conversation. This event will produce an error if the input audio buffer is empty. When in Server VAD mode, the client does not need to send this event, the server will commit the audio buffer automatically. - - Committing the input audio buffer will trigger input audio transcription (if enabled in session configuration), but it will not create a response from the model. The server will respond with an `input_audio_buffer.committed` event. - """ - - type: Required[Literal["input_audio_buffer.commit"]] - """The event type, must be `input_audio_buffer.commit`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_committed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_committed_event.py deleted file mode 100644 index 15dc825..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_committed_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferCommittedEvent"] - - -class InputAudioBufferCommittedEvent(BaseModel): - """ - Returned when an input audio buffer is committed, either by the client or - automatically in server VAD mode. The `item_id` property is the ID of the user - message item that will be created, thus a `conversation.item.created` event - will also be sent to the client. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created.""" - - type: Literal["input_audio_buffer.committed"] - """The event type, must be `input_audio_buffer.committed`.""" - - previous_item_id: Optional[str] = None - """ - The ID of the preceding item after which the new item will be inserted. Can be - `null` if the item has no predecessor. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py deleted file mode 100644 index c2623cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_dtmf_event_received_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferDtmfEventReceivedEvent"] - - -class InputAudioBufferDtmfEventReceivedEvent(BaseModel): - """**SIP Only:** Returned when an DTMF event is received. - - A DTMF event is a message that - represents a telephone keypad press (0–9, *, #, A–D). The `event` property - is the keypad that the user press. The `received_at` is the UTC Unix Timestamp - that the server received the event. - """ - - event: str - """The telephone keypad that was pressed by the user.""" - - received_at: int - """UTC Unix Timestamp when DTMF Event was received by server.""" - - type: Literal["input_audio_buffer.dtmf_event_received"] - """The event type, must be `input_audio_buffer.dtmf_event_received`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_started_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_started_event.py deleted file mode 100644 index 1bd4c74..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_started_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferSpeechStartedEvent"] - - -class InputAudioBufferSpeechStartedEvent(BaseModel): - """ - Sent by the server when in `server_vad` mode to indicate that speech has been - detected in the audio buffer. This can happen any time audio is added to the - buffer (unless speech is already detected). The client may want to use this - event to interrupt audio playback or provide visual feedback to the user. - - The client should expect to receive a `input_audio_buffer.speech_stopped` event - when speech stops. The `item_id` property is the ID of the user message item - that will be created when speech stops and will also be included in the - `input_audio_buffer.speech_stopped` event (unless the client manually commits - the audio buffer during VAD activation). - """ - - audio_start_ms: int - """ - Milliseconds from the start of all audio written to the buffer during the - session when speech was first detected. This will correspond to the beginning of - audio sent to the model, and thus includes the `prefix_padding_ms` configured in - the Session. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created when speech stops.""" - - type: Literal["input_audio_buffer.speech_started"] - """The event type, must be `input_audio_buffer.speech_started`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_stopped_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_stopped_event.py deleted file mode 100644 index b3fb209..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_speech_stopped_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferSpeechStoppedEvent"] - - -class InputAudioBufferSpeechStoppedEvent(BaseModel): - """ - Returned in `server_vad` mode when the server detects the end of speech in - the audio buffer. The server will also send an `conversation.item.created` - event with the user message item that is created from the audio buffer. - """ - - audio_end_ms: int - """Milliseconds since the session started when speech stopped. - - This will correspond to the end of audio sent to the model, and thus includes - the `min_silence_duration_ms` configured in the Session. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the user message item that will be created.""" - - type: Literal["input_audio_buffer.speech_stopped"] - """The event type, must be `input_audio_buffer.speech_stopped`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_timeout_triggered.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_timeout_triggered.py deleted file mode 100644 index 72b107d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/input_audio_buffer_timeout_triggered.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputAudioBufferTimeoutTriggered"] - - -class InputAudioBufferTimeoutTriggered(BaseModel): - """Returned when the Server VAD timeout is triggered for the input audio buffer. - - This is configured - with `idle_timeout_ms` in the `turn_detection` settings of the session, and it indicates that - there hasn't been any speech detected for the configured duration. - - The `audio_start_ms` and `audio_end_ms` fields indicate the segment of audio after the last - model response up to the triggering time, as an offset from the beginning of audio written - to the input audio buffer. This means it demarcates the segment of audio that was silent and - the difference between the start and end values will roughly match the configured timeout. - - The empty audio will be committed to the conversation as an `input_audio` item (there will be a - `input_audio_buffer.committed` event) and a model response will be generated. There may be speech - that didn't trigger VAD but is still detected by the model, so the model may respond with - something relevant to the conversation or a prompt to continue speaking. - """ - - audio_end_ms: int - """ - Millisecond offset of audio written to the input audio buffer at the time the - timeout was triggered. - """ - - audio_start_ms: int - """ - Millisecond offset of audio written to the input audio buffer that was after the - playback time of the last model response. - """ - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item associated with this segment.""" - - type: Literal["input_audio_buffer.timeout_triggered"] - """The event type, must be `input_audio_buffer.timeout_triggered`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/log_prob_properties.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/log_prob_properties.py deleted file mode 100644 index 423af1c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/log_prob_properties.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["LogProbProperties"] - - -class LogProbProperties(BaseModel): - """A log probability object.""" - - token: str - """The token that was used to generate the log probability.""" - - bytes: List[int] - """The bytes that were used to generate the log probability.""" - - logprob: float - """The log probability of the token.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_completed.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_completed.py deleted file mode 100644 index 2fe6414..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_completed.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["McpListToolsCompleted"] - - -class McpListToolsCompleted(BaseModel): - """Returned when listing MCP tools has completed for an item.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP list tools item.""" - - type: Literal["mcp_list_tools.completed"] - """The event type, must be `mcp_list_tools.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_failed.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_failed.py deleted file mode 100644 index 8cad7c0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_failed.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["McpListToolsFailed"] - - -class McpListToolsFailed(BaseModel): - """Returned when listing MCP tools has failed for an item.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP list tools item.""" - - type: Literal["mcp_list_tools.failed"] - """The event type, must be `mcp_list_tools.failed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_in_progress.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_in_progress.py deleted file mode 100644 index 823bb87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/mcp_list_tools_in_progress.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["McpListToolsInProgress"] - - -class McpListToolsInProgress(BaseModel): - """Returned when listing MCP tools is in progress for an item.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP list tools item.""" - - type: Literal["mcp_list_tools.in_progress"] - """The event type, must be `mcp_list_tools.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/noise_reduction_type.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/noise_reduction_type.py deleted file mode 100644 index f433899..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/noise_reduction_type.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["NoiseReductionType"] - -NoiseReductionType: TypeAlias = Literal["near_field", "far_field"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event.py deleted file mode 100644 index b3fa762..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["OutputAudioBufferClearEvent"] - - -class OutputAudioBufferClearEvent(BaseModel): - """**WebRTC/SIP Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - - type: Literal["output_audio_buffer.clear"] - """The event type, must be `output_audio_buffer.clear`.""" - - event_id: Optional[str] = None - """The unique ID of the client event used for error handling.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event_param.py deleted file mode 100644 index 59f897a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/output_audio_buffer_clear_event_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["OutputAudioBufferClearEventParam"] - - -class OutputAudioBufferClearEventParam(TypedDict, total=False): - """**WebRTC/SIP Only:** Emit to cut off the current audio response. - - This will trigger the server to - stop generating audio and emit a `output_audio_buffer.cleared` event. This - event should be preceded by a `response.cancel` client event to stop the - generation of the current response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - - type: Required[Literal["output_audio_buffer.clear"]] - """The event type, must be `output_audio_buffer.clear`.""" - - event_id: str - """The unique ID of the client event used for error handling.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/rate_limits_updated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/rate_limits_updated_event.py deleted file mode 100644 index 951de10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/rate_limits_updated_event.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RateLimitsUpdatedEvent", "RateLimit"] - - -class RateLimit(BaseModel): - limit: Optional[int] = None - """The maximum allowed value for the rate limit.""" - - name: Optional[Literal["requests", "tokens"]] = None - """The name of the rate limit (`requests`, `tokens`).""" - - remaining: Optional[int] = None - """The remaining value before the limit is reached.""" - - reset_seconds: Optional[float] = None - """Seconds until the rate limit resets.""" - - -class RateLimitsUpdatedEvent(BaseModel): - """Emitted at the beginning of a Response to indicate the updated rate limits. - - - When a Response is created some tokens will be "reserved" for the output - tokens, the rate limits shown here reflect that reservation, which is then - adjusted accordingly once the Response is completed. - """ - - event_id: str - """The unique ID of the server event.""" - - rate_limits: List[RateLimit] - """List of rate limit information.""" - - type: Literal["rate_limits.updated"] - """The event type, must be `rate_limits.updated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config.py deleted file mode 100644 index daa5035..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .realtime_audio_config_input import RealtimeAudioConfigInput -from .realtime_audio_config_output import RealtimeAudioConfigOutput - -__all__ = ["RealtimeAudioConfig"] - - -class RealtimeAudioConfig(BaseModel): - """Configuration for input and output audio.""" - - input: Optional[RealtimeAudioConfigInput] = None - - output: Optional[RealtimeAudioConfigOutput] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input.py deleted file mode 100644 index 08e1b14..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input.py +++ /dev/null @@ -1,70 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .audio_transcription import AudioTranscription -from .noise_reduction_type import NoiseReductionType -from .realtime_audio_formats import RealtimeAudioFormats -from .realtime_audio_input_turn_detection import RealtimeAudioInputTurnDetection - -__all__ = ["RealtimeAudioConfigInput", "NoiseReduction"] - - -class NoiseReduction(BaseModel): - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. - Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. - Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. - """ - - type: Optional[NoiseReductionType] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class RealtimeAudioConfigInput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the input audio.""" - - noise_reduction: Optional[NoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: Optional[AudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[RealtimeAudioInputTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. - - Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input_param.py deleted file mode 100644 index 73495e6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_input_param.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -from .noise_reduction_type import NoiseReductionType -from .audio_transcription_param import AudioTranscriptionParam -from .realtime_audio_formats_param import RealtimeAudioFormatsParam -from .realtime_audio_input_turn_detection_param import RealtimeAudioInputTurnDetectionParam - -__all__ = ["RealtimeAudioConfigInputParam", "NoiseReduction"] - - -class NoiseReduction(TypedDict, total=False): - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. - Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. - Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. - """ - - type: NoiseReductionType - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class RealtimeAudioConfigInputParam(TypedDict, total=False): - format: RealtimeAudioFormatsParam - """The format of the input audio.""" - - noise_reduction: NoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: AudioTranscriptionParam - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[RealtimeAudioInputTurnDetectionParam] - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. - - Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output.py deleted file mode 100644 index 2922405..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_audio_formats import RealtimeAudioFormats - -__all__ = ["RealtimeAudioConfigOutput"] - - -class RealtimeAudioConfigOutput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the output audio.""" - - speed: Optional[float] = None - """ - The speed of the model's spoken response as a multiple of the original speed. - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - - This parameter is a post-processing adjustment to the audio after it is - generated, it's also possible to prompt the model to speak faster or slower. - """ - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. We recommend - `marin` and `cedar` for best quality. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output_param.py deleted file mode 100644 index d04fd3a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_output_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -from .realtime_audio_formats_param import RealtimeAudioFormatsParam - -__all__ = ["RealtimeAudioConfigOutputParam"] - - -class RealtimeAudioConfigOutputParam(TypedDict, total=False): - format: RealtimeAudioFormatsParam - """The format of the output audio.""" - - speed: float - """ - The speed of the model's spoken response as a multiple of the original speed. - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - - This parameter is a post-processing adjustment to the audio after it is - generated, it's also possible to prompt the model to speak faster or slower. - """ - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - """The voice the model uses to respond. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. We recommend - `marin` and `cedar` for best quality. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_param.py deleted file mode 100644 index 7899fe3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_config_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .realtime_audio_config_input_param import RealtimeAudioConfigInputParam -from .realtime_audio_config_output_param import RealtimeAudioConfigOutputParam - -__all__ = ["RealtimeAudioConfigParam"] - - -class RealtimeAudioConfigParam(TypedDict, total=False): - """Configuration for input and output audio.""" - - input: RealtimeAudioConfigInputParam - - output: RealtimeAudioConfigOutputParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats.py deleted file mode 100644 index fa10c9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["RealtimeAudioFormats", "AudioPCM", "AudioPCMU", "AudioPCMA"] - - -class AudioPCM(BaseModel): - """The PCM audio format. Only a 24kHz sample rate is supported.""" - - rate: Optional[Literal[24000]] = None - """The sample rate of the audio. Always `24000`.""" - - type: Optional[Literal["audio/pcm"]] = None - """The audio format. Always `audio/pcm`.""" - - -class AudioPCMU(BaseModel): - """The G.711 μ-law format.""" - - type: Optional[Literal["audio/pcmu"]] = None - """The audio format. Always `audio/pcmu`.""" - - -class AudioPCMA(BaseModel): - """The G.711 A-law format.""" - - type: Optional[Literal["audio/pcma"]] = None - """The audio format. Always `audio/pcma`.""" - - -RealtimeAudioFormats: TypeAlias = Annotated[Union[AudioPCM, AudioPCMU, AudioPCMA], PropertyInfo(discriminator="type")] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats_param.py deleted file mode 100644 index 6392f63..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_formats_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias, TypedDict - -__all__ = ["RealtimeAudioFormatsParam", "AudioPCM", "AudioPCMU", "AudioPCMA"] - - -class AudioPCM(TypedDict, total=False): - """The PCM audio format. Only a 24kHz sample rate is supported.""" - - rate: Literal[24000] - """The sample rate of the audio. Always `24000`.""" - - type: Literal["audio/pcm"] - """The audio format. Always `audio/pcm`.""" - - -class AudioPCMU(TypedDict, total=False): - """The G.711 μ-law format.""" - - type: Literal["audio/pcmu"] - """The audio format. Always `audio/pcmu`.""" - - -class AudioPCMA(TypedDict, total=False): - """The G.711 A-law format.""" - - type: Literal["audio/pcma"] - """The audio format. Always `audio/pcma`.""" - - -RealtimeAudioFormatsParam: TypeAlias = Union[AudioPCM, AudioPCMU, AudioPCMA] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection.py deleted file mode 100644 index 8d9aff3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection.py +++ /dev/null @@ -1,115 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["RealtimeAudioInputTurnDetection", "ServerVad", "SemanticVad"] - - -class ServerVad(BaseModel): - """ - Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. - """ - - type: Literal["server_vad"] - """Type of turn detection, `server_vad` to turn on simple Server VAD.""" - - create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - If `interrupt_response` is set to `false` this may fail to create a response if - the model is already responding. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - idle_timeout_ms: Optional[int] = None - """Optional timeout after which a model response will be triggered automatically. - - This is useful for situations in which a long pause from the user is unexpected, - such as a phone call. The model will effectively prompt the user to continue the - conversation based on the current context. - - The timeout value will be applied after the last model response's audio has - finished playing, i.e. it's set to the `response.done` time plus audio playback - duration. - - An `input_audio_buffer.timeout_triggered` event (plus events associated with the - Response) will be emitted when the timeout is reached. Idle timeout is currently - only supported for `server_vad` mode. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt (cancel) any ongoing response with - output to the default conversation (i.e. `conversation` of `auto`) when a VAD - start event occurs. If `true` then the response will be cancelled, otherwise it - will continue until complete. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - -class SemanticVad(BaseModel): - """ - Server-side semantic turn detection which uses a model to determine when the user has finished speaking. - """ - - type: Literal["semantic_vad"] - """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" - - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - -RealtimeAudioInputTurnDetection: TypeAlias = Annotated[ - Union[ServerVad, SemanticVad, None], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection_param.py deleted file mode 100644 index 30522d7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_audio_input_turn_detection_param.py +++ /dev/null @@ -1,112 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["RealtimeAudioInputTurnDetectionParam", "ServerVad", "SemanticVad"] - - -class ServerVad(TypedDict, total=False): - """ - Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. - """ - - type: Required[Literal["server_vad"]] - """Type of turn detection, `server_vad` to turn on simple Server VAD.""" - - create_response: bool - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - If `interrupt_response` is set to `false` this may fail to create a response if - the model is already responding. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - idle_timeout_ms: Optional[int] - """Optional timeout after which a model response will be triggered automatically. - - This is useful for situations in which a long pause from the user is unexpected, - such as a phone call. The model will effectively prompt the user to continue the - conversation based on the current context. - - The timeout value will be applied after the last model response's audio has - finished playing, i.e. it's set to the `response.done` time plus audio playback - duration. - - An `input_audio_buffer.timeout_triggered` event (plus events associated with the - Response) will be emitted when the timeout is reached. Idle timeout is currently - only supported for `server_vad` mode. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt (cancel) any ongoing response with - output to the default conversation (i.e. `conversation` of `auto`) when a VAD - start event occurs. If `true` then the response will be cancelled, otherwise it - will continue until complete. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - -class SemanticVad(TypedDict, total=False): - """ - Server-side semantic turn detection which uses a model to determine when the user has finished speaking. - """ - - type: Required[Literal["semantic_vad"]] - """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" - - create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - -RealtimeAudioInputTurnDetectionParam: TypeAlias = Union[ServerVad, SemanticVad] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event.py deleted file mode 100644 index 3b1c348..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .session_update_event import SessionUpdateEvent -from .response_cancel_event import ResponseCancelEvent -from .response_create_event import ResponseCreateEvent -from .conversation_item_create_event import ConversationItemCreateEvent -from .conversation_item_delete_event import ConversationItemDeleteEvent -from .input_audio_buffer_clear_event import InputAudioBufferClearEvent -from .input_audio_buffer_append_event import InputAudioBufferAppendEvent -from .input_audio_buffer_commit_event import InputAudioBufferCommitEvent -from .output_audio_buffer_clear_event import OutputAudioBufferClearEvent -from .conversation_item_retrieve_event import ConversationItemRetrieveEvent -from .conversation_item_truncate_event import ConversationItemTruncateEvent - -__all__ = ["RealtimeClientEvent"] - -RealtimeClientEvent: TypeAlias = Annotated[ - Union[ - ConversationItemCreateEvent, - ConversationItemDeleteEvent, - ConversationItemRetrieveEvent, - ConversationItemTruncateEvent, - InputAudioBufferAppendEvent, - InputAudioBufferClearEvent, - OutputAudioBufferClearEvent, - InputAudioBufferCommitEvent, - ResponseCancelEvent, - ResponseCreateEvent, - SessionUpdateEvent, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event_param.py deleted file mode 100644 index cda5766..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_client_event_param.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .session_update_event_param import SessionUpdateEventParam -from .response_cancel_event_param import ResponseCancelEventParam -from .response_create_event_param import ResponseCreateEventParam -from .conversation_item_create_event_param import ConversationItemCreateEventParam -from .conversation_item_delete_event_param import ConversationItemDeleteEventParam -from .input_audio_buffer_clear_event_param import InputAudioBufferClearEventParam -from .input_audio_buffer_append_event_param import InputAudioBufferAppendEventParam -from .input_audio_buffer_commit_event_param import InputAudioBufferCommitEventParam -from .output_audio_buffer_clear_event_param import OutputAudioBufferClearEventParam -from .conversation_item_retrieve_event_param import ConversationItemRetrieveEventParam -from .conversation_item_truncate_event_param import ConversationItemTruncateEventParam - -__all__ = ["RealtimeClientEventParam"] - -RealtimeClientEventParam: TypeAlias = Union[ - ConversationItemCreateEventParam, - ConversationItemDeleteEventParam, - ConversationItemRetrieveEventParam, - ConversationItemTruncateEventParam, - InputAudioBufferAppendEventParam, - InputAudioBufferClearEventParam, - OutputAudioBufferClearEventParam, - InputAudioBufferCommitEventParam, - ResponseCancelEventParam, - ResponseCreateEventParam, - SessionUpdateEventParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_connect_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_connect_params.py deleted file mode 100644 index 950f362..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_connect_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["RealtimeConnectParams"] - - -class RealtimeConnectParams(TypedDict, total=False): - call_id: str - - model: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message.py deleted file mode 100644 index 207831a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeConversationItemAssistantMessage", "Content"] - - -class Content(BaseModel): - audio: Optional[str] = None - """ - Base64-encoded audio bytes, these will be parsed as the format specified in the - session output audio type configuration. This defaults to PCM 16-bit 24kHz mono - if not specified. - """ - - text: Optional[str] = None - """The text content.""" - - transcript: Optional[str] = None - """ - The transcript of the audio content, this will always be present if the output - type is `audio`. - """ - - type: Optional[Literal["output_text", "output_audio"]] = None - """ - The content type, `output_text` or `output_audio` depending on the session - `output_modalities` configuration. - """ - - -class RealtimeConversationItemAssistantMessage(BaseModel): - """An assistant message item in a Realtime conversation.""" - - content: List[Content] - """The content of the message.""" - - role: Literal["assistant"] - """The role of the message sender. Always `assistant`.""" - - type: Literal["message"] - """The type of the item. Always `message`.""" - - id: Optional[str] = None - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message_param.py deleted file mode 100644 index abc78e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_assistant_message_param.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeConversationItemAssistantMessageParam", "Content"] - - -class Content(TypedDict, total=False): - audio: str - """ - Base64-encoded audio bytes, these will be parsed as the format specified in the - session output audio type configuration. This defaults to PCM 16-bit 24kHz mono - if not specified. - """ - - text: str - """The text content.""" - - transcript: str - """ - The transcript of the audio content, this will always be present if the output - type is `audio`. - """ - - type: Literal["output_text", "output_audio"] - """ - The content type, `output_text` or `output_audio` depending on the session - `output_modalities` configuration. - """ - - -class RealtimeConversationItemAssistantMessageParam(TypedDict, total=False): - """An assistant message item in a Realtime conversation.""" - - content: Required[Iterable[Content]] - """The content of the message.""" - - role: Required[Literal["assistant"]] - """The role of the message sender. Always `assistant`.""" - - type: Required[Literal["message"]] - """The type of the item. Always `message`.""" - - id: str - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call.py deleted file mode 100644 index 4e40394..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeConversationItemFunctionCall"] - - -class RealtimeConversationItemFunctionCall(BaseModel): - """A function call item in a Realtime conversation.""" - - arguments: str - """The arguments of the function call. - - This is a JSON-encoded string representing the arguments passed to the function, - for example `{"arg1": "value1", "arg2": 42}`. - """ - - name: str - """The name of the function being called.""" - - type: Literal["function_call"] - """The type of the item. Always `function_call`.""" - - id: Optional[str] = None - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - call_id: Optional[str] = None - """The ID of the function call.""" - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output.py deleted file mode 100644 index cdbc352..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeConversationItemFunctionCallOutput"] - - -class RealtimeConversationItemFunctionCallOutput(BaseModel): - """A function call output item in a Realtime conversation.""" - - call_id: str - """The ID of the function call this output is for.""" - - output: str - """ - The output of the function call, this is free text and can contain any - information or simply be empty. - """ - - type: Literal["function_call_output"] - """The type of the item. Always `function_call_output`.""" - - id: Optional[str] = None - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output_param.py deleted file mode 100644 index 2e56a81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_output_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeConversationItemFunctionCallOutputParam"] - - -class RealtimeConversationItemFunctionCallOutputParam(TypedDict, total=False): - """A function call output item in a Realtime conversation.""" - - call_id: Required[str] - """The ID of the function call this output is for.""" - - output: Required[str] - """ - The output of the function call, this is free text and can contain any - information or simply be empty. - """ - - type: Required[Literal["function_call_output"]] - """The type of the item. Always `function_call_output`.""" - - id: str - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_param.py deleted file mode 100644 index 6467ce1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_function_call_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeConversationItemFunctionCallParam"] - - -class RealtimeConversationItemFunctionCallParam(TypedDict, total=False): - """A function call item in a Realtime conversation.""" - - arguments: Required[str] - """The arguments of the function call. - - This is a JSON-encoded string representing the arguments passed to the function, - for example `{"arg1": "value1", "arg2": 42}`. - """ - - name: Required[str] - """The name of the function being called.""" - - type: Required[Literal["function_call"]] - """The type of the item. Always `function_call`.""" - - id: str - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - call_id: str - """The ID of the function call.""" - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message.py deleted file mode 100644 index f69bc03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeConversationItemSystemMessage", "Content"] - - -class Content(BaseModel): - text: Optional[str] = None - """The text content.""" - - type: Optional[Literal["input_text"]] = None - """The content type. Always `input_text` for system messages.""" - - -class RealtimeConversationItemSystemMessage(BaseModel): - """ - A system message in a Realtime conversation can be used to provide additional context or instructions to the model. This is similar but distinct from the instruction prompt provided at the start of a conversation, as system messages can be added at any point in the conversation. For major changes to the conversation's behavior, use instructions, but for smaller updates (e.g. "the user is now asking about a different topic"), use system messages. - """ - - content: List[Content] - """The content of the message.""" - - role: Literal["system"] - """The role of the message sender. Always `system`.""" - - type: Literal["message"] - """The type of the item. Always `message`.""" - - id: Optional[str] = None - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message_param.py deleted file mode 100644 index 9388019..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_system_message_param.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeConversationItemSystemMessageParam", "Content"] - - -class Content(TypedDict, total=False): - text: str - """The text content.""" - - type: Literal["input_text"] - """The content type. Always `input_text` for system messages.""" - - -class RealtimeConversationItemSystemMessageParam(TypedDict, total=False): - """ - A system message in a Realtime conversation can be used to provide additional context or instructions to the model. This is similar but distinct from the instruction prompt provided at the start of a conversation, as system messages can be added at any point in the conversation. For major changes to the conversation's behavior, use instructions, but for smaller updates (e.g. "the user is now asking about a different topic"), use system messages. - """ - - content: Required[Iterable[Content]] - """The content of the message.""" - - role: Required[Literal["system"]] - """The role of the message sender. Always `system`.""" - - type: Required[Literal["message"]] - """The type of the item. Always `message`.""" - - id: str - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message.py deleted file mode 100644 index 20e9614..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message.py +++ /dev/null @@ -1,71 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeConversationItemUserMessage", "Content"] - - -class Content(BaseModel): - audio: Optional[str] = None - """ - Base64-encoded audio bytes (for `input_audio`), these will be parsed as the - format specified in the session input audio type configuration. This defaults to - PCM 16-bit 24kHz mono if not specified. - """ - - detail: Optional[Literal["auto", "low", "high"]] = None - """The detail level of the image (for `input_image`). - - `auto` will default to `high`. - """ - - image_url: Optional[str] = None - """Base64-encoded image bytes (for `input_image`) as a data URI. - - For example `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...`. Supported - formats are PNG and JPEG. - """ - - text: Optional[str] = None - """The text content (for `input_text`).""" - - transcript: Optional[str] = None - """Transcript of the audio (for `input_audio`). - - This is not sent to the model, but will be attached to the message item for - reference. - """ - - type: Optional[Literal["input_text", "input_audio", "input_image"]] = None - """The content type (`input_text`, `input_audio`, or `input_image`).""" - - -class RealtimeConversationItemUserMessage(BaseModel): - """A user message item in a Realtime conversation.""" - - content: List[Content] - """The content of the message.""" - - role: Literal["user"] - """The role of the message sender. Always `user`.""" - - type: Literal["message"] - """The type of the item. Always `message`.""" - - id: Optional[str] = None - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Optional[Literal["realtime.item"]] = None - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message_param.py deleted file mode 100644 index 69a2469..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_conversation_item_user_message_param.py +++ /dev/null @@ -1,71 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeConversationItemUserMessageParam", "Content"] - - -class Content(TypedDict, total=False): - audio: str - """ - Base64-encoded audio bytes (for `input_audio`), these will be parsed as the - format specified in the session input audio type configuration. This defaults to - PCM 16-bit 24kHz mono if not specified. - """ - - detail: Literal["auto", "low", "high"] - """The detail level of the image (for `input_image`). - - `auto` will default to `high`. - """ - - image_url: str - """Base64-encoded image bytes (for `input_image`) as a data URI. - - For example `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...`. Supported - formats are PNG and JPEG. - """ - - text: str - """The text content (for `input_text`).""" - - transcript: str - """Transcript of the audio (for `input_audio`). - - This is not sent to the model, but will be attached to the message item for - reference. - """ - - type: Literal["input_text", "input_audio", "input_image"] - """The content type (`input_text`, `input_audio`, or `input_image`).""" - - -class RealtimeConversationItemUserMessageParam(TypedDict, total=False): - """A user message item in a Realtime conversation.""" - - content: Required[Iterable[Content]] - """The content of the message.""" - - role: Required[Literal["user"]] - """The role of the message sender. Always `user`.""" - - type: Required[Literal["message"]] - """The type of the item. Always `message`.""" - - id: str - """The unique ID of the item. - - This may be provided by the client or generated by the server. - """ - - object: Literal["realtime.item"] - """Identifier for the API object being returned - always `realtime.item`. - - Optional when creating a new item. - """ - - status: Literal["completed", "incomplete", "in_progress"] - """The status of the item. Has no effect on the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error.py deleted file mode 100644 index 2aa5bc9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["RealtimeError"] - - -class RealtimeError(BaseModel): - """Details of the error.""" - - message: str - """A human-readable error message.""" - - type: str - """The type of error (e.g., "invalid_request_error", "server_error").""" - - code: Optional[str] = None - """Error code, if any.""" - - event_id: Optional[str] = None - """The event_id of the client event that caused the error, if applicable.""" - - param: Optional[str] = None - """Parameter related to the error, if any.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error_event.py deleted file mode 100644 index 574464b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_error_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_error import RealtimeError - -__all__ = ["RealtimeErrorEvent"] - - -class RealtimeErrorEvent(BaseModel): - """ - Returned when an error occurs, which could be a client problem or a server - problem. Most errors are recoverable and the session will stay open, we - recommend to implementors to monitor and log error messages by default. - """ - - error: RealtimeError - """Details of the error.""" - - event_id: str - """The unique ID of the server event.""" - - type: Literal["error"] - """The event type, must be `error`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool.py deleted file mode 100644 index 48dbf99..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeFunctionTool"] - - -class RealtimeFunctionTool(BaseModel): - description: Optional[str] = None - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """Parameters of the function in JSON Schema.""" - - type: Optional[Literal["function"]] = None - """The type of the tool, i.e. `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool_param.py deleted file mode 100644 index f42e3e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_function_tool_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["RealtimeFunctionToolParam"] - - -class RealtimeFunctionToolParam(TypedDict, total=False): - description: str - """ - The description of the function, including guidance on when and how to call it, - and guidance about what to tell the user when calling (if anything). - """ - - name: str - """The name of the function.""" - - parameters: object - """Parameters of the function in JSON Schema.""" - - type: Literal["function"] - """The type of the tool, i.e. `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request.py deleted file mode 100644 index 1744c90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcpApprovalRequest"] - - -class RealtimeMcpApprovalRequest(BaseModel): - """A Realtime item requesting human approval of a tool invocation.""" - - id: str - """The unique ID of the approval request.""" - - arguments: str - """A JSON string of arguments for the tool.""" - - name: str - """The name of the tool to run.""" - - server_label: str - """The label of the MCP server making the request.""" - - type: Literal["mcp_approval_request"] - """The type of the item. Always `mcp_approval_request`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request_param.py deleted file mode 100644 index f7cb68d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_request_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcpApprovalRequestParam"] - - -class RealtimeMcpApprovalRequestParam(TypedDict, total=False): - """A Realtime item requesting human approval of a tool invocation.""" - - id: Required[str] - """The unique ID of the approval request.""" - - arguments: Required[str] - """A JSON string of arguments for the tool.""" - - name: Required[str] - """The name of the tool to run.""" - - server_label: Required[str] - """The label of the MCP server making the request.""" - - type: Required[Literal["mcp_approval_request"]] - """The type of the item. Always `mcp_approval_request`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response.py deleted file mode 100644 index f8525a1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcpApprovalResponse"] - - -class RealtimeMcpApprovalResponse(BaseModel): - """A Realtime item responding to an MCP approval request.""" - - id: str - """The unique ID of the approval response.""" - - approval_request_id: str - """The ID of the approval request being answered.""" - - approve: bool - """Whether the request was approved.""" - - type: Literal["mcp_approval_response"] - """The type of the item. Always `mcp_approval_response`.""" - - reason: Optional[str] = None - """Optional reason for the decision.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response_param.py deleted file mode 100644 index 6a65f7c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_approval_response_param.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcpApprovalResponseParam"] - - -class RealtimeMcpApprovalResponseParam(TypedDict, total=False): - """A Realtime item responding to an MCP approval request.""" - - id: Required[str] - """The unique ID of the approval response.""" - - approval_request_id: Required[str] - """The ID of the approval request being answered.""" - - approve: Required[bool] - """Whether the request was approved.""" - - type: Required[Literal["mcp_approval_response"]] - """The type of the item. Always `mcp_approval_response`.""" - - reason: Optional[str] - """Optional reason for the decision.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools.py deleted file mode 100644 index 669d1fb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcpListTools", "Tool"] - - -class Tool(BaseModel): - """A tool available on an MCP server.""" - - input_schema: object - """The JSON schema describing the tool's input.""" - - name: str - """The name of the tool.""" - - annotations: Optional[object] = None - """Additional annotations about the tool.""" - - description: Optional[str] = None - """The description of the tool.""" - - -class RealtimeMcpListTools(BaseModel): - """A Realtime item listing tools available on an MCP server.""" - - server_label: str - """The label of the MCP server.""" - - tools: List[Tool] - """The tools available on the server.""" - - type: Literal["mcp_list_tools"] - """The type of the item. Always `mcp_list_tools`.""" - - id: Optional[str] = None - """The unique ID of the list.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools_param.py deleted file mode 100644 index 614fa53..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_list_tools_param.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcpListToolsParam", "Tool"] - - -class Tool(TypedDict, total=False): - """A tool available on an MCP server.""" - - input_schema: Required[object] - """The JSON schema describing the tool's input.""" - - name: Required[str] - """The name of the tool.""" - - annotations: Optional[object] - """Additional annotations about the tool.""" - - description: Optional[str] - """The description of the tool.""" - - -class RealtimeMcpListToolsParam(TypedDict, total=False): - """A Realtime item listing tools available on an MCP server.""" - - server_label: Required[str] - """The label of the MCP server.""" - - tools: Required[Iterable[Tool]] - """The tools available on the server.""" - - type: Required[Literal["mcp_list_tools"]] - """The type of the item. Always `mcp_list_tools`.""" - - id: str - """The unique ID of the list.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error.py deleted file mode 100644 index 2e7cfdf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcpProtocolError"] - - -class RealtimeMcpProtocolError(BaseModel): - code: int - - message: str - - type: Literal["protocol_error"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error_param.py deleted file mode 100644 index bebe3d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_protocol_error_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcpProtocolErrorParam"] - - -class RealtimeMcpProtocolErrorParam(TypedDict, total=False): - code: Required[int] - - message: Required[str] - - type: Required[Literal["protocol_error"]] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call.py deleted file mode 100644 index f53ad0e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .realtime_mcphttp_error import RealtimeMcphttpError -from .realtime_mcp_protocol_error import RealtimeMcpProtocolError -from .realtime_mcp_tool_execution_error import RealtimeMcpToolExecutionError - -__all__ = ["RealtimeMcpToolCall", "Error"] - -Error: TypeAlias = Annotated[ - Union[RealtimeMcpProtocolError, RealtimeMcpToolExecutionError, RealtimeMcphttpError, None], - PropertyInfo(discriminator="type"), -] - - -class RealtimeMcpToolCall(BaseModel): - """A Realtime item representing an invocation of a tool on an MCP server.""" - - id: str - """The unique ID of the tool call.""" - - arguments: str - """A JSON string of the arguments passed to the tool.""" - - name: str - """The name of the tool that was run.""" - - server_label: str - """The label of the MCP server running the tool.""" - - type: Literal["mcp_call"] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] = None - """The ID of an associated approval request, if any.""" - - error: Optional[Error] = None - """The error from the tool call, if any.""" - - output: Optional[str] = None - """The output from the tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call_param.py deleted file mode 100644 index 8ccb5ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_call_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .realtime_mcphttp_error_param import RealtimeMcphttpErrorParam -from .realtime_mcp_protocol_error_param import RealtimeMcpProtocolErrorParam -from .realtime_mcp_tool_execution_error_param import RealtimeMcpToolExecutionErrorParam - -__all__ = ["RealtimeMcpToolCallParam", "Error"] - -Error: TypeAlias = Union[RealtimeMcpProtocolErrorParam, RealtimeMcpToolExecutionErrorParam, RealtimeMcphttpErrorParam] - - -class RealtimeMcpToolCallParam(TypedDict, total=False): - """A Realtime item representing an invocation of a tool on an MCP server.""" - - id: Required[str] - """The unique ID of the tool call.""" - - arguments: Required[str] - """A JSON string of the arguments passed to the tool.""" - - name: Required[str] - """The name of the tool that was run.""" - - server_label: Required[str] - """The label of the MCP server running the tool.""" - - type: Required[Literal["mcp_call"]] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] - """The ID of an associated approval request, if any.""" - - error: Optional[Error] - """The error from the tool call, if any.""" - - output: Optional[str] - """The output from the tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error.py deleted file mode 100644 index a2ed063..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcpToolExecutionError"] - - -class RealtimeMcpToolExecutionError(BaseModel): - message: str - - type: Literal["tool_execution_error"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error_param.py deleted file mode 100644 index 619e11c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcp_tool_execution_error_param.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcpToolExecutionErrorParam"] - - -class RealtimeMcpToolExecutionErrorParam(TypedDict, total=False): - message: Required[str] - - type: Required[Literal["tool_execution_error"]] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error.py deleted file mode 100644 index 53cff91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeMcphttpError"] - - -class RealtimeMcphttpError(BaseModel): - code: int - - message: str - - type: Literal["http_error"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error_param.py deleted file mode 100644 index 2b80a6f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_mcphttp_error_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeMcphttpErrorParam"] - - -class RealtimeMcphttpErrorParam(TypedDict, total=False): - code: Required[int] - - message: Required[str] - - type: Required[Literal["http_error"]] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response.py deleted file mode 100644 index a23edc4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.metadata import Metadata -from .conversation_item import ConversationItem -from .realtime_audio_formats import RealtimeAudioFormats -from .realtime_response_usage import RealtimeResponseUsage -from .realtime_response_status import RealtimeResponseStatus - -__all__ = ["RealtimeResponse", "Audio", "AudioOutput"] - - -class AudioOutput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the output audio.""" - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend - `marin` and `cedar` for best quality. - """ - - -class Audio(BaseModel): - """Configuration for audio output.""" - - output: Optional[AudioOutput] = None - - -class RealtimeResponse(BaseModel): - """The response resource.""" - - id: Optional[str] = None - """The unique ID of the response, will look like `resp_1234`.""" - - audio: Optional[Audio] = None - """Configuration for audio output.""" - - conversation_id: Optional[str] = None - """ - Which conversation the response is added to, determined by the `conversation` - field in the `response.create` event. If `auto`, the response will be added to - the default conversation and the value of `conversation_id` will be an id like - `conv_1234`. If `none`, the response will not be added to any conversation and - the value of `conversation_id` will be `null`. If responses are being triggered - automatically by VAD the response will be added to the default conversation - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls, that was used in this response. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - object: Optional[Literal["realtime.response"]] = None - """The object type, must be `realtime.response`.""" - - output: Optional[List[ConversationItem]] = None - """The list of output items generated by the response.""" - - output_modalities: Optional[List[Literal["text", "audio"]]] = None - """ - The set of modalities the model used to respond, currently the only possible - values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text - transcript. Setting the output to mode `text` will disable audio output from the - model. - """ - - status: Optional[Literal["completed", "cancelled", "failed", "incomplete", "in_progress"]] = None - """ - The final status of the response (`completed`, `cancelled`, `failed`, or - `incomplete`, `in_progress`). - """ - - status_details: Optional[RealtimeResponseStatus] = None - """Additional details about the status.""" - - usage: Optional[RealtimeResponseUsage] = None - """Usage statistics for the Response, this will correspond to billing. - - A Realtime API session will maintain a conversation context and append new Items - to the Conversation, thus output from previous turns (text and audio tokens) - will become the input for later turns. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output.py deleted file mode 100644 index db02511..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_audio_formats import RealtimeAudioFormats - -__all__ = ["RealtimeResponseCreateAudioOutput", "Output"] - - -class Output(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the output audio.""" - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. - """ - - -class RealtimeResponseCreateAudioOutput(BaseModel): - """Configuration for audio input and output.""" - - output: Optional[Output] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output_param.py deleted file mode 100644 index 22787ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_audio_output_param.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypedDict - -from .realtime_audio_formats_param import RealtimeAudioFormatsParam - -__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output"] - - -class Output(TypedDict, total=False): - format: RealtimeAudioFormatsParam - """The format of the output audio.""" - - voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]] - """The voice the model uses to respond. - - Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`, - `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the - session once the model has responded with audio at least once. - """ - - -class RealtimeResponseCreateAudioOutputParam(TypedDict, total=False): - """Configuration for audio input and output.""" - - output: Output diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool.py deleted file mode 100644 index 72189e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool.py +++ /dev/null @@ -1,153 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel - -__all__ = [ - "RealtimeResponseCreateMcpTool", - "AllowedTools", - "AllowedToolsMcpToolFilter", - "RequireApproval", - "RequireApprovalMcpToolApprovalFilter", - "RequireApprovalMcpToolApprovalFilterAlways", - "RequireApprovalMcpToolApprovalFilterNever", -] - - -class AllowedToolsMcpToolFilter(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -AllowedTools: TypeAlias = Union[List[str], AllowedToolsMcpToolFilter, None] - - -class RequireApprovalMcpToolApprovalFilterAlways(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class RequireApprovalMcpToolApprovalFilterNever(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class RequireApprovalMcpToolApprovalFilter(BaseModel): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: Optional[RequireApprovalMcpToolApprovalFilterAlways] = None - """A filter object to specify which tools are allowed.""" - - never: Optional[RequireApprovalMcpToolApprovalFilterNever] = None - """A filter object to specify which tools are allowed.""" - - -RequireApproval: TypeAlias = Union[RequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] - - -class RealtimeResponseCreateMcpTool(BaseModel): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: str - """A label for this MCP server, used to identify it in tool calls.""" - - type: Literal["mcp"] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[AllowedTools] = None - """List of allowed tool names or a filter object.""" - - authorization: Optional[str] = None - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = None - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] = None - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[RequireApproval] = None - """Specify which of the MCP server's tools require approval.""" - - server_description: Optional[str] = None - """Optional description of the MCP server, used to provide more context.""" - - server_url: Optional[str] = None - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool_param.py deleted file mode 100644 index 68dd6bd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_mcp_tool_param.py +++ /dev/null @@ -1,153 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr - -__all__ = [ - "RealtimeResponseCreateMcpToolParam", - "AllowedTools", - "AllowedToolsMcpToolFilter", - "RequireApproval", - "RequireApprovalMcpToolApprovalFilter", - "RequireApprovalMcpToolApprovalFilterAlways", - "RequireApprovalMcpToolApprovalFilterNever", -] - - -class AllowedToolsMcpToolFilter(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -AllowedTools: TypeAlias = Union[SequenceNotStr[str], AllowedToolsMcpToolFilter] - - -class RequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class RequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class RequireApprovalMcpToolApprovalFilter(TypedDict, total=False): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: RequireApprovalMcpToolApprovalFilterAlways - """A filter object to specify which tools are allowed.""" - - never: RequireApprovalMcpToolApprovalFilterNever - """A filter object to specify which tools are allowed.""" - - -RequireApproval: TypeAlias = Union[RequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] - - -class RealtimeResponseCreateMcpToolParam(TypedDict, total=False): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: Required[str] - """A label for this MCP server, used to identify it in tool calls.""" - - type: Required[Literal["mcp"]] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[AllowedTools] - """List of allowed tool names or a filter object.""" - - authorization: str - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[RequireApproval] - """Specify which of the MCP server's tools require approval.""" - - server_description: str - """Optional description of the MCP server, used to provide more context.""" - - server_url: str - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params.py deleted file mode 100644 index deec8c9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params.py +++ /dev/null @@ -1,100 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..shared.metadata import Metadata -from .conversation_item import ConversationItem -from .realtime_function_tool import RealtimeFunctionTool -from ..responses.response_prompt import ResponsePrompt -from ..responses.tool_choice_mcp import ToolChoiceMcp -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.tool_choice_function import ToolChoiceFunction -from .realtime_response_create_mcp_tool import RealtimeResponseCreateMcpTool -from .realtime_response_create_audio_output import RealtimeResponseCreateAudioOutput - -__all__ = ["RealtimeResponseCreateParams", "ToolChoice", "Tool"] - -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] - -Tool: TypeAlias = Union[RealtimeFunctionTool, RealtimeResponseCreateMcpTool] - - -class RealtimeResponseCreateParams(BaseModel): - """Create a new Realtime response with these parameters""" - - audio: Optional[RealtimeResponseCreateAudioOutput] = None - """Configuration for audio input and output.""" - - conversation: Union[str, Literal["auto", "none"], None] = None - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Optional[List[ConversationItem]] = None - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items that previously - appeared in the session using their id. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. Note that the server sets default instructions which will be used if - this field is not set and are visible in the `session.created` event at the - start of the session. - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - output_modalities: Optional[List[Literal["text", "audio"]]] = None - """ - The set of modalities the model used to respond, currently the only possible - values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text - transcript. Setting the output to mode `text` will disable audio output from the - model. - """ - - prompt: Optional[ResponsePrompt] = None - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: Optional[ToolChoice] = None - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Optional[List[Tool]] = None - """Tools available to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params_param.py deleted file mode 100644 index caad5bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_create_params_param.py +++ /dev/null @@ -1,101 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, TypeAlias, TypedDict - -from ..shared_params.metadata import Metadata -from .conversation_item_param import ConversationItemParam -from .realtime_function_tool_param import RealtimeFunctionToolParam -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.response_prompt_param import ResponsePromptParam -from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam -from ..responses.tool_choice_function_param import ToolChoiceFunctionParam -from .realtime_response_create_mcp_tool_param import RealtimeResponseCreateMcpToolParam -from .realtime_response_create_audio_output_param import RealtimeResponseCreateAudioOutputParam - -__all__ = ["RealtimeResponseCreateParamsParam", "ToolChoice", "Tool"] - -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] - -Tool: TypeAlias = Union[RealtimeFunctionToolParam, RealtimeResponseCreateMcpToolParam] - - -class RealtimeResponseCreateParamsParam(TypedDict, total=False): - """Create a new Realtime response with these parameters""" - - audio: RealtimeResponseCreateAudioOutputParam - """Configuration for audio input and output.""" - - conversation: Union[str, Literal["auto", "none"]] - """Controls which conversation the response is added to. - - Currently supports `auto` and `none`, with `auto` as the default value. The - `auto` value means that the contents of the response will be added to the - default conversation. Set this to `none` to create an out-of-band response which - will not add items to default conversation. - """ - - input: Iterable[ConversationItemParam] - """Input items to include in the prompt for the model. - - Using this field creates a new context for this Response instead of using the - default conversation. An empty array `[]` will clear the context for this - Response. Note that this can include references to items that previously - appeared in the session using their id. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. Note that the server sets default instructions which will be used if - this field is not set and are visible in the `session.created` event at the - start of the session. - """ - - max_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - output_modalities: List[Literal["text", "audio"]] - """ - The set of modalities the model used to respond, currently the only possible - values are `[\"audio\"]`, `[\"text\"]`. Audio output always include a text - transcript. Setting the output to mode `text` will disable audio output from the - model. - """ - - prompt: Optional[ResponsePromptParam] - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: ToolChoice - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Iterable[Tool] - """Tools available to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_status.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_status.py deleted file mode 100644 index 26b272a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_status.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeResponseStatus", "Error"] - - -class Error(BaseModel): - """ - A description of the error that caused the response to fail, - populated when the `status` is `failed`. - """ - - code: Optional[str] = None - """Error code, if any.""" - - type: Optional[str] = None - """The type of error.""" - - -class RealtimeResponseStatus(BaseModel): - """Additional details about the status.""" - - error: Optional[Error] = None - """ - A description of the error that caused the response to fail, populated when the - `status` is `failed`. - """ - - reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None - """The reason the Response did not complete. - - For a `cancelled` Response, one of `turn_detected` (the server VAD detected a - new start of speech) or `client_cancelled` (the client sent a cancel event). For - an `incomplete` Response, one of `max_output_tokens` or `content_filter` (the - server-side safety filter activated and cut off the response). - """ - - type: Optional[Literal["completed", "cancelled", "incomplete", "failed"]] = None - """ - The type of error that caused the response to fail, corresponding with the - `status` field (`completed`, `cancelled`, `incomplete`, `failed`). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage.py deleted file mode 100644 index a5985d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .realtime_response_usage_input_token_details import RealtimeResponseUsageInputTokenDetails -from .realtime_response_usage_output_token_details import RealtimeResponseUsageOutputTokenDetails - -__all__ = ["RealtimeResponseUsage"] - - -class RealtimeResponseUsage(BaseModel): - """Usage statistics for the Response, this will correspond to billing. - - A - Realtime API session will maintain a conversation context and append new - Items to the Conversation, thus output from previous turns (text and - audio tokens) will become the input for later turns. - """ - - input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = None - """Details about the input tokens used in the Response. - - Cached tokens are tokens from previous turns in the conversation that are - included as context for the current response. Cached tokens here are counted as - a subset of input tokens, meaning input tokens will include cached and uncached - tokens. - """ - - input_tokens: Optional[int] = None - """ - The number of input tokens used in the Response, including text and audio - tokens. - """ - - output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] = None - """Details about the output tokens used in the Response.""" - - output_tokens: Optional[int] = None - """ - The number of output tokens sent in the Response, including text and audio - tokens. - """ - - total_tokens: Optional[int] = None - """ - The total number of tokens in the Response including input and output text and - audio tokens. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_input_token_details.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_input_token_details.py deleted file mode 100644 index 0fc7174..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_input_token_details.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["RealtimeResponseUsageInputTokenDetails", "CachedTokensDetails"] - - -class CachedTokensDetails(BaseModel): - """Details about the cached tokens used as input for the Response.""" - - audio_tokens: Optional[int] = None - """The number of cached audio tokens used as input for the Response.""" - - image_tokens: Optional[int] = None - """The number of cached image tokens used as input for the Response.""" - - text_tokens: Optional[int] = None - """The number of cached text tokens used as input for the Response.""" - - -class RealtimeResponseUsageInputTokenDetails(BaseModel): - """Details about the input tokens used in the Response. - - Cached tokens are tokens from previous turns in the conversation that are included as context for the current response. Cached tokens here are counted as a subset of input tokens, meaning input tokens will include cached and uncached tokens. - """ - - audio_tokens: Optional[int] = None - """The number of audio tokens used as input for the Response.""" - - cached_tokens: Optional[int] = None - """The number of cached tokens used as input for the Response.""" - - cached_tokens_details: Optional[CachedTokensDetails] = None - """Details about the cached tokens used as input for the Response.""" - - image_tokens: Optional[int] = None - """The number of image tokens used as input for the Response.""" - - text_tokens: Optional[int] = None - """The number of text tokens used as input for the Response.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_output_token_details.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_output_token_details.py deleted file mode 100644 index 2154c77..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_response_usage_output_token_details.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["RealtimeResponseUsageOutputTokenDetails"] - - -class RealtimeResponseUsageOutputTokenDetails(BaseModel): - """Details about the output tokens used in the Response.""" - - audio_tokens: Optional[int] = None - """The number of audio tokens used in the Response.""" - - text_tokens: Optional[int] = None - """The number of text tokens used in the Response.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_server_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_server_event.py deleted file mode 100644 index 5de53d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_server_event.py +++ /dev/null @@ -1,185 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .conversation_item import ConversationItem -from .response_done_event import ResponseDoneEvent -from .realtime_error_event import RealtimeErrorEvent -from .mcp_list_tools_failed import McpListToolsFailed -from .session_created_event import SessionCreatedEvent -from .session_updated_event import SessionUpdatedEvent -from .conversation_item_done import ConversationItemDone -from .response_created_event import ResponseCreatedEvent -from .conversation_item_added import ConversationItemAdded -from .mcp_list_tools_completed import McpListToolsCompleted -from .response_mcp_call_failed import ResponseMcpCallFailed -from .response_text_done_event import ResponseTextDoneEvent -from .rate_limits_updated_event import RateLimitsUpdatedEvent -from .response_audio_done_event import ResponseAudioDoneEvent -from .response_text_delta_event import ResponseTextDeltaEvent -from .conversation_created_event import ConversationCreatedEvent -from .mcp_list_tools_in_progress import McpListToolsInProgress -from .response_audio_delta_event import ResponseAudioDeltaEvent -from .response_mcp_call_completed import ResponseMcpCallCompleted -from .response_mcp_call_in_progress import ResponseMcpCallInProgress -from .conversation_item_created_event import ConversationItemCreatedEvent -from .conversation_item_deleted_event import ConversationItemDeletedEvent -from .response_output_item_done_event import ResponseOutputItemDoneEvent -from .input_audio_buffer_cleared_event import InputAudioBufferClearedEvent -from .response_content_part_done_event import ResponseContentPartDoneEvent -from .response_mcp_call_arguments_done import ResponseMcpCallArgumentsDone -from .response_output_item_added_event import ResponseOutputItemAddedEvent -from .conversation_item_truncated_event import ConversationItemTruncatedEvent -from .response_content_part_added_event import ResponseContentPartAddedEvent -from .response_mcp_call_arguments_delta import ResponseMcpCallArgumentsDelta -from .input_audio_buffer_committed_event import InputAudioBufferCommittedEvent -from .input_audio_buffer_timeout_triggered import InputAudioBufferTimeoutTriggered -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent -from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent -from .input_audio_buffer_speech_started_event import InputAudioBufferSpeechStartedEvent -from .input_audio_buffer_speech_stopped_event import InputAudioBufferSpeechStoppedEvent -from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent -from .input_audio_buffer_dtmf_event_received_event import InputAudioBufferDtmfEventReceivedEvent -from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent -from .conversation_item_input_audio_transcription_segment import ConversationItemInputAudioTranscriptionSegment -from .conversation_item_input_audio_transcription_delta_event import ConversationItemInputAudioTranscriptionDeltaEvent -from .conversation_item_input_audio_transcription_failed_event import ConversationItemInputAudioTranscriptionFailedEvent -from .conversation_item_input_audio_transcription_completed_event import ( - ConversationItemInputAudioTranscriptionCompletedEvent, -) - -__all__ = [ - "RealtimeServerEvent", - "ConversationItemRetrieved", - "OutputAudioBufferStarted", - "OutputAudioBufferStopped", - "OutputAudioBufferCleared", -] - - -class ConversationItemRetrieved(BaseModel): - """Returned when a conversation item is retrieved with `conversation.item.retrieve`. - - This is provided as a way to fetch the server's representation of an item, for example to get access to the post-processed audio data after noise cancellation and VAD. It includes the full content of the Item, including audio data. - """ - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - type: Literal["conversation.item.retrieved"] - """The event type, must be `conversation.item.retrieved`.""" - - -class OutputAudioBufferStarted(BaseModel): - """ - **WebRTC/SIP Only:** Emitted when the server begins streaming audio to the client. This event is - emitted after an audio content part has been added (`response.content_part.added`) - to the response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.started"] - """The event type, must be `output_audio_buffer.started`.""" - - -class OutputAudioBufferStopped(BaseModel): - """ - **WebRTC/SIP Only:** Emitted when the output audio buffer has been completely drained on the server, - and no more audio is forthcoming. This event is emitted after the full response - data has been sent to the client (`response.done`). - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.stopped"] - """The event type, must be `output_audio_buffer.stopped`.""" - - -class OutputAudioBufferCleared(BaseModel): - """**WebRTC/SIP Only:** Emitted when the output audio buffer is cleared. - - This happens either in VAD - mode when the user has interrupted (`input_audio_buffer.speech_started`), - or when the client has emitted the `output_audio_buffer.clear` event to manually - cut off the current audio response. - [Learn more](https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-audio-in-webrtc). - """ - - event_id: str - """The unique ID of the server event.""" - - response_id: str - """The unique ID of the response that produced the audio.""" - - type: Literal["output_audio_buffer.cleared"] - """The event type, must be `output_audio_buffer.cleared`.""" - - -RealtimeServerEvent: TypeAlias = Annotated[ - Union[ - ConversationCreatedEvent, - ConversationItemCreatedEvent, - ConversationItemDeletedEvent, - ConversationItemInputAudioTranscriptionCompletedEvent, - ConversationItemInputAudioTranscriptionDeltaEvent, - ConversationItemInputAudioTranscriptionFailedEvent, - ConversationItemRetrieved, - ConversationItemTruncatedEvent, - RealtimeErrorEvent, - InputAudioBufferClearedEvent, - InputAudioBufferCommittedEvent, - InputAudioBufferDtmfEventReceivedEvent, - InputAudioBufferSpeechStartedEvent, - InputAudioBufferSpeechStoppedEvent, - RateLimitsUpdatedEvent, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreatedEvent, - ResponseDoneEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - SessionCreatedEvent, - SessionUpdatedEvent, - OutputAudioBufferStarted, - OutputAudioBufferStopped, - OutputAudioBufferCleared, - ConversationItemAdded, - ConversationItemDone, - InputAudioBufferTimeoutTriggered, - ConversationItemInputAudioTranscriptionSegment, - McpListToolsInProgress, - McpListToolsCompleted, - McpListToolsFailed, - ResponseMcpCallArgumentsDelta, - ResponseMcpCallArgumentsDone, - ResponseMcpCallInProgress, - ResponseMcpCallCompleted, - ResponseMcpCallFailed, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_client_secret.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_client_secret.py deleted file mode 100644 index 13a12f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_client_secret.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["RealtimeSessionClientSecret"] - - -class RealtimeSessionClientSecret(BaseModel): - """Ephemeral key returned by the API.""" - - expires_at: int - """Timestamp for when the token expires. - - Currently, all tokens expire after one minute. - """ - - value: str - """ - Ephemeral key usable in client environments to authenticate connections to the - Realtime API. Use this in client-side environments rather than a standard API - token, which should only be used server-side. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request.py deleted file mode 100644 index 4a93c91..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request.py +++ /dev/null @@ -1,131 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_truncation import RealtimeTruncation -from .realtime_audio_config import RealtimeAudioConfig -from .realtime_tools_config import RealtimeToolsConfig -from .realtime_tracing_config import RealtimeTracingConfig -from ..responses.response_prompt import ResponsePrompt -from .realtime_tool_choice_config import RealtimeToolChoiceConfig - -__all__ = ["RealtimeSessionCreateRequest"] - - -class RealtimeSessionCreateRequest(BaseModel): - """Realtime session object configuration.""" - - type: Literal["realtime"] - """The type of session to create. Always `realtime` for the Realtime API.""" - - audio: Optional[RealtimeAudioConfig] = None - """Configuration for input and output audio.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - None, - ] = None - """The Realtime model used for this session.""" - - output_modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - It defaults to `["audio"]`, indicating that the model will respond with audio - plus a transcript. `["text"]` can be used to make the model respond with text - only. It is not possible to request both `text` and `audio` at the same time. - """ - - prompt: Optional[ResponsePrompt] = None - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: Optional[RealtimeToolChoiceConfig] = None - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Optional[RealtimeToolsConfig] = None - """Tools available to the model.""" - - tracing: Optional[RealtimeTracingConfig] = None - """ - Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - truncation: Optional[RealtimeTruncation] = None - """ - When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request_param.py deleted file mode 100644 index dee63d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_request_param.py +++ /dev/null @@ -1,131 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Optional -from typing_extensions import Literal, Required, TypedDict - -from .realtime_truncation_param import RealtimeTruncationParam -from .realtime_audio_config_param import RealtimeAudioConfigParam -from .realtime_tools_config_param import RealtimeToolsConfigParam -from .realtime_tracing_config_param import RealtimeTracingConfigParam -from ..responses.response_prompt_param import ResponsePromptParam -from .realtime_tool_choice_config_param import RealtimeToolChoiceConfigParam - -__all__ = ["RealtimeSessionCreateRequestParam"] - - -class RealtimeSessionCreateRequestParam(TypedDict, total=False): - """Realtime session object configuration.""" - - type: Required[Literal["realtime"]] - """The type of session to create. Always `realtime` for the Realtime API.""" - - audio: RealtimeAudioConfigParam - """Configuration for input and output audio.""" - - include: List[Literal["item.input_audio_transcription.logprobs"]] - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - instructions: str - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"]] - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - ] - """The Realtime model used for this session.""" - - output_modalities: List[Literal["text", "audio"]] - """The set of modalities the model can respond with. - - It defaults to `["audio"]`, indicating that the model will respond with audio - plus a transcript. `["text"]` can be used to make the model respond with text - only. It is not possible to request both `text` and `audio` at the same time. - """ - - prompt: Optional[ResponsePromptParam] - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: RealtimeToolChoiceConfigParam - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: RealtimeToolsConfigParam - """Tools available to the model.""" - - tracing: Optional[RealtimeTracingConfigParam] - """ - Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - truncation: RealtimeTruncationParam - """ - When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_response.py deleted file mode 100644 index 15a200c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_session_create_response.py +++ /dev/null @@ -1,534 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .audio_transcription import AudioTranscription -from .realtime_truncation import RealtimeTruncation -from .noise_reduction_type import NoiseReductionType -from .realtime_audio_formats import RealtimeAudioFormats -from .realtime_function_tool import RealtimeFunctionTool -from ..responses.response_prompt import ResponsePrompt -from ..responses.tool_choice_mcp import ToolChoiceMcp -from ..responses.tool_choice_options import ToolChoiceOptions -from .realtime_session_client_secret import RealtimeSessionClientSecret -from ..responses.tool_choice_function import ToolChoiceFunction - -__all__ = [ - "RealtimeSessionCreateResponse", - "Audio", - "AudioInput", - "AudioInputNoiseReduction", - "AudioInputTurnDetection", - "AudioInputTurnDetectionServerVad", - "AudioInputTurnDetectionSemanticVad", - "AudioOutput", - "ToolChoice", - "Tool", - "ToolMcpTool", - "ToolMcpToolAllowedTools", - "ToolMcpToolAllowedToolsMcpToolFilter", - "ToolMcpToolRequireApproval", - "ToolMcpToolRequireApprovalMcpToolApprovalFilter", - "ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways", - "ToolMcpToolRequireApprovalMcpToolApprovalFilterNever", - "Tracing", - "TracingTracingConfiguration", -] - - -class AudioInputNoiseReduction(BaseModel): - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. - Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. - Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. - """ - - type: Optional[NoiseReductionType] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class AudioInputTurnDetectionServerVad(BaseModel): - """ - Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. - """ - - type: Literal["server_vad"] - """Type of turn detection, `server_vad` to turn on simple Server VAD.""" - - create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - If `interrupt_response` is set to `false` this may fail to create a response if - the model is already responding. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - idle_timeout_ms: Optional[int] = None - """Optional timeout after which a model response will be triggered automatically. - - This is useful for situations in which a long pause from the user is unexpected, - such as a phone call. The model will effectively prompt the user to continue the - conversation based on the current context. - - The timeout value will be applied after the last model response's audio has - finished playing, i.e. it's set to the `response.done` time plus audio playback - duration. - - An `input_audio_buffer.timeout_triggered` event (plus events associated with the - Response) will be emitted when the timeout is reached. Idle timeout is currently - only supported for `server_vad` mode. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt (cancel) any ongoing response with - output to the default conversation (i.e. `conversation` of `auto`) when a VAD - start event occurs. If `true` then the response will be cancelled, otherwise it - will continue until complete. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - -class AudioInputTurnDetectionSemanticVad(BaseModel): - """ - Server-side semantic turn detection which uses a model to determine when the user has finished speaking. - """ - - type: Literal["semantic_vad"] - """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" - - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - -AudioInputTurnDetection: TypeAlias = Annotated[ - Union[AudioInputTurnDetectionServerVad, AudioInputTurnDetectionSemanticVad, None], - PropertyInfo(discriminator="type"), -] - - -class AudioInput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the input audio.""" - - noise_reduction: Optional[AudioInputNoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: Optional[AudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[AudioInputTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. - - Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ - - -class AudioOutput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The format of the output audio.""" - - speed: Optional[float] = None - """ - The speed of the model's spoken response as a multiple of the original speed. - 1.0 is the default speed. 0.25 is the minimum speed. 1.5 is the maximum speed. - This value can only be changed in between model turns, not while a response is - in progress. - - This parameter is a post-processing adjustment to the audio after it is - generated, it's also possible to prompt the model to speak faster or slower. - """ - - voice: Union[ - str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None - ] = None - """The voice the model uses to respond. - - Voice cannot be changed during the session once the model has responded with - audio at least once. Current voice options are `alloy`, `ash`, `ballad`, - `coral`, `echo`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. We recommend - `marin` and `cedar` for best quality. - """ - - -class Audio(BaseModel): - """Configuration for input and output audio.""" - - input: Optional[AudioInput] = None - - output: Optional[AudioOutput] = None - - -ToolChoice: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] - - -class ToolMcpToolAllowedToolsMcpToolFilter(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -ToolMcpToolAllowedTools: TypeAlias = Union[List[str], ToolMcpToolAllowedToolsMcpToolFilter, None] - - -class ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class ToolMcpToolRequireApprovalMcpToolApprovalFilterNever(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class ToolMcpToolRequireApprovalMcpToolApprovalFilter(BaseModel): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: Optional[ToolMcpToolRequireApprovalMcpToolApprovalFilterAlways] = None - """A filter object to specify which tools are allowed.""" - - never: Optional[ToolMcpToolRequireApprovalMcpToolApprovalFilterNever] = None - """A filter object to specify which tools are allowed.""" - - -ToolMcpToolRequireApproval: TypeAlias = Union[ - ToolMcpToolRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None -] - - -class ToolMcpTool(BaseModel): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: str - """A label for this MCP server, used to identify it in tool calls.""" - - type: Literal["mcp"] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[ToolMcpToolAllowedTools] = None - """List of allowed tool names or a filter object.""" - - authorization: Optional[str] = None - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = None - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] = None - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[ToolMcpToolRequireApproval] = None - """Specify which of the MCP server's tools require approval.""" - - server_description: Optional[str] = None - """Optional description of the MCP server, used to provide more context.""" - - server_url: Optional[str] = None - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -Tool: TypeAlias = Union[RealtimeFunctionTool, ToolMcpTool] - - -class TracingTracingConfiguration(BaseModel): - """Granular configuration for tracing.""" - - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - Traces Dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the Traces - Dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the Traces Dashboard. - """ - - -Tracing: TypeAlias = Union[Literal["auto"], TracingTracingConfiguration, None] - - -class RealtimeSessionCreateResponse(BaseModel): - """A new Realtime session configuration, with an ephemeral key. - - Default TTL - for keys is one minute. - """ - - client_secret: RealtimeSessionClientSecret - """Ephemeral key returned by the API.""" - - type: Literal["realtime"] - """The type of session to create. Always `realtime` for the Realtime API.""" - - audio: Optional[Audio] = None - """Configuration for input and output audio.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ - - instructions: Optional[str] = None - """The default system instructions (i.e. - - system message) prepended to model calls. This field allows the client to guide - the model on desired responses. The model can be instructed on response content - and format, (e.g. "be extremely succinct", "act friendly", "here are examples of - good responses") and on audio behavior (e.g. "talk quickly", "inject emotion - into your voice", "laugh frequently"). The instructions are not guaranteed to be - followed by the model, but they provide guidance to the model on the desired - behavior. - - Note that the server sets default instructions which will be used if this field - is not set and are visible in the `session.created` event at the start of the - session. - """ - - max_output_tokens: Union[int, Literal["inf"], None] = None - """ - Maximum number of output tokens for a single assistant response, inclusive of - tool calls. Provide an integer between 1 and 4096 to limit output tokens, or - `inf` for the maximum available tokens for a given model. Defaults to `inf`. - """ - - model: Union[ - str, - Literal[ - "gpt-realtime", - "gpt-realtime-2025-08-28", - "gpt-4o-realtime-preview", - "gpt-4o-realtime-preview-2024-10-01", - "gpt-4o-realtime-preview-2024-12-17", - "gpt-4o-realtime-preview-2025-06-03", - "gpt-4o-mini-realtime-preview", - "gpt-4o-mini-realtime-preview-2024-12-17", - "gpt-realtime-mini", - "gpt-realtime-mini-2025-10-06", - "gpt-realtime-mini-2025-12-15", - "gpt-audio-mini", - "gpt-audio-mini-2025-10-06", - "gpt-audio-mini-2025-12-15", - ], - None, - ] = None - """The Realtime model used for this session.""" - - output_modalities: Optional[List[Literal["text", "audio"]]] = None - """The set of modalities the model can respond with. - - It defaults to `["audio"]`, indicating that the model will respond with audio - plus a transcript. `["text"]` can be used to make the model respond with text - only. It is not possible to request both `text` and `audio` at the same time. - """ - - prompt: Optional[ResponsePrompt] = None - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - tool_choice: Optional[ToolChoice] = None - """How the model chooses tools. - - Provide one of the string modes or force a specific function/MCP tool. - """ - - tools: Optional[List[Tool]] = None - """Tools available to the model.""" - - tracing: Optional[Tracing] = None - """ - Realtime API can write session traces to the - [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once - tracing is enabled for a session, the configuration cannot be modified. - - `auto` will create a trace for the session with default values for the workflow - name, group id, and metadata. - """ - - truncation: Optional[RealtimeTruncation] = None - """ - When the number of tokens in a conversation exceeds the model's input token - limit, the conversation be truncated, meaning messages (starting from the - oldest) will not be included in the model's context. A 32k context model with - 4,096 max output tokens can only include 28,224 tokens in the context before - truncation occurs. - - Clients can configure truncation behavior to truncate with a lower max token - limit, which is an effective way to control token usage and cost. - - Truncation will reduce the number of cached tokens on the next turn (busting the - cache), since messages are dropped from the beginning of the context. However, - clients can also configure truncation to retain messages up to a fraction of the - maximum context size, which will reduce the need for future truncations and thus - improve the cache rate. - - Truncation can be disabled entirely, which means the server will never truncate - but would instead return an error if the conversation exceeds the model's input - token limit. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config.py deleted file mode 100644 index f93c490..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from ..responses.tool_choice_mcp import ToolChoiceMcp -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.tool_choice_function import ToolChoiceFunction - -__all__ = ["RealtimeToolChoiceConfig"] - -RealtimeToolChoiceConfig: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunction, ToolChoiceMcp] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config_param.py deleted file mode 100644 index af92f24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tool_choice_config_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from ..responses.tool_choice_options import ToolChoiceOptions -from ..responses.tool_choice_mcp_param import ToolChoiceMcpParam -from ..responses.tool_choice_function_param import ToolChoiceFunctionParam - -__all__ = ["RealtimeToolChoiceConfigParam"] - -RealtimeToolChoiceConfigParam: TypeAlias = Union[ToolChoiceOptions, ToolChoiceFunctionParam, ToolChoiceMcpParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config.py deleted file mode 100644 index b97599a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .realtime_tools_config_union import RealtimeToolsConfigUnion - -__all__ = ["RealtimeToolsConfig"] - -RealtimeToolsConfig: TypeAlias = List[RealtimeToolsConfigUnion] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_param.py deleted file mode 100644 index 3cc404f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_param.py +++ /dev/null @@ -1,161 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from .realtime_function_tool_param import RealtimeFunctionToolParam - -__all__ = [ - "RealtimeToolsConfigParam", - "RealtimeToolsConfigUnionParam", - "Mcp", - "McpAllowedTools", - "McpAllowedToolsMcpToolFilter", - "McpRequireApproval", - "McpRequireApprovalMcpToolApprovalFilter", - "McpRequireApprovalMcpToolApprovalFilterAlways", - "McpRequireApprovalMcpToolApprovalFilterNever", -] - - -class McpAllowedToolsMcpToolFilter(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] - - -class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: McpRequireApprovalMcpToolApprovalFilterAlways - """A filter object to specify which tools are allowed.""" - - never: McpRequireApprovalMcpToolApprovalFilterNever - """A filter object to specify which tools are allowed.""" - - -McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] - - -class Mcp(TypedDict, total=False): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: Required[str] - """A label for this MCP server, used to identify it in tool calls.""" - - type: Required[Literal["mcp"]] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[McpAllowedTools] - """List of allowed tool names or a filter object.""" - - authorization: str - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[McpRequireApproval] - """Specify which of the MCP server's tools require approval.""" - - server_description: str - """Optional description of the MCP server, used to provide more context.""" - - server_url: str - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -RealtimeToolsConfigUnionParam: TypeAlias = Union[RealtimeFunctionToolParam, Mcp] - -RealtimeToolsConfigParam: TypeAlias = List[RealtimeToolsConfigUnionParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union.py deleted file mode 100644 index 92aaee7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union.py +++ /dev/null @@ -1,159 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .realtime_function_tool import RealtimeFunctionTool - -__all__ = [ - "RealtimeToolsConfigUnion", - "Mcp", - "McpAllowedTools", - "McpAllowedToolsMcpToolFilter", - "McpRequireApproval", - "McpRequireApprovalMcpToolApprovalFilter", - "McpRequireApprovalMcpToolApprovalFilterAlways", - "McpRequireApprovalMcpToolApprovalFilterNever", -] - - -class McpAllowedToolsMcpToolFilter(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter, None] - - -class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilter(BaseModel): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None - """A filter object to specify which tools are allowed.""" - - never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None - """A filter object to specify which tools are allowed.""" - - -McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] - - -class Mcp(BaseModel): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: str - """A label for this MCP server, used to identify it in tool calls.""" - - type: Literal["mcp"] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[McpAllowedTools] = None - """List of allowed tool names or a filter object.""" - - authorization: Optional[str] = None - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = None - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] = None - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[McpRequireApproval] = None - """Specify which of the MCP server's tools require approval.""" - - server_description: Optional[str] = None - """Optional description of the MCP server, used to provide more context.""" - - server_url: Optional[str] = None - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -RealtimeToolsConfigUnion: TypeAlias = Annotated[Union[RealtimeFunctionTool, Mcp], PropertyInfo(discriminator="type")] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union_param.py deleted file mode 100644 index 6889b4c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tools_config_union_param.py +++ /dev/null @@ -1,158 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from .realtime_function_tool_param import RealtimeFunctionToolParam - -__all__ = [ - "RealtimeToolsConfigUnionParam", - "Mcp", - "McpAllowedTools", - "McpAllowedToolsMcpToolFilter", - "McpRequireApproval", - "McpRequireApprovalMcpToolApprovalFilter", - "McpRequireApprovalMcpToolApprovalFilterAlways", - "McpRequireApprovalMcpToolApprovalFilterNever", -] - - -class McpAllowedToolsMcpToolFilter(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] - - -class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: McpRequireApprovalMcpToolApprovalFilterAlways - """A filter object to specify which tools are allowed.""" - - never: McpRequireApprovalMcpToolApprovalFilterNever - """A filter object to specify which tools are allowed.""" - - -McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] - - -class Mcp(TypedDict, total=False): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: Required[str] - """A label for this MCP server, used to identify it in tool calls.""" - - type: Required[Literal["mcp"]] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[McpAllowedTools] - """List of allowed tool names or a filter object.""" - - authorization: str - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[McpRequireApproval] - """Specify which of the MCP server's tools require approval.""" - - server_description: str - """Optional description of the MCP server, used to provide more context.""" - - server_url: str - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -RealtimeToolsConfigUnionParam: TypeAlias = Union[RealtimeFunctionToolParam, Mcp] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config.py deleted file mode 100644 index 37e3ce8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel - -__all__ = ["RealtimeTracingConfig", "TracingConfiguration"] - - -class TracingConfiguration(BaseModel): - """Granular configuration for tracing.""" - - group_id: Optional[str] = None - """ - The group id to attach to this trace to enable filtering and grouping in the - Traces Dashboard. - """ - - metadata: Optional[object] = None - """ - The arbitrary metadata to attach to this trace to enable filtering in the Traces - Dashboard. - """ - - workflow_name: Optional[str] = None - """The name of the workflow to attach to this trace. - - This is used to name the trace in the Traces Dashboard. - """ - - -RealtimeTracingConfig: TypeAlias = Union[Literal["auto"], TracingConfiguration, None] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config_param.py deleted file mode 100644 index 7424128..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_tracing_config_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias, TypedDict - -__all__ = ["RealtimeTracingConfigParam", "TracingConfiguration"] - - -class TracingConfiguration(TypedDict, total=False): - """Granular configuration for tracing.""" - - group_id: str - """ - The group id to attach to this trace to enable filtering and grouping in the - Traces Dashboard. - """ - - metadata: object - """ - The arbitrary metadata to attach to this trace to enable filtering in the Traces - Dashboard. - """ - - workflow_name: str - """The name of the workflow to attach to this trace. - - This is used to name the trace in the Traces Dashboard. - """ - - -RealtimeTracingConfigParam: TypeAlias = Union[Literal["auto"], TracingConfiguration] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio.py deleted file mode 100644 index 7ec29af..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .realtime_transcription_session_audio_input import RealtimeTranscriptionSessionAudioInput - -__all__ = ["RealtimeTranscriptionSessionAudio"] - - -class RealtimeTranscriptionSessionAudio(BaseModel): - """Configuration for input and output audio.""" - - input: Optional[RealtimeTranscriptionSessionAudioInput] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input.py deleted file mode 100644 index 80ff223..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .audio_transcription import AudioTranscription -from .noise_reduction_type import NoiseReductionType -from .realtime_audio_formats import RealtimeAudioFormats -from .realtime_transcription_session_audio_input_turn_detection import ( - RealtimeTranscriptionSessionAudioInputTurnDetection, -) - -__all__ = ["RealtimeTranscriptionSessionAudioInput", "NoiseReduction"] - - -class NoiseReduction(BaseModel): - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. - Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. - Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. - """ - - type: Optional[NoiseReductionType] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class RealtimeTranscriptionSessionAudioInput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The PCM audio format. Only a 24kHz sample rate is supported.""" - - noise_reduction: Optional[NoiseReduction] = None - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: Optional[AudioTranscription] = None - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[RealtimeTranscriptionSessionAudioInputTurnDetection] = None - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. - - Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_param.py deleted file mode 100644 index dd908c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_param.py +++ /dev/null @@ -1,74 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -from .noise_reduction_type import NoiseReductionType -from .audio_transcription_param import AudioTranscriptionParam -from .realtime_audio_formats_param import RealtimeAudioFormatsParam -from .realtime_transcription_session_audio_input_turn_detection_param import ( - RealtimeTranscriptionSessionAudioInputTurnDetectionParam, -) - -__all__ = ["RealtimeTranscriptionSessionAudioInputParam", "NoiseReduction"] - - -class NoiseReduction(TypedDict, total=False): - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. - Noise reduction filters audio added to the input audio buffer before it is sent to VAD and the model. - Filtering the audio can improve VAD and turn detection accuracy (reducing false positives) and model performance by improving perception of the input audio. - """ - - type: NoiseReductionType - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class RealtimeTranscriptionSessionAudioInputParam(TypedDict, total=False): - format: RealtimeAudioFormatsParam - """The PCM audio format. Only a 24kHz sample rate is supported.""" - - noise_reduction: NoiseReduction - """Configuration for input audio noise reduction. - - This can be set to `null` to turn off. Noise reduction filters audio added to - the input audio buffer before it is sent to VAD and the model. Filtering the - audio can improve VAD and turn detection accuracy (reducing false positives) and - model performance by improving perception of the input audio. - """ - - transcription: AudioTranscriptionParam - """ - Configuration for input audio transcription, defaults to off and can be set to - `null` to turn off once on. Input audio transcription is not native to the - model, since the model consumes audio directly. Transcription runs - asynchronously through - [the /audio/transcriptions endpoint](https://platform.openai.com/docs/api-reference/audio/createTranscription) - and should be treated as guidance of input audio content rather than precisely - what the model heard. The client can optionally set the language and prompt for - transcription, these offer additional guidance to the transcription service. - """ - - turn_detection: Optional[RealtimeTranscriptionSessionAudioInputTurnDetectionParam] - """Configuration for turn detection, ether Server VAD or Semantic VAD. - - This can be set to `null` to turn off, in which case the client must manually - trigger model response. - - Server VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - - Semantic VAD is more advanced and uses a turn detection model (in conjunction - with VAD) to semantically estimate whether the user has finished speaking, then - dynamically sets a timeout based on this probability. For example, if user audio - trails off with "uhhm", the model will score a low probability of turn end and - wait longer for the user to continue speaking. This can be useful for more - natural conversations, but may have a higher latency. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py deleted file mode 100644 index 3d4ee77..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection.py +++ /dev/null @@ -1,115 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetection", "ServerVad", "SemanticVad"] - - -class ServerVad(BaseModel): - """ - Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. - """ - - type: Literal["server_vad"] - """Type of turn detection, `server_vad` to turn on simple Server VAD.""" - - create_response: Optional[bool] = None - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - If `interrupt_response` is set to `false` this may fail to create a response if - the model is already responding. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - idle_timeout_ms: Optional[int] = None - """Optional timeout after which a model response will be triggered automatically. - - This is useful for situations in which a long pause from the user is unexpected, - such as a phone call. The model will effectively prompt the user to continue the - conversation based on the current context. - - The timeout value will be applied after the last model response's audio has - finished playing, i.e. it's set to the `response.done` time plus audio playback - duration. - - An `input_audio_buffer.timeout_triggered` event (plus events associated with the - Response) will be emitted when the timeout is reached. Idle timeout is currently - only supported for `server_vad` mode. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt (cancel) any ongoing response with - output to the default conversation (i.e. `conversation` of `auto`) when a VAD - start event occurs. If `true` then the response will be cancelled, otherwise it - will continue until complete. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - prefix_padding_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: Optional[float] = None - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - -class SemanticVad(BaseModel): - """ - Server-side semantic turn detection which uses a model to determine when the user has finished speaking. - """ - - type: Literal["semantic_vad"] - """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" - - create_response: Optional[bool] = None - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Optional[Literal["low", "medium", "high", "auto"]] = None - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ - - interrupt_response: Optional[bool] = None - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - -RealtimeTranscriptionSessionAudioInputTurnDetection: TypeAlias = Annotated[ - Union[ServerVad, SemanticVad, None], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py deleted file mode 100644 index 0aca59c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_input_turn_detection_param.py +++ /dev/null @@ -1,112 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["RealtimeTranscriptionSessionAudioInputTurnDetectionParam", "ServerVad", "SemanticVad"] - - -class ServerVad(TypedDict, total=False): - """ - Server-side voice activity detection (VAD) which flips on when user speech is detected and off after a period of silence. - """ - - type: Required[Literal["server_vad"]] - """Type of turn detection, `server_vad` to turn on simple Server VAD.""" - - create_response: bool - """Whether or not to automatically generate a response when a VAD stop event - occurs. - - If `interrupt_response` is set to `false` this may fail to create a response if - the model is already responding. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - idle_timeout_ms: Optional[int] - """Optional timeout after which a model response will be triggered automatically. - - This is useful for situations in which a long pause from the user is unexpected, - such as a phone call. The model will effectively prompt the user to continue the - conversation based on the current context. - - The timeout value will be applied after the last model response's audio has - finished playing, i.e. it's set to the `response.done` time plus audio playback - duration. - - An `input_audio_buffer.timeout_triggered` event (plus events associated with the - Response) will be emitted when the timeout is reached. Idle timeout is currently - only supported for `server_vad` mode. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt (cancel) any ongoing response with - output to the default conversation (i.e. `conversation` of `auto`) when a VAD - start event occurs. If `true` then the response will be cancelled, otherwise it - will continue until complete. - - If both `create_response` and `interrupt_response` are set to `false`, the model - will never respond automatically but VAD events will still be emitted. - """ - - prefix_padding_ms: int - """Used only for `server_vad` mode. - - Amount of audio to include before the VAD detected speech (in milliseconds). - Defaults to 300ms. - """ - - silence_duration_ms: int - """Used only for `server_vad` mode. - - Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. - With shorter values the model will respond more quickly, but may jump in on - short pauses from the user. - """ - - threshold: float - """Used only for `server_vad` mode. - - Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher - threshold will require louder audio to activate the model, and thus might - perform better in noisy environments. - """ - - -class SemanticVad(TypedDict, total=False): - """ - Server-side semantic turn detection which uses a model to determine when the user has finished speaking. - """ - - type: Required[Literal["semantic_vad"]] - """Type of turn detection, `semantic_vad` to turn on Semantic VAD.""" - - create_response: bool - """ - Whether or not to automatically generate a response when a VAD stop event - occurs. - """ - - eagerness: Literal["low", "medium", "high", "auto"] - """Used only for `semantic_vad` mode. - - The eagerness of the model to respond. `low` will wait longer for the user to - continue speaking, `high` will respond more quickly. `auto` is the default and - is equivalent to `medium`. `low`, `medium`, and `high` have max timeouts of 8s, - 4s, and 2s respectively. - """ - - interrupt_response: bool - """ - Whether or not to automatically interrupt any ongoing response with output to - the default conversation (i.e. `conversation` of `auto`) when a VAD start event - occurs. - """ - - -RealtimeTranscriptionSessionAudioInputTurnDetectionParam: TypeAlias = Union[ServerVad, SemanticVad] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_param.py deleted file mode 100644 index 6bf1117..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_audio_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .realtime_transcription_session_audio_input_param import RealtimeTranscriptionSessionAudioInputParam - -__all__ = ["RealtimeTranscriptionSessionAudioParam"] - - -class RealtimeTranscriptionSessionAudioParam(TypedDict, total=False): - """Configuration for input and output audio.""" - - input: RealtimeTranscriptionSessionAudioInputParam diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request.py deleted file mode 100644 index f72a4ad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_transcription_session_audio import RealtimeTranscriptionSessionAudio - -__all__ = ["RealtimeTranscriptionSessionCreateRequest"] - - -class RealtimeTranscriptionSessionCreateRequest(BaseModel): - """Realtime transcription session object configuration.""" - - type: Literal["transcription"] - """The type of session to create. - - Always `transcription` for transcription sessions. - """ - - audio: Optional[RealtimeTranscriptionSessionAudio] = None - """Configuration for input and output audio.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request_param.py deleted file mode 100644 index 9b4d8ea..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_request_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, Required, TypedDict - -from .realtime_transcription_session_audio_param import RealtimeTranscriptionSessionAudioParam - -__all__ = ["RealtimeTranscriptionSessionCreateRequestParam"] - - -class RealtimeTranscriptionSessionCreateRequestParam(TypedDict, total=False): - """Realtime transcription session object configuration.""" - - type: Required[Literal["transcription"]] - """The type of session to create. - - Always `transcription` for transcription sessions. - """ - - audio: RealtimeTranscriptionSessionAudioParam - """Configuration for input and output audio.""" - - include: List[Literal["item.input_audio_transcription.logprobs"]] - """Additional fields to include in server outputs. - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_response.py deleted file mode 100644 index 6ca6c38..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_create_response.py +++ /dev/null @@ -1,74 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .audio_transcription import AudioTranscription -from .noise_reduction_type import NoiseReductionType -from .realtime_audio_formats import RealtimeAudioFormats -from .realtime_transcription_session_turn_detection import RealtimeTranscriptionSessionTurnDetection - -__all__ = ["RealtimeTranscriptionSessionCreateResponse", "Audio", "AudioInput", "AudioInputNoiseReduction"] - - -class AudioInputNoiseReduction(BaseModel): - """Configuration for input audio noise reduction.""" - - type: Optional[NoiseReductionType] = None - """Type of noise reduction. - - `near_field` is for close-talking microphones such as headphones, `far_field` is - for far-field microphones such as laptop or conference room microphones. - """ - - -class AudioInput(BaseModel): - format: Optional[RealtimeAudioFormats] = None - """The PCM audio format. Only a 24kHz sample rate is supported.""" - - noise_reduction: Optional[AudioInputNoiseReduction] = None - """Configuration for input audio noise reduction.""" - - transcription: Optional[AudioTranscription] = None - """Configuration of the transcription model.""" - - turn_detection: Optional[RealtimeTranscriptionSessionTurnDetection] = None - """Configuration for turn detection. - - Can be set to `null` to turn off. Server VAD means that the model will detect - the start and end of speech based on audio volume and respond at the end of user - speech. - """ - - -class Audio(BaseModel): - """Configuration for input audio for the session.""" - - input: Optional[AudioInput] = None - - -class RealtimeTranscriptionSessionCreateResponse(BaseModel): - """A Realtime transcription session configuration object.""" - - id: str - """Unique identifier for the session that looks like `sess_1234567890abcdef`.""" - - object: str - """The object type. Always `realtime.transcription_session`.""" - - type: Literal["transcription"] - """The type of session. Always `transcription` for transcription sessions.""" - - audio: Optional[Audio] = None - """Configuration for input audio for the session.""" - - expires_at: Optional[int] = None - """Expiration timestamp for the session, in seconds since epoch.""" - - include: Optional[List[Literal["item.input_audio_transcription.logprobs"]]] = None - """Additional fields to include in server outputs. - - - `item.input_audio_transcription.logprobs`: Include logprobs for input audio - transcription. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_turn_detection.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_turn_detection.py deleted file mode 100644 index 8dacd60..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_transcription_session_turn_detection.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["RealtimeTranscriptionSessionTurnDetection"] - - -class RealtimeTranscriptionSessionTurnDetection(BaseModel): - """Configuration for turn detection. - - Can be set to `null` to turn off. Server - VAD means that the model will detect the start and end of speech based on - audio volume and respond at the end of user speech. - """ - - prefix_padding_ms: Optional[int] = None - """Amount of audio to include before the VAD detected speech (in milliseconds). - - Defaults to 300ms. - """ - - silence_duration_ms: Optional[int] = None - """Duration of silence to detect speech stop (in milliseconds). - - Defaults to 500ms. With shorter values the model will respond more quickly, but - may jump in on short pauses from the user. - """ - - threshold: Optional[float] = None - """Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. - - A higher threshold will require louder audio to activate the model, and thus - might perform better in noisy environments. - """ - - type: Optional[str] = None - """Type of turn detection, only `server_vad` is currently supported.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation.py deleted file mode 100644 index 515f869..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .realtime_truncation_retention_ratio import RealtimeTruncationRetentionRatio - -__all__ = ["RealtimeTruncation"] - -RealtimeTruncation: TypeAlias = Union[Literal["auto", "disabled"], RealtimeTruncationRetentionRatio] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_param.py deleted file mode 100644 index 5e42b27..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .realtime_truncation_retention_ratio_param import RealtimeTruncationRetentionRatioParam - -__all__ = ["RealtimeTruncationParam"] - -RealtimeTruncationParam: TypeAlias = Union[Literal["auto", "disabled"], RealtimeTruncationRetentionRatioParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio.py deleted file mode 100644 index 72a93a5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeTruncationRetentionRatio", "TokenLimits"] - - -class TokenLimits(BaseModel): - """Optional custom token limits for this truncation strategy. - - If not provided, the model's default token limits will be used. - """ - - post_instructions: Optional[int] = None - """ - Maximum tokens allowed in the conversation after instructions (which including - tool definitions). For example, setting this to 5,000 would mean that truncation - would occur when the conversation exceeds 5,000 tokens after instructions. This - cannot be higher than the model's context window size minus the maximum output - tokens. - """ - - -class RealtimeTruncationRetentionRatio(BaseModel): - """ - Retain a fraction of the conversation tokens when the conversation exceeds the input token limit. This allows you to amortize truncations across multiple turns, which can help improve cached token usage. - """ - - retention_ratio: float - """ - Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when - the conversation exceeds the input token limit. Setting this to `0.8` means that - messages will be dropped until 80% of the maximum allowed tokens are used. This - helps reduce the frequency of truncations and improve cache rates. - """ - - type: Literal["retention_ratio"] - """Use retention ratio truncation.""" - - token_limits: Optional[TokenLimits] = None - """Optional custom token limits for this truncation strategy. - - If not provided, the model's default token limits will be used. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio_param.py deleted file mode 100644 index 4648fa6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/realtime_truncation_retention_ratio_param.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RealtimeTruncationRetentionRatioParam", "TokenLimits"] - - -class TokenLimits(TypedDict, total=False): - """Optional custom token limits for this truncation strategy. - - If not provided, the model's default token limits will be used. - """ - - post_instructions: int - """ - Maximum tokens allowed in the conversation after instructions (which including - tool definitions). For example, setting this to 5,000 would mean that truncation - would occur when the conversation exceeds 5,000 tokens after instructions. This - cannot be higher than the model's context window size minus the maximum output - tokens. - """ - - -class RealtimeTruncationRetentionRatioParam(TypedDict, total=False): - """ - Retain a fraction of the conversation tokens when the conversation exceeds the input token limit. This allows you to amortize truncations across multiple turns, which can help improve cached token usage. - """ - - retention_ratio: Required[float] - """ - Fraction of post-instruction conversation tokens to retain (`0.0` - `1.0`) when - the conversation exceeds the input token limit. Setting this to `0.8` means that - messages will be dropped until 80% of the maximum allowed tokens are used. This - helps reduce the frequency of truncations and improve cache rates. - """ - - type: Required[Literal["retention_ratio"]] - """Use retention ratio truncation.""" - - token_limits: TokenLimits - """Optional custom token limits for this truncation strategy. - - If not provided, the model's default token limits will be used. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_delta_event.py deleted file mode 100644 index ae87014..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_delta_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioDeltaEvent"] - - -class ResponseAudioDeltaEvent(BaseModel): - """Returned when the model-generated audio is updated.""" - - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """Base64-encoded audio data delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.output_audio.delta"] - """The event type, must be `response.output_audio.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_done_event.py deleted file mode 100644 index 98715ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_done_event.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioDoneEvent"] - - -class ResponseAudioDoneEvent(BaseModel): - """Returned when the model-generated audio is done. - - Also emitted when a Response - is interrupted, incomplete, or cancelled. - """ - - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.output_audio.done"] - """The event type, must be `response.output_audio.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_delta_event.py deleted file mode 100644 index 4ec1a82..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_delta_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDeltaEvent"] - - -class ResponseAudioTranscriptDeltaEvent(BaseModel): - """Returned when the model-generated transcription of audio output is updated.""" - - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """The transcript delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.output_audio_transcript.delta"] - """The event type, must be `response.output_audio_transcript.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_done_event.py deleted file mode 100644 index c2a2416..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_audio_transcript_done_event.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDoneEvent"] - - -class ResponseAudioTranscriptDoneEvent(BaseModel): - """ - Returned when the model-generated transcription of audio output is done - streaming. Also emitted when a Response is interrupted, incomplete, or - cancelled. - """ - - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - transcript: str - """The final transcript of the audio.""" - - type: Literal["response.output_audio_transcript.done"] - """The event type, must be `response.output_audio_transcript.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event.py deleted file mode 100644 index 9c61139..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCancelEvent"] - - -class ResponseCancelEvent(BaseModel): - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. It's safe - to call `response.cancel` even if no response is in progress, an error will be - returned the session will remain unaffected. - """ - - type: Literal["response.cancel"] - """The event type, must be `response.cancel`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - response_id: Optional[str] = None - """ - A specific response ID to cancel - if not provided, will cancel an in-progress - response in the default conversation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event_param.py deleted file mode 100644 index b233b40..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_cancel_event_param.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseCancelEventParam"] - - -class ResponseCancelEventParam(TypedDict, total=False): - """Send this event to cancel an in-progress response. - - The server will respond - with a `response.done` event with a status of `response.status=cancelled`. If - there is no response to cancel, the server will respond with an error. It's safe - to call `response.cancel` even if no response is in progress, an error will be - returned the session will remain unaffected. - """ - - type: Required[Literal["response.cancel"]] - """The event type, must be `response.cancel`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - response_id: str - """ - A specific response ID to cancel - if not provided, will cancel an in-progress - response in the default conversation. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_added_event.py deleted file mode 100644 index e47c84a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_added_event.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseContentPartAddedEvent", "Part"] - - -class Part(BaseModel): - """The content part that was added.""" - - audio: Optional[str] = None - """Base64-encoded audio data (if type is "audio").""" - - text: Optional[str] = None - """The text content (if type is "text").""" - - transcript: Optional[str] = None - """The transcript of the audio (if type is "audio").""" - - type: Optional[Literal["text", "audio"]] = None - """The content type ("text", "audio").""" - - -class ResponseContentPartAddedEvent(BaseModel): - """ - Returned when a new content part is added to an assistant message item during - response generation. - """ - - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item to which the content part was added.""" - - output_index: int - """The index of the output item in the response.""" - - part: Part - """The content part that was added.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.content_part.added"] - """The event type, must be `response.content_part.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_done_event.py deleted file mode 100644 index a6cb855..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_content_part_done_event.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseContentPartDoneEvent", "Part"] - - -class Part(BaseModel): - """The content part that is done.""" - - audio: Optional[str] = None - """Base64-encoded audio data (if type is "audio").""" - - text: Optional[str] = None - """The text content (if type is "text").""" - - transcript: Optional[str] = None - """The transcript of the audio (if type is "audio").""" - - type: Optional[Literal["text", "audio"]] = None - """The content type ("text", "audio").""" - - -class ResponseContentPartDoneEvent(BaseModel): - """ - Returned when a content part is done streaming in an assistant message item. - Also emitted when a Response is interrupted, incomplete, or cancelled. - """ - - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - part: Part - """The content part that is done.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.content_part.done"] - """The event type, must be `response.content_part.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event.py deleted file mode 100644 index 3e98a8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_response_create_params import RealtimeResponseCreateParams - -__all__ = ["ResponseCreateEvent"] - - -class ResponseCreateEvent(BaseModel): - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history by default. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions` and `tools`. If these are set, they will override the Session's - configuration for this Response only. - - Responses can be created out-of-band of the default Conversation, meaning that they can - have arbitrary input, and it's possible to disable writing the output to the Conversation. - Only one Response can write to the default Conversation at a time, but otherwise multiple - Responses can be created in parallel. The `metadata` field is a good way to disambiguate - multiple simultaneous Responses. - - Clients can set `conversation` to `none` to create a Response that does not write to the default - Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting - raw Items and references to existing Items. - """ - - type: Literal["response.create"] - """The event type, must be `response.create`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event.""" - - response: Optional[RealtimeResponseCreateParams] = None - """Create a new Realtime response with these parameters""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event_param.py deleted file mode 100644 index 9da89e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_create_event_param.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .realtime_response_create_params_param import RealtimeResponseCreateParamsParam - -__all__ = ["ResponseCreateEventParam"] - - -class ResponseCreateEventParam(TypedDict, total=False): - """ - This event instructs the server to create a Response, which means triggering - model inference. When in Server VAD mode, the server will create Responses - automatically. - - A Response will include at least one Item, and may have two, in which case - the second will be a function call. These Items will be appended to the - conversation history by default. - - The server will respond with a `response.created` event, events for Items - and content created, and finally a `response.done` event to indicate the - Response is complete. - - The `response.create` event includes inference configuration like - `instructions` and `tools`. If these are set, they will override the Session's - configuration for this Response only. - - Responses can be created out-of-band of the default Conversation, meaning that they can - have arbitrary input, and it's possible to disable writing the output to the Conversation. - Only one Response can write to the default Conversation at a time, but otherwise multiple - Responses can be created in parallel. The `metadata` field is a good way to disambiguate - multiple simultaneous Responses. - - Clients can set `conversation` to `none` to create a Response that does not write to the default - Conversation. Arbitrary input can be provided with the `input` field, which is an array accepting - raw Items and references to existing Items. - """ - - type: Required[Literal["response.create"]] - """The event type, must be `response.create`.""" - - event_id: str - """Optional client-generated ID used to identify this event.""" - - response: RealtimeResponseCreateParamsParam - """Create a new Realtime response with these parameters""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_created_event.py deleted file mode 100644 index dc59412..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_created_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_response import RealtimeResponse - -__all__ = ["ResponseCreatedEvent"] - - -class ResponseCreatedEvent(BaseModel): - """Returned when a new Response is created. - - The first event of response creation, - where the response is in an initial state of `in_progress`. - """ - - event_id: str - """The unique ID of the server event.""" - - response: RealtimeResponse - """The response resource.""" - - type: Literal["response.created"] - """The event type, must be `response.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_done_event.py deleted file mode 100644 index 9c31a2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_done_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .realtime_response import RealtimeResponse - -__all__ = ["ResponseDoneEvent"] - - -class ResponseDoneEvent(BaseModel): - """Returned when a Response is done streaming. - - Always emitted, no matter the - final state. The Response object included in the `response.done` event will - include all output Items in the Response but will omit the raw audio data. - - Clients should check the `status` field of the Response to determine if it was successful - (`completed`) or if there was another outcome: `cancelled`, `failed`, or `incomplete`. - - A response will contain all output items that were generated during the response, excluding - any audio content. - """ - - event_id: str - """The unique ID of the server event.""" - - response: RealtimeResponse - """The response resource.""" - - type: Literal["response.done"] - """The event type, must be `response.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_delta_event.py deleted file mode 100644 index a426c3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_delta_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] - - -class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): - """Returned when the model-generated function call arguments are updated.""" - - call_id: str - """The ID of the function call.""" - - delta: str - """The arguments delta as a JSON string.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the function call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.function_call_arguments.delta"] - """The event type, must be `response.function_call_arguments.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_done_event.py deleted file mode 100644 index 504f91d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_function_call_arguments_done_event.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] - - -class ResponseFunctionCallArgumentsDoneEvent(BaseModel): - """ - Returned when the model-generated function call arguments are done streaming. - Also emitted when a Response is interrupted, incomplete, or cancelled. - """ - - arguments: str - """The final arguments as a JSON string.""" - - call_id: str - """The ID of the function call.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the function call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.function_call_arguments.done"] - """The event type, must be `response.function_call_arguments.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_delta.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_delta.py deleted file mode 100644 index d890de0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_delta.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallArgumentsDelta"] - - -class ResponseMcpCallArgumentsDelta(BaseModel): - """Returned when MCP tool call arguments are updated during response generation.""" - - delta: str - """The JSON-encoded arguments delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP tool call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.mcp_call_arguments.delta"] - """The event type, must be `response.mcp_call_arguments.delta`.""" - - obfuscation: Optional[str] = None - """If present, indicates the delta text was obfuscated.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_done.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_done.py deleted file mode 100644 index a7cb2d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_arguments_done.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallArgumentsDone"] - - -class ResponseMcpCallArgumentsDone(BaseModel): - """Returned when MCP tool call arguments are finalized during response generation.""" - - arguments: str - """The final JSON-encoded arguments string.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP tool call item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.mcp_call_arguments.done"] - """The event type, must be `response.mcp_call_arguments.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_completed.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_completed.py deleted file mode 100644 index 1302605..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_completed.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallCompleted"] - - -class ResponseMcpCallCompleted(BaseModel): - """Returned when an MCP tool call has completed successfully.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP tool call item.""" - - output_index: int - """The index of the output item in the response.""" - - type: Literal["response.mcp_call.completed"] - """The event type, must be `response.mcp_call.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_failed.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_failed.py deleted file mode 100644 index 1c08d1d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_failed.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallFailed"] - - -class ResponseMcpCallFailed(BaseModel): - """Returned when an MCP tool call has failed.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP tool call item.""" - - output_index: int - """The index of the output item in the response.""" - - type: Literal["response.mcp_call.failed"] - """The event type, must be `response.mcp_call.failed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_in_progress.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_in_progress.py deleted file mode 100644 index 4c0ad14..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_mcp_call_in_progress.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallInProgress"] - - -class ResponseMcpCallInProgress(BaseModel): - """Returned when an MCP tool call has started and is in progress.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the MCP tool call item.""" - - output_index: int - """The index of the output item in the response.""" - - type: Literal["response.mcp_call.in_progress"] - """The event type, must be `response.mcp_call.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_added_event.py deleted file mode 100644 index abec0d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_added_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ResponseOutputItemAddedEvent"] - - -class ResponseOutputItemAddedEvent(BaseModel): - """Returned when a new Item is created during Response generation.""" - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - output_index: int - """The index of the output item in the Response.""" - - response_id: str - """The ID of the Response to which the item belongs.""" - - type: Literal["response.output_item.added"] - """The event type, must be `response.output_item.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_done_event.py deleted file mode 100644 index 63936b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_output_item_done_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .conversation_item import ConversationItem - -__all__ = ["ResponseOutputItemDoneEvent"] - - -class ResponseOutputItemDoneEvent(BaseModel): - """Returned when an Item is done streaming. - - Also emitted when a Response is - interrupted, incomplete, or cancelled. - """ - - event_id: str - """The unique ID of the server event.""" - - item: ConversationItem - """A single item within a Realtime conversation.""" - - output_index: int - """The index of the output item in the Response.""" - - response_id: str - """The ID of the Response to which the item belongs.""" - - type: Literal["response.output_item.done"] - """The event type, must be `response.output_item.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_delta_event.py deleted file mode 100644 index b251b76..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_delta_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseTextDeltaEvent"] - - -class ResponseTextDeltaEvent(BaseModel): - """Returned when the text value of an "output_text" content part is updated.""" - - content_index: int - """The index of the content part in the item's content array.""" - - delta: str - """The text delta.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - type: Literal["response.output_text.delta"] - """The event type, must be `response.output_text.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_done_event.py deleted file mode 100644 index 046e520..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/response_text_done_event.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseTextDoneEvent"] - - -class ResponseTextDoneEvent(BaseModel): - """Returned when the text value of an "output_text" content part is done streaming. - - Also - emitted when a Response is interrupted, incomplete, or cancelled. - """ - - content_index: int - """The index of the content part in the item's content array.""" - - event_id: str - """The unique ID of the server event.""" - - item_id: str - """The ID of the item.""" - - output_index: int - """The index of the output item in the response.""" - - response_id: str - """The ID of the response.""" - - text: str - """The final text content.""" - - type: Literal["response.output_text.done"] - """The event type, must be `response.output_text.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_created_event.py deleted file mode 100644 index 1b8d4a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_created_event.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .realtime_session_create_request import RealtimeSessionCreateRequest -from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest - -__all__ = ["SessionCreatedEvent", "Session"] - -Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] - - -class SessionCreatedEvent(BaseModel): - """Returned when a Session is created. - - Emitted automatically when a new - connection is established as the first server event. This event will contain - the default Session configuration. - """ - - event_id: str - """The unique ID of the server event.""" - - session: Session - """The session configuration.""" - - type: Literal["session.created"] - """The event type, must be `session.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event.py deleted file mode 100644 index a8422e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .realtime_session_create_request import RealtimeSessionCreateRequest -from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest - -__all__ = ["SessionUpdateEvent", "Session"] - -Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] - - -class SessionUpdateEvent(BaseModel): - """ - Send this event to update the session’s configuration. - The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present in the `session.update` are updated. To clear a field like - `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. - To clear a field like `turn_detection`, pass `null`. - """ - - session: Session - """Update the Realtime session. - - Choose either a realtime session or a transcription session. - """ - - type: Literal["session.update"] - """The event type, must be `session.update`.""" - - event_id: Optional[str] = None - """Optional client-generated ID used to identify this event. - - This is an arbitrary string that a client may assign. It will be passed back if - there is an error with the event, but the corresponding `session.updated` event - will not include it. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event_param.py deleted file mode 100644 index 910e89c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_update_event_param.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .realtime_session_create_request_param import RealtimeSessionCreateRequestParam -from .realtime_transcription_session_create_request_param import RealtimeTranscriptionSessionCreateRequestParam - -__all__ = ["SessionUpdateEventParam", "Session"] - -Session: TypeAlias = Union[RealtimeSessionCreateRequestParam, RealtimeTranscriptionSessionCreateRequestParam] - - -class SessionUpdateEventParam(TypedDict, total=False): - """ - Send this event to update the session’s configuration. - The client may send this event at any time to update any field - except for `voice` and `model`. `voice` can be updated only if there have been no other audio outputs yet. - - When the server receives a `session.update`, it will respond - with a `session.updated` event showing the full, effective configuration. - Only the fields that are present in the `session.update` are updated. To clear a field like - `instructions`, pass an empty string. To clear a field like `tools`, pass an empty array. - To clear a field like `turn_detection`, pass `null`. - """ - - session: Required[Session] - """Update the Realtime session. - - Choose either a realtime session or a transcription session. - """ - - type: Required[Literal["session.update"]] - """The event type, must be `session.update`.""" - - event_id: str - """Optional client-generated ID used to identify this event. - - This is an arbitrary string that a client may assign. It will be passed back if - there is an error with the event, but the corresponding `session.updated` event - will not include it. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_updated_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_updated_event.py deleted file mode 100644 index e68a08d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/realtime/session_updated_event.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .realtime_session_create_request import RealtimeSessionCreateRequest -from .realtime_transcription_session_create_request import RealtimeTranscriptionSessionCreateRequest - -__all__ = ["SessionUpdatedEvent", "Session"] - -Session: TypeAlias = Union[RealtimeSessionCreateRequest, RealtimeTranscriptionSessionCreateRequest] - - -class SessionUpdatedEvent(BaseModel): - """ - Returned when a session is updated with a `session.update` event, unless - there is an error. - """ - - event_id: str - """The unique ID of the server event.""" - - session: Session - """The session configuration.""" - - type: Literal["session.updated"] - """The event type, must be `session.updated`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/__init__.py deleted file mode 100644 index a4d939d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/__init__.py +++ /dev/null @@ -1,275 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .tool import Tool as Tool -from .response import Response as Response -from .tool_param import ToolParam as ToolParam -from .custom_tool import CustomTool as CustomTool -from .computer_tool import ComputerTool as ComputerTool -from .function_tool import FunctionTool as FunctionTool -from .response_item import ResponseItem as ResponseItem -from .response_error import ResponseError as ResponseError -from .response_usage import ResponseUsage as ResponseUsage -from .parsed_response import ( - ParsedContent as ParsedContent, - ParsedResponse as ParsedResponse, - ParsedResponseOutputItem as ParsedResponseOutputItem, - ParsedResponseOutputText as ParsedResponseOutputText, - ParsedResponseOutputMessage as ParsedResponseOutputMessage, - ParsedResponseFunctionToolCall as ParsedResponseFunctionToolCall, -) -from .response_prompt import ResponsePrompt as ResponsePrompt -from .response_status import ResponseStatus as ResponseStatus -from .tool_choice_mcp import ToolChoiceMcp as ToolChoiceMcp -from .web_search_tool import WebSearchTool as WebSearchTool -from .apply_patch_tool import ApplyPatchTool as ApplyPatchTool -from .file_search_tool import FileSearchTool as FileSearchTool -from .custom_tool_param import CustomToolParam as CustomToolParam -from .tool_choice_shell import ToolChoiceShell as ToolChoiceShell -from .tool_choice_types import ToolChoiceTypes as ToolChoiceTypes -from .compacted_response import CompactedResponse as CompactedResponse -from .easy_input_message import EasyInputMessage as EasyInputMessage -from .response_item_list import ResponseItemList as ResponseItemList -from .tool_choice_custom import ToolChoiceCustom as ToolChoiceCustom -from .computer_tool_param import ComputerToolParam as ComputerToolParam -from .function_shell_tool import FunctionShellTool as FunctionShellTool -from .function_tool_param import FunctionToolParam as FunctionToolParam -from .response_includable import ResponseIncludable as ResponseIncludable -from .response_input_file import ResponseInputFile as ResponseInputFile -from .response_input_item import ResponseInputItem as ResponseInputItem -from .response_input_text import ResponseInputText as ResponseInputText -from .tool_choice_allowed import ToolChoiceAllowed as ToolChoiceAllowed -from .tool_choice_options import ToolChoiceOptions as ToolChoiceOptions -from .response_error_event import ResponseErrorEvent as ResponseErrorEvent -from .response_input_audio import ResponseInputAudio as ResponseInputAudio -from .response_input_image import ResponseInputImage as ResponseInputImage -from .response_input_param import ResponseInputParam as ResponseInputParam -from .response_output_item import ResponseOutputItem as ResponseOutputItem -from .response_output_text import ResponseOutputText as ResponseOutputText -from .response_text_config import ResponseTextConfig as ResponseTextConfig -from .tool_choice_function import ToolChoiceFunction as ToolChoiceFunction -from .response_failed_event import ResponseFailedEvent as ResponseFailedEvent -from .response_prompt_param import ResponsePromptParam as ResponsePromptParam -from .response_queued_event import ResponseQueuedEvent as ResponseQueuedEvent -from .response_stream_event import ResponseStreamEvent as ResponseStreamEvent -from .tool_choice_mcp_param import ToolChoiceMcpParam as ToolChoiceMcpParam -from .web_search_tool_param import WebSearchToolParam as WebSearchToolParam -from .apply_patch_tool_param import ApplyPatchToolParam as ApplyPatchToolParam -from .file_search_tool_param import FileSearchToolParam as FileSearchToolParam -from .input_item_list_params import InputItemListParams as InputItemListParams -from .response_create_params import ResponseCreateParams as ResponseCreateParams -from .response_created_event import ResponseCreatedEvent as ResponseCreatedEvent -from .response_input_content import ResponseInputContent as ResponseInputContent -from .response_compact_params import ResponseCompactParams as ResponseCompactParams -from .response_output_message import ResponseOutputMessage as ResponseOutputMessage -from .response_output_refusal import ResponseOutputRefusal as ResponseOutputRefusal -from .response_reasoning_item import ResponseReasoningItem as ResponseReasoningItem -from .tool_choice_apply_patch import ToolChoiceApplyPatch as ToolChoiceApplyPatch -from .tool_choice_shell_param import ToolChoiceShellParam as ToolChoiceShellParam -from .tool_choice_types_param import ToolChoiceTypesParam as ToolChoiceTypesParam -from .web_search_preview_tool import WebSearchPreviewTool as WebSearchPreviewTool -from .easy_input_message_param import EasyInputMessageParam as EasyInputMessageParam -from .input_token_count_params import InputTokenCountParams as InputTokenCountParams -from .response_compaction_item import ResponseCompactionItem as ResponseCompactionItem -from .response_completed_event import ResponseCompletedEvent as ResponseCompletedEvent -from .response_retrieve_params import ResponseRetrieveParams as ResponseRetrieveParams -from .response_text_done_event import ResponseTextDoneEvent as ResponseTextDoneEvent -from .tool_choice_custom_param import ToolChoiceCustomParam as ToolChoiceCustomParam -from .function_shell_tool_param import FunctionShellToolParam as FunctionShellToolParam -from .response_audio_done_event import ResponseAudioDoneEvent as ResponseAudioDoneEvent -from .response_custom_tool_call import ResponseCustomToolCall as ResponseCustomToolCall -from .response_incomplete_event import ResponseIncompleteEvent as ResponseIncompleteEvent -from .response_input_file_param import ResponseInputFileParam as ResponseInputFileParam -from .response_input_item_param import ResponseInputItemParam as ResponseInputItemParam -from .response_input_text_param import ResponseInputTextParam as ResponseInputTextParam -from .response_text_delta_event import ResponseTextDeltaEvent as ResponseTextDeltaEvent -from .tool_choice_allowed_param import ToolChoiceAllowedParam as ToolChoiceAllowedParam -from .input_token_count_response import InputTokenCountResponse as InputTokenCountResponse -from .response_audio_delta_event import ResponseAudioDeltaEvent as ResponseAudioDeltaEvent -from .response_in_progress_event import ResponseInProgressEvent as ResponseInProgressEvent -from .response_input_audio_param import ResponseInputAudioParam as ResponseInputAudioParam -from .response_input_image_param import ResponseInputImageParam as ResponseInputImageParam -from .response_output_text_param import ResponseOutputTextParam as ResponseOutputTextParam -from .response_text_config_param import ResponseTextConfigParam as ResponseTextConfigParam -from .tool_choice_function_param import ToolChoiceFunctionParam as ToolChoiceFunctionParam -from .response_computer_tool_call import ResponseComputerToolCall as ResponseComputerToolCall -from .response_conversation_param import ResponseConversationParam as ResponseConversationParam -from .response_format_text_config import ResponseFormatTextConfig as ResponseFormatTextConfig -from .response_function_tool_call import ResponseFunctionToolCall as ResponseFunctionToolCall -from .response_input_file_content import ResponseInputFileContent as ResponseInputFileContent -from .response_input_message_item import ResponseInputMessageItem as ResponseInputMessageItem -from .response_input_text_content import ResponseInputTextContent as ResponseInputTextContent -from .response_refusal_done_event import ResponseRefusalDoneEvent as ResponseRefusalDoneEvent -from .response_function_web_search import ResponseFunctionWebSearch as ResponseFunctionWebSearch -from .response_input_content_param import ResponseInputContentParam as ResponseInputContentParam -from .response_input_image_content import ResponseInputImageContent as ResponseInputImageContent -from .response_refusal_delta_event import ResponseRefusalDeltaEvent as ResponseRefusalDeltaEvent -from .response_output_message_param import ResponseOutputMessageParam as ResponseOutputMessageParam -from .response_output_refusal_param import ResponseOutputRefusalParam as ResponseOutputRefusalParam -from .response_reasoning_item_param import ResponseReasoningItemParam as ResponseReasoningItemParam -from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam as ToolChoiceApplyPatchParam -from .web_search_preview_tool_param import WebSearchPreviewToolParam as WebSearchPreviewToolParam -from .response_apply_patch_tool_call import ResponseApplyPatchToolCall as ResponseApplyPatchToolCall -from .response_compaction_item_param import ResponseCompactionItemParam as ResponseCompactionItemParam -from .response_file_search_tool_call import ResponseFileSearchToolCall as ResponseFileSearchToolCall -from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent as ResponseMcpCallFailedEvent -from .response_custom_tool_call_param import ResponseCustomToolCallParam as ResponseCustomToolCallParam -from .response_output_item_done_event import ResponseOutputItemDoneEvent as ResponseOutputItemDoneEvent -from .response_content_part_done_event import ResponseContentPartDoneEvent as ResponseContentPartDoneEvent -from .response_custom_tool_call_output import ResponseCustomToolCallOutput as ResponseCustomToolCallOutput -from .response_function_tool_call_item import ResponseFunctionToolCallItem as ResponseFunctionToolCallItem -from .response_output_item_added_event import ResponseOutputItemAddedEvent as ResponseOutputItemAddedEvent -from .response_computer_tool_call_param import ResponseComputerToolCallParam as ResponseComputerToolCallParam -from .response_content_part_added_event import ResponseContentPartAddedEvent as ResponseContentPartAddedEvent -from .response_format_text_config_param import ResponseFormatTextConfigParam as ResponseFormatTextConfigParam -from .response_function_shell_tool_call import ResponseFunctionShellToolCall as ResponseFunctionShellToolCall -from .response_function_tool_call_param import ResponseFunctionToolCallParam as ResponseFunctionToolCallParam -from .response_input_file_content_param import ResponseInputFileContentParam as ResponseInputFileContentParam -from .response_input_text_content_param import ResponseInputTextContentParam as ResponseInputTextContentParam -from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent as ResponseMcpCallCompletedEvent -from .response_function_call_output_item import ResponseFunctionCallOutputItem as ResponseFunctionCallOutputItem -from .response_function_web_search_param import ResponseFunctionWebSearchParam as ResponseFunctionWebSearchParam -from .response_input_image_content_param import ResponseInputImageContentParam as ResponseInputImageContentParam -from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent as ResponseReasoningTextDoneEvent -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall as ResponseCodeInterpreterToolCall -from .response_input_message_content_list import ResponseInputMessageContentList as ResponseInputMessageContentList -from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent as ResponseMcpCallInProgressEvent -from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent as ResponseReasoningTextDeltaEvent -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent as ResponseAudioTranscriptDoneEvent -from .response_compaction_item_param_param import ResponseCompactionItemParamParam as ResponseCompactionItemParamParam -from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam as ResponseFileSearchToolCallParam -from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent as ResponseMcpListToolsFailedEvent -from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput as ResponseApplyPatchToolCallOutput -from .response_audio_transcript_delta_event import ( - ResponseAudioTranscriptDeltaEvent as ResponseAudioTranscriptDeltaEvent, -) -from .response_custom_tool_call_output_param import ( - ResponseCustomToolCallOutputParam as ResponseCustomToolCallOutputParam, -) -from .response_mcp_call_arguments_done_event import ( - ResponseMcpCallArgumentsDoneEvent as ResponseMcpCallArgumentsDoneEvent, -) -from .response_computer_tool_call_output_item import ( - ResponseComputerToolCallOutputItem as ResponseComputerToolCallOutputItem, -) -from .response_format_text_json_schema_config import ( - ResponseFormatTextJSONSchemaConfig as ResponseFormatTextJSONSchemaConfig, -) -from .response_function_call_output_item_list import ( - ResponseFunctionCallOutputItemList as ResponseFunctionCallOutputItemList, -) -from .response_function_tool_call_output_item import ( - ResponseFunctionToolCallOutputItem as ResponseFunctionToolCallOutputItem, -) -from .response_image_gen_call_completed_event import ( - ResponseImageGenCallCompletedEvent as ResponseImageGenCallCompletedEvent, -) -from .response_mcp_call_arguments_delta_event import ( - ResponseMcpCallArgumentsDeltaEvent as ResponseMcpCallArgumentsDeltaEvent, -) -from .response_mcp_list_tools_completed_event import ( - ResponseMcpListToolsCompletedEvent as ResponseMcpListToolsCompletedEvent, -) -from .response_function_call_output_item_param import ( - ResponseFunctionCallOutputItemParam as ResponseFunctionCallOutputItemParam, -) -from .response_function_shell_tool_call_output import ( - ResponseFunctionShellToolCallOutput as ResponseFunctionShellToolCallOutput, -) -from .response_image_gen_call_generating_event import ( - ResponseImageGenCallGeneratingEvent as ResponseImageGenCallGeneratingEvent, -) -from .response_web_search_call_completed_event import ( - ResponseWebSearchCallCompletedEvent as ResponseWebSearchCallCompletedEvent, -) -from .response_web_search_call_searching_event import ( - ResponseWebSearchCallSearchingEvent as ResponseWebSearchCallSearchingEvent, -) -from .response_code_interpreter_tool_call_param import ( - ResponseCodeInterpreterToolCallParam as ResponseCodeInterpreterToolCallParam, -) -from .response_file_search_call_completed_event import ( - ResponseFileSearchCallCompletedEvent as ResponseFileSearchCallCompletedEvent, -) -from .response_file_search_call_searching_event import ( - ResponseFileSearchCallSearchingEvent as ResponseFileSearchCallSearchingEvent, -) -from .response_image_gen_call_in_progress_event import ( - ResponseImageGenCallInProgressEvent as ResponseImageGenCallInProgressEvent, -) -from .response_input_message_content_list_param import ( - ResponseInputMessageContentListParam as ResponseInputMessageContentListParam, -) -from .response_mcp_list_tools_in_progress_event import ( - ResponseMcpListToolsInProgressEvent as ResponseMcpListToolsInProgressEvent, -) -from .response_custom_tool_call_input_done_event import ( - ResponseCustomToolCallInputDoneEvent as ResponseCustomToolCallInputDoneEvent, -) -from .response_reasoning_summary_part_done_event import ( - ResponseReasoningSummaryPartDoneEvent as ResponseReasoningSummaryPartDoneEvent, -) -from .response_reasoning_summary_text_done_event import ( - ResponseReasoningSummaryTextDoneEvent as ResponseReasoningSummaryTextDoneEvent, -) -from .response_web_search_call_in_progress_event import ( - ResponseWebSearchCallInProgressEvent as ResponseWebSearchCallInProgressEvent, -) -from .response_custom_tool_call_input_delta_event import ( - ResponseCustomToolCallInputDeltaEvent as ResponseCustomToolCallInputDeltaEvent, -) -from .response_file_search_call_in_progress_event import ( - ResponseFileSearchCallInProgressEvent as ResponseFileSearchCallInProgressEvent, -) -from .response_function_call_arguments_done_event import ( - ResponseFunctionCallArgumentsDoneEvent as ResponseFunctionCallArgumentsDoneEvent, -) -from .response_function_shell_call_output_content import ( - ResponseFunctionShellCallOutputContent as ResponseFunctionShellCallOutputContent, -) -from .response_image_gen_call_partial_image_event import ( - ResponseImageGenCallPartialImageEvent as ResponseImageGenCallPartialImageEvent, -) -from .response_output_text_annotation_added_event import ( - ResponseOutputTextAnnotationAddedEvent as ResponseOutputTextAnnotationAddedEvent, -) -from .response_reasoning_summary_part_added_event import ( - ResponseReasoningSummaryPartAddedEvent as ResponseReasoningSummaryPartAddedEvent, -) -from .response_reasoning_summary_text_delta_event import ( - ResponseReasoningSummaryTextDeltaEvent as ResponseReasoningSummaryTextDeltaEvent, -) -from .response_function_call_arguments_delta_event import ( - ResponseFunctionCallArgumentsDeltaEvent as ResponseFunctionCallArgumentsDeltaEvent, -) -from .response_computer_tool_call_output_screenshot import ( - ResponseComputerToolCallOutputScreenshot as ResponseComputerToolCallOutputScreenshot, -) -from .response_format_text_json_schema_config_param import ( - ResponseFormatTextJSONSchemaConfigParam as ResponseFormatTextJSONSchemaConfigParam, -) -from .response_function_call_output_item_list_param import ( - ResponseFunctionCallOutputItemListParam as ResponseFunctionCallOutputItemListParam, -) -from .response_code_interpreter_call_code_done_event import ( - ResponseCodeInterpreterCallCodeDoneEvent as ResponseCodeInterpreterCallCodeDoneEvent, -) -from .response_code_interpreter_call_completed_event import ( - ResponseCodeInterpreterCallCompletedEvent as ResponseCodeInterpreterCallCompletedEvent, -) -from .response_code_interpreter_call_code_delta_event import ( - ResponseCodeInterpreterCallCodeDeltaEvent as ResponseCodeInterpreterCallCodeDeltaEvent, -) -from .response_code_interpreter_call_in_progress_event import ( - ResponseCodeInterpreterCallInProgressEvent as ResponseCodeInterpreterCallInProgressEvent, -) -from .response_code_interpreter_call_interpreting_event import ( - ResponseCodeInterpreterCallInterpretingEvent as ResponseCodeInterpreterCallInterpretingEvent, -) -from .response_function_shell_call_output_content_param import ( - ResponseFunctionShellCallOutputContentParam as ResponseFunctionShellCallOutputContentParam, -) -from .response_computer_tool_call_output_screenshot_param import ( - ResponseComputerToolCallOutputScreenshotParam as ResponseComputerToolCallOutputScreenshotParam, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool.py deleted file mode 100644 index f2ed245..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ApplyPatchTool"] - - -class ApplyPatchTool(BaseModel): - """Allows the assistant to create, delete, or update files using unified diffs.""" - - type: Literal["apply_patch"] - """The type of the tool. Always `apply_patch`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool_param.py deleted file mode 100644 index 2e0a809..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/apply_patch_tool_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ApplyPatchToolParam"] - - -class ApplyPatchToolParam(TypedDict, total=False): - """Allows the assistant to create, delete, or update files using unified diffs.""" - - type: Required[Literal["apply_patch"]] - """The type of the tool. Always `apply_patch`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/compacted_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/compacted_response.py deleted file mode 100644 index 5b333b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/compacted_response.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_usage import ResponseUsage -from .response_output_item import ResponseOutputItem - -__all__ = ["CompactedResponse"] - - -class CompactedResponse(BaseModel): - id: str - """The unique identifier for the compacted response.""" - - created_at: int - """Unix timestamp (in seconds) when the compacted conversation was created.""" - - object: Literal["response.compaction"] - """The object type. Always `response.compaction`.""" - - output: List[ResponseOutputItem] - """The compacted list of output items. - - This is a list of all user messages, followed by a single compaction item. - """ - - usage: ResponseUsage - """ - Token accounting for the compaction pass, including cached, reasoning, and total - tokens. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool.py deleted file mode 100644 index 22871c8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ComputerTool"] - - -class ComputerTool(BaseModel): - """A tool that controls a virtual computer. - - Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). - """ - - display_height: int - """The height of the computer display.""" - - display_width: int - """The width of the computer display.""" - - environment: Literal["windows", "mac", "linux", "ubuntu", "browser"] - """The type of computer environment to control.""" - - type: Literal["computer_use_preview"] - """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool_param.py deleted file mode 100644 index cdf75a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/computer_tool_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ComputerToolParam"] - - -class ComputerToolParam(TypedDict, total=False): - """A tool that controls a virtual computer. - - Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). - """ - - display_height: Required[int] - """The height of the computer display.""" - - display_width: Required[int] - """The width of the computer display.""" - - environment: Required[Literal["windows", "mac", "linux", "ubuntu", "browser"]] - """The type of computer environment to control.""" - - type: Required[Literal["computer_use_preview"]] - """The type of the computer use tool. Always `computer_use_preview`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool.py deleted file mode 100644 index 1ca401a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.custom_tool_input_format import CustomToolInputFormat - -__all__ = ["CustomTool"] - - -class CustomTool(BaseModel): - """A custom tool that processes input using a specified format. - - Learn more about [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - """ - - name: str - """The name of the custom tool, used to identify it in tool calls.""" - - type: Literal["custom"] - """The type of the custom tool. Always `custom`.""" - - description: Optional[str] = None - """Optional description of the custom tool, used to provide more context.""" - - format: Optional[CustomToolInputFormat] = None - """The input format for the custom tool. Default is unconstrained text.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool_param.py deleted file mode 100644 index 4ce43cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/custom_tool_param.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ..shared_params.custom_tool_input_format import CustomToolInputFormat - -__all__ = ["CustomToolParam"] - - -class CustomToolParam(TypedDict, total=False): - """A custom tool that processes input using a specified format. - - Learn more about [custom tools](https://platform.openai.com/docs/guides/function-calling#custom-tools) - """ - - name: Required[str] - """The name of the custom tool, used to identify it in tool calls.""" - - type: Required[Literal["custom"]] - """The type of the custom tool. Always `custom`.""" - - description: str - """Optional description of the custom tool, used to provide more context.""" - - format: CustomToolInputFormat - """The input format for the custom tool. Default is unconstrained text.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message.py deleted file mode 100644 index 9a36a6b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_input_message_content_list import ResponseInputMessageContentList - -__all__ = ["EasyInputMessage"] - - -class EasyInputMessage(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Union[str, ResponseInputMessageContentList] - """ - Text, image, or audio input to the model, used to generate a response. Can also - contain previous assistant responses. - """ - - role: Literal["user", "assistant", "system", "developer"] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message_param.py deleted file mode 100644 index 0a382bd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/easy_input_message_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -from .response_input_message_content_list_param import ResponseInputMessageContentListParam - -__all__ = ["EasyInputMessageParam"] - - -class EasyInputMessageParam(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. Messages with the - `assistant` role are presumed to have been generated by the model in previous - interactions. - """ - - content: Required[Union[str, ResponseInputMessageContentListParam]] - """ - Text, image, or audio input to the model, used to generate a response. Can also - contain previous assistant responses. - """ - - role: Required[Literal["user", "assistant", "system", "developer"]] - """The role of the message input. - - One of `user`, `assistant`, `system`, or `developer`. - """ - - type: Literal["message"] - """The type of the message input. Always `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool.py deleted file mode 100644 index 09c1287..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..shared.compound_filter import CompoundFilter -from ..shared.comparison_filter import ComparisonFilter - -__all__ = ["FileSearchTool", "Filters", "RankingOptions", "RankingOptionsHybridSearch"] - -Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter, None] - - -class RankingOptionsHybridSearch(BaseModel): - """ - Weights that control how reciprocal rank fusion balances semantic embedding matches versus sparse keyword matches when hybrid search is enabled. - """ - - embedding_weight: float - """The weight of the embedding in the reciprocal ranking fusion.""" - - text_weight: float - """The weight of the text in the reciprocal ranking fusion.""" - - -class RankingOptions(BaseModel): - """Ranking options for search.""" - - hybrid_search: Optional[RankingOptionsHybridSearch] = None - """ - Weights that control how reciprocal rank fusion balances semantic embedding - matches versus sparse keyword matches when hybrid search is enabled. - """ - - ranker: Optional[Literal["auto", "default-2024-11-15"]] = None - """The ranker to use for the file search.""" - - score_threshold: Optional[float] = None - """The score threshold for the file search, a number between 0 and 1. - - Numbers closer to 1 will attempt to return only the most relevant results, but - may return fewer results. - """ - - -class FileSearchTool(BaseModel): - """A tool that searches for relevant content from uploaded files. - - Learn more about the [file search tool](https://platform.openai.com/docs/guides/tools-file-search). - """ - - type: Literal["file_search"] - """The type of the file search tool. Always `file_search`.""" - - vector_store_ids: List[str] - """The IDs of the vector stores to search.""" - - filters: Optional[Filters] = None - """A filter to apply.""" - - max_num_results: Optional[int] = None - """The maximum number of results to return. - - This number should be between 1 and 50 inclusive. - """ - - ranking_options: Optional[RankingOptions] = None - """Ranking options for search.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool_param.py deleted file mode 100644 index 82831d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/file_search_tool_param.py +++ /dev/null @@ -1,71 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..shared_params.compound_filter import CompoundFilter -from ..shared_params.comparison_filter import ComparisonFilter - -__all__ = ["FileSearchToolParam", "Filters", "RankingOptions", "RankingOptionsHybridSearch"] - -Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] - - -class RankingOptionsHybridSearch(TypedDict, total=False): - """ - Weights that control how reciprocal rank fusion balances semantic embedding matches versus sparse keyword matches when hybrid search is enabled. - """ - - embedding_weight: Required[float] - """The weight of the embedding in the reciprocal ranking fusion.""" - - text_weight: Required[float] - """The weight of the text in the reciprocal ranking fusion.""" - - -class RankingOptions(TypedDict, total=False): - """Ranking options for search.""" - - hybrid_search: RankingOptionsHybridSearch - """ - Weights that control how reciprocal rank fusion balances semantic embedding - matches versus sparse keyword matches when hybrid search is enabled. - """ - - ranker: Literal["auto", "default-2024-11-15"] - """The ranker to use for the file search.""" - - score_threshold: float - """The score threshold for the file search, a number between 0 and 1. - - Numbers closer to 1 will attempt to return only the most relevant results, but - may return fewer results. - """ - - -class FileSearchToolParam(TypedDict, total=False): - """A tool that searches for relevant content from uploaded files. - - Learn more about the [file search tool](https://platform.openai.com/docs/guides/tools-file-search). - """ - - type: Required[Literal["file_search"]] - """The type of the file search tool. Always `file_search`.""" - - vector_store_ids: Required[SequenceNotStr[str]] - """The IDs of the vector stores to search.""" - - filters: Optional[Filters] - """A filter to apply.""" - - max_num_results: int - """The maximum number of results to return. - - This number should be between 1 and 50 inclusive. - """ - - ranking_options: RankingOptions - """Ranking options for search.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool.py deleted file mode 100644 index 5b237aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FunctionShellTool"] - - -class FunctionShellTool(BaseModel): - """A tool that allows the model to execute shell commands.""" - - type: Literal["shell"] - """The type of the shell tool. Always `shell`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool_param.py deleted file mode 100644 index c640dda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_shell_tool_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FunctionShellToolParam"] - - -class FunctionShellToolParam(TypedDict, total=False): - """A tool that allows the model to execute shell commands.""" - - type: Required[Literal["shell"]] - """The type of the shell tool. Always `shell`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool.py deleted file mode 100644 index b0827a9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FunctionTool"] - - -class FunctionTool(BaseModel): - """Defines a function in your own code the model can choose to call. - - Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - name: str - """The name of the function to call.""" - - parameters: Optional[Dict[str, object]] = None - """A JSON schema object describing the parameters of the function.""" - - strict: Optional[bool] = None - """Whether to enforce strict parameter validation. Default `true`.""" - - type: Literal["function"] - """The type of the function tool. Always `function`.""" - - description: Optional[str] = None - """A description of the function. - - Used by the model to determine whether or not to call the function. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool_param.py deleted file mode 100644 index ba0a316..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/function_tool_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FunctionToolParam"] - - -class FunctionToolParam(TypedDict, total=False): - """Defines a function in your own code the model can choose to call. - - Learn more about [function calling](https://platform.openai.com/docs/guides/function-calling). - """ - - name: Required[str] - """The name of the function to call.""" - - parameters: Required[Optional[Dict[str, object]]] - """A JSON schema object describing the parameters of the function.""" - - strict: Required[Optional[bool]] - """Whether to enforce strict parameter validation. Default `true`.""" - - type: Required[Literal["function"]] - """The type of the function tool. Always `function`.""" - - description: Optional[str] - """A description of the function. - - Used by the model to determine whether or not to call the function. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_item_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_item_list_params.py deleted file mode 100644 index 44a8dc5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_item_list_params.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, TypedDict - -from .response_includable import ResponseIncludable - -__all__ = ["InputItemListParams"] - - -class InputItemListParams(TypedDict, total=False): - after: str - """An item ID to list items after, used in pagination.""" - - include: List[ResponseIncludable] - """Additional fields to include in the response. - - See the `include` parameter for Response creation above for more information. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """The order to return the input items in. Default is `desc`. - - - `asc`: Return the input items in ascending order. - - `desc`: Return the input items in descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_params.py deleted file mode 100644 index 97ee4bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_params.py +++ /dev/null @@ -1,146 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, TypeAlias, TypedDict - -from .tool_param import ToolParam -from .tool_choice_options import ToolChoiceOptions -from .tool_choice_mcp_param import ToolChoiceMcpParam -from .tool_choice_shell_param import ToolChoiceShellParam -from .tool_choice_types_param import ToolChoiceTypesParam -from ..shared_params.reasoning import Reasoning -from .tool_choice_custom_param import ToolChoiceCustomParam -from .response_input_item_param import ResponseInputItemParam -from .tool_choice_allowed_param import ToolChoiceAllowedParam -from .tool_choice_function_param import ToolChoiceFunctionParam -from .response_conversation_param import ResponseConversationParam -from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam -from .response_format_text_config_param import ResponseFormatTextConfigParam - -__all__ = ["InputTokenCountParams", "Conversation", "Text", "ToolChoice"] - - -class InputTokenCountParams(TypedDict, total=False): - conversation: Optional[Conversation] - """The conversation that this response belongs to. - - Items from this conversation are prepended to `input_items` for this response - request. Input items and output items from this response are automatically added - to this conversation after this response completes. - """ - - input: Union[str, Iterable[ResponseInputItemParam], None] - """Text, image, or file inputs to the model, used to generate a response""" - - instructions: Optional[str] - """ - A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - """ - - model: Optional[str] - """Model ID used to generate the response, like `gpt-4o` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - parallel_tool_calls: Optional[bool] - """Whether to allow the model to run tool calls in parallel.""" - - previous_response_id: Optional[str] - """The unique ID of the previous response to the model. - - Use this to create multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - """ - - reasoning: Optional[Reasoning] - """ - **gpt-5 and o-series models only** Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ - - text: Optional[Text] - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tool_choice: Optional[ToolChoice] - """Controls which tool the model should use, if any.""" - - tools: Optional[Iterable[ToolParam]] - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - """ - - truncation: Literal["auto", "disabled"] - """The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - `disabled` (default): If the - input size will exceed the context window size for a model, the request will - fail with a 400 error. - """ - - -Conversation: TypeAlias = Union[str, ResponseConversationParam] - - -class Text(TypedDict, total=False): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: ResponseFormatTextConfigParam - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ - - -ToolChoice: TypeAlias = Union[ - ToolChoiceOptions, - ToolChoiceAllowedParam, - ToolChoiceTypesParam, - ToolChoiceFunctionParam, - ToolChoiceMcpParam, - ToolChoiceCustomParam, - ToolChoiceApplyPatchParam, - ToolChoiceShellParam, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_response.py deleted file mode 100644 index 30ddfc1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/input_token_count_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["InputTokenCountResponse"] - - -class InputTokenCountResponse(BaseModel): - input_tokens: int - - object: Literal["response.input_tokens"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/parsed_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/parsed_response.py deleted file mode 100644 index a859710..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/parsed_response.py +++ /dev/null @@ -1,106 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import TYPE_CHECKING, List, Union, Generic, TypeVar, Optional -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .response import Response -from ..._models import GenericModel -from .response_output_item import ( - McpCall, - McpListTools, - LocalShellCall, - McpApprovalRequest, - ImageGenerationCall, - LocalShellCallAction, -) -from .response_output_text import ResponseOutputText -from .response_output_message import ResponseOutputMessage -from .response_output_refusal import ResponseOutputRefusal -from .response_reasoning_item import ResponseReasoningItem -from .response_compaction_item import ResponseCompactionItem -from .response_custom_tool_call import ResponseCustomToolCall -from .response_computer_tool_call import ResponseComputerToolCall -from .response_function_tool_call import ResponseFunctionToolCall -from .response_function_web_search import ResponseFunctionWebSearch -from .response_apply_patch_tool_call import ResponseApplyPatchToolCall -from .response_file_search_tool_call import ResponseFileSearchToolCall -from .response_function_shell_tool_call import ResponseFunctionShellToolCall -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall -from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput -from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput - -__all__ = ["ParsedResponse", "ParsedResponseOutputMessage", "ParsedResponseOutputText"] - -ContentType = TypeVar("ContentType") - -# we need to disable this check because we're overriding properties -# with subclasses of their types which is technically unsound as -# properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false - - -class ParsedResponseOutputText(ResponseOutputText, GenericModel, Generic[ContentType]): - parsed: Optional[ContentType] = None - - -ParsedContent: TypeAlias = Annotated[ - Union[ParsedResponseOutputText[ContentType], ResponseOutputRefusal], - PropertyInfo(discriminator="type"), -] - - -class ParsedResponseOutputMessage(ResponseOutputMessage, GenericModel, Generic[ContentType]): - if TYPE_CHECKING: - content: List[ParsedContent[ContentType]] # type: ignore[assignment] - else: - content: List[ParsedContent] - - -class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): - parsed_arguments: object = None - - __api_exclude__ = {"parsed_arguments"} - - -ParsedResponseOutputItem: TypeAlias = Annotated[ - Union[ - ParsedResponseOutputMessage[ContentType], - ParsedResponseFunctionToolCall, - ResponseFileSearchToolCall, - ResponseFunctionWebSearch, - ResponseComputerToolCall, - ResponseReasoningItem, - McpCall, - McpApprovalRequest, - ImageGenerationCall, - LocalShellCall, - LocalShellCallAction, - McpListTools, - ResponseCodeInterpreterToolCall, - ResponseCustomToolCall, - ResponseCompactionItem, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - ], - PropertyInfo(discriminator="type"), -] - - -class ParsedResponse(Response, GenericModel, Generic[ContentType]): - if TYPE_CHECKING: - output: List[ParsedResponseOutputItem[ContentType]] # type: ignore[assignment] - else: - output: List[ParsedResponseOutputItem] - - @property - def output_parsed(self) -> Optional[ContentType]: - for output in self.output: - if output.type == "message": - for content in output.content: - if content.type == "output_text" and content.parsed: - return content.parsed - - return None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response.py deleted file mode 100644 index 6bac7d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response.py +++ /dev/null @@ -1,320 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from .tool import Tool -from ..._models import BaseModel -from .response_error import ResponseError -from .response_usage import ResponseUsage -from .response_prompt import ResponsePrompt -from .response_status import ResponseStatus -from .tool_choice_mcp import ToolChoiceMcp -from ..shared.metadata import Metadata -from ..shared.reasoning import Reasoning -from .tool_choice_shell import ToolChoiceShell -from .tool_choice_types import ToolChoiceTypes -from .tool_choice_custom import ToolChoiceCustom -from .response_input_item import ResponseInputItem -from .tool_choice_allowed import ToolChoiceAllowed -from .tool_choice_options import ToolChoiceOptions -from .response_output_item import ResponseOutputItem -from .response_text_config import ResponseTextConfig -from .tool_choice_function import ToolChoiceFunction -from ..shared.responses_model import ResponsesModel -from .tool_choice_apply_patch import ToolChoiceApplyPatch - -__all__ = ["Response", "IncompleteDetails", "ToolChoice", "Conversation"] - - -class IncompleteDetails(BaseModel): - """Details about why the response is incomplete.""" - - reason: Optional[Literal["max_output_tokens", "content_filter"]] = None - """The reason why the response is incomplete.""" - - -ToolChoice: TypeAlias = Union[ - ToolChoiceOptions, - ToolChoiceAllowed, - ToolChoiceTypes, - ToolChoiceFunction, - ToolChoiceMcp, - ToolChoiceCustom, - ToolChoiceApplyPatch, - ToolChoiceShell, -] - - -class Conversation(BaseModel): - """The conversation that this response belonged to. - - Input items and output items from this response were automatically added to this conversation. - """ - - id: str - """The unique ID of the conversation that this response was associated with.""" - - -class Response(BaseModel): - id: str - """Unique identifier for this Response.""" - - created_at: float - """Unix timestamp (in seconds) of when this Response was created.""" - - error: Optional[ResponseError] = None - """An error object returned when the model fails to generate a Response.""" - - incomplete_details: Optional[IncompleteDetails] = None - """Details about why the response is incomplete.""" - - instructions: Union[str, List[ResponseInputItem], None] = None - """A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - """ - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: ResponsesModel - """Model ID used to generate the response, like `gpt-4o` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - object: Literal["response"] - """The object type of this resource - always set to `response`.""" - - output: List[ResponseOutputItem] - """An array of content items generated by the model. - - - The length and order of items in the `output` array is dependent on the - model's response. - - Rather than accessing the first item in the `output` array and assuming it's - an `assistant` message with the content generated by the model, you might - consider using the `output_text` property where supported in SDKs. - """ - - parallel_tool_calls: bool - """Whether to allow the model to run tool calls in parallel.""" - - temperature: Optional[float] = None - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. We generally recommend altering - this or `top_p` but not both. - """ - - tool_choice: ToolChoice - """ - How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - """ - - tools: List[Tool] - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - """ - - top_p: Optional[float] = None - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - """ - - background: Optional[bool] = None - """ - Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - """ - - completed_at: Optional[float] = None - """ - Unix timestamp (in seconds) of when this Response was completed. Only present - when the status is `completed`. - """ - - conversation: Optional[Conversation] = None - """The conversation that this response belonged to. - - Input items and output items from this response were automatically added to this - conversation. - """ - - max_output_tokens: Optional[int] = None - """ - An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - """ - - max_tool_calls: Optional[int] = None - """ - The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - """ - - previous_response_id: Optional[str] = None - """The unique ID of the previous response to the model. - - Use this to create multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - """ - - prompt: Optional[ResponsePrompt] = None - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - prompt_cache_key: Optional[str] = None - """ - Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - """ - - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] = None - """The retention policy for the prompt cache. - - Set to `24h` to enable extended prompt caching, which keeps cached prefixes - active for longer, up to a maximum of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - """ - - reasoning: Optional[Reasoning] = None - """**gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ - - safety_identifier: Optional[str] = None - """ - A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] = None - """Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - """ - - status: Optional[ResponseStatus] = None - """The status of the response generation. - - One of `completed`, `failed`, `in_progress`, `cancelled`, `queued`, or - `incomplete`. - """ - - text: Optional[ResponseTextConfig] = None - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - top_logprobs: Optional[int] = None - """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - """ - - truncation: Optional[Literal["auto", "disabled"]] = None - """The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - """ - - usage: Optional[ResponseUsage] = None - """ - Represents token usage details including input tokens, output tokens, a - breakdown of output tokens, and the total tokens used. - """ - - user: Optional[str] = None - """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - - Use `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - @property - def output_text(self) -> str: - """Convenience property that aggregates all `output_text` items from the `output` list. - - If no `output_text` content blocks exist, then an empty string is returned. - """ - texts: List[str] = [] - for output in self.output: - if output.type == "message": - for content in output.content: - if content.type == "output_text": - texts.append(content.text) - - return "".join(texts) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call.py deleted file mode 100644 index 7af1300..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call.py +++ /dev/null @@ -1,84 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = [ - "ResponseApplyPatchToolCall", - "Operation", - "OperationCreateFile", - "OperationDeleteFile", - "OperationUpdateFile", -] - - -class OperationCreateFile(BaseModel): - """Instruction describing how to create a file via the apply_patch tool.""" - - diff: str - """Diff to apply.""" - - path: str - """Path of the file to create.""" - - type: Literal["create_file"] - """Create a new file with the provided diff.""" - - -class OperationDeleteFile(BaseModel): - """Instruction describing how to delete a file via the apply_patch tool.""" - - path: str - """Path of the file to delete.""" - - type: Literal["delete_file"] - """Delete the specified file.""" - - -class OperationUpdateFile(BaseModel): - """Instruction describing how to update a file via the apply_patch tool.""" - - diff: str - """Diff to apply.""" - - path: str - """Path of the file to update.""" - - type: Literal["update_file"] - """Update an existing file with the provided diff.""" - - -Operation: TypeAlias = Annotated[ - Union[OperationCreateFile, OperationDeleteFile, OperationUpdateFile], PropertyInfo(discriminator="type") -] - - -class ResponseApplyPatchToolCall(BaseModel): - """A tool call that applies file diffs by creating, deleting, or updating files.""" - - id: str - """The unique ID of the apply patch tool call. - - Populated when this item is returned via API. - """ - - call_id: str - """The unique ID of the apply patch tool call generated by the model.""" - - operation: Operation - """ - One of the create_file, delete_file, or update_file operations applied via - apply_patch. - """ - - status: Literal["in_progress", "completed"] - """The status of the apply patch tool call. One of `in_progress` or `completed`.""" - - type: Literal["apply_patch_call"] - """The type of the item. Always `apply_patch_call`.""" - - created_by: Optional[str] = None - """The ID of the entity that created this tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call_output.py deleted file mode 100644 index de63c6e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_apply_patch_tool_call_output.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseApplyPatchToolCallOutput"] - - -class ResponseApplyPatchToolCallOutput(BaseModel): - """The output emitted by an apply patch tool call.""" - - id: str - """The unique ID of the apply patch tool call output. - - Populated when this item is returned via API. - """ - - call_id: str - """The unique ID of the apply patch tool call generated by the model.""" - - status: Literal["completed", "failed"] - """The status of the apply patch tool call output. One of `completed` or `failed`.""" - - type: Literal["apply_patch_call_output"] - """The type of the item. Always `apply_patch_call_output`.""" - - created_by: Optional[str] = None - """The ID of the entity that created this tool call output.""" - - output: Optional[str] = None - """Optional textual output returned by the apply patch tool.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_delta_event.py deleted file mode 100644 index e577d65..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_delta_event.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioDeltaEvent"] - - -class ResponseAudioDeltaEvent(BaseModel): - """Emitted when there is a partial audio response.""" - - delta: str - """A chunk of Base64 encoded response audio bytes.""" - - sequence_number: int - """A sequence number for this chunk of the stream response.""" - - type: Literal["response.audio.delta"] - """The type of the event. Always `response.audio.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_done_event.py deleted file mode 100644 index f5f0401..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_done_event.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioDoneEvent"] - - -class ResponseAudioDoneEvent(BaseModel): - """Emitted when the audio response is complete.""" - - sequence_number: int - """The sequence number of the delta.""" - - type: Literal["response.audio.done"] - """The type of the event. Always `response.audio.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_delta_event.py deleted file mode 100644 index 03be59a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_delta_event.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDeltaEvent"] - - -class ResponseAudioTranscriptDeltaEvent(BaseModel): - """Emitted when there is a partial transcript of audio.""" - - delta: str - """The partial transcript of the audio response.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.audio.transcript.delta"] - """The type of the event. Always `response.audio.transcript.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_done_event.py deleted file mode 100644 index 87219e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_audio_transcript_done_event.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseAudioTranscriptDoneEvent"] - - -class ResponseAudioTranscriptDoneEvent(BaseModel): - """Emitted when the full audio transcript is completed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.audio.transcript.done"] - """The type of the event. Always `response.audio.transcript.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_delta_event.py deleted file mode 100644 index c6bc8b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_delta_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterCallCodeDeltaEvent"] - - -class ResponseCodeInterpreterCallCodeDeltaEvent(BaseModel): - """Emitted when a partial code snippet is streamed by the code interpreter.""" - - delta: str - """The partial code snippet being streamed by the code interpreter.""" - - item_id: str - """The unique identifier of the code interpreter tool call item.""" - - output_index: int - """ - The index of the output item in the response for which the code is being - streamed. - """ - - sequence_number: int - """The sequence number of this event, used to order streaming events.""" - - type: Literal["response.code_interpreter_call_code.delta"] - """The type of the event. Always `response.code_interpreter_call_code.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_done_event.py deleted file mode 100644 index 186c037..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_code_done_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterCallCodeDoneEvent"] - - -class ResponseCodeInterpreterCallCodeDoneEvent(BaseModel): - """Emitted when the code snippet is finalized by the code interpreter.""" - - code: str - """The final code snippet output by the code interpreter.""" - - item_id: str - """The unique identifier of the code interpreter tool call item.""" - - output_index: int - """The index of the output item in the response for which the code is finalized.""" - - sequence_number: int - """The sequence number of this event, used to order streaming events.""" - - type: Literal["response.code_interpreter_call_code.done"] - """The type of the event. Always `response.code_interpreter_call_code.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_completed_event.py deleted file mode 100644 index 197e39e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_completed_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterCallCompletedEvent"] - - -class ResponseCodeInterpreterCallCompletedEvent(BaseModel): - """Emitted when the code interpreter call is completed.""" - - item_id: str - """The unique identifier of the code interpreter tool call item.""" - - output_index: int - """ - The index of the output item in the response for which the code interpreter call - is completed. - """ - - sequence_number: int - """The sequence number of this event, used to order streaming events.""" - - type: Literal["response.code_interpreter_call.completed"] - """The type of the event. Always `response.code_interpreter_call.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_in_progress_event.py deleted file mode 100644 index c775f1b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_in_progress_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterCallInProgressEvent"] - - -class ResponseCodeInterpreterCallInProgressEvent(BaseModel): - """Emitted when a code interpreter call is in progress.""" - - item_id: str - """The unique identifier of the code interpreter tool call item.""" - - output_index: int - """ - The index of the output item in the response for which the code interpreter call - is in progress. - """ - - sequence_number: int - """The sequence number of this event, used to order streaming events.""" - - type: Literal["response.code_interpreter_call.in_progress"] - """The type of the event. Always `response.code_interpreter_call.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_interpreting_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_interpreting_event.py deleted file mode 100644 index 85e9c87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_call_interpreting_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterCallInterpretingEvent"] - - -class ResponseCodeInterpreterCallInterpretingEvent(BaseModel): - """Emitted when the code interpreter is actively interpreting the code snippet.""" - - item_id: str - """The unique identifier of the code interpreter tool call item.""" - - output_index: int - """ - The index of the output item in the response for which the code interpreter is - interpreting code. - """ - - sequence_number: int - """The sequence number of this event, used to order streaming events.""" - - type: Literal["response.code_interpreter_call.interpreting"] - """The type of the event. Always `response.code_interpreter_call.interpreting`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call.py deleted file mode 100644 index d7e30f4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["ResponseCodeInterpreterToolCall", "Output", "OutputLogs", "OutputImage"] - - -class OutputLogs(BaseModel): - """The logs output from the code interpreter.""" - - logs: str - """The logs output from the code interpreter.""" - - type: Literal["logs"] - """The type of the output. Always `logs`.""" - - -class OutputImage(BaseModel): - """The image output from the code interpreter.""" - - type: Literal["image"] - """The type of the output. Always `image`.""" - - url: str - """The URL of the image output from the code interpreter.""" - - -Output: TypeAlias = Annotated[Union[OutputLogs, OutputImage], PropertyInfo(discriminator="type")] - - -class ResponseCodeInterpreterToolCall(BaseModel): - """A tool call to run code.""" - - id: str - """The unique ID of the code interpreter tool call.""" - - code: Optional[str] = None - """The code to run, or null if not available.""" - - container_id: str - """The ID of the container used to run the code.""" - - outputs: Optional[List[Output]] = None - """ - The outputs generated by the code interpreter, such as logs or images. Can be - null if no outputs are available. - """ - - status: Literal["in_progress", "completed", "incomplete", "interpreting", "failed"] - """The status of the code interpreter tool call. - - Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and - `failed`. - """ - - type: Literal["code_interpreter_call"] - """The type of the code interpreter tool call. Always `code_interpreter_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call_param.py deleted file mode 100644 index fc03a3f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_code_interpreter_tool_call_param.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["ResponseCodeInterpreterToolCallParam", "Output", "OutputLogs", "OutputImage"] - - -class OutputLogs(TypedDict, total=False): - """The logs output from the code interpreter.""" - - logs: Required[str] - """The logs output from the code interpreter.""" - - type: Required[Literal["logs"]] - """The type of the output. Always `logs`.""" - - -class OutputImage(TypedDict, total=False): - """The image output from the code interpreter.""" - - type: Required[Literal["image"]] - """The type of the output. Always `image`.""" - - url: Required[str] - """The URL of the image output from the code interpreter.""" - - -Output: TypeAlias = Union[OutputLogs, OutputImage] - - -class ResponseCodeInterpreterToolCallParam(TypedDict, total=False): - """A tool call to run code.""" - - id: Required[str] - """The unique ID of the code interpreter tool call.""" - - code: Required[Optional[str]] - """The code to run, or null if not available.""" - - container_id: Required[str] - """The ID of the container used to run the code.""" - - outputs: Required[Optional[Iterable[Output]]] - """ - The outputs generated by the code interpreter, such as logs or images. Can be - null if no outputs are available. - """ - - status: Required[Literal["in_progress", "completed", "incomplete", "interpreting", "failed"]] - """The status of the code interpreter tool call. - - Valid values are `in_progress`, `completed`, `incomplete`, `interpreting`, and - `failed`. - """ - - type: Required[Literal["code_interpreter_call"]] - """The type of the code interpreter tool call. Always `code_interpreter_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compact_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compact_params.py deleted file mode 100644 index 657c6a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compact_params.py +++ /dev/null @@ -1,133 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -from .response_input_item_param import ResponseInputItemParam - -__all__ = ["ResponseCompactParams"] - - -class ResponseCompactParams(TypedDict, total=False): - model: Required[ - Union[ - Literal[ - "gpt-5.2", - "gpt-5.2-2025-12-11", - "gpt-5.2-chat-latest", - "gpt-5.2-pro", - "gpt-5.2-pro-2025-12-11", - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], - str, - None, - ] - ] - """Model ID used to generate the response, like `gpt-5` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - input: Union[str, Iterable[ResponseInputItemParam], None] - """Text, image, or file inputs to the model, used to generate a response""" - - instructions: Optional[str] - """ - A system (or developer) message inserted into the model's context. When used - along with `previous_response_id`, the instructions from a previous response - will not be carried over to the next response. This makes it simple to swap out - system (or developer) messages in new responses. - """ - - previous_response_id: Optional[str] - """The unique ID of the previous response to the model. - - Use this to create multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item.py deleted file mode 100644 index 36e953b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCompactionItem"] - - -class ResponseCompactionItem(BaseModel): - """ - A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). - """ - - id: str - """The unique ID of the compaction item.""" - - encrypted_content: str - """The encrypted content that was produced by compaction.""" - - type: Literal["compaction"] - """The type of the item. Always `compaction`.""" - - created_by: Optional[str] = None - """The identifier of the actor that created the item.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param.py deleted file mode 100644 index 5ef134b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCompactionItemParam"] - - -class ResponseCompactionItemParam(BaseModel): - """ - A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). - """ - - encrypted_content: str - """The encrypted content of the compaction summary.""" - - type: Literal["compaction"] - """The type of the item. Always `compaction`.""" - - id: Optional[str] = None - """The ID of the compaction item.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param_param.py deleted file mode 100644 index b4d72c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_compaction_item_param_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseCompactionItemParamParam"] - - -class ResponseCompactionItemParamParam(TypedDict, total=False): - """ - A compaction item generated by the [`v1/responses/compact` API](https://platform.openai.com/docs/api-reference/responses/compact). - """ - - encrypted_content: Required[str] - """The encrypted content of the compaction summary.""" - - type: Required[Literal["compaction"]] - """The type of the item. Always `compaction`.""" - - id: Optional[str] - """The ID of the compaction item.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_completed_event.py deleted file mode 100644 index 6dc9581..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_completed_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseCompletedEvent"] - - -class ResponseCompletedEvent(BaseModel): - """Emitted when the model response is complete.""" - - response: Response - """Properties of the completed response.""" - - sequence_number: int - """The sequence number for this event.""" - - type: Literal["response.completed"] - """The type of the event. Always `response.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call.py deleted file mode 100644 index 4e1b3cf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call.py +++ /dev/null @@ -1,237 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = [ - "ResponseComputerToolCall", - "Action", - "ActionClick", - "ActionDoubleClick", - "ActionDrag", - "ActionDragPath", - "ActionKeypress", - "ActionMove", - "ActionScreenshot", - "ActionScroll", - "ActionType", - "ActionWait", - "PendingSafetyCheck", -] - - -class ActionClick(BaseModel): - """A click action.""" - - button: Literal["left", "right", "wheel", "back", "forward"] - """Indicates which mouse button was pressed during the click. - - One of `left`, `right`, `wheel`, `back`, or `forward`. - """ - - type: Literal["click"] - """Specifies the event type. For a click action, this property is always `click`.""" - - x: int - """The x-coordinate where the click occurred.""" - - y: int - """The y-coordinate where the click occurred.""" - - -class ActionDoubleClick(BaseModel): - """A double click action.""" - - type: Literal["double_click"] - """Specifies the event type. - - For a double click action, this property is always set to `double_click`. - """ - - x: int - """The x-coordinate where the double click occurred.""" - - y: int - """The y-coordinate where the double click occurred.""" - - -class ActionDragPath(BaseModel): - """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" - - x: int - """The x-coordinate.""" - - y: int - """The y-coordinate.""" - - -class ActionDrag(BaseModel): - """A drag action.""" - - path: List[ActionDragPath] - """An array of coordinates representing the path of the drag action. - - Coordinates will appear as an array of objects, eg - - ``` - [ - { x: 100, y: 200 }, - { x: 200, y: 300 } - ] - ``` - """ - - type: Literal["drag"] - """Specifies the event type. - - For a drag action, this property is always set to `drag`. - """ - - -class ActionKeypress(BaseModel): - """A collection of keypresses the model would like to perform.""" - - keys: List[str] - """The combination of keys the model is requesting to be pressed. - - This is an array of strings, each representing a key. - """ - - type: Literal["keypress"] - """Specifies the event type. - - For a keypress action, this property is always set to `keypress`. - """ - - -class ActionMove(BaseModel): - """A mouse move action.""" - - type: Literal["move"] - """Specifies the event type. - - For a move action, this property is always set to `move`. - """ - - x: int - """The x-coordinate to move to.""" - - y: int - """The y-coordinate to move to.""" - - -class ActionScreenshot(BaseModel): - """A screenshot action.""" - - type: Literal["screenshot"] - """Specifies the event type. - - For a screenshot action, this property is always set to `screenshot`. - """ - - -class ActionScroll(BaseModel): - """A scroll action.""" - - scroll_x: int - """The horizontal scroll distance.""" - - scroll_y: int - """The vertical scroll distance.""" - - type: Literal["scroll"] - """Specifies the event type. - - For a scroll action, this property is always set to `scroll`. - """ - - x: int - """The x-coordinate where the scroll occurred.""" - - y: int - """The y-coordinate where the scroll occurred.""" - - -class ActionType(BaseModel): - """An action to type in text.""" - - text: str - """The text to type.""" - - type: Literal["type"] - """Specifies the event type. - - For a type action, this property is always set to `type`. - """ - - -class ActionWait(BaseModel): - """A wait action.""" - - type: Literal["wait"] - """Specifies the event type. - - For a wait action, this property is always set to `wait`. - """ - - -Action: TypeAlias = Annotated[ - Union[ - ActionClick, - ActionDoubleClick, - ActionDrag, - ActionKeypress, - ActionMove, - ActionScreenshot, - ActionScroll, - ActionType, - ActionWait, - ], - PropertyInfo(discriminator="type"), -] - - -class PendingSafetyCheck(BaseModel): - """A pending safety check for the computer call.""" - - id: str - """The ID of the pending safety check.""" - - code: Optional[str] = None - """The type of the pending safety check.""" - - message: Optional[str] = None - """Details about the pending safety check.""" - - -class ResponseComputerToolCall(BaseModel): - """A tool call to a computer use tool. - - See the - [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information. - """ - - id: str - """The unique ID of the computer call.""" - - action: Action - """A click action.""" - - call_id: str - """An identifier used when responding to the tool call with output.""" - - pending_safety_checks: List[PendingSafetyCheck] - """The pending safety checks for the computer call.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Literal["computer_call"] - """The type of the computer call. Always `computer_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_item.py deleted file mode 100644 index 90e935c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_item.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot - -__all__ = ["ResponseComputerToolCallOutputItem", "AcknowledgedSafetyCheck"] - - -class AcknowledgedSafetyCheck(BaseModel): - """A pending safety check for the computer call.""" - - id: str - """The ID of the pending safety check.""" - - code: Optional[str] = None - """The type of the pending safety check.""" - - message: Optional[str] = None - """Details about the pending safety check.""" - - -class ResponseComputerToolCallOutputItem(BaseModel): - id: str - """The unique ID of the computer call tool output.""" - - call_id: str - """The ID of the computer tool call that produced the output.""" - - output: ResponseComputerToolCallOutputScreenshot - """A computer screenshot image used with the computer use tool.""" - - type: Literal["computer_call_output"] - """The type of the computer tool call output. Always `computer_call_output`.""" - - acknowledged_safety_checks: Optional[List[AcknowledgedSafetyCheck]] = None - """ - The safety checks reported by the API that have been acknowledged by the - developer. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot.py deleted file mode 100644 index 2c16f21..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseComputerToolCallOutputScreenshot"] - - -class ResponseComputerToolCallOutputScreenshot(BaseModel): - """A computer screenshot image used with the computer use tool.""" - - type: Literal["computer_screenshot"] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ - - file_id: Optional[str] = None - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: Optional[str] = None - """The URL of the screenshot image.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot_param.py deleted file mode 100644 index 857ccf9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_output_screenshot_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseComputerToolCallOutputScreenshotParam"] - - -class ResponseComputerToolCallOutputScreenshotParam(TypedDict, total=False): - """A computer screenshot image used with the computer use tool.""" - - type: Required[Literal["computer_screenshot"]] - """Specifies the event type. - - For a computer screenshot, this property is always set to `computer_screenshot`. - """ - - file_id: str - """The identifier of an uploaded file that contains the screenshot.""" - - image_url: str - """The URL of the screenshot image.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_param.py deleted file mode 100644 index 550ba59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_computer_tool_call_param.py +++ /dev/null @@ -1,235 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr - -__all__ = [ - "ResponseComputerToolCallParam", - "Action", - "ActionClick", - "ActionDoubleClick", - "ActionDrag", - "ActionDragPath", - "ActionKeypress", - "ActionMove", - "ActionScreenshot", - "ActionScroll", - "ActionType", - "ActionWait", - "PendingSafetyCheck", -] - - -class ActionClick(TypedDict, total=False): - """A click action.""" - - button: Required[Literal["left", "right", "wheel", "back", "forward"]] - """Indicates which mouse button was pressed during the click. - - One of `left`, `right`, `wheel`, `back`, or `forward`. - """ - - type: Required[Literal["click"]] - """Specifies the event type. For a click action, this property is always `click`.""" - - x: Required[int] - """The x-coordinate where the click occurred.""" - - y: Required[int] - """The y-coordinate where the click occurred.""" - - -class ActionDoubleClick(TypedDict, total=False): - """A double click action.""" - - type: Required[Literal["double_click"]] - """Specifies the event type. - - For a double click action, this property is always set to `double_click`. - """ - - x: Required[int] - """The x-coordinate where the double click occurred.""" - - y: Required[int] - """The y-coordinate where the double click occurred.""" - - -class ActionDragPath(TypedDict, total=False): - """An x/y coordinate pair, e.g. `{ x: 100, y: 200 }`.""" - - x: Required[int] - """The x-coordinate.""" - - y: Required[int] - """The y-coordinate.""" - - -class ActionDrag(TypedDict, total=False): - """A drag action.""" - - path: Required[Iterable[ActionDragPath]] - """An array of coordinates representing the path of the drag action. - - Coordinates will appear as an array of objects, eg - - ``` - [ - { x: 100, y: 200 }, - { x: 200, y: 300 } - ] - ``` - """ - - type: Required[Literal["drag"]] - """Specifies the event type. - - For a drag action, this property is always set to `drag`. - """ - - -class ActionKeypress(TypedDict, total=False): - """A collection of keypresses the model would like to perform.""" - - keys: Required[SequenceNotStr[str]] - """The combination of keys the model is requesting to be pressed. - - This is an array of strings, each representing a key. - """ - - type: Required[Literal["keypress"]] - """Specifies the event type. - - For a keypress action, this property is always set to `keypress`. - """ - - -class ActionMove(TypedDict, total=False): - """A mouse move action.""" - - type: Required[Literal["move"]] - """Specifies the event type. - - For a move action, this property is always set to `move`. - """ - - x: Required[int] - """The x-coordinate to move to.""" - - y: Required[int] - """The y-coordinate to move to.""" - - -class ActionScreenshot(TypedDict, total=False): - """A screenshot action.""" - - type: Required[Literal["screenshot"]] - """Specifies the event type. - - For a screenshot action, this property is always set to `screenshot`. - """ - - -class ActionScroll(TypedDict, total=False): - """A scroll action.""" - - scroll_x: Required[int] - """The horizontal scroll distance.""" - - scroll_y: Required[int] - """The vertical scroll distance.""" - - type: Required[Literal["scroll"]] - """Specifies the event type. - - For a scroll action, this property is always set to `scroll`. - """ - - x: Required[int] - """The x-coordinate where the scroll occurred.""" - - y: Required[int] - """The y-coordinate where the scroll occurred.""" - - -class ActionType(TypedDict, total=False): - """An action to type in text.""" - - text: Required[str] - """The text to type.""" - - type: Required[Literal["type"]] - """Specifies the event type. - - For a type action, this property is always set to `type`. - """ - - -class ActionWait(TypedDict, total=False): - """A wait action.""" - - type: Required[Literal["wait"]] - """Specifies the event type. - - For a wait action, this property is always set to `wait`. - """ - - -Action: TypeAlias = Union[ - ActionClick, - ActionDoubleClick, - ActionDrag, - ActionKeypress, - ActionMove, - ActionScreenshot, - ActionScroll, - ActionType, - ActionWait, -] - - -class PendingSafetyCheck(TypedDict, total=False): - """A pending safety check for the computer call.""" - - id: Required[str] - """The ID of the pending safety check.""" - - code: Optional[str] - """The type of the pending safety check.""" - - message: Optional[str] - """Details about the pending safety check.""" - - -class ResponseComputerToolCallParam(TypedDict, total=False): - """A tool call to a computer use tool. - - See the - [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information. - """ - - id: Required[str] - """The unique ID of the computer call.""" - - action: Required[Action] - """A click action.""" - - call_id: Required[str] - """An identifier used when responding to the tool call with output.""" - - pending_safety_checks: Required[Iterable[PendingSafetyCheck]] - """The pending safety checks for the computer call.""" - - status: Required[Literal["in_progress", "completed", "incomplete"]] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Required[Literal["computer_call"]] - """The type of the computer call. Always `computer_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_added_event.py deleted file mode 100644 index ec98931..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_added_event.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_output_text import ResponseOutputText -from .response_output_refusal import ResponseOutputRefusal - -__all__ = ["ResponseContentPartAddedEvent", "Part", "PartReasoningText"] - - -class PartReasoningText(BaseModel): - """Reasoning text from the model.""" - - text: str - """The reasoning text from the model.""" - - type: Literal["reasoning_text"] - """The type of the reasoning text. Always `reasoning_text`.""" - - -Part: TypeAlias = Annotated[ - Union[ResponseOutputText, ResponseOutputRefusal, PartReasoningText], PropertyInfo(discriminator="type") -] - - -class ResponseContentPartAddedEvent(BaseModel): - """Emitted when a new content part is added.""" - - content_index: int - """The index of the content part that was added.""" - - item_id: str - """The ID of the output item that the content part was added to.""" - - output_index: int - """The index of the output item that the content part was added to.""" - - part: Part - """The content part that was added.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.content_part.added"] - """The type of the event. Always `response.content_part.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_done_event.py deleted file mode 100644 index f896ad8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_content_part_done_event.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_output_text import ResponseOutputText -from .response_output_refusal import ResponseOutputRefusal - -__all__ = ["ResponseContentPartDoneEvent", "Part", "PartReasoningText"] - - -class PartReasoningText(BaseModel): - """Reasoning text from the model.""" - - text: str - """The reasoning text from the model.""" - - type: Literal["reasoning_text"] - """The type of the reasoning text. Always `reasoning_text`.""" - - -Part: TypeAlias = Annotated[ - Union[ResponseOutputText, ResponseOutputRefusal, PartReasoningText], PropertyInfo(discriminator="type") -] - - -class ResponseContentPartDoneEvent(BaseModel): - """Emitted when a content part is done.""" - - content_index: int - """The index of the content part that is done.""" - - item_id: str - """The ID of the output item that the content part was added to.""" - - output_index: int - """The index of the output item that the content part was added to.""" - - part: Part - """The content part that is done.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.content_part.done"] - """The type of the event. Always `response.content_part.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_conversation_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_conversation_param.py deleted file mode 100644 index d1587fe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_conversation_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ResponseConversationParam"] - - -class ResponseConversationParam(TypedDict, total=False): - """The conversation that this response belongs to.""" - - id: Required[str] - """The unique ID of the conversation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_create_params.py deleted file mode 100644 index 15844c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_create_params.py +++ /dev/null @@ -1,336 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .tool_param import ToolParam -from .response_includable import ResponseIncludable -from .tool_choice_options import ToolChoiceOptions -from .response_input_param import ResponseInputParam -from .response_prompt_param import ResponsePromptParam -from .tool_choice_mcp_param import ToolChoiceMcpParam -from ..shared_params.metadata import Metadata -from .tool_choice_shell_param import ToolChoiceShellParam -from .tool_choice_types_param import ToolChoiceTypesParam -from ..shared_params.reasoning import Reasoning -from .tool_choice_custom_param import ToolChoiceCustomParam -from .tool_choice_allowed_param import ToolChoiceAllowedParam -from .response_text_config_param import ResponseTextConfigParam -from .tool_choice_function_param import ToolChoiceFunctionParam -from .response_conversation_param import ResponseConversationParam -from .tool_choice_apply_patch_param import ToolChoiceApplyPatchParam -from ..shared_params.responses_model import ResponsesModel - -__all__ = [ - "ResponseCreateParamsBase", - "Conversation", - "StreamOptions", - "ToolChoice", - "ResponseCreateParamsNonStreaming", - "ResponseCreateParamsStreaming", -] - - -class ResponseCreateParamsBase(TypedDict, total=False): - background: Optional[bool] - """ - Whether to run the model response in the background. - [Learn more](https://platform.openai.com/docs/guides/background). - """ - - conversation: Optional[Conversation] - """The conversation that this response belongs to. - - Items from this conversation are prepended to `input_items` for this response - request. Input items and output items from this response are automatically added - to this conversation after this response completes. - """ - - include: Optional[List[ResponseIncludable]] - """Specify additional output data to include in the model response. - - Currently supported values are: - - - `web_search_call.action.sources`: Include the sources of the web search tool - call. - - `code_interpreter_call.outputs`: Includes the outputs of python code execution - in code interpreter tool call items. - - `computer_call_output.output.image_url`: Include image urls from the computer - call output. - - `file_search_call.results`: Include the search results of the file search tool - call. - - `message.input_image.image_url`: Include image urls from the input message. - - `message.output_text.logprobs`: Include logprobs with assistant messages. - - `reasoning.encrypted_content`: Includes an encrypted version of reasoning - tokens in reasoning item outputs. This enables reasoning items to be used in - multi-turn conversations when using the Responses API statelessly (like when - the `store` parameter is set to `false`, or when an organization is enrolled - in the zero data retention program). - """ - - input: Union[str, ResponseInputParam] - """Text, image, or file inputs to the model, used to generate a response. - - Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Image inputs](https://platform.openai.com/docs/guides/images) - - [File inputs](https://platform.openai.com/docs/guides/pdf-files) - - [Conversation state](https://platform.openai.com/docs/guides/conversation-state) - - [Function calling](https://platform.openai.com/docs/guides/function-calling) - """ - - instructions: Optional[str] - """A system (or developer) message inserted into the model's context. - - When using along with `previous_response_id`, the instructions from a previous - response will not be carried over to the next response. This makes it simple to - swap out system (or developer) messages in new responses. - """ - - max_output_tokens: Optional[int] - """ - An upper bound for the number of tokens that can be generated for a response, - including visible output tokens and - [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - """ - - max_tool_calls: Optional[int] - """ - The maximum number of total calls to built-in tools that can be processed in a - response. This maximum number applies across all built-in tool calls, not per - individual tool. Any further attempts to call a tool by the model will be - ignored. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - model: ResponsesModel - """Model ID used to generate the response, like `gpt-4o` or `o3`. - - OpenAI offers a wide range of models with different capabilities, performance - characteristics, and price points. Refer to the - [model guide](https://platform.openai.com/docs/models) to browse and compare - available models. - """ - - parallel_tool_calls: Optional[bool] - """Whether to allow the model to run tool calls in parallel.""" - - previous_response_id: Optional[str] - """The unique ID of the previous response to the model. - - Use this to create multi-turn conversations. Learn more about - [conversation state](https://platform.openai.com/docs/guides/conversation-state). - Cannot be used in conjunction with `conversation`. - """ - - prompt: Optional[ResponsePromptParam] - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - prompt_cache_key: str - """ - Used by OpenAI to cache responses for similar requests to optimize your cache - hit rates. Replaces the `user` field. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching). - """ - - prompt_cache_retention: Optional[Literal["in-memory", "24h"]] - """The retention policy for the prompt cache. - - Set to `24h` to enable extended prompt caching, which keeps cached prefixes - active for longer, up to a maximum of 24 hours. - [Learn more](https://platform.openai.com/docs/guides/prompt-caching#prompt-cache-retention). - """ - - reasoning: Optional[Reasoning] - """**gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ - - safety_identifier: str - """ - A stable identifier used to help detect users of your application that may be - violating OpenAI's usage policies. The IDs should be a string that uniquely - identifies each user. We recommend hashing their username or email address, in - order to avoid sending us any identifying information. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] - """Specifies the processing type used for serving the request. - - - If set to 'auto', then the request will be processed with the service tier - configured in the Project settings. Unless otherwise configured, the Project - will use 'default'. - - If set to 'default', then the request will be processed with the standard - pricing and performance for the selected model. - - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or - '[priority](https://openai.com/api-priority-processing/)', then the request - will be processed with the corresponding service tier. - - When not set, the default behavior is 'auto'. - - When the `service_tier` parameter is set, the response body will include the - `service_tier` value based on the processing mode actually used to serve the - request. This response value may be different from the value set in the - parameter. - """ - - store: Optional[bool] - """Whether to store the generated model response for later retrieval via API.""" - - stream_options: Optional[StreamOptions] - """Options for streaming responses. Only set this when you set `stream: true`.""" - - temperature: Optional[float] - """What sampling temperature to use, between 0 and 2. - - Higher values like 0.8 will make the output more random, while lower values like - 0.2 will make it more focused and deterministic. We generally recommend altering - this or `top_p` but not both. - """ - - text: ResponseTextConfigParam - """Configuration options for a text response from the model. - - Can be plain text or structured JSON data. Learn more: - - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - tool_choice: ToolChoice - """ - How the model should select which tool (or tools) to use when generating a - response. See the `tools` parameter to see how to specify which tools the model - can call. - """ - - tools: Iterable[ToolParam] - """An array of tools the model may call while generating a response. - - You can specify which tool to use by setting the `tool_choice` parameter. - - We support the following categories of tools: - - - **Built-in tools**: Tools that are provided by OpenAI that extend the model's - capabilities, like - [web search](https://platform.openai.com/docs/guides/tools-web-search) or - [file search](https://platform.openai.com/docs/guides/tools-file-search). - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - **MCP Tools**: Integrations with third-party systems via custom MCP servers or - predefined connectors such as Google Drive and SharePoint. Learn more about - [MCP Tools](https://platform.openai.com/docs/guides/tools-connectors-mcp). - - **Function calls (custom tools)**: Functions that are defined by you, enabling - the model to call your own code with strongly typed arguments and outputs. - Learn more about - [function calling](https://platform.openai.com/docs/guides/function-calling). - You can also use custom tools to call your own code. - """ - - top_logprobs: Optional[int] - """ - An integer between 0 and 20 specifying the number of most likely tokens to - return at each token position, each with an associated log probability. - """ - - top_p: Optional[float] - """ - An alternative to sampling with temperature, called nucleus sampling, where the - model considers the results of the tokens with top_p probability mass. So 0.1 - means only the tokens comprising the top 10% probability mass are considered. - - We generally recommend altering this or `temperature` but not both. - """ - - truncation: Optional[Literal["auto", "disabled"]] - """The truncation strategy to use for the model response. - - - `auto`: If the input to this Response exceeds the model's context window size, - the model will truncate the response to fit the context window by dropping - items from the beginning of the conversation. - - `disabled` (default): If the input size will exceed the context window size - for a model, the request will fail with a 400 error. - """ - - user: str - """This field is being replaced by `safety_identifier` and `prompt_cache_key`. - - Use `prompt_cache_key` instead to maintain caching optimizations. A stable - identifier for your end-users. Used to boost cache hit rates by better bucketing - similar requests and to help OpenAI detect and prevent abuse. - [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#safety-identifiers). - """ - - -Conversation: TypeAlias = Union[str, ResponseConversationParam] - - -class StreamOptions(TypedDict, total=False): - """Options for streaming responses. Only set this when you set `stream: true`.""" - - include_obfuscation: bool - """When true, stream obfuscation will be enabled. - - Stream obfuscation adds random characters to an `obfuscation` field on streaming - delta events to normalize payload sizes as a mitigation to certain side-channel - attacks. These obfuscation fields are included by default, but add a small - amount of overhead to the data stream. You can set `include_obfuscation` to - false to optimize for bandwidth if you trust the network links between your - application and the OpenAI API. - """ - - -ToolChoice: TypeAlias = Union[ - ToolChoiceOptions, - ToolChoiceAllowedParam, - ToolChoiceTypesParam, - ToolChoiceFunctionParam, - ToolChoiceMcpParam, - ToolChoiceCustomParam, - ToolChoiceApplyPatchParam, - ToolChoiceShellParam, -] - - -class ResponseCreateParamsNonStreaming(ResponseCreateParamsBase, total=False): - stream: Optional[Literal[False]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - """ - - -class ResponseCreateParamsStreaming(ResponseCreateParamsBase): - stream: Required[Literal[True]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - """ - - -ResponseCreateParams = Union[ResponseCreateParamsNonStreaming, ResponseCreateParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_created_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_created_event.py deleted file mode 100644 index 308b2f4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_created_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseCreatedEvent"] - - -class ResponseCreatedEvent(BaseModel): - """An event that is emitted when a response is created.""" - - response: Response - """The response that was created.""" - - sequence_number: int - """The sequence number for this event.""" - - type: Literal["response.created"] - """The type of the event. Always `response.created`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call.py deleted file mode 100644 index f057439..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCustomToolCall"] - - -class ResponseCustomToolCall(BaseModel): - """A call to a custom tool created by the model.""" - - call_id: str - """An identifier used to map this custom tool call to a tool call output.""" - - input: str - """The input for the custom tool call generated by the model.""" - - name: str - """The name of the custom tool being called.""" - - type: Literal["custom_tool_call"] - """The type of the custom tool call. Always `custom_tool_call`.""" - - id: Optional[str] = None - """The unique ID of the custom tool call in the OpenAI platform.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_delta_event.py deleted file mode 100644 index 7473d33..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_delta_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCustomToolCallInputDeltaEvent"] - - -class ResponseCustomToolCallInputDeltaEvent(BaseModel): - """Event representing a delta (partial update) to the input of a custom tool call.""" - - delta: str - """The incremental input data (delta) for the custom tool call.""" - - item_id: str - """Unique identifier for the API item associated with this event.""" - - output_index: int - """The index of the output this delta applies to.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.custom_tool_call_input.delta"] - """The event type identifier.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_done_event.py deleted file mode 100644 index be47ae8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_input_done_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCustomToolCallInputDoneEvent"] - - -class ResponseCustomToolCallInputDoneEvent(BaseModel): - """Event indicating that input for a custom tool call is complete.""" - - input: str - """The complete input data for the custom tool call.""" - - item_id: str - """Unique identifier for the API item associated with this event.""" - - output_index: int - """The index of the output this event applies to.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.custom_tool_call_input.done"] - """The event type identifier.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output.py deleted file mode 100644 index 8339564..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_input_file import ResponseInputFile -from .response_input_text import ResponseInputText -from .response_input_image import ResponseInputImage - -__all__ = ["ResponseCustomToolCallOutput", "OutputOutputContentList"] - -OutputOutputContentList: TypeAlias = Annotated[ - Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") -] - - -class ResponseCustomToolCallOutput(BaseModel): - """The output of a custom tool call from your code, being sent back to the model.""" - - call_id: str - """The call ID, used to map this custom tool call output to a custom tool call.""" - - output: Union[str, List[OutputOutputContentList]] - """ - The output from the custom tool call generated by your code. Can be a string or - an list of output content. - """ - - type: Literal["custom_tool_call_output"] - """The type of the custom tool call output. Always `custom_tool_call_output`.""" - - id: Optional[str] = None - """The unique ID of the custom tool call output in the OpenAI platform.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output_param.py deleted file mode 100644 index db00342..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_output_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .response_input_file_param import ResponseInputFileParam -from .response_input_text_param import ResponseInputTextParam -from .response_input_image_param import ResponseInputImageParam - -__all__ = ["ResponseCustomToolCallOutputParam", "OutputOutputContentList"] - -OutputOutputContentList: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] - - -class ResponseCustomToolCallOutputParam(TypedDict, total=False): - """The output of a custom tool call from your code, being sent back to the model.""" - - call_id: Required[str] - """The call ID, used to map this custom tool call output to a custom tool call.""" - - output: Required[Union[str, Iterable[OutputOutputContentList]]] - """ - The output from the custom tool call generated by your code. Can be a string or - an list of output content. - """ - - type: Required[Literal["custom_tool_call_output"]] - """The type of the custom tool call output. Always `custom_tool_call_output`.""" - - id: str - """The unique ID of the custom tool call output in the OpenAI platform.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_param.py deleted file mode 100644 index 5d4ce33..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_custom_tool_call_param.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseCustomToolCallParam"] - - -class ResponseCustomToolCallParam(TypedDict, total=False): - """A call to a custom tool created by the model.""" - - call_id: Required[str] - """An identifier used to map this custom tool call to a tool call output.""" - - input: Required[str] - """The input for the custom tool call generated by the model.""" - - name: Required[str] - """The name of the custom tool being called.""" - - type: Required[Literal["custom_tool_call"]] - """The type of the custom tool call. Always `custom_tool_call`.""" - - id: str - """The unique ID of the custom tool call in the OpenAI platform.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error.py deleted file mode 100644 index 90958d1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseError"] - - -class ResponseError(BaseModel): - """An error object returned when the model fails to generate a Response.""" - - code: Literal[ - "server_error", - "rate_limit_exceeded", - "invalid_prompt", - "vector_store_timeout", - "invalid_image", - "invalid_image_format", - "invalid_base64_image", - "invalid_image_url", - "image_too_large", - "image_too_small", - "image_parse_error", - "image_content_policy_violation", - "invalid_image_mode", - "image_file_too_large", - "unsupported_image_media_type", - "empty_image_file", - "failed_to_download_image", - "image_file_not_found", - ] - """The error code for the response.""" - - message: str - """A human-readable description of the error.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error_event.py deleted file mode 100644 index 1789f73..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_error_event.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseErrorEvent"] - - -class ResponseErrorEvent(BaseModel): - """Emitted when an error occurs.""" - - code: Optional[str] = None - """The error code.""" - - message: str - """The error message.""" - - param: Optional[str] = None - """The error parameter.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["error"] - """The type of the event. Always `error`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_failed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_failed_event.py deleted file mode 100644 index 2232c96..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_failed_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseFailedEvent"] - - -class ResponseFailedEvent(BaseModel): - """An event that is emitted when a response fails.""" - - response: Response - """The response that failed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.failed"] - """The type of the event. Always `response.failed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_completed_event.py deleted file mode 100644 index 88ffa5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_completed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFileSearchCallCompletedEvent"] - - -class ResponseFileSearchCallCompletedEvent(BaseModel): - """Emitted when a file search call is completed (results found).""" - - item_id: str - """The ID of the output item that the file search call is initiated.""" - - output_index: int - """The index of the output item that the file search call is initiated.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.file_search_call.completed"] - """The type of the event. Always `response.file_search_call.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_in_progress_event.py deleted file mode 100644 index 4f3504f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_in_progress_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFileSearchCallInProgressEvent"] - - -class ResponseFileSearchCallInProgressEvent(BaseModel): - """Emitted when a file search call is initiated.""" - - item_id: str - """The ID of the output item that the file search call is initiated.""" - - output_index: int - """The index of the output item that the file search call is initiated.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.file_search_call.in_progress"] - """The type of the event. Always `response.file_search_call.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_searching_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_searching_event.py deleted file mode 100644 index 5bf1a07..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_call_searching_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFileSearchCallSearchingEvent"] - - -class ResponseFileSearchCallSearchingEvent(BaseModel): - """Emitted when a file search is currently searching.""" - - item_id: str - """The ID of the output item that the file search call is initiated.""" - - output_index: int - """The index of the output item that the file search call is searching.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.file_search_call.searching"] - """The type of the event. Always `response.file_search_call.searching`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call.py deleted file mode 100644 index fa45631..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call.py +++ /dev/null @@ -1,57 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFileSearchToolCall", "Result"] - - -class Result(BaseModel): - attributes: Optional[Dict[str, Union[str, float, bool]]] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - file_id: Optional[str] = None - """The unique ID of the file.""" - - filename: Optional[str] = None - """The name of the file.""" - - score: Optional[float] = None - """The relevance score of the file - a value between 0 and 1.""" - - text: Optional[str] = None - """The text that was retrieved from the file.""" - - -class ResponseFileSearchToolCall(BaseModel): - """The results of a file search tool call. - - See the - [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information. - """ - - id: str - """The unique ID of the file search tool call.""" - - queries: List[str] - """The queries used to search for files.""" - - status: Literal["in_progress", "searching", "completed", "incomplete", "failed"] - """The status of the file search tool call. - - One of `in_progress`, `searching`, `incomplete` or `failed`, - """ - - type: Literal["file_search_call"] - """The type of the file search tool call. Always `file_search_call`.""" - - results: Optional[List[Result]] = None - """The results of the file search tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call_param.py deleted file mode 100644 index 45a5bbb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_file_search_tool_call_param.py +++ /dev/null @@ -1,59 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["ResponseFileSearchToolCallParam", "Result"] - - -class Result(TypedDict, total=False): - attributes: Optional[Dict[str, Union[str, float, bool]]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - file_id: str - """The unique ID of the file.""" - - filename: str - """The name of the file.""" - - score: float - """The relevance score of the file - a value between 0 and 1.""" - - text: str - """The text that was retrieved from the file.""" - - -class ResponseFileSearchToolCallParam(TypedDict, total=False): - """The results of a file search tool call. - - See the - [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information. - """ - - id: Required[str] - """The unique ID of the file search tool call.""" - - queries: Required[SequenceNotStr[str]] - """The queries used to search for files.""" - - status: Required[Literal["in_progress", "searching", "completed", "incomplete", "failed"]] - """The status of the file search tool call. - - One of `in_progress`, `searching`, `incomplete` or `failed`, - """ - - type: Required[Literal["file_search_call"]] - """The type of the file search tool call. Always `file_search_call`.""" - - results: Optional[Iterable[Result]] - """The results of the file search tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config.py deleted file mode 100644 index a4896bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..shared.response_format_text import ResponseFormatText -from ..shared.response_format_json_object import ResponseFormatJSONObject -from .response_format_text_json_schema_config import ResponseFormatTextJSONSchemaConfig - -__all__ = ["ResponseFormatTextConfig"] - -ResponseFormatTextConfig: TypeAlias = Annotated[ - Union[ResponseFormatText, ResponseFormatTextJSONSchemaConfig, ResponseFormatJSONObject], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config_param.py deleted file mode 100644 index fcaf8f3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_config_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from ..shared_params.response_format_text import ResponseFormatText -from ..shared_params.response_format_json_object import ResponseFormatJSONObject -from .response_format_text_json_schema_config_param import ResponseFormatTextJSONSchemaConfigParam - -__all__ = ["ResponseFormatTextConfigParam"] - -ResponseFormatTextConfigParam: TypeAlias = Union[ - ResponseFormatText, ResponseFormatTextJSONSchemaConfigParam, ResponseFormatJSONObject -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config.py deleted file mode 100644 index b953112..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["ResponseFormatTextJSONSchemaConfig"] - - -class ResponseFormatTextJSONSchemaConfig(BaseModel): - """JSON Schema response format. - - Used to generate structured JSON responses. - Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). - """ - - name: str - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - schema_: Dict[str, object] = FieldInfo(alias="schema") - """ - The schema for the response format, described as a JSON Schema object. Learn how - to build JSON schemas [here](https://json-schema.org/). - """ - - type: Literal["json_schema"] - """The type of response format being defined. Always `json_schema`.""" - - description: Optional[str] = None - """ - A description of what the response format is for, used by the model to determine - how to respond in the format. - """ - - strict: Optional[bool] = None - """ - Whether to enable strict schema adherence when generating the output. If set to - true, the model will always follow the exact schema defined in the `schema` - field. Only a subset of JSON Schema is supported when `strict` is `true`. To - learn more, read the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config_param.py deleted file mode 100644 index 6f5c633..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_format_text_json_schema_config_param.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseFormatTextJSONSchemaConfigParam"] - - -class ResponseFormatTextJSONSchemaConfigParam(TypedDict, total=False): - """JSON Schema response format. - - Used to generate structured JSON responses. - Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). - """ - - name: Required[str] - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - schema: Required[Dict[str, object]] - """ - The schema for the response format, described as a JSON Schema object. Learn how - to build JSON schemas [here](https://json-schema.org/). - """ - - type: Required[Literal["json_schema"]] - """The type of response format being defined. Always `json_schema`.""" - - description: str - """ - A description of what the response format is for, used by the model to determine - how to respond in the format. - """ - - strict: Optional[bool] - """ - Whether to enable strict schema adherence when generating the output. If set to - true, the model will always follow the exact schema defined in the `schema` - field. Only a subset of JSON Schema is supported when `strict` is `true`. To - learn more, read the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_delta_event.py deleted file mode 100644 index 0798c2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_delta_event.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDeltaEvent"] - - -class ResponseFunctionCallArgumentsDeltaEvent(BaseModel): - """Emitted when there is a partial function-call arguments delta.""" - - delta: str - """The function-call arguments delta that is added.""" - - item_id: str - """The ID of the output item that the function-call arguments delta is added to.""" - - output_index: int - """ - The index of the output item that the function-call arguments delta is added to. - """ - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.function_call_arguments.delta"] - """The type of the event. Always `response.function_call_arguments.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_done_event.py deleted file mode 100644 index 543cd07..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_arguments_done_event.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionCallArgumentsDoneEvent"] - - -class ResponseFunctionCallArgumentsDoneEvent(BaseModel): - """Emitted when function-call arguments are finalized.""" - - arguments: str - """The function-call arguments.""" - - item_id: str - """The ID of the item.""" - - name: str - """The name of the function that was called.""" - - output_index: int - """The index of the output item.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.function_call_arguments.done"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item.py deleted file mode 100644 index 41898f9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .response_input_file_content import ResponseInputFileContent -from .response_input_text_content import ResponseInputTextContent -from .response_input_image_content import ResponseInputImageContent - -__all__ = ["ResponseFunctionCallOutputItem"] - -ResponseFunctionCallOutputItem: TypeAlias = Annotated[ - Union[ResponseInputTextContent, ResponseInputImageContent, ResponseInputFileContent], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list.py deleted file mode 100644 index 13db577..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .response_function_call_output_item import ResponseFunctionCallOutputItem - -__all__ = ["ResponseFunctionCallOutputItemList"] - -ResponseFunctionCallOutputItemList: TypeAlias = List[ResponseFunctionCallOutputItem] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list_param.py deleted file mode 100644 index 8c286d3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_list_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import TypeAlias - -from .response_input_file_content_param import ResponseInputFileContentParam -from .response_input_text_content_param import ResponseInputTextContentParam -from .response_input_image_content_param import ResponseInputImageContentParam - -__all__ = ["ResponseFunctionCallOutputItemListParam", "ResponseFunctionCallOutputItemParam"] - -ResponseFunctionCallOutputItemParam: TypeAlias = Union[ - ResponseInputTextContentParam, ResponseInputImageContentParam, ResponseInputFileContentParam -] - -ResponseFunctionCallOutputItemListParam: TypeAlias = List[ResponseFunctionCallOutputItemParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_param.py deleted file mode 100644 index 2a703ca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_call_output_item_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .response_input_file_content_param import ResponseInputFileContentParam -from .response_input_text_content_param import ResponseInputTextContentParam -from .response_input_image_content_param import ResponseInputImageContentParam - -__all__ = ["ResponseFunctionCallOutputItemParam"] - -ResponseFunctionCallOutputItemParam: TypeAlias = Union[ - ResponseInputTextContentParam, ResponseInputImageContentParam, ResponseInputFileContentParam -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content.py deleted file mode 100644 index dae48f1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["ResponseFunctionShellCallOutputContent", "Outcome", "OutcomeTimeout", "OutcomeExit"] - - -class OutcomeTimeout(BaseModel): - """Indicates that the shell call exceeded its configured time limit.""" - - type: Literal["timeout"] - """The outcome type. Always `timeout`.""" - - -class OutcomeExit(BaseModel): - """Indicates that the shell commands finished and returned an exit code.""" - - exit_code: int - """The exit code returned by the shell process.""" - - type: Literal["exit"] - """The outcome type. Always `exit`.""" - - -Outcome: TypeAlias = Annotated[Union[OutcomeTimeout, OutcomeExit], PropertyInfo(discriminator="type")] - - -class ResponseFunctionShellCallOutputContent(BaseModel): - """Captured stdout and stderr for a portion of a shell tool call output.""" - - outcome: Outcome - """The exit or timeout outcome associated with this shell call.""" - - stderr: str - """Captured stderr output for the shell call.""" - - stdout: str - """Captured stdout output for the shell call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content_param.py deleted file mode 100644 index 4d8ea70..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_call_output_content_param.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["ResponseFunctionShellCallOutputContentParam", "Outcome", "OutcomeTimeout", "OutcomeExit"] - - -class OutcomeTimeout(TypedDict, total=False): - """Indicates that the shell call exceeded its configured time limit.""" - - type: Required[Literal["timeout"]] - """The outcome type. Always `timeout`.""" - - -class OutcomeExit(TypedDict, total=False): - """Indicates that the shell commands finished and returned an exit code.""" - - exit_code: Required[int] - """The exit code returned by the shell process.""" - - type: Required[Literal["exit"]] - """The outcome type. Always `exit`.""" - - -Outcome: TypeAlias = Union[OutcomeTimeout, OutcomeExit] - - -class ResponseFunctionShellCallOutputContentParam(TypedDict, total=False): - """Captured stdout and stderr for a portion of a shell tool call output.""" - - outcome: Required[Outcome] - """The exit or timeout outcome associated with this shell call.""" - - stderr: Required[str] - """Captured stderr output for the shell call.""" - - stdout: Required[str] - """Captured stdout output for the shell call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call.py deleted file mode 100644 index 7c6a184..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionShellToolCall", "Action"] - - -class Action(BaseModel): - """The shell commands and limits that describe how to run the tool call.""" - - commands: List[str] - - max_output_length: Optional[int] = None - """Optional maximum number of characters to return from each command.""" - - timeout_ms: Optional[int] = None - """Optional timeout in milliseconds for the commands.""" - - -class ResponseFunctionShellToolCall(BaseModel): - """A tool call that executes one or more shell commands in a managed environment.""" - - id: str - """The unique ID of the shell tool call. - - Populated when this item is returned via API. - """ - - action: Action - """The shell commands and limits that describe how to run the tool call.""" - - call_id: str - """The unique ID of the shell tool call generated by the model.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the shell call. - - One of `in_progress`, `completed`, or `incomplete`. - """ - - type: Literal["shell_call"] - """The type of the item. Always `shell_call`.""" - - created_by: Optional[str] = None - """The ID of the entity that created this tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call_output.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call_output.py deleted file mode 100644 index 5523d57..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_shell_tool_call_output.py +++ /dev/null @@ -1,82 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = [ - "ResponseFunctionShellToolCallOutput", - "Output", - "OutputOutcome", - "OutputOutcomeTimeout", - "OutputOutcomeExit", -] - - -class OutputOutcomeTimeout(BaseModel): - """Indicates that the shell call exceeded its configured time limit.""" - - type: Literal["timeout"] - """The outcome type. Always `timeout`.""" - - -class OutputOutcomeExit(BaseModel): - """Indicates that the shell commands finished and returned an exit code.""" - - exit_code: int - """Exit code from the shell process.""" - - type: Literal["exit"] - """The outcome type. Always `exit`.""" - - -OutputOutcome: TypeAlias = Annotated[Union[OutputOutcomeTimeout, OutputOutcomeExit], PropertyInfo(discriminator="type")] - - -class Output(BaseModel): - """The content of a shell tool call output that was emitted.""" - - outcome: OutputOutcome - """ - Represents either an exit outcome (with an exit code) or a timeout outcome for a - shell call output chunk. - """ - - stderr: str - """The standard error output that was captured.""" - - stdout: str - """The standard output that was captured.""" - - created_by: Optional[str] = None - """The identifier of the actor that created the item.""" - - -class ResponseFunctionShellToolCallOutput(BaseModel): - """The output of a shell tool call that was emitted.""" - - id: str - """The unique ID of the shell call output. - - Populated when this item is returned via API. - """ - - call_id: str - """The unique ID of the shell tool call generated by the model.""" - - max_output_length: Optional[int] = None - """The maximum length of the shell command output. - - This is generated by the model and should be passed back with the raw output. - """ - - output: List[Output] - """An array of shell call output contents""" - - type: Literal["shell_call_output"] - """The type of the shell call output. Always `shell_call_output`.""" - - created_by: Optional[str] = None - """The identifier of the actor that created the item.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call.py deleted file mode 100644 index 194e3f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFunctionToolCall"] - - -class ResponseFunctionToolCall(BaseModel): - """A tool call to run a function. - - See the - [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. - """ - - arguments: str - """A JSON string of the arguments to pass to the function.""" - - call_id: str - """The unique ID of the function tool call generated by the model.""" - - name: str - """The name of the function to run.""" - - type: Literal["function_call"] - """The type of the function tool call. Always `function_call`.""" - - id: Optional[str] = None - """The unique ID of the function tool call.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_item.py deleted file mode 100644 index 3df299e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_item.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .response_function_tool_call import ResponseFunctionToolCall - -__all__ = ["ResponseFunctionToolCallItem"] - - -class ResponseFunctionToolCallItem(ResponseFunctionToolCall): - """A tool call to run a function. - - See the - [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. - """ - - id: str # type: ignore - """The unique ID of the function tool call.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_output_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_output_item.py deleted file mode 100644 index 1a2c848..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_output_item.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_input_file import ResponseInputFile -from .response_input_text import ResponseInputText -from .response_input_image import ResponseInputImage - -__all__ = ["ResponseFunctionToolCallOutputItem", "OutputOutputContentList"] - -OutputOutputContentList: TypeAlias = Annotated[ - Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") -] - - -class ResponseFunctionToolCallOutputItem(BaseModel): - id: str - """The unique ID of the function call tool output.""" - - call_id: str - """The unique ID of the function tool call generated by the model.""" - - output: Union[str, List[OutputOutputContentList]] - """ - The output from the function call generated by your code. Can be a string or an - list of output content. - """ - - type: Literal["function_call_output"] - """The type of the function tool call output. Always `function_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_param.py deleted file mode 100644 index 4e8dd3d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_tool_call_param.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseFunctionToolCallParam"] - - -class ResponseFunctionToolCallParam(TypedDict, total=False): - """A tool call to run a function. - - See the - [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more information. - """ - - arguments: Required[str] - """A JSON string of the arguments to pass to the function.""" - - call_id: Required[str] - """The unique ID of the function tool call generated by the model.""" - - name: Required[str] - """The name of the function to run.""" - - type: Required[Literal["function_call"]] - """The type of the function tool call. Always `function_call`.""" - - id: str - """The unique ID of the function tool call.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search.py deleted file mode 100644 index 0cb7e0b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search.py +++ /dev/null @@ -1,84 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["ResponseFunctionWebSearch", "Action", "ActionSearch", "ActionSearchSource", "ActionOpenPage", "ActionFind"] - - -class ActionSearchSource(BaseModel): - """A source used in the search.""" - - type: Literal["url"] - """The type of source. Always `url`.""" - - url: str - """The URL of the source.""" - - -class ActionSearch(BaseModel): - """Action type "search" - Performs a web search query.""" - - query: str - """[DEPRECATED] The search query.""" - - type: Literal["search"] - """The action type.""" - - queries: Optional[List[str]] = None - """The search queries.""" - - sources: Optional[List[ActionSearchSource]] = None - """The sources used in the search.""" - - -class ActionOpenPage(BaseModel): - """Action type "open_page" - Opens a specific URL from search results.""" - - type: Literal["open_page"] - """The action type.""" - - url: str - """The URL opened by the model.""" - - -class ActionFind(BaseModel): - """Action type "find": Searches for a pattern within a loaded page.""" - - pattern: str - """The pattern or text to search for within the page.""" - - type: Literal["find"] - """The action type.""" - - url: str - """The URL of the page searched for the pattern.""" - - -Action: TypeAlias = Annotated[Union[ActionSearch, ActionOpenPage, ActionFind], PropertyInfo(discriminator="type")] - - -class ResponseFunctionWebSearch(BaseModel): - """The results of a web search tool call. - - See the - [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information. - """ - - id: str - """The unique ID of the web search tool call.""" - - action: Action - """ - An object describing the specific action taken in this web search call. Includes - details on how the model used the web (search, open_page, find). - """ - - status: Literal["in_progress", "searching", "completed", "failed"] - """The status of the web search tool call.""" - - type: Literal["web_search_call"] - """The type of the web search tool call. Always `web_search_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search_param.py deleted file mode 100644 index 7db3e3c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_function_web_search_param.py +++ /dev/null @@ -1,92 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr - -__all__ = [ - "ResponseFunctionWebSearchParam", - "Action", - "ActionSearch", - "ActionSearchSource", - "ActionOpenPage", - "ActionFind", -] - - -class ActionSearchSource(TypedDict, total=False): - """A source used in the search.""" - - type: Required[Literal["url"]] - """The type of source. Always `url`.""" - - url: Required[str] - """The URL of the source.""" - - -class ActionSearch(TypedDict, total=False): - """Action type "search" - Performs a web search query.""" - - query: Required[str] - """[DEPRECATED] The search query.""" - - type: Required[Literal["search"]] - """The action type.""" - - queries: SequenceNotStr[str] - """The search queries.""" - - sources: Iterable[ActionSearchSource] - """The sources used in the search.""" - - -class ActionOpenPage(TypedDict, total=False): - """Action type "open_page" - Opens a specific URL from search results.""" - - type: Required[Literal["open_page"]] - """The action type.""" - - url: Required[str] - """The URL opened by the model.""" - - -class ActionFind(TypedDict, total=False): - """Action type "find": Searches for a pattern within a loaded page.""" - - pattern: Required[str] - """The pattern or text to search for within the page.""" - - type: Required[Literal["find"]] - """The action type.""" - - url: Required[str] - """The URL of the page searched for the pattern.""" - - -Action: TypeAlias = Union[ActionSearch, ActionOpenPage, ActionFind] - - -class ResponseFunctionWebSearchParam(TypedDict, total=False): - """The results of a web search tool call. - - See the - [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information. - """ - - id: Required[str] - """The unique ID of the web search tool call.""" - - action: Required[Action] - """ - An object describing the specific action taken in this web search call. Includes - details on how the model used the web (search, open_page, find). - """ - - status: Required[Literal["in_progress", "searching", "completed", "failed"]] - """The status of the web search tool call.""" - - type: Required[Literal["web_search_call"]] - """The type of the web search tool call. Always `web_search_call`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_completed_event.py deleted file mode 100644 index f6ce9d0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_completed_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseImageGenCallCompletedEvent"] - - -class ResponseImageGenCallCompletedEvent(BaseModel): - """ - Emitted when an image generation tool call has completed and the final image is available. - """ - - item_id: str - """The unique identifier of the image generation item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.image_generation_call.completed"] - """The type of the event. Always 'response.image_generation_call.completed'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_generating_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_generating_event.py deleted file mode 100644 index 8e3026d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_generating_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseImageGenCallGeneratingEvent"] - - -class ResponseImageGenCallGeneratingEvent(BaseModel): - """ - Emitted when an image generation tool call is actively generating an image (intermediate state). - """ - - item_id: str - """The unique identifier of the image generation item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of the image generation item being processed.""" - - type: Literal["response.image_generation_call.generating"] - """The type of the event. Always 'response.image_generation_call.generating'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_in_progress_event.py deleted file mode 100644 index 60726a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_in_progress_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseImageGenCallInProgressEvent"] - - -class ResponseImageGenCallInProgressEvent(BaseModel): - """Emitted when an image generation tool call is in progress.""" - - item_id: str - """The unique identifier of the image generation item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of the image generation item being processed.""" - - type: Literal["response.image_generation_call.in_progress"] - """The type of the event. Always 'response.image_generation_call.in_progress'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_partial_image_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_partial_image_event.py deleted file mode 100644 index 289d5d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_image_gen_call_partial_image_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseImageGenCallPartialImageEvent"] - - -class ResponseImageGenCallPartialImageEvent(BaseModel): - """Emitted when a partial image is available during image generation streaming.""" - - item_id: str - """The unique identifier of the image generation item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - partial_image_b64: str - """Base64-encoded partial image data, suitable for rendering as an image.""" - - partial_image_index: int - """ - 0-based index for the partial image (backend is 1-based, but this is 0-based for - the user). - """ - - sequence_number: int - """The sequence number of the image generation item being processed.""" - - type: Literal["response.image_generation_call.partial_image"] - """The type of the event. Always 'response.image_generation_call.partial_image'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_in_progress_event.py deleted file mode 100644 index 9d9bbd9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_in_progress_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseInProgressEvent"] - - -class ResponseInProgressEvent(BaseModel): - """Emitted when the response is in progress.""" - - response: Response - """The response that is in progress.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.in_progress"] - """The type of the event. Always `response.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_includable.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_includable.py deleted file mode 100644 index 675c834..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_includable.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ResponseIncludable"] - -ResponseIncludable: TypeAlias = Literal[ - "file_search_call.results", - "web_search_call.results", - "web_search_call.action.sources", - "message.input_image.image_url", - "computer_call_output.output.image_url", - "code_interpreter_call.outputs", - "reasoning.encrypted_content", - "message.output_text.logprobs", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_incomplete_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_incomplete_event.py deleted file mode 100644 index ef99c5f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_incomplete_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseIncompleteEvent"] - - -class ResponseIncompleteEvent(BaseModel): - """An event that is emitted when a response finishes as incomplete.""" - - response: Response - """The response that was incomplete.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.incomplete"] - """The type of the event. Always `response.incomplete`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio.py deleted file mode 100644 index f362ba4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputAudio", "InputAudio"] - - -class InputAudio(BaseModel): - data: str - """Base64-encoded audio data.""" - - format: Literal["mp3", "wav"] - """The format of the audio data. Currently supported formats are `mp3` and `wav`.""" - - -class ResponseInputAudio(BaseModel): - """An audio input to the model.""" - - input_audio: InputAudio - - type: Literal["input_audio"] - """The type of the input item. Always `input_audio`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio_param.py deleted file mode 100644 index 0be935c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_audio_param.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputAudioParam", "InputAudio"] - - -class InputAudio(TypedDict, total=False): - data: Required[str] - """Base64-encoded audio data.""" - - format: Required[Literal["mp3", "wav"]] - """The format of the audio data. Currently supported formats are `mp3` and `wav`.""" - - -class ResponseInputAudioParam(TypedDict, total=False): - """An audio input to the model.""" - - input_audio: Required[InputAudio] - - type: Required[Literal["input_audio"]] - """The type of the input item. Always `input_audio`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content.py deleted file mode 100644 index 1726909..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .response_input_file import ResponseInputFile -from .response_input_text import ResponseInputText -from .response_input_image import ResponseInputImage - -__all__ = ["ResponseInputContent"] - -ResponseInputContent: TypeAlias = Annotated[ - Union[ResponseInputText, ResponseInputImage, ResponseInputFile], PropertyInfo(discriminator="type") -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content_param.py deleted file mode 100644 index 7791cdf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_content_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .response_input_file_param import ResponseInputFileParam -from .response_input_text_param import ResponseInputTextParam -from .response_input_image_param import ResponseInputImageParam - -__all__ = ["ResponseInputContentParam"] - -ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file.py deleted file mode 100644 index 3e5fb70..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputFile"] - - -class ResponseInputFile(BaseModel): - """A file input to the model.""" - - type: Literal["input_file"] - """The type of the input item. Always `input_file`.""" - - file_data: Optional[str] = None - """The content of the file to be sent to the model.""" - - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - file_url: Optional[str] = None - """The URL of the file to be sent to the model.""" - - filename: Optional[str] = None - """The name of the file to be sent to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content.py deleted file mode 100644 index f0dfef5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputFileContent"] - - -class ResponseInputFileContent(BaseModel): - """A file input to the model.""" - - type: Literal["input_file"] - """The type of the input item. Always `input_file`.""" - - file_data: Optional[str] = None - """The base64-encoded data of the file to be sent to the model.""" - - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - file_url: Optional[str] = None - """The URL of the file to be sent to the model.""" - - filename: Optional[str] = None - """The name of the file to be sent to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content_param.py deleted file mode 100644 index 376f6c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_content_param.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputFileContentParam"] - - -class ResponseInputFileContentParam(TypedDict, total=False): - """A file input to the model.""" - - type: Required[Literal["input_file"]] - """The type of the input item. Always `input_file`.""" - - file_data: Optional[str] - """The base64-encoded data of the file to be sent to the model.""" - - file_id: Optional[str] - """The ID of the file to be sent to the model.""" - - file_url: Optional[str] - """The URL of the file to be sent to the model.""" - - filename: Optional[str] - """The name of the file to be sent to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_param.py deleted file mode 100644 index 8b5da20..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_file_param.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputFileParam"] - - -class ResponseInputFileParam(TypedDict, total=False): - """A file input to the model.""" - - type: Required[Literal["input_file"]] - """The type of the input item. Always `input_file`.""" - - file_data: str - """The content of the file to be sent to the model.""" - - file_id: Optional[str] - """The ID of the file to be sent to the model.""" - - file_url: str - """The URL of the file to be sent to the model.""" - - filename: str - """The name of the file to be sent to the model.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image.py deleted file mode 100644 index 500bc4b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputImage"] - - -class ResponseInputImage(BaseModel): - """An image input to the model. - - Learn about [image inputs](https://platform.openai.com/docs/guides/vision). - """ - - detail: Literal["low", "high", "auto"] - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - type: Literal["input_image"] - """The type of the input item. Always `input_image`.""" - - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - image_url: Optional[str] = None - """The URL of the image to be sent to the model. - - A fully qualified URL or base64 encoded image in a data URL. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content.py deleted file mode 100644 index e38bc28..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputImageContent"] - - -class ResponseInputImageContent(BaseModel): - """An image input to the model. - - Learn about [image inputs](https://platform.openai.com/docs/guides/vision) - """ - - type: Literal["input_image"] - """The type of the input item. Always `input_image`.""" - - detail: Optional[Literal["low", "high", "auto"]] = None - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - file_id: Optional[str] = None - """The ID of the file to be sent to the model.""" - - image_url: Optional[str] = None - """The URL of the image to be sent to the model. - - A fully qualified URL or base64 encoded image in a data URL. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content_param.py deleted file mode 100644 index c21f46d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_content_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputImageContentParam"] - - -class ResponseInputImageContentParam(TypedDict, total=False): - """An image input to the model. - - Learn about [image inputs](https://platform.openai.com/docs/guides/vision) - """ - - type: Required[Literal["input_image"]] - """The type of the input item. Always `input_image`.""" - - detail: Optional[Literal["low", "high", "auto"]] - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - file_id: Optional[str] - """The ID of the file to be sent to the model.""" - - image_url: Optional[str] - """The URL of the image to be sent to the model. - - A fully qualified URL or base64 encoded image in a data URL. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_param.py deleted file mode 100644 index fd8c1bd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_image_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputImageParam"] - - -class ResponseInputImageParam(TypedDict, total=False): - """An image input to the model. - - Learn about [image inputs](https://platform.openai.com/docs/guides/vision). - """ - - detail: Required[Literal["low", "high", "auto"]] - """The detail level of the image to be sent to the model. - - One of `high`, `low`, or `auto`. Defaults to `auto`. - """ - - type: Required[Literal["input_image"]] - """The type of the input item. Always `input_image`.""" - - file_id: Optional[str] - """The ID of the file to be sent to the model.""" - - image_url: Optional[str] - """The URL of the image to be sent to the model. - - A fully qualified URL or base64 encoded image in a data URL. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item.py deleted file mode 100644 index 23eb2c8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item.py +++ /dev/null @@ -1,534 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .easy_input_message import EasyInputMessage -from .response_output_message import ResponseOutputMessage -from .response_reasoning_item import ResponseReasoningItem -from .response_custom_tool_call import ResponseCustomToolCall -from .response_computer_tool_call import ResponseComputerToolCall -from .response_function_tool_call import ResponseFunctionToolCall -from .response_function_web_search import ResponseFunctionWebSearch -from .response_compaction_item_param import ResponseCompactionItemParam -from .response_file_search_tool_call import ResponseFileSearchToolCall -from .response_custom_tool_call_output import ResponseCustomToolCallOutput -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall -from .response_input_message_content_list import ResponseInputMessageContentList -from .response_function_call_output_item_list import ResponseFunctionCallOutputItemList -from .response_function_shell_call_output_content import ResponseFunctionShellCallOutputContent -from .response_computer_tool_call_output_screenshot import ResponseComputerToolCallOutputScreenshot - -__all__ = [ - "ResponseInputItem", - "Message", - "ComputerCallOutput", - "ComputerCallOutputAcknowledgedSafetyCheck", - "FunctionCallOutput", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "LocalShellCallOutput", - "ShellCall", - "ShellCallAction", - "ShellCallOutput", - "ApplyPatchCall", - "ApplyPatchCallOperation", - "ApplyPatchCallOperationCreateFile", - "ApplyPatchCallOperationDeleteFile", - "ApplyPatchCallOperationUpdateFile", - "ApplyPatchCallOutput", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", - "McpApprovalResponse", - "McpCall", - "ItemReference", -] - - -class Message(BaseModel): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. - """ - - content: ResponseInputMessageContentList - """ - A list of one or many input items to the model, containing different content - types. - """ - - role: Literal["user", "system", "developer"] - """The role of the message input. One of `user`, `system`, or `developer`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always set to `message`.""" - - -class ComputerCallOutputAcknowledgedSafetyCheck(BaseModel): - """A pending safety check for the computer call.""" - - id: str - """The ID of the pending safety check.""" - - code: Optional[str] = None - """The type of the pending safety check.""" - - message: Optional[str] = None - """Details about the pending safety check.""" - - -class ComputerCallOutput(BaseModel): - """The output of a computer tool call.""" - - call_id: str - """The ID of the computer tool call that produced the output.""" - - output: ResponseComputerToolCallOutputScreenshot - """A computer screenshot image used with the computer use tool.""" - - type: Literal["computer_call_output"] - """The type of the computer tool call output. Always `computer_call_output`.""" - - id: Optional[str] = None - """The ID of the computer tool call output.""" - - acknowledged_safety_checks: Optional[List[ComputerCallOutputAcknowledgedSafetyCheck]] = None - """ - The safety checks reported by the API that have been acknowledged by the - developer. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - -class FunctionCallOutput(BaseModel): - """The output of a function tool call.""" - - call_id: str - """The unique ID of the function tool call generated by the model.""" - - output: Union[str, ResponseFunctionCallOutputItemList] - """Text, image, or file output of the function tool call.""" - - type: Literal["function_call_output"] - """The type of the function tool call output. Always `function_call_output`.""" - - id: Optional[str] = None - """The unique ID of the function tool call output. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - -class ImageGenerationCall(BaseModel): - """An image generation request made by the model.""" - - id: str - """The unique ID of the image generation call.""" - - result: Optional[str] = None - """The generated image encoded in base64.""" - - status: Literal["in_progress", "completed", "generating", "failed"] - """The status of the image generation call.""" - - type: Literal["image_generation_call"] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(BaseModel): - """Execute a shell command on the server.""" - - command: List[str] - """The command to run.""" - - env: Dict[str, str] - """Environment variables to set for the command.""" - - type: Literal["exec"] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] = None - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] = None - """Optional user to run the command as.""" - - working_directory: Optional[str] = None - """Optional working directory to run the command in.""" - - -class LocalShellCall(BaseModel): - """A tool call to run a command on the local shell.""" - - id: str - """The unique ID of the local shell call.""" - - action: LocalShellCallAction - """Execute a shell command on the server.""" - - call_id: str - """The unique ID of the local shell tool call generated by the model.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the local shell call.""" - - type: Literal["local_shell_call"] - """The type of the local shell call. Always `local_shell_call`.""" - - -class LocalShellCallOutput(BaseModel): - """The output of a local shell tool call.""" - - id: str - """The unique ID of the local shell tool call generated by the model.""" - - output: str - """A JSON string of the output of the local shell tool call.""" - - type: Literal["local_shell_call_output"] - """The type of the local shell tool call output. Always `local_shell_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" - - -class ShellCallAction(BaseModel): - """The shell commands and limits that describe how to run the tool call.""" - - commands: List[str] - """Ordered shell commands for the execution environment to run.""" - - max_output_length: Optional[int] = None - """ - Maximum number of UTF-8 characters to capture from combined stdout and stderr - output. - """ - - timeout_ms: Optional[int] = None - """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" - - -class ShellCall(BaseModel): - """A tool representing a request to execute one or more shell commands.""" - - action: ShellCallAction - """The shell commands and limits that describe how to run the tool call.""" - - call_id: str - """The unique ID of the shell tool call generated by the model.""" - - type: Literal["shell_call"] - """The type of the item. Always `shell_call`.""" - - id: Optional[str] = None - """The unique ID of the shell tool call. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the shell call. - - One of `in_progress`, `completed`, or `incomplete`. - """ - - -class ShellCallOutput(BaseModel): - """The streamed output items emitted by a shell tool call.""" - - call_id: str - """The unique ID of the shell tool call generated by the model.""" - - output: List[ResponseFunctionShellCallOutputContent] - """ - Captured chunks of stdout and stderr output, along with their associated - outcomes. - """ - - type: Literal["shell_call_output"] - """The type of the item. Always `shell_call_output`.""" - - id: Optional[str] = None - """The unique ID of the shell tool call output. - - Populated when this item is returned via API. - """ - - max_output_length: Optional[int] = None - """ - The maximum number of UTF-8 characters captured for this shell call's combined - output. - """ - - -class ApplyPatchCallOperationCreateFile(BaseModel): - """Instruction for creating a new file via the apply_patch tool.""" - - diff: str - """Unified diff content to apply when creating the file.""" - - path: str - """Path of the file to create relative to the workspace root.""" - - type: Literal["create_file"] - """The operation type. Always `create_file`.""" - - -class ApplyPatchCallOperationDeleteFile(BaseModel): - """Instruction for deleting an existing file via the apply_patch tool.""" - - path: str - """Path of the file to delete relative to the workspace root.""" - - type: Literal["delete_file"] - """The operation type. Always `delete_file`.""" - - -class ApplyPatchCallOperationUpdateFile(BaseModel): - """Instruction for updating an existing file via the apply_patch tool.""" - - diff: str - """Unified diff content to apply to the existing file.""" - - path: str - """Path of the file to update relative to the workspace root.""" - - type: Literal["update_file"] - """The operation type. Always `update_file`.""" - - -ApplyPatchCallOperation: TypeAlias = Annotated[ - Union[ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile], - PropertyInfo(discriminator="type"), -] - - -class ApplyPatchCall(BaseModel): - """ - A tool call representing a request to create, delete, or update files using diff patches. - """ - - call_id: str - """The unique ID of the apply patch tool call generated by the model.""" - - operation: ApplyPatchCallOperation - """ - The specific create, delete, or update instruction for the apply_patch tool - call. - """ - - status: Literal["in_progress", "completed"] - """The status of the apply patch tool call. One of `in_progress` or `completed`.""" - - type: Literal["apply_patch_call"] - """The type of the item. Always `apply_patch_call`.""" - - id: Optional[str] = None - """The unique ID of the apply patch tool call. - - Populated when this item is returned via API. - """ - - -class ApplyPatchCallOutput(BaseModel): - """The streamed output emitted by an apply patch tool call.""" - - call_id: str - """The unique ID of the apply patch tool call generated by the model.""" - - status: Literal["completed", "failed"] - """The status of the apply patch tool call output. One of `completed` or `failed`.""" - - type: Literal["apply_patch_call_output"] - """The type of the item. Always `apply_patch_call_output`.""" - - id: Optional[str] = None - """The unique ID of the apply patch tool call output. - - Populated when this item is returned via API. - """ - - output: Optional[str] = None - """ - Optional human-readable log text from the apply patch tool (e.g., patch results - or errors). - """ - - -class McpListToolsTool(BaseModel): - """A tool available on an MCP server.""" - - input_schema: object - """The JSON schema describing the tool's input.""" - - name: str - """The name of the tool.""" - - annotations: Optional[object] = None - """Additional annotations about the tool.""" - - description: Optional[str] = None - """The description of the tool.""" - - -class McpListTools(BaseModel): - """A list of tools available on an MCP server.""" - - id: str - """The unique ID of the list.""" - - server_label: str - """The label of the MCP server.""" - - tools: List[McpListToolsTool] - """The tools available on the server.""" - - type: Literal["mcp_list_tools"] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] = None - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(BaseModel): - """A request for human approval of a tool invocation.""" - - id: str - """The unique ID of the approval request.""" - - arguments: str - """A JSON string of arguments for the tool.""" - - name: str - """The name of the tool to run.""" - - server_label: str - """The label of the MCP server making the request.""" - - type: Literal["mcp_approval_request"] - """The type of the item. Always `mcp_approval_request`.""" - - -class McpApprovalResponse(BaseModel): - """A response to an MCP approval request.""" - - approval_request_id: str - """The ID of the approval request being answered.""" - - approve: bool - """Whether the request was approved.""" - - type: Literal["mcp_approval_response"] - """The type of the item. Always `mcp_approval_response`.""" - - id: Optional[str] = None - """The unique ID of the approval response""" - - reason: Optional[str] = None - """Optional reason for the decision.""" - - -class McpCall(BaseModel): - """An invocation of a tool on an MCP server.""" - - id: str - """The unique ID of the tool call.""" - - arguments: str - """A JSON string of the arguments passed to the tool.""" - - name: str - """The name of the tool that was run.""" - - server_label: str - """The label of the MCP server running the tool.""" - - type: Literal["mcp_call"] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] = None - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] = None - """The error from the tool call, if any.""" - - output: Optional[str] = None - """The output from the tool call.""" - - status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -class ItemReference(BaseModel): - """An internal identifier for an item to reference.""" - - id: str - """The ID of the item to reference.""" - - type: Optional[Literal["item_reference"]] = None - """The type of item to reference. Always `item_reference`.""" - - -ResponseInputItem: TypeAlias = Annotated[ - Union[ - EasyInputMessage, - Message, - ResponseOutputMessage, - ResponseFileSearchToolCall, - ResponseComputerToolCall, - ComputerCallOutput, - ResponseFunctionWebSearch, - ResponseFunctionToolCall, - FunctionCallOutput, - ResponseReasoningItem, - ResponseCompactionItemParam, - ImageGenerationCall, - ResponseCodeInterpreterToolCall, - LocalShellCall, - LocalShellCallOutput, - ShellCall, - ShellCallOutput, - ApplyPatchCall, - ApplyPatchCallOutput, - McpListTools, - McpApprovalRequest, - McpApprovalResponse, - McpCall, - ResponseCustomToolCallOutput, - ResponseCustomToolCall, - ItemReference, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item_param.py deleted file mode 100644 index 2c42b93..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_item_param.py +++ /dev/null @@ -1,531 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from .easy_input_message_param import EasyInputMessageParam -from .response_output_message_param import ResponseOutputMessageParam -from .response_reasoning_item_param import ResponseReasoningItemParam -from .response_custom_tool_call_param import ResponseCustomToolCallParam -from .response_computer_tool_call_param import ResponseComputerToolCallParam -from .response_function_tool_call_param import ResponseFunctionToolCallParam -from .response_function_web_search_param import ResponseFunctionWebSearchParam -from .response_compaction_item_param_param import ResponseCompactionItemParamParam -from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam -from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam -from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam -from .response_input_message_content_list_param import ResponseInputMessageContentListParam -from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam -from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam -from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam - -__all__ = [ - "ResponseInputItemParam", - "Message", - "ComputerCallOutput", - "ComputerCallOutputAcknowledgedSafetyCheck", - "FunctionCallOutput", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "LocalShellCallOutput", - "ShellCall", - "ShellCallAction", - "ShellCallOutput", - "ApplyPatchCall", - "ApplyPatchCallOperation", - "ApplyPatchCallOperationCreateFile", - "ApplyPatchCallOperationDeleteFile", - "ApplyPatchCallOperationUpdateFile", - "ApplyPatchCallOutput", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", - "McpApprovalResponse", - "McpCall", - "ItemReference", -] - - -class Message(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. - """ - - content: Required[ResponseInputMessageContentListParam] - """ - A list of one or many input items to the model, containing different content - types. - """ - - role: Required[Literal["user", "system", "developer"]] - """The role of the message input. One of `user`, `system`, or `developer`.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Literal["message"] - """The type of the message input. Always set to `message`.""" - - -class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): - """A pending safety check for the computer call.""" - - id: Required[str] - """The ID of the pending safety check.""" - - code: Optional[str] - """The type of the pending safety check.""" - - message: Optional[str] - """Details about the pending safety check.""" - - -class ComputerCallOutput(TypedDict, total=False): - """The output of a computer tool call.""" - - call_id: Required[str] - """The ID of the computer tool call that produced the output.""" - - output: Required[ResponseComputerToolCallOutputScreenshotParam] - """A computer screenshot image used with the computer use tool.""" - - type: Required[Literal["computer_call_output"]] - """The type of the computer tool call output. Always `computer_call_output`.""" - - id: Optional[str] - """The ID of the computer tool call output.""" - - acknowledged_safety_checks: Optional[Iterable[ComputerCallOutputAcknowledgedSafetyCheck]] - """ - The safety checks reported by the API that have been acknowledged by the - developer. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - -class FunctionCallOutput(TypedDict, total=False): - """The output of a function tool call.""" - - call_id: Required[str] - """The unique ID of the function tool call generated by the model.""" - - output: Required[Union[str, ResponseFunctionCallOutputItemListParam]] - """Text, image, or file output of the function tool call.""" - - type: Required[Literal["function_call_output"]] - """The type of the function tool call output. Always `function_call_output`.""" - - id: Optional[str] - """The unique ID of the function tool call output. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - -class ImageGenerationCall(TypedDict, total=False): - """An image generation request made by the model.""" - - id: Required[str] - """The unique ID of the image generation call.""" - - result: Required[Optional[str]] - """The generated image encoded in base64.""" - - status: Required[Literal["in_progress", "completed", "generating", "failed"]] - """The status of the image generation call.""" - - type: Required[Literal["image_generation_call"]] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(TypedDict, total=False): - """Execute a shell command on the server.""" - - command: Required[SequenceNotStr[str]] - """The command to run.""" - - env: Required[Dict[str, str]] - """Environment variables to set for the command.""" - - type: Required[Literal["exec"]] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] - """Optional user to run the command as.""" - - working_directory: Optional[str] - """Optional working directory to run the command in.""" - - -class LocalShellCall(TypedDict, total=False): - """A tool call to run a command on the local shell.""" - - id: Required[str] - """The unique ID of the local shell call.""" - - action: Required[LocalShellCallAction] - """Execute a shell command on the server.""" - - call_id: Required[str] - """The unique ID of the local shell tool call generated by the model.""" - - status: Required[Literal["in_progress", "completed", "incomplete"]] - """The status of the local shell call.""" - - type: Required[Literal["local_shell_call"]] - """The type of the local shell call. Always `local_shell_call`.""" - - -class LocalShellCallOutput(TypedDict, total=False): - """The output of a local shell tool call.""" - - id: Required[str] - """The unique ID of the local shell tool call generated by the model.""" - - output: Required[str] - """A JSON string of the output of the local shell tool call.""" - - type: Required[Literal["local_shell_call_output"]] - """The type of the local shell tool call output. Always `local_shell_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" - - -class ShellCallAction(TypedDict, total=False): - """The shell commands and limits that describe how to run the tool call.""" - - commands: Required[SequenceNotStr[str]] - """Ordered shell commands for the execution environment to run.""" - - max_output_length: Optional[int] - """ - Maximum number of UTF-8 characters to capture from combined stdout and stderr - output. - """ - - timeout_ms: Optional[int] - """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" - - -class ShellCall(TypedDict, total=False): - """A tool representing a request to execute one or more shell commands.""" - - action: Required[ShellCallAction] - """The shell commands and limits that describe how to run the tool call.""" - - call_id: Required[str] - """The unique ID of the shell tool call generated by the model.""" - - type: Required[Literal["shell_call"]] - """The type of the item. Always `shell_call`.""" - - id: Optional[str] - """The unique ID of the shell tool call. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the shell call. - - One of `in_progress`, `completed`, or `incomplete`. - """ - - -class ShellCallOutput(TypedDict, total=False): - """The streamed output items emitted by a shell tool call.""" - - call_id: Required[str] - """The unique ID of the shell tool call generated by the model.""" - - output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] - """ - Captured chunks of stdout and stderr output, along with their associated - outcomes. - """ - - type: Required[Literal["shell_call_output"]] - """The type of the item. Always `shell_call_output`.""" - - id: Optional[str] - """The unique ID of the shell tool call output. - - Populated when this item is returned via API. - """ - - max_output_length: Optional[int] - """ - The maximum number of UTF-8 characters captured for this shell call's combined - output. - """ - - -class ApplyPatchCallOperationCreateFile(TypedDict, total=False): - """Instruction for creating a new file via the apply_patch tool.""" - - diff: Required[str] - """Unified diff content to apply when creating the file.""" - - path: Required[str] - """Path of the file to create relative to the workspace root.""" - - type: Required[Literal["create_file"]] - """The operation type. Always `create_file`.""" - - -class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): - """Instruction for deleting an existing file via the apply_patch tool.""" - - path: Required[str] - """Path of the file to delete relative to the workspace root.""" - - type: Required[Literal["delete_file"]] - """The operation type. Always `delete_file`.""" - - -class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): - """Instruction for updating an existing file via the apply_patch tool.""" - - diff: Required[str] - """Unified diff content to apply to the existing file.""" - - path: Required[str] - """Path of the file to update relative to the workspace root.""" - - type: Required[Literal["update_file"]] - """The operation type. Always `update_file`.""" - - -ApplyPatchCallOperation: TypeAlias = Union[ - ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile -] - - -class ApplyPatchCall(TypedDict, total=False): - """ - A tool call representing a request to create, delete, or update files using diff patches. - """ - - call_id: Required[str] - """The unique ID of the apply patch tool call generated by the model.""" - - operation: Required[ApplyPatchCallOperation] - """ - The specific create, delete, or update instruction for the apply_patch tool - call. - """ - - status: Required[Literal["in_progress", "completed"]] - """The status of the apply patch tool call. One of `in_progress` or `completed`.""" - - type: Required[Literal["apply_patch_call"]] - """The type of the item. Always `apply_patch_call`.""" - - id: Optional[str] - """The unique ID of the apply patch tool call. - - Populated when this item is returned via API. - """ - - -class ApplyPatchCallOutput(TypedDict, total=False): - """The streamed output emitted by an apply patch tool call.""" - - call_id: Required[str] - """The unique ID of the apply patch tool call generated by the model.""" - - status: Required[Literal["completed", "failed"]] - """The status of the apply patch tool call output. One of `completed` or `failed`.""" - - type: Required[Literal["apply_patch_call_output"]] - """The type of the item. Always `apply_patch_call_output`.""" - - id: Optional[str] - """The unique ID of the apply patch tool call output. - - Populated when this item is returned via API. - """ - - output: Optional[str] - """ - Optional human-readable log text from the apply patch tool (e.g., patch results - or errors). - """ - - -class McpListToolsTool(TypedDict, total=False): - """A tool available on an MCP server.""" - - input_schema: Required[object] - """The JSON schema describing the tool's input.""" - - name: Required[str] - """The name of the tool.""" - - annotations: Optional[object] - """Additional annotations about the tool.""" - - description: Optional[str] - """The description of the tool.""" - - -class McpListTools(TypedDict, total=False): - """A list of tools available on an MCP server.""" - - id: Required[str] - """The unique ID of the list.""" - - server_label: Required[str] - """The label of the MCP server.""" - - tools: Required[Iterable[McpListToolsTool]] - """The tools available on the server.""" - - type: Required[Literal["mcp_list_tools"]] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(TypedDict, total=False): - """A request for human approval of a tool invocation.""" - - id: Required[str] - """The unique ID of the approval request.""" - - arguments: Required[str] - """A JSON string of arguments for the tool.""" - - name: Required[str] - """The name of the tool to run.""" - - server_label: Required[str] - """The label of the MCP server making the request.""" - - type: Required[Literal["mcp_approval_request"]] - """The type of the item. Always `mcp_approval_request`.""" - - -class McpApprovalResponse(TypedDict, total=False): - """A response to an MCP approval request.""" - - approval_request_id: Required[str] - """The ID of the approval request being answered.""" - - approve: Required[bool] - """Whether the request was approved.""" - - type: Required[Literal["mcp_approval_response"]] - """The type of the item. Always `mcp_approval_response`.""" - - id: Optional[str] - """The unique ID of the approval response""" - - reason: Optional[str] - """Optional reason for the decision.""" - - -class McpCall(TypedDict, total=False): - """An invocation of a tool on an MCP server.""" - - id: Required[str] - """The unique ID of the tool call.""" - - arguments: Required[str] - """A JSON string of the arguments passed to the tool.""" - - name: Required[str] - """The name of the tool that was run.""" - - server_label: Required[str] - """The label of the MCP server running the tool.""" - - type: Required[Literal["mcp_call"]] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] - """The error from the tool call, if any.""" - - output: Optional[str] - """The output from the tool call.""" - - status: Literal["in_progress", "completed", "incomplete", "calling", "failed"] - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -class ItemReference(TypedDict, total=False): - """An internal identifier for an item to reference.""" - - id: Required[str] - """The ID of the item to reference.""" - - type: Optional[Literal["item_reference"]] - """The type of item to reference. Always `item_reference`.""" - - -ResponseInputItemParam: TypeAlias = Union[ - EasyInputMessageParam, - Message, - ResponseOutputMessageParam, - ResponseFileSearchToolCallParam, - ResponseComputerToolCallParam, - ComputerCallOutput, - ResponseFunctionWebSearchParam, - ResponseFunctionToolCallParam, - FunctionCallOutput, - ResponseReasoningItemParam, - ResponseCompactionItemParamParam, - ImageGenerationCall, - ResponseCodeInterpreterToolCallParam, - LocalShellCall, - LocalShellCallOutput, - ShellCall, - ShellCallOutput, - ApplyPatchCall, - ApplyPatchCallOutput, - McpListTools, - McpApprovalRequest, - McpApprovalResponse, - McpCall, - ResponseCustomToolCallOutputParam, - ResponseCustomToolCallParam, - ItemReference, -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list.py deleted file mode 100644 index 99b7c10..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .response_input_content import ResponseInputContent - -__all__ = ["ResponseInputMessageContentList"] - -ResponseInputMessageContentList: TypeAlias = List[ResponseInputContent] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list_param.py deleted file mode 100644 index 080613d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_content_list_param.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import TypeAlias - -from .response_input_file_param import ResponseInputFileParam -from .response_input_text_param import ResponseInputTextParam -from .response_input_image_param import ResponseInputImageParam - -__all__ = ["ResponseInputMessageContentListParam", "ResponseInputContentParam"] - -ResponseInputContentParam: TypeAlias = Union[ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] - -ResponseInputMessageContentListParam: TypeAlias = List[ResponseInputContentParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_item.py deleted file mode 100644 index 6a788e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_message_item.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_input_message_content_list import ResponseInputMessageContentList - -__all__ = ["ResponseInputMessageItem"] - - -class ResponseInputMessageItem(BaseModel): - id: str - """The unique ID of the message input.""" - - content: ResponseInputMessageContentList - """ - A list of one or many input items to the model, containing different content - types. - """ - - role: Literal["user", "system", "developer"] - """The role of the message input. One of `user`, `system`, or `developer`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Optional[Literal["message"]] = None - """The type of the message input. Always set to `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_param.py deleted file mode 100644 index c2d12c0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_param.py +++ /dev/null @@ -1,534 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from .easy_input_message_param import EasyInputMessageParam -from .response_output_message_param import ResponseOutputMessageParam -from .response_reasoning_item_param import ResponseReasoningItemParam -from .response_custom_tool_call_param import ResponseCustomToolCallParam -from .response_computer_tool_call_param import ResponseComputerToolCallParam -from .response_function_tool_call_param import ResponseFunctionToolCallParam -from .response_function_web_search_param import ResponseFunctionWebSearchParam -from .response_compaction_item_param_param import ResponseCompactionItemParamParam -from .response_file_search_tool_call_param import ResponseFileSearchToolCallParam -from .response_custom_tool_call_output_param import ResponseCustomToolCallOutputParam -from .response_code_interpreter_tool_call_param import ResponseCodeInterpreterToolCallParam -from .response_input_message_content_list_param import ResponseInputMessageContentListParam -from .response_function_call_output_item_list_param import ResponseFunctionCallOutputItemListParam -from .response_function_shell_call_output_content_param import ResponseFunctionShellCallOutputContentParam -from .response_computer_tool_call_output_screenshot_param import ResponseComputerToolCallOutputScreenshotParam - -__all__ = [ - "ResponseInputParam", - "ResponseInputItemParam", - "Message", - "ComputerCallOutput", - "ComputerCallOutputAcknowledgedSafetyCheck", - "FunctionCallOutput", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "LocalShellCallOutput", - "ShellCall", - "ShellCallAction", - "ShellCallOutput", - "ApplyPatchCall", - "ApplyPatchCallOperation", - "ApplyPatchCallOperationCreateFile", - "ApplyPatchCallOperationDeleteFile", - "ApplyPatchCallOperationUpdateFile", - "ApplyPatchCallOutput", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", - "McpApprovalResponse", - "McpCall", - "ItemReference", -] - - -class Message(TypedDict, total=False): - """ - A message input to the model with a role indicating instruction following - hierarchy. Instructions given with the `developer` or `system` role take - precedence over instructions given with the `user` role. - """ - - content: Required[ResponseInputMessageContentListParam] - """ - A list of one or many input items to the model, containing different content - types. - """ - - role: Required[Literal["user", "system", "developer"]] - """The role of the message input. One of `user`, `system`, or `developer`.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - type: Literal["message"] - """The type of the message input. Always set to `message`.""" - - -class ComputerCallOutputAcknowledgedSafetyCheck(TypedDict, total=False): - """A pending safety check for the computer call.""" - - id: Required[str] - """The ID of the pending safety check.""" - - code: Optional[str] - """The type of the pending safety check.""" - - message: Optional[str] - """Details about the pending safety check.""" - - -class ComputerCallOutput(TypedDict, total=False): - """The output of a computer tool call.""" - - call_id: Required[str] - """The ID of the computer tool call that produced the output.""" - - output: Required[ResponseComputerToolCallOutputScreenshotParam] - """A computer screenshot image used with the computer use tool.""" - - type: Required[Literal["computer_call_output"]] - """The type of the computer tool call output. Always `computer_call_output`.""" - - id: Optional[str] - """The ID of the computer tool call output.""" - - acknowledged_safety_checks: Optional[Iterable[ComputerCallOutputAcknowledgedSafetyCheck]] - """ - The safety checks reported by the API that have been acknowledged by the - developer. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - -class FunctionCallOutput(TypedDict, total=False): - """The output of a function tool call.""" - - call_id: Required[str] - """The unique ID of the function tool call generated by the model.""" - - output: Required[Union[str, ResponseFunctionCallOutputItemListParam]] - """Text, image, or file output of the function tool call.""" - - type: Required[Literal["function_call_output"]] - """The type of the function tool call output. Always `function_call_output`.""" - - id: Optional[str] - """The unique ID of the function tool call output. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ - - -class ImageGenerationCall(TypedDict, total=False): - """An image generation request made by the model.""" - - id: Required[str] - """The unique ID of the image generation call.""" - - result: Required[Optional[str]] - """The generated image encoded in base64.""" - - status: Required[Literal["in_progress", "completed", "generating", "failed"]] - """The status of the image generation call.""" - - type: Required[Literal["image_generation_call"]] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(TypedDict, total=False): - """Execute a shell command on the server.""" - - command: Required[SequenceNotStr[str]] - """The command to run.""" - - env: Required[Dict[str, str]] - """Environment variables to set for the command.""" - - type: Required[Literal["exec"]] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] - """Optional user to run the command as.""" - - working_directory: Optional[str] - """Optional working directory to run the command in.""" - - -class LocalShellCall(TypedDict, total=False): - """A tool call to run a command on the local shell.""" - - id: Required[str] - """The unique ID of the local shell call.""" - - action: Required[LocalShellCallAction] - """Execute a shell command on the server.""" - - call_id: Required[str] - """The unique ID of the local shell tool call generated by the model.""" - - status: Required[Literal["in_progress", "completed", "incomplete"]] - """The status of the local shell call.""" - - type: Required[Literal["local_shell_call"]] - """The type of the local shell call. Always `local_shell_call`.""" - - -class LocalShellCallOutput(TypedDict, total=False): - """The output of a local shell tool call.""" - - id: Required[str] - """The unique ID of the local shell tool call generated by the model.""" - - output: Required[str] - """A JSON string of the output of the local shell tool call.""" - - type: Required[Literal["local_shell_call_output"]] - """The type of the local shell tool call output. Always `local_shell_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" - - -class ShellCallAction(TypedDict, total=False): - """The shell commands and limits that describe how to run the tool call.""" - - commands: Required[SequenceNotStr[str]] - """Ordered shell commands for the execution environment to run.""" - - max_output_length: Optional[int] - """ - Maximum number of UTF-8 characters to capture from combined stdout and stderr - output. - """ - - timeout_ms: Optional[int] - """Maximum wall-clock time in milliseconds to allow the shell commands to run.""" - - -class ShellCall(TypedDict, total=False): - """A tool representing a request to execute one or more shell commands.""" - - action: Required[ShellCallAction] - """The shell commands and limits that describe how to run the tool call.""" - - call_id: Required[str] - """The unique ID of the shell tool call generated by the model.""" - - type: Required[Literal["shell_call"]] - """The type of the item. Always `shell_call`.""" - - id: Optional[str] - """The unique ID of the shell tool call. - - Populated when this item is returned via API. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] - """The status of the shell call. - - One of `in_progress`, `completed`, or `incomplete`. - """ - - -class ShellCallOutput(TypedDict, total=False): - """The streamed output items emitted by a shell tool call.""" - - call_id: Required[str] - """The unique ID of the shell tool call generated by the model.""" - - output: Required[Iterable[ResponseFunctionShellCallOutputContentParam]] - """ - Captured chunks of stdout and stderr output, along with their associated - outcomes. - """ - - type: Required[Literal["shell_call_output"]] - """The type of the item. Always `shell_call_output`.""" - - id: Optional[str] - """The unique ID of the shell tool call output. - - Populated when this item is returned via API. - """ - - max_output_length: Optional[int] - """ - The maximum number of UTF-8 characters captured for this shell call's combined - output. - """ - - -class ApplyPatchCallOperationCreateFile(TypedDict, total=False): - """Instruction for creating a new file via the apply_patch tool.""" - - diff: Required[str] - """Unified diff content to apply when creating the file.""" - - path: Required[str] - """Path of the file to create relative to the workspace root.""" - - type: Required[Literal["create_file"]] - """The operation type. Always `create_file`.""" - - -class ApplyPatchCallOperationDeleteFile(TypedDict, total=False): - """Instruction for deleting an existing file via the apply_patch tool.""" - - path: Required[str] - """Path of the file to delete relative to the workspace root.""" - - type: Required[Literal["delete_file"]] - """The operation type. Always `delete_file`.""" - - -class ApplyPatchCallOperationUpdateFile(TypedDict, total=False): - """Instruction for updating an existing file via the apply_patch tool.""" - - diff: Required[str] - """Unified diff content to apply to the existing file.""" - - path: Required[str] - """Path of the file to update relative to the workspace root.""" - - type: Required[Literal["update_file"]] - """The operation type. Always `update_file`.""" - - -ApplyPatchCallOperation: TypeAlias = Union[ - ApplyPatchCallOperationCreateFile, ApplyPatchCallOperationDeleteFile, ApplyPatchCallOperationUpdateFile -] - - -class ApplyPatchCall(TypedDict, total=False): - """ - A tool call representing a request to create, delete, or update files using diff patches. - """ - - call_id: Required[str] - """The unique ID of the apply patch tool call generated by the model.""" - - operation: Required[ApplyPatchCallOperation] - """ - The specific create, delete, or update instruction for the apply_patch tool - call. - """ - - status: Required[Literal["in_progress", "completed"]] - """The status of the apply patch tool call. One of `in_progress` or `completed`.""" - - type: Required[Literal["apply_patch_call"]] - """The type of the item. Always `apply_patch_call`.""" - - id: Optional[str] - """The unique ID of the apply patch tool call. - - Populated when this item is returned via API. - """ - - -class ApplyPatchCallOutput(TypedDict, total=False): - """The streamed output emitted by an apply patch tool call.""" - - call_id: Required[str] - """The unique ID of the apply patch tool call generated by the model.""" - - status: Required[Literal["completed", "failed"]] - """The status of the apply patch tool call output. One of `completed` or `failed`.""" - - type: Required[Literal["apply_patch_call_output"]] - """The type of the item. Always `apply_patch_call_output`.""" - - id: Optional[str] - """The unique ID of the apply patch tool call output. - - Populated when this item is returned via API. - """ - - output: Optional[str] - """ - Optional human-readable log text from the apply patch tool (e.g., patch results - or errors). - """ - - -class McpListToolsTool(TypedDict, total=False): - """A tool available on an MCP server.""" - - input_schema: Required[object] - """The JSON schema describing the tool's input.""" - - name: Required[str] - """The name of the tool.""" - - annotations: Optional[object] - """Additional annotations about the tool.""" - - description: Optional[str] - """The description of the tool.""" - - -class McpListTools(TypedDict, total=False): - """A list of tools available on an MCP server.""" - - id: Required[str] - """The unique ID of the list.""" - - server_label: Required[str] - """The label of the MCP server.""" - - tools: Required[Iterable[McpListToolsTool]] - """The tools available on the server.""" - - type: Required[Literal["mcp_list_tools"]] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(TypedDict, total=False): - """A request for human approval of a tool invocation.""" - - id: Required[str] - """The unique ID of the approval request.""" - - arguments: Required[str] - """A JSON string of arguments for the tool.""" - - name: Required[str] - """The name of the tool to run.""" - - server_label: Required[str] - """The label of the MCP server making the request.""" - - type: Required[Literal["mcp_approval_request"]] - """The type of the item. Always `mcp_approval_request`.""" - - -class McpApprovalResponse(TypedDict, total=False): - """A response to an MCP approval request.""" - - approval_request_id: Required[str] - """The ID of the approval request being answered.""" - - approve: Required[bool] - """Whether the request was approved.""" - - type: Required[Literal["mcp_approval_response"]] - """The type of the item. Always `mcp_approval_response`.""" - - id: Optional[str] - """The unique ID of the approval response""" - - reason: Optional[str] - """Optional reason for the decision.""" - - -class McpCall(TypedDict, total=False): - """An invocation of a tool on an MCP server.""" - - id: Required[str] - """The unique ID of the tool call.""" - - arguments: Required[str] - """A JSON string of the arguments passed to the tool.""" - - name: Required[str] - """The name of the tool that was run.""" - - server_label: Required[str] - """The label of the MCP server running the tool.""" - - type: Required[Literal["mcp_call"]] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] - """The error from the tool call, if any.""" - - output: Optional[str] - """The output from the tool call.""" - - status: Literal["in_progress", "completed", "incomplete", "calling", "failed"] - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -class ItemReference(TypedDict, total=False): - """An internal identifier for an item to reference.""" - - id: Required[str] - """The ID of the item to reference.""" - - type: Optional[Literal["item_reference"]] - """The type of item to reference. Always `item_reference`.""" - - -ResponseInputItemParam: TypeAlias = Union[ - EasyInputMessageParam, - Message, - ResponseOutputMessageParam, - ResponseFileSearchToolCallParam, - ResponseComputerToolCallParam, - ComputerCallOutput, - ResponseFunctionWebSearchParam, - ResponseFunctionToolCallParam, - FunctionCallOutput, - ResponseReasoningItemParam, - ResponseCompactionItemParamParam, - ImageGenerationCall, - ResponseCodeInterpreterToolCallParam, - LocalShellCall, - LocalShellCallOutput, - ShellCall, - ShellCallOutput, - ApplyPatchCall, - ApplyPatchCallOutput, - McpListTools, - McpApprovalRequest, - McpApprovalResponse, - McpCall, - ResponseCustomToolCallOutputParam, - ResponseCustomToolCallParam, - ItemReference, -] - -ResponseInputParam: TypeAlias = List[ResponseInputItemParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text.py deleted file mode 100644 index 1e06ba7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputText"] - - -class ResponseInputText(BaseModel): - """A text input to the model.""" - - text: str - """The text input to the model.""" - - type: Literal["input_text"] - """The type of the input item. Always `input_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content.py deleted file mode 100644 index 66dbb8b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseInputTextContent"] - - -class ResponseInputTextContent(BaseModel): - """A text input to the model.""" - - text: str - """The text input to the model.""" - - type: Literal["input_text"] - """The type of the input item. Always `input_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content_param.py deleted file mode 100644 index 013f22d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_content_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputTextContentParam"] - - -class ResponseInputTextContentParam(TypedDict, total=False): - """A text input to the model.""" - - text: Required[str] - """The text input to the model.""" - - type: Required[Literal["input_text"]] - """The type of the input item. Always `input_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_param.py deleted file mode 100644 index e1a2976..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_input_text_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseInputTextParam"] - - -class ResponseInputTextParam(TypedDict, total=False): - """A text input to the model.""" - - text: Required[str] - """The text input to the model.""" - - type: Required[Literal["input_text"]] - """The type of the input item. Always `input_text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item.py deleted file mode 100644 index 3dba681..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item.py +++ /dev/null @@ -1,244 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_output_message import ResponseOutputMessage -from .response_computer_tool_call import ResponseComputerToolCall -from .response_input_message_item import ResponseInputMessageItem -from .response_function_web_search import ResponseFunctionWebSearch -from .response_apply_patch_tool_call import ResponseApplyPatchToolCall -from .response_file_search_tool_call import ResponseFileSearchToolCall -from .response_function_tool_call_item import ResponseFunctionToolCallItem -from .response_function_shell_tool_call import ResponseFunctionShellToolCall -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall -from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput -from .response_computer_tool_call_output_item import ResponseComputerToolCallOutputItem -from .response_function_tool_call_output_item import ResponseFunctionToolCallOutputItem -from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput - -__all__ = [ - "ResponseItem", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "LocalShellCallOutput", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", - "McpApprovalResponse", - "McpCall", -] - - -class ImageGenerationCall(BaseModel): - """An image generation request made by the model.""" - - id: str - """The unique ID of the image generation call.""" - - result: Optional[str] = None - """The generated image encoded in base64.""" - - status: Literal["in_progress", "completed", "generating", "failed"] - """The status of the image generation call.""" - - type: Literal["image_generation_call"] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(BaseModel): - """Execute a shell command on the server.""" - - command: List[str] - """The command to run.""" - - env: Dict[str, str] - """Environment variables to set for the command.""" - - type: Literal["exec"] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] = None - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] = None - """Optional user to run the command as.""" - - working_directory: Optional[str] = None - """Optional working directory to run the command in.""" - - -class LocalShellCall(BaseModel): - """A tool call to run a command on the local shell.""" - - id: str - """The unique ID of the local shell call.""" - - action: LocalShellCallAction - """Execute a shell command on the server.""" - - call_id: str - """The unique ID of the local shell tool call generated by the model.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the local shell call.""" - - type: Literal["local_shell_call"] - """The type of the local shell call. Always `local_shell_call`.""" - - -class LocalShellCallOutput(BaseModel): - """The output of a local shell tool call.""" - - id: str - """The unique ID of the local shell tool call generated by the model.""" - - output: str - """A JSON string of the output of the local shell tool call.""" - - type: Literal["local_shell_call_output"] - """The type of the local shell tool call output. Always `local_shell_call_output`.""" - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. One of `in_progress`, `completed`, or `incomplete`.""" - - -class McpListToolsTool(BaseModel): - """A tool available on an MCP server.""" - - input_schema: object - """The JSON schema describing the tool's input.""" - - name: str - """The name of the tool.""" - - annotations: Optional[object] = None - """Additional annotations about the tool.""" - - description: Optional[str] = None - """The description of the tool.""" - - -class McpListTools(BaseModel): - """A list of tools available on an MCP server.""" - - id: str - """The unique ID of the list.""" - - server_label: str - """The label of the MCP server.""" - - tools: List[McpListToolsTool] - """The tools available on the server.""" - - type: Literal["mcp_list_tools"] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] = None - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(BaseModel): - """A request for human approval of a tool invocation.""" - - id: str - """The unique ID of the approval request.""" - - arguments: str - """A JSON string of arguments for the tool.""" - - name: str - """The name of the tool to run.""" - - server_label: str - """The label of the MCP server making the request.""" - - type: Literal["mcp_approval_request"] - """The type of the item. Always `mcp_approval_request`.""" - - -class McpApprovalResponse(BaseModel): - """A response to an MCP approval request.""" - - id: str - """The unique ID of the approval response""" - - approval_request_id: str - """The ID of the approval request being answered.""" - - approve: bool - """Whether the request was approved.""" - - type: Literal["mcp_approval_response"] - """The type of the item. Always `mcp_approval_response`.""" - - reason: Optional[str] = None - """Optional reason for the decision.""" - - -class McpCall(BaseModel): - """An invocation of a tool on an MCP server.""" - - id: str - """The unique ID of the tool call.""" - - arguments: str - """A JSON string of the arguments passed to the tool.""" - - name: str - """The name of the tool that was run.""" - - server_label: str - """The label of the MCP server running the tool.""" - - type: Literal["mcp_call"] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] = None - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] = None - """The error from the tool call, if any.""" - - output: Optional[str] = None - """The output from the tool call.""" - - status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -ResponseItem: TypeAlias = Annotated[ - Union[ - ResponseInputMessageItem, - ResponseOutputMessage, - ResponseFileSearchToolCall, - ResponseComputerToolCall, - ResponseComputerToolCallOutputItem, - ResponseFunctionWebSearch, - ResponseFunctionToolCallItem, - ResponseFunctionToolCallOutputItem, - ImageGenerationCall, - ResponseCodeInterpreterToolCall, - LocalShellCall, - LocalShellCallOutput, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - McpListTools, - McpApprovalRequest, - McpApprovalResponse, - McpCall, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item_list.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item_list.py deleted file mode 100644 index e2b5a1a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_item_list.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_item import ResponseItem - -__all__ = ["ResponseItemList"] - - -class ResponseItemList(BaseModel): - """A list of Response items.""" - - data: List[ResponseItem] - """A list of items used to generate this response.""" - - first_id: str - """The ID of the first item in the list.""" - - has_more: bool - """Whether there are more items available.""" - - last_id: str - """The ID of the last item in the list.""" - - object: Literal["list"] - """The type of object returned, must be `list`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_delta_event.py deleted file mode 100644 index 303ef49..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_delta_event.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallArgumentsDeltaEvent"] - - -class ResponseMcpCallArgumentsDeltaEvent(BaseModel): - """ - Emitted when there is a delta (partial update) to the arguments of an MCP tool call. - """ - - delta: str - """ - A JSON string containing the partial update to the arguments for the MCP tool - call. - """ - - item_id: str - """The unique identifier of the MCP tool call item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_call_arguments.delta"] - """The type of the event. Always 'response.mcp_call_arguments.delta'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_done_event.py deleted file mode 100644 index 59e71be..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_arguments_done_event.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallArgumentsDoneEvent"] - - -class ResponseMcpCallArgumentsDoneEvent(BaseModel): - """Emitted when the arguments for an MCP tool call are finalized.""" - - arguments: str - """A JSON string containing the finalized arguments for the MCP tool call.""" - - item_id: str - """The unique identifier of the MCP tool call item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_call_arguments.done"] - """The type of the event. Always 'response.mcp_call_arguments.done'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_completed_event.py deleted file mode 100644 index bee54d4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_completed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallCompletedEvent"] - - -class ResponseMcpCallCompletedEvent(BaseModel): - """Emitted when an MCP tool call has completed successfully.""" - - item_id: str - """The ID of the MCP tool call item that completed.""" - - output_index: int - """The index of the output item that completed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_call.completed"] - """The type of the event. Always 'response.mcp_call.completed'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_failed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_failed_event.py deleted file mode 100644 index cb3130b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_failed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallFailedEvent"] - - -class ResponseMcpCallFailedEvent(BaseModel): - """Emitted when an MCP tool call has failed.""" - - item_id: str - """The ID of the MCP tool call item that failed.""" - - output_index: int - """The index of the output item that failed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_call.failed"] - """The type of the event. Always 'response.mcp_call.failed'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_in_progress_event.py deleted file mode 100644 index 7cf6a1d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_call_in_progress_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpCallInProgressEvent"] - - -class ResponseMcpCallInProgressEvent(BaseModel): - """Emitted when an MCP tool call is in progress.""" - - item_id: str - """The unique identifier of the MCP tool call item being processed.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_call.in_progress"] - """The type of the event. Always 'response.mcp_call.in_progress'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_completed_event.py deleted file mode 100644 index 685ba59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_completed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpListToolsCompletedEvent"] - - -class ResponseMcpListToolsCompletedEvent(BaseModel): - """Emitted when the list of available MCP tools has been successfully retrieved.""" - - item_id: str - """The ID of the MCP tool call item that produced this output.""" - - output_index: int - """The index of the output item that was processed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_list_tools.completed"] - """The type of the event. Always 'response.mcp_list_tools.completed'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_failed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_failed_event.py deleted file mode 100644 index c5fa54d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_failed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpListToolsFailedEvent"] - - -class ResponseMcpListToolsFailedEvent(BaseModel): - """Emitted when the attempt to list available MCP tools has failed.""" - - item_id: str - """The ID of the MCP tool call item that failed.""" - - output_index: int - """The index of the output item that failed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_list_tools.failed"] - """The type of the event. Always 'response.mcp_list_tools.failed'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_in_progress_event.py deleted file mode 100644 index 403fdbd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_mcp_list_tools_in_progress_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseMcpListToolsInProgressEvent"] - - -class ResponseMcpListToolsInProgressEvent(BaseModel): - """ - Emitted when the system is in the process of retrieving the list of available MCP tools. - """ - - item_id: str - """The ID of the MCP tool call item that is being processed.""" - - output_index: int - """The index of the output item that is being processed.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.mcp_list_tools.in_progress"] - """The type of the event. Always 'response.mcp_list_tools.in_progress'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item.py deleted file mode 100644 index 990f947..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item.py +++ /dev/null @@ -1,205 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_output_message import ResponseOutputMessage -from .response_reasoning_item import ResponseReasoningItem -from .response_compaction_item import ResponseCompactionItem -from .response_custom_tool_call import ResponseCustomToolCall -from .response_computer_tool_call import ResponseComputerToolCall -from .response_function_tool_call import ResponseFunctionToolCall -from .response_function_web_search import ResponseFunctionWebSearch -from .response_apply_patch_tool_call import ResponseApplyPatchToolCall -from .response_file_search_tool_call import ResponseFileSearchToolCall -from .response_function_shell_tool_call import ResponseFunctionShellToolCall -from .response_code_interpreter_tool_call import ResponseCodeInterpreterToolCall -from .response_apply_patch_tool_call_output import ResponseApplyPatchToolCallOutput -from .response_function_shell_tool_call_output import ResponseFunctionShellToolCallOutput - -__all__ = [ - "ResponseOutputItem", - "ImageGenerationCall", - "LocalShellCall", - "LocalShellCallAction", - "McpCall", - "McpListTools", - "McpListToolsTool", - "McpApprovalRequest", -] - - -class ImageGenerationCall(BaseModel): - """An image generation request made by the model.""" - - id: str - """The unique ID of the image generation call.""" - - result: Optional[str] = None - """The generated image encoded in base64.""" - - status: Literal["in_progress", "completed", "generating", "failed"] - """The status of the image generation call.""" - - type: Literal["image_generation_call"] - """The type of the image generation call. Always `image_generation_call`.""" - - -class LocalShellCallAction(BaseModel): - """Execute a shell command on the server.""" - - command: List[str] - """The command to run.""" - - env: Dict[str, str] - """Environment variables to set for the command.""" - - type: Literal["exec"] - """The type of the local shell action. Always `exec`.""" - - timeout_ms: Optional[int] = None - """Optional timeout in milliseconds for the command.""" - - user: Optional[str] = None - """Optional user to run the command as.""" - - working_directory: Optional[str] = None - """Optional working directory to run the command in.""" - - -class LocalShellCall(BaseModel): - """A tool call to run a command on the local shell.""" - - id: str - """The unique ID of the local shell call.""" - - action: LocalShellCallAction - """Execute a shell command on the server.""" - - call_id: str - """The unique ID of the local shell tool call generated by the model.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the local shell call.""" - - type: Literal["local_shell_call"] - """The type of the local shell call. Always `local_shell_call`.""" - - -class McpCall(BaseModel): - """An invocation of a tool on an MCP server.""" - - id: str - """The unique ID of the tool call.""" - - arguments: str - """A JSON string of the arguments passed to the tool.""" - - name: str - """The name of the tool that was run.""" - - server_label: str - """The label of the MCP server running the tool.""" - - type: Literal["mcp_call"] - """The type of the item. Always `mcp_call`.""" - - approval_request_id: Optional[str] = None - """ - Unique identifier for the MCP tool call approval request. Include this value in - a subsequent `mcp_approval_response` input to approve or reject the - corresponding tool call. - """ - - error: Optional[str] = None - """The error from the tool call, if any.""" - - output: Optional[str] = None - """The output from the tool call.""" - - status: Optional[Literal["in_progress", "completed", "incomplete", "calling", "failed"]] = None - """The status of the tool call. - - One of `in_progress`, `completed`, `incomplete`, `calling`, or `failed`. - """ - - -class McpListToolsTool(BaseModel): - """A tool available on an MCP server.""" - - input_schema: object - """The JSON schema describing the tool's input.""" - - name: str - """The name of the tool.""" - - annotations: Optional[object] = None - """Additional annotations about the tool.""" - - description: Optional[str] = None - """The description of the tool.""" - - -class McpListTools(BaseModel): - """A list of tools available on an MCP server.""" - - id: str - """The unique ID of the list.""" - - server_label: str - """The label of the MCP server.""" - - tools: List[McpListToolsTool] - """The tools available on the server.""" - - type: Literal["mcp_list_tools"] - """The type of the item. Always `mcp_list_tools`.""" - - error: Optional[str] = None - """Error message if the server could not list tools.""" - - -class McpApprovalRequest(BaseModel): - """A request for human approval of a tool invocation.""" - - id: str - """The unique ID of the approval request.""" - - arguments: str - """A JSON string of arguments for the tool.""" - - name: str - """The name of the tool to run.""" - - server_label: str - """The label of the MCP server making the request.""" - - type: Literal["mcp_approval_request"] - """The type of the item. Always `mcp_approval_request`.""" - - -ResponseOutputItem: TypeAlias = Annotated[ - Union[ - ResponseOutputMessage, - ResponseFileSearchToolCall, - ResponseFunctionToolCall, - ResponseFunctionWebSearch, - ResponseComputerToolCall, - ResponseReasoningItem, - ResponseCompactionItem, - ImageGenerationCall, - ResponseCodeInterpreterToolCall, - LocalShellCall, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - McpCall, - McpListTools, - McpApprovalRequest, - ResponseCustomToolCall, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_added_event.py deleted file mode 100644 index a42f628..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_added_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_output_item import ResponseOutputItem - -__all__ = ["ResponseOutputItemAddedEvent"] - - -class ResponseOutputItemAddedEvent(BaseModel): - """Emitted when a new output item is added.""" - - item: ResponseOutputItem - """The output item that was added.""" - - output_index: int - """The index of the output item that was added.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.output_item.added"] - """The type of the event. Always `response.output_item.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_done_event.py deleted file mode 100644 index 50b99da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_item_done_event.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_output_item import ResponseOutputItem - -__all__ = ["ResponseOutputItemDoneEvent"] - - -class ResponseOutputItemDoneEvent(BaseModel): - """Emitted when an output item is marked done.""" - - item: ResponseOutputItem - """The output item that was marked done.""" - - output_index: int - """The index of the output item that was marked done.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.output_item.done"] - """The type of the event. Always `response.output_item.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message.py deleted file mode 100644 index 9c1d1f9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .response_output_text import ResponseOutputText -from .response_output_refusal import ResponseOutputRefusal - -__all__ = ["ResponseOutputMessage", "Content"] - -Content: TypeAlias = Annotated[Union[ResponseOutputText, ResponseOutputRefusal], PropertyInfo(discriminator="type")] - - -class ResponseOutputMessage(BaseModel): - """An output message from the model.""" - - id: str - """The unique ID of the output message.""" - - content: List[Content] - """The content of the output message.""" - - role: Literal["assistant"] - """The role of the output message. Always `assistant`.""" - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - type: Literal["message"] - """The type of the output message. Always `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message_param.py deleted file mode 100644 index 9c2f524..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_message_param.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .response_output_text_param import ResponseOutputTextParam -from .response_output_refusal_param import ResponseOutputRefusalParam - -__all__ = ["ResponseOutputMessageParam", "Content"] - -Content: TypeAlias = Union[ResponseOutputTextParam, ResponseOutputRefusalParam] - - -class ResponseOutputMessageParam(TypedDict, total=False): - """An output message from the model.""" - - id: Required[str] - """The unique ID of the output message.""" - - content: Required[Iterable[Content]] - """The content of the output message.""" - - role: Required[Literal["assistant"]] - """The role of the output message. Always `assistant`.""" - - status: Required[Literal["in_progress", "completed", "incomplete"]] - """The status of the message input. - - One of `in_progress`, `completed`, or `incomplete`. Populated when input items - are returned via API. - """ - - type: Required[Literal["message"]] - """The type of the output message. Always `message`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal.py deleted file mode 100644 index 6bce26a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseOutputRefusal"] - - -class ResponseOutputRefusal(BaseModel): - """A refusal from the model.""" - - refusal: str - """The refusal explanation from the model.""" - - type: Literal["refusal"] - """The type of the refusal. Always `refusal`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal_param.py deleted file mode 100644 index 02bdfdc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_refusal_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseOutputRefusalParam"] - - -class ResponseOutputRefusalParam(TypedDict, total=False): - """A refusal from the model.""" - - refusal: Required[str] - """The refusal explanation from the model.""" - - type: Required[Literal["refusal"]] - """The type of the refusal. Always `refusal`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text.py deleted file mode 100644 index 2386fcb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text.py +++ /dev/null @@ -1,131 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = [ - "ResponseOutputText", - "Annotation", - "AnnotationFileCitation", - "AnnotationURLCitation", - "AnnotationContainerFileCitation", - "AnnotationFilePath", - "Logprob", - "LogprobTopLogprob", -] - - -class AnnotationFileCitation(BaseModel): - """A citation to a file.""" - - file_id: str - """The ID of the file.""" - - filename: str - """The filename of the file cited.""" - - index: int - """The index of the file in the list of files.""" - - type: Literal["file_citation"] - """The type of the file citation. Always `file_citation`.""" - - -class AnnotationURLCitation(BaseModel): - """A citation for a web resource used to generate a model response.""" - - end_index: int - """The index of the last character of the URL citation in the message.""" - - start_index: int - """The index of the first character of the URL citation in the message.""" - - title: str - """The title of the web resource.""" - - type: Literal["url_citation"] - """The type of the URL citation. Always `url_citation`.""" - - url: str - """The URL of the web resource.""" - - -class AnnotationContainerFileCitation(BaseModel): - """A citation for a container file used to generate a model response.""" - - container_id: str - """The ID of the container file.""" - - end_index: int - """The index of the last character of the container file citation in the message.""" - - file_id: str - """The ID of the file.""" - - filename: str - """The filename of the container file cited.""" - - start_index: int - """The index of the first character of the container file citation in the message.""" - - type: Literal["container_file_citation"] - """The type of the container file citation. Always `container_file_citation`.""" - - -class AnnotationFilePath(BaseModel): - """A path to a file.""" - - file_id: str - """The ID of the file.""" - - index: int - """The index of the file in the list of files.""" - - type: Literal["file_path"] - """The type of the file path. Always `file_path`.""" - - -Annotation: TypeAlias = Annotated[ - Union[AnnotationFileCitation, AnnotationURLCitation, AnnotationContainerFileCitation, AnnotationFilePath], - PropertyInfo(discriminator="type"), -] - - -class LogprobTopLogprob(BaseModel): - """The top log probability of a token.""" - - token: str - - bytes: List[int] - - logprob: float - - -class Logprob(BaseModel): - """The log probability of a token.""" - - token: str - - bytes: List[int] - - logprob: float - - top_logprobs: List[LogprobTopLogprob] - - -class ResponseOutputText(BaseModel): - """A text output from the model.""" - - annotations: List[Annotation] - """The annotations of the text output.""" - - text: str - """The text output from the model.""" - - type: Literal["output_text"] - """The type of the output text. Always `output_text`.""" - - logprobs: Optional[List[Logprob]] = None diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_annotation_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_annotation_added_event.py deleted file mode 100644 index b9dc262..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_annotation_added_event.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseOutputTextAnnotationAddedEvent"] - - -class ResponseOutputTextAnnotationAddedEvent(BaseModel): - """Emitted when an annotation is added to output text content.""" - - annotation: object - """The annotation object being added. (See annotation schema for details.)""" - - annotation_index: int - """The index of the annotation within the content part.""" - - content_index: int - """The index of the content part within the output item.""" - - item_id: str - """The unique identifier of the item to which the annotation is being added.""" - - output_index: int - """The index of the output item in the response's output array.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.output_text.annotation.added"] - """The type of the event. Always 'response.output_text.annotation.added'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_param.py deleted file mode 100644 index bc30fbc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_output_text_param.py +++ /dev/null @@ -1,129 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = [ - "ResponseOutputTextParam", - "Annotation", - "AnnotationFileCitation", - "AnnotationURLCitation", - "AnnotationContainerFileCitation", - "AnnotationFilePath", - "Logprob", - "LogprobTopLogprob", -] - - -class AnnotationFileCitation(TypedDict, total=False): - """A citation to a file.""" - - file_id: Required[str] - """The ID of the file.""" - - filename: Required[str] - """The filename of the file cited.""" - - index: Required[int] - """The index of the file in the list of files.""" - - type: Required[Literal["file_citation"]] - """The type of the file citation. Always `file_citation`.""" - - -class AnnotationURLCitation(TypedDict, total=False): - """A citation for a web resource used to generate a model response.""" - - end_index: Required[int] - """The index of the last character of the URL citation in the message.""" - - start_index: Required[int] - """The index of the first character of the URL citation in the message.""" - - title: Required[str] - """The title of the web resource.""" - - type: Required[Literal["url_citation"]] - """The type of the URL citation. Always `url_citation`.""" - - url: Required[str] - """The URL of the web resource.""" - - -class AnnotationContainerFileCitation(TypedDict, total=False): - """A citation for a container file used to generate a model response.""" - - container_id: Required[str] - """The ID of the container file.""" - - end_index: Required[int] - """The index of the last character of the container file citation in the message.""" - - file_id: Required[str] - """The ID of the file.""" - - filename: Required[str] - """The filename of the container file cited.""" - - start_index: Required[int] - """The index of the first character of the container file citation in the message.""" - - type: Required[Literal["container_file_citation"]] - """The type of the container file citation. Always `container_file_citation`.""" - - -class AnnotationFilePath(TypedDict, total=False): - """A path to a file.""" - - file_id: Required[str] - """The ID of the file.""" - - index: Required[int] - """The index of the file in the list of files.""" - - type: Required[Literal["file_path"]] - """The type of the file path. Always `file_path`.""" - - -Annotation: TypeAlias = Union[ - AnnotationFileCitation, AnnotationURLCitation, AnnotationContainerFileCitation, AnnotationFilePath -] - - -class LogprobTopLogprob(TypedDict, total=False): - """The top log probability of a token.""" - - token: Required[str] - - bytes: Required[Iterable[int]] - - logprob: Required[float] - - -class Logprob(TypedDict, total=False): - """The log probability of a token.""" - - token: Required[str] - - bytes: Required[Iterable[int]] - - logprob: Required[float] - - top_logprobs: Required[Iterable[LogprobTopLogprob]] - - -class ResponseOutputTextParam(TypedDict, total=False): - """A text output from the model.""" - - annotations: Required[Iterable[Annotation]] - """The annotations of the text output.""" - - text: Required[str] - """The text output from the model.""" - - type: Required[Literal["output_text"]] - """The type of the output text. Always `output_text`.""" - - logprobs: Iterable[Logprob] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt.py deleted file mode 100644 index e3acacf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Union, Optional -from typing_extensions import TypeAlias - -from ..._models import BaseModel -from .response_input_file import ResponseInputFile -from .response_input_text import ResponseInputText -from .response_input_image import ResponseInputImage - -__all__ = ["ResponsePrompt", "Variables"] - -Variables: TypeAlias = Union[str, ResponseInputText, ResponseInputImage, ResponseInputFile] - - -class ResponsePrompt(BaseModel): - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - id: str - """The unique identifier of the prompt template to use.""" - - variables: Optional[Dict[str, Variables]] = None - """Optional map of values to substitute in for variables in your prompt. - - The substitution values can either be strings, or other Response input types - like images or files. - """ - - version: Optional[str] = None - """Optional version of the prompt template.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt_param.py deleted file mode 100644 index f9a28b6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_prompt_param.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Required, TypeAlias, TypedDict - -from .response_input_file_param import ResponseInputFileParam -from .response_input_text_param import ResponseInputTextParam -from .response_input_image_param import ResponseInputImageParam - -__all__ = ["ResponsePromptParam", "Variables"] - -Variables: TypeAlias = Union[str, ResponseInputTextParam, ResponseInputImageParam, ResponseInputFileParam] - - -class ResponsePromptParam(TypedDict, total=False): - """ - Reference to a prompt template and its variables. - [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts). - """ - - id: Required[str] - """The unique identifier of the prompt template to use.""" - - variables: Optional[Dict[str, Variables]] - """Optional map of values to substitute in for variables in your prompt. - - The substitution values can either be strings, or other Response input types - like images or files. - """ - - version: Optional[str] - """Optional version of the prompt template.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_queued_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_queued_event.py deleted file mode 100644 index a554215..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_queued_event.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .response import Response -from ..._models import BaseModel - -__all__ = ["ResponseQueuedEvent"] - - -class ResponseQueuedEvent(BaseModel): - """Emitted when a response is queued and waiting to be processed.""" - - response: Response - """The full response object that is queued.""" - - sequence_number: int - """The sequence number for this event.""" - - type: Literal["response.queued"] - """The type of the event. Always 'response.queued'.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item.py deleted file mode 100644 index 1a22eb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item.py +++ /dev/null @@ -1,62 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningItem", "Summary", "Content"] - - -class Summary(BaseModel): - """A summary text from the model.""" - - text: str - """A summary of the reasoning output from the model so far.""" - - type: Literal["summary_text"] - """The type of the object. Always `summary_text`.""" - - -class Content(BaseModel): - """Reasoning text from the model.""" - - text: str - """The reasoning text from the model.""" - - type: Literal["reasoning_text"] - """The type of the reasoning text. Always `reasoning_text`.""" - - -class ResponseReasoningItem(BaseModel): - """ - A description of the chain of thought used by a reasoning model while generating - a response. Be sure to include these items in your `input` to the Responses API - for subsequent turns of a conversation if you are manually - [managing context](https://platform.openai.com/docs/guides/conversation-state). - """ - - id: str - """The unique identifier of the reasoning content.""" - - summary: List[Summary] - """Reasoning summary content.""" - - type: Literal["reasoning"] - """The type of the object. Always `reasoning`.""" - - content: Optional[List[Content]] = None - """Reasoning text content.""" - - encrypted_content: Optional[str] = None - """ - The encrypted content of the reasoning item - populated when a response is - generated with `reasoning.encrypted_content` in the `include` parameter. - """ - - status: Optional[Literal["in_progress", "completed", "incomplete"]] = None - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item_param.py deleted file mode 100644 index 40320b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_item_param.py +++ /dev/null @@ -1,62 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseReasoningItemParam", "Summary", "Content"] - - -class Summary(TypedDict, total=False): - """A summary text from the model.""" - - text: Required[str] - """A summary of the reasoning output from the model so far.""" - - type: Required[Literal["summary_text"]] - """The type of the object. Always `summary_text`.""" - - -class Content(TypedDict, total=False): - """Reasoning text from the model.""" - - text: Required[str] - """The reasoning text from the model.""" - - type: Required[Literal["reasoning_text"]] - """The type of the reasoning text. Always `reasoning_text`.""" - - -class ResponseReasoningItemParam(TypedDict, total=False): - """ - A description of the chain of thought used by a reasoning model while generating - a response. Be sure to include these items in your `input` to the Responses API - for subsequent turns of a conversation if you are manually - [managing context](https://platform.openai.com/docs/guides/conversation-state). - """ - - id: Required[str] - """The unique identifier of the reasoning content.""" - - summary: Required[Iterable[Summary]] - """Reasoning summary content.""" - - type: Required[Literal["reasoning"]] - """The type of the object. Always `reasoning`.""" - - content: Iterable[Content] - """Reasoning text content.""" - - encrypted_content: Optional[str] - """ - The encrypted content of the reasoning item - populated when a response is - generated with `reasoning.encrypted_content` in the `include` parameter. - """ - - status: Literal["in_progress", "completed", "incomplete"] - """The status of the item. - - One of `in_progress`, `completed`, or `incomplete`. Populated when items are - returned via API. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_added_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_added_event.py deleted file mode 100644 index e4b0f34..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_added_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryPartAddedEvent", "Part"] - - -class Part(BaseModel): - """The summary part that was added.""" - - text: str - """The text of the summary part.""" - - type: Literal["summary_text"] - """The type of the summary part. Always `summary_text`.""" - - -class ResponseReasoningSummaryPartAddedEvent(BaseModel): - """Emitted when a new reasoning summary part is added.""" - - item_id: str - """The ID of the item this summary part is associated with.""" - - output_index: int - """The index of the output item this summary part is associated with.""" - - part: Part - """The summary part that was added.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the reasoning summary.""" - - type: Literal["response.reasoning_summary_part.added"] - """The type of the event. Always `response.reasoning_summary_part.added`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_done_event.py deleted file mode 100644 index 48f3f68..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_part_done_event.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryPartDoneEvent", "Part"] - - -class Part(BaseModel): - """The completed summary part.""" - - text: str - """The text of the summary part.""" - - type: Literal["summary_text"] - """The type of the summary part. Always `summary_text`.""" - - -class ResponseReasoningSummaryPartDoneEvent(BaseModel): - """Emitted when a reasoning summary part is completed.""" - - item_id: str - """The ID of the item this summary part is associated with.""" - - output_index: int - """The index of the output item this summary part is associated with.""" - - part: Part - """The completed summary part.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the reasoning summary.""" - - type: Literal["response.reasoning_summary_part.done"] - """The type of the event. Always `response.reasoning_summary_part.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_delta_event.py deleted file mode 100644 index 84bcf03..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_delta_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryTextDeltaEvent"] - - -class ResponseReasoningSummaryTextDeltaEvent(BaseModel): - """Emitted when a delta is added to a reasoning summary text.""" - - delta: str - """The text delta that was added to the summary.""" - - item_id: str - """The ID of the item this summary text delta is associated with.""" - - output_index: int - """The index of the output item this summary text delta is associated with.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the reasoning summary.""" - - type: Literal["response.reasoning_summary_text.delta"] - """The type of the event. Always `response.reasoning_summary_text.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_done_event.py deleted file mode 100644 index 244d001..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_summary_text_done_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningSummaryTextDoneEvent"] - - -class ResponseReasoningSummaryTextDoneEvent(BaseModel): - """Emitted when a reasoning summary text is completed.""" - - item_id: str - """The ID of the item this summary text is associated with.""" - - output_index: int - """The index of the output item this summary text is associated with.""" - - sequence_number: int - """The sequence number of this event.""" - - summary_index: int - """The index of the summary part within the reasoning summary.""" - - text: str - """The full text of the completed reasoning summary.""" - - type: Literal["response.reasoning_summary_text.done"] - """The type of the event. Always `response.reasoning_summary_text.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_delta_event.py deleted file mode 100644 index 0e05226..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_delta_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningTextDeltaEvent"] - - -class ResponseReasoningTextDeltaEvent(BaseModel): - """Emitted when a delta is added to a reasoning text.""" - - content_index: int - """The index of the reasoning content part this delta is associated with.""" - - delta: str - """The text delta that was added to the reasoning content.""" - - item_id: str - """The ID of the item this reasoning text delta is associated with.""" - - output_index: int - """The index of the output item this reasoning text delta is associated with.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.reasoning_text.delta"] - """The type of the event. Always `response.reasoning_text.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_done_event.py deleted file mode 100644 index 40e3f47..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_reasoning_text_done_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseReasoningTextDoneEvent"] - - -class ResponseReasoningTextDoneEvent(BaseModel): - """Emitted when a reasoning text is completed.""" - - content_index: int - """The index of the reasoning content part.""" - - item_id: str - """The ID of the item this reasoning text is associated with.""" - - output_index: int - """The index of the output item this reasoning text is associated with.""" - - sequence_number: int - """The sequence number of this event.""" - - text: str - """The full text of the completed reasoning content.""" - - type: Literal["response.reasoning_text.done"] - """The type of the event. Always `response.reasoning_text.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_delta_event.py deleted file mode 100644 index e3933b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_delta_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseRefusalDeltaEvent"] - - -class ResponseRefusalDeltaEvent(BaseModel): - """Emitted when there is a partial refusal text.""" - - content_index: int - """The index of the content part that the refusal text is added to.""" - - delta: str - """The refusal text that is added.""" - - item_id: str - """The ID of the output item that the refusal text is added to.""" - - output_index: int - """The index of the output item that the refusal text is added to.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.refusal.delta"] - """The type of the event. Always `response.refusal.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_done_event.py deleted file mode 100644 index 91adeb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_refusal_done_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseRefusalDoneEvent"] - - -class ResponseRefusalDoneEvent(BaseModel): - """Emitted when refusal text is finalized.""" - - content_index: int - """The index of the content part that the refusal text is finalized.""" - - item_id: str - """The ID of the output item that the refusal text is finalized.""" - - output_index: int - """The index of the output item that the refusal text is finalized.""" - - refusal: str - """The refusal text that is finalized.""" - - sequence_number: int - """The sequence number of this event.""" - - type: Literal["response.refusal.done"] - """The type of the event. Always `response.refusal.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_retrieve_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_retrieve_params.py deleted file mode 100644 index 4013db8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_retrieve_params.py +++ /dev/null @@ -1,59 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import Literal, Required, TypedDict - -from .response_includable import ResponseIncludable - -__all__ = ["ResponseRetrieveParamsBase", "ResponseRetrieveParamsNonStreaming", "ResponseRetrieveParamsStreaming"] - - -class ResponseRetrieveParamsBase(TypedDict, total=False): - include: List[ResponseIncludable] - """Additional fields to include in the response. - - See the `include` parameter for Response creation above for more information. - """ - - include_obfuscation: bool - """When true, stream obfuscation will be enabled. - - Stream obfuscation adds random characters to an `obfuscation` field on streaming - delta events to normalize payload sizes as a mitigation to certain side-channel - attacks. These obfuscation fields are included by default, but add a small - amount of overhead to the data stream. You can set `include_obfuscation` to - false to optimize for bandwidth if you trust the network links between your - application and the OpenAI API. - """ - - starting_after: int - """The sequence number of the event after which to start streaming.""" - - -class ResponseRetrieveParamsNonStreaming(ResponseRetrieveParamsBase, total=False): - stream: Literal[False] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - """ - - -class ResponseRetrieveParamsStreaming(ResponseRetrieveParamsBase): - stream: Required[Literal[True]] - """ - If set to true, the model response data will be streamed to the client as it is - generated using - [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). - See the - [Streaming section below](https://platform.openai.com/docs/api-reference/responses-streaming) - for more information. - """ - - -ResponseRetrieveParams = Union[ResponseRetrieveParamsNonStreaming, ResponseRetrieveParamsStreaming] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_status.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_status.py deleted file mode 100644 index a7887b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ResponseStatus"] - -ResponseStatus: TypeAlias = Literal["completed", "failed", "in_progress", "cancelled", "queued", "incomplete"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_stream_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_stream_event.py deleted file mode 100644 index c0a317c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_stream_event.py +++ /dev/null @@ -1,120 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .response_error_event import ResponseErrorEvent -from .response_failed_event import ResponseFailedEvent -from .response_queued_event import ResponseQueuedEvent -from .response_created_event import ResponseCreatedEvent -from .response_completed_event import ResponseCompletedEvent -from .response_text_done_event import ResponseTextDoneEvent -from .response_audio_done_event import ResponseAudioDoneEvent -from .response_incomplete_event import ResponseIncompleteEvent -from .response_text_delta_event import ResponseTextDeltaEvent -from .response_audio_delta_event import ResponseAudioDeltaEvent -from .response_in_progress_event import ResponseInProgressEvent -from .response_refusal_done_event import ResponseRefusalDoneEvent -from .response_refusal_delta_event import ResponseRefusalDeltaEvent -from .response_mcp_call_failed_event import ResponseMcpCallFailedEvent -from .response_output_item_done_event import ResponseOutputItemDoneEvent -from .response_content_part_done_event import ResponseContentPartDoneEvent -from .response_output_item_added_event import ResponseOutputItemAddedEvent -from .response_content_part_added_event import ResponseContentPartAddedEvent -from .response_mcp_call_completed_event import ResponseMcpCallCompletedEvent -from .response_reasoning_text_done_event import ResponseReasoningTextDoneEvent -from .response_mcp_call_in_progress_event import ResponseMcpCallInProgressEvent -from .response_reasoning_text_delta_event import ResponseReasoningTextDeltaEvent -from .response_audio_transcript_done_event import ResponseAudioTranscriptDoneEvent -from .response_mcp_list_tools_failed_event import ResponseMcpListToolsFailedEvent -from .response_audio_transcript_delta_event import ResponseAudioTranscriptDeltaEvent -from .response_mcp_call_arguments_done_event import ResponseMcpCallArgumentsDoneEvent -from .response_image_gen_call_completed_event import ResponseImageGenCallCompletedEvent -from .response_mcp_call_arguments_delta_event import ResponseMcpCallArgumentsDeltaEvent -from .response_mcp_list_tools_completed_event import ResponseMcpListToolsCompletedEvent -from .response_image_gen_call_generating_event import ResponseImageGenCallGeneratingEvent -from .response_web_search_call_completed_event import ResponseWebSearchCallCompletedEvent -from .response_web_search_call_searching_event import ResponseWebSearchCallSearchingEvent -from .response_file_search_call_completed_event import ResponseFileSearchCallCompletedEvent -from .response_file_search_call_searching_event import ResponseFileSearchCallSearchingEvent -from .response_image_gen_call_in_progress_event import ResponseImageGenCallInProgressEvent -from .response_mcp_list_tools_in_progress_event import ResponseMcpListToolsInProgressEvent -from .response_custom_tool_call_input_done_event import ResponseCustomToolCallInputDoneEvent -from .response_reasoning_summary_part_done_event import ResponseReasoningSummaryPartDoneEvent -from .response_reasoning_summary_text_done_event import ResponseReasoningSummaryTextDoneEvent -from .response_web_search_call_in_progress_event import ResponseWebSearchCallInProgressEvent -from .response_custom_tool_call_input_delta_event import ResponseCustomToolCallInputDeltaEvent -from .response_file_search_call_in_progress_event import ResponseFileSearchCallInProgressEvent -from .response_function_call_arguments_done_event import ResponseFunctionCallArgumentsDoneEvent -from .response_image_gen_call_partial_image_event import ResponseImageGenCallPartialImageEvent -from .response_output_text_annotation_added_event import ResponseOutputTextAnnotationAddedEvent -from .response_reasoning_summary_part_added_event import ResponseReasoningSummaryPartAddedEvent -from .response_reasoning_summary_text_delta_event import ResponseReasoningSummaryTextDeltaEvent -from .response_function_call_arguments_delta_event import ResponseFunctionCallArgumentsDeltaEvent -from .response_code_interpreter_call_code_done_event import ResponseCodeInterpreterCallCodeDoneEvent -from .response_code_interpreter_call_completed_event import ResponseCodeInterpreterCallCompletedEvent -from .response_code_interpreter_call_code_delta_event import ResponseCodeInterpreterCallCodeDeltaEvent -from .response_code_interpreter_call_in_progress_event import ResponseCodeInterpreterCallInProgressEvent -from .response_code_interpreter_call_interpreting_event import ResponseCodeInterpreterCallInterpretingEvent - -__all__ = ["ResponseStreamEvent"] - -ResponseStreamEvent: TypeAlias = Annotated[ - Union[ - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCodeInterpreterCallCodeDeltaEvent, - ResponseCodeInterpreterCallCodeDoneEvent, - ResponseCodeInterpreterCallCompletedEvent, - ResponseCodeInterpreterCallInProgressEvent, - ResponseCodeInterpreterCallInterpretingEvent, - ResponseCompletedEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreatedEvent, - ResponseErrorEvent, - ResponseFileSearchCallCompletedEvent, - ResponseFileSearchCallInProgressEvent, - ResponseFileSearchCallSearchingEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseInProgressEvent, - ResponseFailedEvent, - ResponseIncompleteEvent, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseReasoningSummaryPartAddedEvent, - ResponseReasoningSummaryPartDoneEvent, - ResponseReasoningSummaryTextDeltaEvent, - ResponseReasoningSummaryTextDoneEvent, - ResponseReasoningTextDeltaEvent, - ResponseReasoningTextDoneEvent, - ResponseRefusalDeltaEvent, - ResponseRefusalDoneEvent, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - ResponseWebSearchCallCompletedEvent, - ResponseWebSearchCallInProgressEvent, - ResponseWebSearchCallSearchingEvent, - ResponseImageGenCallCompletedEvent, - ResponseImageGenCallGeneratingEvent, - ResponseImageGenCallInProgressEvent, - ResponseImageGenCallPartialImageEvent, - ResponseMcpCallArgumentsDeltaEvent, - ResponseMcpCallArgumentsDoneEvent, - ResponseMcpCallCompletedEvent, - ResponseMcpCallFailedEvent, - ResponseMcpCallInProgressEvent, - ResponseMcpListToolsCompletedEvent, - ResponseMcpListToolsFailedEvent, - ResponseMcpListToolsInProgressEvent, - ResponseOutputTextAnnotationAddedEvent, - ResponseQueuedEvent, - ResponseCustomToolCallInputDeltaEvent, - ResponseCustomToolCallInputDoneEvent, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config.py deleted file mode 100644 index fbf4da0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .response_format_text_config import ResponseFormatTextConfig - -__all__ = ["ResponseTextConfig"] - - -class ResponseTextConfig(BaseModel): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: Optional[ResponseFormatTextConfig] = None - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] = None - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config_param.py deleted file mode 100644 index 9cd5476..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_config_param.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, TypedDict - -from .response_format_text_config_param import ResponseFormatTextConfigParam - -__all__ = ["ResponseTextConfigParam"] - - -class ResponseTextConfigParam(TypedDict, total=False): - """Configuration options for a text response from the model. - - Can be plain - text or structured JSON data. Learn more: - - [Text inputs and outputs](https://platform.openai.com/docs/guides/text) - - [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) - """ - - format: ResponseFormatTextConfigParam - """An object specifying the format that the model must output. - - Configuring `{ "type": "json_schema" }` enables Structured Outputs, which - ensures the model will match your supplied JSON schema. Learn more in the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - - The default format is `{ "type": "text" }` with no additional options. - - **Not recommended for gpt-4o and newer models:** - - Setting to `{ "type": "json_object" }` enables the older JSON mode, which - ensures the message the model generates is valid JSON. Using `json_schema` is - preferred for models that support it. - """ - - verbosity: Optional[Literal["low", "medium", "high"]] - """Constrains the verbosity of the model's response. - - Lower values will result in more concise responses, while higher values will - result in more verbose responses. Currently supported values are `low`, - `medium`, and `high`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_delta_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_delta_event.py deleted file mode 100644 index 4f802ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_delta_event.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseTextDeltaEvent", "Logprob", "LogprobTopLogprob"] - - -class LogprobTopLogprob(BaseModel): - token: Optional[str] = None - """A possible text token.""" - - logprob: Optional[float] = None - """The log probability of this token.""" - - -class Logprob(BaseModel): - """ - A logprob is the logarithmic probability that the model assigns to producing - a particular token at a given position in the sequence. Less-negative (higher) - logprob values indicate greater model confidence in that token choice. - """ - - token: str - """A possible text token.""" - - logprob: float - """The log probability of this token.""" - - top_logprobs: Optional[List[LogprobTopLogprob]] = None - """The log probability of the top 20 most likely tokens.""" - - -class ResponseTextDeltaEvent(BaseModel): - """Emitted when there is an additional text delta.""" - - content_index: int - """The index of the content part that the text delta was added to.""" - - delta: str - """The text delta that was added.""" - - item_id: str - """The ID of the output item that the text delta was added to.""" - - logprobs: List[Logprob] - """The log probabilities of the tokens in the delta.""" - - output_index: int - """The index of the output item that the text delta was added to.""" - - sequence_number: int - """The sequence number for this event.""" - - type: Literal["response.output_text.delta"] - """The type of the event. Always `response.output_text.delta`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_done_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_done_event.py deleted file mode 100644 index 75bd479..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_text_done_event.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseTextDoneEvent", "Logprob", "LogprobTopLogprob"] - - -class LogprobTopLogprob(BaseModel): - token: Optional[str] = None - """A possible text token.""" - - logprob: Optional[float] = None - """The log probability of this token.""" - - -class Logprob(BaseModel): - """ - A logprob is the logarithmic probability that the model assigns to producing - a particular token at a given position in the sequence. Less-negative (higher) - logprob values indicate greater model confidence in that token choice. - """ - - token: str - """A possible text token.""" - - logprob: float - """The log probability of this token.""" - - top_logprobs: Optional[List[LogprobTopLogprob]] = None - """The log probability of the top 20 most likely tokens.""" - - -class ResponseTextDoneEvent(BaseModel): - """Emitted when text content is finalized.""" - - content_index: int - """The index of the content part that the text content is finalized.""" - - item_id: str - """The ID of the output item that the text content is finalized.""" - - logprobs: List[Logprob] - """The log probabilities of the tokens in the delta.""" - - output_index: int - """The index of the output item that the text content is finalized.""" - - sequence_number: int - """The sequence number for this event.""" - - text: str - """The text content that is finalized.""" - - type: Literal["response.output_text.done"] - """The type of the event. Always `response.output_text.done`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_usage.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_usage.py deleted file mode 100644 index d4b739c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_usage.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["ResponseUsage", "InputTokensDetails", "OutputTokensDetails"] - - -class InputTokensDetails(BaseModel): - """A detailed breakdown of the input tokens.""" - - cached_tokens: int - """The number of tokens that were retrieved from the cache. - - [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching). - """ - - -class OutputTokensDetails(BaseModel): - """A detailed breakdown of the output tokens.""" - - reasoning_tokens: int - """The number of reasoning tokens.""" - - -class ResponseUsage(BaseModel): - """ - Represents token usage details including input tokens, output tokens, - a breakdown of output tokens, and the total tokens used. - """ - - input_tokens: int - """The number of input tokens.""" - - input_tokens_details: InputTokensDetails - """A detailed breakdown of the input tokens.""" - - output_tokens: int - """The number of output tokens.""" - - output_tokens_details: OutputTokensDetails - """A detailed breakdown of the output tokens.""" - - total_tokens: int - """The total number of tokens used.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_completed_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_completed_event.py deleted file mode 100644 index 5aa7afe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_completed_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseWebSearchCallCompletedEvent"] - - -class ResponseWebSearchCallCompletedEvent(BaseModel): - """Emitted when a web search call is completed.""" - - item_id: str - """Unique ID for the output item associated with the web search call.""" - - output_index: int - """The index of the output item that the web search call is associated with.""" - - sequence_number: int - """The sequence number of the web search call being processed.""" - - type: Literal["response.web_search_call.completed"] - """The type of the event. Always `response.web_search_call.completed`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_in_progress_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_in_progress_event.py deleted file mode 100644 index 73b30ff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_in_progress_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseWebSearchCallInProgressEvent"] - - -class ResponseWebSearchCallInProgressEvent(BaseModel): - """Emitted when a web search call is initiated.""" - - item_id: str - """Unique ID for the output item associated with the web search call.""" - - output_index: int - """The index of the output item that the web search call is associated with.""" - - sequence_number: int - """The sequence number of the web search call being processed.""" - - type: Literal["response.web_search_call.in_progress"] - """The type of the event. Always `response.web_search_call.in_progress`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_searching_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_searching_event.py deleted file mode 100644 index 959c095..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/response_web_search_call_searching_event.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseWebSearchCallSearchingEvent"] - - -class ResponseWebSearchCallSearchingEvent(BaseModel): - """Emitted when a web search call is executing.""" - - item_id: str - """Unique ID for the output item associated with the web search call.""" - - output_index: int - """The index of the output item that the web search call is associated with.""" - - sequence_number: int - """The sequence number of the web search call being processed.""" - - type: Literal["response.web_search_call.searching"] - """The type of the event. Always `response.web_search_call.searching`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool.py deleted file mode 100644 index 019962a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool.py +++ /dev/null @@ -1,307 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from . import web_search_tool -from ..._utils import PropertyInfo -from ..._models import BaseModel -from .custom_tool import CustomTool -from .computer_tool import ComputerTool -from .function_tool import FunctionTool -from .web_search_tool import WebSearchTool -from .apply_patch_tool import ApplyPatchTool -from .file_search_tool import FileSearchTool -from .function_shell_tool import FunctionShellTool -from .web_search_preview_tool import WebSearchPreviewTool - -__all__ = [ - "Tool", - "WebSearchTool", - "Mcp", - "McpAllowedTools", - "McpAllowedToolsMcpToolFilter", - "McpRequireApproval", - "McpRequireApprovalMcpToolApprovalFilter", - "McpRequireApprovalMcpToolApprovalFilterAlways", - "McpRequireApprovalMcpToolApprovalFilterNever", - "CodeInterpreter", - "CodeInterpreterContainer", - "CodeInterpreterContainerCodeInterpreterToolAuto", - "ImageGeneration", - "ImageGenerationInputImageMask", - "LocalShell", -] - -WebSearchToolFilters = web_search_tool.Filters -WebSearchToolUserLocation = web_search_tool.UserLocation - - -class McpAllowedToolsMcpToolFilter(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -McpAllowedTools: TypeAlias = Union[List[str], McpAllowedToolsMcpToolFilter, None] - - -class McpRequireApprovalMcpToolApprovalFilterAlways(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilterNever(BaseModel): - """A filter object to specify which tools are allowed.""" - - read_only: Optional[bool] = None - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: Optional[List[str]] = None - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilter(BaseModel): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: Optional[McpRequireApprovalMcpToolApprovalFilterAlways] = None - """A filter object to specify which tools are allowed.""" - - never: Optional[McpRequireApprovalMcpToolApprovalFilterNever] = None - """A filter object to specify which tools are allowed.""" - - -McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"], None] - - -class Mcp(BaseModel): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: str - """A label for this MCP server, used to identify it in tool calls.""" - - type: Literal["mcp"] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[McpAllowedTools] = None - """List of allowed tool names or a filter object.""" - - authorization: Optional[str] = None - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = None - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] = None - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[McpRequireApproval] = None - """Specify which of the MCP server's tools require approval.""" - - server_description: Optional[str] = None - """Optional description of the MCP server, used to provide more context.""" - - server_url: Optional[str] = None - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -class CodeInterpreterContainerCodeInterpreterToolAuto(BaseModel): - """Configuration for a code interpreter container. - - Optionally specify the IDs of the files to run the code on. - """ - - type: Literal["auto"] - """Always `auto`.""" - - file_ids: Optional[List[str]] = None - """An optional list of uploaded files to make available to your code.""" - - memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None - """The memory limit for the code interpreter container.""" - - -CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] - - -class CodeInterpreter(BaseModel): - """A tool that runs Python code to help generate a response to a prompt.""" - - container: CodeInterpreterContainer - """The code interpreter container. - - Can be a container ID or an object that specifies uploaded file IDs to make - available to your code, along with an optional `memory_limit` setting. - """ - - type: Literal["code_interpreter"] - """The type of the code interpreter tool. Always `code_interpreter`.""" - - -class ImageGenerationInputImageMask(BaseModel): - """Optional mask for inpainting. - - Contains `image_url` - (string, optional) and `file_id` (string, optional). - """ - - file_id: Optional[str] = None - """File ID for the mask image.""" - - image_url: Optional[str] = None - """Base64-encoded mask image.""" - - -class ImageGeneration(BaseModel): - """A tool that generates images using the GPT image models.""" - - type: Literal["image_generation"] - """The type of the image generation tool. Always `image_generation`.""" - - background: Optional[Literal["transparent", "opaque", "auto"]] = None - """Background type for the generated image. - - One of `transparent`, `opaque`, or `auto`. Default: `auto`. - """ - - input_fidelity: Optional[Literal["high", "low"]] = None - """ - Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - """ - - input_image_mask: Optional[ImageGenerationInputImageMask] = None - """Optional mask for inpainting. - - Contains `image_url` (string, optional) and `file_id` (string, optional). - """ - - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"], None] = None - """The image generation model to use. Default: `gpt-image-1`.""" - - moderation: Optional[Literal["auto", "low"]] = None - """Moderation level for the generated image. Default: `auto`.""" - - output_compression: Optional[int] = None - """Compression level for the output image. Default: 100.""" - - output_format: Optional[Literal["png", "webp", "jpeg"]] = None - """The output format of the generated image. - - One of `png`, `webp`, or `jpeg`. Default: `png`. - """ - - partial_images: Optional[int] = None - """ - Number of partial images to generate in streaming mode, from 0 (default value) - to 3. - """ - - quality: Optional[Literal["low", "medium", "high", "auto"]] = None - """The quality of the generated image. - - One of `low`, `medium`, `high`, or `auto`. Default: `auto`. - """ - - size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = None - """The size of the generated image. - - One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. - """ - - -class LocalShell(BaseModel): - """A tool that allows the model to execute shell commands in a local environment.""" - - type: Literal["local_shell"] - """The type of the local shell tool. Always `local_shell`.""" - - -Tool: TypeAlias = Annotated[ - Union[ - FunctionTool, - FileSearchTool, - ComputerTool, - WebSearchTool, - Mcp, - CodeInterpreter, - ImageGeneration, - LocalShell, - FunctionShellTool, - CustomTool, - WebSearchPreviewTool, - ApplyPatchTool, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed.py deleted file mode 100644 index 400e170..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceAllowed"] - - -class ToolChoiceAllowed(BaseModel): - """Constrains the tools available to the model to a pre-defined set.""" - - mode: Literal["auto", "required"] - """Constrains the tools available to the model to a pre-defined set. - - `auto` allows the model to pick from among the allowed tools and generate a - message. - - `required` requires the model to call one or more of the allowed tools. - """ - - tools: List[Dict[str, object]] - """A list of tool definitions that the model should be allowed to call. - - For the Responses API, the list of tool definitions might look like: - - ```json - [ - { "type": "function", "name": "get_weather" }, - { "type": "mcp", "server_label": "deepwiki" }, - { "type": "image_generation" } - ] - ``` - """ - - type: Literal["allowed_tools"] - """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed_param.py deleted file mode 100644 index cb316c1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_allowed_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceAllowedParam"] - - -class ToolChoiceAllowedParam(TypedDict, total=False): - """Constrains the tools available to the model to a pre-defined set.""" - - mode: Required[Literal["auto", "required"]] - """Constrains the tools available to the model to a pre-defined set. - - `auto` allows the model to pick from among the allowed tools and generate a - message. - - `required` requires the model to call one or more of the allowed tools. - """ - - tools: Required[Iterable[Dict[str, object]]] - """A list of tool definitions that the model should be allowed to call. - - For the Responses API, the list of tool definitions might look like: - - ```json - [ - { "type": "function", "name": "get_weather" }, - { "type": "mcp", "server_label": "deepwiki" }, - { "type": "image_generation" } - ] - ``` - """ - - type: Required[Literal["allowed_tools"]] - """Allowed tool configuration type. Always `allowed_tools`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch.py deleted file mode 100644 index ef5a5e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceApplyPatch"] - - -class ToolChoiceApplyPatch(BaseModel): - """Forces the model to call the apply_patch tool when executing a tool call.""" - - type: Literal["apply_patch"] - """The tool to call. Always `apply_patch`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch_param.py deleted file mode 100644 index 193c993..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_apply_patch_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceApplyPatchParam"] - - -class ToolChoiceApplyPatchParam(TypedDict, total=False): - """Forces the model to call the apply_patch tool when executing a tool call.""" - - type: Required[Literal["apply_patch"]] - """The tool to call. Always `apply_patch`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom.py deleted file mode 100644 index dec85ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceCustom"] - - -class ToolChoiceCustom(BaseModel): - """Use this option to force the model to call a specific custom tool.""" - - name: str - """The name of the custom tool to call.""" - - type: Literal["custom"] - """For custom tool calling, the type is always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom_param.py deleted file mode 100644 index ccdbab5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_custom_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceCustomParam"] - - -class ToolChoiceCustomParam(TypedDict, total=False): - """Use this option to force the model to call a specific custom tool.""" - - name: Required[str] - """The name of the custom tool to call.""" - - type: Required[Literal["custom"]] - """For custom tool calling, the type is always `custom`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function.py deleted file mode 100644 index b2aab24..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceFunction"] - - -class ToolChoiceFunction(BaseModel): - """Use this option to force the model to call a specific function.""" - - name: str - """The name of the function to call.""" - - type: Literal["function"] - """For function calling, the type is always `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function_param.py deleted file mode 100644 index 837465e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_function_param.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceFunctionParam"] - - -class ToolChoiceFunctionParam(TypedDict, total=False): - """Use this option to force the model to call a specific function.""" - - name: Required[str] - """The name of the function to call.""" - - type: Required[Literal["function"]] - """For function calling, the type is always `function`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp.py deleted file mode 100644 index a2c8049..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceMcp"] - - -class ToolChoiceMcp(BaseModel): - """ - Use this option to force the model to call a specific tool on a remote MCP server. - """ - - server_label: str - """The label of the MCP server to use.""" - - type: Literal["mcp"] - """For MCP tools, the type is always `mcp`.""" - - name: Optional[str] = None - """The name of the tool to call on the server.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp_param.py deleted file mode 100644 index 9726e47..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_mcp_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceMcpParam"] - - -class ToolChoiceMcpParam(TypedDict, total=False): - """ - Use this option to force the model to call a specific tool on a remote MCP server. - """ - - server_label: Required[str] - """The label of the MCP server to use.""" - - type: Required[Literal["mcp"]] - """For MCP tools, the type is always `mcp`.""" - - name: Optional[str] - """The name of the tool to call on the server.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_options.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_options.py deleted file mode 100644 index c200db5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_options.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ToolChoiceOptions"] - -ToolChoiceOptions: TypeAlias = Literal["none", "auto", "required"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell.py deleted file mode 100644 index a78eccc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceShell"] - - -class ToolChoiceShell(BaseModel): - """Forces the model to call the shell tool when a tool call is required.""" - - type: Literal["shell"] - """The tool to call. Always `shell`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell_param.py deleted file mode 100644 index 0dbcc90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_shell_param.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceShellParam"] - - -class ToolChoiceShellParam(TypedDict, total=False): - """Forces the model to call the shell tool when a tool call is required.""" - - type: Required[Literal["shell"]] - """The tool to call. Always `shell`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types.py deleted file mode 100644 index 044c014..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ToolChoiceTypes"] - - -class ToolChoiceTypes(BaseModel): - """ - Indicates that the model should use a built-in tool to generate a response. - [Learn more about built-in tools](https://platform.openai.com/docs/guides/tools). - """ - - type: Literal[ - "file_search", - "web_search_preview", - "computer_use_preview", - "web_search_preview_2025_03_11", - "image_generation", - "code_interpreter", - ] - """The type of hosted tool the model should to use. - - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - Allowed values are: - - - `file_search` - - `web_search_preview` - - `computer_use_preview` - - `code_interpreter` - - `image_generation` - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types_param.py deleted file mode 100644 index 9bf02db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_choice_types_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ToolChoiceTypesParam"] - - -class ToolChoiceTypesParam(TypedDict, total=False): - """ - Indicates that the model should use a built-in tool to generate a response. - [Learn more about built-in tools](https://platform.openai.com/docs/guides/tools). - """ - - type: Required[ - Literal[ - "file_search", - "web_search_preview", - "computer_use_preview", - "web_search_preview_2025_03_11", - "image_generation", - "code_interpreter", - ] - ] - """The type of hosted tool the model should to use. - - Learn more about - [built-in tools](https://platform.openai.com/docs/guides/tools). - - Allowed values are: - - - `file_search` - - `web_search_preview` - - `computer_use_preview` - - `code_interpreter` - - `image_generation` - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_param.py deleted file mode 100644 index 37d3dde..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/tool_param.py +++ /dev/null @@ -1,307 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from . import web_search_tool_param -from ..chat import ChatCompletionFunctionToolParam -from ..._types import SequenceNotStr -from .custom_tool_param import CustomToolParam -from .computer_tool_param import ComputerToolParam -from .function_tool_param import FunctionToolParam -from .web_search_tool_param import WebSearchToolParam -from .apply_patch_tool_param import ApplyPatchToolParam -from .file_search_tool_param import FileSearchToolParam -from .function_shell_tool_param import FunctionShellToolParam -from .web_search_preview_tool_param import WebSearchPreviewToolParam - -__all__ = [ - "ToolParam", - "Mcp", - "McpAllowedTools", - "McpAllowedToolsMcpToolFilter", - "McpRequireApproval", - "McpRequireApprovalMcpToolApprovalFilter", - "McpRequireApprovalMcpToolApprovalFilterAlways", - "McpRequireApprovalMcpToolApprovalFilterNever", - "CodeInterpreter", - "CodeInterpreterContainer", - "CodeInterpreterContainerCodeInterpreterToolAuto", - "ImageGeneration", - "ImageGenerationInputImageMask", - "LocalShell", -] - -WebSearchTool = web_search_tool_param.WebSearchToolParam -WebSearchToolFilters = web_search_tool_param.Filters -WebSearchToolUserLocation = web_search_tool_param.UserLocation - - -class McpAllowedToolsMcpToolFilter(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -McpAllowedTools: TypeAlias = Union[SequenceNotStr[str], McpAllowedToolsMcpToolFilter] - - -class McpRequireApprovalMcpToolApprovalFilterAlways(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilterNever(TypedDict, total=False): - """A filter object to specify which tools are allowed.""" - - read_only: bool - """Indicates whether or not a tool modifies data or is read-only. - - If an MCP server is - [annotated with `readOnlyHint`](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations-readonlyhint), - it will match this filter. - """ - - tool_names: SequenceNotStr[str] - """List of allowed tool names.""" - - -class McpRequireApprovalMcpToolApprovalFilter(TypedDict, total=False): - """Specify which of the MCP server's tools require approval. - - Can be - `always`, `never`, or a filter object associated with tools - that require approval. - """ - - always: McpRequireApprovalMcpToolApprovalFilterAlways - """A filter object to specify which tools are allowed.""" - - never: McpRequireApprovalMcpToolApprovalFilterNever - """A filter object to specify which tools are allowed.""" - - -McpRequireApproval: TypeAlias = Union[McpRequireApprovalMcpToolApprovalFilter, Literal["always", "never"]] - - -class Mcp(TypedDict, total=False): - """ - Give the model access to additional tools via remote Model Context Protocol - (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp). - """ - - server_label: Required[str] - """A label for this MCP server, used to identify it in tool calls.""" - - type: Required[Literal["mcp"]] - """The type of the MCP tool. Always `mcp`.""" - - allowed_tools: Optional[McpAllowedTools] - """List of allowed tool names or a filter object.""" - - authorization: str - """ - An OAuth access token that can be used with a remote MCP server, either with a - custom MCP server URL or a service connector. Your application must handle the - OAuth authorization flow and provide the token here. - """ - - connector_id: Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - """Identifier for service connectors, like those available in ChatGPT. - - One of `server_url` or `connector_id` must be provided. Learn more about service - connectors - [here](https://platform.openai.com/docs/guides/tools-remote-mcp#connectors). - - Currently supported `connector_id` values are: - - - Dropbox: `connector_dropbox` - - Gmail: `connector_gmail` - - Google Calendar: `connector_googlecalendar` - - Google Drive: `connector_googledrive` - - Microsoft Teams: `connector_microsoftteams` - - Outlook Calendar: `connector_outlookcalendar` - - Outlook Email: `connector_outlookemail` - - SharePoint: `connector_sharepoint` - """ - - headers: Optional[Dict[str, str]] - """Optional HTTP headers to send to the MCP server. - - Use for authentication or other purposes. - """ - - require_approval: Optional[McpRequireApproval] - """Specify which of the MCP server's tools require approval.""" - - server_description: str - """Optional description of the MCP server, used to provide more context.""" - - server_url: str - """The URL for the MCP server. - - One of `server_url` or `connector_id` must be provided. - """ - - -class CodeInterpreterContainerCodeInterpreterToolAuto(TypedDict, total=False): - """Configuration for a code interpreter container. - - Optionally specify the IDs of the files to run the code on. - """ - - type: Required[Literal["auto"]] - """Always `auto`.""" - - file_ids: SequenceNotStr[str] - """An optional list of uploaded files to make available to your code.""" - - memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] - """The memory limit for the code interpreter container.""" - - -CodeInterpreterContainer: TypeAlias = Union[str, CodeInterpreterContainerCodeInterpreterToolAuto] - - -class CodeInterpreter(TypedDict, total=False): - """A tool that runs Python code to help generate a response to a prompt.""" - - container: Required[CodeInterpreterContainer] - """The code interpreter container. - - Can be a container ID or an object that specifies uploaded file IDs to make - available to your code, along with an optional `memory_limit` setting. - """ - - type: Required[Literal["code_interpreter"]] - """The type of the code interpreter tool. Always `code_interpreter`.""" - - -class ImageGenerationInputImageMask(TypedDict, total=False): - """Optional mask for inpainting. - - Contains `image_url` - (string, optional) and `file_id` (string, optional). - """ - - file_id: str - """File ID for the mask image.""" - - image_url: str - """Base64-encoded mask image.""" - - -class ImageGeneration(TypedDict, total=False): - """A tool that generates images using the GPT image models.""" - - type: Required[Literal["image_generation"]] - """The type of the image generation tool. Always `image_generation`.""" - - background: Literal["transparent", "opaque", "auto"] - """Background type for the generated image. - - One of `transparent`, `opaque`, or `auto`. Default: `auto`. - """ - - input_fidelity: Optional[Literal["high", "low"]] - """ - Control how much effort the model will exert to match the style and features, - especially facial features, of input images. This parameter is only supported - for `gpt-image-1`. Unsupported for `gpt-image-1-mini`. Supports `high` and - `low`. Defaults to `low`. - """ - - input_image_mask: ImageGenerationInputImageMask - """Optional mask for inpainting. - - Contains `image_url` (string, optional) and `file_id` (string, optional). - """ - - model: Union[str, Literal["gpt-image-1", "gpt-image-1-mini"]] - """The image generation model to use. Default: `gpt-image-1`.""" - - moderation: Literal["auto", "low"] - """Moderation level for the generated image. Default: `auto`.""" - - output_compression: int - """Compression level for the output image. Default: 100.""" - - output_format: Literal["png", "webp", "jpeg"] - """The output format of the generated image. - - One of `png`, `webp`, or `jpeg`. Default: `png`. - """ - - partial_images: int - """ - Number of partial images to generate in streaming mode, from 0 (default value) - to 3. - """ - - quality: Literal["low", "medium", "high", "auto"] - """The quality of the generated image. - - One of `low`, `medium`, `high`, or `auto`. Default: `auto`. - """ - - size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] - """The size of the generated image. - - One of `1024x1024`, `1024x1536`, `1536x1024`, or `auto`. Default: `auto`. - """ - - -class LocalShell(TypedDict, total=False): - """A tool that allows the model to execute shell commands in a local environment.""" - - type: Required[Literal["local_shell"]] - """The type of the local shell tool. Always `local_shell`.""" - - -ToolParam: TypeAlias = Union[ - FunctionToolParam, - FileSearchToolParam, - ComputerToolParam, - WebSearchToolParam, - Mcp, - CodeInterpreter, - ImageGeneration, - LocalShell, - FunctionShellToolParam, - CustomToolParam, - WebSearchPreviewToolParam, - ApplyPatchToolParam, -] - - -ParseableToolParam: TypeAlias = Union[ToolParam, ChatCompletionFunctionToolParam] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool.py deleted file mode 100644 index 12478e8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["WebSearchPreviewTool", "UserLocation"] - - -class UserLocation(BaseModel): - """The user's location.""" - - type: Literal["approximate"] - """The type of location approximation. Always `approximate`.""" - - city: Optional[str] = None - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] = None - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] = None - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] = None - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - -class WebSearchPreviewTool(BaseModel): - """This tool searches the web for relevant results to use in a response. - - Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search). - """ - - type: Literal["web_search_preview", "web_search_preview_2025_03_11"] - """The type of the web search tool. - - One of `web_search_preview` or `web_search_preview_2025_03_11`. - """ - - search_context_size: Optional[Literal["low", "medium", "high"]] = None - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[UserLocation] = None - """The user's location.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool_param.py deleted file mode 100644 index 09619a3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_preview_tool_param.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["WebSearchPreviewToolParam", "UserLocation"] - - -class UserLocation(TypedDict, total=False): - """The user's location.""" - - type: Required[Literal["approximate"]] - """The type of location approximation. Always `approximate`.""" - - city: Optional[str] - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - -class WebSearchPreviewToolParam(TypedDict, total=False): - """This tool searches the web for relevant results to use in a response. - - Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search). - """ - - type: Required[Literal["web_search_preview", "web_search_preview_2025_03_11"]] - """The type of the web search tool. - - One of `web_search_preview` or `web_search_preview_2025_03_11`. - """ - - search_context_size: Literal["low", "medium", "high"] - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[UserLocation] - """The user's location.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool.py deleted file mode 100644 index 769f5c9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["WebSearchTool", "Filters", "UserLocation"] - - -class Filters(BaseModel): - """Filters for the search.""" - - allowed_domains: Optional[List[str]] = None - """Allowed domains for the search. - - If not provided, all domains are allowed. Subdomains of the provided domains are - allowed as well. - - Example: `["pubmed.ncbi.nlm.nih.gov"]` - """ - - -class UserLocation(BaseModel): - """The approximate location of the user.""" - - city: Optional[str] = None - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] = None - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] = None - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] = None - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - type: Optional[Literal["approximate"]] = None - """The type of location approximation. Always `approximate`.""" - - -class WebSearchTool(BaseModel): - """Search the Internet for sources related to the prompt. - - Learn more about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search). - """ - - type: Literal["web_search", "web_search_2025_08_26"] - """The type of the web search tool. - - One of `web_search` or `web_search_2025_08_26`. - """ - - filters: Optional[Filters] = None - """Filters for the search.""" - - search_context_size: Optional[Literal["low", "medium", "high"]] = None - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[UserLocation] = None - """The approximate location of the user.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool_param.py deleted file mode 100644 index a4531a9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/responses/web_search_tool_param.py +++ /dev/null @@ -1,75 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["WebSearchToolParam", "Filters", "UserLocation"] - - -class Filters(TypedDict, total=False): - """Filters for the search.""" - - allowed_domains: Optional[SequenceNotStr[str]] - """Allowed domains for the search. - - If not provided, all domains are allowed. Subdomains of the provided domains are - allowed as well. - - Example: `["pubmed.ncbi.nlm.nih.gov"]` - """ - - -class UserLocation(TypedDict, total=False): - """The approximate location of the user.""" - - city: Optional[str] - """Free text input for the city of the user, e.g. `San Francisco`.""" - - country: Optional[str] - """ - The two-letter [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of - the user, e.g. `US`. - """ - - region: Optional[str] - """Free text input for the region of the user, e.g. `California`.""" - - timezone: Optional[str] - """ - The [IANA timezone](https://timeapi.io/documentation/iana-timezones) of the - user, e.g. `America/Los_Angeles`. - """ - - type: Literal["approximate"] - """The type of location approximation. Always `approximate`.""" - - -class WebSearchToolParam(TypedDict, total=False): - """Search the Internet for sources related to the prompt. - - Learn more about the - [web search tool](https://platform.openai.com/docs/guides/tools-web-search). - """ - - type: Required[Literal["web_search", "web_search_2025_08_26"]] - """The type of the web search tool. - - One of `web_search` or `web_search_2025_08_26`. - """ - - filters: Optional[Filters] - """Filters for the search.""" - - search_context_size: Literal["low", "medium", "high"] - """High level guidance for the amount of context window space to use for the - search. - - One of `low`, `medium`, or `high`. `medium` is the default. - """ - - user_location: Optional[UserLocation] - """The approximate location of the user.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/__init__.py deleted file mode 100644 index 2930b9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .metadata import Metadata as Metadata -from .reasoning import Reasoning as Reasoning -from .all_models import AllModels as AllModels -from .chat_model import ChatModel as ChatModel -from .error_object import ErrorObject as ErrorObject -from .compound_filter import CompoundFilter as CompoundFilter -from .responses_model import ResponsesModel as ResponsesModel -from .reasoning_effort import ReasoningEffort as ReasoningEffort -from .comparison_filter import ComparisonFilter as ComparisonFilter -from .function_definition import FunctionDefinition as FunctionDefinition -from .function_parameters import FunctionParameters as FunctionParameters -from .response_format_text import ResponseFormatText as ResponseFormatText -from .custom_tool_input_format import CustomToolInputFormat as CustomToolInputFormat -from .response_format_json_object import ResponseFormatJSONObject as ResponseFormatJSONObject -from .response_format_json_schema import ResponseFormatJSONSchema as ResponseFormatJSONSchema -from .response_format_text_python import ResponseFormatTextPython as ResponseFormatTextPython -from .response_format_text_grammar import ResponseFormatTextGrammar as ResponseFormatTextGrammar diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/all_models.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/all_models.py deleted file mode 100644 index ba8e1d8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/all_models.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .chat_model import ChatModel - -__all__ = ["AllModels"] - -AllModels: TypeAlias = Union[ - str, - ChatModel, - Literal[ - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/chat_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/chat_model.py deleted file mode 100644 index 8223b81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/chat_model.py +++ /dev/null @@ -1,80 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ChatModel"] - -ChatModel: TypeAlias = Literal[ - "gpt-5.2", - "gpt-5.2-2025-12-11", - "gpt-5.2-chat-latest", - "gpt-5.2-pro", - "gpt-5.2-pro-2025-12-11", - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/comparison_filter.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/comparison_filter.py deleted file mode 100644 index 852cac1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/comparison_filter.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ComparisonFilter"] - - -class ComparisonFilter(BaseModel): - """ - A filter used to compare a specified attribute key to a given value using a defined comparison operation. - """ - - key: str - """The key to compare against the value.""" - - type: Literal["eq", "ne", "gt", "gte", "lt", "lte"] - """ - Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, - `nin`. - - - `eq`: equals - - `ne`: not equal - - `gt`: greater than - - `gte`: greater than or equal - - `lt`: less than - - `lte`: less than or equal - - `in`: in - - `nin`: not in - """ - - value: Union[str, float, bool, List[Union[str, float]]] - """ - The value to compare against the attribute key; supports string, number, or - boolean types. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/compound_filter.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/compound_filter.py deleted file mode 100644 index 4801aaa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/compound_filter.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .comparison_filter import ComparisonFilter - -__all__ = ["CompoundFilter", "Filter"] - -Filter: TypeAlias = Union[ComparisonFilter, object] - - -class CompoundFilter(BaseModel): - """Combine multiple filters using `and` or `or`.""" - - filters: List[Filter] - """Array of filters to combine. - - Items can be `ComparisonFilter` or `CompoundFilter`. - """ - - type: Literal["and", "or"] - """Type of operation: `and` or `or`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/custom_tool_input_format.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/custom_tool_input_format.py deleted file mode 100644 index 9391692..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/custom_tool_input_format.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from ..._utils import PropertyInfo -from ..._models import BaseModel - -__all__ = ["CustomToolInputFormat", "Text", "Grammar"] - - -class Text(BaseModel): - """Unconstrained free-form text.""" - - type: Literal["text"] - """Unconstrained text format. Always `text`.""" - - -class Grammar(BaseModel): - """A grammar defined by the user.""" - - definition: str - """The grammar definition.""" - - syntax: Literal["lark", "regex"] - """The syntax of the grammar definition. One of `lark` or `regex`.""" - - type: Literal["grammar"] - """Grammar format. Always `grammar`.""" - - -CustomToolInputFormat: TypeAlias = Annotated[Union[Text, Grammar], PropertyInfo(discriminator="type")] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/error_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/error_object.py deleted file mode 100644 index 32d7045..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/error_object.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["ErrorObject"] - - -class ErrorObject(BaseModel): - code: Optional[str] = None - - message: str - - param: Optional[str] = None - - type: str diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_definition.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_definition.py deleted file mode 100644 index 33ebb9a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_definition.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel -from .function_parameters import FunctionParameters - -__all__ = ["FunctionDefinition"] - - -class FunctionDefinition(BaseModel): - name: str - """The name of the function to be called. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - description: Optional[str] = None - """ - A description of what the function does, used by the model to choose when and - how to call the function. - """ - - parameters: Optional[FunctionParameters] = None - """The parameters the functions accepts, described as a JSON Schema object. - - See the [guide](https://platform.openai.com/docs/guides/function-calling) for - examples, and the - [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for - documentation about the format. - - Omitting `parameters` defines a function with an empty parameter list. - """ - - strict: Optional[bool] = None - """Whether to enable strict schema adherence when generating the function call. - - If set to true, the model will follow the exact schema defined in the - `parameters` field. Only a subset of JSON Schema is supported when `strict` is - `true`. Learn more about Structured Outputs in the - [function calling guide](https://platform.openai.com/docs/guides/function-calling). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_parameters.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_parameters.py deleted file mode 100644 index a3d83e3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/function_parameters.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict -from typing_extensions import TypeAlias - -__all__ = ["FunctionParameters"] - -FunctionParameters: TypeAlias = Dict[str, object] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/metadata.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/metadata.py deleted file mode 100644 index 0da88c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/metadata.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict -from typing_extensions import TypeAlias - -__all__ = ["Metadata"] - -Metadata: TypeAlias = Dict[str, str] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning.py deleted file mode 100644 index 14f56a0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning.py +++ /dev/null @@ -1,52 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from .reasoning_effort import ReasoningEffort - -__all__ = ["Reasoning"] - - -class Reasoning(BaseModel): - """**gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ - - effort: Optional[ReasoningEffort] = None - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None - """**Deprecated:** use `summary` instead. - - A summary of the reasoning performed by the model. This can be useful for - debugging and understanding the model's reasoning process. One of `auto`, - `concise`, or `detailed`. - """ - - summary: Optional[Literal["auto", "concise", "detailed"]] = None - """A summary of the reasoning performed by the model. - - This can be useful for debugging and understanding the model's reasoning - process. One of `auto`, `concise`, or `detailed`. - - `concise` is supported for `computer-use-preview` models and all reasoning - models after `gpt-5`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning_effort.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning_effort.py deleted file mode 100644 index 24d8516..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/reasoning_effort.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal, TypeAlias - -__all__ = ["ReasoningEffort"] - -ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_object.py deleted file mode 100644 index 98e0da6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_object.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFormatJSONObject"] - - -class ResponseFormatJSONObject(BaseModel): - """JSON object response format. - - An older method of generating JSON responses. - Using `json_schema` is recommended for models that support it. Note that the - model will not generate JSON without a system or user message instructing it - to do so. - """ - - type: Literal["json_object"] - """The type of response format being defined. Always `json_object`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_schema.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_schema.py deleted file mode 100644 index 9b2adb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_json_schema.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["ResponseFormatJSONSchema", "JSONSchema"] - - -class JSONSchema(BaseModel): - """Structured Outputs configuration options, including a JSON Schema.""" - - name: str - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - description: Optional[str] = None - """ - A description of what the response format is for, used by the model to determine - how to respond in the format. - """ - - schema_: Optional[Dict[str, object]] = FieldInfo(alias="schema", default=None) - """ - The schema for the response format, described as a JSON Schema object. Learn how - to build JSON schemas [here](https://json-schema.org/). - """ - - strict: Optional[bool] = None - """ - Whether to enable strict schema adherence when generating the output. If set to - true, the model will always follow the exact schema defined in the `schema` - field. Only a subset of JSON Schema is supported when `strict` is `true`. To - learn more, read the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - """ - - -class ResponseFormatJSONSchema(BaseModel): - """JSON Schema response format. - - Used to generate structured JSON responses. - Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). - """ - - json_schema: JSONSchema - """Structured Outputs configuration options, including a JSON Schema.""" - - type: Literal["json_schema"] - """The type of response format being defined. Always `json_schema`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text.py deleted file mode 100644 index 9f4bc0d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFormatText"] - - -class ResponseFormatText(BaseModel): - """Default response format. Used to generate text responses.""" - - type: Literal["text"] - """The type of response format being defined. Always `text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_grammar.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_grammar.py deleted file mode 100644 index 84cd141..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_grammar.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFormatTextGrammar"] - - -class ResponseFormatTextGrammar(BaseModel): - """ - A custom grammar for the model to follow when generating text. - Learn more in the [custom grammars guide](https://platform.openai.com/docs/guides/custom-grammars). - """ - - grammar: str - """The custom grammar for the model to follow.""" - - type: Literal["grammar"] - """The type of response format being defined. Always `grammar`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_python.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_python.py deleted file mode 100644 index 1b04cb6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/response_format_text_python.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFormatTextPython"] - - -class ResponseFormatTextPython(BaseModel): - """Configure the model to generate valid Python code. - - See the - [custom grammars guide](https://platform.openai.com/docs/guides/custom-grammars) for more details. - """ - - type: Literal["python"] - """The type of response format being defined. Always `python`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/responses_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared/responses_model.py deleted file mode 100644 index 38cdea9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared/responses_model.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from .chat_model import ChatModel - -__all__ = ["ResponsesModel"] - -ResponsesModel: TypeAlias = Union[ - str, - ChatModel, - Literal[ - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/__init__.py deleted file mode 100644 index b6c0912..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .metadata import Metadata as Metadata -from .reasoning import Reasoning as Reasoning -from .chat_model import ChatModel as ChatModel -from .compound_filter import CompoundFilter as CompoundFilter -from .responses_model import ResponsesModel as ResponsesModel -from .reasoning_effort import ReasoningEffort as ReasoningEffort -from .comparison_filter import ComparisonFilter as ComparisonFilter -from .function_definition import FunctionDefinition as FunctionDefinition -from .function_parameters import FunctionParameters as FunctionParameters -from .response_format_text import ResponseFormatText as ResponseFormatText -from .custom_tool_input_format import CustomToolInputFormat as CustomToolInputFormat -from .response_format_json_object import ResponseFormatJSONObject as ResponseFormatJSONObject -from .response_format_json_schema import ResponseFormatJSONSchema as ResponseFormatJSONSchema diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/chat_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/chat_model.py deleted file mode 100644 index c1937a8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/chat_model.py +++ /dev/null @@ -1,82 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ChatModel"] - -ChatModel: TypeAlias = Literal[ - "gpt-5.2", - "gpt-5.2-2025-12-11", - "gpt-5.2-chat-latest", - "gpt-5.2-pro", - "gpt-5.2-pro-2025-12-11", - "gpt-5.1", - "gpt-5.1-2025-11-13", - "gpt-5.1-codex", - "gpt-5.1-mini", - "gpt-5.1-chat-latest", - "gpt-5", - "gpt-5-mini", - "gpt-5-nano", - "gpt-5-2025-08-07", - "gpt-5-mini-2025-08-07", - "gpt-5-nano-2025-08-07", - "gpt-5-chat-latest", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.1-2025-04-14", - "gpt-4.1-mini-2025-04-14", - "gpt-4.1-nano-2025-04-14", - "o4-mini", - "o4-mini-2025-04-16", - "o3", - "o3-2025-04-16", - "o3-mini", - "o3-mini-2025-01-31", - "o1", - "o1-2024-12-17", - "o1-preview", - "o1-preview-2024-09-12", - "o1-mini", - "o1-mini-2024-09-12", - "gpt-4o", - "gpt-4o-2024-11-20", - "gpt-4o-2024-08-06", - "gpt-4o-2024-05-13", - "gpt-4o-audio-preview", - "gpt-4o-audio-preview-2024-10-01", - "gpt-4o-audio-preview-2024-12-17", - "gpt-4o-audio-preview-2025-06-03", - "gpt-4o-mini-audio-preview", - "gpt-4o-mini-audio-preview-2024-12-17", - "gpt-4o-search-preview", - "gpt-4o-mini-search-preview", - "gpt-4o-search-preview-2025-03-11", - "gpt-4o-mini-search-preview-2025-03-11", - "chatgpt-4o-latest", - "codex-mini-latest", - "gpt-4o-mini", - "gpt-4o-mini-2024-07-18", - "gpt-4-turbo", - "gpt-4-turbo-2024-04-09", - "gpt-4-0125-preview", - "gpt-4-turbo-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-3.5-turbo-1106", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k-0613", -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/comparison_filter.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/comparison_filter.py deleted file mode 100644 index 363688e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/comparison_filter.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["ComparisonFilter"] - - -class ComparisonFilter(TypedDict, total=False): - """ - A filter used to compare a specified attribute key to a given value using a defined comparison operation. - """ - - key: Required[str] - """The key to compare against the value.""" - - type: Required[Literal["eq", "ne", "gt", "gte", "lt", "lte"]] - """ - Specifies the comparison operator: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, - `nin`. - - - `eq`: equals - - `ne`: not equal - - `gt`: greater than - - `gte`: greater than or equal - - `lt`: less than - - `lte`: less than or equal - - `in`: in - - `nin`: not in - """ - - value: Required[Union[str, float, bool, SequenceNotStr[Union[str, float]]]] - """ - The value to compare against the attribute key; supports string, number, or - boolean types. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/compound_filter.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/compound_filter.py deleted file mode 100644 index 9358e46..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/compound_filter.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .comparison_filter import ComparisonFilter - -__all__ = ["CompoundFilter", "Filter"] - -Filter: TypeAlias = Union[ComparisonFilter, object] - - -class CompoundFilter(TypedDict, total=False): - """Combine multiple filters using `and` or `or`.""" - - filters: Required[Iterable[Filter]] - """Array of filters to combine. - - Items can be `ComparisonFilter` or `CompoundFilter`. - """ - - type: Required[Literal["and", "or"]] - """Type of operation: `and` or `or`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/custom_tool_input_format.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/custom_tool_input_format.py deleted file mode 100644 index ddc71ca..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/custom_tool_input_format.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["CustomToolInputFormat", "Text", "Grammar"] - - -class Text(TypedDict, total=False): - """Unconstrained free-form text.""" - - type: Required[Literal["text"]] - """Unconstrained text format. Always `text`.""" - - -class Grammar(TypedDict, total=False): - """A grammar defined by the user.""" - - definition: Required[str] - """The grammar definition.""" - - syntax: Required[Literal["lark", "regex"]] - """The syntax of the grammar definition. One of `lark` or `regex`.""" - - type: Required[Literal["grammar"]] - """Grammar format. Always `grammar`.""" - - -CustomToolInputFormat: TypeAlias = Union[Text, Grammar] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_definition.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_definition.py deleted file mode 100644 index b3fdaf8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_definition.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -from .function_parameters import FunctionParameters - -__all__ = ["FunctionDefinition"] - - -class FunctionDefinition(TypedDict, total=False): - name: Required[str] - """The name of the function to be called. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - description: str - """ - A description of what the function does, used by the model to choose when and - how to call the function. - """ - - parameters: FunctionParameters - """The parameters the functions accepts, described as a JSON Schema object. - - See the [guide](https://platform.openai.com/docs/guides/function-calling) for - examples, and the - [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for - documentation about the format. - - Omitting `parameters` defines a function with an empty parameter list. - """ - - strict: Optional[bool] - """Whether to enable strict schema adherence when generating the function call. - - If set to true, the model will follow the exact schema defined in the - `parameters` field. Only a subset of JSON Schema is supported when `strict` is - `true`. Learn more about Structured Outputs in the - [function calling guide](https://platform.openai.com/docs/guides/function-calling). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_parameters.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_parameters.py deleted file mode 100644 index 45fc742..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/function_parameters.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import TypeAlias - -__all__ = ["FunctionParameters"] - -FunctionParameters: TypeAlias = Dict[str, object] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/metadata.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/metadata.py deleted file mode 100644 index 821650b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/metadata.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import TypeAlias - -__all__ = ["Metadata"] - -Metadata: TypeAlias = Dict[str, str] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning.py deleted file mode 100644 index 2bd7ce7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, TypedDict - -from ..shared.reasoning_effort import ReasoningEffort - -__all__ = ["Reasoning"] - - -class Reasoning(TypedDict, total=False): - """**gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ - - effort: Optional[ReasoningEffort] - """ - Constrains effort on reasoning for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - supported values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. - Reducing reasoning effort can result in faster responses and fewer tokens used - on reasoning in a response. - - - `gpt-5.1` defaults to `none`, which does not perform reasoning. The supported - reasoning values for `gpt-5.1` are `none`, `low`, `medium`, and `high`. Tool - calls are supported for all reasoning values in gpt-5.1. - - All models before `gpt-5.1` default to `medium` reasoning effort, and do not - support `none`. - - The `gpt-5-pro` model defaults to (and only supports) `high` reasoning effort. - - `xhigh` is supported for all models after `gpt-5.1-codex-max`. - """ - - generate_summary: Optional[Literal["auto", "concise", "detailed"]] - """**Deprecated:** use `summary` instead. - - A summary of the reasoning performed by the model. This can be useful for - debugging and understanding the model's reasoning process. One of `auto`, - `concise`, or `detailed`. - """ - - summary: Optional[Literal["auto", "concise", "detailed"]] - """A summary of the reasoning performed by the model. - - This can be useful for debugging and understanding the model's reasoning - process. One of `auto`, `concise`, or `detailed`. - - `concise` is supported for `computer-use-preview` models and all reasoning - models after `gpt-5`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning_effort.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning_effort.py deleted file mode 100644 index 8518c2b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/reasoning_effort.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, TypeAlias - -__all__ = ["ReasoningEffort"] - -ReasoningEffort: TypeAlias = Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_object.py deleted file mode 100644 index ef5d43b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_object.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseFormatJSONObject"] - - -class ResponseFormatJSONObject(TypedDict, total=False): - """JSON object response format. - - An older method of generating JSON responses. - Using `json_schema` is recommended for models that support it. Note that the - model will not generate JSON without a system or user message instructing it - to do so. - """ - - type: Required[Literal["json_object"]] - """The type of response format being defined. Always `json_object`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_schema.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_schema.py deleted file mode 100644 index 0a0e846..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_json_schema.py +++ /dev/null @@ -1,54 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseFormatJSONSchema", "JSONSchema"] - - -class JSONSchema(TypedDict, total=False): - """Structured Outputs configuration options, including a JSON Schema.""" - - name: Required[str] - """The name of the response format. - - Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length - of 64. - """ - - description: str - """ - A description of what the response format is for, used by the model to determine - how to respond in the format. - """ - - schema: Dict[str, object] - """ - The schema for the response format, described as a JSON Schema object. Learn how - to build JSON schemas [here](https://json-schema.org/). - """ - - strict: Optional[bool] - """ - Whether to enable strict schema adherence when generating the output. If set to - true, the model will always follow the exact schema defined in the `schema` - field. Only a subset of JSON Schema is supported when `strict` is `true`. To - learn more, read the - [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - """ - - -class ResponseFormatJSONSchema(TypedDict, total=False): - """JSON Schema response format. - - Used to generate structured JSON responses. - Learn more about [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs). - """ - - json_schema: Required[JSONSchema] - """Structured Outputs configuration options, including a JSON Schema.""" - - type: Required[Literal["json_schema"]] - """The type of response format being defined. Always `json_schema`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_text.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_text.py deleted file mode 100644 index c195036..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/response_format_text.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ResponseFormatText"] - - -class ResponseFormatText(TypedDict, total=False): - """Default response format. Used to generate text responses.""" - - type: Required[Literal["text"]] - """The type of response format being defined. Always `text`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/responses_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/responses_model.py deleted file mode 100644 index ad44dd6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/shared_params/responses_model.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -from ..shared.chat_model import ChatModel - -__all__ = ["ResponsesModel"] - -ResponsesModel: TypeAlias = Union[ - str, - ChatModel, - Literal[ - "o1-pro", - "o1-pro-2025-03-19", - "o3-pro", - "o3-pro-2025-06-10", - "o3-deep-research", - "o3-deep-research-2025-06-26", - "o4-mini-deep-research", - "o4-mini-deep-research-2025-06-26", - "computer-use-preview", - "computer-use-preview-2025-03-11", - "gpt-5-codex", - "gpt-5-pro", - "gpt-5-pro-2025-10-06", - "gpt-5.1-codex-max", - ], -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy.py b/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy.py deleted file mode 100644 index cb84244..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["StaticFileChunkingStrategy"] - - -class StaticFileChunkingStrategy(BaseModel): - chunk_overlap_tokens: int - """The number of tokens that overlap between chunks. The default value is `400`. - - Note that the overlap must not exceed half of `max_chunk_size_tokens`. - """ - - max_chunk_size_tokens: int - """The maximum number of tokens in each chunk. - - The default value is `800`. The minimum value is `100` and the maximum value is - `4096`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object.py b/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object.py deleted file mode 100644 index 2a95dce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel -from .static_file_chunking_strategy import StaticFileChunkingStrategy - -__all__ = ["StaticFileChunkingStrategyObject"] - - -class StaticFileChunkingStrategyObject(BaseModel): - static: StaticFileChunkingStrategy - - type: Literal["static"] - """Always `static`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object_param.py deleted file mode 100644 index 40188a4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_object_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .static_file_chunking_strategy_param import StaticFileChunkingStrategyParam - -__all__ = ["StaticFileChunkingStrategyObjectParam"] - - -class StaticFileChunkingStrategyObjectParam(TypedDict, total=False): - """Customize your own chunking strategy by setting chunk size and chunk overlap.""" - - static: Required[StaticFileChunkingStrategyParam] - - type: Required[Literal["static"]] - """Always `static`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_param.py deleted file mode 100644 index f917ac5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/static_file_chunking_strategy_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["StaticFileChunkingStrategyParam"] - - -class StaticFileChunkingStrategyParam(TypedDict, total=False): - chunk_overlap_tokens: Required[int] - """The number of tokens that overlap between chunks. The default value is `400`. - - Note that the overlap must not exceed half of `max_chunk_size_tokens`. - """ - - max_chunk_size_tokens: Required[int] - """The maximum number of tokens in each chunk. - - The default value is `800`. The minimum value is `100` and the maximum value is - `4096`. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/upload.py b/backend/venv39/lib/python3.9/site-packages/openai/types/upload.py deleted file mode 100644 index d248da6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/upload.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .file_object import FileObject - -__all__ = ["Upload"] - - -class Upload(BaseModel): - """The Upload object can accept byte chunks in the form of Parts.""" - - id: str - """The Upload unique identifier, which can be referenced in API endpoints.""" - - bytes: int - """The intended number of bytes to be uploaded.""" - - created_at: int - """The Unix timestamp (in seconds) for when the Upload was created.""" - - expires_at: int - """The Unix timestamp (in seconds) for when the Upload will expire.""" - - filename: str - """The name of the file to be uploaded.""" - - object: Literal["upload"] - """The object type, which is always "upload".""" - - purpose: str - """The intended purpose of the file. - - [Please refer here](https://platform.openai.com/docs/api-reference/files/object#files/object-purpose) - for acceptable values. - """ - - status: Literal["pending", "completed", "cancelled", "expired"] - """The status of the Upload.""" - - file: Optional[FileObject] = None - """The `File` object represents a document that has been uploaded to OpenAI.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/upload_complete_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/upload_complete_params.py deleted file mode 100644 index 846a241..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/upload_complete_params.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .._types import SequenceNotStr - -__all__ = ["UploadCompleteParams"] - - -class UploadCompleteParams(TypedDict, total=False): - part_ids: Required[SequenceNotStr[str]] - """The ordered list of Part IDs.""" - - md5: str - """ - The optional md5 checksum for the file contents to verify if the bytes uploaded - matches what you expect. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/upload_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/upload_create_params.py deleted file mode 100644 index c25d65b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/upload_create_params.py +++ /dev/null @@ -1,57 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from .file_purpose import FilePurpose - -__all__ = ["UploadCreateParams", "ExpiresAfter"] - - -class UploadCreateParams(TypedDict, total=False): - bytes: Required[int] - """The number of bytes in the file you are uploading.""" - - filename: Required[str] - """The name of the file to upload.""" - - mime_type: Required[str] - """The MIME type of the file. - - This must fall within the supported MIME types for your file purpose. See the - supported MIME types for assistants and vision. - """ - - purpose: Required[FilePurpose] - """The intended purpose of the uploaded file. - - See the - [documentation on File purposes](https://platform.openai.com/docs/api-reference/files/create#files-create-purpose). - """ - - expires_after: ExpiresAfter - """The expiration policy for a file. - - By default, files with `purpose=batch` expire after 30 days and all other files - are persisted until they are manually deleted. - """ - - -class ExpiresAfter(TypedDict, total=False): - """The expiration policy for a file. - - By default, files with `purpose=batch` expire after 30 days and all other files are persisted until they are manually deleted. - """ - - anchor: Required[Literal["created_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `created_at`. - """ - - seconds: Required[int] - """The number of seconds after the anchor time that the file will expire. - - Must be between 3600 (1 hour) and 2592000 (30 days). - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/__init__.py deleted file mode 100644 index 41deb0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .upload_part import UploadPart as UploadPart -from .part_create_params import PartCreateParams as PartCreateParams diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/part_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/part_create_params.py deleted file mode 100644 index 9851ca4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/part_create_params.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ..._types import FileTypes - -__all__ = ["PartCreateParams"] - - -class PartCreateParams(TypedDict, total=False): - data: Required[FileTypes] - """The chunk of bytes for this Part.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/upload_part.py b/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/upload_part.py deleted file mode 100644 index e585b1a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/uploads/upload_part.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["UploadPart"] - - -class UploadPart(BaseModel): - """The upload Part represents a chunk of bytes we can add to an Upload object.""" - - id: str - """The upload Part unique identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the Part was created.""" - - object: Literal["upload.part"] - """The object type, which is always `upload.part`.""" - - upload_id: str - """The ID of the Upload object that this Part was added to.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store.py deleted file mode 100644 index 82899ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store.py +++ /dev/null @@ -1,88 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .shared.metadata import Metadata - -__all__ = ["VectorStore", "FileCounts", "ExpiresAfter"] - - -class FileCounts(BaseModel): - cancelled: int - """The number of files that were cancelled.""" - - completed: int - """The number of files that have been successfully processed.""" - - failed: int - """The number of files that have failed to process.""" - - in_progress: int - """The number of files that are currently being processed.""" - - total: int - """The total number of files.""" - - -class ExpiresAfter(BaseModel): - """The expiration policy for a vector store.""" - - anchor: Literal["last_active_at"] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: int - """The number of days after the anchor time that the vector store will expire.""" - - -class VectorStore(BaseModel): - """ - A vector store is a collection of processed files can be used by the `file_search` tool. - """ - - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the vector store was created.""" - - file_counts: FileCounts - - last_active_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the vector store was last active.""" - - metadata: Optional[Metadata] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the vector store.""" - - object: Literal["vector_store"] - """The object type, which is always `vector_store`.""" - - status: Literal["expired", "in_progress", "completed"] - """ - The status of the vector store, which can be either `expired`, `in_progress`, or - `completed`. A status of `completed` indicates that the vector store is ready - for use. - """ - - usage_bytes: int - """The total number of bytes used by the files in the vector store.""" - - expires_after: Optional[ExpiresAfter] = None - """The expiration policy for a vector store.""" - - expires_at: Optional[int] = None - """The Unix timestamp (in seconds) for when the vector store will expire.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_create_params.py deleted file mode 100644 index 2b72562..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_create_params.py +++ /dev/null @@ -1,63 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -from .._types import SequenceNotStr -from .shared_params.metadata import Metadata -from .file_chunking_strategy_param import FileChunkingStrategyParam - -__all__ = ["VectorStoreCreateParams", "ExpiresAfter"] - - -class VectorStoreCreateParams(TypedDict, total=False): - chunking_strategy: FileChunkingStrategyParam - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. - """ - - description: str - """A description for the vector store. - - Can be used to describe the vector store's purpose. - """ - - expires_after: ExpiresAfter - """The expiration policy for a vector store.""" - - file_ids: SequenceNotStr[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. - """ - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: str - """The name of the vector store.""" - - -class ExpiresAfter(TypedDict, total=False): - """The expiration policy for a vector store.""" - - anchor: Required[Literal["last_active_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: Required[int] - """The number of days after the anchor time that the vector store will expire.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_deleted.py deleted file mode 100644 index dfac9ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["VectorStoreDeleted"] - - -class VectorStoreDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["vector_store.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_list_params.py deleted file mode 100644 index e26ff90..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_list_params.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["VectorStoreListParams"] - - -class VectorStoreListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_params.py deleted file mode 100644 index 851d63c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_params.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .._types import SequenceNotStr -from .shared_params.compound_filter import CompoundFilter -from .shared_params.comparison_filter import ComparisonFilter - -__all__ = ["VectorStoreSearchParams", "Filters", "RankingOptions"] - - -class VectorStoreSearchParams(TypedDict, total=False): - query: Required[Union[str, SequenceNotStr[str]]] - """A query string for a search""" - - filters: Filters - """A filter to apply based on file attributes.""" - - max_num_results: int - """The maximum number of results to return. - - This number should be between 1 and 50 inclusive. - """ - - ranking_options: RankingOptions - """Ranking options for search.""" - - rewrite_query: bool - """Whether to rewrite the natural language query for vector search.""" - - -Filters: TypeAlias = Union[ComparisonFilter, CompoundFilter] - - -class RankingOptions(TypedDict, total=False): - """Ranking options for search.""" - - ranker: Literal["none", "auto", "default-2024-11-15"] - """Enable re-ranking; set to `none` to disable, which can help reduce latency.""" - - score_threshold: float diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_response.py deleted file mode 100644 index d78b71b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_search_response.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["VectorStoreSearchResponse", "Content"] - - -class Content(BaseModel): - text: str - """The text content returned from search.""" - - type: Literal["text"] - """The type of content.""" - - -class VectorStoreSearchResponse(BaseModel): - attributes: Optional[Dict[str, Union[str, float, bool]]] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - content: List[Content] - """Content chunks from the file.""" - - file_id: str - """The ID of the vector store file.""" - - filename: str - """The name of the vector store file.""" - - score: float - """The similarity score for the result.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_update_params.py deleted file mode 100644 index 7c6f891..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_store_update_params.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal, Required, TypedDict - -from .shared_params.metadata import Metadata - -__all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] - - -class VectorStoreUpdateParams(TypedDict, total=False): - expires_after: Optional[ExpiresAfter] - """The expiration policy for a vector store.""" - - metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. - """ - - name: Optional[str] - """The name of the vector store.""" - - -class ExpiresAfter(TypedDict, total=False): - """The expiration policy for a vector store.""" - - anchor: Required[Literal["last_active_at"]] - """Anchor timestamp after which the expiration policy applies. - - Supported anchors: `last_active_at`. - """ - - days: Required[int] - """The number of days after the anchor time that the vector store will expire.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/__init__.py deleted file mode 100644 index 96ce301..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .file_list_params import FileListParams as FileListParams -from .vector_store_file import VectorStoreFile as VectorStoreFile -from .file_create_params import FileCreateParams as FileCreateParams -from .file_update_params import FileUpdateParams as FileUpdateParams -from .file_content_response import FileContentResponse as FileContentResponse -from .vector_store_file_batch import VectorStoreFileBatch as VectorStoreFileBatch -from .file_batch_create_params import FileBatchCreateParams as FileBatchCreateParams -from .vector_store_file_deleted import VectorStoreFileDeleted as VectorStoreFileDeleted -from .file_batch_list_files_params import FileBatchListFilesParams as FileBatchListFilesParams diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_create_params.py deleted file mode 100644 index 2ab98a8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_create_params.py +++ /dev/null @@ -1,70 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr -from ..file_chunking_strategy_param import FileChunkingStrategyParam - -__all__ = ["FileBatchCreateParams", "File"] - - -class FileBatchCreateParams(TypedDict, total=False): - attributes: Optional[Dict[str, Union[str, float, bool]]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - chunking_strategy: FileChunkingStrategyParam - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. - """ - - file_ids: SequenceNotStr[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the vector store should use. Useful for tools like `file_search` that can access - files. If `attributes` or `chunking_strategy` are provided, they will be applied - to all files in the batch. Mutually exclusive with `files`. - """ - - files: Iterable[File] - """ - A list of objects that each include a `file_id` plus optional `attributes` or - `chunking_strategy`. Use this when you need to override metadata for specific - files. The global `attributes` or `chunking_strategy` will be ignored and must - be specified for each file. Mutually exclusive with `file_ids`. - """ - - -class File(TypedDict, total=False): - file_id: Required[str] - """ - A [File](https://platform.openai.com/docs/api-reference/files) ID that the - vector store should use. Useful for tools like `file_search` that can access - files. - """ - - attributes: Optional[Dict[str, Union[str, float, bool]]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - chunking_strategy: FileChunkingStrategyParam - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_list_files_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_list_files_params.py deleted file mode 100644 index 2a0a6c6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_batch_list_files_params.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FileBatchListFilesParams"] - - -class FileBatchListFilesParams(TypedDict, total=False): - vector_store_id: Required[str] - - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - filter: Literal["in_progress", "completed", "failed", "cancelled"] - """Filter by file status. - - One of `in_progress`, `completed`, `failed`, `cancelled`. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_content_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_content_response.py deleted file mode 100644 index 32db2f2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_content_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["FileContentResponse"] - - -class FileContentResponse(BaseModel): - text: Optional[str] = None - """The text content""" - - type: Optional[str] = None - """The content type (currently only `"text"`)""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_create_params.py deleted file mode 100644 index 5b89892..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_create_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Required, TypedDict - -from ..file_chunking_strategy_param import FileChunkingStrategyParam - -__all__ = ["FileCreateParams"] - - -class FileCreateParams(TypedDict, total=False): - file_id: Required[str] - """ - A [File](https://platform.openai.com/docs/api-reference/files) ID that the - vector store should use. Useful for tools like `file_search` that can access - files. - """ - - attributes: Optional[Dict[str, Union[str, float, bool]]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - chunking_strategy: FileChunkingStrategyParam - """The chunking strategy used to chunk the file(s). - - If not set, will use the `auto` strategy. Only applicable if `file_ids` is - non-empty. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_list_params.py deleted file mode 100644 index 867b5fb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_list_params.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["FileListParams"] - - -class FileListParams(TypedDict, total=False): - after: str - """A cursor for use in pagination. - - `after` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include after=obj_foo in order to fetch the next page of the - list. - """ - - before: str - """A cursor for use in pagination. - - `before` is an object ID that defines your place in the list. For instance, if - you make a list request and receive 100 objects, starting with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page - of the list. - """ - - filter: Literal["in_progress", "completed", "failed", "cancelled"] - """Filter by file status. - - One of `in_progress`, `completed`, `failed`, `cancelled`. - """ - - limit: int - """A limit on the number of objects to be returned. - - Limit can range between 1 and 100, and the default is 20. - """ - - order: Literal["asc", "desc"] - """Sort order by the `created_at` timestamp of the objects. - - `asc` for ascending order and `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_update_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_update_params.py deleted file mode 100644 index ebf540d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/file_update_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import Required, TypedDict - -__all__ = ["FileUpdateParams"] - - -class FileUpdateParams(TypedDict, total=False): - vector_store_id: Required[str] - - attributes: Required[Optional[Dict[str, Union[str, float, bool]]]] - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file.py deleted file mode 100644 index c1ea022..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file.py +++ /dev/null @@ -1,74 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Union, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..file_chunking_strategy import FileChunkingStrategy - -__all__ = ["VectorStoreFile", "LastError"] - - -class LastError(BaseModel): - """The last error associated with this vector store file. - - Will be `null` if there are no errors. - """ - - code: Literal["server_error", "unsupported_file", "invalid_file"] - """One of `server_error`, `unsupported_file`, or `invalid_file`.""" - - message: str - """A human-readable description of the error.""" - - -class VectorStoreFile(BaseModel): - """A list of files attached to a vector store.""" - - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the vector store file was created.""" - - last_error: Optional[LastError] = None - """The last error associated with this vector store file. - - Will be `null` if there are no errors. - """ - - object: Literal["vector_store.file"] - """The object type, which is always `vector_store.file`.""" - - status: Literal["in_progress", "completed", "cancelled", "failed"] - """ - The status of the vector store file, which can be either `in_progress`, - `completed`, `cancelled`, or `failed`. The status `completed` indicates that the - vector store file is ready for use. - """ - - usage_bytes: int - """The total vector store usage in bytes. - - Note that this may be different from the original file size. - """ - - vector_store_id: str - """ - The ID of the - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - that the [File](https://platform.openai.com/docs/api-reference/files) is - attached to. - """ - - attributes: Optional[Dict[str, Union[str, float, bool]]] = None - """Set of 16 key-value pairs that can be attached to an object. - - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. Keys are - strings with a maximum length of 64 characters. Values are strings with a - maximum length of 512 characters, booleans, or numbers. - """ - - chunking_strategy: Optional[FileChunkingStrategy] = None - """The strategy used to chunk the file.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_batch.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_batch.py deleted file mode 100644 index b07eb25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_batch.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["VectorStoreFileBatch", "FileCounts"] - - -class FileCounts(BaseModel): - cancelled: int - """The number of files that where cancelled.""" - - completed: int - """The number of files that have been processed.""" - - failed: int - """The number of files that have failed to process.""" - - in_progress: int - """The number of files that are currently being processed.""" - - total: int - """The total number of files.""" - - -class VectorStoreFileBatch(BaseModel): - """A batch of files attached to a vector store.""" - - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """ - The Unix timestamp (in seconds) for when the vector store files batch was - created. - """ - - file_counts: FileCounts - - object: Literal["vector_store.files_batch"] - """The object type, which is always `vector_store.file_batch`.""" - - status: Literal["in_progress", "completed", "cancelled", "failed"] - """ - The status of the vector store files batch, which can be either `in_progress`, - `completed`, `cancelled` or `failed`. - """ - - vector_store_id: str - """ - The ID of the - [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - that the [File](https://platform.openai.com/docs/api-reference/files) is - attached to. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_deleted.py b/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_deleted.py deleted file mode 100644 index 5c856f2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/vector_stores/vector_store_file_deleted.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["VectorStoreFileDeleted"] - - -class VectorStoreFileDeleted(BaseModel): - id: str - - deleted: bool - - object: Literal["vector_store.file.deleted"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video.py deleted file mode 100644 index e732ea5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video.py +++ /dev/null @@ -1,55 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .video_size import VideoSize -from .video_model import VideoModel -from .video_seconds import VideoSeconds -from .video_create_error import VideoCreateError - -__all__ = ["Video"] - - -class Video(BaseModel): - """Structured information describing a generated video job.""" - - id: str - """Unique identifier for the video job.""" - - completed_at: Optional[int] = None - """Unix timestamp (seconds) for when the job completed, if finished.""" - - created_at: int - """Unix timestamp (seconds) for when the job was created.""" - - error: Optional[VideoCreateError] = None - """Error payload that explains why generation failed, if applicable.""" - - expires_at: Optional[int] = None - """Unix timestamp (seconds) for when the downloadable assets expire, if set.""" - - model: VideoModel - """The video generation model that produced the job.""" - - object: Literal["video"] - """The object type, which is always `video`.""" - - progress: int - """Approximate completion percentage for the generation task.""" - - prompt: Optional[str] = None - """The prompt that was used to generate the video.""" - - remixed_from_video_id: Optional[str] = None - """Identifier of the source video if this video is a remix.""" - - seconds: VideoSeconds - """Duration of the generated clip in seconds.""" - - size: VideoSize - """The resolution of the generated video.""" - - status: Literal["queued", "in_progress", "completed", "failed"] - """Current lifecycle status of the video job.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_error.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_error.py deleted file mode 100644 index 7f52022..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_error.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["VideoCreateError"] - - -class VideoCreateError(BaseModel): - """An error that occurred while generating the response.""" - - code: str - """A machine-readable error code that was returned.""" - - message: str - """A human-readable description of the error that was returned.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_params.py deleted file mode 100644 index d787aae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_create_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .._types import FileTypes -from .video_size import VideoSize -from .video_seconds import VideoSeconds -from .video_model_param import VideoModelParam - -__all__ = ["VideoCreateParams"] - - -class VideoCreateParams(TypedDict, total=False): - prompt: Required[str] - """Text prompt that describes the video to generate.""" - - input_reference: FileTypes - """Optional image reference that guides generation.""" - - model: VideoModelParam - """The video generation model to use (allowed values: sora-2, sora-2-pro). - - Defaults to `sora-2`. - """ - - seconds: VideoSeconds - """Clip duration in seconds (allowed values: 4, 8, 12). Defaults to 4 seconds.""" - - size: VideoSize - """ - Output resolution formatted as width x height (allowed values: 720x1280, - 1280x720, 1024x1792, 1792x1024). Defaults to 720x1280. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_delete_response.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_delete_response.py deleted file mode 100644 index 1ed543a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_delete_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["VideoDeleteResponse"] - - -class VideoDeleteResponse(BaseModel): - """Confirmation payload returned after deleting a video.""" - - id: str - """Identifier of the deleted video.""" - - deleted: bool - """Indicates that the video resource was deleted.""" - - object: Literal["video.deleted"] - """The object type that signals the deletion response.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_download_content_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_download_content_params.py deleted file mode 100644 index 8c113d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_download_content_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["VideoDownloadContentParams"] - - -class VideoDownloadContentParams(TypedDict, total=False): - variant: Literal["video", "thumbnail", "spritesheet"] - """Which downloadable asset to return. Defaults to the MP4 video.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_list_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_list_params.py deleted file mode 100644 index bf55ba7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_list_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["VideoListParams"] - - -class VideoListParams(TypedDict, total=False): - after: str - """Identifier for the last item from the previous pagination request""" - - limit: int - """Number of items to retrieve""" - - order: Literal["asc", "desc"] - """Sort order of results by timestamp. - - Use `asc` for ascending order or `desc` for descending order. - """ diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_model.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_model.py deleted file mode 100644 index 29d8cb1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_model.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -__all__ = ["VideoModel"] - -VideoModel: TypeAlias = Union[ - str, Literal["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"] -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_model_param.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_model_param.py deleted file mode 100644 index 4310b8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_model_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -__all__ = ["VideoModelParam"] - -VideoModelParam: TypeAlias = Union[ - str, Literal["sora-2", "sora-2-pro", "sora-2-2025-10-06", "sora-2-pro-2025-10-06", "sora-2-2025-12-08"] -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_remix_params.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_remix_params.py deleted file mode 100644 index 15388d6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_remix_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["VideoRemixParams"] - - -class VideoRemixParams(TypedDict, total=False): - prompt: Required[str] - """Updated text prompt that directs the remix generation.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_seconds.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_seconds.py deleted file mode 100644 index e50d37d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_seconds.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["VideoSeconds"] - -VideoSeconds: TypeAlias = Literal["4", "8", "12"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/video_size.py b/backend/venv39/lib/python3.9/site-packages/openai/types/video_size.py deleted file mode 100644 index 215ac88..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/video_size.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["VideoSize"] - -VideoSize: TypeAlias = Literal["720x1280", "1280x720", "1024x1792", "1792x1024"] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/__init__.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/__init__.py deleted file mode 100644 index 8b9e556..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .unwrap_webhook_event import UnwrapWebhookEvent as UnwrapWebhookEvent -from .batch_failed_webhook_event import BatchFailedWebhookEvent as BatchFailedWebhookEvent -from .batch_expired_webhook_event import BatchExpiredWebhookEvent as BatchExpiredWebhookEvent -from .batch_cancelled_webhook_event import BatchCancelledWebhookEvent as BatchCancelledWebhookEvent -from .batch_completed_webhook_event import BatchCompletedWebhookEvent as BatchCompletedWebhookEvent -from .eval_run_failed_webhook_event import EvalRunFailedWebhookEvent as EvalRunFailedWebhookEvent -from .response_failed_webhook_event import ResponseFailedWebhookEvent as ResponseFailedWebhookEvent -from .eval_run_canceled_webhook_event import EvalRunCanceledWebhookEvent as EvalRunCanceledWebhookEvent -from .eval_run_succeeded_webhook_event import EvalRunSucceededWebhookEvent as EvalRunSucceededWebhookEvent -from .response_cancelled_webhook_event import ResponseCancelledWebhookEvent as ResponseCancelledWebhookEvent -from .response_completed_webhook_event import ResponseCompletedWebhookEvent as ResponseCompletedWebhookEvent -from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent as ResponseIncompleteWebhookEvent -from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent as FineTuningJobFailedWebhookEvent -from .realtime_call_incoming_webhook_event import RealtimeCallIncomingWebhookEvent as RealtimeCallIncomingWebhookEvent -from .fine_tuning_job_cancelled_webhook_event import ( - FineTuningJobCancelledWebhookEvent as FineTuningJobCancelledWebhookEvent, -) -from .fine_tuning_job_succeeded_webhook_event import ( - FineTuningJobSucceededWebhookEvent as FineTuningJobSucceededWebhookEvent, -) diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_cancelled_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_cancelled_webhook_event.py deleted file mode 100644 index 9d1c485..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_cancelled_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["BatchCancelledWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the batch API request.""" - - -class BatchCancelledWebhookEvent(BaseModel): - """Sent when a batch API request has been cancelled.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the batch API request was cancelled.""" - - data: Data - """Event data payload.""" - - type: Literal["batch.cancelled"] - """The type of the event. Always `batch.cancelled`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_completed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_completed_webhook_event.py deleted file mode 100644 index 5ae8191..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_completed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["BatchCompletedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the batch API request.""" - - -class BatchCompletedWebhookEvent(BaseModel): - """Sent when a batch API request has been completed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the batch API request was completed.""" - - data: Data - """Event data payload.""" - - type: Literal["batch.completed"] - """The type of the event. Always `batch.completed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_expired_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_expired_webhook_event.py deleted file mode 100644 index 2f08a7f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_expired_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["BatchExpiredWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the batch API request.""" - - -class BatchExpiredWebhookEvent(BaseModel): - """Sent when a batch API request has expired.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the batch API request expired.""" - - data: Data - """Event data payload.""" - - type: Literal["batch.expired"] - """The type of the event. Always `batch.expired`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_failed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_failed_webhook_event.py deleted file mode 100644 index 7166616..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/batch_failed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["BatchFailedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the batch API request.""" - - -class BatchFailedWebhookEvent(BaseModel): - """Sent when a batch API request has failed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the batch API request failed.""" - - data: Data - """Event data payload.""" - - type: Literal["batch.failed"] - """The type of the event. Always `batch.failed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_canceled_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_canceled_webhook_event.py deleted file mode 100644 index 1948f89..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_canceled_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["EvalRunCanceledWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the eval run.""" - - -class EvalRunCanceledWebhookEvent(BaseModel): - """Sent when an eval run has been canceled.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the eval run was canceled.""" - - data: Data - """Event data payload.""" - - type: Literal["eval.run.canceled"] - """The type of the event. Always `eval.run.canceled`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_failed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_failed_webhook_event.py deleted file mode 100644 index 4e4c860..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_failed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["EvalRunFailedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the eval run.""" - - -class EvalRunFailedWebhookEvent(BaseModel): - """Sent when an eval run has failed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the eval run failed.""" - - data: Data - """Event data payload.""" - - type: Literal["eval.run.failed"] - """The type of the event. Always `eval.run.failed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_succeeded_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_succeeded_webhook_event.py deleted file mode 100644 index c20f22e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/eval_run_succeeded_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["EvalRunSucceededWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the eval run.""" - - -class EvalRunSucceededWebhookEvent(BaseModel): - """Sent when an eval run has succeeded.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the eval run succeeded.""" - - data: Data - """Event data payload.""" - - type: Literal["eval.run.succeeded"] - """The type of the event. Always `eval.run.succeeded`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py deleted file mode 100644 index 0cfff85..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_cancelled_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FineTuningJobCancelledWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the fine-tuning job.""" - - -class FineTuningJobCancelledWebhookEvent(BaseModel): - """Sent when a fine-tuning job has been cancelled.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the fine-tuning job was cancelled.""" - - data: Data - """Event data payload.""" - - type: Literal["fine_tuning.job.cancelled"] - """The type of the event. Always `fine_tuning.job.cancelled`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py deleted file mode 100644 index 0eb6bf9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_failed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FineTuningJobFailedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the fine-tuning job.""" - - -class FineTuningJobFailedWebhookEvent(BaseModel): - """Sent when a fine-tuning job has failed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the fine-tuning job failed.""" - - data: Data - """Event data payload.""" - - type: Literal["fine_tuning.job.failed"] - """The type of the event. Always `fine_tuning.job.failed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py deleted file mode 100644 index 26b5ea8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/fine_tuning_job_succeeded_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["FineTuningJobSucceededWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the fine-tuning job.""" - - -class FineTuningJobSucceededWebhookEvent(BaseModel): - """Sent when a fine-tuning job has succeeded.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the fine-tuning job succeeded.""" - - data: Data - """Event data payload.""" - - type: Literal["fine_tuning.job.succeeded"] - """The type of the event. Always `fine_tuning.job.succeeded`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/realtime_call_incoming_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/realtime_call_incoming_webhook_event.py deleted file mode 100644 index 4647a2e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/realtime_call_incoming_webhook_event.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RealtimeCallIncomingWebhookEvent", "Data", "DataSipHeader"] - - -class DataSipHeader(BaseModel): - """A header from the SIP Invite.""" - - name: str - """Name of the SIP Header.""" - - value: str - """Value of the SIP Header.""" - - -class Data(BaseModel): - """Event data payload.""" - - call_id: str - """The unique ID of this call.""" - - sip_headers: List[DataSipHeader] - """Headers from the SIP Invite.""" - - -class RealtimeCallIncomingWebhookEvent(BaseModel): - """Sent when Realtime API Receives a incoming SIP call.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the model response was completed.""" - - data: Data - """Event data payload.""" - - type: Literal["realtime.call.incoming"] - """The type of the event. Always `realtime.call.incoming`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_cancelled_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_cancelled_webhook_event.py deleted file mode 100644 index cd791b3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_cancelled_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCancelledWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the model response.""" - - -class ResponseCancelledWebhookEvent(BaseModel): - """Sent when a background response has been cancelled.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the model response was cancelled.""" - - data: Data - """Event data payload.""" - - type: Literal["response.cancelled"] - """The type of the event. Always `response.cancelled`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_completed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_completed_webhook_event.py deleted file mode 100644 index cf07f0c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_completed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseCompletedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the model response.""" - - -class ResponseCompletedWebhookEvent(BaseModel): - """Sent when a background response has been completed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the model response was completed.""" - - data: Data - """Event data payload.""" - - type: Literal["response.completed"] - """The type of the event. Always `response.completed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_failed_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_failed_webhook_event.py deleted file mode 100644 index aecb1b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_failed_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseFailedWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the model response.""" - - -class ResponseFailedWebhookEvent(BaseModel): - """Sent when a background response has failed.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the model response failed.""" - - data: Data - """Event data payload.""" - - type: Literal["response.failed"] - """The type of the event. Always `response.failed`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_incomplete_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_incomplete_webhook_event.py deleted file mode 100644 index 2367731..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/response_incomplete_webhook_event.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ResponseIncompleteWebhookEvent", "Data"] - - -class Data(BaseModel): - """Event data payload.""" - - id: str - """The unique ID of the model response.""" - - -class ResponseIncompleteWebhookEvent(BaseModel): - """Sent when a background response has been interrupted.""" - - id: str - """The unique ID of the event.""" - - created_at: int - """The Unix timestamp (in seconds) of when the model response was interrupted.""" - - data: Data - """Event data payload.""" - - type: Literal["response.incomplete"] - """The type of the event. Always `response.incomplete`.""" - - object: Optional[Literal["event"]] = None - """The object of the event. Always `event`.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/unwrap_webhook_event.py b/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/unwrap_webhook_event.py deleted file mode 100644 index 952383c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/webhooks/unwrap_webhook_event.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .batch_failed_webhook_event import BatchFailedWebhookEvent -from .batch_expired_webhook_event import BatchExpiredWebhookEvent -from .batch_cancelled_webhook_event import BatchCancelledWebhookEvent -from .batch_completed_webhook_event import BatchCompletedWebhookEvent -from .eval_run_failed_webhook_event import EvalRunFailedWebhookEvent -from .response_failed_webhook_event import ResponseFailedWebhookEvent -from .eval_run_canceled_webhook_event import EvalRunCanceledWebhookEvent -from .eval_run_succeeded_webhook_event import EvalRunSucceededWebhookEvent -from .response_cancelled_webhook_event import ResponseCancelledWebhookEvent -from .response_completed_webhook_event import ResponseCompletedWebhookEvent -from .response_incomplete_webhook_event import ResponseIncompleteWebhookEvent -from .fine_tuning_job_failed_webhook_event import FineTuningJobFailedWebhookEvent -from .realtime_call_incoming_webhook_event import RealtimeCallIncomingWebhookEvent -from .fine_tuning_job_cancelled_webhook_event import FineTuningJobCancelledWebhookEvent -from .fine_tuning_job_succeeded_webhook_event import FineTuningJobSucceededWebhookEvent - -__all__ = ["UnwrapWebhookEvent"] - -UnwrapWebhookEvent: TypeAlias = Annotated[ - Union[ - BatchCancelledWebhookEvent, - BatchCompletedWebhookEvent, - BatchExpiredWebhookEvent, - BatchFailedWebhookEvent, - EvalRunCanceledWebhookEvent, - EvalRunFailedWebhookEvent, - EvalRunSucceededWebhookEvent, - FineTuningJobCancelledWebhookEvent, - FineTuningJobFailedWebhookEvent, - FineTuningJobSucceededWebhookEvent, - RealtimeCallIncomingWebhookEvent, - ResponseCancelledWebhookEvent, - ResponseCompletedWebhookEvent, - ResponseFailedWebhookEvent, - ResponseIncompleteWebhookEvent, - ], - PropertyInfo(discriminator="type"), -] diff --git a/backend/venv39/lib/python3.9/site-packages/openai/types/websocket_connection_options.py b/backend/venv39/lib/python3.9/site-packages/openai/types/websocket_connection_options.py deleted file mode 100644 index 40fd24a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/types/websocket_connection_options.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING -from typing_extensions import Sequence, TypedDict - -if TYPE_CHECKING: - from websockets import Subprotocol - from websockets.extensions import ClientExtensionFactory - - -class WebsocketConnectionOptions(TypedDict, total=False): - """Websocket connection options copied from `websockets`. - - For example: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect - """ - - extensions: Sequence[ClientExtensionFactory] | None - """List of supported extensions, in order in which they should be negotiated and run.""" - - subprotocols: Sequence[Subprotocol] | None - """List of supported subprotocols, in order of decreasing preference.""" - - compression: str | None - """The “permessage-deflate” extension is enabled by default. Set compression to None to disable it. See the [compression guide](https://websockets.readthedocs.io/en/stable/topics/compression.html) for details.""" - - # limits - max_size: int | None - """Maximum size of incoming messages in bytes. None disables the limit.""" - - max_queue: int | None | tuple[int | None, int | None] - """High-water mark of the buffer where frames are received. It defaults to 16 frames. The low-water mark defaults to max_queue // 4. You may pass a (high, low) tuple to set the high-water and low-water marks. If you want to disable flow control entirely, you may set it to None, although that’s a bad idea.""" - - write_limit: int | tuple[int, int | None] - """High-water mark of write buffer in bytes. It is passed to set_write_buffer_limits(). It defaults to 32 KiB. You may pass a (high, low) tuple to set the high-water and low-water marks.""" diff --git a/backend/venv39/lib/python3.9/site-packages/openai/version.py b/backend/venv39/lib/python3.9/site-packages/openai/version.py deleted file mode 100644 index 01a08ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/openai/version.py +++ /dev/null @@ -1,3 +0,0 @@ -from ._version import __version__ - -VERSION: str = __version__ diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/INSTALLER b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/LICENSE b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/LICENSE deleted file mode 100644 index 48c0f72..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/LICENSE +++ /dev/null @@ -1,116 +0,0 @@ -.. -*- restructuredtext -*- - -===================== -Copyrights & Licenses -===================== - -Credits -======= -Passlib is primarily developed by Eli Collins. - -Special thanks to Darin Gordon for testing and -feedback on the :mod:`passlib.totp` module. - -License for Passlib -=================== -Passlib is (c) `Assurance Technologies `_, -and is released under the `BSD license `_:: - - Passlib - Copyright (c) 2008-2020 Assurance Technologies, LLC. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of Assurance Technologies, nor the names of the - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Licenses for incorporated software -================================== -Passlib contains some code derived from the following sources: - -MD5-Crypt ---------- -The source file ``passlib/handlers/md5_crypt.py`` contains code derived from the original -`FreeBSD md5-crypt implementation `_, -which is available under the following license:: - - "THE BEER-WARE LICENSE" (Revision 42): - wrote this file. As long as you retain this notice you - can do whatever you want with this stuff. If we meet some day, and you think - this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - - converted to python May 2008 - by Eli Collins - -DES ---- -The source file ``passlib/crypto/des.py`` contains code derived from -`UnixCrypt.java `_, -a pure-java implementation of the historic unix-crypt password hash algorithm. -It is available under the following license:: - - UnixCrypt.java 0.9 96/11/25 - Copyright (c) 1996 Aki Yoshida. All rights reserved. - Permission to use, copy, modify and distribute this software - for non-commercial or commercial purposes and without fee is - hereby granted provided that this copyright notice appears in - all copies. - - modified April 2001 - by Iris Van den Broeke, Daniel Deville - - modified Aug 2005 - by Greg Wilkins (gregw) - - converted to python Jun 2009 - by Eli Collins - -jBCrypt -------- -The source file ``passlib/crypto/_blowfish/base.py`` contains code derived -from `jBcrypt 0.2 `_, a Java -implementation of the BCrypt password hash algorithm. It is available under -a BSD/ISC license:: - - Copyright (c) 2006 Damien Miller - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Wordsets --------- -The EFF wordsets in ``passlib/_data/wordsets`` are (c) 2016 the Electronic Freedom Foundation. -They were downloaded from ``_, -and are released under the `Creative Commons License `_. diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/METADATA b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/METADATA deleted file mode 100644 index 0665d8a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/METADATA +++ /dev/null @@ -1,40 +0,0 @@ -Metadata-Version: 2.1 -Name: passlib -Version: 1.7.4 -Summary: comprehensive password hashing framework supporting over 30 schemes -Home-page: https://passlib.readthedocs.io -Author: Eli Collins -Author-email: elic@assurancetechnologies.com -License: BSD -Download-URL: https://pypi.python.org/packages/source/p/passlib/passlib-1.7.4.tar.gz -Keywords: password secret hash security -Provides-Extra: argon2 -Requires-Dist: argon2-cffi (>=18.2.0) ; extra == 'argon2' -Provides-Extra: bcrypt -Requires-Dist: bcrypt (>=3.1.0) ; extra == 'bcrypt' -Provides-Extra: build_docs -Requires-Dist: sphinx (>=1.6) ; extra == 'build_docs' -Requires-Dist: sphinxcontrib-fulltoc (>=1.2.0) ; extra == 'build_docs' -Requires-Dist: cloud-sptheme (>=1.10.1) ; extra == 'build_docs' -Provides-Extra: totp -Requires-Dist: cryptography ; extra == 'totp' - -Passlib is a password hashing library for Python 2 & 3, which provides -cross-platform implementations of over 30 password hashing algorithms, as well -as a framework for managing existing password hashes. It's designed to be useful -for a wide range of tasks, from verifying a hash found in /etc/shadow, to -providing full-strength password hashing for multi-user applications. - -* See the `documentation `_ - for details, installation instructions, and examples. - -* See the `homepage `_ - for the latest news and more information. - -* See the `changelog `_ - for a description of what's new in Passlib. - -All releases are signed with the gpg key -`4D8592DF4CE1ED31 `_. - - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/RECORD b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/RECORD deleted file mode 100644 index f884f2a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/RECORD +++ /dev/null @@ -1,202 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/apache.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/apps.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/context.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/_gen_files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/base.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/unrolled.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_md4.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/des.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/digest.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_builtin.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_gen_files.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_salsa.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/exc.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/ext/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/models.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/argon2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/bcrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/cisco.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/des_crypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/digests.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/django.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/fshp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/ldap_digests.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/md5_crypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/misc.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mssql.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mysql.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/oracle.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/pbkdf2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/phpass.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/postgres.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/roundup.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/scram.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/scrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha1_crypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha2_crypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sun_md5_crypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/handlers/windows.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/hash.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/hosts.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/ifc.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/pwd.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/registry.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/__main__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/_test_bad_register.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/backports.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apache.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apps.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context_deprecated.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_builtin_md4.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_des.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_digest.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_scrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django_source.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_argon2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_bcrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_cisco.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_django.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_pbkdf2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_scrypt.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_hosts.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_pwd.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_registry.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_totp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils_handlers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils_md4.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils_pbkdf2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_win32.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/tox_support.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/tests/utils.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/totp.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/binary.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/compat/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/compat/_ordered_dict.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/decor.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/des.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/handlers.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/md4.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/utils/pbkdf2.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/duguoyou/MLFlow/algorithm-showcase/backend/venv39/lib/python3.9/site-packages/passlib/win32.cpython-39.pyc,, -passlib-1.7.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -passlib-1.7.4.dist-info/LICENSE,sha256=qVuo8a-I_41fDQwzUZ9DC3-diZK2nUvDaawEI6egWok,4954 -passlib-1.7.4.dist-info/METADATA,sha256=l-uRq14ie328RCoVsayT7AfMHaJqv34ICbpQtKG00jM,1688 -passlib-1.7.4.dist-info/RECORD,, -passlib-1.7.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -passlib-1.7.4.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 -passlib-1.7.4.dist-info/top_level.txt,sha256=BA9xbJpLdaTxqvYbKigYnMQkzp8-UQr6S4m3lBTkxzw,8 -passlib-1.7.4.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -passlib/__init__.py,sha256=nSZrPEtlMQSKZqxERmYcWCDBD6pJ1P_DL5TdeSjIReU,87 -passlib/_data/wordsets/bip39.txt,sha256=JM5Cwv1KlcG4a77pvOHhzyVb0AIuGbq2vVka_Wi379s,13117 -passlib/_data/wordsets/eff_long.txt,sha256=bVV_BpOVj7XmULaLW-5YXrgs9NoyllUFx4npJHQ7xSI,62144 -passlib/_data/wordsets/eff_prefixed.txt,sha256=eqV6TT7PZYFymZK62VdbrN6_fCg3ivKuxqUPEa7DJvU,10778 -passlib/_data/wordsets/eff_short.txt,sha256=NuzKSeT6IMqEsXbDLy6cgvmPRGWFGQ51-YealcCCR78,7180 -passlib/apache.py,sha256=TsHUCur5W8tK3Rsb9jYeeBCc7Ua_hP9e2tSxzoUVzwc,46661 -passlib/apps.py,sha256=AYqni3QIelR7HCiPj_hv2Mcr8bsfdcUkh07DwQqZxWs,8067 -passlib/context.py,sha256=aJeTjA-h7ke3KObvEM8aSJzKdN3wrOyu0hTt-MTbJt0,109195 -passlib/crypto/__init__.py,sha256=St6CGqhrfz3L5Da3aZvRK69le_FcLLE3gA2dEByOmC0,84 -passlib/crypto/_blowfish/__init__.py,sha256=iZb7ft1vxBjCW7lpDtWwTxuMicgvi673M5F_1PKdVkg,6426 -passlib/crypto/_blowfish/_gen_files.py,sha256=fUrNGWA5NX9CyvoJbNhJv7PJmptbp1uSR9iaWzKkb1I,6176 -passlib/crypto/_blowfish/base.py,sha256=_zF7x6XSbqCl2HH5Eya8KIhhJVbDYuYAWKfxbjOQZWg,20390 -passlib/crypto/_blowfish/unrolled.py,sha256=FOMhVo_jnGS3bMafXfjEffDPSP5vMogFvupnVKAa1lg,37153 -passlib/crypto/_md4.py,sha256=_5RXBX_gowtN0x05PnN0EF_csO4Q_NA5whm6e_vJx08,6905 -passlib/crypto/des.py,sha256=1EsvVd34Z82BYmGb8JIzfVWvTMN70fWhJGmIfmNrBAU,51878 -passlib/crypto/digest.py,sha256=WsfpcC8IM-gvZh56m6v8bjzG4nsNAsaoSv2LNY1_5go,36158 -passlib/crypto/scrypt/__init__.py,sha256=bXmeIerN6DKJSw8XsQEYcsUKCfRpXGb190e-gdHbbqU,9630 -passlib/crypto/scrypt/_builtin.py,sha256=82RZc_4LQv2JCL06bX70hCICBaK30Uy7PGzmZtiOjA0,8910 -passlib/crypto/scrypt/_gen_files.py,sha256=vRhjlIKqwvcILCo20sVf8dXr15tW636t5oojAZFssJE,4683 -passlib/crypto/scrypt/_salsa.py,sha256=b87_YEP3jJSmlU2BHSx-NKiJ4e_1eK-RlC4pWA4y71I,5719 -passlib/exc.py,sha256=MIjUTBLcOai52paDLM1nFh6lMTLBLPAn1PTdbCm-9Fo,14481 -passlib/ext/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -passlib/ext/django/__init__.py,sha256=RvooHmuUwjLXuSuUJr-9URnY1CRVCzU2xdh-jW-mrN0,228 -passlib/ext/django/models.py,sha256=-XpQRLGG2kTuLWNoh-EhKOaeEV5aIfzavw8qTQ-p1fM,1314 -passlib/ext/django/utils.py,sha256=ObpILR1seOZyecYhuQ1G_R9_N6DMuS4kWZve_giRLiw,49409 -passlib/handlers/__init__.py,sha256=sIPjJgOGHpOIstAwDeHTfxKR8wLVqP4zSa4mvBhAZ_8,86 -passlib/handlers/argon2.py,sha256=XrMPknuG-16IAwrd7WUuTKdIkKOD-3UPlHHZOjXZe68,38934 -passlib/handlers/bcrypt.py,sha256=LF33HnoxOhjtr7aFtrKgU5SB4mtw3xGx7C4tqecosrk,53582 -passlib/handlers/cisco.py,sha256=Yz0KhmqVVAV_szNnuZq40WgYg6eomBRoAJBbRrSUkGg,16284 -passlib/handlers/des_crypt.py,sha256=W3srE5kIaRQdhfIObz237sm0vPgqR4p_9ZkSd-9UNPo,22367 -passlib/handlers/digests.py,sha256=AeuVSxas2793ILXX0s6xm1lA1u4RPpE9G8wZSaq0Bs4,6327 -passlib/handlers/django.py,sha256=MmoLua6kZWVItsjRrnDgfktzuEpqlvwlPaexvti6I9M,20185 -passlib/handlers/fshp.py,sha256=78sMdnAkW5YHCPC13bLptdElLFrWzZF7rm3bwUWHATo,7799 -passlib/handlers/ldap_digests.py,sha256=jgxtxcERep4xXgVVfKfSVe5JEE45b5tt87NKGvK9_Zk,13049 -passlib/handlers/md5_crypt.py,sha256=jLt3IP-l0HFfU1u2VEtGI1WBYVNjTqhjvwovfFREiwg,13740 -passlib/handlers/misc.py,sha256=o1tWKAdTp3EnCYJOERpdkQnRwrQfWWKeiJXSQurbVMo,10109 -passlib/handlers/mssql.py,sha256=BECU0VaVtc-RzhGx7E_LVu2moZpEI5GASChFJnzDVxA,8482 -passlib/handlers/mysql.py,sha256=8h83lpTHs5q8zflXP0TyMavrELgtlvgUbcLtFUHnbDY,4796 -passlib/handlers/oracle.py,sha256=WDCqJEo2rDihcuUs4Ka48JBpSm4_JnNqXIVsCGUrkO8,6691 -passlib/handlers/pbkdf2.py,sha256=jVqdo1MSD3_7B5m-osqUTBTwTXnhedLan9lQaM-gysU,19010 -passlib/handlers/phpass.py,sha256=0c7maDUNGxIuyiG_O2hK6MJbxcTu7V2vx67xOq8d7ps,4785 -passlib/handlers/postgres.py,sha256=y9AzGpxjK-z1HLHElRQtLzCMqqtvBwd_xxJraHdGpN4,2274 -passlib/handlers/roundup.py,sha256=lvYArKerC702_MHZXMi3F-iZ9Y2jH10h2UXKDpgqoO8,1178 -passlib/handlers/scram.py,sha256=wBsoBg0qLW8HA5Nsgcnd1bM7ZDYEFbapAGoP0_44N58,22539 -passlib/handlers/scrypt.py,sha256=OYfF2Jjltydr5BswyZ-uFgl4yEjQZowGdIZpEyB7s5Q,14146 -passlib/handlers/sha1_crypt.py,sha256=DZOdKExzlucHCfpgszG1cFdareTqpGUGORNIEn4FJCs,5873 -passlib/handlers/sha2_crypt.py,sha256=kTZm-jmRVnKRhquetVBbiDWi9eY87NTJvUYkjGEm7MY,21800 -passlib/handlers/sun_md5_crypt.py,sha256=uWhoKxBITVwPlh9MIQ3WjVrYjlRMgLrBjLR1Ui2kmZw,13933 -passlib/handlers/windows.py,sha256=nviGebFjOiJO_cDJRo7RiccEhlN2UM7nAQL0pTso9MQ,12384 -passlib/hash.py,sha256=9lVasGFiXDGcL8VOWuEwAjzlATQbmEYF30wOIVotP-U,3750 -passlib/hosts.py,sha256=odRo2WnSfjMuktSIwfR50rzxbKGfzUwZ2CUkvcxvJoA,3302 -passlib/ifc.py,sha256=kL2svtkF99VQDOim_6TE6OGhmSf2EyHrzp0v_UQksqA,14196 -passlib/pwd.py,sha256=VeU_PVkZSvwXPI6AQA96cjqIKyuTvXtUoCK7eI5ab7w,28690 -passlib/registry.py,sha256=5qLDF72XHGSQVoEVqhvEngfZsO2fxVsBpWntX_D0YRs,20301 -passlib/tests/__init__.py,sha256=JIK29mBP8OKz3ChmaEbyr9vvml3weGe7YHMTHzBJcr0,20 -passlib/tests/__main__.py,sha256=iKv9ZuQe5jBzp4Gyp_G3wXhQBxSTJguMx1BCCVVZL6Y,82 -passlib/tests/_test_bad_register.py,sha256=yws8uO2HsUWg8GRQPlxKvE5HniP84QSQW6ncCPiZDpw,541 -passlib/tests/backports.py,sha256=QTi9tD9DO_RlawkInpPDsFaol--5hsMI-cFvwLIE9B0,2593 -passlib/tests/sample1.cfg,sha256=lJsayArbi6FElINzcTQ1VbgTTGY5LKpMdbCJvK_6H8s,243 -passlib/tests/sample1b.cfg,sha256=2ZQnnpumQsEJpKFsTOHuv_ULhQY5PhQPnsa2rSZmTEU,252 -passlib/tests/sample1c.cfg,sha256=u-BGMklAN05efndzADJfFV9gP1Jbns1gDdwC__VfW-8,490 -passlib/tests/sample_config_1s.cfg,sha256=mMgYjX_UvxVVLFTfZ4m-vxVo31MbSNrZA0R7VY6DzTk,238 -passlib/tests/test_apache.py,sha256=_XhDKgV1nON4ddQQU3GdUfSXrwY_x2OoJQ6l7w2Gzbw,29432 -passlib/tests/test_apps.py,sha256=6MrGeFenjSACzbAtp6jf3PNHoITv_v5DbT_7nhrR-KA,5281 -passlib/tests/test_context.py,sha256=Vsl2hhouEi3yn4_J7J10E09OotLneRHzkAY_jS16F08,74546 -passlib/tests/test_context_deprecated.py,sha256=cVXqcPx_Xqlsh6QF2az34RY23wP3pv8SOBbJFQn65Jg,29282 -passlib/tests/test_crypto_builtin_md4.py,sha256=5PWKh1HoQKC4gI4BcgVDh89xw7lix0R1n9Jn0Y8t8mQ,5660 -passlib/tests/test_crypto_des.py,sha256=0xWgS74G6ygl7gIvF6uhjcoThVTt1TqIH4ZUeqXbVmA,8874 -passlib/tests/test_crypto_digest.py,sha256=b15XIFLDUsjsaxPEQUJkb-csM65IRz_9glwZz7qwN7U,20478 -passlib/tests/test_crypto_scrypt.py,sha256=xJDU3e4bt9N1X0fA9zBLBxESk3PsTR89qJeEWNX2Em4,26646 -passlib/tests/test_ext_django.py,sha256=QUKoa6rLn3hbCVNk7_0z9JW5aOFmyLbBwj0PiWhQJ7s,41364 -passlib/tests/test_ext_django_source.py,sha256=AW-PQRQeLz2cOpKGPeKPLSESC4o-ATbu3-Zd45Coi3k,11034 -passlib/tests/test_handlers.py,sha256=WxYhRTthTzDj-FIP2vS_mH0nlpjgrWOp2C-h3mN6DzE,68622 -passlib/tests/test_handlers_argon2.py,sha256=bSNARahGKPZTawLq-qhVdcuvprCDTNXGWPhSh8aRyaY,22837 -passlib/tests/test_handlers_bcrypt.py,sha256=izOVd0WthIi90YKkvskrW5DZPMMCvO2qtwRkefvgkdY,29549 -passlib/tests/test_handlers_cisco.py,sha256=TLvuGQZygEZbjA01t1hfGfBvx3THnv6ZwbNQCKUhsuI,20471 -passlib/tests/test_handlers_django.py,sha256=ADphUgbG9PwoXQPFbEAPeIDfqjK6DENl_wizP52wYSE,15538 -passlib/tests/test_handlers_pbkdf2.py,sha256=vDM9ipts9EYoauheNHtOOYq0Nl8-9ltTML4gnw2EB2g,18788 -passlib/tests/test_handlers_scrypt.py,sha256=wHsbgoV5xhY4SQtgWFCuit3lygkNvd0AQKZ0lmp72do,4188 -passlib/tests/test_hosts.py,sha256=n0gCywmbsw8q8p4WLp-AlQrQuPfe-29fYwUfWwXi4Co,3906 -passlib/tests/test_pwd.py,sha256=Si9qFDXwkbjTsJ9wQTYe-QhlprVoMQ2E79-eX11FPBk,7190 -passlib/tests/test_registry.py,sha256=9BgXvMhHKQQHBGdgV4WyDDZUboUh0tbHYdgPYr1upSo,9246 -passlib/tests/test_totp.py,sha256=T1o3B97SltvC1OKweXQpX1bBGf6KYQnMl8jcpBSg5DU,65746 -passlib/tests/test_utils.py,sha256=yMWrrnsMIg8b8guyzRK8lDJ243rul6ANhrIgImGlyVI,46118 -passlib/tests/test_utils_handlers.py,sha256=rVSuaNqRUb4Q520nVD4C5smzVs-LdFqQjFZMDRTz-zU,32134 -passlib/tests/test_utils_md4.py,sha256=CfQor3ZfV2JO_8x2RxY5Tl5ZsS0hDvIje46cLvLN5Ew,1474 -passlib/tests/test_utils_pbkdf2.py,sha256=gIhycQf4NUNd5yjUrtKfRm3eqqpklS9W2B7-8INp4Cg,12193 -passlib/tests/test_win32.py,sha256=BXVpHSm71ePXmmbBPTN4H38lUgGqG6-iZasbj_l1mVg,1920 -passlib/tests/tox_support.py,sha256=PDaO1ftDtOFzd299EXm0X5HWRzg37VsBiHsdiMOu5FA,2473 -passlib/tests/utils.py,sha256=mNbhjFNG16dmU13ChMyqOSY39OiR2d8LRUBi41dAMko,147541 -passlib/totp.py,sha256=Wryr57req8NFJnw1fI_eycCaTwmSY8WA7Z3OFjAwHOE,73033 -passlib/utils/__init__.py,sha256=VHkQHu7DcdVKyDjhPuyRG_2-25aI4Zwat3wr6K-rAlo,42925 -passlib/utils/binary.py,sha256=dZe2ZjuGr0g6iQseO-ThkQ5XM6KnQFISGQr68vUOOhM,31422 -passlib/utils/compat/__init__.py,sha256=xuPP5PsmLJh_I5NrlaYa012zmWrdzfrYbL_oHqc4tCk,14235 -passlib/utils/compat/_ordered_dict.py,sha256=1nga6blaxokrrDdY3UrQgRXYdifZHCDgPYie1aCJkuI,8368 -passlib/utils/decor.py,sha256=svc2C-_DKfiCMmOBNhn_DK7IeS_WYNg26asjhx76LUA,7651 -passlib/utils/des.py,sha256=jFuvhUA3aaiR1xWX4NpXYm5XgcdewRT5Uas-7jLoSTE,2163 -passlib/utils/handlers.py,sha256=E3oRL908uudK_ZLZWeX5DoPxJL8uCfCGpmAkyfJoWQ8,105286 -passlib/utils/md4.py,sha256=pyxEpUe_t8E0u2ZDWOzYIJa0oXgTQBO7DQ8SMKGX8ag,1218 -passlib/utils/pbkdf2.py,sha256=foDGTAKeZywBAVlLZIRf4bX6fC3bzsoC1i_DtcdXr2I,6832 -passlib/win32.py,sha256=E6Ca-4Ki5ZlCSzd86N1CXjh-xQoJYjW-74-kJ6VsHUU,2591 diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/REQUESTED b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/WHEEL b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/WHEEL deleted file mode 100644 index 6d38aa0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.35.1) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/top_level.txt b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/top_level.txt deleted file mode 100644 index 419829d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -passlib diff --git a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/zip-safe b/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib-1.7.4.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/__init__.py deleted file mode 100644 index 963bfcc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""passlib - suite of password hashing & generation routines""" - -__version__ = '1.7.4' diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/bip39.txt b/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/bip39.txt deleted file mode 100644 index e29842e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/bip39.txt +++ /dev/null @@ -1,2049 +0,0 @@ -abandon -ability -able -about -above -absent -absorb -abstract -absurd -abuse -access -accident -account -accuse -achieve -acid -acoustic -acquire -across -act -action -actor -actress -actual -adapt -add -addict -address -adjust -admit -adult -advance -advice -aerobic -affair -afford -afraid -again -age -agent -agree -ahead -aim -air -airport -aisle -alarm -album -alcohol -alert -alien -all -alley -allow -almost -alone -alpha -already -also -alter -always -amateur -amazing -among -amount -amused -analyst -anchor -ancient -anger -angle -angry -animal -ankle -announce -annual -another -answer -antenna -antique -anxiety -any -apart -apology -appear -apple -approve -april -arch -arctic -area -arena -argue -arm -armed -armor -army -around -arrange -arrest -arrive -arrow -art -artefact -artist -artwork -ask -aspect -assault -asset -assist -assume -asthma -athlete -atom -attack -attend -attitude -attract -auction -audit -august -aunt -author -auto -autumn -average -avocado -avoid -awake -aware -away -awesome -awful -awkward -axis -baby -bachelor -bacon -badge -bag -balance -balcony -ball -bamboo -banana -banner -bar -barely -bargain -barrel -base -basic -basket -battle -beach -bean -beauty -because -become -beef -before -begin -behave -behind -believe -below -belt -bench -benefit -best -betray -better -between -beyond -bicycle -bid -bike -bind -biology -bird -birth -bitter -black -blade -blame -blanket -blast -bleak -bless -blind -blood -blossom -blouse -blue -blur -blush -board -boat -body -boil -bomb -bone -bonus -book -boost -border -boring -borrow -boss -bottom -bounce -box -boy -bracket -brain -brand -brass -brave -bread -breeze -brick -bridge -brief -bright -bring -brisk -broccoli -broken -bronze -broom -brother -brown -brush -bubble -buddy -budget -buffalo -build -bulb -bulk -bullet -bundle -bunker -burden -burger -burst -bus -business -busy -butter -buyer -buzz -cabbage -cabin -cable -cactus -cage -cake -call -calm -camera -camp -can -canal -cancel -candy -cannon -canoe -canvas -canyon -capable -capital -captain -car -carbon -card -cargo -carpet -carry -cart -case -cash -casino -castle -casual -cat -catalog -catch -category -cattle -caught -cause -caution -cave -ceiling -celery -cement -census -century -cereal -certain -chair -chalk -champion -change -chaos -chapter -charge -chase -chat -cheap -check -cheese -chef -cherry -chest -chicken -chief -child -chimney -choice -choose -chronic -chuckle -chunk -churn -cigar -cinnamon -circle -citizen -city -civil -claim -clap -clarify -claw -clay -clean -clerk -clever -click -client -cliff -climb -clinic -clip -clock -clog -close -cloth -cloud -clown -club -clump -cluster -clutch -coach -coast -coconut -code -coffee -coil -coin -collect -color -column -combine -come -comfort -comic -common -company -concert -conduct -confirm -congress -connect -consider -control -convince -cook -cool -copper -copy -coral -core -corn -correct -cost -cotton -couch -country -couple -course -cousin -cover -coyote -crack -cradle -craft -cram -crane -crash -crater -crawl -crazy -cream -credit -creek -crew -cricket -crime -crisp -critic -crop -cross -crouch -crowd -crucial -cruel -cruise -crumble -crunch -crush -cry -crystal -cube -culture -cup -cupboard -curious -current -curtain -curve -cushion -custom -cute -cycle -dad -damage -damp -dance -danger -daring -dash -daughter -dawn -day -deal -debate -debris -decade -december -decide -decline -decorate -decrease -deer -defense -define -defy -degree -delay -deliver -demand -demise -denial -dentist -deny -depart -depend -deposit -depth -deputy -derive -describe -desert -design -desk -despair -destroy -detail -detect -develop -device -devote -diagram -dial -diamond -diary -dice -diesel -diet -differ -digital -dignity -dilemma -dinner -dinosaur -direct -dirt -disagree -discover -disease -dish -dismiss -disorder -display -distance -divert -divide -divorce -dizzy -doctor -document -dog -doll -dolphin -domain -donate -donkey -donor -door -dose -double -dove -draft -dragon -drama -drastic -draw -dream -dress -drift -drill -drink -drip -drive -drop -drum -dry -duck -dumb -dune -during -dust -dutch -duty -dwarf -dynamic -eager -eagle -early -earn -earth -easily -east -easy -echo -ecology -economy -edge -edit -educate -effort -egg -eight -either -elbow -elder -electric -elegant -element -elephant -elevator -elite -else -embark -embody -embrace -emerge -emotion -employ -empower -empty -enable -enact -end -endless -endorse -enemy -energy -enforce -engage -engine -enhance -enjoy -enlist -enough -enrich -enroll -ensure -enter -entire -entry -envelope -episode -equal -equip -era -erase -erode -erosion -error -erupt -escape -essay -essence -estate -eternal -ethics -evidence -evil -evoke -evolve -exact -example -excess -exchange -excite -exclude -excuse -execute -exercise -exhaust -exhibit -exile -exist -exit -exotic -expand -expect -expire -explain -expose -express -extend -extra -eye -eyebrow -fabric -face -faculty -fade -faint -faith -fall -false -fame -family -famous -fan -fancy -fantasy -farm -fashion -fat -fatal -father -fatigue -fault -favorite -feature -february -federal -fee -feed -feel -female -fence -festival -fetch -fever -few -fiber -fiction -field -figure -file -film -filter -final -find -fine -finger -finish -fire -firm -first -fiscal -fish -fit -fitness -fix -flag -flame -flash -flat -flavor -flee -flight -flip -float -flock -floor -flower -fluid -flush -fly -foam -focus -fog -foil -fold -follow -food -foot -force -forest -forget -fork -fortune -forum -forward -fossil -foster -found -fox -fragile -frame -frequent -fresh -friend -fringe -frog -front -frost -frown -frozen -fruit -fuel -fun -funny -furnace -fury -future -gadget -gain -galaxy -gallery -game -gap -garage -garbage -garden -garlic -garment -gas -gasp -gate -gather -gauge -gaze -general -genius -genre -gentle -genuine -gesture -ghost -giant -gift -giggle -ginger -giraffe -girl -give -glad -glance -glare -glass -glide -glimpse -globe -gloom -glory -glove -glow -glue -goat -goddess -gold -good -goose -gorilla -gospel -gossip -govern -gown -grab -grace -grain -grant -grape -grass -gravity -great -green -grid -grief -grit -grocery -group -grow -grunt -guard -guess -guide -guilt -guitar -gun -gym -habit -hair -half -hammer -hamster -hand -happy -harbor -hard -harsh -harvest -hat -have -hawk -hazard -head -health -heart -heavy -hedgehog -height -hello -helmet -help -hen -hero -hidden -high -hill -hint -hip -hire -history -hobby -hockey -hold -hole -holiday -hollow -home -honey -hood -hope -horn -horror -horse -hospital -host -hotel -hour -hover -hub -huge -human -humble -humor -hundred -hungry -hunt -hurdle -hurry -hurt -husband -hybrid -ice -icon -idea -identify -idle -ignore -ill -illegal -illness -image -imitate -immense -immune -impact -impose -improve -impulse -inch -include -income -increase -index -indicate -indoor -industry -infant -inflict -inform -inhale -inherit -initial -inject -injury -inmate -inner -innocent -input -inquiry -insane -insect -inside -inspire -install -intact -interest -into -invest -invite -involve -iron -island -isolate -issue -item -ivory -jacket -jaguar -jar -jazz -jealous -jeans -jelly -jewel -job -join -joke -journey -joy -judge -juice -jump -jungle -junior -junk -just -kangaroo -keen -keep -ketchup -key -kick -kid -kidney -kind -kingdom -kiss -kit -kitchen -kite -kitten -kiwi -knee -knife -knock -know -lab -label -labor -ladder -lady -lake -lamp -language -laptop -large -later -latin -laugh -laundry -lava -law -lawn -lawsuit -layer -lazy -leader -leaf -learn -leave -lecture -left -leg -legal -legend -leisure -lemon -lend -length -lens -leopard -lesson -letter -level -liar -liberty -library -license -life -lift -light -like -limb -limit -link -lion -liquid -list -little -live -lizard -load -loan -lobster -local -lock -logic -lonely -long -loop -lottery -loud -lounge -love -loyal -lucky -luggage -lumber -lunar -lunch -luxury -lyrics -machine -mad -magic -magnet -maid -mail -main -major -make -mammal -man -manage -mandate -mango -mansion -manual -maple -marble -march -margin -marine -market -marriage -mask -mass -master -match -material -math -matrix -matter -maximum -maze -meadow -mean -measure -meat -mechanic -medal -media -melody -melt -member -memory -mention -menu -mercy -merge -merit -merry -mesh -message -metal -method -middle -midnight -milk -million -mimic -mind -minimum -minor -minute -miracle -mirror -misery -miss -mistake -mix -mixed -mixture -mobile -model -modify -mom -moment -monitor -monkey -monster -month -moon -moral -more -morning -mosquito -mother -motion -motor -mountain -mouse -move -movie -much -muffin -mule -multiply -muscle -museum -mushroom -music -must -mutual -myself -mystery -myth -naive -name -napkin -narrow -nasty -nation -nature -near -neck -need -negative -neglect -neither -nephew -nerve -nest -net -network -neutral -never -news -next -nice -night -noble -noise -nominee -noodle -normal -north -nose -notable -note -nothing -notice -novel -now -nuclear -number -nurse -nut -oak -obey -object -oblige -obscure -observe -obtain -obvious -occur -ocean -october -odor -off -offer -office -often -oil -okay -old -olive -olympic -omit -once -one -onion -online -only -open -opera -opinion -oppose -option -orange -orbit -orchard -order -ordinary -organ -orient -original -orphan -ostrich -other -outdoor -outer -output -outside -oval -oven -over -own -owner -oxygen -oyster -ozone -pact -paddle -page -pair -palace -palm -panda -panel -panic -panther -paper -parade -parent -park -parrot -party -pass -patch -path -patient -patrol -pattern -pause -pave -payment -peace -peanut -pear -peasant -pelican -pen -penalty -pencil -people -pepper -perfect -permit -person -pet -phone -photo -phrase -physical -piano -picnic -picture -piece -pig -pigeon -pill -pilot -pink -pioneer -pipe -pistol -pitch -pizza -place -planet -plastic -plate -play -please -pledge -pluck -plug -plunge -poem -poet -point -polar -pole -police -pond -pony -pool -popular -portion -position -possible -post -potato -pottery -poverty -powder -power -practice -praise -predict -prefer -prepare -present -pretty -prevent -price -pride -primary -print -priority -prison -private -prize -problem -process -produce -profit -program -project -promote -proof -property -prosper -protect -proud -provide -public -pudding -pull -pulp -pulse -pumpkin -punch -pupil -puppy -purchase -purity -purpose -purse -push -put -puzzle -pyramid -quality -quantum -quarter -question -quick -quit -quiz -quote -rabbit -raccoon -race -rack -radar -radio -rail -rain -raise -rally -ramp -ranch -random -range -rapid -rare -rate -rather -raven -raw -razor -ready -real -reason -rebel -rebuild -recall -receive -recipe -record -recycle -reduce -reflect -reform -refuse -region -regret -regular -reject -relax -release -relief -rely -remain -remember -remind -remove -render -renew -rent -reopen -repair -repeat -replace -report -require -rescue -resemble -resist -resource -response -result -retire -retreat -return -reunion -reveal -review -reward -rhythm -rib -ribbon -rice -rich -ride -ridge -rifle -right -rigid -ring -riot -ripple -risk -ritual -rival -river -road -roast -robot -robust -rocket -romance -roof -rookie -room -rose -rotate -rough -round -route -royal -rubber -rude -rug -rule -run -runway -rural -sad -saddle -sadness -safe -sail -salad -salmon -salon -salt -salute -same -sample -sand -satisfy -satoshi -sauce -sausage -save -say -scale -scan -scare -scatter -scene -scheme -school -science -scissors -scorpion -scout -scrap -screen -script -scrub -sea -search -season -seat -second -secret -section -security -seed -seek -segment -select -sell -seminar -senior -sense -sentence -series -service -session -settle -setup -seven -shadow -shaft -shallow -share -shed -shell -sheriff -shield -shift -shine -ship -shiver -shock -shoe -shoot -shop -short -shoulder -shove -shrimp -shrug -shuffle -shy -sibling -sick -side -siege -sight -sign -silent -silk -silly -silver -similar -simple -since -sing -siren -sister -situate -six -size -skate -sketch -ski -skill -skin -skirt -skull -slab -slam -sleep -slender -slice -slide -slight -slim -slogan -slot -slow -slush -small -smart -smile -smoke -smooth -snack -snake -snap -sniff -snow -soap -soccer -social -sock -soda -soft -solar -soldier -solid -solution -solve -someone -song -soon -sorry -sort -soul -sound -soup -source -south -space -spare -spatial -spawn -speak -special -speed -spell -spend -sphere -spice -spider -spike -spin -spirit -split -spoil -sponsor -spoon -sport -spot -spray -spread -spring -spy -square -squeeze -squirrel -stable -stadium -staff -stage -stairs -stamp -stand -start -state -stay -steak -steel -stem -step -stereo -stick -still -sting -stock -stomach -stone -stool -story -stove -strategy -street -strike -strong -struggle -student -stuff -stumble -style -subject -submit -subway -success -such -sudden -suffer -sugar -suggest -suit -summer -sun -sunny -sunset -super -supply -supreme -sure -surface -surge -surprise -surround -survey -suspect -sustain -swallow -swamp -swap -swarm -swear -sweet -swift -swim -swing -switch -sword -symbol -symptom -syrup -system -table -tackle -tag -tail -talent -talk -tank -tape -target -task -taste -tattoo -taxi -teach -team -tell -ten -tenant -tennis -tent -term -test -text -thank -that -theme -then -theory -there -they -thing -this -thought -three -thrive -throw -thumb -thunder -ticket -tide -tiger -tilt -timber -time -tiny -tip -tired -tissue -title -toast -tobacco -today -toddler -toe -together -toilet -token -tomato -tomorrow -tone -tongue -tonight -tool -tooth -top -topic -topple -torch -tornado -tortoise -toss -total -tourist -toward -tower -town -toy -track -trade -traffic -tragic -train -transfer -trap -trash -travel -tray -treat -tree -trend -trial -tribe -trick -trigger -trim -trip -trophy -trouble -truck -true -truly -trumpet -trust -truth -try -tube -tuition -tumble -tuna -tunnel -turkey -turn -turtle -twelve -twenty -twice -twin -twist -two -type -typical -ugly -umbrella -unable -unaware -uncle -uncover -under -undo -unfair -unfold -unhappy -uniform -unique -unit -universe -unknown -unlock -until -unusual -unveil -update -upgrade -uphold -upon -upper -upset -urban -urge -usage -use -used -useful -useless -usual -utility -vacant -vacuum -vague -valid -valley -valve -van -vanish -vapor -various -vast -vault -vehicle -velvet -vendor -venture -venue -verb -verify -version -very -vessel -veteran -viable -vibrant -vicious -victory -video -view -village -vintage -violin -virtual -virus -visa -visit -visual -vital -vivid -vocal -voice -void -volcano -volume -vote -voyage -wage -wagon -wait -walk -wall -walnut -want -warfare -warm -warrior -wash -wasp -waste -water -wave -way -wealth -weapon -wear -weasel -weather -web -wedding -weekend -weird -welcome -west -wet -whale -what -wheat -wheel -when -where -whip -whisper -wide -width -wife -wild -will -win -window -wine -wing -wink -winner -winter -wire -wisdom -wise -wish -witness -wolf -woman -wonder -wood -wool -word -work -world -worry -worth -wrap -wreck -wrestle -wrist -write -wrong -yard -year -yellow -you -young -youth -zebra -zero -zone -zoo - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_long.txt b/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_long.txt deleted file mode 100644 index caf71f5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_long.txt +++ /dev/null @@ -1,7776 +0,0 @@ -abacus -abdomen -abdominal -abide -abiding -ability -ablaze -able -abnormal -abrasion -abrasive -abreast -abridge -abroad -abruptly -absence -absentee -absently -absinthe -absolute -absolve -abstain -abstract -absurd -accent -acclaim -acclimate -accompany -account -accuracy -accurate -accustom -acetone -achiness -aching -acid -acorn -acquaint -acquire -acre -acrobat -acronym -acting -action -activate -activator -active -activism -activist -activity -actress -acts -acutely -acuteness -aeration -aerobics -aerosol -aerospace -afar -affair -affected -affecting -affection -affidavit -affiliate -affirm -affix -afflicted -affluent -afford -affront -aflame -afloat -aflutter -afoot -afraid -afterglow -afterlife -aftermath -aftermost -afternoon -aged -ageless -agency -agenda -agent -aggregate -aghast -agile -agility -aging -agnostic -agonize -agonizing -agony -agreeable -agreeably -agreed -agreeing -agreement -aground -ahead -ahoy -aide -aids -aim -ajar -alabaster -alarm -albatross -album -alfalfa -algebra -algorithm -alias -alibi -alienable -alienate -aliens -alike -alive -alkaline -alkalize -almanac -almighty -almost -aloe -aloft -aloha -alone -alongside -aloof -alphabet -alright -although -altitude -alto -aluminum -alumni -always -amaretto -amaze -amazingly -amber -ambiance -ambiguity -ambiguous -ambition -ambitious -ambulance -ambush -amendable -amendment -amends -amenity -amiable -amicably -amid -amigo -amino -amiss -ammonia -ammonium -amnesty -amniotic -among -amount -amperage -ample -amplifier -amplify -amply -amuck -amulet -amusable -amused -amusement -amuser -amusing -anaconda -anaerobic -anagram -anatomist -anatomy -anchor -anchovy -ancient -android -anemia -anemic -aneurism -anew -angelfish -angelic -anger -angled -angler -angles -angling -angrily -angriness -anguished -angular -animal -animate -animating -animation -animator -anime -animosity -ankle -annex -annotate -announcer -annoying -annually -annuity -anointer -another -answering -antacid -antarctic -anteater -antelope -antennae -anthem -anthill -anthology -antibody -antics -antidote -antihero -antiquely -antiques -antiquity -antirust -antitoxic -antitrust -antiviral -antivirus -antler -antonym -antsy -anvil -anybody -anyhow -anymore -anyone -anyplace -anything -anytime -anyway -anywhere -aorta -apache -apostle -appealing -appear -appease -appeasing -appendage -appendix -appetite -appetizer -applaud -applause -apple -appliance -applicant -applied -apply -appointee -appraisal -appraiser -apprehend -approach -approval -approve -apricot -april -apron -aptitude -aptly -aqua -aqueduct -arbitrary -arbitrate -ardently -area -arena -arguable -arguably -argue -arise -armadillo -armband -armchair -armed -armful -armhole -arming -armless -armoire -armored -armory -armrest -army -aroma -arose -around -arousal -arrange -array -arrest -arrival -arrive -arrogance -arrogant -arson -art -ascend -ascension -ascent -ascertain -ashamed -ashen -ashes -ashy -aside -askew -asleep -asparagus -aspect -aspirate -aspire -aspirin -astonish -astound -astride -astrology -astronaut -astronomy -astute -atlantic -atlas -atom -atonable -atop -atrium -atrocious -atrophy -attach -attain -attempt -attendant -attendee -attention -attentive -attest -attic -attire -attitude -attractor -attribute -atypical -auction -audacious -audacity -audible -audibly -audience -audio -audition -augmented -august -authentic -author -autism -autistic -autograph -automaker -automated -automatic -autopilot -available -avalanche -avatar -avenge -avenging -avenue -average -aversion -avert -aviation -aviator -avid -avoid -await -awaken -award -aware -awhile -awkward -awning -awoke -awry -axis -babble -babbling -babied -baboon -backache -backboard -backboned -backdrop -backed -backer -backfield -backfire -backhand -backing -backlands -backlash -backless -backlight -backlit -backlog -backpack -backpedal -backrest -backroom -backshift -backside -backslid -backspace -backspin -backstab -backstage -backtalk -backtrack -backup -backward -backwash -backwater -backyard -bacon -bacteria -bacterium -badass -badge -badland -badly -badness -baffle -baffling -bagel -bagful -baggage -bagged -baggie -bagginess -bagging -baggy -bagpipe -baguette -baked -bakery -bakeshop -baking -balance -balancing -balcony -balmy -balsamic -bamboo -banana -banish -banister -banjo -bankable -bankbook -banked -banker -banking -banknote -bankroll -banner -bannister -banshee -banter -barbecue -barbed -barbell -barber -barcode -barge -bargraph -barista -baritone -barley -barmaid -barman -barn -barometer -barrack -barracuda -barrel -barrette -barricade -barrier -barstool -bartender -barterer -bash -basically -basics -basil -basin -basis -basket -batboy -batch -bath -baton -bats -battalion -battered -battering -battery -batting -battle -bauble -bazooka -blabber -bladder -blade -blah -blame -blaming -blanching -blandness -blank -blaspheme -blasphemy -blast -blatancy -blatantly -blazer -blazing -bleach -bleak -bleep -blemish -blend -bless -blighted -blimp -bling -blinked -blinker -blinking -blinks -blip -blissful -blitz -blizzard -bloated -bloating -blob -blog -bloomers -blooming -blooper -blot -blouse -blubber -bluff -bluish -blunderer -blunt -blurb -blurred -blurry -blurt -blush -blustery -boaster -boastful -boasting -boat -bobbed -bobbing -bobble -bobcat -bobsled -bobtail -bodacious -body -bogged -boggle -bogus -boil -bok -bolster -bolt -bonanza -bonded -bonding -bondless -boned -bonehead -boneless -bonelike -boney -bonfire -bonnet -bonsai -bonus -bony -boogeyman -boogieman -book -boondocks -booted -booth -bootie -booting -bootlace -bootleg -boots -boozy -borax -boring -borough -borrower -borrowing -boss -botanical -botanist -botany -botch -both -bottle -bottling -bottom -bounce -bouncing -bouncy -bounding -boundless -bountiful -bovine -boxcar -boxer -boxing -boxlike -boxy -breach -breath -breeches -breeching -breeder -breeding -breeze -breezy -brethren -brewery -brewing -briar -bribe -brick -bride -bridged -brigade -bright -brilliant -brim -bring -brink -brisket -briskly -briskness -bristle -brittle -broadband -broadcast -broaden -broadly -broadness -broadside -broadways -broiler -broiling -broken -broker -bronchial -bronco -bronze -bronzing -brook -broom -brought -browbeat -brownnose -browse -browsing -bruising -brunch -brunette -brunt -brush -brussels -brute -brutishly -bubble -bubbling -bubbly -buccaneer -bucked -bucket -buckle -buckshot -buckskin -bucktooth -buckwheat -buddhism -buddhist -budding -buddy -budget -buffalo -buffed -buffer -buffing -buffoon -buggy -bulb -bulge -bulginess -bulgur -bulk -bulldog -bulldozer -bullfight -bullfrog -bullhorn -bullion -bullish -bullpen -bullring -bullseye -bullwhip -bully -bunch -bundle -bungee -bunion -bunkbed -bunkhouse -bunkmate -bunny -bunt -busboy -bush -busily -busload -bust -busybody -buzz -cabana -cabbage -cabbie -cabdriver -cable -caboose -cache -cackle -cacti -cactus -caddie -caddy -cadet -cadillac -cadmium -cage -cahoots -cake -calamari -calamity -calcium -calculate -calculus -caliber -calibrate -calm -caloric -calorie -calzone -camcorder -cameo -camera -camisole -camper -campfire -camping -campsite -campus -canal -canary -cancel -candied -candle -candy -cane -canine -canister -cannabis -canned -canning -cannon -cannot -canola -canon -canopener -canopy -canteen -canyon -capable -capably -capacity -cape -capillary -capital -capitol -capped -capricorn -capsize -capsule -caption -captivate -captive -captivity -capture -caramel -carat -caravan -carbon -cardboard -carded -cardiac -cardigan -cardinal -cardstock -carefully -caregiver -careless -caress -caretaker -cargo -caring -carless -carload -carmaker -carnage -carnation -carnival -carnivore -carol -carpenter -carpentry -carpool -carport -carried -carrot -carrousel -carry -cartel -cartload -carton -cartoon -cartridge -cartwheel -carve -carving -carwash -cascade -case -cash -casing -casino -casket -cassette -casually -casualty -catacomb -catalog -catalyst -catalyze -catapult -cataract -catatonic -catcall -catchable -catcher -catching -catchy -caterer -catering -catfight -catfish -cathedral -cathouse -catlike -catnap -catnip -catsup -cattail -cattishly -cattle -catty -catwalk -caucasian -caucus -causal -causation -cause -causing -cauterize -caution -cautious -cavalier -cavalry -caviar -cavity -cedar -celery -celestial -celibacy -celibate -celtic -cement -census -ceramics -ceremony -certainly -certainty -certified -certify -cesarean -cesspool -chafe -chaffing -chain -chair -chalice -challenge -chamber -chamomile -champion -chance -change -channel -chant -chaos -chaperone -chaplain -chapped -chaps -chapter -character -charbroil -charcoal -charger -charging -chariot -charity -charm -charred -charter -charting -chase -chasing -chaste -chastise -chastity -chatroom -chatter -chatting -chatty -cheating -cheddar -cheek -cheer -cheese -cheesy -chef -chemicals -chemist -chemo -cherisher -cherub -chess -chest -chevron -chevy -chewable -chewer -chewing -chewy -chief -chihuahua -childcare -childhood -childish -childless -childlike -chili -chill -chimp -chip -chirping -chirpy -chitchat -chivalry -chive -chloride -chlorine -choice -chokehold -choking -chomp -chooser -choosing -choosy -chop -chosen -chowder -chowtime -chrome -chubby -chuck -chug -chummy -chump -chunk -churn -chute -cider -cilantro -cinch -cinema -cinnamon -circle -circling -circular -circulate -circus -citable -citadel -citation -citizen -citric -citrus -city -civic -civil -clad -claim -clambake -clammy -clamor -clamp -clamshell -clang -clanking -clapped -clapper -clapping -clarify -clarinet -clarity -clash -clasp -class -clatter -clause -clavicle -claw -clay -clean -clear -cleat -cleaver -cleft -clench -clergyman -clerical -clerk -clever -clicker -client -climate -climatic -cling -clinic -clinking -clip -clique -cloak -clobber -clock -clone -cloning -closable -closure -clothes -clothing -cloud -clover -clubbed -clubbing -clubhouse -clump -clumsily -clumsy -clunky -clustered -clutch -clutter -coach -coagulant -coastal -coaster -coasting -coastland -coastline -coat -coauthor -cobalt -cobbler -cobweb -cocoa -coconut -cod -coeditor -coerce -coexist -coffee -cofounder -cognition -cognitive -cogwheel -coherence -coherent -cohesive -coil -coke -cola -cold -coleslaw -coliseum -collage -collapse -collar -collected -collector -collide -collie -collision -colonial -colonist -colonize -colony -colossal -colt -coma -come -comfort -comfy -comic -coming -comma -commence -commend -comment -commerce -commode -commodity -commodore -common -commotion -commute -commuting -compacted -compacter -compactly -compactor -companion -company -compare -compel -compile -comply -component -composed -composer -composite -compost -composure -compound -compress -comprised -computer -computing -comrade -concave -conceal -conceded -concept -concerned -concert -conch -concierge -concise -conclude -concrete -concur -condense -condiment -condition -condone -conducive -conductor -conduit -cone -confess -confetti -confidant -confident -confider -confiding -configure -confined -confining -confirm -conflict -conform -confound -confront -confused -confusing -confusion -congenial -congested -congrats -congress -conical -conjoined -conjure -conjuror -connected -connector -consensus -consent -console -consoling -consonant -constable -constant -constrain -constrict -construct -consult -consumer -consuming -contact -container -contempt -contend -contented -contently -contents -contest -context -contort -contour -contrite -control -contusion -convene -convent -copartner -cope -copied -copier -copilot -coping -copious -copper -copy -coral -cork -cornball -cornbread -corncob -cornea -corned -corner -cornfield -cornflake -cornhusk -cornmeal -cornstalk -corny -coronary -coroner -corporal -corporate -corral -correct -corridor -corrode -corroding -corrosive -corsage -corset -cortex -cosigner -cosmetics -cosmic -cosmos -cosponsor -cost -cottage -cotton -couch -cough -could -countable -countdown -counting -countless -country -county -courier -covenant -cover -coveted -coveting -coyness -cozily -coziness -cozy -crabbing -crabgrass -crablike -crabmeat -cradle -cradling -crafter -craftily -craftsman -craftwork -crafty -cramp -cranberry -crane -cranial -cranium -crank -crate -crave -craving -crawfish -crawlers -crawling -crayfish -crayon -crazed -crazily -craziness -crazy -creamed -creamer -creamlike -crease -creasing -creatable -create -creation -creative -creature -credible -credibly -credit -creed -creme -creole -crepe -crept -crescent -crested -cresting -crestless -crevice -crewless -crewman -crewmate -crib -cricket -cried -crier -crimp -crimson -cringe -cringing -crinkle -crinkly -crisped -crisping -crisply -crispness -crispy -criteria -critter -croak -crock -crook -croon -crop -cross -crouch -crouton -crowbar -crowd -crown -crucial -crudely -crudeness -cruelly -cruelness -cruelty -crumb -crummiest -crummy -crumpet -crumpled -cruncher -crunching -crunchy -crusader -crushable -crushed -crusher -crushing -crust -crux -crying -cryptic -crystal -cubbyhole -cube -cubical -cubicle -cucumber -cuddle -cuddly -cufflink -culinary -culminate -culpable -culprit -cultivate -cultural -culture -cupbearer -cupcake -cupid -cupped -cupping -curable -curator -curdle -cure -curfew -curing -curled -curler -curliness -curling -curly -curry -curse -cursive -cursor -curtain -curtly -curtsy -curvature -curve -curvy -cushy -cusp -cussed -custard -custodian -custody -customary -customer -customize -customs -cut -cycle -cyclic -cycling -cyclist -cylinder -cymbal -cytoplasm -cytoplast -dab -dad -daffodil -dagger -daily -daintily -dainty -dairy -daisy -dallying -dance -dancing -dandelion -dander -dandruff -dandy -danger -dangle -dangling -daredevil -dares -daringly -darkened -darkening -darkish -darkness -darkroom -darling -darn -dart -darwinism -dash -dastardly -data -datebook -dating -daughter -daunting -dawdler -dawn -daybed -daybreak -daycare -daydream -daylight -daylong -dayroom -daytime -dazzler -dazzling -deacon -deafening -deafness -dealer -dealing -dealmaker -dealt -dean -debatable -debate -debating -debit -debrief -debtless -debtor -debug -debunk -decade -decaf -decal -decathlon -decay -deceased -deceit -deceiver -deceiving -december -decency -decent -deception -deceptive -decibel -decidable -decimal -decimeter -decipher -deck -declared -decline -decode -decompose -decorated -decorator -decoy -decrease -decree -dedicate -dedicator -deduce -deduct -deed -deem -deepen -deeply -deepness -deface -defacing -defame -default -defeat -defection -defective -defendant -defender -defense -defensive -deferral -deferred -defiance -defiant -defile -defiling -define -definite -deflate -deflation -deflator -deflected -deflector -defog -deforest -defraud -defrost -deftly -defuse -defy -degraded -degrading -degrease -degree -dehydrate -deity -dejected -delay -delegate -delegator -delete -deletion -delicacy -delicate -delicious -delighted -delirious -delirium -deliverer -delivery -delouse -delta -deluge -delusion -deluxe -demanding -demeaning -demeanor -demise -democracy -democrat -demote -demotion -demystify -denatured -deniable -denial -denim -denote -dense -density -dental -dentist -denture -deny -deodorant -deodorize -departed -departure -depict -deplete -depletion -deplored -deploy -deport -depose -depraved -depravity -deprecate -depress -deprive -depth -deputize -deputy -derail -deranged -derby -derived -desecrate -deserve -deserving -designate -designed -designer -designing -deskbound -desktop -deskwork -desolate -despair -despise -despite -destiny -destitute -destruct -detached -detail -detection -detective -detector -detention -detergent -detest -detonate -detonator -detoxify -detract -deuce -devalue -deviancy -deviant -deviate -deviation -deviator -device -devious -devotedly -devotee -devotion -devourer -devouring -devoutly -dexterity -dexterous -diabetes -diabetic -diabolic -diagnoses -diagnosis -diagram -dial -diameter -diaper -diaphragm -diary -dice -dicing -dictate -dictation -dictator -difficult -diffused -diffuser -diffusion -diffusive -dig -dilation -diligence -diligent -dill -dilute -dime -diminish -dimly -dimmed -dimmer -dimness -dimple -diner -dingbat -dinghy -dinginess -dingo -dingy -dining -dinner -diocese -dioxide -diploma -dipped -dipper -dipping -directed -direction -directive -directly -directory -direness -dirtiness -disabled -disagree -disallow -disarm -disarray -disaster -disband -disbelief -disburse -discard -discern -discharge -disclose -discolor -discount -discourse -discover -discuss -disdain -disengage -disfigure -disgrace -dish -disinfect -disjoin -disk -dislike -disliking -dislocate -dislodge -disloyal -dismantle -dismay -dismiss -dismount -disobey -disorder -disown -disparate -disparity -dispatch -dispense -dispersal -dispersed -disperser -displace -display -displease -disposal -dispose -disprove -dispute -disregard -disrupt -dissuade -distance -distant -distaste -distill -distinct -distort -distract -distress -district -distrust -ditch -ditto -ditzy -dividable -divided -dividend -dividers -dividing -divinely -diving -divinity -divisible -divisibly -division -divisive -divorcee -dizziness -dizzy -doable -docile -dock -doctrine -document -dodge -dodgy -doily -doing -dole -dollar -dollhouse -dollop -dolly -dolphin -domain -domelike -domestic -dominion -dominoes -donated -donation -donator -donor -donut -doodle -doorbell -doorframe -doorknob -doorman -doormat -doornail -doorpost -doorstep -doorstop -doorway -doozy -dork -dormitory -dorsal -dosage -dose -dotted -doubling -douche -dove -down -dowry -doze -drab -dragging -dragonfly -dragonish -dragster -drainable -drainage -drained -drainer -drainpipe -dramatic -dramatize -drank -drapery -drastic -draw -dreaded -dreadful -dreadlock -dreamboat -dreamily -dreamland -dreamless -dreamlike -dreamt -dreamy -drearily -dreary -drench -dress -drew -dribble -dried -drier -drift -driller -drilling -drinkable -drinking -dripping -drippy -drivable -driven -driver -driveway -driving -drizzle -drizzly -drone -drool -droop -drop-down -dropbox -dropkick -droplet -dropout -dropper -drove -drown -drowsily -drudge -drum -dry -dubbed -dubiously -duchess -duckbill -ducking -duckling -ducktail -ducky -duct -dude -duffel -dugout -duh -duke -duller -dullness -duly -dumping -dumpling -dumpster -duo -dupe -duplex -duplicate -duplicity -durable -durably -duration -duress -during -dusk -dust -dutiful -duty -duvet -dwarf -dweeb -dwelled -dweller -dwelling -dwindle -dwindling -dynamic -dynamite -dynasty -dyslexia -dyslexic -each -eagle -earache -eardrum -earflap -earful -earlobe -early -earmark -earmuff -earphone -earpiece -earplugs -earring -earshot -earthen -earthlike -earthling -earthly -earthworm -earthy -earwig -easeful -easel -easiest -easily -easiness -easing -eastbound -eastcoast -easter -eastward -eatable -eaten -eatery -eating -eats -ebay -ebony -ebook -ecard -eccentric -echo -eclair -eclipse -ecologist -ecology -economic -economist -economy -ecosphere -ecosystem -edge -edginess -edging -edgy -edition -editor -educated -education -educator -eel -effective -effects -efficient -effort -eggbeater -egging -eggnog -eggplant -eggshell -egomaniac -egotism -egotistic -either -eject -elaborate -elastic -elated -elbow -eldercare -elderly -eldest -electable -election -elective -elephant -elevate -elevating -elevation -elevator -eleven -elf -eligible -eligibly -eliminate -elite -elitism -elixir -elk -ellipse -elliptic -elm -elongated -elope -eloquence -eloquent -elsewhere -elude -elusive -elves -email -embargo -embark -embassy -embattled -embellish -ember -embezzle -emblaze -emblem -embody -embolism -emboss -embroider -emcee -emerald -emergency -emission -emit -emote -emoticon -emotion -empathic -empathy -emperor -emphases -emphasis -emphasize -emphatic -empirical -employed -employee -employer -emporium -empower -emptier -emptiness -empty -emu -enable -enactment -enamel -enchanted -enchilada -encircle -enclose -enclosure -encode -encore -encounter -encourage -encroach -encrust -encrypt -endanger -endeared -endearing -ended -ending -endless -endnote -endocrine -endorphin -endorse -endowment -endpoint -endurable -endurance -enduring -energetic -energize -energy -enforced -enforcer -engaged -engaging -engine -engorge -engraved -engraver -engraving -engross -engulf -enhance -enigmatic -enjoyable -enjoyably -enjoyer -enjoying -enjoyment -enlarged -enlarging -enlighten -enlisted -enquirer -enrage -enrich -enroll -enslave -ensnare -ensure -entail -entangled -entering -entertain -enticing -entire -entitle -entity -entomb -entourage -entrap -entree -entrench -entrust -entryway -entwine -enunciate -envelope -enviable -enviably -envious -envision -envoy -envy -enzyme -epic -epidemic -epidermal -epidermis -epidural -epilepsy -epileptic -epilogue -epiphany -episode -equal -equate -equation -equator -equinox -equipment -equity -equivocal -eradicate -erasable -erased -eraser -erasure -ergonomic -errand -errant -erratic -error -erupt -escalate -escalator -escapable -escapade -escapist -escargot -eskimo -esophagus -espionage -espresso -esquire -essay -essence -essential -establish -estate -esteemed -estimate -estimator -estranged -estrogen -etching -eternal -eternity -ethanol -ether -ethically -ethics -euphemism -evacuate -evacuee -evade -evaluate -evaluator -evaporate -evasion -evasive -even -everglade -evergreen -everybody -everyday -everyone -evict -evidence -evident -evil -evoke -evolution -evolve -exact -exalted -example -excavate -excavator -exceeding -exception -excess -exchange -excitable -exciting -exclaim -exclude -excluding -exclusion -exclusive -excretion -excretory -excursion -excusable -excusably -excuse -exemplary -exemplify -exemption -exerciser -exert -exes -exfoliate -exhale -exhaust -exhume -exile -existing -exit -exodus -exonerate -exorcism -exorcist -expand -expanse -expansion -expansive -expectant -expedited -expediter -expel -expend -expenses -expensive -expert -expire -expiring -explain -expletive -explicit -explode -exploit -explore -exploring -exponent -exporter -exposable -expose -exposure -express -expulsion -exquisite -extended -extending -extent -extenuate -exterior -external -extinct -extortion -extradite -extras -extrovert -extrude -extruding -exuberant -fable -fabric -fabulous -facebook -facecloth -facedown -faceless -facelift -faceplate -faceted -facial -facility -facing -facsimile -faction -factoid -factor -factsheet -factual -faculty -fade -fading -failing -falcon -fall -false -falsify -fame -familiar -family -famine -famished -fanatic -fancied -fanciness -fancy -fanfare -fang -fanning -fantasize -fantastic -fantasy -fascism -fastball -faster -fasting -fastness -faucet -favorable -favorably -favored -favoring -favorite -fax -feast -federal -fedora -feeble -feed -feel -feisty -feline -felt-tip -feminine -feminism -feminist -feminize -femur -fence -fencing -fender -ferment -fernlike -ferocious -ferocity -ferret -ferris -ferry -fervor -fester -festival -festive -festivity -fetal -fetch -fever -fiber -fiction -fiddle -fiddling -fidelity -fidgeting -fidgety -fifteen -fifth -fiftieth -fifty -figment -figure -figurine -filing -filled -filler -filling -film -filter -filth -filtrate -finale -finalist -finalize -finally -finance -financial -finch -fineness -finer -finicky -finished -finisher -finishing -finite -finless -finlike -fiscally -fit -five -flaccid -flagman -flagpole -flagship -flagstick -flagstone -flail -flakily -flaky -flame -flammable -flanked -flanking -flannels -flap -flaring -flashback -flashbulb -flashcard -flashily -flashing -flashy -flask -flatbed -flatfoot -flatly -flatness -flatten -flattered -flatterer -flattery -flattop -flatware -flatworm -flavored -flavorful -flavoring -flaxseed -fled -fleshed -fleshy -flick -flier -flight -flinch -fling -flint -flip -flirt -float -flock -flogging -flop -floral -florist -floss -flounder -flyable -flyaway -flyer -flying -flyover -flypaper -foam -foe -fog -foil -folic -folk -follicle -follow -fondling -fondly -fondness -fondue -font -food -fool -footage -football -footbath -footboard -footer -footgear -foothill -foothold -footing -footless -footman -footnote -footpad -footpath -footprint -footrest -footsie -footsore -footwear -footwork -fossil -foster -founder -founding -fountain -fox -foyer -fraction -fracture -fragile -fragility -fragment -fragrance -fragrant -frail -frame -framing -frantic -fraternal -frayed -fraying -frays -freckled -freckles -freebase -freebee -freebie -freedom -freefall -freehand -freeing -freeload -freely -freemason -freeness -freestyle -freeware -freeway -freewill -freezable -freezing -freight -french -frenzied -frenzy -frequency -frequent -fresh -fretful -fretted -friction -friday -fridge -fried -friend -frighten -frightful -frigidity -frigidly -frill -fringe -frisbee -frisk -fritter -frivolous -frolic -from -front -frostbite -frosted -frostily -frosting -frostlike -frosty -froth -frown -frozen -fructose -frugality -frugally -fruit -frustrate -frying -gab -gaffe -gag -gainfully -gaining -gains -gala -gallantly -galleria -gallery -galley -gallon -gallows -gallstone -galore -galvanize -gambling -game -gaming -gamma -gander -gangly -gangrene -gangway -gap -garage -garbage -garden -gargle -garland -garlic -garment -garnet -garnish -garter -gas -gatherer -gathering -gating -gauging -gauntlet -gauze -gave -gawk -gazing -gear -gecko -geek -geiger -gem -gender -generic -generous -genetics -genre -gentile -gentleman -gently -gents -geography -geologic -geologist -geology -geometric -geometry -geranium -gerbil -geriatric -germicide -germinate -germless -germproof -gestate -gestation -gesture -getaway -getting -getup -giant -gibberish -giblet -giddily -giddiness -giddy -gift -gigabyte -gigahertz -gigantic -giggle -giggling -giggly -gigolo -gilled -gills -gimmick -girdle -giveaway -given -giver -giving -gizmo -gizzard -glacial -glacier -glade -gladiator -gladly -glamorous -glamour -glance -glancing -glandular -glare -glaring -glass -glaucoma -glazing -gleaming -gleeful -glider -gliding -glimmer -glimpse -glisten -glitch -glitter -glitzy -gloater -gloating -gloomily -gloomy -glorified -glorifier -glorify -glorious -glory -gloss -glove -glowing -glowworm -glucose -glue -gluten -glutinous -glutton -gnarly -gnat -goal -goatskin -goes -goggles -going -goldfish -goldmine -goldsmith -golf -goliath -gonad -gondola -gone -gong -good -gooey -goofball -goofiness -goofy -google -goon -gopher -gore -gorged -gorgeous -gory -gosling -gossip -gothic -gotten -gout -gown -grab -graceful -graceless -gracious -gradation -graded -grader -gradient -grading -gradually -graduate -graffiti -grafted -grafting -grain -granddad -grandkid -grandly -grandma -grandpa -grandson -granite -granny -granola -grant -granular -grape -graph -grapple -grappling -grasp -grass -gratified -gratify -grating -gratitude -gratuity -gravel -graveness -graves -graveyard -gravitate -gravity -gravy -gray -grazing -greasily -greedily -greedless -greedy -green -greeter -greeting -grew -greyhound -grid -grief -grievance -grieving -grievous -grill -grimace -grimacing -grime -griminess -grimy -grinch -grinning -grip -gristle -grit -groggily -groggy -groin -groom -groove -grooving -groovy -grope -ground -grouped -grout -grove -grower -growing -growl -grub -grudge -grudging -grueling -gruffly -grumble -grumbling -grumbly -grumpily -grunge -grunt -guacamole -guidable -guidance -guide -guiding -guileless -guise -gulf -gullible -gully -gulp -gumball -gumdrop -gumminess -gumming -gummy -gurgle -gurgling -guru -gush -gusto -gusty -gutless -guts -gutter -guy -guzzler -gyration -habitable -habitant -habitat -habitual -hacked -hacker -hacking -hacksaw -had -haggler -haiku -half -halogen -halt -halved -halves -hamburger -hamlet -hammock -hamper -hamster -hamstring -handbag -handball -handbook -handbrake -handcart -handclap -handclasp -handcraft -handcuff -handed -handful -handgrip -handgun -handheld -handiness -handiwork -handlebar -handled -handler -handling -handmade -handoff -handpick -handprint -handrail -handsaw -handset -handsfree -handshake -handstand -handwash -handwork -handwoven -handwrite -handyman -hangnail -hangout -hangover -hangup -hankering -hankie -hanky -haphazard -happening -happier -happiest -happily -happiness -happy -harbor -hardcopy -hardcore -hardcover -harddisk -hardened -hardener -hardening -hardhat -hardhead -hardiness -hardly -hardness -hardship -hardware -hardwired -hardwood -hardy -harmful -harmless -harmonica -harmonics -harmonize -harmony -harness -harpist -harsh -harvest -hash -hassle -haste -hastily -hastiness -hasty -hatbox -hatchback -hatchery -hatchet -hatching -hatchling -hate -hatless -hatred -haunt -haven -hazard -hazelnut -hazily -haziness -hazing -hazy -headache -headband -headboard -headcount -headdress -headed -header -headfirst -headgear -heading -headlamp -headless -headlock -headphone -headpiece -headrest -headroom -headscarf -headset -headsman -headstand -headstone -headway -headwear -heap -heat -heave -heavily -heaviness -heaving -hedge -hedging -heftiness -hefty -helium -helmet -helper -helpful -helping -helpless -helpline -hemlock -hemstitch -hence -henchman -henna -herald -herbal -herbicide -herbs -heritage -hermit -heroics -heroism -herring -herself -hertz -hesitancy -hesitant -hesitate -hexagon -hexagram -hubcap -huddle -huddling -huff -hug -hula -hulk -hull -human -humble -humbling -humbly -humid -humiliate -humility -humming -hummus -humongous -humorist -humorless -humorous -humpback -humped -humvee -hunchback -hundredth -hunger -hungrily -hungry -hunk -hunter -hunting -huntress -huntsman -hurdle -hurled -hurler -hurling -hurray -hurricane -hurried -hurry -hurt -husband -hush -husked -huskiness -hut -hybrid -hydrant -hydrated -hydration -hydrogen -hydroxide -hyperlink -hypertext -hyphen -hypnoses -hypnosis -hypnotic -hypnotism -hypnotist -hypnotize -hypocrisy -hypocrite -ibuprofen -ice -iciness -icing -icky -icon -icy -idealism -idealist -idealize -ideally -idealness -identical -identify -identity -ideology -idiocy -idiom -idly -igloo -ignition -ignore -iguana -illicitly -illusion -illusive -image -imaginary -imagines -imaging -imbecile -imitate -imitation -immature -immerse -immersion -imminent -immobile -immodest -immorally -immortal -immovable -immovably -immunity -immunize -impaired -impale -impart -impatient -impeach -impeding -impending -imperfect -imperial -impish -implant -implement -implicate -implicit -implode -implosion -implosive -imply -impolite -important -importer -impose -imposing -impotence -impotency -impotent -impound -imprecise -imprint -imprison -impromptu -improper -improve -improving -improvise -imprudent -impulse -impulsive -impure -impurity -iodine -iodize -ion -ipad -iphone -ipod -irate -irk -iron -irregular -irrigate -irritable -irritably -irritant -irritate -islamic -islamist -isolated -isolating -isolation -isotope -issue -issuing -italicize -italics -item -itinerary -itunes -ivory -ivy -jab -jackal -jacket -jackknife -jackpot -jailbird -jailbreak -jailer -jailhouse -jalapeno -jam -janitor -january -jargon -jarring -jasmine -jaundice -jaunt -java -jawed -jawless -jawline -jaws -jaybird -jaywalker -jazz -jeep -jeeringly -jellied -jelly -jersey -jester -jet -jiffy -jigsaw -jimmy -jingle -jingling -jinx -jitters -jittery -job -jockey -jockstrap -jogger -jogging -john -joining -jokester -jokingly -jolliness -jolly -jolt -jot -jovial -joyfully -joylessly -joyous -joyride -joystick -jubilance -jubilant -judge -judgingly -judicial -judiciary -judo -juggle -juggling -jugular -juice -juiciness -juicy -jujitsu -jukebox -july -jumble -jumbo -jump -junction -juncture -june -junior -juniper -junkie -junkman -junkyard -jurist -juror -jury -justice -justifier -justify -justly -justness -juvenile -kabob -kangaroo -karaoke -karate -karma -kebab -keenly -keenness -keep -keg -kelp -kennel -kept -kerchief -kerosene -kettle -kick -kiln -kilobyte -kilogram -kilometer -kilowatt -kilt -kimono -kindle -kindling -kindly -kindness -kindred -kinetic -kinfolk -king -kinship -kinsman -kinswoman -kissable -kisser -kissing -kitchen -kite -kitten -kitty -kiwi -kleenex -knapsack -knee -knelt -knickers -knoll -koala -kooky -kosher -krypton -kudos -kung -labored -laborer -laboring -laborious -labrador -ladder -ladies -ladle -ladybug -ladylike -lagged -lagging -lagoon -lair -lake -lance -landed -landfall -landfill -landing -landlady -landless -landline -landlord -landmark -landmass -landmine -landowner -landscape -landside -landslide -language -lankiness -lanky -lantern -lapdog -lapel -lapped -lapping -laptop -lard -large -lark -lash -lasso -last -latch -late -lather -latitude -latrine -latter -latticed -launch -launder -laundry -laurel -lavender -lavish -laxative -lazily -laziness -lazy -lecturer -left -legacy -legal -legend -legged -leggings -legible -legibly -legislate -lego -legroom -legume -legwarmer -legwork -lemon -lend -length -lens -lent -leotard -lesser -letdown -lethargic -lethargy -letter -lettuce -level -leverage -levers -levitate -levitator -liability -liable -liberty -librarian -library -licking -licorice -lid -life -lifter -lifting -liftoff -ligament -likely -likeness -likewise -liking -lilac -lilly -lily -limb -limeade -limelight -limes -limit -limping -limpness -line -lingo -linguini -linguist -lining -linked -linoleum -linseed -lint -lion -lip -liquefy -liqueur -liquid -lisp -list -litigate -litigator -litmus -litter -little -livable -lived -lively -liver -livestock -lividly -living -lizard -lubricant -lubricate -lucid -luckily -luckiness -luckless -lucrative -ludicrous -lugged -lukewarm -lullaby -lumber -luminance -luminous -lumpiness -lumping -lumpish -lunacy -lunar -lunchbox -luncheon -lunchroom -lunchtime -lung -lurch -lure -luridness -lurk -lushly -lushness -luster -lustfully -lustily -lustiness -lustrous -lusty -luxurious -luxury -lying -lyrically -lyricism -lyricist -lyrics -macarena -macaroni -macaw -mace -machine -machinist -magazine -magenta -maggot -magical -magician -magma -magnesium -magnetic -magnetism -magnetize -magnifier -magnify -magnitude -magnolia -mahogany -maimed -majestic -majesty -majorette -majority -makeover -maker -makeshift -making -malformed -malt -mama -mammal -mammary -mammogram -manager -managing -manatee -mandarin -mandate -mandatory -mandolin -manger -mangle -mango -mangy -manhandle -manhole -manhood -manhunt -manicotti -manicure -manifesto -manila -mankind -manlike -manliness -manly -manmade -manned -mannish -manor -manpower -mantis -mantra -manual -many -map -marathon -marauding -marbled -marbles -marbling -march -mardi -margarine -margarita -margin -marigold -marina -marine -marital -maritime -marlin -marmalade -maroon -married -marrow -marry -marshland -marshy -marsupial -marvelous -marxism -mascot -masculine -mashed -mashing -massager -masses -massive -mastiff -matador -matchbook -matchbox -matcher -matching -matchless -material -maternal -maternity -math -mating -matriarch -matrimony -matrix -matron -matted -matter -maturely -maturing -maturity -mauve -maverick -maximize -maximum -maybe -mayday -mayflower -moaner -moaning -mobile -mobility -mobilize -mobster -mocha -mocker -mockup -modified -modify -modular -modulator -module -moisten -moistness -moisture -molar -molasses -mold -molecular -molecule -molehill -mollusk -mom -monastery -monday -monetary -monetize -moneybags -moneyless -moneywise -mongoose -mongrel -monitor -monkhood -monogamy -monogram -monologue -monopoly -monorail -monotone -monotype -monoxide -monsieur -monsoon -monstrous -monthly -monument -moocher -moodiness -moody -mooing -moonbeam -mooned -moonlight -moonlike -moonlit -moonrise -moonscape -moonshine -moonstone -moonwalk -mop -morale -morality -morally -morbidity -morbidly -morphine -morphing -morse -mortality -mortally -mortician -mortified -mortify -mortuary -mosaic -mossy -most -mothball -mothproof -motion -motivate -motivator -motive -motocross -motor -motto -mountable -mountain -mounted -mounting -mourner -mournful -mouse -mousiness -moustache -mousy -mouth -movable -move -movie -moving -mower -mowing -much -muck -mud -mug -mulberry -mulch -mule -mulled -mullets -multiple -multiply -multitask -multitude -mumble -mumbling -mumbo -mummified -mummify -mummy -mumps -munchkin -mundane -municipal -muppet -mural -murkiness -murky -murmuring -muscular -museum -mushily -mushiness -mushroom -mushy -music -musket -muskiness -musky -mustang -mustard -muster -mustiness -musty -mutable -mutate -mutation -mute -mutilated -mutilator -mutiny -mutt -mutual -muzzle -myself -myspace -mystified -mystify -myth -nacho -nag -nail -name -naming -nanny -nanometer -nape -napkin -napped -napping -nappy -narrow -nastily -nastiness -national -native -nativity -natural -nature -naturist -nautical -navigate -navigator -navy -nearby -nearest -nearly -nearness -neatly -neatness -nebula -nebulizer -nectar -negate -negation -negative -neglector -negligee -negligent -negotiate -nemeses -nemesis -neon -nephew -nerd -nervous -nervy -nest -net -neurology -neuron -neurosis -neurotic -neuter -neutron -never -next -nibble -nickname -nicotine -niece -nifty -nimble -nimbly -nineteen -ninetieth -ninja -nintendo -ninth -nuclear -nuclei -nucleus -nugget -nullify -number -numbing -numbly -numbness -numeral -numerate -numerator -numeric -numerous -nuptials -nursery -nursing -nurture -nutcase -nutlike -nutmeg -nutrient -nutshell -nuttiness -nutty -nuzzle -nylon -oaf -oak -oasis -oat -obedience -obedient -obituary -object -obligate -obliged -oblivion -oblivious -oblong -obnoxious -oboe -obscure -obscurity -observant -observer -observing -obsessed -obsession -obsessive -obsolete -obstacle -obstinate -obstruct -obtain -obtrusive -obtuse -obvious -occultist -occupancy -occupant -occupier -occupy -ocean -ocelot -octagon -octane -october -octopus -ogle -oil -oink -ointment -okay -old -olive -olympics -omega -omen -ominous -omission -omit -omnivore -onboard -oncoming -ongoing -onion -online -onlooker -only -onscreen -onset -onshore -onslaught -onstage -onto -onward -onyx -oops -ooze -oozy -opacity -opal -open -operable -operate -operating -operation -operative -operator -opium -opossum -opponent -oppose -opposing -opposite -oppressed -oppressor -opt -opulently -osmosis -other -otter -ouch -ought -ounce -outage -outback -outbid -outboard -outbound -outbreak -outburst -outcast -outclass -outcome -outdated -outdoors -outer -outfield -outfit -outflank -outgoing -outgrow -outhouse -outing -outlast -outlet -outline -outlook -outlying -outmatch -outmost -outnumber -outplayed -outpost -outpour -output -outrage -outrank -outreach -outright -outscore -outsell -outshine -outshoot -outsider -outskirts -outsmart -outsource -outspoken -outtakes -outthink -outward -outweigh -outwit -oval -ovary -oven -overact -overall -overarch -overbid -overbill -overbite -overblown -overboard -overbook -overbuilt -overcast -overcoat -overcome -overcook -overcrowd -overdraft -overdrawn -overdress -overdrive -overdue -overeager -overeater -overexert -overfed -overfeed -overfill -overflow -overfull -overgrown -overhand -overhang -overhaul -overhead -overhear -overheat -overhung -overjoyed -overkill -overlabor -overlaid -overlap -overlay -overload -overlook -overlord -overlying -overnight -overpass -overpay -overplant -overplay -overpower -overprice -overrate -overreach -overreact -override -overripe -overrule -overrun -overshoot -overshot -oversight -oversized -oversleep -oversold -overspend -overstate -overstay -overstep -overstock -overstuff -oversweet -overtake -overthrow -overtime -overtly -overtone -overture -overturn -overuse -overvalue -overview -overwrite -owl -oxford -oxidant -oxidation -oxidize -oxidizing -oxygen -oxymoron -oyster -ozone -paced -pacemaker -pacific -pacifier -pacifism -pacifist -pacify -padded -padding -paddle -paddling -padlock -pagan -pager -paging -pajamas -palace -palatable -palm -palpable -palpitate -paltry -pampered -pamperer -pampers -pamphlet -panama -pancake -pancreas -panda -pandemic -pang -panhandle -panic -panning -panorama -panoramic -panther -pantomime -pantry -pants -pantyhose -paparazzi -papaya -paper -paprika -papyrus -parabola -parachute -parade -paradox -paragraph -parakeet -paralegal -paralyses -paralysis -paralyze -paramedic -parameter -paramount -parasail -parasite -parasitic -parcel -parched -parchment -pardon -parish -parka -parking -parkway -parlor -parmesan -parole -parrot -parsley -parsnip -partake -parted -parting -partition -partly -partner -partridge -party -passable -passably -passage -passcode -passenger -passerby -passing -passion -passive -passivism -passover -passport -password -pasta -pasted -pastel -pastime -pastor -pastrami -pasture -pasty -patchwork -patchy -paternal -paternity -path -patience -patient -patio -patriarch -patriot -patrol -patronage -patronize -pauper -pavement -paver -pavestone -pavilion -paving -pawing -payable -payback -paycheck -payday -payee -payer -paying -payment -payphone -payroll -pebble -pebbly -pecan -pectin -peculiar -peddling -pediatric -pedicure -pedigree -pedometer -pegboard -pelican -pellet -pelt -pelvis -penalize -penalty -pencil -pendant -pending -penholder -penknife -pennant -penniless -penny -penpal -pension -pentagon -pentagram -pep -perceive -percent -perch -percolate -perennial -perfected -perfectly -perfume -periscope -perish -perjurer -perjury -perkiness -perky -perm -peroxide -perpetual -perplexed -persecute -persevere -persuaded -persuader -pesky -peso -pessimism -pessimist -pester -pesticide -petal -petite -petition -petri -petroleum -petted -petticoat -pettiness -petty -petunia -phantom -phobia -phoenix -phonebook -phoney -phonics -phoniness -phony -phosphate -photo -phrase -phrasing -placard -placate -placidly -plank -planner -plant -plasma -plaster -plastic -plated -platform -plating -platinum -platonic -platter -platypus -plausible -plausibly -playable -playback -player -playful -playgroup -playhouse -playing -playlist -playmaker -playmate -playoff -playpen -playroom -playset -plaything -playtime -plaza -pleading -pleat -pledge -plentiful -plenty -plethora -plexiglas -pliable -plod -plop -plot -plow -ploy -pluck -plug -plunder -plunging -plural -plus -plutonium -plywood -poach -pod -poem -poet -pogo -pointed -pointer -pointing -pointless -pointy -poise -poison -poker -poking -polar -police -policy -polio -polish -politely -polka -polo -polyester -polygon -polygraph -polymer -poncho -pond -pony -popcorn -pope -poplar -popper -poppy -popsicle -populace -popular -populate -porcupine -pork -porous -porridge -portable -portal -portfolio -porthole -portion -portly -portside -poser -posh -posing -possible -possibly -possum -postage -postal -postbox -postcard -posted -poster -posting -postnasal -posture -postwar -pouch -pounce -pouncing -pound -pouring -pout -powdered -powdering -powdery -power -powwow -pox -praising -prance -prancing -pranker -prankish -prankster -prayer -praying -preacher -preaching -preachy -preamble -precinct -precise -precision -precook -precut -predator -predefine -predict -preface -prefix -preflight -preformed -pregame -pregnancy -pregnant -preheated -prelaunch -prelaw -prelude -premiere -premises -premium -prenatal -preoccupy -preorder -prepaid -prepay -preplan -preppy -preschool -prescribe -preseason -preset -preshow -president -presoak -press -presume -presuming -preteen -pretended -pretender -pretense -pretext -pretty -pretzel -prevail -prevalent -prevent -preview -previous -prewar -prewashed -prideful -pried -primal -primarily -primary -primate -primer -primp -princess -print -prior -prism -prison -prissy -pristine -privacy -private -privatize -prize -proactive -probable -probably -probation -probe -probing -probiotic -problem -procedure -process -proclaim -procreate -procurer -prodigal -prodigy -produce -product -profane -profanity -professed -professor -profile -profound -profusely -progeny -prognosis -program -progress -projector -prologue -prolonged -promenade -prominent -promoter -promotion -prompter -promptly -prone -prong -pronounce -pronto -proofing -proofread -proofs -propeller -properly -property -proponent -proposal -propose -props -prorate -protector -protegee -proton -prototype -protozoan -protract -protrude -proud -provable -proved -proven -provided -provider -providing -province -proving -provoke -provoking -provolone -prowess -prowler -prowling -proximity -proxy -prozac -prude -prudishly -prune -pruning -pry -psychic -public -publisher -pucker -pueblo -pug -pull -pulmonary -pulp -pulsate -pulse -pulverize -puma -pumice -pummel -punch -punctual -punctuate -punctured -pungent -punisher -punk -pupil -puppet -puppy -purchase -pureblood -purebred -purely -pureness -purgatory -purge -purging -purifier -purify -purist -puritan -purity -purple -purplish -purposely -purr -purse -pursuable -pursuant -pursuit -purveyor -pushcart -pushchair -pusher -pushiness -pushing -pushover -pushpin -pushup -pushy -putdown -putt -puzzle -puzzling -pyramid -pyromania -python -quack -quadrant -quail -quaintly -quake -quaking -qualified -qualifier -qualify -quality -qualm -quantum -quarrel -quarry -quartered -quarterly -quarters -quartet -quench -query -quicken -quickly -quickness -quicksand -quickstep -quiet -quill -quilt -quintet -quintuple -quirk -quit -quiver -quizzical -quotable -quotation -quote -rabid -race -racing -racism -rack -racoon -radar -radial -radiance -radiantly -radiated -radiation -radiator -radio -radish -raffle -raft -rage -ragged -raging -ragweed -raider -railcar -railing -railroad -railway -raisin -rake -raking -rally -ramble -rambling -ramp -ramrod -ranch -rancidity -random -ranged -ranger -ranging -ranked -ranking -ransack -ranting -rants -rare -rarity -rascal -rash -rasping -ravage -raven -ravine -raving -ravioli -ravishing -reabsorb -reach -reacquire -reaction -reactive -reactor -reaffirm -ream -reanalyze -reappear -reapply -reappoint -reapprove -rearrange -rearview -reason -reassign -reassure -reattach -reawake -rebalance -rebate -rebel -rebirth -reboot -reborn -rebound -rebuff -rebuild -rebuilt -reburial -rebuttal -recall -recant -recapture -recast -recede -recent -recess -recharger -recipient -recital -recite -reckless -reclaim -recliner -reclining -recluse -reclusive -recognize -recoil -recollect -recolor -reconcile -reconfirm -reconvene -recopy -record -recount -recoup -recovery -recreate -rectal -rectangle -rectified -rectify -recycled -recycler -recycling -reemerge -reenact -reenter -reentry -reexamine -referable -referee -reference -refill -refinance -refined -refinery -refining -refinish -reflected -reflector -reflex -reflux -refocus -refold -reforest -reformat -reformed -reformer -reformist -refract -refrain -refreeze -refresh -refried -refueling -refund -refurbish -refurnish -refusal -refuse -refusing -refutable -refute -regain -regalia -regally -reggae -regime -region -register -registrar -registry -regress -regretful -regroup -regular -regulate -regulator -rehab -reheat -rehire -rehydrate -reimburse -reissue -reiterate -rejoice -rejoicing -rejoin -rekindle -relapse -relapsing -relatable -related -relation -relative -relax -relay -relearn -release -relenting -reliable -reliably -reliance -reliant -relic -relieve -relieving -relight -relish -relive -reload -relocate -relock -reluctant -rely -remake -remark -remarry -rematch -remedial -remedy -remember -reminder -remindful -remission -remix -remnant -remodeler -remold -remorse -remote -removable -removal -removed -remover -removing -rename -renderer -rendering -rendition -renegade -renewable -renewably -renewal -renewed -renounce -renovate -renovator -rentable -rental -rented -renter -reoccupy -reoccur -reopen -reorder -repackage -repacking -repaint -repair -repave -repaying -repayment -repeal -repeated -repeater -repent -rephrase -replace -replay -replica -reply -reporter -repose -repossess -repost -repressed -reprimand -reprint -reprise -reproach -reprocess -reproduce -reprogram -reps -reptile -reptilian -repugnant -repulsion -repulsive -repurpose -reputable -reputably -request -require -requisite -reroute -rerun -resale -resample -rescuer -reseal -research -reselect -reseller -resemble -resend -resent -reset -reshape -reshoot -reshuffle -residence -residency -resident -residual -residue -resigned -resilient -resistant -resisting -resize -resolute -resolved -resonant -resonate -resort -resource -respect -resubmit -result -resume -resupply -resurface -resurrect -retail -retainer -retaining -retake -retaliate -retention -rethink -retinal -retired -retiree -retiring -retold -retool -retorted -retouch -retrace -retract -retrain -retread -retreat -retrial -retrieval -retriever -retry -return -retying -retype -reunion -reunite -reusable -reuse -reveal -reveler -revenge -revenue -reverb -revered -reverence -reverend -reversal -reverse -reversing -reversion -revert -revisable -revise -revision -revisit -revivable -revival -reviver -reviving -revocable -revoke -revolt -revolver -revolving -reward -rewash -rewind -rewire -reword -rework -rewrap -rewrite -rhyme -ribbon -ribcage -rice -riches -richly -richness -rickety -ricotta -riddance -ridden -ride -riding -rifling -rift -rigging -rigid -rigor -rimless -rimmed -rind -rink -rinse -rinsing -riot -ripcord -ripeness -ripening -ripping -ripple -rippling -riptide -rise -rising -risk -risotto -ritalin -ritzy -rival -riverbank -riverbed -riverboat -riverside -riveter -riveting -roamer -roaming -roast -robbing -robe -robin -robotics -robust -rockband -rocker -rocket -rockfish -rockiness -rocking -rocklike -rockslide -rockstar -rocky -rogue -roman -romp -rope -roping -roster -rosy -rotten -rotting -rotunda -roulette -rounding -roundish -roundness -roundup -roundworm -routine -routing -rover -roving -royal -rubbed -rubber -rubbing -rubble -rubdown -ruby -ruckus -rudder -rug -ruined -rule -rumble -rumbling -rummage -rumor -runaround -rundown -runner -running -runny -runt -runway -rupture -rural -ruse -rush -rust -rut -sabbath -sabotage -sacrament -sacred -sacrifice -sadden -saddlebag -saddled -saddling -sadly -sadness -safari -safeguard -safehouse -safely -safeness -saffron -saga -sage -sagging -saggy -said -saint -sake -salad -salami -salaried -salary -saline -salon -saloon -salsa -salt -salutary -salute -salvage -salvaging -salvation -same -sample -sampling -sanction -sanctity -sanctuary -sandal -sandbag -sandbank -sandbar -sandblast -sandbox -sanded -sandfish -sanding -sandlot -sandpaper -sandpit -sandstone -sandstorm -sandworm -sandy -sanitary -sanitizer -sank -santa -sapling -sappiness -sappy -sarcasm -sarcastic -sardine -sash -sasquatch -sassy -satchel -satiable -satin -satirical -satisfied -satisfy -saturate -saturday -sauciness -saucy -sauna -savage -savanna -saved -savings -savior -savor -saxophone -say -scabbed -scabby -scalded -scalding -scale -scaling -scallion -scallop -scalping -scam -scandal -scanner -scanning -scant -scapegoat -scarce -scarcity -scarecrow -scared -scarf -scarily -scariness -scarring -scary -scavenger -scenic -schedule -schematic -scheme -scheming -schilling -schnapps -scholar -science -scientist -scion -scoff -scolding -scone -scoop -scooter -scope -scorch -scorebook -scorecard -scored -scoreless -scorer -scoring -scorn -scorpion -scotch -scoundrel -scoured -scouring -scouting -scouts -scowling -scrabble -scraggly -scrambled -scrambler -scrap -scratch -scrawny -screen -scribble -scribe -scribing -scrimmage -script -scroll -scrooge -scrounger -scrubbed -scrubber -scruffy -scrunch -scrutiny -scuba -scuff -sculptor -sculpture -scurvy -scuttle -secluded -secluding -seclusion -second -secrecy -secret -sectional -sector -secular -securely -security -sedan -sedate -sedation -sedative -sediment -seduce -seducing -segment -seismic -seizing -seldom -selected -selection -selective -selector -self -seltzer -semantic -semester -semicolon -semifinal -seminar -semisoft -semisweet -senate -senator -send -senior -senorita -sensation -sensitive -sensitize -sensually -sensuous -sepia -september -septic -septum -sequel -sequence -sequester -series -sermon -serotonin -serpent -serrated -serve -service -serving -sesame -sessions -setback -setting -settle -settling -setup -sevenfold -seventeen -seventh -seventy -severity -shabby -shack -shaded -shadily -shadiness -shading -shadow -shady -shaft -shakable -shakily -shakiness -shaking -shaky -shale -shallot -shallow -shame -shampoo -shamrock -shank -shanty -shape -shaping -share -sharpener -sharper -sharpie -sharply -sharpness -shawl -sheath -shed -sheep -sheet -shelf -shell -shelter -shelve -shelving -sherry -shield -shifter -shifting -shiftless -shifty -shimmer -shimmy -shindig -shine -shingle -shininess -shining -shiny -ship -shirt -shivering -shock -shone -shoplift -shopper -shopping -shoptalk -shore -shortage -shortcake -shortcut -shorten -shorter -shorthand -shortlist -shortly -shortness -shorts -shortwave -shorty -shout -shove -showbiz -showcase -showdown -shower -showgirl -showing -showman -shown -showoff -showpiece -showplace -showroom -showy -shrank -shrapnel -shredder -shredding -shrewdly -shriek -shrill -shrimp -shrine -shrink -shrivel -shrouded -shrubbery -shrubs -shrug -shrunk -shucking -shudder -shuffle -shuffling -shun -shush -shut -shy -siamese -siberian -sibling -siding -sierra -siesta -sift -sighing -silenced -silencer -silent -silica -silicon -silk -silliness -silly -silo -silt -silver -similarly -simile -simmering -simple -simplify -simply -sincere -sincerity -singer -singing -single -singular -sinister -sinless -sinner -sinuous -sip -siren -sister -sitcom -sitter -sitting -situated -situation -sixfold -sixteen -sixth -sixties -sixtieth -sixtyfold -sizable -sizably -size -sizing -sizzle -sizzling -skater -skating -skedaddle -skeletal -skeleton -skeptic -sketch -skewed -skewer -skid -skied -skier -skies -skiing -skilled -skillet -skillful -skimmed -skimmer -skimming -skimpily -skincare -skinhead -skinless -skinning -skinny -skintight -skipper -skipping -skirmish -skirt -skittle -skydiver -skylight -skyline -skype -skyrocket -skyward -slab -slacked -slacker -slacking -slackness -slacks -slain -slam -slander -slang -slapping -slapstick -slashed -slashing -slate -slather -slaw -sled -sleek -sleep -sleet -sleeve -slept -sliceable -sliced -slicer -slicing -slick -slider -slideshow -sliding -slighted -slighting -slightly -slimness -slimy -slinging -slingshot -slinky -slip -slit -sliver -slobbery -slogan -sloped -sloping -sloppily -sloppy -slot -slouching -slouchy -sludge -slug -slum -slurp -slush -sly -small -smartly -smartness -smasher -smashing -smashup -smell -smelting -smile -smilingly -smirk -smite -smith -smitten -smock -smog -smoked -smokeless -smokiness -smoking -smoky -smolder -smooth -smother -smudge -smudgy -smuggler -smuggling -smugly -smugness -snack -snagged -snaking -snap -snare -snarl -snazzy -sneak -sneer -sneeze -sneezing -snide -sniff -snippet -snipping -snitch -snooper -snooze -snore -snoring -snorkel -snort -snout -snowbird -snowboard -snowbound -snowcap -snowdrift -snowdrop -snowfall -snowfield -snowflake -snowiness -snowless -snowman -snowplow -snowshoe -snowstorm -snowsuit -snowy -snub -snuff -snuggle -snugly -snugness -speak -spearfish -spearhead -spearman -spearmint -species -specimen -specked -speckled -specks -spectacle -spectator -spectrum -speculate -speech -speed -spellbind -speller -spelling -spendable -spender -spending -spent -spew -sphere -spherical -sphinx -spider -spied -spiffy -spill -spilt -spinach -spinal -spindle -spinner -spinning -spinout -spinster -spiny -spiral -spirited -spiritism -spirits -spiritual -splashed -splashing -splashy -splatter -spleen -splendid -splendor -splice -splicing -splinter -splotchy -splurge -spoilage -spoiled -spoiler -spoiling -spoils -spoken -spokesman -sponge -spongy -sponsor -spoof -spookily -spooky -spool -spoon -spore -sporting -sports -sporty -spotless -spotlight -spotted -spotter -spotting -spotty -spousal -spouse -spout -sprain -sprang -sprawl -spray -spree -sprig -spring -sprinkled -sprinkler -sprint -sprite -sprout -spruce -sprung -spry -spud -spur -sputter -spyglass -squabble -squad -squall -squander -squash -squatted -squatter -squatting -squeak -squealer -squealing -squeamish -squeegee -squeeze -squeezing -squid -squiggle -squiggly -squint -squire -squirt -squishier -squishy -stability -stabilize -stable -stack -stadium -staff -stage -staging -stagnant -stagnate -stainable -stained -staining -stainless -stalemate -staleness -stalling -stallion -stamina -stammer -stamp -stand -stank -staple -stapling -starboard -starch -stardom -stardust -starfish -stargazer -staring -stark -starless -starlet -starlight -starlit -starring -starry -starship -starter -starting -startle -startling -startup -starved -starving -stash -state -static -statistic -statue -stature -status -statute -statutory -staunch -stays -steadfast -steadier -steadily -steadying -steam -steed -steep -steerable -steering -steersman -stegosaur -stellar -stem -stench -stencil -step -stereo -sterile -sterility -sterilize -sterling -sternness -sternum -stew -stick -stiffen -stiffly -stiffness -stifle -stifling -stillness -stilt -stimulant -stimulate -stimuli -stimulus -stinger -stingily -stinging -stingray -stingy -stinking -stinky -stipend -stipulate -stir -stitch -stock -stoic -stoke -stole -stomp -stonewall -stoneware -stonework -stoning -stony -stood -stooge -stool -stoop -stoplight -stoppable -stoppage -stopped -stopper -stopping -stopwatch -storable -storage -storeroom -storewide -storm -stout -stove -stowaway -stowing -straddle -straggler -strained -strainer -straining -strangely -stranger -strangle -strategic -strategy -stratus -straw -stray -streak -stream -street -strength -strenuous -strep -stress -stretch -strewn -stricken -strict -stride -strife -strike -striking -strive -striving -strobe -strode -stroller -strongbox -strongly -strongman -struck -structure -strudel -struggle -strum -strung -strut -stubbed -stubble -stubbly -stubborn -stucco -stuck -student -studied -studio -study -stuffed -stuffing -stuffy -stumble -stumbling -stump -stung -stunned -stunner -stunning -stunt -stupor -sturdily -sturdy -styling -stylishly -stylist -stylized -stylus -suave -subarctic -subatomic -subdivide -subdued -subduing -subfloor -subgroup -subheader -subject -sublease -sublet -sublevel -sublime -submarine -submerge -submersed -submitter -subpanel -subpar -subplot -subprime -subscribe -subscript -subsector -subside -subsiding -subsidize -subsidy -subsoil -subsonic -substance -subsystem -subtext -subtitle -subtly -subtotal -subtract -subtype -suburb -subway -subwoofer -subzero -succulent -such -suction -sudden -sudoku -suds -sufferer -suffering -suffice -suffix -suffocate -suffrage -sugar -suggest -suing -suitable -suitably -suitcase -suitor -sulfate -sulfide -sulfite -sulfur -sulk -sullen -sulphate -sulphuric -sultry -superbowl -superglue -superhero -superior -superjet -superman -supermom -supernova -supervise -supper -supplier -supply -support -supremacy -supreme -surcharge -surely -sureness -surface -surfacing -surfboard -surfer -surgery -surgical -surging -surname -surpass -surplus -surprise -surreal -surrender -surrogate -surround -survey -survival -survive -surviving -survivor -sushi -suspect -suspend -suspense -sustained -sustainer -swab -swaddling -swagger -swampland -swan -swapping -swarm -sway -swear -sweat -sweep -swell -swept -swerve -swifter -swiftly -swiftness -swimmable -swimmer -swimming -swimsuit -swimwear -swinger -swinging -swipe -swirl -switch -swivel -swizzle -swooned -swoop -swoosh -swore -sworn -swung -sycamore -sympathy -symphonic -symphony -symptom -synapse -syndrome -synergy -synopses -synopsis -synthesis -synthetic -syrup -system -t-shirt -tabasco -tabby -tableful -tables -tablet -tableware -tabloid -tackiness -tacking -tackle -tackling -tacky -taco -tactful -tactical -tactics -tactile -tactless -tadpole -taekwondo -tag -tainted -take -taking -talcum -talisman -tall -talon -tamale -tameness -tamer -tamper -tank -tanned -tannery -tanning -tantrum -tapeless -tapered -tapering -tapestry -tapioca -tapping -taps -tarantula -target -tarmac -tarnish -tarot -tartar -tartly -tartness -task -tassel -taste -tastiness -tasting -tasty -tattered -tattle -tattling -tattoo -taunt -tavern -thank -that -thaw -theater -theatrics -thee -theft -theme -theology -theorize -thermal -thermos -thesaurus -these -thesis -thespian -thicken -thicket -thickness -thieving -thievish -thigh -thimble -thing -think -thinly -thinner -thinness -thinning -thirstily -thirsting -thirsty -thirteen -thirty -thong -thorn -those -thousand -thrash -thread -threaten -threefold -thrift -thrill -thrive -thriving -throat -throbbing -throng -throttle -throwaway -throwback -thrower -throwing -thud -thumb -thumping -thursday -thus -thwarting -thyself -tiara -tibia -tidal -tidbit -tidiness -tidings -tidy -tiger -tighten -tightly -tightness -tightrope -tightwad -tigress -tile -tiling -till -tilt -timid -timing -timothy -tinderbox -tinfoil -tingle -tingling -tingly -tinker -tinkling -tinsel -tinsmith -tint -tinwork -tiny -tipoff -tipped -tipper -tipping -tiptoeing -tiptop -tiring -tissue -trace -tracing -track -traction -tractor -trade -trading -tradition -traffic -tragedy -trailing -trailside -train -traitor -trance -tranquil -transfer -transform -translate -transpire -transport -transpose -trapdoor -trapeze -trapezoid -trapped -trapper -trapping -traps -trash -travel -traverse -travesty -tray -treachery -treading -treadmill -treason -treat -treble -tree -trekker -tremble -trembling -tremor -trench -trend -trespass -triage -trial -triangle -tribesman -tribunal -tribune -tributary -tribute -triceps -trickery -trickily -tricking -trickle -trickster -tricky -tricolor -tricycle -trident -tried -trifle -trifocals -trillion -trilogy -trimester -trimmer -trimming -trimness -trinity -trio -tripod -tripping -triumph -trivial -trodden -trolling -trombone -trophy -tropical -tropics -trouble -troubling -trough -trousers -trout -trowel -truce -truck -truffle -trump -trunks -trustable -trustee -trustful -trusting -trustless -truth -try -tubby -tubeless -tubular -tucking -tuesday -tug -tuition -tulip -tumble -tumbling -tummy -turban -turbine -turbofan -turbojet -turbulent -turf -turkey -turmoil -turret -turtle -tusk -tutor -tutu -tux -tweak -tweed -tweet -tweezers -twelve -twentieth -twenty -twerp -twice -twiddle -twiddling -twig -twilight -twine -twins -twirl -twistable -twisted -twister -twisting -twisty -twitch -twitter -tycoon -tying -tyke -udder -ultimate -ultimatum -ultra -umbilical -umbrella -umpire -unabashed -unable -unadorned -unadvised -unafraid -unaired -unaligned -unaltered -unarmored -unashamed -unaudited -unawake -unaware -unbaked -unbalance -unbeaten -unbend -unbent -unbiased -unbitten -unblended -unblessed -unblock -unbolted -unbounded -unboxed -unbraided -unbridle -unbroken -unbuckled -unbundle -unburned -unbutton -uncanny -uncapped -uncaring -uncertain -unchain -unchanged -uncharted -uncheck -uncivil -unclad -unclaimed -unclamped -unclasp -uncle -unclip -uncloak -unclog -unclothed -uncoated -uncoiled -uncolored -uncombed -uncommon -uncooked -uncork -uncorrupt -uncounted -uncouple -uncouth -uncover -uncross -uncrown -uncrushed -uncured -uncurious -uncurled -uncut -undamaged -undated -undaunted -undead -undecided -undefined -underage -underarm -undercoat -undercook -undercut -underdog -underdone -underfed -underfeed -underfoot -undergo -undergrad -underhand -underline -underling -undermine -undermost -underpaid -underpass -underpay -underrate -undertake -undertone -undertook -undertow -underuse -underwear -underwent -underwire -undesired -undiluted -undivided -undocked -undoing -undone -undrafted -undress -undrilled -undusted -undying -unearned -unearth -unease -uneasily -uneasy -uneatable -uneaten -unedited -unelected -unending -unengaged -unenvied -unequal -unethical -uneven -unexpired -unexposed -unfailing -unfair -unfasten -unfazed -unfeeling -unfiled -unfilled -unfitted -unfitting -unfixable -unfixed -unflawed -unfocused -unfold -unfounded -unframed -unfreeze -unfrosted -unfrozen -unfunded -unglazed -ungloved -unglue -ungodly -ungraded -ungreased -unguarded -unguided -unhappily -unhappy -unharmed -unhealthy -unheard -unhearing -unheated -unhelpful -unhidden -unhinge -unhitched -unholy -unhook -unicorn -unicycle -unified -unifier -uniformed -uniformly -unify -unimpeded -uninjured -uninstall -uninsured -uninvited -union -uniquely -unisexual -unison -unissued -unit -universal -universe -unjustly -unkempt -unkind -unknotted -unknowing -unknown -unlaced -unlatch -unlawful -unleaded -unlearned -unleash -unless -unleveled -unlighted -unlikable -unlimited -unlined -unlinked -unlisted -unlit -unlivable -unloaded -unloader -unlocked -unlocking -unlovable -unloved -unlovely -unloving -unluckily -unlucky -unmade -unmanaged -unmanned -unmapped -unmarked -unmasked -unmasking -unmatched -unmindful -unmixable -unmixed -unmolded -unmoral -unmovable -unmoved -unmoving -unnamable -unnamed -unnatural -unneeded -unnerve -unnerving -unnoticed -unopened -unopposed -unpack -unpadded -unpaid -unpainted -unpaired -unpaved -unpeeled -unpicked -unpiloted -unpinned -unplanned -unplanted -unpleased -unpledged -unplowed -unplug -unpopular -unproven -unquote -unranked -unrated -unraveled -unreached -unread -unreal -unreeling -unrefined -unrelated -unrented -unrest -unretired -unrevised -unrigged -unripe -unrivaled -unroasted -unrobed -unroll -unruffled -unruly -unrushed -unsaddle -unsafe -unsaid -unsalted -unsaved -unsavory -unscathed -unscented -unscrew -unsealed -unseated -unsecured -unseeing -unseemly -unseen -unselect -unselfish -unsent -unsettled -unshackle -unshaken -unshaved -unshaven -unsheathe -unshipped -unsightly -unsigned -unskilled -unsliced -unsmooth -unsnap -unsocial -unsoiled -unsold -unsolved -unsorted -unspoiled -unspoken -unstable -unstaffed -unstamped -unsteady -unsterile -unstirred -unstitch -unstopped -unstuck -unstuffed -unstylish -unsubtle -unsubtly -unsuited -unsure -unsworn -untagged -untainted -untaken -untamed -untangled -untapped -untaxed -unthawed -unthread -untidy -untie -until -untimed -untimely -untitled -untoasted -untold -untouched -untracked -untrained -untreated -untried -untrimmed -untrue -untruth -unturned -untwist -untying -unusable -unused -unusual -unvalued -unvaried -unvarying -unveiled -unveiling -unvented -unviable -unvisited -unvocal -unwanted -unwarlike -unwary -unwashed -unwatched -unweave -unwed -unwelcome -unwell -unwieldy -unwilling -unwind -unwired -unwitting -unwomanly -unworldly -unworn -unworried -unworthy -unwound -unwoven -unwrapped -unwritten -unzip -upbeat -upchuck -upcoming -upcountry -update -upfront -upgrade -upheaval -upheld -uphill -uphold -uplifted -uplifting -upload -upon -upper -upright -uprising -upriver -uproar -uproot -upscale -upside -upstage -upstairs -upstart -upstate -upstream -upstroke -upswing -uptake -uptight -uptown -upturned -upward -upwind -uranium -urban -urchin -urethane -urgency -urgent -urging -urologist -urology -usable -usage -useable -used -uselessly -user -usher -usual -utensil -utility -utilize -utmost -utopia -utter -vacancy -vacant -vacate -vacation -vagabond -vagrancy -vagrantly -vaguely -vagueness -valiant -valid -valium -valley -valuables -value -vanilla -vanish -vanity -vanquish -vantage -vaporizer -variable -variably -varied -variety -various -varmint -varnish -varsity -varying -vascular -vaseline -vastly -vastness -veal -vegan -veggie -vehicular -velcro -velocity -velvet -vendetta -vending -vendor -veneering -vengeful -venomous -ventricle -venture -venue -venus -verbalize -verbally -verbose -verdict -verify -verse -version -versus -vertebrae -vertical -vertigo -very -vessel -vest -veteran -veto -vexingly -viability -viable -vibes -vice -vicinity -victory -video -viewable -viewer -viewing -viewless -viewpoint -vigorous -village -villain -vindicate -vineyard -vintage -violate -violation -violator -violet -violin -viper -viral -virtual -virtuous -virus -visa -viscosity -viscous -viselike -visible -visibly -vision -visiting -visitor -visor -vista -vitality -vitalize -vitally -vitamins -vivacious -vividly -vividness -vixen -vocalist -vocalize -vocally -vocation -voice -voicing -void -volatile -volley -voltage -volumes -voter -voting -voucher -vowed -vowel -voyage -wackiness -wad -wafer -waffle -waged -wager -wages -waggle -wagon -wake -waking -walk -walmart -walnut -walrus -waltz -wand -wannabe -wanted -wanting -wasabi -washable -washbasin -washboard -washbowl -washcloth -washday -washed -washer -washhouse -washing -washout -washroom -washstand -washtub -wasp -wasting -watch -water -waviness -waving -wavy -whacking -whacky -wham -wharf -wheat -whenever -whiff -whimsical -whinny -whiny -whisking -whoever -whole -whomever -whoopee -whooping -whoops -why -wick -widely -widen -widget -widow -width -wieldable -wielder -wife -wifi -wikipedia -wildcard -wildcat -wilder -wildfire -wildfowl -wildland -wildlife -wildly -wildness -willed -willfully -willing -willow -willpower -wilt -wimp -wince -wincing -wind -wing -winking -winner -winnings -winter -wipe -wired -wireless -wiring -wiry -wisdom -wise -wish -wisplike -wispy -wistful -wizard -wobble -wobbling -wobbly -wok -wolf -wolverine -womanhood -womankind -womanless -womanlike -womanly -womb -woof -wooing -wool -woozy -word -work -worried -worrier -worrisome -worry -worsening -worshiper -worst -wound -woven -wow -wrangle -wrath -wreath -wreckage -wrecker -wrecking -wrench -wriggle -wriggly -wrinkle -wrinkly -wrist -writing -written -wrongdoer -wronged -wrongful -wrongly -wrongness -wrought -xbox -xerox -yahoo -yam -yanking -yapping -yard -yarn -yeah -yearbook -yearling -yearly -yearning -yeast -yelling -yelp -yen -yesterday -yiddish -yield -yin -yippee -yo-yo -yodel -yoga -yogurt -yonder -yoyo -yummy -zap -zealous -zebra -zen -zeppelin -zero -zestfully -zesty -zigzagged -zipfile -zipping -zippy -zips -zit -zodiac -zombie -zone -zoning -zookeeper -zoologist -zoology -zoom diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_prefixed.txt b/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_prefixed.txt deleted file mode 100644 index 9ac732f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_prefixed.txt +++ /dev/null @@ -1,1296 +0,0 @@ -aardvark -abandoned -abbreviate -abdomen -abhorrence -abiding -abnormal -abrasion -absorbing -abundant -abyss -academy -accountant -acetone -achiness -acid -acoustics -acquire -acrobat -actress -acuteness -aerosol -aesthetic -affidavit -afloat -afraid -aftershave -again -agency -aggressor -aghast -agitate -agnostic -agonizing -agreeing -aidless -aimlessly -ajar -alarmclock -albatross -alchemy -alfalfa -algae -aliens -alkaline -almanac -alongside -alphabet -already -also -altitude -aluminum -always -amazingly -ambulance -amendment -amiable -ammunition -amnesty -amoeba -amplifier -amuser -anagram -anchor -android -anesthesia -angelfish -animal -anklet -announcer -anonymous -answer -antelope -anxiety -anyplace -aorta -apartment -apnea -apostrophe -apple -apricot -aquamarine -arachnid -arbitrate -ardently -arena -argument -aristocrat -armchair -aromatic -arrowhead -arsonist -artichoke -asbestos -ascend -aseptic -ashamed -asinine -asleep -asocial -asparagus -astronaut -asymmetric -atlas -atmosphere -atom -atrocious -attic -atypical -auctioneer -auditorium -augmented -auspicious -automobile -auxiliary -avalanche -avenue -aviator -avocado -awareness -awhile -awkward -awning -awoke -axially -azalea -babbling -backpack -badass -bagpipe -bakery -balancing -bamboo -banana -barracuda -basket -bathrobe -bazooka -blade -blender -blimp -blouse -blurred -boatyard -bobcat -body -bogusness -bohemian -boiler -bonnet -boots -borough -bossiness -bottle -bouquet -boxlike -breath -briefcase -broom -brushes -bubblegum -buckle -buddhist -buffalo -bullfrog -bunny -busboy -buzzard -cabin -cactus -cadillac -cafeteria -cage -cahoots -cajoling -cakewalk -calculator -camera -canister -capsule -carrot -cashew -cathedral -caucasian -caviar -ceasefire -cedar -celery -cement -census -ceramics -cesspool -chalkboard -cheesecake -chimney -chlorine -chopsticks -chrome -chute -cilantro -cinnamon -circle -cityscape -civilian -clay -clergyman -clipboard -clock -clubhouse -coathanger -cobweb -coconut -codeword -coexistent -coffeecake -cognitive -cohabitate -collarbone -computer -confetti -copier -cornea -cosmetics -cotton -couch -coverless -coyote -coziness -crawfish -crewmember -crib -croissant -crumble -crystal -cubical -cucumber -cuddly -cufflink -cuisine -culprit -cup -curry -cushion -cuticle -cybernetic -cyclist -cylinder -cymbal -cynicism -cypress -cytoplasm -dachshund -daffodil -dagger -dairy -dalmatian -dandelion -dartboard -dastardly -datebook -daughter -dawn -daytime -dazzler -dealer -debris -decal -dedicate -deepness -defrost -degree -dehydrator -deliverer -democrat -dentist -deodorant -depot -deranged -desktop -detergent -device -dexterity -diamond -dibs -dictionary -diffuser -digit -dilated -dimple -dinnerware -dioxide -diploma -directory -dishcloth -ditto -dividers -dizziness -doctor -dodge -doll -dominoes -donut -doorstep -dorsal -double -downstairs -dozed -drainpipe -dresser -driftwood -droppings -drum -dryer -dubiously -duckling -duffel -dugout -dumpster -duplex -durable -dustpan -dutiful -duvet -dwarfism -dwelling -dwindling -dynamite -dyslexia -eagerness -earlobe -easel -eavesdrop -ebook -eccentric -echoless -eclipse -ecosystem -ecstasy -edged -editor -educator -eelworm -eerie -effects -eggnog -egomaniac -ejection -elastic -elbow -elderly -elephant -elfishly -eliminator -elk -elliptical -elongated -elsewhere -elusive -elves -emancipate -embroidery -emcee -emerald -emission -emoticon -emperor -emulate -enactment -enchilada -endorphin -energy -enforcer -engine -enhance -enigmatic -enjoyably -enlarged -enormous -enquirer -enrollment -ensemble -entryway -enunciate -envoy -enzyme -epidemic -equipment -erasable -ergonomic -erratic -eruption -escalator -eskimo -esophagus -espresso -essay -estrogen -etching -eternal -ethics -etiquette -eucalyptus -eulogy -euphemism -euthanize -evacuation -evergreen -evidence -evolution -exam -excerpt -exerciser -exfoliate -exhale -exist -exorcist -explode -exquisite -exterior -exuberant -fabric -factory -faded -failsafe -falcon -family -fanfare -fasten -faucet -favorite -feasibly -february -federal -feedback -feigned -feline -femur -fence -ferret -festival -fettuccine -feudalist -feverish -fiberglass -fictitious -fiddle -figurine -fillet -finalist -fiscally -fixture -flashlight -fleshiness -flight -florist -flypaper -foamless -focus -foggy -folksong -fondue -footpath -fossil -fountain -fox -fragment -freeway -fridge -frosting -fruit -fryingpan -gadget -gainfully -gallstone -gamekeeper -gangway -garlic -gaslight -gathering -gauntlet -gearbox -gecko -gem -generator -geographer -gerbil -gesture -getaway -geyser -ghoulishly -gibberish -giddiness -giftshop -gigabyte -gimmick -giraffe -giveaway -gizmo -glasses -gleeful -glisten -glove -glucose -glycerin -gnarly -gnomish -goatskin -goggles -goldfish -gong -gooey -gorgeous -gosling -gothic -gourmet -governor -grape -greyhound -grill -groundhog -grumbling -guacamole -guerrilla -guitar -gullible -gumdrop -gurgling -gusto -gutless -gymnast -gynecology -gyration -habitat -hacking -haggard -haiku -halogen -hamburger -handgun -happiness -hardhat -hastily -hatchling -haughty -hazelnut -headband -hedgehog -hefty -heinously -helmet -hemoglobin -henceforth -herbs -hesitation -hexagon -hubcap -huddling -huff -hugeness -hullabaloo -human -hunter -hurricane -hushing -hyacinth -hybrid -hydrant -hygienist -hypnotist -ibuprofen -icepack -icing -iconic -identical -idiocy -idly -igloo -ignition -iguana -illuminate -imaging -imbecile -imitator -immigrant -imprint -iodine -ionosphere -ipad -iphone -iridescent -irksome -iron -irrigation -island -isotope -issueless -italicize -itemizer -itinerary -itunes -ivory -jabbering -jackrabbit -jaguar -jailhouse -jalapeno -jamboree -janitor -jarring -jasmine -jaundice -jawbreaker -jaywalker -jazz -jealous -jeep -jelly -jeopardize -jersey -jetski -jezebel -jiffy -jigsaw -jingling -jobholder -jockstrap -jogging -john -joinable -jokingly -journal -jovial -joystick -jubilant -judiciary -juggle -juice -jujitsu -jukebox -jumpiness -junkyard -juror -justifying -juvenile -kabob -kamikaze -kangaroo -karate -kayak -keepsake -kennel -kerosene -ketchup -khaki -kickstand -kilogram -kimono -kingdom -kiosk -kissing -kite -kleenex -knapsack -kneecap -knickers -koala -krypton -laboratory -ladder -lakefront -lantern -laptop -laryngitis -lasagna -latch -laundry -lavender -laxative -lazybones -lecturer -leftover -leggings -leisure -lemon -length -leopard -leprechaun -lettuce -leukemia -levers -lewdness -liability -library -licorice -lifeboat -lightbulb -likewise -lilac -limousine -lint -lioness -lipstick -liquid -listless -litter -liverwurst -lizard -llama -luau -lubricant -lucidity -ludicrous -luggage -lukewarm -lullaby -lumberjack -lunchbox -luridness -luscious -luxurious -lyrics -macaroni -maestro -magazine -mahogany -maimed -majority -makeover -malformed -mammal -mango -mapmaker -marbles -massager -matchstick -maverick -maximum -mayonnaise -moaning -mobilize -moccasin -modify -moisture -molecule -momentum -monastery -moonshine -mortuary -mosquito -motorcycle -mousetrap -movie -mower -mozzarella -muckiness -mudflow -mugshot -mule -mummy -mundane -muppet -mural -mustard -mutation -myriad -myspace -myth -nail -namesake -nanosecond -napkin -narrator -nastiness -natives -nautically -navigate -nearest -nebula -nectar -nefarious -negotiator -neither -nemesis -neoliberal -nephew -nervously -nest -netting -neuron -nevermore -nextdoor -nicotine -niece -nimbleness -nintendo -nirvana -nuclear -nugget -nuisance -nullify -numbing -nuptials -nursery -nutcracker -nylon -oasis -oat -obediently -obituary -object -obliterate -obnoxious -observer -obtain -obvious -occupation -oceanic -octopus -ocular -office -oftentimes -oiliness -ointment -older -olympics -omissible -omnivorous -oncoming -onion -onlooker -onstage -onward -onyx -oomph -opaquely -opera -opium -opossum -opponent -optical -opulently -oscillator -osmosis -ostrich -otherwise -ought -outhouse -ovation -oven -owlish -oxford -oxidize -oxygen -oyster -ozone -pacemaker -padlock -pageant -pajamas -palm -pamphlet -pantyhose -paprika -parakeet -passport -patio -pauper -pavement -payphone -pebble -peculiarly -pedometer -pegboard -pelican -penguin -peony -pepperoni -peroxide -pesticide -petroleum -pewter -pharmacy -pheasant -phonebook -phrasing -physician -plank -pledge -plotted -plug -plywood -pneumonia -podiatrist -poetic -pogo -poison -poking -policeman -poncho -popcorn -porcupine -postcard -poultry -powerboat -prairie -pretzel -princess -propeller -prune -pry -pseudo -psychopath -publisher -pucker -pueblo -pulley -pumpkin -punchbowl -puppy -purse -pushup -putt -puzzle -pyramid -python -quarters -quesadilla -quilt -quote -racoon -radish -ragweed -railroad -rampantly -rancidity -rarity -raspberry -ravishing -rearrange -rebuilt -receipt -reentry -refinery -register -rehydrate -reimburse -rejoicing -rekindle -relic -remote -renovator -reopen -reporter -request -rerun -reservoir -retriever -reunion -revolver -rewrite -rhapsody -rhetoric -rhino -rhubarb -rhyme -ribbon -riches -ridden -rigidness -rimmed -riptide -riskily -ritzy -riverboat -roamer -robe -rocket -romancer -ropelike -rotisserie -roundtable -royal -rubber -rudderless -rugby -ruined -rulebook -rummage -running -rupture -rustproof -sabotage -sacrifice -saddlebag -saffron -sainthood -saltshaker -samurai -sandworm -sapphire -sardine -sassy -satchel -sauna -savage -saxophone -scarf -scenario -schoolbook -scientist -scooter -scrapbook -sculpture -scythe -secretary -sedative -segregator -seismology -selected -semicolon -senator -septum -sequence -serpent -sesame -settler -severely -shack -shelf -shirt -shovel -shrimp -shuttle -shyness -siamese -sibling -siesta -silicon -simmering -singles -sisterhood -sitcom -sixfold -sizable -skateboard -skeleton -skies -skulk -skylight -slapping -sled -slingshot -sloth -slumbering -smartphone -smelliness -smitten -smokestack -smudge -snapshot -sneezing -sniff -snowsuit -snugness -speakers -sphinx -spider -splashing -sponge -sprout -spur -spyglass -squirrel -statue -steamboat -stingray -stopwatch -strawberry -student -stylus -suave -subway -suction -suds -suffocate -sugar -suitcase -sulphur -superstore -surfer -sushi -swan -sweatshirt -swimwear -sword -sycamore -syllable -symphony -synagogue -syringes -systemize -tablespoon -taco -tadpole -taekwondo -tagalong -takeout -tallness -tamale -tanned -tapestry -tarantula -tastebud -tattoo -tavern -thaw -theater -thimble -thorn -throat -thumb -thwarting -tiara -tidbit -tiebreaker -tiger -timid -tinsel -tiptoeing -tirade -tissue -tractor -tree -tripod -trousers -trucks -tryout -tubeless -tuesday -tugboat -tulip -tumbleweed -tupperware -turtle -tusk -tutorial -tuxedo -tweezers -twins -tyrannical -ultrasound -umbrella -umpire -unarmored -unbuttoned -uncle -underwear -unevenness -unflavored -ungloved -unhinge -unicycle -unjustly -unknown -unlocking -unmarked -unnoticed -unopened -unpaved -unquenched -unroll -unscrewing -untied -unusual -unveiled -unwrinkled -unyielding -unzip -upbeat -upcountry -update -upfront -upgrade -upholstery -upkeep -upload -uppercut -upright -upstairs -uptown -upwind -uranium -urban -urchin -urethane -urgent -urologist -username -usher -utensil -utility -utmost -utopia -utterance -vacuum -vagrancy -valuables -vanquished -vaporizer -varied -vaseline -vegetable -vehicle -velcro -vendor -vertebrae -vestibule -veteran -vexingly -vicinity -videogame -viewfinder -vigilante -village -vinegar -violin -viperfish -virus -visor -vitamins -vivacious -vixen -vocalist -vogue -voicemail -volleyball -voucher -voyage -vulnerable -waffle -wagon -wakeup -walrus -wanderer -wasp -water -waving -wheat -whisper -wholesaler -wick -widow -wielder -wifeless -wikipedia -wildcat -windmill -wipeout -wired -wishbone -wizardry -wobbliness -wolverine -womb -woolworker -workbasket -wound -wrangle -wreckage -wristwatch -wrongdoing -xerox -xylophone -yacht -yahoo -yard -yearbook -yesterday -yiddish -yield -yo-yo -yodel -yogurt -yuppie -zealot -zebra -zeppelin -zestfully -zigzagged -zillion -zipping -zirconium -zodiac -zombie -zookeeper -zucchini diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_short.txt b/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_short.txt deleted file mode 100644 index 4c8baa4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/_data/wordsets/eff_short.txt +++ /dev/null @@ -1,1296 +0,0 @@ -acid -acorn -acre -acts -afar -affix -aged -agent -agile -aging -agony -ahead -aide -aids -aim -ajar -alarm -alias -alibi -alien -alike -alive -aloe -aloft -aloha -alone -amend -amino -ample -amuse -angel -anger -angle -ankle -apple -april -apron -aqua -area -arena -argue -arise -armed -armor -army -aroma -array -arson -art -ashen -ashes -atlas -atom -attic -audio -avert -avoid -awake -award -awoke -axis -bacon -badge -bagel -baggy -baked -baker -balmy -banjo -barge -barn -bash -basil -bask -batch -bath -baton -bats -blade -blank -blast -blaze -bleak -blend -bless -blimp -blink -bloat -blob -blog -blot -blunt -blurt -blush -boast -boat -body -boil -bok -bolt -boned -boney -bonus -bony -book -booth -boots -boss -botch -both -boxer -breed -bribe -brick -bride -brim -bring -brink -brisk -broad -broil -broke -brook -broom -brush -buck -bud -buggy -bulge -bulk -bully -bunch -bunny -bunt -bush -bust -busy -buzz -cable -cache -cadet -cage -cake -calm -cameo -canal -candy -cane -canon -cape -card -cargo -carol -carry -carve -case -cash -cause -cedar -chain -chair -chant -chaos -charm -chase -cheek -cheer -chef -chess -chest -chew -chief -chili -chill -chip -chomp -chop -chow -chuck -chump -chunk -churn -chute -cider -cinch -city -civic -civil -clad -claim -clamp -clap -clash -clasp -class -claw -clay -clean -clear -cleat -cleft -clerk -click -cling -clink -clip -cloak -clock -clone -cloth -cloud -clump -coach -coast -coat -cod -coil -coke -cola -cold -colt -coma -come -comic -comma -cone -cope -copy -coral -cork -cost -cot -couch -cough -cover -cozy -craft -cramp -crane -crank -crate -crave -crawl -crazy -creme -crepe -crept -crib -cried -crisp -crook -crop -cross -crowd -crown -crumb -crush -crust -cub -cult -cupid -cure -curl -curry -curse -curve -curvy -cushy -cut -cycle -dab -dad -daily -dairy -daisy -dance -dandy -darn -dart -dash -data -date -dawn -deaf -deal -dean -debit -debt -debug -decaf -decal -decay -deck -decor -decoy -deed -delay -denim -dense -dent -depth -derby -desk -dial -diary -dice -dig -dill -dime -dimly -diner -dingy -disco -dish -disk -ditch -ditzy -dizzy -dock -dodge -doing -doll -dome -donor -donut -dose -dot -dove -down -dowry -doze -drab -drama -drank -draw -dress -dried -drift -drill -drive -drone -droop -drove -drown -drum -dry -duck -duct -dude -dug -duke -duo -dusk -dust -duty -dwarf -dwell -eagle -early -earth -easel -east -eaten -eats -ebay -ebony -ebook -echo -edge -eel -eject -elbow -elder -elf -elk -elm -elope -elude -elves -email -emit -empty -emu -enter -entry -envoy -equal -erase -error -erupt -essay -etch -evade -even -evict -evil -evoke -exact -exit -fable -faced -fact -fade -fall -false -fancy -fang -fax -feast -feed -femur -fence -fend -ferry -fetal -fetch -fever -fiber -fifth -fifty -film -filth -final -finch -fit -five -flag -flaky -flame -flap -flask -fled -flick -fling -flint -flip -flirt -float -flock -flop -floss -flyer -foam -foe -fog -foil -folic -folk -food -fool -found -fox -foyer -frail -frame -fray -fresh -fried -frill -frisk -from -front -frost -froth -frown -froze -fruit -gag -gains -gala -game -gap -gas -gave -gear -gecko -geek -gem -genre -gift -gig -gills -given -giver -glad -glass -glide -gloss -glove -glow -glue -goal -going -golf -gong -good -gooey -goofy -gore -gown -grab -grain -grant -grape -graph -grasp -grass -grave -gravy -gray -green -greet -grew -grid -grief -grill -grip -grit -groom -grope -growl -grub -grunt -guide -gulf -gulp -gummy -guru -gush -gut -guy -habit -half -halo -halt -happy -harm -hash -hasty -hatch -hate -haven -hazel -hazy -heap -heat -heave -hedge -hefty -help -herbs -hers -hub -hug -hula -hull -human -humid -hump -hung -hunk -hunt -hurry -hurt -hush -hut -ice -icing -icon -icy -igloo -image -ion -iron -islam -issue -item -ivory -ivy -jab -jam -jaws -jazz -jeep -jelly -jet -jiffy -job -jog -jolly -jolt -jot -joy -judge -juice -juicy -july -jumbo -jump -junky -juror -jury -keep -keg -kept -kick -kilt -king -kite -kitty -kiwi -knee -knelt -koala -kung -ladle -lady -lair -lake -lance -land -lapel -large -lash -lasso -last -latch -late -lazy -left -legal -lemon -lend -lens -lent -level -lever -lid -life -lift -lilac -lily -limb -limes -line -lint -lion -lip -list -lived -liver -lunar -lunch -lung -lurch -lure -lurk -lying -lyric -mace -maker -malt -mama -mango -manor -many -map -march -mardi -marry -mash -match -mate -math -moan -mocha -moist -mold -mom -moody -mop -morse -most -motor -motto -mount -mouse -mousy -mouth -move -movie -mower -mud -mug -mulch -mule -mull -mumbo -mummy -mural -muse -music -musky -mute -nacho -nag -nail -name -nanny -nap -navy -near -neat -neon -nerd -nest -net -next -niece -ninth -nutty -oak -oasis -oat -ocean -oil -old -olive -omen -onion -only -ooze -opal -open -opera -opt -otter -ouch -ounce -outer -oval -oven -owl -ozone -pace -pagan -pager -palm -panda -panic -pants -panty -paper -park -party -pasta -patch -path -patio -payer -pecan -penny -pep -perch -perky -perm -pest -petal -petri -petty -photo -plank -plant -plaza -plead -plot -plow -pluck -plug -plus -poach -pod -poem -poet -pogo -point -poise -poker -polar -polio -polka -polo -pond -pony -poppy -pork -poser -pouch -pound -pout -power -prank -press -print -prior -prism -prize -probe -prong -proof -props -prude -prune -pry -pug -pull -pulp -pulse -puma -punch -punk -pupil -puppy -purr -purse -push -putt -quack -quake -query -quiet -quill -quilt -quit -quota -quote -rabid -race -rack -radar -radio -raft -rage -raid -rail -rake -rally -ramp -ranch -range -rank -rant -rash -raven -reach -react -ream -rebel -recap -relax -relay -relic -remix -repay -repel -reply -rerun -reset -rhyme -rice -rich -ride -rigid -rigor -rinse -riot -ripen -rise -risk -ritzy -rival -river -roast -robe -robin -rock -rogue -roman -romp -rope -rover -royal -ruby -rug -ruin -rule -runny -rush -rust -rut -sadly -sage -said -saint -salad -salon -salsa -salt -same -sandy -santa -satin -sauna -saved -savor -sax -say -scale -scam -scan -scare -scarf -scary -scoff -scold -scoop -scoot -scope -score -scorn -scout -scowl -scrap -scrub -scuba -scuff -sect -sedan -self -send -sepia -serve -set -seven -shack -shade -shady -shaft -shaky -sham -shape -share -sharp -shed -sheep -sheet -shelf -shell -shine -shiny -ship -shirt -shock -shop -shore -shout -shove -shown -showy -shred -shrug -shun -shush -shut -shy -sift -silk -silly -silo -sip -siren -sixth -size -skate -skew -skid -skier -skies -skip -skirt -skit -sky -slab -slack -slain -slam -slang -slash -slate -slaw -sled -sleek -sleep -sleet -slept -slice -slick -slimy -sling -slip -slit -slob -slot -slug -slum -slurp -slush -small -smash -smell -smile -smirk -smog -snack -snap -snare -snarl -sneak -sneer -sniff -snore -snort -snout -snowy -snub -snuff -speak -speed -spend -spent -spew -spied -spill -spiny -spoil -spoke -spoof -spool -spoon -sport -spot -spout -spray -spree -spur -squad -squat -squid -stack -staff -stage -stain -stall -stamp -stand -stank -stark -start -stash -state -stays -steam -steep -stem -step -stew -stick -sting -stir -stock -stole -stomp -stony -stood -stool -stoop -stop -storm -stout -stove -straw -stray -strut -stuck -stud -stuff -stump -stung -stunt -suds -sugar -sulk -surf -sushi -swab -swan -swarm -sway -swear -sweat -sweep -swell -swept -swim -swing -swipe -swirl -swoop -swore -syrup -tacky -taco -tag -take -tall -talon -tamer -tank -taper -taps -tarot -tart -task -taste -tasty -taunt -thank -thaw -theft -theme -thigh -thing -think -thong -thorn -those -throb -thud -thumb -thump -thus -tiara -tidal -tidy -tiger -tile -tilt -tint -tiny -trace -track -trade -train -trait -trap -trash -tray -treat -tree -trek -trend -trial -tribe -trick -trio -trout -truce -truck -trump -trunk -try -tug -tulip -tummy -turf -tusk -tutor -tutu -tux -tweak -tweet -twice -twine -twins -twirl -twist -uncle -uncut -undo -unify -union -unit -untie -upon -upper -urban -used -user -usher -utter -value -vapor -vegan -venue -verse -vest -veto -vice -video -view -viral -virus -visa -visor -vixen -vocal -voice -void -volt -voter -vowel -wad -wafer -wager -wages -wagon -wake -walk -wand -wasp -watch -water -wavy -wheat -whiff -whole -whoop -wick -widen -widow -width -wife -wifi -wilt -wimp -wind -wing -wink -wipe -wired -wiry -wise -wish -wispy -wok -wolf -womb -wool -woozy -word -work -worry -wound -woven -wrath -wreck -wrist -xerox -yahoo -yam -yard -year -yeast -yelp -yield -yo-yo -yodel -yoga -yoyo -yummy -zebra -zero -zesty -zippy -zone -zoom diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/apache.py b/backend/venv39/lib/python3.9/site-packages/passlib/apache.py deleted file mode 100644 index a75f2cf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/apache.py +++ /dev/null @@ -1,1255 +0,0 @@ -"""passlib.apache - apache password support""" -# XXX: relocate this to passlib.ext.apache? -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -import os -from warnings import warn -# site -# pkg -from passlib import exc, registry -from passlib.context import CryptContext -from passlib.exc import ExpectedStringError -from passlib.hash import htdigest -from passlib.utils import render_bytes, to_bytes, is_ascii_codec -from passlib.utils.decor import deprecated_method -from passlib.utils.compat import join_bytes, unicode, BytesIO, PY3 -# local -__all__ = [ - 'HtpasswdFile', - 'HtdigestFile', -] - -#============================================================================= -# constants & support -#============================================================================= -_UNSET = object() - -_BCOLON = b":" -_BHASH = b"#" - -# byte values that aren't allowed in fields. -_INVALID_FIELD_CHARS = b":\n\r\t\x00" - -#: _CommonFile._source token types -_SKIPPED = "skipped" -_RECORD = "record" - -#============================================================================= -# common helpers -#============================================================================= -class _CommonFile(object): - """common framework for HtpasswdFile & HtdigestFile""" - #=================================================================== - # instance attrs - #=================================================================== - - # charset encoding used by file (defaults to utf-8) - encoding = None - - # whether users() and other public methods should return unicode or bytes? - # (defaults to False under PY2, True under PY3) - return_unicode = None - - # if bound to local file, these will be set. - _path = None # local file path - _mtime = None # mtime when last loaded, or 0 - - # if true, automatically save to local file after changes are made. - autosave = False - - # dict mapping key -> value for all records in database. - # (e.g. user => hash for Htpasswd) - _records = None - - #: list of tokens for recreating original file contents when saving. if present, - #: will be sequence of (_SKIPPED, b"whitespace/comments") and (_RECORD, ) tuples. - _source = None - - #=================================================================== - # alt constuctors - #=================================================================== - @classmethod - def from_string(cls, data, **kwds): - """create new object from raw string. - - :type data: unicode or bytes - :arg data: - database to load, as single string. - - :param \\*\\*kwds: - all other keywords are the same as in the class constructor - """ - if 'path' in kwds: - raise TypeError("'path' not accepted by from_string()") - self = cls(**kwds) - self.load_string(data) - return self - - @classmethod - def from_path(cls, path, **kwds): - """create new object from file, without binding object to file. - - :type path: str - :arg path: - local filepath to load from - - :param \\*\\*kwds: - all other keywords are the same as in the class constructor - """ - self = cls(**kwds) - self.load(path) - return self - - #=================================================================== - # init - #=================================================================== - def __init__(self, path=None, new=False, autoload=True, autosave=False, - encoding="utf-8", return_unicode=PY3, - ): - # set encoding - if not encoding: - warn("``encoding=None`` is deprecated as of Passlib 1.6, " - "and will cause a ValueError in Passlib 1.8, " - "use ``return_unicode=False`` instead.", - DeprecationWarning, stacklevel=2) - encoding = "utf-8" - return_unicode = False - elif not is_ascii_codec(encoding): - # htpasswd/htdigest files assumes 1-byte chars, and use ":" separator, - # so only ascii-compatible encodings are allowed. - raise ValueError("encoding must be 7-bit ascii compatible") - self.encoding = encoding - - # set other attrs - self.return_unicode = return_unicode - self.autosave = autosave - self._path = path - self._mtime = 0 - - # init db - if not autoload: - warn("``autoload=False`` is deprecated as of Passlib 1.6, " - "and will be removed in Passlib 1.8, use ``new=True`` instead", - DeprecationWarning, stacklevel=2) - new = True - if path and not new: - self.load() - else: - self._records = {} - self._source = [] - - def __repr__(self): - tail = '' - if self.autosave: - tail += ' autosave=True' - if self._path: - tail += ' path=%r' % self._path - if self.encoding != "utf-8": - tail += ' encoding=%r' % self.encoding - return "<%s 0x%0x%s>" % (self.__class__.__name__, id(self), tail) - - # NOTE: ``path`` is a property so that ``_mtime`` is wiped when it's set. - - @property - def path(self): - return self._path - - @path.setter - def path(self, value): - if value != self._path: - self._mtime = 0 - self._path = value - - @property - def mtime(self): - """modify time when last loaded (if bound to a local file)""" - return self._mtime - - #=================================================================== - # loading - #=================================================================== - def load_if_changed(self): - """Reload from ``self.path`` only if file has changed since last load""" - if not self._path: - raise RuntimeError("%r is not bound to a local file" % self) - if self._mtime and self._mtime == os.path.getmtime(self._path): - return False - self.load() - return True - - def load(self, path=None, force=True): - """Load state from local file. - If no path is specified, attempts to load from ``self.path``. - - :type path: str - :arg path: local file to load from - - :type force: bool - :param force: - if ``force=False``, only load from ``self.path`` if file - has changed since last load. - - .. deprecated:: 1.6 - This keyword will be removed in Passlib 1.8; - Applications should use :meth:`load_if_changed` instead. - """ - if path is not None: - with open(path, "rb") as fh: - self._mtime = 0 - self._load_lines(fh) - elif not force: - warn("%(name)s.load(force=False) is deprecated as of Passlib 1.6," - "and will be removed in Passlib 1.8; " - "use %(name)s.load_if_changed() instead." % - dict(name=self.__class__.__name__), - DeprecationWarning, stacklevel=2) - return self.load_if_changed() - elif self._path: - with open(self._path, "rb") as fh: - self._mtime = os.path.getmtime(self._path) - self._load_lines(fh) - else: - raise RuntimeError("%s().path is not set, an explicit path is required" % - self.__class__.__name__) - return True - - def load_string(self, data): - """Load state from unicode or bytes string, replacing current state""" - data = to_bytes(data, self.encoding, "data") - self._mtime = 0 - self._load_lines(BytesIO(data)) - - def _load_lines(self, lines): - """load from sequence of lists""" - parse = self._parse_record - records = {} - source = [] - skipped = b'' - for idx, line in enumerate(lines): - # NOTE: per htpasswd source (https://github.com/apache/httpd/blob/trunk/support/htpasswd.c), - # lines with only whitespace, or with "#" as first non-whitespace char, - # are left alone / ignored. - tmp = line.lstrip() - if not tmp or tmp.startswith(_BHASH): - skipped += line - continue - - # parse valid line - key, value = parse(line, idx+1) - - # NOTE: if multiple entries for a key, we use the first one, - # which seems to match htpasswd source - if key in records: - log.warning("username occurs multiple times in source file: %r" % key) - skipped += line - continue - - # flush buffer of skipped whitespace lines - if skipped: - source.append((_SKIPPED, skipped)) - skipped = b'' - - # store new user line - records[key] = value - source.append((_RECORD, key)) - - # don't bother preserving trailing whitespace, but do preserve trailing comments - if skipped.rstrip(): - source.append((_SKIPPED, skipped)) - - # NOTE: not replacing ._records until parsing succeeds, so loading is atomic. - self._records = records - self._source = source - - def _parse_record(self, record, lineno): # pragma: no cover - abstract method - """parse line of file into (key, value) pair""" - raise NotImplementedError("should be implemented in subclass") - - def _set_record(self, key, value): - """ - helper for setting record which takes care of inserting source line if needed; - - :returns: - bool if key already present - """ - records = self._records - existing = (key in records) - records[key] = value - if not existing: - self._source.append((_RECORD, key)) - return existing - - #=================================================================== - # saving - #=================================================================== - def _autosave(self): - """subclass helper to call save() after any changes""" - if self.autosave and self._path: - self.save() - - def save(self, path=None): - """Save current state to file. - If no path is specified, attempts to save to ``self.path``. - """ - if path is not None: - with open(path, "wb") as fh: - fh.writelines(self._iter_lines()) - elif self._path: - self.save(self._path) - self._mtime = os.path.getmtime(self._path) - else: - raise RuntimeError("%s().path is not set, cannot autosave" % - self.__class__.__name__) - - def to_string(self): - """Export current state as a string of bytes""" - return join_bytes(self._iter_lines()) - - # def clean(self): - # """ - # discard any comments or whitespace that were being preserved from the source file, - # and re-sort keys in alphabetical order - # """ - # self._source = [(_RECORD, key) for key in sorted(self._records)] - # self._autosave() - - def _iter_lines(self): - """iterator yielding lines of database""" - # NOTE: this relies on being an OrderedDict so that it outputs - # records in a deterministic order. - records = self._records - if __debug__: - pending = set(records) - for action, content in self._source: - if action == _SKIPPED: - # 'content' is whitespace/comments to write - yield content - else: - assert action == _RECORD - # 'content' is record key - if content not in records: - # record was deleted - # NOTE: doing it lazily like this so deleting & re-adding user - # preserves their original location in the file. - continue - yield self._render_record(content, records[content]) - if __debug__: - pending.remove(content) - if __debug__: - # sanity check that we actually wrote all the records - # (otherwise _source & _records are somehow out of sync) - assert not pending, "failed to write all records: missing=%r" % (pending,) - - def _render_record(self, key, value): # pragma: no cover - abstract method - """given key/value pair, encode as line of file""" - raise NotImplementedError("should be implemented in subclass") - - #=================================================================== - # field encoding - #=================================================================== - def _encode_user(self, user): - """user-specific wrapper for _encode_field()""" - return self._encode_field(user, "user") - - def _encode_realm(self, realm): # pragma: no cover - abstract method - """realm-specific wrapper for _encode_field()""" - return self._encode_field(realm, "realm") - - def _encode_field(self, value, param="field"): - """convert field to internal representation. - - internal representation is always bytes. byte strings are left as-is, - unicode strings encoding using file's default encoding (or ``utf-8`` - if no encoding has been specified). - - :raises UnicodeEncodeError: - if unicode value cannot be encoded using default encoding. - - :raises ValueError: - if resulting byte string contains a forbidden character, - or is too long (>255 bytes). - - :returns: - encoded identifer as bytes - """ - if isinstance(value, unicode): - value = value.encode(self.encoding) - elif not isinstance(value, bytes): - raise ExpectedStringError(value, param) - if len(value) > 255: - raise ValueError("%s must be at most 255 characters: %r" % - (param, value)) - if any(c in _INVALID_FIELD_CHARS for c in value): - raise ValueError("%s contains invalid characters: %r" % - (param, value,)) - return value - - def _decode_field(self, value): - """decode field from internal representation to format - returns by users() method, etc. - - :raises UnicodeDecodeError: - if unicode value cannot be decoded using default encoding. - (usually indicates wrong encoding set for file). - - :returns: - field as unicode or bytes, as appropriate. - """ - assert isinstance(value, bytes), "expected value to be bytes" - if self.return_unicode: - return value.decode(self.encoding) - else: - return value - - # FIXME: htpasswd doc says passwords limited to 255 chars under Windows & MPE, - # and that longer ones are truncated. this may be side-effect of those - # platforms supporting the 'plaintext' scheme. these classes don't currently - # check for this. - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# htpasswd context -# -# This section sets up a CryptContexts to mimic what schemes Apache -# (and the htpasswd tool) should support on the current system. -# -# Apache has long-time supported some basic builtin schemes (listed below), -# as well as the host's crypt() method -- though it's limited to being able -# to *verify* any scheme using that method, but can only generate "des_crypt" hashes. -# -# Apache 2.4 added builtin bcrypt support (even for platforms w/o native support). -# c.f. http://httpd.apache.org/docs/2.4/programs/htpasswd.html vs the 2.2 docs. -#============================================================================= - -#: set of default schemes that (if chosen) should be using bcrypt, -#: but can't due to lack of bcrypt. -_warn_no_bcrypt = set() - -def _init_default_schemes(): - - #: pick strongest one for host - host_best = None - for name in ["bcrypt", "sha256_crypt"]: - if registry.has_os_crypt_support(name): - host_best = name - break - - # check if we have a bcrypt backend -- otherwise issue warning - # XXX: would like to not spam this unless the user *requests* apache 24 - bcrypt = "bcrypt" if registry.has_backend("bcrypt") else None - _warn_no_bcrypt.clear() - if not bcrypt: - _warn_no_bcrypt.update(["portable_apache_24", "host_apache_24", - "linux_apache_24", "portable", "host"]) - - defaults = dict( - # strongest hash builtin to specific apache version - portable_apache_24=bcrypt or "apr_md5_crypt", - portable_apache_22="apr_md5_crypt", - - # strongest hash across current host & specific apache version - host_apache_24=bcrypt or host_best or "apr_md5_crypt", - host_apache_22=host_best or "apr_md5_crypt", - - # strongest hash on a linux host - linux_apache_24=bcrypt or "sha256_crypt", - linux_apache_22="sha256_crypt", - ) - - # set latest-apache version aliases - # XXX: could check for apache install, and pick correct host 22/24 default? - # could reuse _detect_htpasswd() helper in UTs - defaults.update( - portable=defaults['portable_apache_24'], - host=defaults['host_apache_24'], - ) - return defaults - -#: dict mapping default alias -> appropriate scheme -htpasswd_defaults = _init_default_schemes() - -def _init_htpasswd_context(): - - # start with schemes built into apache - schemes = [ - # builtin support added in apache 2.4 - # (https://bz.apache.org/bugzilla/show_bug.cgi?id=49288) - "bcrypt", - - # support not "builtin" to apache, instead it requires support through host's crypt(). - # adding them here to allow editing htpasswd under windows and then deploying under unix. - "sha256_crypt", - "sha512_crypt", - "des_crypt", - - # apache default as of 2.2.18, and still default in 2.4 - "apr_md5_crypt", - - # NOTE: apache says ONLY intended for transitioning htpasswd <-> ldap - "ldap_sha1", - - # NOTE: apache says ONLY supported on Windows, Netware, TPF - "plaintext" - ] - - # apache can verify anything supported by the native crypt(), - # though htpasswd tool can only generate a limited set of hashes. - # (this list may overlap w/ builtin apache schemes) - schemes.extend(registry.get_supported_os_crypt_schemes()) - - # hack to remove dups and sort into preferred order - preferred = schemes[:3] + ["apr_md5_crypt"] + schemes - schemes = sorted(set(schemes), key=preferred.index) - - # create context object - return CryptContext( - schemes=schemes, - - # NOTE: default will change to "portable" in passlib 2.0 - default=htpasswd_defaults['portable_apache_22'], - - # NOTE: bcrypt "2y" is required, "2b" isn't recognized by libapr (issue 95) - bcrypt__ident="2y", - ) - -#: CryptContext configured to match htpasswd -htpasswd_context = _init_htpasswd_context() - -#============================================================================= -# htpasswd editing -#============================================================================= - -class HtpasswdFile(_CommonFile): - """class for reading & writing Htpasswd files. - - The class constructor accepts the following arguments: - - :type path: filepath - :param path: - - Specifies path to htpasswd file, use to implicitly load from and save to. - - This class has two modes of operation: - - 1. It can be "bound" to a local file by passing a ``path`` to the class - constructor. In this case it will load the contents of the file when - created, and the :meth:`load` and :meth:`save` methods will automatically - load from and save to that file if they are called without arguments. - - 2. Alternately, it can exist as an independant object, in which case - :meth:`load` and :meth:`save` will require an explicit path to be - provided whenever they are called. As well, ``autosave`` behavior - will not be available. - - This feature is new in Passlib 1.6, and is the default if no - ``path`` value is provided to the constructor. - - This is also exposed as a readonly instance attribute. - - :type new: bool - :param new: - - Normally, if *path* is specified, :class:`HtpasswdFile` will - immediately load the contents of the file. However, when creating - a new htpasswd file, applications can set ``new=True`` so that - the existing file (if any) will not be loaded. - - .. versionadded:: 1.6 - This feature was previously enabled by setting ``autoload=False``. - That alias has been deprecated, and will be removed in Passlib 1.8 - - :type autosave: bool - :param autosave: - - Normally, any changes made to an :class:`HtpasswdFile` instance - will not be saved until :meth:`save` is explicitly called. However, - if ``autosave=True`` is specified, any changes made will be - saved to disk immediately (assuming *path* has been set). - - This is also exposed as a writeable instance attribute. - - :type encoding: str - :param encoding: - - Optionally specify character encoding used to read/write file - and hash passwords. Defaults to ``utf-8``, though ``latin-1`` - is the only other commonly encountered encoding. - - This is also exposed as a readonly instance attribute. - - :type default_scheme: str - :param default_scheme: - Optionally specify default scheme to use when encoding new passwords. - - This can be any of the schemes with builtin Apache support, - OR natively supported by the host OS's :func:`crypt.crypt` function. - - * Builtin schemes include ``"bcrypt"`` (apache 2.4+), ``"apr_md5_crypt"`, - and ``"des_crypt"``. - - * Schemes commonly supported by Unix hosts - include ``"bcrypt"``, ``"sha256_crypt"``, and ``"des_crypt"``. - - In order to not have to sort out what you should use, - passlib offers a number of aliases, that will resolve - to the most appropriate scheme based on your needs: - - * ``"portable"``, ``"portable_apache_24"`` -- pick scheme that's portable across hosts - running apache >= 2.4. **This will be the default as of Passlib 2.0**. - - * ``"portable_apache_22"`` -- pick scheme that's portable across hosts - running apache >= 2.4. **This is the default up to Passlib 1.9**. - - * ``"host"``, ``"host_apache_24"`` -- pick strongest scheme supported by - apache >= 2.4 and/or host OS. - - * ``"host_apache_22"`` -- pick strongest scheme supported by - apache >= 2.2 and/or host OS. - - .. versionadded:: 1.6 - This keyword was previously named ``default``. That alias - has been deprecated, and will be removed in Passlib 1.8. - - .. versionchanged:: 1.6.3 - - Added support for ``"bcrypt"``, ``"sha256_crypt"``, and ``"portable"`` alias. - - .. versionchanged:: 1.7 - - Added apache 2.4 semantics, and additional aliases. - - :type context: :class:`~passlib.context.CryptContext` - :param context: - :class:`!CryptContext` instance used to create - and verify the hashes found in the htpasswd file. - The default value is a pre-built context which supports all - of the hashes officially allowed in an htpasswd file. - - This is also exposed as a readonly instance attribute. - - .. warning:: - - This option may be used to add support for non-standard hash - formats to an htpasswd file. However, the resulting file - will probably not be usable by another application, - and particularly not by Apache. - - :param autoload: - Set to ``False`` to prevent the constructor from automatically - loaded the file from disk. - - .. deprecated:: 1.6 - This has been replaced by the *new* keyword. - Instead of setting ``autoload=False``, you should use - ``new=True``. Support for this keyword will be removed - in Passlib 1.8. - - :param default: - Change the default algorithm used to hash new passwords. - - .. deprecated:: 1.6 - This has been renamed to *default_scheme* for clarity. - Support for this alias will be removed in Passlib 1.8. - - Loading & Saving - ================ - .. automethod:: load - .. automethod:: load_if_changed - .. automethod:: load_string - .. automethod:: save - .. automethod:: to_string - - Inspection - ================ - .. automethod:: users - .. automethod:: check_password - .. automethod:: get_hash - - Modification - ================ - .. automethod:: set_password - .. automethod:: delete - - Alternate Constructors - ====================== - .. automethod:: from_string - - Attributes - ========== - .. attribute:: path - - Path to local file that will be used as the default - for all :meth:`load` and :meth:`save` operations. - May be written to, initialized by the *path* constructor keyword. - - .. attribute:: autosave - - Writeable flag indicating whether changes will be automatically - written to *path*. - - Errors - ====== - :raises ValueError: - All of the methods in this class will raise a :exc:`ValueError` if - any user name contains a forbidden character (one of ``:\\r\\n\\t\\x00``), - or is longer than 255 characters. - """ - #=================================================================== - # instance attrs - #=================================================================== - - # NOTE: _records map stores for the key, and for the value, - # both in bytes which use self.encoding - - #=================================================================== - # init & serialization - #=================================================================== - def __init__(self, path=None, default_scheme=None, context=htpasswd_context, - **kwds): - if 'default' in kwds: - warn("``default`` is deprecated as of Passlib 1.6, " - "and will be removed in Passlib 1.8, it has been renamed " - "to ``default_scheem``.", - DeprecationWarning, stacklevel=2) - default_scheme = kwds.pop("default") - if default_scheme: - if default_scheme in _warn_no_bcrypt: - warn("HtpasswdFile: no bcrypt backends available, " - "using fallback for default scheme %r" % default_scheme, - exc.PasslibSecurityWarning) - default_scheme = htpasswd_defaults.get(default_scheme, default_scheme) - context = context.copy(default=default_scheme) - self.context = context - super(HtpasswdFile, self).__init__(path, **kwds) - - def _parse_record(self, record, lineno): - # NOTE: should return (user, hash) tuple - result = record.rstrip().split(_BCOLON) - if len(result) != 2: - raise ValueError("malformed htpasswd file (error reading line %d)" - % lineno) - return result - - def _render_record(self, user, hash): - return render_bytes("%s:%s\n", user, hash) - - #=================================================================== - # public methods - #=================================================================== - - def users(self): - """ - Return list of all users in database - """ - return [self._decode_field(user) for user in self._records] - - ##def has_user(self, user): - ## "check whether entry is present for user" - ## return self._encode_user(user) in self._records - - ##def rename(self, old, new): - ## """rename user account""" - ## old = self._encode_user(old) - ## new = self._encode_user(new) - ## hash = self._records.pop(old) - ## self._records[new] = hash - ## self._autosave() - - def set_password(self, user, password): - """Set password for user; adds user if needed. - - :returns: - * ``True`` if existing user was updated. - * ``False`` if user account was added. - - .. versionchanged:: 1.6 - This method was previously called ``update``, it was renamed - to prevent ambiguity with the dictionary method. - The old alias is deprecated, and will be removed in Passlib 1.8. - """ - hash = self.context.hash(password) - return self.set_hash(user, hash) - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="set_password") - def update(self, user, password): - """set password for user""" - return self.set_password(user, password) - - def get_hash(self, user): - """Return hash stored for user, or ``None`` if user not found. - - .. versionchanged:: 1.6 - This method was previously named ``find``, it was renamed - for clarity. The old name is deprecated, and will be removed - in Passlib 1.8. - """ - try: - return self._records[self._encode_user(user)] - except KeyError: - return None - - def set_hash(self, user, hash): - """ - semi-private helper which allows writing a hash directly; - adds user if needed. - - .. warning:: - does not (currently) do any validation of the hash string - - .. versionadded:: 1.7 - """ - # assert self.context.identify(hash), "unrecognized hash format" - if PY3 and isinstance(hash, str): - hash = hash.encode(self.encoding) - user = self._encode_user(user) - existing = self._set_record(user, hash) - self._autosave() - return existing - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="get_hash") - def find(self, user): - """return hash for user""" - return self.get_hash(user) - - # XXX: rename to something more explicit, like delete_user()? - def delete(self, user): - """Delete user's entry. - - :returns: - * ``True`` if user deleted. - * ``False`` if user not found. - """ - try: - del self._records[self._encode_user(user)] - except KeyError: - return False - self._autosave() - return True - - def check_password(self, user, password): - """ - Verify password for specified user. - If algorithm marked as deprecated by CryptContext, will automatically be re-hashed. - - :returns: - * ``None`` if user not found. - * ``False`` if user found, but password does not match. - * ``True`` if user found and password matches. - - .. versionchanged:: 1.6 - This method was previously called ``verify``, it was renamed - to prevent ambiguity with the :class:`!CryptContext` method. - The old alias is deprecated, and will be removed in Passlib 1.8. - """ - user = self._encode_user(user) - hash = self._records.get(user) - if hash is None: - return None - if isinstance(password, unicode): - # NOTE: encoding password to match file, making the assumption - # that server will use same encoding to hash the password. - password = password.encode(self.encoding) - ok, new_hash = self.context.verify_and_update(password, hash) - if ok and new_hash is not None: - # rehash user's password if old hash was deprecated - assert user in self._records # otherwise would have to use ._set_record() - self._records[user] = new_hash - self._autosave() - return ok - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="check_password") - def verify(self, user, password): - """verify password for user""" - return self.check_password(user, password) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# htdigest editing -#============================================================================= -class HtdigestFile(_CommonFile): - """class for reading & writing Htdigest files. - - The class constructor accepts the following arguments: - - :type path: filepath - :param path: - - Specifies path to htdigest file, use to implicitly load from and save to. - - This class has two modes of operation: - - 1. It can be "bound" to a local file by passing a ``path`` to the class - constructor. In this case it will load the contents of the file when - created, and the :meth:`load` and :meth:`save` methods will automatically - load from and save to that file if they are called without arguments. - - 2. Alternately, it can exist as an independant object, in which case - :meth:`load` and :meth:`save` will require an explicit path to be - provided whenever they are called. As well, ``autosave`` behavior - will not be available. - - This feature is new in Passlib 1.6, and is the default if no - ``path`` value is provided to the constructor. - - This is also exposed as a readonly instance attribute. - - :type default_realm: str - :param default_realm: - - If ``default_realm`` is set, all the :class:`HtdigestFile` - methods that require a realm will use this value if one is not - provided explicitly. If unset, they will raise an error stating - that an explicit realm is required. - - This is also exposed as a writeable instance attribute. - - .. versionadded:: 1.6 - - :type new: bool - :param new: - - Normally, if *path* is specified, :class:`HtdigestFile` will - immediately load the contents of the file. However, when creating - a new htpasswd file, applications can set ``new=True`` so that - the existing file (if any) will not be loaded. - - .. versionadded:: 1.6 - This feature was previously enabled by setting ``autoload=False``. - That alias has been deprecated, and will be removed in Passlib 1.8 - - :type autosave: bool - :param autosave: - - Normally, any changes made to an :class:`HtdigestFile` instance - will not be saved until :meth:`save` is explicitly called. However, - if ``autosave=True`` is specified, any changes made will be - saved to disk immediately (assuming *path* has been set). - - This is also exposed as a writeable instance attribute. - - :type encoding: str - :param encoding: - - Optionally specify character encoding used to read/write file - and hash passwords. Defaults to ``utf-8``, though ``latin-1`` - is the only other commonly encountered encoding. - - This is also exposed as a readonly instance attribute. - - :param autoload: - Set to ``False`` to prevent the constructor from automatically - loaded the file from disk. - - .. deprecated:: 1.6 - This has been replaced by the *new* keyword. - Instead of setting ``autoload=False``, you should use - ``new=True``. Support for this keyword will be removed - in Passlib 1.8. - - Loading & Saving - ================ - .. automethod:: load - .. automethod:: load_if_changed - .. automethod:: load_string - .. automethod:: save - .. automethod:: to_string - - Inspection - ========== - .. automethod:: realms - .. automethod:: users - .. automethod:: check_password(user[, realm], password) - .. automethod:: get_hash - - Modification - ============ - .. automethod:: set_password(user[, realm], password) - .. automethod:: delete - .. automethod:: delete_realm - - Alternate Constructors - ====================== - .. automethod:: from_string - - Attributes - ========== - .. attribute:: default_realm - - The default realm that will be used if one is not provided - to methods that require it. By default this is ``None``, - in which case an explicit realm must be provided for every - method call. Can be written to. - - .. attribute:: path - - Path to local file that will be used as the default - for all :meth:`load` and :meth:`save` operations. - May be written to, initialized by the *path* constructor keyword. - - .. attribute:: autosave - - Writeable flag indicating whether changes will be automatically - written to *path*. - - Errors - ====== - :raises ValueError: - All of the methods in this class will raise a :exc:`ValueError` if - any user name or realm contains a forbidden character (one of ``:\\r\\n\\t\\x00``), - or is longer than 255 characters. - """ - #=================================================================== - # instance attrs - #=================================================================== - - # NOTE: _records map stores (,) for the key, - # and as the value, all as bytes. - - # NOTE: unlike htpasswd, this class doesn't use a CryptContext, - # as only one hash format is supported: htdigest. - - # optionally specify default realm that will be used if none - # is provided to a method call. otherwise realm is always required. - default_realm = None - - #=================================================================== - # init & serialization - #=================================================================== - def __init__(self, path=None, default_realm=None, **kwds): - self.default_realm = default_realm - super(HtdigestFile, self).__init__(path, **kwds) - - def _parse_record(self, record, lineno): - result = record.rstrip().split(_BCOLON) - if len(result) != 3: - raise ValueError("malformed htdigest file (error reading line %d)" - % lineno) - user, realm, hash = result - return (user, realm), hash - - def _render_record(self, key, hash): - user, realm = key - return render_bytes("%s:%s:%s\n", user, realm, hash) - - def _require_realm(self, realm): - if realm is None: - realm = self.default_realm - if realm is None: - raise TypeError("you must specify a realm explicitly, " - "or set the default_realm attribute") - return realm - - def _encode_realm(self, realm): - realm = self._require_realm(realm) - return self._encode_field(realm, "realm") - - def _encode_key(self, user, realm): - return self._encode_user(user), self._encode_realm(realm) - - #=================================================================== - # public methods - #=================================================================== - - def realms(self): - """Return list of all realms in database""" - realms = set(key[1] for key in self._records) - return [self._decode_field(realm) for realm in realms] - - def users(self, realm=None): - """Return list of all users in specified realm. - - * uses ``self.default_realm`` if no realm explicitly provided. - * returns empty list if realm not found. - """ - realm = self._encode_realm(realm) - return [self._decode_field(key[0]) for key in self._records - if key[1] == realm] - - ##def has_user(self, user, realm=None): - ## "check if user+realm combination exists" - ## return self._encode_key(user,realm) in self._records - - ##def rename_realm(self, old, new): - ## """rename all accounts in realm""" - ## old = self._encode_realm(old) - ## new = self._encode_realm(new) - ## keys = [key for key in self._records if key[1] == old] - ## for key in keys: - ## hash = self._records.pop(key) - ## self._set_record((key[0], new), hash) - ## self._autosave() - ## return len(keys) - - ##def rename(self, old, new, realm=None): - ## """rename user account""" - ## old = self._encode_user(old) - ## new = self._encode_user(new) - ## realm = self._encode_realm(realm) - ## hash = self._records.pop((old,realm)) - ## self._set_record((new, realm), hash) - ## self._autosave() - - def set_password(self, user, realm=None, password=_UNSET): - """Set password for user; adds user & realm if needed. - - If ``self.default_realm`` has been set, this may be called - with the syntax ``set_password(user, password)``, - otherwise it must be called with all three arguments: - ``set_password(user, realm, password)``. - - :returns: - * ``True`` if existing user was updated - * ``False`` if user account added. - """ - if password is _UNSET: - # called w/ two args - (user, password), use default realm - realm, password = None, realm - realm = self._require_realm(realm) - hash = htdigest.hash(password, user, realm, encoding=self.encoding) - return self.set_hash(user, realm, hash) - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="set_password") - def update(self, user, realm, password): - """set password for user""" - return self.set_password(user, realm, password) - - def get_hash(self, user, realm=None): - """Return :class:`~passlib.hash.htdigest` hash stored for user. - - * uses ``self.default_realm`` if no realm explicitly provided. - * returns ``None`` if user or realm not found. - - .. versionchanged:: 1.6 - This method was previously named ``find``, it was renamed - for clarity. The old name is deprecated, and will be removed - in Passlib 1.8. - """ - key = self._encode_key(user, realm) - hash = self._records.get(key) - if hash is None: - return None - if PY3: - hash = hash.decode(self.encoding) - return hash - - def set_hash(self, user, realm=None, hash=_UNSET): - """ - semi-private helper which allows writing a hash directly; - adds user & realm if needed. - - If ``self.default_realm`` has been set, this may be called - with the syntax ``set_hash(user, hash)``, - otherwise it must be called with all three arguments: - ``set_hash(user, realm, hash)``. - - .. warning:: - does not (currently) do any validation of the hash string - - .. versionadded:: 1.7 - """ - if hash is _UNSET: - # called w/ two args - (user, hash), use default realm - realm, hash = None, realm - # assert htdigest.identify(hash), "unrecognized hash format" - if PY3 and isinstance(hash, str): - hash = hash.encode(self.encoding) - key = self._encode_key(user, realm) - existing = self._set_record(key, hash) - self._autosave() - return existing - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="get_hash") - def find(self, user, realm): - """return hash for user""" - return self.get_hash(user, realm) - - # XXX: rename to something more explicit, like delete_user()? - def delete(self, user, realm=None): - """Delete user's entry for specified realm. - - if realm is not specified, uses ``self.default_realm``. - - :returns: - * ``True`` if user deleted, - * ``False`` if user not found in realm. - """ - key = self._encode_key(user, realm) - try: - del self._records[key] - except KeyError: - return False - self._autosave() - return True - - def delete_realm(self, realm): - """Delete all users for specified realm. - - if realm is not specified, uses ``self.default_realm``. - - :returns: number of users deleted (0 if realm not found) - """ - realm = self._encode_realm(realm) - records = self._records - keys = [key for key in records if key[1] == realm] - for key in keys: - del records[key] - self._autosave() - return len(keys) - - def check_password(self, user, realm=None, password=_UNSET): - """Verify password for specified user + realm. - - If ``self.default_realm`` has been set, this may be called - with the syntax ``check_password(user, password)``, - otherwise it must be called with all three arguments: - ``check_password(user, realm, password)``. - - :returns: - * ``None`` if user or realm not found. - * ``False`` if user found, but password does not match. - * ``True`` if user found and password matches. - - .. versionchanged:: 1.6 - This method was previously called ``verify``, it was renamed - to prevent ambiguity with the :class:`!CryptContext` method. - The old alias is deprecated, and will be removed in Passlib 1.8. - """ - if password is _UNSET: - # called w/ two args - (user, password), use default realm - realm, password = None, realm - user = self._encode_user(user) - realm = self._encode_realm(realm) - hash = self._records.get((user,realm)) - if hash is None: - return None - return htdigest.verify(password, hash, user, realm, - encoding=self.encoding) - - @deprecated_method(deprecated="1.6", removed="1.8", - replacement="check_password") - def verify(self, user, realm, password): - """verify password for user""" - return self.check_password(user, realm, password) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/apps.py b/backend/venv39/lib/python3.9/site-packages/passlib/apps.py deleted file mode 100644 index 682bbff..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/apps.py +++ /dev/null @@ -1,245 +0,0 @@ -"""passlib.apps""" -#============================================================================= -# imports -#============================================================================= -# core -import logging; log = logging.getLogger(__name__) -from itertools import chain -# site -# pkg -from passlib import hash -from passlib.context import LazyCryptContext -from passlib.utils import sys_bits -# local -__all__ = [ - 'custom_app_context', - 'django_context', - 'ldap_context', 'ldap_nocrypt_context', - 'mysql_context', 'mysql4_context', 'mysql3_context', - 'phpass_context', - 'phpbb3_context', - 'postgres_context', -] - -#============================================================================= -# master containing all identifiable hashes -#============================================================================= -def _load_master_config(): - from passlib.registry import list_crypt_handlers - - # get master list - schemes = list_crypt_handlers() - - # exclude the ones we know have ambiguous or greedy identify() methods. - excluded = [ - # frequently confused for eachother - 'bigcrypt', - 'crypt16', - - # no good identifiers - 'cisco_pix', - 'cisco_type7', - 'htdigest', - 'mysql323', - 'oracle10', - - # all have same size - 'lmhash', - 'msdcc', - 'msdcc2', - 'nthash', - - # plaintext handlers - 'plaintext', - 'ldap_plaintext', - - # disabled handlers - 'django_disabled', - 'unix_disabled', - 'unix_fallback', - ] - for name in excluded: - schemes.remove(name) - - # return config - return dict(schemes=schemes, default="sha256_crypt") -master_context = LazyCryptContext(onload=_load_master_config) - -#============================================================================= -# for quickly bootstrapping new custom applications -#============================================================================= -custom_app_context = LazyCryptContext( - # choose some reasonbly strong schemes - schemes=["sha512_crypt", "sha256_crypt"], - - # set some useful global options - default="sha256_crypt" if sys_bits < 64 else "sha512_crypt", - - # set a good starting point for rounds selection - sha512_crypt__min_rounds = 535000, - sha256_crypt__min_rounds = 535000, - - # if the admin user category is selected, make a much stronger hash, - admin__sha512_crypt__min_rounds = 1024000, - admin__sha256_crypt__min_rounds = 1024000, - ) - -#============================================================================= -# django -#============================================================================= - -#----------------------------------------------------------------------- -# 1.0 -#----------------------------------------------------------------------- - -_django10_schemes = [ - "django_salted_sha1", - "django_salted_md5", - "django_des_crypt", - "hex_md5", - "django_disabled", -] - -django10_context = LazyCryptContext( - schemes=_django10_schemes, - default="django_salted_sha1", - deprecated=["hex_md5"], -) - -#----------------------------------------------------------------------- -# 1.4 -#----------------------------------------------------------------------- - -_django14_schemes = [ - "django_pbkdf2_sha256", - "django_pbkdf2_sha1", - "django_bcrypt" -] + _django10_schemes - -django14_context = LazyCryptContext( - schemes=_django14_schemes, - deprecated=_django10_schemes, -) - -#----------------------------------------------------------------------- -# 1.6 -#----------------------------------------------------------------------- - -_django16_schemes = list(_django14_schemes) -_django16_schemes.insert(1, "django_bcrypt_sha256") -django16_context = LazyCryptContext( - schemes=_django16_schemes, - deprecated=_django10_schemes, -) - -#----------------------------------------------------------------------- -# 1.10 -#----------------------------------------------------------------------- - -_django_110_schemes = [ - "django_pbkdf2_sha256", - "django_pbkdf2_sha1", - "django_argon2", - "django_bcrypt", - "django_bcrypt_sha256", - "django_disabled", -] -django110_context = LazyCryptContext(schemes=_django_110_schemes) - -#----------------------------------------------------------------------- -# 2.1 -#----------------------------------------------------------------------- - -_django21_schemes = list(_django_110_schemes) -_django21_schemes.remove("django_bcrypt") -django21_context = LazyCryptContext(schemes=_django21_schemes) - -#----------------------------------------------------------------------- -# latest -#----------------------------------------------------------------------- - -# this will always point to latest version in passlib -django_context = django21_context - -#============================================================================= -# ldap -#============================================================================= - -#: standard ldap schemes -std_ldap_schemes = [ - "ldap_salted_sha512", - "ldap_salted_sha256", - "ldap_salted_sha1", - "ldap_salted_md5", - "ldap_sha1", - "ldap_md5", - "ldap_plaintext", -] - -# create context with all std ldap schemes EXCEPT crypt -ldap_nocrypt_context = LazyCryptContext(std_ldap_schemes) - -# create context with all possible std ldap + ldap crypt schemes -def _iter_ldap_crypt_schemes(): - from passlib.utils import unix_crypt_schemes - return ('ldap_' + name for name in unix_crypt_schemes) - -def _iter_ldap_schemes(): - """helper which iterates over supported std ldap schemes""" - return chain(std_ldap_schemes, _iter_ldap_crypt_schemes()) -ldap_context = LazyCryptContext(_iter_ldap_schemes()) - -### create context with all std ldap schemes + crypt schemes for localhost -##def _iter_host_ldap_schemes(): -## "helper which iterates over supported std ldap schemes" -## from passlib.handlers.ldap_digests import get_host_ldap_crypt_schemes -## return chain(std_ldap_schemes, get_host_ldap_crypt_schemes()) -##ldap_host_context = LazyCryptContext(_iter_host_ldap_schemes()) - -#============================================================================= -# mysql -#============================================================================= -mysql3_context = LazyCryptContext(["mysql323"]) -mysql4_context = LazyCryptContext(["mysql41", "mysql323"], deprecated="mysql323") -mysql_context = mysql4_context # tracks latest mysql version supported - -#============================================================================= -# postgres -#============================================================================= -postgres_context = LazyCryptContext(["postgres_md5"]) - -#============================================================================= -# phpass & variants -#============================================================================= -def _create_phpass_policy(**kwds): - """helper to choose default alg based on bcrypt availability""" - kwds['default'] = 'bcrypt' if hash.bcrypt.has_backend() else 'phpass' - return kwds - -phpass_context = LazyCryptContext( - schemes=["bcrypt", "phpass", "bsdi_crypt"], - onload=_create_phpass_policy, - ) - -phpbb3_context = LazyCryptContext(["phpass"], phpass__ident="H") - -# TODO: support the drupal phpass variants (see phpass homepage) - -#============================================================================= -# roundup -#============================================================================= - -_std_roundup_schemes = [ "ldap_hex_sha1", "ldap_hex_md5", "ldap_des_crypt", "roundup_plaintext" ] -roundup10_context = LazyCryptContext(_std_roundup_schemes) - -# NOTE: 'roundup15' really applies to roundup 1.4.17+ -roundup_context = roundup15_context = LazyCryptContext( - schemes=_std_roundup_schemes + [ "ldap_pbkdf2_sha1" ], - deprecated=_std_roundup_schemes, - default = "ldap_pbkdf2_sha1", - ldap_pbkdf2_sha1__default_rounds = 10000, - ) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/context.py b/backend/venv39/lib/python3.9/site-packages/passlib/context.py deleted file mode 100644 index bc3cbf5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/context.py +++ /dev/null @@ -1,2637 +0,0 @@ -"""passlib.context - CryptContext implementation""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import re -import logging; log = logging.getLogger(__name__) -import threading -import time -from warnings import warn -# site -# pkg -from passlib import exc -from passlib.exc import ExpectedStringError, ExpectedTypeError, PasslibConfigWarning -from passlib.registry import get_crypt_handler, _validate_handler_name -from passlib.utils import (handlers as uh, to_bytes, - to_unicode, splitcomma, - as_bool, timer, rng, getrandstr, - ) -from passlib.utils.binary import BASE64_CHARS -from passlib.utils.compat import (iteritems, num_types, irange, - PY2, PY3, unicode, SafeConfigParser, - NativeStringIO, BytesIO, - unicode_or_bytes_types, native_string_types, - ) -from passlib.utils.decor import deprecated_method, memoized_property -# local -__all__ = [ - 'CryptContext', - 'LazyCryptContext', - 'CryptPolicy', -] - -#============================================================================= -# support -#============================================================================= - -# private object to detect unset params -_UNSET = object() - -def _coerce_vary_rounds(value): - """parse vary_rounds string to percent as [0,1) float, or integer""" - if value.endswith("%"): - # XXX: deprecate this in favor of raw float? - return float(value.rstrip("%"))*.01 - try: - return int(value) - except ValueError: - return float(value) - -# set of options which aren't allowed to be set via policy -_forbidden_scheme_options = set(["salt"]) - # 'salt' - not allowed since a fixed salt would defeat the purpose. - -# dict containing funcs used to coerce strings to correct type for scheme option keys. -# NOTE: this isn't really needed any longer, since Handler.using() handles the actual parsing. -# keeping this around for now, though, since it makes context.to_dict() output cleaner. -_coerce_scheme_options = dict( - min_rounds=int, - max_rounds=int, - default_rounds=int, - vary_rounds=_coerce_vary_rounds, - salt_size=int, -) - -def _is_handler_registered(handler): - """detect if handler is registered or a custom handler""" - return get_crypt_handler(handler.name, None) is handler - -@staticmethod -def _always_needs_update(hash, secret=None): - """ - dummy function patched into handler.needs_update() by _CryptConfig - when hash alg has been deprecated for context. - """ - return True - -#: list of keys allowed under wildcard "all" scheme w/o a security warning. -_global_settings = set(["truncate_error", "vary_rounds"]) - -#============================================================================= -# crypt policy -#============================================================================= -_preamble = ("The CryptPolicy class has been deprecated as of " - "Passlib 1.6, and will be removed in Passlib 1.8. ") - -class CryptPolicy(object): - """ - .. deprecated:: 1.6 - This class has been deprecated, and will be removed in Passlib 1.8. - All of its functionality has been rolled into :class:`CryptContext`. - - This class previously stored the configuration options for the - CryptContext class. In the interest of interface simplification, - all of this class' functionality has been rolled into the CryptContext - class itself. - The documentation for this class is now focused on documenting how to - migrate to the new api. Additionally, where possible, the deprecation - warnings issued by the CryptPolicy methods will list the replacement call - that should be used. - - Constructors - ============ - CryptPolicy objects can be constructed directly using any of - the keywords accepted by :class:`CryptContext`. Direct uses of the - :class:`!CryptPolicy` constructor should either pass the keywords - directly into the CryptContext constructor, or to :meth:`CryptContext.update` - if the policy object was being used to update an existing context object. - - In addition to passing in keywords directly, - CryptPolicy objects can be constructed by the following methods: - - .. automethod:: from_path - .. automethod:: from_string - .. automethod:: from_source - .. automethod:: from_sources - .. automethod:: replace - - Introspection - ============= - All of the informational methods provided by this class have been deprecated - by identical or similar methods in the :class:`CryptContext` class: - - .. automethod:: has_schemes - .. automethod:: schemes - .. automethod:: iter_handlers - .. automethod:: get_handler - .. automethod:: get_options - .. automethod:: handler_is_deprecated - .. automethod:: get_min_verify_time - - Exporting - ========= - .. automethod:: iter_config - .. automethod:: to_dict - .. automethod:: to_file - .. automethod:: to_string - - .. note:: - CryptPolicy are immutable. - Use the :meth:`replace` method to mutate existing instances. - - .. deprecated:: 1.6 - """ - #=================================================================== - # class methods - #=================================================================== - @classmethod - def from_path(cls, path, section="passlib", encoding="utf-8"): - """create a CryptPolicy instance from a local file. - - .. deprecated:: 1.6 - - Creating a new CryptContext from a file, which was previously done via - ``CryptContext(policy=CryptPolicy.from_path(path))``, can now be - done via ``CryptContext.from_path(path)``. - See :meth:`CryptContext.from_path` for details. - - Updating an existing CryptContext from a file, which was previously done - ``context.policy = CryptPolicy.from_path(path)``, can now be - done via ``context.load_path(path)``. - See :meth:`CryptContext.load_path` for details. - """ - warn(_preamble + - "Instead of ``CryptPolicy.from_path(path)``, " - "use ``CryptContext.from_path(path)`` " - " or ``context.load_path(path)`` for an existing CryptContext.", - DeprecationWarning, stacklevel=2) - return cls(_internal_context=CryptContext.from_path(path, section, - encoding)) - - @classmethod - def from_string(cls, source, section="passlib", encoding="utf-8"): - """create a CryptPolicy instance from a string. - - .. deprecated:: 1.6 - - Creating a new CryptContext from a string, which was previously done via - ``CryptContext(policy=CryptPolicy.from_string(data))``, can now be - done via ``CryptContext.from_string(data)``. - See :meth:`CryptContext.from_string` for details. - - Updating an existing CryptContext from a string, which was previously done - ``context.policy = CryptPolicy.from_string(data)``, can now be - done via ``context.load(data)``. - See :meth:`CryptContext.load` for details. - """ - warn(_preamble + - "Instead of ``CryptPolicy.from_string(source)``, " - "use ``CryptContext.from_string(source)`` or " - "``context.load(source)`` for an existing CryptContext.", - DeprecationWarning, stacklevel=2) - return cls(_internal_context=CryptContext.from_string(source, section, - encoding)) - - @classmethod - def from_source(cls, source, _warn=True): - """create a CryptPolicy instance from some source. - - this method autodetects the source type, and invokes - the appropriate constructor automatically. it attempts - to detect whether the source is a configuration string, a filepath, - a dictionary, or an existing CryptPolicy instance. - - .. deprecated:: 1.6 - - Create a new CryptContext, which could previously be done via - ``CryptContext(policy=CryptPolicy.from_source(source))``, should - now be done using an explicit method: the :class:`CryptContext` - constructor itself, :meth:`CryptContext.from_path`, - or :meth:`CryptContext.from_string`. - - Updating an existing CryptContext, which could previously be done via - ``context.policy = CryptPolicy.from_source(source)``, should - now be done using an explicit method: :meth:`CryptContext.update`, - or :meth:`CryptContext.load`. - """ - if _warn: - warn(_preamble + - "Instead of ``CryptPolicy.from_source()``, " - "use ``CryptContext.from_string(path)`` " - " or ``CryptContext.from_path(source)``, as appropriate.", - DeprecationWarning, stacklevel=2) - if isinstance(source, CryptPolicy): - return source - elif isinstance(source, dict): - return cls(_internal_context=CryptContext(**source)) - elif not isinstance(source, (bytes,unicode)): - raise TypeError("source must be CryptPolicy, dict, config string, " - "or file path: %r" % (type(source),)) - elif any(c in source for c in "\n\r\t") or not source.strip(" \t./;:"): - return cls(_internal_context=CryptContext.from_string(source)) - else: - return cls(_internal_context=CryptContext.from_path(source)) - - @classmethod - def from_sources(cls, sources, _warn=True): - """create a CryptPolicy instance by merging multiple sources. - - each source is interpreted as by :meth:`from_source`, - and the results are merged together. - - .. deprecated:: 1.6 - Instead of using this method to merge multiple policies together, - a :class:`CryptContext` instance should be created, and then - the multiple sources merged together via :meth:`CryptContext.load`. - """ - if _warn: - warn(_preamble + - "Instead of ``CryptPolicy.from_sources()``, " - "use the various CryptContext constructors " - " followed by ``context.update()``.", - DeprecationWarning, stacklevel=2) - if len(sources) == 0: - raise ValueError("no sources specified") - if len(sources) == 1: - return cls.from_source(sources[0], _warn=False) - kwds = {} - for source in sources: - kwds.update(cls.from_source(source, _warn=False)._context.to_dict(resolve=True)) - return cls(_internal_context=CryptContext(**kwds)) - - def replace(self, *args, **kwds): - """create a new CryptPolicy, optionally updating parts of the - existing configuration. - - .. deprecated:: 1.6 - Callers of this method should :meth:`CryptContext.update` or - :meth:`CryptContext.copy` instead. - """ - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "Instead of ``context.policy.replace()``, " - "use ``context.update()`` or ``context.copy()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().replace()``, " - "create a CryptContext instance and " - "use ``context.update()`` or ``context.copy()``.", - DeprecationWarning, stacklevel=2) - sources = [ self ] - if args: - sources.extend(args) - if kwds: - sources.append(kwds) - return CryptPolicy.from_sources(sources, _warn=False) - - #=================================================================== - # instance attrs - #=================================================================== - - # internal CryptContext we're wrapping to handle everything - # until this class is removed. - _context = None - - # flag indicating this is wrapper generated by the CryptContext.policy - # attribute, rather than one created independantly by the application. - _stub_policy = False - - #=================================================================== - # init - #=================================================================== - def __init__(self, *args, **kwds): - context = kwds.pop("_internal_context", None) - if context: - assert isinstance(context, CryptContext) - self._context = context - self._stub_policy = kwds.pop("_stub_policy", False) - assert not (args or kwds), "unexpected args: %r %r" % (args,kwds) - else: - if args: - if len(args) != 1: - raise TypeError("only one positional argument accepted") - if kwds: - raise TypeError("cannot specify positional arg and kwds") - kwds = args[0] - warn(_preamble + - "Instead of constructing a CryptPolicy instance, " - "create a CryptContext directly, or use ``context.update()`` " - "and ``context.load()`` to reconfigure existing CryptContext " - "instances.", - DeprecationWarning, stacklevel=2) - self._context = CryptContext(**kwds) - - #=================================================================== - # public interface for examining options - #=================================================================== - def has_schemes(self): - """return True if policy defines *any* schemes for use. - - .. deprecated:: 1.6 - applications should use ``bool(context.schemes())`` instead. - see :meth:`CryptContext.schemes`. - """ - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "Instead of ``context.policy.has_schemes()``, " - "use ``bool(context.schemes())``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().has_schemes()``, " - "create a CryptContext instance and " - "use ``bool(context.schemes())``.", - DeprecationWarning, stacklevel=2) - return bool(self._context.schemes()) - - def iter_handlers(self): - """return iterator over handlers defined in policy. - - .. deprecated:: 1.6 - applications should use ``context.schemes(resolve=True))`` instead. - see :meth:`CryptContext.schemes`. - """ - if self._stub_policy: - warn(_preamble + - "Instead of ``context.policy.iter_handlers()``, " - "use ``context.schemes(resolve=True)``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().iter_handlers()``, " - "create a CryptContext instance and " - "use ``context.schemes(resolve=True)``.", - DeprecationWarning, stacklevel=2) - return self._context.schemes(resolve=True, unconfigured=True) - - def schemes(self, resolve=False): - """return list of schemes defined in policy. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.schemes` instead. - """ - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "Instead of ``context.policy.schemes()``, " - "use ``context.schemes()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().schemes()``, " - "create a CryptContext instance and " - "use ``context.schemes()``.", - DeprecationWarning, stacklevel=2) - return list(self._context.schemes(resolve=resolve, unconfigured=True)) - - def get_handler(self, name=None, category=None, required=False): - """return handler as specified by name, or default handler. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.handler` instead, - though note that the ``required`` keyword has been removed, - and the new method will always act as if ``required=True``. - """ - if self._stub_policy: - warn(_preamble + - "Instead of ``context.policy.get_handler()``, " - "use ``context.handler()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().get_handler()``, " - "create a CryptContext instance and " - "use ``context.handler()``.", - DeprecationWarning, stacklevel=2) - # CryptContext.handler() doesn't support required=False, - # so wrapping it in try/except - try: - return self._context.handler(name, category, unconfigured=True) - except KeyError: - if required: - raise - else: - return None - - def get_min_verify_time(self, category=None): - """get min_verify_time setting for policy. - - .. deprecated:: 1.6 - min_verify_time option will be removed entirely in passlib 1.8 - - .. versionchanged:: 1.7 - this method now always returns the value automatically - calculated by :meth:`CryptContext.min_verify_time`, - any value specified by policy is ignored. - """ - warn("get_min_verify_time() and min_verify_time option is deprecated and ignored, " - "and will be removed in Passlib 1.8", DeprecationWarning, - stacklevel=2) - return 0 - - def get_options(self, name, category=None): - """return dictionary of options specific to a given handler. - - .. deprecated:: 1.6 - this method has no direct replacement in the 1.6 api, as there - is not a clearly defined use-case. however, examining the output of - :meth:`CryptContext.to_dict` should serve as the closest alternative. - """ - # XXX: might make a public replacement, but need more study of the use cases. - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "``context.policy.get_options()`` will no longer be available.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "``CryptPolicy().get_options()`` will no longer be available.", - DeprecationWarning, stacklevel=2) - if hasattr(name, "name"): - name = name.name - return self._context._config._get_record_options_with_flag(name, category)[0] - - def handler_is_deprecated(self, name, category=None): - """check if handler has been deprecated by policy. - - .. deprecated:: 1.6 - this method has no direct replacement in the 1.6 api, as there - is not a clearly defined use-case. however, examining the output of - :meth:`CryptContext.to_dict` should serve as the closest alternative. - """ - # XXX: might make a public replacement, but need more study of the use cases. - if self._stub_policy: - warn(_preamble + - "``context.policy.handler_is_deprecated()`` will no longer be available.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "``CryptPolicy().handler_is_deprecated()`` will no longer be available.", - DeprecationWarning, stacklevel=2) - if hasattr(name, "name"): - name = name.name - return self._context.handler(name, category).deprecated - - #=================================================================== - # serialization - #=================================================================== - - def iter_config(self, ini=False, resolve=False): - """iterate over key/value pairs representing the policy object. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.to_dict` instead. - """ - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "Instead of ``context.policy.iter_config()``, " - "use ``context.to_dict().items()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().iter_config()``, " - "create a CryptContext instance and " - "use ``context.to_dict().items()``.", - DeprecationWarning, stacklevel=2) - # hacked code that renders keys & values in manner that approximates - # old behavior. context.to_dict() is much cleaner. - context = self._context - if ini: - def render_key(key): - return context._render_config_key(key).replace("__", ".") - def render_value(value): - if isinstance(value, (list,tuple)): - value = ", ".join(value) - return value - resolve = False - else: - render_key = context._render_config_key - render_value = lambda value: value - return ( - (render_key(key), render_value(value)) - for key, value in context._config.iter_config(resolve) - ) - - def to_dict(self, resolve=False): - """export policy object as dictionary of options. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.to_dict` instead. - """ - if self._stub_policy: - warn(_preamble + - "Instead of ``context.policy.to_dict()``, " - "use ``context.to_dict()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().to_dict()``, " - "create a CryptContext instance and " - "use ``context.to_dict()``.", - DeprecationWarning, stacklevel=2) - return self._context.to_dict(resolve) - - def to_file(self, stream, section="passlib"): # pragma: no cover -- deprecated & unused - """export policy to file. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.to_string` instead, - and then write the output to a file as desired. - """ - if self._stub_policy: - warn(_preamble + - "Instead of ``context.policy.to_file(stream)``, " - "use ``stream.write(context.to_string())``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().to_file(stream)``, " - "create a CryptContext instance and " - "use ``stream.write(context.to_string())``.", - DeprecationWarning, stacklevel=2) - out = self._context.to_string(section=section) - if PY2: - out = out.encode("utf-8") - stream.write(out) - - def to_string(self, section="passlib", encoding=None): - """export policy to file. - - .. deprecated:: 1.6 - applications should use :meth:`CryptContext.to_string` instead. - """ - if self._stub_policy: - warn(_preamble + # pragma: no cover -- deprecated & unused - "Instead of ``context.policy.to_string()``, " - "use ``context.to_string()``.", - DeprecationWarning, stacklevel=2) - else: - warn(_preamble + - "Instead of ``CryptPolicy().to_string()``, " - "create a CryptContext instance and " - "use ``context.to_string()``.", - DeprecationWarning, stacklevel=2) - out = self._context.to_string(section=section) - if encoding: - out = out.encode(encoding) - return out - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# _CryptConfig helper class -#============================================================================= -class _CryptConfig(object): - """parses, validates, and stores CryptContext config - - this is a helper used internally by CryptContext to handle - parsing, validation, and serialization of its config options. - split out from the main class, but not made public since - that just complicates interface too much (c.f. CryptPolicy) - - :arg source: config as dict mapping ``(cat,scheme,option) -> value`` - """ - #=================================================================== - # instance attrs - #=================================================================== - - # triple-nested dict which maps scheme -> category -> key -> value, - # storing all hash-specific options - _scheme_options = None - - # double-nested dict which maps key -> category -> value - # storing all CryptContext options - _context_options = None - - # tuple of handler objects - handlers = None - - # tuple of scheme objects in same order as handlers - schemes = None - - # tuple of categories in alphabetical order (not including None) - categories = None - - # set of all context keywords used by active schemes - context_kwds = None - - # dict mapping category -> default scheme - _default_schemes = None - - # dict mapping (scheme, category) -> custom handler - _records = None - - # dict mapping category -> list of custom handler instances for that category, - # in order of schemes(). populated on demand by _get_record_list() - _record_lists = None - - #=================================================================== - # constructor - #=================================================================== - def __init__(self, source): - self._init_scheme_list(source.get((None,None,"schemes"))) - self._init_options(source) - self._init_default_schemes() - self._init_records() - - def _init_scheme_list(self, data): - """initialize .handlers and .schemes attributes""" - handlers = [] - schemes = [] - if isinstance(data, native_string_types): - data = splitcomma(data) - for elem in data or (): - # resolve elem -> handler & scheme - if hasattr(elem, "name"): - handler = elem - scheme = handler.name - _validate_handler_name(scheme) - elif isinstance(elem, native_string_types): - handler = get_crypt_handler(elem) - scheme = handler.name - else: - raise TypeError("scheme must be name or CryptHandler, " - "not %r" % type(elem)) - - # check scheme name isn't already in use - if scheme in schemes: - raise KeyError("multiple handlers with same name: %r" % - (scheme,)) - - # add to handler list - handlers.append(handler) - schemes.append(scheme) - - self.handlers = tuple(handlers) - self.schemes = tuple(schemes) - - #=================================================================== - # lowlevel options - #=================================================================== - - #--------------------------------------------------------------- - # init lowlevel option storage - #--------------------------------------------------------------- - def _init_options(self, source): - """load config dict into internal representation, - and init .categories attr - """ - # prepare dicts & locals - norm_scheme_option = self._norm_scheme_option - norm_context_option = self._norm_context_option - self._scheme_options = scheme_options = {} - self._context_options = context_options = {} - categories = set() - - # load source config into internal storage - for (cat, scheme, key), value in iteritems(source): - categories.add(cat) - explicit_scheme = scheme - if not cat and not scheme and key in _global_settings: - # going forward, not using "__all__" format. instead... - # whitelisting set of keys which should be passed to (all) schemes, - # rather than passed to the CryptContext itself - scheme = "all" - if scheme: - # normalize scheme option - key, value = norm_scheme_option(key, value) - - # e.g. things like "min_rounds" should never be set cross-scheme - # this will be fatal under 2.0. - if scheme == "all" and key not in _global_settings: - warn("The '%s' option should be configured per-algorithm, and not set " - "globally in the context; This will be an error in Passlib 2.0" % - (key,), PasslibConfigWarning) - - # this scheme is going away in 2.0; - # but most keys deserve an extra warning since it impacts security. - if explicit_scheme == "all": - warn("The 'all' scheme is deprecated as of Passlib 1.7, " - "and will be removed in Passlib 2.0; Please configure " - "options on a per-algorithm basis.", DeprecationWarning) - - # store in scheme_options - # map structure: scheme_options[scheme][category][key] = value - try: - category_map = scheme_options[scheme] - except KeyError: - scheme_options[scheme] = {cat: {key: value}} - else: - try: - option_map = category_map[cat] - except KeyError: - category_map[cat] = {key: value} - else: - option_map[key] = value - else: - # normalize context option - if cat and key == "schemes": - raise KeyError("'schemes' context option is not allowed " - "per category") - key, value = norm_context_option(cat, key, value) - if key == "min_verify_time": # ignored in 1.7, to be removed in 1.8 - continue - - # store in context_options - # map structure: context_options[key][category] = value - try: - category_map = context_options[key] - except KeyError: - context_options[key] = {cat: value} - else: - category_map[cat] = value - - # store list of configured categories - categories.discard(None) - self.categories = tuple(sorted(categories)) - - def _norm_scheme_option(self, key, value): - # check for invalid options - if key in _forbidden_scheme_options: - raise KeyError("%r option not allowed in CryptContext " - "configuration" % (key,)) - # coerce strings for certain fields (e.g. min_rounds uses ints) - if isinstance(value, native_string_types): - func = _coerce_scheme_options.get(key) - if func: - value = func(value) - return key, value - - def _norm_context_option(self, cat, key, value): - schemes = self.schemes - if key == "default": - if hasattr(value, "name"): - value = value.name - elif not isinstance(value, native_string_types): - raise ExpectedTypeError(value, "str", "default") - if schemes and value not in schemes: - raise KeyError("default scheme not found in policy") - elif key == "deprecated": - if isinstance(value, native_string_types): - value = splitcomma(value) - elif not isinstance(value, (list,tuple)): - raise ExpectedTypeError(value, "str or seq", "deprecated") - if 'auto' in value: - # XXX: have any statements been made about when this is default? - # should do it in 1.8 at latest. - if len(value) > 1: - raise ValueError("cannot list other schemes if " - "``deprecated=['auto']`` is used") - elif schemes: - # make sure list of deprecated schemes is subset of configured schemes - for scheme in value: - if not isinstance(scheme, native_string_types): - raise ExpectedTypeError(value, "str", "deprecated element") - if scheme not in schemes: - raise KeyError("deprecated scheme not found " - "in policy: %r" % (scheme,)) - elif key == "min_verify_time": - warn("'min_verify_time' was deprecated in Passlib 1.6, is " - "ignored in 1.7, and will be removed in 1.8", - DeprecationWarning) - elif key == "harden_verify": - warn("'harden_verify' is deprecated & ignored as of Passlib 1.7.1, " - " and will be removed in 1.8", - DeprecationWarning) - elif key != "schemes": - raise KeyError("unknown CryptContext keyword: %r" % (key,)) - return key, value - - #--------------------------------------------------------------- - # reading context options - #--------------------------------------------------------------- - def get_context_optionmap(self, key, _default={}): - """return dict mapping category->value for specific context option. - - .. warning:: treat return value as readonly! - """ - return self._context_options.get(key, _default) - - def get_context_option_with_flag(self, category, key): - """return value of specific option, handling category inheritance. - also returns flag indicating whether value is category-specific. - """ - try: - category_map = self._context_options[key] - except KeyError: - return None, False - value = category_map.get(None) - if category: - try: - alt = category_map[category] - except KeyError: - pass - else: - if value is None or alt != value: - return alt, True - return value, False - - #--------------------------------------------------------------- - # reading scheme options - #--------------------------------------------------------------- - def _get_scheme_optionmap(self, scheme, category, default={}): - """return all options for (scheme,category) combination - - .. warning:: treat return value as readonly! - """ - try: - return self._scheme_options[scheme][category] - except KeyError: - return default - - def get_base_handler(self, scheme): - return self.handlers[self.schemes.index(scheme)] - - @staticmethod - def expand_settings(handler): - setting_kwds = handler.setting_kwds - if 'rounds' in handler.setting_kwds: - # XXX: historically this extras won't be listed in setting_kwds - setting_kwds += uh.HasRounds.using_rounds_kwds - return setting_kwds - - # NOTE: this is only used by _get_record_options_with_flag()... - def get_scheme_options_with_flag(self, scheme, category): - """return composite dict of all options set for scheme. - includes options inherited from 'all' and from default category. - result can be modified. - returns (kwds, has_cat_specific_options) - """ - # start out with copy of global options - get_optionmap = self._get_scheme_optionmap - kwds = get_optionmap("all", None).copy() - has_cat_options = False - - # add in category-specific global options - if category: - defkwds = kwds.copy() # <-- used to detect category-specific options - kwds.update(get_optionmap("all", category)) - - # filter out global settings not supported by handler - allowed_settings = self.expand_settings(self.get_base_handler(scheme)) - for key in set(kwds).difference(allowed_settings): - kwds.pop(key) - if category: - for key in set(defkwds).difference(allowed_settings): - defkwds.pop(key) - - # add in default options for scheme - other = get_optionmap(scheme, None) - kwds.update(other) - - # load category-specific options for scheme - if category: - defkwds.update(other) - kwds.update(get_optionmap(scheme, category)) - - # compare default category options to see if there's anything - # category-specific - if kwds != defkwds: - has_cat_options = True - - return kwds, has_cat_options - - #=================================================================== - # deprecated & default schemes - #=================================================================== - def _init_default_schemes(self): - """initialize maps containing default scheme for each category. - - have to do this after _init_options(), since the default scheme - is affected by the list of deprecated schemes. - """ - # init maps & locals - get_optionmap = self.get_context_optionmap - default_map = self._default_schemes = get_optionmap("default").copy() - dep_map = get_optionmap("deprecated") - schemes = self.schemes - if not schemes: - return - - # figure out default scheme - deps = dep_map.get(None) or () - default = default_map.get(None) - if not default: - for scheme in schemes: - if scheme not in deps: - default_map[None] = scheme - break - else: - raise ValueError("must have at least one non-deprecated scheme") - elif default in deps: - raise ValueError("default scheme cannot be deprecated") - - # figure out per-category default schemes, - for cat in self.categories: - cdeps = dep_map.get(cat, deps) - cdefault = default_map.get(cat, default) - if not cdefault: - for scheme in schemes: - if scheme not in cdeps: - default_map[cat] = scheme - break - else: - raise ValueError("must have at least one non-deprecated " - "scheme for %r category" % cat) - elif cdefault in cdeps: - raise ValueError("default scheme for %r category " - "cannot be deprecated" % cat) - - def default_scheme(self, category): - """return default scheme for specific category""" - defaults = self._default_schemes - try: - return defaults[category] - except KeyError: - pass - if not self.schemes: - raise KeyError("no hash schemes configured for this " - "CryptContext instance") - return defaults[None] - - def is_deprecated_with_flag(self, scheme, category): - """is scheme deprecated under particular category?""" - depmap = self.get_context_optionmap("deprecated") - def test(cat): - source = depmap.get(cat, depmap.get(None)) - if source is None: - return None - elif 'auto' in source: - return scheme != self.default_scheme(cat) - else: - return scheme in source - value = test(None) or False - if category: - alt = test(category) - if alt is not None and value != alt: - return alt, True - return value, False - - #=================================================================== - # CryptRecord objects - #=================================================================== - def _init_records(self): - # NOTE: this step handles final validation of settings, - # checking for violations against handler's internal invariants. - # this is why we create all the records now, - # so CryptContext throws error immediately rather than later. - self._record_lists = {} - records = self._records = {} - all_context_kwds = self.context_kwds = set() - get_options = self._get_record_options_with_flag - categories = (None,) + self.categories - for handler in self.handlers: - scheme = handler.name - all_context_kwds.update(handler.context_kwds) - for cat in categories: - kwds, has_cat_options = get_options(scheme, cat) - if cat is None or has_cat_options: - records[scheme, cat] = self._create_record(handler, cat, **kwds) - # NOTE: if handler has no category-specific opts, get_record() - # will automatically use the default category's record. - # NOTE: default records for specific category stored under the - # key (None,category); these are populated on-demand by get_record(). - - @staticmethod - def _create_record(handler, category=None, deprecated=False, **settings): - # create custom handler if needed. - try: - # XXX: relaxed=True is mostly here to retain backwards-compat behavior. - # could make this optional flag in future. - subcls = handler.using(relaxed=True, **settings) - except TypeError as err: - m = re.match(r".* unexpected keyword argument '(.*)'$", str(err)) - if m and m.group(1) in settings: - # translate into KeyError, for backwards compat. - # XXX: push this down to GenericHandler.using() implementation? - key = m.group(1) - raise KeyError("keyword not supported by %s handler: %r" % - (handler.name, key)) - raise - - # using private attrs to store some extra metadata in custom handler - assert subcls is not handler, "expected unique variant of handler" - ##subcls._Context__category = category - subcls._Context__orig_handler = handler - subcls.deprecated = deprecated # attr reserved for this purpose - return subcls - - def _get_record_options_with_flag(self, scheme, category): - """return composite dict of options for given scheme + category. - - this is currently a private method, though some variant - of its output may eventually be made public. - - given a scheme & category, it returns two things: - a set of all the keyword options to pass to :meth:`_create_record`, - and a bool flag indicating whether any of these options - were specific to the named category. if this flag is false, - the options are identical to the options for the default category. - - the options dict includes all the scheme-specific settings, - as well as optional *deprecated* keyword. - """ - # get scheme options - kwds, has_cat_options = self.get_scheme_options_with_flag(scheme, category) - - # throw in deprecated flag - value, not_inherited = self.is_deprecated_with_flag(scheme, category) - if value: - kwds['deprecated'] = True - if not_inherited: - has_cat_options = True - - return kwds, has_cat_options - - def get_record(self, scheme, category): - """return record for specific scheme & category (cached)""" - # NOTE: this is part of the critical path shared by - # all of CryptContext's PasswordHash methods, - # hence all the caching and error checking. - - # quick lookup in cache - try: - return self._records[scheme, category] - except KeyError: - pass - - # type check - if category is not None and not isinstance(category, native_string_types): - if PY2 and isinstance(category, unicode): - # for compatibility with unicode-centric py2 apps - return self.get_record(scheme, category.encode("utf-8")) - raise ExpectedTypeError(category, "str or None", "category") - if scheme is not None and not isinstance(scheme, native_string_types): - raise ExpectedTypeError(scheme, "str or None", "scheme") - - # if scheme=None, - # use record for category's default scheme, and cache result. - if not scheme: - default = self.default_scheme(category) - assert default - record = self._records[None, category] = self.get_record(default, - category) - return record - - # if no record for (scheme, category), - # use record for (scheme, None), and cache result. - if category: - try: - cache = self._records - record = cache[scheme, category] = cache[scheme, None] - return record - except KeyError: - pass - - # scheme not found in configuration for default category - raise KeyError("crypt algorithm not found in policy: %r" % (scheme,)) - - def _get_record_list(self, category=None): - """return list of records for category (cached) - - this is an internal helper used only by identify_record() - """ - # type check of category - handled by _get_record() - # quick lookup in cache - try: - return self._record_lists[category] - except KeyError: - pass - # cache miss - build list from scratch - value = self._record_lists[category] = [ - self.get_record(scheme, category) - for scheme in self.schemes - ] - return value - - def identify_record(self, hash, category, required=True): - """internal helper to identify appropriate custom handler for hash""" - # NOTE: this is part of the critical path shared by - # all of CryptContext's PasswordHash methods, - # hence all the caching and error checking. - # FIXME: if multiple hashes could match (e.g. lmhash vs nthash) - # this will only return first match. might want to do something - # about this in future, but for now only hashes with - # unique identifiers will work properly in a CryptContext. - # XXX: if all handlers have a unique prefix (e.g. all are MCF / LDAP), - # could use dict-lookup to speed up this search. - if not isinstance(hash, unicode_or_bytes_types): - raise ExpectedStringError(hash, "hash") - # type check of category - handled by _get_record_list() - for record in self._get_record_list(category): - if record.identify(hash): - return record - if not required: - return None - elif not self.schemes: - raise KeyError("no crypt algorithms supported") - else: - raise exc.UnknownHashError("hash could not be identified") - - @memoized_property - def disabled_record(self): - for record in self._get_record_list(None): - if record.is_disabled: - return record - raise RuntimeError("no disabled hasher present " - "(perhaps add 'unix_disabled' to list of schemes?)") - - #=================================================================== - # serialization - #=================================================================== - def iter_config(self, resolve=False): - """regenerate original config. - - this is an iterator which yields ``(cat,scheme,option),value`` items, - in the order they generally appear inside an INI file. - if interpreted as a dictionary, it should match the original - keywords passed to the CryptContext (aside from any canonization). - - it's mainly used as the internal backend for most of the public - serialization methods. - """ - # grab various bits of data - scheme_options = self._scheme_options - context_options = self._context_options - scheme_keys = sorted(scheme_options) - context_keys = sorted(context_options) - - # write loaded schemes (may differ from 'schemes' local var) - if 'schemes' in context_keys: - context_keys.remove("schemes") - value = self.handlers if resolve else self.schemes - if value: - yield (None, None, "schemes"), list(value) - - # then run through config for each user category - for cat in (None,) + self.categories: - - # write context options - for key in context_keys: - try: - value = context_options[key][cat] - except KeyError: - pass - else: - if isinstance(value, list): - value = list(value) - yield (cat, None, key), value - - # write per-scheme options for all schemes. - for scheme in scheme_keys: - try: - kwds = scheme_options[scheme][cat] - except KeyError: - pass - else: - for key in sorted(kwds): - yield (cat, scheme, key), kwds[key] - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# main CryptContext class -#============================================================================= -class CryptContext(object): - """Helper for hashing & verifying passwords using multiple algorithms. - - Instances of this class allow applications to choose a specific - set of hash algorithms which they wish to support, set limits and defaults - for the rounds and salt sizes those algorithms should use, flag - which algorithms should be deprecated, and automatically handle - migrating users to stronger hashes when they log in. - - Basic usage:: - - >>> ctx = CryptContext(schemes=[...]) - - See the Passlib online documentation for details and full documentation. - """ - # FIXME: altering the configuration of this object isn't threadsafe, - # but is generally only done during application init, so not a major - # issue (just yet). - - # XXX: would like some way to restrict the categories that are allowed, - # to restrict what the app OR the config can use. - - # XXX: add wrap/unwrap callback hooks so app can mutate hash format? - - # XXX: add method for detecting and warning user about schemes - # which don't have any good distinguishing marks? - # or greedy ones (unix_disabled, plaintext) which are not listed at the end? - - #=================================================================== - # instance attrs - #=================================================================== - - # _CryptConfig instance holding current parsed config - _config = None - - # copy of _config methods, stored in CryptContext instance for speed. - _get_record = None - _identify_record = None - - #=================================================================== - # secondary constructors - #=================================================================== - @classmethod - def _norm_source(cls, source): - """internal helper - accepts string, dict, or context""" - if isinstance(source, dict): - return cls(**source) - elif isinstance(source, cls): - return source - else: - self = cls() - self.load(source) - return self - - @classmethod - def from_string(cls, source, section="passlib", encoding="utf-8"): - """create new CryptContext instance from an INI-formatted string. - - :type source: unicode or bytes - :arg source: - string containing INI-formatted content. - - :type section: str - :param section: - option name of section to read from, defaults to ``"passlib"``. - - :type encoding: str - :arg encoding: - optional encoding used when source is bytes, defaults to ``"utf-8"``. - - :returns: - new :class:`CryptContext` instance, configured based on the - parameters in the *source* string. - - Usage example:: - - >>> from passlib.context import CryptContext - >>> context = CryptContext.from_string(''' - ... [passlib] - ... schemes = sha256_crypt, des_crypt - ... sha256_crypt__default_rounds = 30000 - ... ''') - - .. versionadded:: 1.6 - - .. seealso:: :meth:`to_string`, the inverse of this constructor. - """ - if not isinstance(source, unicode_or_bytes_types): - raise ExpectedTypeError(source, "unicode or bytes", "source") - self = cls(_autoload=False) - self.load(source, section=section, encoding=encoding) - return self - - @classmethod - def from_path(cls, path, section="passlib", encoding="utf-8"): - """create new CryptContext instance from an INI-formatted file. - - this functions exactly the same as :meth:`from_string`, - except that it loads from a local file. - - :type path: str - :arg path: - path to local file containing INI-formatted config. - - :type section: str - :param section: - option name of section to read from, defaults to ``"passlib"``. - - :type encoding: str - :arg encoding: - encoding used to load file, defaults to ``"utf-8"``. - - :returns: - new CryptContext instance, configured based on the parameters - stored in the file *path*. - - .. versionadded:: 1.6 - - .. seealso:: :meth:`from_string` for an equivalent usage example. - """ - self = cls(_autoload=False) - self.load_path(path, section=section, encoding=encoding) - return self - - def copy(self, **kwds): - """Return copy of existing CryptContext instance. - - This function returns a new CryptContext instance whose configuration - is exactly the same as the original, with the exception that any keywords - passed in will take precedence over the original settings. - As an example:: - - >>> from passlib.context import CryptContext - - >>> # given an existing context... - >>> ctx1 = CryptContext(["sha256_crypt", "md5_crypt"]) - - >>> # copy can be used to make a clone, and update - >>> # some of the settings at the same time... - >>> ctx2 = custom_app_context.copy(default="md5_crypt") - - >>> # and the original will be unaffected by the change - >>> ctx1.default_scheme() - "sha256_crypt" - >>> ctx2.default_scheme() - "md5_crypt" - - .. versionadded:: 1.6 - This method was previously named :meth:`!replace`. That alias - has been deprecated, and will be removed in Passlib 1.8. - - .. seealso:: :meth:`update` - """ - # XXX: it would be faster to store ref to self._config, - # but don't want to share config objects til sure - # can rely on them being immutable. - other = CryptContext(_autoload=False) - other.load(self) - if kwds: - other.load(kwds, update=True) - return other - - def using(self, **kwds): - """ - alias for :meth:`copy`, to match PasswordHash.using() - """ - return self.copy(**kwds) - - def replace(self, **kwds): - """deprecated alias of :meth:`copy`""" - warn("CryptContext().replace() has been deprecated in Passlib 1.6, " - "and will be removed in Passlib 1.8, " - "it has been renamed to CryptContext().copy()", - DeprecationWarning, stacklevel=2) - return self.copy(**kwds) - - #=================================================================== - # init - #=================================================================== - def __init__(self, schemes=None, - # keyword only... - policy=_UNSET, # <-- deprecated - _autoload=True, **kwds): - # XXX: add ability to make flag certain contexts as immutable, - # e.g. the builtin passlib ones? - # XXX: add a name or import path for the contexts, to help out repr? - if schemes is not None: - kwds['schemes'] = schemes - if policy is not _UNSET: - warn("The CryptContext ``policy`` keyword has been deprecated as of Passlib 1.6, " - "and will be removed in Passlib 1.8; please use " - "``CryptContext.from_string()` or " - "``CryptContext.from_path()`` instead.", - DeprecationWarning) - if policy is None: - self.load(kwds) - elif isinstance(policy, CryptPolicy): - self.load(policy._context) - self.update(kwds) - else: - raise TypeError("policy must be a CryptPolicy instance") - elif _autoload: - self.load(kwds) - else: - assert not kwds, "_autoload=False and kwds are mutually exclusive" - - # XXX: would this be useful? - ##def __str__(self): - ## if PY3: - ## return self.to_string() - ## else: - ## return self.to_string().encode("utf-8") - - def __repr__(self): - return "" % id(self) - - #=================================================================== - # deprecated policy object - #=================================================================== - def _get_policy(self): - # The CryptPolicy class has been deprecated, so to support any - # legacy accesses, we create a stub policy object so .policy attr - # will continue to work. - # - # the code waits until app accesses a specific policy object attribute - # before issuing deprecation warning, so developer gets method-specific - # suggestion for how to upgrade. - - # NOTE: making a copy of the context so the policy acts like a snapshot, - # to retain the pre-1.6 behavior. - return CryptPolicy(_internal_context=self.copy(), _stub_policy=True) - - def _set_policy(self, policy): - warn("The CryptPolicy class and the ``context.policy`` attribute have " - "been deprecated as of Passlib 1.6, and will be removed in " - "Passlib 1.8; please use the ``context.load()`` and " - "``context.update()`` methods instead.", - DeprecationWarning, stacklevel=2) - if isinstance(policy, CryptPolicy): - self.load(policy._context) - else: - raise TypeError("expected CryptPolicy instance") - - policy = property(_get_policy, _set_policy, - doc="[deprecated] returns CryptPolicy instance " - "tied to this CryptContext") - - #=================================================================== - # loading / updating configuration - #=================================================================== - @staticmethod - def _parse_ini_stream(stream, section, filename): - """helper read INI from stream, extract passlib section as dict""" - # NOTE: this expects a unicode stream under py3, - # and a utf-8 bytes stream under py2, - # allowing the resulting dict to always use native strings. - p = SafeConfigParser() - if PY3: - # python 3.2 deprecated readfp in favor of read_file - p.read_file(stream, filename) - else: - p.readfp(stream, filename) - # XXX: could change load() to accept list of items, - # and skip intermediate dict creation - return dict(p.items(section)) - - def load_path(self, path, update=False, section="passlib", encoding="utf-8"): - """Load new configuration into CryptContext from a local file. - - This function is a wrapper for :meth:`load` which - loads a configuration string from the local file *path*, - instead of an in-memory source. Its behavior and options - are otherwise identical to :meth:`!load` when provided with - an INI-formatted string. - - .. versionadded:: 1.6 - """ - def helper(stream): - kwds = self._parse_ini_stream(stream, section, path) - return self.load(kwds, update=update) - if PY3: - # decode to unicode, which load() expected under py3 - with open(path, "rt", encoding=encoding) as stream: - return helper(stream) - elif encoding in ["utf-8", "ascii"]: - # keep as utf-8 bytes, which load() expects under py2 - with open(path, "rb") as stream: - return helper(stream) - else: - # transcode to utf-8 bytes - with open(path, "rb") as fh: - tmp = fh.read().decode(encoding).encode("utf-8") - return helper(BytesIO(tmp)) - - def load(self, source, update=False, section="passlib", encoding="utf-8"): - """Load new configuration into CryptContext, replacing existing config. - - :arg source: - source of new configuration to load. - this value can be a number of different types: - - * a :class:`!dict` object, or compatible Mapping - - the key/value pairs will be interpreted the same - keywords for the :class:`CryptContext` class constructor. - - * a :class:`!unicode` or :class:`!bytes` string - - this will be interpreted as an INI-formatted file, - and appropriate key/value pairs will be loaded from - the specified *section*. - - * another :class:`!CryptContext` object. - - this will export a snapshot of its configuration - using :meth:`to_dict`. - - :type update: bool - :param update: - By default, :meth:`load` will replace the existing configuration - entirely. If ``update=True``, it will preserve any existing - configuration options that are not overridden by the new source, - much like the :meth:`update` method. - - :type section: str - :param section: - When parsing an INI-formatted string, :meth:`load` will look for - a section named ``"passlib"``. This option allows an alternate - section name to be used. Ignored when loading from a dictionary. - - :type encoding: str - :param encoding: - Encoding to use when **source** is bytes. - Defaults to ``"utf-8"``. Ignored when loading from a dictionary. - - .. deprecated:: 1.8 - - This keyword, and support for bytes input, will be dropped in Passlib 2.0 - - :raises TypeError: - * If the source cannot be identified. - * If an unknown / malformed keyword is encountered. - - :raises ValueError: - If an invalid keyword value is encountered. - - .. note:: - - If an error occurs during a :meth:`!load` call, the :class:`!CryptContext` - instance will be restored to the configuration it was in before - the :meth:`!load` call was made; this is to ensure it is - *never* left in an inconsistent state due to a load error. - - .. versionadded:: 1.6 - """ - #----------------------------------------------------------- - # autodetect source type, convert to dict - #----------------------------------------------------------- - parse_keys = True - if isinstance(source, unicode_or_bytes_types): - if PY3: - source = to_unicode(source, encoding, param="source") - else: - source = to_bytes(source, "utf-8", source_encoding=encoding, - param="source") - source = self._parse_ini_stream(NativeStringIO(source), section, - "") - elif isinstance(source, CryptContext): - # extract dict directly from config, so it can be merged later - source = dict(source._config.iter_config(resolve=True)) - parse_keys = False - elif not hasattr(source, "items"): - # mappings are left alone, otherwise throw an error. - raise ExpectedTypeError(source, "string or dict", "source") - - # XXX: add support for other iterable types, e.g. sequence of pairs? - - #----------------------------------------------------------- - # parse dict keys into (category, scheme, option) format, - # and merge with existing configuration if needed. - #----------------------------------------------------------- - if parse_keys: - parse = self._parse_config_key - source = dict((parse(key), value) - for key, value in iteritems(source)) - if update and self._config is not None: - # if updating, do nothing if source is empty, - if not source: - return - # otherwise overlay source on top of existing config - tmp = source - source = dict(self._config.iter_config(resolve=True)) - source.update(tmp) - - #----------------------------------------------------------- - # compile into _CryptConfig instance, and update state - #----------------------------------------------------------- - config = _CryptConfig(source) - self._config = config - self._reset_dummy_verify() - self._get_record = config.get_record - self._identify_record = config.identify_record - if config.context_kwds: - # (re-)enable method for this instance (in case ELSE clause below ran last load). - self.__dict__.pop("_strip_unused_context_kwds", None) - else: - # disable method for this instance, it's not needed. - self._strip_unused_context_kwds = None - - @staticmethod - def _parse_config_key(ckey): - """helper used to parse ``cat__scheme__option`` keys into a tuple""" - # split string into 1-3 parts - assert isinstance(ckey, native_string_types) - parts = ckey.replace(".", "__").split("__") - count = len(parts) - if count == 1: - cat, scheme, key = None, None, parts[0] - elif count == 2: - cat = None - scheme, key = parts - elif count == 3: - cat, scheme, key = parts - else: - raise TypeError("keys must have less than 3 separators: %r" % - (ckey,)) - # validate & normalize the parts - if cat == "default": - cat = None - elif not cat and cat is not None: - raise TypeError("empty category: %r" % ckey) - if scheme == "context": - scheme = None - elif not scheme and scheme is not None: - raise TypeError("empty scheme: %r" % ckey) - if not key: - raise TypeError("empty option: %r" % ckey) - return cat, scheme, key - - def update(self, *args, **kwds): - """Helper for quickly changing configuration. - - This acts much like the :meth:`!dict.update` method: - it updates the context's configuration, - replacing the original value(s) for the specified keys, - and preserving the rest. - It accepts any :ref:`keyword ` - accepted by the :class:`!CryptContext` constructor. - - .. versionadded:: 1.6 - - .. seealso:: :meth:`copy` - """ - if args: - if len(args) > 1: - raise TypeError("expected at most one positional argument") - if kwds: - raise TypeError("positional arg and keywords mutually exclusive") - self.load(args[0], update=True) - elif kwds: - self.load(kwds, update=True) - - # XXX: make this public? even just as flag to load? - # FIXME: this function suffered some bitrot in 1.6.1, - # will need to be updated before works again. - ##def _simplify(self): - ## "helper to remove redundant/unused options" - ## # don't do anything if no schemes are defined - ## if not self._schemes: - ## return - ## - ## def strip_items(target, filter): - ## keys = [key for key,value in iteritems(target) - ## if filter(key,value)] - ## for key in keys: - ## del target[key] - ## - ## # remove redundant default. - ## defaults = self._default_schemes - ## if defaults.get(None) == self._schemes[0]: - ## del defaults[None] - ## - ## # remove options for unused schemes. - ## scheme_options = self._scheme_options - ## schemes = self._schemes + ("all",) - ## strip_items(scheme_options, lambda k,v: k not in schemes) - ## - ## # remove rendundant cat defaults. - ## cur = self.default_scheme() - ## strip_items(defaults, lambda k,v: k and v==cur) - ## - ## # remove redundant category deprecations. - ## # TODO: this should work w/ 'auto', but needs closer inspection - ## deprecated = self._deprecated_schemes - ## cur = self._deprecated_schemes.get(None) - ## strip_items(deprecated, lambda k,v: k and v==cur) - ## - ## # remove redundant category options. - ## for scheme, config in iteritems(scheme_options): - ## if None in config: - ## cur = config[None] - ## strip_items(config, lambda k,v: k and v==cur) - ## - ## # XXX: anything else? - - #=================================================================== - # reading configuration - #=================================================================== - def schemes(self, resolve=False, category=None, unconfigured=False): - """return schemes loaded into this CryptContext instance. - - :type resolve: bool - :arg resolve: - if ``True``, will return a tuple of :class:`~passlib.ifc.PasswordHash` - objects instead of their names. - - :returns: - returns tuple of the schemes configured for this context - via the *schemes* option. - - .. versionadded:: 1.6 - This was previously available as ``CryptContext().policy.schemes()`` - - .. seealso:: the :ref:`schemes ` option for usage example. - """ - # XXX: should resolv return records rather than handlers? - # or deprecate resolve keyword completely? - # offering up a .hashers Mapping in v1.8 would be great. - # NOTE: supporting 'category' and 'unconfigured' kwds as of 1.7 - # just to pass through to .handler(), but not documenting them... - # may not need to put them to use. - schemes = self._config.schemes - if resolve: - return tuple(self.handler(scheme, category, unconfigured=unconfigured) - for scheme in schemes) - else: - return schemes - - def default_scheme(self, category=None, resolve=False, unconfigured=False): - """return name of scheme that :meth:`hash` will use by default. - - :type resolve: bool - :arg resolve: - if ``True``, will return a :class:`~passlib.ifc.PasswordHash` - object instead of the name. - - :type category: str or None - :param category: - Optional :ref:`user category `. - If specified, this will return the catgory-specific default scheme instead. - - :returns: - name of the default scheme. - - .. seealso:: the :ref:`default ` option for usage example. - - .. versionadded:: 1.6 - - .. versionchanged:: 1.7 - - This now returns a hasher configured with any CryptContext-specific - options (custom rounds settings, etc). Previously this returned - the base hasher from :mod:`passlib.hash`. - """ - # XXX: deprecate this in favor of .handler() or whatever it's replaced with? - # NOTE: supporting 'unconfigured' kwds as of 1.7 - # just to pass through to .handler(), but not documenting them... - # may not need to put them to use. - hasher = self.handler(None, category, unconfigured=unconfigured) - return hasher if resolve else hasher.name - - # XXX: need to decide if exposing this would be useful in any way - ##def categories(self): - ## """return user-categories with algorithm-specific options in this CryptContext. - ## - ## this will always return a tuple. - ## if no categories besides the default category have been configured, - ## the tuple will be empty. - ## """ - ## return self._config.categories - - # XXX: need to decide if exposing this would be useful to applications - # in any meaningful way that isn't already served by to_dict() - ##def options(self, scheme, category=None): - ## kwds, percat = self._config.get_options(scheme, category) - ## return kwds - - def handler(self, scheme=None, category=None, unconfigured=False): - """helper to resolve name of scheme -> :class:`~passlib.ifc.PasswordHash` object used by scheme. - - :arg scheme: - This should identify the scheme to lookup. - If omitted or set to ``None``, this will return the handler - for the default scheme. - - :arg category: - If a user category is specified, and no scheme is provided, - it will use the default for that category. - Otherwise this parameter is ignored. - - :param unconfigured: - - By default, this returns a handler object whose .hash() - and .needs_update() methods will honor the configured - provided by CryptContext. See ``unconfigured=True`` - to get the underlying handler from before any context-specific - configuration was applied. - - :raises KeyError: - If the scheme does not exist OR is not being used within this context. - - :returns: - :class:`~passlib.ifc.PasswordHash` object used to implement - the named scheme within this context (this will usually - be one of the objects from :mod:`passlib.hash`) - - .. versionadded:: 1.6 - This was previously available as ``CryptContext().policy.get_handler()`` - - .. versionchanged:: 1.7 - - This now returns a hasher configured with any CryptContext-specific - options (custom rounds settings, etc). Previously this returned - the base hasher from :mod:`passlib.hash`. - """ - try: - hasher = self._get_record(scheme, category) - if unconfigured: - return hasher._Context__orig_handler - else: - return hasher - except KeyError: - pass - if self._config.handlers: - raise KeyError("crypt algorithm not found in this " - "CryptContext instance: %r" % (scheme,)) - else: - raise KeyError("no crypt algorithms loaded in this " - "CryptContext instance") - - def _get_unregistered_handlers(self): - """check if any handlers in this context aren't in the global registry""" - return tuple(handler for handler in self._config.handlers - if not _is_handler_registered(handler)) - - @property - def context_kwds(self): - """ - return :class:`!set` containing union of all :ref:`contextual keywords ` - supported by the handlers in this context. - - .. versionadded:: 1.6.6 - """ - return self._config.context_kwds - - #=================================================================== - # exporting config - #=================================================================== - @staticmethod - def _render_config_key(key): - """convert 3-part config key to single string""" - cat, scheme, option = key - if cat: - return "%s__%s__%s" % (cat, scheme or "context", option) - elif scheme: - return "%s__%s" % (scheme, option) - else: - return option - - @staticmethod - def _render_ini_value(key, value): - """render value to string suitable for INI file""" - # convert lists to comma separated lists - # (mainly 'schemes' & 'deprecated') - if isinstance(value, (list,tuple)): - value = ", ".join(value) - - # convert numbers to strings - elif isinstance(value, num_types): - if isinstance(value, float) and key[2] == "vary_rounds": - value = ("%.2f" % value).rstrip("0") if value else "0" - else: - value = str(value) - - assert isinstance(value, native_string_types), \ - "expected string for key: %r %r" % (key, value) - - # escape any percent signs. - return value.replace("%", "%%") - - def to_dict(self, resolve=False): - """Return current configuration as a dictionary. - - :type resolve: bool - :arg resolve: - if ``True``, the ``schemes`` key will contain a list of - a :class:`~passlib.ifc.PasswordHash` objects instead of just - their names. - - This method dumps the current configuration of the CryptContext - instance. The key/value pairs should be in the format accepted - by the :class:`!CryptContext` class constructor, in fact - ``CryptContext(**myctx.to_dict())`` will create an exact copy of ``myctx``. - As an example:: - - >>> # you can dump the configuration of any crypt context... - >>> from passlib.apps import ldap_nocrypt_context - >>> ldap_nocrypt_context.to_dict() - {'schemes': ['ldap_salted_sha1', - 'ldap_salted_md5', - 'ldap_sha1', - 'ldap_md5', - 'ldap_plaintext']} - - .. versionadded:: 1.6 - This was previously available as ``CryptContext().policy.to_dict()`` - - .. seealso:: the :ref:`context-serialization-example` example in the tutorial. - """ - # XXX: should resolve default to conditional behavior - # based on presence of unregistered handlers? - render_key = self._render_config_key - return dict((render_key(key), value) - for key, value in self._config.iter_config(resolve)) - - def _write_to_parser(self, parser, section): - """helper to write to ConfigParser instance""" - render_key = self._render_config_key - render_value = self._render_ini_value - parser.add_section(section) - for k,v in self._config.iter_config(): - v = render_value(k, v) - k = render_key(k) - parser.set(section, k, v) - - def to_string(self, section="passlib"): - """serialize to INI format and return as unicode string. - - :param section: - name of INI section to output, defaults to ``"passlib"``. - - :returns: - CryptContext configuration, serialized to a INI unicode string. - - This function acts exactly like :meth:`to_dict`, except that it - serializes all the contents into a single human-readable string, - which can be hand edited, and/or stored in a file. The - output of this method is accepted by :meth:`from_string`, - :meth:`from_path`, and :meth:`load`. As an example:: - - >>> # you can dump the configuration of any crypt context... - >>> from passlib.apps import ldap_nocrypt_context - >>> print ldap_nocrypt_context.to_string() - [passlib] - schemes = ldap_salted_sha1, ldap_salted_md5, ldap_sha1, ldap_md5, ldap_plaintext - - .. versionadded:: 1.6 - This was previously available as ``CryptContext().policy.to_string()`` - - .. seealso:: the :ref:`context-serialization-example` example in the tutorial. - """ - parser = SafeConfigParser() - self._write_to_parser(parser, section) - buf = NativeStringIO() - parser.write(buf) - unregistered = self._get_unregistered_handlers() - if unregistered: - buf.write(( - "# NOTE: the %s handler(s) are not registered with Passlib,\n" - "# this string may not correctly reproduce the current configuration.\n\n" - ) % ", ".join(repr(handler.name) for handler in unregistered)) - out = buf.getvalue() - if not PY3: - out = out.decode("utf-8") - return out - - # XXX: is this useful enough to enable? - ##def write_to_path(self, path, section="passlib", update=False): - ## "write to INI file" - ## parser = ConfigParser() - ## if update and os.path.exists(path): - ## if not parser.read([path]): - ## raise EnvironmentError("failed to read existing file") - ## parser.remove_section(section) - ## self._write_to_parser(parser, section) - ## fh = file(path, "w") - ## parser.write(fh) - ## fh.close() - - #=================================================================== - # verify() hardening - # NOTE: this entire feature has been disabled. - # all contents of this section are NOOPs as of 1.7.1, - # and will be removed in 1.8. - #=================================================================== - - mvt_estimate_max_samples = 20 - mvt_estimate_min_samples = 10 - mvt_estimate_max_time = 2 - mvt_estimate_resolution = 0.01 - harden_verify = None - min_verify_time = 0 - - def reset_min_verify_time(self): - self._reset_dummy_verify() - - #=================================================================== - # password hash api - #=================================================================== - - # NOTE: all the following methods do is look up the appropriate - # custom handler for a given (scheme,category) combination, - # and hand off the real work to the handler itself, - # which is optimized for the specific (scheme,category) configuration. - # - # The custom handlers are cached inside the _CryptConfig - # instance stored in self._config, and are retrieved - # via get_record() and identify_record(). - # - # _get_record() and _identify_record() are references - # to _config methods of the same name, - # stored in CryptContext for speed. - - def _get_or_identify_record(self, hash, scheme=None, category=None): - """return record based on scheme, or failing that, by identifying hash""" - if scheme: - if not isinstance(hash, unicode_or_bytes_types): - raise ExpectedStringError(hash, "hash") - return self._get_record(scheme, category) - else: - # hash typecheck handled by identify_record() - return self._identify_record(hash, category) - - def _strip_unused_context_kwds(self, kwds, record): - """ - helper which removes any context keywords from **kwds** - that are known to be used by another scheme in this context, - but are NOT supported by handler specified by **record**. - - .. note:: - as optimization, load() will set this method to None on a per-instance basis - if there are no context kwds. - """ - if not kwds: - return - unused_kwds = self._config.context_kwds.difference(record.context_kwds) - for key in unused_kwds: - kwds.pop(key, None) - - def needs_update(self, hash, scheme=None, category=None, secret=None): - """Check if hash needs to be replaced for some reason, - in which case the secret should be re-hashed. - - This function is the core of CryptContext's support for hash migration: - This function takes in a hash string, and checks the scheme, - number of rounds, and other properties against the current policy. - It returns ``True`` if the hash is using a deprecated scheme, - or is otherwise outside of the bounds specified by the policy - (e.g. the number of rounds is lower than :ref:`min_rounds ` - configuration for that algorithm). - If so, the password should be re-hashed using :meth:`hash` - Otherwise, it will return ``False``. - - :type hash: unicode or bytes - :arg hash: - The hash string to examine. - - :type scheme: str or None - :param scheme: - - Optional scheme to use. Scheme must be one of the ones - configured for this context (see the - :ref:`schemes ` option). - If no scheme is specified, it will be identified - based on the value of *hash*. - - .. deprecated:: 1.7 - - Support for this keyword is deprecated, and will be removed in Passlib 2.0. - - :type category: str or None - :param category: - Optional :ref:`user category `. - If specified, this will cause any category-specific defaults to - be used when determining if the hash needs to be updated - (e.g. is below the minimum rounds). - - :type secret: unicode, bytes, or None - :param secret: - Optional secret associated with the provided ``hash``. - This is not required, or even currently used for anything... - it's for forward-compatibility with any future - update checks that might need this information. - If provided, Passlib assumes the secret has already been - verified successfully against the hash. - - .. versionadded:: 1.6 - - :returns: ``True`` if hash should be replaced, otherwise ``False``. - - :raises ValueError: - If the hash did not match any of the configured :meth:`schemes`. - - .. versionadded:: 1.6 - This method was previously named :meth:`hash_needs_update`. - - .. seealso:: the :ref:`context-migration-example` example in the tutorial. - """ - if scheme is not None: - # TODO: offer replacement alternative. - # ``context.handler(scheme).needs_update()`` would work, - # but may deprecate .handler() in passlib 1.8. - warn("CryptContext.needs_update(): 'scheme' keyword is deprecated as of " - "Passlib 1.7, and will be removed in Passlib 2.0", - DeprecationWarning) - record = self._get_or_identify_record(hash, scheme, category) - return record.deprecated or record.needs_update(hash, secret=secret) - - @deprecated_method(deprecated="1.6", removed="2.0", replacement="CryptContext.needs_update()") - def hash_needs_update(self, hash, scheme=None, category=None): - """Legacy alias for :meth:`needs_update`. - - .. deprecated:: 1.6 - This method was renamed to :meth:`!needs_update` in version 1.6. - This alias will be removed in version 2.0, and should only - be used for compatibility with Passlib 1.3 - 1.5. - """ - return self.needs_update(hash, scheme, category) - - @deprecated_method(deprecated="1.7", removed="2.0") - def genconfig(self, scheme=None, category=None, **settings): - """Generate a config string for specified scheme. - - .. deprecated:: 1.7 - - This method will be removed in version 2.0, and should only - be used for compatibility with Passlib 1.3 - 1.6. - """ - record = self._get_record(scheme, category) - strip_unused = self._strip_unused_context_kwds - if strip_unused: - strip_unused(settings, record) - return record.genconfig(**settings) - - @deprecated_method(deprecated="1.7", removed="2.0") - def genhash(self, secret, config, scheme=None, category=None, **kwds): - """Generate hash for the specified secret using another hash. - - .. deprecated:: 1.7 - - This method will be removed in version 2.0, and should only - be used for compatibility with Passlib 1.3 - 1.6. - """ - record = self._get_or_identify_record(config, scheme, category) - strip_unused = self._strip_unused_context_kwds - if strip_unused: - strip_unused(kwds, record) - return record.genhash(secret, config, **kwds) - - def identify(self, hash, category=None, resolve=False, required=False, - unconfigured=False): - """Attempt to identify which algorithm the hash belongs to. - - Note that this will only consider the algorithms - currently configured for this context - (see the :ref:`schemes ` option). - All registered algorithms will be checked, from first to last, - and whichever one positively identifies the hash first will be returned. - - :type hash: unicode or bytes - :arg hash: - The hash string to test. - - :type category: str or None - :param category: - Optional :ref:`user category `. - Ignored by this function, this parameter - is provided for symmetry with the other methods. - - :type resolve: bool - :param resolve: - If ``True``, returns the hash handler itself, - instead of the name of the hash. - - :type required: bool - :param required: - If ``True``, this will raise a ValueError if the hash - cannot be identified, instead of returning ``None``. - - :returns: - The handler which first identifies the hash, - or ``None`` if none of the algorithms identify the hash. - """ - record = self._identify_record(hash, category, required) - if record is None: - return None - elif resolve: - if unconfigured: - return record._Context__orig_handler - else: - return record - else: - return record.name - - def hash(self, secret, scheme=None, category=None, **kwds): - """run secret through selected algorithm, returning resulting hash. - - :type secret: unicode or bytes - :arg secret: - the password to hash. - - :type scheme: str or None - :param scheme: - - Optional scheme to use. Scheme must be one of the ones - configured for this context (see the - :ref:`schemes ` option). - If no scheme is specified, the configured default - will be used. - - .. deprecated:: 1.7 - - Support for this keyword is deprecated, and will be removed in Passlib 2.0. - - :type category: str or None - :param category: - Optional :ref:`user category `. - If specified, this will cause any category-specific defaults to - be used when hashing the password (e.g. different default scheme, - different default rounds values, etc). - - :param \\*\\*kwds: - All other keyword options are passed to the selected algorithm's - :meth:`PasswordHash.hash() ` method. - - :returns: - The secret as encoded by the specified algorithm and options. - The return value will always be a :class:`!str`. - - :raises TypeError, ValueError: - * If any of the arguments have an invalid type or value. - This includes any keywords passed to the underlying hash's - :meth:`PasswordHash.hash() ` method. - - .. seealso:: the :ref:`context-basic-example` example in the tutorial - """ - # XXX: could insert normalization to preferred unicode encoding here - if scheme is not None: - # TODO: offer replacement alternative. - # ``context.handler(scheme).hash()`` would work, - # but may deprecate .handler() in passlib 1.8. - warn("CryptContext.hash(): 'scheme' keyword is deprecated as of " - "Passlib 1.7, and will be removed in Passlib 2.0", - DeprecationWarning) - record = self._get_record(scheme, category) - strip_unused = self._strip_unused_context_kwds - if strip_unused: - strip_unused(kwds, record) - return record.hash(secret, **kwds) - - @deprecated_method(deprecated="1.7", removed="2.0", replacement="CryptContext.hash()") - def encrypt(self, *args, **kwds): - """ - Legacy alias for :meth:`hash`. - - .. deprecated:: 1.7 - This method was renamed to :meth:`!hash` in version 1.7. - This alias will be removed in version 2.0, and should only - be used for compatibility with Passlib 1.3 - 1.6. - """ - return self.hash(*args, **kwds) - - def verify(self, secret, hash, scheme=None, category=None, **kwds): - """verify secret against an existing hash. - - If no scheme is specified, this will attempt to identify - the scheme based on the contents of the provided hash - (limited to the schemes configured for this context). - It will then check whether the password verifies against the hash. - - :type secret: unicode or bytes - :arg secret: - the secret to verify - - :type hash: unicode or bytes - :arg hash: - hash string to compare to - - if ``None`` is passed in, this will be treated as "never verifying" - - :type scheme: str - :param scheme: - Optionally force context to use specific scheme. - This is usually not needed, as most hashes can be unambiguously - identified. Scheme must be one of the ones configured - for this context - (see the :ref:`schemes ` option). - - .. deprecated:: 1.7 - - Support for this keyword is deprecated, and will be removed in Passlib 2.0. - - :type category: str or None - :param category: - Optional :ref:`user category ` string. - This is mainly used when generating new hashes, it has little - effect when verifying; this keyword is mainly provided for symmetry. - - :param \\*\\*kwds: - All additional keywords are passed to the appropriate handler, - and should match its :attr:`~passlib.ifc.PasswordHash.context_kwds`. - - :returns: - ``True`` if the password matched the hash, else ``False``. - - :raises ValueError: - * if the hash did not match any of the configured :meth:`schemes`. - - * if any of the arguments have an invalid value (this includes - any keywords passed to the underlying hash's - :meth:`PasswordHash.verify() ` method). - - :raises TypeError: - * if any of the arguments have an invalid type (this includes - any keywords passed to the underlying hash's - :meth:`PasswordHash.verify() ` method). - - .. seealso:: the :ref:`context-basic-example` example in the tutorial - """ - # XXX: could insert normalization to preferred unicode encoding here - # XXX: what about supporting a setter() callback ala django 1.4 ? - if scheme is not None: - # TODO: offer replacement alternative. - # ``context.handler(scheme).verify()`` would work, - # but may deprecate .handler() in passlib 1.8. - warn("CryptContext.verify(): 'scheme' keyword is deprecated as of " - "Passlib 1.7, and will be removed in Passlib 2.0", - DeprecationWarning) - if hash is None: - # convenience feature -- let apps pass in hash=None when user - # isn't found / has no hash; useful because it invokes dummy_verify() - self.dummy_verify() - return False - record = self._get_or_identify_record(hash, scheme, category) - strip_unused = self._strip_unused_context_kwds - if strip_unused: - strip_unused(kwds, record) - return record.verify(secret, hash, **kwds) - - def verify_and_update(self, secret, hash, scheme=None, category=None, **kwds): - """verify password and re-hash the password if needed, all in a single call. - - This is a convenience method which takes care of all the following: - first it verifies the password (:meth:`~CryptContext.verify`), if this is successfull - it checks if the hash needs updating (:meth:`~CryptContext.needs_update`), and if so, - re-hashes the password (:meth:`~CryptContext.hash`), returning the replacement hash. - This series of steps is a very common task for applications - which wish to update deprecated hashes, and this call takes - care of all 3 steps efficiently. - - :type secret: unicode or bytes - :arg secret: - the secret to verify - - :type secret: unicode or bytes - :arg hash: - hash string to compare to. - - if ``None`` is passed in, this will be treated as "never verifying" - - :type scheme: str - :param scheme: - Optionally force context to use specific scheme. - This is usually not needed, as most hashes can be unambiguously - identified. Scheme must be one of the ones configured - for this context - (see the :ref:`schemes ` option). - - .. deprecated:: 1.7 - - Support for this keyword is deprecated, and will be removed in Passlib 2.0. - - :type category: str or None - :param category: - Optional :ref:`user category `. - If specified, this will cause any category-specific defaults to - be used if the password has to be re-hashed. - - :param \\*\\*kwds: - all additional keywords are passed to the appropriate handler, - and should match that hash's - :attr:`PasswordHash.context_kwds `. - - :returns: - This function returns a tuple containing two elements: - ``(verified, replacement_hash)``. The first is a boolean - flag indicating whether the password verified, - and the second an optional replacement hash. - The tuple will always match one of the following 3 cases: - - * ``(False, None)`` indicates the secret failed to verify. - * ``(True, None)`` indicates the secret verified correctly, - and the hash does not need updating. - * ``(True, str)`` indicates the secret verified correctly, - but the current hash needs to be updated. The :class:`!str` - will be the freshly generated hash, to replace the old one. - - :raises TypeError, ValueError: - For the same reasons as :meth:`verify`. - - .. seealso:: the :ref:`context-migration-example` example in the tutorial. - """ - # XXX: could insert normalization to preferred unicode encoding here. - if scheme is not None: - warn("CryptContext.verify(): 'scheme' keyword is deprecated as of " - "Passlib 1.7, and will be removed in Passlib 2.0", - DeprecationWarning) - if hash is None: - # convenience feature -- let apps pass in hash=None when user - # isn't found / has no hash; useful because it invokes dummy_verify() - self.dummy_verify() - return False, None - record = self._get_or_identify_record(hash, scheme, category) - strip_unused = self._strip_unused_context_kwds - if strip_unused and kwds: - clean_kwds = kwds.copy() - strip_unused(clean_kwds, record) - else: - clean_kwds = kwds - # XXX: if record is default scheme, could extend PasswordHash - # api to combine verify & needs_update to single call, - # potentially saving some round-trip parsing. - # but might make these codepaths more complex... - if not record.verify(secret, hash, **clean_kwds): - return False, None - elif record.deprecated or record.needs_update(hash, secret=secret): - # NOTE: we re-hash with default scheme, not current one. - return True, self.hash(secret, category=category, **kwds) - else: - return True, None - - #=================================================================== - # missing-user helper - #=================================================================== - - #: secret used for dummy_verify() - _dummy_secret = "too many secrets" - - @memoized_property - def _dummy_hash(self): - """ - precalculated hash for dummy_verify() to use - """ - return self.hash(self._dummy_secret) - - def _reset_dummy_verify(self): - """ - flush memoized values used by dummy_verify() - """ - type(self)._dummy_hash.clear_cache(self) - - def dummy_verify(self, elapsed=0): - """ - Helper that applications can call when user wasn't found, - in order to simulate time it would take to hash a password. - - Runs verify() against a dummy hash, to simulate verification - of a real account password. - - :param elapsed: - - .. deprecated:: 1.7.1 - - this option is ignored, and will be removed in passlib 1.8. - - .. versionadded:: 1.7 - """ - self.verify(self._dummy_secret, self._dummy_hash) - return False - - #=================================================================== - # disabled hash support - #=================================================================== - - def is_enabled(self, hash): - """ - test if hash represents a usuable password -- - i.e. does not represent an unusuable password such as ``"!"``, - which is recognized by the :class:`~passlib.hash.unix_disabled` hash. - - :raises ValueError: - if the hash is not recognized - (typically solved by adding ``unix_disabled`` to the list of schemes). - """ - return not self._identify_record(hash, None).is_disabled - - def disable(self, hash=None): - """ - return a string to disable logins for user, - usually by returning a non-verifying string such as ``"!"``. - - :param hash: - Callers can optionally provide the account's existing hash. - Some disabled handlers (such as :class:`!unix_disabled`) - will encode this into the returned value, - so that it can be recovered via :meth:`enable`. - - :raises RuntimeError: - if this function is called w/o a disabled hasher - (such as :class:`~passlib.hash.unix_disabled`) included - in the list of schemes. - - :returns: - hash string which will be recognized as valid by the context, - but is guaranteed to not validate against *any* password. - """ - record = self._config.disabled_record - assert record.is_disabled - return record.disable(hash) - - def enable(self, hash): - """ - inverse of :meth:`disable` -- - attempts to recover original hash which was converted - by a :meth:`!disable` call into a disabled hash -- - thus restoring the user's original password. - - :raises ValueError: - if original hash not present, or if the disabled handler doesn't - support encoding the original hash (e.g. ``django_disabled``) - - :returns: - the original hash. - """ - record = self._identify_record(hash, None) - if record.is_disabled: - # XXX: should we throw error if result can't be identified by context? - return record.enable(hash) - else: - # hash wasn't a disabled hash, so return unchanged - return hash - - #=================================================================== - # eoc - #=================================================================== - -class LazyCryptContext(CryptContext): - """CryptContext subclass which doesn't load handlers until needed. - - This is a subclass of CryptContext which takes in a set of arguments - exactly like CryptContext, but won't import any handlers - (or even parse its arguments) until - the first time one of its methods is accessed. - - :arg schemes: - The first positional argument can be a list of schemes, or omitted, - just like CryptContext. - - :param onload: - - If a callable is passed in via this keyword, - it will be invoked at lazy-load time - with the following signature: - ``onload(**kwds) -> kwds``; - where ``kwds`` is all the additional kwds passed to LazyCryptContext. - It should perform any additional deferred initialization, - and return the final dict of options to be passed to CryptContext. - - .. versionadded:: 1.6 - - :param create_policy: - - .. deprecated:: 1.6 - This option will be removed in Passlib 1.8, - applications should use ``onload`` instead. - - :param kwds: - - All additional keywords are passed to CryptContext; - or to the *onload* function (if provided). - - This is mainly used internally by modules such as :mod:`passlib.apps`, - which define a large number of contexts, but only a few of them will be needed - at any one time. Use of this class saves the memory needed to import - the specified handlers until the context instance is actually accessed. - As well, it allows constructing a context at *module-init* time, - but using :func:`!onload()` to provide dynamic configuration - at *application-run* time. - - .. note:: - This class is only useful if you're referencing handler objects by name, - and don't want them imported until runtime. If you want to have the config - validated before your application runs, or are passing in already-imported - handler instances, you should use :class:`CryptContext` instead. - - .. versionadded:: 1.4 - """ - _lazy_kwds = None - - # NOTE: the way this class works changed in 1.6. - # previously it just called _lazy_init() when ``.policy`` was - # first accessed. now that is done whenever any of the public - # attributes are accessed, and the class itself is changed - # to a regular CryptContext, to remove the overhead once it's unneeded. - - def __init__(self, schemes=None, **kwds): - if schemes is not None: - kwds['schemes'] = schemes - self._lazy_kwds = kwds - - def _lazy_init(self): - kwds = self._lazy_kwds - if 'create_policy' in kwds: - warn("The CryptPolicy class, and LazyCryptContext's " - "``create_policy`` keyword have been deprecated as of " - "Passlib 1.6, and will be removed in Passlib 1.8; " - "please use the ``onload`` keyword instead.", - DeprecationWarning) - create_policy = kwds.pop("create_policy") - result = create_policy(**kwds) - policy = CryptPolicy.from_source(result, _warn=False) - kwds = policy._context.to_dict() - elif 'onload' in kwds: - onload = kwds.pop("onload") - kwds = onload(**kwds) - del self._lazy_kwds - super(LazyCryptContext, self).__init__(**kwds) - self.__class__ = CryptContext - - def __getattribute__(self, attr): - if (not attr.startswith("_") or attr.startswith("__")) and \ - self._lazy_kwds is not None: - self._lazy_init() - return object.__getattribute__(self, attr) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/__init__.py deleted file mode 100644 index 89f5484..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""passlib.crypto -- package containing cryptographic primitives used by passlib""" diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/__init__.py deleted file mode 100644 index 1aa1c85..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/__init__.py +++ /dev/null @@ -1,169 +0,0 @@ -"""passlib.crypto._blowfish - pure-python eks-blowfish implementation for bcrypt - -This is a pure-python implementation of the EKS-Blowfish algorithm described by -Provos and Mazieres in `A Future-Adaptable Password Scheme -`_. - -This package contains two submodules: - -* ``_blowfish/base.py`` contains a class implementing the eks-blowfish algorithm - using easy-to-examine code. - -* ``_blowfish/unrolled.py`` contains a subclass which replaces some methods - of the original class with sped-up versions, mainly using unrolled loops - and local variables. this is the class which is actually used by - Passlib to perform BCrypt in pure python. - - This module is auto-generated by a script, ``_blowfish/_gen_files.py``. - -Status ------- -This implementation is usable, but is an order of magnitude too slow to be -usable with real security. For "ok" security, BCrypt hashes should have at -least 2**11 rounds (as of 2011). Assuming a desired response time <= 100ms, -this means a BCrypt implementation should get at least 20 rounds/ms in order -to be both usable *and* secure. On a 2 ghz cpu, this implementation gets -roughly 0.09 rounds/ms under CPython (220x too slow), and 1.9 rounds/ms -under PyPy (10x too slow). - -History -------- -While subsequently modified considerly for Passlib, this code was originally -based on `jBcrypt 0.2 `_, which was -released under the BSD license:: - - Copyright (c) 2006 Damien Miller - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -#============================================================================= -# imports -#============================================================================= -# core -from itertools import chain -import struct -# pkg -from passlib.utils import getrandbytes, rng -from passlib.utils.binary import bcrypt64 -from passlib.utils.compat import BytesIO, unicode, u, native_string_types -from passlib.crypto._blowfish.unrolled import BlowfishEngine -# local -__all__ = [ - 'BlowfishEngine', - 'raw_bcrypt', -] - -#============================================================================= -# bcrypt constants -#============================================================================= - -# bcrypt constant data "OrpheanBeholderScryDoubt" as 6 integers -BCRYPT_CDATA = [ - 0x4f727068, 0x65616e42, 0x65686f6c, - 0x64657253, 0x63727944, 0x6f756274 -] - -# struct used to encode ciphertext as digest (last output byte discarded) -digest_struct = struct.Struct(">6I") - -#============================================================================= -# base bcrypt helper -# -# interface designed only for use by passlib.handlers.bcrypt:BCrypt -# probably not suitable for other purposes -#============================================================================= -BNULL = b'\x00' - -def raw_bcrypt(password, ident, salt, log_rounds): - """perform central password hashing step in bcrypt scheme. - - :param password: the password to hash - :param ident: identifier w/ minor version (e.g. 2, 2a) - :param salt: the binary salt to use (encoded in bcrypt-base64) - :param log_rounds: the log2 of the number of rounds (as int) - :returns: bcrypt-base64 encoded checksum - """ - #=================================================================== - # parse inputs - #=================================================================== - - # parse ident - assert isinstance(ident, native_string_types) - add_null_padding = True - if ident == u('2a') or ident == u('2y') or ident == u('2b'): - pass - elif ident == u('2'): - add_null_padding = False - elif ident == u('2x'): - raise ValueError("crypt_blowfish's buggy '2x' hashes are not " - "currently supported") - else: - raise ValueError("unknown ident: %r" % (ident,)) - - # decode & validate salt - assert isinstance(salt, bytes) - salt = bcrypt64.decode_bytes(salt) - if len(salt) < 16: - raise ValueError("Missing salt bytes") - elif len(salt) > 16: - salt = salt[:16] - - # prepare password - assert isinstance(password, bytes) - if add_null_padding: - password += BNULL - - # validate rounds - if log_rounds < 4 or log_rounds > 31: - raise ValueError("Bad number of rounds") - - #=================================================================== - # - # run EKS-Blowfish algorithm - # - # This uses the "enhanced key schedule" step described by - # Provos and Mazieres in "A Future-Adaptable Password Scheme" - # http://www.openbsd.org/papers/bcrypt-paper.ps - # - #=================================================================== - - engine = BlowfishEngine() - - # convert password & salt into list of 18 32-bit integers (72 bytes total). - pass_words = engine.key_to_words(password) - salt_words = engine.key_to_words(salt) - - # truncate salt_words to original 16 byte salt, or loop won't wrap - # correctly when passed to .eks_salted_expand() - salt_words16 = salt_words[:4] - - # do EKS key schedule setup - engine.eks_salted_expand(pass_words, salt_words16) - - # apply password & salt keys to key schedule a bunch more times. - rounds = 1<> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) -""".strip() - -def render_encipher(write, indent=0): - for i in irange(0, 15, 2): - write(indent, """\ - # Feistel substitution on left word (round %(i)d) - r ^= %(left)s ^ p%(i1)d - - # Feistel substitution on right word (round %(i1)d) - l ^= %(right)s ^ p%(i2)d - """, i=i, i1=i+1, i2=i+2, - left=BFSTR, right=BFSTR.replace("l","r"), - ) - -def write_encipher_function(write, indent=0): - write(indent, """\ - def encipher(self, l, r): - \"""blowfish encipher a single 64-bit block encoded as two 32-bit ints\""" - - (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, - p10, p11, p12, p13, p14, p15, p16, p17) = self.P - S0, S1, S2, S3 = self.S - - l ^= p0 - - """) - render_encipher(write, indent+1) - - write(indent+1, """\ - - return r ^ p17, l - - """) - -def write_expand_function(write, indent=0): - write(indent, """\ - def expand(self, key_words): - \"""unrolled version of blowfish key expansion\""" - ##assert len(key_words) >= 18, "size of key_words must be >= 18" - - P, S = self.P, self.S - S0, S1, S2, S3 = S - - #============================================================= - # integrate key - #============================================================= - """) - for i in irange(18): - write(indent+1, """\ - p%(i)d = P[%(i)d] ^ key_words[%(i)d] - """, i=i) - write(indent+1, """\ - - #============================================================= - # update P - #============================================================= - - #------------------------------------------------ - # update P[0] and P[1] - #------------------------------------------------ - l, r = p0, 0 - - """) - - render_encipher(write, indent+1) - - write(indent+1, """\ - - p0, p1 = l, r = r ^ p17, l - - """) - - for i in irange(2, 18, 2): - write(indent+1, """\ - #------------------------------------------------ - # update P[%(i)d] and P[%(i1)d] - #------------------------------------------------ - l ^= p0 - - """, i=i, i1=i+1) - - render_encipher(write, indent+1) - - write(indent+1, """\ - p%(i)d, p%(i1)d = l, r = r ^ p17, l - - """, i=i, i1=i+1) - - write(indent+1, """\ - - #------------------------------------------------ - # save changes to original P array - #------------------------------------------------ - P[:] = (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, - p10, p11, p12, p13, p14, p15, p16, p17) - - #============================================================= - # update S - #============================================================= - - for box in S: - j = 0 - while j < 256: - l ^= p0 - - """) - - render_encipher(write, indent+3) - - write(indent+3, """\ - - box[j], box[j+1] = l, r = r ^ p17, l - j += 2 - """) - -#============================================================================= -# main -#============================================================================= - -def main(): - target = os.path.join(os.path.dirname(__file__), "unrolled.py") - fh = file(target, "w") - - def write(indent, msg, **kwds): - literal = kwds.pop("literal", False) - if kwds: - msg %= kwds - if not literal: - msg = textwrap.dedent(msg.rstrip(" ")) - if indent: - msg = indent_block(msg, " " * (indent*4)) - fh.write(msg) - - write(0, """\ - \"""passlib.crypto._blowfish.unrolled - unrolled loop implementation of bcrypt, - autogenerated by _gen_files.py - - currently this override the encipher() and expand() methods - with optimized versions, and leaves the other base.py methods alone. - \""" - #================================================================= - # imports - #================================================================= - # pkg - from passlib.crypto._blowfish.base import BlowfishEngine as _BlowfishEngine - # local - __all__ = [ - "BlowfishEngine", - ] - #================================================================= - # - #================================================================= - class BlowfishEngine(_BlowfishEngine): - - """) - - write_encipher_function(write, indent=1) - write_expand_function(write, indent=1) - - write(0, """\ - #================================================================= - # eoc - #================================================================= - - #================================================================= - # eof - #================================================================= - """) - -if __name__ == "__main__": - main() - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/base.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/base.py deleted file mode 100644 index 7b4f2cb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/base.py +++ /dev/null @@ -1,441 +0,0 @@ -"""passlib.crypto._blowfish.base - unoptimized pure-python blowfish engine""" -#============================================================================= -# imports -#============================================================================= -# core -import struct -# pkg -from passlib.utils import repeat_string -# local -__all__ = [ - "BlowfishEngine", -] - -#============================================================================= -# blowfish constants -#============================================================================= -BLOWFISH_P = BLOWFISH_S = None - -def _init_constants(): - global BLOWFISH_P, BLOWFISH_S - - # NOTE: blowfish's spec states these numbers are the hex representation - # of the fractional portion of PI, in order. - - # Initial contents of key schedule - 18 integers - BLOWFISH_P = [ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, - 0x9216d5d9, 0x8979fb1b, - ] - - # all 4 blowfish S boxes in one array - 256 integers per S box - BLOWFISH_S = [ - # sbox 1 - [ - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, - 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, - 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, - 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, - 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, - 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, - 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, - 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, - 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, - 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, - 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, - 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, - 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, - 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, - 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, - 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, - 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, - 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, - 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, - 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, - 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, - 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, - ], - # sbox 2 - [ - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, - 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, - 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, - 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, - 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, - 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, - 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, - 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, - 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, - 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, - 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, - 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, - 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, - 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, - 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, - 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, - 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, - 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, - 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, - 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, - 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, - 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, - ], - # sbox 3 - [ - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, - 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, - 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, - 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, - 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, - 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, - 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, - 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, - 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, - 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, - 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, - 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, - 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, - 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, - 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, - 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, - 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, - 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, - 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, - 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, - 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, - 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, - ], - # sbox 4 - [ - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, - 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, - 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, - 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, - 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, - 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, - 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, - 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, - 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, - 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, - 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, - 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, - 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, - 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, - 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, - 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, - 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, - 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, - 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, - 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, - 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, - 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, - ] - ] - -#============================================================================= -# engine -#============================================================================= -class BlowfishEngine(object): - - def __init__(self): - if BLOWFISH_P is None: - _init_constants() - self.P = list(BLOWFISH_P) - self.S = [ list(box) for box in BLOWFISH_S ] - - #=================================================================== - # common helpers - #=================================================================== - @staticmethod - def key_to_words(data, size=18): - """convert data to tuple of 4-byte integers, repeating or - truncating data as needed to reach specified size""" - assert isinstance(data, bytes) - dlen = len(data) - if not dlen: - # return all zeros - original C code would just read the NUL after - # the password, so mimicing that behavior for this edge case. - return [0]*size - - # repeat data until it fills up 4*size bytes - data = repeat_string(data, size<<2) - - # unpack - return struct.unpack(">%dI" % (size,), data) - - #=================================================================== - # blowfish routines - #=================================================================== - def encipher(self, l, r): - """loop version of blowfish encipher routine""" - P, S = self.P, self.S - l ^= P[0] - i = 1 - while i < 17: - # Feistel substitution on left word - r = ((((S[0][l >> 24] + S[1][(l >> 16) & 0xff]) ^ S[2][(l >> 8) & 0xff]) + - S[3][l & 0xff]) & 0xffffffff) ^ P[i] ^ r - # swap vars so even rounds do Feistel substition on right word - l, r = r, l - i += 1 - return r ^ P[17], l - - # NOTE: decipher is same as above, just with reversed(P) instead. - - def expand(self, key_words): - """perform stock Blowfish keyschedule setup""" - assert len(key_words) >= 18, "key_words must be at least as large as P" - P, S, encipher = self.P, self.S, self.encipher - - i = 0 - while i < 18: - P[i] ^= key_words[i] - i += 1 - - i = l = r = 0 - while i < 18: - P[i], P[i+1] = l,r = encipher(l,r) - i += 2 - - for box in S: - i = 0 - while i < 256: - box[i], box[i+1] = l,r = encipher(l,r) - i += 2 - - #=================================================================== - # eks-blowfish routines - #=================================================================== - def eks_salted_expand(self, key_words, salt_words): - """perform EKS' salted version of Blowfish keyschedule setup""" - # NOTE: this is the same as expand(), except for the addition - # of the operations involving *salt_words*. - - assert len(key_words) >= 18, "key_words must be at least as large as P" - salt_size = len(salt_words) - assert salt_size, "salt_words must not be empty" - assert not salt_size & 1, "salt_words must have even length" - P, S, encipher = self.P, self.S, self.encipher - - i = 0 - while i < 18: - P[i] ^= key_words[i] - i += 1 - - s = i = l = r = 0 - while i < 18: - l ^= salt_words[s] - r ^= salt_words[s+1] - s += 2 - if s == salt_size: - s = 0 - P[i], P[i+1] = l,r = encipher(l,r) # next() - i += 2 - - for box in S: - i = 0 - while i < 256: - l ^= salt_words[s] - r ^= salt_words[s+1] - s += 2 - if s == salt_size: - s = 0 - box[i], box[i+1] = l,r = encipher(l,r) # next() - i += 2 - - def eks_repeated_expand(self, key_words, salt_words, rounds): - """perform rounds stage of EKS keyschedule setup""" - expand = self.expand - n = 0 - while n < rounds: - expand(key_words) - expand(salt_words) - n += 1 - - def repeat_encipher(self, l, r, count): - """repeatedly apply encipher operation to a block""" - encipher = self.encipher - n = 0 - while n < count: - l, r = encipher(l, r) - n += 1 - return l, r - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/unrolled.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/unrolled.py deleted file mode 100644 index 4acf6e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_blowfish/unrolled.py +++ /dev/null @@ -1,771 +0,0 @@ -"""passlib.crypto._blowfish.unrolled - unrolled loop implementation of bcrypt, -autogenerated by _gen_files.py - -currently this override the encipher() and expand() methods -with optimized versions, and leaves the other base.py methods alone. -""" -#============================================================================= -# imports -#============================================================================= -# pkg -from passlib.crypto._blowfish.base import BlowfishEngine as _BlowfishEngine -# local -__all__ = [ - "BlowfishEngine", -] -#============================================================================= -# -#============================================================================= -class BlowfishEngine(_BlowfishEngine): - - def encipher(self, l, r): - """blowfish encipher a single 64-bit block encoded as two 32-bit ints""" - - (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, - p10, p11, p12, p13, p14, p15, p16, p17) = self.P - S0, S1, S2, S3 = self.S - - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - - return r ^ p17, l - - def expand(self, key_words): - """unrolled version of blowfish key expansion""" - ##assert len(key_words) >= 18, "size of key_words must be >= 18" - - P, S = self.P, self.S - S0, S1, S2, S3 = S - - #============================================================= - # integrate key - #============================================================= - p0 = P[0] ^ key_words[0] - p1 = P[1] ^ key_words[1] - p2 = P[2] ^ key_words[2] - p3 = P[3] ^ key_words[3] - p4 = P[4] ^ key_words[4] - p5 = P[5] ^ key_words[5] - p6 = P[6] ^ key_words[6] - p7 = P[7] ^ key_words[7] - p8 = P[8] ^ key_words[8] - p9 = P[9] ^ key_words[9] - p10 = P[10] ^ key_words[10] - p11 = P[11] ^ key_words[11] - p12 = P[12] ^ key_words[12] - p13 = P[13] ^ key_words[13] - p14 = P[14] ^ key_words[14] - p15 = P[15] ^ key_words[15] - p16 = P[16] ^ key_words[16] - p17 = P[17] ^ key_words[17] - - #============================================================= - # update P - #============================================================= - - #------------------------------------------------ - # update P[0] and P[1] - #------------------------------------------------ - l, r = p0, 0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - - p0, p1 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[2] and P[3] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p2, p3 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[4] and P[5] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p4, p5 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[6] and P[7] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p6, p7 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[8] and P[9] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p8, p9 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[10] and P[11] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p10, p11 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[12] and P[13] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p12, p13 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[14] and P[15] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p14, p15 = l, r = r ^ p17, l - - #------------------------------------------------ - # update P[16] and P[17] - #------------------------------------------------ - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - p16, p17 = l, r = r ^ p17, l - - - #------------------------------------------------ - # save changes to original P array - #------------------------------------------------ - P[:] = (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, - p10, p11, p12, p13, p14, p15, p16, p17) - - #============================================================= - # update S - #============================================================= - - for box in S: - j = 0 - while j < 256: - l ^= p0 - - # Feistel substitution on left word (round 0) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p1 - - # Feistel substitution on right word (round 1) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p2 - # Feistel substitution on left word (round 2) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p3 - - # Feistel substitution on right word (round 3) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p4 - # Feistel substitution on left word (round 4) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p5 - - # Feistel substitution on right word (round 5) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p6 - # Feistel substitution on left word (round 6) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p7 - - # Feistel substitution on right word (round 7) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p8 - # Feistel substitution on left word (round 8) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p9 - - # Feistel substitution on right word (round 9) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p10 - # Feistel substitution on left word (round 10) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p11 - - # Feistel substitution on right word (round 11) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p12 - # Feistel substitution on left word (round 12) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p13 - - # Feistel substitution on right word (round 13) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p14 - # Feistel substitution on left word (round 14) - r ^= ((((S0[l >> 24] + S1[(l >> 16) & 0xff]) ^ S2[(l >> 8) & 0xff]) + - S3[l & 0xff]) & 0xffffffff) ^ p15 - - # Feistel substitution on right word (round 15) - l ^= ((((S0[r >> 24] + S1[(r >> 16) & 0xff]) ^ S2[(r >> 8) & 0xff]) + - S3[r & 0xff]) & 0xffffffff) ^ p16 - - box[j], box[j+1] = l, r = r ^ p17, l - j += 2 - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_md4.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_md4.py deleted file mode 100644 index bdc211f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/_md4.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -passlib.crypto._md4 -- fallback implementation of MD4 - -Helper implementing insecure and obsolete md4 algorithm. -used for NTHASH format, which is also insecure and broken, -since it's just md4(password). - -Implementated based on rfc at http://www.faqs.org/rfcs/rfc1320.html - -.. note:: - - This shouldn't be imported directly, it's merely used conditionally - by ``passlib.crypto.lookup_hash()`` when a native implementation can't be found. -""" - -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify -import struct -# site -from passlib.utils.compat import bascii_to_str, irange, PY3 -# local -__all__ = ["md4"] - -#============================================================================= -# utils -#============================================================================= -def F(x,y,z): - return (x&y) | ((~x) & z) - -def G(x,y,z): - return (x&y) | (x&z) | (y&z) - -##def H(x,y,z): -## return x ^ y ^ z - -MASK_32 = 2**32-1 - -#============================================================================= -# main class -#============================================================================= -class md4(object): - """pep-247 compatible implementation of MD4 hash algorithm - - .. attribute:: digest_size - - size of md4 digest in bytes (16 bytes) - - .. method:: update - - update digest by appending additional content - - .. method:: copy - - create clone of digest object, including current state - - .. method:: digest - - return bytes representing md4 digest of current content - - .. method:: hexdigest - - return hexadecimal version of digest - """ - # FIXME: make this follow hash object PEP better. - # FIXME: this isn't threadsafe - - name = "md4" - digest_size = digestsize = 16 - block_size = 64 - - _count = 0 # number of 64-byte blocks processed so far (not including _buf) - _state = None # list of [a,b,c,d] 32 bit ints used as internal register - _buf = None # data processed in 64 byte blocks, this holds leftover from last update - - def __init__(self, content=None): - self._count = 0 - self._state = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] - self._buf = b'' - if content: - self.update(content) - - # round 1 table - [abcd k s] - _round1 = [ - [0,1,2,3, 0,3], - [3,0,1,2, 1,7], - [2,3,0,1, 2,11], - [1,2,3,0, 3,19], - - [0,1,2,3, 4,3], - [3,0,1,2, 5,7], - [2,3,0,1, 6,11], - [1,2,3,0, 7,19], - - [0,1,2,3, 8,3], - [3,0,1,2, 9,7], - [2,3,0,1, 10,11], - [1,2,3,0, 11,19], - - [0,1,2,3, 12,3], - [3,0,1,2, 13,7], - [2,3,0,1, 14,11], - [1,2,3,0, 15,19], - ] - - # round 2 table - [abcd k s] - _round2 = [ - [0,1,2,3, 0,3], - [3,0,1,2, 4,5], - [2,3,0,1, 8,9], - [1,2,3,0, 12,13], - - [0,1,2,3, 1,3], - [3,0,1,2, 5,5], - [2,3,0,1, 9,9], - [1,2,3,0, 13,13], - - [0,1,2,3, 2,3], - [3,0,1,2, 6,5], - [2,3,0,1, 10,9], - [1,2,3,0, 14,13], - - [0,1,2,3, 3,3], - [3,0,1,2, 7,5], - [2,3,0,1, 11,9], - [1,2,3,0, 15,13], - ] - - # round 3 table - [abcd k s] - _round3 = [ - [0,1,2,3, 0,3], - [3,0,1,2, 8,9], - [2,3,0,1, 4,11], - [1,2,3,0, 12,15], - - [0,1,2,3, 2,3], - [3,0,1,2, 10,9], - [2,3,0,1, 6,11], - [1,2,3,0, 14,15], - - [0,1,2,3, 1,3], - [3,0,1,2, 9,9], - [2,3,0,1, 5,11], - [1,2,3,0, 13,15], - - [0,1,2,3, 3,3], - [3,0,1,2, 11,9], - [2,3,0,1, 7,11], - [1,2,3,0, 15,15], - ] - - def _process(self, block): - """process 64 byte block""" - # unpack block into 16 32-bit ints - X = struct.unpack("<16I", block) - - # clone state - orig = self._state - state = list(orig) - - # round 1 - F function - (x&y)|(~x & z) - for a,b,c,d,k,s in self._round1: - t = (state[a] + F(state[b],state[c],state[d]) + X[k]) & MASK_32 - state[a] = ((t<>(32-s)) - - # round 2 - G function - for a,b,c,d,k,s in self._round2: - t = (state[a] + G(state[b],state[c],state[d]) + X[k] + 0x5a827999) & MASK_32 - state[a] = ((t<>(32-s)) - - # round 3 - H function - x ^ y ^ z - for a,b,c,d,k,s in self._round3: - t = (state[a] + (state[b] ^ state[c] ^ state[d]) + X[k] + 0x6ed9eba1) & MASK_32 - state[a] = ((t<>(32-s)) - - # add back into original state - for i in irange(4): - orig[i] = (orig[i]+state[i]) & MASK_32 - - def update(self, content): - if not isinstance(content, bytes): - if PY3: - raise TypeError("expected bytes") - else: - # replicate behavior of hashlib under py2 - content = content.encode("ascii") - buf = self._buf - if buf: - content = buf + content - idx = 0 - end = len(content) - while True: - next = idx + 64 - if next <= end: - self._process(content[idx:next]) - self._count += 1 - idx = next - else: - self._buf = content[idx:] - return - - def copy(self): - other = md4() - other._count = self._count - other._state = list(self._state) - other._buf = self._buf - return other - - def digest(self): - # NOTE: backing up state so we can restore it after _process is called, - # in case object is updated again (this is only attr altered by this method) - orig = list(self._state) - - # final block: buf + 0x80, - # then 0x00 padding until congruent w/ 56 mod 64 bytes - # then last 8 bytes = msg length in bits - buf = self._buf - msglen = self._count*512 + len(buf)*8 - block = buf + b'\x80' + b'\x00' * ((119-len(buf)) % 64) + \ - struct.pack("<2I", msglen & MASK_32, (msglen>>32) & MASK_32) - if len(block) == 128: - self._process(block[:64]) - self._process(block[64:]) - else: - assert len(block) == 64 - self._process(block) - - # render digest & restore un-finalized state - out = struct.pack("<4I", *self._state) - self._state = orig - return out - - def hexdigest(self): - return bascii_to_str(hexlify(self.digest())) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/des.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/des.py deleted file mode 100644 index 3f87aef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/des.py +++ /dev/null @@ -1,848 +0,0 @@ -"""passlib.crypto.des -- DES block encryption routines - -History -======= -These routines (which have since been drastically modified for python) -are based on a Java implementation of the des-crypt algorithm, -found at ``_. - -The copyright & license for that source is as follows:: - - UnixCrypt.java 0.9 96/11/25 - Copyright (c) 1996 Aki Yoshida. All rights reserved. - Permission to use, copy, modify and distribute this software - for non-commercial or commercial purposes and without fee is - hereby granted provided that this copyright notice appears in - all copies. - - --- - - Unix crypt(3C) utility - @version 0.9, 11/25/96 - @author Aki Yoshida - - --- - - modified April 2001 - by Iris Van den Broeke, Daniel Deville - - --- - Unix Crypt. - Implements the one way cryptography used by Unix systems for - simple password protection. - @version $Id: UnixCrypt2.txt,v 1.1.1.1 2005/09/13 22:20:13 christos Exp $ - @author Greg Wilkins (gregw) - -The netbsd des-crypt implementation has some nice notes on how this all works - - http://fxr.googlebit.com/source/lib/libcrypt/crypt.c?v=NETBSD-CURRENT -""" - -# TODO: could use an accelerated C version of this module to speed up lmhash, -# des-crypt, and ext-des-crypt - -#============================================================================= -# imports -#============================================================================= -# core -import struct -# pkg -from passlib import exc -from passlib.utils.compat import join_byte_values, byte_elem_value, \ - irange, irange, int_types -# local -__all__ = [ - "expand_des_key", - "des_encrypt_block", -] - -#============================================================================= -# constants -#============================================================================= - -# masks/upper limits for various integer sizes -INT_24_MASK = 0xffffff -INT_56_MASK = 0xffffffffffffff -INT_64_MASK = 0xffffffffffffffff - -# mask to clear parity bits from 64-bit key -_KDATA_MASK = 0xfefefefefefefefe -_KPARITY_MASK = 0x0101010101010101 - -# mask used to setup key schedule -_KS_MASK = 0xfcfcfcfcffffffff - -#============================================================================= -# static DES tables -#============================================================================= - -# placeholders filled in by _load_tables() -PCXROT = IE3264 = SPE = CF6464 = None - -def _load_tables(): - """delay loading tables until they are actually needed""" - global PCXROT, IE3264, SPE, CF6464 - - #--------------------------------------------------------------- - # Initial key schedule permutation - # PC1ROT - bit reverse, then PC1, then Rotate, then PC2 - #--------------------------------------------------------------- - # NOTE: this was reordered from original table to make perm3264 logic simpler - PC1ROT=( - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000002000, 0x0000000000002000, - 0x0000000000000020, 0x0000000000000020, 0x0000000000002020, 0x0000000000002020, - 0x0000000000000400, 0x0000000000000400, 0x0000000000002400, 0x0000000000002400, - 0x0000000000000420, 0x0000000000000420, 0x0000000000002420, 0x0000000000002420, ), - ( 0x0000000000000000, 0x2000000000000000, 0x0000000400000000, 0x2000000400000000, - 0x0000800000000000, 0x2000800000000000, 0x0000800400000000, 0x2000800400000000, - 0x0008000000000000, 0x2008000000000000, 0x0008000400000000, 0x2008000400000000, - 0x0008800000000000, 0x2008800000000000, 0x0008800400000000, 0x2008800400000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000040, 0x0000000000000040, - 0x0000000020000000, 0x0000000020000000, 0x0000000020000040, 0x0000000020000040, - 0x0000000000200000, 0x0000000000200000, 0x0000000000200040, 0x0000000000200040, - 0x0000000020200000, 0x0000000020200000, 0x0000000020200040, 0x0000000020200040, ), - ( 0x0000000000000000, 0x0002000000000000, 0x0800000000000000, 0x0802000000000000, - 0x0100000000000000, 0x0102000000000000, 0x0900000000000000, 0x0902000000000000, - 0x4000000000000000, 0x4002000000000000, 0x4800000000000000, 0x4802000000000000, - 0x4100000000000000, 0x4102000000000000, 0x4900000000000000, 0x4902000000000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000040000, 0x0000000000040000, - 0x0000020000000000, 0x0000020000000000, 0x0000020000040000, 0x0000020000040000, - 0x0000000000000004, 0x0000000000000004, 0x0000000000040004, 0x0000000000040004, - 0x0000020000000004, 0x0000020000000004, 0x0000020000040004, 0x0000020000040004, ), - ( 0x0000000000000000, 0x0000400000000000, 0x0200000000000000, 0x0200400000000000, - 0x0080000000000000, 0x0080400000000000, 0x0280000000000000, 0x0280400000000000, - 0x0000008000000000, 0x0000408000000000, 0x0200008000000000, 0x0200408000000000, - 0x0080008000000000, 0x0080408000000000, 0x0280008000000000, 0x0280408000000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000010000000, 0x0000000010000000, - 0x0000000000001000, 0x0000000000001000, 0x0000000010001000, 0x0000000010001000, - 0x0000000040000000, 0x0000000040000000, 0x0000000050000000, 0x0000000050000000, - 0x0000000040001000, 0x0000000040001000, 0x0000000050001000, 0x0000000050001000, ), - ( 0x0000000000000000, 0x0000001000000000, 0x0000080000000000, 0x0000081000000000, - 0x1000000000000000, 0x1000001000000000, 0x1000080000000000, 0x1000081000000000, - 0x0004000000000000, 0x0004001000000000, 0x0004080000000000, 0x0004081000000000, - 0x1004000000000000, 0x1004001000000000, 0x1004080000000000, 0x1004081000000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000080, 0x0000000000000080, - 0x0000000000080000, 0x0000000000080000, 0x0000000000080080, 0x0000000000080080, - 0x0000000000800000, 0x0000000000800000, 0x0000000000800080, 0x0000000000800080, - 0x0000000000880000, 0x0000000000880000, 0x0000000000880080, 0x0000000000880080, ), - ( 0x0000000000000000, 0x0000000008000000, 0x0000002000000000, 0x0000002008000000, - 0x0000100000000000, 0x0000100008000000, 0x0000102000000000, 0x0000102008000000, - 0x0000200000000000, 0x0000200008000000, 0x0000202000000000, 0x0000202008000000, - 0x0000300000000000, 0x0000300008000000, 0x0000302000000000, 0x0000302008000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000400000, 0x0000000000400000, - 0x0000000004000000, 0x0000000004000000, 0x0000000004400000, 0x0000000004400000, - 0x0000000000000800, 0x0000000000000800, 0x0000000000400800, 0x0000000000400800, - 0x0000000004000800, 0x0000000004000800, 0x0000000004400800, 0x0000000004400800, ), - ( 0x0000000000000000, 0x0000000000008000, 0x0040000000000000, 0x0040000000008000, - 0x0000004000000000, 0x0000004000008000, 0x0040004000000000, 0x0040004000008000, - 0x8000000000000000, 0x8000000000008000, 0x8040000000000000, 0x8040000000008000, - 0x8000004000000000, 0x8000004000008000, 0x8040004000000000, 0x8040004000008000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000004000, 0x0000000000004000, - 0x0000000000000008, 0x0000000000000008, 0x0000000000004008, 0x0000000000004008, - 0x0000000000000010, 0x0000000000000010, 0x0000000000004010, 0x0000000000004010, - 0x0000000000000018, 0x0000000000000018, 0x0000000000004018, 0x0000000000004018, ), - ( 0x0000000000000000, 0x0000000200000000, 0x0001000000000000, 0x0001000200000000, - 0x0400000000000000, 0x0400000200000000, 0x0401000000000000, 0x0401000200000000, - 0x0020000000000000, 0x0020000200000000, 0x0021000000000000, 0x0021000200000000, - 0x0420000000000000, 0x0420000200000000, 0x0421000000000000, 0x0421000200000000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000010000000000, 0x0000010000000000, - 0x0000000100000000, 0x0000000100000000, 0x0000010100000000, 0x0000010100000000, - 0x0000000000100000, 0x0000000000100000, 0x0000010000100000, 0x0000010000100000, - 0x0000000100100000, 0x0000000100100000, 0x0000010100100000, 0x0000010100100000, ), - ( 0x0000000000000000, 0x0000000080000000, 0x0000040000000000, 0x0000040080000000, - 0x0010000000000000, 0x0010000080000000, 0x0010040000000000, 0x0010040080000000, - 0x0000000800000000, 0x0000000880000000, 0x0000040800000000, 0x0000040880000000, - 0x0010000800000000, 0x0010000880000000, 0x0010040800000000, 0x0010040880000000, ), - ) - #--------------------------------------------------------------- - # Subsequent key schedule rotation permutations - # PC2ROT - PC2 inverse, then Rotate, then PC2 - #--------------------------------------------------------------- - # NOTE: this was reordered from original table to make perm3264 logic simpler - PC2ROTA=( - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000200000, 0x0000000000200000, 0x0000000000200000, 0x0000000000200000, - 0x0000000004000000, 0x0000000004000000, 0x0000000004000000, 0x0000000004000000, - 0x0000000004200000, 0x0000000004200000, 0x0000000004200000, 0x0000000004200000, ), - ( 0x0000000000000000, 0x0000000000000800, 0x0000010000000000, 0x0000010000000800, - 0x0000000000002000, 0x0000000000002800, 0x0000010000002000, 0x0000010000002800, - 0x0000000010000000, 0x0000000010000800, 0x0000010010000000, 0x0000010010000800, - 0x0000000010002000, 0x0000000010002800, 0x0000010010002000, 0x0000010010002800, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000100000000, 0x0000000100000000, 0x0000000100000000, 0x0000000100000000, - 0x0000000000800000, 0x0000000000800000, 0x0000000000800000, 0x0000000000800000, - 0x0000000100800000, 0x0000000100800000, 0x0000000100800000, 0x0000000100800000, ), - ( 0x0000000000000000, 0x0000020000000000, 0x0000000080000000, 0x0000020080000000, - 0x0000000000400000, 0x0000020000400000, 0x0000000080400000, 0x0000020080400000, - 0x0000000008000000, 0x0000020008000000, 0x0000000088000000, 0x0000020088000000, - 0x0000000008400000, 0x0000020008400000, 0x0000000088400000, 0x0000020088400000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000040, 0x0000000000000040, 0x0000000000000040, 0x0000000000000040, - 0x0000000000001000, 0x0000000000001000, 0x0000000000001000, 0x0000000000001000, - 0x0000000000001040, 0x0000000000001040, 0x0000000000001040, 0x0000000000001040, ), - ( 0x0000000000000000, 0x0000000000000010, 0x0000000000000400, 0x0000000000000410, - 0x0000000000000080, 0x0000000000000090, 0x0000000000000480, 0x0000000000000490, - 0x0000000040000000, 0x0000000040000010, 0x0000000040000400, 0x0000000040000410, - 0x0000000040000080, 0x0000000040000090, 0x0000000040000480, 0x0000000040000490, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000080000, 0x0000000000080000, 0x0000000000080000, 0x0000000000080000, - 0x0000000000100000, 0x0000000000100000, 0x0000000000100000, 0x0000000000100000, - 0x0000000000180000, 0x0000000000180000, 0x0000000000180000, 0x0000000000180000, ), - ( 0x0000000000000000, 0x0000000000040000, 0x0000000000000020, 0x0000000000040020, - 0x0000000000000004, 0x0000000000040004, 0x0000000000000024, 0x0000000000040024, - 0x0000000200000000, 0x0000000200040000, 0x0000000200000020, 0x0000000200040020, - 0x0000000200000004, 0x0000000200040004, 0x0000000200000024, 0x0000000200040024, ), - ( 0x0000000000000000, 0x0000000000000008, 0x0000000000008000, 0x0000000000008008, - 0x0010000000000000, 0x0010000000000008, 0x0010000000008000, 0x0010000000008008, - 0x0020000000000000, 0x0020000000000008, 0x0020000000008000, 0x0020000000008008, - 0x0030000000000000, 0x0030000000000008, 0x0030000000008000, 0x0030000000008008, ), - ( 0x0000000000000000, 0x0000400000000000, 0x0000080000000000, 0x0000480000000000, - 0x0000100000000000, 0x0000500000000000, 0x0000180000000000, 0x0000580000000000, - 0x4000000000000000, 0x4000400000000000, 0x4000080000000000, 0x4000480000000000, - 0x4000100000000000, 0x4000500000000000, 0x4000180000000000, 0x4000580000000000, ), - ( 0x0000000000000000, 0x0000000000004000, 0x0000000020000000, 0x0000000020004000, - 0x0001000000000000, 0x0001000000004000, 0x0001000020000000, 0x0001000020004000, - 0x0200000000000000, 0x0200000000004000, 0x0200000020000000, 0x0200000020004000, - 0x0201000000000000, 0x0201000000004000, 0x0201000020000000, 0x0201000020004000, ), - ( 0x0000000000000000, 0x1000000000000000, 0x0004000000000000, 0x1004000000000000, - 0x0002000000000000, 0x1002000000000000, 0x0006000000000000, 0x1006000000000000, - 0x0000000800000000, 0x1000000800000000, 0x0004000800000000, 0x1004000800000000, - 0x0002000800000000, 0x1002000800000000, 0x0006000800000000, 0x1006000800000000, ), - ( 0x0000000000000000, 0x0040000000000000, 0x2000000000000000, 0x2040000000000000, - 0x0000008000000000, 0x0040008000000000, 0x2000008000000000, 0x2040008000000000, - 0x0000001000000000, 0x0040001000000000, 0x2000001000000000, 0x2040001000000000, - 0x0000009000000000, 0x0040009000000000, 0x2000009000000000, 0x2040009000000000, ), - ( 0x0000000000000000, 0x0400000000000000, 0x8000000000000000, 0x8400000000000000, - 0x0000002000000000, 0x0400002000000000, 0x8000002000000000, 0x8400002000000000, - 0x0100000000000000, 0x0500000000000000, 0x8100000000000000, 0x8500000000000000, - 0x0100002000000000, 0x0500002000000000, 0x8100002000000000, 0x8500002000000000, ), - ( 0x0000000000000000, 0x0000800000000000, 0x0800000000000000, 0x0800800000000000, - 0x0000004000000000, 0x0000804000000000, 0x0800004000000000, 0x0800804000000000, - 0x0000000400000000, 0x0000800400000000, 0x0800000400000000, 0x0800800400000000, - 0x0000004400000000, 0x0000804400000000, 0x0800004400000000, 0x0800804400000000, ), - ( 0x0000000000000000, 0x0080000000000000, 0x0000040000000000, 0x0080040000000000, - 0x0008000000000000, 0x0088000000000000, 0x0008040000000000, 0x0088040000000000, - 0x0000200000000000, 0x0080200000000000, 0x0000240000000000, 0x0080240000000000, - 0x0008200000000000, 0x0088200000000000, 0x0008240000000000, 0x0088240000000000, ), - ) - - # NOTE: this was reordered from original table to make perm3264 logic simpler - PC2ROTB=( - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000400, 0x0000000000000400, 0x0000000000000400, 0x0000000000000400, - 0x0000000000080000, 0x0000000000080000, 0x0000000000080000, 0x0000000000080000, - 0x0000000000080400, 0x0000000000080400, 0x0000000000080400, 0x0000000000080400, ), - ( 0x0000000000000000, 0x0000000000800000, 0x0000000000004000, 0x0000000000804000, - 0x0000000080000000, 0x0000000080800000, 0x0000000080004000, 0x0000000080804000, - 0x0000000000040000, 0x0000000000840000, 0x0000000000044000, 0x0000000000844000, - 0x0000000080040000, 0x0000000080840000, 0x0000000080044000, 0x0000000080844000, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000000008, 0x0000000000000008, 0x0000000000000008, 0x0000000000000008, - 0x0000000040000000, 0x0000000040000000, 0x0000000040000000, 0x0000000040000000, - 0x0000000040000008, 0x0000000040000008, 0x0000000040000008, 0x0000000040000008, ), - ( 0x0000000000000000, 0x0000000020000000, 0x0000000200000000, 0x0000000220000000, - 0x0000000000000080, 0x0000000020000080, 0x0000000200000080, 0x0000000220000080, - 0x0000000000100000, 0x0000000020100000, 0x0000000200100000, 0x0000000220100000, - 0x0000000000100080, 0x0000000020100080, 0x0000000200100080, 0x0000000220100080, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000002000, 0x0000000000002000, 0x0000000000002000, 0x0000000000002000, - 0x0000020000000000, 0x0000020000000000, 0x0000020000000000, 0x0000020000000000, - 0x0000020000002000, 0x0000020000002000, 0x0000020000002000, 0x0000020000002000, ), - ( 0x0000000000000000, 0x0000000000000800, 0x0000000100000000, 0x0000000100000800, - 0x0000000010000000, 0x0000000010000800, 0x0000000110000000, 0x0000000110000800, - 0x0000000000000004, 0x0000000000000804, 0x0000000100000004, 0x0000000100000804, - 0x0000000010000004, 0x0000000010000804, 0x0000000110000004, 0x0000000110000804, ), - ( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - 0x0000000000001000, 0x0000000000001000, 0x0000000000001000, 0x0000000000001000, - 0x0000000000000010, 0x0000000000000010, 0x0000000000000010, 0x0000000000000010, - 0x0000000000001010, 0x0000000000001010, 0x0000000000001010, 0x0000000000001010, ), - ( 0x0000000000000000, 0x0000000000000040, 0x0000010000000000, 0x0000010000000040, - 0x0000000000200000, 0x0000000000200040, 0x0000010000200000, 0x0000010000200040, - 0x0000000000008000, 0x0000000000008040, 0x0000010000008000, 0x0000010000008040, - 0x0000000000208000, 0x0000000000208040, 0x0000010000208000, 0x0000010000208040, ), - ( 0x0000000000000000, 0x0000000004000000, 0x0000000008000000, 0x000000000c000000, - 0x0400000000000000, 0x0400000004000000, 0x0400000008000000, 0x040000000c000000, - 0x8000000000000000, 0x8000000004000000, 0x8000000008000000, 0x800000000c000000, - 0x8400000000000000, 0x8400000004000000, 0x8400000008000000, 0x840000000c000000, ), - ( 0x0000000000000000, 0x0002000000000000, 0x0200000000000000, 0x0202000000000000, - 0x1000000000000000, 0x1002000000000000, 0x1200000000000000, 0x1202000000000000, - 0x0008000000000000, 0x000a000000000000, 0x0208000000000000, 0x020a000000000000, - 0x1008000000000000, 0x100a000000000000, 0x1208000000000000, 0x120a000000000000, ), - ( 0x0000000000000000, 0x0000000000400000, 0x0000000000000020, 0x0000000000400020, - 0x0040000000000000, 0x0040000000400000, 0x0040000000000020, 0x0040000000400020, - 0x0800000000000000, 0x0800000000400000, 0x0800000000000020, 0x0800000000400020, - 0x0840000000000000, 0x0840000000400000, 0x0840000000000020, 0x0840000000400020, ), - ( 0x0000000000000000, 0x0080000000000000, 0x0000008000000000, 0x0080008000000000, - 0x2000000000000000, 0x2080000000000000, 0x2000008000000000, 0x2080008000000000, - 0x0020000000000000, 0x00a0000000000000, 0x0020008000000000, 0x00a0008000000000, - 0x2020000000000000, 0x20a0000000000000, 0x2020008000000000, 0x20a0008000000000, ), - ( 0x0000000000000000, 0x0000002000000000, 0x0000040000000000, 0x0000042000000000, - 0x4000000000000000, 0x4000002000000000, 0x4000040000000000, 0x4000042000000000, - 0x0000400000000000, 0x0000402000000000, 0x0000440000000000, 0x0000442000000000, - 0x4000400000000000, 0x4000402000000000, 0x4000440000000000, 0x4000442000000000, ), - ( 0x0000000000000000, 0x0000004000000000, 0x0000200000000000, 0x0000204000000000, - 0x0000080000000000, 0x0000084000000000, 0x0000280000000000, 0x0000284000000000, - 0x0000800000000000, 0x0000804000000000, 0x0000a00000000000, 0x0000a04000000000, - 0x0000880000000000, 0x0000884000000000, 0x0000a80000000000, 0x0000a84000000000, ), - ( 0x0000000000000000, 0x0000000800000000, 0x0000000400000000, 0x0000000c00000000, - 0x0000100000000000, 0x0000100800000000, 0x0000100400000000, 0x0000100c00000000, - 0x0010000000000000, 0x0010000800000000, 0x0010000400000000, 0x0010000c00000000, - 0x0010100000000000, 0x0010100800000000, 0x0010100400000000, 0x0010100c00000000, ), - ( 0x0000000000000000, 0x0100000000000000, 0x0001000000000000, 0x0101000000000000, - 0x0000001000000000, 0x0100001000000000, 0x0001001000000000, 0x0101001000000000, - 0x0004000000000000, 0x0104000000000000, 0x0005000000000000, 0x0105000000000000, - 0x0004001000000000, 0x0104001000000000, 0x0005001000000000, 0x0105001000000000, ), - ) - #--------------------------------------------------------------- - # PCXROT - PC1ROT, PC2ROTA, PC2ROTB listed in order - # of the PC1 rotation schedule, as used by des_setkey - #--------------------------------------------------------------- - ##ROTATES = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1) - ##PCXROT = ( - ## PC1ROT, PC2ROTA, PC2ROTB, PC2ROTB, - ## PC2ROTB, PC2ROTB, PC2ROTB, PC2ROTB, - ## PC2ROTA, PC2ROTB, PC2ROTB, PC2ROTB, - ## PC2ROTB, PC2ROTB, PC2ROTB, PC2ROTA, - ## ) - - # NOTE: modified PCXROT to contain entrys broken into pairs, - # to help generate them in format best used by encoder. - PCXROT = ( - (PC1ROT, PC2ROTA), (PC2ROTB, PC2ROTB), - (PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTB), - (PC2ROTA, PC2ROTB), (PC2ROTB, PC2ROTB), - (PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTA), - ) - - #--------------------------------------------------------------- - # Bit reverse, intial permupation, expantion - # Initial permutation/expansion table - #--------------------------------------------------------------- - # NOTE: this was reordered from original table to make perm3264 logic simpler - IE3264=( - ( 0x0000000000000000, 0x0000000000800800, 0x0000000000008008, 0x0000000000808808, - 0x0000008008000000, 0x0000008008800800, 0x0000008008008008, 0x0000008008808808, - 0x0000000080080000, 0x0000000080880800, 0x0000000080088008, 0x0000000080888808, - 0x0000008088080000, 0x0000008088880800, 0x0000008088088008, 0x0000008088888808, ), - ( 0x0000000000000000, 0x0080080000000000, 0x0000800800000000, 0x0080880800000000, - 0x0800000000000080, 0x0880080000000080, 0x0800800800000080, 0x0880880800000080, - 0x8008000000000000, 0x8088080000000000, 0x8008800800000000, 0x8088880800000000, - 0x8808000000000080, 0x8888080000000080, 0x8808800800000080, 0x8888880800000080, ), - ( 0x0000000000000000, 0x0000000000001000, 0x0000000000000010, 0x0000000000001010, - 0x0000000010000000, 0x0000000010001000, 0x0000000010000010, 0x0000000010001010, - 0x0000000000100000, 0x0000000000101000, 0x0000000000100010, 0x0000000000101010, - 0x0000000010100000, 0x0000000010101000, 0x0000000010100010, 0x0000000010101010, ), - ( 0x0000000000000000, 0x0000100000000000, 0x0000001000000000, 0x0000101000000000, - 0x1000000000000000, 0x1000100000000000, 0x1000001000000000, 0x1000101000000000, - 0x0010000000000000, 0x0010100000000000, 0x0010001000000000, 0x0010101000000000, - 0x1010000000000000, 0x1010100000000000, 0x1010001000000000, 0x1010101000000000, ), - ( 0x0000000000000000, 0x0000000000002000, 0x0000000000000020, 0x0000000000002020, - 0x0000000020000000, 0x0000000020002000, 0x0000000020000020, 0x0000000020002020, - 0x0000000000200000, 0x0000000000202000, 0x0000000000200020, 0x0000000000202020, - 0x0000000020200000, 0x0000000020202000, 0x0000000020200020, 0x0000000020202020, ), - ( 0x0000000000000000, 0x0000200000000000, 0x0000002000000000, 0x0000202000000000, - 0x2000000000000000, 0x2000200000000000, 0x2000002000000000, 0x2000202000000000, - 0x0020000000000000, 0x0020200000000000, 0x0020002000000000, 0x0020202000000000, - 0x2020000000000000, 0x2020200000000000, 0x2020002000000000, 0x2020202000000000, ), - ( 0x0000000000000000, 0x0000000000004004, 0x0400000000000040, 0x0400000000004044, - 0x0000000040040000, 0x0000000040044004, 0x0400000040040040, 0x0400000040044044, - 0x0000000000400400, 0x0000000000404404, 0x0400000000400440, 0x0400000000404444, - 0x0000000040440400, 0x0000000040444404, 0x0400000040440440, 0x0400000040444444, ), - ( 0x0000000000000000, 0x0000400400000000, 0x0000004004000000, 0x0000404404000000, - 0x4004000000000000, 0x4004400400000000, 0x4004004004000000, 0x4004404404000000, - 0x0040040000000000, 0x0040440400000000, 0x0040044004000000, 0x0040444404000000, - 0x4044040000000000, 0x4044440400000000, 0x4044044004000000, 0x4044444404000000, ), - ) - - #--------------------------------------------------------------- - # Table that combines the S, P, and E operations. - #--------------------------------------------------------------- - SPE=( - ( 0x0080088008200000, 0x0000008008000000, 0x0000000000200020, 0x0080088008200020, - 0x0000000000200000, 0x0080088008000020, 0x0000008008000020, 0x0000000000200020, - 0x0080088008000020, 0x0080088008200000, 0x0000008008200000, 0x0080080000000020, - 0x0080080000200020, 0x0000000000200000, 0x0000000000000000, 0x0000008008000020, - 0x0000008008000000, 0x0000000000000020, 0x0080080000200000, 0x0080088008000000, - 0x0080088008200020, 0x0000008008200000, 0x0080080000000020, 0x0080080000200000, - 0x0000000000000020, 0x0080080000000000, 0x0080088008000000, 0x0000008008200020, - 0x0080080000000000, 0x0080080000200020, 0x0000008008200020, 0x0000000000000000, - 0x0000000000000000, 0x0080088008200020, 0x0080080000200000, 0x0000008008000020, - 0x0080088008200000, 0x0000008008000000, 0x0080080000000020, 0x0080080000200000, - 0x0000008008200020, 0x0080080000000000, 0x0080088008000000, 0x0000000000200020, - 0x0080088008000020, 0x0000000000000020, 0x0000000000200020, 0x0000008008200000, - 0x0080088008200020, 0x0080088008000000, 0x0000008008200000, 0x0080080000200020, - 0x0000000000200000, 0x0080080000000020, 0x0000008008000020, 0x0000000000000000, - 0x0000008008000000, 0x0000000000200000, 0x0080080000200020, 0x0080088008200000, - 0x0000000000000020, 0x0000008008200020, 0x0080080000000000, 0x0080088008000020, ), - ( 0x1000800810004004, 0x0000000000000000, 0x0000800810000000, 0x0000000010004004, - 0x1000000000004004, 0x1000800800000000, 0x0000800800004004, 0x0000800810000000, - 0x0000800800000000, 0x1000000010004004, 0x1000000000000000, 0x0000800800004004, - 0x1000000010000000, 0x0000800810004004, 0x0000000010004004, 0x1000000000000000, - 0x0000000010000000, 0x1000800800004004, 0x1000000010004004, 0x0000800800000000, - 0x1000800810000000, 0x0000000000004004, 0x0000000000000000, 0x1000000010000000, - 0x1000800800004004, 0x1000800810000000, 0x0000800810004004, 0x1000000000004004, - 0x0000000000004004, 0x0000000010000000, 0x1000800800000000, 0x1000800810004004, - 0x1000000010000000, 0x0000800810004004, 0x0000800800004004, 0x1000800810000000, - 0x1000800810004004, 0x1000000010000000, 0x1000000000004004, 0x0000000000000000, - 0x0000000000004004, 0x1000800800000000, 0x0000000010000000, 0x1000000010004004, - 0x0000800800000000, 0x0000000000004004, 0x1000800810000000, 0x1000800800004004, - 0x0000800810004004, 0x0000800800000000, 0x0000000000000000, 0x1000000000004004, - 0x1000000000000000, 0x1000800810004004, 0x0000800810000000, 0x0000000010004004, - 0x1000000010004004, 0x0000000010000000, 0x1000800800000000, 0x0000800800004004, - 0x1000800800004004, 0x1000000000000000, 0x0000000010004004, 0x0000800810000000, ), - ( 0x0000000000400410, 0x0010004004400400, 0x0010000000000000, 0x0010000000400410, - 0x0000004004000010, 0x0000000000400400, 0x0010000000400410, 0x0010004004000000, - 0x0010000000400400, 0x0000004004000000, 0x0000004004400400, 0x0000000000000010, - 0x0010004004400410, 0x0010000000000010, 0x0000000000000010, 0x0000004004400410, - 0x0000000000000000, 0x0000004004000010, 0x0010004004400400, 0x0010000000000000, - 0x0010000000000010, 0x0010004004400410, 0x0000004004000000, 0x0000000000400410, - 0x0000004004400410, 0x0010000000400400, 0x0010004004000010, 0x0000004004400400, - 0x0010004004000000, 0x0000000000000000, 0x0000000000400400, 0x0010004004000010, - 0x0010004004400400, 0x0010000000000000, 0x0000000000000010, 0x0000004004000000, - 0x0010000000000010, 0x0000004004000010, 0x0000004004400400, 0x0010000000400410, - 0x0000000000000000, 0x0010004004400400, 0x0010004004000000, 0x0000004004400410, - 0x0000004004000010, 0x0000000000400400, 0x0010004004400410, 0x0000000000000010, - 0x0010004004000010, 0x0000000000400410, 0x0000000000400400, 0x0010004004400410, - 0x0000004004000000, 0x0010000000400400, 0x0010000000400410, 0x0010004004000000, - 0x0010000000400400, 0x0000000000000000, 0x0000004004400410, 0x0010000000000010, - 0x0000000000400410, 0x0010004004000010, 0x0010000000000000, 0x0000004004400400, ), - ( 0x0800100040040080, 0x0000100000001000, 0x0800000000000080, 0x0800100040041080, - 0x0000000000000000, 0x0000000040041000, 0x0800100000001080, 0x0800000040040080, - 0x0000100040041000, 0x0800000000001080, 0x0000000000001000, 0x0800100000000080, - 0x0800000000001080, 0x0800100040040080, 0x0000000040040000, 0x0000000000001000, - 0x0800000040041080, 0x0000100040040000, 0x0000100000000000, 0x0800000000000080, - 0x0000100040040000, 0x0800100000001080, 0x0000000040041000, 0x0000100000000000, - 0x0800100000000080, 0x0000000000000000, 0x0800000040040080, 0x0000100040041000, - 0x0000100000001000, 0x0800000040041080, 0x0800100040041080, 0x0000000040040000, - 0x0800000040041080, 0x0800100000000080, 0x0000000040040000, 0x0800000000001080, - 0x0000100040040000, 0x0000100000001000, 0x0800000000000080, 0x0000000040041000, - 0x0800100000001080, 0x0000000000000000, 0x0000100000000000, 0x0800000040040080, - 0x0000000000000000, 0x0800000040041080, 0x0000100040041000, 0x0000100000000000, - 0x0000000000001000, 0x0800100040041080, 0x0800100040040080, 0x0000000040040000, - 0x0800100040041080, 0x0800000000000080, 0x0000100000001000, 0x0800100040040080, - 0x0800000040040080, 0x0000100040040000, 0x0000000040041000, 0x0800100000001080, - 0x0800100000000080, 0x0000000000001000, 0x0800000000001080, 0x0000100040041000, ), - ( 0x0000000000800800, 0x0000001000000000, 0x0040040000000000, 0x2040041000800800, - 0x2000001000800800, 0x0040040000800800, 0x2040041000000000, 0x0000001000800800, - 0x0000001000000000, 0x2000000000000000, 0x2000000000800800, 0x0040041000000000, - 0x2040040000800800, 0x2000001000800800, 0x0040041000800800, 0x0000000000000000, - 0x0040041000000000, 0x0000000000800800, 0x2000001000000000, 0x2040040000000000, - 0x0040040000800800, 0x2040041000000000, 0x0000000000000000, 0x2000000000800800, - 0x2000000000000000, 0x2040040000800800, 0x2040041000800800, 0x2000001000000000, - 0x0000001000800800, 0x0040040000000000, 0x2040040000000000, 0x0040041000800800, - 0x0040041000800800, 0x2040040000800800, 0x2000001000000000, 0x0000001000800800, - 0x0000001000000000, 0x2000000000000000, 0x2000000000800800, 0x0040040000800800, - 0x0000000000800800, 0x0040041000000000, 0x2040041000800800, 0x0000000000000000, - 0x2040041000000000, 0x0000000000800800, 0x0040040000000000, 0x2000001000000000, - 0x2040040000800800, 0x0040040000000000, 0x0000000000000000, 0x2040041000800800, - 0x2000001000800800, 0x0040041000800800, 0x2040040000000000, 0x0000001000000000, - 0x0040041000000000, 0x2000001000800800, 0x0040040000800800, 0x2040040000000000, - 0x2000000000000000, 0x2040041000000000, 0x0000001000800800, 0x2000000000800800, ), - ( 0x4004000000008008, 0x4004000020000000, 0x0000000000000000, 0x0000200020008008, - 0x4004000020000000, 0x0000200000000000, 0x4004200000008008, 0x0000000020000000, - 0x4004200000000000, 0x4004200020008008, 0x0000200020000000, 0x0000000000008008, - 0x0000200000008008, 0x4004000000008008, 0x0000000020008008, 0x4004200020000000, - 0x0000000020000000, 0x4004200000008008, 0x4004000020008008, 0x0000000000000000, - 0x0000200000000000, 0x4004000000000000, 0x0000200020008008, 0x4004000020008008, - 0x4004200020008008, 0x0000000020008008, 0x0000000000008008, 0x4004200000000000, - 0x4004000000000000, 0x0000200020000000, 0x4004200020000000, 0x0000200000008008, - 0x4004200000000000, 0x0000000000008008, 0x0000200000008008, 0x4004200020000000, - 0x0000200020008008, 0x4004000020000000, 0x0000000000000000, 0x0000200000008008, - 0x0000000000008008, 0x0000200000000000, 0x4004000020008008, 0x0000000020000000, - 0x4004000020000000, 0x4004200020008008, 0x0000200020000000, 0x4004000000000000, - 0x4004200020008008, 0x0000200020000000, 0x0000000020000000, 0x4004200000008008, - 0x4004000000008008, 0x0000000020008008, 0x4004200020000000, 0x0000000000000000, - 0x0000200000000000, 0x4004000000008008, 0x4004200000008008, 0x0000200020008008, - 0x0000000020008008, 0x4004200000000000, 0x4004000000000000, 0x4004000020008008, ), - ( 0x0000400400000000, 0x0020000000000000, 0x0020000000100000, 0x0400000000100040, - 0x0420400400100040, 0x0400400400000040, 0x0020400400000000, 0x0000000000000000, - 0x0000000000100000, 0x0420000000100040, 0x0420000000000040, 0x0000400400100000, - 0x0400000000000040, 0x0020400400100000, 0x0000400400100000, 0x0420000000000040, - 0x0420000000100040, 0x0000400400000000, 0x0400400400000040, 0x0420400400100040, - 0x0000000000000000, 0x0020000000100000, 0x0400000000100040, 0x0020400400000000, - 0x0400400400100040, 0x0420400400000040, 0x0020400400100000, 0x0400000000000040, - 0x0420400400000040, 0x0400400400100040, 0x0020000000000000, 0x0000000000100000, - 0x0420400400000040, 0x0000400400100000, 0x0400400400100040, 0x0420000000000040, - 0x0000400400000000, 0x0020000000000000, 0x0000000000100000, 0x0400400400100040, - 0x0420000000100040, 0x0420400400000040, 0x0020400400000000, 0x0000000000000000, - 0x0020000000000000, 0x0400000000100040, 0x0400000000000040, 0x0020000000100000, - 0x0000000000000000, 0x0420000000100040, 0x0020000000100000, 0x0020400400000000, - 0x0420000000000040, 0x0000400400000000, 0x0420400400100040, 0x0000000000100000, - 0x0020400400100000, 0x0400000000000040, 0x0400400400000040, 0x0420400400100040, - 0x0400000000100040, 0x0020400400100000, 0x0000400400100000, 0x0400400400000040, ), - ( 0x8008000080082000, 0x0000002080082000, 0x8008002000000000, 0x0000000000000000, - 0x0000002000002000, 0x8008000080080000, 0x0000000080082000, 0x8008002080082000, - 0x8008000000000000, 0x0000000000002000, 0x0000002080080000, 0x8008002000000000, - 0x8008002080080000, 0x8008002000002000, 0x8008000000002000, 0x0000000080082000, - 0x0000002000000000, 0x8008002080080000, 0x8008000080080000, 0x0000002000002000, - 0x8008002080082000, 0x8008000000002000, 0x0000000000000000, 0x0000002080080000, - 0x0000000000002000, 0x0000000080080000, 0x8008002000002000, 0x8008000080082000, - 0x0000000080080000, 0x0000002000000000, 0x0000002080082000, 0x8008000000000000, - 0x0000000080080000, 0x0000002000000000, 0x8008000000002000, 0x8008002080082000, - 0x8008002000000000, 0x0000000000002000, 0x0000000000000000, 0x0000002080080000, - 0x8008000080082000, 0x8008002000002000, 0x0000002000002000, 0x8008000080080000, - 0x0000002080082000, 0x8008000000000000, 0x8008000080080000, 0x0000002000002000, - 0x8008002080082000, 0x0000000080080000, 0x0000000080082000, 0x8008000000002000, - 0x0000002080080000, 0x8008002000000000, 0x8008002000002000, 0x0000000080082000, - 0x8008000000000000, 0x0000002080082000, 0x8008002080080000, 0x0000000000000000, - 0x0000000000002000, 0x8008000080082000, 0x0000002000000000, 0x8008002080080000, ), - ) - - #--------------------------------------------------------------- - # compressed/interleaved => final permutation table - # Compression, final permutation, bit reverse - #--------------------------------------------------------------- - # NOTE: this was reordered from original table to make perm6464 logic simpler - CF6464=( - ( 0x0000000000000000, 0x0000002000000000, 0x0000200000000000, 0x0000202000000000, - 0x0020000000000000, 0x0020002000000000, 0x0020200000000000, 0x0020202000000000, - 0x2000000000000000, 0x2000002000000000, 0x2000200000000000, 0x2000202000000000, - 0x2020000000000000, 0x2020002000000000, 0x2020200000000000, 0x2020202000000000, ), - ( 0x0000000000000000, 0x0000000200000000, 0x0000020000000000, 0x0000020200000000, - 0x0002000000000000, 0x0002000200000000, 0x0002020000000000, 0x0002020200000000, - 0x0200000000000000, 0x0200000200000000, 0x0200020000000000, 0x0200020200000000, - 0x0202000000000000, 0x0202000200000000, 0x0202020000000000, 0x0202020200000000, ), - ( 0x0000000000000000, 0x0000000000000020, 0x0000000000002000, 0x0000000000002020, - 0x0000000000200000, 0x0000000000200020, 0x0000000000202000, 0x0000000000202020, - 0x0000000020000000, 0x0000000020000020, 0x0000000020002000, 0x0000000020002020, - 0x0000000020200000, 0x0000000020200020, 0x0000000020202000, 0x0000000020202020, ), - ( 0x0000000000000000, 0x0000000000000002, 0x0000000000000200, 0x0000000000000202, - 0x0000000000020000, 0x0000000000020002, 0x0000000000020200, 0x0000000000020202, - 0x0000000002000000, 0x0000000002000002, 0x0000000002000200, 0x0000000002000202, - 0x0000000002020000, 0x0000000002020002, 0x0000000002020200, 0x0000000002020202, ), - ( 0x0000000000000000, 0x0000008000000000, 0x0000800000000000, 0x0000808000000000, - 0x0080000000000000, 0x0080008000000000, 0x0080800000000000, 0x0080808000000000, - 0x8000000000000000, 0x8000008000000000, 0x8000800000000000, 0x8000808000000000, - 0x8080000000000000, 0x8080008000000000, 0x8080800000000000, 0x8080808000000000, ), - ( 0x0000000000000000, 0x0000000800000000, 0x0000080000000000, 0x0000080800000000, - 0x0008000000000000, 0x0008000800000000, 0x0008080000000000, 0x0008080800000000, - 0x0800000000000000, 0x0800000800000000, 0x0800080000000000, 0x0800080800000000, - 0x0808000000000000, 0x0808000800000000, 0x0808080000000000, 0x0808080800000000, ), - ( 0x0000000000000000, 0x0000000000000080, 0x0000000000008000, 0x0000000000008080, - 0x0000000000800000, 0x0000000000800080, 0x0000000000808000, 0x0000000000808080, - 0x0000000080000000, 0x0000000080000080, 0x0000000080008000, 0x0000000080008080, - 0x0000000080800000, 0x0000000080800080, 0x0000000080808000, 0x0000000080808080, ), - ( 0x0000000000000000, 0x0000000000000008, 0x0000000000000800, 0x0000000000000808, - 0x0000000000080000, 0x0000000000080008, 0x0000000000080800, 0x0000000000080808, - 0x0000000008000000, 0x0000000008000008, 0x0000000008000800, 0x0000000008000808, - 0x0000000008080000, 0x0000000008080008, 0x0000000008080800, 0x0000000008080808, ), - ( 0x0000000000000000, 0x0000001000000000, 0x0000100000000000, 0x0000101000000000, - 0x0010000000000000, 0x0010001000000000, 0x0010100000000000, 0x0010101000000000, - 0x1000000000000000, 0x1000001000000000, 0x1000100000000000, 0x1000101000000000, - 0x1010000000000000, 0x1010001000000000, 0x1010100000000000, 0x1010101000000000, ), - ( 0x0000000000000000, 0x0000000100000000, 0x0000010000000000, 0x0000010100000000, - 0x0001000000000000, 0x0001000100000000, 0x0001010000000000, 0x0001010100000000, - 0x0100000000000000, 0x0100000100000000, 0x0100010000000000, 0x0100010100000000, - 0x0101000000000000, 0x0101000100000000, 0x0101010000000000, 0x0101010100000000, ), - ( 0x0000000000000000, 0x0000000000000010, 0x0000000000001000, 0x0000000000001010, - 0x0000000000100000, 0x0000000000100010, 0x0000000000101000, 0x0000000000101010, - 0x0000000010000000, 0x0000000010000010, 0x0000000010001000, 0x0000000010001010, - 0x0000000010100000, 0x0000000010100010, 0x0000000010101000, 0x0000000010101010, ), - ( 0x0000000000000000, 0x0000000000000001, 0x0000000000000100, 0x0000000000000101, - 0x0000000000010000, 0x0000000000010001, 0x0000000000010100, 0x0000000000010101, - 0x0000000001000000, 0x0000000001000001, 0x0000000001000100, 0x0000000001000101, - 0x0000000001010000, 0x0000000001010001, 0x0000000001010100, 0x0000000001010101, ), - ( 0x0000000000000000, 0x0000004000000000, 0x0000400000000000, 0x0000404000000000, - 0x0040000000000000, 0x0040004000000000, 0x0040400000000000, 0x0040404000000000, - 0x4000000000000000, 0x4000004000000000, 0x4000400000000000, 0x4000404000000000, - 0x4040000000000000, 0x4040004000000000, 0x4040400000000000, 0x4040404000000000, ), - ( 0x0000000000000000, 0x0000000400000000, 0x0000040000000000, 0x0000040400000000, - 0x0004000000000000, 0x0004000400000000, 0x0004040000000000, 0x0004040400000000, - 0x0400000000000000, 0x0400000400000000, 0x0400040000000000, 0x0400040400000000, - 0x0404000000000000, 0x0404000400000000, 0x0404040000000000, 0x0404040400000000, ), - ( 0x0000000000000000, 0x0000000000000040, 0x0000000000004000, 0x0000000000004040, - 0x0000000000400000, 0x0000000000400040, 0x0000000000404000, 0x0000000000404040, - 0x0000000040000000, 0x0000000040000040, 0x0000000040004000, 0x0000000040004040, - 0x0000000040400000, 0x0000000040400040, 0x0000000040404000, 0x0000000040404040, ), - ( 0x0000000000000000, 0x0000000000000004, 0x0000000000000400, 0x0000000000000404, - 0x0000000000040000, 0x0000000000040004, 0x0000000000040400, 0x0000000000040404, - 0x0000000004000000, 0x0000000004000004, 0x0000000004000400, 0x0000000004000404, - 0x0000000004040000, 0x0000000004040004, 0x0000000004040400, 0x0000000004040404, ), - ) - #=================================================================== - # eof _load_tables() - #=================================================================== - -#============================================================================= -# support -#============================================================================= - -def _permute(c, p): - """Returns the permutation of the given 32-bit or 64-bit code with - the specified permutation table.""" - # NOTE: only difference between 32 & 64 bit permutations - # is that len(p)==8 for 32 bit, and len(p)==16 for 64 bit. - out = 0 - for r in p: - out |= r[c&0xf] - c >>= 4 - return out - -#============================================================================= -# packing & unpacking -#============================================================================= -# FIXME: more properly named _uint8_struct... -_uint64_struct = struct.Struct(">Q") - -def _pack64(value): - return _uint64_struct.pack(value) - -def _unpack64(value): - return _uint64_struct.unpack(value)[0] - -def _pack56(value): - return _uint64_struct.pack(value)[1:] - -def _unpack56(value): - return _uint64_struct.unpack(b'\x00' + value)[0] - -#============================================================================= -# 56->64 key manipulation -#============================================================================= - -##def expand_7bit(value): -## "expand 7-bit integer => 7-bits + 1 odd-parity bit" -## # parity calc adapted from 32-bit even parity alg found at -## # http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel -## assert 0 <= value < 0x80, "value out of range" -## return (value<<1) | (0x9669 >> ((value ^ (value >> 4)) & 0xf)) & 1 - -_EXPAND_ITER = irange(49,-7,-7) - -def expand_des_key(key): - """convert DES from 7 bytes to 8 bytes (by inserting empty parity bits)""" - if isinstance(key, bytes): - if len(key) != 7: - raise ValueError("key must be 7 bytes in size") - elif isinstance(key, int_types): - if key < 0 or key > INT_56_MASK: - raise ValueError("key must be 56-bit non-negative integer") - return _unpack64(expand_des_key(_pack56(key))) - else: - raise exc.ExpectedTypeError(key, "bytes or int", "key") - key = _unpack56(key) - # NOTE: the following would insert correctly-valued parity bits in each key, - # but the parity bit would just be ignored in des_encrypt_block(), - # so not bothering to use it. - # XXX: could make parity-restoring optionally available via flag - ##return join_byte_values(expand_7bit((key >> shift) & 0x7f) - ## for shift in _EXPAND_ITER) - return join_byte_values(((key>>shift) & 0x7f)<<1 for shift in _EXPAND_ITER) - -def shrink_des_key(key): - """convert DES key from 8 bytes to 7 bytes (by discarding the parity bits)""" - if isinstance(key, bytes): - if len(key) != 8: - raise ValueError("key must be 8 bytes in size") - return _pack56(shrink_des_key(_unpack64(key))) - elif isinstance(key, int_types): - if key < 0 or key > INT_64_MASK: - raise ValueError("key must be 64-bit non-negative integer") - else: - raise exc.ExpectedTypeError(key, "bytes or int", "key") - key >>= 1 - result = 0 - offset = 0 - while offset < 56: - result |= (key & 0x7f)<>= 8 - offset += 7 - assert not (result & ~INT_64_MASK) - return result - -#============================================================================= -# des encryption -#============================================================================= -def des_encrypt_block(key, input, salt=0, rounds=1): - """encrypt single block of data using DES, operates on 8-byte strings. - - :arg key: - DES key as 7 byte string, or 8 byte string with parity bits - (parity bit values are ignored). - - :arg input: - plaintext block to encrypt, as 8 byte string. - - :arg salt: - Optional 24-bit integer used to mutate the base DES algorithm in a - manner specific to :class:`~passlib.hash.des_crypt` and its variants. - The default value ``0`` provides the normal (unsalted) DES behavior. - The salt functions as follows: - if the ``i``'th bit of ``salt`` is set, - bits ``i`` and ``i+24`` are swapped in the DES E-box output. - - :arg rounds: - Optional number of rounds of to apply the DES key schedule. - the default (``rounds=1``) provides the normal DES behavior, - but :class:`~passlib.hash.des_crypt` and its variants use - alternate rounds values. - - :raises TypeError: if any of the provided args are of the wrong type. - :raises ValueError: - if any of the input blocks are the wrong size, - or the salt/rounds values are out of range. - - :returns: - resulting 8-byte ciphertext block. - """ - # validate & unpack key - if isinstance(key, bytes): - if len(key) == 7: - key = expand_des_key(key) - elif len(key) != 8: - raise ValueError("key must be 7 or 8 bytes") - key = _unpack64(key) - else: - raise exc.ExpectedTypeError(key, "bytes", "key") - - # validate & unpack input - if isinstance(input, bytes): - if len(input) != 8: - raise ValueError("input block must be 8 bytes") - input = _unpack64(input) - else: - raise exc.ExpectedTypeError(input, "bytes", "input") - - # hand things off to other func - result = des_encrypt_int_block(key, input, salt, rounds) - - # repack result - return _pack64(result) - -def des_encrypt_int_block(key, input, salt=0, rounds=1): - """encrypt single block of data using DES, operates on 64-bit integers. - - this function is essentially the same as :func:`des_encrypt_block`, - except that it operates on integers, and will NOT automatically - expand 56-bit keys if provided (since there's no way to detect them). - - :arg key: - DES key as 64-bit integer (the parity bits are ignored). - - :arg input: - input block as 64-bit integer - - :arg salt: - optional 24-bit integer used to mutate the base DES algorithm. - defaults to ``0`` (no mutation applied). - - :arg rounds: - optional number of rounds of to apply the DES key schedule. - defaults to ``1``. - - :raises TypeError: if any of the provided args are of the wrong type. - :raises ValueError: - if any of the input blocks are the wrong size, - or the salt/rounds values are out of range. - - :returns: - resulting ciphertext as 64-bit integer. - """ - #--------------------------------------------------------------- - # input validation - #--------------------------------------------------------------- - - # validate salt, rounds - if rounds < 1: - raise ValueError("rounds must be positive integer") - if salt < 0 or salt > INT_24_MASK: - raise ValueError("salt must be 24-bit non-negative integer") - - # validate & unpack key - if not isinstance(key, int_types): - raise exc.ExpectedTypeError(key, "int", "key") - elif key < 0 or key > INT_64_MASK: - raise ValueError("key must be 64-bit non-negative integer") - - # validate & unpack input - if not isinstance(input, int_types): - raise exc.ExpectedTypeError(input, "int", "input") - elif input < 0 or input > INT_64_MASK: - raise ValueError("input must be 64-bit non-negative integer") - - #--------------------------------------------------------------- - # DES setup - #--------------------------------------------------------------- - # load tables if not already done - global SPE, PCXROT, IE3264, CF6464 - if PCXROT is None: - _load_tables() - - # load SPE into local vars to speed things up and remove an array access call - SPE0, SPE1, SPE2, SPE3, SPE4, SPE5, SPE6, SPE7 = SPE - - # NOTE: parity bits are ignored completely - # (UTs do fuzz testing to ensure this) - - # generate key schedule - # NOTE: generation was modified to output two elements at a time, - # so that per-round loop could do two passes at once. - def _iter_key_schedule(ks_odd): - """given 64-bit key, iterates over the 8 (even,odd) key schedule pairs""" - for p_even, p_odd in PCXROT: - ks_even = _permute(ks_odd, p_even) - ks_odd = _permute(ks_even, p_odd) - yield ks_even & _KS_MASK, ks_odd & _KS_MASK - ks_list = list(_iter_key_schedule(key)) - - # expand 24 bit salt -> 32 bit per des_crypt & bsdi_crypt - salt = ( - ((salt & 0x00003f) << 26) | - ((salt & 0x000fc0) << 12) | - ((salt & 0x03f000) >> 2) | - ((salt & 0xfc0000) >> 16) - ) - - # init L & R - if input == 0: - L = R = 0 - else: - L = ((input >> 31) & 0xaaaaaaaa) | (input & 0x55555555) - L = _permute(L, IE3264) - - R = ((input >> 32) & 0xaaaaaaaa) | ((input >> 1) & 0x55555555) - R = _permute(R, IE3264) - - #--------------------------------------------------------------- - # main DES loop - run for specified number of rounds - #--------------------------------------------------------------- - while rounds: - rounds -= 1 - - # run over each part of the schedule, 2 parts at a time - for ks_even, ks_odd in ks_list: - k = ((R>>32) ^ R) & salt # use the salt to flip specific bits - B = (k<<32) ^ k ^ R ^ ks_even - - L ^= (SPE0[(B>>58)&0x3f] ^ SPE1[(B>>50)&0x3f] ^ - SPE2[(B>>42)&0x3f] ^ SPE3[(B>>34)&0x3f] ^ - SPE4[(B>>26)&0x3f] ^ SPE5[(B>>18)&0x3f] ^ - SPE6[(B>>10)&0x3f] ^ SPE7[(B>>2)&0x3f]) - - k = ((L>>32) ^ L) & salt # use the salt to flip specific bits - B = (k<<32) ^ k ^ L ^ ks_odd - - R ^= (SPE0[(B>>58)&0x3f] ^ SPE1[(B>>50)&0x3f] ^ - SPE2[(B>>42)&0x3f] ^ SPE3[(B>>34)&0x3f] ^ - SPE4[(B>>26)&0x3f] ^ SPE5[(B>>18)&0x3f] ^ - SPE6[(B>>10)&0x3f] ^ SPE7[(B>>2)&0x3f]) - - # swap L and R - L, R = R, L - - #--------------------------------------------------------------- - # return final result - #--------------------------------------------------------------- - C = ( - ((L>>3) & 0x0f0f0f0f00000000) - | - ((L<<33) & 0xf0f0f0f000000000) - | - ((R>>35) & 0x000000000f0f0f0f) - | - ((R<<1) & 0x00000000f0f0f0f0) - ) - return _permute(C, CF6464) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/digest.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/digest.py deleted file mode 100644 index 90e0cad..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/digest.py +++ /dev/null @@ -1,1057 +0,0 @@ -"""passlib.crypto.digest -- crytographic helpers used by the password hashes in passlib - -.. versionadded:: 1.7 -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import division -# core -import hashlib -import logging; log = logging.getLogger(__name__) -try: - # new in py3.4 - from hashlib import pbkdf2_hmac as _stdlib_pbkdf2_hmac - if _stdlib_pbkdf2_hmac.__module__ == "hashlib": - # builtin pure-python backends are slightly faster than stdlib's pure python fallback, - # so only using stdlib's version if it's backed by openssl's pbkdf2_hmac() - log.debug("ignoring pure-python hashlib.pbkdf2_hmac()") - _stdlib_pbkdf2_hmac = None -except ImportError: - _stdlib_pbkdf2_hmac = None -import re -import os -from struct import Struct -from warnings import warn -# site -try: - # https://pypi.python.org/pypi/fastpbkdf2/ - from fastpbkdf2 import pbkdf2_hmac as _fast_pbkdf2_hmac -except ImportError: - _fast_pbkdf2_hmac = None -# pkg -from passlib import exc -from passlib.utils import join_bytes, to_native_str, join_byte_values, to_bytes, \ - SequenceMixin, as_bool -from passlib.utils.compat import irange, int_types, unicode_or_bytes_types, PY3, error_from -from passlib.utils.decor import memoized_property -# local -__all__ = [ - # hash utils - "lookup_hash", - "HashInfo", - "norm_hash_name", - - # hmac utils - "compile_hmac", - - # kdfs - "pbkdf1", - "pbkdf2_hmac", -] - -#============================================================================= -# generic constants -#============================================================================= - -#: max 32-bit value -MAX_UINT32 = (1 << 32) - 1 - -#: max 64-bit value -MAX_UINT64 = (1 << 64) - 1 - -#============================================================================= -# hash utils -#============================================================================= - -#: list of known hash names, used by lookup_hash()'s _norm_hash_name() helper -_known_hash_names = [ - # format: (hashlib/ssl name, iana name or standin, other known aliases ...) - - #---------------------------------------------------- - # hashes with official IANA-assigned names - # (as of 2012-03 - http://www.iana.org/assignments/hash-function-text-names) - #---------------------------------------------------- - ("md2", "md2"), # NOTE: openssl dropped md2 support in v1.0.0 - ("md5", "md5"), - ("sha1", "sha-1"), - ("sha224", "sha-224", "sha2-224"), - ("sha256", "sha-256", "sha2-256"), - ("sha384", "sha-384", "sha2-384"), - ("sha512", "sha-512", "sha2-512"), - - # TODO: add sha3 to this table. - - #---------------------------------------------------- - # hashlib/ssl-supported hashes without official IANA names, - # (hopefully-) compatible stand-ins have been chosen. - #---------------------------------------------------- - - ("blake2b", "blake-2b"), - ("blake2s", "blake-2s"), - ("md4", "md4"), - # NOTE: there was an older "ripemd" and "ripemd-128", - # but python 2.7+ resolves "ripemd" -> "ripemd160", - # so treating "ripemd" as alias here. - ("ripemd160", "ripemd-160", "ripemd"), -] - - -#: dict mapping hashlib names to hardcoded digest info; -#: so this is available even when hashes aren't present. -_fallback_info = { - # name: (digest_size, block_size) - 'blake2b': (64, 128), - 'blake2s': (32, 64), - 'md4': (16, 64), - 'md5': (16, 64), - 'sha1': (20, 64), - 'sha224': (28, 64), - 'sha256': (32, 64), - 'sha384': (48, 128), - 'sha3_224': (28, 144), - 'sha3_256': (32, 136), - 'sha3_384': (48, 104), - 'sha3_512': (64, 72), - 'sha512': (64, 128), - 'shake128': (16, 168), - 'shake256': (32, 136), -} - - -def _gen_fallback_info(): - """ - internal helper used to generate ``_fallback_info`` dict. - currently only run manually to update the above list; - not invoked at runtime. - """ - out = {} - for alg in sorted(hashlib.algorithms_available | set(["md4"])): - info = lookup_hash(alg) - out[info.name] = (info.digest_size, info.block_size) - return out - - -#: cache of hash info instances used by lookup_hash() -_hash_info_cache = {} - -def _get_hash_aliases(name): - """ - internal helper used by :func:`lookup_hash` -- - normalize arbitrary hash name to hashlib format. - if name not recognized, returns dummy record and issues a warning. - - :arg name: - unnormalized name - - :returns: - tuple with 2+ elements: ``(hashlib_name, iana_name|None, ... 0+ aliases)``. - """ - - # normalize input - orig = name - if not isinstance(name, str): - name = to_native_str(name, 'utf-8', 'hash name') - name = re.sub("[_ /]", "-", name.strip().lower()) - if name.startswith("scram-"): # helper for SCRAM protocol (see passlib.handlers.scram) - name = name[6:] - if name.endswith("-plus"): - name = name[:-5] - - # look through standard names and known aliases - def check_table(name): - for row in _known_hash_names: - if name in row: - return row - result = check_table(name) - if result: - return result - - # try to clean name up some more - m = re.match(r"(?i)^(?P[a-z]+)-?(?P\d)?-?(?P\d{3,4})?$", name) - if m: - # roughly follows "SHA2-256" style format, normalize representation, - # and checked table. - iana_name, rev, size = m.group("name", "rev", "size") - if rev: - iana_name += rev - hashlib_name = iana_name - if size: - iana_name += "-" + size - if rev: - hashlib_name += "_" - hashlib_name += size - result = check_table(iana_name) - if result: - return result - - # not found in table, but roughly recognize format. use names we built up as fallback. - log.info("normalizing unrecognized hash name %r => %r / %r", - orig, hashlib_name, iana_name) - - else: - # just can't make sense of it. return something - iana_name = name - hashlib_name = name.replace("-", "_") - log.warning("normalizing unrecognized hash name and format %r => %r / %r", - orig, hashlib_name, iana_name) - - return hashlib_name, iana_name - - -def _get_hash_const(name): - """ - internal helper used by :func:`lookup_hash` -- - lookup hash constructor by name - - :arg name: - name (normalized to hashlib format, e.g. ``"sha256"``) - - :returns: - hash constructor, e.g. ``hashlib.sha256()``; - or None if hash can't be located. - """ - # check hashlib. for an efficient constructor - if not name.startswith("_") and name not in ("new", "algorithms"): - try: - return getattr(hashlib, name) - except AttributeError: - pass - - # check hashlib.new() in case SSL supports the digest - new_ssl_hash = hashlib.new - try: - # new() should throw ValueError if alg is unknown - new_ssl_hash(name, b"") - except ValueError: - pass - else: - # create wrapper function - # XXX: is there a faster way to wrap this? - def const(msg=b""): - return new_ssl_hash(name, msg) - const.__name__ = name - const.__module__ = "hashlib" - const.__doc__ = ("wrapper for hashlib.new(%r),\n" - "generated by passlib.crypto.digest.lookup_hash()") % name - return const - - # use builtin md4 as fallback when not supported by hashlib - if name == "md4": - from passlib.crypto._md4 import md4 - return md4 - - # XXX: any other modules / registries we should check? - # TODO: add pysha3 support. - - return None - - -def lookup_hash(digest, # *, - return_unknown=False, required=True): - """ - Returns a :class:`HashInfo` record containing information about a given hash function. - Can be used to look up a hash constructor by name, normalize hash name representation, etc. - - :arg digest: - This can be any of: - - * A string containing a :mod:`!hashlib` digest name (e.g. ``"sha256"``), - * A string containing an IANA-assigned hash name, - * A digest constructor function (e.g. ``hashlib.sha256``). - - Case is ignored, underscores are converted to hyphens, - and various other cleanups are made. - - :param required: - By default (True), this function will throw an :exc:`~passlib.exc.UnknownHashError` if no hash constructor - can be found, or if the hash is not actually available. - - If this flag is False, it will instead return a dummy :class:`!HashInfo` record - which will defer throwing the error until it's constructor function is called. - This is mainly used by :func:`norm_hash_name`. - - :param return_unknown: - - .. deprecated:: 1.7.3 - - deprecated, and will be removed in passlib 2.0. - this acts like inverse of **required**. - - :returns HashInfo: - :class:`HashInfo` instance containing information about specified digest. - - Multiple calls resolving to the same hash should always - return the same :class:`!HashInfo` instance. - """ - # check for cached entry - cache = _hash_info_cache - try: - return cache[digest] - except (KeyError, TypeError): - # NOTE: TypeError is to catch 'TypeError: unhashable type' (e.g. HashInfo) - pass - - # legacy alias - if return_unknown: - required = False - - # resolve ``digest`` to ``const`` & ``name_record`` - cache_by_name = True - if isinstance(digest, unicode_or_bytes_types): - # normalize name - name_list = _get_hash_aliases(digest) - name = name_list[0] - assert name - - # if name wasn't normalized to hashlib format, - # get info for normalized name and reuse it. - if name != digest: - info = lookup_hash(name, required=required) - cache[digest] = info - return info - - # else look up constructor - # NOTE: may return None, which is handled by HashInfo constructor - const = _get_hash_const(name) - - # if mock fips mode is enabled, replace with dummy constructor - # (to replicate how it would behave on a real fips system). - if const and mock_fips_mode and name not in _fips_algorithms: - def const(source=b""): - raise ValueError("%r disabled for fips by passlib set_mock_fips_mode()" % name) - - elif isinstance(digest, HashInfo): - # handle border case where HashInfo is passed in. - return digest - - elif callable(digest): - # try to lookup digest based on it's self-reported name - # (which we trust to be the canonical "hashlib" name) - const = digest - name_list = _get_hash_aliases(const().name) - name = name_list[0] - other_const = _get_hash_const(name) - if other_const is None: - # this is probably a third-party digest we don't know about, - # so just pass it on through, and register reverse lookup for it's name. - pass - - elif other_const is const: - # if we got back same constructor, this is just a known stdlib constructor, - # which was passed in before we had cached it by name. proceed normally. - pass - - else: - # if we got back different object, then ``const`` is something else - # (such as a mock object), in which case we want to skip caching it by name, - # as that would conflict with real hash. - cache_by_name = False - - else: - raise exc.ExpectedTypeError(digest, "digest name or constructor", "digest") - - # create new instance - info = HashInfo(const=const, names=name_list, required=required) - - # populate cache - if const is not None: - cache[const] = info - if cache_by_name: - for name in name_list: - if name: # (skips iana name if it's empty) - assert cache.get(name) in [None, info], "%r already in cache" % name - cache[name] = info - return info - -#: UT helper for clearing internal cache -lookup_hash.clear_cache = _hash_info_cache.clear - - -def norm_hash_name(name, format="hashlib"): - """Normalize hash function name (convenience wrapper for :func:`lookup_hash`). - - :arg name: - Original hash function name. - - This name can be a Python :mod:`~hashlib` digest name, - a SCRAM mechanism name, IANA assigned hash name, etc. - Case is ignored, and underscores are converted to hyphens. - - :param format: - Naming convention to normalize to. - Possible values are: - - * ``"hashlib"`` (the default) - normalizes name to be compatible - with Python's :mod:`!hashlib`. - - * ``"iana"`` - normalizes name to IANA-assigned hash function name. - For hashes which IANA hasn't assigned a name for, this issues a warning, - and then uses a heuristic to return a "best guess" name. - - :returns: - Hash name, returned as native :class:`!str`. - """ - info = lookup_hash(name, required=False) - if info.unknown: - warn("norm_hash_name(): " + info.error_text, exc.PasslibRuntimeWarning) - if format == "hashlib": - return info.name - elif format == "iana": - return info.iana_name - else: - raise ValueError("unknown format: %r" % (format,)) - - -class HashInfo(SequenceMixin): - """ - Record containing information about a given hash algorithm, as returned :func:`lookup_hash`. - - This class exposes the following attributes: - - .. autoattribute:: const - .. autoattribute:: digest_size - .. autoattribute:: block_size - .. autoattribute:: name - .. autoattribute:: iana_name - .. autoattribute:: aliases - .. autoattribute:: supported - - This object can also be treated a 3-element sequence - containing ``(const, digest_size, block_size)``. - """ - #========================================================================= - # instance attrs - #========================================================================= - - #: Canonical / hashlib-compatible name (e.g. ``"sha256"``). - name = None - - #: IANA assigned name (e.g. ``"sha-256"``), may be ``None`` if unknown. - iana_name = None - - #: Tuple of other known aliases (may be empty) - aliases = () - - #: Hash constructor function (e.g. :func:`hashlib.sha256`) - const = None - - #: Hash's digest size - digest_size = None - - #: Hash's block size - block_size = None - - #: set when hash isn't available, will be filled in with string containing error text - #: that const() will raise. - error_text = None - - #: set when error_text is due to hash algorithm being completely unknown - #: (not just unavailable on current system) - unknown = False - - #========================================================================= - # init - #========================================================================= - - def __init__(self, # *, - const, names, required=True): - """ - initialize new instance. - :arg const: - hash constructor - :arg names: - list of 2+ names. should be list of ``(name, iana_name, ... 0+ aliases)``. - names must be lower-case. only iana name may be None. - """ - # init names - name = self.name = names[0] - self.iana_name = names[1] - self.aliases = names[2:] - - def use_stub_const(msg): - """ - helper that installs stub constructor which throws specified error . - """ - def const(source=b""): - raise exc.UnknownHashError(msg, name) - if required: - # if caller only wants supported digests returned, - # just throw error immediately... - const() - assert "shouldn't get here" - self.error_text = msg - self.const = const - try: - self.digest_size, self.block_size = _fallback_info[name] - except KeyError: - pass - - # handle "constructor not available" case - if const is None: - if names in _known_hash_names: - msg = "unsupported hash: %r" % name - else: - msg = "unknown hash: %r" % name - self.unknown = True - use_stub_const(msg) - # TODO: load in preset digest size info for known hashes. - return - - # create hash instance to inspect - try: - hash = const() - except ValueError as err: - # per issue 116, FIPS compliant systems will have a constructor; - # but it will throw a ValueError with this message. As of 1.7.3, - # translating this into DisabledHashError. - # "ValueError: error:060800A3:digital envelope routines:EVP_DigestInit_ex:disabled for fips" - if "disabled for fips" in str(err).lower(): - msg = "%r hash disabled for fips" % name - else: - msg = "internal error in %r constructor\n(%s: %s)" % (name, type(err).__name__, err) - use_stub_const(msg) - return - - # store stats about hash - self.const = const - self.digest_size = hash.digest_size - self.block_size = hash.block_size - - # do sanity check on digest size - if len(hash.digest()) != hash.digest_size: - raise RuntimeError("%r constructor failed sanity check" % self.name) - - # do sanity check on name. - if hash.name != self.name: - warn("inconsistent digest name: %r resolved to %r, which reports name as %r" % - (self.name, const, hash.name), exc.PasslibRuntimeWarning) - - #========================================================================= - # methods - #========================================================================= - def __repr__(self): - return " digest output``. - - However, if ``multipart=True``, the returned function has the signature - ``hmac() -> update, finalize``, where ``update(msg)`` may be called multiple times, - and ``finalize() -> digest_output`` may be repeatedly called at any point to - calculate the HMAC digest so far. - - The returned object will also have a ``digest_info`` attribute, containing - a :class:`lookup_hash` instance for the specified digest. - - This function exists, and has the weird signature it does, in order to squeeze as - provide as much efficiency as possible, by omitting much of the setup cost - and features of the stdlib :mod:`hmac` module. - """ - # all the following was adapted from stdlib's hmac module - - # resolve digest (cached) - digest_info = lookup_hash(digest) - const, digest_size, block_size = digest_info - assert block_size >= 16, "block size too small" - - # prepare key - if not isinstance(key, bytes): - key = to_bytes(key, param="key") - klen = len(key) - if klen > block_size: - key = const(key).digest() - klen = digest_size - if klen < block_size: - key += b'\x00' * (block_size - klen) - - # create pre-initialized hash constructors - _inner_copy = const(key.translate(_TRANS_36)).copy - _outer_copy = const(key.translate(_TRANS_5C)).copy - - if multipart: - # create multi-part function - # NOTE: this is slightly slower than the single-shot version, - # and should only be used if needed. - def hmac(): - """generated by compile_hmac(multipart=True)""" - inner = _inner_copy() - def finalize(): - outer = _outer_copy() - outer.update(inner.digest()) - return outer.digest() - return inner.update, finalize - else: - - # single-shot function - def hmac(msg): - """generated by compile_hmac()""" - inner = _inner_copy() - inner.update(msg) - outer = _outer_copy() - outer.update(inner.digest()) - return outer.digest() - - # add info attr - hmac.digest_info = digest_info - return hmac - -#============================================================================= -# pbkdf1 -#============================================================================= -def pbkdf1(digest, secret, salt, rounds, keylen=None): - """pkcs#5 password-based key derivation v1.5 - - :arg digest: - digest name or constructor. - - :arg secret: - secret to use when generating the key. - may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). - - :arg salt: - salt string to use when generating key. - may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). - - :param rounds: - number of rounds to use to generate key. - - :arg keylen: - number of bytes to generate (if omitted / ``None``, uses digest's native size) - - :returns: - raw :class:`bytes` of generated key - - .. note:: - - This algorithm has been deprecated, new code should use PBKDF2. - Among other limitations, ``keylen`` cannot be larger - than the digest size of the specified hash. - """ - # resolve digest - const, digest_size, block_size = lookup_hash(digest) - - # validate secret & salt - secret = to_bytes(secret, param="secret") - salt = to_bytes(salt, param="salt") - - # validate rounds - if not isinstance(rounds, int_types): - raise exc.ExpectedTypeError(rounds, "int", "rounds") - if rounds < 1: - raise ValueError("rounds must be at least 1") - - # validate keylen - if keylen is None: - keylen = digest_size - elif not isinstance(keylen, int_types): - raise exc.ExpectedTypeError(keylen, "int or None", "keylen") - elif keylen < 0: - raise ValueError("keylen must be at least 0") - elif keylen > digest_size: - raise ValueError("keylength too large for digest: %r > %r" % - (keylen, digest_size)) - - # main pbkdf1 loop - block = secret + salt - for _ in irange(rounds): - block = const(block).digest() - return block[:keylen] - -#============================================================================= -# pbkdf2 -#============================================================================= - -_pack_uint32 = Struct(">L").pack - -def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None): - """pkcs#5 password-based key derivation v2.0 using HMAC + arbitrary digest. - - :arg digest: - digest name or constructor. - - :arg secret: - passphrase to use to generate key. - may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). - - :arg salt: - salt string to use when generating key. - may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). - - :param rounds: - number of rounds to use to generate key. - - :arg keylen: - number of bytes to generate. - if omitted / ``None``, will use digest's native output size. - - :returns: - raw bytes of generated key - - .. versionchanged:: 1.7 - - This function will use the first available of the following backends: - - * `fastpbk2 `_ - * :func:`hashlib.pbkdf2_hmac` (only available in py2 >= 2.7.8, and py3 >= 3.4) - * builtin pure-python backend - - See :data:`passlib.crypto.digest.PBKDF2_BACKENDS` to determine - which backend(s) are in use. - """ - # validate secret & salt - secret = to_bytes(secret, param="secret") - salt = to_bytes(salt, param="salt") - - # resolve digest - digest_info = lookup_hash(digest) - digest_size = digest_info.digest_size - - # validate rounds - if not isinstance(rounds, int_types): - raise exc.ExpectedTypeError(rounds, "int", "rounds") - if rounds < 1: - raise ValueError("rounds must be at least 1") - - # validate keylen - if keylen is None: - keylen = digest_size - elif not isinstance(keylen, int_types): - raise exc.ExpectedTypeError(keylen, "int or None", "keylen") - elif keylen < 1: - # XXX: could allow keylen=0, but want to be compat w/ stdlib - raise ValueError("keylen must be at least 1") - - # find smallest block count s.t. keylen <= block_count * digest_size; - # make sure block count won't overflow (per pbkdf2 spec) - # this corresponds to throwing error if keylen > digest_size * MAX_UINT32 - # NOTE: stdlib will throw error at lower bound (keylen > MAX_SINT32) - # NOTE: have do this before other backends checked, since fastpbkdf2 raises wrong error - # (InvocationError, not OverflowError) - block_count = (keylen + digest_size - 1) // digest_size - if block_count > MAX_UINT32: - raise OverflowError("keylen too long for digest") - - # - # check for various high-speed backends - # - - # ~3x faster than pure-python backend - # NOTE: have to do this after above guards since fastpbkdf2 lacks bounds checks. - if digest_info.supported_by_fastpbkdf2: - return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) - - # ~1.4x faster than pure-python backend - # NOTE: have to do this after fastpbkdf2 since hashlib-ssl is slower, - # will support larger number of hashes. - if digest_info.supported_by_hashlib_pbkdf2: - return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) - - # - # otherwise use our own implementation - # - - # generated keyed hmac - keyed_hmac = compile_hmac(digest, secret) - - # get helper to calculate pbkdf2 inner loop efficiently - calc_block = _get_pbkdf2_looper(digest_size) - - # assemble & return result - return join_bytes( - calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds) - for i in irange(1, block_count + 1) - )[:keylen] - -#------------------------------------------------------------------------------------- -# pick best choice for pure-python helper -# TODO: consider some alternatives, such as C-accelerated xor_bytes helper if available -#------------------------------------------------------------------------------------- -# NOTE: this env var is only present to support the admin/benchmark_pbkdf2 script -_force_backend = os.environ.get("PASSLIB_PBKDF2_BACKEND") or "any" - -if PY3 and _force_backend in ["any", "from-bytes"]: - from functools import partial - - def _get_pbkdf2_looper(digest_size): - return partial(_pbkdf2_looper, digest_size) - - def _pbkdf2_looper(digest_size, keyed_hmac, digest, rounds): - """ - py3-only implementation of pbkdf2 inner loop; - uses 'int.from_bytes' + integer XOR - """ - from_bytes = int.from_bytes - BIG = "big" # endianess doesn't matter, just has to be consistent - accum = from_bytes(digest, BIG) - for _ in irange(rounds - 1): - digest = keyed_hmac(digest) - accum ^= from_bytes(digest, BIG) - return accum.to_bytes(digest_size, BIG) - - _builtin_backend = "from-bytes" - -elif _force_backend in ["any", "unpack", "from-bytes"]: - from struct import Struct - from passlib.utils import sys_bits - - _have_64_bit = (sys_bits >= 64) - - #: cache used by _get_pbkdf2_looper - _looper_cache = {} - - def _get_pbkdf2_looper(digest_size): - """ - We want a helper function which performs equivalent of the following:: - - def helper(keyed_hmac, digest, rounds): - accum = digest - for _ in irange(rounds - 1): - digest = keyed_hmac(digest) - accum ^= digest - return accum - - However, no efficient way to implement "bytes ^ bytes" in python. - Instead, using approach where we dynamically compile a helper function based - on digest size. Instead of a single `accum` var, this helper breaks the digest - into a series of integers. - - It stores these in a series of`accum_` vars, and performs `accum ^= digest` - by unpacking digest and perform xor for each "accum_ ^= digest_". - this keeps everything in locals, avoiding excessive list creation, encoding or decoding, - etc. - - :param digest_size: - digest size to compile for, in bytes. (must be multiple of 4). - - :return: - helper function with call signature outlined above. - """ - # - # cache helpers - # - try: - return _looper_cache[digest_size] - except KeyError: - pass - - # - # figure out most efficient struct format to unpack digest into list of native ints - # - if _have_64_bit and not digest_size & 0x7: - # digest size multiple of 8, on a 64 bit system -- use array of UINT64 - count = (digest_size >> 3) - fmt = "=%dQ" % count - elif not digest_size & 0x3: - if _have_64_bit: - # digest size multiple of 4, on a 64 bit system -- use array of UINT64 + 1 UINT32 - count = (digest_size >> 3) - fmt = "=%dQI" % count - count += 1 - else: - # digest size multiple of 4, on a 32 bit system -- use array of UINT32 - count = (digest_size >> 2) - fmt = "=%dI" % count - else: - # stopping here, cause no known hashes have digest size that isn't multiple of 4 bytes. - # if needed, could go crazy w/ "H" & "B" - raise NotImplementedError("unsupported digest size: %d" % digest_size) - struct = Struct(fmt) - - # - # build helper source - # - tdict = dict( - digest_size=digest_size, - accum_vars=", ".join("acc_%d" % i for i in irange(count)), - digest_vars=", ".join("dig_%d" % i for i in irange(count)), - ) - - # head of function - source = ( - "def helper(keyed_hmac, digest, rounds):\n" - " '''pbkdf2 loop helper for digest_size={digest_size}'''\n" - " unpack_digest = struct.unpack\n" - " {accum_vars} = unpack_digest(digest)\n" - " for _ in irange(1, rounds):\n" - " digest = keyed_hmac(digest)\n" - " {digest_vars} = unpack_digest(digest)\n" - ).format(**tdict) - - # xor digest - for i in irange(count): - source += " acc_%d ^= dig_%d\n" % (i, i) - - # return result - source += " return struct.pack({accum_vars})\n".format(**tdict) - - # - # compile helper - # - code = compile(source, "", "exec") - gdict = dict(irange=irange, struct=struct) - ldict = dict() - eval(code, gdict, ldict) - helper = ldict['helper'] - if __debug__: - helper.__source__ = source - - # - # store in cache - # - _looper_cache[digest_size] = helper - return helper - - _builtin_backend = "unpack" - -else: - assert _force_backend in ["any", "hexlify"] - - # XXX: older & slower approach that used int(hexlify()), - # keeping it around for a little while just for benchmarking. - - from binascii import hexlify as _hexlify - from passlib.utils import int_to_bytes - - def _get_pbkdf2_looper(digest_size): - return _pbkdf2_looper - - def _pbkdf2_looper(keyed_hmac, digest, rounds): - hexlify = _hexlify - accum = int(hexlify(digest), 16) - for _ in irange(rounds - 1): - digest = keyed_hmac(digest) - accum ^= int(hexlify(digest), 16) - return int_to_bytes(accum, len(digest)) - - _builtin_backend = "hexlify" - -# helper for benchmark script -- disable hashlib, fastpbkdf2 support if builtin requested -if _force_backend == _builtin_backend: - _fast_pbkdf2_hmac = _stdlib_pbkdf2_hmac = None - -# expose info about what backends are active -PBKDF2_BACKENDS = [b for b in [ - "fastpbkdf2" if _fast_pbkdf2_hmac else None, - "hashlib-ssl" if _stdlib_pbkdf2_hmac else None, - "builtin-" + _builtin_backend -] if b] - -# *very* rough estimate of relative speed (compared to sha256 using 'unpack' backend on 64bit arch) -if "fastpbkdf2" in PBKDF2_BACKENDS: - PBKDF2_SPEED_FACTOR = 3 -elif "hashlib-ssl" in PBKDF2_BACKENDS: - PBKDF2_SPEED_FACTOR = 1.4 -else: - # remaining backends have *some* difference in performance, but not enough to matter - PBKDF2_SPEED_FACTOR = 1 - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/__init__.py deleted file mode 100644 index c71873a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/__init__.py +++ /dev/null @@ -1,281 +0,0 @@ -""" -passlib.utils.scrypt -- scrypt hash frontend and help utilities - -XXX: add this module to public docs? -""" -#========================================================================== -# imports -#========================================================================== -from __future__ import absolute_import -# core -import logging; log = logging.getLogger(__name__) -from warnings import warn -# pkg -from passlib import exc -from passlib.utils import to_bytes -from passlib.utils.compat import PYPY -# local -__all__ =[ - "validate", - "scrypt", -] - -#========================================================================== -# config validation -#========================================================================== - -#: internal global constant for setting stdlib scrypt's maxmem (int bytes). -#: set to -1 to auto-calculate (see _load_stdlib_backend() below) -#: set to 0 for openssl default (32mb according to python docs) -#: TODO: standardize this across backends, and expose support via scrypt hash config; -#: currently not very configurable, and only applies to stdlib backend. -SCRYPT_MAXMEM = -1 - -#: max output length in bytes -MAX_KEYLEN = ((1 << 32) - 1) * 32 - -#: max ``r * p`` limit -MAX_RP = (1 << 30) - 1 - -# TODO: unittests for this function -def validate(n, r, p): - """ - helper which validates a set of scrypt config parameters. - scrypt will take ``O(n * r * p)`` time and ``O(n * r)`` memory. - limitations are that ``n = 2**``, ``n < 2**(16*r)``, ``r * p < 2 ** 30``. - - :param n: scrypt rounds - :param r: scrypt block size - :param p: scrypt parallel factor - """ - if r < 1: - raise ValueError("r must be > 0: r=%r" % r) - - if p < 1: - raise ValueError("p must be > 0: p=%r" % p) - - if r * p > MAX_RP: - # pbkdf2-hmac-sha256 limitation - it will be requested to generate ``p*(2*r)*64`` bytes, - # but pbkdf2 can do max of (2**31-1) blocks, and sha-256 has 32 byte block size... - # so ``(2**31-1)*32 >= p*r*128`` -> ``r*p < 2**30`` - raise ValueError("r * p must be < 2**30: r=%r, p=%r" % (r,p)) - - if n < 2 or n & (n - 1): - raise ValueError("n must be > 1, and a power of 2: n=%r" % n) - - return True - - -UINT32_SIZE = 4 - - -def estimate_maxmem(n, r, p, fudge=1.05): - """ - calculate memory required for parameter combination. - assumes parameters have already been validated. - - .. warning:: - this is derived from OpenSSL's scrypt maxmem formula; - and may not be correct for other implementations - (additional buffers, different parallelism tradeoffs, etc). - """ - # XXX: expand to provide upper bound for diff backends, or max across all of them? - # NOTE: openssl's scrypt() enforces it's maxmem parameter based on calc located at - # , ending in line containing "Blen + Vlen > maxmem" - # using the following formula: - # Blen = p * 128 * r - # Vlen = 32 * r * (N + 2) * sizeof(uint32_t) - # total_bytes = Blen + Vlen - maxmem = r * (128 * p + 32 * (n + 2) * UINT32_SIZE) - # add fudge factor so we don't have off-by-one mismatch w/ openssl - maxmem = int(maxmem * fudge) - return maxmem - - -# TODO: configuration picker (may need psutil for full effect) - -#========================================================================== -# hash frontend -#========================================================================== - -#: backend function used by scrypt(), filled in by _set_backend() -_scrypt = None - -#: name of backend currently in use, exposed for informational purposes. -backend = None - -def scrypt(secret, salt, n, r, p=1, keylen=32): - """run SCrypt key derivation function using specified parameters. - - :arg secret: - passphrase string (unicode is encoded to bytes using utf-8). - - :arg salt: - salt string (unicode is encoded to bytes using utf-8). - - :arg n: - integer 'N' parameter - - :arg r: - integer 'r' parameter - - :arg p: - integer 'p' parameter - - :arg keylen: - number of bytes of key to generate. - defaults to 32 (the internal block size). - - :returns: - a *keylen*-sized bytes instance - - SCrypt imposes a number of constraints on it's input parameters: - - * ``r * p < 2**30`` -- due to a limitation of PBKDF2-HMAC-SHA256. - * ``keylen < (2**32 - 1) * 32`` -- due to a limitation of PBKDF2-HMAC-SHA256. - * ``n`` must a be a power of 2, and > 1 -- internal limitation of scrypt() implementation - - :raises ValueError: if the provided parameters are invalid (see constraints above). - - .. warning:: - - Unless the third-party ``scrypt ``_ package - is installed, passlib will use a builtin pure-python implementation of scrypt, - which is *considerably* slower (and thus requires a much lower / less secure - ``n`` value in order to be usuable). Installing the :mod:`!scrypt` package - is strongly recommended. - """ - validate(n, r, p) - secret = to_bytes(secret, param="secret") - salt = to_bytes(salt, param="salt") - if keylen < 1: - raise ValueError("keylen must be at least 1") - if keylen > MAX_KEYLEN: - raise ValueError("keylen too large, must be <= %d" % MAX_KEYLEN) - return _scrypt(secret, salt, n, r, p, keylen) - - -def _load_builtin_backend(): - """ - Load pure-python scrypt implementation built into passlib. - """ - slowdown = 10 if PYPY else 100 - warn("Using builtin scrypt backend, which is %dx slower than is required " - "for adequate security. Installing scrypt support (via 'pip install scrypt') " - "is strongly recommended" % slowdown, exc.PasslibSecurityWarning) - from ._builtin import ScryptEngine - return ScryptEngine.execute - - -def _load_cffi_backend(): - """ - Try to import the ctypes-based scrypt hash function provided by the - ``scrypt ``_ package. - """ - try: - from scrypt import hash - return hash - except ImportError: - pass - # not available, but check to see if package present but outdated / not installed right - try: - import scrypt - except ImportError as err: - if "scrypt" not in str(err): - # e.g. if cffi isn't set up right - # user should try importing scrypt explicitly to diagnose problem. - warn("'scrypt' package failed to import correctly (possible installation issue?)", - exc.PasslibWarning) - # else: package just isn't installed - else: - warn("'scrypt' package is too old (lacks ``hash()`` method)", exc.PasslibWarning) - return None - - -def _load_stdlib_backend(): - """ - Attempt to load stdlib scrypt() implement and return wrapper. - Returns None if not found. - """ - try: - # new in python 3.6, if compiled with openssl >= 1.1 - from hashlib import scrypt as stdlib_scrypt - except ImportError: - return None - - def stdlib_scrypt_wrapper(secret, salt, n, r, p, keylen): - # work out appropriate "maxmem" parameter - # - # TODO: would like to enforce a single "maxmem" policy across all backends; - # and maybe expose this via scrypt hasher config. - # - # for now, since parameters should all be coming from internally-controlled sources - # (password hashes), using policy of "whatever memory the parameters needs". - # furthermore, since stdlib scrypt is only place that needs this, - # currently calculating exactly what maxmem needs to make things work for stdlib call. - # as hack, this can be overriden via SCRYPT_MAXMEM above, - # would like to formalize all of this. - maxmem = SCRYPT_MAXMEM - if maxmem < 0: - maxmem = estimate_maxmem(n, r, p) - return stdlib_scrypt(password=secret, salt=salt, n=n, r=r, p=p, dklen=keylen, - maxmem=maxmem) - - return stdlib_scrypt_wrapper - - -#: list of potential backends -backend_values = ("stdlib", "scrypt", "builtin") - -#: dict mapping backend name -> loader -_backend_loaders = dict( - stdlib=_load_stdlib_backend, - scrypt=_load_cffi_backend, # XXX: rename backend constant to "cffi"? - builtin=_load_builtin_backend, -) - - -def _set_backend(name, dryrun=False): - """ - set backend for scrypt(). if name not specified, loads first available. - - :raises ~passlib.exc.MissingBackendError: if backend can't be found - - .. note:: mainly intended to be called by unittests, and scrypt hash handler - """ - if name == "any": - return - elif name == "default": - for name in backend_values: - try: - return _set_backend(name, dryrun=dryrun) - except exc.MissingBackendError: - continue - raise exc.MissingBackendError("no scrypt backends available") - else: - loader = _backend_loaders.get(name) - if not loader: - raise ValueError("unknown scrypt backend: %r" % (name,)) - hash = loader() - if not hash: - raise exc.MissingBackendError("scrypt backend %r not available" % name) - if dryrun: - return - global _scrypt, backend - backend = name - _scrypt = hash - -# initialize backend -_set_backend("default") - - -def _has_backend(name): - try: - _set_backend(name, dryrun=True) - return True - except exc.MissingBackendError: - return False - -#========================================================================== -# eof -#========================================================================== diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_builtin.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_builtin.py deleted file mode 100644 index e9bb305..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_builtin.py +++ /dev/null @@ -1,244 +0,0 @@ -"""passlib.utils.scrypt._builtin -- scrypt() kdf in pure-python""" -#========================================================================== -# imports -#========================================================================== -# core -import operator -import struct -# pkg -from passlib.utils.compat import izip -from passlib.crypto.digest import pbkdf2_hmac -from passlib.crypto.scrypt._salsa import salsa20 -# local -__all__ =[ - "ScryptEngine", -] - -#========================================================================== -# scrypt engine -#========================================================================== -class ScryptEngine(object): - """ - helper class used to run scrypt kdf, see scrypt() for frontend - - .. warning:: - this class does NO validation of the input ranges or types. - - it's not intended to be used directly, - but only as a backend for :func:`passlib.utils.scrypt.scrypt()`. - """ - #================================================================= - # instance attrs - #================================================================= - - # primary scrypt config parameters - n = 0 - r = 0 - p = 0 - - # derived values & objects - smix_bytes = 0 - iv_bytes = 0 - bmix_len = 0 - bmix_half_len = 0 - bmix_struct = None - integerify = None - - #================================================================= - # frontend - #================================================================= - @classmethod - def execute(cls, secret, salt, n, r, p, keylen): - """create engine & run scrypt() hash calculation""" - return cls(n, r, p).run(secret, salt, keylen) - - #================================================================= - # init - #================================================================= - def __init__(self, n, r, p): - # store config - self.n = n - self.r = r - self.p = p - self.smix_bytes = r << 7 # num bytes in smix input - 2*r*16*4 - self.iv_bytes = self.smix_bytes * p - self.bmix_len = bmix_len = r << 5 # length of bmix block list - 32*r integers - self.bmix_half_len = r << 4 - assert struct.calcsize("I") == 4 - self.bmix_struct = struct.Struct("<" + str(bmix_len) + "I") - - # use optimized bmix for certain cases - if r == 1: - self.bmix = self._bmix_1 - - # pick best integerify function - integerify(bmix_block) should - # take last 64 bytes of block and return a little-endian integer. - # since it's immediately converted % n, we only have to extract - # the first 32 bytes if n < 2**32 - which due to the current - # internal representation, is already unpacked as a 32-bit int. - if n <= 0xFFFFffff: - integerify = operator.itemgetter(-16) - else: - assert n <= 0xFFFFffffFFFFffff - ig1 = operator.itemgetter(-16) - ig2 = operator.itemgetter(-17) - def integerify(X): - return ig1(X) | (ig2(X)<<32) - self.integerify = integerify - - #================================================================= - # frontend - #================================================================= - def run(self, secret, salt, keylen): - """ - run scrypt kdf for specified secret, salt, and keylen - - .. note:: - - * time cost is ``O(n * r * p)`` - * mem cost is ``O(n * r)`` - """ - # stretch salt into initial byte array via pbkdf2 - iv_bytes = self.iv_bytes - input = pbkdf2_hmac("sha256", secret, salt, rounds=1, keylen=iv_bytes) - - # split initial byte array into 'p' mflen-sized chunks, - # and run each chunk through smix() to generate output chunk. - smix = self.smix - if self.p == 1: - output = smix(input) - else: - # XXX: *could* use threading here, if really high p values encountered, - # but would tradeoff for more memory usage. - smix_bytes = self.smix_bytes - output = b''.join( - smix(input[offset:offset+smix_bytes]) - for offset in range(0, iv_bytes, smix_bytes) - ) - - # stretch final byte array into output via pbkdf2 - return pbkdf2_hmac("sha256", secret, output, rounds=1, keylen=keylen) - - #================================================================= - # smix() helper - #================================================================= - def smix(self, input): - """run SCrypt smix function on a single input block - - :arg input: - byte string containing input data. - interpreted as 32*r little endian 4 byte integers. - - :returns: - byte string containing output data - derived by mixing input using n & r parameters. - - .. note:: time & mem cost are both ``O(n * r)`` - """ - # gather locals - bmix = self.bmix - bmix_struct = self.bmix_struct - integerify = self.integerify - n = self.n - - # parse input into 32*r integers ('X' in scrypt source) - # mem cost -- O(r) - buffer = list(bmix_struct.unpack(input)) - - # starting with initial buffer contents, derive V s.t. - # V[0]=initial_buffer ... V[i] = bmix(V[i-1], V[i-1]) ... V[n-1] = bmix(V[n-2], V[n-2]) - # final buffer contents should equal bmix(V[n-1], V[n-1]) - # - # time cost -- O(n * r) -- n loops, bmix is O(r) - # mem cost -- O(n * r) -- V is n-element array of r-element tuples - # NOTE: could do time / memory tradeoff to shrink size of V - def vgen(): - i = 0 - while i < n: - last = tuple(buffer) - yield last - bmix(last, buffer) - i += 1 - V = list(vgen()) - - # generate result from X & V. - # - # time cost -- O(n * r) -- loops n times, calls bmix() which has O(r) time cost - # mem cost -- O(1) -- allocates nothing, calls bmix() which has O(1) mem cost - get_v_elem = V.__getitem__ - n_mask = n - 1 - i = 0 - while i < n: - j = integerify(buffer) & n_mask - result = tuple(a ^ b for a, b in izip(buffer, get_v_elem(j))) - bmix(result, buffer) - i += 1 - - # # NOTE: we could easily support arbitrary values of ``n``, not just powers of 2, - # # but very few implementations have that ability, so not enabling it for now... - # if not n_is_log_2: - # while i < n: - # j = integerify(buffer) % n - # tmp = tuple(a^b for a,b in izip(buffer, get_v_elem(j))) - # bmix(tmp,buffer) - # i += 1 - - # repack tmp - return bmix_struct.pack(*buffer) - - #================================================================= - # bmix() helper - #================================================================= - def bmix(self, source, target): - """ - block mixing function used by smix() - uses salsa20/8 core to mix block contents. - - :arg source: - source to read from. - should be list of 32*r 4-byte integers - (2*r salsa20 blocks). - - :arg target: - target to write to. - should be list with same size as source. - the existing value of this buffer is ignored. - - .. warning:: - - this operates *in place* on target, - so source & target should NOT be same list. - - .. note:: - - * time cost is ``O(r)`` -- loops 16*r times, salsa20() has ``O(1)`` cost. - - * memory cost is ``O(1)`` -- salsa20() uses 16 x uint4, - all other operations done in-place. - """ - ## assert source is not target - # Y[-1] = B[2r-1], Y[i] = hash( Y[i-1] xor B[i]) - # B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ - half = self.bmix_half_len # 16*r out of 32*r - start of Y_1 - tmp = source[-16:] # 'X' in scrypt source - siter = iter(source) - j = 0 - while j < half: - jn = j+16 - target[j:jn] = tmp = salsa20(a ^ b for a, b in izip(tmp, siter)) - target[half+j:half+jn] = tmp = salsa20(a ^ b for a, b in izip(tmp, siter)) - j = jn - - def _bmix_1(self, source, target): - """special bmix() method optimized for ``r=1`` case""" - B = source[16:] - target[:16] = tmp = salsa20(a ^ b for a, b in izip(B, iter(source))) - target[16:] = salsa20(a ^ b for a, b in izip(tmp, B)) - - #================================================================= - # eoc - #================================================================= - -#========================================================================== -# eof -#========================================================================== diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_gen_files.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_gen_files.py deleted file mode 100644 index 55ddfae..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_gen_files.py +++ /dev/null @@ -1,154 +0,0 @@ -"""passlib.utils.scrypt._gen_files - meta script that generates _salsa.py""" -#========================================================================== -# imports -#========================================================================== -# core -import os -# pkg -# local -#========================================================================== -# constants -#========================================================================== - -_SALSA_OPS = [ - # row = (target idx, source idx 1, source idx 2, rotate) - # interpreted as salsa operation over uint32... - # target = (source1+source2)<> (32 - (b)))) - ##x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); - ##x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); - ( 4, 0, 12, 7), - ( 8, 4, 0, 9), - ( 12, 8, 4, 13), - ( 0, 12, 8, 18), - - ##x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); - ##x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); - ( 9, 5, 1, 7), - ( 13, 9, 5, 9), - ( 1, 13, 9, 13), - ( 5, 1, 13, 18), - - ##x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); - ##x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); - ( 14, 10, 6, 7), - ( 2, 14, 10, 9), - ( 6, 2, 14, 13), - ( 10, 6, 2, 18), - - ##x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); - ##x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); - ( 3, 15, 11, 7), - ( 7, 3, 15, 9), - ( 11, 7, 3, 13), - ( 15, 11, 7, 18), - - ##/* Operate on rows. */ - ##x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); - ##x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); - ( 1, 0, 3, 7), - ( 2, 1, 0, 9), - ( 3, 2, 1, 13), - ( 0, 3, 2, 18), - - ##x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); - ##x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); - ( 6, 5, 4, 7), - ( 7, 6, 5, 9), - ( 4, 7, 6, 13), - ( 5, 4, 7, 18), - - ##x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); - ##x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); - ( 11, 10, 9, 7), - ( 8, 11, 10, 9), - ( 9, 8, 11, 13), - ( 10, 9, 8, 18), - - ##x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); - ##x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); - ( 12, 15, 14, 7), - ( 13, 12, 15, 9), - ( 14, 13, 12, 13), - ( 15, 14, 13, 18), -] - -def main(): - target = os.path.join(os.path.dirname(__file__), "_salsa.py") - fh = file(target, "w") - write = fh.write - - VNAMES = ["v%d" % i for i in range(16)] - - PAD = " " * 4 - PAD2 = " " * 8 - PAD3 = " " * 12 - TLIST = ", ".join("b%d" % i for i in range(16)) - VLIST = ", ".join(VNAMES) - kwds = dict( - VLIST=VLIST, - TLIST=TLIST, - ) - - write('''\ -"""passlib.utils.scrypt._salsa - salsa 20/8 core, autogenerated by _gen_salsa.py""" -#================================================================= -# salsa function -#================================================================= - -def salsa20(input): - \"""apply the salsa20/8 core to the provided input - - :args input: input list containing 16 32-bit integers - :returns: result list containing 16 32-bit integers - \""" - - %(TLIST)s = input - %(VLIST)s = \\ - %(TLIST)s - - i = 0 - while i < 4: -''' % kwds) - - for idx, (target, source1, source2, rotate) in enumerate(_SALSA_OPS): - write('''\ - # salsa op %(idx)d: [%(it)d] ^= ([%(is1)d]+[%(is2)d])<<<%(rot1)d - t = (%(src1)s + %(src2)s) & 0xffffffff - %(dst)s ^= ((t & 0x%(rmask)08x) << %(rot1)d) | (t >> %(rot2)d) - -''' % dict( - idx=idx, is1 = source1, is2=source2, it=target, - src1=VNAMES[source1], - src2=VNAMES[source2], - dst=VNAMES[target], - rmask=(1<<(32-rotate))-1, - rot1=rotate, - rot2=32-rotate, - )) - - write('''\ - i += 1 - -''') - - for idx in range(16): - write(PAD + "b%d = (b%d + v%d) & 0xffffffff\n" % (idx,idx,idx)) - - write('''\ - - return %(TLIST)s - -#================================================================= -# eof -#================================================================= -''' % kwds) - -if __name__ == "__main__": - main() - -#========================================================================== -# eof -#========================================================================== diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_salsa.py b/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_salsa.py deleted file mode 100644 index 9112732..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/crypto/scrypt/_salsa.py +++ /dev/null @@ -1,170 +0,0 @@ -"""passlib.utils.scrypt._salsa - salsa 20/8 core, autogenerated by _gen_salsa.py""" -#================================================================= -# salsa function -#================================================================= - -def salsa20(input): - """apply the salsa20/8 core to the provided input - - :args input: input list containing 16 32-bit integers - :returns: result list containing 16 32-bit integers - """ - - b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 = input - v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 = \ - b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 - - i = 0 - while i < 4: - # salsa op 0: [4] ^= ([0]+[12])<<<7 - t = (v0 + v12) & 0xffffffff - v4 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 1: [8] ^= ([4]+[0])<<<9 - t = (v4 + v0) & 0xffffffff - v8 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 2: [12] ^= ([8]+[4])<<<13 - t = (v8 + v4) & 0xffffffff - v12 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 3: [0] ^= ([12]+[8])<<<18 - t = (v12 + v8) & 0xffffffff - v0 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 4: [9] ^= ([5]+[1])<<<7 - t = (v5 + v1) & 0xffffffff - v9 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 5: [13] ^= ([9]+[5])<<<9 - t = (v9 + v5) & 0xffffffff - v13 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 6: [1] ^= ([13]+[9])<<<13 - t = (v13 + v9) & 0xffffffff - v1 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 7: [5] ^= ([1]+[13])<<<18 - t = (v1 + v13) & 0xffffffff - v5 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 8: [14] ^= ([10]+[6])<<<7 - t = (v10 + v6) & 0xffffffff - v14 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 9: [2] ^= ([14]+[10])<<<9 - t = (v14 + v10) & 0xffffffff - v2 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 10: [6] ^= ([2]+[14])<<<13 - t = (v2 + v14) & 0xffffffff - v6 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 11: [10] ^= ([6]+[2])<<<18 - t = (v6 + v2) & 0xffffffff - v10 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 12: [3] ^= ([15]+[11])<<<7 - t = (v15 + v11) & 0xffffffff - v3 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 13: [7] ^= ([3]+[15])<<<9 - t = (v3 + v15) & 0xffffffff - v7 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 14: [11] ^= ([7]+[3])<<<13 - t = (v7 + v3) & 0xffffffff - v11 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 15: [15] ^= ([11]+[7])<<<18 - t = (v11 + v7) & 0xffffffff - v15 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 16: [1] ^= ([0]+[3])<<<7 - t = (v0 + v3) & 0xffffffff - v1 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 17: [2] ^= ([1]+[0])<<<9 - t = (v1 + v0) & 0xffffffff - v2 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 18: [3] ^= ([2]+[1])<<<13 - t = (v2 + v1) & 0xffffffff - v3 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 19: [0] ^= ([3]+[2])<<<18 - t = (v3 + v2) & 0xffffffff - v0 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 20: [6] ^= ([5]+[4])<<<7 - t = (v5 + v4) & 0xffffffff - v6 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 21: [7] ^= ([6]+[5])<<<9 - t = (v6 + v5) & 0xffffffff - v7 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 22: [4] ^= ([7]+[6])<<<13 - t = (v7 + v6) & 0xffffffff - v4 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 23: [5] ^= ([4]+[7])<<<18 - t = (v4 + v7) & 0xffffffff - v5 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 24: [11] ^= ([10]+[9])<<<7 - t = (v10 + v9) & 0xffffffff - v11 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 25: [8] ^= ([11]+[10])<<<9 - t = (v11 + v10) & 0xffffffff - v8 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 26: [9] ^= ([8]+[11])<<<13 - t = (v8 + v11) & 0xffffffff - v9 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 27: [10] ^= ([9]+[8])<<<18 - t = (v9 + v8) & 0xffffffff - v10 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - # salsa op 28: [12] ^= ([15]+[14])<<<7 - t = (v15 + v14) & 0xffffffff - v12 ^= ((t & 0x01ffffff) << 7) | (t >> 25) - - # salsa op 29: [13] ^= ([12]+[15])<<<9 - t = (v12 + v15) & 0xffffffff - v13 ^= ((t & 0x007fffff) << 9) | (t >> 23) - - # salsa op 30: [14] ^= ([13]+[12])<<<13 - t = (v13 + v12) & 0xffffffff - v14 ^= ((t & 0x0007ffff) << 13) | (t >> 19) - - # salsa op 31: [15] ^= ([14]+[13])<<<18 - t = (v14 + v13) & 0xffffffff - v15 ^= ((t & 0x00003fff) << 18) | (t >> 14) - - i += 1 - - b0 = (b0 + v0) & 0xffffffff - b1 = (b1 + v1) & 0xffffffff - b2 = (b2 + v2) & 0xffffffff - b3 = (b3 + v3) & 0xffffffff - b4 = (b4 + v4) & 0xffffffff - b5 = (b5 + v5) & 0xffffffff - b6 = (b6 + v6) & 0xffffffff - b7 = (b7 + v7) & 0xffffffff - b8 = (b8 + v8) & 0xffffffff - b9 = (b9 + v9) & 0xffffffff - b10 = (b10 + v10) & 0xffffffff - b11 = (b11 + v11) & 0xffffffff - b12 = (b12 + v12) & 0xffffffff - b13 = (b13 + v13) & 0xffffffff - b14 = (b14 + v14) & 0xffffffff - b15 = (b15 + v15) & 0xffffffff - - return b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 - -#================================================================= -# eof -#================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/exc.py b/backend/venv39/lib/python3.9/site-packages/passlib/exc.py deleted file mode 100644 index 755c7dc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/exc.py +++ /dev/null @@ -1,397 +0,0 @@ -"""passlib.exc -- exceptions & warnings raised by passlib""" -#============================================================================= -# exceptions -#============================================================================= -class UnknownBackendError(ValueError): - """ - Error raised if multi-backend handler doesn't recognize backend name. - Inherits from :exc:`ValueError`. - - .. versionadded:: 1.7 - """ - def __init__(self, hasher, backend): - self.hasher = hasher - self.backend = backend - message = "%s: unknown backend: %r" % (hasher.name, backend) - ValueError.__init__(self, message) - - -# XXX: add a PasslibRuntimeError as base for Missing/Internal/Security runtime errors? - - -class MissingBackendError(RuntimeError): - """Error raised if multi-backend handler has no available backends; - or if specifically requested backend is not available. - - :exc:`!MissingBackendError` derives - from :exc:`RuntimeError`, since it usually indicates - lack of an external library or OS feature. - This is primarily raised by handlers which depend on - external libraries (which is currently just - :class:`~passlib.hash.bcrypt`). - """ - - -class InternalBackendError(RuntimeError): - """ - Error raised if something unrecoverable goes wrong with backend call; - such as if ``crypt.crypt()`` returning a malformed hash. - - .. versionadded:: 1.7.3 - """ - - -class PasswordValueError(ValueError): - """ - Error raised if a password can't be hashed / verified for various reasons. - This exception derives from the builtin :exc:`!ValueError`. - - May be thrown directly when password violates internal invariants of hasher - (e.g. some don't support NULL characters). Hashers may also throw more specific subclasses, - such as :exc:`!PasswordSizeError`. - - .. versionadded:: 1.7.3 - """ - pass - - -class PasswordSizeError(PasswordValueError): - """ - Error raised if a password exceeds the maximum size allowed - by Passlib (by default, 4096 characters); or if password exceeds - a hash-specific size limitation. - - This exception derives from :exc:`PasswordValueError` (above). - - Many password hash algorithms take proportionately larger amounts of time and/or - memory depending on the size of the password provided. This could present - a potential denial of service (DOS) situation if a maliciously large - password is provided to an application. Because of this, Passlib enforces - a maximum size limit, but one which should be *much* larger - than any legitimate password. :exc:`PasswordSizeError` derives - from :exc:`!ValueError`. - - .. note:: - Applications wishing to use a different limit should set the - ``PASSLIB_MAX_PASSWORD_SIZE`` environmental variable before - Passlib is loaded. The value can be any large positive integer. - - .. attribute:: max_size - - indicates the maximum allowed size. - - .. versionadded:: 1.6 - """ - - max_size = None - - def __init__(self, max_size, msg=None): - self.max_size = max_size - if msg is None: - msg = "password exceeds maximum allowed size" - PasswordValueError.__init__(self, msg) - - # this also prevents a glibc crypt segfault issue, detailed here ... - # http://www.openwall.com/lists/oss-security/2011/11/15/1 - -class PasswordTruncateError(PasswordSizeError): - """ - Error raised if password would be truncated by hash. - This derives from :exc:`PasswordSizeError` (above). - - Hashers such as :class:`~passlib.hash.bcrypt` can be configured to raises - this error by setting ``truncate_error=True``. - - .. attribute:: max_size - - indicates the maximum allowed size. - - .. versionadded:: 1.7 - """ - - def __init__(self, cls, msg=None): - if msg is None: - msg = ("Password too long (%s truncates to %d characters)" % - (cls.name, cls.truncate_size)) - PasswordSizeError.__init__(self, cls.truncate_size, msg) - - -class PasslibSecurityError(RuntimeError): - """ - Error raised if critical security issue is detected - (e.g. an attempt is made to use a vulnerable version of a bcrypt backend). - - .. versionadded:: 1.6.3 - """ - - -class TokenError(ValueError): - """ - Base error raised by v:mod:`passlib.totp` when - a token can't be parsed / isn't valid / etc. - Derives from :exc:`!ValueError`. - - Usually one of the more specific subclasses below will be raised: - - * :class:`MalformedTokenError` -- invalid chars, too few digits - * :class:`InvalidTokenError` -- no match found - * :class:`UsedTokenError` -- match found, but token already used - - .. versionadded:: 1.7 - """ - - #: default message to use if none provided -- subclasses may fill this in - _default_message = 'Token not acceptable' - - def __init__(self, msg=None, *args, **kwds): - if msg is None: - msg = self._default_message - ValueError.__init__(self, msg, *args, **kwds) - - -class MalformedTokenError(TokenError): - """ - Error raised by :mod:`passlib.totp` when a token isn't formatted correctly - (contains invalid characters, wrong number of digits, etc) - """ - _default_message = "Unrecognized token" - - -class InvalidTokenError(TokenError): - """ - Error raised by :mod:`passlib.totp` when a token is formatted correctly, - but doesn't match any tokens within valid range. - """ - _default_message = "Token did not match" - - -class UsedTokenError(TokenError): - """ - Error raised by :mod:`passlib.totp` if a token is reused. - Derives from :exc:`TokenError`. - - .. autoattribute:: expire_time - - .. versionadded:: 1.7 - """ - _default_message = "Token has already been used, please wait for another." - - #: optional value indicating when current counter period will end, - #: and a new token can be generated. - expire_time = None - - def __init__(self, *args, **kwds): - self.expire_time = kwds.pop("expire_time", None) - TokenError.__init__(self, *args, **kwds) - - -class UnknownHashError(ValueError): - """ - Error raised by :class:`~passlib.crypto.lookup_hash` if hash name is not recognized. - This exception derives from :exc:`!ValueError`. - - As of version 1.7.3, this may also be raised if hash algorithm is known, - but has been disabled due to FIPS mode (message will include phrase "disabled for fips"). - - As of version 1.7.4, this may be raised if a :class:`~passlib.context.CryptContext` - is unable to identify the algorithm used by a password hash. - - .. versionadded:: 1.7 - - .. versionchanged: 1.7.3 - added 'message' argument. - - .. versionchanged:: 1.7.4 - altered call signature. - """ - def __init__(self, message=None, value=None): - self.value = value - if message is None: - message = "unknown hash algorithm: %r" % value - self.message = message - ValueError.__init__(self, message, value) - - def __str__(self): - return self.message - - -#============================================================================= -# warnings -#============================================================================= -class PasslibWarning(UserWarning): - """base class for Passlib's user warnings, - derives from the builtin :exc:`UserWarning`. - - .. versionadded:: 1.6 - """ - -# XXX: there's only one reference to this class, and it will go away in 2.0; -# so can probably remove this along with this / roll this into PasslibHashWarning. -class PasslibConfigWarning(PasslibWarning): - """Warning issued when non-fatal issue is found related to the configuration - of a :class:`~passlib.context.CryptContext` instance. - - This occurs primarily in one of two cases: - - * The CryptContext contains rounds limits which exceed the hard limits - imposed by the underlying algorithm. - * An explicit rounds value was provided which exceeds the limits - imposed by the CryptContext. - - In both of these cases, the code will perform correctly & securely; - but the warning is issued as a sign the configuration may need updating. - - .. versionadded:: 1.6 - """ - -class PasslibHashWarning(PasslibWarning): - """Warning issued when non-fatal issue is found with parameters - or hash string passed to a passlib hash class. - - This occurs primarily in one of two cases: - - * A rounds value or other setting was explicitly provided which - exceeded the handler's limits (and has been clamped - by the :ref:`relaxed` flag). - - * A malformed hash string was encountered which (while parsable) - should be re-encoded. - - .. versionadded:: 1.6 - """ - -class PasslibRuntimeWarning(PasslibWarning): - """Warning issued when something unexpected happens during runtime. - - The fact that it's a warning instead of an error means Passlib - was able to correct for the issue, but that it's anomalous enough - that the developers would love to hear under what conditions it occurred. - - .. versionadded:: 1.6 - """ - -class PasslibSecurityWarning(PasslibWarning): - """Special warning issued when Passlib encounters something - that might affect security. - - .. versionadded:: 1.6 - """ - -#============================================================================= -# error constructors -# -# note: these functions are used by the hashes in Passlib to raise common -# error messages. They are currently just functions which return ValueError, -# rather than subclasses of ValueError, since the specificity isn't needed -# yet; and who wants to import a bunch of error classes when catching -# ValueError will do? -#============================================================================= - -def _get_name(handler): - return handler.name if handler else "" - -#------------------------------------------------------------------------ -# generic helpers -#------------------------------------------------------------------------ -def type_name(value): - """return pretty-printed string containing name of value's type""" - cls = value.__class__ - if cls.__module__ and cls.__module__ not in ["__builtin__", "builtins"]: - return "%s.%s" % (cls.__module__, cls.__name__) - elif value is None: - return 'None' - else: - return cls.__name__ - -def ExpectedTypeError(value, expected, param): - """error message when param was supposed to be one type, but found another""" - # NOTE: value is never displayed, since it may sometimes be a password. - name = type_name(value) - return TypeError("%s must be %s, not %s" % (param, expected, name)) - -def ExpectedStringError(value, param): - """error message when param was supposed to be unicode or bytes""" - return ExpectedTypeError(value, "unicode or bytes", param) - -#------------------------------------------------------------------------ -# hash/verify parameter errors -#------------------------------------------------------------------------ -def MissingDigestError(handler=None): - """raised when verify() method gets passed config string instead of hash""" - name = _get_name(handler) - return ValueError("expected %s hash, got %s config string instead" % - (name, name)) - -def NullPasswordError(handler=None): - """raised by OS crypt() supporting hashes, which forbid NULLs in password""" - name = _get_name(handler) - return PasswordValueError("%s does not allow NULL bytes in password" % name) - -#------------------------------------------------------------------------ -# errors when parsing hashes -#------------------------------------------------------------------------ -def InvalidHashError(handler=None): - """error raised if unrecognized hash provided to handler""" - return ValueError("not a valid %s hash" % _get_name(handler)) - -def MalformedHashError(handler=None, reason=None): - """error raised if recognized-but-malformed hash provided to handler""" - text = "malformed %s hash" % _get_name(handler) - if reason: - text = "%s (%s)" % (text, reason) - return ValueError(text) - -def ZeroPaddedRoundsError(handler=None): - """error raised if hash was recognized but contained zero-padded rounds field""" - return MalformedHashError(handler, "zero-padded rounds") - -#------------------------------------------------------------------------ -# settings / hash component errors -#------------------------------------------------------------------------ -def ChecksumSizeError(handler, raw=False): - """error raised if hash was recognized, but checksum was wrong size""" - # TODO: if handler.use_defaults is set, this came from app-provided value, - # not from parsing a hash string, might want different error msg. - checksum_size = handler.checksum_size - unit = "bytes" if raw else "chars" - reason = "checksum must be exactly %d %s" % (checksum_size, unit) - return MalformedHashError(handler, reason) - -#============================================================================= -# sensitive info helpers -#============================================================================= - -#: global flag, set temporarily by UTs to allow debug_only_repr() to display sensitive values. -ENABLE_DEBUG_ONLY_REPR = False - - -def debug_only_repr(value, param="hash"): - """ - helper used to display sensitive data (hashes etc) within error messages. - currently returns placeholder test UNLESS unittests are running, - in which case the real value is displayed. - - mainly useful to prevent hashes / secrets from being exposed in production tracebacks; - while still being visible from test failures. - - NOTE: api subject to change, may formalize this more in the future. - """ - if ENABLE_DEBUG_ONLY_REPR or value is None or isinstance(value, bool): - return repr(value) - return "<%s %s value omitted>" % (param, type(value)) - - -def CryptBackendError(handler, config, hash, # * - source="crypt.crypt()"): - """ - helper to generate standard message when ``crypt.crypt()`` returns invalid result. - takes care of automatically masking contents of config & hash outside of UTs. - """ - name = _get_name(handler) - msg = "%s returned invalid %s hash: config=%s hash=%s" % \ - (source, name, debug_only_repr(config), debug_only_repr(hash)) - raise InternalBackendError(msg) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/ext/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/ext/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/ext/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/__init__.py deleted file mode 100644 index 2dc9b28..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""passlib.ext.django.models -- monkeypatch django hashing framework - -this plugin monkeypatches django's hashing framework -so that it uses a passlib context object, allowing handling of arbitrary -hashes in Django databases. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/models.py b/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/models.py deleted file mode 100644 index e766c2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/models.py +++ /dev/null @@ -1,36 +0,0 @@ -"""passlib.ext.django.models -- monkeypatch django hashing framework""" -#============================================================================= -# imports -#============================================================================= -# core -# site -# pkg -from passlib.context import CryptContext -from passlib.ext.django.utils import DjangoContextAdapter -# local -__all__ = ["password_context"] - -#============================================================================= -# global attrs -#============================================================================= - -#: adapter instance used to drive most of this -adapter = DjangoContextAdapter() - -# the context object which this patches contrib.auth to use for password hashing. -# configuration controlled by ``settings.PASSLIB_CONFIG``. -password_context = adapter.context - -#: hook callers should use if context is changed -context_changed = adapter.reset_hashers - -#============================================================================= -# main code -#============================================================================= - -# load config & install monkeypatch -adapter.load_model() - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/utils.py b/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/utils.py deleted file mode 100644 index 2f8a2ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/ext/django/utils.py +++ /dev/null @@ -1,1276 +0,0 @@ -"""passlib.ext.django.utils - helper functions used by this plugin""" -#============================================================================= -# imports -#============================================================================= -# core -from functools import update_wrapper, wraps -import logging; log = logging.getLogger(__name__) -import sys -import weakref -from warnings import warn -# site -try: - from django import VERSION as DJANGO_VERSION - log.debug("found django %r installation", DJANGO_VERSION) -except ImportError: - log.debug("django installation not found") - DJANGO_VERSION = () -# pkg -from passlib import exc, registry -from passlib.context import CryptContext -from passlib.exc import PasslibRuntimeWarning -from passlib.utils.compat import get_method_function, iteritems, OrderedDict, unicode -from passlib.utils.decor import memoized_property -# local -__all__ = [ - "DJANGO_VERSION", - "MIN_DJANGO_VERSION", - "get_preset_config", - "quirks", -] - -#: minimum version supported by passlib.ext.django -MIN_DJANGO_VERSION = (1, 8) - -#============================================================================= -# quirk detection -#============================================================================= - -class quirks: - - #: django check_password() started throwing error on encoded=None - #: (really identify_hasher did) - none_causes_check_password_error = DJANGO_VERSION >= (2, 1) - - #: django is_usable_password() started returning True for password = {None, ""} values. - empty_is_usable_password = DJANGO_VERSION >= (2, 1) - - #: django is_usable_password() started returning True for non-hash strings in 2.1 - invalid_is_usable_password = DJANGO_VERSION >= (2, 1) - -#============================================================================= -# default policies -#============================================================================= - -# map preset names -> passlib.app attrs -_preset_map = { - "django-1.0": "django10_context", - "django-1.4": "django14_context", - "django-1.6": "django16_context", - "django-latest": "django_context", -} - -def get_preset_config(name): - """Returns configuration string for one of the preset strings - supported by the ``PASSLIB_CONFIG`` setting. - Currently supported presets: - - * ``"passlib-default"`` - default config used by this release of passlib. - * ``"django-default"`` - config matching currently installed django version. - * ``"django-latest"`` - config matching newest django version (currently same as ``"django-1.6"``). - * ``"django-1.0"`` - config used by stock Django 1.0 - 1.3 installs - * ``"django-1.4"`` - config used by stock Django 1.4 installs - * ``"django-1.6"`` - config used by stock Django 1.6 installs - """ - # TODO: add preset which includes HASHERS + PREFERRED_HASHERS, - # after having imported any custom hashers. e.g. "django-current" - if name == "django-default": - if not DJANGO_VERSION: - raise ValueError("can't resolve django-default preset, " - "django not installed") - name = "django-1.6" - if name == "passlib-default": - return PASSLIB_DEFAULT - try: - attr = _preset_map[name] - except KeyError: - raise ValueError("unknown preset config name: %r" % name) - import passlib.apps - return getattr(passlib.apps, attr).to_string() - -# default context used by passlib 1.6 -PASSLIB_DEFAULT = """ -[passlib] - -; list of schemes supported by configuration -; currently all django 1.6, 1.4, and 1.0 hashes, -; and three common modular crypt format hashes. -schemes = - django_pbkdf2_sha256, django_pbkdf2_sha1, django_bcrypt, django_bcrypt_sha256, - django_salted_sha1, django_salted_md5, django_des_crypt, hex_md5, - sha512_crypt, bcrypt, phpass - -; default scheme to use for new hashes -default = django_pbkdf2_sha256 - -; hashes using these schemes will automatically be re-hashed -; when the user logs in (currently all django 1.0 hashes) -deprecated = - django_pbkdf2_sha1, django_salted_sha1, django_salted_md5, - django_des_crypt, hex_md5 - -; sets some common options, including minimum rounds for two primary hashes. -; if a hash has less than this number of rounds, it will be re-hashed. -sha512_crypt__min_rounds = 80000 -django_pbkdf2_sha256__min_rounds = 10000 - -; set somewhat stronger iteration counts for ``User.is_staff`` -staff__sha512_crypt__default_rounds = 100000 -staff__django_pbkdf2_sha256__default_rounds = 12500 - -; and even stronger ones for ``User.is_superuser`` -superuser__sha512_crypt__default_rounds = 120000 -superuser__django_pbkdf2_sha256__default_rounds = 15000 -""" - -#============================================================================= -# helpers -#============================================================================= - -#: prefix used to shoehorn passlib's handler names into django hasher namespace -PASSLIB_WRAPPER_PREFIX = "passlib_" - -#: prefix used by all the django-specific hash formats in passlib; -#: all of these hashes should have a ``.django_name`` attribute. -DJANGO_COMPAT_PREFIX = "django_" - -#: set of hashes w/o "django_" prefix, but which also expose ``.django_name``. -_other_django_hashes = set(["hex_md5"]) - -def _wrap_method(method): - """wrap method object in bare function""" - @wraps(method) - def wrapper(*args, **kwds): - return method(*args, **kwds) - return wrapper - -#============================================================================= -# translator -#============================================================================= -class DjangoTranslator(object): - """ - Object which helps translate passlib hasher objects / names - to and from django hasher objects / names. - - These methods are wrapped in a class so that results can be cached, - but with the ability to have independant caches, since django hasher - names may / may not correspond to the same instance (or even class). - """ - #============================================================================= - # instance attrs - #============================================================================= - - #: CryptContext instance - #: (if any -- generally only set by DjangoContextAdapter subclass) - context = None - - #: internal cache of passlib hasher -> django hasher instance. - #: key stores weakref to passlib hasher. - _django_hasher_cache = None - - #: special case -- unsalted_sha1 - _django_unsalted_sha1 = None - - #: internal cache of django name -> passlib hasher - #: value stores weakrefs to passlib hasher. - _passlib_hasher_cache = None - - #============================================================================= - # init - #============================================================================= - - def __init__(self, context=None, **kwds): - super(DjangoTranslator, self).__init__(**kwds) - if context is not None: - self.context = context - - self._django_hasher_cache = weakref.WeakKeyDictionary() - self._passlib_hasher_cache = weakref.WeakValueDictionary() - - def reset_hashers(self): - self._django_hasher_cache.clear() - self._passlib_hasher_cache.clear() - self._django_unsalted_sha1 = None - - def _get_passlib_hasher(self, passlib_name): - """ - resolve passlib hasher by name, using context if available. - """ - context = self.context - if context is None: - return registry.get_crypt_handler(passlib_name) - else: - return context.handler(passlib_name) - - #============================================================================= - # resolve passlib hasher -> django hasher - #============================================================================= - - def passlib_to_django_name(self, passlib_name): - """ - Convert passlib hasher / name to Django hasher name. - """ - return self.passlib_to_django(passlib_name).algorithm - - # XXX: add option (in class, or call signature) to always return a wrapper, - # rather than native builtin -- would let HashersTest check that - # our own wrapper + implementations are matching up with their tests. - def passlib_to_django(self, passlib_hasher, cached=True): - """ - Convert passlib hasher / name to Django hasher. - - :param passlib_hasher: - passlib hasher / name - - :returns: - django hasher instance - """ - # resolve names to hasher - if not hasattr(passlib_hasher, "name"): - passlib_hasher = self._get_passlib_hasher(passlib_hasher) - - # check cache - if cached: - cache = self._django_hasher_cache - try: - return cache[passlib_hasher] - except KeyError: - pass - result = cache[passlib_hasher] = \ - self.passlib_to_django(passlib_hasher, cached=False) - return result - - # find native equivalent, and return wrapper if there isn't one - django_name = getattr(passlib_hasher, "django_name", None) - if django_name: - return self._create_django_hasher(django_name) - else: - return _PasslibHasherWrapper(passlib_hasher) - - _builtin_django_hashers = dict( - md5="MD5PasswordHasher", - ) - - if DJANGO_VERSION > (2, 1): - # present but disabled by default as of django 2.1; not sure when added, - # so not listing it by default. - _builtin_django_hashers.update( - bcrypt="BCryptPasswordHasher", - ) - - def _create_django_hasher(self, django_name): - """ - helper to create new django hasher by name. - wraps underlying django methods. - """ - # if we haven't patched django, can use it directly - module = sys.modules.get("passlib.ext.django.models") - if module is None or not module.adapter.patched: - from django.contrib.auth.hashers import get_hasher - try: - return get_hasher(django_name) - except ValueError as err: - if not str(err).startswith("Unknown password hashing algorithm"): - raise - else: - # We've patched django's get_hashers(), so calling django's get_hasher() - # or get_hashers_by_algorithm() would only land us back here. - # As non-ideal workaround, have to use original get_hashers(), - get_hashers = module.adapter._manager.getorig("django.contrib.auth.hashers:get_hashers").__wrapped__ - for hasher in get_hashers(): - if hasher.algorithm == django_name: - return hasher - - # hardcode a few for cases where get_hashers() lookup won't work - # (mainly, hashers that are present in django, but disabled by their default config) - path = self._builtin_django_hashers.get(django_name) - if path: - if "." not in path: - path = "django.contrib.auth.hashers." + path - from django.utils.module_loading import import_string - return import_string(path)() - - raise ValueError("unknown hasher: %r" % django_name) - - #============================================================================= - # reverse django -> passlib - #============================================================================= - - def django_to_passlib_name(self, django_name): - """ - Convert Django hasher / name to Passlib hasher name. - """ - return self.django_to_passlib(django_name).name - - def django_to_passlib(self, django_name, cached=True): - """ - Convert Django hasher / name to Passlib hasher / name. - If present, CryptContext will be checked instead of main registry. - - :param django_name: - Django hasher class or algorithm name. - "default" allowed if context provided. - - :raises ValueError: - if can't resolve hasher. - - :returns: - passlib hasher or name - """ - # check for django hasher - if hasattr(django_name, "algorithm"): - - # check for passlib adapter - if isinstance(django_name, _PasslibHasherWrapper): - return django_name.passlib_handler - - # resolve django hasher -> name - django_name = django_name.algorithm - - # check cache - if cached: - cache = self._passlib_hasher_cache - try: - return cache[django_name] - except KeyError: - pass - result = cache[django_name] = \ - self.django_to_passlib(django_name, cached=False) - return result - - # check if it's an obviously-wrapped name - if django_name.startswith(PASSLIB_WRAPPER_PREFIX): - passlib_name = django_name[len(PASSLIB_WRAPPER_PREFIX):] - return self._get_passlib_hasher(passlib_name) - - # resolve default - if django_name == "default": - context = self.context - if context is None: - raise TypeError("can't determine default scheme w/ context") - return context.handler() - - # special case: Django uses a separate hasher for "sha1$$digest" - # hashes (unsalted_sha1) and "sha1$salt$digest" (sha1); - # but passlib uses "django_salted_sha1" for both of these. - if django_name == "unsalted_sha1": - django_name = "sha1" - - # resolve name - # XXX: bother caching these lists / mapping? - # not needed in long-term due to cache above. - context = self.context - if context is None: - # check registry - # TODO: should make iteration via registry easier - candidates = ( - registry.get_crypt_handler(passlib_name) - for passlib_name in registry.list_crypt_handlers() - if passlib_name.startswith(DJANGO_COMPAT_PREFIX) or - passlib_name in _other_django_hashes - ) - else: - # check context - candidates = context.schemes(resolve=True) - for handler in candidates: - if getattr(handler, "django_name", None) == django_name: - return handler - - # give up - # NOTE: this should only happen for custom django hashers that we don't - # know the equivalents for. _HasherHandler (below) is work in - # progress that would allow us to at least return a wrapper. - raise ValueError("can't translate django name to passlib name: %r" % - (django_name,)) - - #============================================================================= - # django hasher lookup - #============================================================================= - - def resolve_django_hasher(self, django_name, cached=True): - """ - Take in a django algorithm name, return django hasher. - """ - # check for django hasher - if hasattr(django_name, "algorithm"): - return django_name - - # resolve to passlib hasher - passlib_hasher = self.django_to_passlib(django_name, cached=cached) - - # special case: Django uses a separate hasher for "sha1$$digest" - # hashes (unsalted_sha1) and "sha1$salt$digest" (sha1); - # but passlib uses "django_salted_sha1" for both of these. - # XXX: this isn't ideal way to handle this. would like to do something - # like pass "django_variant=django_name" into passlib_to_django(), - # and have it cache separate hasher there. - # but that creates a LOT of complication in it's cache structure, - # for what is just one special case. - if django_name == "unsalted_sha1" and passlib_hasher.name == "django_salted_sha1": - if not cached: - return self._create_django_hasher(django_name) - result = self._django_unsalted_sha1 - if result is None: - result = self._django_unsalted_sha1 = self._create_django_hasher(django_name) - return result - - # lookup corresponding django hasher - return self.passlib_to_django(passlib_hasher, cached=cached) - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# adapter -#============================================================================= -class DjangoContextAdapter(DjangoTranslator): - """ - Object which tries to adapt a Passlib CryptContext object, - using a Django-hasher compatible API. - - When installed in django, :mod:`!passlib.ext.django` will create - an instance of this class, and then monkeypatch the appropriate - methods into :mod:`!django.contrib.auth` and other appropriate places. - """ - #============================================================================= - # instance attrs - #============================================================================= - - #: CryptContext instance we're wrapping - context = None - - #: ref to original make_password(), - #: needed to generate usuable passwords that match django - _orig_make_password = None - - #: ref to django helper of this name -- not monkeypatched - is_password_usable = None - - #: PatchManager instance used to track installation - _manager = None - - #: whether config=disabled flag was set - enabled = True - - #: patch status - patched = False - - #============================================================================= - # init - #============================================================================= - def __init__(self, context=None, get_user_category=None, **kwds): - - # init log - self.log = logging.getLogger(__name__ + ".DjangoContextAdapter") - - # init parent, filling in default context object - if context is None: - context = CryptContext() - super(DjangoContextAdapter, self).__init__(context=context, **kwds) - - # setup user category - if get_user_category: - assert callable(get_user_category) - self.get_user_category = get_user_category - - # install lru cache wrappers - try: - from functools import lru_cache # new py32 - except ImportError: - from django.utils.lru_cache import lru_cache # py2 compat, removed in django 3 (or earlier?) - self.get_hashers = lru_cache()(self.get_hashers) - - # get copy of original make_password - from django.contrib.auth.hashers import make_password - if make_password.__module__.startswith("passlib."): - make_password = _PatchManager.peek_unpatched_func(make_password) - self._orig_make_password = make_password - - # get other django helpers - from django.contrib.auth.hashers import is_password_usable - self.is_password_usable = is_password_usable - - # init manager - mlog = logging.getLogger(__name__ + ".DjangoContextAdapter._manager") - self._manager = _PatchManager(log=mlog) - - def reset_hashers(self): - """ - Wrapper to manually reset django's hasher lookup cache - """ - # resets cache for .get_hashers() & .get_hashers_by_algorithm() - from django.contrib.auth.hashers import reset_hashers - reset_hashers(setting="PASSWORD_HASHERS") - - # reset internal caches - super(DjangoContextAdapter, self).reset_hashers() - - #============================================================================= - # django hashers helpers -- hasher lookup - #============================================================================= - - # lru_cache()'ed by init - def get_hashers(self): - """ - Passlib replacement for get_hashers() -- - Return list of available django hasher classes - """ - passlib_to_django = self.passlib_to_django - return [passlib_to_django(hasher) - for hasher in self.context.schemes(resolve=True)] - - def get_hasher(self, algorithm="default"): - """ - Passlib replacement for get_hasher() -- - Return django hasher by name - """ - return self.resolve_django_hasher(algorithm) - - def identify_hasher(self, encoded): - """ - Passlib replacement for identify_hasher() -- - Identify django hasher based on hash. - """ - handler = self.context.identify(encoded, resolve=True, required=True) - if handler.name == "django_salted_sha1" and encoded.startswith("sha1$$"): - # Django uses a separate hasher for "sha1$$digest" hashes, but - # passlib identifies it as belonging to "sha1$salt$digest" handler. - # We want to resolve to correct django hasher. - return self.get_hasher("unsalted_sha1") - return self.passlib_to_django(handler) - - #============================================================================= - # django.contrib.auth.hashers helpers -- password helpers - #============================================================================= - - def make_password(self, password, salt=None, hasher="default"): - """ - Passlib replacement for make_password() - """ - if password is None: - return self._orig_make_password(None) - # NOTE: relying on hasher coming from context, and thus having - # context-specific config baked into it. - passlib_hasher = self.django_to_passlib(hasher) - if "salt" not in passlib_hasher.setting_kwds: - # ignore salt param even if preset - pass - elif hasher.startswith("unsalted_"): - # Django uses a separate 'unsalted_sha1' hasher for "sha1$$digest", - # but passlib just reuses it's "sha1" handler ("sha1$salt$digest"). To make - # this work, have to explicitly tell the sha1 handler to use an empty salt. - passlib_hasher = passlib_hasher.using(salt="") - elif salt: - # Django make_password() autogenerates a salt if salt is bool False (None / ''), - # so we only pass the keyword on if there's actually a fixed salt. - passlib_hasher = passlib_hasher.using(salt=salt) - return passlib_hasher.hash(password) - - def check_password(self, password, encoded, setter=None, preferred="default"): - """ - Passlib replacement for check_password() - """ - # XXX: this currently ignores "preferred" keyword, since its purpose - # was for hash migration, and that's handled by the context. - # XXX: honor "none_causes_check_password_error" quirk for django 2.2+? - # seems safer to return False. - if password is None or not self.is_password_usable(encoded): - return False - - # verify password - context = self.context - try: - correct = context.verify(password, encoded) - except exc.UnknownHashError: - # As of django 1.5, unidentifiable hashes returns False - # (side-effect of django issue 18453) - return False - - if not (correct and setter): - return correct - - # check if we need to rehash - if preferred == "default": - if not context.needs_update(encoded, secret=password): - return correct - else: - # Django's check_password() won't call setter() on a - # 'preferred' alg, even if it's otherwise deprecated. To try and - # replicate this behavior if preferred is set, we look up the - # passlib hasher, and call it's original needs_update() method. - # TODO: Solve redundancy that verify() call - # above is already identifying hash. - hasher = self.django_to_passlib(preferred) - if (hasher.identify(encoded) and - not hasher.needs_update(encoded, secret=password)): - # alg is 'preferred' and hash itself doesn't need updating, - # so nothing to do. - return correct - # else: either hash isn't preferred, or it needs updating. - - # call setter to rehash - setter(password) - return correct - - #============================================================================= - # django users helpers - #============================================================================= - - def user_check_password(self, user, password): - """ - Passlib replacement for User.check_password() - """ - if password is None: - return False - hash = user.password - if not self.is_password_usable(hash): - return False - cat = self.get_user_category(user) - try: - ok, new_hash = self.context.verify_and_update(password, hash, category=cat) - except exc.UnknownHashError: - # As of django 1.5, unidentifiable hashes returns False - # (side-effect of django issue 18453) - return False - if ok and new_hash is not None: - # migrate to new hash if needed. - user.password = new_hash - user.save() - return ok - - def user_set_password(self, user, password): - """ - Passlib replacement for User.set_password() - """ - if password is None: - user.set_unusable_password() - else: - cat = self.get_user_category(user) - user.password = self.context.hash(password, category=cat) - - def get_user_category(self, user): - """ - Helper for hashing passwords per-user -- - figure out the CryptContext category for specified Django user object. - .. note:: - This may be overridden via PASSLIB_GET_CATEGORY django setting - """ - if user.is_superuser: - return "superuser" - elif user.is_staff: - return "staff" - else: - return None - - #============================================================================= - # patch control - #============================================================================= - - HASHERS_PATH = "django.contrib.auth.hashers" - MODELS_PATH = "django.contrib.auth.models" - USER_CLASS_PATH = MODELS_PATH + ":User" - FORMS_PATH = "django.contrib.auth.forms" - - #: list of locations to patch - patch_locations = [ - # - # User object - # NOTE: could leave defaults alone, but want to have user available - # so that we can support get_user_category() - # - (USER_CLASS_PATH + ".check_password", "user_check_password", dict(method=True)), - (USER_CLASS_PATH + ".set_password", "user_set_password", dict(method=True)), - - # - # Hashers module - # - (HASHERS_PATH + ":", "check_password"), - (HASHERS_PATH + ":", "make_password"), - (HASHERS_PATH + ":", "get_hashers"), - (HASHERS_PATH + ":", "get_hasher"), - (HASHERS_PATH + ":", "identify_hasher"), - - # - # Patch known imports from hashers module - # - (MODELS_PATH + ":", "check_password"), - (MODELS_PATH + ":", "make_password"), - (FORMS_PATH + ":", "get_hasher"), - (FORMS_PATH + ":", "identify_hasher"), - - ] - - def install_patch(self): - """ - Install monkeypatch to replace django hasher framework. - """ - # don't reapply - log = self.log - if self.patched: - log.warning("monkeypatching already applied, refusing to reapply") - return False - - # version check - if DJANGO_VERSION < MIN_DJANGO_VERSION: - raise RuntimeError("passlib.ext.django requires django >= %s" % - (MIN_DJANGO_VERSION,)) - - # log start - log.debug("preparing to monkeypatch django ...") - - # run through patch locations - manager = self._manager - for record in self.patch_locations: - if len(record) == 2: - record += ({},) - target, source, opts = record - if target.endswith((":", ",")): - target += source - value = getattr(self, source) - if opts.get("method"): - # have to wrap our method in a function, - # since we're installing it in a class *as* a method - # XXX: make this a flag for .patch()? - value = _wrap_method(value) - manager.patch(target, value) - - # reset django's caches (e.g. get_hash_by_algorithm) - self.reset_hashers() - - # done! - self.patched = True - log.debug("... finished monkeypatching django") - return True - - def remove_patch(self): - """ - Remove monkeypatch from django hasher framework. - As precaution in case there are lingering refs to context, - context object will be wiped. - - .. warning:: - This may cause problems if any other Django modules have imported - their own copies of the patched functions, though the patched - code has been designed to throw an error as soon as possible in - this case. - """ - log = self.log - manager = self._manager - - if self.patched: - log.debug("removing django monkeypatching...") - manager.unpatch_all(unpatch_conflicts=True) - self.context.load({}) - self.patched = False - self.reset_hashers() - log.debug("...finished removing django monkeypatching") - return True - - if manager.isactive(): # pragma: no cover -- sanity check - log.warning("reverting partial monkeypatching of django...") - manager.unpatch_all() - self.context.load({}) - self.reset_hashers() - log.debug("...finished removing django monkeypatching") - return True - - log.debug("django not monkeypatched") - return False - - #============================================================================= - # loading config - #============================================================================= - - def load_model(self): - """ - Load configuration from django, and install patch. - """ - self._load_settings() - if self.enabled: - try: - self.install_patch() - except: - # try to undo what we can - self.remove_patch() - raise - else: - if self.patched: # pragma: no cover -- sanity check - log.error("didn't expect monkeypatching would be applied!") - self.remove_patch() - log.debug("passlib.ext.django loaded") - - def _load_settings(self): - """ - Update settings from django - """ - from django.conf import settings - - # TODO: would like to add support for inheriting config from a preset - # (or from existing hasher state) and letting PASSLIB_CONFIG - # be an update, not a replacement. - - # TODO: wrap and import any custom hashers as passlib handlers, - # so they could be used in the passlib config. - - # load config from settings - _UNSET = object() - config = getattr(settings, "PASSLIB_CONFIG", _UNSET) - if config is _UNSET: - # XXX: should probably deprecate this alias - config = getattr(settings, "PASSLIB_CONTEXT", _UNSET) - if config is _UNSET: - config = "passlib-default" - if config is None: - warn("setting PASSLIB_CONFIG=None is deprecated, " - "and support will be removed in Passlib 1.8, " - "use PASSLIB_CONFIG='disabled' instead.", - DeprecationWarning) - config = "disabled" - elif not isinstance(config, (unicode, bytes, dict)): - raise exc.ExpectedTypeError(config, "str or dict", "PASSLIB_CONFIG") - - # load custom category func (if any) - get_category = getattr(settings, "PASSLIB_GET_CATEGORY", None) - if get_category and not callable(get_category): - raise exc.ExpectedTypeError(get_category, "callable", "PASSLIB_GET_CATEGORY") - - # check if we've been disabled - if config == "disabled": - self.enabled = False - return - else: - self.__dict__.pop("enabled", None) - - # resolve any preset aliases - if isinstance(config, str) and '\n' not in config: - config = get_preset_config(config) - - # setup category func - if get_category: - self.get_user_category = get_category - else: - self.__dict__.pop("get_category", None) - - # setup context - self.context.load(config) - self.reset_hashers() - - #============================================================================= - # eof - #============================================================================= - -#============================================================================= -# wrapping passlib handlers as django hashers -#============================================================================= -_GEN_SALT_SIGNAL = "--!!!generate-new-salt!!!--" - -class ProxyProperty(object): - """helper that proxies another attribute""" - - def __init__(self, attr): - self.attr = attr - - def __get__(self, obj, cls): - if obj is None: - cls = obj - return getattr(obj, self.attr) - - def __set__(self, obj, value): - setattr(obj, self.attr, value) - - def __delete__(self, obj): - delattr(obj, self.attr) - - -class _PasslibHasherWrapper(object): - """ - adapter which which wraps a :cls:`passlib.ifc.PasswordHash` class, - and provides an interface compatible with the Django hasher API. - - :param passlib_handler: - passlib hash handler (e.g. :cls:`passlib.hash.sha256_crypt`. - """ - #===================================================================== - # instance attrs - #===================================================================== - - #: passlib handler that we're adapting. - passlib_handler = None - - # NOTE: 'rounds' attr will store variable rounds, IF handler supports it. - # 'iterations' will act as proxy, for compatibility with django pbkdf2 hashers. - # rounds = None - # iterations = None - - #===================================================================== - # init - #===================================================================== - def __init__(self, passlib_handler): - # init handler - if getattr(passlib_handler, "django_name", None): - raise ValueError("handlers that reflect an official django " - "hasher shouldn't be wrapped: %r" % - (passlib_handler.name,)) - if passlib_handler.is_disabled: - # XXX: could this be implemented? - raise ValueError("can't wrap disabled-hash handlers: %r" % - (passlib_handler.name)) - self.passlib_handler = passlib_handler - - # init rounds support - if self._has_rounds: - self.rounds = passlib_handler.default_rounds - self.iterations = ProxyProperty("rounds") - - #===================================================================== - # internal methods - #===================================================================== - def __repr__(self): - return "" % self.passlib_handler - - #===================================================================== - # internal properties - #===================================================================== - - @memoized_property - def __name__(self): - return "Passlib_%s_PasswordHasher" % self.passlib_handler.name.title() - - @memoized_property - def _has_rounds(self): - return "rounds" in self.passlib_handler.setting_kwds - - @memoized_property - def _translate_kwds(self): - """ - internal helper for safe_summary() -- - used to translate passlib hash options -> django keywords - """ - out = dict(checksum="hash") - if self._has_rounds and "pbkdf2" in self.passlib_handler.name: - out['rounds'] = 'iterations' - return out - - #===================================================================== - # hasher properties - #===================================================================== - - @memoized_property - def algorithm(self): - return PASSLIB_WRAPPER_PREFIX + self.passlib_handler.name - - #===================================================================== - # hasher api - #===================================================================== - def salt(self): - # NOTE: passlib's handler.hash() should generate new salt each time, - # so this just returns a special constant which tells - # encode() (below) not to pass a salt keyword along. - return _GEN_SALT_SIGNAL - - def verify(self, password, encoded): - return self.passlib_handler.verify(password, encoded) - - def encode(self, password, salt=None, rounds=None, iterations=None): - kwds = {} - if salt is not None and salt != _GEN_SALT_SIGNAL: - kwds['salt'] = salt - if self._has_rounds: - if rounds is not None: - kwds['rounds'] = rounds - elif iterations is not None: - kwds['rounds'] = iterations - else: - kwds['rounds'] = self.rounds - elif rounds is not None or iterations is not None: - warn("%s.hash(): 'rounds' and 'iterations' are ignored" % self.__name__) - handler = self.passlib_handler - if kwds: - handler = handler.using(**kwds) - return handler.hash(password) - - def safe_summary(self, encoded): - from django.contrib.auth.hashers import mask_hash - from django.utils.translation import ugettext_noop as _ - handler = self.passlib_handler - items = [ - # since this is user-facing, we're reporting passlib's name, - # without the distracting PASSLIB_HASHER_PREFIX prepended. - (_('algorithm'), handler.name), - ] - if hasattr(handler, "parsehash"): - kwds = handler.parsehash(encoded, sanitize=mask_hash) - for key, value in iteritems(kwds): - key = self._translate_kwds.get(key, key) - items.append((_(key), value)) - return OrderedDict(items) - - def must_update(self, encoded): - # TODO: would like access CryptContext, would need caller to pass it to get_passlib_hasher(). - # for now (as of passlib 1.6.6), replicating django policy that this returns True - # if 'encoded' hash has different rounds value from self.rounds - if self._has_rounds: - # XXX: could cache this subclass somehow (would have to intercept writes to self.rounds) - # TODO: always call subcls/handler.needs_update() in case there's other things to check - subcls = self.passlib_handler.using(min_rounds=self.rounds, max_rounds=self.rounds) - if subcls.needs_update(encoded): - return True - return False - - #===================================================================== - # eoc - #===================================================================== - -#============================================================================= -# adapting django hashers -> passlib handlers -#============================================================================= -# TODO: this code probably halfway works, mainly just needs -# a routine to read HASHERS and PREFERRED_HASHER. - -##from passlib.registry import register_crypt_handler -##from passlib.utils import classproperty, to_native_str, to_unicode -##from passlib.utils.compat import unicode -## -## -##class _HasherHandler(object): -## "helper for wrapping Hasher instances as passlib handlers" -## # FIXME: this generic wrapper doesn't handle custom settings -## # FIXME: genconfig / genhash not supported. -## -## def __init__(self, hasher): -## self.django_hasher = hasher -## if hasattr(hasher, "iterations"): -## # assume encode() accepts an "iterations" parameter. -## # fake min/max rounds -## self.min_rounds = 1 -## self.max_rounds = 0xFFFFffff -## self.default_rounds = self.django_hasher.iterations -## self.setting_kwds += ("rounds",) -## -## # hasher instance - filled in by constructor -## django_hasher = None -## -## setting_kwds = ("salt",) -## context_kwds = () -## -## @property -## def name(self): -## # XXX: need to make sure this wont' collide w/ builtin django hashes. -## # maybe by renaming this to django compatible aliases? -## return DJANGO_PASSLIB_PREFIX + self.django_name -## -## @property -## def django_name(self): -## # expose this so hasher_to_passlib_name() extracts original name -## return self.django_hasher.algorithm -## -## @property -## def ident(self): -## # this should always be correct, as django relies on ident prefix. -## return unicode(self.django_name + "$") -## -## @property -## def identify(self, hash): -## # this should always work, as django relies on ident prefix. -## return to_unicode(hash, "latin-1", "hash").startswith(self.ident) -## -## @property -## def hash(self, secret, salt=None, **kwds): -## # NOTE: from how make_password() is coded, all hashers -## # should have salt param. but only some will have -## # 'iterations' parameter. -## opts = {} -## if 'rounds' in self.setting_kwds and 'rounds' in kwds: -## opts['iterations'] = kwds.pop("rounds") -## if kwds: -## raise TypeError("unexpected keyword arguments: %r" % list(kwds)) -## if isinstance(secret, unicode): -## secret = secret.encode("utf-8") -## if salt is None: -## salt = self.django_hasher.salt() -## return to_native_str(self.django_hasher(secret, salt, **opts)) -## -## @property -## def verify(self, secret, hash): -## hash = to_native_str(hash, "utf-8", "hash") -## if isinstance(secret, unicode): -## secret = secret.encode("utf-8") -## return self.django_hasher.verify(secret, hash) -## -##def register_hasher(hasher): -## handler = _HasherHandler(hasher) -## register_crypt_handler(handler) -## return handler - -#============================================================================= -# monkeypatch helpers -#============================================================================= -# private singleton indicating lack-of-value -_UNSET = object() - -class _PatchManager(object): - """helper to manage monkeypatches and run sanity checks""" - - # NOTE: this could easily use a dict interface, - # but keeping it distinct to make clear that it's not a dict, - # since it has important side-effects. - - #=================================================================== - # init and support - #=================================================================== - def __init__(self, log=None): - # map of key -> (original value, patched value) - # original value may be _UNSET - self.log = log or logging.getLogger(__name__ + "._PatchManager") - self._state = {} - - def isactive(self): - return bool(self._state) - - # bool value tests if any patches are currently applied. - # NOTE: this behavior is deprecated in favor of .isactive - __bool__ = __nonzero__ = isactive - - def _import_path(self, path): - """retrieve obj and final attribute name from resource path""" - name, attr = path.split(":") - obj = __import__(name, fromlist=[attr], level=0) - while '.' in attr: - head, attr = attr.split(".", 1) - obj = getattr(obj, head) - return obj, attr - - @staticmethod - def _is_same_value(left, right): - """check if two values are the same (stripping method wrappers, etc)""" - return get_method_function(left) == get_method_function(right) - - #=================================================================== - # reading - #=================================================================== - def _get_path(self, key, default=_UNSET): - obj, attr = self._import_path(key) - return getattr(obj, attr, default) - - def get(self, path, default=None): - """return current value for path""" - return self._get_path(path, default) - - def getorig(self, path, default=None): - """return original (unpatched) value for path""" - try: - value, _= self._state[path] - except KeyError: - value = self._get_path(path) - return default if value is _UNSET else value - - def check_all(self, strict=False): - """run sanity check on all keys, issue warning if out of sync""" - same = self._is_same_value - for path, (orig, expected) in iteritems(self._state): - if same(self._get_path(path), expected): - continue - msg = "another library has patched resource: %r" % path - if strict: - raise RuntimeError(msg) - else: - warn(msg, PasslibRuntimeWarning) - - #=================================================================== - # patching - #=================================================================== - def _set_path(self, path, value): - obj, attr = self._import_path(path) - if value is _UNSET: - if hasattr(obj, attr): - delattr(obj, attr) - else: - setattr(obj, attr, value) - - def patch(self, path, value, wrap=False): - """monkeypatch object+attr at to have , stores original""" - assert value != _UNSET - current = self._get_path(path) - try: - orig, expected = self._state[path] - except KeyError: - self.log.debug("patching resource: %r", path) - orig = current - else: - self.log.debug("modifying resource: %r", path) - if not self._is_same_value(current, expected): - warn("overridding resource another library has patched: %r" - % path, PasslibRuntimeWarning) - if wrap: - assert callable(value) - wrapped = orig - wrapped_by = value - def wrapper(*args, **kwds): - return wrapped_by(wrapped, *args, **kwds) - update_wrapper(wrapper, value) - value = wrapper - if callable(value): - # needed by DjangoContextAdapter init - get_method_function(value)._patched_original_value = orig - self._set_path(path, value) - self._state[path] = (orig, value) - - @classmethod - def peek_unpatched_func(cls, value): - return value._patched_original_value - - ##def patch_many(self, **kwds): - ## "override specified resources with new values" - ## for path, value in iteritems(kwds): - ## self.patch(path, value) - - def monkeypatch(self, parent, name=None, enable=True, wrap=False): - """function decorator which patches function of same name in """ - def builder(func): - if enable: - sep = "." if ":" in parent else ":" - path = parent + sep + (name or func.__name__) - self.patch(path, func, wrap=wrap) - return func - if callable(name): - # called in non-decorator mode - func = name - name = None - builder(func) - return None - return builder - - #=================================================================== - # unpatching - #=================================================================== - def unpatch(self, path, unpatch_conflicts=True): - try: - orig, expected = self._state[path] - except KeyError: - return - current = self._get_path(path) - self.log.debug("unpatching resource: %r", path) - if not self._is_same_value(current, expected): - if unpatch_conflicts: - warn("reverting resource another library has patched: %r" - % path, PasslibRuntimeWarning) - else: - warn("not reverting resource another library has patched: %r" - % path, PasslibRuntimeWarning) - del self._state[path] - return - self._set_path(path, orig) - del self._state[path] - - def unpatch_all(self, **kwds): - for key in list(self._state): - self.unpatch(key, **kwds) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/__init__.py deleted file mode 100644 index 0a0338c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""passlib.handlers -- holds implementations of all passlib's builtin hash formats""" diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/argon2.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/argon2.py deleted file mode 100644 index 4a5691b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/argon2.py +++ /dev/null @@ -1,1009 +0,0 @@ -"""passlib.handlers.argon2 -- argon2 password hash wrapper - -References -========== -* argon2 - - home: https://github.com/P-H-C/phc-winner-argon2 - - whitepaper: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf -* argon2 cffi wrapper - - pypi: https://pypi.python.org/pypi/argon2_cffi - - home: https://github.com/hynek/argon2_cffi -* argon2 pure python - - pypi: https://pypi.python.org/pypi/argon2pure - - home: https://github.com/bwesterb/argon2pure -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, absolute_import -# core -import logging -log = logging.getLogger(__name__) -import re -import types -from warnings import warn -# site -_argon2_cffi = None # loaded below -_argon2pure = None # dynamically imported by _load_backend_argon2pure() -# pkg -from passlib import exc -from passlib.crypto.digest import MAX_UINT32 -from passlib.utils import classproperty, to_bytes, render_bytes -from passlib.utils.binary import b64s_encode, b64s_decode -from passlib.utils.compat import u, unicode, bascii_to_str, uascii_to_str, PY2 -import passlib.utils.handlers as uh -# local -__all__ = [ - "argon2", -] - -#============================================================================= -# helpers -#============================================================================= - -# NOTE: when adding a new argon2 hash type, need to do the following: -# * add TYPE_XXX constant, and add to ALL_TYPES -# * make sure "_backend_type_map" constructors handle it correctly for all backends -# * make sure _hash_regex & _ident_regex (below) support type string. -# * add reference vectors for testing. - -#: argon2 type constants -- subclasses handle mapping these to backend-specific type constants. -#: (should be lowercase, to match representation in hash string) -TYPE_I = u("i") -TYPE_D = u("d") -TYPE_ID = u("id") # new 2016-10-29; passlib 1.7.2 requires backends new enough for support - -#: list of all known types; first (supported) type will be used as default. -ALL_TYPES = (TYPE_ID, TYPE_I, TYPE_D) -ALL_TYPES_SET = set(ALL_TYPES) - -#============================================================================= -# import argon2 package (https://pypi.python.org/pypi/argon2_cffi) -#============================================================================= - -# import cffi package -# NOTE: we try to do this even if caller is going to use argon2pure, -# so that we can always use the libargon2 default settings when possible. -_argon2_cffi_error = None -try: - import argon2 as _argon2_cffi -except ImportError: - _argon2_cffi = None -else: - if not hasattr(_argon2_cffi, "Type"): - # they have incompatible "argon2" package installed, instead of "argon2_cffi" package. - _argon2_cffi_error = ( - "'argon2' module points to unsupported 'argon2' pypi package; " - "please install 'argon2-cffi' instead." - ) - _argon2_cffi = None - elif not hasattr(_argon2_cffi, "low_level"): - # they have pre-v16 argon2_cffi package - _argon2_cffi_error = "'argon2-cffi' is too old, please update to argon2_cffi >= 18.2.0" - _argon2_cffi = None - -# init default settings for our hasher class -- -# if we have argon2_cffi >= 16.0, use their default hasher settings, otherwise use static default -if hasattr(_argon2_cffi, "PasswordHasher"): - # use cffi's default settings - _default_settings = _argon2_cffi.PasswordHasher() - _default_version = _argon2_cffi.low_level.ARGON2_VERSION -else: - # use fallback settings (for no backend, or argon2pure) - class _DummyCffiHasher: - """ - dummy object to use as source of defaults when argon2_cffi isn't present. - this tries to mimic the attributes of ``argon2.PasswordHasher()`` which the rest of - this module reads. - - .. note:: values last synced w/ argon2 19.2 as of 2019-11-09 - """ - time_cost = 2 - memory_cost = 512 - parallelism = 2 - salt_len = 16 - hash_len = 16 - # NOTE: "type" attribute added in argon2_cffi v18.2; but currently not reading it - # type = _argon2_cffi.Type.ID - - _default_settings = _DummyCffiHasher() - _default_version = 0x13 # v1.9 - -#============================================================================= -# handler -#============================================================================= -class _Argon2Common(uh.SubclassBackendMixin, uh.ParallelismMixin, - uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, - uh.GenericHandler): - """ - Base class which implements brunt of Argon2 code. - This is then subclassed by the various backends, - to override w/ backend-specific methods. - - When a backend is loaded, the bases of the 'argon2' class proper - are modified to prepend the correct backend-specific subclass. - """ - #=================================================================== - # class attrs - #=================================================================== - - #------------------------ - # PasswordHash - #------------------------ - - name = "argon2" - setting_kwds = ("salt", - "salt_size", - "salt_len", # 'salt_size' alias for compat w/ argon2 package - "rounds", - "time_cost", # 'rounds' alias for compat w/ argon2 package - "memory_cost", - "parallelism", - "digest_size", - "hash_len", # 'digest_size' alias for compat w/ argon2 package - "type", # the type of argon2 hash used - ) - - # TODO: could support the optional 'data' parameter, - # but need to research the uses, what a more descriptive name would be, - # and deal w/ fact that argon2_cffi 16.1 doesn't currently support it. - # (argon2_pure does though) - - #------------------------ - # GenericHandler - #------------------------ - - # NOTE: ident -- all argon2 hashes start with "$argon2$" - # XXX: could programmaticaly generate "ident_values" string from ALL_TYPES above - - checksum_size = _default_settings.hash_len - - #: force parsing these kwds - _always_parse_settings = uh.GenericHandler._always_parse_settings + \ - ("type",) - - #: exclude these kwds from parsehash() result (most are aliases for other keys) - _unparsed_settings = uh.GenericHandler._unparsed_settings + \ - ("salt_len", "time_cost", "hash_len", "digest_size") - - #------------------------ - # HasSalt - #------------------------ - default_salt_size = _default_settings.salt_len - min_salt_size = 8 - max_salt_size = MAX_UINT32 - - #------------------------ - # HasRounds - # TODO: once rounds limit logic is factored out, - # make 'rounds' and 'cost' an alias for 'time_cost' - #------------------------ - default_rounds = _default_settings.time_cost - min_rounds = 1 - max_rounds = MAX_UINT32 - rounds_cost = "linear" - - #------------------------ - # ParalleismMixin - #------------------------ - max_parallelism = (1 << 24) - 1 # from argon2.h / ARGON2_MAX_LANES - - #------------------------ - # custom - #------------------------ - - #: max version support - #: NOTE: this is dependant on the backend, and initialized/modified by set_backend() - max_version = _default_version - - #: minimum version before needs_update() marks the hash; if None, defaults to max_version - min_desired_version = None - - #: minimum valid memory_cost - min_memory_cost = 8 # from argon2.h / ARGON2_MIN_MEMORY - - #: maximum number of threads (-1=unlimited); - #: number of threads used by .hash() will be min(parallelism, max_threads) - max_threads = -1 - - #: global flag signalling argon2pure backend to use threads - #: rather than subprocesses. - pure_use_threads = False - - #: internal helper used to store mapping of TYPE_XXX constants -> backend-specific type constants; - #: this is populated by _load_backend_mixin(); and used to detect which types are supported. - #: XXX: could expose keys as class-level .supported_types property? - _backend_type_map = {} - - @classproperty - def type_values(cls): - """ - return tuple of types supported by this backend - - .. versionadded:: 1.7.2 - """ - cls.get_backend() # make sure backend is loaded - return tuple(cls._backend_type_map) - - #=================================================================== - # instance attrs - #=================================================================== - - #: argon2 hash type, one of ALL_TYPES -- class value controls the default - #: .. versionadded:: 1.7.2 - type = TYPE_ID - - #: parallelism setting -- class value controls the default - parallelism = _default_settings.parallelism - - #: hash version (int) - #: NOTE: this is modified by set_backend() - version = _default_version - - #: memory cost -- class value controls the default - memory_cost = _default_settings.memory_cost - - @property - def type_d(self): - """ - flag indicating a Type D hash - - .. deprecated:: 1.7.2; will be removed in passlib 2.0 - """ - return self.type == TYPE_D - - #: optional secret data - data = None - - #=================================================================== - # variant constructor - #=================================================================== - - @classmethod - def using(cls, type=None, memory_cost=None, salt_len=None, time_cost=None, digest_size=None, - checksum_size=None, hash_len=None, max_threads=None, **kwds): - # support aliases which match argon2 naming convention - if time_cost is not None: - if "rounds" in kwds: - raise TypeError("'time_cost' and 'rounds' are mutually exclusive") - kwds['rounds'] = time_cost - - if salt_len is not None: - if "salt_size" in kwds: - raise TypeError("'salt_len' and 'salt_size' are mutually exclusive") - kwds['salt_size'] = salt_len - - if hash_len is not None: - if digest_size is not None: - raise TypeError("'hash_len' and 'digest_size' are mutually exclusive") - digest_size = hash_len - - if checksum_size is not None: - if digest_size is not None: - raise TypeError("'checksum_size' and 'digest_size' are mutually exclusive") - digest_size = checksum_size - - # create variant - subcls = super(_Argon2Common, cls).using(**kwds) - - # set type - if type is not None: - subcls.type = subcls._norm_type(type) - - # set checksum size - relaxed = kwds.get("relaxed") - if digest_size is not None: - if isinstance(digest_size, uh.native_string_types): - digest_size = int(digest_size) - # NOTE: this isn't *really* digest size minimum, but want to enforce secure minimum. - subcls.checksum_size = uh.norm_integer(subcls, digest_size, min=16, max=MAX_UINT32, - param="digest_size", relaxed=relaxed) - - # set memory cost - if memory_cost is not None: - if isinstance(memory_cost, uh.native_string_types): - memory_cost = int(memory_cost) - subcls.memory_cost = subcls._norm_memory_cost(memory_cost, relaxed=relaxed) - - # validate constraints - subcls._validate_constraints(subcls.memory_cost, subcls.parallelism) - - # set max threads - if max_threads is not None: - if isinstance(max_threads, uh.native_string_types): - max_threads = int(max_threads) - if max_threads < 1 and max_threads != -1: - raise ValueError("max_threads (%d) must be -1 (unlimited), or at least 1." % - (max_threads,)) - subcls.max_threads = max_threads - - return subcls - - @classmethod - def _validate_constraints(cls, memory_cost, parallelism): - # NOTE: this is used by class & instance, hence passing in via arguments. - # could switch and make this a hybrid method. - min_memory_cost = 8 * parallelism - if memory_cost < min_memory_cost: - raise ValueError("%s: memory_cost (%d) is too low, must be at least " - "8 * parallelism (8 * %d = %d)" % - (cls.name, memory_cost, - parallelism, min_memory_cost)) - - #=================================================================== - # public api - #=================================================================== - - #: shorter version of _hash_regex, used to quickly identify hashes - _ident_regex = re.compile(r"^\$argon2[a-z]+\$") - - @classmethod - def identify(cls, hash): - hash = uh.to_unicode_for_identify(hash) - return cls._ident_regex.match(hash) is not None - - # hash(), verify(), genhash() -- implemented by backend subclass - - #=================================================================== - # hash parsing / rendering - #=================================================================== - - # info taken from source of decode_string() function in - # - # - # hash format: - # $argon2[$v=]$m=,t=,p=[,keyid=][,data=][$[$]] - # - # NOTE: as of 2016-6-17, the official source (above) lists the "keyid" param in the comments, - # but the actual source of decode_string & encode_string don't mention it at all. - # we're supporting parsing it, but throw NotImplementedError if encountered. - # - # sample hashes: - # v1.0: '$argon2i$m=512,t=2,p=2$5VtWOO3cGWYQHEMaYGbsfQ$AcmqasQgW/wI6wAHAMk4aQ' - # v1.3: '$argon2i$v=19$m=512,t=2,p=2$5VtWOO3cGWYQHEMaYGbsfQ$AcmqasQgW/wI6wAHAMk4aQ' - - #: regex to parse argon hash - _hash_regex = re.compile(br""" - ^ - \$argon2(?P[a-z]+)\$ - (?: - v=(?P\d+) - \$ - )? - m=(?P\d+) - , - t=(?P\d+) - , - p=(?P\d+) - (?: - ,keyid=(?P[^,$]+) - )? - (?: - ,data=(?P[^,$]+) - )? - (?: - \$ - (?P[^$]+) - (?: - \$ - (?P.+) - )? - )? - $ - """, re.X) - - @classmethod - def from_string(cls, hash): - # NOTE: assuming hash will be unicode, or use ascii-compatible encoding. - # TODO: switch to working w/ str or unicode - if isinstance(hash, unicode): - hash = hash.encode("utf-8") - if not isinstance(hash, bytes): - raise exc.ExpectedStringError(hash, "hash") - m = cls._hash_regex.match(hash) - if not m: - raise exc.MalformedHashError(cls) - type, version, memory_cost, time_cost, parallelism, keyid, data, salt, digest = \ - m.group("type", "version", "memory_cost", "time_cost", "parallelism", - "keyid", "data", "salt", "digest") - if keyid: - raise NotImplementedError("argon2 'keyid' parameter not supported") - return cls( - type=type.decode("ascii"), - version=int(version) if version else 0x10, - memory_cost=int(memory_cost), - rounds=int(time_cost), - parallelism=int(parallelism), - salt=b64s_decode(salt) if salt else None, - data=b64s_decode(data) if data else None, - checksum=b64s_decode(digest) if digest else None, - ) - - def to_string(self): - version = self.version - if version == 0x10: - vstr = "" - else: - vstr = "v=%d$" % version - - data = self.data - if data: - kdstr = ",data=" + bascii_to_str(b64s_encode(self.data)) - else: - kdstr = "" - - # NOTE: 'keyid' param currently not supported - return "$argon2%s$%sm=%d,t=%d,p=%d%s$%s$%s" % ( - uascii_to_str(self.type), - vstr, - self.memory_cost, - self.rounds, - self.parallelism, - kdstr, - bascii_to_str(b64s_encode(self.salt)), - bascii_to_str(b64s_encode(self.checksum)), - ) - - #=================================================================== - # init - #=================================================================== - def __init__(self, type=None, type_d=False, version=None, memory_cost=None, data=None, **kwds): - - # handle deprecated kwds - if type_d: - warn('argon2 `type_d=True` keyword is deprecated, and will be removed in passlib 2.0; ' - 'please use ``type="d"`` instead') - assert type is None - type = TYPE_D - - # TODO: factor out variable checksum size support into a mixin. - # set checksum size to specific value before _norm_checksum() is called - checksum = kwds.get("checksum") - if checksum is not None: - self.checksum_size = len(checksum) - - # call parent - super(_Argon2Common, self).__init__(**kwds) - - # init type - if type is None: - assert uh.validate_default_value(self, self.type, self._norm_type, param="type") - else: - self.type = self._norm_type(type) - - # init version - if version is None: - assert uh.validate_default_value(self, self.version, self._norm_version, - param="version") - else: - self.version = self._norm_version(version) - - # init memory cost - if memory_cost is None: - assert uh.validate_default_value(self, self.memory_cost, self._norm_memory_cost, - param="memory_cost") - else: - self.memory_cost = self._norm_memory_cost(memory_cost) - - # init data - if data is None: - assert self.data is None - else: - if not isinstance(data, bytes): - raise uh.exc.ExpectedTypeError(data, "bytes", "data") - self.data = data - - #------------------------------------------------------------------- - # parameter guards - #------------------------------------------------------------------- - - @classmethod - def _norm_type(cls, value): - # type check - if not isinstance(value, unicode): - if PY2 and isinstance(value, bytes): - value = value.decode('ascii') - else: - raise uh.exc.ExpectedTypeError(value, "str", "type") - - # check if type is valid - if value in ALL_TYPES_SET: - return value - - # translate from uppercase - temp = value.lower() - if temp in ALL_TYPES_SET: - return temp - - # failure! - raise ValueError("unknown argon2 hash type: %r" % (value,)) - - @classmethod - def _norm_version(cls, version): - if not isinstance(version, uh.int_types): - raise uh.exc.ExpectedTypeError(version, "integer", "version") - - # minimum valid version - if version < 0x13 and version != 0x10: - raise ValueError("invalid argon2 hash version: %d" % (version,)) - - # check this isn't past backend's max version - backend = cls.get_backend() - if version > cls.max_version: - raise ValueError("%s: hash version 0x%X not supported by %r backend " - "(max version is 0x%X); try updating or switching backends" % - (cls.name, version, backend, cls.max_version)) - return version - - @classmethod - def _norm_memory_cost(cls, memory_cost, relaxed=False): - return uh.norm_integer(cls, memory_cost, min=cls.min_memory_cost, - param="memory_cost", relaxed=relaxed) - - #=================================================================== - # digest calculation - #=================================================================== - - # NOTE: _calc_checksum implemented by backend subclass - - @classmethod - def _get_backend_type(cls, value): - """ - helper to resolve backend constant from type - """ - try: - return cls._backend_type_map[value] - except KeyError: - pass - # XXX: pick better error class? - msg = "unsupported argon2 hash (type %r not supported by %s backend)" % \ - (value, cls.get_backend()) - raise ValueError(msg) - - #=================================================================== - # hash migration - #=================================================================== - - def _calc_needs_update(self, **kwds): - cls = type(self) - if self.type != cls.type: - return True - minver = cls.min_desired_version - if minver is None or minver > cls.max_version: - minver = cls.max_version - if self.version < minver: - # version is too old. - return True - if self.memory_cost != cls.memory_cost: - return True - if self.checksum_size != cls.checksum_size: - return True - return super(_Argon2Common, self)._calc_needs_update(**kwds) - - #=================================================================== - # backend loading - #=================================================================== - - _no_backend_suggestion = " -- recommend you install one (e.g. 'pip install argon2_cffi')" - - @classmethod - def _finalize_backend_mixin(mixin_cls, name, dryrun): - """ - helper called by from backend mixin classes' _load_backend_mixin() -- - invoked after backend imports have been loaded, and performs - feature detection & testing common to all backends. - """ - # check argon2 version - max_version = mixin_cls.max_version - assert isinstance(max_version, int) and max_version >= 0x10 - if max_version < 0x13: - warn("%r doesn't support argon2 v1.3, and should be upgraded" % name, - uh.exc.PasslibSecurityWarning) - - # prefer best available type - for type in ALL_TYPES: - if type in mixin_cls._backend_type_map: - mixin_cls.type = type - break - else: - warn("%r lacks support for all known hash types" % name, uh.exc.PasslibRuntimeWarning) - # NOTE: class will just throw "unsupported argon2 hash" error if they try to use it... - mixin_cls.type = TYPE_ID - - return True - - @classmethod - def _adapt_backend_error(cls, err, hash=None, self=None): - """ - internal helper invoked when backend has hash/verification error; - used to adapt to passlib message. - """ - backend = cls.get_backend() - - # parse hash to throw error if format was invalid, parameter out of range, etc. - if self is None and hash is not None: - self = cls.from_string(hash) - - # check constraints on parsed object - # XXX: could move this to __init__, but not needed by needs_update calls - if self is not None: - self._validate_constraints(self.memory_cost, self.parallelism) - - # as of cffi 16.1, lacks support in hash_secret(), so genhash() will get here. - # as of cffi 16.2, support removed from verify_secret() as well. - if backend == "argon2_cffi" and self.data is not None: - raise NotImplementedError("argon2_cffi backend doesn't support the 'data' parameter") - - # fallback to reporting a malformed hash - text = str(err) - if text not in [ - "Decoding failed" # argon2_cffi's default message - ]: - reason = "%s reported: %s: hash=%r" % (backend, text, hash) - else: - reason = repr(hash) - raise exc.MalformedHashError(cls, reason=reason) - - #=================================================================== - # eoc - #=================================================================== - -#----------------------------------------------------------------------- -# stub backend -#----------------------------------------------------------------------- -class _NoBackend(_Argon2Common): - """ - mixin used before any backend has been loaded. - contains stubs that force loading of one of the available backends. - """ - #=================================================================== - # primary methods - #=================================================================== - @classmethod - def hash(cls, secret): - cls._stub_requires_backend() - return cls.hash(secret) - - @classmethod - def verify(cls, secret, hash): - cls._stub_requires_backend() - return cls.verify(secret, hash) - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genhash(cls, secret, config): - cls._stub_requires_backend() - return cls.genhash(secret, config) - - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - # NOTE: since argon2_cffi takes care of rendering hash, - # _calc_checksum() is only used by the argon2pure backend. - self._stub_requires_backend() - # NOTE: have to use super() here so that we don't recursively - # call subclass's wrapped _calc_checksum - return super(argon2, self)._calc_checksum(secret) - - #=================================================================== - # eoc - #=================================================================== - -#----------------------------------------------------------------------- -# argon2_cffi backend -#----------------------------------------------------------------------- -class _CffiBackend(_Argon2Common): - """ - argon2_cffi backend - """ - #=================================================================== - # backend loading - #=================================================================== - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # make sure we write info to base class's __dict__, not that of a subclass - assert mixin_cls is _CffiBackend - - # we automatically import this at top, so just grab info - if _argon2_cffi is None: - if _argon2_cffi_error: - raise exc.PasslibSecurityError(_argon2_cffi_error) - return False - max_version = _argon2_cffi.low_level.ARGON2_VERSION - log.debug("detected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashes", - _argon2_cffi.__version__, max_version) - - # build type map - TypeEnum = _argon2_cffi.Type - type_map = {} - for type in ALL_TYPES: - try: - type_map[type] = getattr(TypeEnum, type.upper()) - except AttributeError: - # TYPE_ID support not added until v18.2 - assert type not in (TYPE_I, TYPE_D), "unexpected missing type: %r" % type - mixin_cls._backend_type_map = type_map - - # set version info, and run common setup - mixin_cls.version = mixin_cls.max_version = max_version - return mixin_cls._finalize_backend_mixin(name, dryrun) - - #=================================================================== - # primary methods - #=================================================================== - @classmethod - def hash(cls, secret): - # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. - uh.validate_secret(secret) - secret = to_bytes(secret, "utf-8") - # XXX: doesn't seem to be a way to make this honor max_threads - try: - return bascii_to_str(_argon2_cffi.low_level.hash_secret( - type=cls._get_backend_type(cls.type), - memory_cost=cls.memory_cost, - time_cost=cls.default_rounds, - parallelism=cls.parallelism, - salt=to_bytes(cls._generate_salt()), - hash_len=cls.checksum_size, - secret=secret, - )) - except _argon2_cffi.exceptions.HashingError as err: - raise cls._adapt_backend_error(err) - - #: helper for verify() method below -- maps prefixes to type constants - _byte_ident_map = dict((render_bytes(b"$argon2%s$", type.encode("ascii")), type) - for type in ALL_TYPES) - - @classmethod - def verify(cls, secret, hash): - # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. - uh.validate_secret(secret) - secret = to_bytes(secret, "utf-8") - hash = to_bytes(hash, "ascii") - - # read type from start of hash - # NOTE: don't care about malformed strings, lowlevel will throw error for us - type = cls._byte_ident_map.get(hash[:1+hash.find(b"$", 1)], TYPE_I) - type_code = cls._get_backend_type(type) - - # XXX: doesn't seem to be a way to make this honor max_threads - try: - result = _argon2_cffi.low_level.verify_secret(hash, secret, type_code) - assert result is True - return True - except _argon2_cffi.exceptions.VerifyMismatchError: - return False - except _argon2_cffi.exceptions.VerificationError as err: - raise cls._adapt_backend_error(err, hash=hash) - - # NOTE: deprecated, will be removed in 2.0 - @classmethod - def genhash(cls, secret, config): - # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. - uh.validate_secret(secret) - secret = to_bytes(secret, "utf-8") - self = cls.from_string(config) - # XXX: doesn't seem to be a way to make this honor max_threads - try: - result = bascii_to_str(_argon2_cffi.low_level.hash_secret( - type=cls._get_backend_type(self.type), - memory_cost=self.memory_cost, - time_cost=self.rounds, - parallelism=self.parallelism, - salt=to_bytes(self.salt), - hash_len=self.checksum_size, - secret=secret, - version=self.version, - )) - except _argon2_cffi.exceptions.HashingError as err: - raise cls._adapt_backend_error(err, hash=config) - if self.version == 0x10: - # workaround: argon2 0x13 always returns "v=" segment, even for 0x10 hashes - result = result.replace("$v=16$", "$") - return result - - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - raise AssertionError("shouldn't be called under argon2_cffi backend") - - #=================================================================== - # eoc - #=================================================================== - -#----------------------------------------------------------------------- -# argon2pure backend -#----------------------------------------------------------------------- -class _PureBackend(_Argon2Common): - """ - argon2pure backend - """ - #=================================================================== - # backend loading - #=================================================================== - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # make sure we write info to base class's __dict__, not that of a subclass - assert mixin_cls is _PureBackend - - # import argon2pure - global _argon2pure - try: - import argon2pure as _argon2pure - except ImportError: - return False - - # get default / max supported version -- added in v1.2.2 - try: - from argon2pure import ARGON2_DEFAULT_VERSION as max_version - except ImportError: - log.warning("detected 'argon2pure' backend, but package is too old " - "(passlib requires argon2pure >= 1.2.3)") - return False - - log.debug("detected 'argon2pure' backend, with support for 0x%x argon2 hashes", - max_version) - - if not dryrun: - warn("Using argon2pure backend, which is 100x+ slower than is required " - "for adequate security. Installing argon2_cffi (via 'pip install argon2_cffi') " - "is strongly recommended", exc.PasslibSecurityWarning) - - # build type map - type_map = {} - for type in ALL_TYPES: - try: - type_map[type] = getattr(_argon2pure, "ARGON2" + type.upper()) - except AttributeError: - # TYPE_ID support not added until v1.3 - assert type not in (TYPE_I, TYPE_D), "unexpected missing type: %r" % type - mixin_cls._backend_type_map = type_map - - mixin_cls.version = mixin_cls.max_version = max_version - return mixin_cls._finalize_backend_mixin(name, dryrun) - - #=================================================================== - # primary methods - #=================================================================== - - # NOTE: this backend uses default .hash() & .verify() implementations. - - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9. - uh.validate_secret(secret) - secret = to_bytes(secret, "utf-8") - kwds = dict( - password=secret, - salt=self.salt, - time_cost=self.rounds, - memory_cost=self.memory_cost, - parallelism=self.parallelism, - tag_length=self.checksum_size, - type_code=self._get_backend_type(self.type), - version=self.version, - ) - if self.max_threads > 0: - kwds['threads'] = self.max_threads - if self.pure_use_threads: - kwds['use_threads'] = True - if self.data: - kwds['associated_data'] = self.data - # NOTE: should return raw bytes - # NOTE: this may raise _argon2pure.Argon2ParameterError, - # but it if does that, there's a bug in our own parameter checking code. - try: - return _argon2pure.argon2(**kwds) - except _argon2pure.Argon2Error as err: - raise self._adapt_backend_error(err, self=self) - - #=================================================================== - # eoc - #=================================================================== - -class argon2(_NoBackend, _Argon2Common): - """ - This class implements the Argon2 password hash [#argon2-home]_, and follows the :ref:`password-hash-api`. - - Argon2 supports a variable-length salt, and variable time & memory cost, - and a number of other configurable parameters. - - The :meth:`~passlib.ifc.PasswordHash.replace` method accepts the following optional keywords: - - :type type: str - :param type: - Specify the type of argon2 hash to generate. - Can be one of "ID", "I", "D". - - This defaults to "ID" if supported by the backend, otherwise "I". - - :type salt: str - :param salt: - Optional salt string. - If specified, the length must be between 0-1024 bytes. - If not specified, one will be auto-generated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - This corresponds linearly to the amount of time hashing will take. - - :type time_cost: int - :param time_cost: - An alias for **rounds**, for compatibility with underlying argon2 library. - - :param int memory_cost: - Defines the memory usage in kibibytes. - This corresponds linearly to the amount of memory hashing will take. - - :param int parallelism: - Defines the parallelization factor. - *NOTE: this will affect the resulting hash value.* - - :param int digest_size: - Length of the digest in bytes. - - :param int max_threads: - Maximum number of threads that will be used. - -1 means unlimited; otherwise hashing will use ``min(parallelism, max_threads)`` threads. - - .. note:: - - This option is currently only honored by the argon2pure backend. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionchanged:: 1.7.2 - - Added the "type" keyword, and support for type "D" and "ID" hashes. - (Prior versions could verify type "D" hashes, but not generate them). - - .. todo:: - - * Support configurable threading limits. - """ - #============================================================================= - # backend - #============================================================================= - - # NOTE: the brunt of the argon2 class is implemented in _Argon2Common. - # there are then subclass for each backend (e.g. _PureBackend), - # these are dynamically prepended to this class's bases - # in order to load the appropriate backend. - - #: list of potential backends - backends = ("argon2_cffi", "argon2pure") - - #: flag that this class's bases should be modified by SubclassBackendMixin - _backend_mixin_target = True - - #: map of backend -> mixin class, used by _get_backend_loader() - _backend_mixin_map = { - None: _NoBackend, - "argon2_cffi": _CffiBackend, - "argon2pure": _PureBackend, - } - - #============================================================================= - # - #============================================================================= - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/bcrypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/bcrypt.py deleted file mode 100644 index b83b110..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/bcrypt.py +++ /dev/null @@ -1,1243 +0,0 @@ -"""passlib.bcrypt -- implementation of OpenBSD's BCrypt algorithm. - -TODO: - -* support 2x and altered-2a hashes? - http://www.openwall.com/lists/oss-security/2011/06/27/9 - -* deal with lack of PY3-compatibile c-ext implementation -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, absolute_import -# core -from base64 import b64encode -from hashlib import sha256 -import os -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -_bcrypt = None # dynamically imported by _load_backend_bcrypt() -_pybcrypt = None # dynamically imported by _load_backend_pybcrypt() -_bcryptor = None # dynamically imported by _load_backend_bcryptor() -# pkg -_builtin_bcrypt = None # dynamically imported by _load_backend_builtin() -from passlib.crypto.digest import compile_hmac -from passlib.exc import PasslibHashWarning, PasslibSecurityWarning, PasslibSecurityError -from passlib.utils import safe_crypt, repeat_string, to_bytes, parse_version, \ - rng, getrandstr, test_crypt, to_unicode, \ - utf8_truncate, utf8_repeat_string, crypt_accepts_bytes -from passlib.utils.binary import bcrypt64 -from passlib.utils.compat import get_unbound_method_function -from passlib.utils.compat import u, uascii_to_str, unicode, str_to_uascii, PY3, error_from -import passlib.utils.handlers as uh - -# local -__all__ = [ - "bcrypt", -] - -#============================================================================= -# support funcs & constants -#============================================================================= -IDENT_2 = u("$2$") -IDENT_2A = u("$2a$") -IDENT_2X = u("$2x$") -IDENT_2Y = u("$2y$") -IDENT_2B = u("$2b$") -_BNULL = b'\x00' - -# reference hash of "test", used in various self-checks -TEST_HASH_2A = "$2a$04$5BJqKfqMQvV7nS.yUguNcueVirQqDBGaLXSqj.rs.pZPlNR0UX/HK" - -def _detect_pybcrypt(): - """ - internal helper which tries to distinguish pybcrypt vs bcrypt. - - :returns: - True if cext-based py-bcrypt, - False if ffi-based bcrypt, - None if 'bcrypt' module not found. - - .. versionchanged:: 1.6.3 - - Now assuming bcrypt installed, unless py-bcrypt explicitly detected. - Previous releases assumed py-bcrypt by default. - - Making this change since py-bcrypt is (apparently) unmaintained and static, - whereas bcrypt is being actively maintained, and it's internal structure may shift. - """ - # NOTE: this is also used by the unittests. - - # check for module. - try: - import bcrypt - except ImportError: - # XXX: this is ignoring case where py-bcrypt's "bcrypt._bcrypt" C Ext fails to import; - # would need to inspect actual ImportError message to catch that. - return None - - # py-bcrypt has a "._bcrypt.__version__" attribute (confirmed for v0.1 - 0.4), - # which bcrypt lacks (confirmed for v1.0 - 2.0) - # "._bcrypt" alone isn't sufficient, since bcrypt 2.0 now has that attribute. - try: - from bcrypt._bcrypt import __version__ - except ImportError: - return False - return True - -#============================================================================= -# backend mixins -#============================================================================= -class _BcryptCommon(uh.SubclassBackendMixin, uh.TruncateMixin, uh.HasManyIdents, - uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """ - Base class which implements brunt of BCrypt code. - This is then subclassed by the various backends, - to override w/ backend-specific methods. - - When a backend is loaded, the bases of the 'bcrypt' class proper - are modified to prepend the correct backend-specific subclass. - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "bcrypt" - setting_kwds = ("salt", "rounds", "ident", "truncate_error") - - #-------------------- - # GenericHandler - #-------------------- - checksum_size = 31 - checksum_chars = bcrypt64.charmap - - #-------------------- - # HasManyIdents - #-------------------- - default_ident = IDENT_2B - ident_values = (IDENT_2, IDENT_2A, IDENT_2X, IDENT_2Y, IDENT_2B) - ident_aliases = {u("2"): IDENT_2, u("2a"): IDENT_2A, u("2y"): IDENT_2Y, - u("2b"): IDENT_2B} - - #-------------------- - # HasSalt - #-------------------- - min_salt_size = max_salt_size = 22 - salt_chars = bcrypt64.charmap - - # NOTE: 22nd salt char must be in restricted set of ``final_salt_chars``, not full set above. - final_salt_chars = ".Oeu" # bcrypt64._padinfo2[1] - - #-------------------- - # HasRounds - #-------------------- - default_rounds = 12 # current passlib default - min_rounds = 4 # minimum from bcrypt specification - max_rounds = 31 # 32-bit integer limit (since real_rounds=1< class - - # NOTE: set_backend() will execute the ._load_backend_mixin() - # of the matching mixin class, which will handle backend detection - - # appended to HasManyBackends' "no backends available" error message - _no_backend_suggestion = " -- recommend you install one (e.g. 'pip install bcrypt')" - - @classmethod - def _finalize_backend_mixin(mixin_cls, backend, dryrun): - """ - helper called by from backend mixin classes' _load_backend_mixin() -- - invoked after backend imports have been loaded, and performs - feature detection & testing common to all backends. - """ - #---------------------------------------------------------------- - # setup helpers - #---------------------------------------------------------------- - assert mixin_cls is bcrypt._backend_mixin_map[backend], \ - "_configure_workarounds() invoked from wrong class" - - if mixin_cls._workrounds_initialized: - return True - - verify = mixin_cls.verify - - err_types = (ValueError, uh.exc.MissingBackendError) - if _bcryptor: - err_types += (_bcryptor.engine.SaltError,) - - def safe_verify(secret, hash): - """verify() wrapper which traps 'unknown identifier' errors""" - try: - return verify(secret, hash) - except err_types: - # backends without support for given ident will throw various - # errors about unrecognized version: - # os_crypt -- internal code below throws - # - PasswordValueError if there's encoding issue w/ password. - # - InternalBackendError if crypt fails for unknown reason - # (trapped below so we can debug it) - # pybcrypt, bcrypt -- raises ValueError - # bcryptor -- raises bcryptor.engine.SaltError - return NotImplemented - except uh.exc.InternalBackendError: - # _calc_checksum() code may also throw CryptBackendError - # if correct hash isn't returned (e.g. 2y hash converted to 2b, - # such as happens with bcrypt 3.0.0) - log.debug("trapped unexpected response from %r backend: verify(%r, %r):", - backend, secret, hash, exc_info=True) - return NotImplemented - - def assert_lacks_8bit_bug(ident): - """ - helper to check for cryptblowfish 8bit bug (fixed in 2y/2b); - even though it's not known to be present in any of passlib's backends. - this is treated as FATAL, because it can easily result in seriously malformed hashes, - and we can't correct for it ourselves. - - test cases from - reference hash is the incorrectly generated $2x$ hash taken from above url - """ - # NOTE: passlib 1.7.2 and earlier used the commented-out LATIN-1 test vector to detect - # this bug; but python3's crypt.crypt() only supports unicode inputs (and - # always encodes them as UTF8 before passing to crypt); so passlib 1.7.3 - # switched to the UTF8-compatible test vector below. This one's bug_hash value - # ("$2x$...rcAS") was drawn from the same openwall source (above); and the correct - # hash ("$2a$...X6eu") was generated by passing the raw bytes to python2's - # crypt.crypt() using OpenBSD 6.7 (hash confirmed as same for $2a$ & $2b$). - - # LATIN-1 test vector - # secret = b"\xA3" - # bug_hash = ident.encode("ascii") + b"05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e" - # correct_hash = ident.encode("ascii") + b"05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq" - - # UTF-8 test vector - secret = b"\xd1\x91" # aka "\u0451" - bug_hash = ident.encode("ascii") + b"05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS" - correct_hash = ident.encode("ascii") + b"05$6bNw2HLQYeqHYyBfLMsv/OUcZd0LKP39b87nBw3.S2tVZSqiQX6eu" - - if verify(secret, bug_hash): - # NOTE: this only EVER be observed in (broken) 2a and (backward-compat) 2x hashes - # generated by crypt_blowfish library. 2y/2b hashes should not have the bug - # (but we check w/ them anyways). - raise PasslibSecurityError( - "passlib.hash.bcrypt: Your installation of the %r backend is vulnerable to " - "the crypt_blowfish 8-bit bug (CVE-2011-2483) under %r hashes, " - "and should be upgraded or replaced with another backend" % (backend, ident)) - - # it doesn't have wraparound bug, but make sure it *does* verify against the correct - # hash, or we're in some weird third case! - if not verify(secret, correct_hash): - raise RuntimeError("%s backend failed to verify %s 8bit hash" % (backend, ident)) - - def detect_wrap_bug(ident): - """ - check for bsd wraparound bug (fixed in 2b) - this is treated as a warning, because it's rare in the field, - and pybcrypt (as of 2015-7-21) is unpatched, but some people may be stuck with it. - - test cases from - - NOTE: reference hash is of password "0"*72 - - NOTE: if in future we need to deliberately create hashes which have this bug, - can use something like 'hashpw(repeat_string(secret[:((1+secret) % 256) or 1]), 72)' - """ - # check if it exhibits wraparound bug - secret = (b"0123456789"*26)[:255] - bug_hash = ident.encode("ascii") + b"04$R1lJ2gkNaoPGdafE.H.16.nVyh2niHsGJhayOHLMiXlI45o8/DU.6" - if verify(secret, bug_hash): - return True - - # if it doesn't have wraparound bug, make sure it *does* handle things - # correctly -- or we're in some weird third case. - correct_hash = ident.encode("ascii") + b"04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi" - if not verify(secret, correct_hash): - raise RuntimeError("%s backend failed to verify %s wraparound hash" % (backend, ident)) - - return False - - def assert_lacks_wrap_bug(ident): - if not detect_wrap_bug(ident): - return - # should only see in 2a, later idents should NEVER exhibit this bug: - # * 2y implementations should have been free of it - # * 2b was what (supposedly) fixed it - raise RuntimeError("%s backend unexpectedly has wraparound bug for %s" % (backend, ident)) - - #---------------------------------------------------------------- - # check for old 20 support - #---------------------------------------------------------------- - test_hash_20 = b"$2$04$5BJqKfqMQvV7nS.yUguNcuRfMMOXK0xPWavM7pOzjEi5ze5T1k8/S" - result = safe_verify("test", test_hash_20) - if result is NotImplemented: - mixin_cls._lacks_20_support = True - log.debug("%r backend lacks $2$ support, enabling workaround", backend) - elif not result: - raise RuntimeError("%s incorrectly rejected $2$ hash" % backend) - - #---------------------------------------------------------------- - # check for 2a support - #---------------------------------------------------------------- - result = safe_verify("test", TEST_HASH_2A) - if result is NotImplemented: - # 2a support is required, and should always be present - raise RuntimeError("%s lacks support for $2a$ hashes" % backend) - elif not result: - raise RuntimeError("%s incorrectly rejected $2a$ hash" % backend) - else: - assert_lacks_8bit_bug(IDENT_2A) - if detect_wrap_bug(IDENT_2A): - if backend == "os_crypt": - # don't make this a warning for os crypt (e.g. openbsd); - # they'll have proper 2b implementation which will be used for new hashes. - # so even if we didn't have a workaround, this bug wouldn't be a concern. - log.debug("%r backend has $2a$ bsd wraparound bug, enabling workaround", backend) - else: - # installed library has the bug -- want to let users know, - # so they can upgrade it to something better (e.g. bcrypt cffi library) - warn("passlib.hash.bcrypt: Your installation of the %r backend is vulnerable to " - "the bsd wraparound bug, " - "and should be upgraded or replaced with another backend " - "(enabling workaround for now)." % backend, - uh.exc.PasslibSecurityWarning) - mixin_cls._has_2a_wraparound_bug = True - - #---------------------------------------------------------------- - # check for 2y support - #---------------------------------------------------------------- - test_hash_2y = TEST_HASH_2A.replace("2a", "2y") - result = safe_verify("test", test_hash_2y) - if result is NotImplemented: - mixin_cls._lacks_2y_support = True - log.debug("%r backend lacks $2y$ support, enabling workaround", backend) - elif not result: - raise RuntimeError("%s incorrectly rejected $2y$ hash" % backend) - else: - # NOTE: Not using this as fallback candidate, - # lacks wide enough support across implementations. - assert_lacks_8bit_bug(IDENT_2Y) - assert_lacks_wrap_bug(IDENT_2Y) - - #---------------------------------------------------------------- - # TODO: check for 2x support - #---------------------------------------------------------------- - - #---------------------------------------------------------------- - # check for 2b support - #---------------------------------------------------------------- - test_hash_2b = TEST_HASH_2A.replace("2a", "2b") - result = safe_verify("test", test_hash_2b) - if result is NotImplemented: - mixin_cls._lacks_2b_support = True - log.debug("%r backend lacks $2b$ support, enabling workaround", backend) - elif not result: - raise RuntimeError("%s incorrectly rejected $2b$ hash" % backend) - else: - mixin_cls._fallback_ident = IDENT_2B - assert_lacks_8bit_bug(IDENT_2B) - assert_lacks_wrap_bug(IDENT_2B) - - # set flag so we don't have to run this again - mixin_cls._workrounds_initialized = True - return True - - #=================================================================== - # digest calculation - #=================================================================== - - # _calc_checksum() defined by backends - - def _prepare_digest_args(self, secret): - """ - common helper for backends to implement _calc_checksum(). - takes in secret, returns (secret, ident) pair, - """ - return self._norm_digest_args(secret, self.ident, new=self.use_defaults) - - @classmethod - def _norm_digest_args(cls, secret, ident, new=False): - # make sure secret is unicode - require_valid_utf8_bytes = cls._require_valid_utf8_bytes - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - elif require_valid_utf8_bytes: - # if backend requires utf8 bytes (os_crypt); - # make sure input actually is utf8, or don't bother enabling utf-8 specific helpers. - try: - secret.decode("utf-8") - except UnicodeDecodeError: - # XXX: could just throw PasswordValueError here, backend will just do that - # when _calc_digest() is actually called. - require_valid_utf8_bytes = False - - # check max secret size - uh.validate_secret(secret) - - # check for truncation (during .hash() calls only) - if new: - cls._check_truncate_policy(secret) - - # NOTE: especially important to forbid NULLs for bcrypt, since many - # backends (bcryptor, bcrypt) happily accept them, and then - # silently truncate the password at first NULL they encounter! - if _BNULL in secret: - raise uh.exc.NullPasswordError(cls) - - # TODO: figure out way to skip these tests when not needed... - - # protect from wraparound bug by truncating secret before handing it to the backend. - # bcrypt only uses first 72 bytes anyways. - # NOTE: not needed for 2y/2b, but might use 2a as fallback for them. - if cls._has_2a_wraparound_bug and len(secret) >= 255: - if require_valid_utf8_bytes: - # backend requires valid utf8 bytes, so truncate secret to nearest valid segment. - # want to do this in constant time to not give away info about secret. - # NOTE: this only works because bcrypt will ignore everything past - # secret[71], so padding to include a full utf8 sequence - # won't break anything about the final output. - secret = utf8_truncate(secret, 72) - else: - secret = secret[:72] - - # special case handling for variants (ordered most common first) - if ident == IDENT_2A: - # nothing needs to be done. - pass - - elif ident == IDENT_2B: - if cls._lacks_2b_support: - # handle $2b$ hash format even if backend is too old. - # have it generate a 2A/2Y digest, then return it as a 2B hash. - # 2a-only backend could potentially exhibit wraparound bug -- - # but we work around that issue above. - ident = cls._fallback_ident - - elif ident == IDENT_2Y: - if cls._lacks_2y_support: - # handle $2y$ hash format (not supported by BSDs, being phased out on others) - # have it generate a 2A/2B digest, then return it as a 2Y hash. - ident = cls._fallback_ident - - elif ident == IDENT_2: - if cls._lacks_20_support: - # handle legacy $2$ format (not supported by most backends except BSD os_crypt) - # we can fake $2$ behavior using the 2A/2Y/2B algorithm - # by repeating the password until it's at least 72 chars in length. - if secret: - if require_valid_utf8_bytes: - # NOTE: this only works because bcrypt will ignore everything past - # secret[71], so padding to include a full utf8 sequence - # won't break anything about the final output. - secret = utf8_repeat_string(secret, 72) - else: - secret = repeat_string(secret, 72) - ident = cls._fallback_ident - - elif ident == IDENT_2X: - - # NOTE: shouldn't get here. - # XXX: could check if backend does actually offer 'support' - raise RuntimeError("$2x$ hashes not currently supported by passlib") - - else: - raise AssertionError("unexpected ident value: %r" % ident) - - return secret, ident - -#----------------------------------------------------------------------- -# stub backend -#----------------------------------------------------------------------- -class _NoBackend(_BcryptCommon): - """ - mixin used before any backend has been loaded. - contains stubs that force loading of one of the available backends. - """ - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - self._stub_requires_backend() - # NOTE: have to use super() here so that we don't recursively - # call subclass's wrapped _calc_checksum, e.g. bcrypt_sha256._calc_checksum - return super(bcrypt, self)._calc_checksum(secret) - - #=================================================================== - # eoc - #=================================================================== - -#----------------------------------------------------------------------- -# bcrypt backend -#----------------------------------------------------------------------- -class _BcryptBackend(_BcryptCommon): - """ - backend which uses 'bcrypt' package - """ - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # try to import bcrypt - global _bcrypt - if _detect_pybcrypt(): - # pybcrypt was installed instead - return False - try: - import bcrypt as _bcrypt - except ImportError: # pragma: no cover - return False - try: - version = _bcrypt.__about__.__version__ - except: - log.warning("(trapped) error reading bcrypt version", exc_info=True) - version = '' - - log.debug("detected 'bcrypt' backend, version %r", version) - return mixin_cls._finalize_backend_mixin(name, dryrun) - - # # TODO: would like to implementing verify() directly, - # # to skip need for parsing hash strings. - # # below method has a few edge cases where it chokes though. - # @classmethod - # def verify(cls, secret, hash): - # if isinstance(hash, unicode): - # hash = hash.encode("ascii") - # ident = hash[:hash.index(b"$", 1)+1].decode("ascii") - # if ident not in cls.ident_values: - # raise uh.exc.InvalidHashError(cls) - # secret, eff_ident = cls._norm_digest_args(secret, ident) - # if eff_ident != ident: - # # lacks support for original ident, replace w/ new one. - # hash = eff_ident.encode("ascii") + hash[len(ident):] - # result = _bcrypt.hashpw(secret, hash) - # assert result.startswith(eff_ident) - # return consteq(result, hash) - - def _calc_checksum(self, secret): - # bcrypt behavior: - # secret must be bytes - # config must be ascii bytes - # returns ascii bytes - secret, ident = self._prepare_digest_args(secret) - config = self._get_config(ident) - if isinstance(config, unicode): - config = config.encode("ascii") - hash = _bcrypt.hashpw(secret, config) - assert isinstance(hash, bytes) - if not hash.startswith(config) or len(hash) != len(config)+31: - raise uh.exc.CryptBackendError(self, config, hash, source="`bcrypt` package") - return hash[-31:].decode("ascii") - -#----------------------------------------------------------------------- -# bcryptor backend -#----------------------------------------------------------------------- -class _BcryptorBackend(_BcryptCommon): - """ - backend which uses 'bcryptor' package - """ - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # try to import bcryptor - global _bcryptor - try: - import bcryptor as _bcryptor - except ImportError: # pragma: no cover - return False - - # deprecated as of 1.7.2 - if not dryrun: - warn("Support for `bcryptor` is deprecated, and will be removed in Passlib 1.8; " - "Please use `pip install bcrypt` instead", DeprecationWarning) - - return mixin_cls._finalize_backend_mixin(name, dryrun) - - def _calc_checksum(self, secret): - # bcryptor behavior: - # py2: unicode secret/hash encoded as ascii bytes before use, - # bytes taken as-is; returns ascii bytes. - # py3: not supported - secret, ident = self._prepare_digest_args(secret) - config = self._get_config(ident) - hash = _bcryptor.engine.Engine(False).hash_key(secret, config) - if not hash.startswith(config) or len(hash) != len(config) + 31: - raise uh.exc.CryptBackendError(self, config, hash, source="bcryptor library") - return str_to_uascii(hash[-31:]) - -#----------------------------------------------------------------------- -# pybcrypt backend -#----------------------------------------------------------------------- -class _PyBcryptBackend(_BcryptCommon): - """ - backend which uses 'pybcrypt' package - """ - - #: classwide thread lock used for pybcrypt < 0.3 - _calc_lock = None - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # try to import pybcrypt - global _pybcrypt - if not _detect_pybcrypt(): - # not installed, or bcrypt installed instead - return False - try: - import bcrypt as _pybcrypt - except ImportError: # pragma: no cover - # XXX: should we raise AssertionError here? (if get here, _detect_pybcrypt() is broken) - return False - - # deprecated as of 1.7.2 - if not dryrun: - warn("Support for `py-bcrypt` is deprecated, and will be removed in Passlib 1.8; " - "Please use `pip install bcrypt` instead", DeprecationWarning) - - # determine pybcrypt version - try: - version = _pybcrypt._bcrypt.__version__ - except: - log.warning("(trapped) error reading pybcrypt version", exc_info=True) - version = "" - log.debug("detected 'pybcrypt' backend, version %r", version) - - # return calc function based on version - vinfo = parse_version(version) or (0, 0) - if vinfo < (0, 3): - warn("py-bcrypt %s has a major security vulnerability, " - "you should upgrade to py-bcrypt 0.3 immediately." - % version, uh.exc.PasslibSecurityWarning) - if mixin_cls._calc_lock is None: - import threading - mixin_cls._calc_lock = threading.Lock() - mixin_cls._calc_checksum = get_unbound_method_function(mixin_cls._calc_checksum_threadsafe) - - return mixin_cls._finalize_backend_mixin(name, dryrun) - - def _calc_checksum_threadsafe(self, secret): - # as workaround for pybcrypt < 0.3's concurrency issue, - # we wrap everything in a thread lock. as long as bcrypt is only - # used through passlib, this should be safe. - with self._calc_lock: - return self._calc_checksum_raw(secret) - - def _calc_checksum_raw(self, secret): - # py-bcrypt behavior: - # py2: unicode secret/hash encoded as ascii bytes before use, - # bytes taken as-is; returns ascii bytes. - # py3: unicode secret encoded as utf-8 bytes, - # hash encoded as ascii bytes, returns ascii unicode. - secret, ident = self._prepare_digest_args(secret) - config = self._get_config(ident) - hash = _pybcrypt.hashpw(secret, config) - if not hash.startswith(config) or len(hash) != len(config) + 31: - raise uh.exc.CryptBackendError(self, config, hash, source="pybcrypt library") - return str_to_uascii(hash[-31:]) - - _calc_checksum = _calc_checksum_raw - -#----------------------------------------------------------------------- -# os crypt backend -#----------------------------------------------------------------------- -class _OsCryptBackend(_BcryptCommon): - """ - backend which uses :func:`crypt.crypt` - """ - - #: set flag to ensure _prepare_digest_args() doesn't create invalid utf8 string - #: when truncating bytes. - _require_valid_utf8_bytes = not crypt_accepts_bytes - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - if not test_crypt("test", TEST_HASH_2A): - return False - return mixin_cls._finalize_backend_mixin(name, dryrun) - - def _calc_checksum(self, secret): - # - # run secret through crypt.crypt(). - # if everything goes right, we'll get back a properly formed bcrypt hash. - # - secret, ident = self._prepare_digest_args(secret) - config = self._get_config(ident) - hash = safe_crypt(secret, config) - if hash is not None: - if not hash.startswith(config) or len(hash) != len(config) + 31: - raise uh.exc.CryptBackendError(self, config, hash) - return hash[-31:] - - # - # Check if this failed due to non-UTF8 bytes - # In detail: under py3, crypt.crypt() requires unicode inputs, which are then encoded to - # utf8 before passing them to os crypt() call. this is done according to the "s" format - # specifier for PyArg_ParseTuple (https://docs.python.org/3/c-api/arg.html). - # There appears no way to get around that to pass raw bytes; so we just throw error here - # to let user know they need to use another backend if they want raw bytes support. - # - # XXX: maybe just let safe_crypt() throw UnicodeDecodeError under passlib 2.0, - # and then catch it above? maybe have safe_crypt ALWAYS throw error - # instead of returning None? (would save re-detecting what went wrong) - # XXX: isn't secret ALWAYS bytes at this point? - # - if PY3 and isinstance(secret, bytes): - try: - secret.decode("utf-8") - except UnicodeDecodeError: - raise error_from(uh.exc.PasswordValueError( - "python3 crypt.crypt() ony supports bytes passwords using UTF8; " - "passlib recommends running `pip install bcrypt` for general bcrypt support.", - ), None) - - # - # else crypt() call failed for unknown reason. - # - # NOTE: getting here should be considered a bug in passlib -- - # if os_crypt backend detection said there's support, - # and we've already checked all known reasons above; - # want them to file bug so we can figure out what happened. - # in the meantime, users can avoid this by installing bcrypt-cffi backend; - # which won't have this (or utf8) edgecases. - # - # XXX: throw something more specific, like an "InternalBackendError"? - # NOTE: if do change this error, need to update test_81_crypt_fallback() expectations - # about what will be thrown; as well as safe_verify() above. - # - debug_only_repr = uh.exc.debug_only_repr - raise uh.exc.InternalBackendError( - "crypt.crypt() failed for unknown reason; " - "passlib recommends running `pip install bcrypt` for general bcrypt support." - # for debugging UTs -- - "(config=%s, secret=%s)" % (debug_only_repr(config), debug_only_repr(secret)), - ) - -#----------------------------------------------------------------------- -# builtin backend -#----------------------------------------------------------------------- -class _BuiltinBackend(_BcryptCommon): - """ - backend which uses passlib's pure-python implementation - """ - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - from passlib.utils import as_bool - if not as_bool(os.environ.get("PASSLIB_BUILTIN_BCRYPT")): - log.debug("bcrypt 'builtin' backend not enabled via $PASSLIB_BUILTIN_BCRYPT") - return False - global _builtin_bcrypt - from passlib.crypto._blowfish import raw_bcrypt as _builtin_bcrypt - return mixin_cls._finalize_backend_mixin(name, dryrun) - - def _calc_checksum(self, secret): - secret, ident = self._prepare_digest_args(secret) - chk = _builtin_bcrypt(secret, ident[1:-1], - self.salt.encode("ascii"), self.rounds) - return chk.decode("ascii") - -#============================================================================= -# handler -#============================================================================= -class bcrypt(_NoBackend, _BcryptCommon): - """This class implements the BCrypt password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 22 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 12, must be between 4 and 31, inclusive. - This value is logarithmic, the actual number of iterations used will be :samp:`2**{rounds}` - -- increasing the rounds by +1 will double the amount of time taken. - - :type ident: str - :param ident: - Specifies which version of the BCrypt algorithm will be used when creating a new hash. - Typically this option is not needed, as the default (``"2b"``) is usually the correct choice. - If specified, it must be one of the following: - - * ``"2"`` - the first revision of BCrypt, which suffers from a minor security flaw and is generally not used anymore. - * ``"2a"`` - some implementations suffered from rare security flaws, replaced by 2b. - * ``"2y"`` - format specific to the *crypt_blowfish* BCrypt implementation, - identical to ``"2b"`` in all but name. - * ``"2b"`` - latest revision of the official BCrypt algorithm, current default. - - :param bool truncate_error: - By default, BCrypt will silently truncate passwords larger than 72 bytes. - Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash` - to raise a :exc:`~passlib.exc.PasswordTruncateError` instead. - - .. versionadded:: 1.7 - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. versionchanged:: 1.6 - This class now supports ``"2y"`` hashes, and recognizes - (but does not support) the broken ``"2x"`` hashes. - (see the :ref:`crypt_blowfish bug ` - for details). - - .. versionchanged:: 1.6 - Added a pure-python backend. - - .. versionchanged:: 1.6.3 - - Added support for ``"2b"`` variant. - - .. versionchanged:: 1.7 - - Now defaults to ``"2b"`` variant. - """ - #============================================================================= - # backend - #============================================================================= - - # NOTE: the brunt of the bcrypt class is implemented in _BcryptCommon. - # there are then subclass for each backend (e.g. _PyBcryptBackend), - # these are dynamically prepended to this class's bases - # in order to load the appropriate backend. - - #: list of potential backends - backends = ("bcrypt", "pybcrypt", "bcryptor", "os_crypt", "builtin") - - #: flag that this class's bases should be modified by SubclassBackendMixin - _backend_mixin_target = True - - #: map of backend -> mixin class, used by _get_backend_loader() - _backend_mixin_map = { - None: _NoBackend, - "bcrypt": _BcryptBackend, - "pybcrypt": _PyBcryptBackend, - "bcryptor": _BcryptorBackend, - "os_crypt": _OsCryptBackend, - "builtin": _BuiltinBackend, - } - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# variants -#============================================================================= -_UDOLLAR = u("$") - -# XXX: it might be better to have all the bcrypt variants share a common base class, -# and have the (django_)bcrypt_sha256 wrappers just proxy bcrypt instead of subclassing it. -class _wrapped_bcrypt(bcrypt): - """ - abstracts out some bits bcrypt_sha256 & django_bcrypt_sha256 share. - - bypass backend-loading wrappers for hash() etc - - disable truncation support, sha256 wrappers don't need it. - """ - setting_kwds = tuple(elem for elem in bcrypt.setting_kwds if elem not in ["truncate_error"]) - truncate_size = None - - # XXX: these will be needed if any bcrypt backends directly implement this... - # @classmethod - # def hash(cls, secret, **kwds): - # # bypass bcrypt backend overriding this method - # # XXX: would wrapping bcrypt make this easier than subclassing it? - # return super(_BcryptCommon, cls).hash(secret, **kwds) - # - # @classmethod - # def verify(cls, secret, hash): - # # bypass bcrypt backend overriding this method - # return super(_BcryptCommon, cls).verify(secret, hash) - # - # @classmethod - # def genhash(cls, secret, hash): - # # bypass bcrypt backend overriding this method - # return super(_BcryptCommon, cls).genhash(secret, hash) - - @classmethod - def _check_truncate_policy(cls, secret): - # disable check performed by bcrypt(), since this doesn't truncate passwords. - pass - -#============================================================================= -# bcrypt sha256 wrapper -#============================================================================= - -class bcrypt_sha256(_wrapped_bcrypt): - """ - This class implements a composition of BCrypt + HMAC_SHA256, - and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept - all the same optional keywords as the base :class:`bcrypt` hash. - - .. versionadded:: 1.6.2 - - .. versionchanged:: 1.7 - - Now defaults to ``"2b"`` bcrypt variant; though supports older hashes - generated using the ``"2a"`` bcrypt variant. - - .. versionchanged:: 1.7.3 - - For increased security, updated to use HMAC-SHA256 instead of plain SHA256. - Now only supports the ``"2b"`` bcrypt variant. Hash format updated to "v=2". - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "bcrypt_sha256" - - #-------------------- - # GenericHandler - #-------------------- - # this is locked at 2b for now (with 2a allowed only for legacy v1 format) - ident_values = (IDENT_2A, IDENT_2B) - - # clone bcrypt's ident aliases so they can be used here as well... - ident_aliases = (lambda ident_values: dict(item for item in bcrypt.ident_aliases.items() - if item[1] in ident_values))(ident_values) - default_ident = IDENT_2B - - #-------------------- - # class specific - #-------------------- - - _supported_versions = set([1, 2]) - - #=================================================================== - # instance attrs - #=================================================================== - - #: wrapper version. - #: v1 -- used prior to passlib 1.7.3; performs ``bcrypt(sha256(secret), salt, cost)`` - #: v2 -- new in passlib 1.7.3; performs `bcrypt(sha256_hmac(salt, secret), salt, cost)`` - version = 2 - - #=================================================================== - # configuration - #=================================================================== - - @classmethod - def using(cls, version=None, **kwds): - subcls = super(bcrypt_sha256, cls).using(**kwds) - if version is not None: - subcls.version = subcls._norm_version(version) - ident = subcls.default_ident - if subcls.version > 1 and ident != IDENT_2B: - raise ValueError("bcrypt %r hashes not allowed for version %r" % - (ident, subcls.version)) - return subcls - - #=================================================================== - # formatting - #=================================================================== - - # sample hash: - # $bcrypt-sha256$2a,6$/3OeRpbOf8/l6nPPRdZPp.$nRiyYqPobEZGdNRBWihQhiFDh1ws1tu - # $bcrypt-sha256$ -- prefix/identifier - # 2a -- bcrypt variant - # , -- field separator - # 6 -- bcrypt work factor - # $ -- section separator - # /3OeRpbOf8/l6nPPRdZPp. -- salt - # $ -- section separator - # nRiyYqPobEZGdNRBWihQhiFDh1ws1tu -- digest - - # XXX: we can't use .ident attr due to bcrypt code using it. - # working around that via prefix. - prefix = u('$bcrypt-sha256$') - - #: current version 2 hash format - _v2_hash_re = re.compile(r"""(?x) - ^ - [$]bcrypt-sha256[$] - v=(?P\d+), - t=(?P2b), - r=(?P\d{1,2}) - [$](?P[^$]{22}) - (?:[$](?P[^$]{31}))? - $ - """) - - #: old version 1 hash format - _v1_hash_re = re.compile(r"""(?x) - ^ - [$]bcrypt-sha256[$] - (?P2[ab]), - (?P\d{1,2}) - [$](?P[^$]{22}) - (?:[$](?P[^$]{31}))? - $ - """) - - @classmethod - def identify(cls, hash): - hash = uh.to_unicode_for_identify(hash) - if not hash: - return False - return hash.startswith(cls.prefix) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - if not hash.startswith(cls.prefix): - raise uh.exc.InvalidHashError(cls) - m = cls._v2_hash_re.match(hash) - if m: - version = int(m.group("version")) - if version < 2: - raise uh.exc.MalformedHashError(cls) - else: - m = cls._v1_hash_re.match(hash) - if m: - version = 1 - else: - raise uh.exc.MalformedHashError(cls) - rounds = m.group("rounds") - if rounds.startswith(uh._UZERO) and rounds != uh._UZERO: - raise uh.exc.ZeroPaddedRoundsError(cls) - return cls( - version=version, - ident=m.group("type"), - rounds=int(rounds), - salt=m.group("salt"), - checksum=m.group("digest"), - ) - - _v2_template = u("$bcrypt-sha256$v=2,t=%s,r=%d$%s$%s") - _v1_template = u("$bcrypt-sha256$%s,%d$%s$%s") - - def to_string(self): - if self.version == 1: - template = self._v1_template - else: - template = self._v2_template - hash = template % (self.ident.strip(_UDOLLAR), self.rounds, self.salt, self.checksum) - return uascii_to_str(hash) - - #=================================================================== - # init - #=================================================================== - - def __init__(self, version=None, **kwds): - if version is not None: - self.version = self._norm_version(version) - super(bcrypt_sha256, self).__init__(**kwds) - - #=================================================================== - # version - #=================================================================== - - @classmethod - def _norm_version(cls, version): - if version not in cls._supported_versions: - raise ValueError("%s: unknown or unsupported version: %r" % (cls.name, version)) - return version - - #=================================================================== - # checksum - #=================================================================== - - def _calc_checksum(self, secret): - # NOTE: can't use digest directly, since bcrypt stops at first NULL. - # NOTE: bcrypt doesn't fully mix entropy for bytes 55-72 of password - # (XXX: citation needed), so we don't want key to be > 55 bytes. - # thus, have to use base64 (44 bytes) rather than hex (64 bytes). - # XXX: it's later come out that 55-72 may be ok, so later revision of bcrypt_sha256 - # may switch to hex encoding, since it's simpler to implement elsewhere. - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - - if self.version == 1: - # version 1 -- old version just ran secret through sha256(), - # though this could be vulnerable to a breach attach - # (c.f. issue 114); which is why v2 switched to hmac wrapper. - digest = sha256(secret).digest() - else: - # version 2 -- running secret through HMAC keyed off salt. - # this prevents known secret -> sha256 password tables from being - # used to test against a bcrypt_sha256 hash. - # keying off salt (instead of constant string) should minimize chances of this - # colliding with existing table of hmac digest lookups as well. - # NOTE: salt in this case is the "bcrypt64"-encoded value, not the raw salt bytes, - # to make things easier for parallel implementations of this hash -- - # saving them the trouble of implementing a "bcrypt64" decoder. - salt = self.salt - if salt[-1] not in self.final_salt_chars: - # forbidding salts with padding bits set, because bcrypt implementations - # won't consistently hash them the same. since we control this format, - # just prevent these from even getting used. - raise ValueError("invalid salt string") - digest = compile_hmac("sha256", salt.encode("ascii"))(secret) - - # NOTE: output of b64encode() uses "+/" altchars, "=" padding chars, - # and no leading/trailing whitespace. - key = b64encode(digest) - - # hand result off to normal bcrypt algorithm - return super(bcrypt_sha256, self)._calc_checksum(key) - - #=================================================================== - # other - #=================================================================== - - def _calc_needs_update(self, **kwds): - if self.version < type(self).version: - return True - return super(bcrypt_sha256, self)._calc_needs_update(**kwds) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/cisco.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/cisco.py deleted file mode 100644 index e715e1a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/cisco.py +++ /dev/null @@ -1,440 +0,0 @@ -""" -passlib.handlers.cisco -- Cisco password hashes -""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify, unhexlify -from hashlib import md5 -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import right_pad_string, to_unicode, repeat_string, to_bytes -from passlib.utils.binary import h64 -from passlib.utils.compat import unicode, u, join_byte_values, \ - join_byte_elems, iter_byte_values, uascii_to_str -import passlib.utils.handlers as uh -# local -__all__ = [ - "cisco_pix", - "cisco_asa", - "cisco_type7", -] - -#============================================================================= -# utils -#============================================================================= - -#: dummy bytes used by spoil_digest var in cisco_pix._calc_checksum() -_DUMMY_BYTES = b'\xFF' * 32 - -#============================================================================= -# cisco pix firewall hash -#============================================================================= -class cisco_pix(uh.HasUserContext, uh.StaticHandler): - """ - This class implements the password hash used by older Cisco PIX firewalls, - and follows the :ref:`password-hash-api`. - It does a single round of hashing, and relies on the username - as the salt. - - This class only allows passwords <= 16 bytes, anything larger - will result in a :exc:`~passlib.exc.PasswordSizeError` if passed to :meth:`~cisco_pix.hash`, - and be silently rejected if passed to :meth:`~cisco_pix.verify`. - - The :meth:`~passlib.ifc.PasswordHash.hash`, - :meth:`~passlib.ifc.PasswordHash.genhash`, and - :meth:`~passlib.ifc.PasswordHash.verify` methods - all support the following extra keyword: - - :param str user: - String containing name of user account this password is associated with. - - This is *required* in order to correctly hash passwords associated - with a user account on the Cisco device, as it is used to salt - the hash. - - Conversely, this *must* be omitted or set to ``""`` in order to correctly - hash passwords which don't have an associated user account - (such as the "enable" password). - - .. versionadded:: 1.6 - - .. versionchanged:: 1.7.1 - - Passwords > 16 bytes are now rejected / throw error instead of being silently truncated, - to match Cisco behavior. A number of :ref:`bugs ` were fixed - which caused prior releases to generate unverifiable hashes in certain cases. - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "cisco_pix" - - truncate_size = 16 - - # NOTE: these are the default policy for PasswordHash, - # but want to set them explicitly for now. - truncate_error = True - truncate_verify_reject = True - - #-------------------- - # GenericHandler - #-------------------- - checksum_size = 16 - checksum_chars = uh.HASH64_CHARS - - #-------------------- - # custom - #-------------------- - - #: control flag signalling "cisco_asa" mode, set by cisco_asa class - _is_asa = False - - #=================================================================== - # methods - #=================================================================== - def _calc_checksum(self, secret): - """ - This function implements the "encrypted" hash format used by Cisco - PIX & ASA. It's behavior has been confirmed for ASA 9.6, - but is presumed correct for PIX & other ASA releases, - as it fits with known test vectors, and existing literature. - - While nearly the same, the PIX & ASA hashes have slight differences, - so this function performs differently based on the _is_asa class flag. - Noteable changes from PIX to ASA include password size limit - increased from 16 -> 32, and other internal changes. - """ - # select PIX vs or ASA mode - asa = self._is_asa - - # - # encode secret - # - # per ASA 8.4 documentation, - # http://www.cisco.com/c/en/us/td/docs/security/asa/asa84/configuration/guide/asa_84_cli_config/ref_cli.html#Supported_Character_Sets, - # it supposedly uses UTF-8 -- though some double-encoding issues have - # been observed when trying to actually *set* a non-ascii password - # via ASDM, and access via SSH seems to strip 8-bit chars. - # - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - - # - # check if password too large - # - # Per ASA 9.6 changes listed in - # http://www.cisco.com/c/en/us/td/docs/security/asa/roadmap/asa_new_features.html, - # prior releases had a maximum limit of 32 characters. - # Testing with an ASA 9.6 system bears this out -- - # setting 32-char password for a user account, - # and logins will fail if any chars are appended. - # (ASA 9.6 added new PBKDF2-based hash algorithm, - # which supports larger passwords). - # - # Per PIX documentation - # http://www.cisco.com/en/US/docs/security/pix/pix50/configuration/guide/commands.html, - # it would not allow passwords > 16 chars. - # - # Thus, we unconditionally throw a password size error here, - # as nothing valid can come from a larger password. - # NOTE: assuming PIX has same behavior, but at 16 char limit. - # - spoil_digest = None - if len(secret) > self.truncate_size: - if self.use_defaults: - # called from hash() - msg = "Password too long (%s allows at most %d bytes)" % \ - (self.name, self.truncate_size) - raise uh.exc.PasswordSizeError(self.truncate_size, msg=msg) - else: - # called from verify() -- - # We don't want to throw error, or return early, - # as that would let attacker know too much. Instead, we set a - # flag to add some dummy data into the md5 digest, so that - # output won't match truncated version of secret, or anything - # else that's fixed and predictable. - spoil_digest = secret + _DUMMY_BYTES - - # - # append user to secret - # - # Policy appears to be: - # - # * Nothing appended for enable password (user = "") - # - # * ASA: If user present, but secret is >= 28 chars, nothing appended. - # - # * 1-2 byte users not allowed. - # DEVIATION: we're letting them through, and repeating their - # chars ala 3-char user, to simplify testing. - # Could issue warning in the future though. - # - # * 3 byte user has first char repeated, to pad to 4. - # (observed under ASA 9.6, assuming true elsewhere) - # - # * 4 byte users are used directly. - # - # * 5+ byte users are truncated to 4 bytes. - # - user = self.user - if user: - if isinstance(user, unicode): - user = user.encode("utf-8") - if not asa or len(secret) < 28: - secret += repeat_string(user, 4) - - # - # pad / truncate result to limit - # - # While PIX always pads to 16 bytes, ASA increases to 32 bytes IFF - # secret+user > 16 bytes. This makes PIX & ASA have different results - # where secret size in range(13,16), and user is present -- - # PIX will truncate to 16, ASA will truncate to 32. - # - if asa and len(secret) > 16: - pad_size = 32 - else: - pad_size = 16 - secret = right_pad_string(secret, pad_size) - - # - # md5 digest - # - if spoil_digest: - # make sure digest won't match truncated version of secret - secret += spoil_digest - digest = md5(secret).digest() - - # - # drop every 4th byte - # NOTE: guessing this was done because it makes output exactly - # 16 bytes, which may have been a general 'char password[]' - # size limit under PIX - # - digest = join_byte_elems(c for i, c in enumerate(digest) if (i + 1) & 3) - - # - # encode using Hash64 - # - return h64.encode_bytes(digest).decode("ascii") - - # NOTE: works, but needs UTs. - # @classmethod - # def same_as_pix(cls, secret, user=""): - # """ - # test whether (secret + user) combination should - # have the same hash under PIX and ASA. - # - # mainly present to help unittests. - # """ - # # see _calc_checksum() above for details of this logic. - # size = len(to_bytes(secret, "utf-8")) - # if user and size < 28: - # size += 4 - # return size < 17 - - #=================================================================== - # eoc - #=================================================================== - - -class cisco_asa(cisco_pix): - """ - This class implements the password hash used by Cisco ASA/PIX 7.0 and newer (2005). - Aside from a different internal algorithm, it's use and format is identical - to the older :class:`cisco_pix` class. - - For passwords less than 13 characters, this should be identical to :class:`!cisco_pix`, - but will generate a different hash for most larger inputs - (See the `Format & Algorithm`_ section for the details). - - This class only allows passwords <= 32 bytes, anything larger - will result in a :exc:`~passlib.exc.PasswordSizeError` if passed to :meth:`~cisco_asa.hash`, - and be silently rejected if passed to :meth:`~cisco_asa.verify`. - - .. versionadded:: 1.7 - - .. versionchanged:: 1.7.1 - - Passwords > 32 bytes are now rejected / throw error instead of being silently truncated, - to match Cisco behavior. A number of :ref:`bugs ` were fixed - which caused prior releases to generate unverifiable hashes in certain cases. - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "cisco_asa" - - #-------------------- - # TruncateMixin - #-------------------- - truncate_size = 32 - - #-------------------- - # cisco_pix - #-------------------- - _is_asa = True - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# type 7 -#============================================================================= -class cisco_type7(uh.GenericHandler): - """ - This class implements the "Type 7" password encoding used by Cisco IOS, - and follows the :ref:`password-hash-api`. - It has a simple 4-5 bit salt, but is nonetheless a reversible encoding - instead of a real hash. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: int - :param salt: - This may be an optional salt integer drawn from ``range(0,16)``. - If omitted, one will be chosen at random. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` values that are out of range. - - Note that while this class outputs digests in upper-case hexadecimal, - it will accept lower-case as well. - - This class also provides the following additional method: - - .. automethod:: decode - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "cisco_type7" - setting_kwds = ("salt",) - - #-------------------- - # GenericHandler - #-------------------- - checksum_chars = uh.UPPER_HEX_CHARS - - #-------------------- - # HasSalt - #-------------------- - - # NOTE: encoding could handle max_salt_value=99, but since key is only 52 - # chars in size, not sure what appropriate behavior is for that edge case. - min_salt_value = 0 - max_salt_value = 52 - - #=================================================================== - # methods - #=================================================================== - @classmethod - def using(cls, salt=None, **kwds): - subcls = super(cisco_type7, cls).using(**kwds) - if salt is not None: - salt = subcls._norm_salt(salt, relaxed=kwds.get("relaxed")) - subcls._generate_salt = staticmethod(lambda: salt) - return subcls - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - if len(hash) < 2: - raise uh.exc.InvalidHashError(cls) - salt = int(hash[:2]) # may throw ValueError - return cls(salt=salt, checksum=hash[2:].upper()) - - def __init__(self, salt=None, **kwds): - super(cisco_type7, self).__init__(**kwds) - if salt is not None: - salt = self._norm_salt(salt) - elif self.use_defaults: - salt = self._generate_salt() - assert self._norm_salt(salt) == salt, "generated invalid salt: %r" % (salt,) - else: - raise TypeError("no salt specified") - self.salt = salt - - @classmethod - def _norm_salt(cls, salt, relaxed=False): - """ - validate & normalize salt value. - .. note:: - the salt for this algorithm is an integer 0-52, not a string - """ - if not isinstance(salt, int): - raise uh.exc.ExpectedTypeError(salt, "integer", "salt") - if 0 <= salt <= cls.max_salt_value: - return salt - msg = "salt/offset must be in 0..52 range" - if relaxed: - warn(msg, uh.PasslibHashWarning) - return 0 if salt < 0 else cls.max_salt_value - else: - raise ValueError(msg) - - @staticmethod - def _generate_salt(): - return uh.rng.randint(0, 15) - - def to_string(self): - return "%02d%s" % (self.salt, uascii_to_str(self.checksum)) - - def _calc_checksum(self, secret): - # XXX: no idea what unicode policy is, but all examples are - # 7-bit ascii compatible, so using UTF-8 - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return hexlify(self._cipher(secret, self.salt)).decode("ascii").upper() - - @classmethod - def decode(cls, hash, encoding="utf-8"): - """decode hash, returning original password. - - :arg hash: encoded password - :param encoding: optional encoding to use (defaults to ``UTF-8``). - :returns: password as unicode - """ - self = cls.from_string(hash) - tmp = unhexlify(self.checksum.encode("ascii")) - raw = self._cipher(tmp, self.salt) - return raw.decode(encoding) if encoding else raw - - # type7 uses a xor-based vingere variant, using the following secret key: - _key = u("dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncxv9873254k;fg87") - - @classmethod - def _cipher(cls, data, salt): - """xor static key against data - encrypts & decrypts""" - key = cls._key - key_size = len(key) - return join_byte_values( - value ^ ord(key[(salt + idx) % key_size]) - for idx, value in enumerate(iter_byte_values(data)) - ) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/des_crypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/des_crypt.py deleted file mode 100644 index 68a4ca7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/des_crypt.py +++ /dev/null @@ -1,607 +0,0 @@ -"""passlib.handlers.des_crypt - traditional unix (DES) crypt and variants""" -#============================================================================= -# imports -#============================================================================= -# core -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import safe_crypt, test_crypt, to_unicode -from passlib.utils.binary import h64, h64big -from passlib.utils.compat import byte_elem_value, u, uascii_to_str, unicode, suppress_cause -from passlib.crypto.des import des_encrypt_int_block -import passlib.utils.handlers as uh -# local -__all__ = [ - "des_crypt", - "bsdi_crypt", - "bigcrypt", - "crypt16", -] - -#============================================================================= -# pure-python backend for des_crypt family -#============================================================================= -_BNULL = b'\x00' - -def _crypt_secret_to_key(secret): - """convert secret to 64-bit DES key. - - this only uses the first 8 bytes of the secret, - and discards the high 8th bit of each byte at that. - a null parity bit is inserted after every 7th bit of the output. - """ - # NOTE: this would set the parity bits correctly, - # but des_encrypt_int_block() would just ignore them... - ##return sum(expand_7bit(byte_elem_value(c) & 0x7f) << (56-i*8) - ## for i, c in enumerate(secret[:8])) - return sum((byte_elem_value(c) & 0x7f) << (57-i*8) - for i, c in enumerate(secret[:8])) - -def _raw_des_crypt(secret, salt): - """pure-python backed for des_crypt""" - assert len(salt) == 2 - - # NOTE: some OSes will accept non-HASH64 characters in the salt, - # but what value they assign these characters varies wildy, - # so just rejecting them outright. - # the same goes for single-character salts... - # some OSes duplicate the char, some insert a '.' char, - # and openbsd does (something) which creates an invalid hash. - salt_value = h64.decode_int12(salt) - - # gotta do something - no official policy since this predates unicode - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - assert isinstance(secret, bytes) - - # forbidding NULL char because underlying crypt() rejects them too. - if _BNULL in secret: - raise uh.exc.NullPasswordError(des_crypt) - - # convert first 8 bytes of secret string into an integer - key_value = _crypt_secret_to_key(secret) - - # run data through des using input of 0 - result = des_encrypt_int_block(key_value, 0, salt_value, 25) - - # run h64 encode on result - return h64big.encode_int64(result) - -def _bsdi_secret_to_key(secret): - """convert secret to DES key used by bsdi_crypt""" - key_value = _crypt_secret_to_key(secret) - idx = 8 - end = len(secret) - while idx < end: - next = idx + 8 - tmp_value = _crypt_secret_to_key(secret[idx:next]) - key_value = des_encrypt_int_block(key_value, key_value) ^ tmp_value - idx = next - return key_value - -def _raw_bsdi_crypt(secret, rounds, salt): - """pure-python backend for bsdi_crypt""" - - # decode salt - salt_value = h64.decode_int24(salt) - - # gotta do something - no official policy since this predates unicode - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - assert isinstance(secret, bytes) - - # forbidding NULL char because underlying crypt() rejects them too. - if _BNULL in secret: - raise uh.exc.NullPasswordError(bsdi_crypt) - - # convert secret string into an integer - key_value = _bsdi_secret_to_key(secret) - - # run data through des using input of 0 - result = des_encrypt_int_block(key_value, 0, salt_value, rounds) - - # run h64 encode on result - return h64big.encode_int64(result) - -#============================================================================= -# handlers -#============================================================================= -class des_crypt(uh.TruncateMixin, uh.HasManyBackends, uh.HasSalt, uh.GenericHandler): - """This class implements the des-crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :param bool truncate_error: - By default, des_crypt will silently truncate passwords larger than 8 bytes. - Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash` - to raise a :exc:`~passlib.exc.PasswordTruncateError` instead. - - .. versionadded:: 1.7 - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "des_crypt" - setting_kwds = ("salt", "truncate_error") - - #-------------------- - # GenericHandler - #-------------------- - checksum_chars = uh.HASH64_CHARS - checksum_size = 11 - - #-------------------- - # HasSalt - #-------------------- - min_salt_size = max_salt_size = 2 - salt_chars = uh.HASH64_CHARS - - #-------------------- - # TruncateMixin - #-------------------- - truncate_size = 8 - - #=================================================================== - # formatting - #=================================================================== - # FORMAT: 2 chars of H64-encoded salt + 11 chars of H64-encoded checksum - - _hash_regex = re.compile(u(r""" - ^ - (?P[./a-z0-9]{2}) - (?P[./a-z0-9]{11})? - $"""), re.X|re.I) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - salt, chk = hash[:2], hash[2:] - return cls(salt=salt, checksum=chk or None) - - def to_string(self): - hash = u("%s%s") % (self.salt, self.checksum) - return uascii_to_str(hash) - - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - # check for truncation (during .hash() calls only) - if self.use_defaults: - self._check_truncate_policy(secret) - - return self._calc_checksum_backend(secret) - - #=================================================================== - # backend - #=================================================================== - backends = ("os_crypt", "builtin") - - #--------------------------------------------------------------- - # os_crypt backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_os_crypt(cls): - if test_crypt("test", 'abgOeLfPimXQo'): - cls._set_calc_checksum_backend(cls._calc_checksum_os_crypt) - return True - else: - return False - - def _calc_checksum_os_crypt(self, secret): - # NOTE: we let safe_crypt() encode unicode secret -> utf8; - # no official policy since des-crypt predates unicode - hash = safe_crypt(secret, self.salt) - if hash is None: - # py3's crypt.crypt() can't handle non-utf8 bytes. - # fallback to builtin alg, which is always available. - return self._calc_checksum_builtin(secret) - if not hash.startswith(self.salt) or len(hash) != 13: - raise uh.exc.CryptBackendError(self, self.salt, hash) - return hash[2:] - - #--------------------------------------------------------------- - # builtin backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_builtin(cls): - cls._set_calc_checksum_backend(cls._calc_checksum_builtin) - return True - - def _calc_checksum_builtin(self, secret): - return _raw_des_crypt(secret, self.salt.encode("ascii")).decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """This class implements the BSDi-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 4 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 5001, must be between 1 and 16777215, inclusive. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. versionchanged:: 1.6 - :meth:`hash` will now issue a warning if an even number of rounds is used - (see :ref:`bsdi-crypt-security-issues` regarding weak DES keys). - """ - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "bsdi_crypt" - setting_kwds = ("salt", "rounds") - checksum_size = 11 - checksum_chars = uh.HASH64_CHARS - - #--HasSalt-- - min_salt_size = max_salt_size = 4 - salt_chars = uh.HASH64_CHARS - - #--HasRounds-- - default_rounds = 5001 - min_rounds = 1 - max_rounds = 16777215 # (1<<24)-1 - rounds_cost = "linear" - - # NOTE: OpenBSD login.conf reports 7250 as minimum allowed rounds, - # but that seems to be an OS policy, not a algorithm limitation. - - #=================================================================== - # parsing - #=================================================================== - _hash_regex = re.compile(u(r""" - ^ - _ - (?P[./a-z0-9]{4}) - (?P[./a-z0-9]{4}) - (?P[./a-z0-9]{11})? - $"""), re.X|re.I) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - rounds, salt, chk = m.group("rounds", "salt", "chk") - return cls( - rounds=h64.decode_int24(rounds.encode("ascii")), - salt=salt, - checksum=chk, - ) - - def to_string(self): - hash = u("_%s%s%s") % (h64.encode_int24(self.rounds).decode("ascii"), - self.salt, self.checksum) - return uascii_to_str(hash) - - #=================================================================== - # validation - #=================================================================== - - # NOTE: keeping this flag for admin/choose_rounds.py script. - # want to eventually expose rounds logic to that script in better way. - _avoid_even_rounds = True - - @classmethod - def using(cls, **kwds): - subcls = super(bsdi_crypt, cls).using(**kwds) - if not subcls.default_rounds & 1: - # issue warning if caller set an even 'rounds' value. - warn("bsdi_crypt rounds should be odd, as even rounds may reveal weak DES keys", - uh.exc.PasslibSecurityWarning) - return subcls - - @classmethod - def _generate_rounds(cls): - rounds = super(bsdi_crypt, cls)._generate_rounds() - # ensure autogenerated rounds are always odd - # NOTE: doing this even for default_rounds so needs_update() doesn't get - # caught in a loop. - # FIXME: this technically might generate a rounds value 1 larger - # than the requested upper bound - but better to err on side of safety. - return rounds|1 - - #=================================================================== - # migration - #=================================================================== - - def _calc_needs_update(self, **kwds): - # mark bsdi_crypt hashes as deprecated if they have even rounds. - if not self.rounds & 1: - return True - # hand off to base implementation - return super(bsdi_crypt, self)._calc_needs_update(**kwds) - - #=================================================================== - # backends - #=================================================================== - backends = ("os_crypt", "builtin") - - #--------------------------------------------------------------- - # os_crypt backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_os_crypt(cls): - if test_crypt("test", '_/...lLDAxARksGCHin.'): - cls._set_calc_checksum_backend(cls._calc_checksum_os_crypt) - return True - else: - return False - - def _calc_checksum_os_crypt(self, secret): - config = self.to_string() - hash = safe_crypt(secret, config) - if hash is None: - # py3's crypt.crypt() can't handle non-utf8 bytes. - # fallback to builtin alg, which is always available. - return self._calc_checksum_builtin(secret) - if not hash.startswith(config[:9]) or len(hash) != 20: - raise uh.exc.CryptBackendError(self, config, hash) - return hash[-11:] - - #--------------------------------------------------------------- - # builtin backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_builtin(cls): - cls._set_calc_checksum_backend(cls._calc_checksum_builtin) - return True - - def _calc_checksum_builtin(self, secret): - return _raw_bsdi_crypt(secret, self.rounds, self.salt.encode("ascii")).decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -class bigcrypt(uh.HasSalt, uh.GenericHandler): - """This class implements the BigCrypt password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 22 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "bigcrypt" - setting_kwds = ("salt",) - checksum_chars = uh.HASH64_CHARS - # NOTE: checksum chars must be multiple of 11 - - #--HasSalt-- - min_salt_size = max_salt_size = 2 - salt_chars = uh.HASH64_CHARS - - #=================================================================== - # internal helpers - #=================================================================== - _hash_regex = re.compile(u(r""" - ^ - (?P[./a-z0-9]{2}) - (?P([./a-z0-9]{11})+)? - $"""), re.X|re.I) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - salt, chk = m.group("salt", "chk") - return cls(salt=salt, checksum=chk) - - def to_string(self): - hash = u("%s%s") % (self.salt, self.checksum) - return uascii_to_str(hash) - - def _norm_checksum(self, checksum, relaxed=False): - checksum = super(bigcrypt, self)._norm_checksum(checksum, relaxed=relaxed) - if len(checksum) % 11: - raise uh.exc.InvalidHashError(self) - return checksum - - #=================================================================== - # backend - #=================================================================== - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - chk = _raw_des_crypt(secret, self.salt.encode("ascii")) - idx = 8 - end = len(secret) - while idx < end: - next = idx + 8 - chk += _raw_des_crypt(secret[idx:next], chk[-11:-9]) - idx = next - return chk.decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -class crypt16(uh.TruncateMixin, uh.HasSalt, uh.GenericHandler): - """This class implements the crypt16 password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :param bool truncate_error: - By default, crypt16 will silently truncate passwords larger than 16 bytes. - Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash` - to raise a :exc:`~passlib.exc.PasswordTruncateError` instead. - - .. versionadded:: 1.7 - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "crypt16" - setting_kwds = ("salt", "truncate_error") - - #-------------------- - # GenericHandler - #-------------------- - checksum_size = 22 - checksum_chars = uh.HASH64_CHARS - - #-------------------- - # HasSalt - #-------------------- - min_salt_size = max_salt_size = 2 - salt_chars = uh.HASH64_CHARS - - #-------------------- - # TruncateMixin - #-------------------- - truncate_size = 16 - - #=================================================================== - # internal helpers - #=================================================================== - _hash_regex = re.compile(u(r""" - ^ - (?P[./a-z0-9]{2}) - (?P[./a-z0-9]{22})? - $"""), re.X|re.I) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - salt, chk = m.group("salt", "chk") - return cls(salt=salt, checksum=chk) - - def to_string(self): - hash = u("%s%s") % (self.salt, self.checksum) - return uascii_to_str(hash) - - #=================================================================== - # backend - #=================================================================== - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - - # check for truncation (during .hash() calls only) - if self.use_defaults: - self._check_truncate_policy(secret) - - # parse salt value - try: - salt_value = h64.decode_int12(self.salt.encode("ascii")) - except ValueError: # pragma: no cover - caught by class - raise suppress_cause(ValueError("invalid chars in salt")) - - # convert first 8 byts of secret string into an integer, - key1 = _crypt_secret_to_key(secret) - - # run data through des using input of 0 - result1 = des_encrypt_int_block(key1, 0, salt_value, 20) - - # convert next 8 bytes of secret string into integer (key=0 if secret < 8 chars) - key2 = _crypt_secret_to_key(secret[8:16]) - - # run data through des using input of 0 - result2 = des_encrypt_int_block(key2, 0, salt_value, 5) - - # done - chk = h64big.encode_int64(result1) + h64big.encode_int64(result2) - return chk.decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/digests.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/digests.py deleted file mode 100644 index 982155c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/digests.py +++ /dev/null @@ -1,168 +0,0 @@ -"""passlib.handlers.digests - plain hash digests -""" -#============================================================================= -# imports -#============================================================================= -# core -import hashlib -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import to_native_str, to_bytes, render_bytes, consteq -from passlib.utils.compat import unicode, str_to_uascii -import passlib.utils.handlers as uh -from passlib.crypto.digest import lookup_hash -# local -__all__ = [ - "create_hex_hash", - "hex_md4", - "hex_md5", - "hex_sha1", - "hex_sha256", - "hex_sha512", -] - -#============================================================================= -# helpers for hexadecimal hashes -#============================================================================= -class HexDigestHash(uh.StaticHandler): - """this provides a template for supporting passwords stored as plain hexadecimal hashes""" - #=================================================================== - # class attrs - #=================================================================== - _hash_func = None # hash function to use - filled in by create_hex_hash() - checksum_size = None # filled in by create_hex_hash() - checksum_chars = uh.HEX_CHARS - - #: special for detecting if _hash_func is just a stub method. - supported = True - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(self._hash_func(secret).hexdigest()) - - #=================================================================== - # eoc - #=================================================================== - -def create_hex_hash(digest, module=__name__, django_name=None, required=True): - """ - create hex-encoded unsalted hasher for specified digest algorithm. - - .. versionchanged:: 1.7.3 - If called with unknown/supported digest, won't throw error immediately, - but instead return a dummy hasher that will throw error when called. - - set ``required=True`` to restore old behavior. - """ - info = lookup_hash(digest, required=required) - name = "hex_" + info.name - if not info.supported: - info.digest_size = 0 - hasher = type(name, (HexDigestHash,), dict( - name=name, - __module__=module, # so ABCMeta won't clobber it - _hash_func=staticmethod(info.const), # sometimes it's a function, sometimes not. so wrap it. - checksum_size=info.digest_size*2, - __doc__="""This class implements a plain hexadecimal %s hash, and follows the :ref:`password-hash-api`. - -It supports no optional or contextual keywords. -""" % (info.name,) - )) - if not info.supported: - hasher.supported = False - if django_name: - hasher.django_name = django_name - return hasher - -#============================================================================= -# predefined handlers -#============================================================================= - -# NOTE: some digests below are marked as "required=False", because these may not be present on -# FIPS systems (see issue 116). if missing, will return stub hasher that throws error -# if an attempt is made to actually use hash/verify with them. - -hex_md4 = create_hex_hash("md4", required=False) -hex_md5 = create_hex_hash("md5", django_name="unsalted_md5", required=False) -hex_sha1 = create_hex_hash("sha1", required=False) -hex_sha256 = create_hex_hash("sha256") -hex_sha512 = create_hex_hash("sha512") - -#============================================================================= -# htdigest -#============================================================================= -class htdigest(uh.MinimalHandler): - """htdigest hash function. - - .. todo:: - document this hash - """ - name = "htdigest" - setting_kwds = () - context_kwds = ("user", "realm", "encoding") - default_encoding = "utf-8" - - @classmethod - def hash(cls, secret, user, realm, encoding=None): - # NOTE: this was deliberately written so that raw bytes are passed through - # unchanged, the encoding kwd is only used to handle unicode values. - if not encoding: - encoding = cls.default_encoding - uh.validate_secret(secret) - if isinstance(secret, unicode): - secret = secret.encode(encoding) - user = to_bytes(user, encoding, "user") - realm = to_bytes(realm, encoding, "realm") - data = render_bytes("%s:%s:%s", user, realm, secret) - return hashlib.md5(data).hexdigest() - - @classmethod - def _norm_hash(cls, hash): - """normalize hash to native string, and validate it""" - hash = to_native_str(hash, param="hash") - if len(hash) != 32: - raise uh.exc.MalformedHashError(cls, "wrong size") - for char in hash: - if char not in uh.LC_HEX_CHARS: - raise uh.exc.MalformedHashError(cls, "invalid chars in hash") - return hash - - @classmethod - def verify(cls, secret, hash, user, realm, encoding="utf-8"): - hash = cls._norm_hash(hash) - other = cls.hash(secret, user, realm, encoding) - return consteq(hash, other) - - @classmethod - def identify(cls, hash): - try: - cls._norm_hash(hash) - except ValueError: - return False - return True - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genconfig(cls): - return cls.hash("", "", "") - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genhash(cls, secret, config, user, realm, encoding=None): - # NOTE: 'config' is ignored, as this hash has no salting / other configuration. - # just have to make sure it's valid. - cls._norm_hash(config) - return cls.hash(secret, user, realm, encoding) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/django.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/django.py deleted file mode 100644 index 6dd499a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/django.py +++ /dev/null @@ -1,512 +0,0 @@ -"""passlib.handlers.django- Django password hash support""" -#============================================================================= -# imports -#============================================================================= -# core -from base64 import b64encode -from binascii import hexlify -from hashlib import md5, sha1, sha256 -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.handlers.bcrypt import _wrapped_bcrypt -from passlib.hash import argon2, bcrypt, pbkdf2_sha1, pbkdf2_sha256 -from passlib.utils import to_unicode, rng, getrandstr -from passlib.utils.binary import BASE64_CHARS -from passlib.utils.compat import str_to_uascii, uascii_to_str, unicode, u -from passlib.crypto.digest import pbkdf2_hmac -import passlib.utils.handlers as uh -# local -__all__ = [ - "django_salted_sha1", - "django_salted_md5", - "django_bcrypt", - "django_pbkdf2_sha1", - "django_pbkdf2_sha256", - "django_argon2", - "django_des_crypt", - "django_disabled", -] - -#============================================================================= -# lazy imports & constants -#============================================================================= - -# imported by django_des_crypt._calc_checksum() -des_crypt = None - -def _import_des_crypt(): - global des_crypt - if des_crypt is None: - from passlib.hash import des_crypt - return des_crypt - -# django 1.4's salt charset -SALT_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' - -#============================================================================= -# salted hashes -#============================================================================= -class DjangoSaltedHash(uh.HasSalt, uh.GenericHandler): - """base class providing common code for django hashes""" - # name, ident, checksum_size must be set by subclass. - # ident must include "$" suffix. - setting_kwds = ("salt", "salt_size") - - # NOTE: django 1.0-1.3 would accept empty salt strings. - # django 1.4 won't, but this appears to be regression - # (https://code.djangoproject.com/ticket/18144) - # so presumably it will be fixed in a later release. - default_salt_size = 12 - max_salt_size = None - salt_chars = SALT_CHARS - - checksum_chars = uh.LOWER_HEX_CHARS - - @classmethod - def from_string(cls, hash): - salt, chk = uh.parse_mc2(hash, cls.ident, handler=cls) - return cls(salt=salt, checksum=chk) - - def to_string(self): - return uh.render_mc2(self.ident, self.salt, self.checksum) - -# NOTE: only used by PBKDF2 -class DjangoVariableHash(uh.HasRounds, DjangoSaltedHash): - """base class providing common code for django hashes w/ variable rounds""" - setting_kwds = DjangoSaltedHash.setting_kwds + ("rounds",) - - min_rounds = 1 - - @classmethod - def from_string(cls, hash): - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, handler=cls) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self): - return uh.render_mc3(self.ident, self.rounds, self.salt, self.checksum) - -class django_salted_sha1(DjangoSaltedHash): - """This class implements Django's Salted SHA1 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and uses a single round of SHA1. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, a 12 character one will be autogenerated (this is recommended). - If specified, may be any series of characters drawn from the regexp range ``[0-9a-zA-Z]``. - - :type salt_size: int - :param salt_size: - Optional number of characters to use when autogenerating new salts. - Defaults to 12, but can be any positive value. - - This should be compatible with Django 1.4's :class:`!SHA1PasswordHasher` class. - - .. versionchanged: 1.6 - This class now generates 12-character salts instead of 5, - and generated salts uses the character range ``[0-9a-zA-Z]`` instead of - the ``[0-9a-f]``. This is to be compatible with how Django >= 1.4 - generates these hashes; but hashes generated in this manner will still be - correctly interpreted by earlier versions of Django. - """ - name = "django_salted_sha1" - django_name = "sha1" - ident = u("sha1$") - checksum_size = 40 - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(sha1(self.salt.encode("ascii") + secret).hexdigest()) - -class django_salted_md5(DjangoSaltedHash): - """This class implements Django's Salted MD5 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and uses a single round of MD5. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, a 12 character one will be autogenerated (this is recommended). - If specified, may be any series of characters drawn from the regexp range ``[0-9a-zA-Z]``. - - :type salt_size: int - :param salt_size: - Optional number of characters to use when autogenerating new salts. - Defaults to 12, but can be any positive value. - - This should be compatible with the hashes generated by - Django 1.4's :class:`!MD5PasswordHasher` class. - - .. versionchanged: 1.6 - This class now generates 12-character salts instead of 5, - and generated salts uses the character range ``[0-9a-zA-Z]`` instead of - the ``[0-9a-f]``. This is to be compatible with how Django >= 1.4 - generates these hashes; but hashes generated in this manner will still be - correctly interpreted by earlier versions of Django. - """ - name = "django_salted_md5" - django_name = "md5" - ident = u("md5$") - checksum_size = 32 - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(md5(self.salt.encode("ascii") + secret).hexdigest()) - -#============================================================================= -# BCrypt -#============================================================================= - -django_bcrypt = uh.PrefixWrapper("django_bcrypt", bcrypt, - prefix=u('bcrypt$'), ident=u("bcrypt$"), - # NOTE: this docstring is duplicated in the docs, since sphinx - # seems to be having trouble reading it via autodata:: - doc="""This class implements Django 1.4's BCrypt wrapper, and follows the :ref:`password-hash-api`. - - This is identical to :class:`!bcrypt` itself, but with - the Django-specific prefix ``"bcrypt$"`` prepended. - - See :doc:`/lib/passlib.hash.bcrypt` for more details, - the usage and behavior is identical. - - This should be compatible with the hashes generated by - Django 1.4's :class:`!BCryptPasswordHasher` class. - - .. versionadded:: 1.6 - """) -django_bcrypt.django_name = "bcrypt" -django_bcrypt._using_clone_attrs += ("django_name",) - -#============================================================================= -# BCRYPT + SHA256 -#============================================================================= - -class django_bcrypt_sha256(_wrapped_bcrypt): - """This class implements Django 1.6's Bcrypt+SHA256 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - While the algorithm and format is somewhat different, - the api and options for this hash are identical to :class:`!bcrypt` itself, - see :doc:`bcrypt ` for more details. - - .. versionadded:: 1.6.2 - """ - name = "django_bcrypt_sha256" - django_name = "bcrypt_sha256" - _digest = sha256 - - # sample hash: - # bcrypt_sha256$$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu - - # XXX: we can't use .ident attr due to bcrypt code using it. - # working around that via django_prefix - django_prefix = u('bcrypt_sha256$') - - @classmethod - def identify(cls, hash): - hash = uh.to_unicode_for_identify(hash) - if not hash: - return False - return hash.startswith(cls.django_prefix) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - if not hash.startswith(cls.django_prefix): - raise uh.exc.InvalidHashError(cls) - bhash = hash[len(cls.django_prefix):] - if not bhash.startswith("$2"): - raise uh.exc.MalformedHashError(cls) - return super(django_bcrypt_sha256, cls).from_string(bhash) - - def to_string(self): - bhash = super(django_bcrypt_sha256, self).to_string() - return uascii_to_str(self.django_prefix) + bhash - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - secret = hexlify(self._digest(secret).digest()) - return super(django_bcrypt_sha256, self)._calc_checksum(secret) - -#============================================================================= -# PBKDF2 variants -#============================================================================= - -class django_pbkdf2_sha256(DjangoVariableHash): - """This class implements Django's PBKDF2-HMAC-SHA256 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, a 12 character one will be autogenerated (this is recommended). - If specified, may be any series of characters drawn from the regexp range ``[0-9a-zA-Z]``. - - :type salt_size: int - :param salt_size: - Optional number of characters to use when autogenerating new salts. - Defaults to 12, but can be any positive value. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 29000, but must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - This should be compatible with the hashes generated by - Django 1.4's :class:`!PBKDF2PasswordHasher` class. - - .. versionadded:: 1.6 - """ - name = "django_pbkdf2_sha256" - django_name = "pbkdf2_sha256" - ident = u('pbkdf2_sha256$') - min_salt_size = 1 - max_rounds = 0xffffffff # setting at 32-bit limit for now - checksum_chars = uh.PADDED_BASE64_CHARS - checksum_size = 44 # 32 bytes -> base64 - default_rounds = pbkdf2_sha256.default_rounds # NOTE: django 1.6 uses 12000 - _digest = "sha256" - - def _calc_checksum(self, secret): - # NOTE: secret & salt will be encoded using UTF-8 by pbkdf2_hmac() - hash = pbkdf2_hmac(self._digest, secret, self.salt, self.rounds) - return b64encode(hash).rstrip().decode("ascii") - -class django_pbkdf2_sha1(django_pbkdf2_sha256): - """This class implements Django's PBKDF2-HMAC-SHA1 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, a 12 character one will be autogenerated (this is recommended). - If specified, may be any series of characters drawn from the regexp range ``[0-9a-zA-Z]``. - - :type salt_size: int - :param salt_size: - Optional number of characters to use when autogenerating new salts. - Defaults to 12, but can be any positive value. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 131000, but must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - This should be compatible with the hashes generated by - Django 1.4's :class:`!PBKDF2SHA1PasswordHasher` class. - - .. versionadded:: 1.6 - """ - name = "django_pbkdf2_sha1" - django_name = "pbkdf2_sha1" - ident = u('pbkdf2_sha1$') - checksum_size = 28 # 20 bytes -> base64 - default_rounds = pbkdf2_sha1.default_rounds # NOTE: django 1.6 uses 12000 - _digest = "sha1" - -#============================================================================= -# Argon2 -#============================================================================= - -# NOTE: as of 2019-11-11, Django's Argon2PasswordHasher only supports Type I; -# so limiting this to ensure that as well. - -django_argon2 = uh.PrefixWrapper( - name="django_argon2", - wrapped=argon2.using(type="I"), - prefix=u('argon2'), - ident=u('argon2$argon2i$'), - # NOTE: this docstring is duplicated in the docs, since sphinx - # seems to be having trouble reading it via autodata:: - doc="""This class implements Django 1.10's Argon2 wrapper, and follows the :ref:`password-hash-api`. - - This is identical to :class:`!argon2` itself, but with - the Django-specific prefix ``"argon2$"`` prepended. - - See :doc:`argon2 ` for more details, - the usage and behavior is identical. - - This should be compatible with the hashes generated by - Django 1.10's :class:`!Argon2PasswordHasher` class. - - .. versionadded:: 1.7 - """) -django_argon2.django_name = "argon2" -django_argon2._using_clone_attrs += ("django_name",) - -#============================================================================= -# DES -#============================================================================= -class django_des_crypt(uh.TruncateMixin, uh.HasSalt, uh.GenericHandler): - """This class implements Django's :class:`des_crypt` wrapper, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :param bool truncate_error: - By default, django_des_crypt will silently truncate passwords larger than 8 bytes. - Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash` - to raise a :exc:`~passlib.exc.PasswordTruncateError` instead. - - .. versionadded:: 1.7 - - This should be compatible with the hashes generated by - Django 1.4's :class:`!CryptPasswordHasher` class. - Note that Django only supports this hash on Unix systems - (though :class:`!django_des_crypt` is available cross-platform - under Passlib). - - .. versionchanged:: 1.6 - This class will now accept hashes with empty salt strings, - since Django 1.4 generates them this way. - """ - name = "django_des_crypt" - django_name = "crypt" - setting_kwds = ("salt", "salt_size", "truncate_error") - ident = u("crypt$") - checksum_chars = salt_chars = uh.HASH64_CHARS - checksum_size = 11 - min_salt_size = default_salt_size = 2 - truncate_size = 8 - - # NOTE: regarding duplicate salt field: - # - # django 1.0 had a "crypt$$" hash format, - # used [a-z0-9] to generate a 5 char salt, stored it in salt1, - # duplicated the first two chars of salt1 as salt2. - # it would throw an error if salt1 was empty. - # - # django 1.4 started generating 2 char salt using the full alphabet, - # left salt1 empty, and only paid attention to salt2. - # - # in order to be compatible with django 1.0, the hashes generated - # by this function will always include salt1, unless the following - # class-level field is disabled (mainly used for testing) - use_duplicate_salt = True - - @classmethod - def from_string(cls, hash): - salt, chk = uh.parse_mc2(hash, cls.ident, handler=cls) - if chk: - # chk should be full des_crypt hash - if not salt: - # django 1.4 always uses empty salt field, - # so extract salt from des_crypt hash - salt = chk[:2] - elif salt[:2] != chk[:2]: - # django 1.0 stored 5 chars in salt field, and duplicated - # the first two chars in . we keep the full salt, - # but make sure the first two chars match as sanity check. - raise uh.exc.MalformedHashError(cls, - "first two digits of salt and checksum must match") - # in all cases, strip salt chars from - chk = chk[2:] - return cls(salt=salt, checksum=chk) - - def to_string(self): - salt = self.salt - chk = salt[:2] + self.checksum - if self.use_duplicate_salt: - # filling in salt field, so that we're compatible with django 1.0 - return uh.render_mc2(self.ident, salt, chk) - else: - # django 1.4+ style hash - return uh.render_mc2(self.ident, "", chk) - - def _calc_checksum(self, secret): - # NOTE: we lazily import des_crypt, - # since most django deploys won't use django_des_crypt - global des_crypt - if des_crypt is None: - _import_des_crypt() - # check for truncation (during .hash() calls only) - if self.use_defaults: - self._check_truncate_policy(secret) - return des_crypt(salt=self.salt[:2])._calc_checksum(secret) - -class django_disabled(uh.ifc.DisabledHash, uh.StaticHandler): - """This class provides disabled password behavior for Django, and follows the :ref:`password-hash-api`. - - This class does not implement a hash, but instead - claims the special hash string ``"!"`` which Django uses - to indicate an account's password has been disabled. - - * newly encrypted passwords will hash to ``"!"``. - * it rejects all passwords. - - .. note:: - - Django 1.6 prepends a randomly generated 40-char alphanumeric string - to each unusuable password. This class recognizes such strings, - but for backwards compatibility, still returns ``"!"``. - - See ``_ for why - Django appends an alphanumeric string. - - .. versionchanged:: 1.6.2 added Django 1.6 support - - .. versionchanged:: 1.7 started appending an alphanumeric string. - """ - name = "django_disabled" - _hash_prefix = u("!") - suffix_length = 40 - - # XXX: move this to StaticHandler, or wherever _hash_prefix is being used? - @classmethod - def identify(cls, hash): - hash = uh.to_unicode_for_identify(hash) - return hash.startswith(cls._hash_prefix) - - def _calc_checksum(self, secret): - # generate random suffix to match django's behavior - return getrandstr(rng, BASE64_CHARS[:-2], self.suffix_length) - - @classmethod - def verify(cls, secret, hash): - uh.validate_secret(secret) - if not cls.identify(hash): - raise uh.exc.InvalidHashError(cls) - return False - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/fshp.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/fshp.py deleted file mode 100644 index db13e74..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/fshp.py +++ /dev/null @@ -1,214 +0,0 @@ -"""passlib.handlers.fshp -""" - -#============================================================================= -# imports -#============================================================================= -# core -from base64 import b64encode, b64decode -import re -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import to_unicode -import passlib.utils.handlers as uh -from passlib.utils.compat import bascii_to_str, iteritems, u,\ - unicode -from passlib.crypto.digest import pbkdf1 -# local -__all__ = [ - 'fshp', -] -#============================================================================= -# sha1-crypt -#============================================================================= -class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements the FSHP password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :param salt: - Optional raw salt string. - If not specified, one will be autogenerated (this is recommended). - - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 16 bytes, but can be any non-negative value. - - :param rounds: - Optional number of rounds to use. - Defaults to 480000, must be between 1 and 4294967295, inclusive. - - :param variant: - Optionally specifies variant of FSHP to use. - - * ``0`` - uses SHA-1 digest (deprecated). - * ``1`` - uses SHA-2/256 digest (default). - * ``2`` - uses SHA-2/384 digest. - * ``3`` - uses SHA-2/512 digest. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "fshp" - setting_kwds = ("salt", "salt_size", "rounds", "variant") - checksum_chars = uh.PADDED_BASE64_CHARS - ident = u("{FSHP") - # checksum_size is property() that depends on variant - - #--HasRawSalt-- - default_salt_size = 16 # current passlib default, FSHP uses 8 - max_salt_size = None - - #--HasRounds-- - # FIXME: should probably use different default rounds - # based on the variant. setting for default variant (sha256) for now. - default_rounds = 480000 # current passlib default, FSHP uses 4096 - min_rounds = 1 # set by FSHP - max_rounds = 4294967295 # 32-bit integer limit - not set by FSHP - rounds_cost = "linear" - - #--variants-- - default_variant = 1 - _variant_info = { - # variant: (hash name, digest size) - 0: ("sha1", 20), - 1: ("sha256", 32), - 2: ("sha384", 48), - 3: ("sha512", 64), - } - _variant_aliases = dict( - [(unicode(k),k) for k in _variant_info] + - [(v[0],k) for k,v in iteritems(_variant_info)] - ) - - #=================================================================== - # configuration - #=================================================================== - @classmethod - def using(cls, variant=None, **kwds): - subcls = super(fshp, cls).using(**kwds) - if variant is not None: - subcls.default_variant = cls._norm_variant(variant) - return subcls - - #=================================================================== - # instance attrs - #=================================================================== - variant = None - - #=================================================================== - # init - #=================================================================== - def __init__(self, variant=None, **kwds): - # NOTE: variant must be set first, since it controls checksum size, etc. - self.use_defaults = kwds.get("use_defaults") # load this early - if variant is not None: - variant = self._norm_variant(variant) - elif self.use_defaults: - variant = self.default_variant - assert self._norm_variant(variant) == variant, "invalid default variant: %r" % (variant,) - else: - raise TypeError("no variant specified") - self.variant = variant - super(fshp, self).__init__(**kwds) - - @classmethod - def _norm_variant(cls, variant): - if isinstance(variant, bytes): - variant = variant.decode("ascii") - if isinstance(variant, unicode): - try: - variant = cls._variant_aliases[variant] - except KeyError: - raise ValueError("invalid fshp variant") - if not isinstance(variant, int): - raise TypeError("fshp variant must be int or known alias") - if variant not in cls._variant_info: - raise ValueError("invalid fshp variant") - return variant - - @property - def checksum_alg(self): - return self._variant_info[self.variant][0] - - @property - def checksum_size(self): - return self._variant_info[self.variant][1] - - #=================================================================== - # formatting - #=================================================================== - - _hash_regex = re.compile(u(r""" - ^ - \{FSHP - (\d+)\| # variant - (\d+)\| # salt size - (\d+)\} # rounds - ([a-zA-Z0-9+/]+={0,3}) # digest - $"""), re.X) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - variant, salt_size, rounds, data = m.group(1,2,3,4) - variant = int(variant) - salt_size = int(salt_size) - rounds = int(rounds) - try: - data = b64decode(data.encode("ascii")) - except TypeError: - raise uh.exc.MalformedHashError(cls) - salt = data[:salt_size] - chk = data[salt_size:] - return cls(salt=salt, checksum=chk, rounds=rounds, variant=variant) - - def to_string(self): - chk = self.checksum - salt = self.salt - data = bascii_to_str(b64encode(salt+chk)) - return "{FSHP%d|%d|%d}%s" % (self.variant, len(salt), self.rounds, data) - - #=================================================================== - # backend - #=================================================================== - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - # NOTE: for some reason, FSHP uses pbkdf1 with password & salt reversed. - # this has only a minimal impact on security, - # but it is worth noting this deviation. - return pbkdf1( - digest=self.checksum_alg, - secret=self.salt, - salt=secret, - rounds=self.rounds, - keylen=self.checksum_size, - ) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/ldap_digests.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/ldap_digests.py deleted file mode 100644 index 30254f0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/ldap_digests.py +++ /dev/null @@ -1,359 +0,0 @@ -"""passlib.handlers.digests - plain hash digests -""" -#============================================================================= -# imports -#============================================================================= -# core -from base64 import b64encode, b64decode -from hashlib import md5, sha1, sha256, sha512 -import logging; log = logging.getLogger(__name__) -import re -# site -# pkg -from passlib.handlers.misc import plaintext -from passlib.utils import unix_crypt_schemes, to_unicode -from passlib.utils.compat import uascii_to_str, unicode, u -from passlib.utils.decor import classproperty -import passlib.utils.handlers as uh -# local -__all__ = [ - "ldap_plaintext", - "ldap_md5", - "ldap_sha1", - "ldap_salted_md5", - "ldap_salted_sha1", - "ldap_salted_sha256", - "ldap_salted_sha512", - - ##"get_active_ldap_crypt_schemes", - "ldap_des_crypt", - "ldap_bsdi_crypt", - "ldap_md5_crypt", - "ldap_sha1_crypt", - "ldap_bcrypt", - "ldap_sha256_crypt", - "ldap_sha512_crypt", -] - -#============================================================================= -# ldap helpers -#============================================================================= -class _Base64DigestHelper(uh.StaticHandler): - """helper for ldap_md5 / ldap_sha1""" - # XXX: could combine this with hex digests in digests.py - - ident = None # required - prefix identifier - _hash_func = None # required - hash function - _hash_regex = None # required - regexp to recognize hash - checksum_chars = uh.PADDED_BASE64_CHARS - - @classproperty - def _hash_prefix(cls): - """tell StaticHandler to strip ident from checksum""" - return cls.ident - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - chk = self._hash_func(secret).digest() - return b64encode(chk).decode("ascii") - -class _SaltedBase64DigestHelper(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """helper for ldap_salted_md5 / ldap_salted_sha1""" - setting_kwds = ("salt", "salt_size") - checksum_chars = uh.PADDED_BASE64_CHARS - - ident = None # required - prefix identifier - _hash_func = None # required - hash function - _hash_regex = None # required - regexp to recognize hash - min_salt_size = max_salt_size = 4 - - # NOTE: openldap implementation uses 4 byte salt, - # but it's been reported (issue 30) that some servers use larger salts. - # the semi-related rfc3112 recommends support for up to 16 byte salts. - min_salt_size = 4 - default_salt_size = 4 - max_salt_size = 16 - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - try: - data = b64decode(m.group("tmp").encode("ascii")) - except TypeError: - raise uh.exc.MalformedHashError(cls) - cs = cls.checksum_size - assert cs - return cls(checksum=data[:cs], salt=data[cs:]) - - def to_string(self): - data = self.checksum + self.salt - hash = self.ident + b64encode(data).decode("ascii") - return uascii_to_str(hash) - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return self._hash_func(secret + self.salt).digest() - -#============================================================================= -# implementations -#============================================================================= -class ldap_md5(_Base64DigestHelper): - """This class stores passwords using LDAP's plain MD5 format, and follows the :ref:`password-hash-api`. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods have no optional keywords. - """ - name = "ldap_md5" - ident = u("{MD5}") - _hash_func = md5 - _hash_regex = re.compile(u(r"^\{MD5\}(?P[+/a-zA-Z0-9]{22}==)$")) - -class ldap_sha1(_Base64DigestHelper): - """This class stores passwords using LDAP's plain SHA1 format, and follows the :ref:`password-hash-api`. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods have no optional keywords. - """ - name = "ldap_sha1" - ident = u("{SHA}") - _hash_func = sha1 - _hash_regex = re.compile(u(r"^\{SHA\}(?P[+/a-zA-Z0-9]{27}=)$")) - -class ldap_salted_md5(_SaltedBase64DigestHelper): - """This class stores passwords using LDAP's salted MD5 format, and follows the :ref:`password-hash-api`. - - It supports a 4-16 byte salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it may be any 4-16 byte string. - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 4 bytes for compatibility with the LDAP spec, - but some systems use larger salts, and Passlib supports - any value between 4-16. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. versionchanged:: 1.6 - This format now supports variable length salts, instead of a fix 4 bytes. - """ - name = "ldap_salted_md5" - ident = u("{SMD5}") - checksum_size = 16 - _hash_func = md5 - _hash_regex = re.compile(u(r"^\{SMD5\}(?P[+/a-zA-Z0-9]{27,}={0,2})$")) - -class ldap_salted_sha1(_SaltedBase64DigestHelper): - """ - This class stores passwords using LDAP's "Salted SHA1" format, - and follows the :ref:`password-hash-api`. - - It supports a 4-16 byte salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it may be any 4-16 byte string. - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 4 bytes for compatibility with the LDAP spec, - but some systems use larger salts, and Passlib supports - any value between 4-16. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. versionchanged:: 1.6 - This format now supports variable length salts, instead of a fix 4 bytes. - """ - name = "ldap_salted_sha1" - ident = u("{SSHA}") - checksum_size = 20 - _hash_func = sha1 - # NOTE: 32 = ceil((20 + 4) * 4/3) - _hash_regex = re.compile(u(r"^\{SSHA\}(?P[+/a-zA-Z0-9]{32,}={0,2})$")) - - - -class ldap_salted_sha256(_SaltedBase64DigestHelper): - """ - This class stores passwords using LDAP's "Salted SHA2-256" format, - and follows the :ref:`password-hash-api`. - - It supports a 4-16 byte salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it may be any 4-16 byte string. - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 8 bytes for compatibility with the LDAP spec, - but Passlib supports any value between 4-16. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.7.3 - """ - name = "ldap_salted_sha256" - ident = u("{SSHA256}") - checksum_size = 32 - default_salt_size = 8 - _hash_func = sha256 - # NOTE: 48 = ceil((32 + 4) * 4/3) - _hash_regex = re.compile(u(r"^\{SSHA256\}(?P[+/a-zA-Z0-9]{48,}={0,2})$")) - - -class ldap_salted_sha512(_SaltedBase64DigestHelper): - """ - This class stores passwords using LDAP's "Salted SHA2-512" format, - and follows the :ref:`password-hash-api`. - - It supports a 4-16 byte salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it may be any 4-16 byte string. - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 8 bytes for compatibility with the LDAP spec, - but Passlib supports any value between 4-16. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.7.3 - """ - name = "ldap_salted_sha512" - ident = u("{SSHA512}") - checksum_size = 64 - default_salt_size = 8 - _hash_func = sha512 - # NOTE: 91 = ceil((64 + 4) * 4/3) - _hash_regex = re.compile(u(r"^\{SSHA512\}(?P[+/a-zA-Z0-9]{91,}={0,2})$")) - - -class ldap_plaintext(plaintext): - """This class stores passwords in plaintext, and follows the :ref:`password-hash-api`. - - This class acts much like the generic :class:`!passlib.hash.plaintext` handler, - except that it will identify a hash only if it does NOT begin with the ``{XXX}`` identifier prefix - used by RFC2307 passwords. - - The :meth:`~passlib.ifc.PasswordHash.hash`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods all require the - following additional contextual keyword: - - :type encoding: str - :param encoding: - This controls the character encoding to use (defaults to ``utf-8``). - - This encoding will be used to encode :class:`!unicode` passwords - under Python 2, and decode :class:`!bytes` hashes under Python 3. - - .. versionchanged:: 1.6 - The ``encoding`` keyword was added. - """ - # NOTE: this subclasses plaintext, since all it does differently - # is override identify() - - name = "ldap_plaintext" - _2307_pat = re.compile(u(r"^\{\w+\}.*$")) - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genconfig(cls): - # Overridding plaintext.genconfig() since it returns "", - # but have to return non-empty value due to identify() below - return "!" - - @classmethod - def identify(cls, hash): - # NOTE: identifies all strings EXCEPT those with {XXX} prefix - hash = uh.to_unicode_for_identify(hash) - return bool(hash) and cls._2307_pat.match(hash) is None - -#============================================================================= -# {CRYPT} wrappers -# the following are wrappers around the base crypt algorithms, -# which add the ldap required {CRYPT} prefix -#============================================================================= -ldap_crypt_schemes = [ 'ldap_' + name for name in unix_crypt_schemes ] - -def _init_ldap_crypt_handlers(): - # NOTE: I don't like to implicitly modify globals() like this, - # but don't want to write out all these handlers out either :) - g = globals() - for wname in unix_crypt_schemes: - name = 'ldap_' + wname - g[name] = uh.PrefixWrapper(name, wname, prefix=u("{CRYPT}"), lazy=True) - del g -_init_ldap_crypt_handlers() - -##_lcn_host = None -##def get_host_ldap_crypt_schemes(): -## global _lcn_host -## if _lcn_host is None: -## from passlib.hosts import host_context -## schemes = host_context.schemes() -## _lcn_host = [ -## "ldap_" + name -## for name in unix_crypt_names -## if name in schemes -## ] -## return _lcn_host - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/md5_crypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/md5_crypt.py deleted file mode 100644 index e3a2dfa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/md5_crypt.py +++ /dev/null @@ -1,346 +0,0 @@ -"""passlib.handlers.md5_crypt - md5-crypt algorithm""" -#============================================================================= -# imports -#============================================================================= -# core -from hashlib import md5 -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import safe_crypt, test_crypt, repeat_string -from passlib.utils.binary import h64 -from passlib.utils.compat import unicode, u -import passlib.utils.handlers as uh -# local -__all__ = [ - "md5_crypt", - "apr_md5_crypt", -] - -#============================================================================= -# pure-python backend -#============================================================================= -_BNULL = b"\x00" -_MD5_MAGIC = b"$1$" -_APR_MAGIC = b"$apr1$" - -# pre-calculated offsets used to speed up C digest stage (see notes below). -# sequence generated using the following: - ##perms_order = "p,pp,ps,psp,sp,spp".split(",") - ##def offset(i): - ## key = (("p" if i % 2 else "") + ("s" if i % 3 else "") + - ## ("p" if i % 7 else "") + ("" if i % 2 else "p")) - ## return perms_order.index(key) - ##_c_digest_offsets = [(offset(i), offset(i+1)) for i in range(0,42,2)] -_c_digest_offsets = ( - (0, 3), (5, 1), (5, 3), (1, 2), (5, 1), (5, 3), (1, 3), - (4, 1), (5, 3), (1, 3), (5, 0), (5, 3), (1, 3), (5, 1), - (4, 3), (1, 3), (5, 1), (5, 2), (1, 3), (5, 1), (5, 3), - ) - -# map used to transpose bytes when encoding final digest -_transpose_map = (12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 5, 10, 4, 11) - -def _raw_md5_crypt(pwd, salt, use_apr=False): - """perform raw md5-crypt calculation - - this function provides a pure-python implementation of the internals - for the MD5-Crypt algorithms; it doesn't handle any of the - parsing/validation of the hash strings themselves. - - :arg pwd: password chars/bytes to hash - :arg salt: salt chars to use - :arg use_apr: use apache variant - - :returns: - encoded checksum chars - """ - # NOTE: regarding 'apr' format: - # really, apache? you had to invent a whole new "$apr1$" format, - # when all you did was change the ident incorporated into the hash? - # would love to find webpage explaining why just using a portable - # implementation of $1$ wasn't sufficient. *nothing else* was changed. - - #=================================================================== - # init & validate inputs - #=================================================================== - - # validate secret - # XXX: not sure what official unicode policy is, using this as default - if isinstance(pwd, unicode): - pwd = pwd.encode("utf-8") - assert isinstance(pwd, bytes), "pwd not unicode or bytes" - if _BNULL in pwd: - raise uh.exc.NullPasswordError(md5_crypt) - pwd_len = len(pwd) - - # validate salt - should have been taken care of by caller - assert isinstance(salt, unicode), "salt not unicode" - salt = salt.encode("ascii") - assert len(salt) < 9, "salt too large" - # NOTE: spec says salts larger than 8 bytes should be truncated, - # instead of causing an error. this function assumes that's been - # taken care of by the handler class. - - # load APR specific constants - if use_apr: - magic = _APR_MAGIC - else: - magic = _MD5_MAGIC - - #=================================================================== - # digest B - used as subinput to digest A - #=================================================================== - db = md5(pwd + salt + pwd).digest() - - #=================================================================== - # digest A - used to initialize first round of digest C - #=================================================================== - # start out with pwd + magic + salt - a_ctx = md5(pwd + magic + salt) - a_ctx_update = a_ctx.update - - # add pwd_len bytes of b, repeating b as many times as needed. - a_ctx_update(repeat_string(db, pwd_len)) - - # add null chars & first char of password - # NOTE: this may have historically been a bug, - # where they meant to use db[0] instead of B_NULL, - # but the original code memclear'ed db, - # and now all implementations have to use this. - i = pwd_len - evenchar = pwd[:1] - while i: - a_ctx_update(_BNULL if i & 1 else evenchar) - i >>= 1 - - # finish A - da = a_ctx.digest() - - #=================================================================== - # digest C - for a 1000 rounds, combine A, S, and P - # digests in various ways; in order to burn CPU time. - #=================================================================== - - # NOTE: the original MD5-Crypt implementation performs the C digest - # calculation using the following loop: - # - ##dc = da - ##i = 0 - ##while i < rounds: - ## tmp_ctx = md5(pwd if i & 1 else dc) - ## if i % 3: - ## tmp_ctx.update(salt) - ## if i % 7: - ## tmp_ctx.update(pwd) - ## tmp_ctx.update(dc if i & 1 else pwd) - ## dc = tmp_ctx.digest() - ## i += 1 - # - # The code Passlib uses (below) implements an equivalent algorithm, - # it's just been heavily optimized to pre-calculate a large number - # of things beforehand. It works off of a couple of observations - # about the original algorithm: - # - # 1. each round is a combination of 'dc', 'salt', and 'pwd'; and the exact - # combination is determined by whether 'i' a multiple of 2,3, and/or 7. - # 2. since lcm(2,3,7)==42, the series of combinations will repeat - # every 42 rounds. - # 3. even rounds 0-40 consist of 'hash(dc + round-specific-constant)'; - # while odd rounds 1-41 consist of hash(round-specific-constant + dc) - # - # Using these observations, the following code... - # * calculates the round-specific combination of salt & pwd for each round 0-41 - # * runs through as many 42-round blocks as possible (23) - # * runs through as many pairs of rounds as needed for remaining rounds (17) - # * this results in the required 42*23+2*17=1000 rounds required by md5_crypt. - # - # this cuts out a lot of the control overhead incurred when running the - # original loop 1000 times in python, resulting in ~20% increase in - # speed under CPython (though still 2x slower than glibc crypt) - - # prepare the 6 combinations of pwd & salt which are needed - # (order of 'perms' must match how _c_digest_offsets was generated) - pwd_pwd = pwd+pwd - pwd_salt = pwd+salt - perms = [pwd, pwd_pwd, pwd_salt, pwd_salt+pwd, salt+pwd, salt+pwd_pwd] - - # build up list of even-round & odd-round constants, - # and store in 21-element list as (even,odd) pairs. - data = [ (perms[even], perms[odd]) for even, odd in _c_digest_offsets] - - # perform 23 blocks of 42 rounds each (for a total of 966 rounds) - dc = da - blocks = 23 - while blocks: - for even, odd in data: - dc = md5(odd + md5(dc + even).digest()).digest() - blocks -= 1 - - # perform 17 more pairs of rounds (34 more rounds, for a total of 1000) - for even, odd in data[:17]: - dc = md5(odd + md5(dc + even).digest()).digest() - - #=================================================================== - # encode digest using appropriate transpose map - #=================================================================== - return h64.encode_transposed_bytes(dc, _transpose_map).decode("ascii") - -#============================================================================= -# handler -#============================================================================= -class _MD5_Common(uh.HasSalt, uh.GenericHandler): - """common code for md5_crypt and apr_md5_crypt""" - #=================================================================== - # class attrs - #=================================================================== - # name - set in subclass - setting_kwds = ("salt", "salt_size") - # ident - set in subclass - checksum_size = 22 - checksum_chars = uh.HASH64_CHARS - - max_salt_size = 8 - salt_chars = uh.HASH64_CHARS - - #=================================================================== - # methods - #=================================================================== - - @classmethod - def from_string(cls, hash): - salt, chk = uh.parse_mc2(hash, cls.ident, handler=cls) - return cls(salt=salt, checksum=chk) - - def to_string(self): - return uh.render_mc2(self.ident, self.salt, self.checksum) - - # _calc_checksum() - provided by subclass - - #=================================================================== - # eoc - #=================================================================== - -class md5_crypt(uh.HasManyBackends, _MD5_Common): - """This class implements the MD5-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 0-8 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type salt_size: int - :param salt_size: - Optional number of characters to use when autogenerating new salts. - Defaults to 8, but can be any value between 0 and 8. - (This is mainly needed when generating Cisco-compatible hashes, - which require ``salt_size=4``). - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - name = "md5_crypt" - ident = u("$1$") - - #=================================================================== - # methods - #=================================================================== - # FIXME: can't find definitive policy on how md5-crypt handles non-ascii. - # all backends currently coerce -> utf-8 - - backends = ("os_crypt", "builtin") - - #--------------------------------------------------------------- - # os_crypt backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_os_crypt(cls): - if test_crypt("test", '$1$test$pi/xDtU5WFVRqYS6BMU8X/'): - cls._set_calc_checksum_backend(cls._calc_checksum_os_crypt) - return True - else: - return False - - def _calc_checksum_os_crypt(self, secret): - config = self.ident + self.salt - hash = safe_crypt(secret, config) - if hash is None: - # py3's crypt.crypt() can't handle non-utf8 bytes. - # fallback to builtin alg, which is always available. - return self._calc_checksum_builtin(secret) - if not hash.startswith(config) or len(hash) != len(config) + 23: - raise uh.exc.CryptBackendError(self, config, hash) - return hash[-22:] - - #--------------------------------------------------------------- - # builtin backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_builtin(cls): - cls._set_calc_checksum_backend(cls._calc_checksum_builtin) - return True - - def _calc_checksum_builtin(self, secret): - return _raw_md5_crypt(secret, self.salt) - - #=================================================================== - # eoc - #=================================================================== - -class apr_md5_crypt(_MD5_Common): - """This class implements the Apr-MD5-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 0-8 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - name = "apr_md5_crypt" - ident = u("$apr1$") - - #=================================================================== - # methods - #=================================================================== - def _calc_checksum(self, secret): - return _raw_md5_crypt(secret, self.salt, use_apr=True) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/misc.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/misc.py deleted file mode 100644 index 44abc34..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/misc.py +++ /dev/null @@ -1,269 +0,0 @@ -"""passlib.handlers.misc - misc generic handlers -""" -#============================================================================= -# imports -#============================================================================= -# core -import sys -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import to_native_str, str_consteq -from passlib.utils.compat import unicode, u, unicode_or_bytes_types -import passlib.utils.handlers as uh -# local -__all__ = [ - "unix_disabled", - "unix_fallback", - "plaintext", -] - -#============================================================================= -# handler -#============================================================================= -class unix_fallback(uh.ifc.DisabledHash, uh.StaticHandler): - """This class provides the fallback behavior for unix shadow files, and follows the :ref:`password-hash-api`. - - This class does not implement a hash, but instead provides fallback - behavior as found in /etc/shadow on most unix variants. - If used, should be the last scheme in the context. - - * this class will positively identify all hash strings. - * for security, passwords will always hash to ``!``. - * it rejects all passwords if the hash is NOT an empty string (``!`` or ``*`` are frequently used). - * by default it rejects all passwords if the hash is an empty string, - but if ``enable_wildcard=True`` is passed to verify(), - all passwords will be allowed through if the hash is an empty string. - - .. deprecated:: 1.6 - This has been deprecated due to its "wildcard" feature, - and will be removed in Passlib 1.8. Use :class:`unix_disabled` instead. - """ - name = "unix_fallback" - context_kwds = ("enable_wildcard",) - - @classmethod - def identify(cls, hash): - if isinstance(hash, unicode_or_bytes_types): - return True - else: - raise uh.exc.ExpectedStringError(hash, "hash") - - def __init__(self, enable_wildcard=False, **kwds): - warn("'unix_fallback' is deprecated, " - "and will be removed in Passlib 1.8; " - "please use 'unix_disabled' instead.", - DeprecationWarning) - super(unix_fallback, self).__init__(**kwds) - self.enable_wildcard = enable_wildcard - - def _calc_checksum(self, secret): - if self.checksum: - # NOTE: hash will generally be "!", but we want to preserve - # it in case it's something else, like "*". - return self.checksum - else: - return u("!") - - @classmethod - def verify(cls, secret, hash, enable_wildcard=False): - uh.validate_secret(secret) - if not isinstance(hash, unicode_or_bytes_types): - raise uh.exc.ExpectedStringError(hash, "hash") - elif hash: - return False - else: - return enable_wildcard - -_MARKER_CHARS = u("*!") -_MARKER_BYTES = b"*!" - -class unix_disabled(uh.ifc.DisabledHash, uh.MinimalHandler): - """This class provides disabled password behavior for unix shadow files, - and follows the :ref:`password-hash-api`. - - This class does not implement a hash, but instead matches the "disabled account" - strings found in ``/etc/shadow`` on most Unix variants. "encrypting" a password - will simply return the disabled account marker. It will reject all passwords, - no matter the hash string. The :meth:`~passlib.ifc.PasswordHash.hash` - method supports one optional keyword: - - :type marker: str - :param marker: - Optional marker string which overrides the platform default - used to indicate a disabled account. - - If not specified, this will default to ``"*"`` on BSD systems, - and use the Linux default ``"!"`` for all other platforms. - (:attr:`!unix_disabled.default_marker` will contain the default value) - - .. versionadded:: 1.6 - This class was added as a replacement for the now-deprecated - :class:`unix_fallback` class, which had some undesirable features. - """ - name = "unix_disabled" - setting_kwds = ("marker",) - context_kwds = () - - _disable_prefixes = tuple(str(_MARKER_CHARS)) - - # TODO: rename attr to 'marker'... - if 'bsd' in sys.platform: # pragma: no cover -- runtime detection - default_marker = u("*") - else: - # use the linux default for other systems - # (glibc also supports adding old hash after the marker - # so it can be restored later). - default_marker = u("!") - - @classmethod - def using(cls, marker=None, **kwds): - subcls = super(unix_disabled, cls).using(**kwds) - if marker is not None: - if not cls.identify(marker): - raise ValueError("invalid marker: %r" % marker) - subcls.default_marker = marker - return subcls - - @classmethod - def identify(cls, hash): - # NOTE: technically, anything in the /etc/shadow password field - # which isn't valid crypt() output counts as "disabled". - # but that's rather ambiguous, and it's hard to predict what - # valid output is for unknown crypt() implementations. - # so to be on the safe side, we only match things *known* - # to be disabled field indicators, and will add others - # as they are found. things beginning w/ "$" should *never* match. - # - # things currently matched: - # * linux uses "!" - # * bsd uses "*" - # * linux may use "!" + hash to disable but preserve original hash - # * linux counts empty string as "any password"; - # this code recognizes it, but treats it the same as "!" - if isinstance(hash, unicode): - start = _MARKER_CHARS - elif isinstance(hash, bytes): - start = _MARKER_BYTES - else: - raise uh.exc.ExpectedStringError(hash, "hash") - return not hash or hash[0] in start - - @classmethod - def verify(cls, secret, hash): - uh.validate_secret(secret) - if not cls.identify(hash): # handles typecheck - raise uh.exc.InvalidHashError(cls) - return False - - @classmethod - def hash(cls, secret, **kwds): - if kwds: - uh.warn_hash_settings_deprecation(cls, kwds) - return cls.using(**kwds).hash(secret) - uh.validate_secret(secret) - marker = cls.default_marker - assert marker and cls.identify(marker) - return to_native_str(marker, param="marker") - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genhash(cls, secret, config, marker=None): - if not cls.identify(config): - raise uh.exc.InvalidHashError(cls) - elif config: - # preserve the existing str,since it might contain a disabled password hash ("!" + hash) - uh.validate_secret(secret) - return to_native_str(config, param="config") - else: - if marker is not None: - cls = cls.using(marker=marker) - return cls.hash(secret) - - @classmethod - def disable(cls, hash=None): - out = cls.hash("") - if hash is not None: - hash = to_native_str(hash, param="hash") - if cls.identify(hash): - # extract original hash, so that we normalize marker - hash = cls.enable(hash) - if hash: - out += hash - return out - - @classmethod - def enable(cls, hash): - hash = to_native_str(hash, param="hash") - for prefix in cls._disable_prefixes: - if hash.startswith(prefix): - orig = hash[len(prefix):] - if orig: - return orig - else: - raise ValueError("cannot restore original hash") - raise uh.exc.InvalidHashError(cls) - -class plaintext(uh.MinimalHandler): - """This class stores passwords in plaintext, and follows the :ref:`password-hash-api`. - - The :meth:`~passlib.ifc.PasswordHash.hash`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods all require the - following additional contextual keyword: - - :type encoding: str - :param encoding: - This controls the character encoding to use (defaults to ``utf-8``). - - This encoding will be used to encode :class:`!unicode` passwords - under Python 2, and decode :class:`!bytes` hashes under Python 3. - - .. versionchanged:: 1.6 - The ``encoding`` keyword was added. - """ - # NOTE: this is subclassed by ldap_plaintext - - name = "plaintext" - setting_kwds = () - context_kwds = ("encoding",) - default_encoding = "utf-8" - - @classmethod - def identify(cls, hash): - if isinstance(hash, unicode_or_bytes_types): - return True - else: - raise uh.exc.ExpectedStringError(hash, "hash") - - @classmethod - def hash(cls, secret, encoding=None): - uh.validate_secret(secret) - if not encoding: - encoding = cls.default_encoding - return to_native_str(secret, encoding, "secret") - - @classmethod - def verify(cls, secret, hash, encoding=None): - if not encoding: - encoding = cls.default_encoding - hash = to_native_str(hash, encoding, "hash") - if not cls.identify(hash): - raise uh.exc.InvalidHashError(cls) - return str_consteq(cls.hash(secret, encoding), hash) - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genconfig(cls): - return cls.hash("") - - @uh.deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genhash(cls, secret, config, encoding=None): - # NOTE: 'config' is ignored, as this hash has no salting / etc - if not cls.identify(config): - raise uh.exc.InvalidHashError(cls) - return cls.hash(secret, encoding=encoding) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mssql.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mssql.py deleted file mode 100644 index b060b36..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mssql.py +++ /dev/null @@ -1,244 +0,0 @@ -"""passlib.handlers.mssql - MS-SQL Password Hash - -Notes -===== -MS-SQL has used a number of hash algs over the years, -most of which were exposed through the undocumented -'pwdencrypt' and 'pwdcompare' sql functions. - -Known formats -------------- -6.5 - snefru hash, ascii encoded password - no examples found - -7.0 - snefru hash, unicode (what encoding?) - saw ref that these blobs were 16 bytes in size - no examples found - -2000 - byte string using displayed as 0x hex, using 0x0100 prefix. - contains hashes of password and upper-case password. - -2007 - same as 2000, but without the upper-case hash. - -refs ----------- -https://blogs.msdn.com/b/lcris/archive/2007/04/30/sql-server-2005-about-login-password-hashes.aspx?Redirected=true -http://us.generation-nt.com/securing-passwords-hash-help-35429432.html -http://forum.md5decrypter.co.uk/topic230-mysql-and-mssql-get-password-hashes.aspx -http://www.theregister.co.uk/2002/07/08/cracking_ms_sql_server_passwords/ -""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify, unhexlify -from hashlib import sha1 -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import consteq -from passlib.utils.compat import bascii_to_str, unicode, u -import passlib.utils.handlers as uh -# local -__all__ = [ - "mssql2000", - "mssql2005", -] - -#============================================================================= -# mssql 2000 -#============================================================================= -def _raw_mssql(secret, salt): - assert isinstance(secret, unicode) - assert isinstance(salt, bytes) - return sha1(secret.encode("utf-16-le") + salt).digest() - -BIDENT = b"0x0100" -##BIDENT2 = b("\x01\x00") -UIDENT = u("0x0100") - -def _ident_mssql(hash, csize, bsize): - """common identify for mssql 2000/2005""" - if isinstance(hash, unicode): - if len(hash) == csize and hash.startswith(UIDENT): - return True - elif isinstance(hash, bytes): - if len(hash) == csize and hash.startswith(BIDENT): - return True - ##elif len(hash) == bsize and hash.startswith(BIDENT2): # raw bytes - ## return True - else: - raise uh.exc.ExpectedStringError(hash, "hash") - return False - -def _parse_mssql(hash, csize, bsize, handler): - """common parser for mssql 2000/2005; returns 4 byte salt + checksum""" - if isinstance(hash, unicode): - if len(hash) == csize and hash.startswith(UIDENT): - try: - return unhexlify(hash[6:].encode("utf-8")) - except TypeError: # throw when bad char found - pass - elif isinstance(hash, bytes): - # assumes ascii-compat encoding - assert isinstance(hash, bytes) - if len(hash) == csize and hash.startswith(BIDENT): - try: - return unhexlify(hash[6:]) - except TypeError: # throw when bad char found - pass - ##elif len(hash) == bsize and hash.startswith(BIDENT2): # raw bytes - ## return hash[2:] - else: - raise uh.exc.ExpectedStringError(hash, "hash") - raise uh.exc.InvalidHashError(handler) - -class mssql2000(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements the password hash used by MS-SQL 2000, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 4 bytes in length. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - """ - #=================================================================== - # algorithm information - #=================================================================== - name = "mssql2000" - setting_kwds = ("salt",) - checksum_size = 40 - min_salt_size = max_salt_size = 4 - - #=================================================================== - # formatting - #=================================================================== - - # 0100 - 2 byte identifier - # 4 byte salt - # 20 byte checksum - # 20 byte checksum - # = 46 bytes - # encoded '0x' + 92 chars = 94 - - @classmethod - def identify(cls, hash): - return _ident_mssql(hash, 94, 46) - - @classmethod - def from_string(cls, hash): - data = _parse_mssql(hash, 94, 46, cls) - return cls(salt=data[:4], checksum=data[4:]) - - def to_string(self): - raw = self.salt + self.checksum - # raw bytes format - BIDENT2 + raw - return "0x0100" + bascii_to_str(hexlify(raw).upper()) - - def _calc_checksum(self, secret): - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - salt = self.salt - return _raw_mssql(secret, salt) + _raw_mssql(secret.upper(), salt) - - @classmethod - def verify(cls, secret, hash): - # NOTE: we only compare against the upper-case hash - # XXX: add 'full' just to verify both checksums? - uh.validate_secret(secret) - self = cls.from_string(hash) - chk = self.checksum - if chk is None: - raise uh.exc.MissingDigestError(cls) - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - result = _raw_mssql(secret.upper(), self.salt) - return consteq(result, chk[20:]) - -#============================================================================= -# handler -#============================================================================= -class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements the password hash used by MS-SQL 2005, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 4 bytes in length. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - """ - #=================================================================== - # algorithm information - #=================================================================== - name = "mssql2005" - setting_kwds = ("salt",) - - checksum_size = 20 - min_salt_size = max_salt_size = 4 - - #=================================================================== - # formatting - #=================================================================== - - # 0x0100 - 2 byte identifier - # 4 byte salt - # 20 byte checksum - # = 26 bytes - # encoded '0x' + 52 chars = 54 - - @classmethod - def identify(cls, hash): - return _ident_mssql(hash, 54, 26) - - @classmethod - def from_string(cls, hash): - data = _parse_mssql(hash, 54, 26, cls) - return cls(salt=data[:4], checksum=data[4:]) - - def to_string(self): - raw = self.salt + self.checksum - # raw bytes format - BIDENT2 + raw - return "0x0100" + bascii_to_str(hexlify(raw)).upper() - - def _calc_checksum(self, secret): - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - return _raw_mssql(secret, self.salt) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mysql.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mysql.py deleted file mode 100644 index 4a71253..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/mysql.py +++ /dev/null @@ -1,128 +0,0 @@ -"""passlib.handlers.mysql - -MySQL 3.2.3 / OLD_PASSWORD() - - This implements Mysql's OLD_PASSWORD algorithm, introduced in version 3.2.3, deprecated in version 4.1. - - See :mod:`passlib.handlers.mysql_41` for the new algorithm was put in place in version 4.1 - - This algorithm is known to be very insecure, and should only be used to verify existing password hashes. - - http://djangosnippets.org/snippets/1508/ - -MySQL 4.1.1 / NEW PASSWORD - This implements Mysql new PASSWORD algorithm, introduced in version 4.1. - - This function is unsalted, and therefore not very secure against rainbow attacks. - It should only be used when dealing with mysql passwords, - for all other purposes, you should use a salted hash function. - - Description taken from http://dev.mysql.com/doc/refman/6.0/en/password-hashing.html -""" -#============================================================================= -# imports -#============================================================================= -# core -from hashlib import sha1 -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import to_native_str -from passlib.utils.compat import bascii_to_str, unicode, u, \ - byte_elem_value, str_to_uascii -import passlib.utils.handlers as uh -# local -__all__ = [ - 'mysql323', - 'mysq41', -] - -#============================================================================= -# backend -#============================================================================= -class mysql323(uh.StaticHandler): - """This class implements the MySQL 3.2.3 password hash, and follows the :ref:`password-hash-api`. - - It has no salt and a single fixed round. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. - """ - #=================================================================== - # class attrs - #=================================================================== - name = "mysql323" - checksum_size = 16 - checksum_chars = uh.HEX_CHARS - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - # FIXME: no idea if mysql has a policy about handling unicode passwords - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - - MASK_32 = 0xffffffff - MASK_31 = 0x7fffffff - WHITE = b' \t' - - nr1 = 0x50305735 - nr2 = 0x12345671 - add = 7 - for c in secret: - if c in WHITE: - continue - tmp = byte_elem_value(c) - nr1 ^= ((((nr1 & 63)+add)*tmp) + (nr1 << 8)) & MASK_32 - nr2 = (nr2+((nr2 << 8) ^ nr1)) & MASK_32 - add = (add+tmp) & MASK_32 - return u("%08x%08x") % (nr1 & MASK_31, nr2 & MASK_31) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# handler -#============================================================================= -class mysql41(uh.StaticHandler): - """This class implements the MySQL 4.1 password hash, and follows the :ref:`password-hash-api`. - - It has no salt and a single fixed round. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. - """ - #=================================================================== - # class attrs - #=================================================================== - name = "mysql41" - _hash_prefix = u("*") - checksum_chars = uh.HEX_CHARS - checksum_size = 40 - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.upper() - - def _calc_checksum(self, secret): - # FIXME: no idea if mysql has a policy about handling unicode passwords - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(sha1(sha1(secret).digest()).hexdigest()).upper() - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/oracle.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/oracle.py deleted file mode 100644 index a094f37..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/oracle.py +++ /dev/null @@ -1,172 +0,0 @@ -"""passlib.handlers.oracle - Oracle DB Password Hashes""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify, unhexlify -from hashlib import sha1 -import re -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import to_unicode, xor_bytes -from passlib.utils.compat import irange, u, \ - uascii_to_str, unicode, str_to_uascii -from passlib.crypto.des import des_encrypt_block -import passlib.utils.handlers as uh -# local -__all__ = [ - "oracle10g", - "oracle11g" -] - -#============================================================================= -# oracle10 -#============================================================================= -def des_cbc_encrypt(key, value, iv=b'\x00' * 8, pad=b'\x00'): - """performs des-cbc encryption, returns only last block. - - this performs a specific DES-CBC encryption implementation - as needed by the Oracle10 hash. it probably won't be useful for - other purposes as-is. - - input value is null-padded to multiple of 8 bytes. - - :arg key: des key as bytes - :arg value: value to encrypt, as bytes. - :param iv: optional IV - :param pad: optional pad byte - - :returns: last block of DES-CBC encryption of all ``value``'s byte blocks. - """ - value += pad * (-len(value) % 8) # null pad to multiple of 8 - hash = iv # start things off - for offset in irange(0,len(value),8): - chunk = xor_bytes(hash, value[offset:offset+8]) - hash = des_encrypt_block(key, chunk) - return hash - -# magic string used as initial des key by oracle10 -ORACLE10_MAGIC = b"\x01\x23\x45\x67\x89\xAB\xCD\xEF" - -class oracle10(uh.HasUserContext, uh.StaticHandler): - """This class implements the password hash used by Oracle up to version 10g, and follows the :ref:`password-hash-api`. - - It does a single round of hashing, and relies on the username as the salt. - - The :meth:`~passlib.ifc.PasswordHash.hash`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods all require the - following additional contextual keywords: - - :type user: str - :param user: name of oracle user account this password is associated with. - """ - #=================================================================== - # algorithm information - #=================================================================== - name = "oracle10" - checksum_chars = uh.HEX_CHARS - checksum_size = 16 - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.upper() - - def _calc_checksum(self, secret): - # FIXME: not sure how oracle handles unicode. - # online docs about 10g hash indicate it puts ascii chars - # in a 2-byte encoding w/ the high byte set to null. - # they don't say how it handles other chars, or what encoding. - # - # so for now, encoding secret & user to utf-16-be, - # since that fits, and if secret/user is bytes, - # we assume utf-8, and decode first. - # - # this whole mess really needs someone w/ an oracle system, - # and some answers :) - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - user = to_unicode(self.user, "utf-8", param="user") - input = (user+secret).upper().encode("utf-16-be") - hash = des_cbc_encrypt(ORACLE10_MAGIC, input) - hash = des_cbc_encrypt(hash, input) - return hexlify(hash).decode("ascii").upper() - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# oracle11 -#============================================================================= -class oracle11(uh.HasSalt, uh.GenericHandler): - """This class implements the Oracle11g password hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 20 hexadecimal characters. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "oracle11" - setting_kwds = ("salt",) - checksum_size = 40 - checksum_chars = uh.UPPER_HEX_CHARS - - #--HasSalt-- - min_salt_size = max_salt_size = 20 - salt_chars = uh.UPPER_HEX_CHARS - - - #=================================================================== - # methods - #=================================================================== - _hash_regex = re.compile(u("^S:(?P[0-9a-f]{40})(?P[0-9a-f]{20})$"), re.I) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - m = cls._hash_regex.match(hash) - if not m: - raise uh.exc.InvalidHashError(cls) - salt, chk = m.group("salt", "chk") - return cls(salt=salt, checksum=chk.upper()) - - def to_string(self): - chk = self.checksum - hash = u("S:%s%s") % (chk.upper(), self.salt.upper()) - return uascii_to_str(hash) - - def _calc_checksum(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - chk = sha1(secret + unhexlify(self.salt.encode("ascii"))).hexdigest() - return str_to_uascii(chk).upper() - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/pbkdf2.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/pbkdf2.py deleted file mode 100644 index 274278d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/pbkdf2.py +++ /dev/null @@ -1,475 +0,0 @@ -"""passlib.handlers.pbkdf - PBKDF2 based hashes""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify, unhexlify -from base64 import b64encode, b64decode -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import to_unicode -from passlib.utils.binary import ab64_decode, ab64_encode -from passlib.utils.compat import str_to_bascii, u, uascii_to_str, unicode -from passlib.crypto.digest import pbkdf2_hmac -import passlib.utils.handlers as uh -# local -__all__ = [ - "pbkdf2_sha1", - "pbkdf2_sha256", - "pbkdf2_sha512", - "cta_pbkdf2_sha1", - "dlitz_pbkdf2_sha1", - "grub_pbkdf2_sha512", -] - -#============================================================================= -# -#============================================================================= -class Pbkdf2DigestHandler(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """base class for various pbkdf2_{digest} algorithms""" - #=================================================================== - # class attrs - #=================================================================== - - #--GenericHandler-- - setting_kwds = ("salt", "salt_size", "rounds") - checksum_chars = uh.HASH64_CHARS - - #--HasSalt-- - default_salt_size = 16 - max_salt_size = 1024 - - #--HasRounds-- - default_rounds = None # set by subclass - min_rounds = 1 - max_rounds = 0xffffffff # setting at 32-bit limit for now - rounds_cost = "linear" - - #--this class-- - _digest = None # name of subclass-specified hash - - # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check. - # the underlying pbkdf2 specifies no bounds for either. - - # NOTE: defaults chosen to be at least as large as pbkdf2 rfc recommends... - # >8 bytes of entropy in salt, >1000 rounds - # increased due to time since rfc established - - #=================================================================== - # methods - #=================================================================== - - @classmethod - def from_string(cls, hash): - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, handler=cls) - salt = ab64_decode(salt.encode("ascii")) - if chk: - chk = ab64_decode(chk.encode("ascii")) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self): - salt = ab64_encode(self.salt).decode("ascii") - chk = ab64_encode(self.checksum).decode("ascii") - return uh.render_mc3(self.ident, self.rounds, salt, chk) - - def _calc_checksum(self, secret): - # NOTE: pbkdf2_hmac() will encode secret & salt using UTF8 - return pbkdf2_hmac(self._digest, secret, self.salt, self.rounds, self.checksum_size) - -def create_pbkdf2_hash(hash_name, digest_size, rounds=12000, ident=None, module=__name__): - """create new Pbkdf2DigestHandler subclass for a specific hash""" - name = 'pbkdf2_' + hash_name - if ident is None: - ident = u("$pbkdf2-%s$") % (hash_name,) - base = Pbkdf2DigestHandler - return type(name, (base,), dict( - __module__=module, # so ABCMeta won't clobber it. - name=name, - ident=ident, - _digest = hash_name, - default_rounds=rounds, - checksum_size=digest_size, - encoded_checksum_size=(digest_size*4+2)//3, - __doc__="""This class implements a generic ``PBKDF2-HMAC-%(digest)s``-based password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt bytes. - If specified, the length must be between 0-1024 bytes. - If not specified, a %(dsc)d byte salt will be autogenerated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to %(dsc)d bytes, but can be any value between 0 and 1024. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to %(dr)d, but must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ % dict(digest=hash_name.upper(), dsc=base.default_salt_size, dr=rounds) - )) - -#------------------------------------------------------------------------ -# derived handlers -#------------------------------------------------------------------------ -pbkdf2_sha1 = create_pbkdf2_hash("sha1", 20, 131000, ident=u("$pbkdf2$")) -pbkdf2_sha256 = create_pbkdf2_hash("sha256", 32, 29000) -pbkdf2_sha512 = create_pbkdf2_hash("sha512", 64, 25000) - -ldap_pbkdf2_sha1 = uh.PrefixWrapper("ldap_pbkdf2_sha1", pbkdf2_sha1, "{PBKDF2}", "$pbkdf2$", ident=True) -ldap_pbkdf2_sha256 = uh.PrefixWrapper("ldap_pbkdf2_sha256", pbkdf2_sha256, "{PBKDF2-SHA256}", "$pbkdf2-sha256$", ident=True) -ldap_pbkdf2_sha512 = uh.PrefixWrapper("ldap_pbkdf2_sha512", pbkdf2_sha512, "{PBKDF2-SHA512}", "$pbkdf2-sha512$", ident=True) - -#============================================================================= -# cryptacular's pbkdf2 hash -#============================================================================= - -# bytes used by cta hash for base64 values 63 & 64 -CTA_ALTCHARS = b"-_" - -class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements Cryptacular's PBKDF2-based crypt algorithm, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt bytes. - If specified, it may be any length. - If not specified, a one will be autogenerated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 16 bytes, but can be any value between 0 and 1024. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 60000, must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "cta_pbkdf2_sha1" - setting_kwds = ("salt", "salt_size", "rounds") - ident = u("$p5k2$") - checksum_size = 20 - - # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a - # sanity check. underlying algorithm (and reference implementation) - # allows effectively unbounded values for both of these parameters. - - #--HasSalt-- - default_salt_size = 16 - max_salt_size = 1024 - - #--HasRounds-- - default_rounds = pbkdf2_sha1.default_rounds - min_rounds = 1 - max_rounds = 0xffffffff # setting at 32-bit limit for now - rounds_cost = "linear" - - #=================================================================== - # formatting - #=================================================================== - - # hash $p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0= - # ident $p5k2$ - # rounds 1000 - # salt ZxK4ZBJCfQg= - # chk jJZVscWtO--p1-xIZl6jhO2LKR0= - # NOTE: rounds in hex - - @classmethod - def from_string(cls, hash): - # NOTE: passlib deviation - forbidding zero-padded rounds - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, rounds_base=16, handler=cls) - salt = b64decode(salt.encode("ascii"), CTA_ALTCHARS) - if chk: - chk = b64decode(chk.encode("ascii"), CTA_ALTCHARS) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self): - salt = b64encode(self.salt, CTA_ALTCHARS).decode("ascii") - chk = b64encode(self.checksum, CTA_ALTCHARS).decode("ascii") - return uh.render_mc3(self.ident, self.rounds, salt, chk, rounds_base=16) - - #=================================================================== - # backend - #=================================================================== - def _calc_checksum(self, secret): - # NOTE: pbkdf2_hmac() will encode secret & salt using utf-8 - return pbkdf2_hmac("sha1", secret, self.salt, self.rounds, 20) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# dlitz's pbkdf2 hash -#============================================================================= -class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """This class implements Dwayne Litzenberger's PBKDF2-based crypt algorithm, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If specified, it may be any length, but must use the characters in the regexp range ``[./0-9A-Za-z]``. - If not specified, a 16 character salt will be autogenerated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 16 bytes, but can be any value between 0 and 1024. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 60000, must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "dlitz_pbkdf2_sha1" - setting_kwds = ("salt", "salt_size", "rounds") - ident = u("$p5k2$") - _stub_checksum = u("0" * 48 + "=") - - # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a - # sanity check. underlying algorithm (and reference implementation) - # allows effectively unbounded values for both of these parameters. - - #--HasSalt-- - default_salt_size = 16 - max_salt_size = 1024 - salt_chars = uh.HASH64_CHARS - - #--HasRounds-- - # NOTE: for security, the default here is set to match pbkdf2_sha1, - # even though this hash's extra block makes it twice as slow. - default_rounds = pbkdf2_sha1.default_rounds - min_rounds = 1 - max_rounds = 0xffffffff # setting at 32-bit limit for now - rounds_cost = "linear" - - #=================================================================== - # formatting - #=================================================================== - - # hash $p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g - # ident $p5k2$ - # rounds c - # salt u9HvcT4d - # chk Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g - # rounds in lowercase hex, no zero padding - - @classmethod - def from_string(cls, hash): - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, rounds_base=16, - default_rounds=400, handler=cls) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self): - rounds = self.rounds - if rounds == 400: - rounds = None # omit rounds measurement if == 400 - return uh.render_mc3(self.ident, rounds, self.salt, self.checksum, rounds_base=16) - - def _get_config(self): - rounds = self.rounds - if rounds == 400: - rounds = None # omit rounds measurement if == 400 - return uh.render_mc3(self.ident, rounds, self.salt, None, rounds_base=16) - - #=================================================================== - # backend - #=================================================================== - def _calc_checksum(self, secret): - # NOTE: pbkdf2_hmac() will encode secret & salt using utf-8 - salt = self._get_config() - result = pbkdf2_hmac("sha1", secret, salt, self.rounds, 24) - return ab64_encode(result).decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# crowd -#============================================================================= -class atlassian_pbkdf2_sha1(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements the PBKDF2 hash used by Atlassian. - - It supports a fixed-length salt, and a fixed number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt bytes. - If specified, the length must be exactly 16 bytes. - If not specified, a salt will be autogenerated (this is recommended). - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include - ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #--GenericHandler-- - name = "atlassian_pbkdf2_sha1" - setting_kwds =("salt",) - ident = u("{PKCS5S2}") - checksum_size = 32 - - #--HasRawSalt-- - min_salt_size = max_salt_size = 16 - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - ident = cls.ident - if not hash.startswith(ident): - raise uh.exc.InvalidHashError(cls) - data = b64decode(hash[len(ident):].encode("ascii")) - salt, chk = data[:16], data[16:] - return cls(salt=salt, checksum=chk) - - def to_string(self): - data = self.salt + self.checksum - hash = self.ident + b64encode(data).decode("ascii") - return uascii_to_str(hash) - - def _calc_checksum(self, secret): - # TODO: find out what crowd's policy is re: unicode - # crowd seems to use a fixed number of rounds. - # NOTE: pbkdf2_hmac() will encode secret & salt using utf-8 - return pbkdf2_hmac("sha1", secret, self.salt, 10000, 32) - -#============================================================================= -# grub -#============================================================================= -class grub_pbkdf2_sha512(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler): - """This class implements Grub's pbkdf2-hmac-sha512 hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: bytes - :param salt: - Optional salt bytes. - If specified, the length must be between 0-1024 bytes. - If not specified, a 64 byte salt will be autogenerated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 64 bytes, but can be any value between 0 and 1024. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 19000, but must be within ``range(1,1<<32)``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - name = "grub_pbkdf2_sha512" - setting_kwds = ("salt", "salt_size", "rounds") - - ident = u("grub.pbkdf2.sha512.") - checksum_size = 64 - - # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a - # sanity check. the underlying pbkdf2 specifies no bounds for either, - # and it's not clear what grub specifies. - - default_salt_size = 64 - max_salt_size = 1024 - - default_rounds = pbkdf2_sha512.default_rounds - min_rounds = 1 - max_rounds = 0xffffffff # setting at 32-bit limit for now - rounds_cost = "linear" - - @classmethod - def from_string(cls, hash): - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, sep=u("."), - handler=cls) - salt = unhexlify(salt.encode("ascii")) - if chk: - chk = unhexlify(chk.encode("ascii")) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self): - salt = hexlify(self.salt).decode("ascii").upper() - chk = hexlify(self.checksum).decode("ascii").upper() - return uh.render_mc3(self.ident, self.rounds, salt, chk, sep=u(".")) - - def _calc_checksum(self, secret): - # TODO: find out what grub's policy is re: unicode - # NOTE: pbkdf2_hmac() will encode secret & salt using utf-8 - return pbkdf2_hmac("sha512", secret, self.salt, self.rounds, 64) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/phpass.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/phpass.py deleted file mode 100644 index 6736f0f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/phpass.py +++ /dev/null @@ -1,135 +0,0 @@ -"""passlib.handlers.phpass - PHPass Portable Crypt - -phppass located - http://www.openwall.com/phpass/ -algorithm described - http://www.openwall.com/articles/PHP-Users-Passwords - -phpass context - blowfish, bsdi_crypt, phpass -""" -#============================================================================= -# imports -#============================================================================= -# core -from hashlib import md5 -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils.binary import h64 -from passlib.utils.compat import u, uascii_to_str, unicode -import passlib.utils.handlers as uh -# local -__all__ = [ - "phpass", -] - -#============================================================================= -# phpass -#============================================================================= -class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """This class implements the PHPass Portable Hash, and follows the :ref:`password-hash-api`. - - It supports a fixed-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 8 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 19, must be between 7 and 30, inclusive. - This value is logarithmic, the actual number of iterations used will be :samp:`2**{rounds}`. - - :type ident: str - :param ident: - phpBB3 uses ``H`` instead of ``P`` for its identifier, - this may be set to ``H`` in order to generate phpBB3 compatible hashes. - it defaults to ``P``. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "phpass" - setting_kwds = ("salt", "rounds", "ident") - checksum_chars = uh.HASH64_CHARS - - #--HasSalt-- - min_salt_size = max_salt_size = 8 - salt_chars = uh.HASH64_CHARS - - #--HasRounds-- - default_rounds = 19 - min_rounds = 7 - max_rounds = 30 - rounds_cost = "log2" - - #--HasManyIdents-- - default_ident = u("$P$") - ident_values = (u("$P$"), u("$H$")) - ident_aliases = {u("P"):u("$P$"), u("H"):u("$H$")} - - #=================================================================== - # formatting - #=================================================================== - - #$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0 - # $P$ - # 9 - # IQRaTwmf - # eRo7ud9Fh4E2PdI0S3r.L0 - - @classmethod - def from_string(cls, hash): - ident, data = cls._parse_ident(hash) - rounds, salt, chk = data[0], data[1:9], data[9:] - return cls( - ident=ident, - rounds=h64.decode_int6(rounds.encode("ascii")), - salt=salt, - checksum=chk or None, - ) - - def to_string(self): - hash = u("%s%s%s%s") % (self.ident, - h64.encode_int6(self.rounds).decode("ascii"), - self.salt, - self.checksum or u('')) - return uascii_to_str(hash) - - #=================================================================== - # backend - #=================================================================== - def _calc_checksum(self, secret): - # FIXME: can't find definitive policy on how phpass handles non-ascii. - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - real_rounds = 1<`_ - hash names. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - In addition to the standard :ref:`password-hash-api` methods, - this class also provides the following methods for manipulating Passlib - scram hashes in ways useful for pluging into a SCRAM protocol stack: - - .. automethod:: extract_digest_info - .. automethod:: extract_digest_algs - .. automethod:: derive_digest - """ - #=================================================================== - # class attrs - #=================================================================== - - # NOTE: unlike most GenericHandler classes, the 'checksum' attr of - # ScramHandler is actually a map from digest_name -> digest, so - # many of the standard methods have been overridden. - - # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide - # a sanity check; the underlying pbkdf2 specifies no bounds for either. - - #--GenericHandler-- - name = "scram" - setting_kwds = ("salt", "salt_size", "rounds", "algs") - ident = u("$scram$") - - #--HasSalt-- - default_salt_size = 12 - max_salt_size = 1024 - - #--HasRounds-- - default_rounds = 100000 - min_rounds = 1 - max_rounds = 2**32-1 - rounds_cost = "linear" - - #--custom-- - - # default algorithms when creating new hashes. - default_algs = ["sha-1", "sha-256", "sha-512"] - - # list of algs verify prefers to use, in order. - _verify_algs = ["sha-256", "sha-512", "sha-224", "sha-384", "sha-1"] - - #=================================================================== - # instance attrs - #=================================================================== - - # 'checksum' is different from most GenericHandler subclasses, - # in that it contains a dict mapping from alg -> digest, - # or None if no checksum present. - - # list of algorithms to create/compare digests for. - algs = None - - #=================================================================== - # scram frontend helpers - #=================================================================== - @classmethod - def extract_digest_info(cls, hash, alg): - """return (salt, rounds, digest) for specific hash algorithm. - - :type hash: str - :arg hash: - :class:`!scram` hash stored for desired user - - :type alg: str - :arg alg: - Name of digest algorithm (e.g. ``"sha-1"``) requested by client. - - This value is run through :func:`~passlib.crypto.digest.norm_hash_name`, - so it is case-insensitive, and can be the raw SCRAM - mechanism name (e.g. ``"SCRAM-SHA-1"``), the IANA name, - or the hashlib name. - - :raises KeyError: - If the hash does not contain an entry for the requested digest - algorithm. - - :returns: - A tuple containing ``(salt, rounds, digest)``, - where *digest* matches the raw bytes returned by - SCRAM's :func:`Hi` function for the stored password, - the provided *salt*, and the iteration count (*rounds*). - *salt* and *digest* are both raw (unencoded) bytes. - """ - # XXX: this could be sped up by writing custom parsing routine - # that just picks out relevant digest, and doesn't bother - # with full structure validation each time it's called. - alg = norm_hash_name(alg, 'iana') - self = cls.from_string(hash) - chkmap = self.checksum - if not chkmap: - raise ValueError("scram hash contains no digests") - return self.salt, self.rounds, chkmap[alg] - - @classmethod - def extract_digest_algs(cls, hash, format="iana"): - """Return names of all algorithms stored in a given hash. - - :type hash: str - :arg hash: - The :class:`!scram` hash to parse - - :type format: str - :param format: - This changes the naming convention used by the - returned algorithm names. By default the names - are IANA-compatible; possible values are ``"iana"`` or ``"hashlib"``. - - :returns: - Returns a list of digest algorithms; e.g. ``["sha-1"]`` - """ - # XXX: this could be sped up by writing custom parsing routine - # that just picks out relevant names, and doesn't bother - # with full structure validation each time it's called. - algs = cls.from_string(hash).algs - if format == "iana": - return algs - else: - return [norm_hash_name(alg, format) for alg in algs] - - @classmethod - def derive_digest(cls, password, salt, rounds, alg): - """helper to create SaltedPassword digest for SCRAM. - - This performs the step in the SCRAM protocol described as:: - - SaltedPassword := Hi(Normalize(password), salt, i) - - :type password: unicode or utf-8 bytes - :arg password: password to run through digest - - :type salt: bytes - :arg salt: raw salt data - - :type rounds: int - :arg rounds: number of iterations. - - :type alg: str - :arg alg: name of digest to use (e.g. ``"sha-1"``). - - :returns: - raw bytes of ``SaltedPassword`` - """ - if isinstance(password, bytes): - password = password.decode("utf-8") - # NOTE: pbkdf2_hmac() will encode secret & salt using utf-8, - # and handle normalizing alg name. - return pbkdf2_hmac(alg, saslprep(password), salt, rounds) - - #=================================================================== - # serialization - #=================================================================== - - @classmethod - def from_string(cls, hash): - hash = to_native_str(hash, "ascii", "hash") - if not hash.startswith("$scram$"): - raise uh.exc.InvalidHashError(cls) - parts = hash[7:].split("$") - if len(parts) != 3: - raise uh.exc.MalformedHashError(cls) - rounds_str, salt_str, chk_str = parts - - # decode rounds - rounds = int(rounds_str) - if rounds_str != str(rounds): # forbid zero padding, etc. - raise uh.exc.MalformedHashError(cls) - - # decode salt - try: - salt = ab64_decode(salt_str.encode("ascii")) - except TypeError: - raise uh.exc.MalformedHashError(cls) - - # decode algs/digest list - if not chk_str: - # scram hashes MUST have something here. - raise uh.exc.MalformedHashError(cls) - elif "=" in chk_str: - # comma-separated list of 'alg=digest' pairs - algs = None - chkmap = {} - for pair in chk_str.split(","): - alg, digest = pair.split("=") - try: - chkmap[alg] = ab64_decode(digest.encode("ascii")) - except TypeError: - raise uh.exc.MalformedHashError(cls) - else: - # comma-separated list of alg names, no digests - algs = chk_str - chkmap = None - - # return new object - return cls( - rounds=rounds, - salt=salt, - checksum=chkmap, - algs=algs, - ) - - def to_string(self): - salt = bascii_to_str(ab64_encode(self.salt)) - chkmap = self.checksum - chk_str = ",".join( - "%s=%s" % (alg, bascii_to_str(ab64_encode(chkmap[alg]))) - for alg in self.algs - ) - return '$scram$%d$%s$%s' % (self.rounds, salt, chk_str) - - #=================================================================== - # variant constructor - #=================================================================== - @classmethod - def using(cls, default_algs=None, algs=None, **kwds): - # parse aliases - if algs is not None: - assert default_algs is None - default_algs = algs - - # create subclass - subcls = super(scram, cls).using(**kwds) - - # fill in algs - if default_algs is not None: - subcls.default_algs = cls._norm_algs(default_algs) - return subcls - - #=================================================================== - # init - #=================================================================== - def __init__(self, algs=None, **kwds): - super(scram, self).__init__(**kwds) - - # init algs - digest_map = self.checksum - if algs is not None: - if digest_map is not None: - raise RuntimeError("checksum & algs kwds are mutually exclusive") - algs = self._norm_algs(algs) - elif digest_map is not None: - # derive algs list from digest map (if present). - algs = self._norm_algs(digest_map.keys()) - elif self.use_defaults: - algs = list(self.default_algs) - assert self._norm_algs(algs) == algs, "invalid default algs: %r" % (algs,) - else: - raise TypeError("no algs list specified") - self.algs = algs - - def _norm_checksum(self, checksum, relaxed=False): - if not isinstance(checksum, dict): - raise uh.exc.ExpectedTypeError(checksum, "dict", "checksum") - for alg, digest in iteritems(checksum): - if alg != norm_hash_name(alg, 'iana'): - raise ValueError("malformed algorithm name in scram hash: %r" % - (alg,)) - if len(alg) > 9: - raise ValueError("SCRAM limits algorithm names to " - "9 characters: %r" % (alg,)) - if not isinstance(digest, bytes): - raise uh.exc.ExpectedTypeError(digest, "raw bytes", "digests") - # TODO: verify digest size (if digest is known) - if 'sha-1' not in checksum: - # NOTE: required because of SCRAM spec. - raise ValueError("sha-1 must be in algorithm list of scram hash") - return checksum - - @classmethod - def _norm_algs(cls, algs): - """normalize algs parameter""" - if isinstance(algs, native_string_types): - algs = splitcomma(algs) - algs = sorted(norm_hash_name(alg, 'iana') for alg in algs) - if any(len(alg)>9 for alg in algs): - raise ValueError("SCRAM limits alg names to max of 9 characters") - if 'sha-1' not in algs: - # NOTE: required because of SCRAM spec (rfc 5802) - raise ValueError("sha-1 must be in algorithm list of scram hash") - return algs - - #=================================================================== - # migration - #=================================================================== - def _calc_needs_update(self, **kwds): - # marks hashes as deprecated if they don't include at least all default_algs. - # XXX: should we deprecate if they aren't exactly the same, - # to permit removing legacy hashes? - if not set(self.algs).issuperset(self.default_algs): - return True - - # hand off to base implementation - return super(scram, self)._calc_needs_update(**kwds) - - #=================================================================== - # digest methods - #=================================================================== - def _calc_checksum(self, secret, alg=None): - rounds = self.rounds - salt = self.salt - hash = self.derive_digest - if alg: - # if requested, generate digest for specific alg - return hash(secret, salt, rounds, alg) - else: - # by default, return dict containing digests for all algs - return dict( - (alg, hash(secret, salt, rounds, alg)) - for alg in self.algs - ) - - @classmethod - def verify(cls, secret, hash, full=False): - uh.validate_secret(secret) - self = cls.from_string(hash) - chkmap = self.checksum - if not chkmap: - raise ValueError("expected %s hash, got %s config string instead" % - (cls.name, cls.name)) - - # NOTE: to make the verify method efficient, we just calculate hash - # of shortest digest by default. apps can pass in "full=True" to - # check entire hash for consistency. - if full: - correct = failed = False - for alg, digest in iteritems(chkmap): - other = self._calc_checksum(secret, alg) - # NOTE: could do this length check in norm_algs(), - # but don't need to be that strict, and want to be able - # to parse hashes containing algs not supported by platform. - # it's fine if we fail here though. - if len(digest) != len(other): - raise ValueError("mis-sized %s digest in scram hash: %r != %r" - % (alg, len(digest), len(other))) - if consteq(other, digest): - correct = True - else: - failed = True - if correct and failed: - raise ValueError("scram hash verified inconsistently, " - "may be corrupted") - else: - return correct - else: - # XXX: should this just always use sha1 hash? would be faster. - # otherwise only verify against one hash, pick one w/ best security. - for alg in self._verify_algs: - if alg in chkmap: - other = self._calc_checksum(secret, alg) - return consteq(other, chkmap[alg]) - # there should always be sha-1 at the very least, - # or something went wrong inside _norm_algs() - raise AssertionError("sha-1 digest not found!") - - #=================================================================== - # - #=================================================================== - -#============================================================================= -# code used for testing scram against protocol examples during development. -#============================================================================= -##def _test_reference_scram(): -## "quick hack testing scram reference vectors" -## # NOTE: "n,," is GS2 header - see https://tools.ietf.org/html/rfc5801 -## from passlib.utils.compat import print_ -## -## engine = _scram_engine( -## alg="sha-1", -## salt='QSXCR+Q6sek8bf92'.decode("base64"), -## rounds=4096, -## password=u("pencil"), -## ) -## print_(engine.digest.encode("base64").rstrip()) -## -## msg = engine.format_auth_msg( -## username="user", -## client_nonce = "fyko+d2lbbFgONRv9qkxdawL", -## server_nonce = "3rfcNHYJY1ZVvWVs7j", -## header='c=biws', -## ) -## -## cp = engine.get_encoded_client_proof(msg) -## assert cp == "v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=", cp -## -## ss = engine.get_encoded_server_sig(msg) -## assert ss == "rmF9pqV8S7suAoZWja4dJRkFsKQ=", ss -## -##class _scram_engine(object): -## """helper class for verifying scram hash behavior -## against SCRAM protocol examples. not officially part of Passlib. -## -## takes in alg, salt, rounds, and a digest or password. -## -## can calculate the various keys & messages of the scram protocol. -## -## """ -## #========================================================= -## # init -## #========================================================= -## -## @classmethod -## def from_string(cls, hash, alg): -## "create record from scram hash, for given alg" -## return cls(alg, *scram.extract_digest_info(hash, alg)) -## -## def __init__(self, alg, salt, rounds, digest=None, password=None): -## self.alg = norm_hash_name(alg) -## self.salt = salt -## self.rounds = rounds -## self.password = password -## if password: -## data = scram.derive_digest(password, salt, rounds, alg) -## if digest and data != digest: -## raise ValueError("password doesn't match digest") -## else: -## digest = data -## elif not digest: -## raise TypeError("must provide password or digest") -## self.digest = digest -## -## #========================================================= -## # frontend methods -## #========================================================= -## def get_hash(self, data): -## "return hash of raw data" -## return hashlib.new(iana_to_hashlib(self.alg), data).digest() -## -## def get_client_proof(self, msg): -## "return client proof of specified auth msg text" -## return xor_bytes(self.client_key, self.get_client_sig(msg)) -## -## def get_encoded_client_proof(self, msg): -## return self.get_client_proof(msg).encode("base64").rstrip() -## -## def get_client_sig(self, msg): -## "return client signature of specified auth msg text" -## return self.get_hmac(self.stored_key, msg) -## -## def get_server_sig(self, msg): -## "return server signature of specified auth msg text" -## return self.get_hmac(self.server_key, msg) -## -## def get_encoded_server_sig(self, msg): -## return self.get_server_sig(msg).encode("base64").rstrip() -## -## def format_server_response(self, client_nonce, server_nonce): -## return 'r={client_nonce}{server_nonce},s={salt},i={rounds}'.format( -## client_nonce=client_nonce, -## server_nonce=server_nonce, -## rounds=self.rounds, -## salt=self.encoded_salt, -## ) -## -## def format_auth_msg(self, username, client_nonce, server_nonce, -## header='c=biws'): -## return ( -## 'n={username},r={client_nonce}' -## ',' -## 'r={client_nonce}{server_nonce},s={salt},i={rounds}' -## ',' -## '{header},r={client_nonce}{server_nonce}' -## ).format( -## username=username, -## client_nonce=client_nonce, -## server_nonce=server_nonce, -## salt=self.encoded_salt, -## rounds=self.rounds, -## header=header, -## ) -## -## #========================================================= -## # helpers to calculate & cache constant data -## #========================================================= -## def _calc_get_hmac(self): -## return get_prf("hmac-" + iana_to_hashlib(self.alg))[0] -## -## def _calc_client_key(self): -## return self.get_hmac(self.digest, b("Client Key")) -## -## def _calc_stored_key(self): -## return self.get_hash(self.client_key) -## -## def _calc_server_key(self): -## return self.get_hmac(self.digest, b("Server Key")) -## -## def _calc_encoded_salt(self): -## return self.salt.encode("base64").rstrip() -## -## #========================================================= -## # hacks for calculated attributes -## #========================================================= -## -## def __getattr__(self, attr): -## if not attr.startswith("_"): -## f = getattr(self, "_calc_" + attr, None) -## if f: -## value = f() -## setattr(self, attr, value) -## return value -## raise AttributeError("attribute not found") -## -## def __dir__(self): -## cdir = dir(self.__class__) -## attrs = set(cdir) -## attrs.update(self.__dict__) -## attrs.update(attr[6:] for attr in cdir -## if attr.startswith("_calc_")) -## return sorted(attrs) -## #========================================================= -## # eoc -## #========================================================= - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/scrypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/scrypt.py deleted file mode 100644 index 1686fda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/scrypt.py +++ /dev/null @@ -1,383 +0,0 @@ -"""passlib.handlers.scrypt -- scrypt password hash""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, absolute_import -# core -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.crypto import scrypt as _scrypt -from passlib.utils import h64, to_bytes -from passlib.utils.binary import h64, b64s_decode, b64s_encode -from passlib.utils.compat import u, bascii_to_str, suppress_cause -from passlib.utils.decor import classproperty -import passlib.utils.handlers as uh -# local -__all__ = [ - "scrypt", -] - -#============================================================================= -# scrypt format identifiers -#============================================================================= - -IDENT_SCRYPT = u("$scrypt$") # identifier used by passlib -IDENT_7 = u("$7$") # used by official scrypt spec - -_UDOLLAR = u("$") - -#============================================================================= -# handler -#============================================================================= -class scrypt(uh.ParallelismMixin, uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.HasManyIdents, - uh.GenericHandler): - """This class implements an SCrypt-based password [#scrypt-home]_ hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, a variable number of rounds, - as well as some custom tuning parameters unique to scrypt (see below). - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If specified, the length must be between 0-1024 bytes. - If not specified, one will be auto-generated (this is recommended). - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 16 bytes, but can be any value between 0 and 1024. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 16, but must be within ``range(1,32)``. - - .. warning:: - - Unlike many hash algorithms, increasing the rounds value - will increase both the time *and memory* required to hash a password. - - :type block_size: int - :param block_size: - Optional block size to pass to scrypt hash function (the ``r`` parameter). - Useful for tuning scrypt to optimal performance for your CPU architecture. - Defaults to 8. - - :type parallelism: int - :param parallelism: - Optional parallelism to pass to scrypt hash function (the ``p`` parameter). - Defaults to 1. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. note:: - - The underlying scrypt hash function has a number of limitations - on it's parameter values, which forbids certain combinations of settings. - The requirements are: - - * ``linear_rounds = 2**`` - * ``linear_rounds < 2**(16 * block_size)`` - * ``block_size * parallelism <= 2**30-1`` - - .. todo:: - - This class currently does not support configuring default values - for ``block_size`` or ``parallelism`` via a :class:`~passlib.context.CryptContext` - configuration. - """ - - #=================================================================== - # class attrs - #=================================================================== - - #------------------------ - # PasswordHash - #------------------------ - name = "scrypt" - setting_kwds = ("ident", "salt", "salt_size", "rounds", "block_size", "parallelism") - - #------------------------ - # GenericHandler - #------------------------ - # NOTE: scrypt supports arbitrary output sizes. since it's output runs through - # pbkdf2-hmac-sha256 before returning, and this could be raised eventually... - # but a 256-bit digest is more than sufficient for password hashing. - # XXX: make checksum size configurable? could merge w/ argon2 code that does this. - checksum_size = 32 - - #------------------------ - # HasManyIdents - #------------------------ - default_ident = IDENT_SCRYPT - ident_values = (IDENT_SCRYPT, IDENT_7) - - #------------------------ - # HasRawSalt - #------------------------ - default_salt_size = 16 - max_salt_size = 1024 - - #------------------------ - # HasRounds - #------------------------ - # TODO: would like to dynamically pick this based on system - default_rounds = 16 - min_rounds = 1 - max_rounds = 31 # limited by scrypt alg - rounds_cost = "log2" - - # TODO: make default block size configurable via using(), and deprecatable via .needs_update() - - #=================================================================== - # instance attrs - #=================================================================== - - #: default parallelism setting (min=1 currently hardcoded in mixin) - parallelism = 1 - - #: default block size setting - block_size = 8 - - #=================================================================== - # variant constructor - #=================================================================== - - @classmethod - def using(cls, block_size=None, **kwds): - subcls = super(scrypt, cls).using(**kwds) - if block_size is not None: - if isinstance(block_size, uh.native_string_types): - block_size = int(block_size) - subcls.block_size = subcls._norm_block_size(block_size, relaxed=kwds.get("relaxed")) - - # make sure param combination is valid for scrypt() - try: - _scrypt.validate(1 << cls.default_rounds, cls.block_size, cls.parallelism) - except ValueError as err: - raise suppress_cause(ValueError("scrypt: invalid settings combination: " + str(err))) - - return subcls - - #=================================================================== - # parsing - #=================================================================== - - @classmethod - def from_string(cls, hash): - return cls(**cls.parse(hash)) - - @classmethod - def parse(cls, hash): - ident, suffix = cls._parse_ident(hash) - func = getattr(cls, "_parse_%s_string" % ident.strip(_UDOLLAR), None) - if func: - return func(suffix) - else: - raise uh.exc.InvalidHashError(cls) - - # - # passlib's format: - # $scrypt$ln=,r=,p=

    $[$] - # where: - # logN, r, p -- decimal-encoded positive integer, no zero-padding - # logN -- log cost setting - # r -- block size setting (usually 8) - # p -- parallelism setting (usually 1) - # salt, digest -- b64-nopad encoded bytes - # - - @classmethod - def _parse_scrypt_string(cls, suffix): - # break params, salt, and digest sections - parts = suffix.split("$") - if len(parts) == 3: - params, salt, digest = parts - elif len(parts) == 2: - params, salt = parts - digest = None - else: - raise uh.exc.MalformedHashError(cls, "malformed hash") - - # break params apart - parts = params.split(",") - if len(parts) == 3: - nstr, bstr, pstr = parts - assert nstr.startswith("ln=") - assert bstr.startswith("r=") - assert pstr.startswith("p=") - else: - raise uh.exc.MalformedHashError(cls, "malformed settings field") - - return dict( - ident=IDENT_SCRYPT, - rounds=int(nstr[3:]), - block_size=int(bstr[2:]), - parallelism=int(pstr[2:]), - salt=b64s_decode(salt.encode("ascii")), - checksum=b64s_decode(digest.encode("ascii")) if digest else None, - ) - - # - # official format specification defined at - # https://gitlab.com/jas/scrypt-unix-crypt/blob/master/unix-scrypt.txt - # format: - # $7$[$] - # 0 12345 67890 1 - # where: - # All bytes use h64-little-endian encoding - # N: 6-bit log cost setting - # r: 30-bit block size setting - # p: 30-bit parallelism setting - # salt: variable length salt bytes - # digest: fixed 32-byte digest - # - - @classmethod - def _parse_7_string(cls, suffix): - # XXX: annoyingly, official spec embeds salt *raw*, yet doesn't specify a hash encoding. - # so assuming only h64 chars are valid for salt, and are ASCII encoded. - - # split into params & digest - parts = suffix.encode("ascii").split(b"$") - if len(parts) == 2: - params, digest = parts - elif len(parts) == 1: - params, = parts - digest = None - else: - raise uh.exc.MalformedHashError() - - # parse params & return - if len(params) < 11: - raise uh.exc.MalformedHashError(cls, "params field too short") - return dict( - ident=IDENT_7, - rounds=h64.decode_int6(params[:1]), - block_size=h64.decode_int30(params[1:6]), - parallelism=h64.decode_int30(params[6:11]), - salt=params[11:], - checksum=h64.decode_bytes(digest) if digest else None, - ) - - #=================================================================== - # formatting - #=================================================================== - def to_string(self): - ident = self.ident - if ident == IDENT_SCRYPT: - return "$scrypt$ln=%d,r=%d,p=%d$%s$%s" % ( - self.rounds, - self.block_size, - self.parallelism, - bascii_to_str(b64s_encode(self.salt)), - bascii_to_str(b64s_encode(self.checksum)), - ) - else: - assert ident == IDENT_7 - salt = self.salt - try: - salt.decode("ascii") - except UnicodeDecodeError: - raise suppress_cause(NotImplementedError("scrypt $7$ hashes dont support non-ascii salts")) - return bascii_to_str(b"".join([ - b"$7$", - h64.encode_int6(self.rounds), - h64.encode_int30(self.block_size), - h64.encode_int30(self.parallelism), - self.salt, - b"$", - h64.encode_bytes(self.checksum) - ])) - - #=================================================================== - # init - #=================================================================== - def __init__(self, block_size=None, **kwds): - super(scrypt, self).__init__(**kwds) - - # init block size - if block_size is None: - assert uh.validate_default_value(self, self.block_size, self._norm_block_size, - param="block_size") - else: - self.block_size = self._norm_block_size(block_size) - - # NOTE: if hash contains invalid complex constraint, relying on error - # being raised by scrypt call in _calc_checksum() - - @classmethod - def _norm_block_size(cls, block_size, relaxed=False): - return uh.norm_integer(cls, block_size, min=1, param="block_size", relaxed=relaxed) - - def _generate_salt(self): - salt = super(scrypt, self)._generate_salt() - if self.ident == IDENT_7: - # this format doesn't support non-ascii salts. - # as workaround, we take raw bytes, encoded to base64 - salt = b64s_encode(salt) - return salt - - #=================================================================== - # backend configuration - # NOTE: this following HasManyBackends' API, but provides it's own implementation, - # which actually switches the backend that 'passlib.crypto.scrypt.scrypt()' uses. - #=================================================================== - - @classproperty - def backends(cls): - return _scrypt.backend_values - - @classmethod - def get_backend(cls): - return _scrypt.backend - - @classmethod - def has_backend(cls, name="any"): - try: - cls.set_backend(name, dryrun=True) - return True - except uh.exc.MissingBackendError: - return False - - @classmethod - def set_backend(cls, name="any", dryrun=False): - _scrypt._set_backend(name, dryrun=dryrun) - - #=================================================================== - # digest calculation - #=================================================================== - def _calc_checksum(self, secret): - secret = to_bytes(secret, param="secret") - return _scrypt.scrypt(secret, self.salt, n=(1 << self.rounds), r=self.block_size, - p=self.parallelism, keylen=self.checksum_size) - - #=================================================================== - # hash migration - #=================================================================== - - def _calc_needs_update(self, **kwds): - """ - mark hash as needing update if rounds is outside desired bounds. - """ - # XXX: for now, marking all hashes which don't have matching block_size setting - if self.block_size != type(self).block_size: - return True - return super(scrypt, self)._calc_needs_update(**kwds) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha1_crypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha1_crypt.py deleted file mode 100644 index 8f9aa71..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha1_crypt.py +++ /dev/null @@ -1,158 +0,0 @@ -"""passlib.handlers.sha1_crypt -""" - -#============================================================================= -# imports -#============================================================================= - -# core -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import safe_crypt, test_crypt -from passlib.utils.binary import h64 -from passlib.utils.compat import u, unicode, irange -from passlib.crypto.digest import compile_hmac -import passlib.utils.handlers as uh -# local -__all__ = [ -] -#============================================================================= -# sha1-crypt -#============================================================================= -_BNULL = b'\x00' - -class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """This class implements the SHA1-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, an 8 character one will be autogenerated (this is recommended). - If specified, it must be 0-64 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type salt_size: int - :param salt_size: - Optional number of bytes to use when autogenerating new salts. - Defaults to 8 bytes, but can be any value between 0 and 64. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 480000, must be between 1 and 4294967295, inclusive. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - - #=================================================================== - # class attrs - #=================================================================== - #--GenericHandler-- - name = "sha1_crypt" - setting_kwds = ("salt", "salt_size", "rounds") - ident = u("$sha1$") - checksum_size = 28 - checksum_chars = uh.HASH64_CHARS - - #--HasSalt-- - default_salt_size = 8 - max_salt_size = 64 - salt_chars = uh.HASH64_CHARS - - #--HasRounds-- - default_rounds = 480000 # current passlib default - min_rounds = 1 # really, this should be higher. - max_rounds = 4294967295 # 32-bit integer limit - rounds_cost = "linear" - - #=================================================================== - # formatting - #=================================================================== - @classmethod - def from_string(cls, hash): - rounds, salt, chk = uh.parse_mc3(hash, cls.ident, handler=cls) - return cls(rounds=rounds, salt=salt, checksum=chk) - - def to_string(self, config=False): - chk = None if config else self.checksum - return uh.render_mc3(self.ident, self.rounds, self.salt, chk) - - #=================================================================== - # backend - #=================================================================== - backends = ("os_crypt", "builtin") - - #--------------------------------------------------------------- - # os_crypt backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_os_crypt(cls): - if test_crypt("test", '$sha1$1$Wq3GL2Vp$C8U25GvfHS8qGHim' - 'ExLaiSFlGkAe'): - cls._set_calc_checksum_backend(cls._calc_checksum_os_crypt) - return True - else: - return False - - def _calc_checksum_os_crypt(self, secret): - config = self.to_string(config=True) - hash = safe_crypt(secret, config) - if hash is None: - # py3's crypt.crypt() can't handle non-utf8 bytes. - # fallback to builtin alg, which is always available. - return self._calc_checksum_builtin(secret) - if not hash.startswith(config) or len(hash) != len(config) + 29: - raise uh.exc.CryptBackendError(self, config, hash) - return hash[-28:] - - #--------------------------------------------------------------- - # builtin backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_builtin(cls): - cls._set_calc_checksum_backend(cls._calc_checksum_builtin) - return True - - def _calc_checksum_builtin(self, secret): - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - if _BNULL in secret: - raise uh.exc.NullPasswordError(self) - rounds = self.rounds - # NOTE: this seed value is NOT the same as the config string - result = (u("%s$sha1$%s") % (self.salt, rounds)).encode("ascii") - # NOTE: this algorithm is essentially PBKDF1, modified to use HMAC. - keyed_hmac = compile_hmac("sha1", secret) - for _ in irange(rounds): - result = keyed_hmac(result) - return h64.encode_transposed_bytes(result, self._chk_offsets).decode("ascii") - - _chk_offsets = [ - 2,1,0, - 5,4,3, - 8,7,6, - 11,10,9, - 14,13,12, - 17,16,15, - 0,19,18, - ] - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha2_crypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha2_crypt.py deleted file mode 100644 index e6060c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sha2_crypt.py +++ /dev/null @@ -1,534 +0,0 @@ -"""passlib.handlers.sha2_crypt - SHA256-Crypt / SHA512-Crypt""" -#============================================================================= -# imports -#============================================================================= -# core -import hashlib -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils import safe_crypt, test_crypt, \ - repeat_string, to_unicode -from passlib.utils.binary import h64 -from passlib.utils.compat import byte_elem_value, u, \ - uascii_to_str, unicode -import passlib.utils.handlers as uh -# local -__all__ = [ - "sha512_crypt", - "sha256_crypt", -] - -#============================================================================= -# pure-python backend, used by both sha256_crypt & sha512_crypt -# when crypt.crypt() backend is not available. -#============================================================================= -_BNULL = b'\x00' - -# pre-calculated offsets used to speed up C digest stage (see notes below). -# sequence generated using the following: - ##perms_order = "p,pp,ps,psp,sp,spp".split(",") - ##def offset(i): - ## key = (("p" if i % 2 else "") + ("s" if i % 3 else "") + - ## ("p" if i % 7 else "") + ("" if i % 2 else "p")) - ## return perms_order.index(key) - ##_c_digest_offsets = [(offset(i), offset(i+1)) for i in range(0,42,2)] -_c_digest_offsets = ( - (0, 3), (5, 1), (5, 3), (1, 2), (5, 1), (5, 3), (1, 3), - (4, 1), (5, 3), (1, 3), (5, 0), (5, 3), (1, 3), (5, 1), - (4, 3), (1, 3), (5, 1), (5, 2), (1, 3), (5, 1), (5, 3), - ) - -# map used to transpose bytes when encoding final sha256_crypt digest -_256_transpose_map = ( - 20, 10, 0, 11, 1, 21, 2, 22, 12, 23, 13, 3, 14, 4, 24, 5, - 25, 15, 26, 16, 6, 17, 7, 27, 8, 28, 18, 29, 19, 9, 30, 31, -) - -# map used to transpose bytes when encoding final sha512_crypt digest -_512_transpose_map = ( - 42, 21, 0, 1, 43, 22, 23, 2, 44, 45, 24, 3, 4, 46, 25, 26, - 5, 47, 48, 27, 6, 7, 49, 28, 29, 8, 50, 51, 30, 9, 10, 52, - 31, 32, 11, 53, 54, 33, 12, 13, 55, 34, 35, 14, 56, 57, 36, 15, - 16, 58, 37, 38, 17, 59, 60, 39, 18, 19, 61, 40, 41, 20, 62, 63, -) - -def _raw_sha2_crypt(pwd, salt, rounds, use_512=False): - """perform raw sha256-crypt / sha512-crypt - - this function provides a pure-python implementation of the internals - for the SHA256-Crypt and SHA512-Crypt algorithms; it doesn't - handle any of the parsing/validation of the hash strings themselves. - - :arg pwd: password chars/bytes to hash - :arg salt: salt chars to use - :arg rounds: linear rounds cost - :arg use_512: use sha512-crypt instead of sha256-crypt mode - - :returns: - encoded checksum chars - """ - #=================================================================== - # init & validate inputs - #=================================================================== - - # NOTE: the setup portion of this algorithm scales ~linearly in time - # with the size of the password, making it vulnerable to a DOS from - # unreasonably large inputs. the following code has some optimizations - # which would make things even worse, using O(pwd_len**2) memory - # when calculating digest P. - # - # to mitigate these two issues: 1) this code switches to a - # O(pwd_len)-memory algorithm for passwords that are much larger - # than average, and 2) Passlib enforces a library-wide max limit on - # the size of passwords it will allow, to prevent this algorithm and - # others from being DOSed in this way (see passlib.exc.PasswordSizeError - # for details). - - # validate secret - if isinstance(pwd, unicode): - # XXX: not sure what official unicode policy is, using this as default - pwd = pwd.encode("utf-8") - assert isinstance(pwd, bytes) - if _BNULL in pwd: - raise uh.exc.NullPasswordError(sha512_crypt if use_512 else sha256_crypt) - pwd_len = len(pwd) - - # validate rounds - assert 1000 <= rounds <= 999999999, "invalid rounds" - # NOTE: spec says out-of-range rounds should be clipped, instead of - # causing an error. this function assumes that's been taken care of - # by the handler class. - - # validate salt - assert isinstance(salt, unicode), "salt not unicode" - salt = salt.encode("ascii") - salt_len = len(salt) - assert salt_len < 17, "salt too large" - # NOTE: spec says salts larger than 16 bytes should be truncated, - # instead of causing an error. this function assumes that's been - # taken care of by the handler class. - - # load sha256/512 specific constants - if use_512: - hash_const = hashlib.sha512 - transpose_map = _512_transpose_map - else: - hash_const = hashlib.sha256 - transpose_map = _256_transpose_map - - #=================================================================== - # digest B - used as subinput to digest A - #=================================================================== - db = hash_const(pwd + salt + pwd).digest() - - #=================================================================== - # digest A - used to initialize first round of digest C - #=================================================================== - # start out with pwd + salt - a_ctx = hash_const(pwd + salt) - a_ctx_update = a_ctx.update - - # add pwd_len bytes of b, repeating b as many times as needed. - a_ctx_update(repeat_string(db, pwd_len)) - - # for each bit in pwd_len: add b if it's 1, or pwd if it's 0 - i = pwd_len - while i: - a_ctx_update(db if i & 1 else pwd) - i >>= 1 - - # finish A - da = a_ctx.digest() - - #=================================================================== - # digest P from password - used instead of password itself - # when calculating digest C. - #=================================================================== - if pwd_len < 96: - # this method is faster under python, but uses O(pwd_len**2) memory; - # so we don't use it for larger passwords to avoid a potential DOS. - dp = repeat_string(hash_const(pwd * pwd_len).digest(), pwd_len) - else: - # this method is slower under python, but uses a fixed amount of memory. - tmp_ctx = hash_const(pwd) - tmp_ctx_update = tmp_ctx.update - i = pwd_len-1 - while i: - tmp_ctx_update(pwd) - i -= 1 - dp = repeat_string(tmp_ctx.digest(), pwd_len) - assert len(dp) == pwd_len - - #=================================================================== - # digest S - used instead of salt itself when calculating digest C - #=================================================================== - ds = hash_const(salt * (16 + byte_elem_value(da[0]))).digest()[:salt_len] - assert len(ds) == salt_len, "salt_len somehow > hash_len!" - - #=================================================================== - # digest C - for a variable number of rounds, combine A, S, and P - # digests in various ways; in order to burn CPU time. - #=================================================================== - - # NOTE: the original SHA256/512-Crypt specification performs the C digest - # calculation using the following loop: - # - ##dc = da - ##i = 0 - ##while i < rounds: - ## tmp_ctx = hash_const(dp if i & 1 else dc) - ## if i % 3: - ## tmp_ctx.update(ds) - ## if i % 7: - ## tmp_ctx.update(dp) - ## tmp_ctx.update(dc if i & 1 else dp) - ## dc = tmp_ctx.digest() - ## i += 1 - # - # The code Passlib uses (below) implements an equivalent algorithm, - # it's just been heavily optimized to pre-calculate a large number - # of things beforehand. It works off of a couple of observations - # about the original algorithm: - # - # 1. each round is a combination of 'dc', 'ds', and 'dp'; determined - # by the whether 'i' a multiple of 2,3, and/or 7. - # 2. since lcm(2,3,7)==42, the series of combinations will repeat - # every 42 rounds. - # 3. even rounds 0-40 consist of 'hash(dc + round-specific-constant)'; - # while odd rounds 1-41 consist of hash(round-specific-constant + dc) - # - # Using these observations, the following code... - # * calculates the round-specific combination of ds & dp for each round 0-41 - # * runs through as many 42-round blocks as possible - # * runs through as many pairs of rounds as possible for remaining rounds - # * performs once last round if the total rounds should be odd. - # - # this cuts out a lot of the control overhead incurred when running the - # original loop 40,000+ times in python, resulting in ~20% increase in - # speed under CPython (though still 2x slower than glibc crypt) - - # prepare the 6 combinations of ds & dp which are needed - # (order of 'perms' must match how _c_digest_offsets was generated) - dp_dp = dp+dp - dp_ds = dp+ds - perms = [dp, dp_dp, dp_ds, dp_ds+dp, ds+dp, ds+dp_dp] - - # build up list of even-round & odd-round constants, - # and store in 21-element list as (even,odd) pairs. - data = [ (perms[even], perms[odd]) for even, odd in _c_digest_offsets] - - # perform as many full 42-round blocks as possible - dc = da - blocks, tail = divmod(rounds, 42) - while blocks: - for even, odd in data: - dc = hash_const(odd + hash_const(dc + even).digest()).digest() - blocks -= 1 - - # perform any leftover rounds - if tail: - # perform any pairs of rounds - pairs = tail>>1 - for even, odd in data[:pairs]: - dc = hash_const(odd + hash_const(dc + even).digest()).digest() - - # if rounds was odd, do one last round (since we started at 0, - # last round will be an even-numbered round) - if tail & 1: - dc = hash_const(dc + data[pairs][0]).digest() - - #=================================================================== - # encode digest using appropriate transpose map - #=================================================================== - return h64.encode_transposed_bytes(dc, transpose_map).decode("ascii") - -#============================================================================= -# handlers -#============================================================================= -_UROUNDS = u("rounds=") -_UDOLLAR = u("$") -_UZERO = u("0") - -class _SHA2_Common(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, - uh.GenericHandler): - """class containing common code shared by sha256_crypt & sha512_crypt""" - #=================================================================== - # class attrs - #=================================================================== - # name - set by subclass - setting_kwds = ("salt", "rounds", "implicit_rounds", "salt_size") - # ident - set by subclass - checksum_chars = uh.HASH64_CHARS - # checksum_size - set by subclass - - max_salt_size = 16 - salt_chars = uh.HASH64_CHARS - - min_rounds = 1000 # bounds set by spec - max_rounds = 999999999 # bounds set by spec - rounds_cost = "linear" - - _cdb_use_512 = False # flag for _calc_digest_builtin() - _rounds_prefix = None # ident + _UROUNDS - - #=================================================================== - # methods - #=================================================================== - implicit_rounds = False - - def __init__(self, implicit_rounds=None, **kwds): - super(_SHA2_Common, self).__init__(**kwds) - # if user calls hash() w/ 5000 rounds, default to compact form. - if implicit_rounds is None: - implicit_rounds = (self.use_defaults and self.rounds == 5000) - self.implicit_rounds = implicit_rounds - - def _parse_salt(self, salt): - # required per SHA2-crypt spec -- truncate config salts rather than throwing error - return self._norm_salt(salt, relaxed=self.checksum is None) - - def _parse_rounds(self, rounds): - # required per SHA2-crypt spec -- clip config rounds rather than throwing error - return self._norm_rounds(rounds, relaxed=self.checksum is None) - - @classmethod - def from_string(cls, hash): - # basic format this parses - - # $5$[rounds=$][$] - - # TODO: this *could* use uh.parse_mc3(), except that the rounds - # portion has a slightly different grammar. - - # convert to unicode, check for ident prefix, split on dollar signs. - hash = to_unicode(hash, "ascii", "hash") - ident = cls.ident - if not hash.startswith(ident): - raise uh.exc.InvalidHashError(cls) - assert len(ident) == 3 - parts = hash[3:].split(_UDOLLAR) - - # extract rounds value - if parts[0].startswith(_UROUNDS): - assert len(_UROUNDS) == 7 - rounds = parts.pop(0)[7:] - if rounds.startswith(_UZERO) and rounds != _UZERO: - raise uh.exc.ZeroPaddedRoundsError(cls) - rounds = int(rounds) - implicit_rounds = False - else: - rounds = 5000 - implicit_rounds = True - - # rest should be salt and checksum - if len(parts) == 2: - salt, chk = parts - elif len(parts) == 1: - salt = parts[0] - chk = None - else: - raise uh.exc.MalformedHashError(cls) - - # return new object - return cls( - rounds=rounds, - salt=salt, - checksum=chk or None, - implicit_rounds=implicit_rounds, - ) - - def to_string(self): - if self.rounds == 5000 and self.implicit_rounds: - hash = u("%s%s$%s") % (self.ident, self.salt, - self.checksum or u('')) - else: - hash = u("%srounds=%d$%s$%s") % (self.ident, self.rounds, - self.salt, self.checksum or u('')) - return uascii_to_str(hash) - - #=================================================================== - # backends - #=================================================================== - backends = ("os_crypt", "builtin") - - #--------------------------------------------------------------- - # os_crypt backend - #--------------------------------------------------------------- - - #: test hash for OS detection -- provided by subclass - _test_hash = None - - @classmethod - def _load_backend_os_crypt(cls): - if test_crypt(*cls._test_hash): - cls._set_calc_checksum_backend(cls._calc_checksum_os_crypt) - return True - else: - return False - - def _calc_checksum_os_crypt(self, secret): - config = self.to_string() - hash = safe_crypt(secret, config) - if hash is None: - # py3's crypt.crypt() can't handle non-utf8 bytes. - # fallback to builtin alg, which is always available. - return self._calc_checksum_builtin(secret) - # NOTE: avoiding full parsing routine via from_string().checksum, - # and just extracting the bit we need. - cs = self.checksum_size - if not hash.startswith(self.ident) or hash[-cs-1] != _UDOLLAR: - raise uh.exc.CryptBackendError(self, config, hash) - return hash[-cs:] - - #--------------------------------------------------------------- - # builtin backend - #--------------------------------------------------------------- - @classmethod - def _load_backend_builtin(cls): - cls._set_calc_checksum_backend(cls._calc_checksum_builtin) - return True - - def _calc_checksum_builtin(self, secret): - return _raw_sha2_crypt(secret, self.salt, self.rounds, - self._cdb_use_512) - - #=================================================================== - # eoc - #=================================================================== - -class sha256_crypt(_SHA2_Common): - """This class implements the SHA256-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 0-16 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 535000, must be between 1000 and 999999999, inclusive. - - .. note:: - per the official specification, when the rounds parameter is set to 5000, - it may be omitted from the hash string. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. - commented out, currently only supported by :meth:`hash`, and not via :meth:`using`: - - :type implicit_rounds: bool - :param implicit_rounds: - this is an internal option which generally doesn't need to be touched. - - this flag determines whether the hash should omit the rounds parameter - when encoding it to a string; this is only permitted by the spec for rounds=5000, - and the flag is ignored otherwise. the spec requires the two different - encodings be preserved as they are, instead of normalizing them. - """ - #=================================================================== - # class attrs - #=================================================================== - name = "sha256_crypt" - ident = u("$5$") - checksum_size = 43 - # NOTE: using 25/75 weighting of builtin & os_crypt backends - default_rounds = 535000 - - #=================================================================== - # backends - #=================================================================== - _test_hash = ("test", "$5$rounds=1000$test$QmQADEXMG8POI5W" - "Dsaeho0P36yK3Tcrgboabng6bkb/") - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# sha 512 crypt -#============================================================================= -class sha512_crypt(_SHA2_Common): - """This class implements the SHA512-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, one will be autogenerated (this is recommended). - If specified, it must be 0-16 characters, drawn from the regexp range ``[./0-9A-Za-z]``. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 656000, must be between 1000 and 999999999, inclusive. - - .. note:: - per the official specification, when the rounds parameter is set to 5000, - it may be omitted from the hash string. - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - - .. - commented out, currently only supported by :meth:`hash`, and not via :meth:`using`: - - :type implicit_rounds: bool - :param implicit_rounds: - this is an internal option which generally doesn't need to be touched. - - this flag determines whether the hash should omit the rounds parameter - when encoding it to a string; this is only permitted by the spec for rounds=5000, - and the flag is ignored otherwise. the spec requires the two different - encodings be preserved as they are, instead of normalizing them. - """ - - #=================================================================== - # class attrs - #=================================================================== - name = "sha512_crypt" - ident = u("$6$") - checksum_size = 86 - _cdb_use_512 = True - # NOTE: using 25/75 weighting of builtin & os_crypt backends - default_rounds = 656000 - - #=================================================================== - # backend - #=================================================================== - _test_hash = ("test", "$6$rounds=1000$test$2M/Lx6Mtobqj" - "Ljobw0Wmo4Q5OFx5nVLJvmgseatA6oMn" - "yWeBdRDx4DU.1H3eGmse6pgsOgDisWBG" - "I5c7TZauS0") - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sun_md5_crypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sun_md5_crypt.py deleted file mode 100644 index 0eeb4e7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/sun_md5_crypt.py +++ /dev/null @@ -1,363 +0,0 @@ -"""passlib.handlers.sun_md5_crypt - Sun's Md5 Crypt, used on Solaris - -.. warning:: - - This implementation may not reproduce - the original Solaris behavior in some border cases. - See documentation for details. -""" - -#============================================================================= -# imports -#============================================================================= -# core -from hashlib import md5 -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import to_unicode -from passlib.utils.binary import h64 -from passlib.utils.compat import byte_elem_value, irange, u, \ - uascii_to_str, unicode, str_to_bascii -import passlib.utils.handlers as uh -# local -__all__ = [ - "sun_md5_crypt", -] - -#============================================================================= -# backend -#============================================================================= -# constant data used by alg - Hamlet act 3 scene 1 + null char -# exact bytes as in http://www.ibiblio.org/pub/docs/books/gutenberg/etext98/2ws2610.txt -# from Project Gutenberg. - -MAGIC_HAMLET = ( - b"To be, or not to be,--that is the question:--\n" - b"Whether 'tis nobler in the mind to suffer\n" - b"The slings and arrows of outrageous fortune\n" - b"Or to take arms against a sea of troubles,\n" - b"And by opposing end them?--To die,--to sleep,--\n" - b"No more; and by a sleep to say we end\n" - b"The heartache, and the thousand natural shocks\n" - b"That flesh is heir to,--'tis a consummation\n" - b"Devoutly to be wish'd. To die,--to sleep;--\n" - b"To sleep! perchance to dream:--ay, there's the rub;\n" - b"For in that sleep of death what dreams may come,\n" - b"When we have shuffled off this mortal coil,\n" - b"Must give us pause: there's the respect\n" - b"That makes calamity of so long life;\n" - b"For who would bear the whips and scorns of time,\n" - b"The oppressor's wrong, the proud man's contumely,\n" - b"The pangs of despis'd love, the law's delay,\n" - b"The insolence of office, and the spurns\n" - b"That patient merit of the unworthy takes,\n" - b"When he himself might his quietus make\n" - b"With a bare bodkin? who would these fardels bear,\n" - b"To grunt and sweat under a weary life,\n" - b"But that the dread of something after death,--\n" - b"The undiscover'd country, from whose bourn\n" - b"No traveller returns,--puzzles the will,\n" - b"And makes us rather bear those ills we have\n" - b"Than fly to others that we know not of?\n" - b"Thus conscience does make cowards of us all;\n" - b"And thus the native hue of resolution\n" - b"Is sicklied o'er with the pale cast of thought;\n" - b"And enterprises of great pith and moment,\n" - b"With this regard, their currents turn awry,\n" - b"And lose the name of action.--Soft you now!\n" - b"The fair Ophelia!--Nymph, in thy orisons\n" - b"Be all my sins remember'd.\n\x00" #<- apparently null at end of C string is included (test vector won't pass otherwise) -) - -# NOTE: these sequences are pre-calculated iteration ranges used by X & Y loops w/in rounds function below -xr = irange(7) -_XY_ROUNDS = [ - tuple((i,i,i+3) for i in xr), # xrounds 0 - tuple((i,i+1,i+4) for i in xr), # xrounds 1 - tuple((i,i+8,(i+11)&15) for i in xr), # yrounds 0 - tuple((i,(i+9)&15, (i+12)&15) for i in xr), # yrounds 1 -] -del xr - -def raw_sun_md5_crypt(secret, rounds, salt): - """given secret & salt, return encoded sun-md5-crypt checksum""" - global MAGIC_HAMLET - assert isinstance(secret, bytes) - assert isinstance(salt, bytes) - - # validate rounds - if rounds <= 0: - rounds = 0 - real_rounds = 4096 + rounds - # NOTE: spec seems to imply max 'rounds' is 2**32-1 - - # generate initial digest to start off round 0. - # NOTE: algorithm 'salt' includes full config string w/ trailing "$" - result = md5(secret + salt).digest() - assert len(result) == 16 - - # NOTE: many things in this function have been inlined (to speed up the loop - # as much as possible), to the point that this code barely resembles - # the algorithm as described in the docs. in particular: - # - # * all accesses to a given bit have been inlined using the formula - # rbitval(bit) = (rval((bit>>3) & 15) >> (bit & 7)) & 1 - # - # * the calculation of coinflip value R has been inlined - # - # * the conditional division of coinflip value V has been inlined as - # a shift right of 0 or 1. - # - # * the i, i+3, etc iterations are precalculated in lists. - # - # * the round-based conditional division of x & y is now performed - # by choosing an appropriate precalculated list, so that it only - # calculates the 7 bits which will actually be used. - # - X_ROUNDS_0, X_ROUNDS_1, Y_ROUNDS_0, Y_ROUNDS_1 = _XY_ROUNDS - - # NOTE: % appears to be *slightly* slower than &, so we prefer & if possible - - round = 0 - while round < real_rounds: - # convert last result byte string to list of byte-ints for easy access - rval = [ byte_elem_value(c) for c in result ].__getitem__ - - # build up X bit by bit - x = 0 - xrounds = X_ROUNDS_1 if (rval((round>>3) & 15)>>(round & 7)) & 1 else X_ROUNDS_0 - for i, ia, ib in xrounds: - a = rval(ia) - b = rval(ib) - v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1) - x |= ((rval((v>>3)&15)>>(v&7))&1) << i - - # build up Y bit by bit - y = 0 - yrounds = Y_ROUNDS_1 if (rval(((round+64)>>3) & 15)>>(round & 7)) & 1 else Y_ROUNDS_0 - for i, ia, ib in yrounds: - a = rval(ia) - b = rval(ib) - v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1) - y |= ((rval((v>>3)&15)>>(v&7))&1) << i - - # extract x'th and y'th bit, xoring them together to yeild "coin flip" - coin = ((rval(x>>3) >> (x&7)) ^ (rval(y>>3) >> (y&7))) & 1 - - # construct hash for this round - h = md5(result) - if coin: - h.update(MAGIC_HAMLET) - h.update(unicode(round).encode("ascii")) - result = h.digest() - - round += 1 - - # encode output - return h64.encode_transposed_bytes(result, _chk_offsets) - -# NOTE: same offsets as md5_crypt -_chk_offsets = ( - 12,6,0, - 13,7,1, - 14,8,2, - 15,9,3, - 5,10,4, - 11, -) - -#============================================================================= -# handler -#============================================================================= -class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler): - """This class implements the Sun-MD5-Crypt password hash, and follows the :ref:`password-hash-api`. - - It supports a variable-length salt, and a variable number of rounds. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords: - - :type salt: str - :param salt: - Optional salt string. - If not specified, a salt will be autogenerated (this is recommended). - If specified, it must be drawn from the regexp range ``[./0-9A-Za-z]``. - - :type salt_size: int - :param salt_size: - If no salt is specified, this parameter can be used to specify - the size (in characters) of the autogenerated salt. - It currently defaults to 8. - - :type rounds: int - :param rounds: - Optional number of rounds to use. - Defaults to 34000, must be between 0 and 4294963199, inclusive. - - :type bare_salt: bool - :param bare_salt: - Optional flag used to enable an alternate salt digest behavior - used by some hash strings in this scheme. - This flag can be ignored by most users. - Defaults to ``False``. - (see :ref:`smc-bare-salt` for details). - - :type relaxed: bool - :param relaxed: - By default, providing an invalid value for one of the other - keywords will result in a :exc:`ValueError`. If ``relaxed=True``, - and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning` - will be issued instead. Correctable errors include ``rounds`` - that are too small or too large, and ``salt`` strings that are too long. - - .. versionadded:: 1.6 - """ - #=================================================================== - # class attrs - #=================================================================== - name = "sun_md5_crypt" - setting_kwds = ("salt", "rounds", "bare_salt", "salt_size") - checksum_chars = uh.HASH64_CHARS - checksum_size = 22 - - # NOTE: docs say max password length is 255. - # release 9u2 - - # NOTE: not sure if original crypt has a salt size limit, - # all instances that have been seen use 8 chars. - default_salt_size = 8 - max_salt_size = None - salt_chars = uh.HASH64_CHARS - - default_rounds = 34000 # current passlib default - min_rounds = 0 - max_rounds = 4294963199 ##2**32-1-4096 - # XXX: ^ not sure what it does if past this bound... does 32 int roll over? - rounds_cost = "linear" - - ident_values = (u("$md5$"), u("$md5,")) - - #=================================================================== - # instance attrs - #=================================================================== - bare_salt = False # flag to indicate legacy hashes that lack "$$" suffix - - #=================================================================== - # constructor - #=================================================================== - def __init__(self, bare_salt=False, **kwds): - self.bare_salt = bare_salt - super(sun_md5_crypt, self).__init__(**kwds) - - #=================================================================== - # internal helpers - #=================================================================== - @classmethod - def identify(cls, hash): - hash = uh.to_unicode_for_identify(hash) - return hash.startswith(cls.ident_values) - - @classmethod - def from_string(cls, hash): - hash = to_unicode(hash, "ascii", "hash") - - # - # detect if hash specifies rounds value. - # if so, parse and validate it. - # by end, set 'rounds' to int value, and 'tail' containing salt+chk - # - if hash.startswith(u("$md5$")): - rounds = 0 - salt_idx = 5 - elif hash.startswith(u("$md5,rounds=")): - idx = hash.find(u("$"), 12) - if idx == -1: - raise uh.exc.MalformedHashError(cls, "unexpected end of rounds") - rstr = hash[12:idx] - try: - rounds = int(rstr) - except ValueError: - raise uh.exc.MalformedHashError(cls, "bad rounds") - if rstr != unicode(rounds): - raise uh.exc.ZeroPaddedRoundsError(cls) - if rounds == 0: - # NOTE: not sure if this is forbidden by spec or not; - # but allowing it would complicate things, - # and it should never occur anyways. - raise uh.exc.MalformedHashError(cls, "explicit zero rounds") - salt_idx = idx+1 - else: - raise uh.exc.InvalidHashError(cls) - - # - # salt/checksum separation is kinda weird, - # to deal cleanly with some backward-compatible workarounds - # implemented by original implementation. - # - chk_idx = hash.rfind(u("$"), salt_idx) - if chk_idx == -1: - # ''-config for $-hash - salt = hash[salt_idx:] - chk = None - bare_salt = True - elif chk_idx == len(hash)-1: - if chk_idx > salt_idx and hash[-2] == u("$"): - raise uh.exc.MalformedHashError(cls, "too many '$' separators") - # $-config for $$-hash - salt = hash[salt_idx:-1] - chk = None - bare_salt = False - elif chk_idx > 0 and hash[chk_idx-1] == u("$"): - # $$-hash - salt = hash[salt_idx:chk_idx-1] - chk = hash[chk_idx+1:] - bare_salt = False - else: - # $-hash - salt = hash[salt_idx:chk_idx] - chk = hash[chk_idx+1:] - bare_salt = True - - return cls( - rounds=rounds, - salt=salt, - checksum=chk, - bare_salt=bare_salt, - ) - - def to_string(self, _withchk=True): - ss = u('') if self.bare_salt else u('$') - rounds = self.rounds - if rounds > 0: - hash = u("$md5,rounds=%d$%s%s") % (rounds, self.salt, ss) - else: - hash = u("$md5$%s%s") % (self.salt, ss) - if _withchk: - chk = self.checksum - hash = u("%s$%s") % (hash, chk) - return uascii_to_str(hash) - - #=================================================================== - # primary interface - #=================================================================== - # TODO: if we're on solaris, check for native crypt() support. - # this will require extra testing, to make sure native crypt - # actually behaves correctly. of particular importance: - # when using ""-config, make sure to append "$x" to string. - - def _calc_checksum(self, secret): - # NOTE: no reference for how sun_md5_crypt handles unicode - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - config = str_to_bascii(self.to_string(_withchk=False)) - return raw_sun_md5_crypt(secret, self.rounds, config).decode("ascii") - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/windows.py b/backend/venv39/lib/python3.9/site-packages/passlib/handlers/windows.py deleted file mode 100644 index e17beba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/handlers/windows.py +++ /dev/null @@ -1,334 +0,0 @@ -"""passlib.handlers.nthash - Microsoft Windows -related hashes""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify -import logging; log = logging.getLogger(__name__) -from warnings import warn -# site -# pkg -from passlib.utils import to_unicode, right_pad_string -from passlib.utils.compat import unicode -from passlib.crypto.digest import lookup_hash -md4 = lookup_hash("md4").const -import passlib.utils.handlers as uh -# local -__all__ = [ - "lmhash", - "nthash", - "bsd_nthash", - "msdcc", - "msdcc2", -] - -#============================================================================= -# lanman hash -#============================================================================= -class lmhash(uh.TruncateMixin, uh.HasEncodingContext, uh.StaticHandler): - """This class implements the Lan Manager Password hash, and follows the :ref:`password-hash-api`. - - It has no salt and a single fixed round. - - The :meth:`~passlib.ifc.PasswordHash.using` method accepts a single - optional keyword: - - :param bool truncate_error: - By default, this will silently truncate passwords larger than 14 bytes. - Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash` - to raise a :exc:`~passlib.exc.PasswordTruncateError` instead. - - .. versionadded:: 1.7 - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.verify` methods accept a single - optional keyword: - - :type encoding: str - :param encoding: - - This specifies what character encoding LMHASH should use when - calculating digest. It defaults to ``cp437``, the most - common encoding encountered. - - Note that while this class outputs digests in lower-case hexadecimal, - it will accept upper-case as well. - """ - #=================================================================== - # class attrs - #=================================================================== - - #-------------------- - # PasswordHash - #-------------------- - name = "lmhash" - setting_kwds = ("truncate_error",) - - #-------------------- - # GenericHandler - #-------------------- - checksum_chars = uh.HEX_CHARS - checksum_size = 32 - - #-------------------- - # TruncateMixin - #-------------------- - truncate_size = 14 - - #-------------------- - # custom - #-------------------- - default_encoding = "cp437" - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - # check for truncation (during .hash() calls only) - if self.use_defaults: - self._check_truncate_policy(secret) - - return hexlify(self.raw(secret, self.encoding)).decode("ascii") - - # magic constant used by LMHASH - _magic = b"KGS!@#$%" - - @classmethod - def raw(cls, secret, encoding=None): - """encode password using LANMAN hash algorithm. - - :type secret: unicode or utf-8 encoded bytes - :arg secret: secret to hash - :type encoding: str - :arg encoding: - optional encoding to use for unicode inputs. - this defaults to ``cp437``, which is the - common case for most situations. - - :returns: returns string of raw bytes - """ - if not encoding: - encoding = cls.default_encoding - # some nice empircal data re: different encodings is at... - # http://www.openwall.com/lists/john-dev/2011/08/01/2 - # http://www.freerainbowtables.com/phpBB3/viewtopic.php?t=387&p=12163 - from passlib.crypto.des import des_encrypt_block - MAGIC = cls._magic - if isinstance(secret, unicode): - # perform uppercasing while we're still unicode, - # to give a better shot at getting non-ascii chars right. - # (though some codepages do NOT upper-case the same as unicode). - secret = secret.upper().encode(encoding) - elif isinstance(secret, bytes): - # FIXME: just trusting ascii upper will work? - # and if not, how to do codepage specific case conversion? - # we could decode first using , - # but *that* might not always be right. - secret = secret.upper() - else: - raise TypeError("secret must be unicode or bytes") - secret = right_pad_string(secret, 14) - return des_encrypt_block(secret[0:7], MAGIC) + \ - des_encrypt_block(secret[7:14], MAGIC) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# ntlm hash -#============================================================================= -class nthash(uh.StaticHandler): - """This class implements the NT Password hash, and follows the :ref:`password-hash-api`. - - It has no salt and a single fixed round. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. - - Note that while this class outputs lower-case hexadecimal digests, - it will accept upper-case digests as well. - """ - #=================================================================== - # class attrs - #=================================================================== - name = "nthash" - checksum_chars = uh.HEX_CHARS - checksum_size = 32 - - #=================================================================== - # methods - #=================================================================== - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - return hexlify(self.raw(secret)).decode("ascii") - - @classmethod - def raw(cls, secret): - """encode password using MD4-based NTHASH algorithm - - :arg secret: secret as unicode or utf-8 encoded bytes - - :returns: returns string of raw bytes - """ - secret = to_unicode(secret, "utf-8", param="secret") - # XXX: found refs that say only first 128 chars are used. - return md4(secret.encode("utf-16-le")).digest() - - @classmethod - def raw_nthash(cls, secret, hex=False): - warn("nthash.raw_nthash() is deprecated, and will be removed " - "in Passlib 1.8, please use nthash.raw() instead", - DeprecationWarning) - ret = nthash.raw(secret) - return hexlify(ret).decode("ascii") if hex else ret - - #=================================================================== - # eoc - #=================================================================== - -bsd_nthash = uh.PrefixWrapper("bsd_nthash", nthash, prefix="$3$$", ident="$3$$", - doc="""The class support FreeBSD's representation of NTHASH - (which is compatible with the :ref:`modular-crypt-format`), - and follows the :ref:`password-hash-api`. - - It has no salt and a single fixed round. - - The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. - """) - -##class ntlm_pair(object): -## "combined lmhash & nthash" -## name = "ntlm_pair" -## setting_kwds = () -## _hash_regex = re.compile(u"^(?P[0-9a-f]{32}):(?P[0-9][a-f]{32})$", -## re.I) -## -## @classmethod -## def identify(cls, hash): -## hash = to_unicode(hash, "latin-1", "hash") -## return len(hash) == 65 and cls._hash_regex.match(hash) is not None -## -## @classmethod -## def hash(cls, secret, config=None): -## if config is not None and not cls.identify(config): -## raise uh.exc.InvalidHashError(cls) -## return lmhash.hash(secret) + ":" + nthash.hash(secret) -## -## @classmethod -## def verify(cls, secret, hash): -## hash = to_unicode(hash, "ascii", "hash") -## m = cls._hash_regex.match(hash) -## if not m: -## raise uh.exc.InvalidHashError(cls) -## lm, nt = m.group("lm", "nt") -## # NOTE: verify against both in case encoding issue -## # causes one not to match. -## return lmhash.verify(secret, lm) or nthash.verify(secret, nt) - -#============================================================================= -# msdcc v1 -#============================================================================= -class msdcc(uh.HasUserContext, uh.StaticHandler): - """This class implements Microsoft's Domain Cached Credentials password hash, - and follows the :ref:`password-hash-api`. - - It has a fixed number of rounds, and uses the associated - username as the salt. - - The :meth:`~passlib.ifc.PasswordHash.hash`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods - have the following optional keywords: - - :type user: str - :param user: - String containing name of user account this password is associated with. - This is required to properly calculate the hash. - - This keyword is case-insensitive, and should contain just the username - (e.g. ``Administrator``, not ``SOMEDOMAIN\\Administrator``). - - Note that while this class outputs lower-case hexadecimal digests, - it will accept upper-case digests as well. - """ - name = "msdcc" - checksum_chars = uh.HEX_CHARS - checksum_size = 32 - - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - return hexlify(self.raw(secret, self.user)).decode("ascii") - - @classmethod - def raw(cls, secret, user): - """encode password using mscash v1 algorithm - - :arg secret: secret as unicode or utf-8 encoded bytes - :arg user: username to use as salt - - :returns: returns string of raw bytes - """ - secret = to_unicode(secret, "utf-8", param="secret").encode("utf-16-le") - user = to_unicode(user, "utf-8", param="user").lower().encode("utf-16-le") - return md4(md4(secret).digest() + user).digest() - -#============================================================================= -# msdcc2 aka mscash2 -#============================================================================= -class msdcc2(uh.HasUserContext, uh.StaticHandler): - """This class implements version 2 of Microsoft's Domain Cached Credentials - password hash, and follows the :ref:`password-hash-api`. - - It has a fixed number of rounds, and uses the associated - username as the salt. - - The :meth:`~passlib.ifc.PasswordHash.hash`, :meth:`~passlib.ifc.PasswordHash.genhash`, and :meth:`~passlib.ifc.PasswordHash.verify` methods - have the following extra keyword: - - :type user: str - :param user: - String containing name of user account this password is associated with. - This is required to properly calculate the hash. - - This keyword is case-insensitive, and should contain just the username - (e.g. ``Administrator``, not ``SOMEDOMAIN\\Administrator``). - """ - name = "msdcc2" - checksum_chars = uh.HEX_CHARS - checksum_size = 32 - - @classmethod - def _norm_hash(cls, hash): - return hash.lower() - - def _calc_checksum(self, secret): - return hexlify(self.raw(secret, self.user)).decode("ascii") - - @classmethod - def raw(cls, secret, user): - """encode password using msdcc v2 algorithm - - :type secret: unicode or utf-8 bytes - :arg secret: secret - - :type user: str - :arg user: username to use as salt - - :returns: returns string of raw bytes - """ - from passlib.crypto.digest import pbkdf2_hmac - secret = to_unicode(secret, "utf-8", param="secret").encode("utf-16-le") - user = to_unicode(user, "utf-8", param="user").lower().encode("utf-16-le") - tmp = md4(md4(secret).digest() + user).digest() - return pbkdf2_hmac("sha1", tmp, user, 10240, 16) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/hash.py b/backend/venv39/lib/python3.9/site-packages/passlib/hash.py deleted file mode 100644 index 2cc0628..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/hash.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -passlib.hash - proxy object mapping hash scheme names -> handlers - -================== -***** NOTICE ***** -================== - -This module does not actually contain any hashes. This file -is a stub that replaces itself with a proxy object. - -This proxy object (passlib.registry._PasslibRegistryProxy) -handles lazy-loading hashes as they are requested. - -The actual implementation of the various hashes is store elsewhere, -mainly in the submodules of the ``passlib.handlers`` subpackage. -""" - -#============================================================================= -# import proxy object and replace this module -#============================================================================= - -# XXX: if any platform has problem w/ lazy modules, could support 'non-lazy' -# version which just imports all schemes known to list_crypt_handlers() - -from passlib.registry import _proxy -import sys -sys.modules[__name__] = _proxy - -#============================================================================= -# HACK: the following bit of code is unreachable, but it's presence seems to -# help make autocomplete work for certain IDEs such as PyCharm. -# this list is automatically regenerated using $SOURCE/admin/regen.py -#============================================================================= - -#---------------------------------------------------- -# begin autocomplete hack (autogenerated 2016-11-10) -#---------------------------------------------------- -if False: - from passlib.handlers.argon2 import argon2 - from passlib.handlers.bcrypt import bcrypt, bcrypt_sha256 - from passlib.handlers.cisco import cisco_asa, cisco_pix, cisco_type7 - from passlib.handlers.des_crypt import bigcrypt, bsdi_crypt, crypt16, des_crypt - from passlib.handlers.digests import hex_md4, hex_md5, hex_sha1, hex_sha256, hex_sha512, htdigest - from passlib.handlers.django import django_bcrypt, django_bcrypt_sha256, django_des_crypt, django_disabled, django_pbkdf2_sha1, django_pbkdf2_sha256, django_salted_md5, django_salted_sha1 - from passlib.handlers.fshp import fshp - from passlib.handlers.ldap_digests import ldap_bcrypt, ldap_bsdi_crypt, ldap_des_crypt, ldap_md5, ldap_md5_crypt, ldap_plaintext, ldap_salted_md5, ldap_salted_sha1, ldap_salted_sha256, ldap_salted_sha512, ldap_sha1, ldap_sha1_crypt, ldap_sha256_crypt, ldap_sha512_crypt - from passlib.handlers.md5_crypt import apr_md5_crypt, md5_crypt - from passlib.handlers.misc import plaintext, unix_disabled, unix_fallback - from passlib.handlers.mssql import mssql2000, mssql2005 - from passlib.handlers.mysql import mysql323, mysql41 - from passlib.handlers.oracle import oracle10, oracle11 - from passlib.handlers.pbkdf2 import atlassian_pbkdf2_sha1, cta_pbkdf2_sha1, dlitz_pbkdf2_sha1, grub_pbkdf2_sha512, ldap_pbkdf2_sha1, ldap_pbkdf2_sha256, ldap_pbkdf2_sha512, pbkdf2_sha1, pbkdf2_sha256, pbkdf2_sha512 - from passlib.handlers.phpass import phpass - from passlib.handlers.postgres import postgres_md5 - from passlib.handlers.roundup import ldap_hex_md5, ldap_hex_sha1, roundup_plaintext - from passlib.handlers.scram import scram - from passlib.handlers.scrypt import scrypt - from passlib.handlers.sha1_crypt import sha1_crypt - from passlib.handlers.sha2_crypt import sha256_crypt, sha512_crypt - from passlib.handlers.sun_md5_crypt import sun_md5_crypt - from passlib.handlers.windows import bsd_nthash, lmhash, msdcc, msdcc2, nthash -#---------------------------------------------------- -# end autocomplete hack -#---------------------------------------------------- - -#============================================================================= -# eoc -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/hosts.py b/backend/venv39/lib/python3.9/site-packages/passlib/hosts.py deleted file mode 100644 index 1f137a2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/hosts.py +++ /dev/null @@ -1,106 +0,0 @@ -"""passlib.hosts""" -#============================================================================= -# imports -#============================================================================= -# core -from warnings import warn -# pkg -from passlib.context import LazyCryptContext -from passlib.exc import PasslibRuntimeWarning -from passlib import registry -from passlib.utils import has_crypt, unix_crypt_schemes -# local -__all__ = [ - "linux_context", "linux2_context", - "openbsd_context", - "netbsd_context", - "freebsd_context", - "host_context", -] - -#============================================================================= -# linux support -#============================================================================= - -# known platform names - linux2 - -linux_context = linux2_context = LazyCryptContext( - schemes = [ "sha512_crypt", "sha256_crypt", "md5_crypt", - "des_crypt", "unix_disabled" ], - deprecated = [ "des_crypt" ], - ) - -#============================================================================= -# bsd support -#============================================================================= - -# known platform names - -# freebsd2 -# freebsd3 -# freebsd4 -# freebsd5 -# freebsd6 -# freebsd7 -# -# netbsd1 - -# referencing source via -http://fxr.googlebit.com -# freebsd 6,7,8 - des, md5, bcrypt, bsd_nthash -# netbsd - des, ext, md5, bcrypt, sha1 -# openbsd - des, ext, md5, bcrypt - -freebsd_context = LazyCryptContext(["bcrypt", "md5_crypt", "bsd_nthash", - "des_crypt", "unix_disabled"]) - -openbsd_context = LazyCryptContext(["bcrypt", "md5_crypt", "bsdi_crypt", - "des_crypt", "unix_disabled"]) - -netbsd_context = LazyCryptContext(["bcrypt", "sha1_crypt", "md5_crypt", - "bsdi_crypt", "des_crypt", "unix_disabled"]) - -# XXX: include darwin in this list? it's got a BSD crypt variant, -# but that's not what it uses for user passwords. - -#============================================================================= -# current host -#============================================================================= -if registry.os_crypt_present: - # NOTE: this is basically mimicing the output of os crypt(), - # except that it uses passlib's (usually stronger) defaults settings, - # and can be inspected and used much more flexibly. - - def _iter_os_crypt_schemes(): - """helper which iterates over supported os_crypt schemes""" - out = registry.get_supported_os_crypt_schemes() - if out: - # only offer disabled handler if there's another scheme in front, - # as this can't actually hash any passwords - out += ("unix_disabled",) - return out - - host_context = LazyCryptContext(_iter_os_crypt_schemes()) - -#============================================================================= -# other platforms -#============================================================================= - -# known platform strings - -# aix3 -# aix4 -# atheos -# beos5 -# darwin -# generic -# hp-ux11 -# irix5 -# irix6 -# mac -# next3 -# os2emx -# riscos -# sunos5 -# unixware7 - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/ifc.py b/backend/venv39/lib/python3.9/site-packages/passlib/ifc.py deleted file mode 100644 index 559d256..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/ifc.py +++ /dev/null @@ -1,353 +0,0 @@ -"""passlib.ifc - abstract interfaces used by Passlib""" -#============================================================================= -# imports -#============================================================================= -# core -import logging; log = logging.getLogger(__name__) -import sys -# site -# pkg -from passlib.utils.decor import deprecated_method -# local -__all__ = [ - "PasswordHash", -] - -#============================================================================= -# 2/3 compatibility helpers -#============================================================================= -def recreate_with_metaclass(meta): - """class decorator that re-creates class using metaclass""" - def builder(cls): - if meta is type(cls): - return cls - return meta(cls.__name__, cls.__bases__, cls.__dict__.copy()) - return builder - -#============================================================================= -# PasswordHash interface -#============================================================================= -from abc import ABCMeta, abstractmethod, abstractproperty - -# TODO: make this actually use abstractproperty(), -# now that we dropped py25, 'abc' is always available. - -# XXX: rename to PasswordHasher? - -@recreate_with_metaclass(ABCMeta) -class PasswordHash(object): - """This class describes an abstract interface which all password hashes - in Passlib adhere to. Under Python 2.6 and up, this is an actual - Abstract Base Class built using the :mod:`!abc` module. - - See the Passlib docs for full documentation. - """ - #=================================================================== - # class attributes - #=================================================================== - - #--------------------------------------------------------------- - # general information - #--------------------------------------------------------------- - ##name - ##setting_kwds - ##context_kwds - - #: flag which indicates this hasher matches a "disabled" hash - #: (e.g. unix_disabled, or django_disabled); and doesn't actually - #: depend on the provided password. - is_disabled = False - - #: Should be None, or a positive integer indicating hash - #: doesn't support secrets larger than this value. - #: Whether hash throws error or silently truncates secret - #: depends on .truncate_error and .truncate_verify_reject flags below. - #: NOTE: calls may treat as boolean, since value will never be 0. - #: .. versionadded:: 1.7 - #: .. TODO: passlib 1.8: deprecate/rename this attr to "max_secret_size"? - truncate_size = None - - # NOTE: these next two default to the optimistic "ideal", - # most hashes in passlib have to default to False - # for backward compat and/or expected behavior with existing hashes. - - #: If True, .hash() should throw a :exc:`~passlib.exc.PasswordSizeError` for - #: any secrets larger than .truncate_size. Many hashers default to False - #: for historical / compatibility purposes, indicating they will silently - #: truncate instead. All such hashers SHOULD support changing - #: the policy via ``.using(truncate_error=True)``. - #: .. versionadded:: 1.7 - #: .. TODO: passlib 1.8: deprecate/rename this attr to "truncate_hash_error"? - truncate_error = True - - #: If True, .verify() should reject secrets larger than max_password_size. - #: Many hashers default to False for historical / compatibility purposes, - #: indicating they will match on the truncated portion instead. - #: .. versionadded:: 1.7.1 - truncate_verify_reject = True - - #--------------------------------------------------------------- - # salt information -- if 'salt' in setting_kwds - #--------------------------------------------------------------- - ##min_salt_size - ##max_salt_size - ##default_salt_size - ##salt_chars - ##default_salt_chars - - #--------------------------------------------------------------- - # rounds information -- if 'rounds' in setting_kwds - #--------------------------------------------------------------- - ##min_rounds - ##max_rounds - ##default_rounds - ##rounds_cost - - #--------------------------------------------------------------- - # encoding info -- if 'encoding' in context_kwds - #--------------------------------------------------------------- - ##default_encoding - - #=================================================================== - # primary methods - #=================================================================== - @classmethod - @abstractmethod - def hash(cls, secret, # * - **setting_and_context_kwds): # pragma: no cover -- abstract method - r""" - Hash secret, returning result. - Should handle generating salt, etc, and should return string - containing identifier, salt & other configuration, as well as digest. - - :param \\*\\*settings_kwds: - - Pass in settings to customize configuration of resulting hash. - - .. deprecated:: 1.7 - - Starting with Passlib 1.7, callers should no longer pass settings keywords - (e.g. ``rounds`` or ``salt`` directly to :meth:`!hash`); should use - ``.using(**settings).hash(secret)`` construction instead. - - Support will be removed in Passlib 2.0. - - :param \\*\\*context_kwds: - - Specific algorithms may require context-specific information (such as the user login). - """ - # FIXME: need stub for classes that define .encrypt() instead ... - # this should call .encrypt(), and check for recursion back to here. - raise NotImplementedError("must be implemented by subclass") - - @deprecated_method(deprecated="1.7", removed="2.0", replacement=".hash()") - @classmethod - def encrypt(cls, *args, **kwds): - """ - Legacy alias for :meth:`hash`. - - .. deprecated:: 1.7 - This method was renamed to :meth:`!hash` in version 1.7. - This alias will be removed in version 2.0, and should only - be used for compatibility with Passlib 1.3 - 1.6. - """ - return cls.hash(*args, **kwds) - - # XXX: could provide default implementation which hands value to - # hash(), and then does constant-time comparision on the result - # (after making both are same string type) - @classmethod - @abstractmethod - def verify(cls, secret, hash, **context_kwds): # pragma: no cover -- abstract method - """verify secret against hash, returns True/False""" - raise NotImplementedError("must be implemented by subclass") - - #=================================================================== - # configuration - #=================================================================== - @classmethod - @abstractmethod - def using(cls, relaxed=False, **kwds): - """ - Return another hasher object (typically a subclass of the current one), - which integrates the configuration options specified by ``kwds``. - This should *always* return a new object, even if no configuration options are changed. - - .. todo:: - - document which options are accepted. - - :returns: - typically returns a subclass for most hasher implementations. - - .. todo:: - - add this method to main documentation. - """ - raise NotImplementedError("must be implemented by subclass") - - #=================================================================== - # migration - #=================================================================== - @classmethod - def needs_update(cls, hash, secret=None): - """ - check if hash's configuration is outside desired bounds, - or contains some other internal option which requires - updating the password hash. - - :param hash: - hash string to examine - - :param secret: - optional secret known to have verified against the provided hash. - (this is used by some hashes to detect legacy algorithm mistakes). - - :return: - whether secret needs re-hashing. - - .. versionadded:: 1.7 - """ - # by default, always report that we don't need update - return False - - #=================================================================== - # additional methods - #=================================================================== - @classmethod - @abstractmethod - def identify(cls, hash): # pragma: no cover -- abstract method - """check if hash belongs to this scheme, returns True/False""" - raise NotImplementedError("must be implemented by subclass") - - @deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genconfig(cls, **setting_kwds): # pragma: no cover -- abstract method - """ - compile settings into a configuration string for genhash() - - .. deprecated:: 1.7 - - As of 1.7, this method is deprecated, and slated for complete removal in Passlib 2.0. - - For all known real-world uses, hashing a constant string - should provide equivalent functionality. - - This deprecation may be reversed if a use-case presents itself in the mean time. - """ - # NOTE: this fallback runs full hash alg, w/ whatever cost param is passed along. - # implementations (esp ones w/ variable cost) will want to subclass this - # with a constant-time implementation that just renders a config string. - if cls.context_kwds: - raise NotImplementedError("must be implemented by subclass") - return cls.using(**setting_kwds).hash("") - - @deprecated_method(deprecated="1.7", removed="2.0") - @classmethod - def genhash(cls, secret, config, **context): - """ - generated hash for secret, using settings from config/hash string - - .. deprecated:: 1.7 - - As of 1.7, this method is deprecated, and slated for complete removal in Passlib 2.0. - - This deprecation may be reversed if a use-case presents itself in the mean time. - """ - # XXX: if hashes reliably offered a .parse() method, could make a fallback for this. - raise NotImplementedError("must be implemented by subclass") - - #=================================================================== - # undocumented methods / attributes - #=================================================================== - # the following entry points are used internally by passlib, - # and aren't documented as part of the exposed interface. - # they are subject to change between releases, - # but are documented here so there's a list of them *somewhere*. - - #--------------------------------------------------------------- - # extra metdata - #--------------------------------------------------------------- - - #: this attribute shouldn't be used by hashers themselves, - #: it's reserved for the CryptContext to track which hashers are deprecated. - #: Note the context will only set this on objects it owns (and generated by .using()), - #: and WONT set it on global objects. - #: [added in 1.7] - #: TODO: document this, or at least the use of testing for - #: 'CryptContext().handler().deprecated' - deprecated = False - - #: optionally present if hasher corresponds to format built into Django. - #: this attribute (if not None) should be the Django 'algorithm' name. - #: also indicates to passlib.ext.django that (when installed in django), - #: django's native hasher should be used in preference to this one. - ## django_name - - #--------------------------------------------------------------- - # checksum information - defined for many hashes - #--------------------------------------------------------------- - ## checksum_chars - ## checksum_size - - #--------------------------------------------------------------- - # experimental methods - #--------------------------------------------------------------- - - ##@classmethod - ##def normhash(cls, hash): - ## """helper to clean up non-canonic instances of hash. - ## currently only provided by bcrypt() to fix an historical passlib issue. - ## """ - - # experimental helper to parse hash into components. - ##@classmethod - ##def parsehash(cls, hash, checksum=True, sanitize=False): - ## """helper to parse hash into components, returns dict""" - - # experiment helper to estimate bitsize of different hashes, - # implement for GenericHandler, but may be currently be off for some hashes. - # want to expand this into a way to programmatically compare - # "strengths" of different hashes and hash algorithms. - # still needs to have some factor for estimate relative cost per round, - # ala in the style of the scrypt whitepaper. - ##@classmethod - ##def bitsize(cls, **kwds): - ## """returns dict mapping component -> bits contributed. - ## components currently include checksum, salt, rounds. - ## """ - - #=================================================================== - # eoc - #=================================================================== - -class DisabledHash(PasswordHash): - """ - extended disabled-hash methods; only need be present if .disabled = True - """ - - is_disabled = True - - @classmethod - def disable(cls, hash=None): - """ - return string representing a 'disabled' hash; - optionally including previously enabled hash - (this is up to the individual scheme). - """ - # default behavior: ignore original hash, return standalone marker - return cls.hash("") - - @classmethod - def enable(cls, hash): - """ - given a disabled-hash string, - extract previously-enabled hash if one is present, - otherwise raises ValueError - """ - # default behavior: no way to restore original hash - raise ValueError("cannot restore original hash") - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/pwd.py b/backend/venv39/lib/python3.9/site-packages/passlib/pwd.py deleted file mode 100644 index 27ed228..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/pwd.py +++ /dev/null @@ -1,809 +0,0 @@ -"""passlib.pwd -- password generation helpers""" -#============================================================================= -# imports -#============================================================================= -from __future__ import absolute_import, division, print_function, unicode_literals -# core -import codecs -from collections import defaultdict -try: - from collections.abc import MutableMapping -except ImportError: - # py2 compat - from collections import MutableMapping -from math import ceil, log as logf -import logging; log = logging.getLogger(__name__) -import pkg_resources -import os -# site -# pkg -from passlib import exc -from passlib.utils.compat import PY2, irange, itervalues, int_types -from passlib.utils import rng, getrandstr, to_unicode -from passlib.utils.decor import memoized_property -# local -__all__ = [ - "genword", "default_charsets", - "genphrase", "default_wordsets", -] - -#============================================================================= -# constants -#============================================================================= - -# XXX: rename / publically document this map? -entropy_aliases = dict( - # barest protection from throttled online attack - unsafe=12, - - # some protection from unthrottled online attack - weak=24, - - # some protection from offline attacks - fair=36, - - # reasonable protection from offline attacks - strong=48, - - # very good protection from offline attacks - secure=60, -) - -#============================================================================= -# internal helpers -#============================================================================= - -def _superclasses(obj, cls): - """return remaining classes in object's MRO after cls""" - mro = type(obj).__mro__ - return mro[mro.index(cls)+1:] - - -def _self_info_rate(source): - """ - returns 'rate of self-information' -- - i.e. average (per-symbol) entropy of the sequence **source**, - where probability of a given symbol occurring is calculated based on - the number of occurrences within the sequence itself. - - if all elements of the source are unique, this should equal ``log(len(source), 2)``. - - :arg source: - iterable containing 0+ symbols - (e.g. list of strings or ints, string of characters, etc). - - :returns: - float bits of entropy - """ - try: - size = len(source) - except TypeError: - # if len() doesn't work, calculate size by summing counts later - size = None - counts = defaultdict(int) - for char in source: - counts[char] += 1 - if size is None: - values = counts.values() - size = sum(values) - else: - values = itervalues(counts) - if not size: - return 0 - # NOTE: the following performs ``- sum(value / size * logf(value / size, 2) for value in values)``, - # it just does so with as much pulled out of the sum() loop as possible... - return logf(size, 2) - sum(value * logf(value, 2) for value in values) / size - - -# def _total_self_info(source): -# """ -# return total self-entropy of a sequence -# (the average entropy per symbol * size of sequence) -# """ -# return _self_info_rate(source) * len(source) - - -def _open_asset_path(path, encoding=None): - """ - :param asset_path: - string containing absolute path to file, - or package-relative path using format - ``"python.module:relative/file/path"``. - - :returns: - filehandle opened in 'rb' mode - (unless encoding explicitly specified) - """ - if encoding: - return codecs.getreader(encoding)(_open_asset_path(path)) - if os.path.isabs(path): - return open(path, "rb") - package, sep, subpath = path.partition(":") - if not sep: - raise ValueError("asset path must be absolute file path " - "or use 'pkg.name:sub/path' format: %r" % (path,)) - return pkg_resources.resource_stream(package, subpath) - - -#: type aliases -_sequence_types = (list, tuple) -_set_types = (set, frozenset) - -#: set of elements that ensure_unique() has validated already. -_ensure_unique_cache = set() - - -def _ensure_unique(source, param="source"): - """ - helper for generators -- - Throws ValueError if source elements aren't unique. - Error message will display (abbreviated) repr of the duplicates in a string/list - """ - # check cache to speed things up for frozensets / tuples / strings - cache = _ensure_unique_cache - hashable = True - try: - if source in cache: - return True - except TypeError: - hashable = False - - # check if it has dup elements - if isinstance(source, _set_types) or len(set(source)) == len(source): - if hashable: - try: - cache.add(source) - except TypeError: - # XXX: under pypy, "list() in set()" above doesn't throw TypeError, - # but trying to add unhashable it to a set *does*. - pass - return True - - # build list of duplicate values - seen = set() - dups = set() - for elem in source: - (dups if elem in seen else seen).add(elem) - dups = sorted(dups) - trunc = 8 - if len(dups) > trunc: - trunc = 5 - dup_repr = ", ".join(repr(str(word)) for word in dups[:trunc]) - if len(dups) > trunc: - dup_repr += ", ... plus %d others" % (len(dups) - trunc) - - # throw error - raise ValueError("`%s` cannot contain duplicate elements: %s" % - (param, dup_repr)) - -#============================================================================= -# base generator class -#============================================================================= -class SequenceGenerator(object): - """ - Base class used by word & phrase generators. - - These objects take a series of options, corresponding - to those of the :func:`generate` function. - They act as callables which can be used to generate a password - or a list of 1+ passwords. They also expose some read-only - informational attributes. - - Parameters - ---------- - :param entropy: - Optionally specify the amount of entropy the resulting passwords - should contain (as measured with respect to the generator itself). - This will be used to auto-calculate the required password size. - - :param length: - Optionally specify the length of password to generate, - measured as count of whatever symbols the subclass uses (characters or words). - Note if ``entropy`` requires a larger minimum length, - that will be used instead. - - :param rng: - Optionally provide a custom RNG source to use. - Should be an instance of :class:`random.Random`, - defaults to :class:`random.SystemRandom`. - - Attributes - ---------- - .. autoattribute:: length - .. autoattribute:: symbol_count - .. autoattribute:: entropy_per_symbol - .. autoattribute:: entropy - - Subclassing - ----------- - Subclasses must implement the ``.__next__()`` method, - and set ``.symbol_count`` before calling base ``__init__`` method. - """ - #============================================================================= - # instance attrs - #============================================================================= - - #: requested size of final password - length = None - - #: requested entropy of final password - requested_entropy = "strong" - - #: random number source to use - rng = rng - - #: number of potential symbols (must be filled in by subclass) - symbol_count = None - - #============================================================================= - # init - #============================================================================= - def __init__(self, entropy=None, length=None, rng=None, **kwds): - - # make sure subclass set things up correctly - assert self.symbol_count is not None, "subclass must set .symbol_count" - - # init length & requested entropy - if entropy is not None or length is None: - if entropy is None: - entropy = self.requested_entropy - entropy = entropy_aliases.get(entropy, entropy) - if entropy <= 0: - raise ValueError("`entropy` must be positive number") - min_length = int(ceil(entropy / self.entropy_per_symbol)) - if length is None or length < min_length: - length = min_length - - self.requested_entropy = entropy - - if length < 1: - raise ValueError("`length` must be positive integer") - self.length = length - - # init other common options - if rng is not None: - self.rng = rng - - # hand off to parent - if kwds and _superclasses(self, SequenceGenerator) == (object,): - raise TypeError("Unexpected keyword(s): %s" % ", ".join(kwds.keys())) - super(SequenceGenerator, self).__init__(**kwds) - - #============================================================================= - # informational helpers - #============================================================================= - - @memoized_property - def entropy_per_symbol(self): - """ - Average entropy per symbol (assuming all symbols have equal probability) - """ - return logf(self.symbol_count, 2) - - @memoized_property - def entropy(self): - """ - Effective entropy of generated passwords. - - This value will always be a multiple of :attr:`entropy_per_symbol`. - If entropy is specified in constructor, :attr:`length` will be chosen so - so that this value is the smallest multiple >= :attr:`requested_entropy`. - """ - return self.length * self.entropy_per_symbol - - #============================================================================= - # generation - #============================================================================= - def __next__(self): - """main generation function, should create one password/phrase""" - raise NotImplementedError("implement in subclass") - - def __call__(self, returns=None): - """ - frontend used by genword() / genphrase() to create passwords - """ - if returns is None: - return next(self) - elif isinstance(returns, int_types): - return [next(self) for _ in irange(returns)] - elif returns is iter: - return self - else: - raise exc.ExpectedTypeError(returns, ", int, or ", "returns") - - def __iter__(self): - return self - - if PY2: - def next(self): - return self.__next__() - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# default charsets -#============================================================================= - -#: global dict of predefined characters sets -default_charsets = dict( - # ascii letters, digits, and some punctuation - ascii_72='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*?/', - - # ascii letters and digits - ascii_62='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', - - # ascii_50, without visually similar '1IiLl', '0Oo', '5S', '8B' - ascii_50='234679abcdefghjkmnpqrstuvwxyzACDEFGHJKMNPQRTUVWXYZ', - - # lower case hexadecimal - hex='0123456789abcdef', -) - -#============================================================================= -# password generator -#============================================================================= - -class WordGenerator(SequenceGenerator): - """ - Class which generates passwords by randomly choosing from a string of unique characters. - - Parameters - ---------- - :param chars: - custom character string to draw from. - - :param charset: - predefined charset to draw from. - - :param \\*\\*kwds: - all other keywords passed to the :class:`SequenceGenerator` parent class. - - Attributes - ---------- - .. autoattribute:: chars - .. autoattribute:: charset - .. autoattribute:: default_charsets - """ - #============================================================================= - # instance attrs - #============================================================================= - - #: Predefined character set in use (set to None for instances using custom 'chars') - charset = "ascii_62" - - #: string of chars to draw from -- usually filled in from charset - chars = None - - #============================================================================= - # init - #============================================================================= - def __init__(self, chars=None, charset=None, **kwds): - - # init chars and charset - if chars: - if charset: - raise TypeError("`chars` and `charset` are mutually exclusive") - else: - if not charset: - charset = self.charset - assert charset - chars = default_charsets[charset] - self.charset = charset - chars = to_unicode(chars, param="chars") - _ensure_unique(chars, param="chars") - self.chars = chars - - # hand off to parent - super(WordGenerator, self).__init__(**kwds) - # log.debug("WordGenerator(): entropy/char=%r", self.entropy_per_symbol) - - #============================================================================= - # informational helpers - #============================================================================= - - @memoized_property - def symbol_count(self): - return len(self.chars) - - #============================================================================= - # generation - #============================================================================= - - def __next__(self): - # XXX: could do things like optionally ensure certain character groups - # (e.g. letters & punctuation) are included - return getrandstr(self.rng, self.chars, self.length) - - #============================================================================= - # eoc - #============================================================================= - - -def genword(entropy=None, length=None, returns=None, **kwds): - """Generate one or more random passwords. - - This function uses :mod:`random.SystemRandom` to generate - one or more passwords using various character sets. - The complexity of the password can be specified - by size, or by the desired amount of entropy. - - Usage Example:: - - >>> # generate a random alphanumeric string with 48 bits of entropy (the default) - >>> from passlib import pwd - >>> pwd.genword() - 'DnBHvDjMK6' - - >>> # generate a random hexadecimal string with 52 bits of entropy - >>> pwd.genword(entropy=52, charset="hex") - '310f1a7ac793f' - - :param entropy: - Strength of resulting password, measured in 'guessing entropy' bits. - An appropriate **length** value will be calculated - based on the requested entropy amount, and the size of the character set. - - This can be a positive integer, or one of the following preset - strings: ``"weak"`` (24), ``"fair"`` (36), - ``"strong"`` (48), and ``"secure"`` (56). - - If neither this or **length** is specified, **entropy** will default - to ``"strong"`` (48). - - :param length: - Size of resulting password, measured in characters. - If omitted, the size is auto-calculated based on the **entropy** parameter. - - If both **entropy** and **length** are specified, - the stronger value will be used. - - :param returns: - Controls what this function returns: - - * If ``None`` (the default), this function will generate a single password. - * If an integer, this function will return a list containing that many passwords. - * If the ``iter`` constant, will return an iterator that yields passwords. - - :param chars: - - Optionally specify custom string of characters to use when randomly - generating a password. This option cannot be combined with **charset**. - - :param charset: - - The predefined character set to draw from (if not specified by **chars**). - There are currently four presets available: - - * ``"ascii_62"`` (the default) -- all digits and ascii upper & lowercase letters. - Provides ~5.95 entropy per character. - - * ``"ascii_50"`` -- subset which excludes visually similar characters - (``1IiLl0Oo5S8B``). Provides ~5.64 entropy per character. - - * ``"ascii_72"`` -- all digits and ascii upper & lowercase letters, - as well as some punctuation. Provides ~6.17 entropy per character. - - * ``"hex"`` -- Lower case hexadecimal. Providers 4 bits of entropy per character. - - :returns: - :class:`!unicode` string containing randomly generated password; - or list of 1+ passwords if :samp:`returns={int}` is specified. - """ - gen = WordGenerator(length=length, entropy=entropy, **kwds) - return gen(returns) - -#============================================================================= -# default wordsets -#============================================================================= - -def _load_wordset(asset_path): - """ - load wordset from compressed datafile within package data. - file should be utf-8 encoded - - :param asset_path: - string containing absolute path to wordset file, - or "python.module:relative/file/path". - - :returns: - tuple of words, as loaded from specified words file. - """ - # open resource file, convert to tuple of words (strip blank lines & ws) - with _open_asset_path(asset_path, "utf-8") as fh: - gen = (word.strip() for word in fh) - words = tuple(word for word in gen if word) - - # NOTE: works but not used - # # detect if file uses " " format, and strip numeric prefix - # def extract(row): - # idx, word = row.replace("\t", " ").split(" ", 1) - # if not idx.isdigit(): - # raise ValueError("row is not dice index + word") - # return word - # try: - # extract(words[-1]) - # except ValueError: - # pass - # else: - # words = tuple(extract(word) for word in words) - - log.debug("loaded %d-element wordset from %r", len(words), asset_path) - return words - - -class WordsetDict(MutableMapping): - """ - Special mapping used to store dictionary of wordsets. - Different from a regular dict in that some wordsets - may be lazy-loaded from an asset path. - """ - - #: dict of key -> asset path - paths = None - - #: dict of key -> value - _loaded = None - - def __init__(self, *args, **kwds): - self.paths = {} - self._loaded = {} - super(WordsetDict, self).__init__(*args, **kwds) - - def __getitem__(self, key): - try: - return self._loaded[key] - except KeyError: - pass - path = self.paths[key] - value = self._loaded[key] = _load_wordset(path) - return value - - def set_path(self, key, path): - """ - set asset path to lazy-load wordset from. - """ - self.paths[key] = path - - def __setitem__(self, key, value): - self._loaded[key] = value - - def __delitem__(self, key): - if key in self: - del self._loaded[key] - self.paths.pop(key, None) - else: - del self.paths[key] - - @property - def _keyset(self): - keys = set(self._loaded) - keys.update(self.paths) - return keys - - def __iter__(self): - return iter(self._keyset) - - def __len__(self): - return len(self._keyset) - - # NOTE: speeds things up, and prevents contains from lazy-loading - def __contains__(self, key): - return key in self._loaded or key in self.paths - - -#: dict of predefined word sets. -#: key is name of wordset, value should be sequence of words. -default_wordsets = WordsetDict() - -# register the wordsets built into passlib -for name in "eff_long eff_short eff_prefixed bip39".split(): - default_wordsets.set_path(name, "passlib:_data/wordsets/%s.txt" % name) - -#============================================================================= -# passphrase generator -#============================================================================= -class PhraseGenerator(SequenceGenerator): - """class which generates passphrases by randomly choosing - from a list of unique words. - - :param wordset: - wordset to draw from. - :param preset: - name of preset wordlist to use instead of ``wordset``. - :param spaces: - whether to insert spaces between words in output (defaults to ``True``). - :param \\*\\*kwds: - all other keywords passed to the :class:`SequenceGenerator` parent class. - - .. autoattribute:: wordset - """ - #============================================================================= - # instance attrs - #============================================================================= - - #: predefined wordset to use - wordset = "eff_long" - - #: list of words to draw from - words = None - - #: separator to use when joining words - sep = " " - - #============================================================================= - # init - #============================================================================= - def __init__(self, wordset=None, words=None, sep=None, **kwds): - - # load wordset - if words is not None: - if wordset is not None: - raise TypeError("`words` and `wordset` are mutually exclusive") - else: - if wordset is None: - wordset = self.wordset - assert wordset - words = default_wordsets[wordset] - self.wordset = wordset - - # init words - if not isinstance(words, _sequence_types): - words = tuple(words) - _ensure_unique(words, param="words") - self.words = words - - # init separator - if sep is None: - sep = self.sep - sep = to_unicode(sep, param="sep") - self.sep = sep - - # hand off to parent - super(PhraseGenerator, self).__init__(**kwds) - ##log.debug("PhraseGenerator(): entropy/word=%r entropy/char=%r min_chars=%r", - ## self.entropy_per_symbol, self.entropy_per_char, self.min_chars) - - #============================================================================= - # informational helpers - #============================================================================= - - @memoized_property - def symbol_count(self): - return len(self.words) - - #============================================================================= - # generation - #============================================================================= - - def __next__(self): - words = (self.rng.choice(self.words) for _ in irange(self.length)) - return self.sep.join(words) - - #============================================================================= - # eoc - #============================================================================= - - -def genphrase(entropy=None, length=None, returns=None, **kwds): - """Generate one or more random password / passphrases. - - This function uses :mod:`random.SystemRandom` to generate - one or more passwords; it can be configured to generate - alphanumeric passwords, or full english phrases. - The complexity of the password can be specified - by size, or by the desired amount of entropy. - - Usage Example:: - - >>> # generate random phrase with 48 bits of entropy - >>> from passlib import pwd - >>> pwd.genphrase() - 'gangly robbing salt shove' - - >>> # generate a random phrase with 52 bits of entropy - >>> # using a particular wordset - >>> pwd.genword(entropy=52, wordset="bip39") - 'wheat dilemma reward rescue diary' - - :param entropy: - Strength of resulting password, measured in 'guessing entropy' bits. - An appropriate **length** value will be calculated - based on the requested entropy amount, and the size of the word set. - - This can be a positive integer, or one of the following preset - strings: ``"weak"`` (24), ``"fair"`` (36), - ``"strong"`` (48), and ``"secure"`` (56). - - If neither this or **length** is specified, **entropy** will default - to ``"strong"`` (48). - - :param length: - Length of resulting password, measured in words. - If omitted, the size is auto-calculated based on the **entropy** parameter. - - If both **entropy** and **length** are specified, - the stronger value will be used. - - :param returns: - Controls what this function returns: - - * If ``None`` (the default), this function will generate a single password. - * If an integer, this function will return a list containing that many passwords. - * If the ``iter`` builtin, will return an iterator that yields passwords. - - :param words: - - Optionally specifies a list/set of words to use when randomly generating a passphrase. - This option cannot be combined with **wordset**. - - :param wordset: - - The predefined word set to draw from (if not specified by **words**). - There are currently four presets available: - - ``"eff_long"`` (the default) - - Wordset containing 7776 english words of ~7 letters. - Constructed by the EFF, it offers ~12.9 bits of entropy per word. - - This wordset (and the other ``"eff_"`` wordsets) - were `created by the EFF `_ - to aid in generating passwords. See their announcement page - for more details about the design & properties of these wordsets. - - ``"eff_short"`` - - Wordset containing 1296 english words of ~4.5 letters. - Constructed by the EFF, it offers ~10.3 bits of entropy per word. - - ``"eff_prefixed"`` - - Wordset containing 1296 english words of ~8 letters, - selected so that they each have a unique 3-character prefix. - Constructed by the EFF, it offers ~10.3 bits of entropy per word. - - ``"bip39"`` - - Wordset of 2048 english words of ~5 letters, - selected so that they each have a unique 4-character prefix. - Published as part of Bitcoin's `BIP 39 `_, - this wordset has exactly 11 bits of entropy per word. - - This list offers words that are typically shorter than ``"eff_long"`` - (at the cost of slightly less entropy); and much shorter than - ``"eff_prefixed"`` (at the cost of a longer unique prefix). - - :param sep: - Optional separator to use when joining words. - Defaults to ``" "`` (a space), but can be an empty string, a hyphen, etc. - - :returns: - :class:`!unicode` string containing randomly generated passphrase; - or list of 1+ passphrases if :samp:`returns={int}` is specified. - """ - gen = PhraseGenerator(entropy=entropy, length=length, **kwds) - return gen(returns) - -#============================================================================= -# strength measurement -# -# NOTE: -# for a little while, had rough draft of password strength measurement alg here. -# but not sure if there's value in yet another measurement algorithm, -# that's not just duplicating the effort of libraries like zxcbn. -# may revive it later, but for now, leaving some refs to others out there: -# * NIST 800-63 has simple alg -# * zxcvbn (https://tech.dropbox.com/2012/04/zxcvbn-realistic-password-strength-estimation/) -# might also be good, and has approach similar to composite approach i was already thinking about, -# but much more well thought out. -# * passfault (https://github.com/c-a-m/passfault) looks thorough, -# but may have licensing issues, plus porting to python looks like very big job :( -# * give a look at running things through zlib - might be able to cheaply -# catch extra redundancies. -#============================================================================= - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/registry.py b/backend/venv39/lib/python3.9/site-packages/passlib/registry.py deleted file mode 100644 index 9964b25..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/registry.py +++ /dev/null @@ -1,547 +0,0 @@ -"""passlib.registry - registry for password hash handlers""" -#============================================================================= -# imports -#============================================================================= -# core -import re -import logging; log = logging.getLogger(__name__) -from warnings import warn -# pkg -from passlib import exc -from passlib.exc import ExpectedTypeError, PasslibWarning -from passlib.ifc import PasswordHash -from passlib.utils import ( - is_crypt_handler, has_crypt as os_crypt_present, - unix_crypt_schemes as os_crypt_schemes, -) -from passlib.utils.compat import unicode_or_str -from passlib.utils.decor import memoize_single_value -# local -__all__ = [ - "register_crypt_handler_path", - "register_crypt_handler", - "get_crypt_handler", - "list_crypt_handlers", -] - -#============================================================================= -# proxy object used in place of 'passlib.hash' module -#============================================================================= -class _PasslibRegistryProxy(object): - """proxy module passlib.hash - - this module is in fact an object which lazy-loads - the requested password hash algorithm from wherever it has been stored. - it acts as a thin wrapper around :func:`passlib.registry.get_crypt_handler`. - """ - __name__ = "passlib.hash" - __package__ = None - - def __getattr__(self, attr): - if attr.startswith("_"): - raise AttributeError("missing attribute: %r" % (attr,)) - handler = get_crypt_handler(attr, None) - if handler: - return handler - else: - raise AttributeError("unknown password hash: %r" % (attr,)) - - def __setattr__(self, attr, value): - if attr.startswith("_"): - # writing to private attributes should behave normally. - # (required so GAE can write to the __loader__ attribute). - object.__setattr__(self, attr, value) - else: - # writing to public attributes should be treated - # as attempting to register a handler. - register_crypt_handler(value, _attr=attr) - - def __repr__(self): - return "" - - def __dir__(self): - # this adds in lazy-loaded handler names, - # otherwise this is the standard dir() implementation. - attrs = set(dir(self.__class__)) - attrs.update(self.__dict__) - attrs.update(_locations) - return sorted(attrs) - -# create single instance - available publically as 'passlib.hash' -_proxy = _PasslibRegistryProxy() - -#============================================================================= -# internal registry state -#============================================================================= - -# singleton uses to detect omitted keywords -_UNSET = object() - -# dict mapping name -> loaded handlers (just uses proxy object's internal dict) -_handlers = _proxy.__dict__ - -# dict mapping names -> import path for lazy loading. -# * import path should be "module.path" or "module.path:attr" -# * if attr omitted, "name" used as default. -_locations = dict( - # NOTE: this is a hardcoded list of the handlers built into passlib, - # applications should call register_crypt_handler_path() - apr_md5_crypt = "passlib.handlers.md5_crypt", - argon2 = "passlib.handlers.argon2", - atlassian_pbkdf2_sha1 = "passlib.handlers.pbkdf2", - bcrypt = "passlib.handlers.bcrypt", - bcrypt_sha256 = "passlib.handlers.bcrypt", - bigcrypt = "passlib.handlers.des_crypt", - bsd_nthash = "passlib.handlers.windows", - bsdi_crypt = "passlib.handlers.des_crypt", - cisco_pix = "passlib.handlers.cisco", - cisco_asa = "passlib.handlers.cisco", - cisco_type7 = "passlib.handlers.cisco", - cta_pbkdf2_sha1 = "passlib.handlers.pbkdf2", - crypt16 = "passlib.handlers.des_crypt", - des_crypt = "passlib.handlers.des_crypt", - django_argon2 = "passlib.handlers.django", - django_bcrypt = "passlib.handlers.django", - django_bcrypt_sha256 = "passlib.handlers.django", - django_pbkdf2_sha256 = "passlib.handlers.django", - django_pbkdf2_sha1 = "passlib.handlers.django", - django_salted_sha1 = "passlib.handlers.django", - django_salted_md5 = "passlib.handlers.django", - django_des_crypt = "passlib.handlers.django", - django_disabled = "passlib.handlers.django", - dlitz_pbkdf2_sha1 = "passlib.handlers.pbkdf2", - fshp = "passlib.handlers.fshp", - grub_pbkdf2_sha512 = "passlib.handlers.pbkdf2", - hex_md4 = "passlib.handlers.digests", - hex_md5 = "passlib.handlers.digests", - hex_sha1 = "passlib.handlers.digests", - hex_sha256 = "passlib.handlers.digests", - hex_sha512 = "passlib.handlers.digests", - htdigest = "passlib.handlers.digests", - ldap_plaintext = "passlib.handlers.ldap_digests", - ldap_md5 = "passlib.handlers.ldap_digests", - ldap_sha1 = "passlib.handlers.ldap_digests", - ldap_hex_md5 = "passlib.handlers.roundup", - ldap_hex_sha1 = "passlib.handlers.roundup", - ldap_salted_md5 = "passlib.handlers.ldap_digests", - ldap_salted_sha1 = "passlib.handlers.ldap_digests", - ldap_salted_sha256 = "passlib.handlers.ldap_digests", - ldap_salted_sha512 = "passlib.handlers.ldap_digests", - ldap_des_crypt = "passlib.handlers.ldap_digests", - ldap_bsdi_crypt = "passlib.handlers.ldap_digests", - ldap_md5_crypt = "passlib.handlers.ldap_digests", - ldap_bcrypt = "passlib.handlers.ldap_digests", - ldap_sha1_crypt = "passlib.handlers.ldap_digests", - ldap_sha256_crypt = "passlib.handlers.ldap_digests", - ldap_sha512_crypt = "passlib.handlers.ldap_digests", - ldap_pbkdf2_sha1 = "passlib.handlers.pbkdf2", - ldap_pbkdf2_sha256 = "passlib.handlers.pbkdf2", - ldap_pbkdf2_sha512 = "passlib.handlers.pbkdf2", - lmhash = "passlib.handlers.windows", - md5_crypt = "passlib.handlers.md5_crypt", - msdcc = "passlib.handlers.windows", - msdcc2 = "passlib.handlers.windows", - mssql2000 = "passlib.handlers.mssql", - mssql2005 = "passlib.handlers.mssql", - mysql323 = "passlib.handlers.mysql", - mysql41 = "passlib.handlers.mysql", - nthash = "passlib.handlers.windows", - oracle10 = "passlib.handlers.oracle", - oracle11 = "passlib.handlers.oracle", - pbkdf2_sha1 = "passlib.handlers.pbkdf2", - pbkdf2_sha256 = "passlib.handlers.pbkdf2", - pbkdf2_sha512 = "passlib.handlers.pbkdf2", - phpass = "passlib.handlers.phpass", - plaintext = "passlib.handlers.misc", - postgres_md5 = "passlib.handlers.postgres", - roundup_plaintext = "passlib.handlers.roundup", - scram = "passlib.handlers.scram", - scrypt = "passlib.handlers.scrypt", - sha1_crypt = "passlib.handlers.sha1_crypt", - sha256_crypt = "passlib.handlers.sha2_crypt", - sha512_crypt = "passlib.handlers.sha2_crypt", - sun_md5_crypt = "passlib.handlers.sun_md5_crypt", - unix_disabled = "passlib.handlers.misc", - unix_fallback = "passlib.handlers.misc", -) - -# master regexp for detecting valid handler names -_name_re = re.compile("^[a-z][a-z0-9_]+[a-z0-9]$") - -# names which aren't allowed for various reasons -# (mainly keyword conflicts in CryptContext) -_forbidden_names = frozenset(["onload", "policy", "context", "all", - "default", "none", "auto"]) - -#============================================================================= -# registry frontend functions -#============================================================================= -def _validate_handler_name(name): - """helper to validate handler name - - :raises ValueError: - * if empty name - * if name not lower case - * if name contains double underscores - * if name is reserved (e.g. ``context``, ``all``). - """ - if not name: - raise ValueError("handler name cannot be empty: %r" % (name,)) - if name.lower() != name: - raise ValueError("name must be lower-case: %r" % (name,)) - if not _name_re.match(name): - raise ValueError("invalid name (must be 3+ characters, " - " begin with a-z, and contain only underscore, a-z, " - "0-9): %r" % (name,)) - if '__' in name: - raise ValueError("name may not contain double-underscores: %r" % - (name,)) - if name in _forbidden_names: - raise ValueError("that name is not allowed: %r" % (name,)) - return True - -def register_crypt_handler_path(name, path): - """register location to lazy-load handler when requested. - - custom hashes may be registered via :func:`register_crypt_handler`, - or they may be registered by this function, - which will delay actually importing and loading the handler - until a call to :func:`get_crypt_handler` is made for the specified name. - - :arg name: name of handler - :arg path: module import path - - the specified module path should contain a password hash handler - called :samp:`{name}`, or the path may contain a colon, - specifying the module and module attribute to use. - for example, the following would cause ``get_handler("myhash")`` to look - for a class named ``myhash`` within the ``myapp.helpers`` module:: - - >>> from passlib.registry import registry_crypt_handler_path - >>> registry_crypt_handler_path("myhash", "myapp.helpers") - - ...while this form would cause ``get_handler("myhash")`` to look - for a class name ``MyHash`` within the ``myapp.helpers`` module:: - - >>> from passlib.registry import registry_crypt_handler_path - >>> registry_crypt_handler_path("myhash", "myapp.helpers:MyHash") - """ - # validate name - _validate_handler_name(name) - - # validate path - if path.startswith("."): - raise ValueError("path cannot start with '.'") - if ':' in path: - if path.count(':') > 1: - raise ValueError("path cannot have more than one ':'") - if path.find('.', path.index(':')) > -1: - raise ValueError("path cannot have '.' to right of ':'") - - # store location - _locations[name] = path - log.debug("registered path to %r handler: %r", name, path) - -def register_crypt_handler(handler, force=False, _attr=None): - """register password hash handler. - - this method immediately registers a handler with the internal passlib registry, - so that it will be returned by :func:`get_crypt_handler` when requested. - - :arg handler: the password hash handler to register - :param force: force override of existing handler (defaults to False) - :param _attr: - [internal kwd] if specified, ensures ``handler.name`` - matches this value, or raises :exc:`ValueError`. - - :raises TypeError: - if the specified object does not appear to be a valid handler. - - :raises ValueError: - if the specified object's name (or other required attributes) - contain invalid values. - - :raises KeyError: - if a (different) handler was already registered with - the same name, and ``force=True`` was not specified. - """ - # validate handler - if not is_crypt_handler(handler): - raise ExpectedTypeError(handler, "password hash handler", "handler") - if not handler: - raise AssertionError("``bool(handler)`` must be True") - - # validate name - name = handler.name - _validate_handler_name(name) - if _attr and _attr != name: - raise ValueError("handlers must be stored only under their own name (%r != %r)" % - (_attr, name)) - - # check for existing handler - other = _handlers.get(name) - if other: - if other is handler: - log.debug("same %r handler already registered: %r", name, handler) - return - elif force: - log.warning("overriding previously registered %r handler: %r", - name, other) - else: - raise KeyError("another %r handler has already been registered: %r" % - (name, other)) - - # register handler - _handlers[name] = handler - log.debug("registered %r handler: %r", name, handler) - -def get_crypt_handler(name, default=_UNSET): - """return handler for specified password hash scheme. - - this method looks up a handler for the specified scheme. - if the handler is not already loaded, - it checks if the location is known, and loads it first. - - :arg name: name of handler to return - :param default: optional default value to return if no handler with specified name is found. - - :raises KeyError: if no handler matching that name is found, and no default specified, a KeyError will be raised. - - :returns: handler attached to name, or default value (if specified). - """ - # catch invalid names before we check _handlers, - # since it's a module dict, and exposes things like __package__, etc. - if name.startswith("_"): - if default is _UNSET: - raise KeyError("invalid handler name: %r" % (name,)) - else: - return default - - # check if handler is already loaded - try: - return _handlers[name] - except KeyError: - pass - - # normalize name (and if changed, check dict again) - assert isinstance(name, unicode_or_str), "name must be string instance" - alt = name.replace("-","_").lower() - if alt != name: - warn("handler names should be lower-case, and use underscores instead " - "of hyphens: %r => %r" % (name, alt), PasslibWarning, - stacklevel=2) - name = alt - - # try to load using new name - try: - return _handlers[name] - except KeyError: - pass - - # check if lazy load mapping has been specified for this driver - path = _locations.get(name) - if path: - if ':' in path: - modname, modattr = path.split(":") - else: - modname, modattr = path, name - ##log.debug("loading %r handler from path: '%s:%s'", name, modname, modattr) - - # try to load the module - any import errors indicate runtime config, usually - # either missing package, or bad path provided to register_crypt_handler_path() - mod = __import__(modname, fromlist=[modattr], level=0) - - # first check if importing module triggered register_crypt_handler(), - # (this is discouraged due to its magical implicitness) - handler = _handlers.get(name) - if handler: - # XXX: issue deprecation warning here? - assert is_crypt_handler(handler), "unexpected object: name=%r object=%r" % (name, handler) - return handler - - # then get real handler & register it - handler = getattr(mod, modattr) - register_crypt_handler(handler, _attr=name) - return handler - - # fail! - if default is _UNSET: - raise KeyError("no crypt handler found for algorithm: %r" % (name,)) - else: - return default - -def list_crypt_handlers(loaded_only=False): - """return sorted list of all known crypt handler names. - - :param loaded_only: if ``True``, only returns names of handlers which have actually been loaded. - - :returns: list of names of all known handlers - """ - names = set(_handlers) - if not loaded_only: - names.update(_locations) - # strip private attrs out of namespace and sort. - # TODO: make _handlers a separate list, so we don't have module namespace mixed in. - return sorted(name for name in names if not name.startswith("_")) - -# NOTE: these two functions mainly exist just for the unittests... - -def _has_crypt_handler(name, loaded_only=False): - """check if handler name is known. - - this is only useful for two cases: - - * quickly checking if handler has already been loaded - * checking if handler exists, without actually loading it - - :arg name: name of handler - :param loaded_only: if ``True``, returns False if handler exists but hasn't been loaded - """ - return (name in _handlers) or (not loaded_only and name in _locations) - -def _unload_handler_name(name, locations=True): - """unloads a handler from the registry. - - .. warning:: - - this is an internal function, - used only by the unittests. - - if loaded handler is found with specified name, it's removed. - if path to lazy load handler is found, it's removed. - - missing names are a noop. - - :arg name: name of handler to unload - :param locations: if False, won't purge registered handler locations (default True) - """ - if name in _handlers: - del _handlers[name] - if locations and name in _locations: - del _locations[name] - -#============================================================================= -# inspection helpers -#============================================================================= - -#------------------------------------------------------------------ -# general -#------------------------------------------------------------------ - -# TODO: needs UTs -def _resolve(hasher, param="value"): - """ - internal helper to resolve argument to hasher object - """ - if is_crypt_handler(hasher): - return hasher - elif isinstance(hasher, unicode_or_str): - return get_crypt_handler(hasher) - else: - raise exc.ExpectedTypeError(hasher, unicode_or_str, param) - - -#: backend aliases -ANY = "any" -BUILTIN = "builtin" -OS_CRYPT = "os_crypt" - -# TODO: needs UTs -def has_backend(hasher, backend=ANY, safe=False): - """ - Test if specified backend is available for hasher. - - :param hasher: - Hasher name or object. - - :param backend: - Name of backend, or ``"any"`` if any backend will do. - For hashers without multiple backends, will pretend - they have a single backend named ``"builtin"``. - - :param safe: - By default, throws error if backend is unknown. - If ``safe=True``, will just return false value. - - :raises ValueError: - * if hasher name is unknown. - * if backend is unknown to hasher, and safe=False. - - :return: - True if backend available, False if not available, - and None if unknown + safe=True. - """ - hasher = _resolve(hasher) - - if backend == ANY: - if not hasattr(hasher, "get_backend"): - # single backend, assume it's loaded - return True - - # multiple backends, check at least one is loadable - try: - hasher.get_backend() - return True - except exc.MissingBackendError: - return False - - # test for specific backend - if hasattr(hasher, "has_backend"): - # multiple backends - if safe and backend not in hasher.backends: - return None - return hasher.has_backend(backend) - - # single builtin backend - if backend == BUILTIN: - return True - elif safe: - return None - else: - raise exc.UnknownBackendError(hasher, backend) - -#------------------------------------------------------------------ -# os crypt -#------------------------------------------------------------------ - -# TODO: move unix_crypt_schemes list to here. -# os_crypt_schemes -- alias for unix_crypt_schemes above - - -# TODO: needs UTs -@memoize_single_value -def get_supported_os_crypt_schemes(): - """ - return tuple of schemes which :func:`crypt.crypt` natively supports. - """ - if not os_crypt_present: - return () - cache = tuple(name for name in os_crypt_schemes - if get_crypt_handler(name).has_backend(OS_CRYPT)) - if not cache: # pragma: no cover -- sanity check - # no idea what OS this could happen on... - import platform - warn("crypt.crypt() function is present, but doesn't support any " - "formats known to passlib! (system=%r release=%r)" % - (platform.system(), platform.release()), - exc.PasslibRuntimeWarning) - return cache - - -# TODO: needs UTs -def has_os_crypt_support(hasher): - """ - check if hash is supported by native :func:`crypt.crypt` function. - if :func:`crypt.crypt` is not present, will always return False. - - :param hasher: - name or hasher object. - - :returns bool: - True if hash format is supported by OS, else False. - """ - return os_crypt_present and has_backend(hasher, OS_CRYPT, safe=True) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/__init__.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/__init__.py deleted file mode 100644 index 389da76..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""passlib tests""" diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/__main__.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/__main__.py deleted file mode 100644 index 2424576..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -import os -from nose import run -run( - defaultTest=os.path.dirname(__file__), -) - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/_test_bad_register.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/_test_bad_register.py deleted file mode 100644 index f0683fc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/_test_bad_register.py +++ /dev/null @@ -1,15 +0,0 @@ -"""helper for method in test_registry.py""" -from passlib.registry import register_crypt_handler -import passlib.utils.handlers as uh - -class dummy_bad(uh.StaticHandler): - name = "dummy_bad" - -class alt_dummy_bad(uh.StaticHandler): - name = "dummy_bad" - -# NOTE: if passlib.tests is being run from symlink (e.g. via gaeunit), -# this module may be imported a second time as test._test_bad_registry. -# we don't want it to do anything in that case. -if __name__.startswith("passlib.tests"): - register_crypt_handler(alt_dummy_bad) diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/backports.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/backports.py deleted file mode 100644 index 5058cec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/backports.py +++ /dev/null @@ -1,67 +0,0 @@ -"""backports of needed unittest2 features""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -import re -import sys -##from warnings import warn -# site -# pkg -from passlib.utils.compat import PY26 -# local -__all__ = [ - "TestCase", - "unittest", - # TODO: deprecate these exports in favor of "unittest.XXX" - "skip", "skipIf", "skipUnless", -] - -#============================================================================= -# import latest unittest module available -#============================================================================= -try: - import unittest2 as unittest -except ImportError: - if PY26: - raise ImportError("Passlib's tests require 'unittest2' under Python 2.6 (as of Passlib 1.7)") - # python 2.7 and python 3.2 both have unittest2 features (at least, the ones we use) - import unittest - -#============================================================================= -# unittest aliases -#============================================================================= -skip = unittest.skip -skipIf = unittest.skipIf -skipUnless = unittest.skipUnless -SkipTest = unittest.SkipTest - -#============================================================================= -# custom test harness -#============================================================================= -class TestCase(unittest.TestCase): - """backports a number of unittest2 features in TestCase""" - - #=================================================================== - # backport some unittest2 names - #=================================================================== - - #--------------------------------------------------------------- - # backport assertRegex() alias from 3.2 to 2.7 - # was present in 2.7 under an alternate name - #--------------------------------------------------------------- - if not hasattr(unittest.TestCase, "assertRegex"): - assertRegex = unittest.TestCase.assertRegexpMatches - - if not hasattr(unittest.TestCase, "assertRaisesRegex"): - assertRaisesRegex = unittest.TestCase.assertRaisesRegexp - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1.cfg b/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1.cfg deleted file mode 100644 index 56e3ae8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -all__vary_rounds = 0.1 -bsdi_crypt__default_rounds = 25001 -bsdi_crypt__max_rounds = 30001 -sha512_crypt__max_rounds = 50000 -sha512_crypt__min_rounds = 40000 - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1b.cfg b/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1b.cfg deleted file mode 100644 index 542a603..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1b.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -all__vary_rounds = 0.1 -bsdi_crypt__default_rounds = 25001 -bsdi_crypt__max_rounds = 30001 -sha512_crypt__max_rounds = 50000 -sha512_crypt__min_rounds = 40000 - diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1c.cfg b/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1c.cfg deleted file mode 100644 index a5033eb..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample1c.cfg and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample_config_1s.cfg b/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample_config_1s.cfg deleted file mode 100644 index 495a13e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/sample_config_1s.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -all.vary_rounds = 10%% -bsdi_crypt.max_rounds = 30000 -bsdi_crypt.default_rounds = 25000 -sha512_crypt.max_rounds = 50000 -sha512_crypt.min_rounds = 40000 diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apache.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apache.py deleted file mode 100644 index 198b425..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apache.py +++ /dev/null @@ -1,769 +0,0 @@ -"""tests for passlib.apache -- (c) Assurance Technologies 2008-2011""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -from logging import getLogger -import os -import subprocess -# site -# pkg -from passlib import apache, registry -from passlib.exc import MissingBackendError -from passlib.utils.compat import irange -from passlib.tests.backports import unittest -from passlib.tests.utils import TestCase, get_file, set_file, ensure_mtime_changed -from passlib.utils.compat import u -from passlib.utils import to_bytes -from passlib.utils.handlers import to_unicode_for_identify -# module -log = getLogger(__name__) - -#============================================================================= -# helpers -#============================================================================= - -def backdate_file_mtime(path, offset=10): - """backdate file's mtime by specified amount""" - # NOTE: this is used so we can test code which detects mtime changes, - # without having to actually *pause* for that long. - atime = os.path.getatime(path) - mtime = os.path.getmtime(path)-offset - os.utime(path, (atime, mtime)) - -#============================================================================= -# detect external HTPASSWD tool -#============================================================================= - - -htpasswd_path = os.environ.get("PASSLIB_TEST_HTPASSWD_PATH") or "htpasswd" - - -def _call_htpasswd(args, stdin=None): - """ - helper to run htpasswd cmd - """ - if stdin is not None: - stdin = stdin.encode("utf-8") - proc = subprocess.Popen([htpasswd_path] + args, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, stdin=subprocess.PIPE if stdin else None) - out, err = proc.communicate(stdin) - rc = proc.wait() - out = to_unicode_for_identify(out or "") - return out, rc - - -def _call_htpasswd_verify(path, user, password): - """ - wrapper for htpasswd verify - """ - out, rc = _call_htpasswd(["-vi", path, user], password) - return not rc - - -def _detect_htpasswd(): - """ - helper to check if htpasswd is present - """ - try: - out, rc = _call_htpasswd([]) - except OSError: - # TODO: under py3, could trap the more specific FileNotFoundError - # cmd not found - return False, False - # when called w/o args, it should print usage to stderr & return rc=2 - if not rc: - log.warning("htpasswd test returned with rc=0") - have_bcrypt = " -B " in out - return True, have_bcrypt - - -HAVE_HTPASSWD, HAVE_HTPASSWD_BCRYPT = _detect_htpasswd() - -requires_htpasswd_cmd = unittest.skipUnless(HAVE_HTPASSWD, "requires `htpasswd` cmdline tool") - - -#============================================================================= -# htpasswd -#============================================================================= -class HtpasswdFileTest(TestCase): - """test HtpasswdFile class""" - descriptionPrefix = "HtpasswdFile" - - # sample with 4 users - sample_01 = (b'user2:2CHkkwa2AtqGs\n' - b'user3:{SHA}3ipNV1GrBtxPmHFC21fCbVCSXIo=\n' - b'user4:pass4\n' - b'user1:$apr1$t4tc7jTh$GPIWVUo8sQKJlUdV8V5vu0\n') - - # sample 1 with user 1, 2 deleted; 4 changed - sample_02 = b'user3:{SHA}3ipNV1GrBtxPmHFC21fCbVCSXIo=\nuser4:pass4\n' - - # sample 1 with user2 updated, user 1 first entry removed, and user 5 added - sample_03 = (b'user2:pass2x\n' - b'user3:{SHA}3ipNV1GrBtxPmHFC21fCbVCSXIo=\n' - b'user4:pass4\n' - b'user1:$apr1$t4tc7jTh$GPIWVUo8sQKJlUdV8V5vu0\n' - b'user5:pass5\n') - - # standalone sample with 8-bit username - sample_04_utf8 = b'user\xc3\xa6:2CHkkwa2AtqGs\n' - sample_04_latin1 = b'user\xe6:2CHkkwa2AtqGs\n' - - sample_dup = b'user1:pass1\nuser1:pass2\n' - - # sample with bcrypt & sha256_crypt hashes - sample_05 = (b'user2:2CHkkwa2AtqGs\n' - b'user3:{SHA}3ipNV1GrBtxPmHFC21fCbVCSXIo=\n' - b'user4:pass4\n' - b'user1:$apr1$t4tc7jTh$GPIWVUo8sQKJlUdV8V5vu0\n' - b'user5:$2a$12$yktDxraxijBZ360orOyCOePFGhuis/umyPNJoL5EbsLk.s6SWdrRO\n' - b'user6:$5$rounds=110000$cCRp/xUUGVgwR4aP$' - b'p0.QKFS5qLNRqw1/47lXYiAcgIjJK.WjCO8nrEKuUK.\n') - - def test_00_constructor_autoload(self): - """test constructor autoload""" - # check with existing file - path = self.mktemp() - set_file(path, self.sample_01) - ht = apache.HtpasswdFile(path) - self.assertEqual(ht.to_string(), self.sample_01) - self.assertEqual(ht.path, path) - self.assertTrue(ht.mtime) - - # check changing path - ht.path = path + "x" - self.assertEqual(ht.path, path + "x") - self.assertFalse(ht.mtime) - - # check new=True - ht = apache.HtpasswdFile(path, new=True) - self.assertEqual(ht.to_string(), b"") - self.assertEqual(ht.path, path) - self.assertFalse(ht.mtime) - - # check autoload=False (deprecated alias for new=True) - with self.assertWarningList("``autoload=False`` is deprecated"): - ht = apache.HtpasswdFile(path, autoload=False) - self.assertEqual(ht.to_string(), b"") - self.assertEqual(ht.path, path) - self.assertFalse(ht.mtime) - - # check missing file - os.remove(path) - self.assertRaises(IOError, apache.HtpasswdFile, path) - - # NOTE: "default_scheme" option checked via set_password() test, among others - - def test_00_from_path(self): - path = self.mktemp() - set_file(path, self.sample_01) - ht = apache.HtpasswdFile.from_path(path) - self.assertEqual(ht.to_string(), self.sample_01) - self.assertEqual(ht.path, None) - self.assertFalse(ht.mtime) - - def test_01_delete(self): - """test delete()""" - ht = apache.HtpasswdFile.from_string(self.sample_01) - self.assertTrue(ht.delete("user1")) # should delete both entries - self.assertTrue(ht.delete("user2")) - self.assertFalse(ht.delete("user5")) # user not present - self.assertEqual(ht.to_string(), self.sample_02) - - # invalid user - self.assertRaises(ValueError, ht.delete, "user:") - - def test_01_delete_autosave(self): - path = self.mktemp() - sample = b'user1:pass1\nuser2:pass2\n' - set_file(path, sample) - - ht = apache.HtpasswdFile(path) - ht.delete("user1") - self.assertEqual(get_file(path), sample) - - ht = apache.HtpasswdFile(path, autosave=True) - ht.delete("user1") - self.assertEqual(get_file(path), b"user2:pass2\n") - - def test_02_set_password(self): - """test set_password()""" - ht = apache.HtpasswdFile.from_string( - self.sample_01, default_scheme="plaintext") - self.assertTrue(ht.set_password("user2", "pass2x")) - self.assertFalse(ht.set_password("user5", "pass5")) - self.assertEqual(ht.to_string(), self.sample_03) - - # test legacy default kwd - with self.assertWarningList("``default`` is deprecated"): - ht = apache.HtpasswdFile.from_string(self.sample_01, default="plaintext") - self.assertTrue(ht.set_password("user2", "pass2x")) - self.assertFalse(ht.set_password("user5", "pass5")) - self.assertEqual(ht.to_string(), self.sample_03) - - # invalid user - self.assertRaises(ValueError, ht.set_password, "user:", "pass") - - # test that legacy update() still works - with self.assertWarningList("update\(\) is deprecated"): - ht.update("user2", "test") - self.assertTrue(ht.check_password("user2", "test")) - - def test_02_set_password_autosave(self): - path = self.mktemp() - sample = b'user1:pass1\n' - set_file(path, sample) - - ht = apache.HtpasswdFile(path) - ht.set_password("user1", "pass2") - self.assertEqual(get_file(path), sample) - - ht = apache.HtpasswdFile(path, default_scheme="plaintext", autosave=True) - ht.set_password("user1", "pass2") - self.assertEqual(get_file(path), b"user1:pass2\n") - - def test_02_set_password_default_scheme(self): - """test set_password() -- default_scheme""" - - def check(scheme): - ht = apache.HtpasswdFile(default_scheme=scheme) - ht.set_password("user1", "pass1") - return ht.context.identify(ht.get_hash("user1")) - - # explicit scheme - self.assertEqual(check("sha256_crypt"), "sha256_crypt") - self.assertEqual(check("des_crypt"), "des_crypt") - - # unknown scheme - self.assertRaises(KeyError, check, "xxx") - - # alias resolution - self.assertEqual(check("portable"), apache.htpasswd_defaults["portable"]) - self.assertEqual(check("portable_apache_22"), apache.htpasswd_defaults["portable_apache_22"]) - self.assertEqual(check("host_apache_22"), apache.htpasswd_defaults["host_apache_22"]) - - # default - self.assertEqual(check(None), apache.htpasswd_defaults["portable_apache_22"]) - - def test_03_users(self): - """test users()""" - ht = apache.HtpasswdFile.from_string(self.sample_01) - ht.set_password("user5", "pass5") - ht.delete("user3") - ht.set_password("user3", "pass3") - self.assertEqual(sorted(ht.users()), ["user1", "user2", "user3", "user4", "user5"]) - - def test_04_check_password(self): - """test check_password()""" - ht = apache.HtpasswdFile.from_string(self.sample_05) - self.assertRaises(TypeError, ht.check_password, 1, 'pass9') - self.assertTrue(ht.check_password("user9","pass9") is None) - - # users 1..6 of sample_01 run through all the main hash formats, - # to make sure they're recognized. - for i in irange(1, 7): - i = str(i) - try: - self.assertTrue(ht.check_password("user"+i, "pass"+i)) - self.assertTrue(ht.check_password("user"+i, "pass9") is False) - except MissingBackendError: - if i == "5": - # user5 uses bcrypt, which is apparently not available right now - continue - raise - - self.assertRaises(ValueError, ht.check_password, "user:", "pass") - - # test that legacy verify() still works - with self.assertWarningList(["verify\(\) is deprecated"]*2): - self.assertTrue(ht.verify("user1", "pass1")) - self.assertFalse(ht.verify("user1", "pass2")) - - def test_05_load(self): - """test load()""" - # setup empty file - path = self.mktemp() - set_file(path, "") - backdate_file_mtime(path, 5) - ha = apache.HtpasswdFile(path, default_scheme="plaintext") - self.assertEqual(ha.to_string(), b"") - - # make changes, check load_if_changed() does nothing - ha.set_password("user1", "pass1") - ha.load_if_changed() - self.assertEqual(ha.to_string(), b"user1:pass1\n") - - # change file - set_file(path, self.sample_01) - ha.load_if_changed() - self.assertEqual(ha.to_string(), self.sample_01) - - # make changes, check load() overwrites them - ha.set_password("user5", "pass5") - ha.load() - self.assertEqual(ha.to_string(), self.sample_01) - - # test load w/ no path - hb = apache.HtpasswdFile() - self.assertRaises(RuntimeError, hb.load) - self.assertRaises(RuntimeError, hb.load_if_changed) - - # test load w/ dups and explicit path - set_file(path, self.sample_dup) - hc = apache.HtpasswdFile() - hc.load(path) - self.assertTrue(hc.check_password('user1','pass1')) - - # NOTE: load_string() tested via from_string(), which is used all over this file - - def test_06_save(self): - """test save()""" - # load from file - path = self.mktemp() - set_file(path, self.sample_01) - ht = apache.HtpasswdFile(path) - - # make changes, check they saved - ht.delete("user1") - ht.delete("user2") - ht.save() - self.assertEqual(get_file(path), self.sample_02) - - # test save w/ no path - hb = apache.HtpasswdFile(default_scheme="plaintext") - hb.set_password("user1", "pass1") - self.assertRaises(RuntimeError, hb.save) - - # test save w/ explicit path - hb.save(path) - self.assertEqual(get_file(path), b"user1:pass1\n") - - def test_07_encodings(self): - """test 'encoding' kwd""" - # test bad encodings cause failure in constructor - self.assertRaises(ValueError, apache.HtpasswdFile, encoding="utf-16") - - # check sample utf-8 - ht = apache.HtpasswdFile.from_string(self.sample_04_utf8, encoding="utf-8", - return_unicode=True) - self.assertEqual(ht.users(), [ u("user\u00e6") ]) - - # test deprecated encoding=None - with self.assertWarningList("``encoding=None`` is deprecated"): - ht = apache.HtpasswdFile.from_string(self.sample_04_utf8, encoding=None) - self.assertEqual(ht.users(), [ b'user\xc3\xa6' ]) - - # check sample latin-1 - ht = apache.HtpasswdFile.from_string(self.sample_04_latin1, - encoding="latin-1", return_unicode=True) - self.assertEqual(ht.users(), [ u("user\u00e6") ]) - - def test_08_get_hash(self): - """test get_hash()""" - ht = apache.HtpasswdFile.from_string(self.sample_01) - self.assertEqual(ht.get_hash("user3"), b"{SHA}3ipNV1GrBtxPmHFC21fCbVCSXIo=") - self.assertEqual(ht.get_hash("user4"), b"pass4") - self.assertEqual(ht.get_hash("user5"), None) - - with self.assertWarningList("find\(\) is deprecated"): - self.assertEqual(ht.find("user4"), b"pass4") - - def test_09_to_string(self): - """test to_string""" - - # check with known sample - ht = apache.HtpasswdFile.from_string(self.sample_01) - self.assertEqual(ht.to_string(), self.sample_01) - - # test blank - ht = apache.HtpasswdFile() - self.assertEqual(ht.to_string(), b"") - - def test_10_repr(self): - ht = apache.HtpasswdFile("fakepath", autosave=True, new=True, encoding="latin-1") - repr(ht) - - def test_11_malformed(self): - self.assertRaises(ValueError, apache.HtpasswdFile.from_string, - b'realm:user1:pass1\n') - self.assertRaises(ValueError, apache.HtpasswdFile.from_string, - b'pass1\n') - - def test_12_from_string(self): - # forbid path kwd - self.assertRaises(TypeError, apache.HtpasswdFile.from_string, - b'', path=None) - - def test_13_whitespace(self): - """whitespace & comment handling""" - - # per htpasswd source (https://github.com/apache/httpd/blob/trunk/support/htpasswd.c), - # lines that match "^\s*(#.*)?$" should be ignored - source = to_bytes( - '\n' - 'user2:pass2\n' - 'user4:pass4\n' - 'user7:pass7\r\n' - ' \t \n' - 'user1:pass1\n' - ' # legacy users\n' - '#user6:pass6\n' - 'user5:pass5\n\n' - ) - - # loading should see all users (except user6, who was commented out) - ht = apache.HtpasswdFile.from_string(source) - self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user7"]) - - # update existing user - ht.set_hash("user4", "althash4") - self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user7"]) - - # add a new user - ht.set_hash("user6", "althash6") - self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user6", "user7"]) - - # delete existing user - ht.delete("user7") - self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user6"]) - - # re-serialization should preserve whitespace - target = to_bytes( - '\n' - 'user2:pass2\n' - 'user4:althash4\n' - ' \t \n' - 'user1:pass1\n' - ' # legacy users\n' - '#user6:pass6\n' - 'user5:pass5\n' - 'user6:althash6\n' - ) - self.assertEqual(ht.to_string(), target) - - @requires_htpasswd_cmd - def test_htpasswd_cmd_verify(self): - """ - verify "htpasswd" command can read output - """ - path = self.mktemp() - ht = apache.HtpasswdFile(path=path, new=True) - - def hash_scheme(pwd, scheme): - return ht.context.handler(scheme).hash(pwd) - - # base scheme - ht.set_hash("user1", hash_scheme("password","apr_md5_crypt")) - - # 2.2-compat scheme - host_no_bcrypt = apache.htpasswd_defaults["host_apache_22"] - ht.set_hash("user2", hash_scheme("password", host_no_bcrypt)) - - # 2.4-compat scheme - host_best = apache.htpasswd_defaults["host"] - ht.set_hash("user3", hash_scheme("password", host_best)) - - # unsupported scheme -- should always fail to verify - ht.set_hash("user4", "$xxx$foo$bar$baz") - - # make sure htpasswd properly recognizes hashes - ht.save() - - self.assertFalse(_call_htpasswd_verify(path, "user1", "wrong")) - self.assertFalse(_call_htpasswd_verify(path, "user2", "wrong")) - self.assertFalse(_call_htpasswd_verify(path, "user3", "wrong")) - self.assertFalse(_call_htpasswd_verify(path, "user4", "wrong")) - - self.assertTrue(_call_htpasswd_verify(path, "user1", "password")) - self.assertTrue(_call_htpasswd_verify(path, "user2", "password")) - self.assertTrue(_call_htpasswd_verify(path, "user3", "password")) - - @requires_htpasswd_cmd - @unittest.skipUnless(registry.has_backend("bcrypt"), "bcrypt support required") - def test_htpasswd_cmd_verify_bcrypt(self): - """ - verify "htpasswd" command can read bcrypt format - - this tests for regression of issue 95, where we output "$2b$" instead of "$2y$"; - fixed in v1.7.2. - """ - path = self.mktemp() - ht = apache.HtpasswdFile(path=path, new=True) - def hash_scheme(pwd, scheme): - return ht.context.handler(scheme).hash(pwd) - ht.set_hash("user1", hash_scheme("password", "bcrypt")) - ht.save() - self.assertFalse(_call_htpasswd_verify(path, "user1", "wrong")) - if HAVE_HTPASSWD_BCRYPT: - self.assertTrue(_call_htpasswd_verify(path, "user1", "password")) - else: - # apache2.2 should fail, acting like it's an unknown hash format - self.assertFalse(_call_htpasswd_verify(path, "user1", "password")) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# htdigest -#============================================================================= -class HtdigestFileTest(TestCase): - """test HtdigestFile class""" - descriptionPrefix = "HtdigestFile" - - # sample with 4 users - sample_01 = (b'user2:realm:549d2a5f4659ab39a80dac99e159ab19\n' - b'user3:realm:a500bb8c02f6a9170ae46af10c898744\n' - b'user4:realm:ab7b5d5f28ccc7666315f508c7358519\n' - b'user1:realm:2a6cf53e7d8f8cf39d946dc880b14128\n') - - # sample 1 with user 1, 2 deleted; 4 changed - sample_02 = (b'user3:realm:a500bb8c02f6a9170ae46af10c898744\n' - b'user4:realm:ab7b5d5f28ccc7666315f508c7358519\n') - - # sample 1 with user2 updated, user 1 first entry removed, and user 5 added - sample_03 = (b'user2:realm:5ba6d8328943c23c64b50f8b29566059\n' - b'user3:realm:a500bb8c02f6a9170ae46af10c898744\n' - b'user4:realm:ab7b5d5f28ccc7666315f508c7358519\n' - b'user1:realm:2a6cf53e7d8f8cf39d946dc880b14128\n' - b'user5:realm:03c55fdc6bf71552356ad401bdb9af19\n') - - # standalone sample with 8-bit username & realm - sample_04_utf8 = b'user\xc3\xa6:realm\xc3\xa6:549d2a5f4659ab39a80dac99e159ab19\n' - sample_04_latin1 = b'user\xe6:realm\xe6:549d2a5f4659ab39a80dac99e159ab19\n' - - def test_00_constructor_autoload(self): - """test constructor autoload""" - # check with existing file - path = self.mktemp() - set_file(path, self.sample_01) - ht = apache.HtdigestFile(path) - self.assertEqual(ht.to_string(), self.sample_01) - - # check without autoload - ht = apache.HtdigestFile(path, new=True) - self.assertEqual(ht.to_string(), b"") - - # check missing file - os.remove(path) - self.assertRaises(IOError, apache.HtdigestFile, path) - - # NOTE: default_realm option checked via other tests. - - def test_01_delete(self): - """test delete()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - self.assertTrue(ht.delete("user1", "realm")) - self.assertTrue(ht.delete("user2", "realm")) - self.assertFalse(ht.delete("user5", "realm")) - self.assertFalse(ht.delete("user3", "realm5")) - self.assertEqual(ht.to_string(), self.sample_02) - - # invalid user - self.assertRaises(ValueError, ht.delete, "user:", "realm") - - # invalid realm - self.assertRaises(ValueError, ht.delete, "user", "realm:") - - def test_01_delete_autosave(self): - path = self.mktemp() - set_file(path, self.sample_01) - - ht = apache.HtdigestFile(path) - self.assertTrue(ht.delete("user1", "realm")) - self.assertFalse(ht.delete("user3", "realm5")) - self.assertFalse(ht.delete("user5", "realm")) - self.assertEqual(get_file(path), self.sample_01) - - ht.autosave = True - self.assertTrue(ht.delete("user2", "realm")) - self.assertEqual(get_file(path), self.sample_02) - - def test_02_set_password(self): - """test update()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - self.assertTrue(ht.set_password("user2", "realm", "pass2x")) - self.assertFalse(ht.set_password("user5", "realm", "pass5")) - self.assertEqual(ht.to_string(), self.sample_03) - - # default realm - self.assertRaises(TypeError, ht.set_password, "user2", "pass3") - ht.default_realm = "realm2" - ht.set_password("user2", "pass3") - ht.check_password("user2", "realm2", "pass3") - - # invalid user - self.assertRaises(ValueError, ht.set_password, "user:", "realm", "pass") - self.assertRaises(ValueError, ht.set_password, "u"*256, "realm", "pass") - - # invalid realm - self.assertRaises(ValueError, ht.set_password, "user", "realm:", "pass") - self.assertRaises(ValueError, ht.set_password, "user", "r"*256, "pass") - - # test that legacy update() still works - with self.assertWarningList("update\(\) is deprecated"): - ht.update("user2", "realm2", "test") - self.assertTrue(ht.check_password("user2", "test")) - - # TODO: test set_password autosave - - def test_03_users(self): - """test users()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - ht.set_password("user5", "realm", "pass5") - ht.delete("user3", "realm") - ht.set_password("user3", "realm", "pass3") - self.assertEqual(sorted(ht.users("realm")), ["user1", "user2", "user3", "user4", "user5"]) - - self.assertRaises(TypeError, ht.users, 1) - - def test_04_check_password(self): - """test check_password()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - self.assertRaises(TypeError, ht.check_password, 1, 'realm', 'pass5') - self.assertRaises(TypeError, ht.check_password, 'user', 1, 'pass5') - self.assertIs(ht.check_password("user5", "realm","pass5"), None) - for i in irange(1,5): - i = str(i) - self.assertTrue(ht.check_password("user"+i, "realm", "pass"+i)) - self.assertIs(ht.check_password("user"+i, "realm", "pass5"), False) - - # default realm - self.assertRaises(TypeError, ht.check_password, "user5", "pass5") - ht.default_realm = "realm" - self.assertTrue(ht.check_password("user1", "pass1")) - self.assertIs(ht.check_password("user5", "pass5"), None) - - # test that legacy verify() still works - with self.assertWarningList(["verify\(\) is deprecated"]*2): - self.assertTrue(ht.verify("user1", "realm", "pass1")) - self.assertFalse(ht.verify("user1", "realm", "pass2")) - - # invalid user - self.assertRaises(ValueError, ht.check_password, "user:", "realm", "pass") - - def test_05_load(self): - """test load()""" - # setup empty file - path = self.mktemp() - set_file(path, "") - backdate_file_mtime(path, 5) - ha = apache.HtdigestFile(path) - self.assertEqual(ha.to_string(), b"") - - # make changes, check load_if_changed() does nothing - ha.set_password("user1", "realm", "pass1") - ha.load_if_changed() - self.assertEqual(ha.to_string(), b'user1:realm:2a6cf53e7d8f8cf39d946dc880b14128\n') - - # change file - set_file(path, self.sample_01) - ha.load_if_changed() - self.assertEqual(ha.to_string(), self.sample_01) - - # make changes, check load_if_changed overwrites them - ha.set_password("user5", "realm", "pass5") - ha.load() - self.assertEqual(ha.to_string(), self.sample_01) - - # test load w/ no path - hb = apache.HtdigestFile() - self.assertRaises(RuntimeError, hb.load) - self.assertRaises(RuntimeError, hb.load_if_changed) - - # test load w/ explicit path - hc = apache.HtdigestFile() - hc.load(path) - self.assertEqual(hc.to_string(), self.sample_01) - - # change file, test deprecated force=False kwd - ensure_mtime_changed(path) - set_file(path, "") - with self.assertWarningList(r"load\(force=False\) is deprecated"): - ha.load(force=False) - self.assertEqual(ha.to_string(), b"") - - def test_06_save(self): - """test save()""" - # load from file - path = self.mktemp() - set_file(path, self.sample_01) - ht = apache.HtdigestFile(path) - - # make changes, check they saved - ht.delete("user1", "realm") - ht.delete("user2", "realm") - ht.save() - self.assertEqual(get_file(path), self.sample_02) - - # test save w/ no path - hb = apache.HtdigestFile() - hb.set_password("user1", "realm", "pass1") - self.assertRaises(RuntimeError, hb.save) - - # test save w/ explicit path - hb.save(path) - self.assertEqual(get_file(path), hb.to_string()) - - def test_07_realms(self): - """test realms() & delete_realm()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - - self.assertEqual(ht.delete_realm("x"), 0) - self.assertEqual(ht.realms(), ['realm']) - - self.assertEqual(ht.delete_realm("realm"), 4) - self.assertEqual(ht.realms(), []) - self.assertEqual(ht.to_string(), b"") - - def test_08_get_hash(self): - """test get_hash()""" - ht = apache.HtdigestFile.from_string(self.sample_01) - self.assertEqual(ht.get_hash("user3", "realm"), "a500bb8c02f6a9170ae46af10c898744") - self.assertEqual(ht.get_hash("user4", "realm"), "ab7b5d5f28ccc7666315f508c7358519") - self.assertEqual(ht.get_hash("user5", "realm"), None) - - with self.assertWarningList("find\(\) is deprecated"): - self.assertEqual(ht.find("user4", "realm"), "ab7b5d5f28ccc7666315f508c7358519") - - def test_09_encodings(self): - """test encoding parameter""" - # test bad encodings cause failure in constructor - self.assertRaises(ValueError, apache.HtdigestFile, encoding="utf-16") - - # check sample utf-8 - ht = apache.HtdigestFile.from_string(self.sample_04_utf8, encoding="utf-8", return_unicode=True) - self.assertEqual(ht.realms(), [ u("realm\u00e6") ]) - self.assertEqual(ht.users(u("realm\u00e6")), [ u("user\u00e6") ]) - - # check sample latin-1 - ht = apache.HtdigestFile.from_string(self.sample_04_latin1, encoding="latin-1", return_unicode=True) - self.assertEqual(ht.realms(), [ u("realm\u00e6") ]) - self.assertEqual(ht.users(u("realm\u00e6")), [ u("user\u00e6") ]) - - def test_10_to_string(self): - """test to_string()""" - - # check sample - ht = apache.HtdigestFile.from_string(self.sample_01) - self.assertEqual(ht.to_string(), self.sample_01) - - # check blank - ht = apache.HtdigestFile() - self.assertEqual(ht.to_string(), b"") - - def test_11_malformed(self): - self.assertRaises(ValueError, apache.HtdigestFile.from_string, - b'realm:user1:pass1:other\n') - self.assertRaises(ValueError, apache.HtdigestFile.from_string, - b'user1:pass1\n') - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apps.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apps.py deleted file mode 100644 index 167437f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_apps.py +++ /dev/null @@ -1,139 +0,0 @@ -"""test passlib.apps""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib import apps, hash as hashmod -from passlib.tests.utils import TestCase -# module - -#============================================================================= -# test predefined app contexts -#============================================================================= -class AppsTest(TestCase): - """perform general tests to make sure contexts work""" - # NOTE: these tests are not really comprehensive, - # since they would do little but duplicate - # the presets in apps.py - # - # they mainly try to ensure no typos - # or dynamic behavior foul-ups. - - def test_master_context(self): - ctx = apps.master_context - self.assertGreater(len(ctx.schemes()), 50) - - def test_custom_app_context(self): - ctx = apps.custom_app_context - self.assertEqual(ctx.schemes(), ("sha512_crypt", "sha256_crypt")) - for hash in [ - ('$6$rounds=41128$VoQLvDjkaZ6L6BIE$4pt.1Ll1XdDYduEwEYPCMOBiR6W6' - 'znsyUEoNlcVXpv2gKKIbQolgmTGe6uEEVJ7azUxuc8Tf7zV9SD2z7Ij751'), - ('$5$rounds=31817$iZGmlyBQ99JSB5n6$p4E.pdPBWx19OajgjLRiOW0itGny' - 'xDGgMlDcOsfaI17'), - ]: - self.assertTrue(ctx.verify("test", hash)) - - def test_django16_context(self): - ctx = apps.django16_context - for hash in [ - 'pbkdf2_sha256$29000$ZsgquwnCyBs2$fBxRQpfKd2PIeMxtkKPy0h7SrnrN+EU/cm67aitoZ2s=', - 'sha1$0d082$cdb462ae8b6be8784ef24b20778c4d0c82d5957f', - 'md5$b887a$37767f8a745af10612ad44c80ff52e92', - 'crypt$95a6d$95x74hLDQKXI2', - '098f6bcd4621d373cade4e832627b4f6', - ]: - self.assertTrue(ctx.verify("test", hash)) - - self.assertEqual(ctx.identify("!"), "django_disabled") - self.assertFalse(ctx.verify("test", "!")) - - def test_django_context(self): - ctx = apps.django_context - for hash in [ - 'pbkdf2_sha256$29000$ZsgquwnCyBs2$fBxRQpfKd2PIeMxtkKPy0h7SrnrN+EU/cm67aitoZ2s=', - ]: - self.assertTrue(ctx.verify("test", hash)) - - self.assertEqual(ctx.identify("!"), "django_disabled") - self.assertFalse(ctx.verify("test", "!")) - - def test_ldap_nocrypt_context(self): - ctx = apps.ldap_nocrypt_context - for hash in [ - '{SSHA}cPusOzd6d5n3OjSVK3R329ZGCNyFcC7F', - 'test', - ]: - self.assertTrue(ctx.verify("test", hash)) - - self.assertIs(ctx.identify('{CRYPT}$5$rounds=31817$iZGmlyBQ99JSB5' - 'n6$p4E.pdPBWx19OajgjLRiOW0itGnyxDGgMlDcOsfaI17'), None) - - def test_ldap_context(self): - ctx = apps.ldap_context - for hash in [ - ('{CRYPT}$5$rounds=31817$iZGmlyBQ99JSB5n6$p4E.pdPBWx19OajgjLRiOW0' - 'itGnyxDGgMlDcOsfaI17'), - '{SSHA}cPusOzd6d5n3OjSVK3R329ZGCNyFcC7F', - 'test', - ]: - self.assertTrue(ctx.verify("test", hash)) - - def test_ldap_mysql_context(self): - ctx = apps.mysql_context - for hash in [ - '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29', - '378b243e220ca493', - ]: - self.assertTrue(ctx.verify("test", hash)) - - def test_postgres_context(self): - ctx = apps.postgres_context - hash = 'md55d9c68c6c50ed3d02a2fcf54f63993b6' - self.assertTrue(ctx.verify("test", hash, user='user')) - - def test_phppass_context(self): - ctx = apps.phpass_context - for hash in [ - '$P$8Ja1vJsKa5qyy/b3mCJGXM7GyBnt6..', - '$H$8b95CoYQnQ9Y6fSTsACyphNh5yoM02.', - '_cD..aBxeRhYFJvtUvsI', - ]: - self.assertTrue(ctx.verify("test", hash)) - - h1 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS" - if hashmod.bcrypt.has_backend(): - self.assertTrue(ctx.verify("test", h1)) - self.assertEqual(ctx.default_scheme(), "bcrypt") - self.assertEqual(ctx.handler().name, "bcrypt") - else: - self.assertEqual(ctx.identify(h1), "bcrypt") - self.assertEqual(ctx.default_scheme(), "phpass") - self.assertEqual(ctx.handler().name, "phpass") - - def test_phpbb3_context(self): - ctx = apps.phpbb3_context - for hash in [ - '$P$8Ja1vJsKa5qyy/b3mCJGXM7GyBnt6..', - '$H$8b95CoYQnQ9Y6fSTsACyphNh5yoM02.', - ]: - self.assertTrue(ctx.verify("test", hash)) - self.assertTrue(ctx.hash("test").startswith("$H$")) - - def test_roundup_context(self): - ctx = apps.roundup_context - for hash in [ - '{PBKDF2}9849$JMTYu3eOUSoFYExprVVqbQ$N5.gV.uR1.BTgLSvi0qyPiRlGZ0', - '{SHA}a94a8fe5ccb19ba61c4c0873d391e987982fbbd3', - '{CRYPT}dptOmKDriOGfU', - '{plaintext}test', - ]: - self.assertTrue(ctx.verify("test", hash)) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context.py deleted file mode 100644 index 09b52c0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context.py +++ /dev/null @@ -1,1786 +0,0 @@ -"""tests for passlib.context""" -#============================================================================= -# imports -#============================================================================= -# core -from __future__ import with_statement -from passlib.utils.compat import PY3 -if PY3: - from configparser import NoSectionError -else: - from ConfigParser import NoSectionError -import datetime -from functools import partial -import logging; log = logging.getLogger(__name__) -import os -import warnings -# site -# pkg -from passlib import hash -from passlib.context import CryptContext, LazyCryptContext -from passlib.exc import PasslibConfigWarning, PasslibHashWarning -from passlib.utils import tick, to_unicode -from passlib.utils.compat import irange, u, unicode, str_to_uascii, PY2, PY26 -import passlib.utils.handlers as uh -from passlib.tests.utils import (TestCase, set_file, TICK_RESOLUTION, - quicksleep, time_call, handler_derived_from) -from passlib.registry import (register_crypt_handler_path, - _has_crypt_handler as has_crypt_handler, - _unload_handler_name as unload_handler_name, - get_crypt_handler, - ) -# local -#============================================================================= -# support -#============================================================================= -here = os.path.abspath(os.path.dirname(__file__)) - -def merge_dicts(first, *args, **kwds): - target = first.copy() - for arg in args: - target.update(arg) - if kwds: - target.update(kwds) - return target - -#============================================================================= -# -#============================================================================= -class CryptContextTest(TestCase): - descriptionPrefix = "CryptContext" - - # TODO: these unittests could really use a good cleanup - # and reorganizing, to ensure they're getting everything. - - #=================================================================== - # sample configurations used in tests - #=================================================================== - - #--------------------------------------------------------------- - # sample 1 - typical configuration - #--------------------------------------------------------------- - sample_1_schemes = ["des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"] - sample_1_handlers = [get_crypt_handler(name) for name in sample_1_schemes] - - sample_1_dict = dict( - schemes = sample_1_schemes, - default = "md5_crypt", - all__vary_rounds = 0.1, - bsdi_crypt__max_rounds = 30001, - bsdi_crypt__default_rounds = 25001, - sha512_crypt__max_rounds = 50000, - sha512_crypt__min_rounds = 40000, - ) - - sample_1_resolved_dict = merge_dicts(sample_1_dict, - schemes = sample_1_handlers) - - sample_1_unnormalized = u("""\ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -; this is using %... -all__vary_rounds = 10%% -bsdi_crypt__default_rounds = 25001 -bsdi_crypt__max_rounds = 30001 -sha512_crypt__max_rounds = 50000 -sha512_crypt__min_rounds = 40000 -""") - - sample_1_unicode = u("""\ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -all__vary_rounds = 0.1 -bsdi_crypt__default_rounds = 25001 -bsdi_crypt__max_rounds = 30001 -sha512_crypt__max_rounds = 50000 -sha512_crypt__min_rounds = 40000 - -""") - - #--------------------------------------------------------------- - # sample 1 external files - #--------------------------------------------------------------- - - # sample 1 string with '\n' linesep - sample_1_path = os.path.join(here, "sample1.cfg") - - # sample 1 with '\r\n' linesep - sample_1b_unicode = sample_1_unicode.replace(u("\n"), u("\r\n")) - sample_1b_path = os.path.join(here, "sample1b.cfg") - - # sample 1 using UTF-16 and alt section - sample_1c_bytes = sample_1_unicode.replace(u("[passlib]"), - u("[mypolicy]")).encode("utf-16") - sample_1c_path = os.path.join(here, "sample1c.cfg") - - # enable to regenerate sample files - if False: - set_file(sample_1_path, sample_1_unicode) - set_file(sample_1b_path, sample_1b_unicode) - set_file(sample_1c_path, sample_1c_bytes) - - #--------------------------------------------------------------- - # sample 2 & 12 - options patch - #--------------------------------------------------------------- - sample_2_dict = dict( - # using this to test full replacement of existing options - bsdi_crypt__min_rounds = 29001, - bsdi_crypt__max_rounds = 35001, - bsdi_crypt__default_rounds = 31001, - # using this to test partial replacement of existing options - sha512_crypt__min_rounds=45000, - ) - - sample_2_unicode = """\ -[passlib] -bsdi_crypt__min_rounds = 29001 -bsdi_crypt__max_rounds = 35001 -bsdi_crypt__default_rounds = 31001 -sha512_crypt__min_rounds = 45000 -""" - - # sample 2 overlayed on top of sample 1 - sample_12_dict = merge_dicts(sample_1_dict, sample_2_dict) - - #--------------------------------------------------------------- - # sample 3 & 123 - just changing default from sample 1 - #--------------------------------------------------------------- - sample_3_dict = dict( - default="sha512_crypt", - ) - - # sample 3 overlayed on 2 overlayed on 1 - sample_123_dict = merge_dicts(sample_12_dict, sample_3_dict) - - #--------------------------------------------------------------- - # sample 4 - used by api tests - #--------------------------------------------------------------- - sample_4_dict = dict( - schemes = [ "des_crypt", "md5_crypt", "phpass", "bsdi_crypt", - "sha256_crypt"], - deprecated = [ "des_crypt", ], - default = "sha256_crypt", - bsdi_crypt__max_rounds = 31, - bsdi_crypt__default_rounds = 25, - bsdi_crypt__vary_rounds = 0, - sha256_crypt__max_rounds = 3000, - sha256_crypt__min_rounds = 2000, - sha256_crypt__default_rounds = 3000, - phpass__ident = "H", - phpass__default_rounds = 7, - ) - - #=================================================================== - # setup - #=================================================================== - def setUp(self): - super(CryptContextTest, self).setUp() - warnings.filterwarnings("ignore", "The 'all' scheme is deprecated.*") - warnings.filterwarnings("ignore", ".*'scheme' keyword is deprecated as of Passlib 1.7.*") - - #=================================================================== - # constructors - #=================================================================== - def test_01_constructor(self): - """test class constructor""" - - # test blank constructor works correctly - ctx = CryptContext() - self.assertEqual(ctx.to_dict(), {}) - - # test sample 1 with scheme=names - ctx = CryptContext(**self.sample_1_dict) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 with scheme=handlers - ctx = CryptContext(**self.sample_1_resolved_dict) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 2: options w/o schemes - ctx = CryptContext(**self.sample_2_dict) - self.assertEqual(ctx.to_dict(), self.sample_2_dict) - - # test sample 3: default only - ctx = CryptContext(**self.sample_3_dict) - self.assertEqual(ctx.to_dict(), self.sample_3_dict) - - # test unicode scheme names (issue 54) - ctx = CryptContext(schemes=[u("sha256_crypt")]) - self.assertEqual(ctx.schemes(), ("sha256_crypt",)) - - def test_02_from_string(self): - """test from_string() constructor""" - # test sample 1 unicode - ctx = CryptContext.from_string(self.sample_1_unicode) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 with unnormalized inputs - ctx = CryptContext.from_string(self.sample_1_unnormalized) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 utf-8 - ctx = CryptContext.from_string(self.sample_1_unicode.encode("utf-8")) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 w/ '\r\n' linesep - ctx = CryptContext.from_string(self.sample_1b_unicode) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 using UTF-16 and alt section - ctx = CryptContext.from_string(self.sample_1c_bytes, section="mypolicy", - encoding="utf-16") - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test wrong type - self.assertRaises(TypeError, CryptContext.from_string, None) - - # test missing section - self.assertRaises(NoSectionError, CryptContext.from_string, - self.sample_1_unicode, section="fakesection") - - def test_03_from_path(self): - """test from_path() constructor""" - # make sure sample files exist - if not os.path.exists(self.sample_1_path): - raise RuntimeError("can't find data file: %r" % self.sample_1_path) - - # test sample 1 - ctx = CryptContext.from_path(self.sample_1_path) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 w/ '\r\n' linesep - ctx = CryptContext.from_path(self.sample_1b_path) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test sample 1 encoding using UTF-16 and alt section - ctx = CryptContext.from_path(self.sample_1c_path, section="mypolicy", - encoding="utf-16") - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test missing file - self.assertRaises(EnvironmentError, CryptContext.from_path, - os.path.join(here, "sample1xxx.cfg")) - - # test missing section - self.assertRaises(NoSectionError, CryptContext.from_path, - self.sample_1_path, section="fakesection") - - def test_04_copy(self): - """test copy() method""" - cc1 = CryptContext(**self.sample_1_dict) - - # overlay sample 2 onto copy - cc2 = cc1.copy(**self.sample_2_dict) - self.assertEqual(cc1.to_dict(), self.sample_1_dict) - self.assertEqual(cc2.to_dict(), self.sample_12_dict) - - # check that repeating overlay makes no change - cc2b = cc2.copy(**self.sample_2_dict) - self.assertEqual(cc1.to_dict(), self.sample_1_dict) - self.assertEqual(cc2b.to_dict(), self.sample_12_dict) - - # overlay sample 3 on copy - cc3 = cc2.copy(**self.sample_3_dict) - self.assertEqual(cc3.to_dict(), self.sample_123_dict) - - # test empty copy creates separate copy - cc4 = cc1.copy() - self.assertIsNot(cc4, cc1) - self.assertEqual(cc1.to_dict(), self.sample_1_dict) - self.assertEqual(cc4.to_dict(), self.sample_1_dict) - - # ... and that modifying copy doesn't affect original - cc4.update(**self.sample_2_dict) - self.assertEqual(cc1.to_dict(), self.sample_1_dict) - self.assertEqual(cc4.to_dict(), self.sample_12_dict) - - def test_09_repr(self): - """test repr()""" - cc1 = CryptContext(**self.sample_1_dict) - # NOTE: "0x-1234" format used by Pyston 0.5.1 (support deprecated 2019-11) - self.assertRegex(repr(cc1), "^$") - - #=================================================================== - # modifiers - #=================================================================== - def test_10_load(self): - """test load() / load_path() method""" - # NOTE: load() is the workhorse that handles all policy parsing, - # compilation, and validation. most of its features are tested - # elsewhere, since all the constructors and modifiers are just - # wrappers for it. - - # source_type 'auto' - ctx = CryptContext() - - # detect dict - ctx.load(self.sample_1_dict) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # detect unicode string - ctx.load(self.sample_1_unicode) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # detect bytes string - ctx.load(self.sample_1_unicode.encode("utf-8")) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # anything else - TypeError - self.assertRaises(TypeError, ctx.load, None) - - # NOTE: load_path() tested by from_path() - # NOTE: additional string tests done by from_string() - - # update flag - tested by update() method tests - # encoding keyword - tested by from_string() & from_path() - # section keyword - tested by from_string() & from_path() - - # test load empty - ctx = CryptContext(**self.sample_1_dict) - ctx.load({}, update=True) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # multiple loads should clear the state - ctx = CryptContext() - ctx.load(self.sample_1_dict) - ctx.load(self.sample_2_dict) - self.assertEqual(ctx.to_dict(), self.sample_2_dict) - - def test_11_load_rollback(self): - """test load() errors restore old state""" - # create initial context - cc = CryptContext(["des_crypt", "sha256_crypt"], - sha256_crypt__default_rounds=5000, - all__vary_rounds=0.1, - ) - result = cc.to_string() - - # do an update operation that should fail during parsing - # XXX: not sure what the right error type is here. - self.assertRaises(TypeError, cc.update, too__many__key__parts=True) - self.assertEqual(cc.to_string(), result) - - # do an update operation that should fail during extraction - # FIXME: this isn't failing even in broken case, need to figure out - # way to ensure some keys come after this one. - self.assertRaises(KeyError, cc.update, fake_context_option=True) - self.assertEqual(cc.to_string(), result) - - # do an update operation that should fail during compilation - self.assertRaises(ValueError, cc.update, sha256_crypt__min_rounds=10000) - self.assertEqual(cc.to_string(), result) - - def test_12_update(self): - """test update() method""" - - # empty overlay - ctx = CryptContext(**self.sample_1_dict) - ctx.update() - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - - # test basic overlay - ctx = CryptContext(**self.sample_1_dict) - ctx.update(**self.sample_2_dict) - self.assertEqual(ctx.to_dict(), self.sample_12_dict) - - # ... and again - ctx.update(**self.sample_3_dict) - self.assertEqual(ctx.to_dict(), self.sample_123_dict) - - # overlay w/ dict arg - ctx = CryptContext(**self.sample_1_dict) - ctx.update(self.sample_2_dict) - self.assertEqual(ctx.to_dict(), self.sample_12_dict) - - # overlay w/ string - ctx = CryptContext(**self.sample_1_dict) - ctx.update(self.sample_2_unicode) - self.assertEqual(ctx.to_dict(), self.sample_12_dict) - - # too many args - self.assertRaises(TypeError, ctx.update, {}, {}) - self.assertRaises(TypeError, ctx.update, {}, schemes=['des_crypt']) - - # wrong arg type - self.assertRaises(TypeError, ctx.update, None) - - #=================================================================== - # option parsing - #=================================================================== - def test_20_options(self): - """test basic option parsing""" - def parse(**kwds): - return CryptContext(**kwds).to_dict() - - # - # common option parsing tests - # - - # test keys with blank fields are rejected - # blank option - self.assertRaises(TypeError, CryptContext, __=0.1) - self.assertRaises(TypeError, CryptContext, default__scheme__='x') - - # blank scheme - self.assertRaises(TypeError, CryptContext, __option='x') - self.assertRaises(TypeError, CryptContext, default____option='x') - - # blank category - self.assertRaises(TypeError, CryptContext, __scheme__option='x') - - # test keys with too many field are rejected - self.assertRaises(TypeError, CryptContext, - category__scheme__option__invalid = 30000) - - # keys with mixed separators should be handled correctly. - # (testing actual data, not to_dict(), since re-render hid original bug) - self.assertRaises(KeyError, parse, - **{"admin.context__schemes":"md5_crypt"}) - ctx = CryptContext(**{"schemes":"md5_crypt,des_crypt", - "admin.context__default":"des_crypt"}) - self.assertEqual(ctx.default_scheme("admin"), "des_crypt") - - # - # context option -specific tests - # - - # test context option key parsing - result = dict(default="md5_crypt") - self.assertEqual(parse(default="md5_crypt"), result) - self.assertEqual(parse(context__default="md5_crypt"), result) - self.assertEqual(parse(default__context__default="md5_crypt"), result) - self.assertEqual(parse(**{"context.default":"md5_crypt"}), result) - self.assertEqual(parse(**{"default.context.default":"md5_crypt"}), result) - - # test context option key parsing w/ category - result = dict(admin__context__default="md5_crypt") - self.assertEqual(parse(admin__context__default="md5_crypt"), result) - self.assertEqual(parse(**{"admin.context.default":"md5_crypt"}), result) - - # - # hash option -specific tests - # - - # test hash option key parsing - result = dict(all__vary_rounds=0.1) - self.assertEqual(parse(all__vary_rounds=0.1), result) - self.assertEqual(parse(default__all__vary_rounds=0.1), result) - self.assertEqual(parse(**{"all.vary_rounds":0.1}), result) - self.assertEqual(parse(**{"default.all.vary_rounds":0.1}), result) - - # test hash option key parsing w/ category - result = dict(admin__all__vary_rounds=0.1) - self.assertEqual(parse(admin__all__vary_rounds=0.1), result) - self.assertEqual(parse(**{"admin.all.vary_rounds":0.1}), result) - - # settings not allowed if not in hash.setting_kwds - ctx = CryptContext(["phpass", "md5_crypt"], phpass__ident="P") - self.assertRaises(KeyError, ctx.copy, md5_crypt__ident="P") - - # hash options 'salt' and 'rounds' not allowed - self.assertRaises(KeyError, CryptContext, schemes=["des_crypt"], - des_crypt__salt="xx") - self.assertRaises(KeyError, CryptContext, schemes=["des_crypt"], - all__salt="xx") - - def test_21_schemes(self): - """test 'schemes' context option parsing""" - - # schemes can be empty - cc = CryptContext(schemes=None) - self.assertEqual(cc.schemes(), ()) - - # schemes can be list of names - cc = CryptContext(schemes=["des_crypt", "md5_crypt"]) - self.assertEqual(cc.schemes(), ("des_crypt", "md5_crypt")) - - # schemes can be comma-sep string - cc = CryptContext(schemes=" des_crypt, md5_crypt, ") - self.assertEqual(cc.schemes(), ("des_crypt", "md5_crypt")) - - # schemes can be list of handlers - cc = CryptContext(schemes=[hash.des_crypt, hash.md5_crypt]) - self.assertEqual(cc.schemes(), ("des_crypt", "md5_crypt")) - - # scheme must be name or handler - self.assertRaises(TypeError, CryptContext, schemes=[uh.StaticHandler]) - - # handlers must have a name - class nameless(uh.StaticHandler): - name = None - self.assertRaises(ValueError, CryptContext, schemes=[nameless]) - - # names must be unique - class dummy_1(uh.StaticHandler): - name = 'dummy_1' - self.assertRaises(KeyError, CryptContext, schemes=[dummy_1, dummy_1]) - - # schemes not allowed per-category - self.assertRaises(KeyError, CryptContext, - admin__context__schemes=["md5_crypt"]) - - def test_22_deprecated(self): - """test 'deprecated' context option parsing""" - def getdep(ctx, category=None): - return [name for name in ctx.schemes() - if ctx.handler(name, category).deprecated] - - # no schemes - all deprecated values allowed - cc = CryptContext(deprecated=["md5_crypt"]) - cc.update(schemes=["md5_crypt", "des_crypt"]) - self.assertEqual(getdep(cc),["md5_crypt"]) - - # deprecated values allowed if subset of schemes - cc = CryptContext(deprecated=["md5_crypt"], schemes=["md5_crypt", "des_crypt"]) - self.assertEqual(getdep(cc), ["md5_crypt"]) - - # can be handler - # XXX: allow handlers in deprecated list? not for now. - self.assertRaises(TypeError, CryptContext, deprecated=[hash.md5_crypt], - schemes=["md5_crypt", "des_crypt"]) -## cc = CryptContext(deprecated=[hash.md5_crypt], schemes=["md5_crypt", "des_crypt"]) -## self.assertEqual(getdep(cc), ["md5_crypt"]) - - # comma sep list - cc = CryptContext(deprecated="md5_crypt,des_crypt", schemes=["md5_crypt", "des_crypt", "sha256_crypt"]) - self.assertEqual(getdep(cc), ["md5_crypt", "des_crypt"]) - - # values outside of schemes not allowed - self.assertRaises(KeyError, CryptContext, schemes=['des_crypt'], - deprecated=['md5_crypt']) - - # deprecating ALL schemes should cause ValueError - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt'], - deprecated=['des_crypt']) - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt', 'md5_crypt'], - admin__context__deprecated=['des_crypt', 'md5_crypt']) - - # deprecating explicit default scheme should cause ValueError - - # ... default listed as deprecated - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt', 'md5_crypt'], - default="md5_crypt", - deprecated="md5_crypt") - - # ... global default deprecated per-category - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt', 'md5_crypt'], - default="md5_crypt", - admin__context__deprecated="md5_crypt") - - # ... category default deprecated globally - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt', 'md5_crypt'], - admin__context__default="md5_crypt", - deprecated="md5_crypt") - - # ... category default deprecated in category - self.assertRaises(ValueError, CryptContext, - schemes=['des_crypt', 'md5_crypt'], - admin__context__default="md5_crypt", - admin__context__deprecated="md5_crypt") - - # category deplist should shadow default deplist - CryptContext( - schemes=['des_crypt', 'md5_crypt'], - deprecated="md5_crypt", - admin__context__default="md5_crypt", - admin__context__deprecated=[]) - - # wrong type - self.assertRaises(TypeError, CryptContext, deprecated=123) - - # deprecated per-category - cc = CryptContext(deprecated=["md5_crypt"], - schemes=["md5_crypt", "des_crypt"], - admin__context__deprecated=["des_crypt"], - ) - self.assertEqual(getdep(cc), ["md5_crypt"]) - self.assertEqual(getdep(cc, "user"), ["md5_crypt"]) - self.assertEqual(getdep(cc, "admin"), ["des_crypt"]) - - # blank per-category deprecated list, shadowing default list - cc = CryptContext(deprecated=["md5_crypt"], - schemes=["md5_crypt", "des_crypt"], - admin__context__deprecated=[], - ) - self.assertEqual(getdep(cc), ["md5_crypt"]) - self.assertEqual(getdep(cc, "user"), ["md5_crypt"]) - self.assertEqual(getdep(cc, "admin"), []) - - def test_23_default(self): - """test 'default' context option parsing""" - - # anything allowed if no schemes - self.assertEqual(CryptContext(default="md5_crypt").to_dict(), - dict(default="md5_crypt")) - - # default allowed if in scheme list - ctx = CryptContext(default="md5_crypt", schemes=["des_crypt", "md5_crypt"]) - self.assertEqual(ctx.default_scheme(), "md5_crypt") - - # default can be handler - # XXX: sure we want to allow this ? maybe deprecate in future. - ctx = CryptContext(default=hash.md5_crypt, schemes=["des_crypt", "md5_crypt"]) - self.assertEqual(ctx.default_scheme(), "md5_crypt") - - # implicit default should be first non-deprecated scheme - ctx = CryptContext(schemes=["des_crypt", "md5_crypt"]) - self.assertEqual(ctx.default_scheme(), "des_crypt") - ctx.update(deprecated="des_crypt") - self.assertEqual(ctx.default_scheme(), "md5_crypt") - - # error if not in scheme list - self.assertRaises(KeyError, CryptContext, schemes=['des_crypt'], - default='md5_crypt') - - # wrong type - self.assertRaises(TypeError, CryptContext, default=1) - - # per-category - ctx = CryptContext(default="des_crypt", - schemes=["des_crypt", "md5_crypt"], - admin__context__default="md5_crypt") - self.assertEqual(ctx.default_scheme(), "des_crypt") - self.assertEqual(ctx.default_scheme("user"), "des_crypt") - self.assertEqual(ctx.default_scheme("admin"), "md5_crypt") - - def test_24_vary_rounds(self): - """test 'vary_rounds' hash option parsing""" - def parse(v): - return CryptContext(all__vary_rounds=v).to_dict()['all__vary_rounds'] - - # floats should be preserved - self.assertEqual(parse(0.1), 0.1) - self.assertEqual(parse('0.1'), 0.1) - - # 'xx%' should be converted to float - self.assertEqual(parse('10%'), 0.1) - - # ints should be preserved - self.assertEqual(parse(1000), 1000) - self.assertEqual(parse('1000'), 1000) - - #=================================================================== - # inspection & serialization - #=================================================================== - - def assertHandlerDerivedFrom(self, handler, base, msg=None): - self.assertTrue(handler_derived_from(handler, base), msg=msg) - - def test_30_schemes(self): - """test schemes() method""" - # NOTE: also checked under test_21 - - # test empty - ctx = CryptContext() - self.assertEqual(ctx.schemes(), ()) - self.assertEqual(ctx.schemes(resolve=True), ()) - - # test sample 1 - ctx = CryptContext(**self.sample_1_dict) - self.assertEqual(ctx.schemes(), tuple(self.sample_1_schemes)) - self.assertEqual(ctx.schemes(resolve=True, unconfigured=True), tuple(self.sample_1_handlers)) - for result, correct in zip(ctx.schemes(resolve=True), self.sample_1_handlers): - self.assertTrue(handler_derived_from(result, correct)) - - # test sample 2 - ctx = CryptContext(**self.sample_2_dict) - self.assertEqual(ctx.schemes(), ()) - - def test_31_default_scheme(self): - """test default_scheme() method""" - # NOTE: also checked under test_23 - - # test empty - ctx = CryptContext() - self.assertRaises(KeyError, ctx.default_scheme) - - # test sample 1 - ctx = CryptContext(**self.sample_1_dict) - self.assertEqual(ctx.default_scheme(), "md5_crypt") - self.assertEqual(ctx.default_scheme(resolve=True, unconfigured=True), hash.md5_crypt) - self.assertHandlerDerivedFrom(ctx.default_scheme(resolve=True), hash.md5_crypt) - - # test sample 2 - ctx = CryptContext(**self.sample_2_dict) - self.assertRaises(KeyError, ctx.default_scheme) - - # test defaults to first in scheme - ctx = CryptContext(schemes=self.sample_1_schemes) - self.assertEqual(ctx.default_scheme(), "des_crypt") - - # categories tested under test_23 - - def test_32_handler(self): - """test handler() method""" - - # default for empty - ctx = CryptContext() - self.assertRaises(KeyError, ctx.handler) - self.assertRaises(KeyError, ctx.handler, "md5_crypt") - - # default for sample 1 - ctx = CryptContext(**self.sample_1_dict) - self.assertEqual(ctx.handler(unconfigured=True), hash.md5_crypt) - self.assertHandlerDerivedFrom(ctx.handler(), hash.md5_crypt) - - # by name - self.assertEqual(ctx.handler("des_crypt", unconfigured=True), hash.des_crypt) - self.assertHandlerDerivedFrom(ctx.handler("des_crypt"), hash.des_crypt) - - # name not in schemes - self.assertRaises(KeyError, ctx.handler, "mysql323") - - # check handler() honors category default - ctx = CryptContext("sha256_crypt,md5_crypt", admin__context__default="md5_crypt") - self.assertEqual(ctx.handler(unconfigured=True), hash.sha256_crypt) - self.assertHandlerDerivedFrom(ctx.handler(), hash.sha256_crypt) - - self.assertEqual(ctx.handler(category="staff", unconfigured=True), hash.sha256_crypt) - self.assertHandlerDerivedFrom(ctx.handler(category="staff"), hash.sha256_crypt) - - self.assertEqual(ctx.handler(category="admin", unconfigured=True), hash.md5_crypt) - self.assertHandlerDerivedFrom(ctx.handler(category="staff"), hash.sha256_crypt) - - # test unicode category strings are accepted under py2 - if PY2: - self.assertEqual(ctx.handler(category=u("staff"), unconfigured=True), hash.sha256_crypt) - self.assertEqual(ctx.handler(category=u("admin"), unconfigured=True), hash.md5_crypt) - - def test_33_options(self): - """test internal _get_record_options() method""" - - def options(ctx, scheme, category=None): - return ctx._config._get_record_options_with_flag(scheme, category)[0] - - # this checks that (3 schemes, 3 categories) inherit options correctly. - # the 'user' category is not present in the options. - cc4 = CryptContext( - truncate_error=True, - schemes = [ "sha512_crypt", "des_crypt", "bsdi_crypt"], - deprecated = ["sha512_crypt", "des_crypt"], - all__vary_rounds = 0.1, - bsdi_crypt__vary_rounds=0.2, - sha512_crypt__max_rounds = 20000, - admin__context__deprecated = [ "des_crypt", "bsdi_crypt" ], - admin__all__vary_rounds = 0.05, - admin__bsdi_crypt__vary_rounds=0.3, - admin__sha512_crypt__max_rounds = 40000, - ) - self.assertEqual(cc4._config.categories, ("admin",)) - - # - # sha512_crypt - # NOTE: 'truncate_error' shouldn't be passed along... - # - self.assertEqual(options(cc4, "sha512_crypt"), dict( - deprecated=True, - vary_rounds=0.1, # inherited from all__ - max_rounds=20000, - )) - - self.assertEqual(options(cc4, "sha512_crypt", "user"), dict( - deprecated=True, # unconfigured category inherits from default - vary_rounds=0.1, - max_rounds=20000, - )) - - self.assertEqual(options(cc4, "sha512_crypt", "admin"), dict( - # NOT deprecated - context option overridden per-category - vary_rounds=0.05, # global overridden per-cateogry - max_rounds=40000, # overridden per-category - )) - - # - # des_crypt - # NOTE: vary_rounds shouldn't be passed along... - # - self.assertEqual(options(cc4, "des_crypt"), dict( - deprecated=True, - truncate_error=True, - )) - - self.assertEqual(options(cc4, "des_crypt", "user"), dict( - deprecated=True, # unconfigured category inherits from default - truncate_error=True, - )) - - self.assertEqual(options(cc4, "des_crypt", "admin"), dict( - deprecated=True, # unchanged though overidden - truncate_error=True, - )) - - # - # bsdi_crypt - # - self.assertEqual(options(cc4, "bsdi_crypt"), dict( - vary_rounds=0.2, # overridden from all__vary_rounds - )) - - self.assertEqual(options(cc4, "bsdi_crypt", "user"), dict( - vary_rounds=0.2, # unconfigured category inherits from default - )) - - self.assertEqual(options(cc4, "bsdi_crypt", "admin"), dict( - vary_rounds=0.3, - deprecated=True, # deprecation set per-category - )) - - def test_34_to_dict(self): - """test to_dict() method""" - # NOTE: this is tested all throughout this test case. - ctx = CryptContext(**self.sample_1_dict) - self.assertEqual(ctx.to_dict(), self.sample_1_dict) - self.assertEqual(ctx.to_dict(resolve=True), self.sample_1_resolved_dict) - - def test_35_to_string(self): - """test to_string() method""" - - # create ctx and serialize - ctx = CryptContext(**self.sample_1_dict) - dump = ctx.to_string() - - # check ctx->string returns canonical format. - # NOTE: ConfigParser for PY26 doesn't use OrderedDict, - # making to_string()'s ordering unpredictable... - # so we skip this test under PY26. - if not PY26: - self.assertEqual(dump, self.sample_1_unicode) - - # check ctx->string->ctx->dict returns original - ctx2 = CryptContext.from_string(dump) - self.assertEqual(ctx2.to_dict(), self.sample_1_dict) - - # test section kwd is honored - other = ctx.to_string(section="password-security") - self.assertEqual(other, dump.replace("[passlib]","[password-security]")) - - # test unmanaged handler warning - from passlib.tests.test_utils_handlers import UnsaltedHash - ctx3 = CryptContext([UnsaltedHash, "md5_crypt"]) - dump = ctx3.to_string() - self.assertRegex(dump, r"# NOTE: the 'unsalted_test_hash' handler\(s\)" - r" are not registered with Passlib") - - #=================================================================== - # password hash api - #=================================================================== - nonstring_vectors = [ - (None, {}), - (None, {"scheme": "des_crypt"}), - (1, {}), - ((), {}), - ] - - def test_40_basic(self): - """test basic hash/identify/verify functionality""" - handlers = [hash.md5_crypt, hash.des_crypt, hash.bsdi_crypt] - cc = CryptContext(handlers, bsdi_crypt__default_rounds=5) - - # run through handlers - for crypt in handlers: - h = cc.hash("test", scheme=crypt.name) - self.assertEqual(cc.identify(h), crypt.name) - self.assertEqual(cc.identify(h, resolve=True, unconfigured=True), crypt) - self.assertHandlerDerivedFrom(cc.identify(h, resolve=True), crypt) - self.assertTrue(cc.verify('test', h)) - self.assertFalse(cc.verify('notest', h)) - - # test default - h = cc.hash("test") - self.assertEqual(cc.identify(h), "md5_crypt") - - # test genhash - h = cc.genhash('secret', cc.genconfig()) - self.assertEqual(cc.identify(h), 'md5_crypt') - - h = cc.genhash('secret', cc.genconfig(), scheme='md5_crypt') - self.assertEqual(cc.identify(h), 'md5_crypt') - - self.assertRaises(ValueError, cc.genhash, 'secret', cc.genconfig(), scheme="des_crypt") - - def test_41_genconfig(self): - """test genconfig() method""" - cc = CryptContext(schemes=["md5_crypt", "phpass"], - phpass__ident="H", - phpass__default_rounds=7, - admin__phpass__ident="P", - ) - - # uses default scheme - self.assertTrue(cc.genconfig().startswith("$1$")) - - # override scheme - self.assertTrue(cc.genconfig(scheme="phpass").startswith("$H$5")) - - # category override - self.assertTrue(cc.genconfig(scheme="phpass", category="admin").startswith("$P$5")) - self.assertTrue(cc.genconfig(scheme="phpass", category="staff").startswith("$H$5")) - - # override scheme & custom settings - self.assertEqual( - cc.genconfig(scheme="phpass", salt='.'*8, rounds=8, ident='P'), - '$P$6........22zGEuacuPOqEpYPDeR0R/', # NOTE: config string generated w/ rounds=1 - ) - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # test unicode category strings are accepted under py2 - # this tests basic _get_record() used by hash/genhash/verify. - # we have to omit scheme=xxx so codepath is tested fully - if PY2: - c2 = cc.copy(default="phpass") - self.assertTrue(c2.genconfig(category=u("admin")).startswith("$P$5")) - self.assertTrue(c2.genconfig(category=u("staff")).startswith("$H$5")) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().genconfig) - self.assertRaises(KeyError, CryptContext().genconfig, scheme='md5_crypt') - - # bad scheme values - self.assertRaises(KeyError, cc.genconfig, scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.genconfig, scheme=1, category='staff') - self.assertRaises(TypeError, cc.genconfig, scheme=1) - - # bad category values - self.assertRaises(TypeError, cc.genconfig, category=1) - - - def test_42_genhash(self): - """test genhash() method""" - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # rejects non-string secrets - cc = CryptContext(["des_crypt"]) - hash = cc.hash('stub') - for secret, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.genhash, secret, hash, **kwds) - - # rejects non-string config strings - cc = CryptContext(["des_crypt"]) - for config, kwds in self.nonstring_vectors: - if hash is None: - # NOTE: as of 1.7, genhash is just wrapper for hash(), - # and handles genhash(secret, None) fine. - continue - self.assertRaises(TypeError, cc.genhash, 'secret', config, **kwds) - - # rejects config=None, even if default scheme lacks config string - cc = CryptContext(["mysql323"]) - self.assertRaises(TypeError, cc.genhash, "stub", None) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().genhash, 'secret', 'hash') - - # bad scheme values - self.assertRaises(KeyError, cc.genhash, 'secret', hash, scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.genhash, 'secret', hash, scheme=1) - - # bad category values - self.assertRaises(TypeError, cc.genconfig, 'secret', hash, category=1) - - def test_43_hash(self,): - """test hash() method""" - # XXX: what more can we test here that isn't deprecated - # or handled under another test (e.g. context kwds?) - - # respects rounds - cc = CryptContext(**self.sample_4_dict) - hash = cc.hash("password") - self.assertTrue(hash.startswith("$5$rounds=3000$")) - self.assertTrue(cc.verify("password", hash)) - self.assertFalse(cc.verify("passwordx", hash)) - - # make default > max throws error if attempted - # XXX: move this to copy() test? - self.assertRaises(ValueError, cc.copy, - sha256_crypt__default_rounds=4000) - - # rejects non-string secrets - cc = CryptContext(["des_crypt"]) - for secret, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.hash, secret, **kwds) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().hash, 'secret') - - # bad category values - self.assertRaises(TypeError, cc.hash, 'secret', category=1) - - def test_43_hash_legacy(self, use_16_legacy=False): - """test hash() method -- legacy 'scheme' and settings keywords""" - cc = CryptContext(**self.sample_4_dict) - - # TODO: should migrate these tests elsewhere, or remove them. - # can be replaced with following equivalent: - # - # def wrapper(secret, scheme=None, category=None, **kwds): - # handler = cc.handler(scheme, category) - # if kwds: - # handler = handler.using(**kwds) - # return handler.hash(secret) - # - # need to make sure bits being tested here are tested - # under the tests for the equivalent methods called above, - # and then discard the rest of these under 2.0. - - # hash specific settings - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertEqual( - cc.hash("password", scheme="phpass", salt='.'*8), - '$H$5........De04R5Egz0aq8Tf.1eVhY/', - ) - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertEqual( - cc.hash("password", scheme="phpass", salt='.'*8, ident="P"), - '$P$5........De04R5Egz0aq8Tf.1eVhY/', - ) - - # NOTE: more thorough job of rounds limits done below. - - # min rounds - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertEqual( - cc.hash("password", rounds=1999, salt="nacl"), - '$5$rounds=1999$nacl$nmfwJIxqj0csloAAvSER0B8LU0ERCAbhmMug4Twl609', - ) - - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertEqual( - cc.hash("password", rounds=2001, salt="nacl"), - '$5$rounds=2001$nacl$8PdeoPL4aXQnJ0woHhqgIw/efyfCKC2WHneOpnvF.31' - ) - # NOTE: max rounds, etc tested in genconfig() - - # bad scheme values - self.assertRaises(KeyError, cc.hash, 'secret', scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.hash, 'secret', scheme=1) - - def test_44_identify(self): - """test identify() border cases""" - handlers = ["md5_crypt", "des_crypt", "bsdi_crypt"] - cc = CryptContext(handlers, bsdi_crypt__default_rounds=5) - - # check unknown hash - self.assertEqual(cc.identify('$9$232323123$1287319827'), None) - self.assertRaises(ValueError, cc.identify, '$9$232323123$1287319827', required=True) - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # rejects non-string hashes - cc = CryptContext(["des_crypt"]) - for hash, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.identify, hash, **kwds) - - # throws error without schemes - cc = CryptContext() - self.assertIs(cc.identify('hash'), None) - self.assertRaises(KeyError, cc.identify, 'hash', required=True) - - # bad category values - self.assertRaises(TypeError, cc.identify, None, category=1) - - def test_45_verify(self): - """test verify() scheme kwd""" - handlers = ["md5_crypt", "des_crypt", "bsdi_crypt"] - cc = CryptContext(handlers, bsdi_crypt__default_rounds=5) - - h = hash.md5_crypt.hash("test") - - # check base verify - self.assertTrue(cc.verify("test", h)) - self.assertTrue(not cc.verify("notest", h)) - - # check verify using right alg - self.assertTrue(cc.verify('test', h, scheme='md5_crypt')) - self.assertTrue(not cc.verify('notest', h, scheme='md5_crypt')) - - # check verify using wrong alg - self.assertRaises(ValueError, cc.verify, 'test', h, scheme='bsdi_crypt') - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # unknown hash should throw error - self.assertRaises(ValueError, cc.verify, 'stub', '$6$232323123$1287319827') - - # rejects non-string secrets - cc = CryptContext(["des_crypt"]) - h = refhash = cc.hash('stub') - for secret, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.verify, secret, h, **kwds) - - # always treat hash=None as False - self.assertFalse(cc.verify(secret, None)) - - # rejects non-string hashes - cc = CryptContext(["des_crypt"]) - for h, kwds in self.nonstring_vectors: - if h is None: - continue - self.assertRaises(TypeError, cc.verify, 'secret', h, **kwds) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().verify, 'secret', 'hash') - - # bad scheme values - self.assertRaises(KeyError, cc.verify, 'secret', refhash, scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.verify, 'secret', refhash, scheme=1) - - # bad category values - self.assertRaises(TypeError, cc.verify, 'secret', refhash, category=1) - - def test_46_needs_update(self): - """test needs_update() method""" - cc = CryptContext(**self.sample_4_dict) - - # check deprecated scheme - self.assertTrue(cc.needs_update('9XXD4trGYeGJA')) - self.assertFalse(cc.needs_update('$1$J8HC2RCr$HcmM.7NxB2weSvlw2FgzU0')) - - # check min rounds - self.assertTrue(cc.needs_update('$5$rounds=1999$jD81UCoo.zI.UETs$Y7qSTQ6mTiU9qZB4fRr43wRgQq4V.5AAf7F97Pzxey/')) - self.assertFalse(cc.needs_update('$5$rounds=2000$228SSRje04cnNCaQ$YGV4RYu.5sNiBvorQDlO0WWQjyJVGKBcJXz3OtyQ2u8')) - - # check max rounds - self.assertFalse(cc.needs_update('$5$rounds=3000$fS9iazEwTKi7QPW4$VasgBC8FqlOvD7x2HhABaMXCTh9jwHclPA9j5YQdns.')) - self.assertTrue(cc.needs_update('$5$rounds=3001$QlFHHifXvpFX4PLs$/0ekt7lSs/lOikSerQ0M/1porEHxYq7W/2hdFpxA3fA')) - - #-------------------------------------------------------------- - # test hash.needs_update() interface - #-------------------------------------------------------------- - check_state = [] - class dummy(uh.StaticHandler): - name = 'dummy' - _hash_prefix = '@' - - @classmethod - def needs_update(cls, hash, secret=None): - check_state.append((hash, secret)) - return secret == "nu" - - def _calc_checksum(self, secret): - from hashlib import md5 - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(md5(secret).hexdigest()) - - # calling needs_update should query callback - ctx = CryptContext([dummy]) - hash = refhash = dummy.hash("test") - self.assertFalse(ctx.needs_update(hash)) - self.assertEqual(check_state, [(hash,None)]) - del check_state[:] - - # now with a password - self.assertFalse(ctx.needs_update(hash, secret='bob')) - self.assertEqual(check_state, [(hash,'bob')]) - del check_state[:] - - # now when it returns True - self.assertTrue(ctx.needs_update(hash, secret='nu')) - self.assertEqual(check_state, [(hash,'nu')]) - del check_state[:] - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # rejects non-string hashes - cc = CryptContext(["des_crypt"]) - for hash, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.needs_update, hash, **kwds) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().needs_update, 'hash') - - # bad scheme values - self.assertRaises(KeyError, cc.needs_update, refhash, scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.needs_update, refhash, scheme=1) - - # bad category values - self.assertRaises(TypeError, cc.needs_update, refhash, category=1) - - def test_47_verify_and_update(self): - """test verify_and_update()""" - cc = CryptContext(**self.sample_4_dict) - - # create some hashes - h1 = cc.handler("des_crypt").hash("password") - h2 = cc.handler("sha256_crypt").hash("password") - - # check bad password, deprecated hash - ok, new_hash = cc.verify_and_update("wrongpass", h1) - self.assertFalse(ok) - self.assertIs(new_hash, None) - - # check bad password, good hash - ok, new_hash = cc.verify_and_update("wrongpass", h2) - self.assertFalse(ok) - self.assertIs(new_hash, None) - - # check right password, deprecated hash - ok, new_hash = cc.verify_and_update("password", h1) - self.assertTrue(ok) - self.assertTrue(cc.identify(new_hash), "sha256_crypt") - - # check right password, good hash - ok, new_hash = cc.verify_and_update("password", h2) - self.assertTrue(ok) - self.assertIs(new_hash, None) - - #-------------------------------------------------------------- - # border cases - #-------------------------------------------------------------- - - # rejects non-string secrets - cc = CryptContext(["des_crypt"]) - hash = refhash = cc.hash('stub') - for secret, kwds in self.nonstring_vectors: - self.assertRaises(TypeError, cc.verify_and_update, secret, hash, **kwds) - - # always treat hash=None as False - self.assertEqual(cc.verify_and_update(secret, None), (False, None)) - - # rejects non-string hashes - cc = CryptContext(["des_crypt"]) - for hash, kwds in self.nonstring_vectors: - if hash is None: - continue - self.assertRaises(TypeError, cc.verify_and_update, 'secret', hash, **kwds) - - # throws error without schemes - self.assertRaises(KeyError, CryptContext().verify_and_update, 'secret', 'hash') - - # bad scheme values - self.assertRaises(KeyError, cc.verify_and_update, 'secret', refhash, scheme="fake") # XXX: should this be ValueError? - self.assertRaises(TypeError, cc.verify_and_update, 'secret', refhash, scheme=1) - - # bad category values - self.assertRaises(TypeError, cc.verify_and_update, 'secret', refhash, category=1) - - def test_48_context_kwds(self): - """hash(), verify(), and verify_and_update() -- discard unused context keywords""" - - # setup test case - # NOTE: postgres_md5 hash supports 'user' context kwd, which is used for this test. - from passlib.hash import des_crypt, md5_crypt, postgres_md5 - des_hash = des_crypt.hash("stub") - pg_root_hash = postgres_md5.hash("stub", user="root") - pg_admin_hash = postgres_md5.hash("stub", user="admin") - - #------------------------------------------------------------ - # case 1: contextual kwds not supported by any hash in CryptContext - #------------------------------------------------------------ - cc1 = CryptContext([des_crypt, md5_crypt]) - self.assertEqual(cc1.context_kwds, set()) - - # des_scrypt should work w/o any contextual kwds - self.assertTrue(des_crypt.identify(cc1.hash("stub")), "des_crypt") - self.assertTrue(cc1.verify("stub", des_hash)) - self.assertEqual(cc1.verify_and_update("stub", des_hash), (True, None)) - - # des_crypt should throw error due to unknown context keyword - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertRaises(TypeError, cc1.hash, "stub", user="root") - self.assertRaises(TypeError, cc1.verify, "stub", des_hash, user="root") - self.assertRaises(TypeError, cc1.verify_and_update, "stub", des_hash, user="root") - - #------------------------------------------------------------ - # case 2: at least one contextual kwd supported by non-default hash - #------------------------------------------------------------ - cc2 = CryptContext([des_crypt, postgres_md5]) - self.assertEqual(cc2.context_kwds, set(["user"])) - - # verify des_crypt works w/o "user" kwd - self.assertTrue(des_crypt.identify(cc2.hash("stub")), "des_crypt") - self.assertTrue(cc2.verify("stub", des_hash)) - self.assertEqual(cc2.verify_and_update("stub", des_hash), (True, None)) - - # verify des_crypt ignores "user" kwd - self.assertTrue(des_crypt.identify(cc2.hash("stub", user="root")), "des_crypt") - self.assertTrue(cc2.verify("stub", des_hash, user="root")) - self.assertEqual(cc2.verify_and_update("stub", des_hash, user="root"), (True, None)) - - # verify error with unknown kwd - with self.assertWarningList(["passing settings to.*is deprecated"]): - self.assertRaises(TypeError, cc2.hash, "stub", badkwd="root") - self.assertRaises(TypeError, cc2.verify, "stub", des_hash, badkwd="root") - self.assertRaises(TypeError, cc2.verify_and_update, "stub", des_hash, badkwd="root") - - #------------------------------------------------------------ - # case 3: at least one contextual kwd supported by default hash - #------------------------------------------------------------ - cc3 = CryptContext([postgres_md5, des_crypt], deprecated="auto") - self.assertEqual(cc3.context_kwds, set(["user"])) - - # postgres_md5 should have error w/o context kwd - self.assertRaises(TypeError, cc3.hash, "stub") - self.assertRaises(TypeError, cc3.verify, "stub", pg_root_hash) - self.assertRaises(TypeError, cc3.verify_and_update, "stub", pg_root_hash) - - # postgres_md5 should work w/ context kwd - self.assertEqual(cc3.hash("stub", user="root"), pg_root_hash) - self.assertTrue(cc3.verify("stub", pg_root_hash, user="root")) - self.assertEqual(cc3.verify_and_update("stub", pg_root_hash, user="root"), (True, None)) - - # verify_and_update() should fail against wrong user - self.assertEqual(cc3.verify_and_update("stub", pg_root_hash, user="admin"), (False, None)) - - # verify_and_update() should pass all context kwds through when rehashing - self.assertEqual(cc3.verify_and_update("stub", des_hash, user="root"), - (True, pg_root_hash)) - - #=================================================================== - # rounds options - #=================================================================== - - # TODO: now that rounds generation has moved out of _CryptRecord to HasRounds, - # this should just test that we're passing right options to handler.using(), - # and that resulting handler has right settings. - # Can then just let HasRounds tests (which are a copy of this) deal with things. - - # NOTE: the follow tests check how _CryptRecord handles - # the min/max/default/vary_rounds options, via the output of - # genconfig(). it's assumed hash() takes the same codepath. - - def test_50_rounds_limits(self): - """test rounds limits""" - cc = CryptContext(schemes=["sha256_crypt"], - sha256_crypt__min_rounds=2000, - sha256_crypt__max_rounds=3000, - sha256_crypt__default_rounds=2500, - ) - - # stub digest returned by sha256_crypt's genconfig calls.. - STUB = '...........................................' - - #-------------------------------------------------- - # settings should have been applied to custom handler, - # it should take care of the rest - #-------------------------------------------------- - custom_handler = cc._get_record("sha256_crypt", None) - self.assertEqual(custom_handler.min_desired_rounds, 2000) - self.assertEqual(custom_handler.max_desired_rounds, 3000) - self.assertEqual(custom_handler.default_rounds, 2500) - - #-------------------------------------------------- - # min_rounds - #-------------------------------------------------- - - # set below handler minimum - with self.assertWarningList([PasslibHashWarning]*2): - c2 = cc.copy(sha256_crypt__min_rounds=500, sha256_crypt__max_rounds=None, - sha256_crypt__default_rounds=500) - self.assertEqual(c2.genconfig(salt="nacl"), "$5$rounds=1000$nacl$" + STUB) - - # below policy minimum - # NOTE: formerly issued a warning in passlib 1.6, now just a wrapper for .replace() - with self.assertWarningList([]): - self.assertEqual( - cc.genconfig(rounds=1999, salt="nacl"), '$5$rounds=1999$nacl$' + STUB) - - # equal to policy minimum - self.assertEqual( - cc.genconfig(rounds=2000, salt="nacl"), '$5$rounds=2000$nacl$' + STUB) - - # above policy minimum - self.assertEqual( - cc.genconfig(rounds=2001, salt="nacl"), '$5$rounds=2001$nacl$' + STUB) - - #-------------------------------------------------- - # max rounds - #-------------------------------------------------- - - # set above handler max - with self.assertWarningList([PasslibHashWarning]*2): - c2 = cc.copy(sha256_crypt__max_rounds=int(1e9)+500, sha256_crypt__min_rounds=None, - sha256_crypt__default_rounds=int(1e9)+500) - - self.assertEqual(c2.genconfig(salt="nacl"), "$5$rounds=999999999$nacl$" + STUB) - - # above policy max - # NOTE: formerly issued a warning in passlib 1.6, now just a wrapper for .using() - with self.assertWarningList([]): - self.assertEqual( - cc.genconfig(rounds=3001, salt="nacl"), '$5$rounds=3001$nacl$' + STUB) - - # equal policy max - self.assertEqual( - cc.genconfig(rounds=3000, salt="nacl"), '$5$rounds=3000$nacl$' + STUB) - - # below policy max - self.assertEqual( - cc.genconfig(rounds=2999, salt="nacl"), '$5$rounds=2999$nacl$' + STUB) - - #-------------------------------------------------- - # default_rounds - #-------------------------------------------------- - - # explicit default rounds - self.assertEqual(cc.genconfig(salt="nacl"), '$5$rounds=2500$nacl$' + STUB) - - # fallback default rounds - use handler's - df = hash.sha256_crypt.default_rounds - c2 = cc.copy(sha256_crypt__default_rounds=None, sha256_crypt__max_rounds=df<<1) - self.assertEqual(c2.genconfig(salt="nacl"), '$5$rounds=%d$nacl$%s' % (df, STUB)) - - # fallback default rounds - use handler's, but clipped to max rounds - c2 = cc.copy(sha256_crypt__default_rounds=None, sha256_crypt__max_rounds=3000) - self.assertEqual(c2.genconfig(salt="nacl"), '$5$rounds=3000$nacl$' + STUB) - - # TODO: test default falls back to mx / mn if handler has no default. - - # default rounds - out of bounds - self.assertRaises(ValueError, cc.copy, sha256_crypt__default_rounds=1999) - cc.copy(sha256_crypt__default_rounds=2000) - cc.copy(sha256_crypt__default_rounds=3000) - self.assertRaises(ValueError, cc.copy, sha256_crypt__default_rounds=3001) - - #-------------------------------------------------- - # border cases - #-------------------------------------------------- - - # invalid min/max bounds - c2 = CryptContext(schemes=["sha256_crypt"]) - # NOTE: as of v1.7, these are clipped w/ a warning instead... - # self.assertRaises(ValueError, c2.copy, sha256_crypt__min_rounds=-1) - # self.assertRaises(ValueError, c2.copy, sha256_crypt__max_rounds=-1) - self.assertRaises(ValueError, c2.copy, sha256_crypt__min_rounds=2000, - sha256_crypt__max_rounds=1999) - - # test bad values - self.assertRaises(ValueError, CryptContext, sha256_crypt__min_rounds='x') - self.assertRaises(ValueError, CryptContext, sha256_crypt__max_rounds='x') - self.assertRaises(ValueError, CryptContext, all__vary_rounds='x') - self.assertRaises(ValueError, CryptContext, sha256_crypt__default_rounds='x') - - # test bad types rejected - bad = datetime.datetime.now() # picked cause can't be compared to int - self.assertRaises(TypeError, CryptContext, "sha256_crypt", sha256_crypt__min_rounds=bad) - self.assertRaises(TypeError, CryptContext, "sha256_crypt", sha256_crypt__max_rounds=bad) - self.assertRaises(TypeError, CryptContext, "sha256_crypt", all__vary_rounds=bad) - self.assertRaises(TypeError, CryptContext, "sha256_crypt", sha256_crypt__default_rounds=bad) - - def test_51_linear_vary_rounds(self): - """test linear vary rounds""" - cc = CryptContext(schemes=["sha256_crypt"], - sha256_crypt__min_rounds=1995, - sha256_crypt__max_rounds=2005, - sha256_crypt__default_rounds=2000, - ) - - # test negative - self.assertRaises(ValueError, cc.copy, all__vary_rounds=-1) - self.assertRaises(ValueError, cc.copy, all__vary_rounds="-1%") - self.assertRaises(ValueError, cc.copy, all__vary_rounds="101%") - - # test static - c2 = cc.copy(all__vary_rounds=0) - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 0) - self.assert_rounds_range(c2, "sha256_crypt", 2000, 2000) - - c2 = cc.copy(all__vary_rounds="0%") - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 0) - self.assert_rounds_range(c2, "sha256_crypt", 2000, 2000) - - # test absolute - c2 = cc.copy(all__vary_rounds=1) - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 1) - self.assert_rounds_range(c2, "sha256_crypt", 1999, 2001) - c2 = cc.copy(all__vary_rounds=100) - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 100) - self.assert_rounds_range(c2, "sha256_crypt", 1995, 2005) - - # test relative - c2 = cc.copy(all__vary_rounds="0.1%") - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 0.001) - self.assert_rounds_range(c2, "sha256_crypt", 1998, 2002) - c2 = cc.copy(all__vary_rounds="100%") - self.assertEqual(c2._get_record("sha256_crypt", None).vary_rounds, 1.0) - self.assert_rounds_range(c2, "sha256_crypt", 1995, 2005) - - def test_52_log2_vary_rounds(self): - """test log2 vary rounds""" - cc = CryptContext(schemes=["bcrypt"], - bcrypt__min_rounds=15, - bcrypt__max_rounds=25, - bcrypt__default_rounds=20, - ) - - # test negative - self.assertRaises(ValueError, cc.copy, all__vary_rounds=-1) - self.assertRaises(ValueError, cc.copy, all__vary_rounds="-1%") - self.assertRaises(ValueError, cc.copy, all__vary_rounds="101%") - - # test static - c2 = cc.copy(all__vary_rounds=0) - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 0) - self.assert_rounds_range(c2, "bcrypt", 20, 20) - - c2 = cc.copy(all__vary_rounds="0%") - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 0) - self.assert_rounds_range(c2, "bcrypt", 20, 20) - - # test absolute - c2 = cc.copy(all__vary_rounds=1) - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 1) - self.assert_rounds_range(c2, "bcrypt", 19, 21) - c2 = cc.copy(all__vary_rounds=100) - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 100) - self.assert_rounds_range(c2, "bcrypt", 15, 25) - - # test relative - should shift over at 50% mark - c2 = cc.copy(all__vary_rounds="1%") - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 0.01) - self.assert_rounds_range(c2, "bcrypt", 20, 20) - - c2 = cc.copy(all__vary_rounds="49%") - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 0.49) - self.assert_rounds_range(c2, "bcrypt", 20, 20) - - c2 = cc.copy(all__vary_rounds="50%") - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 0.5) - self.assert_rounds_range(c2, "bcrypt", 19, 20) - - c2 = cc.copy(all__vary_rounds="100%") - self.assertEqual(c2._get_record("bcrypt", None).vary_rounds, 1.0) - self.assert_rounds_range(c2, "bcrypt", 15, 21) - - def assert_rounds_range(self, context, scheme, lower, upper): - """helper to check vary_rounds covers specified range""" - # NOTE: this runs enough times the min and max *should* be hit, - # though there's a faint chance it will randomly fail. - handler = context.handler(scheme) - salt = handler.default_salt_chars[0:1] * handler.max_salt_size - seen = set() - for i in irange(300): - h = context.genconfig(scheme, salt=salt) - r = handler.from_string(h).rounds - seen.add(r) - self.assertEqual(min(seen), lower, "vary_rounds had wrong lower limit:") - self.assertEqual(max(seen), upper, "vary_rounds had wrong upper limit:") - - #=================================================================== - # harden_verify / min_verify_time - #=================================================================== - def test_harden_verify_parsing(self): - """harden_verify -- parsing""" - warnings.filterwarnings("ignore", ".*harden_verify.*", - category=DeprecationWarning) - - # valid values - ctx = CryptContext(schemes=["sha256_crypt"]) - self.assertEqual(ctx.harden_verify, None) - self.assertEqual(ctx.using(harden_verify="").harden_verify, None) - self.assertEqual(ctx.using(harden_verify="true").harden_verify, None) - self.assertEqual(ctx.using(harden_verify="false").harden_verify, None) - - def test_dummy_verify(self): - """ - dummy_verify() method - """ - # check dummy_verify() takes expected time - expected = 0.05 - accuracy = 0.2 - handler = DelayHash.using() - handler.delay = expected - ctx = CryptContext(schemes=[handler]) - ctx.dummy_verify() # prime the memoized helpers - elapsed, _ = time_call(ctx.dummy_verify) - self.assertAlmostEqual(elapsed, expected, delta=expected * accuracy) - - # TODO: test dummy_verify() invoked by .verify() when hash is None, - # and same for .verify_and_update() - - #=================================================================== - # feature tests - #=================================================================== - def test_61_autodeprecate(self): - """test deprecated='auto' is handled correctly""" - - def getstate(ctx, category=None): - return [ctx.handler(scheme, category).deprecated for scheme in ctx.schemes()] - - # correctly reports default - ctx = CryptContext("sha256_crypt,md5_crypt,des_crypt", deprecated="auto") - self.assertEqual(getstate(ctx, None), [False, True, True]) - self.assertEqual(getstate(ctx, "admin"), [False, True, True]) - - # correctly reports changed default - ctx.update(default="md5_crypt") - self.assertEqual(getstate(ctx, None), [True, False, True]) - self.assertEqual(getstate(ctx, "admin"), [True, False, True]) - - # category default is handled correctly - ctx.update(admin__context__default="des_crypt") - self.assertEqual(getstate(ctx, None), [True, False, True]) - self.assertEqual(getstate(ctx, "admin"), [True, True, False]) - - # handles 1 scheme - ctx = CryptContext(["sha256_crypt"], deprecated="auto") - self.assertEqual(getstate(ctx, None), [False]) - self.assertEqual(getstate(ctx, "admin"), [False]) - - # disallow auto & other deprecated schemes at same time. - self.assertRaises(ValueError, CryptContext, "sha256_crypt,md5_crypt", - deprecated="auto,md5_crypt") - self.assertRaises(ValueError, CryptContext, "sha256_crypt,md5_crypt", - deprecated="md5_crypt,auto") - - def test_disabled_hashes(self): - """disabled hash support""" - # - # init ref info - # - from passlib.exc import UnknownHashError - from passlib.hash import md5_crypt, unix_disabled - - ctx = CryptContext(["des_crypt"]) - ctx2 = CryptContext(["des_crypt", "unix_disabled"]) - h_ref = ctx.hash("foo") - h_other = md5_crypt.hash('foo') - - # - # ctx.disable() - # - - # test w/o disabled hash support - self.assertRaisesRegex(RuntimeError, "no disabled hasher present", - ctx.disable) - self.assertRaisesRegex(RuntimeError, "no disabled hasher present", - ctx.disable, h_ref) - self.assertRaisesRegex(RuntimeError, "no disabled hasher present", - ctx.disable, h_other) - - # test w/ disabled hash support - h_dis = ctx2.disable() - self.assertEqual(h_dis, unix_disabled.default_marker) - h_dis_ref = ctx2.disable(h_ref) - self.assertEqual(h_dis_ref, unix_disabled.default_marker + h_ref) - - h_dis_other = ctx2.disable(h_other) - self.assertEqual(h_dis_other, unix_disabled.default_marker + h_other) - - # don't double-wrap existing disabled hash - self.assertEqual(ctx2.disable(h_dis_ref), h_dis_ref) - - # - # ctx.is_enabled() - # - - # test w/o disabled hash support - self.assertTrue(ctx.is_enabled(h_ref)) - self.assertRaises(UnknownHashError, ctx.is_enabled, h_other) - self.assertRaises(UnknownHashError, ctx.is_enabled, h_dis) - self.assertRaises(UnknownHashError, ctx.is_enabled, h_dis_ref) - - # test w/ disabled hash support - self.assertTrue(ctx2.is_enabled(h_ref)) - self.assertRaises(UnknownHashError, ctx.is_enabled, h_other) - self.assertFalse(ctx2.is_enabled(h_dis)) - self.assertFalse(ctx2.is_enabled(h_dis_ref)) - - # - # ctx.enable() - # - - # test w/o disabled hash support - self.assertRaises(UnknownHashError, ctx.enable, "") - self.assertRaises(TypeError, ctx.enable, None) - self.assertEqual(ctx.enable(h_ref), h_ref) - self.assertRaises(UnknownHashError, ctx.enable, h_other) - self.assertRaises(UnknownHashError, ctx.enable, h_dis) - self.assertRaises(UnknownHashError, ctx.enable, h_dis_ref) - - # test w/ disabled hash support - self.assertRaises(UnknownHashError, ctx.enable, "") - self.assertRaises(TypeError, ctx2.enable, None) - self.assertEqual(ctx2.enable(h_ref), h_ref) - self.assertRaises(UnknownHashError, ctx2.enable, h_other) - self.assertRaisesRegex(ValueError, "cannot restore original hash", - ctx2.enable, h_dis) - self.assertEqual(ctx2.enable(h_dis_ref), h_ref) - - #=================================================================== - # eoc - #=================================================================== - -import hashlib, time - -class DelayHash(uh.StaticHandler): - """dummy hasher which delays by specified amount""" - name = "delay_hash" - checksum_chars = uh.LOWER_HEX_CHARS - checksum_size = 40 - delay = 0 - _hash_prefix = u("$x$") - - def _calc_checksum(self, secret): - time.sleep(self.delay) - if isinstance(secret, unicode): - secret = secret.encode("utf-8") - return str_to_uascii(hashlib.sha1(b"prefix" + secret).hexdigest()) - -#============================================================================= -# LazyCryptContext -#============================================================================= -class dummy_2(uh.StaticHandler): - name = "dummy_2" - -class LazyCryptContextTest(TestCase): - descriptionPrefix = "LazyCryptContext" - - def setUp(self): - # make sure this isn't registered before OR after - unload_handler_name("dummy_2") - self.addCleanup(unload_handler_name, "dummy_2") - - def test_kwd_constructor(self): - """test plain kwds""" - self.assertFalse(has_crypt_handler("dummy_2")) - register_crypt_handler_path("dummy_2", "passlib.tests.test_context") - - cc = LazyCryptContext(iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) - - self.assertFalse(has_crypt_handler("dummy_2", True)) - - self.assertEqual(cc.schemes(), ("dummy_2", "des_crypt")) - self.assertTrue(cc.handler("des_crypt").deprecated) - - self.assertTrue(has_crypt_handler("dummy_2", True)) - - def test_callable_constructor(self): - self.assertFalse(has_crypt_handler("dummy_2")) - register_crypt_handler_path("dummy_2", "passlib.tests.test_context") - - def onload(flag=False): - self.assertTrue(flag) - return dict(schemes=iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) - - cc = LazyCryptContext(onload=onload, flag=True) - - self.assertFalse(has_crypt_handler("dummy_2", True)) - - self.assertEqual(cc.schemes(), ("dummy_2", "des_crypt")) - self.assertTrue(cc.handler("des_crypt").deprecated) - - self.assertTrue(has_crypt_handler("dummy_2", True)) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context_deprecated.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context_deprecated.py deleted file mode 100644 index 0f76624..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_context_deprecated.py +++ /dev/null @@ -1,743 +0,0 @@ -"""tests for passlib.context - -this file is a clone of the 1.5 test_context.py, -containing the tests using the legacy CryptPolicy api. -it's being preserved here to ensure the old api doesn't break -(until Passlib 1.8, when this and the legacy api will be removed). -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -from logging import getLogger -import os -import warnings -# site -try: - from pkg_resources import resource_filename -except ImportError: - resource_filename = None -# pkg -from passlib import hash -from passlib.context import CryptContext, CryptPolicy, LazyCryptContext -from passlib.utils import to_bytes, to_unicode -import passlib.utils.handlers as uh -from passlib.tests.utils import TestCase, set_file -from passlib.registry import (register_crypt_handler_path, - _has_crypt_handler as has_crypt_handler, - _unload_handler_name as unload_handler_name, - ) -# module -log = getLogger(__name__) - -#============================================================================= -# -#============================================================================= -class CryptPolicyTest(TestCase): - """test CryptPolicy object""" - - # TODO: need to test user categories w/in all this - - descriptionPrefix = "CryptPolicy" - - #=================================================================== - # sample crypt policies used for testing - #=================================================================== - - #--------------------------------------------------------------- - # sample 1 - average config file - #--------------------------------------------------------------- - # NOTE: copy of this is stored in file passlib/tests/sample_config_1s.cfg - sample_config_1s = """\ -[passlib] -schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt -default = md5_crypt -all.vary_rounds = 10%% -bsdi_crypt.max_rounds = 30000 -bsdi_crypt.default_rounds = 25000 -sha512_crypt.max_rounds = 50000 -sha512_crypt.min_rounds = 40000 -""" - sample_config_1s_path = os.path.abspath(os.path.join( - os.path.dirname(__file__), "sample_config_1s.cfg")) - if not os.path.exists(sample_config_1s_path) and resource_filename: - # in case we're zipped up in an egg. - sample_config_1s_path = resource_filename("passlib.tests", - "sample_config_1s.cfg") - - # make sure sample_config_1s uses \n linesep - tests rely on this - assert sample_config_1s.startswith("[passlib]\nschemes") - - sample_config_1pd = dict( - schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"], - default = "md5_crypt", - # NOTE: not maintaining backwards compat for rendering to "10%" - all__vary_rounds = 0.1, - bsdi_crypt__max_rounds = 30000, - bsdi_crypt__default_rounds = 25000, - sha512_crypt__max_rounds = 50000, - sha512_crypt__min_rounds = 40000, - ) - - sample_config_1pid = { - "schemes": "des_crypt, md5_crypt, bsdi_crypt, sha512_crypt", - "default": "md5_crypt", - # NOTE: not maintaining backwards compat for rendering to "10%" - "all.vary_rounds": 0.1, - "bsdi_crypt.max_rounds": 30000, - "bsdi_crypt.default_rounds": 25000, - "sha512_crypt.max_rounds": 50000, - "sha512_crypt.min_rounds": 40000, - } - - sample_config_1prd = dict( - schemes = [ hash.des_crypt, hash.md5_crypt, hash.bsdi_crypt, hash.sha512_crypt], - default = "md5_crypt", # NOTE: passlib <= 1.5 was handler obj. - # NOTE: not maintaining backwards compat for rendering to "10%" - all__vary_rounds = 0.1, - bsdi_crypt__max_rounds = 30000, - bsdi_crypt__default_rounds = 25000, - sha512_crypt__max_rounds = 50000, - sha512_crypt__min_rounds = 40000, - ) - - #--------------------------------------------------------------- - # sample 2 - partial policy & result of overlay on sample 1 - #--------------------------------------------------------------- - sample_config_2s = """\ -[passlib] -bsdi_crypt.min_rounds = 29000 -bsdi_crypt.max_rounds = 35000 -bsdi_crypt.default_rounds = 31000 -sha512_crypt.min_rounds = 45000 -""" - - sample_config_2pd = dict( - # using this to test full replacement of existing options - bsdi_crypt__min_rounds = 29000, - bsdi_crypt__max_rounds = 35000, - bsdi_crypt__default_rounds = 31000, - # using this to test partial replacement of existing options - sha512_crypt__min_rounds=45000, - ) - - sample_config_12pd = dict( - schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"], - default = "md5_crypt", - # NOTE: not maintaining backwards compat for rendering to "10%" - all__vary_rounds = 0.1, - bsdi_crypt__min_rounds = 29000, - bsdi_crypt__max_rounds = 35000, - bsdi_crypt__default_rounds = 31000, - sha512_crypt__max_rounds = 50000, - sha512_crypt__min_rounds=45000, - ) - - #--------------------------------------------------------------- - # sample 3 - just changing default - #--------------------------------------------------------------- - sample_config_3pd = dict( - default="sha512_crypt", - ) - - sample_config_123pd = dict( - schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"], - default = "sha512_crypt", - # NOTE: not maintaining backwards compat for rendering to "10%" - all__vary_rounds = 0.1, - bsdi_crypt__min_rounds = 29000, - bsdi_crypt__max_rounds = 35000, - bsdi_crypt__default_rounds = 31000, - sha512_crypt__max_rounds = 50000, - sha512_crypt__min_rounds=45000, - ) - - #--------------------------------------------------------------- - # sample 4 - category specific - #--------------------------------------------------------------- - sample_config_4s = """ -[passlib] -schemes = sha512_crypt -all.vary_rounds = 10%% -default.sha512_crypt.max_rounds = 20000 -admin.all.vary_rounds = 5%% -admin.sha512_crypt.max_rounds = 40000 -""" - - sample_config_4pd = dict( - schemes = [ "sha512_crypt" ], - # NOTE: not maintaining backwards compat for rendering to "10%" - all__vary_rounds = 0.1, - sha512_crypt__max_rounds = 20000, - # NOTE: not maintaining backwards compat for rendering to "5%" - admin__all__vary_rounds = 0.05, - admin__sha512_crypt__max_rounds = 40000, - ) - - #--------------------------------------------------------------- - # sample 5 - to_string & deprecation testing - #--------------------------------------------------------------- - sample_config_5s = sample_config_1s + """\ -deprecated = des_crypt -admin__context__deprecated = des_crypt, bsdi_crypt -""" - - sample_config_5pd = sample_config_1pd.copy() - sample_config_5pd.update( - deprecated = [ "des_crypt" ], - admin__context__deprecated = [ "des_crypt", "bsdi_crypt" ], - ) - - sample_config_5pid = sample_config_1pid.copy() - sample_config_5pid.update({ - "deprecated": "des_crypt", - "admin.context.deprecated": "des_crypt, bsdi_crypt", - }) - - sample_config_5prd = sample_config_1prd.copy() - sample_config_5prd.update({ - # XXX: should deprecated return the actual handlers in this case? - # would have to modify how policy stores info, for one. - "deprecated": ["des_crypt"], - "admin__context__deprecated": ["des_crypt", "bsdi_crypt"], - }) - - #=================================================================== - # constructors - #=================================================================== - def setUp(self): - TestCase.setUp(self) - warnings.filterwarnings("ignore", - r"The CryptPolicy class has been deprecated") - warnings.filterwarnings("ignore", - r"the method.*hash_needs_update.*is deprecated") - warnings.filterwarnings("ignore", "The 'all' scheme is deprecated.*") - warnings.filterwarnings("ignore", "bsdi_crypt rounds should be odd") - - def test_00_constructor(self): - """test CryptPolicy() constructor""" - policy = CryptPolicy(**self.sample_config_1pd) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - policy = CryptPolicy(self.sample_config_1pd) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - self.assertRaises(TypeError, CryptPolicy, {}, {}) - self.assertRaises(TypeError, CryptPolicy, {}, dummy=1) - - # check key with too many separators is rejected - self.assertRaises(TypeError, CryptPolicy, - schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"], - bad__key__bsdi_crypt__max_rounds = 30000, - ) - - # check nameless handler rejected - class nameless(uh.StaticHandler): - name = None - self.assertRaises(ValueError, CryptPolicy, schemes=[nameless]) - - # check scheme must be name or crypt handler - self.assertRaises(TypeError, CryptPolicy, schemes=[uh.StaticHandler]) - - # check name conflicts are rejected - class dummy_1(uh.StaticHandler): - name = 'dummy_1' - self.assertRaises(KeyError, CryptPolicy, schemes=[dummy_1, dummy_1]) - - # with unknown deprecated value - self.assertRaises(KeyError, CryptPolicy, - schemes=['des_crypt'], - deprecated=['md5_crypt']) - - # with unknown default value - self.assertRaises(KeyError, CryptPolicy, - schemes=['des_crypt'], - default='md5_crypt') - - def test_01_from_path_simple(self): - """test CryptPolicy.from_path() constructor""" - # NOTE: this is separate so it can also run under GAE - - # test preset stored in existing file - path = self.sample_config_1s_path - policy = CryptPolicy.from_path(path) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test if path missing - self.assertRaises(EnvironmentError, CryptPolicy.from_path, path + 'xxx') - - def test_01_from_path(self): - """test CryptPolicy.from_path() constructor with encodings""" - path = self.mktemp() - - # test "\n" linesep - set_file(path, self.sample_config_1s) - policy = CryptPolicy.from_path(path) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test "\r\n" linesep - set_file(path, self.sample_config_1s.replace("\n","\r\n")) - policy = CryptPolicy.from_path(path) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test with custom encoding - uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8") - set_file(path, uc2) - policy = CryptPolicy.from_path(path, encoding="utf-16") - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - def test_02_from_string(self): - """test CryptPolicy.from_string() constructor""" - # test "\n" linesep - policy = CryptPolicy.from_string(self.sample_config_1s) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test "\r\n" linesep - policy = CryptPolicy.from_string( - self.sample_config_1s.replace("\n","\r\n")) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test with unicode - data = to_unicode(self.sample_config_1s) - policy = CryptPolicy.from_string(data) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test with non-ascii-compatible encoding - uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8") - policy = CryptPolicy.from_string(uc2, encoding="utf-16") - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # test category specific options - policy = CryptPolicy.from_string(self.sample_config_4s) - self.assertEqual(policy.to_dict(), self.sample_config_4pd) - - def test_03_from_source(self): - """test CryptPolicy.from_source() constructor""" - # pass it a path - policy = CryptPolicy.from_source(self.sample_config_1s_path) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # pass it a string - policy = CryptPolicy.from_source(self.sample_config_1s) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # pass it a dict (NOTE: make a copy to detect in-place modifications) - policy = CryptPolicy.from_source(self.sample_config_1pd.copy()) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # pass it existing policy - p2 = CryptPolicy.from_source(policy) - self.assertIs(policy, p2) - - # pass it something wrong - self.assertRaises(TypeError, CryptPolicy.from_source, 1) - self.assertRaises(TypeError, CryptPolicy.from_source, []) - - def test_04_from_sources(self): - """test CryptPolicy.from_sources() constructor""" - - # pass it empty list - self.assertRaises(ValueError, CryptPolicy.from_sources, []) - - # pass it one-element list - policy = CryptPolicy.from_sources([self.sample_config_1s]) - self.assertEqual(policy.to_dict(), self.sample_config_1pd) - - # pass multiple sources - policy = CryptPolicy.from_sources( - [ - self.sample_config_1s_path, - self.sample_config_2s, - self.sample_config_3pd, - ]) - self.assertEqual(policy.to_dict(), self.sample_config_123pd) - - def test_05_replace(self): - """test CryptPolicy.replace() constructor""" - - p1 = CryptPolicy(**self.sample_config_1pd) - - # check overlaying sample 2 - p2 = p1.replace(**self.sample_config_2pd) - self.assertEqual(p2.to_dict(), self.sample_config_12pd) - - # check repeating overlay makes no change - p2b = p2.replace(**self.sample_config_2pd) - self.assertEqual(p2b.to_dict(), self.sample_config_12pd) - - # check overlaying sample 3 - p3 = p2.replace(self.sample_config_3pd) - self.assertEqual(p3.to_dict(), self.sample_config_123pd) - - def test_06_forbidden(self): - """test CryptPolicy() forbidden kwds""" - - # salt not allowed to be set - self.assertRaises(KeyError, CryptPolicy, - schemes=["des_crypt"], - des_crypt__salt="xx", - ) - self.assertRaises(KeyError, CryptPolicy, - schemes=["des_crypt"], - all__salt="xx", - ) - - # schemes not allowed for category - self.assertRaises(KeyError, CryptPolicy, - schemes=["des_crypt"], - user__context__schemes=["md5_crypt"], - ) - - #=================================================================== - # reading - #=================================================================== - def test_10_has_schemes(self): - """test has_schemes() method""" - - p1 = CryptPolicy(**self.sample_config_1pd) - self.assertTrue(p1.has_schemes()) - - p3 = CryptPolicy(**self.sample_config_3pd) - self.assertTrue(not p3.has_schemes()) - - def test_11_iter_handlers(self): - """test iter_handlers() method""" - - p1 = CryptPolicy(**self.sample_config_1pd) - s = self.sample_config_1prd['schemes'] - self.assertEqual(list(p1.iter_handlers()), s) - - p3 = CryptPolicy(**self.sample_config_3pd) - self.assertEqual(list(p3.iter_handlers()), []) - - def test_12_get_handler(self): - """test get_handler() method""" - - p1 = CryptPolicy(**self.sample_config_1pd) - - # check by name - self.assertIs(p1.get_handler("bsdi_crypt"), hash.bsdi_crypt) - - # check by missing name - self.assertIs(p1.get_handler("sha256_crypt"), None) - self.assertRaises(KeyError, p1.get_handler, "sha256_crypt", required=True) - - # check default - self.assertIs(p1.get_handler(), hash.md5_crypt) - - def test_13_get_options(self): - """test get_options() method""" - - p12 = CryptPolicy(**self.sample_config_12pd) - - self.assertEqual(p12.get_options("bsdi_crypt"),dict( - # NOTE: not maintaining backwards compat for rendering to "10%" - vary_rounds = 0.1, - min_rounds = 29000, - max_rounds = 35000, - default_rounds = 31000, - )) - - self.assertEqual(p12.get_options("sha512_crypt"),dict( - # NOTE: not maintaining backwards compat for rendering to "10%" - vary_rounds = 0.1, - min_rounds = 45000, - max_rounds = 50000, - )) - - p4 = CryptPolicy.from_string(self.sample_config_4s) - self.assertEqual(p4.get_options("sha512_crypt"), dict( - # NOTE: not maintaining backwards compat for rendering to "10%" - vary_rounds=0.1, - max_rounds=20000, - )) - - self.assertEqual(p4.get_options("sha512_crypt", "user"), dict( - # NOTE: not maintaining backwards compat for rendering to "10%" - vary_rounds=0.1, - max_rounds=20000, - )) - - self.assertEqual(p4.get_options("sha512_crypt", "admin"), dict( - # NOTE: not maintaining backwards compat for rendering to "5%" - vary_rounds=0.05, - max_rounds=40000, - )) - - def test_14_handler_is_deprecated(self): - """test handler_is_deprecated() method""" - pa = CryptPolicy(**self.sample_config_1pd) - pb = CryptPolicy(**self.sample_config_5pd) - - self.assertFalse(pa.handler_is_deprecated("des_crypt")) - self.assertFalse(pa.handler_is_deprecated(hash.bsdi_crypt)) - self.assertFalse(pa.handler_is_deprecated("sha512_crypt")) - - self.assertTrue(pb.handler_is_deprecated("des_crypt")) - self.assertFalse(pb.handler_is_deprecated(hash.bsdi_crypt)) - self.assertFalse(pb.handler_is_deprecated("sha512_crypt")) - - # check categories as well - self.assertTrue(pb.handler_is_deprecated("des_crypt", "user")) - self.assertFalse(pb.handler_is_deprecated("bsdi_crypt", "user")) - self.assertTrue(pb.handler_is_deprecated("des_crypt", "admin")) - self.assertTrue(pb.handler_is_deprecated("bsdi_crypt", "admin")) - - # check deprecation is overridden per category - pc = CryptPolicy( - schemes=["md5_crypt", "des_crypt"], - deprecated=["md5_crypt"], - user__context__deprecated=["des_crypt"], - ) - self.assertTrue(pc.handler_is_deprecated("md5_crypt")) - self.assertFalse(pc.handler_is_deprecated("des_crypt")) - self.assertFalse(pc.handler_is_deprecated("md5_crypt", "user")) - self.assertTrue(pc.handler_is_deprecated("des_crypt", "user")) - - def test_15_min_verify_time(self): - """test get_min_verify_time() method""" - # silence deprecation warnings for min verify time - warnings.filterwarnings("ignore", category=DeprecationWarning) - - pa = CryptPolicy() - self.assertEqual(pa.get_min_verify_time(), 0) - self.assertEqual(pa.get_min_verify_time('admin'), 0) - - pb = pa.replace(min_verify_time=.1) - self.assertEqual(pb.get_min_verify_time(), 0) - self.assertEqual(pb.get_min_verify_time('admin'), 0) - - #=================================================================== - # serialization - #=================================================================== - def test_20_iter_config(self): - """test iter_config() method""" - p5 = CryptPolicy(**self.sample_config_5pd) - self.assertEqual(dict(p5.iter_config()), self.sample_config_5pd) - self.assertEqual(dict(p5.iter_config(resolve=True)), self.sample_config_5prd) - self.assertEqual(dict(p5.iter_config(ini=True)), self.sample_config_5pid) - - def test_21_to_dict(self): - """test to_dict() method""" - p5 = CryptPolicy(**self.sample_config_5pd) - self.assertEqual(p5.to_dict(), self.sample_config_5pd) - self.assertEqual(p5.to_dict(resolve=True), self.sample_config_5prd) - - def test_22_to_string(self): - """test to_string() method""" - pa = CryptPolicy(**self.sample_config_5pd) - s = pa.to_string() # NOTE: can't compare string directly, ordering etc may not match - pb = CryptPolicy.from_string(s) - self.assertEqual(pb.to_dict(), self.sample_config_5pd) - - s = pa.to_string(encoding="latin-1") - self.assertIsInstance(s, bytes) - - #=================================================================== - # - #=================================================================== - -#============================================================================= -# CryptContext -#============================================================================= -class CryptContextTest(TestCase): - """test CryptContext class""" - descriptionPrefix = "CryptContext" - - def setUp(self): - TestCase.setUp(self) - warnings.filterwarnings("ignore", - r"CryptContext\(\)\.replace\(\) has been deprecated.*") - warnings.filterwarnings("ignore", - r"The CryptContext ``policy`` keyword has been deprecated.*") - warnings.filterwarnings("ignore", ".*(CryptPolicy|context\.policy).*(has|have) been deprecated.*") - warnings.filterwarnings("ignore", - r"the method.*hash_needs_update.*is deprecated") - - #=================================================================== - # constructor - #=================================================================== - def test_00_constructor(self): - """test constructor""" - # create crypt context using handlers - cc = CryptContext([hash.md5_crypt, hash.bsdi_crypt, hash.des_crypt]) - c,b,a = cc.policy.iter_handlers() - self.assertIs(a, hash.des_crypt) - self.assertIs(b, hash.bsdi_crypt) - self.assertIs(c, hash.md5_crypt) - - # create context using names - cc = CryptContext(["md5_crypt", "bsdi_crypt", "des_crypt"]) - c,b,a = cc.policy.iter_handlers() - self.assertIs(a, hash.des_crypt) - self.assertIs(b, hash.bsdi_crypt) - self.assertIs(c, hash.md5_crypt) - - # policy kwd - policy = cc.policy - cc = CryptContext(policy=policy) - self.assertEqual(cc.to_dict(), policy.to_dict()) - - cc = CryptContext(policy=policy, default="bsdi_crypt") - self.assertNotEqual(cc.to_dict(), policy.to_dict()) - self.assertEqual(cc.to_dict(), dict(schemes=["md5_crypt","bsdi_crypt","des_crypt"], - default="bsdi_crypt")) - - self.assertRaises(TypeError, setattr, cc, 'policy', None) - self.assertRaises(TypeError, CryptContext, policy='x') - - def test_01_replace(self): - """test replace()""" - - cc = CryptContext(["md5_crypt", "bsdi_crypt", "des_crypt"]) - self.assertIs(cc.policy.get_handler(), hash.md5_crypt) - - cc2 = cc.replace() - self.assertIsNot(cc2, cc) - # NOTE: was not able to maintain backward compatibility with this... - ##self.assertIs(cc2.policy, cc.policy) - - cc3 = cc.replace(default="bsdi_crypt") - self.assertIsNot(cc3, cc) - # NOTE: was not able to maintain backward compatibility with this... - ##self.assertIs(cc3.policy, cc.policy) - self.assertIs(cc3.policy.get_handler(), hash.bsdi_crypt) - - def test_02_no_handlers(self): - """test no handlers""" - - # check constructor... - cc = CryptContext() - self.assertRaises(KeyError, cc.identify, 'hash', required=True) - self.assertRaises(KeyError, cc.hash, 'secret') - self.assertRaises(KeyError, cc.verify, 'secret', 'hash') - - # check updating policy after the fact... - cc = CryptContext(['md5_crypt']) - p = CryptPolicy(schemes=[]) - cc.policy = p - - self.assertRaises(KeyError, cc.identify, 'hash', required=True) - self.assertRaises(KeyError, cc.hash, 'secret') - self.assertRaises(KeyError, cc.verify, 'secret', 'hash') - - #=================================================================== - # policy adaptation - #=================================================================== - sample_policy_1 = dict( - schemes = [ "des_crypt", "md5_crypt", "phpass", "bsdi_crypt", - "sha256_crypt"], - deprecated = [ "des_crypt", ], - default = "sha256_crypt", - bsdi_crypt__max_rounds = 30, - bsdi_crypt__default_rounds = 25, - bsdi_crypt__vary_rounds = 0, - sha256_crypt__max_rounds = 3000, - sha256_crypt__min_rounds = 2000, - sha256_crypt__default_rounds = 3000, - phpass__ident = "H", - phpass__default_rounds = 7, - ) - - def test_12_hash_needs_update(self): - """test hash_needs_update() method""" - cc = CryptContext(**self.sample_policy_1) - - # check deprecated scheme - self.assertTrue(cc.hash_needs_update('9XXD4trGYeGJA')) - self.assertFalse(cc.hash_needs_update('$1$J8HC2RCr$HcmM.7NxB2weSvlw2FgzU0')) - - # check min rounds - self.assertTrue(cc.hash_needs_update('$5$rounds=1999$jD81UCoo.zI.UETs$Y7qSTQ6mTiU9qZB4fRr43wRgQq4V.5AAf7F97Pzxey/')) - self.assertFalse(cc.hash_needs_update('$5$rounds=2000$228SSRje04cnNCaQ$YGV4RYu.5sNiBvorQDlO0WWQjyJVGKBcJXz3OtyQ2u8')) - - # check max rounds - self.assertFalse(cc.hash_needs_update('$5$rounds=3000$fS9iazEwTKi7QPW4$VasgBC8FqlOvD7x2HhABaMXCTh9jwHclPA9j5YQdns.')) - self.assertTrue(cc.hash_needs_update('$5$rounds=3001$QlFHHifXvpFX4PLs$/0ekt7lSs/lOikSerQ0M/1porEHxYq7W/2hdFpxA3fA')) - - #=================================================================== - # border cases - #=================================================================== - def test_30_nonstring_hash(self): - """test non-string hash values cause error""" - warnings.filterwarnings("ignore", ".*needs_update.*'scheme' keyword is deprecated.*") - - # - # test hash=None or some other non-string causes TypeError - # and that explicit-scheme code path behaves the same. - # - cc = CryptContext(["des_crypt"]) - for hash, kwds in [ - (None, {}), - # NOTE: 'scheme' kwd is deprecated... - (None, {"scheme": "des_crypt"}), - (1, {}), - ((), {}), - ]: - - self.assertRaises(TypeError, cc.hash_needs_update, hash, **kwds) - - cc2 = CryptContext(["mysql323"]) - self.assertRaises(TypeError, cc2.hash_needs_update, None) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# LazyCryptContext -#============================================================================= -class dummy_2(uh.StaticHandler): - name = "dummy_2" - -class LazyCryptContextTest(TestCase): - descriptionPrefix = "LazyCryptContext" - - def setUp(self): - TestCase.setUp(self) - - # make sure this isn't registered before OR after - unload_handler_name("dummy_2") - self.addCleanup(unload_handler_name, "dummy_2") - - # silence some warnings - warnings.filterwarnings("ignore", - r"CryptContext\(\)\.replace\(\) has been deprecated") - warnings.filterwarnings("ignore", ".*(CryptPolicy|context\.policy).*(has|have) been deprecated.*") - - def test_kwd_constructor(self): - """test plain kwds""" - self.assertFalse(has_crypt_handler("dummy_2")) - register_crypt_handler_path("dummy_2", "passlib.tests.test_context") - - cc = LazyCryptContext(iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) - - self.assertFalse(has_crypt_handler("dummy_2", True)) - - self.assertTrue(cc.policy.handler_is_deprecated("des_crypt")) - self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"]) - - self.assertTrue(has_crypt_handler("dummy_2", True)) - - def test_callable_constructor(self): - """test create_policy() hook, returning CryptPolicy""" - self.assertFalse(has_crypt_handler("dummy_2")) - register_crypt_handler_path("dummy_2", "passlib.tests.test_context") - - def create_policy(flag=False): - self.assertTrue(flag) - return CryptPolicy(schemes=iter(["dummy_2", "des_crypt"]), deprecated=["des_crypt"]) - - cc = LazyCryptContext(create_policy=create_policy, flag=True) - - self.assertFalse(has_crypt_handler("dummy_2", True)) - - self.assertTrue(cc.policy.handler_is_deprecated("des_crypt")) - self.assertEqual(cc.policy.schemes(), ["dummy_2", "des_crypt"]) - - self.assertTrue(has_crypt_handler("dummy_2", True)) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_builtin_md4.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_builtin_md4.py deleted file mode 100644 index 0aca1eb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_builtin_md4.py +++ /dev/null @@ -1,160 +0,0 @@ -"""passlib.tests -- unittests for passlib.crypto._md4""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, division -# core -from binascii import hexlify -import hashlib -# site -# pkg -# module -from passlib.utils.compat import bascii_to_str, PY3, u -from passlib.crypto.digest import lookup_hash -from passlib.tests.utils import TestCase, skipUnless -# local -__all__ = [ - "_Common_MD4_Test", - "MD4_Builtin_Test", - "MD4_SSL_Test", -] -#============================================================================= -# test pure-python MD4 implementation -#============================================================================= -class _Common_MD4_Test(TestCase): - """common code for testing md4 backends""" - - vectors = [ - # input -> hex digest - # test vectors from http://www.faqs.org/rfcs/rfc1320.html - A.5 - (b"", "31d6cfe0d16ae931b73c59d7e0c089c0"), - (b"a", "bde52cb31de33e46245e05fbdbd6fb24"), - (b"abc", "a448017aaf21d8525fc10ae87aa6729d"), - (b"message digest", "d9130a8164549fe818874806e1c7014b"), - (b"abcdefghijklmnopqrstuvwxyz", "d79e1c308aa5bbcdeea8ed63df412da9"), - (b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "043f8582f241db351ce627e153e7f0e4"), - (b"12345678901234567890123456789012345678901234567890123456789012345678901234567890", "e33b4ddc9c38f2199c3e7b164fcc0536"), - ] - - def get_md4_const(self): - """ - get md4 constructor -- - overridden by subclasses to use alternate backends. - """ - return lookup_hash("md4").const - - def test_attrs(self): - """informational attributes""" - h = self.get_md4_const()() - self.assertEqual(h.name, "md4") - self.assertEqual(h.digest_size, 16) - self.assertEqual(h.block_size, 64) - - def test_md4_update(self): - """update() method""" - md4 = self.get_md4_const() - h = md4(b'') - self.assertEqual(h.hexdigest(), "31d6cfe0d16ae931b73c59d7e0c089c0") - - h.update(b'a') - self.assertEqual(h.hexdigest(), "bde52cb31de33e46245e05fbdbd6fb24") - - h.update(b'bcdefghijklmnopqrstuvwxyz') - self.assertEqual(h.hexdigest(), "d79e1c308aa5bbcdeea8ed63df412da9") - - if PY3: - # reject unicode, hash should return digest of b'' - h = md4() - self.assertRaises(TypeError, h.update, u('a')) - self.assertEqual(h.hexdigest(), "31d6cfe0d16ae931b73c59d7e0c089c0") - else: - # coerce unicode to ascii, hash should return digest of b'a' - h = md4() - h.update(u('a')) - self.assertEqual(h.hexdigest(), "bde52cb31de33e46245e05fbdbd6fb24") - - def test_md4_hexdigest(self): - """hexdigest() method""" - md4 = self.get_md4_const() - for input, hex in self.vectors: - out = md4(input).hexdigest() - self.assertEqual(out, hex) - - def test_md4_digest(self): - """digest() method""" - md4 = self.get_md4_const() - for input, hex in self.vectors: - out = bascii_to_str(hexlify(md4(input).digest())) - self.assertEqual(out, hex) - - def test_md4_copy(self): - """copy() method""" - md4 = self.get_md4_const() - h = md4(b'abc') - - h2 = h.copy() - h2.update(b'def') - self.assertEqual(h2.hexdigest(), '804e7f1c2586e50b49ac65db5b645131') - - h.update(b'ghi') - self.assertEqual(h.hexdigest(), 'c5225580bfe176f6deeee33dee98732c') - - -#------------------------------------------------------------------------ -# create subclasses to test various backends -#------------------------------------------------------------------------ - -def has_native_md4(): # pragma: no cover -- runtime detection - """ - check if hashlib natively supports md4. - """ - try: - hashlib.new("md4") - return True - except ValueError: - # not supported - ssl probably missing (e.g. ironpython) - return False - - -@skipUnless(has_native_md4(), "hashlib lacks ssl/md4 support") -class MD4_SSL_Test(_Common_MD4_Test): - descriptionPrefix = "hashlib.new('md4')" - - # NOTE: we trust ssl got md4 implementation right, - # this is more to test our test is correct :) - - def setUp(self): - super(MD4_SSL_Test, self).setUp() - - # make sure we're using right constructor. - self.assertEqual(self.get_md4_const().__module__, "hashlib") - - -class MD4_Builtin_Test(_Common_MD4_Test): - descriptionPrefix = "passlib.crypto._md4.md4()" - - def setUp(self): - super(MD4_Builtin_Test, self).setUp() - - if has_native_md4(): - - # Temporarily make lookup_hash() use builtin pure-python implementation, - # by monkeypatching hashlib.new() to ensure we fall back to passlib's md4 class. - orig = hashlib.new - def wrapper(name, *args): - if name == "md4": - raise ValueError("md4 disabled for testing") - return orig(name, *args) - self.patchAttr(hashlib, "new", wrapper) - - # flush cache before & after test, since we're mucking with it. - lookup_hash.clear_cache() - self.addCleanup(lookup_hash.clear_cache) - - # make sure we're using right constructor. - self.assertEqual(self.get_md4_const().__module__, "passlib.crypto._md4") - - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_des.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_des.py deleted file mode 100644 index ab31845..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_des.py +++ /dev/null @@ -1,194 +0,0 @@ -"""passlib.tests -- unittests for passlib.crypto.des""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, division -# core -from functools import partial -# site -# pkg -# module -from passlib.utils import getrandbytes -from passlib.tests.utils import TestCase - -#============================================================================= -# test DES routines -#============================================================================= -class DesTest(TestCase): - descriptionPrefix = "passlib.crypto.des" - - # test vectors taken from http://www.skepticfiles.org/faq/testdes.htm - des_test_vectors = [ - # key, plaintext, ciphertext - (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7), - (0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x7359B2163E4EDC58), - (0x3000000000000000, 0x1000000000000001, 0x958E6E627A05557B), - (0x1111111111111111, 0x1111111111111111, 0xF40379AB9E0EC533), - (0x0123456789ABCDEF, 0x1111111111111111, 0x17668DFC7292532D), - (0x1111111111111111, 0x0123456789ABCDEF, 0x8A5AE1F81AB8F2DD), - (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7), - (0xFEDCBA9876543210, 0x0123456789ABCDEF, 0xED39D950FA74BCC4), - (0x7CA110454A1A6E57, 0x01A1D6D039776742, 0x690F5B0D9A26939B), - (0x0131D9619DC1376E, 0x5CD54CA83DEF57DA, 0x7A389D10354BD271), - (0x07A1133E4A0B2686, 0x0248D43806F67172, 0x868EBB51CAB4599A), - (0x3849674C2602319E, 0x51454B582DDF440A, 0x7178876E01F19B2A), - (0x04B915BA43FEB5B6, 0x42FD443059577FA2, 0xAF37FB421F8C4095), - (0x0113B970FD34F2CE, 0x059B5E0851CF143A, 0x86A560F10EC6D85B), - (0x0170F175468FB5E6, 0x0756D8E0774761D2, 0x0CD3DA020021DC09), - (0x43297FAD38E373FE, 0x762514B829BF486A, 0xEA676B2CB7DB2B7A), - (0x07A7137045DA2A16, 0x3BDD119049372802, 0xDFD64A815CAF1A0F), - (0x04689104C2FD3B2F, 0x26955F6835AF609A, 0x5C513C9C4886C088), - (0x37D06BB516CB7546, 0x164D5E404F275232, 0x0A2AEEAE3FF4AB77), - (0x1F08260D1AC2465E, 0x6B056E18759F5CCA, 0xEF1BF03E5DFA575A), - (0x584023641ABA6176, 0x004BD6EF09176062, 0x88BF0DB6D70DEE56), - (0x025816164629B007, 0x480D39006EE762F2, 0xA1F9915541020B56), - (0x49793EBC79B3258F, 0x437540C8698F3CFA, 0x6FBF1CAFCFFD0556), - (0x4FB05E1515AB73A7, 0x072D43A077075292, 0x2F22E49BAB7CA1AC), - (0x49E95D6D4CA229BF, 0x02FE55778117F12A, 0x5A6B612CC26CCE4A), - (0x018310DC409B26D6, 0x1D9D5C5018F728C2, 0x5F4C038ED12B2E41), - (0x1C587F1C13924FEF, 0x305532286D6F295A, 0x63FAC0D034D9F793), - (0x0101010101010101, 0x0123456789ABCDEF, 0x617B3A0CE8F07100), - (0x1F1F1F1F0E0E0E0E, 0x0123456789ABCDEF, 0xDB958605F8C8C606), - (0xE0FEE0FEF1FEF1FE, 0x0123456789ABCDEF, 0xEDBFD1C66C29CCC7), - (0x0000000000000000, 0xFFFFFFFFFFFFFFFF, 0x355550B2150E2451), - (0xFFFFFFFFFFFFFFFF, 0x0000000000000000, 0xCAAAAF4DEAF1DBAE), - (0x0123456789ABCDEF, 0x0000000000000000, 0xD5D44FF720683D0D), - (0xFEDCBA9876543210, 0xFFFFFFFFFFFFFFFF, 0x2A2BB008DF97C2F2), - ] - - def test_01_expand(self): - """expand_des_key()""" - from passlib.crypto.des import expand_des_key, shrink_des_key, \ - _KDATA_MASK, INT_56_MASK - - # make sure test vectors are preserved (sans parity bits) - # uses ints, bytes are tested under # 02 - for key1, _, _ in self.des_test_vectors: - key2 = shrink_des_key(key1) - key3 = expand_des_key(key2) - # NOTE: this assumes expand_des_key() sets parity bits to 0 - self.assertEqual(key3, key1 & _KDATA_MASK) - - # type checks - self.assertRaises(TypeError, expand_des_key, 1.0) - - # too large - self.assertRaises(ValueError, expand_des_key, INT_56_MASK+1) - self.assertRaises(ValueError, expand_des_key, b"\x00"*8) - - # too small - self.assertRaises(ValueError, expand_des_key, -1) - self.assertRaises(ValueError, expand_des_key, b"\x00"*6) - - def test_02_shrink(self): - """shrink_des_key()""" - from passlib.crypto.des import expand_des_key, shrink_des_key, INT_64_MASK - rng = self.getRandom() - - # make sure reverse works for some random keys - # uses bytes, ints are tested under # 01 - for i in range(20): - key1 = getrandbytes(rng, 7) - key2 = expand_des_key(key1) - key3 = shrink_des_key(key2) - self.assertEqual(key3, key1) - - # type checks - self.assertRaises(TypeError, shrink_des_key, 1.0) - - # too large - self.assertRaises(ValueError, shrink_des_key, INT_64_MASK+1) - self.assertRaises(ValueError, shrink_des_key, b"\x00"*9) - - # too small - self.assertRaises(ValueError, shrink_des_key, -1) - self.assertRaises(ValueError, shrink_des_key, b"\x00"*7) - - def _random_parity(self, key): - """randomize parity bits""" - from passlib.crypto.des import _KDATA_MASK, _KPARITY_MASK, INT_64_MASK - rng = self.getRandom() - return (key & _KDATA_MASK) | (rng.randint(0,INT_64_MASK) & _KPARITY_MASK) - - def test_03_encrypt_bytes(self): - """des_encrypt_block()""" - from passlib.crypto.des import (des_encrypt_block, shrink_des_key, - _pack64, _unpack64) - - # run through test vectors - for key, plaintext, correct in self.des_test_vectors: - # convert to bytes - key = _pack64(key) - plaintext = _pack64(plaintext) - correct = _pack64(correct) - - # test 64-bit key - result = des_encrypt_block(key, plaintext) - self.assertEqual(result, correct, "key=%r plaintext=%r:" % - (key, plaintext)) - - # test 56-bit version - key2 = shrink_des_key(key) - result = des_encrypt_block(key2, plaintext) - self.assertEqual(result, correct, "key=%r shrink(key)=%r plaintext=%r:" % - (key, key2, plaintext)) - - # test with random parity bits - for _ in range(20): - key3 = _pack64(self._random_parity(_unpack64(key))) - result = des_encrypt_block(key3, plaintext) - self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" % - (key, key3, plaintext)) - - # check invalid keys - stub = b'\x00' * 8 - self.assertRaises(TypeError, des_encrypt_block, 0, stub) - self.assertRaises(ValueError, des_encrypt_block, b'\x00'*6, stub) - - # check invalid input - self.assertRaises(TypeError, des_encrypt_block, stub, 0) - self.assertRaises(ValueError, des_encrypt_block, stub, b'\x00'*7) - - # check invalid salts - self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=-1) - self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=1<<24) - - # check invalid rounds - self.assertRaises(ValueError, des_encrypt_block, stub, stub, 0, rounds=0) - - def test_04_encrypt_ints(self): - """des_encrypt_int_block()""" - from passlib.crypto.des import des_encrypt_int_block - - # run through test vectors - for key, plaintext, correct in self.des_test_vectors: - # test 64-bit key - result = des_encrypt_int_block(key, plaintext) - self.assertEqual(result, correct, "key=%r plaintext=%r:" % - (key, plaintext)) - - # test with random parity bits - for _ in range(20): - key3 = self._random_parity(key) - result = des_encrypt_int_block(key3, plaintext) - self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" % - (key, key3, plaintext)) - - # check invalid keys - self.assertRaises(TypeError, des_encrypt_int_block, b'\x00', 0) - self.assertRaises(ValueError, des_encrypt_int_block, -1, 0) - - # check invalid input - self.assertRaises(TypeError, des_encrypt_int_block, 0, b'\x00') - self.assertRaises(ValueError, des_encrypt_int_block, 0, -1) - - # check invalid salts - self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=-1) - self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=1<<24) - - # check invalid rounds - self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, 0, rounds=0) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_digest.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_digest.py deleted file mode 100644 index 461d209..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_digest.py +++ /dev/null @@ -1,544 +0,0 @@ -"""tests for passlib.utils.(des|pbkdf2|md4)""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement, division -# core -from binascii import hexlify -import hashlib -import warnings -# site -# pkg -# module -from passlib.exc import UnknownHashError -from passlib.utils.compat import PY3, u, JYTHON -from passlib.tests.utils import TestCase, TEST_MODE, skipUnless, hb - -#============================================================================= -# test assorted crypto helpers -#============================================================================= -class HashInfoTest(TestCase): - """test various crypto functions""" - descriptionPrefix = "passlib.crypto.digest" - - #: list of formats norm_hash_name() should support - norm_hash_formats = ["hashlib", "iana"] - - #: test cases for norm_hash_name() - #: each row contains (iana name, hashlib name, ... 0+ unnormalized names) - norm_hash_samples = [ - # real hashes - ("md5", "md5", "SCRAM-MD5-PLUS", "MD-5"), - ("sha1", "sha-1", "SCRAM-SHA-1", "SHA1"), - ("sha256", "sha-256", "SHA_256", "sha2-256"), - ("ripemd160", "ripemd-160", "SCRAM-RIPEMD-160", "RIPEmd160", - # NOTE: there was an older "RIPEMD" & "RIPEMD-128", but python treates "RIPEMD" - # as alias for "RIPEMD-160" - "ripemd", "SCRAM-RIPEMD"), - - # fake hashes (to check if fallback normalization behaves sanely) - ("sha4_256", "sha4-256", "SHA4-256", "SHA-4-256"), - ("test128", "test-128", "TEST128"), - ("test2", "test2", "TEST-2"), - ("test3_128", "test3-128", "TEST-3-128"), - ] - - def test_norm_hash_name(self): - """norm_hash_name()""" - from itertools import chain - from passlib.crypto.digest import norm_hash_name, _known_hash_names - - # snapshot warning state, ignore unknown hash warnings - ctx = warnings.catch_warnings() - ctx.__enter__() - self.addCleanup(ctx.__exit__) - warnings.filterwarnings("ignore", '.*unknown hash') - warnings.filterwarnings("ignore", '.*unsupported hash') - - # test string types - self.assertEqual(norm_hash_name(u("MD4")), "md4") - self.assertEqual(norm_hash_name(b"MD4"), "md4") - self.assertRaises(TypeError, norm_hash_name, None) - - # test selected results - for row in chain(_known_hash_names, self.norm_hash_samples): - for idx, format in enumerate(self.norm_hash_formats): - correct = row[idx] - for value in row: - result = norm_hash_name(value, format) - self.assertEqual(result, correct, - "name=%r, format=%r:" % (value, - format)) - - def test_lookup_hash_ctor(self): - """lookup_hash() -- constructor""" - from passlib.crypto.digest import lookup_hash - - # invalid/unknown names should be rejected - self.assertRaises(ValueError, lookup_hash, "new") - self.assertRaises(ValueError, lookup_hash, "__name__") - self.assertRaises(ValueError, lookup_hash, "sha4") - - # 1. should return hashlib builtin if found - self.assertEqual(lookup_hash("md5"), (hashlib.md5, 16, 64)) - - # 2. should return wrapper around hashlib.new() if found - try: - hashlib.new("sha") - has_sha = True - except ValueError: - has_sha = False - if has_sha: - record = lookup_hash("sha") - const = record[0] - self.assertEqual(record, (const, 20, 64)) - self.assertEqual(hexlify(const(b"abc").digest()), - b"0164b8a914cd2a5e74c4f7ff082c4d97f1edf880") - - else: - self.assertRaises(ValueError, lookup_hash, "sha") - - # 3. should fall back to builtin md4 - try: - hashlib.new("md4") - has_md4 = True - except ValueError: - has_md4 = False - record = lookup_hash("md4") - const = record[0] - if not has_md4: - from passlib.crypto._md4 import md4 - self.assertIs(const, md4) - self.assertEqual(record, (const, 16, 64)) - self.assertEqual(hexlify(const(b"abc").digest()), - b"a448017aaf21d8525fc10ae87aa6729d") - - # should memoize records - self.assertIs(lookup_hash("md5"), lookup_hash("md5")) - - def test_lookup_hash_w_unknown_name(self): - """lookup_hash() -- unknown hash name""" - from passlib.crypto.digest import lookup_hash - - # unknown names should be rejected by default - self.assertRaises(UnknownHashError, lookup_hash, "xxx256") - - # required=False should return stub record instead - info = lookup_hash("xxx256", required=False) - self.assertFalse(info.supported) - self.assertRaisesRegex(UnknownHashError, "unknown hash: 'xxx256'", info.const) - self.assertEqual(info.name, "xxx256") - self.assertEqual(info.digest_size, None) - self.assertEqual(info.block_size, None) - - # should cache stub records - info2 = lookup_hash("xxx256", required=False) - self.assertIs(info2, info) - - def test_mock_fips_mode(self): - """ - lookup_hash() -- test set_mock_fips_mode() - """ - from passlib.crypto.digest import lookup_hash, _set_mock_fips_mode - - # check if md5 is available so we can test mock helper - if not lookup_hash("md5", required=False).supported: - raise self.skipTest("md5 not supported") - - # enable monkeypatch to mock up fips mode - _set_mock_fips_mode() - self.addCleanup(_set_mock_fips_mode, False) - - pat = "'md5' hash disabled for fips" - self.assertRaisesRegex(UnknownHashError, pat, lookup_hash, "md5") - - info = lookup_hash("md5", required=False) - self.assertRegex(info.error_text, pat) - self.assertRaisesRegex(UnknownHashError, pat, info.const) - - # should use hardcoded fallback info - self.assertEqual(info.digest_size, 16) - self.assertEqual(info.block_size, 64) - - def test_lookup_hash_metadata(self): - """lookup_hash() -- metadata""" - - from passlib.crypto.digest import lookup_hash - - # quick test of metadata using known reference - sha256 - info = lookup_hash("sha256") - self.assertEqual(info.name, "sha256") - self.assertEqual(info.iana_name, "sha-256") - self.assertEqual(info.block_size, 64) - self.assertEqual(info.digest_size, 32) - self.assertIs(lookup_hash("SHA2-256"), info) - - # quick test of metadata using known reference - md5 - info = lookup_hash("md5") - self.assertEqual(info.name, "md5") - self.assertEqual(info.iana_name, "md5") - self.assertEqual(info.block_size, 64) - self.assertEqual(info.digest_size, 16) - - def test_lookup_hash_alt_types(self): - """lookup_hash() -- alternate types""" - - from passlib.crypto.digest import lookup_hash - - info = lookup_hash("sha256") - self.assertIs(lookup_hash(info), info) - self.assertIs(lookup_hash(info.const), info) - - self.assertRaises(TypeError, lookup_hash, 123) - - # TODO: write full test of compile_hmac() -- currently relying on pbkdf2_hmac() tests - -#============================================================================= -# test PBKDF1 support -#============================================================================= -class Pbkdf1_Test(TestCase): - """test kdf helpers""" - descriptionPrefix = "passlib.crypto.digest.pbkdf1" - - pbkdf1_tests = [ - # (password, salt, rounds, keylen, hash, result) - - # - # from http://www.di-mgt.com.au/cryptoKDFs.html - # - (b'password', hb('78578E5A5D63CB06'), 1000, 16, 'sha1', hb('dc19847e05c64d2faf10ebfb4a3d2a20')), - - # - # custom - # - (b'password', b'salt', 1000, 0, 'md5', b''), - (b'password', b'salt', 1000, 1, 'md5', hb('84')), - (b'password', b'salt', 1000, 8, 'md5', hb('8475c6a8531a5d27')), - (b'password', b'salt', 1000, 16, 'md5', hb('8475c6a8531a5d27e386cd496457812c')), - (b'password', b'salt', 1000, None, 'md5', hb('8475c6a8531a5d27e386cd496457812c')), - (b'password', b'salt', 1000, None, 'sha1', hb('4a8fd48e426ed081b535be5769892fa396293efb')), - ] - if not JYTHON: # FIXME: find out why not jython, or reenable this. - pbkdf1_tests.append( - (b'password', b'salt', 1000, None, 'md4', hb('f7f2e91100a8f96190f2dd177cb26453')) - ) - - def test_known(self): - """test reference vectors""" - from passlib.crypto.digest import pbkdf1 - for secret, salt, rounds, keylen, digest, correct in self.pbkdf1_tests: - result = pbkdf1(digest, secret, salt, rounds, keylen) - self.assertEqual(result, correct) - - def test_border(self): - """test border cases""" - from passlib.crypto.digest import pbkdf1 - def helper(secret=b'secret', salt=b'salt', rounds=1, keylen=1, hash='md5'): - return pbkdf1(hash, secret, salt, rounds, keylen) - helper() - - # salt/secret wrong type - self.assertRaises(TypeError, helper, secret=1) - self.assertRaises(TypeError, helper, salt=1) - - # non-existent hashes - self.assertRaises(ValueError, helper, hash='missing') - - # rounds < 1 and wrong type - self.assertRaises(ValueError, helper, rounds=0) - self.assertRaises(TypeError, helper, rounds='1') - - # keylen < 0, keylen > block_size, and wrong type - self.assertRaises(ValueError, helper, keylen=-1) - self.assertRaises(ValueError, helper, keylen=17, hash='md5') - self.assertRaises(TypeError, helper, keylen='1') - -#============================================================================= -# test PBKDF2-HMAC support -#============================================================================= - -# import the test subject -from passlib.crypto.digest import pbkdf2_hmac, PBKDF2_BACKENDS - -# NOTE: relying on tox to verify this works under all the various backends. -class Pbkdf2Test(TestCase): - """test pbkdf2() support""" - descriptionPrefix = "passlib.crypto.digest.pbkdf2_hmac() " % ", ".join(PBKDF2_BACKENDS) - - pbkdf2_test_vectors = [ - # (result, secret, salt, rounds, keylen, digest="sha1") - - # - # from rfc 3962 - # - - # test case 1 / 128 bit - ( - hb("cdedb5281bb2f801565a1122b2563515"), - b"password", b"ATHENA.MIT.EDUraeburn", 1, 16 - ), - - # test case 2 / 128 bit - ( - hb("01dbee7f4a9e243e988b62c73cda935d"), - b"password", b"ATHENA.MIT.EDUraeburn", 2, 16 - ), - - # test case 2 / 256 bit - ( - hb("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"), - b"password", b"ATHENA.MIT.EDUraeburn", 2, 32 - ), - - # test case 3 / 256 bit - ( - hb("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"), - b"password", b"ATHENA.MIT.EDUraeburn", 1200, 32 - ), - - # test case 4 / 256 bit - ( - hb("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"), - b"password", b'\x12\x34\x56\x78\x78\x56\x34\x12', 5, 32 - ), - - # test case 5 / 256 bit - ( - hb("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"), - b"X"*64, b"pass phrase equals block size", 1200, 32 - ), - - # test case 6 / 256 bit - ( - hb("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"), - b"X"*65, b"pass phrase exceeds block size", 1200, 32 - ), - - # - # from rfc 6070 - # - ( - hb("0c60c80f961f0e71f3a9b524af6012062fe037a6"), - b"password", b"salt", 1, 20, - ), - - ( - hb("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), - b"password", b"salt", 2, 20, - ), - - ( - hb("4b007901b765489abead49d926f721d065a429c1"), - b"password", b"salt", 4096, 20, - ), - - # just runs too long - could enable if ALL option is set - ##( - ## - ## hb("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"), - ## "password", "salt", 16777216, 20, - ##), - - ( - hb("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), - b"passwordPASSWORDpassword", - b"saltSALTsaltSALTsaltSALTsaltSALTsalt", - 4096, 25, - ), - - ( - hb("56fa6aa75548099dcc37d7f03425e0c3"), - b"pass\00word", b"sa\00lt", 4096, 16, - ), - - # - # from example in http://grub.enbug.org/Authentication - # - ( - hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED" - "97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC" - "6C29E293F0A0"), - b"hello", - hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71" - "784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073" - "994D79080136"), - 10000, 64, "sha512" - ), - - # - # test vectors from fastpbkdf2 - # - ( - hb('55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc' - '49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783'), - b'passwd', b'salt', 1, 64, 'sha256', - ), - - ( - hb('4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56' - 'a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d'), - b'Password', b'NaCl', 80000, 64, 'sha256', - ), - - ( - hb('120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b'), - b'password', b'salt', 1, 32, 'sha256', - ), - - ( - hb('ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43'), - b'password', b'salt', 2, 32, 'sha256', - ), - - ( - hb('c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a'), - b'password', b'salt', 4096, 32, 'sha256', - ), - - ( - hb('348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c' - '635518c7dac47e9'), - b'passwordPASSWORDpassword', b'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, 40, 'sha256', - ), - - ( - hb('9e83f279c040f2a11aa4a02b24c418f2d3cb39560c9627fa4f47e3bcc2897c3d'), - b'', b'salt', 1024, 32, 'sha256', - ), - - ( - hb('ea5808411eb0c7e830deab55096cee582761e22a9bc034e3ece925225b07bf46'), - b'password', b'', 1024, 32, 'sha256', - ), - - ( - hb('89b69d0516f829893c696226650a8687'), - b'pass\x00word', b'sa\x00lt', 4096, 16, 'sha256', - ), - - ( - hb('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252'), - b'password', b'salt', 1, 32, 'sha512', - ), - - ( - hb('e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53c'), - b'password', b'salt', 2, 32, 'sha512', - ), - - ( - hb('d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5'), - b'password', b'salt', 4096, 32, 'sha512', - ), - - ( - hb('6e23f27638084b0f7ea1734e0d9841f55dd29ea60a834466f3396bac801fac1eeb' - '63802f03a0b4acd7603e3699c8b74437be83ff01ad7f55dac1ef60f4d56480c35e' - 'e68fd52c6936'), - b'passwordPASSWORDpassword', b'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 1, 72, 'sha512', - ), - - ( - hb('0c60c80f961f0e71f3a9b524af6012062fe037a6'), - b'password', b'salt', 1, 20, 'sha1', - ), - - # - # custom tests - # - ( - hb('e248fb6b13365146f8ac6307cc222812'), - b"secret", b"salt", 10, 16, "sha1", - ), - ( - hb('e248fb6b13365146f8ac6307cc2228127872da6d'), - b"secret", b"salt", 10, None, "sha1", - ), - ( - hb('b1d5485772e6f76d5ebdc11b38d3eff0a5b2bd50dc11f937e86ecacd0cd40d1b' - '9113e0734e3b76a3'), - b"secret", b"salt", 62, 40, "md5", - ), - ( - hb('ea014cc01f78d3883cac364bb5d054e2be238fb0b6081795a9d84512126e3129' - '062104d2183464c4'), - b"secret", b"salt", 62, 40, "md4", - ), - ] - - def test_known(self): - """test reference vectors""" - for row in self.pbkdf2_test_vectors: - correct, secret, salt, rounds, keylen = row[:5] - digest = row[5] if len(row) == 6 else "sha1" - result = pbkdf2_hmac(digest, secret, salt, rounds, keylen) - self.assertEqual(result, correct) - - def test_backends(self): - """verify expected backends are present""" - from passlib.crypto.digest import PBKDF2_BACKENDS - - # check for fastpbkdf2 - try: - import fastpbkdf2 - has_fastpbkdf2 = True - except ImportError: - has_fastpbkdf2 = False - self.assertEqual("fastpbkdf2" in PBKDF2_BACKENDS, has_fastpbkdf2) - - # check for hashlib - try: - from hashlib import pbkdf2_hmac - has_hashlib_ssl = pbkdf2_hmac.__module__ != "hashlib" - except ImportError: - has_hashlib_ssl = False - self.assertEqual("hashlib-ssl" in PBKDF2_BACKENDS, has_hashlib_ssl) - - # check for appropriate builtin - from passlib.utils.compat import PY3 - if PY3: - self.assertIn("builtin-from-bytes", PBKDF2_BACKENDS) - else: - # XXX: only true as long as this is preferred over hexlify - self.assertIn("builtin-unpack", PBKDF2_BACKENDS) - - def test_border(self): - """test border cases""" - def helper(secret=b'password', salt=b'salt', rounds=1, keylen=None, digest="sha1"): - return pbkdf2_hmac(digest, secret, salt, rounds, keylen) - helper() - - # invalid rounds - self.assertRaises(ValueError, helper, rounds=-1) - self.assertRaises(ValueError, helper, rounds=0) - self.assertRaises(TypeError, helper, rounds='x') - - # invalid keylen - helper(keylen=1) - self.assertRaises(ValueError, helper, keylen=-1) - self.assertRaises(ValueError, helper, keylen=0) - # NOTE: hashlib actually throws error for keylen>=MAX_SINT32, - # but pbkdf2 forbids anything > MAX_UINT32 * digest_size - self.assertRaises(OverflowError, helper, keylen=20*(2**32-1)+1) - self.assertRaises(TypeError, helper, keylen='x') - - # invalid secret/salt type - self.assertRaises(TypeError, helper, salt=5) - self.assertRaises(TypeError, helper, secret=5) - - # invalid hash - self.assertRaises(ValueError, helper, digest='foo') - self.assertRaises(TypeError, helper, digest=5) - - def test_default_keylen(self): - """test keylen==None""" - def helper(secret=b'password', salt=b'salt', rounds=1, keylen=None, digest="sha1"): - return pbkdf2_hmac(digest, secret, salt, rounds, keylen) - self.assertEqual(len(helper(digest='sha1')), 20) - self.assertEqual(len(helper(digest='sha256')), 32) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_scrypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_scrypt.py deleted file mode 100644 index 73ff1fa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_crypto_scrypt.py +++ /dev/null @@ -1,634 +0,0 @@ -"""tests for passlib.utils.scrypt""" -#============================================================================= -# imports -#============================================================================= -# core -from binascii import hexlify -import hashlib -import logging; log = logging.getLogger(__name__) -import struct -import warnings -warnings.filterwarnings("ignore", ".*using builtin scrypt backend.*") -# site -# pkg -from passlib import exc -from passlib.utils import getrandbytes -from passlib.utils.compat import PYPY, u, bascii_to_str -from passlib.utils.decor import classproperty -from passlib.tests.utils import TestCase, skipUnless, TEST_MODE, hb -# subject -from passlib.crypto import scrypt as scrypt_mod -# local -__all__ = [ - "ScryptEngineTest", - "BuiltinScryptTest", - "FastScryptTest", -] - -#============================================================================= -# support functions -#============================================================================= -def hexstr(data): - """return bytes as hex str""" - return bascii_to_str(hexlify(data)) - -def unpack_uint32_list(data, check_count=None): - """unpack bytes as list of uint32 values""" - count = len(data) // 4 - assert check_count is None or check_count == count - return struct.unpack("<%dI" % count, data) - -def seed_bytes(seed, count): - """ - generate random reference bytes from specified seed. - used to generate some predictable test vectors. - """ - if hasattr(seed, "encode"): - seed = seed.encode("ascii") - buf = b'' - i = 0 - while len(buf) < count: - buf += hashlib.sha256(seed + struct.pack("" % cls.backend - backend = None - - #============================================================================= - # setup - #============================================================================= - def setUp(self): - assert self.backend - scrypt_mod._set_backend(self.backend) - super(_CommonScryptTest, self).setUp() - - #============================================================================= - # reference vectors - #============================================================================= - - reference_vectors = [ - # entry format: (secret, salt, n, r, p, keylen, result) - - #------------------------------------------------------------------------ - # test vectors from scrypt whitepaper -- - # http://www.tarsnap.com/scrypt/scrypt.pdf, appendix b - # - # also present in (expired) scrypt rfc draft -- - # https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01, section 11 - #------------------------------------------------------------------------ - ("", "", 16, 1, 1, 64, hb(""" - 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 - f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 - fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 - e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 - """)), - - ("password", "NaCl", 1024, 8, 16, 64, hb(""" - fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe - 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 - 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da - c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 - """)), - - # NOTE: the following are skipped for all backends unless TEST_MODE="full" - - ("pleaseletmein", "SodiumChloride", 16384, 8, 1, 64, hb(""" - 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb - fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2 - d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 - e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87 - """)), - - # NOTE: the following are always skipped for the builtin backend, - # (just takes too long to be worth it) - - ("pleaseletmein", "SodiumChloride", 1048576, 8, 1, 64, hb(""" - 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81 - ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47 - 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3 - 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4 - """)), - ] - - def test_reference_vectors(self): - """reference vectors""" - for secret, salt, n, r, p, keylen, result in self.reference_vectors: - if n >= 1024 and TEST_MODE(max="default"): - # skip large values unless we're running full test suite - continue - if n > 16384 and self.backend == "builtin": - # skip largest vector for builtin, takes WAAY too long - # (46s under pypy, ~5m under cpython) - continue - log.debug("scrypt reference vector: %r %r n=%r r=%r p=%r", secret, salt, n, r, p) - self.assertEqual(scrypt_mod.scrypt(secret, salt, n, r, p, keylen), result) - - #============================================================================= - # fuzz testing - #============================================================================= - - _already_tested_others = None - - def test_other_backends(self): - """compare output to other backends""" - # only run once, since test is symetric. - # maybe this means it should go somewhere else? - if self._already_tested_others: - raise self.skipTest("already run under %r backend test" % self._already_tested_others) - self._already_tested_others = self.backend - rng = self.getRandom() - - # get available backends - orig = scrypt_mod.backend - available = set(name for name in scrypt_mod.backend_values - if scrypt_mod._has_backend(name)) - scrypt_mod._set_backend(orig) - available.discard(self.backend) - if not available: - raise self.skipTest("no other backends found") - - warnings.filterwarnings("ignore", "(?i)using builtin scrypt backend", - category=exc.PasslibSecurityWarning) - - # generate some random options, and cross-check output - for _ in range(10): - # NOTE: keeping values low due to builtin test - secret = getrandbytes(rng, rng.randint(0, 64)) - salt = getrandbytes(rng, rng.randint(0, 64)) - n = 1 << rng.randint(1, 10) - r = rng.randint(1, 8) - p = rng.randint(1, 3) - ks = rng.randint(1, 64) - previous = None - backends = set() - for name in available: - scrypt_mod._set_backend(name) - self.assertNotIn(scrypt_mod._scrypt, backends) - backends.add(scrypt_mod._scrypt) - result = hexstr(scrypt_mod.scrypt(secret, salt, n, r, p, ks)) - self.assertEqual(len(result), 2*ks) - if previous is not None: - self.assertEqual(result, previous, - msg="%r output differs from others %r: %r" % - (name, available, [secret, salt, n, r, p, ks])) - - #============================================================================= - # test input types - #============================================================================= - def test_backend(self): - """backend management""" - # clobber backend - scrypt_mod.backend = None - scrypt_mod._scrypt = None - self.assertRaises(TypeError, scrypt_mod.scrypt, 's', 's', 2, 2, 2, 16) - - # reload backend - scrypt_mod._set_backend(self.backend) - self.assertEqual(scrypt_mod.backend, self.backend) - scrypt_mod.scrypt('s', 's', 2, 2, 2, 16) - - # throw error for unknown backend - self.assertRaises(ValueError, scrypt_mod._set_backend, 'xxx') - self.assertEqual(scrypt_mod.backend, self.backend) - - def test_secret_param(self): - """'secret' parameter""" - - def run_scrypt(secret): - return hexstr(scrypt_mod.scrypt(secret, "salt", 2, 2, 2, 16)) - - # unicode - TEXT = u("abc\u00defg") - self.assertEqual(run_scrypt(TEXT), '05717106997bfe0da42cf4779a2f8bd8') - - # utf8 bytes - TEXT_UTF8 = b'abc\xc3\x9efg' - self.assertEqual(run_scrypt(TEXT_UTF8), '05717106997bfe0da42cf4779a2f8bd8') - - # latin1 bytes - TEXT_LATIN1 = b'abc\xdefg' - self.assertEqual(run_scrypt(TEXT_LATIN1), '770825d10eeaaeaf98e8a3c40f9f441d') - - # accept empty string - self.assertEqual(run_scrypt(""), 'ca1399e5fae5d3b9578dcd2b1faff6e2') - - # reject other types - self.assertRaises(TypeError, run_scrypt, None) - self.assertRaises(TypeError, run_scrypt, 1) - - def test_salt_param(self): - """'salt' parameter""" - - def run_scrypt(salt): - return hexstr(scrypt_mod.scrypt("secret", salt, 2, 2, 2, 16)) - - # unicode - TEXT = u("abc\u00defg") - self.assertEqual(run_scrypt(TEXT), 'a748ec0f4613929e9e5f03d1ab741d88') - - # utf8 bytes - TEXT_UTF8 = b'abc\xc3\x9efg' - self.assertEqual(run_scrypt(TEXT_UTF8), 'a748ec0f4613929e9e5f03d1ab741d88') - - # latin1 bytes - TEXT_LATIN1 = b'abc\xdefg' - self.assertEqual(run_scrypt(TEXT_LATIN1), '91d056fb76fb6e9a7d1cdfffc0a16cd1') - - # reject other types - self.assertRaises(TypeError, run_scrypt, None) - self.assertRaises(TypeError, run_scrypt, 1) - - def test_n_param(self): - """'n' (rounds) parameter""" - - def run_scrypt(n): - return hexstr(scrypt_mod.scrypt("secret", "salt", n, 2, 2, 16)) - - # must be > 1, and a power of 2 - self.assertRaises(ValueError, run_scrypt, -1) - self.assertRaises(ValueError, run_scrypt, 0) - self.assertRaises(ValueError, run_scrypt, 1) - self.assertEqual(run_scrypt(2), 'dacf2bca255e2870e6636fa8c8957a66') - self.assertRaises(ValueError, run_scrypt, 3) - self.assertRaises(ValueError, run_scrypt, 15) - self.assertEqual(run_scrypt(16), '0272b8fc72bc54b1159340ed99425233') - - def test_r_param(self): - """'r' (block size) parameter""" - def run_scrypt(r, n=2, p=2): - return hexstr(scrypt_mod.scrypt("secret", "salt", n, r, p, 16)) - - # must be > 1 - self.assertRaises(ValueError, run_scrypt, -1) - self.assertRaises(ValueError, run_scrypt, 0) - self.assertEqual(run_scrypt(1), '3d630447d9f065363b8a79b0b3670251') - self.assertEqual(run_scrypt(2), 'dacf2bca255e2870e6636fa8c8957a66') - self.assertEqual(run_scrypt(5), '114f05e985a903c27237b5578e763736') - - # reject r*p >= 2**30 - self.assertRaises(ValueError, run_scrypt, (1<<30), p=1) - self.assertRaises(ValueError, run_scrypt, (1<<30) / 2, p=2) - - def test_p_param(self): - """'p' (parallelism) parameter""" - def run_scrypt(p, n=2, r=2): - return hexstr(scrypt_mod.scrypt("secret", "salt", n, r, p, 16)) - - # must be > 1 - self.assertRaises(ValueError, run_scrypt, -1) - self.assertRaises(ValueError, run_scrypt, 0) - self.assertEqual(run_scrypt(1), 'f2960ea8b7d48231fcec1b89b784a6fa') - self.assertEqual(run_scrypt(2), 'dacf2bca255e2870e6636fa8c8957a66') - self.assertEqual(run_scrypt(5), '848a0eeb2b3543e7f543844d6ca79782') - - # reject r*p >= 2**30 - self.assertRaises(ValueError, run_scrypt, (1<<30), r=1) - self.assertRaises(ValueError, run_scrypt, (1<<30) / 2, r=2) - - def test_keylen_param(self): - """'keylen' parameter""" - rng = self.getRandom() - - def run_scrypt(keylen): - return hexstr(scrypt_mod.scrypt("secret", "salt", 2, 2, 2, keylen)) - - # must be > 0 - self.assertRaises(ValueError, run_scrypt, -1) - self.assertRaises(ValueError, run_scrypt, 0) - self.assertEqual(run_scrypt(1), 'da') - - # pick random value - ksize = rng.randint(1, 1 << 10) - self.assertEqual(len(run_scrypt(ksize)), 2*ksize) # 2 hex chars per output - - # one more than upper bound - self.assertRaises(ValueError, run_scrypt, ((2**32) - 1) * 32 + 1) - - #============================================================================= - # eoc - #============================================================================= - - -#----------------------------------------------------------------------- -# check what backends 'should' be available -#----------------------------------------------------------------------- - -def _can_import_cffi_scrypt(): - try: - import scrypt - except ImportError as err: - if "scrypt" in str(err): - return False - raise - return True - -has_cffi_scrypt = _can_import_cffi_scrypt() - - -def _can_import_stdlib_scrypt(): - try: - from hashlib import scrypt - return True - except ImportError: - return False - -has_stdlib_scrypt = _can_import_stdlib_scrypt() - -#----------------------------------------------------------------------- -# test individual backends -#----------------------------------------------------------------------- - -# NOTE: builtin version runs VERY slow (except under PyPy, where it's only 11x slower), -# so skipping under quick test mode. -@skipUnless(PYPY or TEST_MODE(min="default"), "skipped under current test mode") -class BuiltinScryptTest(_CommonScryptTest): - backend = "builtin" - - def setUp(self): - super(BuiltinScryptTest, self).setUp() - warnings.filterwarnings("ignore", "(?i)using builtin scrypt backend", - category=exc.PasslibSecurityWarning) - - def test_missing_backend(self): - """backend management -- missing backend""" - if has_stdlib_scrypt or has_cffi_scrypt: - raise self.skipTest("non-builtin backend is present") - self.assertRaises(exc.MissingBackendError, scrypt_mod._set_backend, 'scrypt') - - -@skipUnless(has_cffi_scrypt, "'scrypt' package not found") -class ScryptPackageTest(_CommonScryptTest): - backend = "scrypt" - - def test_default_backend(self): - """backend management -- default backend""" - if has_stdlib_scrypt: - raise self.skipTest("higher priority backend present") - scrypt_mod._set_backend("default") - self.assertEqual(scrypt_mod.backend, "scrypt") - - -@skipUnless(has_stdlib_scrypt, "'hashlib.scrypt()' not found") -class StdlibScryptTest(_CommonScryptTest): - backend = "stdlib" - - def test_default_backend(self): - """backend management -- default backend""" - scrypt_mod._set_backend("default") - self.assertEqual(scrypt_mod.backend, "stdlib") - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django.py deleted file mode 100644 index 2a0b418..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django.py +++ /dev/null @@ -1,1080 +0,0 @@ -"""test passlib.ext.django""" -#============================================================================= -# imports -#============================================================================= -# core -from __future__ import absolute_import, division, print_function -import logging; log = logging.getLogger(__name__) -import sys -import re -# site -# pkg -from passlib import apps as _apps, exc, registry -from passlib.apps import django10_context, django14_context, django16_context -from passlib.context import CryptContext -from passlib.ext.django.utils import ( - DJANGO_VERSION, MIN_DJANGO_VERSION, DjangoTranslator, quirks, -) -from passlib.utils.compat import iteritems, get_method_function, u -from passlib.utils.decor import memoized_property -# tests -from passlib.tests.utils import TestCase, TEST_MODE, handler_derived_from -from passlib.tests.test_handlers import get_handler_case -# local -__all__ = [ - "DjangoBehaviorTest", - "ExtensionBehaviorTest", - "DjangoExtensionTest", - - "_ExtensionSupport", - "_ExtensionTest", -] -#============================================================================= -# configure django settings for testcases -#============================================================================= - -# whether we have supported django version -has_min_django = DJANGO_VERSION >= MIN_DJANGO_VERSION - -# import and configure empty django settings -# NOTE: we don't want to set up entirety of django, so not using django.setup() directly. -# instead, manually configuring the settings, and setting it up w/ no apps installed. -# in future, may need to alter this so we call django.setup() after setting -# DJANGO_SETTINGS_MODULE to a custom settings module w/ a dummy django app. -if has_min_django: - # - # initialize django settings manually - # - from django.conf import settings, LazySettings - - if not isinstance(settings, LazySettings): - # this probably means django globals have been configured already, - # which we don't want, since test cases reset and manipulate settings. - raise RuntimeError("expected django.conf.settings to be LazySettings: %r" % (settings,)) - - # else configure a blank settings instance for the unittests - if not settings.configured: - settings.configure() - - # - # init django apps w/ NO installed apps. - # NOTE: required for django >= 1.9 - # - from django.apps import apps - apps.populate(["django.contrib.contenttypes", "django.contrib.auth"]) - -# log a warning if tested w/ newer version. -# NOTE: this is mainly here as place to mark what version it was run against before release. -if DJANGO_VERSION >= (3, 2): - log.info("this release hasn't been tested against Django %r", DJANGO_VERSION) - -#============================================================================= -# support funcs -#============================================================================= - -# flag for update_settings() to remove specified key entirely -UNSET = object() - -def update_settings(**kwds): - """helper to update django settings from kwds""" - for k,v in iteritems(kwds): - if v is UNSET: - if hasattr(settings, k): - delattr(settings, k) - else: - setattr(settings, k, v) - -if has_min_django: - from django.contrib.auth.models import User - - class FakeUser(User): - """mock user object for use in testing""" - # NOTE: this mainly just overrides .save() to test commit behavior. - - # NOTE: .Meta.app_label required for django >= 1.9 - class Meta: - app_label = __name__ - - @memoized_property - def saved_passwords(self): - return [] - - def pop_saved_passwords(self): - try: - return self.saved_passwords[:] - finally: - del self.saved_passwords[:] - - def save(self, update_fields=None): - # NOTE: ignoring update_fields for test purposes - self.saved_passwords.append(self.password) - -def create_mock_setter(): - state = [] - def setter(password): - state.append(password) - def popstate(): - try: - return state[:] - finally: - del state[:] - setter.popstate = popstate - return setter - - -def check_django_hasher_has_backend(name): - """ - check whether django hasher is available; - or if it should be skipped because django lacks third-party library. - """ - assert name - from django.contrib.auth.hashers import make_password - try: - make_password("", hasher=name) - return True - except ValueError as err: - if re.match("Couldn't load '.*?' algorithm .* No module named .*", str(err)): - return False - raise - -#============================================================================= -# work up stock django config -#============================================================================= - -def _modify_django_config(kwds, sha_rounds=None): - """ - helper to build django CryptContext config matching expected setup for stock django deploy. - :param kwds: - :param sha_rounds: - :return: - """ - # make sure we have dict - if hasattr(kwds, "to_dict"): - # type: CryptContext - kwds = kwds.to_dict() - - # update defaults - kwds.update( - # TODO: push this to passlib.apps django contexts - deprecated="auto", - ) - - # fill in default rounds for current django version, so our sample hashes come back - # unchanged, instead of being upgraded in-place by check_password(). - if sha_rounds is None and has_min_django: - from django.contrib.auth.hashers import PBKDF2PasswordHasher - sha_rounds = PBKDF2PasswordHasher.iterations - - # modify rounds - if sha_rounds: - kwds.update( - django_pbkdf2_sha1__default_rounds=sha_rounds, - django_pbkdf2_sha256__default_rounds=sha_rounds, - ) - - return kwds - -#---------------------------------------------------- -# build config dict that matches stock django -#---------------------------------------------------- - -# XXX: replace this with code that interrogates default django config directly? -# could then separate out "validation of djangoXX_context objects" -# and "validation that individual hashers match django". -# or maybe add a "get_django_context(django_version)" helper to passlib.apps? -if DJANGO_VERSION >= (2, 1): - stock_config = _modify_django_config(_apps.django21_context) -elif DJANGO_VERSION >= (1, 10): - stock_config = _modify_django_config(_apps.django110_context) -else: - # assert DJANGO_VERSION >= (1, 8) - stock_config = _modify_django_config(_apps.django16_context) - -#---------------------------------------------------- -# override sample hashes used in test cases -#---------------------------------------------------- -from passlib.hash import django_pbkdf2_sha256 -sample_hashes = dict( - django_pbkdf2_sha256=("not a password", django_pbkdf2_sha256 - .using(rounds=stock_config.get("django_pbkdf2_sha256__default_rounds")) - .hash("not a password")) -) - -#============================================================================= -# test utils -#============================================================================= - -class _ExtensionSupport(object): - """ - test support funcs for loading/unloading extension. - this class is mixed in to various TestCase subclasses. - """ - #=================================================================== - # support funcs - #=================================================================== - - @classmethod - def _iter_patch_candidates(cls): - """helper to scan for monkeypatches. - - returns tuple containing: - * object (module or class) - * attribute of object - * value of attribute - * whether it should or should not be patched - """ - # XXX: this and assert_unpatched() could probably be refactored to use - # the PatchManager class to do the heavy lifting. - from django.contrib.auth import models, hashers - user_attrs = ["check_password", "set_password"] - model_attrs = ["check_password", "make_password"] - hasher_attrs = ["check_password", "make_password", "get_hasher", "identify_hasher", - "get_hashers"] - objs = [(models, model_attrs), - (models.User, user_attrs), - (hashers, hasher_attrs), - ] - for obj, patched in objs: - for attr in dir(obj): - if attr.startswith("_"): - continue - value = obj.__dict__.get(attr, UNSET) # can't use getattr() due to GAE - if value is UNSET and attr not in patched: - continue - value = get_method_function(value) - source = getattr(value, "__module__", None) - if source: - yield obj, attr, source, (attr in patched) - - #=================================================================== - # verify current patch state - #=================================================================== - - def assert_unpatched(self): - """ - test that django is in unpatched state - """ - # make sure we aren't currently patched - mod = sys.modules.get("passlib.ext.django.models") - self.assertFalse(mod and mod.adapter.patched, "patch should not be enabled") - - # make sure no objects have been replaced, by checking __module__ - for obj, attr, source, patched in self._iter_patch_candidates(): - if patched: - self.assertTrue(source.startswith("django.contrib.auth."), - "obj=%r attr=%r was not reverted: %r" % - (obj, attr, source)) - else: - self.assertFalse(source.startswith("passlib."), - "obj=%r attr=%r should not have been patched: %r" % - (obj, attr, source)) - - def assert_patched(self, context=None): - """ - helper to ensure django HAS been patched, and is using specified config - """ - # make sure we're currently patched - mod = sys.modules.get("passlib.ext.django.models") - self.assertTrue(mod and mod.adapter.patched, "patch should have been enabled") - - # make sure only the expected objects have been patched - for obj, attr, source, patched in self._iter_patch_candidates(): - if patched: - self.assertTrue(source == "passlib.ext.django.utils", - "obj=%r attr=%r should have been patched: %r" % - (obj, attr, source)) - else: - self.assertFalse(source.startswith("passlib."), - "obj=%r attr=%r should not have been patched: %r" % - (obj, attr, source)) - - # check context matches - if context is not None: - context = CryptContext._norm_source(context) - self.assertEqual(mod.password_context.to_dict(resolve=True), - context.to_dict(resolve=True)) - - #=================================================================== - # load / unload the extension (and verify it worked) - #=================================================================== - - _config_keys = ["PASSLIB_CONFIG", "PASSLIB_CONTEXT", "PASSLIB_GET_CATEGORY"] - - def load_extension(self, check=True, **kwds): - """ - helper to load extension with specified config & patch django - """ - self.unload_extension() - if check: - config = kwds.get("PASSLIB_CONFIG") or kwds.get("PASSLIB_CONTEXT") - for key in self._config_keys: - kwds.setdefault(key, UNSET) - update_settings(**kwds) - import passlib.ext.django.models - if check: - self.assert_patched(context=config) - - def unload_extension(self): - """ - helper to remove patches and unload extension - """ - # remove patches and unload module - mod = sys.modules.get("passlib.ext.django.models") - if mod: - mod.adapter.remove_patch() - del sys.modules["passlib.ext.django.models"] - # wipe config from django settings - update_settings(**dict((key, UNSET) for key in self._config_keys)) - # check everything's gone - self.assert_unpatched() - - #=================================================================== - # eoc - #=================================================================== - - -# XXX: rename to ExtensionFixture? -# NOTE: would roll this into _ExtensionSupport class; -# but we have to mix that one into django's TestCase classes as well; -# and our TestCase class (and this setUp() method) would foul things up. -class _ExtensionTest(TestCase, _ExtensionSupport): - """ - TestCase mixin which makes sure extension is unloaded before test; - and make sure it's unloaded after test as well. - """ - #============================================================================= - # setup - #============================================================================= - - def setUp(self): - super(_ExtensionTest, self).setUp() - - self.require_TEST_MODE("default") - - if not DJANGO_VERSION: - raise self.skipTest("Django not installed") - elif not has_min_django: - raise self.skipTest("Django version too old") - - # reset to baseline, and verify it worked - self.unload_extension() - - # and do the same when the test exits - self.addCleanup(self.unload_extension) - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# extension tests -#============================================================================= - -#: static passwords used by DjangoBehaviorTest methods -PASS1 = "toomanysecrets" -WRONG1 = "letmein" - - -class DjangoBehaviorTest(_ExtensionTest): - """ - tests model to verify it matches django's behavior. - - running this class verifies the tests correctly assert what Django itself does. - - running the ExtensionBehaviorTest subclass below verifies "passlib.ext.django" - matches what the tests assert. - """ - #============================================================================= - # class attrs - #============================================================================= - - descriptionPrefix = "verify django behavior" - - #: tracks whether tests should assume "passlib.ext.django" monkeypatch is applied. - #: (set to True by ExtensionBehaviorTest subclass) - patched = False - - #: dict containing CryptContext() config which should match current django deploy. - #: used by tests to verify expected behavior. - config = stock_config - - # NOTE: if this test fails, it means we're not accounting for - # some part of django's hashing logic, or that this is - # running against an untested version of django with a new - # hashing policy. - - #============================================================================= - # test helpers - #============================================================================= - - @memoized_property - def context(self): - """ - per-test CryptContext() created from .config. - """ - return CryptContext._norm_source(self.config) - - def assert_unusable_password(self, user): - """ - check that user object is set to 'unusable password' constant - """ - self.assertTrue(user.password.startswith("!")) - self.assertFalse(user.has_usable_password()) - self.assertEqual(user.pop_saved_passwords(), []) - - def assert_valid_password(self, user, hash=UNSET, saved=None): - """ - check that user object has a usable password hash. - :param hash: optionally check it has this exact hash - :param saved: check that mock commit history for user.password matches this list - """ - if hash is UNSET: - self.assertNotEqual(user.password, "!") - self.assertNotEqual(user.password, None) - else: - self.assertEqual(user.password, hash) - self.assertTrue(user.has_usable_password(), - "hash should be usable: %r" % (user.password,)) - self.assertEqual(user.pop_saved_passwords(), - [] if saved is None else [saved]) - - #============================================================================= - # test hashing interface - #----------------------------------------------------------------------------- - # these functions are run against both the actual django code, - # to verify the assumptions of the unittests are correct; - # and run against the passlib extension, to verify it matches those assumptions. - # - # these tests check the following django methods: - # User.set_password() - # User.check_password() - # make_password() -- 1.4 only - # check_password() - # identify_hasher() - # User.has_usable_password() - # User.set_unusable_password() - # - # XXX: this take a while to run. what could be trimmed? - # - # TODO: add get_hasher() checks where appropriate in tests below. - #============================================================================= - - def test_extension_config(self): - """ - test extension config is loaded correctly - """ - if not self.patched: - raise self.skipTest("extension not loaded") - - ctx = self.context - - # contexts should match - from django.contrib.auth.hashers import check_password - from passlib.ext.django.models import password_context - self.assertEqual(password_context.to_dict(resolve=True), ctx.to_dict(resolve=True)) - - # should have patched both places - from django.contrib.auth.models import check_password as check_password2 - self.assertEqual(check_password2, check_password) - - def test_default_algorithm(self): - """ - test django's default algorithm - """ - ctx = self.context - - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import make_password - - # User.set_password() should use default alg - user = FakeUser() - user.set_password(PASS1) - self.assertTrue(ctx.handler().verify(PASS1, user.password)) - self.assert_valid_password(user) - - # User.check_password() - n/a - - # make_password() should use default alg - hash = make_password(PASS1) - self.assertTrue(ctx.handler().verify(PASS1, hash)) - - # check_password() - n/a - - def test_empty_password(self): - """ - test how methods handle empty string as password - """ - ctx = self.context - - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - # User.set_password() should use default alg - user = FakeUser() - user.set_password('') - hash = user.password - self.assertTrue(ctx.handler().verify('', hash)) - self.assert_valid_password(user, hash) - - # User.check_password() should return True - self.assertTrue(user.check_password("")) - self.assert_valid_password(user, hash) - - # XXX: test make_password() ? - - # TODO: is_password_usable() - - # identify_hasher() -- na - - # check_password() should return True - self.assertTrue(check_password("", hash)) - - def test_unusable_flag(self): - """ - test how methods handle 'unusable flag' in hash - """ - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - # sanity check via user.set_unusable_password() - user = FakeUser() - user.set_unusable_password() - self.assert_unusable_password(user) - - # ensure User.set_password() sets unusable flag - user = FakeUser() - user.set_password(None) - self.assert_unusable_password(user) - - # User.check_password() should always fail - self.assertFalse(user.check_password(None)) - self.assertFalse(user.check_password('None')) - self.assertFalse(user.check_password('')) - self.assertFalse(user.check_password(PASS1)) - self.assertFalse(user.check_password(WRONG1)) - self.assert_unusable_password(user) - - # make_password() should also set flag - self.assertTrue(make_password(None).startswith("!")) - - # check_password() should return False (didn't handle disabled under 1.3) - self.assertFalse(check_password(PASS1, '!')) - - # identify_hasher() and is_password_usable() should reject it - self.assertFalse(is_password_usable(user.password)) - self.assertRaises(ValueError, identify_hasher, user.password) - - def test_none_hash_value(self): - """ - test how methods handle None as hash value - """ - patched = self.patched - - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - # User.set_password() - n/a - - # User.check_password() - returns False - user = FakeUser() - user.password = None - if quirks.none_causes_check_password_error and not patched: - # django 2.1+ - self.assertRaises(TypeError, user.check_password, PASS1) - else: - self.assertFalse(user.check_password(PASS1)) - - self.assertEqual(user.has_usable_password(), - quirks.empty_is_usable_password) - - # TODO: is_password_usable() - - # make_password() - n/a - - # check_password() - error - if quirks.none_causes_check_password_error and not patched: - self.assertRaises(TypeError, check_password, PASS1, None) - else: - self.assertFalse(check_password(PASS1, None)) - - # identify_hasher() - error - self.assertRaises(TypeError, identify_hasher, None) - - def test_empty_hash_value(self): - """ - test how methods handle empty string as hash value - """ - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - # User.set_password() - n/a - - # User.check_password() - # As of django 1.5, blank hash returns False (django issue 18453) - user = FakeUser() - user.password = "" - self.assertFalse(user.check_password(PASS1)) - - # verify hash wasn't changed/upgraded during check_password() call - self.assertEqual(user.password, "") - self.assertEqual(user.pop_saved_passwords(), []) - - # User.has_usable_password() - self.assertEqual(user.has_usable_password(), quirks.empty_is_usable_password) - - # TODO: is_password_usable() - - # make_password() - n/a - - # check_password() - self.assertFalse(check_password(PASS1, "")) - - # identify_hasher() - throws error - self.assertRaises(ValueError, identify_hasher, "") - - def test_invalid_hash_values(self): - """ - test how methods handle invalid hash values. - """ - for hash in [ - "$789$foo", # empty identifier - ]: - with self.subTest(hash=hash): - self._do_test_invalid_hash_value(hash) - - def _do_test_invalid_hash_value(self, hash): - - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - # User.set_password() - n/a - - # User.check_password() - # As of django 1.5, invalid hash returns False (side effect of django issue 18453) - user = FakeUser() - user.password = hash - self.assertFalse(user.check_password(PASS1)) - - # verify hash wasn't changed/upgraded during check_password() call - self.assertEqual(user.password, hash) - self.assertEqual(user.pop_saved_passwords(), []) - - # User.has_usable_password() - self.assertEqual(user.has_usable_password(), quirks.invalid_is_usable_password) - - # TODO: is_password_usable() - - # make_password() - n/a - - # check_password() - self.assertFalse(check_password(PASS1, hash)) - - # identify_hasher() - throws error - self.assertRaises(ValueError, identify_hasher, hash) - - def test_available_schemes(self): - """ - run a bunch of subtests for each hasher available in the default django setup - (as determined by reading self.context) - """ - for scheme in self.context.schemes(): - with self.subTest(scheme=scheme): - self._do_test_available_scheme(scheme) - - def _do_test_available_scheme(self, scheme): - """ - helper to test how specific hasher behaves. - :param scheme: *passlib* name of hasher (e.g. "django_pbkdf2_sha256") - """ - log = self.getLogger() - ctx = self.context - patched = self.patched - setter = create_mock_setter() - - # NOTE: import has to be done w/in method, in case monkeypatching is applied by setUp() - from django.contrib.auth.hashers import ( - check_password, - make_password, - is_password_usable, - identify_hasher, - ) - - #------------------------------------------------------- - # setup constants & imports, pick a sample secret/hash combo - #------------------------------------------------------- - handler = ctx.handler(scheme) - log.debug("testing scheme: %r => %r", scheme, handler) - deprecated = ctx.handler(scheme).deprecated - assert not deprecated or scheme != ctx.default_scheme() - try: - testcase = get_handler_case(scheme) - except exc.MissingBackendError: - raise self.skipTest("backend not available") - assert handler_derived_from(handler, testcase.handler) - if handler.is_disabled: - raise self.skipTest("skip disabled hasher") - - # verify that django has a backend available - # (since our hasher may use different set of backends, - # get_handler_case() above may work, but django will have nothing) - if not patched and not check_django_hasher_has_backend(handler.django_name): - assert scheme in ["django_bcrypt", "django_bcrypt_sha256", "django_argon2"], \ - "%r scheme should always have active backend" % scheme - log.warning("skipping scheme %r due to missing django dependency", scheme) - raise self.skipTest("skip due to missing dependency") - - # find a sample (secret, hash) pair to test with - try: - secret, hash = sample_hashes[scheme] - except KeyError: - get_sample_hash = testcase("setUp").get_sample_hash - while True: - secret, hash = get_sample_hash() - if secret: # don't select blank passwords - break - other = 'dontletmein' - - #------------------------------------------------------- - # User.set_password() - not tested here - #------------------------------------------------------- - - #------------------------------------------------------- - # User.check_password()+migration against known hash - #------------------------------------------------------- - user = FakeUser() - user.password = hash - - # check against invalid password - self.assertFalse(user.check_password(None)) - ##self.assertFalse(user.check_password('')) - self.assertFalse(user.check_password(other)) - self.assert_valid_password(user, hash) - - # check against valid password - self.assertTrue(user.check_password(secret)) - - # check if it upgraded the hash - # NOTE: needs_update kept separate in case we need to test rounds. - needs_update = deprecated - if needs_update: - self.assertNotEqual(user.password, hash) - self.assertFalse(handler.identify(user.password)) - self.assertTrue(ctx.handler().verify(secret, user.password)) - self.assert_valid_password(user, saved=user.password) - else: - self.assert_valid_password(user, hash) - - # don't need to check rest for most deployments - if TEST_MODE(max="default"): - return - - #------------------------------------------------------- - # make_password() correctly selects algorithm - #------------------------------------------------------- - alg = DjangoTranslator().passlib_to_django_name(scheme) - hash2 = make_password(secret, hasher=alg) - self.assertTrue(handler.verify(secret, hash2)) - - #------------------------------------------------------- - # check_password()+setter against known hash - #------------------------------------------------------- - # should call setter only if it needs_update - self.assertTrue(check_password(secret, hash, setter=setter)) - self.assertEqual(setter.popstate(), [secret] if needs_update else []) - - # should not call setter - self.assertFalse(check_password(other, hash, setter=setter)) - self.assertEqual(setter.popstate(), []) - - ### check preferred kwd is ignored (feature we don't currently support fully) - ##self.assertTrue(check_password(secret, hash, setter=setter, preferred='fooey')) - ##self.assertEqual(setter.popstate(), [secret]) - - # TODO: get_hasher() - - #------------------------------------------------------- - # identify_hasher() recognizes known hash - #------------------------------------------------------- - self.assertTrue(is_password_usable(hash)) - name = DjangoTranslator().django_to_passlib_name(identify_hasher(hash).algorithm) - self.assertEqual(name, scheme) - - #=================================================================== - # eoc - #=================================================================== - -#=================================================================== -# extension fidelity tests -#=================================================================== - -class ExtensionBehaviorTest(DjangoBehaviorTest): - """ - test that "passlib.ext.django" conforms to behavioral assertions in DjangoBehaviorTest - """ - descriptionPrefix = "verify extension behavior" - - config = dict( - schemes="sha256_crypt,md5_crypt,des_crypt", - deprecated="des_crypt", - ) - - def setUp(self): - super(ExtensionBehaviorTest, self).setUp() - - # always load extension before each test - self.load_extension(PASSLIB_CONFIG=self.config) - self.patched = True - -#=================================================================== -# extension internal tests -#=================================================================== - -class DjangoExtensionTest(_ExtensionTest): - """ - test the ``passlib.ext.django`` plugin - """ - #=================================================================== - # class attrs - #=================================================================== - - descriptionPrefix = "passlib.ext.django plugin" - - #=================================================================== - # monkeypatch testing - #=================================================================== - - def test_00_patch_control(self): - """test set_django_password_context patch/unpatch""" - - # check config="disabled" - self.load_extension(PASSLIB_CONFIG="disabled", check=False) - self.assert_unpatched() - - # check legacy config=None - with self.assertWarningList("PASSLIB_CONFIG=None is deprecated"): - self.load_extension(PASSLIB_CONFIG=None, check=False) - self.assert_unpatched() - - # try stock django 1.0 context - self.load_extension(PASSLIB_CONFIG="django-1.0", check=False) - self.assert_patched(context=django10_context) - - # try to remove patch - self.unload_extension() - - # patch to use stock django 1.4 context - self.load_extension(PASSLIB_CONFIG="django-1.4", check=False) - self.assert_patched(context=django14_context) - - # try to remove patch again - self.unload_extension() - - def test_01_overwrite_detection(self): - """test detection of foreign monkeypatching""" - # NOTE: this sets things up, and spot checks two methods, - # this should be enough to verify patch manager is working. - # TODO: test unpatch behavior honors flag. - - # configure plugin to use sample context - config = "[passlib]\nschemes=des_crypt\n" - self.load_extension(PASSLIB_CONFIG=config) - - # setup helpers - import django.contrib.auth.models as models - from passlib.ext.django.models import adapter - def dummy(): - pass - - # mess with User.set_password, make sure it's detected - orig = models.User.set_password - models.User.set_password = dummy - with self.assertWarningList("another library has patched.*User\.set_password"): - adapter._manager.check_all() - models.User.set_password = orig - - # mess with models.check_password, make sure it's detected - orig = models.check_password - models.check_password = dummy - with self.assertWarningList("another library has patched.*models:check_password"): - adapter._manager.check_all() - models.check_password = orig - - def test_02_handler_wrapper(self): - """test Hasher-compatible handler wrappers""" - from django.contrib.auth import hashers - - passlib_to_django = DjangoTranslator().passlib_to_django - - # should return native django hasher if available - if DJANGO_VERSION > (1, 10): - self.assertRaises(ValueError, passlib_to_django, "hex_md5") - else: - hasher = passlib_to_django("hex_md5") - self.assertIsInstance(hasher, hashers.UnsaltedMD5PasswordHasher) - - # should return native django hasher - # NOTE: present but not enabled by default in django as of 2.1 - # (see _builtin_django_hashers) - hasher = passlib_to_django("django_bcrypt") - self.assertIsInstance(hasher, hashers.BCryptPasswordHasher) - - # otherwise should return wrapper - from passlib.hash import sha256_crypt - hasher = passlib_to_django("sha256_crypt") - self.assertEqual(hasher.algorithm, "passlib_sha256_crypt") - - # and wrapper should return correct hash - encoded = hasher.encode("stub") - self.assertTrue(sha256_crypt.verify("stub", encoded)) - self.assertTrue(hasher.verify("stub", encoded)) - self.assertFalse(hasher.verify("xxxx", encoded)) - - # test wrapper accepts options - encoded = hasher.encode("stub", "abcd"*4, rounds=1234) - self.assertEqual(encoded, "$5$rounds=1234$abcdabcdabcdabcd$" - "v2RWkZQzctPdejyRqmmTDQpZN6wTh7.RUy9zF2LftT6") - self.assertEqual(hasher.safe_summary(encoded), - {'algorithm': 'sha256_crypt', - 'salt': u('abcdab**********'), - 'rounds': 1234, - 'hash': u('v2RWkZ*************************************'), - }) - - # made up name should throw error - # XXX: should this throw ValueError instead, to match django? - self.assertRaises(KeyError, passlib_to_django, "does_not_exist") - - #=================================================================== - # PASSLIB_CONFIG settings - #=================================================================== - def test_11_config_disabled(self): - """test PASSLIB_CONFIG='disabled'""" - # test config=None (deprecated) - with self.assertWarningList("PASSLIB_CONFIG=None is deprecated"): - self.load_extension(PASSLIB_CONFIG=None, check=False) - self.assert_unpatched() - - # test disabled config - self.load_extension(PASSLIB_CONFIG="disabled", check=False) - self.assert_unpatched() - - def test_12_config_presets(self): - """test PASSLIB_CONFIG=''""" - # test django presets - self.load_extension(PASSLIB_CONTEXT="django-default", check=False) - ctx = django16_context - self.assert_patched(ctx) - - self.load_extension(PASSLIB_CONFIG="django-1.0", check=False) - self.assert_patched(django10_context) - - self.load_extension(PASSLIB_CONFIG="django-1.4", check=False) - self.assert_patched(django14_context) - - def test_13_config_defaults(self): - """test PASSLIB_CONFIG default behavior""" - # check implicit default - from passlib.ext.django.utils import PASSLIB_DEFAULT - default = CryptContext.from_string(PASSLIB_DEFAULT) - self.load_extension() - self.assert_patched(PASSLIB_DEFAULT) - - # check default preset - self.load_extension(PASSLIB_CONTEXT="passlib-default", check=False) - self.assert_patched(PASSLIB_DEFAULT) - - # check explicit string - self.load_extension(PASSLIB_CONTEXT=PASSLIB_DEFAULT, check=False) - self.assert_patched(PASSLIB_DEFAULT) - - def test_14_config_invalid(self): - """test PASSLIB_CONFIG type checks""" - update_settings(PASSLIB_CONTEXT=123, PASSLIB_CONFIG=UNSET) - self.assertRaises(TypeError, __import__, 'passlib.ext.django.models') - - self.unload_extension() - update_settings(PASSLIB_CONFIG="missing-preset", PASSLIB_CONTEXT=UNSET) - self.assertRaises(ValueError, __import__, 'passlib.ext.django.models') - - #=================================================================== - # PASSLIB_GET_CATEGORY setting - #=================================================================== - def test_21_category_setting(self): - """test PASSLIB_GET_CATEGORY parameter""" - # define config where rounds can be used to detect category - config = dict( - schemes = ["sha256_crypt"], - sha256_crypt__default_rounds = 1000, - staff__sha256_crypt__default_rounds = 2000, - superuser__sha256_crypt__default_rounds = 3000, - ) - from passlib.hash import sha256_crypt - - def run(**kwds): - """helper to take in user opts, return rounds used in password""" - user = FakeUser(**kwds) - user.set_password("stub") - return sha256_crypt.from_string(user.password).rounds - - # test default get_category - self.load_extension(PASSLIB_CONFIG=config) - self.assertEqual(run(), 1000) - self.assertEqual(run(is_staff=True), 2000) - self.assertEqual(run(is_superuser=True), 3000) - - # test patch uses explicit get_category function - def get_category(user): - return user.first_name or None - self.load_extension(PASSLIB_CONTEXT=config, - PASSLIB_GET_CATEGORY=get_category) - self.assertEqual(run(), 1000) - self.assertEqual(run(first_name='other'), 1000) - self.assertEqual(run(first_name='staff'), 2000) - self.assertEqual(run(first_name='superuser'), 3000) - - # test patch can disable get_category entirely - def get_category(user): - return None - self.load_extension(PASSLIB_CONTEXT=config, - PASSLIB_GET_CATEGORY=get_category) - self.assertEqual(run(), 1000) - self.assertEqual(run(first_name='other'), 1000) - self.assertEqual(run(first_name='staff', is_staff=True), 1000) - self.assertEqual(run(first_name='superuser', is_superuser=True), 1000) - - # test bad value - self.assertRaises(TypeError, self.load_extension, PASSLIB_CONTEXT=config, - PASSLIB_GET_CATEGORY='x') - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django_source.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django_source.py deleted file mode 100644 index 4b42e59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_ext_django_source.py +++ /dev/null @@ -1,250 +0,0 @@ -""" -test passlib.ext.django against django source tests -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import absolute_import, division, print_function -# core -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils.compat import suppress_cause -from passlib.ext.django.utils import DJANGO_VERSION, DjangoTranslator, _PasslibHasherWrapper -# tests -from passlib.tests.utils import TestCase, TEST_MODE -from .test_ext_django import ( - has_min_django, stock_config, _ExtensionSupport, -) -if has_min_django: - from .test_ext_django import settings -# local -__all__ = [ - "HashersTest", -] -#============================================================================= -# HashersTest -- -# hack up the some of the real django tests to run w/ extension loaded, -# to ensure we mimic their behavior. -# however, the django tests were moved out of the package, and into a source-only location -# as of django 1.7. so we disable tests from that point on unless test-runner specifies -#============================================================================= - -#: ref to django unittest root module (if found) -test_hashers_mod = None - -#: message about why test module isn't present (if not found) -hashers_skip_msg = None - -#---------------------------------------------------------------------- -# try to load django's tests/auth_tests/test_hasher.py module, -# or note why we failed. -#---------------------------------------------------------------------- -if TEST_MODE(max="quick"): - hashers_skip_msg = "requires >= 'default' test mode" - -elif has_min_django: - import os - import sys - source_path = os.environ.get("PASSLIB_TESTS_DJANGO_SOURCE_PATH") - - if source_path: - if not os.path.exists(source_path): - raise EnvironmentError("django source path not found: %r" % source_path) - if not all(os.path.exists(os.path.join(source_path, name)) - for name in ["django", "tests"]): - raise EnvironmentError("invalid django source path: %r" % source_path) - log.info("using django tests from source path: %r", source_path) - tests_path = os.path.join(source_path, "tests") - sys.path.insert(0, tests_path) - try: - from auth_tests import test_hashers as test_hashers_mod - except ImportError as err: - raise suppress_cause( - EnvironmentError("error trying to import django tests " - "from source path (%r): %r" % - (source_path, err))) - finally: - sys.path.remove(tests_path) - - else: - hashers_skip_msg = "requires PASSLIB_TESTS_DJANGO_SOURCE_PATH to be set" - - if TEST_MODE("full"): - # print warning so user knows what's happening - sys.stderr.write("\nWARNING: $PASSLIB_TESTS_DJANGO_SOURCE_PATH is not set; " - "can't run Django's own unittests against passlib.ext.django\n") - -elif DJANGO_VERSION: - hashers_skip_msg = "django version too old" - -else: - hashers_skip_msg = "django not installed" - -#---------------------------------------------------------------------- -# if found module, create wrapper to run django's own tests, -# but with passlib monkeypatched in. -#---------------------------------------------------------------------- -if test_hashers_mod: - from django.core.signals import setting_changed - from django.dispatch import receiver - from django.utils.module_loading import import_string - from passlib.utils.compat import get_unbound_method_function - - class HashersTest(test_hashers_mod.TestUtilsHashPass, _ExtensionSupport): - """ - Run django's hasher unittests against passlib's extension - and workalike implementations - """ - - #================================================================== - # helpers - #================================================================== - - # port patchAttr() helper method from passlib.tests.utils.TestCase - patchAttr = get_unbound_method_function(TestCase.patchAttr) - - #================================================================== - # custom setup - #================================================================== - def setUp(self): - #--------------------------------------------------------- - # install passlib.ext.django adapter, and get context - #--------------------------------------------------------- - self.load_extension(PASSLIB_CONTEXT=stock_config, check=False) - from passlib.ext.django.models import adapter - context = adapter.context - - #--------------------------------------------------------- - # patch tests module to use our versions of patched funcs - # (which should be installed in hashers module) - #--------------------------------------------------------- - from django.contrib.auth import hashers - for attr in ["make_password", - "check_password", - "identify_hasher", - "is_password_usable", - "get_hasher"]: - self.patchAttr(test_hashers_mod, attr, getattr(hashers, attr)) - - #--------------------------------------------------------- - # django tests expect empty django_des_crypt salt field - #--------------------------------------------------------- - from passlib.hash import django_des_crypt - self.patchAttr(django_des_crypt, "use_duplicate_salt", False) - - #--------------------------------------------------------- - # install receiver to update scheme list if test changes settings - #--------------------------------------------------------- - django_to_passlib_name = DjangoTranslator().django_to_passlib_name - - @receiver(setting_changed, weak=False) - def update_schemes(**kwds): - if kwds and kwds['setting'] != 'PASSWORD_HASHERS': - return - assert context is adapter.context - schemes = [ - django_to_passlib_name(import_string(hash_path)()) - for hash_path in settings.PASSWORD_HASHERS - ] - # workaround for a few tests that only specify hex_md5, - # but test for django_salted_md5 format. - if "hex_md5" in schemes and "django_salted_md5" not in schemes: - schemes.append("django_salted_md5") - schemes.append("django_disabled") - context.update(schemes=schemes, deprecated="auto") - adapter.reset_hashers() - - self.addCleanup(setting_changed.disconnect, update_schemes) - - update_schemes() - - #--------------------------------------------------------- - # need password_context to keep up to date with django_hasher.iterations, - # which is frequently patched by django tests. - # - # HACK: to fix this, inserting wrapper around a bunch of context - # methods so that any time adapter calls them, - # attrs are resynced first. - #--------------------------------------------------------- - - def update_rounds(): - """ - sync django hasher config -> passlib hashers - """ - for handler in context.schemes(resolve=True): - if 'rounds' not in handler.setting_kwds: - continue - hasher = adapter.passlib_to_django(handler) - if isinstance(hasher, _PasslibHasherWrapper): - continue - rounds = getattr(hasher, "rounds", None) or \ - getattr(hasher, "iterations", None) - if rounds is None: - continue - # XXX: this doesn't modify the context, which would - # cause other weirdness (since it would replace handler factories completely, - # instead of just updating their state) - handler.min_desired_rounds = handler.max_desired_rounds = handler.default_rounds = rounds - - _in_update = [False] - - def update_wrapper(wrapped, *args, **kwds): - """ - wrapper around arbitrary func, that first triggers sync - """ - if not _in_update[0]: - _in_update[0] = True - try: - update_rounds() - finally: - _in_update[0] = False - return wrapped(*args, **kwds) - - # sync before any context call - for attr in ["schemes", "handler", "default_scheme", "hash", - "verify", "needs_update", "verify_and_update"]: - self.patchAttr(context, attr, update_wrapper, wrap=True) - - # sync whenever adapter tries to resolve passlib hasher - self.patchAttr(adapter, "django_to_passlib", update_wrapper, wrap=True) - - def tearDown(self): - # NOTE: could rely on addCleanup() instead, but need py26 compat - self.unload_extension() - super(HashersTest, self).tearDown() - - #================================================================== - # skip a few methods that can't be replicated properly - # *want to minimize these as much as possible* - #================================================================== - - _OMIT = lambda self: self.skipTest("omitted by passlib") - - # XXX: this test registers two classes w/ same algorithm id, - # something we don't support -- how does django sanely handle - # that anyways? get_hashers_by_algorithm() should throw KeyError, right? - test_pbkdf2_upgrade_new_hasher = _OMIT - - # TODO: support wrapping django's harden-runtime feature? - # would help pass their tests. - test_check_password_calls_harden_runtime = _OMIT - test_bcrypt_harden_runtime = _OMIT - test_pbkdf2_harden_runtime = _OMIT - - #================================================================== - # eoc - #================================================================== - -else: - # otherwise leave a stub so test log tells why test was skipped. - - class HashersTest(TestCase): - - def test_external_django_hasher_tests(self): - """external django hasher tests""" - raise self.skipTest(hashers_skip_msg) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers.py deleted file mode 100644 index cad5ef9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers.py +++ /dev/null @@ -1,1819 +0,0 @@ -"""passlib.tests.test_handlers - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -import os -import sys -import warnings -# site -# pkg -from passlib import exc, hash -from passlib.utils import repeat_string -from passlib.utils.compat import irange, PY3, u, get_method_function -from passlib.tests.utils import TestCase, HandlerCase, skipUnless, \ - TEST_MODE, UserHandlerMixin, EncodingHandlerMixin -# module - -#============================================================================= -# constants & support -#============================================================================= - -# some common unicode passwords which used as test cases -UPASS_WAV = u('\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2') -UPASS_USD = u("\u20AC\u00A5$") -UPASS_TABLE = u("t\u00e1\u0411\u2113\u0259") - -PASS_TABLE_UTF8 = b't\xc3\xa1\xd0\x91\xe2\x84\x93\xc9\x99' # utf-8 - -# handlers which support multiple backends, but don't have multi-backend tests. -_omitted_backend_tests = ["django_bcrypt", "django_bcrypt_sha256", "django_argon2"] - -#: modules where get_handler_case() should search for test cases. -_handler_test_modules = [ - "test_handlers", - "test_handlers_argon2", - "test_handlers_bcrypt", - "test_handlers_cisco", - "test_handlers_django", - "test_handlers_pbkdf2", - "test_handlers_scrypt", -] - -def get_handler_case(scheme): - """ - return HandlerCase instance for scheme, used by other tests. - - :param scheme: name of hasher to locate test for (e.g. "bcrypt") - - :raises KeyError: - if scheme isn't known hasher. - - :raises MissingBackendError: - if hasher doesn't have any available backends. - - :returns: - HandlerCase subclass (which derives from TestCase) - """ - from passlib.registry import get_crypt_handler - handler = get_crypt_handler(scheme) - if hasattr(handler, "backends") and scheme not in _omitted_backend_tests: - # XXX: if no backends available, could proceed to pick first backend for test lookup; - # should investigate if that would be useful to callers. - try: - backend = handler.get_backend() - except exc.MissingBackendError: - assert scheme in conditionally_available_hashes - raise - name = "%s_%s_test" % (scheme, backend) - else: - name = "%s_test" % scheme - for module in _handler_test_modules: - modname = "passlib.tests." + module - __import__(modname) - mod = sys.modules[modname] - try: - return getattr(mod, name) - except AttributeError: - pass - # every hasher should have test suite, so if we get here, means test is either missing, - # misnamed, or _handler_test_modules list is out of date. - raise RuntimeError("can't find test case named %r for %r" % (name, scheme)) - -#: hashes which there may not be a backend available for, -#: and get_handler_case() may (correctly) throw a MissingBackendError -conditionally_available_hashes = ["argon2", "bcrypt", "bcrypt_sha256"] - -#============================================================================= -# apr md5 crypt -#============================================================================= -class apr_md5_crypt_test(HandlerCase): - handler = hash.apr_md5_crypt - - known_correct_hashes = [ - # - # http://httpd.apache.org/docs/2.2/misc/password_encryptions.html - # - ('myPassword', '$apr1$r31.....$HqJZimcKQFAMYayBlzkrA/'), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, '$apr1$bzYrOHUx$a1FcpXuQDJV3vPY20CS6N1'), - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash ----\/ - '$apr1$r31.....$HqJZimcKQFAMYayBlzkrA!' - ] - -#============================================================================= -# bigcrypt -#============================================================================= -class bigcrypt_test(HandlerCase): - handler = hash.bigcrypt - - # TODO: find an authoritative source of test vectors - known_correct_hashes = [ - - # - # various docs & messages on the web. - # - ("passphrase", "qiyh4XPJGsOZ2MEAyLkfWqeQ"), - ("This is very long passwd", "f8.SVpL2fvwjkAnxn8/rgTkwvrif6bjYB5c"), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, 'SEChBAyMbMNhgGLyP7kD1HZU'), - ] - - known_unidentified_hashes = [ - # one char short (10 % 11) - "qiyh4XPJGsOZ2MEAyLkfWqe" - - # one char too many (1 % 11) - "f8.SVpL2fvwjkAnxn8/rgTkwvrif6bjYB5cd" - ] - - # omit des_crypt from known_other since it's a valid bigcrypt hash too. - known_other_hashes = [row for row in HandlerCase.known_other_hashes - if row[0] != "des_crypt"] - - def test_90_internal(self): - # check that _norm_checksum() also validates checksum size. - # (current code uses regex in parser) - self.assertRaises(ValueError, hash.bigcrypt, use_defaults=True, - checksum=u('yh4XPJGsOZ')) - -#============================================================================= -# bsdi crypt -#============================================================================= -class _bsdi_crypt_test(HandlerCase): - """test BSDiCrypt algorithm""" - handler = hash.bsdi_crypt - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', '_J9..CCCCXBrJUJV154M'), - ('U*U***U', '_J9..CCCCXUhOBTXzaiE'), - ('U*U***U*', '_J9..CCCC4gQ.mB/PffM'), - ('*U*U*U*U', '_J9..XXXXvlzQGqpPPdk'), - ('*U*U*U*U*', '_J9..XXXXsqM/YSSP..Y'), - ('*U*U*U*U*U*U*U*U', '_J9..XXXXVL7qJCnku0I'), - ('*U*U*U*U*U*U*U*U*', '_J9..XXXXAj8cFbP5scI'), - ('ab1234567', '_J9..SDizh.vll5VED9g'), - ('cr1234567', '_J9..SDizRjWQ/zePPHc'), - ('zxyDPWgydbQjgq', '_J9..SDizxmRI1GjnQuE'), - ('726 even', '_K9..SaltNrQgIYUAeoY'), - ('', '_J9..SDSD5YGyRCr4W4c'), - - # - # custom - # - (" ", "_K1..crsmZxOLzfJH8iw"), - ("my", '_KR/.crsmykRplHbAvwA'), # <-- to detect old 12-bit rounds bug - ("my socra", "_K1..crsmf/9NzZr1fLM"), - ("my socrates", '_K1..crsmOv1rbde9A9o'), - ("my socrates note", "_K1..crsm/2qeAhdISMA"), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '_7C/.ABw0WIKy0ILVqo2'), - ] - known_unidentified_hashes = [ - # bad char in otherwise correctly formatted hash - # \/ - "_K1.!crsmZxOLzfJH8iw" - ] - - platform_crypt_support = [ - # openbsd 5.8 dropped everything except bcrypt - ("openbsd[6789]", False), - ("openbsd5", None), - ("openbsd", True), - - ("freebsd|netbsd|darwin", True), - ("solaris", False), - ("linux", None), # may be present if libxcrypt is in use - ] - - def test_77_fuzz_input(self, **kwds): - # we want to generate even rounds to verify it's correct, but want to ignore warnings - warnings.filterwarnings("ignore", "bsdi_crypt rounds should be odd.*") - super(_bsdi_crypt_test, self).test_77_fuzz_input(**kwds) - - def test_needs_update_w_even_rounds(self): - """needs_update() should flag even rounds""" - handler = self.handler - even_hash = '_Y/../cG0zkJa6LY6k4c' - odd_hash = '_Z/..TgFg0/ptQtpAgws' - secret = 'test' - - # don't issue warning - self.assertTrue(handler.verify(secret, even_hash)) - self.assertTrue(handler.verify(secret, odd_hash)) - - # *do* signal as needing updates - self.assertTrue(handler.needs_update(even_hash)) - self.assertFalse(handler.needs_update(odd_hash)) - - # new hashes shouldn't have even rounds - new_hash = handler.hash("stub") - self.assertFalse(handler.needs_update(new_hash)) - -# create test cases for specific backends -bsdi_crypt_os_crypt_test = _bsdi_crypt_test.create_backend_case("os_crypt") -bsdi_crypt_builtin_test = _bsdi_crypt_test.create_backend_case("builtin") - -#============================================================================= -# crypt16 -#============================================================================= -class crypt16_test(HandlerCase): - handler = hash.crypt16 - - # TODO: find an authortative source of test vectors - known_correct_hashes = [ - # - # from messages around the web, including - # http://seclists.org/bugtraq/1999/Mar/76 - # - ("passphrase", "qi8H8R7OM4xMUNMPuRAZxlY."), - ("printf", "aaCjFz4Sh8Eg2QSqAReePlq6"), - ("printf", "AA/xje2RyeiSU0iBY3PDwjYo"), - ("LOLOAQICI82QB4IP", "/.FcK3mad6JwYt8LVmDqz9Lc"), - ("LOLOAQICI", "/.FcK3mad6JwYSaRHJoTPzY2"), - ("LOLOAQIC", "/.FcK3mad6JwYelhbtlysKy6"), - ("L", "/.CIu/PzYCkl6elhbtlysKy6"), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, 'YeDc9tKkkmDvwP7buzpwhoqQ'), - ] - -#============================================================================= -# des crypt -#============================================================================= -class _des_crypt_test(HandlerCase): - """test des-crypt algorithm""" - handler = hash.des_crypt - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', 'CCNf8Sbh3HDfQ'), - ('U*U***U', 'CCX.K.MFy4Ois'), - ('U*U***U*', 'CC4rMpbg9AMZ.'), - ('*U*U*U*U', 'XXxzOu6maQKqQ'), - ('', 'SDbsugeBiC58A'), - - # - # custom - # - ('', 'OgAwTx2l6NADI'), - (' ', '/Hk.VPuwQTXbc'), - ('test', 'N1tQbOFcM5fpg'), - ('Compl3X AlphaNu3meric', 'um.Wguz3eVCx2'), - ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', 'sNYqfOyauIyic'), - ('AlOtBsOl', 'cEpWz5IUCShqM'), - - # ensures utf-8 used for unicode - (u('hell\u00D6'), 'saykDgk3BPZ9E'), - ] - known_unidentified_hashes = [ - # bad char in otherwise correctly formatted hash - #\/ - '!gAwTx2l6NADI', - - # wrong size - 'OgAwTx2l6NAD', - 'OgAwTx2l6NADIj', - ] - - platform_crypt_support = [ - # openbsd 5.8 dropped everything except bcrypt - ("openbsd[6789]", False), - ("openbsd5", None), - ("openbsd", True), - - ("freebsd|netbsd|linux|solaris|darwin", True), - ] - -# create test cases for specific backends -des_crypt_os_crypt_test = _des_crypt_test.create_backend_case("os_crypt") -des_crypt_builtin_test = _des_crypt_test.create_backend_case("builtin") - -#============================================================================= -# fshp -#============================================================================= -class fshp_test(HandlerCase): - """test fshp algorithm""" - handler = hash.fshp - - known_correct_hashes = [ - # - # test vectors from FSHP reference implementation - # https://github.com/bdd/fshp-is-not-secure-anymore/blob/master/python/test.py - # - ('test', '{FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M='), - - ('test', - '{FSHP1|8|4096}MTIzNDU2NzjTdHcmoXwNc0f' - 'f9+ArUHoN0CvlbPZpxFi1C6RDM/MHSA==' - ), - - ('OrpheanBeholderScryDoubt', - '{FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhz' - 'GLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g==' - ), - ('ExecuteOrder66', - '{FSHP3|16|8192}0aY7rZQ+/PR+Rd5/I9ss' - 'RM7cjguyT8ibypNaSp/U1uziNO3BVlg5qPU' - 'ng+zHUDQC3ao/JbzOnIBUtAeWHEy7a2vZeZ' - '7jAwyJJa2EqOsq4Io=' - ), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, '{FSHP1|16|16384}9v6/l3Lu/d9by5nznpOS' - 'cqQo8eKu/b/CKli3RCkgYg4nRTgZu5y659YV8cCZ68UL'), - ] - - known_unidentified_hashes = [ - # incorrect header - '{FSHX0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=', - 'FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=', - ] - - known_malformed_hashes = [ - # bad base64 padding - '{FSHP0|0|1}qUqP5cyxm6YcTAhz05Hph5gvu9M', - - # wrong salt size - '{FSHP0|1|1}qUqP5cyxm6YcTAhz05Hph5gvu9M=', - - # bad rounds - '{FSHP0|0|A}qUqP5cyxm6YcTAhz05Hph5gvu9M=', - ] - - def test_90_variant(self): - """test variant keyword""" - handler = self.handler - kwds = dict(salt=b'a', rounds=1) - - # accepts ints - handler(variant=1, **kwds) - - # accepts bytes or unicode - handler(variant=u('1'), **kwds) - handler(variant=b'1', **kwds) - - # aliases - handler(variant=u('sha256'), **kwds) - handler(variant=b'sha256', **kwds) - - # rejects None - self.assertRaises(TypeError, handler, variant=None, **kwds) - - # rejects other types - self.assertRaises(TypeError, handler, variant=complex(1,1), **kwds) - - # invalid variant - self.assertRaises(ValueError, handler, variant='9', **kwds) - self.assertRaises(ValueError, handler, variant=9, **kwds) - -#============================================================================= -# hex digests -#============================================================================= -class hex_md4_test(HandlerCase): - handler = hash.hex_md4 - known_correct_hashes = [ - ("password", '8a9d093f14f8701df17732b2bb182c74'), - (UPASS_TABLE, '876078368c47817ce5f9115f3a42cf74'), - ] - -class hex_md5_test(HandlerCase): - handler = hash.hex_md5 - known_correct_hashes = [ - ("password", '5f4dcc3b5aa765d61d8327deb882cf99'), - (UPASS_TABLE, '05473f8a19f66815e737b33264a0d0b0'), - ] - - # XXX: should test this for ALL the create_hex_md5() hashers. - def test_mock_fips_mode(self): - """ - if md5 isn't available, a dummy instance should be created. - (helps on FIPS systems). - """ - from passlib.exc import UnknownHashError - from passlib.crypto.digest import lookup_hash, _set_mock_fips_mode - - # check if md5 is available so we can test mock helper - supported = lookup_hash("md5", required=False).supported - self.assertEqual(self.handler.supported, supported) - if supported: - _set_mock_fips_mode() - self.addCleanup(_set_mock_fips_mode, False) - - # HACK: have to recreate hasher, since underlying HashInfo has changed. - # could reload module and re-import, but this should be good enough. - from passlib.handlers.digests import create_hex_hash - hasher = create_hex_hash("md5", required=False) - self.assertFalse(hasher.supported) - - # can identify hashes even if disabled - ref1 = '5f4dcc3b5aa765d61d8327deb882cf99' - ref2 = 'xxx' - self.assertTrue(hasher.identify(ref1)) - self.assertFalse(hasher.identify(ref2)) - - # throw error if try to use it - pat = "'md5' hash disabled for fips" - self.assertRaisesRegex(UnknownHashError, pat, hasher.hash, "password") - self.assertRaisesRegex(UnknownHashError, pat, hasher.verify, "password", ref1) - - -class hex_sha1_test(HandlerCase): - handler = hash.hex_sha1 - known_correct_hashes = [ - ("password", '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'), - (UPASS_TABLE, 'e059b2628e3a3e2de095679de9822c1d1466e0f0'), - ] - -class hex_sha256_test(HandlerCase): - handler = hash.hex_sha256 - known_correct_hashes = [ - ("password", '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8'), - (UPASS_TABLE, '6ed729e19bf24d3d20f564375820819932029df05547116cfc2cc868a27b4493'), - ] - -class hex_sha512_test(HandlerCase): - handler = hash.hex_sha512 - known_correct_hashes = [ - ("password", 'b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c' - '706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cac' - 'bc86'), - (UPASS_TABLE, 'd91bb0a23d66dca07a1781fd63ae6a05f6919ee5fc368049f350c9f' - '293b078a18165d66097cf0d89fdfbeed1ad6e7dba2344e57348cd6d51308c843a06f' - '29caf'), - ] - -#============================================================================= -# htdigest hash -#============================================================================= -class htdigest_test(UserHandlerMixin, HandlerCase): - handler = hash.htdigest - - known_correct_hashes = [ - # secret, user, realm - - # from RFC 2617 - (("Circle Of Life", "Mufasa", "testrealm@host.com"), - '939e7578ed9e3c518a452acee763bce9'), - - # custom - ((UPASS_TABLE, UPASS_USD, UPASS_WAV), - '4dabed2727d583178777fab468dd1f17'), - ] - - known_unidentified_hashes = [ - # bad char \/ - currently rejecting upper hex chars, may change - '939e7578edAe3c518a452acee763bce9', - - # bad char \/ - '939e7578edxe3c518a452acee763bce9', - ] - - def test_80_user(self): - raise self.skipTest("test case doesn't support 'realm' keyword") - - def populate_context(self, secret, kwds): - """insert username into kwds""" - if isinstance(secret, tuple): - secret, user, realm = secret - else: - user, realm = "user", "realm" - kwds.setdefault("user", user) - kwds.setdefault("realm", realm) - return secret - -#============================================================================= -# ldap hashes -#============================================================================= -class ldap_md5_test(HandlerCase): - handler = hash.ldap_md5 - known_correct_hashes = [ - ("helloworld", '{MD5}/F4DjTilcDIIVEHn/nAQsA=='), - (UPASS_TABLE, '{MD5}BUc/ihn2aBXnN7MyZKDQsA=='), - ] - -class ldap_sha1_test(HandlerCase): - handler = hash.ldap_sha1 - known_correct_hashes = [ - ("helloworld", '{SHA}at+xg6SiyUovktq1redipHiJpaE='), - (UPASS_TABLE, '{SHA}4FmyYo46Pi3glWed6YIsHRRm4PA='), - ] - -class ldap_salted_md5_test(HandlerCase): - handler = hash.ldap_salted_md5 - known_correct_hashes = [ - ("testing1234", '{SMD5}UjFY34os/pnZQ3oQOzjqGu4yeXE='), - (UPASS_TABLE, '{SMD5}Z0ioJ58LlzUeRxm3K6JPGAvBGIM='), - - # alternate salt sizes (8, 15, 16) - ('test', '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw'), - ('test', '{SMD5}XRlncfRzvGi0FDzgR98tUgBg7B3jXOs9p9S615qTkg=='), - ('test', '{SMD5}FbAkzOMOxRbMp6Nn4hnZuel9j9Gas7a2lvI+x5hT6j0='), - ] - - known_malformed_hashes = [ - # salt too small (3) - '{SMD5}IGVhwK+anvspmfDt2t0vgGjt/Q==', - - # incorrect base64 encoding - '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4c', - '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw' - '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P4cw=', - '{SMD5}LnuZPJhiaY95/4lmV=pg548xBsD4P4cw', - '{SMD5}LnuZPJhiaY95/4lmVFpg548xBsD4P===', - ] - -class ldap_salted_sha1_test(HandlerCase): - handler = hash.ldap_salted_sha1 - known_correct_hashes = [ - ("testing123", '{SSHA}0c0blFTXXNuAMHECS4uxrj3ZieMoWImr'), - ("secret", "{SSHA}0H+zTv8o4MR4H43n03eCsvw1luG8LdB7"), - (UPASS_TABLE, '{SSHA}3yCSD1nLZXznra4N8XzZgAL+s1sQYsx5'), - - # alternate salt sizes (8, 15, 16) - ('test', '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOckw=='), - ('test', '{SSHA}/ZMF5KymNM+uEOjW+9STKlfCFj51bg3BmBNCiPHeW2ttbU0='), - ('test', '{SSHA}Pfx6Vf48AT9x3FVv8znbo8WQkEVSipHSWovxXmvNWUvp/d/7'), - ] - - known_malformed_hashes = [ - # salt too small (3) - '{SSHA}ZQK3Yvtvl6wtIRoISgMGPkcWU7Nfq5U=', - - # incorrect base64 encoding - '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOck', - '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOckw=', - '{SSHA}P90+qijSp8MJ1tN25j5o1Pf=UvlqjXHOGeOckw==', - '{SSHA}P90+qijSp8MJ1tN25j5o1PflUvlqjXHOGeOck===', - ] - - -class ldap_salted_sha256_test(HandlerCase): - handler = hash.ldap_salted_sha256 - known_correct_hashes = [ - # generated locally - # salt size = 8 - ("password", '{SSHA256}x1tymSTVjozxQ2PtT46ysrzhZxbcskK0o2f8hEFx7fAQQmhtDSEkJA=='), - ("test", '{SSHA256}xfqc9aOR6z15YaEk3/Ufd7UL9+JozB/1EPmCDTizL0GkdA7BuNda6w=='), - ("toomanysecrets", '{SSHA256}RrTKrg6HFXcjJ+eDAq4UtbODxOr9RLeG+I69FoJvutcbY0zpfU+p1Q=='), - (u('letm\xe8\xefn'), '{SSHA256}km7UjUTBZN8a+gf1ND2/qn15N7LsO/jmGYJXvyTfJKAbI0RoLWWslQ=='), - - # alternate salt sizes (4, 15, 16) - # generated locally - ('test', '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDIm'), - ('test', '{SSHA256}J6MFQdkfjdmXz9UyUPb773kekJdm4dgSL4y8WQEQW11VipHSundOKaV0LsV4L6U='), - ('test', '{SSHA256}uBLazLaiBaPb6Cpnvq2XTYDkvXbYIuqRW1anMKk85d1/j1GqFQIgpHSOMUYIIcS4'), - ] - - known_malformed_hashes = [ - # salt too small (3) - '{SSHA256}Lpdyr1+lR+rtxgp3SpQnUuNw33ENivTl28nzF2ZI4Gm41/o=', - - # incorrect base64 encoding - '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDI@', - '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDI', - '{SSHA256}TFv2RpwyO0U9mA0Hk8FsXRa1I+4dNUtv27Qa8dzGVLinlDIm===', - ] - - - -class ldap_salted_sha512_test(HandlerCase): - handler = hash.ldap_salted_sha512 - known_correct_hashes = [ - # generated by testing ldap server web interface (see issue 124 comments) - # salt size = 8 - ("toomanysecrets", '{SSHA512}wExp4xjiCHS0zidJDC4UJq9EEeIebAQPJ1PWSwfhxWjfutI9XiiKuHm2AE41cEFfK+8HyI8bh+ztbczUGsvVFIgICWWPt7qu'), - (u('letm\xe8\xefn'), '{SSHA512}mpNUSmZc3TNx+RnPwkIAVMf7ocEKLPrIoQNsg4Eu8dHvyCeb2xzHp5A6n4tF7ntknSvfvRZaJII4ImvNJlYsgiwAm0FMqR+3'), - - # generated locally - # salt size = 8 - ("password", '{SSHA512}f/lFQskkl7PdMsTGJxHZq8LDt/l+UqRMm6/pj4pV7/xZkcOaKCgvQqp+KCeXc/Vd4RY6vEHWn4y0DnFcQ6wgyv9fyxk='), - ("test", '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+Uc'), - - # alternate salt sizes (4, 15, 16) - # generated locally - ('test', '{SSHA512}Yg9DQ2wURCFGwobu7R2O6cq7nVbnGMPrFCX0aPQ9kj/y1hd6k9PEzkgWCB5aXdPwPzNrVb0PkiHiBnG1CxFiT+B8L8U='), - ('test', '{SSHA512}5ecDGWs5RY4xLszUO6hAcl90W3wAozGQoI4Gqj8xSZdcfU1lVEM4aY8s+4xVeLitcn7BO8i7xkzMFWLoxas7SeHc23sP4dx77937PyeE0A=='), - ('test', '{SSHA512}6FQv5W47HGg2MFBFZofoiIbO8KRW75Pm51NKoInpthYQQ5ujazHGhVGzrj3JXgA7j0k+UNmkHdbJjdY5xcUHPzynFEII4fwfIySEcG5NKSU='), - ] - - known_malformed_hashes = [ - # salt too small (3) - '{SSHA512}zFnn4/8x8GveUaMqgrYWyIWqFQ0Irt6gADPtRk4Uv3nUC6uR5cD8+YdQni/0ZNij9etm6p17kSFuww3M6l+d6AbAeA==', - - # incorrect base64 encoding - '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U', - '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U@', - '{SSHA512}Tgx/uhHnlM9/GgQvI31dN7cheDXg7WypZwaaIkyRsgV/BKIzBG3G/wUd9o1dpi06p3SYzMedg0lvTc3b6CtdO0Xo/f9/L+U===', - ] - - -class ldap_plaintext_test(HandlerCase): - # TODO: integrate EncodingHandlerMixin - handler = hash.ldap_plaintext - known_correct_hashes = [ - ("password", 'password'), - (UPASS_TABLE, UPASS_TABLE if PY3 else PASS_TABLE_UTF8), - (PASS_TABLE_UTF8, UPASS_TABLE if PY3 else PASS_TABLE_UTF8), - ] - known_unidentified_hashes = [ - "{FOO}bar", - - # NOTE: this hash currently rejects the empty string. - "", - ] - - known_other_hashes = [ - ("ldap_md5", "{MD5}/F4DjTilcDIIVEHn/nAQsA==") - ] - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_password(self): - # NOTE: this hash currently rejects the empty string. - while True: - pwd = super(ldap_plaintext_test.FuzzHashGenerator, self).random_password() - if pwd: - return pwd - -class _ldap_md5_crypt_test(HandlerCase): - # NOTE: since the ldap_{crypt} handlers are all wrappers, don't need - # separate test; this is just to test the codebase end-to-end - handler = hash.ldap_md5_crypt - - known_correct_hashes = [ - # - # custom - # - ('', '{CRYPT}$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.'), - (' ', '{CRYPT}$1$m/5ee7ol$bZn0kIBFipq39e.KDXX8I0'), - ('test', '{CRYPT}$1$ec6XvcoW$ghEtNK2U1MC5l.Dwgi3020'), - ('Compl3X AlphaNu3meric', '{CRYPT}$1$nX1e7EeI$ljQn72ZUgt6Wxd9hfvHdV0'), - ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '{CRYPT}$1$jQS7o98J$V6iTcr71CGgwW2laf17pi1'), - ('test', '{CRYPT}$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '{CRYPT}$1$d6/Ky1lU$/xpf8m7ftmWLF.TjHCqel0'), - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash - '{CRYPT}$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o!', - ] - -# create test cases for specific backends -ldap_md5_crypt_os_crypt_test =_ldap_md5_crypt_test.create_backend_case("os_crypt") -ldap_md5_crypt_builtin_test =_ldap_md5_crypt_test.create_backend_case("builtin") - -class _ldap_sha1_crypt_test(HandlerCase): - # NOTE: this isn't for testing the hash (see ldap_md5_crypt note) - # but as a self-test of the os_crypt patching code in HandlerCase. - handler = hash.ldap_sha1_crypt - - known_correct_hashes = [ - ('password', '{CRYPT}$sha1$10$c.mcTzCw$gF8UeYst9yXX7WNZKc5Fjkq0.au7'), - (UPASS_TABLE, '{CRYPT}$sha1$10$rnqXlOsF$aGJf.cdRPewJAXo1Rn1BkbaYh0fP'), - ] - - def populate_settings(self, kwds): - kwds.setdefault("rounds", 10) - super(_ldap_sha1_crypt_test, self).populate_settings(kwds) - - def test_77_fuzz_input(self, **ignored): - raise self.skipTest("unneeded") - -# create test cases for specific backends -ldap_sha1_crypt_os_crypt_test = _ldap_sha1_crypt_test.create_backend_case("os_crypt") - -#============================================================================= -# lanman -#============================================================================= -class lmhash_test(EncodingHandlerMixin, HandlerCase): - handler = hash.lmhash - secret_case_insensitive = True - - known_correct_hashes = [ - # - # http://msdn.microsoft.com/en-us/library/cc245828(v=prot.10).aspx - # - ("OLDPASSWORD", "c9b81d939d6fd80cd408e6b105741864"), - ("NEWPASSWORD", '09eeab5aa415d6e4d408e6b105741864'), - ("welcome", "c23413a8a1e7665faad3b435b51404ee"), - - # - # custom - # - ('', 'aad3b435b51404eeaad3b435b51404ee'), - ('zzZZZzz', 'a5e6066de61c3e35aad3b435b51404ee'), - ('passphrase', '855c3697d9979e78ac404c4ba2c66533'), - ('Yokohama', '5ecd9236d21095ce7584248b8d2c9f9e'), - - # ensures cp437 used for unicode - (u('ENCYCLOP\xC6DIA'), 'fed6416bffc9750d48462b9d7aaac065'), - (u('encyclop\xE6dia'), 'fed6416bffc9750d48462b9d7aaac065'), - - # test various encoding values - ((u("\xC6"), None), '25d8ab4a0659c97aaad3b435b51404ee'), - ((u("\xC6"), "cp437"), '25d8ab4a0659c97aaad3b435b51404ee'), - ((u("\xC6"), "latin-1"), '184eecbbe9991b44aad3b435b51404ee'), - ((u("\xC6"), "utf-8"), '00dd240fcfab20b8aad3b435b51404ee'), - ] - - known_unidentified_hashes = [ - # bad char in otherwise correct hash - '855c3697d9979e78ac404c4ba2c6653X', - ] - - def test_90_raw(self): - """test lmhash.raw() method""" - from binascii import unhexlify - from passlib.utils.compat import str_to_bascii - lmhash = self.handler - for secret, hash in self.known_correct_hashes: - kwds = {} - secret = self.populate_context(secret, kwds) - data = unhexlify(str_to_bascii(hash)) - self.assertEqual(lmhash.raw(secret, **kwds), data) - self.assertRaises(TypeError, lmhash.raw, 1) - -#============================================================================= -# md5 crypt -#============================================================================= -class _md5_crypt_test(HandlerCase): - handler = hash.md5_crypt - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', '$1$dXc3I7Rw$ctlgjDdWJLMT.qwHsWhXR1'), - ('U*U***U', '$1$dXc3I7Rw$94JPyQc/eAgQ3MFMCoMF.0'), - ('U*U***U*', '$1$dXc3I7Rw$is1mVIAEtAhIzSdfn5JOO0'), - ('*U*U*U*U', '$1$eQT9Hwbt$XtuElNJD.eW5MN5UCWyTQ0'), - ('', '$1$Eu.GHtia$CFkL/nE1BYTlEPiVx1VWX0'), - - # - # custom - # - - # NOTE: would need to patch HandlerCase to coerce hashes - # to native str for this first one to work under py3. -## ('', b('$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.')), - ('', '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.'), - (' ', '$1$m/5ee7ol$bZn0kIBFipq39e.KDXX8I0'), - ('test', '$1$ec6XvcoW$ghEtNK2U1MC5l.Dwgi3020'), - ('Compl3X AlphaNu3meric', '$1$nX1e7EeI$ljQn72ZUgt6Wxd9hfvHdV0'), - ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$1$jQS7o98J$V6iTcr71CGgwW2laf17pi1'), - ('test', '$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'), - (b'test', '$1$SuMrG47N$ymvzYjr7QcEQjaK5m1PGx1'), - (u('s'), '$1$ssssssss$YgmLTApYTv12qgTwBoj8i/'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '$1$d6/Ky1lU$/xpf8m7ftmWLF.TjHCqel0'), - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash \/ - '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o!', - - # too many fields - '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.$', - ] - - platform_crypt_support = [ - # openbsd 5.8 dropped everything except bcrypt - ("openbsd[6789]", False), - ("openbsd5", None), - ("openbsd", True), - - ("freebsd|netbsd|linux|solaris", True), - ("darwin", False), - ] - -# create test cases for specific backends -md5_crypt_os_crypt_test = _md5_crypt_test.create_backend_case("os_crypt") -md5_crypt_builtin_test = _md5_crypt_test.create_backend_case("builtin") - -#============================================================================= -# msdcc 1 & 2 -#============================================================================= -class msdcc_test(UserHandlerMixin, HandlerCase): - handler = hash.msdcc - user_case_insensitive = True - - known_correct_hashes = [ - - # - # http://www.jedge.com/wordpress/windows-password-cache/ - # - (("Asdf999", "sevans"), "b1176c2587478785ec1037e5abc916d0"), - - # - # http://infosecisland.com/blogview/12156-Cachedump-for-Meterpreter-in-Action.html - # - (("ASDqwe123", "jdoe"), "592cdfbc3f1ef77ae95c75f851e37166"), - - # - # http://comments.gmane.org/gmane.comp.security.openwall.john.user/1917 - # - (("test1", "test1"), "64cd29e36a8431a2b111378564a10631"), - (("test2", "test2"), "ab60bdb4493822b175486810ac2abe63"), - (("test3", "test3"), "14dd041848e12fc48c0aa7a416a4a00c"), - (("test4", "test4"), "b945d24866af4b01a6d89b9d932a153c"), - - # - # http://ciscoit.wordpress.com/2011/04/13/metasploit-hashdump-vs-cachedump/ - # - (("1234qwer!@#$", "Administrator"), "7b69d06ef494621e3f47b9802fe7776d"), - - # - # http://www.securiteam.com/tools/5JP0I2KFPA.html - # - (("password", "user"), "2d9f0b052932ad18b87f315641921cda"), - - # - # from JTR 1.7.9 - # - (("", "root"), "176a4c2bd45ac73687676c2f09045353"), - (("test1", "TEST1"), "64cd29e36a8431a2b111378564a10631"), - (("okolada", "nineteen_characters"), "290efa10307e36a79b3eebf2a6b29455"), - ((u("\u00FC"), u("\u00FC")), "48f84e6f73d6d5305f6558a33fa2c9bb"), - ((u("\u00FC\u00FC"), u("\u00FC\u00FC")), "593246a8335cf0261799bda2a2a9c623"), - ((u("\u20AC\u20AC"), "user"), "9121790702dda0fa5d353014c334c2ce"), - - # - # custom - # - - # ensures utf-8 used for unicode - ((UPASS_TABLE, 'bob'), 'fcb82eb4212865c7ac3503156ca3f349'), - ] - - known_alternate_hashes = [ - # check uppercase accepted. - ("B1176C2587478785EC1037E5ABC916D0", ("Asdf999", "sevans"), - "b1176c2587478785ec1037e5abc916d0"), - ] - -class msdcc2_test(UserHandlerMixin, HandlerCase): - handler = hash.msdcc2 - user_case_insensitive = True - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - (("test1", "test1"), "607bbe89611e37446e736f7856515bf8"), - (("qerwt", "Joe"), "e09b38f84ab0be586b730baf61781e30"), - (("12345", "Joe"), "6432f517a900b3fc34ffe57f0f346e16"), - (("", "bin"), "c0cbe0313a861062e29f92ede58f9b36"), - (("w00t", "nineteen_characters"), "87136ae0a18b2dafe4a41d555425b2ed"), - (("w00t", "eighteencharacters"), "fc5df74eca97afd7cd5abb0032496223"), - (("longpassword", "twentyXXX_characters"), "cfc6a1e33eb36c3d4f84e4c2606623d2"), - (("longpassword", "twentyoneX_characters"), "99ff74cea552799da8769d30b2684bee"), - (("longpassword", "twentytwoXX_characters"), "0a721bdc92f27d7fb23b87a445ec562f"), - (("test2", "TEST2"), "c6758e5be7fc943d00b97972a8a97620"), - (("test3", "test3"), "360e51304a2d383ea33467ab0b639cc4"), - (("test4", "test4"), "6f79ee93518306f071c47185998566ae"), - ((u("\u00FC"), "joe"), "bdb80f2c4656a8b8591bd27d39064a54"), - ((u("\u20AC\u20AC"), "joe"), "1e1e20f482ff748038e47d801d0d1bda"), - ((u("\u00FC\u00FC"), "admin"), "0839e4a07c00f18a8c65cf5b985b9e73"), - - # - # custom - # - - # custom unicode test - ((UPASS_TABLE, 'bob'), 'cad511dc9edefcf69201da72efb6bb55'), - ] - -#============================================================================= -# mssql 2000 & 2005 -#============================================================================= -class mssql2000_test(HandlerCase): - handler = hash.mssql2000 - secret_case_insensitive = "verify-only" - # FIXME: fix UT framework - this hash is sensitive to password case, but verify() is not - - known_correct_hashes = [ - # - # http://hkashfi.blogspot.com/2007/08/breaking-sql-server-2005-hashes.html - # - ('Test', '0x010034767D5C0CFA5FDCA28C4A56085E65E882E71CB0ED2503412FD54D6119FFF04129A1D72E7C3194F7284A7F3A'), - ('TEST', '0x010034767D5C2FD54D6119FFF04129A1D72E7C3194F7284A7F3A2FD54D6119FFF04129A1D72E7C3194F7284A7F3A'), - - # - # http://www.sqlmag.com/forums/aft/68438 - # - ('x', '0x010086489146C46DD7318D2514D1AC706457CBF6CD3DF8407F071DB4BBC213939D484BF7A766E974F03C96524794'), - - # - # http://stackoverflow.com/questions/173329/how-to-decrypt-a-password-from-sql-server - # - ('AAAA', '0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D12625EF019E157120D58DD46569AC7BF4118455D'), - - # - # http://msmvps.com/blogs/gladchenko/archive/2005/04/06/41083.aspx - # - ('123', '0x01002D60BA07FE612C8DE537DF3BFCFA49CD9968324481C1A8A8FE612C8DE537DF3BFCFA49CD9968324481C1A8A8'), - - # - # http://www.simple-talk.com/sql/t-sql-programming/temporarily-changing-an-unknown-password-of-the-sa-account-/ - # - ('12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'), - - # - # XXX: sample is incomplete, password unknown - # https://anthonystechblog.wordpress.com/2011/04/20/password-encryption-in-sql-server-how-to-tell-if-a-user-is-using-a-weak-password/ - # (????, '0x0100813F782D66EF15E40B1A3FDF7AB88B322F51401A87D8D3E3A8483C4351A3D96FC38499E6CDD2B6F?????????'), - # - - # - # from JTR 1.7.9 - # - ('foo', '0x0100A607BA7C54A24D17B565C59F1743776A10250F581D482DA8B6D6261460D3F53B279CC6913CE747006A2E3254'), - ('bar', '0x01000508513EADDF6DB7DDD270CCA288BF097F2FF69CC2DB74FBB9644D6901764F999BAB9ECB80DE578D92E3F80D'), - ('canard', '0x01008408C523CF06DCB237835D701C165E68F9460580132E28ED8BC558D22CEDF8801F4503468A80F9C52A12C0A3'), - ('lapin', '0x0100BF088517935FC9183FE39FDEC77539FD5CB52BA5F5761881E5B9638641A79DBF0F1501647EC941F3355440A2'), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_USD, '0x0100624C0961B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5'), - (UPASS_TABLE, '0x010083104228FAD559BE52477F2131E538BE9734E5C4B0ADEFD7F6D784B03C98585DC634FE2B8CA3A6DFFEC729B4'), - - ] - - known_alternate_hashes = [ - # lower case hex - ('0x01005b20054332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b3', - '12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'), - ] - - known_unidentified_hashes = [ - # malformed start - '0X01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3', - - # wrong magic value - '0x02005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3', - - # wrong size - '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3', - '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3AF', - - # mssql2005 - '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3', - ] - - known_malformed_hashes = [ - # non-hex char -----\/ - b'0x01005B200543327G2E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3', - u('0x01005B200543327G2E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'), - ] - -class mssql2005_test(HandlerCase): - handler = hash.mssql2005 - - known_correct_hashes = [ - # - # http://hkashfi.blogspot.com/2007/08/breaking-sql-server-2005-hashes.html - # - ('TEST', '0x010034767D5C2FD54D6119FFF04129A1D72E7C3194F7284A7F3A'), - - # - # http://www.openwall.com/lists/john-users/2009/07/14/2 - # - ('toto', '0x01004086CEB6BF932BC4151A1AF1F13CD17301D70816A8886908'), - - # - # http://msmvps.com/blogs/gladchenko/archive/2005/04/06/41083.aspx - # - ('123', '0x01004A335DCEDB366D99F564D460B1965B146D6184E4E1025195'), - ('123', '0x0100E11D573F359629B344990DCD3D53DE82CF8AD6BBA7B638B6'), - - # - # XXX: password unknown - # http://www.simple-talk.com/sql/t-sql-programming/temporarily-changing-an-unknown-password-of-the-sa-account-/ - # (???, '0x01004086CEB6301EEC0A994E49E30DA235880057410264030797'), - # - - # - # http://therelentlessfrontend.com/2010/03/26/encrypting-and-decrypting-passwords-in-sql-server/ - # - ('AAAA', '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30'), - - # - # from JTR 1.7.9 - # - ("toto", "0x01004086CEB6BF932BC4151A1AF1F13CD17301D70816A8886908"), - ("titi", "0x01004086CEB60ED526885801C23B366965586A43D3DEAC6DD3FD"), - ("foo", "0x0100A607BA7C54A24D17B565C59F1743776A10250F581D482DA8"), - ("bar", "0x01000508513EADDF6DB7DDD270CCA288BF097F2FF69CC2DB74FB"), - ("canard", "0x01008408C523CF06DCB237835D701C165E68F9460580132E28ED"), - ("lapin", "0x0100BF088517935FC9183FE39FDEC77539FD5CB52BA5F5761881"), - - # - # adapted from mssql2000.known_correct_hashes (above) - # - ('Test', '0x010034767D5C0CFA5FDCA28C4A56085E65E882E71CB0ED250341'), - ('Test', '0x0100993BF2315F36CC441485B35C4D84687DC02C78B0E680411F'), - ('x', '0x010086489146C46DD7318D2514D1AC706457CBF6CD3DF8407F07'), - ('AAAA', '0x0100CF465B7B12625EF019E157120D58DD46569AC7BF4118455D'), - ('123', '0x01002D60BA07FE612C8DE537DF3BFCFA49CD9968324481C1A8A8'), - ('12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_USD, '0x0100624C0961B28E39FEE13FD0C35F57B4523F0DA1861C11D5A5'), - (UPASS_TABLE, '0x010083104228FAD559BE52477F2131E538BE9734E5C4B0ADEFD7'), - ] - - known_alternate_hashes = [ - # lower case hex - ('0x01005b20054332752e1bc2e7c5df0f9ebfe486e9bee063e8d3b3', - '12345', '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3'), - ] - - known_unidentified_hashes = [ - # malformed start - '0X010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30', - - # wrong magic value - '0x020036D726AE86834E97F20B198ACD219D60B446AC5E48C54F30', - - # wrong size - '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F', - '0x010036D726AE86834E97F20B198ACD219D60B446AC5E48C54F3012', - - # mssql2000 - '0x01005B20054332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B332752E1BC2E7C5DF0F9EBFE486E9BEE063E8D3B3', - ] - - known_malformed_hashes = [ - # non-hex char --\/ - '0x010036D726AE86G34E97F20B198ACD219D60B446AC5E48C54F30', - ] - -#============================================================================= -# mysql 323 & 41 -#============================================================================= -class mysql323_test(HandlerCase): - handler = hash.mysql323 - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('drew', '697a7de87c5390b2'), - ('password', "5d2e19393cc5ef67"), - - # - # custom - # - ('mypass', '6f8c114b58f2ce9e'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '4ef327ca5491c8d7'), - ] - - known_unidentified_hashes = [ - # bad char in otherwise correct hash - '6z8c114b58f2ce9e', - ] - - def test_90_whitespace(self): - """check whitespace is ignored per spec""" - h = self.do_encrypt("mypass") - h2 = self.do_encrypt("my pass") - self.assertEqual(h, h2) - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def accept_password_pair(self, secret, other): - # override to handle whitespace - return secret.replace(" ","") != other.replace(" ","") - -class mysql41_test(HandlerCase): - handler = hash.mysql41 - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('verysecretpassword', '*2C905879F74F28F8570989947D06A8429FB943E6'), - ('12345678123456781234567812345678', '*F9F1470004E888963FB466A5452C9CBD9DF6239C'), - ("' OR 1 /*'", '*97CF7A3ACBE0CA58D5391AC8377B5D9AC11D46D9'), - - # - # custom - # - ('mypass', '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '*E7AFE21A9CFA2FC9D15D942AE8FB5C240FE5837B'), - ] - known_unidentified_hashes = [ - # bad char in otherwise correct hash - '*6Z8989366EAF75BB670AD8EA7A7FC1176A95CEF4', - ] - -#============================================================================= -# NTHASH -#============================================================================= -class nthash_test(HandlerCase): - handler = hash.nthash - - known_correct_hashes = [ - # - # http://msdn.microsoft.com/en-us/library/cc245828(v=prot.10).aspx - # - ("OLDPASSWORD", u("6677b2c394311355b54f25eec5bfacf5")), - ("NEWPASSWORD", u("256781a62031289d3c2c98c14f1efc8c")), - - # - # from JTR 1.7.9 - # - - # ascii - ('', '31d6cfe0d16ae931b73c59d7e0c089c0'), - ('tigger', 'b7e0ea9fbffcf6dd83086e905089effd'), - - # utf-8 - (b'\xC3\xBC', '8bd6e4fb88e01009818749c5443ea712'), - (b'\xC3\xBC\xC3\xBC', 'cc1260adb6985ca749f150c7e0b22063'), - (b'\xE2\x82\xAC', '030926b781938db4365d46adc7cfbcb8'), - (b'\xE2\x82\xAC\xE2\x82\xAC','682467b963bb4e61943e170a04f7db46'), - - # - # custom - # - ('passphrase', '7f8fe03093cc84b267b109625f6bbf4b'), - ] - - known_unidentified_hashes = [ - # bad char in otherwise correct hash - '7f8fe03093cc84b267b109625f6bbfxb', - ] - -class bsd_nthash_test(HandlerCase): - handler = hash.bsd_nthash - - known_correct_hashes = [ - ('passphrase', '$3$$7f8fe03093cc84b267b109625f6bbf4b'), - (b'\xC3\xBC', '$3$$8bd6e4fb88e01009818749c5443ea712'), - ] - - known_unidentified_hashes = [ - # bad char in otherwise correct hash --\/ - '$3$$7f8fe03093cc84b267b109625f6bbfxb', - ] - -#============================================================================= -# oracle 10 & 11 -#============================================================================= -class oracle10_test(UserHandlerMixin, HandlerCase): - handler = hash.oracle10 - secret_case_insensitive = True - user_case_insensitive = True - - # TODO: get more test vectors (especially ones which properly test unicode) - known_correct_hashes = [ - # ((secret,user),hash) - - # - # http://www.petefinnigan.com/default/default_password_list.htm - # - (('tiger', 'scott'), 'F894844C34402B67'), - ((u('ttTiGGeR'), u('ScO')), '7AA1A84E31ED7771'), - (("d_syspw", "SYSTEM"), '1B9F1F9A5CB9EB31'), - (("strat_passwd", "strat_user"), 'AEBEDBB4EFB5225B'), - - # - # http://openwall.info/wiki/john/sample-hashes - # - (('#95LWEIGHTS', 'USER'), '000EA4D72A142E29'), - (('CIAO2010', 'ALFREDO'), 'EB026A76F0650F7B'), - - # - # from JTR 1.7.9 - # - (('GLOUGlou', 'Bob'), 'CDC6B483874B875B'), - (('GLOUGLOUTER', 'bOB'), 'EF1F9139DB2D5279'), - (('LONG_MOT_DE_PASSE_OUI', 'BOB'), 'EC8147ABB3373D53'), - - # - # custom - # - ((UPASS_TABLE, 'System'), 'B915A853F297B281'), - ] - - known_unidentified_hashes = [ - # bad char in hash --\ - 'F894844C34402B6Z', - ] - -class oracle11_test(HandlerCase): - handler = hash.oracle11 - # TODO: find more test vectors (especially ones which properly test unicode) - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ("abc123", "S:5FDAB69F543563582BA57894FE1C1361FB8ED57B903603F2C52ED1B4D642"), - ("SyStEm123!@#", "S:450F957ECBE075D2FA009BA822A9E28709FBC3DA82B44D284DDABEC14C42"), - ("oracle", "S:3437FF72BD69E3FB4D10C750B92B8FB90B155E26227B9AB62D94F54E5951"), - ("11g", "S:61CE616647A4F7980AFD7C7245261AF25E0AFE9C9763FCF0D54DA667D4E6"), - ("11g", "S:B9E7556F53500C8C78A58F50F24439D79962DE68117654B6700CE7CC71CF"), - - # - # source? - # - ("SHAlala", "S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C"), - - # - # custom - # - (UPASS_TABLE, 'S:51586343E429A6DF024B8F242F2E9F8507B1096FACD422E29142AA4974B0'), - ] - -#============================================================================= -# PHPass Portable Crypt -#============================================================================= -class phpass_test(HandlerCase): - handler = hash.phpass - - known_correct_hashes = [ - # - # from official 0.3 implementation - # http://www.openwall.com/phpass/ - # - ('test12345', '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'), # from the source - - # - # from JTR 1.7.9 - # - ('test1', '$H$9aaaaaSXBjgypwqm.JsMssPLiS8YQ00'), - ('123456', '$H$9PE8jEklgZhgLmZl5.HYJAzfGCQtzi1'), - ('123456', '$H$9pdx7dbOW3Nnt32sikrjAxYFjX8XoK1'), - ('thisisalongertestPW', '$P$912345678LIjjb6PhecupozNBmDndU0'), - ('JohnRipper', '$P$612345678si5M0DDyPpmRCmcltU/YW/'), - ('JohnRipper', '$H$712345678WhEyvy1YWzT4647jzeOmo0'), - ('JohnRipper', '$P$B12345678L6Lpt4BxNotVIMILOa9u81'), - - # - # custom - # - ('', '$P$7JaFQsPzJSuenezefD/3jHgt5hVfNH0'), - ('compL3X!', '$P$FiS0N5L672xzQx1rt1vgdJQRYKnQM9/'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '$P$7SMy8VxnfsIy2Sxm7fJxDSdil.h7TW.'), - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash - # ---\/ - '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r!L0', - ] - -#============================================================================= -# plaintext -#============================================================================= -class plaintext_test(HandlerCase): - # TODO: integrate EncodingHandlerMixin - handler = hash.plaintext - accepts_all_hashes = True - - known_correct_hashes = [ - ('',''), - ('password', 'password'), - - # ensure unicode uses utf-8 - (UPASS_TABLE, UPASS_TABLE if PY3 else PASS_TABLE_UTF8), - (PASS_TABLE_UTF8, UPASS_TABLE if PY3 else PASS_TABLE_UTF8), - ] - -#============================================================================= -# postgres_md5 -#============================================================================= -class postgres_md5_test(UserHandlerMixin, HandlerCase): - handler = hash.postgres_md5 - known_correct_hashes = [ - # ((secret,user),hash) - - # - # generated using postgres 8.1 - # - (('mypass', 'postgres'), 'md55fba2ea04fd36069d2574ea71c8efe9d'), - (('mypass', 'root'), 'md540c31989b20437833f697e485811254b'), - (("testpassword",'testuser'), 'md5d4fc5129cc2c25465a5370113ae9835f'), - - # - # custom - # - - # verify unicode->utf8 - ((UPASS_TABLE, 'postgres'), 'md5cb9f11283265811ce076db86d18a22d2'), - ] - known_unidentified_hashes = [ - # bad 'z' char in otherwise correct hash - 'md54zc31989b20437833f697e485811254b', - ] - -#============================================================================= -# (netbsd's) sha1 crypt -#============================================================================= -class _sha1_crypt_test(HandlerCase): - handler = hash.sha1_crypt - - known_correct_hashes = [ - # - # custom - # - ("password", "$sha1$19703$iVdJqfSE$v4qYKl1zqYThwpjJAoKX6UvlHq/a"), - ("password", "$sha1$21773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH"), - (UPASS_TABLE, '$sha1$40000$uJ3Sp7LE$.VEmLO5xntyRFYihC7ggd3297T/D'), - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash - '$sha1$21773$u!7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH', - - # zero padded rounds - '$sha1$01773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH', - - # too many fields - '$sha1$21773$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH$', - - # empty rounds field - '$sha1$$uV7PTeux$I9oHnvwPZHMO0Nq6/WgyGV/tDJIH$', - ] - - platform_crypt_support = [ - ("netbsd", True), - ("freebsd|openbsd|solaris|darwin", False), - ("linux", None), # may be present if libxcrypt is in use - ] - -# create test cases for specific backends -sha1_crypt_os_crypt_test = _sha1_crypt_test.create_backend_case("os_crypt") -sha1_crypt_builtin_test = _sha1_crypt_test.create_backend_case("builtin") - -#============================================================================= -# roundup -#============================================================================= - -# NOTE: all roundup hashes use PrefixWrapper, -# so there's nothing natively to test. -# so we just have a few quick cases... - -class RoundupTest(TestCase): - - def _test_pair(self, h, secret, hash): - self.assertTrue(h.verify(secret, hash)) - self.assertFalse(h.verify('x'+secret, hash)) - - def test_pairs(self): - self._test_pair( - hash.ldap_hex_sha1, - "sekrit", - '{SHA}8d42e738c7adee551324955458b5e2c0b49ee655') - - self._test_pair( - hash.ldap_hex_md5, - "sekrit", - '{MD5}ccbc53f4464604e714f69dd11138d8b5') - - self._test_pair( - hash.ldap_des_crypt, - "sekrit", - '{CRYPT}nFia0rj2TT59A') - - self._test_pair( - hash.roundup_plaintext, - "sekrit", - '{plaintext}sekrit') - - self._test_pair( - hash.ldap_pbkdf2_sha1, - "sekrit", - '{PBKDF2}5000$7BvbBq.EZzz/O0HuwX3iP.nAG3s$g3oPnFFaga2BJaX5PoPRljl4XIE') - -#============================================================================= -# sha256-crypt -#============================================================================= -class _sha256_crypt_test(HandlerCase): - handler = hash.sha256_crypt - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', '$5$LKO/Ute40T3FNF95$U0prpBQd4PloSGU0pnpM4z9wKn4vZ1.jsrzQfPqxph9'), - ('U*U***U', '$5$LKO/Ute40T3FNF95$fdgfoJEBoMajNxCv3Ru9LyQ0xZgv0OBMQoq80LQ/Qd.'), - ('U*U***U*', '$5$LKO/Ute40T3FNF95$8Ry82xGnnPI/6HtFYnvPBTYgOL23sdMXn8C29aO.x/A'), - ('*U*U*U*U', '$5$9mx1HkCz7G1xho50$O7V7YgleJKLUhcfk9pgzdh3RapEaWqMtEp9UUBAKIPA'), - ('', '$5$kc7lRD1fpYg0g.IP$d7CMTcEqJyTXyeq8hTdu/jB/I6DGkoo62NXbHIR7S43'), - - # - # custom tests - # - ('', '$5$rounds=10428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3'), - (' ', '$5$rounds=10376$I5lNtXtRmf.OoMd8$Ko3AI1VvTANdyKhBPavaRjJzNpSatKU6QVN9uwS9MH.'), - ('test', '$5$rounds=11858$WH1ABM5sKhxbkgCK$aTQsjPkz0rBsH3lQlJxw9HDTDXPKBxC0LlVeV69P.t1'), - ('Compl3X AlphaNu3meric', '$5$rounds=10350$o.pwkySLCzwTdmQX$nCMVsnF3TXWcBPOympBUUSQi6LGGloZoOsVJMGJ09UB'), - ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$5$rounds=11944$9dhlu07dQMRWvTId$LyUI5VWkGFwASlzntk1RLurxX54LUhgAcJZIt0pYGT7'), - (u('with unic\u00D6de'), '$5$rounds=1000$IbG0EuGQXw5EkMdP$LQ5AfPf13KufFsKtmazqnzSGZ4pxtUNw3woQ.ELRDF4'), - ] - - if TEST_MODE("full"): - # builtin alg was changed in 1.6, and had possibility of fencepost - # errors near rounds that are multiples of 42. these hashes test rounds - # 1004..1012 (42*24=1008 +/- 4) to ensure no mistakes were made. - # (also relying on fuzz testing against os_crypt backend). - known_correct_hashes.extend([ - ("secret", '$5$rounds=1004$nacl$oiWPbm.kQ7.jTCZoOtdv7/tO5mWv/vxw5yTqlBagVR7'), - ("secret", '$5$rounds=1005$nacl$6Mo/TmGDrXxg.bMK9isRzyWH3a..6HnSVVsJMEX7ud/'), - ("secret", '$5$rounds=1006$nacl$I46VwuAiUBwmVkfPFakCtjVxYYaOJscsuIeuZLbfKID'), - ("secret", '$5$rounds=1007$nacl$9fY4j1AV3N/dV/YMUn1enRHKH.7nEL4xf1wWB6wfDD4'), - ("secret", '$5$rounds=1008$nacl$CiFWCfn8ODmWs0I1xAdXFo09tM8jr075CyP64bu3by9'), - ("secret", '$5$rounds=1009$nacl$QtpFX.CJHgVQ9oAjVYStxAeiU38OmFILWm684c6FyED'), - ("secret", '$5$rounds=1010$nacl$ktAwXuT5WbjBW/0ZU1eNMpqIWY1Sm4twfRE1zbZyo.B'), - ("secret", '$5$rounds=1011$nacl$QJWLBEhO9qQHyMx4IJojSN9sS41P1Yuz9REddxdO721'), - ("secret", '$5$rounds=1012$nacl$mmf/k2PkbBF4VCtERgky3bEVavmLZKFwAcvxD1p3kV2'), - ]) - - known_malformed_hashes = [ - # bad char in otherwise correct hash - '$5$rounds=10428$uy/:jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMeZGsGx2aBvxTvDFI613c3', - - # zero-padded rounds - '$5$rounds=010428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3', - - # extra "$" - '$5$rounds=10428$uy/jIAhCetNCTtb0$YWvUOXbkqlqhyoPMpN8BMe.ZGsGx2aBvxTvDFI613c3$', - ] - - known_correct_configs = [ - # config, secret, result - - # - # taken from official specification at http://www.akkadia.org/drepper/SHA-crypt.txt - # - ( "$5$saltstring", "Hello world!", - "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" ), - ( "$5$rounds=10000$saltstringsaltstring", "Hello world!", - "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2." - "opqey6IcA" ), - ( "$5$rounds=5000$toolongsaltstring", "This is just a test", - "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8" - "mGRcvxa5" ), - ( "$5$rounds=1400$anotherlongsaltstring", - "a very much longer text to encrypt. This one even stretches over more" - "than one line.", - "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12" - "oP84Bnq1" ), - ( "$5$rounds=77777$short", - "we have a short salt string but not a short password", - "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" ), - ( "$5$rounds=123456$asaltof16chars..", "a short string", - "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/" - "cZKmF/wJvD" ), - ( "$5$rounds=10$roundstoolow", "the minimum number is still observed", - "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97" - "2bIC" ), - ] - - filter_config_warnings = True # rounds too low, salt too small - - platform_crypt_support = [ - ("freebsd(9|1\d)|linux", True), - ("freebsd8", None), # added in freebsd 8.3 - ("freebsd|openbsd|netbsd|darwin", False), - ("solaris", None), # depends on policy - ] - -# create test cases for specific backends -sha256_crypt_os_crypt_test = _sha256_crypt_test.create_backend_case("os_crypt") -sha256_crypt_builtin_test = _sha256_crypt_test.create_backend_case("builtin") - -#============================================================================= -# test sha512-crypt -#============================================================================= -class _sha512_crypt_test(HandlerCase): - handler = hash.sha512_crypt - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', "$6$LKO/Ute40T3FNF95$6S/6T2YuOIHY0N3XpLKABJ3soYcXD9mB7uVbtEZDj/LNscVhZoZ9DEH.sBciDrMsHOWOoASbNLTypH/5X26gN0"), - ('U*U***U', "$6$LKO/Ute40T3FNF95$wK80cNqkiAUzFuVGxW6eFe8J.fSVI65MD5yEm8EjYMaJuDrhwe5XXpHDJpwF/kY.afsUs1LlgQAaOapVNbggZ1"), - ('U*U***U*', "$6$LKO/Ute40T3FNF95$YS81pp1uhOHTgKLhSMtQCr2cDiUiN03Ud3gyD4ameviK1Zqz.w3oXsMgO6LrqmIEcG3hiqaUqHi/WEE2zrZqa/"), - ('*U*U*U*U', "$6$OmBOuxFYBZCYAadG$WCckkSZok9xhp4U1shIZEV7CCVwQUwMVea7L3A77th6SaE9jOPupEMJB.z0vIWCDiN9WLh2m9Oszrj5G.gt330"), - ('', "$6$ojWH1AiTee9x1peC$QVEnTvRVlPRhcLQCk/HnHaZmlGAAjCfrAN0FtOsOnUk5K5Bn/9eLHHiRzrTzaIKjW9NTLNIBUCtNVOowWS2mN."), - - # - # custom tests - # - ('', '$6$rounds=11021$KsvQipYPWpr93wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1'), - (' ', '$6$rounds=11104$ED9SA4qGmd57Fq2m$q/.PqACDM/JpAHKmr86nkPzzuR5.YpYa8ZJJvI8Zd89ZPUYTJExsFEIuTYbM7gAGcQtTkCEhBKmp1S1QZwaXx0'), - ('test', '$6$rounds=11531$G/gkPn17kHYo0gTF$Kq.uZBHlSBXyzsOJXtxJruOOH4yc0Is13uY7yK0PvAvXxbvc1w8DO1RzREMhKsc82K/Jh8OquV8FZUlreYPJk1'), - ('Compl3X AlphaNu3meric', '$6$rounds=10787$wakX8nGKEzgJ4Scy$X78uqaX1wYXcSCtS4BVYw2trWkvpa8p7lkAtS9O/6045fK4UB2/Jia0Uy/KzCpODlfVxVNZzCCoV9s2hoLfDs/'), - ('4lpHa N|_|M3r1K W/ Cur5Es: #$%(*)(*%#', '$6$rounds=11065$5KXQoE1bztkY5IZr$Jf6krQSUKKOlKca4hSW07MSerFFzVIZt/N3rOTsUgKqp7cUdHrwV8MoIVNCk9q9WL3ZRMsdbwNXpVk0gVxKtz1'), - - # ensures utf-8 used for unicode - (UPASS_TABLE, '$6$rounds=40000$PEZTJDiyzV28M3.m$GTlnzfzGB44DGd1XqlmC4erAJKCP.rhvLvrYxiT38htrNzVGBnplFOHjejUGVrCfusGWxLQCc3pFO0A/1jYYr0'), - ] - - known_malformed_hashes = [ - # zero-padded rounds - '$6$rounds=011021$KsvQipYPWpr93wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1', - # bad char in otherwise correct hash - '$6$rounds=11021$KsvQipYPWpr9:wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1', - ] - - known_correct_configs = [ - # config, secret, result - - # - # taken from official specification at http://www.akkadia.org/drepper/SHA-crypt.txt - # - ("$6$saltstring", "Hello world!", - "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" - "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" ), - - ( "$6$rounds=10000$saltstringsaltstring", "Hello world!", - "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb" - "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." ), - - ( "$6$rounds=5000$toolongsaltstring", "This is just a test", - "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ" - "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" ), - - ( "$6$rounds=1400$anotherlongsaltstring", - "a very much longer text to encrypt. This one even stretches over more" - "than one line.", - "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP" - "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" ), - - ( "$6$rounds=77777$short", - "we have a short salt string but not a short password", - "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g" - "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" ), - - ( "$6$rounds=123456$asaltof16chars..", "a short string", - "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc" - "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" ), - - ( "$6$rounds=10$roundstoolow", "the minimum number is still observed", - "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x" - "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." ), - ] - - filter_config_warnings = True # rounds too low, salt too small - - platform_crypt_support = _sha256_crypt_test.platform_crypt_support - -# create test cases for specific backends -sha512_crypt_os_crypt_test = _sha512_crypt_test.create_backend_case("os_crypt") -sha512_crypt_builtin_test = _sha512_crypt_test.create_backend_case("builtin") - -#============================================================================= -# sun md5 crypt -#============================================================================= -class sun_md5_crypt_test(HandlerCase): - handler = hash.sun_md5_crypt - - # TODO: this scheme needs some real test vectors, especially due to - # the "bare salt" issue which plagued the official parser. - known_correct_hashes = [ - # - # http://forums.halcyoninc.com/showthread.php?t=258 - # - ("Gpcs3_adm", "$md5$zrdhpMlZ$$wBvMOEqbSjU.hu5T2VEP01"), - - # - # http://www.c0t0d0s0.org/archives/4453-Less-known-Solaris-features-On-passwords-Part-2-Using-stronger-password-hashing.html - # - ("aa12345678", "$md5$vyy8.OVF$$FY4TWzuauRl4.VQNobqMY."), - - # - # http://www.cuddletech.com/blog/pivot/entry.php?id=778 - # - ("this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"), - - # - # http://compgroups.net/comp.unix.solaris/password-file-in-linux-and-solaris-8-9 - # - ("passwd", "$md5$RPgLF6IJ$WTvAlUJ7MqH5xak2FMEwS/"), - - # - # source: http://solaris-training.com/301_HTML/docs/deepdiv.pdf page 27 - # FIXME: password unknown - # "$md5,rounds=8000$kS9FT1JC$$mnUrRO618lLah5iazwJ9m1" - - # - # source: http://www.visualexams.com/310-303.htm - # XXX: this has 9 salt chars unlike all other hashes. is that valid? - # FIXME: password unknown - # "$md5,rounds=2006$2amXesSj5$$kCF48vfPsHDjlKNXeEw7V." - # - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, '$md5,rounds=5000$10VYDzAA$$1arAVtMA3trgE1qJ2V0Ez1'), - ] - - known_correct_configs = [ - # (config, secret, hash) - - #--------------------------- - # test salt string handling - # - # these tests attempt to verify that passlib is handling - # the "bare salt" issue (see sun md5 crypt docs) - # in a sane manner - #--------------------------- - - # config with "$" suffix, hash strings with "$$" suffix, - # should all be treated the same, with one "$" added to salt digest. - ("$md5$3UqYqndY$", - "this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"), - ("$md5$3UqYqndY$$.................DUMMY", - "this", "$md5$3UqYqndY$$6P.aaWOoucxxq.l00SS9k0"), - - # config with no suffix, hash strings with "$" suffix, - # should all be treated the same, and no suffix added to salt digest. - # NOTE: this is just a guess re: config w/ no suffix, - # but otherwise there's no sane way to encode bare_salt=False - # within config string. - ("$md5$3UqYqndY", - "this", "$md5$3UqYqndY$HIZVnfJNGCPbDZ9nIRSgP1"), - ("$md5$3UqYqndY$.................DUMMY", - "this", "$md5$3UqYqndY$HIZVnfJNGCPbDZ9nIRSgP1"), - ] - - known_malformed_hashes = [ - # unexpected end of hash - "$md5,rounds=5000", - - # bad rounds - "$md5,rounds=500A$xxxx", - "$md5,rounds=0500$xxxx", - "$md5,rounds=0$xxxx", - - # bad char in otherwise correct hash - "$md5$RPgL!6IJ$WTvAlUJ7MqH5xak2FMEwS/", - - # digest too short - "$md5$RPgLa6IJ$WTvAlUJ7MqH5xak2FMEwS", - - # digest too long - "$md5$RPgLa6IJ$WTvAlUJ7MqH5xak2FMEwS/.", - - # 2+ "$" at end of salt in config - # NOTE: not sure what correct behavior is, so forbidding format for now. - "$md5$3UqYqndY$$", - - # 3+ "$" at end of salt in hash - # NOTE: not sure what correct behavior is, so forbidding format for now. - "$md5$RPgLa6IJ$$$WTvAlUJ7MqH5xak2FMEwS/", - - ] - - platform_crypt_support = [ - ("solaris", True), - ("freebsd|openbsd|netbsd|linux|darwin", False), - ] - def do_verify(self, secret, hash): - # Override to fake error for "$..." hash string listed in known_correct_configs (above) - # These have to be hash strings, in order to test bare salt issue. - if isinstance(hash, str) and hash.endswith("$.................DUMMY"): - raise ValueError("pretending '$...' stub hash is config string") - return self.handler.verify(secret, hash) - -#============================================================================= -# unix disabled / fallback -#============================================================================= -class unix_disabled_test(HandlerCase): - handler = hash.unix_disabled -# accepts_all_hashes = True # TODO: turn this off. - - known_correct_hashes = [ - # everything should hash to "!" (or "*" on BSD), - # and nothing should verify against either string - ("password", "!"), - (UPASS_TABLE, "*"), - ] - - known_unidentified_hashes = [ - # should never identify anything crypt() could return... - "$1$xxx", - "abc", - "./az", - "{SHA}xxx", - ] - - def test_76_hash_border(self): - # so empty strings pass - self.accepts_all_hashes = True - super(unix_disabled_test, self).test_76_hash_border() - - def test_90_special(self): - """test marker option & special behavior""" - warnings.filterwarnings("ignore", "passing settings to .*.hash\(\) is deprecated") - handler = self.handler - - # preserve hash if provided - self.assertEqual(handler.genhash("stub", "!asd"), "!asd") - - # use marker if no hash - self.assertEqual(handler.genhash("stub", ""), handler.default_marker) - self.assertEqual(handler.hash("stub"), handler.default_marker) - self.assertEqual(handler.using().default_marker, handler.default_marker) - - # custom marker - self.assertEqual(handler.genhash("stub", "", marker="*xxx"), "*xxx") - self.assertEqual(handler.hash("stub", marker="*xxx"), "*xxx") - self.assertEqual(handler.using(marker="*xxx").hash("stub"), "*xxx") - - # reject invalid marker - self.assertRaises(ValueError, handler.genhash, 'stub', "", marker='abc') - self.assertRaises(ValueError, handler.hash, 'stub', marker='abc') - self.assertRaises(ValueError, handler.using, marker='abc') - -class unix_fallback_test(HandlerCase): - handler = hash.unix_fallback - accepts_all_hashes = True - - known_correct_hashes = [ - # *everything* should hash to "!", and nothing should verify - ("password", "!"), - (UPASS_TABLE, "!"), - ] - - # silence annoying deprecation warning - def setUp(self): - super(unix_fallback_test, self).setUp() - warnings.filterwarnings("ignore", "'unix_fallback' is deprecated") - - def test_90_wildcard(self): - """test enable_wildcard flag""" - h = self.handler - self.assertTrue(h.verify('password','', enable_wildcard=True)) - self.assertFalse(h.verify('password','')) - for c in "!*x": - self.assertFalse(h.verify('password',c, enable_wildcard=True)) - self.assertFalse(h.verify('password',c)) - - def test_91_preserves_existing(self): - """test preserves existing disabled hash""" - handler = self.handler - - # use marker if no hash - self.assertEqual(handler.genhash("stub", ""), "!") - self.assertEqual(handler.hash("stub"), "!") - - # use hash if provided and valid - self.assertEqual(handler.genhash("stub", "!asd"), "!asd") - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_argon2.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_argon2.py deleted file mode 100644 index e771769..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_argon2.py +++ /dev/null @@ -1,507 +0,0 @@ -"""passlib.tests.test_handlers_argon2 - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -# core -import logging -log = logging.getLogger(__name__) -import re -import warnings -# site -# pkg -from passlib import hash -from passlib.utils.compat import unicode -from passlib.tests.utils import HandlerCase, TEST_MODE -from passlib.tests.test_handlers import UPASS_TABLE, PASS_TABLE_UTF8 -# module - -#============================================================================= -# a bunch of tests lifted nearlky verbatim from official argon2 UTs... -# https://github.com/P-H-C/phc-winner-argon2/blob/master/src/test.c -#============================================================================= -def hashtest(version, t, logM, p, secret, salt, hex_digest, hash): - return dict(version=version, rounds=t, logM=logM, memory_cost=1< max uint32 - "$argon2i$v=19$m=65536,t=8589934592,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY", - - # unexpected param - "$argon2i$v=19$m=65536,t=2,p=4,q=5$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY", - - # wrong param order - "$argon2i$v=19$t=2,m=65536,p=4,q=5$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY", - - # constraint violation: m < 8 * p - "$argon2i$v=19$m=127,t=2,p=16$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", - ] - - known_parsehash_results = [ - ('$argon2i$v=19$m=256,t=2,p=3$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A', - dict(type="i", memory_cost=256, rounds=2, parallelism=3, salt=b'somesalt', - checksum=b'\x00\x91H\xb0\xd6S0\xa4\xc0{\x00x\xf8D\xcd\xd4')), - ] - - def setUpWarnings(self): - super(_base_argon2_test, self).setUpWarnings() - warnings.filterwarnings("ignore", ".*Using argon2pure backend.*") - - def do_stub_encrypt(self, handler=None, **settings): - if self.backend == "argon2_cffi": - # overriding default since no way to get stub config from argon2._calc_hash() - # (otherwise test_21b_max_rounds blocks trying to do max rounds) - handler = (handler or self.handler).using(**settings) - self = handler(use_defaults=True) - self.checksum = self._stub_checksum - assert self.checksum - return self.to_string() - else: - return super(_base_argon2_test, self).do_stub_encrypt(handler, **settings) - - def test_03_legacy_hash_workflow(self): - # override base method - raise self.skipTest("legacy 1.6 workflow not supported") - - def test_keyid_parameter(self): - # NOTE: keyid parameter currently not supported by official argon2 hash parser, - # even though it's mentioned in the format spec. - # we're trying to be consistent w/ this, so hashes w/ keyid should - # always through a NotImplementedError. - self.assertRaises(NotImplementedError, self.handler.verify, 'password', - "$argon2i$v=19$m=65536,t=2,p=4,keyid=ABCD$c29tZXNhbHQ$" - "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4") - - def test_data_parameter(self): - # NOTE: argon2 c library doesn't support passing in a data parameter to argon2_hash(); - # but argon2_verify() appears to parse that info... but then discards it (!?). - # not sure what proper behavior is, filed issue -- https://github.com/P-H-C/phc-winner-argon2/issues/143 - # For now, replicating behavior we have for the two backends, to detect when things change. - handler = self.handler - - # ref hash of 'password' when 'data' is correctly passed into argon2() - sample1 = '$argon2i$v=19$m=512,t=2,p=2,data=c29tZWRhdGE$c29tZXNhbHQ$KgHyCesFyyjkVkihZ5VNFw' - - # ref hash of 'password' when 'data' is silently discarded (same digest as w/o data) - sample2 = '$argon2i$v=19$m=512,t=2,p=2,data=c29tZWRhdGE$c29tZXNhbHQ$uEeXt1dxN1iFKGhklseW4w' - - # hash of 'password' w/o the data field - sample3 = '$argon2i$v=19$m=512,t=2,p=2$c29tZXNhbHQ$uEeXt1dxN1iFKGhklseW4w' - - # - # test sample 1 - # - - if self.backend == "argon2_cffi": - # argon2_cffi v16.1 would incorrectly return False here. - # but v16.2 patches so it throws error on data parameter. - # our code should detect that, and adapt it into a NotImplementedError - self.assertRaises(NotImplementedError, handler.verify, "password", sample1) - - # incorrectly returns sample3, dropping data parameter - self.assertEqual(handler.genhash("password", sample1), sample3) - - else: - assert self.backend == "argon2pure" - # should parse and verify - self.assertTrue(handler.verify("password", sample1)) - - # should preserve sample1 - self.assertEqual(handler.genhash("password", sample1), sample1) - - # - # test sample 2 - # - - if self.backend == "argon2_cffi": - # argon2_cffi v16.1 would incorrectly return True here. - # but v16.2 patches so it throws error on data parameter. - # our code should detect that, and adapt it into a NotImplementedError - self.assertRaises(NotImplementedError, handler.verify,"password", sample2) - - # incorrectly returns sample3, dropping data parameter - self.assertEqual(handler.genhash("password", sample1), sample3) - - else: - assert self.backend == "argon2pure" - # should parse, but fail to verify - self.assertFalse(self.handler.verify("password", sample2)) - - # should return sample1 (corrected digest) - self.assertEqual(handler.genhash("password", sample2), sample1) - - def test_keyid_and_data_parameters(self): - # test combination of the two, just in case - self.assertRaises(NotImplementedError, self.handler.verify, 'stub', - "$argon2i$v=19$m=65536,t=2,p=4,keyid=ABCD,data=EFGH$c29tZXNhbHQ$" - "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4") - - def test_type_kwd(self): - cls = self.handler - - # XXX: this mirrors test_30_HasManyIdents(); - # maybe switch argon2 class to use that mixin instead of "type" kwd? - - # check settings - self.assertTrue("type" in cls.setting_kwds) - - # check supported type_values - for value in cls.type_values: - self.assertIsInstance(value, unicode) - self.assertTrue("i" in cls.type_values) - self.assertTrue("d" in cls.type_values) - - # check default - self.assertTrue(cls.type in cls.type_values) - - # check constructor validates ident correctly. - handler = cls - hash = self.get_sample_hash()[1] - kwds = handler.parsehash(hash) - del kwds['type'] - - # ... accepts good type - handler(type=cls.type, **kwds) - - # XXX: this is policy "ident" uses, maybe switch to it? - # # ... requires type w/o defaults - # self.assertRaises(TypeError, handler, **kwds) - handler(**kwds) - - # ... supplies default type - handler(use_defaults=True, **kwds) - - # ... rejects bad type - self.assertRaises(ValueError, handler, type='xXx', **kwds) - - def test_type_using(self): - handler = self.handler - - # XXX: this mirrors test_has_many_idents_using(); - # maybe switch argon2 class to use that mixin instead of "type" kwd? - - orig_type = handler.type - for alt_type in handler.type_values: - if alt_type != orig_type: - break - else: - raise AssertionError("expected to find alternate type: default=%r values=%r" % - (orig_type, handler.type_values)) - - def effective_type(cls): - return cls(use_defaults=True).type - - # keep default if nothing else specified - subcls = handler.using() - self.assertEqual(subcls.type, orig_type) - - # accepts alt type - subcls = handler.using(type=alt_type) - self.assertEqual(subcls.type, alt_type) - self.assertEqual(handler.type, orig_type) - - # check subcls actually *generates* default type, - # and that we didn't affect orig handler - self.assertEqual(effective_type(subcls), alt_type) - self.assertEqual(effective_type(handler), orig_type) - - # rejects bad type - self.assertRaises(ValueError, handler.using, type='xXx') - - # honor 'type' alias - subcls = handler.using(type=alt_type) - self.assertEqual(subcls.type, alt_type) - self.assertEqual(handler.type, orig_type) - - # check type aliases are being honored - self.assertEqual(effective_type(handler.using(type="I")), "i") - - def test_needs_update_w_type(self): - handler = self.handler - - hash = handler.hash("stub") - self.assertFalse(handler.needs_update(hash)) - - hash2 = re.sub(r"\$argon2\w+\$", "$argon2d$", hash) - self.assertTrue(handler.needs_update(hash2)) - - def test_needs_update_w_version(self): - handler = self.handler.using(memory_cost=65536, time_cost=2, parallelism=4, - digest_size=32) - hash = ("$argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$" - "QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY") - if handler.max_version == 0x10: - self.assertFalse(handler.needs_update(hash)) - else: - self.assertTrue(handler.needs_update(hash)) - - def test_argon_byte_encoding(self): - """verify we're using right base64 encoding for argon2""" - handler = self.handler - if handler.version != 0x13: - # TODO: make this fatal, and add refs for other version. - raise self.skipTest("handler uses wrong version for sample hashes") - - # 8 byte salt - salt = b'somesalt' - temp = handler.using(memory_cost=256, time_cost=2, parallelism=2, salt=salt, - checksum_size=32, type="i") - hash = temp.hash("password") - self.assertEqual(hash, "$argon2i$v=19$m=256,t=2,p=2" - "$c29tZXNhbHQ" - "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E") - - # 16 byte salt - salt = b'somesalt\x00\x00\x00\x00\x00\x00\x00\x00' - temp = handler.using(memory_cost=256, time_cost=2, parallelism=2, salt=salt, - checksum_size=32, type="i") - hash = temp.hash("password") - self.assertEqual(hash, "$argon2i$v=19$m=256,t=2,p=2" - "$c29tZXNhbHQAAAAAAAAAAA" - "$rqnbEp1/jFDUEKZZmw+z14amDsFqMDC53dIe57ZHD38") - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - settings_map = HandlerCase.FuzzHashGenerator.settings_map.copy() - settings_map.update(memory_cost="random_memory_cost", type="random_type") - - def random_type(self): - return self.rng.choice(self.handler.type_values) - - def random_memory_cost(self): - if self.test.backend == "argon2pure": - return self.randintgauss(128, 384, 256, 128) - else: - return self.randintgauss(128, 32767, 16384, 4096) - - # TODO: fuzz parallelism, digest_size - -#----------------------------------------- -# test suites for specific backends -#----------------------------------------- - -class argon2_argon2_cffi_test(_base_argon2_test.create_backend_case("argon2_cffi")): - - # add some more test vectors that take too long under argon2pure - known_correct_hashes = _base_argon2_test.known_correct_hashes + [ - # - # sample hashes from argon2 cffi package's unittests, - # which in turn were generated by official argon2 cmdline tool. - # - - # v1.2, type I, w/o a version tag - ('password', "$argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$" - "QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY"), - - # v1.3, type I - ('password', "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$" - "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4"), - - # v1.3, type D - ('password', "$argon2d$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$" - "cZn5d+rFh+ZfuRhm2iGUGgcrW5YLeM6q7L3vBsdmFA0"), - - # v1.3, type ID - ('password', "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$" - "GpZ3sK/oH9p7VIiV56G/64Zo/8GaUw434IimaPqxwCo"), - - # - # custom - # - - # ensure trailing null bytes handled correctly - ('password\x00', "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$" - "Vpzuc0v0SrP88LcVvmg+z5RoOYpMDKH/lt6O+CZabIQ"), - - ] - - # add reference hashes from argon2 clib tests - known_correct_hashes.extend( - (info['secret'], info['hash']) for info in reference_data - if info['logM'] <= (18 if TEST_MODE("full") else 16) - ) - -class argon2_argon2pure_test(_base_argon2_test.create_backend_case("argon2pure")): - - # XXX: setting max_threads at 1 to prevent argon2pure from using multiprocessing, - # which causes big problems when testing under pypy. - # would like a "pure_use_threads" option instead, to make it use multiprocessing.dummy instead. - handler = hash.argon2.using(memory_cost=32, parallelism=2) - - # don't use multiprocessing for unittests, makes it a lot harder to ctrl-c - # XXX: make this controlled by env var? - handler.pure_use_threads = True - - # add reference hashes from argon2 clib tests - known_correct_hashes = _base_argon2_test.known_correct_hashes[:] - - known_correct_hashes.extend( - (info['secret'], info['hash']) for info in reference_data - if info['logM'] < 16 - ) - - class FuzzHashGenerator(_base_argon2_test.FuzzHashGenerator): - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(1, 3, 2, 1) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_bcrypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_bcrypt.py deleted file mode 100644 index 64fc8bf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_bcrypt.py +++ /dev/null @@ -1,688 +0,0 @@ -"""passlib.tests.test_handlers - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -import os -import warnings -# site -# pkg -from passlib import hash -from passlib.handlers.bcrypt import IDENT_2, IDENT_2X -from passlib.utils import repeat_string, to_bytes, is_safe_crypt_input -from passlib.utils.compat import irange, PY3 -from passlib.tests.utils import HandlerCase, TEST_MODE -from passlib.tests.test_handlers import UPASS_TABLE -# module - -#============================================================================= -# bcrypt -#============================================================================= -class _bcrypt_test(HandlerCase): - """base for BCrypt test cases""" - handler = hash.bcrypt - reduce_default_rounds = True - fuzz_salts_need_bcrypt_repair = True - - known_correct_hashes = [ - # - # from JTR 1.7.9 - # - ('U*U*U*U*', '$2a$05$c92SVSfjeiCD6F2nAD6y0uBpJDjdRkt0EgeC4/31Rf2LUZbDRDE.O'), - ('U*U***U', '$2a$05$WY62Xk2TXZ7EvVDQ5fmjNu7b0GEzSzUXUh2cllxJwhtOeMtWV3Ujq'), - ('U*U***U*', '$2a$05$Fa0iKV3E2SYVUlMknirWU.CFYGvJ67UwVKI1E2FP6XeLiZGcH3MJi'), - ('*U*U*U*U', '$2a$05$.WRrXibc1zPgIdRXYfv.4uu6TD1KWf0VnHzq/0imhUhuxSxCyeBs2'), - ('', '$2a$05$Otz9agnajgrAe0.kFVF9V.tzaStZ2s1s4ZWi/LY4sw2k/MTVFj/IO'), - - # - # test vectors from http://www.openwall.com/crypt v1.2 - # note that this omits any hashes that depend on crypt_blowfish's - # various CVE-2011-2483 workarounds (hash 2a and \xff\xff in password, - # and any 2x hashes); and only contain hashes which are correct - # under both crypt_blowfish 1.2 AND OpenBSD. - # - ('U*U', '$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW'), - ('U*U*', '$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK'), - ('U*U*U', '$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a'), - ('', '$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy'), - ('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - '0123456789chars after 72 are ignored', - '$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui'), - (b'\xa3', - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq'), - (b'\xff\xa3345', - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e'), - (b'\xa3ab', - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS'), - (b'\xaa'*72 + b'chars after 72 are ignored as usual', - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6'), - (b'\xaa\x55'*36, - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy'), - (b'\x55\xaa\xff'*24, - '$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe'), - - # keeping one of their 2y tests, because we are supporting that. - (b'\xa3', - '$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq'), - - # - # 8bit bug (fixed in 2y/2b) - # - - # NOTE: see assert_lacks_8bit_bug() for origins of this test vector. - (b"\xd1\x91", "$2y$05$6bNw2HLQYeqHYyBfLMsv/OUcZd0LKP39b87nBw3.S2tVZSqiQX6eu"), - - # - # bsd wraparound bug (fixed in 2b) - # - - # NOTE: if backend is vulnerable, password will hash the same as '0'*72 - # ("$2a$04$R1lJ2gkNaoPGdafE.H.16.nVyh2niHsGJhayOHLMiXlI45o8/DU.6"), - # rather than same as ("0123456789"*8)[:72] - # 255 should be sufficient, but checking - (("0123456789"*26)[:254], '$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi'), - (("0123456789"*26)[:255], '$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi'), - (("0123456789"*26)[:256], '$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi'), - (("0123456789"*26)[:257], '$2a$04$R1lJ2gkNaoPGdafE.H.16.1MKHPvmKwryeulRe225LKProWYwt9Oi'), - - - # - # from py-bcrypt tests - # - ('', '$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s.'), - ('a', '$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u'), - ('abc', '$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi'), - ('abcdefghijklmnopqrstuvwxyz', - '$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq'), - ('~!@#$%^&*() ~!@#$%^&*()PNBFRD', - '$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS'), - - # - # custom test vectors - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, - '$2a$05$Z17AXnnlpzddNUvnC6cZNOSwMA/8oNiKnHTHTwLlBijfucQQlHjaG'), - - # ensure 2b support - (UPASS_TABLE, - '$2b$05$Z17AXnnlpzddNUvnC6cZNOSwMA/8oNiKnHTHTwLlBijfucQQlHjaG'), - - ] - - if TEST_MODE("full"): - # - # add some extra tests related to 2/2a - # - CONFIG_2 = '$2$05$' + '.'*22 - CONFIG_A = '$2a$05$' + '.'*22 - known_correct_hashes.extend([ - ("", CONFIG_2 + 'J2ihDv8vVf7QZ9BsaRrKyqs2tkn55Yq'), - ("", CONFIG_A + 'J2ihDv8vVf7QZ9BsaRrKyqs2tkn55Yq'), - ("abc", CONFIG_2 + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ("abc", CONFIG_A + 'ev6gDwpVye3oMCUpLY85aTpfBNHD0Ga'), - ("abc"*23, CONFIG_2 + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ("abc"*23, CONFIG_A + '2kIdfSj/4/R/Q6n847VTvc68BXiRYZC'), - ("abc"*24, CONFIG_2 + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ("abc"*24, CONFIG_A + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ("abc"*24+'x', CONFIG_2 + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ("abc"*24+'x', CONFIG_A + 'XuQjdH.wPVNUZ/bOfstdW/FqB8QSjte'), - ]) - - known_correct_configs = [ - ('$2a$04$uM6csdM8R9SXTex/gbTaye', UPASS_TABLE, - '$2a$04$uM6csdM8R9SXTex/gbTayezuvzFEufYGd2uB6of7qScLjQ4GwcD4G'), - ] - - known_unidentified_hashes = [ - # invalid minor version - "$2f$12$EXRkfkdmXnagzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q", - "$2`$12$EXRkfkdmXnagzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q", - ] - - known_malformed_hashes = [ - # bad char in otherwise correct hash - # \/ - "$2a$12$EXRkfkdmXn!gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q", - - # unsupported (but recognized) minor version - "$2x$12$EXRkfkdmXnagzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q", - - # rounds not zero-padded (py-bcrypt rejects this, therefore so do we) - '$2a$6$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s.' - - # NOTE: salts with padding bits set are technically malformed, - # but we can reliably correct & issue a warning for that. - ] - - platform_crypt_support = [ - ("freedbsd|openbsd|netbsd", True), - ("darwin", False), - ("linux", None), # may be present via addon, e.g. debian's libpam-unix2 - ("solaris", None), # depends on system policy - ] - - #=================================================================== - # override some methods - #=================================================================== - def setUp(self): - # ensure builtin is enabled for duration of test. - if TEST_MODE("full") and self.backend == "builtin": - key = "PASSLIB_BUILTIN_BCRYPT" - orig = os.environ.get(key) - if orig: - self.addCleanup(os.environ.__setitem__, key, orig) - else: - self.addCleanup(os.environ.__delitem__, key) - os.environ[key] = "true" - - super(_bcrypt_test, self).setUp() - - # silence this warning, will come up a bunch during testing of old 2a hashes. - warnings.filterwarnings("ignore", ".*backend is vulnerable to the bsd wraparound bug.*") - - def populate_settings(self, kwds): - # builtin is still just way too slow. - if self.backend == "builtin": - kwds.setdefault("rounds", 4) - super(_bcrypt_test, self).populate_settings(kwds) - - #=================================================================== - # fuzz testing - #=================================================================== - def crypt_supports_variant(self, hash): - """check if OS crypt is expected to support given ident""" - from passlib.handlers.bcrypt import bcrypt, IDENT_2X, IDENT_2Y - from passlib.utils import safe_crypt - ident = bcrypt.from_string(hash) - return (safe_crypt("test", ident + "04$5BJqKfqMQvV7nS.yUguNcu") or "").startswith(ident) - - fuzz_verifiers = HandlerCase.fuzz_verifiers + ( - "fuzz_verifier_bcrypt", - "fuzz_verifier_pybcrypt", - "fuzz_verifier_bcryptor", - ) - - def fuzz_verifier_bcrypt(self): - # test against bcrypt, if available - from passlib.handlers.bcrypt import IDENT_2, IDENT_2A, IDENT_2B, IDENT_2X, IDENT_2Y, _detect_pybcrypt - from passlib.utils import to_native_str, to_bytes - try: - import bcrypt - except ImportError: - return - if _detect_pybcrypt(): - return - def check_bcrypt(secret, hash): - """bcrypt""" - secret = to_bytes(secret, self.FuzzHashGenerator.password_encoding) - if hash.startswith(IDENT_2B): - # bcrypt <1.1 lacks 2B support - hash = IDENT_2A + hash[4:] - elif hash.startswith(IDENT_2): - # bcrypt doesn't support $2$ hashes; but we can fake it - # using the $2a$ algorithm, by repeating the password until - # it's 72 chars in length. - hash = IDENT_2A + hash[3:] - if secret: - secret = repeat_string(secret, 72) - elif hash.startswith(IDENT_2Y) and bcrypt.__version__ == "3.0.0": - hash = IDENT_2B + hash[4:] - hash = to_bytes(hash) - try: - return bcrypt.hashpw(secret, hash) == hash - except ValueError: - raise ValueError("bcrypt rejected hash: %r (secret=%r)" % (hash, secret)) - return check_bcrypt - - def fuzz_verifier_pybcrypt(self): - # test against py-bcrypt, if available - from passlib.handlers.bcrypt import ( - IDENT_2, IDENT_2A, IDENT_2B, IDENT_2X, IDENT_2Y, - _PyBcryptBackend, - ) - from passlib.utils import to_native_str - - loaded = _PyBcryptBackend._load_backend_mixin("pybcrypt", False) - if not loaded: - return - - from passlib.handlers.bcrypt import _pybcrypt as bcrypt_mod - - lock = _PyBcryptBackend._calc_lock # reuse threadlock workaround for pybcrypt 0.2 - - def check_pybcrypt(secret, hash): - """pybcrypt""" - secret = to_native_str(secret, self.FuzzHashGenerator.password_encoding) - if len(secret) > 200: # vulnerable to wraparound bug - secret = secret[:200] - if hash.startswith((IDENT_2B, IDENT_2Y)): - hash = IDENT_2A + hash[4:] - try: - if lock: - with lock: - return bcrypt_mod.hashpw(secret, hash) == hash - else: - return bcrypt_mod.hashpw(secret, hash) == hash - except ValueError: - raise ValueError("py-bcrypt rejected hash: %r" % (hash,)) - return check_pybcrypt - - def fuzz_verifier_bcryptor(self): - # test against bcryptor if available - from passlib.handlers.bcrypt import IDENT_2, IDENT_2A, IDENT_2Y, IDENT_2B - from passlib.utils import to_native_str - try: - from bcryptor.engine import Engine - except ImportError: - return - def check_bcryptor(secret, hash): - """bcryptor""" - secret = to_native_str(secret, self.FuzzHashGenerator.password_encoding) - if hash.startswith((IDENT_2B, IDENT_2Y)): - hash = IDENT_2A + hash[4:] - elif hash.startswith(IDENT_2): - # bcryptor doesn't support $2$ hashes; but we can fake it - # using the $2a$ algorithm, by repeating the password until - # it's 72 chars in length. - hash = IDENT_2A + hash[3:] - if secret: - secret = repeat_string(secret, 72) - return Engine(False).hash_key(secret, hash) == hash - return check_bcryptor - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def generate(self): - opts = super(_bcrypt_test.FuzzHashGenerator, self).generate() - - secret = opts['secret'] - other = opts['other'] - settings = opts['settings'] - ident = settings.get('ident') - - if ident == IDENT_2X: - # 2x is just recognized, not supported. don't test with it. - del settings['ident'] - - elif ident == IDENT_2 and other and repeat_string(to_bytes(other), len(to_bytes(secret))) == to_bytes(secret): - # avoid false failure due to flaw in 0-revision bcrypt: - # repeated strings like 'abc' and 'abcabc' hash identically. - opts['secret'], opts['other'] = self.random_password_pair() - - return opts - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(5, 8, 6, 1) - - #=================================================================== - # custom tests - #=================================================================== - known_incorrect_padding = [ - # password, bad hash, good hash - - # 2 bits of salt padding set -# ("loppux", # \/ -# "$2a$12$oaQbBqq8JnSM1NHRPQGXORm4GCUMqp7meTnkft4zgSnrbhoKdDV0C", -# "$2a$12$oaQbBqq8JnSM1NHRPQGXOOm4GCUMqp7meTnkft4zgSnrbhoKdDV0C"), - ("test", # \/ - '$2a$04$oaQbBqq8JnSM1NHRPQGXORY4Vw3bdHKLIXTecPDRAcJ98cz1ilveO', - '$2a$04$oaQbBqq8JnSM1NHRPQGXOOY4Vw3bdHKLIXTecPDRAcJ98cz1ilveO'), - - # all 4 bits of salt padding set -# ("Passlib11", # \/ -# "$2a$12$M8mKpW9a2vZ7PYhq/8eJVcUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK", -# "$2a$12$M8mKpW9a2vZ7PYhq/8eJVOUtKxpo6j0zAezu0G/HAMYgMkhPu4fLK"), - ("test", # \/ - "$2a$04$yjDgE74RJkeqC0/1NheSScrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS", - "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS"), - - # bad checksum padding - ("test", # \/ - "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIV", - "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS"), - ] - - def test_90_bcrypt_padding(self): - """test passlib correctly handles bcrypt padding bits""" - self.require_TEST_MODE("full") - # - # prevents reccurrence of issue 25 (https://code.google.com/p/passlib/issues/detail?id=25) - # were some unused bits were incorrectly set in bcrypt salt strings. - # (fixed since 1.5.3) - # - bcrypt = self.handler - corr_desc = ".*incorrectly set padding bits" - - # - # test hash() / genconfig() don't generate invalid salts anymore - # - def check_padding(hash): - assert hash.startswith(("$2a$", "$2b$")) and len(hash) >= 28, \ - "unexpectedly malformed hash: %r" % (hash,) - self.assertTrue(hash[28] in '.Oeu', - "unused bits incorrectly set in hash: %r" % (hash,)) - for i in irange(6): - check_padding(bcrypt.genconfig()) - for i in irange(3): - check_padding(bcrypt.using(rounds=bcrypt.min_rounds).hash("bob")) - - # - # test genconfig() corrects invalid salts & issues warning. - # - with self.assertWarningList(["salt too large", corr_desc]): - hash = bcrypt.genconfig(salt="."*21 + "A.", rounds=5, relaxed=True) - self.assertEqual(hash, "$2b$05$" + "." * (22 + 31)) - - # - # test public methods against good & bad hashes - # - samples = self.known_incorrect_padding - for pwd, bad, good in samples: - - # make sure genhash() corrects bad configs, leaves good unchanged - with self.assertWarningList([corr_desc]): - self.assertEqual(bcrypt.genhash(pwd, bad), good) - with self.assertWarningList([]): - self.assertEqual(bcrypt.genhash(pwd, good), good) - - # make sure verify() works correctly with good & bad hashes - with self.assertWarningList([corr_desc]): - self.assertTrue(bcrypt.verify(pwd, bad)) - with self.assertWarningList([]): - self.assertTrue(bcrypt.verify(pwd, good)) - - # make sure normhash() corrects bad hashes, leaves good unchanged - with self.assertWarningList([corr_desc]): - self.assertEqual(bcrypt.normhash(bad), good) - with self.assertWarningList([]): - self.assertEqual(bcrypt.normhash(good), good) - - # make sure normhash() leaves non-bcrypt hashes alone - self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc") - - def test_needs_update_w_padding(self): - """needs_update corrects bcrypt padding""" - # NOTE: see padding test above for details about issue this detects - bcrypt = self.handler.using(rounds=4) - - # PASS1 = "test" - # bad contains invalid 'c' char at end of salt: - # \/ - BAD1 = "$2a$04$yjDgE74RJkeqC0/1NheSScrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS" - GOOD1 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS" - - self.assertTrue(bcrypt.needs_update(BAD1)) - self.assertFalse(bcrypt.needs_update(GOOD1)) - - #=================================================================== - # eoc - #=================================================================== - -# create test cases for specific backends -bcrypt_bcrypt_test = _bcrypt_test.create_backend_case("bcrypt") -bcrypt_pybcrypt_test = _bcrypt_test.create_backend_case("pybcrypt") -bcrypt_bcryptor_test = _bcrypt_test.create_backend_case("bcryptor") - -class bcrypt_os_crypt_test(_bcrypt_test.create_backend_case("os_crypt")): - - # os crypt doesn't support non-utf8 secret bytes - known_correct_hashes = [row for row in _bcrypt_test.known_correct_hashes - if is_safe_crypt_input(row[0])] - - # os crypt backend doesn't currently implement a per-call fallback if it fails - has_os_crypt_fallback = False - -bcrypt_builtin_test = _bcrypt_test.create_backend_case("builtin") - -#============================================================================= -# bcrypt -#============================================================================= -class _bcrypt_sha256_test(HandlerCase): - "base for BCrypt-SHA256 test cases" - handler = hash.bcrypt_sha256 - reduce_default_rounds = True - forbidden_characters = None - fuzz_salts_need_bcrypt_repair = True - - known_correct_hashes = [ - #------------------------------------------------------------------- - # custom test vectors for old v1 format - #------------------------------------------------------------------- - - # empty - ("", - '$bcrypt-sha256$2a,5$E/e/2AOhqM5W/KJTFQzLce$F6dYSxOdAEoJZO2eoHUZWZljW/e0TXO'), - - # ascii - ("password", - '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu'), - - # unicode / utf8 - (UPASS_TABLE, - '$bcrypt-sha256$2a,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje'), - (UPASS_TABLE.encode("utf-8"), - '$bcrypt-sha256$2a,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje'), - - # ensure 2b support - ("password", - '$bcrypt-sha256$2b,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu'), - (UPASS_TABLE, - '$bcrypt-sha256$2b,5$.US1fQ4TQS.ZTz/uJ5Kyn.$QNdPDOTKKT5/sovNz1iWg26quOU4Pje'), - - # test >72 chars is hashed correctly -- under bcrypt these hash the same. - # NOTE: test_60_truncate_size() handles this already, this is just for overkill :) - (repeat_string("abc123", 72), - '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$r/hyEtqJ0teqPEmfTLoZ83ciAI1Q74.'), - (repeat_string("abc123", 72) + "qwr", - '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$021KLEif6epjot5yoxk0m8I0929ohEa'), - (repeat_string("abc123", 72) + "xyz", - '$bcrypt-sha256$2b,5$X1g1nh3g0v4h6970O68cxe$7.1kgpHduMGEjvM3fX6e/QCvfn6OKja'), - - #------------------------------------------------------------------- - # custom test vectors for v2 format - # TODO: convert to v2 format - #------------------------------------------------------------------- - - # empty - ("", - '$bcrypt-sha256$v=2,t=2b,r=5$E/e/2AOhqM5W/KJTFQzLce$WFPIZKtDDTriqWwlmRFfHiOTeheAZWe'), - - # ascii - ("password", - '$bcrypt-sha256$v=2,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe$wOK1VFFtS8IGTrGa7.h5fs0u84qyPbS'), - - # unicode / utf8 - (UPASS_TABLE, - '$bcrypt-sha256$v=2,t=2b,r=5$.US1fQ4TQS.ZTz/uJ5Kyn.$pzzgp40k8reM1CuQb03PvE0IDPQSdV6'), - (UPASS_TABLE.encode("utf-8"), - '$bcrypt-sha256$v=2,t=2b,r=5$.US1fQ4TQS.ZTz/uJ5Kyn.$pzzgp40k8reM1CuQb03PvE0IDPQSdV6'), - - # test >72 chars is hashed correctly -- under bcrypt these hash the same. - # NOTE: test_60_truncate_size() handles this already, this is just for overkill :) - (repeat_string("abc123", 72), - '$bcrypt-sha256$v=2,t=2b,r=5$X1g1nh3g0v4h6970O68cxe$zu1cloESVFIOsUIo7fCEgkdHaI9SSue'), - (repeat_string("abc123", 72) + "qwr", - '$bcrypt-sha256$v=2,t=2b,r=5$X1g1nh3g0v4h6970O68cxe$CBF9csfEdW68xv3DwE6xSULXMtqEFP.'), - (repeat_string("abc123", 72) + "xyz", - '$bcrypt-sha256$v=2,t=2b,r=5$X1g1nh3g0v4h6970O68cxe$zC/1UDUG2ofEXB6Onr2vvyFzfhEOS3S'), - ] - - known_correct_configs =[ - # v1 - ('$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe', - "password", '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu'), - # v2 - ('$bcrypt-sha256$v=2,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe', - "password", '$bcrypt-sha256$v=2,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe$wOK1VFFtS8IGTrGa7.h5fs0u84qyPbS'), - ] - - known_malformed_hashes = [ - #------------------------------------------------------------------- - # v1 format - #------------------------------------------------------------------- - - # bad char in otherwise correct hash - # \/ - '$bcrypt-sha256$2a,5$5Hg1DKF!PE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unrecognized bcrypt variant - '$bcrypt-sha256$2c,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unsupported bcrypt variant - '$bcrypt-sha256$2x,5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # rounds zero-padded - '$bcrypt-sha256$2a,05$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # config string w/ $ added - '$bcrypt-sha256$2a,5$5Hg1DKFqPE8C2aflZ5vVoe$', - - #------------------------------------------------------------------- - # v2 format - #------------------------------------------------------------------- - - # bad char in otherwise correct hash - # \/ - '$bcrypt-sha256$v=2,t=2b,r=5$5Hg1DKF!PE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unsupported version (for this format) - '$bcrypt-sha256$v=1,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unrecognized version - '$bcrypt-sha256$v=3,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unrecognized bcrypt variant - '$bcrypt-sha256$v=2,t=2c,r=5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # unsupported bcrypt variant - '$bcrypt-sha256$v=2,t=2a,r=5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - '$bcrypt-sha256$v=2,t=2x,r=5$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # rounds zero-padded - '$bcrypt-sha256$v=2,t=2b,r=05$5Hg1DKFqPE8C2aflZ5vVoe$12BjNE0p7axMg55.Y/mHsYiVuFBDQyu', - - # config string w/ $ added - '$bcrypt-sha256$v=2,t=2b,r=5$5Hg1DKFqPE8C2aflZ5vVoe$', - ] - - #=================================================================== - # override some methods -- cloned from bcrypt - #=================================================================== - def setUp(self): - # ensure builtin is enabled for duration of test. - if TEST_MODE("full") and self.backend == "builtin": - key = "PASSLIB_BUILTIN_BCRYPT" - orig = os.environ.get(key) - if orig: - self.addCleanup(os.environ.__setitem__, key, orig) - else: - self.addCleanup(os.environ.__delitem__, key) - os.environ[key] = "enabled" - super(_bcrypt_sha256_test, self).setUp() - warnings.filterwarnings("ignore", ".*backend is vulnerable to the bsd wraparound bug.*") - - def populate_settings(self, kwds): - # builtin is still just way too slow. - if self.backend == "builtin": - kwds.setdefault("rounds", 4) - super(_bcrypt_sha256_test, self).populate_settings(kwds) - - #=================================================================== - # override ident tests for now - #=================================================================== - - def require_many_idents(self): - raise self.skipTest("multiple idents not supported") - - def test_30_HasOneIdent(self): - # forbidding ident keyword, we only support "2b" for now - handler = self.handler - handler(use_defaults=True) - self.assertRaises(ValueError, handler, ident="$2y$", use_defaults=True) - - #=================================================================== - # fuzz testing -- cloned from bcrypt - #=================================================================== - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(5, 8, 6, 1) - - def random_ident(self): - return "2b" - - #=================================================================== - # custom tests - #=================================================================== - - def test_using_version(self): - # default to v2 - handler = self.handler - self.assertEqual(handler.version, 2) - - # allow v1 explicitly - subcls = handler.using(version=1) - self.assertEqual(subcls.version, 1) - - # forbid unknown ver - self.assertRaises(ValueError, handler.using, version=999) - - # allow '2a' only for v1 - subcls = handler.using(version=1, ident="2a") - self.assertRaises(ValueError, handler.using, ident="2a") - - def test_calc_digest_v2(self): - """ - test digest calc v2 matches bcrypt() - """ - from passlib.hash import bcrypt - from passlib.crypto.digest import compile_hmac - from passlib.utils.binary import b64encode - - # manually calc intermediary digest - salt = "nyKYxTAvjmy6lMDYMl11Uu" - secret = "test" - temp_digest = compile_hmac("sha256", salt.encode("ascii"))(secret.encode("ascii")) - temp_digest = b64encode(temp_digest).decode("ascii") - self.assertEqual(temp_digest, "J5TlyIDm+IcSWmKiDJm+MeICndBkFVPn4kKdJW8f+xY=") - - # manually final hash from intermediary - # XXX: genhash() could be useful here - bcrypt_digest = bcrypt(ident="2b", salt=salt, rounds=12)._calc_checksum(temp_digest) - self.assertEqual(bcrypt_digest, "M0wE0Ov/9LXoQFCe.jRHu3MSHPF54Ta") - self.assertTrue(bcrypt.verify(temp_digest, "$2b$12$" + salt + bcrypt_digest)) - - # confirm handler outputs same thing. - # XXX: genhash() could be useful here - result = self.handler(ident="2b", salt=salt, rounds=12)._calc_checksum(secret) - self.assertEqual(result, bcrypt_digest) - - #=================================================================== - # eoc - #=================================================================== - -# create test cases for specific backends -bcrypt_sha256_bcrypt_test = _bcrypt_sha256_test.create_backend_case("bcrypt") -bcrypt_sha256_pybcrypt_test = _bcrypt_sha256_test.create_backend_case("pybcrypt") -bcrypt_sha256_bcryptor_test = _bcrypt_sha256_test.create_backend_case("bcryptor") - -class bcrypt_sha256_os_crypt_test(_bcrypt_sha256_test.create_backend_case("os_crypt")): - - @classmethod - def _get_safe_crypt_handler_backend(cls): - return bcrypt_os_crypt_test._get_safe_crypt_handler_backend() - - has_os_crypt_fallback = False - -bcrypt_sha256_builtin_test = _bcrypt_sha256_test.create_backend_case("builtin") - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_cisco.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_cisco.py deleted file mode 100644 index ea6594b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_cisco.py +++ /dev/null @@ -1,457 +0,0 @@ -""" -passlib.tests.test_handlers_cisco - tests for Cisco-specific algorithms -""" -#============================================================================= -# imports -#============================================================================= -from __future__ import absolute_import, division, print_function -# core -import logging -log = logging.getLogger(__name__) -# site -# pkg -from passlib import hash, exc -from passlib.utils.compat import u -from .utils import UserHandlerMixin, HandlerCase, repeat_string -from .test_handlers import UPASS_TABLE -# module -__all__ = [ - "cisco_pix_test", - "cisco_asa_test", - "cisco_type7_test", -] -#============================================================================= -# shared code for cisco PIX & ASA -#============================================================================= - -class _PixAsaSharedTest(UserHandlerMixin, HandlerCase): - """ - class w/ shared info for PIX & ASA tests. - """ - __unittest_skip = True # for TestCase - requires_user = False # for UserHandlerMixin - - #: shared list of hashes which should be identical under pix & asa7 - #: (i.e. combined secret + user < 17 bytes) - pix_asa_shared_hashes = [ - # - # http://www.perlmonks.org/index.pl?node_id=797623 - # - (("cisco", ""), "2KFQnbNIdI.2KYOU"), # confirmed ASA 9.6 - - # - # http://www.hsc.fr/ressources/breves/pix_crack.html.en - # - (("hsc", ""), "YtT8/k6Np8F1yz2c"), # confirmed ASA 9.6 - - # - # www.freerainbowtables.com/phpBB3/viewtopic.php?f=2&t=1441 - # - (("", ""), "8Ry2YjIyt7RRXU24"), # confirmed ASA 9.6 - (("cisco", "john"), "hN7LzeyYjw12FSIU"), - (("cisco", "jack"), "7DrfeZ7cyOj/PslD"), - - # - # http://comments.gmane.org/gmane.comp.security.openwall.john.user/2529 - # - (("ripper", "alex"), "h3mJrcH0901pqX/m"), - (("cisco", "cisco"), "3USUcOPFUiMCO4Jk"), - (("cisco", "cisco1"), "3USUcOPFUiMCO4Jk"), - (("CscFw-ITC!", "admcom"), "lZt7HSIXw3.QP7.R"), - ("cangetin", "TynyB./ftknE77QP"), - (("cangetin", "rramsey"), "jgBZqYtsWfGcUKDi"), - - # - # http://openwall.info/wiki/john/sample-hashes - # - (("phonehome", "rharris"), "zyIIMSYjiPm0L7a6"), - - # - # http://www.openwall.com/lists/john-users/2010/08/08/3 - # - (("cangetin", ""), "TynyB./ftknE77QP"), - (("cangetin", "rramsey"), "jgBZqYtsWfGcUKDi"), - - # - # from JTR 1.7.9 - # - ("test1", "TRPEas6f/aa6JSPL"), - ("test2", "OMT6mXmAvGyzrCtp"), - ("test3", "gTC7RIy1XJzagmLm"), - ("test4", "oWC1WRwqlBlbpf/O"), - ("password", "NuLKvvWGg.x9HEKO"), - ("0123456789abcdef", ".7nfVBEIEu4KbF/1"), - - # - # http://www.cisco.com/en/US/docs/security/pix/pix50/configuration/guide/commands.html#wp5472 - # - (("1234567890123456", ""), "feCkwUGktTCAgIbD"), # canonical source - (("watag00s1am", ""), "jMorNbK0514fadBh"), # canonical source - - # - # custom - # - (("cisco1", "cisco1"), "jmINXNH6p1BxUppp"), - - # ensures utf-8 used for unicode - (UPASS_TABLE, 'CaiIvkLMu2TOHXGT'), - - # - # passlib reference vectors - # - # Some of these have been confirmed on various ASA firewalls, - # and the exact version is noted next to each hash. - # Would like to verify these under more PIX & ASA versions. - # - # Those without a note are generally an extrapolation, - # to ensure the code stays consistent, but for various reasons, - # hasn't been verified. - # - # * One such case is usernames w/ 1 & 2 digits -- - # ASA (9.6 at least) requires 3+ digits in username. - # - # The following hashes (below 13 chars) should be identical for PIX/ASA. - # Ones which differ are listed separately in the known_correct_hashes - # list for the two test classes. - # - - # 4 char password - (('1234', ''), 'RLPMUQ26KL4blgFN'), # confirmed ASA 9.6 - - # 8 char password - (('01234567', ''), '0T52THgnYdV1tlOF'), # confirmed ASA 9.6 - (('01234567', '3'), '.z0dT9Alkdc7EIGS'), - (('01234567', '36'), 'CC3Lam53t/mHhoE7'), - (('01234567', '365'), '8xPrWpNnBdD2DzdZ'), # confirmed ASA 9.6 - (('01234567', '3333'), '.z0dT9Alkdc7EIGS'), # confirmed ASA 9.6 - (('01234567', '3636'), 'CC3Lam53t/mHhoE7'), # confirmed ASA 9.6 - (('01234567', '3653'), '8xPrWpNnBdD2DzdZ'), # confirmed ASA 9.6 - (('01234567', 'adm'), 'dfWs2qiao6KD/P2L'), # confirmed ASA 9.6 - (('01234567', 'adma'), 'dfWs2qiao6KD/P2L'), # confirmed ASA 9.6 - (('01234567', 'admad'), 'dfWs2qiao6KD/P2L'), # confirmed ASA 9.6 - (('01234567', 'user'), 'PNZ4ycbbZ0jp1.j1'), # confirmed ASA 9.6 - (('01234567', 'user1234'), 'PNZ4ycbbZ0jp1.j1'), # confirmed ASA 9.6 - - # 12 char password - (('0123456789ab', ''), 'S31BxZOGlAigndcJ'), # confirmed ASA 9.6 - (('0123456789ab', '36'), 'wFqSX91X5.YaRKsi'), - (('0123456789ab', '365'), 'qjgo3kNgTVxExbno'), # confirmed ASA 9.6 - (('0123456789ab', '3333'), 'mcXPL/vIZcIxLUQs'), # confirmed ASA 9.6 - (('0123456789ab', '3636'), 'wFqSX91X5.YaRKsi'), # confirmed ASA 9.6 - (('0123456789ab', '3653'), 'qjgo3kNgTVxExbno'), # confirmed ASA 9.6 - (('0123456789ab', 'user'), 'f.T4BKdzdNkjxQl7'), # confirmed ASA 9.6 - (('0123456789ab', 'user1234'), 'f.T4BKdzdNkjxQl7'), # confirmed ASA 9.6 - - # NOTE: remaining reference vectors for 13+ char passwords - # are split up between cisco_pix & cisco_asa tests. - - # unicode passwords - # ASA supposedly uses utf-8 encoding, but entering non-ascii - # chars is error-prone, and while UTF-8 appears to be intended, - # observed behaviors include: - # * ssh cli stripping non-ascii chars entirely - # * ASDM web iface double-encoding utf-8 strings - ((u("t\xe1ble").encode("utf-8"), 'user'), 'Og8fB4NyF0m5Ed9c'), - ((u("t\xe1ble").encode("utf-8").decode("latin-1").encode("utf-8"), - 'user'), 'cMvFC2XVBmK/68yB'), # confirmed ASA 9.6 when typed into ASDM - ] - - def test_calc_digest_spoiler(self): - """ - _calc_checksum() -- spoil oversize passwords during verify - - for details, see 'spoil_digest' flag instead that function. - this helps cisco_pix/cisco_asa implement their policy of - ``.truncate_verify_reject=True``. - """ - def calc(secret, for_hash=False): - return self.handler(use_defaults=for_hash)._calc_checksum(secret) - - # short (non-truncated) password - short_secret = repeat_string("1234", self.handler.truncate_size) - short_hash = calc(short_secret) - - # longer password should have totally different hash, - # to prevent verify from matching (i.e. "spoiled"). - long_secret = short_secret + "X" - long_hash = calc(long_secret) - self.assertNotEqual(long_hash, short_hash) - - # spoiled hash should depend on whole secret, - # so that output isn't predictable - alt_long_secret = short_secret + "Y" - alt_long_hash = calc(alt_long_secret) - self.assertNotEqual(alt_long_hash, short_hash) - self.assertNotEqual(alt_long_hash, long_hash) - - # for hash(), should throw error if password too large - calc(short_secret, for_hash=True) - self.assertRaises(exc.PasswordSizeError, calc, long_secret, for_hash=True) - self.assertRaises(exc.PasswordSizeError, calc, alt_long_secret, for_hash=True) - -#============================================================================= -# cisco pix -#============================================================================= -class cisco_pix_test(_PixAsaSharedTest): - handler = hash.cisco_pix - - #: known correct pix hashes - known_correct_hashes = _PixAsaSharedTest.pix_asa_shared_hashes + [ - # - # passlib reference vectors (PIX-specific) - # - # NOTE: See 'pix_asa_shared_hashes' for general PIX+ASA vectors, - # and general notes about the 'passlib reference vectors' test set. - # - # All of the following are PIX-specific, as ASA starts - # to use a different padding size at 13 characters. - # - # TODO: these need confirming w/ an actual PIX system. - # - - # 13 char password - (('0123456789abc', ''), 'eacOpB7vE7ZDukSF'), - (('0123456789abc', '3'), 'ylJTd/qei66WZe3w'), - (('0123456789abc', '36'), 'hDx8QRlUhwd6bU8N'), - (('0123456789abc', '365'), 'vYOOtnkh1HXcMrM7'), - (('0123456789abc', '3333'), 'ylJTd/qei66WZe3w'), - (('0123456789abc', '3636'), 'hDx8QRlUhwd6bU8N'), - (('0123456789abc', '3653'), 'vYOOtnkh1HXcMrM7'), - (('0123456789abc', 'user'), 'f4/.SALxqDo59mfV'), - (('0123456789abc', 'user1234'), 'f4/.SALxqDo59mfV'), - - # 14 char password - (('0123456789abcd', ''), '6r8888iMxEoPdLp4'), - (('0123456789abcd', '3'), 'f5lvmqWYj9gJqkIH'), - (('0123456789abcd', '36'), 'OJJ1Khg5HeAYBH1c'), - (('0123456789abcd', '365'), 'OJJ1Khg5HeAYBH1c'), - (('0123456789abcd', '3333'), 'f5lvmqWYj9gJqkIH'), - (('0123456789abcd', '3636'), 'OJJ1Khg5HeAYBH1c'), - (('0123456789abcd', '3653'), 'OJJ1Khg5HeAYBH1c'), - (('0123456789abcd', 'adm'), 'DbPLCFIkHc2SiyDk'), - (('0123456789abcd', 'adma'), 'DbPLCFIkHc2SiyDk'), - (('0123456789abcd', 'user'), 'WfO2UiTapPkF/FSn'), - (('0123456789abcd', 'user1234'), 'WfO2UiTapPkF/FSn'), - - # 15 char password - (('0123456789abcde', ''), 'al1e0XFIugTYLai3'), - (('0123456789abcde', '3'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', '36'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', '365'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', '3333'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', '3636'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', '3653'), 'lYbwBu.f82OIApQB'), - (('0123456789abcde', 'adm'), 'KgKx1UQvdR/09i9u'), - (('0123456789abcde', 'adma'), 'KgKx1UQvdR/09i9u'), - (('0123456789abcde', 'user'), 'qLopkenJ4WBqxaZN'), - (('0123456789abcde', 'user1234'), 'qLopkenJ4WBqxaZN'), - - # 16 char password - (('0123456789abcdef', ''), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', '36'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', '365'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', '3333'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', '3636'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', '3653'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', 'user'), '.7nfVBEIEu4KbF/1'), - (('0123456789abcdef', 'user1234'), '.7nfVBEIEu4KbF/1'), - ] - - -#============================================================================= -# cisco asa -#============================================================================= -class cisco_asa_test(_PixAsaSharedTest): - handler = hash.cisco_asa - - known_correct_hashes = _PixAsaSharedTest.pix_asa_shared_hashes + [ - # - # passlib reference vectors (ASA-specific) - # - # NOTE: See 'pix_asa_shared_hashes' for general PIX+ASA vectors, - # and general notes about the 'passlib reference vectors' test set. - # - - # 13 char password - # NOTE: past this point, ASA pads to 32 bytes instead of 16 - # for all cases where user is set (secret + 4 bytes > 16), - # but still uses 16 bytes for enable pwds (secret <= 16). - # hashes w/ user WON'T match PIX, but "enable" passwords will. - (('0123456789abc', ''), 'eacOpB7vE7ZDukSF'), # confirmed ASA 9.6 - (('0123456789abc', '36'), 'FRV9JG18UBEgX0.O'), - (('0123456789abc', '365'), 'NIwkusG9hmmMy6ZQ'), # confirmed ASA 9.6 - (('0123456789abc', '3333'), 'NmrkP98nT7RAeKZz'), # confirmed ASA 9.6 - (('0123456789abc', '3636'), 'FRV9JG18UBEgX0.O'), # confirmed ASA 9.6 - (('0123456789abc', '3653'), 'NIwkusG9hmmMy6ZQ'), # confirmed ASA 9.6 - (('0123456789abc', 'user'), '8Q/FZeam5ai1A47p'), # confirmed ASA 9.6 - (('0123456789abc', 'user1234'), '8Q/FZeam5ai1A47p'), # confirmed ASA 9.6 - - # 14 char password - (('0123456789abcd', ''), '6r8888iMxEoPdLp4'), # confirmed ASA 9.6 - (('0123456789abcd', '3'), 'yxGoujXKPduTVaYB'), - (('0123456789abcd', '36'), 'W0jckhnhjnr/DiT/'), - (('0123456789abcd', '365'), 'HuVOxfMQNahaoF8u'), # confirmed ASA 9.6 - (('0123456789abcd', '3333'), 'yxGoujXKPduTVaYB'), # confirmed ASA 9.6 - (('0123456789abcd', '3636'), 'W0jckhnhjnr/DiT/'), # confirmed ASA 9.6 - (('0123456789abcd', '3653'), 'HuVOxfMQNahaoF8u'), # confirmed ASA 9.6 - (('0123456789abcd', 'adm'), 'RtOmSeoCs4AUdZqZ'), # confirmed ASA 9.6 - (('0123456789abcd', 'adma'), 'RtOmSeoCs4AUdZqZ'), # confirmed ASA 9.6 - (('0123456789abcd', 'user'), 'rrucwrcM0h25pr.m'), # confirmed ASA 9.6 - (('0123456789abcd', 'user1234'), 'rrucwrcM0h25pr.m'), # confirmed ASA 9.6 - - # 15 char password - (('0123456789abcde', ''), 'al1e0XFIugTYLai3'), # confirmed ASA 9.6 - (('0123456789abcde', '3'), 'nAZrQoHaL.fgrIqt'), - (('0123456789abcde', '36'), '2GxIQ6ICE795587X'), - (('0123456789abcde', '365'), 'QmDsGwCRBbtGEKqM'), # confirmed ASA 9.6 - (('0123456789abcde', '3333'), 'nAZrQoHaL.fgrIqt'), # confirmed ASA 9.6 - (('0123456789abcde', '3636'), '2GxIQ6ICE795587X'), # confirmed ASA 9.6 - (('0123456789abcde', '3653'), 'QmDsGwCRBbtGEKqM'), # confirmed ASA 9.6 - (('0123456789abcde', 'adm'), 'Aj2aP0d.nk62wl4m'), # confirmed ASA 9.6 - (('0123456789abcde', 'adma'), 'Aj2aP0d.nk62wl4m'), # confirmed ASA 9.6 - (('0123456789abcde', 'user'), 'etxiXfo.bINJcXI7'), # confirmed ASA 9.6 - (('0123456789abcde', 'user1234'), 'etxiXfo.bINJcXI7'), # confirmed ASA 9.6 - - # 16 char password - (('0123456789abcdef', ''), '.7nfVBEIEu4KbF/1'), # confirmed ASA 9.6 - (('0123456789abcdef', '36'), 'GhI8.yFSC5lwoafg'), - (('0123456789abcdef', '365'), 'KFBI6cNQauyY6h/G'), # confirmed ASA 9.6 - (('0123456789abcdef', '3333'), 'Ghdi1IlsswgYzzMH'), # confirmed ASA 9.6 - (('0123456789abcdef', '3636'), 'GhI8.yFSC5lwoafg'), # confirmed ASA 9.6 - (('0123456789abcdef', '3653'), 'KFBI6cNQauyY6h/G'), # confirmed ASA 9.6 - (('0123456789abcdef', 'user'), 'IneB.wc9sfRzLPoh'), # confirmed ASA 9.6 - (('0123456789abcdef', 'user1234'), 'IneB.wc9sfRzLPoh'), # confirmed ASA 9.6 - - # 17 char password - # NOTE: past this point, ASA pads to 32 bytes instead of 16 - # for ALL cases, since secret > 16 bytes even for enable pwds; - # and so none of these rest here should match PIX. - (('0123456789abcdefq', ''), 'bKshl.EN.X3CVFRQ'), # confirmed ASA 9.6 - (('0123456789abcdefq', '36'), 'JAeTXHs0n30svlaG'), - (('0123456789abcdefq', '365'), '4fKSSUBHT1ChGqHp'), # confirmed ASA 9.6 - (('0123456789abcdefq', '3333'), 'USEJbxI6.VY4ecBP'), # confirmed ASA 9.6 - (('0123456789abcdefq', '3636'), 'JAeTXHs0n30svlaG'), # confirmed ASA 9.6 - (('0123456789abcdefq', '3653'), '4fKSSUBHT1ChGqHp'), # confirmed ASA 9.6 - (('0123456789abcdefq', 'user'), '/dwqyD7nGdwSrDwk'), # confirmed ASA 9.6 - (('0123456789abcdefq', 'user1234'), '/dwqyD7nGdwSrDwk'), # confirmed ASA 9.6 - - # 27 char password - (('0123456789abcdefqwertyuiopa', ''), '4wp19zS3OCe.2jt5'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', '36'), 'PjUoGqWBKPyV9qOe'), - (('0123456789abcdefqwertyuiopa', '365'), 'bfCy6xFAe5O/gzvM'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', '3333'), 'rd/ZMuGTJFIb2BNG'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', '3636'), 'PjUoGqWBKPyV9qOe'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', '3653'), 'bfCy6xFAe5O/gzvM'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', 'user'), 'zynfWw3UtszxLMgL'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopa', 'user1234'), 'zynfWw3UtszxLMgL'), # confirmed ASA 9.6 - - # 28 char password - # NOTE: past this point, ASA stops appending the username AT ALL, - # even though there's still room for the first few chars. - (('0123456789abcdefqwertyuiopas', ''), 'W6nbOddI0SutTK7m'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopas', '36'), 'W6nbOddI0SutTK7m'), - (('0123456789abcdefqwertyuiopas', '365'), 'W6nbOddI0SutTK7m'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopas', 'user'), 'W6nbOddI0SutTK7m'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopas', 'user1234'), 'W6nbOddI0SutTK7m'), # confirmed ASA 9.6 - - # 32 char password - # NOTE: this is max size that ASA allows, and throws error for larger - (('0123456789abcdefqwertyuiopasdfgh', ''), '5hPT/iC6DnoBxo6a'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopasdfgh', '36'), '5hPT/iC6DnoBxo6a'), - (('0123456789abcdefqwertyuiopasdfgh', '365'), '5hPT/iC6DnoBxo6a'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopasdfgh', 'user'), '5hPT/iC6DnoBxo6a'), # confirmed ASA 9.6 - (('0123456789abcdefqwertyuiopasdfgh', 'user1234'), '5hPT/iC6DnoBxo6a'), # confirmed ASA 9.6 - ] - - -#============================================================================= -# cisco type 7 -#============================================================================= -class cisco_type7_test(HandlerCase): - handler = hash.cisco_type7 - salt_bits = 4 - salt_type = int - - known_correct_hashes = [ - # - # http://mccltd.net/blog/?p=1034 - # - ("secure ", "04480E051A33490E"), - - # - # http://insecure.org/sploits/cisco.passwords.html - # - ("Its time to go to lunch!", - "153B1F1F443E22292D73212D5300194315591954465A0D0B59"), - - # - # http://blog.ioshints.info/2007/11/type-7-decryption-in-cisco-ios.html - # - ("t35t:pa55w0rd", "08351F1B1D431516475E1B54382F"), - - # - # http://www.m00nie.com/2011/09/cisco-type-7-password-decryption-and-encryption-with-perl/ - # - ("hiImTesting:)", "020E0D7206320A325847071E5F5E"), - - # - # http://packetlife.net/forums/thread/54/ - # - ("cisco123", "060506324F41584B56"), - ("cisco123", "1511021F07257A767B"), - - # - # source ? - # - ('Supe&8ZUbeRp4SS', "06351A3149085123301517391C501918"), - - # - # custom - # - - # ensures utf-8 used for unicode - (UPASS_TABLE, '0958EDC8A9F495F6F8A5FD'), - ] - - known_unidentified_hashes = [ - # salt with hex value - "0A480E051A33490E", - - # salt value > 52. this may in fact be valid, but we reject it for now - # (see docs for more). - '99400E4812', - ] - - def test_90_decode(self): - """test cisco_type7.decode()""" - from passlib.utils import to_unicode, to_bytes - - handler = self.handler - for secret, hash in self.known_correct_hashes: - usecret = to_unicode(secret) - bsecret = to_bytes(secret) - self.assertEqual(handler.decode(hash), usecret) - self.assertEqual(handler.decode(hash, None), bsecret) - - self.assertRaises(UnicodeDecodeError, handler.decode, - '0958EDC8A9F495F6F8A5FD', 'ascii') - - def test_91_salt(self): - """test salt value border cases""" - handler = self.handler - self.assertRaises(TypeError, handler, salt=None) - handler(salt=None, use_defaults=True) - self.assertRaises(TypeError, handler, salt='abc') - self.assertRaises(ValueError, handler, salt=-10) - self.assertRaises(ValueError, handler, salt=100) - - self.assertRaises(TypeError, handler.using, salt='abc') - self.assertRaises(ValueError, handler.using, salt=-10) - self.assertRaises(ValueError, handler.using, salt=100) - with self.assertWarningList("salt/offset must be.*"): - subcls = handler.using(salt=100, relaxed=True) - self.assertEqual(subcls(use_defaults=True).salt, 52) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_django.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_django.py deleted file mode 100644 index f7c9a0d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_django.py +++ /dev/null @@ -1,413 +0,0 @@ -"""passlib.tests.test_handlers_django - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -import re -import warnings -# site -# pkg -from passlib import hash -from passlib.utils import repeat_string -from passlib.utils.compat import u -from passlib.tests.utils import TestCase, HandlerCase, skipUnless, SkipTest -from passlib.tests.test_handlers import UPASS_USD, UPASS_TABLE -from passlib.tests.test_ext_django import DJANGO_VERSION, MIN_DJANGO_VERSION, \ - check_django_hasher_has_backend -# module - -#============================================================================= -# django -#============================================================================= - -# standard string django uses -UPASS_LETMEIN = u('l\xe8tmein') - -def vstr(version): - return ".".join(str(e) for e in version) - -class _DjangoHelper(TestCase): - """ - mixin for HandlerCase subclasses that are testing a hasher - which is also present in django. - """ - __unittest_skip = True - - #: minimum django version where hash alg is present / that we support testing against - min_django_version = MIN_DJANGO_VERSION - - #: max django version where hash alg is present - #: TODO: for a bunch of the tests below, this is just max version where - #: settings.PASSWORD_HASHERS includes it by default -- could add helper to patch - #: desired django hasher back in for duration of test. - #: XXX: change this to "disabled_in_django_version" instead? - max_django_version = None - - def _require_django_support(self): - # make sure min django version - if DJANGO_VERSION < self.min_django_version: - raise self.skipTest("Django >= %s not installed" % vstr(self.min_django_version)) - if self.max_django_version and DJANGO_VERSION > self.max_django_version: - raise self.skipTest("Django <= %s not installed" % vstr(self.max_django_version)) - - # make sure django has a backend for specified hasher - name = self.handler.django_name - if not check_django_hasher_has_backend(name): - raise self.skipTest('django hasher %r not available' % name) - - return True - - extra_fuzz_verifiers = HandlerCase.fuzz_verifiers + ( - "fuzz_verifier_django", - ) - - def fuzz_verifier_django(self): - try: - self._require_django_support() - except SkipTest: - return None - from django.contrib.auth.hashers import check_password - - def verify_django(secret, hash): - """django/check_password""" - if self.handler.name == "django_bcrypt" and hash.startswith("bcrypt$$2y$"): - hash = hash.replace("$$2y$", "$$2a$") - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - return check_password(secret, hash) - return verify_django - - def test_90_django_reference(self): - """run known correct hashes through Django's check_password()""" - self._require_django_support() - # XXX: esp. when it's no longer supported by django, - # should verify it's *NOT* recognized - from django.contrib.auth.hashers import check_password - assert self.known_correct_hashes - for secret, hash in self.iter_known_hashes(): - self.assertTrue(check_password(secret, hash), - "secret=%r hash=%r failed to verify" % - (secret, hash)) - self.assertFalse(check_password('x' + secret, hash), - "mangled secret=%r hash=%r incorrect verified" % - (secret, hash)) - - def test_91_django_generation(self): - """test against output of Django's make_password()""" - self._require_django_support() - # XXX: esp. when it's no longer supported by django, - # should verify it's *NOT* recognized - from passlib.utils import tick - from django.contrib.auth.hashers import make_password - name = self.handler.django_name # set for all the django_* handlers - end = tick() + self.max_fuzz_time/2 - generator = self.FuzzHashGenerator(self, self.getRandom()) - while tick() < end: - secret, other = generator.random_password_pair() - if not secret: # django rejects empty passwords. - continue - if isinstance(secret, bytes): - secret = secret.decode("utf-8") - hash = make_password(secret, hasher=name) - self.assertTrue(self.do_identify(hash)) - self.assertTrue(self.do_verify(secret, hash)) - self.assertFalse(self.do_verify(other, hash)) - -class django_disabled_test(HandlerCase): - """test django_disabled""" - handler = hash.django_disabled - disabled_contains_salt = True - - known_correct_hashes = [ - # *everything* should hash to "!", and nothing should verify - ("password", "!"), - ("", "!"), - (UPASS_TABLE, "!"), - ] - - known_alternate_hashes = [ - # django 1.6 appends random alpnum string - ("!9wa845vn7098ythaehasldkfj", "password", "!"), - ] - -class django_des_crypt_test(HandlerCase, _DjangoHelper): - """test django_des_crypt""" - handler = hash.django_des_crypt - max_django_version = (1,9) - - known_correct_hashes = [ - # ensures only first two digits of salt count. - ("password", 'crypt$c2$c2M87q...WWcU'), - ("password", 'crypt$c2e86$c2M87q...WWcU'), - ("passwordignoreme", 'crypt$c2.AZ$c2M87q...WWcU'), - - # ensures utf-8 used for unicode - (UPASS_USD, 'crypt$c2e86$c2hN1Bxd6ZiWs'), - (UPASS_TABLE, 'crypt$0.aQs$0.wB.TT0Czvlo'), - (u("hell\u00D6"), "crypt$sa$saykDgk3BPZ9E"), - - # prevent regression of issue 22 - ("foo", 'crypt$MNVY.9ajgdvDQ$MNVY.9ajgdvDQ'), - ] - - known_alternate_hashes = [ - # ensure django 1.4 empty salt field is accepted; - # but that salt field is re-filled (for django 1.0 compatibility) - ('crypt$$c2M87q...WWcU', "password", 'crypt$c2$c2M87q...WWcU'), - ] - - known_unidentified_hashes = [ - 'sha1$aa$bb', - ] - - known_malformed_hashes = [ - # checksum too short - 'crypt$c2$c2M87q', - - # salt must be >2 - 'crypt$f$c2M87q...WWcU', - - # make sure first 2 chars of salt & chk field agree. - 'crypt$ffe86$c2M87q...WWcU', - ] - -class django_salted_md5_test(HandlerCase, _DjangoHelper): - """test django_salted_md5""" - handler = hash.django_salted_md5 - max_django_version = (1,9) - - known_correct_hashes = [ - # test extra large salt - ("password", 'md5$123abcdef$c8272612932975ee80e8a35995708e80'), - - # test django 1.4 alphanumeric salt - ("test", 'md5$3OpqnFAHW5CT$54b29300675271049a1ebae07b395e20'), - - # ensures utf-8 used for unicode - (UPASS_USD, 'md5$c2e86$92105508419a81a6babfaecf876a2fa0'), - (UPASS_TABLE, 'md5$d9eb8$01495b32852bffb27cf5d4394fe7a54c'), - ] - - known_unidentified_hashes = [ - 'sha1$aa$bb', - ] - - known_malformed_hashes = [ - # checksum too short - 'md5$aa$bb', - ] - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_salt_size(self): - # workaround for django14 regression -- - # 1.4 won't accept hashes with empty salt strings, unlike 1.3 and earlier. - # looks to be fixed in a future release -- https://code.djangoproject.com/ticket/18144 - # for now, we avoid salt_size==0 under 1.4 - handler = self.handler - default = handler.default_salt_size - assert handler.min_salt_size == 0 - lower = 1 - upper = handler.max_salt_size or default*4 - return self.randintgauss(lower, upper, default, default*.5) - -class django_salted_sha1_test(HandlerCase, _DjangoHelper): - """test django_salted_sha1""" - handler = hash.django_salted_sha1 - max_django_version = (1,9) - - known_correct_hashes = [ - # test extra large salt - ("password",'sha1$123abcdef$e4a1877b0e35c47329e7ed7e58014276168a37ba'), - - # test django 1.4 alphanumeric salt - ("test", 'sha1$bcwHF9Hy8lxS$6b4cfa0651b43161c6f1471ce9523acf1f751ba3'), - - # ensures utf-8 used for unicode - (UPASS_USD, 'sha1$c2e86$0f75c5d7fbd100d587c127ef0b693cde611b4ada'), - (UPASS_TABLE, 'sha1$6d853$ef13a4d8fb57aed0cb573fe9c82e28dc7fd372d4'), - - # generic password - ("MyPassword", 'sha1$54123$893cf12e134c3c215f3a76bd50d13f92404a54d3'), - ] - - known_unidentified_hashes = [ - 'md5$aa$bb', - ] - - known_malformed_hashes = [ - # checksum too short - 'sha1$c2e86$0f75', - ] - - # reuse custom random_salt_size() helper... - FuzzHashGenerator = django_salted_md5_test.FuzzHashGenerator - -class django_pbkdf2_sha256_test(HandlerCase, _DjangoHelper): - """test django_pbkdf2_sha256""" - handler = hash.django_pbkdf2_sha256 - - known_correct_hashes = [ - # - # custom - generated via django 1.4 hasher - # - ('not a password', - 'pbkdf2_sha256$10000$kjVJaVz6qsnJ$5yPHw3rwJGECpUf70daLGhOrQ5+AMxIJdz1c3bqK1Rs='), - (UPASS_TABLE, - 'pbkdf2_sha256$10000$bEwAfNrH1TlQ$OgYUblFNUX1B8GfMqaCYUK/iHyO0pa7STTDdaEJBuY0='), - ] - -class django_pbkdf2_sha1_test(HandlerCase, _DjangoHelper): - """test django_pbkdf2_sha1""" - handler = hash.django_pbkdf2_sha1 - - known_correct_hashes = [ - # - # custom - generated via django 1.4 hashers - # - ('not a password', - 'pbkdf2_sha1$10000$wz5B6WkasRoF$atJmJ1o+XfJxKq1+Nu1f1i57Z5I='), - (UPASS_TABLE, - 'pbkdf2_sha1$10000$KZKWwvqb8BfL$rw5pWsxJEU4JrZAQhHTCO+u0f5Y='), - ] - -@skipUnless(hash.bcrypt.has_backend(), "no bcrypt backends available") -class django_bcrypt_test(HandlerCase, _DjangoHelper): - """test django_bcrypt""" - handler = hash.django_bcrypt - # XXX: not sure when this wasn't in default list anymore. somewhere in [2.0 - 2.2] - max_django_version = (2, 0) - fuzz_salts_need_bcrypt_repair = True - - known_correct_hashes = [ - # - # just copied and adapted a few test vectors from bcrypt (above), - # since django_bcrypt is just a wrapper for the real bcrypt class. - # - ('', 'bcrypt$$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s.'), - ('abcdefghijklmnopqrstuvwxyz', - 'bcrypt$$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq'), - (UPASS_TABLE, - 'bcrypt$$2a$05$Z17AXnnlpzddNUvnC6cZNOSwMA/8oNiKnHTHTwLlBijfucQQlHjaG'), - ] - - # NOTE: the following have been cloned from _bcrypt_test() - - def populate_settings(self, kwds): - # speed up test w/ lower rounds - kwds.setdefault("rounds", 4) - super(django_bcrypt_test, self).populate_settings(kwds) - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(5, 8, 6, 1) - - def random_ident(self): - # omit multi-ident tests, only $2a$ counts for this class - # XXX: enable this to check 2a / 2b? - return None - -@skipUnless(hash.bcrypt.has_backend(), "no bcrypt backends available") -class django_bcrypt_sha256_test(HandlerCase, _DjangoHelper): - """test django_bcrypt_sha256""" - handler = hash.django_bcrypt_sha256 - forbidden_characters = None - fuzz_salts_need_bcrypt_repair = True - - known_correct_hashes = [ - # - # custom - generated via django 1.6 hasher - # - ('', - 'bcrypt_sha256$$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu'), - (UPASS_LETMEIN, - 'bcrypt_sha256$$2a$08$NDjSAIcas.EcoxCRiArvT.MkNiPYVhrsrnJsRkLueZOoV1bsQqlmC'), - (UPASS_TABLE, - 'bcrypt_sha256$$2a$06$kCXUnRFQptGg491siDKNTu8RxjBGSjALHRuvhPYNFsa4Ea5d9M48u'), - - # test >72 chars is hashed correctly -- under bcrypt these hash the same. - (repeat_string("abc123",72), - 'bcrypt_sha256$$2a$06$Tg/oYyZTyAf.Nb3qSgN61OySmyXA8FoY4PjGizjE1QSDfuL5MXNni'), - (repeat_string("abc123",72)+"qwr", - 'bcrypt_sha256$$2a$06$Tg/oYyZTyAf.Nb3qSgN61Ocy0BEz1RK6xslSNi8PlaLX2pe7x/KQG'), - (repeat_string("abc123",72)+"xyz", - 'bcrypt_sha256$$2a$06$Tg/oYyZTyAf.Nb3qSgN61OvY2zoRVUa2Pugv2ExVOUT2YmhvxUFUa'), - ] - - known_malformed_hashers = [ - # data in django salt field - 'bcrypt_sha256$xyz$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu', - ] - - # NOTE: the following have been cloned from _bcrypt_test() - - def populate_settings(self, kwds): - # speed up test w/ lower rounds - kwds.setdefault("rounds", 4) - super(django_bcrypt_sha256_test, self).populate_settings(kwds) - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(5, 8, 6, 1) - - def random_ident(self): - # omit multi-ident tests, only $2a$ counts for this class - # XXX: enable this to check 2a / 2b? - return None - -from passlib.tests.test_handlers_argon2 import _base_argon2_test - -@skipUnless(hash.argon2.has_backend(), "no argon2 backends available") -class django_argon2_test(HandlerCase, _DjangoHelper): - """test django_bcrypt""" - handler = hash.django_argon2 - - # NOTE: most of this adapted from _base_argon2_test & argon2pure test - - known_correct_hashes = [ - # sample test - ("password", 'argon2$argon2i$v=19$m=256,t=1,p=1$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A'), - - # sample w/ all parameters different - ("password", 'argon2$argon2i$v=19$m=380,t=2,p=2$c29tZXNhbHQ$SrssP8n7m/12VWPM8dvNrw'), - - # generated from django 1.10.3 - (UPASS_LETMEIN, 'argon2$argon2i$v=19$m=512,t=2,p=2$V25jN1l4UUJZWkR1$MxpA1BD2Gh7+D79gaAw6sQ'), - ] - - def setUpWarnings(self): - super(django_argon2_test, self).setUpWarnings() - warnings.filterwarnings("ignore", ".*Using argon2pure backend.*") - - def do_stub_encrypt(self, handler=None, **settings): - # overriding default since no way to get stub config from argon2._calc_hash() - # (otherwise test_21b_max_rounds blocks trying to do max rounds) - handler = (handler or self.handler).using(**settings) - self = handler.wrapped(use_defaults=True) - self.checksum = self._stub_checksum - assert self.checksum - return handler._wrap_hash(self.to_string()) - - def test_03_legacy_hash_workflow(self): - # override base method - raise self.skipTest("legacy 1.6 workflow not supported") - - class FuzzHashGenerator(_base_argon2_test.FuzzHashGenerator): - - def random_type(self): - # override default since django only uses type I (see note in class) - return "I" - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(1, 3, 2, 1) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_pbkdf2.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_pbkdf2.py deleted file mode 100644 index 4d2f048..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_pbkdf2.py +++ /dev/null @@ -1,480 +0,0 @@ -"""passlib.tests.test_handlers - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -# core -import logging -log = logging.getLogger(__name__) -import warnings -# site -# pkg -from passlib import hash -from passlib.utils.compat import u -from passlib.tests.utils import TestCase, HandlerCase -from passlib.tests.test_handlers import UPASS_WAV -# module - -#============================================================================= -# ldap_pbkdf2_{digest} -#============================================================================= -# NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs, -# they don't extensive separate testing. - -class ldap_pbkdf2_test(TestCase): - - def test_wrappers(self): - """test ldap pbkdf2 wrappers""" - - self.assertTrue( - hash.ldap_pbkdf2_sha1.verify( - "password", - '{PBKDF2}1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI', - ) - ) - - self.assertTrue( - hash.ldap_pbkdf2_sha256.verify( - "password", - '{PBKDF2-SHA256}1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg' - '.fJPeq1h/gXXY7acBp9/6c.tmQ' - ) - ) - - self.assertTrue( - hash.ldap_pbkdf2_sha512.verify( - "password", - '{PBKDF2-SHA512}1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1' - '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww' - ) - ) - -#============================================================================= -# pbkdf2 hashes -#============================================================================= -class atlassian_pbkdf2_sha1_test(HandlerCase): - handler = hash.atlassian_pbkdf2_sha1 - - known_correct_hashes = [ - # - # generated using Jira - # - ("admin", '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/p'), - (UPASS_WAV, - "{PKCS5S2}cE9Yq6Am5tQGdHSHhky2XLeOnURwzaLBG2sur7FHKpvy2u0qDn6GcVGRjlmJoIUy"), - ] - - known_malformed_hashes = [ - # bad char ---\/ - '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy!0IPksHChwoTAVYFrhsgoq8/p' - - # bad size, missing padding - '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/' - - # bad size, with correct padding - '{PKCS5S2}c4xaeTQM0lUieMS3V5voiexyX9XhqC2dBd5ecVy60IPksHChwoTAVYFrhsgoq8/=' - ] - -class pbkdf2_sha1_test(HandlerCase): - handler = hash.pbkdf2_sha1 - known_correct_hashes = [ - ("password", '$pbkdf2$1212$OB.dtnSEXZK8U5cgxU/GYQ$y5LKPOplRmok7CZp/aqVDVg8zGI'), - (UPASS_WAV, - '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc'), - ] - - known_malformed_hashes = [ - # zero padded rounds field - '$pbkdf2$01212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc', - - # empty rounds field - '$pbkdf2$$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc', - - # too many field - '$pbkdf2$1212$THDqatpidANpadlLeTeOEg$HV3oi1k5C5LQCgG1BMOL.BX4YZc$', - ] - -class pbkdf2_sha256_test(HandlerCase): - handler = hash.pbkdf2_sha256 - known_correct_hashes = [ - ("password", - '$pbkdf2-sha256$1212$4vjV83LKPjQzk31VI4E0Vw$hsYF68OiOUPdDZ1Fg.fJPeq1h/gXXY7acBp9/6c.tmQ' - ), - (UPASS_WAV, - '$pbkdf2-sha256$1212$3SABFJGDtyhrQMVt1uABPw$WyaUoqCLgvz97s523nF4iuOqZNbp5Nt8do/cuaa7AiI' - ), - ] - -class pbkdf2_sha512_test(HandlerCase): - handler = hash.pbkdf2_sha512 - known_correct_hashes = [ - ("password", - '$pbkdf2-sha512$1212$RHY0Fr3IDMSVO/RSZyb5ow$eNLfBK.eVozomMr.1gYa1' - '7k9B7KIK25NOEshvhrSX.esqY3s.FvWZViXz4KoLlQI.BzY/YTNJOiKc5gBYFYGww' - ), - (UPASS_WAV, - '$pbkdf2-sha512$1212$KkbvoKGsAIcF8IslDR6skQ$8be/PRmd88Ps8fmPowCJt' - 'tH9G3vgxpG.Krjt3KT.NP6cKJ0V4Prarqf.HBwz0dCkJ6xgWnSj2ynXSV7MlvMa8Q' - ), - ] - -class cta_pbkdf2_sha1_test(HandlerCase): - handler = hash.cta_pbkdf2_sha1 - known_correct_hashes = [ - # - # test vectors from original implementation - # - (u("hashy the \N{SNOWMAN}"), '$p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0='), - - # - # custom - # - ("password", "$p5k2$1$$h1TDLGSw9ST8UMAPeIE13i0t12c="), - (UPASS_WAV, - "$p5k2$4321$OTg3NjU0MzIx$jINJrSvZ3LXeIbUdrJkRpN62_WQ="), - ] - -class dlitz_pbkdf2_sha1_test(HandlerCase): - handler = hash.dlitz_pbkdf2_sha1 - known_correct_hashes = [ - # - # test vectors from original implementation - # - ('cloadm', '$p5k2$$exec$r1EWMCMk7Rlv3L/RNcFXviDefYa0hlql'), - ('gnu', '$p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g'), - ('dcl', '$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL'), - ('spam', '$p5k2$3e8$H0NX9mT/$wk/sE8vv6OMKuMaqazCJYDSUhWY9YB2J'), - (UPASS_WAV, - '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ'), - ] - -class grub_pbkdf2_sha512_test(HandlerCase): - handler = hash.grub_pbkdf2_sha512 - known_correct_hashes = [ - # - # test vectors generated from cmd line tool - # - - # salt=32 bytes - (UPASS_WAV, - 'grub.pbkdf2.sha512.10000.BCAC1CEC5E4341C8C511C529' - '7FA877BE91C2817B32A35A3ECF5CA6B8B257F751.6968526A' - '2A5B1AEEE0A29A9E057336B48D388FFB3F600233237223C21' - '04DE1752CEC35B0DD1ED49563398A282C0F471099C2803FBA' - '47C7919CABC43192C68F60'), - - # salt=64 bytes - ('toomanysecrets', - 'grub.pbkdf2.sha512.10000.9B436BB6978682363D5C449B' - 'BEAB322676946C632208BC1294D51F47174A9A3B04A7E4785' - '986CD4EA7470FAB8FE9F6BD522D1FC6C51109A8596FB7AD48' - '7C4493.0FE5EF169AFFCB67D86E2581B1E251D88C777B98BA' - '2D3256ECC9F765D84956FC5CA5C4B6FD711AA285F0A04DCF4' - '634083F9A20F4B6F339A52FBD6BED618E527B'), - - ] - -#============================================================================= -# scram hash -#============================================================================= -class scram_test(HandlerCase): - handler = hash.scram - - # TODO: need a bunch more reference vectors from some real - # SCRAM transactions. - known_correct_hashes = [ - # - # taken from example in SCRAM specification (rfc 5802) - # - ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'), - - # - # custom - # - - # same as 5802 example hash, but with sha-256 & sha-512 added. - ('pencil', '$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,' - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'), - - # test unicode passwords & saslprep (all the passwords below - # should normalize to the same value: 'IX \xE0') - (u('IX \xE0'), '$scram$6400$0BojBCBE6P2/N4bQ$' - 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'), - (u('\u2168\u3000a\u0300'), '$scram$6400$0BojBCBE6P2/N4bQ$' - 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'), - (u('\u00ADIX \xE0'), '$scram$6400$0BojBCBE6P2/N4bQ$' - 'sha-1=YniLes.b8WFMvBhtSACZyyvxeCc'), - ] - - known_malformed_hashes = [ - # zero-padding in rounds - '$scram$04096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', - - # non-digit in rounds - '$scram$409A$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', - - # bad char in salt ---\/ - '$scram$4096$QSXCR.Q6sek8bf9-$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', - - # bad char in digest ---\/ - '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX3-', - - # missing sections - '$scram$4096$QSXCR.Q6sek8bf92', - '$scram$4096$QSXCR.Q6sek8bf92$', - - # too many sections - '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30$', - - # missing separator - '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY', - - # too many chars in alg name - '$scram$4096$QSXCR.Q6sek8bf92$sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'shaxxx-190=HZbuOlKbWl.eR8AfIposuKbhX30', - - # missing sha-1 alg - '$scram$4096$QSXCR.Q6sek8bf92$sha-256=HZbuOlKbWl.eR8AfIposuKbhX30', - - # non-iana name - '$scram$4096$QSXCR.Q6sek8bf92$sha1=HZbuOlKbWl.eR8AfIposuKbhX30', - ] - - def setUp(self): - super(scram_test, self).setUp() - - # some platforms lack stringprep (e.g. Jython, IronPython) - self.require_stringprep() - - # silence norm_hash_name() warning - warnings.filterwarnings("ignore", r"norm_hash_name\(\): unknown hash") - - def test_90_algs(self): - """test parsing of 'algs' setting""" - defaults = dict(salt=b'A'*10, rounds=1000) - def parse(algs, **kwds): - for k in defaults: - kwds.setdefault(k, defaults[k]) - return self.handler(algs=algs, **kwds).algs - - # None -> default list - self.assertEqual(parse(None, use_defaults=True), hash.scram.default_algs) - self.assertRaises(TypeError, parse, None) - - # strings should be parsed - self.assertEqual(parse("sha1"), ["sha-1"]) - self.assertEqual(parse("sha1, sha256, md5"), ["md5","sha-1","sha-256"]) - - # lists should be normalized - self.assertEqual(parse(["sha-1","sha256"]), ["sha-1","sha-256"]) - - # sha-1 required - self.assertRaises(ValueError, parse, ["sha-256"]) - self.assertRaises(ValueError, parse, algs=[], use_defaults=True) - - # alg names must be < 10 chars - self.assertRaises(ValueError, parse, ["sha-1","shaxxx-190"]) - - # alg & checksum mutually exclusive. - self.assertRaises(RuntimeError, parse, ['sha-1'], - checksum={"sha-1": b"\x00"*20}) - - def test_90_checksums(self): - """test internal parsing of 'checksum' keyword""" - # check non-bytes checksum values are rejected - self.assertRaises(TypeError, self.handler, use_defaults=True, - checksum={'sha-1': u('X')*20}) - - # check sha-1 is required - self.assertRaises(ValueError, self.handler, use_defaults=True, - checksum={'sha-256': b'X'*32}) - - # XXX: anything else that's not tested by the other code already? - - def test_91_extract_digest_info(self): - """test scram.extract_digest_info()""" - edi = self.handler.extract_digest_info - - # return appropriate value or throw KeyError - h = "$scram$10$AAAAAA$sha-1=AQ,bbb=Ag,ccc=Aw" - s = b'\x00'*4 - self.assertEqual(edi(h,"SHA1"), (s,10, b'\x01')) - self.assertEqual(edi(h,"bbb"), (s,10, b'\x02')) - self.assertEqual(edi(h,"ccc"), (s,10, b'\x03')) - self.assertRaises(KeyError, edi, h, "ddd") - - # config strings should cause value error. - c = "$scram$10$....$sha-1,bbb,ccc" - self.assertRaises(ValueError, edi, c, "sha-1") - self.assertRaises(ValueError, edi, c, "bbb") - self.assertRaises(ValueError, edi, c, "ddd") - - def test_92_extract_digest_algs(self): - """test scram.extract_digest_algs()""" - eda = self.handler.extract_digest_algs - - self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30'), ["sha-1"]) - - self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30', format="hashlib"), - ["sha1"]) - - self.assertEqual(eda('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,' - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ'), - ["sha-1","sha-256","sha-512"]) - - def test_93_derive_digest(self): - """test scram.derive_digest()""" - # NOTE: this just does a light test, since derive_digest - # is used by hash / verify, and is tested pretty well via those. - hash = self.handler.derive_digest - - # check various encodings of password work. - s1 = b'\x01\x02\x03' - d1 = b'\xb2\xfb\xab\x82[tNuPnI\x8aZZ\x19\x87\xcen\xe9\xd3' - self.assertEqual(hash(u("\u2168"), s1, 1000, 'sha-1'), d1) - self.assertEqual(hash(b"\xe2\x85\xa8", s1, 1000, 'SHA-1'), d1) - self.assertEqual(hash(u("IX"), s1, 1000, 'sha1'), d1) - self.assertEqual(hash(b"IX", s1, 1000, 'SHA1'), d1) - - # check algs - self.assertEqual(hash("IX", s1, 1000, 'md5'), - b'3\x19\x18\xc0\x1c/\xa8\xbf\xe4\xa3\xc2\x8eM\xe8od') - self.assertRaises(ValueError, hash, "IX", s1, 1000, 'sha-666') - - # check rounds - self.assertRaises(ValueError, hash, "IX", s1, 0, 'sha-1') - - # unicode salts accepted as of passlib 1.7 (previous caused TypeError) - self.assertEqual(hash(u("IX"), s1.decode("latin-1"), 1000, 'sha1'), d1) - - def test_94_saslprep(self): - """test hash/verify use saslprep""" - # NOTE: this just does a light test that saslprep() is being - # called in various places, relying in saslpreps()'s tests - # to verify full normalization behavior. - - # hash unnormalized - h = self.do_encrypt(u("I\u00ADX")) - self.assertTrue(self.do_verify(u("IX"), h)) - self.assertTrue(self.do_verify(u("\u2168"), h)) - - # hash normalized - h = self.do_encrypt(u("\xF3")) - self.assertTrue(self.do_verify(u("o\u0301"), h)) - self.assertTrue(self.do_verify(u("\u200Do\u0301"), h)) - - # throws error if forbidden char provided - self.assertRaises(ValueError, self.do_encrypt, u("\uFDD0")) - self.assertRaises(ValueError, self.do_verify, u("\uFDD0"), h) - - def test_94_using_w_default_algs(self, param="default_algs"): - """using() -- 'default_algs' parameter""" - # create subclass - handler = self.handler - orig = list(handler.default_algs) # in case it's modified in place - subcls = handler.using(**{param: "sha1,md5"}) - - # shouldn't have changed handler - self.assertEqual(handler.default_algs, orig) - - # should have own set - self.assertEqual(subcls.default_algs, ["md5", "sha-1"]) - - # test hash output - h1 = subcls.hash("dummy") - self.assertEqual(handler.extract_digest_algs(h1), ["md5", "sha-1"]) - - def test_94_using_w_algs(self): - """using() -- 'algs' parameter""" - self.test_94_using_w_default_algs(param="algs") - - def test_94_needs_update_algs(self): - """needs_update() -- algs setting""" - handler1 = self.handler.using(algs="sha1,md5") - - # shouldn't need update, has same algs - h1 = handler1.hash("dummy") - self.assertFalse(handler1.needs_update(h1)) - - # *currently* shouldn't need update, has superset of algs required by handler2 - # (may change this policy) - handler2 = handler1.using(algs="sha1") - self.assertFalse(handler2.needs_update(h1)) - - # should need update, doesn't have all algs required by handler3 - handler3 = handler1.using(algs="sha1,sha256") - self.assertTrue(handler3.needs_update(h1)) - - def test_95_context_algs(self): - """test handling of 'algs' in context object""" - handler = self.handler - from passlib.context import CryptContext - c1 = CryptContext(["scram"], scram__algs="sha1,md5") - - h = c1.hash("dummy") - self.assertEqual(handler.extract_digest_algs(h), ["md5", "sha-1"]) - self.assertFalse(c1.needs_update(h)) - - c2 = c1.copy(scram__algs="sha1") - self.assertFalse(c2.needs_update(h)) - - c2 = c1.copy(scram__algs="sha1,sha256") - self.assertTrue(c2.needs_update(h)) - - def test_96_full_verify(self): - """test verify(full=True) flag""" - def vpart(s, h): - return self.handler.verify(s, h) - def vfull(s, h): - return self.handler.verify(s, h, full=True) - - # reference - h = ('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVY,' - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ') - self.assertTrue(vfull('pencil', h)) - self.assertFalse(vfull('tape', h)) - - # catch truncated digests. - h = ('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhV,' # -1 char - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ') - self.assertRaises(ValueError, vfull, 'pencil', h) - - # catch padded digests. - h = ('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' - 'sha-256=qXUXrlcvnaxxWG00DdRgVioR2gnUpuX5r.3EZ1rdhVYa,' # +1 char - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ') - self.assertRaises(ValueError, vfull, 'pencil', h) - - # catch hash containing digests belonging to diff passwords. - # proper behavior for quick-verify (the default) is undefined, - # but full-verify should throw error. - h = ('$scram$4096$QSXCR.Q6sek8bf92$' - 'sha-1=HZbuOlKbWl.eR8AfIposuKbhX30,' # 'pencil' - 'sha-256=R7RJDWIbeKRTFwhE9oxh04kab0CllrQ3kCcpZUcligc,' # 'tape' - 'sha-512=lzgniLFcvglRLS0gt.C4gy.NurS3OIOVRAU1zZOV4P.qFiVFO2/' # 'pencil' - 'edGQSu/kD1LwdX0SNV/KsPdHSwEl5qRTuZQ') - self.assertTrue(vpart('tape', h)) - self.assertFalse(vpart('pencil', h)) - self.assertRaises(ValueError, vfull, 'pencil', h) - self.assertRaises(ValueError, vfull, 'tape', h) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_scrypt.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_scrypt.py deleted file mode 100644 index 5ab6d9f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_handlers_scrypt.py +++ /dev/null @@ -1,111 +0,0 @@ -"""passlib.tests.test_handlers - tests for passlib hash algorithms""" -#============================================================================= -# imports -#============================================================================= -# core -import logging; log = logging.getLogger(__name__) -import warnings -warnings.filterwarnings("ignore", ".*using builtin scrypt backend.*") -# site -# pkg -from passlib import hash -from passlib.tests.utils import HandlerCase, TEST_MODE -from passlib.tests.test_handlers import UPASS_TABLE, PASS_TABLE_UTF8 -# module - -#============================================================================= -# scrypt hash -#============================================================================= -class _scrypt_test(HandlerCase): - handler = hash.scrypt - - known_correct_hashes = [ - # - # excepted from test vectors from scrypt whitepaper - # (http://www.tarsnap.com/scrypt/scrypt.pdf, appendix b), - # and encoded using passlib's custom format - # - - # salt=b"" - ("", "$scrypt$ln=4,r=1,p=1$$d9ZXYjhleyA7GcpCwYoEl/FrSETjB0ro39/6P+3iFEI"), - - # salt=b"NaCl" - ("password", "$scrypt$ln=10,r=8,p=16$TmFDbA$/bq+HJ00cgB4VucZDQHp/nxq18vII3gw53N2Y0s3MWI"), - - # - # custom - # - - # simple test - ("test", '$scrypt$ln=8,r=8,p=1$wlhLyXmP8b53bm1NKYVQqg$mTpvG8lzuuDk+DWz8HZIB6Vum6erDuUm0As5yU+VxWA'), - - # different block value - ("password", '$scrypt$ln=8,r=2,p=1$dO6d0xoDoLT2PofQGoNQag$g/Wf2A0vhHhaJM+addK61QPBthSmYB6uVTtQzh8CM3o'), - - # different rounds - (UPASS_TABLE, '$scrypt$ln=7,r=8,p=1$jjGmtDamdA4BQAjBeA9BSA$OiWRHhQtpDx7M/793x6UXK14AD512jg/qNm/hkWZG4M'), - - # alt encoding - (PASS_TABLE_UTF8, '$scrypt$ln=7,r=8,p=1$jjGmtDamdA4BQAjBeA9BSA$OiWRHhQtpDx7M/793x6UXK14AD512jg/qNm/hkWZG4M'), - - # diff block & parallel counts as well - ("nacl", '$scrypt$ln=1,r=4,p=2$yhnD+J+Tci4lZCwFgHCuVQ$fAsEWmxSHuC0cHKMwKVFPzrQukgvK09Sj+NueTSxKds') - ] - - if TEST_MODE("full"): - # add some hashes with larger rounds value. - known_correct_hashes.extend([ - # - # from scrypt whitepaper - # - - # salt=b"SodiumChloride" - ("pleaseletmein", "$scrypt$ln=14,r=8,p=1$U29kaXVtQ2hsb3JpZGU" - "$cCO9yzr9c0hGHAbNgf046/2o+7qQT44+qbVD9lRdofI"), - - # - # openwall format (https://gitlab.com/jas/scrypt-unix-crypt/blob/master/unix-scrypt.txt) - # - ("pleaseletmein", - "$7$C6..../....SodiumChloride$kBGj9fHznVYFQMEn/qDCfrDevf9YDtcDdKvEqHJLV8D"), - - ]) - - known_malformed_hashes = [ - # missing 'p' value - '$scrypt$ln=10,r=1$wvif8/4fg1Cq9V7L2dv73w$bJcLia1lyfQ1X2x0xflehwVXPzWIUQWWdnlGwfVzBeQ', - - # rounds too low - '$scrypt$ln=0,r=1,p=1$wvif8/4fg1Cq9V7L2dv73w$bJcLia1lyfQ1X2x0xflehwVXPzWIUQWWdnlGwfVzBeQ', - - # invalid block size - '$scrypt$ln=10,r=A,p=1$wvif8/4fg1Cq9V7L2dv73w$bJcLia1lyfQ1X2x0xflehwVXPzWIUQWWdnlGwfVzBeQ', - - # r*p too large - '$scrypt$ln=10,r=134217728,p=8$wvif8/4fg1Cq9V7L2dv73w$bJcLia1lyfQ1X2x0xflehwVXPzWIUQWWdnlGwfVzBeQ', - ] - - def setUpWarnings(self): - super(_scrypt_test, self).setUpWarnings() - warnings.filterwarnings("ignore", ".*using builtin scrypt backend.*") - - def populate_settings(self, kwds): - # builtin is still just way too slow. - if self.backend == "builtin": - kwds.setdefault("rounds", 6) - super(_scrypt_test, self).populate_settings(kwds) - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - def random_rounds(self): - # decrease default rounds for fuzz testing to speed up volume. - return self.randintgauss(4, 10, 6, 1) - -# create test cases for specific backends -scrypt_stdlib_test = _scrypt_test.create_backend_case("stdlib") -scrypt_scrypt_test = _scrypt_test.create_backend_case("scrypt") -scrypt_builtin_test = _scrypt_test.create_backend_case("builtin") - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_hosts.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_hosts.py deleted file mode 100644 index cbf93ab..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_hosts.py +++ /dev/null @@ -1,97 +0,0 @@ -"""test passlib.hosts""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib import hosts, hash as hashmod -from passlib.utils import unix_crypt_schemes -from passlib.tests.utils import TestCase -# module - -#============================================================================= -# test predefined app contexts -#============================================================================= -class HostsTest(TestCase): - """perform general tests to make sure contexts work""" - # NOTE: these tests are not really comprehensive, - # since they would do little but duplicate - # the presets in apps.py - # - # they mainly try to ensure no typos - # or dynamic behavior foul-ups. - - def check_unix_disabled(self, ctx): - for hash in [ - "", - "!", - "*", - "!$1$TXl/FX/U$BZge.lr.ux6ekjEjxmzwz0", - ]: - self.assertEqual(ctx.identify(hash), 'unix_disabled') - self.assertFalse(ctx.verify('test', hash)) - - def test_linux_context(self): - ctx = hosts.linux_context - for hash in [ - ('$6$rounds=41128$VoQLvDjkaZ6L6BIE$4pt.1Ll1XdDYduEwEYPCMOBiR6W6' - 'znsyUEoNlcVXpv2gKKIbQolgmTGe6uEEVJ7azUxuc8Tf7zV9SD2z7Ij751'), - ('$5$rounds=31817$iZGmlyBQ99JSB5n6$p4E.pdPBWx19OajgjLRiOW0itGny' - 'xDGgMlDcOsfaI17'), - '$1$TXl/FX/U$BZge.lr.ux6ekjEjxmzwz0', - 'kAJJz.Rwp0A/I', - ]: - self.assertTrue(ctx.verify("test", hash)) - self.check_unix_disabled(ctx) - - def test_bsd_contexts(self): - for ctx in [ - hosts.freebsd_context, - hosts.openbsd_context, - hosts.netbsd_context, - ]: - for hash in [ - '$1$TXl/FX/U$BZge.lr.ux6ekjEjxmzwz0', - 'kAJJz.Rwp0A/I', - ]: - self.assertTrue(ctx.verify("test", hash)) - h1 = "$2a$04$yjDgE74RJkeqC0/1NheSSOrvKeu9IbKDpcQf/Ox3qsrRS/Kw42qIS" - if hashmod.bcrypt.has_backend(): - self.assertTrue(ctx.verify("test", h1)) - else: - self.assertEqual(ctx.identify(h1), "bcrypt") - self.check_unix_disabled(ctx) - - def test_host_context(self): - ctx = getattr(hosts, "host_context", None) - if not ctx: - return self.skipTest("host_context not available on this platform") - - # validate schemes is non-empty, - # and contains unix_disabled + at least one real scheme - schemes = list(ctx.schemes()) - self.assertTrue(schemes, "appears to be unix system, but no known schemes supported by crypt") - self.assertTrue('unix_disabled' in schemes) - schemes.remove("unix_disabled") - self.assertTrue(schemes, "should have schemes beside fallback scheme") - self.assertTrue(set(unix_crypt_schemes).issuperset(schemes)) - - # check for hash support - self.check_unix_disabled(ctx) - for scheme, hash in [ - ("sha512_crypt", ('$6$rounds=41128$VoQLvDjkaZ6L6BIE$4pt.1Ll1XdDYduEwEYPCMOBiR6W6' - 'znsyUEoNlcVXpv2gKKIbQolgmTGe6uEEVJ7azUxuc8Tf7zV9SD2z7Ij751')), - ("sha256_crypt", ('$5$rounds=31817$iZGmlyBQ99JSB5n6$p4E.pdPBWx19OajgjLRiOW0itGny' - 'xDGgMlDcOsfaI17')), - ("md5_crypt", '$1$TXl/FX/U$BZge.lr.ux6ekjEjxmzwz0'), - ("des_crypt", 'kAJJz.Rwp0A/I'), - ]: - if scheme in schemes: - self.assertTrue(ctx.verify("test", hash)) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_pwd.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_pwd.py deleted file mode 100644 index 2c983cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_pwd.py +++ /dev/null @@ -1,205 +0,0 @@ -"""passlib.tests -- tests for passlib.pwd""" -#============================================================================= -# imports -#============================================================================= -# core -import itertools -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.tests.utils import TestCase -# local -__all__ = [ - "UtilsTest", - "GenerateTest", - "StrengthTest", -] - -#============================================================================= -# -#============================================================================= -class UtilsTest(TestCase): - """test internal utilities""" - descriptionPrefix = "passlib.pwd" - - def test_self_info_rate(self): - """_self_info_rate()""" - from passlib.pwd import _self_info_rate - - self.assertEqual(_self_info_rate(""), 0) - - self.assertEqual(_self_info_rate("a" * 8), 0) - - self.assertEqual(_self_info_rate("ab"), 1) - self.assertEqual(_self_info_rate("ab" * 8), 1) - - self.assertEqual(_self_info_rate("abcd"), 2) - self.assertEqual(_self_info_rate("abcd" * 8), 2) - self.assertAlmostEqual(_self_info_rate("abcdaaaa"), 1.5488, places=4) - - # def test_total_self_info(self): - # """_total_self_info()""" - # from passlib.pwd import _total_self_info - # - # self.assertEqual(_total_self_info(""), 0) - # - # self.assertEqual(_total_self_info("a" * 8), 0) - # - # self.assertEqual(_total_self_info("ab"), 2) - # self.assertEqual(_total_self_info("ab" * 8), 16) - # - # self.assertEqual(_total_self_info("abcd"), 8) - # self.assertEqual(_total_self_info("abcd" * 8), 64) - # self.assertAlmostEqual(_total_self_info("abcdaaaa"), 12.3904, places=4) - -#============================================================================= -# word generation -#============================================================================= - -# import subject -from passlib.pwd import genword, default_charsets -ascii_62 = default_charsets['ascii_62'] -hex = default_charsets['hex'] - -class WordGeneratorTest(TestCase): - """test generation routines""" - descriptionPrefix = "passlib.pwd.genword()" - - def setUp(self): - super(WordGeneratorTest, self).setUp() - - # patch some RNG references so they're reproducible. - from passlib.pwd import SequenceGenerator - self.patchAttr(SequenceGenerator, "rng", - self.getRandom("pwd generator")) - - def assertResultContents(self, results, count, chars, unique=True): - """check result list matches expected count & charset""" - self.assertEqual(len(results), count) - if unique: - if unique is True: - unique = count - self.assertEqual(len(set(results)), unique) - self.assertEqual(set("".join(results)), set(chars)) - - def test_general(self): - """general behavior""" - - # basic usage - result = genword() - self.assertEqual(len(result), 9) - - # malformed keyword should have useful error. - self.assertRaisesRegex(TypeError, "(?i)unexpected keyword.*badkwd", genword, badkwd=True) - - def test_returns(self): - """'returns' keyword""" - # returns=int option - results = genword(returns=5000) - self.assertResultContents(results, 5000, ascii_62) - - # returns=iter option - gen = genword(returns=iter) - results = [next(gen) for _ in range(5000)] - self.assertResultContents(results, 5000, ascii_62) - - # invalid returns option - self.assertRaises(TypeError, genword, returns='invalid-type') - - def test_charset(self): - """'charset' & 'chars' options""" - # charset option - results = genword(charset="hex", returns=5000) - self.assertResultContents(results, 5000, hex) - - # chars option - # there are 3**3=27 possible combinations - results = genword(length=3, chars="abc", returns=5000) - self.assertResultContents(results, 5000, "abc", unique=27) - - # chars + charset - self.assertRaises(TypeError, genword, chars='abc', charset='hex') - - # TODO: test rng option - -#============================================================================= -# phrase generation -#============================================================================= - -# import subject -from passlib.pwd import genphrase -simple_words = ["alpha", "beta", "gamma"] - -class PhraseGeneratorTest(TestCase): - """test generation routines""" - descriptionPrefix = "passlib.pwd.genphrase()" - - def assertResultContents(self, results, count, words, unique=True, sep=" "): - """check result list matches expected count & charset""" - self.assertEqual(len(results), count) - if unique: - if unique is True: - unique = count - self.assertEqual(len(set(results)), unique) - out = set(itertools.chain.from_iterable(elem.split(sep) for elem in results)) - self.assertEqual(out, set(words)) - - def test_general(self): - """general behavior""" - - # basic usage - result = genphrase() - self.assertEqual(len(result.split(" ")), 4) # 48 / log(7776, 2) ~= 3.7 -> 4 - - # malformed keyword should have useful error. - self.assertRaisesRegex(TypeError, "(?i)unexpected keyword.*badkwd", genphrase, badkwd=True) - - def test_entropy(self): - """'length' & 'entropy' keywords""" - - # custom entropy - result = genphrase(entropy=70) - self.assertEqual(len(result.split(" ")), 6) # 70 / log(7776, 2) ~= 5.4 -> 6 - - # custom length - result = genphrase(length=3) - self.assertEqual(len(result.split(" ")), 3) - - # custom length < entropy - result = genphrase(length=3, entropy=48) - self.assertEqual(len(result.split(" ")), 4) - - # custom length > entropy - result = genphrase(length=4, entropy=12) - self.assertEqual(len(result.split(" ")), 4) - - def test_returns(self): - """'returns' keyword""" - # returns=int option - results = genphrase(returns=1000, words=simple_words) - self.assertResultContents(results, 1000, simple_words) - - # returns=iter option - gen = genphrase(returns=iter, words=simple_words) - results = [next(gen) for _ in range(1000)] - self.assertResultContents(results, 1000, simple_words) - - # invalid returns option - self.assertRaises(TypeError, genphrase, returns='invalid-type') - - def test_wordset(self): - """'wordset' & 'words' options""" - # wordset option - results = genphrase(words=simple_words, returns=5000) - self.assertResultContents(results, 5000, simple_words) - - # words option - results = genphrase(length=3, words=simple_words, returns=5000) - self.assertResultContents(results, 5000, simple_words, unique=3**3) - - # words + wordset - self.assertRaises(TypeError, genphrase, words=simple_words, wordset='bip39') - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_registry.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_registry.py deleted file mode 100644 index 8cec48d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_registry.py +++ /dev/null @@ -1,228 +0,0 @@ -"""tests for passlib.hash -- (c) Assurance Technologies 2003-2009""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -from logging import getLogger -import warnings -import sys -# site -# pkg -from passlib import hash, registry, exc -from passlib.registry import register_crypt_handler, register_crypt_handler_path, \ - get_crypt_handler, list_crypt_handlers, _unload_handler_name as unload_handler_name -import passlib.utils.handlers as uh -from passlib.tests.utils import TestCase -# module -log = getLogger(__name__) - -#============================================================================= -# dummy handlers -# -# NOTE: these are defined outside of test case -# since they're used by test_register_crypt_handler_path(), -# which needs them to be available as module globals. -#============================================================================= -class dummy_0(uh.StaticHandler): - name = "dummy_0" - -class alt_dummy_0(uh.StaticHandler): - name = "dummy_0" - -dummy_x = 1 - -#============================================================================= -# test registry -#============================================================================= -class RegistryTest(TestCase): - - descriptionPrefix = "passlib.registry" - - def setUp(self): - super(RegistryTest, self).setUp() - - # backup registry state & restore it after test. - locations = dict(registry._locations) - handlers = dict(registry._handlers) - def restore(): - registry._locations.clear() - registry._locations.update(locations) - registry._handlers.clear() - registry._handlers.update(handlers) - self.addCleanup(restore) - - def test_hash_proxy(self): - """test passlib.hash proxy object""" - # check dir works - dir(hash) - - # check repr works - repr(hash) - - # check non-existent attrs raise error - self.assertRaises(AttributeError, getattr, hash, 'fooey') - - # GAE tries to set __loader__, - # make sure that doesn't call register_crypt_handler. - old = getattr(hash, "__loader__", None) - test = object() - hash.__loader__ = test - self.assertIs(hash.__loader__, test) - if old is None: - del hash.__loader__ - self.assertFalse(hasattr(hash, "__loader__")) - else: - hash.__loader__ = old - self.assertIs(hash.__loader__, old) - - # check storing attr calls register_crypt_handler - class dummy_1(uh.StaticHandler): - name = "dummy_1" - hash.dummy_1 = dummy_1 - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - # check storing under wrong name results in error - self.assertRaises(ValueError, setattr, hash, "dummy_1x", dummy_1) - - def test_register_crypt_handler_path(self): - """test register_crypt_handler_path()""" - # NOTE: this messes w/ internals of registry, shouldn't be used publically. - paths = registry._locations - - # check namespace is clear - self.assertTrue('dummy_0' not in paths) - self.assertFalse(hasattr(hash, 'dummy_0')) - - # check invalid names are rejected - self.assertRaises(ValueError, register_crypt_handler_path, - "dummy_0", ".test_registry") - self.assertRaises(ValueError, register_crypt_handler_path, - "dummy_0", __name__ + ":dummy_0:xxx") - self.assertRaises(ValueError, register_crypt_handler_path, - "dummy_0", __name__ + ":dummy_0.xxx") - - # try lazy load - register_crypt_handler_path('dummy_0', __name__) - self.assertTrue('dummy_0' in list_crypt_handlers()) - self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True)) - self.assertIs(hash.dummy_0, dummy_0) - self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True)) - unload_handler_name('dummy_0') - - # try lazy load w/ alt - register_crypt_handler_path('dummy_0', __name__ + ':alt_dummy_0') - self.assertIs(hash.dummy_0, alt_dummy_0) - unload_handler_name('dummy_0') - - # check lazy load w/ wrong type fails - register_crypt_handler_path('dummy_x', __name__) - self.assertRaises(TypeError, get_crypt_handler, 'dummy_x') - - # check lazy load w/ wrong name fails - register_crypt_handler_path('alt_dummy_0', __name__) - self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0") - unload_handler_name("alt_dummy_0") - - # TODO: check lazy load which calls register_crypt_handler (warning should be issued) - sys.modules.pop("passlib.tests._test_bad_register", None) - register_crypt_handler_path("dummy_bad", "passlib.tests._test_bad_register") - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning) - h = get_crypt_handler("dummy_bad") - from passlib.tests import _test_bad_register as tbr - self.assertIs(h, tbr.alt_dummy_bad) - - def test_register_crypt_handler(self): - """test register_crypt_handler()""" - - self.assertRaises(TypeError, register_crypt_handler, {}) - - self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name=None))) - self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="AB_CD"))) - self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab-cd"))) - self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="ab__cd"))) - self.assertRaises(ValueError, register_crypt_handler, type('x', (uh.StaticHandler,), dict(name="default"))) - - class dummy_1(uh.StaticHandler): - name = "dummy_1" - - class dummy_1b(uh.StaticHandler): - name = "dummy_1" - - self.assertTrue('dummy_1' not in list_crypt_handlers()) - - register_crypt_handler(dummy_1) - register_crypt_handler(dummy_1) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - self.assertRaises(KeyError, register_crypt_handler, dummy_1b) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - register_crypt_handler(dummy_1b, force=True) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1b) - - self.assertTrue('dummy_1' in list_crypt_handlers()) - - def test_get_crypt_handler(self): - """test get_crypt_handler()""" - - class dummy_1(uh.StaticHandler): - name = "dummy_1" - - # without available handler - self.assertRaises(KeyError, get_crypt_handler, "dummy_1") - self.assertIs(get_crypt_handler("dummy_1", None), None) - - # already loaded handler - register_crypt_handler(dummy_1) - self.assertIs(get_crypt_handler("dummy_1"), dummy_1) - - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "handler names should be lower-case, and use underscores instead of hyphens:.*", UserWarning) - - # already loaded handler, using incorrect name - self.assertIs(get_crypt_handler("DUMMY-1"), dummy_1) - - # lazy load of unloaded handler, using incorrect name - register_crypt_handler_path('dummy_0', __name__) - self.assertIs(get_crypt_handler("DUMMY-0"), dummy_0) - - # check system & private names aren't returned - from passlib import hash - hash.__dict__["_fake"] = "dummy" - for name in ["_fake", "__package__"]: - self.assertRaises(KeyError, get_crypt_handler, name) - self.assertIs(get_crypt_handler(name, None), None) - - def test_list_crypt_handlers(self): - """test list_crypt_handlers()""" - from passlib.registry import list_crypt_handlers - - # check system & private names aren't returned - hash.__dict__["_fake"] = "dummy" - for name in list_crypt_handlers(): - self.assertFalse(name.startswith("_"), "%r: " % name) - unload_handler_name("_fake") - - def test_handlers(self): - """verify we have tests for all builtin handlers""" - from passlib.registry import list_crypt_handlers - from passlib.tests.test_handlers import get_handler_case, conditionally_available_hashes - for name in list_crypt_handlers(): - # skip some wrappers that don't need independant testing - if name.startswith("ldap_") and name[5:] in list_crypt_handlers(): - continue - if name in ["roundup_plaintext"]: - continue - # check the remaining ones all have a handler - try: - self.assertTrue(get_handler_case(name)) - except exc.MissingBackendError: - if name in conditionally_available_hashes: # expected to fail on some setups - continue - raise - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_totp.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_totp.py deleted file mode 100644 index 604d2e9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_totp.py +++ /dev/null @@ -1,1604 +0,0 @@ -"""passlib.tests -- test passlib.totp""" -#============================================================================= -# imports -#============================================================================= -# core -import datetime -from functools import partial -import logging; log = logging.getLogger(__name__) -import sys -import time as _time -# site -# pkg -from passlib import exc -from passlib.utils.compat import unicode, u -from passlib.tests.utils import TestCase, time_call -# subject -from passlib import totp as totp_module -from passlib.totp import TOTP, AppWallet, AES_SUPPORT -# local -__all__ = [ - "EngineTest", -] - -#============================================================================= -# helpers -#============================================================================= - -# XXX: python 3 changed what error base64.b16decode() throws, from TypeError to base64.Error(). -# it wasn't until 3.3 that base32decode() also got changed. -# really should normalize this in the code to a single BinaryDecodeError, -# predicting this cross-version is getting unmanagable. -Base32DecodeError = Base16DecodeError = TypeError -if sys.version_info >= (3,0): - from binascii import Error as Base16DecodeError -if sys.version_info >= (3,3): - from binascii import Error as Base32DecodeError - -PASS1 = "abcdef" -PASS2 = b"\x00\xFF" -KEY1 = '4AOGGDBBQSYHNTUZ' -KEY1_RAW = b'\xe0\x1cc\x0c!\x84\xb0v\xce\x99' -KEY2_RAW = b'\xee]\xcb9\x870\x06 D\xc8y/\xa54&\xe4\x9c\x13\xc2\x18' -KEY3 = 'S3JDVB7QD2R7JPXX' # used in docstrings -KEY4 = 'JBSWY3DPEHPK3PXP' # from google keyuri spec -KEY4_RAW = b'Hello!\xde\xad\xbe\xef' - -# NOTE: for randtime() below, -# * want at least 7 bits on fractional side, to test fractional times to at least 0.01s precision -# * want at least 32 bits on integer side, to test for 32-bit epoch issues. -# most systems *should* have 53 bit mantissa, leaving plenty of room on both ends, -# so using (1<<37) as scale, to allocate 16 bits on fractional side, but generate reasonable # of > 1<<32 times. -# sanity check that we're above 44 ensures minimum requirements (44 - 37 int = 7 frac) -assert sys.float_info.radix == 2, "unexpected float_info.radix" -assert sys.float_info.mant_dig >= 44, "double precision unexpectedly small" - -def _get_max_time_t(): - """ - helper to calc max_time_t constant (see below) - """ - value = 1 << 30 # even for 32 bit systems will handle this - year = 0 - while True: - next_value = value << 1 - try: - next_year = datetime.datetime.utcfromtimestamp(next_value-1).year - except (ValueError, OSError, OverflowError): - # utcfromtimestamp() may throw any of the following: - # - # * year out of range for datetime: - # py < 3.6 throws ValueError. - # (py 3.6.0 returns odd value instead, see workaround below) - # - # * int out of range for host's gmtime/localtime: - # py2 throws ValueError, py3 throws OSError. - # - # * int out of range for host's time_t: - # py2 throws ValueError, py3 throws OverflowError. - # - break - - # Workaround for python 3.6.0 issue -- - # Instead of throwing ValueError if year out of range for datetime, - # Python 3.6 will do some weird behavior that masks high bits - # e.g. (1<<40) -> year 36812, but (1<<41) -> year 6118. - # (Appears to be bug http://bugs.python.org/issue29100) - # This check stops at largest non-wrapping bit size. - if next_year < year: - break - - value = next_value - - # 'value-1' is maximum. - value -= 1 - - # check for crazy case where we're beyond what datetime supports - # (caused by bug 29100 again). compare to max value that datetime - # module supports -- datetime.datetime(9999, 12, 31, 23, 59, 59, 999999) - max_datetime_timestamp = 253402318800 - return min(value, max_datetime_timestamp) - -#: Rough approximation of max value acceptable by hosts's time_t. -#: This is frequently ~2**37 on 64 bit, and ~2**31 on 32 bit systems. -max_time_t = _get_max_time_t() - -def to_b32_size(raw_size): - return (raw_size * 8 + 4) // 5 - -#============================================================================= -# wallet -#============================================================================= -class AppWalletTest(TestCase): - descriptionPrefix = "passlib.totp.AppWallet" - - #============================================================================= - # constructor - #============================================================================= - - def test_secrets_types(self): - """constructor -- 'secrets' param -- input types""" - - # no secrets - wallet = AppWallet() - self.assertEqual(wallet._secrets, {}) - self.assertFalse(wallet.has_secrets) - - # dict - ref = {"1": b"aaa", "2": b"bbb"} - wallet = AppWallet(ref) - self.assertEqual(wallet._secrets, ref) - self.assertTrue(wallet.has_secrets) - - # # list - # wallet = AppWallet(list(ref.items())) - # self.assertEqual(wallet._secrets, ref) - - # # iter - # wallet = AppWallet(iter(ref.items())) - # self.assertEqual(wallet._secrets, ref) - - # "tag:value" string - wallet = AppWallet("\n 1: aaa\n# comment\n \n2: bbb ") - self.assertEqual(wallet._secrets, ref) - - # ensure ":" allowed in secret - wallet = AppWallet("1: aaa: bbb \n# comment\n \n2: bbb ") - self.assertEqual(wallet._secrets, {"1": b"aaa: bbb", "2": b"bbb"}) - - # json dict - wallet = AppWallet('{"1":"aaa","2":"bbb"}') - self.assertEqual(wallet._secrets, ref) - - # # json list - # wallet = AppWallet('[["1","aaa"],["2","bbb"]]') - # self.assertEqual(wallet._secrets, ref) - - # invalid type - self.assertRaises(TypeError, AppWallet, 123) - - # invalid json obj - self.assertRaises(TypeError, AppWallet, "[123]") - - # # invalid list items - # self.assertRaises(ValueError, AppWallet, ["1", b"aaa"]) - - # forbid empty secret - self.assertRaises(ValueError, AppWallet, {"1": "aaa", "2": ""}) - - def test_secrets_tags(self): - """constructor -- 'secrets' param -- tag/value normalization""" - - # test reference - ref = {"1": b"aaa", "02": b"bbb", "C": b"ccc"} - wallet = AppWallet(ref) - self.assertEqual(wallet._secrets, ref) - - # accept unicode - wallet = AppWallet({u("1"): b"aaa", u("02"): b"bbb", u("C"): b"ccc"}) - self.assertEqual(wallet._secrets, ref) - - # normalize int tags - wallet = AppWallet({1: b"aaa", "02": b"bbb", "C": b"ccc"}) - self.assertEqual(wallet._secrets, ref) - - # forbid non-str/int tags - self.assertRaises(TypeError, AppWallet, {(1,): "aaa"}) - - # accept valid tags - wallet = AppWallet({"1-2_3.4": b"aaa"}) - - # forbid invalid tags - self.assertRaises(ValueError, AppWallet, {"-abc": "aaa"}) - self.assertRaises(ValueError, AppWallet, {"ab*$": "aaa"}) - - # coerce value to bytes - wallet = AppWallet({"1": u("aaa"), "02": "bbb", "C": b"ccc"}) - self.assertEqual(wallet._secrets, ref) - - # forbid invalid value types - self.assertRaises(TypeError, AppWallet, {"1": 123}) - self.assertRaises(TypeError, AppWallet, {"1": None}) - self.assertRaises(TypeError, AppWallet, {"1": []}) - - # TODO: test secrets_path - - def test_default_tag(self): - """constructor -- 'default_tag' param""" - - # should sort numerically - wallet = AppWallet({"1": "one", "02": "two"}) - self.assertEqual(wallet.default_tag, "02") - self.assertEqual(wallet.get_secret(wallet.default_tag), b"two") - - # should sort alphabetically if non-digit present - wallet = AppWallet({"1": "one", "02": "two", "A": "aaa"}) - self.assertEqual(wallet.default_tag, "A") - self.assertEqual(wallet.get_secret(wallet.default_tag), b"aaa") - - # should use honor custom tag - wallet = AppWallet({"1": "one", "02": "two", "A": "aaa"}, default_tag="1") - self.assertEqual(wallet.default_tag, "1") - self.assertEqual(wallet.get_secret(wallet.default_tag), b"one") - - # throw error on unknown value - self.assertRaises(KeyError, AppWallet, {"1": "one", "02": "two", "A": "aaa"}, - default_tag="B") - - # should be empty - wallet = AppWallet() - self.assertEqual(wallet.default_tag, None) - self.assertRaises(KeyError, wallet.get_secret, None) - - # TODO: test 'cost' param - - #============================================================================= - # encrypt_key() & decrypt_key() helpers - #============================================================================= - def require_aes_support(self, canary=None): - if AES_SUPPORT: - canary and canary() - else: - canary and self.assertRaises(RuntimeError, canary) - raise self.skipTest("'cryptography' package not installed") - - def test_decrypt_key(self): - """.decrypt_key()""" - - wallet = AppWallet({"1": PASS1, "2": PASS2}) - - # check for support - CIPHER1 = dict(v=1, c=13, s='6D7N7W53O7HHS37NLUFQ', - k='MHCTEGSNPFN5CGBJ', t='1') - self.require_aes_support(canary=partial(wallet.decrypt_key, CIPHER1)) - - # reference key - self.assertEqual(wallet.decrypt_key(CIPHER1)[0], KEY1_RAW) - - # different salt used to encrypt same raw key - CIPHER2 = dict(v=1, c=13, s='SPZJ54Y6IPUD2BYA4C6A', - k='ZGDXXTVQOWYLC2AU', t='1') - self.assertEqual(wallet.decrypt_key(CIPHER2)[0], KEY1_RAW) - - # different sized key, password, and cost - CIPHER3 = dict(v=1, c=8, s='FCCTARTIJWE7CPQHUDKA', - k='D2DRS32YESGHHINWFFCELKN7Z6NAHM4M', t='2') - self.assertEqual(wallet.decrypt_key(CIPHER3)[0], KEY2_RAW) - - # wrong password should silently result in wrong key - temp = CIPHER1.copy() - temp.update(t='2') - self.assertEqual(wallet.decrypt_key(temp)[0], b'\xafD6.F7\xeb\x19\x05Q') - - # missing tag should throw error - temp = CIPHER1.copy() - temp.update(t='3') - self.assertRaises(KeyError, wallet.decrypt_key, temp) - - # unknown version should throw error - temp = CIPHER1.copy() - temp.update(v=999) - self.assertRaises(ValueError, wallet.decrypt_key, temp) - - def test_decrypt_key_needs_recrypt(self): - """.decrypt_key() -- needs_recrypt flag""" - self.require_aes_support() - - wallet = AppWallet({"1": PASS1, "2": PASS2}, encrypt_cost=13) - - # ref should be accepted - ref = dict(v=1, c=13, s='AAAA', k='AAAA', t='2') - self.assertFalse(wallet.decrypt_key(ref)[1]) - - # wrong cost - temp = ref.copy() - temp.update(c=8) - self.assertTrue(wallet.decrypt_key(temp)[1]) - - # wrong tag - temp = ref.copy() - temp.update(t="1") - self.assertTrue(wallet.decrypt_key(temp)[1]) - - # XXX: should this check salt_size? - - def assertSaneResult(self, result, wallet, key, tag="1", - needs_recrypt=False): - """check encrypt_key() result has expected format""" - - self.assertEqual(set(result), set(["v", "t", "c", "s", "k"])) - - self.assertEqual(result['v'], 1) - self.assertEqual(result['t'], tag) - self.assertEqual(result['c'], wallet.encrypt_cost) - - self.assertEqual(len(result['s']), to_b32_size(wallet.salt_size)) - self.assertEqual(len(result['k']), to_b32_size(len(key))) - - result_key, result_needs_recrypt = wallet.decrypt_key(result) - self.assertEqual(result_key, key) - self.assertEqual(result_needs_recrypt, needs_recrypt) - - def test_encrypt_key(self): - """.encrypt_key()""" - - # check for support - wallet = AppWallet({"1": PASS1}, encrypt_cost=5) - self.require_aes_support(canary=partial(wallet.encrypt_key, KEY1_RAW)) - - # basic behavior - result = wallet.encrypt_key(KEY1_RAW) - self.assertSaneResult(result, wallet, KEY1_RAW) - - # creates new salt each time - other = wallet.encrypt_key(KEY1_RAW) - self.assertSaneResult(result, wallet, KEY1_RAW) - self.assertNotEqual(other['s'], result['s']) - self.assertNotEqual(other['k'], result['k']) - - # honors custom cost - wallet2 = AppWallet({"1": PASS1}, encrypt_cost=6) - result = wallet2.encrypt_key(KEY1_RAW) - self.assertSaneResult(result, wallet2, KEY1_RAW) - - # honors default tag - wallet2 = AppWallet({"1": PASS1, "2": PASS2}) - result = wallet2.encrypt_key(KEY1_RAW) - self.assertSaneResult(result, wallet2, KEY1_RAW, tag="2") - - # honor salt size - wallet2 = AppWallet({"1": PASS1}) - wallet2.salt_size = 64 - result = wallet2.encrypt_key(KEY1_RAW) - self.assertSaneResult(result, wallet2, KEY1_RAW) - - # larger key - result = wallet.encrypt_key(KEY2_RAW) - self.assertSaneResult(result, wallet, KEY2_RAW) - - # border case: empty key - # XXX: might want to allow this, but documenting behavior for now - self.assertRaises(ValueError, wallet.encrypt_key, b"") - - def test_encrypt_cost_timing(self): - """verify cost parameter via timing""" - self.require_aes_support() - - # time default cost - wallet = AppWallet({"1": "aaa"}) - wallet.encrypt_cost -= 2 - delta, _ = time_call(partial(wallet.encrypt_key, KEY1_RAW), maxtime=0) - - # this should take (2**3=8) times as long - wallet.encrypt_cost += 3 - delta2, _ = time_call(partial(wallet.encrypt_key, KEY1_RAW), maxtime=0) - - # TODO: rework timing test here to inject mock pbkdf2_hmac() function instead; - # and test that it's being invoked w/ proper options. - self.assertAlmostEqual(delta2, delta*8, delta=(delta*8)*0.5) - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# common OTP code -#============================================================================= - -#: used as base value for RFC test vector keys -RFC_KEY_BYTES_20 = "12345678901234567890".encode("ascii") -RFC_KEY_BYTES_32 = (RFC_KEY_BYTES_20*2)[:32] -RFC_KEY_BYTES_64 = (RFC_KEY_BYTES_20*4)[:64] - -# TODO: this class is separate from TotpTest due to historical issue, -# when there was a base class, and a separate HOTP class. -# these test case classes should probably be combined. -class TotpTest(TestCase): - """ - common code shared by TotpTest & HotpTest - """ - #============================================================================= - # class attrs - #============================================================================= - - descriptionPrefix = "passlib.totp.TOTP" - - #============================================================================= - # setup - #============================================================================= - def setUp(self): - super(TotpTest, self).setUp() - - # clear norm_hash_name() cache so 'unknown hash' warnings get emitted each time - from passlib.crypto.digest import lookup_hash - lookup_hash.clear_cache() - - # monkeypatch module's rng to be deterministic - self.patchAttr(totp_module, "rng", self.getRandom()) - - #============================================================================= - # general helpers - #============================================================================= - def randtime(self): - """ - helper to generate random epoch time - :returns float: epoch time - """ - return self.getRandom().random() * max_time_t - - def randotp(self, cls=None, **kwds): - """ - helper which generates a random TOTP instance. - """ - rng = self.getRandom() - if "key" not in kwds: - kwds['new'] = True - kwds.setdefault("digits", rng.randint(6, 10)) - kwds.setdefault("alg", rng.choice(["sha1", "sha256", "sha512"])) - kwds.setdefault("period", rng.randint(10, 120)) - return (cls or TOTP)(**kwds) - - def test_randotp(self): - """ - internal test -- randotp() - """ - otp1 = self.randotp() - otp2 = self.randotp() - - self.assertNotEqual(otp1.key, otp2.key, "key not randomized:") - - # NOTE: has (1/5)**10 odds of failure - for _ in range(10): - if otp1.digits != otp2.digits: - break - otp2 = self.randotp() - else: - self.fail("digits not randomized") - - # NOTE: has (1/3)**10 odds of failure - for _ in range(10): - if otp1.alg != otp2.alg: - break - otp2 = self.randotp() - else: - self.fail("alg not randomized") - - #============================================================================= - # reference vector helpers - #============================================================================= - - #: default options used by test vectors (unless otherwise stated) - vector_defaults = dict(format="base32", alg="sha1", period=30, digits=8) - - #: various TOTP test vectors, - #: each element in list has format [options, (time, token <, int(expires)>), ...] - vectors = [ - - #------------------------------------------------------------------------- - # passlib test vectors - #------------------------------------------------------------------------- - - # 10 byte key, 6 digits - [dict(key="ACDEFGHJKL234567", digits=6), - # test fencepost to make sure we're rounding right - (1412873399, '221105'), # == 29 mod 30 - (1412873400, '178491'), # == 0 mod 30 - (1412873401, '178491'), # == 1 mod 30 - (1412873429, '178491'), # == 29 mod 30 - (1412873430, '915114'), # == 0 mod 30 - ], - - # 10 byte key, 8 digits - [dict(key="ACDEFGHJKL234567", digits=8), - # should be same as 6 digits (above), but w/ 2 more digits on left side of token. - (1412873399, '20221105'), # == 29 mod 30 - (1412873400, '86178491'), # == 0 mod 30 - (1412873401, '86178491'), # == 1 mod 30 - (1412873429, '86178491'), # == 29 mod 30 - (1412873430, '03915114'), # == 0 mod 30 - ], - - # sanity check on key used in docstrings - [dict(key="S3JD-VB7Q-D2R7-JPXX", digits=6), - (1419622709, '000492'), - (1419622739, '897212'), - ], - - #------------------------------------------------------------------------- - # reference vectors taken from http://tools.ietf.org/html/rfc6238, appendix B - # NOTE: while appendix B states same key used for all tests, the reference - # code in the appendix repeats the key up to the alg's block size, - # and uses *that* as the secret... so that's what we're doing here. - #------------------------------------------------------------------------- - - # sha1 test vectors - [dict(key=RFC_KEY_BYTES_20, format="raw", alg="sha1"), - (59, '94287082'), - (1111111109, '07081804'), - (1111111111, '14050471'), - (1234567890, '89005924'), - (2000000000, '69279037'), - (20000000000, '65353130'), - ], - - # sha256 test vectors - [dict(key=RFC_KEY_BYTES_32, format="raw", alg="sha256"), - (59, '46119246'), - (1111111109, '68084774'), - (1111111111, '67062674'), - (1234567890, '91819424'), - (2000000000, '90698825'), - (20000000000, '77737706'), - ], - - # sha512 test vectors - [dict(key=RFC_KEY_BYTES_64, format="raw", alg="sha512"), - (59, '90693936'), - (1111111109, '25091201'), - (1111111111, '99943326'), - (1234567890, '93441116'), - (2000000000, '38618901'), - (20000000000, '47863826'), - ], - - #------------------------------------------------------------------------- - # other test vectors - #------------------------------------------------------------------------- - - # generated at http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript - [dict(key="JBSWY3DPEHPK3PXP", digits=6), (1409192430, '727248'), (1419890990, '122419')], - [dict(key="JBSWY3DPEHPK3PXP", digits=9, period=41), (1419891152, '662331049')], - - # found in https://github.com/eloquent/otis/blob/develop/test/suite/Totp/Value/TotpValueGeneratorTest.php, line 45 - [dict(key=RFC_KEY_BYTES_20, format="raw", period=60), (1111111111, '19360094')], - [dict(key=RFC_KEY_BYTES_32, format="raw", alg="sha256", period=60), (1111111111, '40857319')], - [dict(key=RFC_KEY_BYTES_64, format="raw", alg="sha512", period=60), (1111111111, '37023009')], - - ] - - def iter_test_vectors(self): - """ - helper to iterate over test vectors. - yields ``(totp, time, token, expires, prefix)`` tuples. - """ - from passlib.totp import TOTP - for row in self.vectors: - kwds = self.vector_defaults.copy() - kwds.update(row[0]) - for entry in row[1:]: - if len(entry) == 3: - time, token, expires = entry - else: - time, token = entry - expires = None - # NOTE: not re-using otp between calls so that stateful methods - # (like .match) don't have problems. - log.debug("test vector: %r time=%r token=%r expires=%r", kwds, time, token, expires) - otp = TOTP(**kwds) - prefix = "alg=%r time=%r token=%r: " % (otp.alg, time, token) - yield otp, time, token, expires, prefix - - #============================================================================= - # constructor tests - #============================================================================= - def test_ctor_w_new(self): - """constructor -- 'new' parameter""" - - # exactly one of 'key' or 'new' is required - self.assertRaises(TypeError, TOTP) - self.assertRaises(TypeError, TOTP, key='4aoggdbbqsyhntuz', new=True) - - # generates new key - otp = TOTP(new=True) - otp2 = TOTP(new=True) - self.assertNotEqual(otp.key, otp2.key) - - def test_ctor_w_size(self): - """constructor -- 'size' parameter""" - - # should default to digest size, per RFC - self.assertEqual(len(TOTP(new=True, alg="sha1").key), 20) - self.assertEqual(len(TOTP(new=True, alg="sha256").key), 32) - self.assertEqual(len(TOTP(new=True, alg="sha512").key), 64) - - # explicit key size - self.assertEqual(len(TOTP(new=True, size=10).key), 10) - self.assertEqual(len(TOTP(new=True, size=16).key), 16) - - # for new=True, maximum size enforced (based on alg) - self.assertRaises(ValueError, TOTP, new=True, size=21, alg="sha1") - - # for new=True, minimum size enforced - self.assertRaises(ValueError, TOTP, new=True, size=9) - - # for existing key, minimum size is only warned about - with self.assertWarningList([ - dict(category=exc.PasslibSecurityWarning, message_re=".*for security purposes, secret key must be.*") - ]): - _ = TOTP('0A'*9, 'hex') - - def test_ctor_w_key_and_format(self): - """constructor -- 'key' and 'format' parameters""" - - # handle base32 encoding (the default) - self.assertEqual(TOTP(KEY1).key, KEY1_RAW) - - # .. w/ lower case - self.assertEqual(TOTP(KEY1.lower()).key, KEY1_RAW) - - # .. w/ spaces (e.g. user-entered data) - self.assertEqual(TOTP(' 4aog gdbb qsyh ntuz ').key, KEY1_RAW) - - # .. w/ invalid char - self.assertRaises(Base32DecodeError, TOTP, 'ao!ggdbbqsyhntuz') - - # handle hex encoding - self.assertEqual(TOTP('e01c630c2184b076ce99', 'hex').key, KEY1_RAW) - - # .. w/ invalid char - self.assertRaises(Base16DecodeError, TOTP, 'X01c630c2184b076ce99', 'hex') - - # handle raw bytes - self.assertEqual(TOTP(KEY1_RAW, "raw").key, KEY1_RAW) - - def test_ctor_w_alg(self): - """constructor -- 'alg' parameter""" - - # normalize hash names - self.assertEqual(TOTP(KEY1, alg="SHA-256").alg, "sha256") - self.assertEqual(TOTP(KEY1, alg="SHA256").alg, "sha256") - - # invalid alg - self.assertRaises(ValueError, TOTP, KEY1, alg="SHA-333") - - def test_ctor_w_digits(self): - """constructor -- 'digits' parameter""" - self.assertRaises(ValueError, TOTP, KEY1, digits=5) - self.assertEqual(TOTP(KEY1, digits=6).digits, 6) # min value - self.assertEqual(TOTP(KEY1, digits=10).digits, 10) # max value - self.assertRaises(ValueError, TOTP, KEY1, digits=11) - - def test_ctor_w_period(self): - """constructor -- 'period' parameter""" - - # default - self.assertEqual(TOTP(KEY1).period, 30) - - # explicit value - self.assertEqual(TOTP(KEY1, period=63).period, 63) - - # reject wrong type - self.assertRaises(TypeError, TOTP, KEY1, period=1.5) - self.assertRaises(TypeError, TOTP, KEY1, period='abc') - - # reject non-positive values - self.assertRaises(ValueError, TOTP, KEY1, period=0) - self.assertRaises(ValueError, TOTP, KEY1, period=-1) - - def test_ctor_w_label(self): - """constructor -- 'label' parameter""" - self.assertEqual(TOTP(KEY1).label, None) - self.assertEqual(TOTP(KEY1, label="foo@bar").label, "foo@bar") - self.assertRaises(ValueError, TOTP, KEY1, label="foo:bar") - - def test_ctor_w_issuer(self): - """constructor -- 'issuer' parameter""" - self.assertEqual(TOTP(KEY1).issuer, None) - self.assertEqual(TOTP(KEY1, issuer="foo.com").issuer, "foo.com") - self.assertRaises(ValueError, TOTP, KEY1, issuer="foo.com:bar") - - #============================================================================= - # using() tests - #============================================================================= - - # TODO: test using() w/ 'digits', 'alg', 'issue', 'wallet', **wallet_kwds - - def test_using_w_period(self): - """using() -- 'period' parameter""" - - # default - self.assertEqual(TOTP(KEY1).period, 30) - - # explicit value - self.assertEqual(TOTP.using(period=63)(KEY1).period, 63) - - # reject wrong type - self.assertRaises(TypeError, TOTP.using, period=1.5) - self.assertRaises(TypeError, TOTP.using, period='abc') - - # reject non-positive values - self.assertRaises(ValueError, TOTP.using, period=0) - self.assertRaises(ValueError, TOTP.using, period=-1) - - def test_using_w_now(self): - """using -- 'now' parameter""" - - # NOTE: reading time w/ normalize_time() to make sure custom .now actually has effect. - - # default -- time.time - otp = self.randotp() - self.assertIs(otp.now, _time.time) - self.assertAlmostEqual(otp.normalize_time(None), int(_time.time())) - - # custom function - counter = [123.12] - def now(): - counter[0] += 1 - return counter[0] - otp = self.randotp(cls=TOTP.using(now=now)) - # NOTE: TOTP() constructor invokes this as part of test, using up counter values 124 & 125 - self.assertEqual(otp.normalize_time(None), 126) - self.assertEqual(otp.normalize_time(None), 127) - - # require callable - self.assertRaises(TypeError, TOTP.using, now=123) - - # require returns int/float - msg_re = r"now\(\) function must return non-negative" - self.assertRaisesRegex(AssertionError, msg_re, TOTP.using, now=lambda: 'abc') - - # require returns non-negative value - self.assertRaisesRegex(AssertionError, msg_re, TOTP.using, now=lambda: -1) - - #============================================================================= - # internal method tests - #============================================================================= - - def test_normalize_token_instance(self, otp=None): - """normalize_token() -- instance method""" - if otp is None: - otp = self.randotp(digits=7) - - # unicode & bytes - self.assertEqual(otp.normalize_token(u('1234567')), '1234567') - self.assertEqual(otp.normalize_token(b'1234567'), '1234567') - - # int - self.assertEqual(otp.normalize_token(1234567), '1234567') - - # int which needs 0 padding - self.assertEqual(otp.normalize_token(234567), '0234567') - - # reject wrong types (float, None) - self.assertRaises(TypeError, otp.normalize_token, 1234567.0) - self.assertRaises(TypeError, otp.normalize_token, None) - - # too few digits - self.assertRaises(exc.MalformedTokenError, otp.normalize_token, '123456') - - # too many digits - self.assertRaises(exc.MalformedTokenError, otp.normalize_token, '01234567') - self.assertRaises(exc.MalformedTokenError, otp.normalize_token, 12345678) - - def test_normalize_token_class(self): - """normalize_token() -- class method""" - self.test_normalize_token_instance(otp=TOTP.using(digits=7)) - - def test_normalize_time(self): - """normalize_time()""" - TotpFactory = TOTP.using() - otp = self.randotp(TotpFactory) - - for _ in range(10): - time = self.randtime() - tint = int(time) - - self.assertEqual(otp.normalize_time(time), tint) - self.assertEqual(otp.normalize_time(tint + 0.5), tint) - - self.assertEqual(otp.normalize_time(tint), tint) - - dt = datetime.datetime.utcfromtimestamp(time) - self.assertEqual(otp.normalize_time(dt), tint) - - orig = TotpFactory.now - try: - TotpFactory.now = staticmethod(lambda: time) - self.assertEqual(otp.normalize_time(None), tint) - finally: - TotpFactory.now = orig - - self.assertRaises(TypeError, otp.normalize_time, '1234') - - #============================================================================= - # key attr tests - #============================================================================= - - def test_key_attrs(self): - """pretty_key() and .key attributes""" - rng = self.getRandom() - - # test key attrs - otp = TOTP(KEY1_RAW, "raw") - self.assertEqual(otp.key, KEY1_RAW) - self.assertEqual(otp.hex_key, 'e01c630c2184b076ce99') - self.assertEqual(otp.base32_key, KEY1) - - # test pretty_key() - self.assertEqual(otp.pretty_key(), '4AOG-GDBB-QSYH-NTUZ') - self.assertEqual(otp.pretty_key(sep=" "), '4AOG GDBB QSYH NTUZ') - self.assertEqual(otp.pretty_key(sep=False), KEY1) - self.assertEqual(otp.pretty_key(format="hex"), 'e01c-630c-2184-b076-ce99') - - # quick fuzz test: make attr access works for random key & random size - otp = TOTP(new=True, size=rng.randint(10, 20)) - _ = otp.hex_key - _ = otp.base32_key - _ = otp.pretty_key() - - #============================================================================= - # generate() tests - #============================================================================= - def test_totp_token(self): - """generate() -- TotpToken() class""" - from passlib.totp import TOTP, TotpToken - - # test known set of values - otp = TOTP('s3jdvb7qd2r7jpxx') - result = otp.generate(1419622739) - self.assertIsInstance(result, TotpToken) - self.assertEqual(result.token, '897212') - self.assertEqual(result.counter, 47320757) - ##self.assertEqual(result.start_time, 1419622710) - self.assertEqual(result.expire_time, 1419622740) - self.assertEqual(result, ('897212', 1419622740)) - self.assertEqual(len(result), 2) - self.assertEqual(result[0], '897212') - self.assertEqual(result[1], 1419622740) - self.assertRaises(IndexError, result.__getitem__, -3) - self.assertRaises(IndexError, result.__getitem__, 2) - self.assertTrue(result) - - # time dependant bits... - otp.now = lambda : 1419622739.5 - self.assertEqual(result.remaining, 0.5) - self.assertTrue(result.valid) - - otp.now = lambda : 1419622741 - self.assertEqual(result.remaining, 0) - self.assertFalse(result.valid) - - # same time -- shouldn't return same object, but should be equal - result2 = otp.generate(1419622739) - self.assertIsNot(result2, result) - self.assertEqual(result2, result) - - # diff time in period -- shouldn't return same object, but should be equal - result3 = otp.generate(1419622711) - self.assertIsNot(result3, result) - self.assertEqual(result3, result) - - # shouldn't be equal - result4 = otp.generate(1419622999) - self.assertNotEqual(result4, result) - - def test_generate(self): - """generate()""" - from passlib.totp import TOTP - - # generate token - otp = TOTP(new=True) - time = self.randtime() - result = otp.generate(time) - token = result.token - self.assertIsInstance(token, unicode) - start_time = result.counter * 30 - - # should generate same token for next 29s - self.assertEqual(otp.generate(start_time + 29).token, token) - - # and new one at 30s - self.assertNotEqual(otp.generate(start_time + 30).token, token) - - # verify round-trip conversion of datetime - dt = datetime.datetime.utcfromtimestamp(time) - self.assertEqual(int(otp.normalize_time(dt)), int(time)) - - # handle datetime object - self.assertEqual(otp.generate(dt).token, token) - - # omitting value should use current time - otp2 = TOTP.using(now=lambda: time)(key=otp.base32_key) - self.assertEqual(otp2.generate().token, token) - - # reject invalid time - self.assertRaises(ValueError, otp.generate, -1) - - def test_generate_w_reference_vectors(self): - """generate() -- reference vectors""" - for otp, time, token, expires, prefix in self.iter_test_vectors(): - # should output correct token for specified time - result = otp.generate(time) - self.assertEqual(result.token, token, msg=prefix) - self.assertEqual(result.counter, time // otp.period, msg=prefix) - if expires: - self.assertEqual(result.expire_time, expires) - - #============================================================================= - # TotpMatch() tests - #============================================================================= - - def assertTotpMatch(self, match, time, skipped=0, period=30, window=30, msg=''): - from passlib.totp import TotpMatch - - # test type - self.assertIsInstance(match, TotpMatch) - - # totp sanity check - self.assertIsInstance(match.totp, TOTP) - self.assertEqual(match.totp.period, period) - - # test attrs - self.assertEqual(match.time, time, msg=msg + " matched time:") - expected = time // period - counter = expected + skipped - self.assertEqual(match.counter, counter, msg=msg + " matched counter:") - self.assertEqual(match.expected_counter, expected, msg=msg + " expected counter:") - self.assertEqual(match.skipped, skipped, msg=msg + " skipped:") - self.assertEqual(match.cache_seconds, period + window) - expire_time = (counter + 1) * period - self.assertEqual(match.expire_time, expire_time) - self.assertEqual(match.cache_time, expire_time + window) - - # test tuple - self.assertEqual(len(match), 2) - self.assertEqual(match, (counter, time)) - self.assertRaises(IndexError, match.__getitem__, -3) - self.assertEqual(match[0], counter) - self.assertEqual(match[1], time) - self.assertRaises(IndexError, match.__getitem__, 2) - - # test bool - self.assertTrue(match) - - def test_totp_match_w_valid_token(self): - """match() -- valid TotpMatch object""" - time = 141230981 - token = '781501' - otp = TOTP.using(now=lambda: time + 24 * 3600)(KEY3) - result = otp.match(token, time) - self.assertTotpMatch(result, time=time, skipped=0) - - def test_totp_match_w_older_token(self): - """match() -- valid TotpMatch object with future token""" - from passlib.totp import TotpMatch - - time = 141230981 - token = '781501' - otp = TOTP.using(now=lambda: time + 24 * 3600)(KEY3) - result = otp.match(token, time - 30) - self.assertTotpMatch(result, time=time - 30, skipped=1) - - def test_totp_match_w_new_token(self): - """match() -- valid TotpMatch object with past token""" - time = 141230981 - token = '781501' - otp = TOTP.using(now=lambda: time + 24 * 3600)(KEY3) - result = otp.match(token, time + 30) - self.assertTotpMatch(result, time=time + 30, skipped=-1) - - def test_totp_match_w_invalid_token(self): - """match() -- invalid TotpMatch object""" - time = 141230981 - token = '781501' - otp = TOTP.using(now=lambda: time + 24 * 3600)(KEY3) - self.assertRaises(exc.InvalidTokenError, otp.match, token, time + 60) - - #============================================================================= - # match() tests - #============================================================================= - - def assertVerifyMatches(self, expect_skipped, token, time, # * - otp, gen_time=None, **kwds): - """helper to test otp.match() output is correct""" - # NOTE: TotpMatch return type tested more throughly above ^^^ - msg = "key=%r alg=%r period=%r token=%r gen_time=%r time=%r:" % \ - (otp.base32_key, otp.alg, otp.period, token, gen_time, time) - result = otp.match(token, time, **kwds) - self.assertTotpMatch(result, - time=otp.normalize_time(time), - period=otp.period, - window=kwds.get("window", 30), - skipped=expect_skipped, - msg=msg) - - def assertVerifyRaises(self, exc_class, token, time, # * - otp, gen_time=None, - **kwds): - """helper to test otp.match() throws correct error""" - # NOTE: TotpMatch return type tested more throughly above ^^^ - msg = "key=%r alg=%r period=%r token=%r gen_time=%r time=%r:" % \ - (otp.base32_key, otp.alg, otp.period, token, gen_time, time) - return self.assertRaises(exc_class, otp.match, token, time, - __msg__=msg, **kwds) - - def test_match_w_window(self): - """match() -- 'time' and 'window' parameters""" - - # init generator & helper - otp = self.randotp() - period = otp.period - time = self.randtime() - token = otp.generate(time).token - common = dict(otp=otp, gen_time=time) - assertMatches = partial(self.assertVerifyMatches, **common) - assertRaises = partial(self.assertVerifyRaises, **common) - - #------------------------------- - # basic validation, and 'window' parameter - #------------------------------- - - # validate against previous counter (passes if window >= period) - assertRaises(exc.InvalidTokenError, token, time - period, window=0) - assertMatches(+1, token, time - period, window=period) - assertMatches(+1, token, time - period, window=2 * period) - - # validate against current counter - assertMatches(0, token, time, window=0) - - # validate against next counter (passes if window >= period) - assertRaises(exc.InvalidTokenError, token, time + period, window=0) - assertMatches(-1, token, time + period, window=period) - assertMatches(-1, token, time + period, window=2 * period) - - # validate against two time steps later (should never pass) - assertRaises(exc.InvalidTokenError, token, time + 2 * period, window=0) - assertRaises(exc.InvalidTokenError, token, time + 2 * period, window=period) - assertMatches(-2, token, time + 2 * period, window=2 * period) - - # TODO: test window values that aren't multiples of period - # (esp ensure counter rounding works correctly) - - #------------------------------- - # time normalization - #------------------------------- - - # handle datetimes - dt = datetime.datetime.utcfromtimestamp(time) - assertMatches(0, token, dt, window=0) - - # reject invalid time - assertRaises(ValueError, token, -1) - - def test_match_w_skew(self): - """match() -- 'skew' parameters""" - # init generator & helper - otp = self.randotp() - period = otp.period - time = self.randtime() - common = dict(otp=otp, gen_time=time) - assertMatches = partial(self.assertVerifyMatches, **common) - assertRaises = partial(self.assertVerifyRaises, **common) - - # assume client is running far behind server / has excessive transmission delay - skew = 3 * period - behind_token = otp.generate(time - skew).token - assertRaises(exc.InvalidTokenError, behind_token, time, window=0) - assertMatches(-3, behind_token, time, window=0, skew=-skew) - - # assume client is running far ahead of server - ahead_token = otp.generate(time + skew).token - assertRaises(exc.InvalidTokenError, ahead_token, time, window=0) - assertMatches(+3, ahead_token, time, window=0, skew=skew) - - # TODO: test skew + larger window - - def test_match_w_reuse(self): - """match() -- 'reuse' and 'last_counter' parameters""" - - # init generator & helper - otp = self.randotp() - period = otp.period - time = self.randtime() - tdata = otp.generate(time) - token = tdata.token - counter = tdata.counter - expire_time = tdata.expire_time - common = dict(otp=otp, gen_time=time) - assertMatches = partial(self.assertVerifyMatches, **common) - assertRaises = partial(self.assertVerifyRaises, **common) - - # last counter unset -- - # previous period's token should count as valid - assertMatches(-1, token, time + period, window=period) - - # last counter set 2 periods ago -- - # previous period's token should count as valid - assertMatches(-1, token, time + period, last_counter=counter-1, - window=period) - - # last counter set 2 periods ago -- - # 2 periods ago's token should NOT count as valid - assertRaises(exc.InvalidTokenError, token, time + 2 * period, - last_counter=counter, window=period) - - # last counter set 1 period ago -- - # previous period's token should now be rejected as 'used' - err = assertRaises(exc.UsedTokenError, token, time + period, - last_counter=counter, window=period) - self.assertEqual(err.expire_time, expire_time) - - # last counter set to current period -- - # current period's token should be rejected - err = assertRaises(exc.UsedTokenError, token, time, - last_counter=counter, window=0) - self.assertEqual(err.expire_time, expire_time) - - def test_match_w_token_normalization(self): - """match() -- token normalization""" - # setup test helper - otp = TOTP('otxl2f5cctbprpzx') - match = otp.match - time = 1412889861 - - # separators / spaces should be stripped (orig token '332136') - self.assertTrue(match(' 3 32-136 ', time)) - - # ascii bytes - self.assertTrue(match(b'332136', time)) - - # too few digits - self.assertRaises(exc.MalformedTokenError, match, '12345', time) - - # invalid char - self.assertRaises(exc.MalformedTokenError, match, '12345X', time) - - # leading zeros count towards size - self.assertRaises(exc.MalformedTokenError, match, '0123456', time) - - def test_match_w_reference_vectors(self): - """match() -- reference vectors""" - for otp, time, token, expires, msg in self.iter_test_vectors(): - # create wrapper - match = otp.match - - # token should match against time - result = match(token, time) - self.assertTrue(result) - self.assertEqual(result.counter, time // otp.period, msg=msg) - - # should NOT match against another time - self.assertRaises(exc.InvalidTokenError, match, token, time + 100, window=0) - - #============================================================================= - # verify() tests - #============================================================================= - def test_verify(self): - """verify()""" - # NOTE: since this is thin wrapper around .from_source() and .match(), - # just testing basic behavior here. - - from passlib.totp import TOTP - - time = 1412889861 - TotpFactory = TOTP.using(now=lambda: time) - - # successful match - source1 = dict(v=1, type="totp", key='otxl2f5cctbprpzx') - match = TotpFactory.verify('332136', source1) - self.assertTotpMatch(match, time=time) - - # failed match - source1 = dict(v=1, type="totp", key='otxl2f5cctbprpzx') - self.assertRaises(exc.InvalidTokenError, TotpFactory.verify, '332155', source1) - - # bad source - source1 = dict(v=1, type="totp") - self.assertRaises(ValueError, TotpFactory.verify, '332155', source1) - - # successful match -- json source - source1json = '{"v": 1, "type": "totp", "key": "otxl2f5cctbprpzx"}' - match = TotpFactory.verify('332136', source1json) - self.assertTotpMatch(match, time=time) - - # successful match -- URI - source1uri = 'otpauth://totp/Label?secret=otxl2f5cctbprpzx' - match = TotpFactory.verify('332136', source1uri) - self.assertTotpMatch(match, time=time) - - #============================================================================= - # serialization frontend tests - #============================================================================= - def test_from_source(self): - """from_source()""" - from passlib.totp import TOTP - from_source = TOTP.from_source - - # uri (unicode) - otp = from_source(u("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "issuer=Example")) - self.assertEqual(otp.key, KEY4_RAW) - - # uri (bytes) - otp = from_source(b"otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&" - b"issuer=Example") - self.assertEqual(otp.key, KEY4_RAW) - - # dict - otp = from_source(dict(v=1, type="totp", key=KEY4)) - self.assertEqual(otp.key, KEY4_RAW) - - # json (unicode) - otp = from_source(u('{"v": 1, "type": "totp", "key": "JBSWY3DPEHPK3PXP"}')) - self.assertEqual(otp.key, KEY4_RAW) - - # json (bytes) - otp = from_source(b'{"v": 1, "type": "totp", "key": "JBSWY3DPEHPK3PXP"}') - self.assertEqual(otp.key, KEY4_RAW) - - # TOTP object -- return unchanged - self.assertIs(from_source(otp), otp) - - # TOTP object w/ different wallet -- return new one. - wallet1 = AppWallet() - otp1 = TOTP.using(wallet=wallet1).from_source(otp) - self.assertIsNot(otp1, otp) - self.assertEqual(otp1.to_dict(), otp.to_dict()) - - # TOTP object w/ same wallet -- return original - otp2 = TOTP.using(wallet=wallet1).from_source(otp1) - self.assertIs(otp2, otp1) - - # random string - self.assertRaises(ValueError, from_source, u("foo")) - self.assertRaises(ValueError, from_source, b"foo") - - #============================================================================= - # uri serialization tests - #============================================================================= - def test_from_uri(self): - """from_uri()""" - from passlib.totp import TOTP - from_uri = TOTP.from_uri - - # URIs from https://code.google.com/p/google-authenticator/wiki/KeyUriFormat - - #-------------------------------------------------------------------------------- - # canonical uri - #-------------------------------------------------------------------------------- - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "issuer=Example") - self.assertIsInstance(otp, TOTP) - self.assertEqual(otp.key, KEY4_RAW) - self.assertEqual(otp.label, "alice@google.com") - self.assertEqual(otp.issuer, "Example") - self.assertEqual(otp.alg, "sha1") # default - self.assertEqual(otp.period, 30) # default - self.assertEqual(otp.digits, 6) # default - - #-------------------------------------------------------------------------------- - # secret param - #-------------------------------------------------------------------------------- - - # secret case insensitive - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=jbswy3dpehpk3pxp&" - "issuer=Example") - self.assertEqual(otp.key, KEY4_RAW) - - # missing secret - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?digits=6") - - # undecodable secret - self.assertRaises(Base32DecodeError, from_uri, "otpauth://totp/Example:alice@google.com?" - "secret=JBSWY3DPEHP@3PXP") - - #-------------------------------------------------------------------------------- - # label param - #-------------------------------------------------------------------------------- - - # w/ encoded space - otp = from_uri("otpauth://totp/Provider1:Alice%20Smith?secret=JBSWY3DPEHPK3PXP&" - "issuer=Provider1") - self.assertEqual(otp.label, "Alice Smith") - self.assertEqual(otp.issuer, "Provider1") - - # w/ encoded space and colon - # (note url has leading space before 'alice') -- taken from KeyURI spec - otp = from_uri("otpauth://totp/Big%20Corporation%3A%20alice@bigco.com?" - "secret=JBSWY3DPEHPK3PXP") - self.assertEqual(otp.label, "alice@bigco.com") - self.assertEqual(otp.issuer, "Big Corporation") - - #-------------------------------------------------------------------------------- - # issuer param / prefix - #-------------------------------------------------------------------------------- - - # 'new style' issuer only - otp = from_uri("otpauth://totp/alice@bigco.com?secret=JBSWY3DPEHPK3PXP&issuer=Big%20Corporation") - self.assertEqual(otp.label, "alice@bigco.com") - self.assertEqual(otp.issuer, "Big Corporation") - - # new-vs-old issuer mismatch - self.assertRaises(ValueError, TOTP.from_uri, - "otpauth://totp/Provider1:alice?secret=JBSWY3DPEHPK3PXP&issuer=Provider2") - - #-------------------------------------------------------------------------------- - # algorithm param - #-------------------------------------------------------------------------------- - - # custom alg - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA256") - self.assertEqual(otp.alg, "sha256") - - # unknown alg - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?" - "secret=JBSWY3DPEHPK3PXP&algorithm=SHA333") - - #-------------------------------------------------------------------------------- - # digit param - #-------------------------------------------------------------------------------- - - # custom digits - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&digits=8") - self.assertEqual(otp.digits, 8) - - # digits out of range / invalid - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&digits=A") - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&digits=%20") - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&digits=15") - - #-------------------------------------------------------------------------------- - # period param - #-------------------------------------------------------------------------------- - - # custom period - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&period=63") - self.assertEqual(otp.period, 63) - - # reject period < 1 - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?" - "secret=JBSWY3DPEHPK3PXP&period=0") - - self.assertRaises(ValueError, from_uri, "otpauth://totp/Example:alice@google.com?" - "secret=JBSWY3DPEHPK3PXP&period=-1") - - #-------------------------------------------------------------------------------- - # unrecognized param - #-------------------------------------------------------------------------------- - - # should issue warning, but otherwise ignore extra param - with self.assertWarningList([ - dict(category=exc.PasslibRuntimeWarning, message_re="unexpected parameters encountered") - ]): - otp = from_uri("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "foo=bar&period=63") - self.assertEqual(otp.base32_key, KEY4) - self.assertEqual(otp.period, 63) - - def test_to_uri(self): - """to_uri()""" - - #------------------------------------------------------------------------- - # label & issuer parameters - #------------------------------------------------------------------------- - - # with label & issuer - otp = TOTP(KEY4, alg="sha1", digits=6, period=30) - self.assertEqual(otp.to_uri("alice@google.com", "Example Org"), - "otpauth://totp/Example%20Org:alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "issuer=Example%20Org") - - # label is required - self.assertRaises(ValueError, otp.to_uri, None, "Example Org") - - # with label only - self.assertEqual(otp.to_uri("alice@google.com"), - "otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP") - - # with default label from constructor - otp.label = "alice@google.com" - self.assertEqual(otp.to_uri(), - "otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP") - - # with default label & default issuer from constructor - otp.issuer = "Example Org" - self.assertEqual(otp.to_uri(), - "otpauth://totp/Example%20Org:alice@google.com?secret=JBSWY3DPEHPK3PXP" - "&issuer=Example%20Org") - - # reject invalid label - self.assertRaises(ValueError, otp.to_uri, "label:with:semicolons") - - # reject invalid issuer - self.assertRaises(ValueError, otp.to_uri, "alice@google.com", "issuer:with:semicolons") - - #------------------------------------------------------------------------- - # algorithm parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, alg="sha256").to_uri("alice@google.com"), - "otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "algorithm=SHA256") - - #------------------------------------------------------------------------- - # digits parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, digits=8).to_uri("alice@google.com"), - "otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "digits=8") - - #------------------------------------------------------------------------- - # period parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, period=63).to_uri("alice@google.com"), - "otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP&" - "period=63") - - #============================================================================= - # dict serialization tests - #============================================================================= - def test_from_dict(self): - """from_dict()""" - from passlib.totp import TOTP - from_dict = TOTP.from_dict - - #-------------------------------------------------------------------------------- - # canonical simple example - #-------------------------------------------------------------------------------- - otp = from_dict(dict(v=1, type="totp", key=KEY4, label="alice@google.com", issuer="Example")) - self.assertIsInstance(otp, TOTP) - self.assertEqual(otp.key, KEY4_RAW) - self.assertEqual(otp.label, "alice@google.com") - self.assertEqual(otp.issuer, "Example") - self.assertEqual(otp.alg, "sha1") # default - self.assertEqual(otp.period, 30) # default - self.assertEqual(otp.digits, 6) # default - - #-------------------------------------------------------------------------------- - # metadata - #-------------------------------------------------------------------------------- - - # missing version - self.assertRaises(ValueError, from_dict, dict(type="totp", key=KEY4)) - - # invalid version - self.assertRaises(ValueError, from_dict, dict(v=0, type="totp", key=KEY4)) - self.assertRaises(ValueError, from_dict, dict(v=999, type="totp", key=KEY4)) - - # missing type - self.assertRaises(ValueError, from_dict, dict(v=1, key=KEY4)) - - #-------------------------------------------------------------------------------- - # secret param - #-------------------------------------------------------------------------------- - - # secret case insensitive - otp = from_dict(dict(v=1, type="totp", key=KEY4.lower(), label="alice@google.com", issuer="Example")) - self.assertEqual(otp.key, KEY4_RAW) - - # missing secret - self.assertRaises(ValueError, from_dict, dict(v=1, type="totp")) - - # undecodable secret - self.assertRaises(Base32DecodeError, from_dict, - dict(v=1, type="totp", key="JBSWY3DPEHP@3PXP")) - - #-------------------------------------------------------------------------------- - # label & issuer params - #-------------------------------------------------------------------------------- - - otp = from_dict(dict(v=1, type="totp", key=KEY4, label="Alice Smith", issuer="Provider1")) - self.assertEqual(otp.label, "Alice Smith") - self.assertEqual(otp.issuer, "Provider1") - - #-------------------------------------------------------------------------------- - # algorithm param - #-------------------------------------------------------------------------------- - - # custom alg - otp = from_dict(dict(v=1, type="totp", key=KEY4, alg="sha256")) - self.assertEqual(otp.alg, "sha256") - - # unknown alg - self.assertRaises(ValueError, from_dict, dict(v=1, type="totp", key=KEY4, alg="sha333")) - - #-------------------------------------------------------------------------------- - # digit param - #-------------------------------------------------------------------------------- - - # custom digits - otp = from_dict(dict(v=1, type="totp", key=KEY4, digits=8)) - self.assertEqual(otp.digits, 8) - - # digits out of range / invalid - self.assertRaises(TypeError, from_dict, dict(v=1, type="totp", key=KEY4, digits="A")) - self.assertRaises(ValueError, from_dict, dict(v=1, type="totp", key=KEY4, digits=15)) - - #-------------------------------------------------------------------------------- - # period param - #-------------------------------------------------------------------------------- - - # custom period - otp = from_dict(dict(v=1, type="totp", key=KEY4, period=63)) - self.assertEqual(otp.period, 63) - - # reject period < 1 - self.assertRaises(ValueError, from_dict, dict(v=1, type="totp", key=KEY4, period=0)) - self.assertRaises(ValueError, from_dict, dict(v=1, type="totp", key=KEY4, period=-1)) - - #-------------------------------------------------------------------------------- - # unrecognized param - #-------------------------------------------------------------------------------- - self.assertRaises(TypeError, from_dict, dict(v=1, type="totp", key=KEY4, INVALID=123)) - - def test_to_dict(self): - """to_dict()""" - - #------------------------------------------------------------------------- - # label & issuer parameters - #------------------------------------------------------------------------- - - # without label or issuer - otp = TOTP(KEY4, alg="sha1", digits=6, period=30) - self.assertEqual(otp.to_dict(), dict(v=1, type="totp", key=KEY4)) - - # with label & issuer from constructor - otp = TOTP(KEY4, alg="sha1", digits=6, period=30, - label="alice@google.com", issuer="Example Org") - self.assertEqual(otp.to_dict(), - dict(v=1, type="totp", key=KEY4, - label="alice@google.com", issuer="Example Org")) - - # with label only - otp = TOTP(KEY4, alg="sha1", digits=6, period=30, - label="alice@google.com") - self.assertEqual(otp.to_dict(), - dict(v=1, type="totp", key=KEY4, - label="alice@google.com")) - - # with issuer only - otp = TOTP(KEY4, alg="sha1", digits=6, period=30, - issuer="Example Org") - self.assertEqual(otp.to_dict(), - dict(v=1, type="totp", key=KEY4, - issuer="Example Org")) - - # don't serialize default issuer - TotpFactory = TOTP.using(issuer="Example Org") - otp = TotpFactory(KEY4) - self.assertEqual(otp.to_dict(), dict(v=1, type="totp", key=KEY4)) - - # don't serialize default issuer *even if explicitly set* - otp = TotpFactory(KEY4, issuer="Example Org") - self.assertEqual(otp.to_dict(), dict(v=1, type="totp", key=KEY4)) - - #------------------------------------------------------------------------- - # algorithm parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, alg="sha256").to_dict(), - dict(v=1, type="totp", key=KEY4, alg="sha256")) - - #------------------------------------------------------------------------- - # digits parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, digits=8).to_dict(), - dict(v=1, type="totp", key=KEY4, digits=8)) - - #------------------------------------------------------------------------- - # period parameter - #------------------------------------------------------------------------- - self.assertEqual(TOTP(KEY4, period=63).to_dict(), - dict(v=1, type="totp", key=KEY4, period=63)) - - # TODO: to_dict() - # with encrypt=False - # with encrypt="auto" + wallet + secrets - # with encrypt="auto" + wallet + no secrets - # with encrypt="auto" + no wallet - # with encrypt=True + wallet + secrets - # with encrypt=True + wallet + no secrets - # with encrypt=True + no wallet - # that 'changed' is set for old versions, and old encryption tags. - - #============================================================================= - # json serialization tests - #============================================================================= - - # TODO: from_json() / to_json(). - # (skipped for right now cause just wrapper for from_dict/to_dict) - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils.py deleted file mode 100644 index 59ba160..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_utils.py +++ /dev/null @@ -1,1171 +0,0 @@ -"""tests for passlib.util""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -from functools import partial -import warnings -# site -# pkg -# module -from passlib.utils import is_ascii_safe, to_bytes -from passlib.utils.compat import irange, PY2, PY3, u, unicode, join_bytes, PYPY -from passlib.tests.utils import TestCase, hb, run_with_fixed_seeds - -#============================================================================= -# byte funcs -#============================================================================= -class MiscTest(TestCase): - """tests various parts of utils module""" - - # NOTE: could test xor_bytes(), but it's exercised well enough by pbkdf2 test - - def test_compat(self): - """test compat's lazymodule""" - from passlib.utils import compat - # "" - self.assertRegex(repr(compat), - r"^$") - - # test synthentic dir() - dir(compat) - self.assertTrue('UnicodeIO' in dir(compat)) - self.assertTrue('irange' in dir(compat)) - - def test_classproperty(self): - from passlib.utils.decor import classproperty - - class test(object): - xvar = 1 - @classproperty - def xprop(cls): - return cls.xvar - - self.assertEqual(test.xprop, 1) - prop = test.__dict__['xprop'] - self.assertIs(prop.im_func, prop.__func__) - - def test_deprecated_function(self): - from passlib.utils.decor import deprecated_function - # NOTE: not comprehensive, just tests the basic behavior - - @deprecated_function(deprecated="1.6", removed="1.8") - def test_func(*args): - """test docstring""" - return args - - self.assertTrue(".. deprecated::" in test_func.__doc__) - - with self.assertWarningList(dict(category=DeprecationWarning, - message="the function passlib.tests.test_utils.test_func() " - "is deprecated as of Passlib 1.6, and will be " - "removed in Passlib 1.8." - )): - self.assertEqual(test_func(1,2), (1,2)) - - def test_memoized_property(self): - from passlib.utils.decor import memoized_property - - class dummy(object): - counter = 0 - - @memoized_property - def value(self): - value = self.counter - self.counter = value+1 - return value - - d = dummy() - self.assertEqual(d.value, 0) - self.assertEqual(d.value, 0) - self.assertEqual(d.counter, 1) - - prop = dummy.value - if not PY3: - self.assertIs(prop.im_func, prop.__func__) - - def test_getrandbytes(self): - """getrandbytes()""" - from passlib.utils import getrandbytes - wrapper = partial(getrandbytes, self.getRandom()) - self.assertEqual(len(wrapper(0)), 0) - a = wrapper(10) - b = wrapper(10) - self.assertIsInstance(a, bytes) - self.assertEqual(len(a), 10) - self.assertEqual(len(b), 10) - self.assertNotEqual(a, b) - - @run_with_fixed_seeds(count=1024) - def test_getrandstr(self, seed): - """getrandstr()""" - from passlib.utils import getrandstr - - wrapper = partial(getrandstr, self.getRandom(seed=seed)) - - # count 0 - self.assertEqual(wrapper('abc',0), '') - - # count <0 - self.assertRaises(ValueError, wrapper, 'abc', -1) - - # letters 0 - self.assertRaises(ValueError, wrapper, '', 0) - - # letters 1 - self.assertEqual(wrapper('a', 5), 'aaaaa') - - # NOTE: the following parts are non-deterministic, - # with a small chance of failure (outside chance it may pick - # a string w/o one char, even more remote chance of picking - # same string). to combat this, we run it against multiple - # fixed seeds (using run_with_fixed_seeds decorator), - # and hope that they're sufficient to test the range of behavior. - - # letters - x = wrapper(u('abc'), 32) - y = wrapper(u('abc'), 32) - self.assertIsInstance(x, unicode) - self.assertNotEqual(x,y) - self.assertEqual(sorted(set(x)), [u('a'),u('b'),u('c')]) - - # bytes - x = wrapper(b'abc', 32) - y = wrapper(b'abc', 32) - self.assertIsInstance(x, bytes) - self.assertNotEqual(x,y) - # NOTE: decoding this due to py3 bytes - self.assertEqual(sorted(set(x.decode("ascii"))), [u('a'),u('b'),u('c')]) - - def test_generate_password(self): - """generate_password()""" - from passlib.utils import generate_password - warnings.filterwarnings("ignore", "The function.*generate_password\(\) is deprecated") - self.assertEqual(len(generate_password(15)), 15) - - def test_is_crypt_context(self): - """test is_crypt_context()""" - from passlib.utils import is_crypt_context - from passlib.context import CryptContext - cc = CryptContext(["des_crypt"]) - self.assertTrue(is_crypt_context(cc)) - self.assertFalse(not is_crypt_context(cc)) - - def test_genseed(self): - """test genseed()""" - import random - from passlib.utils import genseed - rng = random.Random(genseed()) - a = rng.randint(0, 10**10) - - rng = random.Random(genseed()) - b = rng.randint(0, 10**10) - - self.assertNotEqual(a,b) - - rng.seed(genseed(rng)) - - def test_crypt(self): - """test crypt.crypt() wrappers""" - from passlib.utils import has_crypt, safe_crypt, test_crypt - from passlib.registry import get_supported_os_crypt_schemes, get_crypt_handler - - # test everything is disabled - supported = get_supported_os_crypt_schemes() - if not has_crypt: - self.assertEqual(supported, ()) - self.assertEqual(safe_crypt("test", "aa"), None) - self.assertFalse(test_crypt("test", "aaqPiZY5xR5l.")) # des_crypt() hash of "test" - raise self.skipTest("crypt.crypt() not available") - - # expect there to be something supported, if crypt() is present - if not supported: - # NOTE: failures here should be investigated. usually means one of: - # 1) at least one of passlib's os_crypt detection routines is giving false negative - # 2) crypt() ONLY supports some hash alg which passlib doesn't know about - # 3) crypt() is present but completely disabled (never encountered this yet) - raise self.fail("crypt() present, but no supported schemes found!") - - # pick cheap alg if possible, with minimum rounds, to speed up this test. - # NOTE: trusting hasher class works properly (should have been verified using it's own UTs) - for scheme in ("md5_crypt", "sha256_crypt"): - if scheme in supported: - break - else: - scheme = supported[-1] - hasher = get_crypt_handler(scheme) - if getattr(hasher, "min_rounds", None): - hasher = hasher.using(rounds=hasher.min_rounds) - - # helpers to generate hashes & config strings to work with - def get_hash(secret): - assert isinstance(secret, unicode) - hash = hasher.hash(secret) - if isinstance(hash, bytes): # py2 - hash = hash.decode("utf-8") - assert isinstance(hash, unicode) - return hash - - # test ascii password & return type - s1 = u("test") - h1 = get_hash(s1) - result = safe_crypt(s1, h1) - self.assertIsInstance(result, unicode) - self.assertEqual(result, h1) - self.assertEqual(safe_crypt(to_bytes(s1), to_bytes(h1)), h1) - - # make sure crypt doesn't just blindly return h1 for whatever we pass in - h1x = h1[:-2] + 'xx' - self.assertEqual(safe_crypt(s1, h1x), h1) - - # test utf-8 / unicode password - s2 = u('test\u1234') - h2 = get_hash(s2) - self.assertEqual(safe_crypt(s2, h2), h2) - self.assertEqual(safe_crypt(to_bytes(s2), to_bytes(h2)), h2) - - # test rejects null chars in password - self.assertRaises(ValueError, safe_crypt, '\x00', h1) - - # check test_crypt() - self.assertTrue(test_crypt("test", h1)) - self.assertFalse(test_crypt("test", h1x)) - - # check crypt returning variant error indicators - # some platforms return None on errors, others empty string, - # The BSDs in some cases return ":" - import passlib.utils as mod - orig = mod._crypt - try: - retval = None - mod._crypt = lambda secret, hash: retval - - for retval in [None, "", ":", ":0", "*0"]: - self.assertEqual(safe_crypt("test", h1), None) - self.assertFalse(test_crypt("test", h1)) - - retval = 'xxx' - self.assertEqual(safe_crypt("test", h1), "xxx") - self.assertFalse(test_crypt("test", h1)) - - finally: - mod._crypt = orig - - def test_consteq(self): - """test consteq()""" - # NOTE: this test is kind of over the top, but that's only because - # this is used for the critical task of comparing hashes for equality. - from passlib.utils import consteq, str_consteq - - # ensure error raises for wrong types - self.assertRaises(TypeError, consteq, u(''), b'') - self.assertRaises(TypeError, consteq, u(''), 1) - self.assertRaises(TypeError, consteq, u(''), None) - - self.assertRaises(TypeError, consteq, b'', u('')) - self.assertRaises(TypeError, consteq, b'', 1) - self.assertRaises(TypeError, consteq, b'', None) - - self.assertRaises(TypeError, consteq, None, u('')) - self.assertRaises(TypeError, consteq, None, b'') - self.assertRaises(TypeError, consteq, 1, u('')) - self.assertRaises(TypeError, consteq, 1, b'') - - def consteq_supports_string(value): - # under PY2, it supports all unicode strings (when present at all), - # under PY3, compare_digest() only supports ascii unicode strings. - # confirmed for: cpython 2.7.9, cpython 3.4, pypy, pypy3, pyston - return (consteq is str_consteq or PY2 or is_ascii_safe(value)) - - # check equal inputs compare correctly - for value in [ - u("a"), - u("abc"), - u("\xff\xa2\x12\x00")*10, - ]: - if consteq_supports_string(value): - self.assertTrue(consteq(value, value), "value %r:" % (value,)) - else: - self.assertRaises(TypeError, consteq, value, value) - self.assertTrue(str_consteq(value, value), "value %r:" % (value,)) - - value = value.encode("latin-1") - self.assertTrue(consteq(value, value), "value %r:" % (value,)) - - # check non-equal inputs compare correctly - for l,r in [ - # check same-size comparisons with differing contents fail. - (u("a"), u("c")), - (u("abcabc"), u("zbaabc")), - (u("abcabc"), u("abzabc")), - (u("abcabc"), u("abcabz")), - ((u("\xff\xa2\x12\x00")*10)[:-1] + u("\x01"), - u("\xff\xa2\x12\x00")*10), - - # check different-size comparisons fail. - (u(""), u("a")), - (u("abc"), u("abcdef")), - (u("abc"), u("defabc")), - (u("qwertyuiopasdfghjklzxcvbnm"), u("abc")), - ]: - if consteq_supports_string(l) and consteq_supports_string(r): - self.assertFalse(consteq(l, r), "values %r %r:" % (l,r)) - self.assertFalse(consteq(r, l), "values %r %r:" % (r,l)) - else: - self.assertRaises(TypeError, consteq, l, r) - self.assertRaises(TypeError, consteq, r, l) - self.assertFalse(str_consteq(l, r), "values %r %r:" % (l,r)) - self.assertFalse(str_consteq(r, l), "values %r %r:" % (r,l)) - - l = l.encode("latin-1") - r = r.encode("latin-1") - self.assertFalse(consteq(l, r), "values %r %r:" % (l,r)) - self.assertFalse(consteq(r, l), "values %r %r:" % (r,l)) - - # TODO: add some tests to ensure we take THETA(strlen) time. - # this might be hard to do reproducably. - # NOTE: below code was used to generate stats for analysis - ##from math import log as logb - ##import timeit - ##multipliers = [ 1< encode() -> decode() -> raw - # - - # generate some random bytes - size = rng.randint(1 if saw_zero else 0, 12) - if not size: - saw_zero = True - enc_size = (4*size+2)//3 - raw = getrandbytes(rng, size) - - # encode them, check invariants - encoded = engine.encode_bytes(raw) - self.assertEqual(len(encoded), enc_size) - - # make sure decode returns original - result = engine.decode_bytes(encoded) - self.assertEqual(result, raw) - - # - # test encoded -> decode() -> encode() -> encoded - # - - # generate some random encoded data - if size % 4 == 1: - size += rng.choice([-1,1,2]) - raw_size = 3*size//4 - encoded = getrandstr(rng, engine.bytemap, size) - - # decode them, check invariants - raw = engine.decode_bytes(encoded) - self.assertEqual(len(raw), raw_size, "encoded %d:" % size) - - # make sure encode returns original (barring padding bits) - result = engine.encode_bytes(raw) - if size % 4: - self.assertEqual(result[:-1], encoded[:-1]) - else: - self.assertEqual(result, encoded) - - def test_repair_unused(self): - """test repair_unused()""" - # NOTE: this test relies on encode_bytes() always returning clear - # padding bits - which should be ensured by test vectors. - from passlib.utils import getrandstr - rng = self.getRandom() - engine = self.engine - check_repair_unused = self.engine.check_repair_unused - i = 0 - while i < 300: - size = rng.randint(0,23) - cdata = getrandstr(rng, engine.charmap, size).encode("ascii") - if size & 3 == 1: - # should throw error - self.assertRaises(ValueError, check_repair_unused, cdata) - continue - rdata = engine.encode_bytes(engine.decode_bytes(cdata)) - if rng.random() < .5: - cdata = cdata.decode("ascii") - rdata = rdata.decode("ascii") - if cdata == rdata: - # should leave unchanged - ok, result = check_repair_unused(cdata) - self.assertFalse(ok) - self.assertEqual(result, rdata) - else: - # should repair bits - self.assertNotEqual(size % 4, 0) - ok, result = check_repair_unused(cdata) - self.assertTrue(ok) - self.assertEqual(result, rdata) - i += 1 - - #=================================================================== - # test transposed encode/decode - encoding independant - #=================================================================== - # NOTE: these tests assume normal encode/decode has been tested elsewhere. - - transposed = [ - # orig, result, transpose map - (b"\x33\x22\x11", b"\x11\x22\x33",[2,1,0]), - (b"\x22\x33\x11", b"\x11\x22\x33",[1,2,0]), - ] - - transposed_dups = [ - # orig, result, transpose projection - (b"\x11\x11\x22", b"\x11\x22\x33",[0,0,1]), - ] - - def test_encode_transposed_bytes(self): - """test encode_transposed_bytes()""" - engine = self.engine - for result, input, offsets in self.transposed + self.transposed_dups: - tmp = engine.encode_transposed_bytes(input, offsets) - out = engine.decode_bytes(tmp) - self.assertEqual(out, result) - - self.assertRaises(TypeError, engine.encode_transposed_bytes, u("a"), []) - - def test_decode_transposed_bytes(self): - """test decode_transposed_bytes()""" - engine = self.engine - for input, result, offsets in self.transposed: - tmp = engine.encode_bytes(input) - out = engine.decode_transposed_bytes(tmp, offsets) - self.assertEqual(out, result) - - def test_decode_transposed_bytes_bad(self): - """test decode_transposed_bytes() fails if map is a one-way""" - engine = self.engine - for input, _, offsets in self.transposed_dups: - tmp = engine.encode_bytes(input) - self.assertRaises(TypeError, engine.decode_transposed_bytes, tmp, - offsets) - - #=================================================================== - # test 6bit handling - #=================================================================== - def check_int_pair(self, bits, encoded_pairs): - """helper to check encode_intXX & decode_intXX functions""" - rng = self.getRandom() - engine = self.engine - encode = getattr(engine, "encode_int%s" % bits) - decode = getattr(engine, "decode_int%s" % bits) - pad = -bits % 6 - chars = (bits+pad)//6 - upper = 1< block_size, and wrong type - self.assertRaises(ValueError, helper, keylen=-1) - self.assertRaises(ValueError, helper, keylen=17, hash='md5') - self.assertRaises(TypeError, helper, keylen='1') - -#============================================================================= -# test PBKDF2 support -#============================================================================= -class Pbkdf2_Test(TestCase): - """test pbkdf2() support""" - descriptionPrefix = "passlib.utils.pbkdf2.pbkdf2()" - - pbkdf2_test_vectors = [ - # (result, secret, salt, rounds, keylen, prf="sha1") - - # - # from rfc 3962 - # - - # test case 1 / 128 bit - ( - hb("cdedb5281bb2f801565a1122b2563515"), - b"password", b"ATHENA.MIT.EDUraeburn", 1, 16 - ), - - # test case 2 / 128 bit - ( - hb("01dbee7f4a9e243e988b62c73cda935d"), - b"password", b"ATHENA.MIT.EDUraeburn", 2, 16 - ), - - # test case 2 / 256 bit - ( - hb("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"), - b"password", b"ATHENA.MIT.EDUraeburn", 2, 32 - ), - - # test case 3 / 256 bit - ( - hb("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"), - b"password", b"ATHENA.MIT.EDUraeburn", 1200, 32 - ), - - # test case 4 / 256 bit - ( - hb("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"), - b"password", b'\x12\x34\x56\x78\x78\x56\x34\x12', 5, 32 - ), - - # test case 5 / 256 bit - ( - hb("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"), - b"X"*64, b"pass phrase equals block size", 1200, 32 - ), - - # test case 6 / 256 bit - ( - hb("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"), - b"X"*65, b"pass phrase exceeds block size", 1200, 32 - ), - - # - # from rfc 6070 - # - ( - hb("0c60c80f961f0e71f3a9b524af6012062fe037a6"), - b"password", b"salt", 1, 20, - ), - - ( - hb("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), - b"password", b"salt", 2, 20, - ), - - ( - hb("4b007901b765489abead49d926f721d065a429c1"), - b"password", b"salt", 4096, 20, - ), - - # just runs too long - could enable if ALL option is set - ##( - ## - ## unhexlify("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"), - ## "password", "salt", 16777216, 20, - ##), - - ( - hb("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), - b"passwordPASSWORDpassword", - b"saltSALTsaltSALTsaltSALTsaltSALTsalt", - 4096, 25, - ), - - ( - hb("56fa6aa75548099dcc37d7f03425e0c3"), - b"pass\00word", b"sa\00lt", 4096, 16, - ), - - # - # from example in http://grub.enbug.org/Authentication - # - ( - hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED" - "97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC" - "6C29E293F0A0"), - b"hello", - hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71" - "784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073" - "994D79080136"), - 10000, 64, "hmac-sha512" - ), - - # - # custom - # - ( - hb('e248fb6b13365146f8ac6307cc222812'), - b"secret", b"salt", 10, 16, "hmac-sha1", - ), - ( - hb('e248fb6b13365146f8ac6307cc2228127872da6d'), - b"secret", b"salt", 10, None, "hmac-sha1", - ), - - ] - - def setUp(self): - super(Pbkdf2_Test, self).setUp() - warnings.filterwarnings("ignore", ".*passlib.utils.pbkdf2.*deprecated", DeprecationWarning) - - def test_known(self): - """test reference vectors""" - from passlib.utils.pbkdf2 import pbkdf2 - for row in self.pbkdf2_test_vectors: - correct, secret, salt, rounds, keylen = row[:5] - prf = row[5] if len(row) == 6 else "hmac-sha1" - result = pbkdf2(secret, salt, rounds, keylen, prf) - self.assertEqual(result, correct) - - def test_border(self): - """test border cases""" - from passlib.utils.pbkdf2 import pbkdf2 - def helper(secret=b'password', salt=b'salt', rounds=1, keylen=None, prf="hmac-sha1"): - return pbkdf2(secret, salt, rounds, keylen, prf) - helper() - - # invalid rounds - self.assertRaises(ValueError, helper, rounds=-1) - self.assertRaises(ValueError, helper, rounds=0) - self.assertRaises(TypeError, helper, rounds='x') - - # invalid keylen - self.assertRaises(ValueError, helper, keylen=-1) - self.assertRaises(ValueError, helper, keylen=0) - helper(keylen=1) - self.assertRaises(OverflowError, helper, keylen=20*(2**32-1)+1) - self.assertRaises(TypeError, helper, keylen='x') - - # invalid secret/salt type - self.assertRaises(TypeError, helper, salt=5) - self.assertRaises(TypeError, helper, secret=5) - - # invalid hash - self.assertRaises(ValueError, helper, prf='hmac-foo') - self.assertRaises(NotImplementedError, helper, prf='foo') - self.assertRaises(TypeError, helper, prf=5) - - def test_default_keylen(self): - """test keylen==None""" - from passlib.utils.pbkdf2 import pbkdf2 - def helper(secret=b'password', salt=b'salt', rounds=1, keylen=None, prf="hmac-sha1"): - return pbkdf2(secret, salt, rounds, keylen, prf) - self.assertEqual(len(helper(prf='hmac-sha1')), 20) - self.assertEqual(len(helper(prf='hmac-sha256')), 32) - - def test_custom_prf(self): - """test custom prf function""" - from passlib.utils.pbkdf2 import pbkdf2 - def prf(key, msg): - return hashlib.md5(key+msg+b'fooey').digest() - self.assertRaises(NotImplementedError, pbkdf2, b'secret', b'salt', 1000, 20, prf) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_win32.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_win32.py deleted file mode 100644 index e818b62..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/test_win32.py +++ /dev/null @@ -1,50 +0,0 @@ -"""tests for passlib.win32 -- (c) Assurance Technologies 2003-2009""" -#============================================================================= -# imports -#============================================================================= -# core -import warnings -# site -# pkg -from passlib.tests.utils import TestCase -# module -from passlib.utils.compat import u - -#============================================================================= -# -#============================================================================= -class UtilTest(TestCase): - """test util funcs in passlib.win32""" - - ##test hashes from http://msdn.microsoft.com/en-us/library/cc245828(v=prot.10).aspx - ## among other places - - def setUp(self): - super(UtilTest, self).setUp() - warnings.filterwarnings("ignore", - "the 'passlib.win32' module is deprecated") - - def test_lmhash(self): - from passlib.win32 import raw_lmhash - for secret, hash in [ - ("OLDPASSWORD", u("c9b81d939d6fd80cd408e6b105741864")), - ("NEWPASSWORD", u('09eeab5aa415d6e4d408e6b105741864')), - ("welcome", u("c23413a8a1e7665faad3b435b51404ee")), - ]: - result = raw_lmhash(secret, hex=True) - self.assertEqual(result, hash) - - def test_nthash(self): - warnings.filterwarnings("ignore", - r"nthash\.raw_nthash\(\) is deprecated") - from passlib.win32 import raw_nthash - for secret, hash in [ - ("OLDPASSWORD", u("6677b2c394311355b54f25eec5bfacf5")), - ("NEWPASSWORD", u("256781a62031289d3c2c98c14f1efc8c")), - ]: - result = raw_nthash(secret, hex=True) - self.assertEqual(result, hash) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/tox_support.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/tox_support.py deleted file mode 100644 index 43170bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/tox_support.py +++ /dev/null @@ -1,83 +0,0 @@ -"""passlib.tests.tox_support - helper script for tox tests""" -#============================================================================= -# init script env -#============================================================================= -import os, sys -root_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir) -sys.path.insert(0, root_dir) - -#============================================================================= -# imports -#============================================================================= -# core -import re -import logging; log = logging.getLogger(__name__) -# site -# pkg -from passlib.utils.compat import print_ -# local -__all__ = [ -] - -#============================================================================= -# main -#============================================================================= -TH_PATH = "passlib.tests.test_handlers" - -def do_hash_tests(*args): - """return list of hash algorithm tests that match regexes""" - if not args: - print(TH_PATH) - return - suffix = '' - args = list(args) - while True: - if args[0] == "--method": - suffix = '.' + args[1] - del args[:2] - else: - break - from passlib.tests import test_handlers - names = [TH_PATH + ":" + name + suffix for name in dir(test_handlers) - if not name.startswith("_") and any(re.match(arg,name) for arg in args)] - print_("\n".join(names)) - return not names - -def do_preset_tests(name): - """return list of preset test names""" - if name == "django" or name == "django-hashes": - do_hash_tests("django_.*_test", "hex_md5_test") - if name == "django": - print_("passlib.tests.test_ext_django") - else: - raise ValueError("unknown name: %r" % name) - -def do_setup_gae(path, runtime): - """write fake GAE ``app.yaml`` to current directory so nosegae will work""" - from passlib.tests.utils import set_file - set_file(os.path.join(path, "app.yaml"), """\ -application: fake-app -version: 2 -runtime: %s -api_version: 1 -threadsafe: no - -handlers: -- url: /.* - script: dummy.py - -libraries: -- name: django - version: "latest" -""" % runtime) - -def main(cmd, *args): - return globals()["do_" + cmd](*args) - -if __name__ == "__main__": - import sys - sys.exit(main(*sys.argv[1:]) or 0) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/tests/utils.py b/backend/venv39/lib/python3.9/site-packages/passlib/tests/utils.py deleted file mode 100644 index 79a9f9f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/tests/utils.py +++ /dev/null @@ -1,3621 +0,0 @@ -"""helpers for passlib unittests""" -#============================================================================= -# imports -#============================================================================= -from __future__ import with_statement -# core -from binascii import unhexlify -import contextlib -from functools import wraps, partial -import hashlib -import logging; log = logging.getLogger(__name__) -import random -import re -import os -import sys -import tempfile -import threading -import time -from passlib.exc import PasslibHashWarning, PasslibConfigWarning -from passlib.utils.compat import PY3, JYTHON -import warnings -from warnings import warn -# site -# pkg -from passlib import exc -from passlib.exc import MissingBackendError -import passlib.registry as registry -from passlib.tests.backports import TestCase as _TestCase, skip, skipIf, skipUnless, SkipTest -from passlib.utils import has_rounds_info, has_salt_info, rounds_cost_values, \ - rng as sys_rng, getrandstr, is_ascii_safe, to_native_str, \ - repeat_string, tick, batch -from passlib.utils.compat import iteritems, irange, u, unicode, PY2, nullcontext -from passlib.utils.decor import classproperty -import passlib.utils.handlers as uh -# local -__all__ = [ - # util funcs - 'TEST_MODE', - 'set_file', 'get_file', - - # unit testing - 'TestCase', - 'HandlerCase', -] - -#============================================================================= -# environment detection -#============================================================================= -# figure out if we're running under GAE; -# some tests (e.g. FS writing) should be skipped. -# XXX: is there better way to do this? -try: - import google.appengine -except ImportError: - GAE = False -else: - GAE = True - -def ensure_mtime_changed(path): - """ensure file's mtime has changed""" - # NOTE: this is hack to deal w/ filesystems whose mtime resolution is >= 1s, - # when a test needs to be sure the mtime changed after writing to the file. - last = os.path.getmtime(path) - while os.path.getmtime(path) == last: - time.sleep(0.1) - os.utime(path, None) - -def _get_timer_resolution(timer): - def sample(): - start = cur = timer() - while start == cur: - cur = timer() - return cur-start - return min(sample() for _ in range(3)) -TICK_RESOLUTION = _get_timer_resolution(tick) - -#============================================================================= -# test mode -#============================================================================= -_TEST_MODES = ["quick", "default", "full"] -_test_mode = _TEST_MODES.index(os.environ.get("PASSLIB_TEST_MODE", - "default").strip().lower()) - -def TEST_MODE(min=None, max=None): - """check if test for specified mode should be enabled. - - ``"quick"`` - run the bare minimum tests to ensure functionality. - variable-cost hashes are tested at their lowest setting. - hash algorithms are only tested against the backend that will - be used on the current host. no fuzz testing is done. - - ``"default"`` - same as ``"quick"``, except: hash algorithms are tested - at default levels, and a brief round of fuzz testing is done - for each hash. - - ``"full"`` - extra regression and internal tests are enabled, hash algorithms are tested - against all available backends, unavailable ones are mocked whre possible, - additional time is devoted to fuzz testing. - """ - if min and _test_mode < _TEST_MODES.index(min): - return False - if max and _test_mode > _TEST_MODES.index(max): - return False - return True - -#============================================================================= -# hash object inspection -#============================================================================= -def has_relaxed_setting(handler): - """check if handler supports 'relaxed' kwd""" - # FIXME: I've been lazy, should probably just add 'relaxed' kwd - # to all handlers that derive from GenericHandler - - # ignore wrapper classes for now.. though could introspec. - if hasattr(handler, "orig_prefix"): - return False - - return 'relaxed' in handler.setting_kwds or issubclass(handler, - uh.GenericHandler) - -def get_effective_rounds(handler, rounds=None): - """get effective rounds value from handler""" - handler = unwrap_handler(handler) - return handler(rounds=rounds, use_defaults=True).rounds - -def is_default_backend(handler, backend): - """check if backend is the default for source""" - try: - orig = handler.get_backend() - except MissingBackendError: - return False - try: - handler.set_backend("default") - return handler.get_backend() == backend - finally: - handler.set_backend(orig) - -def iter_alt_backends(handler, current=None, fallback=False): - """ - iterate over alternate backends available to handler. - - .. warning:: - not thread-safe due to has_backend() call - """ - if current is None: - current = handler.get_backend() - backends = handler.backends - idx = backends.index(current)+1 if fallback else 0 - for backend in backends[idx:]: - if backend != current and handler.has_backend(backend): - yield backend - -def get_alt_backend(*args, **kwds): - for backend in iter_alt_backends(*args, **kwds): - return backend - return None - -def unwrap_handler(handler): - """return original handler, removing any wrapper objects""" - while hasattr(handler, "wrapped"): - handler = handler.wrapped - return handler - -def handler_derived_from(handler, base): - """ - test if was derived from via . - """ - # XXX: need way to do this more formally via ifc, - # for now just hacking in the cases we encounter in testing. - if handler == base: - return True - elif isinstance(handler, uh.PrefixWrapper): - while handler: - if handler == base: - return True - # helper set by PrefixWrapper().using() just for this case... - handler = handler._derived_from - return False - elif isinstance(handler, type) and issubclass(handler, uh.MinimalHandler): - return issubclass(handler, base) - else: - raise NotImplementedError("don't know how to inspect handler: %r" % (handler,)) - -@contextlib.contextmanager -def patch_calc_min_rounds(handler): - """ - internal helper for do_config_encrypt() -- - context manager which temporarily replaces handler's _calc_checksum() - with one that uses min_rounds; useful when trying to generate config - with high rounds value, but don't care if output is correct. - """ - if isinstance(handler, type) and issubclass(handler, uh.HasRounds): - # XXX: also require GenericHandler for this branch? - wrapped = handler._calc_checksum - def wrapper(self, *args, **kwds): - rounds = self.rounds - try: - self.rounds = self.min_rounds - return wrapped(self, *args, **kwds) - finally: - self.rounds = rounds - handler._calc_checksum = wrapper - try: - yield - finally: - handler._calc_checksum = wrapped - elif isinstance(handler, uh.PrefixWrapper): - with patch_calc_min_rounds(handler.wrapped): - yield - else: - yield - return - -#============================================================================= -# misc helpers -#============================================================================= -def set_file(path, content): - """set file to specified bytes""" - if isinstance(content, unicode): - content = content.encode("utf-8") - with open(path, "wb") as fh: - fh.write(content) - -def get_file(path): - """read file as bytes""" - with open(path, "rb") as fh: - return fh.read() - -def tonn(source): - """convert native string to non-native string""" - if not isinstance(source, str): - return source - elif PY3: - return source.encode("utf-8") - else: - try: - return source.decode("utf-8") - except UnicodeDecodeError: - return source.decode("latin-1") - -def hb(source): - """ - helper for represent byte strings in hex. - - usage: ``hb("deadbeef23")`` - """ - return unhexlify(re.sub(r"\s", "", source)) - -def limit(value, lower, upper): - if value < lower: - return lower - elif value > upper: - return upper - return value - -def quicksleep(delay): - """because time.sleep() doesn't even have 10ms accuracy on some OSes""" - start = tick() - while tick()-start < delay: - pass - -def time_call(func, setup=None, maxtime=1, bestof=10): - """ - timeit() wrapper which tries to get as accurate a measurement as possible w/in maxtime seconds. - - :returns: - ``(avg_seconds_per_call, log10_number_of_repetitions)`` - """ - from timeit import Timer - from math import log - timer = Timer(func, setup=setup or '') - number = 1 - end = tick() + maxtime - while True: - delta = min(timer.repeat(bestof, number)) - if tick() >= end: - return delta/number, int(log(number, 10)) - number *= 10 - -def run_with_fixed_seeds(count=128, master_seed=0x243F6A8885A308D3): - """ - decorator run test method w/ multiple fixed seeds. - """ - def builder(func): - @wraps(func) - def wrapper(*args, **kwds): - rng = random.Random(master_seed) - for _ in irange(count): - kwds['seed'] = rng.getrandbits(32) - func(*args, **kwds) - return wrapper - return builder - -#============================================================================= -# custom test harness -#============================================================================= - -class TestCase(_TestCase): - """passlib-specific test case class - - this class adds a number of features to the standard TestCase... - * common prefix for all test descriptions - * resets warnings filter & registry for every test - * tweaks to message formatting - * __msg__ kwd added to assertRaises() - * suite of methods for matching against warnings - """ - #=================================================================== - # add various custom features - #=================================================================== - - #--------------------------------------------------------------- - # make it easy for test cases to add common prefix to shortDescription - #--------------------------------------------------------------- - - # string prepended to all tests in TestCase - descriptionPrefix = None - - def shortDescription(self): - """wrap shortDescription() method to prepend descriptionPrefix""" - desc = super(TestCase, self).shortDescription() - prefix = self.descriptionPrefix - if prefix: - desc = "%s: %s" % (prefix, desc or str(self)) - return desc - - #--------------------------------------------------------------- - # hack things so nose and ut2 both skip subclasses who have - # "__unittest_skip=True" set, or whose names start with "_" - #--------------------------------------------------------------- - @classproperty - def __unittest_skip__(cls): - # NOTE: this attr is technically a unittest2 internal detail. - name = cls.__name__ - return name.startswith("_") or \ - getattr(cls, "_%s__unittest_skip" % name, False) - - @classproperty - def __test__(cls): - # make nose just proxy __unittest_skip__ - return not cls.__unittest_skip__ - - # flag to skip *this* class - __unittest_skip = True - - #--------------------------------------------------------------- - # reset warning filters & registry before each test - #--------------------------------------------------------------- - - # flag to reset all warning filters & ignore state - resetWarningState = True - - def setUp(self): - super(TestCase, self).setUp() - self.setUpWarnings() - # have uh.debug_only_repr() return real values for duration of test - self.patchAttr(exc, "ENABLE_DEBUG_ONLY_REPR", True) - - def setUpWarnings(self): - """helper to init warning filters before subclass setUp()""" - if self.resetWarningState: - ctx = reset_warnings() - ctx.__enter__() - self.addCleanup(ctx.__exit__) - - # ignore security warnings, tests may deliberately cause these - # TODO: may want to filter out a few of this, but not blanket filter... - # warnings.filterwarnings("ignore", category=exc.PasslibSecurityWarning) - - # ignore warnings about PasswordHash features deprecated in 1.7 - # TODO: should be cleaned in 2.0, when support will be dropped. - # should be kept until then, so we test the legacy paths. - warnings.filterwarnings("ignore", r"the method .*\.(encrypt|genconfig|genhash)\(\) is deprecated") - warnings.filterwarnings("ignore", r"the 'vary_rounds' option is deprecated") - warnings.filterwarnings("ignore", r"Support for `(py-bcrypt|bcryptor)` is deprecated") - - #--------------------------------------------------------------- - # tweak message formatting so longMessage mode is only enabled - # if msg ends with ":", and turn on longMessage by default. - #--------------------------------------------------------------- - longMessage = True - - def _formatMessage(self, msg, std): - if self.longMessage and msg and msg.rstrip().endswith(":"): - return '%s %s' % (msg.rstrip(), std) - else: - return msg or std - - #--------------------------------------------------------------- - # override assertRaises() to support '__msg__' keyword, - # and to return the caught exception for further examination - #--------------------------------------------------------------- - def assertRaises(self, _exc_type, _callable=None, *args, **kwds): - msg = kwds.pop("__msg__", None) - if _callable is None: - # FIXME: this ignores 'msg' - return super(TestCase, self).assertRaises(_exc_type, None, - *args, **kwds) - try: - result = _callable(*args, **kwds) - except _exc_type as err: - return err - std = "function returned %r, expected it to raise %r" % (result, - _exc_type) - raise self.failureException(self._formatMessage(msg, std)) - - #--------------------------------------------------------------- - # forbid a bunch of deprecated aliases so I stop using them - #--------------------------------------------------------------- - def assertEquals(self, *a, **k): - raise AssertionError("this alias is deprecated by unittest2") - assertNotEquals = assertRegexMatches = assertEquals - - #=================================================================== - # custom methods for matching warnings - #=================================================================== - def assertWarning(self, warning, - message_re=None, message=None, - category=None, - filename_re=None, filename=None, - lineno=None, - msg=None, - ): - """check if warning matches specified parameters. - 'warning' is the instance of Warning to match against; - can also be instance of WarningMessage (as returned by catch_warnings). - """ - # check input type - if hasattr(warning, "category"): - # resolve WarningMessage -> Warning, but preserve original - wmsg = warning - warning = warning.message - else: - # no original WarningMessage, passed raw Warning - wmsg = None - - # tests that can use a warning instance or WarningMessage object - if message: - self.assertEqual(str(warning), message, msg) - if message_re: - self.assertRegex(str(warning), message_re, msg) - if category: - self.assertIsInstance(warning, category, msg) - - # tests that require a WarningMessage object - if filename or filename_re: - if not wmsg: - raise TypeError("matching on filename requires a " - "WarningMessage instance") - real = wmsg.filename - if real.endswith(".pyc") or real.endswith(".pyo"): - # FIXME: should use a stdlib call to resolve this back - # to module's original filename. - real = real[:-1] - if filename: - self.assertEqual(real, filename, msg) - if filename_re: - self.assertRegex(real, filename_re, msg) - if lineno: - if not wmsg: - raise TypeError("matching on lineno requires a " - "WarningMessage instance") - self.assertEqual(wmsg.lineno, lineno, msg) - - class _AssertWarningList(warnings.catch_warnings): - """context manager for assertWarningList()""" - def __init__(self, case, **kwds): - self.case = case - self.kwds = kwds - self.__super = super(TestCase._AssertWarningList, self) - self.__super.__init__(record=True) - - def __enter__(self): - self.log = self.__super.__enter__() - - def __exit__(self, *exc_info): - self.__super.__exit__(*exc_info) - if exc_info[0] is None: - self.case.assertWarningList(self.log, **self.kwds) - - def assertWarningList(self, wlist=None, desc=None, msg=None): - """check that warning list (e.g. from catch_warnings) matches pattern""" - if desc is None: - assert wlist is not None - return self._AssertWarningList(self, desc=wlist, msg=msg) - # TODO: make this display better diff of *which* warnings did not match - assert desc is not None - if not isinstance(desc, (list,tuple)): - desc = [desc] - for idx, entry in enumerate(desc): - if isinstance(entry, str): - entry = dict(message_re=entry) - elif isinstance(entry, type) and issubclass(entry, Warning): - entry = dict(category=entry) - elif not isinstance(entry, dict): - raise TypeError("entry must be str, warning, or dict") - try: - data = wlist[idx] - except IndexError: - break - self.assertWarning(data, msg=msg, **entry) - else: - if len(wlist) == len(desc): - return - std = "expected %d warnings, found %d: wlist=%s desc=%r" % \ - (len(desc), len(wlist), self._formatWarningList(wlist), desc) - raise self.failureException(self._formatMessage(msg, std)) - - def consumeWarningList(self, wlist, desc=None, *args, **kwds): - """[deprecated] assertWarningList() variant that clears list afterwards""" - if desc is None: - desc = [] - self.assertWarningList(wlist, desc, *args, **kwds) - del wlist[:] - - def _formatWarning(self, entry): - tail = "" - if hasattr(entry, "message"): - # WarningMessage instance. - tail = " filename=%r lineno=%r" % (entry.filename, entry.lineno) - if entry.line: - tail += " line=%r" % (entry.line,) - entry = entry.message - cls = type(entry) - return "<%s.%s message=%r%s>" % (cls.__module__, cls.__name__, - str(entry), tail) - - def _formatWarningList(self, wlist): - return "[%s]" % ", ".join(self._formatWarning(entry) for entry in wlist) - - #=================================================================== - # capability tests - #=================================================================== - def require_stringprep(self): - """helper to skip test if stringprep is missing""" - from passlib.utils import stringprep - if not stringprep: - from passlib.utils import _stringprep_missing_reason - raise self.skipTest("not available - stringprep module is " + - _stringprep_missing_reason) - - def require_TEST_MODE(self, level): - """skip test for all PASSLIB_TEST_MODE values below """ - if not TEST_MODE(level): - raise self.skipTest("requires >= %r test mode" % level) - - def require_writeable_filesystem(self): - """skip test if writeable FS not available""" - if GAE: - return self.skipTest("GAE doesn't offer read/write filesystem access") - - #=================================================================== - # reproducible random helpers - #=================================================================== - - #: global thread lock for random state - #: XXX: could split into global & per-instance locks if need be - _random_global_lock = threading.Lock() - - #: cache of global seed value, initialized on first call to getRandom() - _random_global_seed = None - - #: per-instance cache of name -> RNG - _random_cache = None - - def getRandom(self, name="default", seed=None): - """ - Return a :class:`random.Random` object for current test method to use. - Within an instance, multiple calls with the same name will return - the same object. - - When first created, each RNG will be seeded with value derived from - a global seed, the test class module & name, the current test method name, - and the **name** parameter. - - The global seed taken from the $RANDOM_TEST_SEED env var, - the $PYTHONHASHSEED env var, or a randomly generated the - first time this method is called. In all cases, the value - is logged for reproducibility. - - :param name: - name to uniquely identify separate RNGs w/in a test - (e.g. for threaded tests). - - :param seed: - override global seed when initialzing rng. - - :rtype: random.Random - """ - # check cache - cache = self._random_cache - if cache and name in cache: - return cache[name] - - with self._random_global_lock: - - # check cache again, and initialize it - cache = self._random_cache - if cache and name in cache: - return cache[name] - elif not cache: - cache = self._random_cache = {} - - # init global seed - global_seed = seed or TestCase._random_global_seed - if global_seed is None: - # NOTE: checking PYTHONHASHSEED, because if that's set, - # the test runner wants something reproducible. - global_seed = TestCase._random_global_seed = \ - int(os.environ.get("RANDOM_TEST_SEED") or - os.environ.get("PYTHONHASHSEED") or - sys_rng.getrandbits(32)) - # XXX: would it be better to print() this? - log.info("using RANDOM_TEST_SEED=%d", global_seed) - - # create seed - cls = type(self) - source = "\n".join([str(global_seed), cls.__module__, cls.__name__, - self._testMethodName, name]) - digest = hashlib.sha256(source.encode("utf-8")).hexdigest() - seed = int(digest[:16], 16) - - # create rng - value = cache[name] = random.Random(seed) - return value - - #=================================================================== - # subtests - #=================================================================== - - has_real_subtest = hasattr(_TestCase, "subTest") - - @contextlib.contextmanager - def subTest(self, *args, **kwds): - """ - wrapper/backport for .subTest() which also traps SkipTest errors. - (see source for details) - """ - # this function works around two things: - # * TestCase.subTest() wasn't added until Py34; so for older python versions, - # we either need unittest2 installed, or provide stub of our own. - # this method provides a stub if needed (based on .has_real_subtest check) - # - # * as 2020-10-08, .subTest() doesn't play nicely w/ .skipTest(); - # and also makes it hard to debug which subtest had a failure. - # (see https://bugs.python.org/issue25894 and https://bugs.python.org/issue35327) - # this method traps skipTest exceptions, and adds some logging to help debug - # which subtest caused the issue. - - # setup way to log subtest info - # XXX: would like better way to inject messages into test output; - # but this at least gets us something for debugging... - # NOTE: this hack will miss parent params if called from nested .subTest() - def _render_title(_msg=None, **params): - out = ("[%s] " % _msg if _msg else "") - if params: - out += "(%s)" % " ".join("%s=%r" % tuple(item) for item in params.items()) - return out.strip() or "" - - test_log = self.getLogger() - title = _render_title(*args, **kwds) - - # use real subtest manager if available - if self.has_real_subtest: - ctx = super(TestCase, self).subTest(*args, **kwds) - else: - ctx = nullcontext() - - # run the subtest - with ctx: - test_log.info("running subtest: %s", title) - try: - yield - except SkipTest: - # silence "SkipTest" exceptions, want to keep running next subtest. - test_log.info("subtest skipped: %s", title) - pass - except Exception as err: - # log unhandled exception occurred - # (assuming traceback will be reported up higher, so not bothering here) - test_log.warning("subtest failed: %s: %s: %r", title, type(err).__name__, str(err)) - raise - - # XXX: check for "failed" state in ``self._outcome`` before writing this? - test_log.info("subtest passed: %s", title) - - #=================================================================== - # other - #=================================================================== - _mktemp_queue = None - - def mktemp(self, *args, **kwds): - """create temp file that's cleaned up at end of test""" - self.require_writeable_filesystem() - fd, path = tempfile.mkstemp(*args, **kwds) - os.close(fd) - queue = self._mktemp_queue - if queue is None: - queue = self._mktemp_queue = [] - def cleaner(): - for path in queue: - if os.path.exists(path): - os.remove(path) - del queue[:] - self.addCleanup(cleaner) - queue.append(path) - return path - - def patchAttr(self, obj, attr, value, require_existing=True, wrap=False): - """monkeypatch object value, restoring original value on cleanup""" - try: - orig = getattr(obj, attr) - except AttributeError: - if require_existing: - raise - def cleanup(): - try: - delattr(obj, attr) - except AttributeError: - pass - self.addCleanup(cleanup) - else: - self.addCleanup(setattr, obj, attr, orig) - if wrap: - value = partial(value, orig) - wraps(orig)(value) - setattr(obj, attr, value) - - def getLogger(self): - """ - return logger named after current test. - """ - cls = type(self) - # NOTE: conditional on qualname for PY2 compat - path = cls.__module__ + "." + getattr(cls, "__qualname__", cls.__name__) - name = self._testMethodName - if name: - path = path + "." + name - return logging.getLogger(path) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# other unittest helpers -#============================================================================= - -RESERVED_BACKEND_NAMES = ["any", "default"] - - -def doesnt_require_backend(func): - """ - decorator for HandlerCase.create_backend_case() -- - used to decorate methods that should be run even if backend isn't present - (by default, full test suite is skipped when backend is missing) - - NOTE: tests decorated with this should not rely on handler have expected (or any!) backend. - """ - func._doesnt_require_backend = True - return func - - -class HandlerCase(TestCase): - """base class for testing password hash handlers (esp passlib.utils.handlers subclasses) - - In order to use this to test a handler, - create a subclass will all the appropriate attributes - filled as listed in the example below, - and run the subclass via unittest. - - .. todo:: - - Document all of the options HandlerCase offers. - - .. note:: - - This is subclass of :class:`unittest.TestCase` - (or :class:`unittest2.TestCase` if available). - """ - #=================================================================== - # class attrs - should be filled in by subclass - #=================================================================== - - #--------------------------------------------------------------- - # handler setup - #--------------------------------------------------------------- - - # handler class to test [required] - handler = None - - # if set, run tests against specified backend - backend = None - - #--------------------------------------------------------------- - # test vectors - #--------------------------------------------------------------- - - # list of (secret, hash) tuples which are known to be correct - known_correct_hashes = [] - - # list of (config, secret, hash) tuples are known to be correct - known_correct_configs = [] - - # list of (alt_hash, secret, hash) tuples, where alt_hash is a hash - # using an alternate representation that should be recognized and verify - # correctly, but should be corrected to match hash when passed through - # genhash() - known_alternate_hashes = [] - - # hashes so malformed they aren't even identified properly - known_unidentified_hashes = [] - - # hashes which are identifiabled but malformed - they should identify() - # as True, but cause an error when passed to genhash/verify. - known_malformed_hashes = [] - - # list of (handler name, hash) pairs for other algorithm's hashes that - # handler shouldn't identify as belonging to it this list should generally - # be sufficient (if handler name in list, that entry will be skipped) - known_other_hashes = [ - ('des_crypt', '6f8c114b58f2c'), - ('md5_crypt', '$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.'), - ('sha512_crypt', "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywW" - "vt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1"), - ] - - # passwords used to test basic hash behavior - generally - # don't need to be overidden. - stock_passwords = [ - u("test"), - u("\u20AC\u00A5$"), - b'\xe2\x82\xac\xc2\xa5$' - ] - - #--------------------------------------------------------------- - # option flags - #--------------------------------------------------------------- - - # whether hash is case insensitive - # True, False, or special value "verify-only" (which indicates - # hash contains case-sensitive portion, but verifies is case-insensitive) - secret_case_insensitive = False - - # flag if scheme accepts ALL hash strings (e.g. plaintext) - accepts_all_hashes = False - - # flag if scheme has "is_disabled" set, and contains 'salted' data - disabled_contains_salt = False - - # flag/hack to filter PasslibHashWarning issued by test_72_configs() - filter_config_warnings = False - - # forbid certain characters in passwords - @classproperty - def forbidden_characters(cls): - # anything that supports crypt() interface should forbid null chars, - # since crypt() uses null-terminated strings. - if 'os_crypt' in getattr(cls.handler, "backends", ()): - return b"\x00" - return None - - #=================================================================== - # internal class attrs - #=================================================================== - __unittest_skip = True - - @property - def descriptionPrefix(self): - handler = self.handler - name = handler.name - if hasattr(handler, "get_backend"): - name += " (%s backend)" % (handler.get_backend(),) - return name - - #=================================================================== - # support methods - #=================================================================== - - #--------------------------------------------------------------- - # configuration helpers - #--------------------------------------------------------------- - @classmethod - def iter_known_hashes(cls): - """iterate through known (secret, hash) pairs""" - for secret, hash in cls.known_correct_hashes: - yield secret, hash - for config, secret, hash in cls.known_correct_configs: - yield secret, hash - for alt, secret, hash in cls.known_alternate_hashes: - yield secret, hash - - def get_sample_hash(self): - """test random sample secret/hash pair""" - known = list(self.iter_known_hashes()) - return self.getRandom().choice(known) - - #--------------------------------------------------------------- - # test helpers - #--------------------------------------------------------------- - def check_verify(self, secret, hash, msg=None, negate=False): - """helper to check verify() outcome, honoring is_disabled_handler""" - result = self.do_verify(secret, hash) - self.assertTrue(result is True or result is False, - "verify() returned non-boolean value: %r" % (result,)) - if self.handler.is_disabled or negate: - if not result: - return - if not msg: - msg = ("verify incorrectly returned True: secret=%r, hash=%r" % - (secret, hash)) - raise self.failureException(msg) - else: - if result: - return - if not msg: - msg = "verify failed: secret=%r, hash=%r" % (secret, hash) - raise self.failureException(msg) - - def check_returned_native_str(self, result, func_name): - self.assertIsInstance(result, str, - "%s() failed to return native string: %r" % (func_name, result,)) - - #--------------------------------------------------------------- - # PasswordHash helpers - wraps all calls to PasswordHash api, - # so that subclasses can fill in defaults and account for other specialized behavior - #--------------------------------------------------------------- - def populate_settings(self, kwds): - """subclassable method to populate default settings""" - # use lower rounds settings for certain test modes - handler = self.handler - if 'rounds' in handler.setting_kwds and 'rounds' not in kwds: - mn = handler.min_rounds - df = handler.default_rounds - if TEST_MODE(max="quick"): - # use minimum rounds for quick mode - kwds['rounds'] = max(3, mn) - else: - # use default/16 otherwise - factor = 3 - if getattr(handler, "rounds_cost", None) == "log2": - df -= factor - else: - df //= (1<= 1") - - # check min_salt_size - if cls.min_salt_size < 0: - raise AssertionError("min_salt_chars must be >= 0") - if mx_set and cls.min_salt_size > cls.max_salt_size: - raise AssertionError("min_salt_chars must be <= max_salt_chars") - - # check default_salt_size - if cls.default_salt_size < cls.min_salt_size: - raise AssertionError("default_salt_size must be >= min_salt_size") - if mx_set and cls.default_salt_size > cls.max_salt_size: - raise AssertionError("default_salt_size must be <= max_salt_size") - - # check for 'salt_size' keyword - # NOTE: skipping warning if default salt size is already maxed out - # (might change that in future) - if 'salt_size' not in cls.setting_kwds and (not mx_set or cls.default_salt_size < cls.max_salt_size): - warn('%s: hash handler supports range of salt sizes, ' - 'but doesn\'t offer \'salt_size\' setting' % (cls.name,)) - - # check salt_chars & default_salt_chars - if cls.salt_chars: - if not cls.default_salt_chars: - raise AssertionError("default_salt_chars must not be empty") - for c in cls.default_salt_chars: - if c not in cls.salt_chars: - raise AssertionError("default_salt_chars must be subset of salt_chars: %r not in salt_chars" % (c,)) - else: - if not cls.default_salt_chars: - raise AssertionError("default_salt_chars MUST be specified if salt_chars is empty") - - @property - def salt_bits(self): - """calculate number of salt bits in hash""" - # XXX: replace this with bitsize() method? - handler = self.handler - assert has_salt_info(handler), "need explicit bit-size for " + handler.name - from math import log - # FIXME: this may be off for case-insensitive hashes, but that accounts - # for ~1 bit difference, which is good enough for test_11() - return int(handler.default_salt_size * - log(len(handler.default_salt_chars), 2)) - - def test_11_unique_salt(self): - """test hash() / genconfig() creates new salt each time""" - self.require_salt() - # odds of picking 'n' identical salts at random is '(.5**salt_bits)**n'. - # we want to pick the smallest N needed s.t. odds are <1/10**d, just - # to eliminate false-positives. which works out to n>3.33+d-salt_bits. - # for 1/1e12 odds, n=1 is sufficient for most hashes, but a few border cases (e.g. - # cisco_type7) have < 16 bits of salt, requiring more. - samples = max(1, 4 + 12 - self.salt_bits) - - def sampler(func): - value1 = func() - for _ in irange(samples): - value2 = func() - if value1 != value2: - return - raise self.failureException("failed to find different salt after " - "%d samples" % (samples,)) - sampler(self.do_genconfig) - sampler(lambda: self.do_encrypt("stub")) - - def test_12_min_salt_size(self): - """test hash() / genconfig() honors min_salt_size""" - self.require_salt_info() - - handler = self.handler - salt_char = handler.salt_chars[0:1] - min_size = handler.min_salt_size - - # - # check min is accepted - # - s1 = salt_char * min_size - self.do_genconfig(salt=s1) - - self.do_encrypt('stub', salt_size=min_size) - - # - # check min-1 is rejected - # - if min_size > 0: - self.assertRaises(ValueError, self.do_genconfig, - salt=s1[:-1]) - - self.assertRaises(ValueError, self.do_encrypt, 'stub', - salt_size=min_size-1) - - def test_13_max_salt_size(self): - """test hash() / genconfig() honors max_salt_size""" - self.require_salt_info() - - handler = self.handler - max_size = handler.max_salt_size - salt_char = handler.salt_chars[0:1] - - # NOTE: skipping this for hashes like argon2 since max_salt_size takes WAY too much memory - if max_size is None or max_size > (1 << 20): - # - # if it's not set, salt should never be truncated; so test it - # with an unreasonably large salt. - # - s1 = salt_char * 1024 - c1 = self.do_stub_encrypt(salt=s1) - c2 = self.do_stub_encrypt(salt=s1 + salt_char) - self.assertNotEqual(c1, c2) - - self.do_stub_encrypt(salt_size=1024) - - else: - # - # check max size is accepted - # - s1 = salt_char * max_size - c1 = self.do_stub_encrypt(salt=s1) - - self.do_stub_encrypt(salt_size=max_size) - - # - # check max size + 1 is rejected - # - s2 = s1 + salt_char - self.assertRaises(ValueError, self.do_stub_encrypt, salt=s2) - - self.assertRaises(ValueError, self.do_stub_encrypt, salt_size=max_size + 1) - - # - # should accept too-large salt in relaxed mode - # - if has_relaxed_setting(handler): - with warnings.catch_warnings(record=True): # issues passlibhandlerwarning - c2 = self.do_stub_encrypt(salt=s2, relaxed=True) - self.assertEqual(c2, c1) - - # - # if min_salt supports it, check smaller than mx is NOT truncated - # - if handler.min_salt_size < max_size: - c3 = self.do_stub_encrypt(salt=s1[:-1]) - self.assertNotEqual(c3, c1) - - # whether salt should be passed through bcrypt repair function - fuzz_salts_need_bcrypt_repair = False - - def prepare_salt(self, salt): - """prepare generated salt""" - if self.fuzz_salts_need_bcrypt_repair: - from passlib.utils.binary import bcrypt64 - salt = bcrypt64.repair_unused(salt) - return salt - - def test_14_salt_chars(self): - """test hash() honors salt_chars""" - self.require_salt_info() - - handler = self.handler - mx = handler.max_salt_size - mn = handler.min_salt_size - cs = handler.salt_chars - raw = isinstance(cs, bytes) - - # make sure all listed chars are accepted - for salt in batch(cs, mx or 32): - if len(salt) < mn: - salt = repeat_string(salt, mn) - salt = self.prepare_salt(salt) - self.do_stub_encrypt(salt=salt) - - # check some invalid salt chars, make sure they're rejected - source = u('\x00\xff') - if raw: - source = source.encode("latin-1") - chunk = max(mn, 1) - for c in source: - if c not in cs: - self.assertRaises(ValueError, self.do_stub_encrypt, salt=c*chunk, - __msg__="invalid salt char %r:" % (c,)) - - @property - def salt_type(self): - """hack to determine salt keyword's datatype""" - # NOTE: cisco_type7 uses 'int' - if getattr(self.handler, "_salt_is_bytes", False): - return bytes - else: - return unicode - - def test_15_salt_type(self): - """test non-string salt values""" - self.require_salt() - salt_type = self.salt_type - salt_size = getattr(self.handler, "min_salt_size", 0) or 8 - - # should always throw error for random class. - class fake(object): - pass - self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=fake()) - - # unicode should be accepted only if salt_type is unicode. - if salt_type is not unicode: - self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=u('x') * salt_size) - - # bytes should be accepted only if salt_type is bytes, - # OR if salt type is unicode and running PY2 - to allow native strings. - if not (salt_type is bytes or (PY2 and salt_type is unicode)): - self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=b'x' * salt_size) - - def test_using_salt_size(self): - """Handler.using() -- default_salt_size""" - self.require_salt_info() - - handler = self.handler - mn = handler.min_salt_size - mx = handler.max_salt_size - df = handler.default_salt_size - - # should prevent setting below handler limit - self.assertRaises(ValueError, handler.using, default_salt_size=-1) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(default_salt_size=-1, relaxed=True) - self.assertEqual(temp.default_salt_size, mn) - - # should prevent setting above handler limit - if mx: - self.assertRaises(ValueError, handler.using, default_salt_size=mx+1) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(default_salt_size=mx+1, relaxed=True) - self.assertEqual(temp.default_salt_size, mx) - - # try setting to explicit value - if mn != mx: - temp = handler.using(default_salt_size=mn+1) - self.assertEqual(temp.default_salt_size, mn+1) - self.assertEqual(handler.default_salt_size, df) - - temp = handler.using(default_salt_size=mn+2) - self.assertEqual(temp.default_salt_size, mn+2) - self.assertEqual(handler.default_salt_size, df) - - # accept strings - if mn == mx: - ref = mn - else: - ref = mn + 1 - temp = handler.using(default_salt_size=str(ref)) - self.assertEqual(temp.default_salt_size, ref) - - # reject invalid strings - self.assertRaises(ValueError, handler.using, default_salt_size=str(ref) + "xxx") - - # honor 'salt_size' alias - temp = handler.using(salt_size=ref) - self.assertEqual(temp.default_salt_size, ref) - - #=================================================================== - # rounds - #=================================================================== - def require_rounds_info(self): - if not has_rounds_info(self.handler): - raise self.skipTest("handler lacks rounds attributes") - - def test_20_optional_rounds_attributes(self): - """validate optional rounds attributes""" - self.require_rounds_info() - - cls = self.handler - AssertionError = self.failureException - - # check max_rounds - if cls.max_rounds is None: - raise AssertionError("max_rounds not specified") - if cls.max_rounds < 1: - raise AssertionError("max_rounds must be >= 1") - - # check min_rounds - if cls.min_rounds < 0: - raise AssertionError("min_rounds must be >= 0") - if cls.min_rounds > cls.max_rounds: - raise AssertionError("min_rounds must be <= max_rounds") - - # check default_rounds - if cls.default_rounds is not None: - if cls.default_rounds < cls.min_rounds: - raise AssertionError("default_rounds must be >= min_rounds") - if cls.default_rounds > cls.max_rounds: - raise AssertionError("default_rounds must be <= max_rounds") - - # check rounds_cost - if cls.rounds_cost not in rounds_cost_values: - raise AssertionError("unknown rounds cost constant: %r" % (cls.rounds_cost,)) - - def test_21_min_rounds(self): - """test hash() / genconfig() honors min_rounds""" - self.require_rounds_info() - handler = self.handler - min_rounds = handler.min_rounds - - # check min is accepted - self.do_genconfig(rounds=min_rounds) - self.do_encrypt('stub', rounds=min_rounds) - - # check min-1 is rejected - self.assertRaises(ValueError, self.do_genconfig, rounds=min_rounds-1) - self.assertRaises(ValueError, self.do_encrypt, 'stub', rounds=min_rounds-1) - - # TODO: check relaxed mode clips min-1 - - def test_21b_max_rounds(self): - """test hash() / genconfig() honors max_rounds""" - self.require_rounds_info() - handler = self.handler - max_rounds = handler.max_rounds - - if max_rounds is not None: - # check max+1 is rejected - self.assertRaises(ValueError, self.do_genconfig, rounds=max_rounds+1) - self.assertRaises(ValueError, self.do_encrypt, 'stub', rounds=max_rounds+1) - - # handle max rounds - if max_rounds is None: - self.do_stub_encrypt(rounds=(1 << 31) - 1) - else: - self.do_stub_encrypt(rounds=max_rounds) - - # TODO: check relaxed mode clips max+1 - - #-------------------------------------------------------------------------------------- - # HasRounds.using() / .needs_update() -- desired rounds limits - #-------------------------------------------------------------------------------------- - def _create_using_rounds_helper(self): - """ - setup test helpers for testing handler.using()'s rounds parameters. - """ - self.require_rounds_info() - handler = self.handler - - if handler.name == "bsdi_crypt": - # hack to bypass bsdi-crypt's "odd rounds only" behavior, messes up this test - orig_handler = handler - handler = handler.using() - handler._generate_rounds = classmethod(lambda cls: super(orig_handler, cls)._generate_rounds()) - - # create some fake values to test with - orig_min_rounds = handler.min_rounds - orig_max_rounds = handler.max_rounds - orig_default_rounds = handler.default_rounds - medium = ((orig_max_rounds or 9999) + orig_min_rounds) // 2 - if medium == orig_default_rounds: - medium += 1 - small = (orig_min_rounds + medium) // 2 - large = ((orig_max_rounds or 9999) + medium) // 2 - - if handler.name == "bsdi_crypt": - # hack to avoid even numbered rounds - small |= 1 - medium |= 1 - large |= 1 - adj = 2 - else: - adj = 1 - - # create a subclass with small/medium/large as new default desired values - with self.assertWarningList([]): - subcls = handler.using( - min_desired_rounds=small, - max_desired_rounds=large, - default_rounds=medium, - ) - - # return helpers - return handler, subcls, small, medium, large, adj - - def test_has_rounds_using_harness(self): - """ - HasRounds.using() -- sanity check test harness - """ - # setup helpers - self.require_rounds_info() - handler = self.handler - orig_min_rounds = handler.min_rounds - orig_max_rounds = handler.max_rounds - orig_default_rounds = handler.default_rounds - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - - # shouldn't affect original handler at all - self.assertEqual(handler.min_rounds, orig_min_rounds) - self.assertEqual(handler.max_rounds, orig_max_rounds) - self.assertEqual(handler.min_desired_rounds, None) - self.assertEqual(handler.max_desired_rounds, None) - self.assertEqual(handler.default_rounds, orig_default_rounds) - - # should affect subcls' desired value, but not hard min/max - self.assertEqual(subcls.min_rounds, orig_min_rounds) - self.assertEqual(subcls.max_rounds, orig_max_rounds) - self.assertEqual(subcls.default_rounds, medium) - self.assertEqual(subcls.min_desired_rounds, small) - self.assertEqual(subcls.max_desired_rounds, large) - - def test_has_rounds_using_w_min_rounds(self): - """ - HasRounds.using() -- min_rounds / min_desired_rounds - """ - # setup helpers - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - orig_min_rounds = handler.min_rounds - orig_max_rounds = handler.max_rounds - orig_default_rounds = handler.default_rounds - - # .using() should clip values below valid minimum, w/ warning - if orig_min_rounds > 0: - self.assertRaises(ValueError, handler.using, min_desired_rounds=orig_min_rounds - adj) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(min_desired_rounds=orig_min_rounds - adj, relaxed=True) - self.assertEqual(temp.min_desired_rounds, orig_min_rounds) - - # .using() should clip values above valid maximum, w/ warning - if orig_max_rounds: - self.assertRaises(ValueError, handler.using, min_desired_rounds=orig_max_rounds + adj) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(min_desired_rounds=orig_max_rounds + adj, relaxed=True) - self.assertEqual(temp.min_desired_rounds, orig_max_rounds) - - # .using() should allow values below previous desired minimum, w/o warning - with self.assertWarningList([]): - temp = subcls.using(min_desired_rounds=small - adj) - self.assertEqual(temp.min_desired_rounds, small - adj) - - # .using() should allow values w/in previous range - temp = subcls.using(min_desired_rounds=small + 2 * adj) - self.assertEqual(temp.min_desired_rounds, small + 2 * adj) - - # .using() should allow values above previous desired maximum, w/o warning - with self.assertWarningList([]): - temp = subcls.using(min_desired_rounds=large + adj) - self.assertEqual(temp.min_desired_rounds, large + adj) - - # hash() etc should allow explicit values below desired minimum - # NOTE: formerly issued a warning in passlib 1.6, now just a wrapper for .using() - self.assertEqual(get_effective_rounds(subcls, small + adj), small + adj) - self.assertEqual(get_effective_rounds(subcls, small), small) - with self.assertWarningList([]): - self.assertEqual(get_effective_rounds(subcls, small - adj), small - adj) - - # 'min_rounds' should be treated as alias for 'min_desired_rounds' - temp = handler.using(min_rounds=small) - self.assertEqual(temp.min_desired_rounds, small) - - # should be able to specify strings - temp = handler.using(min_rounds=str(small)) - self.assertEqual(temp.min_desired_rounds, small) - - # invalid strings should cause error - self.assertRaises(ValueError, handler.using, min_rounds=str(small) + "xxx") - - def test_has_rounds_replace_w_max_rounds(self): - """ - HasRounds.using() -- max_rounds / max_desired_rounds - """ - # setup helpers - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - orig_min_rounds = handler.min_rounds - orig_max_rounds = handler.max_rounds - - # .using() should clip values below valid minimum w/ warning - if orig_min_rounds > 0: - self.assertRaises(ValueError, handler.using, max_desired_rounds=orig_min_rounds - adj) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(max_desired_rounds=orig_min_rounds - adj, relaxed=True) - self.assertEqual(temp.max_desired_rounds, orig_min_rounds) - - # .using() should clip values above valid maximum, w/ warning - if orig_max_rounds: - self.assertRaises(ValueError, handler.using, max_desired_rounds=orig_max_rounds + adj) - with self.assertWarningList([PasslibHashWarning]): - temp = handler.using(max_desired_rounds=orig_max_rounds + adj, relaxed=True) - self.assertEqual(temp.max_desired_rounds, orig_max_rounds) - - # .using() should clip values below previous minimum, w/ warning - with self.assertWarningList([PasslibConfigWarning]): - temp = subcls.using(max_desired_rounds=small - adj) - self.assertEqual(temp.max_desired_rounds, small) - - # .using() should reject explicit min > max - self.assertRaises(ValueError, subcls.using, - min_desired_rounds=medium+adj, - max_desired_rounds=medium-adj) - - # .using() should allow values w/in previous range - temp = subcls.using(min_desired_rounds=large - 2 * adj) - self.assertEqual(temp.min_desired_rounds, large - 2 * adj) - - # .using() should allow values above previous desired maximum, w/o warning - with self.assertWarningList([]): - temp = subcls.using(max_desired_rounds=large + adj) - self.assertEqual(temp.max_desired_rounds, large + adj) - - # hash() etc should allow explicit values above desired minimum, w/o warning - # NOTE: formerly issued a warning in passlib 1.6, now just a wrapper for .using() - self.assertEqual(get_effective_rounds(subcls, large - adj), large - adj) - self.assertEqual(get_effective_rounds(subcls, large), large) - with self.assertWarningList([]): - self.assertEqual(get_effective_rounds(subcls, large + adj), large + adj) - - # 'max_rounds' should be treated as alias for 'max_desired_rounds' - temp = handler.using(max_rounds=large) - self.assertEqual(temp.max_desired_rounds, large) - - # should be able to specify strings - temp = handler.using(max_desired_rounds=str(large)) - self.assertEqual(temp.max_desired_rounds, large) - - # invalid strings should cause error - self.assertRaises(ValueError, handler.using, max_desired_rounds=str(large) + "xxx") - - def test_has_rounds_using_w_default_rounds(self): - """ - HasRounds.using() -- default_rounds - """ - # setup helpers - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - orig_max_rounds = handler.max_rounds - - # XXX: are there any other cases that need testing? - - # implicit default rounds -- increase to min_rounds - temp = subcls.using(min_rounds=medium+adj) - self.assertEqual(temp.default_rounds, medium+adj) - - # implicit default rounds -- decrease to max_rounds - temp = subcls.using(max_rounds=medium-adj) - self.assertEqual(temp.default_rounds, medium-adj) - - # explicit default rounds below desired minimum - # XXX: make this a warning if min is implicit? - self.assertRaises(ValueError, subcls.using, default_rounds=small-adj) - - # explicit default rounds above desired maximum - # XXX: make this a warning if max is implicit? - if orig_max_rounds: - self.assertRaises(ValueError, subcls.using, default_rounds=large+adj) - - # hash() etc should implicit default rounds, but get overridden - self.assertEqual(get_effective_rounds(subcls), medium) - self.assertEqual(get_effective_rounds(subcls, medium+adj), medium+adj) - - # should be able to specify strings - temp = handler.using(default_rounds=str(medium)) - self.assertEqual(temp.default_rounds, medium) - - # invalid strings should cause error - self.assertRaises(ValueError, handler.using, default_rounds=str(medium) + "xxx") - - def test_has_rounds_using_w_rounds(self): - """ - HasRounds.using() -- rounds - """ - # setup helpers - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - orig_max_rounds = handler.max_rounds - - # 'rounds' should be treated as fallback for min, max, and default - temp = subcls.using(rounds=medium+adj) - self.assertEqual(temp.min_desired_rounds, medium+adj) - self.assertEqual(temp.default_rounds, medium+adj) - self.assertEqual(temp.max_desired_rounds, medium+adj) - - # 'rounds' should be treated as fallback for min, max, and default - temp = subcls.using(rounds=medium+1, min_rounds=small+adj, - default_rounds=medium, max_rounds=large-adj) - self.assertEqual(temp.min_desired_rounds, small+adj) - self.assertEqual(temp.default_rounds, medium) - self.assertEqual(temp.max_desired_rounds, large-adj) - - def test_has_rounds_using_w_vary_rounds_parsing(self): - """ - HasRounds.using() -- vary_rounds parsing - """ - # setup helpers - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - - def parse(value): - return subcls.using(vary_rounds=value).vary_rounds - - # floats should be preserved - self.assertEqual(parse(0.1), 0.1) - self.assertEqual(parse('0.1'), 0.1) - - # 'xx%' should be converted to float - self.assertEqual(parse('10%'), 0.1) - - # ints should be preserved - self.assertEqual(parse(1000), 1000) - self.assertEqual(parse('1000'), 1000) - - # float bounds should be enforced - self.assertRaises(ValueError, parse, -0.1) - self.assertRaises(ValueError, parse, 1.1) - - def test_has_rounds_using_w_vary_rounds_generation(self): - """ - HasRounds.using() -- vary_rounds generation - """ - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - - def get_effective_range(cls): - seen = set(get_effective_rounds(cls) for _ in irange(1000)) - return min(seen), max(seen) - - def assert_rounds_range(vary_rounds, lower, upper): - temp = subcls.using(vary_rounds=vary_rounds) - seen_lower, seen_upper = get_effective_range(temp) - self.assertEqual(seen_lower, lower, "vary_rounds had wrong lower limit:") - self.assertEqual(seen_upper, upper, "vary_rounds had wrong upper limit:") - - # test static - assert_rounds_range(0, medium, medium) - assert_rounds_range("0%", medium, medium) - - # test absolute - assert_rounds_range(adj, medium - adj, medium + adj) - assert_rounds_range(50, max(small, medium - 50), min(large, medium + 50)) - - # test relative - should shift over at 50% mark - if handler.rounds_cost == "log2": - # log rounds "50%" variance should only increase/decrease by 1 cost value - assert_rounds_range("1%", medium, medium) - assert_rounds_range("49%", medium, medium) - assert_rounds_range("50%", medium - adj, medium) - else: - # for linear rounds, range is frequently so huge, won't ever see ends. - # so we just check it's within an expected range. - lower, upper = get_effective_range(subcls.using(vary_rounds="50%")) - - self.assertGreaterEqual(lower, max(small, medium * 0.5)) - self.assertLessEqual(lower, max(small, medium * 0.8)) - - self.assertGreaterEqual(upper, min(large, medium * 1.2)) - self.assertLessEqual(upper, min(large, medium * 1.5)) - - def test_has_rounds_using_and_needs_update(self): - """ - HasRounds.using() -- desired_rounds + needs_update() - """ - handler, subcls, small, medium, large, adj = self._create_using_rounds_helper() - - temp = subcls.using(min_desired_rounds=small+2, max_desired_rounds=large-2) - - # generate some sample hashes - small_hash = self.do_stub_encrypt(subcls, rounds=small) - medium_hash = self.do_stub_encrypt(subcls, rounds=medium) - large_hash = self.do_stub_encrypt(subcls, rounds=large) - - # everything should be w/in bounds for original handler - self.assertFalse(subcls.needs_update(small_hash)) - self.assertFalse(subcls.needs_update(medium_hash)) - self.assertFalse(subcls.needs_update(large_hash)) - - # small & large should require update for temp handler - self.assertTrue(temp.needs_update(small_hash)) - self.assertFalse(temp.needs_update(medium_hash)) - self.assertTrue(temp.needs_update(large_hash)) - - #=================================================================== - # idents - #=================================================================== - def require_many_idents(self): - handler = self.handler - if not isinstance(handler, type) or not issubclass(handler, uh.HasManyIdents): - raise self.skipTest("handler doesn't derive from HasManyIdents") - - def test_30_HasManyIdents(self): - """validate HasManyIdents configuration""" - cls = self.handler - self.require_many_idents() - - # check settings - self.assertTrue('ident' in cls.setting_kwds) - - # check ident_values list - for value in cls.ident_values: - self.assertIsInstance(value, unicode, - "cls.ident_values must be unicode:") - self.assertTrue(len(cls.ident_values)>1, - "cls.ident_values must have 2+ elements:") - - # check default_ident value - self.assertIsInstance(cls.default_ident, unicode, - "cls.default_ident must be unicode:") - self.assertTrue(cls.default_ident in cls.ident_values, - "cls.default_ident must specify member of cls.ident_values") - - # check optional aliases list - if cls.ident_aliases: - for alias, ident in iteritems(cls.ident_aliases): - self.assertIsInstance(alias, unicode, - "cls.ident_aliases keys must be unicode:") # XXX: allow ints? - self.assertIsInstance(ident, unicode, - "cls.ident_aliases values must be unicode:") - self.assertTrue(ident in cls.ident_values, - "cls.ident_aliases must map to cls.ident_values members: %r" % (ident,)) - - # check constructor validates ident correctly. - handler = cls - hash = self.get_sample_hash()[1] - kwds = handler.parsehash(hash) - del kwds['ident'] - - # ... accepts good ident - handler(ident=cls.default_ident, **kwds) - - # ... requires ident w/o defaults - self.assertRaises(TypeError, handler, **kwds) - - # ... supplies default ident - handler(use_defaults=True, **kwds) - - # ... rejects bad ident - self.assertRaises(ValueError, handler, ident='xXx', **kwds) - - # TODO: check various supported idents - - def test_has_many_idents_using(self): - """HasManyIdents.using() -- 'default_ident' and 'ident' keywords""" - self.require_many_idents() - - # pick alt ident to test with - handler = self.handler - orig_ident = handler.default_ident - for alt_ident in handler.ident_values: - if alt_ident != orig_ident: - break - else: - raise AssertionError("expected to find alternate ident: default=%r values=%r" % - (orig_ident, handler.ident_values)) - - def effective_ident(cls): - cls = unwrap_handler(cls) - return cls(use_defaults=True).ident - - # keep default if nothing else specified - subcls = handler.using() - self.assertEqual(subcls.default_ident, orig_ident) - - # accepts alt ident - subcls = handler.using(default_ident=alt_ident) - self.assertEqual(subcls.default_ident, alt_ident) - self.assertEqual(handler.default_ident, orig_ident) - - # check subcls actually *generates* default ident, - # and that we didn't affect orig handler - self.assertEqual(effective_ident(subcls), alt_ident) - self.assertEqual(effective_ident(handler), orig_ident) - - # rejects bad ident - self.assertRaises(ValueError, handler.using, default_ident='xXx') - - # honor 'ident' alias - subcls = handler.using(ident=alt_ident) - self.assertEqual(subcls.default_ident, alt_ident) - self.assertEqual(handler.default_ident, orig_ident) - - # forbid both at same time - self.assertRaises(TypeError, handler.using, default_ident=alt_ident, ident=alt_ident) - - # check ident aliases are being honored - if handler.ident_aliases: - for alias, ident in handler.ident_aliases.items(): - subcls = handler.using(ident=alias) - self.assertEqual(subcls.default_ident, ident, msg="alias %r:" % alias) - - #=================================================================== - # password size limits - #=================================================================== - def test_truncate_error_setting(self): - """ - validate 'truncate_error' setting & related attributes - """ - # If it doesn't have truncate_size set, - # it shouldn't support truncate_error - hasher = self.handler - if hasher.truncate_size is None: - self.assertNotIn("truncate_error", hasher.setting_kwds) - return - - # if hasher defaults to silently truncating, - # it MUST NOT use .truncate_verify_reject, - # because resulting hashes wouldn't verify! - if not hasher.truncate_error: - self.assertFalse(hasher.truncate_verify_reject) - - # if hasher doesn't have configurable policy, - # it must throw error by default - if "truncate_error" not in hasher.setting_kwds: - self.assertTrue(hasher.truncate_error) - return - - # test value parsing - def parse_value(value): - return hasher.using(truncate_error=value).truncate_error - self.assertEqual(parse_value(None), hasher.truncate_error) - self.assertEqual(parse_value(True), True) - self.assertEqual(parse_value("true"), True) - self.assertEqual(parse_value(False), False) - self.assertEqual(parse_value("false"), False) - self.assertRaises(ValueError, parse_value, "xxx") - - def test_secret_wo_truncate_size(self): - """ - test no password size limits enforced (if truncate_size=None) - """ - # skip if hasher has a maximum password size - hasher = self.handler - if hasher.truncate_size is not None: - self.assertGreaterEqual(hasher.truncate_size, 1) - raise self.skipTest("truncate_size is set") - - # NOTE: this doesn't do an exhaustive search to verify algorithm - # doesn't have some cutoff point, it just tries - # 1024-character string, and alters the last char. - # as long as algorithm doesn't clip secret at point <1024, - # the new secret shouldn't verify. - - # hash a 1024-byte secret - secret = "too many secrets" * 16 - alt = "x" - hash = self.do_encrypt(secret) - - # check that verify doesn't silently reject secret - # (i.e. hasher mistakenly honors .truncate_verify_reject) - verify_success = not hasher.is_disabled - self.assertEqual(self.do_verify(secret, hash), verify_success, - msg="verify rejected correct secret") - - # alter last byte, should get different hash, which won't verify - alt_secret = secret[:-1] + alt - self.assertFalse(self.do_verify(alt_secret, hash), - "full password not used in digest") - - def test_secret_w_truncate_size(self): - """ - test password size limits raise truncate_error (if appropriate) - """ - #-------------------------------------------------- - # check if test is applicable - #-------------------------------------------------- - handler = self.handler - truncate_size = handler.truncate_size - if not truncate_size: - raise self.skipTest("truncate_size not set") - - #-------------------------------------------------- - # setup vars - #-------------------------------------------------- - # try to get versions w/ and w/o truncate_error set. - # set to None if policy isn't configruable - size_error_type = exc.PasswordSizeError - if "truncate_error" in handler.setting_kwds: - without_error = handler.using(truncate_error=False) - with_error = handler.using(truncate_error=True) - size_error_type = exc.PasswordTruncateError - elif handler.truncate_error: - without_error = None - with_error = handler - else: - # NOTE: this mode is currently an error in test_truncate_error_setting() - without_error = handler - with_error = None - - # create some test secrets - base = "too many secrets" - alt = "x" # char that's not in base, used to mutate test secrets - long_secret = repeat_string(base, truncate_size+1) - short_secret = long_secret[:-1] - alt_long_secret = long_secret[:-1] + alt - alt_short_secret = short_secret[:-1] + alt - - # init flags - short_verify_success = not handler.is_disabled - long_verify_success = short_verify_success and \ - not handler.truncate_verify_reject - - #-------------------------------------------------- - # do tests on length secret, and resulting hash. - # should pass regardless of truncate_error policy. - #-------------------------------------------------- - assert without_error or with_error - for cand_hasher in [without_error, with_error]: - - # create & hash string that's exactly chars. - short_hash = self.do_encrypt(short_secret, handler=cand_hasher) - - # check hash verifies, regardless of .truncate_verify_reject - self.assertEqual(self.do_verify(short_secret, short_hash, - handler=cand_hasher), - short_verify_success) - - # changing 'th char should invalidate hash - # if this fails, means (reported) truncate_size is too large. - self.assertFalse(self.do_verify(alt_short_secret, short_hash, - handler=with_error), - "truncate_size value is too large") - - # verify should truncate long secret before comparing - # (unless truncate_verify_reject is set) - self.assertEqual(self.do_verify(long_secret, short_hash, - handler=cand_hasher), - long_verify_success) - - #-------------------------------------------------- - # do tests on length secret, - # w/ truncate error disabled (should silently truncate) - #-------------------------------------------------- - if without_error: - - # create & hash string that's exactly truncate_size+1 chars - long_hash = self.do_encrypt(long_secret, handler=without_error) - - # check verifies against secret (unless truncate_verify_reject=True) - self.assertEqual(self.do_verify(long_secret, long_hash, - handler=without_error), - short_verify_success) - - # check mutating last char doesn't change outcome. - # if this fails, means (reported) truncate_size is too small. - self.assertEqual(self.do_verify(alt_long_secret, long_hash, - handler=without_error), - short_verify_success) - - # check short_secret verifies against this hash - # if this fails, means (reported) truncate_size is too large. - self.assertTrue(self.do_verify(short_secret, long_hash, - handler=without_error)) - - #-------------------------------------------------- - # do tests on length secret, - # w/ truncate error - #-------------------------------------------------- - if with_error: - - # with errors enabled, should forbid truncation. - err = self.assertRaises(size_error_type, self.do_encrypt, - long_secret, handler=with_error) - self.assertEqual(err.max_size, truncate_size) - - #=================================================================== - # password contents - #=================================================================== - def test_61_secret_case_sensitive(self): - """test password case sensitivity""" - hash_insensitive = self.secret_case_insensitive is True - verify_insensitive = self.secret_case_insensitive in [True, - "verify-only"] - - # test hashing lower-case verifies against lower & upper - lower = 'test' - upper = 'TEST' - h1 = self.do_encrypt(lower) - if verify_insensitive and not self.handler.is_disabled: - self.assertTrue(self.do_verify(upper, h1), - "verify() should not be case sensitive") - else: - self.assertFalse(self.do_verify(upper, h1), - "verify() should be case sensitive") - - # test hashing upper-case verifies against lower & upper - h2 = self.do_encrypt(upper) - if verify_insensitive and not self.handler.is_disabled: - self.assertTrue(self.do_verify(lower, h2), - "verify() should not be case sensitive") - else: - self.assertFalse(self.do_verify(lower, h2), - "verify() should be case sensitive") - - # test genhash - # XXX: 2.0: what about 'verify-only' hashes once genhash() is removed? - # won't have easy way to recreate w/ same config to see if hash differs. - # (though only hash this applies to is mssql2000) - h2 = self.do_genhash(upper, h1) - if hash_insensitive or (self.handler.is_disabled and not self.disabled_contains_salt): - self.assertEqual(h2, h1, - "genhash() should not be case sensitive") - else: - self.assertNotEqual(h2, h1, - "genhash() should be case sensitive") - - def test_62_secret_border(self): - """test non-string passwords are rejected""" - hash = self.get_sample_hash()[1] - - # secret=None - self.assertRaises(TypeError, self.do_encrypt, None) - self.assertRaises(TypeError, self.do_genhash, None, hash) - self.assertRaises(TypeError, self.do_verify, None, hash) - - # secret=int (picked as example of entirely wrong class) - self.assertRaises(TypeError, self.do_encrypt, 1) - self.assertRaises(TypeError, self.do_genhash, 1, hash) - self.assertRaises(TypeError, self.do_verify, 1, hash) - - # xxx: move to password size limits section, above? - def test_63_large_secret(self): - """test MAX_PASSWORD_SIZE is enforced""" - from passlib.exc import PasswordSizeError - from passlib.utils import MAX_PASSWORD_SIZE - secret = '.' * (1+MAX_PASSWORD_SIZE) - hash = self.get_sample_hash()[1] - err = self.assertRaises(PasswordSizeError, self.do_genhash, secret, hash) - self.assertEqual(err.max_size, MAX_PASSWORD_SIZE) - self.assertRaises(PasswordSizeError, self.do_encrypt, secret) - self.assertRaises(PasswordSizeError, self.do_verify, secret, hash) - - def test_64_forbidden_chars(self): - """test forbidden characters not allowed in password""" - chars = self.forbidden_characters - if not chars: - raise self.skipTest("none listed") - base = u('stub') - if isinstance(chars, bytes): - from passlib.utils.compat import iter_byte_chars - chars = iter_byte_chars(chars) - base = base.encode("ascii") - for c in chars: - self.assertRaises(ValueError, self.do_encrypt, base + c + base) - - #=================================================================== - # check identify(), verify(), genhash() against test vectors - #=================================================================== - def is_secret_8bit(self, secret): - secret = self.populate_context(secret, {}) - return not is_ascii_safe(secret) - - def expect_os_crypt_failure(self, secret): - """ - check if we're expecting potential verify failure due to crypt.crypt() encoding limitation - """ - if PY3 and self.backend == "os_crypt" and isinstance(secret, bytes): - try: - secret.decode("utf-8") - except UnicodeDecodeError: - return True - return False - - def test_70_hashes(self): - """test known hashes""" - - # sanity check - self.assertTrue(self.known_correct_hashes or self.known_correct_configs, - "test must set at least one of 'known_correct_hashes' " - "or 'known_correct_configs'") - - # run through known secret/hash pairs - saw8bit = False - for secret, hash in self.iter_known_hashes(): - if self.is_secret_8bit(secret): - saw8bit = True - - # hash should be positively identified by handler - self.assertTrue(self.do_identify(hash), - "identify() failed to identify hash: %r" % (hash,)) - - # check if what we're about to do is expected to fail due to crypt.crypt() limitation. - expect_os_crypt_failure = self.expect_os_crypt_failure(secret) - try: - - # secret should verify successfully against hash - self.check_verify(secret, hash, "verify() of known hash failed: " - "secret=%r, hash=%r" % (secret, hash)) - - # genhash() should reproduce same hash - result = self.do_genhash(secret, hash) - self.assertIsInstance(result, str, - "genhash() failed to return native string: %r" % (result,)) - if self.handler.is_disabled and self.disabled_contains_salt: - continue - self.assertEqual(result, hash, "genhash() failed to reproduce " - "known hash: secret=%r, hash=%r: result=%r" % - (secret, hash, result)) - - except MissingBackendError: - if not expect_os_crypt_failure: - raise - - # would really like all handlers to have at least one 8-bit test vector - if not saw8bit: - warn("%s: no 8-bit secrets tested" % self.__class__) - - def test_71_alternates(self): - """test known alternate hashes""" - if not self.known_alternate_hashes: - raise self.skipTest("no alternate hashes provided") - for alt, secret, hash in self.known_alternate_hashes: - - # hash should be positively identified by handler - self.assertTrue(self.do_identify(hash), - "identify() failed to identify alternate hash: %r" % - (hash,)) - - # secret should verify successfully against hash - self.check_verify(secret, alt, "verify() of known alternate hash " - "failed: secret=%r, hash=%r" % (secret, alt)) - - # genhash() should reproduce canonical hash - result = self.do_genhash(secret, alt) - self.assertIsInstance(result, str, - "genhash() failed to return native string: %r" % (result,)) - if self.handler.is_disabled and self.disabled_contains_salt: - continue - self.assertEqual(result, hash, "genhash() failed to normalize " - "known alternate hash: secret=%r, alt=%r, hash=%r: " - "result=%r" % (secret, alt, hash, result)) - - def test_72_configs(self): - """test known config strings""" - # special-case handlers without settings - if not self.handler.setting_kwds: - self.assertFalse(self.known_correct_configs, - "handler should not have config strings") - raise self.skipTest("hash has no settings") - - if not self.known_correct_configs: - # XXX: make this a requirement? - raise self.skipTest("no config strings provided") - - # make sure config strings work (hashes in list tested in test_70) - if self.filter_config_warnings: - warnings.filterwarnings("ignore", category=PasslibHashWarning) - for config, secret, hash in self.known_correct_configs: - - # config should be positively identified by handler - self.assertTrue(self.do_identify(config), - "identify() failed to identify known config string: %r" % - (config,)) - - # verify() should throw error for config strings. - self.assertRaises(ValueError, self.do_verify, secret, config, - __msg__="verify() failed to reject config string: %r" % - (config,)) - - # genhash() should reproduce hash from config. - result = self.do_genhash(secret, config) - self.assertIsInstance(result, str, - "genhash() failed to return native string: %r" % (result,)) - self.assertEqual(result, hash, "genhash() failed to reproduce " - "known hash from config: secret=%r, config=%r, hash=%r: " - "result=%r" % (secret, config, hash, result)) - - def test_73_unidentified(self): - """test known unidentifiably-mangled strings""" - if not self.known_unidentified_hashes: - raise self.skipTest("no unidentified hashes provided") - for hash in self.known_unidentified_hashes: - - # identify() should reject these - self.assertFalse(self.do_identify(hash), - "identify() incorrectly identified known unidentifiable " - "hash: %r" % (hash,)) - - # verify() should throw error - self.assertRaises(ValueError, self.do_verify, 'stub', hash, - __msg__= "verify() failed to throw error for unidentifiable " - "hash: %r" % (hash,)) - - # genhash() should throw error - self.assertRaises(ValueError, self.do_genhash, 'stub', hash, - __msg__= "genhash() failed to throw error for unidentifiable " - "hash: %r" % (hash,)) - - def test_74_malformed(self): - """test known identifiable-but-malformed strings""" - if not self.known_malformed_hashes: - raise self.skipTest("no malformed hashes provided") - for hash in self.known_malformed_hashes: - - # identify() should accept these - self.assertTrue(self.do_identify(hash), - "identify() failed to identify known malformed " - "hash: %r" % (hash,)) - - # verify() should throw error - self.assertRaises(ValueError, self.do_verify, 'stub', hash, - __msg__= "verify() failed to throw error for malformed " - "hash: %r" % (hash,)) - - # genhash() should throw error - self.assertRaises(ValueError, self.do_genhash, 'stub', hash, - __msg__= "genhash() failed to throw error for malformed " - "hash: %r" % (hash,)) - - def test_75_foreign(self): - """test known foreign hashes""" - if self.accepts_all_hashes: - raise self.skipTest("not applicable") - if not self.known_other_hashes: - raise self.skipTest("no foreign hashes provided") - for name, hash in self.known_other_hashes: - # NOTE: most tests use default list of foreign hashes, - # so they may include ones belonging to that hash... - # hence the 'own' logic. - - if name == self.handler.name: - # identify should accept these - self.assertTrue(self.do_identify(hash), - "identify() failed to identify known hash: %r" % (hash,)) - - # verify & genhash should NOT throw error - self.do_verify('stub', hash) - result = self.do_genhash('stub', hash) - self.assertIsInstance(result, str, - "genhash() failed to return native string: %r" % (result,)) - - else: - # identify should reject these - self.assertFalse(self.do_identify(hash), - "identify() incorrectly identified hash belonging to " - "%s: %r" % (name, hash)) - - # verify should throw error - self.assertRaises(ValueError, self.do_verify, 'stub', hash, - __msg__= "verify() failed to throw error for hash " - "belonging to %s: %r" % (name, hash,)) - - # genhash() should throw error - self.assertRaises(ValueError, self.do_genhash, 'stub', hash, - __msg__= "genhash() failed to throw error for hash " - "belonging to %s: %r" % (name, hash)) - - def test_76_hash_border(self): - """test non-string hashes are rejected""" - # - # test hash=None is handled correctly - # - self.assertRaises(TypeError, self.do_identify, None) - self.assertRaises(TypeError, self.do_verify, 'stub', None) - - # NOTE: changed in 1.7 -- previously 'None' would be accepted when config strings not supported. - self.assertRaises(TypeError, self.do_genhash, 'stub', None) - - # - # test hash=int is rejected (picked as example of entirely wrong type) - # - self.assertRaises(TypeError, self.do_identify, 1) - self.assertRaises(TypeError, self.do_verify, 'stub', 1) - self.assertRaises(TypeError, self.do_genhash, 'stub', 1) - - # - # test hash='' is rejected for all but the plaintext hashes - # - for hash in [u(''), b'']: - if self.accepts_all_hashes: - # then it accepts empty string as well. - self.assertTrue(self.do_identify(hash)) - self.do_verify('stub', hash) - result = self.do_genhash('stub', hash) - self.check_returned_native_str(result, "genhash") - else: - # otherwise it should reject them - self.assertFalse(self.do_identify(hash), - "identify() incorrectly identified empty hash") - self.assertRaises(ValueError, self.do_verify, 'stub', hash, - __msg__="verify() failed to reject empty hash") - self.assertRaises(ValueError, self.do_genhash, 'stub', hash, - __msg__="genhash() failed to reject empty hash") - - # - # test identify doesn't throw decoding errors on 8-bit input - # - self.do_identify('\xe2\x82\xac\xc2\xa5$') # utf-8 - self.do_identify('abc\x91\x00') # non-utf8 - - #=================================================================== - # test parsehash() - #=================================================================== - - #: optional list of known parse hash results for hasher - known_parsehash_results = [] - - def require_parsehash(self): - if not hasattr(self.handler, "parsehash"): - raise SkipTest("parsehash() not implemented") - - def test_70_parsehash(self): - """ - parsehash() - """ - # TODO: would like to enhance what this test covers - - self.require_parsehash() - handler = self.handler - - # calls should succeed, and return dict - hash = self.do_encrypt("stub") - result = handler.parsehash(hash) - self.assertIsInstance(result, dict) - # TODO: figure out what invariants we can reliably parse, - # or maybe make subclasses specify that? - - # w/ checksum=False, should omit that key - result2 = handler.parsehash(hash, checksum=False) - correct2 = result.copy() - correct2.pop("checksum", None) - self.assertEqual(result2, correct2) - - # w/ sanitize=True - # correct output should mask salt / checksum; - # but all else should be the same - result3 = handler.parsehash(hash, sanitize=True) - correct3 = result.copy() - if PY2: - # silence warning about bytes & unicode not comparing - # (sanitize may convert bytes into base64 text) - warnings.filterwarnings("ignore", ".*unequal comparison failed to convert.*", - category=UnicodeWarning) - for key in ("salt", "checksum"): - if key in result3: - self.assertNotEqual(result3[key], correct3[key]) - self.assert_is_masked(result3[key]) - correct3[key] = result3[key] - self.assertEqual(result3, correct3) - - def assert_is_masked(self, value): - """ - check value properly masked by :func:`passlib.utils.mask_value` - """ - if value is None: - return - self.assertIsInstance(value, unicode) - # assumes mask_value() defaults will never show more than chars (4); - # and show nothing if size less than 1/ (8). - ref = value if len(value) < 8 else value[4:] - if set(ref) == set(["*"]): - return True - raise self.fail("value not masked: %r" % value) - - def test_71_parsehash_results(self): - """ - parsehash() -- known outputs - """ - self.require_parsehash() - samples = self.known_parsehash_results - if not samples: - raise self.skipTest("no samples present") - # XXX: expand to test w/ checksum=False and/or sanitize=True? - # or read "_unsafe_settings"? - for hash, correct in self.known_parsehash_results: - result = self.handler.parsehash(hash) - self.assertEqual(result, correct, "hash=%r:" % hash) - - #=================================================================== - # fuzz testing - #=================================================================== - def test_77_fuzz_input(self, threaded=False): - """fuzz testing -- random passwords and options - - This test attempts to perform some basic fuzz testing of the hash, - based on whatever information can be found about it. - It does as much as it can within a fixed amount of time - (defaults to 1 second, but can be overridden via $PASSLIB_TEST_FUZZ_TIME). - It tests the following: - - * randomly generated passwords including extended unicode chars - * randomly selected rounds values (if rounds supported) - * randomly selected salt sizes (if salts supported) - * randomly selected identifiers (if multiple found) - * runs output of selected backend against other available backends - (if any) to detect errors occurring between different backends. - * runs output against other "external" verifiers such as OS crypt() - - :param report_thread_state: - if true, writes state of loop to current_thread().passlib_fuzz_state. - used to help debug multi-threaded fuzz test issues (below) - """ - if self.handler.is_disabled: - raise self.skipTest("not applicable") - - # gather info - from passlib.utils import tick - max_time = self.max_fuzz_time - if max_time <= 0: - raise self.skipTest("disabled by test mode") - verifiers = self.get_fuzz_verifiers(threaded=threaded) - def vname(v): - return (v.__doc__ or v.__name__).splitlines()[0] - - # init rng -- using separate one for each thread - # so things are predictable for given RANDOM_TEST_SEED - # (relies on test_78_fuzz_threading() to give threads unique names) - if threaded: - thread_name = threading.current_thread().name - else: - thread_name = "fuzz test" - rng = self.getRandom(name=thread_name) - generator = self.FuzzHashGenerator(self, rng) - - # do as many tests as possible for max_time seconds - log.debug("%s: %s: started; max_time=%r verifiers=%d (%s)", - self.descriptionPrefix, thread_name, max_time, len(verifiers), - ", ".join(vname(v) for v in verifiers)) - start = tick() - stop = start + max_time - count = 0 - while tick() <= stop: - # generate random password & options - opts = generator.generate() - secret = opts['secret'] - other = opts['other'] - settings = opts['settings'] - ctx = opts['context'] - if ctx: - settings['context'] = ctx - - # create new hash - hash = self.do_encrypt(secret, **settings) - ##log.debug("fuzz test: hash=%r secret=%r other=%r", - ## hash, secret, other) - - # run through all verifiers we found. - for verify in verifiers: - name = vname(verify) - result = verify(secret, hash, **ctx) - if result == "skip": # let verifiers signal lack of support - continue - assert result is True or result is False - if not result: - raise self.failureException("failed to verify against %r verifier: " - "secret=%r config=%r hash=%r" % - (name, secret, settings, hash)) - # occasionally check that some other secrets WON'T verify - # against this hash. - if rng.random() < .1: - result = verify(other, hash, **ctx) - if result and result != "skip": - raise self.failureException("was able to verify wrong " - "password using %s: wrong_secret=%r real_secret=%r " - "config=%r hash=%r" % (name, other, secret, settings, hash)) - count += 1 - - log.debug("%s: %s: done; elapsed=%r count=%r", - self.descriptionPrefix, thread_name, tick() - start, count) - - def test_78_fuzz_threading(self): - """multithreaded fuzz testing -- random password & options using multiple threads - - run test_77 simultaneously in multiple threads - in an attempt to detect any concurrency issues - (e.g. the bug fixed by pybcrypt 0.3) - """ - self.require_TEST_MODE("full") - import threading - - # check if this test should run - if self.handler.is_disabled: - raise self.skipTest("not applicable") - thread_count = self.fuzz_thread_count - if thread_count < 1 or self.max_fuzz_time <= 0: - raise self.skipTest("disabled by test mode") - - # buffer to hold errors thrown by threads - failed_lock = threading.Lock() - failed = [0] - - # launch threads, all of which run - # test_77_fuzz_input(), and see if any errors get thrown. - # if hash has concurrency issues, this should reveal it. - def wrapper(): - try: - self.test_77_fuzz_input(threaded=True) - except SkipTest: - pass - except: - with failed_lock: - failed[0] += 1 - raise - def launch(n): - cls = type(self) - name = "Fuzz-Thread-%d ('%s:%s.%s')" % (n, cls.__module__, cls.__name__, - self._testMethodName) - thread = threading.Thread(target=wrapper, name=name) - thread.setDaemon(True) - thread.start() - return thread - threads = [launch(n) for n in irange(thread_count)] - - # wait until all threads exit - timeout = self.max_fuzz_time * thread_count * 4 - stalled = 0 - for thread in threads: - thread.join(timeout) - if not thread.is_alive(): - continue - # XXX: not sure why this is happening, main one seems 1/4 times for sun_md5_crypt - log.error("%s timed out after %f seconds", thread.name, timeout) - stalled += 1 - - # if any thread threw an error, raise one ourselves. - if failed[0]: - raise self.fail("%d/%d threads failed concurrent fuzz testing " - "(see error log for details)" % (failed[0], thread_count)) - if stalled: - raise self.fail("%d/%d threads stalled during concurrent fuzz testing " - "(see error log for details)" % (stalled, thread_count)) - - #--------------------------------------------------------------- - # fuzz constants & helpers - #--------------------------------------------------------------- - - @property - def max_fuzz_time(self): - """amount of time to spend on fuzz testing""" - value = float(os.environ.get("PASSLIB_TEST_FUZZ_TIME") or 0) - if value: - return value - elif TEST_MODE(max="quick"): - return 0 - elif TEST_MODE(max="default"): - return 1 - else: - return 5 - - @property - def fuzz_thread_count(self): - """number of threads for threaded fuzz testing""" - value = int(os.environ.get("PASSLIB_TEST_FUZZ_THREADS") or 0) - if value: - return value - elif TEST_MODE(max="quick"): - return 0 - else: - return 10 - - #--------------------------------------------------------------- - # fuzz verifiers - #--------------------------------------------------------------- - - #: list of custom fuzz-test verifiers (in addition to hasher itself, - #: and backend-specific wrappers of hasher). each element is - #: name of method that will return None / a verifier callable. - fuzz_verifiers = ("fuzz_verifier_default",) - - def get_fuzz_verifiers(self, threaded=False): - """return list of password verifiers (including external libs) - - used by fuzz testing. - verifiers should be callable with signature - ``func(password: unicode, hash: ascii str) -> ok: bool``. - """ - handler = self.handler - verifiers = [] - - # call all methods starting with prefix in order to create - for method_name in self.fuzz_verifiers: - func = getattr(self, method_name)() - if func is not None: - verifiers.append(func) - - # create verifiers for any other available backends - # NOTE: skipping this under threading test, - # since backend switching isn't threadsafe (yet) - if hasattr(handler, "backends") and TEST_MODE("full") and not threaded: - def maker(backend): - def func(secret, hash): - orig_backend = handler.get_backend() - try: - handler.set_backend(backend) - return handler.verify(secret, hash) - finally: - handler.set_backend(orig_backend) - func.__name__ = "check_" + backend + "_backend" - func.__doc__ = backend + "-backend" - return func - for backend in iter_alt_backends(handler): - verifiers.append(maker(backend)) - - return verifiers - - def fuzz_verifier_default(self): - # test against self - def check_default(secret, hash, **ctx): - return self.do_verify(secret, hash, **ctx) - if self.backend: - check_default.__doc__ = self.backend + "-backend" - else: - check_default.__doc__ = "self" - return check_default - - #--------------------------------------------------------------- - # fuzz settings generation - #--------------------------------------------------------------- - class FuzzHashGenerator(object): - """ - helper which takes care of generating random - passwords & configuration options to test hash with. - separate from test class so we can create one per thread. - """ - #========================================================== - # class attrs - #========================================================== - - # alphabet for randomly generated passwords - password_alphabet = u('qwertyASDF1234<>.@*#! \u00E1\u0259\u0411\u2113') - - # encoding when testing bytes - password_encoding = "utf-8" - - # map of setting kwd -> method name. - # will ignore setting if method returns None. - # subclasses should make copy of dict. - settings_map = dict(rounds="random_rounds", - salt_size="random_salt_size", - ident="random_ident") - - # map of context kwd -> method name. - context_map = {} - - #========================================================== - # init / generation - #========================================================== - - def __init__(self, test, rng): - self.test = test - self.handler = test.handler - self.rng = rng - - def generate(self): - """ - generate random password and options for fuzz testing. - :returns: - `(secret, other_secret, settings_kwds, context_kwds)` - """ - def gendict(map): - out = {} - for key, meth in map.items(): - value = getattr(self, meth)() - if value is not None: - out[key] = value - return out - secret, other = self.random_password_pair() - return dict(secret=secret, - other=other, - settings=gendict(self.settings_map), - context=gendict(self.context_map), - ) - - #========================================================== - # helpers - #========================================================== - def randintgauss(self, lower, upper, mu, sigma): - """generate random int w/ gauss distirbution""" - value = self.rng.normalvariate(mu, sigma) - return int(limit(value, lower, upper)) - - #========================================================== - # settings generation - #========================================================== - - def random_rounds(self): - handler = self.handler - if not has_rounds_info(handler): - return None - default = handler.default_rounds or handler.min_rounds - lower = handler.min_rounds - if handler.rounds_cost == "log2": - upper = default - else: - upper = min(default*2, handler.max_rounds) - return self.randintgauss(lower, upper, default, default*.5) - - def random_salt_size(self): - handler = self.handler - if not (has_salt_info(handler) and 'salt_size' in handler.setting_kwds): - return None - default = handler.default_salt_size - lower = handler.min_salt_size - upper = handler.max_salt_size or default*4 - return self.randintgauss(lower, upper, default, default*.5) - - def random_ident(self): - rng = self.rng - handler = self.handler - if 'ident' not in handler.setting_kwds or not hasattr(handler, "ident_values"): - return None - if rng.random() < .5: - return None - # resolve wrappers before reading values - handler = getattr(handler, "wrapped", handler) - return rng.choice(handler.ident_values) - - #========================================================== - # fuzz password generation - #========================================================== - def random_password_pair(self): - """generate random password, and non-matching alternate password""" - secret = self.random_password() - while True: - other = self.random_password() - if self.accept_password_pair(secret, other): - break - rng = self.rng - if rng.randint(0,1): - secret = secret.encode(self.password_encoding) - if rng.randint(0,1): - other = other.encode(self.password_encoding) - return secret, other - - def random_password(self): - """generate random passwords for fuzz testing""" - # occasionally try an empty password - rng = self.rng - if rng.random() < .0001: - return u('') - - # check if truncate size needs to be considered - handler = self.handler - truncate_size = handler.truncate_error and handler.truncate_size - max_size = truncate_size or 999999 - - # pick endpoint - if max_size < 50 or rng.random() < .5: - # chance of small password (~15 chars) - size = self.randintgauss(1, min(max_size, 50), 15, 15) - else: - # otherwise large password (~70 chars) - size = self.randintgauss(50, min(max_size, 99), 70, 20) - - # generate random password - result = getrandstr(rng, self.password_alphabet, size) - - # trim ones that encode past truncate point. - if truncate_size and isinstance(result, unicode): - while len(result.encode("utf-8")) > truncate_size: - result = result[:-1] - - return result - - def accept_password_pair(self, secret, other): - """verify fuzz pair contains different passwords""" - return secret != other - - #========================================================== - # eoc FuzzGenerator - #========================================================== - - #=================================================================== - # "disabled hasher" api - #=================================================================== - - def test_disable_and_enable(self): - """.disable() / .enable() methods""" - # - # setup - # - handler = self.handler - if not handler.is_disabled: - self.assertFalse(hasattr(handler, "disable")) - self.assertFalse(hasattr(handler, "enable")) - self.assertFalse(self.disabled_contains_salt) - raise self.skipTest("not applicable") - - # - # disable() - # - - # w/o existing hash - disabled_default = handler.disable() - self.assertIsInstance(disabled_default, str, - msg="disable() must return native string") - self.assertTrue(handler.identify(disabled_default), - msg="identify() didn't recognize disable() result: %r" % (disabled_default)) - - # w/ existing hash - stub = self.getRandom().choice(self.known_other_hashes)[1] - disabled_stub = handler.disable(stub) - self.assertIsInstance(disabled_stub, str, - msg="disable() must return native string") - self.assertTrue(handler.identify(disabled_stub), - msg="identify() didn't recognize disable() result: %r" % (disabled_stub)) - - # - # enable() - # - - # w/o original hash - self.assertRaisesRegex(ValueError, "cannot restore original hash", - handler.enable, disabled_default) - - # w/ original hash - try: - result = handler.enable(disabled_stub) - error = None - except ValueError as e: - result = None - error = e - - if error is None: - # if supports recovery, should have returned stub (e.g. unix_disabled); - self.assertIsInstance(result, str, - msg="enable() must return native string") - self.assertEqual(result, stub) - else: - # if doesn't, should have thrown appropriate error - self.assertIsInstance(error, ValueError) - self.assertRegex("cannot restore original hash", str(error)) - - # - # test repeating disable() & salting state - # - - # repeating disabled - disabled_default2 = handler.disable() - if self.disabled_contains_salt: - # should return new salt for each call (e.g. django_disabled) - self.assertNotEqual(disabled_default2, disabled_default) - elif error is None: - # should return same result for each hash, but unique across hashes - self.assertEqual(disabled_default2, disabled_default) - - # repeating same hash ... - disabled_stub2 = handler.disable(stub) - if self.disabled_contains_salt: - # ... should return different string (if salted) - self.assertNotEqual(disabled_stub2, disabled_stub) - else: - # ... should return same string - self.assertEqual(disabled_stub2, disabled_stub) - - # using different hash ... - disabled_other = handler.disable(stub + 'xxx') - if self.disabled_contains_salt or error is None: - # ... should return different string (if salted or hash encoded) - self.assertNotEqual(disabled_other, disabled_stub) - else: - # ... should return same string - self.assertEqual(disabled_other, disabled_stub) - - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# HandlerCase mixins providing additional tests for certain hashes -#============================================================================= -class OsCryptMixin(HandlerCase): - """helper used by create_backend_case() which adds additional features - to test the os_crypt backend. - - * if crypt support is missing, inserts fake crypt support to simulate - a working safe_crypt, to test passlib's codepath as fully as possible. - - * extra tests to verify non-conformant crypt implementations are handled - correctly. - - * check that native crypt support is detected correctly for known platforms. - """ - #=================================================================== - # class attrs - #=================================================================== - - # platforms that are known to support / not support this hash natively. - # list of (platform_regex, True|False|None) entries. - platform_crypt_support = [] - - #=================================================================== - # instance attrs - #=================================================================== - __unittest_skip = True - - # force this backend - backend = "os_crypt" - - # flag read by HandlerCase to detect if fake os crypt is enabled. - using_patched_crypt = False - - #=================================================================== - # setup - #=================================================================== - def setUp(self): - assert self.backend == "os_crypt" - if not self.handler.has_backend("os_crypt"): - # XXX: currently, any tests that use this are skipped entirely! (see issue 120) - self._patch_safe_crypt() - super(OsCryptMixin, self).setUp() - - @classmethod - def _get_safe_crypt_handler_backend(cls): - """ - return (handler, backend) pair to use for faking crypt.crypt() support for hash. - backend will be None if none availabe. - """ - # find handler that generates safe_crypt() compatible hash - handler = unwrap_handler(cls.handler) - - # hack to prevent recursion issue when .has_backend() is called - handler.get_backend() - - # find backend which isn't os_crypt - alt_backend = get_alt_backend(handler, "os_crypt") - return handler, alt_backend - - @property - def has_os_crypt_fallback(self): - """ - test if there's a fallback handler to test against if os_crypt can't support - a specified secret (may be explicitly set to False for some subclasses) - """ - return self._get_safe_crypt_handler_backend()[0] is not None - - def _patch_safe_crypt(self): - """if crypt() doesn't support current hash alg, this patches - safe_crypt() so that it transparently uses another one of the handler's - backends, so that we can go ahead and test as much of code path - as possible. - """ - # find handler & backend - handler, alt_backend = self._get_safe_crypt_handler_backend() - if not alt_backend: - raise AssertionError("handler has no available alternate backends!") - - # create subclass of handler, which we swap to an alternate backend - alt_handler = handler.using() - alt_handler.set_backend(alt_backend) - - def crypt_stub(secret, hash): - hash = alt_handler.genhash(secret, hash) - assert isinstance(hash, str) - return hash - - import passlib.utils as mod - self.patchAttr(mod, "_crypt", crypt_stub) - self.using_patched_crypt = True - - @classmethod - def _get_skip_backend_reason(cls, backend): - """ - make sure os_crypt backend is tested - when it's known os_crypt will be faked by _patch_safe_crypt() - """ - assert backend == "os_crypt" - reason = super(OsCryptMixin, cls)._get_skip_backend_reason(backend) - - from passlib.utils import has_crypt - if reason == cls._BACKEND_NOT_AVAILABLE and has_crypt: - if TEST_MODE("full") and cls._get_safe_crypt_handler_backend()[1]: - # in this case, _patch_safe_crypt() will monkeypatch os_crypt - # to use another backend, just so we can test os_crypt fully. - return None - else: - return "hash not supported by os crypt()" - - return reason - - #=================================================================== - # custom tests - #=================================================================== - - # TODO: turn into decorator, and use mock library. - def _use_mock_crypt(self): - """ - patch passlib.utils.safe_crypt() so it returns mock value for duration of test. - returns function whose .return_value controls what's returned. - this defaults to None. - """ - import passlib.utils as mod - - def mock_crypt(secret, config): - # let 'test' string through so _load_os_crypt_backend() will still work - if secret == "test": - return mock_crypt.__wrapped__(secret, config) - else: - return mock_crypt.return_value - - mock_crypt.__wrapped__ = mod._crypt - mock_crypt.return_value = None - - self.patchAttr(mod, "_crypt", mock_crypt) - - return mock_crypt - - def test_80_faulty_crypt(self): - """test with faulty crypt()""" - hash = self.get_sample_hash()[1] - exc_types = (exc.InternalBackendError,) - mock_crypt = self._use_mock_crypt() - - def test(value): - # set safe_crypt() to return specified value, and - # make sure assertion error is raised by handler. - mock_crypt.return_value = value - self.assertRaises(exc_types, self.do_genhash, "stub", hash) - self.assertRaises(exc_types, self.do_encrypt, "stub") - self.assertRaises(exc_types, self.do_verify, "stub", hash) - - test('$x' + hash[2:]) # detect wrong prefix - test(hash[:-1]) # detect too short - test(hash + 'x') # detect too long - - def test_81_crypt_fallback(self): - """test per-call crypt() fallback""" - - # mock up safe_crypt to return None - mock_crypt = self._use_mock_crypt() - mock_crypt.return_value = None - - if self.has_os_crypt_fallback: - # handler should have a fallback to use when os_crypt backend refuses to handle secret. - h1 = self.do_encrypt("stub") - h2 = self.do_genhash("stub", h1) - self.assertEqual(h2, h1) - self.assertTrue(self.do_verify("stub", h1)) - else: - # handler should give up - from passlib.exc import InternalBackendError as err_type - hash = self.get_sample_hash()[1] - self.assertRaises(err_type, self.do_encrypt, 'stub') - self.assertRaises(err_type, self.do_genhash, 'stub', hash) - self.assertRaises(err_type, self.do_verify, 'stub', hash) - - @doesnt_require_backend - def test_82_crypt_support(self): - """ - test platform-specific crypt() support detection - - NOTE: this is mainly just a sanity check to ensure the runtime - detection is functioning correctly on some known platforms, - so that we can feel more confident it'll work right on unknown ones. - """ - - # skip wrapper handlers, won't ever have crypt support - if hasattr(self.handler, "orig_prefix"): - raise self.skipTest("not applicable to wrappers") - - # look for first entry that matches current system - # XXX: append "/" + platform.release() to string? - # XXX: probably should rework to support rows being dicts w/ "minver" / "maxver" keys, - # instead of hack where we add major # as part of platform regex. - using_backend = not self.using_patched_crypt - name = self.handler.name - platform = sys.platform - for pattern, expected in self.platform_crypt_support: - if re.match(pattern, platform): - break - else: - raise self.skipTest("no data for %r platform (current host support = %r)" % - (platform, using_backend)) - - # rules can use "state=None" to signal varied support; - # e.g. platform='freebsd8' ... sha256_crypt not added until 8.3 - if expected is None: - raise self.skipTest("varied support on %r platform (current host support = %r)" % - (platform, using_backend)) - - # compare expectation vs reality - if expected == using_backend: - pass - elif expected: - self.fail("expected %r platform would have native support for %r" % - (platform, name)) - else: - self.fail("did not expect %r platform would have native support for %r" % - (platform, name)) - - #=================================================================== - # fuzzy verified support -- add additional verifier that uses os crypt() - #=================================================================== - - def fuzz_verifier_crypt(self): - """test results against OS crypt()""" - - # don't use this if we're faking safe_crypt (pointless test), - # or if handler is a wrapper (only original handler will be supported by os) - handler = self.handler - if self.using_patched_crypt or hasattr(handler, "wrapped"): - return None - - # create a wrapper for fuzzy verified to use - from crypt import crypt - from passlib.utils import _safe_crypt_lock - encoding = self.FuzzHashGenerator.password_encoding - - def check_crypt(secret, hash): - """stdlib-crypt""" - if not self.crypt_supports_variant(hash): - return "skip" - # XXX: any reason not to use safe_crypt() here? or just want to test against bare metal? - secret = to_native_str(secret, encoding) - with _safe_crypt_lock: - return crypt(secret, hash) == hash - - return check_crypt - - def crypt_supports_variant(self, hash): - """ - fuzzy_verified_crypt() helper -- - used to determine if os crypt() supports a particular hash variant. - """ - return True - - #=================================================================== - # eoc - #=================================================================== - -class UserHandlerMixin(HandlerCase): - """helper for handlers w/ 'user' context kwd; mixin for HandlerCase - - this overrides the HandlerCase test harness methods - so that a username is automatically inserted to hash/verify - calls. as well, passing in a pair of strings as the password - will be interpreted as (secret,user) - """ - #=================================================================== - # option flags - #=================================================================== - default_user = "user" - requires_user = True - user_case_insensitive = False - - #=================================================================== - # instance attrs - #=================================================================== - __unittest_skip = True - - #=================================================================== - # custom tests - #=================================================================== - def test_80_user(self): - """test user context keyword""" - handler = self.handler - password = 'stub' - hash = handler.hash(password, user=self.default_user) - - if self.requires_user: - self.assertRaises(TypeError, handler.hash, password) - self.assertRaises(TypeError, handler.genhash, password, hash) - self.assertRaises(TypeError, handler.verify, password, hash) - else: - # e.g. cisco_pix works with or without one. - handler.hash(password) - handler.genhash(password, hash) - handler.verify(password, hash) - - def test_81_user_case(self): - """test user case sensitivity""" - lower = self.default_user.lower() - upper = lower.upper() - hash = self.do_encrypt('stub', context=dict(user=lower)) - if self.user_case_insensitive: - self.assertTrue(self.do_verify('stub', hash, user=upper), - "user should not be case sensitive") - else: - self.assertFalse(self.do_verify('stub', hash, user=upper), - "user should be case sensitive") - - def test_82_user_salt(self): - """test user used as salt""" - config = self.do_stub_encrypt() - h1 = self.do_genhash('stub', config, user='admin') - h2 = self.do_genhash('stub', config, user='admin') - self.assertEqual(h2, h1) - h3 = self.do_genhash('stub', config, user='root') - self.assertNotEqual(h3, h1) - - # TODO: user size? kinda dicey, depends on algorithm. - - #=================================================================== - # override test helpers - #=================================================================== - def populate_context(self, secret, kwds): - """insert username into kwds""" - if isinstance(secret, tuple): - secret, user = secret - elif not self.requires_user: - return secret - else: - user = self.default_user - if 'user' not in kwds: - kwds['user'] = user - return secret - - #=================================================================== - # modify fuzz testing - #=================================================================== - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - context_map = HandlerCase.FuzzHashGenerator.context_map.copy() - context_map.update(user="random_user") - - user_alphabet = u("asdQWE123") - - def random_user(self): - rng = self.rng - if not self.test.requires_user and rng.random() < .1: - return None - return getrandstr(rng, self.user_alphabet, rng.randint(2,10)) - - #=================================================================== - # eoc - #=================================================================== - -class EncodingHandlerMixin(HandlerCase): - """helper for handlers w/ 'encoding' context kwd; mixin for HandlerCase - - this overrides the HandlerCase test harness methods - so that an encoding can be inserted to hash/verify - calls by passing in a pair of strings as the password - will be interpreted as (secret,encoding) - """ - #=================================================================== - # instance attrs - #=================================================================== - __unittest_skip = True - - # restrict stock passwords & fuzz alphabet to latin-1, - # so different encodings can be tested safely. - stock_passwords = [ - u("test"), - b"test", - u("\u00AC\u00BA"), - ] - - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): - - password_alphabet = u('qwerty1234<>.@*#! \u00AC') - - def populate_context(self, secret, kwds): - """insert encoding into kwds""" - if isinstance(secret, tuple): - secret, encoding = secret - kwds.setdefault('encoding', encoding) - return secret - #=================================================================== - # eoc - #=================================================================== - -#============================================================================= -# warnings helpers -#============================================================================= -class reset_warnings(warnings.catch_warnings): - """catch_warnings() wrapper which clears warning registry & filters""" - - def __init__(self, reset_filter="always", reset_registry=".*", **kwds): - super(reset_warnings, self).__init__(**kwds) - self._reset_filter = reset_filter - self._reset_registry = re.compile(reset_registry) if reset_registry else None - - def __enter__(self): - # let parent class archive filter state - ret = super(reset_warnings, self).__enter__() - - # reset the filter to list everything - if self._reset_filter: - warnings.resetwarnings() - warnings.simplefilter(self._reset_filter) - - # archive and clear the __warningregistry__ key for all modules - # that match the 'reset' pattern. - pattern = self._reset_registry - if pattern: - backup = self._orig_registry = {} - for name, mod in list(sys.modules.items()): - if mod is None or not pattern.match(name): - continue - reg = getattr(mod, "__warningregistry__", None) - if reg: - backup[name] = reg.copy() - reg.clear() - return ret - - def __exit__(self, *exc_info): - # restore warning registry for all modules - pattern = self._reset_registry - if pattern: - # restore registry backup, clearing all registry entries that we didn't archive - backup = self._orig_registry - for name, mod in list(sys.modules.items()): - if mod is None or not pattern.match(name): - continue - reg = getattr(mod, "__warningregistry__", None) - if reg: - reg.clear() - orig = backup.get(name) - if orig: - if reg is None: - setattr(mod, "__warningregistry__", orig) - else: - reg.update(orig) - super(reset_warnings, self).__exit__(*exc_info) - -#============================================================================= -# eof -#============================================================================= diff --git a/backend/venv39/lib/python3.9/site-packages/passlib/totp.py b/backend/venv39/lib/python3.9/site-packages/passlib/totp.py deleted file mode 100644 index 9ad5000..0000000 --- a/backend/venv39/lib/python3.9/site-packages/passlib/totp.py +++ /dev/null @@ -1,1908 +0,0 @@ -"""passlib.totp -- TOTP / RFC6238 / Google Authenticator utilities.""" -#============================================================================= -# imports -#============================================================================= -from __future__ import absolute_import, division, print_function -from passlib.utils.compat import PY3 -# core -import base64 -import calendar -import json -import logging; log = logging.getLogger(__name__) -import math -import struct -import sys -import time as _time -import re -if PY3: - from urllib.parse import urlparse, parse_qsl, quote, unquote -else: - from urllib import quote, unquote - from urlparse import urlparse, parse_qsl -from warnings import warn -# site -try: - # TOTP encrypted keys only supported if cryptography (https://cryptography.io) is installed - from cryptography.hazmat.backends import default_backend as _cg_default_backend - import cryptography.hazmat.primitives.ciphers.algorithms - import cryptography.hazmat.primitives.ciphers.modes - from cryptography.hazmat.primitives import ciphers as _cg_ciphers - del cryptography -except ImportError: - log.debug("can't import 'cryptography' package, totp encryption disabled") - _cg_ciphers = _cg_default_backend = None -# pkg -from passlib import exc -from passlib.exc import TokenError, MalformedTokenError, InvalidTokenError, UsedTokenError -from passlib.utils import (to_unicode, to_bytes, consteq, - getrandbytes, rng, SequenceMixin, xor_bytes, getrandstr) -from passlib.utils.binary import BASE64_CHARS, b32encode, b32decode -from passlib.utils.compat import (u, unicode, native_string_types, bascii_to_str, int_types, num_types, - irange, byte_elem_value, UnicodeIO, suppress_cause) -from passlib.utils.decor import hybrid_method, memoized_property -from passlib.crypto.digest import lookup_hash, compile_hmac, pbkdf2_hmac -from passlib.hash import pbkdf2_sha256 -# local -__all__ = [ - # frontend classes - "AppWallet", - "TOTP", - - # errors (defined in passlib.exc, but exposed here for convenience) - "TokenError", - "MalformedTokenError", - "InvalidTokenError", - "UsedTokenError", - - # internal helper classes - "TotpToken", - "TotpMatch", -] - -#============================================================================= -# HACK: python < 2.7.4's urlparse() won't parse query strings unless the url scheme -# is one of the schemes in the urlparse.uses_query list. 2.7 abandoned -# this, and parses query if present, regardless of the scheme. -# as a workaround for older versions, we add "otpauth" to the known list. -# this was fixed by https://bugs.python.org/issue9374, in 2.7.4 release. -#============================================================================= -if sys.version_info < (2,7,4): - from urlparse import uses_query - if "otpauth" not in uses_query: - uses_query.append("otpauth") - log.debug("registered 'otpauth' scheme with urlparse.uses_query") - del uses_query - -#============================================================================= -# internal helpers -#============================================================================= - -#----------------------------------------------------------------------------- -# token parsing / rendering helpers -#----------------------------------------------------------------------------- - -#: regex used to clean whitespace from tokens & keys -_clean_re = re.compile(u(r"\s|[-=]"), re.U) - -_chunk_sizes = [4,6,5] - -def _get_group_size(klen): - """ - helper for group_string() -- - calculates optimal size of group for given string size. - """ - # look for exact divisor - for size in _chunk_sizes: - if not klen % size: - return size - # fallback to divisor with largest remainder - # (so chunks are as close to even as possible) - best = _chunk_sizes[0] - rem = 0 - for size in _chunk_sizes: - if klen % size > rem: - best = size - rem = klen % size - return best - -def group_string(value, sep="-"): - """ - reformat string into (roughly) evenly-sized groups, separated by **sep**. - useful for making tokens & keys easier to read by humans. - """ - klen = len(value) - size = _get_group_size(klen) - return sep.join(value[o:o+size] for o in irange(0, klen, size)) - -#----------------------------------------------------------------------------- -# encoding helpers -#----------------------------------------------------------------------------- - -def _decode_bytes(key, format): - """ - internal TOTP() helper -- - decodes key according to specified format. - """ - if format == "raw": - if not isinstance(key, bytes): - raise exc.ExpectedTypeError(key, "bytes", "key") - return key - # for encoded data, key must be either unicode or ascii-encoded bytes, - # and must contain a hex or base32 string. - key = to_unicode(key, param="key") - key = _clean_re.sub("", key).encode("utf-8") # strip whitespace & hypens - if format == "hex" or format == "base16": - return base64.b16decode(key.upper()) - elif format == "base32": - return b32decode(key) - # XXX: add base64 support? - else: - raise ValueError("unknown byte-encoding format: %r" % (format,)) - -#============================================================================= -# OTP management -#============================================================================= - -#: flag for detecting if encrypted totp support is present -AES_SUPPORT = bool(_cg_ciphers) - -#: regex for validating secret tags -_tag_re = re.compile("(?i)^[a-z0-9][a-z0-9_.-]*$") - -class AppWallet(object): - """ - This class stores application-wide secrets that can be used - to encrypt & decrypt TOTP keys for storage. - It's mostly an internal detail, applications usually just need - to pass ``secrets`` or ``secrets_path`` to :meth:`TOTP.using`. - - .. seealso:: - - :ref:`totp-storing-instances` for more details on this workflow. - - Arguments - ========= - :param secrets: - Dict of application secrets to use when encrypting/decrypting - stored TOTP keys. This should include a secret to use when encrypting - new keys, but may contain additional older secrets to decrypt - existing stored keys. - - The dict should map tags -> secrets, so that each secret is identified - by a unique tag. This tag will be stored along with the encrypted - key in order to determine which secret should be used for decryption. - Tag should be string that starts with regex range ``[a-z0-9]``, - and the remaining characters must be in ``[a-z0-9_.-]``. - - It is recommended to use something like a incremental counter - ("1", "2", ...), an ISO date ("2016-01-01", "2016-05-16", ...), - or a timestamp ("19803495", "19813495", ...) when assigning tags. - - This mapping be provided in three formats: - - * A python dict mapping tag -> secret - * A JSON-formatted string containing the dict - * A multiline string with the format ``"tag: value\\ntag: value\\n..."`` - - (This last format is mainly useful when loading from a text file via **secrets_path**) - - .. seealso:: :func:`generate_secret` to create a secret with sufficient entropy - - :param secrets_path: - Alternately, callers can specify a separate file where the - application-wide secrets are stored, using either of the string - formats described in **secrets**. - - :param default_tag: - Specifies which tag in **secrets** should be used as the default - for encrypting new keys. If omitted, the tags will be sorted, - and the largest tag used as the default. - - if all tags are numeric, they will be sorted numerically; - otherwise they will be sorted alphabetically. - this permits tags to be assigned numerically, - or e.g. using ``YYYY-MM-DD`` dates. - - :param encrypt_cost: - Optional time-cost factor for key encryption. - This value corresponds to log2() of the number of PBKDF2 - rounds used. - - .. warning:: - - The application secret(s) should be stored in a secure location by - your application, and each secret should contain a large amount - of entropy (to prevent brute-force attacks if the encrypted keys - are leaked). - - :func:`generate_secret` is provided as a convenience helper - to generate a new application secret of suitable size. - - Best practice is to load these values from a file via **secrets_path**, - and then have your application give up permission to read this file - once it's running. - - Public Methods - ============== - .. autoattribute:: has_secrets - .. autoattribute:: default_tag - - Semi-Private Methods - ==================== - The following methods are used internally by the :class:`TOTP` - class in order to encrypt & decrypt keys using the provided application - secrets. They will generally not be publically useful, and may have their - API changed periodically. - - .. automethod:: get_secret - .. automethod:: encrypt_key - .. automethod:: decrypt_key - """ - #======================================================================== - # instance attrs - #======================================================================== - - #: default salt size for encrypt_key() output - salt_size = 12 - - #: default cost (log2 of pbkdf2 rounds) for encrypt_key() output - #: NOTE: this is relatively low, since the majority of the security - #: relies on a high entropy secret to pass to AES. - encrypt_cost = 14 - - #: map of secret tag -> secret bytes - _secrets = None - - #: tag for default secret - default_tag = None - - #======================================================================== - # init - #======================================================================== - def __init__(self, secrets=None, default_tag=None, encrypt_cost=None, - secrets_path=None): - - # TODO: allow a lot more things to be customized from here, - # e.g. setting default TOTP constructor options. - - # - # init cost - # - if encrypt_cost is not None: - if isinstance(encrypt_cost, native_string_types): - encrypt_cost = int(encrypt_cost) - assert encrypt_cost >= 0 - self.encrypt_cost = encrypt_cost - - # - # init secrets map - # - - # load secrets from file (if needed) - if secrets_path is not None: - if secrets is not None: - raise TypeError("'secrets' and 'secrets_path' are mutually exclusive") - secrets = open(secrets_path, "rt").read() - - # parse & store secrets - secrets = self._secrets = self._parse_secrets(secrets) - - # - # init default tag/secret - # - if secrets: - if default_tag is not None: - # verify that tag is present in map - self.get_secret(default_tag) - elif all(tag.isdigit() for tag in secrets): - default_tag = max(secrets, key=int) - else: - default_tag = max(secrets) - self.default_tag = default_tag - - def _parse_secrets(self, source): - """ - parse 'secrets' parameter - - :returns: - Dict[tag:str, secret:bytes] - """ - # parse string formats - # to make this easy to pass in configuration from a separate file, - # 'secrets' can be string using two formats -- json & "tag:value\n" - check_type = True - if isinstance(source, native_string_types): - if source.lstrip().startswith(("[", "{")): - # json list / dict - source = json.loads(source) - elif "\n" in source and ":" in source: - # multiline string containing series of "tag: value\n" rows; - # empty and "#\n" rows are ignored - def iter_pairs(source): - for line in source.splitlines(): - line = line.strip() - if line and not line.startswith("#"): - tag, secret = line.split(":", 1) - yield tag.strip(), secret.strip() - source = iter_pairs(source) - check_type = False - else: - raise ValueError("unrecognized secrets string format") - - # ensure we have iterable of (tag, value) pairs - if source is None: - return {} - elif isinstance(source, dict): - source = source.items() - # XXX: could support iterable of (tag,value) pairs, but not yet needed... - # elif check_type and (isinstance(source, str) or not isinstance(source, Iterable)): - elif check_type: - raise TypeError("'secrets' must be mapping, or list of items") - - # parse into final dict, normalizing contents - return dict(self._parse_secret_pair(tag, value) - for tag, value in source) - - def _parse_secret_pair(self, tag, value): - if isinstance(tag, native_string_types): - pass - elif isinstance(tag, int): - tag = str(tag) - else: - raise TypeError("tag must be unicode/string: %r" % (tag,)) - if not _tag_re.match(tag): - raise ValueError("tag contains invalid characters: %r" % (tag,)) - if not isinstance(value, bytes): - value = to_bytes(value, param="secret %r" % (tag,)) - if not value: - raise ValueError("tag contains empty secret: %r" % (tag,)) - return tag, value - - #======================================================================== - # accessing secrets - #======================================================================== - - @property - def has_secrets(self): - """whether at least one application secret is present""" - return self.default_tag is not None - - def get_secret(self, tag): - """ - resolve a secret tag to the secret (as bytes). - throws a KeyError if not found. - """ - secrets = self._secrets - if not secrets: - raise KeyError("no application secrets configured") - try: - return secrets[tag] - except KeyError: - raise suppress_cause(KeyError("unknown secret tag: %r" % (tag,))) - - #======================================================================== - # encrypted key helpers -- used internally by TOTP - #======================================================================== - - @staticmethod - def _cipher_aes_key(value, secret, salt, cost, decrypt=False): - """ - Internal helper for :meth:`encrypt_key` -- - handles lowlevel encryption/decryption. - - Algorithm details: - - This function uses PBKDF2-HMAC-SHA256 to generate a 32-byte AES key - and a 16-byte IV from the application secret & random salt. - It then uses AES-256-CTR to encrypt/decrypt the TOTP key. - - CTR mode was chosen over CBC because the main attack scenario here - is that the attacker has stolen the database, and is trying to decrypt a TOTP key - (the plaintext value here). To make it hard for them, we want every password - to decrypt to a potentially valid key -- thus need to avoid any authentication - or padding oracle attacks. While some random padding construction could be devised - to make this work for CBC mode, a stream cipher mode is just plain simpler. - OFB/CFB modes would also work here, but seeing as they have malleability - and cyclic issues (though remote and barely relevant here), - CTR was picked as the best overall choice. - """ - # make sure backend AES support is available - if _cg_ciphers is None: - raise RuntimeError("TOTP encryption requires 'cryptography' package " - "(https://cryptography.io)") - - # use pbkdf2 to derive both key (32 bytes) & iv (16 bytes) - # NOTE: this requires 2 sha256 blocks to be calculated. - keyiv = pbkdf2_hmac("sha256", secret, salt=salt, rounds=(1 << cost), keylen=48) - - # use AES-256-CTR to encrypt/decrypt input value - cipher = _cg_ciphers.Cipher(_cg_ciphers.algorithms.AES(keyiv[:32]), - _cg_ciphers.modes.CTR(keyiv[32:]), - _cg_default_backend()) - ctx = cipher.decryptor() if decrypt else cipher.encryptor() - return ctx.update(value) + ctx.finalize() - - def encrypt_key(self, key): - """ - Helper used to encrypt TOTP keys for storage. - - :param key: - TOTP key to encrypt, as raw bytes. - - :returns: - dict containing encrypted TOTP key & configuration parameters. - this format should be treated as opaque, and potentially subject - to change, though it is designed to be easily serialized/deserialized - (e.g. via JSON). - - .. note:: - - This function requires installation of the external - `cryptography `_ package. - - To give some algorithm details: This function uses AES-256-CTR to encrypt - the provided data. It takes the application secret and randomly generated salt, - and uses PBKDF2-HMAC-SHA256 to combine them and generate the AES key & IV. - """ - if not key: - raise ValueError("no key provided") - salt = getrandbytes(rng, self.salt_size) - cost = self.encrypt_cost - tag = self.default_tag - if not tag: - raise TypeError("no application secrets configured, can't encrypt OTP key") - ckey = self._cipher_aes_key(key, self.get_secret(tag), salt, cost) - # XXX: switch to base64? - return dict(v=1, c=cost, t=tag, s=b32encode(salt), k=b32encode(ckey)) - - def decrypt_key(self, enckey): - """ - Helper used to decrypt TOTP keys from storage format. - Consults configured secrets to decrypt key. - - :param source: - source object, as returned by :meth:`encrypt_key`. - - :returns: - ``(key, needs_recrypt)`` -- - - **key** will be the decrypted key, as bytes. - - **needs_recrypt** will be a boolean flag indicating - whether encryption cost or default tag is too old, - and henace that key needs re-encrypting before storing. - - .. note:: - - This function requires installation of the external - `cryptography `_ package. - """ - if not isinstance(enckey, dict): - raise TypeError("'enckey' must be dictionary") - version = enckey.get("v", None) - needs_recrypt = False - if version == 1: - _cipher_key = self._cipher_aes_key - else: - raise ValueError("missing / unrecognized 'enckey' version: %r" % (version,)) - tag = enckey['t'] - cost = enckey['c'] - key = _cipher_key( - value=b32decode(enckey['k']), - secret=self.get_secret(tag), - salt=b32decode(enckey['s']), - cost=cost, - ) - if cost != self.encrypt_cost or tag != self.default_tag: - needs_recrypt = True - return key, needs_recrypt - - #============================================================================= - # eoc - #============================================================================= - -#============================================================================= -# TOTP class -#============================================================================= - -#: helper to convert HOTP counter to bytes -_pack_uint64 = struct.Struct(">Q").pack - -#: helper to extract value from HOTP digest -_unpack_uint32 = struct.Struct(">I").unpack - -#: dummy bytes used as temp key for .using() method -_DUMMY_KEY = b"\x00" * 16 - -class TOTP(object): - """ - Helper for generating and verifying TOTP codes. - - Given a secret key and set of configuration options, this object - offers methods for token generation, token validation, and serialization. - It can also be used to track important persistent TOTP state, - such as the last counter used. - - This class accepts the following options - (only **key** and **format** may be specified as positional arguments). - - :arg str key: - The secret key to use. By default, should be encoded as - a base32 string (see **format** for other encodings). - - Exactly one of **key** or ``new=True`` must be specified. - - :arg str format: - The encoding used by the **key** parameter. May be one of: - ``"base32"`` (base32-encoded string), - ``"hex"`` (hexadecimal string), or ``"raw"`` (raw bytes). - Defaults to ``"base32"``. - - :param bool new: - If ``True``, a new key will be generated using :class:`random.SystemRandom`. - - Exactly one ``new=True`` or **key** must be specified. - - :param str label: - Label to associate with this token when generating a URI. - Displayed to user by most OTP client applications (e.g. Google Authenticator), - and typically has format such as ``"John Smith"`` or ``"jsmith@webservice.example.org"``. - Defaults to ``None``. - See :meth:`to_uri` for details. - - :param str issuer: - String identifying the token issuer (e.g. the domain name of your service). - Used internally by some OTP client applications (e.g. Google Authenticator) to distinguish entries - which otherwise have the same label. - Optional but strongly recommended if you're rendering to a URI. - Defaults to ``None``. - See :meth:`to_uri` for details. - - :param int size: - Number of bytes when generating new keys. Defaults to size of hash algorithm (e.g. 20 for SHA1). - - .. warning:: - - Overriding the default values for ``digits``, ``period``, or ``alg`` may - cause problems with some OTP client programs (such as Google Authenticator), - which may have these defaults hardcoded. - - :param int digits: - The number of digits in the generated / accepted tokens. Defaults to ``6``. - Must be in range [6 .. 10]. - - .. rst-class:: inline-title - .. caution:: - Due to a limitation of the HOTP algorithm, the 10th digit can only take on values 0 .. 2, - and thus offers very little extra security. - - :param str alg: - Name of hash algorithm to use. Defaults to ``"sha1"``. - ``"sha256"`` and ``"sha512"`` are also accepted, per :rfc:`6238`. - - :param int period: - The time-step period to use, in integer seconds. Defaults to ``30``. - - .. - See the passlib documentation for a full list of attributes & methods. - """ - #============================================================================= - # class attrs - #============================================================================= - - #: minimum number of bytes to allow in key, enforced by passlib. - # XXX: see if spec says anything relevant to this. - _min_key_size = 10 - - #: minimum & current serialization version (may be set independently by subclasses) - min_json_version = json_version = 1 - - #: AppWallet that this class will use for encrypting/decrypting keys. - #: (can be overwritten via the :meth:`TOTP.using()` constructor) - wallet = None - - #: function to get system time in seconds, as needed by :meth:`generate` and :meth:`verify`. - #: defaults to :func:`time.time`, but can be overridden on a per-instance basis. - now = _time.time - - #============================================================================= - # instance attrs - #============================================================================= - - #--------------------------------------------------------------------------- - # configuration attrs - #--------------------------------------------------------------------------- - - #: [private] secret key as raw :class:`!bytes` - #: see .key property for public access. - _key = None - - #: [private] cached copy of encrypted secret, - #: so .to_json() doesn't have to re-encrypt on each call. - _encrypted_key = None - - #: [private] cached copy of keyed HMAC function, - #: so ._generate() doesn't have to rebuild this each time - #: ._find_match() invokes it. - _keyed_hmac = None - - #: number of digits in the generated tokens. - digits = 6 - - #: name of hash algorithm in use (e.g. ``"sha1"``) - alg = "sha1" - - #: default label for :meth:`to_uri` - label = None - - #: default issuer for :meth:`to_uri` - issuer = None - - #: number of seconds per counter step. - #: *(TOTP uses an internal time-derived counter which - #: increments by 1 every* :attr:`!period` *seconds)*. - period = 30 - - #--------------------------------------------------------------------------- - # state attrs - #--------------------------------------------------------------------------- - - #: Flag set by deserialization methods to indicate the object needs to be re-serialized. - #: This can be for a number of reasons -- encoded using deprecated format, - #: or encrypted using a deprecated key or too few rounds. - changed = False - - #============================================================================= - # prototype construction - #============================================================================= - @classmethod - def using(cls, digits=None, alg=None, period=None, - issuer=None, wallet=None, now=None, **kwds): - """ - Dynamically create subtype of :class:`!TOTP` class - which has the specified defaults set. - - :parameters: **digits, alg, period, issuer**: - - All these options are the same as in the :class:`TOTP` constructor, - and the resulting class will use any values you specify here - as the default for all TOTP instances it creates. - - :param wallet: - Optional :class:`AppWallet` that will be used for encrypting/decrypting keys. - - :param secrets, secrets_path, encrypt_cost: - - If specified, these options will be passed to the :class:`AppWallet` constructor, - allowing you to directly specify the secret keys that should be used - to encrypt & decrypt stored keys. - - :returns: - subclass of :class:`!TOTP`. - - This method is useful for creating a TOTP class configured - to use your application's secrets for encrypting & decrypting - keys, as well as create new keys using it's desired configuration defaults. - - As an example:: - - >>> # your application can create a custom class when it initializes - >>> from passlib.totp import TOTP, generate_secret - >>> TotpFactory = TOTP.using(secrets={"1": generate_secret()}) - - >>> # subsequent TOTP objects created from this factory - >>> # will use the specified secrets to encrypt their keys... - >>> totp = TotpFactory.new() - >>> totp.to_dict() - {'enckey': {'c': 14, - 'k': 'H77SYXWORDPGVOQTFRR2HFUB3C45XXI7', - 's': 'G5DOQPIHIBUM2OOHHADQ', - 't': '1', - 'v': 1}, - 'type': 'totp', - 'v': 1} - - .. seealso:: :ref:`totp-creation` and :ref:`totp-storing-instances` tutorials for a usage example - """ - # XXX: could add support for setting default match 'window' and 'reuse' policy - - # :param now: - # Optional callable that should return current time for generator to use. - # Default to :func:`time.time`. This optional is generally not needed, - # and is mainly present for examples & unit-testing. - - subcls = type("TOTP", (cls,), {}) - - def norm_param(attr, value): - """ - helper which uses constructor to validate parameter value. - it returns corresponding attribute, so we use normalized value. - """ - # NOTE: this creates *subclass* instance, - # so normalization takes into account any custom params - # already stored. - kwds = dict(key=_DUMMY_KEY, format="raw") - kwds[attr] = value - obj = subcls(**kwds) - return getattr(obj, attr) - - if digits is not None: - subcls.digits = norm_param("digits", digits) - - if alg is not None: - subcls.alg = norm_param("alg", alg) - - if period is not None: - subcls.period = norm_param("period", period) - - # XXX: add default size as configurable parameter? - - if issuer is not None: - subcls.issuer = norm_param("issuer", issuer) - - if kwds: - subcls.wallet = AppWallet(**kwds) - if wallet: - raise TypeError("'wallet' and 'secrets' keywords are mutually exclusive") - elif wallet is not None: - if not isinstance(wallet, AppWallet): - raise exc.ExpectedTypeError(wallet, AppWallet, "wallet") - subcls.wallet = wallet - - if now is not None: - assert isinstance(now(), num_types) and now() >= 0, \ - "now() function must return non-negative int/float" - subcls.now = staticmethod(now) - - return subcls - - #============================================================================= - # init - #============================================================================= - - @classmethod - def new(cls, **kwds): - """ - convenience alias for creating new TOTP key, same as ``TOTP(new=True)`` - """ - return cls(new=True, **kwds) - - def __init__(self, key=None, format="base32", - # keyword only... - new=False, digits=None, alg=None, size=None, period=None, - label=None, issuer=None, changed=False, - **kwds): - super(TOTP, self).__init__(**kwds) - if changed: - self.changed = changed - - # validate & normalize alg - info = lookup_hash(alg or self.alg) - self.alg = info.name - digest_size = info.digest_size - if digest_size < 4: - raise RuntimeError("%r hash digest too small" % alg) - - # parse or generate new key - if new: - # generate new key - if key: - raise TypeError("'key' and 'new=True' are mutually exclusive") - if size is None: - # default to digest size, per RFC 6238 Section 5.1 - size = digest_size - elif size > digest_size: - # not forbidden by spec, but would just be wasted bytes. - # maybe just warn about this? - raise ValueError("'size' should be less than digest size " - "(%d)" % digest_size) - self.key = getrandbytes(rng, size) - elif not key: - raise TypeError("must specify either an existing 'key', or 'new=True'") - elif format == "encrypted": - # NOTE: this handles decrypting & setting '.key' - self.encrypted_key = key - elif key: - # use existing key, encoded using specified - self.key = _decode_bytes(key, format) - - # enforce min key size - if len(self.key) < self._min_key_size: - # only making this fatal for new=True, - # so that existing (but ridiculously small) keys can still be used. - msg = "for security purposes, secret key must be >= %d bytes" % self._min_key_size - if new: - raise ValueError(msg) - else: - warn(msg, exc.PasslibSecurityWarning, stacklevel=1) - - # validate digits - if digits is None: - digits = self.digits - if not isinstance(digits, int_types): - raise TypeError("digits must be an integer, not a %r" % type(digits)) - if digits < 6 or digits > 10: - raise ValueError("digits must in range(6,11)") - self.digits = digits - - # validate label - if label: - self._check_label(label) - self.label = label - - # validate issuer - if issuer: - self._check_issuer(issuer) - self.issuer = issuer - - # init period - if period is not None: - self._check_serial(period, "period", minval=1) - self.period = period - - #============================================================================= - # helpers to verify value types & ranges - #============================================================================= - - @staticmethod - def _check_serial(value, param, minval=0): - """ - check that serial value (e.g. 'counter') is non-negative integer - """ - if not isinstance(value, int_types): - raise exc.ExpectedTypeError(value, "int", param) - if value < minval: - raise ValueError("%s must be >= %d" % (param, minval)) - - @staticmethod - def _check_label(label): - """ - check that label doesn't contain chars forbidden by KeyURI spec - """ - if label and ":" in label: - raise ValueError("label may not contain ':'") - - @staticmethod - def _check_issuer(issuer): - """ - check that issuer doesn't contain chars forbidden by KeyURI spec - """ - if issuer and ":" in issuer: - raise ValueError("issuer may not contain ':'") - - #============================================================================= - # key attributes - #============================================================================= - - #------------------------------------------------------------------ - # raw key - #------------------------------------------------------------------ - @property - def key(self): - """ - secret key as raw bytes - """ - return self._key - - @key.setter - def key(self, value): - # set key - if not isinstance(value, bytes): - raise exc.ExpectedTypeError(value, bytes, "key") - self._key = value - - # clear cached properties derived from key - self._encrypted_key = self._keyed_hmac = None - - #------------------------------------------------------------------ - # encrypted key - #------------------------------------------------------------------ - @property - def encrypted_key(self): - """ - secret key, encrypted using application secret. - this match the output of :meth:`AppWallet.encrypt_key`, - and should be treated as an opaque json serializable object. - """ - enckey = self._encrypted_key - if enckey is None: - wallet = self.wallet - if not wallet: - raise TypeError("no application secrets present, can't encrypt TOTP key") - enckey = self._encrypted_key = wallet.encrypt_key(self.key) - return enckey - - @encrypted_key.setter - def encrypted_key(self, value): - wallet = self.wallet - if not wallet: - raise TypeError("no application secrets present, can't decrypt TOTP key") - self.key, needs_recrypt = wallet.decrypt_key(value) - if needs_recrypt: - # mark as changed so it gets re-encrypted & written to db - self.changed = True - else: - # cache encrypted key for re-use - self._encrypted_key = value - - #------------------------------------------------------------------ - # pretty-printed / encoded key helpers - #------------------------------------------------------------------ - - @property - def hex_key(self): - """ - secret key encoded as hexadecimal string - """ - return bascii_to_str(base64.b16encode(self.key)).lower() - - @property - def base32_key(self): - """ - secret key encoded as base32 string - """ - return b32encode(self.key) - - def pretty_key(self, format="base32", sep="-"): - """ - pretty-print the secret key. - - This is mainly useful for situations where the user cannot get the qrcode to work, - and must enter the key manually into their TOTP client. It tries to format - the key in a manner that is easier for humans to read. - - :param format: - format to output secret key. ``"hex"`` and ``"base32"`` are both accepted. - - :param sep: - separator to insert to break up key visually. - can be any of ``"-"`` (the default), ``" "``, or ``False`` (no separator). - - :return: - key as native string. - - Usage example:: - - >>> t = TOTP('s3jdvb7qd2r7jpxx') - >>> t.pretty_key() - 'S3JD-VB7Q-D2R7-JPXX' - """ - if format == "hex" or format == "base16": - key = self.hex_key - elif format == "base32": - key = self.base32_key - else: - raise ValueError("unknown byte-encoding format: %r" % (format,)) - if sep: - key = group_string(key, sep) - return key - - #============================================================================= - # time & token parsing - #============================================================================= - - @classmethod - def normalize_time(cls, time): - """ - Normalize time value to unix epoch seconds. - - :arg time: - Can be ``None``, :class:`!datetime`, - or unix epoch timestamp as :class:`!float` or :class:`!int`. - If ``None``, uses current system time. - Naive datetimes are treated as UTC. - - :returns: - unix epoch timestamp as :class:`int`. - """ - if isinstance(time, int_types): - return time - elif isinstance(time, float): - return int(time) - elif time is None: - return int(cls.now()) - elif hasattr(time, "utctimetuple"): - # coerce datetime to UTC timestamp - # NOTE: utctimetuple() assumes naive datetimes are in UTC - # NOTE: we explicitly *don't* want microseconds. - return calendar.timegm(time.utctimetuple()) - else: - raise exc.ExpectedTypeError(time, "int, float, or datetime", "time") - - def _time_to_counter(self, time): - """ - convert timestamp to HOTP counter using :attr:`period`. - """ - return time // self.period - - def _counter_to_time(self, counter): - """ - convert HOTP counter to timestamp using :attr:`period`. - """ - return counter * self.period - - @hybrid_method - def normalize_token(self_or_cls, token): - """ - Normalize OTP token representation: - strips whitespace, converts integers to a zero-padded string, - validates token content & number of digits. - - This is a hybrid method -- it can be called at the class level, - as ``TOTP.normalize_token()``, or the instance level as ``TOTP().normalize_token()``. - It will normalize to the instance-specific number of :attr:`~TOTP.digits`, - or use the class default. - - :arg token: - token as ascii bytes, unicode, or an integer. - - :raises ValueError: - if token has wrong number of digits, or contains non-numeric characters. - - :returns: - token as :class:`!unicode` string, containing only digits 0-9. - """ - digits = self_or_cls.digits - if isinstance(token, int_types): - token = u("%0*d") % (digits, token) - else: - token = to_unicode(token, param="token") - token = _clean_re.sub(u(""), token) - if not token.isdigit(): - raise MalformedTokenError("Token must contain only the digits 0-9") - if len(token) != digits: - raise MalformedTokenError("Token must have exactly %d digits" % digits) - return token - - #============================================================================= - # token generation - #============================================================================= - -# # debug helper -# def generate_range(self, size, time=None): -# counter = self._time_to_counter(time) - (size + 1) // 2 -# end = counter + size -# while counter <= end: -# token = self._generate(counter) -# yield TotpToken(self, token, counter) -# counter += 1 - - def generate(self, time=None): - """ - Generate token for specified time - (uses current time if none specified). - - :arg time: - Can be ``None``, a :class:`!datetime`, - or class:`!float` / :class:`!int` unix epoch timestamp. - If ``None`` (the default), uses current system time. - Naive datetimes are treated as UTC. - - :returns: - - A :class:`TotpToken` instance, which can be treated - as a sequence of ``(token, expire_time)`` -- see that class - for more details. - - Usage example:: - - >>> # generate a new token, wrapped in a TotpToken instance... - >>> otp = TOTP('s3jdvb7qd2r7jpxx') - >>> otp.generate(1419622739) - - - >>> # when you just need the token... - >>> otp.generate(1419622739).token - '897212' - """ - time = self.normalize_time(time) - counter = self._time_to_counter(time) - if counter < 0: - raise ValueError("timestamp must be >= 0") - token = self._generate(counter) - return TotpToken(self, token, counter) - - def _generate(self, counter): - """ - base implementation of HOTP token generation algorithm. - - :arg counter: HOTP counter, as non-negative integer - :returns: token as unicode string - """ - # generate digest - assert isinstance(counter, int_types), "counter must be integer" - assert counter >= 0, "counter must be non-negative" - keyed_hmac = self._keyed_hmac - if keyed_hmac is None: - keyed_hmac = self._keyed_hmac = compile_hmac(self.alg, self.key) - digest = keyed_hmac(_pack_uint64(counter)) - digest_size = keyed_hmac.digest_info.digest_size - assert len(digest) == digest_size, "digest_size: sanity check failed" - - # derive 31-bit token value - assert digest_size >= 20, "digest_size: sanity check 2 failed" # otherwise 0xF+4 will run off end of hash. - offset = byte_elem_value(digest[-1]) & 0xF - value = _unpack_uint32(digest[offset:offset+4])[0] & 0x7fffffff - - # render to decimal string, return last chars - # NOTE: the 10'th digit is not as secure, as it can only take on values 0-2, not 0-9, - # due to 31-bit mask on int ">I". But some servers / clients use it :| - # if 31-bit mask removed (which breaks spec), would only get values 0-4. - digits = self.digits - assert 0 < digits < 11, "digits: sanity check failed" - return (u("%0*d") % (digits, value))[-digits:] - - #============================================================================= - # token verification - #============================================================================= - - @classmethod - def verify(cls, token, source, **kwds): - r""" - Convenience wrapper around :meth:`TOTP.from_source` and :meth:`TOTP.match`. - - This parses a TOTP key & configuration from the specified source, - and tries and match the token. - It's designed to parallel the :meth:`passlib.ifc.PasswordHash.verify` method. - - :param token: - Token string to match. - - :param source: - Serialized TOTP key. - Can be anything accepted by :meth:`TOTP.from_source`. - - :param \\*\\*kwds: - All additional keywords passed to :meth:`TOTP.match`. - - :return: - A :class:`TotpMatch` instance, or raises a :exc:`TokenError`. - """ - return cls.from_source(source).match(token, **kwds) - - def match(self, token, time=None, window=30, skew=0, last_counter=None): - """ - Match TOTP token against specified timestamp. - Searches within a window before & after the provided time, - in order to account for transmission delay and small amounts of skew in the client's clock. - - :arg token: - Token to validate. - may be integer or string (whitespace and hyphens are ignored). - - :param time: - Unix epoch timestamp, can be any of :class:`!float`, :class:`!int`, or :class:`!datetime`. - if ``None`` (the default), uses current system time. - *this should correspond to the time the token was received from the client*. - - :param int window: - How far backward and forward in time to search for a match. - Measured in seconds. Defaults to ``30``. Typically only useful if set - to multiples of :attr:`period`. - - :param int skew: - Adjust timestamp by specified value, to account for excessive - client clock skew. Measured in seconds. Defaults to ``0``. - - Negative skew (the common case) indicates transmission delay, - and/or that the client clock is running behind the server. - - Positive skew indicates the client clock is running ahead of the server - (and by enough that it cancels out any negative skew added by - the transmission delay). - - You should ensure the server clock uses a reliable time source such as NTP, - so that only the client clock's inaccuracy needs to be accounted for. - - This is an advanced parameter that should usually be left at ``0``; - The **window** parameter is usually enough to account - for any observed transmission delay. - - :param last_counter: - Optional value of last counter value that was successfully used. - If specified, verify will never search earlier counters, - no matter how large the window is. - - Useful when client has previously authenticated, - and thus should never provide a token older than previously - verified value. - - :raises ~passlib.exc.TokenError: - - If the token is malformed, fails to match, or has already been used. - - :returns TotpMatch: - - Returns a :class:`TotpMatch` instance on successful match. - Can be treated as tuple of ``(counter, time)``. - Raises error if token is malformed / can't be verified. - - Usage example:: - - >>> totp = TOTP('s3jdvb7qd2r7jpxx') - - >>> # valid token for this time period - >>> totp.match('897212', 1419622729) - - - >>> # token from counter step 30 sec ago (within allowed window) - >>> totp.match('000492', 1419622729) - - - >>> # invalid token -- token from 60 sec ago (outside of window) - >>> totp.match('760389', 1419622729) - Traceback: - ... - InvalidTokenError: Token did not match - """ - time = self.normalize_time(time) - self._check_serial(window, "window") - - client_time = time + skew - if last_counter is None: - last_counter = -1 - start = max(last_counter, self._time_to_counter(client_time - window)) - end = self._time_to_counter(client_time + window) + 1 - # XXX: could pass 'expected = _time_to_counter(client_time + TRANSMISSION_DELAY)' - # to the _find_match() method, would help if window set to very large value. - - counter = self._find_match(token, start, end) - assert counter >= last_counter, "sanity check failed: counter went backward" - - if counter == last_counter: - raise UsedTokenError(expire_time=(last_counter + 1) * self.period) - - # NOTE: By returning match tied to

    `` or ```` - if completion_type: - paths = auto_complete_paths(current, completion_type) - options = [(path, 0) for path in paths] - for option in options: - opt_label = option[0] - # append '=' to options which require args - if option[1] and option[0][:2] == "--": - opt_label += "=" - print(opt_label) - else: - # show main parser options only when necessary - - opts = [i.option_list for i in parser.option_groups] - opts.append(parser.option_list) - flattened_opts = chain.from_iterable(opts) - if current.startswith("-"): - for opt in flattened_opts: - if opt.help != optparse.SUPPRESS_HELP: - subcommands += opt._long_opts + opt._short_opts - else: - # get completion type given cwords and all available options - completion_type = get_path_completion_type(cwords, cword, flattened_opts) - if completion_type: - subcommands = list(auto_complete_paths(current, completion_type)) - - print(" ".join([x for x in subcommands if x.startswith(current)])) - sys.exit(1) - - -def get_path_completion_type( - cwords: List[str], cword: int, opts: Iterable[Any] -) -> Optional[str]: - """Get the type of path completion (``file``, ``dir``, ``path`` or None) - - :param cwords: same as the environmental variable ``COMP_WORDS`` - :param cword: same as the environmental variable ``COMP_CWORD`` - :param opts: The available options to check - :return: path completion type (``file``, ``dir``, ``path`` or None) - """ - if cword < 2 or not cwords[cword - 2].startswith("-"): - return None - for opt in opts: - if opt.help == optparse.SUPPRESS_HELP: - continue - for o in str(opt).split("/"): - if cwords[cword - 2].split("=")[0] == o: - if not opt.metavar or any( - x in ("path", "file", "dir") for x in opt.metavar.split("/") - ): - return opt.metavar - return None - - -def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]: - """If ``completion_type`` is ``file`` or ``path``, list all regular files - and directories starting with ``current``; otherwise only list directories - starting with ``current``. - - :param current: The word to be completed - :param completion_type: path completion type(`file`, `path` or `dir`)i - :return: A generator of regular files and/or directories - """ - directory, filename = os.path.split(current) - current_path = os.path.abspath(directory) - # Don't complete paths if they can't be accessed - if not os.access(current_path, os.R_OK): - return - filename = os.path.normcase(filename) - # list all files that start with ``filename`` - file_list = ( - x for x in os.listdir(current_path) if os.path.normcase(x).startswith(filename) - ) - for f in file_list: - opt = os.path.join(current_path, f) - comp_file = os.path.normcase(os.path.join(directory, f)) - # complete regular files when there is not ```` after option - # complete directories when there is ````, ```` or - # ````after option - if completion_type != "dir" and os.path.isfile(opt): - yield comp_file - elif os.path.isdir(opt): - yield os.path.join(comp_file, "") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/base_command.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/base_command.py deleted file mode 100644 index eea3830..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/base_command.py +++ /dev/null @@ -1,214 +0,0 @@ -"""Base Command class, and related routines""" - -import logging -import logging.config -import optparse -import os -import sys -import traceback -from optparse import Values -from typing import Any, List, Optional, Tuple - -from pip._internal.cli import cmdoptions -from pip._internal.cli.command_context import CommandContextMixIn -from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter -from pip._internal.cli.status_codes import ( - ERROR, - PREVIOUS_BUILD_DIR_ERROR, - UNKNOWN_ERROR, - VIRTUALENV_NOT_FOUND, -) -from pip._internal.exceptions import ( - BadCommand, - CommandError, - InstallationError, - NetworkConnectionError, - PreviousBuildDirError, - UninstallationError, -) -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.filesystem import check_path_owner -from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging -from pip._internal.utils.misc import get_prog, normalize_path -from pip._internal.utils.temp_dir import TempDirectoryTypeRegistry as TempDirRegistry -from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry -from pip._internal.utils.virtualenv import running_under_virtualenv - -__all__ = ["Command"] - -logger = logging.getLogger(__name__) - - -class Command(CommandContextMixIn): - usage: str = "" - ignore_require_venv: bool = False - - def __init__(self, name: str, summary: str, isolated: bool = False) -> None: - super().__init__() - - self.name = name - self.summary = summary - self.parser = ConfigOptionParser( - usage=self.usage, - prog=f"{get_prog()} {name}", - formatter=UpdatingDefaultsHelpFormatter(), - add_help_option=False, - name=name, - description=self.__doc__, - isolated=isolated, - ) - - self.tempdir_registry: Optional[TempDirRegistry] = None - - # Commands should add options to this option group - optgroup_name = f"{self.name.capitalize()} Options" - self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) - - # Add the general options - gen_opts = cmdoptions.make_option_group( - cmdoptions.general_group, - self.parser, - ) - self.parser.add_option_group(gen_opts) - - self.add_options() - - def add_options(self) -> None: - pass - - def handle_pip_version_check(self, options: Values) -> None: - """ - This is a no-op so that commands by default do not do the pip version - check. - """ - # Make sure we do the pip version check if the index_group options - # are present. - assert not hasattr(options, "no_index") - - def run(self, options: Values, args: List[Any]) -> int: - raise NotImplementedError - - def parse_args(self, args: List[str]) -> Tuple[Any, Any]: - # factored out for testability - return self.parser.parse_args(args) - - def main(self, args: List[str]) -> int: - try: - with self.main_context(): - return self._main(args) - finally: - logging.shutdown() - - def _main(self, args: List[str]) -> int: - # We must initialize this before the tempdir manager, otherwise the - # configuration would not be accessible by the time we clean up the - # tempdir manager. - self.tempdir_registry = self.enter_context(tempdir_registry()) - # Intentionally set as early as possible so globally-managed temporary - # directories are available to the rest of the code. - self.enter_context(global_tempdir_manager()) - - options, args = self.parse_args(args) - - # Set verbosity so that it can be used elsewhere. - self.verbosity = options.verbose - options.quiet - - level_number = setup_logging( - verbosity=self.verbosity, - no_color=options.no_color, - user_log_file=options.log, - ) - - # TODO: Try to get these passing down from the command? - # without resorting to os.environ to hold these. - # This also affects isolated builds and it should. - - if options.no_input: - os.environ["PIP_NO_INPUT"] = "1" - - if options.exists_action: - os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action) - - if options.require_venv and not self.ignore_require_venv: - # If a venv is required check if it can really be found - if not running_under_virtualenv(): - logger.critical("Could not find an activated virtualenv (required).") - sys.exit(VIRTUALENV_NOT_FOUND) - - if options.cache_dir: - options.cache_dir = normalize_path(options.cache_dir) - if not check_path_owner(options.cache_dir): - logger.warning( - "The directory '%s' or its parent directory is not owned " - "or is not writable by the current user. The cache " - "has been disabled. Check the permissions and owner of " - "that directory. If executing pip with sudo, you should " - "use sudo's -H flag.", - options.cache_dir, - ) - options.cache_dir = None - - if getattr(options, "build_dir", None): - deprecated( - reason=( - "The -b/--build/--build-dir/--build-directory " - "option is deprecated and has no effect anymore." - ), - replacement=( - "use the TMPDIR/TEMP/TMP environment variable, " - "possibly combined with --no-clean" - ), - gone_in="21.3", - issue=8333, - ) - - if "2020-resolver" in options.features_enabled: - logger.warning( - "--use-feature=2020-resolver no longer has any effect, " - "since it is now the default dependency resolver in pip. " - "This will become an error in pip 21.0." - ) - - try: - status = self.run(options, args) - assert isinstance(status, int) - return status - except PreviousBuildDirError as exc: - logger.critical(str(exc)) - logger.debug("Exception information:", exc_info=True) - - return PREVIOUS_BUILD_DIR_ERROR - except ( - InstallationError, - UninstallationError, - BadCommand, - NetworkConnectionError, - ) as exc: - logger.critical(str(exc)) - logger.debug("Exception information:", exc_info=True) - - return ERROR - except CommandError as exc: - logger.critical("%s", exc) - logger.debug("Exception information:", exc_info=True) - - return ERROR - except BrokenStdoutLoggingError: - # Bypass our logger and write any remaining messages to stderr - # because stdout no longer works. - print("ERROR: Pipe to stdout was broken", file=sys.stderr) - if level_number <= logging.DEBUG: - traceback.print_exc(file=sys.stderr) - - return ERROR - except KeyboardInterrupt: - logger.critical("Operation cancelled by user") - logger.debug("Exception information:", exc_info=True) - - return ERROR - except BaseException: - logger.critical("Exception:", exc_info=True) - - return UNKNOWN_ERROR - finally: - self.handle_pip_version_check(options) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/cmdoptions.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/cmdoptions.py deleted file mode 100644 index b4f0f83..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/cmdoptions.py +++ /dev/null @@ -1,1009 +0,0 @@ -""" -shared options and groups - -The principle here is to define options once, but *not* instantiate them -globally. One reason being that options with action='append' can carry state -between parses. pip parses general options twice internally, and shouldn't -pass on state. To be consistent, all options will follow this design. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import os -import textwrap -import warnings -from functools import partial -from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values -from textwrap import dedent -from typing import Any, Callable, Dict, Optional, Tuple - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli.parser import ConfigOptionParser -from pip._internal.cli.progress_bars import BAR_TYPES -from pip._internal.exceptions import CommandError -from pip._internal.locations import USER_CACHE_DIR, get_src_prefix -from pip._internal.models.format_control import FormatControl -from pip._internal.models.index import PyPI -from pip._internal.models.target_python import TargetPython -from pip._internal.utils.hashes import STRONG_HASHES -from pip._internal.utils.misc import strtobool - - -def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None: - """ - Raise an option parsing error using parser.error(). - - Args: - parser: an OptionParser instance. - option: an Option instance. - msg: the error text. - """ - msg = f"{option} error: {msg}" - msg = textwrap.fill(" ".join(msg.split())) - parser.error(msg) - - -def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup: - """ - Return an OptionGroup object - group -- assumed to be dict with 'name' and 'options' keys - parser -- an optparse Parser - """ - option_group = OptionGroup(parser, group["name"]) - for option in group["options"]: - option_group.add_option(option()) - return option_group - - -def check_install_build_global( - options: Values, check_options: Optional[Values] = None -) -> None: - """Disable wheels if per-setup.py call options are set. - - :param options: The OptionParser options to update. - :param check_options: The options to check, if not supplied defaults to - options. - """ - if check_options is None: - check_options = options - - def getname(n: str) -> Optional[Any]: - return getattr(check_options, n, None) - - names = ["build_options", "global_options", "install_options"] - if any(map(getname, names)): - control = options.format_control - control.disallow_binaries() - warnings.warn( - "Disabling all use of wheels due to the use of --build-option " - "/ --global-option / --install-option.", - stacklevel=2, - ) - - -def check_dist_restriction(options: Values, check_target: bool = False) -> None: - """Function for determining if custom platform options are allowed. - - :param options: The OptionParser options. - :param check_target: Whether or not to check if --target is being used. - """ - dist_restriction_set = any( - [ - options.python_version, - options.platforms, - options.abis, - options.implementation, - ] - ) - - binary_only = FormatControl(set(), {":all:"}) - sdist_dependencies_allowed = ( - options.format_control != binary_only and not options.ignore_dependencies - ) - - # Installations or downloads using dist restrictions must not combine - # source distributions and dist-specific wheels, as they are not - # guaranteed to be locally compatible. - if dist_restriction_set and sdist_dependencies_allowed: - raise CommandError( - "When restricting platform and interpreter constraints using " - "--python-version, --platform, --abi, or --implementation, " - "either --no-deps must be set, or --only-binary=:all: must be " - "set and --no-binary must not be set (or must be set to " - ":none:)." - ) - - if check_target: - if dist_restriction_set and not options.target_dir: - raise CommandError( - "Can not use any platform or abi specific options unless " - "installing via '--target'" - ) - - -def _path_option_check(option: Option, opt: str, value: str) -> str: - return os.path.expanduser(value) - - -def _package_name_option_check(option: Option, opt: str, value: str) -> str: - return canonicalize_name(value) - - -class PipOption(Option): - TYPES = Option.TYPES + ("path", "package_name") - TYPE_CHECKER = Option.TYPE_CHECKER.copy() - TYPE_CHECKER["package_name"] = _package_name_option_check - TYPE_CHECKER["path"] = _path_option_check - - -########### -# options # -########### - -help_: Callable[..., Option] = partial( - Option, - "-h", - "--help", - dest="help", - action="help", - help="Show help.", -) - -isolated_mode: Callable[..., Option] = partial( - Option, - "--isolated", - dest="isolated_mode", - action="store_true", - default=False, - help=( - "Run pip in an isolated mode, ignoring environment variables and user " - "configuration." - ), -) - -require_virtualenv: Callable[..., Option] = partial( - Option, - # Run only if inside a virtualenv, bail if not. - "--require-virtualenv", - "--require-venv", - dest="require_venv", - action="store_true", - default=False, - help=SUPPRESS_HELP, -) - -verbose: Callable[..., Option] = partial( - Option, - "-v", - "--verbose", - dest="verbose", - action="count", - default=0, - help="Give more output. Option is additive, and can be used up to 3 times.", -) - -no_color: Callable[..., Option] = partial( - Option, - "--no-color", - dest="no_color", - action="store_true", - default=False, - help="Suppress colored output.", -) - -version: Callable[..., Option] = partial( - Option, - "-V", - "--version", - dest="version", - action="store_true", - help="Show version and exit.", -) - -quiet: Callable[..., Option] = partial( - Option, - "-q", - "--quiet", - dest="quiet", - action="count", - default=0, - help=( - "Give less output. Option is additive, and can be used up to 3" - " times (corresponding to WARNING, ERROR, and CRITICAL logging" - " levels)." - ), -) - -progress_bar: Callable[..., Option] = partial( - Option, - "--progress-bar", - dest="progress_bar", - type="choice", - choices=list(BAR_TYPES.keys()), - default="on", - help=( - "Specify type of progress to be displayed [" - + "|".join(BAR_TYPES.keys()) - + "] (default: %default)" - ), -) - -log: Callable[..., Option] = partial( - PipOption, - "--log", - "--log-file", - "--local-log", - dest="log", - metavar="path", - type="path", - help="Path to a verbose appending log.", -) - -no_input: Callable[..., Option] = partial( - Option, - # Don't ask for input - "--no-input", - dest="no_input", - action="store_true", - default=False, - help="Disable prompting for input.", -) - -proxy: Callable[..., Option] = partial( - Option, - "--proxy", - dest="proxy", - type="str", - default="", - help="Specify a proxy in the form [user:passwd@]proxy.server:port.", -) - -retries: Callable[..., Option] = partial( - Option, - "--retries", - dest="retries", - type="int", - default=5, - help="Maximum number of retries each connection should attempt " - "(default %default times).", -) - -timeout: Callable[..., Option] = partial( - Option, - "--timeout", - "--default-timeout", - metavar="sec", - dest="timeout", - type="float", - default=15, - help="Set the socket timeout (default %default seconds).", -) - - -def exists_action() -> Option: - return Option( - # Option when path already exist - "--exists-action", - dest="exists_action", - type="choice", - choices=["s", "i", "w", "b", "a"], - default=[], - action="append", - metavar="action", - help="Default action when a path already exists: " - "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", - ) - - -cert: Callable[..., Option] = partial( - PipOption, - "--cert", - dest="cert", - type="path", - metavar="path", - help=( - "Path to PEM-encoded CA certificate bundle. " - "If provided, overrides the default. " - "See 'SSL Certificate Verification' in pip documentation " - "for more information." - ), -) - -client_cert: Callable[..., Option] = partial( - PipOption, - "--client-cert", - dest="client_cert", - type="path", - default=None, - metavar="path", - help="Path to SSL client certificate, a single file containing the " - "private key and the certificate in PEM format.", -) - -index_url: Callable[..., Option] = partial( - Option, - "-i", - "--index-url", - "--pypi-url", - dest="index_url", - metavar="URL", - default=PyPI.simple_url, - help="Base URL of the Python Package Index (default %default). " - "This should point to a repository compliant with PEP 503 " - "(the simple repository API) or a local directory laid out " - "in the same format.", -) - - -def extra_index_url() -> Option: - return Option( - "--extra-index-url", - dest="extra_index_urls", - metavar="URL", - action="append", - default=[], - help="Extra URLs of package indexes to use in addition to " - "--index-url. Should follow the same rules as " - "--index-url.", - ) - - -no_index: Callable[..., Option] = partial( - Option, - "--no-index", - dest="no_index", - action="store_true", - default=False, - help="Ignore package index (only looking at --find-links URLs instead).", -) - - -def find_links() -> Option: - return Option( - "-f", - "--find-links", - dest="find_links", - action="append", - default=[], - metavar="url", - help="If a URL or path to an html file, then parse for links to " - "archives such as sdist (.tar.gz) or wheel (.whl) files. " - "If a local path or file:// URL that's a directory, " - "then look for archives in the directory listing. " - "Links to VCS project URLs are not supported.", - ) - - -def trusted_host() -> Option: - return Option( - "--trusted-host", - dest="trusted_hosts", - action="append", - metavar="HOSTNAME", - default=[], - help="Mark this host or host:port pair as trusted, even though it " - "does not have valid or any HTTPS.", - ) - - -def constraints() -> Option: - return Option( - "-c", - "--constraint", - dest="constraints", - action="append", - default=[], - metavar="file", - help="Constrain versions using the given constraints file. " - "This option can be used multiple times.", - ) - - -def requirements() -> Option: - return Option( - "-r", - "--requirement", - dest="requirements", - action="append", - default=[], - metavar="file", - help="Install from the given requirements file. " - "This option can be used multiple times.", - ) - - -def editable() -> Option: - return Option( - "-e", - "--editable", - dest="editables", - action="append", - default=[], - metavar="path/url", - help=( - "Install a project in editable mode (i.e. setuptools " - '"develop mode") from a local project path or a VCS url.' - ), - ) - - -def _handle_src(option: Option, opt_str: str, value: str, parser: OptionParser) -> None: - value = os.path.abspath(value) - setattr(parser.values, option.dest, value) - - -src: Callable[..., Option] = partial( - PipOption, - "--src", - "--source", - "--source-dir", - "--source-directory", - dest="src_dir", - type="path", - metavar="dir", - default=get_src_prefix(), - action="callback", - callback=_handle_src, - help="Directory to check out editable projects into. " - 'The default in a virtualenv is "/src". ' - 'The default for global installs is "/src".', -) - - -def _get_format_control(values: Values, option: Option) -> Any: - """Get a format_control object.""" - return getattr(values, option.dest) - - -def _handle_no_binary( - option: Option, opt_str: str, value: str, parser: OptionParser -) -> None: - existing = _get_format_control(parser.values, option) - FormatControl.handle_mutual_excludes( - value, - existing.no_binary, - existing.only_binary, - ) - - -def _handle_only_binary( - option: Option, opt_str: str, value: str, parser: OptionParser -) -> None: - existing = _get_format_control(parser.values, option) - FormatControl.handle_mutual_excludes( - value, - existing.only_binary, - existing.no_binary, - ) - - -def no_binary() -> Option: - format_control = FormatControl(set(), set()) - return Option( - "--no-binary", - dest="format_control", - action="callback", - callback=_handle_no_binary, - type="str", - default=format_control, - help="Do not use binary packages. Can be supplied multiple times, and " - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all binary packages, ":none:" to empty the set (notice ' - "the colons), or one or more package names with commas between " - "them (no colons). Note that some packages are tricky to compile " - "and may fail to install when this option is used on them.", - ) - - -def only_binary() -> Option: - format_control = FormatControl(set(), set()) - return Option( - "--only-binary", - dest="format_control", - action="callback", - callback=_handle_only_binary, - type="str", - default=format_control, - help="Do not use source packages. Can be supplied multiple times, and " - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all source packages, ":none:" to empty the set, or one ' - "or more package names with commas between them. Packages " - "without binary distributions will fail to install when this " - "option is used on them.", - ) - - -platforms: Callable[..., Option] = partial( - Option, - "--platform", - dest="platforms", - metavar="platform", - action="append", - default=None, - help=( - "Only use wheels compatible with . Defaults to the " - "platform of the running system. Use this option multiple times to " - "specify multiple platforms supported by the target interpreter." - ), -) - - -# This was made a separate function for unit-testing purposes. -def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]: - """ - Convert a version string like "3", "37", or "3.7.3" into a tuple of ints. - - :return: A 2-tuple (version_info, error_msg), where `error_msg` is - non-None if and only if there was a parsing error. - """ - if not value: - # The empty string is the same as not providing a value. - return (None, None) - - parts = value.split(".") - if len(parts) > 3: - return ((), "at most three version parts are allowed") - - if len(parts) == 1: - # Then we are in the case of "3" or "37". - value = parts[0] - if len(value) > 1: - parts = [value[0], value[1:]] - - try: - version_info = tuple(int(part) for part in parts) - except ValueError: - return ((), "each version part must be an integer") - - return (version_info, None) - - -def _handle_python_version( - option: Option, opt_str: str, value: str, parser: OptionParser -) -> None: - """ - Handle a provided --python-version value. - """ - version_info, error_msg = _convert_python_version(value) - if error_msg is not None: - msg = "invalid --python-version value: {!r}: {}".format( - value, - error_msg, - ) - raise_option_error(parser, option=option, msg=msg) - - parser.values.python_version = version_info - - -python_version: Callable[..., Option] = partial( - Option, - "--python-version", - dest="python_version", - metavar="python_version", - action="callback", - callback=_handle_python_version, - type="str", - default=None, - help=dedent( - """\ - The Python interpreter version to use for wheel and "Requires-Python" - compatibility checks. Defaults to a version derived from the running - interpreter. The version can be specified using up to three dot-separated - integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor - version can also be given as a string without dots (e.g. "37" for 3.7.0). - """ - ), -) - - -implementation: Callable[..., Option] = partial( - Option, - "--implementation", - dest="implementation", - metavar="implementation", - default=None, - help=( - "Only use wheels compatible with Python " - "implementation , e.g. 'pp', 'jy', 'cp', " - " or 'ip'. If not specified, then the current " - "interpreter implementation is used. Use 'py' to force " - "implementation-agnostic wheels." - ), -) - - -abis: Callable[..., Option] = partial( - Option, - "--abi", - dest="abis", - metavar="abi", - action="append", - default=None, - help=( - "Only use wheels compatible with Python abi , e.g. 'pypy_41'. " - "If not specified, then the current interpreter abi tag is used. " - "Use this option multiple times to specify multiple abis supported " - "by the target interpreter. Generally you will need to specify " - "--implementation, --platform, and --python-version when using this " - "option." - ), -) - - -def add_target_python_options(cmd_opts: OptionGroup) -> None: - cmd_opts.add_option(platforms()) - cmd_opts.add_option(python_version()) - cmd_opts.add_option(implementation()) - cmd_opts.add_option(abis()) - - -def make_target_python(options: Values) -> TargetPython: - target_python = TargetPython( - platforms=options.platforms, - py_version_info=options.python_version, - abis=options.abis, - implementation=options.implementation, - ) - - return target_python - - -def prefer_binary() -> Option: - return Option( - "--prefer-binary", - dest="prefer_binary", - action="store_true", - default=False, - help="Prefer older binary packages over newer source packages.", - ) - - -cache_dir: Callable[..., Option] = partial( - PipOption, - "--cache-dir", - dest="cache_dir", - default=USER_CACHE_DIR, - metavar="dir", - type="path", - help="Store the cache data in .", -) - - -def _handle_no_cache_dir( - option: Option, opt: str, value: str, parser: OptionParser -) -> None: - """ - Process a value provided for the --no-cache-dir option. - - This is an optparse.Option callback for the --no-cache-dir option. - """ - # The value argument will be None if --no-cache-dir is passed via the - # command-line, since the option doesn't accept arguments. However, - # the value can be non-None if the option is triggered e.g. by an - # environment variable, like PIP_NO_CACHE_DIR=true. - if value is not None: - # Then parse the string value to get argument error-checking. - try: - strtobool(value) - except ValueError as exc: - raise_option_error(parser, option=option, msg=str(exc)) - - # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool() - # converted to 0 (like "false" or "no") caused cache_dir to be disabled - # rather than enabled (logic would say the latter). Thus, we disable - # the cache directory not just on values that parse to True, but (for - # backwards compatibility reasons) also on values that parse to False. - # In other words, always set it to False if the option is provided in - # some (valid) form. - parser.values.cache_dir = False - - -no_cache: Callable[..., Option] = partial( - Option, - "--no-cache-dir", - dest="cache_dir", - action="callback", - callback=_handle_no_cache_dir, - help="Disable the cache.", -) - -no_deps: Callable[..., Option] = partial( - Option, - "--no-deps", - "--no-dependencies", - dest="ignore_dependencies", - action="store_true", - default=False, - help="Don't install package dependencies.", -) - -build_dir: Callable[..., Option] = partial( - PipOption, - "-b", - "--build", - "--build-dir", - "--build-directory", - dest="build_dir", - type="path", - metavar="dir", - help=SUPPRESS_HELP, -) - -ignore_requires_python: Callable[..., Option] = partial( - Option, - "--ignore-requires-python", - dest="ignore_requires_python", - action="store_true", - help="Ignore the Requires-Python information.", -) - -no_build_isolation: Callable[..., Option] = partial( - Option, - "--no-build-isolation", - dest="build_isolation", - action="store_false", - default=True, - help="Disable isolation when building a modern source distribution. " - "Build dependencies specified by PEP 518 must be already installed " - "if this option is used.", -) - - -def _handle_no_use_pep517( - option: Option, opt: str, value: str, parser: OptionParser -) -> None: - """ - Process a value provided for the --no-use-pep517 option. - - This is an optparse.Option callback for the no_use_pep517 option. - """ - # Since --no-use-pep517 doesn't accept arguments, the value argument - # will be None if --no-use-pep517 is passed via the command-line. - # However, the value can be non-None if the option is triggered e.g. - # by an environment variable, for example "PIP_NO_USE_PEP517=true". - if value is not None: - msg = """A value was passed for --no-use-pep517, - probably using either the PIP_NO_USE_PEP517 environment variable - or the "no-use-pep517" config file option. Use an appropriate value - of the PIP_USE_PEP517 environment variable or the "use-pep517" - config file option instead. - """ - raise_option_error(parser, option=option, msg=msg) - - # Otherwise, --no-use-pep517 was passed via the command-line. - parser.values.use_pep517 = False - - -use_pep517: Any = partial( - Option, - "--use-pep517", - dest="use_pep517", - action="store_true", - default=None, - help="Use PEP 517 for building source distributions " - "(use --no-use-pep517 to force legacy behaviour).", -) - -no_use_pep517: Any = partial( - Option, - "--no-use-pep517", - dest="use_pep517", - action="callback", - callback=_handle_no_use_pep517, - default=None, - help=SUPPRESS_HELP, -) - -install_options: Callable[..., Option] = partial( - Option, - "--install-option", - dest="install_options", - action="append", - metavar="options", - help="Extra arguments to be supplied to the setup.py install " - 'command (use like --install-option="--install-scripts=/usr/local/' - 'bin"). Use multiple --install-option options to pass multiple ' - "options to setup.py install. If you are using an option with a " - "directory path, be sure to use absolute path.", -) - -build_options: Callable[..., Option] = partial( - Option, - "--build-option", - dest="build_options", - metavar="options", - action="append", - help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", -) - -global_options: Callable[..., Option] = partial( - Option, - "--global-option", - dest="global_options", - action="append", - metavar="options", - help="Extra global options to be supplied to the setup.py " - "call before the install or bdist_wheel command.", -) - -no_clean: Callable[..., Option] = partial( - Option, - "--no-clean", - action="store_true", - default=False, - help="Don't clean up build directories.", -) - -pre: Callable[..., Option] = partial( - Option, - "--pre", - action="store_true", - default=False, - help="Include pre-release and development versions. By default, " - "pip only finds stable versions.", -) - -disable_pip_version_check: Callable[..., Option] = partial( - Option, - "--disable-pip-version-check", - dest="disable_pip_version_check", - action="store_true", - default=False, - help="Don't periodically check PyPI to determine whether a new version " - "of pip is available for download. Implied with --no-index.", -) - - -def _handle_merge_hash( - option: Option, opt_str: str, value: str, parser: OptionParser -) -> None: - """Given a value spelled "algo:digest", append the digest to a list - pointed to in a dict by the algo name.""" - if not parser.values.hashes: - parser.values.hashes = {} - try: - algo, digest = value.split(":", 1) - except ValueError: - parser.error( - "Arguments to {} must be a hash name " # noqa - "followed by a value, like --hash=sha256:" - "abcde...".format(opt_str) - ) - if algo not in STRONG_HASHES: - parser.error( - "Allowed hash algorithms for {} are {}.".format( # noqa - opt_str, ", ".join(STRONG_HASHES) - ) - ) - parser.values.hashes.setdefault(algo, []).append(digest) - - -hash: Callable[..., Option] = partial( - Option, - "--hash", - # Hash values eventually end up in InstallRequirement.hashes due to - # __dict__ copying in process_line(). - dest="hashes", - action="callback", - callback=_handle_merge_hash, - type="string", - help="Verify that the package's archive matches this " - "hash before installing. Example: --hash=sha256:abcdef...", -) - - -require_hashes: Callable[..., Option] = partial( - Option, - "--require-hashes", - dest="require_hashes", - action="store_true", - default=False, - help="Require a hash to check each requirement against, for " - "repeatable installs. This option is implied when any package in a " - "requirements file has a --hash option.", -) - - -list_path: Callable[..., Option] = partial( - PipOption, - "--path", - dest="path", - type="path", - action="append", - help="Restrict to the specified installation path for listing " - "packages (can be used multiple times).", -) - - -def check_list_path_option(options: Values) -> None: - if options.path and (options.user or options.local): - raise CommandError("Cannot combine '--path' with '--user' or '--local'") - - -list_exclude: Callable[..., Option] = partial( - PipOption, - "--exclude", - dest="excludes", - action="append", - metavar="package", - type="package_name", - help="Exclude specified package from the output", -) - - -no_python_version_warning: Callable[..., Option] = partial( - Option, - "--no-python-version-warning", - dest="no_python_version_warning", - action="store_true", - default=False, - help="Silence deprecation warnings for upcoming unsupported Pythons.", -) - - -use_new_feature: Callable[..., Option] = partial( - Option, - "--use-feature", - dest="features_enabled", - metavar="feature", - action="append", - default=[], - choices=["2020-resolver", "fast-deps", "in-tree-build"], - help="Enable new functionality, that may be backward incompatible.", -) - -use_deprecated_feature: Callable[..., Option] = partial( - Option, - "--use-deprecated", - dest="deprecated_features_enabled", - metavar="feature", - action="append", - default=[], - choices=["legacy-resolver"], - help=("Enable deprecated functionality, that will be removed in the future."), -) - - -########## -# groups # -########## - -general_group: Dict[str, Any] = { - "name": "General Options", - "options": [ - help_, - isolated_mode, - require_virtualenv, - verbose, - version, - quiet, - log, - no_input, - proxy, - retries, - timeout, - exists_action, - trusted_host, - cert, - client_cert, - cache_dir, - no_cache, - disable_pip_version_check, - no_color, - no_python_version_warning, - use_new_feature, - use_deprecated_feature, - ], -} - -index_group: Dict[str, Any] = { - "name": "Package Index Options", - "options": [ - index_url, - extra_index_url, - no_index, - find_links, - ], -} diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/command_context.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/command_context.py deleted file mode 100644 index ed68322..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/command_context.py +++ /dev/null @@ -1,27 +0,0 @@ -from contextlib import ExitStack, contextmanager -from typing import ContextManager, Iterator, TypeVar - -_T = TypeVar("_T", covariant=True) - - -class CommandContextMixIn: - def __init__(self) -> None: - super().__init__() - self._in_main_context = False - self._main_context = ExitStack() - - @contextmanager - def main_context(self) -> Iterator[None]: - assert not self._in_main_context - - self._in_main_context = True - try: - with self._main_context: - yield - finally: - self._in_main_context = False - - def enter_context(self, context_provider: ContextManager[_T]) -> _T: - assert self._in_main_context - - return self._main_context.enter_context(context_provider) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main.py deleted file mode 100644 index 0e31221..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Primary application entrypoint. -""" -import locale -import logging -import os -import sys -from typing import List, Optional - -from pip._internal.cli.autocompletion import autocomplete -from pip._internal.cli.main_parser import parse_command -from pip._internal.commands import create_command -from pip._internal.exceptions import PipError -from pip._internal.utils import deprecation - -logger = logging.getLogger(__name__) - - -# Do not import and use main() directly! Using it directly is actively -# discouraged by pip's maintainers. The name, location and behavior of -# this function is subject to change, so calling it directly is not -# portable across different pip versions. - -# In addition, running pip in-process is unsupported and unsafe. This is -# elaborated in detail at -# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program. -# That document also provides suggestions that should work for nearly -# all users that are considering importing and using main() directly. - -# However, we know that certain users will still want to invoke pip -# in-process. If you understand and accept the implications of using pip -# in an unsupported manner, the best approach is to use runpy to avoid -# depending on the exact location of this entry point. - -# The following example shows how to use runpy to invoke pip in that -# case: -# -# sys.argv = ["pip", your, args, here] -# runpy.run_module("pip", run_name="__main__") -# -# Note that this will exit the process after running, unlike a direct -# call to main. As it is not safe to do any processing after calling -# main, this should not be an issue in practice. - - -def main(args: Optional[List[str]] = None) -> int: - if args is None: - args = sys.argv[1:] - - # Configure our deprecation warnings to be sent through loggers - deprecation.install_warning_logger() - - autocomplete() - - try: - cmd_name, cmd_args = parse_command(args) - except PipError as exc: - sys.stderr.write(f"ERROR: {exc}") - sys.stderr.write(os.linesep) - sys.exit(1) - - # Needed for locale.getpreferredencoding(False) to work - # in pip._internal.utils.encoding.auto_decode - try: - locale.setlocale(locale.LC_ALL, "") - except locale.Error as e: - # setlocale can apparently crash if locale are uninitialized - logger.debug("Ignoring error %s when setting locale", e) - command = create_command(cmd_name, isolated=("--isolated" in cmd_args)) - - return command.main(cmd_args) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main_parser.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main_parser.py deleted file mode 100644 index 3666ab0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/main_parser.py +++ /dev/null @@ -1,87 +0,0 @@ -"""A single place for constructing and exposing the main parser -""" - -import os -import sys -from typing import List, Tuple - -from pip._internal.cli import cmdoptions -from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter -from pip._internal.commands import commands_dict, get_similar_commands -from pip._internal.exceptions import CommandError -from pip._internal.utils.misc import get_pip_version, get_prog - -__all__ = ["create_main_parser", "parse_command"] - - -def create_main_parser() -> ConfigOptionParser: - """Creates and returns the main parser for pip's CLI""" - - parser = ConfigOptionParser( - usage="\n%prog [options]", - add_help_option=False, - formatter=UpdatingDefaultsHelpFormatter(), - name="global", - prog=get_prog(), - ) - parser.disable_interspersed_args() - - parser.version = get_pip_version() - - # add the general options - gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) - parser.add_option_group(gen_opts) - - # so the help formatter knows - parser.main = True # type: ignore - - # create command listing for description - description = [""] + [ - f"{name:27} {command_info.summary}" - for name, command_info in commands_dict.items() - ] - parser.description = "\n".join(description) - - return parser - - -def parse_command(args: List[str]) -> Tuple[str, List[str]]: - parser = create_main_parser() - - # Note: parser calls disable_interspersed_args(), so the result of this - # call is to split the initial args into the general options before the - # subcommand and everything else. - # For example: - # args: ['--timeout=5', 'install', '--user', 'INITools'] - # general_options: ['--timeout==5'] - # args_else: ['install', '--user', 'INITools'] - general_options, args_else = parser.parse_args(args) - - # --version - if general_options.version: - sys.stdout.write(parser.version) - sys.stdout.write(os.linesep) - sys.exit() - - # pip || pip help -> print_help() - if not args_else or (args_else[0] == "help" and len(args_else) == 1): - parser.print_help() - sys.exit() - - # the subcommand name - cmd_name = args_else[0] - - if cmd_name not in commands_dict: - guess = get_similar_commands(cmd_name) - - msg = [f'unknown command "{cmd_name}"'] - if guess: - msg.append(f'maybe you meant "{guess}"') - - raise CommandError(" - ".join(msg)) - - # all the args without the subcommand - cmd_args = args[:] - cmd_args.remove(cmd_name) - - return cmd_name, cmd_args diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/parser.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/parser.py deleted file mode 100644 index a1c99a8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/parser.py +++ /dev/null @@ -1,292 +0,0 @@ -"""Base option parser setup""" - -import logging -import optparse -import shutil -import sys -import textwrap -from contextlib import suppress -from typing import Any, Dict, Iterator, List, Tuple - -from pip._internal.cli.status_codes import UNKNOWN_ERROR -from pip._internal.configuration import Configuration, ConfigurationError -from pip._internal.utils.misc import redact_auth_from_url, strtobool - -logger = logging.getLogger(__name__) - - -class PrettyHelpFormatter(optparse.IndentedHelpFormatter): - """A prettier/less verbose help formatter for optparse.""" - - def __init__(self, *args: Any, **kwargs: Any) -> None: - # help position must be aligned with __init__.parseopts.description - kwargs["max_help_position"] = 30 - kwargs["indent_increment"] = 1 - kwargs["width"] = shutil.get_terminal_size()[0] - 2 - super().__init__(*args, **kwargs) - - def format_option_strings(self, option: optparse.Option) -> str: - return self._format_option_strings(option) - - def _format_option_strings( - self, option: optparse.Option, mvarfmt: str = " <{}>", optsep: str = ", " - ) -> str: - """ - Return a comma-separated list of option strings and metavars. - - :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') - :param mvarfmt: metavar format string - :param optsep: separator - """ - opts = [] - - if option._short_opts: - opts.append(option._short_opts[0]) - if option._long_opts: - opts.append(option._long_opts[0]) - if len(opts) > 1: - opts.insert(1, optsep) - - if option.takes_value(): - assert option.dest is not None - metavar = option.metavar or option.dest.lower() - opts.append(mvarfmt.format(metavar.lower())) - - return "".join(opts) - - def format_heading(self, heading: str) -> str: - if heading == "Options": - return "" - return heading + ":\n" - - def format_usage(self, usage: str) -> str: - """ - Ensure there is only one newline between usage and the first heading - if there is no description. - """ - msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " ")) - return msg - - def format_description(self, description: str) -> str: - # leave full control over description to us - if description: - if hasattr(self.parser, "main"): - label = "Commands" - else: - label = "Description" - # some doc strings have initial newlines, some don't - description = description.lstrip("\n") - # some doc strings have final newlines and spaces, some don't - description = description.rstrip() - # dedent, then reindent - description = self.indent_lines(textwrap.dedent(description), " ") - description = f"{label}:\n{description}\n" - return description - else: - return "" - - def format_epilog(self, epilog: str) -> str: - # leave full control over epilog to us - if epilog: - return epilog - else: - return "" - - def indent_lines(self, text: str, indent: str) -> str: - new_lines = [indent + line for line in text.split("\n")] - return "\n".join(new_lines) - - -class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): - """Custom help formatter for use in ConfigOptionParser. - - This is updates the defaults before expanding them, allowing - them to show up correctly in the help listing. - - Also redact auth from url type options - """ - - def expand_default(self, option: optparse.Option) -> str: - default_values = None - if self.parser is not None: - assert isinstance(self.parser, ConfigOptionParser) - self.parser._update_defaults(self.parser.defaults) - assert option.dest is not None - default_values = self.parser.defaults.get(option.dest) - help_text = super().expand_default(option) - - if default_values and option.metavar == "URL": - if isinstance(default_values, str): - default_values = [default_values] - - # If its not a list, we should abort and just return the help text - if not isinstance(default_values, list): - default_values = [] - - for val in default_values: - help_text = help_text.replace(val, redact_auth_from_url(val)) - - return help_text - - -class CustomOptionParser(optparse.OptionParser): - def insert_option_group( - self, idx: int, *args: Any, **kwargs: Any - ) -> optparse.OptionGroup: - """Insert an OptionGroup at a given position.""" - group = self.add_option_group(*args, **kwargs) - - self.option_groups.pop() - self.option_groups.insert(idx, group) - - return group - - @property - def option_list_all(self) -> List[optparse.Option]: - """Get a list of all options, including those in option groups.""" - res = self.option_list[:] - for i in self.option_groups: - res.extend(i.option_list) - - return res - - -class ConfigOptionParser(CustomOptionParser): - """Custom option parser which updates its defaults by checking the - configuration files and environmental variables""" - - def __init__( - self, - *args: Any, - name: str, - isolated: bool = False, - **kwargs: Any, - ) -> None: - self.name = name - self.config = Configuration(isolated) - - assert self.name - super().__init__(*args, **kwargs) - - def check_default(self, option: optparse.Option, key: str, val: Any) -> Any: - try: - return option.check_value(key, val) - except optparse.OptionValueError as exc: - print(f"An error occurred during configuration: {exc}") - sys.exit(3) - - def _get_ordered_configuration_items(self) -> Iterator[Tuple[str, Any]]: - # Configuration gives keys in an unordered manner. Order them. - override_order = ["global", self.name, ":env:"] - - # Pool the options into different groups - section_items: Dict[str, List[Tuple[str, Any]]] = { - name: [] for name in override_order - } - for section_key, val in self.config.items(): - # ignore empty values - if not val: - logger.debug( - "Ignoring configuration key '%s' as it's value is empty.", - section_key, - ) - continue - - section, key = section_key.split(".", 1) - if section in override_order: - section_items[section].append((key, val)) - - # Yield each group in their override order - for section in override_order: - for key, val in section_items[section]: - yield key, val - - def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]: - """Updates the given defaults with values from the config files and - the environ. Does a little special handling for certain types of - options (lists).""" - - # Accumulate complex default state. - self.values = optparse.Values(self.defaults) - late_eval = set() - # Then set the options with those values - for key, val in self._get_ordered_configuration_items(): - # '--' because configuration supports only long names - option = self.get_option("--" + key) - - # Ignore options not present in this parser. E.g. non-globals put - # in [global] by users that want them to apply to all applicable - # commands. - if option is None: - continue - - assert option.dest is not None - - if option.action in ("store_true", "store_false"): - try: - val = strtobool(val) - except ValueError: - self.error( - "{} is not a valid value for {} option, " # noqa - "please specify a boolean value like yes/no, " - "true/false or 1/0 instead.".format(val, key) - ) - elif option.action == "count": - with suppress(ValueError): - val = strtobool(val) - with suppress(ValueError): - val = int(val) - if not isinstance(val, int) or val < 0: - self.error( - "{} is not a valid value for {} option, " # noqa - "please instead specify either a non-negative integer " - "or a boolean value like yes/no or false/true " - "which is equivalent to 1/0.".format(val, key) - ) - elif option.action == "append": - val = val.split() - val = [self.check_default(option, key, v) for v in val] - elif option.action == "callback": - assert option.callback is not None - late_eval.add(option.dest) - opt_str = option.get_opt_string() - val = option.convert_value(opt_str, val) - # From take_action - args = option.callback_args or () - kwargs = option.callback_kwargs or {} - option.callback(option, opt_str, val, self, *args, **kwargs) - else: - val = self.check_default(option, key, val) - - defaults[option.dest] = val - - for key in late_eval: - defaults[key] = getattr(self.values, key) - self.values = None - return defaults - - def get_default_values(self) -> optparse.Values: - """Overriding to make updating the defaults after instantiation of - the option parser possible, _update_defaults() does the dirty work.""" - if not self.process_default_values: - # Old, pre-Optik 1.5 behaviour. - return optparse.Values(self.defaults) - - # Load the configuration, or error out in case of an error - try: - self.config.load() - except ConfigurationError as err: - self.exit(UNKNOWN_ERROR, str(err)) - - defaults = self._update_defaults(self.defaults.copy()) # ours - for option in self._get_all_options(): - assert option.dest is not None - default = defaults.get(option.dest) - if isinstance(default, str): - opt_str = option.get_opt_string() - defaults[option.dest] = option.check_value(opt_str, default) - return optparse.Values(defaults) - - def error(self, msg: str) -> None: - self.print_usage(sys.stderr) - self.exit(UNKNOWN_ERROR, f"{msg}\n") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/progress_bars.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/progress_bars.py deleted file mode 100644 index f3db295..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/progress_bars.py +++ /dev/null @@ -1,250 +0,0 @@ -import itertools -import sys -from signal import SIGINT, default_int_handler, signal -from typing import Any - -from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar -from pip._vendor.progress.spinner import Spinner - -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.logging import get_indentation -from pip._internal.utils.misc import format_size - -try: - from pip._vendor import colorama -# Lots of different errors can come from this, including SystemError and -# ImportError. -except Exception: - colorama = None - - -def _select_progress_class(preferred: Bar, fallback: Bar) -> Bar: - encoding = getattr(preferred.file, "encoding", None) - - # If we don't know what encoding this file is in, then we'll just assume - # that it doesn't support unicode and use the ASCII bar. - if not encoding: - return fallback - - # Collect all of the possible characters we want to use with the preferred - # bar. - characters = [ - getattr(preferred, "empty_fill", ""), - getattr(preferred, "fill", ""), - ] - characters += list(getattr(preferred, "phases", [])) - - # Try to decode the characters we're using for the bar using the encoding - # of the given file, if this works then we'll assume that we can use the - # fancier bar and if not we'll fall back to the plaintext bar. - try: - "".join(characters).encode(encoding) - except UnicodeEncodeError: - return fallback - else: - return preferred - - -_BaseBar: Any = _select_progress_class(IncrementalBar, Bar) - - -class InterruptibleMixin: - """ - Helper to ensure that self.finish() gets called on keyboard interrupt. - - This allows downloads to be interrupted without leaving temporary state - (like hidden cursors) behind. - - This class is similar to the progress library's existing SigIntMixin - helper, but as of version 1.2, that helper has the following problems: - - 1. It calls sys.exit(). - 2. It discards the existing SIGINT handler completely. - 3. It leaves its own handler in place even after an uninterrupted finish, - which will have unexpected delayed effects if the user triggers an - unrelated keyboard interrupt some time after a progress-displaying - download has already completed, for example. - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """ - Save the original SIGINT handler for later. - """ - # https://github.com/python/mypy/issues/5887 - super().__init__(*args, **kwargs) # type: ignore - - self.original_handler = signal(SIGINT, self.handle_sigint) - - # If signal() returns None, the previous handler was not installed from - # Python, and we cannot restore it. This probably should not happen, - # but if it does, we must restore something sensible instead, at least. - # The least bad option should be Python's default SIGINT handler, which - # just raises KeyboardInterrupt. - if self.original_handler is None: - self.original_handler = default_int_handler - - def finish(self) -> None: - """ - Restore the original SIGINT handler after finishing. - - This should happen regardless of whether the progress display finishes - normally, or gets interrupted. - """ - super().finish() # type: ignore - signal(SIGINT, self.original_handler) - - def handle_sigint(self, signum, frame): # type: ignore - """ - Call self.finish() before delegating to the original SIGINT handler. - - This handler should only be in place while the progress display is - active. - """ - self.finish() - self.original_handler(signum, frame) - - -class SilentBar(Bar): - def update(self) -> None: - pass - - -class BlueEmojiBar(IncrementalBar): - - suffix = "%(percent)d%%" - bar_prefix = " " - bar_suffix = " " - phases = ("\U0001F539", "\U0001F537", "\U0001F535") - - -class DownloadProgressMixin: - def __init__(self, *args: Any, **kwargs: Any) -> None: - # https://github.com/python/mypy/issues/5887 - super().__init__(*args, **kwargs) # type: ignore - self.message: str = (" " * (get_indentation() + 2)) + self.message - - @property - def downloaded(self) -> str: - return format_size(self.index) # type: ignore - - @property - def download_speed(self) -> str: - # Avoid zero division errors... - if self.avg == 0.0: # type: ignore - return "..." - return format_size(1 / self.avg) + "/s" # type: ignore - - @property - def pretty_eta(self) -> str: - if self.eta: # type: ignore - return f"eta {self.eta_td}" # type: ignore - return "" - - def iter(self, it): # type: ignore - for x in it: - yield x - # B305 is incorrectly raised here - # https://github.com/PyCQA/flake8-bugbear/issues/59 - self.next(len(x)) # noqa: B305 - self.finish() - - -class WindowsMixin: - def __init__(self, *args: Any, **kwargs: Any) -> None: - # The Windows terminal does not support the hide/show cursor ANSI codes - # even with colorama. So we'll ensure that hide_cursor is False on - # Windows. - # This call needs to go before the super() call, so that hide_cursor - # is set in time. The base progress bar class writes the "hide cursor" - # code to the terminal in its init, so if we don't set this soon - # enough, we get a "hide" with no corresponding "show"... - if WINDOWS and self.hide_cursor: # type: ignore - self.hide_cursor = False - - # https://github.com/python/mypy/issues/5887 - super().__init__(*args, **kwargs) # type: ignore - - # Check if we are running on Windows and we have the colorama module, - # if we do then wrap our file with it. - if WINDOWS and colorama: - self.file = colorama.AnsiToWin32(self.file) # type: ignore - # The progress code expects to be able to call self.file.isatty() - # but the colorama.AnsiToWin32() object doesn't have that, so we'll - # add it. - self.file.isatty = lambda: self.file.wrapped.isatty() - # The progress code expects to be able to call self.file.flush() - # but the colorama.AnsiToWin32() object doesn't have that, so we'll - # add it. - self.file.flush = lambda: self.file.wrapped.flush() - - -class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, DownloadProgressMixin): - - file = sys.stdout - message = "%(percent)d%%" - suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" - - -class DefaultDownloadProgressBar(BaseDownloadProgressBar, _BaseBar): - pass - - -class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): - pass - - -class DownloadBar(BaseDownloadProgressBar, Bar): - pass - - -class DownloadFillingCirclesBar(BaseDownloadProgressBar, FillingCirclesBar): - pass - - -class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, BlueEmojiBar): - pass - - -class DownloadProgressSpinner( - WindowsMixin, InterruptibleMixin, DownloadProgressMixin, Spinner -): - - file = sys.stdout - suffix = "%(downloaded)s %(download_speed)s" - - def next_phase(self) -> str: - if not hasattr(self, "_phaser"): - self._phaser = itertools.cycle(self.phases) - return next(self._phaser) - - def update(self) -> None: - message = self.message % self - phase = self.next_phase() - suffix = self.suffix % self - line = "".join( - [ - message, - " " if message else "", - phase, - " " if suffix else "", - suffix, - ] - ) - - self.writeln(line) - - -BAR_TYPES = { - "off": (DownloadSilentBar, DownloadSilentBar), - "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), - "ascii": (DownloadBar, DownloadProgressSpinner), - "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), - "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner), -} - - -def DownloadProgressProvider(progress_bar, max=None): # type: ignore - if max is None or max == 0: - return BAR_TYPES[progress_bar][1]().iter - else: - return BAR_TYPES[progress_bar][0](max=max).iter diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/req_command.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/req_command.py deleted file mode 100644 index 4129bf7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/req_command.py +++ /dev/null @@ -1,453 +0,0 @@ -"""Contains the Command base classes that depend on PipSession. - -The classes in this module are in a separate module so the commands not -needing download / PackageFinder capability don't unnecessarily import the -PackageFinder machinery and all its vendored dependencies, etc. -""" - -import logging -import os -import sys -from functools import partial -from optparse import Values -from typing import Any, List, Optional, Tuple - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.cli.command_context import CommandContextMixIn -from pip._internal.exceptions import CommandError, PreviousBuildDirError -from pip._internal.index.collector import LinkCollector -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.models.target_python import TargetPython -from pip._internal.network.session import PipSession -from pip._internal.operations.prepare import RequirementPreparer -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, - install_req_from_parsed_requirement, - install_req_from_req_string, -) -from pip._internal.req.req_file import parse_requirements -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_tracker import RequirementTracker -from pip._internal.resolution.base import BaseResolver -from pip._internal.self_outdated_check import pip_self_version_check -from pip._internal.utils.temp_dir import ( - TempDirectory, - TempDirectoryTypeRegistry, - tempdir_kinds, -) -from pip._internal.utils.virtualenv import running_under_virtualenv - -logger = logging.getLogger(__name__) - - -class SessionCommandMixin(CommandContextMixIn): - - """ - A class mixin for command classes needing _build_session(). - """ - - def __init__(self) -> None: - super().__init__() - self._session: Optional[PipSession] = None - - @classmethod - def _get_index_urls(cls, options: Values) -> Optional[List[str]]: - """Return a list of index urls from user-provided options.""" - index_urls = [] - if not getattr(options, "no_index", False): - url = getattr(options, "index_url", None) - if url: - index_urls.append(url) - urls = getattr(options, "extra_index_urls", None) - if urls: - index_urls.extend(urls) - # Return None rather than an empty list - return index_urls or None - - def get_default_session(self, options: Values) -> PipSession: - """Get a default-managed session.""" - if self._session is None: - self._session = self.enter_context(self._build_session(options)) - # there's no type annotation on requests.Session, so it's - # automatically ContextManager[Any] and self._session becomes Any, - # then https://github.com/python/mypy/issues/7696 kicks in - assert self._session is not None - return self._session - - def _build_session( - self, - options: Values, - retries: Optional[int] = None, - timeout: Optional[int] = None, - ) -> PipSession: - assert not options.cache_dir or os.path.isabs(options.cache_dir) - session = PipSession( - cache=( - os.path.join(options.cache_dir, "http") if options.cache_dir else None - ), - retries=retries if retries is not None else options.retries, - trusted_hosts=options.trusted_hosts, - index_urls=self._get_index_urls(options), - ) - - # Handle custom ca-bundles from the user - if options.cert: - session.verify = options.cert - - # Handle SSL client certificate - if options.client_cert: - session.cert = options.client_cert - - # Handle timeouts - if options.timeout or timeout: - session.timeout = timeout if timeout is not None else options.timeout - - # Handle configured proxies - if options.proxy: - session.proxies = { - "http": options.proxy, - "https": options.proxy, - } - - # Determine if we can prompt the user for authentication or not - session.auth.prompting = not options.no_input - - return session - - -class IndexGroupCommand(Command, SessionCommandMixin): - - """ - Abstract base class for commands with the index_group options. - - This also corresponds to the commands that permit the pip version check. - """ - - def handle_pip_version_check(self, options: Values) -> None: - """ - Do the pip version check if not disabled. - - This overrides the default behavior of not doing the check. - """ - # Make sure the index_group options are present. - assert hasattr(options, "no_index") - - if options.disable_pip_version_check or options.no_index: - return - - # Otherwise, check if we're using the latest version of pip available. - session = self._build_session( - options, retries=0, timeout=min(5, options.timeout) - ) - with session: - pip_self_version_check(session, options) - - -KEEPABLE_TEMPDIR_TYPES = [ - tempdir_kinds.BUILD_ENV, - tempdir_kinds.EPHEM_WHEEL_CACHE, - tempdir_kinds.REQ_BUILD, -] - - -def warn_if_run_as_root() -> None: - """Output a warning for sudo users on Unix. - - In a virtual environment, sudo pip still writes to virtualenv. - On Windows, users may run pip as Administrator without issues. - This warning only applies to Unix root users outside of virtualenv. - """ - if running_under_virtualenv(): - return - if not hasattr(os, "getuid"): - return - # On Windows, there are no "system managed" Python packages. Installing as - # Administrator via pip is the correct way of updating system environments. - # - # We choose sys.platform over utils.compat.WINDOWS here to enable Mypy platform - # checks: https://mypy.readthedocs.io/en/stable/common_issues.html - if sys.platform == "win32" or sys.platform == "cygwin": - return - if sys.platform == "darwin" or sys.platform == "linux": - if os.getuid() != 0: - return - logger.warning( - "Running pip as the 'root' user can result in broken permissions and " - "conflicting behaviour with the system package manager. " - "It is recommended to use a virtual environment instead: " - "https://pip.pypa.io/warnings/venv" - ) - - -def with_cleanup(func: Any) -> Any: - """Decorator for common logic related to managing temporary - directories. - """ - - def configure_tempdir_registry(registry: TempDirectoryTypeRegistry) -> None: - for t in KEEPABLE_TEMPDIR_TYPES: - registry.set_delete(t, False) - - def wrapper( - self: RequirementCommand, options: Values, args: List[Any] - ) -> Optional[int]: - assert self.tempdir_registry is not None - if options.no_clean: - configure_tempdir_registry(self.tempdir_registry) - - try: - return func(self, options, args) - except PreviousBuildDirError: - # This kind of conflict can occur when the user passes an explicit - # build directory with a pre-existing folder. In that case we do - # not want to accidentally remove it. - configure_tempdir_registry(self.tempdir_registry) - raise - - return wrapper - - -class RequirementCommand(IndexGroupCommand): - def __init__(self, *args: Any, **kw: Any) -> None: - super().__init__(*args, **kw) - - self.cmd_opts.add_option(cmdoptions.no_clean()) - - @staticmethod - def determine_resolver_variant(options: Values) -> str: - """Determines which resolver should be used, based on the given options.""" - if "legacy-resolver" in options.deprecated_features_enabled: - return "legacy" - - return "2020-resolver" - - @classmethod - def make_requirement_preparer( - cls, - temp_build_dir: TempDirectory, - options: Values, - req_tracker: RequirementTracker, - session: PipSession, - finder: PackageFinder, - use_user_site: bool, - download_dir: Optional[str] = None, - ) -> RequirementPreparer: - """ - Create a RequirementPreparer instance for the given parameters. - """ - temp_build_dir_path = temp_build_dir.path - assert temp_build_dir_path is not None - - resolver_variant = cls.determine_resolver_variant(options) - if resolver_variant == "2020-resolver": - lazy_wheel = "fast-deps" in options.features_enabled - if lazy_wheel: - logger.warning( - "pip is using lazily downloaded wheels using HTTP " - "range requests to obtain dependency information. " - "This experimental feature is enabled through " - "--use-feature=fast-deps and it is not ready for " - "production." - ) - else: - lazy_wheel = False - if "fast-deps" in options.features_enabled: - logger.warning( - "fast-deps has no effect when used with the legacy resolver." - ) - - return RequirementPreparer( - build_dir=temp_build_dir_path, - src_dir=options.src_dir, - download_dir=download_dir, - build_isolation=options.build_isolation, - req_tracker=req_tracker, - session=session, - progress_bar=options.progress_bar, - finder=finder, - require_hashes=options.require_hashes, - use_user_site=use_user_site, - lazy_wheel=lazy_wheel, - in_tree_build="in-tree-build" in options.features_enabled, - ) - - @classmethod - def make_resolver( - cls, - preparer: RequirementPreparer, - finder: PackageFinder, - options: Values, - wheel_cache: Optional[WheelCache] = None, - use_user_site: bool = False, - ignore_installed: bool = True, - ignore_requires_python: bool = False, - force_reinstall: bool = False, - upgrade_strategy: str = "to-satisfy-only", - use_pep517: Optional[bool] = None, - py_version_info: Optional[Tuple[int, ...]] = None, - ) -> BaseResolver: - """ - Create a Resolver instance for the given parameters. - """ - make_install_req = partial( - install_req_from_req_string, - isolated=options.isolated_mode, - use_pep517=use_pep517, - ) - resolver_variant = cls.determine_resolver_variant(options) - # The long import name and duplicated invocation is needed to convince - # Mypy into correctly typechecking. Otherwise it would complain the - # "Resolver" class being redefined. - if resolver_variant == "2020-resolver": - import pip._internal.resolution.resolvelib.resolver - - return pip._internal.resolution.resolvelib.resolver.Resolver( - preparer=preparer, - finder=finder, - wheel_cache=wheel_cache, - make_install_req=make_install_req, - use_user_site=use_user_site, - ignore_dependencies=options.ignore_dependencies, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - force_reinstall=force_reinstall, - upgrade_strategy=upgrade_strategy, - py_version_info=py_version_info, - ) - import pip._internal.resolution.legacy.resolver - - return pip._internal.resolution.legacy.resolver.Resolver( - preparer=preparer, - finder=finder, - wheel_cache=wheel_cache, - make_install_req=make_install_req, - use_user_site=use_user_site, - ignore_dependencies=options.ignore_dependencies, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - force_reinstall=force_reinstall, - upgrade_strategy=upgrade_strategy, - py_version_info=py_version_info, - ) - - def get_requirements( - self, - args: List[str], - options: Values, - finder: PackageFinder, - session: PipSession, - ) -> List[InstallRequirement]: - """ - Parse command-line arguments into the corresponding requirements. - """ - requirements: List[InstallRequirement] = [] - for filename in options.constraints: - for parsed_req in parse_requirements( - filename, - constraint=True, - finder=finder, - options=options, - session=session, - ): - req_to_add = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode, - user_supplied=False, - ) - requirements.append(req_to_add) - - for req in args: - req_to_add = install_req_from_line( - req, - None, - isolated=options.isolated_mode, - use_pep517=options.use_pep517, - user_supplied=True, - ) - requirements.append(req_to_add) - - for req in options.editables: - req_to_add = install_req_from_editable( - req, - user_supplied=True, - isolated=options.isolated_mode, - use_pep517=options.use_pep517, - ) - requirements.append(req_to_add) - - # NOTE: options.require_hashes may be set if --require-hashes is True - for filename in options.requirements: - for parsed_req in parse_requirements( - filename, finder=finder, options=options, session=session - ): - req_to_add = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode, - use_pep517=options.use_pep517, - user_supplied=True, - ) - requirements.append(req_to_add) - - # If any requirement has hash options, enable hash checking. - if any(req.has_hash_options for req in requirements): - options.require_hashes = True - - if not (args or options.editables or options.requirements): - opts = {"name": self.name} - if options.find_links: - raise CommandError( - "You must give at least one requirement to {name} " - '(maybe you meant "pip {name} {links}"?)'.format( - **dict(opts, links=" ".join(options.find_links)) - ) - ) - else: - raise CommandError( - "You must give at least one requirement to {name} " - '(see "pip help {name}")'.format(**opts) - ) - - return requirements - - @staticmethod - def trace_basic_info(finder: PackageFinder) -> None: - """ - Trace basic information about the provided objects. - """ - # Display where finder is looking for packages - search_scope = finder.search_scope - locations = search_scope.get_formatted_locations() - if locations: - logger.info(locations) - - def _build_package_finder( - self, - options: Values, - session: PipSession, - target_python: Optional[TargetPython] = None, - ignore_requires_python: Optional[bool] = None, - ) -> PackageFinder: - """ - Create a package finder appropriate to this requirement command. - - :param ignore_requires_python: Whether to ignore incompatible - "Requires-Python" values in links. Defaults to False. - """ - link_collector = LinkCollector.create(session, options=options) - selection_prefs = SelectionPreferences( - allow_yanked=True, - format_control=options.format_control, - allow_all_prereleases=options.pre, - prefer_binary=options.prefer_binary, - ignore_requires_python=ignore_requires_python, - ) - - return PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - target_python=target_python, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/spinners.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/spinners.py deleted file mode 100644 index 1e313e1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/spinners.py +++ /dev/null @@ -1,157 +0,0 @@ -import contextlib -import itertools -import logging -import sys -import time -from typing import IO, Iterator - -from pip._vendor.progress import HIDE_CURSOR, SHOW_CURSOR - -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.logging import get_indentation - -logger = logging.getLogger(__name__) - - -class SpinnerInterface: - def spin(self) -> None: - raise NotImplementedError() - - def finish(self, final_status: str) -> None: - raise NotImplementedError() - - -class InteractiveSpinner(SpinnerInterface): - def __init__( - self, - message: str, - file: IO[str] = None, - spin_chars: str = "-\\|/", - # Empirically, 8 updates/second looks nice - min_update_interval_seconds: float = 0.125, - ): - self._message = message - if file is None: - file = sys.stdout - self._file = file - self._rate_limiter = RateLimiter(min_update_interval_seconds) - self._finished = False - - self._spin_cycle = itertools.cycle(spin_chars) - - self._file.write(" " * get_indentation() + self._message + " ... ") - self._width = 0 - - def _write(self, status: str) -> None: - assert not self._finished - # Erase what we wrote before by backspacing to the beginning, writing - # spaces to overwrite the old text, and then backspacing again - backup = "\b" * self._width - self._file.write(backup + " " * self._width + backup) - # Now we have a blank slate to add our status - self._file.write(status) - self._width = len(status) - self._file.flush() - self._rate_limiter.reset() - - def spin(self) -> None: - if self._finished: - return - if not self._rate_limiter.ready(): - return - self._write(next(self._spin_cycle)) - - def finish(self, final_status: str) -> None: - if self._finished: - return - self._write(final_status) - self._file.write("\n") - self._file.flush() - self._finished = True - - -# Used for dumb terminals, non-interactive installs (no tty), etc. -# We still print updates occasionally (once every 60 seconds by default) to -# act as a keep-alive for systems like Travis-CI that take lack-of-output as -# an indication that a task has frozen. -class NonInteractiveSpinner(SpinnerInterface): - def __init__(self, message: str, min_update_interval_seconds: float = 60.0) -> None: - self._message = message - self._finished = False - self._rate_limiter = RateLimiter(min_update_interval_seconds) - self._update("started") - - def _update(self, status: str) -> None: - assert not self._finished - self._rate_limiter.reset() - logger.info("%s: %s", self._message, status) - - def spin(self) -> None: - if self._finished: - return - if not self._rate_limiter.ready(): - return - self._update("still running...") - - def finish(self, final_status: str) -> None: - if self._finished: - return - self._update(f"finished with status '{final_status}'") - self._finished = True - - -class RateLimiter: - def __init__(self, min_update_interval_seconds: float) -> None: - self._min_update_interval_seconds = min_update_interval_seconds - self._last_update: float = 0 - - def ready(self) -> bool: - now = time.time() - delta = now - self._last_update - return delta >= self._min_update_interval_seconds - - def reset(self) -> None: - self._last_update = time.time() - - -@contextlib.contextmanager -def open_spinner(message: str) -> Iterator[SpinnerInterface]: - # Interactive spinner goes directly to sys.stdout rather than being routed - # through the logging system, but it acts like it has level INFO, - # i.e. it's only displayed if we're at level INFO or better. - # Non-interactive spinner goes through the logging system, so it is always - # in sync with logging configuration. - if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: - spinner: SpinnerInterface = InteractiveSpinner(message) - else: - spinner = NonInteractiveSpinner(message) - try: - with hidden_cursor(sys.stdout): - yield spinner - except KeyboardInterrupt: - spinner.finish("canceled") - raise - except Exception: - spinner.finish("error") - raise - else: - spinner.finish("done") - - -@contextlib.contextmanager -def hidden_cursor(file: IO[str]) -> Iterator[None]: - # The Windows terminal does not support the hide/show cursor ANSI codes, - # even via colorama. So don't even try. - if WINDOWS: - yield - # We don't want to clutter the output with control characters if we're - # writing to a file, or if the user is running with --quiet. - # See https://github.com/pypa/pip/issues/3418 - elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: - yield - else: - file.write(HIDE_CURSOR) - try: - yield - finally: - file.write(SHOW_CURSOR) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/status_codes.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/status_codes.py deleted file mode 100644 index 5e29502..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/cli/status_codes.py +++ /dev/null @@ -1,6 +0,0 @@ -SUCCESS = 0 -ERROR = 1 -UNKNOWN_ERROR = 2 -VIRTUALENV_NOT_FOUND = 3 -PREVIOUS_BUILD_DIR_ERROR = 4 -NO_MATCHES_FOUND = 23 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/__init__.py deleted file mode 100644 index 8e94b38..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/__init__.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -Package containing all pip commands -""" - -import importlib -from collections import OrderedDict, namedtuple -from typing import Any, Dict, Optional - -from pip._internal.cli.base_command import Command - -CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary') - -# The ordering matters for help display. -# Also, even though the module path starts with the same -# "pip._internal.commands" prefix in each case, we include the full path -# because it makes testing easier (specifically when modifying commands_dict -# in test setup / teardown by adding info for a FakeCommand class defined -# in a test-related module). -# Finally, we need to pass an iterable of pairs here rather than a dict -# so that the ordering won't be lost when using Python 2.7. -commands_dict: Dict[str, CommandInfo] = OrderedDict([ - ('install', CommandInfo( - 'pip._internal.commands.install', 'InstallCommand', - 'Install packages.', - )), - ('download', CommandInfo( - 'pip._internal.commands.download', 'DownloadCommand', - 'Download packages.', - )), - ('uninstall', CommandInfo( - 'pip._internal.commands.uninstall', 'UninstallCommand', - 'Uninstall packages.', - )), - ('freeze', CommandInfo( - 'pip._internal.commands.freeze', 'FreezeCommand', - 'Output installed packages in requirements format.', - )), - ('list', CommandInfo( - 'pip._internal.commands.list', 'ListCommand', - 'List installed packages.', - )), - ('show', CommandInfo( - 'pip._internal.commands.show', 'ShowCommand', - 'Show information about installed packages.', - )), - ('check', CommandInfo( - 'pip._internal.commands.check', 'CheckCommand', - 'Verify installed packages have compatible dependencies.', - )), - ('config', CommandInfo( - 'pip._internal.commands.configuration', 'ConfigurationCommand', - 'Manage local and global configuration.', - )), - ('search', CommandInfo( - 'pip._internal.commands.search', 'SearchCommand', - 'Search PyPI for packages.', - )), - ('cache', CommandInfo( - 'pip._internal.commands.cache', 'CacheCommand', - "Inspect and manage pip's wheel cache.", - )), - ('index', CommandInfo( - 'pip._internal.commands.index', 'IndexCommand', - "Inspect information available from package indexes.", - )), - ('wheel', CommandInfo( - 'pip._internal.commands.wheel', 'WheelCommand', - 'Build wheels from your requirements.', - )), - ('hash', CommandInfo( - 'pip._internal.commands.hash', 'HashCommand', - 'Compute hashes of package archives.', - )), - ('completion', CommandInfo( - 'pip._internal.commands.completion', 'CompletionCommand', - 'A helper command used for command completion.', - )), - ('debug', CommandInfo( - 'pip._internal.commands.debug', 'DebugCommand', - 'Show information useful for debugging.', - )), - ('help', CommandInfo( - 'pip._internal.commands.help', 'HelpCommand', - 'Show help for commands.', - )), -]) - - -def create_command(name: str, **kwargs: Any) -> Command: - """ - Create an instance of the Command class with the given name. - """ - module_path, class_name, summary = commands_dict[name] - module = importlib.import_module(module_path) - command_class = getattr(module, class_name) - command = command_class(name=name, summary=summary, **kwargs) - - return command - - -def get_similar_commands(name: str) -> Optional[str]: - """Command name auto-correct.""" - from difflib import get_close_matches - - name = name.lower() - - close_commands = get_close_matches(name, commands_dict.keys()) - - if close_commands: - return close_commands[0] - else: - return None diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/cache.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/cache.py deleted file mode 100644 index 3a5bb9c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/cache.py +++ /dev/null @@ -1,216 +0,0 @@ -import os -import textwrap -from optparse import Values -from typing import Any, List - -import pip._internal.utils.filesystem as filesystem -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.exceptions import CommandError, PipError -from pip._internal.utils.logging import getLogger - -logger = getLogger(__name__) - - -class CacheCommand(Command): - """ - Inspect and manage pip's wheel cache. - - Subcommands: - - - dir: Show the cache directory. - - info: Show information about the cache. - - list: List filenames of packages stored in the cache. - - remove: Remove one or more package from the cache. - - purge: Remove all items from the cache. - - ```` can be a glob expression or a package name. - """ - - ignore_require_venv = True - usage = """ - %prog dir - %prog info - %prog list [] [--format=[human, abspath]] - %prog remove - %prog purge - """ - - def add_options(self) -> None: - - self.cmd_opts.add_option( - '--format', - action='store', - dest='list_format', - default="human", - choices=('human', 'abspath'), - help="Select the output format among: human (default) or abspath" - ) - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[Any]) -> int: - handlers = { - "dir": self.get_cache_dir, - "info": self.get_cache_info, - "list": self.list_cache_items, - "remove": self.remove_cache_items, - "purge": self.purge_cache, - } - - if not options.cache_dir: - logger.error("pip cache commands can not " - "function since cache is disabled.") - return ERROR - - # Determine action - if not args or args[0] not in handlers: - logger.error( - "Need an action (%s) to perform.", - ", ".join(sorted(handlers)), - ) - return ERROR - - action = args[0] - - # Error handling happens here, not in the action-handlers. - try: - handlers[action](options, args[1:]) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - return SUCCESS - - def get_cache_dir(self, options: Values, args: List[Any]) -> None: - if args: - raise CommandError('Too many arguments') - - logger.info(options.cache_dir) - - def get_cache_info(self, options: Values, args: List[Any]) -> None: - if args: - raise CommandError('Too many arguments') - - num_http_files = len(self._find_http_files(options)) - num_packages = len(self._find_wheels(options, '*')) - - http_cache_location = self._cache_dir(options, 'http') - wheels_cache_location = self._cache_dir(options, 'wheels') - http_cache_size = filesystem.format_directory_size(http_cache_location) - wheels_cache_size = filesystem.format_directory_size( - wheels_cache_location - ) - - message = textwrap.dedent(""" - Package index page cache location: {http_cache_location} - Package index page cache size: {http_cache_size} - Number of HTTP files: {num_http_files} - Wheels location: {wheels_cache_location} - Wheels size: {wheels_cache_size} - Number of wheels: {package_count} - """).format( - http_cache_location=http_cache_location, - http_cache_size=http_cache_size, - num_http_files=num_http_files, - wheels_cache_location=wheels_cache_location, - package_count=num_packages, - wheels_cache_size=wheels_cache_size, - ).strip() - - logger.info(message) - - def list_cache_items(self, options: Values, args: List[Any]) -> None: - if len(args) > 1: - raise CommandError('Too many arguments') - - if args: - pattern = args[0] - else: - pattern = '*' - - files = self._find_wheels(options, pattern) - if options.list_format == 'human': - self.format_for_human(files) - else: - self.format_for_abspath(files) - - def format_for_human(self, files: List[str]) -> None: - if not files: - logger.info('Nothing cached.') - return - - results = [] - for filename in files: - wheel = os.path.basename(filename) - size = filesystem.format_file_size(filename) - results.append(f' - {wheel} ({size})') - logger.info('Cache contents:\n') - logger.info('\n'.join(sorted(results))) - - def format_for_abspath(self, files: List[str]) -> None: - if not files: - return - - results = [] - for filename in files: - results.append(filename) - - logger.info('\n'.join(sorted(results))) - - def remove_cache_items(self, options: Values, args: List[Any]) -> None: - if len(args) > 1: - raise CommandError('Too many arguments') - - if not args: - raise CommandError('Please provide a pattern') - - files = self._find_wheels(options, args[0]) - - # Only fetch http files if no specific pattern given - if args[0] == '*': - files += self._find_http_files(options) - - if not files: - raise CommandError('No matching packages') - - for filename in files: - os.unlink(filename) - logger.verbose("Removed %s", filename) - logger.info("Files removed: %s", len(files)) - - def purge_cache(self, options: Values, args: List[Any]) -> None: - if args: - raise CommandError('Too many arguments') - - return self.remove_cache_items(options, ['*']) - - def _cache_dir(self, options: Values, subdir: str) -> str: - return os.path.join(options.cache_dir, subdir) - - def _find_http_files(self, options: Values) -> List[str]: - http_dir = self._cache_dir(options, 'http') - return filesystem.find_files(http_dir, '*') - - def _find_wheels(self, options: Values, pattern: str) -> List[str]: - wheel_dir = self._cache_dir(options, 'wheels') - - # The wheel filename format, as specified in PEP 427, is: - # {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl - # - # Additionally, non-alphanumeric values in the distribution are - # normalized to underscores (_), meaning hyphens can never occur - # before `-{version}`. - # - # Given that information: - # - If the pattern we're given contains a hyphen (-), the user is - # providing at least the version. Thus, we can just append `*.whl` - # to match the rest of it. - # - If the pattern we're given doesn't contain a hyphen (-), the - # user is only providing the name. Thus, we append `-*.whl` to - # match the hyphen before the version, followed by anything else. - # - # PEP 427: https://www.python.org/dev/peps/pep-0427/ - pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl") - - return filesystem.find_files(wheel_dir, pattern) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/check.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/check.py deleted file mode 100644 index f9412a7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/check.py +++ /dev/null @@ -1,47 +0,0 @@ -import logging -from optparse import Values -from typing import Any, List - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.operations.check import ( - check_package_set, - create_package_set_from_installed, -) -from pip._internal.utils.misc import write_output - -logger = logging.getLogger(__name__) - - -class CheckCommand(Command): - """Verify installed packages have compatible dependencies.""" - - usage = """ - %prog [options]""" - - def run(self, options: Values, args: List[Any]) -> int: - - package_set, parsing_probs = create_package_set_from_installed() - missing, conflicting = check_package_set(package_set) - - for project_name in missing: - version = package_set[project_name].version - for dependency in missing[project_name]: - write_output( - "%s %s requires %s, which is not installed.", - project_name, version, dependency[0], - ) - - for project_name in conflicting: - version = package_set[project_name].version - for dep_name, dep_version, req in conflicting[project_name]: - write_output( - "%s %s has requirement %s, but you have %s %s.", - project_name, version, req, dep_name, dep_version, - ) - - if missing or conflicting or parsing_probs: - return ERROR - else: - write_output("No broken requirements found.") - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/completion.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/completion.py deleted file mode 100644 index 9ce7888..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/completion.py +++ /dev/null @@ -1,91 +0,0 @@ -import sys -import textwrap -from optparse import Values -from typing import List - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.utils.misc import get_prog - -BASE_COMPLETION = """ -# pip {shell} completion start{script}# pip {shell} completion end -""" - -COMPLETION_SCRIPTS = { - 'bash': """ - _pip_completion() - {{ - COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ - COMP_CWORD=$COMP_CWORD \\ - PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) - }} - complete -o default -F _pip_completion {prog} - """, - 'zsh': """ - function _pip_completion {{ - local words cword - read -Ac words - read -cn cword - reply=( $( COMP_WORDS="$words[*]" \\ - COMP_CWORD=$(( cword-1 )) \\ - PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )) - }} - compctl -K _pip_completion {prog} - """, - 'fish': """ - function __fish_complete_pip - set -lx COMP_WORDS (commandline -o) "" - set -lx COMP_CWORD ( \\ - math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ - ) - set -lx PIP_AUTO_COMPLETE 1 - string split \\ -- (eval $COMP_WORDS[1]) - end - complete -fa "(__fish_complete_pip)" -c {prog} - """, -} - - -class CompletionCommand(Command): - """A helper command to be used for command completion.""" - - ignore_require_venv = True - - def add_options(self) -> None: - self.cmd_opts.add_option( - '--bash', '-b', - action='store_const', - const='bash', - dest='shell', - help='Emit completion code for bash') - self.cmd_opts.add_option( - '--zsh', '-z', - action='store_const', - const='zsh', - dest='shell', - help='Emit completion code for zsh') - self.cmd_opts.add_option( - '--fish', '-f', - action='store_const', - const='fish', - dest='shell', - help='Emit completion code for fish') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - """Prints the completion code of the given shell""" - shells = COMPLETION_SCRIPTS.keys() - shell_options = ['--' + shell for shell in sorted(shells)] - if options.shell in shells: - script = textwrap.dedent( - COMPLETION_SCRIPTS.get(options.shell, '').format( - prog=get_prog()) - ) - print(BASE_COMPLETION.format(script=script, shell=options.shell)) - return SUCCESS - else: - sys.stderr.write( - 'ERROR: You must pass {}\n' .format(' or '.join(shell_options)) - ) - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/configuration.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/configuration.py deleted file mode 100644 index 6e47b87..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/configuration.py +++ /dev/null @@ -1,266 +0,0 @@ -import logging -import os -import subprocess -from optparse import Values -from typing import Any, List, Optional - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.configuration import ( - Configuration, - Kind, - get_configuration_files, - kinds, -) -from pip._internal.exceptions import PipError -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import get_prog, write_output - -logger = logging.getLogger(__name__) - - -class ConfigurationCommand(Command): - """ - Manage local and global configuration. - - Subcommands: - - - list: List the active configuration (or from the file specified) - - edit: Edit the configuration file in an editor - - get: Get the value associated with name - - set: Set the name=value - - unset: Unset the value associated with name - - debug: List the configuration files and values defined under them - - If none of --user, --global and --site are passed, a virtual - environment configuration file is used if one is active and the file - exists. Otherwise, all modifications happen on the to the user file by - default. - """ - - ignore_require_venv = True - usage = """ - %prog [] list - %prog [] [--editor ] edit - - %prog [] get name - %prog [] set name value - %prog [] unset name - %prog [] debug - """ - - def add_options(self) -> None: - self.cmd_opts.add_option( - '--editor', - dest='editor', - action='store', - default=None, - help=( - 'Editor to use to edit the file. Uses VISUAL or EDITOR ' - 'environment variables if not provided.' - ) - ) - - self.cmd_opts.add_option( - '--global', - dest='global_file', - action='store_true', - default=False, - help='Use the system-wide configuration file only' - ) - - self.cmd_opts.add_option( - '--user', - dest='user_file', - action='store_true', - default=False, - help='Use the user configuration file only' - ) - - self.cmd_opts.add_option( - '--site', - dest='site_file', - action='store_true', - default=False, - help='Use the current environment configuration file only' - ) - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - handlers = { - "list": self.list_values, - "edit": self.open_in_editor, - "get": self.get_name, - "set": self.set_name_value, - "unset": self.unset_name, - "debug": self.list_config_values, - } - - # Determine action - if not args or args[0] not in handlers: - logger.error( - "Need an action (%s) to perform.", - ", ".join(sorted(handlers)), - ) - return ERROR - - action = args[0] - - # Determine which configuration files are to be loaded - # Depends on whether the command is modifying. - try: - load_only = self._determine_file( - options, need_value=(action in ["get", "set", "unset", "edit"]) - ) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - # Load a new configuration - self.configuration = Configuration( - isolated=options.isolated_mode, load_only=load_only - ) - self.configuration.load() - - # Error handling happens here, not in the action-handlers. - try: - handlers[action](options, args[1:]) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - return SUCCESS - - def _determine_file(self, options: Values, need_value: bool) -> Optional[Kind]: - file_options = [key for key, value in ( - (kinds.USER, options.user_file), - (kinds.GLOBAL, options.global_file), - (kinds.SITE, options.site_file), - ) if value] - - if not file_options: - if not need_value: - return None - # Default to user, unless there's a site file. - elif any( - os.path.exists(site_config_file) - for site_config_file in get_configuration_files()[kinds.SITE] - ): - return kinds.SITE - else: - return kinds.USER - elif len(file_options) == 1: - return file_options[0] - - raise PipError( - "Need exactly one file to operate upon " - "(--user, --site, --global) to perform." - ) - - def list_values(self, options: Values, args: List[str]) -> None: - self._get_n_args(args, "list", n=0) - - for key, value in sorted(self.configuration.items()): - write_output("%s=%r", key, value) - - def get_name(self, options: Values, args: List[str]) -> None: - key = self._get_n_args(args, "get [name]", n=1) - value = self.configuration.get_value(key) - - write_output("%s", value) - - def set_name_value(self, options: Values, args: List[str]) -> None: - key, value = self._get_n_args(args, "set [name] [value]", n=2) - self.configuration.set_value(key, value) - - self._save_configuration() - - def unset_name(self, options: Values, args: List[str]) -> None: - key = self._get_n_args(args, "unset [name]", n=1) - self.configuration.unset_value(key) - - self._save_configuration() - - def list_config_values(self, options: Values, args: List[str]) -> None: - """List config key-value pairs across different config files""" - self._get_n_args(args, "debug", n=0) - - self.print_env_var_values() - # Iterate over config files and print if they exist, and the - # key-value pairs present in them if they do - for variant, files in sorted(self.configuration.iter_config_files()): - write_output("%s:", variant) - for fname in files: - with indent_log(): - file_exists = os.path.exists(fname) - write_output("%s, exists: %r", - fname, file_exists) - if file_exists: - self.print_config_file_values(variant) - - def print_config_file_values(self, variant: Kind) -> None: - """Get key-value pairs from the file of a variant""" - for name, value in self.configuration.\ - get_values_in_config(variant).items(): - with indent_log(): - write_output("%s: %s", name, value) - - def print_env_var_values(self) -> None: - """Get key-values pairs present as environment variables""" - write_output("%s:", 'env_var') - with indent_log(): - for key, value in sorted(self.configuration.get_environ_vars()): - env_var = f'PIP_{key.upper()}' - write_output("%s=%r", env_var, value) - - def open_in_editor(self, options: Values, args: List[str]) -> None: - editor = self._determine_editor(options) - - fname = self.configuration.get_file_to_edit() - if fname is None: - raise PipError("Could not determine appropriate file.") - - try: - subprocess.check_call([editor, fname]) - except subprocess.CalledProcessError as e: - raise PipError( - "Editor Subprocess exited with exit code {}" - .format(e.returncode) - ) - - def _get_n_args(self, args: List[str], example: str, n: int) -> Any: - """Helper to make sure the command got the right number of arguments - """ - if len(args) != n: - msg = ( - 'Got unexpected number of arguments, expected {}. ' - '(example: "{} config {}")' - ).format(n, get_prog(), example) - raise PipError(msg) - - if n == 1: - return args[0] - else: - return args - - def _save_configuration(self) -> None: - # We successfully ran a modifying command. Need to save the - # configuration. - try: - self.configuration.save() - except Exception: - logger.exception( - "Unable to save configuration. Please report this as a bug." - ) - raise PipError("Internal Error.") - - def _determine_editor(self, options: Values) -> str: - if options.editor is not None: - return options.editor - elif "VISUAL" in os.environ: - return os.environ["VISUAL"] - elif "EDITOR" in os.environ: - return os.environ["EDITOR"] - else: - raise PipError("Could not determine editor to use.") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/debug.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/debug.py deleted file mode 100644 index b316b67..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/debug.py +++ /dev/null @@ -1,204 +0,0 @@ -import locale -import logging -import os -import sys -from optparse import Values -from types import ModuleType -from typing import Any, Dict, List, Optional - -import pip._vendor -from pip._vendor.certifi import where -from pip._vendor.packaging.version import parse as parse_version - -from pip import __file__ as pip_location -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.configuration import Configuration -from pip._internal.metadata import get_environment -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import get_pip_version - -logger = logging.getLogger(__name__) - - -def show_value(name: str, value: Any) -> None: - logger.info('%s: %s', name, value) - - -def show_sys_implementation() -> None: - logger.info('sys.implementation:') - implementation_name = sys.implementation.name - with indent_log(): - show_value('name', implementation_name) - - -def create_vendor_txt_map() -> Dict[str, str]: - vendor_txt_path = os.path.join( - os.path.dirname(pip_location), - '_vendor', - 'vendor.txt' - ) - - with open(vendor_txt_path) as f: - # Purge non version specifying lines. - # Also, remove any space prefix or suffixes (including comments). - lines = [line.strip().split(' ', 1)[0] - for line in f.readlines() if '==' in line] - - # Transform into "module" -> version dict. - return dict(line.split('==', 1) for line in lines) # type: ignore - - -def get_module_from_module_name(module_name: str) -> ModuleType: - # Module name can be uppercase in vendor.txt for some reason... - module_name = module_name.lower() - # PATCH: setuptools is actually only pkg_resources. - if module_name == 'setuptools': - module_name = 'pkg_resources' - - __import__( - f'pip._vendor.{module_name}', - globals(), - locals(), - level=0 - ) - return getattr(pip._vendor, module_name) - - -def get_vendor_version_from_module(module_name: str) -> Optional[str]: - module = get_module_from_module_name(module_name) - version = getattr(module, '__version__', None) - - if not version: - # Try to find version in debundled module info. - env = get_environment([os.path.dirname(module.__file__)]) - dist = env.get_distribution(module_name) - if dist: - version = str(dist.version) - - return version - - -def show_actual_vendor_versions(vendor_txt_versions: Dict[str, str]) -> None: - """Log the actual version and print extra info if there is - a conflict or if the actual version could not be imported. - """ - for module_name, expected_version in vendor_txt_versions.items(): - extra_message = '' - actual_version = get_vendor_version_from_module(module_name) - if not actual_version: - extra_message = ' (Unable to locate actual module version, using'\ - ' vendor.txt specified version)' - actual_version = expected_version - elif parse_version(actual_version) != parse_version(expected_version): - extra_message = ' (CONFLICT: vendor.txt suggests version should'\ - ' be {})'.format(expected_version) - logger.info('%s==%s%s', module_name, actual_version, extra_message) - - -def show_vendor_versions() -> None: - logger.info('vendored library versions:') - - vendor_txt_versions = create_vendor_txt_map() - with indent_log(): - show_actual_vendor_versions(vendor_txt_versions) - - -def show_tags(options: Values) -> None: - tag_limit = 10 - - target_python = make_target_python(options) - tags = target_python.get_tags() - - # Display the target options that were explicitly provided. - formatted_target = target_python.format_given() - suffix = '' - if formatted_target: - suffix = f' (target: {formatted_target})' - - msg = 'Compatible tags: {}{}'.format(len(tags), suffix) - logger.info(msg) - - if options.verbose < 1 and len(tags) > tag_limit: - tags_limited = True - tags = tags[:tag_limit] - else: - tags_limited = False - - with indent_log(): - for tag in tags: - logger.info(str(tag)) - - if tags_limited: - msg = ( - '...\n' - '[First {tag_limit} tags shown. Pass --verbose to show all.]' - ).format(tag_limit=tag_limit) - logger.info(msg) - - -def ca_bundle_info(config: Configuration) -> str: - levels = set() - for key, _ in config.items(): - levels.add(key.split('.')[0]) - - if not levels: - return "Not specified" - - levels_that_override_global = ['install', 'wheel', 'download'] - global_overriding_level = [ - level for level in levels if level in levels_that_override_global - ] - if not global_overriding_level: - return 'global' - - if 'global' in levels: - levels.remove('global') - return ", ".join(levels) - - -class DebugCommand(Command): - """ - Display debug information. - """ - - usage = """ - %prog """ - ignore_require_venv = True - - def add_options(self) -> None: - cmdoptions.add_target_python_options(self.cmd_opts) - self.parser.insert_option_group(0, self.cmd_opts) - self.parser.config.load() - - def run(self, options: Values, args: List[str]) -> int: - logger.warning( - "This command is only meant for debugging. " - "Do not use this with automation for parsing and getting these " - "details, since the output and options of this command may " - "change without notice." - ) - show_value('pip version', get_pip_version()) - show_value('sys.version', sys.version) - show_value('sys.executable', sys.executable) - show_value('sys.getdefaultencoding', sys.getdefaultencoding()) - show_value('sys.getfilesystemencoding', sys.getfilesystemencoding()) - show_value( - 'locale.getpreferredencoding', locale.getpreferredencoding(), - ) - show_value('sys.platform', sys.platform) - show_sys_implementation() - - show_value("'cert' config value", ca_bundle_info(self.parser.config)) - show_value("REQUESTS_CA_BUNDLE", os.environ.get('REQUESTS_CA_BUNDLE')) - show_value("CURL_CA_BUNDLE", os.environ.get('CURL_CA_BUNDLE')) - show_value("pip._vendor.certifi.where()", where()) - show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) - - show_vendor_versions() - - show_tags(options) - - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/download.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/download.py deleted file mode 100644 index 2302645..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/download.py +++ /dev/null @@ -1,139 +0,0 @@ -import logging -import os -from optparse import Values -from typing import List - -from pip._internal.cli import cmdoptions -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.misc import ensure_dir, normalize_path, write_output -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -class DownloadCommand(RequirementCommand): - """ - Download packages from: - - - PyPI (and other indexes) using requirement specifiers. - - VCS project urls. - - Local project directories. - - Local or remote source archives. - - pip also supports downloading from "requirements files", which provide - an easy way to specify a whole environment to be downloaded. - """ - - usage = """ - %prog [options] [package-index-options] ... - %prog [options] -r [package-index-options] ... - %prog [options] ... - %prog [options] ... - %prog [options] ...""" - - def add_options(self) -> None: - self.cmd_opts.add_option(cmdoptions.constraints()) - self.cmd_opts.add_option(cmdoptions.requirements()) - self.cmd_opts.add_option(cmdoptions.build_dir()) - self.cmd_opts.add_option(cmdoptions.no_deps()) - self.cmd_opts.add_option(cmdoptions.global_options()) - self.cmd_opts.add_option(cmdoptions.no_binary()) - self.cmd_opts.add_option(cmdoptions.only_binary()) - self.cmd_opts.add_option(cmdoptions.prefer_binary()) - self.cmd_opts.add_option(cmdoptions.src()) - self.cmd_opts.add_option(cmdoptions.pre()) - self.cmd_opts.add_option(cmdoptions.require_hashes()) - self.cmd_opts.add_option(cmdoptions.progress_bar()) - self.cmd_opts.add_option(cmdoptions.no_build_isolation()) - self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) - self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) - - self.cmd_opts.add_option( - '-d', '--dest', '--destination-dir', '--destination-directory', - dest='download_dir', - metavar='dir', - default=os.curdir, - help=("Download packages into ."), - ) - - cmdoptions.add_target_python_options(self.cmd_opts) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, self.cmd_opts) - - @with_cleanup - def run(self, options: Values, args: List[str]) -> int: - - options.ignore_installed = True - # editable doesn't really make sense for `pip download`, but the bowels - # of the RequirementSet code require that property. - options.editables = [] - - cmdoptions.check_dist_restriction(options) - - options.download_dir = normalize_path(options.download_dir) - ensure_dir(options.download_dir) - - session = self.get_default_session(options) - - target_python = make_target_python(options) - finder = self._build_package_finder( - options=options, - session=session, - target_python=target_python, - ignore_requires_python=options.ignore_requires_python, - ) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - delete=not options.no_clean, - kind="download", - globally_managed=True, - ) - - reqs = self.get_requirements(args, options, finder, session) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - download_dir=options.download_dir, - use_user_site=False, - ) - - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - ignore_requires_python=options.ignore_requires_python, - py_version_info=options.python_version, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) - - downloaded: List[str] = [] - for req in requirement_set.requirements.values(): - if req.satisfied_by is None: - assert req.name is not None - preparer.save_linked_requirement(req) - downloaded.append(req.name) - if downloaded: - write_output('Successfully downloaded %s', ' '.join(downloaded)) - - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/freeze.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/freeze.py deleted file mode 100644 index 1ccc875..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/freeze.py +++ /dev/null @@ -1,84 +0,0 @@ -import sys -from optparse import Values -from typing import List - -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.operations.freeze import freeze -from pip._internal.utils.compat import stdlib_pkgs - -DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} - - -class FreezeCommand(Command): - """ - Output installed packages in requirements format. - - packages are listed in a case-insensitive sorted order. - """ - - usage = """ - %prog [options]""" - log_streams = ("ext://sys.stderr", "ext://sys.stderr") - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', - default=[], - metavar='file', - help="Use the order in the given requirements file and its " - "comments when generating output. This option can be " - "used multiple times.") - self.cmd_opts.add_option( - '-l', '--local', - dest='local', - action='store_true', - default=False, - help='If in a virtualenv that has global access, do not output ' - 'globally-installed packages.') - self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', - default=False, - help='Only output packages installed in user-site.') - self.cmd_opts.add_option(cmdoptions.list_path()) - self.cmd_opts.add_option( - '--all', - dest='freeze_all', - action='store_true', - help='Do not skip these packages in the output:' - ' {}'.format(', '.join(DEV_PKGS))) - self.cmd_opts.add_option( - '--exclude-editable', - dest='exclude_editable', - action='store_true', - help='Exclude editable package from output.') - self.cmd_opts.add_option(cmdoptions.list_exclude()) - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - skip = set(stdlib_pkgs) - if not options.freeze_all: - skip.update(DEV_PKGS) - - if options.excludes: - skip.update(options.excludes) - - cmdoptions.check_list_path_option(options) - - for line in freeze( - requirement=options.requirements, - local_only=options.local, - user_only=options.user, - paths=options.path, - isolated=options.isolated_mode, - skip=skip, - exclude_editable=options.exclude_editable, - ): - sys.stdout.write(line + '\n') - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/hash.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/hash.py deleted file mode 100644 index 3e4c32f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/hash.py +++ /dev/null @@ -1,55 +0,0 @@ -import hashlib -import logging -import sys -from optparse import Values -from typing import List - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES -from pip._internal.utils.misc import read_chunks, write_output - -logger = logging.getLogger(__name__) - - -class HashCommand(Command): - """ - Compute a hash of a local package archive. - - These can be used with --hash in a requirements file to do repeatable - installs. - """ - - usage = '%prog [options] ...' - ignore_require_venv = True - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-a', '--algorithm', - dest='algorithm', - choices=STRONG_HASHES, - action='store', - default=FAVORITE_HASH, - help='The hash algorithm to use: one of {}'.format( - ', '.join(STRONG_HASHES))) - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - if not args: - self.parser.print_usage(sys.stderr) - return ERROR - - algorithm = options.algorithm - for path in args: - write_output('%s:\n--hash=%s:%s', - path, algorithm, _hash_of_file(path, algorithm)) - return SUCCESS - - -def _hash_of_file(path: str, algorithm: str) -> str: - """Return the hash digest of a file.""" - with open(path, 'rb') as archive: - hash = hashlib.new(algorithm) - for chunk in read_chunks(archive): - hash.update(chunk) - return hash.hexdigest() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/help.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/help.py deleted file mode 100644 index 811ce89..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/help.py +++ /dev/null @@ -1,41 +0,0 @@ -from optparse import Values -from typing import List - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.exceptions import CommandError - - -class HelpCommand(Command): - """Show help for commands""" - - usage = """ - %prog """ - ignore_require_venv = True - - def run(self, options: Values, args: List[str]) -> int: - from pip._internal.commands import ( - commands_dict, - create_command, - get_similar_commands, - ) - - try: - # 'pip help' with no args is handled by pip.__init__.parseopt() - cmd_name = args[0] # the command we need help for - except IndexError: - return SUCCESS - - if cmd_name not in commands_dict: - guess = get_similar_commands(cmd_name) - - msg = [f'unknown command "{cmd_name}"'] - if guess: - msg.append(f'maybe you meant "{guess}"') - - raise CommandError(' - '.join(msg)) - - command = create_command(cmd_name) - command.parser.print_help() - - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/index.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/index.py deleted file mode 100644 index c505464..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/index.py +++ /dev/null @@ -1,139 +0,0 @@ -import logging -from optparse import Values -from typing import Any, Iterable, List, Optional, Union - -from pip._vendor.packaging.version import LegacyVersion, Version - -from pip._internal.cli import cmdoptions -from pip._internal.cli.req_command import IndexGroupCommand -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.commands.search import print_dist_installation_info -from pip._internal.exceptions import CommandError, DistributionNotFound, PipError -from pip._internal.index.collector import LinkCollector -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.models.target_python import TargetPython -from pip._internal.network.session import PipSession -from pip._internal.utils.misc import write_output - -logger = logging.getLogger(__name__) - - -class IndexCommand(IndexGroupCommand): - """ - Inspect information available from package indexes. - """ - - usage = """ - %prog versions - """ - - def add_options(self) -> None: - cmdoptions.add_target_python_options(self.cmd_opts) - - self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) - self.cmd_opts.add_option(cmdoptions.pre()) - self.cmd_opts.add_option(cmdoptions.no_binary()) - self.cmd_opts.add_option(cmdoptions.only_binary()) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[Any]) -> int: - handlers = { - "versions": self.get_available_package_versions, - } - - logger.warning( - "pip index is currently an experimental command. " - "It may be removed/changed in a future release " - "without prior warning." - ) - - # Determine action - if not args or args[0] not in handlers: - logger.error( - "Need an action (%s) to perform.", - ", ".join(sorted(handlers)), - ) - return ERROR - - action = args[0] - - # Error handling happens here, not in the action-handlers. - try: - handlers[action](options, args[1:]) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - return SUCCESS - - def _build_package_finder( - self, - options: Values, - session: PipSession, - target_python: Optional[TargetPython] = None, - ignore_requires_python: Optional[bool] = None, - ) -> PackageFinder: - """ - Create a package finder appropriate to the index command. - """ - link_collector = LinkCollector.create(session, options=options) - - # Pass allow_yanked=False to ignore yanked versions. - selection_prefs = SelectionPreferences( - allow_yanked=False, - allow_all_prereleases=options.pre, - ignore_requires_python=ignore_requires_python, - ) - - return PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - target_python=target_python, - ) - - def get_available_package_versions(self, options: Values, args: List[Any]) -> None: - if len(args) != 1: - raise CommandError('You need to specify exactly one argument') - - target_python = cmdoptions.make_target_python(options) - query = args[0] - - with self._build_session(options) as session: - finder = self._build_package_finder( - options=options, - session=session, - target_python=target_python, - ignore_requires_python=options.ignore_requires_python, - ) - - versions: Iterable[Union[LegacyVersion, Version]] = ( - candidate.version - for candidate in finder.find_all_candidates(query) - ) - - if not options.pre: - # Remove prereleases - versions = (version for version in versions - if not version.is_prerelease) - versions = set(versions) - - if not versions: - raise DistributionNotFound( - 'No matching distribution found for {}'.format(query)) - - formatted_versions = [str(ver) for ver in sorted( - versions, reverse=True)] - latest = formatted_versions[0] - - write_output('{} ({})'.format(query, latest)) - write_output('Available versions: {}'.format( - ', '.join(formatted_versions))) - print_dist_installation_info(query, latest) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/install.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/install.py deleted file mode 100644 index 02da077..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/install.py +++ /dev/null @@ -1,750 +0,0 @@ -import errno -import operator -import os -import shutil -import site -from optparse import SUPPRESS_HELP, Values -from typing import Iterable, List, Optional - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.req_command import ( - RequirementCommand, - warn_if_run_as_root, - with_cleanup, -) -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.exceptions import CommandError, InstallationError -from pip._internal.locations import get_scheme -from pip._internal.metadata import get_environment -from pip._internal.models.format_control import FormatControl -from pip._internal.operations.check import ConflictDetails, check_install_conflicts -from pip._internal.req import install_given_reqs -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.distutils_args import parse_distutils_args -from pip._internal.utils.filesystem import test_writable_dir -from pip._internal.utils.logging import getLogger -from pip._internal.utils.misc import ( - ensure_dir, - get_pip_version, - protect_pip_from_modification_on_windows, - write_output, -) -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.virtualenv import ( - running_under_virtualenv, - virtualenv_no_global, -) -from pip._internal.wheel_builder import ( - BinaryAllowedPredicate, - build, - should_build_for_install_command, -) - -logger = getLogger(__name__) - - -def get_check_binary_allowed(format_control: FormatControl) -> BinaryAllowedPredicate: - def check_binary_allowed(req: InstallRequirement) -> bool: - canonical_name = canonicalize_name(req.name or "") - allowed_formats = format_control.get_allowed_formats(canonical_name) - return "binary" in allowed_formats - - return check_binary_allowed - - -class InstallCommand(RequirementCommand): - """ - Install packages from: - - - PyPI (and other indexes) using requirement specifiers. - - VCS project urls. - - Local project directories. - - Local or remote source archives. - - pip also supports installing from "requirements files", which provide - an easy way to specify a whole environment to be installed. - """ - - usage = """ - %prog [options] [package-index-options] ... - %prog [options] -r [package-index-options] ... - %prog [options] [-e] ... - %prog [options] [-e] ... - %prog [options] ...""" - - def add_options(self) -> None: - self.cmd_opts.add_option(cmdoptions.requirements()) - self.cmd_opts.add_option(cmdoptions.constraints()) - self.cmd_opts.add_option(cmdoptions.no_deps()) - self.cmd_opts.add_option(cmdoptions.pre()) - - self.cmd_opts.add_option(cmdoptions.editable()) - self.cmd_opts.add_option( - '-t', '--target', - dest='target_dir', - metavar='dir', - default=None, - help='Install packages into . ' - 'By default this will not replace existing files/folders in ' - '. Use --upgrade to replace existing packages in ' - 'with new versions.' - ) - cmdoptions.add_target_python_options(self.cmd_opts) - - self.cmd_opts.add_option( - '--user', - dest='use_user_site', - action='store_true', - help="Install to the Python user install directory for your " - "platform. Typically ~/.local/, or %APPDATA%\\Python on " - "Windows. (See the Python documentation for site.USER_BASE " - "for full details.)") - self.cmd_opts.add_option( - '--no-user', - dest='use_user_site', - action='store_false', - help=SUPPRESS_HELP) - self.cmd_opts.add_option( - '--root', - dest='root_path', - metavar='dir', - default=None, - help="Install everything relative to this alternate root " - "directory.") - self.cmd_opts.add_option( - '--prefix', - dest='prefix_path', - metavar='dir', - default=None, - help="Installation prefix where lib, bin and other top-level " - "folders are placed") - - self.cmd_opts.add_option(cmdoptions.build_dir()) - - self.cmd_opts.add_option(cmdoptions.src()) - - self.cmd_opts.add_option( - '-U', '--upgrade', - dest='upgrade', - action='store_true', - help='Upgrade all specified packages to the newest available ' - 'version. The handling of dependencies depends on the ' - 'upgrade-strategy used.' - ) - - self.cmd_opts.add_option( - '--upgrade-strategy', - dest='upgrade_strategy', - default='only-if-needed', - choices=['only-if-needed', 'eager'], - help='Determines how dependency upgrading should be handled ' - '[default: %default]. ' - '"eager" - dependencies are upgraded regardless of ' - 'whether the currently installed version satisfies the ' - 'requirements of the upgraded package(s). ' - '"only-if-needed" - are upgraded only when they do not ' - 'satisfy the requirements of the upgraded package(s).' - ) - - self.cmd_opts.add_option( - '--force-reinstall', - dest='force_reinstall', - action='store_true', - help='Reinstall all packages even if they are already ' - 'up-to-date.') - - self.cmd_opts.add_option( - '-I', '--ignore-installed', - dest='ignore_installed', - action='store_true', - help='Ignore the installed packages, overwriting them. ' - 'This can break your system if the existing package ' - 'is of a different version or was installed ' - 'with a different package manager!' - ) - - self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) - self.cmd_opts.add_option(cmdoptions.no_build_isolation()) - self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) - - self.cmd_opts.add_option(cmdoptions.install_options()) - self.cmd_opts.add_option(cmdoptions.global_options()) - - self.cmd_opts.add_option( - "--compile", - action="store_true", - dest="compile", - default=True, - help="Compile Python source files to bytecode", - ) - - self.cmd_opts.add_option( - "--no-compile", - action="store_false", - dest="compile", - help="Do not compile Python source files to bytecode", - ) - - self.cmd_opts.add_option( - "--no-warn-script-location", - action="store_false", - dest="warn_script_location", - default=True, - help="Do not warn when installing scripts outside PATH", - ) - self.cmd_opts.add_option( - "--no-warn-conflicts", - action="store_false", - dest="warn_about_conflicts", - default=True, - help="Do not warn about broken dependencies", - ) - - self.cmd_opts.add_option(cmdoptions.no_binary()) - self.cmd_opts.add_option(cmdoptions.only_binary()) - self.cmd_opts.add_option(cmdoptions.prefer_binary()) - self.cmd_opts.add_option(cmdoptions.require_hashes()) - self.cmd_opts.add_option(cmdoptions.progress_bar()) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, self.cmd_opts) - - @with_cleanup - def run(self, options: Values, args: List[str]) -> int: - if options.use_user_site and options.target_dir is not None: - raise CommandError("Can not combine '--user' and '--target'") - - cmdoptions.check_install_build_global(options) - upgrade_strategy = "to-satisfy-only" - if options.upgrade: - upgrade_strategy = options.upgrade_strategy - - cmdoptions.check_dist_restriction(options, check_target=True) - - install_options = options.install_options or [] - - logger.verbose("Using %s", get_pip_version()) - options.use_user_site = decide_user_install( - options.use_user_site, - prefix_path=options.prefix_path, - target_dir=options.target_dir, - root_path=options.root_path, - isolated_mode=options.isolated_mode, - ) - - target_temp_dir: Optional[TempDirectory] = None - target_temp_dir_path: Optional[str] = None - if options.target_dir: - options.ignore_installed = True - options.target_dir = os.path.abspath(options.target_dir) - if (os.path.exists(options.target_dir) and not - os.path.isdir(options.target_dir)): - raise CommandError( - "Target path exists but is not a directory, will not " - "continue." - ) - - # Create a target directory for using with the target option - target_temp_dir = TempDirectory(kind="target") - target_temp_dir_path = target_temp_dir.path - self.enter_context(target_temp_dir) - - global_options = options.global_options or [] - - session = self.get_default_session(options) - - target_python = make_target_python(options) - finder = self._build_package_finder( - options=options, - session=session, - target_python=target_python, - ignore_requires_python=options.ignore_requires_python, - ) - wheel_cache = WheelCache(options.cache_dir, options.format_control) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - delete=not options.no_clean, - kind="install", - globally_managed=True, - ) - - try: - reqs = self.get_requirements(args, options, finder, session) - - reject_location_related_install_options( - reqs, options.install_options - ) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - use_user_site=options.use_user_site, - ) - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - wheel_cache=wheel_cache, - use_user_site=options.use_user_site, - ignore_installed=options.ignore_installed, - ignore_requires_python=options.ignore_requires_python, - force_reinstall=options.force_reinstall, - upgrade_strategy=upgrade_strategy, - use_pep517=options.use_pep517, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=not options.target_dir - ) - - try: - pip_req = requirement_set.get_requirement("pip") - except KeyError: - modifying_pip = False - else: - # If we're not replacing an already installed pip, - # we're not modifying it. - modifying_pip = pip_req.satisfied_by is None - protect_pip_from_modification_on_windows( - modifying_pip=modifying_pip - ) - - check_binary_allowed = get_check_binary_allowed( - finder.format_control - ) - - reqs_to_build = [ - r for r in requirement_set.requirements.values() - if should_build_for_install_command( - r, check_binary_allowed - ) - ] - - _, build_failures = build( - reqs_to_build, - wheel_cache=wheel_cache, - verify=True, - build_options=[], - global_options=[], - ) - - # If we're using PEP 517, we cannot do a direct install - # so we fail here. - pep517_build_failure_names: List[str] = [ - r.name # type: ignore - for r in build_failures if r.use_pep517 - ] - if pep517_build_failure_names: - raise InstallationError( - "Could not build wheels for {} which use" - " PEP 517 and cannot be installed directly".format( - ", ".join(pep517_build_failure_names) - ) - ) - - # For now, we just warn about failures building legacy - # requirements, as we'll fall through to a direct - # install for those. - for r in build_failures: - if not r.use_pep517: - r.legacy_install_reason = 8368 - - to_install = resolver.get_installation_order( - requirement_set - ) - - # Check for conflicts in the package set we're installing. - conflicts: Optional[ConflictDetails] = None - should_warn_about_conflicts = ( - not options.ignore_dependencies and - options.warn_about_conflicts - ) - if should_warn_about_conflicts: - conflicts = self._determine_conflicts(to_install) - - # Don't warn about script install locations if - # --target or --prefix has been specified - warn_script_location = options.warn_script_location - if options.target_dir or options.prefix_path: - warn_script_location = False - - installed = install_given_reqs( - to_install, - install_options, - global_options, - root=options.root_path, - home=target_temp_dir_path, - prefix=options.prefix_path, - warn_script_location=warn_script_location, - use_user_site=options.use_user_site, - pycompile=options.compile, - ) - - lib_locations = get_lib_location_guesses( - user=options.use_user_site, - home=target_temp_dir_path, - root=options.root_path, - prefix=options.prefix_path, - isolated=options.isolated_mode, - ) - env = get_environment(lib_locations) - - installed.sort(key=operator.attrgetter('name')) - items = [] - for result in installed: - item = result.name - try: - installed_dist = env.get_distribution(item) - if installed_dist is not None: - item = f"{item}-{installed_dist.version}" - except Exception: - pass - items.append(item) - - if conflicts is not None: - self._warn_about_conflicts( - conflicts, - resolver_variant=self.determine_resolver_variant(options), - ) - - installed_desc = ' '.join(items) - if installed_desc: - write_output( - 'Successfully installed %s', installed_desc, - ) - except OSError as error: - show_traceback = (self.verbosity >= 1) - - message = create_os_error_message( - error, show_traceback, options.use_user_site, - ) - logger.error(message, exc_info=show_traceback) # noqa - - return ERROR - - if options.target_dir: - assert target_temp_dir - self._handle_target_dir( - options.target_dir, target_temp_dir, options.upgrade - ) - - warn_if_run_as_root() - return SUCCESS - - def _handle_target_dir( - self, target_dir: str, target_temp_dir: TempDirectory, upgrade: bool - ) -> None: - ensure_dir(target_dir) - - # Checking both purelib and platlib directories for installed - # packages to be moved to target directory - lib_dir_list = [] - - # Checking both purelib and platlib directories for installed - # packages to be moved to target directory - scheme = get_scheme('', home=target_temp_dir.path) - purelib_dir = scheme.purelib - platlib_dir = scheme.platlib - data_dir = scheme.data - - if os.path.exists(purelib_dir): - lib_dir_list.append(purelib_dir) - if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: - lib_dir_list.append(platlib_dir) - if os.path.exists(data_dir): - lib_dir_list.append(data_dir) - - for lib_dir in lib_dir_list: - for item in os.listdir(lib_dir): - if lib_dir == data_dir: - ddir = os.path.join(data_dir, item) - if any(s.startswith(ddir) for s in lib_dir_list[:-1]): - continue - target_item_dir = os.path.join(target_dir, item) - if os.path.exists(target_item_dir): - if not upgrade: - logger.warning( - 'Target directory %s already exists. Specify ' - '--upgrade to force replacement.', - target_item_dir - ) - continue - if os.path.islink(target_item_dir): - logger.warning( - 'Target directory %s already exists and is ' - 'a link. pip will not automatically replace ' - 'links, please remove if replacement is ' - 'desired.', - target_item_dir - ) - continue - if os.path.isdir(target_item_dir): - shutil.rmtree(target_item_dir) - else: - os.remove(target_item_dir) - - shutil.move( - os.path.join(lib_dir, item), - target_item_dir - ) - - def _determine_conflicts( - self, to_install: List[InstallRequirement] - ) -> Optional[ConflictDetails]: - try: - return check_install_conflicts(to_install) - except Exception: - logger.exception( - "Error while checking for conflicts. Please file an issue on " - "pip's issue tracker: https://github.com/pypa/pip/issues/new" - ) - return None - - def _warn_about_conflicts( - self, conflict_details: ConflictDetails, resolver_variant: str - ) -> None: - package_set, (missing, conflicting) = conflict_details - if not missing and not conflicting: - return - - parts: List[str] = [] - if resolver_variant == "legacy": - parts.append( - "pip's legacy dependency resolver does not consider dependency " - "conflicts when selecting packages. This behaviour is the " - "source of the following dependency conflicts." - ) - else: - assert resolver_variant == "2020-resolver" - parts.append( - "pip's dependency resolver does not currently take into account " - "all the packages that are installed. This behaviour is the " - "source of the following dependency conflicts." - ) - - # NOTE: There is some duplication here, with commands/check.py - for project_name in missing: - version = package_set[project_name][0] - for dependency in missing[project_name]: - message = ( - "{name} {version} requires {requirement}, " - "which is not installed." - ).format( - name=project_name, - version=version, - requirement=dependency[1], - ) - parts.append(message) - - for project_name in conflicting: - version = package_set[project_name][0] - for dep_name, dep_version, req in conflicting[project_name]: - message = ( - "{name} {version} requires {requirement}, but {you} have " - "{dep_name} {dep_version} which is incompatible." - ).format( - name=project_name, - version=version, - requirement=req, - dep_name=dep_name, - dep_version=dep_version, - you=("you" if resolver_variant == "2020-resolver" else "you'll") - ) - parts.append(message) - - logger.critical("\n".join(parts)) - - -def get_lib_location_guesses( - user: bool = False, - home: Optional[str] = None, - root: Optional[str] = None, - isolated: bool = False, - prefix: Optional[str] = None -) -> List[str]: - scheme = get_scheme( - '', - user=user, - home=home, - root=root, - isolated=isolated, - prefix=prefix, - ) - return [scheme.purelib, scheme.platlib] - - -def site_packages_writable(root: Optional[str], isolated: bool) -> bool: - return all( - test_writable_dir(d) for d in set( - get_lib_location_guesses(root=root, isolated=isolated)) - ) - - -def decide_user_install( - use_user_site: Optional[bool], - prefix_path: Optional[str] = None, - target_dir: Optional[str] = None, - root_path: Optional[str] = None, - isolated_mode: bool = False, -) -> bool: - """Determine whether to do a user install based on the input options. - - If use_user_site is False, no additional checks are done. - If use_user_site is True, it is checked for compatibility with other - options. - If use_user_site is None, the default behaviour depends on the environment, - which is provided by the other arguments. - """ - # In some cases (config from tox), use_user_site can be set to an integer - # rather than a bool, which 'use_user_site is False' wouldn't catch. - if (use_user_site is not None) and (not use_user_site): - logger.debug("Non-user install by explicit request") - return False - - if use_user_site: - if prefix_path: - raise CommandError( - "Can not combine '--user' and '--prefix' as they imply " - "different installation locations" - ) - if virtualenv_no_global(): - raise InstallationError( - "Can not perform a '--user' install. User site-packages " - "are not visible in this virtualenv." - ) - logger.debug("User install by explicit request") - return True - - # If we are here, user installs have not been explicitly requested/avoided - assert use_user_site is None - - # user install incompatible with --prefix/--target - if prefix_path or target_dir: - logger.debug("Non-user install due to --prefix or --target option") - return False - - # If user installs are not enabled, choose a non-user install - if not site.ENABLE_USER_SITE: - logger.debug("Non-user install because user site-packages disabled") - return False - - # If we have permission for a non-user install, do that, - # otherwise do a user install. - if site_packages_writable(root=root_path, isolated=isolated_mode): - logger.debug("Non-user install because site-packages writeable") - return False - - logger.info("Defaulting to user installation because normal site-packages " - "is not writeable") - return True - - -def reject_location_related_install_options( - requirements: List[InstallRequirement], options: Optional[List[str]] -) -> None: - """If any location-changing --install-option arguments were passed for - requirements or on the command-line, then show a deprecation warning. - """ - def format_options(option_names: Iterable[str]) -> List[str]: - return ["--{}".format(name.replace("_", "-")) for name in option_names] - - offenders = [] - - for requirement in requirements: - install_options = requirement.install_options - location_options = parse_distutils_args(install_options) - if location_options: - offenders.append( - "{!r} from {}".format( - format_options(location_options.keys()), requirement - ) - ) - - if options: - location_options = parse_distutils_args(options) - if location_options: - offenders.append( - "{!r} from command line".format( - format_options(location_options.keys()) - ) - ) - - if not offenders: - return - - raise CommandError( - "Location-changing options found in --install-option: {}." - " This is unsupported, use pip-level options like --user," - " --prefix, --root, and --target instead.".format( - "; ".join(offenders) - ) - ) - - -def create_os_error_message( - error: OSError, show_traceback: bool, using_user_site: bool -) -> str: - """Format an error message for an OSError - - It may occur anytime during the execution of the install command. - """ - parts = [] - - # Mention the error if we are not going to show a traceback - parts.append("Could not install packages due to an OSError") - if not show_traceback: - parts.append(": ") - parts.append(str(error)) - else: - parts.append(".") - - # Spilt the error indication from a helper message (if any) - parts[-1] += "\n" - - # Suggest useful actions to the user: - # (1) using user site-packages or (2) verifying the permissions - if error.errno == errno.EACCES: - user_option_part = "Consider using the `--user` option" - permissions_part = "Check the permissions" - - if not running_under_virtualenv() and not using_user_site: - parts.extend([ - user_option_part, " or ", - permissions_part.lower(), - ]) - else: - parts.append(permissions_part) - parts.append(".\n") - - # Suggest the user to enable Long Paths if path length is - # more than 260 - if (WINDOWS and error.errno == errno.ENOENT and error.filename and - len(error.filename) > 260): - parts.append( - "HINT: This error might have occurred since " - "this system does not have Windows Long Path " - "support enabled. You can find information on " - "how to enable this at " - "https://pip.pypa.io/warnings/enable-long-paths\n" - ) - - return "".join(parts).strip() + "\n" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/list.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/list.py deleted file mode 100644 index 828889f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/list.py +++ /dev/null @@ -1,337 +0,0 @@ -import json -import logging -from optparse import Values -from typing import TYPE_CHECKING, Iterator, List, Optional, Sequence, Tuple, cast - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli import cmdoptions -from pip._internal.cli.req_command import IndexGroupCommand -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.exceptions import CommandError -from pip._internal.index.collector import LinkCollector -from pip._internal.index.package_finder import PackageFinder -from pip._internal.metadata import BaseDistribution, get_environment -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.network.session import PipSession -from pip._internal.utils.misc import stdlib_pkgs, tabulate, write_output -from pip._internal.utils.parallel import map_multithread - -if TYPE_CHECKING: - from pip._internal.metadata.base import DistributionVersion - - class _DistWithLatestInfo(BaseDistribution): - """Give the distribution object a couple of extra fields. - - These will be populated during ``get_outdated()``. This is dirty but - makes the rest of the code much cleaner. - """ - latest_version: DistributionVersion - latest_filetype: str - - _ProcessedDists = Sequence[_DistWithLatestInfo] - - -logger = logging.getLogger(__name__) - - -class ListCommand(IndexGroupCommand): - """ - List installed packages, including editables. - - Packages are listed in a case-insensitive sorted order. - """ - - ignore_require_venv = True - usage = """ - %prog [options]""" - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-o', '--outdated', - action='store_true', - default=False, - help='List outdated packages') - self.cmd_opts.add_option( - '-u', '--uptodate', - action='store_true', - default=False, - help='List uptodate packages') - self.cmd_opts.add_option( - '-e', '--editable', - action='store_true', - default=False, - help='List editable projects.') - self.cmd_opts.add_option( - '-l', '--local', - action='store_true', - default=False, - help=('If in a virtualenv that has global access, do not list ' - 'globally-installed packages.'), - ) - self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', - default=False, - help='Only output packages installed in user-site.') - self.cmd_opts.add_option(cmdoptions.list_path()) - self.cmd_opts.add_option( - '--pre', - action='store_true', - default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), - ) - - self.cmd_opts.add_option( - '--format', - action='store', - dest='list_format', - default="columns", - choices=('columns', 'freeze', 'json'), - help="Select the output format among: columns (default), freeze, " - "or json", - ) - - self.cmd_opts.add_option( - '--not-required', - action='store_true', - dest='not_required', - help="List packages that are not dependencies of " - "installed packages.", - ) - - self.cmd_opts.add_option( - '--exclude-editable', - action='store_false', - dest='include_editable', - help='Exclude editable package from output.', - ) - self.cmd_opts.add_option( - '--include-editable', - action='store_true', - dest='include_editable', - help='Include editable package from output.', - default=True, - ) - self.cmd_opts.add_option(cmdoptions.list_exclude()) - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, self.parser - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, self.cmd_opts) - - def _build_package_finder( - self, options: Values, session: PipSession - ) -> PackageFinder: - """ - Create a package finder appropriate to this list command. - """ - link_collector = LinkCollector.create(session, options=options) - - # Pass allow_yanked=False to ignore yanked versions. - selection_prefs = SelectionPreferences( - allow_yanked=False, - allow_all_prereleases=options.pre, - ) - - return PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - ) - - def run(self, options: Values, args: List[str]) -> int: - if options.outdated and options.uptodate: - raise CommandError( - "Options --outdated and --uptodate cannot be combined.") - - cmdoptions.check_list_path_option(options) - - skip = set(stdlib_pkgs) - if options.excludes: - skip.update(canonicalize_name(n) for n in options.excludes) - - packages: "_ProcessedDists" = [ - cast("_DistWithLatestInfo", d) - for d in get_environment(options.path).iter_installed_distributions( - local_only=options.local, - user_only=options.user, - editables_only=options.editable, - include_editables=options.include_editable, - skip=skip, - ) - ] - - # get_not_required must be called firstly in order to find and - # filter out all dependencies correctly. Otherwise a package - # can't be identified as requirement because some parent packages - # could be filtered out before. - if options.not_required: - packages = self.get_not_required(packages, options) - - if options.outdated: - packages = self.get_outdated(packages, options) - elif options.uptodate: - packages = self.get_uptodate(packages, options) - - self.output_package_listing(packages, options) - return SUCCESS - - def get_outdated( - self, packages: "_ProcessedDists", options: Values - ) -> "_ProcessedDists": - return [ - dist for dist in self.iter_packages_latest_infos(packages, options) - if dist.latest_version > dist.version - ] - - def get_uptodate( - self, packages: "_ProcessedDists", options: Values - ) -> "_ProcessedDists": - return [ - dist for dist in self.iter_packages_latest_infos(packages, options) - if dist.latest_version == dist.version - ] - - def get_not_required( - self, packages: "_ProcessedDists", options: Values - ) -> "_ProcessedDists": - dep_keys = { - canonicalize_name(dep.name) - for dist in packages - for dep in (dist.iter_dependencies() or ()) - } - - # Create a set to remove duplicate packages, and cast it to a list - # to keep the return type consistent with get_outdated and - # get_uptodate - return list({pkg for pkg in packages if pkg.canonical_name not in dep_keys}) - - def iter_packages_latest_infos( - self, packages: "_ProcessedDists", options: Values - ) -> Iterator["_DistWithLatestInfo"]: - with self._build_session(options) as session: - finder = self._build_package_finder(options, session) - - def latest_info( - dist: "_DistWithLatestInfo" - ) -> Optional["_DistWithLatestInfo"]: - all_candidates = finder.find_all_candidates(dist.canonical_name) - if not options.pre: - # Remove prereleases - all_candidates = [candidate for candidate in all_candidates - if not candidate.version.is_prerelease] - - evaluator = finder.make_candidate_evaluator( - project_name=dist.canonical_name, - ) - best_candidate = evaluator.sort_best_candidate(all_candidates) - if best_candidate is None: - return None - - remote_version = best_candidate.version - if best_candidate.link.is_wheel: - typ = 'wheel' - else: - typ = 'sdist' - dist.latest_version = remote_version - dist.latest_filetype = typ - return dist - - for dist in map_multithread(latest_info, packages): - if dist is not None: - yield dist - - def output_package_listing( - self, packages: "_ProcessedDists", options: Values - ) -> None: - packages = sorted( - packages, - key=lambda dist: dist.canonical_name, - ) - if options.list_format == 'columns' and packages: - data, header = format_for_columns(packages, options) - self.output_package_listing_columns(data, header) - elif options.list_format == 'freeze': - for dist in packages: - if options.verbose >= 1: - write_output("%s==%s (%s)", dist.raw_name, - dist.version, dist.location) - else: - write_output("%s==%s", dist.raw_name, dist.version) - elif options.list_format == 'json': - write_output(format_for_json(packages, options)) - - def output_package_listing_columns( - self, data: List[List[str]], header: List[str] - ) -> None: - # insert the header first: we need to know the size of column names - if len(data) > 0: - data.insert(0, header) - - pkg_strings, sizes = tabulate(data) - - # Create and add a separator. - if len(data) > 0: - pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) - - for val in pkg_strings: - write_output(val) - - -def format_for_columns( - pkgs: "_ProcessedDists", options: Values -) -> Tuple[List[List[str]], List[str]]: - """ - Convert the package data into something usable - by output_package_listing_columns. - """ - running_outdated = options.outdated - # Adjust the header for the `pip list --outdated` case. - if running_outdated: - header = ["Package", "Version", "Latest", "Type"] - else: - header = ["Package", "Version"] - - data = [] - if options.verbose >= 1 or any(x.editable for x in pkgs): - header.append("Location") - if options.verbose >= 1: - header.append("Installer") - - for proj in pkgs: - # if we're working on the 'outdated' list, separate out the - # latest_version and type - row = [proj.raw_name, str(proj.version)] - - if running_outdated: - row.append(str(proj.latest_version)) - row.append(proj.latest_filetype) - - if options.verbose >= 1 or proj.editable: - row.append(proj.location or "") - if options.verbose >= 1: - row.append(proj.installer) - - data.append(row) - - return data, header - - -def format_for_json(packages: "_ProcessedDists", options: Values) -> str: - data = [] - for dist in packages: - info = { - 'name': dist.raw_name, - 'version': str(dist.version), - } - if options.verbose >= 1: - info['location'] = dist.location or "" - info['installer'] = dist.installer - if options.outdated: - info['latest_version'] = str(dist.latest_version) - info['latest_filetype'] = dist.latest_filetype - data.append(info) - return json.dumps(data) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/search.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/search.py deleted file mode 100644 index 7a20ba1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/search.py +++ /dev/null @@ -1,164 +0,0 @@ -import logging -import shutil -import sys -import textwrap -import xmlrpc.client -from collections import OrderedDict -from optparse import Values -from typing import TYPE_CHECKING, Dict, List, Optional - -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.cli.base_command import Command -from pip._internal.cli.req_command import SessionCommandMixin -from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS -from pip._internal.exceptions import CommandError -from pip._internal.metadata import get_default_environment -from pip._internal.models.index import PyPI -from pip._internal.network.xmlrpc import PipXmlrpcTransport -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import write_output - -if TYPE_CHECKING: - from typing import TypedDict - - class TransformedHit(TypedDict): - name: str - summary: str - versions: List[str] - -logger = logging.getLogger(__name__) - - -class SearchCommand(Command, SessionCommandMixin): - """Search for PyPI packages whose name or summary contains .""" - - usage = """ - %prog [options] """ - ignore_require_venv = True - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-i', '--index', - dest='index', - metavar='URL', - default=PyPI.pypi_url, - help='Base URL of Python Package Index (default %default)') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - if not args: - raise CommandError('Missing required argument (search query).') - query = args - pypi_hits = self.search(query, options) - hits = transform_hits(pypi_hits) - - terminal_width = None - if sys.stdout.isatty(): - terminal_width = shutil.get_terminal_size()[0] - - print_results(hits, terminal_width=terminal_width) - if pypi_hits: - return SUCCESS - return NO_MATCHES_FOUND - - def search(self, query: List[str], options: Values) -> List[Dict[str, str]]: - index_url = options.index - - session = self.get_default_session(options) - - transport = PipXmlrpcTransport(index_url, session) - pypi = xmlrpc.client.ServerProxy(index_url, transport) - try: - hits = pypi.search({'name': query, 'summary': query}, 'or') - except xmlrpc.client.Fault as fault: - message = "XMLRPC request failed [code: {code}]\n{string}".format( - code=fault.faultCode, - string=fault.faultString, - ) - raise CommandError(message) - assert isinstance(hits, list) - return hits - - -def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]: - """ - The list from pypi is really a list of versions. We want a list of - packages with the list of versions stored inline. This converts the - list from pypi into one we can use. - """ - packages: Dict[str, "TransformedHit"] = OrderedDict() - for hit in hits: - name = hit['name'] - summary = hit['summary'] - version = hit['version'] - - if name not in packages.keys(): - packages[name] = { - 'name': name, - 'summary': summary, - 'versions': [version], - } - else: - packages[name]['versions'].append(version) - - # if this is the highest version, replace summary and score - if version == highest_version(packages[name]['versions']): - packages[name]['summary'] = summary - - return list(packages.values()) - - -def print_dist_installation_info(name: str, latest: str) -> None: - env = get_default_environment() - dist = env.get_distribution(name) - if dist is not None: - with indent_log(): - if dist.version == latest: - write_output('INSTALLED: %s (latest)', dist.version) - else: - write_output('INSTALLED: %s', dist.version) - if parse_version(latest).pre: - write_output('LATEST: %s (pre-release; install' - ' with "pip install --pre")', latest) - else: - write_output('LATEST: %s', latest) - - -def print_results( - hits: List["TransformedHit"], - name_column_width: Optional[int] = None, - terminal_width: Optional[int] = None, -) -> None: - if not hits: - return - if name_column_width is None: - name_column_width = max([ - len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) - for hit in hits - ]) + 4 - - for hit in hits: - name = hit['name'] - summary = hit['summary'] or '' - latest = highest_version(hit.get('versions', ['-'])) - if terminal_width is not None: - target_width = terminal_width - name_column_width - 5 - if target_width > 10: - # wrap and indent summary to fit terminal - summary_lines = textwrap.wrap(summary, target_width) - summary = ('\n' + ' ' * (name_column_width + 3)).join( - summary_lines) - - name_latest = f'{name} ({latest})' - line = f'{name_latest:{name_column_width}} - {summary}' - try: - write_output(line) - print_dist_installation_info(name, latest) - except UnicodeEncodeError: - pass - - -def highest_version(versions: List[str]) -> str: - return max(versions, key=parse_version) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/show.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/show.py deleted file mode 100644 index 5b2de39..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/show.py +++ /dev/null @@ -1,234 +0,0 @@ -import csv -import logging -import pathlib -from optparse import Values -from typing import Iterator, List, NamedTuple, Optional, Tuple - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.metadata import BaseDistribution, get_default_environment -from pip._internal.utils.misc import write_output - -logger = logging.getLogger(__name__) - - -class ShowCommand(Command): - """ - Show information about one or more installed packages. - - The output is in RFC-compliant mail header format. - """ - - usage = """ - %prog [options] ...""" - ignore_require_venv = True - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-f', '--files', - dest='files', - action='store_true', - default=False, - help='Show the full list of installed files for each package.') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - if not args: - logger.warning('ERROR: Please provide a package name or names.') - return ERROR - query = args - - results = search_packages_info(query) - if not print_results( - results, list_files=options.files, verbose=options.verbose): - return ERROR - return SUCCESS - - -class _PackageInfo(NamedTuple): - name: str - version: str - location: str - requires: List[str] - required_by: List[str] - installer: str - metadata_version: str - classifiers: List[str] - summary: str - homepage: str - author: str - author_email: str - license: str - entry_points: List[str] - files: Optional[List[str]] - - -def _covert_legacy_entry(entry: Tuple[str, ...], info: Tuple[str, ...]) -> str: - """Convert a legacy installed-files.txt path into modern RECORD path. - - The legacy format stores paths relative to the info directory, while the - modern format stores paths relative to the package root, e.g. the - site-packages directory. - - :param entry: Path parts of the installed-files.txt entry. - :param info: Path parts of the egg-info directory relative to package root. - :returns: The converted entry. - - For best compatibility with symlinks, this does not use ``abspath()`` or - ``Path.resolve()``, but tries to work with path parts: - - 1. While ``entry`` starts with ``..``, remove the equal amounts of parts - from ``info``; if ``info`` is empty, start appending ``..`` instead. - 2. Join the two directly. - """ - while entry and entry[0] == "..": - if not info or info[-1] == "..": - info += ("..",) - else: - info = info[:-1] - entry = entry[1:] - return str(pathlib.Path(*info, *entry)) - - -def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]: - """ - Gather details from installed distributions. Print distribution name, - version, location, and installed files. Installed files requires a - pip generated 'installed-files.txt' in the distributions '.egg-info' - directory. - """ - env = get_default_environment() - - installed = { - dist.canonical_name: dist - for dist in env.iter_distributions() - } - query_names = [canonicalize_name(name) for name in query] - missing = sorted( - [name for name, pkg in zip(query, query_names) if pkg not in installed] - ) - if missing: - logger.warning('Package(s) not found: %s', ', '.join(missing)) - - def _get_requiring_packages(current_dist: BaseDistribution) -> List[str]: - return [ - dist.metadata["Name"] or "UNKNOWN" - for dist in installed.values() - if current_dist.canonical_name in { - canonicalize_name(d.name) for d in dist.iter_dependencies() - } - ] - - def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]: - try: - text = dist.read_text('RECORD') - except FileNotFoundError: - return None - # This extra Path-str cast normalizes entries. - return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines())) - - def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[str]]: - try: - text = dist.read_text('installed-files.txt') - except FileNotFoundError: - return None - paths = (p for p in text.splitlines(keepends=False) if p) - root = dist.location - info = dist.info_directory - if root is None or info is None: - return paths - try: - info_rel = pathlib.Path(info).relative_to(root) - except ValueError: # info is not relative to root. - return paths - if not info_rel.parts: # info *is* root. - return paths - return ( - _covert_legacy_entry(pathlib.Path(p).parts, info_rel.parts) - for p in paths - ) - - for query_name in query_names: - try: - dist = installed[query_name] - except KeyError: - continue - - try: - entry_points_text = dist.read_text('entry_points.txt') - entry_points = entry_points_text.splitlines(keepends=False) - except FileNotFoundError: - entry_points = [] - - files_iter = _files_from_record(dist) or _files_from_legacy(dist) - if files_iter is None: - files: Optional[List[str]] = None - else: - files = sorted(files_iter) - - metadata = dist.metadata - - yield _PackageInfo( - name=dist.raw_name, - version=str(dist.version), - location=dist.location or "", - requires=[req.name for req in dist.iter_dependencies()], - required_by=_get_requiring_packages(dist), - installer=dist.installer, - metadata_version=dist.metadata_version or "", - classifiers=metadata.get_all("Classifier", []), - summary=metadata.get("Summary", ""), - homepage=metadata.get("Home-page", ""), - author=metadata.get("Author", ""), - author_email=metadata.get("Author-email", ""), - license=metadata.get("License", ""), - entry_points=entry_points, - files=files, - ) - - -def print_results( - distributions: Iterator[_PackageInfo], - list_files: bool, - verbose: bool, -) -> bool: - """ - Print the information from installed distributions found. - """ - results_printed = False - for i, dist in enumerate(distributions): - results_printed = True - if i > 0: - write_output("---") - - write_output("Name: %s", dist.name) - write_output("Version: %s", dist.version) - write_output("Summary: %s", dist.summary) - write_output("Home-page: %s", dist.homepage) - write_output("Author: %s", dist.author) - write_output("Author-email: %s", dist.author_email) - write_output("License: %s", dist.license) - write_output("Location: %s", dist.location) - write_output("Requires: %s", ', '.join(dist.requires)) - write_output("Required-by: %s", ', '.join(dist.required_by)) - - if verbose: - write_output("Metadata-Version: %s", dist.metadata_version) - write_output("Installer: %s", dist.installer) - write_output("Classifiers:") - for classifier in dist.classifiers: - write_output(" %s", classifier) - write_output("Entry-points:") - for entry in dist.entry_points: - write_output(" %s", entry.strip()) - if list_files: - write_output("Files:") - if dist.files is None: - write_output("Cannot locate RECORD or installed-files.txt") - else: - for line in dist.files: - write_output(" %s", line.strip()) - return results_printed diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/uninstall.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/uninstall.py deleted file mode 100644 index c590627..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/uninstall.py +++ /dev/null @@ -1,100 +0,0 @@ -import logging -from optparse import Values -from typing import List - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli.base_command import Command -from pip._internal.cli.req_command import SessionCommandMixin, warn_if_run_as_root -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.exceptions import InstallationError -from pip._internal.req import parse_requirements -from pip._internal.req.constructors import ( - install_req_from_line, - install_req_from_parsed_requirement, -) -from pip._internal.utils.misc import protect_pip_from_modification_on_windows - -logger = logging.getLogger(__name__) - - -class UninstallCommand(Command, SessionCommandMixin): - """ - Uninstall packages. - - pip is able to uninstall most installed packages. Known exceptions are: - - - Pure distutils packages installed with ``python setup.py install``, which - leave behind no metadata to determine what files were installed. - - Script wrappers installed by ``python setup.py develop``. - """ - - usage = """ - %prog [options] ... - %prog [options] -r ...""" - - def add_options(self) -> None: - self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', - default=[], - metavar='file', - help='Uninstall all the packages listed in the given requirements ' - 'file. This option can be used multiple times.', - ) - self.cmd_opts.add_option( - '-y', '--yes', - dest='yes', - action='store_true', - help="Don't ask for confirmation of uninstall deletions.") - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options: Values, args: List[str]) -> int: - session = self.get_default_session(options) - - reqs_to_uninstall = {} - for name in args: - req = install_req_from_line( - name, isolated=options.isolated_mode, - ) - if req.name: - reqs_to_uninstall[canonicalize_name(req.name)] = req - else: - logger.warning( - "Invalid requirement: %r ignored -" - " the uninstall command expects named" - " requirements.", - name, - ) - for filename in options.requirements: - for parsed_req in parse_requirements( - filename, - options=options, - session=session): - req = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode - ) - if req.name: - reqs_to_uninstall[canonicalize_name(req.name)] = req - if not reqs_to_uninstall: - raise InstallationError( - f'You must give at least one requirement to {self.name} (see ' - f'"pip help {self.name}")' - ) - - protect_pip_from_modification_on_windows( - modifying_pip="pip" in reqs_to_uninstall - ) - - for req in reqs_to_uninstall.values(): - uninstall_pathset = req.uninstall( - auto_confirm=options.yes, verbose=self.verbosity > 0, - ) - if uninstall_pathset: - uninstall_pathset.commit() - - warn_if_run_as_root() - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/wheel.py deleted file mode 100644 index c8bf4e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/commands/wheel.py +++ /dev/null @@ -1,176 +0,0 @@ -import logging -import os -import shutil -from optparse import Values -from typing import List - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.exceptions import CommandError -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.misc import ensure_dir, normalize_path -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.wheel_builder import build, should_build_for_wheel_command - -logger = logging.getLogger(__name__) - - -class WheelCommand(RequirementCommand): - """ - Build Wheel archives for your requirements and dependencies. - - Wheel is a built-package format, and offers the advantage of not - recompiling your software during every install. For more details, see the - wheel docs: https://wheel.readthedocs.io/en/latest/ - - Requirements: setuptools>=0.8, and wheel. - - 'pip wheel' uses the bdist_wheel setuptools extension from the wheel - package to build individual wheels. - - """ - - usage = """ - %prog [options] ... - %prog [options] -r ... - %prog [options] [-e] ... - %prog [options] [-e] ... - %prog [options] ...""" - - def add_options(self) -> None: - - self.cmd_opts.add_option( - '-w', '--wheel-dir', - dest='wheel_dir', - metavar='dir', - default=os.curdir, - help=("Build wheels into , where the default is the " - "current working directory."), - ) - self.cmd_opts.add_option(cmdoptions.no_binary()) - self.cmd_opts.add_option(cmdoptions.only_binary()) - self.cmd_opts.add_option(cmdoptions.prefer_binary()) - self.cmd_opts.add_option(cmdoptions.no_build_isolation()) - self.cmd_opts.add_option(cmdoptions.use_pep517()) - self.cmd_opts.add_option(cmdoptions.no_use_pep517()) - self.cmd_opts.add_option(cmdoptions.constraints()) - self.cmd_opts.add_option(cmdoptions.editable()) - self.cmd_opts.add_option(cmdoptions.requirements()) - self.cmd_opts.add_option(cmdoptions.src()) - self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) - self.cmd_opts.add_option(cmdoptions.no_deps()) - self.cmd_opts.add_option(cmdoptions.build_dir()) - self.cmd_opts.add_option(cmdoptions.progress_bar()) - - self.cmd_opts.add_option( - '--no-verify', - dest='no_verify', - action='store_true', - default=False, - help="Don't verify if built wheel is valid.", - ) - - self.cmd_opts.add_option(cmdoptions.build_options()) - self.cmd_opts.add_option(cmdoptions.global_options()) - - self.cmd_opts.add_option( - '--pre', - action='store_true', - default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), - ) - - self.cmd_opts.add_option(cmdoptions.require_hashes()) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, self.cmd_opts) - - @with_cleanup - def run(self, options: Values, args: List[str]) -> int: - cmdoptions.check_install_build_global(options) - - session = self.get_default_session(options) - - finder = self._build_package_finder(options, session) - wheel_cache = WheelCache(options.cache_dir, options.format_control) - - options.wheel_dir = normalize_path(options.wheel_dir) - ensure_dir(options.wheel_dir) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - delete=not options.no_clean, - kind="wheel", - globally_managed=True, - ) - - reqs = self.get_requirements(args, options, finder, session) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - download_dir=options.wheel_dir, - use_user_site=False, - ) - - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - wheel_cache=wheel_cache, - ignore_requires_python=options.ignore_requires_python, - use_pep517=options.use_pep517, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) - - reqs_to_build: List[InstallRequirement] = [] - for req in requirement_set.requirements.values(): - if req.is_wheel: - preparer.save_linked_requirement(req) - elif should_build_for_wheel_command(req): - reqs_to_build.append(req) - - # build wheels - build_successes, build_failures = build( - reqs_to_build, - wheel_cache=wheel_cache, - verify=(not options.no_verify), - build_options=options.build_options or [], - global_options=options.global_options or [], - ) - for req in build_successes: - assert req.link and req.link.is_wheel - assert req.local_file_path - # copy from cache to target directory - try: - shutil.copy(req.local_file_path, options.wheel_dir) - except OSError as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - build_failures.append(req) - if len(build_failures) != 0: - raise CommandError( - "Failed to build one or more wheels" - ) - - return SUCCESS diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/configuration.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/configuration.py deleted file mode 100644 index a4698ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/configuration.py +++ /dev/null @@ -1,403 +0,0 @@ -"""Configuration management setup - -Some terminology: -- name - As written in config files. -- value - Value associated with a name -- key - Name combined with it's section (section.name) -- variant - A single word describing where the configuration key-value pair came from -""" - -import configparser -import locale -import logging -import os -import sys -from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple - -from pip._internal.exceptions import ( - ConfigurationError, - ConfigurationFileCouldNotBeLoaded, -) -from pip._internal.utils import appdirs -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.misc import ensure_dir, enum - -RawConfigParser = configparser.RawConfigParser # Shorthand -Kind = NewType("Kind", str) - -CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf' -ENV_NAMES_IGNORED = "version", "help" - -# The kinds of configurations there are. -kinds = enum( - USER="user", # User Specific - GLOBAL="global", # System Wide - SITE="site", # [Virtual] Environment Specific - ENV="env", # from PIP_CONFIG_FILE - ENV_VAR="env-var", # from Environment Variables -) -OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR -VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.SITE - -logger = logging.getLogger(__name__) - - -# NOTE: Maybe use the optionx attribute to normalize keynames. -def _normalize_name(name): - # type: (str) -> str - """Make a name consistent regardless of source (environment or file) - """ - name = name.lower().replace('_', '-') - if name.startswith('--'): - name = name[2:] # only prefer long opts - return name - - -def _disassemble_key(name): - # type: (str) -> List[str] - if "." not in name: - error_message = ( - "Key does not contain dot separated section and key. " - "Perhaps you wanted to use 'global.{}' instead?" - ).format(name) - raise ConfigurationError(error_message) - return name.split(".", 1) - - -def get_configuration_files(): - # type: () -> Dict[Kind, List[str]] - global_config_files = [ - os.path.join(path, CONFIG_BASENAME) - for path in appdirs.site_config_dirs('pip') - ] - - site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) - legacy_config_file = os.path.join( - os.path.expanduser('~'), - 'pip' if WINDOWS else '.pip', - CONFIG_BASENAME, - ) - new_config_file = os.path.join( - appdirs.user_config_dir("pip"), CONFIG_BASENAME - ) - return { - kinds.GLOBAL: global_config_files, - kinds.SITE: [site_config_file], - kinds.USER: [legacy_config_file, new_config_file], - } - - -class Configuration: - """Handles management of configuration. - - Provides an interface to accessing and managing configuration files. - - This class converts provides an API that takes "section.key-name" style - keys and stores the value associated with it as "key-name" under the - section "section". - - This allows for a clean interface wherein the both the section and the - key-name are preserved in an easy to manage form in the configuration files - and the data stored is also nice. - """ - - def __init__(self, isolated, load_only=None): - # type: (bool, Optional[Kind]) -> None - super().__init__() - - if load_only is not None and load_only not in VALID_LOAD_ONLY: - raise ConfigurationError( - "Got invalid value for load_only - should be one of {}".format( - ", ".join(map(repr, VALID_LOAD_ONLY)) - ) - ) - self.isolated = isolated - self.load_only = load_only - - # Because we keep track of where we got the data from - self._parsers = { - variant: [] for variant in OVERRIDE_ORDER - } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] - self._config = { - variant: {} for variant in OVERRIDE_ORDER - } # type: Dict[Kind, Dict[str, Any]] - self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] - - def load(self): - # type: () -> None - """Loads configuration from configuration files and environment - """ - self._load_config_files() - if not self.isolated: - self._load_environment_vars() - - def get_file_to_edit(self): - # type: () -> Optional[str] - """Returns the file with highest priority in configuration - """ - assert self.load_only is not None, \ - "Need to be specified a file to be editing" - - try: - return self._get_parser_to_modify()[0] - except IndexError: - return None - - def items(self): - # type: () -> Iterable[Tuple[str, Any]] - """Returns key-value pairs like dict.items() representing the loaded - configuration - """ - return self._dictionary.items() - - def get_value(self, key): - # type: (str) -> Any - """Get a value from the configuration. - """ - try: - return self._dictionary[key] - except KeyError: - raise ConfigurationError(f"No such key - {key}") - - def set_value(self, key, value): - # type: (str, Any) -> None - """Modify a value in the configuration. - """ - self._ensure_have_load_only() - - assert self.load_only - fname, parser = self._get_parser_to_modify() - - if parser is not None: - section, name = _disassemble_key(key) - - # Modify the parser and the configuration - if not parser.has_section(section): - parser.add_section(section) - parser.set(section, name, value) - - self._config[self.load_only][key] = value - self._mark_as_modified(fname, parser) - - def unset_value(self, key): - # type: (str) -> None - """Unset a value in the configuration.""" - self._ensure_have_load_only() - - assert self.load_only - if key not in self._config[self.load_only]: - raise ConfigurationError(f"No such key - {key}") - - fname, parser = self._get_parser_to_modify() - - if parser is not None: - section, name = _disassemble_key(key) - if not (parser.has_section(section) - and parser.remove_option(section, name)): - # The option was not removed. - raise ConfigurationError( - "Fatal Internal error [id=1]. Please report as a bug." - ) - - # The section may be empty after the option was removed. - if not parser.items(section): - parser.remove_section(section) - self._mark_as_modified(fname, parser) - - del self._config[self.load_only][key] - - def save(self): - # type: () -> None - """Save the current in-memory state. - """ - self._ensure_have_load_only() - - for fname, parser in self._modified_parsers: - logger.info("Writing to %s", fname) - - # Ensure directory exists. - ensure_dir(os.path.dirname(fname)) - - with open(fname, "w") as f: - parser.write(f) - - # - # Private routines - # - - def _ensure_have_load_only(self): - # type: () -> None - if self.load_only is None: - raise ConfigurationError("Needed a specific file to be modifying.") - logger.debug("Will be working with %s variant only", self.load_only) - - @property - def _dictionary(self): - # type: () -> Dict[str, Any] - """A dictionary representing the loaded configuration. - """ - # NOTE: Dictionaries are not populated if not loaded. So, conditionals - # are not needed here. - retval = {} - - for variant in OVERRIDE_ORDER: - retval.update(self._config[variant]) - - return retval - - def _load_config_files(self): - # type: () -> None - """Loads configuration from configuration files - """ - config_files = dict(self.iter_config_files()) - if config_files[kinds.ENV][0:1] == [os.devnull]: - logger.debug( - "Skipping loading configuration files due to " - "environment's PIP_CONFIG_FILE being os.devnull" - ) - return - - for variant, files in config_files.items(): - for fname in files: - # If there's specific variant set in `load_only`, load only - # that variant, not the others. - if self.load_only is not None and variant != self.load_only: - logger.debug( - "Skipping file '%s' (variant: %s)", fname, variant - ) - continue - - parser = self._load_file(variant, fname) - - # Keeping track of the parsers used - self._parsers[variant].append((fname, parser)) - - def _load_file(self, variant, fname): - # type: (Kind, str) -> RawConfigParser - logger.debug("For variant '%s', will try loading '%s'", variant, fname) - parser = self._construct_parser(fname) - - for section in parser.sections(): - items = parser.items(section) - self._config[variant].update(self._normalized_keys(section, items)) - - return parser - - def _construct_parser(self, fname): - # type: (str) -> RawConfigParser - parser = configparser.RawConfigParser() - # If there is no such file, don't bother reading it but create the - # parser anyway, to hold the data. - # Doing this is useful when modifying and saving files, where we don't - # need to construct a parser. - if os.path.exists(fname): - try: - parser.read(fname) - except UnicodeDecodeError: - # See https://github.com/pypa/pip/issues/4963 - raise ConfigurationFileCouldNotBeLoaded( - reason="contains invalid {} characters".format( - locale.getpreferredencoding(False) - ), - fname=fname, - ) - except configparser.Error as error: - # See https://github.com/pypa/pip/issues/4893 - raise ConfigurationFileCouldNotBeLoaded(error=error) - return parser - - def _load_environment_vars(self): - # type: () -> None - """Loads configuration from environment variables - """ - self._config[kinds.ENV_VAR].update( - self._normalized_keys(":env:", self.get_environ_vars()) - ) - - def _normalized_keys(self, section, items): - # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] - """Normalizes items to construct a dictionary with normalized keys. - - This routine is where the names become keys and are made the same - regardless of source - configuration files or environment. - """ - normalized = {} - for name, val in items: - key = section + "." + _normalize_name(name) - normalized[key] = val - return normalized - - def get_environ_vars(self): - # type: () -> Iterable[Tuple[str, str]] - """Returns a generator with all environmental vars with prefix PIP_""" - for key, val in os.environ.items(): - if key.startswith("PIP_"): - name = key[4:].lower() - if name not in ENV_NAMES_IGNORED: - yield name, val - - # XXX: This is patched in the tests. - def iter_config_files(self): - # type: () -> Iterable[Tuple[Kind, List[str]]] - """Yields variant and configuration files associated with it. - - This should be treated like items of a dictionary. - """ - # SMELL: Move the conditions out of this function - - # environment variables have the lowest priority - config_file = os.environ.get('PIP_CONFIG_FILE', None) - if config_file is not None: - yield kinds.ENV, [config_file] - else: - yield kinds.ENV, [] - - config_files = get_configuration_files() - - # at the base we have any global configuration - yield kinds.GLOBAL, config_files[kinds.GLOBAL] - - # per-user configuration next - should_load_user_config = not self.isolated and not ( - config_file and os.path.exists(config_file) - ) - if should_load_user_config: - # The legacy config file is overridden by the new config file - yield kinds.USER, config_files[kinds.USER] - - # finally virtualenv configuration first trumping others - yield kinds.SITE, config_files[kinds.SITE] - - def get_values_in_config(self, variant): - # type: (Kind) -> Dict[str, Any] - """Get values present in a config file""" - return self._config[variant] - - def _get_parser_to_modify(self): - # type: () -> Tuple[str, RawConfigParser] - # Determine which parser to modify - assert self.load_only - parsers = self._parsers[self.load_only] - if not parsers: - # This should not happen if everything works correctly. - raise ConfigurationError( - "Fatal Internal error [id=2]. Please report as a bug." - ) - - # Use the highest priority parser. - return parsers[-1] - - # XXX: This is patched in the tests. - def _mark_as_modified(self, fname, parser): - # type: (str, RawConfigParser) -> None - file_parser_tuple = (fname, parser) - if file_parser_tuple not in self._modified_parsers: - self._modified_parsers.append(file_parser_tuple) - - def __repr__(self): - # type: () -> str - return f"{self.__class__.__name__}({self._dictionary!r})" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/__init__.py deleted file mode 100644 index 9a89a83..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.distributions.sdist import SourceDistribution -from pip._internal.distributions.wheel import WheelDistribution -from pip._internal.req.req_install import InstallRequirement - - -def make_distribution_for_install_requirement( - install_req: InstallRequirement, -) -> AbstractDistribution: - """Returns a Distribution for the given InstallRequirement""" - # Editable requirements will always be source distributions. They use the - # legacy logic until we create a modern standard for them. - if install_req.editable: - return SourceDistribution(install_req) - - # If it's a wheel, it's a WheelDistribution - if install_req.is_wheel: - return WheelDistribution(install_req) - - # Otherwise, a SourceDistribution - return SourceDistribution(install_req) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/base.py deleted file mode 100644 index fbdd5e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/base.py +++ /dev/null @@ -1,38 +0,0 @@ -import abc -from typing import Optional - -from pip._vendor.pkg_resources import Distribution - -from pip._internal.index.package_finder import PackageFinder -from pip._internal.req import InstallRequirement - - -class AbstractDistribution(metaclass=abc.ABCMeta): - """A base class for handling installable artifacts. - - The requirements for anything installable are as follows: - - - we must be able to determine the requirement name - (or we can't correctly handle the non-upgrade case). - - - for packages with setup requirements, we must also be able - to determine their requirements without installing additional - packages (for the same reason as run-time dependencies) - - - we must be able to create a Distribution object exposing the - above metadata. - """ - - def __init__(self, req: InstallRequirement) -> None: - super().__init__() - self.req = req - - @abc.abstractmethod - def get_pkg_resources_distribution(self) -> Optional[Distribution]: - raise NotImplementedError() - - @abc.abstractmethod - def prepare_distribution_metadata( - self, finder: PackageFinder, build_isolation: bool - ) -> None: - raise NotImplementedError() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/installed.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/installed.py deleted file mode 100644 index 0d452e2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/installed.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Optional - -from pip._vendor.pkg_resources import Distribution - -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.index.package_finder import PackageFinder - - -class InstalledDistribution(AbstractDistribution): - """Represents an installed package. - - This does not need any preparation as the required information has already - been computed. - """ - - def get_pkg_resources_distribution(self) -> Optional[Distribution]: - return self.req.satisfied_by - - def prepare_distribution_metadata( - self, finder: PackageFinder, build_isolation: bool - ) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/sdist.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/sdist.py deleted file mode 100644 index 596b516..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/sdist.py +++ /dev/null @@ -1,95 +0,0 @@ -import logging -from typing import Set, Tuple - -from pip._vendor.pkg_resources import Distribution - -from pip._internal.build_env import BuildEnvironment -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.exceptions import InstallationError -from pip._internal.index.package_finder import PackageFinder -from pip._internal.utils.subprocess import runner_with_spinner_message - -logger = logging.getLogger(__name__) - - -class SourceDistribution(AbstractDistribution): - """Represents a source distribution. - - The preparation step for these needs metadata for the packages to be - generated, either using PEP 517 or using the legacy `setup.py egg_info`. - """ - - def get_pkg_resources_distribution(self) -> Distribution: - return self.req.get_dist() - - def prepare_distribution_metadata( - self, finder: PackageFinder, build_isolation: bool - ) -> None: - # Load pyproject.toml, to determine whether PEP 517 is to be used - self.req.load_pyproject_toml() - - # Set up the build isolation, if this requirement should be isolated - should_isolate = self.req.use_pep517 and build_isolation - if should_isolate: - self._setup_isolation(finder) - - self.req.prepare_metadata() - - def _setup_isolation(self, finder: PackageFinder) -> None: - def _raise_conflicts( - conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]] - ) -> None: - format_string = ( - "Some build dependencies for {requirement} " - "conflict with {conflicting_with}: {description}." - ) - error_message = format_string.format( - requirement=self.req, - conflicting_with=conflicting_with, - description=", ".join( - f"{installed} is incompatible with {wanted}" - for installed, wanted in sorted(conflicting) - ), - ) - raise InstallationError(error_message) - - # Isolate in a BuildEnvironment and install the build-time - # requirements. - pyproject_requires = self.req.pyproject_requires - assert pyproject_requires is not None - - self.req.build_env = BuildEnvironment() - self.req.build_env.install_requirements( - finder, pyproject_requires, "overlay", "Installing build dependencies" - ) - conflicting, missing = self.req.build_env.check_requirements( - self.req.requirements_to_check - ) - if conflicting: - _raise_conflicts("PEP 517/518 supported requirements", conflicting) - if missing: - logger.warning( - "Missing build requirements in pyproject.toml for %s.", - self.req, - ) - logger.warning( - "The project does not specify a build backend, and " - "pip cannot fall back to setuptools without %s.", - " and ".join(map(repr, sorted(missing))), - ) - # Install any extra build dependencies that the backend requests. - # This must be done in a second pass, as the pyproject.toml - # dependencies must be installed before we can call the backend. - with self.req.build_env: - runner = runner_with_spinner_message("Getting requirements to build wheel") - backend = self.req.pep517_backend - assert backend is not None - with backend.subprocess_runner(runner): - reqs = backend.get_requires_for_build_wheel() - - conflicting, missing = self.req.build_env.check_requirements(reqs) - if conflicting: - _raise_conflicts("the backend dependencies", conflicting) - self.req.build_env.install_requirements( - finder, missing, "normal", "Installing backend dependencies" - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/wheel.py deleted file mode 100644 index 00a70b0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/distributions/wheel.py +++ /dev/null @@ -1,34 +0,0 @@ -from zipfile import ZipFile - -from pip._vendor.pkg_resources import Distribution - -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.index.package_finder import PackageFinder -from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel - - -class WheelDistribution(AbstractDistribution): - """Represents a wheel distribution. - - This does not need any preparation as wheels can be directly unpacked. - """ - - def get_pkg_resources_distribution(self) -> Distribution: - """Loads the metadata from the wheel file into memory and returns a - Distribution that uses it, not relying on the wheel file or - requirement. - """ - # Set as part of preparation during download. - assert self.req.local_file_path - # Wheels are never unnamed. - assert self.req.name - - with ZipFile(self.req.local_file_path, allowZip64=True) as z: - return pkg_resources_distribution_for_wheel( - z, self.req.name, self.req.local_file_path - ) - - def prepare_distribution_metadata( - self, finder: PackageFinder, build_isolation: bool - ) -> None: - pass diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/exceptions.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/exceptions.py deleted file mode 100644 index 8aacf81..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/exceptions.py +++ /dev/null @@ -1,397 +0,0 @@ -"""Exceptions used throughout package""" - -import configparser -from itertools import chain, groupby, repeat -from typing import TYPE_CHECKING, Dict, List, Optional - -from pip._vendor.pkg_resources import Distribution -from pip._vendor.requests.models import Request, Response - -if TYPE_CHECKING: - from hashlib import _Hash - - from pip._internal.req.req_install import InstallRequirement - - -class PipError(Exception): - """Base pip exception""" - - -class ConfigurationError(PipError): - """General exception in configuration""" - - -class InstallationError(PipError): - """General exception during installation""" - - -class UninstallationError(PipError): - """General exception during uninstallation""" - - -class NoneMetadataError(PipError): - """ - Raised when accessing "METADATA" or "PKG-INFO" metadata for a - pip._vendor.pkg_resources.Distribution object and - `dist.has_metadata('METADATA')` returns True but - `dist.get_metadata('METADATA')` returns None (and similarly for - "PKG-INFO"). - """ - - def __init__(self, dist, metadata_name): - # type: (Distribution, str) -> None - """ - :param dist: A Distribution object. - :param metadata_name: The name of the metadata being accessed - (can be "METADATA" or "PKG-INFO"). - """ - self.dist = dist - self.metadata_name = metadata_name - - def __str__(self): - # type: () -> str - # Use `dist` in the error message because its stringification - # includes more information, like the version and location. - return ( - 'None {} metadata found for distribution: {}'.format( - self.metadata_name, self.dist, - ) - ) - - -class UserInstallationInvalid(InstallationError): - """A --user install is requested on an environment without user site.""" - - def __str__(self): - # type: () -> str - return "User base directory is not specified" - - -class InvalidSchemeCombination(InstallationError): - def __str__(self): - # type: () -> str - before = ", ".join(str(a) for a in self.args[:-1]) - return f"Cannot set {before} and {self.args[-1]} together" - - -class DistributionNotFound(InstallationError): - """Raised when a distribution cannot be found to satisfy a requirement""" - - -class RequirementsFileParseError(InstallationError): - """Raised when a general error occurs parsing a requirements file line.""" - - -class BestVersionAlreadyInstalled(PipError): - """Raised when the most up-to-date version of a package is already - installed.""" - - -class BadCommand(PipError): - """Raised when virtualenv or a command is not found""" - - -class CommandError(PipError): - """Raised when there is an error in command-line arguments""" - - -class PreviousBuildDirError(PipError): - """Raised when there's a previous conflicting build directory""" - - -class NetworkConnectionError(PipError): - """HTTP connection error""" - - def __init__(self, error_msg, response=None, request=None): - # type: (str, Response, Request) -> None - """ - Initialize NetworkConnectionError with `request` and `response` - objects. - """ - self.response = response - self.request = request - self.error_msg = error_msg - if (self.response is not None and not self.request and - hasattr(response, 'request')): - self.request = self.response.request - super().__init__(error_msg, response, request) - - def __str__(self): - # type: () -> str - return str(self.error_msg) - - -class InvalidWheelFilename(InstallationError): - """Invalid wheel filename.""" - - -class UnsupportedWheel(InstallationError): - """Unsupported wheel.""" - - -class MetadataInconsistent(InstallationError): - """Built metadata contains inconsistent information. - - This is raised when the metadata contains values (e.g. name and version) - that do not match the information previously obtained from sdist filename - or user-supplied ``#egg=`` value. - """ - def __init__(self, ireq, field, f_val, m_val): - # type: (InstallRequirement, str, str, str) -> None - self.ireq = ireq - self.field = field - self.f_val = f_val - self.m_val = m_val - - def __str__(self): - # type: () -> str - template = ( - "Requested {} has inconsistent {}: " - "filename has {!r}, but metadata has {!r}" - ) - return template.format(self.ireq, self.field, self.f_val, self.m_val) - - -class InstallationSubprocessError(InstallationError): - """A subprocess call failed during installation.""" - def __init__(self, returncode, description): - # type: (int, str) -> None - self.returncode = returncode - self.description = description - - def __str__(self): - # type: () -> str - return ( - "Command errored out with exit status {}: {} " - "Check the logs for full command output." - ).format(self.returncode, self.description) - - -class HashErrors(InstallationError): - """Multiple HashError instances rolled into one for reporting""" - - def __init__(self): - # type: () -> None - self.errors = [] # type: List[HashError] - - def append(self, error): - # type: (HashError) -> None - self.errors.append(error) - - def __str__(self): - # type: () -> str - lines = [] - self.errors.sort(key=lambda e: e.order) - for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): - lines.append(cls.head) - lines.extend(e.body() for e in errors_of_cls) - if lines: - return '\n'.join(lines) - return '' - - def __nonzero__(self): - # type: () -> bool - return bool(self.errors) - - def __bool__(self): - # type: () -> bool - return self.__nonzero__() - - -class HashError(InstallationError): - """ - A failure to verify a package against known-good hashes - - :cvar order: An int sorting hash exception classes by difficulty of - recovery (lower being harder), so the user doesn't bother fretting - about unpinned packages when he has deeper issues, like VCS - dependencies, to deal with. Also keeps error reports in a - deterministic order. - :cvar head: A section heading for display above potentially many - exceptions of this kind - :ivar req: The InstallRequirement that triggered this error. This is - pasted on after the exception is instantiated, because it's not - typically available earlier. - - """ - req = None # type: Optional[InstallRequirement] - head = '' - order = -1 # type: int - - def body(self): - # type: () -> str - """Return a summary of me for display under the heading. - - This default implementation simply prints a description of the - triggering requirement. - - :param req: The InstallRequirement that provoked this error, with - its link already populated by the resolver's _populate_link(). - - """ - return f' {self._requirement_name()}' - - def __str__(self): - # type: () -> str - return f'{self.head}\n{self.body()}' - - def _requirement_name(self): - # type: () -> str - """Return a description of the requirement that triggered me. - - This default implementation returns long description of the req, with - line numbers - - """ - return str(self.req) if self.req else 'unknown package' - - -class VcsHashUnsupported(HashError): - """A hash was provided for a version-control-system-based requirement, but - we don't have a method for hashing those.""" - - order = 0 - head = ("Can't verify hashes for these requirements because we don't " - "have a way to hash version control repositories:") - - -class DirectoryUrlHashUnsupported(HashError): - """A hash was provided for a version-control-system-based requirement, but - we don't have a method for hashing those.""" - - order = 1 - head = ("Can't verify hashes for these file:// requirements because they " - "point to directories:") - - -class HashMissing(HashError): - """A hash was needed for a requirement but is absent.""" - - order = 2 - head = ('Hashes are required in --require-hashes mode, but they are ' - 'missing from some requirements. Here is a list of those ' - 'requirements along with the hashes their downloaded archives ' - 'actually had. Add lines like these to your requirements files to ' - 'prevent tampering. (If you did not enable --require-hashes ' - 'manually, note that it turns on automatically when any package ' - 'has a hash.)') - - def __init__(self, gotten_hash): - # type: (str) -> None - """ - :param gotten_hash: The hash of the (possibly malicious) archive we - just downloaded - """ - self.gotten_hash = gotten_hash - - def body(self): - # type: () -> str - # Dodge circular import. - from pip._internal.utils.hashes import FAVORITE_HASH - - package = None - if self.req: - # In the case of URL-based requirements, display the original URL - # seen in the requirements file rather than the package name, - # so the output can be directly copied into the requirements file. - package = (self.req.original_link if self.req.original_link - # In case someone feeds something downright stupid - # to InstallRequirement's constructor. - else getattr(self.req, 'req', None)) - return ' {} --hash={}:{}'.format(package or 'unknown package', - FAVORITE_HASH, - self.gotten_hash) - - -class HashUnpinned(HashError): - """A requirement had a hash specified but was not pinned to a specific - version.""" - - order = 3 - head = ('In --require-hashes mode, all requirements must have their ' - 'versions pinned with ==. These do not:') - - -class HashMismatch(HashError): - """ - Distribution file hash values don't match. - - :ivar package_name: The name of the package that triggered the hash - mismatch. Feel free to write to this after the exception is raise to - improve its error message. - - """ - order = 4 - head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' - 'FILE. If you have updated the package versions, please update ' - 'the hashes. Otherwise, examine the package contents carefully; ' - 'someone may have tampered with them.') - - def __init__(self, allowed, gots): - # type: (Dict[str, List[str]], Dict[str, _Hash]) -> None - """ - :param allowed: A dict of algorithm names pointing to lists of allowed - hex digests - :param gots: A dict of algorithm names pointing to hashes we - actually got from the files under suspicion - """ - self.allowed = allowed - self.gots = gots - - def body(self): - # type: () -> str - return ' {}:\n{}'.format(self._requirement_name(), - self._hash_comparison()) - - def _hash_comparison(self): - # type: () -> str - """ - Return a comparison of actual and expected hash values. - - Example:: - - Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde - or 123451234512345123451234512345123451234512345 - Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef - - """ - def hash_then_or(hash_name): - # type: (str) -> chain[str] - # For now, all the decent hashes have 6-char names, so we can get - # away with hard-coding space literals. - return chain([hash_name], repeat(' or')) - - lines = [] # type: List[str] - for hash_name, expecteds in self.allowed.items(): - prefix = hash_then_or(hash_name) - lines.extend((' Expected {} {}'.format(next(prefix), e)) - for e in expecteds) - lines.append(' Got {}\n'.format( - self.gots[hash_name].hexdigest())) - return '\n'.join(lines) - - -class UnsupportedPythonVersion(InstallationError): - """Unsupported python version according to Requires-Python package - metadata.""" - - -class ConfigurationFileCouldNotBeLoaded(ConfigurationError): - """When there are errors while loading a configuration file - """ - - def __init__(self, reason="could not be loaded", fname=None, error=None): - # type: (str, Optional[str], Optional[configparser.Error]) -> None - super().__init__(error) - self.reason = reason - self.fname = fname - self.error = error - - def __str__(self): - # type: () -> str - if self.fname is not None: - message_part = f" in {self.fname}." - else: - assert self.error is not None - message_part = f".\n{self.error}\n" - return f"Configuration file {self.reason}{message_part}" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/__init__.py deleted file mode 100644 index 7a17b7b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Index interaction code -""" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/collector.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/collector.py deleted file mode 100644 index 14d745e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/collector.py +++ /dev/null @@ -1,534 +0,0 @@ -""" -The main purpose of this module is to expose LinkCollector.collect_sources(). -""" - -import cgi -import collections -import functools -import html -import itertools -import logging -import os -import re -import urllib.parse -import urllib.request -import xml.etree.ElementTree -from optparse import Values -from typing import ( - Callable, - Iterable, - List, - MutableMapping, - NamedTuple, - Optional, - Sequence, - Union, -) - -from pip._vendor import html5lib, requests -from pip._vendor.requests import Response -from pip._vendor.requests.exceptions import RetryError, SSLError - -from pip._internal.exceptions import NetworkConnectionError -from pip._internal.models.link import Link -from pip._internal.models.search_scope import SearchScope -from pip._internal.network.session import PipSession -from pip._internal.network.utils import raise_for_status -from pip._internal.utils.filetypes import is_archive_file -from pip._internal.utils.misc import pairwise, redact_auth_from_url -from pip._internal.vcs import vcs - -from .sources import CandidatesFromPage, LinkSource, build_source - -logger = logging.getLogger(__name__) - -HTMLElement = xml.etree.ElementTree.Element -ResponseHeaders = MutableMapping[str, str] - - -def _match_vcs_scheme(url: str) -> Optional[str]: - """Look for VCS schemes in the URL. - - Returns the matched VCS scheme, or None if there's no match. - """ - for scheme in vcs.schemes: - if url.lower().startswith(scheme) and url[len(scheme)] in '+:': - return scheme - return None - - -class _NotHTML(Exception): - def __init__(self, content_type: str, request_desc: str) -> None: - super().__init__(content_type, request_desc) - self.content_type = content_type - self.request_desc = request_desc - - -def _ensure_html_header(response: Response) -> None: - """Check the Content-Type header to ensure the response contains HTML. - - Raises `_NotHTML` if the content type is not text/html. - """ - content_type = response.headers.get("Content-Type", "") - if not content_type.lower().startswith("text/html"): - raise _NotHTML(content_type, response.request.method) - - -class _NotHTTP(Exception): - pass - - -def _ensure_html_response(url: str, session: PipSession) -> None: - """Send a HEAD request to the URL, and ensure the response contains HTML. - - Raises `_NotHTTP` if the URL is not available for a HEAD request, or - `_NotHTML` if the content type is not text/html. - """ - scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url) - if scheme not in {'http', 'https'}: - raise _NotHTTP() - - resp = session.head(url, allow_redirects=True) - raise_for_status(resp) - - _ensure_html_header(resp) - - -def _get_html_response(url: str, session: PipSession) -> Response: - """Access an HTML page with GET, and return the response. - - This consists of three parts: - - 1. If the URL looks suspiciously like an archive, send a HEAD first to - check the Content-Type is HTML, to avoid downloading a large file. - Raise `_NotHTTP` if the content type cannot be determined, or - `_NotHTML` if it is not HTML. - 2. Actually perform the request. Raise HTTP exceptions on network failures. - 3. Check the Content-Type header to make sure we got HTML, and raise - `_NotHTML` otherwise. - """ - if is_archive_file(Link(url).filename): - _ensure_html_response(url, session=session) - - logger.debug('Getting page %s', redact_auth_from_url(url)) - - resp = session.get( - url, - headers={ - "Accept": "text/html", - # We don't want to blindly returned cached data for - # /simple/, because authors generally expecting that - # twine upload && pip install will function, but if - # they've done a pip install in the last ~10 minutes - # it won't. Thus by setting this to zero we will not - # blindly use any cached data, however the benefit of - # using max-age=0 instead of no-cache, is that we will - # still support conditional requests, so we will still - # minimize traffic sent in cases where the page hasn't - # changed at all, we will just always incur the round - # trip for the conditional GET now instead of only - # once per 10 minutes. - # For more information, please see pypa/pip#5670. - "Cache-Control": "max-age=0", - }, - ) - raise_for_status(resp) - - # The check for archives above only works if the url ends with - # something that looks like an archive. However that is not a - # requirement of an url. Unless we issue a HEAD request on every - # url we cannot know ahead of time for sure if something is HTML - # or not. However we can check after we've downloaded it. - _ensure_html_header(resp) - - return resp - - -def _get_encoding_from_headers(headers: ResponseHeaders) -> Optional[str]: - """Determine if we have any encoding information in our headers. - """ - if headers and "Content-Type" in headers: - content_type, params = cgi.parse_header(headers["Content-Type"]) - if "charset" in params: - return params['charset'] - return None - - -def _determine_base_url(document: HTMLElement, page_url: str) -> str: - """Determine the HTML document's base URL. - - This looks for a ```` tag in the HTML document. If present, its href - attribute denotes the base URL of anchor tags in the document. If there is - no such tag (or if it does not have a valid href attribute), the HTML - file's URL is used as the base URL. - - :param document: An HTML document representation. The current - implementation expects the result of ``html5lib.parse()``. - :param page_url: The URL of the HTML document. - """ - for base in document.findall(".//base"): - href = base.get("href") - if href is not None: - return href - return page_url - - -def _clean_url_path_part(part: str) -> str: - """ - Clean a "part" of a URL path (i.e. after splitting on "@" characters). - """ - # We unquote prior to quoting to make sure nothing is double quoted. - return urllib.parse.quote(urllib.parse.unquote(part)) - - -def _clean_file_url_path(part: str) -> str: - """ - Clean the first part of a URL path that corresponds to a local - filesystem path (i.e. the first part after splitting on "@" characters). - """ - # We unquote prior to quoting to make sure nothing is double quoted. - # Also, on Windows the path part might contain a drive letter which - # should not be quoted. On Linux where drive letters do not - # exist, the colon should be quoted. We rely on urllib.request - # to do the right thing here. - return urllib.request.pathname2url(urllib.request.url2pathname(part)) - - -# percent-encoded: / -_reserved_chars_re = re.compile('(@|%2F)', re.IGNORECASE) - - -def _clean_url_path(path: str, is_local_path: bool) -> str: - """ - Clean the path portion of a URL. - """ - if is_local_path: - clean_func = _clean_file_url_path - else: - clean_func = _clean_url_path_part - - # Split on the reserved characters prior to cleaning so that - # revision strings in VCS URLs are properly preserved. - parts = _reserved_chars_re.split(path) - - cleaned_parts = [] - for to_clean, reserved in pairwise(itertools.chain(parts, [''])): - cleaned_parts.append(clean_func(to_clean)) - # Normalize %xx escapes (e.g. %2f -> %2F) - cleaned_parts.append(reserved.upper()) - - return ''.join(cleaned_parts) - - -def _clean_link(url: str) -> str: - """ - Make sure a link is fully quoted. - For example, if ' ' occurs in the URL, it will be replaced with "%20", - and without double-quoting other characters. - """ - # Split the URL into parts according to the general structure - # `scheme://netloc/path;parameters?query#fragment`. - result = urllib.parse.urlparse(url) - # If the netloc is empty, then the URL refers to a local filesystem path. - is_local_path = not result.netloc - path = _clean_url_path(result.path, is_local_path=is_local_path) - return urllib.parse.urlunparse(result._replace(path=path)) - - -def _create_link_from_element( - anchor: HTMLElement, - page_url: str, - base_url: str, -) -> Optional[Link]: - """ - Convert an anchor element in a simple repository page to a Link. - """ - href = anchor.get("href") - if not href: - return None - - url = _clean_link(urllib.parse.urljoin(base_url, href)) - pyrequire = anchor.get('data-requires-python') - pyrequire = html.unescape(pyrequire) if pyrequire else None - - yanked_reason = anchor.get('data-yanked') - if yanked_reason: - yanked_reason = html.unescape(yanked_reason) - - link = Link( - url, - comes_from=page_url, - requires_python=pyrequire, - yanked_reason=yanked_reason, - ) - - return link - - -class CacheablePageContent: - def __init__(self, page: "HTMLPage") -> None: - assert page.cache_link_parsing - self.page = page - - def __eq__(self, other: object) -> bool: - return (isinstance(other, type(self)) and - self.page.url == other.page.url) - - def __hash__(self) -> int: - return hash(self.page.url) - - -def with_cached_html_pages( - fn: Callable[["HTMLPage"], Iterable[Link]], -) -> Callable[["HTMLPage"], List[Link]]: - """ - Given a function that parses an Iterable[Link] from an HTMLPage, cache the - function's result (keyed by CacheablePageContent), unless the HTMLPage - `page` has `page.cache_link_parsing == False`. - """ - - @functools.lru_cache(maxsize=None) - def wrapper(cacheable_page: CacheablePageContent) -> List[Link]: - return list(fn(cacheable_page.page)) - - @functools.wraps(fn) - def wrapper_wrapper(page: "HTMLPage") -> List[Link]: - if page.cache_link_parsing: - return wrapper(CacheablePageContent(page)) - return list(fn(page)) - - return wrapper_wrapper - - -@with_cached_html_pages -def parse_links(page: "HTMLPage") -> Iterable[Link]: - """ - Parse an HTML document, and yield its anchor elements as Link objects. - """ - document = html5lib.parse( - page.content, - transport_encoding=page.encoding, - namespaceHTMLElements=False, - ) - - url = page.url - base_url = _determine_base_url(document, url) - for anchor in document.findall(".//a"): - link = _create_link_from_element( - anchor, - page_url=url, - base_url=base_url, - ) - if link is None: - continue - yield link - - -class HTMLPage: - """Represents one page, along with its URL""" - - def __init__( - self, - content: bytes, - encoding: Optional[str], - url: str, - cache_link_parsing: bool = True, - ) -> None: - """ - :param encoding: the encoding to decode the given content. - :param url: the URL from which the HTML was downloaded. - :param cache_link_parsing: whether links parsed from this page's url - should be cached. PyPI index urls should - have this set to False, for example. - """ - self.content = content - self.encoding = encoding - self.url = url - self.cache_link_parsing = cache_link_parsing - - def __str__(self) -> str: - return redact_auth_from_url(self.url) - - -def _handle_get_page_fail( - link: Link, - reason: Union[str, Exception], - meth: Optional[Callable[..., None]] = None -) -> None: - if meth is None: - meth = logger.debug - meth("Could not fetch URL %s: %s - skipping", link, reason) - - -def _make_html_page(response: Response, cache_link_parsing: bool = True) -> HTMLPage: - encoding = _get_encoding_from_headers(response.headers) - return HTMLPage( - response.content, - encoding=encoding, - url=response.url, - cache_link_parsing=cache_link_parsing) - - -def _get_html_page( - link: Link, session: Optional[PipSession] = None -) -> Optional["HTMLPage"]: - if session is None: - raise TypeError( - "_get_html_page() missing 1 required keyword argument: 'session'" - ) - - url = link.url.split('#', 1)[0] - - # Check for VCS schemes that do not support lookup as web pages. - vcs_scheme = _match_vcs_scheme(url) - if vcs_scheme: - logger.warning('Cannot look at %s URL %s because it does not support ' - 'lookup as web pages.', vcs_scheme, link) - return None - - # Tack index.html onto file:// URLs that point to directories - scheme, _, path, _, _, _ = urllib.parse.urlparse(url) - if (scheme == 'file' and os.path.isdir(urllib.request.url2pathname(path))): - # add trailing slash if not present so urljoin doesn't trim - # final segment - if not url.endswith('/'): - url += '/' - url = urllib.parse.urljoin(url, 'index.html') - logger.debug(' file: URL is directory, getting %s', url) - - try: - resp = _get_html_response(url, session=session) - except _NotHTTP: - logger.warning( - 'Skipping page %s because it looks like an archive, and cannot ' - 'be checked by a HTTP HEAD request.', link, - ) - except _NotHTML as exc: - logger.warning( - 'Skipping page %s because the %s request got Content-Type: %s.' - 'The only supported Content-Type is text/html', - link, exc.request_desc, exc.content_type, - ) - except NetworkConnectionError as exc: - _handle_get_page_fail(link, exc) - except RetryError as exc: - _handle_get_page_fail(link, exc) - except SSLError as exc: - reason = "There was a problem confirming the ssl certificate: " - reason += str(exc) - _handle_get_page_fail(link, reason, meth=logger.info) - except requests.ConnectionError as exc: - _handle_get_page_fail(link, f"connection error: {exc}") - except requests.Timeout: - _handle_get_page_fail(link, "timed out") - else: - return _make_html_page(resp, - cache_link_parsing=link.cache_link_parsing) - return None - - -class CollectedSources(NamedTuple): - find_links: Sequence[Optional[LinkSource]] - index_urls: Sequence[Optional[LinkSource]] - - -class LinkCollector: - - """ - Responsible for collecting Link objects from all configured locations, - making network requests as needed. - - The class's main method is its collect_sources() method. - """ - - def __init__( - self, - session: PipSession, - search_scope: SearchScope, - ) -> None: - self.search_scope = search_scope - self.session = session - - @classmethod - def create( - cls, session: PipSession, - options: Values, - suppress_no_index: bool = False - ) -> "LinkCollector": - """ - :param session: The Session to use to make requests. - :param suppress_no_index: Whether to ignore the --no-index option - when constructing the SearchScope object. - """ - index_urls = [options.index_url] + options.extra_index_urls - if options.no_index and not suppress_no_index: - logger.debug( - 'Ignoring indexes: %s', - ','.join(redact_auth_from_url(url) for url in index_urls), - ) - index_urls = [] - - # Make sure find_links is a list before passing to create(). - find_links = options.find_links or [] - - search_scope = SearchScope.create( - find_links=find_links, index_urls=index_urls, - ) - link_collector = LinkCollector( - session=session, search_scope=search_scope, - ) - return link_collector - - @property - def find_links(self) -> List[str]: - return self.search_scope.find_links - - def fetch_page(self, location: Link) -> Optional[HTMLPage]: - """ - Fetch an HTML page containing package links. - """ - return _get_html_page(location, session=self.session) - - def collect_sources( - self, - project_name: str, - candidates_from_page: CandidatesFromPage, - ) -> CollectedSources: - # The OrderedDict calls deduplicate sources by URL. - index_url_sources = collections.OrderedDict( - build_source( - loc, - candidates_from_page=candidates_from_page, - page_validator=self.session.is_secure_origin, - expand_dir=False, - cache_link_parsing=False, - ) - for loc in self.search_scope.get_index_urls_locations(project_name) - ).values() - find_links_sources = collections.OrderedDict( - build_source( - loc, - candidates_from_page=candidates_from_page, - page_validator=self.session.is_secure_origin, - expand_dir=True, - cache_link_parsing=True, - ) - for loc in self.find_links - ).values() - - if logger.isEnabledFor(logging.DEBUG): - lines = [ - f"* {s.link}" - for s in itertools.chain(find_links_sources, index_url_sources) - if s is not None and s.link is not None - ] - lines = [ - f"{len(lines)} location(s) to search " - f"for versions of {project_name}:" - ] + lines - logger.debug("\n".join(lines)) - - return CollectedSources( - find_links=list(find_links_sources), - index_urls=list(index_url_sources), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/package_finder.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/package_finder.py deleted file mode 100644 index 2dadb5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/package_finder.py +++ /dev/null @@ -1,982 +0,0 @@ -"""Routines related to PyPI, indexes""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import functools -import itertools -import logging -import re -from typing import FrozenSet, Iterable, List, Optional, Set, Tuple, Union - -from pip._vendor.packaging import specifiers -from pip._vendor.packaging.tags import Tag -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import _BaseVersion -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.exceptions import ( - BestVersionAlreadyInstalled, - DistributionNotFound, - InvalidWheelFilename, - UnsupportedWheel, -) -from pip._internal.index.collector import LinkCollector, parse_links -from pip._internal.models.candidate import InstallationCandidate -from pip._internal.models.format_control import FormatControl -from pip._internal.models.link import Link -from pip._internal.models.search_scope import SearchScope -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.models.target_python import TargetPython -from pip._internal.models.wheel import Wheel -from pip._internal.req import InstallRequirement -from pip._internal.utils._log import getLogger -from pip._internal.utils.filetypes import WHEEL_EXTENSION -from pip._internal.utils.hashes import Hashes -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import build_netloc -from pip._internal.utils.packaging import check_requires_python -from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS -from pip._internal.utils.urls import url_to_path - -__all__ = ['FormatControl', 'BestCandidateResult', 'PackageFinder'] - - -logger = getLogger(__name__) - -BuildTag = Union[Tuple[()], Tuple[int, str]] -CandidateSortingKey = ( - Tuple[int, int, int, _BaseVersion, Optional[int], BuildTag] -) - - -def _check_link_requires_python( - link: Link, - version_info: Tuple[int, int, int], - ignore_requires_python: bool = False, -) -> bool: - """ - Return whether the given Python version is compatible with a link's - "Requires-Python" value. - - :param version_info: A 3-tuple of ints representing the Python - major-minor-micro version to check. - :param ignore_requires_python: Whether to ignore the "Requires-Python" - value if the given Python version isn't compatible. - """ - try: - is_compatible = check_requires_python( - link.requires_python, version_info=version_info, - ) - except specifiers.InvalidSpecifier: - logger.debug( - "Ignoring invalid Requires-Python (%r) for link: %s", - link.requires_python, link, - ) - else: - if not is_compatible: - version = '.'.join(map(str, version_info)) - if not ignore_requires_python: - logger.verbose( - 'Link requires a different Python (%s not in: %r): %s', - version, link.requires_python, link, - ) - return False - - logger.debug( - 'Ignoring failed Requires-Python check (%s not in: %r) ' - 'for link: %s', - version, link.requires_python, link, - ) - - return True - - -class LinkEvaluator: - - """ - Responsible for evaluating links for a particular project. - """ - - _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - def __init__( - self, - project_name: str, - canonical_name: str, - formats: FrozenSet[str], - target_python: TargetPython, - allow_yanked: bool, - ignore_requires_python: Optional[bool] = None, - ) -> None: - """ - :param project_name: The user supplied package name. - :param canonical_name: The canonical package name. - :param formats: The formats allowed for this package. Should be a set - with 'binary' or 'source' or both in it. - :param target_python: The target Python interpreter to use when - evaluating link compatibility. This is used, for example, to - check wheel compatibility, as well as when checking the Python - version, e.g. the Python version embedded in a link filename - (or egg fragment) and against an HTML link's optional PEP 503 - "data-requires-python" attribute. - :param allow_yanked: Whether files marked as yanked (in the sense - of PEP 592) are permitted to be candidates for install. - :param ignore_requires_python: Whether to ignore incompatible - PEP 503 "data-requires-python" values in HTML links. Defaults - to False. - """ - if ignore_requires_python is None: - ignore_requires_python = False - - self._allow_yanked = allow_yanked - self._canonical_name = canonical_name - self._ignore_requires_python = ignore_requires_python - self._formats = formats - self._target_python = target_python - - self.project_name = project_name - - def evaluate_link(self, link: Link) -> Tuple[bool, Optional[str]]: - """ - Determine whether a link is a candidate for installation. - - :return: A tuple (is_candidate, result), where `result` is (1) a - version string if `is_candidate` is True, and (2) if - `is_candidate` is False, an optional string to log the reason - the link fails to qualify. - """ - version = None - if link.is_yanked and not self._allow_yanked: - reason = link.yanked_reason or '' - return (False, f'yanked for reason: {reason}') - - if link.egg_fragment: - egg_info = link.egg_fragment - ext = link.ext - else: - egg_info, ext = link.splitext() - if not ext: - return (False, 'not a file') - if ext not in SUPPORTED_EXTENSIONS: - return (False, f'unsupported archive format: {ext}') - if "binary" not in self._formats and ext == WHEEL_EXTENSION: - reason = 'No binaries permitted for {}'.format( - self.project_name) - return (False, reason) - if "macosx10" in link.path and ext == '.zip': - return (False, 'macosx10 one') - if ext == WHEEL_EXTENSION: - try: - wheel = Wheel(link.filename) - except InvalidWheelFilename: - return (False, 'invalid wheel filename') - if canonicalize_name(wheel.name) != self._canonical_name: - reason = 'wrong project name (not {})'.format( - self.project_name) - return (False, reason) - - supported_tags = self._target_python.get_tags() - if not wheel.supported(supported_tags): - # Include the wheel's tags in the reason string to - # simplify troubleshooting compatibility issues. - file_tags = wheel.get_formatted_file_tags() - reason = ( - "none of the wheel's tags ({}) are compatible " - "(run pip debug --verbose to show compatible tags)".format( - ', '.join(file_tags) - ) - ) - return (False, reason) - - version = wheel.version - - # This should be up by the self.ok_binary check, but see issue 2700. - if "source" not in self._formats and ext != WHEEL_EXTENSION: - reason = f'No sources permitted for {self.project_name}' - return (False, reason) - - if not version: - version = _extract_version_from_fragment( - egg_info, self._canonical_name, - ) - if not version: - reason = f'Missing project version for {self.project_name}' - return (False, reason) - - match = self._py_version_re.search(version) - if match: - version = version[:match.start()] - py_version = match.group(1) - if py_version != self._target_python.py_version: - return (False, 'Python version is incorrect') - - supports_python = _check_link_requires_python( - link, version_info=self._target_python.py_version_info, - ignore_requires_python=self._ignore_requires_python, - ) - if not supports_python: - # Return None for the reason text to suppress calling - # _log_skipped_link(). - return (False, None) - - logger.debug('Found link %s, version: %s', link, version) - - return (True, version) - - -def filter_unallowed_hashes( - candidates: List[InstallationCandidate], - hashes: Hashes, - project_name: str, -) -> List[InstallationCandidate]: - """ - Filter out candidates whose hashes aren't allowed, and return a new - list of candidates. - - If at least one candidate has an allowed hash, then all candidates with - either an allowed hash or no hash specified are returned. Otherwise, - the given candidates are returned. - - Including the candidates with no hash specified when there is a match - allows a warning to be logged if there is a more preferred candidate - with no hash specified. Returning all candidates in the case of no - matches lets pip report the hash of the candidate that would otherwise - have been installed (e.g. permitting the user to more easily update - their requirements file with the desired hash). - """ - if not hashes: - logger.debug( - 'Given no hashes to check %s links for project %r: ' - 'discarding no candidates', - len(candidates), - project_name, - ) - # Make sure we're not returning back the given value. - return list(candidates) - - matches_or_no_digest = [] - # Collect the non-matches for logging purposes. - non_matches = [] - match_count = 0 - for candidate in candidates: - link = candidate.link - if not link.has_hash: - pass - elif link.is_hash_allowed(hashes=hashes): - match_count += 1 - else: - non_matches.append(candidate) - continue - - matches_or_no_digest.append(candidate) - - if match_count: - filtered = matches_or_no_digest - else: - # Make sure we're not returning back the given value. - filtered = list(candidates) - - if len(filtered) == len(candidates): - discard_message = 'discarding no candidates' - else: - discard_message = 'discarding {} non-matches:\n {}'.format( - len(non_matches), - '\n '.join(str(candidate.link) for candidate in non_matches) - ) - - logger.debug( - 'Checked %s links for project %r against %s hashes ' - '(%s matches, %s no digest): %s', - len(candidates), - project_name, - hashes.digest_count, - match_count, - len(matches_or_no_digest) - match_count, - discard_message - ) - - return filtered - - -class CandidatePreferences: - - """ - Encapsulates some of the preferences for filtering and sorting - InstallationCandidate objects. - """ - - def __init__( - self, - prefer_binary: bool = False, - allow_all_prereleases: bool = False, - ) -> None: - """ - :param allow_all_prereleases: Whether to allow all pre-releases. - """ - self.allow_all_prereleases = allow_all_prereleases - self.prefer_binary = prefer_binary - - -class BestCandidateResult: - """A collection of candidates, returned by `PackageFinder.find_best_candidate`. - - This class is only intended to be instantiated by CandidateEvaluator's - `compute_best_candidate()` method. - """ - - def __init__( - self, - candidates: List[InstallationCandidate], - applicable_candidates: List[InstallationCandidate], - best_candidate: Optional[InstallationCandidate], - ) -> None: - """ - :param candidates: A sequence of all available candidates found. - :param applicable_candidates: The applicable candidates. - :param best_candidate: The most preferred candidate found, or None - if no applicable candidates were found. - """ - assert set(applicable_candidates) <= set(candidates) - - if best_candidate is None: - assert not applicable_candidates - else: - assert best_candidate in applicable_candidates - - self._applicable_candidates = applicable_candidates - self._candidates = candidates - - self.best_candidate = best_candidate - - def iter_all(self) -> Iterable[InstallationCandidate]: - """Iterate through all candidates. - """ - return iter(self._candidates) - - def iter_applicable(self) -> Iterable[InstallationCandidate]: - """Iterate through the applicable candidates. - """ - return iter(self._applicable_candidates) - - -class CandidateEvaluator: - - """ - Responsible for filtering and sorting candidates for installation based - on what tags are valid. - """ - - @classmethod - def create( - cls, - project_name: str, - target_python: Optional[TargetPython] = None, - prefer_binary: bool = False, - allow_all_prereleases: bool = False, - specifier: Optional[specifiers.BaseSpecifier] = None, - hashes: Optional[Hashes] = None, - ) -> "CandidateEvaluator": - """Create a CandidateEvaluator object. - - :param target_python: The target Python interpreter to use when - checking compatibility. If None (the default), a TargetPython - object will be constructed from the running Python. - :param specifier: An optional object implementing `filter` - (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable - versions. - :param hashes: An optional collection of allowed hashes. - """ - if target_python is None: - target_python = TargetPython() - if specifier is None: - specifier = specifiers.SpecifierSet() - - supported_tags = target_python.get_tags() - - return cls( - project_name=project_name, - supported_tags=supported_tags, - specifier=specifier, - prefer_binary=prefer_binary, - allow_all_prereleases=allow_all_prereleases, - hashes=hashes, - ) - - def __init__( - self, - project_name: str, - supported_tags: List[Tag], - specifier: specifiers.BaseSpecifier, - prefer_binary: bool = False, - allow_all_prereleases: bool = False, - hashes: Optional[Hashes] = None, - ) -> None: - """ - :param supported_tags: The PEP 425 tags supported by the target - Python in order of preference (most preferred first). - """ - self._allow_all_prereleases = allow_all_prereleases - self._hashes = hashes - self._prefer_binary = prefer_binary - self._project_name = project_name - self._specifier = specifier - self._supported_tags = supported_tags - # Since the index of the tag in the _supported_tags list is used - # as a priority, precompute a map from tag to index/priority to be - # used in wheel.find_most_preferred_tag. - self._wheel_tag_preferences = { - tag: idx for idx, tag in enumerate(supported_tags) - } - - def get_applicable_candidates( - self, - candidates: List[InstallationCandidate], - ) -> List[InstallationCandidate]: - """ - Return the applicable candidates from a list of candidates. - """ - # Using None infers from the specifier instead. - allow_prereleases = self._allow_all_prereleases or None - specifier = self._specifier - versions = { - str(v) for v in specifier.filter( - # We turn the version object into a str here because otherwise - # when we're debundled but setuptools isn't, Python will see - # packaging.version.Version and - # pkg_resources._vendor.packaging.version.Version as different - # types. This way we'll use a str as a common data interchange - # format. If we stop using the pkg_resources provided specifier - # and start using our own, we can drop the cast to str(). - (str(c.version) for c in candidates), - prereleases=allow_prereleases, - ) - } - - # Again, converting version to str to deal with debundling. - applicable_candidates = [ - c for c in candidates if str(c.version) in versions - ] - - filtered_applicable_candidates = filter_unallowed_hashes( - candidates=applicable_candidates, - hashes=self._hashes, - project_name=self._project_name, - ) - - return sorted(filtered_applicable_candidates, key=self._sort_key) - - def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey: - """ - Function to pass as the `key` argument to a call to sorted() to sort - InstallationCandidates by preference. - - Returns a tuple such that tuples sorting as greater using Python's - default comparison operator are more preferred. - - The preference is as follows: - - First and foremost, candidates with allowed (matching) hashes are - always preferred over candidates without matching hashes. This is - because e.g. if the only candidate with an allowed hash is yanked, - we still want to use that candidate. - - Second, excepting hash considerations, candidates that have been - yanked (in the sense of PEP 592) are always less preferred than - candidates that haven't been yanked. Then: - - If not finding wheels, they are sorted by version only. - If finding wheels, then the sort order is by version, then: - 1. existing installs - 2. wheels ordered via Wheel.support_index_min(self._supported_tags) - 3. source archives - If prefer_binary was set, then all wheels are sorted above sources. - - Note: it was considered to embed this logic into the Link - comparison operators, but then different sdist links - with the same version, would have to be considered equal - """ - valid_tags = self._supported_tags - support_num = len(valid_tags) - build_tag: BuildTag = () - binary_preference = 0 - link = candidate.link - if link.is_wheel: - # can raise InvalidWheelFilename - wheel = Wheel(link.filename) - try: - pri = -(wheel.find_most_preferred_tag( - valid_tags, self._wheel_tag_preferences - )) - except ValueError: - raise UnsupportedWheel( - "{} is not a supported wheel for this platform. It " - "can't be sorted.".format(wheel.filename) - ) - if self._prefer_binary: - binary_preference = 1 - if wheel.build_tag is not None: - match = re.match(r'^(\d+)(.*)$', wheel.build_tag) - build_tag_groups = match.groups() - build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) - else: # sdist - pri = -(support_num) - has_allowed_hash = int(link.is_hash_allowed(self._hashes)) - yank_value = -1 * int(link.is_yanked) # -1 for yanked. - return ( - has_allowed_hash, yank_value, binary_preference, candidate.version, - pri, build_tag, - ) - - def sort_best_candidate( - self, - candidates: List[InstallationCandidate], - ) -> Optional[InstallationCandidate]: - """ - Return the best candidate per the instance's sort order, or None if - no candidate is acceptable. - """ - if not candidates: - return None - best_candidate = max(candidates, key=self._sort_key) - return best_candidate - - def compute_best_candidate( - self, - candidates: List[InstallationCandidate], - ) -> BestCandidateResult: - """ - Compute and return a `BestCandidateResult` instance. - """ - applicable_candidates = self.get_applicable_candidates(candidates) - - best_candidate = self.sort_best_candidate(applicable_candidates) - - return BestCandidateResult( - candidates, - applicable_candidates=applicable_candidates, - best_candidate=best_candidate, - ) - - -class PackageFinder: - """This finds packages. - - This is meant to match easy_install's technique for looking for - packages, by reading pages and looking for appropriate links. - """ - - def __init__( - self, - link_collector: LinkCollector, - target_python: TargetPython, - allow_yanked: bool, - format_control: Optional[FormatControl] = None, - candidate_prefs: Optional[CandidatePreferences] = None, - ignore_requires_python: Optional[bool] = None, - ) -> None: - """ - This constructor is primarily meant to be used by the create() class - method and from tests. - - :param format_control: A FormatControl object, used to control - the selection of source packages / binary packages when consulting - the index and links. - :param candidate_prefs: Options to use when creating a - CandidateEvaluator object. - """ - if candidate_prefs is None: - candidate_prefs = CandidatePreferences() - - format_control = format_control or FormatControl(set(), set()) - - self._allow_yanked = allow_yanked - self._candidate_prefs = candidate_prefs - self._ignore_requires_python = ignore_requires_python - self._link_collector = link_collector - self._target_python = target_python - - self.format_control = format_control - - # These are boring links that have already been logged somehow. - self._logged_links: Set[Link] = set() - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - @classmethod - def create( - cls, - link_collector: LinkCollector, - selection_prefs: SelectionPreferences, - target_python: Optional[TargetPython] = None, - ) -> "PackageFinder": - """Create a PackageFinder. - - :param selection_prefs: The candidate selection preferences, as a - SelectionPreferences object. - :param target_python: The target Python interpreter to use when - checking compatibility. If None (the default), a TargetPython - object will be constructed from the running Python. - """ - if target_python is None: - target_python = TargetPython() - - candidate_prefs = CandidatePreferences( - prefer_binary=selection_prefs.prefer_binary, - allow_all_prereleases=selection_prefs.allow_all_prereleases, - ) - - return cls( - candidate_prefs=candidate_prefs, - link_collector=link_collector, - target_python=target_python, - allow_yanked=selection_prefs.allow_yanked, - format_control=selection_prefs.format_control, - ignore_requires_python=selection_prefs.ignore_requires_python, - ) - - @property - def target_python(self) -> TargetPython: - return self._target_python - - @property - def search_scope(self) -> SearchScope: - return self._link_collector.search_scope - - @search_scope.setter - def search_scope(self, search_scope: SearchScope) -> None: - self._link_collector.search_scope = search_scope - - @property - def find_links(self) -> List[str]: - return self._link_collector.find_links - - @property - def index_urls(self) -> List[str]: - return self.search_scope.index_urls - - @property - def trusted_hosts(self) -> Iterable[str]: - for host_port in self._link_collector.session.pip_trusted_origins: - yield build_netloc(*host_port) - - @property - def allow_all_prereleases(self) -> bool: - return self._candidate_prefs.allow_all_prereleases - - def set_allow_all_prereleases(self) -> None: - self._candidate_prefs.allow_all_prereleases = True - - @property - def prefer_binary(self) -> bool: - return self._candidate_prefs.prefer_binary - - def set_prefer_binary(self) -> None: - self._candidate_prefs.prefer_binary = True - - def make_link_evaluator(self, project_name: str) -> LinkEvaluator: - canonical_name = canonicalize_name(project_name) - formats = self.format_control.get_allowed_formats(canonical_name) - - return LinkEvaluator( - project_name=project_name, - canonical_name=canonical_name, - formats=formats, - target_python=self._target_python, - allow_yanked=self._allow_yanked, - ignore_requires_python=self._ignore_requires_python, - ) - - def _sort_links(self, links: Iterable[Link]) -> List[Link]: - """ - Returns elements of links in order, non-egg links first, egg links - second, while eliminating duplicates - """ - eggs, no_eggs = [], [] - seen: Set[Link] = set() - for link in links: - if link not in seen: - seen.add(link) - if link.egg_fragment: - eggs.append(link) - else: - no_eggs.append(link) - return no_eggs + eggs - - def _log_skipped_link(self, link: Link, reason: str) -> None: - if link not in self._logged_links: - # Put the link at the end so the reason is more visible and because - # the link string is usually very long. - logger.debug('Skipping link: %s: %s', reason, link) - self._logged_links.add(link) - - def get_install_candidate( - self, link_evaluator: LinkEvaluator, link: Link - ) -> Optional[InstallationCandidate]: - """ - If the link is a candidate for install, convert it to an - InstallationCandidate and return it. Otherwise, return None. - """ - is_candidate, result = link_evaluator.evaluate_link(link) - if not is_candidate: - if result: - self._log_skipped_link(link, reason=result) - return None - - return InstallationCandidate( - name=link_evaluator.project_name, - link=link, - version=result, - ) - - def evaluate_links( - self, link_evaluator: LinkEvaluator, links: Iterable[Link] - ) -> List[InstallationCandidate]: - """ - Convert links that are candidates to InstallationCandidate objects. - """ - candidates = [] - for link in self._sort_links(links): - candidate = self.get_install_candidate(link_evaluator, link) - if candidate is not None: - candidates.append(candidate) - - return candidates - - def process_project_url( - self, project_url: Link, link_evaluator: LinkEvaluator - ) -> List[InstallationCandidate]: - logger.debug( - 'Fetching project page and analyzing links: %s', project_url, - ) - html_page = self._link_collector.fetch_page(project_url) - if html_page is None: - return [] - - page_links = list(parse_links(html_page)) - - with indent_log(): - package_links = self.evaluate_links( - link_evaluator, - links=page_links, - ) - - return package_links - - @functools.lru_cache(maxsize=None) - def find_all_candidates(self, project_name: str) -> List[InstallationCandidate]: - """Find all available InstallationCandidate for project_name - - This checks index_urls and find_links. - All versions found are returned as an InstallationCandidate list. - - See LinkEvaluator.evaluate_link() for details on which files - are accepted. - """ - link_evaluator = self.make_link_evaluator(project_name) - - collected_sources = self._link_collector.collect_sources( - project_name=project_name, - candidates_from_page=functools.partial( - self.process_project_url, - link_evaluator=link_evaluator, - ), - ) - - page_candidates_it = itertools.chain.from_iterable( - source.page_candidates() - for sources in collected_sources - for source in sources - if source is not None - ) - page_candidates = list(page_candidates_it) - - file_links_it = itertools.chain.from_iterable( - source.file_links() - for sources in collected_sources - for source in sources - if source is not None - ) - file_candidates = self.evaluate_links( - link_evaluator, - sorted(file_links_it, reverse=True), - ) - - if logger.isEnabledFor(logging.DEBUG) and file_candidates: - paths = [url_to_path(c.link.url) for c in file_candidates] - logger.debug("Local files found: %s", ", ".join(paths)) - - # This is an intentional priority ordering - return file_candidates + page_candidates - - def make_candidate_evaluator( - self, - project_name: str, - specifier: Optional[specifiers.BaseSpecifier] = None, - hashes: Optional[Hashes] = None, - ) -> CandidateEvaluator: - """Create a CandidateEvaluator object to use. - """ - candidate_prefs = self._candidate_prefs - return CandidateEvaluator.create( - project_name=project_name, - target_python=self._target_python, - prefer_binary=candidate_prefs.prefer_binary, - allow_all_prereleases=candidate_prefs.allow_all_prereleases, - specifier=specifier, - hashes=hashes, - ) - - @functools.lru_cache(maxsize=None) - def find_best_candidate( - self, - project_name: str, - specifier: Optional[specifiers.BaseSpecifier] = None, - hashes: Optional[Hashes] = None, - ) -> BestCandidateResult: - """Find matches for the given project and specifier. - - :param specifier: An optional object implementing `filter` - (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable - versions. - - :return: A `BestCandidateResult` instance. - """ - candidates = self.find_all_candidates(project_name) - candidate_evaluator = self.make_candidate_evaluator( - project_name=project_name, - specifier=specifier, - hashes=hashes, - ) - return candidate_evaluator.compute_best_candidate(candidates) - - def find_requirement( - self, req: InstallRequirement, upgrade: bool - ) -> Optional[InstallationCandidate]: - """Try to find a Link matching req - - Expects req, an InstallRequirement and upgrade, a boolean - Returns a InstallationCandidate if found, - Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise - """ - hashes = req.hashes(trust_internet=False) - best_candidate_result = self.find_best_candidate( - req.name, specifier=req.specifier, hashes=hashes, - ) - best_candidate = best_candidate_result.best_candidate - - installed_version: Optional[_BaseVersion] = None - if req.satisfied_by is not None: - installed_version = parse_version(req.satisfied_by.version) - - def _format_versions(cand_iter: Iterable[InstallationCandidate]) -> str: - # This repeated parse_version and str() conversion is needed to - # handle different vendoring sources from pip and pkg_resources. - # If we stop using the pkg_resources provided specifier and start - # using our own, we can drop the cast to str(). - return ", ".join(sorted( - {str(c.version) for c in cand_iter}, - key=parse_version, - )) or "none" - - if installed_version is None and best_candidate is None: - logger.critical( - 'Could not find a version that satisfies the requirement %s ' - '(from versions: %s)', - req, - _format_versions(best_candidate_result.iter_all()), - ) - - raise DistributionNotFound( - 'No matching distribution found for {}'.format( - req) - ) - - best_installed = False - if installed_version and ( - best_candidate is None or - best_candidate.version <= installed_version): - best_installed = True - - if not upgrade and installed_version is not None: - if best_installed: - logger.debug( - 'Existing installed version (%s) is most up-to-date and ' - 'satisfies requirement', - installed_version, - ) - else: - logger.debug( - 'Existing installed version (%s) satisfies requirement ' - '(most up-to-date version is %s)', - installed_version, - best_candidate.version, - ) - return None - - if best_installed: - # We have an existing version, and its the best version - logger.debug( - 'Installed version (%s) is most up-to-date (past versions: ' - '%s)', - installed_version, - _format_versions(best_candidate_result.iter_applicable()), - ) - raise BestVersionAlreadyInstalled - - logger.debug( - 'Using version %s (newest of versions: %s)', - best_candidate.version, - _format_versions(best_candidate_result.iter_applicable()), - ) - return best_candidate - - -def _find_name_version_sep(fragment: str, canonical_name: str) -> int: - """Find the separator's index based on the package's canonical name. - - :param fragment: A + filename "fragment" (stem) or - egg fragment. - :param canonical_name: The package's canonical name. - - This function is needed since the canonicalized name does not necessarily - have the same length as the egg info's name part. An example:: - - >>> fragment = 'foo__bar-1.0' - >>> canonical_name = 'foo-bar' - >>> _find_name_version_sep(fragment, canonical_name) - 8 - """ - # Project name and version must be separated by one single dash. Find all - # occurrences of dashes; if the string in front of it matches the canonical - # name, this is the one separating the name and version parts. - for i, c in enumerate(fragment): - if c != "-": - continue - if canonicalize_name(fragment[:i]) == canonical_name: - return i - raise ValueError(f"{fragment} does not match {canonical_name}") - - -def _extract_version_from_fragment(fragment: str, canonical_name: str) -> Optional[str]: - """Parse the version string from a + filename - "fragment" (stem) or egg fragment. - - :param fragment: The string to parse. E.g. foo-2.1 - :param canonical_name: The canonicalized name of the package this - belongs to. - """ - try: - version_start = _find_name_version_sep(fragment, canonical_name) + 1 - except ValueError: - return None - version = fragment[version_start:] - if not version: - return None - return version diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/sources.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/sources.py deleted file mode 100644 index eec3f12..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/index/sources.py +++ /dev/null @@ -1,224 +0,0 @@ -import logging -import mimetypes -import os -import pathlib -from typing import Callable, Iterable, Optional, Tuple - -from pip._internal.models.candidate import InstallationCandidate -from pip._internal.models.link import Link -from pip._internal.utils.urls import path_to_url, url_to_path -from pip._internal.vcs import is_url - -logger = logging.getLogger(__name__) - -FoundCandidates = Iterable[InstallationCandidate] -FoundLinks = Iterable[Link] -CandidatesFromPage = Callable[[Link], Iterable[InstallationCandidate]] -PageValidator = Callable[[Link], bool] - - -class LinkSource: - @property - def link(self) -> Optional[Link]: - """Returns the underlying link, if there's one.""" - raise NotImplementedError() - - def page_candidates(self) -> FoundCandidates: - """Candidates found by parsing an archive listing HTML file.""" - raise NotImplementedError() - - def file_links(self) -> FoundLinks: - """Links found by specifying archives directly.""" - raise NotImplementedError() - - -def _is_html_file(file_url: str) -> bool: - return mimetypes.guess_type(file_url, strict=False)[0] == "text/html" - - -class _FlatDirectorySource(LinkSource): - """Link source specified by ``--find-links=``. - - This looks the content of the directory, and returns: - - * ``page_candidates``: Links listed on each HTML file in the directory. - * ``file_candidates``: Archives in the directory. - """ - - def __init__( - self, - candidates_from_page: CandidatesFromPage, - path: str, - ) -> None: - self._candidates_from_page = candidates_from_page - self._path = pathlib.Path(os.path.realpath(path)) - - @property - def link(self) -> Optional[Link]: - return None - - def page_candidates(self) -> FoundCandidates: - for path in self._path.iterdir(): - url = path_to_url(str(path)) - if not _is_html_file(url): - continue - yield from self._candidates_from_page(Link(url)) - - def file_links(self) -> FoundLinks: - for path in self._path.iterdir(): - url = path_to_url(str(path)) - if _is_html_file(url): - continue - yield Link(url) - - -class _LocalFileSource(LinkSource): - """``--find-links=`` or ``--[extra-]index-url=``. - - If a URL is supplied, it must be a ``file:`` URL. If a path is supplied to - the option, it is converted to a URL first. This returns: - - * ``page_candidates``: Links listed on an HTML file. - * ``file_candidates``: The non-HTML file. - """ - - def __init__( - self, - candidates_from_page: CandidatesFromPage, - link: Link, - ) -> None: - self._candidates_from_page = candidates_from_page - self._link = link - - @property - def link(self) -> Optional[Link]: - return self._link - - def page_candidates(self) -> FoundCandidates: - if not _is_html_file(self._link.url): - return - yield from self._candidates_from_page(self._link) - - def file_links(self) -> FoundLinks: - if _is_html_file(self._link.url): - return - yield self._link - - -class _RemoteFileSource(LinkSource): - """``--find-links=`` or ``--[extra-]index-url=``. - - This returns: - - * ``page_candidates``: Links listed on an HTML file. - * ``file_candidates``: The non-HTML file. - """ - - def __init__( - self, - candidates_from_page: CandidatesFromPage, - page_validator: PageValidator, - link: Link, - ) -> None: - self._candidates_from_page = candidates_from_page - self._page_validator = page_validator - self._link = link - - @property - def link(self) -> Optional[Link]: - return self._link - - def page_candidates(self) -> FoundCandidates: - if not self._page_validator(self._link): - return - yield from self._candidates_from_page(self._link) - - def file_links(self) -> FoundLinks: - yield self._link - - -class _IndexDirectorySource(LinkSource): - """``--[extra-]index-url=``. - - This is treated like a remote URL; ``candidates_from_page`` contains logic - for this by appending ``index.html`` to the link. - """ - - def __init__( - self, - candidates_from_page: CandidatesFromPage, - link: Link, - ) -> None: - self._candidates_from_page = candidates_from_page - self._link = link - - @property - def link(self) -> Optional[Link]: - return self._link - - def page_candidates(self) -> FoundCandidates: - yield from self._candidates_from_page(self._link) - - def file_links(self) -> FoundLinks: - return () - - -def build_source( - location: str, - *, - candidates_from_page: CandidatesFromPage, - page_validator: PageValidator, - expand_dir: bool, - cache_link_parsing: bool, -) -> Tuple[Optional[str], Optional[LinkSource]]: - - path: Optional[str] = None - url: Optional[str] = None - if os.path.exists(location): # Is a local path. - url = path_to_url(location) - path = location - elif location.startswith("file:"): # A file: URL. - url = location - path = url_to_path(location) - elif is_url(location): - url = location - - if url is None: - msg = ( - "Location '%s' is ignored: " - "it is either a non-existing path or lacks a specific scheme." - ) - logger.warning(msg, location) - return (None, None) - - if path is None: - source: LinkSource = _RemoteFileSource( - candidates_from_page=candidates_from_page, - page_validator=page_validator, - link=Link(url, cache_link_parsing=cache_link_parsing), - ) - return (url, source) - - if os.path.isdir(path): - if expand_dir: - source = _FlatDirectorySource( - candidates_from_page=candidates_from_page, - path=path, - ) - else: - source = _IndexDirectorySource( - candidates_from_page=candidates_from_page, - link=Link(url, cache_link_parsing=cache_link_parsing), - ) - return (url, source) - elif os.path.isfile(path): - source = _LocalFileSource( - candidates_from_page=candidates_from_page, - link=Link(url, cache_link_parsing=cache_link_parsing), - ) - return (url, source) - logger.warning( - "Location '%s' is ignored: it is neither a file nor a directory.", - location, - ) - return (url, None) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/__init__.py deleted file mode 100644 index 2c2fd86..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/__init__.py +++ /dev/null @@ -1,408 +0,0 @@ -import functools -import logging -import os -import pathlib -import sys -import sysconfig -from typing import Any, Dict, Iterator, List, Optional, Tuple - -from pip._internal.models.scheme import SCHEME_KEYS, Scheme -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.virtualenv import running_under_virtualenv - -from . import _distutils, _sysconfig -from .base import ( - USER_CACHE_DIR, - get_major_minor_version, - get_src_prefix, - is_osx_framework, - site_packages, - user_site, -) - -__all__ = [ - "USER_CACHE_DIR", - "get_bin_prefix", - "get_bin_user", - "get_major_minor_version", - "get_platlib", - "get_prefixed_libs", - "get_purelib", - "get_scheme", - "get_src_prefix", - "site_packages", - "user_site", -] - - -logger = logging.getLogger(__name__) - -if os.environ.get("_PIP_LOCATIONS_NO_WARN_ON_MISMATCH"): - _MISMATCH_LEVEL = logging.DEBUG -else: - _MISMATCH_LEVEL = logging.WARNING - -_PLATLIBDIR: str = getattr(sys, "platlibdir", "lib") - - -def _looks_like_bpo_44860() -> bool: - """The resolution to bpo-44860 will change this incorrect platlib. - - See . - """ - from distutils.command.install import INSTALL_SCHEMES # type: ignore - - try: - unix_user_platlib = INSTALL_SCHEMES["unix_user"]["platlib"] - except KeyError: - return False - return unix_user_platlib == "$usersite" - - -def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool: - platlib = scheme["platlib"] - if "/lib64/" not in platlib: - return False - unpatched = platlib.replace("/lib64/", "/lib/") - return unpatched.replace("$platbase/", "$base/") == scheme["purelib"] - - -@functools.lru_cache(maxsize=None) -def _looks_like_red_hat_lib() -> bool: - """Red Hat patches platlib in unix_prefix and unix_home, but not purelib. - - This is the only way I can see to tell a Red Hat-patched Python. - """ - from distutils.command.install import INSTALL_SCHEMES # type: ignore - - return all( - k in INSTALL_SCHEMES - and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k]) - for k in ("unix_prefix", "unix_home") - ) - - -@functools.lru_cache(maxsize=None) -def _looks_like_debian_scheme() -> bool: - """Debian adds two additional schemes.""" - from distutils.command.install import INSTALL_SCHEMES # type: ignore - - return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES - - -@functools.lru_cache(maxsize=None) -def _looks_like_red_hat_scheme() -> bool: - """Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``. - - Red Hat's ``00251-change-user-install-location.patch`` changes the install - command's ``prefix`` and ``exec_prefix`` to append ``"/local"``. This is - (fortunately?) done quite unconditionally, so we create a default command - object without any configuration to detect this. - """ - from distutils.command.install import install - from distutils.dist import Distribution - - cmd: Any = install(Distribution()) - cmd.finalize_options() - return ( - cmd.exec_prefix == f"{os.path.normpath(sys.exec_prefix)}/local" - and cmd.prefix == f"{os.path.normpath(sys.prefix)}/local" - ) - - -@functools.lru_cache(maxsize=None) -def _looks_like_msys2_mingw_scheme() -> bool: - """MSYS2 patches distutils and sysconfig to use a UNIX-like scheme. - - However, MSYS2 incorrectly patches sysconfig ``nt`` scheme. The fix is - likely going to be included in their 3.10 release, so we ignore the warning. - See msys2/MINGW-packages#9319. - - MSYS2 MINGW's patch uses lowercase ``"lib"`` instead of the usual uppercase, - and is missing the final ``"site-packages"``. - """ - paths = sysconfig.get_paths("nt", expand=False) - return all( - "Lib" not in p and "lib" in p and not p.endswith("site-packages") - for p in (paths[key] for key in ("platlib", "purelib")) - ) - - -def _fix_abiflags(parts: Tuple[str]) -> Iterator[str]: - ldversion = sysconfig.get_config_var("LDVERSION") - abiflags: str = getattr(sys, "abiflags", None) - - # LDVERSION does not end with sys.abiflags. Just return the path unchanged. - if not ldversion or not abiflags or not ldversion.endswith(abiflags): - yield from parts - return - - # Strip sys.abiflags from LDVERSION-based path components. - for part in parts: - if part.endswith(ldversion): - part = part[: (0 - len(abiflags))] - yield part - - -@functools.lru_cache(maxsize=None) -def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None: - issue_url = "https://github.com/pypa/pip/issues/10151" - message = ( - "Value for %s does not match. Please report this to <%s>" - "\ndistutils: %s" - "\nsysconfig: %s" - ) - logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new) - - -def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool: - if old == new: - return False - _warn_mismatched(old, new, key=key) - return True - - -@functools.lru_cache(maxsize=None) -def _log_context( - *, - user: bool = False, - home: Optional[str] = None, - root: Optional[str] = None, - prefix: Optional[str] = None, -) -> None: - parts = [ - "Additional context:", - "user = %r", - "home = %r", - "root = %r", - "prefix = %r", - ] - - logger.log(_MISMATCH_LEVEL, "\n".join(parts), user, home, root, prefix) - - -def get_scheme( - dist_name: str, - user: bool = False, - home: Optional[str] = None, - root: Optional[str] = None, - isolated: bool = False, - prefix: Optional[str] = None, -) -> Scheme: - old = _distutils.get_scheme( - dist_name, - user=user, - home=home, - root=root, - isolated=isolated, - prefix=prefix, - ) - new = _sysconfig.get_scheme( - dist_name, - user=user, - home=home, - root=root, - isolated=isolated, - prefix=prefix, - ) - - warning_contexts = [] - for k in SCHEME_KEYS: - old_v = pathlib.Path(getattr(old, k)) - new_v = pathlib.Path(getattr(new, k)) - - if old_v == new_v: - continue - - # distutils incorrectly put PyPy packages under ``site-packages/python`` - # in the ``posix_home`` scheme, but PyPy devs said they expect the - # directory name to be ``pypy`` instead. So we treat this as a bug fix - # and not warn about it. See bpo-43307 and python/cpython#24628. - skip_pypy_special_case = ( - sys.implementation.name == "pypy" - and home is not None - and k in ("platlib", "purelib") - and old_v.parent == new_v.parent - and old_v.name.startswith("python") - and new_v.name.startswith("pypy") - ) - if skip_pypy_special_case: - continue - - # sysconfig's ``osx_framework_user`` does not include ``pythonX.Y`` in - # the ``include`` value, but distutils's ``headers`` does. We'll let - # CPython decide whether this is a bug or feature. See bpo-43948. - skip_osx_framework_user_special_case = ( - user - and is_osx_framework() - and k == "headers" - and old_v.parent.parent == new_v.parent - and old_v.parent.name.startswith("python") - ) - if skip_osx_framework_user_special_case: - continue - - # On Red Hat and derived Linux distributions, distutils is patched to - # use "lib64" instead of "lib" for platlib. - if k == "platlib" and _looks_like_red_hat_lib(): - continue - - # On Python 3.9+, sysconfig's posix_user scheme sets platlib against - # sys.platlibdir, but distutils's unix_user incorrectly coninutes - # using the same $usersite for both platlib and purelib. This creates a - # mismatch when sys.platlibdir is not "lib". - skip_bpo_44860 = ( - user - and k == "platlib" - and not WINDOWS - and sys.version_info >= (3, 9) - and _PLATLIBDIR != "lib" - and _looks_like_bpo_44860() - ) - if skip_bpo_44860: - continue - - # Both Debian and Red Hat patch Python to place the system site under - # /usr/local instead of /usr. Debian also places lib in dist-packages - # instead of site-packages, but the /usr/local check should cover it. - skip_linux_system_special_case = ( - not (user or home or prefix or running_under_virtualenv()) - and old_v.parts[1:3] == ("usr", "local") - and len(new_v.parts) > 1 - and new_v.parts[1] == "usr" - and (len(new_v.parts) < 3 or new_v.parts[2] != "local") - and (_looks_like_red_hat_scheme() or _looks_like_debian_scheme()) - ) - if skip_linux_system_special_case: - continue - - # On Python 3.7 and earlier, sysconfig does not include sys.abiflags in - # the "pythonX.Y" part of the path, but distutils does. - skip_sysconfig_abiflag_bug = ( - sys.version_info < (3, 8) - and not WINDOWS - and k in ("headers", "platlib", "purelib") - and tuple(_fix_abiflags(old_v.parts)) == new_v.parts - ) - if skip_sysconfig_abiflag_bug: - continue - - # MSYS2 MINGW's sysconfig patch does not include the "site-packages" - # part of the path. This is incorrect and will be fixed in MSYS. - skip_msys2_mingw_bug = ( - WINDOWS and k in ("platlib", "purelib") and _looks_like_msys2_mingw_scheme() - ) - if skip_msys2_mingw_bug: - continue - - warning_contexts.append((old_v, new_v, f"scheme.{k}")) - - if not warning_contexts: - return old - - # Check if this path mismatch is caused by distutils config files. Those - # files will no longer work once we switch to sysconfig, so this raises a - # deprecation message for them. - default_old = _distutils.distutils_scheme( - dist_name, - user, - home, - root, - isolated, - prefix, - ignore_config_files=True, - ) - if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS): - deprecated( - "Configuring installation scheme with distutils config files " - "is deprecated and will no longer work in the near future. If you " - "are using a Homebrew or Linuxbrew Python, please see discussion " - "at https://github.com/Homebrew/homebrew-core/issues/76621", - replacement=None, - gone_in=None, - ) - return old - - # Post warnings about this mismatch so user can report them back. - for old_v, new_v, key in warning_contexts: - _warn_mismatched(old_v, new_v, key=key) - _log_context(user=user, home=home, root=root, prefix=prefix) - - return old - - -def get_bin_prefix() -> str: - old = _distutils.get_bin_prefix() - new = _sysconfig.get_bin_prefix() - if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="bin_prefix"): - _log_context() - return old - - -def get_bin_user() -> str: - return _sysconfig.get_scheme("", user=True).scripts - - -def _looks_like_deb_system_dist_packages(value: str) -> bool: - """Check if the value is Debian's APT-controlled dist-packages. - - Debian's ``distutils.sysconfig.get_python_lib()`` implementation returns the - default package path controlled by APT, but does not patch ``sysconfig`` to - do the same. This is similar to the bug worked around in ``get_scheme()``, - but here the default is ``deb_system`` instead of ``unix_local``. Ultimately - we can't do anything about this Debian bug, and this detection allows us to - skip the warning when needed. - """ - if not _looks_like_debian_scheme(): - return False - if value == "/usr/lib/python3/dist-packages": - return True - return False - - -def get_purelib() -> str: - """Return the default pure-Python lib location.""" - old = _distutils.get_purelib() - new = _sysconfig.get_purelib() - if _looks_like_deb_system_dist_packages(old): - return old - if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="purelib"): - _log_context() - return old - - -def get_platlib() -> str: - """Return the default platform-shared lib location.""" - old = _distutils.get_platlib() - new = _sysconfig.get_platlib() - if _looks_like_deb_system_dist_packages(old): - return old - if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="platlib"): - _log_context() - return old - - -def get_prefixed_libs(prefix: str) -> List[str]: - """Return the lib locations under ``prefix``.""" - old_pure, old_plat = _distutils.get_prefixed_libs(prefix) - new_pure, new_plat = _sysconfig.get_prefixed_libs(prefix) - - warned = [ - _warn_if_mismatch( - pathlib.Path(old_pure), - pathlib.Path(new_pure), - key="prefixed-purelib", - ), - _warn_if_mismatch( - pathlib.Path(old_plat), - pathlib.Path(new_plat), - key="prefixed-platlib", - ), - ] - if any(warned): - _log_context(prefix=prefix) - - if old_pure == old_plat: - return [old_pure] - return [old_pure, old_plat] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_distutils.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_distutils.py deleted file mode 100644 index 2ec79e6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_distutils.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Locations where we look for configs, install stuff, etc""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import os -import sys -from distutils.cmd import Command as DistutilsCommand -from distutils.command.install import SCHEME_KEYS -from distutils.command.install import install as distutils_install_command -from distutils.sysconfig import get_python_lib -from typing import Dict, List, Optional, Tuple, Union, cast - -from pip._internal.models.scheme import Scheme -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.virtualenv import running_under_virtualenv - -from .base import get_major_minor_version - -logger = logging.getLogger(__name__) - - -def distutils_scheme( - dist_name: str, - user: bool = False, - home: str = None, - root: str = None, - isolated: bool = False, - prefix: str = None, - *, - ignore_config_files: bool = False, -) -> Dict[str, str]: - """ - Return a distutils install scheme - """ - from distutils.dist import Distribution - - dist_args: Dict[str, Union[str, List[str]]] = {"name": dist_name} - if isolated: - dist_args["script_args"] = ["--no-user-cfg"] - - d = Distribution(dist_args) - if not ignore_config_files: - try: - d.parse_config_files() - except UnicodeDecodeError: - # Typeshed does not include find_config_files() for some reason. - paths = d.find_config_files() # type: ignore - logger.warning( - "Ignore distutils configs in %s due to encoding errors.", - ", ".join(os.path.basename(p) for p in paths), - ) - obj: Optional[DistutilsCommand] = None - obj = d.get_command_obj("install", create=True) - assert obj is not None - i = cast(distutils_install_command, obj) - # NOTE: setting user or home has the side-effect of creating the home dir - # or user base for installations during finalize_options() - # ideally, we'd prefer a scheme class that has no side-effects. - assert not (user and prefix), f"user={user} prefix={prefix}" - assert not (home and prefix), f"home={home} prefix={prefix}" - i.user = user or i.user - if user or home: - i.prefix = "" - i.prefix = prefix or i.prefix - i.home = home or i.home - i.root = root or i.root - i.finalize_options() - - scheme = {} - for key in SCHEME_KEYS: - scheme[key] = getattr(i, "install_" + key) - - # install_lib specified in setup.cfg should install *everything* - # into there (i.e. it takes precedence over both purelib and - # platlib). Note, i.install_lib is *always* set after - # finalize_options(); we only want to override here if the user - # has explicitly requested it hence going back to the config - if "install_lib" in d.get_option_dict("install"): - scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) - - if running_under_virtualenv(): - if home: - prefix = home - elif user: - prefix = i.install_userbase # type: ignore - else: - prefix = i.prefix - scheme["headers"] = os.path.join( - prefix, - "include", - "site", - f"python{get_major_minor_version()}", - dist_name, - ) - - if root is not None: - path_no_drive = os.path.splitdrive(os.path.abspath(scheme["headers"]))[1] - scheme["headers"] = os.path.join(root, path_no_drive[1:]) - - return scheme - - -def get_scheme( - dist_name: str, - user: bool = False, - home: Optional[str] = None, - root: Optional[str] = None, - isolated: bool = False, - prefix: Optional[str] = None, -) -> Scheme: - """ - Get the "scheme" corresponding to the input parameters. The distutils - documentation provides the context for the available schemes: - https://docs.python.org/3/install/index.html#alternate-installation - - :param dist_name: the name of the package to retrieve the scheme for, used - in the headers scheme path - :param user: indicates to use the "user" scheme - :param home: indicates to use the "home" scheme and provides the base - directory for the same - :param root: root under which other directories are re-based - :param isolated: equivalent to --no-user-cfg, i.e. do not consider - ~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for - scheme paths - :param prefix: indicates to use the "prefix" scheme and provides the - base directory for the same - """ - scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix) - return Scheme( - platlib=scheme["platlib"], - purelib=scheme["purelib"], - headers=scheme["headers"], - scripts=scheme["scripts"], - data=scheme["data"], - ) - - -def get_bin_prefix() -> str: - # XXX: In old virtualenv versions, sys.prefix can contain '..' components, - # so we need to call normpath to eliminate them. - prefix = os.path.normpath(sys.prefix) - if WINDOWS: - bin_py = os.path.join(prefix, "Scripts") - # buildout uses 'bin' on Windows too? - if not os.path.exists(bin_py): - bin_py = os.path.join(prefix, "bin") - return bin_py - # Forcing to use /usr/local/bin for standard macOS framework installs - # Also log to ~/Library/Logs/ for use with the Console.app log viewer - if sys.platform[:6] == "darwin" and prefix[:16] == "/System/Library/": - return "/usr/local/bin" - return os.path.join(prefix, "bin") - - -def get_purelib() -> str: - return get_python_lib(plat_specific=False) - - -def get_platlib() -> str: - return get_python_lib(plat_specific=True) - - -def get_prefixed_libs(prefix: str) -> Tuple[str, str]: - return ( - get_python_lib(plat_specific=False, prefix=prefix), - get_python_lib(plat_specific=True, prefix=prefix), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_sysconfig.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_sysconfig.py deleted file mode 100644 index 5e141aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/_sysconfig.py +++ /dev/null @@ -1,219 +0,0 @@ -import distutils.util # FIXME: For change_root. -import logging -import os -import sys -import sysconfig -import typing - -from pip._internal.exceptions import InvalidSchemeCombination, UserInstallationInvalid -from pip._internal.models.scheme import SCHEME_KEYS, Scheme -from pip._internal.utils.virtualenv import running_under_virtualenv - -from .base import get_major_minor_version, is_osx_framework - -logger = logging.getLogger(__name__) - - -# Notes on _infer_* functions. -# Unfortunately ``get_default_scheme()`` didn't exist before 3.10, so there's no -# way to ask things like "what is the '_prefix' scheme on this platform". These -# functions try to answer that with some heuristics while accounting for ad-hoc -# platforms not covered by CPython's default sysconfig implementation. If the -# ad-hoc implementation does not fully implement sysconfig, we'll fall back to -# a POSIX scheme. - -_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names()) - -_PREFERRED_SCHEME_API = getattr(sysconfig, "get_preferred_scheme", None) - - -def _should_use_osx_framework_prefix() -> bool: - """Check for Apple's ``osx_framework_library`` scheme. - - Python distributed by Apple's Command Line Tools has this special scheme - that's used when: - - * This is a framework build. - * We are installing into the system prefix. - - This does not account for ``pip install --prefix`` (also means we're not - installing to the system prefix), which should use ``posix_prefix``, but - logic here means ``_infer_prefix()`` outputs ``osx_framework_library``. But - since ``prefix`` is not available for ``sysconfig.get_default_scheme()``, - which is the stdlib replacement for ``_infer_prefix()``, presumably Apple - wouldn't be able to magically switch between ``osx_framework_library`` and - ``posix_prefix``. ``_infer_prefix()`` returning ``osx_framework_library`` - means its behavior is consistent whether we use the stdlib implementation - or our own, and we deal with this special case in ``get_scheme()`` instead. - """ - return ( - "osx_framework_library" in _AVAILABLE_SCHEMES - and not running_under_virtualenv() - and is_osx_framework() - ) - - -def _infer_prefix() -> str: - """Try to find a prefix scheme for the current platform. - - This tries: - - * A special ``osx_framework_library`` for Python distributed by Apple's - Command Line Tools, when not running in a virtual environment. - * Implementation + OS, used by PyPy on Windows (``pypy_nt``). - * Implementation without OS, used by PyPy on POSIX (``pypy``). - * OS + "prefix", used by CPython on POSIX (``posix_prefix``). - * Just the OS name, used by CPython on Windows (``nt``). - - If none of the above works, fall back to ``posix_prefix``. - """ - if _PREFERRED_SCHEME_API: - return _PREFERRED_SCHEME_API("prefix") - if _should_use_osx_framework_prefix(): - return "osx_framework_library" - implementation_suffixed = f"{sys.implementation.name}_{os.name}" - if implementation_suffixed in _AVAILABLE_SCHEMES: - return implementation_suffixed - if sys.implementation.name in _AVAILABLE_SCHEMES: - return sys.implementation.name - suffixed = f"{os.name}_prefix" - if suffixed in _AVAILABLE_SCHEMES: - return suffixed - if os.name in _AVAILABLE_SCHEMES: # On Windows, prefx is just called "nt". - return os.name - return "posix_prefix" - - -def _infer_user() -> str: - """Try to find a user scheme for the current platform.""" - if _PREFERRED_SCHEME_API: - return _PREFERRED_SCHEME_API("user") - if is_osx_framework() and not running_under_virtualenv(): - suffixed = "osx_framework_user" - else: - suffixed = f"{os.name}_user" - if suffixed in _AVAILABLE_SCHEMES: - return suffixed - if "posix_user" not in _AVAILABLE_SCHEMES: # User scheme unavailable. - raise UserInstallationInvalid() - return "posix_user" - - -def _infer_home() -> str: - """Try to find a home for the current platform.""" - if _PREFERRED_SCHEME_API: - return _PREFERRED_SCHEME_API("home") - suffixed = f"{os.name}_home" - if suffixed in _AVAILABLE_SCHEMES: - return suffixed - return "posix_home" - - -# Update these keys if the user sets a custom home. -_HOME_KEYS = [ - "installed_base", - "base", - "installed_platbase", - "platbase", - "prefix", - "exec_prefix", -] -if sysconfig.get_config_var("userbase") is not None: - _HOME_KEYS.append("userbase") - - -def get_scheme( - dist_name: str, - user: bool = False, - home: typing.Optional[str] = None, - root: typing.Optional[str] = None, - isolated: bool = False, - prefix: typing.Optional[str] = None, -) -> Scheme: - """ - Get the "scheme" corresponding to the input parameters. - - :param dist_name: the name of the package to retrieve the scheme for, used - in the headers scheme path - :param user: indicates to use the "user" scheme - :param home: indicates to use the "home" scheme - :param root: root under which other directories are re-based - :param isolated: ignored, but kept for distutils compatibility (where - this controls whether the user-site pydistutils.cfg is honored) - :param prefix: indicates to use the "prefix" scheme and provides the - base directory for the same - """ - if user and prefix: - raise InvalidSchemeCombination("--user", "--prefix") - if home and prefix: - raise InvalidSchemeCombination("--home", "--prefix") - - if home is not None: - scheme_name = _infer_home() - elif user: - scheme_name = _infer_user() - else: - scheme_name = _infer_prefix() - - # Special case: When installing into a custom prefix, use posix_prefix - # instead of osx_framework_library. See _should_use_osx_framework_prefix() - # docstring for details. - if prefix is not None and scheme_name == "osx_framework_library": - scheme_name = "posix_prefix" - - if home is not None: - variables = {k: home for k in _HOME_KEYS} - elif prefix is not None: - variables = {k: prefix for k in _HOME_KEYS} - else: - variables = {} - - paths = sysconfig.get_paths(scheme=scheme_name, vars=variables) - - # Logic here is very arbitrary, we're doing it for compatibility, don't ask. - # 1. Pip historically uses a special header path in virtual environments. - # 2. If the distribution name is not known, distutils uses 'UNKNOWN'. We - # only do the same when not running in a virtual environment because - # pip's historical header path logic (see point 1) did not do this. - if running_under_virtualenv(): - if user: - base = variables.get("userbase", sys.prefix) - else: - base = variables.get("base", sys.prefix) - python_xy = f"python{get_major_minor_version()}" - paths["include"] = os.path.join(base, "include", "site", python_xy) - elif not dist_name: - dist_name = "UNKNOWN" - - scheme = Scheme( - platlib=paths["platlib"], - purelib=paths["purelib"], - headers=os.path.join(paths["include"], dist_name), - scripts=paths["scripts"], - data=paths["data"], - ) - if root is not None: - for key in SCHEME_KEYS: - value = distutils.util.change_root(root, getattr(scheme, key)) - setattr(scheme, key, value) - return scheme - - -def get_bin_prefix() -> str: - # Forcing to use /usr/local/bin for standard macOS framework installs. - if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/": - return "/usr/local/bin" - return sysconfig.get_paths()["scripts"] - - -def get_purelib() -> str: - return sysconfig.get_paths()["purelib"] - - -def get_platlib() -> str: - return sysconfig.get_paths()["platlib"] - - -def get_prefixed_libs(prefix: str) -> typing.Tuple[str, str]: - paths = sysconfig.get_paths(vars={"base": prefix, "platbase": prefix}) - return (paths["purelib"], paths["platlib"]) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/base.py deleted file mode 100644 index 86dad4a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/locations/base.py +++ /dev/null @@ -1,52 +0,0 @@ -import functools -import os -import site -import sys -import sysconfig -import typing - -from pip._internal.utils import appdirs -from pip._internal.utils.virtualenv import running_under_virtualenv - -# Application Directories -USER_CACHE_DIR = appdirs.user_cache_dir("pip") - -# FIXME doesn't account for venv linked to global site-packages -site_packages: typing.Optional[str] = sysconfig.get_path("purelib") - - -def get_major_minor_version() -> str: - """ - Return the major-minor version of the current Python as a string, e.g. - "3.7" or "3.10". - """ - return "{}.{}".format(*sys.version_info) - - -def get_src_prefix() -> str: - if running_under_virtualenv(): - src_prefix = os.path.join(sys.prefix, "src") - else: - # FIXME: keep src in cwd for now (it is not a temporary folder) - try: - src_prefix = os.path.join(os.getcwd(), "src") - except OSError: - # In case the current working directory has been renamed or deleted - sys.exit("The folder you are executing pip from can no longer be found.") - - # under macOS + virtualenv sys.prefix is not properly resolved - # it is something like /path/to/python/bin/.. - return os.path.abspath(src_prefix) - - -try: - # Use getusersitepackages if this is present, as it ensures that the - # value is initialised properly. - user_site: typing.Optional[str] = site.getusersitepackages() -except AttributeError: - user_site = site.USER_SITE - - -@functools.lru_cache(maxsize=None) -def is_osx_framework() -> bool: - return bool(sysconfig.get_config_var("PYTHONFRAMEWORK")) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/main.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/main.py deleted file mode 100644 index 51eee15..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/main.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import List, Optional - - -def main(args=None): - # type: (Optional[List[str]]) -> int - """This is preserved for old console scripts that may still be referencing - it. - - For additional details, see https://github.com/pypa/pip/issues/7498. - """ - from pip._internal.utils.entrypoints import _wrapper - - return _wrapper(args) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/__init__.py deleted file mode 100644 index e3429d2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import List, Optional - -from .base import BaseDistribution, BaseEnvironment - -__all__ = [ - "BaseDistribution", - "BaseEnvironment", - "get_default_environment", - "get_environment", - "get_wheel_distribution", -] - - -def get_default_environment() -> BaseEnvironment: - """Get the default representation for the current environment. - - This returns an Environment instance from the chosen backend. The default - Environment instance should be built from ``sys.path`` and may use caching - to share instance state accorss calls. - """ - from .pkg_resources import Environment - - return Environment.default() - - -def get_environment(paths: Optional[List[str]]) -> BaseEnvironment: - """Get a representation of the environment specified by ``paths``. - - This returns an Environment instance from the chosen backend based on the - given import paths. The backend must build a fresh instance representing - the state of installed distributions when this function is called. - """ - from .pkg_resources import Environment - - return Environment.from_paths(paths) - - -def get_wheel_distribution(wheel_path: str, canonical_name: str) -> BaseDistribution: - """Get the representation of the specified wheel's distribution metadata. - - This returns a Distribution instance from the chosen backend based on - the given wheel's ``.dist-info`` directory. - - :param canonical_name: Normalized project name of the given wheel. - """ - from .pkg_resources import Distribution - - return Distribution.from_wheel(wheel_path, canonical_name) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/base.py deleted file mode 100644 index 9fdc123..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/base.py +++ /dev/null @@ -1,242 +0,0 @@ -import email.message -import json -import logging -import re -from typing import ( - TYPE_CHECKING, - Collection, - Container, - Iterable, - Iterator, - List, - Optional, - Union, -) - -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.version import LegacyVersion, Version - -from pip._internal.models.direct_url import ( - DIRECT_URL_METADATA_NAME, - DirectUrl, - DirectUrlValidationError, -) -from pip._internal.utils.misc import stdlib_pkgs # TODO: Move definition here. - -if TYPE_CHECKING: - from typing import Protocol - - from pip._vendor.packaging.utils import NormalizedName -else: - Protocol = object - -DistributionVersion = Union[LegacyVersion, Version] - -logger = logging.getLogger(__name__) - - -class BaseEntryPoint(Protocol): - @property - def name(self) -> str: - raise NotImplementedError() - - @property - def value(self) -> str: - raise NotImplementedError() - - @property - def group(self) -> str: - raise NotImplementedError() - - -class BaseDistribution(Protocol): - @property - def location(self) -> Optional[str]: - """Where the distribution is loaded from. - - A string value is not necessarily a filesystem path, since distributions - can be loaded from other sources, e.g. arbitrary zip archives. ``None`` - means the distribution is created in-memory. - - Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If - this is a symbolic link, we want to preserve the relative path between - it and files in the distribution. - """ - raise NotImplementedError() - - @property - def info_directory(self) -> Optional[str]: - """Location of the .[egg|dist]-info directory. - - Similarly to ``location``, a string value is not necessarily a - filesystem path. ``None`` means the distribution is created in-memory. - - For a modern .dist-info installation on disk, this should be something - like ``{location}/{raw_name}-{version}.dist-info``. - - Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If - this is a symbolic link, we want to preserve the relative path between - it and other files in the distribution. - """ - raise NotImplementedError() - - @property - def canonical_name(self) -> "NormalizedName": - raise NotImplementedError() - - @property - def version(self) -> DistributionVersion: - raise NotImplementedError() - - @property - def direct_url(self) -> Optional[DirectUrl]: - """Obtain a DirectUrl from this distribution. - - Returns None if the distribution has no `direct_url.json` metadata, - or if `direct_url.json` is invalid. - """ - try: - content = self.read_text(DIRECT_URL_METADATA_NAME) - except FileNotFoundError: - return None - try: - return DirectUrl.from_json(content) - except ( - UnicodeDecodeError, - json.JSONDecodeError, - DirectUrlValidationError, - ) as e: - logger.warning( - "Error parsing %s for %s: %s", - DIRECT_URL_METADATA_NAME, - self.canonical_name, - e, - ) - return None - - @property - def installer(self) -> str: - raise NotImplementedError() - - @property - def editable(self) -> bool: - raise NotImplementedError() - - @property - def local(self) -> bool: - raise NotImplementedError() - - @property - def in_usersite(self) -> bool: - raise NotImplementedError() - - @property - def in_site_packages(self) -> bool: - raise NotImplementedError() - - def read_text(self, name: str) -> str: - """Read a file in the .dist-info (or .egg-info) directory. - - Should raise ``FileNotFoundError`` if ``name`` does not exist in the - metadata directory. - """ - raise NotImplementedError() - - def iter_entry_points(self) -> Iterable[BaseEntryPoint]: - raise NotImplementedError() - - @property - def metadata(self) -> email.message.Message: - """Metadata of distribution parsed from e.g. METADATA or PKG-INFO.""" - raise NotImplementedError() - - @property - def metadata_version(self) -> Optional[str]: - """Value of "Metadata-Version:" in distribution metadata, if available.""" - return self.metadata.get("Metadata-Version") - - @property - def raw_name(self) -> str: - """Value of "Name:" in distribution metadata.""" - # The metadata should NEVER be missing the Name: key, but if it somehow - # does not, fall back to the known canonical name. - return self.metadata.get("Name", self.canonical_name) - - def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]: - raise NotImplementedError() - - -class BaseEnvironment: - """An environment containing distributions to introspect.""" - - @classmethod - def default(cls) -> "BaseEnvironment": - raise NotImplementedError() - - @classmethod - def from_paths(cls, paths: Optional[List[str]]) -> "BaseEnvironment": - raise NotImplementedError() - - def get_distribution(self, name: str) -> Optional["BaseDistribution"]: - """Given a requirement name, return the installed distributions.""" - raise NotImplementedError() - - def _iter_distributions(self) -> Iterator["BaseDistribution"]: - """Iterate through installed distributions. - - This function should be implemented by subclass, but never called - directly. Use the public ``iter_distribution()`` instead, which - implements additional logic to make sure the distributions are valid. - """ - raise NotImplementedError() - - def iter_distributions(self) -> Iterator["BaseDistribution"]: - """Iterate through installed distributions.""" - for dist in self._iter_distributions(): - # Make sure the distribution actually comes from a valid Python - # packaging distribution. Pip's AdjacentTempDirectory leaves folders - # e.g. ``~atplotlib.dist-info`` if cleanup was interrupted. The - # valid project name pattern is taken from PEP 508. - project_name_valid = re.match( - r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", - dist.canonical_name, - flags=re.IGNORECASE, - ) - if not project_name_valid: - logger.warning( - "Ignoring invalid distribution %s (%s)", - dist.canonical_name, - dist.location, - ) - continue - yield dist - - def iter_installed_distributions( - self, - local_only: bool = True, - skip: Container[str] = stdlib_pkgs, - include_editables: bool = True, - editables_only: bool = False, - user_only: bool = False, - ) -> Iterator[BaseDistribution]: - """Return a list of installed distributions. - - :param local_only: If True (default), only return installations - local to the current virtualenv, if in a virtualenv. - :param skip: An iterable of canonicalized project names to ignore; - defaults to ``stdlib_pkgs``. - :param include_editables: If False, don't report editables. - :param editables_only: If True, only report editables. - :param user_only: If True, only report installations in the user - site directory. - """ - it = self.iter_distributions() - if local_only: - it = (d for d in it if d.local) - if not include_editables: - it = (d for d in it if not d.editable) - if editables_only: - it = (d for d in it if d.editable) - if user_only: - it = (d for d in it if d.in_usersite) - return (d for d in it if d.canonical_name not in skip) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/pkg_resources.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/pkg_resources.py deleted file mode 100644 index 5946006..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/metadata/pkg_resources.py +++ /dev/null @@ -1,153 +0,0 @@ -import email.message -import logging -import zipfile -from typing import ( - TYPE_CHECKING, - Collection, - Iterable, - Iterator, - List, - NamedTuple, - Optional, -) - -from pip._vendor import pkg_resources -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.utils import misc # TODO: Move definition here. -from pip._internal.utils.packaging import get_installer, get_metadata -from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel - -from .base import BaseDistribution, BaseEntryPoint, BaseEnvironment, DistributionVersion - -if TYPE_CHECKING: - from pip._vendor.packaging.utils import NormalizedName - -logger = logging.getLogger(__name__) - - -class EntryPoint(NamedTuple): - name: str - value: str - group: str - - -class Distribution(BaseDistribution): - def __init__(self, dist: pkg_resources.Distribution) -> None: - self._dist = dist - - @classmethod - def from_wheel(cls, path: str, name: str) -> "Distribution": - with zipfile.ZipFile(path, allowZip64=True) as zf: - dist = pkg_resources_distribution_for_wheel(zf, name, path) - return cls(dist) - - @property - def location(self) -> Optional[str]: - return self._dist.location - - @property - def info_directory(self) -> Optional[str]: - return self._dist.egg_info - - @property - def canonical_name(self) -> "NormalizedName": - return canonicalize_name(self._dist.project_name) - - @property - def version(self) -> DistributionVersion: - return parse_version(self._dist.version) - - @property - def installer(self) -> str: - return get_installer(self._dist) - - @property - def editable(self) -> bool: - return misc.dist_is_editable(self._dist) - - @property - def local(self) -> bool: - return misc.dist_is_local(self._dist) - - @property - def in_usersite(self) -> bool: - return misc.dist_in_usersite(self._dist) - - @property - def in_site_packages(self) -> bool: - return misc.dist_in_site_packages(self._dist) - - def read_text(self, name: str) -> str: - if not self._dist.has_metadata(name): - raise FileNotFoundError(name) - return self._dist.get_metadata(name) - - def iter_entry_points(self) -> Iterable[BaseEntryPoint]: - for group, entries in self._dist.get_entry_map().items(): - for name, entry_point in entries.items(): - name, _, value = str(entry_point).partition("=") - yield EntryPoint(name=name.strip(), value=value.strip(), group=group) - - @property - def metadata(self) -> email.message.Message: - return get_metadata(self._dist) - - def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]: - if extras: # pkg_resources raises on invalid extras, so we sanitize. - extras = frozenset(extras).intersection(self._dist.extras) - return self._dist.requires(extras) - - -class Environment(BaseEnvironment): - def __init__(self, ws: pkg_resources.WorkingSet) -> None: - self._ws = ws - - @classmethod - def default(cls) -> BaseEnvironment: - return cls(pkg_resources.working_set) - - @classmethod - def from_paths(cls, paths: Optional[List[str]]) -> BaseEnvironment: - return cls(pkg_resources.WorkingSet(paths)) - - def _search_distribution(self, name: str) -> Optional[BaseDistribution]: - """Find a distribution matching the ``name`` in the environment. - - This searches from *all* distributions available in the environment, to - match the behavior of ``pkg_resources.get_distribution()``. - """ - canonical_name = canonicalize_name(name) - for dist in self.iter_distributions(): - if dist.canonical_name == canonical_name: - return dist - return None - - def get_distribution(self, name: str) -> Optional[BaseDistribution]: - - # Search the distribution by looking through the working set. - dist = self._search_distribution(name) - if dist: - return dist - - # If distribution could not be found, call working_set.require to - # update the working set, and try to find the distribution again. - # This might happen for e.g. when you install a package twice, once - # using setup.py develop and again using setup.py install. Now when - # running pip uninstall twice, the package gets removed from the - # working set in the first uninstall, so we have to populate the - # working set again so that pip knows about it and the packages gets - # picked up and is successfully uninstalled the second time too. - try: - # We didn't pass in any version specifiers, so this can never - # raise pkg_resources.VersionConflict. - self._ws.require(name) - except pkg_resources.DistributionNotFound: - return None - return self._search_distribution(name) - - def _iter_distributions(self) -> Iterator[BaseDistribution]: - for dist in self._ws: - yield Distribution(dist) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/__init__.py deleted file mode 100644 index 7855226..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""A package that contains models that represent entities. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/candidate.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/candidate.py deleted file mode 100644 index c673d8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/candidate.py +++ /dev/null @@ -1,31 +0,0 @@ -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.models.link import Link -from pip._internal.utils.models import KeyBasedCompareMixin - - -class InstallationCandidate(KeyBasedCompareMixin): - """Represents a potential "candidate" for installation. - """ - - __slots__ = ["name", "version", "link"] - - def __init__(self, name: str, version: str, link: Link) -> None: - self.name = name - self.version = parse_version(version) - self.link = link - - super().__init__( - key=(self.name, self.version, self.link), - defining_class=InstallationCandidate - ) - - def __repr__(self) -> str: - return "".format( - self.name, self.version, self.link, - ) - - def __str__(self) -> str: - return '{!r} candidate (version {} at {})'.format( - self.name, self.version, self.link, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/direct_url.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/direct_url.py deleted file mode 100644 index 3f9b699..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/direct_url.py +++ /dev/null @@ -1,220 +0,0 @@ -""" PEP 610 """ -import json -import re -import urllib.parse -from typing import Any, Dict, Iterable, Optional, Type, TypeVar, Union - -__all__ = [ - "DirectUrl", - "DirectUrlValidationError", - "DirInfo", - "ArchiveInfo", - "VcsInfo", -] - -T = TypeVar("T") - -DIRECT_URL_METADATA_NAME = "direct_url.json" -ENV_VAR_RE = re.compile(r"^\$\{[A-Za-z0-9-_]+\}(:\$\{[A-Za-z0-9-_]+\})?$") - - -class DirectUrlValidationError(Exception): - pass - - -def _get( - d: Dict[str, Any], expected_type: Type[T], key: str, default: Optional[T] = None -) -> Optional[T]: - """Get value from dictionary and verify expected type.""" - if key not in d: - return default - value = d[key] - if not isinstance(value, expected_type): - raise DirectUrlValidationError( - "{!r} has unexpected type for {} (expected {})".format( - value, key, expected_type - ) - ) - return value - - -def _get_required( - d: Dict[str, Any], expected_type: Type[T], key: str, default: Optional[T] = None -) -> T: - value = _get(d, expected_type, key, default) - if value is None: - raise DirectUrlValidationError(f"{key} must have a value") - return value - - -def _exactly_one_of(infos: Iterable[Optional["InfoType"]]) -> "InfoType": - infos = [info for info in infos if info is not None] - if not infos: - raise DirectUrlValidationError( - "missing one of archive_info, dir_info, vcs_info" - ) - if len(infos) > 1: - raise DirectUrlValidationError( - "more than one of archive_info, dir_info, vcs_info" - ) - assert infos[0] is not None - return infos[0] - - -def _filter_none(**kwargs: Any) -> Dict[str, Any]: - """Make dict excluding None values.""" - return {k: v for k, v in kwargs.items() if v is not None} - - -class VcsInfo: - name = "vcs_info" - - def __init__( - self, - vcs: str, - commit_id: str, - requested_revision: Optional[str] = None, - resolved_revision: Optional[str] = None, - resolved_revision_type: Optional[str] = None, - ) -> None: - self.vcs = vcs - self.requested_revision = requested_revision - self.commit_id = commit_id - self.resolved_revision = resolved_revision - self.resolved_revision_type = resolved_revision_type - - @classmethod - def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["VcsInfo"]: - if d is None: - return None - return cls( - vcs=_get_required(d, str, "vcs"), - commit_id=_get_required(d, str, "commit_id"), - requested_revision=_get(d, str, "requested_revision"), - resolved_revision=_get(d, str, "resolved_revision"), - resolved_revision_type=_get(d, str, "resolved_revision_type"), - ) - - def _to_dict(self) -> Dict[str, Any]: - return _filter_none( - vcs=self.vcs, - requested_revision=self.requested_revision, - commit_id=self.commit_id, - resolved_revision=self.resolved_revision, - resolved_revision_type=self.resolved_revision_type, - ) - - -class ArchiveInfo: - name = "archive_info" - - def __init__( - self, - hash: Optional[str] = None, - ) -> None: - self.hash = hash - - @classmethod - def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["ArchiveInfo"]: - if d is None: - return None - return cls(hash=_get(d, str, "hash")) - - def _to_dict(self) -> Dict[str, Any]: - return _filter_none(hash=self.hash) - - -class DirInfo: - name = "dir_info" - - def __init__( - self, - editable: bool = False, - ) -> None: - self.editable = editable - - @classmethod - def _from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional["DirInfo"]: - if d is None: - return None - return cls( - editable=_get_required(d, bool, "editable", default=False) - ) - - def _to_dict(self) -> Dict[str, Any]: - return _filter_none(editable=self.editable or None) - - -InfoType = Union[ArchiveInfo, DirInfo, VcsInfo] - - -class DirectUrl: - - def __init__( - self, - url: str, - info: InfoType, - subdirectory: Optional[str] = None, - ) -> None: - self.url = url - self.info = info - self.subdirectory = subdirectory - - def _remove_auth_from_netloc(self, netloc: str) -> str: - if "@" not in netloc: - return netloc - user_pass, netloc_no_user_pass = netloc.split("@", 1) - if ( - isinstance(self.info, VcsInfo) and - self.info.vcs == "git" and - user_pass == "git" - ): - return netloc - if ENV_VAR_RE.match(user_pass): - return netloc - return netloc_no_user_pass - - @property - def redacted_url(self) -> str: - """url with user:password part removed unless it is formed with - environment variables as specified in PEP 610, or it is ``git`` - in the case of a git URL. - """ - purl = urllib.parse.urlsplit(self.url) - netloc = self._remove_auth_from_netloc(purl.netloc) - surl = urllib.parse.urlunsplit( - (purl.scheme, netloc, purl.path, purl.query, purl.fragment) - ) - return surl - - def validate(self) -> None: - self.from_dict(self.to_dict()) - - @classmethod - def from_dict(cls, d: Dict[str, Any]) -> "DirectUrl": - return DirectUrl( - url=_get_required(d, str, "url"), - subdirectory=_get(d, str, "subdirectory"), - info=_exactly_one_of( - [ - ArchiveInfo._from_dict(_get(d, dict, "archive_info")), - DirInfo._from_dict(_get(d, dict, "dir_info")), - VcsInfo._from_dict(_get(d, dict, "vcs_info")), - ] - ), - ) - - def to_dict(self) -> Dict[str, Any]: - res = _filter_none( - url=self.redacted_url, - subdirectory=self.subdirectory, - ) - res[self.info.name] = self.info._to_dict() - return res - - @classmethod - def from_json(cls, s: str) -> "DirectUrl": - return cls.from_dict(json.loads(s)) - - def to_json(self) -> str: - return json.dumps(self.to_dict(), sort_keys=True) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/format_control.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/format_control.py deleted file mode 100644 index 010c362..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/format_control.py +++ /dev/null @@ -1,84 +0,0 @@ -from typing import FrozenSet, Optional, Set - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import CommandError - - -class FormatControl: - """Helper for managing formats from which a package can be installed. - """ - - __slots__ = ["no_binary", "only_binary"] - - def __init__( - self, - no_binary: Optional[Set[str]] = None, - only_binary: Optional[Set[str]] = None - ) -> None: - if no_binary is None: - no_binary = set() - if only_binary is None: - only_binary = set() - - self.no_binary = no_binary - self.only_binary = only_binary - - def __eq__(self, other: object) -> bool: - if not isinstance(other, self.__class__): - return NotImplemented - - if self.__slots__ != other.__slots__: - return False - - return all( - getattr(self, k) == getattr(other, k) - for k in self.__slots__ - ) - - def __repr__(self) -> str: - return "{}({}, {})".format( - self.__class__.__name__, - self.no_binary, - self.only_binary - ) - - @staticmethod - def handle_mutual_excludes(value: str, target: Set[str], other: Set[str]) -> None: - if value.startswith('-'): - raise CommandError( - "--no-binary / --only-binary option requires 1 argument." - ) - new = value.split(',') - while ':all:' in new: - other.clear() - target.clear() - target.add(':all:') - del new[:new.index(':all:') + 1] - # Without a none, we want to discard everything as :all: covers it - if ':none:' not in new: - return - for name in new: - if name == ':none:': - target.clear() - continue - name = canonicalize_name(name) - other.discard(name) - target.add(name) - - def get_allowed_formats(self, canonical_name: str) -> FrozenSet[str]: - result = {"binary", "source"} - if canonical_name in self.only_binary: - result.discard('source') - elif canonical_name in self.no_binary: - result.discard('binary') - elif ':all:' in self.only_binary: - result.discard('source') - elif ':all:' in self.no_binary: - result.discard('binary') - return frozenset(result) - - def disallow_binaries(self) -> None: - self.handle_mutual_excludes( - ':all:', self.no_binary, self.only_binary, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/index.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/index.py deleted file mode 100644 index 1874a5b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/index.py +++ /dev/null @@ -1,32 +0,0 @@ -import urllib.parse - - -class PackageIndex: - """Represents a Package Index and provides easier access to endpoints - """ - - __slots__ = ['url', 'netloc', 'simple_url', 'pypi_url', - 'file_storage_domain'] - - def __init__(self, url: str, file_storage_domain: str) -> None: - super().__init__() - self.url = url - self.netloc = urllib.parse.urlsplit(url).netloc - self.simple_url = self._url_for_path('simple') - self.pypi_url = self._url_for_path('pypi') - - # This is part of a temporary hack used to block installs of PyPI - # packages which depend on external urls only necessary until PyPI can - # block such packages themselves - self.file_storage_domain = file_storage_domain - - def _url_for_path(self, path: str) -> str: - return urllib.parse.urljoin(self.url, path) - - -PyPI = PackageIndex( - 'https://pypi.org/', file_storage_domain='files.pythonhosted.org' -) -TestPyPI = PackageIndex( - 'https://test.pypi.org/', file_storage_domain='test-files.pythonhosted.org' -) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/link.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/link.py deleted file mode 100644 index 9ef1ca3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/link.py +++ /dev/null @@ -1,288 +0,0 @@ -import functools -import logging -import os -import posixpath -import re -import urllib.parse -from typing import TYPE_CHECKING, Dict, List, NamedTuple, Optional, Tuple, Union - -from pip._internal.utils.filetypes import WHEEL_EXTENSION -from pip._internal.utils.hashes import Hashes -from pip._internal.utils.misc import ( - redact_auth_from_url, - split_auth_from_netloc, - splitext, -) -from pip._internal.utils.models import KeyBasedCompareMixin -from pip._internal.utils.urls import path_to_url, url_to_path - -if TYPE_CHECKING: - from pip._internal.index.collector import HTMLPage - -logger = logging.getLogger(__name__) - - -_SUPPORTED_HASHES = ("sha1", "sha224", "sha384", "sha256", "sha512", "md5") - - -class Link(KeyBasedCompareMixin): - """Represents a parsed link from a Package Index's simple URL - """ - - __slots__ = [ - "_parsed_url", - "_url", - "comes_from", - "requires_python", - "yanked_reason", - "cache_link_parsing", - ] - - def __init__( - self, - url: str, - comes_from: Optional[Union[str, "HTMLPage"]] = None, - requires_python: Optional[str] = None, - yanked_reason: Optional[str] = None, - cache_link_parsing: bool = True, - ) -> None: - """ - :param url: url of the resource pointed to (href of the link) - :param comes_from: instance of HTMLPage where the link was found, - or string. - :param requires_python: String containing the `Requires-Python` - metadata field, specified in PEP 345. This may be specified by - a data-requires-python attribute in the HTML link tag, as - described in PEP 503. - :param yanked_reason: the reason the file has been yanked, if the - file has been yanked, or None if the file hasn't been yanked. - This is the value of the "data-yanked" attribute, if present, in - a simple repository HTML link. If the file has been yanked but - no reason was provided, this should be the empty string. See - PEP 592 for more information and the specification. - :param cache_link_parsing: A flag that is used elsewhere to determine - whether resources retrieved from this link - should be cached. PyPI index urls should - generally have this set to False, for - example. - """ - - # url can be a UNC windows share - if url.startswith('\\\\'): - url = path_to_url(url) - - self._parsed_url = urllib.parse.urlsplit(url) - # Store the url as a private attribute to prevent accidentally - # trying to set a new value. - self._url = url - - self.comes_from = comes_from - self.requires_python = requires_python if requires_python else None - self.yanked_reason = yanked_reason - - super().__init__(key=url, defining_class=Link) - - self.cache_link_parsing = cache_link_parsing - - def __str__(self) -> str: - if self.requires_python: - rp = f' (requires-python:{self.requires_python})' - else: - rp = '' - if self.comes_from: - return '{} (from {}){}'.format( - redact_auth_from_url(self._url), self.comes_from, rp) - else: - return redact_auth_from_url(str(self._url)) - - def __repr__(self) -> str: - return f'' - - @property - def url(self) -> str: - return self._url - - @property - def filename(self) -> str: - path = self.path.rstrip('/') - name = posixpath.basename(path) - if not name: - # Make sure we don't leak auth information if the netloc - # includes a username and password. - netloc, user_pass = split_auth_from_netloc(self.netloc) - return netloc - - name = urllib.parse.unquote(name) - assert name, f'URL {self._url!r} produced no filename' - return name - - @property - def file_path(self) -> str: - return url_to_path(self.url) - - @property - def scheme(self) -> str: - return self._parsed_url.scheme - - @property - def netloc(self) -> str: - """ - This can contain auth information. - """ - return self._parsed_url.netloc - - @property - def path(self) -> str: - return urllib.parse.unquote(self._parsed_url.path) - - def splitext(self) -> Tuple[str, str]: - return splitext(posixpath.basename(self.path.rstrip('/'))) - - @property - def ext(self) -> str: - return self.splitext()[1] - - @property - def url_without_fragment(self) -> str: - scheme, netloc, path, query, fragment = self._parsed_url - return urllib.parse.urlunsplit((scheme, netloc, path, query, '')) - - _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') - - @property - def egg_fragment(self) -> Optional[str]: - match = self._egg_fragment_re.search(self._url) - if not match: - return None - return match.group(1) - - _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') - - @property - def subdirectory_fragment(self) -> Optional[str]: - match = self._subdirectory_fragment_re.search(self._url) - if not match: - return None - return match.group(1) - - _hash_re = re.compile( - r'({choices})=([a-f0-9]+)'.format(choices="|".join(_SUPPORTED_HASHES)) - ) - - @property - def hash(self) -> Optional[str]: - match = self._hash_re.search(self._url) - if match: - return match.group(2) - return None - - @property - def hash_name(self) -> Optional[str]: - match = self._hash_re.search(self._url) - if match: - return match.group(1) - return None - - @property - def show_url(self) -> str: - return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) - - @property - def is_file(self) -> bool: - return self.scheme == 'file' - - def is_existing_dir(self) -> bool: - return self.is_file and os.path.isdir(self.file_path) - - @property - def is_wheel(self) -> bool: - return self.ext == WHEEL_EXTENSION - - @property - def is_vcs(self) -> bool: - from pip._internal.vcs import vcs - - return self.scheme in vcs.all_schemes - - @property - def is_yanked(self) -> bool: - return self.yanked_reason is not None - - @property - def has_hash(self) -> bool: - return self.hash_name is not None - - def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool: - """ - Return True if the link has a hash and it is allowed. - """ - if hashes is None or not self.has_hash: - return False - # Assert non-None so mypy knows self.hash_name and self.hash are str. - assert self.hash_name is not None - assert self.hash is not None - - return hashes.is_hash_allowed(self.hash_name, hex_digest=self.hash) - - -class _CleanResult(NamedTuple): - """Convert link for equivalency check. - - This is used in the resolver to check whether two URL-specified requirements - likely point to the same distribution and can be considered equivalent. This - equivalency logic avoids comparing URLs literally, which can be too strict - (e.g. "a=1&b=2" vs "b=2&a=1") and produce conflicts unexpecting to users. - - Currently this does three things: - - 1. Drop the basic auth part. This is technically wrong since a server can - serve different content based on auth, but if it does that, it is even - impossible to guarantee two URLs without auth are equivalent, since - the user can input different auth information when prompted. So the - practical solution is to assume the auth doesn't affect the response. - 2. Parse the query to avoid the ordering issue. Note that ordering under the - same key in the query are NOT cleaned; i.e. "a=1&a=2" and "a=2&a=1" are - still considered different. - 3. Explicitly drop most of the fragment part, except ``subdirectory=`` and - hash values, since it should have no impact the downloaded content. Note - that this drops the "egg=" part historically used to denote the requested - project (and extras), which is wrong in the strictest sense, but too many - people are supplying it inconsistently to cause superfluous resolution - conflicts, so we choose to also ignore them. - """ - - parsed: urllib.parse.SplitResult - query: Dict[str, List[str]] - subdirectory: str - hashes: Dict[str, str] - - -def _clean_link(link: Link) -> _CleanResult: - parsed = link._parsed_url - netloc = parsed.netloc.rsplit("@", 1)[-1] - # According to RFC 8089, an empty host in file: means localhost. - if parsed.scheme == "file" and not netloc: - netloc = "localhost" - fragment = urllib.parse.parse_qs(parsed.fragment) - if "egg" in fragment: - logger.debug("Ignoring egg= fragment in %s", link) - try: - # If there are multiple subdirectory values, use the first one. - # This matches the behavior of Link.subdirectory_fragment. - subdirectory = fragment["subdirectory"][0] - except (IndexError, KeyError): - subdirectory = "" - # If there are multiple hash values under the same algorithm, use the - # first one. This matches the behavior of Link.hash_value. - hashes = {k: fragment[k][0] for k in _SUPPORTED_HASHES if k in fragment} - return _CleanResult( - parsed=parsed._replace(netloc=netloc, query="", fragment=""), - query=urllib.parse.parse_qs(parsed.query), - subdirectory=subdirectory, - hashes=hashes, - ) - - -@functools.lru_cache(maxsize=None) -def links_equivalent(link1: Link, link2: Link) -> bool: - return _clean_link(link1) == _clean_link(link2) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/scheme.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/scheme.py deleted file mode 100644 index 9a8dafb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/scheme.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -For types associated with installation schemes. - -For a general overview of available schemes and their context, see -https://docs.python.org/3/install/index.html#alternate-installation. -""" - - -SCHEME_KEYS = ['platlib', 'purelib', 'headers', 'scripts', 'data'] - - -class Scheme: - """A Scheme holds paths which are used as the base directories for - artifacts associated with a Python package. - """ - - __slots__ = SCHEME_KEYS - - def __init__( - self, - platlib: str, - purelib: str, - headers: str, - scripts: str, - data: str, - ) -> None: - self.platlib = platlib - self.purelib = purelib - self.headers = headers - self.scripts = scripts - self.data = data diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/search_scope.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/search_scope.py deleted file mode 100644 index 24ec983..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/search_scope.py +++ /dev/null @@ -1,126 +0,0 @@ -import itertools -import logging -import os -import posixpath -import urllib.parse -from typing import List - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.models.index import PyPI -from pip._internal.utils.compat import has_tls -from pip._internal.utils.misc import normalize_path, redact_auth_from_url - -logger = logging.getLogger(__name__) - - -class SearchScope: - - """ - Encapsulates the locations that pip is configured to search. - """ - - __slots__ = ["find_links", "index_urls"] - - @classmethod - def create( - cls, - find_links: List[str], - index_urls: List[str], - ) -> "SearchScope": - """ - Create a SearchScope object after normalizing the `find_links`. - """ - # Build find_links. If an argument starts with ~, it may be - # a local file relative to a home directory. So try normalizing - # it and if it exists, use the normalized version. - # This is deliberately conservative - it might be fine just to - # blindly normalize anything starting with a ~... - built_find_links: List[str] = [] - for link in find_links: - if link.startswith('~'): - new_link = normalize_path(link) - if os.path.exists(new_link): - link = new_link - built_find_links.append(link) - - # If we don't have TLS enabled, then WARN if anyplace we're looking - # relies on TLS. - if not has_tls(): - for link in itertools.chain(index_urls, built_find_links): - parsed = urllib.parse.urlparse(link) - if parsed.scheme == 'https': - logger.warning( - 'pip is configured with locations that require ' - 'TLS/SSL, however the ssl module in Python is not ' - 'available.' - ) - break - - return cls( - find_links=built_find_links, - index_urls=index_urls, - ) - - def __init__( - self, - find_links: List[str], - index_urls: List[str], - ) -> None: - self.find_links = find_links - self.index_urls = index_urls - - def get_formatted_locations(self) -> str: - lines = [] - redacted_index_urls = [] - if self.index_urls and self.index_urls != [PyPI.simple_url]: - for url in self.index_urls: - - redacted_index_url = redact_auth_from_url(url) - - # Parse the URL - purl = urllib.parse.urlsplit(redacted_index_url) - - # URL is generally invalid if scheme and netloc is missing - # there are issues with Python and URL parsing, so this test - # is a bit crude. See bpo-20271, bpo-23505. Python doesn't - # always parse invalid URLs correctly - it should raise - # exceptions for malformed URLs - if not purl.scheme and not purl.netloc: - logger.warning( - 'The index url "%s" seems invalid, ' - 'please provide a scheme.', redacted_index_url) - - redacted_index_urls.append(redacted_index_url) - - lines.append('Looking in indexes: {}'.format( - ', '.join(redacted_index_urls))) - - if self.find_links: - lines.append( - 'Looking in links: {}'.format(', '.join( - redact_auth_from_url(url) for url in self.find_links)) - ) - return '\n'.join(lines) - - def get_index_urls_locations(self, project_name: str) -> List[str]: - """Returns the locations found via self.index_urls - - Checks the url_name on the main (first in the list) index and - use this url_name to produce all locations - """ - - def mkurl_pypi_url(url: str) -> str: - loc = posixpath.join( - url, - urllib.parse.quote(canonicalize_name(project_name))) - # For maximum compatibility with easy_install, ensure the path - # ends in a trailing slash. Although this isn't in the spec - # (and PyPI can handle it without the slash) some other index - # implementations might break if they relied on easy_install's - # behavior. - if not loc.endswith('/'): - loc = loc + '/' - return loc - - return [mkurl_pypi_url(url) for url in self.index_urls] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/selection_prefs.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/selection_prefs.py deleted file mode 100644 index 66a5636..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/selection_prefs.py +++ /dev/null @@ -1,46 +0,0 @@ -from typing import Optional - -from pip._internal.models.format_control import FormatControl - - -class SelectionPreferences: - """ - Encapsulates the candidate selection preferences for downloading - and installing files. - """ - - __slots__ = ['allow_yanked', 'allow_all_prereleases', 'format_control', - 'prefer_binary', 'ignore_requires_python'] - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - def __init__( - self, - allow_yanked: bool, - allow_all_prereleases: bool = False, - format_control: Optional[FormatControl] = None, - prefer_binary: bool = False, - ignore_requires_python: Optional[bool] = None, - ) -> None: - """Create a SelectionPreferences object. - - :param allow_yanked: Whether files marked as yanked (in the sense - of PEP 592) are permitted to be candidates for install. - :param format_control: A FormatControl object or None. Used to control - the selection of source packages / binary packages when consulting - the index and links. - :param prefer_binary: Whether to prefer an old, but valid, binary - dist over a new source dist. - :param ignore_requires_python: Whether to ignore incompatible - "Requires-Python" values in links. Defaults to False. - """ - if ignore_requires_python is None: - ignore_requires_python = False - - self.allow_yanked = allow_yanked - self.allow_all_prereleases = allow_all_prereleases - self.format_control = format_control - self.prefer_binary = prefer_binary - self.ignore_requires_python = ignore_requires_python diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/target_python.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/target_python.py deleted file mode 100644 index 11b2591..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/target_python.py +++ /dev/null @@ -1,111 +0,0 @@ -import sys -from typing import List, Optional, Tuple - -from pip._vendor.packaging.tags import Tag - -from pip._internal.utils.compatibility_tags import get_supported, version_info_to_nodot -from pip._internal.utils.misc import normalize_version_info - - -class TargetPython: - - """ - Encapsulates the properties of a Python interpreter one is targeting - for a package install, download, etc. - """ - - __slots__ = [ - "_given_py_version_info", - "abis", - "implementation", - "platforms", - "py_version", - "py_version_info", - "_valid_tags", - ] - - def __init__( - self, - platforms: Optional[List[str]] = None, - py_version_info: Optional[Tuple[int, ...]] = None, - abis: Optional[List[str]] = None, - implementation: Optional[str] = None, - ) -> None: - """ - :param platforms: A list of strings or None. If None, searches for - packages that are supported by the current system. Otherwise, will - find packages that can be built on the platforms passed in. These - packages will only be downloaded for distribution: they will - not be built locally. - :param py_version_info: An optional tuple of ints representing the - Python version information to use (e.g. `sys.version_info[:3]`). - This can have length 1, 2, or 3 when provided. - :param abis: A list of strings or None. This is passed to - compatibility_tags.py's get_supported() function as is. - :param implementation: A string or None. This is passed to - compatibility_tags.py's get_supported() function as is. - """ - # Store the given py_version_info for when we call get_supported(). - self._given_py_version_info = py_version_info - - if py_version_info is None: - py_version_info = sys.version_info[:3] - else: - py_version_info = normalize_version_info(py_version_info) - - py_version = '.'.join(map(str, py_version_info[:2])) - - self.abis = abis - self.implementation = implementation - self.platforms = platforms - self.py_version = py_version - self.py_version_info = py_version_info - - # This is used to cache the return value of get_tags(). - self._valid_tags: Optional[List[Tag]] = None - - def format_given(self) -> str: - """ - Format the given, non-None attributes for display. - """ - display_version = None - if self._given_py_version_info is not None: - display_version = '.'.join( - str(part) for part in self._given_py_version_info - ) - - key_values = [ - ('platforms', self.platforms), - ('version_info', display_version), - ('abis', self.abis), - ('implementation', self.implementation), - ] - return ' '.join( - f'{key}={value!r}' for key, value in key_values - if value is not None - ) - - def get_tags(self) -> List[Tag]: - """ - Return the supported PEP 425 tags to check wheel candidates against. - - The tags are returned in order of preference (most preferred first). - """ - if self._valid_tags is None: - # Pass versions=None if no py_version_info was given since - # versions=None uses special default logic. - py_version_info = self._given_py_version_info - if py_version_info is None: - version = None - else: - version = version_info_to_nodot(py_version_info) - - tags = get_supported( - version=version, - platforms=self.platforms, - abis=self.abis, - impl=self.implementation, - ) - self._valid_tags = tags - - return self._valid_tags diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/wheel.py deleted file mode 100644 index a79a861..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/models/wheel.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Represents a wheel file and provides access to the various parts of the -name that have meaning. -""" -import re -from typing import Dict, Iterable, List - -from pip._vendor.packaging.tags import Tag - -from pip._internal.exceptions import InvalidWheelFilename - - -class Wheel: - """A wheel file""" - - wheel_file_re = re.compile( - r"""^(?P(?P.+?)-(?P.*?)) - ((-(?P\d[^-]*?))?-(?P.+?)-(?P.+?)-(?P.+?) - \.whl|\.dist-info)$""", - re.VERBOSE - ) - - def __init__(self, filename: str) -> None: - """ - :raises InvalidWheelFilename: when the filename is invalid for a wheel - """ - wheel_info = self.wheel_file_re.match(filename) - if not wheel_info: - raise InvalidWheelFilename( - f"{filename} is not a valid wheel filename." - ) - self.filename = filename - self.name = wheel_info.group('name').replace('_', '-') - # we'll assume "_" means "-" due to wheel naming scheme - # (https://github.com/pypa/pip/issues/1150) - self.version = wheel_info.group('ver').replace('_', '-') - self.build_tag = wheel_info.group('build') - self.pyversions = wheel_info.group('pyver').split('.') - self.abis = wheel_info.group('abi').split('.') - self.plats = wheel_info.group('plat').split('.') - - # All the tag combinations from this file - self.file_tags = { - Tag(x, y, z) for x in self.pyversions - for y in self.abis for z in self.plats - } - - def get_formatted_file_tags(self) -> List[str]: - """Return the wheel's tags as a sorted list of strings.""" - return sorted(str(tag) for tag in self.file_tags) - - def support_index_min(self, tags: List[Tag]) -> int: - """Return the lowest index that one of the wheel's file_tag combinations - achieves in the given list of supported tags. - - For example, if there are 8 supported tags and one of the file tags - is first in the list, then return 0. - - :param tags: the PEP 425 tags to check the wheel against, in order - with most preferred first. - - :raises ValueError: If none of the wheel's file tags match one of - the supported tags. - """ - return min(tags.index(tag) for tag in self.file_tags if tag in tags) - - def find_most_preferred_tag( - self, tags: List[Tag], tag_to_priority: Dict[Tag, int] - ) -> int: - """Return the priority of the most preferred tag that one of the wheel's file - tag combinations achieves in the given list of supported tags using the given - tag_to_priority mapping, where lower priorities are more-preferred. - - This is used in place of support_index_min in some cases in order to avoid - an expensive linear scan of a large list of tags. - - :param tags: the PEP 425 tags to check the wheel against. - :param tag_to_priority: a mapping from tag to priority of that tag, where - lower is more preferred. - - :raises ValueError: If none of the wheel's file tags match one of - the supported tags. - """ - return min( - tag_to_priority[tag] for tag in self.file_tags if tag in tag_to_priority - ) - - def supported(self, tags: Iterable[Tag]) -> bool: - """Return whether the wheel is compatible with one of the given tags. - - :param tags: the PEP 425 tags to check the wheel against. - """ - return not self.file_tags.isdisjoint(tags) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/__init__.py deleted file mode 100644 index b51bde9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Contains purely network-related utilities. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/auth.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/auth.py deleted file mode 100644 index 74d2254..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/auth.py +++ /dev/null @@ -1,316 +0,0 @@ -"""Network Authentication Helpers - -Contains interface (MultiDomainBasicAuth) and associated glue code for -providing credentials in the context of network requests. -""" - -import urllib.parse -from typing import Any, Dict, List, Optional, Tuple - -from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth -from pip._vendor.requests.models import Request, Response -from pip._vendor.requests.utils import get_netrc_auth - -from pip._internal.utils.logging import getLogger -from pip._internal.utils.misc import ( - ask, - ask_input, - ask_password, - remove_auth_from_url, - split_auth_netloc_from_url, -) -from pip._internal.vcs.versioncontrol import AuthInfo - -logger = getLogger(__name__) - -Credentials = Tuple[str, str, str] - -try: - import keyring -except ImportError: - keyring = None -except Exception as exc: - logger.warning( - "Keyring is skipped due to an exception: %s", - str(exc), - ) - keyring = None - - -def get_keyring_auth(url: Optional[str], username: Optional[str]) -> Optional[AuthInfo]: - """Return the tuple auth for a given url from keyring.""" - global keyring - if not url or not keyring: - return None - - try: - try: - get_credential = keyring.get_credential - except AttributeError: - pass - else: - logger.debug("Getting credentials from keyring for %s", url) - cred = get_credential(url, username) - if cred is not None: - return cred.username, cred.password - return None - - if username: - logger.debug("Getting password from keyring for %s", url) - password = keyring.get_password(url, username) - if password: - return username, password - - except Exception as exc: - logger.warning( - "Keyring is skipped due to an exception: %s", - str(exc), - ) - keyring = None - return None - - -class MultiDomainBasicAuth(AuthBase): - def __init__( - self, prompting: bool = True, index_urls: Optional[List[str]] = None - ) -> None: - self.prompting = prompting - self.index_urls = index_urls - self.passwords: Dict[str, AuthInfo] = {} - # When the user is prompted to enter credentials and keyring is - # available, we will offer to save them. If the user accepts, - # this value is set to the credentials they entered. After the - # request authenticates, the caller should call - # ``save_credentials`` to save these. - self._credentials_to_save: Optional[Credentials] = None - - def _get_index_url(self, url: str) -> Optional[str]: - """Return the original index URL matching the requested URL. - - Cached or dynamically generated credentials may work against - the original index URL rather than just the netloc. - - The provided url should have had its username and password - removed already. If the original index url had credentials then - they will be included in the return value. - - Returns None if no matching index was found, or if --no-index - was specified by the user. - """ - if not url or not self.index_urls: - return None - - for u in self.index_urls: - prefix = remove_auth_from_url(u).rstrip("/") + "/" - if url.startswith(prefix): - return u - return None - - def _get_new_credentials( - self, - original_url: str, - allow_netrc: bool = True, - allow_keyring: bool = False, - ) -> AuthInfo: - """Find and return credentials for the specified URL.""" - # Split the credentials and netloc from the url. - url, netloc, url_user_password = split_auth_netloc_from_url( - original_url, - ) - - # Start with the credentials embedded in the url - username, password = url_user_password - if username is not None and password is not None: - logger.debug("Found credentials in url for %s", netloc) - return url_user_password - - # Find a matching index url for this request - index_url = self._get_index_url(url) - if index_url: - # Split the credentials from the url. - index_info = split_auth_netloc_from_url(index_url) - if index_info: - index_url, _, index_url_user_password = index_info - logger.debug("Found index url %s", index_url) - - # If an index URL was found, try its embedded credentials - if index_url and index_url_user_password[0] is not None: - username, password = index_url_user_password - if username is not None and password is not None: - logger.debug("Found credentials in index url for %s", netloc) - return index_url_user_password - - # Get creds from netrc if we still don't have them - if allow_netrc: - netrc_auth = get_netrc_auth(original_url) - if netrc_auth: - logger.debug("Found credentials in netrc for %s", netloc) - return netrc_auth - - # If we don't have a password and keyring is available, use it. - if allow_keyring: - # The index url is more specific than the netloc, so try it first - # fmt: off - kr_auth = ( - get_keyring_auth(index_url, username) or - get_keyring_auth(netloc, username) - ) - # fmt: on - if kr_auth: - logger.debug("Found credentials in keyring for %s", netloc) - return kr_auth - - return username, password - - def _get_url_and_credentials( - self, original_url: str - ) -> Tuple[str, Optional[str], Optional[str]]: - """Return the credentials to use for the provided URL. - - If allowed, netrc and keyring may be used to obtain the - correct credentials. - - Returns (url_without_credentials, username, password). Note - that even if the original URL contains credentials, this - function may return a different username and password. - """ - url, netloc, _ = split_auth_netloc_from_url(original_url) - - # Try to get credentials from original url - username, password = self._get_new_credentials(original_url) - - # If credentials not found, use any stored credentials for this netloc - if username is None and password is None: - username, password = self.passwords.get(netloc, (None, None)) - - if username is not None or password is not None: - # Convert the username and password if they're None, so that - # this netloc will show up as "cached" in the conditional above. - # Further, HTTPBasicAuth doesn't accept None, so it makes sense to - # cache the value that is going to be used. - username = username or "" - password = password or "" - - # Store any acquired credentials. - self.passwords[netloc] = (username, password) - - assert ( - # Credentials were found - (username is not None and password is not None) - # Credentials were not found - or (username is None and password is None) - ), f"Could not load credentials from url: {original_url}" - - return url, username, password - - def __call__(self, req: Request) -> Request: - # Get credentials for this request - url, username, password = self._get_url_and_credentials(req.url) - - # Set the url of the request to the url without any credentials - req.url = url - - if username is not None and password is not None: - # Send the basic auth with this request - req = HTTPBasicAuth(username, password)(req) - - # Attach a hook to handle 401 responses - req.register_hook("response", self.handle_401) - - return req - - # Factored out to allow for easy patching in tests - def _prompt_for_password( - self, netloc: str - ) -> Tuple[Optional[str], Optional[str], bool]: - username = ask_input(f"User for {netloc}: ") - if not username: - return None, None, False - auth = get_keyring_auth(netloc, username) - if auth and auth[0] is not None and auth[1] is not None: - return auth[0], auth[1], False - password = ask_password("Password: ") - return username, password, True - - # Factored out to allow for easy patching in tests - def _should_save_password_to_keyring(self) -> bool: - if not keyring: - return False - return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y" - - def handle_401(self, resp: Response, **kwargs: Any) -> Response: - # We only care about 401 responses, anything else we want to just - # pass through the actual response - if resp.status_code != 401: - return resp - - # We are not able to prompt the user so simply return the response - if not self.prompting: - return resp - - parsed = urllib.parse.urlparse(resp.url) - - # Query the keyring for credentials: - username, password = self._get_new_credentials( - resp.url, - allow_netrc=False, - allow_keyring=True, - ) - - # Prompt the user for a new username and password - save = False - if not username and not password: - username, password, save = self._prompt_for_password(parsed.netloc) - - # Store the new username and password to use for future requests - self._credentials_to_save = None - if username is not None and password is not None: - self.passwords[parsed.netloc] = (username, password) - - # Prompt to save the password to keyring - if save and self._should_save_password_to_keyring(): - self._credentials_to_save = (parsed.netloc, username, password) - - # Consume content and release the original connection to allow our new - # request to reuse the same one. - resp.content - resp.raw.release_conn() - - # Add our new username and password to the request - req = HTTPBasicAuth(username or "", password or "")(resp.request) - req.register_hook("response", self.warn_on_401) - - # On successful request, save the credentials that were used to - # keyring. (Note that if the user responded "no" above, this member - # is not set and nothing will be saved.) - if self._credentials_to_save: - req.register_hook("response", self.save_credentials) - - # Send our new request - new_resp = resp.connection.send(req, **kwargs) - new_resp.history.append(resp) - - return new_resp - - def warn_on_401(self, resp: Response, **kwargs: Any) -> None: - """Response callback to warn about incorrect credentials.""" - if resp.status_code == 401: - logger.warning( - "401 Error, Credentials not correct for %s", - resp.request.url, - ) - - def save_credentials(self, resp: Response, **kwargs: Any) -> None: - """Response callback to save credentials on success.""" - assert keyring is not None, "should never reach here without keyring" - if not keyring: - return - - creds = self._credentials_to_save - self._credentials_to_save = None - if creds and resp.status_code < 400: - try: - logger.info("Saving credentials to keyring") - keyring.set_password(*creds) - except Exception: - logger.exception("Failed to save credentials") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/cache.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/cache.py deleted file mode 100644 index 2d915e6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/cache.py +++ /dev/null @@ -1,69 +0,0 @@ -"""HTTP cache implementation. -""" - -import os -from contextlib import contextmanager -from typing import Iterator, Optional - -from pip._vendor.cachecontrol.cache import BaseCache -from pip._vendor.cachecontrol.caches import FileCache -from pip._vendor.requests.models import Response - -from pip._internal.utils.filesystem import adjacent_tmp_file, replace -from pip._internal.utils.misc import ensure_dir - - -def is_from_cache(response: Response) -> bool: - return getattr(response, "from_cache", False) - - -@contextmanager -def suppressed_cache_errors() -> Iterator[None]: - """If we can't access the cache then we can just skip caching and process - requests as if caching wasn't enabled. - """ - try: - yield - except OSError: - pass - - -class SafeFileCache(BaseCache): - """ - A file based cache which is safe to use even when the target directory may - not be accessible or writable. - """ - - def __init__(self, directory: str) -> None: - assert directory is not None, "Cache directory must not be None." - super().__init__() - self.directory = directory - - def _get_cache_path(self, name: str) -> str: - # From cachecontrol.caches.file_cache.FileCache._fn, brought into our - # class for backwards-compatibility and to avoid using a non-public - # method. - hashed = FileCache.encode(name) - parts = list(hashed[:5]) + [hashed] - return os.path.join(self.directory, *parts) - - def get(self, key: str) -> Optional[bytes]: - path = self._get_cache_path(key) - with suppressed_cache_errors(): - with open(path, "rb") as f: - return f.read() - - def set(self, key: str, value: bytes) -> None: - path = self._get_cache_path(key) - with suppressed_cache_errors(): - ensure_dir(os.path.dirname(path)) - - with adjacent_tmp_file(path) as f: - f.write(value) - - replace(f.name, path) - - def delete(self, key: str) -> None: - path = self._get_cache_path(key) - with suppressed_cache_errors(): - os.remove(path) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/download.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/download.py deleted file mode 100644 index 47af547..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/download.py +++ /dev/null @@ -1,184 +0,0 @@ -"""Download files with progress indicators. -""" -import cgi -import logging -import mimetypes -import os -from typing import Iterable, Optional, Tuple - -from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response - -from pip._internal.cli.progress_bars import DownloadProgressProvider -from pip._internal.exceptions import NetworkConnectionError -from pip._internal.models.index import PyPI -from pip._internal.models.link import Link -from pip._internal.network.cache import is_from_cache -from pip._internal.network.session import PipSession -from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks -from pip._internal.utils.misc import format_size, redact_auth_from_url, splitext - -logger = logging.getLogger(__name__) - - -def _get_http_response_size(resp: Response) -> Optional[int]: - try: - return int(resp.headers["content-length"]) - except (ValueError, KeyError, TypeError): - return None - - -def _prepare_download( - resp: Response, - link: Link, - progress_bar: str, -) -> Iterable[bytes]: - total_length = _get_http_response_size(resp) - - if link.netloc == PyPI.file_storage_domain: - url = link.show_url - else: - url = link.url_without_fragment - - logged_url = redact_auth_from_url(url) - - if total_length: - logged_url = "{} ({})".format(logged_url, format_size(total_length)) - - if is_from_cache(resp): - logger.info("Using cached %s", logged_url) - else: - logger.info("Downloading %s", logged_url) - - if logger.getEffectiveLevel() > logging.INFO: - show_progress = False - elif is_from_cache(resp): - show_progress = False - elif not total_length: - show_progress = True - elif total_length > (40 * 1000): - show_progress = True - else: - show_progress = False - - chunks = response_chunks(resp, CONTENT_CHUNK_SIZE) - - if not show_progress: - return chunks - - return DownloadProgressProvider(progress_bar, max=total_length)(chunks) - - -def sanitize_content_filename(filename: str) -> str: - """ - Sanitize the "filename" value from a Content-Disposition header. - """ - return os.path.basename(filename) - - -def parse_content_disposition(content_disposition: str, default_filename: str) -> str: - """ - Parse the "filename" value from a Content-Disposition header, and - return the default filename if the result is empty. - """ - _type, params = cgi.parse_header(content_disposition) - filename = params.get("filename") - if filename: - # We need to sanitize the filename to prevent directory traversal - # in case the filename contains ".." path parts. - filename = sanitize_content_filename(filename) - return filename or default_filename - - -def _get_http_response_filename(resp: Response, link: Link) -> str: - """Get an ideal filename from the given HTTP response, falling back to - the link filename if not provided. - """ - filename = link.filename # fallback - # Have a look at the Content-Disposition header for a better guess - content_disposition = resp.headers.get("content-disposition") - if content_disposition: - filename = parse_content_disposition(content_disposition, filename) - ext: Optional[str] = splitext(filename)[1] - if not ext: - ext = mimetypes.guess_extension(resp.headers.get("content-type", "")) - if ext: - filename += ext - if not ext and link.url != resp.url: - ext = os.path.splitext(resp.url)[1] - if ext: - filename += ext - return filename - - -def _http_get_download(session: PipSession, link: Link) -> Response: - target_url = link.url.split("#", 1)[0] - resp = session.get(target_url, headers=HEADERS, stream=True) - raise_for_status(resp) - return resp - - -class Downloader: - def __init__( - self, - session: PipSession, - progress_bar: str, - ) -> None: - self._session = session - self._progress_bar = progress_bar - - def __call__(self, link: Link, location: str) -> Tuple[str, str]: - """Download the file given by link into location.""" - try: - resp = _http_get_download(self._session, link) - except NetworkConnectionError as e: - assert e.response is not None - logger.critical( - "HTTP error %s while getting %s", e.response.status_code, link - ) - raise - - filename = _get_http_response_filename(resp, link) - filepath = os.path.join(location, filename) - - chunks = _prepare_download(resp, link, self._progress_bar) - with open(filepath, "wb") as content_file: - for chunk in chunks: - content_file.write(chunk) - content_type = resp.headers.get("Content-Type", "") - return filepath, content_type - - -class BatchDownloader: - def __init__( - self, - session: PipSession, - progress_bar: str, - ) -> None: - self._session = session - self._progress_bar = progress_bar - - def __call__( - self, links: Iterable[Link], location: str - ) -> Iterable[Tuple[Link, Tuple[str, str]]]: - """Download the files given by links into location.""" - for link in links: - try: - resp = _http_get_download(self._session, link) - except NetworkConnectionError as e: - assert e.response is not None - logger.critical( - "HTTP error %s while getting %s", - e.response.status_code, - link, - ) - raise - - filename = _get_http_response_filename(resp, link) - filepath = os.path.join(location, filename) - - chunks = _prepare_download(resp, link, self._progress_bar) - with open(filepath, "wb") as content_file: - for chunk in chunks: - content_file.write(chunk) - content_type = resp.headers.get("Content-Type", "") - yield link, (filepath, content_type) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/lazy_wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/lazy_wheel.py deleted file mode 100644 index 249bd05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/lazy_wheel.py +++ /dev/null @@ -1,210 +0,0 @@ -"""Lazy ZIP over HTTP""" - -__all__ = ["HTTPRangeRequestUnsupported", "dist_from_wheel_url"] - -from bisect import bisect_left, bisect_right -from contextlib import contextmanager -from tempfile import NamedTemporaryFile -from typing import Any, Dict, Iterator, List, Optional, Tuple -from zipfile import BadZipfile, ZipFile - -from pip._vendor.pkg_resources import Distribution -from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response - -from pip._internal.network.session import PipSession -from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks -from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel - - -class HTTPRangeRequestUnsupported(Exception): - pass - - -def dist_from_wheel_url(name: str, url: str, session: PipSession) -> Distribution: - """Return a pkg_resources.Distribution from the given wheel URL. - - This uses HTTP range requests to only fetch the potion of the wheel - containing metadata, just enough for the object to be constructed. - If such requests are not supported, HTTPRangeRequestUnsupported - is raised. - """ - with LazyZipOverHTTP(url, session) as wheel: - # For read-only ZIP files, ZipFile only needs methods read, - # seek, seekable and tell, not the whole IO protocol. - zip_file = ZipFile(wheel) # type: ignore - # After context manager exit, wheel.name - # is an invalid file by intention. - return pkg_resources_distribution_for_wheel(zip_file, name, wheel.name) - - -class LazyZipOverHTTP: - """File-like object mapped to a ZIP file over HTTP. - - This uses HTTP range requests to lazily fetch the file's content, - which is supposed to be fed to ZipFile. If such requests are not - supported by the server, raise HTTPRangeRequestUnsupported - during initialization. - """ - - def __init__( - self, url: str, session: PipSession, chunk_size: int = CONTENT_CHUNK_SIZE - ) -> None: - head = session.head(url, headers=HEADERS) - raise_for_status(head) - assert head.status_code == 200 - self._session, self._url, self._chunk_size = session, url, chunk_size - self._length = int(head.headers["Content-Length"]) - self._file = NamedTemporaryFile() - self.truncate(self._length) - self._left: List[int] = [] - self._right: List[int] = [] - if "bytes" not in head.headers.get("Accept-Ranges", "none"): - raise HTTPRangeRequestUnsupported("range request is not supported") - self._check_zip() - - @property - def mode(self) -> str: - """Opening mode, which is always rb.""" - return "rb" - - @property - def name(self) -> str: - """Path to the underlying file.""" - return self._file.name - - def seekable(self) -> bool: - """Return whether random access is supported, which is True.""" - return True - - def close(self) -> None: - """Close the file.""" - self._file.close() - - @property - def closed(self) -> bool: - """Whether the file is closed.""" - return self._file.closed - - def read(self, size: int = -1) -> bytes: - """Read up to size bytes from the object and return them. - - As a convenience, if size is unspecified or -1, - all bytes until EOF are returned. Fewer than - size bytes may be returned if EOF is reached. - """ - download_size = max(size, self._chunk_size) - start, length = self.tell(), self._length - stop = length if size < 0 else min(start + download_size, length) - start = max(0, stop - download_size) - self._download(start, stop - 1) - return self._file.read(size) - - def readable(self) -> bool: - """Return whether the file is readable, which is True.""" - return True - - def seek(self, offset: int, whence: int = 0) -> int: - """Change stream position and return the new absolute position. - - Seek to offset relative position indicated by whence: - * 0: Start of stream (the default). pos should be >= 0; - * 1: Current position - pos may be negative; - * 2: End of stream - pos usually negative. - """ - return self._file.seek(offset, whence) - - def tell(self) -> int: - """Return the current position.""" - return self._file.tell() - - def truncate(self, size: Optional[int] = None) -> int: - """Resize the stream to the given size in bytes. - - If size is unspecified resize to the current position. - The current stream position isn't changed. - - Return the new file size. - """ - return self._file.truncate(size) - - def writable(self) -> bool: - """Return False.""" - return False - - def __enter__(self) -> "LazyZipOverHTTP": - self._file.__enter__() - return self - - def __exit__(self, *exc: Any) -> Optional[bool]: - return self._file.__exit__(*exc) - - @contextmanager - def _stay(self) -> Iterator[None]: - """Return a context manager keeping the position. - - At the end of the block, seek back to original position. - """ - pos = self.tell() - try: - yield - finally: - self.seek(pos) - - def _check_zip(self) -> None: - """Check and download until the file is a valid ZIP.""" - end = self._length - 1 - for start in reversed(range(0, end, self._chunk_size)): - self._download(start, end) - with self._stay(): - try: - # For read-only ZIP files, ZipFile only needs - # methods read, seek, seekable and tell. - ZipFile(self) # type: ignore - except BadZipfile: - pass - else: - break - - def _stream_response( - self, start: int, end: int, base_headers: Dict[str, str] = HEADERS - ) -> Response: - """Return HTTP response to a range request from start to end.""" - headers = base_headers.copy() - headers["Range"] = f"bytes={start}-{end}" - # TODO: Get range requests to be correctly cached - headers["Cache-Control"] = "no-cache" - return self._session.get(self._url, headers=headers, stream=True) - - def _merge( - self, start: int, end: int, left: int, right: int - ) -> Iterator[Tuple[int, int]]: - """Return an iterator of intervals to be fetched. - - Args: - start (int): Start of needed interval - end (int): End of needed interval - left (int): Index of first overlapping downloaded data - right (int): Index after last overlapping downloaded data - """ - lslice, rslice = self._left[left:right], self._right[left:right] - i = start = min([start] + lslice[:1]) - end = max([end] + rslice[-1:]) - for j, k in zip(lslice, rslice): - if j > i: - yield i, j - 1 - i = k + 1 - if i <= end: - yield i, end - self._left[left:right], self._right[left:right] = [start], [end] - - def _download(self, start: int, end: int) -> None: - """Download bytes from start to end inclusively.""" - with self._stay(): - left = bisect_left(self._right, start) - right = bisect_right(self._left, end) - for start, end in self._merge(start, end, left, right): - response = self._stream_response(start, end) - response.raise_for_status() - self.seek(start) - for chunk in response_chunks(response, self._chunk_size): - self._file.write(chunk) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/session.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/session.py deleted file mode 100644 index faaae40..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/session.py +++ /dev/null @@ -1,454 +0,0 @@ -"""PipSession and supporting code, containing all pip-specific -network request configuration and behavior. -""" - -# When mypy runs on Windows the call to distro.linux_distribution() is skipped -# resulting in the failure: -# -# error: unused 'type: ignore' comment -# -# If the upstream module adds typing, this comment should be removed. See -# https://github.com/nir0s/distro/pull/269 -# -# mypy: warn-unused-ignores=False - -import email.utils -import ipaddress -import json -import logging -import mimetypes -import os -import platform -import shutil -import subprocess -import sys -import urllib.parse -import warnings -from typing import Any, Dict, Iterator, List, Mapping, Optional, Sequence, Tuple, Union - -from pip._vendor import requests, urllib3 -from pip._vendor.cachecontrol import CacheControlAdapter -from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter -from pip._vendor.requests.models import PreparedRequest, Response -from pip._vendor.requests.structures import CaseInsensitiveDict -from pip._vendor.urllib3.connectionpool import ConnectionPool -from pip._vendor.urllib3.exceptions import InsecureRequestWarning - -from pip import __version__ -from pip._internal.metadata import get_default_environment -from pip._internal.models.link import Link -from pip._internal.network.auth import MultiDomainBasicAuth -from pip._internal.network.cache import SafeFileCache - -# Import ssl from compat so the initial import occurs in only one place. -from pip._internal.utils.compat import has_tls -from pip._internal.utils.glibc import libc_ver -from pip._internal.utils.misc import build_url_from_netloc, parse_netloc -from pip._internal.utils.urls import url_to_path - -logger = logging.getLogger(__name__) - -SecureOrigin = Tuple[str, str, Optional[Union[int, str]]] - - -# Ignore warning raised when using --trusted-host. -warnings.filterwarnings("ignore", category=InsecureRequestWarning) - - -SECURE_ORIGINS: List[SecureOrigin] = [ - # protocol, hostname, port - # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) - ("https", "*", "*"), - ("*", "localhost", "*"), - ("*", "127.0.0.0/8", "*"), - ("*", "::1/128", "*"), - ("file", "*", None), - # ssh is always secure. - ("ssh", "*", "*"), -] - - -# These are environment variables present when running under various -# CI systems. For each variable, some CI systems that use the variable -# are indicated. The collection was chosen so that for each of a number -# of popular systems, at least one of the environment variables is used. -# This list is used to provide some indication of and lower bound for -# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive. -# For more background, see: https://github.com/pypa/pip/issues/5499 -CI_ENVIRONMENT_VARIABLES = ( - # Azure Pipelines - "BUILD_BUILDID", - # Jenkins - "BUILD_ID", - # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI - "CI", - # Explicit environment variable. - "PIP_IS_CI", -) - - -def looks_like_ci() -> bool: - """ - Return whether it looks like pip is running under CI. - """ - # We don't use the method of checking for a tty (e.g. using isatty()) - # because some CI systems mimic a tty (e.g. Travis CI). Thus that - # method doesn't provide definitive information in either direction. - return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES) - - -def user_agent() -> str: - """ - Return a string representing the user agent. - """ - data: Dict[str, Any] = { - "installer": {"name": "pip", "version": __version__}, - "python": platform.python_version(), - "implementation": { - "name": platform.python_implementation(), - }, - } - - if data["implementation"]["name"] == "CPython": - data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == "PyPy": - pypy_version_info = sys.pypy_version_info # type: ignore - if pypy_version_info.releaselevel == "final": - pypy_version_info = pypy_version_info[:3] - data["implementation"]["version"] = ".".join( - [str(x) for x in pypy_version_info] - ) - elif data["implementation"]["name"] == "Jython": - # Complete Guess - data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == "IronPython": - # Complete Guess - data["implementation"]["version"] = platform.python_version() - - if sys.platform.startswith("linux"): - from pip._vendor import distro - - # https://github.com/nir0s/distro/pull/269 - linux_distribution = distro.linux_distribution() # type: ignore - distro_infos = dict( - filter( - lambda x: x[1], - zip(["name", "version", "id"], linux_distribution), - ) - ) - libc = dict( - filter( - lambda x: x[1], - zip(["lib", "version"], libc_ver()), - ) - ) - if libc: - distro_infos["libc"] = libc - if distro_infos: - data["distro"] = distro_infos - - if sys.platform.startswith("darwin") and platform.mac_ver()[0]: - data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} - - if platform.system(): - data.setdefault("system", {})["name"] = platform.system() - - if platform.release(): - data.setdefault("system", {})["release"] = platform.release() - - if platform.machine(): - data["cpu"] = platform.machine() - - if has_tls(): - import _ssl as ssl - - data["openssl_version"] = ssl.OPENSSL_VERSION - - setuptools_dist = get_default_environment().get_distribution("setuptools") - if setuptools_dist is not None: - data["setuptools_version"] = str(setuptools_dist.version) - - if shutil.which("rustc") is not None: - # If for any reason `rustc --version` fails, silently ignore it - try: - rustc_output = subprocess.check_output( - ["rustc", "--version"], stderr=subprocess.STDOUT, timeout=0.5 - ) - except Exception: - pass - else: - if rustc_output.startswith(b"rustc "): - # The format of `rustc --version` is: - # `b'rustc 1.52.1 (9bc8c42bb 2021-05-09)\n'` - # We extract just the middle (1.52.1) part - data["rustc_version"] = rustc_output.split(b" ")[1].decode() - - # Use None rather than False so as not to give the impression that - # pip knows it is not being run under CI. Rather, it is a null or - # inconclusive result. Also, we include some value rather than no - # value to make it easier to know that the check has been run. - data["ci"] = True if looks_like_ci() else None - - user_data = os.environ.get("PIP_USER_AGENT_USER_DATA") - if user_data is not None: - data["user_data"] = user_data - - return "{data[installer][name]}/{data[installer][version]} {json}".format( - data=data, - json=json.dumps(data, separators=(",", ":"), sort_keys=True), - ) - - -class LocalFSAdapter(BaseAdapter): - def send( - self, - request: PreparedRequest, - stream: bool = False, - timeout: Optional[Union[float, Tuple[float, float]]] = None, - verify: Union[bool, str] = True, - cert: Optional[Union[str, Tuple[str, str]]] = None, - proxies: Optional[Mapping[str, str]] = None, - ) -> Response: - pathname = url_to_path(request.url) - - resp = Response() - resp.status_code = 200 - resp.url = request.url - - try: - stats = os.stat(pathname) - except OSError as exc: - resp.status_code = 404 - resp.raw = exc - else: - modified = email.utils.formatdate(stats.st_mtime, usegmt=True) - content_type = mimetypes.guess_type(pathname)[0] or "text/plain" - resp.headers = CaseInsensitiveDict( - { - "Content-Type": content_type, - "Content-Length": stats.st_size, - "Last-Modified": modified, - } - ) - - resp.raw = open(pathname, "rb") - resp.close = resp.raw.close - - return resp - - def close(self) -> None: - pass - - -class InsecureHTTPAdapter(HTTPAdapter): - def cert_verify( - self, - conn: ConnectionPool, - url: str, - verify: Union[bool, str], - cert: Optional[Union[str, Tuple[str, str]]], - ) -> None: - super().cert_verify(conn=conn, url=url, verify=False, cert=cert) - - -class InsecureCacheControlAdapter(CacheControlAdapter): - def cert_verify( - self, - conn: ConnectionPool, - url: str, - verify: Union[bool, str], - cert: Optional[Union[str, Tuple[str, str]]], - ) -> None: - super().cert_verify(conn=conn, url=url, verify=False, cert=cert) - - -class PipSession(requests.Session): - - timeout: Optional[int] = None - - def __init__( - self, - *args: Any, - retries: int = 0, - cache: Optional[str] = None, - trusted_hosts: Sequence[str] = (), - index_urls: Optional[List[str]] = None, - **kwargs: Any, - ) -> None: - """ - :param trusted_hosts: Domains not to emit warnings for when not using - HTTPS. - """ - super().__init__(*args, **kwargs) - - # Namespace the attribute with "pip_" just in case to prevent - # possible conflicts with the base class. - self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = [] - - # Attach our User Agent to the request - self.headers["User-Agent"] = user_agent() - - # Attach our Authentication handler to the session - self.auth = MultiDomainBasicAuth(index_urls=index_urls) - - # Create our urllib3.Retry instance which will allow us to customize - # how we handle retries. - retries = urllib3.Retry( - # Set the total number of retries that a particular request can - # have. - total=retries, - # A 503 error from PyPI typically means that the Fastly -> Origin - # connection got interrupted in some way. A 503 error in general - # is typically considered a transient error so we'll go ahead and - # retry it. - # A 500 may indicate transient error in Amazon S3 - # A 520 or 527 - may indicate transient error in CloudFlare - status_forcelist=[500, 503, 520, 527], - # Add a small amount of back off between failed requests in - # order to prevent hammering the service. - backoff_factor=0.25, - ) # type: ignore - - # Our Insecure HTTPAdapter disables HTTPS validation. It does not - # support caching so we'll use it for all http:// URLs. - # If caching is disabled, we will also use it for - # https:// hosts that we've marked as ignoring - # TLS errors for (trusted-hosts). - insecure_adapter = InsecureHTTPAdapter(max_retries=retries) - - # We want to _only_ cache responses on securely fetched origins or when - # the host is specified as trusted. We do this because - # we can't validate the response of an insecurely/untrusted fetched - # origin, and we don't want someone to be able to poison the cache and - # require manual eviction from the cache to fix it. - if cache: - secure_adapter = CacheControlAdapter( - cache=SafeFileCache(cache), - max_retries=retries, - ) - self._trusted_host_adapter = InsecureCacheControlAdapter( - cache=SafeFileCache(cache), - max_retries=retries, - ) - else: - secure_adapter = HTTPAdapter(max_retries=retries) - self._trusted_host_adapter = insecure_adapter - - self.mount("https://", secure_adapter) - self.mount("http://", insecure_adapter) - - # Enable file:// urls - self.mount("file://", LocalFSAdapter()) - - for host in trusted_hosts: - self.add_trusted_host(host, suppress_logging=True) - - def update_index_urls(self, new_index_urls: List[str]) -> None: - """ - :param new_index_urls: New index urls to update the authentication - handler with. - """ - self.auth.index_urls = new_index_urls - - def add_trusted_host( - self, host: str, source: Optional[str] = None, suppress_logging: bool = False - ) -> None: - """ - :param host: It is okay to provide a host that has previously been - added. - :param source: An optional source string, for logging where the host - string came from. - """ - if not suppress_logging: - msg = f"adding trusted host: {host!r}" - if source is not None: - msg += f" (from {source})" - logger.info(msg) - - host_port = parse_netloc(host) - if host_port not in self.pip_trusted_origins: - self.pip_trusted_origins.append(host_port) - - self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter) - if not host_port[1]: - # Mount wildcard ports for the same host. - self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter) - - def iter_secure_origins(self) -> Iterator[SecureOrigin]: - yield from SECURE_ORIGINS - for host, port in self.pip_trusted_origins: - yield ("*", host, "*" if port is None else port) - - def is_secure_origin(self, location: Link) -> bool: - # Determine if this url used a secure transport mechanism - parsed = urllib.parse.urlparse(str(location)) - origin_protocol, origin_host, origin_port = ( - parsed.scheme, - parsed.hostname, - parsed.port, - ) - - # The protocol to use to see if the protocol matches. - # Don't count the repository type as part of the protocol: in - # cases such as "git+ssh", only use "ssh". (I.e., Only verify against - # the last scheme.) - origin_protocol = origin_protocol.rsplit("+", 1)[-1] - - # Determine if our origin is a secure origin by looking through our - # hardcoded list of secure origins, as well as any additional ones - # configured on this PackageFinder instance. - for secure_origin in self.iter_secure_origins(): - secure_protocol, secure_host, secure_port = secure_origin - if origin_protocol != secure_protocol and secure_protocol != "*": - continue - - try: - addr = ipaddress.ip_address(origin_host) - network = ipaddress.ip_network(secure_host) - except ValueError: - # We don't have both a valid address or a valid network, so - # we'll check this origin against hostnames. - if ( - origin_host - and origin_host.lower() != secure_host.lower() - and secure_host != "*" - ): - continue - else: - # We have a valid address and network, so see if the address - # is contained within the network. - if addr not in network: - continue - - # Check to see if the port matches. - if ( - origin_port != secure_port - and secure_port != "*" - and secure_port is not None - ): - continue - - # If we've gotten here, then this origin matches the current - # secure origin and we should return True - return True - - # If we've gotten to this point, then the origin isn't secure and we - # will not accept it as a valid location to search. We will however - # log a warning that we are ignoring it. - logger.warning( - "The repository located at %s is not a trusted or secure host and " - "is being ignored. If this repository is available via HTTPS we " - "recommend you use HTTPS instead, otherwise you may silence " - "this warning and allow it anyway with '--trusted-host %s'.", - origin_host, - origin_host, - ) - - return False - - def request(self, method: str, url: str, *args: Any, **kwargs: Any) -> Response: - # Allow setting a default timeout on a session - kwargs.setdefault("timeout", self.timeout) - - # Dispatch the actual request - return super().request(method, url, *args, **kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/utils.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/utils.py deleted file mode 100644 index 094cf1b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/utils.py +++ /dev/null @@ -1,96 +0,0 @@ -from typing import Dict, Iterator - -from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response - -from pip._internal.exceptions import NetworkConnectionError - -# The following comments and HTTP headers were originally added by -# Donald Stufft in git commit 22c562429a61bb77172039e480873fb239dd8c03. -# -# We use Accept-Encoding: identity here because requests defaults to -# accepting compressed responses. This breaks in a variety of ways -# depending on how the server is configured. -# - Some servers will notice that the file isn't a compressible file -# and will leave the file alone and with an empty Content-Encoding -# - Some servers will notice that the file is already compressed and -# will leave the file alone, adding a Content-Encoding: gzip header -# - Some servers won't notice anything at all and will take a file -# that's already been compressed and compress it again, and set -# the Content-Encoding: gzip header -# By setting this to request only the identity encoding we're hoping -# to eliminate the third case. Hopefully there does not exist a server -# which when given a file will notice it is already compressed and that -# you're not asking for a compressed file and will then decompress it -# before sending because if that's the case I don't think it'll ever be -# possible to make this work. -HEADERS: Dict[str, str] = {"Accept-Encoding": "identity"} - - -def raise_for_status(resp: Response) -> None: - http_error_msg = "" - if isinstance(resp.reason, bytes): - # We attempt to decode utf-8 first because some servers - # choose to localize their reason strings. If the string - # isn't utf-8, we fall back to iso-8859-1 for all other - # encodings. - try: - reason = resp.reason.decode("utf-8") - except UnicodeDecodeError: - reason = resp.reason.decode("iso-8859-1") - else: - reason = resp.reason - - if 400 <= resp.status_code < 500: - http_error_msg = ( - f"{resp.status_code} Client Error: {reason} for url: {resp.url}" - ) - - elif 500 <= resp.status_code < 600: - http_error_msg = ( - f"{resp.status_code} Server Error: {reason} for url: {resp.url}" - ) - - if http_error_msg: - raise NetworkConnectionError(http_error_msg, response=resp) - - -def response_chunks( - response: Response, chunk_size: int = CONTENT_CHUNK_SIZE -) -> Iterator[bytes]: - """Given a requests Response, provide the data chunks.""" - try: - # Special case for urllib3. - for chunk in response.raw.stream( - chunk_size, - # We use decode_content=False here because we don't - # want urllib3 to mess with the raw bytes we get - # from the server. If we decompress inside of - # urllib3 then we cannot verify the checksum - # because the checksum will be of the compressed - # file. This breakage will only occur if the - # server adds a Content-Encoding header, which - # depends on how the server was configured: - # - Some servers will notice that the file isn't a - # compressible file and will leave the file alone - # and with an empty Content-Encoding - # - Some servers will notice that the file is - # already compressed and will leave the file - # alone and will add a Content-Encoding: gzip - # header - # - Some servers won't notice anything at all and - # will take a file that's already been compressed - # and compress it again and set the - # Content-Encoding: gzip header - # - # By setting this not to decode automatically we - # hope to eliminate problems with the second case. - decode_content=False, - ): - yield chunk - except AttributeError: - # Standard file-like object. - while True: - chunk = response.raw.read(chunk_size) - if not chunk: - break - yield chunk diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/xmlrpc.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/xmlrpc.py deleted file mode 100644 index 4a7d55d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/network/xmlrpc.py +++ /dev/null @@ -1,60 +0,0 @@ -"""xmlrpclib.Transport implementation -""" - -import logging -import urllib.parse -import xmlrpc.client -from typing import TYPE_CHECKING, Tuple - -from pip._internal.exceptions import NetworkConnectionError -from pip._internal.network.session import PipSession -from pip._internal.network.utils import raise_for_status - -if TYPE_CHECKING: - from xmlrpc.client import _HostType, _Marshallable - -logger = logging.getLogger(__name__) - - -class PipXmlrpcTransport(xmlrpc.client.Transport): - """Provide a `xmlrpclib.Transport` implementation via a `PipSession` - object. - """ - - def __init__( - self, index_url: str, session: PipSession, use_datetime: bool = False - ) -> None: - super().__init__(use_datetime) - index_parts = urllib.parse.urlparse(index_url) - self._scheme = index_parts.scheme - self._session = session - - def request( - self, - host: "_HostType", - handler: str, - request_body: bytes, - verbose: bool = False, - ) -> Tuple["_Marshallable", ...]: - assert isinstance(host, str) - parts = (self._scheme, host, handler, None, None, None) - url = urllib.parse.urlunparse(parts) - try: - headers = {"Content-Type": "text/xml"} - response = self._session.post( - url, - data=request_body, - headers=headers, - stream=True, - ) - raise_for_status(response) - self.verbose = verbose - return self.parse_response(response.raw) - except NetworkConnectionError as exc: - assert exc.response - logger.critical( - "HTTP error %s while getting %s", - exc.response.status_code, - url, - ) - raise diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata.py deleted file mode 100644 index 1c82683..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Metadata generation logic for source distributions. -""" - -import os - -from pip._vendor.pep517.wrappers import Pep517HookCaller - -from pip._internal.build_env import BuildEnvironment -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.temp_dir import TempDirectory - - -def generate_metadata(build_env, backend): - # type: (BuildEnvironment, Pep517HookCaller) -> str - """Generate metadata using mechanisms described in PEP 517. - - Returns the generated metadata directory. - """ - metadata_tmpdir = TempDirectory( - kind="modern-metadata", globally_managed=True - ) - - metadata_dir = metadata_tmpdir.path - - with build_env: - # Note that Pep517HookCaller implements a fallback for - # prepare_metadata_for_build_wheel, so we don't have to - # consider the possibility that this hook doesn't exist. - runner = runner_with_spinner_message("Preparing wheel metadata") - with backend.subprocess_runner(runner): - distinfo_dir = backend.prepare_metadata_for_build_wheel( - metadata_dir - ) - - return os.path.join(metadata_dir, distinfo_dir) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata_legacy.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata_legacy.py deleted file mode 100644 index f46538a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/metadata_legacy.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Metadata generation logic for legacy source distributions. -""" - -import logging -import os - -from pip._internal.build_env import BuildEnvironment -from pip._internal.exceptions import InstallationError -from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -def _find_egg_info(directory): - # type: (str) -> str - """Find an .egg-info subdirectory in `directory`. - """ - filenames = [ - f for f in os.listdir(directory) if f.endswith(".egg-info") - ] - - if not filenames: - raise InstallationError( - f"No .egg-info directory found in {directory}" - ) - - if len(filenames) > 1: - raise InstallationError( - "More than one .egg-info directory found in {}".format( - directory - ) - ) - - return os.path.join(directory, filenames[0]) - - -def generate_metadata( - build_env, # type: BuildEnvironment - setup_py_path, # type: str - source_dir, # type: str - isolated, # type: bool - details, # type: str -): - # type: (...) -> str - """Generate metadata using setup.py-based defacto mechanisms. - - Returns the generated metadata directory. - """ - logger.debug( - 'Running setup.py (path:%s) egg_info for package %s', - setup_py_path, details, - ) - - egg_info_dir = TempDirectory( - kind="pip-egg-info", globally_managed=True - ).path - - args = make_setuptools_egg_info_args( - setup_py_path, - egg_info_dir=egg_info_dir, - no_user_config=isolated, - ) - - with build_env: - call_subprocess( - args, - cwd=source_dir, - command_desc='python setup.py egg_info', - ) - - # Return the .egg-info directory. - return _find_egg_info(egg_info_dir) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel.py deleted file mode 100644 index 903bd7a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging -import os -from typing import Optional - -from pip._vendor.pep517.wrappers import Pep517HookCaller - -from pip._internal.utils.subprocess import runner_with_spinner_message - -logger = logging.getLogger(__name__) - - -def build_wheel_pep517( - name, # type: str - backend, # type: Pep517HookCaller - metadata_directory, # type: str - tempd, # type: str -): - # type: (...) -> Optional[str] - """Build one InstallRequirement using the PEP 517 build process. - - Returns path to wheel if successfully built. Otherwise, returns None. - """ - assert metadata_directory is not None - try: - logger.debug('Destination directory: %s', tempd) - - runner = runner_with_spinner_message( - f'Building wheel for {name} (PEP 517)' - ) - with backend.subprocess_runner(runner): - wheel_name = backend.build_wheel( - tempd, - metadata_directory=metadata_directory, - ) - except Exception: - logger.error('Failed building wheel for %s', name) - return None - return os.path.join(tempd, wheel_name) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel_legacy.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel_legacy.py deleted file mode 100644 index 755c3bc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/build/wheel_legacy.py +++ /dev/null @@ -1,110 +0,0 @@ -import logging -import os.path -from typing import List, Optional - -from pip._internal.cli.spinners import open_spinner -from pip._internal.utils.setuptools_build import make_setuptools_bdist_wheel_args -from pip._internal.utils.subprocess import ( - LOG_DIVIDER, - call_subprocess, - format_command_args, -) - -logger = logging.getLogger(__name__) - - -def format_command_result( - command_args, # type: List[str] - command_output, # type: str -): - # type: (...) -> str - """Format command information for logging.""" - command_desc = format_command_args(command_args) - text = f'Command arguments: {command_desc}\n' - - if not command_output: - text += 'Command output: None' - elif logger.getEffectiveLevel() > logging.DEBUG: - text += 'Command output: [use --verbose to show]' - else: - if not command_output.endswith('\n'): - command_output += '\n' - text += f'Command output:\n{command_output}{LOG_DIVIDER}' - - return text - - -def get_legacy_build_wheel_path( - names, # type: List[str] - temp_dir, # type: str - name, # type: str - command_args, # type: List[str] - command_output, # type: str -): - # type: (...) -> Optional[str] - """Return the path to the wheel in the temporary build directory.""" - # Sort for determinism. - names = sorted(names) - if not names: - msg = ( - 'Legacy build of wheel for {!r} created no files.\n' - ).format(name) - msg += format_command_result(command_args, command_output) - logger.warning(msg) - return None - - if len(names) > 1: - msg = ( - 'Legacy build of wheel for {!r} created more than one file.\n' - 'Filenames (choosing first): {}\n' - ).format(name, names) - msg += format_command_result(command_args, command_output) - logger.warning(msg) - - return os.path.join(temp_dir, names[0]) - - -def build_wheel_legacy( - name, # type: str - setup_py_path, # type: str - source_dir, # type: str - global_options, # type: List[str] - build_options, # type: List[str] - tempd, # type: str -): - # type: (...) -> Optional[str] - """Build one unpacked package using the "legacy" build process. - - Returns path to wheel if successfully built. Otherwise, returns None. - """ - wheel_args = make_setuptools_bdist_wheel_args( - setup_py_path, - global_options=global_options, - build_options=build_options, - destination_dir=tempd, - ) - - spin_message = f'Building wheel for {name} (setup.py)' - with open_spinner(spin_message) as spinner: - logger.debug('Destination directory: %s', tempd) - - try: - output = call_subprocess( - wheel_args, - cwd=source_dir, - spinner=spinner, - ) - except Exception: - spinner.finish("error") - logger.error('Failed building wheel for %s', name) - return None - - names = os.listdir(tempd) - wheel_path = get_legacy_build_wheel_path( - names=names, - temp_dir=tempd, - name=name, - command_args=wheel_args, - command_output=output, - ) - return wheel_path diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/check.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/check.py deleted file mode 100644 index f3963fb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/check.py +++ /dev/null @@ -1,153 +0,0 @@ -"""Validation of dependencies of packages -""" - -import logging -from typing import TYPE_CHECKING, Callable, Dict, List, NamedTuple, Optional, Set, Tuple - -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.distributions import make_distribution_for_install_requirement -from pip._internal.metadata import get_default_environment -from pip._internal.metadata.base import DistributionVersion -from pip._internal.req.req_install import InstallRequirement - -if TYPE_CHECKING: - from pip._vendor.packaging.utils import NormalizedName - -logger = logging.getLogger(__name__) - - -class PackageDetails(NamedTuple): - version: DistributionVersion - dependencies: List[Requirement] - - -# Shorthands -PackageSet = Dict['NormalizedName', PackageDetails] -Missing = Tuple['NormalizedName', Requirement] -Conflicting = Tuple['NormalizedName', DistributionVersion, Requirement] - -MissingDict = Dict['NormalizedName', List[Missing]] -ConflictingDict = Dict['NormalizedName', List[Conflicting]] -CheckResult = Tuple[MissingDict, ConflictingDict] -ConflictDetails = Tuple[PackageSet, CheckResult] - - -def create_package_set_from_installed() -> Tuple[PackageSet, bool]: - """Converts a list of distributions into a PackageSet.""" - package_set = {} - problems = False - env = get_default_environment() - for dist in env.iter_installed_distributions(local_only=False, skip=()): - name = dist.canonical_name - try: - dependencies = list(dist.iter_dependencies()) - package_set[name] = PackageDetails(dist.version, dependencies) - except (OSError, ValueError) as e: - # Don't crash on unreadable or broken metadata. - logger.warning("Error parsing requirements for %s: %s", name, e) - problems = True - return package_set, problems - - -def check_package_set(package_set, should_ignore=None): - # type: (PackageSet, Optional[Callable[[str], bool]]) -> CheckResult - """Check if a package set is consistent - - If should_ignore is passed, it should be a callable that takes a - package name and returns a boolean. - """ - - missing = {} - conflicting = {} - - for package_name, package_detail in package_set.items(): - # Info about dependencies of package_name - missing_deps = set() # type: Set[Missing] - conflicting_deps = set() # type: Set[Conflicting] - - if should_ignore and should_ignore(package_name): - continue - - for req in package_detail.dependencies: - name = canonicalize_name(req.name) - - # Check if it's missing - if name not in package_set: - missed = True - if req.marker is not None: - missed = req.marker.evaluate() - if missed: - missing_deps.add((name, req)) - continue - - # Check if there's a conflict - version = package_set[name].version - if not req.specifier.contains(version, prereleases=True): - conflicting_deps.add((name, version, req)) - - if missing_deps: - missing[package_name] = sorted(missing_deps, key=str) - if conflicting_deps: - conflicting[package_name] = sorted(conflicting_deps, key=str) - - return missing, conflicting - - -def check_install_conflicts(to_install): - # type: (List[InstallRequirement]) -> ConflictDetails - """For checking if the dependency graph would be consistent after \ - installing given requirements - """ - # Start from the current state - package_set, _ = create_package_set_from_installed() - # Install packages - would_be_installed = _simulate_installation_of(to_install, package_set) - - # Only warn about directly-dependent packages; create a whitelist of them - whitelist = _create_whitelist(would_be_installed, package_set) - - return ( - package_set, - check_package_set( - package_set, should_ignore=lambda name: name not in whitelist - ) - ) - - -def _simulate_installation_of(to_install, package_set): - # type: (List[InstallRequirement], PackageSet) -> Set[NormalizedName] - """Computes the version of packages after installing to_install. - """ - # Keep track of packages that were installed - installed = set() - - # Modify it as installing requirement_set would (assuming no errors) - for inst_req in to_install: - abstract_dist = make_distribution_for_install_requirement(inst_req) - dist = abstract_dist.get_pkg_resources_distribution() - - assert dist is not None - name = canonicalize_name(dist.project_name) - package_set[name] = PackageDetails(dist.parsed_version, dist.requires()) - - installed.add(name) - - return installed - - -def _create_whitelist(would_be_installed, package_set): - # type: (Set[NormalizedName], PackageSet) -> Set[NormalizedName] - packages_affected = set(would_be_installed) - - for package_name in package_set: - if package_name in packages_affected: - continue - - for req in package_set[package_name].dependencies: - if canonicalize_name(req.name) in packages_affected: - packages_affected.add(package_name) - break - - return packages_affected diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/freeze.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/freeze.py deleted file mode 100644 index defb20c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/freeze.py +++ /dev/null @@ -1,277 +0,0 @@ -import collections -import logging -import os -from typing import ( - Container, - Dict, - Iterable, - Iterator, - List, - NamedTuple, - Optional, - Set, - Union, -) - -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import Version - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.metadata import BaseDistribution, get_environment -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, -) -from pip._internal.req.req_file import COMMENT_RE -from pip._internal.utils.direct_url_helpers import direct_url_as_pep440_direct_reference - -logger = logging.getLogger(__name__) - - -class _EditableInfo(NamedTuple): - requirement: Optional[str] - editable: bool - comments: List[str] - - -def freeze( - requirement=None, # type: Optional[List[str]] - local_only=False, # type: bool - user_only=False, # type: bool - paths=None, # type: Optional[List[str]] - isolated=False, # type: bool - exclude_editable=False, # type: bool - skip=() # type: Container[str] -): - # type: (...) -> Iterator[str] - installations = {} # type: Dict[str, FrozenRequirement] - - dists = get_environment(paths).iter_installed_distributions( - local_only=local_only, - skip=(), - user_only=user_only, - ) - for dist in dists: - req = FrozenRequirement.from_dist(dist) - if exclude_editable and req.editable: - continue - installations[req.canonical_name] = req - - if requirement: - # the options that don't get turned into an InstallRequirement - # should only be emitted once, even if the same option is in multiple - # requirements files, so we need to keep track of what has been emitted - # so that we don't emit it again if it's seen again - emitted_options = set() # type: Set[str] - # keep track of which files a requirement is in so that we can - # give an accurate warning if a requirement appears multiple times. - req_files = collections.defaultdict(list) # type: Dict[str, List[str]] - for req_file_path in requirement: - with open(req_file_path) as req_file: - for line in req_file: - if (not line.strip() or - line.strip().startswith('#') or - line.startswith(( - '-r', '--requirement', - '-f', '--find-links', - '-i', '--index-url', - '--pre', - '--trusted-host', - '--process-dependency-links', - '--extra-index-url', - '--use-feature'))): - line = line.rstrip() - if line not in emitted_options: - emitted_options.add(line) - yield line - continue - - if line.startswith('-e') or line.startswith('--editable'): - if line.startswith('-e'): - line = line[2:].strip() - else: - line = line[len('--editable'):].strip().lstrip('=') - line_req = install_req_from_editable( - line, - isolated=isolated, - ) - else: - line_req = install_req_from_line( - COMMENT_RE.sub('', line).strip(), - isolated=isolated, - ) - - if not line_req.name: - logger.info( - "Skipping line in requirement file [%s] because " - "it's not clear what it would install: %s", - req_file_path, line.strip(), - ) - logger.info( - " (add #egg=PackageName to the URL to avoid" - " this warning)" - ) - else: - line_req_canonical_name = canonicalize_name( - line_req.name) - if line_req_canonical_name not in installations: - # either it's not installed, or it is installed - # but has been processed already - if not req_files[line_req.name]: - logger.warning( - "Requirement file [%s] contains %s, but " - "package %r is not installed", - req_file_path, - COMMENT_RE.sub('', line).strip(), - line_req.name - ) - else: - req_files[line_req.name].append(req_file_path) - else: - yield str(installations[ - line_req_canonical_name]).rstrip() - del installations[line_req_canonical_name] - req_files[line_req.name].append(req_file_path) - - # Warn about requirements that were included multiple times (in a - # single requirements file or in different requirements files). - for name, files in req_files.items(): - if len(files) > 1: - logger.warning("Requirement %s included multiple times [%s]", - name, ', '.join(sorted(set(files)))) - - yield( - '## The following requirements were added by ' - 'pip freeze:' - ) - for installation in sorted( - installations.values(), key=lambda x: x.name.lower()): - if installation.canonical_name not in skip: - yield str(installation).rstrip() - - -def _format_as_name_version(dist: BaseDistribution) -> str: - if isinstance(dist.version, Version): - return f"{dist.raw_name}=={dist.version}" - return f"{dist.raw_name}==={dist.version}" - - -def _get_editable_info(dist: BaseDistribution) -> _EditableInfo: - """ - Compute and return values (req, editable, comments) for use in - FrozenRequirement.from_dist(). - """ - if not dist.editable: - return _EditableInfo(requirement=None, editable=False, comments=[]) - if dist.location is None: - display = _format_as_name_version(dist) - logger.warning("Editable requirement not found on disk: %s", display) - return _EditableInfo( - requirement=None, - editable=True, - comments=[f"# Editable install not found ({display})"], - ) - - location = os.path.normcase(os.path.abspath(dist.location)) - - from pip._internal.vcs import RemoteNotFoundError, RemoteNotValidError, vcs - - vcs_backend = vcs.get_backend_for_dir(location) - - if vcs_backend is None: - display = _format_as_name_version(dist) - logger.debug( - 'No VCS found for editable requirement "%s" in: %r', display, - location, - ) - return _EditableInfo( - requirement=location, - editable=True, - comments=[f'# Editable install with no version control ({display})'], - ) - - vcs_name = type(vcs_backend).__name__ - - try: - req = vcs_backend.get_src_requirement(location, dist.raw_name) - except RemoteNotFoundError: - display = _format_as_name_version(dist) - return _EditableInfo( - requirement=location, - editable=True, - comments=[f'# Editable {vcs_name} install with no remote ({display})'], - ) - except RemoteNotValidError as ex: - display = _format_as_name_version(dist) - return _EditableInfo( - requirement=location, - editable=True, - comments=[ - f"# Editable {vcs_name} install ({display}) with either a deleted " - f"local remote or invalid URI:", - f"# '{ex.url}'", - ], - ) - - except BadCommand: - logger.warning( - 'cannot determine version of editable source in %s ' - '(%s command not found in path)', - location, - vcs_backend.name, - ) - return _EditableInfo(requirement=None, editable=True, comments=[]) - - except InstallationError as exc: - logger.warning( - "Error when trying to get requirement for VCS system %s, " - "falling back to uneditable format", exc - ) - else: - return _EditableInfo(requirement=req, editable=True, comments=[]) - - logger.warning('Could not determine repository location of %s', location) - - return _EditableInfo( - requirement=None, - editable=False, - comments=['## !! Could not determine repository location'], - ) - - -class FrozenRequirement: - def __init__(self, name, req, editable, comments=()): - # type: (str, Union[str, Requirement], bool, Iterable[str]) -> None - self.name = name - self.canonical_name = canonicalize_name(name) - self.req = req - self.editable = editable - self.comments = comments - - @classmethod - def from_dist(cls, dist: BaseDistribution) -> "FrozenRequirement": - # TODO `get_requirement_info` is taking care of editable requirements. - # TODO This should be refactored when we will add detection of - # editable that provide .dist-info metadata. - req, editable, comments = _get_editable_info(dist) - if req is None and not editable: - # if PEP 610 metadata is present, attempt to use it - direct_url = dist.direct_url - if direct_url: - req = direct_url_as_pep440_direct_reference( - direct_url, dist.raw_name - ) - comments = [] - if req is None: - # name==version requirement - req = _format_as_name_version(dist) - - return cls(dist.raw_name, req, editable, comments=comments) - - def __str__(self): - # type: () -> str - req = self.req - if self.editable: - req = f'-e {req}' - return '\n'.join(list(self.comments) + [str(req)]) + '\n' diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/__init__.py deleted file mode 100644 index 24d6a5d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""For modules related to installing packages. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/editable_legacy.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/editable_legacy.py deleted file mode 100644 index 6882c47..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/editable_legacy.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Legacy editable installation process, i.e. `setup.py develop`. -""" -import logging -from typing import List, Optional, Sequence - -from pip._internal.build_env import BuildEnvironment -from pip._internal.utils.logging import indent_log -from pip._internal.utils.setuptools_build import make_setuptools_develop_args -from pip._internal.utils.subprocess import call_subprocess - -logger = logging.getLogger(__name__) - - -def install_editable( - install_options, # type: List[str] - global_options, # type: Sequence[str] - prefix, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool - name, # type: str - setup_py_path, # type: str - isolated, # type: bool - build_env, # type: BuildEnvironment - unpacked_source_directory, # type: str -): - # type: (...) -> None - """Install a package in editable mode. Most arguments are pass-through - to setuptools. - """ - logger.info('Running setup.py develop for %s', name) - - args = make_setuptools_develop_args( - setup_py_path, - global_options=global_options, - install_options=install_options, - no_user_config=isolated, - prefix=prefix, - home=home, - use_user_site=use_user_site, - ) - - with indent_log(): - with build_env: - call_subprocess( - args, - cwd=unpacked_source_directory, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/legacy.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/legacy.py deleted file mode 100644 index 4cb24fe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/legacy.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Legacy installation process, i.e. `setup.py install`. -""" - -import logging -import os -import sys -from distutils.util import change_root -from typing import List, Optional, Sequence - -from pip._internal.build_env import BuildEnvironment -from pip._internal.exceptions import InstallationError -from pip._internal.models.scheme import Scheme -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ensure_dir -from pip._internal.utils.setuptools_build import make_setuptools_install_args -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -class LegacyInstallFailure(Exception): - def __init__(self): - # type: () -> None - self.parent = sys.exc_info() - - -def write_installed_files_from_setuptools_record( - record_lines: List[str], - root: Optional[str], - req_description: str, -) -> None: - def prepend_root(path): - # type: (str) -> str - if root is None or not os.path.isabs(path): - return path - else: - return change_root(root, path) - - for line in record_lines: - directory = os.path.dirname(line) - if directory.endswith('.egg-info'): - egg_info_dir = prepend_root(directory) - break - else: - message = ( - "{} did not indicate that it installed an " - ".egg-info directory. Only setup.py projects " - "generating .egg-info directories are supported." - ).format(req_description) - raise InstallationError(message) - - new_lines = [] - for line in record_lines: - filename = line.strip() - if os.path.isdir(filename): - filename += os.path.sep - new_lines.append( - os.path.relpath(prepend_root(filename), egg_info_dir) - ) - new_lines.sort() - ensure_dir(egg_info_dir) - inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') - with open(inst_files_path, 'w') as f: - f.write('\n'.join(new_lines) + '\n') - - -def install( - install_options, # type: List[str] - global_options, # type: Sequence[str] - root, # type: Optional[str] - home, # type: Optional[str] - prefix, # type: Optional[str] - use_user_site, # type: bool - pycompile, # type: bool - scheme, # type: Scheme - setup_py_path, # type: str - isolated, # type: bool - req_name, # type: str - build_env, # type: BuildEnvironment - unpacked_source_directory, # type: str - req_description, # type: str -): - # type: (...) -> bool - - header_dir = scheme.headers - - with TempDirectory(kind="record") as temp_dir: - try: - record_filename = os.path.join(temp_dir.path, 'install-record.txt') - install_args = make_setuptools_install_args( - setup_py_path, - global_options=global_options, - install_options=install_options, - record_filename=record_filename, - root=root, - prefix=prefix, - header_dir=header_dir, - home=home, - use_user_site=use_user_site, - no_user_config=isolated, - pycompile=pycompile, - ) - - runner = runner_with_spinner_message( - f"Running setup.py install for {req_name}" - ) - with indent_log(), build_env: - runner( - cmd=install_args, - cwd=unpacked_source_directory, - ) - - if not os.path.exists(record_filename): - logger.debug('Record file %s not found', record_filename) - # Signal to the caller that we didn't install the new package - return False - - except Exception: - # Signal to the caller that we didn't install the new package - raise LegacyInstallFailure - - # At this point, we have successfully installed the requirement. - - # We intentionally do not use any encoding to read the file because - # setuptools writes the file using distutils.file_util.write_file, - # which does not specify an encoding. - with open(record_filename) as f: - record_lines = f.read().splitlines() - - write_installed_files_from_setuptools_record(record_lines, root, req_description) - return True diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/wheel.py deleted file mode 100644 index b5eafda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/install/wheel.py +++ /dev/null @@ -1,803 +0,0 @@ -"""Support for installing and building the "wheel" binary package format. -""" - -import collections -import compileall -import contextlib -import csv -import importlib -import logging -import os.path -import re -import shutil -import sys -import warnings -from base64 import urlsafe_b64encode -from email.message import Message -from itertools import chain, filterfalse, starmap -from typing import ( - IO, - TYPE_CHECKING, - Any, - BinaryIO, - Callable, - Dict, - Iterable, - Iterator, - List, - NewType, - Optional, - Sequence, - Set, - Tuple, - Union, - cast, -) -from zipfile import ZipFile, ZipInfo - -from pip._vendor.distlib.scripts import ScriptMaker -from pip._vendor.distlib.util import get_export_entry -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.six import ensure_str, ensure_text, reraise - -from pip._internal.exceptions import InstallationError -from pip._internal.locations import get_major_minor_version -from pip._internal.metadata import BaseDistribution, get_wheel_distribution -from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl -from pip._internal.models.scheme import SCHEME_KEYS, Scheme -from pip._internal.utils.filesystem import adjacent_tmp_file, replace -from pip._internal.utils.misc import captured_stdout, ensure_dir, hash_file, partition -from pip._internal.utils.unpacking import ( - current_umask, - is_within_directory, - set_extracted_file_to_default_mode_plus_executable, - zip_item_is_executable, -) -from pip._internal.utils.wheel import parse_wheel - -if TYPE_CHECKING: - from typing import Protocol - - class File(Protocol): - src_record_path = None # type: RecordPath - dest_path = None # type: str - changed = None # type: bool - - def save(self): - # type: () -> None - pass - - -logger = logging.getLogger(__name__) - -RecordPath = NewType('RecordPath', str) -InstalledCSVRow = Tuple[RecordPath, str, Union[int, str]] - - -def rehash(path, blocksize=1 << 20): - # type: (str, int) -> Tuple[str, str] - """Return (encoded_digest, length) for path using hashlib.sha256()""" - h, length = hash_file(path, blocksize) - digest = 'sha256=' + urlsafe_b64encode( - h.digest() - ).decode('latin1').rstrip('=') - return (digest, str(length)) - - -def csv_io_kwargs(mode): - # type: (str) -> Dict[str, Any] - """Return keyword arguments to properly open a CSV file - in the given mode. - """ - return {'mode': mode, 'newline': '', 'encoding': 'utf-8'} - - -def fix_script(path): - # type: (str) -> bool - """Replace #!python with #!/path/to/python - Return True if file was changed. - """ - # XXX RECORD hashes will need to be updated - assert os.path.isfile(path) - - with open(path, 'rb') as script: - firstline = script.readline() - if not firstline.startswith(b'#!python'): - return False - exename = sys.executable.encode(sys.getfilesystemencoding()) - firstline = b'#!' + exename + os.linesep.encode("ascii") - rest = script.read() - with open(path, 'wb') as script: - script.write(firstline) - script.write(rest) - return True - - -def wheel_root_is_purelib(metadata): - # type: (Message) -> bool - return metadata.get("Root-Is-Purelib", "").lower() == "true" - - -def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, str]]: - console_scripts = {} - gui_scripts = {} - for entry_point in dist.iter_entry_points(): - if entry_point.group == "console_scripts": - console_scripts[entry_point.name] = entry_point.value - elif entry_point.group == "gui_scripts": - gui_scripts[entry_point.name] = entry_point.value - return console_scripts, gui_scripts - - -def message_about_scripts_not_on_PATH(scripts): - # type: (Sequence[str]) -> Optional[str] - """Determine if any scripts are not on PATH and format a warning. - Returns a warning message if one or more scripts are not on PATH, - otherwise None. - """ - if not scripts: - return None - - # Group scripts by the path they were installed in - grouped_by_dir = collections.defaultdict(set) # type: Dict[str, Set[str]] - for destfile in scripts: - parent_dir = os.path.dirname(destfile) - script_name = os.path.basename(destfile) - grouped_by_dir[parent_dir].add(script_name) - - # We don't want to warn for directories that are on PATH. - not_warn_dirs = [ - os.path.normcase(i).rstrip(os.sep) for i in - os.environ.get("PATH", "").split(os.pathsep) - ] - # If an executable sits with sys.executable, we don't warn for it. - # This covers the case of venv invocations without activating the venv. - not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) - warn_for = { - parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() - if os.path.normcase(parent_dir) not in not_warn_dirs - } # type: Dict[str, Set[str]] - if not warn_for: - return None - - # Format a message - msg_lines = [] - for parent_dir, dir_scripts in warn_for.items(): - sorted_scripts = sorted(dir_scripts) # type: List[str] - if len(sorted_scripts) == 1: - start_text = "script {} is".format(sorted_scripts[0]) - else: - start_text = "scripts {} are".format( - ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1] - ) - - msg_lines.append( - "The {} installed in '{}' which is not on PATH." - .format(start_text, parent_dir) - ) - - last_line_fmt = ( - "Consider adding {} to PATH or, if you prefer " - "to suppress this warning, use --no-warn-script-location." - ) - if len(msg_lines) == 1: - msg_lines.append(last_line_fmt.format("this directory")) - else: - msg_lines.append(last_line_fmt.format("these directories")) - - # Add a note if any directory starts with ~ - warn_for_tilde = any( - i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i - ) - if warn_for_tilde: - tilde_warning_msg = ( - "NOTE: The current PATH contains path(s) starting with `~`, " - "which may not be expanded by all applications." - ) - msg_lines.append(tilde_warning_msg) - - # Returns the formatted multiline message - return "\n".join(msg_lines) - - -def _normalized_outrows(outrows): - # type: (Iterable[InstalledCSVRow]) -> List[Tuple[str, str, str]] - """Normalize the given rows of a RECORD file. - - Items in each row are converted into str. Rows are then sorted to make - the value more predictable for tests. - - Each row is a 3-tuple (path, hash, size) and corresponds to a record of - a RECORD file (see PEP 376 and PEP 427 for details). For the rows - passed to this function, the size can be an integer as an int or string, - or the empty string. - """ - # Normally, there should only be one row per path, in which case the - # second and third elements don't come into play when sorting. - # However, in cases in the wild where a path might happen to occur twice, - # we don't want the sort operation to trigger an error (but still want - # determinism). Since the third element can be an int or string, we - # coerce each element to a string to avoid a TypeError in this case. - # For additional background, see-- - # https://github.com/pypa/pip/issues/5868 - return sorted( - (ensure_str(record_path, encoding='utf-8'), hash_, str(size)) - for record_path, hash_, size in outrows - ) - - -def _record_to_fs_path(record_path): - # type: (RecordPath) -> str - return record_path - - -def _fs_to_record_path(path, relative_to=None): - # type: (str, Optional[str]) -> RecordPath - if relative_to is not None: - # On Windows, do not handle relative paths if they belong to different - # logical disks - if os.path.splitdrive(path)[0].lower() == \ - os.path.splitdrive(relative_to)[0].lower(): - path = os.path.relpath(path, relative_to) - path = path.replace(os.path.sep, '/') - return cast('RecordPath', path) - - -def _parse_record_path(record_column): - # type: (str) -> RecordPath - p = ensure_text(record_column, encoding='utf-8') - return cast('RecordPath', p) - - -def get_csv_rows_for_installed( - old_csv_rows, # type: List[List[str]] - installed, # type: Dict[RecordPath, RecordPath] - changed, # type: Set[RecordPath] - generated, # type: List[str] - lib_dir, # type: str -): - # type: (...) -> List[InstalledCSVRow] - """ - :param installed: A map from archive RECORD path to installation RECORD - path. - """ - installed_rows = [] # type: List[InstalledCSVRow] - for row in old_csv_rows: - if len(row) > 3: - logger.warning('RECORD line has more than three elements: %s', row) - old_record_path = _parse_record_path(row[0]) - new_record_path = installed.pop(old_record_path, old_record_path) - if new_record_path in changed: - digest, length = rehash(_record_to_fs_path(new_record_path)) - else: - digest = row[1] if len(row) > 1 else '' - length = row[2] if len(row) > 2 else '' - installed_rows.append((new_record_path, digest, length)) - for f in generated: - path = _fs_to_record_path(f, lib_dir) - digest, length = rehash(f) - installed_rows.append((path, digest, length)) - for installed_record_path in installed.values(): - installed_rows.append((installed_record_path, '', '')) - return installed_rows - - -def get_console_script_specs(console): - # type: (Dict[str, str]) -> List[str] - """ - Given the mapping from entrypoint name to callable, return the relevant - console script specs. - """ - # Don't mutate caller's version - console = console.copy() - - scripts_to_generate = [] - - # Special case pip and setuptools to generate versioned wrappers - # - # The issue is that some projects (specifically, pip and setuptools) use - # code in setup.py to create "versioned" entry points - pip2.7 on Python - # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into - # the wheel metadata at build time, and so if the wheel is installed with - # a *different* version of Python the entry points will be wrong. The - # correct fix for this is to enhance the metadata to be able to describe - # such versioned entry points, but that won't happen till Metadata 2.0 is - # available. - # In the meantime, projects using versioned entry points will either have - # incorrect versioned entry points, or they will not be able to distribute - # "universal" wheels (i.e., they will need a wheel per Python version). - # - # Because setuptools and pip are bundled with _ensurepip and virtualenv, - # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we - # override the versioned entry points in the wheel and generate the - # correct ones. This code is purely a short-term measure until Metadata 2.0 - # is available. - # - # To add the level of hack in this section of code, in order to support - # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment - # variable which will control which version scripts get installed. - # - # ENSUREPIP_OPTIONS=altinstall - # - Only pipX.Y and easy_install-X.Y will be generated and installed - # ENSUREPIP_OPTIONS=install - # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note - # that this option is technically if ENSUREPIP_OPTIONS is set and is - # not altinstall - # DEFAULT - # - The default behavior is to install pip, pipX, pipX.Y, easy_install - # and easy_install-X.Y. - pip_script = console.pop('pip', None) - if pip_script: - if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append('pip = ' + pip_script) - - if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": - scripts_to_generate.append( - 'pip{} = {}'.format(sys.version_info[0], pip_script) - ) - - scripts_to_generate.append( - f'pip{get_major_minor_version()} = {pip_script}' - ) - # Delete any other versioned pip entry points - pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] - for k in pip_ep: - del console[k] - easy_install_script = console.pop('easy_install', None) - if easy_install_script: - if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append( - 'easy_install = ' + easy_install_script - ) - - scripts_to_generate.append( - 'easy_install-{} = {}'.format( - get_major_minor_version(), easy_install_script - ) - ) - # Delete any other versioned easy_install entry points - easy_install_ep = [ - k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) - ] - for k in easy_install_ep: - del console[k] - - # Generate the console entry points specified in the wheel - scripts_to_generate.extend(starmap('{} = {}'.format, console.items())) - - return scripts_to_generate - - -class ZipBackedFile: - def __init__(self, src_record_path, dest_path, zip_file): - # type: (RecordPath, str, ZipFile) -> None - self.src_record_path = src_record_path - self.dest_path = dest_path - self._zip_file = zip_file - self.changed = False - - def _getinfo(self): - # type: () -> ZipInfo - return self._zip_file.getinfo(self.src_record_path) - - def save(self): - # type: () -> None - # directory creation is lazy and after file filtering - # to ensure we don't install empty dirs; empty dirs can't be - # uninstalled. - parent_dir = os.path.dirname(self.dest_path) - ensure_dir(parent_dir) - - # When we open the output file below, any existing file is truncated - # before we start writing the new contents. This is fine in most - # cases, but can cause a segfault if pip has loaded a shared - # object (e.g. from pyopenssl through its vendored urllib3) - # Since the shared object is mmap'd an attempt to call a - # symbol in it will then cause a segfault. Unlinking the file - # allows writing of new contents while allowing the process to - # continue to use the old copy. - if os.path.exists(self.dest_path): - os.unlink(self.dest_path) - - zipinfo = self._getinfo() - - with self._zip_file.open(zipinfo) as f: - with open(self.dest_path, "wb") as dest: - shutil.copyfileobj(f, dest) - - if zip_item_is_executable(zipinfo): - set_extracted_file_to_default_mode_plus_executable(self.dest_path) - - -class ScriptFile: - def __init__(self, file): - # type: (File) -> None - self._file = file - self.src_record_path = self._file.src_record_path - self.dest_path = self._file.dest_path - self.changed = False - - def save(self): - # type: () -> None - self._file.save() - self.changed = fix_script(self.dest_path) - - -class MissingCallableSuffix(InstallationError): - def __init__(self, entry_point): - # type: (str) -> None - super().__init__( - "Invalid script entry point: {} - A callable " - "suffix is required. Cf https://packaging.python.org/" - "specifications/entry-points/#use-for-scripts for more " - "information.".format(entry_point) - ) - - -def _raise_for_invalid_entrypoint(specification): - # type: (str) -> None - entry = get_export_entry(specification) - if entry is not None and entry.suffix is None: - raise MissingCallableSuffix(str(entry)) - - -class PipScriptMaker(ScriptMaker): - def make(self, specification, options=None): - # type: (str, Dict[str, Any]) -> List[str] - _raise_for_invalid_entrypoint(specification) - return super().make(specification, options) - - -def _install_wheel( - name, # type: str - wheel_zip, # type: ZipFile - wheel_path, # type: str - scheme, # type: Scheme - pycompile=True, # type: bool - warn_script_location=True, # type: bool - direct_url=None, # type: Optional[DirectUrl] - requested=False, # type: bool -): - # type: (...) -> None - """Install a wheel. - - :param name: Name of the project to install - :param wheel_zip: open ZipFile for wheel being installed - :param scheme: Distutils scheme dictating the install directories - :param req_description: String used in place of the requirement, for - logging - :param pycompile: Whether to byte-compile installed Python files - :param warn_script_location: Whether to check that scripts are installed - into a directory on PATH - :raises UnsupportedWheel: - * when the directory holds an unpacked wheel with incompatible - Wheel-Version - * when the .dist-info dir does not match the wheel - """ - info_dir, metadata = parse_wheel(wheel_zip, name) - - if wheel_root_is_purelib(metadata): - lib_dir = scheme.purelib - else: - lib_dir = scheme.platlib - - # Record details of the files moved - # installed = files copied from the wheel to the destination - # changed = files changed while installing (scripts #! line typically) - # generated = files newly generated during the install (script wrappers) - installed = {} # type: Dict[RecordPath, RecordPath] - changed = set() # type: Set[RecordPath] - generated = [] # type: List[str] - - def record_installed(srcfile, destfile, modified=False): - # type: (RecordPath, str, bool) -> None - """Map archive RECORD paths to installation RECORD paths.""" - newpath = _fs_to_record_path(destfile, lib_dir) - installed[srcfile] = newpath - if modified: - changed.add(_fs_to_record_path(destfile)) - - def all_paths(): - # type: () -> Iterable[RecordPath] - names = wheel_zip.namelist() - # If a flag is set, names may be unicode in Python 2. We convert to - # text explicitly so these are valid for lookup in RECORD. - decoded_names = map(ensure_text, names) - for name in decoded_names: - yield cast("RecordPath", name) - - def is_dir_path(path): - # type: (RecordPath) -> bool - return path.endswith("/") - - def assert_no_path_traversal(dest_dir_path, target_path): - # type: (str, str) -> None - if not is_within_directory(dest_dir_path, target_path): - message = ( - "The wheel {!r} has a file {!r} trying to install" - " outside the target directory {!r}" - ) - raise InstallationError( - message.format(wheel_path, target_path, dest_dir_path) - ) - - def root_scheme_file_maker(zip_file, dest): - # type: (ZipFile, str) -> Callable[[RecordPath], File] - def make_root_scheme_file(record_path): - # type: (RecordPath) -> File - normed_path = os.path.normpath(record_path) - dest_path = os.path.join(dest, normed_path) - assert_no_path_traversal(dest, dest_path) - return ZipBackedFile(record_path, dest_path, zip_file) - - return make_root_scheme_file - - def data_scheme_file_maker(zip_file, scheme): - # type: (ZipFile, Scheme) -> Callable[[RecordPath], File] - scheme_paths = {} - for key in SCHEME_KEYS: - encoded_key = ensure_text(key) - scheme_paths[encoded_key] = ensure_text( - getattr(scheme, key), encoding=sys.getfilesystemencoding() - ) - - def make_data_scheme_file(record_path): - # type: (RecordPath) -> File - normed_path = os.path.normpath(record_path) - try: - _, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2) - except ValueError: - message = ( - "Unexpected file in {}: {!r}. .data directory contents" - " should be named like: '/'." - ).format(wheel_path, record_path) - raise InstallationError(message) - - try: - scheme_path = scheme_paths[scheme_key] - except KeyError: - valid_scheme_keys = ", ".join(sorted(scheme_paths)) - message = ( - "Unknown scheme key used in {}: {} (for file {!r}). .data" - " directory contents should be in subdirectories named" - " with a valid scheme key ({})" - ).format( - wheel_path, scheme_key, record_path, valid_scheme_keys - ) - raise InstallationError(message) - - dest_path = os.path.join(scheme_path, dest_subpath) - assert_no_path_traversal(scheme_path, dest_path) - return ZipBackedFile(record_path, dest_path, zip_file) - - return make_data_scheme_file - - def is_data_scheme_path(path): - # type: (RecordPath) -> bool - return path.split("/", 1)[0].endswith(".data") - - paths = all_paths() - file_paths = filterfalse(is_dir_path, paths) - root_scheme_paths, data_scheme_paths = partition( - is_data_scheme_path, file_paths - ) - - make_root_scheme_file = root_scheme_file_maker( - wheel_zip, - ensure_text(lib_dir, encoding=sys.getfilesystemencoding()), - ) - files = map(make_root_scheme_file, root_scheme_paths) - - def is_script_scheme_path(path): - # type: (RecordPath) -> bool - parts = path.split("/", 2) - return ( - len(parts) > 2 and - parts[0].endswith(".data") and - parts[1] == "scripts" - ) - - other_scheme_paths, script_scheme_paths = partition( - is_script_scheme_path, data_scheme_paths - ) - - make_data_scheme_file = data_scheme_file_maker(wheel_zip, scheme) - other_scheme_files = map(make_data_scheme_file, other_scheme_paths) - files = chain(files, other_scheme_files) - - # Get the defined entry points - distribution = get_wheel_distribution(wheel_path, canonicalize_name(name)) - console, gui = get_entrypoints(distribution) - - def is_entrypoint_wrapper(file): - # type: (File) -> bool - # EP, EP.exe and EP-script.py are scripts generated for - # entry point EP by setuptools - path = file.dest_path - name = os.path.basename(path) - if name.lower().endswith('.exe'): - matchname = name[:-4] - elif name.lower().endswith('-script.py'): - matchname = name[:-10] - elif name.lower().endswith(".pya"): - matchname = name[:-4] - else: - matchname = name - # Ignore setuptools-generated scripts - return (matchname in console or matchname in gui) - - script_scheme_files = map(make_data_scheme_file, script_scheme_paths) - script_scheme_files = filterfalse( - is_entrypoint_wrapper, script_scheme_files - ) - script_scheme_files = map(ScriptFile, script_scheme_files) - files = chain(files, script_scheme_files) - - for file in files: - file.save() - record_installed(file.src_record_path, file.dest_path, file.changed) - - def pyc_source_file_paths(): - # type: () -> Iterator[str] - # We de-duplicate installation paths, since there can be overlap (e.g. - # file in .data maps to same location as file in wheel root). - # Sorting installation paths makes it easier to reproduce and debug - # issues related to permissions on existing files. - for installed_path in sorted(set(installed.values())): - full_installed_path = os.path.join(lib_dir, installed_path) - if not os.path.isfile(full_installed_path): - continue - if not full_installed_path.endswith('.py'): - continue - yield full_installed_path - - def pyc_output_path(path): - # type: (str) -> str - """Return the path the pyc file would have been written to. - """ - return importlib.util.cache_from_source(path) - - # Compile all of the pyc files for the installed files - if pycompile: - with captured_stdout() as stdout: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore') - for path in pyc_source_file_paths(): - # Python 2's `compileall.compile_file` requires a str in - # error cases, so we must convert to the native type. - path_arg = ensure_str( - path, encoding=sys.getfilesystemencoding() - ) - success = compileall.compile_file( - path_arg, force=True, quiet=True - ) - if success: - pyc_path = pyc_output_path(path) - assert os.path.exists(pyc_path) - pyc_record_path = cast( - "RecordPath", pyc_path.replace(os.path.sep, "/") - ) - record_installed(pyc_record_path, pyc_path) - logger.debug(stdout.getvalue()) - - maker = PipScriptMaker(None, scheme.scripts) - - # Ensure old scripts are overwritten. - # See https://github.com/pypa/pip/issues/1800 - maker.clobber = True - - # Ensure we don't generate any variants for scripts because this is almost - # never what somebody wants. - # See https://bitbucket.org/pypa/distlib/issue/35/ - maker.variants = {''} - - # This is required because otherwise distlib creates scripts that are not - # executable. - # See https://bitbucket.org/pypa/distlib/issue/32/ - maker.set_mode = True - - # Generate the console and GUI entry points specified in the wheel - scripts_to_generate = get_console_script_specs(console) - - gui_scripts_to_generate = list(starmap('{} = {}'.format, gui.items())) - - generated_console_scripts = maker.make_multiple(scripts_to_generate) - generated.extend(generated_console_scripts) - - generated.extend( - maker.make_multiple(gui_scripts_to_generate, {'gui': True}) - ) - - if warn_script_location: - msg = message_about_scripts_not_on_PATH(generated_console_scripts) - if msg is not None: - logger.warning(msg) - - generated_file_mode = 0o666 & ~current_umask() - - @contextlib.contextmanager - def _generate_file(path, **kwargs): - # type: (str, **Any) -> Iterator[BinaryIO] - with adjacent_tmp_file(path, **kwargs) as f: - yield f - os.chmod(f.name, generated_file_mode) - replace(f.name, path) - - dest_info_dir = os.path.join(lib_dir, info_dir) - - # Record pip as the installer - installer_path = os.path.join(dest_info_dir, 'INSTALLER') - with _generate_file(installer_path) as installer_file: - installer_file.write(b'pip\n') - generated.append(installer_path) - - # Record the PEP 610 direct URL reference - if direct_url is not None: - direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME) - with _generate_file(direct_url_path) as direct_url_file: - direct_url_file.write(direct_url.to_json().encode("utf-8")) - generated.append(direct_url_path) - - # Record the REQUESTED file - if requested: - requested_path = os.path.join(dest_info_dir, 'REQUESTED') - with open(requested_path, "wb"): - pass - generated.append(requested_path) - - record_text = distribution.read_text('RECORD') - record_rows = list(csv.reader(record_text.splitlines())) - - rows = get_csv_rows_for_installed( - record_rows, - installed=installed, - changed=changed, - generated=generated, - lib_dir=lib_dir) - - # Record details of all files installed - record_path = os.path.join(dest_info_dir, 'RECORD') - - with _generate_file(record_path, **csv_io_kwargs('w')) as record_file: - # The type mypy infers for record_file is different for Python 3 - # (typing.IO[Any]) and Python 2 (typing.BinaryIO). We explicitly - # cast to typing.IO[str] as a workaround. - writer = csv.writer(cast('IO[str]', record_file)) - writer.writerows(_normalized_outrows(rows)) - - -@contextlib.contextmanager -def req_error_context(req_description): - # type: (str) -> Iterator[None] - try: - yield - except InstallationError as e: - message = "For req: {}. {}".format(req_description, e.args[0]) - reraise( - InstallationError, InstallationError(message), sys.exc_info()[2] - ) - - -def install_wheel( - name, # type: str - wheel_path, # type: str - scheme, # type: Scheme - req_description, # type: str - pycompile=True, # type: bool - warn_script_location=True, # type: bool - direct_url=None, # type: Optional[DirectUrl] - requested=False, # type: bool -): - # type: (...) -> None - with ZipFile(wheel_path, allowZip64=True) as z: - with req_error_context(req_description): - _install_wheel( - name=name, - wheel_zip=z, - wheel_path=wheel_path, - scheme=scheme, - pycompile=pycompile, - warn_script_location=warn_script_location, - direct_url=direct_url, - requested=requested, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/prepare.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/prepare.py deleted file mode 100644 index 247e63f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/operations/prepare.py +++ /dev/null @@ -1,655 +0,0 @@ -"""Prepares a distribution for installation -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import mimetypes -import os -import shutil -from typing import Dict, Iterable, List, Optional, Tuple - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.pkg_resources import Distribution - -from pip._internal.distributions import make_distribution_for_install_requirement -from pip._internal.distributions.installed import InstalledDistribution -from pip._internal.exceptions import ( - DirectoryUrlHashUnsupported, - HashMismatch, - HashUnpinned, - InstallationError, - NetworkConnectionError, - PreviousBuildDirError, - VcsHashUnsupported, -) -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.network.download import BatchDownloader, Downloader -from pip._internal.network.lazy_wheel import ( - HTTPRangeRequestUnsupported, - dist_from_wheel_url, -) -from pip._internal.network.session import PipSession -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_tracker import RequirementTracker -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.filesystem import copy2_fixed -from pip._internal.utils.hashes import Hashes, MissingHashes -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import display_path, hide_url, is_installable_dir, rmtree -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.unpacking import unpack_file -from pip._internal.vcs import vcs - -logger = logging.getLogger(__name__) - - -def _get_prepared_distribution( - req, # type: InstallRequirement - req_tracker, # type: RequirementTracker - finder, # type: PackageFinder - build_isolation, # type: bool -): - # type: (...) -> Distribution - """Prepare a distribution for installation.""" - abstract_dist = make_distribution_for_install_requirement(req) - with req_tracker.track(req): - abstract_dist.prepare_distribution_metadata(finder, build_isolation) - return abstract_dist.get_pkg_resources_distribution() - - -def unpack_vcs_link(link, location): - # type: (Link, str) -> None - vcs_backend = vcs.get_backend_for_scheme(link.scheme) - assert vcs_backend is not None - vcs_backend.unpack(location, url=hide_url(link.url)) - - -class File: - - def __init__(self, path, content_type): - # type: (str, Optional[str]) -> None - self.path = path - if content_type is None: - self.content_type = mimetypes.guess_type(path)[0] - else: - self.content_type = content_type - - -def get_http_url( - link, # type: Link - download, # type: Downloader - download_dir=None, # type: Optional[str] - hashes=None, # type: Optional[Hashes] -): - # type: (...) -> File - temp_dir = TempDirectory(kind="unpack", globally_managed=True) - # If a download dir is specified, is the file already downloaded there? - already_downloaded_path = None - if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) - - if already_downloaded_path: - from_path = already_downloaded_path - content_type = None - else: - # let's download to a tmp dir - from_path, content_type = download(link, temp_dir.path) - if hashes: - hashes.check_against_path(from_path) - - return File(from_path, content_type) - - -def _copy2_ignoring_special_files(src, dest): - # type: (str, str) -> None - """Copying special files is not supported, but as a convenience to users - we skip errors copying them. This supports tools that may create e.g. - socket files in the project source directory. - """ - try: - copy2_fixed(src, dest) - except shutil.SpecialFileError as e: - # SpecialFileError may be raised due to either the source or - # destination. If the destination was the cause then we would actually - # care, but since the destination directory is deleted prior to - # copy we ignore all of them assuming it is caused by the source. - logger.warning( - "Ignoring special file error '%s' encountered copying %s to %s.", - str(e), - src, - dest, - ) - - -def _copy_source_tree(source, target): - # type: (str, str) -> None - target_abspath = os.path.abspath(target) - target_basename = os.path.basename(target_abspath) - target_dirname = os.path.dirname(target_abspath) - - def ignore(d, names): - # type: (str, List[str]) -> List[str] - skipped = [] # type: List[str] - if d == source: - # Pulling in those directories can potentially be very slow, - # exclude the following directories if they appear in the top - # level dir (and only it). - # See discussion at https://github.com/pypa/pip/pull/6770 - skipped += ['.tox', '.nox'] - if os.path.abspath(d) == target_dirname: - # Prevent an infinite recursion if the target is in source. - # This can happen when TMPDIR is set to ${PWD}/... - # and we copy PWD to TMPDIR. - skipped += [target_basename] - return skipped - - shutil.copytree( - source, - target, - ignore=ignore, - symlinks=True, - copy_function=_copy2_ignoring_special_files, - ) - - -def get_file_url( - link, # type: Link - download_dir=None, # type: Optional[str] - hashes=None # type: Optional[Hashes] -): - # type: (...) -> File - """Get file and optionally check its hash. - """ - # If a download dir is specified, is the file already there and valid? - already_downloaded_path = None - if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) - - if already_downloaded_path: - from_path = already_downloaded_path - else: - from_path = link.file_path - - # If --require-hashes is off, `hashes` is either empty, the - # link's embedded hash, or MissingHashes; it is required to - # match. If --require-hashes is on, we are satisfied by any - # hash in `hashes` matching: a URL-based or an option-based - # one; no internet-sourced hash will be in `hashes`. - if hashes: - hashes.check_against_path(from_path) - return File(from_path, None) - - -def unpack_url( - link, # type: Link - location, # type: str - download, # type: Downloader - download_dir=None, # type: Optional[str] - hashes=None, # type: Optional[Hashes] -): - # type: (...) -> Optional[File] - """Unpack link into location, downloading if required. - - :param hashes: A Hashes object, one of whose embedded hashes must match, - or HashMismatch will be raised. If the Hashes is empty, no matches are - required, and unhashable types of requirements (like VCS ones, which - would ordinarily raise HashUnsupported) are allowed. - """ - # non-editable vcs urls - if link.is_vcs: - unpack_vcs_link(link, location) - return None - - # Once out-of-tree-builds are no longer supported, could potentially - # replace the below condition with `assert not link.is_existing_dir` - # - unpack_url does not need to be called for in-tree-builds. - # - # As further cleanup, _copy_source_tree and accompanying tests can - # be removed. - if link.is_existing_dir(): - deprecated( - "A future pip version will change local packages to be built " - "in-place without first copying to a temporary directory. " - "We recommend you use --use-feature=in-tree-build to test " - "your packages with this new behavior before it becomes the " - "default.\n", - replacement=None, - gone_in="21.3", - issue=7555 - ) - if os.path.isdir(location): - rmtree(location) - _copy_source_tree(link.file_path, location) - return None - - # file urls - if link.is_file: - file = get_file_url(link, download_dir, hashes=hashes) - - # http urls - else: - file = get_http_url( - link, - download, - download_dir, - hashes=hashes, - ) - - # unpack the archive to the build dir location. even when only downloading - # archives, they have to be unpacked to parse dependencies, except wheels - if not link.is_wheel: - unpack_file(file.path, location, file.content_type) - - return file - - -def _check_download_dir(link, download_dir, hashes): - # type: (Link, str, Optional[Hashes]) -> Optional[str] - """ Check download_dir for previously downloaded file with correct hash - If a correct file is found return its path else None - """ - download_path = os.path.join(download_dir, link.filename) - - if not os.path.exists(download_path): - return None - - # If already downloaded, does its hash match? - logger.info('File was already downloaded %s', download_path) - if hashes: - try: - hashes.check_against_path(download_path) - except HashMismatch: - logger.warning( - 'Previously-downloaded file %s has bad hash. ' - 'Re-downloading.', - download_path - ) - os.unlink(download_path) - return None - return download_path - - -class RequirementPreparer: - """Prepares a Requirement - """ - - def __init__( - self, - build_dir, # type: str - download_dir, # type: Optional[str] - src_dir, # type: str - build_isolation, # type: bool - req_tracker, # type: RequirementTracker - session, # type: PipSession - progress_bar, # type: str - finder, # type: PackageFinder - require_hashes, # type: bool - use_user_site, # type: bool - lazy_wheel, # type: bool - in_tree_build, # type: bool - ): - # type: (...) -> None - super().__init__() - - self.src_dir = src_dir - self.build_dir = build_dir - self.req_tracker = req_tracker - self._session = session - self._download = Downloader(session, progress_bar) - self._batch_download = BatchDownloader(session, progress_bar) - self.finder = finder - - # Where still-packed archives should be written to. If None, they are - # not saved, and are deleted immediately after unpacking. - self.download_dir = download_dir - - # Is build isolation allowed? - self.build_isolation = build_isolation - - # Should hash-checking be required? - self.require_hashes = require_hashes - - # Should install in user site-packages? - self.use_user_site = use_user_site - - # Should wheels be downloaded lazily? - self.use_lazy_wheel = lazy_wheel - - # Should in-tree builds be used for local paths? - self.in_tree_build = in_tree_build - - # Memoized downloaded files, as mapping of url: (path, mime type) - self._downloaded = {} # type: Dict[str, Tuple[str, str]] - - # Previous "header" printed for a link-based InstallRequirement - self._previous_requirement_header = ("", "") - - def _log_preparing_link(self, req): - # type: (InstallRequirement) -> None - """Provide context for the requirement being prepared.""" - if req.link.is_file and not req.original_link_is_in_wheel_cache: - message = "Processing %s" - information = str(display_path(req.link.file_path)) - else: - message = "Collecting %s" - information = str(req.req or req) - - if (message, information) != self._previous_requirement_header: - self._previous_requirement_header = (message, information) - logger.info(message, information) - - if req.original_link_is_in_wheel_cache: - with indent_log(): - logger.info("Using cached %s", req.link.filename) - - def _ensure_link_req_src_dir(self, req, parallel_builds): - # type: (InstallRequirement, bool) -> None - """Ensure source_dir of a linked InstallRequirement.""" - # Since source_dir is only set for editable requirements. - if req.link.is_wheel: - # We don't need to unpack wheels, so no need for a source - # directory. - return - assert req.source_dir is None - if req.link.is_existing_dir() and self.in_tree_build: - # build local directories in-tree - req.source_dir = req.link.file_path - return - - # We always delete unpacked sdists after pip runs. - req.ensure_has_source_dir( - self.build_dir, - autodelete=True, - parallel_builds=parallel_builds, - ) - - # If a checkout exists, it's unwise to keep going. version - # inconsistencies are logged later, but do not fail the - # installation. - # FIXME: this won't upgrade when there's an existing - # package unpacked in `req.source_dir` - if is_installable_dir(req.source_dir): - raise PreviousBuildDirError( - "pip can't proceed with requirements '{}' due to a" - "pre-existing build directory ({}). This is likely " - "due to a previous installation that failed . pip is " - "being responsible and not assuming it can delete this. " - "Please delete it and try again.".format(req, req.source_dir) - ) - - def _get_linked_req_hashes(self, req): - # type: (InstallRequirement) -> Hashes - # By the time this is called, the requirement's link should have - # been checked so we can tell what kind of requirements req is - # and raise some more informative errors than otherwise. - # (For example, we can raise VcsHashUnsupported for a VCS URL - # rather than HashMissing.) - if not self.require_hashes: - return req.hashes(trust_internet=True) - - # We could check these first 2 conditions inside unpack_url - # and save repetition of conditions, but then we would - # report less-useful error messages for unhashable - # requirements, complaining that there's no hash provided. - if req.link.is_vcs: - raise VcsHashUnsupported() - if req.link.is_existing_dir(): - raise DirectoryUrlHashUnsupported() - - # Unpinned packages are asking for trouble when a new version - # is uploaded. This isn't a security check, but it saves users - # a surprising hash mismatch in the future. - # file:/// URLs aren't pinnable, so don't complain about them - # not being pinned. - if req.original_link is None and not req.is_pinned: - raise HashUnpinned() - - # If known-good hashes are missing for this requirement, - # shim it with a facade object that will provoke hash - # computation and then raise a HashMissing exception - # showing the user what the hash should be. - return req.hashes(trust_internet=False) or MissingHashes() - - def _fetch_metadata_using_lazy_wheel(self, link): - # type: (Link) -> Optional[Distribution] - """Fetch metadata using lazy wheel, if possible.""" - if not self.use_lazy_wheel: - return None - if self.require_hashes: - logger.debug('Lazy wheel is not used as hash checking is required') - return None - if link.is_file or not link.is_wheel: - logger.debug( - 'Lazy wheel is not used as ' - '%r does not points to a remote wheel', - link, - ) - return None - - wheel = Wheel(link.filename) - name = canonicalize_name(wheel.name) - logger.info( - 'Obtaining dependency information from %s %s', - name, wheel.version, - ) - url = link.url.split('#', 1)[0] - try: - return dist_from_wheel_url(name, url, self._session) - except HTTPRangeRequestUnsupported: - logger.debug('%s does not support range requests', url) - return None - - def _complete_partial_requirements( - self, - partially_downloaded_reqs, # type: Iterable[InstallRequirement] - parallel_builds=False, # type: bool - ): - # type: (...) -> None - """Download any requirements which were only fetched by metadata.""" - # Download to a temporary directory. These will be copied over as - # needed for downstream 'download', 'wheel', and 'install' commands. - temp_dir = TempDirectory(kind="unpack", globally_managed=True).path - - # Map each link to the requirement that owns it. This allows us to set - # `req.local_file_path` on the appropriate requirement after passing - # all the links at once into BatchDownloader. - links_to_fully_download = {} # type: Dict[Link, InstallRequirement] - for req in partially_downloaded_reqs: - assert req.link - links_to_fully_download[req.link] = req - - batch_download = self._batch_download( - links_to_fully_download.keys(), - temp_dir, - ) - for link, (filepath, _) in batch_download: - logger.debug("Downloading link %s to %s", link, filepath) - req = links_to_fully_download[link] - req.local_file_path = filepath - - # This step is necessary to ensure all lazy wheels are processed - # successfully by the 'download', 'wheel', and 'install' commands. - for req in partially_downloaded_reqs: - self._prepare_linked_requirement(req, parallel_builds) - - def prepare_linked_requirement(self, req, parallel_builds=False): - # type: (InstallRequirement, bool) -> Distribution - """Prepare a requirement to be obtained from req.link.""" - assert req.link - link = req.link - self._log_preparing_link(req) - with indent_log(): - # Check if the relevant file is already available - # in the download directory - file_path = None - if self.download_dir is not None and link.is_wheel: - hashes = self._get_linked_req_hashes(req) - file_path = _check_download_dir(req.link, self.download_dir, hashes) - - if file_path is not None: - # The file is already available, so mark it as downloaded - self._downloaded[req.link.url] = file_path, None - else: - # The file is not available, attempt to fetch only metadata - wheel_dist = self._fetch_metadata_using_lazy_wheel(link) - if wheel_dist is not None: - req.needs_more_preparation = True - return wheel_dist - - # None of the optimizations worked, fully prepare the requirement - return self._prepare_linked_requirement(req, parallel_builds) - - def prepare_linked_requirements_more(self, reqs, parallel_builds=False): - # type: (Iterable[InstallRequirement], bool) -> None - """Prepare linked requirements more, if needed.""" - reqs = [req for req in reqs if req.needs_more_preparation] - for req in reqs: - # Determine if any of these requirements were already downloaded. - if self.download_dir is not None and req.link.is_wheel: - hashes = self._get_linked_req_hashes(req) - file_path = _check_download_dir(req.link, self.download_dir, hashes) - if file_path is not None: - self._downloaded[req.link.url] = file_path, None - req.needs_more_preparation = False - - # Prepare requirements we found were already downloaded for some - # reason. The other downloads will be completed separately. - partially_downloaded_reqs = [] # type: List[InstallRequirement] - for req in reqs: - if req.needs_more_preparation: - partially_downloaded_reqs.append(req) - else: - self._prepare_linked_requirement(req, parallel_builds) - - # TODO: separate this part out from RequirementPreparer when the v1 - # resolver can be removed! - self._complete_partial_requirements( - partially_downloaded_reqs, parallel_builds=parallel_builds, - ) - - def _prepare_linked_requirement(self, req, parallel_builds): - # type: (InstallRequirement, bool) -> Distribution - assert req.link - link = req.link - - self._ensure_link_req_src_dir(req, parallel_builds) - hashes = self._get_linked_req_hashes(req) - - if link.is_existing_dir() and self.in_tree_build: - local_file = None - elif link.url not in self._downloaded: - try: - local_file = unpack_url( - link, req.source_dir, self._download, - self.download_dir, hashes - ) - except NetworkConnectionError as exc: - raise InstallationError( - 'Could not install requirement {} because of HTTP ' - 'error {} for URL {}'.format(req, exc, link) - ) - else: - file_path, content_type = self._downloaded[link.url] - if hashes: - hashes.check_against_path(file_path) - local_file = File(file_path, content_type) - - # For use in later processing, - # preserve the file path on the requirement. - if local_file: - req.local_file_path = local_file.path - - dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, - ) - return dist - - def save_linked_requirement(self, req): - # type: (InstallRequirement) -> None - assert self.download_dir is not None - assert req.link is not None - link = req.link - if link.is_vcs or (link.is_existing_dir() and req.editable): - # Make a .zip of the source_dir we already created. - req.archive(self.download_dir) - return - - if link.is_existing_dir(): - logger.debug( - 'Not copying link to destination directory ' - 'since it is a directory: %s', link, - ) - return - if req.local_file_path is None: - # No distribution was downloaded for this requirement. - return - - download_location = os.path.join(self.download_dir, link.filename) - if not os.path.exists(download_location): - shutil.copy(req.local_file_path, download_location) - download_path = display_path(download_location) - logger.info('Saved %s', download_path) - - def prepare_editable_requirement( - self, - req, # type: InstallRequirement - ): - # type: (...) -> Distribution - """Prepare an editable requirement - """ - assert req.editable, "cannot prepare a non-editable req as editable" - - logger.info('Obtaining %s', req) - - with indent_log(): - if self.require_hashes: - raise InstallationError( - 'The editable requirement {} cannot be installed when ' - 'requiring hashes, because there is no single file to ' - 'hash.'.format(req) - ) - req.ensure_has_source_dir(self.src_dir) - req.update_editable() - - dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, - ) - - req.check_if_exists(self.use_user_site) - - return dist - - def prepare_installed_requirement( - self, - req, # type: InstallRequirement - skip_reason # type: str - ): - # type: (...) -> Distribution - """Prepare an already-installed requirement - """ - assert req.satisfied_by, "req should have been satisfied but isn't" - assert skip_reason is not None, ( - "did not get skip reason skipped but req.satisfied_by " - "is set to {}".format(req.satisfied_by) - ) - logger.info( - 'Requirement %s: %s (%s)', - skip_reason, req, req.satisfied_by.version - ) - with indent_log(): - if self.require_hashes: - logger.debug( - 'Since it is already installed, we are trusting this ' - 'package without checking its hash. To ensure a ' - 'completely repeatable environment, install into an ' - 'empty virtualenv.' - ) - return InstalledDistribution(req).get_pkg_resources_distribution() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/pyproject.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/pyproject.py deleted file mode 100644 index 5aa6160..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/pyproject.py +++ /dev/null @@ -1,183 +0,0 @@ -import os -from collections import namedtuple -from typing import Any, List, Optional - -from pip._vendor import tomli -from pip._vendor.packaging.requirements import InvalidRequirement, Requirement - -from pip._internal.exceptions import InstallationError - - -def _is_list_of_str(obj): - # type: (Any) -> bool - return ( - isinstance(obj, list) and - all(isinstance(item, str) for item in obj) - ) - - -def make_pyproject_path(unpacked_source_directory): - # type: (str) -> str - return os.path.join(unpacked_source_directory, 'pyproject.toml') - - -BuildSystemDetails = namedtuple('BuildSystemDetails', [ - 'requires', 'backend', 'check', 'backend_path' -]) - - -def load_pyproject_toml( - use_pep517, # type: Optional[bool] - pyproject_toml, # type: str - setup_py, # type: str - req_name # type: str -): - # type: (...) -> Optional[BuildSystemDetails] - """Load the pyproject.toml file. - - Parameters: - use_pep517 - Has the user requested PEP 517 processing? None - means the user hasn't explicitly specified. - pyproject_toml - Location of the project's pyproject.toml file - setup_py - Location of the project's setup.py file - req_name - The name of the requirement we're processing (for - error reporting) - - Returns: - None if we should use the legacy code path, otherwise a tuple - ( - requirements from pyproject.toml, - name of PEP 517 backend, - requirements we should check are installed after setting - up the build environment - directory paths to import the backend from (backend-path), - relative to the project root. - ) - """ - has_pyproject = os.path.isfile(pyproject_toml) - has_setup = os.path.isfile(setup_py) - - if has_pyproject: - with open(pyproject_toml, encoding="utf-8") as f: - pp_toml = tomli.load(f) - build_system = pp_toml.get("build-system") - else: - build_system = None - - # The following cases must use PEP 517 - # We check for use_pep517 being non-None and falsey because that means - # the user explicitly requested --no-use-pep517. The value 0 as - # opposed to False can occur when the value is provided via an - # environment variable or config file option (due to the quirk of - # strtobool() returning an integer in pip's configuration code). - if has_pyproject and not has_setup: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project does not have a setup.py" - ) - use_pep517 = True - elif build_system and "build-backend" in build_system: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project specifies a build backend of {} " - "in pyproject.toml".format( - build_system["build-backend"] - ) - ) - use_pep517 = True - - # If we haven't worked out whether to use PEP 517 yet, - # and the user hasn't explicitly stated a preference, - # we do so if the project has a pyproject.toml file. - elif use_pep517 is None: - use_pep517 = has_pyproject - - # At this point, we know whether we're going to use PEP 517. - assert use_pep517 is not None - - # If we're using the legacy code path, there is nothing further - # for us to do here. - if not use_pep517: - return None - - if build_system is None: - # Either the user has a pyproject.toml with no build-system - # section, or the user has no pyproject.toml, but has opted in - # explicitly via --use-pep517. - # In the absence of any explicit backend specification, we - # assume the setuptools backend that most closely emulates the - # traditional direct setup.py execution, and require wheel and - # a version of setuptools that supports that backend. - - build_system = { - "requires": ["setuptools>=40.8.0", "wheel"], - "build-backend": "setuptools.build_meta:__legacy__", - } - - # If we're using PEP 517, we have build system information (either - # from pyproject.toml, or defaulted by the code above). - # Note that at this point, we do not know if the user has actually - # specified a backend, though. - assert build_system is not None - - # Ensure that the build-system section in pyproject.toml conforms - # to PEP 518. - error_template = ( - "{package} has a pyproject.toml file that does not comply " - "with PEP 518: {reason}" - ) - - # Specifying the build-system table but not the requires key is invalid - if "requires" not in build_system: - raise InstallationError( - error_template.format(package=req_name, reason=( - "it has a 'build-system' table but not " - "'build-system.requires' which is mandatory in the table" - )) - ) - - # Error out if requires is not a list of strings - requires = build_system["requires"] - if not _is_list_of_str(requires): - raise InstallationError(error_template.format( - package=req_name, - reason="'build-system.requires' is not a list of strings.", - )) - - # Each requirement must be valid as per PEP 508 - for requirement in requires: - try: - Requirement(requirement) - except InvalidRequirement: - raise InstallationError( - error_template.format( - package=req_name, - reason=( - "'build-system.requires' contains an invalid " - "requirement: {!r}".format(requirement) - ), - ) - ) - - backend = build_system.get("build-backend") - backend_path = build_system.get("backend-path", []) - check = [] # type: List[str] - if backend is None: - # If the user didn't specify a backend, we assume they want to use - # the setuptools backend. But we can't be sure they have included - # a version of setuptools which supplies the backend, or wheel - # (which is needed by the backend) in their requirements. So we - # make a note to check that those requirements are present once - # we have set up the environment. - # This is quite a lot of work to check for a very specific case. But - # the problem is, that case is potentially quite common - projects that - # adopted PEP 518 early for the ability to specify requirements to - # execute setup.py, but never considered needing to mention the build - # tools themselves. The original PEP 518 code had a similar check (but - # implemented in a different way). - backend = "setuptools.build_meta:__legacy__" - check = ["setuptools>=40.8.0", "wheel"] - - return BuildSystemDetails(requires, backend, check, backend_path) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/__init__.py deleted file mode 100644 index aaea748..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -import collections -import logging -from typing import Iterator, List, Optional, Sequence, Tuple - -from pip._internal.utils.logging import indent_log - -from .req_file import parse_requirements -from .req_install import InstallRequirement -from .req_set import RequirementSet - -__all__ = [ - "RequirementSet", "InstallRequirement", - "parse_requirements", "install_given_reqs", -] - -logger = logging.getLogger(__name__) - - -class InstallationResult: - def __init__(self, name: str) -> None: - self.name = name - - def __repr__(self) -> str: - return f"InstallationResult(name={self.name!r})" - - -def _validate_requirements( - requirements: List[InstallRequirement], -) -> Iterator[Tuple[str, InstallRequirement]]: - for req in requirements: - assert req.name, f"invalid to-be-installed requirement: {req}" - yield req.name, req - - -def install_given_reqs( - requirements: List[InstallRequirement], - install_options: List[str], - global_options: Sequence[str], - root: Optional[str], - home: Optional[str], - prefix: Optional[str], - warn_script_location: bool, - use_user_site: bool, - pycompile: bool, -) -> List[InstallationResult]: - """ - Install everything in the given list. - - (to be called after having downloaded and unpacked the packages) - """ - to_install = collections.OrderedDict(_validate_requirements(requirements)) - - if to_install: - logger.info( - 'Installing collected packages: %s', - ', '.join(to_install.keys()), - ) - - installed = [] - - with indent_log(): - for req_name, requirement in to_install.items(): - if requirement.should_reinstall: - logger.info('Attempting uninstall: %s', req_name) - with indent_log(): - uninstalled_pathset = requirement.uninstall( - auto_confirm=True - ) - else: - uninstalled_pathset = None - - try: - requirement.install( - install_options, - global_options, - root=root, - home=home, - prefix=prefix, - warn_script_location=warn_script_location, - use_user_site=use_user_site, - pycompile=pycompile, - ) - except Exception: - # if install did not succeed, rollback previous uninstall - if uninstalled_pathset and not requirement.install_succeeded: - uninstalled_pathset.rollback() - raise - else: - if uninstalled_pathset and requirement.install_succeeded: - uninstalled_pathset.commit() - - installed.append(InstallationResult(req_name)) - - return installed diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/constructors.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/constructors.py deleted file mode 100644 index d0f5b42..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/constructors.py +++ /dev/null @@ -1,474 +0,0 @@ -"""Backing implementation for InstallRequirement's various constructors - -The idea here is that these formed a major chunk of InstallRequirement's size -so, moving them and support code dedicated to them outside of that class -helps creates for better understandability for the rest of the code. - -These are meant to be used elsewhere within pip to create instances of -InstallRequirement. -""" - -import logging -import os -import re -from typing import Any, Dict, Optional, Set, Tuple, Union - -from pip._vendor.packaging.markers import Marker -from pip._vendor.packaging.requirements import InvalidRequirement, Requirement -from pip._vendor.packaging.specifiers import Specifier -from pip._vendor.pkg_resources import RequirementParseError, parse_requirements - -from pip._internal.exceptions import InstallationError -from pip._internal.models.index import PyPI, TestPyPI -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.pyproject import make_pyproject_path -from pip._internal.req.req_file import ParsedRequirement -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.filetypes import is_archive_file -from pip._internal.utils.misc import is_installable_dir -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs import is_url, vcs - -__all__ = [ - "install_req_from_editable", "install_req_from_line", - "parse_editable" -] - -logger = logging.getLogger(__name__) -operators = Specifier._operators.keys() - - -def _strip_extras(path: str) -> Tuple[str, Optional[str]]: - m = re.match(r'^(.+)(\[[^\]]+\])$', path) - extras = None - if m: - path_no_extras = m.group(1) - extras = m.group(2) - else: - path_no_extras = path - - return path_no_extras, extras - - -def convert_extras(extras: Optional[str]) -> Set[str]: - if not extras: - return set() - return Requirement("placeholder" + extras.lower()).extras - - -def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]: - """Parses an editable requirement into: - - a requirement name - - an URL - - extras - - editable options - Accepted requirements: - svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir - .[some_extra] - """ - - url = editable_req - - # If a file path is specified with extras, strip off the extras. - url_no_extras, extras = _strip_extras(url) - - if os.path.isdir(url_no_extras): - setup_py = os.path.join(url_no_extras, 'setup.py') - setup_cfg = os.path.join(url_no_extras, 'setup.cfg') - if not os.path.exists(setup_py) and not os.path.exists(setup_cfg): - msg = ( - 'File "setup.py" or "setup.cfg" not found. Directory cannot be ' - 'installed in editable mode: {}' - .format(os.path.abspath(url_no_extras)) - ) - pyproject_path = make_pyproject_path(url_no_extras) - if os.path.isfile(pyproject_path): - msg += ( - '\n(A "pyproject.toml" file was found, but editable ' - 'mode currently requires a setuptools-based build.)' - ) - raise InstallationError(msg) - - # Treating it as code that has already been checked out - url_no_extras = path_to_url(url_no_extras) - - if url_no_extras.lower().startswith('file:'): - package_name = Link(url_no_extras).egg_fragment - if extras: - return ( - package_name, - url_no_extras, - Requirement("placeholder" + extras.lower()).extras, - ) - else: - return package_name, url_no_extras, set() - - for version_control in vcs: - if url.lower().startswith(f'{version_control}:'): - url = f'{version_control}+{url}' - break - - link = Link(url) - - if not link.is_vcs: - backends = ", ".join(vcs.all_schemes) - raise InstallationError( - f'{editable_req} is not a valid editable requirement. ' - f'It should either be a path to a local project or a VCS URL ' - f'(beginning with {backends}).' - ) - - package_name = link.egg_fragment - if not package_name: - raise InstallationError( - "Could not detect requirement name for '{}', please specify one " - "with #egg=your_package_name".format(editable_req) - ) - return package_name, url, set() - - -def deduce_helpful_msg(req: str) -> str: - """Returns helpful msg in case requirements file does not exist, - or cannot be parsed. - - :params req: Requirements file path - """ - msg = "" - if os.path.exists(req): - msg = " The path does exist. " - # Try to parse and check if it is a requirements file. - try: - with open(req) as fp: - # parse first line only - next(parse_requirements(fp.read())) - msg += ( - "The argument you provided " - "({}) appears to be a" - " requirements file. If that is the" - " case, use the '-r' flag to install" - " the packages specified within it." - ).format(req) - except RequirementParseError: - logger.debug( - "Cannot parse '%s' as requirements file", req, exc_info=True - ) - else: - msg += f" File '{req}' does not exist." - return msg - - -class RequirementParts: - def __init__( - self, - requirement: Optional[Requirement], - link: Optional[Link], - markers: Optional[Marker], - extras: Set[str], - ): - self.requirement = requirement - self.link = link - self.markers = markers - self.extras = extras - - -def parse_req_from_editable(editable_req: str) -> RequirementParts: - name, url, extras_override = parse_editable(editable_req) - - if name is not None: - try: - req: Optional[Requirement] = Requirement(name) - except InvalidRequirement: - raise InstallationError(f"Invalid requirement: '{name}'") - else: - req = None - - link = Link(url) - - return RequirementParts(req, link, None, extras_override) - - -# ---- The actual constructors follow ---- - - -def install_req_from_editable( - editable_req: str, - comes_from: Optional[Union[InstallRequirement, str]] = None, - use_pep517: Optional[bool] = None, - isolated: bool = False, - options: Optional[Dict[str, Any]] = None, - constraint: bool = False, - user_supplied: bool = False, -) -> InstallRequirement: - - parts = parse_req_from_editable(editable_req) - - return InstallRequirement( - parts.requirement, - comes_from=comes_from, - user_supplied=user_supplied, - editable=True, - link=parts.link, - constraint=constraint, - use_pep517=use_pep517, - isolated=isolated, - install_options=options.get("install_options", []) if options else [], - global_options=options.get("global_options", []) if options else [], - hash_options=options.get("hashes", {}) if options else {}, - extras=parts.extras, - ) - - -def _looks_like_path(name: str) -> bool: - """Checks whether the string "looks like" a path on the filesystem. - - This does not check whether the target actually exists, only judge from the - appearance. - - Returns true if any of the following conditions is true: - * a path separator is found (either os.path.sep or os.path.altsep); - * a dot is found (which represents the current directory). - """ - if os.path.sep in name: - return True - if os.path.altsep is not None and os.path.altsep in name: - return True - if name.startswith("."): - return True - return False - - -def _get_url_from_path(path: str, name: str) -> Optional[str]: - """ - First, it checks whether a provided path is an installable directory. If it - is, returns the path. - - If false, check if the path is an archive file (such as a .whl). - The function checks if the path is a file. If false, if the path has - an @, it will treat it as a PEP 440 URL requirement and return the path. - """ - if _looks_like_path(name) and os.path.isdir(path): - if is_installable_dir(path): - return path_to_url(path) - raise InstallationError( - f"Directory {name!r} is not installable. Neither 'setup.py' " - "nor 'pyproject.toml' found." - ) - if not is_archive_file(path): - return None - if os.path.isfile(path): - return path_to_url(path) - urlreq_parts = name.split('@', 1) - if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]): - # If the path contains '@' and the part before it does not look - # like a path, try to treat it as a PEP 440 URL req instead. - return None - logger.warning( - 'Requirement %r looks like a filename, but the ' - 'file does not exist', - name - ) - return path_to_url(path) - - -def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementParts: - if is_url(name): - marker_sep = '; ' - else: - marker_sep = ';' - if marker_sep in name: - name, markers_as_string = name.split(marker_sep, 1) - markers_as_string = markers_as_string.strip() - if not markers_as_string: - markers = None - else: - markers = Marker(markers_as_string) - else: - markers = None - name = name.strip() - req_as_string = None - path = os.path.normpath(os.path.abspath(name)) - link = None - extras_as_string = None - - if is_url(name): - link = Link(name) - else: - p, extras_as_string = _strip_extras(path) - url = _get_url_from_path(p, name) - if url is not None: - link = Link(url) - - # it's a local file, dir, or url - if link: - # Handle relative file URLs - if link.scheme == 'file' and re.search(r'\.\./', link.url): - link = Link( - path_to_url(os.path.normpath(os.path.abspath(link.path)))) - # wheel file - if link.is_wheel: - wheel = Wheel(link.filename) # can raise InvalidWheelFilename - req_as_string = f"{wheel.name}=={wheel.version}" - else: - # set the req to the egg fragment. when it's not there, this - # will become an 'unnamed' requirement - req_as_string = link.egg_fragment - - # a requirement specifier - else: - req_as_string = name - - extras = convert_extras(extras_as_string) - - def with_source(text: str) -> str: - if not line_source: - return text - return f'{text} (from {line_source})' - - def _parse_req_string(req_as_string: str) -> Requirement: - try: - req = Requirement(req_as_string) - except InvalidRequirement: - if os.path.sep in req_as_string: - add_msg = "It looks like a path." - add_msg += deduce_helpful_msg(req_as_string) - elif ('=' in req_as_string and - not any(op in req_as_string for op in operators)): - add_msg = "= is not a valid operator. Did you mean == ?" - else: - add_msg = '' - msg = with_source( - f'Invalid requirement: {req_as_string!r}' - ) - if add_msg: - msg += f'\nHint: {add_msg}' - raise InstallationError(msg) - else: - # Deprecate extras after specifiers: "name>=1.0[extras]" - # This currently works by accident because _strip_extras() parses - # any extras in the end of the string and those are saved in - # RequirementParts - for spec in req.specifier: - spec_str = str(spec) - if spec_str.endswith(']'): - msg = f"Extras after version '{spec_str}'." - raise InstallationError(msg) - return req - - if req_as_string is not None: - req: Optional[Requirement] = _parse_req_string(req_as_string) - else: - req = None - - return RequirementParts(req, link, markers, extras) - - -def install_req_from_line( - name: str, - comes_from: Optional[Union[str, InstallRequirement]] = None, - use_pep517: Optional[bool] = None, - isolated: bool = False, - options: Optional[Dict[str, Any]] = None, - constraint: bool = False, - line_source: Optional[str] = None, - user_supplied: bool = False, -) -> InstallRequirement: - """Creates an InstallRequirement from a name, which might be a - requirement, directory containing 'setup.py', filename, or URL. - - :param line_source: An optional string describing where the line is from, - for logging purposes in case of an error. - """ - parts = parse_req_from_line(name, line_source) - - return InstallRequirement( - parts.requirement, comes_from, link=parts.link, markers=parts.markers, - use_pep517=use_pep517, isolated=isolated, - install_options=options.get("install_options", []) if options else [], - global_options=options.get("global_options", []) if options else [], - hash_options=options.get("hashes", {}) if options else {}, - constraint=constraint, - extras=parts.extras, - user_supplied=user_supplied, - ) - - -def install_req_from_req_string( - req_string: str, - comes_from: Optional[InstallRequirement] = None, - isolated: bool = False, - use_pep517: Optional[bool] = None, - user_supplied: bool = False, -) -> InstallRequirement: - try: - req = Requirement(req_string) - except InvalidRequirement: - raise InstallationError(f"Invalid requirement: '{req_string}'") - - domains_not_allowed = [ - PyPI.file_storage_domain, - TestPyPI.file_storage_domain, - ] - if (req.url and comes_from and comes_from.link and - comes_from.link.netloc in domains_not_allowed): - # Explicitly disallow pypi packages that depend on external urls - raise InstallationError( - "Packages installed from PyPI cannot depend on packages " - "which are not also hosted on PyPI.\n" - "{} depends on {} ".format(comes_from.name, req) - ) - - return InstallRequirement( - req, - comes_from, - isolated=isolated, - use_pep517=use_pep517, - user_supplied=user_supplied, - ) - - -def install_req_from_parsed_requirement( - parsed_req: ParsedRequirement, - isolated: bool = False, - use_pep517: Optional[bool] = None, - user_supplied: bool = False, -) -> InstallRequirement: - if parsed_req.is_editable: - req = install_req_from_editable( - parsed_req.requirement, - comes_from=parsed_req.comes_from, - use_pep517=use_pep517, - constraint=parsed_req.constraint, - isolated=isolated, - user_supplied=user_supplied, - ) - - else: - req = install_req_from_line( - parsed_req.requirement, - comes_from=parsed_req.comes_from, - use_pep517=use_pep517, - isolated=isolated, - options=parsed_req.options, - constraint=parsed_req.constraint, - line_source=parsed_req.line_source, - user_supplied=user_supplied, - ) - return req - - -def install_req_from_link_and_ireq( - link: Link, ireq: InstallRequirement -) -> InstallRequirement: - return InstallRequirement( - req=ireq.req, - comes_from=ireq.comes_from, - editable=ireq.editable, - link=link, - markers=ireq.markers, - use_pep517=ireq.use_pep517, - isolated=ireq.isolated, - install_options=ireq.install_options, - global_options=ireq.global_options, - hash_options=ireq.hash_options, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_file.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_file.py deleted file mode 100644 index 01c6cf6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_file.py +++ /dev/null @@ -1,528 +0,0 @@ -""" -Requirements file parsing -""" - -import optparse -import os -import re -import shlex -import urllib.parse -from optparse import Values -from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Optional, Tuple - -from pip._internal.cli import cmdoptions -from pip._internal.exceptions import InstallationError, RequirementsFileParseError -from pip._internal.models.search_scope import SearchScope -from pip._internal.network.session import PipSession -from pip._internal.network.utils import raise_for_status -from pip._internal.utils.encoding import auto_decode -from pip._internal.utils.urls import get_url_scheme - -if TYPE_CHECKING: - # NoReturn introduced in 3.6.2; imported only for type checking to maintain - # pip compatibility with older patch versions of Python 3.6 - from typing import NoReturn - - from pip._internal.index.package_finder import PackageFinder - -__all__ = ['parse_requirements'] - -ReqFileLines = Iterator[Tuple[int, str]] - -LineParser = Callable[[str], Tuple[str, Values]] - -SCHEME_RE = re.compile(r'^(http|https|file):', re.I) -COMMENT_RE = re.compile(r'(^|\s+)#.*$') - -# Matches environment variable-style values in '${MY_VARIABLE_1}' with the -# variable name consisting of only uppercase letters, digits or the '_' -# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, -# 2013 Edition. -ENV_VAR_RE = re.compile(r'(?P\$\{(?P[A-Z0-9_]+)\})') - -SUPPORTED_OPTIONS: List[Callable[..., optparse.Option]] = [ - cmdoptions.index_url, - cmdoptions.extra_index_url, - cmdoptions.no_index, - cmdoptions.constraints, - cmdoptions.requirements, - cmdoptions.editable, - cmdoptions.find_links, - cmdoptions.no_binary, - cmdoptions.only_binary, - cmdoptions.prefer_binary, - cmdoptions.require_hashes, - cmdoptions.pre, - cmdoptions.trusted_host, - cmdoptions.use_new_feature, -] - -# options to be passed to requirements -SUPPORTED_OPTIONS_REQ: List[Callable[..., optparse.Option]] = [ - cmdoptions.install_options, - cmdoptions.global_options, - cmdoptions.hash, -] - -# the 'dest' string values -SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ] - - -class ParsedRequirement: - def __init__( - self, - requirement: str, - is_editable: bool, - comes_from: str, - constraint: bool, - options: Optional[Dict[str, Any]] = None, - line_source: Optional[str] = None, - ) -> None: - self.requirement = requirement - self.is_editable = is_editable - self.comes_from = comes_from - self.options = options - self.constraint = constraint - self.line_source = line_source - - -class ParsedLine: - def __init__( - self, - filename: str, - lineno: int, - args: str, - opts: Values, - constraint: bool, - ) -> None: - self.filename = filename - self.lineno = lineno - self.opts = opts - self.constraint = constraint - - if args: - self.is_requirement = True - self.is_editable = False - self.requirement = args - elif opts.editables: - self.is_requirement = True - self.is_editable = True - # We don't support multiple -e on one line - self.requirement = opts.editables[0] - else: - self.is_requirement = False - - -def parse_requirements( - filename: str, - session: PipSession, - finder: Optional["PackageFinder"] = None, - options: Optional[optparse.Values] = None, - constraint: bool = False, -) -> Iterator[ParsedRequirement]: - """Parse a requirements file and yield ParsedRequirement instances. - - :param filename: Path or url of requirements file. - :param session: PipSession instance. - :param finder: Instance of pip.index.PackageFinder. - :param options: cli options. - :param constraint: If true, parsing a constraint file rather than - requirements file. - """ - line_parser = get_line_parser(finder) - parser = RequirementsFileParser(session, line_parser) - - for parsed_line in parser.parse(filename, constraint): - parsed_req = handle_line( - parsed_line, - options=options, - finder=finder, - session=session - ) - if parsed_req is not None: - yield parsed_req - - -def preprocess(content: str) -> ReqFileLines: - """Split, filter, and join lines, and return a line iterator - - :param content: the content of the requirements file - """ - lines_enum: ReqFileLines = enumerate(content.splitlines(), start=1) - lines_enum = join_lines(lines_enum) - lines_enum = ignore_comments(lines_enum) - lines_enum = expand_env_variables(lines_enum) - return lines_enum - - -def handle_requirement_line( - line: ParsedLine, - options: Optional[optparse.Values] = None, -) -> ParsedRequirement: - - # preserve for the nested code path - line_comes_from = '{} {} (line {})'.format( - '-c' if line.constraint else '-r', line.filename, line.lineno, - ) - - assert line.is_requirement - - if line.is_editable: - # For editable requirements, we don't support per-requirement - # options, so just return the parsed requirement. - return ParsedRequirement( - requirement=line.requirement, - is_editable=line.is_editable, - comes_from=line_comes_from, - constraint=line.constraint, - ) - else: - if options: - # Disable wheels if the user has specified build options - cmdoptions.check_install_build_global(options, line.opts) - - # get the options that apply to requirements - req_options = {} - for dest in SUPPORTED_OPTIONS_REQ_DEST: - if dest in line.opts.__dict__ and line.opts.__dict__[dest]: - req_options[dest] = line.opts.__dict__[dest] - - line_source = f'line {line.lineno} of {line.filename}' - return ParsedRequirement( - requirement=line.requirement, - is_editable=line.is_editable, - comes_from=line_comes_from, - constraint=line.constraint, - options=req_options, - line_source=line_source, - ) - - -def handle_option_line( - opts: Values, - filename: str, - lineno: int, - finder: Optional["PackageFinder"] = None, - options: Optional[optparse.Values] = None, - session: Optional[PipSession] = None, -) -> None: - - if options: - # percolate options upward - if opts.require_hashes: - options.require_hashes = opts.require_hashes - if opts.features_enabled: - options.features_enabled.extend( - f for f in opts.features_enabled - if f not in options.features_enabled - ) - - # set finder options - if finder: - find_links = finder.find_links - index_urls = finder.index_urls - if opts.index_url: - index_urls = [opts.index_url] - if opts.no_index is True: - index_urls = [] - if opts.extra_index_urls: - index_urls.extend(opts.extra_index_urls) - if opts.find_links: - # FIXME: it would be nice to keep track of the source - # of the find_links: support a find-links local path - # relative to a requirements file. - value = opts.find_links[0] - req_dir = os.path.dirname(os.path.abspath(filename)) - relative_to_reqs_file = os.path.join(req_dir, value) - if os.path.exists(relative_to_reqs_file): - value = relative_to_reqs_file - find_links.append(value) - - if session: - # We need to update the auth urls in session - session.update_index_urls(index_urls) - - search_scope = SearchScope( - find_links=find_links, - index_urls=index_urls, - ) - finder.search_scope = search_scope - - if opts.pre: - finder.set_allow_all_prereleases() - - if opts.prefer_binary: - finder.set_prefer_binary() - - if session: - for host in opts.trusted_hosts or []: - source = f'line {lineno} of {filename}' - session.add_trusted_host(host, source=source) - - -def handle_line( - line: ParsedLine, - options: Optional[optparse.Values] = None, - finder: Optional["PackageFinder"] = None, - session: Optional[PipSession] = None, -) -> Optional[ParsedRequirement]: - """Handle a single parsed requirements line; This can result in - creating/yielding requirements, or updating the finder. - - :param line: The parsed line to be processed. - :param options: CLI options. - :param finder: The finder - updated by non-requirement lines. - :param session: The session - updated by non-requirement lines. - - Returns a ParsedRequirement object if the line is a requirement line, - otherwise returns None. - - For lines that contain requirements, the only options that have an effect - are from SUPPORTED_OPTIONS_REQ, and they are scoped to the - requirement. Other options from SUPPORTED_OPTIONS may be present, but are - ignored. - - For lines that do not contain requirements, the only options that have an - effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may - be present, but are ignored. These lines may contain multiple options - (although our docs imply only one is supported), and all our parsed and - affect the finder. - """ - - if line.is_requirement: - parsed_req = handle_requirement_line(line, options) - return parsed_req - else: - handle_option_line( - line.opts, - line.filename, - line.lineno, - finder, - options, - session, - ) - return None - - -class RequirementsFileParser: - def __init__( - self, - session: PipSession, - line_parser: LineParser, - ) -> None: - self._session = session - self._line_parser = line_parser - - def parse(self, filename: str, constraint: bool) -> Iterator[ParsedLine]: - """Parse a given file, yielding parsed lines. - """ - yield from self._parse_and_recurse(filename, constraint) - - def _parse_and_recurse( - self, filename: str, constraint: bool - ) -> Iterator[ParsedLine]: - for line in self._parse_file(filename, constraint): - if ( - not line.is_requirement and - (line.opts.requirements or line.opts.constraints) - ): - # parse a nested requirements file - if line.opts.requirements: - req_path = line.opts.requirements[0] - nested_constraint = False - else: - req_path = line.opts.constraints[0] - nested_constraint = True - - # original file is over http - if SCHEME_RE.search(filename): - # do a url join so relative paths work - req_path = urllib.parse.urljoin(filename, req_path) - # original file and nested file are paths - elif not SCHEME_RE.search(req_path): - # do a join so relative paths work - req_path = os.path.join( - os.path.dirname(filename), req_path, - ) - - yield from self._parse_and_recurse(req_path, nested_constraint) - else: - yield line - - def _parse_file(self, filename: str, constraint: bool) -> Iterator[ParsedLine]: - _, content = get_file_content(filename, self._session) - - lines_enum = preprocess(content) - - for line_number, line in lines_enum: - try: - args_str, opts = self._line_parser(line) - except OptionParsingError as e: - # add offending line - msg = f'Invalid requirement: {line}\n{e.msg}' - raise RequirementsFileParseError(msg) - - yield ParsedLine( - filename, - line_number, - args_str, - opts, - constraint, - ) - - -def get_line_parser(finder: Optional["PackageFinder"]) -> LineParser: - def parse_line(line: str) -> Tuple[str, Values]: - # Build new parser for each line since it accumulates appendable - # options. - parser = build_parser() - defaults = parser.get_default_values() - defaults.index_url = None - if finder: - defaults.format_control = finder.format_control - - args_str, options_str = break_args_options(line) - - opts, _ = parser.parse_args(shlex.split(options_str), defaults) - - return args_str, opts - - return parse_line - - -def break_args_options(line: str) -> Tuple[str, str]: - """Break up the line into an args and options string. We only want to shlex - (and then optparse) the options, not the args. args can contain markers - which are corrupted by shlex. - """ - tokens = line.split(' ') - args = [] - options = tokens[:] - for token in tokens: - if token.startswith('-') or token.startswith('--'): - break - else: - args.append(token) - options.pop(0) - return ' '.join(args), ' '.join(options) - - -class OptionParsingError(Exception): - def __init__(self, msg: str) -> None: - self.msg = msg - - -def build_parser() -> optparse.OptionParser: - """ - Return a parser for parsing requirement lines - """ - parser = optparse.OptionParser(add_help_option=False) - - option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ - for option_factory in option_factories: - option = option_factory() - parser.add_option(option) - - # By default optparse sys.exits on parsing errors. We want to wrap - # that in our own exception. - def parser_exit(self: Any, msg: str) -> "NoReturn": - raise OptionParsingError(msg) - # NOTE: mypy disallows assigning to a method - # https://github.com/python/mypy/issues/2427 - parser.exit = parser_exit # type: ignore - - return parser - - -def join_lines(lines_enum: ReqFileLines) -> ReqFileLines: - """Joins a line ending in '\' with the previous line (except when following - comments). The joined line takes on the index of the first line. - """ - primary_line_number = None - new_line: List[str] = [] - for line_number, line in lines_enum: - if not line.endswith('\\') or COMMENT_RE.match(line): - if COMMENT_RE.match(line): - # this ensures comments are always matched later - line = ' ' + line - if new_line: - new_line.append(line) - assert primary_line_number is not None - yield primary_line_number, ''.join(new_line) - new_line = [] - else: - yield line_number, line - else: - if not new_line: - primary_line_number = line_number - new_line.append(line.strip('\\')) - - # last line contains \ - if new_line: - assert primary_line_number is not None - yield primary_line_number, ''.join(new_line) - - # TODO: handle space after '\'. - - -def ignore_comments(lines_enum: ReqFileLines) -> ReqFileLines: - """ - Strips comments and filter empty lines. - """ - for line_number, line in lines_enum: - line = COMMENT_RE.sub('', line) - line = line.strip() - if line: - yield line_number, line - - -def expand_env_variables(lines_enum: ReqFileLines) -> ReqFileLines: - """Replace all environment variables that can be retrieved via `os.getenv`. - - The only allowed format for environment variables defined in the - requirement file is `${MY_VARIABLE_1}` to ensure two things: - - 1. Strings that contain a `$` aren't accidentally (partially) expanded. - 2. Ensure consistency across platforms for requirement files. - - These points are the result of a discussion on the `github pull - request #3514 `_. - - Valid characters in variable names follow the `POSIX standard - `_ and are limited - to uppercase letter, digits and the `_` (underscore). - """ - for line_number, line in lines_enum: - for env_var, var_name in ENV_VAR_RE.findall(line): - value = os.getenv(var_name) - if not value: - continue - - line = line.replace(env_var, value) - - yield line_number, line - - -def get_file_content(url: str, session: PipSession) -> Tuple[str, str]: - """Gets the content of a file; it may be a filename, file: URL, or - http: URL. Returns (location, content). Content is unicode. - Respects # -*- coding: declarations on the retrieved files. - - :param url: File path or url. - :param session: PipSession instance. - """ - scheme = get_url_scheme(url) - - # Pip has special support for file:// URLs (LocalFSAdapter). - if scheme in ['http', 'https', 'file']: - resp = session.get(url) - raise_for_status(resp) - return resp.url, resp.text - - # Assume this is a bare path. - try: - with open(url, 'rb') as f: - content = auto_decode(f.read()) - except OSError as exc: - raise InstallationError(f'Could not open requirements file: {exc}') - return url, content diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_install.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_install.py deleted file mode 100644 index 4c58cdb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_install.py +++ /dev/null @@ -1,846 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import os -import shutil -import sys -import uuid -import zipfile -from typing import Any, Dict, Iterable, List, Optional, Sequence, Union - -from pip._vendor import pkg_resources, six -from pip._vendor.packaging.markers import Marker -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.specifiers import SpecifierSet -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import Version -from pip._vendor.packaging.version import parse as parse_version -from pip._vendor.pep517.wrappers import Pep517HookCaller -from pip._vendor.pkg_resources import Distribution - -from pip._internal.build_env import BuildEnvironment, NoOpBuildEnvironment -from pip._internal.exceptions import InstallationError -from pip._internal.locations import get_scheme -from pip._internal.models.link import Link -from pip._internal.operations.build.metadata import generate_metadata -from pip._internal.operations.build.metadata_legacy import ( - generate_metadata as generate_metadata_legacy, -) -from pip._internal.operations.install.editable_legacy import ( - install_editable as install_editable_legacy, -) -from pip._internal.operations.install.legacy import LegacyInstallFailure -from pip._internal.operations.install.legacy import install as install_legacy -from pip._internal.operations.install.wheel import install_wheel -from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path -from pip._internal.req.req_uninstall import UninstallPathSet -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.direct_url_helpers import direct_url_from_link -from pip._internal.utils.hashes import Hashes -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - ask_path_exists, - backup_dir, - display_path, - dist_in_site_packages, - dist_in_usersite, - get_distribution, - hide_url, - redact_auth_from_url, -) -from pip._internal.utils.packaging import get_metadata -from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds -from pip._internal.utils.virtualenv import running_under_virtualenv -from pip._internal.vcs import vcs - -logger = logging.getLogger(__name__) - - -def _get_dist(metadata_directory: str) -> Distribution: - """Return a pkg_resources.Distribution for the provided - metadata directory. - """ - dist_dir = metadata_directory.rstrip(os.sep) - - # Build a PathMetadata object, from path to metadata. :wink: - base_dir, dist_dir_name = os.path.split(dist_dir) - metadata = pkg_resources.PathMetadata(base_dir, dist_dir) - - # Determine the correct Distribution object type. - if dist_dir.endswith(".egg-info"): - dist_cls = pkg_resources.Distribution - dist_name = os.path.splitext(dist_dir_name)[0] - else: - assert dist_dir.endswith(".dist-info") - dist_cls = pkg_resources.DistInfoDistribution - dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0] - - return dist_cls( - base_dir, - project_name=dist_name, - metadata=metadata, - ) - - -class InstallRequirement: - """ - Represents something that may be installed later on, may have information - about where to fetch the relevant requirement and also contains logic for - installing the said requirement. - """ - - def __init__( - self, - req: Optional[Requirement], - comes_from: Optional[Union[str, "InstallRequirement"]], - editable: bool = False, - link: Optional[Link] = None, - markers: Optional[Marker] = None, - use_pep517: Optional[bool] = None, - isolated: bool = False, - install_options: Optional[List[str]] = None, - global_options: Optional[List[str]] = None, - hash_options: Optional[Dict[str, List[str]]] = None, - constraint: bool = False, - extras: Iterable[str] = (), - user_supplied: bool = False, - ) -> None: - assert req is None or isinstance(req, Requirement), req - self.req = req - self.comes_from = comes_from - self.constraint = constraint - self.editable = editable - self.legacy_install_reason: Optional[int] = None - - # source_dir is the local directory where the linked requirement is - # located, or unpacked. In case unpacking is needed, creating and - # populating source_dir is done by the RequirementPreparer. Note this - # is not necessarily the directory where pyproject.toml or setup.py is - # located - that one is obtained via unpacked_source_directory. - self.source_dir: Optional[str] = None - if self.editable: - assert link - if link.is_file: - self.source_dir = os.path.normpath( - os.path.abspath(link.file_path) - ) - - if link is None and req and req.url: - # PEP 508 URL requirement - link = Link(req.url) - self.link = self.original_link = link - self.original_link_is_in_wheel_cache = False - - # Path to any downloaded or already-existing package. - self.local_file_path: Optional[str] = None - if self.link and self.link.is_file: - self.local_file_path = self.link.file_path - - if extras: - self.extras = extras - elif req: - self.extras = { - pkg_resources.safe_extra(extra) for extra in req.extras - } - else: - self.extras = set() - if markers is None and req: - markers = req.marker - self.markers = markers - - # This holds the pkg_resources.Distribution object if this requirement - # is already available: - self.satisfied_by: Optional[Distribution] = None - # Whether the installation process should try to uninstall an existing - # distribution before installing this requirement. - self.should_reinstall = False - # Temporary build location - self._temp_build_dir: Optional[TempDirectory] = None - # Set to True after successful installation - self.install_succeeded: Optional[bool] = None - # Supplied options - self.install_options = install_options if install_options else [] - self.global_options = global_options if global_options else [] - self.hash_options = hash_options if hash_options else {} - # Set to True after successful preparation of this requirement - self.prepared = False - # User supplied requirement are explicitly requested for installation - # by the user via CLI arguments or requirements files, as opposed to, - # e.g. dependencies, extras or constraints. - self.user_supplied = user_supplied - - self.isolated = isolated - self.build_env: BuildEnvironment = NoOpBuildEnvironment() - - # For PEP 517, the directory where we request the project metadata - # gets stored. We need this to pass to build_wheel, so the backend - # can ensure that the wheel matches the metadata (see the PEP for - # details). - self.metadata_directory: Optional[str] = None - - # The static build requirements (from pyproject.toml) - self.pyproject_requires: Optional[List[str]] = None - - # Build requirements that we will check are available - self.requirements_to_check: List[str] = [] - - # The PEP 517 backend we should use to build the project - self.pep517_backend: Optional[Pep517HookCaller] = None - - # Are we using PEP 517 for this requirement? - # After pyproject.toml has been loaded, the only valid values are True - # and False. Before loading, None is valid (meaning "use the default"). - # Setting an explicit value before loading pyproject.toml is supported, - # but after loading this flag should be treated as read only. - self.use_pep517 = use_pep517 - - # This requirement needs more preparation before it can be built - self.needs_more_preparation = False - - def __str__(self) -> str: - if self.req: - s = str(self.req) - if self.link: - s += ' from {}'.format(redact_auth_from_url(self.link.url)) - elif self.link: - s = redact_auth_from_url(self.link.url) - else: - s = '' - if self.satisfied_by is not None: - s += ' in {}'.format(display_path(self.satisfied_by.location)) - if self.comes_from: - if isinstance(self.comes_from, str): - comes_from: Optional[str] = self.comes_from - else: - comes_from = self.comes_from.from_path() - if comes_from: - s += f' (from {comes_from})' - return s - - def __repr__(self) -> str: - return '<{} object: {} editable={!r}>'.format( - self.__class__.__name__, str(self), self.editable) - - def format_debug(self) -> str: - """An un-tested helper for getting state, for debugging. - """ - attributes = vars(self) - names = sorted(attributes) - - state = ( - "{}={!r}".format(attr, attributes[attr]) for attr in sorted(names) - ) - return '<{name} object: {{{state}}}>'.format( - name=self.__class__.__name__, - state=", ".join(state), - ) - - # Things that are valid for all kinds of requirements? - @property - def name(self) -> Optional[str]: - if self.req is None: - return None - return pkg_resources.safe_name(self.req.name) - - @property - def specifier(self) -> SpecifierSet: - return self.req.specifier - - @property - def is_pinned(self) -> bool: - """Return whether I am pinned to an exact version. - - For example, some-package==1.2 is pinned; some-package>1.2 is not. - """ - specifiers = self.specifier - return (len(specifiers) == 1 and - next(iter(specifiers)).operator in {'==', '==='}) - - def match_markers(self, extras_requested: Optional[Iterable[str]] = None) -> bool: - if not extras_requested: - # Provide an extra to safely evaluate the markers - # without matching any extra - extras_requested = ('',) - if self.markers is not None: - return any( - self.markers.evaluate({'extra': extra}) - for extra in extras_requested) - else: - return True - - @property - def has_hash_options(self) -> bool: - """Return whether any known-good hashes are specified as options. - - These activate --require-hashes mode; hashes specified as part of a - URL do not. - - """ - return bool(self.hash_options) - - def hashes(self, trust_internet: bool = True) -> Hashes: - """Return a hash-comparer that considers my option- and URL-based - hashes to be known-good. - - Hashes in URLs--ones embedded in the requirements file, not ones - downloaded from an index server--are almost peers with ones from - flags. They satisfy --require-hashes (whether it was implicitly or - explicitly activated) but do not activate it. md5 and sha224 are not - allowed in flags, which should nudge people toward good algos. We - always OR all hashes together, even ones from URLs. - - :param trust_internet: Whether to trust URL-based (#md5=...) hashes - downloaded from the internet, as by populate_link() - - """ - good_hashes = self.hash_options.copy() - link = self.link if trust_internet else self.original_link - if link and link.hash: - good_hashes.setdefault(link.hash_name, []).append(link.hash) - return Hashes(good_hashes) - - def from_path(self) -> Optional[str]: - """Format a nice indicator to show where this "comes from" - """ - if self.req is None: - return None - s = str(self.req) - if self.comes_from: - if isinstance(self.comes_from, str): - comes_from = self.comes_from - else: - comes_from = self.comes_from.from_path() - if comes_from: - s += '->' + comes_from - return s - - def ensure_build_location( - self, build_dir: str, autodelete: bool, parallel_builds: bool - ) -> str: - assert build_dir is not None - if self._temp_build_dir is not None: - assert self._temp_build_dir.path - return self._temp_build_dir.path - if self.req is None: - # Some systems have /tmp as a symlink which confuses custom - # builds (such as numpy). Thus, we ensure that the real path - # is returned. - self._temp_build_dir = TempDirectory( - kind=tempdir_kinds.REQ_BUILD, globally_managed=True - ) - - return self._temp_build_dir.path - - # This is the only remaining place where we manually determine the path - # for the temporary directory. It is only needed for editables where - # it is the value of the --src option. - - # When parallel builds are enabled, add a UUID to the build directory - # name so multiple builds do not interfere with each other. - dir_name: str = canonicalize_name(self.name) - if parallel_builds: - dir_name = f"{dir_name}_{uuid.uuid4().hex}" - - # FIXME: Is there a better place to create the build_dir? (hg and bzr - # need this) - if not os.path.exists(build_dir): - logger.debug('Creating directory %s', build_dir) - os.makedirs(build_dir) - actual_build_dir = os.path.join(build_dir, dir_name) - # `None` indicates that we respect the globally-configured deletion - # settings, which is what we actually want when auto-deleting. - delete_arg = None if autodelete else False - return TempDirectory( - path=actual_build_dir, - delete=delete_arg, - kind=tempdir_kinds.REQ_BUILD, - globally_managed=True, - ).path - - def _set_requirement(self) -> None: - """Set requirement after generating metadata. - """ - assert self.req is None - assert self.metadata is not None - assert self.source_dir is not None - - # Construct a Requirement object from the generated metadata - if isinstance(parse_version(self.metadata["Version"]), Version): - op = "==" - else: - op = "===" - - self.req = Requirement( - "".join([ - self.metadata["Name"], - op, - self.metadata["Version"], - ]) - ) - - def warn_on_mismatching_name(self) -> None: - metadata_name = canonicalize_name(self.metadata["Name"]) - if canonicalize_name(self.req.name) == metadata_name: - # Everything is fine. - return - - # If we're here, there's a mismatch. Log a warning about it. - logger.warning( - 'Generating metadata for package %s ' - 'produced metadata for project name %s. Fix your ' - '#egg=%s fragments.', - self.name, metadata_name, self.name - ) - self.req = Requirement(metadata_name) - - def check_if_exists(self, use_user_site: bool) -> None: - """Find an installed distribution that satisfies or conflicts - with this requirement, and set self.satisfied_by or - self.should_reinstall appropriately. - """ - if self.req is None: - return - existing_dist = get_distribution(self.req.name) - if not existing_dist: - return - - # pkg_resouces may contain a different copy of packaging.version from - # pip in if the downstream distributor does a poor job debundling pip. - # We avoid existing_dist.parsed_version and let SpecifierSet.contains - # parses the version instead. - existing_version = existing_dist.version - version_compatible = ( - existing_version is not None and - self.req.specifier.contains(existing_version, prereleases=True) - ) - if not version_compatible: - self.satisfied_by = None - if use_user_site: - if dist_in_usersite(existing_dist): - self.should_reinstall = True - elif (running_under_virtualenv() and - dist_in_site_packages(existing_dist)): - raise InstallationError( - "Will not install to the user site because it will " - "lack sys.path precedence to {} in {}".format( - existing_dist.project_name, existing_dist.location) - ) - else: - self.should_reinstall = True - else: - if self.editable: - self.should_reinstall = True - # when installing editables, nothing pre-existing should ever - # satisfy - self.satisfied_by = None - else: - self.satisfied_by = existing_dist - - # Things valid for wheels - @property - def is_wheel(self) -> bool: - if not self.link: - return False - return self.link.is_wheel - - # Things valid for sdists - @property - def unpacked_source_directory(self) -> str: - return os.path.join( - self.source_dir, - self.link and self.link.subdirectory_fragment or '') - - @property - def setup_py_path(self) -> str: - assert self.source_dir, f"No source dir for {self}" - setup_py = os.path.join(self.unpacked_source_directory, 'setup.py') - - return setup_py - - @property - def pyproject_toml_path(self) -> str: - assert self.source_dir, f"No source dir for {self}" - return make_pyproject_path(self.unpacked_source_directory) - - def load_pyproject_toml(self) -> None: - """Load the pyproject.toml file. - - After calling this routine, all of the attributes related to PEP 517 - processing for this requirement have been set. In particular, the - use_pep517 attribute can be used to determine whether we should - follow the PEP 517 or legacy (setup.py) code path. - """ - pyproject_toml_data = load_pyproject_toml( - self.use_pep517, - self.pyproject_toml_path, - self.setup_py_path, - str(self) - ) - - if pyproject_toml_data is None: - self.use_pep517 = False - return - - self.use_pep517 = True - requires, backend, check, backend_path = pyproject_toml_data - self.requirements_to_check = check - self.pyproject_requires = requires - self.pep517_backend = Pep517HookCaller( - self.unpacked_source_directory, backend, backend_path=backend_path, - ) - - def _generate_metadata(self) -> str: - """Invokes metadata generator functions, with the required arguments. - """ - if not self.use_pep517: - assert self.unpacked_source_directory - - if not os.path.exists(self.setup_py_path): - raise InstallationError( - f'File "setup.py" not found for legacy project {self}.' - ) - - return generate_metadata_legacy( - build_env=self.build_env, - setup_py_path=self.setup_py_path, - source_dir=self.unpacked_source_directory, - isolated=self.isolated, - details=self.name or f"from {self.link}" - ) - - assert self.pep517_backend is not None - - return generate_metadata( - build_env=self.build_env, - backend=self.pep517_backend, - ) - - def prepare_metadata(self) -> None: - """Ensure that project metadata is available. - - Under PEP 517, call the backend hook to prepare the metadata. - Under legacy processing, call setup.py egg-info. - """ - assert self.source_dir - - with indent_log(): - self.metadata_directory = self._generate_metadata() - - # Act on the newly generated metadata, based on the name and version. - if not self.name: - self._set_requirement() - else: - self.warn_on_mismatching_name() - - self.assert_source_matches_version() - - @property - def metadata(self) -> Any: - if not hasattr(self, '_metadata'): - self._metadata = get_metadata(self.get_dist()) - - return self._metadata - - def get_dist(self) -> Distribution: - return _get_dist(self.metadata_directory) - - def assert_source_matches_version(self) -> None: - assert self.source_dir - version = self.metadata['version'] - if self.req.specifier and version not in self.req.specifier: - logger.warning( - 'Requested %s, but installing version %s', - self, - version, - ) - else: - logger.debug( - 'Source in %s has version %s, which satisfies requirement %s', - display_path(self.source_dir), - version, - self, - ) - - # For both source distributions and editables - def ensure_has_source_dir( - self, - parent_dir: str, - autodelete: bool = False, - parallel_builds: bool = False, - ) -> None: - """Ensure that a source_dir is set. - - This will create a temporary build dir if the name of the requirement - isn't known yet. - - :param parent_dir: The ideal pip parent_dir for the source_dir. - Generally src_dir for editables and build_dir for sdists. - :return: self.source_dir - """ - if self.source_dir is None: - self.source_dir = self.ensure_build_location( - parent_dir, - autodelete=autodelete, - parallel_builds=parallel_builds, - ) - - # For editable installations - def update_editable(self) -> None: - if not self.link: - logger.debug( - "Cannot update repository at %s; repository location is " - "unknown", - self.source_dir, - ) - return - assert self.editable - assert self.source_dir - if self.link.scheme == 'file': - # Static paths don't get updated - return - vcs_backend = vcs.get_backend_for_scheme(self.link.scheme) - # Editable requirements are validated in Requirement constructors. - # So here, if it's neither a path nor a valid VCS URL, it's a bug. - assert vcs_backend, f"Unsupported VCS URL {self.link.url}" - hidden_url = hide_url(self.link.url) - vcs_backend.obtain(self.source_dir, url=hidden_url) - - # Top-level Actions - def uninstall( - self, auto_confirm: bool = False, verbose: bool = False - ) -> Optional[UninstallPathSet]: - """ - Uninstall the distribution currently satisfying this requirement. - - Prompts before removing or modifying files unless - ``auto_confirm`` is True. - - Refuses to delete or modify files outside of ``sys.prefix`` - - thus uninstallation within a virtual environment can only - modify that virtual environment, even if the virtualenv is - linked to global site-packages. - - """ - assert self.req - dist = get_distribution(self.req.name) - if not dist: - logger.warning("Skipping %s as it is not installed.", self.name) - return None - logger.info('Found existing installation: %s', dist) - - uninstalled_pathset = UninstallPathSet.from_dist(dist) - uninstalled_pathset.remove(auto_confirm, verbose) - return uninstalled_pathset - - def _get_archive_name(self, path: str, parentdir: str, rootdir: str) -> str: - - def _clean_zip_name(name: str, prefix: str) -> str: - assert name.startswith(prefix + os.path.sep), ( - f"name {name!r} doesn't start with prefix {prefix!r}" - ) - name = name[len(prefix) + 1:] - name = name.replace(os.path.sep, '/') - return name - - path = os.path.join(parentdir, path) - name = _clean_zip_name(path, rootdir) - return self.name + '/' + name - - def archive(self, build_dir: Optional[str]) -> None: - """Saves archive to provided build_dir. - - Used for saving downloaded VCS requirements as part of `pip download`. - """ - assert self.source_dir - if build_dir is None: - return - - create_archive = True - archive_name = '{}-{}.zip'.format(self.name, self.metadata["version"]) - archive_path = os.path.join(build_dir, archive_name) - - if os.path.exists(archive_path): - response = ask_path_exists( - 'The file {} exists. (i)gnore, (w)ipe, ' - '(b)ackup, (a)bort '.format( - display_path(archive_path)), - ('i', 'w', 'b', 'a')) - if response == 'i': - create_archive = False - elif response == 'w': - logger.warning('Deleting %s', display_path(archive_path)) - os.remove(archive_path) - elif response == 'b': - dest_file = backup_dir(archive_path) - logger.warning( - 'Backing up %s to %s', - display_path(archive_path), - display_path(dest_file), - ) - shutil.move(archive_path, dest_file) - elif response == 'a': - sys.exit(-1) - - if not create_archive: - return - - zip_output = zipfile.ZipFile( - archive_path, 'w', zipfile.ZIP_DEFLATED, allowZip64=True, - ) - with zip_output: - dir = os.path.normcase( - os.path.abspath(self.unpacked_source_directory) - ) - for dirpath, dirnames, filenames in os.walk(dir): - for dirname in dirnames: - dir_arcname = self._get_archive_name( - dirname, parentdir=dirpath, rootdir=dir, - ) - zipdir = zipfile.ZipInfo(dir_arcname + '/') - zipdir.external_attr = 0x1ED << 16 # 0o755 - zip_output.writestr(zipdir, '') - for filename in filenames: - file_arcname = self._get_archive_name( - filename, parentdir=dirpath, rootdir=dir, - ) - filename = os.path.join(dirpath, filename) - zip_output.write(filename, file_arcname) - - logger.info('Saved %s', display_path(archive_path)) - - def install( - self, - install_options: List[str], - global_options: Optional[Sequence[str]] = None, - root: Optional[str] = None, - home: Optional[str] = None, - prefix: Optional[str] = None, - warn_script_location: bool = True, - use_user_site: bool = False, - pycompile: bool = True - ) -> None: - scheme = get_scheme( - self.name, - user=use_user_site, - home=home, - root=root, - isolated=self.isolated, - prefix=prefix, - ) - - global_options = global_options if global_options is not None else [] - if self.editable: - install_editable_legacy( - install_options, - global_options, - prefix=prefix, - home=home, - use_user_site=use_user_site, - name=self.name, - setup_py_path=self.setup_py_path, - isolated=self.isolated, - build_env=self.build_env, - unpacked_source_directory=self.unpacked_source_directory, - ) - self.install_succeeded = True - return - - if self.is_wheel: - assert self.local_file_path - direct_url = None - if self.original_link: - direct_url = direct_url_from_link( - self.original_link, - self.source_dir, - self.original_link_is_in_wheel_cache, - ) - install_wheel( - self.name, - self.local_file_path, - scheme=scheme, - req_description=str(self.req), - pycompile=pycompile, - warn_script_location=warn_script_location, - direct_url=direct_url, - requested=self.user_supplied, - ) - self.install_succeeded = True - return - - # TODO: Why don't we do this for editable installs? - - # Extend the list of global and install options passed on to - # the setup.py call with the ones from the requirements file. - # Options specified in requirements file override those - # specified on the command line, since the last option given - # to setup.py is the one that is used. - global_options = list(global_options) + self.global_options - install_options = list(install_options) + self.install_options - - try: - success = install_legacy( - install_options=install_options, - global_options=global_options, - root=root, - home=home, - prefix=prefix, - use_user_site=use_user_site, - pycompile=pycompile, - scheme=scheme, - setup_py_path=self.setup_py_path, - isolated=self.isolated, - req_name=self.name, - build_env=self.build_env, - unpacked_source_directory=self.unpacked_source_directory, - req_description=str(self.req), - ) - except LegacyInstallFailure as exc: - self.install_succeeded = False - six.reraise(*exc.parent) - except Exception: - self.install_succeeded = True - raise - - self.install_succeeded = success - - if success and self.legacy_install_reason == 8368: - deprecated( - reason=( - "{} was installed using the legacy 'setup.py install' " - "method, because a wheel could not be built for it.". - format(self.name) - ), - replacement="to fix the wheel build issue reported above", - gone_in=None, - issue=8368, - ) - - -def check_invalid_constraint_type(req: InstallRequirement) -> str: - - # Check for unsupported forms - problem = "" - if not req.name: - problem = "Unnamed requirements are not allowed as constraints" - elif req.editable: - problem = "Editable requirements are not allowed as constraints" - elif req.extras: - problem = "Constraints cannot have extras" - - if problem: - deprecated( - reason=( - "Constraints are only allowed to take the form of a package " - "name and a version specifier. Other forms were originally " - "permitted as an accident of the implementation, but were " - "undocumented. The new implementation of the resolver no " - "longer supports these forms." - ), - replacement="replacing the constraint with a requirement", - # No plan yet for when the new resolver becomes default - gone_in=None, - issue=8210, - ) - - return problem diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_set.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_set.py deleted file mode 100644 index 39a2b01..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_set.py +++ /dev/null @@ -1,190 +0,0 @@ -import logging -from collections import OrderedDict -from typing import Dict, Iterable, List, Optional, Tuple - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import InstallationError -from pip._internal.models.wheel import Wheel -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils import compatibility_tags - -logger = logging.getLogger(__name__) - - -class RequirementSet: - - def __init__(self, check_supported_wheels: bool = True) -> None: - """Create a RequirementSet. - """ - - self.requirements: Dict[str, InstallRequirement] = OrderedDict() - self.check_supported_wheels = check_supported_wheels - - self.unnamed_requirements: List[InstallRequirement] = [] - - def __str__(self) -> str: - requirements = sorted( - (req for req in self.requirements.values() if not req.comes_from), - key=lambda req: canonicalize_name(req.name or ""), - ) - return ' '.join(str(req.req) for req in requirements) - - def __repr__(self) -> str: - requirements = sorted( - self.requirements.values(), - key=lambda req: canonicalize_name(req.name or ""), - ) - - format_string = '<{classname} object; {count} requirement(s): {reqs}>' - return format_string.format( - classname=self.__class__.__name__, - count=len(requirements), - reqs=', '.join(str(req.req) for req in requirements), - ) - - def add_unnamed_requirement(self, install_req: InstallRequirement) -> None: - assert not install_req.name - self.unnamed_requirements.append(install_req) - - def add_named_requirement(self, install_req: InstallRequirement) -> None: - assert install_req.name - - project_name = canonicalize_name(install_req.name) - self.requirements[project_name] = install_req - - def add_requirement( - self, - install_req: InstallRequirement, - parent_req_name: Optional[str] = None, - extras_requested: Optional[Iterable[str]] = None - ) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]]: - """Add install_req as a requirement to install. - - :param parent_req_name: The name of the requirement that needed this - added. The name is used because when multiple unnamed requirements - resolve to the same name, we could otherwise end up with dependency - links that point outside the Requirements set. parent_req must - already be added. Note that None implies that this is a user - supplied requirement, vs an inferred one. - :param extras_requested: an iterable of extras used to evaluate the - environment markers. - :return: Additional requirements to scan. That is either [] if - the requirement is not applicable, or [install_req] if the - requirement is applicable and has just been added. - """ - # If the markers do not match, ignore this requirement. - if not install_req.match_markers(extras_requested): - logger.info( - "Ignoring %s: markers '%s' don't match your environment", - install_req.name, install_req.markers, - ) - return [], None - - # If the wheel is not supported, raise an error. - # Should check this after filtering out based on environment markers to - # allow specifying different wheels based on the environment/OS, in a - # single requirements file. - if install_req.link and install_req.link.is_wheel: - wheel = Wheel(install_req.link.filename) - tags = compatibility_tags.get_supported() - if (self.check_supported_wheels and not wheel.supported(tags)): - raise InstallationError( - "{} is not a supported wheel on this platform.".format( - wheel.filename) - ) - - # This next bit is really a sanity check. - assert not install_req.user_supplied or parent_req_name is None, ( - "a user supplied req shouldn't have a parent" - ) - - # Unnamed requirements are scanned again and the requirement won't be - # added as a dependency until after scanning. - if not install_req.name: - self.add_unnamed_requirement(install_req) - return [install_req], None - - try: - existing_req: Optional[InstallRequirement] = self.get_requirement( - install_req.name) - except KeyError: - existing_req = None - - has_conflicting_requirement = ( - parent_req_name is None and - existing_req and - not existing_req.constraint and - existing_req.extras == install_req.extras and - existing_req.req and - install_req.req and - existing_req.req.specifier != install_req.req.specifier - ) - if has_conflicting_requirement: - raise InstallationError( - "Double requirement given: {} (already in {}, name={!r})" - .format(install_req, existing_req, install_req.name) - ) - - # When no existing requirement exists, add the requirement as a - # dependency and it will be scanned again after. - if not existing_req: - self.add_named_requirement(install_req) - # We'd want to rescan this requirement later - return [install_req], install_req - - # Assume there's no need to scan, and that we've already - # encountered this for scanning. - if install_req.constraint or not existing_req.constraint: - return [], existing_req - - does_not_satisfy_constraint = ( - install_req.link and - not ( - existing_req.link and - install_req.link.path == existing_req.link.path - ) - ) - if does_not_satisfy_constraint: - raise InstallationError( - "Could not satisfy constraints for '{}': " - "installation from path or url cannot be " - "constrained to a version".format(install_req.name) - ) - # If we're now installing a constraint, mark the existing - # object for real installation. - existing_req.constraint = False - # If we're now installing a user supplied requirement, - # mark the existing object as such. - if install_req.user_supplied: - existing_req.user_supplied = True - existing_req.extras = tuple(sorted( - set(existing_req.extras) | set(install_req.extras) - )) - logger.debug( - "Setting %s extras to: %s", - existing_req, existing_req.extras, - ) - # Return the existing requirement for addition to the parent and - # scanning again. - return [existing_req], existing_req - - def has_requirement(self, name: str) -> bool: - project_name = canonicalize_name(name) - - return ( - project_name in self.requirements and - not self.requirements[project_name].constraint - ) - - def get_requirement(self, name: str) -> InstallRequirement: - project_name = canonicalize_name(name) - - if project_name in self.requirements: - return self.requirements[project_name] - - raise KeyError(f"No project with the name {name!r}") - - @property - def all_requirements(self) -> List[InstallRequirement]: - return self.unnamed_requirements + list(self.requirements.values()) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_tracker.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_tracker.py deleted file mode 100644 index 27c6baf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_tracker.py +++ /dev/null @@ -1,130 +0,0 @@ -import contextlib -import hashlib -import logging -import os -from types import TracebackType -from typing import Dict, Iterator, Optional, Set, Type, Union - -from pip._internal.models.link import Link -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -@contextlib.contextmanager -def update_env_context_manager(**changes: str) -> Iterator[None]: - target = os.environ - - # Save values from the target and change them. - non_existent_marker = object() - saved_values: Dict[str, Union[object, str]] = {} - for name, new_value in changes.items(): - try: - saved_values[name] = target[name] - except KeyError: - saved_values[name] = non_existent_marker - target[name] = new_value - - try: - yield - finally: - # Restore original values in the target. - for name, original_value in saved_values.items(): - if original_value is non_existent_marker: - del target[name] - else: - assert isinstance(original_value, str) # for mypy - target[name] = original_value - - -@contextlib.contextmanager -def get_requirement_tracker() -> Iterator["RequirementTracker"]: - root = os.environ.get('PIP_REQ_TRACKER') - with contextlib.ExitStack() as ctx: - if root is None: - root = ctx.enter_context( - TempDirectory(kind='req-tracker') - ).path - ctx.enter_context(update_env_context_manager(PIP_REQ_TRACKER=root)) - logger.debug("Initialized build tracking at %s", root) - - with RequirementTracker(root) as tracker: - yield tracker - - -class RequirementTracker: - - def __init__(self, root: str) -> None: - self._root = root - self._entries: Set[InstallRequirement] = set() - logger.debug("Created build tracker: %s", self._root) - - def __enter__(self) -> "RequirementTracker": - logger.debug("Entered build tracker: %s", self._root) - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType] - ) -> None: - self.cleanup() - - def _entry_path(self, link: Link) -> str: - hashed = hashlib.sha224(link.url_without_fragment.encode()).hexdigest() - return os.path.join(self._root, hashed) - - def add(self, req: InstallRequirement) -> None: - """Add an InstallRequirement to build tracking. - """ - - assert req.link - # Get the file to write information about this requirement. - entry_path = self._entry_path(req.link) - - # Try reading from the file. If it exists and can be read from, a build - # is already in progress, so a LookupError is raised. - try: - with open(entry_path) as fp: - contents = fp.read() - except FileNotFoundError: - pass - else: - message = '{} is already being built: {}'.format( - req.link, contents) - raise LookupError(message) - - # If we're here, req should really not be building already. - assert req not in self._entries - - # Start tracking this requirement. - with open(entry_path, 'w', encoding="utf-8") as fp: - fp.write(str(req)) - self._entries.add(req) - - logger.debug('Added %s to build tracker %r', req, self._root) - - def remove(self, req: InstallRequirement) -> None: - """Remove an InstallRequirement from build tracking. - """ - - assert req.link - # Delete the created file and the corresponding entries. - os.unlink(self._entry_path(req.link)) - self._entries.remove(req) - - logger.debug('Removed %s from build tracker %r', req, self._root) - - def cleanup(self) -> None: - for req in set(self._entries): - self.remove(req) - - logger.debug("Removed build tracker: %r", self._root) - - @contextlib.contextmanager - def track(self, req: InstallRequirement) -> Iterator[None]: - self.add(req) - yield - self.remove(req) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_uninstall.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_uninstall.py deleted file mode 100644 index 0c51c84..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/req/req_uninstall.py +++ /dev/null @@ -1,629 +0,0 @@ -import csv -import functools -import os -import sys -import sysconfig -from importlib.util import cache_from_source -from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Set, Tuple - -from pip._vendor import pkg_resources -from pip._vendor.pkg_resources import Distribution - -from pip._internal.exceptions import UninstallationError -from pip._internal.locations import get_bin_prefix, get_bin_user -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.logging import getLogger, indent_log -from pip._internal.utils.misc import ( - ask, - dist_in_usersite, - dist_is_local, - egg_link_path, - is_local, - normalize_path, - renames, - rmtree, -) -from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory - -logger = getLogger(__name__) - - -def _script_names(dist: Distribution, script_name: str, is_gui: bool) -> List[str]: - """Create the fully qualified name of the files created by - {console,gui}_scripts for the given ``dist``. - Returns the list of file names - """ - if dist_in_usersite(dist): - bin_dir = get_bin_user() - else: - bin_dir = get_bin_prefix() - exe_name = os.path.join(bin_dir, script_name) - paths_to_remove = [exe_name] - if WINDOWS: - paths_to_remove.append(exe_name + '.exe') - paths_to_remove.append(exe_name + '.exe.manifest') - if is_gui: - paths_to_remove.append(exe_name + '-script.pyw') - else: - paths_to_remove.append(exe_name + '-script.py') - return paths_to_remove - - -def _unique(fn: Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]]: - @functools.wraps(fn) - def unique(*args: Any, **kw: Any) -> Iterator[Any]: - seen: Set[Any] = set() - for item in fn(*args, **kw): - if item not in seen: - seen.add(item) - yield item - return unique - - -@_unique -def uninstallation_paths(dist: Distribution) -> Iterator[str]: - """ - Yield all the uninstallation paths for dist based on RECORD-without-.py[co] - - Yield paths to all the files in RECORD. For each .py file in RECORD, add - the .pyc and .pyo in the same directory. - - UninstallPathSet.add() takes care of the __pycache__ .py[co]. - - If RECORD is not found, raises UninstallationError, - with possible information from the INSTALLER file. - - https://packaging.python.org/specifications/recording-installed-packages/ - """ - try: - r = csv.reader(dist.get_metadata_lines('RECORD')) - except FileNotFoundError as missing_record_exception: - msg = 'Cannot uninstall {dist}, RECORD file not found.'.format(dist=dist) - try: - installer = next(dist.get_metadata_lines('INSTALLER')) - if not installer or installer == 'pip': - raise ValueError() - except (OSError, StopIteration, ValueError): - dep = '{}=={}'.format(dist.project_name, dist.version) - msg += (" You might be able to recover from this via: " - "'pip install --force-reinstall --no-deps {}'.".format(dep)) - else: - msg += ' Hint: The package was installed by {}.'.format(installer) - raise UninstallationError(msg) from missing_record_exception - for row in r: - path = os.path.join(dist.location, row[0]) - yield path - if path.endswith('.py'): - dn, fn = os.path.split(path) - base = fn[:-3] - path = os.path.join(dn, base + '.pyc') - yield path - path = os.path.join(dn, base + '.pyo') - yield path - - -def compact(paths: Iterable[str]) -> Set[str]: - """Compact a path set to contain the minimal number of paths - necessary to contain all paths in the set. If /a/path/ and - /a/path/to/a/file.txt are both in the set, leave only the - shorter path.""" - - sep = os.path.sep - short_paths: Set[str] = set() - for path in sorted(paths, key=len): - should_skip = any( - path.startswith(shortpath.rstrip("*")) and - path[len(shortpath.rstrip("*").rstrip(sep))] == sep - for shortpath in short_paths - ) - if not should_skip: - short_paths.add(path) - return short_paths - - -def compress_for_rename(paths: Iterable[str]) -> Set[str]: - """Returns a set containing the paths that need to be renamed. - - This set may include directories when the original sequence of paths - included every file on disk. - """ - case_map = {os.path.normcase(p): p for p in paths} - remaining = set(case_map) - unchecked = sorted({os.path.split(p)[0] for p in case_map.values()}, key=len) - wildcards: Set[str] = set() - - def norm_join(*a: str) -> str: - return os.path.normcase(os.path.join(*a)) - - for root in unchecked: - if any(os.path.normcase(root).startswith(w) - for w in wildcards): - # This directory has already been handled. - continue - - all_files: Set[str] = set() - all_subdirs: Set[str] = set() - for dirname, subdirs, files in os.walk(root): - all_subdirs.update(norm_join(root, dirname, d) - for d in subdirs) - all_files.update(norm_join(root, dirname, f) - for f in files) - # If all the files we found are in our remaining set of files to - # remove, then remove them from the latter set and add a wildcard - # for the directory. - if not (all_files - remaining): - remaining.difference_update(all_files) - wildcards.add(root + os.sep) - - return set(map(case_map.__getitem__, remaining)) | wildcards - - -def compress_for_output_listing(paths: Iterable[str]) -> Tuple[Set[str], Set[str]]: - """Returns a tuple of 2 sets of which paths to display to user - - The first set contains paths that would be deleted. Files of a package - are not added and the top-level directory of the package has a '*' added - at the end - to signify that all it's contents are removed. - - The second set contains files that would have been skipped in the above - folders. - """ - - will_remove = set(paths) - will_skip = set() - - # Determine folders and files - folders = set() - files = set() - for path in will_remove: - if path.endswith(".pyc"): - continue - if path.endswith("__init__.py") or ".dist-info" in path: - folders.add(os.path.dirname(path)) - files.add(path) - - # probably this one https://github.com/python/mypy/issues/390 - _normcased_files = set(map(os.path.normcase, files)) # type: ignore - - folders = compact(folders) - - # This walks the tree using os.walk to not miss extra folders - # that might get added. - for folder in folders: - for dirpath, _, dirfiles in os.walk(folder): - for fname in dirfiles: - if fname.endswith(".pyc"): - continue - - file_ = os.path.join(dirpath, fname) - if (os.path.isfile(file_) and - os.path.normcase(file_) not in _normcased_files): - # We are skipping this file. Add it to the set. - will_skip.add(file_) - - will_remove = files | { - os.path.join(folder, "*") for folder in folders - } - - return will_remove, will_skip - - -class StashedUninstallPathSet: - """A set of file rename operations to stash files while - tentatively uninstalling them.""" - def __init__(self) -> None: - # Mapping from source file root to [Adjacent]TempDirectory - # for files under that directory. - self._save_dirs: Dict[str, TempDirectory] = {} - # (old path, new path) tuples for each move that may need - # to be undone. - self._moves: List[Tuple[str, str]] = [] - - def _get_directory_stash(self, path: str) -> str: - """Stashes a directory. - - Directories are stashed adjacent to their original location if - possible, or else moved/copied into the user's temp dir.""" - - try: - save_dir: TempDirectory = AdjacentTempDirectory(path) - except OSError: - save_dir = TempDirectory(kind="uninstall") - self._save_dirs[os.path.normcase(path)] = save_dir - - return save_dir.path - - def _get_file_stash(self, path: str) -> str: - """Stashes a file. - - If no root has been provided, one will be created for the directory - in the user's temp directory.""" - path = os.path.normcase(path) - head, old_head = os.path.dirname(path), None - save_dir = None - - while head != old_head: - try: - save_dir = self._save_dirs[head] - break - except KeyError: - pass - head, old_head = os.path.dirname(head), head - else: - # Did not find any suitable root - head = os.path.dirname(path) - save_dir = TempDirectory(kind='uninstall') - self._save_dirs[head] = save_dir - - relpath = os.path.relpath(path, head) - if relpath and relpath != os.path.curdir: - return os.path.join(save_dir.path, relpath) - return save_dir.path - - def stash(self, path: str) -> str: - """Stashes the directory or file and returns its new location. - Handle symlinks as files to avoid modifying the symlink targets. - """ - path_is_dir = os.path.isdir(path) and not os.path.islink(path) - if path_is_dir: - new_path = self._get_directory_stash(path) - else: - new_path = self._get_file_stash(path) - - self._moves.append((path, new_path)) - if (path_is_dir and os.path.isdir(new_path)): - # If we're moving a directory, we need to - # remove the destination first or else it will be - # moved to inside the existing directory. - # We just created new_path ourselves, so it will - # be removable. - os.rmdir(new_path) - renames(path, new_path) - return new_path - - def commit(self) -> None: - """Commits the uninstall by removing stashed files.""" - for _, save_dir in self._save_dirs.items(): - save_dir.cleanup() - self._moves = [] - self._save_dirs = {} - - def rollback(self) -> None: - """Undoes the uninstall by moving stashed files back.""" - for p in self._moves: - logger.info("Moving to %s\n from %s", *p) - - for new_path, path in self._moves: - try: - logger.debug('Replacing %s from %s', new_path, path) - if os.path.isfile(new_path) or os.path.islink(new_path): - os.unlink(new_path) - elif os.path.isdir(new_path): - rmtree(new_path) - renames(path, new_path) - except OSError as ex: - logger.error("Failed to restore %s", new_path) - logger.debug("Exception: %s", ex) - - self.commit() - - @property - def can_rollback(self) -> bool: - return bool(self._moves) - - -class UninstallPathSet: - """A set of file paths to be removed in the uninstallation of a - requirement.""" - def __init__(self, dist: Distribution) -> None: - self.paths: Set[str] = set() - self._refuse: Set[str] = set() - self.pth: Dict[str, UninstallPthEntries] = {} - self.dist = dist - self._moved_paths = StashedUninstallPathSet() - - def _permitted(self, path: str) -> bool: - """ - Return True if the given path is one we are permitted to - remove/modify, False otherwise. - - """ - return is_local(path) - - def add(self, path: str) -> None: - head, tail = os.path.split(path) - - # we normalize the head to resolve parent directory symlinks, but not - # the tail, since we only want to uninstall symlinks, not their targets - path = os.path.join(normalize_path(head), os.path.normcase(tail)) - - if not os.path.exists(path): - return - if self._permitted(path): - self.paths.add(path) - else: - self._refuse.add(path) - - # __pycache__ files can show up after 'installed-files.txt' is created, - # due to imports - if os.path.splitext(path)[1] == '.py': - self.add(cache_from_source(path)) - - def add_pth(self, pth_file: str, entry: str) -> None: - pth_file = normalize_path(pth_file) - if self._permitted(pth_file): - if pth_file not in self.pth: - self.pth[pth_file] = UninstallPthEntries(pth_file) - self.pth[pth_file].add(entry) - else: - self._refuse.add(pth_file) - - def remove(self, auto_confirm: bool = False, verbose: bool = False) -> None: - """Remove paths in ``self.paths`` with confirmation (unless - ``auto_confirm`` is True).""" - - if not self.paths: - logger.info( - "Can't uninstall '%s'. No files were found to uninstall.", - self.dist.project_name, - ) - return - - dist_name_version = ( - self.dist.project_name + "-" + self.dist.version - ) - logger.info('Uninstalling %s:', dist_name_version) - - with indent_log(): - if auto_confirm or self._allowed_to_proceed(verbose): - moved = self._moved_paths - - for_rename = compress_for_rename(self.paths) - - for path in sorted(compact(for_rename)): - moved.stash(path) - logger.verbose('Removing file or directory %s', path) - - for pth in self.pth.values(): - pth.remove() - - logger.info('Successfully uninstalled %s', dist_name_version) - - def _allowed_to_proceed(self, verbose: bool) -> bool: - """Display which files would be deleted and prompt for confirmation - """ - - def _display(msg: str, paths: Iterable[str]) -> None: - if not paths: - return - - logger.info(msg) - with indent_log(): - for path in sorted(compact(paths)): - logger.info(path) - - if not verbose: - will_remove, will_skip = compress_for_output_listing(self.paths) - else: - # In verbose mode, display all the files that are going to be - # deleted. - will_remove = set(self.paths) - will_skip = set() - - _display('Would remove:', will_remove) - _display('Would not remove (might be manually added):', will_skip) - _display('Would not remove (outside of prefix):', self._refuse) - if verbose: - _display('Will actually move:', compress_for_rename(self.paths)) - - return ask('Proceed (Y/n)? ', ('y', 'n', '')) != 'n' - - def rollback(self) -> None: - """Rollback the changes previously made by remove().""" - if not self._moved_paths.can_rollback: - logger.error( - "Can't roll back %s; was not uninstalled", - self.dist.project_name, - ) - return - logger.info('Rolling back uninstall of %s', self.dist.project_name) - self._moved_paths.rollback() - for pth in self.pth.values(): - pth.rollback() - - def commit(self) -> None: - """Remove temporary save dir: rollback will no longer be possible.""" - self._moved_paths.commit() - - @classmethod - def from_dist(cls, dist: Distribution) -> "UninstallPathSet": - dist_path = normalize_path(dist.location) - if not dist_is_local(dist): - logger.info( - "Not uninstalling %s at %s, outside environment %s", - dist.key, - dist_path, - sys.prefix, - ) - return cls(dist) - - if dist_path in {p for p in {sysconfig.get_path("stdlib"), - sysconfig.get_path("platstdlib")} - if p}: - logger.info( - "Not uninstalling %s at %s, as it is in the standard library.", - dist.key, - dist_path, - ) - return cls(dist) - - paths_to_remove = cls(dist) - develop_egg_link = egg_link_path(dist) - develop_egg_link_egg_info = '{}.egg-info'.format( - pkg_resources.to_filename(dist.project_name)) - egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) - # Special case for distutils installed package - distutils_egg_info = getattr(dist._provider, 'path', None) - - # Uninstall cases order do matter as in the case of 2 installs of the - # same package, pip needs to uninstall the currently detected version - if (egg_info_exists and dist.egg_info.endswith('.egg-info') and - not dist.egg_info.endswith(develop_egg_link_egg_info)): - # if dist.egg_info.endswith(develop_egg_link_egg_info), we - # are in fact in the develop_egg_link case - paths_to_remove.add(dist.egg_info) - if dist.has_metadata('installed-files.txt'): - for installed_file in dist.get_metadata( - 'installed-files.txt').splitlines(): - path = os.path.normpath( - os.path.join(dist.egg_info, installed_file) - ) - paths_to_remove.add(path) - # FIXME: need a test for this elif block - # occurs with --single-version-externally-managed/--record outside - # of pip - elif dist.has_metadata('top_level.txt'): - if dist.has_metadata('namespace_packages.txt'): - namespaces = dist.get_metadata('namespace_packages.txt') - else: - namespaces = [] - for top_level_pkg in [ - p for p - in dist.get_metadata('top_level.txt').splitlines() - if p and p not in namespaces]: - path = os.path.join(dist.location, top_level_pkg) - paths_to_remove.add(path) - paths_to_remove.add(path + '.py') - paths_to_remove.add(path + '.pyc') - paths_to_remove.add(path + '.pyo') - - elif distutils_egg_info: - raise UninstallationError( - "Cannot uninstall {!r}. It is a distutils installed project " - "and thus we cannot accurately determine which files belong " - "to it which would lead to only a partial uninstall.".format( - dist.project_name, - ) - ) - - elif dist.location.endswith('.egg'): - # package installed by easy_install - # We cannot match on dist.egg_name because it can slightly vary - # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg - paths_to_remove.add(dist.location) - easy_install_egg = os.path.split(dist.location)[1] - easy_install_pth = os.path.join(os.path.dirname(dist.location), - 'easy-install.pth') - paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) - - elif egg_info_exists and dist.egg_info.endswith('.dist-info'): - for path in uninstallation_paths(dist): - paths_to_remove.add(path) - - elif develop_egg_link: - # develop egg - with open(develop_egg_link) as fh: - link_pointer = os.path.normcase(fh.readline().strip()) - assert (link_pointer == dist.location), ( - 'Egg-link {} does not match installed location of {} ' - '(at {})'.format( - link_pointer, dist.project_name, dist.location) - ) - paths_to_remove.add(develop_egg_link) - easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), - 'easy-install.pth') - paths_to_remove.add_pth(easy_install_pth, dist.location) - - else: - logger.debug( - 'Not sure how to uninstall: %s - Check: %s', - dist, dist.location, - ) - - # find distutils scripts= scripts - if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): - for script in dist.metadata_listdir('scripts'): - if dist_in_usersite(dist): - bin_dir = get_bin_user() - else: - bin_dir = get_bin_prefix() - paths_to_remove.add(os.path.join(bin_dir, script)) - if WINDOWS: - paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') - - # find console_scripts - _scripts_to_remove = [] - console_scripts = dist.get_entry_map(group='console_scripts') - for name in console_scripts.keys(): - _scripts_to_remove.extend(_script_names(dist, name, False)) - # find gui_scripts - gui_scripts = dist.get_entry_map(group='gui_scripts') - for name in gui_scripts.keys(): - _scripts_to_remove.extend(_script_names(dist, name, True)) - - for s in _scripts_to_remove: - paths_to_remove.add(s) - - return paths_to_remove - - -class UninstallPthEntries: - def __init__(self, pth_file: str) -> None: - self.file = pth_file - self.entries: Set[str] = set() - self._saved_lines: Optional[List[bytes]] = None - - def add(self, entry: str) -> None: - entry = os.path.normcase(entry) - # On Windows, os.path.normcase converts the entry to use - # backslashes. This is correct for entries that describe absolute - # paths outside of site-packages, but all the others use forward - # slashes. - # os.path.splitdrive is used instead of os.path.isabs because isabs - # treats non-absolute paths with drive letter markings like c:foo\bar - # as absolute paths. It also does not recognize UNC paths if they don't - # have more than "\\sever\share". Valid examples: "\\server\share\" or - # "\\server\share\folder". - if WINDOWS and not os.path.splitdrive(entry)[0]: - entry = entry.replace('\\', '/') - self.entries.add(entry) - - def remove(self) -> None: - logger.verbose('Removing pth entries from %s:', self.file) - - # If the file doesn't exist, log a warning and return - if not os.path.isfile(self.file): - logger.warning( - "Cannot remove entries from nonexistent file %s", self.file - ) - return - with open(self.file, 'rb') as fh: - # windows uses '\r\n' with py3k, but uses '\n' with py2.x - lines = fh.readlines() - self._saved_lines = lines - if any(b'\r\n' in line for line in lines): - endline = '\r\n' - else: - endline = '\n' - # handle missing trailing newline - if lines and not lines[-1].endswith(endline.encode("utf-8")): - lines[-1] = lines[-1] + endline.encode("utf-8") - for entry in self.entries: - try: - logger.verbose('Removing entry: %s', entry) - lines.remove((entry + endline).encode("utf-8")) - except ValueError: - pass - with open(self.file, 'wb') as fh: - fh.writelines(lines) - - def rollback(self) -> bool: - if self._saved_lines is None: - logger.error( - 'Cannot roll back changes to %s, none were made', self.file - ) - return False - logger.debug('Rolling %s back to previous state', self.file) - with open(self.file, 'wb') as fh: - fh.writelines(self._saved_lines) - return True diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/base.py deleted file mode 100644 index 3f83ef0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/base.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Callable, List - -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_set import RequirementSet - -InstallRequirementProvider = Callable[[str, InstallRequirement], InstallRequirement] - - -class BaseResolver: - def resolve( - self, root_reqs: List[InstallRequirement], check_supported_wheels: bool - ) -> RequirementSet: - raise NotImplementedError() - - def get_installation_order( - self, req_set: RequirementSet - ) -> List[InstallRequirement]: - raise NotImplementedError() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/legacy/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/legacy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/legacy/resolver.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/legacy/resolver.py deleted file mode 100644 index 4df8f7e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/legacy/resolver.py +++ /dev/null @@ -1,453 +0,0 @@ -"""Dependency Resolution - -The dependency resolution in pip is performed as follows: - -for top-level requirements: - a. only one spec allowed per project, regardless of conflicts or not. - otherwise a "double requirement" exception is raised - b. they override sub-dependency requirements. -for sub-dependencies - a. "first found, wins" (where the order is breadth first) -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import sys -from collections import defaultdict -from itertools import chain -from typing import DefaultDict, Iterable, List, Optional, Set, Tuple - -from pip._vendor.packaging import specifiers -from pip._vendor.pkg_resources import Distribution - -from pip._internal.cache import WheelCache -from pip._internal.exceptions import ( - BestVersionAlreadyInstalled, - DistributionNotFound, - HashError, - HashErrors, - UnsupportedPythonVersion, -) -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.link import Link -from pip._internal.operations.prepare import RequirementPreparer -from pip._internal.req.req_install import ( - InstallRequirement, - check_invalid_constraint_type, -) -from pip._internal.req.req_set import RequirementSet -from pip._internal.resolution.base import BaseResolver, InstallRequirementProvider -from pip._internal.utils.compatibility_tags import get_supported -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import dist_in_usersite, normalize_version_info -from pip._internal.utils.packaging import check_requires_python, get_requires_python - -logger = logging.getLogger(__name__) - -DiscoveredDependencies = DefaultDict[str, List[InstallRequirement]] - - -def _check_dist_requires_python( - dist: Distribution, - version_info: Tuple[int, int, int], - ignore_requires_python: bool = False, -) -> None: - """ - Check whether the given Python version is compatible with a distribution's - "Requires-Python" value. - - :param version_info: A 3-tuple of ints representing the Python - major-minor-micro version to check. - :param ignore_requires_python: Whether to ignore the "Requires-Python" - value if the given Python version isn't compatible. - - :raises UnsupportedPythonVersion: When the given Python version isn't - compatible. - """ - requires_python = get_requires_python(dist) - try: - is_compatible = check_requires_python( - requires_python, version_info=version_info - ) - except specifiers.InvalidSpecifier as exc: - logger.warning( - "Package %r has an invalid Requires-Python: %s", dist.project_name, exc - ) - return - - if is_compatible: - return - - version = ".".join(map(str, version_info)) - if ignore_requires_python: - logger.debug( - "Ignoring failed Requires-Python check for package %r: %s not in %r", - dist.project_name, - version, - requires_python, - ) - return - - raise UnsupportedPythonVersion( - "Package {!r} requires a different Python: {} not in {!r}".format( - dist.project_name, version, requires_python - ) - ) - - -class Resolver(BaseResolver): - """Resolves which packages need to be installed/uninstalled to perform \ - the requested operation without breaking the requirements of any package. - """ - - _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} - - def __init__( - self, - preparer: RequirementPreparer, - finder: PackageFinder, - wheel_cache: Optional[WheelCache], - make_install_req: InstallRequirementProvider, - use_user_site: bool, - ignore_dependencies: bool, - ignore_installed: bool, - ignore_requires_python: bool, - force_reinstall: bool, - upgrade_strategy: str, - py_version_info: Optional[Tuple[int, ...]] = None, - ) -> None: - super().__init__() - assert upgrade_strategy in self._allowed_strategies - - if py_version_info is None: - py_version_info = sys.version_info[:3] - else: - py_version_info = normalize_version_info(py_version_info) - - self._py_version_info = py_version_info - - self.preparer = preparer - self.finder = finder - self.wheel_cache = wheel_cache - - self.upgrade_strategy = upgrade_strategy - self.force_reinstall = force_reinstall - self.ignore_dependencies = ignore_dependencies - self.ignore_installed = ignore_installed - self.ignore_requires_python = ignore_requires_python - self.use_user_site = use_user_site - self._make_install_req = make_install_req - - self._discovered_dependencies: DiscoveredDependencies = defaultdict(list) - - def resolve( - self, root_reqs: List[InstallRequirement], check_supported_wheels: bool - ) -> RequirementSet: - """Resolve what operations need to be done - - As a side-effect of this method, the packages (and their dependencies) - are downloaded, unpacked and prepared for installation. This - preparation is done by ``pip.operations.prepare``. - - Once PyPI has static dependency metadata available, it would be - possible to move the preparation to become a step separated from - dependency resolution. - """ - requirement_set = RequirementSet(check_supported_wheels=check_supported_wheels) - for req in root_reqs: - if req.constraint: - check_invalid_constraint_type(req) - requirement_set.add_requirement(req) - - # Actually prepare the files, and collect any exceptions. Most hash - # exceptions cannot be checked ahead of time, because - # _populate_link() needs to be called before we can make decisions - # based on link type. - discovered_reqs: List[InstallRequirement] = [] - hash_errors = HashErrors() - for req in chain(requirement_set.all_requirements, discovered_reqs): - try: - discovered_reqs.extend(self._resolve_one(requirement_set, req)) - except HashError as exc: - exc.req = req - hash_errors.append(exc) - - if hash_errors: - raise hash_errors - - return requirement_set - - def _is_upgrade_allowed(self, req: InstallRequirement) -> bool: - if self.upgrade_strategy == "to-satisfy-only": - return False - elif self.upgrade_strategy == "eager": - return True - else: - assert self.upgrade_strategy == "only-if-needed" - return req.user_supplied or req.constraint - - def _set_req_to_reinstall(self, req: InstallRequirement) -> None: - """ - Set a requirement to be installed. - """ - # Don't uninstall the conflict if doing a user install and the - # conflict is not a user install. - if not self.use_user_site or dist_in_usersite(req.satisfied_by): - req.should_reinstall = True - req.satisfied_by = None - - def _check_skip_installed( - self, req_to_install: InstallRequirement - ) -> Optional[str]: - """Check if req_to_install should be skipped. - - This will check if the req is installed, and whether we should upgrade - or reinstall it, taking into account all the relevant user options. - - After calling this req_to_install will only have satisfied_by set to - None if the req_to_install is to be upgraded/reinstalled etc. Any - other value will be a dist recording the current thing installed that - satisfies the requirement. - - Note that for vcs urls and the like we can't assess skipping in this - routine - we simply identify that we need to pull the thing down, - then later on it is pulled down and introspected to assess upgrade/ - reinstalls etc. - - :return: A text reason for why it was skipped, or None. - """ - if self.ignore_installed: - return None - - req_to_install.check_if_exists(self.use_user_site) - if not req_to_install.satisfied_by: - return None - - if self.force_reinstall: - self._set_req_to_reinstall(req_to_install) - return None - - if not self._is_upgrade_allowed(req_to_install): - if self.upgrade_strategy == "only-if-needed": - return "already satisfied, skipping upgrade" - return "already satisfied" - - # Check for the possibility of an upgrade. For link-based - # requirements we have to pull the tree down and inspect to assess - # the version #, so it's handled way down. - if not req_to_install.link: - try: - self.finder.find_requirement(req_to_install, upgrade=True) - except BestVersionAlreadyInstalled: - # Then the best version is installed. - return "already up-to-date" - except DistributionNotFound: - # No distribution found, so we squash the error. It will - # be raised later when we re-try later to do the install. - # Why don't we just raise here? - pass - - self._set_req_to_reinstall(req_to_install) - return None - - def _find_requirement_link(self, req: InstallRequirement) -> Optional[Link]: - upgrade = self._is_upgrade_allowed(req) - best_candidate = self.finder.find_requirement(req, upgrade) - if not best_candidate: - return None - - # Log a warning per PEP 592 if necessary before returning. - link = best_candidate.link - if link.is_yanked: - reason = link.yanked_reason or "" - msg = ( - # Mark this as a unicode string to prevent - # "UnicodeEncodeError: 'ascii' codec can't encode character" - # in Python 2 when the reason contains non-ascii characters. - "The candidate selected for download or install is a " - "yanked version: {candidate}\n" - "Reason for being yanked: {reason}" - ).format(candidate=best_candidate, reason=reason) - logger.warning(msg) - - return link - - def _populate_link(self, req: InstallRequirement) -> None: - """Ensure that if a link can be found for this, that it is found. - - Note that req.link may still be None - if the requirement is already - installed and not needed to be upgraded based on the return value of - _is_upgrade_allowed(). - - If preparer.require_hashes is True, don't use the wheel cache, because - cached wheels, always built locally, have different hashes than the - files downloaded from the index server and thus throw false hash - mismatches. Furthermore, cached wheels at present have undeterministic - contents due to file modification times. - """ - if req.link is None: - req.link = self._find_requirement_link(req) - - if self.wheel_cache is None or self.preparer.require_hashes: - return - cache_entry = self.wheel_cache.get_cache_entry( - link=req.link, - package_name=req.name, - supported_tags=get_supported(), - ) - if cache_entry is not None: - logger.debug("Using cached wheel link: %s", cache_entry.link) - if req.link is req.original_link and cache_entry.persistent: - req.original_link_is_in_wheel_cache = True - req.link = cache_entry.link - - def _get_dist_for(self, req: InstallRequirement) -> Distribution: - """Takes a InstallRequirement and returns a single AbstractDist \ - representing a prepared variant of the same. - """ - if req.editable: - return self.preparer.prepare_editable_requirement(req) - - # satisfied_by is only evaluated by calling _check_skip_installed, - # so it must be None here. - assert req.satisfied_by is None - skip_reason = self._check_skip_installed(req) - - if req.satisfied_by: - return self.preparer.prepare_installed_requirement(req, skip_reason) - - # We eagerly populate the link, since that's our "legacy" behavior. - self._populate_link(req) - dist = self.preparer.prepare_linked_requirement(req) - - # NOTE - # The following portion is for determining if a certain package is - # going to be re-installed/upgraded or not and reporting to the user. - # This should probably get cleaned up in a future refactor. - - # req.req is only avail after unpack for URL - # pkgs repeat check_if_exists to uninstall-on-upgrade - # (#14) - if not self.ignore_installed: - req.check_if_exists(self.use_user_site) - - if req.satisfied_by: - should_modify = ( - self.upgrade_strategy != "to-satisfy-only" - or self.force_reinstall - or self.ignore_installed - or req.link.scheme == "file" - ) - if should_modify: - self._set_req_to_reinstall(req) - else: - logger.info( - "Requirement already satisfied (use --upgrade to upgrade): %s", - req, - ) - return dist - - def _resolve_one( - self, - requirement_set: RequirementSet, - req_to_install: InstallRequirement, - ) -> List[InstallRequirement]: - """Prepare a single requirements file. - - :return: A list of additional InstallRequirements to also install. - """ - # Tell user what we are doing for this requirement: - # obtain (editable), skipping, processing (local url), collecting - # (remote url or package name) - if req_to_install.constraint or req_to_install.prepared: - return [] - - req_to_install.prepared = True - - # Parse and return dependencies - dist = self._get_dist_for(req_to_install) - # This will raise UnsupportedPythonVersion if the given Python - # version isn't compatible with the distribution's Requires-Python. - _check_dist_requires_python( - dist, - version_info=self._py_version_info, - ignore_requires_python=self.ignore_requires_python, - ) - - more_reqs: List[InstallRequirement] = [] - - def add_req(subreq: Distribution, extras_requested: Iterable[str]) -> None: - sub_install_req = self._make_install_req( - str(subreq), - req_to_install, - ) - parent_req_name = req_to_install.name - to_scan_again, add_to_parent = requirement_set.add_requirement( - sub_install_req, - parent_req_name=parent_req_name, - extras_requested=extras_requested, - ) - if parent_req_name and add_to_parent: - self._discovered_dependencies[parent_req_name].append(add_to_parent) - more_reqs.extend(to_scan_again) - - with indent_log(): - # We add req_to_install before its dependencies, so that we - # can refer to it when adding dependencies. - if not requirement_set.has_requirement(req_to_install.name): - # 'unnamed' requirements will get added here - # 'unnamed' requirements can only come from being directly - # provided by the user. - assert req_to_install.user_supplied - requirement_set.add_requirement(req_to_install, parent_req_name=None) - - if not self.ignore_dependencies: - if req_to_install.extras: - logger.debug( - "Installing extra requirements: %r", - ",".join(req_to_install.extras), - ) - missing_requested = sorted( - set(req_to_install.extras) - set(dist.extras) - ) - for missing in missing_requested: - logger.warning("%s does not provide the extra '%s'", dist, missing) - - available_requested = sorted( - set(dist.extras) & set(req_to_install.extras) - ) - for subreq in dist.requires(available_requested): - add_req(subreq, extras_requested=available_requested) - - return more_reqs - - def get_installation_order( - self, req_set: RequirementSet - ) -> List[InstallRequirement]: - """Create the installation order. - - The installation order is topological - requirements are installed - before the requiring thing. We break cycles at an arbitrary point, - and make no other guarantees. - """ - # The current implementation, which we may change at any point - # installs the user specified things in the order given, except when - # dependencies must come earlier to achieve topological order. - order = [] - ordered_reqs: Set[InstallRequirement] = set() - - def schedule(req: InstallRequirement) -> None: - if req.satisfied_by or req in ordered_reqs: - return - if req.constraint: - return - ordered_reqs.add(req) - for dep in self._discovered_dependencies[req.name]: - schedule(dep) - order.append(req) - - for install_req in req_set.requirements.values(): - schedule(install_req) - return order diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/base.py deleted file mode 100644 index 7f258c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/base.py +++ /dev/null @@ -1,144 +0,0 @@ -from typing import FrozenSet, Iterable, Optional, Tuple, Union - -from pip._vendor.packaging.specifiers import SpecifierSet -from pip._vendor.packaging.utils import NormalizedName, canonicalize_name -from pip._vendor.packaging.version import LegacyVersion, Version - -from pip._internal.models.link import Link, links_equivalent -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.hashes import Hashes - -CandidateLookup = Tuple[Optional["Candidate"], Optional[InstallRequirement]] -CandidateVersion = Union[LegacyVersion, Version] - - -def format_name(project: str, extras: FrozenSet[str]) -> str: - if not extras: - return project - canonical_extras = sorted(canonicalize_name(e) for e in extras) - return "{}[{}]".format(project, ",".join(canonical_extras)) - - -class Constraint: - def __init__( - self, specifier: SpecifierSet, hashes: Hashes, links: FrozenSet[Link] - ) -> None: - self.specifier = specifier - self.hashes = hashes - self.links = links - - @classmethod - def empty(cls) -> "Constraint": - return Constraint(SpecifierSet(), Hashes(), frozenset()) - - @classmethod - def from_ireq(cls, ireq: InstallRequirement) -> "Constraint": - links = frozenset([ireq.link]) if ireq.link else frozenset() - return Constraint(ireq.specifier, ireq.hashes(trust_internet=False), links) - - def __nonzero__(self) -> bool: - return bool(self.specifier) or bool(self.hashes) or bool(self.links) - - def __bool__(self) -> bool: - return self.__nonzero__() - - def __and__(self, other: InstallRequirement) -> "Constraint": - if not isinstance(other, InstallRequirement): - return NotImplemented - specifier = self.specifier & other.specifier - hashes = self.hashes & other.hashes(trust_internet=False) - links = self.links - if other.link: - links = links.union([other.link]) - return Constraint(specifier, hashes, links) - - def is_satisfied_by(self, candidate: "Candidate") -> bool: - # Reject if there are any mismatched URL constraints on this package. - if self.links and not all(_match_link(link, candidate) for link in self.links): - return False - # We can safely always allow prereleases here since PackageFinder - # already implements the prerelease logic, and would have filtered out - # prerelease candidates if the user does not expect them. - return self.specifier.contains(candidate.version, prereleases=True) - - -class Requirement: - @property - def project_name(self) -> NormalizedName: - """The "project name" of a requirement. - - This is different from ``name`` if this requirement contains extras, - in which case ``name`` would contain the ``[...]`` part, while this - refers to the name of the project. - """ - raise NotImplementedError("Subclass should override") - - @property - def name(self) -> str: - """The name identifying this requirement in the resolver. - - This is different from ``project_name`` if this requirement contains - extras, where ``project_name`` would not contain the ``[...]`` part. - """ - raise NotImplementedError("Subclass should override") - - def is_satisfied_by(self, candidate: "Candidate") -> bool: - return False - - def get_candidate_lookup(self) -> CandidateLookup: - raise NotImplementedError("Subclass should override") - - def format_for_error(self) -> str: - raise NotImplementedError("Subclass should override") - - -def _match_link(link: Link, candidate: "Candidate") -> bool: - if candidate.source_link: - return links_equivalent(link, candidate.source_link) - return False - - -class Candidate: - @property - def project_name(self) -> NormalizedName: - """The "project name" of the candidate. - - This is different from ``name`` if this candidate contains extras, - in which case ``name`` would contain the ``[...]`` part, while this - refers to the name of the project. - """ - raise NotImplementedError("Override in subclass") - - @property - def name(self) -> str: - """The name identifying this candidate in the resolver. - - This is different from ``project_name`` if this candidate contains - extras, where ``project_name`` would not contain the ``[...]`` part. - """ - raise NotImplementedError("Override in subclass") - - @property - def version(self) -> CandidateVersion: - raise NotImplementedError("Override in subclass") - - @property - def is_installed(self) -> bool: - raise NotImplementedError("Override in subclass") - - @property - def is_editable(self) -> bool: - raise NotImplementedError("Override in subclass") - - @property - def source_link(self) -> Optional[Link]: - raise NotImplementedError("Override in subclass") - - def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: - raise NotImplementedError("Override in subclass") - - def get_install_requirement(self) -> Optional[InstallRequirement]: - raise NotImplementedError("Override in subclass") - - def format_for_error(self) -> str: - raise NotImplementedError("Subclass should override") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py deleted file mode 100644 index 5d510db..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py +++ /dev/null @@ -1,555 +0,0 @@ -import logging -import sys -from typing import TYPE_CHECKING, Any, FrozenSet, Iterable, Optional, Tuple, Union, cast - -from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet -from pip._vendor.packaging.utils import NormalizedName, canonicalize_name -from pip._vendor.packaging.version import Version -from pip._vendor.packaging.version import parse as parse_version -from pip._vendor.pkg_resources import Distribution - -from pip._internal.exceptions import HashError, MetadataInconsistent -from pip._internal.models.link import Link, links_equivalent -from pip._internal.models.wheel import Wheel -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, -) -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.misc import dist_is_editable, normalize_version_info -from pip._internal.utils.packaging import get_requires_python - -from .base import Candidate, CandidateVersion, Requirement, format_name - -if TYPE_CHECKING: - from .factory import Factory - -logger = logging.getLogger(__name__) - -BaseCandidate = Union[ - "AlreadyInstalledCandidate", - "EditableCandidate", - "LinkCandidate", -] - -# Avoid conflicting with the PyPI package "Python". -REQUIRES_PYTHON_IDENTIFIER = cast(NormalizedName, "") - - -def as_base_candidate(candidate: Candidate) -> Optional[BaseCandidate]: - """The runtime version of BaseCandidate.""" - base_candidate_classes = ( - AlreadyInstalledCandidate, - EditableCandidate, - LinkCandidate, - ) - if isinstance(candidate, base_candidate_classes): - return candidate - return None - - -def make_install_req_from_link( - link: Link, template: InstallRequirement -) -> InstallRequirement: - assert not template.editable, "template is editable" - if template.req: - line = str(template.req) - else: - line = link.url - ireq = install_req_from_line( - line, - user_supplied=template.user_supplied, - comes_from=template.comes_from, - use_pep517=template.use_pep517, - isolated=template.isolated, - constraint=template.constraint, - options=dict( - install_options=template.install_options, - global_options=template.global_options, - hashes=template.hash_options, - ), - ) - ireq.original_link = template.original_link - ireq.link = link - return ireq - - -def make_install_req_from_editable( - link: Link, template: InstallRequirement -) -> InstallRequirement: - assert template.editable, "template not editable" - return install_req_from_editable( - link.url, - user_supplied=template.user_supplied, - comes_from=template.comes_from, - use_pep517=template.use_pep517, - isolated=template.isolated, - constraint=template.constraint, - options=dict( - install_options=template.install_options, - global_options=template.global_options, - hashes=template.hash_options, - ), - ) - - -def make_install_req_from_dist( - dist: Distribution, template: InstallRequirement -) -> InstallRequirement: - project_name = canonicalize_name(dist.project_name) - if template.req: - line = str(template.req) - elif template.link: - line = f"{project_name} @ {template.link.url}" - else: - line = f"{project_name}=={dist.parsed_version}" - ireq = install_req_from_line( - line, - user_supplied=template.user_supplied, - comes_from=template.comes_from, - use_pep517=template.use_pep517, - isolated=template.isolated, - constraint=template.constraint, - options=dict( - install_options=template.install_options, - global_options=template.global_options, - hashes=template.hash_options, - ), - ) - ireq.satisfied_by = dist - return ireq - - -class _InstallRequirementBackedCandidate(Candidate): - """A candidate backed by an ``InstallRequirement``. - - This represents a package request with the target not being already - in the environment, and needs to be fetched and installed. The backing - ``InstallRequirement`` is responsible for most of the leg work; this - class exposes appropriate information to the resolver. - - :param link: The link passed to the ``InstallRequirement``. The backing - ``InstallRequirement`` will use this link to fetch the distribution. - :param source_link: The link this candidate "originates" from. This is - different from ``link`` when the link is found in the wheel cache. - ``link`` would point to the wheel cache, while this points to the - found remote link (e.g. from pypi.org). - """ - - is_installed = False - - def __init__( - self, - link: Link, - source_link: Link, - ireq: InstallRequirement, - factory: "Factory", - name: Optional[NormalizedName] = None, - version: Optional[CandidateVersion] = None, - ) -> None: - self._link = link - self._source_link = source_link - self._factory = factory - self._ireq = ireq - self._name = name - self._version = version - self.dist = self._prepare() - - def __str__(self) -> str: - return f"{self.name} {self.version}" - - def __repr__(self) -> str: - return "{class_name}({link!r})".format( - class_name=self.__class__.__name__, - link=str(self._link), - ) - - def __hash__(self) -> int: - return hash((self.__class__, self._link)) - - def __eq__(self, other: Any) -> bool: - if isinstance(other, self.__class__): - return links_equivalent(self._link, other._link) - return False - - @property - def source_link(self) -> Optional[Link]: - return self._source_link - - @property - def project_name(self) -> NormalizedName: - """The normalised name of the project the candidate refers to""" - if self._name is None: - self._name = canonicalize_name(self.dist.project_name) - return self._name - - @property - def name(self) -> str: - return self.project_name - - @property - def version(self) -> CandidateVersion: - if self._version is None: - self._version = parse_version(self.dist.version) - return self._version - - def format_for_error(self) -> str: - return "{} {} (from {})".format( - self.name, - self.version, - self._link.file_path if self._link.is_file else self._link, - ) - - def _prepare_distribution(self) -> Distribution: - raise NotImplementedError("Override in subclass") - - def _check_metadata_consistency(self, dist: Distribution) -> None: - """Check for consistency of project name and version of dist.""" - canonical_name = canonicalize_name(dist.project_name) - if self._name is not None and self._name != canonical_name: - raise MetadataInconsistent( - self._ireq, - "name", - self._name, - dist.project_name, - ) - parsed_version = parse_version(dist.version) - if self._version is not None and self._version != parsed_version: - raise MetadataInconsistent( - self._ireq, - "version", - str(self._version), - dist.version, - ) - - def _prepare(self) -> Distribution: - try: - dist = self._prepare_distribution() - except HashError as e: - # Provide HashError the underlying ireq that caused it. This - # provides context for the resulting error message to show the - # offending line to the user. - e.req = self._ireq - raise - self._check_metadata_consistency(dist) - return dist - - def _get_requires_python_dependency(self) -> Optional[Requirement]: - requires_python = get_requires_python(self.dist) - if requires_python is None: - return None - try: - spec = SpecifierSet(requires_python) - except InvalidSpecifier as e: - message = "Package %r has an invalid Requires-Python: %s" - logger.warning(message, self.name, e) - return None - return self._factory.make_requires_python_requirement(spec) - - def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: - requires = self.dist.requires() if with_requires else () - for r in requires: - yield self._factory.make_requirement_from_spec(str(r), self._ireq) - yield self._get_requires_python_dependency() - - def get_install_requirement(self) -> Optional[InstallRequirement]: - return self._ireq - - -class LinkCandidate(_InstallRequirementBackedCandidate): - is_editable = False - - def __init__( - self, - link: Link, - template: InstallRequirement, - factory: "Factory", - name: Optional[NormalizedName] = None, - version: Optional[CandidateVersion] = None, - ) -> None: - source_link = link - cache_entry = factory.get_wheel_cache_entry(link, name) - if cache_entry is not None: - logger.debug("Using cached wheel link: %s", cache_entry.link) - link = cache_entry.link - ireq = make_install_req_from_link(link, template) - assert ireq.link == link - if ireq.link.is_wheel and not ireq.link.is_file: - wheel = Wheel(ireq.link.filename) - wheel_name = canonicalize_name(wheel.name) - assert name == wheel_name, f"{name!r} != {wheel_name!r} for wheel" - # Version may not be present for PEP 508 direct URLs - if version is not None: - wheel_version = Version(wheel.version) - assert version == wheel_version, "{!r} != {!r} for wheel {}".format( - version, wheel_version, name - ) - - if ( - cache_entry is not None - and cache_entry.persistent - and template.link is template.original_link - ): - ireq.original_link_is_in_wheel_cache = True - - super().__init__( - link=link, - source_link=source_link, - ireq=ireq, - factory=factory, - name=name, - version=version, - ) - - def _prepare_distribution(self) -> Distribution: - return self._factory.preparer.prepare_linked_requirement( - self._ireq, parallel_builds=True - ) - - -class EditableCandidate(_InstallRequirementBackedCandidate): - is_editable = True - - def __init__( - self, - link: Link, - template: InstallRequirement, - factory: "Factory", - name: Optional[NormalizedName] = None, - version: Optional[CandidateVersion] = None, - ) -> None: - super().__init__( - link=link, - source_link=link, - ireq=make_install_req_from_editable(link, template), - factory=factory, - name=name, - version=version, - ) - - def _prepare_distribution(self) -> Distribution: - return self._factory.preparer.prepare_editable_requirement(self._ireq) - - -class AlreadyInstalledCandidate(Candidate): - is_installed = True - source_link = None - - def __init__( - self, - dist: Distribution, - template: InstallRequirement, - factory: "Factory", - ) -> None: - self.dist = dist - self._ireq = make_install_req_from_dist(dist, template) - self._factory = factory - - # This is just logging some messages, so we can do it eagerly. - # The returned dist would be exactly the same as self.dist because we - # set satisfied_by in make_install_req_from_dist. - # TODO: Supply reason based on force_reinstall and upgrade_strategy. - skip_reason = "already satisfied" - factory.preparer.prepare_installed_requirement(self._ireq, skip_reason) - - def __str__(self) -> str: - return str(self.dist) - - def __repr__(self) -> str: - return "{class_name}({distribution!r})".format( - class_name=self.__class__.__name__, - distribution=self.dist, - ) - - def __hash__(self) -> int: - return hash((self.__class__, self.name, self.version)) - - def __eq__(self, other: Any) -> bool: - if isinstance(other, self.__class__): - return self.name == other.name and self.version == other.version - return False - - @property - def project_name(self) -> NormalizedName: - return canonicalize_name(self.dist.project_name) - - @property - def name(self) -> str: - return self.project_name - - @property - def version(self) -> CandidateVersion: - return parse_version(self.dist.version) - - @property - def is_editable(self) -> bool: - return dist_is_editable(self.dist) - - def format_for_error(self) -> str: - return f"{self.name} {self.version} (Installed)" - - def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: - if not with_requires: - return - for r in self.dist.requires(): - yield self._factory.make_requirement_from_spec(str(r), self._ireq) - - def get_install_requirement(self) -> Optional[InstallRequirement]: - return None - - -class ExtrasCandidate(Candidate): - """A candidate that has 'extras', indicating additional dependencies. - - Requirements can be for a project with dependencies, something like - foo[extra]. The extras don't affect the project/version being installed - directly, but indicate that we need additional dependencies. We model that - by having an artificial ExtrasCandidate that wraps the "base" candidate. - - The ExtrasCandidate differs from the base in the following ways: - - 1. It has a unique name, of the form foo[extra]. This causes the resolver - to treat it as a separate node in the dependency graph. - 2. When we're getting the candidate's dependencies, - a) We specify that we want the extra dependencies as well. - b) We add a dependency on the base candidate. - See below for why this is needed. - 3. We return None for the underlying InstallRequirement, as the base - candidate will provide it, and we don't want to end up with duplicates. - - The dependency on the base candidate is needed so that the resolver can't - decide that it should recommend foo[extra1] version 1.0 and foo[extra2] - version 2.0. Having those candidates depend on foo=1.0 and foo=2.0 - respectively forces the resolver to recognise that this is a conflict. - """ - - def __init__( - self, - base: BaseCandidate, - extras: FrozenSet[str], - ) -> None: - self.base = base - self.extras = extras - - def __str__(self) -> str: - name, rest = str(self.base).split(" ", 1) - return "{}[{}] {}".format(name, ",".join(self.extras), rest) - - def __repr__(self) -> str: - return "{class_name}(base={base!r}, extras={extras!r})".format( - class_name=self.__class__.__name__, - base=self.base, - extras=self.extras, - ) - - def __hash__(self) -> int: - return hash((self.base, self.extras)) - - def __eq__(self, other: Any) -> bool: - if isinstance(other, self.__class__): - return self.base == other.base and self.extras == other.extras - return False - - @property - def project_name(self) -> NormalizedName: - return self.base.project_name - - @property - def name(self) -> str: - """The normalised name of the project the candidate refers to""" - return format_name(self.base.project_name, self.extras) - - @property - def version(self) -> CandidateVersion: - return self.base.version - - def format_for_error(self) -> str: - return "{} [{}]".format( - self.base.format_for_error(), ", ".join(sorted(self.extras)) - ) - - @property - def is_installed(self) -> bool: - return self.base.is_installed - - @property - def is_editable(self) -> bool: - return self.base.is_editable - - @property - def source_link(self) -> Optional[Link]: - return self.base.source_link - - def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: - factory = self.base._factory - - # Add a dependency on the exact base - # (See note 2b in the class docstring) - yield factory.make_requirement_from_candidate(self.base) - if not with_requires: - return - - # The user may have specified extras that the candidate doesn't - # support. We ignore any unsupported extras here. - valid_extras = self.extras.intersection(self.base.dist.extras) - invalid_extras = self.extras.difference(self.base.dist.extras) - for extra in sorted(invalid_extras): - logger.warning( - "%s %s does not provide the extra '%s'", - self.base.name, - self.version, - extra, - ) - - for r in self.base.dist.requires(valid_extras): - requirement = factory.make_requirement_from_spec( - str(r), self.base._ireq, valid_extras - ) - if requirement: - yield requirement - - def get_install_requirement(self) -> Optional[InstallRequirement]: - # We don't return anything here, because we always - # depend on the base candidate, and we'll get the - # install requirement from that. - return None - - -class RequiresPythonCandidate(Candidate): - is_installed = False - source_link = None - - def __init__(self, py_version_info: Optional[Tuple[int, ...]]) -> None: - if py_version_info is not None: - version_info = normalize_version_info(py_version_info) - else: - version_info = sys.version_info[:3] - self._version = Version(".".join(str(c) for c in version_info)) - - # We don't need to implement __eq__() and __ne__() since there is always - # only one RequiresPythonCandidate in a resolution, i.e. the host Python. - # The built-in object.__eq__() and object.__ne__() do exactly what we want. - - def __str__(self) -> str: - return f"Python {self._version}" - - @property - def project_name(self) -> NormalizedName: - return REQUIRES_PYTHON_IDENTIFIER - - @property - def name(self) -> str: - return REQUIRES_PYTHON_IDENTIFIER - - @property - def version(self) -> CandidateVersion: - return self._version - - def format_for_error(self) -> str: - return f"Python {self.version}" - - def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: - return () - - def get_install_requirement(self) -> Optional[InstallRequirement]: - return None diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py deleted file mode 100644 index e7fd344..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py +++ /dev/null @@ -1,700 +0,0 @@ -import contextlib -import functools -import logging -from typing import ( - TYPE_CHECKING, - Dict, - FrozenSet, - Iterable, - Iterator, - List, - Mapping, - NamedTuple, - Optional, - Sequence, - Set, - Tuple, - TypeVar, - cast, -) - -from pip._vendor.packaging.requirements import InvalidRequirement -from pip._vendor.packaging.requirements import Requirement as PackagingRequirement -from pip._vendor.packaging.specifiers import SpecifierSet -from pip._vendor.packaging.utils import NormalizedName, canonicalize_name -from pip._vendor.resolvelib import ResolutionImpossible - -from pip._internal.cache import CacheEntry, WheelCache -from pip._internal.exceptions import ( - DistributionNotFound, - InstallationError, - InstallationSubprocessError, - MetadataInconsistent, - UnsupportedPythonVersion, - UnsupportedWheel, -) -from pip._internal.index.package_finder import PackageFinder -from pip._internal.metadata import BaseDistribution, get_default_environment -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.operations.prepare import RequirementPreparer -from pip._internal.req.constructors import install_req_from_link_and_ireq -from pip._internal.req.req_install import ( - InstallRequirement, - check_invalid_constraint_type, -) -from pip._internal.resolution.base import InstallRequirementProvider -from pip._internal.utils.compatibility_tags import get_supported -from pip._internal.utils.hashes import Hashes -from pip._internal.utils.virtualenv import running_under_virtualenv - -from .base import Candidate, CandidateVersion, Constraint, Requirement -from .candidates import ( - AlreadyInstalledCandidate, - BaseCandidate, - EditableCandidate, - ExtrasCandidate, - LinkCandidate, - RequiresPythonCandidate, - as_base_candidate, -) -from .found_candidates import FoundCandidates, IndexCandidateInfo -from .requirements import ( - ExplicitRequirement, - RequiresPythonRequirement, - SpecifierRequirement, - UnsatisfiableRequirement, -) - -if TYPE_CHECKING: - from typing import Protocol - - class ConflictCause(Protocol): - requirement: RequiresPythonRequirement - parent: Candidate - - -logger = logging.getLogger(__name__) - -C = TypeVar("C") -Cache = Dict[Link, C] - - -class CollectedRootRequirements(NamedTuple): - requirements: List[Requirement] - constraints: Dict[str, Constraint] - user_requested: Dict[str, int] - - -class Factory: - def __init__( - self, - finder: PackageFinder, - preparer: RequirementPreparer, - make_install_req: InstallRequirementProvider, - wheel_cache: Optional[WheelCache], - use_user_site: bool, - force_reinstall: bool, - ignore_installed: bool, - ignore_requires_python: bool, - py_version_info: Optional[Tuple[int, ...]] = None, - ) -> None: - self._finder = finder - self.preparer = preparer - self._wheel_cache = wheel_cache - self._python_candidate = RequiresPythonCandidate(py_version_info) - self._make_install_req_from_spec = make_install_req - self._use_user_site = use_user_site - self._force_reinstall = force_reinstall - self._ignore_requires_python = ignore_requires_python - - self._build_failures: Cache[InstallationError] = {} - self._link_candidate_cache: Cache[LinkCandidate] = {} - self._editable_candidate_cache: Cache[EditableCandidate] = {} - self._installed_candidate_cache: Dict[str, AlreadyInstalledCandidate] = {} - self._extras_candidate_cache: Dict[ - Tuple[int, FrozenSet[str]], ExtrasCandidate - ] = {} - - if not ignore_installed: - env = get_default_environment() - self._installed_dists = { - dist.canonical_name: dist - for dist in env.iter_installed_distributions(local_only=False) - } - else: - self._installed_dists = {} - - @property - def force_reinstall(self) -> bool: - return self._force_reinstall - - def _fail_if_link_is_unsupported_wheel(self, link: Link) -> None: - if not link.is_wheel: - return - wheel = Wheel(link.filename) - if wheel.supported(self._finder.target_python.get_tags()): - return - msg = f"{link.filename} is not a supported wheel on this platform." - raise UnsupportedWheel(msg) - - def _make_extras_candidate( - self, base: BaseCandidate, extras: FrozenSet[str] - ) -> ExtrasCandidate: - cache_key = (id(base), extras) - try: - candidate = self._extras_candidate_cache[cache_key] - except KeyError: - candidate = ExtrasCandidate(base, extras) - self._extras_candidate_cache[cache_key] = candidate - return candidate - - def _make_candidate_from_dist( - self, - dist: BaseDistribution, - extras: FrozenSet[str], - template: InstallRequirement, - ) -> Candidate: - try: - base = self._installed_candidate_cache[dist.canonical_name] - except KeyError: - from pip._internal.metadata.pkg_resources import Distribution as _Dist - - compat_dist = cast(_Dist, dist)._dist - base = AlreadyInstalledCandidate(compat_dist, template, factory=self) - self._installed_candidate_cache[dist.canonical_name] = base - if not extras: - return base - return self._make_extras_candidate(base, extras) - - def _make_candidate_from_link( - self, - link: Link, - extras: FrozenSet[str], - template: InstallRequirement, - name: Optional[NormalizedName], - version: Optional[CandidateVersion], - ) -> Optional[Candidate]: - # TODO: Check already installed candidate, and use it if the link and - # editable flag match. - - if link in self._build_failures: - # We already tried this candidate before, and it does not build. - # Don't bother trying again. - return None - - if template.editable: - if link not in self._editable_candidate_cache: - try: - self._editable_candidate_cache[link] = EditableCandidate( - link, - template, - factory=self, - name=name, - version=version, - ) - except (InstallationSubprocessError, MetadataInconsistent) as e: - logger.warning("Discarding %s. %s", link, e) - self._build_failures[link] = e - return None - base: BaseCandidate = self._editable_candidate_cache[link] - else: - if link not in self._link_candidate_cache: - try: - self._link_candidate_cache[link] = LinkCandidate( - link, - template, - factory=self, - name=name, - version=version, - ) - except (InstallationSubprocessError, MetadataInconsistent) as e: - logger.warning("Discarding %s. %s", link, e) - self._build_failures[link] = e - return None - base = self._link_candidate_cache[link] - - if not extras: - return base - return self._make_extras_candidate(base, extras) - - def _iter_found_candidates( - self, - ireqs: Sequence[InstallRequirement], - specifier: SpecifierSet, - hashes: Hashes, - prefers_installed: bool, - incompatible_ids: Set[int], - ) -> Iterable[Candidate]: - if not ireqs: - return () - - # The InstallRequirement implementation requires us to give it a - # "template". Here we just choose the first requirement to represent - # all of them. - # Hopefully the Project model can correct this mismatch in the future. - template = ireqs[0] - assert template.req, "Candidates found on index must be PEP 508" - name = canonicalize_name(template.req.name) - - extras: FrozenSet[str] = frozenset() - for ireq in ireqs: - assert ireq.req, "Candidates found on index must be PEP 508" - specifier &= ireq.req.specifier - hashes &= ireq.hashes(trust_internet=False) - extras |= frozenset(ireq.extras) - - def _get_installed_candidate() -> Optional[Candidate]: - """Get the candidate for the currently-installed version.""" - # If --force-reinstall is set, we want the version from the index - # instead, so we "pretend" there is nothing installed. - if self._force_reinstall: - return None - try: - installed_dist = self._installed_dists[name] - except KeyError: - return None - # Don't use the installed distribution if its version does not fit - # the current dependency graph. - if not specifier.contains(installed_dist.version, prereleases=True): - return None - candidate = self._make_candidate_from_dist( - dist=installed_dist, - extras=extras, - template=template, - ) - # The candidate is a known incompatiblity. Don't use it. - if id(candidate) in incompatible_ids: - return None - return candidate - - def iter_index_candidate_infos() -> Iterator[IndexCandidateInfo]: - result = self._finder.find_best_candidate( - project_name=name, - specifier=specifier, - hashes=hashes, - ) - icans = list(result.iter_applicable()) - - # PEP 592: Yanked releases must be ignored unless only yanked - # releases can satisfy the version range. So if this is false, - # all yanked icans need to be skipped. - all_yanked = all(ican.link.is_yanked for ican in icans) - - # PackageFinder returns earlier versions first, so we reverse. - for ican in reversed(icans): - if not all_yanked and ican.link.is_yanked: - continue - func = functools.partial( - self._make_candidate_from_link, - link=ican.link, - extras=extras, - template=template, - name=name, - version=ican.version, - ) - yield ican.version, func - - return FoundCandidates( - iter_index_candidate_infos, - _get_installed_candidate(), - prefers_installed, - incompatible_ids, - ) - - def _iter_explicit_candidates_from_base( - self, - base_requirements: Iterable[Requirement], - extras: FrozenSet[str], - ) -> Iterator[Candidate]: - """Produce explicit candidates from the base given an extra-ed package. - - :param base_requirements: Requirements known to the resolver. The - requirements are guaranteed to not have extras. - :param extras: The extras to inject into the explicit requirements' - candidates. - """ - for req in base_requirements: - lookup_cand, _ = req.get_candidate_lookup() - if lookup_cand is None: # Not explicit. - continue - # We've stripped extras from the identifier, and should always - # get a BaseCandidate here, unless there's a bug elsewhere. - base_cand = as_base_candidate(lookup_cand) - assert base_cand is not None, "no extras here" - yield self._make_extras_candidate(base_cand, extras) - - def _iter_candidates_from_constraints( - self, - identifier: str, - constraint: Constraint, - template: InstallRequirement, - ) -> Iterator[Candidate]: - """Produce explicit candidates from constraints. - - This creates "fake" InstallRequirement objects that are basically clones - of what "should" be the template, but with original_link set to link. - """ - for link in constraint.links: - self._fail_if_link_is_unsupported_wheel(link) - candidate = self._make_candidate_from_link( - link, - extras=frozenset(), - template=install_req_from_link_and_ireq(link, template), - name=canonicalize_name(identifier), - version=None, - ) - if candidate: - yield candidate - - def find_candidates( - self, - identifier: str, - requirements: Mapping[str, Iterator[Requirement]], - incompatibilities: Mapping[str, Iterator[Candidate]], - constraint: Constraint, - prefers_installed: bool, - ) -> Iterable[Candidate]: - # Collect basic lookup information from the requirements. - explicit_candidates: Set[Candidate] = set() - ireqs: List[InstallRequirement] = [] - for req in requirements[identifier]: - cand, ireq = req.get_candidate_lookup() - if cand is not None: - explicit_candidates.add(cand) - if ireq is not None: - ireqs.append(ireq) - - # If the current identifier contains extras, add explicit candidates - # from entries from extra-less identifier. - with contextlib.suppress(InvalidRequirement): - parsed_requirement = PackagingRequirement(identifier) - explicit_candidates.update( - self._iter_explicit_candidates_from_base( - requirements.get(parsed_requirement.name, ()), - frozenset(parsed_requirement.extras), - ), - ) - - # Add explicit candidates from constraints. We only do this if there are - # kown ireqs, which represent requirements not already explicit. If - # there are no ireqs, we're constraining already-explicit requirements, - # which is handled later when we return the explicit candidates. - if ireqs: - try: - explicit_candidates.update( - self._iter_candidates_from_constraints( - identifier, - constraint, - template=ireqs[0], - ), - ) - except UnsupportedWheel: - # If we're constrained to install a wheel incompatible with the - # target architecture, no candidates will ever be valid. - return () - - # Since we cache all the candidates, incompatibility identification - # can be made quicker by comparing only the id() values. - incompat_ids = {id(c) for c in incompatibilities.get(identifier, ())} - - # If none of the requirements want an explicit candidate, we can ask - # the finder for candidates. - if not explicit_candidates: - return self._iter_found_candidates( - ireqs, - constraint.specifier, - constraint.hashes, - prefers_installed, - incompat_ids, - ) - - return ( - c - for c in explicit_candidates - if id(c) not in incompat_ids - and constraint.is_satisfied_by(c) - and all(req.is_satisfied_by(c) for req in requirements[identifier]) - ) - - def _make_requirement_from_install_req( - self, ireq: InstallRequirement, requested_extras: Iterable[str] - ) -> Optional[Requirement]: - if not ireq.match_markers(requested_extras): - logger.info( - "Ignoring %s: markers '%s' don't match your environment", - ireq.name, - ireq.markers, - ) - return None - if not ireq.link: - return SpecifierRequirement(ireq) - self._fail_if_link_is_unsupported_wheel(ireq.link) - cand = self._make_candidate_from_link( - ireq.link, - extras=frozenset(ireq.extras), - template=ireq, - name=canonicalize_name(ireq.name) if ireq.name else None, - version=None, - ) - if cand is None: - # There's no way we can satisfy a URL requirement if the underlying - # candidate fails to build. An unnamed URL must be user-supplied, so - # we fail eagerly. If the URL is named, an unsatisfiable requirement - # can make the resolver do the right thing, either backtrack (and - # maybe find some other requirement that's buildable) or raise a - # ResolutionImpossible eventually. - if not ireq.name: - raise self._build_failures[ireq.link] - return UnsatisfiableRequirement(canonicalize_name(ireq.name)) - return self.make_requirement_from_candidate(cand) - - def collect_root_requirements( - self, root_ireqs: List[InstallRequirement] - ) -> CollectedRootRequirements: - collected = CollectedRootRequirements([], {}, {}) - for i, ireq in enumerate(root_ireqs): - if ireq.constraint: - # Ensure we only accept valid constraints - problem = check_invalid_constraint_type(ireq) - if problem: - raise InstallationError(problem) - if not ireq.match_markers(): - continue - assert ireq.name, "Constraint must be named" - name = canonicalize_name(ireq.name) - if name in collected.constraints: - collected.constraints[name] &= ireq - else: - collected.constraints[name] = Constraint.from_ireq(ireq) - else: - req = self._make_requirement_from_install_req( - ireq, - requested_extras=(), - ) - if req is None: - continue - if ireq.user_supplied and req.name not in collected.user_requested: - collected.user_requested[req.name] = i - collected.requirements.append(req) - return collected - - def make_requirement_from_candidate( - self, candidate: Candidate - ) -> ExplicitRequirement: - return ExplicitRequirement(candidate) - - def make_requirement_from_spec( - self, - specifier: str, - comes_from: InstallRequirement, - requested_extras: Iterable[str] = (), - ) -> Optional[Requirement]: - ireq = self._make_install_req_from_spec(specifier, comes_from) - return self._make_requirement_from_install_req(ireq, requested_extras) - - def make_requires_python_requirement( - self, specifier: Optional[SpecifierSet] - ) -> Optional[Requirement]: - if self._ignore_requires_python or specifier is None: - return None - return RequiresPythonRequirement(specifier, self._python_candidate) - - def get_wheel_cache_entry( - self, link: Link, name: Optional[str] - ) -> Optional[CacheEntry]: - """Look up the link in the wheel cache. - - If ``preparer.require_hashes`` is True, don't use the wheel cache, - because cached wheels, always built locally, have different hashes - than the files downloaded from the index server and thus throw false - hash mismatches. Furthermore, cached wheels at present have - nondeterministic contents due to file modification times. - """ - if self._wheel_cache is None or self.preparer.require_hashes: - return None - return self._wheel_cache.get_cache_entry( - link=link, - package_name=name, - supported_tags=get_supported(), - ) - - def get_dist_to_uninstall(self, candidate: Candidate) -> Optional[BaseDistribution]: - # TODO: Are there more cases this needs to return True? Editable? - dist = self._installed_dists.get(candidate.project_name) - if dist is None: # Not installed, no uninstallation required. - return None - - # We're installing into global site. The current installation must - # be uninstalled, no matter it's in global or user site, because the - # user site installation has precedence over global. - if not self._use_user_site: - return dist - - # We're installing into user site. Remove the user site installation. - if dist.in_usersite: - return dist - - # We're installing into user site, but the installed incompatible - # package is in global site. We can't uninstall that, and would let - # the new user installation to "shadow" it. But shadowing won't work - # in virtual environments, so we error out. - if running_under_virtualenv() and dist.in_site_packages: - message = ( - f"Will not install to the user site because it will lack " - f"sys.path precedence to {dist.raw_name} in {dist.location}" - ) - raise InstallationError(message) - return None - - def _report_requires_python_error( - self, causes: Sequence["ConflictCause"] - ) -> UnsupportedPythonVersion: - assert causes, "Requires-Python error reported with no cause" - - version = self._python_candidate.version - - if len(causes) == 1: - specifier = str(causes[0].requirement.specifier) - message = ( - f"Package {causes[0].parent.name!r} requires a different " - f"Python: {version} not in {specifier!r}" - ) - return UnsupportedPythonVersion(message) - - message = f"Packages require a different Python. {version} not in:" - for cause in causes: - package = cause.parent.format_for_error() - specifier = str(cause.requirement.specifier) - message += f"\n{specifier!r} (required by {package})" - return UnsupportedPythonVersion(message) - - def _report_single_requirement_conflict( - self, req: Requirement, parent: Optional[Candidate] - ) -> DistributionNotFound: - if parent is None: - req_disp = str(req) - else: - req_disp = f"{req} (from {parent.name})" - - cands = self._finder.find_all_candidates(req.project_name) - versions = [str(v) for v in sorted({c.version for c in cands})] - - logger.critical( - "Could not find a version that satisfies the requirement %s " - "(from versions: %s)", - req_disp, - ", ".join(versions) or "none", - ) - if str(req) == "requirements.txt": - logger.info( - "HINT: You are attempting to install a package literally " - 'named "requirements.txt" (which cannot exist). Consider ' - "using the '-r' flag to install the packages listed in " - "requirements.txt" - ) - - return DistributionNotFound(f"No matching distribution found for {req}") - - def get_installation_error( - self, - e: "ResolutionImpossible[Requirement, Candidate]", - constraints: Dict[str, Constraint], - ) -> InstallationError: - - assert e.causes, "Installation error reported with no cause" - - # If one of the things we can't solve is "we need Python X.Y", - # that is what we report. - requires_python_causes = [ - cause - for cause in e.causes - if isinstance(cause.requirement, RequiresPythonRequirement) - and not cause.requirement.is_satisfied_by(self._python_candidate) - ] - if requires_python_causes: - # The comprehension above makes sure all Requirement instances are - # RequiresPythonRequirement, so let's cast for convinience. - return self._report_requires_python_error( - cast("Sequence[ConflictCause]", requires_python_causes), - ) - - # Otherwise, we have a set of causes which can't all be satisfied - # at once. - - # The simplest case is when we have *one* cause that can't be - # satisfied. We just report that case. - if len(e.causes) == 1: - req, parent = e.causes[0] - if req.name not in constraints: - return self._report_single_requirement_conflict(req, parent) - - # OK, we now have a list of requirements that can't all be - # satisfied at once. - - # A couple of formatting helpers - def text_join(parts: List[str]) -> str: - if len(parts) == 1: - return parts[0] - - return ", ".join(parts[:-1]) + " and " + parts[-1] - - def describe_trigger(parent: Candidate) -> str: - ireq = parent.get_install_requirement() - if not ireq or not ireq.comes_from: - return f"{parent.name}=={parent.version}" - if isinstance(ireq.comes_from, InstallRequirement): - return str(ireq.comes_from.name) - return str(ireq.comes_from) - - triggers = set() - for req, parent in e.causes: - if parent is None: - # This is a root requirement, so we can report it directly - trigger = req.format_for_error() - else: - trigger = describe_trigger(parent) - triggers.add(trigger) - - if triggers: - info = text_join(sorted(triggers)) - else: - info = "the requested packages" - - msg = ( - "Cannot install {} because these package versions " - "have conflicting dependencies.".format(info) - ) - logger.critical(msg) - msg = "\nThe conflict is caused by:" - - relevant_constraints = set() - for req, parent in e.causes: - if req.name in constraints: - relevant_constraints.add(req.name) - msg = msg + "\n " - if parent: - msg = msg + f"{parent.name} {parent.version} depends on " - else: - msg = msg + "The user requested " - msg = msg + req.format_for_error() - for key in relevant_constraints: - spec = constraints[key].specifier - msg += f"\n The user requested (constraint) {key}{spec}" - - msg = ( - msg - + "\n\n" - + "To fix this you could try to:\n" - + "1. loosen the range of package versions you've specified\n" - + "2. remove package versions to allow pip attempt to solve " - + "the dependency conflict\n" - ) - - logger.info(msg) - - return DistributionNotFound( - "ResolutionImpossible: for help visit " - "https://pip.pypa.io/en/latest/user_guide/" - "#fixing-conflicting-dependencies" - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py deleted file mode 100644 index d2fa5ef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py +++ /dev/null @@ -1,142 +0,0 @@ -"""Utilities to lazily create and visit candidates found. - -Creating and visiting a candidate is a *very* costly operation. It involves -fetching, extracting, potentially building modules from source, and verifying -distribution metadata. It is therefore crucial for performance to keep -everything here lazy all the way down, so we only touch candidates that we -absolutely need, and not "download the world" when we only need one version of -something. -""" - -import functools -from typing import Callable, Iterator, Optional, Set, Tuple - -from pip._vendor.packaging.version import _BaseVersion -from pip._vendor.six.moves import collections_abc # type: ignore - -from .base import Candidate - -IndexCandidateInfo = Tuple[_BaseVersion, Callable[[], Optional[Candidate]]] - - -def _iter_built(infos: Iterator[IndexCandidateInfo]) -> Iterator[Candidate]: - """Iterator for ``FoundCandidates``. - - This iterator is used when the package is not already installed. Candidates - from index come later in their normal ordering. - """ - versions_found: Set[_BaseVersion] = set() - for version, func in infos: - if version in versions_found: - continue - candidate = func() - if candidate is None: - continue - yield candidate - versions_found.add(version) - - -def _iter_built_with_prepended( - installed: Candidate, infos: Iterator[IndexCandidateInfo] -) -> Iterator[Candidate]: - """Iterator for ``FoundCandidates``. - - This iterator is used when the resolver prefers the already-installed - candidate and NOT to upgrade. The installed candidate is therefore - always yielded first, and candidates from index come later in their - normal ordering, except skipped when the version is already installed. - """ - yield installed - versions_found: Set[_BaseVersion] = {installed.version} - for version, func in infos: - if version in versions_found: - continue - candidate = func() - if candidate is None: - continue - yield candidate - versions_found.add(version) - - -def _iter_built_with_inserted( - installed: Candidate, infos: Iterator[IndexCandidateInfo] -) -> Iterator[Candidate]: - """Iterator for ``FoundCandidates``. - - This iterator is used when the resolver prefers to upgrade an - already-installed package. Candidates from index are returned in their - normal ordering, except replaced when the version is already installed. - - The implementation iterates through and yields other candidates, inserting - the installed candidate exactly once before we start yielding older or - equivalent candidates, or after all other candidates if they are all newer. - """ - versions_found: Set[_BaseVersion] = set() - for version, func in infos: - if version in versions_found: - continue - # If the installed candidate is better, yield it first. - if installed.version >= version: - yield installed - versions_found.add(installed.version) - candidate = func() - if candidate is None: - continue - yield candidate - versions_found.add(version) - - # If the installed candidate is older than all other candidates. - if installed.version not in versions_found: - yield installed - - -class FoundCandidates(collections_abc.Sequence): - """A lazy sequence to provide candidates to the resolver. - - The intended usage is to return this from `find_matches()` so the resolver - can iterate through the sequence multiple times, but only access the index - page when remote packages are actually needed. This improve performances - when suitable candidates are already installed on disk. - """ - - def __init__( - self, - get_infos: Callable[[], Iterator[IndexCandidateInfo]], - installed: Optional[Candidate], - prefers_installed: bool, - incompatible_ids: Set[int], - ): - self._get_infos = get_infos - self._installed = installed - self._prefers_installed = prefers_installed - self._incompatible_ids = incompatible_ids - - def __getitem__(self, index: int) -> Candidate: - # Implemented to satisfy the ABC check. This is not needed by the - # resolver, and should not be used by the provider either (for - # performance reasons). - raise NotImplementedError("don't do this") - - def __iter__(self) -> Iterator[Candidate]: - infos = self._get_infos() - if not self._installed: - iterator = _iter_built(infos) - elif self._prefers_installed: - iterator = _iter_built_with_prepended(self._installed, infos) - else: - iterator = _iter_built_with_inserted(self._installed, infos) - return (c for c in iterator if id(c) not in self._incompatible_ids) - - def __len__(self) -> int: - # Implemented to satisfy the ABC check. This is not needed by the - # resolver, and should not be used by the provider either (for - # performance reasons). - raise NotImplementedError("don't do this") - - @functools.lru_cache(maxsize=1) - def __bool__(self) -> bool: - if self._prefers_installed and self._installed: - return True - return any(self) - - __nonzero__ = __bool__ # XXX: Python 2. diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/provider.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/provider.py deleted file mode 100644 index 632854d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/provider.py +++ /dev/null @@ -1,197 +0,0 @@ -import collections -import math -from typing import TYPE_CHECKING, Dict, Iterable, Iterator, Mapping, Sequence, Union - -from pip._vendor.resolvelib.providers import AbstractProvider - -from .base import Candidate, Constraint, Requirement -from .candidates import REQUIRES_PYTHON_IDENTIFIER -from .factory import Factory - -if TYPE_CHECKING: - from pip._vendor.resolvelib.providers import Preference - from pip._vendor.resolvelib.resolvers import RequirementInformation - - PreferenceInformation = RequirementInformation[Requirement, Candidate] - - _ProviderBase = AbstractProvider[Requirement, Candidate, str] -else: - _ProviderBase = AbstractProvider - -# Notes on the relationship between the provider, the factory, and the -# candidate and requirement classes. -# -# The provider is a direct implementation of the resolvelib class. Its role -# is to deliver the API that resolvelib expects. -# -# Rather than work with completely abstract "requirement" and "candidate" -# concepts as resolvelib does, pip has concrete classes implementing these two -# ideas. The API of Requirement and Candidate objects are defined in the base -# classes, but essentially map fairly directly to the equivalent provider -# methods. In particular, `find_matches` and `is_satisfied_by` are -# requirement methods, and `get_dependencies` is a candidate method. -# -# The factory is the interface to pip's internal mechanisms. It is stateless, -# and is created by the resolver and held as a property of the provider. It is -# responsible for creating Requirement and Candidate objects, and provides -# services to those objects (access to pip's finder and preparer). - - -class PipProvider(_ProviderBase): - """Pip's provider implementation for resolvelib. - - :params constraints: A mapping of constraints specified by the user. Keys - are canonicalized project names. - :params ignore_dependencies: Whether the user specified ``--no-deps``. - :params upgrade_strategy: The user-specified upgrade strategy. - :params user_requested: A set of canonicalized package names that the user - supplied for pip to install/upgrade. - """ - - def __init__( - self, - factory: Factory, - constraints: Dict[str, Constraint], - ignore_dependencies: bool, - upgrade_strategy: str, - user_requested: Dict[str, int], - ) -> None: - self._factory = factory - self._constraints = constraints - self._ignore_dependencies = ignore_dependencies - self._upgrade_strategy = upgrade_strategy - self._user_requested = user_requested - self._known_depths: Dict[str, float] = collections.defaultdict(lambda: math.inf) - - def identify(self, requirement_or_candidate: Union[Requirement, Candidate]) -> str: - return requirement_or_candidate.name - - def get_preference( - self, - identifier: str, - resolutions: Mapping[str, Candidate], - candidates: Mapping[str, Iterator[Candidate]], - information: Mapping[str, Iterator["PreferenceInformation"]], - ) -> "Preference": - """Produce a sort key for given requirement based on preference. - - The lower the return value is, the more preferred this group of - arguments is. - - Currently pip considers the followings in order: - - * Prefer if any of the known requirements is "direct", e.g. points to an - explicit URL. - * If equal, prefer if any requirement is "pinned", i.e. contains - operator ``===`` or ``==``. - * If equal, calculate an approximate "depth" and resolve requirements - closer to the user-specified requirements first. - * Order user-specified requirements by the order they are specified. - * If equal, prefers "non-free" requirements, i.e. contains at least one - operator, such as ``>=`` or ``<``. - * If equal, order alphabetically for consistency (helps debuggability). - """ - lookups = (r.get_candidate_lookup() for r, _ in information[identifier]) - candidate, ireqs = zip(*lookups) - operators = [ - specifier.operator - for specifier_set in (ireq.specifier for ireq in ireqs if ireq) - for specifier in specifier_set - ] - - direct = candidate is not None - pinned = any(op[:2] == "==" for op in operators) - unfree = bool(operators) - - try: - requested_order: Union[int, float] = self._user_requested[identifier] - except KeyError: - requested_order = math.inf - parent_depths = ( - self._known_depths[parent.name] if parent is not None else 0.0 - for _, parent in information[identifier] - ) - inferred_depth = min(d for d in parent_depths) + 1.0 - self._known_depths[identifier] = inferred_depth - else: - inferred_depth = 1.0 - - requested_order = self._user_requested.get(identifier, math.inf) - - # Requires-Python has only one candidate and the check is basically - # free, so we always do it first to avoid needless work if it fails. - requires_python = identifier == REQUIRES_PYTHON_IDENTIFIER - - # HACK: Setuptools have a very long and solid backward compatibility - # track record, and extremely few projects would request a narrow, - # non-recent version range of it since that would break a lot things. - # (Most projects specify it only to request for an installer feature, - # which does not work, but that's another topic.) Intentionally - # delaying Setuptools helps reduce branches the resolver has to check. - # This serves as a temporary fix for issues like "apache-airlfow[all]" - # while we work on "proper" branch pruning techniques. - delay_this = identifier == "setuptools" - - return ( - not requires_python, - delay_this, - not direct, - not pinned, - inferred_depth, - requested_order, - not unfree, - identifier, - ) - - def _get_constraint(self, identifier: str) -> Constraint: - if identifier in self._constraints: - return self._constraints[identifier] - - # HACK: Theoratically we should check whether this identifier is a valid - # "NAME[EXTRAS]" format, and parse out the name part with packaging or - # some regular expression. But since pip's resolver only spits out - # three kinds of identifiers: normalized PEP 503 names, normalized names - # plus extras, and Requires-Python, we can cheat a bit here. - name, open_bracket, _ = identifier.partition("[") - if open_bracket and name in self._constraints: - return self._constraints[name] - - return Constraint.empty() - - def find_matches( - self, - identifier: str, - requirements: Mapping[str, Iterator[Requirement]], - incompatibilities: Mapping[str, Iterator[Candidate]], - ) -> Iterable[Candidate]: - def _eligible_for_upgrade(name: str) -> bool: - """Are upgrades allowed for this project? - - This checks the upgrade strategy, and whether the project was one - that the user specified in the command line, in order to decide - whether we should upgrade if there's a newer version available. - - (Note that we don't need access to the `--upgrade` flag, because - an upgrade strategy of "to-satisfy-only" means that `--upgrade` - was not specified). - """ - if self._upgrade_strategy == "eager": - return True - elif self._upgrade_strategy == "only-if-needed": - return name in self._user_requested - return False - - return self._factory.find_candidates( - identifier=identifier, - requirements=requirements, - constraint=self._get_constraint(identifier), - prefers_installed=(not _eligible_for_upgrade(identifier)), - incompatibilities=incompatibilities, - ) - - def is_satisfied_by(self, requirement: Requirement, candidate: Candidate) -> bool: - return requirement.is_satisfied_by(candidate) - - def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]: - with_requires = not self._ignore_dependencies - return [r for r in candidate.iter_dependencies(with_requires) if r is not None] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/reporter.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/reporter.py deleted file mode 100644 index 7cf88ba..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/reporter.py +++ /dev/null @@ -1,69 +0,0 @@ -from collections import defaultdict -from logging import getLogger -from typing import Any, DefaultDict - -from pip._vendor.resolvelib.reporters import BaseReporter - -from .base import Candidate, Requirement - -logger = getLogger(__name__) - - -class PipReporter(BaseReporter): - def __init__(self) -> None: - self.backtracks_by_package: DefaultDict[str, int] = defaultdict(int) - - self._messages_at_backtrack = { - 1: ( - "pip is looking at multiple versions of {package_name} to " - "determine which version is compatible with other " - "requirements. This could take a while." - ), - 8: ( - "pip is looking at multiple versions of {package_name} to " - "determine which version is compatible with other " - "requirements. This could take a while." - ), - 13: ( - "This is taking longer than usual. You might need to provide " - "the dependency resolver with stricter constraints to reduce " - "runtime. If you want to abort this run, you can press " - "Ctrl + C to do so. To improve how pip performs, tell us what " - "happened here: https://pip.pypa.io/surveys/backtracking" - ), - } - - def backtracking(self, candidate: Candidate) -> None: - self.backtracks_by_package[candidate.name] += 1 - - count = self.backtracks_by_package[candidate.name] - if count not in self._messages_at_backtrack: - return - - message = self._messages_at_backtrack[count] - logger.info("INFO: %s", message.format(package_name=candidate.name)) - - -class PipDebuggingReporter(BaseReporter): - """A reporter that does an info log for every event it sees.""" - - def starting(self) -> None: - logger.info("Reporter.starting()") - - def starting_round(self, index: int) -> None: - logger.info("Reporter.starting_round(%r)", index) - - def ending_round(self, index: int, state: Any) -> None: - logger.info("Reporter.ending_round(%r, state)", index) - - def ending(self, state: Any) -> None: - logger.info("Reporter.ending(%r)", state) - - def adding_requirement(self, requirement: Requirement, parent: Candidate) -> None: - logger.info("Reporter.adding_requirement(%r, %r)", requirement, parent) - - def backtracking(self, candidate: Candidate) -> None: - logger.info("Reporter.backtracking(%r)", candidate) - - def pinning(self, candidate: Candidate) -> None: - logger.info("Reporter.pinning(%r)", candidate) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/requirements.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/requirements.py deleted file mode 100644 index c19f83c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/requirements.py +++ /dev/null @@ -1,166 +0,0 @@ -from pip._vendor.packaging.specifiers import SpecifierSet -from pip._vendor.packaging.utils import NormalizedName, canonicalize_name - -from pip._internal.req.req_install import InstallRequirement - -from .base import Candidate, CandidateLookup, Requirement, format_name - - -class ExplicitRequirement(Requirement): - def __init__(self, candidate: Candidate) -> None: - self.candidate = candidate - - def __str__(self) -> str: - return str(self.candidate) - - def __repr__(self) -> str: - return "{class_name}({candidate!r})".format( - class_name=self.__class__.__name__, - candidate=self.candidate, - ) - - @property - def project_name(self) -> NormalizedName: - # No need to canonicalise - the candidate did this - return self.candidate.project_name - - @property - def name(self) -> str: - # No need to canonicalise - the candidate did this - return self.candidate.name - - def format_for_error(self) -> str: - return self.candidate.format_for_error() - - def get_candidate_lookup(self) -> CandidateLookup: - return self.candidate, None - - def is_satisfied_by(self, candidate: Candidate) -> bool: - return candidate == self.candidate - - -class SpecifierRequirement(Requirement): - def __init__(self, ireq: InstallRequirement) -> None: - assert ireq.link is None, "This is a link, not a specifier" - self._ireq = ireq - self._extras = frozenset(ireq.extras) - - def __str__(self) -> str: - return str(self._ireq.req) - - def __repr__(self) -> str: - return "{class_name}({requirement!r})".format( - class_name=self.__class__.__name__, - requirement=str(self._ireq.req), - ) - - @property - def project_name(self) -> NormalizedName: - assert self._ireq.req, "Specifier-backed ireq is always PEP 508" - return canonicalize_name(self._ireq.req.name) - - @property - def name(self) -> str: - return format_name(self.project_name, self._extras) - - def format_for_error(self) -> str: - - # Convert comma-separated specifiers into "A, B, ..., F and G" - # This makes the specifier a bit more "human readable", without - # risking a change in meaning. (Hopefully! Not all edge cases have - # been checked) - parts = [s.strip() for s in str(self).split(",")] - if len(parts) == 0: - return "" - elif len(parts) == 1: - return parts[0] - - return ", ".join(parts[:-1]) + " and " + parts[-1] - - def get_candidate_lookup(self) -> CandidateLookup: - return None, self._ireq - - def is_satisfied_by(self, candidate: Candidate) -> bool: - assert candidate.name == self.name, ( - f"Internal issue: Candidate is not for this requirement " - f"{candidate.name} vs {self.name}" - ) - # We can safely always allow prereleases here since PackageFinder - # already implements the prerelease logic, and would have filtered out - # prerelease candidates if the user does not expect them. - assert self._ireq.req, "Specifier-backed ireq is always PEP 508" - spec = self._ireq.req.specifier - return spec.contains(candidate.version, prereleases=True) - - -class RequiresPythonRequirement(Requirement): - """A requirement representing Requires-Python metadata.""" - - def __init__(self, specifier: SpecifierSet, match: Candidate) -> None: - self.specifier = specifier - self._candidate = match - - def __str__(self) -> str: - return f"Python {self.specifier}" - - def __repr__(self) -> str: - return "{class_name}({specifier!r})".format( - class_name=self.__class__.__name__, - specifier=str(self.specifier), - ) - - @property - def project_name(self) -> NormalizedName: - return self._candidate.project_name - - @property - def name(self) -> str: - return self._candidate.name - - def format_for_error(self) -> str: - return str(self) - - def get_candidate_lookup(self) -> CandidateLookup: - if self.specifier.contains(self._candidate.version, prereleases=True): - return self._candidate, None - return None, None - - def is_satisfied_by(self, candidate: Candidate) -> bool: - assert candidate.name == self._candidate.name, "Not Python candidate" - # We can safely always allow prereleases here since PackageFinder - # already implements the prerelease logic, and would have filtered out - # prerelease candidates if the user does not expect them. - return self.specifier.contains(candidate.version, prereleases=True) - - -class UnsatisfiableRequirement(Requirement): - """A requirement that cannot be satisfied.""" - - def __init__(self, name: NormalizedName) -> None: - self._name = name - - def __str__(self) -> str: - return f"{self._name} (unavailable)" - - def __repr__(self) -> str: - return "{class_name}({name!r})".format( - class_name=self.__class__.__name__, - name=str(self._name), - ) - - @property - def project_name(self) -> NormalizedName: - return self._name - - @property - def name(self) -> str: - return self._name - - def format_for_error(self) -> str: - return str(self) - - def get_candidate_lookup(self) -> CandidateLookup: - return None, None - - def is_satisfied_by(self, candidate: Candidate) -> bool: - return False diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py deleted file mode 100644 index f89afaf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py +++ /dev/null @@ -1,272 +0,0 @@ -import functools -import logging -import os -from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, cast - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible -from pip._vendor.resolvelib import Resolver as RLResolver -from pip._vendor.resolvelib.structs import DirectedGraph - -from pip._internal.cache import WheelCache -from pip._internal.index.package_finder import PackageFinder -from pip._internal.operations.prepare import RequirementPreparer -from pip._internal.req.req_install import InstallRequirement -from pip._internal.req.req_set import RequirementSet -from pip._internal.resolution.base import BaseResolver, InstallRequirementProvider -from pip._internal.resolution.resolvelib.provider import PipProvider -from pip._internal.resolution.resolvelib.reporter import ( - PipDebuggingReporter, - PipReporter, -) -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.filetypes import is_archive_file - -from .base import Candidate, Requirement -from .factory import Factory - -if TYPE_CHECKING: - from pip._vendor.resolvelib.resolvers import Result as RLResult - - Result = RLResult[Requirement, Candidate, str] - - -logger = logging.getLogger(__name__) - - -class Resolver(BaseResolver): - _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} - - def __init__( - self, - preparer: RequirementPreparer, - finder: PackageFinder, - wheel_cache: Optional[WheelCache], - make_install_req: InstallRequirementProvider, - use_user_site: bool, - ignore_dependencies: bool, - ignore_installed: bool, - ignore_requires_python: bool, - force_reinstall: bool, - upgrade_strategy: str, - py_version_info: Optional[Tuple[int, ...]] = None, - ): - super().__init__() - assert upgrade_strategy in self._allowed_strategies - - self.factory = Factory( - finder=finder, - preparer=preparer, - make_install_req=make_install_req, - wheel_cache=wheel_cache, - use_user_site=use_user_site, - force_reinstall=force_reinstall, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - py_version_info=py_version_info, - ) - self.ignore_dependencies = ignore_dependencies - self.upgrade_strategy = upgrade_strategy - self._result: Optional[Result] = None - - def resolve( - self, root_reqs: List[InstallRequirement], check_supported_wheels: bool - ) -> RequirementSet: - collected = self.factory.collect_root_requirements(root_reqs) - provider = PipProvider( - factory=self.factory, - constraints=collected.constraints, - ignore_dependencies=self.ignore_dependencies, - upgrade_strategy=self.upgrade_strategy, - user_requested=collected.user_requested, - ) - if "PIP_RESOLVER_DEBUG" in os.environ: - reporter: BaseReporter = PipDebuggingReporter() - else: - reporter = PipReporter() - resolver: RLResolver[Requirement, Candidate, str] = RLResolver( - provider, - reporter, - ) - - try: - try_to_avoid_resolution_too_deep = 2000000 - result = self._result = resolver.resolve( - collected.requirements, max_rounds=try_to_avoid_resolution_too_deep - ) - - except ResolutionImpossible as e: - error = self.factory.get_installation_error( - cast("ResolutionImpossible[Requirement, Candidate]", e), - collected.constraints, - ) - raise error from e - - req_set = RequirementSet(check_supported_wheels=check_supported_wheels) - for candidate in result.mapping.values(): - ireq = candidate.get_install_requirement() - if ireq is None: - continue - - # Check if there is already an installation under the same name, - # and set a flag for later stages to uninstall it, if needed. - installed_dist = self.factory.get_dist_to_uninstall(candidate) - if installed_dist is None: - # There is no existing installation -- nothing to uninstall. - ireq.should_reinstall = False - elif self.factory.force_reinstall: - # The --force-reinstall flag is set -- reinstall. - ireq.should_reinstall = True - elif installed_dist.version != candidate.version: - # The installation is different in version -- reinstall. - ireq.should_reinstall = True - elif candidate.is_editable or installed_dist.editable: - # The incoming distribution is editable, or different in - # editable-ness to installation -- reinstall. - ireq.should_reinstall = True - elif candidate.source_link and candidate.source_link.is_file: - # The incoming distribution is under file:// - if candidate.source_link.is_wheel: - # is a local wheel -- do nothing. - logger.info( - "%s is already installed with the same version as the " - "provided wheel. Use --force-reinstall to force an " - "installation of the wheel.", - ireq.name, - ) - continue - - looks_like_sdist = ( - is_archive_file(candidate.source_link.file_path) - and candidate.source_link.ext != ".zip" - ) - if looks_like_sdist: - # is a local sdist -- show a deprecation warning! - reason = ( - "Source distribution is being reinstalled despite an " - "installed package having the same name and version as " - "the installed package." - ) - replacement = "use --force-reinstall" - deprecated( - reason=reason, - replacement=replacement, - gone_in="21.3", - issue=8711, - ) - - # is a local sdist or path -- reinstall - ireq.should_reinstall = True - else: - continue - - link = candidate.source_link - if link and link.is_yanked: - # The reason can contain non-ASCII characters, Unicode - # is required for Python 2. - msg = ( - "The candidate selected for download or install is a " - "yanked version: {name!r} candidate (version {version} " - "at {link})\nReason for being yanked: {reason}" - ).format( - name=candidate.name, - version=candidate.version, - link=link, - reason=link.yanked_reason or "", - ) - logger.warning(msg) - - req_set.add_named_requirement(ireq) - - reqs = req_set.all_requirements - self.factory.preparer.prepare_linked_requirements_more(reqs) - return req_set - - def get_installation_order( - self, req_set: RequirementSet - ) -> List[InstallRequirement]: - """Get order for installation of requirements in RequirementSet. - - The returned list contains a requirement before another that depends on - it. This helps ensure that the environment is kept consistent as they - get installed one-by-one. - - The current implementation creates a topological ordering of the - dependency graph, while breaking any cycles in the graph at arbitrary - points. We make no guarantees about where the cycle would be broken, - other than they would be broken. - """ - assert self._result is not None, "must call resolve() first" - - graph = self._result.graph - weights = get_topological_weights( - graph, - expected_node_count=len(self._result.mapping) + 1, - ) - - sorted_items = sorted( - req_set.requirements.items(), - key=functools.partial(_req_set_item_sorter, weights=weights), - reverse=True, - ) - return [ireq for _, ireq in sorted_items] - - -def get_topological_weights( - graph: "DirectedGraph[Optional[str]]", expected_node_count: int -) -> Dict[Optional[str], int]: - """Assign weights to each node based on how "deep" they are. - - This implementation may change at any point in the future without prior - notice. - - We take the length for the longest path to any node from root, ignoring any - paths that contain a single node twice (i.e. cycles). This is done through - a depth-first search through the graph, while keeping track of the path to - the node. - - Cycles in the graph result would result in node being revisited while also - being it's own path. In this case, take no action. This helps ensure we - don't get stuck in a cycle. - - When assigning weight, the longer path (i.e. larger length) is preferred. - """ - path: Set[Optional[str]] = set() - weights: Dict[Optional[str], int] = {} - - def visit(node: Optional[str]) -> None: - if node in path: - # We hit a cycle, so we'll break it here. - return - - # Time to visit the children! - path.add(node) - for child in graph.iter_children(node): - visit(child) - path.remove(node) - - last_known_parent_count = weights.get(node, 0) - weights[node] = max(last_known_parent_count, len(path)) - - # `None` is guaranteed to be the root node by resolvelib. - visit(None) - - # Sanity checks - assert weights[None] == 0 - assert len(weights) == expected_node_count - - return weights - - -def _req_set_item_sorter( - item: Tuple[str, InstallRequirement], - weights: Dict[Optional[str], int], -) -> Tuple[int, str]: - """Key function used to sort install requirements for installation. - - Based on the "weight" mapping calculated in ``get_installation_order()``. - The canonical package name is returned as the second member as a tie- - breaker to ensure the result is predictable, which is useful in tests. - """ - name = canonicalize_name(item[0]) - return weights[name], name diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/self_outdated_check.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/self_outdated_check.py deleted file mode 100644 index 6b24965..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/self_outdated_check.py +++ /dev/null @@ -1,187 +0,0 @@ -import datetime -import hashlib -import json -import logging -import optparse -import os.path -import sys -from typing import Any, Dict - -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.index.collector import LinkCollector -from pip._internal.index.package_finder import PackageFinder -from pip._internal.metadata import get_default_environment -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.network.session import PipSession -from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace -from pip._internal.utils.misc import ensure_dir - -SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" - - -logger = logging.getLogger(__name__) - - -def _get_statefile_name(key): - # type: (str) -> str - key_bytes = key.encode() - name = hashlib.sha224(key_bytes).hexdigest() - return name - - -class SelfCheckState: - def __init__(self, cache_dir): - # type: (str) -> None - self.state = {} # type: Dict[str, Any] - self.statefile_path = None - - # Try to load the existing state - if cache_dir: - self.statefile_path = os.path.join( - cache_dir, "selfcheck", _get_statefile_name(self.key) - ) - try: - with open(self.statefile_path, encoding="utf-8") as statefile: - self.state = json.load(statefile) - except (OSError, ValueError, KeyError): - # Explicitly suppressing exceptions, since we don't want to - # error out if the cache file is invalid. - pass - - @property - def key(self): - # type: () -> str - return sys.prefix - - def save(self, pypi_version, current_time): - # type: (str, datetime.datetime) -> None - # If we do not have a path to cache in, don't bother saving. - if not self.statefile_path: - return - - # Check to make sure that we own the directory - if not check_path_owner(os.path.dirname(self.statefile_path)): - return - - # Now that we've ensured the directory is owned by this user, we'll go - # ahead and make sure that all our directories are created. - ensure_dir(os.path.dirname(self.statefile_path)) - - state = { - # Include the key so it's easy to tell which pip wrote the - # file. - "key": self.key, - "last_check": current_time.strftime(SELFCHECK_DATE_FMT), - "pypi_version": pypi_version, - } - - text = json.dumps(state, sort_keys=True, separators=(",", ":")) - - with adjacent_tmp_file(self.statefile_path) as f: - f.write(text.encode()) - - try: - # Since we have a prefix-specific state file, we can just - # overwrite whatever is there, no need to check. - replace(f.name, self.statefile_path) - except OSError: - # Best effort. - pass - - -def was_installed_by_pip(pkg): - # type: (str) -> bool - """Checks whether pkg was installed by pip - - This is used not to display the upgrade message when pip is in fact - installed by system package manager, such as dnf on Fedora. - """ - dist = get_default_environment().get_distribution(pkg) - return dist is not None and "pip" == dist.installer - - -def pip_self_version_check(session, options): - # type: (PipSession, optparse.Values) -> None - """Check for an update for pip. - - Limit the frequency of checks to once per week. State is stored either in - the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix - of the pip script path. - """ - installed_dist = get_default_environment().get_distribution("pip") - if not installed_dist: - return - - pip_version = installed_dist.version - pypi_version = None - - try: - state = SelfCheckState(cache_dir=options.cache_dir) - - current_time = datetime.datetime.utcnow() - # Determine if we need to refresh the state - if "last_check" in state.state and "pypi_version" in state.state: - last_check = datetime.datetime.strptime( - state.state["last_check"], - SELFCHECK_DATE_FMT - ) - if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: - pypi_version = state.state["pypi_version"] - - # Refresh the version if we need to or just see if we need to warn - if pypi_version is None: - # Lets use PackageFinder to see what the latest pip version is - link_collector = LinkCollector.create( - session, - options=options, - suppress_no_index=True, - ) - - # Pass allow_yanked=False so we don't suggest upgrading to a - # yanked version. - selection_prefs = SelectionPreferences( - allow_yanked=False, - allow_all_prereleases=False, # Explicitly set to False - ) - - finder = PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - ) - best_candidate = finder.find_best_candidate("pip").best_candidate - if best_candidate is None: - return - pypi_version = str(best_candidate.version) - - # save that we've performed a check - state.save(pypi_version, current_time) - - remote_version = parse_version(pypi_version) - - local_version_is_older = ( - pip_version < remote_version and - pip_version.base_version != remote_version.base_version and - was_installed_by_pip('pip') - ) - - # Determine if our pypi_version is older - if not local_version_is_older: - return - - # We cannot tell how the current pip is available in the current - # command context, so be pragmatic here and suggest the command - # that's always available. This does not accommodate spaces in - # `sys.executable`. - pip_cmd = f"{sys.executable} -m pip" - logger.warning( - "You are using pip version %s; however, version %s is " - "available.\nYou should consider upgrading via the " - "'%s install --upgrade pip' command.", - pip_version, pypi_version, pip_cmd - ) - except Exception: - logger.debug( - "There was an error checking the latest version of pip", - exc_info=True, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/_log.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/_log.py deleted file mode 100644 index 92c4c6a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/_log.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Customize logging - -Defines custom logger class for the `logger.verbose(...)` method. - -init_logging() must be called before any other modules that call logging.getLogger. -""" - -import logging -from typing import Any, cast - -# custom log level for `--verbose` output -# between DEBUG and INFO -VERBOSE = 15 - - -class VerboseLogger(logging.Logger): - """Custom Logger, defining a verbose log-level - - VERBOSE is between INFO and DEBUG. - """ - - def verbose(self, msg: str, *args: Any, **kwargs: Any) -> None: - return self.log(VERBOSE, msg, *args, **kwargs) - - -def getLogger(name: str) -> VerboseLogger: - """logging.getLogger, but ensures our VerboseLogger class is returned""" - return cast(VerboseLogger, logging.getLogger(name)) - - -def init_logging() -> None: - """Register our VerboseLogger and VERBOSE log level. - - Should be called before any calls to getLogger(), - i.e. in pip._internal.__init__ - """ - logging.setLoggerClass(VerboseLogger) - logging.addLevelName(VERBOSE, "VERBOSE") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/appdirs.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/appdirs.py deleted file mode 100644 index a8403b7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/appdirs.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -This code wraps the vendored appdirs module to so the return values are -compatible for the current pip code base. - -The intention is to rewrite current usages gradually, keeping the tests pass, -and eventually drop this after all usages are changed. -""" - -import os -from typing import List - -from pip._vendor import appdirs as _appdirs - - -def user_cache_dir(appname: str) -> str: - return _appdirs.user_cache_dir(appname, appauthor=False) - - -def user_config_dir(appname: str, roaming: bool = True) -> str: - path = _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) - if _appdirs.system == "darwin" and not os.path.isdir(path): - path = os.path.expanduser("~/.config/") - if appname: - path = os.path.join(path, appname) - return path - - -# for the discussion regarding site_config_dir locations -# see -def site_config_dirs(appname: str) -> List[str]: - dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) - if _appdirs.system not in ["win32", "darwin"]: - # always look in /etc directly as well - return dirval.split(os.pathsep) + ["/etc"] - return [dirval] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compat.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compat.py deleted file mode 100644 index 3f4d300..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compat.py +++ /dev/null @@ -1,63 +0,0 @@ -"""Stuff that differs in different Python versions and platform -distributions.""" - -import logging -import os -import sys - -__all__ = ["get_path_uid", "stdlib_pkgs", "WINDOWS"] - - -logger = logging.getLogger(__name__) - - -def has_tls() -> bool: - try: - import _ssl # noqa: F401 # ignore unused - - return True - except ImportError: - pass - - from pip._vendor.urllib3.util import IS_PYOPENSSL - - return IS_PYOPENSSL - - -def get_path_uid(path: str) -> int: - """ - Return path's uid. - - Does not follow symlinks: - https://github.com/pypa/pip/pull/935#discussion_r5307003 - - Placed this function in compat due to differences on AIX and - Jython, that should eventually go away. - - :raises OSError: When path is a symlink or can't be read. - """ - if hasattr(os, "O_NOFOLLOW"): - fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) - file_uid = os.fstat(fd).st_uid - os.close(fd) - else: # AIX and Jython - # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW - if not os.path.islink(path): - # older versions of Jython don't have `os.fstat` - file_uid = os.stat(path).st_uid - else: - # raise OSError for parity with os.O_NOFOLLOW above - raise OSError(f"{path} is a symlink; Will not return uid for symlinks") - return file_uid - - -# packages in the stdlib that may have installation metadata, but should not be -# considered 'installed'. this theoretically could be determined based on -# dist.location (py27:`sysconfig.get_paths()['stdlib']`, -# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may -# make this ineffective, so hard-coding -stdlib_pkgs = {"python", "wsgiref", "argparse"} - - -# windows detection, covers cpython and ironpython -WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compatibility_tags.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compatibility_tags.py deleted file mode 100644 index f1c0f06..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/compatibility_tags.py +++ /dev/null @@ -1,168 +0,0 @@ -"""Generate and work with PEP 425 Compatibility Tags. -""" - -import re -from typing import TYPE_CHECKING, List, Optional, Tuple - -from pip._vendor.packaging.tags import ( - Tag, - compatible_tags, - cpython_tags, - generic_tags, - interpreter_name, - interpreter_version, - mac_platforms, -) - -if TYPE_CHECKING: - from pip._vendor.packaging.tags import PythonVersion - - -_osx_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)") - - -def version_info_to_nodot(version_info: Tuple[int, ...]) -> str: - # Only use up to the first two numbers. - return "".join(map(str, version_info[:2])) - - -def _mac_platforms(arch: str) -> List[str]: - match = _osx_arch_pat.match(arch) - if match: - name, major, minor, actual_arch = match.groups() - mac_version = (int(major), int(minor)) - arches = [ - # Since we have always only checked that the platform starts - # with "macosx", for backwards-compatibility we extract the - # actual prefix provided by the user in case they provided - # something like "macosxcustom_". It may be good to remove - # this as undocumented or deprecate it in the future. - "{}_{}".format(name, arch[len("macosx_") :]) - for arch in mac_platforms(mac_version, actual_arch) - ] - else: - # arch pattern didn't match (?!) - arches = [arch] - return arches - - -def _custom_manylinux_platforms(arch: str) -> List[str]: - arches = [arch] - arch_prefix, arch_sep, arch_suffix = arch.partition("_") - if arch_prefix == "manylinux2014": - # manylinux1/manylinux2010 wheels run on most manylinux2014 systems - # with the exception of wheels depending on ncurses. PEP 599 states - # manylinux1/manylinux2010 wheels should be considered - # manylinux2014 wheels: - # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels - if arch_suffix in {"i686", "x86_64"}: - arches.append("manylinux2010" + arch_sep + arch_suffix) - arches.append("manylinux1" + arch_sep + arch_suffix) - elif arch_prefix == "manylinux2010": - # manylinux1 wheels run on most manylinux2010 systems with the - # exception of wheels depending on ncurses. PEP 571 states - # manylinux1 wheels should be considered manylinux2010 wheels: - # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels - arches.append("manylinux1" + arch_sep + arch_suffix) - return arches - - -def _get_custom_platforms(arch: str) -> List[str]: - arch_prefix, arch_sep, arch_suffix = arch.partition("_") - if arch.startswith("macosx"): - arches = _mac_platforms(arch) - elif arch_prefix in ["manylinux2014", "manylinux2010"]: - arches = _custom_manylinux_platforms(arch) - else: - arches = [arch] - return arches - - -def _expand_allowed_platforms(platforms: Optional[List[str]]) -> Optional[List[str]]: - if not platforms: - return None - - seen = set() - result = [] - - for p in platforms: - if p in seen: - continue - additions = [c for c in _get_custom_platforms(p) if c not in seen] - seen.update(additions) - result.extend(additions) - - return result - - -def _get_python_version(version: str) -> "PythonVersion": - if len(version) > 1: - return int(version[0]), int(version[1:]) - else: - return (int(version[0]),) - - -def _get_custom_interpreter( - implementation: Optional[str] = None, version: Optional[str] = None -) -> str: - if implementation is None: - implementation = interpreter_name() - if version is None: - version = interpreter_version() - return f"{implementation}{version}" - - -def get_supported( - version: Optional[str] = None, - platforms: Optional[List[str]] = None, - impl: Optional[str] = None, - abis: Optional[List[str]] = None, -) -> List[Tag]: - """Return a list of supported tags for each version specified in - `versions`. - - :param version: a string version, of the form "33" or "32", - or None. The version will be assumed to support our ABI. - :param platform: specify a list of platforms you want valid - tags for, or None. If None, use the local system platform. - :param impl: specify the exact implementation you want valid - tags for, or None. If None, use the local interpreter impl. - :param abis: specify a list of abis you want valid - tags for, or None. If None, use the local interpreter abi. - """ - supported: List[Tag] = [] - - python_version: Optional["PythonVersion"] = None - if version is not None: - python_version = _get_python_version(version) - - interpreter = _get_custom_interpreter(impl, version) - - platforms = _expand_allowed_platforms(platforms) - - is_cpython = (impl or interpreter_name()) == "cp" - if is_cpython: - supported.extend( - cpython_tags( - python_version=python_version, - abis=abis, - platforms=platforms, - ) - ) - else: - supported.extend( - generic_tags( - interpreter=interpreter, - abis=abis, - platforms=platforms, - ) - ) - supported.extend( - compatible_tags( - python_version=python_version, - interpreter=interpreter, - platforms=platforms, - ) - ) - - return supported diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/datetime.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/datetime.py deleted file mode 100644 index 8668b3b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/datetime.py +++ /dev/null @@ -1,11 +0,0 @@ -"""For when pip wants to check the date or time. -""" - -import datetime - - -def today_is_later_than(year: int, month: int, day: int) -> bool: - today = datetime.date.today() - given = datetime.date(year, month, day) - - return today > given diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/deprecation.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/deprecation.py deleted file mode 100644 index 57dbdbd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/deprecation.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -A module that implements tooling to enable easy warnings about deprecations. -""" - -import logging -import warnings -from typing import Any, Optional, TextIO, Type, Union - -from pip._vendor.packaging.version import parse - -from pip import __version__ as current_version - -DEPRECATION_MSG_PREFIX = "DEPRECATION: " - - -class PipDeprecationWarning(Warning): - pass - - -_original_showwarning: Any = None - - -# Warnings <-> Logging Integration -def _showwarning( - message: Union[Warning, str], - category: Type[Warning], - filename: str, - lineno: int, - file: Optional[TextIO] = None, - line: Optional[str] = None, -) -> None: - if file is not None: - if _original_showwarning is not None: - _original_showwarning(message, category, filename, lineno, file, line) - elif issubclass(category, PipDeprecationWarning): - # We use a specially named logger which will handle all of the - # deprecation messages for pip. - logger = logging.getLogger("pip._internal.deprecations") - logger.warning(message) - else: - _original_showwarning(message, category, filename, lineno, file, line) - - -def install_warning_logger() -> None: - # Enable our Deprecation Warnings - warnings.simplefilter("default", PipDeprecationWarning, append=True) - - global _original_showwarning - - if _original_showwarning is None: - _original_showwarning = warnings.showwarning - warnings.showwarning = _showwarning - - -def deprecated( - reason: str, - replacement: Optional[str], - gone_in: Optional[str], - issue: Optional[int] = None, -) -> None: - """Helper to deprecate existing functionality. - - reason: - Textual reason shown to the user about why this functionality has - been deprecated. - replacement: - Textual suggestion shown to the user about what alternative - functionality they can use. - gone_in: - The version of pip does this functionality should get removed in. - Raises errors if pip's current version is greater than or equal to - this. - issue: - Issue number on the tracker that would serve as a useful place for - users to find related discussion and provide feedback. - - Always pass replacement, gone_in and issue as keyword arguments for clarity - at the call site. - """ - - # Construct a nice message. - # This is eagerly formatted as we want it to get logged as if someone - # typed this entire message out. - sentences = [ - (reason, DEPRECATION_MSG_PREFIX + "{}"), - (gone_in, "pip {} will remove support for this functionality."), - (replacement, "A possible replacement is {}."), - ( - issue, - ( - "You can find discussion regarding this at " - "https://github.com/pypa/pip/issues/{}." - ), - ), - ] - message = " ".join( - template.format(val) for val, template in sentences if val is not None - ) - - # Raise as an error if it has to be removed. - if gone_in is not None and parse(current_version) >= parse(gone_in): - raise PipDeprecationWarning(message) - - warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/direct_url_helpers.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/direct_url_helpers.py deleted file mode 100644 index 088e977..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/direct_url_helpers.py +++ /dev/null @@ -1,79 +0,0 @@ -from typing import Optional - -from pip._internal.models.direct_url import ArchiveInfo, DirectUrl, DirInfo, VcsInfo -from pip._internal.models.link import Link -from pip._internal.vcs import vcs - - -def direct_url_as_pep440_direct_reference(direct_url: DirectUrl, name: str) -> str: - """Convert a DirectUrl to a pip requirement string.""" - direct_url.validate() # if invalid, this is a pip bug - requirement = name + " @ " - fragments = [] - if isinstance(direct_url.info, VcsInfo): - requirement += "{}+{}@{}".format( - direct_url.info.vcs, direct_url.url, direct_url.info.commit_id - ) - elif isinstance(direct_url.info, ArchiveInfo): - requirement += direct_url.url - if direct_url.info.hash: - fragments.append(direct_url.info.hash) - else: - assert isinstance(direct_url.info, DirInfo) - requirement += direct_url.url - if direct_url.subdirectory: - fragments.append("subdirectory=" + direct_url.subdirectory) - if fragments: - requirement += "#" + "&".join(fragments) - return requirement - - -def direct_url_from_link( - link: Link, source_dir: Optional[str] = None, link_is_in_wheel_cache: bool = False -) -> DirectUrl: - if link.is_vcs: - vcs_backend = vcs.get_backend_for_scheme(link.scheme) - assert vcs_backend - url, requested_revision, _ = vcs_backend.get_url_rev_and_auth( - link.url_without_fragment - ) - # For VCS links, we need to find out and add commit_id. - if link_is_in_wheel_cache: - # If the requested VCS link corresponds to a cached - # wheel, it means the requested revision was an - # immutable commit hash, otherwise it would not have - # been cached. In that case we don't have a source_dir - # with the VCS checkout. - assert requested_revision - commit_id = requested_revision - else: - # If the wheel was not in cache, it means we have - # had to checkout from VCS to build and we have a source_dir - # which we can inspect to find out the commit id. - assert source_dir - commit_id = vcs_backend.get_revision(source_dir) - return DirectUrl( - url=url, - info=VcsInfo( - vcs=vcs_backend.name, - commit_id=commit_id, - requested_revision=requested_revision, - ), - subdirectory=link.subdirectory_fragment, - ) - elif link.is_existing_dir(): - return DirectUrl( - url=link.url_without_fragment, - info=DirInfo(), - subdirectory=link.subdirectory_fragment, - ) - else: - hash = None - hash_name = link.hash_name - if hash_name: - hash = f"{hash_name}={link.hash}" - return DirectUrl( - url=link.url_without_fragment, - info=ArchiveInfo(hash=hash), - subdirectory=link.subdirectory_fragment, - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/distutils_args.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/distutils_args.py deleted file mode 100644 index e4aa5b8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/distutils_args.py +++ /dev/null @@ -1,42 +0,0 @@ -from distutils.errors import DistutilsArgError -from distutils.fancy_getopt import FancyGetopt -from typing import Dict, List - -_options = [ - ("exec-prefix=", None, ""), - ("home=", None, ""), - ("install-base=", None, ""), - ("install-data=", None, ""), - ("install-headers=", None, ""), - ("install-lib=", None, ""), - ("install-platlib=", None, ""), - ("install-purelib=", None, ""), - ("install-scripts=", None, ""), - ("prefix=", None, ""), - ("root=", None, ""), - ("user", None, ""), -] - - -# typeshed doesn't permit Tuple[str, None, str], see python/typeshed#3469. -_distutils_getopt = FancyGetopt(_options) # type: ignore - - -def parse_distutils_args(args: List[str]) -> Dict[str, str]: - """Parse provided arguments, returning an object that has the - matched arguments. - - Any unknown arguments are ignored. - """ - result = {} - for arg in args: - try: - _, match = _distutils_getopt.getopt(args=[arg]) - except DistutilsArgError: - # We don't care about any other options, which here may be - # considered unrecognized since our option list is not - # exhaustive. - pass - else: - result.update(match.__dict__) - return result diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/encoding.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/encoding.py deleted file mode 100644 index 1c73f6c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/encoding.py +++ /dev/null @@ -1,36 +0,0 @@ -import codecs -import locale -import re -import sys -from typing import List, Tuple - -BOMS: List[Tuple[bytes, str]] = [ - (codecs.BOM_UTF8, "utf-8"), - (codecs.BOM_UTF16, "utf-16"), - (codecs.BOM_UTF16_BE, "utf-16-be"), - (codecs.BOM_UTF16_LE, "utf-16-le"), - (codecs.BOM_UTF32, "utf-32"), - (codecs.BOM_UTF32_BE, "utf-32-be"), - (codecs.BOM_UTF32_LE, "utf-32-le"), -] - -ENCODING_RE = re.compile(br"coding[:=]\s*([-\w.]+)") - - -def auto_decode(data: bytes) -> str: - """Check a bytes string for a BOM to correctly detect the encoding - - Fallback to locale.getpreferredencoding(False) like open() on Python3""" - for bom, encoding in BOMS: - if data.startswith(bom): - return data[len(bom) :].decode(encoding) - # Lets check the first two lines as in PEP263 - for line in data.split(b"\n")[:2]: - if line[0:1] == b"#" and ENCODING_RE.search(line): - result = ENCODING_RE.search(line) - assert result is not None - encoding = result.groups()[0].decode("ascii") - return data.decode(encoding) - return data.decode( - locale.getpreferredencoding(False) or sys.getdefaultencoding(), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/entrypoints.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/entrypoints.py deleted file mode 100644 index 1504a12..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/entrypoints.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -from typing import List, Optional - -from pip._internal.cli.main import main - - -def _wrapper(args: Optional[List[str]] = None) -> int: - """Central wrapper for all old entrypoints. - - Historically pip has had several entrypoints defined. Because of issues - arising from PATH, sys.path, multiple Pythons, their interactions, and most - of them having a pip installed, users suffer every time an entrypoint gets - moved. - - To alleviate this pain, and provide a mechanism for warning users and - directing them to an appropriate place for help, we now define all of - our old entrypoints as wrappers for the current one. - """ - sys.stderr.write( - "WARNING: pip is being invoked by an old script wrapper. This will " - "fail in a future version of pip.\n" - "Please see https://github.com/pypa/pip/issues/5599 for advice on " - "fixing the underlying issue.\n" - "To avoid this problem you can invoke Python with '-m pip' instead of " - "running pip directly.\n" - ) - return main(args) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filesystem.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filesystem.py deleted file mode 100644 index b7e6191..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filesystem.py +++ /dev/null @@ -1,182 +0,0 @@ -import fnmatch -import os -import os.path -import random -import shutil -import stat -import sys -from contextlib import contextmanager -from tempfile import NamedTemporaryFile -from typing import Any, BinaryIO, Iterator, List, Union, cast - -from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed - -from pip._internal.utils.compat import get_path_uid -from pip._internal.utils.misc import format_size - - -def check_path_owner(path: str) -> bool: - # If we don't have a way to check the effective uid of this process, then - # we'll just assume that we own the directory. - if sys.platform == "win32" or not hasattr(os, "geteuid"): - return True - - assert os.path.isabs(path) - - previous = None - while path != previous: - if os.path.lexists(path): - # Check if path is writable by current user. - if os.geteuid() == 0: - # Special handling for root user in order to handle properly - # cases where users use sudo without -H flag. - try: - path_uid = get_path_uid(path) - except OSError: - return False - return path_uid == 0 - else: - return os.access(path, os.W_OK) - else: - previous, path = path, os.path.dirname(path) - return False # assume we don't own the path - - -def copy2_fixed(src: str, dest: str) -> None: - """Wrap shutil.copy2() but map errors copying socket files to - SpecialFileError as expected. - - See also https://bugs.python.org/issue37700. - """ - try: - shutil.copy2(src, dest) - except OSError: - for f in [src, dest]: - try: - is_socket_file = is_socket(f) - except OSError: - # An error has already occurred. Another error here is not - # a problem and we can ignore it. - pass - else: - if is_socket_file: - raise shutil.SpecialFileError(f"`{f}` is a socket") - - raise - - -def is_socket(path: str) -> bool: - return stat.S_ISSOCK(os.lstat(path).st_mode) - - -@contextmanager -def adjacent_tmp_file(path: str, **kwargs: Any) -> Iterator[BinaryIO]: - """Return a file-like object pointing to a tmp file next to path. - - The file is created securely and is ensured to be written to disk - after the context reaches its end. - - kwargs will be passed to tempfile.NamedTemporaryFile to control - the way the temporary file will be opened. - """ - with NamedTemporaryFile( - delete=False, - dir=os.path.dirname(path), - prefix=os.path.basename(path), - suffix=".tmp", - **kwargs, - ) as f: - result = cast(BinaryIO, f) - try: - yield result - finally: - result.flush() - os.fsync(result.fileno()) - - -# Tenacity raises RetryError by default, explicitly raise the original exception -_replace_retry = retry(reraise=True, stop=stop_after_delay(1), wait=wait_fixed(0.25)) - -replace = _replace_retry(os.replace) - - -# test_writable_dir and _test_writable_dir_win are copied from Flit, -# with the author's agreement to also place them under pip's license. -def test_writable_dir(path: str) -> bool: - """Check if a directory is writable. - - Uses os.access() on POSIX, tries creating files on Windows. - """ - # If the directory doesn't exist, find the closest parent that does. - while not os.path.isdir(path): - parent = os.path.dirname(path) - if parent == path: - break # Should never get here, but infinite loops are bad - path = parent - - if os.name == "posix": - return os.access(path, os.W_OK) - - return _test_writable_dir_win(path) - - -def _test_writable_dir_win(path: str) -> bool: - # os.access doesn't work on Windows: http://bugs.python.org/issue2528 - # and we can't use tempfile: http://bugs.python.org/issue22107 - basename = "accesstest_deleteme_fishfingers_custard_" - alphabet = "abcdefghijklmnopqrstuvwxyz0123456789" - for _ in range(10): - name = basename + "".join(random.choice(alphabet) for _ in range(6)) - file = os.path.join(path, name) - try: - fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL) - except FileExistsError: - pass - except PermissionError: - # This could be because there's a directory with the same name. - # But it's highly unlikely there's a directory called that, - # so we'll assume it's because the parent dir is not writable. - # This could as well be because the parent dir is not readable, - # due to non-privileged user access. - return False - else: - os.close(fd) - os.unlink(file) - return True - - # This should never be reached - raise OSError("Unexpected condition testing for writable directory") - - -def find_files(path: str, pattern: str) -> List[str]: - """Returns a list of absolute paths of files beneath path, recursively, - with filenames which match the UNIX-style shell glob pattern.""" - result: List[str] = [] - for root, _, files in os.walk(path): - matches = fnmatch.filter(files, pattern) - result.extend(os.path.join(root, f) for f in matches) - return result - - -def file_size(path: str) -> Union[int, float]: - # If it's a symlink, return 0. - if os.path.islink(path): - return 0 - return os.path.getsize(path) - - -def format_file_size(path: str) -> str: - return format_size(file_size(path)) - - -def directory_size(path: str) -> Union[int, float]: - size = 0.0 - for root, _dirs, files in os.walk(path): - for filename in files: - file_path = os.path.join(root, filename) - size += file_size(file_path) - return size - - -def format_directory_size(path: str) -> str: - return format_size(directory_size(path)) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filetypes.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filetypes.py deleted file mode 100644 index da93584..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/filetypes.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Filetype information. -""" - -from typing import Tuple - -from pip._internal.utils.misc import splitext - -WHEEL_EXTENSION = ".whl" -BZ2_EXTENSIONS = (".tar.bz2", ".tbz") # type: Tuple[str, ...] -XZ_EXTENSIONS = ( - ".tar.xz", - ".txz", - ".tlz", - ".tar.lz", - ".tar.lzma", -) # type: Tuple[str, ...] -ZIP_EXTENSIONS = (".zip", WHEEL_EXTENSION) # type: Tuple[str, ...] -TAR_EXTENSIONS = (".tar.gz", ".tgz", ".tar") # type: Tuple[str, ...] -ARCHIVE_EXTENSIONS = ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS - - -def is_archive_file(name): - # type: (str) -> bool - """Return True if `name` is a considered as an archive file.""" - ext = splitext(name)[1].lower() - if ext in ARCHIVE_EXTENSIONS: - return True - return False diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/glibc.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/glibc.py deleted file mode 100644 index 1c9ff35..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/glibc.py +++ /dev/null @@ -1,92 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import os -import sys -from typing import Optional, Tuple - - -def glibc_version_string(): - # type: () -> Optional[str] - "Returns glibc version string, or None if not using glibc." - return glibc_version_string_confstr() or glibc_version_string_ctypes() - - -def glibc_version_string_confstr(): - # type: () -> Optional[str] - "Primary implementation of glibc_version_string using os.confstr." - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module: - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 - if sys.platform == "win32": - return None - try: - # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17": - _, version = os.confstr("CS_GNU_LIBC_VERSION").split() - except (AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def glibc_version_string_ctypes(): - # type: () -> Optional[str] - "Fallback implementation of glibc_version_string using ctypes." - - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - process_namespace = ctypes.CDLL(None) - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -# platform.libc_ver regularly returns completely nonsensical glibc -# versions. E.g. on my computer, platform says: -# -# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' -# ('glibc', '2.7') -# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' -# ('glibc', '2.9') -# -# But the truth is: -# -# ~$ ldd --version -# ldd (Debian GLIBC 2.22-11) 2.22 -# -# This is unfortunate, because it means that the linehaul data on libc -# versions that was generated by pip 8.1.2 and earlier is useless and -# misleading. Solution: instead of using platform, use our code that actually -# works. -def libc_ver(): - # type: () -> Tuple[str, str] - """Try to determine the glibc version - - Returns a tuple of strings (lib, version) which default to empty strings - in case the lookup fails. - """ - glibc_version = glibc_version_string() - if glibc_version is None: - return ("", "") - else: - return ("glibc", glibc_version) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/hashes.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/hashes.py deleted file mode 100644 index 3d20b8d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/hashes.py +++ /dev/null @@ -1,165 +0,0 @@ -import hashlib -from typing import TYPE_CHECKING, BinaryIO, Dict, Iterator, List - -from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError -from pip._internal.utils.misc import read_chunks - -if TYPE_CHECKING: - from hashlib import _Hash - - # NoReturn introduced in 3.6.2; imported only for type checking to maintain - # pip compatibility with older patch versions of Python 3.6 - from typing import NoReturn - - -# The recommended hash algo of the moment. Change this whenever the state of -# the art changes; it won't hurt backward compatibility. -FAVORITE_HASH = "sha256" - - -# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` -# Currently, those are the ones at least as collision-resistant as sha256. -STRONG_HASHES = ["sha256", "sha384", "sha512"] - - -class Hashes: - """A wrapper that builds multiple hashes at once and checks them against - known-good values - - """ - - def __init__(self, hashes=None): - # type: (Dict[str, List[str]]) -> None - """ - :param hashes: A dict of algorithm names pointing to lists of allowed - hex digests - """ - allowed = {} - if hashes is not None: - for alg, keys in hashes.items(): - # Make sure values are always sorted (to ease equality checks) - allowed[alg] = sorted(keys) - self._allowed = allowed - - def __and__(self, other): - # type: (Hashes) -> Hashes - if not isinstance(other, Hashes): - return NotImplemented - - # If either of the Hashes object is entirely empty (i.e. no hash - # specified at all), all hashes from the other object are allowed. - if not other: - return self - if not self: - return other - - # Otherwise only hashes that present in both objects are allowed. - new = {} - for alg, values in other._allowed.items(): - if alg not in self._allowed: - continue - new[alg] = [v for v in values if v in self._allowed[alg]] - return Hashes(new) - - @property - def digest_count(self): - # type: () -> int - return sum(len(digests) for digests in self._allowed.values()) - - def is_hash_allowed( - self, - hash_name, # type: str - hex_digest, # type: str - ): - # type: (...) -> bool - """Return whether the given hex digest is allowed.""" - return hex_digest in self._allowed.get(hash_name, []) - - def check_against_chunks(self, chunks): - # type: (Iterator[bytes]) -> None - """Check good hashes against ones built from iterable of chunks of - data. - - Raise HashMismatch if none match. - - """ - gots = {} - for hash_name in self._allowed.keys(): - try: - gots[hash_name] = hashlib.new(hash_name) - except (ValueError, TypeError): - raise InstallationError(f"Unknown hash name: {hash_name}") - - for chunk in chunks: - for hash in gots.values(): - hash.update(chunk) - - for hash_name, got in gots.items(): - if got.hexdigest() in self._allowed[hash_name]: - return - self._raise(gots) - - def _raise(self, gots): - # type: (Dict[str, _Hash]) -> NoReturn - raise HashMismatch(self._allowed, gots) - - def check_against_file(self, file): - # type: (BinaryIO) -> None - """Check good hashes against a file-like object - - Raise HashMismatch if none match. - - """ - return self.check_against_chunks(read_chunks(file)) - - def check_against_path(self, path): - # type: (str) -> None - with open(path, "rb") as file: - return self.check_against_file(file) - - def __nonzero__(self): - # type: () -> bool - """Return whether I know any known-good hashes.""" - return bool(self._allowed) - - def __bool__(self): - # type: () -> bool - return self.__nonzero__() - - def __eq__(self, other): - # type: (object) -> bool - if not isinstance(other, Hashes): - return NotImplemented - return self._allowed == other._allowed - - def __hash__(self): - # type: () -> int - return hash( - ",".join( - sorted( - ":".join((alg, digest)) - for alg, digest_list in self._allowed.items() - for digest in digest_list - ) - ) - ) - - -class MissingHashes(Hashes): - """A workalike for Hashes used when we're missing a hash for a requirement - - It computes the actual hash of the requirement and raises a HashMissing - exception showing it to the user. - - """ - - def __init__(self): - # type: () -> None - """Don't offer the ``hashes`` kwarg.""" - # Pass our favorite hash in to generate a "gotten hash". With the - # empty list, it will never match, so an error will always raise. - super().__init__(hashes={FAVORITE_HASH: []}) - - def _raise(self, gots): - # type: (Dict[str, _Hash]) -> NoReturn - raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/inject_securetransport.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/inject_securetransport.py deleted file mode 100644 index b6863d9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/inject_securetransport.py +++ /dev/null @@ -1,36 +0,0 @@ -"""A helper module that injects SecureTransport, on import. - -The import should be done as early as possible, to ensure all requests and -sessions (or whatever) are created after injecting SecureTransport. - -Note that we only do the injection on macOS, when the linked OpenSSL is too -old to handle TLSv1.2. -""" - -import sys - - -def inject_securetransport(): - # type: () -> None - # Only relevant on macOS - if sys.platform != "darwin": - return - - try: - import ssl - except ImportError: - return - - # Checks for OpenSSL 1.0.1 - if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100F: - return - - try: - from pip._vendor.urllib3.contrib import securetransport - except (ImportError, OSError): - return - - securetransport.inject_into_urllib3() - - -inject_securetransport() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/logging.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/logging.py deleted file mode 100644 index 39a18fd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/logging.py +++ /dev/null @@ -1,391 +0,0 @@ -import contextlib -import errno -import logging -import logging.handlers -import os -import sys -from logging import Filter -from typing import IO, Any, Callable, Iterator, Optional, TextIO, Type, cast - -from pip._internal.utils._log import VERBOSE, getLogger -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX -from pip._internal.utils.misc import ensure_dir - -try: - import threading -except ImportError: - import dummy_threading as threading # type: ignore - - -try: - from pip._vendor import colorama -# Lots of different errors can come from this, including SystemError and -# ImportError. -except Exception: - colorama = None - - -_log_state = threading.local() -subprocess_logger = getLogger("pip.subprocessor") - - -class BrokenStdoutLoggingError(Exception): - """ - Raised if BrokenPipeError occurs for the stdout stream while logging. - """ - - pass - - -# BrokenPipeError manifests differently in Windows and non-Windows. -if WINDOWS: - # In Windows, a broken pipe can show up as EINVAL rather than EPIPE: - # https://bugs.python.org/issue19612 - # https://bugs.python.org/issue30418 - def _is_broken_pipe_error(exc_class, exc): - # type: (Type[BaseException], BaseException) -> bool - """See the docstring for non-Windows below.""" - return (exc_class is BrokenPipeError) or ( - isinstance(exc, OSError) and exc.errno in (errno.EINVAL, errno.EPIPE) - ) - - -else: - # Then we are in the non-Windows case. - def _is_broken_pipe_error(exc_class, exc): - # type: (Type[BaseException], BaseException) -> bool - """ - Return whether an exception is a broken pipe error. - - Args: - exc_class: an exception class. - exc: an exception instance. - """ - return exc_class is BrokenPipeError - - -@contextlib.contextmanager -def indent_log(num=2): - # type: (int) -> Iterator[None] - """ - A context manager which will cause the log output to be indented for any - log messages emitted inside it. - """ - # For thread-safety - _log_state.indentation = get_indentation() - _log_state.indentation += num - try: - yield - finally: - _log_state.indentation -= num - - -def get_indentation(): - # type: () -> int - return getattr(_log_state, "indentation", 0) - - -class IndentingFormatter(logging.Formatter): - default_time_format = "%Y-%m-%dT%H:%M:%S" - - def __init__( - self, - *args, # type: Any - add_timestamp=False, # type: bool - **kwargs, # type: Any - ): - # type: (...) -> None - """ - A logging.Formatter that obeys the indent_log() context manager. - - :param add_timestamp: A bool indicating output lines should be prefixed - with their record's timestamp. - """ - self.add_timestamp = add_timestamp - super().__init__(*args, **kwargs) - - def get_message_start(self, formatted, levelno): - # type: (str, int) -> str - """ - Return the start of the formatted log message (not counting the - prefix to add to each line). - """ - if levelno < logging.WARNING: - return "" - if formatted.startswith(DEPRECATION_MSG_PREFIX): - # Then the message already has a prefix. We don't want it to - # look like "WARNING: DEPRECATION: ...." - return "" - if levelno < logging.ERROR: - return "WARNING: " - - return "ERROR: " - - def format(self, record): - # type: (logging.LogRecord) -> str - """ - Calls the standard formatter, but will indent all of the log message - lines by our current indentation level. - """ - formatted = super().format(record) - message_start = self.get_message_start(formatted, record.levelno) - formatted = message_start + formatted - - prefix = "" - if self.add_timestamp: - prefix = f"{self.formatTime(record)} " - prefix += " " * get_indentation() - formatted = "".join([prefix + line for line in formatted.splitlines(True)]) - return formatted - - -def _color_wrap(*colors): - # type: (*str) -> Callable[[str], str] - def wrapped(inp): - # type: (str) -> str - return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) - - return wrapped - - -class ColorizedStreamHandler(logging.StreamHandler): - - # Don't build up a list of colors if we don't have colorama - if colorama: - COLORS = [ - # This needs to be in order from highest logging level to lowest. - (logging.ERROR, _color_wrap(colorama.Fore.RED)), - (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)), - ] - else: - COLORS = [] - - def __init__(self, stream=None, no_color=None): - # type: (Optional[TextIO], bool) -> None - super().__init__(stream) - self._no_color = no_color - - if WINDOWS and colorama: - self.stream = colorama.AnsiToWin32(self.stream) - - def _using_stdout(self): - # type: () -> bool - """ - Return whether the handler is using sys.stdout. - """ - if WINDOWS and colorama: - # Then self.stream is an AnsiToWin32 object. - stream = cast(colorama.AnsiToWin32, self.stream) - return stream.wrapped is sys.stdout - - return self.stream is sys.stdout - - def should_color(self): - # type: () -> bool - # Don't colorize things if we do not have colorama or if told not to - if not colorama or self._no_color: - return False - - real_stream = ( - self.stream - if not isinstance(self.stream, colorama.AnsiToWin32) - else self.stream.wrapped - ) - - # If the stream is a tty we should color it - if hasattr(real_stream, "isatty") and real_stream.isatty(): - return True - - # If we have an ANSI term we should color it - if os.environ.get("TERM") == "ANSI": - return True - - # If anything else we should not color it - return False - - def format(self, record): - # type: (logging.LogRecord) -> str - msg = super().format(record) - - if self.should_color(): - for level, color in self.COLORS: - if record.levelno >= level: - msg = color(msg) - break - - return msg - - # The logging module says handleError() can be customized. - def handleError(self, record): - # type: (logging.LogRecord) -> None - exc_class, exc = sys.exc_info()[:2] - # If a broken pipe occurred while calling write() or flush() on the - # stdout stream in logging's Handler.emit(), then raise our special - # exception so we can handle it in main() instead of logging the - # broken pipe error and continuing. - if ( - exc_class - and exc - and self._using_stdout() - and _is_broken_pipe_error(exc_class, exc) - ): - raise BrokenStdoutLoggingError() - - return super().handleError(record) - - -class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): - def _open(self): - # type: () -> IO[Any] - ensure_dir(os.path.dirname(self.baseFilename)) - return super()._open() - - -class MaxLevelFilter(Filter): - def __init__(self, level): - # type: (int) -> None - self.level = level - - def filter(self, record): - # type: (logging.LogRecord) -> bool - return record.levelno < self.level - - -class ExcludeLoggerFilter(Filter): - - """ - A logging Filter that excludes records from a logger (or its children). - """ - - def filter(self, record): - # type: (logging.LogRecord) -> bool - # The base Filter class allows only records from a logger (or its - # children). - return not super().filter(record) - - -def setup_logging(verbosity, no_color, user_log_file): - # type: (int, bool, Optional[str]) -> int - """Configures and sets up all of the logging - - Returns the requested logging level, as its integer value. - """ - - # Determine the level to be logging at. - if verbosity >= 2: - level_number = logging.DEBUG - elif verbosity == 1: - level_number = VERBOSE - elif verbosity == -1: - level_number = logging.WARNING - elif verbosity == -2: - level_number = logging.ERROR - elif verbosity <= -3: - level_number = logging.CRITICAL - else: - level_number = logging.INFO - - level = logging.getLevelName(level_number) - - # The "root" logger should match the "console" level *unless* we also need - # to log to a user log file. - include_user_log = user_log_file is not None - if include_user_log: - additional_log_file = user_log_file - root_level = "DEBUG" - else: - additional_log_file = "/dev/null" - root_level = level - - # Disable any logging besides WARNING unless we have DEBUG level logging - # enabled for vendored libraries. - vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" - - # Shorthands for clarity - log_streams = { - "stdout": "ext://sys.stdout", - "stderr": "ext://sys.stderr", - } - handler_classes = { - "stream": "pip._internal.utils.logging.ColorizedStreamHandler", - "file": "pip._internal.utils.logging.BetterRotatingFileHandler", - } - handlers = ["console", "console_errors", "console_subprocess"] + ( - ["user_log"] if include_user_log else [] - ) - - logging.config.dictConfig( - { - "version": 1, - "disable_existing_loggers": False, - "filters": { - "exclude_warnings": { - "()": "pip._internal.utils.logging.MaxLevelFilter", - "level": logging.WARNING, - }, - "restrict_to_subprocess": { - "()": "logging.Filter", - "name": subprocess_logger.name, - }, - "exclude_subprocess": { - "()": "pip._internal.utils.logging.ExcludeLoggerFilter", - "name": subprocess_logger.name, - }, - }, - "formatters": { - "indent": { - "()": IndentingFormatter, - "format": "%(message)s", - }, - "indent_with_timestamp": { - "()": IndentingFormatter, - "format": "%(message)s", - "add_timestamp": True, - }, - }, - "handlers": { - "console": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stdout"], - "filters": ["exclude_subprocess", "exclude_warnings"], - "formatter": "indent", - }, - "console_errors": { - "level": "WARNING", - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["exclude_subprocess"], - "formatter": "indent", - }, - # A handler responsible for logging to the console messages - # from the "subprocessor" logger. - "console_subprocess": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["restrict_to_subprocess"], - "formatter": "indent", - }, - "user_log": { - "level": "DEBUG", - "class": handler_classes["file"], - "filename": additional_log_file, - "encoding": "utf-8", - "delay": True, - "formatter": "indent_with_timestamp", - }, - }, - "root": { - "level": root_level, - "handlers": handlers, - }, - "loggers": {"pip._vendor": {"level": vendored_log_level}}, - } - ) - - return level_number diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/misc.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/misc.py deleted file mode 100644 index 99ebea3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/misc.py +++ /dev/null @@ -1,828 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import contextlib -import errno -import getpass -import hashlib -import io -import logging -import os -import posixpath -import shutil -import stat -import sys -import urllib.parse -from io import StringIO -from itertools import filterfalse, tee, zip_longest -from types import TracebackType -from typing import ( - Any, - AnyStr, - BinaryIO, - Callable, - Container, - ContextManager, - Iterable, - Iterator, - List, - Optional, - TextIO, - Tuple, - Type, - TypeVar, - cast, -) - -from pip._vendor.pkg_resources import Distribution -from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed - -from pip import __version__ -from pip._internal.exceptions import CommandError -from pip._internal.locations import get_major_minor_version, site_packages, user_site -from pip._internal.utils.compat import WINDOWS, stdlib_pkgs -from pip._internal.utils.virtualenv import ( - running_under_virtualenv, - virtualenv_no_global, -) - -__all__ = [ - "rmtree", - "display_path", - "backup_dir", - "ask", - "splitext", - "format_size", - "is_installable_dir", - "normalize_path", - "renames", - "get_prog", - "captured_stdout", - "ensure_dir", - "remove_auth_from_url", -] - - -logger = logging.getLogger(__name__) - -T = TypeVar("T") -ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType] -VersionInfo = Tuple[int, int, int] -NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]] - - -def get_pip_version(): - # type: () -> str - pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") - pip_pkg_dir = os.path.abspath(pip_pkg_dir) - - return "pip {} from {} (python {})".format( - __version__, - pip_pkg_dir, - get_major_minor_version(), - ) - - -def normalize_version_info(py_version_info): - # type: (Tuple[int, ...]) -> Tuple[int, int, int] - """ - Convert a tuple of ints representing a Python version to one of length - three. - - :param py_version_info: a tuple of ints representing a Python version, - or None to specify no version. The tuple can have any length. - - :return: a tuple of length three if `py_version_info` is non-None. - Otherwise, return `py_version_info` unchanged (i.e. None). - """ - if len(py_version_info) < 3: - py_version_info += (3 - len(py_version_info)) * (0,) - elif len(py_version_info) > 3: - py_version_info = py_version_info[:3] - - return cast("VersionInfo", py_version_info) - - -def ensure_dir(path): - # type: (AnyStr) -> None - """os.path.makedirs without EEXIST.""" - try: - os.makedirs(path) - except OSError as e: - # Windows can raise spurious ENOTEMPTY errors. See #6426. - if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY: - raise - - -def get_prog(): - # type: () -> str - try: - prog = os.path.basename(sys.argv[0]) - if prog in ("__main__.py", "-c"): - return f"{sys.executable} -m pip" - else: - return prog - except (AttributeError, TypeError, IndexError): - pass - return "pip" - - -# Retry every half second for up to 3 seconds -# Tenacity raises RetryError by default, explicitly raise the original exception -@retry(reraise=True, stop=stop_after_delay(3), wait=wait_fixed(0.5)) -def rmtree(dir, ignore_errors=False): - # type: (AnyStr, bool) -> None - shutil.rmtree(dir, ignore_errors=ignore_errors, onerror=rmtree_errorhandler) - - -def rmtree_errorhandler(func, path, exc_info): - # type: (Callable[..., Any], str, ExcInfo) -> None - """On Windows, the files in .svn are read-only, so when rmtree() tries to - remove them, an exception is thrown. We catch that here, remove the - read-only attribute, and hopefully continue without problems.""" - try: - has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE) - except OSError: - # it's equivalent to os.path.exists - return - - if has_attr_readonly: - # convert to read/write - os.chmod(path, stat.S_IWRITE) - # use the original function to repeat the operation - func(path) - return - else: - raise - - -def display_path(path): - # type: (str) -> str - """Gives the display value for a given path, making it relative to cwd - if possible.""" - path = os.path.normcase(os.path.abspath(path)) - if path.startswith(os.getcwd() + os.path.sep): - path = "." + path[len(os.getcwd()) :] - return path - - -def backup_dir(dir, ext=".bak"): - # type: (str, str) -> str - """Figure out the name of a directory to back up the given dir to - (adding .bak, .bak2, etc)""" - n = 1 - extension = ext - while os.path.exists(dir + extension): - n += 1 - extension = ext + str(n) - return dir + extension - - -def ask_path_exists(message, options): - # type: (str, Iterable[str]) -> str - for action in os.environ.get("PIP_EXISTS_ACTION", "").split(): - if action in options: - return action - return ask(message, options) - - -def _check_no_input(message): - # type: (str) -> None - """Raise an error if no input is allowed.""" - if os.environ.get("PIP_NO_INPUT"): - raise Exception( - f"No input was expected ($PIP_NO_INPUT set); question: {message}" - ) - - -def ask(message, options): - # type: (str, Iterable[str]) -> str - """Ask the message interactively, with the given possible responses""" - while 1: - _check_no_input(message) - response = input(message) - response = response.strip().lower() - if response not in options: - print( - "Your response ({!r}) was not one of the expected responses: " - "{}".format(response, ", ".join(options)) - ) - else: - return response - - -def ask_input(message): - # type: (str) -> str - """Ask for input interactively.""" - _check_no_input(message) - return input(message) - - -def ask_password(message): - # type: (str) -> str - """Ask for a password interactively.""" - _check_no_input(message) - return getpass.getpass(message) - - -def strtobool(val): - # type: (str) -> int - """Convert a string representation of truth to true (1) or false (0). - - True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values - are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if - 'val' is anything else. - """ - val = val.lower() - if val in ("y", "yes", "t", "true", "on", "1"): - return 1 - elif val in ("n", "no", "f", "false", "off", "0"): - return 0 - else: - raise ValueError(f"invalid truth value {val!r}") - - -def format_size(bytes): - # type: (float) -> str - if bytes > 1000 * 1000: - return "{:.1f} MB".format(bytes / 1000.0 / 1000) - elif bytes > 10 * 1000: - return "{} kB".format(int(bytes / 1000)) - elif bytes > 1000: - return "{:.1f} kB".format(bytes / 1000.0) - else: - return "{} bytes".format(int(bytes)) - - -def tabulate(rows): - # type: (Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]] - """Return a list of formatted rows and a list of column sizes. - - For example:: - - >>> tabulate([['foobar', 2000], [0xdeadbeef]]) - (['foobar 2000', '3735928559'], [10, 4]) - """ - rows = [tuple(map(str, row)) for row in rows] - sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")] - table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] - return table, sizes - - -def is_installable_dir(path: str) -> bool: - """Is path is a directory containing pyproject.toml or setup.py? - - If pyproject.toml exists, this is a PEP 517 project. Otherwise we look for - a legacy setuptools layout by identifying setup.py. We don't check for the - setup.cfg because using it without setup.py is only available for PEP 517 - projects, which are already covered by the pyproject.toml check. - """ - if not os.path.isdir(path): - return False - if os.path.isfile(os.path.join(path, "pyproject.toml")): - return True - if os.path.isfile(os.path.join(path, "setup.py")): - return True - return False - - -def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): - # type: (BinaryIO, int) -> Iterator[bytes] - """Yield pieces of data from a file-like object until EOF.""" - while True: - chunk = file.read(size) - if not chunk: - break - yield chunk - - -def normalize_path(path, resolve_symlinks=True): - # type: (str, bool) -> str - """ - Convert a path to its canonical, case-normalized, absolute version. - - """ - path = os.path.expanduser(path) - if resolve_symlinks: - path = os.path.realpath(path) - else: - path = os.path.abspath(path) - return os.path.normcase(path) - - -def splitext(path): - # type: (str) -> Tuple[str, str] - """Like os.path.splitext, but take off .tar too""" - base, ext = posixpath.splitext(path) - if base.lower().endswith(".tar"): - ext = base[-4:] + ext - base = base[:-4] - return base, ext - - -def renames(old, new): - # type: (str, str) -> None - """Like os.renames(), but handles renaming across devices.""" - # Implementation borrowed from os.renames(). - head, tail = os.path.split(new) - if head and tail and not os.path.exists(head): - os.makedirs(head) - - shutil.move(old, new) - - head, tail = os.path.split(old) - if head and tail: - try: - os.removedirs(head) - except OSError: - pass - - -def is_local(path): - # type: (str) -> bool - """ - Return True if path is within sys.prefix, if we're running in a virtualenv. - - If we're not in a virtualenv, all paths are considered "local." - - Caution: this function assumes the head of path has been normalized - with normalize_path. - """ - if not running_under_virtualenv(): - return True - return path.startswith(normalize_path(sys.prefix)) - - -def dist_is_local(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution object is installed locally - (i.e. within current virtualenv). - - Always True if we're not in a virtualenv. - - """ - return is_local(dist_location(dist)) - - -def dist_in_usersite(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is installed in user site. - """ - return dist_location(dist).startswith(normalize_path(user_site)) - - -def dist_in_site_packages(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is installed in - sysconfig.get_python_lib(). - """ - return dist_location(dist).startswith(normalize_path(site_packages)) - - -def dist_is_editable(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is an editable install. - """ - for path_item in sys.path: - egg_link = os.path.join(path_item, dist.project_name + ".egg-link") - if os.path.isfile(egg_link): - return True - return False - - -def get_installed_distributions( - local_only=True, # type: bool - skip=stdlib_pkgs, # type: Container[str] - include_editables=True, # type: bool - editables_only=False, # type: bool - user_only=False, # type: bool - paths=None, # type: Optional[List[str]] -): - # type: (...) -> List[Distribution] - """Return a list of installed Distribution objects. - - Left for compatibility until direct pkg_resources uses are refactored out. - """ - from pip._internal.metadata import get_default_environment, get_environment - from pip._internal.metadata.pkg_resources import Distribution as _Dist - - if paths is None: - env = get_default_environment() - else: - env = get_environment(paths) - dists = env.iter_installed_distributions( - local_only=local_only, - skip=skip, - include_editables=include_editables, - editables_only=editables_only, - user_only=user_only, - ) - return [cast(_Dist, dist)._dist for dist in dists] - - -def get_distribution(req_name): - # type: (str) -> Optional[Distribution] - """Given a requirement name, return the installed Distribution object. - - This searches from *all* distributions available in the environment, to - match the behavior of ``pkg_resources.get_distribution()``. - - Left for compatibility until direct pkg_resources uses are refactored out. - """ - from pip._internal.metadata import get_default_environment - from pip._internal.metadata.pkg_resources import Distribution as _Dist - - dist = get_default_environment().get_distribution(req_name) - if dist is None: - return None - return cast(_Dist, dist)._dist - - -def egg_link_path(dist): - # type: (Distribution) -> Optional[str] - """ - Return the path for the .egg-link file if it exists, otherwise, None. - - There's 3 scenarios: - 1) not in a virtualenv - try to find in site.USER_SITE, then site_packages - 2) in a no-global virtualenv - try to find in site_packages - 3) in a yes-global virtualenv - try to find in site_packages, then site.USER_SITE - (don't look in global location) - - For #1 and #3, there could be odd cases, where there's an egg-link in 2 - locations. - - This method will just return the first one found. - """ - sites = [] - if running_under_virtualenv(): - sites.append(site_packages) - if not virtualenv_no_global() and user_site: - sites.append(user_site) - else: - if user_site: - sites.append(user_site) - sites.append(site_packages) - - for site in sites: - egglink = os.path.join(site, dist.project_name) + ".egg-link" - if os.path.isfile(egglink): - return egglink - return None - - -def dist_location(dist): - # type: (Distribution) -> str - """ - Get the site-packages location of this distribution. Generally - this is dist.location, except in the case of develop-installed - packages, where dist.location is the source code location, and we - want to know where the egg-link file is. - - The returned location is normalized (in particular, with symlinks removed). - """ - egg_link = egg_link_path(dist) - if egg_link: - return normalize_path(egg_link) - return normalize_path(dist.location) - - -def write_output(msg, *args): - # type: (Any, Any) -> None - logger.info(msg, *args) - - -class StreamWrapper(StringIO): - orig_stream = None # type: TextIO - - @classmethod - def from_stream(cls, orig_stream): - # type: (TextIO) -> StreamWrapper - cls.orig_stream = orig_stream - return cls() - - # compileall.compile_dir() needs stdout.encoding to print to stdout - # https://github.com/python/mypy/issues/4125 - @property - def encoding(self): # type: ignore - return self.orig_stream.encoding - - -@contextlib.contextmanager -def captured_output(stream_name): - # type: (str) -> Iterator[StreamWrapper] - """Return a context manager used by captured_stdout/stdin/stderr - that temporarily replaces the sys stream *stream_name* with a StringIO. - - Taken from Lib/support/__init__.py in the CPython repo. - """ - orig_stdout = getattr(sys, stream_name) - setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) - try: - yield getattr(sys, stream_name) - finally: - setattr(sys, stream_name, orig_stdout) - - -def captured_stdout(): - # type: () -> ContextManager[StreamWrapper] - """Capture the output of sys.stdout: - - with captured_stdout() as stdout: - print('hello') - self.assertEqual(stdout.getvalue(), 'hello\n') - - Taken from Lib/support/__init__.py in the CPython repo. - """ - return captured_output("stdout") - - -def captured_stderr(): - # type: () -> ContextManager[StreamWrapper] - """ - See captured_stdout(). - """ - return captured_output("stderr") - - -# Simulates an enum -def enum(*sequential, **named): - # type: (*Any, **Any) -> Type[Any] - enums = dict(zip(sequential, range(len(sequential))), **named) - reverse = {value: key for key, value in enums.items()} - enums["reverse_mapping"] = reverse - return type("Enum", (), enums) - - -def build_netloc(host, port): - # type: (str, Optional[int]) -> str - """ - Build a netloc from a host-port pair - """ - if port is None: - return host - if ":" in host: - # Only wrap host with square brackets when it is IPv6 - host = f"[{host}]" - return f"{host}:{port}" - - -def build_url_from_netloc(netloc, scheme="https"): - # type: (str, str) -> str - """ - Build a full URL from a netloc. - """ - if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc: - # It must be a bare IPv6 address, so wrap it with brackets. - netloc = f"[{netloc}]" - return f"{scheme}://{netloc}" - - -def parse_netloc(netloc): - # type: (str) -> Tuple[str, Optional[int]] - """ - Return the host-port pair from a netloc. - """ - url = build_url_from_netloc(netloc) - parsed = urllib.parse.urlparse(url) - return parsed.hostname, parsed.port - - -def split_auth_from_netloc(netloc): - # type: (str) -> NetlocTuple - """ - Parse out and remove the auth information from a netloc. - - Returns: (netloc, (username, password)). - """ - if "@" not in netloc: - return netloc, (None, None) - - # Split from the right because that's how urllib.parse.urlsplit() - # behaves if more than one @ is present (which can be checked using - # the password attribute of urlsplit()'s return value). - auth, netloc = netloc.rsplit("@", 1) - pw = None # type: Optional[str] - if ":" in auth: - # Split from the left because that's how urllib.parse.urlsplit() - # behaves if more than one : is present (which again can be checked - # using the password attribute of the return value) - user, pw = auth.split(":", 1) - else: - user, pw = auth, None - - user = urllib.parse.unquote(user) - if pw is not None: - pw = urllib.parse.unquote(pw) - - return netloc, (user, pw) - - -def redact_netloc(netloc): - # type: (str) -> str - """ - Replace the sensitive data in a netloc with "****", if it exists. - - For example: - - "user:pass@example.com" returns "user:****@example.com" - - "accesstoken@example.com" returns "****@example.com" - """ - netloc, (user, password) = split_auth_from_netloc(netloc) - if user is None: - return netloc - if password is None: - user = "****" - password = "" - else: - user = urllib.parse.quote(user) - password = ":****" - return "{user}{password}@{netloc}".format( - user=user, password=password, netloc=netloc - ) - - -def _transform_url(url, transform_netloc): - # type: (str, Callable[[str], Tuple[Any, ...]]) -> Tuple[str, NetlocTuple] - """Transform and replace netloc in a url. - - transform_netloc is a function taking the netloc and returning a - tuple. The first element of this tuple is the new netloc. The - entire tuple is returned. - - Returns a tuple containing the transformed url as item 0 and the - original tuple returned by transform_netloc as item 1. - """ - purl = urllib.parse.urlsplit(url) - netloc_tuple = transform_netloc(purl.netloc) - # stripped url - url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment) - surl = urllib.parse.urlunsplit(url_pieces) - return surl, cast("NetlocTuple", netloc_tuple) - - -def _get_netloc(netloc): - # type: (str) -> NetlocTuple - return split_auth_from_netloc(netloc) - - -def _redact_netloc(netloc): - # type: (str) -> Tuple[str,] - return (redact_netloc(netloc),) - - -def split_auth_netloc_from_url(url): - # type: (str) -> Tuple[str, str, Tuple[str, str]] - """ - Parse a url into separate netloc, auth, and url with no auth. - - Returns: (url_without_auth, netloc, (username, password)) - """ - url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc) - return url_without_auth, netloc, auth - - -def remove_auth_from_url(url): - # type: (str) -> str - """Return a copy of url with 'username:password@' removed.""" - # username/pass params are passed to subversion through flags - # and are not recognized in the url. - return _transform_url(url, _get_netloc)[0] - - -def redact_auth_from_url(url): - # type: (str) -> str - """Replace the password in a given url with ****.""" - return _transform_url(url, _redact_netloc)[0] - - -class HiddenText: - def __init__( - self, - secret, # type: str - redacted, # type: str - ): - # type: (...) -> None - self.secret = secret - self.redacted = redacted - - def __repr__(self): - # type: (...) -> str - return "".format(str(self)) - - def __str__(self): - # type: (...) -> str - return self.redacted - - # This is useful for testing. - def __eq__(self, other): - # type: (Any) -> bool - if type(self) != type(other): - return False - - # The string being used for redaction doesn't also have to match, - # just the raw, original string. - return self.secret == other.secret - - -def hide_value(value): - # type: (str) -> HiddenText - return HiddenText(value, redacted="****") - - -def hide_url(url): - # type: (str) -> HiddenText - redacted = redact_auth_from_url(url) - return HiddenText(url, redacted=redacted) - - -def protect_pip_from_modification_on_windows(modifying_pip): - # type: (bool) -> None - """Protection of pip.exe from modification on Windows - - On Windows, any operation modifying pip should be run as: - python -m pip ... - """ - pip_names = [ - "pip.exe", - "pip{}.exe".format(sys.version_info[0]), - "pip{}.{}.exe".format(*sys.version_info[:2]), - ] - - # See https://github.com/pypa/pip/issues/1299 for more discussion - should_show_use_python_msg = ( - modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names - ) - - if should_show_use_python_msg: - new_command = [sys.executable, "-m", "pip"] + sys.argv[1:] - raise CommandError( - "To modify pip, please run the following command:\n{}".format( - " ".join(new_command) - ) - ) - - -def is_console_interactive(): - # type: () -> bool - """Is this console interactive?""" - return sys.stdin is not None and sys.stdin.isatty() - - -def hash_file(path, blocksize=1 << 20): - # type: (str, int) -> Tuple[Any, int] - """Return (hash, length) for path using hashlib.sha256()""" - - h = hashlib.sha256() - length = 0 - with open(path, "rb") as f: - for block in read_chunks(f, size=blocksize): - length += len(block) - h.update(block) - return h, length - - -def is_wheel_installed(): - # type: () -> bool - """ - Return whether the wheel package is installed. - """ - try: - import wheel # noqa: F401 - except ImportError: - return False - - return True - - -def pairwise(iterable): - # type: (Iterable[Any]) -> Iterator[Tuple[Any, Any]] - """ - Return paired elements. - - For example: - s -> (s0, s1), (s2, s3), (s4, s5), ... - """ - iterable = iter(iterable) - return zip_longest(iterable, iterable) - - -def partition( - pred, # type: Callable[[T], bool] - iterable, # type: Iterable[T] -): - # type: (...) -> Tuple[Iterable[T], Iterable[T]] - """ - Use a predicate to partition entries into false entries and true entries, - like - - partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 - """ - t1, t2 = tee(iterable) - return filterfalse(pred, t1), filter(pred, t2) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/models.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/models.py deleted file mode 100644 index 0e02bc7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/models.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Utilities for defining models -""" - -import operator -from typing import Any, Callable, Type - - -class KeyBasedCompareMixin: - """Provides comparison capabilities that is based on a key""" - - __slots__ = ["_compare_key", "_defining_class"] - - def __init__(self, key, defining_class): - # type: (Any, Type[KeyBasedCompareMixin]) -> None - self._compare_key = key - self._defining_class = defining_class - - def __hash__(self): - # type: () -> int - return hash(self._compare_key) - - def __lt__(self, other): - # type: (Any) -> bool - return self._compare(other, operator.__lt__) - - def __le__(self, other): - # type: (Any) -> bool - return self._compare(other, operator.__le__) - - def __gt__(self, other): - # type: (Any) -> bool - return self._compare(other, operator.__gt__) - - def __ge__(self, other): - # type: (Any) -> bool - return self._compare(other, operator.__ge__) - - def __eq__(self, other): - # type: (Any) -> bool - return self._compare(other, operator.__eq__) - - def _compare(self, other, method): - # type: (Any, Callable[[Any, Any], bool]) -> bool - if not isinstance(other, self._defining_class): - return NotImplemented - - return method(self._compare_key, other._compare_key) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/packaging.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/packaging.py deleted file mode 100644 index 3f9dbd3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/packaging.py +++ /dev/null @@ -1,89 +0,0 @@ -import logging -from email.message import Message -from email.parser import FeedParser -from typing import Optional, Tuple - -from pip._vendor import pkg_resources -from pip._vendor.packaging import specifiers, version -from pip._vendor.pkg_resources import Distribution - -from pip._internal.exceptions import NoneMetadataError -from pip._internal.utils.misc import display_path - -logger = logging.getLogger(__name__) - - -def check_requires_python(requires_python, version_info): - # type: (Optional[str], Tuple[int, ...]) -> bool - """ - Check if the given Python version matches a "Requires-Python" specifier. - - :param version_info: A 3-tuple of ints representing a Python - major-minor-micro version to check (e.g. `sys.version_info[:3]`). - - :return: `True` if the given Python version satisfies the requirement. - Otherwise, return `False`. - - :raises InvalidSpecifier: If `requires_python` has an invalid format. - """ - if requires_python is None: - # The package provides no information - return True - requires_python_specifier = specifiers.SpecifierSet(requires_python) - - python_version = version.parse(".".join(map(str, version_info))) - return python_version in requires_python_specifier - - -def get_metadata(dist): - # type: (Distribution) -> Message - """ - :raises NoneMetadataError: if the distribution reports `has_metadata()` - True but `get_metadata()` returns None. - """ - metadata_name = "METADATA" - if isinstance(dist, pkg_resources.DistInfoDistribution) and dist.has_metadata( - metadata_name - ): - metadata = dist.get_metadata(metadata_name) - elif dist.has_metadata("PKG-INFO"): - metadata_name = "PKG-INFO" - metadata = dist.get_metadata(metadata_name) - else: - logger.warning("No metadata found in %s", display_path(dist.location)) - metadata = "" - - if metadata is None: - raise NoneMetadataError(dist, metadata_name) - - feed_parser = FeedParser() - # The following line errors out if with a "NoneType" TypeError if - # passed metadata=None. - feed_parser.feed(metadata) - return feed_parser.close() - - -def get_requires_python(dist): - # type: (pkg_resources.Distribution) -> Optional[str] - """ - Return the "Requires-Python" metadata for a distribution, or None - if not present. - """ - pkg_info_dict = get_metadata(dist) - requires_python = pkg_info_dict.get("Requires-Python") - - if requires_python is not None: - # Convert to a str to satisfy the type checker, since requires_python - # can be a Header object. - requires_python = str(requires_python) - - return requires_python - - -def get_installer(dist): - # type: (Distribution) -> str - if dist.has_metadata("INSTALLER"): - for line in dist.get_metadata_lines("INSTALLER"): - if line.strip(): - return line.strip() - return "" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/parallel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/parallel.py deleted file mode 100644 index de91dc8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/parallel.py +++ /dev/null @@ -1,101 +0,0 @@ -"""Convenient parallelization of higher order functions. - -This module provides two helper functions, with appropriate fallbacks on -Python 2 and on systems lacking support for synchronization mechanisms: - -- map_multiprocess -- map_multithread - -These helpers work like Python 3's map, with two differences: - -- They don't guarantee the order of processing of - the elements of the iterable. -- The underlying process/thread pools chop the iterable into - a number of chunks, so that for very long iterables using - a large value for chunksize can make the job complete much faster - than using the default value of 1. -""" - -__all__ = ["map_multiprocess", "map_multithread"] - -from contextlib import contextmanager -from multiprocessing import Pool as ProcessPool -from multiprocessing import pool -from multiprocessing.dummy import Pool as ThreadPool -from typing import Callable, Iterable, Iterator, TypeVar, Union - -from pip._vendor.requests.adapters import DEFAULT_POOLSIZE - -Pool = Union[pool.Pool, pool.ThreadPool] -S = TypeVar("S") -T = TypeVar("T") - -# On platforms without sem_open, multiprocessing[.dummy] Pool -# cannot be created. -try: - import multiprocessing.synchronize # noqa -except ImportError: - LACK_SEM_OPEN = True -else: - LACK_SEM_OPEN = False - -# Incredibly large timeout to work around bpo-8296 on Python 2. -TIMEOUT = 2000000 - - -@contextmanager -def closing(pool): - # type: (Pool) -> Iterator[Pool] - """Return a context manager making sure the pool closes properly.""" - try: - yield pool - finally: - # For Pool.imap*, close and join are needed - # for the returned iterator to begin yielding. - pool.close() - pool.join() - pool.terminate() - - -def _map_fallback(func, iterable, chunksize=1): - # type: (Callable[[S], T], Iterable[S], int) -> Iterator[T] - """Make an iterator applying func to each element in iterable. - - This function is the sequential fallback either on Python 2 - where Pool.imap* doesn't react to KeyboardInterrupt - or when sem_open is unavailable. - """ - return map(func, iterable) - - -def _map_multiprocess(func, iterable, chunksize=1): - # type: (Callable[[S], T], Iterable[S], int) -> Iterator[T] - """Chop iterable into chunks and submit them to a process pool. - - For very long iterables using a large value for chunksize can make - the job complete much faster than using the default value of 1. - - Return an unordered iterator of the results. - """ - with closing(ProcessPool()) as pool: - return pool.imap_unordered(func, iterable, chunksize) - - -def _map_multithread(func, iterable, chunksize=1): - # type: (Callable[[S], T], Iterable[S], int) -> Iterator[T] - """Chop iterable into chunks and submit them to a thread pool. - - For very long iterables using a large value for chunksize can make - the job complete much faster than using the default value of 1. - - Return an unordered iterator of the results. - """ - with closing(ThreadPool(DEFAULT_POOLSIZE)) as pool: - return pool.imap_unordered(func, iterable, chunksize) - - -if LACK_SEM_OPEN: - map_multiprocess = map_multithread = _map_fallback -else: - map_multiprocess = _map_multiprocess - map_multithread = _map_multithread diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/pkg_resources.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/pkg_resources.py deleted file mode 100644 index ee1eca3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/pkg_resources.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import Dict, Iterable, List - -from pip._vendor.pkg_resources import yield_lines - - -class DictMetadata: - """IMetadataProvider that reads metadata files from a dictionary.""" - - def __init__(self, metadata): - # type: (Dict[str, bytes]) -> None - self._metadata = metadata - - def has_metadata(self, name): - # type: (str) -> bool - return name in self._metadata - - def get_metadata(self, name): - # type: (str) -> str - try: - return self._metadata[name].decode() - except UnicodeDecodeError as e: - # Mirrors handling done in pkg_resources.NullProvider. - e.reason += f" in {name} file" - raise - - def get_metadata_lines(self, name): - # type: (str) -> Iterable[str] - return yield_lines(self.get_metadata(name)) - - def metadata_isdir(self, name): - # type: (str) -> bool - return False - - def metadata_listdir(self, name): - # type: (str) -> List[str] - return [] - - def run_script(self, script_name, namespace): - # type: (str, str) -> None - pass diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/setuptools_build.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/setuptools_build.py deleted file mode 100644 index 4b8e4b3..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/setuptools_build.py +++ /dev/null @@ -1,173 +0,0 @@ -import sys -from typing import List, Optional, Sequence - -# Shim to wrap setup.py invocation with setuptools -# -# We set sys.argv[0] to the path to the underlying setup.py file so -# setuptools / distutils don't take the path to the setup.py to be "-c" when -# invoking via the shim. This avoids e.g. the following manifest_maker -# warning: "warning: manifest_maker: standard file '-c' not found". -_SETUPTOOLS_SHIM = ( - "import io, os, sys, setuptools, tokenize; sys.argv[0] = {0!r}; __file__={0!r};" - "f = getattr(tokenize, 'open', open)(__file__) " - "if os.path.exists(__file__) " - "else io.StringIO('from setuptools import setup; setup()');" - "code = f.read().replace('\\r\\n', '\\n');" - "f.close();" - "exec(compile(code, __file__, 'exec'))" -) - - -def make_setuptools_shim_args( - setup_py_path, # type: str - global_options=None, # type: Sequence[str] - no_user_config=False, # type: bool - unbuffered_output=False, # type: bool -): - # type: (...) -> List[str] - """ - Get setuptools command arguments with shim wrapped setup file invocation. - - :param setup_py_path: The path to setup.py to be wrapped. - :param global_options: Additional global options. - :param no_user_config: If True, disables personal user configuration. - :param unbuffered_output: If True, adds the unbuffered switch to the - argument list. - """ - args = [sys.executable] - if unbuffered_output: - args += ["-u"] - args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)] - if global_options: - args += global_options - if no_user_config: - args += ["--no-user-cfg"] - return args - - -def make_setuptools_bdist_wheel_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - build_options, # type: Sequence[str] - destination_dir, # type: str -): - # type: (...) -> List[str] - # NOTE: Eventually, we'd want to also -S to the flags here, when we're - # isolating. Currently, it breaks Python in virtualenvs, because it - # relies on site.py to find parts of the standard library outside the - # virtualenv. - args = make_setuptools_shim_args( - setup_py_path, global_options=global_options, unbuffered_output=True - ) - args += ["bdist_wheel", "-d", destination_dir] - args += build_options - return args - - -def make_setuptools_clean_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] -): - # type: (...) -> List[str] - args = make_setuptools_shim_args( - setup_py_path, global_options=global_options, unbuffered_output=True - ) - args += ["clean", "--all"] - return args - - -def make_setuptools_develop_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - install_options, # type: Sequence[str] - no_user_config, # type: bool - prefix, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool -): - # type: (...) -> List[str] - assert not (use_user_site and prefix) - - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - no_user_config=no_user_config, - ) - - args += ["develop", "--no-deps"] - - args += install_options - - if prefix: - args += ["--prefix", prefix] - if home is not None: - args += ["--install-dir", home] - - if use_user_site: - args += ["--user", "--prefix="] - - return args - - -def make_setuptools_egg_info_args( - setup_py_path, # type: str - egg_info_dir, # type: Optional[str] - no_user_config, # type: bool -): - # type: (...) -> List[str] - args = make_setuptools_shim_args(setup_py_path, no_user_config=no_user_config) - - args += ["egg_info"] - - if egg_info_dir: - args += ["--egg-base", egg_info_dir] - - return args - - -def make_setuptools_install_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - install_options, # type: Sequence[str] - record_filename, # type: str - root, # type: Optional[str] - prefix, # type: Optional[str] - header_dir, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool - no_user_config, # type: bool - pycompile, # type: bool -): - # type: (...) -> List[str] - assert not (use_user_site and prefix) - assert not (use_user_site and root) - - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - no_user_config=no_user_config, - unbuffered_output=True, - ) - args += ["install", "--record", record_filename] - args += ["--single-version-externally-managed"] - - if root is not None: - args += ["--root", root] - if prefix is not None: - args += ["--prefix", prefix] - if home is not None: - args += ["--home", home] - if use_user_site: - args += ["--user", "--prefix="] - - if pycompile: - args += ["--compile"] - else: - args += ["--no-compile"] - - if header_dir: - args += ["--install-headers", header_dir] - - args += install_options - - return args diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/subprocess.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/subprocess.py deleted file mode 100644 index da052ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/subprocess.py +++ /dev/null @@ -1,281 +0,0 @@ -import logging -import os -import shlex -import subprocess -from typing import Any, Callable, Iterable, List, Mapping, Optional, Union - -from pip._internal.cli.spinners import SpinnerInterface, open_spinner -from pip._internal.exceptions import InstallationSubprocessError -from pip._internal.utils.logging import VERBOSE, subprocess_logger -from pip._internal.utils.misc import HiddenText - -CommandArgs = List[Union[str, HiddenText]] - - -LOG_DIVIDER = "----------------------------------------" - - -def make_command(*args): - # type: (Union[str, HiddenText, CommandArgs]) -> CommandArgs - """ - Create a CommandArgs object. - """ - command_args = [] # type: CommandArgs - for arg in args: - # Check for list instead of CommandArgs since CommandArgs is - # only known during type-checking. - if isinstance(arg, list): - command_args.extend(arg) - else: - # Otherwise, arg is str or HiddenText. - command_args.append(arg) - - return command_args - - -def format_command_args(args): - # type: (Union[List[str], CommandArgs]) -> str - """ - Format command arguments for display. - """ - # For HiddenText arguments, display the redacted form by calling str(). - # Also, we don't apply str() to arguments that aren't HiddenText since - # this can trigger a UnicodeDecodeError in Python 2 if the argument - # has type unicode and includes a non-ascii character. (The type - # checker doesn't ensure the annotations are correct in all cases.) - return " ".join( - shlex.quote(str(arg)) if isinstance(arg, HiddenText) else shlex.quote(arg) - for arg in args - ) - - -def reveal_command_args(args): - # type: (Union[List[str], CommandArgs]) -> List[str] - """ - Return the arguments in their raw, unredacted form. - """ - return [arg.secret if isinstance(arg, HiddenText) else arg for arg in args] - - -def make_subprocess_output_error( - cmd_args, # type: Union[List[str], CommandArgs] - cwd, # type: Optional[str] - lines, # type: List[str] - exit_status, # type: int -): - # type: (...) -> str - """ - Create and return the error message to use to log a subprocess error - with command output. - - :param lines: A list of lines, each ending with a newline. - """ - command = format_command_args(cmd_args) - - # We know the joined output value ends in a newline. - output = "".join(lines) - msg = ( - # Use a unicode string to avoid "UnicodeEncodeError: 'ascii' - # codec can't encode character ..." in Python 2 when a format - # argument (e.g. `output`) has a non-ascii character. - "Command errored out with exit status {exit_status}:\n" - " command: {command_display}\n" - " cwd: {cwd_display}\n" - "Complete output ({line_count} lines):\n{output}{divider}" - ).format( - exit_status=exit_status, - command_display=command, - cwd_display=cwd, - line_count=len(lines), - output=output, - divider=LOG_DIVIDER, - ) - return msg - - -def call_subprocess( - cmd, # type: Union[List[str], CommandArgs] - show_stdout=False, # type: bool - cwd=None, # type: Optional[str] - on_returncode="raise", # type: str - extra_ok_returncodes=None, # type: Optional[Iterable[int]] - command_desc=None, # type: Optional[str] - extra_environ=None, # type: Optional[Mapping[str, Any]] - unset_environ=None, # type: Optional[Iterable[str]] - spinner=None, # type: Optional[SpinnerInterface] - log_failed_cmd=True, # type: Optional[bool] - stdout_only=False, # type: Optional[bool] -): - # type: (...) -> str - """ - Args: - show_stdout: if true, use INFO to log the subprocess's stderr and - stdout streams. Otherwise, use DEBUG. Defaults to False. - extra_ok_returncodes: an iterable of integer return codes that are - acceptable, in addition to 0. Defaults to None, which means []. - unset_environ: an iterable of environment variable names to unset - prior to calling subprocess.Popen(). - log_failed_cmd: if false, failed commands are not logged, only raised. - stdout_only: if true, return only stdout, else return both. When true, - logging of both stdout and stderr occurs when the subprocess has - terminated, else logging occurs as subprocess output is produced. - """ - if extra_ok_returncodes is None: - extra_ok_returncodes = [] - if unset_environ is None: - unset_environ = [] - # Most places in pip use show_stdout=False. What this means is-- - # - # - We connect the child's output (combined stderr and stdout) to a - # single pipe, which we read. - # - We log this output to stderr at DEBUG level as it is received. - # - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't - # requested), then we show a spinner so the user can still see the - # subprocess is in progress. - # - If the subprocess exits with an error, we log the output to stderr - # at ERROR level if it hasn't already been displayed to the console - # (e.g. if --verbose logging wasn't enabled). This way we don't log - # the output to the console twice. - # - # If show_stdout=True, then the above is still done, but with DEBUG - # replaced by INFO. - if show_stdout: - # Then log the subprocess output at INFO level. - log_subprocess = subprocess_logger.info - used_level = logging.INFO - else: - # Then log the subprocess output using VERBOSE. This also ensures - # it will be logged to the log file (aka user_log), if enabled. - log_subprocess = subprocess_logger.verbose - used_level = VERBOSE - - # Whether the subprocess will be visible in the console. - showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level - - # Only use the spinner if we're not showing the subprocess output - # and we have a spinner. - use_spinner = not showing_subprocess and spinner is not None - - if command_desc is None: - command_desc = format_command_args(cmd) - - log_subprocess("Running command %s", command_desc) - env = os.environ.copy() - if extra_environ: - env.update(extra_environ) - for name in unset_environ: - env.pop(name, None) - try: - proc = subprocess.Popen( - # Convert HiddenText objects to the underlying str. - reveal_command_args(cmd), - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT if not stdout_only else subprocess.PIPE, - cwd=cwd, - env=env, - errors="backslashreplace", - ) - except Exception as exc: - if log_failed_cmd: - subprocess_logger.critical( - "Error %s while executing command %s", - exc, - command_desc, - ) - raise - all_output = [] - if not stdout_only: - assert proc.stdout - assert proc.stdin - proc.stdin.close() - # In this mode, stdout and stderr are in the same pipe. - while True: - line = proc.stdout.readline() # type: str - if not line: - break - line = line.rstrip() - all_output.append(line + "\n") - - # Show the line immediately. - log_subprocess(line) - # Update the spinner. - if use_spinner: - assert spinner - spinner.spin() - try: - proc.wait() - finally: - if proc.stdout: - proc.stdout.close() - output = "".join(all_output) - else: - # In this mode, stdout and stderr are in different pipes. - # We must use communicate() which is the only safe way to read both. - out, err = proc.communicate() - # log line by line to preserve pip log indenting - for out_line in out.splitlines(): - log_subprocess(out_line) - all_output.append(out) - for err_line in err.splitlines(): - log_subprocess(err_line) - all_output.append(err) - output = out - - proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes - if use_spinner: - assert spinner - if proc_had_error: - spinner.finish("error") - else: - spinner.finish("done") - if proc_had_error: - if on_returncode == "raise": - if not showing_subprocess and log_failed_cmd: - # Then the subprocess streams haven't been logged to the - # console yet. - msg = make_subprocess_output_error( - cmd_args=cmd, - cwd=cwd, - lines=all_output, - exit_status=proc.returncode, - ) - subprocess_logger.error(msg) - raise InstallationSubprocessError(proc.returncode, command_desc) - elif on_returncode == "warn": - subprocess_logger.warning( - 'Command "%s" had error code %s in %s', - command_desc, - proc.returncode, - cwd, - ) - elif on_returncode == "ignore": - pass - else: - raise ValueError(f"Invalid value: on_returncode={on_returncode!r}") - return output - - -def runner_with_spinner_message(message): - # type: (str) -> Callable[..., None] - """Provide a subprocess_runner that shows a spinner message. - - Intended for use with for pep517's Pep517HookCaller. Thus, the runner has - an API that matches what's expected by Pep517HookCaller.subprocess_runner. - """ - - def runner( - cmd, # type: List[str] - cwd=None, # type: Optional[str] - extra_environ=None, # type: Optional[Mapping[str, Any]] - ): - # type: (...) -> None - with open_spinner(message) as spinner: - call_subprocess( - cmd, - cwd=cwd, - extra_environ=extra_environ, - spinner=spinner, - ) - - return runner diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/temp_dir.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/temp_dir.py deleted file mode 100644 index 477cbe6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/temp_dir.py +++ /dev/null @@ -1,260 +0,0 @@ -import errno -import itertools -import logging -import os.path -import tempfile -from contextlib import ExitStack, contextmanager -from typing import Any, Dict, Iterator, Optional, TypeVar, Union - -from pip._internal.utils.misc import enum, rmtree - -logger = logging.getLogger(__name__) - -_T = TypeVar("_T", bound="TempDirectory") - - -# Kinds of temporary directories. Only needed for ones that are -# globally-managed. -tempdir_kinds = enum( - BUILD_ENV="build-env", - EPHEM_WHEEL_CACHE="ephem-wheel-cache", - REQ_BUILD="req-build", -) - - -_tempdir_manager = None # type: Optional[ExitStack] - - -@contextmanager -def global_tempdir_manager(): - # type: () -> Iterator[None] - global _tempdir_manager - with ExitStack() as stack: - old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack - try: - yield - finally: - _tempdir_manager = old_tempdir_manager - - -class TempDirectoryTypeRegistry: - """Manages temp directory behavior""" - - def __init__(self): - # type: () -> None - self._should_delete = {} # type: Dict[str, bool] - - def set_delete(self, kind, value): - # type: (str, bool) -> None - """Indicate whether a TempDirectory of the given kind should be - auto-deleted. - """ - self._should_delete[kind] = value - - def get_delete(self, kind): - # type: (str) -> bool - """Get configured auto-delete flag for a given TempDirectory type, - default True. - """ - return self._should_delete.get(kind, True) - - -_tempdir_registry = None # type: Optional[TempDirectoryTypeRegistry] - - -@contextmanager -def tempdir_registry(): - # type: () -> Iterator[TempDirectoryTypeRegistry] - """Provides a scoped global tempdir registry that can be used to dictate - whether directories should be deleted. - """ - global _tempdir_registry - old_tempdir_registry = _tempdir_registry - _tempdir_registry = TempDirectoryTypeRegistry() - try: - yield _tempdir_registry - finally: - _tempdir_registry = old_tempdir_registry - - -class _Default: - pass - - -_default = _Default() - - -class TempDirectory: - """Helper class that owns and cleans up a temporary directory. - - This class can be used as a context manager or as an OO representation of a - temporary directory. - - Attributes: - path - Location to the created temporary directory - delete - Whether the directory should be deleted when exiting - (when used as a contextmanager) - - Methods: - cleanup() - Deletes the temporary directory - - When used as a context manager, if the delete attribute is True, on - exiting the context the temporary directory is deleted. - """ - - def __init__( - self, - path=None, # type: Optional[str] - delete=_default, # type: Union[bool, None, _Default] - kind="temp", # type: str - globally_managed=False, # type: bool - ): - super().__init__() - - if delete is _default: - if path is not None: - # If we were given an explicit directory, resolve delete option - # now. - delete = False - else: - # Otherwise, we wait until cleanup and see what - # tempdir_registry says. - delete = None - - # The only time we specify path is in for editables where it - # is the value of the --src option. - if path is None: - path = self._create(kind) - - self._path = path - self._deleted = False - self.delete = delete - self.kind = kind - - if globally_managed: - assert _tempdir_manager is not None - _tempdir_manager.enter_context(self) - - @property - def path(self): - # type: () -> str - assert not self._deleted, f"Attempted to access deleted path: {self._path}" - return self._path - - def __repr__(self): - # type: () -> str - return f"<{self.__class__.__name__} {self.path!r}>" - - def __enter__(self): - # type: (_T) -> _T - return self - - def __exit__(self, exc, value, tb): - # type: (Any, Any, Any) -> None - if self.delete is not None: - delete = self.delete - elif _tempdir_registry: - delete = _tempdir_registry.get_delete(self.kind) - else: - delete = True - - if delete: - self.cleanup() - - def _create(self, kind): - # type: (str) -> str - """Create a temporary directory and store its path in self.path""" - # We realpath here because some systems have their default tmpdir - # symlinked to another directory. This tends to confuse build - # scripts, so we canonicalize the path by traversing potential - # symlinks here. - path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-")) - logger.debug("Created temporary directory: %s", path) - return path - - def cleanup(self): - # type: () -> None - """Remove the temporary directory created and reset state""" - self._deleted = True - if not os.path.exists(self._path): - return - rmtree(self._path) - - -class AdjacentTempDirectory(TempDirectory): - """Helper class that creates a temporary directory adjacent to a real one. - - Attributes: - original - The original directory to create a temp directory for. - path - After calling create() or entering, contains the full - path to the temporary directory. - delete - Whether the directory should be deleted when exiting - (when used as a contextmanager) - - """ - - # The characters that may be used to name the temp directory - # We always prepend a ~ and then rotate through these until - # a usable name is found. - # pkg_resources raises a different error for .dist-info folder - # with leading '-' and invalid metadata - LEADING_CHARS = "-~.=%0123456789" - - def __init__(self, original, delete=None): - # type: (str, Optional[bool]) -> None - self.original = original.rstrip("/\\") - super().__init__(delete=delete) - - @classmethod - def _generate_names(cls, name): - # type: (str) -> Iterator[str] - """Generates a series of temporary names. - - The algorithm replaces the leading characters in the name - with ones that are valid filesystem characters, but are not - valid package names (for both Python and pip definitions of - package). - """ - for i in range(1, len(name)): - for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i - 1 - ): - new_name = "~" + "".join(candidate) + name[i:] - if new_name != name: - yield new_name - - # If we make it this far, we will have to make a longer name - for i in range(len(cls.LEADING_CHARS)): - for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i - ): - new_name = "~" + "".join(candidate) + name - if new_name != name: - yield new_name - - def _create(self, kind): - # type: (str) -> str - root, name = os.path.split(self.original) - for candidate in self._generate_names(name): - path = os.path.join(root, candidate) - try: - os.mkdir(path) - except OSError as ex: - # Continue if the name exists already - if ex.errno != errno.EEXIST: - raise - else: - path = os.path.realpath(path) - break - else: - # Final fallback on the default behavior. - path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-")) - - logger.debug("Created temporary directory: %s", path) - return path diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/unpacking.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/unpacking.py deleted file mode 100644 index bffb3cd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/unpacking.py +++ /dev/null @@ -1,267 +0,0 @@ -"""Utilities related archives. -""" - -import logging -import os -import shutil -import stat -import tarfile -import zipfile -from typing import Iterable, List, Optional -from zipfile import ZipInfo - -from pip._internal.exceptions import InstallationError -from pip._internal.utils.filetypes import ( - BZ2_EXTENSIONS, - TAR_EXTENSIONS, - XZ_EXTENSIONS, - ZIP_EXTENSIONS, -) -from pip._internal.utils.misc import ensure_dir - -logger = logging.getLogger(__name__) - - -SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS - -try: - import bz2 # noqa - - SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS -except ImportError: - logger.debug("bz2 module is not available") - -try: - # Only for Python 3.3+ - import lzma # noqa - - SUPPORTED_EXTENSIONS += XZ_EXTENSIONS -except ImportError: - logger.debug("lzma module is not available") - - -def current_umask(): - # type: () -> int - """Get the current umask which involves having to set it temporarily.""" - mask = os.umask(0) - os.umask(mask) - return mask - - -def split_leading_dir(path): - # type: (str) -> List[str] - path = path.lstrip("/").lstrip("\\") - if "/" in path and ( - ("\\" in path and path.find("/") < path.find("\\")) or "\\" not in path - ): - return path.split("/", 1) - elif "\\" in path: - return path.split("\\", 1) - else: - return [path, ""] - - -def has_leading_dir(paths): - # type: (Iterable[str]) -> bool - """Returns true if all the paths have the same leading path name - (i.e., everything is in one subdirectory in an archive)""" - common_prefix = None - for path in paths: - prefix, rest = split_leading_dir(path) - if not prefix: - return False - elif common_prefix is None: - common_prefix = prefix - elif prefix != common_prefix: - return False - return True - - -def is_within_directory(directory, target): - # type: (str, str) -> bool - """ - Return true if the absolute path of target is within the directory - """ - abs_directory = os.path.abspath(directory) - abs_target = os.path.abspath(target) - - prefix = os.path.commonprefix([abs_directory, abs_target]) - return prefix == abs_directory - - -def set_extracted_file_to_default_mode_plus_executable(path): - # type: (str) -> None - """ - Make file present at path have execute for user/group/world - (chmod +x) is no-op on windows per python docs - """ - os.chmod(path, (0o777 & ~current_umask() | 0o111)) - - -def zip_item_is_executable(info): - # type: (ZipInfo) -> bool - mode = info.external_attr >> 16 - # if mode and regular file and any execute permissions for - # user/group/world? - return bool(mode and stat.S_ISREG(mode) and mode & 0o111) - - -def unzip_file(filename, location, flatten=True): - # type: (str, str, bool) -> None - """ - Unzip the file (with path `filename`) to the destination `location`. All - files are written based on system defaults and umask (i.e. permissions are - not preserved), except that regular file members with any execute - permissions (user, group, or world) have "chmod +x" applied after being - written. Note that for windows, any execute changes using os.chmod are - no-ops per the python docs. - """ - ensure_dir(location) - zipfp = open(filename, "rb") - try: - zip = zipfile.ZipFile(zipfp, allowZip64=True) - leading = has_leading_dir(zip.namelist()) and flatten - for info in zip.infolist(): - name = info.filename - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not is_within_directory(location, fn): - message = ( - "The zip file ({}) has a file ({}) trying to install " - "outside target directory ({})" - ) - raise InstallationError(message.format(filename, fn, location)) - if fn.endswith("/") or fn.endswith("\\"): - # A directory - ensure_dir(fn) - else: - ensure_dir(dir) - # Don't use read() to avoid allocating an arbitrarily large - # chunk of memory for the file's content - fp = zip.open(name) - try: - with open(fn, "wb") as destfp: - shutil.copyfileobj(fp, destfp) - finally: - fp.close() - if zip_item_is_executable(info): - set_extracted_file_to_default_mode_plus_executable(fn) - finally: - zipfp.close() - - -def untar_file(filename, location): - # type: (str, str) -> None - """ - Untar the file (with path `filename`) to the destination `location`. - All files are written based on system defaults and umask (i.e. permissions - are not preserved), except that regular file members with any execute - permissions (user, group, or world) have "chmod +x" applied after being - written. Note that for windows, any execute changes using os.chmod are - no-ops per the python docs. - """ - ensure_dir(location) - if filename.lower().endswith(".gz") or filename.lower().endswith(".tgz"): - mode = "r:gz" - elif filename.lower().endswith(BZ2_EXTENSIONS): - mode = "r:bz2" - elif filename.lower().endswith(XZ_EXTENSIONS): - mode = "r:xz" - elif filename.lower().endswith(".tar"): - mode = "r" - else: - logger.warning( - "Cannot determine compression type for file %s", - filename, - ) - mode = "r:*" - tar = tarfile.open(filename, mode, encoding="utf-8") - try: - leading = has_leading_dir([member.name for member in tar.getmembers()]) - for member in tar.getmembers(): - fn = member.name - if leading: - fn = split_leading_dir(fn)[1] - path = os.path.join(location, fn) - if not is_within_directory(location, path): - message = ( - "The tar file ({}) has a file ({}) trying to install " - "outside target directory ({})" - ) - raise InstallationError(message.format(filename, path, location)) - if member.isdir(): - ensure_dir(path) - elif member.issym(): - try: - # https://github.com/python/typeshed/issues/2673 - tar._extract_member(member, path) # type: ignore - except Exception as exc: - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - logger.warning( - "In the tar file %s the member %s is invalid: %s", - filename, - member.name, - exc, - ) - continue - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError) as exc: - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - logger.warning( - "In the tar file %s the member %s is invalid: %s", - filename, - member.name, - exc, - ) - continue - ensure_dir(os.path.dirname(path)) - assert fp is not None - with open(path, "wb") as destfp: - shutil.copyfileobj(fp, destfp) - fp.close() - # Update the timestamp (useful for cython compiled files) - tar.utime(member, path) - # member have any execute permissions for user/group/world? - if member.mode & 0o111: - set_extracted_file_to_default_mode_plus_executable(path) - finally: - tar.close() - - -def unpack_file( - filename, # type: str - location, # type: str - content_type=None, # type: Optional[str] -): - # type: (...) -> None - filename = os.path.realpath(filename) - if ( - content_type == "application/zip" - or filename.lower().endswith(ZIP_EXTENSIONS) - or zipfile.is_zipfile(filename) - ): - unzip_file(filename, location, flatten=not filename.endswith(".whl")) - elif ( - content_type == "application/x-gzip" - or tarfile.is_tarfile(filename) - or filename.lower().endswith(TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS) - ): - untar_file(filename, location) - else: - # FIXME: handle? - # FIXME: magic signatures? - logger.critical( - "Cannot unpack file %s (downloaded from %s, content-type: %s); " - "cannot detect archive format", - filename, - location, - content_type, - ) - raise InstallationError(f"Cannot determine archive format of {location}") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/urls.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/urls.py deleted file mode 100644 index 7b51052..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/urls.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import string -import urllib.parse -import urllib.request -from typing import Optional - -from .compat import WINDOWS - - -def get_url_scheme(url): - # type: (str) -> Optional[str] - if ":" not in url: - return None - return url.split(":", 1)[0].lower() - - -def path_to_url(path): - # type: (str) -> str - """ - Convert a path to a file: URL. The path will be made absolute and have - quoted path parts. - """ - path = os.path.normpath(os.path.abspath(path)) - url = urllib.parse.urljoin("file:", urllib.request.pathname2url(path)) - return url - - -def url_to_path(url): - # type: (str) -> str - """ - Convert a file: URL to a path. - """ - assert url.startswith( - "file:" - ), f"You can only turn file: urls into filenames (not {url!r})" - - _, netloc, path, _, _ = urllib.parse.urlsplit(url) - - if not netloc or netloc == "localhost": - # According to RFC 8089, same as empty authority. - netloc = "" - elif WINDOWS: - # If we have a UNC path, prepend UNC share notation. - netloc = "\\\\" + netloc - else: - raise ValueError( - f"non-local file URIs are not supported on this platform: {url!r}" - ) - - path = urllib.request.url2pathname(netloc + path) - - # On Windows, urlsplit parses the path as something like "/C:/Users/foo". - # This creates issues for path-related functions like io.open(), so we try - # to detect and strip the leading slash. - if ( - WINDOWS - and not netloc # Not UNC. - and len(path) >= 3 - and path[0] == "/" # Leading slash to strip. - and path[1] in string.ascii_letters # Drive letter. - and path[2:4] in (":", ":/") # Colon + end of string, or colon + absolute path. - ): - path = path[1:] - - return path diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/virtualenv.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/virtualenv.py deleted file mode 100644 index 51cacb5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/virtualenv.py +++ /dev/null @@ -1,111 +0,0 @@ -import logging -import os -import re -import site -import sys -from typing import List, Optional - -logger = logging.getLogger(__name__) -_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile( - r"include-system-site-packages\s*=\s*(?Ptrue|false)" -) - - -def _running_under_venv(): - # type: () -> bool - """Checks if sys.base_prefix and sys.prefix match. - - This handles PEP 405 compliant virtual environments. - """ - return sys.prefix != getattr(sys, "base_prefix", sys.prefix) - - -def _running_under_regular_virtualenv(): - # type: () -> bool - """Checks if sys.real_prefix is set. - - This handles virtual environments created with pypa's virtualenv. - """ - # pypa/virtualenv case - return hasattr(sys, "real_prefix") - - -def running_under_virtualenv(): - # type: () -> bool - """Return True if we're running inside a virtualenv, False otherwise.""" - return _running_under_venv() or _running_under_regular_virtualenv() - - -def _get_pyvenv_cfg_lines(): - # type: () -> Optional[List[str]] - """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines - - Returns None, if it could not read/access the file. - """ - pyvenv_cfg_file = os.path.join(sys.prefix, "pyvenv.cfg") - try: - # Although PEP 405 does not specify, the built-in venv module always - # writes with UTF-8. (pypa/pip#8717) - with open(pyvenv_cfg_file, encoding="utf-8") as f: - return f.read().splitlines() # avoids trailing newlines - except OSError: - return None - - -def _no_global_under_venv(): - # type: () -> bool - """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion - - PEP 405 specifies that when system site-packages are not supposed to be - visible from a virtual environment, `pyvenv.cfg` must contain the following - line: - - include-system-site-packages = false - - Additionally, log a warning if accessing the file fails. - """ - cfg_lines = _get_pyvenv_cfg_lines() - if cfg_lines is None: - # We're not in a "sane" venv, so assume there is no system - # site-packages access (since that's PEP 405's default state). - logger.warning( - "Could not access 'pyvenv.cfg' despite a virtual environment " - "being active. Assuming global site-packages is not accessible " - "in this environment." - ) - return True - - for line in cfg_lines: - match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) - if match is not None and match.group("value") == "false": - return True - return False - - -def _no_global_under_regular_virtualenv(): - # type: () -> bool - """Check if "no-global-site-packages.txt" exists beside site.py - - This mirrors logic in pypa/virtualenv for determining whether system - site-packages are visible in the virtual environment. - """ - site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) - no_global_site_packages_file = os.path.join( - site_mod_dir, - "no-global-site-packages.txt", - ) - return os.path.exists(no_global_site_packages_file) - - -def virtualenv_no_global(): - # type: () -> bool - """Returns a boolean, whether running in venv with no system site-packages.""" - # PEP 405 compliance needs to be checked first since virtualenv >=20 would - # return True for both checks, but is only able to use the PEP 405 config. - if _running_under_venv(): - return _no_global_under_venv() - - if _running_under_regular_virtualenv(): - return _no_global_under_regular_virtualenv() - - return False diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/wheel.py deleted file mode 100644 index 42f0808..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/utils/wheel.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Support functions for working with wheel files. -""" - -import logging -from email.message import Message -from email.parser import Parser -from typing import Dict, Tuple -from zipfile import BadZipFile, ZipFile - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.pkg_resources import DistInfoDistribution, Distribution - -from pip._internal.exceptions import UnsupportedWheel -from pip._internal.utils.pkg_resources import DictMetadata - -VERSION_COMPATIBLE = (1, 0) - - -logger = logging.getLogger(__name__) - - -class WheelMetadata(DictMetadata): - """Metadata provider that maps metadata decoding exceptions to our - internal exception type. - """ - - def __init__(self, metadata, wheel_name): - # type: (Dict[str, bytes], str) -> None - super().__init__(metadata) - self._wheel_name = wheel_name - - def get_metadata(self, name): - # type: (str) -> str - try: - return super().get_metadata(name) - except UnicodeDecodeError as e: - # Augment the default error with the origin of the file. - raise UnsupportedWheel( - f"Error decoding metadata for {self._wheel_name}: {e}" - ) - - -def pkg_resources_distribution_for_wheel(wheel_zip, name, location): - # type: (ZipFile, str, str) -> Distribution - """Get a pkg_resources distribution given a wheel. - - :raises UnsupportedWheel: on any errors - """ - info_dir, _ = parse_wheel(wheel_zip, name) - - metadata_files = [p for p in wheel_zip.namelist() if p.startswith(f"{info_dir}/")] - - metadata_text = {} # type: Dict[str, bytes] - for path in metadata_files: - _, metadata_name = path.split("/", 1) - - try: - metadata_text[metadata_name] = read_wheel_metadata_file(wheel_zip, path) - except UnsupportedWheel as e: - raise UnsupportedWheel("{} has an invalid wheel, {}".format(name, str(e))) - - metadata = WheelMetadata(metadata_text, location) - - return DistInfoDistribution(location=location, metadata=metadata, project_name=name) - - -def parse_wheel(wheel_zip, name): - # type: (ZipFile, str) -> Tuple[str, Message] - """Extract information from the provided wheel, ensuring it meets basic - standards. - - Returns the name of the .dist-info directory and the parsed WHEEL metadata. - """ - try: - info_dir = wheel_dist_info_dir(wheel_zip, name) - metadata = wheel_metadata(wheel_zip, info_dir) - version = wheel_version(metadata) - except UnsupportedWheel as e: - raise UnsupportedWheel("{} has an invalid wheel, {}".format(name, str(e))) - - check_compatibility(version, name) - - return info_dir, metadata - - -def wheel_dist_info_dir(source, name): - # type: (ZipFile, str) -> str - """Returns the name of the contained .dist-info directory. - - Raises AssertionError or UnsupportedWheel if not found, >1 found, or - it doesn't match the provided name. - """ - # Zip file path separators must be / - subdirs = {p.split("/", 1)[0] for p in source.namelist()} - - info_dirs = [s for s in subdirs if s.endswith(".dist-info")] - - if not info_dirs: - raise UnsupportedWheel(".dist-info directory not found") - - if len(info_dirs) > 1: - raise UnsupportedWheel( - "multiple .dist-info directories found: {}".format(", ".join(info_dirs)) - ) - - info_dir = info_dirs[0] - - info_dir_name = canonicalize_name(info_dir) - canonical_name = canonicalize_name(name) - if not info_dir_name.startswith(canonical_name): - raise UnsupportedWheel( - ".dist-info directory {!r} does not start with {!r}".format( - info_dir, canonical_name - ) - ) - - return info_dir - - -def read_wheel_metadata_file(source, path): - # type: (ZipFile, str) -> bytes - try: - return source.read(path) - # BadZipFile for general corruption, KeyError for missing entry, - # and RuntimeError for password-protected files - except (BadZipFile, KeyError, RuntimeError) as e: - raise UnsupportedWheel(f"could not read {path!r} file: {e!r}") - - -def wheel_metadata(source, dist_info_dir): - # type: (ZipFile, str) -> Message - """Return the WHEEL metadata of an extracted wheel, if possible. - Otherwise, raise UnsupportedWheel. - """ - path = f"{dist_info_dir}/WHEEL" - # Zip file path separators must be / - wheel_contents = read_wheel_metadata_file(source, path) - - try: - wheel_text = wheel_contents.decode() - except UnicodeDecodeError as e: - raise UnsupportedWheel(f"error decoding {path!r}: {e!r}") - - # FeedParser (used by Parser) does not raise any exceptions. The returned - # message may have .defects populated, but for backwards-compatibility we - # currently ignore them. - return Parser().parsestr(wheel_text) - - -def wheel_version(wheel_data): - # type: (Message) -> Tuple[int, ...] - """Given WHEEL metadata, return the parsed Wheel-Version. - Otherwise, raise UnsupportedWheel. - """ - version_text = wheel_data["Wheel-Version"] - if version_text is None: - raise UnsupportedWheel("WHEEL is missing Wheel-Version") - - version = version_text.strip() - - try: - return tuple(map(int, version.split("."))) - except ValueError: - raise UnsupportedWheel(f"invalid Wheel-Version: {version!r}") - - -def check_compatibility(version, name): - # type: (Tuple[int, ...], str) -> None - """Raises errors or warns if called with an incompatible Wheel-Version. - - pip should refuse to install a Wheel-Version that's a major series - ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when - installing a version only minor version ahead (e.g 1.2 > 1.1). - - version: a 2-tuple representing a Wheel-Version (Major, Minor) - name: name of wheel or package to raise exception about - - :raises UnsupportedWheel: when an incompatible Wheel-Version is given - """ - if version[0] > VERSION_COMPATIBLE[0]: - raise UnsupportedWheel( - "{}'s Wheel-Version ({}) is not compatible with this version " - "of pip".format(name, ".".join(map(str, version))) - ) - elif version > VERSION_COMPATIBLE: - logger.warning( - "Installing from a newer Wheel-Version (%s)", - ".".join(map(str, version)), - ) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/__init__.py deleted file mode 100644 index b6beddb..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Expose a limited set of classes and functions so callers outside of -# the vcs package don't need to import deeper than `pip._internal.vcs`. -# (The test directory may still need to import from a vcs sub-package.) -# Import all vcs modules to register each VCS in the VcsSupport object. -import pip._internal.vcs.bazaar -import pip._internal.vcs.git -import pip._internal.vcs.mercurial -import pip._internal.vcs.subversion # noqa: F401 -from pip._internal.vcs.versioncontrol import ( # noqa: F401 - RemoteNotFoundError, - RemoteNotValidError, - is_url, - make_vcs_requirement_url, - vcs, -) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/bazaar.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/bazaar.py deleted file mode 100644 index 42b6877..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/bazaar.py +++ /dev/null @@ -1,96 +0,0 @@ -import logging -from typing import List, Optional, Tuple - -from pip._internal.utils.misc import HiddenText, display_path -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs.versioncontrol import ( - AuthInfo, - RemoteNotFoundError, - RevOptions, - VersionControl, - vcs, -) - -logger = logging.getLogger(__name__) - - -class Bazaar(VersionControl): - name = 'bzr' - dirname = '.bzr' - repo_name = 'branch' - schemes = ( - 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', - 'bzr+lp', 'bzr+file' - ) - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - return ['-r', rev] - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Checking out %s%s to %s', - url, - rev_display, - display_path(dest), - ) - cmd_args = ( - make_command('branch', '-q', rev_options.to_args(), url, dest) - ) - self.run_command(cmd_args) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command(make_command('switch', url), cwd=dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command('pull', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it - url, rev, user_pass = super().get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'bzr+' + url - return url, rev, user_pass - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - urls = cls.run_command( - ['info'], show_stdout=False, stdout_only=True, cwd=location - ) - for line in urls.splitlines(): - line = line.strip() - for x in ('checkout of branch: ', - 'parent branch: '): - if line.startswith(x): - repo = line.split(x)[1] - if cls._is_local_repository(repo): - return path_to_url(repo) - return repo - raise RemoteNotFoundError - - @classmethod - def get_revision(cls, location): - # type: (str) -> str - revision = cls.run_command( - ['revno'], show_stdout=False, stdout_only=True, cwd=location, - ) - return revision.splitlines()[-1] - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """Always assume the versions don't match""" - return False - - -vcs.register(Bazaar) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/git.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/git.py deleted file mode 100644 index 8919aa5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/git.py +++ /dev/null @@ -1,506 +0,0 @@ -import logging -import os.path -import pathlib -import re -import urllib.parse -import urllib.request -from typing import List, Optional, Tuple - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.misc import HiddenText, display_path, hide_url -from pip._internal.utils.subprocess import make_command -from pip._internal.vcs.versioncontrol import ( - AuthInfo, - RemoteNotFoundError, - RemoteNotValidError, - RevOptions, - VersionControl, - find_path_to_project_root_from_repo_root, - vcs, -) - -urlsplit = urllib.parse.urlsplit -urlunsplit = urllib.parse.urlunsplit - - -logger = logging.getLogger(__name__) - - -GIT_VERSION_REGEX = re.compile( - r"^git version " # Prefix. - r"(\d+)" # Major. - r"\.(\d+)" # Dot, minor. - r"(?:\.(\d+))?" # Optional dot, patch. - r".*$" # Suffix, including any pre- and post-release segments we don't care about. -) - -HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$') - -# SCP (Secure copy protocol) shorthand. e.g. 'git@example.com:foo/bar.git' -SCP_REGEX = re.compile(r"""^ - # Optional user, e.g. 'git@' - (\w+@)? - # Server, e.g. 'github.com'. - ([^/:]+): - # The server-side path. e.g. 'user/project.git'. Must start with an - # alphanumeric character so as not to be confusable with a Windows paths - # like 'C:/foo/bar' or 'C:\foo\bar'. - (\w[^:]*) -$""", re.VERBOSE) - - -def looks_like_hash(sha): - # type: (str) -> bool - return bool(HASH_REGEX.match(sha)) - - -class Git(VersionControl): - name = 'git' - dirname = '.git' - repo_name = 'clone' - schemes = ( - 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', - ) - # Prevent the user's environment variables from interfering with pip: - # https://github.com/pypa/pip/issues/1130 - unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') - default_arg_rev = 'HEAD' - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - return [rev] - - def is_immutable_rev_checkout(self, url, dest): - # type: (str, str) -> bool - _, rev_options = self.get_url_rev_options(hide_url(url)) - if not rev_options.rev: - return False - if not self.is_commit_id_equal(dest, rev_options.rev): - # the current commit is different from rev, - # which means rev was something else than a commit hash - return False - # return False in the rare case rev is both a commit hash - # and a tag or a branch; we don't want to cache in that case - # because that branch/tag could point to something else in the future - is_tag_or_branch = bool( - self.get_revision_sha(dest, rev_options.rev)[0] - ) - return not is_tag_or_branch - - def get_git_version(self) -> Tuple[int, ...]: - version = self.run_command( - ['version'], show_stdout=False, stdout_only=True - ) - match = GIT_VERSION_REGEX.match(version) - if not match: - return () - return tuple(int(c) for c in match.groups()) - - @classmethod - def get_current_branch(cls, location): - # type: (str) -> Optional[str] - """ - Return the current branch, or None if HEAD isn't at a branch - (e.g. detached HEAD). - """ - # git-symbolic-ref exits with empty stdout if "HEAD" is a detached - # HEAD rather than a symbolic ref. In addition, the -q causes the - # command to exit with status code 1 instead of 128 in this case - # and to suppress the message to stderr. - args = ['symbolic-ref', '-q', 'HEAD'] - output = cls.run_command( - args, - extra_ok_returncodes=(1, ), - show_stdout=False, - stdout_only=True, - cwd=location, - ) - ref = output.strip() - - if ref.startswith('refs/heads/'): - return ref[len('refs/heads/'):] - - return None - - @classmethod - def get_revision_sha(cls, dest, rev): - # type: (str, str) -> Tuple[Optional[str], bool] - """ - Return (sha_or_none, is_branch), where sha_or_none is a commit hash - if the revision names a remote branch or tag, otherwise None. - - Args: - dest: the repository directory. - rev: the revision name. - """ - # Pass rev to pre-filter the list. - output = cls.run_command( - ['show-ref', rev], - cwd=dest, - show_stdout=False, - stdout_only=True, - on_returncode='ignore', - ) - refs = {} - # NOTE: We do not use splitlines here since that would split on other - # unicode separators, which can be maliciously used to install a - # different revision. - for line in output.strip().split("\n"): - line = line.rstrip("\r") - if not line: - continue - try: - ref_sha, ref_name = line.split(" ", maxsplit=2) - except ValueError: - # Include the offending line to simplify troubleshooting if - # this error ever occurs. - raise ValueError(f'unexpected show-ref line: {line!r}') - - refs[ref_name] = ref_sha - - branch_ref = f'refs/remotes/origin/{rev}' - tag_ref = f'refs/tags/{rev}' - - sha = refs.get(branch_ref) - if sha is not None: - return (sha, True) - - sha = refs.get(tag_ref) - - return (sha, False) - - @classmethod - def _should_fetch(cls, dest, rev): - # type: (str, str) -> bool - """ - Return true if rev is a ref or is a commit that we don't have locally. - - Branches and tags are not considered in this method because they are - assumed to be always available locally (which is a normal outcome of - ``git clone`` and ``git fetch --tags``). - """ - if rev.startswith("refs/"): - # Always fetch remote refs. - return True - - if not looks_like_hash(rev): - # Git fetch would fail with abbreviated commits. - return False - - if cls.has_commit(dest, rev): - # Don't fetch if we have the commit locally. - return False - - return True - - @classmethod - def resolve_revision(cls, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> RevOptions - """ - Resolve a revision to a new RevOptions object with the SHA1 of the - branch, tag, or ref if found. - - Args: - rev_options: a RevOptions object. - """ - rev = rev_options.arg_rev - # The arg_rev property's implementation for Git ensures that the - # rev return value is always non-None. - assert rev is not None - - sha, is_branch = cls.get_revision_sha(dest, rev) - - if sha is not None: - rev_options = rev_options.make_new(sha) - rev_options.branch_name = rev if is_branch else None - - return rev_options - - # Do not show a warning for the common case of something that has - # the form of a Git commit hash. - if not looks_like_hash(rev): - logger.warning( - "Did not find branch or tag '%s', assuming revision or ref.", - rev, - ) - - if not cls._should_fetch(dest, rev): - return rev_options - - # fetch the requested revision - cls.run_command( - make_command('fetch', '-q', url, rev_options.to_args()), - cwd=dest, - ) - # Change the revision to the SHA of the ref we fetched - sha = cls.get_revision(dest, rev='FETCH_HEAD') - rev_options = rev_options.make_new(sha) - - return rev_options - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """ - Return whether the current commit hash equals the given name. - - Args: - dest: the repository directory. - name: a string name. - """ - if not name: - # Then avoid an unnecessary subprocess call. - return False - - return cls.get_revision(dest) == name - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info('Cloning %s%s to %s', url, rev_display, display_path(dest)) - self.run_command(make_command('clone', '-q', url, dest)) - - if rev_options.rev: - # Then a specific revision was requested. - rev_options = self.resolve_revision(dest, url, rev_options) - branch_name = getattr(rev_options, 'branch_name', None) - if branch_name is None: - # Only do a checkout if the current commit id doesn't match - # the requested revision. - if not self.is_commit_id_equal(dest, rev_options.rev): - cmd_args = make_command( - 'checkout', '-q', rev_options.to_args(), - ) - self.run_command(cmd_args, cwd=dest) - elif self.get_current_branch(dest) != branch_name: - # Then a specific branch was requested, and that branch - # is not yet checked out. - track_branch = f'origin/{branch_name}' - cmd_args = [ - 'checkout', '-b', branch_name, '--track', track_branch, - ] - self.run_command(cmd_args, cwd=dest) - else: - sha = self.get_revision(dest) - rev_options = rev_options.make_new(sha) - - logger.info("Resolved %s to commit %s", url, rev_options.rev) - - #: repo may contain submodules - self.update_submodules(dest) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command( - make_command('config', 'remote.origin.url', url), - cwd=dest, - ) - cmd_args = make_command('checkout', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - self.update_submodules(dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - # First fetch changes from the default remote - if self.get_git_version() >= (1, 9): - # fetch tags in addition to everything else - self.run_command(['fetch', '-q', '--tags'], cwd=dest) - else: - self.run_command(['fetch', '-q'], cwd=dest) - # Then reset to wanted revision (maybe even origin/master) - rev_options = self.resolve_revision(dest, url, rev_options) - cmd_args = make_command('reset', '--hard', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - #: update submodules - self.update_submodules(dest) - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - """ - Return URL of the first remote encountered. - - Raises RemoteNotFoundError if the repository does not have a remote - url configured. - """ - # We need to pass 1 for extra_ok_returncodes since the command - # exits with return code 1 if there are no matching lines. - stdout = cls.run_command( - ['config', '--get-regexp', r'remote\..*\.url'], - extra_ok_returncodes=(1, ), - show_stdout=False, - stdout_only=True, - cwd=location, - ) - remotes = stdout.splitlines() - try: - found_remote = remotes[0] - except IndexError: - raise RemoteNotFoundError - - for remote in remotes: - if remote.startswith('remote.origin.url '): - found_remote = remote - break - url = found_remote.split(' ')[1] - return cls._git_remote_to_pip_url(url.strip()) - - @staticmethod - def _git_remote_to_pip_url(url): - # type: (str) -> str - """ - Convert a remote url from what git uses to what pip accepts. - - There are 3 legal forms **url** may take: - - 1. A fully qualified url: ssh://git@example.com/foo/bar.git - 2. A local project.git folder: /path/to/bare/repository.git - 3. SCP shorthand for form 1: git@example.com:foo/bar.git - - Form 1 is output as-is. Form 2 must be converted to URI and form 3 must - be converted to form 1. - - See the corresponding test test_git_remote_url_to_pip() for examples of - sample inputs/outputs. - """ - if re.match(r"\w+://", url): - # This is already valid. Pass it though as-is. - return url - if os.path.exists(url): - # A local bare remote (git clone --mirror). - # Needs a file:// prefix. - return pathlib.PurePath(url).as_uri() - scp_match = SCP_REGEX.match(url) - if scp_match: - # Add an ssh:// prefix and replace the ':' with a '/'. - return scp_match.expand(r"ssh://\1\2/\3") - # Otherwise, bail out. - raise RemoteNotValidError(url) - - @classmethod - def has_commit(cls, location, rev): - # type: (str, str) -> bool - """ - Check if rev is a commit that is available in the local repository. - """ - try: - cls.run_command( - ['rev-parse', '-q', '--verify', "sha^" + rev], - cwd=location, - log_failed_cmd=False, - ) - except InstallationError: - return False - else: - return True - - @classmethod - def get_revision(cls, location, rev=None): - # type: (str, Optional[str]) -> str - if rev is None: - rev = 'HEAD' - current_rev = cls.run_command( - ['rev-parse', rev], - show_stdout=False, - stdout_only=True, - cwd=location, - ) - return current_rev.strip() - - @classmethod - def get_subdirectory(cls, location): - # type: (str) -> Optional[str] - """ - Return the path to Python project root, relative to the repo root. - Return None if the project root is in the repo root. - """ - # find the repo root - git_dir = cls.run_command( - ['rev-parse', '--git-dir'], - show_stdout=False, - stdout_only=True, - cwd=location, - ).strip() - if not os.path.isabs(git_dir): - git_dir = os.path.join(location, git_dir) - repo_root = os.path.abspath(os.path.join(git_dir, '..')) - return find_path_to_project_root_from_repo_root(location, repo_root) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - """ - Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. - That's required because although they use SSH they sometimes don't - work with a ssh:// scheme (e.g. GitHub). But we need a scheme for - parsing. Hence we remove it again afterwards and return it as a stub. - """ - # Works around an apparent Git bug - # (see https://article.gmane.org/gmane.comp.version-control.git/146500) - scheme, netloc, path, query, fragment = urlsplit(url) - if scheme.endswith('file'): - initial_slashes = path[:-len(path.lstrip('/'))] - newpath = ( - initial_slashes + - urllib.request.url2pathname(path) - .replace('\\', '/').lstrip('/') - ) - after_plus = scheme.find('+') + 1 - url = scheme[:after_plus] + urlunsplit( - (scheme[after_plus:], netloc, newpath, query, fragment), - ) - - if '://' not in url: - assert 'file:' not in url - url = url.replace('git+', 'git+ssh://') - url, rev, user_pass = super().get_url_rev_and_auth(url) - url = url.replace('ssh://', '') - else: - url, rev, user_pass = super().get_url_rev_and_auth(url) - - return url, rev, user_pass - - @classmethod - def update_submodules(cls, location): - # type: (str) -> None - if not os.path.exists(os.path.join(location, '.gitmodules')): - return - cls.run_command( - ['submodule', 'update', '--init', '--recursive', '-q'], - cwd=location, - ) - - @classmethod - def get_repository_root(cls, location): - # type: (str) -> Optional[str] - loc = super().get_repository_root(location) - if loc: - return loc - try: - r = cls.run_command( - ['rev-parse', '--show-toplevel'], - cwd=location, - show_stdout=False, - stdout_only=True, - on_returncode='raise', - log_failed_cmd=False, - ) - except BadCommand: - logger.debug("could not determine if %s is under git control " - "because git is not available", location) - return None - except InstallationError: - return None - return os.path.normpath(r.rstrip('\r\n')) - - @staticmethod - def should_add_vcs_url_prefix(repo_url): - # type: (str) -> bool - """In either https or ssh form, requirements must be prefixed with git+. - """ - return True - - -vcs.register(Git) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/mercurial.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/mercurial.py deleted file mode 100644 index 8f8b09b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/mercurial.py +++ /dev/null @@ -1,158 +0,0 @@ -import configparser -import logging -import os -from typing import List, Optional - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.misc import HiddenText, display_path -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs.versioncontrol import ( - RevOptions, - VersionControl, - find_path_to_project_root_from_repo_root, - vcs, -) - -logger = logging.getLogger(__name__) - - -class Mercurial(VersionControl): - name = 'hg' - dirname = '.hg' - repo_name = 'clone' - schemes = ( - 'hg+file', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http', - ) - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - return [rev] - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Cloning hg %s%s to %s', - url, - rev_display, - display_path(dest), - ) - self.run_command(make_command('clone', '--noupdate', '-q', url, dest)) - self.run_command( - make_command('update', '-q', rev_options.to_args()), - cwd=dest, - ) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - repo_config = os.path.join(dest, self.dirname, 'hgrc') - config = configparser.RawConfigParser() - try: - config.read(repo_config) - config.set('paths', 'default', url.secret) - with open(repo_config, 'w') as config_file: - config.write(config_file) - except (OSError, configparser.NoSectionError) as exc: - logger.warning( - 'Could not switch Mercurial repository to %s: %s', url, exc, - ) - else: - cmd_args = make_command('update', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command(['pull', '-q'], cwd=dest) - cmd_args = make_command('update', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - url = cls.run_command( - ['showconfig', 'paths.default'], - show_stdout=False, - stdout_only=True, - cwd=location, - ).strip() - if cls._is_local_repository(url): - url = path_to_url(url) - return url.strip() - - @classmethod - def get_revision(cls, location): - # type: (str) -> str - """ - Return the repository-local changeset revision number, as an integer. - """ - current_revision = cls.run_command( - ['parents', '--template={rev}'], - show_stdout=False, - stdout_only=True, - cwd=location, - ).strip() - return current_revision - - @classmethod - def get_requirement_revision(cls, location): - # type: (str) -> str - """ - Return the changeset identification hash, as a 40-character - hexadecimal string - """ - current_rev_hash = cls.run_command( - ['parents', '--template={node}'], - show_stdout=False, - stdout_only=True, - cwd=location, - ).strip() - return current_rev_hash - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """Always assume the versions don't match""" - return False - - @classmethod - def get_subdirectory(cls, location): - # type: (str) -> Optional[str] - """ - Return the path to Python project root, relative to the repo root. - Return None if the project root is in the repo root. - """ - # find the repo root - repo_root = cls.run_command( - ['root'], show_stdout=False, stdout_only=True, cwd=location - ).strip() - if not os.path.isabs(repo_root): - repo_root = os.path.abspath(os.path.join(location, repo_root)) - return find_path_to_project_root_from_repo_root(location, repo_root) - - @classmethod - def get_repository_root(cls, location): - # type: (str) -> Optional[str] - loc = super().get_repository_root(location) - if loc: - return loc - try: - r = cls.run_command( - ['root'], - cwd=location, - show_stdout=False, - stdout_only=True, - on_returncode='raise', - log_failed_cmd=False, - ) - except BadCommand: - logger.debug("could not determine if %s is under hg control " - "because hg is not available", location) - return None - except InstallationError: - return None - return os.path.normpath(r.rstrip('\r\n')) - - -vcs.register(Mercurial) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/subversion.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/subversion.py deleted file mode 100644 index 965e0b4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/subversion.py +++ /dev/null @@ -1,329 +0,0 @@ -import logging -import os -import re -from typing import List, Optional, Tuple - -from pip._internal.utils.misc import ( - HiddenText, - display_path, - is_console_interactive, - is_installable_dir, - split_auth_from_netloc, -) -from pip._internal.utils.subprocess import CommandArgs, make_command -from pip._internal.vcs.versioncontrol import ( - AuthInfo, - RemoteNotFoundError, - RevOptions, - VersionControl, - vcs, -) - -logger = logging.getLogger(__name__) - -_svn_xml_url_re = re.compile('url="([^"]+)"') -_svn_rev_re = re.compile(r'committed-rev="(\d+)"') -_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') -_svn_info_xml_url_re = re.compile(r'(.*)') - - -class Subversion(VersionControl): - name = 'svn' - dirname = '.svn' - repo_name = 'checkout' - schemes = ( - 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn', 'svn+file' - ) - - @classmethod - def should_add_vcs_url_prefix(cls, remote_url): - # type: (str) -> bool - return True - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - return ['-r', rev] - - @classmethod - def get_revision(cls, location): - # type: (str) -> str - """ - Return the maximum revision for all files under a given location - """ - # Note: taken from setuptools.command.egg_info - revision = 0 - - for base, dirs, _ in os.walk(location): - if cls.dirname not in dirs: - dirs[:] = [] - continue # no sense walking uncontrolled subdirs - dirs.remove(cls.dirname) - entries_fn = os.path.join(base, cls.dirname, 'entries') - if not os.path.exists(entries_fn): - # FIXME: should we warn? - continue - - dirurl, localrev = cls._get_svn_url_rev(base) - - if base == location: - assert dirurl is not None - base = dirurl + '/' # save the root url - elif not dirurl or not dirurl.startswith(base): - dirs[:] = [] - continue # not part of the same svn tree, skip it - revision = max(revision, localrev) - return str(revision) - - @classmethod - def get_netloc_and_auth(cls, netloc, scheme): - # type: (str, str) -> Tuple[str, Tuple[Optional[str], Optional[str]]] - """ - This override allows the auth information to be passed to svn via the - --username and --password options instead of via the URL. - """ - if scheme == 'ssh': - # The --username and --password options can't be used for - # svn+ssh URLs, so keep the auth information in the URL. - return super().get_netloc_and_auth(netloc, scheme) - - return split_auth_from_netloc(netloc) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it - url, rev, user_pass = super().get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'svn+' + url - return url, rev, user_pass - - @staticmethod - def make_rev_args(username, password): - # type: (Optional[str], Optional[HiddenText]) -> CommandArgs - extra_args = [] # type: CommandArgs - if username: - extra_args += ['--username', username] - if password: - extra_args += ['--password', password] - - return extra_args - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - # In cases where the source is in a subdirectory, we have to look up in - # the location until we find a valid project root. - orig_location = location - while not is_installable_dir(location): - last_location = location - location = os.path.dirname(location) - if location == last_location: - # We've traversed up to the root of the filesystem without - # finding a Python project. - logger.warning( - "Could not find Python project for directory %s (tried all " - "parent directories)", - orig_location, - ) - raise RemoteNotFoundError - - url, _rev = cls._get_svn_url_rev(location) - if url is None: - raise RemoteNotFoundError - - return url - - @classmethod - def _get_svn_url_rev(cls, location): - # type: (str) -> Tuple[Optional[str], int] - from pip._internal.exceptions import InstallationError - - entries_path = os.path.join(location, cls.dirname, 'entries') - if os.path.exists(entries_path): - with open(entries_path) as f: - data = f.read() - else: # subversion >= 1.7 does not have the 'entries' file - data = '' - - url = None - if (data.startswith('8') or - data.startswith('9') or - data.startswith('10')): - entries = list(map(str.splitlines, data.split('\n\x0c\n'))) - del entries[0][0] # get rid of the '8' - url = entries[0][3] - revs = [int(d[9]) for d in entries if len(d) > 9 and d[9]] + [0] - elif data.startswith('= 1.7 - # Note that using get_remote_call_options is not necessary here - # because `svn info` is being run against a local directory. - # We don't need to worry about making sure interactive mode - # is being used to prompt for passwords, because passwords - # are only potentially needed for remote server requests. - xml = cls.run_command( - ['info', '--xml', location], - show_stdout=False, - stdout_only=True, - ) - match = _svn_info_xml_url_re.search(xml) - assert match is not None - url = match.group(1) - revs = [ - int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) - ] - except InstallationError: - url, revs = None, [] - - if revs: - rev = max(revs) - else: - rev = 0 - - return url, rev - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """Always assume the versions don't match""" - return False - - def __init__(self, use_interactive=None): - # type: (bool) -> None - if use_interactive is None: - use_interactive = is_console_interactive() - self.use_interactive = use_interactive - - # This member is used to cache the fetched version of the current - # ``svn`` client. - # Special value definitions: - # None: Not evaluated yet. - # Empty tuple: Could not parse version. - self._vcs_version = None # type: Optional[Tuple[int, ...]] - - super().__init__() - - def call_vcs_version(self): - # type: () -> Tuple[int, ...] - """Query the version of the currently installed Subversion client. - - :return: A tuple containing the parts of the version information or - ``()`` if the version returned from ``svn`` could not be parsed. - :raises: BadCommand: If ``svn`` is not installed. - """ - # Example versions: - # svn, version 1.10.3 (r1842928) - # compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0 - # svn, version 1.7.14 (r1542130) - # compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu - # svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0) - # compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2 - version_prefix = 'svn, version ' - version = self.run_command( - ['--version'], show_stdout=False, stdout_only=True - ) - if not version.startswith(version_prefix): - return () - - version = version[len(version_prefix):].split()[0] - version_list = version.partition('-')[0].split('.') - try: - parsed_version = tuple(map(int, version_list)) - except ValueError: - return () - - return parsed_version - - def get_vcs_version(self): - # type: () -> Tuple[int, ...] - """Return the version of the currently installed Subversion client. - - If the version of the Subversion client has already been queried, - a cached value will be used. - - :return: A tuple containing the parts of the version information or - ``()`` if the version returned from ``svn`` could not be parsed. - :raises: BadCommand: If ``svn`` is not installed. - """ - if self._vcs_version is not None: - # Use cached version, if available. - # If parsing the version failed previously (empty tuple), - # do not attempt to parse it again. - return self._vcs_version - - vcs_version = self.call_vcs_version() - self._vcs_version = vcs_version - return vcs_version - - def get_remote_call_options(self): - # type: () -> CommandArgs - """Return options to be used on calls to Subversion that contact the server. - - These options are applicable for the following ``svn`` subcommands used - in this class. - - - checkout - - switch - - update - - :return: A list of command line arguments to pass to ``svn``. - """ - if not self.use_interactive: - # --non-interactive switch is available since Subversion 0.14.4. - # Subversion < 1.8 runs in interactive mode by default. - return ['--non-interactive'] - - svn_version = self.get_vcs_version() - # By default, Subversion >= 1.8 runs in non-interactive mode if - # stdin is not a TTY. Since that is how pip invokes SVN, in - # call_subprocess(), pip must pass --force-interactive to ensure - # the user can be prompted for a password, if required. - # SVN added the --force-interactive option in SVN 1.8. Since - # e.g. RHEL/CentOS 7, which is supported until 2024, ships with - # SVN 1.7, pip should continue to support SVN 1.7. Therefore, pip - # can't safely add the option if the SVN version is < 1.8 (or unknown). - if svn_version >= (1, 8): - return ['--force-interactive'] - - return [] - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Checking out %s%s to %s', - url, - rev_display, - display_path(dest), - ) - cmd_args = make_command( - 'checkout', '-q', self.get_remote_call_options(), - rev_options.to_args(), url, dest, - ) - self.run_command(cmd_args) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command( - 'switch', self.get_remote_call_options(), rev_options.to_args(), - url, dest, - ) - self.run_command(cmd_args) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command( - 'update', self.get_remote_call_options(), rev_options.to_args(), - dest, - ) - self.run_command(cmd_args) - - -vcs.register(Subversion) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py deleted file mode 100644 index cddd78c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py +++ /dev/null @@ -1,722 +0,0 @@ -"""Handles all VCS (version control) support""" - -import logging -import os -import shutil -import sys -import urllib.parse -from typing import ( - Any, - Dict, - Iterable, - Iterator, - List, - Mapping, - Optional, - Tuple, - Type, - Union, -) - -from pip._internal.cli.spinners import SpinnerInterface -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.misc import ( - HiddenText, - ask_path_exists, - backup_dir, - display_path, - hide_url, - hide_value, - is_installable_dir, - rmtree, -) -from pip._internal.utils.subprocess import CommandArgs, call_subprocess, make_command -from pip._internal.utils.urls import get_url_scheme - -__all__ = ['vcs'] - - -logger = logging.getLogger(__name__) - -AuthInfo = Tuple[Optional[str], Optional[str]] - - -def is_url(name): - # type: (str) -> bool - """ - Return true if the name looks like a URL. - """ - scheme = get_url_scheme(name) - if scheme is None: - return False - return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes - - -def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None): - # type: (str, str, str, Optional[str]) -> str - """ - Return the URL for a VCS requirement. - - Args: - repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+"). - project_name: the (unescaped) project name. - """ - egg_project_name = project_name.replace("-", "_") - req = f'{repo_url}@{rev}#egg={egg_project_name}' - if subdir: - req += f'&subdirectory={subdir}' - - return req - - -def find_path_to_project_root_from_repo_root(location, repo_root): - # type: (str, str) -> Optional[str] - """ - Find the the Python project's root by searching up the filesystem from - `location`. Return the path to project root relative to `repo_root`. - Return None if the project root is `repo_root`, or cannot be found. - """ - # find project root. - orig_location = location - while not is_installable_dir(location): - last_location = location - location = os.path.dirname(location) - if location == last_location: - # We've traversed up to the root of the filesystem without - # finding a Python project. - logger.warning( - "Could not find a Python project for directory %s (tried all " - "parent directories)", - orig_location, - ) - return None - - if os.path.samefile(repo_root, location): - return None - - return os.path.relpath(location, repo_root) - - -class RemoteNotFoundError(Exception): - pass - - -class RemoteNotValidError(Exception): - def __init__(self, url: str): - super().__init__(url) - self.url = url - - -class RevOptions: - - """ - Encapsulates a VCS-specific revision to install, along with any VCS - install options. - - Instances of this class should be treated as if immutable. - """ - - def __init__( - self, - vc_class, # type: Type[VersionControl] - rev=None, # type: Optional[str] - extra_args=None, # type: Optional[CommandArgs] - ): - # type: (...) -> None - """ - Args: - vc_class: a VersionControl subclass. - rev: the name of the revision to install. - extra_args: a list of extra options. - """ - if extra_args is None: - extra_args = [] - - self.extra_args = extra_args - self.rev = rev - self.vc_class = vc_class - self.branch_name = None # type: Optional[str] - - def __repr__(self): - # type: () -> str - return f'' - - @property - def arg_rev(self): - # type: () -> Optional[str] - if self.rev is None: - return self.vc_class.default_arg_rev - - return self.rev - - def to_args(self): - # type: () -> CommandArgs - """ - Return the VCS-specific command arguments. - """ - args = [] # type: CommandArgs - rev = self.arg_rev - if rev is not None: - args += self.vc_class.get_base_rev_args(rev) - args += self.extra_args - - return args - - def to_display(self): - # type: () -> str - if not self.rev: - return '' - - return f' (to revision {self.rev})' - - def make_new(self, rev): - # type: (str) -> RevOptions - """ - Make a copy of the current instance, but with a new rev. - - Args: - rev: the name of the revision for the new object. - """ - return self.vc_class.make_rev_options(rev, extra_args=self.extra_args) - - -class VcsSupport: - _registry = {} # type: Dict[str, VersionControl] - schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] - - def __init__(self): - # type: () -> None - # Register more schemes with urlparse for various version control - # systems - urllib.parse.uses_netloc.extend(self.schemes) - super().__init__() - - def __iter__(self): - # type: () -> Iterator[str] - return self._registry.__iter__() - - @property - def backends(self): - # type: () -> List[VersionControl] - return list(self._registry.values()) - - @property - def dirnames(self): - # type: () -> List[str] - return [backend.dirname for backend in self.backends] - - @property - def all_schemes(self): - # type: () -> List[str] - schemes = [] # type: List[str] - for backend in self.backends: - schemes.extend(backend.schemes) - return schemes - - def register(self, cls): - # type: (Type[VersionControl]) -> None - if not hasattr(cls, 'name'): - logger.warning('Cannot register VCS %s', cls.__name__) - return - if cls.name not in self._registry: - self._registry[cls.name] = cls() - logger.debug('Registered VCS backend: %s', cls.name) - - def unregister(self, name): - # type: (str) -> None - if name in self._registry: - del self._registry[name] - - def get_backend_for_dir(self, location): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object if a repository of that type is found - at the given directory. - """ - vcs_backends = {} - for vcs_backend in self._registry.values(): - repo_path = vcs_backend.get_repository_root(location) - if not repo_path: - continue - logger.debug('Determine that %s uses VCS: %s', - location, vcs_backend.name) - vcs_backends[repo_path] = vcs_backend - - if not vcs_backends: - return None - - # Choose the VCS in the inner-most directory. Since all repository - # roots found here would be either `location` or one of its - # parents, the longest path should have the most path components, - # i.e. the backend representing the inner-most repository. - inner_most_repo_path = max(vcs_backends, key=len) - return vcs_backends[inner_most_repo_path] - - def get_backend_for_scheme(self, scheme): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object or None. - """ - for vcs_backend in self._registry.values(): - if scheme in vcs_backend.schemes: - return vcs_backend - return None - - def get_backend(self, name): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object or None. - """ - name = name.lower() - return self._registry.get(name) - - -vcs = VcsSupport() - - -class VersionControl: - name = '' - dirname = '' - repo_name = '' - # List of supported schemes for this Version Control - schemes = () # type: Tuple[str, ...] - # Iterable of environment variable names to pass to call_subprocess(). - unset_environ = () # type: Tuple[str, ...] - default_arg_rev = None # type: Optional[str] - - @classmethod - def should_add_vcs_url_prefix(cls, remote_url): - # type: (str) -> bool - """ - Return whether the vcs prefix (e.g. "git+") should be added to a - repository's remote url when used in a requirement. - """ - return not remote_url.lower().startswith(f'{cls.name}:') - - @classmethod - def get_subdirectory(cls, location): - # type: (str) -> Optional[str] - """ - Return the path to Python project root, relative to the repo root. - Return None if the project root is in the repo root. - """ - return None - - @classmethod - def get_requirement_revision(cls, repo_dir): - # type: (str) -> str - """ - Return the revision string that should be used in a requirement. - """ - return cls.get_revision(repo_dir) - - @classmethod - def get_src_requirement(cls, repo_dir, project_name): - # type: (str, str) -> str - """ - Return the requirement string to use to redownload the files - currently at the given repository directory. - - Args: - project_name: the (unescaped) project name. - - The return value has a form similar to the following: - - {repository_url}@{revision}#egg={project_name} - """ - repo_url = cls.get_remote_url(repo_dir) - - if cls.should_add_vcs_url_prefix(repo_url): - repo_url = f'{cls.name}+{repo_url}' - - revision = cls.get_requirement_revision(repo_dir) - subdir = cls.get_subdirectory(repo_dir) - req = make_vcs_requirement_url(repo_url, revision, project_name, - subdir=subdir) - - return req - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - """ - Return the base revision arguments for a vcs command. - - Args: - rev: the name of a revision to install. Cannot be None. - """ - raise NotImplementedError - - def is_immutable_rev_checkout(self, url, dest): - # type: (str, str) -> bool - """ - Return true if the commit hash checked out at dest matches - the revision in url. - - Always return False, if the VCS does not support immutable commit - hashes. - - This method does not check if there are local uncommitted changes - in dest after checkout, as pip currently has no use case for that. - """ - return False - - @classmethod - def make_rev_options(cls, rev=None, extra_args=None): - # type: (Optional[str], Optional[CommandArgs]) -> RevOptions - """ - Return a RevOptions object. - - Args: - rev: the name of a revision to install. - extra_args: a list of extra options. - """ - return RevOptions(cls, rev, extra_args=extra_args) - - @classmethod - def _is_local_repository(cls, repo): - # type: (str) -> bool - """ - posix absolute paths start with os.path.sep, - win32 ones start with drive (like c:\\folder) - """ - drive, tail = os.path.splitdrive(repo) - return repo.startswith(os.path.sep) or bool(drive) - - @classmethod - def get_netloc_and_auth(cls, netloc, scheme): - # type: (str, str) -> Tuple[str, Tuple[Optional[str], Optional[str]]] - """ - Parse the repository URL's netloc, and return the new netloc to use - along with auth information. - - Args: - netloc: the original repository URL netloc. - scheme: the repository URL's scheme without the vcs prefix. - - This is mainly for the Subversion class to override, so that auth - information can be provided via the --username and --password options - instead of through the URL. For other subclasses like Git without - such an option, auth information must stay in the URL. - - Returns: (netloc, (username, password)). - """ - return netloc, (None, None) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - """ - Parse the repository URL to use, and return the URL, revision, - and auth info to use. - - Returns: (url, rev, (username, password)). - """ - scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) - if '+' not in scheme: - raise ValueError( - "Sorry, {!r} is a malformed VCS url. " - "The format is +://, " - "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp".format(url) - ) - # Remove the vcs prefix. - scheme = scheme.split('+', 1)[1] - netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme) - rev = None - if '@' in path: - path, rev = path.rsplit('@', 1) - if not rev: - raise InstallationError( - "The URL {!r} has an empty revision (after @) " - "which is not supported. Include a revision after @ " - "or remove @ from the URL.".format(url) - ) - url = urllib.parse.urlunsplit((scheme, netloc, path, query, '')) - return url, rev, user_pass - - @staticmethod - def make_rev_args(username, password): - # type: (Optional[str], Optional[HiddenText]) -> CommandArgs - """ - Return the RevOptions "extra arguments" to use in obtain(). - """ - return [] - - def get_url_rev_options(self, url): - # type: (HiddenText) -> Tuple[HiddenText, RevOptions] - """ - Return the URL and RevOptions object to use in obtain(), - as a tuple (url, rev_options). - """ - secret_url, rev, user_pass = self.get_url_rev_and_auth(url.secret) - username, secret_password = user_pass - password = None # type: Optional[HiddenText] - if secret_password is not None: - password = hide_value(secret_password) - extra_args = self.make_rev_args(username, password) - rev_options = self.make_rev_options(rev, extra_args=extra_args) - - return hide_url(secret_url), rev_options - - @staticmethod - def normalize_url(url): - # type: (str) -> str - """ - Normalize a URL for comparison by unquoting it and removing any - trailing slash. - """ - return urllib.parse.unquote(url).rstrip('/') - - @classmethod - def compare_urls(cls, url1, url2): - # type: (str, str) -> bool - """ - Compare two repo URLs for identity, ignoring incidental differences. - """ - return (cls.normalize_url(url1) == cls.normalize_url(url2)) - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Fetch a revision from a repository, in the case that this is the - first fetch from the repository. - - Args: - dest: the directory to fetch the repository to. - rev_options: a RevOptions object. - """ - raise NotImplementedError - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Switch the repo at ``dest`` to point to ``URL``. - - Args: - rev_options: a RevOptions object. - """ - raise NotImplementedError - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Update an already-existing repo to the given ``rev_options``. - - Args: - rev_options: a RevOptions object. - """ - raise NotImplementedError - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """ - Return whether the id of the current commit equals the given name. - - Args: - dest: the repository directory. - name: a string name. - """ - raise NotImplementedError - - def obtain(self, dest, url): - # type: (str, HiddenText) -> None - """ - Install or update in editable mode the package represented by this - VersionControl object. - - :param dest: the repository directory in which to install or update. - :param url: the repository URL starting with a vcs prefix. - """ - url, rev_options = self.get_url_rev_options(url) - - if not os.path.exists(dest): - self.fetch_new(dest, url, rev_options) - return - - rev_display = rev_options.to_display() - if self.is_repository_directory(dest): - existing_url = self.get_remote_url(dest) - if self.compare_urls(existing_url, url.secret): - logger.debug( - '%s in %s exists, and has correct URL (%s)', - self.repo_name.title(), - display_path(dest), - url, - ) - if not self.is_commit_id_equal(dest, rev_options.rev): - logger.info( - 'Updating %s %s%s', - display_path(dest), - self.repo_name, - rev_display, - ) - self.update(dest, url, rev_options) - else: - logger.info('Skipping because already up-to-date.') - return - - logger.warning( - '%s %s in %s exists with URL %s', - self.name, - self.repo_name, - display_path(dest), - existing_url, - ) - prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', - ('s', 'i', 'w', 'b')) - else: - logger.warning( - 'Directory %s already exists, and is not a %s %s.', - dest, - self.name, - self.repo_name, - ) - # https://github.com/python/mypy/issues/1174 - prompt = ('(i)gnore, (w)ipe, (b)ackup ', # type: ignore - ('i', 'w', 'b')) - - logger.warning( - 'The plan is to install the %s repository %s', - self.name, - url, - ) - response = ask_path_exists('What to do? {}'.format( - prompt[0]), prompt[1]) - - if response == 'a': - sys.exit(-1) - - if response == 'w': - logger.warning('Deleting %s', display_path(dest)) - rmtree(dest) - self.fetch_new(dest, url, rev_options) - return - - if response == 'b': - dest_dir = backup_dir(dest) - logger.warning( - 'Backing up %s to %s', display_path(dest), dest_dir, - ) - shutil.move(dest, dest_dir) - self.fetch_new(dest, url, rev_options) - return - - # Do nothing if the response is "i". - if response == 's': - logger.info( - 'Switching %s %s to %s%s', - self.repo_name, - display_path(dest), - url, - rev_display, - ) - self.switch(dest, url, rev_options) - - def unpack(self, location, url): - # type: (str, HiddenText) -> None - """ - Clean up current location and download the url repository - (and vcs infos) into location - - :param url: the repository URL starting with a vcs prefix. - """ - if os.path.exists(location): - rmtree(location) - self.obtain(location, url=url) - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - """ - Return the url used at location - - Raises RemoteNotFoundError if the repository does not have a remote - url configured. - """ - raise NotImplementedError - - @classmethod - def get_revision(cls, location): - # type: (str) -> str - """ - Return the current commit id of the files at the given location. - """ - raise NotImplementedError - - @classmethod - def run_command( - cls, - cmd, # type: Union[List[str], CommandArgs] - show_stdout=True, # type: bool - cwd=None, # type: Optional[str] - on_returncode='raise', # type: str - extra_ok_returncodes=None, # type: Optional[Iterable[int]] - command_desc=None, # type: Optional[str] - extra_environ=None, # type: Optional[Mapping[str, Any]] - spinner=None, # type: Optional[SpinnerInterface] - log_failed_cmd=True, # type: bool - stdout_only=False, # type: bool - ): - # type: (...) -> str - """ - Run a VCS subcommand - This is simply a wrapper around call_subprocess that adds the VCS - command name, and checks that the VCS is available - """ - cmd = make_command(cls.name, *cmd) - try: - return call_subprocess(cmd, show_stdout, cwd, - on_returncode=on_returncode, - extra_ok_returncodes=extra_ok_returncodes, - command_desc=command_desc, - extra_environ=extra_environ, - unset_environ=cls.unset_environ, - spinner=spinner, - log_failed_cmd=log_failed_cmd, - stdout_only=stdout_only) - except FileNotFoundError: - # errno.ENOENT = no such file or directory - # In other words, the VCS executable isn't available - raise BadCommand( - f'Cannot find command {cls.name!r} - do you have ' - f'{cls.name!r} installed and in your PATH?') - except PermissionError: - # errno.EACCES = Permission denied - # This error occurs, for instance, when the command is installed - # only for another user. So, the current user don't have - # permission to call the other user command. - raise BadCommand( - f"No permission to execute {cls.name!r} - install it " - f"locally, globally (ask admin), or check your PATH. " - f"See possible solutions at " - f"https://pip.pypa.io/en/latest/reference/pip_freeze/" - f"#fixing-permission-denied." - ) - - @classmethod - def is_repository_directory(cls, path): - # type: (str) -> bool - """ - Return whether a directory path is a repository directory. - """ - logger.debug('Checking in %s for %s (%s)...', - path, cls.dirname, cls.name) - return os.path.exists(os.path.join(path, cls.dirname)) - - @classmethod - def get_repository_root(cls, location): - # type: (str) -> Optional[str] - """ - Return the "root" (top-level) directory controlled by the vcs, - or `None` if the directory is not in any. - - It is meant to be overridden to implement smarter detection - mechanisms for specific vcs. - - This can do more than is_repository_directory() alone. For - example, the Git override checks that Git is actually available. - """ - if cls.is_repository_directory(location): - return location - return None diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_internal/wheel_builder.py b/backend/venv39/lib/python3.9/site-packages/pip/_internal/wheel_builder.py deleted file mode 100644 index 92f172b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_internal/wheel_builder.py +++ /dev/null @@ -1,360 +0,0 @@ -"""Orchestrator for building wheels from InstallRequirements. -""" - -import logging -import os.path -import re -import shutil -from typing import Any, Callable, Iterable, List, Optional, Tuple - -from pip._vendor.packaging.utils import canonicalize_name, canonicalize_version -from pip._vendor.packaging.version import InvalidVersion, Version - -from pip._internal.cache import WheelCache -from pip._internal.exceptions import InvalidWheelFilename, UnsupportedWheel -from pip._internal.metadata import get_wheel_distribution -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.operations.build.wheel import build_wheel_pep517 -from pip._internal.operations.build.wheel_legacy import build_wheel_legacy -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ensure_dir, hash_file, is_wheel_installed -from pip._internal.utils.setuptools_build import make_setuptools_clean_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs import vcs - -logger = logging.getLogger(__name__) - -_egg_info_re = re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.IGNORECASE) - -BinaryAllowedPredicate = Callable[[InstallRequirement], bool] -BuildResult = Tuple[List[InstallRequirement], List[InstallRequirement]] - - -def _contains_egg_info(s): - # type: (str) -> bool - """Determine whether the string looks like an egg_info. - - :param s: The string to parse. E.g. foo-2.1 - """ - return bool(_egg_info_re.search(s)) - - -def _should_build( - req, # type: InstallRequirement - need_wheel, # type: bool - check_binary_allowed, # type: BinaryAllowedPredicate -): - # type: (...) -> bool - """Return whether an InstallRequirement should be built into a wheel.""" - if req.constraint: - # never build requirements that are merely constraints - return False - if req.is_wheel: - if need_wheel: - logger.info( - 'Skipping %s, due to already being wheel.', req.name, - ) - return False - - if need_wheel: - # i.e. pip wheel, not pip install - return True - - # From this point, this concerns the pip install command only - # (need_wheel=False). - - if req.editable or not req.source_dir: - return False - - if req.use_pep517: - return True - - if not check_binary_allowed(req): - logger.info( - "Skipping wheel build for %s, due to binaries " - "being disabled for it.", req.name, - ) - return False - - if not is_wheel_installed(): - # we don't build legacy requirements if wheel is not installed - logger.info( - "Using legacy 'setup.py install' for %s, " - "since package 'wheel' is not installed.", req.name, - ) - return False - - return True - - -def should_build_for_wheel_command( - req, # type: InstallRequirement -): - # type: (...) -> bool - return _should_build( - req, need_wheel=True, check_binary_allowed=_always_true - ) - - -def should_build_for_install_command( - req, # type: InstallRequirement - check_binary_allowed, # type: BinaryAllowedPredicate -): - # type: (...) -> bool - return _should_build( - req, need_wheel=False, check_binary_allowed=check_binary_allowed - ) - - -def _should_cache( - req, # type: InstallRequirement -): - # type: (...) -> Optional[bool] - """ - Return whether a built InstallRequirement can be stored in the persistent - wheel cache, assuming the wheel cache is available, and _should_build() - has determined a wheel needs to be built. - """ - if req.editable or not req.source_dir: - # never cache editable requirements - return False - - if req.link and req.link.is_vcs: - # VCS checkout. Do not cache - # unless it points to an immutable commit hash. - assert not req.editable - assert req.source_dir - vcs_backend = vcs.get_backend_for_scheme(req.link.scheme) - assert vcs_backend - if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir): - return True - return False - - assert req.link - base, ext = req.link.splitext() - if _contains_egg_info(base): - return True - - # Otherwise, do not cache. - return False - - -def _get_cache_dir( - req, # type: InstallRequirement - wheel_cache, # type: WheelCache -): - # type: (...) -> str - """Return the persistent or temporary cache directory where the built - wheel need to be stored. - """ - cache_available = bool(wheel_cache.cache_dir) - assert req.link - if cache_available and _should_cache(req): - cache_dir = wheel_cache.get_path_for_link(req.link) - else: - cache_dir = wheel_cache.get_ephem_path_for_link(req.link) - return cache_dir - - -def _always_true(_): - # type: (Any) -> bool - return True - - -def _verify_one(req, wheel_path): - # type: (InstallRequirement, str) -> None - canonical_name = canonicalize_name(req.name or "") - w = Wheel(os.path.basename(wheel_path)) - if canonicalize_name(w.name) != canonical_name: - raise InvalidWheelFilename( - "Wheel has unexpected file name: expected {!r}, " - "got {!r}".format(canonical_name, w.name), - ) - dist = get_wheel_distribution(wheel_path, canonical_name) - dist_verstr = str(dist.version) - if canonicalize_version(dist_verstr) != canonicalize_version(w.version): - raise InvalidWheelFilename( - "Wheel has unexpected file name: expected {!r}, " - "got {!r}".format(dist_verstr, w.version), - ) - metadata_version_value = dist.metadata_version - if metadata_version_value is None: - raise UnsupportedWheel("Missing Metadata-Version") - try: - metadata_version = Version(metadata_version_value) - except InvalidVersion: - msg = f"Invalid Metadata-Version: {metadata_version_value}" - raise UnsupportedWheel(msg) - if (metadata_version >= Version("1.2") - and not isinstance(dist.version, Version)): - raise UnsupportedWheel( - "Metadata 1.2 mandates PEP 440 version, " - "but {!r} is not".format(dist_verstr) - ) - - -def _build_one( - req, # type: InstallRequirement - output_dir, # type: str - verify, # type: bool - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> Optional[str] - """Build one wheel. - - :return: The filename of the built wheel, or None if the build failed. - """ - try: - ensure_dir(output_dir) - except OSError as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - return None - - # Install build deps into temporary directory (PEP 518) - with req.build_env: - wheel_path = _build_one_inside_env( - req, output_dir, build_options, global_options - ) - if wheel_path and verify: - try: - _verify_one(req, wheel_path) - except (InvalidWheelFilename, UnsupportedWheel) as e: - logger.warning("Built wheel for %s is invalid: %s", req.name, e) - return None - return wheel_path - - -def _build_one_inside_env( - req, # type: InstallRequirement - output_dir, # type: str - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> Optional[str] - with TempDirectory(kind="wheel") as temp_dir: - assert req.name - if req.use_pep517: - assert req.metadata_directory - assert req.pep517_backend - if global_options: - logger.warning( - 'Ignoring --global-option when building %s using PEP 517', req.name - ) - if build_options: - logger.warning( - 'Ignoring --build-option when building %s using PEP 517', req.name - ) - wheel_path = build_wheel_pep517( - name=req.name, - backend=req.pep517_backend, - metadata_directory=req.metadata_directory, - tempd=temp_dir.path, - ) - else: - wheel_path = build_wheel_legacy( - name=req.name, - setup_py_path=req.setup_py_path, - source_dir=req.unpacked_source_directory, - global_options=global_options, - build_options=build_options, - tempd=temp_dir.path, - ) - - if wheel_path is not None: - wheel_name = os.path.basename(wheel_path) - dest_path = os.path.join(output_dir, wheel_name) - try: - wheel_hash, length = hash_file(wheel_path) - shutil.move(wheel_path, dest_path) - logger.info('Created wheel for %s: ' - 'filename=%s size=%d sha256=%s', - req.name, wheel_name, length, - wheel_hash.hexdigest()) - logger.info('Stored in directory: %s', output_dir) - return dest_path - except Exception as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - # Ignore return, we can't do anything else useful. - if not req.use_pep517: - _clean_one_legacy(req, global_options) - return None - - -def _clean_one_legacy(req, global_options): - # type: (InstallRequirement, List[str]) -> bool - clean_args = make_setuptools_clean_args( - req.setup_py_path, - global_options=global_options, - ) - - logger.info('Running setup.py clean for %s', req.name) - try: - call_subprocess(clean_args, cwd=req.source_dir) - return True - except Exception: - logger.error('Failed cleaning build dir for %s', req.name) - return False - - -def build( - requirements, # type: Iterable[InstallRequirement] - wheel_cache, # type: WheelCache - verify, # type: bool - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> BuildResult - """Build wheels. - - :return: The list of InstallRequirement that succeeded to build and - the list of InstallRequirement that failed to build. - """ - if not requirements: - return [], [] - - # Build the wheels. - logger.info( - 'Building wheels for collected packages: %s', - ', '.join(req.name for req in requirements), # type: ignore - ) - - with indent_log(): - build_successes, build_failures = [], [] - for req in requirements: - cache_dir = _get_cache_dir(req, wheel_cache) - wheel_file = _build_one( - req, cache_dir, verify, build_options, global_options - ) - if wheel_file: - # Update the link for this. - req.link = Link(path_to_url(wheel_file)) - req.local_file_path = req.link.file_path - assert req.link.is_wheel - build_successes.append(req) - else: - build_failures.append(req) - - # notify success/failure - if build_successes: - logger.info( - 'Successfully built %s', - ' '.join([req.name for req in build_successes]), # type: ignore - ) - if build_failures: - logger.info( - 'Failed to build %s', - ' '.join([req.name for req in build_failures]), # type: ignore - ) - # Return a list of requirements that failed to build - return build_successes, build_failures diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/__init__.py deleted file mode 100644 index 57e32da..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -pip._vendor is for vendoring dependencies of pip to prevent needing pip to -depend on something external. - -Files inside of pip._vendor should be considered immutable and should only be -updated to versions from upstream. -""" -from __future__ import absolute_import - -import glob -import os.path -import sys - -# Downstream redistributors which have debundled our dependencies should also -# patch this value to be true. This will trigger the additional patching -# to cause things like "six" to be available as pip. -DEBUNDLED = False - -# By default, look in this directory for a bunch of .whl files which we will -# add to the beginning of sys.path before attempting to import anything. This -# is done to support downstream re-distributors like Debian and Fedora who -# wish to create their own Wheels for our dependencies to aid in debundling. -WHEEL_DIR = os.path.abspath(os.path.dirname(__file__)) - - -# Define a small helper function to alias our vendored modules to the real ones -# if the vendored ones do not exist. This idea of this was taken from -# https://github.com/kennethreitz/requests/pull/2567. -def vendored(modulename): - vendored_name = "{0}.{1}".format(__name__, modulename) - - try: - __import__(modulename, globals(), locals(), level=0) - except ImportError: - # We can just silently allow import failures to pass here. If we - # got to this point it means that ``import pip._vendor.whatever`` - # failed and so did ``import whatever``. Since we're importing this - # upfront in an attempt to alias imports, not erroring here will - # just mean we get a regular import error whenever pip *actually* - # tries to import one of these modules to use it, which actually - # gives us a better error message than we would have otherwise - # gotten. - pass - else: - sys.modules[vendored_name] = sys.modules[modulename] - base, head = vendored_name.rsplit(".", 1) - setattr(sys.modules[base], head, sys.modules[modulename]) - - -# If we're operating in a debundled setup, then we want to go ahead and trigger -# the aliasing of our vendored libraries as well as looking for wheels to add -# to our sys.path. This will cause all of this code to be a no-op typically -# however downstream redistributors can enable it in a consistent way across -# all platforms. -if DEBUNDLED: - # Actually look inside of WHEEL_DIR to find .whl files and add them to the - # front of our sys.path. - sys.path[:] = glob.glob(os.path.join(WHEEL_DIR, "*.whl")) + sys.path - - # Actually alias all of our vendored dependencies. - vendored("appdirs") - vendored("cachecontrol") - vendored("certifi") - vendored("colorama") - vendored("distlib") - vendored("distro") - vendored("html5lib") - vendored("six") - vendored("six.moves") - vendored("six.moves.urllib") - vendored("six.moves.urllib.parse") - vendored("packaging") - vendored("packaging.version") - vendored("packaging.specifiers") - vendored("pep517") - vendored("pkg_resources") - vendored("progress") - vendored("requests") - vendored("requests.exceptions") - vendored("requests.packages") - vendored("requests.packages.urllib3") - vendored("requests.packages.urllib3._collections") - vendored("requests.packages.urllib3.connection") - vendored("requests.packages.urllib3.connectionpool") - vendored("requests.packages.urllib3.contrib") - vendored("requests.packages.urllib3.contrib.ntlmpool") - vendored("requests.packages.urllib3.contrib.pyopenssl") - vendored("requests.packages.urllib3.exceptions") - vendored("requests.packages.urllib3.fields") - vendored("requests.packages.urllib3.filepost") - vendored("requests.packages.urllib3.packages") - vendored("requests.packages.urllib3.packages.ordered_dict") - vendored("requests.packages.urllib3.packages.six") - vendored("requests.packages.urllib3.packages.ssl_match_hostname") - vendored("requests.packages.urllib3.packages.ssl_match_hostname." - "_implementation") - vendored("requests.packages.urllib3.poolmanager") - vendored("requests.packages.urllib3.request") - vendored("requests.packages.urllib3.response") - vendored("requests.packages.urllib3.util") - vendored("requests.packages.urllib3.util.connection") - vendored("requests.packages.urllib3.util.request") - vendored("requests.packages.urllib3.util.response") - vendored("requests.packages.urllib3.util.retry") - vendored("requests.packages.urllib3.util.ssl_") - vendored("requests.packages.urllib3.util.timeout") - vendored("requests.packages.urllib3.util.url") - vendored("resolvelib") - vendored("tenacity") - vendored("tomli") - vendored("urllib3") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/appdirs.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/appdirs.py deleted file mode 100644 index 33a3b77..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/appdirs.py +++ /dev/null @@ -1,633 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (c) 2005-2010 ActiveState Software Inc. -# Copyright (c) 2013 Eddy Petrișor - -"""Utilities for determining application-specific dirs. - -See for details and usage. -""" -# Dev Notes: -# - MSDN on where to store app data files: -# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 -# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html -# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - -__version__ = "1.4.4" -__version_info__ = tuple(int(segment) for segment in __version__.split(".")) - - -import sys -import os - -PY3 = sys.version_info[0] == 3 - -if PY3: - unicode = str - -if sys.platform.startswith('java'): - import platform - os_name = platform.java_ver()[3][0] - if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. - system = 'win32' - elif os_name.startswith('Mac'): # "Mac OS X", etc. - system = 'darwin' - else: # "Linux", "SunOS", "FreeBSD", etc. - # Setting this to "linux2" is not ideal, but only Windows or Mac - # are actually checked for and the rest of the module expects - # *sys.platform* style strings. - system = 'linux2' -elif sys.platform == 'cli' and os.name == 'nt': - # Detect Windows in IronPython to match pip._internal.utils.compat.WINDOWS - # Discussion: - system = 'win32' -else: - system = sys.platform - - - -def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - - for a discussion of issues. - - Typical user data directories are: - Mac OS X: ~/Library/Application Support/ # or ~/.config/, if the other does not exist - Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined - Win XP (not roaming): C:\Documents and Settings\\Application Data\\ - Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ - Win 7 (not roaming): C:\Users\\AppData\Local\\ - Win 7 (roaming): C:\Users\\AppData\Roaming\\ - - For Unix, we follow the XDG spec and support $XDG_DATA_HOME. - That means, by default "~/.local/share/". - """ - if system == "win32": - if appauthor is None: - appauthor = appname - const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" - path = os.path.normpath(_get_win_folder(const)) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - elif system == 'darwin': - path = os.path.expanduser('~/Library/Application Support/') - if appname: - path = os.path.join(path, appname) - else: - path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): - r"""Return full path to the user-shared data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "multipath" is an optional parameter only applicable to *nix - which indicates that the entire list of data dirs should be - returned. By default, the first item from XDG_DATA_DIRS is - returned, or '/usr/local/share/', - if XDG_DATA_DIRS is not set - - Typical site data directories are: - Mac OS X: /Library/Application Support/ - Unix: /usr/local/share/ or /usr/share/ - Win XP: C:\Documents and Settings\All Users\Application Data\\ - Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) - Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7. - - For Unix, this is using the $XDG_DATA_DIRS[0] default. - - WARNING: Do not use this on Windows. See the Vista-Fail note above for why. - """ - if system == "win32": - if appauthor is None: - appauthor = appname - path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - elif system == 'darwin': - path = os.path.expanduser('/Library/Application Support') - if appname: - path = os.path.join(path, appname) - else: - # XDG default for $XDG_DATA_DIRS - # only first, if multipath is False - path = os.getenv('XDG_DATA_DIRS', - os.pathsep.join(['/usr/local/share', '/usr/share'])) - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] - if appname: - if version: - appname = os.path.join(appname, version) - pathlist = [os.path.join(x, appname) for x in pathlist] - - if multipath: - path = os.pathsep.join(pathlist) - else: - path = pathlist[0] - return path - - if appname and version: - path = os.path.join(path, version) - return path - - -def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific config dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - - for a discussion of issues. - - Typical user config directories are: - Mac OS X: same as user_data_dir - Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined - Win *: same as user_data_dir - - For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. - That means, by default "~/.config/". - """ - if system in ["win32", "darwin"]: - path = user_data_dir(appname, appauthor, None, roaming) - else: - path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -# for the discussion regarding site_config_dir locations -# see -def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): - r"""Return full path to the user-shared data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "multipath" is an optional parameter only applicable to *nix - which indicates that the entire list of config dirs should be - returned. By default, the first item from XDG_CONFIG_DIRS is - returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set - - Typical site config directories are: - Mac OS X: same as site_data_dir - Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in - $XDG_CONFIG_DIRS - Win *: same as site_data_dir - Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) - - For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False - - WARNING: Do not use this on Windows. See the Vista-Fail note above for why. - """ - if system in ["win32", "darwin"]: - path = site_data_dir(appname, appauthor) - if appname and version: - path = os.path.join(path, version) - else: - # XDG default for $XDG_CONFIG_DIRS (missing or empty) - # see - # only first, if multipath is False - path = os.getenv('XDG_CONFIG_DIRS') or '/etc/xdg' - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) if x] - if appname: - if version: - appname = os.path.join(appname, version) - pathlist = [os.path.join(x, appname) for x in pathlist] - - if multipath: - path = os.pathsep.join(pathlist) - else: - path = pathlist[0] - return path - - -def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): - r"""Return full path to the user-specific cache dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "opinion" (boolean) can be False to disable the appending of - "Cache" to the base app data dir for Windows. See - discussion below. - - Typical user cache directories are: - Mac OS X: ~/Library/Caches/ - Unix: ~/.cache/ (XDG default) - Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache - Vista: C:\Users\\AppData\Local\\\Cache - - On Windows the only suggestion in the MSDN docs is that local settings go in - the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming - app data dir (the default returned by `user_data_dir` above). Apps typically - put cache data somewhere *under* the given dir here. Some examples: - ...\Mozilla\Firefox\Profiles\\Cache - ...\Acme\SuperApp\Cache\1.0 - OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. - This can be disabled with the `opinion=False` option. - """ - if system == "win32": - if appauthor is None: - appauthor = appname - path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) - # When using Python 2, return paths as bytes on Windows like we do on - # other operating systems. See helper function docs for more details. - if not PY3 and isinstance(path, unicode): - path = _win_path_to_bytes(path) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - if opinion: - path = os.path.join(path, "Cache") - elif system == 'darwin': - path = os.path.expanduser('~/Library/Caches') - if appname: - path = os.path.join(path, appname) - else: - path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific state dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - - for a discussion of issues. - - Typical user state directories are: - Mac OS X: same as user_data_dir - Unix: ~/.local/state/ # or in $XDG_STATE_HOME, if defined - Win *: same as user_data_dir - - For Unix, we follow this Debian proposal - to extend the XDG spec and support $XDG_STATE_HOME. - - That means, by default "~/.local/state/". - """ - if system in ["win32", "darwin"]: - path = user_data_dir(appname, appauthor, None, roaming) - else: - path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): - r"""Return full path to the user-specific log dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be ".". - Only applied when appname is present. - "opinion" (boolean) can be False to disable the appending of - "Logs" to the base app data dir for Windows, and "log" to the - base cache dir for Unix. See discussion below. - - Typical user log directories are: - Mac OS X: ~/Library/Logs/ - Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined - Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs - Vista: C:\Users\\AppData\Local\\\Logs - - On Windows the only suggestion in the MSDN docs is that local settings - go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in - examples of what some windows apps use for a logs dir.) - - OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` - value for Windows and appends "log" to the user cache dir for Unix. - This can be disabled with the `opinion=False` option. - """ - if system == "darwin": - path = os.path.join( - os.path.expanduser('~/Library/Logs'), - appname) - elif system == "win32": - path = user_data_dir(appname, appauthor, version) - version = False - if opinion: - path = os.path.join(path, "Logs") - else: - path = user_cache_dir(appname, appauthor, version) - version = False - if opinion: - path = os.path.join(path, "log") - if appname and version: - path = os.path.join(path, version) - return path - - -class AppDirs(object): - """Convenience wrapper for getting application dirs.""" - def __init__(self, appname=None, appauthor=None, version=None, - roaming=False, multipath=False): - self.appname = appname - self.appauthor = appauthor - self.version = version - self.roaming = roaming - self.multipath = multipath - - @property - def user_data_dir(self): - return user_data_dir(self.appname, self.appauthor, - version=self.version, roaming=self.roaming) - - @property - def site_data_dir(self): - return site_data_dir(self.appname, self.appauthor, - version=self.version, multipath=self.multipath) - - @property - def user_config_dir(self): - return user_config_dir(self.appname, self.appauthor, - version=self.version, roaming=self.roaming) - - @property - def site_config_dir(self): - return site_config_dir(self.appname, self.appauthor, - version=self.version, multipath=self.multipath) - - @property - def user_cache_dir(self): - return user_cache_dir(self.appname, self.appauthor, - version=self.version) - - @property - def user_state_dir(self): - return user_state_dir(self.appname, self.appauthor, - version=self.version) - - @property - def user_log_dir(self): - return user_log_dir(self.appname, self.appauthor, - version=self.version) - - -#---- internal support stuff - -def _get_win_folder_from_registry(csidl_name): - """This is a fallback technique at best. I'm not sure if using the - registry for this guarantees us the correct answer for all CSIDL_* - names. - """ - if PY3: - import winreg as _winreg - else: - import _winreg - - shell_folder_name = { - "CSIDL_APPDATA": "AppData", - "CSIDL_COMMON_APPDATA": "Common AppData", - "CSIDL_LOCAL_APPDATA": "Local AppData", - }[csidl_name] - - key = _winreg.OpenKey( - _winreg.HKEY_CURRENT_USER, - r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" - ) - dir, type = _winreg.QueryValueEx(key, shell_folder_name) - return dir - - -def _get_win_folder_with_pywin32(csidl_name): - from win32com.shell import shellcon, shell - dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) - # Try to make this a unicode path because SHGetFolderPath does - # not return unicode strings when there is unicode data in the - # path. - try: - dir = unicode(dir) - - # Downgrade to short path name if have highbit chars. See - # . - has_high_char = False - for c in dir: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - try: - import win32api - dir = win32api.GetShortPathName(dir) - except ImportError: - pass - except UnicodeError: - pass - return dir - - -def _get_win_folder_with_ctypes(csidl_name): - import ctypes - - csidl_const = { - "CSIDL_APPDATA": 26, - "CSIDL_COMMON_APPDATA": 35, - "CSIDL_LOCAL_APPDATA": 28, - }[csidl_name] - - buf = ctypes.create_unicode_buffer(1024) - ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) - - # Downgrade to short path name if have highbit chars. See - # . - has_high_char = False - for c in buf: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - buf2 = ctypes.create_unicode_buffer(1024) - if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): - buf = buf2 - - return buf.value - -def _get_win_folder_with_jna(csidl_name): - import array - from com.sun import jna - from com.sun.jna.platform import win32 - - buf_size = win32.WinDef.MAX_PATH * 2 - buf = array.zeros('c', buf_size) - shell = win32.Shell32.INSTANCE - shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) - dir = jna.Native.toString(buf.tostring()).rstrip("\0") - - # Downgrade to short path name if have highbit chars. See - # . - has_high_char = False - for c in dir: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - buf = array.zeros('c', buf_size) - kernel = win32.Kernel32.INSTANCE - if kernel.GetShortPathName(dir, buf, buf_size): - dir = jna.Native.toString(buf.tostring()).rstrip("\0") - - return dir - -if system == "win32": - try: - from ctypes import windll - _get_win_folder = _get_win_folder_with_ctypes - except ImportError: - try: - import com.sun.jna - _get_win_folder = _get_win_folder_with_jna - except ImportError: - _get_win_folder = _get_win_folder_from_registry - - -def _win_path_to_bytes(path): - """Encode Windows paths to bytes. Only used on Python 2. - - Motivation is to be consistent with other operating systems where paths - are also returned as bytes. This avoids problems mixing bytes and Unicode - elsewhere in the codebase. For more details and discussion see - . - - If encoding using ASCII and MBCS fails, return the original Unicode path. - """ - for encoding in ('ASCII', 'MBCS'): - try: - return path.encode(encoding) - except (UnicodeEncodeError, LookupError): - pass - return path - - -#---- self test code - -if __name__ == "__main__": - appname = "MyApp" - appauthor = "MyCompany" - - props = ("user_data_dir", - "user_config_dir", - "user_cache_dir", - "user_state_dir", - "user_log_dir", - "site_data_dir", - "site_config_dir") - - print("-- app dirs %s --" % __version__) - - print("-- app dirs (with optional 'version')") - dirs = AppDirs(appname, appauthor, version="1.0") - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (without optional 'version')") - dirs = AppDirs(appname, appauthor) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (without optional 'appauthor')") - dirs = AppDirs(appname) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (with disabled 'appauthor')") - dirs = AppDirs(appname, appauthor=False) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/__init__.py deleted file mode 100644 index a1bbbbe..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""CacheControl import Interface. - -Make it easy to import from cachecontrol without long namespaces. -""" -__author__ = "Eric Larson" -__email__ = "eric@ionrock.org" -__version__ = "0.12.6" - -from .wrapper import CacheControl -from .adapter import CacheControlAdapter -from .controller import CacheController diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/_cmd.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/_cmd.py deleted file mode 100644 index f1e0ad9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/_cmd.py +++ /dev/null @@ -1,57 +0,0 @@ -import logging - -from pip._vendor import requests - -from pip._vendor.cachecontrol.adapter import CacheControlAdapter -from pip._vendor.cachecontrol.cache import DictCache -from pip._vendor.cachecontrol.controller import logger - -from argparse import ArgumentParser - - -def setup_logging(): - logger.setLevel(logging.DEBUG) - handler = logging.StreamHandler() - logger.addHandler(handler) - - -def get_session(): - adapter = CacheControlAdapter( - DictCache(), cache_etags=True, serializer=None, heuristic=None - ) - sess = requests.Session() - sess.mount("http://", adapter) - sess.mount("https://", adapter) - - sess.cache_controller = adapter.controller - return sess - - -def get_args(): - parser = ArgumentParser() - parser.add_argument("url", help="The URL to try and cache") - return parser.parse_args() - - -def main(args=None): - args = get_args() - sess = get_session() - - # Make a request to get a response - resp = sess.get(args.url) - - # Turn on logging - setup_logging() - - # try setting the cache - sess.cache_controller.cache_response(resp.request, resp.raw) - - # Now try to get it - if sess.cache_controller.cached_request(resp.request): - print("Cached!") - else: - print("Not cached :(") - - -if __name__ == "__main__": - main() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/adapter.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/adapter.py deleted file mode 100644 index 815650e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/adapter.py +++ /dev/null @@ -1,133 +0,0 @@ -import types -import functools -import zlib - -from pip._vendor.requests.adapters import HTTPAdapter - -from .controller import CacheController -from .cache import DictCache -from .filewrapper import CallbackFileWrapper - - -class CacheControlAdapter(HTTPAdapter): - invalidating_methods = {"PUT", "DELETE"} - - def __init__( - self, - cache=None, - cache_etags=True, - controller_class=None, - serializer=None, - heuristic=None, - cacheable_methods=None, - *args, - **kw - ): - super(CacheControlAdapter, self).__init__(*args, **kw) - self.cache = DictCache() if cache is None else cache - self.heuristic = heuristic - self.cacheable_methods = cacheable_methods or ("GET",) - - controller_factory = controller_class or CacheController - self.controller = controller_factory( - self.cache, cache_etags=cache_etags, serializer=serializer - ) - - def send(self, request, cacheable_methods=None, **kw): - """ - Send a request. Use the request information to see if it - exists in the cache and cache the response if we need to and can. - """ - cacheable = cacheable_methods or self.cacheable_methods - if request.method in cacheable: - try: - cached_response = self.controller.cached_request(request) - except zlib.error: - cached_response = None - if cached_response: - return self.build_response(request, cached_response, from_cache=True) - - # check for etags and add headers if appropriate - request.headers.update(self.controller.conditional_headers(request)) - - resp = super(CacheControlAdapter, self).send(request, **kw) - - return resp - - def build_response( - self, request, response, from_cache=False, cacheable_methods=None - ): - """ - Build a response by making a request or using the cache. - - This will end up calling send and returning a potentially - cached response - """ - cacheable = cacheable_methods or self.cacheable_methods - if not from_cache and request.method in cacheable: - # Check for any heuristics that might update headers - # before trying to cache. - if self.heuristic: - response = self.heuristic.apply(response) - - # apply any expiration heuristics - if response.status == 304: - # We must have sent an ETag request. This could mean - # that we've been expired already or that we simply - # have an etag. In either case, we want to try and - # update the cache if that is the case. - cached_response = self.controller.update_cached_response( - request, response - ) - - if cached_response is not response: - from_cache = True - - # We are done with the server response, read a - # possible response body (compliant servers will - # not return one, but we cannot be 100% sure) and - # release the connection back to the pool. - response.read(decode_content=False) - response.release_conn() - - response = cached_response - - # We always cache the 301 responses - elif response.status == 301: - self.controller.cache_response(request, response) - else: - # Wrap the response file with a wrapper that will cache the - # response when the stream has been consumed. - response._fp = CallbackFileWrapper( - response._fp, - functools.partial( - self.controller.cache_response, request, response - ), - ) - if response.chunked: - super_update_chunk_length = response._update_chunk_length - - def _update_chunk_length(self): - super_update_chunk_length() - if self.chunk_left == 0: - self._fp._close() - - response._update_chunk_length = types.MethodType( - _update_chunk_length, response - ) - - resp = super(CacheControlAdapter, self).build_response(request, response) - - # See if we should invalidate the cache. - if request.method in self.invalidating_methods and resp.ok: - cache_url = self.controller.cache_url(request.url) - self.cache.delete(cache_url) - - # Give the request a from_cache attr to let people use it - resp.from_cache = from_cache - - return resp - - def close(self): - self.cache.close() - super(CacheControlAdapter, self).close() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/cache.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/cache.py deleted file mode 100644 index 94e0773..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/cache.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -The cache object API for implementing caches. The default is a thread -safe in-memory dictionary. -""" -from threading import Lock - - -class BaseCache(object): - - def get(self, key): - raise NotImplementedError() - - def set(self, key, value): - raise NotImplementedError() - - def delete(self, key): - raise NotImplementedError() - - def close(self): - pass - - -class DictCache(BaseCache): - - def __init__(self, init_dict=None): - self.lock = Lock() - self.data = init_dict or {} - - def get(self, key): - return self.data.get(key, None) - - def set(self, key, value): - with self.lock: - self.data.update({key: value}) - - def delete(self, key): - with self.lock: - if key in self.data: - self.data.pop(key) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/__init__.py deleted file mode 100644 index 0e1658f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .file_cache import FileCache # noqa -from .redis_cache import RedisCache # noqa diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py deleted file mode 100644 index 607b945..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py +++ /dev/null @@ -1,146 +0,0 @@ -import hashlib -import os -from textwrap import dedent - -from ..cache import BaseCache -from ..controller import CacheController - -try: - FileNotFoundError -except NameError: - # py2.X - FileNotFoundError = (IOError, OSError) - - -def _secure_open_write(filename, fmode): - # We only want to write to this file, so open it in write only mode - flags = os.O_WRONLY - - # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only - # will open *new* files. - # We specify this because we want to ensure that the mode we pass is the - # mode of the file. - flags |= os.O_CREAT | os.O_EXCL - - # Do not follow symlinks to prevent someone from making a symlink that - # we follow and insecurely open a cache file. - if hasattr(os, "O_NOFOLLOW"): - flags |= os.O_NOFOLLOW - - # On Windows we'll mark this file as binary - if hasattr(os, "O_BINARY"): - flags |= os.O_BINARY - - # Before we open our file, we want to delete any existing file that is - # there - try: - os.remove(filename) - except (IOError, OSError): - # The file must not exist already, so we can just skip ahead to opening - pass - - # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a - # race condition happens between the os.remove and this line, that an - # error will be raised. Because we utilize a lockfile this should only - # happen if someone is attempting to attack us. - fd = os.open(filename, flags, fmode) - try: - return os.fdopen(fd, "wb") - - except: - # An error occurred wrapping our FD in a file object - os.close(fd) - raise - - -class FileCache(BaseCache): - - def __init__( - self, - directory, - forever=False, - filemode=0o0600, - dirmode=0o0700, - use_dir_lock=None, - lock_class=None, - ): - - if use_dir_lock is not None and lock_class is not None: - raise ValueError("Cannot use use_dir_lock and lock_class together") - - try: - from lockfile import LockFile - from lockfile.mkdirlockfile import MkdirLockFile - except ImportError: - notice = dedent( - """ - NOTE: In order to use the FileCache you must have - lockfile installed. You can install it via pip: - pip install lockfile - """ - ) - raise ImportError(notice) - - else: - if use_dir_lock: - lock_class = MkdirLockFile - - elif lock_class is None: - lock_class = LockFile - - self.directory = directory - self.forever = forever - self.filemode = filemode - self.dirmode = dirmode - self.lock_class = lock_class - - @staticmethod - def encode(x): - return hashlib.sha224(x.encode()).hexdigest() - - def _fn(self, name): - # NOTE: This method should not change as some may depend on it. - # See: https://github.com/ionrock/cachecontrol/issues/63 - hashed = self.encode(name) - parts = list(hashed[:5]) + [hashed] - return os.path.join(self.directory, *parts) - - def get(self, key): - name = self._fn(key) - try: - with open(name, "rb") as fh: - return fh.read() - - except FileNotFoundError: - return None - - def set(self, key, value): - name = self._fn(key) - - # Make sure the directory exists - try: - os.makedirs(os.path.dirname(name), self.dirmode) - except (IOError, OSError): - pass - - with self.lock_class(name) as lock: - # Write our actual file - with _secure_open_write(lock.path, self.filemode) as fh: - fh.write(value) - - def delete(self, key): - name = self._fn(key) - if not self.forever: - try: - os.remove(name) - except FileNotFoundError: - pass - - -def url_to_file_path(url, filecache): - """Return the file cache path based on the URL. - - This does not ensure the file exists! - """ - key = CacheController.cache_url(url) - return filecache._fn(key) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py deleted file mode 100644 index ed705ce..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import division - -from datetime import datetime -from pip._vendor.cachecontrol.cache import BaseCache - - -class RedisCache(BaseCache): - - def __init__(self, conn): - self.conn = conn - - def get(self, key): - return self.conn.get(key) - - def set(self, key, value, expires=None): - if not expires: - self.conn.set(key, value) - else: - expires = expires - datetime.utcnow() - self.conn.setex(key, int(expires.total_seconds()), value) - - def delete(self, key): - self.conn.delete(key) - - def clear(self): - """Helper for clearing all the keys in a database. Use with - caution!""" - for key in self.conn.keys(): - self.conn.delete(key) - - def close(self): - """Redis uses connection pooling, no need to close the connection.""" - pass diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/compat.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/compat.py deleted file mode 100644 index 33b5aed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/compat.py +++ /dev/null @@ -1,29 +0,0 @@ -try: - from urllib.parse import urljoin -except ImportError: - from urlparse import urljoin - - -try: - import cPickle as pickle -except ImportError: - import pickle - - -# Handle the case where the requests module has been patched to not have -# urllib3 bundled as part of its source. -try: - from pip._vendor.requests.packages.urllib3.response import HTTPResponse -except ImportError: - from pip._vendor.urllib3.response import HTTPResponse - -try: - from pip._vendor.requests.packages.urllib3.util import is_fp_closed -except ImportError: - from pip._vendor.urllib3.util import is_fp_closed - -# Replicate some six behaviour -try: - text_type = unicode -except NameError: - text_type = str diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/controller.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/controller.py deleted file mode 100644 index dafe55c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/controller.py +++ /dev/null @@ -1,376 +0,0 @@ -""" -The httplib2 algorithms ported for use with requests. -""" -import logging -import re -import calendar -import time -from email.utils import parsedate_tz - -from pip._vendor.requests.structures import CaseInsensitiveDict - -from .cache import DictCache -from .serialize import Serializer - - -logger = logging.getLogger(__name__) - -URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") - - -def parse_uri(uri): - """Parses a URI using the regex given in Appendix B of RFC 3986. - - (scheme, authority, path, query, fragment) = parse_uri(uri) - """ - groups = URI.match(uri).groups() - return (groups[1], groups[3], groups[4], groups[6], groups[8]) - - -class CacheController(object): - """An interface to see if request should cached or not. - """ - - def __init__( - self, cache=None, cache_etags=True, serializer=None, status_codes=None - ): - self.cache = DictCache() if cache is None else cache - self.cache_etags = cache_etags - self.serializer = serializer or Serializer() - self.cacheable_status_codes = status_codes or (200, 203, 300, 301) - - @classmethod - def _urlnorm(cls, uri): - """Normalize the URL to create a safe key for the cache""" - (scheme, authority, path, query, fragment) = parse_uri(uri) - if not scheme or not authority: - raise Exception("Only absolute URIs are allowed. uri = %s" % uri) - - scheme = scheme.lower() - authority = authority.lower() - - if not path: - path = "/" - - # Could do syntax based normalization of the URI before - # computing the digest. See Section 6.2.2 of Std 66. - request_uri = query and "?".join([path, query]) or path - defrag_uri = scheme + "://" + authority + request_uri - - return defrag_uri - - @classmethod - def cache_url(cls, uri): - return cls._urlnorm(uri) - - def parse_cache_control(self, headers): - known_directives = { - # https://tools.ietf.org/html/rfc7234#section-5.2 - "max-age": (int, True), - "max-stale": (int, False), - "min-fresh": (int, True), - "no-cache": (None, False), - "no-store": (None, False), - "no-transform": (None, False), - "only-if-cached": (None, False), - "must-revalidate": (None, False), - "public": (None, False), - "private": (None, False), - "proxy-revalidate": (None, False), - "s-maxage": (int, True), - } - - cc_headers = headers.get("cache-control", headers.get("Cache-Control", "")) - - retval = {} - - for cc_directive in cc_headers.split(","): - if not cc_directive.strip(): - continue - - parts = cc_directive.split("=", 1) - directive = parts[0].strip() - - try: - typ, required = known_directives[directive] - except KeyError: - logger.debug("Ignoring unknown cache-control directive: %s", directive) - continue - - if not typ or not required: - retval[directive] = None - if typ: - try: - retval[directive] = typ(parts[1].strip()) - except IndexError: - if required: - logger.debug( - "Missing value for cache-control " "directive: %s", - directive, - ) - except ValueError: - logger.debug( - "Invalid value for cache-control directive " "%s, must be %s", - directive, - typ.__name__, - ) - - return retval - - def cached_request(self, request): - """ - Return a cached response if it exists in the cache, otherwise - return False. - """ - cache_url = self.cache_url(request.url) - logger.debug('Looking up "%s" in the cache', cache_url) - cc = self.parse_cache_control(request.headers) - - # Bail out if the request insists on fresh data - if "no-cache" in cc: - logger.debug('Request header has "no-cache", cache bypassed') - return False - - if "max-age" in cc and cc["max-age"] == 0: - logger.debug('Request header has "max_age" as 0, cache bypassed') - return False - - # Request allows serving from the cache, let's see if we find something - cache_data = self.cache.get(cache_url) - if cache_data is None: - logger.debug("No cache entry available") - return False - - # Check whether it can be deserialized - resp = self.serializer.loads(request, cache_data) - if not resp: - logger.warning("Cache entry deserialization failed, entry ignored") - return False - - # If we have a cached 301, return it immediately. We don't - # need to test our response for other headers b/c it is - # intrinsically "cacheable" as it is Permanent. - # See: - # https://tools.ietf.org/html/rfc7231#section-6.4.2 - # - # Client can try to refresh the value by repeating the request - # with cache busting headers as usual (ie no-cache). - if resp.status == 301: - msg = ( - 'Returning cached "301 Moved Permanently" response ' - "(ignoring date and etag information)" - ) - logger.debug(msg) - return resp - - headers = CaseInsensitiveDict(resp.headers) - if not headers or "date" not in headers: - if "etag" not in headers: - # Without date or etag, the cached response can never be used - # and should be deleted. - logger.debug("Purging cached response: no date or etag") - self.cache.delete(cache_url) - logger.debug("Ignoring cached response: no date") - return False - - now = time.time() - date = calendar.timegm(parsedate_tz(headers["date"])) - current_age = max(0, now - date) - logger.debug("Current age based on date: %i", current_age) - - # TODO: There is an assumption that the result will be a - # urllib3 response object. This may not be best since we - # could probably avoid instantiating or constructing the - # response until we know we need it. - resp_cc = self.parse_cache_control(headers) - - # determine freshness - freshness_lifetime = 0 - - # Check the max-age pragma in the cache control header - if "max-age" in resp_cc: - freshness_lifetime = resp_cc["max-age"] - logger.debug("Freshness lifetime from max-age: %i", freshness_lifetime) - - # If there isn't a max-age, check for an expires header - elif "expires" in headers: - expires = parsedate_tz(headers["expires"]) - if expires is not None: - expire_time = calendar.timegm(expires) - date - freshness_lifetime = max(0, expire_time) - logger.debug("Freshness lifetime from expires: %i", freshness_lifetime) - - # Determine if we are setting freshness limit in the - # request. Note, this overrides what was in the response. - if "max-age" in cc: - freshness_lifetime = cc["max-age"] - logger.debug( - "Freshness lifetime from request max-age: %i", freshness_lifetime - ) - - if "min-fresh" in cc: - min_fresh = cc["min-fresh"] - # adjust our current age by our min fresh - current_age += min_fresh - logger.debug("Adjusted current age from min-fresh: %i", current_age) - - # Return entry if it is fresh enough - if freshness_lifetime > current_age: - logger.debug('The response is "fresh", returning cached response') - logger.debug("%i > %i", freshness_lifetime, current_age) - return resp - - # we're not fresh. If we don't have an Etag, clear it out - if "etag" not in headers: - logger.debug('The cached response is "stale" with no etag, purging') - self.cache.delete(cache_url) - - # return the original handler - return False - - def conditional_headers(self, request): - cache_url = self.cache_url(request.url) - resp = self.serializer.loads(request, self.cache.get(cache_url)) - new_headers = {} - - if resp: - headers = CaseInsensitiveDict(resp.headers) - - if "etag" in headers: - new_headers["If-None-Match"] = headers["ETag"] - - if "last-modified" in headers: - new_headers["If-Modified-Since"] = headers["Last-Modified"] - - return new_headers - - def cache_response(self, request, response, body=None, status_codes=None): - """ - Algorithm for caching requests. - - This assumes a requests Response object. - """ - # From httplib2: Don't cache 206's since we aren't going to - # handle byte range requests - cacheable_status_codes = status_codes or self.cacheable_status_codes - if response.status not in cacheable_status_codes: - logger.debug( - "Status code %s not in %s", response.status, cacheable_status_codes - ) - return - - response_headers = CaseInsensitiveDict(response.headers) - - # If we've been given a body, our response has a Content-Length, that - # Content-Length is valid then we can check to see if the body we've - # been given matches the expected size, and if it doesn't we'll just - # skip trying to cache it. - if ( - body is not None - and "content-length" in response_headers - and response_headers["content-length"].isdigit() - and int(response_headers["content-length"]) != len(body) - ): - return - - cc_req = self.parse_cache_control(request.headers) - cc = self.parse_cache_control(response_headers) - - cache_url = self.cache_url(request.url) - logger.debug('Updating cache with response from "%s"', cache_url) - - # Delete it from the cache if we happen to have it stored there - no_store = False - if "no-store" in cc: - no_store = True - logger.debug('Response header has "no-store"') - if "no-store" in cc_req: - no_store = True - logger.debug('Request header has "no-store"') - if no_store and self.cache.get(cache_url): - logger.debug('Purging existing cache entry to honor "no-store"') - self.cache.delete(cache_url) - if no_store: - return - - # https://tools.ietf.org/html/rfc7234#section-4.1: - # A Vary header field-value of "*" always fails to match. - # Storing such a response leads to a deserialization warning - # during cache lookup and is not allowed to ever be served, - # so storing it can be avoided. - if "*" in response_headers.get("vary", ""): - logger.debug('Response header has "Vary: *"') - return - - # If we've been given an etag, then keep the response - if self.cache_etags and "etag" in response_headers: - logger.debug("Caching due to etag") - self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) - ) - - # Add to the cache any 301s. We do this before looking that - # the Date headers. - elif response.status == 301: - logger.debug("Caching permanant redirect") - self.cache.set(cache_url, self.serializer.dumps(request, response)) - - # Add to the cache if the response headers demand it. If there - # is no date header then we can't do anything about expiring - # the cache. - elif "date" in response_headers: - # cache when there is a max-age > 0 - if "max-age" in cc and cc["max-age"] > 0: - logger.debug("Caching b/c date exists and max-age > 0") - self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) - ) - - # If the request can expire, it means we should cache it - # in the meantime. - elif "expires" in response_headers: - if response_headers["expires"]: - logger.debug("Caching b/c of expires header") - self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) - ) - - def update_cached_response(self, request, response): - """On a 304 we will get a new set of headers that we want to - update our cached value with, assuming we have one. - - This should only ever be called when we've sent an ETag and - gotten a 304 as the response. - """ - cache_url = self.cache_url(request.url) - - cached_response = self.serializer.loads(request, self.cache.get(cache_url)) - - if not cached_response: - # we didn't have a cached response - return response - - # Lets update our headers with the headers from the new request: - # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1 - # - # The server isn't supposed to send headers that would make - # the cached body invalid. But... just in case, we'll be sure - # to strip out ones we know that might be problmatic due to - # typical assumptions. - excluded_headers = ["content-length"] - - cached_response.headers.update( - dict( - (k, v) - for k, v in response.headers.items() - if k.lower() not in excluded_headers - ) - ) - - # we want a 200 b/c we have content via the cache - cached_response.status = 200 - - # update our cache - self.cache.set(cache_url, self.serializer.dumps(request, cached_response)) - - return cached_response diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/filewrapper.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/filewrapper.py deleted file mode 100644 index 30ed4c5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/filewrapper.py +++ /dev/null @@ -1,80 +0,0 @@ -from io import BytesIO - - -class CallbackFileWrapper(object): - """ - Small wrapper around a fp object which will tee everything read into a - buffer, and when that file is closed it will execute a callback with the - contents of that buffer. - - All attributes are proxied to the underlying file object. - - This class uses members with a double underscore (__) leading prefix so as - not to accidentally shadow an attribute. - """ - - def __init__(self, fp, callback): - self.__buf = BytesIO() - self.__fp = fp - self.__callback = callback - - def __getattr__(self, name): - # The vaguaries of garbage collection means that self.__fp is - # not always set. By using __getattribute__ and the private - # name[0] allows looking up the attribute value and raising an - # AttributeError when it doesn't exist. This stop thigns from - # infinitely recursing calls to getattr in the case where - # self.__fp hasn't been set. - # - # [0] https://docs.python.org/2/reference/expressions.html#atom-identifiers - fp = self.__getattribute__("_CallbackFileWrapper__fp") - return getattr(fp, name) - - def __is_fp_closed(self): - try: - return self.__fp.fp is None - - except AttributeError: - pass - - try: - return self.__fp.closed - - except AttributeError: - pass - - # We just don't cache it then. - # TODO: Add some logging here... - return False - - def _close(self): - if self.__callback: - self.__callback(self.__buf.getvalue()) - - # We assign this to None here, because otherwise we can get into - # really tricky problems where the CPython interpreter dead locks - # because the callback is holding a reference to something which - # has a __del__ method. Setting this to None breaks the cycle - # and allows the garbage collector to do it's thing normally. - self.__callback = None - - def read(self, amt=None): - data = self.__fp.read(amt) - self.__buf.write(data) - if self.__is_fp_closed(): - self._close() - - return data - - def _safe_read(self, amt): - data = self.__fp._safe_read(amt) - if amt == 2 and data == b"\r\n": - # urllib executes this read to toss the CRLF at the end - # of the chunk. - return data - - self.__buf.write(data) - if self.__is_fp_closed(): - self._close() - - return data diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/heuristics.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/heuristics.py deleted file mode 100644 index 6c0e979..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/heuristics.py +++ /dev/null @@ -1,135 +0,0 @@ -import calendar -import time - -from email.utils import formatdate, parsedate, parsedate_tz - -from datetime import datetime, timedelta - -TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" - - -def expire_after(delta, date=None): - date = date or datetime.utcnow() - return date + delta - - -def datetime_to_header(dt): - return formatdate(calendar.timegm(dt.timetuple())) - - -class BaseHeuristic(object): - - def warning(self, response): - """ - Return a valid 1xx warning header value describing the cache - adjustments. - - The response is provided too allow warnings like 113 - http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need - to explicitly say response is over 24 hours old. - """ - return '110 - "Response is Stale"' - - def update_headers(self, response): - """Update the response headers with any new headers. - - NOTE: This SHOULD always include some Warning header to - signify that the response was cached by the client, not - by way of the provided headers. - """ - return {} - - def apply(self, response): - updated_headers = self.update_headers(response) - - if updated_headers: - response.headers.update(updated_headers) - warning_header_value = self.warning(response) - if warning_header_value is not None: - response.headers.update({"Warning": warning_header_value}) - - return response - - -class OneDayCache(BaseHeuristic): - """ - Cache the response by providing an expires 1 day in the - future. - """ - - def update_headers(self, response): - headers = {} - - if "expires" not in response.headers: - date = parsedate(response.headers["date"]) - expires = expire_after(timedelta(days=1), date=datetime(*date[:6])) - headers["expires"] = datetime_to_header(expires) - headers["cache-control"] = "public" - return headers - - -class ExpiresAfter(BaseHeuristic): - """ - Cache **all** requests for a defined time period. - """ - - def __init__(self, **kw): - self.delta = timedelta(**kw) - - def update_headers(self, response): - expires = expire_after(self.delta) - return {"expires": datetime_to_header(expires), "cache-control": "public"} - - def warning(self, response): - tmpl = "110 - Automatically cached for %s. Response might be stale" - return tmpl % self.delta - - -class LastModified(BaseHeuristic): - """ - If there is no Expires header already, fall back on Last-Modified - using the heuristic from - http://tools.ietf.org/html/rfc7234#section-4.2.2 - to calculate a reasonable value. - - Firefox also does something like this per - https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ - http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 - Unlike mozilla we limit this to 24-hr. - """ - cacheable_by_default_statuses = { - 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 - } - - def update_headers(self, resp): - headers = resp.headers - - if "expires" in headers: - return {} - - if "cache-control" in headers and headers["cache-control"] != "public": - return {} - - if resp.status not in self.cacheable_by_default_statuses: - return {} - - if "date" not in headers or "last-modified" not in headers: - return {} - - date = calendar.timegm(parsedate_tz(headers["date"])) - last_modified = parsedate(headers["last-modified"]) - if date is None or last_modified is None: - return {} - - now = time.time() - current_age = max(0, now - date) - delta = date - calendar.timegm(last_modified) - freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) - if freshness_lifetime <= current_age: - return {} - - expires = date + freshness_lifetime - return {"expires": time.strftime(TIME_FMT, time.gmtime(expires))} - - def warning(self, resp): - return None diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/serialize.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/serialize.py deleted file mode 100644 index 3b6ec2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/serialize.py +++ /dev/null @@ -1,188 +0,0 @@ -import base64 -import io -import json -import zlib - -from pip._vendor import msgpack -from pip._vendor.requests.structures import CaseInsensitiveDict - -from .compat import HTTPResponse, pickle, text_type - - -def _b64_decode_bytes(b): - return base64.b64decode(b.encode("ascii")) - - -def _b64_decode_str(s): - return _b64_decode_bytes(s).decode("utf8") - - -class Serializer(object): - - def dumps(self, request, response, body=None): - response_headers = CaseInsensitiveDict(response.headers) - - if body is None: - body = response.read(decode_content=False) - - # NOTE: 99% sure this is dead code. I'm only leaving it - # here b/c I don't have a test yet to prove - # it. Basically, before using - # `cachecontrol.filewrapper.CallbackFileWrapper`, - # this made an effort to reset the file handle. The - # `CallbackFileWrapper` short circuits this code by - # setting the body as the content is consumed, the - # result being a `body` argument is *always* passed - # into cache_response, and in turn, - # `Serializer.dump`. - response._fp = io.BytesIO(body) - - # NOTE: This is all a bit weird, but it's really important that on - # Python 2.x these objects are unicode and not str, even when - # they contain only ascii. The problem here is that msgpack - # understands the difference between unicode and bytes and we - # have it set to differentiate between them, however Python 2 - # doesn't know the difference. Forcing these to unicode will be - # enough to have msgpack know the difference. - data = { - u"response": { - u"body": body, - u"headers": dict( - (text_type(k), text_type(v)) for k, v in response.headers.items() - ), - u"status": response.status, - u"version": response.version, - u"reason": text_type(response.reason), - u"strict": response.strict, - u"decode_content": response.decode_content, - } - } - - # Construct our vary headers - data[u"vary"] = {} - if u"vary" in response_headers: - varied_headers = response_headers[u"vary"].split(",") - for header in varied_headers: - header = text_type(header).strip() - header_value = request.headers.get(header, None) - if header_value is not None: - header_value = text_type(header_value) - data[u"vary"][header] = header_value - - return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)]) - - def loads(self, request, data): - # Short circuit if we've been given an empty set of data - if not data: - return - - # Determine what version of the serializer the data was serialized - # with - try: - ver, data = data.split(b",", 1) - except ValueError: - ver = b"cc=0" - - # Make sure that our "ver" is actually a version and isn't a false - # positive from a , being in the data stream. - if ver[:3] != b"cc=": - data = ver + data - ver = b"cc=0" - - # Get the version number out of the cc=N - ver = ver.split(b"=", 1)[-1].decode("ascii") - - # Dispatch to the actual load method for the given version - try: - return getattr(self, "_loads_v{}".format(ver))(request, data) - - except AttributeError: - # This is a version we don't have a loads function for, so we'll - # just treat it as a miss and return None - return - - def prepare_response(self, request, cached): - """Verify our vary headers match and construct a real urllib3 - HTTPResponse object. - """ - # Special case the '*' Vary value as it means we cannot actually - # determine if the cached response is suitable for this request. - # This case is also handled in the controller code when creating - # a cache entry, but is left here for backwards compatibility. - if "*" in cached.get("vary", {}): - return - - # Ensure that the Vary headers for the cached response match our - # request - for header, value in cached.get("vary", {}).items(): - if request.headers.get(header, None) != value: - return - - body_raw = cached["response"].pop("body") - - headers = CaseInsensitiveDict(data=cached["response"]["headers"]) - if headers.get("transfer-encoding", "") == "chunked": - headers.pop("transfer-encoding") - - cached["response"]["headers"] = headers - - try: - body = io.BytesIO(body_raw) - except TypeError: - # This can happen if cachecontrol serialized to v1 format (pickle) - # using Python 2. A Python 2 str(byte string) will be unpickled as - # a Python 3 str (unicode string), which will cause the above to - # fail with: - # - # TypeError: 'str' does not support the buffer interface - body = io.BytesIO(body_raw.encode("utf8")) - - return HTTPResponse(body=body, preload_content=False, **cached["response"]) - - def _loads_v0(self, request, data): - # The original legacy cache data. This doesn't contain enough - # information to construct everything we need, so we'll treat this as - # a miss. - return - - def _loads_v1(self, request, data): - try: - cached = pickle.loads(data) - except ValueError: - return - - return self.prepare_response(request, cached) - - def _loads_v2(self, request, data): - try: - cached = json.loads(zlib.decompress(data).decode("utf8")) - except (ValueError, zlib.error): - return - - # We need to decode the items that we've base64 encoded - cached["response"]["body"] = _b64_decode_bytes(cached["response"]["body"]) - cached["response"]["headers"] = dict( - (_b64_decode_str(k), _b64_decode_str(v)) - for k, v in cached["response"]["headers"].items() - ) - cached["response"]["reason"] = _b64_decode_str(cached["response"]["reason"]) - cached["vary"] = dict( - (_b64_decode_str(k), _b64_decode_str(v) if v is not None else v) - for k, v in cached["vary"].items() - ) - - return self.prepare_response(request, cached) - - def _loads_v3(self, request, data): - # Due to Python 2 encoding issues, it's impossible to know for sure - # exactly how to load v3 entries, thus we'll treat these as a miss so - # that they get rewritten out as v4 entries. - return - - def _loads_v4(self, request, data): - try: - cached = msgpack.loads(data, raw=False) - except ValueError: - return - - return self.prepare_response(request, cached) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/wrapper.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/wrapper.py deleted file mode 100644 index d8e6fc6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/cachecontrol/wrapper.py +++ /dev/null @@ -1,29 +0,0 @@ -from .adapter import CacheControlAdapter -from .cache import DictCache - - -def CacheControl( - sess, - cache=None, - cache_etags=True, - serializer=None, - heuristic=None, - controller_class=None, - adapter_class=None, - cacheable_methods=None, -): - - cache = DictCache() if cache is None else cache - adapter_class = adapter_class or CacheControlAdapter - adapter = adapter_class( - cache, - cache_etags=cache_etags, - serializer=serializer, - heuristic=heuristic, - controller_class=controller_class, - cacheable_methods=cacheable_methods, - ) - sess.mount("http://", adapter) - sess.mount("https://", adapter) - - return sess diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py deleted file mode 100644 index eebdf88..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .core import contents, where - -__version__ = "2021.05.30" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py deleted file mode 100644 index 0037634..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -import argparse - -from pip._vendor.certifi import contents, where - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--contents", action="store_true") -args = parser.parse_args() - -if args.contents: - print(contents()) -else: - print(where()) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem deleted file mode 100644 index 96e2fc6..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem +++ /dev/null @@ -1,4257 +0,0 @@ - -# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Label: "GlobalSign Root CA" -# Serial: 4835703278459707669005204 -# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a -# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c -# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Label: "GlobalSign Root CA - R2" -# Serial: 4835703278459682885658125 -# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 -# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe -# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- - -# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Label: "Entrust.net Premium 2048 Secure Server CA" -# Serial: 946069240 -# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 -# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 -# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 -MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub -j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo -U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b -u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ -bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er -fF6adulZkMV8gzURZVE= ------END CERTIFICATE----- - -# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Label: "Baltimore CyberTrust Root" -# Serial: 33554617 -# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 -# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 -# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Label: "Entrust Root Certification Authority" -# Serial: 1164660820 -# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 -# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 -# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- - -# Issuer: CN=AAA Certificate Services O=Comodo CA Limited -# Subject: CN=AAA Certificate Services O=Comodo CA Limited -# Label: "Comodo AAA Services root" -# Serial: 1 -# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 -# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 -# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2" -# Serial: 1289 -# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b -# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 -# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3" -# Serial: 1478 -# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf -# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 -# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 -# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 -# Label: "Security Communication Root CA" -# Serial: 0 -# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a -# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 -# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- - -# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Label: "XRamp Global CA Root" -# Serial: 107108908803651509692980124233745014957 -# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 -# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 -# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - -# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Label: "Go Daddy Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 -# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 -# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- - -# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Label: "Starfield Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 -# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a -# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root CA" -# Serial: 17154717934120587862167794914071425081 -# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 -# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 -# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert High Assurance EV Root CA" -# Serial: 3553400076410547919724730734378100087 -# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a -# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 -# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - -# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Label: "DST Root CA X3" -# Serial: 91299735575339953335919266965803778155 -# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 -# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 -# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Label: "SwissSign Gold CA - G2" -# Serial: 13492815561806991280 -# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 -# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 -# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Label: "SwissSign Silver CA - G2" -# Serial: 5700383053117599563 -# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 -# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb -# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu -IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow -RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY -U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv -Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br -YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF -nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH -6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt -eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ -c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ -MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH -HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf -jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 -5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB -rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c -wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB -AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp -WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 -xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ -2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ -IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 -aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X -em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR -dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ -OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ -hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy -tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- - -# Issuer: CN=SecureTrust CA O=SecureTrust Corporation -# Subject: CN=SecureTrust CA O=SecureTrust Corporation -# Label: "SecureTrust CA" -# Serial: 17199774589125277788362757014266862032 -# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 -# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 -# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -# Issuer: CN=Secure Global CA O=SecureTrust Corporation -# Subject: CN=Secure Global CA O=SecureTrust Corporation -# Label: "Secure Global CA" -# Serial: 9751836167731051554232119481456978597 -# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de -# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b -# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO Certification Authority O=COMODO CA Limited -# Label: "COMODO Certification Authority" -# Serial: 104350513648249232941998508985834464573 -# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 -# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b -# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- - -# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Label: "Network Solutions Certificate Authority" -# Serial: 116697915152937497490437556386812487904 -# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e -# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce -# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi -MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV -UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO -ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz -c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP -OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl -mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF -BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 -qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw -gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu -bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp -dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 -6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ -h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH -/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN -pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -# Issuer: CN=Certigna O=Dhimyotis -# Subject: CN=Certigna O=Dhimyotis -# Label: "Certigna" -# Serial: 18364802974209362175 -# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff -# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 -# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc -# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc -# Label: "Cybertrust Global Root" -# Serial: 4835703278459682877484360 -# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 -# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 -# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG -A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh -bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE -ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS -b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 -7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS -J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y -HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP -t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz -FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY -XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw -hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js -MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA -A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj -Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx -XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o -omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc -A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -# Issuer: O=certSIGN OU=certSIGN ROOT CA -# Subject: O=certSIGN OU=certSIGN ROOT CA -# Label: "certSIGN ROOT CA" -# Serial: 35210227249154 -# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 -# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b -# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Label: "Hongkong Post Root CA 1" -# Serial: 1000 -# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca -# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 -# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx -FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg -Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG -A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr -b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ -jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn -PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh -ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 -nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h -q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED -MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC -mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 -7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB -oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs -EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO -fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi -AmvZWg== ------END CERTIFICATE----- - -# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Label: "SecureSign RootCA11" -# Serial: 1 -# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 -# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 -# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr -MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG -A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 -MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp -Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD -QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz -i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 -h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV -MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 -UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni -8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC -h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD -VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB -AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm -KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ -X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr -QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 -pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN -QSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 6047274297262753887 -# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 -# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa -# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy -MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD -VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv -ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl -AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF -661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 -am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 -ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 -PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS -3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k -SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF -3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM -ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g -StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz -Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB -jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Commercial O=AffirmTrust -# Subject: CN=AffirmTrust Commercial O=AffirmTrust -# Label: "AffirmTrust Commercial" -# Serial: 8608355977964138876 -# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 -# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 -# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP -Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr -ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL -MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 -yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr -VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ -nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG -XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj -vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt -Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g -N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC -nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Networking O=AffirmTrust -# Subject: CN=AffirmTrust Networking O=AffirmTrust -# Label: "AffirmTrust Networking" -# Serial: 8957382827206547757 -# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f -# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f -# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y -YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua -kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL -QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp -6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG -yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i -QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO -tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu -QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ -Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u -olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 -x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium O=AffirmTrust -# Subject: CN=AffirmTrust Premium O=AffirmTrust -# Label: "AffirmTrust Premium" -# Serial: 7893706540734352110 -# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 -# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 -# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz -dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG -A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U -cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf -qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ -JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ -+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS -s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 -HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 -70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG -V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S -qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S -5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia -C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX -OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE -FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 -KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B -8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ -MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc -0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ -u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF -u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH -YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 -GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO -RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e -KeC2uAloGRwYQw== ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust -# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust -# Label: "AffirmTrust Premium ECC" -# Serial: 8401224907861490260 -# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d -# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb -# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes -# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes -# Label: "EC-ACC" -# Serial: -23701579247955709139626555126524820479 -# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 -# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 -# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 ------BEGIN CERTIFICATE----- -MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB -8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy -dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 -YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 -dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh -IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD -LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG -EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g -KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD -ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu -bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg -ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R -85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm -4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV -HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd -QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t -lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB -o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 -opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo -dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW -ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN -AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y -/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k -SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy -Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS -Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl -nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2011" -# Serial: 0 -# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 -# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d -# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 ------BEGIN CERTIFICATE----- -MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix -RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p -YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw -NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK -EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl -cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz -dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ -fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns -bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD -75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP -FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV -HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp -5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu -b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA -A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p -6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 -TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 -dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys -Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI -l7WdmplNsDz4SgCbZN2fOUvRJ9e4 ------END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- - -# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Label: "TeliaSonera Root CA v1" -# Serial: 199041966741090107964904287217786801558 -# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c -# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 -# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw -NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv -b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD -VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F -VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 -7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X -Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ -/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs -81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm -dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe -Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu -sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 -pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs -slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ -arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG -9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl -dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj -TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed -Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 -Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI -OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 -vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW -t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn -HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx -SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- - -# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Label: "E-Tugra Certification Authority" -# Serial: 7667447206703254355 -# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 -# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 -# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV -BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC -aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV -BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 -Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz -MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ -BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp -em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN -ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY -B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH -D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF -Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo -q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D -k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH -fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut -dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM -ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 -zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn -rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX -U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 -Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 -XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF -Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR -HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY -GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c -77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 -+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK -vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 -FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl -yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P -AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD -y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d -NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 14367148294922964480859022125800977897474 -# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e -# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb -# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c ------BEGIN CERTIFICATE----- -MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ -FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F -uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX -kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs -ewv4n4Q= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Label: "Staat der Nederlanden EV Root CA" -# Serial: 10000013 -# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba -# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb -# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a ------BEGIN CERTIFICATE----- -MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y -MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg -TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS -b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS -M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC -UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d -Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p -rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l -pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb -j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC -KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS -/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X -cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH -1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP -px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 -MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI -eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u -2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS -v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC -wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy -CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e -vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 -Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa -Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL -eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 -FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc -7uzXLg== ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - G2" -# Serial: 1246989352 -# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 -# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 -# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 ------BEGIN CERTIFICATE----- -MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 -cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs -IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz -dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy -NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu -dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt -dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 -aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T -RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN -cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW -wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 -U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 -jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN -BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ -jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ -Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v -1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R -nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH -VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - EC1" -# Serial: 51543124481930649114116133369 -# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc -# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 -# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 ------BEGIN CERTIFICATE----- -MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG -A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 -d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu -dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq -RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy -MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD -VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g -Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi -A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt -ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH -Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC -R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX -hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-1" -# Serial: 15752444095811006489 -# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 -# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a -# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y -IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB -pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h -IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG -A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU -cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid -RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V -seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme -9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV -EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW -hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ -DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I -/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf -ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ -yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts -L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN -zl/HHk484IkzlQsPpTLWPFp5LBk= ------END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-2" -# Serial: 2711694510199101698 -# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 -# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 -# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 ------BEGIN CERTIFICATE----- -MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig -Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk -MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg -Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD -VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy -dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ -QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq -1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp -2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK -DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape -az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF -3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 -oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM -g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 -mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh -8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd -BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U -nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw -DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX -dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ -MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL -/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX -CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa -ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW -2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 -N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 -Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB -As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp -5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu -1uwJ ------END CERTIFICATE----- - -# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor ECA-1" -# Serial: 9548242946988625984 -# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c -# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd -# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y -IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig -RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb -3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA -BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 -3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou -owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ -wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF -ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf -BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv -civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 -AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F -hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 -soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI -WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi -tJ/X5g== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Label: "GlobalSign Root CA - R6" -# Serial: 1417766617973444989252670301619537 -# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae -# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 -# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GC CA" -# Serial: 44084345621038548146064804565436152554 -# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 -# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 -# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 146587175971765017618439757810265552097 -# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 -# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 -# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy -MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl -cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM -f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX -mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 -zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P -fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc -vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 -Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp -zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO -Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW -k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ -DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF -lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW -Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 -d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z -XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR -gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 -d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv -J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg -DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM -+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy -F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 -SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws -E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R2 O=Google Trust Services LLC -# Subject: CN=GTS Root R2 O=Google Trust Services LLC -# Label: "GTS Root R2" -# Serial: 146587176055767053814479386953112547951 -# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b -# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d -# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy -MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl -cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv -CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg -GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu -XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd -re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu -PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 -mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K -8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj -x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR -nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 -kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok -twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp -8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT -vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT -z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA -pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb -pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB -R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R -RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk -0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC -5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF -izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn -yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R3 O=Google Trust Services LLC -# Subject: CN=GTS Root R3 O=Google Trust Services LLC -# Label: "GTS Root R3" -# Serial: 146587176140553309517047991083707763997 -# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 -# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 -# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 ------BEGIN CERTIFICATE----- -MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout -736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A -DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk -fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA -njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 146587176229350439916519468929765261721 -# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 -# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb -# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd ------BEGIN CERTIFICATE----- -MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu -hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l -xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 -CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx -sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== ------END CERTIFICATE----- - -# Issuer: CN=UCA Global G2 Root O=UniTrust -# Subject: CN=UCA Global G2 Root O=UniTrust -# Label: "UCA Global G2 Root" -# Serial: 124779693093741543919145257850076631279 -# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 -# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a -# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- - -# Issuer: CN=UCA Extended Validation Root O=UniTrust -# Subject: CN=UCA Extended Validation Root O=UniTrust -# Label: "UCA Extended Validation Root" -# Serial: 106100277556486529736699587978573607008 -# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 -# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a -# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- - -# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Label: "Certigna Root CA" -# Serial: 269714418870597844693661054334862075617 -# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 -# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 -# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign Root CA - G1" -# Serial: 235931866688319308814040 -# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac -# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c -# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign ECC Root CA - G3" -# Serial: 287880440101571086945156 -# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 -# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 -# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Label: "emSign Root CA - C1" -# Serial: 825510296613316004955058 -# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 -# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 -# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Label: "emSign ECC Root CA - C3" -# Serial: 582948710642506000014504 -# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 -# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 -# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Label: "Hongkong Post Root CA 3" -# Serial: 46170865288971385588281144162979347873371282084 -# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 -# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 -# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 ------BEGIN CERTIFICATE----- -MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL -BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ -SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n -a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 -NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT -CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u -Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO -dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI -VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV -9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY -2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY -vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt -bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb -x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ -l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK -TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj -Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e -i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw -DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG -7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk -MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr -gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk -GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS -3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm -Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ -l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c -JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP -L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa -LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG -mpv0 ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - G4" -# Serial: 289383649854506086828220374796556676440 -# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 -# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 -# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw -gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL -Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg -MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw -BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 -MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 -c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ -bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ -2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E -T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j -5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM -C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T -DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX -wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A -2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm -nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl -N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj -c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS -5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS -Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr -hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ -B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI -AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw -H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ -b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk -2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol -IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk -5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY -n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE----- - -# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft ECC Root Certificate Authority 2017" -# Serial: 136839042543790627607696632466672567020 -# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 -# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 -# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft RSA Root Certificate Authority 2017" -# Serial: 40975477897264996090493496164228220339 -# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 -# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 -# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Label: "e-Szigno Root CA 2017" -# Serial: 411379200276854331539784714 -# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 -# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 -# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- - -# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Label: "certSIGN Root CA G2" -# Serial: 313609486401300475190 -# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 -# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 -# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global Certification Authority" -# Serial: 1846098327275375458322922162 -# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e -# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 -# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw -CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x -ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 -c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx -OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI -SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn -swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu -7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 -1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW -80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP -JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l -RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw -hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 -coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc -BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n -twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W -0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe -uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q -lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB -aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE -sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT -MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe -qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh -VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 -h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 -EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK -yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P256 Certification Authority" -# Serial: 4151900041497450638097112925 -# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 -# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf -# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN -FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w -DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw -CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh -DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P384 Certification Authority" -# Serial: 2704997926503831671788816187 -# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 -# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 -# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB -BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ -j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF -1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G -A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 -AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC -MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu -Sw== ------END CERTIFICATE----- - -# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Label: "NAVER Global Root Certification Authority" -# Serial: 9013692873798656336226253319739695165984492813 -# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b -# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 -# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- - -# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" -# Serial: 131542671362353147877283741781055151509 -# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb -# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a -# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Label: "GlobalSign Root R46" -# Serial: 1552617688466950547958867513931858518042577 -# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef -# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 -# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Label: "GlobalSign Root E46" -# Serial: 1552617690338932563915843282459653771421763 -# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f -# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 -# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH -# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH -# Label: "GLOBALTRUST 2020" -# Serial: 109160994242082918454945253 -# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 -# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 -# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a ------BEGIN CERTIFICATE----- -MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG -A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw -FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx -MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u -aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b -RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z -YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 -QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw -yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ -BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ -SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH -r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 -4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me -dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw -q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 -nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu -H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA -VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC -XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd -6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf -+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi -kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 -wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB -TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C -MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn -4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I -aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy -qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE----- - -# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Label: "ANF Secure Server Root CA" -# Serial: 996390341000653745 -# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 -# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 -# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 ------BEGIN CERTIFICATE----- -MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV -BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk -YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV -BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN -MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF -UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD -VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v -dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj -cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q -yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH -2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX -H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL -zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR -p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz -W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ -SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn -LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 -n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B -u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj -o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L -9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej -rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK -pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 -vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq -OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ -/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 -2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI -+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 -MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo -tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= ------END CERTIFICATE----- - -# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum EC-384 CA" -# Serial: 160250656287871593594747141429395092468 -# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 -# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed -# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Root CA" -# Serial: 40870380103424195783807378461123655149 -# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 -# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 -# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 -MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu -MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV -BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw -MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg -U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ -n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q -p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq -NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF -8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 -HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa -mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi -7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF -ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P -qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ -v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 -Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 -vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD -ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 -WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo -zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR -5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ -GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf -5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq -0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D -P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM -qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP -0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf -E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb ------END CERTIFICATE----- diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/core.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/core.py deleted file mode 100644 index b8140cf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/certifi/core.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -certifi.py -~~~~~~~~~~ - -This module returns the installation location of cacert.pem or its contents. -""" -import os - - -class _PipPatchedCertificate(Exception): - pass - - -try: - # Return a certificate file on disk for a standalone pip zipapp running in - # an isolated build environment to use. Passing --cert to the standalone - # pip does not work since requests calls where() unconditionally on import. - _PIP_STANDALONE_CERT = os.environ.get("_PIP_STANDALONE_CERT") - if _PIP_STANDALONE_CERT: - def where(): - return _PIP_STANDALONE_CERT - raise _PipPatchedCertificate() - - from importlib.resources import path as get_path, read_text - - _CACERT_CTX = None - _CACERT_PATH = None - - def where(): - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("pip._vendor.certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - - return _CACERT_PATH - -except _PipPatchedCertificate: - pass - -except ImportError: - # This fallback will work for Python versions prior to 3.7 that lack the - # importlib.resources module but relies on the existing `where` function - # so won't address issues with environments like PyOxidizer that don't set - # __file__ on modules. - def read_text(_module, _path, encoding="ascii"): - with open(where(), "r", encoding=encoding) as data: - return data.read() - - # If we don't have importlib.resources, then we will just do the old logic - # of assuming we're on the filesystem and munge the path directly. - def where(): - f = os.path.dirname(__file__) - - return os.path.join(f, "cacert.pem") - - -def contents(): - return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/__init__.py deleted file mode 100644 index 80ad254..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/__init__.py +++ /dev/null @@ -1,83 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - - -from .universaldetector import UniversalDetector -from .enums import InputState -from .version import __version__, VERSION - - -__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION'] - - -def detect(byte_str): - """ - Detect the encoding of the given byte string. - - :param byte_str: The byte sequence to examine. - :type byte_str: ``bytes`` or ``bytearray`` - """ - if not isinstance(byte_str, bytearray): - if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) - detector = UniversalDetector() - detector.feed(byte_str) - return detector.close() - - -def detect_all(byte_str): - """ - Detect all the possible encodings of the given byte string. - - :param byte_str: The byte sequence to examine. - :type byte_str: ``bytes`` or ``bytearray`` - """ - if not isinstance(byte_str, bytearray): - if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) - - detector = UniversalDetector() - detector.feed(byte_str) - detector.close() - - if detector._input_state == InputState.HIGH_BYTE: - results = [] - for prober in detector._charset_probers: - if prober.get_confidence() > detector.MINIMUM_THRESHOLD: - charset_name = prober.charset_name - lower_charset_name = prober.charset_name.lower() - # Use Windows encoding name instead of ISO-8859 if we saw any - # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): - if detector._has_win_bytes: - charset_name = detector.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - results.append({ - 'encoding': charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language, - }) - if len(results) > 0: - return sorted(results, key=lambda result: -result['confidence']) - - return [detector.result] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5freq.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5freq.py deleted file mode 100644 index 38f3251..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5freq.py +++ /dev/null @@ -1,386 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Big5 frequency table -# by Taiwan's Mandarin Promotion Council -# -# -# 128 --> 0.42261 -# 256 --> 0.57851 -# 512 --> 0.74851 -# 1024 --> 0.89384 -# 2048 --> 0.97583 -# -# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 -# Random Distribution Ration = 512/(5401-512)=0.105 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR - -BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 - -#Char to FreqOrder table -BIG5_TABLE_SIZE = 5376 - -BIG5_CHAR_TO_FREQ_ORDER = ( - 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 -3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 -1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 - 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 -3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 -4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 -5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 - 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 - 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 - 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 -2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 -1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 -3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 - 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 -3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 -2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 - 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 -3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 -1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 -5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 - 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 -5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 -1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 - 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 - 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 -3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 -3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 - 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 -2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 -2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 - 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 - 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 -3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 -1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 -1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 -1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 -2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 - 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 -4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 -1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 -5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 -2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 - 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 - 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 - 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 - 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 -5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 - 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 -1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 - 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 - 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 -5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 -1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 - 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 -3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 -4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 -3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 - 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 - 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 -1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 -4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 -3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 -3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 -2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 -5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 -3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 -5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 -1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 -2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 -1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 - 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 -1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 -4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 -3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 - 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 - 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 - 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 -2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 -5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 -1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 -2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 -1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 -1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 -5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 -5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 -5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 -3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 -4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 -4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 -2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 -5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 -3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 - 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 -5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 -5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 -1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 -2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 -3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 -4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 -5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 -3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 -4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 -1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 -1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 -4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 -1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 - 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 -1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 -1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 -3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 - 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 -5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 -2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 -1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 -1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 -5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 - 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 -4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 - 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 -2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 - 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 -1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 -1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 - 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 -4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 -4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 -1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 -3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 -5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 -5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 -1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 -2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 -1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 -3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 -2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 -3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 -2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 -4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 -4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 -3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 - 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 -3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 - 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 -3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 -4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 -3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 -1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 -5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 - 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 -5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 -1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 - 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 -4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 -4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 - 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 -2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 -2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 -3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 -1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 -4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 -2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 -1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 -1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 -2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 -3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 -1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 -5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 -1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 -4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 -1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 - 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 -1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 -4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 -4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 -2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 -1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 -4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 - 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 -5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 -2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 -3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 -4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 - 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 -5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 -5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 -1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 -4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 -4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 -2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 -3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 -3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 -2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 -1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 -4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 -3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 -3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 -2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 -4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 -5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 -3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 -2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 -3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 -1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 -2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 -3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 -4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 -2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 -2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 -5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 -1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 -2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 -1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 -3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 -4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 -2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 -3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 -3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 -2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 -4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 -2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 -3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 -4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 -5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 -3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 - 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 -1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 -4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 -1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 -4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 -5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 - 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 -5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 -5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 -2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 -3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 -2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 -2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 - 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 -1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 -4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 -3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 -3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 - 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 -2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 - 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 -2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 -4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 -1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 -4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 -1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 -3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 - 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 -3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 -5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 -5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 -3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 -3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 -1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 -2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 -5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 -1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 -1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 -3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 - 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 -1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 -4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 -5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 -2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 -3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 - 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 -1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 -2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 -2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 -5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 -5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 -5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 -2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 -2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 -1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 -4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 -3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 -3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 -4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 -4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 -2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 -2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 -5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 -4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 -5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 -4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 - 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 - 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 -1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 -3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 -4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 -1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 -5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 -2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 -2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 -3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 -5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 -1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 -3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 -5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 -1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 -5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 -2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 -3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 -2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 -3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 -3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 -3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 -4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 - 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 -2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 -4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 -3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 -5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 -1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 -5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 - 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 -1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 - 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 -4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 -1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 -4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 -1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 - 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 -3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 -4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 -5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 - 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 -3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 - 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 -2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 -) - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5prober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5prober.py deleted file mode 100644 index 98f9970..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/big5prober.py +++ /dev/null @@ -1,47 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import Big5DistributionAnalysis -from .mbcssm import BIG5_SM_MODEL - - -class Big5Prober(MultiByteCharSetProber): - def __init__(self): - super(Big5Prober, self).__init__() - self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) - self.distribution_analyzer = Big5DistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "Big5" - - @property - def language(self): - return "Chinese" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/chardistribution.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/chardistribution.py deleted file mode 100644 index c0395f4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/chardistribution.py +++ /dev/null @@ -1,233 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, - EUCTW_TYPICAL_DISTRIBUTION_RATIO) -from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, - EUCKR_TYPICAL_DISTRIBUTION_RATIO) -from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, - GB2312_TYPICAL_DISTRIBUTION_RATIO) -from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, - BIG5_TYPICAL_DISTRIBUTION_RATIO) -from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, - JIS_TYPICAL_DISTRIBUTION_RATIO) - - -class CharDistributionAnalysis(object): - ENOUGH_DATA_THRESHOLD = 1024 - SURE_YES = 0.99 - SURE_NO = 0.01 - MINIMUM_DATA_THRESHOLD = 3 - - def __init__(self): - # Mapping table to get frequency order from char order (get from - # GetOrder()) - self._char_to_freq_order = None - self._table_size = None # Size of above table - # This is a constant value which varies from language to language, - # used in calculating confidence. See - # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html - # for further detail. - self.typical_distribution_ratio = None - self._done = None - self._total_chars = None - self._freq_chars = None - self.reset() - - def reset(self): - """reset analyser, clear any state""" - # If this flag is set to True, detection is done and conclusion has - # been made - self._done = False - self._total_chars = 0 # Total characters encountered - # The number of characters whose frequency order is less than 512 - self._freq_chars = 0 - - def feed(self, char, char_len): - """feed a character with known length""" - if char_len == 2: - # we only care about 2-bytes character in our distribution analysis - order = self.get_order(char) - else: - order = -1 - if order >= 0: - self._total_chars += 1 - # order is valid - if order < self._table_size: - if 512 > self._char_to_freq_order[order]: - self._freq_chars += 1 - - def get_confidence(self): - """return confidence based on existing data""" - # if we didn't receive any character in our consideration range, - # return negative answer - if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: - return self.SURE_NO - - if self._total_chars != self._freq_chars: - r = (self._freq_chars / ((self._total_chars - self._freq_chars) - * self.typical_distribution_ratio)) - if r < self.SURE_YES: - return r - - # normalize confidence (we don't want to be 100% sure) - return self.SURE_YES - - def got_enough_data(self): - # It is not necessary to receive all data to draw conclusion. - # For charset detection, certain amount of data is enough - return self._total_chars > self.ENOUGH_DATA_THRESHOLD - - def get_order(self, byte_str): - # We do not handle characters based on the original encoding string, - # but convert this encoding string to a number, here called order. - # This allows multiple encodings of a language to share one frequency - # table. - return -1 - - -class EUCTWDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCTWDistributionAnalysis, self).__init__() - self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER - self._table_size = EUCTW_TABLE_SIZE - self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-TW encoding, we are interested - # first byte range: 0xc4 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char = byte_str[0] - if first_char >= 0xC4: - return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 - else: - return -1 - - -class EUCKRDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCKRDistributionAnalysis, self).__init__() - self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER - self._table_size = EUCKR_TABLE_SIZE - self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-KR encoding, we are interested - # first byte range: 0xb0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char = byte_str[0] - if first_char >= 0xB0: - return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 - else: - return -1 - - -class GB2312DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(GB2312DistributionAnalysis, self).__init__() - self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER - self._table_size = GB2312_TABLE_SIZE - self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for GB2312 encoding, we are interested - # first byte range: 0xb0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if (first_char >= 0xB0) and (second_char >= 0xA1): - return 94 * (first_char - 0xB0) + second_char - 0xA1 - else: - return -1 - - -class Big5DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(Big5DistributionAnalysis, self).__init__() - self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER - self._table_size = BIG5_TABLE_SIZE - self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for big5 encoding, we are interested - # first byte range: 0xa4 -- 0xfe - # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if first_char >= 0xA4: - if second_char >= 0xA1: - return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 - else: - return 157 * (first_char - 0xA4) + second_char - 0x40 - else: - return -1 - - -class SJISDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(SJISDistributionAnalysis, self).__init__() - self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER - self._table_size = JIS_TABLE_SIZE - self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for sjis encoding, we are interested - # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe - # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if (first_char >= 0x81) and (first_char <= 0x9F): - order = 188 * (first_char - 0x81) - elif (first_char >= 0xE0) and (first_char <= 0xEF): - order = 188 * (first_char - 0xE0 + 31) - else: - return -1 - order = order + second_char - 0x40 - if second_char > 0x7F: - order = -1 - return order - - -class EUCJPDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCJPDistributionAnalysis, self).__init__() - self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER - self._table_size = JIS_TABLE_SIZE - self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-JP encoding, we are interested - # first byte range: 0xa0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - char = byte_str[0] - if char >= 0xA0: - return 94 * (char - 0xA1) + byte_str[1] - 0xa1 - else: - return -1 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetgroupprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetgroupprober.py deleted file mode 100644 index 5812cef..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetgroupprober.py +++ /dev/null @@ -1,107 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import ProbingState -from .charsetprober import CharSetProber - - -class CharSetGroupProber(CharSetProber): - def __init__(self, lang_filter=None): - super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) - self._active_num = 0 - self.probers = [] - self._best_guess_prober = None - - def reset(self): - super(CharSetGroupProber, self).reset() - self._active_num = 0 - for prober in self.probers: - if prober: - prober.reset() - prober.active = True - self._active_num += 1 - self._best_guess_prober = None - - @property - def charset_name(self): - if not self._best_guess_prober: - self.get_confidence() - if not self._best_guess_prober: - return None - return self._best_guess_prober.charset_name - - @property - def language(self): - if not self._best_guess_prober: - self.get_confidence() - if not self._best_guess_prober: - return None - return self._best_guess_prober.language - - def feed(self, byte_str): - for prober in self.probers: - if not prober: - continue - if not prober.active: - continue - state = prober.feed(byte_str) - if not state: - continue - if state == ProbingState.FOUND_IT: - self._best_guess_prober = prober - self._state = ProbingState.FOUND_IT - return self.state - elif state == ProbingState.NOT_ME: - prober.active = False - self._active_num -= 1 - if self._active_num <= 0: - self._state = ProbingState.NOT_ME - return self.state - return self.state - - def get_confidence(self): - state = self.state - if state == ProbingState.FOUND_IT: - return 0.99 - elif state == ProbingState.NOT_ME: - return 0.01 - best_conf = 0.0 - self._best_guess_prober = None - for prober in self.probers: - if not prober: - continue - if not prober.active: - self.logger.debug('%s not active', prober.charset_name) - continue - conf = prober.get_confidence() - self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) - if best_conf < conf: - best_conf = conf - self._best_guess_prober = prober - if not self._best_guess_prober: - return 0.0 - return best_conf diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetprober.py deleted file mode 100644 index eac4e59..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/charsetprober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import logging -import re - -from .enums import ProbingState - - -class CharSetProber(object): - - SHORTCUT_THRESHOLD = 0.95 - - def __init__(self, lang_filter=None): - self._state = None - self.lang_filter = lang_filter - self.logger = logging.getLogger(__name__) - - def reset(self): - self._state = ProbingState.DETECTING - - @property - def charset_name(self): - return None - - def feed(self, buf): - pass - - @property - def state(self): - return self._state - - def get_confidence(self): - return 0.0 - - @staticmethod - def filter_high_byte_only(buf): - buf = re.sub(b'([\x00-\x7F])+', b' ', buf) - return buf - - @staticmethod - def filter_international_words(buf): - """ - We define three types of bytes: - alphabet: english alphabets [a-zA-Z] - international: international characters [\x80-\xFF] - marker: everything else [^a-zA-Z\x80-\xFF] - - The input buffer can be thought to contain a series of words delimited - by markers. This function works to filter all words that contain at - least one international character. All contiguous sequences of markers - are replaced by a single space ascii character. - - This filter applies to all scripts which do not use English characters. - """ - filtered = bytearray() - - # This regex expression filters out only words that have at-least one - # international character. The word may include one marker character at - # the end. - words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', - buf) - - for word in words: - filtered.extend(word[:-1]) - - # If the last character in the word is a marker, replace it with a - # space as markers shouldn't affect our analysis (they are used - # similarly across all languages and may thus have similar - # frequencies). - last_char = word[-1:] - if not last_char.isalpha() and last_char < b'\x80': - last_char = b' ' - filtered.extend(last_char) - - return filtered - - @staticmethod - def filter_with_english_letters(buf): - """ - Returns a copy of ``buf`` that retains only the sequences of English - alphabet and high byte characters that are not between <> characters. - Also retains English alphabet and high byte characters immediately - before occurrences of >. - - This filter can be applied to all scripts which contain both English - characters and extended ASCII characters, but is currently only used by - ``Latin1Prober``. - """ - filtered = bytearray() - in_tag = False - prev = 0 - - for curr in range(len(buf)): - # Slice here to get bytes instead of an int with Python 3 - buf_char = buf[curr:curr + 1] - # Check if we're coming out of or entering an HTML tag - if buf_char == b'>': - in_tag = False - elif buf_char == b'<': - in_tag = True - - # If current character is not extended-ASCII and not alphabetic... - if buf_char < b'\x80' and not buf_char.isalpha(): - # ...and we're not in a tag - if curr > prev and not in_tag: - # Keep everything after last non-extended-ASCII, - # non-alphabetic character - filtered.extend(buf[prev:curr]) - # Output a space to delimit stretch we kept - filtered.extend(b' ') - prev = curr + 1 - - # If we're not in a tag... - if not in_tag: - # Keep everything after last non-extended-ASCII, non-alphabetic - # character - filtered.extend(buf[prev:]) - - return filtered diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/chardetect.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/chardetect.py deleted file mode 100644 index 6d6f93a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cli/chardetect.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Script which takes one or more file paths and reports on their detected -encodings - -Example:: - - % chardetect somefile someotherfile - somefile: windows-1252 with confidence 0.5 - someotherfile: ascii with confidence 1.0 - -If no paths are provided, it takes its input from stdin. - -""" - -from __future__ import absolute_import, print_function, unicode_literals - -import argparse -import sys - -from pip._vendor.chardet import __version__ -from pip._vendor.chardet.compat import PY2 -from pip._vendor.chardet.universaldetector import UniversalDetector - - -def description_of(lines, name='stdin'): - """ - Return a string describing the probable encoding of a file or - list of strings. - - :param lines: The lines to get the encoding of. - :type lines: Iterable of bytes - :param name: Name of file or collection of lines - :type name: str - """ - u = UniversalDetector() - for line in lines: - line = bytearray(line) - u.feed(line) - # shortcut out of the loop to save reading further - particularly useful if we read a BOM. - if u.done: - break - u.close() - result = u.result - if PY2: - name = name.decode(sys.getfilesystemencoding(), 'ignore') - if result['encoding']: - return '{}: {} with confidence {}'.format(name, result['encoding'], - result['confidence']) - else: - return '{}: no result'.format(name) - - -def main(argv=None): - """ - Handles command line arguments and gets things started. - - :param argv: List of arguments, as if specified on the command-line. - If None, ``sys.argv[1:]`` is used instead. - :type argv: list of str - """ - # Get command line arguments - parser = argparse.ArgumentParser( - description="Takes one or more file paths and reports their detected \ - encodings") - parser.add_argument('input', - help='File whose encoding we would like to determine. \ - (default: stdin)', - type=argparse.FileType('rb'), nargs='*', - default=[sys.stdin if PY2 else sys.stdin.buffer]) - parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) - args = parser.parse_args(argv) - - for f in args.input: - if f.isatty(): - print("You are running chardetect interactively. Press " + - "CTRL-D twice at the start of a blank line to signal the " + - "end of your input. If you want help, run chardetect " + - "--help\n", file=sys.stderr) - print(description_of(f, f.name)) - - -if __name__ == '__main__': - main() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/codingstatemachine.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/codingstatemachine.py deleted file mode 100644 index 68fba44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/codingstatemachine.py +++ /dev/null @@ -1,88 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import logging - -from .enums import MachineState - - -class CodingStateMachine(object): - """ - A state machine to verify a byte sequence for a particular encoding. For - each byte the detector receives, it will feed that byte to every active - state machine available, one byte at a time. The state machine changes its - state based on its previous state and the byte it receives. There are 3 - states in a state machine that are of interest to an auto-detector: - - START state: This is the state to start with, or a legal byte sequence - (i.e. a valid code point) for character has been identified. - - ME state: This indicates that the state machine identified a byte sequence - that is specific to the charset it is designed for and that - there is no other possible encoding which can contain this byte - sequence. This will to lead to an immediate positive answer for - the detector. - - ERROR state: This indicates the state machine identified an illegal byte - sequence for that encoding. This will lead to an immediate - negative answer for this encoding. Detector will exclude this - encoding from consideration from here on. - """ - def __init__(self, sm): - self._model = sm - self._curr_byte_pos = 0 - self._curr_char_len = 0 - self._curr_state = None - self.logger = logging.getLogger(__name__) - self.reset() - - def reset(self): - self._curr_state = MachineState.START - - def next_state(self, c): - # for each byte we get its class - # if it is first byte, we also get byte length - byte_class = self._model['class_table'][c] - if self._curr_state == MachineState.START: - self._curr_byte_pos = 0 - self._curr_char_len = self._model['char_len_table'][byte_class] - # from byte's class and state_table, we get its next state - curr_state = (self._curr_state * self._model['class_factor'] - + byte_class) - self._curr_state = self._model['state_table'][curr_state] - self._curr_byte_pos += 1 - return self._curr_state - - def get_current_charlen(self): - return self._curr_char_len - - def get_coding_state_machine(self): - return self._model['name'] - - @property - def language(self): - return self._model['language'] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/compat.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/compat.py deleted file mode 100644 index 8941572..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/compat.py +++ /dev/null @@ -1,36 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# Contributor(s): -# Dan Blanchard -# Ian Cordasco -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import sys - - -if sys.version_info < (3, 0): - PY2 = True - PY3 = False - string_types = (str, unicode) - text_type = unicode - iteritems = dict.iteritems -else: - PY2 = False - PY3 = True - string_types = (bytes, str) - text_type = str - iteritems = dict.items diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cp949prober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cp949prober.py deleted file mode 100644 index efd793a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/cp949prober.py +++ /dev/null @@ -1,49 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .chardistribution import EUCKRDistributionAnalysis -from .codingstatemachine import CodingStateMachine -from .mbcharsetprober import MultiByteCharSetProber -from .mbcssm import CP949_SM_MODEL - - -class CP949Prober(MultiByteCharSetProber): - def __init__(self): - super(CP949Prober, self).__init__() - self.coding_sm = CodingStateMachine(CP949_SM_MODEL) - # NOTE: CP949 is a superset of EUC-KR, so the distribution should be - # not different. - self.distribution_analyzer = EUCKRDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "CP949" - - @property - def language(self): - return "Korean" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/enums.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/enums.py deleted file mode 100644 index 0451207..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/enums.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -All of the Enums that are used throughout the chardet package. - -:author: Dan Blanchard (dan.blanchard@gmail.com) -""" - - -class InputState(object): - """ - This enum represents the different states a universal detector can be in. - """ - PURE_ASCII = 0 - ESC_ASCII = 1 - HIGH_BYTE = 2 - - -class LanguageFilter(object): - """ - This enum represents the different language filters we can apply to a - ``UniversalDetector``. - """ - CHINESE_SIMPLIFIED = 0x01 - CHINESE_TRADITIONAL = 0x02 - JAPANESE = 0x04 - KOREAN = 0x08 - NON_CJK = 0x10 - ALL = 0x1F - CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL - CJK = CHINESE | JAPANESE | KOREAN - - -class ProbingState(object): - """ - This enum represents the different states a prober can be in. - """ - DETECTING = 0 - FOUND_IT = 1 - NOT_ME = 2 - - -class MachineState(object): - """ - This enum represents the different states a state machine can be in. - """ - START = 0 - ERROR = 1 - ITS_ME = 2 - - -class SequenceLikelihood(object): - """ - This enum represents the likelihood of a character following the previous one. - """ - NEGATIVE = 0 - UNLIKELY = 1 - LIKELY = 2 - POSITIVE = 3 - - @classmethod - def get_num_categories(cls): - """:returns: The number of likelihood categories in the enum.""" - return 4 - - -class CharacterCategory(object): - """ - This enum represents the different categories language models for - ``SingleByteCharsetProber`` put characters into. - - Anything less than CONTROL is considered a letter. - """ - UNDEFINED = 255 - LINE_BREAK = 254 - SYMBOL = 253 - DIGIT = 252 - CONTROL = 251 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escprober.py deleted file mode 100644 index c70493f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escprober.py +++ /dev/null @@ -1,101 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .codingstatemachine import CodingStateMachine -from .enums import LanguageFilter, ProbingState, MachineState -from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, - ISO2022KR_SM_MODEL) - - -class EscCharSetProber(CharSetProber): - """ - This CharSetProber uses a "code scheme" approach for detecting encodings, - whereby easily recognizable escape or shift sequences are relied on to - identify these encodings. - """ - - def __init__(self, lang_filter=None): - super(EscCharSetProber, self).__init__(lang_filter=lang_filter) - self.coding_sm = [] - if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: - self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) - self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) - if self.lang_filter & LanguageFilter.JAPANESE: - self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) - if self.lang_filter & LanguageFilter.KOREAN: - self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) - self.active_sm_count = None - self._detected_charset = None - self._detected_language = None - self._state = None - self.reset() - - def reset(self): - super(EscCharSetProber, self).reset() - for coding_sm in self.coding_sm: - if not coding_sm: - continue - coding_sm.active = True - coding_sm.reset() - self.active_sm_count = len(self.coding_sm) - self._detected_charset = None - self._detected_language = None - - @property - def charset_name(self): - return self._detected_charset - - @property - def language(self): - return self._detected_language - - def get_confidence(self): - if self._detected_charset: - return 0.99 - else: - return 0.00 - - def feed(self, byte_str): - for c in byte_str: - for coding_sm in self.coding_sm: - if not coding_sm or not coding_sm.active: - continue - coding_state = coding_sm.next_state(c) - if coding_state == MachineState.ERROR: - coding_sm.active = False - self.active_sm_count -= 1 - if self.active_sm_count <= 0: - self._state = ProbingState.NOT_ME - return self.state - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - self._detected_charset = coding_sm.get_coding_state_machine() - self._detected_language = coding_sm.language - return self.state - - return self.state diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escsm.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escsm.py deleted file mode 100644 index 0069523..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/escsm.py +++ /dev/null @@ -1,246 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import MachineState - -HZ_CLS = ( -1,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,0,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,4,0,5,2,0, # 78 - 7f -1,1,1,1,1,1,1,1, # 80 - 87 -1,1,1,1,1,1,1,1, # 88 - 8f -1,1,1,1,1,1,1,1, # 90 - 97 -1,1,1,1,1,1,1,1, # 98 - 9f -1,1,1,1,1,1,1,1, # a0 - a7 -1,1,1,1,1,1,1,1, # a8 - af -1,1,1,1,1,1,1,1, # b0 - b7 -1,1,1,1,1,1,1,1, # b8 - bf -1,1,1,1,1,1,1,1, # c0 - c7 -1,1,1,1,1,1,1,1, # c8 - cf -1,1,1,1,1,1,1,1, # d0 - d7 -1,1,1,1,1,1,1,1, # d8 - df -1,1,1,1,1,1,1,1, # e0 - e7 -1,1,1,1,1,1,1,1, # e8 - ef -1,1,1,1,1,1,1,1, # f0 - f7 -1,1,1,1,1,1,1,1, # f8 - ff -) - -HZ_ST = ( -MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 - 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f - 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 - 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f -) - -HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) - -HZ_SM_MODEL = {'class_table': HZ_CLS, - 'class_factor': 6, - 'state_table': HZ_ST, - 'char_len_table': HZ_CHAR_LEN_TABLE, - 'name': "HZ-GB-2312", - 'language': 'Chinese'} - -ISO2022CN_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,3,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,4,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022CN_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 - 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f -) - -ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) - -ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, - 'class_factor': 9, - 'state_table': ISO2022CN_ST, - 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, - 'name': "ISO-2022-CN", - 'language': 'Chinese'} - -ISO2022JP_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,2,2, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,7,0,0,0, # 20 - 27 -3,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -6,0,4,0,8,0,0,0, # 40 - 47 -0,9,5,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022JP_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 -) - -ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - -ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, - 'class_factor': 10, - 'state_table': ISO2022JP_ST, - 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, - 'name': "ISO-2022-JP", - 'language': 'Japanese'} - -ISO2022KR_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,3,0,0,0, # 20 - 27 -0,4,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,5,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022KR_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 -) - -ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) - -ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, - 'class_factor': 6, - 'state_table': ISO2022KR_ST, - 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, - 'name': "ISO-2022-KR", - 'language': 'Korean'} - - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/eucjpprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/eucjpprober.py deleted file mode 100644 index 20ce8f7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/eucjpprober.py +++ /dev/null @@ -1,92 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import ProbingState, MachineState -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCJPDistributionAnalysis -from .jpcntx import EUCJPContextAnalysis -from .mbcssm import EUCJP_SM_MODEL - - -class EUCJPProber(MultiByteCharSetProber): - def __init__(self): - super(EUCJPProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) - self.distribution_analyzer = EUCJPDistributionAnalysis() - self.context_analyzer = EUCJPContextAnalysis() - self.reset() - - def reset(self): - super(EUCJPProber, self).reset() - self.context_analyzer.reset() - - @property - def charset_name(self): - return "EUC-JP" - - @property - def language(self): - return "Japanese" - - def feed(self, byte_str): - for i in range(len(byte_str)): - # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.context_analyzer.feed(self._last_char, char_len) - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.context_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - context_conf = self.context_analyzer.get_confidence() - distrib_conf = self.distribution_analyzer.get_confidence() - return max(context_conf, distrib_conf) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrfreq.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrfreq.py deleted file mode 100644 index b68078c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrfreq.py +++ /dev/null @@ -1,195 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Sampling from about 20M text materials include literature and computer technology - -# 128 --> 0.79 -# 256 --> 0.92 -# 512 --> 0.986 -# 1024 --> 0.99944 -# 2048 --> 0.99999 -# -# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 -# Random Distribution Ration = 512 / (2350-512) = 0.279. -# -# Typical Distribution Ratio - -EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 - -EUCKR_TABLE_SIZE = 2352 - -# Char to FreqOrder table , -EUCKR_CHAR_TO_FREQ_ORDER = ( - 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, -1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, -1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, - 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, - 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, - 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, -1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, - 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, - 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, -1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, -1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, -1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, -1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, -1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, - 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, -1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, -1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, -1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, -1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, - 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, -1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, - 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, - 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, -1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, - 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, -1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, - 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, - 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, -1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, -1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, -1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, -1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, - 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, -1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, - 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, - 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, -1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, -1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, -1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, -1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, -1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, -1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, - 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, - 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, - 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, -1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, - 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, -1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, - 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, - 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, -2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, - 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, - 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, -2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, -2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, -2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, - 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, - 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, -2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, - 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, -1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, -2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, -1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, -2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, -2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, -1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, - 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, -2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, -2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, - 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, - 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, -2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, -1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, -2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, -2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, -2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, -2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, -2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, -2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, -1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, -2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, -2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, -2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, -2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, -2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, -1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, -1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, -2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, -1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, -2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, -1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, - 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, -2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, - 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, -2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, - 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, -2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, -2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, - 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, -2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, -1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, - 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, -1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, -2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, -1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, -2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, - 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, -2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, -1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, -2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, -1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, -2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, -1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, - 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, -2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, -2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, - 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, - 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, -1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, -1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, - 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, -2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, -2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, - 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, - 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, - 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, -2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, - 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, - 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, -2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, -2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, - 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, -2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, -1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, - 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, -2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, -2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, -2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, - 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, - 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, - 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, -2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, -2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, -2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, -1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, -2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, - 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 -) - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrprober.py deleted file mode 100644 index 345a060..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euckrprober.py +++ /dev/null @@ -1,47 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCKRDistributionAnalysis -from .mbcssm import EUCKR_SM_MODEL - - -class EUCKRProber(MultiByteCharSetProber): - def __init__(self): - super(EUCKRProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) - self.distribution_analyzer = EUCKRDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "EUC-KR" - - @property - def language(self): - return "Korean" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwfreq.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwfreq.py deleted file mode 100644 index ed7a995..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwfreq.py +++ /dev/null @@ -1,387 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# EUCTW frequency table -# Converted from big5 work -# by Taiwan's Mandarin Promotion Council -# - -# 128 --> 0.42261 -# 256 --> 0.57851 -# 512 --> 0.74851 -# 1024 --> 0.89384 -# 2048 --> 0.97583 -# -# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 -# Random Distribution Ration = 512/(5401-512)=0.105 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR - -EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 - -# Char to FreqOrder table , -EUCTW_TABLE_SIZE = 5376 - -EUCTW_CHAR_TO_FREQ_ORDER = ( - 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 -3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 -1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 - 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 -3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 -4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 -7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 - 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 - 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 - 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 -2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 -1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 -3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 - 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 -3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 -2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 - 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 -3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 -1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 -7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 - 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 -7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 -1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 - 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 - 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 -3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 -3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 - 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 -2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 -2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 - 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 - 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 -3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 -1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 -1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 -1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 -2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 - 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 -4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 -1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 -7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 -2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 - 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 - 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 - 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 - 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 -7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 - 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 -1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 - 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 - 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 -7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 -1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 - 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 -3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 -4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 -3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 - 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 - 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 -1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 -4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 -3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 -3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 -2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 -7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 -3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 -7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 -1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 -2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 -1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 - 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 -1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 -4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 -3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 - 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 - 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 - 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 -2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 -7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 -1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 -2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 -1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 -1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 -7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 -7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 -7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 -3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 -4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 -1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 -7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 -2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 -7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 -3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 -3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 -7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 -2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 -7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 - 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 -4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 -2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 -7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 -3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 -2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 -2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 - 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 -2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 -1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 -1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 -2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 -1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 -7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 -7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 -2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 -4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 -1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 -7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 - 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 -4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 - 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 -2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 - 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 -1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 -1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 - 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 -3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 -3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 -1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 -3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 -7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 -7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 -1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 -2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 -1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 -3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 -2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 -3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 -2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 -4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 -4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 -3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 - 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 -3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 - 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 -3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 -3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 -3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 -1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 -7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 - 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 -7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 -1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 - 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 -4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 -3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 - 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 -2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 -2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 -3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 -1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 -4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 -2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 -1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 -1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 -2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 -3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 -1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 -7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 -1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 -4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 -1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 - 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 -1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 -3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 -3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 -2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 -1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 -4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 - 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 -7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 -2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 -3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 -4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 - 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 -7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 -7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 -1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 -4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 -3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 -2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 -3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 -3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 -2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 -1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 -4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 -3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 -3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 -2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 -4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 -7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 -3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 -2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 -3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 -1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 -2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 -3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 -4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 -2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 -2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 -7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 -1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 -2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 -1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 -3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 -4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 -2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 -3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 -3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 -2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 -4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 -2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 -3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 -4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 -7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 -3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 - 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 -1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 -4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 -1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 -4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 -7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 - 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 -7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 -2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 -1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 -1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 -3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 - 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 - 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 - 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 -3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 -2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 - 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 -7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 -1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 -3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 -7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 -1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 -7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 -4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 -1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 -2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 -2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 -4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 - 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 - 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 -3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 -3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 -1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 -2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 -7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 -1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 -1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 -3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 - 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 -1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 -4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 -7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 -2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 -3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 - 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 -1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 -2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 -2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 -7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 -7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 -7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 -2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 -2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 -1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 -4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 -3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 -3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 -4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 -4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 -2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 -2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 -7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 -4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 -7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 -2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 -1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 -3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 -4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 -2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 - 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 -2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 -1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 -2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 -2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 -4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 -7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 -1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 -3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 -7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 -1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 -8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 -2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 -8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 -2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 -2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 -8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 -8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 -8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 - 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 -8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 -4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 -3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 -8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 -1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 -8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 - 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 -1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 - 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 -4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 -1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 -4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 -1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 - 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 -3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 -4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 -8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 - 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 -3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 - 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 -2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 -) - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwprober.py deleted file mode 100644 index 35669cc..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/euctwprober.py +++ /dev/null @@ -1,46 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCTWDistributionAnalysis -from .mbcssm import EUCTW_SM_MODEL - -class EUCTWProber(MultiByteCharSetProber): - def __init__(self): - super(EUCTWProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) - self.distribution_analyzer = EUCTWDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "EUC-TW" - - @property - def language(self): - return "Taiwan" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312freq.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312freq.py deleted file mode 100644 index 697837b..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312freq.py +++ /dev/null @@ -1,283 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# GB2312 most frequently used character table -# -# Char to FreqOrder table , from hz6763 - -# 512 --> 0.79 -- 0.79 -# 1024 --> 0.92 -- 0.13 -# 2048 --> 0.98 -- 0.06 -# 6768 --> 1.00 -- 0.02 -# -# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 -# Random Distribution Ration = 512 / (3755 - 512) = 0.157 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR - -GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 - -GB2312_TABLE_SIZE = 3760 - -GB2312_CHAR_TO_FREQ_ORDER = ( -1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, -2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, -2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, - 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, -1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, -1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, - 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, -1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, -2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, -3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, - 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, -1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, - 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, -2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, - 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, -2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, -1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, -3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, - 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, -1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, - 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, -2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, -1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, -3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, -1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, -2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, -1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, - 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, -3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, -3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, - 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, -3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, - 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, -1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, -3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, -2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, -1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, - 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, -1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, -4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, - 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, -3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, -3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, - 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, -1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, -2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, -1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, -1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, - 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, -3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, -3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, -4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, - 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, -3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, -1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, -1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, -4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, - 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, - 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, -3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, -1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, - 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, -1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, -2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, - 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, - 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, - 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, -3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, -4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, -3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, - 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, -2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, -2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, -2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, - 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, -2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, - 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, - 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, - 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, -3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, -2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, -2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, -1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, - 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, -2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, - 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, - 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, -1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, -1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, - 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, - 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, -1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, -2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, -3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, -2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, -2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, -2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, -3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, -1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, -1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, -2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, -1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, -3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, -1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, -1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, -3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, - 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, -2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, -1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, -4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, -1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, -1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, -3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, -1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, - 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, - 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, -1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, - 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, -1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, -1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, - 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, -3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, -4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, -3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, -2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, -2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, -1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, -3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, -2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, -1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, -1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, - 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, -2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, -2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, -3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, -4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, -3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, - 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, -3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, -2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, -1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, - 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, - 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, -3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, -4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, -2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, -1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, -1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, - 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, -1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, -3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, - 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, - 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, -1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, - 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, -1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, - 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, -2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, - 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, -2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, -2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, -1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, -1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, -2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, - 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, -1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, -1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, -2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, -2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, -3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, -1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, -4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, - 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, - 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, -3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, -1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, - 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, -3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, -1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, -4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, -1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, -2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, -1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, - 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, -1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, -3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, - 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, -2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, - 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, -1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, -1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, -1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, -3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, -2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, -3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, -3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, -3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, - 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, -2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, - 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, -2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, - 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, -1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, - 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, - 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, -1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, -3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, -3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, -1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, -1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, -3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, -2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, -2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, -1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, -3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, - 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, -4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, -1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, -2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, -3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, -3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, -1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, - 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, - 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, -2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, - 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, -1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, - 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, -1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, -1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, -1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, -1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, -1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, - 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, - 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 -) - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312prober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312prober.py deleted file mode 100644 index 8446d2d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312prober.py +++ /dev/null @@ -1,46 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import GB2312DistributionAnalysis -from .mbcssm import GB2312_SM_MODEL - -class GB2312Prober(MultiByteCharSetProber): - def __init__(self): - super(GB2312Prober, self).__init__() - self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) - self.distribution_analyzer = GB2312DistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "GB2312" - - @property - def language(self): - return "Chinese" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/hebrewprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/hebrewprober.py deleted file mode 100644 index b0e1bf4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/hebrewprober.py +++ /dev/null @@ -1,292 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Shy Shalom -# Portions created by the Initial Developer are Copyright (C) 2005 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState - -# This prober doesn't actually recognize a language or a charset. -# It is a helper prober for the use of the Hebrew model probers - -### General ideas of the Hebrew charset recognition ### -# -# Four main charsets exist in Hebrew: -# "ISO-8859-8" - Visual Hebrew -# "windows-1255" - Logical Hebrew -# "ISO-8859-8-I" - Logical Hebrew -# "x-mac-hebrew" - ?? Logical Hebrew ?? -# -# Both "ISO" charsets use a completely identical set of code points, whereas -# "windows-1255" and "x-mac-hebrew" are two different proper supersets of -# these code points. windows-1255 defines additional characters in the range -# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific -# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. -# x-mac-hebrew defines similar additional code points but with a different -# mapping. -# -# As far as an average Hebrew text with no diacritics is concerned, all four -# charsets are identical with respect to code points. Meaning that for the -# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters -# (including final letters). -# -# The dominant difference between these charsets is their directionality. -# "Visual" directionality means that the text is ordered as if the renderer is -# not aware of a BIDI rendering algorithm. The renderer sees the text and -# draws it from left to right. The text itself when ordered naturally is read -# backwards. A buffer of Visual Hebrew generally looks like so: -# "[last word of first line spelled backwards] [whole line ordered backwards -# and spelled backwards] [first word of first line spelled backwards] -# [end of line] [last word of second line] ... etc' " -# adding punctuation marks, numbers and English text to visual text is -# naturally also "visual" and from left to right. -# -# "Logical" directionality means the text is ordered "naturally" according to -# the order it is read. It is the responsibility of the renderer to display -# the text from right to left. A BIDI algorithm is used to place general -# punctuation marks, numbers and English text in the text. -# -# Texts in x-mac-hebrew are almost impossible to find on the Internet. From -# what little evidence I could find, it seems that its general directionality -# is Logical. -# -# To sum up all of the above, the Hebrew probing mechanism knows about two -# charsets: -# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are -# backwards while line order is natural. For charset recognition purposes -# the line order is unimportant (In fact, for this implementation, even -# word order is unimportant). -# Logical Hebrew - "windows-1255" - normal, naturally ordered text. -# -# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be -# specifically identified. -# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew -# that contain special punctuation marks or diacritics is displayed with -# some unconverted characters showing as question marks. This problem might -# be corrected using another model prober for x-mac-hebrew. Due to the fact -# that x-mac-hebrew texts are so rare, writing another model prober isn't -# worth the effort and performance hit. -# -#### The Prober #### -# -# The prober is divided between two SBCharSetProbers and a HebrewProber, -# all of which are managed, created, fed data, inquired and deleted by the -# SBCSGroupProber. The two SBCharSetProbers identify that the text is in -# fact some kind of Hebrew, Logical or Visual. The final decision about which -# one is it is made by the HebrewProber by combining final-letter scores -# with the scores of the two SBCharSetProbers to produce a final answer. -# -# The SBCSGroupProber is responsible for stripping the original text of HTML -# tags, English characters, numbers, low-ASCII punctuation characters, spaces -# and new lines. It reduces any sequence of such characters to a single space. -# The buffer fed to each prober in the SBCS group prober is pure text in -# high-ASCII. -# The two SBCharSetProbers (model probers) share the same language model: -# Win1255Model. -# The first SBCharSetProber uses the model normally as any other -# SBCharSetProber does, to recognize windows-1255, upon which this model was -# built. The second SBCharSetProber is told to make the pair-of-letter -# lookup in the language model backwards. This in practice exactly simulates -# a visual Hebrew model using the windows-1255 logical Hebrew model. -# -# The HebrewProber is not using any language model. All it does is look for -# final-letter evidence suggesting the text is either logical Hebrew or visual -# Hebrew. Disjointed from the model probers, the results of the HebrewProber -# alone are meaningless. HebrewProber always returns 0.00 as confidence -# since it never identifies a charset by itself. Instead, the pointer to the -# HebrewProber is passed to the model probers as a helper "Name Prober". -# When the Group prober receives a positive identification from any prober, -# it asks for the name of the charset identified. If the prober queried is a -# Hebrew model prober, the model prober forwards the call to the -# HebrewProber to make the final decision. In the HebrewProber, the -# decision is made according to the final-letters scores maintained and Both -# model probers scores. The answer is returned in the form of the name of the -# charset identified, either "windows-1255" or "ISO-8859-8". - -class HebrewProber(CharSetProber): - # windows-1255 / ISO-8859-8 code points of interest - FINAL_KAF = 0xea - NORMAL_KAF = 0xeb - FINAL_MEM = 0xed - NORMAL_MEM = 0xee - FINAL_NUN = 0xef - NORMAL_NUN = 0xf0 - FINAL_PE = 0xf3 - NORMAL_PE = 0xf4 - FINAL_TSADI = 0xf5 - NORMAL_TSADI = 0xf6 - - # Minimum Visual vs Logical final letter score difference. - # If the difference is below this, don't rely solely on the final letter score - # distance. - MIN_FINAL_CHAR_DISTANCE = 5 - - # Minimum Visual vs Logical model score difference. - # If the difference is below this, don't rely at all on the model score - # distance. - MIN_MODEL_DISTANCE = 0.01 - - VISUAL_HEBREW_NAME = "ISO-8859-8" - LOGICAL_HEBREW_NAME = "windows-1255" - - def __init__(self): - super(HebrewProber, self).__init__() - self._final_char_logical_score = None - self._final_char_visual_score = None - self._prev = None - self._before_prev = None - self._logical_prober = None - self._visual_prober = None - self.reset() - - def reset(self): - self._final_char_logical_score = 0 - self._final_char_visual_score = 0 - # The two last characters seen in the previous buffer, - # mPrev and mBeforePrev are initialized to space in order to simulate - # a word delimiter at the beginning of the data - self._prev = ' ' - self._before_prev = ' ' - # These probers are owned by the group prober. - - def set_model_probers(self, logicalProber, visualProber): - self._logical_prober = logicalProber - self._visual_prober = visualProber - - def is_final(self, c): - return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, - self.FINAL_PE, self.FINAL_TSADI] - - def is_non_final(self, c): - # The normal Tsadi is not a good Non-Final letter due to words like - # 'lechotet' (to chat) containing an apostrophe after the tsadi. This - # apostrophe is converted to a space in FilterWithoutEnglishLetters - # causing the Non-Final tsadi to appear at an end of a word even - # though this is not the case in the original text. - # The letters Pe and Kaf rarely display a related behavior of not being - # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' - # for example legally end with a Non-Final Pe or Kaf. However, the - # benefit of these letters as Non-Final letters outweighs the damage - # since these words are quite rare. - return c in [self.NORMAL_KAF, self.NORMAL_MEM, - self.NORMAL_NUN, self.NORMAL_PE] - - def feed(self, byte_str): - # Final letter analysis for logical-visual decision. - # Look for evidence that the received buffer is either logical Hebrew - # or visual Hebrew. - # The following cases are checked: - # 1) A word longer than 1 letter, ending with a final letter. This is - # an indication that the text is laid out "naturally" since the - # final letter really appears at the end. +1 for logical score. - # 2) A word longer than 1 letter, ending with a Non-Final letter. In - # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, - # should not end with the Non-Final form of that letter. Exceptions - # to this rule are mentioned above in isNonFinal(). This is an - # indication that the text is laid out backwards. +1 for visual - # score - # 3) A word longer than 1 letter, starting with a final letter. Final - # letters should not appear at the beginning of a word. This is an - # indication that the text is laid out backwards. +1 for visual - # score. - # - # The visual score and logical score are accumulated throughout the - # text and are finally checked against each other in GetCharSetName(). - # No checking for final letters in the middle of words is done since - # that case is not an indication for either Logical or Visual text. - # - # We automatically filter out all 7-bit characters (replace them with - # spaces) so the word boundary detection works properly. [MAP] - - if self.state == ProbingState.NOT_ME: - # Both model probers say it's not them. No reason to continue. - return ProbingState.NOT_ME - - byte_str = self.filter_high_byte_only(byte_str) - - for cur in byte_str: - if cur == ' ': - # We stand on a space - a word just ended - if self._before_prev != ' ': - # next-to-last char was not a space so self._prev is not a - # 1 letter word - if self.is_final(self._prev): - # case (1) [-2:not space][-1:final letter][cur:space] - self._final_char_logical_score += 1 - elif self.is_non_final(self._prev): - # case (2) [-2:not space][-1:Non-Final letter][ - # cur:space] - self._final_char_visual_score += 1 - else: - # Not standing on a space - if ((self._before_prev == ' ') and - (self.is_final(self._prev)) and (cur != ' ')): - # case (3) [-2:space][-1:final letter][cur:not space] - self._final_char_visual_score += 1 - self._before_prev = self._prev - self._prev = cur - - # Forever detecting, till the end or until both model probers return - # ProbingState.NOT_ME (handled above) - return ProbingState.DETECTING - - @property - def charset_name(self): - # Make the decision: is it Logical or Visual? - # If the final letter score distance is dominant enough, rely on it. - finalsub = self._final_char_logical_score - self._final_char_visual_score - if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: - return self.LOGICAL_HEBREW_NAME - if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: - return self.VISUAL_HEBREW_NAME - - # It's not dominant enough, try to rely on the model scores instead. - modelsub = (self._logical_prober.get_confidence() - - self._visual_prober.get_confidence()) - if modelsub > self.MIN_MODEL_DISTANCE: - return self.LOGICAL_HEBREW_NAME - if modelsub < -self.MIN_MODEL_DISTANCE: - return self.VISUAL_HEBREW_NAME - - # Still no good, back to final letter distance, maybe it'll save the - # day. - if finalsub < 0.0: - return self.VISUAL_HEBREW_NAME - - # (finalsub > 0 - Logical) or (don't know what to do) default to - # Logical. - return self.LOGICAL_HEBREW_NAME - - @property - def language(self): - return 'Hebrew' - - @property - def state(self): - # Remain active as long as any of the model probers are active. - if (self._logical_prober.state == ProbingState.NOT_ME) and \ - (self._visual_prober.state == ProbingState.NOT_ME): - return ProbingState.NOT_ME - return ProbingState.DETECTING diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jisfreq.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jisfreq.py deleted file mode 100644 index 83fc082..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jisfreq.py +++ /dev/null @@ -1,325 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Sampling from about 20M text materials include literature and computer technology -# -# Japanese frequency table, applied to both S-JIS and EUC-JP -# They are sorted in order. - -# 128 --> 0.77094 -# 256 --> 0.85710 -# 512 --> 0.92635 -# 1024 --> 0.97130 -# 2048 --> 0.99431 -# -# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 -# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 -# -# Typical Distribution Ratio, 25% of IDR - -JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 - -# Char to FreqOrder table , -JIS_TABLE_SIZE = 4368 - -JIS_CHAR_TO_FREQ_ORDER = ( - 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 -3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 -1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 -2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 -2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 -5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 -1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 -5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 -5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 -5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 -5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 -5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 -5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 -1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 -1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 -1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 -2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 -3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 -3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 - 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 - 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 -1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 - 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 -5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 - 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 - 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 - 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 - 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 - 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 -5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 -5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 -5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 -4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 -5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 -5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 -5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 -5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 -5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 -5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 -5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 -5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 -5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 -3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 -5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 -5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 -5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 -5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 -5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 -5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 -5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 -5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 -5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 -5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 -5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 -5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 -5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 -5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 -5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 -5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 -5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 -5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 -5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 -5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 -5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 -5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 -5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 -5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 -5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 -5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 -5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 -5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 -5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 -5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 -5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 -5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 -5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 -5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 -5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 -5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 -5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 -5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 -6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 -6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 -6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 -6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 -6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 -6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 -6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 -6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 -4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 - 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 - 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 -1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 -1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 - 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 -3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 -3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 - 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 -3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 -3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 - 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 -2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 - 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 -3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 -1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 - 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 -1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 - 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 -2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 -2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 -2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 -2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 -1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 -1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 -1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 -1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 -2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 -1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 -2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 -1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 -1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 -1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 -1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 -1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 -1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 - 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 - 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 -1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 -2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 -2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 -2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 -3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 -3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 - 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 -3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 -1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 - 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 -2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 -1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 - 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 -3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 -4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 -2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 -1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 -2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 -1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 - 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 - 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 -1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 -2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 -2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 -2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 -3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 -1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 -2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 - 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 - 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 - 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 -1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 -2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 - 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 -1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 -1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 - 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 -1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 -1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 -1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 - 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 -2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 - 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 -2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 -3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 -2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 -1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 -6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 -1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 -2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 -1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 - 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 - 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 -3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 -3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 -1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 -1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 -1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 -1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 - 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 - 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 -2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 - 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 -3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 -2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 - 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 -1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 -2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 - 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 -1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 - 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 -4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 -2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 -1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 - 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 -1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 -2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 - 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 -6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 -1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 -1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 -2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 -3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 - 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 -3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 -1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 - 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 -1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 - 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 -3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 - 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 -2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 - 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 -4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 -2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 -1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 -1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 -1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 - 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 -1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 -3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 -1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 -3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 - 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 - 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 - 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 -2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 -1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 - 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 -1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 - 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 -1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 - 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 - 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 - 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 -1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 -1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 -2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 -4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 - 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 -1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 - 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 -1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 -3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 -1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 -2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 -2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 -1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 -1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 -2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 - 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 -2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 -1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 -1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 -1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 -1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 -3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 -2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 -2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 - 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 -3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 -3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 -1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 -2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 -1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 -2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 -) - - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jpcntx.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jpcntx.py deleted file mode 100644 index 20044e4..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/jpcntx.py +++ /dev/null @@ -1,233 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - - -# This is hiragana 2-char sequence table, the number in each cell represents its frequency category -jp2CharContext = ( -(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), -(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), -(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), -(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), -(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), -(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), -(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), -(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), -(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), -(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), -(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), -(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), -(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), -(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), -(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), -(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), -(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), -(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), -(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), -(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), -(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), -(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), -(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), -(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), -(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), -(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), -(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), -(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), -(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), -(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), -(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), -(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), -(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), -(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), -(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), -(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), -(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), -(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), -(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), -(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), -(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), -(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), -(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), -(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), -(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), -(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), -(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), -(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), -(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), -(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), -(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), -(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), -(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), -(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), -(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), -(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), -(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), -(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), -(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), -(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), -(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), -(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), -(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), -(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), -(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), -(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), -(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), -(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), -(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), -(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), -(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), -(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), -(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), -(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), -) - -class JapaneseContextAnalysis(object): - NUM_OF_CATEGORY = 6 - DONT_KNOW = -1 - ENOUGH_REL_THRESHOLD = 100 - MAX_REL_THRESHOLD = 1000 - MINIMUM_DATA_THRESHOLD = 4 - - def __init__(self): - self._total_rel = None - self._rel_sample = None - self._need_to_skip_char_num = None - self._last_char_order = None - self._done = None - self.reset() - - def reset(self): - self._total_rel = 0 # total sequence received - # category counters, each integer counts sequence in its category - self._rel_sample = [0] * self.NUM_OF_CATEGORY - # if last byte in current buffer is not the last byte of a character, - # we need to know how many bytes to skip in next buffer - self._need_to_skip_char_num = 0 - self._last_char_order = -1 # The order of previous char - # If this flag is set to True, detection is done and conclusion has - # been made - self._done = False - - def feed(self, byte_str, num_bytes): - if self._done: - return - - # The buffer we got is byte oriented, and a character may span in more than one - # buffers. In case the last one or two byte in last buffer is not - # complete, we record how many byte needed to complete that character - # and skip these bytes here. We can choose to record those bytes as - # well and analyse the character once it is complete, but since a - # character will not make much difference, by simply skipping - # this character will simply our logic and improve performance. - i = self._need_to_skip_char_num - while i < num_bytes: - order, char_len = self.get_order(byte_str[i:i + 2]) - i += char_len - if i > num_bytes: - self._need_to_skip_char_num = i - num_bytes - self._last_char_order = -1 - else: - if (order != -1) and (self._last_char_order != -1): - self._total_rel += 1 - if self._total_rel > self.MAX_REL_THRESHOLD: - self._done = True - break - self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 - self._last_char_order = order - - def got_enough_data(self): - return self._total_rel > self.ENOUGH_REL_THRESHOLD - - def get_confidence(self): - # This is just one way to calculate confidence. It works well for me. - if self._total_rel > self.MINIMUM_DATA_THRESHOLD: - return (self._total_rel - self._rel_sample[0]) / self._total_rel - else: - return self.DONT_KNOW - - def get_order(self, byte_str): - return -1, 1 - -class SJISContextAnalysis(JapaneseContextAnalysis): - def __init__(self): - super(SJISContextAnalysis, self).__init__() - self._charset_name = "SHIFT_JIS" - - @property - def charset_name(self): - return self._charset_name - - def get_order(self, byte_str): - if not byte_str: - return -1, 1 - # find out current char's byte length - first_char = byte_str[0] - if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): - char_len = 2 - if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): - self._charset_name = "CP932" - else: - char_len = 1 - - # return its order if it is hiragana - if len(byte_str) > 1: - second_char = byte_str[1] - if (first_char == 202) and (0x9F <= second_char <= 0xF1): - return second_char - 0x9F, char_len - - return -1, char_len - -class EUCJPContextAnalysis(JapaneseContextAnalysis): - def get_order(self, byte_str): - if not byte_str: - return -1, 1 - # find out current char's byte length - first_char = byte_str[0] - if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): - char_len = 2 - elif first_char == 0x8F: - char_len = 3 - else: - char_len = 1 - - # return its order if it is hiragana - if len(byte_str) > 1: - second_char = byte_str[1] - if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): - return second_char - 0xA1, char_len - - return -1, char_len - - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langbulgarianmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langbulgarianmodel.py deleted file mode 100644 index e963a50..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langbulgarianmodel.py +++ /dev/null @@ -1,4650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -BULGARIAN_LANG_MODEL = { - 63: { # 'e' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 1, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 45: { # '\xad' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 1, # 'М' - 36: 0, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 31: { # 'А' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 1, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 2, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 2, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 0, # 'и' - 26: 2, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 32: { # 'Б' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 1, # 'Щ' - 61: 2, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 35: { # 'В' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 2, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 2, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 43: { # 'Г' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 1, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 37: { # 'Д' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 2, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 44: { # 'Е' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 2, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 0, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 55: { # 'Ж' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 47: { # 'З' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 40: { # 'И' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 2, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 2, # 'Я' - 1: 1, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 3, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 0, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 59: { # 'Й' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 33: { # 'К' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 46: { # 'Л' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 2, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 38: { # 'М' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 36: { # 'Н' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 2, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 41: { # 'О' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 2, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 2, # 'ч' - 27: 0, # 'ш' - 24: 2, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 30: { # 'П' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 2, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 39: { # 'Р' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 2, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 28: { # 'С' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 3, # 'А' - 32: 2, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 34: { # 'Т' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 51: { # 'У' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 2, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 48: { # 'Ф' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 49: { # 'Х' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 53: { # 'Ц' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 50: { # 'Ч' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 54: { # 'Ш' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 57: { # 'Щ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 61: { # 'Ъ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 60: { # 'Ю' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 1, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 0, # 'е' - 23: 2, # 'ж' - 15: 1, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 56: { # 'Я' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 1, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 1: { # 'а' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 18: { # 'б' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 0, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 2, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 3, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 9: { # 'в' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 0, # 'в' - 20: 2, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 20: { # 'г' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 11: { # 'д' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 1, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 3: { # 'е' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 2, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 23: { # 'ж' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 15: { # 'з' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 2: { # 'и' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 1, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 26: { # 'й' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 12: { # 'к' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 3, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 10: { # 'л' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 1, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 3, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 14: { # 'м' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 6: { # 'н' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 2, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 3, # 'ф' - 25: 2, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 4: { # 'о' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 13: { # 'п' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 7: { # 'р' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 2, # 'ч' - 27: 3, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 8: { # 'с' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 5: { # 'т' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 19: { # 'у' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 2, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 2, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 29: { # 'ф' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 2, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 25: { # 'х' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 22: { # 'ц' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 21: { # 'ч' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 27: { # 'ш' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 24: { # 'щ' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 17: { # 'ъ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 1, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 3, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 2, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 52: { # 'ь' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 42: { # 'ю' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 1, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 1, # 'е' - 23: 2, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 1, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 16: { # 'я' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 1, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 3, # 'х' - 22: 2, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 2, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 58: { # 'є' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 62: { # '№' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -ISO_8859_5_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 194, # '\x80' - 129: 195, # '\x81' - 130: 196, # '\x82' - 131: 197, # '\x83' - 132: 198, # '\x84' - 133: 199, # '\x85' - 134: 200, # '\x86' - 135: 201, # '\x87' - 136: 202, # '\x88' - 137: 203, # '\x89' - 138: 204, # '\x8a' - 139: 205, # '\x8b' - 140: 206, # '\x8c' - 141: 207, # '\x8d' - 142: 208, # '\x8e' - 143: 209, # '\x8f' - 144: 210, # '\x90' - 145: 211, # '\x91' - 146: 212, # '\x92' - 147: 213, # '\x93' - 148: 214, # '\x94' - 149: 215, # '\x95' - 150: 216, # '\x96' - 151: 217, # '\x97' - 152: 218, # '\x98' - 153: 219, # '\x99' - 154: 220, # '\x9a' - 155: 221, # '\x9b' - 156: 222, # '\x9c' - 157: 223, # '\x9d' - 158: 224, # '\x9e' - 159: 225, # '\x9f' - 160: 81, # '\xa0' - 161: 226, # 'Ё' - 162: 227, # 'Ђ' - 163: 228, # 'Ѓ' - 164: 229, # 'Є' - 165: 230, # 'Ѕ' - 166: 105, # 'І' - 167: 231, # 'Ї' - 168: 232, # 'Ј' - 169: 233, # 'Љ' - 170: 234, # 'Њ' - 171: 235, # 'Ћ' - 172: 236, # 'Ќ' - 173: 45, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 31, # 'А' - 177: 32, # 'Б' - 178: 35, # 'В' - 179: 43, # 'Г' - 180: 37, # 'Д' - 181: 44, # 'Е' - 182: 55, # 'Ж' - 183: 47, # 'З' - 184: 40, # 'И' - 185: 59, # 'Й' - 186: 33, # 'К' - 187: 46, # 'Л' - 188: 38, # 'М' - 189: 36, # 'Н' - 190: 41, # 'О' - 191: 30, # 'П' - 192: 39, # 'Р' - 193: 28, # 'С' - 194: 34, # 'Т' - 195: 51, # 'У' - 196: 48, # 'Ф' - 197: 49, # 'Х' - 198: 53, # 'Ц' - 199: 50, # 'Ч' - 200: 54, # 'Ш' - 201: 57, # 'Щ' - 202: 61, # 'Ъ' - 203: 239, # 'Ы' - 204: 67, # 'Ь' - 205: 240, # 'Э' - 206: 60, # 'Ю' - 207: 56, # 'Я' - 208: 1, # 'а' - 209: 18, # 'б' - 210: 9, # 'в' - 211: 20, # 'г' - 212: 11, # 'д' - 213: 3, # 'е' - 214: 23, # 'ж' - 215: 15, # 'з' - 216: 2, # 'и' - 217: 26, # 'й' - 218: 12, # 'к' - 219: 10, # 'л' - 220: 14, # 'м' - 221: 6, # 'н' - 222: 4, # 'о' - 223: 13, # 'п' - 224: 7, # 'р' - 225: 8, # 'с' - 226: 5, # 'т' - 227: 19, # 'у' - 228: 29, # 'ф' - 229: 25, # 'х' - 230: 22, # 'ц' - 231: 21, # 'ч' - 232: 27, # 'ш' - 233: 24, # 'щ' - 234: 17, # 'ъ' - 235: 75, # 'ы' - 236: 52, # 'ь' - 237: 241, # 'э' - 238: 42, # 'ю' - 239: 16, # 'я' - 240: 62, # '№' - 241: 242, # 'ё' - 242: 243, # 'ђ' - 243: 244, # 'ѓ' - 244: 58, # 'є' - 245: 245, # 'ѕ' - 246: 98, # 'і' - 247: 246, # 'ї' - 248: 247, # 'ј' - 249: 248, # 'љ' - 250: 249, # 'њ' - 251: 250, # 'ћ' - 252: 251, # 'ќ' - 253: 91, # '§' - 254: 252, # 'ў' - 255: 253, # 'џ' -} - -ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Bulgarian', - char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') - -WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 206, # 'Ђ' - 129: 207, # 'Ѓ' - 130: 208, # '‚' - 131: 209, # 'ѓ' - 132: 210, # '„' - 133: 211, # '…' - 134: 212, # '†' - 135: 213, # '‡' - 136: 120, # '€' - 137: 214, # '‰' - 138: 215, # 'Љ' - 139: 216, # '‹' - 140: 217, # 'Њ' - 141: 218, # 'Ќ' - 142: 219, # 'Ћ' - 143: 220, # 'Џ' - 144: 221, # 'ђ' - 145: 78, # '‘' - 146: 64, # '’' - 147: 83, # '“' - 148: 121, # '”' - 149: 98, # '•' - 150: 117, # '–' - 151: 105, # '—' - 152: 222, # None - 153: 223, # '™' - 154: 224, # 'љ' - 155: 225, # '›' - 156: 226, # 'њ' - 157: 227, # 'ќ' - 158: 228, # 'ћ' - 159: 229, # 'џ' - 160: 88, # '\xa0' - 161: 230, # 'Ў' - 162: 231, # 'ў' - 163: 232, # 'Ј' - 164: 233, # '¤' - 165: 122, # 'Ґ' - 166: 89, # '¦' - 167: 106, # '§' - 168: 234, # 'Ё' - 169: 235, # '©' - 170: 236, # 'Є' - 171: 237, # '«' - 172: 238, # '¬' - 173: 45, # '\xad' - 174: 239, # '®' - 175: 240, # 'Ї' - 176: 73, # '°' - 177: 80, # '±' - 178: 118, # 'І' - 179: 114, # 'і' - 180: 241, # 'ґ' - 181: 242, # 'µ' - 182: 243, # '¶' - 183: 244, # '·' - 184: 245, # 'ё' - 185: 62, # '№' - 186: 58, # 'є' - 187: 246, # '»' - 188: 247, # 'ј' - 189: 248, # 'Ѕ' - 190: 249, # 'ѕ' - 191: 250, # 'ї' - 192: 31, # 'А' - 193: 32, # 'Б' - 194: 35, # 'В' - 195: 43, # 'Г' - 196: 37, # 'Д' - 197: 44, # 'Е' - 198: 55, # 'Ж' - 199: 47, # 'З' - 200: 40, # 'И' - 201: 59, # 'Й' - 202: 33, # 'К' - 203: 46, # 'Л' - 204: 38, # 'М' - 205: 36, # 'Н' - 206: 41, # 'О' - 207: 30, # 'П' - 208: 39, # 'Р' - 209: 28, # 'С' - 210: 34, # 'Т' - 211: 51, # 'У' - 212: 48, # 'Ф' - 213: 49, # 'Х' - 214: 53, # 'Ц' - 215: 50, # 'Ч' - 216: 54, # 'Ш' - 217: 57, # 'Щ' - 218: 61, # 'Ъ' - 219: 251, # 'Ы' - 220: 67, # 'Ь' - 221: 252, # 'Э' - 222: 60, # 'Ю' - 223: 56, # 'Я' - 224: 1, # 'а' - 225: 18, # 'б' - 226: 9, # 'в' - 227: 20, # 'г' - 228: 11, # 'д' - 229: 3, # 'е' - 230: 23, # 'ж' - 231: 15, # 'з' - 232: 2, # 'и' - 233: 26, # 'й' - 234: 12, # 'к' - 235: 10, # 'л' - 236: 14, # 'м' - 237: 6, # 'н' - 238: 4, # 'о' - 239: 13, # 'п' - 240: 7, # 'р' - 241: 8, # 'с' - 242: 5, # 'т' - 243: 19, # 'у' - 244: 29, # 'ф' - 245: 25, # 'х' - 246: 22, # 'ц' - 247: 21, # 'ч' - 248: 27, # 'ш' - 249: 24, # 'щ' - 250: 17, # 'ъ' - 251: 75, # 'ы' - 252: 52, # 'ь' - 253: 253, # 'э' - 254: 42, # 'ю' - 255: 16, # 'я' -} - -WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Bulgarian', - char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langgreekmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langgreekmodel.py deleted file mode 100644 index d99528e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langgreekmodel.py +++ /dev/null @@ -1,4398 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -GREEK_LANG_MODEL = { - 60: { # 'e' - 60: 2, # 'e' - 55: 1, # 'o' - 58: 2, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 55: { # 'o' - 60: 0, # 'e' - 55: 2, # 'o' - 58: 2, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 58: { # 't' - 60: 2, # 'e' - 55: 1, # 'o' - 58: 1, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 1, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 36: { # '·' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 61: { # 'Ά' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 1, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 1, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 46: { # 'Έ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 2, # 'β' - 20: 2, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 1, # 'σ' - 2: 2, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 54: { # 'Ό' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 31: { # 'Α' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 2, # 'Β' - 43: 2, # 'Γ' - 41: 1, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 2, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 1, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 2, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 2, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 1, # 'θ' - 5: 0, # 'ι' - 11: 2, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 2, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 51: { # 'Β' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 1, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 43: { # 'Γ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 1, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 41: { # 'Δ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 1, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 34: { # 'Ε' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 2, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 1, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 2, # 'Χ' - 57: 2, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 1, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 1, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 1, # 'ύ' - 27: 0, # 'ώ' - }, - 40: { # 'Η' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 2, # 'Θ' - 47: 0, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 52: { # 'Θ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 1, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 47: { # 'Ι' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 1, # 'Β' - 43: 1, # 'Γ' - 41: 2, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 2, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 1, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 1, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 44: { # 'Κ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 1, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 1, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 53: { # 'Λ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 2, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 2, # 'Σ' - 33: 0, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 1, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 38: { # 'Μ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 2, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 2, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 49: { # 'Ν' - 60: 2, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 1, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 1, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 59: { # 'Ξ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 39: { # 'Ο' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 1, # 'Β' - 43: 2, # 'Γ' - 41: 2, # 'Δ' - 34: 2, # 'Ε' - 40: 1, # 'Η' - 52: 2, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 2, # 'Φ' - 50: 2, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 1, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 35: { # 'Π' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 2, # 'Λ' - 38: 1, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 1, # 'έ' - 22: 1, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 3, # 'ώ' - }, - 48: { # 'Ρ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 1, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 1, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 37: { # 'Σ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 2, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 2, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 2, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 2, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 33: { # 'Τ' - 60: 0, # 'e' - 55: 1, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 2, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 45: { # 'Υ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 2, # 'Η' - 52: 2, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 1, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 56: { # 'Φ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 1, # 'ύ' - 27: 1, # 'ώ' - }, - 50: { # 'Χ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 1, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 1, # 'Ω' - 17: 2, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 57: { # 'Ω' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 2, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 17: { # 'ά' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 3, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 3, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 18: { # 'έ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 3, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 22: { # 'ή' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 15: { # 'ί' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 3, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 1, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 1: { # 'α' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 2, # 'ε' - 32: 3, # 'ζ' - 13: 1, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 29: { # 'β' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 2, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 3, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 20: { # 'γ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 21: { # 'δ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 3: { # 'ε' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 2, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 2, # 'ε' - 32: 2, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 32: { # 'ζ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 2, # 'ώ' - }, - 13: { # 'η' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 25: { # 'θ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 1, # 'λ' - 10: 3, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 5: { # 'ι' - 60: 0, # 'e' - 55: 1, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 0, # 'ύ' - 27: 3, # 'ώ' - }, - 11: { # 'κ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 16: { # 'λ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 1, # 'β' - 20: 2, # 'γ' - 21: 1, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 10: { # 'μ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 3, # 'φ' - 23: 0, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 6: { # 'ν' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 1, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 30: { # 'ξ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 3, # 'ύ' - 27: 1, # 'ώ' - }, - 4: { # 'ο' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 2, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 1, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 9: { # 'π' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 3, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 2, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 8: { # 'ρ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 1, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 3, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 14: { # 'ς' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 7: { # 'σ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 2: { # 'τ' - 60: 0, # 'e' - 55: 2, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 12: { # 'υ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 2, # 'ε' - 32: 2, # 'ζ' - 13: 2, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 2, # 'ώ' - }, - 28: { # 'φ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 1, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 23: { # 'χ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 42: { # 'ψ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 1, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 24: { # 'ω' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 1, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 19: { # 'ό' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 1, # 'ε' - 32: 2, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 1, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 26: { # 'ύ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 2, # 'β' - 20: 2, # 'γ' - 21: 1, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 27: { # 'ώ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 1, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 1, # 'η' - 25: 2, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 1, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 1, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1253_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '€' - 129: 255, # None - 130: 255, # '‚' - 131: 255, # 'ƒ' - 132: 255, # '„' - 133: 255, # '…' - 134: 255, # '†' - 135: 255, # '‡' - 136: 255, # None - 137: 255, # '‰' - 138: 255, # None - 139: 255, # '‹' - 140: 255, # None - 141: 255, # None - 142: 255, # None - 143: 255, # None - 144: 255, # None - 145: 255, # '‘' - 146: 255, # '’' - 147: 255, # '“' - 148: 255, # '”' - 149: 255, # '•' - 150: 255, # '–' - 151: 255, # '—' - 152: 255, # None - 153: 255, # '™' - 154: 255, # None - 155: 255, # '›' - 156: 255, # None - 157: 255, # None - 158: 255, # None - 159: 255, # None - 160: 253, # '\xa0' - 161: 233, # '΅' - 162: 61, # 'Ά' - 163: 253, # '£' - 164: 253, # '¤' - 165: 253, # '¥' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # None - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # '®' - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 253, # 'µ' - 182: 253, # '¶' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None -} - -WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel(charset_name='windows-1253', - language='Greek', - char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') - -ISO_8859_7_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '\x80' - 129: 255, # '\x81' - 130: 255, # '\x82' - 131: 255, # '\x83' - 132: 255, # '\x84' - 133: 255, # '\x85' - 134: 255, # '\x86' - 135: 255, # '\x87' - 136: 255, # '\x88' - 137: 255, # '\x89' - 138: 255, # '\x8a' - 139: 255, # '\x8b' - 140: 255, # '\x8c' - 141: 255, # '\x8d' - 142: 255, # '\x8e' - 143: 255, # '\x8f' - 144: 255, # '\x90' - 145: 255, # '\x91' - 146: 255, # '\x92' - 147: 255, # '\x93' - 148: 255, # '\x94' - 149: 255, # '\x95' - 150: 255, # '\x96' - 151: 255, # '\x97' - 152: 255, # '\x98' - 153: 255, # '\x99' - 154: 255, # '\x9a' - 155: 255, # '\x9b' - 156: 255, # '\x9c' - 157: 255, # '\x9d' - 158: 255, # '\x9e' - 159: 255, # '\x9f' - 160: 253, # '\xa0' - 161: 233, # '‘' - 162: 90, # '’' - 163: 253, # '£' - 164: 253, # '€' - 165: 253, # '₯' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # 'ͺ' - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # None - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 248, # '΅' - 182: 61, # 'Ά' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None -} - -ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-7', - language='Greek', - char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhebrewmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhebrewmodel.py deleted file mode 100644 index 484c652..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhebrewmodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -HEBREW_LANG_MODEL = { - 50: { # 'a' - 50: 0, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 2, # 'l' - 54: 2, # 'n' - 49: 0, # 'o' - 51: 2, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 0, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 60: { # 'c' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 61: { # 'd' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 0, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 42: { # 'e' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 2, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 2, # 'l' - 54: 2, # 'n' - 49: 1, # 'o' - 51: 2, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 1, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 53: { # 'i' - 50: 1, # 'a' - 60: 2, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 0, # 'i' - 56: 1, # 'l' - 54: 2, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 56: { # 'l' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 2, # 'e' - 53: 2, # 'i' - 56: 2, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 54: { # 'n' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 49: { # 'o' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 2, # 'n' - 49: 1, # 'o' - 51: 2, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 51: { # 'r' - 50: 2, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 2, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 43: { # 's' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 2, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 2, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 44: { # 't' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 2, # 'e' - 53: 2, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 63: { # 'u' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 34: { # '\xa0' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 1, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 2, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 55: { # '´' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 2, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 1, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 48: { # '¼' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 39: { # '½' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 57: { # '¾' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 30: { # 'ְ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 2, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 0, # 'ף' - 18: 2, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 59: { # 'ֱ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 1, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 41: { # 'ֲ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 33: { # 'ִ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 2, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 37: { # 'ֵ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 1, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 36: { # 'ֶ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 1, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 2, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 31: { # 'ַ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 29: { # 'ָ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 2, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 35: { # 'ֹ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 62: { # 'ֻ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 1, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 28: { # 'ּ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 3, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 3, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 3, # 'ַ' - 29: 3, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 2, # 'ׁ' - 45: 1, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 2, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 2, # 'מ' - 23: 1, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 38: { # 'ׁ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 2, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 45: { # 'ׂ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 2, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 9: { # 'א' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 2, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 8: { # 'ב' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 1, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 20: { # 'ג' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 2, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 16: { # 'ד' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 3: { # 'ה' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 3, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 0, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 2: { # 'ו' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 3, # 'ֹ' - 62: 0, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 24: { # 'ז' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 1, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 1, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 14: { # 'ח' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 1, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 22: { # 'ט' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 1, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 2, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 1: { # 'י' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 25: { # 'ך' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 15: { # 'כ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 4: { # 'ל' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 3, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 11: { # 'ם' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 6: { # 'מ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 0, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 23: { # 'ן' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 12: { # 'נ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 19: { # 'ס' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 2, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 1, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 13: { # 'ע' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 1, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 26: { # 'ף' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 18: { # 'פ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 2, # 'ב' - 20: 3, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 27: { # 'ץ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 21: { # 'צ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 1, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 0, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 17: { # 'ק' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 7: { # 'ר' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 2, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 10: { # 'ש' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 3, # 'ׁ' - 45: 2, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 5: { # 'ת' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 1, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 32: { # '–' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 52: { # '’' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 47: { # '“' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 46: { # '”' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 58: { # '†' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 2, # '†' - 40: 0, # '…' - }, - 40: { # '…' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1255_HEBREW_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 69, # 'A' - 66: 91, # 'B' - 67: 79, # 'C' - 68: 80, # 'D' - 69: 92, # 'E' - 70: 89, # 'F' - 71: 97, # 'G' - 72: 90, # 'H' - 73: 68, # 'I' - 74: 111, # 'J' - 75: 112, # 'K' - 76: 82, # 'L' - 77: 73, # 'M' - 78: 95, # 'N' - 79: 85, # 'O' - 80: 78, # 'P' - 81: 121, # 'Q' - 82: 86, # 'R' - 83: 71, # 'S' - 84: 67, # 'T' - 85: 102, # 'U' - 86: 107, # 'V' - 87: 84, # 'W' - 88: 114, # 'X' - 89: 103, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 50, # 'a' - 98: 74, # 'b' - 99: 60, # 'c' - 100: 61, # 'd' - 101: 42, # 'e' - 102: 76, # 'f' - 103: 70, # 'g' - 104: 64, # 'h' - 105: 53, # 'i' - 106: 105, # 'j' - 107: 93, # 'k' - 108: 56, # 'l' - 109: 65, # 'm' - 110: 54, # 'n' - 111: 49, # 'o' - 112: 66, # 'p' - 113: 110, # 'q' - 114: 51, # 'r' - 115: 43, # 's' - 116: 44, # 't' - 117: 63, # 'u' - 118: 81, # 'v' - 119: 77, # 'w' - 120: 98, # 'x' - 121: 75, # 'y' - 122: 108, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 124, # '€' - 129: 202, # None - 130: 203, # '‚' - 131: 204, # 'ƒ' - 132: 205, # '„' - 133: 40, # '…' - 134: 58, # '†' - 135: 206, # '‡' - 136: 207, # 'ˆ' - 137: 208, # '‰' - 138: 209, # None - 139: 210, # '‹' - 140: 211, # None - 141: 212, # None - 142: 213, # None - 143: 214, # None - 144: 215, # None - 145: 83, # '‘' - 146: 52, # '’' - 147: 47, # '“' - 148: 46, # '”' - 149: 72, # '•' - 150: 32, # '–' - 151: 94, # '—' - 152: 216, # '˜' - 153: 113, # '™' - 154: 217, # None - 155: 109, # '›' - 156: 218, # None - 157: 219, # None - 158: 220, # None - 159: 221, # None - 160: 34, # '\xa0' - 161: 116, # '¡' - 162: 222, # '¢' - 163: 118, # '£' - 164: 100, # '₪' - 165: 223, # '¥' - 166: 224, # '¦' - 167: 117, # '§' - 168: 119, # '¨' - 169: 104, # '©' - 170: 125, # '×' - 171: 225, # '«' - 172: 226, # '¬' - 173: 87, # '\xad' - 174: 99, # '®' - 175: 227, # '¯' - 176: 106, # '°' - 177: 122, # '±' - 178: 123, # '²' - 179: 228, # '³' - 180: 55, # '´' - 181: 229, # 'µ' - 182: 230, # '¶' - 183: 101, # '·' - 184: 231, # '¸' - 185: 232, # '¹' - 186: 120, # '÷' - 187: 233, # '»' - 188: 48, # '¼' - 189: 39, # '½' - 190: 57, # '¾' - 191: 234, # '¿' - 192: 30, # 'ְ' - 193: 59, # 'ֱ' - 194: 41, # 'ֲ' - 195: 88, # 'ֳ' - 196: 33, # 'ִ' - 197: 37, # 'ֵ' - 198: 36, # 'ֶ' - 199: 31, # 'ַ' - 200: 29, # 'ָ' - 201: 35, # 'ֹ' - 202: 235, # None - 203: 62, # 'ֻ' - 204: 28, # 'ּ' - 205: 236, # 'ֽ' - 206: 126, # '־' - 207: 237, # 'ֿ' - 208: 238, # '׀' - 209: 38, # 'ׁ' - 210: 45, # 'ׂ' - 211: 239, # '׃' - 212: 240, # 'װ' - 213: 241, # 'ױ' - 214: 242, # 'ײ' - 215: 243, # '׳' - 216: 127, # '״' - 217: 244, # None - 218: 245, # None - 219: 246, # None - 220: 247, # None - 221: 248, # None - 222: 249, # None - 223: 250, # None - 224: 9, # 'א' - 225: 8, # 'ב' - 226: 20, # 'ג' - 227: 16, # 'ד' - 228: 3, # 'ה' - 229: 2, # 'ו' - 230: 24, # 'ז' - 231: 14, # 'ח' - 232: 22, # 'ט' - 233: 1, # 'י' - 234: 25, # 'ך' - 235: 15, # 'כ' - 236: 4, # 'ל' - 237: 11, # 'ם' - 238: 6, # 'מ' - 239: 23, # 'ן' - 240: 12, # 'נ' - 241: 19, # 'ס' - 242: 13, # 'ע' - 243: 26, # 'ף' - 244: 18, # 'פ' - 245: 27, # 'ץ' - 246: 21, # 'צ' - 247: 17, # 'ק' - 248: 7, # 'ר' - 249: 10, # 'ש' - 250: 5, # 'ת' - 251: 251, # None - 252: 252, # None - 253: 128, # '\u200e' - 254: 96, # '\u200f' - 255: 253, # None -} - -WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel(charset_name='windows-1255', - language='Hebrew', - char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, - language_model=HEBREW_LANG_MODEL, - typical_positive_ratio=0.984004, - keep_ascii_letters=False, - alphabet='אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhungarianmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhungarianmodel.py deleted file mode 100644 index bbc5cda..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langhungarianmodel.py +++ /dev/null @@ -1,4650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -HUNGARIAN_LANG_MODEL = { - 28: { # 'A' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 2, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 2, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 2, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 1, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 40: { # 'B' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 3, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 54: { # 'C' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 3, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 45: { # 'D' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 32: { # 'E' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 2, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 50: { # 'F' - 28: 1, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 0, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 49: { # 'G' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 2, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 38: { # 'H' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 0, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 1, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 2, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 39: { # 'I' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 2, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 53: { # 'J' - 28: 2, # 'A' - 40: 0, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 0, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 36: { # 'K' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 2, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 41: { # 'L' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 34: { # 'M' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 3, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 1, # 'ű' - }, - 35: { # 'N' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 2, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 2, # 'Y' - 52: 1, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 47: { # 'O' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 2, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 46: { # 'P' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 3, # 'á' - 15: 2, # 'é' - 30: 0, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 43: { # 'R' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 2, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 2, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 33: { # 'S' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 3, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 1, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 37: { # 'T' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 57: { # 'U' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 48: { # 'V' - 28: 2, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 55: { # 'Y' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 2, # 'Z' - 2: 1, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 52: { # 'Z' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 1, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 2: { # 'a' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 18: { # 'b' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 26: { # 'c' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 1, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 2, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 2, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 17: { # 'd' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 2, # 'k' - 6: 1, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 1: { # 'e' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 2, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 27: { # 'f' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 3, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 3, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 12: { # 'g' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 20: { # 'h' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 9: { # 'i' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 3, # 'ó' - 24: 1, # 'ö' - 31: 2, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 1, # 'ű' - }, - 22: { # 'j' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 1, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 1, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 7: { # 'k' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 1, # 'ú' - 29: 3, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 6: { # 'l' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 3, # 'ő' - 56: 1, # 'ű' - }, - 13: { # 'm' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 1, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 3, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 2, # 'ű' - }, - 4: { # 'n' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 1, # 'x' - 16: 3, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 8: { # 'o' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 23: { # 'p' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 10: { # 'r' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 2, # 'ű' - }, - 5: { # 's' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 3: { # 't' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 1, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 3, # 'ő' - 56: 2, # 'ű' - }, - 21: { # 'u' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 2, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 1, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 1, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 19: { # 'v' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 2, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 62: { # 'x' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 16: { # 'y' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 2, # 'ű' - }, - 11: { # 'z' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 51: { # 'Á' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 44: { # 'É' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 61: { # 'Í' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 0, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 58: { # 'Ó' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 2, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 59: { # 'Ö' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 60: { # 'Ú' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 2, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 63: { # 'Ü' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 14: { # 'á' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 15: { # 'é' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 30: { # 'í' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 25: { # 'ó' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 1, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 24: { # 'ö' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 0, # 'a' - 18: 3, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 31: { # 'ú' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 3, # 'j' - 7: 1, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 29: { # 'ü' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 0, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 42: { # 'ő' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 56: { # 'ű' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 72, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 161, # '€' - 129: 162, # None - 130: 163, # '‚' - 131: 164, # None - 132: 165, # '„' - 133: 166, # '…' - 134: 167, # '†' - 135: 168, # '‡' - 136: 169, # None - 137: 170, # '‰' - 138: 171, # 'Š' - 139: 172, # '‹' - 140: 173, # 'Ś' - 141: 174, # 'Ť' - 142: 175, # 'Ž' - 143: 176, # 'Ź' - 144: 177, # None - 145: 178, # '‘' - 146: 179, # '’' - 147: 180, # '“' - 148: 78, # '”' - 149: 181, # '•' - 150: 69, # '–' - 151: 182, # '—' - 152: 183, # None - 153: 184, # '™' - 154: 185, # 'š' - 155: 186, # '›' - 156: 187, # 'ś' - 157: 188, # 'ť' - 158: 189, # 'ž' - 159: 190, # 'ź' - 160: 191, # '\xa0' - 161: 192, # 'ˇ' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ą' - 166: 197, # '¦' - 167: 76, # '§' - 168: 198, # '¨' - 169: 199, # '©' - 170: 200, # 'Ş' - 171: 201, # '«' - 172: 202, # '¬' - 173: 203, # '\xad' - 174: 204, # '®' - 175: 205, # 'Ż' - 176: 81, # '°' - 177: 206, # '±' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'µ' - 182: 211, # '¶' - 183: 212, # '·' - 184: 213, # '¸' - 185: 214, # 'ą' - 186: 215, # 'ş' - 187: 216, # '»' - 188: 217, # 'Ľ' - 189: 218, # '˝' - 190: 219, # 'ľ' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 83, # 'Â' - 195: 222, # 'Ă' - 196: 80, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 70, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 84, # 'ŕ' - 225: 14, # 'á' - 226: 75, # 'â' - 227: 242, # 'ă' - 228: 71, # 'ä' - 229: 82, # 'ĺ' - 230: 243, # 'ć' - 231: 73, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 85, # 'ę' - 235: 79, # 'ë' - 236: 86, # 'ě' - 237: 30, # 'í' - 238: 77, # 'î' - 239: 87, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 74, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' -} - -WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1250', - language='Hungarian', - char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') - -ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 71, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 159, # '\x80' - 129: 160, # '\x81' - 130: 161, # '\x82' - 131: 162, # '\x83' - 132: 163, # '\x84' - 133: 164, # '\x85' - 134: 165, # '\x86' - 135: 166, # '\x87' - 136: 167, # '\x88' - 137: 168, # '\x89' - 138: 169, # '\x8a' - 139: 170, # '\x8b' - 140: 171, # '\x8c' - 141: 172, # '\x8d' - 142: 173, # '\x8e' - 143: 174, # '\x8f' - 144: 175, # '\x90' - 145: 176, # '\x91' - 146: 177, # '\x92' - 147: 178, # '\x93' - 148: 179, # '\x94' - 149: 180, # '\x95' - 150: 181, # '\x96' - 151: 182, # '\x97' - 152: 183, # '\x98' - 153: 184, # '\x99' - 154: 185, # '\x9a' - 155: 186, # '\x9b' - 156: 187, # '\x9c' - 157: 188, # '\x9d' - 158: 189, # '\x9e' - 159: 190, # '\x9f' - 160: 191, # '\xa0' - 161: 192, # 'Ą' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ľ' - 166: 197, # 'Ś' - 167: 75, # '§' - 168: 198, # '¨' - 169: 199, # 'Š' - 170: 200, # 'Ş' - 171: 201, # 'Ť' - 172: 202, # 'Ź' - 173: 203, # '\xad' - 174: 204, # 'Ž' - 175: 205, # 'Ż' - 176: 79, # '°' - 177: 206, # 'ą' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'ľ' - 182: 211, # 'ś' - 183: 212, # 'ˇ' - 184: 213, # '¸' - 185: 214, # 'š' - 186: 215, # 'ş' - 187: 216, # 'ť' - 188: 217, # 'ź' - 189: 218, # '˝' - 190: 219, # 'ž' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 81, # 'Â' - 195: 222, # 'Ă' - 196: 78, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 69, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 82, # 'ŕ' - 225: 14, # 'á' - 226: 74, # 'â' - 227: 242, # 'ă' - 228: 70, # 'ä' - 229: 80, # 'ĺ' - 230: 243, # 'ć' - 231: 72, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 83, # 'ę' - 235: 77, # 'ë' - 236: 84, # 'ě' - 237: 30, # 'í' - 238: 76, # 'î' - 239: 85, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 73, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' -} - -ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-2', - language='Hungarian', - char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langrussianmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langrussianmodel.py deleted file mode 100644 index 5594452..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langrussianmodel.py +++ /dev/null @@ -1,5718 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -RUSSIAN_LANG_MODEL = { - 37: { # 'А' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 44: { # 'Б' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 33: { # 'В' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 0, # 'ю' - 16: 1, # 'я' - }, - 46: { # 'Г' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 41: { # 'Д' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 3, # 'ж' - 20: 1, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 48: { # 'Е' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 2, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 1, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 56: { # 'Ж' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 1, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 2, # 'ю' - 16: 0, # 'я' - }, - 51: { # 'З' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 1, # 'я' - }, - 42: { # 'И' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 2, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 60: { # 'Й' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 36: { # 'К' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 49: { # 'Л' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 1, # 'я' - }, - 38: { # 'М' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 1, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 31: { # 'Н' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 2, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 34: { # 'О' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 2, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 2, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 35: { # 'П' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 1, # 'с' - 6: 1, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 2, # 'я' - }, - 45: { # 'Р' - 37: 2, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 2, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 32: { # 'С' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 2, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 40: { # 'Т' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 52: { # 'У' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 1, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 1, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 53: { # 'Ф' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 1, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 55: { # 'Х' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 58: { # 'Ц' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 50: { # 'Ч' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 57: { # 'Ш' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 63: { # 'Щ' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 62: { # 'Ы' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 61: { # 'Ь' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 47: { # 'Э' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 59: { # 'Ю' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 43: { # 'Я' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 1, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 3: { # 'а' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 21: { # 'б' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 10: { # 'в' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 19: { # 'г' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 13: { # 'д' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 3, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 2: { # 'е' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 24: { # 'ж' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 1, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 20: { # 'з' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 4: { # 'и' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 23: { # 'й' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 11: { # 'к' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 3, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 8: { # 'л' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 3, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 12: { # 'м' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 5: { # 'н' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 2, # 'щ' - 54: 1, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 1: { # 'о' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 15: { # 'п' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 9: { # 'р' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 7: { # 'с' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 6: { # 'т' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 2, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 14: { # 'у' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 2, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 2, # 'я' - }, - 39: { # 'ф' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 26: { # 'х' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 3, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 28: { # 'ц' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 1, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 22: { # 'ч' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 3, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 25: { # 'ш' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 29: { # 'щ' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 2, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 54: { # 'ъ' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 18: { # 'ы' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 1, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 2, # 'я' - }, - 17: { # 'ь' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 0, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 0, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 30: { # 'э' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 27: { # 'ю' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 1, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 1, # 'я' - }, - 16: { # 'я' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 2, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 2, # 'ю' - 16: 2, # 'я' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -IBM866_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 3, # 'а' - 161: 21, # 'б' - 162: 10, # 'в' - 163: 19, # 'г' - 164: 13, # 'д' - 165: 2, # 'е' - 166: 24, # 'ж' - 167: 20, # 'з' - 168: 4, # 'и' - 169: 23, # 'й' - 170: 11, # 'к' - 171: 8, # 'л' - 172: 12, # 'м' - 173: 5, # 'н' - 174: 1, # 'о' - 175: 15, # 'п' - 176: 191, # '░' - 177: 192, # '▒' - 178: 193, # '▓' - 179: 194, # '│' - 180: 195, # '┤' - 181: 196, # '╡' - 182: 197, # '╢' - 183: 198, # '╖' - 184: 199, # '╕' - 185: 200, # '╣' - 186: 201, # '║' - 187: 202, # '╗' - 188: 203, # '╝' - 189: 204, # '╜' - 190: 205, # '╛' - 191: 206, # '┐' - 192: 207, # '└' - 193: 208, # '┴' - 194: 209, # '┬' - 195: 210, # '├' - 196: 211, # '─' - 197: 212, # '┼' - 198: 213, # '╞' - 199: 214, # '╟' - 200: 215, # '╚' - 201: 216, # '╔' - 202: 217, # '╩' - 203: 218, # '╦' - 204: 219, # '╠' - 205: 220, # '═' - 206: 221, # '╬' - 207: 222, # '╧' - 208: 223, # '╨' - 209: 224, # '╤' - 210: 225, # '╥' - 211: 226, # '╙' - 212: 227, # '╘' - 213: 228, # '╒' - 214: 229, # '╓' - 215: 230, # '╫' - 216: 231, # '╪' - 217: 232, # '┘' - 218: 233, # '┌' - 219: 234, # '█' - 220: 235, # '▄' - 221: 236, # '▌' - 222: 237, # '▐' - 223: 238, # '▀' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # 'Ё' - 241: 68, # 'ё' - 242: 240, # 'Є' - 243: 241, # 'є' - 244: 242, # 'Ї' - 245: 243, # 'ї' - 246: 244, # 'Ў' - 247: 245, # 'ў' - 248: 246, # '°' - 249: 247, # '∙' - 250: 248, # '·' - 251: 249, # '√' - 252: 250, # '№' - 253: 251, # '¤' - 254: 252, # '■' - 255: 255, # '\xa0' -} - -IBM866_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM866', - language='Russian', - char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'Ђ' - 129: 192, # 'Ѓ' - 130: 193, # '‚' - 131: 194, # 'ѓ' - 132: 195, # '„' - 133: 196, # '…' - 134: 197, # '†' - 135: 198, # '‡' - 136: 199, # '€' - 137: 200, # '‰' - 138: 201, # 'Љ' - 139: 202, # '‹' - 140: 203, # 'Њ' - 141: 204, # 'Ќ' - 142: 205, # 'Ћ' - 143: 206, # 'Џ' - 144: 207, # 'ђ' - 145: 208, # '‘' - 146: 209, # '’' - 147: 210, # '“' - 148: 211, # '”' - 149: 212, # '•' - 150: 213, # '–' - 151: 214, # '—' - 152: 215, # None - 153: 216, # '™' - 154: 217, # 'љ' - 155: 218, # '›' - 156: 219, # 'њ' - 157: 220, # 'ќ' - 158: 221, # 'ћ' - 159: 222, # 'џ' - 160: 223, # '\xa0' - 161: 224, # 'Ў' - 162: 225, # 'ў' - 163: 226, # 'Ј' - 164: 227, # '¤' - 165: 228, # 'Ґ' - 166: 229, # '¦' - 167: 230, # '§' - 168: 231, # 'Ё' - 169: 232, # '©' - 170: 233, # 'Є' - 171: 234, # '«' - 172: 235, # '¬' - 173: 236, # '\xad' - 174: 237, # '®' - 175: 238, # 'Ї' - 176: 239, # '°' - 177: 240, # '±' - 178: 241, # 'І' - 179: 242, # 'і' - 180: 243, # 'ґ' - 181: 244, # 'µ' - 182: 245, # '¶' - 183: 246, # '·' - 184: 68, # 'ё' - 185: 247, # '№' - 186: 248, # 'є' - 187: 249, # '»' - 188: 250, # 'ј' - 189: 251, # 'Ѕ' - 190: 252, # 'ѕ' - 191: 253, # 'ї' - 192: 37, # 'А' - 193: 44, # 'Б' - 194: 33, # 'В' - 195: 46, # 'Г' - 196: 41, # 'Д' - 197: 48, # 'Е' - 198: 56, # 'Ж' - 199: 51, # 'З' - 200: 42, # 'И' - 201: 60, # 'Й' - 202: 36, # 'К' - 203: 49, # 'Л' - 204: 38, # 'М' - 205: 31, # 'Н' - 206: 34, # 'О' - 207: 35, # 'П' - 208: 45, # 'Р' - 209: 32, # 'С' - 210: 40, # 'Т' - 211: 52, # 'У' - 212: 53, # 'Ф' - 213: 55, # 'Х' - 214: 58, # 'Ц' - 215: 50, # 'Ч' - 216: 57, # 'Ш' - 217: 63, # 'Щ' - 218: 70, # 'Ъ' - 219: 62, # 'Ы' - 220: 61, # 'Ь' - 221: 47, # 'Э' - 222: 59, # 'Ю' - 223: 43, # 'Я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 16, # 'я' -} - -WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Russian', - char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -IBM855_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'ђ' - 129: 192, # 'Ђ' - 130: 193, # 'ѓ' - 131: 194, # 'Ѓ' - 132: 68, # 'ё' - 133: 195, # 'Ё' - 134: 196, # 'є' - 135: 197, # 'Є' - 136: 198, # 'ѕ' - 137: 199, # 'Ѕ' - 138: 200, # 'і' - 139: 201, # 'І' - 140: 202, # 'ї' - 141: 203, # 'Ї' - 142: 204, # 'ј' - 143: 205, # 'Ј' - 144: 206, # 'љ' - 145: 207, # 'Љ' - 146: 208, # 'њ' - 147: 209, # 'Њ' - 148: 210, # 'ћ' - 149: 211, # 'Ћ' - 150: 212, # 'ќ' - 151: 213, # 'Ќ' - 152: 214, # 'ў' - 153: 215, # 'Ў' - 154: 216, # 'џ' - 155: 217, # 'Џ' - 156: 27, # 'ю' - 157: 59, # 'Ю' - 158: 54, # 'ъ' - 159: 70, # 'Ъ' - 160: 3, # 'а' - 161: 37, # 'А' - 162: 21, # 'б' - 163: 44, # 'Б' - 164: 28, # 'ц' - 165: 58, # 'Ц' - 166: 13, # 'д' - 167: 41, # 'Д' - 168: 2, # 'е' - 169: 48, # 'Е' - 170: 39, # 'ф' - 171: 53, # 'Ф' - 172: 19, # 'г' - 173: 46, # 'Г' - 174: 218, # '«' - 175: 219, # '»' - 176: 220, # '░' - 177: 221, # '▒' - 178: 222, # '▓' - 179: 223, # '│' - 180: 224, # '┤' - 181: 26, # 'х' - 182: 55, # 'Х' - 183: 4, # 'и' - 184: 42, # 'И' - 185: 225, # '╣' - 186: 226, # '║' - 187: 227, # '╗' - 188: 228, # '╝' - 189: 23, # 'й' - 190: 60, # 'Й' - 191: 229, # '┐' - 192: 230, # '└' - 193: 231, # '┴' - 194: 232, # '┬' - 195: 233, # '├' - 196: 234, # '─' - 197: 235, # '┼' - 198: 11, # 'к' - 199: 36, # 'К' - 200: 236, # '╚' - 201: 237, # '╔' - 202: 238, # '╩' - 203: 239, # '╦' - 204: 240, # '╠' - 205: 241, # '═' - 206: 242, # '╬' - 207: 243, # '¤' - 208: 8, # 'л' - 209: 49, # 'Л' - 210: 12, # 'м' - 211: 38, # 'М' - 212: 5, # 'н' - 213: 31, # 'Н' - 214: 1, # 'о' - 215: 34, # 'О' - 216: 15, # 'п' - 217: 244, # '┘' - 218: 245, # '┌' - 219: 246, # '█' - 220: 247, # '▄' - 221: 35, # 'П' - 222: 16, # 'я' - 223: 248, # '▀' - 224: 43, # 'Я' - 225: 9, # 'р' - 226: 45, # 'Р' - 227: 7, # 'с' - 228: 32, # 'С' - 229: 6, # 'т' - 230: 40, # 'Т' - 231: 14, # 'у' - 232: 52, # 'У' - 233: 24, # 'ж' - 234: 56, # 'Ж' - 235: 10, # 'в' - 236: 33, # 'В' - 237: 17, # 'ь' - 238: 61, # 'Ь' - 239: 249, # '№' - 240: 250, # '\xad' - 241: 18, # 'ы' - 242: 62, # 'Ы' - 243: 20, # 'з' - 244: 51, # 'З' - 245: 25, # 'ш' - 246: 57, # 'Ш' - 247: 30, # 'э' - 248: 47, # 'Э' - 249: 29, # 'щ' - 250: 63, # 'Щ' - 251: 22, # 'ч' - 252: 50, # 'Ч' - 253: 251, # '§' - 254: 252, # '■' - 255: 255, # '\xa0' -} - -IBM855_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM855', - language='Russian', - char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -KOI8_R_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '─' - 129: 192, # '│' - 130: 193, # '┌' - 131: 194, # '┐' - 132: 195, # '└' - 133: 196, # '┘' - 134: 197, # '├' - 135: 198, # '┤' - 136: 199, # '┬' - 137: 200, # '┴' - 138: 201, # '┼' - 139: 202, # '▀' - 140: 203, # '▄' - 141: 204, # '█' - 142: 205, # '▌' - 143: 206, # '▐' - 144: 207, # '░' - 145: 208, # '▒' - 146: 209, # '▓' - 147: 210, # '⌠' - 148: 211, # '■' - 149: 212, # '∙' - 150: 213, # '√' - 151: 214, # '≈' - 152: 215, # '≤' - 153: 216, # '≥' - 154: 217, # '\xa0' - 155: 218, # '⌡' - 156: 219, # '°' - 157: 220, # '²' - 158: 221, # '·' - 159: 222, # '÷' - 160: 223, # '═' - 161: 224, # '║' - 162: 225, # '╒' - 163: 68, # 'ё' - 164: 226, # '╓' - 165: 227, # '╔' - 166: 228, # '╕' - 167: 229, # '╖' - 168: 230, # '╗' - 169: 231, # '╘' - 170: 232, # '╙' - 171: 233, # '╚' - 172: 234, # '╛' - 173: 235, # '╜' - 174: 236, # '╝' - 175: 237, # '╞' - 176: 238, # '╟' - 177: 239, # '╠' - 178: 240, # '╡' - 179: 241, # 'Ё' - 180: 242, # '╢' - 181: 243, # '╣' - 182: 244, # '╤' - 183: 245, # '╥' - 184: 246, # '╦' - 185: 247, # '╧' - 186: 248, # '╨' - 187: 249, # '╩' - 188: 250, # '╪' - 189: 251, # '╫' - 190: 252, # '╬' - 191: 253, # '©' - 192: 27, # 'ю' - 193: 3, # 'а' - 194: 21, # 'б' - 195: 28, # 'ц' - 196: 13, # 'д' - 197: 2, # 'е' - 198: 39, # 'ф' - 199: 19, # 'г' - 200: 26, # 'х' - 201: 4, # 'и' - 202: 23, # 'й' - 203: 11, # 'к' - 204: 8, # 'л' - 205: 12, # 'м' - 206: 5, # 'н' - 207: 1, # 'о' - 208: 15, # 'п' - 209: 16, # 'я' - 210: 9, # 'р' - 211: 7, # 'с' - 212: 6, # 'т' - 213: 14, # 'у' - 214: 24, # 'ж' - 215: 10, # 'в' - 216: 17, # 'ь' - 217: 18, # 'ы' - 218: 20, # 'з' - 219: 25, # 'ш' - 220: 30, # 'э' - 221: 29, # 'щ' - 222: 22, # 'ч' - 223: 54, # 'ъ' - 224: 59, # 'Ю' - 225: 37, # 'А' - 226: 44, # 'Б' - 227: 58, # 'Ц' - 228: 41, # 'Д' - 229: 48, # 'Е' - 230: 53, # 'Ф' - 231: 46, # 'Г' - 232: 55, # 'Х' - 233: 42, # 'И' - 234: 60, # 'Й' - 235: 36, # 'К' - 236: 49, # 'Л' - 237: 38, # 'М' - 238: 31, # 'Н' - 239: 34, # 'О' - 240: 35, # 'П' - 241: 43, # 'Я' - 242: 45, # 'Р' - 243: 32, # 'С' - 244: 40, # 'Т' - 245: 52, # 'У' - 246: 56, # 'Ж' - 247: 33, # 'В' - 248: 61, # 'Ь' - 249: 62, # 'Ы' - 250: 51, # 'З' - 251: 57, # 'Ш' - 252: 47, # 'Э' - 253: 63, # 'Щ' - 254: 50, # 'Ч' - 255: 70, # 'Ъ' -} - -KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='KOI8-R', - language='Russian', - char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 191, # '†' - 161: 192, # '°' - 162: 193, # 'Ґ' - 163: 194, # '£' - 164: 195, # '§' - 165: 196, # '•' - 166: 197, # '¶' - 167: 198, # 'І' - 168: 199, # '®' - 169: 200, # '©' - 170: 201, # '™' - 171: 202, # 'Ђ' - 172: 203, # 'ђ' - 173: 204, # '≠' - 174: 205, # 'Ѓ' - 175: 206, # 'ѓ' - 176: 207, # '∞' - 177: 208, # '±' - 178: 209, # '≤' - 179: 210, # '≥' - 180: 211, # 'і' - 181: 212, # 'µ' - 182: 213, # 'ґ' - 183: 214, # 'Ј' - 184: 215, # 'Є' - 185: 216, # 'є' - 186: 217, # 'Ї' - 187: 218, # 'ї' - 188: 219, # 'Љ' - 189: 220, # 'љ' - 190: 221, # 'Њ' - 191: 222, # 'њ' - 192: 223, # 'ј' - 193: 224, # 'Ѕ' - 194: 225, # '¬' - 195: 226, # '√' - 196: 227, # 'ƒ' - 197: 228, # '≈' - 198: 229, # '∆' - 199: 230, # '«' - 200: 231, # '»' - 201: 232, # '…' - 202: 233, # '\xa0' - 203: 234, # 'Ћ' - 204: 235, # 'ћ' - 205: 236, # 'Ќ' - 206: 237, # 'ќ' - 207: 238, # 'ѕ' - 208: 239, # '–' - 209: 240, # '—' - 210: 241, # '“' - 211: 242, # '”' - 212: 243, # '‘' - 213: 244, # '’' - 214: 245, # '÷' - 215: 246, # '„' - 216: 247, # 'Ў' - 217: 248, # 'ў' - 218: 249, # 'Џ' - 219: 250, # 'џ' - 220: 251, # '№' - 221: 252, # 'Ё' - 222: 68, # 'ё' - 223: 16, # 'я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 255, # '€' -} - -MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='MacCyrillic', - language='Russian', - char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '\x80' - 129: 192, # '\x81' - 130: 193, # '\x82' - 131: 194, # '\x83' - 132: 195, # '\x84' - 133: 196, # '\x85' - 134: 197, # '\x86' - 135: 198, # '\x87' - 136: 199, # '\x88' - 137: 200, # '\x89' - 138: 201, # '\x8a' - 139: 202, # '\x8b' - 140: 203, # '\x8c' - 141: 204, # '\x8d' - 142: 205, # '\x8e' - 143: 206, # '\x8f' - 144: 207, # '\x90' - 145: 208, # '\x91' - 146: 209, # '\x92' - 147: 210, # '\x93' - 148: 211, # '\x94' - 149: 212, # '\x95' - 150: 213, # '\x96' - 151: 214, # '\x97' - 152: 215, # '\x98' - 153: 216, # '\x99' - 154: 217, # '\x9a' - 155: 218, # '\x9b' - 156: 219, # '\x9c' - 157: 220, # '\x9d' - 158: 221, # '\x9e' - 159: 222, # '\x9f' - 160: 223, # '\xa0' - 161: 224, # 'Ё' - 162: 225, # 'Ђ' - 163: 226, # 'Ѓ' - 164: 227, # 'Є' - 165: 228, # 'Ѕ' - 166: 229, # 'І' - 167: 230, # 'Ї' - 168: 231, # 'Ј' - 169: 232, # 'Љ' - 170: 233, # 'Њ' - 171: 234, # 'Ћ' - 172: 235, # 'Ќ' - 173: 236, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 37, # 'А' - 177: 44, # 'Б' - 178: 33, # 'В' - 179: 46, # 'Г' - 180: 41, # 'Д' - 181: 48, # 'Е' - 182: 56, # 'Ж' - 183: 51, # 'З' - 184: 42, # 'И' - 185: 60, # 'Й' - 186: 36, # 'К' - 187: 49, # 'Л' - 188: 38, # 'М' - 189: 31, # 'Н' - 190: 34, # 'О' - 191: 35, # 'П' - 192: 45, # 'Р' - 193: 32, # 'С' - 194: 40, # 'Т' - 195: 52, # 'У' - 196: 53, # 'Ф' - 197: 55, # 'Х' - 198: 58, # 'Ц' - 199: 50, # 'Ч' - 200: 57, # 'Ш' - 201: 63, # 'Щ' - 202: 70, # 'Ъ' - 203: 62, # 'Ы' - 204: 61, # 'Ь' - 205: 47, # 'Э' - 206: 59, # 'Ю' - 207: 43, # 'Я' - 208: 3, # 'а' - 209: 21, # 'б' - 210: 10, # 'в' - 211: 19, # 'г' - 212: 13, # 'д' - 213: 2, # 'е' - 214: 24, # 'ж' - 215: 20, # 'з' - 216: 4, # 'и' - 217: 23, # 'й' - 218: 11, # 'к' - 219: 8, # 'л' - 220: 12, # 'м' - 221: 5, # 'н' - 222: 1, # 'о' - 223: 15, # 'п' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # '№' - 241: 68, # 'ё' - 242: 240, # 'ђ' - 243: 241, # 'ѓ' - 244: 242, # 'є' - 245: 243, # 'ѕ' - 246: 244, # 'і' - 247: 245, # 'ї' - 248: 246, # 'ј' - 249: 247, # 'љ' - 250: 248, # 'њ' - 251: 249, # 'ћ' - 252: 250, # 'ќ' - 253: 251, # '§' - 254: 252, # 'ў' - 255: 255, # 'џ' -} - -ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Russian', - char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langthaimodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langthaimodel.py deleted file mode 100644 index 9a37db5..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langthaimodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -THAI_LANG_MODEL = { - 5: { # 'ก' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 3, # 'ฎ' - 57: 2, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 2, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 2, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 3, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 1, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 30: { # 'ข' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 0, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 2, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 2, # 'ี' - 40: 3, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 24: { # 'ค' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 2, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 3, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 8: { # 'ง' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 1, # 'ฉ' - 34: 2, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 2, # 'ศ' - 46: 1, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 3, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 26: { # 'จ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 3, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 52: { # 'ฉ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 1, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 34: { # 'ช' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 1, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 51: { # 'ซ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 3, # 'ึ' - 27: 2, # 'ื' - 32: 1, # 'ุ' - 35: 1, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 1, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 47: { # 'ญ' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 3, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 2, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 58: { # 'ฎ' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 1, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 57: { # 'ฏ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 49: { # 'ฐ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 53: { # 'ฑ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 55: { # 'ฒ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 43: { # 'ณ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 3, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 3, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 3, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 20: { # 'ด' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 2, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 1, # 'ึ' - 27: 2, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 2, # 'ๆ' - 37: 2, # '็' - 6: 1, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 19: { # 'ต' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 2, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 2, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 1, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 2, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 44: { # 'ถ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 3, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 14: { # 'ท' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 3, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 3, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 1, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 3, # 'ศ' - 46: 1, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 48: { # 'ธ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 2, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 2, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 3: { # 'น' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 2, # 'ถ' - 14: 3, # 'ท' - 48: 3, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 1, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 3, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 3, # 'โ' - 29: 3, # 'ใ' - 33: 3, # 'ไ' - 50: 2, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 17: { # 'บ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 1, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 2, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 2, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 25: { # 'ป' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 1, # 'ฎ' - 57: 3, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 1, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 2, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 1, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 39: { # 'ผ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 1, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 0, # 'ุ' - 35: 3, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 1, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 62: { # 'ฝ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 1, # 'ี' - 40: 2, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 1, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 31: { # 'พ' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 2, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 1, # 'ึ' - 27: 3, # 'ื' - 32: 1, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 0, # '่' - 7: 1, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 54: { # 'ฟ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 45: { # 'ภ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 2, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 9: { # 'ม' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 2, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 1, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 2, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 16: { # 'ย' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 2, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 1, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 2, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 2: { # 'ร' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 2, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 3, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 3, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 3, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 2, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 2, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 3, # 'เ' - 28: 3, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 61: { # 'ฤ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 2, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 15: { # 'ล' - 5: 2, # 'ก' - 30: 3, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 3, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 2, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 2, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 12: { # 'ว' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 2, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 42: { # 'ศ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 2, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 3, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 2, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 46: { # 'ษ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 2, # 'ฎ' - 57: 1, # 'ฏ' - 49: 2, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 18: { # 'ส' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 3, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 2, # 'ภ' - 9: 3, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 0, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 1, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 21: { # 'ห' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 4: { # 'อ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 63: { # 'ฯ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 22: { # 'ะ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 1, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 10: { # 'ั' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 3, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 2, # 'ฐ' - 53: 0, # 'ฑ' - 55: 3, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 1: { # 'า' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 1, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 2, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 3, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 3, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 36: { # 'ำ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 23: { # 'ิ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 3, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 2, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 3, # 'ศ' - 46: 2, # 'ษ' - 18: 2, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 13: { # 'ี' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 40: { # 'ึ' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 3, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 27: { # 'ื' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 32: { # 'ุ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 3, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 1, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 1, # 'ศ' - 46: 2, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 35: { # 'ู' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 11: { # 'เ' - 5: 3, # 'ก' - 30: 3, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 3, # 'ฉ' - 34: 3, # 'ช' - 51: 2, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 3, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 3, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 28: { # 'แ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 3, # 'ต' - 44: 2, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 3, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 41: { # 'โ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 1, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 29: { # 'ใ' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 33: { # 'ไ' - 5: 1, # 'ก' - 30: 2, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 1, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 2, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 50: { # 'ๆ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 37: { # '็' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 6: { # '่' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 7: { # '้' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 38: { # '์' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 1, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 56: { # '๑' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 2, # '๑' - 59: 1, # '๒' - 60: 1, # '๕' - }, - 59: { # '๒' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 1, # '๑' - 59: 1, # '๒' - 60: 3, # '๕' - }, - 60: { # '๕' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 2, # '๑' - 59: 1, # '๒' - 60: 0, # '๕' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -TIS_620_THAI_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 182, # 'A' - 66: 106, # 'B' - 67: 107, # 'C' - 68: 100, # 'D' - 69: 183, # 'E' - 70: 184, # 'F' - 71: 185, # 'G' - 72: 101, # 'H' - 73: 94, # 'I' - 74: 186, # 'J' - 75: 187, # 'K' - 76: 108, # 'L' - 77: 109, # 'M' - 78: 110, # 'N' - 79: 111, # 'O' - 80: 188, # 'P' - 81: 189, # 'Q' - 82: 190, # 'R' - 83: 89, # 'S' - 84: 95, # 'T' - 85: 112, # 'U' - 86: 113, # 'V' - 87: 191, # 'W' - 88: 192, # 'X' - 89: 193, # 'Y' - 90: 194, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 64, # 'a' - 98: 72, # 'b' - 99: 73, # 'c' - 100: 114, # 'd' - 101: 74, # 'e' - 102: 115, # 'f' - 103: 116, # 'g' - 104: 102, # 'h' - 105: 81, # 'i' - 106: 201, # 'j' - 107: 117, # 'k' - 108: 90, # 'l' - 109: 103, # 'm' - 110: 78, # 'n' - 111: 82, # 'o' - 112: 96, # 'p' - 113: 202, # 'q' - 114: 91, # 'r' - 115: 79, # 's' - 116: 84, # 't' - 117: 104, # 'u' - 118: 105, # 'v' - 119: 97, # 'w' - 120: 98, # 'x' - 121: 92, # 'y' - 122: 203, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 209, # '\x80' - 129: 210, # '\x81' - 130: 211, # '\x82' - 131: 212, # '\x83' - 132: 213, # '\x84' - 133: 88, # '\x85' - 134: 214, # '\x86' - 135: 215, # '\x87' - 136: 216, # '\x88' - 137: 217, # '\x89' - 138: 218, # '\x8a' - 139: 219, # '\x8b' - 140: 220, # '\x8c' - 141: 118, # '\x8d' - 142: 221, # '\x8e' - 143: 222, # '\x8f' - 144: 223, # '\x90' - 145: 224, # '\x91' - 146: 99, # '\x92' - 147: 85, # '\x93' - 148: 83, # '\x94' - 149: 225, # '\x95' - 150: 226, # '\x96' - 151: 227, # '\x97' - 152: 228, # '\x98' - 153: 229, # '\x99' - 154: 230, # '\x9a' - 155: 231, # '\x9b' - 156: 232, # '\x9c' - 157: 233, # '\x9d' - 158: 234, # '\x9e' - 159: 235, # '\x9f' - 160: 236, # None - 161: 5, # 'ก' - 162: 30, # 'ข' - 163: 237, # 'ฃ' - 164: 24, # 'ค' - 165: 238, # 'ฅ' - 166: 75, # 'ฆ' - 167: 8, # 'ง' - 168: 26, # 'จ' - 169: 52, # 'ฉ' - 170: 34, # 'ช' - 171: 51, # 'ซ' - 172: 119, # 'ฌ' - 173: 47, # 'ญ' - 174: 58, # 'ฎ' - 175: 57, # 'ฏ' - 176: 49, # 'ฐ' - 177: 53, # 'ฑ' - 178: 55, # 'ฒ' - 179: 43, # 'ณ' - 180: 20, # 'ด' - 181: 19, # 'ต' - 182: 44, # 'ถ' - 183: 14, # 'ท' - 184: 48, # 'ธ' - 185: 3, # 'น' - 186: 17, # 'บ' - 187: 25, # 'ป' - 188: 39, # 'ผ' - 189: 62, # 'ฝ' - 190: 31, # 'พ' - 191: 54, # 'ฟ' - 192: 45, # 'ภ' - 193: 9, # 'ม' - 194: 16, # 'ย' - 195: 2, # 'ร' - 196: 61, # 'ฤ' - 197: 15, # 'ล' - 198: 239, # 'ฦ' - 199: 12, # 'ว' - 200: 42, # 'ศ' - 201: 46, # 'ษ' - 202: 18, # 'ส' - 203: 21, # 'ห' - 204: 76, # 'ฬ' - 205: 4, # 'อ' - 206: 66, # 'ฮ' - 207: 63, # 'ฯ' - 208: 22, # 'ะ' - 209: 10, # 'ั' - 210: 1, # 'า' - 211: 36, # 'ำ' - 212: 23, # 'ิ' - 213: 13, # 'ี' - 214: 40, # 'ึ' - 215: 27, # 'ื' - 216: 32, # 'ุ' - 217: 35, # 'ู' - 218: 86, # 'ฺ' - 219: 240, # None - 220: 241, # None - 221: 242, # None - 222: 243, # None - 223: 244, # '฿' - 224: 11, # 'เ' - 225: 28, # 'แ' - 226: 41, # 'โ' - 227: 29, # 'ใ' - 228: 33, # 'ไ' - 229: 245, # 'ๅ' - 230: 50, # 'ๆ' - 231: 37, # '็' - 232: 6, # '่' - 233: 7, # '้' - 234: 67, # '๊' - 235: 77, # '๋' - 236: 38, # '์' - 237: 93, # 'ํ' - 238: 246, # '๎' - 239: 247, # '๏' - 240: 68, # '๐' - 241: 56, # '๑' - 242: 59, # '๒' - 243: 65, # '๓' - 244: 69, # '๔' - 245: 60, # '๕' - 246: 70, # '๖' - 247: 80, # '๗' - 248: 71, # '๘' - 249: 87, # '๙' - 250: 248, # '๚' - 251: 249, # '๛' - 252: 250, # None - 253: 251, # None - 254: 252, # None - 255: 253, # None -} - -TIS_620_THAI_MODEL = SingleByteCharSetModel(charset_name='TIS-620', - language='Thai', - char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, - language_model=THAI_LANG_MODEL, - typical_positive_ratio=0.926386, - keep_ascii_letters=False, - alphabet='กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langturkishmodel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langturkishmodel.py deleted file mode 100644 index 43f4230..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/langturkishmodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -TURKISH_LANG_MODEL = { - 23: { # 'A' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 37: { # 'B' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 47: { # 'C' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 39: { # 'D' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 0, # 'ş' - }, - 29: { # 'E' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 52: { # 'F' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 1, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 2, # 'ş' - }, - 36: { # 'G' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 2, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 1, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 45: { # 'H' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 2, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 2, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 53: { # 'I' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 60: { # 'J' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 16: { # 'K' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 1, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 49: { # 'L' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 2, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 20: { # 'M' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 0, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 46: { # 'N' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 42: { # 'O' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 2, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 48: { # 'P' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 44: { # 'R' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 35: { # 'S' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 1, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 2, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 31: { # 'T' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 2, # 't' - 14: 2, # 'u' - 32: 1, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 51: { # 'U' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 38: { # 'V' - 23: 1, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 1, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 62: { # 'W' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 43: { # 'Y' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 0, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 1, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 56: { # 'Z' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 1: { # 'a' - 23: 3, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 1, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 21: { # 'b' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 3, # 'g' - 25: 1, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 2, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 28: { # 'c' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 2, # 'T' - 51: 2, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 3, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 1, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 1, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 2, # 'ş' - }, - 12: { # 'd' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 2: { # 'e' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 18: { # 'f' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 1, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 1, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 27: { # 'g' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 25: { # 'h' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 3: { # 'i' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 1, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 3, # 'g' - 25: 1, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 24: { # 'j' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 10: { # 'k' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 2, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 5: { # 'l' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 1, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 2, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 13: { # 'm' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 2, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 4: { # 'n' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 15: { # 'o' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 2, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 2, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 2, # 'ş' - }, - 26: { # 'p' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 7: { # 'r' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 1, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 8: { # 's' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 9: { # 't' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 14: { # 'u' - 23: 3, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 2, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 2, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 32: { # 'v' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 57: { # 'w' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 1, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 58: { # 'x' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 11: { # 'y' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 22: { # 'z' - 23: 2, # 'A' - 37: 2, # 'B' - 47: 1, # 'C' - 39: 2, # 'D' - 29: 3, # 'E' - 52: 1, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 2, # 'N' - 42: 2, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 3, # 'T' - 51: 2, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 1, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 2, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 1, # 'Ş' - 19: 2, # 'ş' - }, - 63: { # '·' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 54: { # 'Ç' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 3, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 50: { # 'Ö' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 2, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 1, # 'N' - 42: 2, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 1, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 1, # 's' - 9: 2, # 't' - 14: 0, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 55: { # 'Ü' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 59: { # 'â' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 0, # 'ş' - }, - 33: { # 'ç' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 0, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 61: { # 'î' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 1, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 34: { # 'ö' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 1, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 3, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 1, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 17: { # 'ü' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 30: { # 'ğ' - 23: 0, # 'A' - 37: 2, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 2, # 'N' - 42: 2, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 3, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 2, # 'İ' - 6: 2, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 41: { # 'İ' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 2, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 6: { # 'ı' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 40: { # 'Ş' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 2, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 0, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 3, # 'f' - 27: 0, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 1, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 1, # 'ü' - 30: 2, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 2, # 'ş' - }, - 19: { # 'ş' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 2, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 1, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -ISO_8859_9_TURKISH_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 255, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 255, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 255, # ' ' - 33: 255, # '!' - 34: 255, # '"' - 35: 255, # '#' - 36: 255, # '$' - 37: 255, # '%' - 38: 255, # '&' - 39: 255, # "'" - 40: 255, # '(' - 41: 255, # ')' - 42: 255, # '*' - 43: 255, # '+' - 44: 255, # ',' - 45: 255, # '-' - 46: 255, # '.' - 47: 255, # '/' - 48: 255, # '0' - 49: 255, # '1' - 50: 255, # '2' - 51: 255, # '3' - 52: 255, # '4' - 53: 255, # '5' - 54: 255, # '6' - 55: 255, # '7' - 56: 255, # '8' - 57: 255, # '9' - 58: 255, # ':' - 59: 255, # ';' - 60: 255, # '<' - 61: 255, # '=' - 62: 255, # '>' - 63: 255, # '?' - 64: 255, # '@' - 65: 23, # 'A' - 66: 37, # 'B' - 67: 47, # 'C' - 68: 39, # 'D' - 69: 29, # 'E' - 70: 52, # 'F' - 71: 36, # 'G' - 72: 45, # 'H' - 73: 53, # 'I' - 74: 60, # 'J' - 75: 16, # 'K' - 76: 49, # 'L' - 77: 20, # 'M' - 78: 46, # 'N' - 79: 42, # 'O' - 80: 48, # 'P' - 81: 69, # 'Q' - 82: 44, # 'R' - 83: 35, # 'S' - 84: 31, # 'T' - 85: 51, # 'U' - 86: 38, # 'V' - 87: 62, # 'W' - 88: 65, # 'X' - 89: 43, # 'Y' - 90: 56, # 'Z' - 91: 255, # '[' - 92: 255, # '\\' - 93: 255, # ']' - 94: 255, # '^' - 95: 255, # '_' - 96: 255, # '`' - 97: 1, # 'a' - 98: 21, # 'b' - 99: 28, # 'c' - 100: 12, # 'd' - 101: 2, # 'e' - 102: 18, # 'f' - 103: 27, # 'g' - 104: 25, # 'h' - 105: 3, # 'i' - 106: 24, # 'j' - 107: 10, # 'k' - 108: 5, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 15, # 'o' - 112: 26, # 'p' - 113: 64, # 'q' - 114: 7, # 'r' - 115: 8, # 's' - 116: 9, # 't' - 117: 14, # 'u' - 118: 32, # 'v' - 119: 57, # 'w' - 120: 58, # 'x' - 121: 11, # 'y' - 122: 22, # 'z' - 123: 255, # '{' - 124: 255, # '|' - 125: 255, # '}' - 126: 255, # '~' - 127: 255, # '\x7f' - 128: 180, # '\x80' - 129: 179, # '\x81' - 130: 178, # '\x82' - 131: 177, # '\x83' - 132: 176, # '\x84' - 133: 175, # '\x85' - 134: 174, # '\x86' - 135: 173, # '\x87' - 136: 172, # '\x88' - 137: 171, # '\x89' - 138: 170, # '\x8a' - 139: 169, # '\x8b' - 140: 168, # '\x8c' - 141: 167, # '\x8d' - 142: 166, # '\x8e' - 143: 165, # '\x8f' - 144: 164, # '\x90' - 145: 163, # '\x91' - 146: 162, # '\x92' - 147: 161, # '\x93' - 148: 160, # '\x94' - 149: 159, # '\x95' - 150: 101, # '\x96' - 151: 158, # '\x97' - 152: 157, # '\x98' - 153: 156, # '\x99' - 154: 155, # '\x9a' - 155: 154, # '\x9b' - 156: 153, # '\x9c' - 157: 152, # '\x9d' - 158: 151, # '\x9e' - 159: 106, # '\x9f' - 160: 150, # '\xa0' - 161: 149, # '¡' - 162: 148, # '¢' - 163: 147, # '£' - 164: 146, # '¤' - 165: 145, # '¥' - 166: 144, # '¦' - 167: 100, # '§' - 168: 143, # '¨' - 169: 142, # '©' - 170: 141, # 'ª' - 171: 140, # '«' - 172: 139, # '¬' - 173: 138, # '\xad' - 174: 137, # '®' - 175: 136, # '¯' - 176: 94, # '°' - 177: 80, # '±' - 178: 93, # '²' - 179: 135, # '³' - 180: 105, # '´' - 181: 134, # 'µ' - 182: 133, # '¶' - 183: 63, # '·' - 184: 132, # '¸' - 185: 131, # '¹' - 186: 130, # 'º' - 187: 129, # '»' - 188: 128, # '¼' - 189: 127, # '½' - 190: 126, # '¾' - 191: 125, # '¿' - 192: 124, # 'À' - 193: 104, # 'Á' - 194: 73, # 'Â' - 195: 99, # 'Ã' - 196: 79, # 'Ä' - 197: 85, # 'Å' - 198: 123, # 'Æ' - 199: 54, # 'Ç' - 200: 122, # 'È' - 201: 98, # 'É' - 202: 92, # 'Ê' - 203: 121, # 'Ë' - 204: 120, # 'Ì' - 205: 91, # 'Í' - 206: 103, # 'Î' - 207: 119, # 'Ï' - 208: 68, # 'Ğ' - 209: 118, # 'Ñ' - 210: 117, # 'Ò' - 211: 97, # 'Ó' - 212: 116, # 'Ô' - 213: 115, # 'Õ' - 214: 50, # 'Ö' - 215: 90, # '×' - 216: 114, # 'Ø' - 217: 113, # 'Ù' - 218: 112, # 'Ú' - 219: 111, # 'Û' - 220: 55, # 'Ü' - 221: 41, # 'İ' - 222: 40, # 'Ş' - 223: 86, # 'ß' - 224: 89, # 'à' - 225: 70, # 'á' - 226: 59, # 'â' - 227: 78, # 'ã' - 228: 71, # 'ä' - 229: 82, # 'å' - 230: 88, # 'æ' - 231: 33, # 'ç' - 232: 77, # 'è' - 233: 66, # 'é' - 234: 84, # 'ê' - 235: 83, # 'ë' - 236: 110, # 'ì' - 237: 75, # 'í' - 238: 61, # 'î' - 239: 96, # 'ï' - 240: 30, # 'ğ' - 241: 67, # 'ñ' - 242: 109, # 'ò' - 243: 74, # 'ó' - 244: 87, # 'ô' - 245: 102, # 'õ' - 246: 34, # 'ö' - 247: 95, # '÷' - 248: 81, # 'ø' - 249: 108, # 'ù' - 250: 76, # 'ú' - 251: 72, # 'û' - 252: 17, # 'ü' - 253: 6, # 'ı' - 254: 19, # 'ş' - 255: 107, # 'ÿ' -} - -ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-9', - language='Turkish', - char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, - language_model=TURKISH_LANG_MODEL, - typical_positive_ratio=0.97029, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş') - diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/latin1prober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/latin1prober.py deleted file mode 100644 index 7d1e8c2..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/latin1prober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState - -FREQ_CAT_NUM = 4 - -UDF = 0 # undefined -OTH = 1 # other -ASC = 2 # ascii capital letter -ASS = 3 # ascii small letter -ACV = 4 # accent capital vowel -ACO = 5 # accent capital other -ASV = 6 # accent small vowel -ASO = 7 # accent small other -CLASS_NUM = 8 # total classes - -Latin1_CharToClass = ( - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F - OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 - ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F - ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 - ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F - OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 - ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F - ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 - ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F - OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 - OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F - UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 - OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF - ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 - ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF - ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 - ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF - ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 - ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF - ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 - ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF -) - -# 0 : illegal -# 1 : very unlikely -# 2 : normal -# 3 : very likely -Latin1ClassModel = ( -# UDF OTH ASC ASS ACV ACO ASV ASO - 0, 0, 0, 0, 0, 0, 0, 0, # UDF - 0, 3, 3, 3, 3, 3, 3, 3, # OTH - 0, 3, 3, 3, 3, 3, 3, 3, # ASC - 0, 3, 3, 3, 1, 1, 3, 3, # ASS - 0, 3, 3, 3, 1, 2, 1, 2, # ACV - 0, 3, 3, 3, 3, 3, 3, 3, # ACO - 0, 3, 1, 3, 1, 1, 1, 3, # ASV - 0, 3, 1, 3, 1, 1, 3, 3, # ASO -) - - -class Latin1Prober(CharSetProber): - def __init__(self): - super(Latin1Prober, self).__init__() - self._last_char_class = None - self._freq_counter = None - self.reset() - - def reset(self): - self._last_char_class = OTH - self._freq_counter = [0] * FREQ_CAT_NUM - CharSetProber.reset(self) - - @property - def charset_name(self): - return "ISO-8859-1" - - @property - def language(self): - return "" - - def feed(self, byte_str): - byte_str = self.filter_with_english_letters(byte_str) - for c in byte_str: - char_class = Latin1_CharToClass[c] - freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) - + char_class] - if freq == 0: - self._state = ProbingState.NOT_ME - break - self._freq_counter[freq] += 1 - self._last_char_class = char_class - - return self.state - - def get_confidence(self): - if self.state == ProbingState.NOT_ME: - return 0.01 - - total = sum(self._freq_counter) - if total < 0.01: - confidence = 0.0 - else: - confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) - / total) - if confidence < 0.0: - confidence = 0.0 - # lower the confidence of latin1 so that other more accurate - # detector can take priority. - confidence = confidence * 0.73 - return confidence diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcharsetprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcharsetprober.py deleted file mode 100644 index 6256ecf..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcharsetprober.py +++ /dev/null @@ -1,91 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# Proofpoint, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState - - -class MultiByteCharSetProber(CharSetProber): - """ - MultiByteCharSetProber - """ - - def __init__(self, lang_filter=None): - super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) - self.distribution_analyzer = None - self.coding_sm = None - self._last_char = [0, 0] - - def reset(self): - super(MultiByteCharSetProber, self).reset() - if self.coding_sm: - self.coding_sm.reset() - if self.distribution_analyzer: - self.distribution_analyzer.reset() - self._last_char = [0, 0] - - @property - def charset_name(self): - raise NotImplementedError - - @property - def language(self): - raise NotImplementedError - - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.distribution_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - return self.distribution_analyzer.get_confidence() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcsgroupprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcsgroupprober.py deleted file mode 100644 index 530abe7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcsgroupprober.py +++ /dev/null @@ -1,54 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# Proofpoint, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetgroupprober import CharSetGroupProber -from .utf8prober import UTF8Prober -from .sjisprober import SJISProber -from .eucjpprober import EUCJPProber -from .gb2312prober import GB2312Prober -from .euckrprober import EUCKRProber -from .cp949prober import CP949Prober -from .big5prober import Big5Prober -from .euctwprober import EUCTWProber - - -class MBCSGroupProber(CharSetGroupProber): - def __init__(self, lang_filter=None): - super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) - self.probers = [ - UTF8Prober(), - SJISProber(), - EUCJPProber(), - GB2312Prober(), - EUCKRProber(), - CP949Prober(), - Big5Prober(), - EUCTWProber() - ] - self.reset() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcssm.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcssm.py deleted file mode 100644 index 8360d0f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/mbcssm.py +++ /dev/null @@ -1,572 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import MachineState - -# BIG5 - -BIG5_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 4,4,4,4,4,4,4,4, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 4,3,3,3,3,3,3,3, # a0 - a7 - 3,3,3,3,3,3,3,3, # a8 - af - 3,3,3,3,3,3,3,3, # b0 - b7 - 3,3,3,3,3,3,3,3, # b8 - bf - 3,3,3,3,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff -) - -BIG5_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 -) - -BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) - -BIG5_SM_MODEL = {'class_table': BIG5_CLS, - 'class_factor': 5, - 'state_table': BIG5_ST, - 'char_len_table': BIG5_CHAR_LEN_TABLE, - 'name': 'Big5'} - -# CP949 - -CP949_CLS = ( - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f - 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f - 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f - 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f - 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f - 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f - 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f - 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f - 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af - 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf - 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff -) - -CP949_ST = ( -#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = - MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 -) - -CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) - -CP949_SM_MODEL = {'class_table': CP949_CLS, - 'class_factor': 10, - 'state_table': CP949_ST, - 'char_len_table': CP949_CHAR_LEN_TABLE, - 'name': 'CP949'} - -# EUC-JP - -EUCJP_CLS = ( - 4,4,4,4,4,4,4,4, # 00 - 07 - 4,4,4,4,4,4,5,5, # 08 - 0f - 4,4,4,4,4,4,4,4, # 10 - 17 - 4,4,4,5,4,4,4,4, # 18 - 1f - 4,4,4,4,4,4,4,4, # 20 - 27 - 4,4,4,4,4,4,4,4, # 28 - 2f - 4,4,4,4,4,4,4,4, # 30 - 37 - 4,4,4,4,4,4,4,4, # 38 - 3f - 4,4,4,4,4,4,4,4, # 40 - 47 - 4,4,4,4,4,4,4,4, # 48 - 4f - 4,4,4,4,4,4,4,4, # 50 - 57 - 4,4,4,4,4,4,4,4, # 58 - 5f - 4,4,4,4,4,4,4,4, # 60 - 67 - 4,4,4,4,4,4,4,4, # 68 - 6f - 4,4,4,4,4,4,4,4, # 70 - 77 - 4,4,4,4,4,4,4,4, # 78 - 7f - 5,5,5,5,5,5,5,5, # 80 - 87 - 5,5,5,5,5,5,1,3, # 88 - 8f - 5,5,5,5,5,5,5,5, # 90 - 97 - 5,5,5,5,5,5,5,5, # 98 - 9f - 5,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,0,5 # f8 - ff -) - -EUCJP_ST = ( - 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f - 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 -) - -EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) - -EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, - 'class_factor': 6, - 'state_table': EUCJP_ST, - 'char_len_table': EUCJP_CHAR_LEN_TABLE, - 'name': 'EUC-JP'} - -# EUC-KR - -EUCKR_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 - 1,1,1,1,1,1,1,1, # 48 - 4f - 1,1,1,1,1,1,1,1, # 50 - 57 - 1,1,1,1,1,1,1,1, # 58 - 5f - 1,1,1,1,1,1,1,1, # 60 - 67 - 1,1,1,1,1,1,1,1, # 68 - 6f - 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,3,3,3, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,3,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 2,2,2,2,2,2,2,2, # e0 - e7 - 2,2,2,2,2,2,2,2, # e8 - ef - 2,2,2,2,2,2,2,2, # f0 - f7 - 2,2,2,2,2,2,2,0 # f8 - ff -) - -EUCKR_ST = ( - MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f -) - -EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) - -EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, - 'class_factor': 4, - 'state_table': EUCKR_ST, - 'char_len_table': EUCKR_CHAR_LEN_TABLE, - 'name': 'EUC-KR'} - -# EUC-TW - -EUCTW_CLS = ( - 2,2,2,2,2,2,2,2, # 00 - 07 - 2,2,2,2,2,2,0,0, # 08 - 0f - 2,2,2,2,2,2,2,2, # 10 - 17 - 2,2,2,0,2,2,2,2, # 18 - 1f - 2,2,2,2,2,2,2,2, # 20 - 27 - 2,2,2,2,2,2,2,2, # 28 - 2f - 2,2,2,2,2,2,2,2, # 30 - 37 - 2,2,2,2,2,2,2,2, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,2, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,6,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,3,4,4,4,4,4,4, # a0 - a7 - 5,5,1,1,1,1,1,1, # a8 - af - 1,1,1,1,1,1,1,1, # b0 - b7 - 1,1,1,1,1,1,1,1, # b8 - bf - 1,1,3,1,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff -) - -EUCTW_ST = ( - MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 - MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 - MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f -) - -EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) - -EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, - 'class_factor': 7, - 'state_table': EUCTW_ST, - 'char_len_table': EUCTW_CHAR_LEN_TABLE, - 'name': 'x-euc-tw'} - -# GB2312 - -GB2312_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 3,3,3,3,3,3,3,3, # 30 - 37 - 3,3,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,4, # 78 - 7f - 5,6,6,6,6,6,6,6, # 80 - 87 - 6,6,6,6,6,6,6,6, # 88 - 8f - 6,6,6,6,6,6,6,6, # 90 - 97 - 6,6,6,6,6,6,6,6, # 98 - 9f - 6,6,6,6,6,6,6,6, # a0 - a7 - 6,6,6,6,6,6,6,6, # a8 - af - 6,6,6,6,6,6,6,6, # b0 - b7 - 6,6,6,6,6,6,6,6, # b8 - bf - 6,6,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 6,6,6,6,6,6,6,6, # e0 - e7 - 6,6,6,6,6,6,6,6, # e8 - ef - 6,6,6,6,6,6,6,6, # f0 - f7 - 6,6,6,6,6,6,6,0 # f8 - ff -) - -GB2312_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 - 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f -) - -# To be accurate, the length of class 6 can be either 2 or 4. -# But it is not necessary to discriminate between the two since -# it is used for frequency analysis only, and we are validating -# each code range there as well. So it is safe to set it to be -# 2 here. -GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) - -GB2312_SM_MODEL = {'class_table': GB2312_CLS, - 'class_factor': 7, - 'state_table': GB2312_ST, - 'char_len_table': GB2312_CHAR_LEN_TABLE, - 'name': 'GB2312'} - -# Shift_JIS - -SJIS_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 3,3,3,3,3,2,2,3, # 80 - 87 - 3,3,3,3,3,3,3,3, # 88 - 8f - 3,3,3,3,3,3,3,3, # 90 - 97 - 3,3,3,3,3,3,3,3, # 98 - 9f - #0xa0 is illegal in sjis encoding, but some pages does - #contain such byte. We need to be more error forgiven. - 2,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,4,4,4, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,0,0,0) # f8 - ff - - -SJIS_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 -) - -SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) - -SJIS_SM_MODEL = {'class_table': SJIS_CLS, - 'class_factor': 6, - 'state_table': SJIS_ST, - 'char_len_table': SJIS_CHAR_LEN_TABLE, - 'name': 'Shift_JIS'} - -# UCS2-BE - -UCS2BE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff -) - -UCS2BE_ST = ( - 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 - 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f - 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 - 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f - 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 -) - -UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) - -UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, - 'class_factor': 6, - 'state_table': UCS2BE_ST, - 'char_len_table': UCS2BE_CHAR_LEN_TABLE, - 'name': 'UTF-16BE'} - -# UCS2-LE - -UCS2LE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff -) - -UCS2LE_ST = ( - 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 - 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f - 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 - 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f - 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 -) - -UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) - -UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, - 'class_factor': 6, - 'state_table': UCS2LE_ST, - 'char_len_table': UCS2LE_CHAR_LEN_TABLE, - 'name': 'UTF-16LE'} - -# UTF-8 - -UTF8_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 - 1,1,1,1,1,1,1,1, # 48 - 4f - 1,1,1,1,1,1,1,1, # 50 - 57 - 1,1,1,1,1,1,1,1, # 58 - 5f - 1,1,1,1,1,1,1,1, # 60 - 67 - 1,1,1,1,1,1,1,1, # 68 - 6f - 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 2,2,2,2,3,3,3,3, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 5,5,5,5,5,5,5,5, # a0 - a7 - 5,5,5,5,5,5,5,5, # a8 - af - 5,5,5,5,5,5,5,5, # b0 - b7 - 5,5,5,5,5,5,5,5, # b8 - bf - 0,0,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 7,8,8,8,8,8,8,8, # e0 - e7 - 8,8,8,8,8,9,8,8, # e8 - ef - 10,11,11,11,11,11,11,11, # f0 - f7 - 12,13,13,13,14,15,0,0 # f8 - ff -) - -UTF8_ST = ( - MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 - 9, 11, 8, 7, 6, 5, 4, 3,#08-0f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f - MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f - MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f - MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f - MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af - MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf -) - -UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) - -UTF8_SM_MODEL = {'class_table': UTF8_CLS, - 'class_factor': 16, - 'state_table': UTF8_ST, - 'char_len_table': UTF8_CHAR_LEN_TABLE, - 'name': 'UTF-8'} diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/metadata/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/metadata/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/metadata/languages.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/metadata/languages.py deleted file mode 100644 index 3237d5a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/metadata/languages.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Metadata about languages used by our model training code for our -SingleByteCharSetProbers. Could be used for other things in the future. - -This code is based on the language metadata from the uchardet project. -""" -from __future__ import absolute_import, print_function - -from string import ascii_letters - - -# TODO: Add Ukranian (KOI8-U) - -class Language(object): - """Metadata about a language useful for training models - - :ivar name: The human name for the language, in English. - :type name: str - :ivar iso_code: 2-letter ISO 639-1 if possible, 3-letter ISO code otherwise, - or use another catalog as a last resort. - :type iso_code: str - :ivar use_ascii: Whether or not ASCII letters should be included in trained - models. - :type use_ascii: bool - :ivar charsets: The charsets we want to support and create data for. - :type charsets: list of str - :ivar alphabet: The characters in the language's alphabet. If `use_ascii` is - `True`, you only need to add those not in the ASCII set. - :type alphabet: str - :ivar wiki_start_pages: The Wikipedia pages to start from if we're crawling - Wikipedia for training data. - :type wiki_start_pages: list of str - """ - def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, - alphabet=None, wiki_start_pages=None): - super(Language, self).__init__() - self.name = name - self.iso_code = iso_code - self.use_ascii = use_ascii - self.charsets = charsets - if self.use_ascii: - if alphabet: - alphabet += ascii_letters - else: - alphabet = ascii_letters - elif not alphabet: - raise ValueError('Must supply alphabet if use_ascii is False') - self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None - self.wiki_start_pages = wiki_start_pages - - def __repr__(self): - return '{}({})'.format(self.__class__.__name__, - ', '.join('{}={!r}'.format(k, v) - for k, v in self.__dict__.items() - if not k.startswith('_'))) - - -LANGUAGES = {'Arabic': Language(name='Arabic', - iso_code='ar', - use_ascii=False, - # We only support encodings that use isolated - # forms, because the current recommendation is - # that the rendering system handles presentation - # forms. This means we purposefully skip IBM864. - charsets=['ISO-8859-6', 'WINDOWS-1256', - 'CP720', 'CP864'], - alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ', - wiki_start_pages=[u'الصفحة_الرئيسية']), - 'Belarusian': Language(name='Belarusian', - iso_code='be', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM866', 'MacCyrillic'], - alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ' - u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'), - wiki_start_pages=[u'Галоўная_старонка']), - 'Bulgarian': Language(name='Bulgarian', - iso_code='bg', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM855'], - alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ' - u'абвгдежзийклмнопрстуфхцчшщъьюя'), - wiki_start_pages=[u'Начална_страница']), - 'Czech': Language(name='Czech', - iso_code='cz', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ', - wiki_start_pages=[u'Hlavní_strana']), - 'Danish': Language(name='Danish', - iso_code='da', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'æøåÆØÅ', - wiki_start_pages=[u'Forside']), - 'German': Language(name='German', - iso_code='de', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - alphabet=u'äöüßÄÖÜ', - wiki_start_pages=[u'Wikipedia:Hauptseite']), - 'Greek': Language(name='Greek', - iso_code='el', - use_ascii=False, - charsets=['ISO-8859-7', 'WINDOWS-1253'], - alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ' - u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'), - wiki_start_pages=[u'Πύλη:Κύρια']), - 'English': Language(name='English', - iso_code='en', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Main_Page']), - 'Esperanto': Language(name='Esperanto', - iso_code='eo', - # Q, W, X, and Y not used at all - use_ascii=False, - charsets=['ISO-8859-3'], - alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz' - u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'), - wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']), - 'Spanish': Language(name='Spanish', - iso_code='es', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ', - wiki_start_pages=[u'Wikipedia:Portada']), - 'Estonian': Language(name='Estonian', - iso_code='et', - use_ascii=False, - charsets=['ISO-8859-4', 'ISO-8859-13', - 'WINDOWS-1257'], - # C, F, Š, Q, W, X, Y, Z, Ž are only for - # loanwords - alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ' - u'abdeghijklmnoprstuvõäöü'), - wiki_start_pages=[u'Esileht']), - 'Finnish': Language(name='Finnish', - iso_code='fi', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÅÄÖŠŽåäöšž', - wiki_start_pages=[u'Wikipedia:Etusivu']), - 'French': Language(name='French', - iso_code='fr', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ', - wiki_start_pages=[u'Wikipédia:Accueil_principal', - u'Bœuf (animal)']), - 'Hebrew': Language(name='Hebrew', - iso_code='he', - use_ascii=False, - charsets=['ISO-8859-8', 'WINDOWS-1255'], - alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ', - wiki_start_pages=[u'עמוד_ראשי']), - 'Croatian': Language(name='Croatian', - iso_code='hr', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčćdđefghijklmnoprsštuvzž' - u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stranica']), - 'Hungarian': Language(name='Hungarian', - iso_code='hu', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű' - u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'), - wiki_start_pages=[u'Kezdőlap']), - 'Italian': Language(name='Italian', - iso_code='it', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÀÈÉÌÒÓÙàèéìòóù', - wiki_start_pages=[u'Pagina_principale']), - 'Lithuanian': Language(name='Lithuanian', - iso_code='lt', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, and X not used at all - alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ' - u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'), - wiki_start_pages=[u'Pagrindinis_puslapis']), - 'Latvian': Language(name='Latvian', - iso_code='lv', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, X, Y are only for loanwords - alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ' - u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'), - wiki_start_pages=[u'Sākumlapa']), - 'Macedonian': Language(name='Macedonian', - iso_code='mk', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ' - u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'), - wiki_start_pages=[u'Главна_страница']), - 'Dutch': Language(name='Dutch', - iso_code='nl', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Hoofdpagina']), - 'Polish': Language(name='Polish', - iso_code='pl', - # Q and X are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ' - u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'), - wiki_start_pages=[u'Wikipedia:Strona_główna']), - 'Portuguese': Language(name='Portuguese', - iso_code='pt', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú', - wiki_start_pages=[u'Wikipédia:Página_principal']), - 'Romanian': Language(name='Romanian', - iso_code='ro', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'ăâîșțĂÂÎȘȚ', - wiki_start_pages=[u'Pagina_principală']), - 'Russian': Language(name='Russian', - iso_code='ru', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'KOI8-R', 'MacCyrillic', 'IBM866', - 'IBM855'], - alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя' - u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'), - wiki_start_pages=[u'Заглавная_страница']), - 'Slovak': Language(name='Slovak', - iso_code='sk', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ', - wiki_start_pages=[u'Hlavná_stránka']), - 'Slovene': Language(name='Slovene', - iso_code='sl', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčdefghijklmnoprsštuvzž' - u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stran']), - # Serbian can be written in both Latin and Cyrillic, but there's no - # simple way to get the Latin alphabet pages from Wikipedia through - # the API, so for now we just support Cyrillic. - 'Serbian': Language(name='Serbian', - iso_code='sr', - alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ' - u'абвгдђежзијклљмнњопрстћуфхцчџш'), - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - wiki_start_pages=[u'Главна_страна']), - 'Thai': Language(name='Thai', - iso_code='th', - use_ascii=False, - charsets=['ISO-8859-11', 'TIS-620', 'CP874'], - alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛', - wiki_start_pages=[u'หน้าหลัก']), - 'Turkish': Language(name='Turkish', - iso_code='tr', - # Q, W, and X are not used by Turkish - use_ascii=False, - charsets=['ISO-8859-3', 'ISO-8859-9', - 'WINDOWS-1254'], - alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû' - u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'), - wiki_start_pages=[u'Ana_Sayfa']), - 'Vietnamese': Language(name='Vietnamese', - iso_code='vi', - use_ascii=False, - # Windows-1258 is the only common 8-bit - # Vietnamese encoding supported by Python. - # From Wikipedia: - # For systems that lack support for Unicode, - # dozens of 8-bit Vietnamese code pages are - # available.[1] The most common are VISCII - # (TCVN 5712:1993), VPS, and Windows-1258.[3] - # Where ASCII is required, such as when - # ensuring readability in plain text e-mail, - # Vietnamese letters are often encoded - # according to Vietnamese Quoted-Readable - # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] - # though usage of either variable-width - # scheme has declined dramatically following - # the adoption of Unicode on the World Wide - # Web. - charsets=['WINDOWS-1258'], - alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy' - u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'), - wiki_start_pages=[u'Chữ_Quốc_ngữ']), - } diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcharsetprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcharsetprober.py deleted file mode 100644 index 46ba835..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcharsetprober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from collections import namedtuple - -from .charsetprober import CharSetProber -from .enums import CharacterCategory, ProbingState, SequenceLikelihood - - -SingleByteCharSetModel = namedtuple('SingleByteCharSetModel', - ['charset_name', - 'language', - 'char_to_order_map', - 'language_model', - 'typical_positive_ratio', - 'keep_ascii_letters', - 'alphabet']) - - -class SingleByteCharSetProber(CharSetProber): - SAMPLE_SIZE = 64 - SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 - POSITIVE_SHORTCUT_THRESHOLD = 0.95 - NEGATIVE_SHORTCUT_THRESHOLD = 0.05 - - def __init__(self, model, reversed=False, name_prober=None): - super(SingleByteCharSetProber, self).__init__() - self._model = model - # TRUE if we need to reverse every pair in the model lookup - self._reversed = reversed - # Optional auxiliary prober for name decision - self._name_prober = name_prober - self._last_order = None - self._seq_counters = None - self._total_seqs = None - self._total_char = None - self._freq_char = None - self.reset() - - def reset(self): - super(SingleByteCharSetProber, self).reset() - # char order of last character - self._last_order = 255 - self._seq_counters = [0] * SequenceLikelihood.get_num_categories() - self._total_seqs = 0 - self._total_char = 0 - # characters that fall in our sampling range - self._freq_char = 0 - - @property - def charset_name(self): - if self._name_prober: - return self._name_prober.charset_name - else: - return self._model.charset_name - - @property - def language(self): - if self._name_prober: - return self._name_prober.language - else: - return self._model.language - - def feed(self, byte_str): - # TODO: Make filter_international_words keep things in self.alphabet - if not self._model.keep_ascii_letters: - byte_str = self.filter_international_words(byte_str) - if not byte_str: - return self.state - char_to_order_map = self._model.char_to_order_map - language_model = self._model.language_model - for char in byte_str: - order = char_to_order_map.get(char, CharacterCategory.UNDEFINED) - # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but - # CharacterCategory.SYMBOL is actually 253, so we use CONTROL - # to make it closer to the original intent. The only difference - # is whether or not we count digits and control characters for - # _total_char purposes. - if order < CharacterCategory.CONTROL: - self._total_char += 1 - # TODO: Follow uchardet's lead and discount confidence for frequent - # control characters. - # See https://github.com/BYVoid/uchardet/commit/55b4f23971db61 - if order < self.SAMPLE_SIZE: - self._freq_char += 1 - if self._last_order < self.SAMPLE_SIZE: - self._total_seqs += 1 - if not self._reversed: - lm_cat = language_model[self._last_order][order] - else: - lm_cat = language_model[order][self._last_order] - self._seq_counters[lm_cat] += 1 - self._last_order = order - - charset_name = self._model.charset_name - if self.state == ProbingState.DETECTING: - if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: - confidence = self.get_confidence() - if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, we have a winner', - charset_name, confidence) - self._state = ProbingState.FOUND_IT - elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, below negative ' - 'shortcut threshhold %s', charset_name, - confidence, - self.NEGATIVE_SHORTCUT_THRESHOLD) - self._state = ProbingState.NOT_ME - - return self.state - - def get_confidence(self): - r = 0.01 - if self._total_seqs > 0: - r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / - self._total_seqs / self._model.typical_positive_ratio) - r = r * self._freq_char / self._total_char - if r >= 1.0: - r = 0.99 - return r diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcsgroupprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcsgroupprober.py deleted file mode 100644 index bdeef4e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sbcsgroupprober.py +++ /dev/null @@ -1,83 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetgroupprober import CharSetGroupProber -from .hebrewprober import HebrewProber -from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL, - WINDOWS_1251_BULGARIAN_MODEL) -from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL -from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL -# from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL, -# WINDOWS_1250_HUNGARIAN_MODEL) -from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL, - ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL, - MACCYRILLIC_RUSSIAN_MODEL, - WINDOWS_1251_RUSSIAN_MODEL) -from .langthaimodel import TIS_620_THAI_MODEL -from .langturkishmodel import ISO_8859_9_TURKISH_MODEL -from .sbcharsetprober import SingleByteCharSetProber - - -class SBCSGroupProber(CharSetGroupProber): - def __init__(self): - super(SBCSGroupProber, self).__init__() - hebrew_prober = HebrewProber() - logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - False, hebrew_prober) - # TODO: See if using ISO-8859-8 Hebrew model works better here, since - # it's actually the visual one - visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - True, hebrew_prober) - hebrew_prober.set_model_probers(logical_hebrew_prober, - visual_hebrew_prober) - # TODO: ORDER MATTERS HERE. I changed the order vs what was in master - # and several tests failed that did not before. Some thought - # should be put into the ordering, and we should consider making - # order not matter here, because that is very counter-intuitive. - self.probers = [ - SingleByteCharSetProber(WINDOWS_1251_RUSSIAN_MODEL), - SingleByteCharSetProber(KOI8_R_RUSSIAN_MODEL), - SingleByteCharSetProber(ISO_8859_5_RUSSIAN_MODEL), - SingleByteCharSetProber(MACCYRILLIC_RUSSIAN_MODEL), - SingleByteCharSetProber(IBM866_RUSSIAN_MODEL), - SingleByteCharSetProber(IBM855_RUSSIAN_MODEL), - SingleByteCharSetProber(ISO_8859_7_GREEK_MODEL), - SingleByteCharSetProber(WINDOWS_1253_GREEK_MODEL), - SingleByteCharSetProber(ISO_8859_5_BULGARIAN_MODEL), - SingleByteCharSetProber(WINDOWS_1251_BULGARIAN_MODEL), - # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) - # after we retrain model. - # SingleByteCharSetProber(ISO_8859_2_HUNGARIAN_MODEL), - # SingleByteCharSetProber(WINDOWS_1250_HUNGARIAN_MODEL), - SingleByteCharSetProber(TIS_620_THAI_MODEL), - SingleByteCharSetProber(ISO_8859_9_TURKISH_MODEL), - hebrew_prober, - logical_hebrew_prober, - visual_hebrew_prober, - ] - self.reset() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sjisprober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sjisprober.py deleted file mode 100644 index 9e29623..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/sjisprober.py +++ /dev/null @@ -1,92 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import SJISDistributionAnalysis -from .jpcntx import SJISContextAnalysis -from .mbcssm import SJIS_SM_MODEL -from .enums import ProbingState, MachineState - - -class SJISProber(MultiByteCharSetProber): - def __init__(self): - super(SJISProber, self).__init__() - self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) - self.distribution_analyzer = SJISDistributionAnalysis() - self.context_analyzer = SJISContextAnalysis() - self.reset() - - def reset(self): - super(SJISProber, self).reset() - self.context_analyzer.reset() - - @property - def charset_name(self): - return self.context_analyzer.charset_name - - @property - def language(self): - return "Japanese" - - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.context_analyzer.feed(self._last_char[2 - char_len:], - char_len) - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 - - char_len], char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - context_conf = self.context_analyzer.get_confidence() - distrib_conf = self.distribution_analyzer.get_confidence() - return max(context_conf, distrib_conf) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/universaldetector.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/universaldetector.py deleted file mode 100644 index 055a8ac..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/universaldetector.py +++ /dev/null @@ -1,286 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### -""" -Module containing the UniversalDetector detector class, which is the primary -class a user of ``chardet`` should use. - -:author: Mark Pilgrim (initial port to Python) -:author: Shy Shalom (original C code) -:author: Dan Blanchard (major refactoring for 3.0) -:author: Ian Cordasco -""" - - -import codecs -import logging -import re - -from .charsetgroupprober import CharSetGroupProber -from .enums import InputState, LanguageFilter, ProbingState -from .escprober import EscCharSetProber -from .latin1prober import Latin1Prober -from .mbcsgroupprober import MBCSGroupProber -from .sbcsgroupprober import SBCSGroupProber - - -class UniversalDetector(object): - """ - The ``UniversalDetector`` class underlies the ``chardet.detect`` function - and coordinates all of the different charset probers. - - To get a ``dict`` containing an encoding and its confidence, you can simply - run: - - .. code:: - - u = UniversalDetector() - u.feed(some_bytes) - u.close() - detected = u.result - - """ - - MINIMUM_THRESHOLD = 0.20 - HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') - ESC_DETECTOR = re.compile(b'(\033|~{)') - WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') - ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', - 'iso-8859-2': 'Windows-1250', - 'iso-8859-5': 'Windows-1251', - 'iso-8859-6': 'Windows-1256', - 'iso-8859-7': 'Windows-1253', - 'iso-8859-8': 'Windows-1255', - 'iso-8859-9': 'Windows-1254', - 'iso-8859-13': 'Windows-1257'} - - def __init__(self, lang_filter=LanguageFilter.ALL): - self._esc_charset_prober = None - self._charset_probers = [] - self.result = None - self.done = None - self._got_data = None - self._input_state = None - self._last_char = None - self.lang_filter = lang_filter - self.logger = logging.getLogger(__name__) - self._has_win_bytes = None - self.reset() - - def reset(self): - """ - Reset the UniversalDetector and all of its probers back to their - initial states. This is called by ``__init__``, so you only need to - call this directly in between analyses of different documents. - """ - self.result = {'encoding': None, 'confidence': 0.0, 'language': None} - self.done = False - self._got_data = False - self._has_win_bytes = False - self._input_state = InputState.PURE_ASCII - self._last_char = b'' - if self._esc_charset_prober: - self._esc_charset_prober.reset() - for prober in self._charset_probers: - prober.reset() - - def feed(self, byte_str): - """ - Takes a chunk of a document and feeds it through all of the relevant - charset probers. - - After calling ``feed``, you can check the value of the ``done`` - attribute to see if you need to continue feeding the - ``UniversalDetector`` more data, or if it has made a prediction - (in the ``result`` attribute). - - .. note:: - You should always call ``close`` when you're done feeding in your - document if ``done`` is not already ``True``. - """ - if self.done: - return - - if not len(byte_str): - return - - if not isinstance(byte_str, bytearray): - byte_str = bytearray(byte_str) - - # First check for known BOMs, since these are guaranteed to be correct - if not self._got_data: - # If the data starts with BOM, we know it is UTF - if byte_str.startswith(codecs.BOM_UTF8): - # EF BB BF UTF-8 with BOM - self.result = {'encoding': "UTF-8-SIG", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith((codecs.BOM_UTF32_LE, - codecs.BOM_UTF32_BE)): - # FF FE 00 00 UTF-32, little-endian BOM - # 00 00 FE FF UTF-32, big-endian BOM - self.result = {'encoding': "UTF-32", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\xFE\xFF\x00\x00'): - # FE FF 00 00 UCS-4, unusual octet order BOM (3412) - self.result = {'encoding': "X-ISO-10646-UCS-4-3412", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\x00\x00\xFF\xFE'): - # 00 00 FF FE UCS-4, unusual octet order BOM (2143) - self.result = {'encoding': "X-ISO-10646-UCS-4-2143", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): - # FF FE UTF-16, little endian BOM - # FE FF UTF-16, big endian BOM - self.result = {'encoding': "UTF-16", - 'confidence': 1.0, - 'language': ''} - - self._got_data = True - if self.result['encoding'] is not None: - self.done = True - return - - # If none of those matched and we've only see ASCII so far, check - # for high bytes and escape sequences - if self._input_state == InputState.PURE_ASCII: - if self.HIGH_BYTE_DETECTOR.search(byte_str): - self._input_state = InputState.HIGH_BYTE - elif self._input_state == InputState.PURE_ASCII and \ - self.ESC_DETECTOR.search(self._last_char + byte_str): - self._input_state = InputState.ESC_ASCII - - self._last_char = byte_str[-1:] - - # If we've seen escape sequences, use the EscCharSetProber, which - # uses a simple state machine to check for known escape sequences in - # HZ and ISO-2022 encodings, since those are the only encodings that - # use such sequences. - if self._input_state == InputState.ESC_ASCII: - if not self._esc_charset_prober: - self._esc_charset_prober = EscCharSetProber(self.lang_filter) - if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': - self._esc_charset_prober.charset_name, - 'confidence': - self._esc_charset_prober.get_confidence(), - 'language': - self._esc_charset_prober.language} - self.done = True - # If we've seen high bytes (i.e., those with values greater than 127), - # we need to do more complicated checks using all our multi-byte and - # single-byte probers that are left. The single-byte probers - # use character bigram distributions to determine the encoding, whereas - # the multi-byte probers use a combination of character unigram and - # bigram distributions. - elif self._input_state == InputState.HIGH_BYTE: - if not self._charset_probers: - self._charset_probers = [MBCSGroupProber(self.lang_filter)] - # If we're checking non-CJK encodings, use single-byte prober - if self.lang_filter & LanguageFilter.NON_CJK: - self._charset_probers.append(SBCSGroupProber()) - self._charset_probers.append(Latin1Prober()) - for prober in self._charset_probers: - if prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': prober.charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language} - self.done = True - break - if self.WIN_BYTE_DETECTOR.search(byte_str): - self._has_win_bytes = True - - def close(self): - """ - Stop analyzing the current document and come up with a final - prediction. - - :returns: The ``result`` attribute, a ``dict`` with the keys - `encoding`, `confidence`, and `language`. - """ - # Don't bother with checks if we're already done - if self.done: - return self.result - self.done = True - - if not self._got_data: - self.logger.debug('no data received!') - - # Default to ASCII if it is all we've seen so far - elif self._input_state == InputState.PURE_ASCII: - self.result = {'encoding': 'ascii', - 'confidence': 1.0, - 'language': ''} - - # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD - elif self._input_state == InputState.HIGH_BYTE: - prober_confidence = None - max_prober_confidence = 0.0 - max_prober = None - for prober in self._charset_probers: - if not prober: - continue - prober_confidence = prober.get_confidence() - if prober_confidence > max_prober_confidence: - max_prober_confidence = prober_confidence - max_prober = prober - if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): - charset_name = max_prober.charset_name - lower_charset_name = max_prober.charset_name.lower() - confidence = max_prober.get_confidence() - # Use Windows encoding name instead of ISO-8859 if we saw any - # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): - if self._has_win_bytes: - charset_name = self.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - self.result = {'encoding': charset_name, - 'confidence': confidence, - 'language': max_prober.language} - - # Log all prober confidences if none met MINIMUM_THRESHOLD - if self.logger.getEffectiveLevel() <= logging.DEBUG: - if self.result['encoding'] is None: - self.logger.debug('no probers hit minimum threshold') - for group_prober in self._charset_probers: - if not group_prober: - continue - if isinstance(group_prober, CharSetGroupProber): - for prober in group_prober.probers: - self.logger.debug('%s %s confidence = %s', - prober.charset_name, - prober.language, - prober.get_confidence()) - else: - self.logger.debug('%s %s confidence = %s', - group_prober.charset_name, - group_prober.language, - group_prober.get_confidence()) - return self.result diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/utf8prober.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/utf8prober.py deleted file mode 100644 index 6c3196c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/utf8prober.py +++ /dev/null @@ -1,82 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState -from .codingstatemachine import CodingStateMachine -from .mbcssm import UTF8_SM_MODEL - - - -class UTF8Prober(CharSetProber): - ONE_CHAR_PROB = 0.5 - - def __init__(self): - super(UTF8Prober, self).__init__() - self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) - self._num_mb_chars = None - self.reset() - - def reset(self): - super(UTF8Prober, self).reset() - self.coding_sm.reset() - self._num_mb_chars = 0 - - @property - def charset_name(self): - return "utf-8" - - @property - def language(self): - return "" - - def feed(self, byte_str): - for c in byte_str: - coding_state = self.coding_sm.next_state(c) - if coding_state == MachineState.ERROR: - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - if self.coding_sm.get_current_charlen() >= 2: - self._num_mb_chars += 1 - - if self.state == ProbingState.DETECTING: - if self.get_confidence() > self.SHORTCUT_THRESHOLD: - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - unlike = 0.99 - if self._num_mb_chars < 6: - unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars - return 1.0 - unlike - else: - return unlike diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/version.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/version.py deleted file mode 100644 index 70369b9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/chardet/version.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -This module exists only to simplify retrieving the version number of chardet -from within setup.py and from chardet subpackages. - -:author: Dan Blanchard (dan.blanchard@gmail.com) -""" - -__version__ = "4.0.0" -VERSION = __version__.split('.') diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/__init__.py deleted file mode 100644 index b149ed7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from .initialise import init, deinit, reinit, colorama_text -from .ansi import Fore, Back, Style, Cursor -from .ansitowin32 import AnsiToWin32 - -__version__ = '0.4.4' diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansi.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansi.py deleted file mode 100644 index 11ec695..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansi.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -''' -This module generates ANSI character codes to printing colors to terminals. -See: http://en.wikipedia.org/wiki/ANSI_escape_code -''' - -CSI = '\033[' -OSC = '\033]' -BEL = '\a' - - -def code_to_chars(code): - return CSI + str(code) + 'm' - -def set_title(title): - return OSC + '2;' + title + BEL - -def clear_screen(mode=2): - return CSI + str(mode) + 'J' - -def clear_line(mode=2): - return CSI + str(mode) + 'K' - - -class AnsiCodes(object): - def __init__(self): - # the subclasses declare class attributes which are numbers. - # Upon instantiation we define instance attributes, which are the same - # as the class attributes but wrapped with the ANSI escape sequence - for name in dir(self): - if not name.startswith('_'): - value = getattr(self, name) - setattr(self, name, code_to_chars(value)) - - -class AnsiCursor(object): - def UP(self, n=1): - return CSI + str(n) + 'A' - def DOWN(self, n=1): - return CSI + str(n) + 'B' - def FORWARD(self, n=1): - return CSI + str(n) + 'C' - def BACK(self, n=1): - return CSI + str(n) + 'D' - def POS(self, x=1, y=1): - return CSI + str(y) + ';' + str(x) + 'H' - - -class AnsiFore(AnsiCodes): - BLACK = 30 - RED = 31 - GREEN = 32 - YELLOW = 33 - BLUE = 34 - MAGENTA = 35 - CYAN = 36 - WHITE = 37 - RESET = 39 - - # These are fairly well supported, but not part of the standard. - LIGHTBLACK_EX = 90 - LIGHTRED_EX = 91 - LIGHTGREEN_EX = 92 - LIGHTYELLOW_EX = 93 - LIGHTBLUE_EX = 94 - LIGHTMAGENTA_EX = 95 - LIGHTCYAN_EX = 96 - LIGHTWHITE_EX = 97 - - -class AnsiBack(AnsiCodes): - BLACK = 40 - RED = 41 - GREEN = 42 - YELLOW = 43 - BLUE = 44 - MAGENTA = 45 - CYAN = 46 - WHITE = 47 - RESET = 49 - - # These are fairly well supported, but not part of the standard. - LIGHTBLACK_EX = 100 - LIGHTRED_EX = 101 - LIGHTGREEN_EX = 102 - LIGHTYELLOW_EX = 103 - LIGHTBLUE_EX = 104 - LIGHTMAGENTA_EX = 105 - LIGHTCYAN_EX = 106 - LIGHTWHITE_EX = 107 - - -class AnsiStyle(AnsiCodes): - BRIGHT = 1 - DIM = 2 - NORMAL = 22 - RESET_ALL = 0 - -Fore = AnsiFore() -Back = AnsiBack() -Style = AnsiStyle() -Cursor = AnsiCursor() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansitowin32.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansitowin32.py deleted file mode 100644 index 6039a05..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/ansitowin32.py +++ /dev/null @@ -1,258 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import re -import sys -import os - -from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style, BEL -from .winterm import WinTerm, WinColor, WinStyle -from .win32 import windll, winapi_test - - -winterm = None -if windll is not None: - winterm = WinTerm() - - -class StreamWrapper(object): - ''' - Wraps a stream (such as stdout), acting as a transparent proxy for all - attribute access apart from method 'write()', which is delegated to our - Converter instance. - ''' - def __init__(self, wrapped, converter): - # double-underscore everything to prevent clashes with names of - # attributes on the wrapped stream object. - self.__wrapped = wrapped - self.__convertor = converter - - def __getattr__(self, name): - return getattr(self.__wrapped, name) - - def __enter__(self, *args, **kwargs): - # special method lookup bypasses __getattr__/__getattribute__, see - # https://stackoverflow.com/questions/12632894/why-doesnt-getattr-work-with-exit - # thus, contextlib magic methods are not proxied via __getattr__ - return self.__wrapped.__enter__(*args, **kwargs) - - def __exit__(self, *args, **kwargs): - return self.__wrapped.__exit__(*args, **kwargs) - - def write(self, text): - self.__convertor.write(text) - - def isatty(self): - stream = self.__wrapped - if 'PYCHARM_HOSTED' in os.environ: - if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__): - return True - try: - stream_isatty = stream.isatty - except AttributeError: - return False - else: - return stream_isatty() - - @property - def closed(self): - stream = self.__wrapped - try: - return stream.closed - except AttributeError: - return True - - -class AnsiToWin32(object): - ''' - Implements a 'write()' method which, on Windows, will strip ANSI character - sequences from the text, and if outputting to a tty, will convert them into - win32 function calls. - ''' - ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer - ANSI_OSC_RE = re.compile('\001?\033\\]([^\a]*)(\a)\002?') # Operating System Command - - def __init__(self, wrapped, convert=None, strip=None, autoreset=False): - # The wrapped stream (normally sys.stdout or sys.stderr) - self.wrapped = wrapped - - # should we reset colors to defaults after every .write() - self.autoreset = autoreset - - # create the proxy wrapping our output stream - self.stream = StreamWrapper(wrapped, self) - - on_windows = os.name == 'nt' - # We test if the WinAPI works, because even if we are on Windows - # we may be using a terminal that doesn't support the WinAPI - # (e.g. Cygwin Terminal). In this case it's up to the terminal - # to support the ANSI codes. - conversion_supported = on_windows and winapi_test() - - # should we strip ANSI sequences from our output? - if strip is None: - strip = conversion_supported or (not self.stream.closed and not self.stream.isatty()) - self.strip = strip - - # should we should convert ANSI sequences into win32 calls? - if convert is None: - convert = conversion_supported and not self.stream.closed and self.stream.isatty() - self.convert = convert - - # dict of ansi codes to win32 functions and parameters - self.win32_calls = self.get_win32_calls() - - # are we wrapping stderr? - self.on_stderr = self.wrapped is sys.stderr - - def should_wrap(self): - ''' - True if this class is actually needed. If false, then the output - stream will not be affected, nor will win32 calls be issued, so - wrapping stdout is not actually required. This will generally be - False on non-Windows platforms, unless optional functionality like - autoreset has been requested using kwargs to init() - ''' - return self.convert or self.strip or self.autoreset - - def get_win32_calls(self): - if self.convert and winterm: - return { - AnsiStyle.RESET_ALL: (winterm.reset_all, ), - AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), - AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), - AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), - AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), - AnsiFore.RED: (winterm.fore, WinColor.RED), - AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), - AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), - AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), - AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), - AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), - AnsiFore.WHITE: (winterm.fore, WinColor.GREY), - AnsiFore.RESET: (winterm.fore, ), - AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), - AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), - AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), - AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), - AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), - AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), - AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), - AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), - AnsiBack.BLACK: (winterm.back, WinColor.BLACK), - AnsiBack.RED: (winterm.back, WinColor.RED), - AnsiBack.GREEN: (winterm.back, WinColor.GREEN), - AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), - AnsiBack.BLUE: (winterm.back, WinColor.BLUE), - AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), - AnsiBack.CYAN: (winterm.back, WinColor.CYAN), - AnsiBack.WHITE: (winterm.back, WinColor.GREY), - AnsiBack.RESET: (winterm.back, ), - AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), - AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), - AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), - AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), - AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), - AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), - AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), - AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), - } - return dict() - - def write(self, text): - if self.strip or self.convert: - self.write_and_convert(text) - else: - self.wrapped.write(text) - self.wrapped.flush() - if self.autoreset: - self.reset_all() - - - def reset_all(self): - if self.convert: - self.call_win32('m', (0,)) - elif not self.strip and not self.stream.closed: - self.wrapped.write(Style.RESET_ALL) - - - def write_and_convert(self, text): - ''' - Write the given text to our wrapped stream, stripping any ANSI - sequences from the text, and optionally converting them into win32 - calls. - ''' - cursor = 0 - text = self.convert_osc(text) - for match in self.ANSI_CSI_RE.finditer(text): - start, end = match.span() - self.write_plain_text(text, cursor, start) - self.convert_ansi(*match.groups()) - cursor = end - self.write_plain_text(text, cursor, len(text)) - - - def write_plain_text(self, text, start, end): - if start < end: - self.wrapped.write(text[start:end]) - self.wrapped.flush() - - - def convert_ansi(self, paramstring, command): - if self.convert: - params = self.extract_params(command, paramstring) - self.call_win32(command, params) - - - def extract_params(self, command, paramstring): - if command in 'Hf': - params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) - while len(params) < 2: - # defaults: - params = params + (1,) - else: - params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) - if len(params) == 0: - # defaults: - if command in 'JKm': - params = (0,) - elif command in 'ABCD': - params = (1,) - - return params - - - def call_win32(self, command, params): - if command == 'm': - for param in params: - if param in self.win32_calls: - func_args = self.win32_calls[param] - func = func_args[0] - args = func_args[1:] - kwargs = dict(on_stderr=self.on_stderr) - func(*args, **kwargs) - elif command in 'J': - winterm.erase_screen(params[0], on_stderr=self.on_stderr) - elif command in 'K': - winterm.erase_line(params[0], on_stderr=self.on_stderr) - elif command in 'Hf': # cursor position - absolute - winterm.set_cursor_position(params, on_stderr=self.on_stderr) - elif command in 'ABCD': # cursor position - relative - n = params[0] - # A - up, B - down, C - forward, D - back - x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] - winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) - - - def convert_osc(self, text): - for match in self.ANSI_OSC_RE.finditer(text): - start, end = match.span() - text = text[:start] + text[end:] - paramstring, command = match.groups() - if command == BEL: - if paramstring.count(";") == 1: - params = paramstring.split(";") - # 0 - change title and icon (we will only change title) - # 1 - change icon (we don't support this) - # 2 - change title - if params[0] in '02': - winterm.set_title(params[1]) - return text diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/initialise.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/initialise.py deleted file mode 100644 index 430d066..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/initialise.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import atexit -import contextlib -import sys - -from .ansitowin32 import AnsiToWin32 - - -orig_stdout = None -orig_stderr = None - -wrapped_stdout = None -wrapped_stderr = None - -atexit_done = False - - -def reset_all(): - if AnsiToWin32 is not None: # Issue #74: objects might become None at exit - AnsiToWin32(orig_stdout).reset_all() - - -def init(autoreset=False, convert=None, strip=None, wrap=True): - - if not wrap and any([autoreset, convert, strip]): - raise ValueError('wrap=False conflicts with any other arg=True') - - global wrapped_stdout, wrapped_stderr - global orig_stdout, orig_stderr - - orig_stdout = sys.stdout - orig_stderr = sys.stderr - - if sys.stdout is None: - wrapped_stdout = None - else: - sys.stdout = wrapped_stdout = \ - wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - if sys.stderr is None: - wrapped_stderr = None - else: - sys.stderr = wrapped_stderr = \ - wrap_stream(orig_stderr, convert, strip, autoreset, wrap) - - global atexit_done - if not atexit_done: - atexit.register(reset_all) - atexit_done = True - - -def deinit(): - if orig_stdout is not None: - sys.stdout = orig_stdout - if orig_stderr is not None: - sys.stderr = orig_stderr - - -@contextlib.contextmanager -def colorama_text(*args, **kwargs): - init(*args, **kwargs) - try: - yield - finally: - deinit() - - -def reinit(): - if wrapped_stdout is not None: - sys.stdout = wrapped_stdout - if wrapped_stderr is not None: - sys.stderr = wrapped_stderr - - -def wrap_stream(stream, convert, strip, autoreset, wrap): - if wrap: - wrapper = AnsiToWin32(stream, - convert=convert, strip=strip, autoreset=autoreset) - if wrapper.should_wrap(): - stream = wrapper.stream - return stream diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/win32.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/win32.py deleted file mode 100644 index c2d8360..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/win32.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. - -# from winbase.h -STDOUT = -11 -STDERR = -12 - -try: - import ctypes - from ctypes import LibraryLoader - windll = LibraryLoader(ctypes.WinDLL) - from ctypes import wintypes -except (AttributeError, ImportError): - windll = None - SetConsoleTextAttribute = lambda *_: None - winapi_test = lambda *_: None -else: - from ctypes import byref, Structure, c_char, POINTER - - COORD = wintypes._COORD - - class CONSOLE_SCREEN_BUFFER_INFO(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("dwSize", COORD), - ("dwCursorPosition", COORD), - ("wAttributes", wintypes.WORD), - ("srWindow", wintypes.SMALL_RECT), - ("dwMaximumWindowSize", COORD), - ] - def __str__(self): - return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( - self.dwSize.Y, self.dwSize.X - , self.dwCursorPosition.Y, self.dwCursorPosition.X - , self.wAttributes - , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right - , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X - ) - - _GetStdHandle = windll.kernel32.GetStdHandle - _GetStdHandle.argtypes = [ - wintypes.DWORD, - ] - _GetStdHandle.restype = wintypes.HANDLE - - _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo - _GetConsoleScreenBufferInfo.argtypes = [ - wintypes.HANDLE, - POINTER(CONSOLE_SCREEN_BUFFER_INFO), - ] - _GetConsoleScreenBufferInfo.restype = wintypes.BOOL - - _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute - _SetConsoleTextAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - ] - _SetConsoleTextAttribute.restype = wintypes.BOOL - - _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition - _SetConsoleCursorPosition.argtypes = [ - wintypes.HANDLE, - COORD, - ] - _SetConsoleCursorPosition.restype = wintypes.BOOL - - _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA - _FillConsoleOutputCharacterA.argtypes = [ - wintypes.HANDLE, - c_char, - wintypes.DWORD, - COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputCharacterA.restype = wintypes.BOOL - - _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute - _FillConsoleOutputAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - wintypes.DWORD, - COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputAttribute.restype = wintypes.BOOL - - _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW - _SetConsoleTitleW.argtypes = [ - wintypes.LPCWSTR - ] - _SetConsoleTitleW.restype = wintypes.BOOL - - def _winapi_test(handle): - csbi = CONSOLE_SCREEN_BUFFER_INFO() - success = _GetConsoleScreenBufferInfo( - handle, byref(csbi)) - return bool(success) - - def winapi_test(): - return any(_winapi_test(h) for h in - (_GetStdHandle(STDOUT), _GetStdHandle(STDERR))) - - def GetConsoleScreenBufferInfo(stream_id=STDOUT): - handle = _GetStdHandle(stream_id) - csbi = CONSOLE_SCREEN_BUFFER_INFO() - success = _GetConsoleScreenBufferInfo( - handle, byref(csbi)) - return csbi - - def SetConsoleTextAttribute(stream_id, attrs): - handle = _GetStdHandle(stream_id) - return _SetConsoleTextAttribute(handle, attrs) - - def SetConsoleCursorPosition(stream_id, position, adjust=True): - position = COORD(*position) - # If the position is out of range, do nothing. - if position.Y <= 0 or position.X <= 0: - return - # Adjust for Windows' SetConsoleCursorPosition: - # 1. being 0-based, while ANSI is 1-based. - # 2. expecting (x,y), while ANSI uses (y,x). - adjusted_position = COORD(position.Y - 1, position.X - 1) - if adjust: - # Adjust for viewport's scroll position - sr = GetConsoleScreenBufferInfo(STDOUT).srWindow - adjusted_position.Y += sr.Top - adjusted_position.X += sr.Left - # Resume normal processing - handle = _GetStdHandle(stream_id) - return _SetConsoleCursorPosition(handle, adjusted_position) - - def FillConsoleOutputCharacter(stream_id, char, length, start): - handle = _GetStdHandle(stream_id) - char = c_char(char.encode()) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - success = _FillConsoleOutputCharacterA( - handle, char, length, start, byref(num_written)) - return num_written.value - - def FillConsoleOutputAttribute(stream_id, attr, length, start): - ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' - handle = _GetStdHandle(stream_id) - attribute = wintypes.WORD(attr) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - return _FillConsoleOutputAttribute( - handle, attribute, length, start, byref(num_written)) - - def SetConsoleTitle(title): - return _SetConsoleTitleW(title) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/winterm.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/winterm.py deleted file mode 100644 index 0fdb4ec..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/colorama/winterm.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from . import win32 - - -# from wincon.h -class WinColor(object): - BLACK = 0 - BLUE = 1 - GREEN = 2 - CYAN = 3 - RED = 4 - MAGENTA = 5 - YELLOW = 6 - GREY = 7 - -# from wincon.h -class WinStyle(object): - NORMAL = 0x00 # dim text, dim background - BRIGHT = 0x08 # bright text, dim background - BRIGHT_BACKGROUND = 0x80 # dim text, bright background - -class WinTerm(object): - - def __init__(self): - self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes - self.set_attrs(self._default) - self._default_fore = self._fore - self._default_back = self._back - self._default_style = self._style - # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. - # So that LIGHT_EX colors and BRIGHT style do not clobber each other, - # we track them separately, since LIGHT_EX is overwritten by Fore/Back - # and BRIGHT is overwritten by Style codes. - self._light = 0 - - def get_attrs(self): - return self._fore + self._back * 16 + (self._style | self._light) - - def set_attrs(self, value): - self._fore = value & 7 - self._back = (value >> 4) & 7 - self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) - - def reset_all(self, on_stderr=None): - self.set_attrs(self._default) - self.set_console(attrs=self._default) - self._light = 0 - - def fore(self, fore=None, light=False, on_stderr=False): - if fore is None: - fore = self._default_fore - self._fore = fore - # Emulate LIGHT_EX with BRIGHT Style - if light: - self._light |= WinStyle.BRIGHT - else: - self._light &= ~WinStyle.BRIGHT - self.set_console(on_stderr=on_stderr) - - def back(self, back=None, light=False, on_stderr=False): - if back is None: - back = self._default_back - self._back = back - # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style - if light: - self._light |= WinStyle.BRIGHT_BACKGROUND - else: - self._light &= ~WinStyle.BRIGHT_BACKGROUND - self.set_console(on_stderr=on_stderr) - - def style(self, style=None, on_stderr=False): - if style is None: - style = self._default_style - self._style = style - self.set_console(on_stderr=on_stderr) - - def set_console(self, attrs=None, on_stderr=False): - if attrs is None: - attrs = self.get_attrs() - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleTextAttribute(handle, attrs) - - def get_position(self, handle): - position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition - # Because Windows coordinates are 0-based, - # and win32.SetConsoleCursorPosition expects 1-based. - position.X += 1 - position.Y += 1 - return position - - def set_cursor_position(self, position=None, on_stderr=False): - if position is None: - # I'm not currently tracking the position, so there is no default. - # position = self.get_position() - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleCursorPosition(handle, position) - - def cursor_adjust(self, x, y, on_stderr=False): - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - position = self.get_position(handle) - adjusted_position = (position.Y + y, position.X + x) - win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) - - def erase_screen(self, mode=0, on_stderr=False): - # 0 should clear from the cursor to the end of the screen. - # 1 should clear from the cursor to the beginning of the screen. - # 2 should clear the entire screen, and move cursor to (1,1) - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - csbi = win32.GetConsoleScreenBufferInfo(handle) - # get the number of character cells in the current buffer - cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y - # get number of character cells before current cursor position - cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X - if mode == 0: - from_coord = csbi.dwCursorPosition - cells_to_erase = cells_in_screen - cells_before_cursor - elif mode == 1: - from_coord = win32.COORD(0, 0) - cells_to_erase = cells_before_cursor - elif mode == 2: - from_coord = win32.COORD(0, 0) - cells_to_erase = cells_in_screen - else: - # invalid mode - return - # fill the entire screen with blanks - win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) - # now set the buffer's attributes accordingly - win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) - if mode == 2: - # put the cursor where needed - win32.SetConsoleCursorPosition(handle, (1, 1)) - - def erase_line(self, mode=0, on_stderr=False): - # 0 should clear from the cursor to the end of the line. - # 1 should clear from the cursor to the beginning of the line. - # 2 should clear the entire line. - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - csbi = win32.GetConsoleScreenBufferInfo(handle) - if mode == 0: - from_coord = csbi.dwCursorPosition - cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X - elif mode == 1: - from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) - cells_to_erase = csbi.dwCursorPosition.X - elif mode == 2: - from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) - cells_to_erase = csbi.dwSize.X - else: - # invalid mode - return - # fill the entire screen with blanks - win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) - # now set the buffer's attributes accordingly - win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) - - def set_title(self, title): - win32.SetConsoleTitle(title) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/__init__.py deleted file mode 100644 index 492c2c7..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2019 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import logging - -__version__ = '0.3.2' - -class DistlibException(Exception): - pass - -try: - from logging import NullHandler -except ImportError: # pragma: no cover - class NullHandler(logging.Handler): - def handle(self, record): pass - def emit(self, record): pass - def createLock(self): self.lock = None - -logger = logging.getLogger(__name__) -logger.addHandler(NullHandler()) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/__init__.py deleted file mode 100644 index f7dbf4c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Modules copied from Python 3 standard libraries, for internal use only. - -Individual classes and functions are found in d2._backport.misc. Intended -usage is to always import things missing from 3.1 from that module: the -built-in/stdlib objects will be used if found. -""" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/misc.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/misc.py deleted file mode 100644 index cfb318d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/misc.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Backports for individual classes and functions.""" - -import os -import sys - -__all__ = ['cache_from_source', 'callable', 'fsencode'] - - -try: - from imp import cache_from_source -except ImportError: - def cache_from_source(py_file, debug=__debug__): - ext = debug and 'c' or 'o' - return py_file + ext - - -try: - callable = callable -except NameError: - from collections import Callable - - def callable(obj): - return isinstance(obj, Callable) - - -try: - fsencode = os.fsencode -except AttributeError: - def fsencode(filename): - if isinstance(filename, bytes): - return filename - elif isinstance(filename, str): - return filename.encode(sys.getfilesystemencoding()) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/shutil.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/shutil.py deleted file mode 100644 index 10ed362..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/shutil.py +++ /dev/null @@ -1,764 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Utility functions for copying and archiving files and directory trees. - -XXX The functions here don't copy the resource fork or other metadata on Mac. - -""" - -import os -import sys -import stat -from os.path import abspath -import fnmatch -try: - from collections.abc import Callable -except ImportError: - from collections import Callable -import errno -from . import tarfile - -try: - import bz2 - _BZ2_SUPPORTED = True -except ImportError: - _BZ2_SUPPORTED = False - -try: - from pwd import getpwnam -except ImportError: - getpwnam = None - -try: - from grp import getgrnam -except ImportError: - getgrnam = None - -__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", - "copytree", "move", "rmtree", "Error", "SpecialFileError", - "ExecError", "make_archive", "get_archive_formats", - "register_archive_format", "unregister_archive_format", - "get_unpack_formats", "register_unpack_format", - "unregister_unpack_format", "unpack_archive", "ignore_patterns"] - -class Error(EnvironmentError): - pass - -class SpecialFileError(EnvironmentError): - """Raised when trying to do a kind of operation (e.g. copying) which is - not supported on a special file (e.g. a named pipe)""" - -class ExecError(EnvironmentError): - """Raised when a command could not be executed""" - -class ReadError(EnvironmentError): - """Raised when an archive cannot be read""" - -class RegistryError(Exception): - """Raised when a registry operation with the archiving - and unpacking registries fails""" - - -try: - WindowsError -except NameError: - WindowsError = None - -def copyfileobj(fsrc, fdst, length=16*1024): - """copy data from file-like object fsrc to file-like object fdst""" - while 1: - buf = fsrc.read(length) - if not buf: - break - fdst.write(buf) - -def _samefile(src, dst): - # Macintosh, Unix. - if hasattr(os.path, 'samefile'): - try: - return os.path.samefile(src, dst) - except OSError: - return False - - # All other platforms: check for same pathname. - return (os.path.normcase(os.path.abspath(src)) == - os.path.normcase(os.path.abspath(dst))) - -def copyfile(src, dst): - """Copy data from src to dst""" - if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) - - for fn in [src, dst]: - try: - st = os.stat(fn) - except OSError: - # File most likely does not exist - pass - else: - # XXX What about other special files? (sockets, devices...) - if stat.S_ISFIFO(st.st_mode): - raise SpecialFileError("`%s` is a named pipe" % fn) - - with open(src, 'rb') as fsrc: - with open(dst, 'wb') as fdst: - copyfileobj(fsrc, fdst) - -def copymode(src, dst): - """Copy mode bits from src to dst""" - if hasattr(os, 'chmod'): - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - os.chmod(dst, mode) - -def copystat(src, dst): - """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - if hasattr(os, 'utime'): - os.utime(dst, (st.st_atime, st.st_mtime)) - if hasattr(os, 'chmod'): - os.chmod(dst, mode) - if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - try: - os.chflags(dst, st.st_flags) - except OSError as why: - if (not hasattr(errno, 'EOPNOTSUPP') or - why.errno != errno.EOPNOTSUPP): - raise - -def copy(src, dst): - """Copy data and mode bits ("cp src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copymode(src, dst) - -def copy2(src, dst): - """Copy data and all stat info ("cp -p src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copystat(src, dst) - -def ignore_patterns(*patterns): - """Function that can be used as copytree() ignore parameter. - - Patterns is a sequence of glob-style patterns - that are used to exclude files""" - def _ignore_patterns(path, names): - ignored_names = [] - for pattern in patterns: - ignored_names.extend(fnmatch.filter(names, pattern)) - return set(ignored_names) - return _ignore_patterns - -def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, - ignore_dangling_symlinks=False): - """Recursively copy a directory tree. - - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. If the file pointed by the symlink doesn't - exist, an exception will be added in the list of errors raised in - an Error exception at the end of the copy process. - - You can set the optional ignore_dangling_symlinks flag to true if you - want to silence this exception. Notice that this has no effect on - platforms that don't support os.symlink. - - The optional ignore argument is a callable. If given, it - is called with the `src` parameter, which is the directory - being visited by copytree(), and `names` which is the list of - `src` contents, as returned by os.listdir(): - - callable(src, names) -> ignored_names - - Since copytree() is called recursively, the callable will be - called once for each directory that is copied. It returns a - list of names relative to the `src` directory that should - not be copied. - - The optional copy_function argument is a callable that will be used - to copy each file. It will be called with the source path and the - destination path as arguments. By default, copy2() is used, but any - function that supports the same signature (like copy()) can be used. - - """ - names = os.listdir(src) - if ignore is not None: - ignored_names = ignore(src, names) - else: - ignored_names = set() - - os.makedirs(dst) - errors = [] - for name in names: - if name in ignored_names: - continue - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if os.path.islink(srcname): - linkto = os.readlink(srcname) - if symlinks: - os.symlink(linkto, dstname) - else: - # ignore dangling symlink if the flag is on - if not os.path.exists(linkto) and ignore_dangling_symlinks: - continue - # otherwise let the copy occurs. copy2 will raise an error - copy_function(srcname, dstname) - elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore, copy_function) - else: - # Will raise a SpecialFileError for unsupported file types - copy_function(srcname, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except Error as err: - errors.extend(err.args[0]) - except EnvironmentError as why: - errors.append((srcname, dstname, str(why))) - try: - copystat(src, dst) - except OSError as why: - if WindowsError is not None and isinstance(why, WindowsError): - # Copying file access times may fail on Windows - pass - else: - errors.extend((src, dst, str(why))) - if errors: - raise Error(errors) - -def rmtree(path, ignore_errors=False, onerror=None): - """Recursively delete a directory tree. - - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, - path, exc_info) where func is os.listdir, os.remove, or os.rmdir; - path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. - - """ - if ignore_errors: - def onerror(*args): - pass - elif onerror is None: - def onerror(*args): - raise - try: - if os.path.islink(path): - # symlinks to directories are forbidden, see bug #1669 - raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns - return - names = [] - try: - names = os.listdir(path) - except os.error: - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) - try: - mode = os.lstat(fullname).st_mode - except os.error: - mode = 0 - if stat.S_ISDIR(mode): - rmtree(fullname, ignore_errors, onerror) - else: - try: - os.remove(fullname) - except os.error: - onerror(os.remove, fullname, sys.exc_info()) - try: - os.rmdir(path) - except os.error: - onerror(os.rmdir, path, sys.exc_info()) - - -def _basename(path): - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. - return os.path.basename(path.rstrip(os.path.sep)) - -def move(src, dst): - """Recursively move a file or directory to another location. This is - similar to the Unix "mv" command. - - If the destination is a directory or a symlink to a directory, the source - is moved inside the directory. The destination path must not already - exist. - - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. - - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. - A lot more could be done here... A look at a mv.c shows a lot of - the issues this implementation glosses over. - - """ - real_dst = dst - if os.path.isdir(dst): - if _samefile(src, dst): - # We might be on a case insensitive filesystem, - # perform the rename anyway. - os.rename(src, dst) - return - - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error("Destination path '%s' already exists" % real_dst) - try: - os.rename(src, real_dst) - except OSError: - if os.path.isdir(src): - if _destinsrc(src, dst): - raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) - copytree(src, real_dst, symlinks=True) - rmtree(src) - else: - copy2(src, real_dst) - os.unlink(src) - -def _destinsrc(src, dst): - src = abspath(src) - dst = abspath(dst) - if not src.endswith(os.path.sep): - src += os.path.sep - if not dst.endswith(os.path.sep): - dst += os.path.sep - return dst.startswith(src) - -def _get_gid(name): - """Returns a gid, given a group name.""" - if getgrnam is None or name is None: - return None - try: - result = getgrnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _get_uid(name): - """Returns an uid, given a user name.""" - if getpwnam is None or name is None: - return None - try: - result = getpwnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, - owner=None, group=None, logger=None): - """Create a (possibly compressed) tar file from all the files under - 'base_dir'. - - 'compress' must be "gzip" (the default), "bzip2", or None. - - 'owner' and 'group' can be used to define an owner and a group for the - archive that is being built. If not provided, the current owner and group - will be used. - - The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). - - Returns the output filename. - """ - tar_compression = {'gzip': 'gz', None: ''} - compress_ext = {'gzip': '.gz'} - - if _BZ2_SUPPORTED: - tar_compression['bzip2'] = 'bz2' - compress_ext['bzip2'] = '.bz2' - - # flags for compression program, each element of list will be an argument - if compress is not None and compress not in compress_ext: - raise ValueError("bad value for 'compress', or compression format not " - "supported : {0}".format(compress)) - - archive_name = base_name + '.tar' + compress_ext.get(compress, '') - archive_dir = os.path.dirname(archive_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # creating the tarball - if logger is not None: - logger.info('Creating tar archive') - - uid = _get_uid(owner) - gid = _get_gid(group) - - def _set_uid_gid(tarinfo): - if gid is not None: - tarinfo.gid = gid - tarinfo.gname = group - if uid is not None: - tarinfo.uid = uid - tarinfo.uname = owner - return tarinfo - - if not dry_run: - tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) - try: - tar.add(base_dir, filter=_set_uid_gid) - finally: - tar.close() - - return archive_name - -def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils.errors import DistutilsExecError - from distutils.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename - -def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): - """Create a zip file from all the files under 'base_dir'. - - The output zip file will be named 'base_name' + ".zip". Uses either the - "zipfile" Python module (if available) or the InfoZIP "zip" utility - (if installed and found on the default search path). If neither tool is - available, raises ExecError. Returns the name of the output zip - file. - """ - zip_filename = base_name + ".zip" - archive_dir = os.path.dirname(base_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, zip_filename, verbose, dry_run) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) - - if not dry_run: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zip.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) - zip.close() - - return zip_filename - -_ARCHIVE_FORMATS = { - 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), - 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [], "ZIP file"), - } - -if _BZ2_SUPPORTED: - _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], - "bzip2'ed tar-file") - -def get_archive_formats(): - """Returns a list of supported formats for archiving and unarchiving. - - Each element of the returned sequence is a tuple (name, description) - """ - formats = [(name, registry[2]) for name, registry in - _ARCHIVE_FORMATS.items()] - formats.sort() - return formats - -def register_archive_format(name, function, extra_args=None, description=''): - """Registers an archive format. - - name is the name of the format. function is the callable that will be - used to create archives. If provided, extra_args is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_archive_formats() function. - """ - if extra_args is None: - extra_args = [] - if not isinstance(function, Callable): - raise TypeError('The %s object is not callable' % function) - if not isinstance(extra_args, (tuple, list)): - raise TypeError('extra_args needs to be a sequence') - for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2: - raise TypeError('extra_args elements are : (arg_name, value)') - - _ARCHIVE_FORMATS[name] = (function, extra_args, description) - -def unregister_archive_format(name): - del _ARCHIVE_FORMATS[name] - -def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, - dry_run=0, owner=None, group=None, logger=None): - """Create an archive file (eg. zip or tar). - - 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "bztar" - or "gztar". - - 'root_dir' is a directory that will be the root directory of the - archive; ie. we typically chdir into 'root_dir' before creating the - archive. 'base_dir' is the directory where we start archiving from; - ie. 'base_dir' will be the common prefix of all files and - directories in the archive. 'root_dir' and 'base_dir' both default - to the current directory. Returns the name of the archive file. - - 'owner' and 'group' are used when creating a tar archive. By default, - uses the current owner and group. - """ - save_cwd = os.getcwd() - if root_dir is not None: - if logger is not None: - logger.debug("changing into '%s'", root_dir) - base_name = os.path.abspath(base_name) - if not dry_run: - os.chdir(root_dir) - - if base_dir is None: - base_dir = os.curdir - - kwargs = {'dry_run': dry_run, 'logger': logger} - - try: - format_info = _ARCHIVE_FORMATS[format] - except KeyError: - raise ValueError("unknown archive format '%s'" % format) - - func = format_info[0] - for arg, val in format_info[1]: - kwargs[arg] = val - - if format != 'zip': - kwargs['owner'] = owner - kwargs['group'] = group - - try: - filename = func(base_name, base_dir, **kwargs) - finally: - if root_dir is not None: - if logger is not None: - logger.debug("changing back to '%s'", save_cwd) - os.chdir(save_cwd) - - return filename - - -def get_unpack_formats(): - """Returns a list of supported formats for unpacking. - - Each element of the returned sequence is a tuple - (name, extensions, description) - """ - formats = [(name, info[0], info[3]) for name, info in - _UNPACK_FORMATS.items()] - formats.sort() - return formats - -def _check_unpack_options(extensions, function, extra_args): - """Checks what gets registered as an unpacker.""" - # first make sure no other unpacker is registered for this extension - existing_extensions = {} - for name, info in _UNPACK_FORMATS.items(): - for ext in info[0]: - existing_extensions[ext] = name - - for extension in extensions: - if extension in existing_extensions: - msg = '%s is already registered for "%s"' - raise RegistryError(msg % (extension, - existing_extensions[extension])) - - if not isinstance(function, Callable): - raise TypeError('The registered function must be a callable') - - -def register_unpack_format(name, extensions, function, extra_args=None, - description=''): - """Registers an unpack format. - - `name` is the name of the format. `extensions` is a list of extensions - corresponding to the format. - - `function` is the callable that will be - used to unpack archives. The callable will receive archives to unpack. - If it's unable to handle an archive, it needs to raise a ReadError - exception. - - If provided, `extra_args` is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_unpack_formats() function. - """ - if extra_args is None: - extra_args = [] - _check_unpack_options(extensions, function, extra_args) - _UNPACK_FORMATS[name] = extensions, function, extra_args, description - -def unregister_unpack_format(name): - """Removes the pack format from the registry.""" - del _UNPACK_FORMATS[name] - -def _ensure_directory(path): - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - -def _unpack_zipfile(filename, extract_dir): - """Unpack zip `filename` to `extract_dir` - """ - try: - import zipfile - except ImportError: - raise ReadError('zlib not supported, cannot unpack this archive.') - - if not zipfile.is_zipfile(filename): - raise ReadError("%s is not a zip file" % filename) - - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: - continue - - target = os.path.join(extract_dir, *name.split('/')) - if not target: - continue - - _ensure_directory(target) - if not name.endswith('/'): - # file - data = zip.read(info.filename) - f = open(target, 'wb') - try: - f.write(data) - finally: - f.close() - del data - finally: - zip.close() - -def _unpack_tarfile(filename, extract_dir): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise ReadError( - "%s is not a compressed or uncompressed tar file" % filename) - try: - tarobj.extractall(extract_dir) - finally: - tarobj.close() - -_UNPACK_FORMATS = { - 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), - 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), - 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") - } - -if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], - "bzip2'ed tar-file") - -def _find_unpack_format(filename): - for name, info in _UNPACK_FORMATS.items(): - for extension in info[0]: - if filename.endswith(extension): - return name - return None - -def unpack_archive(filename, extract_dir=None, format=None): - """Unpack an archive. - - `filename` is the name of the archive. - - `extract_dir` is the name of the target directory, where the archive - is unpacked. If not provided, the current working directory is used. - - `format` is the archive format: one of "zip", "tar", or "gztar". Or any - other registered format. If not provided, unpack_archive will use the - filename extension and see if an unpacker was registered for that - extension. - - In case none is found, a ValueError is raised. - """ - if extract_dir is None: - extract_dir = os.getcwd() - - if format is not None: - try: - format_info = _UNPACK_FORMATS[format] - except KeyError: - raise ValueError("Unknown unpack format '{0}'".format(format)) - - func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) - else: - # we need to look at the registered unpackers supported extensions - format = _find_unpack_format(filename) - if format is None: - raise ReadError("Unknown archive format '{0}'".format(filename)) - - func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) - func(filename, extract_dir, **kwargs) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg deleted file mode 100644 index 1746bd0..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg +++ /dev/null @@ -1,84 +0,0 @@ -[posix_prefix] -# Configuration directories. Some of these come straight out of the -# configure script. They are for implementing the other variables, not to -# be used directly in [resource_locations]. -confdir = /etc -datadir = /usr/share -libdir = /usr/lib -statedir = /var -# User resource directory -local = ~/.local/{distribution.name} - -stdlib = {base}/lib/python{py_version_short} -platstdlib = {platbase}/lib/python{py_version_short} -purelib = {base}/lib/python{py_version_short}/site-packages -platlib = {platbase}/lib/python{py_version_short}/site-packages -include = {base}/include/python{py_version_short}{abiflags} -platinclude = {platbase}/include/python{py_version_short}{abiflags} -data = {base} - -[posix_home] -stdlib = {base}/lib/python -platstdlib = {base}/lib/python -purelib = {base}/lib/python -platlib = {base}/lib/python -include = {base}/include/python -platinclude = {base}/include/python -scripts = {base}/bin -data = {base} - -[nt] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2_home] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[nt_user] -stdlib = {userbase}/Python{py_version_nodot} -platstdlib = {userbase}/Python{py_version_nodot} -purelib = {userbase}/Python{py_version_nodot}/site-packages -platlib = {userbase}/Python{py_version_nodot}/site-packages -include = {userbase}/Python{py_version_nodot}/Include -scripts = {userbase}/Scripts -data = {userbase} - -[posix_user] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[osx_framework_user] -stdlib = {userbase}/lib/python -platstdlib = {userbase}/lib/python -purelib = {userbase}/lib/python/site-packages -platlib = {userbase}/lib/python/site-packages -include = {userbase}/include -scripts = {userbase}/bin -data = {userbase} diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.py deleted file mode 100644 index b470a37..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.py +++ /dev/null @@ -1,786 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Access to Python's configuration information.""" - -import codecs -import os -import re -import sys -from os.path import pardir, realpath -try: - import configparser -except ImportError: - import ConfigParser as configparser - - -__all__ = [ - 'get_config_h_filename', - 'get_config_var', - 'get_config_vars', - 'get_makefile_filename', - 'get_path', - 'get_path_names', - 'get_paths', - 'get_platform', - 'get_python_version', - 'get_scheme_names', - 'parse_config_h', -] - - -def _safe_realpath(path): - try: - return realpath(path) - except OSError: - return path - - -if sys.executable: - _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable)) -else: - # sys.executable can be empty if argv[0] has been changed and Python is - # unable to retrieve the real program name - _PROJECT_BASE = _safe_realpath(os.getcwd()) - -if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir)) -# PC/VS7.1 -if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) -# PC/AMD64 -if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) - - -def is_python_build(): - for fn in ("Setup.dist", "Setup.local"): - if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): - return True - return False - -_PYTHON_BUILD = is_python_build() - -_cfg_read = False - -def _ensure_cfg_read(): - global _cfg_read - if not _cfg_read: - from ..resources import finder - backport_package = __name__.rsplit('.', 1)[0] - _finder = finder(backport_package) - _cfgfile = _finder.find('sysconfig.cfg') - assert _cfgfile, 'sysconfig.cfg exists' - with _cfgfile.as_stream() as s: - _SCHEMES.readfp(s) - if _PYTHON_BUILD: - for scheme in ('posix_prefix', 'posix_home'): - _SCHEMES.set(scheme, 'include', '{srcdir}/Include') - _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') - - _cfg_read = True - - -_SCHEMES = configparser.RawConfigParser() -_VAR_REPL = re.compile(r'\{([^{]*?)\}') - -def _expand_globals(config): - _ensure_cfg_read() - if config.has_section('globals'): - globals = config.items('globals') - else: - globals = tuple() - - sections = config.sections() - for section in sections: - if section == 'globals': - continue - for option, value in globals: - if config.has_option(section, option): - continue - config.set(section, option, value) - config.remove_section('globals') - - # now expanding local variables defined in the cfg file - # - for section in config.sections(): - variables = dict(config.items(section)) - - def _replacer(matchobj): - name = matchobj.group(1) - if name in variables: - return variables[name] - return matchobj.group(0) - - for option, value in config.items(section): - config.set(section, option, _VAR_REPL.sub(_replacer, value)) - -#_expand_globals(_SCHEMES) - -_PY_VERSION = '%s.%s.%s' % sys.version_info[:3] -_PY_VERSION_SHORT = '%s.%s' % sys.version_info[:2] -_PY_VERSION_SHORT_NO_DOT = '%s%s' % sys.version_info[:2] -_PREFIX = os.path.normpath(sys.prefix) -_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) -_CONFIG_VARS = None -_USER_BASE = None - - -def _subst_vars(path, local_vars): - """In the string `path`, replace tokens like {some.thing} with the - corresponding value from the map `local_vars`. - - If there is no corresponding value, leave the token unchanged. - """ - def _replacer(matchobj): - name = matchobj.group(1) - if name in local_vars: - return local_vars[name] - elif name in os.environ: - return os.environ[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, path) - - -def _extend_dict(target_dict, other_dict): - target_keys = target_dict.keys() - for key, value in other_dict.items(): - if key in target_keys: - continue - target_dict[key] = value - - -def _expand_vars(scheme, vars): - res = {} - if vars is None: - vars = {} - _extend_dict(vars, get_config_vars()) - - for key, value in _SCHEMES.items(scheme): - if os.name in ('posix', 'nt'): - value = os.path.expanduser(value) - res[key] = os.path.normpath(_subst_vars(value, vars)) - return res - - -def format_value(value, vars): - def _replacer(matchobj): - name = matchobj.group(1) - if name in vars: - return vars[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, value) - - -def _get_default_scheme(): - if os.name == 'posix': - # the default scheme for posix is posix_prefix - return 'posix_prefix' - return os.name - - -def _getuserbase(): - env_base = os.environ.get("PYTHONUSERBASE", None) - - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - # what about 'os2emx', 'riscos' ? - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - return env_base - else: - return joinuser(base, "Python") - - if sys.platform == "darwin": - framework = get_config_var("PYTHONFRAMEWORK") - if framework: - if env_base: - return env_base - else: - return joinuser("~", "Library", framework, "%d.%d" % - sys.version_info[:2]) - - if env_base: - return env_base - else: - return joinuser("~", ".local") - - -def _parse_makefile(filename, vars=None): - """Parse a Makefile-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - # Regexes needed for parsing Makefile (and similar syntaxes, - # like old-style Setup files). - _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - - if vars is None: - vars = {} - done = {} - notdone = {} - - with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f: - lines = f.readlines() - - for line in lines: - if line.startswith('#') or line.strip() == '': - continue - m = _variable_rx.match(line) - if m: - n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # do variable interpolation here - variables = list(notdone.keys()) - - # Variables with a 'PY_' prefix in the makefile. These need to - # be made available without that prefix through sysconfig. - # Special care is needed to ensure that variable expansion works, even - # if the expansion uses the name without a prefix. - renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - - while len(variables) > 0: - for name in tuple(variables): - value = notdone[name] - m = _findvar1_rx.search(value) or _findvar2_rx.search(value) - if m is not None: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if (name.startswith('PY_') and - name[3:] in renamed_variables): - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - - else: - done[n] = item = "" - - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: - value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - variables.remove(name) - - if (name.startswith('PY_') and - name[3:] in renamed_variables): - - name = name[3:] - if name not in done: - done[name] = value - - else: - # bogus variable reference (e.g. "prefix=$/opt/python"); - # just drop it since we can't deal - done[name] = value - variables.remove(name) - - # strip spurious spaces - for k, v in done.items(): - if isinstance(v, str): - done[k] = v.strip() - - # save the results in the global dictionary - vars.update(done) - return vars - - -def get_makefile_filename(): - """Return the path of the Makefile.""" - if _PYTHON_BUILD: - return os.path.join(_PROJECT_BASE, "Makefile") - if hasattr(sys, 'abiflags'): - config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) - else: - config_dir_name = 'config' - return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') - - -def _init_posix(vars): - """Initialize the module as appropriate for POSIX systems.""" - # load the installed Makefile: - makefile = get_makefile_filename() - try: - _parse_makefile(makefile, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % makefile - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # load the installed pyconfig.h: - config_h = get_config_h_filename() - try: - with open(config_h) as f: - parse_config_h(f, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % config_h - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # On AIX, there are wrong paths to the linker scripts in the Makefile - # -- these paths are relative to the Python source, but when installed - # the scripts are in another directory. - if _PYTHON_BUILD: - vars['LDSHARED'] = vars['BLDSHARED'] - - -def _init_non_posix(vars): - """Initialize the module as appropriate for NT""" - # set basic install directories - vars['LIBDEST'] = get_path('stdlib') - vars['BINLIBDEST'] = get_path('platstdlib') - vars['INCLUDEPY'] = get_path('include') - vars['SO'] = '.pyd' - vars['EXE'] = '.exe' - vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT - vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) - -# -# public APIs -# - - -def parse_config_h(fp, vars=None): - """Parse a config.h-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - if vars is None: - vars = {} - define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") - undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") - - while True: - line = fp.readline() - if not line: - break - m = define_rx.match(line) - if m: - n, v = m.group(1, 2) - try: - v = int(v) - except ValueError: - pass - vars[n] = v - else: - m = undef_rx.match(line) - if m: - vars[m.group(1)] = 0 - return vars - - -def get_config_h_filename(): - """Return the path of pyconfig.h.""" - if _PYTHON_BUILD: - if os.name == "nt": - inc_dir = os.path.join(_PROJECT_BASE, "PC") - else: - inc_dir = _PROJECT_BASE - else: - inc_dir = get_path('platinclude') - return os.path.join(inc_dir, 'pyconfig.h') - - -def get_scheme_names(): - """Return a tuple containing the schemes names.""" - return tuple(sorted(_SCHEMES.sections())) - - -def get_path_names(): - """Return a tuple containing the paths names.""" - # xxx see if we want a static list - return _SCHEMES.options('posix_prefix') - - -def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): - """Return a mapping containing an install scheme. - - ``scheme`` is the install scheme name. If not provided, it will - return the default scheme for the current platform. - """ - _ensure_cfg_read() - if expand: - return _expand_vars(scheme, vars) - else: - return dict(_SCHEMES.items(scheme)) - - -def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): - """Return a path corresponding to the scheme. - - ``scheme`` is the install scheme name. - """ - return get_paths(scheme, vars, expand)[name] - - -def get_config_vars(*args): - """With no arguments, return a dictionary of all configuration - variables relevant for the current platform. - - On Unix, this means every variable defined in Python's installed Makefile; - On Windows and Mac OS it's a much smaller set. - - With arguments, return a list of values that result from looking up - each argument in the configuration variable dictionary. - """ - global _CONFIG_VARS - if _CONFIG_VARS is None: - _CONFIG_VARS = {} - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # distutils2 module. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] - _CONFIG_VARS['base'] = _PREFIX - _CONFIG_VARS['platbase'] = _EXEC_PREFIX - _CONFIG_VARS['projectbase'] = _PROJECT_BASE - try: - _CONFIG_VARS['abiflags'] = sys.abiflags - except AttributeError: - # sys.abiflags may not be defined on all platforms. - _CONFIG_VARS['abiflags'] = '' - - if os.name in ('nt', 'os2'): - _init_non_posix(_CONFIG_VARS) - if os.name == 'posix': - _init_posix(_CONFIG_VARS) - # Setting 'userbase' is done below the call to the - # init function to enable using 'get_config_var' in - # the init-function. - if sys.version >= '2.6': - _CONFIG_VARS['userbase'] = _getuserbase() - - if 'srcdir' not in _CONFIG_VARS: - _CONFIG_VARS['srcdir'] = _PROJECT_BASE - else: - _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if _PYTHON_BUILD and os.name == "posix": - base = _PROJECT_BASE - try: - cwd = os.getcwd() - except OSError: - cwd = None - if (not os.path.isabs(_CONFIG_VARS['srcdir']) and - base != cwd): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) - _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) - - if sys.platform == 'darwin': - kernel_version = os.uname()[2] # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _CONFIG_VARS[key] - flags = re.sub(r'-arch\s+\w+\s', ' ', flags) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _CONFIG_VARS[key] = flags - else: - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub(r'-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _CONFIG_VARS[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - CFLAGS = _CONFIG_VARS.get('CFLAGS', '') - m = re.search(r'-isysroot\s+(\S+)', CFLAGS) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub(r'-isysroot\s+\S+(\s|$)', ' ', flags) - _CONFIG_VARS[key] = flags - - if args: - vals = [] - for name in args: - vals.append(_CONFIG_VARS.get(name)) - return vals - else: - return _CONFIG_VARS - - -def get_config_var(name): - """Return the value of a single variable using the dictionary returned by - 'get_config_vars()'. - - Equivalent to get_config_vars().get(name) - """ - return get_config_vars().get(name) - - -def get_platform(): - """Return a string that identifies the current platform. - - This is used mainly to distinguish platform-specific build directories and - platform-specific built distributions. Typically includes the OS name - and version and the architecture (as supplied by 'os.uname()'), - although the exact information included depends on the OS; eg. for IRIX - the architecture isn't particularly important (IRIX only runs on SGI - hardware), but for Linux the kernel version isn't particularly - important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - irix-5.3 - irix64-6.2 - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win-ia64 (64bit Windows on Itanium) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - """ - if os.name == 'nt': - # sniff sys.version for architecture. - prefix = " bit (" - i = sys.version.find(prefix) - if i == -1: - return sys.platform - j = sys.version.find(")", i) - look = sys.version[i+len(prefix):j].lower() - if look == 'amd64': - return 'win-amd64' - if look == 'itanium': - return 'win-ia64' - return sys.platform - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - osname, host, release, version, machine = os.uname() - - # Convert the OS name to lowercase, remove '/' characters - # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # fall through to standard osname-release-machine representation - elif osname[:4] == "irix": # could be "irix64"! - return "%s-%s" % (osname, release) - elif osname[:3] == "aix": - return "%s-%s.%s" % (osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile(r'[\d.]+') - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - cfgvars = get_config_vars() - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if True: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search(r'ProductUserVisibleVersion\s*' - r'(.*?)', f.read()) - finally: - f.close() - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - - if not macver: - macver = macrelease - - if macver: - release = macver - osname = "macosx" - - if ((macrelease + '.') >= '10.4.' and - '-arch' in get_config_vars().get('CFLAGS', '').strip()): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall(r'-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r" % (archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxsize >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - # See 'i386' case - if sys.maxsize >= 2**32: - machine = 'ppc64' - else: - machine = 'ppc' - - return "%s-%s-%s" % (osname, release, machine) - - -def get_python_version(): - return _PY_VERSION_SHORT - - -def _print_dict(title, data): - for index, (key, value) in enumerate(sorted(data.items())): - if index == 0: - print('%s: ' % (title)) - print('\t%s = "%s"' % (key, value)) - - -def _main(): - """Display all information sysconfig detains.""" - print('Platform: "%s"' % get_platform()) - print('Python version: "%s"' % get_python_version()) - print('Current installation scheme: "%s"' % _get_default_scheme()) - print() - _print_dict('Paths', get_paths()) - print() - _print_dict('Variables', get_config_vars()) - - -if __name__ == '__main__': - _main() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/tarfile.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/tarfile.py deleted file mode 100644 index d66d856..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/tarfile.py +++ /dev/null @@ -1,2607 +0,0 @@ -#------------------------------------------------------------------- -# tarfile.py -#------------------------------------------------------------------- -# Copyright (C) 2002 Lars Gustaebel -# All rights reserved. -# -# 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. -# -from __future__ import print_function - -"""Read from and write to tar format archives. -""" - -__version__ = "$Revision$" - -version = "0.9.0" -__author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" -__date__ = "$Date: 2011-02-25 17:42:01 +0200 (Fri, 25 Feb 2011) $" -__cvsid__ = "$Id: tarfile.py 88586 2011-02-25 15:42:01Z marc-andre.lemburg $" -__credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." - -#--------- -# Imports -#--------- -import sys -import os -import stat -import errno -import time -import struct -import copy -import re - -try: - import grp, pwd -except ImportError: - grp = pwd = None - -# os.symlink on Windows prior to 6.0 raises NotImplementedError -symlink_exception = (AttributeError, NotImplementedError) -try: - # WindowsError (1314) will be raised if the caller does not hold the - # SeCreateSymbolicLinkPrivilege privilege - symlink_exception += (WindowsError,) -except NameError: - pass - -# from tarfile import * -__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] - -if sys.version_info[0] < 3: - import __builtin__ as builtins -else: - import builtins - -_open = builtins.open # Since 'open' is TarFile.open - -#--------------------------------------------------------- -# tar constants -#--------------------------------------------------------- -NUL = b"\0" # the null character -BLOCKSIZE = 512 # length of processing blocks -RECORDSIZE = BLOCKSIZE * 20 # length of records -GNU_MAGIC = b"ustar \0" # magic gnu tar string -POSIX_MAGIC = b"ustar\x0000" # magic posix tar string - -LENGTH_NAME = 100 # maximum length of a filename -LENGTH_LINK = 100 # maximum length of a linkname -LENGTH_PREFIX = 155 # maximum length of the prefix field - -REGTYPE = b"0" # regular file -AREGTYPE = b"\0" # regular file -LNKTYPE = b"1" # link (inside tarfile) -SYMTYPE = b"2" # symbolic link -CHRTYPE = b"3" # character special device -BLKTYPE = b"4" # block special device -DIRTYPE = b"5" # directory -FIFOTYPE = b"6" # fifo special device -CONTTYPE = b"7" # contiguous file - -GNUTYPE_LONGNAME = b"L" # GNU tar longname -GNUTYPE_LONGLINK = b"K" # GNU tar longlink -GNUTYPE_SPARSE = b"S" # GNU tar sparse file - -XHDTYPE = b"x" # POSIX.1-2001 extended header -XGLTYPE = b"g" # POSIX.1-2001 global header -SOLARIS_XHDTYPE = b"X" # Solaris extended header - -USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format -GNU_FORMAT = 1 # GNU tar format -PAX_FORMAT = 2 # POSIX.1-2001 (pax) format -DEFAULT_FORMAT = GNU_FORMAT - -#--------------------------------------------------------- -# tarfile constants -#--------------------------------------------------------- -# File types that tarfile supports: -SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, - SYMTYPE, DIRTYPE, FIFOTYPE, - CONTTYPE, CHRTYPE, BLKTYPE, - GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# File types that will be treated as a regular file. -REGULAR_TYPES = (REGTYPE, AREGTYPE, - CONTTYPE, GNUTYPE_SPARSE) - -# File types that are part of the GNU tar format. -GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# Fields from a pax header that override a TarInfo attribute. -PAX_FIELDS = ("path", "linkpath", "size", "mtime", - "uid", "gid", "uname", "gname") - -# Fields from a pax header that are affected by hdrcharset. -PAX_NAME_FIELDS = set(("path", "linkpath", "uname", "gname")) - -# Fields in a pax header that are numbers, all other fields -# are treated as strings. -PAX_NUMBER_FIELDS = { - "atime": float, - "ctime": float, - "mtime": float, - "uid": int, - "gid": int, - "size": int -} - -#--------------------------------------------------------- -# Bits used in the mode field, values in octal. -#--------------------------------------------------------- -S_IFLNK = 0o120000 # symbolic link -S_IFREG = 0o100000 # regular file -S_IFBLK = 0o060000 # block device -S_IFDIR = 0o040000 # directory -S_IFCHR = 0o020000 # character device -S_IFIFO = 0o010000 # fifo - -TSUID = 0o4000 # set UID on execution -TSGID = 0o2000 # set GID on execution -TSVTX = 0o1000 # reserved - -TUREAD = 0o400 # read by owner -TUWRITE = 0o200 # write by owner -TUEXEC = 0o100 # execute/search by owner -TGREAD = 0o040 # read by group -TGWRITE = 0o020 # write by group -TGEXEC = 0o010 # execute/search by group -TOREAD = 0o004 # read by other -TOWRITE = 0o002 # write by other -TOEXEC = 0o001 # execute/search by other - -#--------------------------------------------------------- -# initialization -#--------------------------------------------------------- -if os.name in ("nt", "ce"): - ENCODING = "utf-8" -else: - ENCODING = sys.getfilesystemencoding() - -#--------------------------------------------------------- -# Some useful functions -#--------------------------------------------------------- - -def stn(s, length, encoding, errors): - """Convert a string to a null-terminated bytes object. - """ - s = s.encode(encoding, errors) - return s[:length] + (length - len(s)) * NUL - -def nts(s, encoding, errors): - """Convert a null-terminated bytes object to a string. - """ - p = s.find(b"\0") - if p != -1: - s = s[:p] - return s.decode(encoding, errors) - -def nti(s): - """Convert a number field to a python number. - """ - # There are two possible encodings for a number field, see - # itn() below. - if s[0] != chr(0o200): - try: - n = int(nts(s, "ascii", "strict") or "0", 8) - except ValueError: - raise InvalidHeaderError("invalid header") - else: - n = 0 - for i in range(len(s) - 1): - n <<= 8 - n += ord(s[i + 1]) - return n - -def itn(n, digits=8, format=DEFAULT_FORMAT): - """Convert a python number to a number field. - """ - # POSIX 1003.1-1988 requires numbers to be encoded as a string of - # octal digits followed by a null-byte, this allows values up to - # (8**(digits-1))-1. GNU tar allows storing numbers greater than - # that if necessary. A leading 0o200 byte indicates this particular - # encoding, the following digits-1 bytes are a big-endian - # representation. This allows values up to (256**(digits-1))-1. - if 0 <= n < 8 ** (digits - 1): - s = ("%0*o" % (digits - 1, n)).encode("ascii") + NUL - else: - if format != GNU_FORMAT or n >= 256 ** (digits - 1): - raise ValueError("overflow in number field") - - if n < 0: - # XXX We mimic GNU tar's behaviour with negative numbers, - # this could raise OverflowError. - n = struct.unpack("L", struct.pack("l", n))[0] - - s = bytearray() - for i in range(digits - 1): - s.insert(0, n & 0o377) - n >>= 8 - s.insert(0, 0o200) - return s - -def calc_chksums(buf): - """Calculate the checksum for a member's header by summing up all - characters except for the chksum field which is treated as if - it was filled with spaces. According to the GNU tar sources, - some tars (Sun and NeXT) calculate chksum with signed char, - which will be different if there are chars in the buffer with - the high bit set. So we calculate two checksums, unsigned and - signed. - """ - unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) - signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) - return unsigned_chksum, signed_chksum - -def copyfileobj(src, dst, length=None): - """Copy length bytes from fileobj src to fileobj dst. - If length is None, copy the entire content. - """ - if length == 0: - return - if length is None: - while True: - buf = src.read(16*1024) - if not buf: - break - dst.write(buf) - return - - BUFSIZE = 16 * 1024 - blocks, remainder = divmod(length, BUFSIZE) - for b in range(blocks): - buf = src.read(BUFSIZE) - if len(buf) < BUFSIZE: - raise IOError("end of file reached") - dst.write(buf) - - if remainder != 0: - buf = src.read(remainder) - if len(buf) < remainder: - raise IOError("end of file reached") - dst.write(buf) - return - -filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((TUREAD, "r"),), - ((TUWRITE, "w"),), - ((TUEXEC|TSUID, "s"), - (TSUID, "S"), - (TUEXEC, "x")), - - ((TGREAD, "r"),), - ((TGWRITE, "w"),), - ((TGEXEC|TSGID, "s"), - (TSGID, "S"), - (TGEXEC, "x")), - - ((TOREAD, "r"),), - ((TOWRITE, "w"),), - ((TOEXEC|TSVTX, "t"), - (TSVTX, "T"), - (TOEXEC, "x")) -) - -def filemode(mode): - """Convert a file's mode to a string of the form - -rwxrwxrwx. - Used by TarFile.list() - """ - perm = [] - for table in filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) - -class TarError(Exception): - """Base exception.""" - pass -class ExtractError(TarError): - """General exception for extract errors.""" - pass -class ReadError(TarError): - """Exception for unreadable tar archives.""" - pass -class CompressionError(TarError): - """Exception for unavailable compression methods.""" - pass -class StreamError(TarError): - """Exception for unsupported operations on stream-like TarFiles.""" - pass -class HeaderError(TarError): - """Base exception for header errors.""" - pass -class EmptyHeaderError(HeaderError): - """Exception for empty headers.""" - pass -class TruncatedHeaderError(HeaderError): - """Exception for truncated headers.""" - pass -class EOFHeaderError(HeaderError): - """Exception for end of file headers.""" - pass -class InvalidHeaderError(HeaderError): - """Exception for invalid headers.""" - pass -class SubsequentHeaderError(HeaderError): - """Exception for missing and invalid extended headers.""" - pass - -#--------------------------- -# internal stream interface -#--------------------------- -class _LowLevelFile(object): - """Low-level file object. Supports reading and writing. - It is used instead of a regular file object for streaming - access. - """ - - def __init__(self, name, mode): - mode = { - "r": os.O_RDONLY, - "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, - }[mode] - if hasattr(os, "O_BINARY"): - mode |= os.O_BINARY - self.fd = os.open(name, mode, 0o666) - - def close(self): - os.close(self.fd) - - def read(self, size): - return os.read(self.fd, size) - - def write(self, s): - os.write(self.fd, s) - -class _Stream(object): - """Class that serves as an adapter between TarFile and - a stream-like object. The stream-like object only - needs to have a read() or write() method and is accessed - blockwise. Use of gzip or bzip2 compression is possible. - A stream-like object could be for example: sys.stdin, - sys.stdout, a socket, a tape device etc. - - _Stream is intended to be used only internally. - """ - - def __init__(self, name, mode, comptype, fileobj, bufsize): - """Construct a _Stream object. - """ - self._extfileobj = True - if fileobj is None: - fileobj = _LowLevelFile(name, mode) - self._extfileobj = False - - if comptype == '*': - # Enable transparent compression detection for the - # stream interface - fileobj = _StreamProxy(fileobj) - comptype = fileobj.getcomptype() - - self.name = name or "" - self.mode = mode - self.comptype = comptype - self.fileobj = fileobj - self.bufsize = bufsize - self.buf = b"" - self.pos = 0 - self.closed = False - - try: - if comptype == "gz": - try: - import zlib - except ImportError: - raise CompressionError("zlib module is not available") - self.zlib = zlib - self.crc = zlib.crc32(b"") - if mode == "r": - self._init_read_gz() - else: - self._init_write_gz() - - if comptype == "bz2": - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - if mode == "r": - self.dbuf = b"" - self.cmp = bz2.BZ2Decompressor() - else: - self.cmp = bz2.BZ2Compressor() - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - def __del__(self): - if hasattr(self, "closed") and not self.closed: - self.close() - - def _init_write_gz(self): - """Initialize for writing with gzip compression. - """ - self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, - -self.zlib.MAX_WBITS, - self.zlib.DEF_MEM_LEVEL, - 0) - timestamp = struct.pack(" self.bufsize: - self.fileobj.write(self.buf[:self.bufsize]) - self.buf = self.buf[self.bufsize:] - - def close(self): - """Close the _Stream object. No operation should be - done on it afterwards. - """ - if self.closed: - return - - if self.mode == "w" and self.comptype != "tar": - self.buf += self.cmp.flush() - - if self.mode == "w" and self.buf: - self.fileobj.write(self.buf) - self.buf = b"" - if self.comptype == "gz": - # The native zlib crc is an unsigned 32-bit integer, but - # the Python wrapper implicitly casts that to a signed C - # long. So, on a 32-bit box self.crc may "look negative", - # while the same crc on a 64-bit box may "look positive". - # To avoid irksome warnings from the `struct` module, force - # it to look positive on all boxes. - self.fileobj.write(struct.pack("= 0: - blocks, remainder = divmod(pos - self.pos, self.bufsize) - for i in range(blocks): - self.read(self.bufsize) - self.read(remainder) - else: - raise StreamError("seeking backwards is not allowed") - return self.pos - - def read(self, size=None): - """Return the next size number of bytes from the stream. - If size is not defined, return all bytes of the stream - up to EOF. - """ - if size is None: - t = [] - while True: - buf = self._read(self.bufsize) - if not buf: - break - t.append(buf) - buf = "".join(t) - else: - buf = self._read(size) - self.pos += len(buf) - return buf - - def _read(self, size): - """Return size bytes from the stream. - """ - if self.comptype == "tar": - return self.__read(size) - - c = len(self.dbuf) - while c < size: - buf = self.__read(self.bufsize) - if not buf: - break - try: - buf = self.cmp.decompress(buf) - except IOError: - raise ReadError("invalid compressed data") - self.dbuf += buf - c += len(buf) - buf = self.dbuf[:size] - self.dbuf = self.dbuf[size:] - return buf - - def __read(self, size): - """Return size bytes from stream. If internal buffer is empty, - read another block from the stream. - """ - c = len(self.buf) - while c < size: - buf = self.fileobj.read(self.bufsize) - if not buf: - break - self.buf += buf - c += len(buf) - buf = self.buf[:size] - self.buf = self.buf[size:] - return buf -# class _Stream - -class _StreamProxy(object): - """Small proxy class that enables transparent compression - detection for the Stream interface (mode 'r|*'). - """ - - def __init__(self, fileobj): - self.fileobj = fileobj - self.buf = self.fileobj.read(BLOCKSIZE) - - def read(self, size): - self.read = self.fileobj.read - return self.buf - - def getcomptype(self): - if self.buf.startswith(b"\037\213\010"): - return "gz" - if self.buf.startswith(b"BZh91"): - return "bz2" - return "tar" - - def close(self): - self.fileobj.close() -# class StreamProxy - -class _BZ2Proxy(object): - """Small proxy class that enables external file object - support for "r:bz2" and "w:bz2" modes. This is actually - a workaround for a limitation in bz2 module's BZ2File - class which (unlike gzip.GzipFile) has no support for - a file object argument. - """ - - blocksize = 16 * 1024 - - def __init__(self, fileobj, mode): - self.fileobj = fileobj - self.mode = mode - self.name = getattr(self.fileobj, "name", None) - self.init() - - def init(self): - import bz2 - self.pos = 0 - if self.mode == "r": - self.bz2obj = bz2.BZ2Decompressor() - self.fileobj.seek(0) - self.buf = b"" - else: - self.bz2obj = bz2.BZ2Compressor() - - def read(self, size): - x = len(self.buf) - while x < size: - raw = self.fileobj.read(self.blocksize) - if not raw: - break - data = self.bz2obj.decompress(raw) - self.buf += data - x += len(data) - - buf = self.buf[:size] - self.buf = self.buf[size:] - self.pos += len(buf) - return buf - - def seek(self, pos): - if pos < self.pos: - self.init() - self.read(pos - self.pos) - - def tell(self): - return self.pos - - def write(self, data): - self.pos += len(data) - raw = self.bz2obj.compress(data) - self.fileobj.write(raw) - - def close(self): - if self.mode == "w": - raw = self.bz2obj.flush() - self.fileobj.write(raw) -# class _BZ2Proxy - -#------------------------ -# Extraction file object -#------------------------ -class _FileInFile(object): - """A thin wrapper around an existing file object that - provides a part of its data as an individual file - object. - """ - - def __init__(self, fileobj, offset, size, blockinfo=None): - self.fileobj = fileobj - self.offset = offset - self.size = size - self.position = 0 - - if blockinfo is None: - blockinfo = [(0, size)] - - # Construct a map with data and zero blocks. - self.map_index = 0 - self.map = [] - lastpos = 0 - realpos = self.offset - for offset, size in blockinfo: - if offset > lastpos: - self.map.append((False, lastpos, offset, None)) - self.map.append((True, offset, offset + size, realpos)) - realpos += size - lastpos = offset + size - if lastpos < self.size: - self.map.append((False, lastpos, self.size, None)) - - def seekable(self): - if not hasattr(self.fileobj, "seekable"): - # XXX gzip.GzipFile and bz2.BZ2File - return True - return self.fileobj.seekable() - - def tell(self): - """Return the current file position. - """ - return self.position - - def seek(self, position): - """Seek to a position in the file. - """ - self.position = position - - def read(self, size=None): - """Read data from the file. - """ - if size is None: - size = self.size - self.position - else: - size = min(size, self.size - self.position) - - buf = b"" - while size > 0: - while True: - data, start, stop, offset = self.map[self.map_index] - if start <= self.position < stop: - break - else: - self.map_index += 1 - if self.map_index == len(self.map): - self.map_index = 0 - length = min(size, stop - self.position) - if data: - self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) - else: - buf += NUL * length - size -= length - self.position += length - return buf -#class _FileInFile - - -class ExFileObject(object): - """File-like object for reading an archive member. - Is returned by TarFile.extractfile(). - """ - blocksize = 1024 - - def __init__(self, tarfile, tarinfo): - self.fileobj = _FileInFile(tarfile.fileobj, - tarinfo.offset_data, - tarinfo.size, - tarinfo.sparse) - self.name = tarinfo.name - self.mode = "r" - self.closed = False - self.size = tarinfo.size - - self.position = 0 - self.buffer = b"" - - def readable(self): - return True - - def writable(self): - return False - - def seekable(self): - return self.fileobj.seekable() - - def read(self, size=None): - """Read at most size bytes from the file. If size is not - present or None, read all data until EOF is reached. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - buf = b"" - if self.buffer: - if size is None: - buf = self.buffer - self.buffer = b"" - else: - buf = self.buffer[:size] - self.buffer = self.buffer[size:] - - if size is None: - buf += self.fileobj.read() - else: - buf += self.fileobj.read(size - len(buf)) - - self.position += len(buf) - return buf - - # XXX TextIOWrapper uses the read1() method. - read1 = read - - def readline(self, size=-1): - """Read one entire line from the file. If size is present - and non-negative, return a string with at most that - size, which may be an incomplete line. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - while True: - buf = self.fileobj.read(self.blocksize) - self.buffer += buf - if not buf or b"\n" in buf: - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - pos = len(self.buffer) - break - - if size != -1: - pos = min(size, pos) - - buf = self.buffer[:pos] - self.buffer = self.buffer[pos:] - self.position += len(buf) - return buf - - def readlines(self): - """Return a list with all remaining lines. - """ - result = [] - while True: - line = self.readline() - if not line: break - result.append(line) - return result - - def tell(self): - """Return the current file position. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - return self.position - - def seek(self, pos, whence=os.SEEK_SET): - """Seek to a position in the file. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - if whence == os.SEEK_SET: - self.position = min(max(pos, 0), self.size) - elif whence == os.SEEK_CUR: - if pos < 0: - self.position = max(self.position + pos, 0) - else: - self.position = min(self.position + pos, self.size) - elif whence == os.SEEK_END: - self.position = max(min(self.size + pos, self.size), 0) - else: - raise ValueError("Invalid argument") - - self.buffer = b"" - self.fileobj.seek(self.position) - - def close(self): - """Close the file object. - """ - self.closed = True - - def __iter__(self): - """Get an iterator over the file's lines. - """ - while True: - line = self.readline() - if not line: - break - yield line -#class ExFileObject - -#------------------ -# Exported Classes -#------------------ -class TarInfo(object): - """Informational class which holds the details about an - archive member given by a tar header block. - TarInfo objects are returned by TarFile.getmember(), - TarFile.getmembers() and TarFile.gettarinfo() and are - usually created internally. - """ - - __slots__ = ("name", "mode", "uid", "gid", "size", "mtime", - "chksum", "type", "linkname", "uname", "gname", - "devmajor", "devminor", - "offset", "offset_data", "pax_headers", "sparse", - "tarfile", "_sparse_structs", "_link_target") - - def __init__(self, name=""): - """Construct a TarInfo object. name is the optional name - of the member. - """ - self.name = name # member name - self.mode = 0o644 # file permissions - self.uid = 0 # user id - self.gid = 0 # group id - self.size = 0 # file size - self.mtime = 0 # modification time - self.chksum = 0 # header checksum - self.type = REGTYPE # member type - self.linkname = "" # link name - self.uname = "" # user name - self.gname = "" # group name - self.devmajor = 0 # device major number - self.devminor = 0 # device minor number - - self.offset = 0 # the tar header starts here - self.offset_data = 0 # the file's data starts here - - self.sparse = None # sparse member information - self.pax_headers = {} # pax header information - - # In pax headers the "name" and "linkname" field are called - # "path" and "linkpath". - def _getpath(self): - return self.name - def _setpath(self, name): - self.name = name - path = property(_getpath, _setpath) - - def _getlinkpath(self): - return self.linkname - def _setlinkpath(self, linkname): - self.linkname = linkname - linkpath = property(_getlinkpath, _setlinkpath) - - def __repr__(self): - return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) - - def get_info(self): - """Return the TarInfo's attributes as a dictionary. - """ - info = { - "name": self.name, - "mode": self.mode & 0o7777, - "uid": self.uid, - "gid": self.gid, - "size": self.size, - "mtime": self.mtime, - "chksum": self.chksum, - "type": self.type, - "linkname": self.linkname, - "uname": self.uname, - "gname": self.gname, - "devmajor": self.devmajor, - "devminor": self.devminor - } - - if info["type"] == DIRTYPE and not info["name"].endswith("/"): - info["name"] += "/" - - return info - - def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescape"): - """Return a tar header as a string of 512 byte blocks. - """ - info = self.get_info() - - if format == USTAR_FORMAT: - return self.create_ustar_header(info, encoding, errors) - elif format == GNU_FORMAT: - return self.create_gnu_header(info, encoding, errors) - elif format == PAX_FORMAT: - return self.create_pax_header(info, encoding) - else: - raise ValueError("invalid format") - - def create_ustar_header(self, info, encoding, errors): - """Return the object as a ustar header block. - """ - info["magic"] = POSIX_MAGIC - - if len(info["linkname"]) > LENGTH_LINK: - raise ValueError("linkname is too long") - - if len(info["name"]) > LENGTH_NAME: - info["prefix"], info["name"] = self._posix_split_name(info["name"]) - - return self._create_header(info, USTAR_FORMAT, encoding, errors) - - def create_gnu_header(self, info, encoding, errors): - """Return the object as a GNU header block sequence. - """ - info["magic"] = GNU_MAGIC - - buf = b"" - if len(info["linkname"]) > LENGTH_LINK: - buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK, encoding, errors) - - if len(info["name"]) > LENGTH_NAME: - buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME, encoding, errors) - - return buf + self._create_header(info, GNU_FORMAT, encoding, errors) - - def create_pax_header(self, info, encoding): - """Return the object as a ustar header block. If it cannot be - represented this way, prepend a pax extended header sequence - with supplement information. - """ - info["magic"] = POSIX_MAGIC - pax_headers = self.pax_headers.copy() - - # Test string fields for values that exceed the field length or cannot - # be represented in ASCII encoding. - for name, hname, length in ( - ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), - ("uname", "uname", 32), ("gname", "gname", 32)): - - if hname in pax_headers: - # The pax header has priority. - continue - - # Try to encode the string as ASCII. - try: - info[name].encode("ascii", "strict") - except UnicodeEncodeError: - pax_headers[hname] = info[name] - continue - - if len(info[name]) > length: - pax_headers[hname] = info[name] - - # Test number fields for values that exceed the field limit or values - # that like to be stored as float. - for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): - if name in pax_headers: - # The pax header has priority. Avoid overflow. - info[name] = 0 - continue - - val = info[name] - if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): - pax_headers[name] = str(val) - info[name] = 0 - - # Create a pax extended header if necessary. - if pax_headers: - buf = self._create_pax_generic_header(pax_headers, XHDTYPE, encoding) - else: - buf = b"" - - return buf + self._create_header(info, USTAR_FORMAT, "ascii", "replace") - - @classmethod - def create_pax_global_header(cls, pax_headers): - """Return the object as a pax global header block sequence. - """ - return cls._create_pax_generic_header(pax_headers, XGLTYPE, "utf8") - - def _posix_split_name(self, name): - """Split a name longer than 100 chars into a prefix - and a name part. - """ - prefix = name[:LENGTH_PREFIX + 1] - while prefix and prefix[-1] != "/": - prefix = prefix[:-1] - - name = name[len(prefix):] - prefix = prefix[:-1] - - if not prefix or len(name) > LENGTH_NAME: - raise ValueError("name is too long") - return prefix, name - - @staticmethod - def _create_header(info, format, encoding, errors): - """Return a header block. info is a dictionary with file - information, format must be one of the *_FORMAT constants. - """ - parts = [ - stn(info.get("name", ""), 100, encoding, errors), - itn(info.get("mode", 0) & 0o7777, 8, format), - itn(info.get("uid", 0), 8, format), - itn(info.get("gid", 0), 8, format), - itn(info.get("size", 0), 12, format), - itn(info.get("mtime", 0), 12, format), - b" ", # checksum field - info.get("type", REGTYPE), - stn(info.get("linkname", ""), 100, encoding, errors), - info.get("magic", POSIX_MAGIC), - stn(info.get("uname", ""), 32, encoding, errors), - stn(info.get("gname", ""), 32, encoding, errors), - itn(info.get("devmajor", 0), 8, format), - itn(info.get("devminor", 0), 8, format), - stn(info.get("prefix", ""), 155, encoding, errors) - ] - - buf = struct.pack("%ds" % BLOCKSIZE, b"".join(parts)) - chksum = calc_chksums(buf[-BLOCKSIZE:])[0] - buf = buf[:-364] + ("%06o\0" % chksum).encode("ascii") + buf[-357:] - return buf - - @staticmethod - def _create_payload(payload): - """Return the string payload filled with zero bytes - up to the next 512 byte border. - """ - blocks, remainder = divmod(len(payload), BLOCKSIZE) - if remainder > 0: - payload += (BLOCKSIZE - remainder) * NUL - return payload - - @classmethod - def _create_gnu_long_header(cls, name, type, encoding, errors): - """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence - for name. - """ - name = name.encode(encoding, errors) + NUL - - info = {} - info["name"] = "././@LongLink" - info["type"] = type - info["size"] = len(name) - info["magic"] = GNU_MAGIC - - # create extended header + name blocks. - return cls._create_header(info, USTAR_FORMAT, encoding, errors) + \ - cls._create_payload(name) - - @classmethod - def _create_pax_generic_header(cls, pax_headers, type, encoding): - """Return a POSIX.1-2008 extended or global header sequence - that contains a list of keyword, value pairs. The values - must be strings. - """ - # Check if one of the fields contains surrogate characters and thereby - # forces hdrcharset=BINARY, see _proc_pax() for more information. - binary = False - for keyword, value in pax_headers.items(): - try: - value.encode("utf8", "strict") - except UnicodeEncodeError: - binary = True - break - - records = b"" - if binary: - # Put the hdrcharset field at the beginning of the header. - records += b"21 hdrcharset=BINARY\n" - - for keyword, value in pax_headers.items(): - keyword = keyword.encode("utf8") - if binary: - # Try to restore the original byte representation of `value'. - # Needless to say, that the encoding must match the string. - value = value.encode(encoding, "surrogateescape") - else: - value = value.encode("utf8") - - l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' - n = p = 0 - while True: - n = l + len(str(p)) - if n == p: - break - p = n - records += bytes(str(p), "ascii") + b" " + keyword + b"=" + value + b"\n" - - # We use a hardcoded "././@PaxHeader" name like star does - # instead of the one that POSIX recommends. - info = {} - info["name"] = "././@PaxHeader" - info["type"] = type - info["size"] = len(records) - info["magic"] = POSIX_MAGIC - - # Create pax header + record blocks. - return cls._create_header(info, USTAR_FORMAT, "ascii", "replace") + \ - cls._create_payload(records) - - @classmethod - def frombuf(cls, buf, encoding, errors): - """Construct a TarInfo object from a 512 byte bytes object. - """ - if len(buf) == 0: - raise EmptyHeaderError("empty header") - if len(buf) != BLOCKSIZE: - raise TruncatedHeaderError("truncated header") - if buf.count(NUL) == BLOCKSIZE: - raise EOFHeaderError("end of file header") - - chksum = nti(buf[148:156]) - if chksum not in calc_chksums(buf): - raise InvalidHeaderError("bad checksum") - - obj = cls() - obj.name = nts(buf[0:100], encoding, errors) - obj.mode = nti(buf[100:108]) - obj.uid = nti(buf[108:116]) - obj.gid = nti(buf[116:124]) - obj.size = nti(buf[124:136]) - obj.mtime = nti(buf[136:148]) - obj.chksum = chksum - obj.type = buf[156:157] - obj.linkname = nts(buf[157:257], encoding, errors) - obj.uname = nts(buf[265:297], encoding, errors) - obj.gname = nts(buf[297:329], encoding, errors) - obj.devmajor = nti(buf[329:337]) - obj.devminor = nti(buf[337:345]) - prefix = nts(buf[345:500], encoding, errors) - - # Old V7 tar format represents a directory as a regular - # file with a trailing slash. - if obj.type == AREGTYPE and obj.name.endswith("/"): - obj.type = DIRTYPE - - # The old GNU sparse format occupies some of the unused - # space in the buffer for up to 4 sparse structures. - # Save the them for later processing in _proc_sparse(). - if obj.type == GNUTYPE_SPARSE: - pos = 386 - structs = [] - for i in range(4): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[482]) - origsize = nti(buf[483:495]) - obj._sparse_structs = (structs, isextended, origsize) - - # Remove redundant slashes from directories. - if obj.isdir(): - obj.name = obj.name.rstrip("/") - - # Reconstruct a ustar longname. - if prefix and obj.type not in GNU_TYPES: - obj.name = prefix + "/" + obj.name - return obj - - @classmethod - def fromtarfile(cls, tarfile): - """Return the next TarInfo object from TarFile object - tarfile. - """ - buf = tarfile.fileobj.read(BLOCKSIZE) - obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors) - obj.offset = tarfile.fileobj.tell() - BLOCKSIZE - return obj._proc_member(tarfile) - - #-------------------------------------------------------------------------- - # The following are methods that are called depending on the type of a - # member. The entry point is _proc_member() which can be overridden in a - # subclass to add custom _proc_*() methods. A _proc_*() method MUST - # implement the following - # operations: - # 1. Set self.offset_data to the position where the data blocks begin, - # if there is data that follows. - # 2. Set tarfile.offset to the position where the next member's header will - # begin. - # 3. Return self or another valid TarInfo object. - def _proc_member(self, tarfile): - """Choose the right processing method depending on - the type and call it. - """ - if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): - return self._proc_gnulong(tarfile) - elif self.type == GNUTYPE_SPARSE: - return self._proc_sparse(tarfile) - elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): - return self._proc_pax(tarfile) - else: - return self._proc_builtin(tarfile) - - def _proc_builtin(self, tarfile): - """Process a builtin type or an unknown type which - will be treated as a regular file. - """ - self.offset_data = tarfile.fileobj.tell() - offset = self.offset_data - if self.isreg() or self.type not in SUPPORTED_TYPES: - # Skip the following data blocks. - offset += self._block(self.size) - tarfile.offset = offset - - # Patch the TarInfo object with saved global - # header information. - self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) - - return self - - def _proc_gnulong(self, tarfile): - """Process the blocks that hold a GNU longname - or longlink member. - """ - buf = tarfile.fileobj.read(self._block(self.size)) - - # Fetch the next header and process it. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Patch the TarInfo object from the next header with - # the longname information. - next.offset = self.offset - if self.type == GNUTYPE_LONGNAME: - next.name = nts(buf, tarfile.encoding, tarfile.errors) - elif self.type == GNUTYPE_LONGLINK: - next.linkname = nts(buf, tarfile.encoding, tarfile.errors) - - return next - - def _proc_sparse(self, tarfile): - """Process a GNU sparse header plus extra headers. - """ - # We already collected some sparse structures in frombuf(). - structs, isextended, origsize = self._sparse_structs - del self._sparse_structs - - # Collect sparse structures from extended header blocks. - while isextended: - buf = tarfile.fileobj.read(BLOCKSIZE) - pos = 0 - for i in range(21): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - if offset and numbytes: - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[504]) - self.sparse = structs - - self.offset_data = tarfile.fileobj.tell() - tarfile.offset = self.offset_data + self._block(self.size) - self.size = origsize - return self - - def _proc_pax(self, tarfile): - """Process an extended or global header as described in - POSIX.1-2008. - """ - # Read the header information. - buf = tarfile.fileobj.read(self._block(self.size)) - - # A pax header stores supplemental information for either - # the following file (extended) or all following files - # (global). - if self.type == XGLTYPE: - pax_headers = tarfile.pax_headers - else: - pax_headers = tarfile.pax_headers.copy() - - # Check if the pax header contains a hdrcharset field. This tells us - # the encoding of the path, linkpath, uname and gname fields. Normally, - # these fields are UTF-8 encoded but since POSIX.1-2008 tar - # implementations are allowed to store them as raw binary strings if - # the translation to UTF-8 fails. - match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) - if match is not None: - pax_headers["hdrcharset"] = match.group(1).decode("utf8") - - # For the time being, we don't care about anything other than "BINARY". - # The only other value that is currently allowed by the standard is - # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. - hdrcharset = pax_headers.get("hdrcharset") - if hdrcharset == "BINARY": - encoding = tarfile.encoding - else: - encoding = "utf8" - - # Parse pax header information. A record looks like that: - # "%d %s=%s\n" % (length, keyword, value). length is the size - # of the complete record including the length field itself and - # the newline. keyword and value are both UTF-8 encoded strings. - regex = re.compile(br"(\d+) ([^=]+)=") - pos = 0 - while True: - match = regex.match(buf, pos) - if not match: - break - - length, keyword = match.groups() - length = int(length) - value = buf[match.end(2) + 1:match.start(1) + length - 1] - - # Normally, we could just use "utf8" as the encoding and "strict" - # as the error handler, but we better not take the risk. For - # example, GNU tar <= 1.23 is known to store filenames it cannot - # translate to UTF-8 as raw strings (unfortunately without a - # hdrcharset=BINARY header). - # We first try the strict standard encoding, and if that fails we - # fall back on the user's encoding and error handler. - keyword = self._decode_pax_field(keyword, "utf8", "utf8", - tarfile.errors) - if keyword in PAX_NAME_FIELDS: - value = self._decode_pax_field(value, encoding, tarfile.encoding, - tarfile.errors) - else: - value = self._decode_pax_field(value, "utf8", "utf8", - tarfile.errors) - - pax_headers[keyword] = value - pos += length - - # Fetch the next header. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Process GNU sparse information. - if "GNU.sparse.map" in pax_headers: - # GNU extended sparse format version 0.1. - self._proc_gnusparse_01(next, pax_headers) - - elif "GNU.sparse.size" in pax_headers: - # GNU extended sparse format version 0.0. - self._proc_gnusparse_00(next, pax_headers, buf) - - elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": - # GNU extended sparse format version 1.0. - self._proc_gnusparse_10(next, pax_headers, tarfile) - - if self.type in (XHDTYPE, SOLARIS_XHDTYPE): - # Patch the TarInfo object with the extended header info. - next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) - next.offset = self.offset - - if "size" in pax_headers: - # If the extended header replaces the size field, - # we need to recalculate the offset where the next - # header starts. - offset = next.offset_data - if next.isreg() or next.type not in SUPPORTED_TYPES: - offset += next._block(next.size) - tarfile.offset = offset - - return next - - def _proc_gnusparse_00(self, next, pax_headers, buf): - """Process a GNU tar extended sparse header, version 0.0. - """ - offsets = [] - for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): - offsets.append(int(match.group(1))) - numbytes = [] - for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): - numbytes.append(int(match.group(1))) - next.sparse = list(zip(offsets, numbytes)) - - def _proc_gnusparse_01(self, next, pax_headers): - """Process a GNU tar extended sparse header, version 0.1. - """ - sparse = [int(x) for x in pax_headers["GNU.sparse.map"].split(",")] - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _proc_gnusparse_10(self, next, pax_headers, tarfile): - """Process a GNU tar extended sparse header, version 1.0. - """ - fields = None - sparse = [] - buf = tarfile.fileobj.read(BLOCKSIZE) - fields, buf = buf.split(b"\n", 1) - fields = int(fields) - while len(sparse) < fields * 2: - if b"\n" not in buf: - buf += tarfile.fileobj.read(BLOCKSIZE) - number, buf = buf.split(b"\n", 1) - sparse.append(int(number)) - next.offset_data = tarfile.fileobj.tell() - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _apply_pax_info(self, pax_headers, encoding, errors): - """Replace fields with supplemental information from a previous - pax extended or global header. - """ - for keyword, value in pax_headers.items(): - if keyword == "GNU.sparse.name": - setattr(self, "path", value) - elif keyword == "GNU.sparse.size": - setattr(self, "size", int(value)) - elif keyword == "GNU.sparse.realsize": - setattr(self, "size", int(value)) - elif keyword in PAX_FIELDS: - if keyword in PAX_NUMBER_FIELDS: - try: - value = PAX_NUMBER_FIELDS[keyword](value) - except ValueError: - value = 0 - if keyword == "path": - value = value.rstrip("/") - setattr(self, keyword, value) - - self.pax_headers = pax_headers.copy() - - def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors): - """Decode a single field from a pax record. - """ - try: - return value.decode(encoding, "strict") - except UnicodeDecodeError: - return value.decode(fallback_encoding, fallback_errors) - - def _block(self, count): - """Round up a byte count by BLOCKSIZE and return it, - e.g. _block(834) => 1024. - """ - blocks, remainder = divmod(count, BLOCKSIZE) - if remainder: - blocks += 1 - return blocks * BLOCKSIZE - - def isreg(self): - return self.type in REGULAR_TYPES - def isfile(self): - return self.isreg() - def isdir(self): - return self.type == DIRTYPE - def issym(self): - return self.type == SYMTYPE - def islnk(self): - return self.type == LNKTYPE - def ischr(self): - return self.type == CHRTYPE - def isblk(self): - return self.type == BLKTYPE - def isfifo(self): - return self.type == FIFOTYPE - def issparse(self): - return self.sparse is not None - def isdev(self): - return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) -# class TarInfo - -class TarFile(object): - """The TarFile Class provides an interface to tar archives. - """ - - debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) - - dereference = False # If true, add content of linked file to the - # tar file, else the link. - - ignore_zeros = False # If true, skips empty or invalid blocks and - # continues processing. - - errorlevel = 1 # If 0, fatal errors only appear in debug - # messages (if debug >= 0). If > 0, errors - # are passed to the caller as exceptions. - - format = DEFAULT_FORMAT # The format to use when creating an archive. - - encoding = ENCODING # Encoding for 8-bit character strings. - - errors = None # Error handler for unicode conversion. - - tarinfo = TarInfo # The default TarInfo class to use. - - fileobject = ExFileObject # The default ExFileObject class to use. - - def __init__(self, name=None, mode="r", fileobj=None, format=None, - tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, - errors="surrogateescape", pax_headers=None, debug=None, errorlevel=None): - """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to - read from an existing archive, 'a' to append data to an existing - file or 'w' to create a new file overwriting an existing one. `mode' - defaults to 'r'. - If `fileobj' is given, it is used for reading or writing data. If it - can be determined, `mode' is overridden by `fileobj's mode. - `fileobj' is not closed, when TarFile is closed. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] - - if not fileobj: - if self.mode == "a" and not os.path.exists(name): - # Create nonexistent files in append mode. - self.mode = "w" - self._mode = "wb" - fileobj = bltn_open(name, self._mode) - self._extfileobj = False - else: - if name is None and hasattr(fileobj, "name"): - name = fileobj.name - if hasattr(fileobj, "mode"): - self._mode = fileobj.mode - self._extfileobj = True - self.name = os.path.abspath(name) if name else None - self.fileobj = fileobj - - # Init attributes. - if format is not None: - self.format = format - if tarinfo is not None: - self.tarinfo = tarinfo - if dereference is not None: - self.dereference = dereference - if ignore_zeros is not None: - self.ignore_zeros = ignore_zeros - if encoding is not None: - self.encoding = encoding - self.errors = errors - - if pax_headers is not None and self.format == PAX_FORMAT: - self.pax_headers = pax_headers - else: - self.pax_headers = {} - - if debug is not None: - self.debug = debug - if errorlevel is not None: - self.errorlevel = errorlevel - - # Init datastructures. - self.closed = False - self.members = [] # list of members as TarInfo objects - self._loaded = False # flag if all members have been read - self.offset = self.fileobj.tell() - # current position in the archive file - self.inodes = {} # dictionary caching the inodes of - # archive members already added - - try: - if self.mode == "r": - self.firstmember = None - self.firstmember = self.next() - - if self.mode == "a": - # Move to the end of the archive, - # before the first empty block. - while True: - self.fileobj.seek(self.offset) - try: - tarinfo = self.tarinfo.fromtarfile(self) - self.members.append(tarinfo) - except EOFHeaderError: - self.fileobj.seek(self.offset) - break - except HeaderError as e: - raise ReadError(str(e)) - - if self.mode in "aw": - self._loaded = True - - if self.pax_headers: - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - #-------------------------------------------------------------------------- - # Below are the classmethods which act as alternate constructors to the - # TarFile class. The open() method is the only one that is needed for - # public use; it is the "super"-constructor and is able to select an - # adequate "sub"-constructor for a particular compression using the mapping - # from OPEN_METH. - # - # This concept allows one to subclass TarFile without losing the comfort of - # the super-constructor. A sub-constructor is registered and made available - # by adding it to the mapping in OPEN_METH. - - @classmethod - def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): - """Open a tar archive for reading, writing or appending. Return - an appropriate TarFile class. - - mode: - 'r' or 'r:*' open for reading with transparent compression - 'r:' open for reading exclusively uncompressed - 'r:gz' open for reading with gzip compression - 'r:bz2' open for reading with bzip2 compression - 'a' or 'a:' open for appending, creating the file if necessary - 'w' or 'w:' open for writing without compression - 'w:gz' open for writing with gzip compression - 'w:bz2' open for writing with bzip2 compression - - 'r|*' open a stream of tar blocks with transparent compression - 'r|' open an uncompressed stream of tar blocks for reading - 'r|gz' open a gzip compressed stream of tar blocks - 'r|bz2' open a bzip2 compressed stream of tar blocks - 'w|' open an uncompressed stream for writing - 'w|gz' open a gzip compressed stream for writing - 'w|bz2' open a bzip2 compressed stream for writing - """ - - if not name and not fileobj: - raise ValueError("nothing to open") - - if mode in ("r", "r:*"): - # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - if fileobj is not None: - saved_pos = fileobj.tell() - try: - return func(name, "r", fileobj, **kwargs) - except (ReadError, CompressionError) as e: - if fileobj is not None: - fileobj.seek(saved_pos) - continue - raise ReadError("file could not be opened successfully") - - elif ":" in mode: - filemode, comptype = mode.split(":", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - # Select the *open() function according to - # given compression. - if comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - else: - raise CompressionError("unknown compression type %r" % comptype) - return func(name, filemode, fileobj, **kwargs) - - elif "|" in mode: - filemode, comptype = mode.split("|", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - if filemode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - stream = _Stream(name, filemode, comptype, fileobj, bufsize) - try: - t = cls(name, filemode, stream, **kwargs) - except: - stream.close() - raise - t._extfileobj = False - return t - - elif mode in "aw": - return cls.taropen(name, mode, fileobj, **kwargs) - - raise ValueError("undiscernible mode") - - @classmethod - def taropen(cls, name, mode="r", fileobj=None, **kwargs): - """Open uncompressed tar archive name for reading or writing. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - return cls(name, mode, fileobj, **kwargs) - - @classmethod - def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open gzip compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - try: - import gzip - gzip.GzipFile - except (ImportError, AttributeError): - raise CompressionError("gzip module is not available") - - extfileobj = fileobj is not None - try: - fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) - t = cls.taropen(name, mode, fileobj, **kwargs) - except IOError: - if not extfileobj and fileobj is not None: - fileobj.close() - if fileobj is None: - raise - raise ReadError("not a gzip file") - except: - if not extfileobj and fileobj is not None: - fileobj.close() - raise - t._extfileobj = extfileobj - return t - - @classmethod - def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open bzip2 compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'.") - - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - - if fileobj is not None: - fileobj = _BZ2Proxy(fileobj, mode) - else: - fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) - - try: - t = cls.taropen(name, mode, fileobj, **kwargs) - except (IOError, EOFError): - fileobj.close() - raise ReadError("not a bzip2 file") - t._extfileobj = False - return t - - # All *open() methods are registered here. - OPEN_METH = { - "tar": "taropen", # uncompressed tar - "gz": "gzopen", # gzip compressed tar - "bz2": "bz2open" # bzip2 compressed tar - } - - #-------------------------------------------------------------------------- - # The public methods which TarFile provides: - - def close(self): - """Close the TarFile. In write-mode, two finishing zero blocks are - appended to the archive. - """ - if self.closed: - return - - if self.mode in "aw": - self.fileobj.write(NUL * (BLOCKSIZE * 2)) - self.offset += (BLOCKSIZE * 2) - # fill up the end with zero-blocks - # (like option -b20 for tar does) - blocks, remainder = divmod(self.offset, RECORDSIZE) - if remainder > 0: - self.fileobj.write(NUL * (RECORDSIZE - remainder)) - - if not self._extfileobj: - self.fileobj.close() - self.closed = True - - def getmember(self, name): - """Return a TarInfo object for member `name'. If `name' can not be - found in the archive, KeyError is raised. If a member occurs more - than once in the archive, its last occurrence is assumed to be the - most up-to-date version. - """ - tarinfo = self._getmember(name) - if tarinfo is None: - raise KeyError("filename %r not found" % name) - return tarinfo - - def getmembers(self): - """Return the members of the archive as a list of TarInfo objects. The - list has the same order as the members in the archive. - """ - self._check() - if not self._loaded: # if we want to obtain a list of - self._load() # all members, we first have to - # scan the whole archive. - return self.members - - def getnames(self): - """Return the members of the archive as a list of their names. It has - the same order as the list returned by getmembers(). - """ - return [tarinfo.name for tarinfo in self.getmembers()] - - def gettarinfo(self, name=None, arcname=None, fileobj=None): - """Create a TarInfo object for either the file `name' or the file - object `fileobj' (using os.fstat on its file descriptor). You can - modify some of the TarInfo's attributes before you add it using - addfile(). If given, `arcname' specifies an alternative name for the - file in the archive. - """ - self._check("aw") - - # When fileobj is given, replace name by - # fileobj's real name. - if fileobj is not None: - name = fileobj.name - - # Building the name of the member in the archive. - # Backward slashes are converted to forward slashes, - # Absolute paths are turned to relative paths. - if arcname is None: - arcname = name - drv, arcname = os.path.splitdrive(arcname) - arcname = arcname.replace(os.sep, "/") - arcname = arcname.lstrip("/") - - # Now, fill the TarInfo object with - # information specific for the file. - tarinfo = self.tarinfo() - tarinfo.tarfile = self - - # Use os.stat or os.lstat, depending on platform - # and if symlinks shall be resolved. - if fileobj is None: - if hasattr(os, "lstat") and not self.dereference: - statres = os.lstat(name) - else: - statres = os.stat(name) - else: - statres = os.fstat(fileobj.fileno()) - linkname = "" - - stmd = statres.st_mode - if stat.S_ISREG(stmd): - inode = (statres.st_ino, statres.st_dev) - if not self.dereference and statres.st_nlink > 1 and \ - inode in self.inodes and arcname != self.inodes[inode]: - # Is it a hardlink to an already - # archived file? - type = LNKTYPE - linkname = self.inodes[inode] - else: - # The inode is added only if its valid. - # For win32 it is always 0. - type = REGTYPE - if inode[0]: - self.inodes[inode] = arcname - elif stat.S_ISDIR(stmd): - type = DIRTYPE - elif stat.S_ISFIFO(stmd): - type = FIFOTYPE - elif stat.S_ISLNK(stmd): - type = SYMTYPE - linkname = os.readlink(name) - elif stat.S_ISCHR(stmd): - type = CHRTYPE - elif stat.S_ISBLK(stmd): - type = BLKTYPE - else: - return None - - # Fill the TarInfo object with all - # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if type == REGTYPE: - tarinfo.size = statres.st_size - else: - tarinfo.size = 0 - tarinfo.mtime = statres.st_mtime - tarinfo.type = type - tarinfo.linkname = linkname - if pwd: - try: - tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] - except KeyError: - pass - if grp: - try: - tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] - except KeyError: - pass - - if type in (CHRTYPE, BLKTYPE): - if hasattr(os, "major") and hasattr(os, "minor"): - tarinfo.devmajor = os.major(statres.st_rdev) - tarinfo.devminor = os.minor(statres.st_rdev) - return tarinfo - - def list(self, verbose=True): - """Print a table of contents to sys.stdout. If `verbose' is False, only - the names of the members are printed. If it is True, an `ls -l'-like - output is produced. - """ - self._check() - - for tarinfo in self: - if verbose: - print(filemode(tarinfo.mode), end=' ') - print("%s/%s" % (tarinfo.uname or tarinfo.uid, - tarinfo.gname or tarinfo.gid), end=' ') - if tarinfo.ischr() or tarinfo.isblk(): - print("%10s" % ("%d,%d" \ - % (tarinfo.devmajor, tarinfo.devminor)), end=' ') - else: - print("%10d" % tarinfo.size, end=' ') - print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6], end=' ') - - print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') - - if verbose: - if tarinfo.issym(): - print("->", tarinfo.linkname, end=' ') - if tarinfo.islnk(): - print("link to", tarinfo.linkname, end=' ') - print() - - def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): - """Add the file `name' to the archive. `name' may be any type of file - (directory, fifo, symbolic link, etc.). If given, `arcname' - specifies an alternative name for the file in the archive. - Directories are added recursively by default. This can be avoided by - setting `recursive' to False. `exclude' is a function that should - return True for each filename to be excluded. `filter' is a function - that expects a TarInfo object argument and returns the changed - TarInfo object, if it returns None the TarInfo object will be - excluded from the archive. - """ - self._check("aw") - - if arcname is None: - arcname = name - - # Exclude pathnames. - if exclude is not None: - import warnings - warnings.warn("use the filter argument instead", - DeprecationWarning, 2) - if exclude(name): - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.abspath(name) == self.name: - self._dbg(2, "tarfile: Skipped %r" % name) - return - - self._dbg(1, name) - - # Create a TarInfo object from the file. - tarinfo = self.gettarinfo(name, arcname) - - if tarinfo is None: - self._dbg(1, "tarfile: Unsupported type %r" % name) - return - - # Change or exclude the TarInfo object. - if filter is not None: - tarinfo = filter(tarinfo) - if tarinfo is None: - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Append the tar header and data to the archive. - if tarinfo.isreg(): - f = bltn_open(name, "rb") - self.addfile(tarinfo, f) - f.close() - - elif tarinfo.isdir(): - self.addfile(tarinfo) - if recursive: - for f in os.listdir(name): - self.add(os.path.join(name, f), os.path.join(arcname, f), - recursive, exclude, filter=filter) - - else: - self.addfile(tarinfo) - - def addfile(self, tarinfo, fileobj=None): - """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is - given, tarinfo.size bytes are read from it and added to the archive. - You can create TarInfo objects using gettarinfo(). - On Windows platforms, `fileobj' should always be opened with mode - 'rb' to avoid irritation about the file size. - """ - self._check("aw") - - tarinfo = copy.copy(tarinfo) - - buf = tarinfo.tobuf(self.format, self.encoding, self.errors) - self.fileobj.write(buf) - self.offset += len(buf) - - # If there's data to follow, append it. - if fileobj is not None: - copyfileobj(fileobj, self.fileobj, tarinfo.size) - blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) - if remainder > 0: - self.fileobj.write(NUL * (BLOCKSIZE - remainder)) - blocks += 1 - self.offset += blocks * BLOCKSIZE - - self.members.append(tarinfo) - - def extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir()) - - # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extract(self, member, path="", set_attrs=True): - """Extract a member from the archive to the current working directory, - using its full name. Its file information is extracted as accurately - as possible. `member' may be a filename or a TarInfo object. You can - specify a different directory using `path'. File attributes (owner, - mtime, mode) are set unless `set_attrs' is False. - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - # Prepare the link target for makelink(). - if tarinfo.islnk(): - tarinfo._link_target = os.path.join(path, tarinfo.linkname) - - try: - self._extract_member(tarinfo, os.path.join(path, tarinfo.name), - set_attrs=set_attrs) - except EnvironmentError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extractfile(self, member): - """Extract a member from the archive as a file object. `member' may be - a filename or a TarInfo object. If `member' is a regular file, a - file-like object is returned. If `member' is a link, a file-like - object is constructed from the link's target. If `member' is none of - the above, None is returned. - The file-like object is read-only and provides the following - methods: read(), readline(), readlines(), seek() and tell() - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - if tarinfo.isreg(): - return self.fileobject(self, tarinfo) - - elif tarinfo.type not in SUPPORTED_TYPES: - # If a member's type is unknown, it is treated as a - # regular file. - return self.fileobject(self, tarinfo) - - elif tarinfo.islnk() or tarinfo.issym(): - if isinstance(self.fileobj, _Stream): - # A small but ugly workaround for the case that someone tries - # to extract a (sym)link as a file-object from a non-seekable - # stream of tar blocks. - raise StreamError("cannot extract (sym)link as file object") - else: - # A (sym)link's file object is its target's file object. - return self.extractfile(self._find_link_target(tarinfo)) - else: - # If there's no data associated with the member (directory, chrdev, - # blkdev, etc.), return None instead of a file object. - return None - - def _extract_member(self, tarinfo, targetpath, set_attrs=True): - """Extract the TarInfo object tarinfo to a physical - file called targetpath. - """ - # Fetch the TarInfo object for the given name - # and build the destination pathname, replacing - # forward slashes to platform specific separators. - targetpath = targetpath.rstrip("/") - targetpath = targetpath.replace("/", os.sep) - - # Create all upper directories. - upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): - # Create directories that are not part of the archive with - # default permissions. - os.makedirs(upperdirs) - - if tarinfo.islnk() or tarinfo.issym(): - self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) - else: - self._dbg(1, tarinfo.name) - - if tarinfo.isreg(): - self.makefile(tarinfo, targetpath) - elif tarinfo.isdir(): - self.makedir(tarinfo, targetpath) - elif tarinfo.isfifo(): - self.makefifo(tarinfo, targetpath) - elif tarinfo.ischr() or tarinfo.isblk(): - self.makedev(tarinfo, targetpath) - elif tarinfo.islnk() or tarinfo.issym(): - self.makelink(tarinfo, targetpath) - elif tarinfo.type not in SUPPORTED_TYPES: - self.makeunknown(tarinfo, targetpath) - else: - self.makefile(tarinfo, targetpath) - - if set_attrs: - self.chown(tarinfo, targetpath) - if not tarinfo.issym(): - self.chmod(tarinfo, targetpath) - self.utime(tarinfo, targetpath) - - #-------------------------------------------------------------------------- - # Below are the different file methods. They are called via - # _extract_member() when extract() is called. They can be replaced in a - # subclass to implement other functionality. - - def makedir(self, tarinfo, targetpath): - """Make a directory called targetpath. - """ - try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) - except EnvironmentError as e: - if e.errno != errno.EEXIST: - raise - - def makefile(self, tarinfo, targetpath): - """Make a file called targetpath. - """ - source = self.fileobj - source.seek(tarinfo.offset_data) - target = bltn_open(targetpath, "wb") - if tarinfo.sparse is not None: - for offset, size in tarinfo.sparse: - target.seek(offset) - copyfileobj(source, target, size) - else: - copyfileobj(source, target, tarinfo.size) - target.seek(tarinfo.size) - target.truncate() - target.close() - - def makeunknown(self, tarinfo, targetpath): - """Make a file from a TarInfo object with an unknown type - at targetpath. - """ - self.makefile(tarinfo, targetpath) - self._dbg(1, "tarfile: Unknown file type %r, " \ - "extracted as regular file." % tarinfo.type) - - def makefifo(self, tarinfo, targetpath): - """Make a fifo called targetpath. - """ - if hasattr(os, "mkfifo"): - os.mkfifo(targetpath) - else: - raise ExtractError("fifo not supported by system") - - def makedev(self, tarinfo, targetpath): - """Make a character or block device called targetpath. - """ - if not hasattr(os, "mknod") or not hasattr(os, "makedev"): - raise ExtractError("special devices not supported by system") - - mode = tarinfo.mode - if tarinfo.isblk(): - mode |= stat.S_IFBLK - else: - mode |= stat.S_IFCHR - - os.mknod(targetpath, mode, - os.makedev(tarinfo.devmajor, tarinfo.devminor)) - - def makelink(self, tarinfo, targetpath): - """Make a (symbolic) link called targetpath. If it cannot be created - (platform limitation), we try to make a copy of the referenced file - instead of a link. - """ - try: - # For systems that support symbolic and hard links. - if tarinfo.issym(): - os.symlink(tarinfo.linkname, targetpath) - else: - # See extract(). - if os.path.exists(tarinfo._link_target): - os.link(tarinfo._link_target, targetpath) - else: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except symlink_exception: - if tarinfo.issym(): - linkpath = os.path.join(os.path.dirname(tarinfo.name), - tarinfo.linkname) - else: - linkpath = tarinfo.linkname - else: - try: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except KeyError: - raise ExtractError("unable to resolve link inside archive") - - def chown(self, tarinfo, targetpath): - """Set owner of targetpath according to tarinfo. - """ - if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: - # We have to be root to do so. - try: - g = grp.getgrnam(tarinfo.gname)[2] - except KeyError: - g = tarinfo.gid - try: - u = pwd.getpwnam(tarinfo.uname)[2] - except KeyError: - u = tarinfo.uid - try: - if tarinfo.issym() and hasattr(os, "lchown"): - os.lchown(targetpath, u, g) - else: - if sys.platform != "os2emx": - os.chown(targetpath, u, g) - except EnvironmentError as e: - raise ExtractError("could not change owner") - - def chmod(self, tarinfo, targetpath): - """Set file permissions of targetpath according to tarinfo. - """ - if hasattr(os, 'chmod'): - try: - os.chmod(targetpath, tarinfo.mode) - except EnvironmentError as e: - raise ExtractError("could not change mode") - - def utime(self, tarinfo, targetpath): - """Set modification time of targetpath according to tarinfo. - """ - if not hasattr(os, 'utime'): - return - try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) - except EnvironmentError as e: - raise ExtractError("could not change modification time") - - #-------------------------------------------------------------------------- - def next(self): - """Return the next member of the archive as a TarInfo object, when - TarFile is opened for reading. Return None if there is no more - available. - """ - self._check("ra") - if self.firstmember is not None: - m = self.firstmember - self.firstmember = None - return m - - # Read the next block. - self.fileobj.seek(self.offset) - tarinfo = None - while True: - try: - tarinfo = self.tarinfo.fromtarfile(self) - except EOFHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - except InvalidHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - elif self.offset == 0: - raise ReadError(str(e)) - except EmptyHeaderError: - if self.offset == 0: - raise ReadError("empty file") - except TruncatedHeaderError as e: - if self.offset == 0: - raise ReadError(str(e)) - except SubsequentHeaderError as e: - raise ReadError(str(e)) - break - - if tarinfo is not None: - self.members.append(tarinfo) - else: - self._loaded = True - - return tarinfo - - #-------------------------------------------------------------------------- - # Little helper methods: - - def _getmember(self, name, tarinfo=None, normalize=False): - """Find an archive member by name from bottom to top. - If tarinfo is given, it is used as the starting point. - """ - # Ensure that all members have been loaded. - members = self.getmembers() - - # Limit the member search list up to tarinfo. - if tarinfo is not None: - members = members[:members.index(tarinfo)] - - if normalize: - name = os.path.normpath(name) - - for member in reversed(members): - if normalize: - member_name = os.path.normpath(member.name) - else: - member_name = member.name - - if name == member_name: - return member - - def _load(self): - """Read through the entire archive file and look for readable - members. - """ - while True: - tarinfo = self.next() - if tarinfo is None: - break - self._loaded = True - - def _check(self, mode=None): - """Check if TarFile is still open, and if the operation's mode - corresponds to TarFile's mode. - """ - if self.closed: - raise IOError("%s is closed" % self.__class__.__name__) - if mode is not None and self.mode not in mode: - raise IOError("bad operation for mode %r" % self.mode) - - def _find_link_target(self, tarinfo): - """Find the target member of a symlink or hardlink member in the - archive. - """ - if tarinfo.issym(): - # Always search the entire archive. - linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname - limit = None - else: - # Search the archive before the link, because a hard link is - # just a reference to an already archived file. - linkname = tarinfo.linkname - limit = tarinfo - - member = self._getmember(linkname, tarinfo=limit, normalize=True) - if member is None: - raise KeyError("linkname %r not found" % linkname) - return member - - def __iter__(self): - """Provide an iterator object. - """ - if self._loaded: - return iter(self.members) - else: - return TarIter(self) - - def _dbg(self, level, msg): - """Write debugging output to sys.stderr. - """ - if level <= self.debug: - print(msg, file=sys.stderr) - - def __enter__(self): - self._check() - return self - - def __exit__(self, type, value, traceback): - if type is None: - self.close() - else: - # An exception occurred. We must not call close() because - # it would try to write end-of-archive blocks and padding. - if not self._extfileobj: - self.fileobj.close() - self.closed = True -# class TarFile - -class TarIter(object): - """Iterator Class. - - for tarinfo in TarFile(...): - suite... - """ - - def __init__(self, tarfile): - """Construct a TarIter object. - """ - self.tarfile = tarfile - self.index = 0 - def __iter__(self): - """Return iterator object. - """ - return self - - def __next__(self): - """Return the next item using TarFile's next() method. - When all members have been read, set TarFile as _loaded. - """ - # Fix for SF #1100429: Under rare circumstances it can - # happen that getmembers() is called during iteration, - # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: - tarinfo = self.tarfile.next() - if not tarinfo: - self.tarfile._loaded = True - raise StopIteration - else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration - self.index += 1 - return tarinfo - - next = __next__ # for Python 2.x - -#-------------------- -# exported functions -#-------------------- -def is_tarfile(name): - """Return True if name points to a tar archive that we - are able to handle, else return False. - """ - try: - t = open(name) - t.close() - return True - except TarError: - return False - -bltn_open = open -open = TarFile.open diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/compat.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/compat.py deleted file mode 100644 index c316fd9..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/compat.py +++ /dev/null @@ -1,1120 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2017 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import absolute_import - -import os -import re -import sys - -try: - import ssl -except ImportError: # pragma: no cover - ssl = None - -if sys.version_info[0] < 3: # pragma: no cover - from StringIO import StringIO - string_types = basestring, - text_type = unicode - from types import FileType as file_type - import __builtin__ as builtins - import ConfigParser as configparser - from ._backport import shutil - from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit - from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, - pathname2url, ContentTooShortError, splittype) - - def quote(s): - if isinstance(s, unicode): - s = s.encode('utf-8') - return _quote(s) - - import urllib2 - from urllib2 import (Request, urlopen, URLError, HTTPError, - HTTPBasicAuthHandler, HTTPPasswordMgr, - HTTPHandler, HTTPRedirectHandler, - build_opener) - if ssl: - from urllib2 import HTTPSHandler - import httplib - import xmlrpclib - import Queue as queue - from HTMLParser import HTMLParser - import htmlentitydefs - raw_input = raw_input - from itertools import ifilter as filter - from itertools import ifilterfalse as filterfalse - - _userprog = None - def splituser(host): - """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" - global _userprog - if _userprog is None: - import re - _userprog = re.compile('^(.*)@(.*)$') - - match = _userprog.match(host) - if match: return match.group(1, 2) - return None, host - -else: # pragma: no cover - from io import StringIO - string_types = str, - text_type = str - from io import TextIOWrapper as file_type - import builtins - import configparser - import shutil - from urllib.parse import (urlparse, urlunparse, urljoin, splituser, quote, - unquote, urlsplit, urlunsplit, splittype) - from urllib.request import (urlopen, urlretrieve, Request, url2pathname, - pathname2url, - HTTPBasicAuthHandler, HTTPPasswordMgr, - HTTPHandler, HTTPRedirectHandler, - build_opener) - if ssl: - from urllib.request import HTTPSHandler - from urllib.error import HTTPError, URLError, ContentTooShortError - import http.client as httplib - import urllib.request as urllib2 - import xmlrpc.client as xmlrpclib - import queue - from html.parser import HTMLParser - import html.entities as htmlentitydefs - raw_input = input - from itertools import filterfalse - filter = filter - -try: - from ssl import match_hostname, CertificateError -except ImportError: # pragma: no cover - class CertificateError(ValueError): - pass - - - def _dnsname_match(dn, hostname, max_wildcards=1): - """Matching according to RFC 6125, section 6.4.3 - - http://tools.ietf.org/html/rfc6125#section-6.4.3 - """ - pats = [] - if not dn: - return False - - parts = dn.split('.') - leftmost, remainder = parts[0], parts[1:] - - wildcards = leftmost.count('*') - if wildcards > max_wildcards: - # Issue #17980: avoid denials of service by refusing more - # than one wildcard per fragment. A survey of established - # policy among SSL implementations showed it to be a - # reasonable choice. - raise CertificateError( - "too many wildcards in certificate DNS name: " + repr(dn)) - - # speed up common case w/o wildcards - if not wildcards: - return dn.lower() == hostname.lower() - - # RFC 6125, section 6.4.3, subitem 1. - # The client SHOULD NOT attempt to match a presented identifier in which - # the wildcard character comprises a label other than the left-most label. - if leftmost == '*': - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append('[^.]+') - elif leftmost.startswith('xn--') or hostname.startswith('xn--'): - # RFC 6125, section 6.4.3, subitem 3. - # The client SHOULD NOT attempt to match a presented identifier - # where the wildcard character is embedded within an A-label or - # U-label of an internationalized domain name. - pats.append(re.escape(leftmost)) - else: - # Otherwise, '*' matches any dotless string, e.g. www* - pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) - - # add the remaining fragments, ignore any wildcards - for frag in remainder: - pats.append(re.escape(frag)) - - pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) - return pat.match(hostname) - - - def match_hostname(cert, hostname): - """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 - rules are followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError("empty or no certificate, match_hostname needs a " - "SSL socket or SSL context with either " - "CERT_OPTIONAL or CERT_REQUIRED") - dnsnames = [] - san = cert.get('subjectAltName', ()) - for key, value in san: - if key == 'DNS': - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if not dnsnames: - # The subject is only checked when there is no dNSName entry - # in subjectAltName - for sub in cert.get('subject', ()): - for key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == 'commonName': - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - raise CertificateError("hostname %r " - "doesn't match either of %s" - % (hostname, ', '.join(map(repr, dnsnames)))) - elif len(dnsnames) == 1: - raise CertificateError("hostname %r " - "doesn't match %r" - % (hostname, dnsnames[0])) - else: - raise CertificateError("no appropriate commonName or " - "subjectAltName fields were found") - - -try: - from types import SimpleNamespace as Container -except ImportError: # pragma: no cover - class Container(object): - """ - A generic container for when multiple values need to be returned - """ - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - -try: - from shutil import which -except ImportError: # pragma: no cover - # Implementation from Python 3.3 - def which(cmd, mode=os.F_OK | os.X_OK, path=None): - """Given a command, mode, and a PATH string, return the path which - conforms to the given mode on the PATH, or None if there is no such - file. - - `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result - of os.environ.get("PATH"), or can be overridden with a custom search - path. - - """ - # Check that a given file can be accessed with the correct mode. - # Additionally check that `file` is not a directory, as on Windows - # directories pass the os.access check. - def _access_check(fn, mode): - return (os.path.exists(fn) and os.access(fn, mode) - and not os.path.isdir(fn)) - - # If we're given a path with a directory part, look it up directly rather - # than referring to PATH directories. This includes checking relative to the - # current directory, e.g. ./script - if os.path.dirname(cmd): - if _access_check(cmd, mode): - return cmd - return None - - if path is None: - path = os.environ.get("PATH", os.defpath) - if not path: - return None - path = path.split(os.pathsep) - - if sys.platform == "win32": - # The current directory takes precedence on Windows. - if not os.curdir in path: - path.insert(0, os.curdir) - - # PATHEXT is necessary to check on Windows. - pathext = os.environ.get("PATHEXT", "").split(os.pathsep) - # See if the given file matches any of the expected path extensions. - # This will allow us to short circuit when given "python.exe". - # If it does match, only test that one, otherwise we have to try - # others. - if any(cmd.lower().endswith(ext.lower()) for ext in pathext): - files = [cmd] - else: - files = [cmd + ext for ext in pathext] - else: - # On other platforms you don't have things like PATHEXT to tell you - # what file suffixes are executable, so just pass on cmd as-is. - files = [cmd] - - seen = set() - for dir in path: - normdir = os.path.normcase(dir) - if not normdir in seen: - seen.add(normdir) - for thefile in files: - name = os.path.join(dir, thefile) - if _access_check(name, mode): - return name - return None - - -# ZipFile is a context manager in 2.7, but not in 2.6 - -from zipfile import ZipFile as BaseZipFile - -if hasattr(BaseZipFile, '__enter__'): # pragma: no cover - ZipFile = BaseZipFile -else: # pragma: no cover - from zipfile import ZipExtFile as BaseZipExtFile - - class ZipExtFile(BaseZipExtFile): - def __init__(self, base): - self.__dict__.update(base.__dict__) - - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.close() - # return None, so if an exception occurred, it will propagate - - class ZipFile(BaseZipFile): - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.close() - # return None, so if an exception occurred, it will propagate - - def open(self, *args, **kwargs): - base = BaseZipFile.open(self, *args, **kwargs) - return ZipExtFile(base) - -try: - from platform import python_implementation -except ImportError: # pragma: no cover - def python_implementation(): - """Return a string identifying the Python implementation.""" - if 'PyPy' in sys.version: - return 'PyPy' - if os.name == 'java': - return 'Jython' - if sys.version.startswith('IronPython'): - return 'IronPython' - return 'CPython' - -try: - import sysconfig -except ImportError: # pragma: no cover - from ._backport import sysconfig - -try: - callable = callable -except NameError: # pragma: no cover - from collections.abc import Callable - - def callable(obj): - return isinstance(obj, Callable) - - -try: - fsencode = os.fsencode - fsdecode = os.fsdecode -except AttributeError: # pragma: no cover - # Issue #99: on some systems (e.g. containerised), - # sys.getfilesystemencoding() returns None, and we need a real value, - # so fall back to utf-8. From the CPython 2.7 docs relating to Unix and - # sys.getfilesystemencoding(): the return value is "the user’s preference - # according to the result of nl_langinfo(CODESET), or None if the - # nl_langinfo(CODESET) failed." - _fsencoding = sys.getfilesystemencoding() or 'utf-8' - if _fsencoding == 'mbcs': - _fserrors = 'strict' - else: - _fserrors = 'surrogateescape' - - def fsencode(filename): - if isinstance(filename, bytes): - return filename - elif isinstance(filename, text_type): - return filename.encode(_fsencoding, _fserrors) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) - - def fsdecode(filename): - if isinstance(filename, text_type): - return filename - elif isinstance(filename, bytes): - return filename.decode(_fsencoding, _fserrors) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) - -try: - from tokenize import detect_encoding -except ImportError: # pragma: no cover - from codecs import BOM_UTF8, lookup - import re - - cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)") - - def _get_normal_name(orig_enc): - """Imitates get_normal_name in tokenizer.c.""" - # Only care about the first 12 characters. - enc = orig_enc[:12].lower().replace("_", "-") - if enc == "utf-8" or enc.startswith("utf-8-"): - return "utf-8" - if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ - enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): - return "iso-8859-1" - return orig_enc - - def detect_encoding(readline): - """ - The detect_encoding() function is used to detect the encoding that should - be used to decode a Python source file. It requires one argument, readline, - in the same way as the tokenize() generator. - - It will call readline a maximum of twice, and return the encoding used - (as a string) and a list of any lines (left as bytes) it has read in. - - It detects the encoding from the presence of a utf-8 bom or an encoding - cookie as specified in pep-0263. If both a bom and a cookie are present, - but disagree, a SyntaxError will be raised. If the encoding cookie is an - invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, - 'utf-8-sig' is returned. - - If no encoding is specified, then the default of 'utf-8' will be returned. - """ - try: - filename = readline.__self__.name - except AttributeError: - filename = None - bom_found = False - encoding = None - default = 'utf-8' - def read_or_stop(): - try: - return readline() - except StopIteration: - return b'' - - def find_cookie(line): - try: - # Decode as UTF-8. Either the line is an encoding declaration, - # in which case it should be pure ASCII, or it must be UTF-8 - # per default encoding. - line_string = line.decode('utf-8') - except UnicodeDecodeError: - msg = "invalid or missing encoding declaration" - if filename is not None: - msg = '{} for {!r}'.format(msg, filename) - raise SyntaxError(msg) - - matches = cookie_re.findall(line_string) - if not matches: - return None - encoding = _get_normal_name(matches[0]) - try: - codec = lookup(encoding) - except LookupError: - # This behaviour mimics the Python interpreter - if filename is None: - msg = "unknown encoding: " + encoding - else: - msg = "unknown encoding for {!r}: {}".format(filename, - encoding) - raise SyntaxError(msg) - - if bom_found: - if codec.name != 'utf-8': - # This behaviour mimics the Python interpreter - if filename is None: - msg = 'encoding problem: utf-8' - else: - msg = 'encoding problem for {!r}: utf-8'.format(filename) - raise SyntaxError(msg) - encoding += '-sig' - return encoding - - first = read_or_stop() - if first.startswith(BOM_UTF8): - bom_found = True - first = first[3:] - default = 'utf-8-sig' - if not first: - return default, [] - - encoding = find_cookie(first) - if encoding: - return encoding, [first] - - second = read_or_stop() - if not second: - return default, [first] - - encoding = find_cookie(second) - if encoding: - return encoding, [first, second] - - return default, [first, second] - -# For converting & <-> & etc. -try: - from html import escape -except ImportError: - from cgi import escape -if sys.version_info[:2] < (3, 4): - unescape = HTMLParser().unescape -else: - from html import unescape - -try: - from collections import ChainMap -except ImportError: # pragma: no cover - from collections import MutableMapping - - try: - from reprlib import recursive_repr as _recursive_repr - except ImportError: - def _recursive_repr(fillvalue='...'): - ''' - Decorator to make a repr function return fillvalue for a recursive - call - ''' - - def decorating_function(user_function): - repr_running = set() - - def wrapper(self): - key = id(self), get_ident() - if key in repr_running: - return fillvalue - repr_running.add(key) - try: - result = user_function(self) - finally: - repr_running.discard(key) - return result - - # Can't use functools.wraps() here because of bootstrap issues - wrapper.__module__ = getattr(user_function, '__module__') - wrapper.__doc__ = getattr(user_function, '__doc__') - wrapper.__name__ = getattr(user_function, '__name__') - wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) - return wrapper - - return decorating_function - - class ChainMap(MutableMapping): - ''' A ChainMap groups multiple dicts (or other mappings) together - to create a single, updateable view. - - The underlying mappings are stored in a list. That list is public and can - accessed or updated using the *maps* attribute. There is no other state. - - Lookups search the underlying mappings successively until a key is found. - In contrast, writes, updates, and deletions only operate on the first - mapping. - - ''' - - def __init__(self, *maps): - '''Initialize a ChainMap by setting *maps* to the given mappings. - If no mappings are provided, a single empty dictionary is used. - - ''' - self.maps = list(maps) or [{}] # always at least one map - - def __missing__(self, key): - raise KeyError(key) - - def __getitem__(self, key): - for mapping in self.maps: - try: - return mapping[key] # can't use 'key in mapping' with defaultdict - except KeyError: - pass - return self.__missing__(key) # support subclasses that define __missing__ - - def get(self, key, default=None): - return self[key] if key in self else default - - def __len__(self): - return len(set().union(*self.maps)) # reuses stored hash values if possible - - def __iter__(self): - return iter(set().union(*self.maps)) - - def __contains__(self, key): - return any(key in m for m in self.maps) - - def __bool__(self): - return any(self.maps) - - @_recursive_repr() - def __repr__(self): - return '{0.__class__.__name__}({1})'.format( - self, ', '.join(map(repr, self.maps))) - - @classmethod - def fromkeys(cls, iterable, *args): - 'Create a ChainMap with a single dict created from the iterable.' - return cls(dict.fromkeys(iterable, *args)) - - def copy(self): - 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' - return self.__class__(self.maps[0].copy(), *self.maps[1:]) - - __copy__ = copy - - def new_child(self): # like Django's Context.push() - 'New ChainMap with a new dict followed by all previous maps.' - return self.__class__({}, *self.maps) - - @property - def parents(self): # like Django's Context.pop() - 'New ChainMap from maps[1:].' - return self.__class__(*self.maps[1:]) - - def __setitem__(self, key, value): - self.maps[0][key] = value - - def __delitem__(self, key): - try: - del self.maps[0][key] - except KeyError: - raise KeyError('Key not found in the first mapping: {!r}'.format(key)) - - def popitem(self): - 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' - try: - return self.maps[0].popitem() - except KeyError: - raise KeyError('No keys found in the first mapping.') - - def pop(self, key, *args): - 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' - try: - return self.maps[0].pop(key, *args) - except KeyError: - raise KeyError('Key not found in the first mapping: {!r}'.format(key)) - - def clear(self): - 'Clear maps[0], leaving maps[1:] intact.' - self.maps[0].clear() - -try: - from importlib.util import cache_from_source # Python >= 3.4 -except ImportError: # pragma: no cover - try: - from imp import cache_from_source - except ImportError: # pragma: no cover - def cache_from_source(path, debug_override=None): - assert path.endswith('.py') - if debug_override is None: - debug_override = __debug__ - if debug_override: - suffix = 'c' - else: - suffix = 'o' - return path + suffix - -try: - from collections import OrderedDict -except ImportError: # pragma: no cover -## {{{ http://code.activestate.com/recipes/576693/ (r9) -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. - try: - from thread import get_ident as _get_ident - except ImportError: - from dummy_thread import get_ident as _get_ident - - try: - from _abcoll import KeysView, ValuesView, ItemsView - except ImportError: - pass - - - class OrderedDict(dict): - 'Dictionary that remembers insertion order' - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running=None): - 'od.__repr__() <==> repr(od)' - if not _repr_running: _repr_running = {} - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) - -try: - from logging.config import BaseConfigurator, valid_ident -except ImportError: # pragma: no cover - IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) - - - def valid_ident(s): - m = IDENTIFIER.match(s) - if not m: - raise ValueError('Not a valid Python identifier: %r' % s) - return True - - - # The ConvertingXXX classes are wrappers around standard Python containers, - # and they serve to convert any suitable values in the container. The - # conversion converts base dicts, lists and tuples to their wrapped - # equivalents, whereas strings which match a conversion format are converted - # appropriately. - # - # Each wrapper should have a configurator attribute holding the actual - # configurator to use for conversion. - - class ConvertingDict(dict): - """A converting dictionary wrapper.""" - - def __getitem__(self, key): - value = dict.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def get(self, key, default=None): - value = dict.get(self, key, default) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def pop(self, key, default=None): - value = dict.pop(self, key, default) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - class ConvertingList(list): - """A converting list wrapper.""" - def __getitem__(self, key): - value = list.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def pop(self, idx=-1): - value = list.pop(self, idx) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - return result - - class ConvertingTuple(tuple): - """A converting tuple wrapper.""" - def __getitem__(self, key): - value = tuple.__getitem__(self, key) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - class BaseConfigurator(object): - """ - The configurator base class which defines some useful defaults. - """ - - CONVERT_PATTERN = re.compile(r'^(?P[a-z]+)://(?P.*)$') - - WORD_PATTERN = re.compile(r'^\s*(\w+)\s*') - DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*') - INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*') - DIGIT_PATTERN = re.compile(r'^\d+$') - - value_converters = { - 'ext' : 'ext_convert', - 'cfg' : 'cfg_convert', - } - - # We might want to use a different one, e.g. importlib - importer = staticmethod(__import__) - - def __init__(self, config): - self.config = ConvertingDict(config) - self.config.configurator = self - - def resolve(self, s): - """ - Resolve strings to objects using standard import and attribute - syntax. - """ - name = s.split('.') - used = name.pop(0) - try: - found = self.importer(used) - for frag in name: - used += '.' + frag - try: - found = getattr(found, frag) - except AttributeError: - self.importer(used) - found = getattr(found, frag) - return found - except ImportError: - e, tb = sys.exc_info()[1:] - v = ValueError('Cannot resolve %r: %s' % (s, e)) - v.__cause__, v.__traceback__ = e, tb - raise v - - def ext_convert(self, value): - """Default converter for the ext:// protocol.""" - return self.resolve(value) - - def cfg_convert(self, value): - """Default converter for the cfg:// protocol.""" - rest = value - m = self.WORD_PATTERN.match(rest) - if m is None: - raise ValueError("Unable to convert %r" % value) - else: - rest = rest[m.end():] - d = self.config[m.groups()[0]] - #print d, rest - while rest: - m = self.DOT_PATTERN.match(rest) - if m: - d = d[m.groups()[0]] - else: - m = self.INDEX_PATTERN.match(rest) - if m: - idx = m.groups()[0] - if not self.DIGIT_PATTERN.match(idx): - d = d[idx] - else: - try: - n = int(idx) # try as number first (most likely) - d = d[n] - except TypeError: - d = d[idx] - if m: - rest = rest[m.end():] - else: - raise ValueError('Unable to convert ' - '%r at %r' % (value, rest)) - #rest should be empty - return d - - def convert(self, value): - """ - Convert values to an appropriate type. dicts, lists and tuples are - replaced by their converting alternatives. Strings are checked to - see if they have a conversion format and are converted if they do. - """ - if not isinstance(value, ConvertingDict) and isinstance(value, dict): - value = ConvertingDict(value) - value.configurator = self - elif not isinstance(value, ConvertingList) and isinstance(value, list): - value = ConvertingList(value) - value.configurator = self - elif not isinstance(value, ConvertingTuple) and\ - isinstance(value, tuple): - value = ConvertingTuple(value) - value.configurator = self - elif isinstance(value, string_types): - m = self.CONVERT_PATTERN.match(value) - if m: - d = m.groupdict() - prefix = d['prefix'] - converter = self.value_converters.get(prefix, None) - if converter: - suffix = d['suffix'] - converter = getattr(self, converter) - value = converter(suffix) - return value - - def configure_custom(self, config): - """Configure an object with a user-supplied factory.""" - c = config.pop('()') - if not callable(c): - c = self.resolve(c) - props = config.pop('.', None) - # Check for valid identifiers - kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) - result = c(**kwargs) - if props: - for name, value in props.items(): - setattr(result, name, value) - return result - - def as_tuple(self, value): - """Utility function which converts lists to tuples.""" - if isinstance(value, list): - value = tuple(value) - return value diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/database.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/database.py deleted file mode 100644 index 0a90c30..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/database.py +++ /dev/null @@ -1,1339 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2017 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""PEP 376 implementation.""" - -from __future__ import unicode_literals - -import base64 -import codecs -import contextlib -import hashlib -import logging -import os -import posixpath -import sys -import zipimport - -from . import DistlibException, resources -from .compat import StringIO -from .version import get_scheme, UnsupportedVersionError -from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME, - LEGACY_METADATA_FILENAME) -from .util import (parse_requirement, cached_property, parse_name_and_version, - read_exports, write_exports, CSVReader, CSVWriter) - - -__all__ = ['Distribution', 'BaseInstalledDistribution', - 'InstalledDistribution', 'EggInfoDistribution', - 'DistributionPath'] - - -logger = logging.getLogger(__name__) - -EXPORTS_FILENAME = 'pydist-exports.json' -COMMANDS_FILENAME = 'pydist-commands.json' - -DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', - 'RESOURCES', EXPORTS_FILENAME, 'SHARED') - -DISTINFO_EXT = '.dist-info' - - -class _Cache(object): - """ - A simple cache mapping names and .dist-info paths to distributions - """ - def __init__(self): - """ - Initialise an instance. There is normally one for each DistributionPath. - """ - self.name = {} - self.path = {} - self.generated = False - - def clear(self): - """ - Clear the cache, setting it to its initial state. - """ - self.name.clear() - self.path.clear() - self.generated = False - - def add(self, dist): - """ - Add a distribution to the cache. - :param dist: The distribution to add. - """ - if dist.path not in self.path: - self.path[dist.path] = dist - self.name.setdefault(dist.key, []).append(dist) - - -class DistributionPath(object): - """ - Represents a set of distributions installed on a path (typically sys.path). - """ - def __init__(self, path=None, include_egg=False): - """ - Create an instance from a path, optionally including legacy (distutils/ - setuptools/distribute) distributions. - :param path: The path to use, as a list of directories. If not specified, - sys.path is used. - :param include_egg: If True, this instance will look for and return legacy - distributions as well as those based on PEP 376. - """ - if path is None: - path = sys.path - self.path = path - self._include_dist = True - self._include_egg = include_egg - - self._cache = _Cache() - self._cache_egg = _Cache() - self._cache_enabled = True - self._scheme = get_scheme('default') - - def _get_cache_enabled(self): - return self._cache_enabled - - def _set_cache_enabled(self, value): - self._cache_enabled = value - - cache_enabled = property(_get_cache_enabled, _set_cache_enabled) - - def clear_cache(self): - """ - Clears the internal cache. - """ - self._cache.clear() - self._cache_egg.clear() - - - def _yield_distributions(self): - """ - Yield .dist-info and/or .egg(-info) distributions. - """ - # We need to check if we've seen some resources already, because on - # some Linux systems (e.g. some Debian/Ubuntu variants) there are - # symlinks which alias other files in the environment. - seen = set() - for path in self.path: - finder = resources.finder_for_path(path) - if finder is None: - continue - r = finder.find('') - if not r or not r.is_container: - continue - rset = sorted(r.resources) - for entry in rset: - r = finder.find(entry) - if not r or r.path in seen: - continue - if self._include_dist and entry.endswith(DISTINFO_EXT): - possible_filenames = [METADATA_FILENAME, - WHEEL_METADATA_FILENAME, - LEGACY_METADATA_FILENAME] - for metadata_filename in possible_filenames: - metadata_path = posixpath.join(entry, metadata_filename) - pydist = finder.find(metadata_path) - if pydist: - break - else: - continue - - with contextlib.closing(pydist.as_stream()) as stream: - metadata = Metadata(fileobj=stream, scheme='legacy') - logger.debug('Found %s', r.path) - seen.add(r.path) - yield new_dist_class(r.path, metadata=metadata, - env=self) - elif self._include_egg and entry.endswith(('.egg-info', - '.egg')): - logger.debug('Found %s', r.path) - seen.add(r.path) - yield old_dist_class(r.path, self) - - def _generate_cache(self): - """ - Scan the path for distributions and populate the cache with - those that are found. - """ - gen_dist = not self._cache.generated - gen_egg = self._include_egg and not self._cache_egg.generated - if gen_dist or gen_egg: - for dist in self._yield_distributions(): - if isinstance(dist, InstalledDistribution): - self._cache.add(dist) - else: - self._cache_egg.add(dist) - - if gen_dist: - self._cache.generated = True - if gen_egg: - self._cache_egg.generated = True - - @classmethod - def distinfo_dirname(cls, name, version): - """ - The *name* and *version* parameters are converted into their - filename-escaped form, i.e. any ``'-'`` characters are replaced - with ``'_'`` other than the one in ``'dist-info'`` and the one - separating the name from the version number. - - :parameter name: is converted to a standard distribution name by replacing - any runs of non- alphanumeric characters with a single - ``'-'``. - :type name: string - :parameter version: is converted to a standard version string. Spaces - become dots, and all other non-alphanumeric characters - (except dots) become dashes, with runs of multiple - dashes condensed to a single dash. - :type version: string - :returns: directory name - :rtype: string""" - name = name.replace('-', '_') - return '-'.join([name, version]) + DISTINFO_EXT - - def get_distributions(self): - """ - Provides an iterator that looks for distributions and returns - :class:`InstalledDistribution` or - :class:`EggInfoDistribution` instances for each one of them. - - :rtype: iterator of :class:`InstalledDistribution` and - :class:`EggInfoDistribution` instances - """ - if not self._cache_enabled: - for dist in self._yield_distributions(): - yield dist - else: - self._generate_cache() - - for dist in self._cache.path.values(): - yield dist - - if self._include_egg: - for dist in self._cache_egg.path.values(): - yield dist - - def get_distribution(self, name): - """ - Looks for a named distribution on the path. - - This function only returns the first result found, as no more than one - value is expected. If nothing is found, ``None`` is returned. - - :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` - or ``None`` - """ - result = None - name = name.lower() - if not self._cache_enabled: - for dist in self._yield_distributions(): - if dist.key == name: - result = dist - break - else: - self._generate_cache() - - if name in self._cache.name: - result = self._cache.name[name][0] - elif self._include_egg and name in self._cache_egg.name: - result = self._cache_egg.name[name][0] - return result - - def provides_distribution(self, name, version=None): - """ - Iterates over all distributions to find which distributions provide *name*. - If a *version* is provided, it will be used to filter the results. - - This function only returns the first result found, since no more than - one values are expected. If the directory is not found, returns ``None``. - - :parameter version: a version specifier that indicates the version - required, conforming to the format in ``PEP-345`` - - :type name: string - :type version: string - """ - matcher = None - if version is not None: - try: - matcher = self._scheme.matcher('%s (%s)' % (name, version)) - except ValueError: - raise DistlibException('invalid name or version: %r, %r' % - (name, version)) - - for dist in self.get_distributions(): - # We hit a problem on Travis where enum34 was installed and doesn't - # have a provides attribute ... - if not hasattr(dist, 'provides'): - logger.debug('No "provides": %s', dist) - else: - provided = dist.provides - - for p in provided: - p_name, p_ver = parse_name_and_version(p) - if matcher is None: - if p_name == name: - yield dist - break - else: - if p_name == name and matcher.match(p_ver): - yield dist - break - - def get_file_path(self, name, relative_path): - """ - Return the path to a resource file. - """ - dist = self.get_distribution(name) - if dist is None: - raise LookupError('no distribution named %r found' % name) - return dist.get_resource_path(relative_path) - - def get_exported_entries(self, category, name=None): - """ - Return all of the exported entries in a particular category. - - :param category: The category to search for entries. - :param name: If specified, only entries with that name are returned. - """ - for dist in self.get_distributions(): - r = dist.exports - if category in r: - d = r[category] - if name is not None: - if name in d: - yield d[name] - else: - for v in d.values(): - yield v - - -class Distribution(object): - """ - A base class for distributions, whether installed or from indexes. - Either way, it must have some metadata, so that's all that's needed - for construction. - """ - - build_time_dependency = False - """ - Set to True if it's known to be only a build-time dependency (i.e. - not needed after installation). - """ - - requested = False - """A boolean that indicates whether the ``REQUESTED`` metadata file is - present (in other words, whether the package was installed by user - request or it was installed as a dependency).""" - - def __init__(self, metadata): - """ - Initialise an instance. - :param metadata: The instance of :class:`Metadata` describing this - distribution. - """ - self.metadata = metadata - self.name = metadata.name - self.key = self.name.lower() # for case-insensitive comparisons - self.version = metadata.version - self.locator = None - self.digest = None - self.extras = None # additional features requested - self.context = None # environment marker overrides - self.download_urls = set() - self.digests = {} - - @property - def source_url(self): - """ - The source archive download URL for this distribution. - """ - return self.metadata.source_url - - download_url = source_url # Backward compatibility - - @property - def name_and_version(self): - """ - A utility property which displays the name and version in parentheses. - """ - return '%s (%s)' % (self.name, self.version) - - @property - def provides(self): - """ - A set of distribution names and versions provided by this distribution. - :return: A set of "name (version)" strings. - """ - plist = self.metadata.provides - s = '%s (%s)' % (self.name, self.version) - if s not in plist: - plist.append(s) - return plist - - def _get_requirements(self, req_attr): - md = self.metadata - logger.debug('Getting requirements from metadata %r', md.todict()) - reqts = getattr(md, req_attr) - return set(md.get_requirements(reqts, extras=self.extras, - env=self.context)) - - @property - def run_requires(self): - return self._get_requirements('run_requires') - - @property - def meta_requires(self): - return self._get_requirements('meta_requires') - - @property - def build_requires(self): - return self._get_requirements('build_requires') - - @property - def test_requires(self): - return self._get_requirements('test_requires') - - @property - def dev_requires(self): - return self._get_requirements('dev_requires') - - def matches_requirement(self, req): - """ - Say if this instance matches (fulfills) a requirement. - :param req: The requirement to match. - :rtype req: str - :return: True if it matches, else False. - """ - # Requirement may contain extras - parse to lose those - # from what's passed to the matcher - r = parse_requirement(req) - scheme = get_scheme(self.metadata.scheme) - try: - matcher = scheme.matcher(r.requirement) - except UnsupportedVersionError: - # XXX compat-mode if cannot read the version - logger.warning('could not read version %r - using name only', - req) - name = req.split()[0] - matcher = scheme.matcher(name) - - name = matcher.key # case-insensitive - - result = False - for p in self.provides: - p_name, p_ver = parse_name_and_version(p) - if p_name != name: - continue - try: - result = matcher.match(p_ver) - break - except UnsupportedVersionError: - pass - return result - - def __repr__(self): - """ - Return a textual representation of this instance, - """ - if self.source_url: - suffix = ' [%s]' % self.source_url - else: - suffix = '' - return '' % (self.name, self.version, suffix) - - def __eq__(self, other): - """ - See if this distribution is the same as another. - :param other: The distribution to compare with. To be equal to one - another. distributions must have the same type, name, - version and source_url. - :return: True if it is the same, else False. - """ - if type(other) is not type(self): - result = False - else: - result = (self.name == other.name and - self.version == other.version and - self.source_url == other.source_url) - return result - - def __hash__(self): - """ - Compute hash in a way which matches the equality test. - """ - return hash(self.name) + hash(self.version) + hash(self.source_url) - - -class BaseInstalledDistribution(Distribution): - """ - This is the base class for installed distributions (whether PEP 376 or - legacy). - """ - - hasher = None - - def __init__(self, metadata, path, env=None): - """ - Initialise an instance. - :param metadata: An instance of :class:`Metadata` which describes the - distribution. This will normally have been initialised - from a metadata file in the ``path``. - :param path: The path of the ``.dist-info`` or ``.egg-info`` - directory for the distribution. - :param env: This is normally the :class:`DistributionPath` - instance where this distribution was found. - """ - super(BaseInstalledDistribution, self).__init__(metadata) - self.path = path - self.dist_path = env - - def get_hash(self, data, hasher=None): - """ - Get the hash of some data, using a particular hash algorithm, if - specified. - - :param data: The data to be hashed. - :type data: bytes - :param hasher: The name of a hash implementation, supported by hashlib, - or ``None``. Examples of valid values are ``'sha1'``, - ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and - ``'sha512'``. If no hasher is specified, the ``hasher`` - attribute of the :class:`InstalledDistribution` instance - is used. If the hasher is determined to be ``None``, MD5 - is used as the hashing algorithm. - :returns: The hash of the data. If a hasher was explicitly specified, - the returned hash will be prefixed with the specified hasher - followed by '='. - :rtype: str - """ - if hasher is None: - hasher = self.hasher - if hasher is None: - hasher = hashlib.md5 - prefix = '' - else: - hasher = getattr(hashlib, hasher) - prefix = '%s=' % self.hasher - digest = hasher(data).digest() - digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') - return '%s%s' % (prefix, digest) - - -class InstalledDistribution(BaseInstalledDistribution): - """ - Created with the *path* of the ``.dist-info`` directory provided to the - constructor. It reads the metadata contained in ``pydist.json`` when it is - instantiated., or uses a passed in Metadata instance (useful for when - dry-run mode is being used). - """ - - hasher = 'sha256' - - def __init__(self, path, metadata=None, env=None): - self.modules = [] - self.finder = finder = resources.finder_for_path(path) - if finder is None: - raise ValueError('finder unavailable for %s' % path) - if env and env._cache_enabled and path in env._cache.path: - metadata = env._cache.path[path].metadata - elif metadata is None: - r = finder.find(METADATA_FILENAME) - # Temporary - for Wheel 0.23 support - if r is None: - r = finder.find(WHEEL_METADATA_FILENAME) - # Temporary - for legacy support - if r is None: - r = finder.find(LEGACY_METADATA_FILENAME) - if r is None: - raise ValueError('no %s found in %s' % (METADATA_FILENAME, - path)) - with contextlib.closing(r.as_stream()) as stream: - metadata = Metadata(fileobj=stream, scheme='legacy') - - super(InstalledDistribution, self).__init__(metadata, path, env) - - if env and env._cache_enabled: - env._cache.add(self) - - r = finder.find('REQUESTED') - self.requested = r is not None - p = os.path.join(path, 'top_level.txt') - if os.path.exists(p): - with open(p, 'rb') as f: - data = f.read().decode('utf-8') - self.modules = data.splitlines() - - def __repr__(self): - return '' % ( - self.name, self.version, self.path) - - def __str__(self): - return "%s %s" % (self.name, self.version) - - def _get_records(self): - """ - Get the list of installed files for the distribution - :return: A list of tuples of path, hash and size. Note that hash and - size might be ``None`` for some entries. The path is exactly - as stored in the file (which is as in PEP 376). - """ - results = [] - r = self.get_distinfo_resource('RECORD') - with contextlib.closing(r.as_stream()) as stream: - with CSVReader(stream=stream) as record_reader: - # Base location is parent dir of .dist-info dir - #base_location = os.path.dirname(self.path) - #base_location = os.path.abspath(base_location) - for row in record_reader: - missing = [None for i in range(len(row), 3)] - path, checksum, size = row + missing - #if not os.path.isabs(path): - # path = path.replace('/', os.sep) - # path = os.path.join(base_location, path) - results.append((path, checksum, size)) - return results - - @cached_property - def exports(self): - """ - Return the information exported by this distribution. - :return: A dictionary of exports, mapping an export category to a dict - of :class:`ExportEntry` instances describing the individual - export entries, and keyed by name. - """ - result = {} - r = self.get_distinfo_resource(EXPORTS_FILENAME) - if r: - result = self.read_exports() - return result - - def read_exports(self): - """ - Read exports data from a file in .ini format. - - :return: A dictionary of exports, mapping an export category to a list - of :class:`ExportEntry` instances describing the individual - export entries. - """ - result = {} - r = self.get_distinfo_resource(EXPORTS_FILENAME) - if r: - with contextlib.closing(r.as_stream()) as stream: - result = read_exports(stream) - return result - - def write_exports(self, exports): - """ - Write a dictionary of exports to a file in .ini format. - :param exports: A dictionary of exports, mapping an export category to - a list of :class:`ExportEntry` instances describing the - individual export entries. - """ - rf = self.get_distinfo_file(EXPORTS_FILENAME) - with open(rf, 'w') as f: - write_exports(exports, f) - - def get_resource_path(self, relative_path): - """ - NOTE: This API may change in the future. - - Return the absolute path to a resource file with the given relative - path. - - :param relative_path: The path, relative to .dist-info, of the resource - of interest. - :return: The absolute path where the resource is to be found. - """ - r = self.get_distinfo_resource('RESOURCES') - with contextlib.closing(r.as_stream()) as stream: - with CSVReader(stream=stream) as resources_reader: - for relative, destination in resources_reader: - if relative == relative_path: - return destination - raise KeyError('no resource file with relative path %r ' - 'is installed' % relative_path) - - def list_installed_files(self): - """ - Iterates over the ``RECORD`` entries and returns a tuple - ``(path, hash, size)`` for each line. - - :returns: iterator of (path, hash, size) - """ - for result in self._get_records(): - yield result - - def write_installed_files(self, paths, prefix, dry_run=False): - """ - Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any - existing ``RECORD`` file is silently overwritten. - - prefix is used to determine when to write absolute paths. - """ - prefix = os.path.join(prefix, '') - base = os.path.dirname(self.path) - base_under_prefix = base.startswith(prefix) - base = os.path.join(base, '') - record_path = self.get_distinfo_file('RECORD') - logger.info('creating %s', record_path) - if dry_run: - return None - with CSVWriter(record_path) as writer: - for path in paths: - if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')): - # do not put size and hash, as in PEP-376 - hash_value = size = '' - else: - size = '%d' % os.path.getsize(path) - with open(path, 'rb') as fp: - hash_value = self.get_hash(fp.read()) - if path.startswith(base) or (base_under_prefix and - path.startswith(prefix)): - path = os.path.relpath(path, base) - writer.writerow((path, hash_value, size)) - - # add the RECORD file itself - if record_path.startswith(base): - record_path = os.path.relpath(record_path, base) - writer.writerow((record_path, '', '')) - return record_path - - def check_installed_files(self): - """ - Checks that the hashes and sizes of the files in ``RECORD`` are - matched by the files themselves. Returns a (possibly empty) list of - mismatches. Each entry in the mismatch list will be a tuple consisting - of the path, 'exists', 'size' or 'hash' according to what didn't match - (existence is checked first, then size, then hash), the expected - value and the actual value. - """ - mismatches = [] - base = os.path.dirname(self.path) - record_path = self.get_distinfo_file('RECORD') - for path, hash_value, size in self.list_installed_files(): - if not os.path.isabs(path): - path = os.path.join(base, path) - if path == record_path: - continue - if not os.path.exists(path): - mismatches.append((path, 'exists', True, False)) - elif os.path.isfile(path): - actual_size = str(os.path.getsize(path)) - if size and actual_size != size: - mismatches.append((path, 'size', size, actual_size)) - elif hash_value: - if '=' in hash_value: - hasher = hash_value.split('=', 1)[0] - else: - hasher = None - - with open(path, 'rb') as f: - actual_hash = self.get_hash(f.read(), hasher) - if actual_hash != hash_value: - mismatches.append((path, 'hash', hash_value, actual_hash)) - return mismatches - - @cached_property - def shared_locations(self): - """ - A dictionary of shared locations whose keys are in the set 'prefix', - 'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'. - The corresponding value is the absolute path of that category for - this distribution, and takes into account any paths selected by the - user at installation time (e.g. via command-line arguments). In the - case of the 'namespace' key, this would be a list of absolute paths - for the roots of namespace packages in this distribution. - - The first time this property is accessed, the relevant information is - read from the SHARED file in the .dist-info directory. - """ - result = {} - shared_path = os.path.join(self.path, 'SHARED') - if os.path.isfile(shared_path): - with codecs.open(shared_path, 'r', encoding='utf-8') as f: - lines = f.read().splitlines() - for line in lines: - key, value = line.split('=', 1) - if key == 'namespace': - result.setdefault(key, []).append(value) - else: - result[key] = value - return result - - def write_shared_locations(self, paths, dry_run=False): - """ - Write shared location information to the SHARED file in .dist-info. - :param paths: A dictionary as described in the documentation for - :meth:`shared_locations`. - :param dry_run: If True, the action is logged but no file is actually - written. - :return: The path of the file written to. - """ - shared_path = os.path.join(self.path, 'SHARED') - logger.info('creating %s', shared_path) - if dry_run: - return None - lines = [] - for key in ('prefix', 'lib', 'headers', 'scripts', 'data'): - path = paths[key] - if os.path.isdir(paths[key]): - lines.append('%s=%s' % (key, path)) - for ns in paths.get('namespace', ()): - lines.append('namespace=%s' % ns) - - with codecs.open(shared_path, 'w', encoding='utf-8') as f: - f.write('\n'.join(lines)) - return shared_path - - def get_distinfo_resource(self, path): - if path not in DIST_FILES: - raise DistlibException('invalid path for a dist-info file: ' - '%r at %r' % (path, self.path)) - finder = resources.finder_for_path(self.path) - if finder is None: - raise DistlibException('Unable to get a finder for %s' % self.path) - return finder.find(path) - - def get_distinfo_file(self, path): - """ - Returns a path located under the ``.dist-info`` directory. Returns a - string representing the path. - - :parameter path: a ``'/'``-separated path relative to the - ``.dist-info`` directory or an absolute path; - If *path* is an absolute path and doesn't start - with the ``.dist-info`` directory path, - a :class:`DistlibException` is raised - :type path: str - :rtype: str - """ - # Check if it is an absolute path # XXX use relpath, add tests - if path.find(os.sep) >= 0: - # it's an absolute path? - distinfo_dirname, path = path.split(os.sep)[-2:] - if distinfo_dirname != self.path.split(os.sep)[-1]: - raise DistlibException( - 'dist-info file %r does not belong to the %r %s ' - 'distribution' % (path, self.name, self.version)) - - # The file must be relative - if path not in DIST_FILES: - raise DistlibException('invalid path for a dist-info file: ' - '%r at %r' % (path, self.path)) - - return os.path.join(self.path, path) - - def list_distinfo_files(self): - """ - Iterates over the ``RECORD`` entries and returns paths for each line if - the path is pointing to a file located in the ``.dist-info`` directory - or one of its subdirectories. - - :returns: iterator of paths - """ - base = os.path.dirname(self.path) - for path, checksum, size in self._get_records(): - # XXX add separator or use real relpath algo - if not os.path.isabs(path): - path = os.path.join(base, path) - if path.startswith(self.path): - yield path - - def __eq__(self, other): - return (isinstance(other, InstalledDistribution) and - self.path == other.path) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -class EggInfoDistribution(BaseInstalledDistribution): - """Created with the *path* of the ``.egg-info`` directory or file provided - to the constructor. It reads the metadata contained in the file itself, or - if the given path happens to be a directory, the metadata is read from the - file ``PKG-INFO`` under that directory.""" - - requested = True # as we have no way of knowing, assume it was - shared_locations = {} - - def __init__(self, path, env=None): - def set_name_and_version(s, n, v): - s.name = n - s.key = n.lower() # for case-insensitive comparisons - s.version = v - - self.path = path - self.dist_path = env - if env and env._cache_enabled and path in env._cache_egg.path: - metadata = env._cache_egg.path[path].metadata - set_name_and_version(self, metadata.name, metadata.version) - else: - metadata = self._get_metadata(path) - - # Need to be set before caching - set_name_and_version(self, metadata.name, metadata.version) - - if env and env._cache_enabled: - env._cache_egg.add(self) - super(EggInfoDistribution, self).__init__(metadata, path, env) - - def _get_metadata(self, path): - requires = None - - def parse_requires_data(data): - """Create a list of dependencies from a requires.txt file. - - *data*: the contents of a setuptools-produced requires.txt file. - """ - reqs = [] - lines = data.splitlines() - for line in lines: - line = line.strip() - if line.startswith('['): - logger.warning('Unexpected line: quitting requirement scan: %r', - line) - break - r = parse_requirement(line) - if not r: - logger.warning('Not recognised as a requirement: %r', line) - continue - if r.extras: - logger.warning('extra requirements in requires.txt are ' - 'not supported') - if not r.constraints: - reqs.append(r.name) - else: - cons = ', '.join('%s%s' % c for c in r.constraints) - reqs.append('%s (%s)' % (r.name, cons)) - return reqs - - def parse_requires_path(req_path): - """Create a list of dependencies from a requires.txt file. - - *req_path*: the path to a setuptools-produced requires.txt file. - """ - - reqs = [] - try: - with codecs.open(req_path, 'r', 'utf-8') as fp: - reqs = parse_requires_data(fp.read()) - except IOError: - pass - return reqs - - tl_path = tl_data = None - if path.endswith('.egg'): - if os.path.isdir(path): - p = os.path.join(path, 'EGG-INFO') - meta_path = os.path.join(p, 'PKG-INFO') - metadata = Metadata(path=meta_path, scheme='legacy') - req_path = os.path.join(p, 'requires.txt') - tl_path = os.path.join(p, 'top_level.txt') - requires = parse_requires_path(req_path) - else: - # FIXME handle the case where zipfile is not available - zipf = zipimport.zipimporter(path) - fileobj = StringIO( - zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) - metadata = Metadata(fileobj=fileobj, scheme='legacy') - try: - data = zipf.get_data('EGG-INFO/requires.txt') - tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode('utf-8') - requires = parse_requires_data(data.decode('utf-8')) - except IOError: - requires = None - elif path.endswith('.egg-info'): - if os.path.isdir(path): - req_path = os.path.join(path, 'requires.txt') - requires = parse_requires_path(req_path) - path = os.path.join(path, 'PKG-INFO') - tl_path = os.path.join(path, 'top_level.txt') - metadata = Metadata(path=path, scheme='legacy') - else: - raise DistlibException('path must end with .egg-info or .egg, ' - 'got %r' % path) - - if requires: - metadata.add_requirements(requires) - # look for top-level modules in top_level.txt, if present - if tl_data is None: - if tl_path is not None and os.path.exists(tl_path): - with open(tl_path, 'rb') as f: - tl_data = f.read().decode('utf-8') - if not tl_data: - tl_data = [] - else: - tl_data = tl_data.splitlines() - self.modules = tl_data - return metadata - - def __repr__(self): - return '' % ( - self.name, self.version, self.path) - - def __str__(self): - return "%s %s" % (self.name, self.version) - - def check_installed_files(self): - """ - Checks that the hashes and sizes of the files in ``RECORD`` are - matched by the files themselves. Returns a (possibly empty) list of - mismatches. Each entry in the mismatch list will be a tuple consisting - of the path, 'exists', 'size' or 'hash' according to what didn't match - (existence is checked first, then size, then hash), the expected - value and the actual value. - """ - mismatches = [] - record_path = os.path.join(self.path, 'installed-files.txt') - if os.path.exists(record_path): - for path, _, _ in self.list_installed_files(): - if path == record_path: - continue - if not os.path.exists(path): - mismatches.append((path, 'exists', True, False)) - return mismatches - - def list_installed_files(self): - """ - Iterates over the ``installed-files.txt`` entries and returns a tuple - ``(path, hash, size)`` for each line. - - :returns: a list of (path, hash, size) - """ - - def _md5(path): - f = open(path, 'rb') - try: - content = f.read() - finally: - f.close() - return hashlib.md5(content).hexdigest() - - def _size(path): - return os.stat(path).st_size - - record_path = os.path.join(self.path, 'installed-files.txt') - result = [] - if os.path.exists(record_path): - with codecs.open(record_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - p = os.path.normpath(os.path.join(self.path, line)) - # "./" is present as a marker between installed files - # and installation metadata files - if not os.path.exists(p): - logger.warning('Non-existent file: %s', p) - if p.endswith(('.pyc', '.pyo')): - continue - #otherwise fall through and fail - if not os.path.isdir(p): - result.append((p, _md5(p), _size(p))) - result.append((record_path, None, None)) - return result - - def list_distinfo_files(self, absolute=False): - """ - Iterates over the ``installed-files.txt`` entries and returns paths for - each line if the path is pointing to a file located in the - ``.egg-info`` directory or one of its subdirectories. - - :parameter absolute: If *absolute* is ``True``, each returned path is - transformed into a local absolute path. Otherwise the - raw value from ``installed-files.txt`` is returned. - :type absolute: boolean - :returns: iterator of paths - """ - record_path = os.path.join(self.path, 'installed-files.txt') - if os.path.exists(record_path): - skip = True - with codecs.open(record_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if line == './': - skip = False - continue - if not skip: - p = os.path.normpath(os.path.join(self.path, line)) - if p.startswith(self.path): - if absolute: - yield p - else: - yield line - - def __eq__(self, other): - return (isinstance(other, EggInfoDistribution) and - self.path == other.path) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - -new_dist_class = InstalledDistribution -old_dist_class = EggInfoDistribution - - -class DependencyGraph(object): - """ - Represents a dependency graph between distributions. - - The dependency relationships are stored in an ``adjacency_list`` that maps - distributions to a list of ``(other, label)`` tuples where ``other`` - is a distribution and the edge is labeled with ``label`` (i.e. the version - specifier, if such was provided). Also, for more efficient traversal, for - every distribution ``x``, a list of predecessors is kept in - ``reverse_list[x]``. An edge from distribution ``a`` to - distribution ``b`` means that ``a`` depends on ``b``. If any missing - dependencies are found, they are stored in ``missing``, which is a - dictionary that maps distributions to a list of requirements that were not - provided by any other distributions. - """ - - def __init__(self): - self.adjacency_list = {} - self.reverse_list = {} - self.missing = {} - - def add_distribution(self, distribution): - """Add the *distribution* to the graph. - - :type distribution: :class:`distutils2.database.InstalledDistribution` - or :class:`distutils2.database.EggInfoDistribution` - """ - self.adjacency_list[distribution] = [] - self.reverse_list[distribution] = [] - #self.missing[distribution] = [] - - def add_edge(self, x, y, label=None): - """Add an edge from distribution *x* to distribution *y* with the given - *label*. - - :type x: :class:`distutils2.database.InstalledDistribution` or - :class:`distutils2.database.EggInfoDistribution` - :type y: :class:`distutils2.database.InstalledDistribution` or - :class:`distutils2.database.EggInfoDistribution` - :type label: ``str`` or ``None`` - """ - self.adjacency_list[x].append((y, label)) - # multiple edges are allowed, so be careful - if x not in self.reverse_list[y]: - self.reverse_list[y].append(x) - - def add_missing(self, distribution, requirement): - """ - Add a missing *requirement* for the given *distribution*. - - :type distribution: :class:`distutils2.database.InstalledDistribution` - or :class:`distutils2.database.EggInfoDistribution` - :type requirement: ``str`` - """ - logger.debug('%s missing %r', distribution, requirement) - self.missing.setdefault(distribution, []).append(requirement) - - def _repr_dist(self, dist): - return '%s %s' % (dist.name, dist.version) - - def repr_node(self, dist, level=1): - """Prints only a subgraph""" - output = [self._repr_dist(dist)] - for other, label in self.adjacency_list[dist]: - dist = self._repr_dist(other) - if label is not None: - dist = '%s [%s]' % (dist, label) - output.append(' ' * level + str(dist)) - suboutput = self.repr_node(other, level + 1) - subs = suboutput.split('\n') - output.extend(subs[1:]) - return '\n'.join(output) - - def to_dot(self, f, skip_disconnected=True): - """Writes a DOT output for the graph to the provided file *f*. - - If *skip_disconnected* is set to ``True``, then all distributions - that are not dependent on any other distribution are skipped. - - :type f: has to support ``file``-like operations - :type skip_disconnected: ``bool`` - """ - disconnected = [] - - f.write("digraph dependencies {\n") - for dist, adjs in self.adjacency_list.items(): - if len(adjs) == 0 and not skip_disconnected: - disconnected.append(dist) - for other, label in adjs: - if not label is None: - f.write('"%s" -> "%s" [label="%s"]\n' % - (dist.name, other.name, label)) - else: - f.write('"%s" -> "%s"\n' % (dist.name, other.name)) - if not skip_disconnected and len(disconnected) > 0: - f.write('subgraph disconnected {\n') - f.write('label = "Disconnected"\n') - f.write('bgcolor = red\n') - - for dist in disconnected: - f.write('"%s"' % dist.name) - f.write('\n') - f.write('}\n') - f.write('}\n') - - def topological_sort(self): - """ - Perform a topological sort of the graph. - :return: A tuple, the first element of which is a topologically sorted - list of distributions, and the second element of which is a - list of distributions that cannot be sorted because they have - circular dependencies and so form a cycle. - """ - result = [] - # Make a shallow copy of the adjacency list - alist = {} - for k, v in self.adjacency_list.items(): - alist[k] = v[:] - while True: - # See what we can remove in this run - to_remove = [] - for k, v in list(alist.items())[:]: - if not v: - to_remove.append(k) - del alist[k] - if not to_remove: - # What's left in alist (if anything) is a cycle. - break - # Remove from the adjacency list of others - for k, v in alist.items(): - alist[k] = [(d, r) for d, r in v if d not in to_remove] - logger.debug('Moving to result: %s', - ['%s (%s)' % (d.name, d.version) for d in to_remove]) - result.extend(to_remove) - return result, list(alist.keys()) - - def __repr__(self): - """Representation of the graph""" - output = [] - for dist, adjs in self.adjacency_list.items(): - output.append(self.repr_node(dist)) - return '\n'.join(output) - - -def make_graph(dists, scheme='default'): - """Makes a dependency graph from the given distributions. - - :parameter dists: a list of distributions - :type dists: list of :class:`distutils2.database.InstalledDistribution` and - :class:`distutils2.database.EggInfoDistribution` instances - :rtype: a :class:`DependencyGraph` instance - """ - scheme = get_scheme(scheme) - graph = DependencyGraph() - provided = {} # maps names to lists of (version, dist) tuples - - # first, build the graph and find out what's provided - for dist in dists: - graph.add_distribution(dist) - - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Add to provided: %s, %s, %s', name, version, dist) - provided.setdefault(name, []).append((version, dist)) - - # now make the edges - for dist in dists: - requires = (dist.run_requires | dist.meta_requires | - dist.build_requires | dist.dev_requires) - for req in requires: - try: - matcher = scheme.matcher(req) - except UnsupportedVersionError: - # XXX compat-mode if cannot read the version - logger.warning('could not read version %r - using name only', - req) - name = req.split()[0] - matcher = scheme.matcher(name) - - name = matcher.key # case-insensitive - - matched = False - if name in provided: - for version, provider in provided[name]: - try: - match = matcher.match(version) - except UnsupportedVersionError: - match = False - - if match: - graph.add_edge(dist, provider, req) - matched = True - break - if not matched: - graph.add_missing(dist, req) - return graph - - -def get_dependent_dists(dists, dist): - """Recursively generate a list of distributions from *dists* that are - dependent on *dist*. - - :param dists: a list of distributions - :param dist: a distribution, member of *dists* for which we are interested - """ - if dist not in dists: - raise DistlibException('given distribution %r is not a member ' - 'of the list' % dist.name) - graph = make_graph(dists) - - dep = [dist] # dependent distributions - todo = graph.reverse_list[dist] # list of nodes we should inspect - - while todo: - d = todo.pop() - dep.append(d) - for succ in graph.reverse_list[d]: - if succ not in dep: - todo.append(succ) - - dep.pop(0) # remove dist from dep, was there to prevent infinite loops - return dep - - -def get_required_dists(dists, dist): - """Recursively generate a list of distributions from *dists* that are - required by *dist*. - - :param dists: a list of distributions - :param dist: a distribution, member of *dists* for which we are interested - """ - if dist not in dists: - raise DistlibException('given distribution %r is not a member ' - 'of the list' % dist.name) - graph = make_graph(dists) - - req = [] # required distributions - todo = graph.adjacency_list[dist] # list of nodes we should inspect - - while todo: - d = todo.pop()[0] - req.append(d) - for pred in graph.adjacency_list[d]: - if pred not in req: - todo.append(pred) - - return req - - -def make_dist(name, version, **kwargs): - """ - A convenience method for making a dist given just a name and version. - """ - summary = kwargs.pop('summary', 'Placeholder for summary') - md = Metadata(**kwargs) - md.name = name - md.version = version - md.summary = summary or 'Placeholder for summary' - return Distribution(md) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/index.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/index.py deleted file mode 100644 index b1fbbf8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/index.py +++ /dev/null @@ -1,509 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import hashlib -import logging -import os -import shutil -import subprocess -import tempfile -try: - from threading import Thread -except ImportError: - from dummy_threading import Thread - -from . import DistlibException -from .compat import (HTTPBasicAuthHandler, Request, HTTPPasswordMgr, - urlparse, build_opener, string_types) -from .util import zip_dir, ServerProxy - -logger = logging.getLogger(__name__) - -DEFAULT_INDEX = 'https://pypi.org/pypi' -DEFAULT_REALM = 'pypi' - -class PackageIndex(object): - """ - This class represents a package index compatible with PyPI, the Python - Package Index. - """ - - boundary = b'----------ThIs_Is_tHe_distlib_index_bouNdaRY_$' - - def __init__(self, url=None): - """ - Initialise an instance. - - :param url: The URL of the index. If not specified, the URL for PyPI is - used. - """ - self.url = url or DEFAULT_INDEX - self.read_configuration() - scheme, netloc, path, params, query, frag = urlparse(self.url) - if params or query or frag or scheme not in ('http', 'https'): - raise DistlibException('invalid repository: %s' % self.url) - self.password_handler = None - self.ssl_verifier = None - self.gpg = None - self.gpg_home = None - with open(os.devnull, 'w') as sink: - # Use gpg by default rather than gpg2, as gpg2 insists on - # prompting for passwords - for s in ('gpg', 'gpg2'): - try: - rc = subprocess.check_call([s, '--version'], stdout=sink, - stderr=sink) - if rc == 0: - self.gpg = s - break - except OSError: - pass - - def _get_pypirc_command(self): - """ - Get the distutils command for interacting with PyPI configurations. - :return: the command. - """ - from .util import _get_pypirc_command as cmd - return cmd() - - def read_configuration(self): - """ - Read the PyPI access configuration as supported by distutils. This populates - ``username``, ``password``, ``realm`` and ``url`` attributes from the - configuration. - """ - from .util import _load_pypirc - cfg = _load_pypirc(self) - self.username = cfg.get('username') - self.password = cfg.get('password') - self.realm = cfg.get('realm', 'pypi') - self.url = cfg.get('repository', self.url) - - def save_configuration(self): - """ - Save the PyPI access configuration. You must have set ``username`` and - ``password`` attributes before calling this method. - """ - self.check_credentials() - from .util import _store_pypirc - _store_pypirc(self) - - def check_credentials(self): - """ - Check that ``username`` and ``password`` have been set, and raise an - exception if not. - """ - if self.username is None or self.password is None: - raise DistlibException('username and password must be set') - pm = HTTPPasswordMgr() - _, netloc, _, _, _, _ = urlparse(self.url) - pm.add_password(self.realm, netloc, self.username, self.password) - self.password_handler = HTTPBasicAuthHandler(pm) - - def register(self, metadata): - """ - Register a distribution on PyPI, using the provided metadata. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the distribution to be - registered. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - metadata.validate() - d = metadata.todict() - d[':action'] = 'verify' - request = self.encode_request(d.items(), []) - response = self.send_request(request) - d[':action'] = 'submit' - request = self.encode_request(d.items(), []) - return self.send_request(request) - - def _reader(self, name, stream, outbuf): - """ - Thread runner for reading lines of from a subprocess into a buffer. - - :param name: The logical name of the stream (used for logging only). - :param stream: The stream to read from. This will typically a pipe - connected to the output stream of a subprocess. - :param outbuf: The list to append the read lines to. - """ - while True: - s = stream.readline() - if not s: - break - s = s.decode('utf-8').rstrip() - outbuf.append(s) - logger.debug('%s: %s' % (name, s)) - stream.close() - - def get_sign_command(self, filename, signer, sign_password, - keystore=None): - """ - Return a suitable command for signing a file. - - :param filename: The pathname to the file to be signed. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :param keystore: The path to a directory which contains the keys - used in verification. If not specified, the - instance's ``gpg_home`` attribute is used instead. - :return: The signing command as a list suitable to be - passed to :class:`subprocess.Popen`. - """ - cmd = [self.gpg, '--status-fd', '2', '--no-tty'] - if keystore is None: - keystore = self.gpg_home - if keystore: - cmd.extend(['--homedir', keystore]) - if sign_password is not None: - cmd.extend(['--batch', '--passphrase-fd', '0']) - td = tempfile.mkdtemp() - sf = os.path.join(td, os.path.basename(filename) + '.asc') - cmd.extend(['--detach-sign', '--armor', '--local-user', - signer, '--output', sf, filename]) - logger.debug('invoking: %s', ' '.join(cmd)) - return cmd, sf - - def run_command(self, cmd, input_data=None): - """ - Run a command in a child process , passing it any input data specified. - - :param cmd: The command to run. - :param input_data: If specified, this must be a byte string containing - data to be sent to the child process. - :return: A tuple consisting of the subprocess' exit code, a list of - lines read from the subprocess' ``stdout``, and a list of - lines read from the subprocess' ``stderr``. - """ - kwargs = { - 'stdout': subprocess.PIPE, - 'stderr': subprocess.PIPE, - } - if input_data is not None: - kwargs['stdin'] = subprocess.PIPE - stdout = [] - stderr = [] - p = subprocess.Popen(cmd, **kwargs) - # We don't use communicate() here because we may need to - # get clever with interacting with the command - t1 = Thread(target=self._reader, args=('stdout', p.stdout, stdout)) - t1.start() - t2 = Thread(target=self._reader, args=('stderr', p.stderr, stderr)) - t2.start() - if input_data is not None: - p.stdin.write(input_data) - p.stdin.close() - - p.wait() - t1.join() - t2.join() - return p.returncode, stdout, stderr - - def sign_file(self, filename, signer, sign_password, keystore=None): - """ - Sign a file. - - :param filename: The pathname to the file to be signed. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :param keystore: The path to a directory which contains the keys - used in signing. If not specified, the instance's - ``gpg_home`` attribute is used instead. - :return: The absolute pathname of the file where the signature is - stored. - """ - cmd, sig_file = self.get_sign_command(filename, signer, sign_password, - keystore) - rc, stdout, stderr = self.run_command(cmd, - sign_password.encode('utf-8')) - if rc != 0: - raise DistlibException('sign command failed with error ' - 'code %s' % rc) - return sig_file - - def upload_file(self, metadata, filename, signer=None, sign_password=None, - filetype='sdist', pyversion='source', keystore=None): - """ - Upload a release file to the index. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the file to be uploaded. - :param filename: The pathname of the file to be uploaded. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :param filetype: The type of the file being uploaded. This is the - distutils command which produced that file, e.g. - ``sdist`` or ``bdist_wheel``. - :param pyversion: The version of Python which the release relates - to. For code compatible with any Python, this would - be ``source``, otherwise it would be e.g. ``3.2``. - :param keystore: The path to a directory which contains the keys - used in signing. If not specified, the instance's - ``gpg_home`` attribute is used instead. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - if not os.path.exists(filename): - raise DistlibException('not found: %s' % filename) - metadata.validate() - d = metadata.todict() - sig_file = None - if signer: - if not self.gpg: - logger.warning('no signing program available - not signed') - else: - sig_file = self.sign_file(filename, signer, sign_password, - keystore) - with open(filename, 'rb') as f: - file_data = f.read() - md5_digest = hashlib.md5(file_data).hexdigest() - sha256_digest = hashlib.sha256(file_data).hexdigest() - d.update({ - ':action': 'file_upload', - 'protocol_version': '1', - 'filetype': filetype, - 'pyversion': pyversion, - 'md5_digest': md5_digest, - 'sha256_digest': sha256_digest, - }) - files = [('content', os.path.basename(filename), file_data)] - if sig_file: - with open(sig_file, 'rb') as f: - sig_data = f.read() - files.append(('gpg_signature', os.path.basename(sig_file), - sig_data)) - shutil.rmtree(os.path.dirname(sig_file)) - request = self.encode_request(d.items(), files) - return self.send_request(request) - - def upload_documentation(self, metadata, doc_dir): - """ - Upload documentation to the index. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the documentation to be - uploaded. - :param doc_dir: The pathname of the directory which contains the - documentation. This should be the directory that - contains the ``index.html`` for the documentation. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - if not os.path.isdir(doc_dir): - raise DistlibException('not a directory: %r' % doc_dir) - fn = os.path.join(doc_dir, 'index.html') - if not os.path.exists(fn): - raise DistlibException('not found: %r' % fn) - metadata.validate() - name, version = metadata.name, metadata.version - zip_data = zip_dir(doc_dir).getvalue() - fields = [(':action', 'doc_upload'), - ('name', name), ('version', version)] - files = [('content', name, zip_data)] - request = self.encode_request(fields, files) - return self.send_request(request) - - def get_verify_command(self, signature_filename, data_filename, - keystore=None): - """ - Return a suitable command for verifying a file. - - :param signature_filename: The pathname to the file containing the - signature. - :param data_filename: The pathname to the file containing the - signed data. - :param keystore: The path to a directory which contains the keys - used in verification. If not specified, the - instance's ``gpg_home`` attribute is used instead. - :return: The verifying command as a list suitable to be - passed to :class:`subprocess.Popen`. - """ - cmd = [self.gpg, '--status-fd', '2', '--no-tty'] - if keystore is None: - keystore = self.gpg_home - if keystore: - cmd.extend(['--homedir', keystore]) - cmd.extend(['--verify', signature_filename, data_filename]) - logger.debug('invoking: %s', ' '.join(cmd)) - return cmd - - def verify_signature(self, signature_filename, data_filename, - keystore=None): - """ - Verify a signature for a file. - - :param signature_filename: The pathname to the file containing the - signature. - :param data_filename: The pathname to the file containing the - signed data. - :param keystore: The path to a directory which contains the keys - used in verification. If not specified, the - instance's ``gpg_home`` attribute is used instead. - :return: True if the signature was verified, else False. - """ - if not self.gpg: - raise DistlibException('verification unavailable because gpg ' - 'unavailable') - cmd = self.get_verify_command(signature_filename, data_filename, - keystore) - rc, stdout, stderr = self.run_command(cmd) - if rc not in (0, 1): - raise DistlibException('verify command failed with error ' - 'code %s' % rc) - return rc == 0 - - def download_file(self, url, destfile, digest=None, reporthook=None): - """ - This is a convenience method for downloading a file from an URL. - Normally, this will be a file from the index, though currently - no check is made for this (i.e. a file can be downloaded from - anywhere). - - The method is just like the :func:`urlretrieve` function in the - standard library, except that it allows digest computation to be - done during download and checking that the downloaded data - matched any expected value. - - :param url: The URL of the file to be downloaded (assumed to be - available via an HTTP GET request). - :param destfile: The pathname where the downloaded file is to be - saved. - :param digest: If specified, this must be a (hasher, value) - tuple, where hasher is the algorithm used (e.g. - ``'md5'``) and ``value`` is the expected value. - :param reporthook: The same as for :func:`urlretrieve` in the - standard library. - """ - if digest is None: - digester = None - logger.debug('No digest specified') - else: - if isinstance(digest, (list, tuple)): - hasher, digest = digest - else: - hasher = 'md5' - digester = getattr(hashlib, hasher)() - logger.debug('Digest specified: %s' % digest) - # The following code is equivalent to urlretrieve. - # We need to do it this way so that we can compute the - # digest of the file as we go. - with open(destfile, 'wb') as dfp: - # addinfourl is not a context manager on 2.x - # so we have to use try/finally - sfp = self.send_request(Request(url)) - try: - headers = sfp.info() - blocksize = 8192 - size = -1 - read = 0 - blocknum = 0 - if "content-length" in headers: - size = int(headers["Content-Length"]) - if reporthook: - reporthook(blocknum, blocksize, size) - while True: - block = sfp.read(blocksize) - if not block: - break - read += len(block) - dfp.write(block) - if digester: - digester.update(block) - blocknum += 1 - if reporthook: - reporthook(blocknum, blocksize, size) - finally: - sfp.close() - - # check that we got the whole file, if we can - if size >= 0 and read < size: - raise DistlibException( - 'retrieval incomplete: got only %d out of %d bytes' - % (read, size)) - # if we have a digest, it must match. - if digester: - actual = digester.hexdigest() - if digest != actual: - raise DistlibException('%s digest mismatch for %s: expected ' - '%s, got %s' % (hasher, destfile, - digest, actual)) - logger.debug('Digest verified: %s', digest) - - def send_request(self, req): - """ - Send a standard library :class:`Request` to PyPI and return its - response. - - :param req: The request to send. - :return: The HTTP response from PyPI (a standard library HTTPResponse). - """ - handlers = [] - if self.password_handler: - handlers.append(self.password_handler) - if self.ssl_verifier: - handlers.append(self.ssl_verifier) - opener = build_opener(*handlers) - return opener.open(req) - - def encode_request(self, fields, files): - """ - Encode fields and files for posting to an HTTP server. - - :param fields: The fields to send as a list of (fieldname, value) - tuples. - :param files: The files to send as a list of (fieldname, filename, - file_bytes) tuple. - """ - # Adapted from packaging, which in turn was adapted from - # http://code.activestate.com/recipes/146306 - - parts = [] - boundary = self.boundary - for k, values in fields: - if not isinstance(values, (list, tuple)): - values = [values] - - for v in values: - parts.extend(( - b'--' + boundary, - ('Content-Disposition: form-data; name="%s"' % - k).encode('utf-8'), - b'', - v.encode('utf-8'))) - for key, filename, value in files: - parts.extend(( - b'--' + boundary, - ('Content-Disposition: form-data; name="%s"; filename="%s"' % - (key, filename)).encode('utf-8'), - b'', - value)) - - parts.extend((b'--' + boundary + b'--', b'')) - - body = b'\r\n'.join(parts) - ct = b'multipart/form-data; boundary=' + boundary - headers = { - 'Content-type': ct, - 'Content-length': str(len(body)) - } - return Request(self.url, body, headers) - - def search(self, terms, operator=None): - if isinstance(terms, string_types): - terms = {'name': terms} - rpc_proxy = ServerProxy(self.url, timeout=3.0) - try: - return rpc_proxy.search(terms, operator or 'and') - finally: - rpc_proxy('close')() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/locators.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/locators.py deleted file mode 100644 index 0c7d639..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/locators.py +++ /dev/null @@ -1,1300 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2015 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# - -import gzip -from io import BytesIO -import json -import logging -import os -import posixpath -import re -try: - import threading -except ImportError: # pragma: no cover - import dummy_threading as threading -import zlib - -from . import DistlibException -from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, - queue, quote, unescape, build_opener, - HTTPRedirectHandler as BaseRedirectHandler, text_type, - Request, HTTPError, URLError) -from .database import Distribution, DistributionPath, make_dist -from .metadata import Metadata, MetadataInvalidError -from .util import (cached_property, ensure_slash, split_filename, get_project_data, - parse_requirement, parse_name_and_version, ServerProxy, - normalize_name) -from .version import get_scheme, UnsupportedVersionError -from .wheel import Wheel, is_compatible - -logger = logging.getLogger(__name__) - -HASHER_HASH = re.compile(r'^(\w+)=([a-f0-9]+)') -CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I) -HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml') -DEFAULT_INDEX = 'https://pypi.org/pypi' - -def get_all_distribution_names(url=None): - """ - Return all distribution names known by an index. - :param url: The URL of the index. - :return: A list of all known distribution names. - """ - if url is None: - url = DEFAULT_INDEX - client = ServerProxy(url, timeout=3.0) - try: - return client.list_packages() - finally: - client('close')() - -class RedirectHandler(BaseRedirectHandler): - """ - A class to work around a bug in some Python 3.2.x releases. - """ - # There's a bug in the base version for some 3.2.x - # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header - # returns e.g. /abc, it bails because it says the scheme '' - # is bogus, when actually it should use the request's - # URL for the scheme. See Python issue #13696. - def http_error_302(self, req, fp, code, msg, headers): - # Some servers (incorrectly) return multiple Location headers - # (so probably same goes for URI). Use first header. - newurl = None - for key in ('location', 'uri'): - if key in headers: - newurl = headers[key] - break - if newurl is None: # pragma: no cover - return - urlparts = urlparse(newurl) - if urlparts.scheme == '': - newurl = urljoin(req.get_full_url(), newurl) - if hasattr(headers, 'replace_header'): - headers.replace_header(key, newurl) - else: - headers[key] = newurl - return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, - headers) - - http_error_301 = http_error_303 = http_error_307 = http_error_302 - -class Locator(object): - """ - A base class for locators - things that locate distributions. - """ - source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz') - binary_extensions = ('.egg', '.exe', '.whl') - excluded_extensions = ('.pdf',) - - # A list of tags indicating which wheels you want to match. The default - # value of None matches against the tags compatible with the running - # Python. If you want to match other values, set wheel_tags on a locator - # instance to a list of tuples (pyver, abi, arch) which you want to match. - wheel_tags = None - - downloadable_extensions = source_extensions + ('.whl',) - - def __init__(self, scheme='default'): - """ - Initialise an instance. - :param scheme: Because locators look for most recent versions, they - need to know the version scheme to use. This specifies - the current PEP-recommended scheme - use ``'legacy'`` - if you need to support existing distributions on PyPI. - """ - self._cache = {} - self.scheme = scheme - # Because of bugs in some of the handlers on some of the platforms, - # we use our own opener rather than just using urlopen. - self.opener = build_opener(RedirectHandler()) - # If get_project() is called from locate(), the matcher instance - # is set from the requirement passed to locate(). See issue #18 for - # why this can be useful to know. - self.matcher = None - self.errors = queue.Queue() - - def get_errors(self): - """ - Return any errors which have occurred. - """ - result = [] - while not self.errors.empty(): # pragma: no cover - try: - e = self.errors.get(False) - result.append(e) - except self.errors.Empty: - continue - self.errors.task_done() - return result - - def clear_errors(self): - """ - Clear any errors which may have been logged. - """ - # Just get the errors and throw them away - self.get_errors() - - def clear_cache(self): - self._cache.clear() - - def _get_scheme(self): - return self._scheme - - def _set_scheme(self, value): - self._scheme = value - - scheme = property(_get_scheme, _set_scheme) - - def _get_project(self, name): - """ - For a given project, get a dictionary mapping available versions to Distribution - instances. - - This should be implemented in subclasses. - - If called from a locate() request, self.matcher will be set to a - matcher for the requirement to satisfy, otherwise it will be None. - """ - raise NotImplementedError('Please implement in the subclass') - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Please implement in the subclass') - - def get_project(self, name): - """ - For a given project, get a dictionary mapping available versions to Distribution - instances. - - This calls _get_project to do all the work, and just implements a caching layer on top. - """ - if self._cache is None: # pragma: no cover - result = self._get_project(name) - elif name in self._cache: - result = self._cache[name] - else: - self.clear_errors() - result = self._get_project(name) - self._cache[name] = result - return result - - def score_url(self, url): - """ - Give an url a score which can be used to choose preferred URLs - for a given project release. - """ - t = urlparse(url) - basename = posixpath.basename(t.path) - compatible = True - is_wheel = basename.endswith('.whl') - is_downloadable = basename.endswith(self.downloadable_extensions) - if is_wheel: - compatible = is_compatible(Wheel(basename), self.wheel_tags) - return (t.scheme == 'https', 'pypi.org' in t.netloc, - is_downloadable, is_wheel, compatible, basename) - - def prefer_url(self, url1, url2): - """ - Choose one of two URLs where both are candidates for distribution - archives for the same version of a distribution (for example, - .tar.gz vs. zip). - - The current implementation favours https:// URLs over http://, archives - from PyPI over those from other locations, wheel compatibility (if a - wheel) and then the archive name. - """ - result = url2 - if url1: - s1 = self.score_url(url1) - s2 = self.score_url(url2) - if s1 > s2: - result = url1 - if result != url2: - logger.debug('Not replacing %r with %r', url1, url2) - else: - logger.debug('Replacing %r with %r', url1, url2) - return result - - def split_filename(self, filename, project_name): - """ - Attempt to split a filename in project name, version and Python version. - """ - return split_filename(filename, project_name) - - def convert_url_to_download_info(self, url, project_name): - """ - See if a URL is a candidate for a download URL for a project (the URL - has typically been scraped from an HTML page). - - If it is, a dictionary is returned with keys "name", "version", - "filename" and "url"; otherwise, None is returned. - """ - def same_project(name1, name2): - return normalize_name(name1) == normalize_name(name2) - - result = None - scheme, netloc, path, params, query, frag = urlparse(url) - if frag.lower().startswith('egg='): # pragma: no cover - logger.debug('%s: version hint in fragment: %r', - project_name, frag) - m = HASHER_HASH.match(frag) - if m: - algo, digest = m.groups() - else: - algo, digest = None, None - origpath = path - if path and path[-1] == '/': # pragma: no cover - path = path[:-1] - if path.endswith('.whl'): - try: - wheel = Wheel(path) - if not is_compatible(wheel, self.wheel_tags): - logger.debug('Wheel not compatible: %s', path) - else: - if project_name is None: - include = True - else: - include = same_project(wheel.name, project_name) - if include: - result = { - 'name': wheel.name, - 'version': wheel.version, - 'filename': wheel.filename, - 'url': urlunparse((scheme, netloc, origpath, - params, query, '')), - 'python-version': ', '.join( - ['.'.join(list(v[2:])) for v in wheel.pyver]), - } - except Exception as e: # pragma: no cover - logger.warning('invalid path for wheel: %s', path) - elif not path.endswith(self.downloadable_extensions): # pragma: no cover - logger.debug('Not downloadable: %s', path) - else: # downloadable extension - path = filename = posixpath.basename(path) - for ext in self.downloadable_extensions: - if path.endswith(ext): - path = path[:-len(ext)] - t = self.split_filename(path, project_name) - if not t: # pragma: no cover - logger.debug('No match for project/version: %s', path) - else: - name, version, pyver = t - if not project_name or same_project(project_name, name): - result = { - 'name': name, - 'version': version, - 'filename': filename, - 'url': urlunparse((scheme, netloc, origpath, - params, query, '')), - #'packagetype': 'sdist', - } - if pyver: # pragma: no cover - result['python-version'] = pyver - break - if result and algo: - result['%s_digest' % algo] = digest - return result - - def _get_digest(self, info): - """ - Get a digest from a dictionary by looking at a "digests" dictionary - or keys of the form 'algo_digest'. - - Returns a 2-tuple (algo, digest) if found, else None. Currently - looks only for SHA256, then MD5. - """ - result = None - if 'digests' in info: - digests = info['digests'] - for algo in ('sha256', 'md5'): - if algo in digests: - result = (algo, digests[algo]) - break - if not result: - for algo in ('sha256', 'md5'): - key = '%s_digest' % algo - if key in info: - result = (algo, info[key]) - break - return result - - def _update_version_data(self, result, info): - """ - Update a result dictionary (the final result from _get_project) with a - dictionary for a specific version, which typically holds information - gleaned from a filename or URL for an archive for the distribution. - """ - name = info.pop('name') - version = info.pop('version') - if version in result: - dist = result[version] - md = dist.metadata - else: - dist = make_dist(name, version, scheme=self.scheme) - md = dist.metadata - dist.digest = digest = self._get_digest(info) - url = info['url'] - result['digests'][url] = digest - if md.source_url != info['url']: - md.source_url = self.prefer_url(md.source_url, url) - result['urls'].setdefault(version, set()).add(url) - dist.locator = self - result[version] = dist - - def locate(self, requirement, prereleases=False): - """ - Find the most recent distribution which matches the given - requirement. - - :param requirement: A requirement of the form 'foo (1.0)' or perhaps - 'foo (>= 1.0, < 2.0, != 1.3)' - :param prereleases: If ``True``, allow pre-release versions - to be located. Otherwise, pre-release versions - are not returned. - :return: A :class:`Distribution` instance, or ``None`` if no such - distribution could be located. - """ - result = None - r = parse_requirement(requirement) - if r is None: # pragma: no cover - raise DistlibException('Not a valid requirement: %r' % requirement) - scheme = get_scheme(self.scheme) - self.matcher = matcher = scheme.matcher(r.requirement) - logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__) - versions = self.get_project(r.name) - if len(versions) > 2: # urls and digests keys are present - # sometimes, versions are invalid - slist = [] - vcls = matcher.version_class - for k in versions: - if k in ('urls', 'digests'): - continue - try: - if not matcher.match(k): - pass # logger.debug('%s did not match %r', matcher, k) - else: - if prereleases or not vcls(k).is_prerelease: - slist.append(k) - # else: - # logger.debug('skipping pre-release ' - # 'version %s of %s', k, matcher.name) - except Exception: # pragma: no cover - logger.warning('error matching %s with %r', matcher, k) - pass # slist.append(k) - if len(slist) > 1: - slist = sorted(slist, key=scheme.key) - if slist: - logger.debug('sorted list: %s', slist) - version = slist[-1] - result = versions[version] - if result: - if r.extras: - result.extras = r.extras - result.download_urls = versions.get('urls', {}).get(version, set()) - d = {} - sd = versions.get('digests', {}) - for url in result.download_urls: - if url in sd: # pragma: no cover - d[url] = sd[url] - result.digests = d - self.matcher = None - return result - - -class PyPIRPCLocator(Locator): - """ - This locator uses XML-RPC to locate distributions. It therefore - cannot be used with simple mirrors (that only mirror file content). - """ - def __init__(self, url, **kwargs): - """ - Initialise an instance. - - :param url: The URL to use for XML-RPC. - :param kwargs: Passed to the superclass constructor. - """ - super(PyPIRPCLocator, self).__init__(**kwargs) - self.base_url = url - self.client = ServerProxy(url, timeout=3.0) - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - return set(self.client.list_packages()) - - def _get_project(self, name): - result = {'urls': {}, 'digests': {}} - versions = self.client.package_releases(name, True) - for v in versions: - urls = self.client.release_urls(name, v) - data = self.client.release_data(name, v) - metadata = Metadata(scheme=self.scheme) - metadata.name = data['name'] - metadata.version = data['version'] - metadata.license = data.get('license') - metadata.keywords = data.get('keywords', []) - metadata.summary = data.get('summary') - dist = Distribution(metadata) - if urls: - info = urls[0] - metadata.source_url = info['url'] - dist.digest = self._get_digest(info) - dist.locator = self - result[v] = dist - for info in urls: - url = info['url'] - digest = self._get_digest(info) - result['urls'].setdefault(v, set()).add(url) - result['digests'][url] = digest - return result - -class PyPIJSONLocator(Locator): - """ - This locator uses PyPI's JSON interface. It's very limited in functionality - and probably not worth using. - """ - def __init__(self, url, **kwargs): - super(PyPIJSONLocator, self).__init__(**kwargs) - self.base_url = ensure_slash(url) - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Not available from this locator') - - def _get_project(self, name): - result = {'urls': {}, 'digests': {}} - url = urljoin(self.base_url, '%s/json' % quote(name)) - try: - resp = self.opener.open(url) - data = resp.read().decode() # for now - d = json.loads(data) - md = Metadata(scheme=self.scheme) - data = d['info'] - md.name = data['name'] - md.version = data['version'] - md.license = data.get('license') - md.keywords = data.get('keywords', []) - md.summary = data.get('summary') - dist = Distribution(md) - dist.locator = self - urls = d['urls'] - result[md.version] = dist - for info in d['urls']: - url = info['url'] - dist.download_urls.add(url) - dist.digests[url] = self._get_digest(info) - result['urls'].setdefault(md.version, set()).add(url) - result['digests'][url] = self._get_digest(info) - # Now get other releases - for version, infos in d['releases'].items(): - if version == md.version: - continue # already done - omd = Metadata(scheme=self.scheme) - omd.name = md.name - omd.version = version - odist = Distribution(omd) - odist.locator = self - result[version] = odist - for info in infos: - url = info['url'] - odist.download_urls.add(url) - odist.digests[url] = self._get_digest(info) - result['urls'].setdefault(version, set()).add(url) - result['digests'][url] = self._get_digest(info) -# for info in urls: -# md.source_url = info['url'] -# dist.digest = self._get_digest(info) -# dist.locator = self -# for info in urls: -# url = info['url'] -# result['urls'].setdefault(md.version, set()).add(url) -# result['digests'][url] = self._get_digest(info) - except Exception as e: - self.errors.put(text_type(e)) - logger.exception('JSON fetch failed: %s', e) - return result - - -class Page(object): - """ - This class represents a scraped HTML page. - """ - # The following slightly hairy-looking regex just looks for the contents of - # an anchor link, which has an attribute "href" either immediately preceded - # or immediately followed by a "rel" attribute. The attribute values can be - # declared with double quotes, single quotes or no quotes - which leads to - # the length of the expression. - _href = re.compile(""" -(rel\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*))\\s+)? -href\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*)) -(\\s+rel\\s*=\\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\\s\n]*)))? -""", re.I | re.S | re.X) - _base = re.compile(r"""]+)""", re.I | re.S) - - def __init__(self, data, url): - """ - Initialise an instance with the Unicode page contents and the URL they - came from. - """ - self.data = data - self.base_url = self.url = url - m = self._base.search(self.data) - if m: - self.base_url = m.group(1) - - _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) - - @cached_property - def links(self): - """ - Return the URLs of all the links on a page together with information - about their "rel" attribute, for determining which ones to treat as - downloads and which ones to queue for further scraping. - """ - def clean(url): - "Tidy up an URL." - scheme, netloc, path, params, query, frag = urlparse(url) - return urlunparse((scheme, netloc, quote(path), - params, query, frag)) - - result = set() - for match in self._href.finditer(self.data): - d = match.groupdict('') - rel = (d['rel1'] or d['rel2'] or d['rel3'] or - d['rel4'] or d['rel5'] or d['rel6']) - url = d['url1'] or d['url2'] or d['url3'] - url = urljoin(self.base_url, url) - url = unescape(url) - url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url) - result.add((url, rel)) - # We sort the result, hoping to bring the most recent versions - # to the front - result = sorted(result, key=lambda t: t[0], reverse=True) - return result - - -class SimpleScrapingLocator(Locator): - """ - A locator which scrapes HTML pages to locate downloads for a distribution. - This runs multiple threads to do the I/O; performance is at least as good - as pip's PackageFinder, which works in an analogous fashion. - """ - - # These are used to deal with various Content-Encoding schemes. - decoders = { - 'deflate': zlib.decompress, - 'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(b)).read(), - 'none': lambda b: b, - } - - def __init__(self, url, timeout=None, num_workers=10, **kwargs): - """ - Initialise an instance. - :param url: The root URL to use for scraping. - :param timeout: The timeout, in seconds, to be applied to requests. - This defaults to ``None`` (no timeout specified). - :param num_workers: The number of worker threads you want to do I/O, - This defaults to 10. - :param kwargs: Passed to the superclass. - """ - super(SimpleScrapingLocator, self).__init__(**kwargs) - self.base_url = ensure_slash(url) - self.timeout = timeout - self._page_cache = {} - self._seen = set() - self._to_fetch = queue.Queue() - self._bad_hosts = set() - self.skip_externals = False - self.num_workers = num_workers - self._lock = threading.RLock() - # See issue #45: we need to be resilient when the locator is used - # in a thread, e.g. with concurrent.futures. We can't use self._lock - # as it is for coordinating our internal threads - the ones created - # in _prepare_threads. - self._gplock = threading.RLock() - self.platform_check = False # See issue #112 - - def _prepare_threads(self): - """ - Threads are created only when get_project is called, and terminate - before it returns. They are there primarily to parallelise I/O (i.e. - fetching web pages). - """ - self._threads = [] - for i in range(self.num_workers): - t = threading.Thread(target=self._fetch) - t.setDaemon(True) - t.start() - self._threads.append(t) - - def _wait_threads(self): - """ - Tell all the threads to terminate (by sending a sentinel value) and - wait for them to do so. - """ - # Note that you need two loops, since you can't say which - # thread will get each sentinel - for t in self._threads: - self._to_fetch.put(None) # sentinel - for t in self._threads: - t.join() - self._threads = [] - - def _get_project(self, name): - result = {'urls': {}, 'digests': {}} - with self._gplock: - self.result = result - self.project_name = name - url = urljoin(self.base_url, '%s/' % quote(name)) - self._seen.clear() - self._page_cache.clear() - self._prepare_threads() - try: - logger.debug('Queueing %s', url) - self._to_fetch.put(url) - self._to_fetch.join() - finally: - self._wait_threads() - del self.result - return result - - platform_dependent = re.compile(r'\b(linux_(i\d86|x86_64|arm\w+)|' - r'win(32|_amd64)|macosx_?\d+)\b', re.I) - - def _is_platform_dependent(self, url): - """ - Does an URL refer to a platform-specific download? - """ - return self.platform_dependent.search(url) - - def _process_download(self, url): - """ - See if an URL is a suitable download for a project. - - If it is, register information in the result dictionary (for - _get_project) about the specific version it's for. - - Note that the return value isn't actually used other than as a boolean - value. - """ - if self.platform_check and self._is_platform_dependent(url): - info = None - else: - info = self.convert_url_to_download_info(url, self.project_name) - logger.debug('process_download: %s -> %s', url, info) - if info: - with self._lock: # needed because self.result is shared - self._update_version_data(self.result, info) - return info - - def _should_queue(self, link, referrer, rel): - """ - Determine whether a link URL from a referring page and with a - particular "rel" attribute should be queued for scraping. - """ - scheme, netloc, path, _, _, _ = urlparse(link) - if path.endswith(self.source_extensions + self.binary_extensions + - self.excluded_extensions): - result = False - elif self.skip_externals and not link.startswith(self.base_url): - result = False - elif not referrer.startswith(self.base_url): - result = False - elif rel not in ('homepage', 'download'): - result = False - elif scheme not in ('http', 'https', 'ftp'): - result = False - elif self._is_platform_dependent(link): - result = False - else: - host = netloc.split(':', 1)[0] - if host.lower() == 'localhost': - result = False - else: - result = True - logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, - referrer, result) - return result - - def _fetch(self): - """ - Get a URL to fetch from the work queue, get the HTML page, examine its - links for download candidates and candidates for further scraping. - - This is a handy method to run in a thread. - """ - while True: - url = self._to_fetch.get() - try: - if url: - page = self.get_page(url) - if page is None: # e.g. after an error - continue - for link, rel in page.links: - if link not in self._seen: - try: - self._seen.add(link) - if (not self._process_download(link) and - self._should_queue(link, url, rel)): - logger.debug('Queueing %s from %s', link, url) - self._to_fetch.put(link) - except MetadataInvalidError: # e.g. invalid versions - pass - except Exception as e: # pragma: no cover - self.errors.put(text_type(e)) - finally: - # always do this, to avoid hangs :-) - self._to_fetch.task_done() - if not url: - #logger.debug('Sentinel seen, quitting.') - break - - def get_page(self, url): - """ - Get the HTML for an URL, possibly from an in-memory cache. - - XXX TODO Note: this cache is never actually cleared. It's assumed that - the data won't get stale over the lifetime of a locator instance (not - necessarily true for the default_locator). - """ - # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api - scheme, netloc, path, _, _, _ = urlparse(url) - if scheme == 'file' and os.path.isdir(url2pathname(path)): - url = urljoin(ensure_slash(url), 'index.html') - - if url in self._page_cache: - result = self._page_cache[url] - logger.debug('Returning %s from cache: %s', url, result) - else: - host = netloc.split(':', 1)[0] - result = None - if host in self._bad_hosts: - logger.debug('Skipping %s due to bad host %s', url, host) - else: - req = Request(url, headers={'Accept-encoding': 'identity'}) - try: - logger.debug('Fetching %s', url) - resp = self.opener.open(req, timeout=self.timeout) - logger.debug('Fetched %s', url) - headers = resp.info() - content_type = headers.get('Content-Type', '') - if HTML_CONTENT_TYPE.match(content_type): - final_url = resp.geturl() - data = resp.read() - encoding = headers.get('Content-Encoding') - if encoding: - decoder = self.decoders[encoding] # fail if not found - data = decoder(data) - encoding = 'utf-8' - m = CHARSET.search(content_type) - if m: - encoding = m.group(1) - try: - data = data.decode(encoding) - except UnicodeError: # pragma: no cover - data = data.decode('latin-1') # fallback - result = Page(data, final_url) - self._page_cache[final_url] = result - except HTTPError as e: - if e.code != 404: - logger.exception('Fetch failed: %s: %s', url, e) - except URLError as e: # pragma: no cover - logger.exception('Fetch failed: %s: %s', url, e) - with self._lock: - self._bad_hosts.add(host) - except Exception as e: # pragma: no cover - logger.exception('Fetch failed: %s: %s', url, e) - finally: - self._page_cache[url] = result # even if None (failure) - return result - - _distname_re = re.compile(']*>([^<]+)<') - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - page = self.get_page(self.base_url) - if not page: - raise DistlibException('Unable to get %s' % self.base_url) - for match in self._distname_re.finditer(page.data): - result.add(match.group(1)) - return result - -class DirectoryLocator(Locator): - """ - This class locates distributions in a directory tree. - """ - - def __init__(self, path, **kwargs): - """ - Initialise an instance. - :param path: The root of the directory tree to search. - :param kwargs: Passed to the superclass constructor, - except for: - * recursive - if True (the default), subdirectories are - recursed into. If False, only the top-level directory - is searched, - """ - self.recursive = kwargs.pop('recursive', True) - super(DirectoryLocator, self).__init__(**kwargs) - path = os.path.abspath(path) - if not os.path.isdir(path): # pragma: no cover - raise DistlibException('Not a directory: %r' % path) - self.base_dir = path - - def should_include(self, filename, parent): - """ - Should a filename be considered as a candidate for a distribution - archive? As well as the filename, the directory which contains it - is provided, though not used by the current implementation. - """ - return filename.endswith(self.downloadable_extensions) - - def _get_project(self, name): - result = {'urls': {}, 'digests': {}} - for root, dirs, files in os.walk(self.base_dir): - for fn in files: - if self.should_include(fn, root): - fn = os.path.join(root, fn) - url = urlunparse(('file', '', - pathname2url(os.path.abspath(fn)), - '', '', '')) - info = self.convert_url_to_download_info(url, name) - if info: - self._update_version_data(result, info) - if not self.recursive: - break - return result - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - for root, dirs, files in os.walk(self.base_dir): - for fn in files: - if self.should_include(fn, root): - fn = os.path.join(root, fn) - url = urlunparse(('file', '', - pathname2url(os.path.abspath(fn)), - '', '', '')) - info = self.convert_url_to_download_info(url, None) - if info: - result.add(info['name']) - if not self.recursive: - break - return result - -class JSONLocator(Locator): - """ - This locator uses special extended metadata (not available on PyPI) and is - the basis of performant dependency resolution in distlib. Other locators - require archive downloads before dependencies can be determined! As you - might imagine, that can be slow. - """ - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Not available from this locator') - - def _get_project(self, name): - result = {'urls': {}, 'digests': {}} - data = get_project_data(name) - if data: - for info in data.get('files', []): - if info['ptype'] != 'sdist' or info['pyversion'] != 'source': - continue - # We don't store summary in project metadata as it makes - # the data bigger for no benefit during dependency - # resolution - dist = make_dist(data['name'], info['version'], - summary=data.get('summary', - 'Placeholder for summary'), - scheme=self.scheme) - md = dist.metadata - md.source_url = info['url'] - # TODO SHA256 digest - if 'digest' in info and info['digest']: - dist.digest = ('md5', info['digest']) - md.dependencies = info.get('requirements', {}) - dist.exports = info.get('exports', {}) - result[dist.version] = dist - result['urls'].setdefault(dist.version, set()).add(info['url']) - return result - -class DistPathLocator(Locator): - """ - This locator finds installed distributions in a path. It can be useful for - adding to an :class:`AggregatingLocator`. - """ - def __init__(self, distpath, **kwargs): - """ - Initialise an instance. - - :param distpath: A :class:`DistributionPath` instance to search. - """ - super(DistPathLocator, self).__init__(**kwargs) - assert isinstance(distpath, DistributionPath) - self.distpath = distpath - - def _get_project(self, name): - dist = self.distpath.get_distribution(name) - if dist is None: - result = {'urls': {}, 'digests': {}} - else: - result = { - dist.version: dist, - 'urls': {dist.version: set([dist.source_url])}, - 'digests': {dist.version: set([None])} - } - return result - - -class AggregatingLocator(Locator): - """ - This class allows you to chain and/or merge a list of locators. - """ - def __init__(self, *locators, **kwargs): - """ - Initialise an instance. - - :param locators: The list of locators to search. - :param kwargs: Passed to the superclass constructor, - except for: - * merge - if False (the default), the first successful - search from any of the locators is returned. If True, - the results from all locators are merged (this can be - slow). - """ - self.merge = kwargs.pop('merge', False) - self.locators = locators - super(AggregatingLocator, self).__init__(**kwargs) - - def clear_cache(self): - super(AggregatingLocator, self).clear_cache() - for locator in self.locators: - locator.clear_cache() - - def _set_scheme(self, value): - self._scheme = value - for locator in self.locators: - locator.scheme = value - - scheme = property(Locator.scheme.fget, _set_scheme) - - def _get_project(self, name): - result = {} - for locator in self.locators: - d = locator.get_project(name) - if d: - if self.merge: - files = result.get('urls', {}) - digests = result.get('digests', {}) - # next line could overwrite result['urls'], result['digests'] - result.update(d) - df = result.get('urls') - if files and df: - for k, v in files.items(): - if k in df: - df[k] |= v - else: - df[k] = v - dd = result.get('digests') - if digests and dd: - dd.update(digests) - else: - # See issue #18. If any dists are found and we're looking - # for specific constraints, we only return something if - # a match is found. For example, if a DirectoryLocator - # returns just foo (1.0) while we're looking for - # foo (>= 2.0), we'll pretend there was nothing there so - # that subsequent locators can be queried. Otherwise we - # would just return foo (1.0) which would then lead to a - # failure to find foo (>= 2.0), because other locators - # weren't searched. Note that this only matters when - # merge=False. - if self.matcher is None: - found = True - else: - found = False - for k in d: - if self.matcher.match(k): - found = True - break - if found: - result = d - break - return result - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - for locator in self.locators: - try: - result |= locator.get_distribution_names() - except NotImplementedError: - pass - return result - - -# We use a legacy scheme simply because most of the dists on PyPI use legacy -# versions which don't conform to PEP 426 / PEP 440. -default_locator = AggregatingLocator( - JSONLocator(), - SimpleScrapingLocator('https://pypi.org/simple/', - timeout=3.0), - scheme='legacy') - -locate = default_locator.locate - - -class DependencyFinder(object): - """ - Locate dependencies for distributions. - """ - - def __init__(self, locator=None): - """ - Initialise an instance, using the specified locator - to locate distributions. - """ - self.locator = locator or default_locator - self.scheme = get_scheme(self.locator.scheme) - - def add_distribution(self, dist): - """ - Add a distribution to the finder. This will update internal information - about who provides what. - :param dist: The distribution to add. - """ - logger.debug('adding distribution %s', dist) - name = dist.key - self.dists_by_name[name] = dist - self.dists[(name, dist.version)] = dist - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Add to provided: %s, %s, %s', name, version, dist) - self.provided.setdefault(name, set()).add((version, dist)) - - def remove_distribution(self, dist): - """ - Remove a distribution from the finder. This will update internal - information about who provides what. - :param dist: The distribution to remove. - """ - logger.debug('removing distribution %s', dist) - name = dist.key - del self.dists_by_name[name] - del self.dists[(name, dist.version)] - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Remove from provided: %s, %s, %s', name, version, dist) - s = self.provided[name] - s.remove((version, dist)) - if not s: - del self.provided[name] - - def get_matcher(self, reqt): - """ - Get a version matcher for a requirement. - :param reqt: The requirement - :type reqt: str - :return: A version matcher (an instance of - :class:`distlib.version.Matcher`). - """ - try: - matcher = self.scheme.matcher(reqt) - except UnsupportedVersionError: # pragma: no cover - # XXX compat-mode if cannot read the version - name = reqt.split()[0] - matcher = self.scheme.matcher(name) - return matcher - - def find_providers(self, reqt): - """ - Find the distributions which can fulfill a requirement. - - :param reqt: The requirement. - :type reqt: str - :return: A set of distribution which can fulfill the requirement. - """ - matcher = self.get_matcher(reqt) - name = matcher.key # case-insensitive - result = set() - provided = self.provided - if name in provided: - for version, provider in provided[name]: - try: - match = matcher.match(version) - except UnsupportedVersionError: - match = False - - if match: - result.add(provider) - break - return result - - def try_to_replace(self, provider, other, problems): - """ - Attempt to replace one provider with another. This is typically used - when resolving dependencies from multiple sources, e.g. A requires - (B >= 1.0) while C requires (B >= 1.1). - - For successful replacement, ``provider`` must meet all the requirements - which ``other`` fulfills. - - :param provider: The provider we are trying to replace with. - :param other: The provider we're trying to replace. - :param problems: If False is returned, this will contain what - problems prevented replacement. This is currently - a tuple of the literal string 'cantreplace', - ``provider``, ``other`` and the set of requirements - that ``provider`` couldn't fulfill. - :return: True if we can replace ``other`` with ``provider``, else - False. - """ - rlist = self.reqts[other] - unmatched = set() - for s in rlist: - matcher = self.get_matcher(s) - if not matcher.match(provider.version): - unmatched.add(s) - if unmatched: - # can't replace other with provider - problems.add(('cantreplace', provider, other, - frozenset(unmatched))) - result = False - else: - # can replace other with provider - self.remove_distribution(other) - del self.reqts[other] - for s in rlist: - self.reqts.setdefault(provider, set()).add(s) - self.add_distribution(provider) - result = True - return result - - def find(self, requirement, meta_extras=None, prereleases=False): - """ - Find a distribution and all distributions it depends on. - - :param requirement: The requirement specifying the distribution to - find, or a Distribution instance. - :param meta_extras: A list of meta extras such as :test:, :build: and - so on. - :param prereleases: If ``True``, allow pre-release versions to be - returned - otherwise, don't return prereleases - unless they're all that's available. - - Return a set of :class:`Distribution` instances and a set of - problems. - - The distributions returned should be such that they have the - :attr:`required` attribute set to ``True`` if they were - from the ``requirement`` passed to ``find()``, and they have the - :attr:`build_time_dependency` attribute set to ``True`` unless they - are post-installation dependencies of the ``requirement``. - - The problems should be a tuple consisting of the string - ``'unsatisfied'`` and the requirement which couldn't be satisfied - by any distribution known to the locator. - """ - - self.provided = {} - self.dists = {} - self.dists_by_name = {} - self.reqts = {} - - meta_extras = set(meta_extras or []) - if ':*:' in meta_extras: - meta_extras.remove(':*:') - # :meta: and :run: are implicitly included - meta_extras |= set([':test:', ':build:', ':dev:']) - - if isinstance(requirement, Distribution): - dist = odist = requirement - logger.debug('passed %s as requirement', odist) - else: - dist = odist = self.locator.locate(requirement, - prereleases=prereleases) - if dist is None: - raise DistlibException('Unable to locate %r' % requirement) - logger.debug('located %s', odist) - dist.requested = True - problems = set() - todo = set([dist]) - install_dists = set([odist]) - while todo: - dist = todo.pop() - name = dist.key # case-insensitive - if name not in self.dists_by_name: - self.add_distribution(dist) - else: - #import pdb; pdb.set_trace() - other = self.dists_by_name[name] - if other != dist: - self.try_to_replace(dist, other, problems) - - ireqts = dist.run_requires | dist.meta_requires - sreqts = dist.build_requires - ereqts = set() - if meta_extras and dist in install_dists: - for key in ('test', 'build', 'dev'): - e = ':%s:' % key - if e in meta_extras: - ereqts |= getattr(dist, '%s_requires' % key) - all_reqts = ireqts | sreqts | ereqts - for r in all_reqts: - providers = self.find_providers(r) - if not providers: - logger.debug('No providers found for %r', r) - provider = self.locator.locate(r, prereleases=prereleases) - # If no provider is found and we didn't consider - # prereleases, consider them now. - if provider is None and not prereleases: - provider = self.locator.locate(r, prereleases=True) - if provider is None: - logger.debug('Cannot satisfy %r', r) - problems.add(('unsatisfied', r)) - else: - n, v = provider.key, provider.version - if (n, v) not in self.dists: - todo.add(provider) - providers.add(provider) - if r in ireqts and dist in install_dists: - install_dists.add(provider) - logger.debug('Adding %s to install_dists', - provider.name_and_version) - for p in providers: - name = p.key - if name not in self.dists_by_name: - self.reqts.setdefault(p, set()).add(r) - else: - other = self.dists_by_name[name] - if other != p: - # see if other can be replaced by p - self.try_to_replace(p, other, problems) - - dists = set(self.dists.values()) - for dist in dists: - dist.build_time_dependency = dist not in install_dists - if dist.build_time_dependency: - logger.debug('%s is a build-time dependency only.', - dist.name_and_version) - logger.debug('find done for %s', odist) - return dists, problems diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/manifest.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/manifest.py deleted file mode 100644 index ca0fe44..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/manifest.py +++ /dev/null @@ -1,393 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2013 Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -""" -Class representing the list of files in a distribution. - -Equivalent to distutils.filelist, but fixes some problems. -""" -import fnmatch -import logging -import os -import re -import sys - -from . import DistlibException -from .compat import fsdecode -from .util import convert_path - - -__all__ = ['Manifest'] - -logger = logging.getLogger(__name__) - -# a \ followed by some spaces + EOL -_COLLAPSE_PATTERN = re.compile('\\\\w*\n', re.M) -_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) - -# -# Due to the different results returned by fnmatch.translate, we need -# to do slightly different processing for Python 2.7 and 3.2 ... this needed -# to be brought in for Python 3.6 onwards. -# -_PYTHON_VERSION = sys.version_info[:2] - -class Manifest(object): - """A list of files built by on exploring the filesystem and filtered by - applying various patterns to what we find there. - """ - - def __init__(self, base=None): - """ - Initialise an instance. - - :param base: The base directory to explore under. - """ - self.base = os.path.abspath(os.path.normpath(base or os.getcwd())) - self.prefix = self.base + os.sep - self.allfiles = None - self.files = set() - - # - # Public API - # - - def findall(self): - """Find all files under the base and set ``allfiles`` to the absolute - pathnames of files found. - """ - from stat import S_ISREG, S_ISDIR, S_ISLNK - - self.allfiles = allfiles = [] - root = self.base - stack = [root] - pop = stack.pop - push = stack.append - - while stack: - root = pop() - names = os.listdir(root) - - for name in names: - fullname = os.path.join(root, name) - - # Avoid excess stat calls -- just one will do, thank you! - stat = os.stat(fullname) - mode = stat.st_mode - if S_ISREG(mode): - allfiles.append(fsdecode(fullname)) - elif S_ISDIR(mode) and not S_ISLNK(mode): - push(fullname) - - def add(self, item): - """ - Add a file to the manifest. - - :param item: The pathname to add. This can be relative to the base. - """ - if not item.startswith(self.prefix): - item = os.path.join(self.base, item) - self.files.add(os.path.normpath(item)) - - def add_many(self, items): - """ - Add a list of files to the manifest. - - :param items: The pathnames to add. These can be relative to the base. - """ - for item in items: - self.add(item) - - def sorted(self, wantdirs=False): - """ - Return sorted files in directory order - """ - - def add_dir(dirs, d): - dirs.add(d) - logger.debug('add_dir added %s', d) - if d != self.base: - parent, _ = os.path.split(d) - assert parent not in ('', '/') - add_dir(dirs, parent) - - result = set(self.files) # make a copy! - if wantdirs: - dirs = set() - for f in result: - add_dir(dirs, os.path.dirname(f)) - result |= dirs - return [os.path.join(*path_tuple) for path_tuple in - sorted(os.path.split(path) for path in result)] - - def clear(self): - """Clear all collected files.""" - self.files = set() - self.allfiles = [] - - def process_directive(self, directive): - """ - Process a directive which either adds some files from ``allfiles`` to - ``files``, or removes some files from ``files``. - - :param directive: The directive to process. This should be in a format - compatible with distutils ``MANIFEST.in`` files: - - http://docs.python.org/distutils/sourcedist.html#commands - """ - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dirpattern). - action, patterns, thedir, dirpattern = self._parse_directive(directive) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - if action == 'include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=True): - logger.warning('no files found matching %r', pattern) - - elif action == 'exclude': - for pattern in patterns: - found = self._exclude_pattern(pattern, anchor=True) - #if not found: - # logger.warning('no previously-included files ' - # 'found matching %r', pattern) - - elif action == 'global-include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=False): - logger.warning('no files found matching %r ' - 'anywhere in distribution', pattern) - - elif action == 'global-exclude': - for pattern in patterns: - found = self._exclude_pattern(pattern, anchor=False) - #if not found: - # logger.warning('no previously-included files ' - # 'matching %r found anywhere in ' - # 'distribution', pattern) - - elif action == 'recursive-include': - for pattern in patterns: - if not self._include_pattern(pattern, prefix=thedir): - logger.warning('no files found matching %r ' - 'under directory %r', pattern, thedir) - - elif action == 'recursive-exclude': - for pattern in patterns: - found = self._exclude_pattern(pattern, prefix=thedir) - #if not found: - # logger.warning('no previously-included files ' - # 'matching %r found under directory %r', - # pattern, thedir) - - elif action == 'graft': - if not self._include_pattern(None, prefix=dirpattern): - logger.warning('no directories found matching %r', - dirpattern) - - elif action == 'prune': - if not self._exclude_pattern(None, prefix=dirpattern): - logger.warning('no previously-included directories found ' - 'matching %r', dirpattern) - else: # pragma: no cover - # This should never happen, as it should be caught in - # _parse_template_line - raise DistlibException( - 'invalid action %r' % action) - - # - # Private API - # - - def _parse_directive(self, directive): - """ - Validate a directive. - :param directive: The directive to validate. - :return: A tuple of action, patterns, thedir, dir_patterns - """ - words = directive.split() - if len(words) == 1 and words[0] not in ('include', 'exclude', - 'global-include', - 'global-exclude', - 'recursive-include', - 'recursive-exclude', - 'graft', 'prune'): - # no action given, let's use the default 'include' - words.insert(0, 'include') - - action = words[0] - patterns = thedir = dir_pattern = None - - if action in ('include', 'exclude', - 'global-include', 'global-exclude'): - if len(words) < 2: - raise DistlibException( - '%r expects ...' % action) - - patterns = [convert_path(word) for word in words[1:]] - - elif action in ('recursive-include', 'recursive-exclude'): - if len(words) < 3: - raise DistlibException( - '%r expects ...' % action) - - thedir = convert_path(words[1]) - patterns = [convert_path(word) for word in words[2:]] - - elif action in ('graft', 'prune'): - if len(words) != 2: - raise DistlibException( - '%r expects a single ' % action) - - dir_pattern = convert_path(words[1]) - - else: - raise DistlibException('unknown action %r' % action) - - return action, patterns, thedir, dir_pattern - - def _include_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Select strings (presumably filenames) from 'self.files' that - match 'pattern', a Unix-style wildcard (glob) pattern. - - Patterns are not quite the same as implemented by the 'fnmatch' - module: '*' and '?' match non-special characters, where "special" - is platform-dependent: slash on Unix; colon, slash, and backslash on - DOS/Windows; and colon on Mac OS. - - If 'anchor' is true (the default), then the pattern match is more - stringent: "*.py" will match "foo.py" but not "foo/bar.py". If - 'anchor' is false, both of these will match. - - If 'prefix' is supplied, then only filenames starting with 'prefix' - (itself a pattern) and ending with 'pattern', with anything in between - them, will match. 'anchor' is ignored in this case. - - If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and - 'pattern' is assumed to be either a string containing a regex or a - regex object -- no translation is done, the regex is just compiled - and used as-is. - - Selected strings will be added to self.files. - - Return True if files are found. - """ - # XXX docstring lying about what the special chars are? - found = False - pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) - - # delayed loading of allfiles list - if self.allfiles is None: - self.findall() - - for name in self.allfiles: - if pattern_re.search(name): - self.files.add(name) - found = True - return found - - def _exclude_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Remove strings (presumably filenames) from 'files' that match - 'pattern'. - - Other parameters are the same as for 'include_pattern()', above. - The list 'self.files' is modified in place. Return True if files are - found. - - This API is public to allow e.g. exclusion of SCM subdirs, e.g. when - packaging source distributions - """ - found = False - pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) - for f in list(self.files): - if pattern_re.search(f): - self.files.remove(f) - found = True - return found - - def _translate_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Translate a shell-like wildcard pattern to a compiled regular - expression. - - Return the compiled regex. If 'is_regex' true, - then 'pattern' is directly compiled to a regex (if it's a string) - or just returned as-is (assumes it's a regex object). - """ - if is_regex: - if isinstance(pattern, str): - return re.compile(pattern) - else: - return pattern - - if _PYTHON_VERSION > (3, 2): - # ditch start and end characters - start, _, end = self._glob_to_re('_').partition('_') - - if pattern: - pattern_re = self._glob_to_re(pattern) - if _PYTHON_VERSION > (3, 2): - assert pattern_re.startswith(start) and pattern_re.endswith(end) - else: - pattern_re = '' - - base = re.escape(os.path.join(self.base, '')) - if prefix is not None: - # ditch end of pattern character - if _PYTHON_VERSION <= (3, 2): - empty_pattern = self._glob_to_re('') - prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)] - else: - prefix_re = self._glob_to_re(prefix) - assert prefix_re.startswith(start) and prefix_re.endswith(end) - prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] - sep = os.sep - if os.sep == '\\': - sep = r'\\' - if _PYTHON_VERSION <= (3, 2): - pattern_re = '^' + base + sep.join((prefix_re, - '.*' + pattern_re)) - else: - pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] - pattern_re = r'%s%s%s%s.*%s%s' % (start, base, prefix_re, sep, - pattern_re, end) - else: # no prefix -- respect anchor flag - if anchor: - if _PYTHON_VERSION <= (3, 2): - pattern_re = '^' + base + pattern_re - else: - pattern_re = r'%s%s%s' % (start, base, pattern_re[len(start):]) - - return re.compile(pattern_re) - - def _glob_to_re(self, pattern): - """Translate a shell-like glob pattern to a regular expression. - - Return a string containing the regex. Differs from - 'fnmatch.translate()' in that '*' does not match "special characters" - (which are platform-specific). - """ - pattern_re = fnmatch.translate(pattern) - - # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which - # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, - # and by extension they shouldn't match such "special characters" under - # any OS. So change all non-escaped dots in the RE to match any - # character except the special characters (currently: just os.sep). - sep = os.sep - if os.sep == '\\': - # we're using a regex to manipulate a regex, so we need - # to escape the backslash twice - sep = r'\\\\' - escaped = r'\1[^%s]' % sep - pattern_re = re.sub(r'((? y, - '!=': lambda x, y: x != y, - '<': lambda x, y: x < y, - '<=': lambda x, y: x == y or x < y, - '>': lambda x, y: x > y, - '>=': lambda x, y: x == y or x > y, - 'and': lambda x, y: x and y, - 'or': lambda x, y: x or y, - 'in': lambda x, y: x in y, - 'not in': lambda x, y: x not in y, - } - - def evaluate(self, expr, context): - """ - Evaluate a marker expression returned by the :func:`parse_requirement` - function in the specified context. - """ - if isinstance(expr, string_types): - if expr[0] in '\'"': - result = expr[1:-1] - else: - if expr not in context: - raise SyntaxError('unknown variable: %s' % expr) - result = context[expr] - else: - assert isinstance(expr, dict) - op = expr['op'] - if op not in self.operations: - raise NotImplementedError('op not implemented: %s' % op) - elhs = expr['lhs'] - erhs = expr['rhs'] - if _is_literal(expr['lhs']) and _is_literal(expr['rhs']): - raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs)) - - lhs = self.evaluate(elhs, context) - rhs = self.evaluate(erhs, context) - result = self.operations[op](lhs, rhs) - return result - -def default_context(): - def format_full_version(info): - version = '%s.%s.%s' % (info.major, info.minor, info.micro) - kind = info.releaselevel - if kind != 'final': - version += kind[0] + str(info.serial) - return version - - if hasattr(sys, 'implementation'): - implementation_version = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - else: - implementation_version = '0' - implementation_name = '' - - result = { - 'implementation_name': implementation_name, - 'implementation_version': implementation_version, - 'os_name': os.name, - 'platform_machine': platform.machine(), - 'platform_python_implementation': platform.python_implementation(), - 'platform_release': platform.release(), - 'platform_system': platform.system(), - 'platform_version': platform.version(), - 'platform_in_venv': str(in_venv()), - 'python_full_version': platform.python_version(), - 'python_version': platform.python_version()[:3], - 'sys_platform': sys.platform, - } - return result - -DEFAULT_CONTEXT = default_context() -del default_context - -evaluator = Evaluator() - -def interpret(marker, execution_context=None): - """ - Interpret a marker and return a result depending on environment. - - :param marker: The marker to interpret. - :type marker: str - :param execution_context: The context used for name lookup. - :type execution_context: mapping - """ - try: - expr, rest = parse_marker(marker) - except Exception as e: - raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e)) - if rest and rest[0] != '#': - raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest)) - context = dict(DEFAULT_CONTEXT) - if execution_context: - context.update(execution_context) - return evaluator.evaluate(expr, context) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/metadata.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/metadata.py deleted file mode 100644 index 6a26b0a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/metadata.py +++ /dev/null @@ -1,1058 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Implementation of the Metadata for Python packages PEPs. - -Supports all metadata formats (1.0, 1.1, 1.2, 1.3/2.1 and withdrawn 2.0). -""" -from __future__ import unicode_literals - -import codecs -from email import message_from_file -import json -import logging -import re - - -from . import DistlibException, __version__ -from .compat import StringIO, string_types, text_type -from .markers import interpret -from .util import extract_by_key, get_extras -from .version import get_scheme, PEP440_VERSION_RE - -logger = logging.getLogger(__name__) - - -class MetadataMissingError(DistlibException): - """A required metadata is missing""" - - -class MetadataConflictError(DistlibException): - """Attempt to read or write metadata fields that are conflictual.""" - - -class MetadataUnrecognizedVersionError(DistlibException): - """Unknown metadata version number.""" - - -class MetadataInvalidError(DistlibException): - """A metadata value is invalid""" - -# public API of this module -__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] - -# Encoding used for the PKG-INFO files -PKG_INFO_ENCODING = 'utf-8' - -# preferred version. Hopefully will be changed -# to 1.2 once PEP 345 is supported everywhere -PKG_INFO_PREFERRED_VERSION = '1.1' - -_LINE_PREFIX_1_2 = re.compile('\n \\|') -_LINE_PREFIX_PRE_1_2 = re.compile('\n ') -_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License') - -_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License', 'Classifier', 'Download-URL', 'Obsoletes', - 'Provides', 'Requires') - -_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', - 'Download-URL') - -_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'Maintainer', 'Maintainer-email', 'License', - 'Classifier', 'Download-URL', 'Obsoletes-Dist', - 'Project-URL', 'Provides-Dist', 'Requires-Dist', - 'Requires-Python', 'Requires-External') - -_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', - 'Obsoletes-Dist', 'Requires-External', 'Maintainer', - 'Maintainer-email', 'Project-URL') - -_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'Maintainer', 'Maintainer-email', 'License', - 'Classifier', 'Download-URL', 'Obsoletes-Dist', - 'Project-URL', 'Provides-Dist', 'Requires-Dist', - 'Requires-Python', 'Requires-External', 'Private-Version', - 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension', - 'Provides-Extra') - -_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', - 'Setup-Requires-Dist', 'Extension') - -# See issue #106: Sometimes 'Requires' and 'Provides' occur wrongly in -# the metadata. Include them in the tuple literal below to allow them -# (for now). -# Ditto for Obsoletes - see issue #140. -_566_FIELDS = _426_FIELDS + ('Description-Content-Type', - 'Requires', 'Provides', 'Obsoletes') - -_566_MARKERS = ('Description-Content-Type',) - -_ALL_FIELDS = set() -_ALL_FIELDS.update(_241_FIELDS) -_ALL_FIELDS.update(_314_FIELDS) -_ALL_FIELDS.update(_345_FIELDS) -_ALL_FIELDS.update(_426_FIELDS) -_ALL_FIELDS.update(_566_FIELDS) - -EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') - - -def _version2fieldlist(version): - if version == '1.0': - return _241_FIELDS - elif version == '1.1': - return _314_FIELDS - elif version == '1.2': - return _345_FIELDS - elif version in ('1.3', '2.1'): - # avoid adding field names if already there - return _345_FIELDS + tuple(f for f in _566_FIELDS if f not in _345_FIELDS) - elif version == '2.0': - return _426_FIELDS - raise MetadataUnrecognizedVersionError(version) - - -def _best_version(fields): - """Detect the best version depending on the fields used.""" - def _has_marker(keys, markers): - for marker in markers: - if marker in keys: - return True - return False - - keys = [] - for key, value in fields.items(): - if value in ([], 'UNKNOWN', None): - continue - keys.append(key) - - possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.0', '2.1'] - - # first let's try to see if a field is not part of one of the version - for key in keys: - if key not in _241_FIELDS and '1.0' in possible_versions: - possible_versions.remove('1.0') - logger.debug('Removed 1.0 due to %s', key) - if key not in _314_FIELDS and '1.1' in possible_versions: - possible_versions.remove('1.1') - logger.debug('Removed 1.1 due to %s', key) - if key not in _345_FIELDS and '1.2' in possible_versions: - possible_versions.remove('1.2') - logger.debug('Removed 1.2 due to %s', key) - if key not in _566_FIELDS and '1.3' in possible_versions: - possible_versions.remove('1.3') - logger.debug('Removed 1.3 due to %s', key) - if key not in _566_FIELDS and '2.1' in possible_versions: - if key != 'Description': # In 2.1, description allowed after headers - possible_versions.remove('2.1') - logger.debug('Removed 2.1 due to %s', key) - if key not in _426_FIELDS and '2.0' in possible_versions: - possible_versions.remove('2.0') - logger.debug('Removed 2.0 due to %s', key) - - # possible_version contains qualified versions - if len(possible_versions) == 1: - return possible_versions[0] # found ! - elif len(possible_versions) == 0: - logger.debug('Out of options - unknown metadata set: %s', fields) - raise MetadataConflictError('Unknown metadata set') - - # let's see if one unique marker is found - is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) - is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) - is_2_1 = '2.1' in possible_versions and _has_marker(keys, _566_MARKERS) - is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) - if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_0) > 1: - raise MetadataConflictError('You used incompatible 1.1/1.2/2.0/2.1 fields') - - # we have the choice, 1.0, or 1.2, or 2.0 - # - 1.0 has a broken Summary field but works with all tools - # - 1.1 is to avoid - # - 1.2 fixes Summary but has little adoption - # - 2.0 adds more features and is very new - if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_0: - # we couldn't find any specific marker - if PKG_INFO_PREFERRED_VERSION in possible_versions: - return PKG_INFO_PREFERRED_VERSION - if is_1_1: - return '1.1' - if is_1_2: - return '1.2' - if is_2_1: - return '2.1' - - return '2.0' - -# This follows the rules about transforming keys as described in -# https://www.python.org/dev/peps/pep-0566/#id17 -_ATTR2FIELD = { - name.lower().replace("-", "_"): name for name in _ALL_FIELDS -} -_FIELD2ATTR = {field: attr for attr, field in _ATTR2FIELD.items()} - -_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') -_VERSIONS_FIELDS = ('Requires-Python',) -_VERSION_FIELDS = ('Version',) -_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', - 'Requires', 'Provides', 'Obsoletes-Dist', - 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', - 'Provides-Extra', 'Extension') -_LISTTUPLEFIELDS = ('Project-URL',) - -_ELEMENTSFIELD = ('Keywords',) - -_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') - -_MISSING = object() - -_FILESAFE = re.compile('[^A-Za-z0-9.]+') - - -def _get_name_and_version(name, version, for_filename=False): - """Return the distribution name with version. - - If for_filename is true, return a filename-escaped form.""" - if for_filename: - # For both name and version any runs of non-alphanumeric or '.' - # characters are replaced with a single '-'. Additionally any - # spaces in the version string become '.' - name = _FILESAFE.sub('-', name) - version = _FILESAFE.sub('-', version.replace(' ', '.')) - return '%s-%s' % (name, version) - - -class LegacyMetadata(object): - """The legacy metadata of a release. - - Supports versions 1.0, 1.1, 1.2, 2.0 and 1.3/2.1 (auto-detected). You can - instantiate the class with one of these arguments (or none): - - *path*, the path to a metadata file - - *fileobj* give a file-like object with metadata as content - - *mapping* is a dict-like object - - *scheme* is a version scheme name - """ - # TODO document the mapping API and UNKNOWN default key - - def __init__(self, path=None, fileobj=None, mapping=None, - scheme='default'): - if [path, fileobj, mapping].count(None) < 2: - raise TypeError('path, fileobj and mapping are exclusive') - self._fields = {} - self.requires_files = [] - self._dependencies = None - self.scheme = scheme - if path is not None: - self.read(path) - elif fileobj is not None: - self.read_file(fileobj) - elif mapping is not None: - self.update(mapping) - self.set_metadata_version() - - def set_metadata_version(self): - self._fields['Metadata-Version'] = _best_version(self._fields) - - def _write_field(self, fileobj, name, value): - fileobj.write('%s: %s\n' % (name, value)) - - def __getitem__(self, name): - return self.get(name) - - def __setitem__(self, name, value): - return self.set(name, value) - - def __delitem__(self, name): - field_name = self._convert_name(name) - try: - del self._fields[field_name] - except KeyError: - raise KeyError(name) - - def __contains__(self, name): - return (name in self._fields or - self._convert_name(name) in self._fields) - - def _convert_name(self, name): - if name in _ALL_FIELDS: - return name - name = name.replace('-', '_').lower() - return _ATTR2FIELD.get(name, name) - - def _default_value(self, name): - if name in _LISTFIELDS or name in _ELEMENTSFIELD: - return [] - return 'UNKNOWN' - - def _remove_line_prefix(self, value): - if self.metadata_version in ('1.0', '1.1'): - return _LINE_PREFIX_PRE_1_2.sub('\n', value) - else: - return _LINE_PREFIX_1_2.sub('\n', value) - - def __getattr__(self, name): - if name in _ATTR2FIELD: - return self[name] - raise AttributeError(name) - - # - # Public API - # - -# dependencies = property(_get_dependencies, _set_dependencies) - - def get_fullname(self, filesafe=False): - """Return the distribution name with version. - - If filesafe is true, return a filename-escaped form.""" - return _get_name_and_version(self['Name'], self['Version'], filesafe) - - def is_field(self, name): - """return True if name is a valid metadata key""" - name = self._convert_name(name) - return name in _ALL_FIELDS - - def is_multi_field(self, name): - name = self._convert_name(name) - return name in _LISTFIELDS - - def read(self, filepath): - """Read the metadata values from a file path.""" - fp = codecs.open(filepath, 'r', encoding='utf-8') - try: - self.read_file(fp) - finally: - fp.close() - - def read_file(self, fileob): - """Read the metadata values from a file object.""" - msg = message_from_file(fileob) - self._fields['Metadata-Version'] = msg['metadata-version'] - - # When reading, get all the fields we can - for field in _ALL_FIELDS: - if field not in msg: - continue - if field in _LISTFIELDS: - # we can have multiple lines - values = msg.get_all(field) - if field in _LISTTUPLEFIELDS and values is not None: - values = [tuple(value.split(',')) for value in values] - self.set(field, values) - else: - # single line - value = msg[field] - if value is not None and value != 'UNKNOWN': - self.set(field, value) - - # PEP 566 specifies that the body be used for the description, if - # available - body = msg.get_payload() - self["Description"] = body if body else self["Description"] - # logger.debug('Attempting to set metadata for %s', self) - # self.set_metadata_version() - - def write(self, filepath, skip_unknown=False): - """Write the metadata fields to filepath.""" - fp = codecs.open(filepath, 'w', encoding='utf-8') - try: - self.write_file(fp, skip_unknown) - finally: - fp.close() - - def write_file(self, fileobject, skip_unknown=False): - """Write the PKG-INFO format data to a file object.""" - self.set_metadata_version() - - for field in _version2fieldlist(self['Metadata-Version']): - values = self.get(field) - if skip_unknown and values in ('UNKNOWN', [], ['UNKNOWN']): - continue - if field in _ELEMENTSFIELD: - self._write_field(fileobject, field, ','.join(values)) - continue - if field not in _LISTFIELDS: - if field == 'Description': - if self.metadata_version in ('1.0', '1.1'): - values = values.replace('\n', '\n ') - else: - values = values.replace('\n', '\n |') - values = [values] - - if field in _LISTTUPLEFIELDS: - values = [','.join(value) for value in values] - - for value in values: - self._write_field(fileobject, field, value) - - def update(self, other=None, **kwargs): - """Set metadata values from the given iterable `other` and kwargs. - - Behavior is like `dict.update`: If `other` has a ``keys`` method, - they are looped over and ``self[key]`` is assigned ``other[key]``. - Else, ``other`` is an iterable of ``(key, value)`` iterables. - - Keys that don't match a metadata field or that have an empty value are - dropped. - """ - def _set(key, value): - if key in _ATTR2FIELD and value: - self.set(self._convert_name(key), value) - - if not other: - # other is None or empty container - pass - elif hasattr(other, 'keys'): - for k in other.keys(): - _set(k, other[k]) - else: - for k, v in other: - _set(k, v) - - if kwargs: - for k, v in kwargs.items(): - _set(k, v) - - def set(self, name, value): - """Control then set a metadata field.""" - name = self._convert_name(name) - - if ((name in _ELEMENTSFIELD or name == 'Platform') and - not isinstance(value, (list, tuple))): - if isinstance(value, string_types): - value = [v.strip() for v in value.split(',')] - else: - value = [] - elif (name in _LISTFIELDS and - not isinstance(value, (list, tuple))): - if isinstance(value, string_types): - value = [value] - else: - value = [] - - if logger.isEnabledFor(logging.WARNING): - project_name = self['Name'] - - scheme = get_scheme(self.scheme) - if name in _PREDICATE_FIELDS and value is not None: - for v in value: - # check that the values are valid - if not scheme.is_valid_matcher(v.split(';')[0]): - logger.warning( - "'%s': '%s' is not valid (field '%s')", - project_name, v, name) - # FIXME this rejects UNKNOWN, is that right? - elif name in _VERSIONS_FIELDS and value is not None: - if not scheme.is_valid_constraint_list(value): - logger.warning("'%s': '%s' is not a valid version (field '%s')", - project_name, value, name) - elif name in _VERSION_FIELDS and value is not None: - if not scheme.is_valid_version(value): - logger.warning("'%s': '%s' is not a valid version (field '%s')", - project_name, value, name) - - if name in _UNICODEFIELDS: - if name == 'Description': - value = self._remove_line_prefix(value) - - self._fields[name] = value - - def get(self, name, default=_MISSING): - """Get a metadata field.""" - name = self._convert_name(name) - if name not in self._fields: - if default is _MISSING: - default = self._default_value(name) - return default - if name in _UNICODEFIELDS: - value = self._fields[name] - return value - elif name in _LISTFIELDS: - value = self._fields[name] - if value is None: - return [] - res = [] - for val in value: - if name not in _LISTTUPLEFIELDS: - res.append(val) - else: - # That's for Project-URL - res.append((val[0], val[1])) - return res - - elif name in _ELEMENTSFIELD: - value = self._fields[name] - if isinstance(value, string_types): - return value.split(',') - return self._fields[name] - - def check(self, strict=False): - """Check if the metadata is compliant. If strict is True then raise if - no Name or Version are provided""" - self.set_metadata_version() - - # XXX should check the versions (if the file was loaded) - missing, warnings = [], [] - - for attr in ('Name', 'Version'): # required by PEP 345 - if attr not in self: - missing.append(attr) - - if strict and missing != []: - msg = 'missing required metadata: %s' % ', '.join(missing) - raise MetadataMissingError(msg) - - for attr in ('Home-page', 'Author'): - if attr not in self: - missing.append(attr) - - # checking metadata 1.2 (XXX needs to check 1.1, 1.0) - if self['Metadata-Version'] != '1.2': - return missing, warnings - - scheme = get_scheme(self.scheme) - - def are_valid_constraints(value): - for v in value: - if not scheme.is_valid_matcher(v.split(';')[0]): - return False - return True - - for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints), - (_VERSIONS_FIELDS, - scheme.is_valid_constraint_list), - (_VERSION_FIELDS, - scheme.is_valid_version)): - for field in fields: - value = self.get(field, None) - if value is not None and not controller(value): - warnings.append("Wrong value for '%s': %s" % (field, value)) - - return missing, warnings - - def todict(self, skip_missing=False): - """Return fields as a dict. - - Field names will be converted to use the underscore-lowercase style - instead of hyphen-mixed case (i.e. home_page instead of Home-page). - This is as per https://www.python.org/dev/peps/pep-0566/#id17. - """ - self.set_metadata_version() - - fields = _version2fieldlist(self['Metadata-Version']) - - data = {} - - for field_name in fields: - if not skip_missing or field_name in self._fields: - key = _FIELD2ATTR[field_name] - if key != 'project_url': - data[key] = self[field_name] - else: - data[key] = [','.join(u) for u in self[field_name]] - - return data - - def add_requirements(self, requirements): - if self['Metadata-Version'] == '1.1': - # we can't have 1.1 metadata *and* Setuptools requires - for field in ('Obsoletes', 'Requires', 'Provides'): - if field in self: - del self[field] - self['Requires-Dist'] += requirements - - # Mapping API - # TODO could add iter* variants - - def keys(self): - return list(_version2fieldlist(self['Metadata-Version'])) - - def __iter__(self): - for key in self.keys(): - yield key - - def values(self): - return [self[key] for key in self.keys()] - - def items(self): - return [(key, self[key]) for key in self.keys()] - - def __repr__(self): - return '<%s %s %s>' % (self.__class__.__name__, self.name, - self.version) - - -METADATA_FILENAME = 'pydist.json' -WHEEL_METADATA_FILENAME = 'metadata.json' -LEGACY_METADATA_FILENAME = 'METADATA' - - -class Metadata(object): - """ - The metadata of a release. This implementation uses 2.0 (JSON) - metadata where possible. If not possible, it wraps a LegacyMetadata - instance which handles the key-value metadata format. - """ - - METADATA_VERSION_MATCHER = re.compile(r'^\d+(\.\d+)*$') - - NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) - - VERSION_MATCHER = PEP440_VERSION_RE - - SUMMARY_MATCHER = re.compile('.{1,2047}') - - METADATA_VERSION = '2.0' - - GENERATOR = 'distlib (%s)' % __version__ - - MANDATORY_KEYS = { - 'name': (), - 'version': (), - 'summary': ('legacy',), - } - - INDEX_KEYS = ('name version license summary description author ' - 'author_email keywords platform home_page classifiers ' - 'download_url') - - DEPENDENCY_KEYS = ('extras run_requires test_requires build_requires ' - 'dev_requires provides meta_requires obsoleted_by ' - 'supports_environments') - - SYNTAX_VALIDATORS = { - 'metadata_version': (METADATA_VERSION_MATCHER, ()), - 'name': (NAME_MATCHER, ('legacy',)), - 'version': (VERSION_MATCHER, ('legacy',)), - 'summary': (SUMMARY_MATCHER, ('legacy',)), - } - - __slots__ = ('_legacy', '_data', 'scheme') - - def __init__(self, path=None, fileobj=None, mapping=None, - scheme='default'): - if [path, fileobj, mapping].count(None) < 2: - raise TypeError('path, fileobj and mapping are exclusive') - self._legacy = None - self._data = None - self.scheme = scheme - #import pdb; pdb.set_trace() - if mapping is not None: - try: - self._validate_mapping(mapping, scheme) - self._data = mapping - except MetadataUnrecognizedVersionError: - self._legacy = LegacyMetadata(mapping=mapping, scheme=scheme) - self.validate() - else: - data = None - if path: - with open(path, 'rb') as f: - data = f.read() - elif fileobj: - data = fileobj.read() - if data is None: - # Initialised with no args - to be added - self._data = { - 'metadata_version': self.METADATA_VERSION, - 'generator': self.GENERATOR, - } - else: - if not isinstance(data, text_type): - data = data.decode('utf-8') - try: - self._data = json.loads(data) - self._validate_mapping(self._data, scheme) - except ValueError: - # Note: MetadataUnrecognizedVersionError does not - # inherit from ValueError (it's a DistlibException, - # which should not inherit from ValueError). - # The ValueError comes from the json.load - if that - # succeeds and we get a validation error, we want - # that to propagate - self._legacy = LegacyMetadata(fileobj=StringIO(data), - scheme=scheme) - self.validate() - - common_keys = set(('name', 'version', 'license', 'keywords', 'summary')) - - none_list = (None, list) - none_dict = (None, dict) - - mapped_keys = { - 'run_requires': ('Requires-Dist', list), - 'build_requires': ('Setup-Requires-Dist', list), - 'dev_requires': none_list, - 'test_requires': none_list, - 'meta_requires': none_list, - 'extras': ('Provides-Extra', list), - 'modules': none_list, - 'namespaces': none_list, - 'exports': none_dict, - 'commands': none_dict, - 'classifiers': ('Classifier', list), - 'source_url': ('Download-URL', None), - 'metadata_version': ('Metadata-Version', None), - } - - del none_list, none_dict - - def __getattribute__(self, key): - common = object.__getattribute__(self, 'common_keys') - mapped = object.__getattribute__(self, 'mapped_keys') - if key in mapped: - lk, maker = mapped[key] - if self._legacy: - if lk is None: - result = None if maker is None else maker() - else: - result = self._legacy.get(lk) - else: - value = None if maker is None else maker() - if key not in ('commands', 'exports', 'modules', 'namespaces', - 'classifiers'): - result = self._data.get(key, value) - else: - # special cases for PEP 459 - sentinel = object() - result = sentinel - d = self._data.get('extensions') - if d: - if key == 'commands': - result = d.get('python.commands', value) - elif key == 'classifiers': - d = d.get('python.details') - if d: - result = d.get(key, value) - else: - d = d.get('python.exports') - if not d: - d = self._data.get('python.exports') - if d: - result = d.get(key, value) - if result is sentinel: - result = value - elif key not in common: - result = object.__getattribute__(self, key) - elif self._legacy: - result = self._legacy.get(key) - else: - result = self._data.get(key) - return result - - def _validate_value(self, key, value, scheme=None): - if key in self.SYNTAX_VALIDATORS: - pattern, exclusions = self.SYNTAX_VALIDATORS[key] - if (scheme or self.scheme) not in exclusions: - m = pattern.match(value) - if not m: - raise MetadataInvalidError("'%s' is an invalid value for " - "the '%s' property" % (value, - key)) - - def __setattr__(self, key, value): - self._validate_value(key, value) - common = object.__getattribute__(self, 'common_keys') - mapped = object.__getattribute__(self, 'mapped_keys') - if key in mapped: - lk, _ = mapped[key] - if self._legacy: - if lk is None: - raise NotImplementedError - self._legacy[lk] = value - elif key not in ('commands', 'exports', 'modules', 'namespaces', - 'classifiers'): - self._data[key] = value - else: - # special cases for PEP 459 - d = self._data.setdefault('extensions', {}) - if key == 'commands': - d['python.commands'] = value - elif key == 'classifiers': - d = d.setdefault('python.details', {}) - d[key] = value - else: - d = d.setdefault('python.exports', {}) - d[key] = value - elif key not in common: - object.__setattr__(self, key, value) - else: - if key == 'keywords': - if isinstance(value, string_types): - value = value.strip() - if value: - value = value.split() - else: - value = [] - if self._legacy: - self._legacy[key] = value - else: - self._data[key] = value - - @property - def name_and_version(self): - return _get_name_and_version(self.name, self.version, True) - - @property - def provides(self): - if self._legacy: - result = self._legacy['Provides-Dist'] - else: - result = self._data.setdefault('provides', []) - s = '%s (%s)' % (self.name, self.version) - if s not in result: - result.append(s) - return result - - @provides.setter - def provides(self, value): - if self._legacy: - self._legacy['Provides-Dist'] = value - else: - self._data['provides'] = value - - def get_requirements(self, reqts, extras=None, env=None): - """ - Base method to get dependencies, given a set of extras - to satisfy and an optional environment context. - :param reqts: A list of sometimes-wanted dependencies, - perhaps dependent on extras and environment. - :param extras: A list of optional components being requested. - :param env: An optional environment for marker evaluation. - """ - if self._legacy: - result = reqts - else: - result = [] - extras = get_extras(extras or [], self.extras) - for d in reqts: - if 'extra' not in d and 'environment' not in d: - # unconditional - include = True - else: - if 'extra' not in d: - # Not extra-dependent - only environment-dependent - include = True - else: - include = d.get('extra') in extras - if include: - # Not excluded because of extras, check environment - marker = d.get('environment') - if marker: - include = interpret(marker, env) - if include: - result.extend(d['requires']) - for key in ('build', 'dev', 'test'): - e = ':%s:' % key - if e in extras: - extras.remove(e) - # A recursive call, but it should terminate since 'test' - # has been removed from the extras - reqts = self._data.get('%s_requires' % key, []) - result.extend(self.get_requirements(reqts, extras=extras, - env=env)) - return result - - @property - def dictionary(self): - if self._legacy: - return self._from_legacy() - return self._data - - @property - def dependencies(self): - if self._legacy: - raise NotImplementedError - else: - return extract_by_key(self._data, self.DEPENDENCY_KEYS) - - @dependencies.setter - def dependencies(self, value): - if self._legacy: - raise NotImplementedError - else: - self._data.update(value) - - def _validate_mapping(self, mapping, scheme): - if mapping.get('metadata_version') != self.METADATA_VERSION: - raise MetadataUnrecognizedVersionError() - missing = [] - for key, exclusions in self.MANDATORY_KEYS.items(): - if key not in mapping: - if scheme not in exclusions: - missing.append(key) - if missing: - msg = 'Missing metadata items: %s' % ', '.join(missing) - raise MetadataMissingError(msg) - for k, v in mapping.items(): - self._validate_value(k, v, scheme) - - def validate(self): - if self._legacy: - missing, warnings = self._legacy.check(True) - if missing or warnings: - logger.warning('Metadata: missing: %s, warnings: %s', - missing, warnings) - else: - self._validate_mapping(self._data, self.scheme) - - def todict(self): - if self._legacy: - return self._legacy.todict(True) - else: - result = extract_by_key(self._data, self.INDEX_KEYS) - return result - - def _from_legacy(self): - assert self._legacy and not self._data - result = { - 'metadata_version': self.METADATA_VERSION, - 'generator': self.GENERATOR, - } - lmd = self._legacy.todict(True) # skip missing ones - for k in ('name', 'version', 'license', 'summary', 'description', - 'classifier'): - if k in lmd: - if k == 'classifier': - nk = 'classifiers' - else: - nk = k - result[nk] = lmd[k] - kw = lmd.get('Keywords', []) - if kw == ['']: - kw = [] - result['keywords'] = kw - keys = (('requires_dist', 'run_requires'), - ('setup_requires_dist', 'build_requires')) - for ok, nk in keys: - if ok in lmd and lmd[ok]: - result[nk] = [{'requires': lmd[ok]}] - result['provides'] = self.provides - author = {} - maintainer = {} - return result - - LEGACY_MAPPING = { - 'name': 'Name', - 'version': 'Version', - ('extensions', 'python.details', 'license'): 'License', - 'summary': 'Summary', - 'description': 'Description', - ('extensions', 'python.project', 'project_urls', 'Home'): 'Home-page', - ('extensions', 'python.project', 'contacts', 0, 'name'): 'Author', - ('extensions', 'python.project', 'contacts', 0, 'email'): 'Author-email', - 'source_url': 'Download-URL', - ('extensions', 'python.details', 'classifiers'): 'Classifier', - } - - def _to_legacy(self): - def process_entries(entries): - reqts = set() - for e in entries: - extra = e.get('extra') - env = e.get('environment') - rlist = e['requires'] - for r in rlist: - if not env and not extra: - reqts.add(r) - else: - marker = '' - if extra: - marker = 'extra == "%s"' % extra - if env: - if marker: - marker = '(%s) and %s' % (env, marker) - else: - marker = env - reqts.add(';'.join((r, marker))) - return reqts - - assert self._data and not self._legacy - result = LegacyMetadata() - nmd = self._data - # import pdb; pdb.set_trace() - for nk, ok in self.LEGACY_MAPPING.items(): - if not isinstance(nk, tuple): - if nk in nmd: - result[ok] = nmd[nk] - else: - d = nmd - found = True - for k in nk: - try: - d = d[k] - except (KeyError, IndexError): - found = False - break - if found: - result[ok] = d - r1 = process_entries(self.run_requires + self.meta_requires) - r2 = process_entries(self.build_requires + self.dev_requires) - if self.extras: - result['Provides-Extra'] = sorted(self.extras) - result['Requires-Dist'] = sorted(r1) - result['Setup-Requires-Dist'] = sorted(r2) - # TODO: any other fields wanted - return result - - def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True): - if [path, fileobj].count(None) != 1: - raise ValueError('Exactly one of path and fileobj is needed') - self.validate() - if legacy: - if self._legacy: - legacy_md = self._legacy - else: - legacy_md = self._to_legacy() - if path: - legacy_md.write(path, skip_unknown=skip_unknown) - else: - legacy_md.write_file(fileobj, skip_unknown=skip_unknown) - else: - if self._legacy: - d = self._from_legacy() - else: - d = self._data - if fileobj: - json.dump(d, fileobj, ensure_ascii=True, indent=2, - sort_keys=True) - else: - with codecs.open(path, 'w', 'utf-8') as f: - json.dump(d, f, ensure_ascii=True, indent=2, - sort_keys=True) - - def add_requirements(self, requirements): - if self._legacy: - self._legacy.add_requirements(requirements) - else: - run_requires = self._data.setdefault('run_requires', []) - always = None - for entry in run_requires: - if 'environment' not in entry and 'extra' not in entry: - always = entry - break - if always is None: - always = { 'requires': requirements } - run_requires.insert(0, always) - else: - rset = set(always['requires']) | set(requirements) - always['requires'] = sorted(rset) - - def __repr__(self): - name = self.name or '(no name)' - version = self.version or 'no version' - return '<%s %s %s (%s)>' % (self.__class__.__name__, - self.metadata_version, name, version) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/resources.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/resources.py deleted file mode 100644 index fef52aa..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/resources.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2017 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import unicode_literals - -import bisect -import io -import logging -import os -import pkgutil -import sys -import types -import zipimport - -from . import DistlibException -from .util import cached_property, get_cache_base, Cache - -logger = logging.getLogger(__name__) - - -cache = None # created when needed - - -class ResourceCache(Cache): - def __init__(self, base=None): - if base is None: - # Use native string to avoid issues on 2.x: see Python #20140. - base = os.path.join(get_cache_base(), str('resource-cache')) - super(ResourceCache, self).__init__(base) - - def is_stale(self, resource, path): - """ - Is the cache stale for the given resource? - - :param resource: The :class:`Resource` being cached. - :param path: The path of the resource in the cache. - :return: True if the cache is stale. - """ - # Cache invalidation is a hard problem :-) - return True - - def get(self, resource): - """ - Get a resource into the cache, - - :param resource: A :class:`Resource` instance. - :return: The pathname of the resource in the cache. - """ - prefix, path = resource.finder.get_cache_info(resource) - if prefix is None: - result = path - else: - result = os.path.join(self.base, self.prefix_to_dir(prefix), path) - dirname = os.path.dirname(result) - if not os.path.isdir(dirname): - os.makedirs(dirname) - if not os.path.exists(result): - stale = True - else: - stale = self.is_stale(resource, path) - if stale: - # write the bytes of the resource to the cache location - with open(result, 'wb') as f: - f.write(resource.bytes) - return result - - -class ResourceBase(object): - def __init__(self, finder, name): - self.finder = finder - self.name = name - - -class Resource(ResourceBase): - """ - A class representing an in-package resource, such as a data file. This is - not normally instantiated by user code, but rather by a - :class:`ResourceFinder` which manages the resource. - """ - is_container = False # Backwards compatibility - - def as_stream(self): - """ - Get the resource as a stream. - - This is not a property to make it obvious that it returns a new stream - each time. - """ - return self.finder.get_stream(self) - - @cached_property - def file_path(self): - global cache - if cache is None: - cache = ResourceCache() - return cache.get(self) - - @cached_property - def bytes(self): - return self.finder.get_bytes(self) - - @cached_property - def size(self): - return self.finder.get_size(self) - - -class ResourceContainer(ResourceBase): - is_container = True # Backwards compatibility - - @cached_property - def resources(self): - return self.finder.get_resources(self) - - -class ResourceFinder(object): - """ - Resource finder for file system resources. - """ - - if sys.platform.startswith('java'): - skipped_extensions = ('.pyc', '.pyo', '.class') - else: - skipped_extensions = ('.pyc', '.pyo') - - def __init__(self, module): - self.module = module - self.loader = getattr(module, '__loader__', None) - self.base = os.path.dirname(getattr(module, '__file__', '')) - - def _adjust_path(self, path): - return os.path.realpath(path) - - def _make_path(self, resource_name): - # Issue #50: need to preserve type of path on Python 2.x - # like os.path._get_sep - if isinstance(resource_name, bytes): # should only happen on 2.x - sep = b'/' - else: - sep = '/' - parts = resource_name.split(sep) - parts.insert(0, self.base) - result = os.path.join(*parts) - return self._adjust_path(result) - - def _find(self, path): - return os.path.exists(path) - - def get_cache_info(self, resource): - return None, resource.path - - def find(self, resource_name): - path = self._make_path(resource_name) - if not self._find(path): - result = None - else: - if self._is_directory(path): - result = ResourceContainer(self, resource_name) - else: - result = Resource(self, resource_name) - result.path = path - return result - - def get_stream(self, resource): - return open(resource.path, 'rb') - - def get_bytes(self, resource): - with open(resource.path, 'rb') as f: - return f.read() - - def get_size(self, resource): - return os.path.getsize(resource.path) - - def get_resources(self, resource): - def allowed(f): - return (f != '__pycache__' and not - f.endswith(self.skipped_extensions)) - return set([f for f in os.listdir(resource.path) if allowed(f)]) - - def is_container(self, resource): - return self._is_directory(resource.path) - - _is_directory = staticmethod(os.path.isdir) - - def iterator(self, resource_name): - resource = self.find(resource_name) - if resource is not None: - todo = [resource] - while todo: - resource = todo.pop(0) - yield resource - if resource.is_container: - rname = resource.name - for name in resource.resources: - if not rname: - new_name = name - else: - new_name = '/'.join([rname, name]) - child = self.find(new_name) - if child.is_container: - todo.append(child) - else: - yield child - - -class ZipResourceFinder(ResourceFinder): - """ - Resource finder for resources in .zip files. - """ - def __init__(self, module): - super(ZipResourceFinder, self).__init__(module) - archive = self.loader.archive - self.prefix_len = 1 + len(archive) - # PyPy doesn't have a _files attr on zipimporter, and you can't set one - if hasattr(self.loader, '_files'): - self._files = self.loader._files - else: - self._files = zipimport._zip_directory_cache[archive] - self.index = sorted(self._files) - - def _adjust_path(self, path): - return path - - def _find(self, path): - path = path[self.prefix_len:] - if path in self._files: - result = True - else: - if path and path[-1] != os.sep: - path = path + os.sep - i = bisect.bisect(self.index, path) - try: - result = self.index[i].startswith(path) - except IndexError: - result = False - if not result: - logger.debug('_find failed: %r %r', path, self.loader.prefix) - else: - logger.debug('_find worked: %r %r', path, self.loader.prefix) - return result - - def get_cache_info(self, resource): - prefix = self.loader.archive - path = resource.path[1 + len(prefix):] - return prefix, path - - def get_bytes(self, resource): - return self.loader.get_data(resource.path) - - def get_stream(self, resource): - return io.BytesIO(self.get_bytes(resource)) - - def get_size(self, resource): - path = resource.path[self.prefix_len:] - return self._files[path][3] - - def get_resources(self, resource): - path = resource.path[self.prefix_len:] - if path and path[-1] != os.sep: - path += os.sep - plen = len(path) - result = set() - i = bisect.bisect(self.index, path) - while i < len(self.index): - if not self.index[i].startswith(path): - break - s = self.index[i][plen:] - result.add(s.split(os.sep, 1)[0]) # only immediate children - i += 1 - return result - - def _is_directory(self, path): - path = path[self.prefix_len:] - if path and path[-1] != os.sep: - path += os.sep - i = bisect.bisect(self.index, path) - try: - result = self.index[i].startswith(path) - except IndexError: - result = False - return result - - -_finder_registry = { - type(None): ResourceFinder, - zipimport.zipimporter: ZipResourceFinder -} - -try: - # In Python 3.6, _frozen_importlib -> _frozen_importlib_external - try: - import _frozen_importlib_external as _fi - except ImportError: - import _frozen_importlib as _fi - _finder_registry[_fi.SourceFileLoader] = ResourceFinder - _finder_registry[_fi.FileFinder] = ResourceFinder - # See issue #146 - _finder_registry[_fi.SourcelessFileLoader] = ResourceFinder - del _fi -except (ImportError, AttributeError): - pass - - -def register_finder(loader, finder_maker): - _finder_registry[type(loader)] = finder_maker - - -_finder_cache = {} - - -def finder(package): - """ - Return a resource finder for a package. - :param package: The name of the package. - :return: A :class:`ResourceFinder` instance for the package. - """ - if package in _finder_cache: - result = _finder_cache[package] - else: - if package not in sys.modules: - __import__(package) - module = sys.modules[package] - path = getattr(module, '__path__', None) - if path is None: - raise DistlibException('You cannot get a finder for a module, ' - 'only for a package') - loader = getattr(module, '__loader__', None) - finder_maker = _finder_registry.get(type(loader)) - if finder_maker is None: - raise DistlibException('Unable to locate finder for %r' % package) - result = finder_maker(module) - _finder_cache[package] = result - return result - - -_dummy_module = types.ModuleType(str('__dummy__')) - - -def finder_for_path(path): - """ - Return a resource finder for a path, which should represent a container. - - :param path: The path. - :return: A :class:`ResourceFinder` instance for the path. - """ - result = None - # calls any path hooks, gets importer into cache - pkgutil.get_importer(path) - loader = sys.path_importer_cache.get(path) - finder = _finder_registry.get(type(loader)) - if finder: - module = _dummy_module - module.__file__ = os.path.join(path, '') - module.__loader__ = loader - result = finder(module) - return result diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/scripts.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/scripts.py deleted file mode 100644 index 1ac01dd..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/scripts.py +++ /dev/null @@ -1,423 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2015 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from io import BytesIO -import logging -import os -import re -import struct -import sys - -from .compat import sysconfig, detect_encoding, ZipFile -from .resources import finder -from .util import (FileOperator, get_export_entry, convert_path, - get_executable, in_venv) - -logger = logging.getLogger(__name__) - -_DEFAULT_MANIFEST = ''' - - - - - - - - - - - - -'''.strip() - -# check if Python is called on the first line with this expression -FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$') -SCRIPT_TEMPLATE = r'''# -*- coding: utf-8 -*- -import re -import sys -from %(module)s import %(import_name)s -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(%(func)s()) -''' - - -def enquote_executable(executable): - if ' ' in executable: - # make sure we quote only the executable in case of env - # for example /usr/bin/env "/dir with spaces/bin/jython" - # instead of "/usr/bin/env /dir with spaces/bin/jython" - # otherwise whole - if executable.startswith('/usr/bin/env '): - env, _executable = executable.split(' ', 1) - if ' ' in _executable and not _executable.startswith('"'): - executable = '%s "%s"' % (env, _executable) - else: - if not executable.startswith('"'): - executable = '"%s"' % executable - return executable - -# Keep the old name around (for now), as there is at least one project using it! -_enquote_executable = enquote_executable - -class ScriptMaker(object): - """ - A class to copy or create scripts from source scripts or callable - specifications. - """ - script_template = SCRIPT_TEMPLATE - - executable = None # for shebangs - - def __init__(self, source_dir, target_dir, add_launchers=True, - dry_run=False, fileop=None): - self.source_dir = source_dir - self.target_dir = target_dir - self.add_launchers = add_launchers - self.force = False - self.clobber = False - # It only makes sense to set mode bits on POSIX. - self.set_mode = (os.name == 'posix') or (os.name == 'java' and - os._name == 'posix') - self.variants = set(('', 'X.Y')) - self._fileop = fileop or FileOperator(dry_run) - - self._is_nt = os.name == 'nt' or ( - os.name == 'java' and os._name == 'nt') - self.version_info = sys.version_info - - def _get_alternate_executable(self, executable, options): - if options.get('gui', False) and self._is_nt: # pragma: no cover - dn, fn = os.path.split(executable) - fn = fn.replace('python', 'pythonw') - executable = os.path.join(dn, fn) - return executable - - if sys.platform.startswith('java'): # pragma: no cover - def _is_shell(self, executable): - """ - Determine if the specified executable is a script - (contains a #! line) - """ - try: - with open(executable) as fp: - return fp.read(2) == '#!' - except (OSError, IOError): - logger.warning('Failed to open %s', executable) - return False - - def _fix_jython_executable(self, executable): - if self._is_shell(executable): - # Workaround for Jython is not needed on Linux systems. - import java - - if java.lang.System.getProperty('os.name') == 'Linux': - return executable - elif executable.lower().endswith('jython.exe'): - # Use wrapper exe for Jython on Windows - return executable - return '/usr/bin/env %s' % executable - - def _build_shebang(self, executable, post_interp): - """ - Build a shebang line. In the simple case (on Windows, or a shebang line - which is not too long or contains spaces) use a simple formulation for - the shebang. Otherwise, use /bin/sh as the executable, with a contrived - shebang which allows the script to run either under Python or sh, using - suitable quoting. Thanks to Harald Nordgren for his input. - - See also: http://www.in-ulm.de/~mascheck/various/shebang/#length - https://hg.mozilla.org/mozilla-central/file/tip/mach - """ - if os.name != 'posix': - simple_shebang = True - else: - # Add 3 for '#!' prefix and newline suffix. - shebang_length = len(executable) + len(post_interp) + 3 - if sys.platform == 'darwin': - max_shebang_length = 512 - else: - max_shebang_length = 127 - simple_shebang = ((b' ' not in executable) and - (shebang_length <= max_shebang_length)) - - if simple_shebang: - result = b'#!' + executable + post_interp + b'\n' - else: - result = b'#!/bin/sh\n' - result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n' - result += b"' '''" - return result - - def _get_shebang(self, encoding, post_interp=b'', options=None): - enquote = True - if self.executable: - executable = self.executable - enquote = False # assume this will be taken care of - elif not sysconfig.is_python_build(): - executable = get_executable() - elif in_venv(): # pragma: no cover - executable = os.path.join(sysconfig.get_path('scripts'), - 'python%s' % sysconfig.get_config_var('EXE')) - else: # pragma: no cover - executable = os.path.join( - sysconfig.get_config_var('BINDIR'), - 'python%s%s' % (sysconfig.get_config_var('VERSION'), - sysconfig.get_config_var('EXE'))) - if options: - executable = self._get_alternate_executable(executable, options) - - if sys.platform.startswith('java'): # pragma: no cover - executable = self._fix_jython_executable(executable) - - # Normalise case for Windows - COMMENTED OUT - # executable = os.path.normcase(executable) - # N.B. The normalising operation above has been commented out: See - # issue #124. Although paths in Windows are generally case-insensitive, - # they aren't always. For example, a path containing a ẞ (which is a - # LATIN CAPITAL LETTER SHARP S - U+1E9E) is normcased to ß (which is a - # LATIN SMALL LETTER SHARP S' - U+00DF). The two are not considered by - # Windows as equivalent in path names. - - # If the user didn't specify an executable, it may be necessary to - # cater for executable paths with spaces (not uncommon on Windows) - if enquote: - executable = enquote_executable(executable) - # Issue #51: don't use fsencode, since we later try to - # check that the shebang is decodable using utf-8. - executable = executable.encode('utf-8') - # in case of IronPython, play safe and enable frames support - if (sys.platform == 'cli' and '-X:Frames' not in post_interp - and '-X:FullFrames' not in post_interp): # pragma: no cover - post_interp += b' -X:Frames' - shebang = self._build_shebang(executable, post_interp) - # Python parser starts to read a script using UTF-8 until - # it gets a #coding:xxx cookie. The shebang has to be the - # first line of a file, the #coding:xxx cookie cannot be - # written before. So the shebang has to be decodable from - # UTF-8. - try: - shebang.decode('utf-8') - except UnicodeDecodeError: # pragma: no cover - raise ValueError( - 'The shebang (%r) is not decodable from utf-8' % shebang) - # If the script is encoded to a custom encoding (use a - # #coding:xxx cookie), the shebang has to be decodable from - # the script encoding too. - if encoding != 'utf-8': - try: - shebang.decode(encoding) - except UnicodeDecodeError: # pragma: no cover - raise ValueError( - 'The shebang (%r) is not decodable ' - 'from the script encoding (%r)' % (shebang, encoding)) - return shebang - - def _get_script_text(self, entry): - return self.script_template % dict(module=entry.prefix, - import_name=entry.suffix.split('.')[0], - func=entry.suffix) - - manifest = _DEFAULT_MANIFEST - - def get_manifest(self, exename): - base = os.path.basename(exename) - return self.manifest % base - - def _write_script(self, names, shebang, script_bytes, filenames, ext): - use_launcher = self.add_launchers and self._is_nt - linesep = os.linesep.encode('utf-8') - if not shebang.endswith(linesep): - shebang += linesep - if not use_launcher: - script_bytes = shebang + script_bytes - else: # pragma: no cover - if ext == 'py': - launcher = self._get_launcher('t') - else: - launcher = self._get_launcher('w') - stream = BytesIO() - with ZipFile(stream, 'w') as zf: - zf.writestr('__main__.py', script_bytes) - zip_data = stream.getvalue() - script_bytes = launcher + shebang + zip_data - for name in names: - outname = os.path.join(self.target_dir, name) - if use_launcher: # pragma: no cover - n, e = os.path.splitext(outname) - if e.startswith('.py'): - outname = n - outname = '%s.exe' % outname - try: - self._fileop.write_binary_file(outname, script_bytes) - except Exception: - # Failed writing an executable - it might be in use. - logger.warning('Failed to write executable - trying to ' - 'use .deleteme logic') - dfname = '%s.deleteme' % outname - if os.path.exists(dfname): - os.remove(dfname) # Not allowed to fail here - os.rename(outname, dfname) # nor here - self._fileop.write_binary_file(outname, script_bytes) - logger.debug('Able to replace executable using ' - '.deleteme logic') - try: - os.remove(dfname) - except Exception: - pass # still in use - ignore error - else: - if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover - outname = '%s.%s' % (outname, ext) - if os.path.exists(outname) and not self.clobber: - logger.warning('Skipping existing file %s', outname) - continue - self._fileop.write_binary_file(outname, script_bytes) - if self.set_mode: - self._fileop.set_executable_mode([outname]) - filenames.append(outname) - - variant_separator = '-' - - def get_script_filenames(self, name): - result = set() - if '' in self.variants: - result.add(name) - if 'X' in self.variants: - result.add('%s%s' % (name, self.version_info[0])) - if 'X.Y' in self.variants: - result.add('%s%s%s.%s' % (name, self.variant_separator, - self.version_info[0], self.version_info[1])) - return result - - def _make_script(self, entry, filenames, options=None): - post_interp = b'' - if options: - args = options.get('interpreter_args', []) - if args: - args = ' %s' % ' '.join(args) - post_interp = args.encode('utf-8') - shebang = self._get_shebang('utf-8', post_interp, options=options) - script = self._get_script_text(entry).encode('utf-8') - scriptnames = self.get_script_filenames(entry.name) - if options and options.get('gui', False): - ext = 'pyw' - else: - ext = 'py' - self._write_script(scriptnames, shebang, script, filenames, ext) - - def _copy_script(self, script, filenames): - adjust = False - script = os.path.join(self.source_dir, convert_path(script)) - outname = os.path.join(self.target_dir, os.path.basename(script)) - if not self.force and not self._fileop.newer(script, outname): - logger.debug('not copying %s (up-to-date)', script) - return - - # Always open the file, but ignore failures in dry-run mode -- - # that way, we'll get accurate feedback if we can read the - # script. - try: - f = open(script, 'rb') - except IOError: # pragma: no cover - if not self.dry_run: - raise - f = None - else: - first_line = f.readline() - if not first_line: # pragma: no cover - logger.warning('%s is an empty file (skipping)', script) - return - - match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n')) - if match: - adjust = True - post_interp = match.group(1) or b'' - - if not adjust: - if f: - f.close() - self._fileop.copy_file(script, outname) - if self.set_mode: - self._fileop.set_executable_mode([outname]) - filenames.append(outname) - else: - logger.info('copying and adjusting %s -> %s', script, - self.target_dir) - if not self._fileop.dry_run: - encoding, lines = detect_encoding(f.readline) - f.seek(0) - shebang = self._get_shebang(encoding, post_interp) - if b'pythonw' in first_line: # pragma: no cover - ext = 'pyw' - else: - ext = 'py' - n = os.path.basename(outname) - self._write_script([n], shebang, f.read(), filenames, ext) - if f: - f.close() - - @property - def dry_run(self): - return self._fileop.dry_run - - @dry_run.setter - def dry_run(self, value): - self._fileop.dry_run = value - - if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover - # Executable launcher support. - # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/ - - def _get_launcher(self, kind): - if struct.calcsize('P') == 8: # 64-bit - bits = '64' - else: - bits = '32' - name = '%s%s.exe' % (kind, bits) - # Issue 31: don't hardcode an absolute package name, but - # determine it relative to the current package - distlib_package = __name__.rsplit('.', 1)[0] - resource = finder(distlib_package).find(name) - if not resource: - msg = ('Unable to find resource %s in package %s' % (name, - distlib_package)) - raise ValueError(msg) - return resource.bytes - - # Public API follows - - def make(self, specification, options=None): - """ - Make a script. - - :param specification: The specification, which is either a valid export - entry specification (to make a script from a - callable) or a filename (to make a script by - copying from a source location). - :param options: A dictionary of options controlling script generation. - :return: A list of all absolute pathnames written to. - """ - filenames = [] - entry = get_export_entry(specification) - if entry is None: - self._copy_script(specification, filenames) - else: - self._make_script(entry, filenames, options=options) - return filenames - - def make_multiple(self, specifications, options=None): - """ - Take a list of specifications and make scripts from them, - :param specifications: A list of specifications. - :return: A list of all absolute pathnames written to, - """ - filenames = [] - for specification in specifications: - filenames.extend(self.make(specification, options)) - return filenames diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t32.exe b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t32.exe deleted file mode 100644 index 8932a18..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t32.exe and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t64.exe b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t64.exe deleted file mode 100644 index 325b805..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/t64.exe and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/util.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/util.py deleted file mode 100644 index b9e2c69..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/util.py +++ /dev/null @@ -1,1965 +0,0 @@ -# -# Copyright (C) 2012-2021 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import codecs -from collections import deque -import contextlib -import csv -from glob import iglob as std_iglob -import io -import json -import logging -import os -import py_compile -import re -import socket -try: - import ssl -except ImportError: # pragma: no cover - ssl = None -import subprocess -import sys -import tarfile -import tempfile -import textwrap - -try: - import threading -except ImportError: # pragma: no cover - import dummy_threading as threading -import time - -from . import DistlibException -from .compat import (string_types, text_type, shutil, raw_input, StringIO, - cache_from_source, urlopen, urljoin, httplib, xmlrpclib, - splittype, HTTPHandler, BaseConfigurator, valid_ident, - Container, configparser, URLError, ZipFile, fsdecode, - unquote, urlparse) - -logger = logging.getLogger(__name__) - -# -# Requirement parsing code as per PEP 508 -# - -IDENTIFIER = re.compile(r'^([\w\.-]+)\s*') -VERSION_IDENTIFIER = re.compile(r'^([\w\.*+-]+)\s*') -COMPARE_OP = re.compile(r'^(<=?|>=?|={2,3}|[~!]=)\s*') -MARKER_OP = re.compile(r'^((<=?)|(>=?)|={2,3}|[~!]=|in|not\s+in)\s*') -OR = re.compile(r'^or\b\s*') -AND = re.compile(r'^and\b\s*') -NON_SPACE = re.compile(r'(\S+)\s*') -STRING_CHUNK = re.compile(r'([\s\w\.{}()*+#:;,/?!~`@$%^&=|<>\[\]-]+)') - - -def parse_marker(marker_string): - """ - Parse a marker string and return a dictionary containing a marker expression. - - The dictionary will contain keys "op", "lhs" and "rhs" for non-terminals in - the expression grammar, or strings. A string contained in quotes is to be - interpreted as a literal string, and a string not contained in quotes is a - variable (such as os_name). - """ - def marker_var(remaining): - # either identifier, or literal string - m = IDENTIFIER.match(remaining) - if m: - result = m.groups()[0] - remaining = remaining[m.end():] - elif not remaining: - raise SyntaxError('unexpected end of input') - else: - q = remaining[0] - if q not in '\'"': - raise SyntaxError('invalid expression: %s' % remaining) - oq = '\'"'.replace(q, '') - remaining = remaining[1:] - parts = [q] - while remaining: - # either a string chunk, or oq, or q to terminate - if remaining[0] == q: - break - elif remaining[0] == oq: - parts.append(oq) - remaining = remaining[1:] - else: - m = STRING_CHUNK.match(remaining) - if not m: - raise SyntaxError('error in string literal: %s' % remaining) - parts.append(m.groups()[0]) - remaining = remaining[m.end():] - else: - s = ''.join(parts) - raise SyntaxError('unterminated string: %s' % s) - parts.append(q) - result = ''.join(parts) - remaining = remaining[1:].lstrip() # skip past closing quote - return result, remaining - - def marker_expr(remaining): - if remaining and remaining[0] == '(': - result, remaining = marker(remaining[1:].lstrip()) - if remaining[0] != ')': - raise SyntaxError('unterminated parenthesis: %s' % remaining) - remaining = remaining[1:].lstrip() - else: - lhs, remaining = marker_var(remaining) - while remaining: - m = MARKER_OP.match(remaining) - if not m: - break - op = m.groups()[0] - remaining = remaining[m.end():] - rhs, remaining = marker_var(remaining) - lhs = {'op': op, 'lhs': lhs, 'rhs': rhs} - result = lhs - return result, remaining - - def marker_and(remaining): - lhs, remaining = marker_expr(remaining) - while remaining: - m = AND.match(remaining) - if not m: - break - remaining = remaining[m.end():] - rhs, remaining = marker_expr(remaining) - lhs = {'op': 'and', 'lhs': lhs, 'rhs': rhs} - return lhs, remaining - - def marker(remaining): - lhs, remaining = marker_and(remaining) - while remaining: - m = OR.match(remaining) - if not m: - break - remaining = remaining[m.end():] - rhs, remaining = marker_and(remaining) - lhs = {'op': 'or', 'lhs': lhs, 'rhs': rhs} - return lhs, remaining - - return marker(marker_string) - - -def parse_requirement(req): - """ - Parse a requirement passed in as a string. Return a Container - whose attributes contain the various parts of the requirement. - """ - remaining = req.strip() - if not remaining or remaining.startswith('#'): - return None - m = IDENTIFIER.match(remaining) - if not m: - raise SyntaxError('name expected: %s' % remaining) - distname = m.groups()[0] - remaining = remaining[m.end():] - extras = mark_expr = versions = uri = None - if remaining and remaining[0] == '[': - i = remaining.find(']', 1) - if i < 0: - raise SyntaxError('unterminated extra: %s' % remaining) - s = remaining[1:i] - remaining = remaining[i + 1:].lstrip() - extras = [] - while s: - m = IDENTIFIER.match(s) - if not m: - raise SyntaxError('malformed extra: %s' % s) - extras.append(m.groups()[0]) - s = s[m.end():] - if not s: - break - if s[0] != ',': - raise SyntaxError('comma expected in extras: %s' % s) - s = s[1:].lstrip() - if not extras: - extras = None - if remaining: - if remaining[0] == '@': - # it's a URI - remaining = remaining[1:].lstrip() - m = NON_SPACE.match(remaining) - if not m: - raise SyntaxError('invalid URI: %s' % remaining) - uri = m.groups()[0] - t = urlparse(uri) - # there are issues with Python and URL parsing, so this test - # is a bit crude. See bpo-20271, bpo-23505. Python doesn't - # always parse invalid URLs correctly - it should raise - # exceptions for malformed URLs - if not (t.scheme and t.netloc): - raise SyntaxError('Invalid URL: %s' % uri) - remaining = remaining[m.end():].lstrip() - else: - - def get_versions(ver_remaining): - """ - Return a list of operator, version tuples if any are - specified, else None. - """ - m = COMPARE_OP.match(ver_remaining) - versions = None - if m: - versions = [] - while True: - op = m.groups()[0] - ver_remaining = ver_remaining[m.end():] - m = VERSION_IDENTIFIER.match(ver_remaining) - if not m: - raise SyntaxError('invalid version: %s' % ver_remaining) - v = m.groups()[0] - versions.append((op, v)) - ver_remaining = ver_remaining[m.end():] - if not ver_remaining or ver_remaining[0] != ',': - break - ver_remaining = ver_remaining[1:].lstrip() - m = COMPARE_OP.match(ver_remaining) - if not m: - raise SyntaxError('invalid constraint: %s' % ver_remaining) - if not versions: - versions = None - return versions, ver_remaining - - if remaining[0] != '(': - versions, remaining = get_versions(remaining) - else: - i = remaining.find(')', 1) - if i < 0: - raise SyntaxError('unterminated parenthesis: %s' % remaining) - s = remaining[1:i] - remaining = remaining[i + 1:].lstrip() - # As a special diversion from PEP 508, allow a version number - # a.b.c in parentheses as a synonym for ~= a.b.c (because this - # is allowed in earlier PEPs) - if COMPARE_OP.match(s): - versions, _ = get_versions(s) - else: - m = VERSION_IDENTIFIER.match(s) - if not m: - raise SyntaxError('invalid constraint: %s' % s) - v = m.groups()[0] - s = s[m.end():].lstrip() - if s: - raise SyntaxError('invalid constraint: %s' % s) - versions = [('~=', v)] - - if remaining: - if remaining[0] != ';': - raise SyntaxError('invalid requirement: %s' % remaining) - remaining = remaining[1:].lstrip() - - mark_expr, remaining = parse_marker(remaining) - - if remaining and remaining[0] != '#': - raise SyntaxError('unexpected trailing data: %s' % remaining) - - if not versions: - rs = distname - else: - rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions])) - return Container(name=distname, extras=extras, constraints=versions, - marker=mark_expr, url=uri, requirement=rs) - - -def get_resources_dests(resources_root, rules): - """Find destinations for resources files""" - - def get_rel_path(root, path): - # normalizes and returns a lstripped-/-separated path - root = root.replace(os.path.sep, '/') - path = path.replace(os.path.sep, '/') - assert path.startswith(root) - return path[len(root):].lstrip('/') - - destinations = {} - for base, suffix, dest in rules: - prefix = os.path.join(resources_root, base) - for abs_base in iglob(prefix): - abs_glob = os.path.join(abs_base, suffix) - for abs_path in iglob(abs_glob): - resource_file = get_rel_path(resources_root, abs_path) - if dest is None: # remove the entry if it was here - destinations.pop(resource_file, None) - else: - rel_path = get_rel_path(abs_base, abs_path) - rel_dest = dest.replace(os.path.sep, '/').rstrip('/') - destinations[resource_file] = rel_dest + '/' + rel_path - return destinations - - -def in_venv(): - if hasattr(sys, 'real_prefix'): - # virtualenv venvs - result = True - else: - # PEP 405 venvs - result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix) - return result - - -def get_executable(): -# The __PYVENV_LAUNCHER__ dance is apparently no longer needed, as -# changes to the stub launcher mean that sys.executable always points -# to the stub on OS X -# if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__' -# in os.environ): -# result = os.environ['__PYVENV_LAUNCHER__'] -# else: -# result = sys.executable -# return result - # Avoid normcasing: see issue #143 - # result = os.path.normcase(sys.executable) - result = sys.executable - if not isinstance(result, text_type): - result = fsdecode(result) - return result - - -def proceed(prompt, allowed_chars, error_prompt=None, default=None): - p = prompt - while True: - s = raw_input(p) - p = prompt - if not s and default: - s = default - if s: - c = s[0].lower() - if c in allowed_chars: - break - if error_prompt: - p = '%c: %s\n%s' % (c, error_prompt, prompt) - return c - - -def extract_by_key(d, keys): - if isinstance(keys, string_types): - keys = keys.split() - result = {} - for key in keys: - if key in d: - result[key] = d[key] - return result - -def read_exports(stream): - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getreader('utf-8')(stream) - # Try to load as JSON, falling back on legacy format - data = stream.read() - stream = StringIO(data) - try: - jdata = json.load(stream) - result = jdata['extensions']['python.exports']['exports'] - for group, entries in result.items(): - for k, v in entries.items(): - s = '%s = %s' % (k, v) - entry = get_export_entry(s) - assert entry is not None - entries[k] = entry - return result - except Exception: - stream.seek(0, 0) - - def read_stream(cp, stream): - if hasattr(cp, 'read_file'): - cp.read_file(stream) - else: - cp.readfp(stream) - - cp = configparser.ConfigParser() - try: - read_stream(cp, stream) - except configparser.MissingSectionHeaderError: - stream.close() - data = textwrap.dedent(data) - stream = StringIO(data) - read_stream(cp, stream) - - result = {} - for key in cp.sections(): - result[key] = entries = {} - for name, value in cp.items(key): - s = '%s = %s' % (name, value) - entry = get_export_entry(s) - assert entry is not None - #entry.dist = self - entries[name] = entry - return result - - -def write_exports(exports, stream): - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getwriter('utf-8')(stream) - cp = configparser.ConfigParser() - for k, v in exports.items(): - # TODO check k, v for valid values - cp.add_section(k) - for entry in v.values(): - if entry.suffix is None: - s = entry.prefix - else: - s = '%s:%s' % (entry.prefix, entry.suffix) - if entry.flags: - s = '%s [%s]' % (s, ', '.join(entry.flags)) - cp.set(k, entry.name, s) - cp.write(stream) - - -@contextlib.contextmanager -def tempdir(): - td = tempfile.mkdtemp() - try: - yield td - finally: - shutil.rmtree(td) - -@contextlib.contextmanager -def chdir(d): - cwd = os.getcwd() - try: - os.chdir(d) - yield - finally: - os.chdir(cwd) - - -@contextlib.contextmanager -def socket_timeout(seconds=15): - cto = socket.getdefaulttimeout() - try: - socket.setdefaulttimeout(seconds) - yield - finally: - socket.setdefaulttimeout(cto) - - -class cached_property(object): - def __init__(self, func): - self.func = func - #for attr in ('__name__', '__module__', '__doc__'): - # setattr(self, attr, getattr(func, attr, None)) - - def __get__(self, obj, cls=None): - if obj is None: - return self - value = self.func(obj) - object.__setattr__(obj, self.func.__name__, value) - #obj.__dict__[self.func.__name__] = value = self.func(obj) - return value - -def convert_path(pathname): - """Return 'pathname' as a name that will work on the native filesystem. - - The path is split on '/' and put back together again using the current - directory separator. Needed because filenames in the setup script are - always supplied in Unix style, and have to be converted to the local - convention before we can actually use them in the filesystem. Raises - ValueError on non-Unix-ish systems if 'pathname' either starts or - ends with a slash. - """ - if os.sep == '/': - return pathname - if not pathname: - return pathname - if pathname[0] == '/': - raise ValueError("path '%s' cannot be absolute" % pathname) - if pathname[-1] == '/': - raise ValueError("path '%s' cannot end with '/'" % pathname) - - paths = pathname.split('/') - while os.curdir in paths: - paths.remove(os.curdir) - if not paths: - return os.curdir - return os.path.join(*paths) - - -class FileOperator(object): - def __init__(self, dry_run=False): - self.dry_run = dry_run - self.ensured = set() - self._init_record() - - def _init_record(self): - self.record = False - self.files_written = set() - self.dirs_created = set() - - def record_as_written(self, path): - if self.record: - self.files_written.add(path) - - def newer(self, source, target): - """Tell if the target is newer than the source. - - Returns true if 'source' exists and is more recently modified than - 'target', or if 'source' exists and 'target' doesn't. - - Returns false if both exist and 'target' is the same age or younger - than 'source'. Raise PackagingFileError if 'source' does not exist. - - Note that this test is not very accurate: files created in the same - second will have the same "age". - """ - if not os.path.exists(source): - raise DistlibException("file '%r' does not exist" % - os.path.abspath(source)) - if not os.path.exists(target): - return True - - return os.stat(source).st_mtime > os.stat(target).st_mtime - - def copy_file(self, infile, outfile, check=True): - """Copy a file respecting dry-run and force flags. - """ - self.ensure_dir(os.path.dirname(outfile)) - logger.info('Copying %s to %s', infile, outfile) - if not self.dry_run: - msg = None - if check: - if os.path.islink(outfile): - msg = '%s is a symlink' % outfile - elif os.path.exists(outfile) and not os.path.isfile(outfile): - msg = '%s is a non-regular file' % outfile - if msg: - raise ValueError(msg + ' which would be overwritten') - shutil.copyfile(infile, outfile) - self.record_as_written(outfile) - - def copy_stream(self, instream, outfile, encoding=None): - assert not os.path.isdir(outfile) - self.ensure_dir(os.path.dirname(outfile)) - logger.info('Copying stream %s to %s', instream, outfile) - if not self.dry_run: - if encoding is None: - outstream = open(outfile, 'wb') - else: - outstream = codecs.open(outfile, 'w', encoding=encoding) - try: - shutil.copyfileobj(instream, outstream) - finally: - outstream.close() - self.record_as_written(outfile) - - def write_binary_file(self, path, data): - self.ensure_dir(os.path.dirname(path)) - if not self.dry_run: - if os.path.exists(path): - os.remove(path) - with open(path, 'wb') as f: - f.write(data) - self.record_as_written(path) - - def write_text_file(self, path, data, encoding): - self.write_binary_file(path, data.encode(encoding)) - - def set_mode(self, bits, mask, files): - if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'): - # Set the executable bits (owner, group, and world) on - # all the files specified. - for f in files: - if self.dry_run: - logger.info("changing mode of %s", f) - else: - mode = (os.stat(f).st_mode | bits) & mask - logger.info("changing mode of %s to %o", f, mode) - os.chmod(f, mode) - - set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f) - - def ensure_dir(self, path): - path = os.path.abspath(path) - if path not in self.ensured and not os.path.exists(path): - self.ensured.add(path) - d, f = os.path.split(path) - self.ensure_dir(d) - logger.info('Creating %s' % path) - if not self.dry_run: - os.mkdir(path) - if self.record: - self.dirs_created.add(path) - - def byte_compile(self, path, optimize=False, force=False, prefix=None, hashed_invalidation=False): - dpath = cache_from_source(path, not optimize) - logger.info('Byte-compiling %s to %s', path, dpath) - if not self.dry_run: - if force or self.newer(path, dpath): - if not prefix: - diagpath = None - else: - assert path.startswith(prefix) - diagpath = path[len(prefix):] - compile_kwargs = {} - if hashed_invalidation and hasattr(py_compile, 'PycInvalidationMode'): - compile_kwargs['invalidation_mode'] = py_compile.PycInvalidationMode.CHECKED_HASH - py_compile.compile(path, dpath, diagpath, True, **compile_kwargs) # raise error - self.record_as_written(dpath) - return dpath - - def ensure_removed(self, path): - if os.path.exists(path): - if os.path.isdir(path) and not os.path.islink(path): - logger.debug('Removing directory tree at %s', path) - if not self.dry_run: - shutil.rmtree(path) - if self.record: - if path in self.dirs_created: - self.dirs_created.remove(path) - else: - if os.path.islink(path): - s = 'link' - else: - s = 'file' - logger.debug('Removing %s %s', s, path) - if not self.dry_run: - os.remove(path) - if self.record: - if path in self.files_written: - self.files_written.remove(path) - - def is_writable(self, path): - result = False - while not result: - if os.path.exists(path): - result = os.access(path, os.W_OK) - break - parent = os.path.dirname(path) - if parent == path: - break - path = parent - return result - - def commit(self): - """ - Commit recorded changes, turn off recording, return - changes. - """ - assert self.record - result = self.files_written, self.dirs_created - self._init_record() - return result - - def rollback(self): - if not self.dry_run: - for f in list(self.files_written): - if os.path.exists(f): - os.remove(f) - # dirs should all be empty now, except perhaps for - # __pycache__ subdirs - # reverse so that subdirs appear before their parents - dirs = sorted(self.dirs_created, reverse=True) - for d in dirs: - flist = os.listdir(d) - if flist: - assert flist == ['__pycache__'] - sd = os.path.join(d, flist[0]) - os.rmdir(sd) - os.rmdir(d) # should fail if non-empty - self._init_record() - -def resolve(module_name, dotted_path): - if module_name in sys.modules: - mod = sys.modules[module_name] - else: - mod = __import__(module_name) - if dotted_path is None: - result = mod - else: - parts = dotted_path.split('.') - result = getattr(mod, parts.pop(0)) - for p in parts: - result = getattr(result, p) - return result - - -class ExportEntry(object): - def __init__(self, name, prefix, suffix, flags): - self.name = name - self.prefix = prefix - self.suffix = suffix - self.flags = flags - - @cached_property - def value(self): - return resolve(self.prefix, self.suffix) - - def __repr__(self): # pragma: no cover - return '' % (self.name, self.prefix, - self.suffix, self.flags) - - def __eq__(self, other): - if not isinstance(other, ExportEntry): - result = False - else: - result = (self.name == other.name and - self.prefix == other.prefix and - self.suffix == other.suffix and - self.flags == other.flags) - return result - - __hash__ = object.__hash__ - - -ENTRY_RE = re.compile(r'''(?P(\w|[-.+])+) - \s*=\s*(?P(\w+)([:\.]\w+)*) - \s*(\[\s*(?P[\w-]+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])? - ''', re.VERBOSE) - -def get_export_entry(specification): - m = ENTRY_RE.search(specification) - if not m: - result = None - if '[' in specification or ']' in specification: - raise DistlibException("Invalid specification " - "'%s'" % specification) - else: - d = m.groupdict() - name = d['name'] - path = d['callable'] - colons = path.count(':') - if colons == 0: - prefix, suffix = path, None - else: - if colons != 1: - raise DistlibException("Invalid specification " - "'%s'" % specification) - prefix, suffix = path.split(':') - flags = d['flags'] - if flags is None: - if '[' in specification or ']' in specification: - raise DistlibException("Invalid specification " - "'%s'" % specification) - flags = [] - else: - flags = [f.strip() for f in flags.split(',')] - result = ExportEntry(name, prefix, suffix, flags) - return result - - -def get_cache_base(suffix=None): - """ - Return the default base location for distlib caches. If the directory does - not exist, it is created. Use the suffix provided for the base directory, - and default to '.distlib' if it isn't provided. - - On Windows, if LOCALAPPDATA is defined in the environment, then it is - assumed to be a directory, and will be the parent directory of the result. - On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home - directory - using os.expanduser('~') - will be the parent directory of - the result. - - The result is just the directory '.distlib' in the parent directory as - determined above, or with the name specified with ``suffix``. - """ - if suffix is None: - suffix = '.distlib' - if os.name == 'nt' and 'LOCALAPPDATA' in os.environ: - result = os.path.expandvars('$localappdata') - else: - # Assume posix, or old Windows - result = os.path.expanduser('~') - # we use 'isdir' instead of 'exists', because we want to - # fail if there's a file with that name - if os.path.isdir(result): - usable = os.access(result, os.W_OK) - if not usable: - logger.warning('Directory exists but is not writable: %s', result) - else: - try: - os.makedirs(result) - usable = True - except OSError: - logger.warning('Unable to create %s', result, exc_info=True) - usable = False - if not usable: - result = tempfile.mkdtemp() - logger.warning('Default location unusable, using %s', result) - return os.path.join(result, suffix) - - -def path_to_cache_dir(path): - """ - Convert an absolute path to a directory name for use in a cache. - - The algorithm used is: - - #. On Windows, any ``':'`` in the drive is replaced with ``'---'``. - #. Any occurrence of ``os.sep`` is replaced with ``'--'``. - #. ``'.cache'`` is appended. - """ - d, p = os.path.splitdrive(os.path.abspath(path)) - if d: - d = d.replace(':', '---') - p = p.replace(os.sep, '--') - return d + p + '.cache' - - -def ensure_slash(s): - if not s.endswith('/'): - return s + '/' - return s - - -def parse_credentials(netloc): - username = password = None - if '@' in netloc: - prefix, netloc = netloc.rsplit('@', 1) - if ':' not in prefix: - username = prefix - else: - username, password = prefix.split(':', 1) - if username: - username = unquote(username) - if password: - password = unquote(password) - return username, password, netloc - - -def get_process_umask(): - result = os.umask(0o22) - os.umask(result) - return result - -def is_string_sequence(seq): - result = True - i = None - for i, s in enumerate(seq): - if not isinstance(s, string_types): - result = False - break - assert i is not None - return result - -PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-' - '([a-z0-9_.+-]+)', re.I) -PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)') - - -def split_filename(filename, project_name=None): - """ - Extract name, version, python version from a filename (no extension) - - Return name, version, pyver or None - """ - result = None - pyver = None - filename = unquote(filename).replace(' ', '-') - m = PYTHON_VERSION.search(filename) - if m: - pyver = m.group(1) - filename = filename[:m.start()] - if project_name and len(filename) > len(project_name) + 1: - m = re.match(re.escape(project_name) + r'\b', filename) - if m: - n = m.end() - result = filename[:n], filename[n + 1:], pyver - if result is None: - m = PROJECT_NAME_AND_VERSION.match(filename) - if m: - result = m.group(1), m.group(3), pyver - return result - -# Allow spaces in name because of legacy dists like "Twisted Core" -NAME_VERSION_RE = re.compile(r'(?P[\w .-]+)\s*' - r'\(\s*(?P[^\s)]+)\)$') - -def parse_name_and_version(p): - """ - A utility method used to get name and version from a string. - - From e.g. a Provides-Dist value. - - :param p: A value in a form 'foo (1.0)' - :return: The name and version as a tuple. - """ - m = NAME_VERSION_RE.match(p) - if not m: - raise DistlibException('Ill-formed name/version string: \'%s\'' % p) - d = m.groupdict() - return d['name'].strip().lower(), d['ver'] - -def get_extras(requested, available): - result = set() - requested = set(requested or []) - available = set(available or []) - if '*' in requested: - requested.remove('*') - result |= available - for r in requested: - if r == '-': - result.add(r) - elif r.startswith('-'): - unwanted = r[1:] - if unwanted not in available: - logger.warning('undeclared extra: %s' % unwanted) - if unwanted in result: - result.remove(unwanted) - else: - if r not in available: - logger.warning('undeclared extra: %s' % r) - result.add(r) - return result -# -# Extended metadata functionality -# - -def _get_external_data(url): - result = {} - try: - # urlopen might fail if it runs into redirections, - # because of Python issue #13696. Fixed in locators - # using a custom redirect handler. - resp = urlopen(url) - headers = resp.info() - ct = headers.get('Content-Type') - if not ct.startswith('application/json'): - logger.debug('Unexpected response for JSON request: %s', ct) - else: - reader = codecs.getreader('utf-8')(resp) - #data = reader.read().decode('utf-8') - #result = json.loads(data) - result = json.load(reader) - except Exception as e: - logger.exception('Failed to get external data for %s: %s', url, e) - return result - -_external_data_base_url = 'https://www.red-dove.com/pypi/projects/' - -def get_project_data(name): - url = '%s/%s/project.json' % (name[0].upper(), name) - url = urljoin(_external_data_base_url, url) - result = _get_external_data(url) - return result - -def get_package_data(name, version): - url = '%s/%s/package-%s.json' % (name[0].upper(), name, version) - url = urljoin(_external_data_base_url, url) - return _get_external_data(url) - - -class Cache(object): - """ - A class implementing a cache for resources that need to live in the file system - e.g. shared libraries. This class was moved from resources to here because it - could be used by other modules, e.g. the wheel module. - """ - - def __init__(self, base): - """ - Initialise an instance. - - :param base: The base directory where the cache should be located. - """ - # we use 'isdir' instead of 'exists', because we want to - # fail if there's a file with that name - if not os.path.isdir(base): # pragma: no cover - os.makedirs(base) - if (os.stat(base).st_mode & 0o77) != 0: - logger.warning('Directory \'%s\' is not private', base) - self.base = os.path.abspath(os.path.normpath(base)) - - def prefix_to_dir(self, prefix): - """ - Converts a resource prefix to a directory name in the cache. - """ - return path_to_cache_dir(prefix) - - def clear(self): - """ - Clear the cache. - """ - not_removed = [] - for fn in os.listdir(self.base): - fn = os.path.join(self.base, fn) - try: - if os.path.islink(fn) or os.path.isfile(fn): - os.remove(fn) - elif os.path.isdir(fn): - shutil.rmtree(fn) - except Exception: - not_removed.append(fn) - return not_removed - - -class EventMixin(object): - """ - A very simple publish/subscribe system. - """ - def __init__(self): - self._subscribers = {} - - def add(self, event, subscriber, append=True): - """ - Add a subscriber for an event. - - :param event: The name of an event. - :param subscriber: The subscriber to be added (and called when the - event is published). - :param append: Whether to append or prepend the subscriber to an - existing subscriber list for the event. - """ - subs = self._subscribers - if event not in subs: - subs[event] = deque([subscriber]) - else: - sq = subs[event] - if append: - sq.append(subscriber) - else: - sq.appendleft(subscriber) - - def remove(self, event, subscriber): - """ - Remove a subscriber for an event. - - :param event: The name of an event. - :param subscriber: The subscriber to be removed. - """ - subs = self._subscribers - if event not in subs: - raise ValueError('No subscribers: %r' % event) - subs[event].remove(subscriber) - - def get_subscribers(self, event): - """ - Return an iterator for the subscribers for an event. - :param event: The event to return subscribers for. - """ - return iter(self._subscribers.get(event, ())) - - def publish(self, event, *args, **kwargs): - """ - Publish a event and return a list of values returned by its - subscribers. - - :param event: The event to publish. - :param args: The positional arguments to pass to the event's - subscribers. - :param kwargs: The keyword arguments to pass to the event's - subscribers. - """ - result = [] - for subscriber in self.get_subscribers(event): - try: - value = subscriber(event, *args, **kwargs) - except Exception: - logger.exception('Exception during event publication') - value = None - result.append(value) - logger.debug('publish %s: args = %s, kwargs = %s, result = %s', - event, args, kwargs, result) - return result - -# -# Simple sequencing -# -class Sequencer(object): - def __init__(self): - self._preds = {} - self._succs = {} - self._nodes = set() # nodes with no preds/succs - - def add_node(self, node): - self._nodes.add(node) - - def remove_node(self, node, edges=False): - if node in self._nodes: - self._nodes.remove(node) - if edges: - for p in set(self._preds.get(node, ())): - self.remove(p, node) - for s in set(self._succs.get(node, ())): - self.remove(node, s) - # Remove empties - for k, v in list(self._preds.items()): - if not v: - del self._preds[k] - for k, v in list(self._succs.items()): - if not v: - del self._succs[k] - - def add(self, pred, succ): - assert pred != succ - self._preds.setdefault(succ, set()).add(pred) - self._succs.setdefault(pred, set()).add(succ) - - def remove(self, pred, succ): - assert pred != succ - try: - preds = self._preds[succ] - succs = self._succs[pred] - except KeyError: # pragma: no cover - raise ValueError('%r not a successor of anything' % succ) - try: - preds.remove(pred) - succs.remove(succ) - except KeyError: # pragma: no cover - raise ValueError('%r not a successor of %r' % (succ, pred)) - - def is_step(self, step): - return (step in self._preds or step in self._succs or - step in self._nodes) - - def get_steps(self, final): - if not self.is_step(final): - raise ValueError('Unknown: %r' % final) - result = [] - todo = [] - seen = set() - todo.append(final) - while todo: - step = todo.pop(0) - if step in seen: - # if a step was already seen, - # move it to the end (so it will appear earlier - # when reversed on return) ... but not for the - # final step, as that would be confusing for - # users - if step != final: - result.remove(step) - result.append(step) - else: - seen.add(step) - result.append(step) - preds = self._preds.get(step, ()) - todo.extend(preds) - return reversed(result) - - @property - def strong_connections(self): - #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm - index_counter = [0] - stack = [] - lowlinks = {} - index = {} - result = [] - - graph = self._succs - - def strongconnect(node): - # set the depth index for this node to the smallest unused index - index[node] = index_counter[0] - lowlinks[node] = index_counter[0] - index_counter[0] += 1 - stack.append(node) - - # Consider successors - try: - successors = graph[node] - except Exception: - successors = [] - for successor in successors: - if successor not in lowlinks: - # Successor has not yet been visited - strongconnect(successor) - lowlinks[node] = min(lowlinks[node],lowlinks[successor]) - elif successor in stack: - # the successor is in the stack and hence in the current - # strongly connected component (SCC) - lowlinks[node] = min(lowlinks[node],index[successor]) - - # If `node` is a root node, pop the stack and generate an SCC - if lowlinks[node] == index[node]: - connected_component = [] - - while True: - successor = stack.pop() - connected_component.append(successor) - if successor == node: break - component = tuple(connected_component) - # storing the result - result.append(component) - - for node in graph: - if node not in lowlinks: - strongconnect(node) - - return result - - @property - def dot(self): - result = ['digraph G {'] - for succ in self._preds: - preds = self._preds[succ] - for pred in preds: - result.append(' %s -> %s;' % (pred, succ)) - for node in self._nodes: - result.append(' %s;' % node) - result.append('}') - return '\n'.join(result) - -# -# Unarchiving functionality for zip, tar, tgz, tbz, whl -# - -ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', - '.tgz', '.tbz', '.whl') - -def unarchive(archive_filename, dest_dir, format=None, check=True): - - def check_path(path): - if not isinstance(path, text_type): - path = path.decode('utf-8') - p = os.path.abspath(os.path.join(dest_dir, path)) - if not p.startswith(dest_dir) or p[plen] != os.sep: - raise ValueError('path outside destination: %r' % p) - - dest_dir = os.path.abspath(dest_dir) - plen = len(dest_dir) - archive = None - if format is None: - if archive_filename.endswith(('.zip', '.whl')): - format = 'zip' - elif archive_filename.endswith(('.tar.gz', '.tgz')): - format = 'tgz' - mode = 'r:gz' - elif archive_filename.endswith(('.tar.bz2', '.tbz')): - format = 'tbz' - mode = 'r:bz2' - elif archive_filename.endswith('.tar'): - format = 'tar' - mode = 'r' - else: # pragma: no cover - raise ValueError('Unknown format for %r' % archive_filename) - try: - if format == 'zip': - archive = ZipFile(archive_filename, 'r') - if check: - names = archive.namelist() - for name in names: - check_path(name) - else: - archive = tarfile.open(archive_filename, mode) - if check: - names = archive.getnames() - for name in names: - check_path(name) - if format != 'zip' and sys.version_info[0] < 3: - # See Python issue 17153. If the dest path contains Unicode, - # tarfile extraction fails on Python 2.x if a member path name - # contains non-ASCII characters - it leads to an implicit - # bytes -> unicode conversion using ASCII to decode. - for tarinfo in archive.getmembers(): - if not isinstance(tarinfo.name, text_type): - tarinfo.name = tarinfo.name.decode('utf-8') - archive.extractall(dest_dir) - - finally: - if archive: - archive.close() - - -def zip_dir(directory): - """zip a directory tree into a BytesIO object""" - result = io.BytesIO() - dlen = len(directory) - with ZipFile(result, "w") as zf: - for root, dirs, files in os.walk(directory): - for name in files: - full = os.path.join(root, name) - rel = root[dlen:] - dest = os.path.join(rel, name) - zf.write(full, dest) - return result - -# -# Simple progress bar -# - -UNITS = ('', 'K', 'M', 'G','T','P') - - -class Progress(object): - unknown = 'UNKNOWN' - - def __init__(self, minval=0, maxval=100): - assert maxval is None or maxval >= minval - self.min = self.cur = minval - self.max = maxval - self.started = None - self.elapsed = 0 - self.done = False - - def update(self, curval): - assert self.min <= curval - assert self.max is None or curval <= self.max - self.cur = curval - now = time.time() - if self.started is None: - self.started = now - else: - self.elapsed = now - self.started - - def increment(self, incr): - assert incr >= 0 - self.update(self.cur + incr) - - def start(self): - self.update(self.min) - return self - - def stop(self): - if self.max is not None: - self.update(self.max) - self.done = True - - @property - def maximum(self): - return self.unknown if self.max is None else self.max - - @property - def percentage(self): - if self.done: - result = '100 %' - elif self.max is None: - result = ' ?? %' - else: - v = 100.0 * (self.cur - self.min) / (self.max - self.min) - result = '%3d %%' % v - return result - - def format_duration(self, duration): - if (duration <= 0) and self.max is None or self.cur == self.min: - result = '??:??:??' - #elif duration < 1: - # result = '--:--:--' - else: - result = time.strftime('%H:%M:%S', time.gmtime(duration)) - return result - - @property - def ETA(self): - if self.done: - prefix = 'Done' - t = self.elapsed - #import pdb; pdb.set_trace() - else: - prefix = 'ETA ' - if self.max is None: - t = -1 - elif self.elapsed == 0 or (self.cur == self.min): - t = 0 - else: - #import pdb; pdb.set_trace() - t = float(self.max - self.min) - t /= self.cur - self.min - t = (t - 1) * self.elapsed - return '%s: %s' % (prefix, self.format_duration(t)) - - @property - def speed(self): - if self.elapsed == 0: - result = 0.0 - else: - result = (self.cur - self.min) / self.elapsed - for unit in UNITS: - if result < 1000: - break - result /= 1000.0 - return '%d %sB/s' % (result, unit) - -# -# Glob functionality -# - -RICH_GLOB = re.compile(r'\{([^}]*)\}') -_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]') -_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$') - - -def iglob(path_glob): - """Extended globbing function that supports ** and {opt1,opt2,opt3}.""" - if _CHECK_RECURSIVE_GLOB.search(path_glob): - msg = """invalid glob %r: recursive glob "**" must be used alone""" - raise ValueError(msg % path_glob) - if _CHECK_MISMATCH_SET.search(path_glob): - msg = """invalid glob %r: mismatching set marker '{' or '}'""" - raise ValueError(msg % path_glob) - return _iglob(path_glob) - - -def _iglob(path_glob): - rich_path_glob = RICH_GLOB.split(path_glob, 1) - if len(rich_path_glob) > 1: - assert len(rich_path_glob) == 3, rich_path_glob - prefix, set, suffix = rich_path_glob - for item in set.split(','): - for path in _iglob(''.join((prefix, item, suffix))): - yield path - else: - if '**' not in path_glob: - for item in std_iglob(path_glob): - yield item - else: - prefix, radical = path_glob.split('**', 1) - if prefix == '': - prefix = '.' - if radical == '': - radical = '*' - else: - # we support both - radical = radical.lstrip('/') - radical = radical.lstrip('\\') - for path, dir, files in os.walk(prefix): - path = os.path.normpath(path) - for fn in _iglob(os.path.join(path, radical)): - yield fn - -if ssl: - from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname, - CertificateError) - - -# -# HTTPSConnection which verifies certificates/matches domains -# - - class HTTPSConnection(httplib.HTTPSConnection): - ca_certs = None # set this to the path to the certs file (.pem) - check_domain = True # only used if ca_certs is not None - - # noinspection PyPropertyAccess - def connect(self): - sock = socket.create_connection((self.host, self.port), self.timeout) - if getattr(self, '_tunnel_host', False): - self.sock = sock - self._tunnel() - - if not hasattr(ssl, 'SSLContext'): - # For 2.x - if self.ca_certs: - cert_reqs = ssl.CERT_REQUIRED - else: - cert_reqs = ssl.CERT_NONE - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, - cert_reqs=cert_reqs, - ssl_version=ssl.PROTOCOL_SSLv23, - ca_certs=self.ca_certs) - else: # pragma: no cover - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - if hasattr(ssl, 'OP_NO_SSLv2'): - context.options |= ssl.OP_NO_SSLv2 - if self.cert_file: - context.load_cert_chain(self.cert_file, self.key_file) - kwargs = {} - if self.ca_certs: - context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(cafile=self.ca_certs) - if getattr(ssl, 'HAS_SNI', False): - kwargs['server_hostname'] = self.host - self.sock = context.wrap_socket(sock, **kwargs) - if self.ca_certs and self.check_domain: - try: - match_hostname(self.sock.getpeercert(), self.host) - logger.debug('Host verified: %s', self.host) - except CertificateError: # pragma: no cover - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - raise - - class HTTPSHandler(BaseHTTPSHandler): - def __init__(self, ca_certs, check_domain=True): - BaseHTTPSHandler.__init__(self) - self.ca_certs = ca_certs - self.check_domain = check_domain - - def _conn_maker(self, *args, **kwargs): - """ - This is called to create a connection instance. Normally you'd - pass a connection class to do_open, but it doesn't actually check for - a class, and just expects a callable. As long as we behave just as a - constructor would have, we should be OK. If it ever changes so that - we *must* pass a class, we'll create an UnsafeHTTPSConnection class - which just sets check_domain to False in the class definition, and - choose which one to pass to do_open. - """ - result = HTTPSConnection(*args, **kwargs) - if self.ca_certs: - result.ca_certs = self.ca_certs - result.check_domain = self.check_domain - return result - - def https_open(self, req): - try: - return self.do_open(self._conn_maker, req) - except URLError as e: - if 'certificate verify failed' in str(e.reason): - raise CertificateError('Unable to verify server certificate ' - 'for %s' % req.host) - else: - raise - - # - # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The- - # Middle proxy using HTTP listens on port 443, or an index mistakenly serves - # HTML containing a http://xyz link when it should be https://xyz), - # you can use the following handler class, which does not allow HTTP traffic. - # - # It works by inheriting from HTTPHandler - so build_opener won't add a - # handler for HTTP itself. - # - class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler): - def http_open(self, req): - raise URLError('Unexpected HTTP request on what should be a secure ' - 'connection: %s' % req) - -# -# XML-RPC with timeouts -# - -_ver_info = sys.version_info[:2] - -if _ver_info == (2, 6): - class HTTP(httplib.HTTP): - def __init__(self, host='', port=None, **kwargs): - if port == 0: # 0 means use port 0, not the default port - port = None - self._setup(self._connection_class(host, port, **kwargs)) - - - if ssl: - class HTTPS(httplib.HTTPS): - def __init__(self, host='', port=None, **kwargs): - if port == 0: # 0 means use port 0, not the default port - port = None - self._setup(self._connection_class(host, port, **kwargs)) - - -class Transport(xmlrpclib.Transport): - def __init__(self, timeout, use_datetime=0): - self.timeout = timeout - xmlrpclib.Transport.__init__(self, use_datetime) - - def make_connection(self, host): - h, eh, x509 = self.get_host_info(host) - if _ver_info == (2, 6): - result = HTTP(h, timeout=self.timeout) - else: - if not self._connection or host != self._connection[0]: - self._extra_headers = eh - self._connection = host, httplib.HTTPConnection(h) - result = self._connection[1] - return result - -if ssl: - class SafeTransport(xmlrpclib.SafeTransport): - def __init__(self, timeout, use_datetime=0): - self.timeout = timeout - xmlrpclib.SafeTransport.__init__(self, use_datetime) - - def make_connection(self, host): - h, eh, kwargs = self.get_host_info(host) - if not kwargs: - kwargs = {} - kwargs['timeout'] = self.timeout - if _ver_info == (2, 6): - result = HTTPS(host, None, **kwargs) - else: - if not self._connection or host != self._connection[0]: - self._extra_headers = eh - self._connection = host, httplib.HTTPSConnection(h, None, - **kwargs) - result = self._connection[1] - return result - - -class ServerProxy(xmlrpclib.ServerProxy): - def __init__(self, uri, **kwargs): - self.timeout = timeout = kwargs.pop('timeout', None) - # The above classes only come into play if a timeout - # is specified - if timeout is not None: - # scheme = splittype(uri) # deprecated as of Python 3.8 - scheme = urlparse(uri)[0] - use_datetime = kwargs.get('use_datetime', 0) - if scheme == 'https': - tcls = SafeTransport - else: - tcls = Transport - kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime) - self.transport = t - xmlrpclib.ServerProxy.__init__(self, uri, **kwargs) - -# -# CSV functionality. This is provided because on 2.x, the csv module can't -# handle Unicode. However, we need to deal with Unicode in e.g. RECORD files. -# - -def _csv_open(fn, mode, **kwargs): - if sys.version_info[0] < 3: - mode += 'b' - else: - kwargs['newline'] = '' - # Python 3 determines encoding from locale. Force 'utf-8' - # file encoding to match other forced utf-8 encoding - kwargs['encoding'] = 'utf-8' - return open(fn, mode, **kwargs) - - -class CSVBase(object): - defaults = { - 'delimiter': str(','), # The strs are used because we need native - 'quotechar': str('"'), # str in the csv API (2.x won't take - 'lineterminator': str('\n') # Unicode) - } - - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.stream.close() - - -class CSVReader(CSVBase): - def __init__(self, **kwargs): - if 'stream' in kwargs: - stream = kwargs['stream'] - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getreader('utf-8')(stream) - self.stream = stream - else: - self.stream = _csv_open(kwargs['path'], 'r') - self.reader = csv.reader(self.stream, **self.defaults) - - def __iter__(self): - return self - - def next(self): - result = next(self.reader) - if sys.version_info[0] < 3: - for i, item in enumerate(result): - if not isinstance(item, text_type): - result[i] = item.decode('utf-8') - return result - - __next__ = next - -class CSVWriter(CSVBase): - def __init__(self, fn, **kwargs): - self.stream = _csv_open(fn, 'w') - self.writer = csv.writer(self.stream, **self.defaults) - - def writerow(self, row): - if sys.version_info[0] < 3: - r = [] - for item in row: - if isinstance(item, text_type): - item = item.encode('utf-8') - r.append(item) - row = r - self.writer.writerow(row) - -# -# Configurator functionality -# - -class Configurator(BaseConfigurator): - - value_converters = dict(BaseConfigurator.value_converters) - value_converters['inc'] = 'inc_convert' - - def __init__(self, config, base=None): - super(Configurator, self).__init__(config) - self.base = base or os.getcwd() - - def configure_custom(self, config): - def convert(o): - if isinstance(o, (list, tuple)): - result = type(o)([convert(i) for i in o]) - elif isinstance(o, dict): - if '()' in o: - result = self.configure_custom(o) - else: - result = {} - for k in o: - result[k] = convert(o[k]) - else: - result = self.convert(o) - return result - - c = config.pop('()') - if not callable(c): - c = self.resolve(c) - props = config.pop('.', None) - # Check for valid identifiers - args = config.pop('[]', ()) - if args: - args = tuple([convert(o) for o in args]) - items = [(k, convert(config[k])) for k in config if valid_ident(k)] - kwargs = dict(items) - result = c(*args, **kwargs) - if props: - for n, v in props.items(): - setattr(result, n, convert(v)) - return result - - def __getitem__(self, key): - result = self.config[key] - if isinstance(result, dict) and '()' in result: - self.config[key] = result = self.configure_custom(result) - return result - - def inc_convert(self, value): - """Default converter for the inc:// protocol.""" - if not os.path.isabs(value): - value = os.path.join(self.base, value) - with codecs.open(value, 'r', encoding='utf-8') as f: - result = json.load(f) - return result - - -class SubprocessMixin(object): - """ - Mixin for running subprocesses and capturing their output - """ - def __init__(self, verbose=False, progress=None): - self.verbose = verbose - self.progress = progress - - def reader(self, stream, context): - """ - Read lines from a subprocess' output stream and either pass to a progress - callable (if specified) or write progress information to sys.stderr. - """ - progress = self.progress - verbose = self.verbose - while True: - s = stream.readline() - if not s: - break - if progress is not None: - progress(s, context) - else: - if not verbose: - sys.stderr.write('.') - else: - sys.stderr.write(s.decode('utf-8')) - sys.stderr.flush() - stream.close() - - def run_command(self, cmd, **kwargs): - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, **kwargs) - t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout')) - t1.start() - t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr')) - t2.start() - p.wait() - t1.join() - t2.join() - if self.progress is not None: - self.progress('done.', 'main') - elif self.verbose: - sys.stderr.write('done.\n') - return p - - -def normalize_name(name): - """Normalize a python package name a la PEP 503""" - # https://www.python.org/dev/peps/pep-0503/#normalized-names - return re.sub('[-_.]+', '-', name).lower() - -# def _get_pypirc_command(): - # """ - # Get the distutils command for interacting with PyPI configurations. - # :return: the command. - # """ - # from distutils.core import Distribution - # from distutils.config import PyPIRCCommand - # d = Distribution() - # return PyPIRCCommand(d) - -class PyPIRCFile(object): - - DEFAULT_REPOSITORY = 'https://upload.pypi.org/legacy/' - DEFAULT_REALM = 'pypi' - - def __init__(self, fn=None, url=None): - if fn is None: - fn = os.path.join(os.path.expanduser('~'), '.pypirc') - self.filename = fn - self.url = url - - def read(self): - result = {} - - if os.path.exists(self.filename): - repository = self.url or self.DEFAULT_REPOSITORY - - config = configparser.RawConfigParser() - config.read(self.filename) - sections = config.sections() - if 'distutils' in sections: - # let's get the list of servers - index_servers = config.get('distutils', 'index-servers') - _servers = [server.strip() for server in - index_servers.split('\n') - if server.strip() != ''] - if _servers == []: - # nothing set, let's try to get the default pypi - if 'pypi' in sections: - _servers = ['pypi'] - else: - for server in _servers: - result = {'server': server} - result['username'] = config.get(server, 'username') - - # optional params - for key, default in (('repository', self.DEFAULT_REPOSITORY), - ('realm', self.DEFAULT_REALM), - ('password', None)): - if config.has_option(server, key): - result[key] = config.get(server, key) - else: - result[key] = default - - # work around people having "repository" for the "pypi" - # section of their config set to the HTTP (rather than - # HTTPS) URL - if (server == 'pypi' and - repository in (self.DEFAULT_REPOSITORY, 'pypi')): - result['repository'] = self.DEFAULT_REPOSITORY - elif (result['server'] != repository and - result['repository'] != repository): - result = {} - elif 'server-login' in sections: - # old format - server = 'server-login' - if config.has_option(server, 'repository'): - repository = config.get(server, 'repository') - else: - repository = self.DEFAULT_REPOSITORY - result = { - 'username': config.get(server, 'username'), - 'password': config.get(server, 'password'), - 'repository': repository, - 'server': server, - 'realm': self.DEFAULT_REALM - } - return result - - def update(self, username, password): - # import pdb; pdb.set_trace() - config = configparser.RawConfigParser() - fn = self.filename - config.read(fn) - if not config.has_section('pypi'): - config.add_section('pypi') - config.set('pypi', 'username', username) - config.set('pypi', 'password', password) - with open(fn, 'w') as f: - config.write(f) - -def _load_pypirc(index): - """ - Read the PyPI access configuration as supported by distutils. - """ - return PyPIRCFile(url=index.url).read() - -def _store_pypirc(index): - PyPIRCFile().update(index.username, index.password) - -# -# get_platform()/get_host_platform() copied from Python 3.10.a0 source, with some minor -# tweaks -# - -def get_host_platform(): - """Return a string that identifies the current platform. This is used mainly to - distinguish platform-specific build directories and platform-specific built - distributions. Typically includes the OS name and version and the - architecture (as supplied by 'os.uname()'), although the exact information - included depends on the OS; eg. on Linux, the kernel version isn't - particularly important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - - """ - if os.name == 'nt': - if 'amd64' in sys.version.lower(): - return 'win-amd64' - if '(arm)' in sys.version.lower(): - return 'win-arm32' - if '(arm64)' in sys.version.lower(): - return 'win-arm64' - return sys.platform - - # Set for cross builds explicitly - if "_PYTHON_HOST_PLATFORM" in os.environ: - return os.environ["_PYTHON_HOST_PLATFORM"] - - if os.name != 'posix' or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - - (osname, host, release, version, machine) = os.uname() - - # Convert the OS name to lowercase, remove '/' characters, and translate - # spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_').replace('/', '-') - - if osname[:5] == 'linux': - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - - elif osname[:5] == 'sunos': - if release[0] >= '5': # SunOS 5 == Solaris 2 - osname = 'solaris' - release = '%d.%s' % (int(release[0]) - 3, release[2:]) - # We can't use 'platform.architecture()[0]' because a - # bootstrap problem. We use a dict to get an error - # if some suspicious happens. - bitness = {2147483647:'32bit', 9223372036854775807:'64bit'} - machine += '.%s' % bitness[sys.maxsize] - # fall through to standard osname-release-machine representation - elif osname[:3] == 'aix': - from _aix_support import aix_platform - return aix_platform() - elif osname[:6] == 'cygwin': - osname = 'cygwin' - rel_re = re.compile (r'[\d.]+', re.ASCII) - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == 'darwin': - import _osx_support, distutils.sysconfig - osname, release, machine = _osx_support.get_platform_osx( - distutils.sysconfig.get_config_vars(), - osname, release, machine) - - return '%s-%s-%s' % (osname, release, machine) - - -_TARGET_TO_PLAT = { - 'x86' : 'win32', - 'x64' : 'win-amd64', - 'arm' : 'win-arm32', -} - - -def get_platform(): - if os.name != 'nt': - return get_host_platform() - cross_compilation_target = os.environ.get('VSCMD_ARG_TGT_ARCH') - if cross_compilation_target not in _TARGET_TO_PLAT: - return get_host_platform() - return _TARGET_TO_PLAT[cross_compilation_target] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/version.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/version.py deleted file mode 100644 index 86c069a..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/version.py +++ /dev/null @@ -1,739 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2017 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -""" -Implementation of a flexible versioning scheme providing support for PEP-440, -setuptools-compatible and semantic versioning. -""" - -import logging -import re - -from .compat import string_types -from .util import parse_requirement - -__all__ = ['NormalizedVersion', 'NormalizedMatcher', - 'LegacyVersion', 'LegacyMatcher', - 'SemanticVersion', 'SemanticMatcher', - 'UnsupportedVersionError', 'get_scheme'] - -logger = logging.getLogger(__name__) - - -class UnsupportedVersionError(ValueError): - """This is an unsupported version.""" - pass - - -class Version(object): - def __init__(self, s): - self._string = s = s.strip() - self._parts = parts = self.parse(s) - assert isinstance(parts, tuple) - assert len(parts) > 0 - - def parse(self, s): - raise NotImplementedError('please implement in a subclass') - - def _check_compatible(self, other): - if type(self) != type(other): - raise TypeError('cannot compare %r and %r' % (self, other)) - - def __eq__(self, other): - self._check_compatible(other) - return self._parts == other._parts - - def __ne__(self, other): - return not self.__eq__(other) - - def __lt__(self, other): - self._check_compatible(other) - return self._parts < other._parts - - def __gt__(self, other): - return not (self.__lt__(other) or self.__eq__(other)) - - def __le__(self, other): - return self.__lt__(other) or self.__eq__(other) - - def __ge__(self, other): - return self.__gt__(other) or self.__eq__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - def __hash__(self): - return hash(self._parts) - - def __repr__(self): - return "%s('%s')" % (self.__class__.__name__, self._string) - - def __str__(self): - return self._string - - @property - def is_prerelease(self): - raise NotImplementedError('Please implement in subclasses.') - - -class Matcher(object): - version_class = None - - # value is either a callable or the name of a method - _operators = { - '<': lambda v, c, p: v < c, - '>': lambda v, c, p: v > c, - '<=': lambda v, c, p: v == c or v < c, - '>=': lambda v, c, p: v == c or v > c, - '==': lambda v, c, p: v == c, - '===': lambda v, c, p: v == c, - # by default, compatible => >=. - '~=': lambda v, c, p: v == c or v > c, - '!=': lambda v, c, p: v != c, - } - - # this is a method only to support alternative implementations - # via overriding - def parse_requirement(self, s): - return parse_requirement(s) - - def __init__(self, s): - if self.version_class is None: - raise ValueError('Please specify a version class') - self._string = s = s.strip() - r = self.parse_requirement(s) - if not r: - raise ValueError('Not valid: %r' % s) - self.name = r.name - self.key = self.name.lower() # for case-insensitive comparisons - clist = [] - if r.constraints: - # import pdb; pdb.set_trace() - for op, s in r.constraints: - if s.endswith('.*'): - if op not in ('==', '!='): - raise ValueError('\'.*\' not allowed for ' - '%r constraints' % op) - # Could be a partial version (e.g. for '2.*') which - # won't parse as a version, so keep it as a string - vn, prefix = s[:-2], True - # Just to check that vn is a valid version - self.version_class(vn) - else: - # Should parse as a version, so we can create an - # instance for the comparison - vn, prefix = self.version_class(s), False - clist.append((op, vn, prefix)) - self._parts = tuple(clist) - - def match(self, version): - """ - Check if the provided version matches the constraints. - - :param version: The version to match against this instance. - :type version: String or :class:`Version` instance. - """ - if isinstance(version, string_types): - version = self.version_class(version) - for operator, constraint, prefix in self._parts: - f = self._operators.get(operator) - if isinstance(f, string_types): - f = getattr(self, f) - if not f: - msg = ('%r not implemented ' - 'for %s' % (operator, self.__class__.__name__)) - raise NotImplementedError(msg) - if not f(version, constraint, prefix): - return False - return True - - @property - def exact_version(self): - result = None - if len(self._parts) == 1 and self._parts[0][0] in ('==', '==='): - result = self._parts[0][1] - return result - - def _check_compatible(self, other): - if type(self) != type(other) or self.name != other.name: - raise TypeError('cannot compare %s and %s' % (self, other)) - - def __eq__(self, other): - self._check_compatible(other) - return self.key == other.key and self._parts == other._parts - - def __ne__(self, other): - return not self.__eq__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - def __hash__(self): - return hash(self.key) + hash(self._parts) - - def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self._string) - - def __str__(self): - return self._string - - -PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|b|c|rc)(\d+))?' - r'(\.(post)(\d+))?(\.(dev)(\d+))?' - r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$') - - -def _pep_440_key(s): - s = s.strip() - m = PEP440_VERSION_RE.match(s) - if not m: - raise UnsupportedVersionError('Not a valid version: %s' % s) - groups = m.groups() - nums = tuple(int(v) for v in groups[1].split('.')) - while len(nums) > 1 and nums[-1] == 0: - nums = nums[:-1] - - if not groups[0]: - epoch = 0 - else: - epoch = int(groups[0]) - pre = groups[4:6] - post = groups[7:9] - dev = groups[10:12] - local = groups[13] - if pre == (None, None): - pre = () - else: - pre = pre[0], int(pre[1]) - if post == (None, None): - post = () - else: - post = post[0], int(post[1]) - if dev == (None, None): - dev = () - else: - dev = dev[0], int(dev[1]) - if local is None: - local = () - else: - parts = [] - for part in local.split('.'): - # to ensure that numeric compares as > lexicographic, avoid - # comparing them directly, but encode a tuple which ensures - # correct sorting - if part.isdigit(): - part = (1, int(part)) - else: - part = (0, part) - parts.append(part) - local = tuple(parts) - if not pre: - # either before pre-release, or final release and after - if not post and dev: - # before pre-release - pre = ('a', -1) # to sort before a0 - else: - pre = ('z',) # to sort after all pre-releases - # now look at the state of post and dev. - if not post: - post = ('_',) # sort before 'a' - if not dev: - dev = ('final',) - - #print('%s -> %s' % (s, m.groups())) - return epoch, nums, pre, post, dev, local - - -_normalized_key = _pep_440_key - - -class NormalizedVersion(Version): - """A rational version. - - Good: - 1.2 # equivalent to "1.2.0" - 1.2.0 - 1.2a1 - 1.2.3a2 - 1.2.3b1 - 1.2.3c1 - 1.2.3.4 - TODO: fill this out - - Bad: - 1 # minimum two numbers - 1.2a # release level must have a release serial - 1.2.3b - """ - def parse(self, s): - result = _normalized_key(s) - # _normalized_key loses trailing zeroes in the release - # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0 - # However, PEP 440 prefix matching needs it: for example, - # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0). - m = PEP440_VERSION_RE.match(s) # must succeed - groups = m.groups() - self._release_clause = tuple(int(v) for v in groups[1].split('.')) - return result - - PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev']) - - @property - def is_prerelease(self): - return any(t[0] in self.PREREL_TAGS for t in self._parts if t) - - -def _match_prefix(x, y): - x = str(x) - y = str(y) - if x == y: - return True - if not x.startswith(y): - return False - n = len(y) - return x[n] == '.' - - -class NormalizedMatcher(Matcher): - version_class = NormalizedVersion - - # value is either a callable or the name of a method - _operators = { - '~=': '_match_compatible', - '<': '_match_lt', - '>': '_match_gt', - '<=': '_match_le', - '>=': '_match_ge', - '==': '_match_eq', - '===': '_match_arbitrary', - '!=': '_match_ne', - } - - def _adjust_local(self, version, constraint, prefix): - if prefix: - strip_local = '+' not in constraint and version._parts[-1] - else: - # both constraint and version are - # NormalizedVersion instances. - # If constraint does not have a local component, - # ensure the version doesn't, either. - strip_local = not constraint._parts[-1] and version._parts[-1] - if strip_local: - s = version._string.split('+', 1)[0] - version = self.version_class(s) - return version, constraint - - def _match_lt(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version >= constraint: - return False - release_clause = constraint._release_clause - pfx = '.'.join([str(i) for i in release_clause]) - return not _match_prefix(version, pfx) - - def _match_gt(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version <= constraint: - return False - release_clause = constraint._release_clause - pfx = '.'.join([str(i) for i in release_clause]) - return not _match_prefix(version, pfx) - - def _match_le(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - return version <= constraint - - def _match_ge(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - return version >= constraint - - def _match_eq(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if not prefix: - result = (version == constraint) - else: - result = _match_prefix(version, constraint) - return result - - def _match_arbitrary(self, version, constraint, prefix): - return str(version) == str(constraint) - - def _match_ne(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if not prefix: - result = (version != constraint) - else: - result = not _match_prefix(version, constraint) - return result - - def _match_compatible(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version == constraint: - return True - if version < constraint: - return False -# if not prefix: -# return True - release_clause = constraint._release_clause - if len(release_clause) > 1: - release_clause = release_clause[:-1] - pfx = '.'.join([str(i) for i in release_clause]) - return _match_prefix(version, pfx) - -_REPLACEMENTS = ( - (re.compile('[.+-]$'), ''), # remove trailing puncts - (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start - (re.compile('^[.-]'), ''), # remove leading puncts - (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses - (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion) - (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion) - (re.compile('[.]{2,}'), '.'), # multiple runs of '.' - (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha - (re.compile(r'\b(pre-alpha|prealpha)\b'), - 'pre.alpha'), # standardise - (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses -) - -_SUFFIX_REPLACEMENTS = ( - (re.compile('^[:~._+-]+'), ''), # remove leading puncts - (re.compile('[,*")([\\]]'), ''), # remove unwanted chars - (re.compile('[~:+_ -]'), '.'), # replace illegal chars - (re.compile('[.]{2,}'), '.'), # multiple runs of '.' - (re.compile(r'\.$'), ''), # trailing '.' -) - -_NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)') - - -def _suggest_semantic_version(s): - """ - Try to suggest a semantic form for a version for which - _suggest_normalized_version couldn't come up with anything. - """ - result = s.strip().lower() - for pat, repl in _REPLACEMENTS: - result = pat.sub(repl, result) - if not result: - result = '0.0.0' - - # Now look for numeric prefix, and separate it out from - # the rest. - #import pdb; pdb.set_trace() - m = _NUMERIC_PREFIX.match(result) - if not m: - prefix = '0.0.0' - suffix = result - else: - prefix = m.groups()[0].split('.') - prefix = [int(i) for i in prefix] - while len(prefix) < 3: - prefix.append(0) - if len(prefix) == 3: - suffix = result[m.end():] - else: - suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():] - prefix = prefix[:3] - prefix = '.'.join([str(i) for i in prefix]) - suffix = suffix.strip() - if suffix: - #import pdb; pdb.set_trace() - # massage the suffix. - for pat, repl in _SUFFIX_REPLACEMENTS: - suffix = pat.sub(repl, suffix) - - if not suffix: - result = prefix - else: - sep = '-' if 'dev' in suffix else '+' - result = prefix + sep + suffix - if not is_semver(result): - result = None - return result - - -def _suggest_normalized_version(s): - """Suggest a normalized version close to the given version string. - - If you have a version string that isn't rational (i.e. NormalizedVersion - doesn't like it) then you might be able to get an equivalent (or close) - rational version from this function. - - This does a number of simple normalizations to the given string, based - on observation of versions currently in use on PyPI. Given a dump of - those version during PyCon 2009, 4287 of them: - - 2312 (53.93%) match NormalizedVersion without change - with the automatic suggestion - - 3474 (81.04%) match when using this suggestion method - - @param s {str} An irrational version string. - @returns A rational version string, or None, if couldn't determine one. - """ - try: - _normalized_key(s) - return s # already rational - except UnsupportedVersionError: - pass - - rs = s.lower() - - # part of this could use maketrans - for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), - ('beta', 'b'), ('rc', 'c'), ('-final', ''), - ('-pre', 'c'), - ('-release', ''), ('.release', ''), ('-stable', ''), - ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), - ('final', '')): - rs = rs.replace(orig, repl) - - # if something ends with dev or pre, we add a 0 - rs = re.sub(r"pre$", r"pre0", rs) - rs = re.sub(r"dev$", r"dev0", rs) - - # if we have something like "b-2" or "a.2" at the end of the - # version, that is probably beta, alpha, etc - # let's remove the dash or dot - rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs) - - # 1.0-dev-r371 -> 1.0.dev371 - # 0.1-dev-r79 -> 0.1.dev79 - rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) - - # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 - rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) - - # Clean: v0.3, v1.0 - if rs.startswith('v'): - rs = rs[1:] - - # Clean leading '0's on numbers. - #TODO: unintended side-effect on, e.g., "2003.05.09" - # PyPI stats: 77 (~2%) better - rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) - - # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers - # zero. - # PyPI stats: 245 (7.56%) better - rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) - - # the 'dev-rNNN' tag is a dev tag - rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) - - # clean the - when used as a pre delimiter - rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) - - # a terminal "dev" or "devel" can be changed into ".dev0" - rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) - - # a terminal "dev" can be changed into ".dev0" - rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) - - # a terminal "final" or "stable" can be removed - rs = re.sub(r"(final|stable)$", "", rs) - - # The 'r' and the '-' tags are post release tags - # 0.4a1.r10 -> 0.4a1.post10 - # 0.9.33-17222 -> 0.9.33.post17222 - # 0.9.33-r17222 -> 0.9.33.post17222 - rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) - - # Clean 'r' instead of 'dev' usage: - # 0.9.33+r17222 -> 0.9.33.dev17222 - # 1.0dev123 -> 1.0.dev123 - # 1.0.git123 -> 1.0.dev123 - # 1.0.bzr123 -> 1.0.dev123 - # 0.1a0dev.123 -> 0.1a0.dev123 - # PyPI stats: ~150 (~4%) better - rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) - - # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: - # 0.2.pre1 -> 0.2c1 - # 0.2-c1 -> 0.2c1 - # 1.0preview123 -> 1.0c123 - # PyPI stats: ~21 (0.62%) better - rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) - - # Tcl/Tk uses "px" for their post release markers - rs = re.sub(r"p(\d+)$", r".post\1", rs) - - try: - _normalized_key(rs) - except UnsupportedVersionError: - rs = None - return rs - -# -# Legacy version processing (distribute-compatible) -# - -_VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I) -_VERSION_REPLACE = { - 'pre': 'c', - 'preview': 'c', - '-': 'final-', - 'rc': 'c', - 'dev': '@', - '': None, - '.': None, -} - - -def _legacy_key(s): - def get_parts(s): - result = [] - for p in _VERSION_PART.split(s.lower()): - p = _VERSION_REPLACE.get(p, p) - if p: - if '0' <= p[:1] <= '9': - p = p.zfill(8) - else: - p = '*' + p - result.append(p) - result.append('*final') - return result - - result = [] - for p in get_parts(s): - if p.startswith('*'): - if p < '*final': - while result and result[-1] == '*final-': - result.pop() - while result and result[-1] == '00000000': - result.pop() - result.append(p) - return tuple(result) - - -class LegacyVersion(Version): - def parse(self, s): - return _legacy_key(s) - - @property - def is_prerelease(self): - result = False - for x in self._parts: - if (isinstance(x, string_types) and x.startswith('*') and - x < '*final'): - result = True - break - return result - - -class LegacyMatcher(Matcher): - version_class = LegacyVersion - - _operators = dict(Matcher._operators) - _operators['~='] = '_match_compatible' - - numeric_re = re.compile(r'^(\d+(\.\d+)*)') - - def _match_compatible(self, version, constraint, prefix): - if version < constraint: - return False - m = self.numeric_re.match(str(constraint)) - if not m: - logger.warning('Cannot compute compatible match for version %s ' - ' and constraint %s', version, constraint) - return True - s = m.groups()[0] - if '.' in s: - s = s.rsplit('.', 1)[0] - return _match_prefix(version, s) - -# -# Semantic versioning -# - -_SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)' - r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?' - r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I) - - -def is_semver(s): - return _SEMVER_RE.match(s) - - -def _semantic_key(s): - def make_tuple(s, absent): - if s is None: - result = (absent,) - else: - parts = s[1:].split('.') - # We can't compare ints and strings on Python 3, so fudge it - # by zero-filling numeric values so simulate a numeric comparison - result = tuple([p.zfill(8) if p.isdigit() else p for p in parts]) - return result - - m = is_semver(s) - if not m: - raise UnsupportedVersionError(s) - groups = m.groups() - major, minor, patch = [int(i) for i in groups[:3]] - # choose the '|' and '*' so that versions sort correctly - pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*') - return (major, minor, patch), pre, build - - -class SemanticVersion(Version): - def parse(self, s): - return _semantic_key(s) - - @property - def is_prerelease(self): - return self._parts[1][0] != '|' - - -class SemanticMatcher(Matcher): - version_class = SemanticVersion - - -class VersionScheme(object): - def __init__(self, key, matcher, suggester=None): - self.key = key - self.matcher = matcher - self.suggester = suggester - - def is_valid_version(self, s): - try: - self.matcher.version_class(s) - result = True - except UnsupportedVersionError: - result = False - return result - - def is_valid_matcher(self, s): - try: - self.matcher(s) - result = True - except UnsupportedVersionError: - result = False - return result - - def is_valid_constraint_list(self, s): - """ - Used for processing some metadata fields - """ - # See issue #140. Be tolerant of a single trailing comma. - if s.endswith(','): - s = s[:-1] - return self.is_valid_matcher('dummy_name (%s)' % s) - - def suggest(self, s): - if self.suggester is None: - result = None - else: - result = self.suggester(s) - return result - -_SCHEMES = { - 'normalized': VersionScheme(_normalized_key, NormalizedMatcher, - _suggest_normalized_version), - 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s), - 'semantic': VersionScheme(_semantic_key, SemanticMatcher, - _suggest_semantic_version), -} - -_SCHEMES['default'] = _SCHEMES['normalized'] - - -def get_scheme(name): - if name not in _SCHEMES: - raise ValueError('unknown scheme name: %r' % name) - return _SCHEMES[name] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w32.exe b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w32.exe deleted file mode 100644 index e6439e9..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w32.exe and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w64.exe b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w64.exe deleted file mode 100644 index 46139db..0000000 Binary files a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/w64.exe and /dev/null differ diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/wheel.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/wheel.py deleted file mode 100644 index 5262c83..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distlib/wheel.py +++ /dev/null @@ -1,1056 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2020 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import unicode_literals - -import base64 -import codecs -import datetime -from email import message_from_file -import hashlib -import imp -import json -import logging -import os -import posixpath -import re -import shutil -import sys -import tempfile -import zipfile - -from . import __version__, DistlibException -from .compat import sysconfig, ZipFile, fsdecode, text_type, filter -from .database import InstalledDistribution -from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME, - LEGACY_METADATA_FILENAME) -from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, - cached_property, get_cache_base, read_exports, tempdir, - get_platform) -from .version import NormalizedVersion, UnsupportedVersionError - -logger = logging.getLogger(__name__) - -cache = None # created when needed - -if hasattr(sys, 'pypy_version_info'): # pragma: no cover - IMP_PREFIX = 'pp' -elif sys.platform.startswith('java'): # pragma: no cover - IMP_PREFIX = 'jy' -elif sys.platform == 'cli': # pragma: no cover - IMP_PREFIX = 'ip' -else: - IMP_PREFIX = 'cp' - -VER_SUFFIX = sysconfig.get_config_var('py_version_nodot') -if not VER_SUFFIX: # pragma: no cover - if sys.version_info[1] >= 10: - VER_SUFFIX = '%s_%s' % sys.version_info[:2] # PEP 641 (draft) - else: - VER_SUFFIX = '%s%s' % sys.version_info[:2] -PYVER = 'py' + VER_SUFFIX -IMPVER = IMP_PREFIX + VER_SUFFIX - -ARCH = get_platform().replace('-', '_').replace('.', '_') - -ABI = sysconfig.get_config_var('SOABI') -if ABI and ABI.startswith('cpython-'): - ABI = ABI.replace('cpython-', 'cp').split('-')[0] -else: - def _derive_abi(): - parts = ['cp', VER_SUFFIX] - if sysconfig.get_config_var('Py_DEBUG'): - parts.append('d') - if sysconfig.get_config_var('WITH_PYMALLOC'): - parts.append('m') - if sysconfig.get_config_var('Py_UNICODE_SIZE') == 4: - parts.append('u') - return ''.join(parts) - ABI = _derive_abi() - del _derive_abi - -FILENAME_RE = re.compile(r''' -(?P[^-]+) --(?P\d+[^-]*) -(-(?P\d+[^-]*))? --(?P\w+\d+(\.\w+\d+)*) --(?P\w+) --(?P\w+(\.\w+)*) -\.whl$ -''', re.IGNORECASE | re.VERBOSE) - -NAME_VERSION_RE = re.compile(r''' -(?P[^-]+) --(?P\d+[^-]*) -(-(?P\d+[^-]*))?$ -''', re.IGNORECASE | re.VERBOSE) - -SHEBANG_RE = re.compile(br'\s*#![^\r\n]*') -SHEBANG_DETAIL_RE = re.compile(br'^(\s*#!("[^"]+"|\S+))\s+(.*)$') -SHEBANG_PYTHON = b'#!python' -SHEBANG_PYTHONW = b'#!pythonw' - -if os.sep == '/': - to_posix = lambda o: o -else: - to_posix = lambda o: o.replace(os.sep, '/') - - -class Mounter(object): - def __init__(self): - self.impure_wheels = {} - self.libs = {} - - def add(self, pathname, extensions): - self.impure_wheels[pathname] = extensions - self.libs.update(extensions) - - def remove(self, pathname): - extensions = self.impure_wheels.pop(pathname) - for k, v in extensions: - if k in self.libs: - del self.libs[k] - - def find_module(self, fullname, path=None): - if fullname in self.libs: - result = self - else: - result = None - return result - - def load_module(self, fullname): - if fullname in sys.modules: - result = sys.modules[fullname] - else: - if fullname not in self.libs: - raise ImportError('unable to find extension for %s' % fullname) - result = imp.load_dynamic(fullname, self.libs[fullname]) - result.__loader__ = self - parts = fullname.rsplit('.', 1) - if len(parts) > 1: - result.__package__ = parts[0] - return result - -_hook = Mounter() - - -class Wheel(object): - """ - Class to build and install from Wheel files (PEP 427). - """ - - wheel_version = (1, 1) - hash_kind = 'sha256' - - def __init__(self, filename=None, sign=False, verify=False): - """ - Initialise an instance using a (valid) filename. - """ - self.sign = sign - self.should_verify = verify - self.buildver = '' - self.pyver = [PYVER] - self.abi = ['none'] - self.arch = ['any'] - self.dirname = os.getcwd() - if filename is None: - self.name = 'dummy' - self.version = '0.1' - self._filename = self.filename - else: - m = NAME_VERSION_RE.match(filename) - if m: - info = m.groupdict('') - self.name = info['nm'] - # Reinstate the local version separator - self.version = info['vn'].replace('_', '-') - self.buildver = info['bn'] - self._filename = self.filename - else: - dirname, filename = os.path.split(filename) - m = FILENAME_RE.match(filename) - if not m: - raise DistlibException('Invalid name or ' - 'filename: %r' % filename) - if dirname: - self.dirname = os.path.abspath(dirname) - self._filename = filename - info = m.groupdict('') - self.name = info['nm'] - self.version = info['vn'] - self.buildver = info['bn'] - self.pyver = info['py'].split('.') - self.abi = info['bi'].split('.') - self.arch = info['ar'].split('.') - - @property - def filename(self): - """ - Build and return a filename from the various components. - """ - if self.buildver: - buildver = '-' + self.buildver - else: - buildver = '' - pyver = '.'.join(self.pyver) - abi = '.'.join(self.abi) - arch = '.'.join(self.arch) - # replace - with _ as a local version separator - version = self.version.replace('-', '_') - return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, - pyver, abi, arch) - - @property - def exists(self): - path = os.path.join(self.dirname, self.filename) - return os.path.isfile(path) - - @property - def tags(self): - for pyver in self.pyver: - for abi in self.abi: - for arch in self.arch: - yield pyver, abi, arch - - @cached_property - def metadata(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - wrapper = codecs.getreader('utf-8') - with ZipFile(pathname, 'r') as zf: - wheel_metadata = self.get_wheel_metadata(zf) - wv = wheel_metadata['Wheel-Version'].split('.', 1) - file_version = tuple([int(i) for i in wv]) - # if file_version < (1, 1): - # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME, - # LEGACY_METADATA_FILENAME] - # else: - # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME] - fns = [WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME] - result = None - for fn in fns: - try: - metadata_filename = posixpath.join(info_dir, fn) - with zf.open(metadata_filename) as bf: - wf = wrapper(bf) - result = Metadata(fileobj=wf) - if result: - break - except KeyError: - pass - if not result: - raise ValueError('Invalid wheel, because metadata is ' - 'missing: looked in %s' % ', '.join(fns)) - return result - - def get_wheel_metadata(self, zf): - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - metadata_filename = posixpath.join(info_dir, 'WHEEL') - with zf.open(metadata_filename) as bf: - wf = codecs.getreader('utf-8')(bf) - message = message_from_file(wf) - return dict(message) - - @cached_property - def info(self): - pathname = os.path.join(self.dirname, self.filename) - with ZipFile(pathname, 'r') as zf: - result = self.get_wheel_metadata(zf) - return result - - def process_shebang(self, data): - m = SHEBANG_RE.match(data) - if m: - end = m.end() - shebang, data_after_shebang = data[:end], data[end:] - # Preserve any arguments after the interpreter - if b'pythonw' in shebang.lower(): - shebang_python = SHEBANG_PYTHONW - else: - shebang_python = SHEBANG_PYTHON - m = SHEBANG_DETAIL_RE.match(shebang) - if m: - args = b' ' + m.groups()[-1] - else: - args = b'' - shebang = shebang_python + args - data = shebang + data_after_shebang - else: - cr = data.find(b'\r') - lf = data.find(b'\n') - if cr < 0 or cr > lf: - term = b'\n' - else: - if data[cr:cr + 2] == b'\r\n': - term = b'\r\n' - else: - term = b'\r' - data = SHEBANG_PYTHON + term + data - return data - - def get_hash(self, data, hash_kind=None): - if hash_kind is None: - hash_kind = self.hash_kind - try: - hasher = getattr(hashlib, hash_kind) - except AttributeError: - raise DistlibException('Unsupported hash algorithm: %r' % hash_kind) - result = hasher(data).digest() - result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') - return hash_kind, result - - def write_record(self, records, record_path, base): - records = list(records) # make a copy, as mutated - p = to_posix(os.path.relpath(record_path, base)) - records.append((p, '', '')) - with CSVWriter(record_path) as writer: - for row in records: - writer.writerow(row) - - def write_records(self, info, libdir, archive_paths): - records = [] - distinfo, info_dir = info - hasher = getattr(hashlib, self.hash_kind) - for ap, p in archive_paths: - with open(p, 'rb') as f: - data = f.read() - digest = '%s=%s' % self.get_hash(data) - size = os.path.getsize(p) - records.append((ap, digest, size)) - - p = os.path.join(distinfo, 'RECORD') - self.write_record(records, p, libdir) - ap = to_posix(os.path.join(info_dir, 'RECORD')) - archive_paths.append((ap, p)) - - def build_zip(self, pathname, archive_paths): - with ZipFile(pathname, 'w', zipfile.ZIP_DEFLATED) as zf: - for ap, p in archive_paths: - logger.debug('Wrote %s to %s in wheel', p, ap) - zf.write(p, ap) - - def build(self, paths, tags=None, wheel_version=None): - """ - Build a wheel from files in specified paths, and use any specified tags - when determining the name of the wheel. - """ - if tags is None: - tags = {} - - libkey = list(filter(lambda o: o in paths, ('purelib', 'platlib')))[0] - if libkey == 'platlib': - is_pure = 'false' - default_pyver = [IMPVER] - default_abi = [ABI] - default_arch = [ARCH] - else: - is_pure = 'true' - default_pyver = [PYVER] - default_abi = ['none'] - default_arch = ['any'] - - self.pyver = tags.get('pyver', default_pyver) - self.abi = tags.get('abi', default_abi) - self.arch = tags.get('arch', default_arch) - - libdir = paths[libkey] - - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - archive_paths = [] - - # First, stuff which is not in site-packages - for key in ('data', 'headers', 'scripts'): - if key not in paths: - continue - path = paths[key] - if os.path.isdir(path): - for root, dirs, files in os.walk(path): - for fn in files: - p = fsdecode(os.path.join(root, fn)) - rp = os.path.relpath(p, path) - ap = to_posix(os.path.join(data_dir, key, rp)) - archive_paths.append((ap, p)) - if key == 'scripts' and not p.endswith('.exe'): - with open(p, 'rb') as f: - data = f.read() - data = self.process_shebang(data) - with open(p, 'wb') as f: - f.write(data) - - # Now, stuff which is in site-packages, other than the - # distinfo stuff. - path = libdir - distinfo = None - for root, dirs, files in os.walk(path): - if root == path: - # At the top level only, save distinfo for later - # and skip it for now - for i, dn in enumerate(dirs): - dn = fsdecode(dn) - if dn.endswith('.dist-info'): - distinfo = os.path.join(root, dn) - del dirs[i] - break - assert distinfo, '.dist-info directory expected, not found' - - for fn in files: - # comment out next suite to leave .pyc files in - if fsdecode(fn).endswith(('.pyc', '.pyo')): - continue - p = os.path.join(root, fn) - rp = to_posix(os.path.relpath(p, path)) - archive_paths.append((rp, p)) - - # Now distinfo. Assumed to be flat, i.e. os.listdir is enough. - files = os.listdir(distinfo) - for fn in files: - if fn not in ('RECORD', 'INSTALLER', 'SHARED', 'WHEEL'): - p = fsdecode(os.path.join(distinfo, fn)) - ap = to_posix(os.path.join(info_dir, fn)) - archive_paths.append((ap, p)) - - wheel_metadata = [ - 'Wheel-Version: %d.%d' % (wheel_version or self.wheel_version), - 'Generator: distlib %s' % __version__, - 'Root-Is-Purelib: %s' % is_pure, - ] - for pyver, abi, arch in self.tags: - wheel_metadata.append('Tag: %s-%s-%s' % (pyver, abi, arch)) - p = os.path.join(distinfo, 'WHEEL') - with open(p, 'w') as f: - f.write('\n'.join(wheel_metadata)) - ap = to_posix(os.path.join(info_dir, 'WHEEL')) - archive_paths.append((ap, p)) - - # sort the entries by archive path. Not needed by any spec, but it - # keeps the archive listing and RECORD tidier than they would otherwise - # be. Use the number of path segments to keep directory entries together, - # and keep the dist-info stuff at the end. - def sorter(t): - ap = t[0] - n = ap.count('/') - if '.dist-info' in ap: - n += 10000 - return (n, ap) - archive_paths = sorted(archive_paths, key=sorter) - - # Now, at last, RECORD. - # Paths in here are archive paths - nothing else makes sense. - self.write_records((distinfo, info_dir), libdir, archive_paths) - # Now, ready to build the zip file - pathname = os.path.join(self.dirname, self.filename) - self.build_zip(pathname, archive_paths) - return pathname - - def skip_entry(self, arcname): - """ - Determine whether an archive entry should be skipped when verifying - or installing. - """ - # The signature file won't be in RECORD, - # and we don't currently don't do anything with it - # We also skip directories, as they won't be in RECORD - # either. See: - # - # https://github.com/pypa/wheel/issues/294 - # https://github.com/pypa/wheel/issues/287 - # https://github.com/pypa/wheel/pull/289 - # - return arcname.endswith(('/', '/RECORD.jws')) - - def install(self, paths, maker, **kwargs): - """ - Install a wheel to the specified paths. If kwarg ``warner`` is - specified, it should be a callable, which will be called with two - tuples indicating the wheel version of this software and the wheel - version in the file, if there is a discrepancy in the versions. - This can be used to issue any warnings to raise any exceptions. - If kwarg ``lib_only`` is True, only the purelib/platlib files are - installed, and the headers, scripts, data and dist-info metadata are - not written. If kwarg ``bytecode_hashed_invalidation`` is True, written - bytecode will try to use file-hash based invalidation (PEP-552) on - supported interpreter versions (CPython 2.7+). - - The return value is a :class:`InstalledDistribution` instance unless - ``options.lib_only`` is True, in which case the return value is ``None``. - """ - - dry_run = maker.dry_run - warner = kwargs.get('warner') - lib_only = kwargs.get('lib_only', False) - bc_hashed_invalidation = kwargs.get('bytecode_hashed_invalidation', False) - - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME) - wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') - record_name = posixpath.join(info_dir, 'RECORD') - - wrapper = codecs.getreader('utf-8') - - with ZipFile(pathname, 'r') as zf: - with zf.open(wheel_metadata_name) as bwf: - wf = wrapper(bwf) - message = message_from_file(wf) - wv = message['Wheel-Version'].split('.', 1) - file_version = tuple([int(i) for i in wv]) - if (file_version != self.wheel_version) and warner: - warner(self.wheel_version, file_version) - - if message['Root-Is-Purelib'] == 'true': - libdir = paths['purelib'] - else: - libdir = paths['platlib'] - - records = {} - with zf.open(record_name) as bf: - with CSVReader(stream=bf) as reader: - for row in reader: - p = row[0] - records[p] = row - - data_pfx = posixpath.join(data_dir, '') - info_pfx = posixpath.join(info_dir, '') - script_pfx = posixpath.join(data_dir, 'scripts', '') - - # make a new instance rather than a copy of maker's, - # as we mutate it - fileop = FileOperator(dry_run=dry_run) - fileop.record = True # so we can rollback if needed - - bc = not sys.dont_write_bytecode # Double negatives. Lovely! - - outfiles = [] # for RECORD writing - - # for script copying/shebang processing - workdir = tempfile.mkdtemp() - # set target dir later - # we default add_launchers to False, as the - # Python Launcher should be used instead - maker.source_dir = workdir - maker.target_dir = None - try: - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - if self.skip_entry(u_arcname): - continue - row = records[u_arcname] - if row[2] and str(zinfo.file_size) != row[2]: - raise DistlibException('size mismatch for ' - '%s' % u_arcname) - if row[1]: - kind, value = row[1].split('=', 1) - with zf.open(arcname) as bf: - data = bf.read() - _, digest = self.get_hash(data, kind) - if digest != value: - raise DistlibException('digest mismatch for ' - '%s' % arcname) - - if lib_only and u_arcname.startswith((info_pfx, data_pfx)): - logger.debug('lib_only: skipping %s', u_arcname) - continue - is_script = (u_arcname.startswith(script_pfx) - and not u_arcname.endswith('.exe')) - - if u_arcname.startswith(data_pfx): - _, where, rp = u_arcname.split('/', 2) - outfile = os.path.join(paths[where], convert_path(rp)) - else: - # meant for site-packages. - if u_arcname in (wheel_metadata_name, record_name): - continue - outfile = os.path.join(libdir, convert_path(u_arcname)) - if not is_script: - with zf.open(arcname) as bf: - fileop.copy_stream(bf, outfile) - # Issue #147: permission bits aren't preserved. Using - # zf.extract(zinfo, libdir) should have worked, but didn't, - # see https://www.thetopsites.net/article/53834422.shtml - # So ... manually preserve permission bits as given in zinfo - if os.name == 'posix': - # just set the normal permission bits - os.chmod(outfile, (zinfo.external_attr >> 16) & 0x1FF) - outfiles.append(outfile) - # Double check the digest of the written file - if not dry_run and row[1]: - with open(outfile, 'rb') as bf: - data = bf.read() - _, newdigest = self.get_hash(data, kind) - if newdigest != digest: - raise DistlibException('digest mismatch ' - 'on write for ' - '%s' % outfile) - if bc and outfile.endswith('.py'): - try: - pyc = fileop.byte_compile(outfile, - hashed_invalidation=bc_hashed_invalidation) - outfiles.append(pyc) - except Exception: - # Don't give up if byte-compilation fails, - # but log it and perhaps warn the user - logger.warning('Byte-compilation failed', - exc_info=True) - else: - fn = os.path.basename(convert_path(arcname)) - workname = os.path.join(workdir, fn) - with zf.open(arcname) as bf: - fileop.copy_stream(bf, workname) - - dn, fn = os.path.split(outfile) - maker.target_dir = dn - filenames = maker.make(fn) - fileop.set_executable_mode(filenames) - outfiles.extend(filenames) - - if lib_only: - logger.debug('lib_only: returning None') - dist = None - else: - # Generate scripts - - # Try to get pydist.json so we can see if there are - # any commands to generate. If this fails (e.g. because - # of a legacy wheel), log a warning but don't give up. - commands = None - file_version = self.info['Wheel-Version'] - if file_version == '1.0': - # Use legacy info - ep = posixpath.join(info_dir, 'entry_points.txt') - try: - with zf.open(ep) as bwf: - epdata = read_exports(bwf) - commands = {} - for key in ('console', 'gui'): - k = '%s_scripts' % key - if k in epdata: - commands['wrap_%s' % key] = d = {} - for v in epdata[k].values(): - s = '%s:%s' % (v.prefix, v.suffix) - if v.flags: - s += ' [%s]' % ','.join(v.flags) - d[v.name] = s - except Exception: - logger.warning('Unable to read legacy script ' - 'metadata, so cannot generate ' - 'scripts') - else: - try: - with zf.open(metadata_name) as bwf: - wf = wrapper(bwf) - commands = json.load(wf).get('extensions') - if commands: - commands = commands.get('python.commands') - except Exception: - logger.warning('Unable to read JSON metadata, so ' - 'cannot generate scripts') - if commands: - console_scripts = commands.get('wrap_console', {}) - gui_scripts = commands.get('wrap_gui', {}) - if console_scripts or gui_scripts: - script_dir = paths.get('scripts', '') - if not os.path.isdir(script_dir): - raise ValueError('Valid script path not ' - 'specified') - maker.target_dir = script_dir - for k, v in console_scripts.items(): - script = '%s = %s' % (k, v) - filenames = maker.make(script) - fileop.set_executable_mode(filenames) - - if gui_scripts: - options = {'gui': True } - for k, v in gui_scripts.items(): - script = '%s = %s' % (k, v) - filenames = maker.make(script, options) - fileop.set_executable_mode(filenames) - - p = os.path.join(libdir, info_dir) - dist = InstalledDistribution(p) - - # Write SHARED - paths = dict(paths) # don't change passed in dict - del paths['purelib'] - del paths['platlib'] - paths['lib'] = libdir - p = dist.write_shared_locations(paths, dry_run) - if p: - outfiles.append(p) - - # Write RECORD - dist.write_installed_files(outfiles, paths['prefix'], - dry_run) - return dist - except Exception: # pragma: no cover - logger.exception('installation failed.') - fileop.rollback() - raise - finally: - shutil.rmtree(workdir) - - def _get_dylib_cache(self): - global cache - if cache is None: - # Use native string to avoid issues on 2.x: see Python #20140. - base = os.path.join(get_cache_base(), str('dylib-cache'), - '%s.%s' % sys.version_info[:2]) - cache = Cache(base) - return cache - - def _get_extensions(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - arcname = posixpath.join(info_dir, 'EXTENSIONS') - wrapper = codecs.getreader('utf-8') - result = [] - with ZipFile(pathname, 'r') as zf: - try: - with zf.open(arcname) as bf: - wf = wrapper(bf) - extensions = json.load(wf) - cache = self._get_dylib_cache() - prefix = cache.prefix_to_dir(pathname) - cache_base = os.path.join(cache.base, prefix) - if not os.path.isdir(cache_base): - os.makedirs(cache_base) - for name, relpath in extensions.items(): - dest = os.path.join(cache_base, convert_path(relpath)) - if not os.path.exists(dest): - extract = True - else: - file_time = os.stat(dest).st_mtime - file_time = datetime.datetime.fromtimestamp(file_time) - info = zf.getinfo(relpath) - wheel_time = datetime.datetime(*info.date_time) - extract = wheel_time > file_time - if extract: - zf.extract(relpath, cache_base) - result.append((name, dest)) - except KeyError: - pass - return result - - def is_compatible(self): - """ - Determine if a wheel is compatible with the running system. - """ - return is_compatible(self) - - def is_mountable(self): - """ - Determine if a wheel is asserted as mountable by its metadata. - """ - return True # for now - metadata details TBD - - def mount(self, append=False): - pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) - if not self.is_compatible(): - msg = 'Wheel %s not compatible with this Python.' % pathname - raise DistlibException(msg) - if not self.is_mountable(): - msg = 'Wheel %s is marked as not mountable.' % pathname - raise DistlibException(msg) - if pathname in sys.path: - logger.debug('%s already in path', pathname) - else: - if append: - sys.path.append(pathname) - else: - sys.path.insert(0, pathname) - extensions = self._get_extensions() - if extensions: - if _hook not in sys.meta_path: - sys.meta_path.append(_hook) - _hook.add(pathname, extensions) - - def unmount(self): - pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) - if pathname not in sys.path: - logger.debug('%s not in path', pathname) - else: - sys.path.remove(pathname) - if pathname in _hook.impure_wheels: - _hook.remove(pathname) - if not _hook.impure_wheels: - if _hook in sys.meta_path: - sys.meta_path.remove(_hook) - - def verify(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME) - wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') - record_name = posixpath.join(info_dir, 'RECORD') - - wrapper = codecs.getreader('utf-8') - - with ZipFile(pathname, 'r') as zf: - with zf.open(wheel_metadata_name) as bwf: - wf = wrapper(bwf) - message = message_from_file(wf) - wv = message['Wheel-Version'].split('.', 1) - file_version = tuple([int(i) for i in wv]) - # TODO version verification - - records = {} - with zf.open(record_name) as bf: - with CSVReader(stream=bf) as reader: - for row in reader: - p = row[0] - records[p] = row - - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - # See issue #115: some wheels have .. in their entries, but - # in the filename ... e.g. __main__..py ! So the check is - # updated to look for .. in the directory portions - p = u_arcname.split('/') - if '..' in p: - raise DistlibException('invalid entry in ' - 'wheel: %r' % u_arcname) - - if self.skip_entry(u_arcname): - continue - row = records[u_arcname] - if row[2] and str(zinfo.file_size) != row[2]: - raise DistlibException('size mismatch for ' - '%s' % u_arcname) - if row[1]: - kind, value = row[1].split('=', 1) - with zf.open(arcname) as bf: - data = bf.read() - _, digest = self.get_hash(data, kind) - if digest != value: - raise DistlibException('digest mismatch for ' - '%s' % arcname) - - def update(self, modifier, dest_dir=None, **kwargs): - """ - Update the contents of a wheel in a generic way. The modifier should - be a callable which expects a dictionary argument: its keys are - archive-entry paths, and its values are absolute filesystem paths - where the contents the corresponding archive entries can be found. The - modifier is free to change the contents of the files pointed to, add - new entries and remove entries, before returning. This method will - extract the entire contents of the wheel to a temporary location, call - the modifier, and then use the passed (and possibly updated) - dictionary to write a new wheel. If ``dest_dir`` is specified, the new - wheel is written there -- otherwise, the original wheel is overwritten. - - The modifier should return True if it updated the wheel, else False. - This method returns the same value the modifier returns. - """ - - def get_version(path_map, info_dir): - version = path = None - key = '%s/%s' % (info_dir, LEGACY_METADATA_FILENAME) - if key not in path_map: - key = '%s/PKG-INFO' % info_dir - if key in path_map: - path = path_map[key] - version = Metadata(path=path).version - return version, path - - def update_version(version, path): - updated = None - try: - v = NormalizedVersion(version) - i = version.find('-') - if i < 0: - updated = '%s+1' % version - else: - parts = [int(s) for s in version[i + 1:].split('.')] - parts[-1] += 1 - updated = '%s+%s' % (version[:i], - '.'.join(str(i) for i in parts)) - except UnsupportedVersionError: - logger.debug('Cannot update non-compliant (PEP-440) ' - 'version %r', version) - if updated: - md = Metadata(path=path) - md.version = updated - legacy = path.endswith(LEGACY_METADATA_FILENAME) - md.write(path=path, legacy=legacy) - logger.debug('Version updated from %r to %r', version, - updated) - - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - record_name = posixpath.join(info_dir, 'RECORD') - with tempdir() as workdir: - with ZipFile(pathname, 'r') as zf: - path_map = {} - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - if u_arcname == record_name: - continue - if '..' in u_arcname: - raise DistlibException('invalid entry in ' - 'wheel: %r' % u_arcname) - zf.extract(zinfo, workdir) - path = os.path.join(workdir, convert_path(u_arcname)) - path_map[u_arcname] = path - - # Remember the version. - original_version, _ = get_version(path_map, info_dir) - # Files extracted. Call the modifier. - modified = modifier(path_map, **kwargs) - if modified: - # Something changed - need to build a new wheel. - current_version, path = get_version(path_map, info_dir) - if current_version and (current_version == original_version): - # Add or update local version to signify changes. - update_version(current_version, path) - # Decide where the new wheel goes. - if dest_dir is None: - fd, newpath = tempfile.mkstemp(suffix='.whl', - prefix='wheel-update-', - dir=workdir) - os.close(fd) - else: - if not os.path.isdir(dest_dir): - raise DistlibException('Not a directory: %r' % dest_dir) - newpath = os.path.join(dest_dir, self.filename) - archive_paths = list(path_map.items()) - distinfo = os.path.join(workdir, info_dir) - info = distinfo, info_dir - self.write_records(info, workdir, archive_paths) - self.build_zip(newpath, archive_paths) - if dest_dir is None: - shutil.copyfile(newpath, pathname) - return modified - -def _get_glibc_version(): - import platform - ver = platform.libc_ver() - result = [] - if ver[0] == 'glibc': - for s in ver[1].split('.'): - result.append(int(s) if s.isdigit() else 0) - result = tuple(result) - return result - -def compatible_tags(): - """ - Return (pyver, abi, arch) tuples compatible with this Python. - """ - versions = [VER_SUFFIX] - major = VER_SUFFIX[0] - for minor in range(sys.version_info[1] - 1, - 1, -1): - versions.append(''.join([major, str(minor)])) - - abis = [] - for suffix, _, _ in imp.get_suffixes(): - if suffix.startswith('.abi'): - abis.append(suffix.split('.', 2)[1]) - abis.sort() - if ABI != 'none': - abis.insert(0, ABI) - abis.append('none') - result = [] - - arches = [ARCH] - if sys.platform == 'darwin': - m = re.match(r'(\w+)_(\d+)_(\d+)_(\w+)$', ARCH) - if m: - name, major, minor, arch = m.groups() - minor = int(minor) - matches = [arch] - if arch in ('i386', 'ppc'): - matches.append('fat') - if arch in ('i386', 'ppc', 'x86_64'): - matches.append('fat3') - if arch in ('ppc64', 'x86_64'): - matches.append('fat64') - if arch in ('i386', 'x86_64'): - matches.append('intel') - if arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): - matches.append('universal') - while minor >= 0: - for match in matches: - s = '%s_%s_%s_%s' % (name, major, minor, match) - if s != ARCH: # already there - arches.append(s) - minor -= 1 - - # Most specific - our Python version, ABI and arch - for abi in abis: - for arch in arches: - result.append((''.join((IMP_PREFIX, versions[0])), abi, arch)) - # manylinux - if abi != 'none' and sys.platform.startswith('linux'): - arch = arch.replace('linux_', '') - parts = _get_glibc_version() - if len(parts) == 2: - if parts >= (2, 5): - result.append((''.join((IMP_PREFIX, versions[0])), abi, - 'manylinux1_%s' % arch)) - if parts >= (2, 12): - result.append((''.join((IMP_PREFIX, versions[0])), abi, - 'manylinux2010_%s' % arch)) - if parts >= (2, 17): - result.append((''.join((IMP_PREFIX, versions[0])), abi, - 'manylinux2014_%s' % arch)) - result.append((''.join((IMP_PREFIX, versions[0])), abi, - 'manylinux_%s_%s_%s' % (parts[0], parts[1], - arch))) - - # where no ABI / arch dependency, but IMP_PREFIX dependency - for i, version in enumerate(versions): - result.append((''.join((IMP_PREFIX, version)), 'none', 'any')) - if i == 0: - result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any')) - - # no IMP_PREFIX, ABI or arch dependency - for i, version in enumerate(versions): - result.append((''.join(('py', version)), 'none', 'any')) - if i == 0: - result.append((''.join(('py', version[0])), 'none', 'any')) - - return set(result) - - -COMPATIBLE_TAGS = compatible_tags() - -del compatible_tags - - -def is_compatible(wheel, tags=None): - if not isinstance(wheel, Wheel): - wheel = Wheel(wheel) # assume it's a filename - result = False - if tags is None: - tags = COMPATIBLE_TAGS - for ver, abi, arch in tags: - if ver in wheel.pyver and abi in wheel.abi and arch in wheel.arch: - result = True - break - return result diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distro.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distro.py deleted file mode 100644 index 0611b62..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/distro.py +++ /dev/null @@ -1,1230 +0,0 @@ -# Copyright 2015,2016,2017 Nir Cohen -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -The ``distro`` package (``distro`` stands for Linux Distribution) provides -information about the Linux distribution it runs on, such as a reliable -machine-readable distro ID, or version information. - -It is the recommended replacement for Python's original -:py:func:`platform.linux_distribution` function, but it provides much more -functionality. An alternative implementation became necessary because Python -3.5 deprecated this function, and Python 3.8 will remove it altogether. -Its predecessor function :py:func:`platform.dist` was already -deprecated since Python 2.6 and will also be removed in Python 3.8. -Still, there are many cases in which access to OS distribution information -is needed. See `Python issue 1322 `_ for -more information. -""" - -import os -import re -import sys -import json -import shlex -import logging -import argparse -import subprocess - - -_UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc') -_OS_RELEASE_BASENAME = 'os-release' - -#: Translation table for normalizing the "ID" attribute defined in os-release -#: files, for use by the :func:`distro.id` method. -#: -#: * Key: Value as defined in the os-release file, translated to lower case, -#: with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_OS_ID = { - 'ol': 'oracle', # Oracle Linux -} - -#: Translation table for normalizing the "Distributor ID" attribute returned by -#: the lsb_release command, for use by the :func:`distro.id` method. -#: -#: * Key: Value as returned by the lsb_release command, translated to lower -#: case, with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_LSB_ID = { - 'enterpriseenterpriseas': 'oracle', # Oracle Enterprise Linux 4 - 'enterpriseenterpriseserver': 'oracle', # Oracle Linux 5 - 'redhatenterpriseworkstation': 'rhel', # RHEL 6, 7 Workstation - 'redhatenterpriseserver': 'rhel', # RHEL 6, 7 Server - 'redhatenterprisecomputenode': 'rhel', # RHEL 6 ComputeNode -} - -#: Translation table for normalizing the distro ID derived from the file name -#: of distro release files, for use by the :func:`distro.id` method. -#: -#: * Key: Value as derived from the file name of a distro release file, -#: translated to lower case, with blanks translated to underscores. -#: -#: * Value: Normalized value. -NORMALIZED_DISTRO_ID = { - 'redhat': 'rhel', # RHEL 6.x, 7.x -} - -# Pattern for content of distro release file (reversed) -_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( - r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)') - -# Pattern for base file name of distro release file -_DISTRO_RELEASE_BASENAME_PATTERN = re.compile( - r'(\w+)[-_](release|version)$') - -# Base file names to be ignored when searching for distro release file -_DISTRO_RELEASE_IGNORE_BASENAMES = ( - 'debian_version', - 'lsb-release', - 'oem-release', - _OS_RELEASE_BASENAME, - 'system-release', - 'plesk-release', -) - - -def linux_distribution(full_distribution_name=True): - """ - Return information about the current OS distribution as a tuple - ``(id_name, version, codename)`` with items as follows: - - * ``id_name``: If *full_distribution_name* is false, the result of - :func:`distro.id`. Otherwise, the result of :func:`distro.name`. - - * ``version``: The result of :func:`distro.version`. - - * ``codename``: The result of :func:`distro.codename`. - - The interface of this function is compatible with the original - :py:func:`platform.linux_distribution` function, supporting a subset of - its parameters. - - The data it returns may not exactly be the same, because it uses more data - sources than the original function, and that may lead to different data if - the OS distribution is not consistent across multiple data sources it - provides (there are indeed such distributions ...). - - Another reason for differences is the fact that the :func:`distro.id` - method normalizes the distro ID string to a reliable machine-readable value - for a number of popular OS distributions. - """ - return _distro.linux_distribution(full_distribution_name) - - -def id(): - """ - Return the distro ID of the current distribution, as a - machine-readable string. - - For a number of OS distributions, the returned distro ID value is - *reliable*, in the sense that it is documented and that it does not change - across releases of the distribution. - - This package maintains the following reliable distro ID values: - - ============== ========================================= - Distro ID Distribution - ============== ========================================= - "ubuntu" Ubuntu - "debian" Debian - "rhel" RedHat Enterprise Linux - "centos" CentOS - "fedora" Fedora - "sles" SUSE Linux Enterprise Server - "opensuse" openSUSE - "amazon" Amazon Linux - "arch" Arch Linux - "cloudlinux" CloudLinux OS - "exherbo" Exherbo Linux - "gentoo" GenToo Linux - "ibm_powerkvm" IBM PowerKVM - "kvmibm" KVM for IBM z Systems - "linuxmint" Linux Mint - "mageia" Mageia - "mandriva" Mandriva Linux - "parallels" Parallels - "pidora" Pidora - "raspbian" Raspbian - "oracle" Oracle Linux (and Oracle Enterprise Linux) - "scientific" Scientific Linux - "slackware" Slackware - "xenserver" XenServer - "openbsd" OpenBSD - "netbsd" NetBSD - "freebsd" FreeBSD - "midnightbsd" MidnightBSD - ============== ========================================= - - If you have a need to get distros for reliable IDs added into this set, - or if you find that the :func:`distro.id` function returns a different - distro ID for one of the listed distros, please create an issue in the - `distro issue tracker`_. - - **Lookup hierarchy and transformations:** - - First, the ID is obtained from the following sources, in the specified - order. The first available and non-empty value is used: - - * the value of the "ID" attribute of the os-release file, - - * the value of the "Distributor ID" attribute returned by the lsb_release - command, - - * the first part of the file name of the distro release file, - - The so determined ID value then passes the following transformations, - before it is returned by this method: - - * it is translated to lower case, - - * blanks (which should not be there anyway) are translated to underscores, - - * a normalization of the ID is performed, based upon - `normalization tables`_. The purpose of this normalization is to ensure - that the ID is as reliable as possible, even across incompatible changes - in the OS distributions. A common reason for an incompatible change is - the addition of an os-release file, or the addition of the lsb_release - command, with ID values that differ from what was previously determined - from the distro release file name. - """ - return _distro.id() - - -def name(pretty=False): - """ - Return the name of the current OS distribution, as a human-readable - string. - - If *pretty* is false, the name is returned without version or codename. - (e.g. "CentOS Linux") - - If *pretty* is true, the version and codename are appended. - (e.g. "CentOS Linux 7.1.1503 (Core)") - - **Lookup hierarchy:** - - The name is obtained from the following sources, in the specified order. - The first available and non-empty value is used: - - * If *pretty* is false: - - - the value of the "NAME" attribute of the os-release file, - - - the value of the "Distributor ID" attribute returned by the lsb_release - command, - - - the value of the "" field of the distro release file. - - * If *pretty* is true: - - - the value of the "PRETTY_NAME" attribute of the os-release file, - - - the value of the "Description" attribute returned by the lsb_release - command, - - - the value of the "" field of the distro release file, appended - with the value of the pretty version ("" and "" - fields) of the distro release file, if available. - """ - return _distro.name(pretty) - - -def version(pretty=False, best=False): - """ - Return the version of the current OS distribution, as a human-readable - string. - - If *pretty* is false, the version is returned without codename (e.g. - "7.0"). - - If *pretty* is true, the codename in parenthesis is appended, if the - codename is non-empty (e.g. "7.0 (Maipo)"). - - Some distributions provide version numbers with different precisions in - the different sources of distribution information. Examining the different - sources in a fixed priority order does not always yield the most precise - version (e.g. for Debian 8.2, or CentOS 7.1). - - The *best* parameter can be used to control the approach for the returned - version: - - If *best* is false, the first non-empty version number in priority order of - the examined sources is returned. - - If *best* is true, the most precise version number out of all examined - sources is returned. - - **Lookup hierarchy:** - - In all cases, the version number is obtained from the following sources. - If *best* is false, this order represents the priority order: - - * the value of the "VERSION_ID" attribute of the os-release file, - * the value of the "Release" attribute returned by the lsb_release - command, - * the version number parsed from the "" field of the first line - of the distro release file, - * the version number parsed from the "PRETTY_NAME" attribute of the - os-release file, if it follows the format of the distro release files. - * the version number parsed from the "Description" attribute returned by - the lsb_release command, if it follows the format of the distro release - files. - """ - return _distro.version(pretty, best) - - -def version_parts(best=False): - """ - Return the version of the current OS distribution as a tuple - ``(major, minor, build_number)`` with items as follows: - - * ``major``: The result of :func:`distro.major_version`. - - * ``minor``: The result of :func:`distro.minor_version`. - - * ``build_number``: The result of :func:`distro.build_number`. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.version_parts(best) - - -def major_version(best=False): - """ - Return the major version of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The major version is the first - part of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.major_version(best) - - -def minor_version(best=False): - """ - Return the minor version of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The minor version is the second - part of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.minor_version(best) - - -def build_number(best=False): - """ - Return the build number of the current OS distribution, as a string, - if provided. - Otherwise, the empty string is returned. The build number is the third part - of the dot-separated version string. - - For a description of the *best* parameter, see the :func:`distro.version` - method. - """ - return _distro.build_number(best) - - -def like(): - """ - Return a space-separated list of distro IDs of distributions that are - closely related to the current OS distribution in regards to packaging - and programming interfaces, for example distributions the current - distribution is a derivative from. - - **Lookup hierarchy:** - - This information item is only provided by the os-release file. - For details, see the description of the "ID_LIKE" attribute in the - `os-release man page - `_. - """ - return _distro.like() - - -def codename(): - """ - Return the codename for the release of the current OS distribution, - as a string. - - If the distribution does not have a codename, an empty string is returned. - - Note that the returned codename is not always really a codename. For - example, openSUSE returns "x86_64". This function does not handle such - cases in any special way and just returns the string it finds, if any. - - **Lookup hierarchy:** - - * the codename within the "VERSION" attribute of the os-release file, if - provided, - - * the value of the "Codename" attribute returned by the lsb_release - command, - - * the value of the "" field of the distro release file. - """ - return _distro.codename() - - -def info(pretty=False, best=False): - """ - Return certain machine-readable information items about the current OS - distribution in a dictionary, as shown in the following example: - - .. sourcecode:: python - - { - 'id': 'rhel', - 'version': '7.0', - 'version_parts': { - 'major': '7', - 'minor': '0', - 'build_number': '' - }, - 'like': 'fedora', - 'codename': 'Maipo' - } - - The dictionary structure and keys are always the same, regardless of which - information items are available in the underlying data sources. The values - for the various keys are as follows: - - * ``id``: The result of :func:`distro.id`. - - * ``version``: The result of :func:`distro.version`. - - * ``version_parts -> major``: The result of :func:`distro.major_version`. - - * ``version_parts -> minor``: The result of :func:`distro.minor_version`. - - * ``version_parts -> build_number``: The result of - :func:`distro.build_number`. - - * ``like``: The result of :func:`distro.like`. - - * ``codename``: The result of :func:`distro.codename`. - - For a description of the *pretty* and *best* parameters, see the - :func:`distro.version` method. - """ - return _distro.info(pretty, best) - - -def os_release_info(): - """ - Return a dictionary containing key-value pairs for the information items - from the os-release file data source of the current OS distribution. - - See `os-release file`_ for details about these information items. - """ - return _distro.os_release_info() - - -def lsb_release_info(): - """ - Return a dictionary containing key-value pairs for the information items - from the lsb_release command data source of the current OS distribution. - - See `lsb_release command output`_ for details about these information - items. - """ - return _distro.lsb_release_info() - - -def distro_release_info(): - """ - Return a dictionary containing key-value pairs for the information items - from the distro release file data source of the current OS distribution. - - See `distro release file`_ for details about these information items. - """ - return _distro.distro_release_info() - - -def uname_info(): - """ - Return a dictionary containing key-value pairs for the information items - from the distro release file data source of the current OS distribution. - """ - return _distro.uname_info() - - -def os_release_attr(attribute): - """ - Return a single named information item from the os-release file data source - of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `os-release file`_ for details about these information items. - """ - return _distro.os_release_attr(attribute) - - -def lsb_release_attr(attribute): - """ - Return a single named information item from the lsb_release command output - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `lsb_release command output`_ for details about these information - items. - """ - return _distro.lsb_release_attr(attribute) - - -def distro_release_attr(attribute): - """ - Return a single named information item from the distro release file - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - - See `distro release file`_ for details about these information items. - """ - return _distro.distro_release_attr(attribute) - - -def uname_attr(attribute): - """ - Return a single named information item from the distro release file - data source of the current OS distribution. - - Parameters: - - * ``attribute`` (string): Key of the information item. - - Returns: - - * (string): Value of the information item, if the item exists. - The empty string, if the item does not exist. - """ - return _distro.uname_attr(attribute) - - -class cached_property(object): - """A version of @property which caches the value. On access, it calls the - underlying function and sets the value in `__dict__` so future accesses - will not re-call the property. - """ - def __init__(self, f): - self._fname = f.__name__ - self._f = f - - def __get__(self, obj, owner): - assert obj is not None, 'call {} on an instance'.format(self._fname) - ret = obj.__dict__[self._fname] = self._f(obj) - return ret - - -class LinuxDistribution(object): - """ - Provides information about a OS distribution. - - This package creates a private module-global instance of this class with - default initialization arguments, that is used by the - `consolidated accessor functions`_ and `single source accessor functions`_. - By using default initialization arguments, that module-global instance - returns data about the current OS distribution (i.e. the distro this - package runs on). - - Normally, it is not necessary to create additional instances of this class. - However, in situations where control is needed over the exact data sources - that are used, instances of this class can be created with a specific - distro release file, or a specific os-release file, or without invoking the - lsb_release command. - """ - - def __init__(self, - include_lsb=True, - os_release_file='', - distro_release_file='', - include_uname=True): - """ - The initialization method of this class gathers information from the - available data sources, and stores that in private instance attributes. - Subsequent access to the information items uses these private instance - attributes, so that the data sources are read only once. - - Parameters: - - * ``include_lsb`` (bool): Controls whether the - `lsb_release command output`_ is included as a data source. - - If the lsb_release command is not available in the program execution - path, the data source for the lsb_release command will be empty. - - * ``os_release_file`` (string): The path name of the - `os-release file`_ that is to be used as a data source. - - An empty string (the default) will cause the default path name to - be used (see `os-release file`_ for details). - - If the specified or defaulted os-release file does not exist, the - data source for the os-release file will be empty. - - * ``distro_release_file`` (string): The path name of the - `distro release file`_ that is to be used as a data source. - - An empty string (the default) will cause a default search algorithm - to be used (see `distro release file`_ for details). - - If the specified distro release file does not exist, or if no default - distro release file can be found, the data source for the distro - release file will be empty. - - * ``include_uname`` (bool): Controls whether uname command output is - included as a data source. If the uname command is not available in - the program execution path the data source for the uname command will - be empty. - - Public instance attributes: - - * ``os_release_file`` (string): The path name of the - `os-release file`_ that is actually used as a data source. The - empty string if no distro release file is used as a data source. - - * ``distro_release_file`` (string): The path name of the - `distro release file`_ that is actually used as a data source. The - empty string if no distro release file is used as a data source. - - * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. - This controls whether the lsb information will be loaded. - - * ``include_uname`` (bool): The result of the ``include_uname`` - parameter. This controls whether the uname information will - be loaded. - - Raises: - - * :py:exc:`IOError`: Some I/O issue with an os-release file or distro - release file. - - * :py:exc:`subprocess.CalledProcessError`: The lsb_release command had - some issue (other than not being available in the program execution - path). - - * :py:exc:`UnicodeError`: A data source has unexpected characters or - uses an unexpected encoding. - """ - self.os_release_file = os_release_file or \ - os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME) - self.distro_release_file = distro_release_file or '' # updated later - self.include_lsb = include_lsb - self.include_uname = include_uname - - def __repr__(self): - """Return repr of all info - """ - return \ - "LinuxDistribution(" \ - "os_release_file={self.os_release_file!r}, " \ - "distro_release_file={self.distro_release_file!r}, " \ - "include_lsb={self.include_lsb!r}, " \ - "include_uname={self.include_uname!r}, " \ - "_os_release_info={self._os_release_info!r}, " \ - "_lsb_release_info={self._lsb_release_info!r}, " \ - "_distro_release_info={self._distro_release_info!r}, " \ - "_uname_info={self._uname_info!r})".format( - self=self) - - def linux_distribution(self, full_distribution_name=True): - """ - Return information about the OS distribution that is compatible - with Python's :func:`platform.linux_distribution`, supporting a subset - of its parameters. - - For details, see :func:`distro.linux_distribution`. - """ - return ( - self.name() if full_distribution_name else self.id(), - self.version(), - self.codename() - ) - - def id(self): - """Return the distro ID of the OS distribution, as a string. - - For details, see :func:`distro.id`. - """ - def normalize(distro_id, table): - distro_id = distro_id.lower().replace(' ', '_') - return table.get(distro_id, distro_id) - - distro_id = self.os_release_attr('id') - if distro_id: - return normalize(distro_id, NORMALIZED_OS_ID) - - distro_id = self.lsb_release_attr('distributor_id') - if distro_id: - return normalize(distro_id, NORMALIZED_LSB_ID) - - distro_id = self.distro_release_attr('id') - if distro_id: - return normalize(distro_id, NORMALIZED_DISTRO_ID) - - distro_id = self.uname_attr('id') - if distro_id: - return normalize(distro_id, NORMALIZED_DISTRO_ID) - - return '' - - def name(self, pretty=False): - """ - Return the name of the OS distribution, as a string. - - For details, see :func:`distro.name`. - """ - name = self.os_release_attr('name') \ - or self.lsb_release_attr('distributor_id') \ - or self.distro_release_attr('name') \ - or self.uname_attr('name') - if pretty: - name = self.os_release_attr('pretty_name') \ - or self.lsb_release_attr('description') - if not name: - name = self.distro_release_attr('name') \ - or self.uname_attr('name') - version = self.version(pretty=True) - if version: - name = name + ' ' + version - return name or '' - - def version(self, pretty=False, best=False): - """ - Return the version of the OS distribution, as a string. - - For details, see :func:`distro.version`. - """ - versions = [ - self.os_release_attr('version_id'), - self.lsb_release_attr('release'), - self.distro_release_attr('version_id'), - self._parse_distro_release_content( - self.os_release_attr('pretty_name')).get('version_id', ''), - self._parse_distro_release_content( - self.lsb_release_attr('description')).get('version_id', ''), - self.uname_attr('release') - ] - version = '' - if best: - # This algorithm uses the last version in priority order that has - # the best precision. If the versions are not in conflict, that - # does not matter; otherwise, using the last one instead of the - # first one might be considered a surprise. - for v in versions: - if v.count(".") > version.count(".") or version == '': - version = v - else: - for v in versions: - if v != '': - version = v - break - if pretty and version and self.codename(): - version = '{0} ({1})'.format(version, self.codename()) - return version - - def version_parts(self, best=False): - """ - Return the version of the OS distribution, as a tuple of version - numbers. - - For details, see :func:`distro.version_parts`. - """ - version_str = self.version(best=best) - if version_str: - version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?') - matches = version_regex.match(version_str) - if matches: - major, minor, build_number = matches.groups() - return major, minor or '', build_number or '' - return '', '', '' - - def major_version(self, best=False): - """ - Return the major version number of the current distribution. - - For details, see :func:`distro.major_version`. - """ - return self.version_parts(best)[0] - - def minor_version(self, best=False): - """ - Return the minor version number of the current distribution. - - For details, see :func:`distro.minor_version`. - """ - return self.version_parts(best)[1] - - def build_number(self, best=False): - """ - Return the build number of the current distribution. - - For details, see :func:`distro.build_number`. - """ - return self.version_parts(best)[2] - - def like(self): - """ - Return the IDs of distributions that are like the OS distribution. - - For details, see :func:`distro.like`. - """ - return self.os_release_attr('id_like') or '' - - def codename(self): - """ - Return the codename of the OS distribution. - - For details, see :func:`distro.codename`. - """ - try: - # Handle os_release specially since distros might purposefully set - # this to empty string to have no codename - return self._os_release_info['codename'] - except KeyError: - return self.lsb_release_attr('codename') \ - or self.distro_release_attr('codename') \ - or '' - - def info(self, pretty=False, best=False): - """ - Return certain machine-readable information about the OS - distribution. - - For details, see :func:`distro.info`. - """ - return dict( - id=self.id(), - version=self.version(pretty, best), - version_parts=dict( - major=self.major_version(best), - minor=self.minor_version(best), - build_number=self.build_number(best) - ), - like=self.like(), - codename=self.codename(), - ) - - def os_release_info(self): - """ - Return a dictionary containing key-value pairs for the information - items from the os-release file data source of the OS distribution. - - For details, see :func:`distro.os_release_info`. - """ - return self._os_release_info - - def lsb_release_info(self): - """ - Return a dictionary containing key-value pairs for the information - items from the lsb_release command data source of the OS - distribution. - - For details, see :func:`distro.lsb_release_info`. - """ - return self._lsb_release_info - - def distro_release_info(self): - """ - Return a dictionary containing key-value pairs for the information - items from the distro release file data source of the OS - distribution. - - For details, see :func:`distro.distro_release_info`. - """ - return self._distro_release_info - - def uname_info(self): - """ - Return a dictionary containing key-value pairs for the information - items from the uname command data source of the OS distribution. - - For details, see :func:`distro.uname_info`. - """ - return self._uname_info - - def os_release_attr(self, attribute): - """ - Return a single named information item from the os-release file data - source of the OS distribution. - - For details, see :func:`distro.os_release_attr`. - """ - return self._os_release_info.get(attribute, '') - - def lsb_release_attr(self, attribute): - """ - Return a single named information item from the lsb_release command - output data source of the OS distribution. - - For details, see :func:`distro.lsb_release_attr`. - """ - return self._lsb_release_info.get(attribute, '') - - def distro_release_attr(self, attribute): - """ - Return a single named information item from the distro release file - data source of the OS distribution. - - For details, see :func:`distro.distro_release_attr`. - """ - return self._distro_release_info.get(attribute, '') - - def uname_attr(self, attribute): - """ - Return a single named information item from the uname command - output data source of the OS distribution. - - For details, see :func:`distro.uname_release_attr`. - """ - return self._uname_info.get(attribute, '') - - @cached_property - def _os_release_info(self): - """ - Get the information items from the specified os-release file. - - Returns: - A dictionary containing all information items. - """ - if os.path.isfile(self.os_release_file): - with open(self.os_release_file) as release_file: - return self._parse_os_release_content(release_file) - return {} - - @staticmethod - def _parse_os_release_content(lines): - """ - Parse the lines of an os-release file. - - Parameters: - - * lines: Iterable through the lines in the os-release file. - Each line must be a unicode string or a UTF-8 encoded byte - string. - - Returns: - A dictionary containing all information items. - """ - props = {} - lexer = shlex.shlex(lines, posix=True) - lexer.whitespace_split = True - - # The shlex module defines its `wordchars` variable using literals, - # making it dependent on the encoding of the Python source file. - # In Python 2.6 and 2.7, the shlex source file is encoded in - # 'iso-8859-1', and the `wordchars` variable is defined as a byte - # string. This causes a UnicodeDecodeError to be raised when the - # parsed content is a unicode object. The following fix resolves that - # (... but it should be fixed in shlex...): - if sys.version_info[0] == 2 and isinstance(lexer.wordchars, bytes): - lexer.wordchars = lexer.wordchars.decode('iso-8859-1') - - tokens = list(lexer) - for token in tokens: - # At this point, all shell-like parsing has been done (i.e. - # comments processed, quotes and backslash escape sequences - # processed, multi-line values assembled, trailing newlines - # stripped, etc.), so the tokens are now either: - # * variable assignments: var=value - # * commands or their arguments (not allowed in os-release) - if '=' in token: - k, v = token.split('=', 1) - props[k.lower()] = v - else: - # Ignore any tokens that are not variable assignments - pass - - if 'version_codename' in props: - # os-release added a version_codename field. Use that in - # preference to anything else Note that some distros purposefully - # do not have code names. They should be setting - # version_codename="" - props['codename'] = props['version_codename'] - elif 'ubuntu_codename' in props: - # Same as above but a non-standard field name used on older Ubuntus - props['codename'] = props['ubuntu_codename'] - elif 'version' in props: - # If there is no version_codename, parse it from the version - codename = re.search(r'(\(\D+\))|,(\s+)?\D+', props['version']) - if codename: - codename = codename.group() - codename = codename.strip('()') - codename = codename.strip(',') - codename = codename.strip() - # codename appears within paranthese. - props['codename'] = codename - - return props - - @cached_property - def _lsb_release_info(self): - """ - Get the information items from the lsb_release command output. - - Returns: - A dictionary containing all information items. - """ - if not self.include_lsb: - return {} - with open(os.devnull, 'w') as devnull: - try: - cmd = ('lsb_release', '-a') - stdout = subprocess.check_output(cmd, stderr=devnull) - except OSError: # Command not found - return {} - content = self._to_str(stdout).splitlines() - return self._parse_lsb_release_content(content) - - @staticmethod - def _parse_lsb_release_content(lines): - """ - Parse the output of the lsb_release command. - - Parameters: - - * lines: Iterable through the lines of the lsb_release output. - Each line must be a unicode string or a UTF-8 encoded byte - string. - - Returns: - A dictionary containing all information items. - """ - props = {} - for line in lines: - kv = line.strip('\n').split(':', 1) - if len(kv) != 2: - # Ignore lines without colon. - continue - k, v = kv - props.update({k.replace(' ', '_').lower(): v.strip()}) - return props - - @cached_property - def _uname_info(self): - with open(os.devnull, 'w') as devnull: - try: - cmd = ('uname', '-rs') - stdout = subprocess.check_output(cmd, stderr=devnull) - except OSError: - return {} - content = self._to_str(stdout).splitlines() - return self._parse_uname_content(content) - - @staticmethod - def _parse_uname_content(lines): - props = {} - match = re.search(r'^([^\s]+)\s+([\d\.]+)', lines[0].strip()) - if match: - name, version = match.groups() - - # This is to prevent the Linux kernel version from - # appearing as the 'best' version on otherwise - # identifiable distributions. - if name == 'Linux': - return {} - props['id'] = name.lower() - props['name'] = name - props['release'] = version - return props - - @staticmethod - def _to_str(text): - encoding = sys.getfilesystemencoding() - encoding = 'utf-8' if encoding == 'ascii' else encoding - - if sys.version_info[0] >= 3: - if isinstance(text, bytes): - return text.decode(encoding) - else: - if isinstance(text, unicode): # noqa - return text.encode(encoding) - - return text - - @cached_property - def _distro_release_info(self): - """ - Get the information items from the specified distro release file. - - Returns: - A dictionary containing all information items. - """ - if self.distro_release_file: - # If it was specified, we use it and parse what we can, even if - # its file name or content does not match the expected pattern. - distro_info = self._parse_distro_release_file( - self.distro_release_file) - basename = os.path.basename(self.distro_release_file) - # The file name pattern for user-specified distro release files - # is somewhat more tolerant (compared to when searching for the - # file), because we want to use what was specified as best as - # possible. - match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) - if 'name' in distro_info \ - and 'cloudlinux' in distro_info['name'].lower(): - distro_info['id'] = 'cloudlinux' - elif match: - distro_info['id'] = match.group(1) - return distro_info - else: - try: - basenames = os.listdir(_UNIXCONFDIR) - # We sort for repeatability in cases where there are multiple - # distro specific files; e.g. CentOS, Oracle, Enterprise all - # containing `redhat-release` on top of their own. - basenames.sort() - except OSError: - # This may occur when /etc is not readable but we can't be - # sure about the *-release files. Check common entries of - # /etc for information. If they turn out to not be there the - # error is handled in `_parse_distro_release_file()`. - basenames = ['SuSE-release', - 'arch-release', - 'base-release', - 'centos-release', - 'fedora-release', - 'gentoo-release', - 'mageia-release', - 'mandrake-release', - 'mandriva-release', - 'mandrivalinux-release', - 'manjaro-release', - 'oracle-release', - 'redhat-release', - 'sl-release', - 'slackware-version'] - for basename in basenames: - if basename in _DISTRO_RELEASE_IGNORE_BASENAMES: - continue - match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) - if match: - filepath = os.path.join(_UNIXCONFDIR, basename) - distro_info = self._parse_distro_release_file(filepath) - if 'name' in distro_info: - # The name is always present if the pattern matches - self.distro_release_file = filepath - distro_info['id'] = match.group(1) - if 'cloudlinux' in distro_info['name'].lower(): - distro_info['id'] = 'cloudlinux' - return distro_info - return {} - - def _parse_distro_release_file(self, filepath): - """ - Parse a distro release file. - - Parameters: - - * filepath: Path name of the distro release file. - - Returns: - A dictionary containing all information items. - """ - try: - with open(filepath) as fp: - # Only parse the first line. For instance, on SLES there - # are multiple lines. We don't want them... - return self._parse_distro_release_content(fp.readline()) - except (OSError, IOError): - # Ignore not being able to read a specific, seemingly version - # related file. - # See https://github.com/nir0s/distro/issues/162 - return {} - - @staticmethod - def _parse_distro_release_content(line): - """ - Parse a line from a distro release file. - - Parameters: - * line: Line from the distro release file. Must be a unicode string - or a UTF-8 encoded byte string. - - Returns: - A dictionary containing all information items. - """ - matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match( - line.strip()[::-1]) - distro_info = {} - if matches: - # regexp ensures non-None - distro_info['name'] = matches.group(3)[::-1] - if matches.group(2): - distro_info['version_id'] = matches.group(2)[::-1] - if matches.group(1): - distro_info['codename'] = matches.group(1)[::-1] - elif line: - distro_info['name'] = line.strip() - return distro_info - - -_distro = LinuxDistribution() - - -def main(): - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - logger.addHandler(logging.StreamHandler(sys.stdout)) - - parser = argparse.ArgumentParser(description="OS distro info tool") - parser.add_argument( - '--json', - '-j', - help="Output in machine readable format", - action="store_true") - args = parser.parse_args() - - if args.json: - logger.info(json.dumps(info(), indent=4, sort_keys=True)) - else: - logger.info('Name: %s', name(pretty=True)) - distribution_version = version(pretty=True) - logger.info('Version: %s', distribution_version) - distribution_codename = codename() - logger.info('Codename: %s', distribution_codename) - - -if __name__ == '__main__': - main() diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/__init__.py deleted file mode 100644 index d1d82f1..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -HTML parsing library based on the `WHATWG HTML specification -`_. The parser is designed to be compatible with -existing HTML found in the wild and implements well-defined error recovery that -is largely compatible with modern desktop web browsers. - -Example usage:: - - from pip._vendor import html5lib - with open("my_document.html", "rb") as f: - tree = html5lib.parse(f) - -For convenience, this module re-exports the following names: - -* :func:`~.html5parser.parse` -* :func:`~.html5parser.parseFragment` -* :class:`~.html5parser.HTMLParser` -* :func:`~.treebuilders.getTreeBuilder` -* :func:`~.treewalkers.getTreeWalker` -* :func:`~.serializer.serialize` -""" - -from __future__ import absolute_import, division, unicode_literals - -from .html5parser import HTMLParser, parse, parseFragment -from .treebuilders import getTreeBuilder -from .treewalkers import getTreeWalker -from .serializer import serialize - -__all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder", - "getTreeWalker", "serialize"] - -# this has to be at the top level, see how setup.py parses this -#: Distribution version number. -__version__ = "1.1" diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_ihatexml.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_ihatexml.py deleted file mode 100644 index 3ff803c..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_ihatexml.py +++ /dev/null @@ -1,289 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import re -import warnings - -from .constants import DataLossWarning - -baseChar = """ -[#x0041-#x005A] | [#x0061-#x007A] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | -[#x00F8-#x00FF] | [#x0100-#x0131] | [#x0134-#x013E] | [#x0141-#x0148] | -[#x014A-#x017E] | [#x0180-#x01C3] | [#x01CD-#x01F0] | [#x01F4-#x01F5] | -[#x01FA-#x0217] | [#x0250-#x02A8] | [#x02BB-#x02C1] | #x0386 | -[#x0388-#x038A] | #x038C | [#x038E-#x03A1] | [#x03A3-#x03CE] | -[#x03D0-#x03D6] | #x03DA | #x03DC | #x03DE | #x03E0 | [#x03E2-#x03F3] | -[#x0401-#x040C] | [#x040E-#x044F] | [#x0451-#x045C] | [#x045E-#x0481] | -[#x0490-#x04C4] | [#x04C7-#x04C8] | [#x04CB-#x04CC] | [#x04D0-#x04EB] | -[#x04EE-#x04F5] | [#x04F8-#x04F9] | [#x0531-#x0556] | #x0559 | -[#x0561-#x0586] | [#x05D0-#x05EA] | [#x05F0-#x05F2] | [#x0621-#x063A] | -[#x0641-#x064A] | [#x0671-#x06B7] | [#x06BA-#x06BE] | [#x06C0-#x06CE] | -[#x06D0-#x06D3] | #x06D5 | [#x06E5-#x06E6] | [#x0905-#x0939] | #x093D | -[#x0958-#x0961] | [#x0985-#x098C] | [#x098F-#x0990] | [#x0993-#x09A8] | -[#x09AA-#x09B0] | #x09B2 | [#x09B6-#x09B9] | [#x09DC-#x09DD] | -[#x09DF-#x09E1] | [#x09F0-#x09F1] | [#x0A05-#x0A0A] | [#x0A0F-#x0A10] | -[#x0A13-#x0A28] | [#x0A2A-#x0A30] | [#x0A32-#x0A33] | [#x0A35-#x0A36] | -[#x0A38-#x0A39] | [#x0A59-#x0A5C] | #x0A5E | [#x0A72-#x0A74] | -[#x0A85-#x0A8B] | #x0A8D | [#x0A8F-#x0A91] | [#x0A93-#x0AA8] | -[#x0AAA-#x0AB0] | [#x0AB2-#x0AB3] | [#x0AB5-#x0AB9] | #x0ABD | #x0AE0 | -[#x0B05-#x0B0C] | [#x0B0F-#x0B10] | [#x0B13-#x0B28] | [#x0B2A-#x0B30] | -[#x0B32-#x0B33] | [#x0B36-#x0B39] | #x0B3D | [#x0B5C-#x0B5D] | -[#x0B5F-#x0B61] | [#x0B85-#x0B8A] | [#x0B8E-#x0B90] | [#x0B92-#x0B95] | -[#x0B99-#x0B9A] | #x0B9C | [#x0B9E-#x0B9F] | [#x0BA3-#x0BA4] | -[#x0BA8-#x0BAA] | [#x0BAE-#x0BB5] | [#x0BB7-#x0BB9] | [#x0C05-#x0C0C] | -[#x0C0E-#x0C10] | [#x0C12-#x0C28] | [#x0C2A-#x0C33] | [#x0C35-#x0C39] | -[#x0C60-#x0C61] | [#x0C85-#x0C8C] | [#x0C8E-#x0C90] | [#x0C92-#x0CA8] | -[#x0CAA-#x0CB3] | [#x0CB5-#x0CB9] | #x0CDE | [#x0CE0-#x0CE1] | -[#x0D05-#x0D0C] | [#x0D0E-#x0D10] | [#x0D12-#x0D28] | [#x0D2A-#x0D39] | -[#x0D60-#x0D61] | [#x0E01-#x0E2E] | #x0E30 | [#x0E32-#x0E33] | -[#x0E40-#x0E45] | [#x0E81-#x0E82] | #x0E84 | [#x0E87-#x0E88] | #x0E8A | -#x0E8D | [#x0E94-#x0E97] | [#x0E99-#x0E9F] | [#x0EA1-#x0EA3] | #x0EA5 | -#x0EA7 | [#x0EAA-#x0EAB] | [#x0EAD-#x0EAE] | #x0EB0 | [#x0EB2-#x0EB3] | -#x0EBD | [#x0EC0-#x0EC4] | [#x0F40-#x0F47] | [#x0F49-#x0F69] | -[#x10A0-#x10C5] | [#x10D0-#x10F6] | #x1100 | [#x1102-#x1103] | -[#x1105-#x1107] | #x1109 | [#x110B-#x110C] | [#x110E-#x1112] | #x113C | -#x113E | #x1140 | #x114C | #x114E | #x1150 | [#x1154-#x1155] | #x1159 | -[#x115F-#x1161] | #x1163 | #x1165 | #x1167 | #x1169 | [#x116D-#x116E] | -[#x1172-#x1173] | #x1175 | #x119E | #x11A8 | #x11AB | [#x11AE-#x11AF] | -[#x11B7-#x11B8] | #x11BA | [#x11BC-#x11C2] | #x11EB | #x11F0 | #x11F9 | -[#x1E00-#x1E9B] | [#x1EA0-#x1EF9] | [#x1F00-#x1F15] | [#x1F18-#x1F1D] | -[#x1F20-#x1F45] | [#x1F48-#x1F4D] | [#x1F50-#x1F57] | #x1F59 | #x1F5B | -#x1F5D | [#x1F5F-#x1F7D] | [#x1F80-#x1FB4] | [#x1FB6-#x1FBC] | #x1FBE | -[#x1FC2-#x1FC4] | [#x1FC6-#x1FCC] | [#x1FD0-#x1FD3] | [#x1FD6-#x1FDB] | -[#x1FE0-#x1FEC] | [#x1FF2-#x1FF4] | [#x1FF6-#x1FFC] | #x2126 | -[#x212A-#x212B] | #x212E | [#x2180-#x2182] | [#x3041-#x3094] | -[#x30A1-#x30FA] | [#x3105-#x312C] | [#xAC00-#xD7A3]""" - -ideographic = """[#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]""" - -combiningCharacter = """ -[#x0300-#x0345] | [#x0360-#x0361] | [#x0483-#x0486] | [#x0591-#x05A1] | -[#x05A3-#x05B9] | [#x05BB-#x05BD] | #x05BF | [#x05C1-#x05C2] | #x05C4 | -[#x064B-#x0652] | #x0670 | [#x06D6-#x06DC] | [#x06DD-#x06DF] | -[#x06E0-#x06E4] | [#x06E7-#x06E8] | [#x06EA-#x06ED] | [#x0901-#x0903] | -#x093C | [#x093E-#x094C] | #x094D | [#x0951-#x0954] | [#x0962-#x0963] | -[#x0981-#x0983] | #x09BC | #x09BE | #x09BF | [#x09C0-#x09C4] | -[#x09C7-#x09C8] | [#x09CB-#x09CD] | #x09D7 | [#x09E2-#x09E3] | #x0A02 | -#x0A3C | #x0A3E | #x0A3F | [#x0A40-#x0A42] | [#x0A47-#x0A48] | -[#x0A4B-#x0A4D] | [#x0A70-#x0A71] | [#x0A81-#x0A83] | #x0ABC | -[#x0ABE-#x0AC5] | [#x0AC7-#x0AC9] | [#x0ACB-#x0ACD] | [#x0B01-#x0B03] | -#x0B3C | [#x0B3E-#x0B43] | [#x0B47-#x0B48] | [#x0B4B-#x0B4D] | -[#x0B56-#x0B57] | [#x0B82-#x0B83] | [#x0BBE-#x0BC2] | [#x0BC6-#x0BC8] | -[#x0BCA-#x0BCD] | #x0BD7 | [#x0C01-#x0C03] | [#x0C3E-#x0C44] | -[#x0C46-#x0C48] | [#x0C4A-#x0C4D] | [#x0C55-#x0C56] | [#x0C82-#x0C83] | -[#x0CBE-#x0CC4] | [#x0CC6-#x0CC8] | [#x0CCA-#x0CCD] | [#x0CD5-#x0CD6] | -[#x0D02-#x0D03] | [#x0D3E-#x0D43] | [#x0D46-#x0D48] | [#x0D4A-#x0D4D] | -#x0D57 | #x0E31 | [#x0E34-#x0E3A] | [#x0E47-#x0E4E] | #x0EB1 | -[#x0EB4-#x0EB9] | [#x0EBB-#x0EBC] | [#x0EC8-#x0ECD] | [#x0F18-#x0F19] | -#x0F35 | #x0F37 | #x0F39 | #x0F3E | #x0F3F | [#x0F71-#x0F84] | -[#x0F86-#x0F8B] | [#x0F90-#x0F95] | #x0F97 | [#x0F99-#x0FAD] | -[#x0FB1-#x0FB7] | #x0FB9 | [#x20D0-#x20DC] | #x20E1 | [#x302A-#x302F] | -#x3099 | #x309A""" - -digit = """ -[#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] | -[#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] | -[#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] | -[#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29]""" - -extender = """ -#x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 | -#[#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE]""" - -letter = " | ".join([baseChar, ideographic]) - -# Without the -name = " | ".join([letter, digit, ".", "-", "_", combiningCharacter, - extender]) -nameFirst = " | ".join([letter, "_"]) - -reChar = re.compile(r"#x([\d|A-F]{4,4})") -reCharRange = re.compile(r"\[#x([\d|A-F]{4,4})-#x([\d|A-F]{4,4})\]") - - -def charStringToList(chars): - charRanges = [item.strip() for item in chars.split(" | ")] - rv = [] - for item in charRanges: - foundMatch = False - for regexp in (reChar, reCharRange): - match = regexp.match(item) - if match is not None: - rv.append([hexToInt(item) for item in match.groups()]) - if len(rv[-1]) == 1: - rv[-1] = rv[-1] * 2 - foundMatch = True - break - if not foundMatch: - assert len(item) == 1 - - rv.append([ord(item)] * 2) - rv = normaliseCharList(rv) - return rv - - -def normaliseCharList(charList): - charList = sorted(charList) - for item in charList: - assert item[1] >= item[0] - rv = [] - i = 0 - while i < len(charList): - j = 1 - rv.append(charList[i]) - while i + j < len(charList) and charList[i + j][0] <= rv[-1][1] + 1: - rv[-1][1] = charList[i + j][1] - j += 1 - i += j - return rv - - -# We don't really support characters above the BMP :( -max_unicode = int("FFFF", 16) - - -def missingRanges(charList): - rv = [] - if charList[0] != 0: - rv.append([0, charList[0][0] - 1]) - for i, item in enumerate(charList[:-1]): - rv.append([item[1] + 1, charList[i + 1][0] - 1]) - if charList[-1][1] != max_unicode: - rv.append([charList[-1][1] + 1, max_unicode]) - return rv - - -def listToRegexpStr(charList): - rv = [] - for item in charList: - if item[0] == item[1]: - rv.append(escapeRegexp(chr(item[0]))) - else: - rv.append(escapeRegexp(chr(item[0])) + "-" + - escapeRegexp(chr(item[1]))) - return "[%s]" % "".join(rv) - - -def hexToInt(hex_str): - return int(hex_str, 16) - - -def escapeRegexp(string): - specialCharacters = (".", "^", "$", "*", "+", "?", "{", "}", - "[", "]", "|", "(", ")", "-") - for char in specialCharacters: - string = string.replace(char, "\\" + char) - - return string - -# output from the above -nonXmlNameBMPRegexp = re.compile('[\x00-,/:-@\\[-\\^`\\{-\xb6\xb8-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u02cf\u02d2-\u02ff\u0346-\u035f\u0362-\u0385\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482\u0487-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u0590\u05a2\u05ba\u05be\u05c0\u05c3\u05c5-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u063f\u0653-\u065f\u066a-\u066f\u06b8-\u06b9\u06bf\u06cf\u06d4\u06e9\u06ee-\u06ef\u06fa-\u0900\u0904\u093a-\u093b\u094e-\u0950\u0955-\u0957\u0964-\u0965\u0970-\u0980\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09bb\u09bd\u09c5-\u09c6\u09c9-\u09ca\u09ce-\u09d6\u09d8-\u09db\u09de\u09e4-\u09e5\u09f2-\u0a01\u0a03-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a3b\u0a3d\u0a43-\u0a46\u0a49-\u0a4a\u0a4e-\u0a58\u0a5d\u0a5f-\u0a65\u0a75-\u0a80\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abb\u0ac6\u0aca\u0ace-\u0adf\u0ae1-\u0ae5\u0af0-\u0b00\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3b\u0b44-\u0b46\u0b49-\u0b4a\u0b4e-\u0b55\u0b58-\u0b5b\u0b5e\u0b62-\u0b65\u0b70-\u0b81\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0bbd\u0bc3-\u0bc5\u0bc9\u0bce-\u0bd6\u0bd8-\u0be6\u0bf0-\u0c00\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c3d\u0c45\u0c49\u0c4e-\u0c54\u0c57-\u0c5f\u0c62-\u0c65\u0c70-\u0c81\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cbd\u0cc5\u0cc9\u0cce-\u0cd4\u0cd7-\u0cdd\u0cdf\u0ce2-\u0ce5\u0cf0-\u0d01\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d3d\u0d44-\u0d45\u0d49\u0d4e-\u0d56\u0d58-\u0d5f\u0d62-\u0d65\u0d70-\u0e00\u0e2f\u0e3b-\u0e3f\u0e4f\u0e5a-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eba\u0ebe-\u0ebf\u0ec5\u0ec7\u0ece-\u0ecf\u0eda-\u0f17\u0f1a-\u0f1f\u0f2a-\u0f34\u0f36\u0f38\u0f3a-\u0f3d\u0f48\u0f6a-\u0f70\u0f85\u0f8c-\u0f8f\u0f96\u0f98\u0fae-\u0fb0\u0fb8\u0fba-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u20cf\u20dd-\u20e0\u20e2-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3004\u3006\u3008-\u3020\u3030\u3036-\u3040\u3095-\u3098\u309b-\u309c\u309f-\u30a0\u30fb\u30ff-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa - -nonXmlNameFirstBMPRegexp = re.compile('[\x00-@\\[-\\^`\\{-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u0385\u0387\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u0640\u064b-\u0670\u06b8-\u06b9\u06bf\u06cf\u06d4\u06d6-\u06e4\u06e7-\u0904\u093a-\u093c\u093e-\u0957\u0962-\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09db\u09de\u09e2-\u09ef\u09f2-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a58\u0a5d\u0a5f-\u0a71\u0a75-\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abc\u0abe-\u0adf\u0ae1-\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3c\u0b3e-\u0b5b\u0b5e\u0b62-\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c5f\u0c62-\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cdd\u0cdf\u0ce2-\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d5f\u0d62-\u0e00\u0e2f\u0e31\u0e34-\u0e3f\u0e46-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eb1\u0eb4-\u0ebc\u0ebe-\u0ebf\u0ec5-\u0f3f\u0f48\u0f6a-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3006\u3008-\u3020\u302a-\u3040\u3095-\u30a0\u30fb-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa - -# Simpler things -nonPubidCharRegexp = re.compile("[^\x20\x0D\x0Aa-zA-Z0-9\\-'()+,./:=?;!*#@$_%]") - - -class InfosetFilter(object): - replacementRegexp = re.compile(r"U[\dA-F]{5,5}") - - def __init__(self, - dropXmlnsLocalName=False, - dropXmlnsAttrNs=False, - preventDoubleDashComments=False, - preventDashAtCommentEnd=False, - replaceFormFeedCharacters=True, - preventSingleQuotePubid=False): - - self.dropXmlnsLocalName = dropXmlnsLocalName - self.dropXmlnsAttrNs = dropXmlnsAttrNs - - self.preventDoubleDashComments = preventDoubleDashComments - self.preventDashAtCommentEnd = preventDashAtCommentEnd - - self.replaceFormFeedCharacters = replaceFormFeedCharacters - - self.preventSingleQuotePubid = preventSingleQuotePubid - - self.replaceCache = {} - - def coerceAttribute(self, name, namespace=None): - if self.dropXmlnsLocalName and name.startswith("xmlns:"): - warnings.warn("Attributes cannot begin with xmlns", DataLossWarning) - return None - elif (self.dropXmlnsAttrNs and - namespace == "http://www.w3.org/2000/xmlns/"): - warnings.warn("Attributes cannot be in the xml namespace", DataLossWarning) - return None - else: - return self.toXmlName(name) - - def coerceElement(self, name): - return self.toXmlName(name) - - def coerceComment(self, data): - if self.preventDoubleDashComments: - while "--" in data: - warnings.warn("Comments cannot contain adjacent dashes", DataLossWarning) - data = data.replace("--", "- -") - if data.endswith("-"): - warnings.warn("Comments cannot end in a dash", DataLossWarning) - data += " " - return data - - def coerceCharacters(self, data): - if self.replaceFormFeedCharacters: - for _ in range(data.count("\x0C")): - warnings.warn("Text cannot contain U+000C", DataLossWarning) - data = data.replace("\x0C", " ") - # Other non-xml characters - return data - - def coercePubid(self, data): - dataOutput = data - for char in nonPubidCharRegexp.findall(data): - warnings.warn("Coercing non-XML pubid", DataLossWarning) - replacement = self.getReplacementCharacter(char) - dataOutput = dataOutput.replace(char, replacement) - if self.preventSingleQuotePubid and dataOutput.find("'") >= 0: - warnings.warn("Pubid cannot contain single quote", DataLossWarning) - dataOutput = dataOutput.replace("'", self.getReplacementCharacter("'")) - return dataOutput - - def toXmlName(self, name): - nameFirst = name[0] - nameRest = name[1:] - m = nonXmlNameFirstBMPRegexp.match(nameFirst) - if m: - warnings.warn("Coercing non-XML name: %s" % name, DataLossWarning) - nameFirstOutput = self.getReplacementCharacter(nameFirst) - else: - nameFirstOutput = nameFirst - - nameRestOutput = nameRest - replaceChars = set(nonXmlNameBMPRegexp.findall(nameRest)) - for char in replaceChars: - warnings.warn("Coercing non-XML name: %s" % name, DataLossWarning) - replacement = self.getReplacementCharacter(char) - nameRestOutput = nameRestOutput.replace(char, replacement) - return nameFirstOutput + nameRestOutput - - def getReplacementCharacter(self, char): - if char in self.replaceCache: - replacement = self.replaceCache[char] - else: - replacement = self.escapeChar(char) - return replacement - - def fromXmlName(self, name): - for item in set(self.replacementRegexp.findall(name)): - name = name.replace(item, self.unescapeChar(item)) - return name - - def escapeChar(self, char): - replacement = "U%05X" % ord(char) - self.replaceCache[char] = replacement - return replacement - - def unescapeChar(self, charcode): - return chr(int(charcode[1:], 16)) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_inputstream.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_inputstream.py deleted file mode 100644 index e0bb376..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_inputstream.py +++ /dev/null @@ -1,918 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from pip._vendor.six import text_type -from pip._vendor.six.moves import http_client, urllib - -import codecs -import re -from io import BytesIO, StringIO - -from pip._vendor import webencodings - -from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase -from .constants import _ReparseException -from . import _utils - -# Non-unicode versions of constants for use in the pre-parser -spaceCharactersBytes = frozenset([item.encode("ascii") for item in spaceCharacters]) -asciiLettersBytes = frozenset([item.encode("ascii") for item in asciiLetters]) -asciiUppercaseBytes = frozenset([item.encode("ascii") for item in asciiUppercase]) -spacesAngleBrackets = spaceCharactersBytes | frozenset([b">", b"<"]) - - -invalid_unicode_no_surrogate = "[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]" # noqa - -if _utils.supports_lone_surrogates: - # Use one extra step of indirection and create surrogates with - # eval. Not using this indirection would introduce an illegal - # unicode literal on platforms not supporting such lone - # surrogates. - assert invalid_unicode_no_surrogate[-1] == "]" and invalid_unicode_no_surrogate.count("]") == 1 - invalid_unicode_re = re.compile(invalid_unicode_no_surrogate[:-1] + - eval('"\\uD800-\\uDFFF"') + # pylint:disable=eval-used - "]") -else: - invalid_unicode_re = re.compile(invalid_unicode_no_surrogate) - -non_bmp_invalid_codepoints = {0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, - 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, - 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE, - 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, - 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, - 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, - 0x10FFFE, 0x10FFFF} - -ascii_punctuation_re = re.compile("[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005C\u005B-\u0060\u007B-\u007E]") - -# Cache for charsUntil() -charsUntilRegEx = {} - - -class BufferedStream(object): - """Buffering for streams that do not have buffering of their own - - The buffer is implemented as a list of chunks on the assumption that - joining many strings will be slow since it is O(n**2) - """ - - def __init__(self, stream): - self.stream = stream - self.buffer = [] - self.position = [-1, 0] # chunk number, offset - - def tell(self): - pos = 0 - for chunk in self.buffer[:self.position[0]]: - pos += len(chunk) - pos += self.position[1] - return pos - - def seek(self, pos): - assert pos <= self._bufferedBytes() - offset = pos - i = 0 - while len(self.buffer[i]) < offset: - offset -= len(self.buffer[i]) - i += 1 - self.position = [i, offset] - - def read(self, bytes): - if not self.buffer: - return self._readStream(bytes) - elif (self.position[0] == len(self.buffer) and - self.position[1] == len(self.buffer[-1])): - return self._readStream(bytes) - else: - return self._readFromBuffer(bytes) - - def _bufferedBytes(self): - return sum([len(item) for item in self.buffer]) - - def _readStream(self, bytes): - data = self.stream.read(bytes) - self.buffer.append(data) - self.position[0] += 1 - self.position[1] = len(data) - return data - - def _readFromBuffer(self, bytes): - remainingBytes = bytes - rv = [] - bufferIndex = self.position[0] - bufferOffset = self.position[1] - while bufferIndex < len(self.buffer) and remainingBytes != 0: - assert remainingBytes > 0 - bufferedData = self.buffer[bufferIndex] - - if remainingBytes <= len(bufferedData) - bufferOffset: - bytesToRead = remainingBytes - self.position = [bufferIndex, bufferOffset + bytesToRead] - else: - bytesToRead = len(bufferedData) - bufferOffset - self.position = [bufferIndex, len(bufferedData)] - bufferIndex += 1 - rv.append(bufferedData[bufferOffset:bufferOffset + bytesToRead]) - remainingBytes -= bytesToRead - - bufferOffset = 0 - - if remainingBytes: - rv.append(self._readStream(remainingBytes)) - - return b"".join(rv) - - -def HTMLInputStream(source, **kwargs): - # Work around Python bug #20007: read(0) closes the connection. - # http://bugs.python.org/issue20007 - if (isinstance(source, http_client.HTTPResponse) or - # Also check for addinfourl wrapping HTTPResponse - (isinstance(source, urllib.response.addbase) and - isinstance(source.fp, http_client.HTTPResponse))): - isUnicode = False - elif hasattr(source, "read"): - isUnicode = isinstance(source.read(0), text_type) - else: - isUnicode = isinstance(source, text_type) - - if isUnicode: - encodings = [x for x in kwargs if x.endswith("_encoding")] - if encodings: - raise TypeError("Cannot set an encoding with a unicode input, set %r" % encodings) - - return HTMLUnicodeInputStream(source, **kwargs) - else: - return HTMLBinaryInputStream(source, **kwargs) - - -class HTMLUnicodeInputStream(object): - """Provides a unicode stream of characters to the HTMLTokenizer. - - This class takes care of character encoding and removing or replacing - incorrect byte-sequences and also provides column and line tracking. - - """ - - _defaultChunkSize = 10240 - - def __init__(self, source): - """Initialises the HTMLInputStream. - - HTMLInputStream(source, [encoding]) -> Normalized stream from source - for use by html5lib. - - source can be either a file-object, local filename or a string. - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - - """ - - if not _utils.supports_lone_surrogates: - # Such platforms will have already checked for such - # surrogate errors, so no need to do this checking. - self.reportCharacterErrors = None - elif len("\U0010FFFF") == 1: - self.reportCharacterErrors = self.characterErrorsUCS4 - else: - self.reportCharacterErrors = self.characterErrorsUCS2 - - # List of where new lines occur - self.newLines = [0] - - self.charEncoding = (lookupEncoding("utf-8"), "certain") - self.dataStream = self.openStream(source) - - self.reset() - - def reset(self): - self.chunk = "" - self.chunkSize = 0 - self.chunkOffset = 0 - self.errors = [] - - # number of (complete) lines in previous chunks - self.prevNumLines = 0 - # number of columns in the last line of the previous chunk - self.prevNumCols = 0 - - # Deal with CR LF and surrogates split over chunk boundaries - self._bufferedCharacter = None - - def openStream(self, source): - """Produces a file object from source. - - source can be either a file object, local filename or a string. - - """ - # Already a file object - if hasattr(source, 'read'): - stream = source - else: - stream = StringIO(source) - - return stream - - def _position(self, offset): - chunk = self.chunk - nLines = chunk.count('\n', 0, offset) - positionLine = self.prevNumLines + nLines - lastLinePos = chunk.rfind('\n', 0, offset) - if lastLinePos == -1: - positionColumn = self.prevNumCols + offset - else: - positionColumn = offset - (lastLinePos + 1) - return (positionLine, positionColumn) - - def position(self): - """Returns (line, col) of the current position in the stream.""" - line, col = self._position(self.chunkOffset) - return (line + 1, col) - - def char(self): - """ Read one character from the stream or queue if available. Return - EOF when EOF is reached. - """ - # Read a new chunk from the input stream if necessary - if self.chunkOffset >= self.chunkSize: - if not self.readChunk(): - return EOF - - chunkOffset = self.chunkOffset - char = self.chunk[chunkOffset] - self.chunkOffset = chunkOffset + 1 - - return char - - def readChunk(self, chunkSize=None): - if chunkSize is None: - chunkSize = self._defaultChunkSize - - self.prevNumLines, self.prevNumCols = self._position(self.chunkSize) - - self.chunk = "" - self.chunkSize = 0 - self.chunkOffset = 0 - - data = self.dataStream.read(chunkSize) - - # Deal with CR LF and surrogates broken across chunks - if self._bufferedCharacter: - data = self._bufferedCharacter + data - self._bufferedCharacter = None - elif not data: - # We have no more data, bye-bye stream - return False - - if len(data) > 1: - lastv = ord(data[-1]) - if lastv == 0x0D or 0xD800 <= lastv <= 0xDBFF: - self._bufferedCharacter = data[-1] - data = data[:-1] - - if self.reportCharacterErrors: - self.reportCharacterErrors(data) - - # Replace invalid characters - data = data.replace("\r\n", "\n") - data = data.replace("\r", "\n") - - self.chunk = data - self.chunkSize = len(data) - - return True - - def characterErrorsUCS4(self, data): - for _ in range(len(invalid_unicode_re.findall(data))): - self.errors.append("invalid-codepoint") - - def characterErrorsUCS2(self, data): - # Someone picked the wrong compile option - # You lose - skip = False - for match in invalid_unicode_re.finditer(data): - if skip: - continue - codepoint = ord(match.group()) - pos = match.start() - # Pretty sure there should be endianness issues here - if _utils.isSurrogatePair(data[pos:pos + 2]): - # We have a surrogate pair! - char_val = _utils.surrogatePairToCodepoint(data[pos:pos + 2]) - if char_val in non_bmp_invalid_codepoints: - self.errors.append("invalid-codepoint") - skip = True - elif (codepoint >= 0xD800 and codepoint <= 0xDFFF and - pos == len(data) - 1): - self.errors.append("invalid-codepoint") - else: - skip = False - self.errors.append("invalid-codepoint") - - def charsUntil(self, characters, opposite=False): - """ Returns a string of characters from the stream up to but not - including any character in 'characters' or EOF. 'characters' must be - a container that supports the 'in' method and iteration over its - characters. - """ - - # Use a cache of regexps to find the required characters - try: - chars = charsUntilRegEx[(characters, opposite)] - except KeyError: - if __debug__: - for c in characters: - assert(ord(c) < 128) - regex = "".join(["\\x%02x" % ord(c) for c in characters]) - if not opposite: - regex = "^%s" % regex - chars = charsUntilRegEx[(characters, opposite)] = re.compile("[%s]+" % regex) - - rv = [] - - while True: - # Find the longest matching prefix - m = chars.match(self.chunk, self.chunkOffset) - if m is None: - # If nothing matched, and it wasn't because we ran out of chunk, - # then stop - if self.chunkOffset != self.chunkSize: - break - else: - end = m.end() - # If not the whole chunk matched, return everything - # up to the part that didn't match - if end != self.chunkSize: - rv.append(self.chunk[self.chunkOffset:end]) - self.chunkOffset = end - break - # If the whole remainder of the chunk matched, - # use it all and read the next chunk - rv.append(self.chunk[self.chunkOffset:]) - if not self.readChunk(): - # Reached EOF - break - - r = "".join(rv) - return r - - def unget(self, char): - # Only one character is allowed to be ungotten at once - it must - # be consumed again before any further call to unget - if char is not EOF: - if self.chunkOffset == 0: - # unget is called quite rarely, so it's a good idea to do - # more work here if it saves a bit of work in the frequently - # called char and charsUntil. - # So, just prepend the ungotten character onto the current - # chunk: - self.chunk = char + self.chunk - self.chunkSize += 1 - else: - self.chunkOffset -= 1 - assert self.chunk[self.chunkOffset] == char - - -class HTMLBinaryInputStream(HTMLUnicodeInputStream): - """Provides a unicode stream of characters to the HTMLTokenizer. - - This class takes care of character encoding and removing or replacing - incorrect byte-sequences and also provides column and line tracking. - - """ - - def __init__(self, source, override_encoding=None, transport_encoding=None, - same_origin_parent_encoding=None, likely_encoding=None, - default_encoding="windows-1252", useChardet=True): - """Initialises the HTMLInputStream. - - HTMLInputStream(source, [encoding]) -> Normalized stream from source - for use by html5lib. - - source can be either a file-object, local filename or a string. - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - - """ - # Raw Stream - for unicode objects this will encode to utf-8 and set - # self.charEncoding as appropriate - self.rawStream = self.openStream(source) - - HTMLUnicodeInputStream.__init__(self, self.rawStream) - - # Encoding Information - # Number of bytes to use when looking for a meta element with - # encoding information - self.numBytesMeta = 1024 - # Number of bytes to use when using detecting encoding using chardet - self.numBytesChardet = 100 - # Things from args - self.override_encoding = override_encoding - self.transport_encoding = transport_encoding - self.same_origin_parent_encoding = same_origin_parent_encoding - self.likely_encoding = likely_encoding - self.default_encoding = default_encoding - - # Determine encoding - self.charEncoding = self.determineEncoding(useChardet) - assert self.charEncoding[0] is not None - - # Call superclass - self.reset() - - def reset(self): - self.dataStream = self.charEncoding[0].codec_info.streamreader(self.rawStream, 'replace') - HTMLUnicodeInputStream.reset(self) - - def openStream(self, source): - """Produces a file object from source. - - source can be either a file object, local filename or a string. - - """ - # Already a file object - if hasattr(source, 'read'): - stream = source - else: - stream = BytesIO(source) - - try: - stream.seek(stream.tell()) - except Exception: - stream = BufferedStream(stream) - - return stream - - def determineEncoding(self, chardet=True): - # BOMs take precedence over everything - # This will also read past the BOM if present - charEncoding = self.detectBOM(), "certain" - if charEncoding[0] is not None: - return charEncoding - - # If we've been overridden, we've been overridden - charEncoding = lookupEncoding(self.override_encoding), "certain" - if charEncoding[0] is not None: - return charEncoding - - # Now check the transport layer - charEncoding = lookupEncoding(self.transport_encoding), "certain" - if charEncoding[0] is not None: - return charEncoding - - # Look for meta elements with encoding information - charEncoding = self.detectEncodingMeta(), "tentative" - if charEncoding[0] is not None: - return charEncoding - - # Parent document encoding - charEncoding = lookupEncoding(self.same_origin_parent_encoding), "tentative" - if charEncoding[0] is not None and not charEncoding[0].name.startswith("utf-16"): - return charEncoding - - # "likely" encoding - charEncoding = lookupEncoding(self.likely_encoding), "tentative" - if charEncoding[0] is not None: - return charEncoding - - # Guess with chardet, if available - if chardet: - try: - from pip._vendor.chardet.universaldetector import UniversalDetector - except ImportError: - pass - else: - buffers = [] - detector = UniversalDetector() - while not detector.done: - buffer = self.rawStream.read(self.numBytesChardet) - assert isinstance(buffer, bytes) - if not buffer: - break - buffers.append(buffer) - detector.feed(buffer) - detector.close() - encoding = lookupEncoding(detector.result['encoding']) - self.rawStream.seek(0) - if encoding is not None: - return encoding, "tentative" - - # Try the default encoding - charEncoding = lookupEncoding(self.default_encoding), "tentative" - if charEncoding[0] is not None: - return charEncoding - - # Fallback to html5lib's default if even that hasn't worked - return lookupEncoding("windows-1252"), "tentative" - - def changeEncoding(self, newEncoding): - assert self.charEncoding[1] != "certain" - newEncoding = lookupEncoding(newEncoding) - if newEncoding is None: - return - if newEncoding.name in ("utf-16be", "utf-16le"): - newEncoding = lookupEncoding("utf-8") - assert newEncoding is not None - elif newEncoding == self.charEncoding[0]: - self.charEncoding = (self.charEncoding[0], "certain") - else: - self.rawStream.seek(0) - self.charEncoding = (newEncoding, "certain") - self.reset() - raise _ReparseException("Encoding changed from %s to %s" % (self.charEncoding[0], newEncoding)) - - def detectBOM(self): - """Attempts to detect at BOM at the start of the stream. If - an encoding can be determined from the BOM return the name of the - encoding otherwise return None""" - bomDict = { - codecs.BOM_UTF8: 'utf-8', - codecs.BOM_UTF16_LE: 'utf-16le', codecs.BOM_UTF16_BE: 'utf-16be', - codecs.BOM_UTF32_LE: 'utf-32le', codecs.BOM_UTF32_BE: 'utf-32be' - } - - # Go to beginning of file and read in 4 bytes - string = self.rawStream.read(4) - assert isinstance(string, bytes) - - # Try detecting the BOM using bytes from the string - encoding = bomDict.get(string[:3]) # UTF-8 - seek = 3 - if not encoding: - # Need to detect UTF-32 before UTF-16 - encoding = bomDict.get(string) # UTF-32 - seek = 4 - if not encoding: - encoding = bomDict.get(string[:2]) # UTF-16 - seek = 2 - - # Set the read position past the BOM if one was found, otherwise - # set it to the start of the stream - if encoding: - self.rawStream.seek(seek) - return lookupEncoding(encoding) - else: - self.rawStream.seek(0) - return None - - def detectEncodingMeta(self): - """Report the encoding declared by the meta element - """ - buffer = self.rawStream.read(self.numBytesMeta) - assert isinstance(buffer, bytes) - parser = EncodingParser(buffer) - self.rawStream.seek(0) - encoding = parser.getEncoding() - - if encoding is not None and encoding.name in ("utf-16be", "utf-16le"): - encoding = lookupEncoding("utf-8") - - return encoding - - -class EncodingBytes(bytes): - """String-like object with an associated position and various extra methods - If the position is ever greater than the string length then an exception is - raised""" - def __new__(self, value): - assert isinstance(value, bytes) - return bytes.__new__(self, value.lower()) - - def __init__(self, value): - # pylint:disable=unused-argument - self._position = -1 - - def __iter__(self): - return self - - def __next__(self): - p = self._position = self._position + 1 - if p >= len(self): - raise StopIteration - elif p < 0: - raise TypeError - return self[p:p + 1] - - def next(self): - # Py2 compat - return self.__next__() - - def previous(self): - p = self._position - if p >= len(self): - raise StopIteration - elif p < 0: - raise TypeError - self._position = p = p - 1 - return self[p:p + 1] - - def setPosition(self, position): - if self._position >= len(self): - raise StopIteration - self._position = position - - def getPosition(self): - if self._position >= len(self): - raise StopIteration - if self._position >= 0: - return self._position - else: - return None - - position = property(getPosition, setPosition) - - def getCurrentByte(self): - return self[self.position:self.position + 1] - - currentByte = property(getCurrentByte) - - def skip(self, chars=spaceCharactersBytes): - """Skip past a list of characters""" - p = self.position # use property for the error-checking - while p < len(self): - c = self[p:p + 1] - if c not in chars: - self._position = p - return c - p += 1 - self._position = p - return None - - def skipUntil(self, chars): - p = self.position - while p < len(self): - c = self[p:p + 1] - if c in chars: - self._position = p - return c - p += 1 - self._position = p - return None - - def matchBytes(self, bytes): - """Look for a sequence of bytes at the start of a string. If the bytes - are found return True and advance the position to the byte after the - match. Otherwise return False and leave the position alone""" - rv = self.startswith(bytes, self.position) - if rv: - self.position += len(bytes) - return rv - - def jumpTo(self, bytes): - """Look for the next sequence of bytes matching a given sequence. If - a match is found advance the position to the last byte of the match""" - try: - self._position = self.index(bytes, self.position) + len(bytes) - 1 - except ValueError: - raise StopIteration - return True - - -class EncodingParser(object): - """Mini parser for detecting character encoding from meta elements""" - - def __init__(self, data): - """string - the data to work on for encoding detection""" - self.data = EncodingBytes(data) - self.encoding = None - - def getEncoding(self): - if b"") - - def handleMeta(self): - if self.data.currentByte not in spaceCharactersBytes: - # if we have ") - - def getAttribute(self): - """Return a name,value pair for the next attribute in the stream, - if one is found, or None""" - data = self.data - # Step 1 (skip chars) - c = data.skip(spaceCharactersBytes | frozenset([b"/"])) - assert c is None or len(c) == 1 - # Step 2 - if c in (b">", None): - return None - # Step 3 - attrName = [] - attrValue = [] - # Step 4 attribute name - while True: - if c == b"=" and attrName: - break - elif c in spaceCharactersBytes: - # Step 6! - c = data.skip() - break - elif c in (b"/", b">"): - return b"".join(attrName), b"" - elif c in asciiUppercaseBytes: - attrName.append(c.lower()) - elif c is None: - return None - else: - attrName.append(c) - # Step 5 - c = next(data) - # Step 7 - if c != b"=": - data.previous() - return b"".join(attrName), b"" - # Step 8 - next(data) - # Step 9 - c = data.skip() - # Step 10 - if c in (b"'", b'"'): - # 10.1 - quoteChar = c - while True: - # 10.2 - c = next(data) - # 10.3 - if c == quoteChar: - next(data) - return b"".join(attrName), b"".join(attrValue) - # 10.4 - elif c in asciiUppercaseBytes: - attrValue.append(c.lower()) - # 10.5 - else: - attrValue.append(c) - elif c == b">": - return b"".join(attrName), b"" - elif c in asciiUppercaseBytes: - attrValue.append(c.lower()) - elif c is None: - return None - else: - attrValue.append(c) - # Step 11 - while True: - c = next(data) - if c in spacesAngleBrackets: - return b"".join(attrName), b"".join(attrValue) - elif c in asciiUppercaseBytes: - attrValue.append(c.lower()) - elif c is None: - return None - else: - attrValue.append(c) - - -class ContentAttrParser(object): - def __init__(self, data): - assert isinstance(data, bytes) - self.data = data - - def parse(self): - try: - # Check if the attr name is charset - # otherwise return - self.data.jumpTo(b"charset") - self.data.position += 1 - self.data.skip() - if not self.data.currentByte == b"=": - # If there is no = sign keep looking for attrs - return None - self.data.position += 1 - self.data.skip() - # Look for an encoding between matching quote marks - if self.data.currentByte in (b'"', b"'"): - quoteMark = self.data.currentByte - self.data.position += 1 - oldPosition = self.data.position - if self.data.jumpTo(quoteMark): - return self.data[oldPosition:self.data.position] - else: - return None - else: - # Unquoted value - oldPosition = self.data.position - try: - self.data.skipUntil(spaceCharactersBytes) - return self.data[oldPosition:self.data.position] - except StopIteration: - # Return the whole remaining value - return self.data[oldPosition:] - except StopIteration: - return None - - -def lookupEncoding(encoding): - """Return the python codec name corresponding to an encoding or None if the - string doesn't correspond to a valid encoding.""" - if isinstance(encoding, bytes): - try: - encoding = encoding.decode("ascii") - except UnicodeDecodeError: - return None - - if encoding is not None: - try: - return webencodings.lookup(encoding) - except AttributeError: - return None - else: - return None diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_tokenizer.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_tokenizer.py deleted file mode 100644 index 5f00253..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_tokenizer.py +++ /dev/null @@ -1,1735 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from pip._vendor.six import unichr as chr - -from collections import deque, OrderedDict -from sys import version_info - -from .constants import spaceCharacters -from .constants import entities -from .constants import asciiLetters, asciiUpper2Lower -from .constants import digits, hexDigits, EOF -from .constants import tokenTypes, tagTokenTypes -from .constants import replacementCharacters - -from ._inputstream import HTMLInputStream - -from ._trie import Trie - -entitiesTrie = Trie(entities) - -if version_info >= (3, 7): - attributeMap = dict -else: - attributeMap = OrderedDict - - -class HTMLTokenizer(object): - """ This class takes care of tokenizing HTML. - - * self.currentToken - Holds the token that is currently being processed. - - * self.state - Holds a reference to the method to be invoked... XXX - - * self.stream - Points to HTMLInputStream object. - """ - - def __init__(self, stream, parser=None, **kwargs): - - self.stream = HTMLInputStream(stream, **kwargs) - self.parser = parser - - # Setup the initial tokenizer state - self.escapeFlag = False - self.lastFourChars = [] - self.state = self.dataState - self.escape = False - - # The current token being created - self.currentToken = None - super(HTMLTokenizer, self).__init__() - - def __iter__(self): - """ This is where the magic happens. - - We do our usually processing through the states and when we have a token - to return we yield the token which pauses processing until the next token - is requested. - """ - self.tokenQueue = deque([]) - # Start processing. When EOF is reached self.state will return False - # instead of True and the loop will terminate. - while self.state(): - while self.stream.errors: - yield {"type": tokenTypes["ParseError"], "data": self.stream.errors.pop(0)} - while self.tokenQueue: - yield self.tokenQueue.popleft() - - def consumeNumberEntity(self, isHex): - """This function returns either U+FFFD or the character based on the - decimal or hexadecimal representation. It also discards ";" if present. - If not present self.tokenQueue.append({"type": tokenTypes["ParseError"]}) is invoked. - """ - - allowed = digits - radix = 10 - if isHex: - allowed = hexDigits - radix = 16 - - charStack = [] - - # Consume all the characters that are in range while making sure we - # don't hit an EOF. - c = self.stream.char() - while c in allowed and c is not EOF: - charStack.append(c) - c = self.stream.char() - - # Convert the set of characters consumed to an int. - charAsInt = int("".join(charStack), radix) - - # Certain characters get replaced with others - if charAsInt in replacementCharacters: - char = replacementCharacters[charAsInt] - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "illegal-codepoint-for-numeric-entity", - "datavars": {"charAsInt": charAsInt}}) - elif ((0xD800 <= charAsInt <= 0xDFFF) or - (charAsInt > 0x10FFFF)): - char = "\uFFFD" - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "illegal-codepoint-for-numeric-entity", - "datavars": {"charAsInt": charAsInt}}) - else: - # Should speed up this check somehow (e.g. move the set to a constant) - if ((0x0001 <= charAsInt <= 0x0008) or - (0x000E <= charAsInt <= 0x001F) or - (0x007F <= charAsInt <= 0x009F) or - (0xFDD0 <= charAsInt <= 0xFDEF) or - charAsInt in frozenset([0x000B, 0xFFFE, 0xFFFF, 0x1FFFE, - 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, - 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, - 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, - 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, - 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE, - 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, - 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, - 0xFFFFF, 0x10FFFE, 0x10FFFF])): - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": - "illegal-codepoint-for-numeric-entity", - "datavars": {"charAsInt": charAsInt}}) - try: - # Try/except needed as UCS-2 Python builds' unichar only works - # within the BMP. - char = chr(charAsInt) - except ValueError: - v = charAsInt - 0x10000 - char = chr(0xD800 | (v >> 10)) + chr(0xDC00 | (v & 0x3FF)) - - # Discard the ; if present. Otherwise, put it back on the queue and - # invoke parseError on parser. - if c != ";": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "numeric-entity-without-semicolon"}) - self.stream.unget(c) - - return char - - def consumeEntity(self, allowedChar=None, fromAttribute=False): - # Initialise to the default output for when no entity is matched - output = "&" - - charStack = [self.stream.char()] - if (charStack[0] in spaceCharacters or charStack[0] in (EOF, "<", "&") or - (allowedChar is not None and allowedChar == charStack[0])): - self.stream.unget(charStack[0]) - - elif charStack[0] == "#": - # Read the next character to see if it's hex or decimal - hex = False - charStack.append(self.stream.char()) - if charStack[-1] in ("x", "X"): - hex = True - charStack.append(self.stream.char()) - - # charStack[-1] should be the first digit - if (hex and charStack[-1] in hexDigits) \ - or (not hex and charStack[-1] in digits): - # At least one digit found, so consume the whole number - self.stream.unget(charStack[-1]) - output = self.consumeNumberEntity(hex) - else: - # No digits found - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "expected-numeric-entity"}) - self.stream.unget(charStack.pop()) - output = "&" + "".join(charStack) - - else: - # At this point in the process might have named entity. Entities - # are stored in the global variable "entities". - # - # Consume characters and compare to these to a substring of the - # entity names in the list until the substring no longer matches. - while (charStack[-1] is not EOF): - if not entitiesTrie.has_keys_with_prefix("".join(charStack)): - break - charStack.append(self.stream.char()) - - # At this point we have a string that starts with some characters - # that may match an entity - # Try to find the longest entity the string will match to take care - # of ¬i for instance. - try: - entityName = entitiesTrie.longest_prefix("".join(charStack[:-1])) - entityLength = len(entityName) - except KeyError: - entityName = None - - if entityName is not None: - if entityName[-1] != ";": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "named-entity-without-semicolon"}) - if (entityName[-1] != ";" and fromAttribute and - (charStack[entityLength] in asciiLetters or - charStack[entityLength] in digits or - charStack[entityLength] == "=")): - self.stream.unget(charStack.pop()) - output = "&" + "".join(charStack) - else: - output = entities[entityName] - self.stream.unget(charStack.pop()) - output += "".join(charStack[entityLength:]) - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-named-entity"}) - self.stream.unget(charStack.pop()) - output = "&" + "".join(charStack) - - if fromAttribute: - self.currentToken["data"][-1][1] += output - else: - if output in spaceCharacters: - tokenType = "SpaceCharacters" - else: - tokenType = "Characters" - self.tokenQueue.append({"type": tokenTypes[tokenType], "data": output}) - - def processEntityInAttribute(self, allowedChar): - """This method replaces the need for "entityInAttributeValueState". - """ - self.consumeEntity(allowedChar=allowedChar, fromAttribute=True) - - def emitCurrentToken(self): - """This method is a generic handler for emitting the tags. It also sets - the state to "data" because that's what's needed after a token has been - emitted. - """ - token = self.currentToken - # Add token to the queue to be yielded - if (token["type"] in tagTokenTypes): - token["name"] = token["name"].translate(asciiUpper2Lower) - if token["type"] == tokenTypes["StartTag"]: - raw = token["data"] - data = attributeMap(raw) - if len(raw) > len(data): - # we had some duplicated attribute, fix so first wins - data.update(raw[::-1]) - token["data"] = data - - if token["type"] == tokenTypes["EndTag"]: - if token["data"]: - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "attributes-in-end-tag"}) - if token["selfClosing"]: - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "self-closing-flag-on-end-tag"}) - self.tokenQueue.append(token) - self.state = self.dataState - - # Below are the various tokenizer states worked out. - def dataState(self): - data = self.stream.char() - if data == "&": - self.state = self.entityDataState - elif data == "<": - self.state = self.tagOpenState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\u0000"}) - elif data is EOF: - # Tokenization ends. - return False - elif data in spaceCharacters: - # Directly after emitting a token you switch back to the "data - # state". At that point spaceCharacters are important so they are - # emitted separately. - self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": - data + self.stream.charsUntil(spaceCharacters, True)}) - # No need to update lastFourChars here, since the first space will - # have already been appended to lastFourChars and will have broken - # any sequences - else: - chars = self.stream.charsUntil(("&", "<", "\u0000")) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": - data + chars}) - return True - - def entityDataState(self): - self.consumeEntity() - self.state = self.dataState - return True - - def rcdataState(self): - data = self.stream.char() - if data == "&": - self.state = self.characterReferenceInRcdata - elif data == "<": - self.state = self.rcdataLessThanSignState - elif data == EOF: - # Tokenization ends. - return False - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - elif data in spaceCharacters: - # Directly after emitting a token you switch back to the "data - # state". At that point spaceCharacters are important so they are - # emitted separately. - self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": - data + self.stream.charsUntil(spaceCharacters, True)}) - # No need to update lastFourChars here, since the first space will - # have already been appended to lastFourChars and will have broken - # any sequences - else: - chars = self.stream.charsUntil(("&", "<", "\u0000")) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": - data + chars}) - return True - - def characterReferenceInRcdata(self): - self.consumeEntity() - self.state = self.rcdataState - return True - - def rawtextState(self): - data = self.stream.char() - if data == "<": - self.state = self.rawtextLessThanSignState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - elif data == EOF: - # Tokenization ends. - return False - else: - chars = self.stream.charsUntil(("<", "\u0000")) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": - data + chars}) - return True - - def scriptDataState(self): - data = self.stream.char() - if data == "<": - self.state = self.scriptDataLessThanSignState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - elif data == EOF: - # Tokenization ends. - return False - else: - chars = self.stream.charsUntil(("<", "\u0000")) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": - data + chars}) - return True - - def plaintextState(self): - data = self.stream.char() - if data == EOF: - # Tokenization ends. - return False - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": - data + self.stream.charsUntil("\u0000")}) - return True - - def tagOpenState(self): - data = self.stream.char() - if data == "!": - self.state = self.markupDeclarationOpenState - elif data == "/": - self.state = self.closeTagOpenState - elif data in asciiLetters: - self.currentToken = {"type": tokenTypes["StartTag"], - "name": data, "data": [], - "selfClosing": False, - "selfClosingAcknowledged": False} - self.state = self.tagNameState - elif data == ">": - # XXX In theory it could be something besides a tag name. But - # do we really care? - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-tag-name-but-got-right-bracket"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<>"}) - self.state = self.dataState - elif data == "?": - # XXX In theory it could be something besides a tag name. But - # do we really care? - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-tag-name-but-got-question-mark"}) - self.stream.unget(data) - self.state = self.bogusCommentState - else: - # XXX - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-tag-name"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.stream.unget(data) - self.state = self.dataState - return True - - def closeTagOpenState(self): - data = self.stream.char() - if data in asciiLetters: - self.currentToken = {"type": tokenTypes["EndTag"], "name": data, - "data": [], "selfClosing": False} - self.state = self.tagNameState - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-closing-tag-but-got-right-bracket"}) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-closing-tag-but-got-eof"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "": - self.emitCurrentToken() - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-tag-name"}) - self.state = self.dataState - elif data == "/": - self.state = self.selfClosingStartTagState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["name"] += "\uFFFD" - else: - self.currentToken["name"] += data - # (Don't use charsUntil here, because tag names are - # very short and it's faster to not do anything fancy) - return True - - def rcdataLessThanSignState(self): - data = self.stream.char() - if data == "/": - self.temporaryBuffer = "" - self.state = self.rcdataEndTagOpenState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.stream.unget(data) - self.state = self.rcdataState - return True - - def rcdataEndTagOpenState(self): - data = self.stream.char() - if data in asciiLetters: - self.temporaryBuffer += data - self.state = self.rcdataEndTagNameState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "" and appropriate: - self.currentToken = {"type": tokenTypes["EndTag"], - "name": self.temporaryBuffer, - "data": [], "selfClosing": False} - self.emitCurrentToken() - self.state = self.dataState - elif data in asciiLetters: - self.temporaryBuffer += data - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "" and appropriate: - self.currentToken = {"type": tokenTypes["EndTag"], - "name": self.temporaryBuffer, - "data": [], "selfClosing": False} - self.emitCurrentToken() - self.state = self.dataState - elif data in asciiLetters: - self.temporaryBuffer += data - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "" and appropriate: - self.currentToken = {"type": tokenTypes["EndTag"], - "name": self.temporaryBuffer, - "data": [], "selfClosing": False} - self.emitCurrentToken() - self.state = self.dataState - elif data in asciiLetters: - self.temporaryBuffer += data - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) - self.state = self.scriptDataState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - self.state = self.scriptDataEscapedState - elif data == EOF: - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - self.state = self.scriptDataEscapedState - return True - - def scriptDataEscapedLessThanSignState(self): - data = self.stream.char() - if data == "/": - self.temporaryBuffer = "" - self.state = self.scriptDataEscapedEndTagOpenState - elif data in asciiLetters: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<" + data}) - self.temporaryBuffer = data - self.state = self.scriptDataDoubleEscapeStartState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.stream.unget(data) - self.state = self.scriptDataEscapedState - return True - - def scriptDataEscapedEndTagOpenState(self): - data = self.stream.char() - if data in asciiLetters: - self.temporaryBuffer = data - self.state = self.scriptDataEscapedEndTagNameState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "" and appropriate: - self.currentToken = {"type": tokenTypes["EndTag"], - "name": self.temporaryBuffer, - "data": [], "selfClosing": False} - self.emitCurrentToken() - self.state = self.dataState - elif data in asciiLetters: - self.temporaryBuffer += data - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": ""))): - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - if self.temporaryBuffer.lower() == "script": - self.state = self.scriptDataDoubleEscapedState - else: - self.state = self.scriptDataEscapedState - elif data in asciiLetters: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - self.temporaryBuffer += data - else: - self.stream.unget(data) - self.state = self.scriptDataEscapedState - return True - - def scriptDataDoubleEscapedState(self): - data = self.stream.char() - if data == "-": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) - self.state = self.scriptDataDoubleEscapedDashState - elif data == "<": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.state = self.scriptDataDoubleEscapedLessThanSignState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - elif data == EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-script-in-script"}) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - return True - - def scriptDataDoubleEscapedDashState(self): - data = self.stream.char() - if data == "-": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) - self.state = self.scriptDataDoubleEscapedDashDashState - elif data == "<": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.state = self.scriptDataDoubleEscapedLessThanSignState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - self.state = self.scriptDataDoubleEscapedState - elif data == EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-script-in-script"}) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - self.state = self.scriptDataDoubleEscapedState - return True - - def scriptDataDoubleEscapedDashDashState(self): - data = self.stream.char() - if data == "-": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) - elif data == "<": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) - self.state = self.scriptDataDoubleEscapedLessThanSignState - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) - self.state = self.scriptDataState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": "\uFFFD"}) - self.state = self.scriptDataDoubleEscapedState - elif data == EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-script-in-script"}) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - self.state = self.scriptDataDoubleEscapedState - return True - - def scriptDataDoubleEscapedLessThanSignState(self): - data = self.stream.char() - if data == "/": - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "/"}) - self.temporaryBuffer = "" - self.state = self.scriptDataDoubleEscapeEndState - else: - self.stream.unget(data) - self.state = self.scriptDataDoubleEscapedState - return True - - def scriptDataDoubleEscapeEndState(self): - data = self.stream.char() - if data in (spaceCharacters | frozenset(("/", ">"))): - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - if self.temporaryBuffer.lower() == "script": - self.state = self.scriptDataEscapedState - else: - self.state = self.scriptDataDoubleEscapedState - elif data in asciiLetters: - self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) - self.temporaryBuffer += data - else: - self.stream.unget(data) - self.state = self.scriptDataDoubleEscapedState - return True - - def beforeAttributeNameState(self): - data = self.stream.char() - if data in spaceCharacters: - self.stream.charsUntil(spaceCharacters, True) - elif data in asciiLetters: - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - elif data == ">": - self.emitCurrentToken() - elif data == "/": - self.state = self.selfClosingStartTagState - elif data in ("'", '"', "=", "<"): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "invalid-character-in-attribute-name"}) - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"].append(["\uFFFD", ""]) - self.state = self.attributeNameState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-attribute-name-but-got-eof"}) - self.state = self.dataState - else: - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - return True - - def attributeNameState(self): - data = self.stream.char() - leavingThisState = True - emitToken = False - if data == "=": - self.state = self.beforeAttributeValueState - elif data in asciiLetters: - self.currentToken["data"][-1][0] += data +\ - self.stream.charsUntil(asciiLetters, True) - leavingThisState = False - elif data == ">": - # XXX If we emit here the attributes are converted to a dict - # without being checked and when the code below runs we error - # because data is a dict not a list - emitToken = True - elif data in spaceCharacters: - self.state = self.afterAttributeNameState - elif data == "/": - self.state = self.selfClosingStartTagState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"][-1][0] += "\uFFFD" - leavingThisState = False - elif data in ("'", '"', "<"): - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": - "invalid-character-in-attribute-name"}) - self.currentToken["data"][-1][0] += data - leavingThisState = False - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "eof-in-attribute-name"}) - self.state = self.dataState - else: - self.currentToken["data"][-1][0] += data - leavingThisState = False - - if leavingThisState: - # Attributes are not dropped at this stage. That happens when the - # start tag token is emitted so values can still be safely appended - # to attributes, but we do want to report the parse error in time. - self.currentToken["data"][-1][0] = ( - self.currentToken["data"][-1][0].translate(asciiUpper2Lower)) - for name, _ in self.currentToken["data"][:-1]: - if self.currentToken["data"][-1][0] == name: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "duplicate-attribute"}) - break - # XXX Fix for above XXX - if emitToken: - self.emitCurrentToken() - return True - - def afterAttributeNameState(self): - data = self.stream.char() - if data in spaceCharacters: - self.stream.charsUntil(spaceCharacters, True) - elif data == "=": - self.state = self.beforeAttributeValueState - elif data == ">": - self.emitCurrentToken() - elif data in asciiLetters: - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - elif data == "/": - self.state = self.selfClosingStartTagState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"].append(["\uFFFD", ""]) - self.state = self.attributeNameState - elif data in ("'", '"', "<"): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "invalid-character-after-attribute-name"}) - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-end-of-tag-but-got-eof"}) - self.state = self.dataState - else: - self.currentToken["data"].append([data, ""]) - self.state = self.attributeNameState - return True - - def beforeAttributeValueState(self): - data = self.stream.char() - if data in spaceCharacters: - self.stream.charsUntil(spaceCharacters, True) - elif data == "\"": - self.state = self.attributeValueDoubleQuotedState - elif data == "&": - self.state = self.attributeValueUnQuotedState - self.stream.unget(data) - elif data == "'": - self.state = self.attributeValueSingleQuotedState - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-attribute-value-but-got-right-bracket"}) - self.emitCurrentToken() - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"][-1][1] += "\uFFFD" - self.state = self.attributeValueUnQuotedState - elif data in ("=", "<", "`"): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "equals-in-unquoted-attribute-value"}) - self.currentToken["data"][-1][1] += data - self.state = self.attributeValueUnQuotedState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-attribute-value-but-got-eof"}) - self.state = self.dataState - else: - self.currentToken["data"][-1][1] += data - self.state = self.attributeValueUnQuotedState - return True - - def attributeValueDoubleQuotedState(self): - data = self.stream.char() - if data == "\"": - self.state = self.afterAttributeValueState - elif data == "&": - self.processEntityInAttribute('"') - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"][-1][1] += "\uFFFD" - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-attribute-value-double-quote"}) - self.state = self.dataState - else: - self.currentToken["data"][-1][1] += data +\ - self.stream.charsUntil(("\"", "&", "\u0000")) - return True - - def attributeValueSingleQuotedState(self): - data = self.stream.char() - if data == "'": - self.state = self.afterAttributeValueState - elif data == "&": - self.processEntityInAttribute("'") - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"][-1][1] += "\uFFFD" - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-attribute-value-single-quote"}) - self.state = self.dataState - else: - self.currentToken["data"][-1][1] += data +\ - self.stream.charsUntil(("'", "&", "\u0000")) - return True - - def attributeValueUnQuotedState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.beforeAttributeNameState - elif data == "&": - self.processEntityInAttribute(">") - elif data == ">": - self.emitCurrentToken() - elif data in ('"', "'", "=", "<", "`"): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-character-in-unquoted-attribute-value"}) - self.currentToken["data"][-1][1] += data - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"][-1][1] += "\uFFFD" - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-attribute-value-no-quotes"}) - self.state = self.dataState - else: - self.currentToken["data"][-1][1] += data + self.stream.charsUntil( - frozenset(("&", ">", '"', "'", "=", "<", "`", "\u0000")) | spaceCharacters) - return True - - def afterAttributeValueState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.beforeAttributeNameState - elif data == ">": - self.emitCurrentToken() - elif data == "/": - self.state = self.selfClosingStartTagState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-EOF-after-attribute-value"}) - self.stream.unget(data) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-character-after-attribute-value"}) - self.stream.unget(data) - self.state = self.beforeAttributeNameState - return True - - def selfClosingStartTagState(self): - data = self.stream.char() - if data == ">": - self.currentToken["selfClosing"] = True - self.emitCurrentToken() - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": - "unexpected-EOF-after-solidus-in-tag"}) - self.stream.unget(data) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-character-after-solidus-in-tag"}) - self.stream.unget(data) - self.state = self.beforeAttributeNameState - return True - - def bogusCommentState(self): - # Make a new comment token and give it as value all the characters - # until the first > or EOF (charsUntil checks for EOF automatically) - # and emit it. - data = self.stream.charsUntil(">") - data = data.replace("\u0000", "\uFFFD") - self.tokenQueue.append( - {"type": tokenTypes["Comment"], "data": data}) - - # Eat the character directly after the bogus comment which is either a - # ">" or an EOF. - self.stream.char() - self.state = self.dataState - return True - - def markupDeclarationOpenState(self): - charStack = [self.stream.char()] - if charStack[-1] == "-": - charStack.append(self.stream.char()) - if charStack[-1] == "-": - self.currentToken = {"type": tokenTypes["Comment"], "data": ""} - self.state = self.commentStartState - return True - elif charStack[-1] in ('d', 'D'): - matched = True - for expected in (('o', 'O'), ('c', 'C'), ('t', 'T'), - ('y', 'Y'), ('p', 'P'), ('e', 'E')): - charStack.append(self.stream.char()) - if charStack[-1] not in expected: - matched = False - break - if matched: - self.currentToken = {"type": tokenTypes["Doctype"], - "name": "", - "publicId": None, "systemId": None, - "correct": True} - self.state = self.doctypeState - return True - elif (charStack[-1] == "[" and - self.parser is not None and - self.parser.tree.openElements and - self.parser.tree.openElements[-1].namespace != self.parser.tree.defaultNamespace): - matched = True - for expected in ["C", "D", "A", "T", "A", "["]: - charStack.append(self.stream.char()) - if charStack[-1] != expected: - matched = False - break - if matched: - self.state = self.cdataSectionState - return True - - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-dashes-or-doctype"}) - - while charStack: - self.stream.unget(charStack.pop()) - self.state = self.bogusCommentState - return True - - def commentStartState(self): - data = self.stream.char() - if data == "-": - self.state = self.commentStartDashState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "incorrect-comment"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-comment"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["data"] += data - self.state = self.commentState - return True - - def commentStartDashState(self): - data = self.stream.char() - if data == "-": - self.state = self.commentEndState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "-\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "incorrect-comment"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-comment"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["data"] += "-" + data - self.state = self.commentState - return True - - def commentState(self): - data = self.stream.char() - if data == "-": - self.state = self.commentEndDashState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "\uFFFD" - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "eof-in-comment"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["data"] += data + \ - self.stream.charsUntil(("-", "\u0000")) - return True - - def commentEndDashState(self): - data = self.stream.char() - if data == "-": - self.state = self.commentEndState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "-\uFFFD" - self.state = self.commentState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-comment-end-dash"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["data"] += "-" + data - self.state = self.commentState - return True - - def commentEndState(self): - data = self.stream.char() - if data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "--\uFFFD" - self.state = self.commentState - elif data == "!": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-bang-after-double-dash-in-comment"}) - self.state = self.commentEndBangState - elif data == "-": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-dash-after-double-dash-in-comment"}) - self.currentToken["data"] += data - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-comment-double-dash"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - # XXX - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-comment"}) - self.currentToken["data"] += "--" + data - self.state = self.commentState - return True - - def commentEndBangState(self): - data = self.stream.char() - if data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == "-": - self.currentToken["data"] += "--!" - self.state = self.commentEndDashState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["data"] += "--!\uFFFD" - self.state = self.commentState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-comment-end-bang-state"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["data"] += "--!" + data - self.state = self.commentState - return True - - def doctypeState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.beforeDoctypeNameState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-doctype-name-but-got-eof"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "need-space-after-doctype"}) - self.stream.unget(data) - self.state = self.beforeDoctypeNameState - return True - - def beforeDoctypeNameState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-doctype-name-but-got-right-bracket"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["name"] = "\uFFFD" - self.state = self.doctypeNameState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-doctype-name-but-got-eof"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["name"] = data - self.state = self.doctypeNameState - return True - - def doctypeNameState(self): - data = self.stream.char() - if data in spaceCharacters: - self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) - self.state = self.afterDoctypeNameState - elif data == ">": - self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["name"] += "\uFFFD" - self.state = self.doctypeNameState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype-name"}) - self.currentToken["correct"] = False - self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["name"] += data - return True - - def afterDoctypeNameState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.currentToken["correct"] = False - self.stream.unget(data) - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - if data in ("p", "P"): - matched = True - for expected in (("u", "U"), ("b", "B"), ("l", "L"), - ("i", "I"), ("c", "C")): - data = self.stream.char() - if data not in expected: - matched = False - break - if matched: - self.state = self.afterDoctypePublicKeywordState - return True - elif data in ("s", "S"): - matched = True - for expected in (("y", "Y"), ("s", "S"), ("t", "T"), - ("e", "E"), ("m", "M")): - data = self.stream.char() - if data not in expected: - matched = False - break - if matched: - self.state = self.afterDoctypeSystemKeywordState - return True - - # All the characters read before the current 'data' will be - # [a-zA-Z], so they're garbage in the bogus doctype and can be - # discarded; only the latest character might be '>' or EOF - # and needs to be ungetted - self.stream.unget(data) - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "expected-space-or-right-bracket-in-doctype", "datavars": - {"data": data}}) - self.currentToken["correct"] = False - self.state = self.bogusDoctypeState - - return True - - def afterDoctypePublicKeywordState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.beforeDoctypePublicIdentifierState - elif data in ("'", '"'): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.stream.unget(data) - self.state = self.beforeDoctypePublicIdentifierState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.stream.unget(data) - self.state = self.beforeDoctypePublicIdentifierState - return True - - def beforeDoctypePublicIdentifierState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == "\"": - self.currentToken["publicId"] = "" - self.state = self.doctypePublicIdentifierDoubleQuotedState - elif data == "'": - self.currentToken["publicId"] = "" - self.state = self.doctypePublicIdentifierSingleQuotedState - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-end-of-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["correct"] = False - self.state = self.bogusDoctypeState - return True - - def doctypePublicIdentifierDoubleQuotedState(self): - data = self.stream.char() - if data == "\"": - self.state = self.afterDoctypePublicIdentifierState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["publicId"] += "\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-end-of-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["publicId"] += data - return True - - def doctypePublicIdentifierSingleQuotedState(self): - data = self.stream.char() - if data == "'": - self.state = self.afterDoctypePublicIdentifierState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["publicId"] += "\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-end-of-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["publicId"] += data - return True - - def afterDoctypePublicIdentifierState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.betweenDoctypePublicAndSystemIdentifiersState - elif data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == '"': - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierDoubleQuotedState - elif data == "'": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierSingleQuotedState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["correct"] = False - self.state = self.bogusDoctypeState - return True - - def betweenDoctypePublicAndSystemIdentifiersState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data == '"': - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierDoubleQuotedState - elif data == "'": - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierSingleQuotedState - elif data == EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["correct"] = False - self.state = self.bogusDoctypeState - return True - - def afterDoctypeSystemKeywordState(self): - data = self.stream.char() - if data in spaceCharacters: - self.state = self.beforeDoctypeSystemIdentifierState - elif data in ("'", '"'): - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.stream.unget(data) - self.state = self.beforeDoctypeSystemIdentifierState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.stream.unget(data) - self.state = self.beforeDoctypeSystemIdentifierState - return True - - def beforeDoctypeSystemIdentifierState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == "\"": - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierDoubleQuotedState - elif data == "'": - self.currentToken["systemId"] = "" - self.state = self.doctypeSystemIdentifierSingleQuotedState - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.currentToken["correct"] = False - self.state = self.bogusDoctypeState - return True - - def doctypeSystemIdentifierDoubleQuotedState(self): - data = self.stream.char() - if data == "\"": - self.state = self.afterDoctypeSystemIdentifierState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["systemId"] += "\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-end-of-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["systemId"] += data - return True - - def doctypeSystemIdentifierSingleQuotedState(self): - data = self.stream.char() - if data == "'": - self.state = self.afterDoctypeSystemIdentifierState - elif data == "\u0000": - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - self.currentToken["systemId"] += "\uFFFD" - elif data == ">": - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-end-of-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.currentToken["systemId"] += data - return True - - def afterDoctypeSystemIdentifierState(self): - data = self.stream.char() - if data in spaceCharacters: - pass - elif data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "eof-in-doctype"}) - self.currentToken["correct"] = False - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": - "unexpected-char-in-doctype"}) - self.state = self.bogusDoctypeState - return True - - def bogusDoctypeState(self): - data = self.stream.char() - if data == ">": - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - elif data is EOF: - # XXX EMIT - self.stream.unget(data) - self.tokenQueue.append(self.currentToken) - self.state = self.dataState - else: - pass - return True - - def cdataSectionState(self): - data = [] - while True: - data.append(self.stream.charsUntil("]")) - data.append(self.stream.charsUntil(">")) - char = self.stream.char() - if char == EOF: - break - else: - assert char == ">" - if data[-1][-2:] == "]]": - data[-1] = data[-1][:-2] - break - else: - data.append(char) - - data = "".join(data) # pylint:disable=redefined-variable-type - # Deal with null here rather than in the parser - nullCount = data.count("\u0000") - if nullCount > 0: - for _ in range(nullCount): - self.tokenQueue.append({"type": tokenTypes["ParseError"], - "data": "invalid-codepoint"}) - data = data.replace("\u0000", "\uFFFD") - if data: - self.tokenQueue.append({"type": tokenTypes["Characters"], - "data": data}) - self.state = self.dataState - return True diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py deleted file mode 100644 index 07bad5d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from .py import Trie - -__all__ = ["Trie"] diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py deleted file mode 100644 index 6b71975..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -try: - from collections.abc import Mapping -except ImportError: # Python 2.7 - from collections import Mapping - - -class Trie(Mapping): - """Abstract base class for tries""" - - def keys(self, prefix=None): - # pylint:disable=arguments-differ - keys = super(Trie, self).keys() - - if prefix is None: - return set(keys) - - return {x for x in keys if x.startswith(prefix)} - - def has_keys_with_prefix(self, prefix): - for key in self.keys(): - if key.startswith(prefix): - return True - - return False - - def longest_prefix(self, prefix): - if prefix in self: - return prefix - - for i in range(1, len(prefix) + 1): - if prefix[:-i] in self: - return prefix[:-i] - - raise KeyError(prefix) - - def longest_prefix_item(self, prefix): - lprefix = self.longest_prefix(prefix) - return (lprefix, self[lprefix]) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py deleted file mode 100644 index c178b21..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals -from pip._vendor.six import text_type - -from bisect import bisect_left - -from ._base import Trie as ABCTrie - - -class Trie(ABCTrie): - def __init__(self, data): - if not all(isinstance(x, text_type) for x in data.keys()): - raise TypeError("All keys must be strings") - - self._data = data - self._keys = sorted(data.keys()) - self._cachestr = "" - self._cachepoints = (0, len(data)) - - def __contains__(self, key): - return key in self._data - - def __len__(self): - return len(self._data) - - def __iter__(self): - return iter(self._data) - - def __getitem__(self, key): - return self._data[key] - - def keys(self, prefix=None): - if prefix is None or prefix == "" or not self._keys: - return set(self._keys) - - if prefix.startswith(self._cachestr): - lo, hi = self._cachepoints - start = i = bisect_left(self._keys, prefix, lo, hi) - else: - start = i = bisect_left(self._keys, prefix) - - keys = set() - if start == len(self._keys): - return keys - - while self._keys[i].startswith(prefix): - keys.add(self._keys[i]) - i += 1 - - self._cachestr = prefix - self._cachepoints = (start, i) - - return keys - - def has_keys_with_prefix(self, prefix): - if prefix in self._data: - return True - - if prefix.startswith(self._cachestr): - lo, hi = self._cachepoints - i = bisect_left(self._keys, prefix, lo, hi) - else: - i = bisect_left(self._keys, prefix) - - if i == len(self._keys): - return False - - return self._keys[i].startswith(prefix) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_utils.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_utils.py deleted file mode 100644 index d7c4926..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/_utils.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from types import ModuleType - -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping - -from pip._vendor.six import text_type, PY3 - -if PY3: - import xml.etree.ElementTree as default_etree -else: - try: - import xml.etree.cElementTree as default_etree - except ImportError: - import xml.etree.ElementTree as default_etree - - -__all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair", - "surrogatePairToCodepoint", "moduleFactoryFactory", - "supports_lone_surrogates"] - - -# Platforms not supporting lone surrogates (\uD800-\uDFFF) should be -# caught by the below test. In general this would be any platform -# using UTF-16 as its encoding of unicode strings, such as -# Jython. This is because UTF-16 itself is based on the use of such -# surrogates, and there is no mechanism to further escape such -# escapes. -try: - _x = eval('"\\uD800"') # pylint:disable=eval-used - if not isinstance(_x, text_type): - # We need this with u"" because of http://bugs.jython.org/issue2039 - _x = eval('u"\\uD800"') # pylint:disable=eval-used - assert isinstance(_x, text_type) -except Exception: - supports_lone_surrogates = False -else: - supports_lone_surrogates = True - - -class MethodDispatcher(dict): - """Dict with 2 special properties: - - On initiation, keys that are lists, sets or tuples are converted to - multiple keys so accessing any one of the items in the original - list-like object returns the matching value - - md = MethodDispatcher({("foo", "bar"):"baz"}) - md["foo"] == "baz" - - A default value which can be set through the default attribute. - """ - - def __init__(self, items=()): - _dictEntries = [] - for name, value in items: - if isinstance(name, (list, tuple, frozenset, set)): - for item in name: - _dictEntries.append((item, value)) - else: - _dictEntries.append((name, value)) - dict.__init__(self, _dictEntries) - assert len(self) == len(_dictEntries) - self.default = None - - def __getitem__(self, key): - return dict.get(self, key, self.default) - - def __get__(self, instance, owner=None): - return BoundMethodDispatcher(instance, self) - - -class BoundMethodDispatcher(Mapping): - """Wraps a MethodDispatcher, binding its return values to `instance`""" - def __init__(self, instance, dispatcher): - self.instance = instance - self.dispatcher = dispatcher - - def __getitem__(self, key): - # see https://docs.python.org/3/reference/datamodel.html#object.__get__ - # on a function, __get__ is used to bind a function to an instance as a bound method - return self.dispatcher[key].__get__(self.instance) - - def get(self, key, default): - if key in self.dispatcher: - return self[key] - else: - return default - - def __iter__(self): - return iter(self.dispatcher) - - def __len__(self): - return len(self.dispatcher) - - def __contains__(self, key): - return key in self.dispatcher - - -# Some utility functions to deal with weirdness around UCS2 vs UCS4 -# python builds - -def isSurrogatePair(data): - return (len(data) == 2 and - ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and - ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF) - - -def surrogatePairToCodepoint(data): - char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 + - (ord(data[1]) - 0xDC00)) - return char_val - -# Module Factory Factory (no, this isn't Java, I know) -# Here to stop this being duplicated all over the place. - - -def moduleFactoryFactory(factory): - moduleCache = {} - - def moduleFactory(baseModule, *args, **kwargs): - if isinstance(ModuleType.__name__, type("")): - name = "_%s_factory" % baseModule.__name__ - else: - name = b"_%s_factory" % baseModule.__name__ - - kwargs_tuple = tuple(kwargs.items()) - - try: - return moduleCache[name][args][kwargs_tuple] - except KeyError: - mod = ModuleType(name) - objs = factory(baseModule, *args, **kwargs) - mod.__dict__.update(objs) - if "name" not in moduleCache: - moduleCache[name] = {} - if "args" not in moduleCache[name]: - moduleCache[name][args] = {} - if "kwargs" not in moduleCache[name][args]: - moduleCache[name][args][kwargs_tuple] = {} - moduleCache[name][args][kwargs_tuple] = mod - return mod - - return moduleFactory - - -def memoize(func): - cache = {} - - def wrapped(*args, **kwargs): - key = (tuple(args), tuple(kwargs.items())) - if key not in cache: - cache[key] = func(*args, **kwargs) - return cache[key] - - return wrapped diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/constants.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/constants.py deleted file mode 100644 index fe3e237..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/constants.py +++ /dev/null @@ -1,2946 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import string - -EOF = None - -E = { - "null-character": - "Null character in input stream, replaced with U+FFFD.", - "invalid-codepoint": - "Invalid codepoint in stream.", - "incorrectly-placed-solidus": - "Solidus (/) incorrectly placed in tag.", - "incorrect-cr-newline-entity": - "Incorrect CR newline entity, replaced with LF.", - "illegal-windows-1252-entity": - "Entity used with illegal number (windows-1252 reference).", - "cant-convert-numeric-entity": - "Numeric entity couldn't be converted to character " - "(codepoint U+%(charAsInt)08x).", - "illegal-codepoint-for-numeric-entity": - "Numeric entity represents an illegal codepoint: " - "U+%(charAsInt)08x.", - "numeric-entity-without-semicolon": - "Numeric entity didn't end with ';'.", - "expected-numeric-entity-but-got-eof": - "Numeric entity expected. Got end of file instead.", - "expected-numeric-entity": - "Numeric entity expected but none found.", - "named-entity-without-semicolon": - "Named entity didn't end with ';'.", - "expected-named-entity": - "Named entity expected. Got none.", - "attributes-in-end-tag": - "End tag contains unexpected attributes.", - 'self-closing-flag-on-end-tag': - "End tag contains unexpected self-closing flag.", - "expected-tag-name-but-got-right-bracket": - "Expected tag name. Got '>' instead.", - "expected-tag-name-but-got-question-mark": - "Expected tag name. Got '?' instead. (HTML doesn't " - "support processing instructions.)", - "expected-tag-name": - "Expected tag name. Got something else instead", - "expected-closing-tag-but-got-right-bracket": - "Expected closing tag. Got '>' instead. Ignoring ''.", - "expected-closing-tag-but-got-eof": - "Expected closing tag. Unexpected end of file.", - "expected-closing-tag-but-got-char": - "Expected closing tag. Unexpected character '%(data)s' found.", - "eof-in-tag-name": - "Unexpected end of file in the tag name.", - "expected-attribute-name-but-got-eof": - "Unexpected end of file. Expected attribute name instead.", - "eof-in-attribute-name": - "Unexpected end of file in attribute name.", - "invalid-character-in-attribute-name": - "Invalid character in attribute name", - "duplicate-attribute": - "Dropped duplicate attribute on tag.", - "expected-end-of-tag-name-but-got-eof": - "Unexpected end of file. Expected = or end of tag.", - "expected-attribute-value-but-got-eof": - "Unexpected end of file. Expected attribute value.", - "expected-attribute-value-but-got-right-bracket": - "Expected attribute value. Got '>' instead.", - 'equals-in-unquoted-attribute-value': - "Unexpected = in unquoted attribute", - 'unexpected-character-in-unquoted-attribute-value': - "Unexpected character in unquoted attribute", - "invalid-character-after-attribute-name": - "Unexpected character after attribute name.", - "unexpected-character-after-attribute-value": - "Unexpected character after attribute value.", - "eof-in-attribute-value-double-quote": - "Unexpected end of file in attribute value (\").", - "eof-in-attribute-value-single-quote": - "Unexpected end of file in attribute value (').", - "eof-in-attribute-value-no-quotes": - "Unexpected end of file in attribute value.", - "unexpected-EOF-after-solidus-in-tag": - "Unexpected end of file in tag. Expected >", - "unexpected-character-after-solidus-in-tag": - "Unexpected character after / in tag. Expected >", - "expected-dashes-or-doctype": - "Expected '--' or 'DOCTYPE'. Not found.", - "unexpected-bang-after-double-dash-in-comment": - "Unexpected ! after -- in comment", - "unexpected-space-after-double-dash-in-comment": - "Unexpected space after -- in comment", - "incorrect-comment": - "Incorrect comment.", - "eof-in-comment": - "Unexpected end of file in comment.", - "eof-in-comment-end-dash": - "Unexpected end of file in comment (-)", - "unexpected-dash-after-double-dash-in-comment": - "Unexpected '-' after '--' found in comment.", - "eof-in-comment-double-dash": - "Unexpected end of file in comment (--).", - "eof-in-comment-end-space-state": - "Unexpected end of file in comment.", - "eof-in-comment-end-bang-state": - "Unexpected end of file in comment.", - "unexpected-char-in-comment": - "Unexpected character in comment found.", - "need-space-after-doctype": - "No space after literal string 'DOCTYPE'.", - "expected-doctype-name-but-got-right-bracket": - "Unexpected > character. Expected DOCTYPE name.", - "expected-doctype-name-but-got-eof": - "Unexpected end of file. Expected DOCTYPE name.", - "eof-in-doctype-name": - "Unexpected end of file in DOCTYPE name.", - "eof-in-doctype": - "Unexpected end of file in DOCTYPE.", - "expected-space-or-right-bracket-in-doctype": - "Expected space or '>'. Got '%(data)s'", - "unexpected-end-of-doctype": - "Unexpected end of DOCTYPE.", - "unexpected-char-in-doctype": - "Unexpected character in DOCTYPE.", - "eof-in-innerhtml": - "XXX innerHTML EOF", - "unexpected-doctype": - "Unexpected DOCTYPE. Ignored.", - "non-html-root": - "html needs to be the first start tag.", - "expected-doctype-but-got-eof": - "Unexpected End of file. Expected DOCTYPE.", - "unknown-doctype": - "Erroneous DOCTYPE.", - "expected-doctype-but-got-chars": - "Unexpected non-space characters. Expected DOCTYPE.", - "expected-doctype-but-got-start-tag": - "Unexpected start tag (%(name)s). Expected DOCTYPE.", - "expected-doctype-but-got-end-tag": - "Unexpected end tag (%(name)s). Expected DOCTYPE.", - "end-tag-after-implied-root": - "Unexpected end tag (%(name)s) after the (implied) root element.", - "expected-named-closing-tag-but-got-eof": - "Unexpected end of file. Expected end tag (%(name)s).", - "two-heads-are-not-better-than-one": - "Unexpected start tag head in existing head. Ignored.", - "unexpected-end-tag": - "Unexpected end tag (%(name)s). Ignored.", - "unexpected-start-tag-out-of-my-head": - "Unexpected start tag (%(name)s) that can be in head. Moved.", - "unexpected-start-tag": - "Unexpected start tag (%(name)s).", - "missing-end-tag": - "Missing end tag (%(name)s).", - "missing-end-tags": - "Missing end tags (%(name)s).", - "unexpected-start-tag-implies-end-tag": - "Unexpected start tag (%(startName)s) " - "implies end tag (%(endName)s).", - "unexpected-start-tag-treated-as": - "Unexpected start tag (%(originalName)s). Treated as %(newName)s.", - "deprecated-tag": - "Unexpected start tag %(name)s. Don't use it!", - "unexpected-start-tag-ignored": - "Unexpected start tag %(name)s. Ignored.", - "expected-one-end-tag-but-got-another": - "Unexpected end tag (%(gotName)s). " - "Missing end tag (%(expectedName)s).", - "end-tag-too-early": - "End tag (%(name)s) seen too early. Expected other end tag.", - "end-tag-too-early-named": - "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).", - "end-tag-too-early-ignored": - "End tag (%(name)s) seen too early. Ignored.", - "adoption-agency-1.1": - "End tag (%(name)s) violates step 1, " - "paragraph 1 of the adoption agency algorithm.", - "adoption-agency-1.2": - "End tag (%(name)s) violates step 1, " - "paragraph 2 of the adoption agency algorithm.", - "adoption-agency-1.3": - "End tag (%(name)s) violates step 1, " - "paragraph 3 of the adoption agency algorithm.", - "adoption-agency-4.4": - "End tag (%(name)s) violates step 4, " - "paragraph 4 of the adoption agency algorithm.", - "unexpected-end-tag-treated-as": - "Unexpected end tag (%(originalName)s). Treated as %(newName)s.", - "no-end-tag": - "This element (%(name)s) has no end tag.", - "unexpected-implied-end-tag-in-table": - "Unexpected implied end tag (%(name)s) in the table phase.", - "unexpected-implied-end-tag-in-table-body": - "Unexpected implied end tag (%(name)s) in the table body phase.", - "unexpected-char-implies-table-voodoo": - "Unexpected non-space characters in " - "table context caused voodoo mode.", - "unexpected-hidden-input-in-table": - "Unexpected input with type hidden in table context.", - "unexpected-form-in-table": - "Unexpected form in table context.", - "unexpected-start-tag-implies-table-voodoo": - "Unexpected start tag (%(name)s) in " - "table context caused voodoo mode.", - "unexpected-end-tag-implies-table-voodoo": - "Unexpected end tag (%(name)s) in " - "table context caused voodoo mode.", - "unexpected-cell-in-table-body": - "Unexpected table cell start tag (%(name)s) " - "in the table body phase.", - "unexpected-cell-end-tag": - "Got table cell end tag (%(name)s) " - "while required end tags are missing.", - "unexpected-end-tag-in-table-body": - "Unexpected end tag (%(name)s) in the table body phase. Ignored.", - "unexpected-implied-end-tag-in-table-row": - "Unexpected implied end tag (%(name)s) in the table row phase.", - "unexpected-end-tag-in-table-row": - "Unexpected end tag (%(name)s) in the table row phase. Ignored.", - "unexpected-select-in-select": - "Unexpected select start tag in the select phase " - "treated as select end tag.", - "unexpected-input-in-select": - "Unexpected input start tag in the select phase.", - "unexpected-start-tag-in-select": - "Unexpected start tag token (%(name)s in the select phase. " - "Ignored.", - "unexpected-end-tag-in-select": - "Unexpected end tag (%(name)s) in the select phase. Ignored.", - "unexpected-table-element-start-tag-in-select-in-table": - "Unexpected table element start tag (%(name)s) in the select in table phase.", - "unexpected-table-element-end-tag-in-select-in-table": - "Unexpected table element end tag (%(name)s) in the select in table phase.", - "unexpected-char-after-body": - "Unexpected non-space characters in the after body phase.", - "unexpected-start-tag-after-body": - "Unexpected start tag token (%(name)s)" - " in the after body phase.", - "unexpected-end-tag-after-body": - "Unexpected end tag token (%(name)s)" - " in the after body phase.", - "unexpected-char-in-frameset": - "Unexpected characters in the frameset phase. Characters ignored.", - "unexpected-start-tag-in-frameset": - "Unexpected start tag token (%(name)s)" - " in the frameset phase. Ignored.", - "unexpected-frameset-in-frameset-innerhtml": - "Unexpected end tag token (frameset) " - "in the frameset phase (innerHTML).", - "unexpected-end-tag-in-frameset": - "Unexpected end tag token (%(name)s)" - " in the frameset phase. Ignored.", - "unexpected-char-after-frameset": - "Unexpected non-space characters in the " - "after frameset phase. Ignored.", - "unexpected-start-tag-after-frameset": - "Unexpected start tag (%(name)s)" - " in the after frameset phase. Ignored.", - "unexpected-end-tag-after-frameset": - "Unexpected end tag (%(name)s)" - " in the after frameset phase. Ignored.", - "unexpected-end-tag-after-body-innerhtml": - "Unexpected end tag after body(innerHtml)", - "expected-eof-but-got-char": - "Unexpected non-space characters. Expected end of file.", - "expected-eof-but-got-start-tag": - "Unexpected start tag (%(name)s)" - ". Expected end of file.", - "expected-eof-but-got-end-tag": - "Unexpected end tag (%(name)s)" - ". Expected end of file.", - "eof-in-table": - "Unexpected end of file. Expected table content.", - "eof-in-select": - "Unexpected end of file. Expected select content.", - "eof-in-frameset": - "Unexpected end of file. Expected frameset content.", - "eof-in-script-in-script": - "Unexpected end of file. Expected script content.", - "eof-in-foreign-lands": - "Unexpected end of file. Expected foreign content", - "non-void-element-with-trailing-solidus": - "Trailing solidus not allowed on element %(name)s", - "unexpected-html-element-in-foreign-content": - "Element %(name)s not allowed in a non-html context", - "unexpected-end-tag-before-html": - "Unexpected end tag (%(name)s) before html.", - "unexpected-inhead-noscript-tag": - "Element %(name)s not allowed in a inhead-noscript context", - "eof-in-head-noscript": - "Unexpected end of file. Expected inhead-noscript content", - "char-in-head-noscript": - "Unexpected non-space character. Expected inhead-noscript content", - "XXX-undefined-error": - "Undefined error (this sucks and should be fixed)", -} - -namespaces = { - "html": "http://www.w3.org/1999/xhtml", - "mathml": "http://www.w3.org/1998/Math/MathML", - "svg": "http://www.w3.org/2000/svg", - "xlink": "http://www.w3.org/1999/xlink", - "xml": "http://www.w3.org/XML/1998/namespace", - "xmlns": "http://www.w3.org/2000/xmlns/" -} - -scopingElements = frozenset([ - (namespaces["html"], "applet"), - (namespaces["html"], "caption"), - (namespaces["html"], "html"), - (namespaces["html"], "marquee"), - (namespaces["html"], "object"), - (namespaces["html"], "table"), - (namespaces["html"], "td"), - (namespaces["html"], "th"), - (namespaces["mathml"], "mi"), - (namespaces["mathml"], "mo"), - (namespaces["mathml"], "mn"), - (namespaces["mathml"], "ms"), - (namespaces["mathml"], "mtext"), - (namespaces["mathml"], "annotation-xml"), - (namespaces["svg"], "foreignObject"), - (namespaces["svg"], "desc"), - (namespaces["svg"], "title"), -]) - -formattingElements = frozenset([ - (namespaces["html"], "a"), - (namespaces["html"], "b"), - (namespaces["html"], "big"), - (namespaces["html"], "code"), - (namespaces["html"], "em"), - (namespaces["html"], "font"), - (namespaces["html"], "i"), - (namespaces["html"], "nobr"), - (namespaces["html"], "s"), - (namespaces["html"], "small"), - (namespaces["html"], "strike"), - (namespaces["html"], "strong"), - (namespaces["html"], "tt"), - (namespaces["html"], "u") -]) - -specialElements = frozenset([ - (namespaces["html"], "address"), - (namespaces["html"], "applet"), - (namespaces["html"], "area"), - (namespaces["html"], "article"), - (namespaces["html"], "aside"), - (namespaces["html"], "base"), - (namespaces["html"], "basefont"), - (namespaces["html"], "bgsound"), - (namespaces["html"], "blockquote"), - (namespaces["html"], "body"), - (namespaces["html"], "br"), - (namespaces["html"], "button"), - (namespaces["html"], "caption"), - (namespaces["html"], "center"), - (namespaces["html"], "col"), - (namespaces["html"], "colgroup"), - (namespaces["html"], "command"), - (namespaces["html"], "dd"), - (namespaces["html"], "details"), - (namespaces["html"], "dir"), - (namespaces["html"], "div"), - (namespaces["html"], "dl"), - (namespaces["html"], "dt"), - (namespaces["html"], "embed"), - (namespaces["html"], "fieldset"), - (namespaces["html"], "figure"), - (namespaces["html"], "footer"), - (namespaces["html"], "form"), - (namespaces["html"], "frame"), - (namespaces["html"], "frameset"), - (namespaces["html"], "h1"), - (namespaces["html"], "h2"), - (namespaces["html"], "h3"), - (namespaces["html"], "h4"), - (namespaces["html"], "h5"), - (namespaces["html"], "h6"), - (namespaces["html"], "head"), - (namespaces["html"], "header"), - (namespaces["html"], "hr"), - (namespaces["html"], "html"), - (namespaces["html"], "iframe"), - # Note that image is commented out in the spec as "this isn't an - # element that can end up on the stack, so it doesn't matter," - (namespaces["html"], "image"), - (namespaces["html"], "img"), - (namespaces["html"], "input"), - (namespaces["html"], "isindex"), - (namespaces["html"], "li"), - (namespaces["html"], "link"), - (namespaces["html"], "listing"), - (namespaces["html"], "marquee"), - (namespaces["html"], "menu"), - (namespaces["html"], "meta"), - (namespaces["html"], "nav"), - (namespaces["html"], "noembed"), - (namespaces["html"], "noframes"), - (namespaces["html"], "noscript"), - (namespaces["html"], "object"), - (namespaces["html"], "ol"), - (namespaces["html"], "p"), - (namespaces["html"], "param"), - (namespaces["html"], "plaintext"), - (namespaces["html"], "pre"), - (namespaces["html"], "script"), - (namespaces["html"], "section"), - (namespaces["html"], "select"), - (namespaces["html"], "style"), - (namespaces["html"], "table"), - (namespaces["html"], "tbody"), - (namespaces["html"], "td"), - (namespaces["html"], "textarea"), - (namespaces["html"], "tfoot"), - (namespaces["html"], "th"), - (namespaces["html"], "thead"), - (namespaces["html"], "title"), - (namespaces["html"], "tr"), - (namespaces["html"], "ul"), - (namespaces["html"], "wbr"), - (namespaces["html"], "xmp"), - (namespaces["svg"], "foreignObject") -]) - -htmlIntegrationPointElements = frozenset([ - (namespaces["mathml"], "annotation-xml"), - (namespaces["svg"], "foreignObject"), - (namespaces["svg"], "desc"), - (namespaces["svg"], "title") -]) - -mathmlTextIntegrationPointElements = frozenset([ - (namespaces["mathml"], "mi"), - (namespaces["mathml"], "mo"), - (namespaces["mathml"], "mn"), - (namespaces["mathml"], "ms"), - (namespaces["mathml"], "mtext") -]) - -adjustSVGAttributes = { - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterres": "filterRes", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan" -} - -adjustMathMLAttributes = {"definitionurl": "definitionURL"} - -adjustForeignAttributes = { - "xlink:actuate": ("xlink", "actuate", namespaces["xlink"]), - "xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]), - "xlink:href": ("xlink", "href", namespaces["xlink"]), - "xlink:role": ("xlink", "role", namespaces["xlink"]), - "xlink:show": ("xlink", "show", namespaces["xlink"]), - "xlink:title": ("xlink", "title", namespaces["xlink"]), - "xlink:type": ("xlink", "type", namespaces["xlink"]), - "xml:base": ("xml", "base", namespaces["xml"]), - "xml:lang": ("xml", "lang", namespaces["xml"]), - "xml:space": ("xml", "space", namespaces["xml"]), - "xmlns": (None, "xmlns", namespaces["xmlns"]), - "xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"]) -} - -unadjustForeignAttributes = {(ns, local): qname for qname, (prefix, local, ns) in - adjustForeignAttributes.items()} - -spaceCharacters = frozenset([ - "\t", - "\n", - "\u000C", - " ", - "\r" -]) - -tableInsertModeElements = frozenset([ - "table", - "tbody", - "tfoot", - "thead", - "tr" -]) - -asciiLowercase = frozenset(string.ascii_lowercase) -asciiUppercase = frozenset(string.ascii_uppercase) -asciiLetters = frozenset(string.ascii_letters) -digits = frozenset(string.digits) -hexDigits = frozenset(string.hexdigits) - -asciiUpper2Lower = {ord(c): ord(c.lower()) for c in string.ascii_uppercase} - -# Heading elements need to be ordered -headingElements = ( - "h1", - "h2", - "h3", - "h4", - "h5", - "h6" -) - -voidElements = frozenset([ - "base", - "command", - "event-source", - "link", - "meta", - "hr", - "br", - "img", - "embed", - "param", - "area", - "col", - "input", - "source", - "track" -]) - -cdataElements = frozenset(['title', 'textarea']) - -rcdataElements = frozenset([ - 'style', - 'script', - 'xmp', - 'iframe', - 'noembed', - 'noframes', - 'noscript' -]) - -booleanAttributes = { - "": frozenset(["irrelevant", "itemscope"]), - "style": frozenset(["scoped"]), - "img": frozenset(["ismap"]), - "audio": frozenset(["autoplay", "controls"]), - "video": frozenset(["autoplay", "controls"]), - "script": frozenset(["defer", "async"]), - "details": frozenset(["open"]), - "datagrid": frozenset(["multiple", "disabled"]), - "command": frozenset(["hidden", "disabled", "checked", "default"]), - "hr": frozenset(["noshade"]), - "menu": frozenset(["autosubmit"]), - "fieldset": frozenset(["disabled", "readonly"]), - "option": frozenset(["disabled", "readonly", "selected"]), - "optgroup": frozenset(["disabled", "readonly"]), - "button": frozenset(["disabled", "autofocus"]), - "input": frozenset(["disabled", "readonly", "required", "autofocus", "checked", "ismap"]), - "select": frozenset(["disabled", "readonly", "autofocus", "multiple"]), - "output": frozenset(["disabled", "readonly"]), - "iframe": frozenset(["seamless"]), -} - -# entitiesWindows1252 has to be _ordered_ and needs to have an index. It -# therefore can't be a frozenset. -entitiesWindows1252 = ( - 8364, # 0x80 0x20AC EURO SIGN - 65533, # 0x81 UNDEFINED - 8218, # 0x82 0x201A SINGLE LOW-9 QUOTATION MARK - 402, # 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK - 8222, # 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK - 8230, # 0x85 0x2026 HORIZONTAL ELLIPSIS - 8224, # 0x86 0x2020 DAGGER - 8225, # 0x87 0x2021 DOUBLE DAGGER - 710, # 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT - 8240, # 0x89 0x2030 PER MILLE SIGN - 352, # 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON - 8249, # 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK - 338, # 0x8C 0x0152 LATIN CAPITAL LIGATURE OE - 65533, # 0x8D UNDEFINED - 381, # 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON - 65533, # 0x8F UNDEFINED - 65533, # 0x90 UNDEFINED - 8216, # 0x91 0x2018 LEFT SINGLE QUOTATION MARK - 8217, # 0x92 0x2019 RIGHT SINGLE QUOTATION MARK - 8220, # 0x93 0x201C LEFT DOUBLE QUOTATION MARK - 8221, # 0x94 0x201D RIGHT DOUBLE QUOTATION MARK - 8226, # 0x95 0x2022 BULLET - 8211, # 0x96 0x2013 EN DASH - 8212, # 0x97 0x2014 EM DASH - 732, # 0x98 0x02DC SMALL TILDE - 8482, # 0x99 0x2122 TRADE MARK SIGN - 353, # 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON - 8250, # 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - 339, # 0x9C 0x0153 LATIN SMALL LIGATURE OE - 65533, # 0x9D UNDEFINED - 382, # 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON - 376 # 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS -) - -xmlEntities = frozenset(['lt;', 'gt;', 'amp;', 'apos;', 'quot;']) - -entities = { - "AElig": "\xc6", - "AElig;": "\xc6", - "AMP": "&", - "AMP;": "&", - "Aacute": "\xc1", - "Aacute;": "\xc1", - "Abreve;": "\u0102", - "Acirc": "\xc2", - "Acirc;": "\xc2", - "Acy;": "\u0410", - "Afr;": "\U0001d504", - "Agrave": "\xc0", - "Agrave;": "\xc0", - "Alpha;": "\u0391", - "Amacr;": "\u0100", - "And;": "\u2a53", - "Aogon;": "\u0104", - "Aopf;": "\U0001d538", - "ApplyFunction;": "\u2061", - "Aring": "\xc5", - "Aring;": "\xc5", - "Ascr;": "\U0001d49c", - "Assign;": "\u2254", - "Atilde": "\xc3", - "Atilde;": "\xc3", - "Auml": "\xc4", - "Auml;": "\xc4", - "Backslash;": "\u2216", - "Barv;": "\u2ae7", - "Barwed;": "\u2306", - "Bcy;": "\u0411", - "Because;": "\u2235", - "Bernoullis;": "\u212c", - "Beta;": "\u0392", - "Bfr;": "\U0001d505", - "Bopf;": "\U0001d539", - "Breve;": "\u02d8", - "Bscr;": "\u212c", - "Bumpeq;": "\u224e", - "CHcy;": "\u0427", - "COPY": "\xa9", - "COPY;": "\xa9", - "Cacute;": "\u0106", - "Cap;": "\u22d2", - "CapitalDifferentialD;": "\u2145", - "Cayleys;": "\u212d", - "Ccaron;": "\u010c", - "Ccedil": "\xc7", - "Ccedil;": "\xc7", - "Ccirc;": "\u0108", - "Cconint;": "\u2230", - "Cdot;": "\u010a", - "Cedilla;": "\xb8", - "CenterDot;": "\xb7", - "Cfr;": "\u212d", - "Chi;": "\u03a7", - "CircleDot;": "\u2299", - "CircleMinus;": "\u2296", - "CirclePlus;": "\u2295", - "CircleTimes;": "\u2297", - "ClockwiseContourIntegral;": "\u2232", - "CloseCurlyDoubleQuote;": "\u201d", - "CloseCurlyQuote;": "\u2019", - "Colon;": "\u2237", - "Colone;": "\u2a74", - "Congruent;": "\u2261", - "Conint;": "\u222f", - "ContourIntegral;": "\u222e", - "Copf;": "\u2102", - "Coproduct;": "\u2210", - "CounterClockwiseContourIntegral;": "\u2233", - "Cross;": "\u2a2f", - "Cscr;": "\U0001d49e", - "Cup;": "\u22d3", - "CupCap;": "\u224d", - "DD;": "\u2145", - "DDotrahd;": "\u2911", - "DJcy;": "\u0402", - "DScy;": "\u0405", - "DZcy;": "\u040f", - "Dagger;": "\u2021", - "Darr;": "\u21a1", - "Dashv;": "\u2ae4", - "Dcaron;": "\u010e", - "Dcy;": "\u0414", - "Del;": "\u2207", - "Delta;": "\u0394", - "Dfr;": "\U0001d507", - "DiacriticalAcute;": "\xb4", - "DiacriticalDot;": "\u02d9", - "DiacriticalDoubleAcute;": "\u02dd", - "DiacriticalGrave;": "`", - "DiacriticalTilde;": "\u02dc", - "Diamond;": "\u22c4", - "DifferentialD;": "\u2146", - "Dopf;": "\U0001d53b", - "Dot;": "\xa8", - "DotDot;": "\u20dc", - "DotEqual;": "\u2250", - "DoubleContourIntegral;": "\u222f", - "DoubleDot;": "\xa8", - "DoubleDownArrow;": "\u21d3", - "DoubleLeftArrow;": "\u21d0", - "DoubleLeftRightArrow;": "\u21d4", - "DoubleLeftTee;": "\u2ae4", - "DoubleLongLeftArrow;": "\u27f8", - "DoubleLongLeftRightArrow;": "\u27fa", - "DoubleLongRightArrow;": "\u27f9", - "DoubleRightArrow;": "\u21d2", - "DoubleRightTee;": "\u22a8", - "DoubleUpArrow;": "\u21d1", - "DoubleUpDownArrow;": "\u21d5", - "DoubleVerticalBar;": "\u2225", - "DownArrow;": "\u2193", - "DownArrowBar;": "\u2913", - "DownArrowUpArrow;": "\u21f5", - "DownBreve;": "\u0311", - "DownLeftRightVector;": "\u2950", - "DownLeftTeeVector;": "\u295e", - "DownLeftVector;": "\u21bd", - "DownLeftVectorBar;": "\u2956", - "DownRightTeeVector;": "\u295f", - "DownRightVector;": "\u21c1", - "DownRightVectorBar;": "\u2957", - "DownTee;": "\u22a4", - "DownTeeArrow;": "\u21a7", - "Downarrow;": "\u21d3", - "Dscr;": "\U0001d49f", - "Dstrok;": "\u0110", - "ENG;": "\u014a", - "ETH": "\xd0", - "ETH;": "\xd0", - "Eacute": "\xc9", - "Eacute;": "\xc9", - "Ecaron;": "\u011a", - "Ecirc": "\xca", - "Ecirc;": "\xca", - "Ecy;": "\u042d", - "Edot;": "\u0116", - "Efr;": "\U0001d508", - "Egrave": "\xc8", - "Egrave;": "\xc8", - "Element;": "\u2208", - "Emacr;": "\u0112", - "EmptySmallSquare;": "\u25fb", - "EmptyVerySmallSquare;": "\u25ab", - "Eogon;": "\u0118", - "Eopf;": "\U0001d53c", - "Epsilon;": "\u0395", - "Equal;": "\u2a75", - "EqualTilde;": "\u2242", - "Equilibrium;": "\u21cc", - "Escr;": "\u2130", - "Esim;": "\u2a73", - "Eta;": "\u0397", - "Euml": "\xcb", - "Euml;": "\xcb", - "Exists;": "\u2203", - "ExponentialE;": "\u2147", - "Fcy;": "\u0424", - "Ffr;": "\U0001d509", - "FilledSmallSquare;": "\u25fc", - "FilledVerySmallSquare;": "\u25aa", - "Fopf;": "\U0001d53d", - "ForAll;": "\u2200", - "Fouriertrf;": "\u2131", - "Fscr;": "\u2131", - "GJcy;": "\u0403", - "GT": ">", - "GT;": ">", - "Gamma;": "\u0393", - "Gammad;": "\u03dc", - "Gbreve;": "\u011e", - "Gcedil;": "\u0122", - "Gcirc;": "\u011c", - "Gcy;": "\u0413", - "Gdot;": "\u0120", - "Gfr;": "\U0001d50a", - "Gg;": "\u22d9", - "Gopf;": "\U0001d53e", - "GreaterEqual;": "\u2265", - "GreaterEqualLess;": "\u22db", - "GreaterFullEqual;": "\u2267", - "GreaterGreater;": "\u2aa2", - "GreaterLess;": "\u2277", - "GreaterSlantEqual;": "\u2a7e", - "GreaterTilde;": "\u2273", - "Gscr;": "\U0001d4a2", - "Gt;": "\u226b", - "HARDcy;": "\u042a", - "Hacek;": "\u02c7", - "Hat;": "^", - "Hcirc;": "\u0124", - "Hfr;": "\u210c", - "HilbertSpace;": "\u210b", - "Hopf;": "\u210d", - "HorizontalLine;": "\u2500", - "Hscr;": "\u210b", - "Hstrok;": "\u0126", - "HumpDownHump;": "\u224e", - "HumpEqual;": "\u224f", - "IEcy;": "\u0415", - "IJlig;": "\u0132", - "IOcy;": "\u0401", - "Iacute": "\xcd", - "Iacute;": "\xcd", - "Icirc": "\xce", - "Icirc;": "\xce", - "Icy;": "\u0418", - "Idot;": "\u0130", - "Ifr;": "\u2111", - "Igrave": "\xcc", - "Igrave;": "\xcc", - "Im;": "\u2111", - "Imacr;": "\u012a", - "ImaginaryI;": "\u2148", - "Implies;": "\u21d2", - "Int;": "\u222c", - "Integral;": "\u222b", - "Intersection;": "\u22c2", - "InvisibleComma;": "\u2063", - "InvisibleTimes;": "\u2062", - "Iogon;": "\u012e", - "Iopf;": "\U0001d540", - "Iota;": "\u0399", - "Iscr;": "\u2110", - "Itilde;": "\u0128", - "Iukcy;": "\u0406", - "Iuml": "\xcf", - "Iuml;": "\xcf", - "Jcirc;": "\u0134", - "Jcy;": "\u0419", - "Jfr;": "\U0001d50d", - "Jopf;": "\U0001d541", - "Jscr;": "\U0001d4a5", - "Jsercy;": "\u0408", - "Jukcy;": "\u0404", - "KHcy;": "\u0425", - "KJcy;": "\u040c", - "Kappa;": "\u039a", - "Kcedil;": "\u0136", - "Kcy;": "\u041a", - "Kfr;": "\U0001d50e", - "Kopf;": "\U0001d542", - "Kscr;": "\U0001d4a6", - "LJcy;": "\u0409", - "LT": "<", - "LT;": "<", - "Lacute;": "\u0139", - "Lambda;": "\u039b", - "Lang;": "\u27ea", - "Laplacetrf;": "\u2112", - "Larr;": "\u219e", - "Lcaron;": "\u013d", - "Lcedil;": "\u013b", - "Lcy;": "\u041b", - "LeftAngleBracket;": "\u27e8", - "LeftArrow;": "\u2190", - "LeftArrowBar;": "\u21e4", - "LeftArrowRightArrow;": "\u21c6", - "LeftCeiling;": "\u2308", - "LeftDoubleBracket;": "\u27e6", - "LeftDownTeeVector;": "\u2961", - "LeftDownVector;": "\u21c3", - "LeftDownVectorBar;": "\u2959", - "LeftFloor;": "\u230a", - "LeftRightArrow;": "\u2194", - "LeftRightVector;": "\u294e", - "LeftTee;": "\u22a3", - "LeftTeeArrow;": "\u21a4", - "LeftTeeVector;": "\u295a", - "LeftTriangle;": "\u22b2", - "LeftTriangleBar;": "\u29cf", - "LeftTriangleEqual;": "\u22b4", - "LeftUpDownVector;": "\u2951", - "LeftUpTeeVector;": "\u2960", - "LeftUpVector;": "\u21bf", - "LeftUpVectorBar;": "\u2958", - "LeftVector;": "\u21bc", - "LeftVectorBar;": "\u2952", - "Leftarrow;": "\u21d0", - "Leftrightarrow;": "\u21d4", - "LessEqualGreater;": "\u22da", - "LessFullEqual;": "\u2266", - "LessGreater;": "\u2276", - "LessLess;": "\u2aa1", - "LessSlantEqual;": "\u2a7d", - "LessTilde;": "\u2272", - "Lfr;": "\U0001d50f", - "Ll;": "\u22d8", - "Lleftarrow;": "\u21da", - "Lmidot;": "\u013f", - "LongLeftArrow;": "\u27f5", - "LongLeftRightArrow;": "\u27f7", - "LongRightArrow;": "\u27f6", - "Longleftarrow;": "\u27f8", - "Longleftrightarrow;": "\u27fa", - "Longrightarrow;": "\u27f9", - "Lopf;": "\U0001d543", - "LowerLeftArrow;": "\u2199", - "LowerRightArrow;": "\u2198", - "Lscr;": "\u2112", - "Lsh;": "\u21b0", - "Lstrok;": "\u0141", - "Lt;": "\u226a", - "Map;": "\u2905", - "Mcy;": "\u041c", - "MediumSpace;": "\u205f", - "Mellintrf;": "\u2133", - "Mfr;": "\U0001d510", - "MinusPlus;": "\u2213", - "Mopf;": "\U0001d544", - "Mscr;": "\u2133", - "Mu;": "\u039c", - "NJcy;": "\u040a", - "Nacute;": "\u0143", - "Ncaron;": "\u0147", - "Ncedil;": "\u0145", - "Ncy;": "\u041d", - "NegativeMediumSpace;": "\u200b", - "NegativeThickSpace;": "\u200b", - "NegativeThinSpace;": "\u200b", - "NegativeVeryThinSpace;": "\u200b", - "NestedGreaterGreater;": "\u226b", - "NestedLessLess;": "\u226a", - "NewLine;": "\n", - "Nfr;": "\U0001d511", - "NoBreak;": "\u2060", - "NonBreakingSpace;": "\xa0", - "Nopf;": "\u2115", - "Not;": "\u2aec", - "NotCongruent;": "\u2262", - "NotCupCap;": "\u226d", - "NotDoubleVerticalBar;": "\u2226", - "NotElement;": "\u2209", - "NotEqual;": "\u2260", - "NotEqualTilde;": "\u2242\u0338", - "NotExists;": "\u2204", - "NotGreater;": "\u226f", - "NotGreaterEqual;": "\u2271", - "NotGreaterFullEqual;": "\u2267\u0338", - "NotGreaterGreater;": "\u226b\u0338", - "NotGreaterLess;": "\u2279", - "NotGreaterSlantEqual;": "\u2a7e\u0338", - "NotGreaterTilde;": "\u2275", - "NotHumpDownHump;": "\u224e\u0338", - "NotHumpEqual;": "\u224f\u0338", - "NotLeftTriangle;": "\u22ea", - "NotLeftTriangleBar;": "\u29cf\u0338", - "NotLeftTriangleEqual;": "\u22ec", - "NotLess;": "\u226e", - "NotLessEqual;": "\u2270", - "NotLessGreater;": "\u2278", - "NotLessLess;": "\u226a\u0338", - "NotLessSlantEqual;": "\u2a7d\u0338", - "NotLessTilde;": "\u2274", - "NotNestedGreaterGreater;": "\u2aa2\u0338", - "NotNestedLessLess;": "\u2aa1\u0338", - "NotPrecedes;": "\u2280", - "NotPrecedesEqual;": "\u2aaf\u0338", - "NotPrecedesSlantEqual;": "\u22e0", - "NotReverseElement;": "\u220c", - "NotRightTriangle;": "\u22eb", - "NotRightTriangleBar;": "\u29d0\u0338", - "NotRightTriangleEqual;": "\u22ed", - "NotSquareSubset;": "\u228f\u0338", - "NotSquareSubsetEqual;": "\u22e2", - "NotSquareSuperset;": "\u2290\u0338", - "NotSquareSupersetEqual;": "\u22e3", - "NotSubset;": "\u2282\u20d2", - "NotSubsetEqual;": "\u2288", - "NotSucceeds;": "\u2281", - "NotSucceedsEqual;": "\u2ab0\u0338", - "NotSucceedsSlantEqual;": "\u22e1", - "NotSucceedsTilde;": "\u227f\u0338", - "NotSuperset;": "\u2283\u20d2", - "NotSupersetEqual;": "\u2289", - "NotTilde;": "\u2241", - "NotTildeEqual;": "\u2244", - "NotTildeFullEqual;": "\u2247", - "NotTildeTilde;": "\u2249", - "NotVerticalBar;": "\u2224", - "Nscr;": "\U0001d4a9", - "Ntilde": "\xd1", - "Ntilde;": "\xd1", - "Nu;": "\u039d", - "OElig;": "\u0152", - "Oacute": "\xd3", - "Oacute;": "\xd3", - "Ocirc": "\xd4", - "Ocirc;": "\xd4", - "Ocy;": "\u041e", - "Odblac;": "\u0150", - "Ofr;": "\U0001d512", - "Ograve": "\xd2", - "Ograve;": "\xd2", - "Omacr;": "\u014c", - "Omega;": "\u03a9", - "Omicron;": "\u039f", - "Oopf;": "\U0001d546", - "OpenCurlyDoubleQuote;": "\u201c", - "OpenCurlyQuote;": "\u2018", - "Or;": "\u2a54", - "Oscr;": "\U0001d4aa", - "Oslash": "\xd8", - "Oslash;": "\xd8", - "Otilde": "\xd5", - "Otilde;": "\xd5", - "Otimes;": "\u2a37", - "Ouml": "\xd6", - "Ouml;": "\xd6", - "OverBar;": "\u203e", - "OverBrace;": "\u23de", - "OverBracket;": "\u23b4", - "OverParenthesis;": "\u23dc", - "PartialD;": "\u2202", - "Pcy;": "\u041f", - "Pfr;": "\U0001d513", - "Phi;": "\u03a6", - "Pi;": "\u03a0", - "PlusMinus;": "\xb1", - "Poincareplane;": "\u210c", - "Popf;": "\u2119", - "Pr;": "\u2abb", - "Precedes;": "\u227a", - "PrecedesEqual;": "\u2aaf", - "PrecedesSlantEqual;": "\u227c", - "PrecedesTilde;": "\u227e", - "Prime;": "\u2033", - "Product;": "\u220f", - "Proportion;": "\u2237", - "Proportional;": "\u221d", - "Pscr;": "\U0001d4ab", - "Psi;": "\u03a8", - "QUOT": "\"", - "QUOT;": "\"", - "Qfr;": "\U0001d514", - "Qopf;": "\u211a", - "Qscr;": "\U0001d4ac", - "RBarr;": "\u2910", - "REG": "\xae", - "REG;": "\xae", - "Racute;": "\u0154", - "Rang;": "\u27eb", - "Rarr;": "\u21a0", - "Rarrtl;": "\u2916", - "Rcaron;": "\u0158", - "Rcedil;": "\u0156", - "Rcy;": "\u0420", - "Re;": "\u211c", - "ReverseElement;": "\u220b", - "ReverseEquilibrium;": "\u21cb", - "ReverseUpEquilibrium;": "\u296f", - "Rfr;": "\u211c", - "Rho;": "\u03a1", - "RightAngleBracket;": "\u27e9", - "RightArrow;": "\u2192", - "RightArrowBar;": "\u21e5", - "RightArrowLeftArrow;": "\u21c4", - "RightCeiling;": "\u2309", - "RightDoubleBracket;": "\u27e7", - "RightDownTeeVector;": "\u295d", - "RightDownVector;": "\u21c2", - "RightDownVectorBar;": "\u2955", - "RightFloor;": "\u230b", - "RightTee;": "\u22a2", - "RightTeeArrow;": "\u21a6", - "RightTeeVector;": "\u295b", - "RightTriangle;": "\u22b3", - "RightTriangleBar;": "\u29d0", - "RightTriangleEqual;": "\u22b5", - "RightUpDownVector;": "\u294f", - "RightUpTeeVector;": "\u295c", - "RightUpVector;": "\u21be", - "RightUpVectorBar;": "\u2954", - "RightVector;": "\u21c0", - "RightVectorBar;": "\u2953", - "Rightarrow;": "\u21d2", - "Ropf;": "\u211d", - "RoundImplies;": "\u2970", - "Rrightarrow;": "\u21db", - "Rscr;": "\u211b", - "Rsh;": "\u21b1", - "RuleDelayed;": "\u29f4", - "SHCHcy;": "\u0429", - "SHcy;": "\u0428", - "SOFTcy;": "\u042c", - "Sacute;": "\u015a", - "Sc;": "\u2abc", - "Scaron;": "\u0160", - "Scedil;": "\u015e", - "Scirc;": "\u015c", - "Scy;": "\u0421", - "Sfr;": "\U0001d516", - "ShortDownArrow;": "\u2193", - "ShortLeftArrow;": "\u2190", - "ShortRightArrow;": "\u2192", - "ShortUpArrow;": "\u2191", - "Sigma;": "\u03a3", - "SmallCircle;": "\u2218", - "Sopf;": "\U0001d54a", - "Sqrt;": "\u221a", - "Square;": "\u25a1", - "SquareIntersection;": "\u2293", - "SquareSubset;": "\u228f", - "SquareSubsetEqual;": "\u2291", - "SquareSuperset;": "\u2290", - "SquareSupersetEqual;": "\u2292", - "SquareUnion;": "\u2294", - "Sscr;": "\U0001d4ae", - "Star;": "\u22c6", - "Sub;": "\u22d0", - "Subset;": "\u22d0", - "SubsetEqual;": "\u2286", - "Succeeds;": "\u227b", - "SucceedsEqual;": "\u2ab0", - "SucceedsSlantEqual;": "\u227d", - "SucceedsTilde;": "\u227f", - "SuchThat;": "\u220b", - "Sum;": "\u2211", - "Sup;": "\u22d1", - "Superset;": "\u2283", - "SupersetEqual;": "\u2287", - "Supset;": "\u22d1", - "THORN": "\xde", - "THORN;": "\xde", - "TRADE;": "\u2122", - "TSHcy;": "\u040b", - "TScy;": "\u0426", - "Tab;": "\t", - "Tau;": "\u03a4", - "Tcaron;": "\u0164", - "Tcedil;": "\u0162", - "Tcy;": "\u0422", - "Tfr;": "\U0001d517", - "Therefore;": "\u2234", - "Theta;": "\u0398", - "ThickSpace;": "\u205f\u200a", - "ThinSpace;": "\u2009", - "Tilde;": "\u223c", - "TildeEqual;": "\u2243", - "TildeFullEqual;": "\u2245", - "TildeTilde;": "\u2248", - "Topf;": "\U0001d54b", - "TripleDot;": "\u20db", - "Tscr;": "\U0001d4af", - "Tstrok;": "\u0166", - "Uacute": "\xda", - "Uacute;": "\xda", - "Uarr;": "\u219f", - "Uarrocir;": "\u2949", - "Ubrcy;": "\u040e", - "Ubreve;": "\u016c", - "Ucirc": "\xdb", - "Ucirc;": "\xdb", - "Ucy;": "\u0423", - "Udblac;": "\u0170", - "Ufr;": "\U0001d518", - "Ugrave": "\xd9", - "Ugrave;": "\xd9", - "Umacr;": "\u016a", - "UnderBar;": "_", - "UnderBrace;": "\u23df", - "UnderBracket;": "\u23b5", - "UnderParenthesis;": "\u23dd", - "Union;": "\u22c3", - "UnionPlus;": "\u228e", - "Uogon;": "\u0172", - "Uopf;": "\U0001d54c", - "UpArrow;": "\u2191", - "UpArrowBar;": "\u2912", - "UpArrowDownArrow;": "\u21c5", - "UpDownArrow;": "\u2195", - "UpEquilibrium;": "\u296e", - "UpTee;": "\u22a5", - "UpTeeArrow;": "\u21a5", - "Uparrow;": "\u21d1", - "Updownarrow;": "\u21d5", - "UpperLeftArrow;": "\u2196", - "UpperRightArrow;": "\u2197", - "Upsi;": "\u03d2", - "Upsilon;": "\u03a5", - "Uring;": "\u016e", - "Uscr;": "\U0001d4b0", - "Utilde;": "\u0168", - "Uuml": "\xdc", - "Uuml;": "\xdc", - "VDash;": "\u22ab", - "Vbar;": "\u2aeb", - "Vcy;": "\u0412", - "Vdash;": "\u22a9", - "Vdashl;": "\u2ae6", - "Vee;": "\u22c1", - "Verbar;": "\u2016", - "Vert;": "\u2016", - "VerticalBar;": "\u2223", - "VerticalLine;": "|", - "VerticalSeparator;": "\u2758", - "VerticalTilde;": "\u2240", - "VeryThinSpace;": "\u200a", - "Vfr;": "\U0001d519", - "Vopf;": "\U0001d54d", - "Vscr;": "\U0001d4b1", - "Vvdash;": "\u22aa", - "Wcirc;": "\u0174", - "Wedge;": "\u22c0", - "Wfr;": "\U0001d51a", - "Wopf;": "\U0001d54e", - "Wscr;": "\U0001d4b2", - "Xfr;": "\U0001d51b", - "Xi;": "\u039e", - "Xopf;": "\U0001d54f", - "Xscr;": "\U0001d4b3", - "YAcy;": "\u042f", - "YIcy;": "\u0407", - "YUcy;": "\u042e", - "Yacute": "\xdd", - "Yacute;": "\xdd", - "Ycirc;": "\u0176", - "Ycy;": "\u042b", - "Yfr;": "\U0001d51c", - "Yopf;": "\U0001d550", - "Yscr;": "\U0001d4b4", - "Yuml;": "\u0178", - "ZHcy;": "\u0416", - "Zacute;": "\u0179", - "Zcaron;": "\u017d", - "Zcy;": "\u0417", - "Zdot;": "\u017b", - "ZeroWidthSpace;": "\u200b", - "Zeta;": "\u0396", - "Zfr;": "\u2128", - "Zopf;": "\u2124", - "Zscr;": "\U0001d4b5", - "aacute": "\xe1", - "aacute;": "\xe1", - "abreve;": "\u0103", - "ac;": "\u223e", - "acE;": "\u223e\u0333", - "acd;": "\u223f", - "acirc": "\xe2", - "acirc;": "\xe2", - "acute": "\xb4", - "acute;": "\xb4", - "acy;": "\u0430", - "aelig": "\xe6", - "aelig;": "\xe6", - "af;": "\u2061", - "afr;": "\U0001d51e", - "agrave": "\xe0", - "agrave;": "\xe0", - "alefsym;": "\u2135", - "aleph;": "\u2135", - "alpha;": "\u03b1", - "amacr;": "\u0101", - "amalg;": "\u2a3f", - "amp": "&", - "amp;": "&", - "and;": "\u2227", - "andand;": "\u2a55", - "andd;": "\u2a5c", - "andslope;": "\u2a58", - "andv;": "\u2a5a", - "ang;": "\u2220", - "ange;": "\u29a4", - "angle;": "\u2220", - "angmsd;": "\u2221", - "angmsdaa;": "\u29a8", - "angmsdab;": "\u29a9", - "angmsdac;": "\u29aa", - "angmsdad;": "\u29ab", - "angmsdae;": "\u29ac", - "angmsdaf;": "\u29ad", - "angmsdag;": "\u29ae", - "angmsdah;": "\u29af", - "angrt;": "\u221f", - "angrtvb;": "\u22be", - "angrtvbd;": "\u299d", - "angsph;": "\u2222", - "angst;": "\xc5", - "angzarr;": "\u237c", - "aogon;": "\u0105", - "aopf;": "\U0001d552", - "ap;": "\u2248", - "apE;": "\u2a70", - "apacir;": "\u2a6f", - "ape;": "\u224a", - "apid;": "\u224b", - "apos;": "'", - "approx;": "\u2248", - "approxeq;": "\u224a", - "aring": "\xe5", - "aring;": "\xe5", - "ascr;": "\U0001d4b6", - "ast;": "*", - "asymp;": "\u2248", - "asympeq;": "\u224d", - "atilde": "\xe3", - "atilde;": "\xe3", - "auml": "\xe4", - "auml;": "\xe4", - "awconint;": "\u2233", - "awint;": "\u2a11", - "bNot;": "\u2aed", - "backcong;": "\u224c", - "backepsilon;": "\u03f6", - "backprime;": "\u2035", - "backsim;": "\u223d", - "backsimeq;": "\u22cd", - "barvee;": "\u22bd", - "barwed;": "\u2305", - "barwedge;": "\u2305", - "bbrk;": "\u23b5", - "bbrktbrk;": "\u23b6", - "bcong;": "\u224c", - "bcy;": "\u0431", - "bdquo;": "\u201e", - "becaus;": "\u2235", - "because;": "\u2235", - "bemptyv;": "\u29b0", - "bepsi;": "\u03f6", - "bernou;": "\u212c", - "beta;": "\u03b2", - "beth;": "\u2136", - "between;": "\u226c", - "bfr;": "\U0001d51f", - "bigcap;": "\u22c2", - "bigcirc;": "\u25ef", - "bigcup;": "\u22c3", - "bigodot;": "\u2a00", - "bigoplus;": "\u2a01", - "bigotimes;": "\u2a02", - "bigsqcup;": "\u2a06", - "bigstar;": "\u2605", - "bigtriangledown;": "\u25bd", - "bigtriangleup;": "\u25b3", - "biguplus;": "\u2a04", - "bigvee;": "\u22c1", - "bigwedge;": "\u22c0", - "bkarow;": "\u290d", - "blacklozenge;": "\u29eb", - "blacksquare;": "\u25aa", - "blacktriangle;": "\u25b4", - "blacktriangledown;": "\u25be", - "blacktriangleleft;": "\u25c2", - "blacktriangleright;": "\u25b8", - "blank;": "\u2423", - "blk12;": "\u2592", - "blk14;": "\u2591", - "blk34;": "\u2593", - "block;": "\u2588", - "bne;": "=\u20e5", - "bnequiv;": "\u2261\u20e5", - "bnot;": "\u2310", - "bopf;": "\U0001d553", - "bot;": "\u22a5", - "bottom;": "\u22a5", - "bowtie;": "\u22c8", - "boxDL;": "\u2557", - "boxDR;": "\u2554", - "boxDl;": "\u2556", - "boxDr;": "\u2553", - "boxH;": "\u2550", - "boxHD;": "\u2566", - "boxHU;": "\u2569", - "boxHd;": "\u2564", - "boxHu;": "\u2567", - "boxUL;": "\u255d", - "boxUR;": "\u255a", - "boxUl;": "\u255c", - "boxUr;": "\u2559", - "boxV;": "\u2551", - "boxVH;": "\u256c", - "boxVL;": "\u2563", - "boxVR;": "\u2560", - "boxVh;": "\u256b", - "boxVl;": "\u2562", - "boxVr;": "\u255f", - "boxbox;": "\u29c9", - "boxdL;": "\u2555", - "boxdR;": "\u2552", - "boxdl;": "\u2510", - "boxdr;": "\u250c", - "boxh;": "\u2500", - "boxhD;": "\u2565", - "boxhU;": "\u2568", - "boxhd;": "\u252c", - "boxhu;": "\u2534", - "boxminus;": "\u229f", - "boxplus;": "\u229e", - "boxtimes;": "\u22a0", - "boxuL;": "\u255b", - "boxuR;": "\u2558", - "boxul;": "\u2518", - "boxur;": "\u2514", - "boxv;": "\u2502", - "boxvH;": "\u256a", - "boxvL;": "\u2561", - "boxvR;": "\u255e", - "boxvh;": "\u253c", - "boxvl;": "\u2524", - "boxvr;": "\u251c", - "bprime;": "\u2035", - "breve;": "\u02d8", - "brvbar": "\xa6", - "brvbar;": "\xa6", - "bscr;": "\U0001d4b7", - "bsemi;": "\u204f", - "bsim;": "\u223d", - "bsime;": "\u22cd", - "bsol;": "\\", - "bsolb;": "\u29c5", - "bsolhsub;": "\u27c8", - "bull;": "\u2022", - "bullet;": "\u2022", - "bump;": "\u224e", - "bumpE;": "\u2aae", - "bumpe;": "\u224f", - "bumpeq;": "\u224f", - "cacute;": "\u0107", - "cap;": "\u2229", - "capand;": "\u2a44", - "capbrcup;": "\u2a49", - "capcap;": "\u2a4b", - "capcup;": "\u2a47", - "capdot;": "\u2a40", - "caps;": "\u2229\ufe00", - "caret;": "\u2041", - "caron;": "\u02c7", - "ccaps;": "\u2a4d", - "ccaron;": "\u010d", - "ccedil": "\xe7", - "ccedil;": "\xe7", - "ccirc;": "\u0109", - "ccups;": "\u2a4c", - "ccupssm;": "\u2a50", - "cdot;": "\u010b", - "cedil": "\xb8", - "cedil;": "\xb8", - "cemptyv;": "\u29b2", - "cent": "\xa2", - "cent;": "\xa2", - "centerdot;": "\xb7", - "cfr;": "\U0001d520", - "chcy;": "\u0447", - "check;": "\u2713", - "checkmark;": "\u2713", - "chi;": "\u03c7", - "cir;": "\u25cb", - "cirE;": "\u29c3", - "circ;": "\u02c6", - "circeq;": "\u2257", - "circlearrowleft;": "\u21ba", - "circlearrowright;": "\u21bb", - "circledR;": "\xae", - "circledS;": "\u24c8", - "circledast;": "\u229b", - "circledcirc;": "\u229a", - "circleddash;": "\u229d", - "cire;": "\u2257", - "cirfnint;": "\u2a10", - "cirmid;": "\u2aef", - "cirscir;": "\u29c2", - "clubs;": "\u2663", - "clubsuit;": "\u2663", - "colon;": ":", - "colone;": "\u2254", - "coloneq;": "\u2254", - "comma;": ",", - "commat;": "@", - "comp;": "\u2201", - "compfn;": "\u2218", - "complement;": "\u2201", - "complexes;": "\u2102", - "cong;": "\u2245", - "congdot;": "\u2a6d", - "conint;": "\u222e", - "copf;": "\U0001d554", - "coprod;": "\u2210", - "copy": "\xa9", - "copy;": "\xa9", - "copysr;": "\u2117", - "crarr;": "\u21b5", - "cross;": "\u2717", - "cscr;": "\U0001d4b8", - "csub;": "\u2acf", - "csube;": "\u2ad1", - "csup;": "\u2ad0", - "csupe;": "\u2ad2", - "ctdot;": "\u22ef", - "cudarrl;": "\u2938", - "cudarrr;": "\u2935", - "cuepr;": "\u22de", - "cuesc;": "\u22df", - "cularr;": "\u21b6", - "cularrp;": "\u293d", - "cup;": "\u222a", - "cupbrcap;": "\u2a48", - "cupcap;": "\u2a46", - "cupcup;": "\u2a4a", - "cupdot;": "\u228d", - "cupor;": "\u2a45", - "cups;": "\u222a\ufe00", - "curarr;": "\u21b7", - "curarrm;": "\u293c", - "curlyeqprec;": "\u22de", - "curlyeqsucc;": "\u22df", - "curlyvee;": "\u22ce", - "curlywedge;": "\u22cf", - "curren": "\xa4", - "curren;": "\xa4", - "curvearrowleft;": "\u21b6", - "curvearrowright;": "\u21b7", - "cuvee;": "\u22ce", - "cuwed;": "\u22cf", - "cwconint;": "\u2232", - "cwint;": "\u2231", - "cylcty;": "\u232d", - "dArr;": "\u21d3", - "dHar;": "\u2965", - "dagger;": "\u2020", - "daleth;": "\u2138", - "darr;": "\u2193", - "dash;": "\u2010", - "dashv;": "\u22a3", - "dbkarow;": "\u290f", - "dblac;": "\u02dd", - "dcaron;": "\u010f", - "dcy;": "\u0434", - "dd;": "\u2146", - "ddagger;": "\u2021", - "ddarr;": "\u21ca", - "ddotseq;": "\u2a77", - "deg": "\xb0", - "deg;": "\xb0", - "delta;": "\u03b4", - "demptyv;": "\u29b1", - "dfisht;": "\u297f", - "dfr;": "\U0001d521", - "dharl;": "\u21c3", - "dharr;": "\u21c2", - "diam;": "\u22c4", - "diamond;": "\u22c4", - "diamondsuit;": "\u2666", - "diams;": "\u2666", - "die;": "\xa8", - "digamma;": "\u03dd", - "disin;": "\u22f2", - "div;": "\xf7", - "divide": "\xf7", - "divide;": "\xf7", - "divideontimes;": "\u22c7", - "divonx;": "\u22c7", - "djcy;": "\u0452", - "dlcorn;": "\u231e", - "dlcrop;": "\u230d", - "dollar;": "$", - "dopf;": "\U0001d555", - "dot;": "\u02d9", - "doteq;": "\u2250", - "doteqdot;": "\u2251", - "dotminus;": "\u2238", - "dotplus;": "\u2214", - "dotsquare;": "\u22a1", - "doublebarwedge;": "\u2306", - "downarrow;": "\u2193", - "downdownarrows;": "\u21ca", - "downharpoonleft;": "\u21c3", - "downharpoonright;": "\u21c2", - "drbkarow;": "\u2910", - "drcorn;": "\u231f", - "drcrop;": "\u230c", - "dscr;": "\U0001d4b9", - "dscy;": "\u0455", - "dsol;": "\u29f6", - "dstrok;": "\u0111", - "dtdot;": "\u22f1", - "dtri;": "\u25bf", - "dtrif;": "\u25be", - "duarr;": "\u21f5", - "duhar;": "\u296f", - "dwangle;": "\u29a6", - "dzcy;": "\u045f", - "dzigrarr;": "\u27ff", - "eDDot;": "\u2a77", - "eDot;": "\u2251", - "eacute": "\xe9", - "eacute;": "\xe9", - "easter;": "\u2a6e", - "ecaron;": "\u011b", - "ecir;": "\u2256", - "ecirc": "\xea", - "ecirc;": "\xea", - "ecolon;": "\u2255", - "ecy;": "\u044d", - "edot;": "\u0117", - "ee;": "\u2147", - "efDot;": "\u2252", - "efr;": "\U0001d522", - "eg;": "\u2a9a", - "egrave": "\xe8", - "egrave;": "\xe8", - "egs;": "\u2a96", - "egsdot;": "\u2a98", - "el;": "\u2a99", - "elinters;": "\u23e7", - "ell;": "\u2113", - "els;": "\u2a95", - "elsdot;": "\u2a97", - "emacr;": "\u0113", - "empty;": "\u2205", - "emptyset;": "\u2205", - "emptyv;": "\u2205", - "emsp13;": "\u2004", - "emsp14;": "\u2005", - "emsp;": "\u2003", - "eng;": "\u014b", - "ensp;": "\u2002", - "eogon;": "\u0119", - "eopf;": "\U0001d556", - "epar;": "\u22d5", - "eparsl;": "\u29e3", - "eplus;": "\u2a71", - "epsi;": "\u03b5", - "epsilon;": "\u03b5", - "epsiv;": "\u03f5", - "eqcirc;": "\u2256", - "eqcolon;": "\u2255", - "eqsim;": "\u2242", - "eqslantgtr;": "\u2a96", - "eqslantless;": "\u2a95", - "equals;": "=", - "equest;": "\u225f", - "equiv;": "\u2261", - "equivDD;": "\u2a78", - "eqvparsl;": "\u29e5", - "erDot;": "\u2253", - "erarr;": "\u2971", - "escr;": "\u212f", - "esdot;": "\u2250", - "esim;": "\u2242", - "eta;": "\u03b7", - "eth": "\xf0", - "eth;": "\xf0", - "euml": "\xeb", - "euml;": "\xeb", - "euro;": "\u20ac", - "excl;": "!", - "exist;": "\u2203", - "expectation;": "\u2130", - "exponentiale;": "\u2147", - "fallingdotseq;": "\u2252", - "fcy;": "\u0444", - "female;": "\u2640", - "ffilig;": "\ufb03", - "fflig;": "\ufb00", - "ffllig;": "\ufb04", - "ffr;": "\U0001d523", - "filig;": "\ufb01", - "fjlig;": "fj", - "flat;": "\u266d", - "fllig;": "\ufb02", - "fltns;": "\u25b1", - "fnof;": "\u0192", - "fopf;": "\U0001d557", - "forall;": "\u2200", - "fork;": "\u22d4", - "forkv;": "\u2ad9", - "fpartint;": "\u2a0d", - "frac12": "\xbd", - "frac12;": "\xbd", - "frac13;": "\u2153", - "frac14": "\xbc", - "frac14;": "\xbc", - "frac15;": "\u2155", - "frac16;": "\u2159", - "frac18;": "\u215b", - "frac23;": "\u2154", - "frac25;": "\u2156", - "frac34": "\xbe", - "frac34;": "\xbe", - "frac35;": "\u2157", - "frac38;": "\u215c", - "frac45;": "\u2158", - "frac56;": "\u215a", - "frac58;": "\u215d", - "frac78;": "\u215e", - "frasl;": "\u2044", - "frown;": "\u2322", - "fscr;": "\U0001d4bb", - "gE;": "\u2267", - "gEl;": "\u2a8c", - "gacute;": "\u01f5", - "gamma;": "\u03b3", - "gammad;": "\u03dd", - "gap;": "\u2a86", - "gbreve;": "\u011f", - "gcirc;": "\u011d", - "gcy;": "\u0433", - "gdot;": "\u0121", - "ge;": "\u2265", - "gel;": "\u22db", - "geq;": "\u2265", - "geqq;": "\u2267", - "geqslant;": "\u2a7e", - "ges;": "\u2a7e", - "gescc;": "\u2aa9", - "gesdot;": "\u2a80", - "gesdoto;": "\u2a82", - "gesdotol;": "\u2a84", - "gesl;": "\u22db\ufe00", - "gesles;": "\u2a94", - "gfr;": "\U0001d524", - "gg;": "\u226b", - "ggg;": "\u22d9", - "gimel;": "\u2137", - "gjcy;": "\u0453", - "gl;": "\u2277", - "glE;": "\u2a92", - "gla;": "\u2aa5", - "glj;": "\u2aa4", - "gnE;": "\u2269", - "gnap;": "\u2a8a", - "gnapprox;": "\u2a8a", - "gne;": "\u2a88", - "gneq;": "\u2a88", - "gneqq;": "\u2269", - "gnsim;": "\u22e7", - "gopf;": "\U0001d558", - "grave;": "`", - "gscr;": "\u210a", - "gsim;": "\u2273", - "gsime;": "\u2a8e", - "gsiml;": "\u2a90", - "gt": ">", - "gt;": ">", - "gtcc;": "\u2aa7", - "gtcir;": "\u2a7a", - "gtdot;": "\u22d7", - "gtlPar;": "\u2995", - "gtquest;": "\u2a7c", - "gtrapprox;": "\u2a86", - "gtrarr;": "\u2978", - "gtrdot;": "\u22d7", - "gtreqless;": "\u22db", - "gtreqqless;": "\u2a8c", - "gtrless;": "\u2277", - "gtrsim;": "\u2273", - "gvertneqq;": "\u2269\ufe00", - "gvnE;": "\u2269\ufe00", - "hArr;": "\u21d4", - "hairsp;": "\u200a", - "half;": "\xbd", - "hamilt;": "\u210b", - "hardcy;": "\u044a", - "harr;": "\u2194", - "harrcir;": "\u2948", - "harrw;": "\u21ad", - "hbar;": "\u210f", - "hcirc;": "\u0125", - "hearts;": "\u2665", - "heartsuit;": "\u2665", - "hellip;": "\u2026", - "hercon;": "\u22b9", - "hfr;": "\U0001d525", - "hksearow;": "\u2925", - "hkswarow;": "\u2926", - "hoarr;": "\u21ff", - "homtht;": "\u223b", - "hookleftarrow;": "\u21a9", - "hookrightarrow;": "\u21aa", - "hopf;": "\U0001d559", - "horbar;": "\u2015", - "hscr;": "\U0001d4bd", - "hslash;": "\u210f", - "hstrok;": "\u0127", - "hybull;": "\u2043", - "hyphen;": "\u2010", - "iacute": "\xed", - "iacute;": "\xed", - "ic;": "\u2063", - "icirc": "\xee", - "icirc;": "\xee", - "icy;": "\u0438", - "iecy;": "\u0435", - "iexcl": "\xa1", - "iexcl;": "\xa1", - "iff;": "\u21d4", - "ifr;": "\U0001d526", - "igrave": "\xec", - "igrave;": "\xec", - "ii;": "\u2148", - "iiiint;": "\u2a0c", - "iiint;": "\u222d", - "iinfin;": "\u29dc", - "iiota;": "\u2129", - "ijlig;": "\u0133", - "imacr;": "\u012b", - "image;": "\u2111", - "imagline;": "\u2110", - "imagpart;": "\u2111", - "imath;": "\u0131", - "imof;": "\u22b7", - "imped;": "\u01b5", - "in;": "\u2208", - "incare;": "\u2105", - "infin;": "\u221e", - "infintie;": "\u29dd", - "inodot;": "\u0131", - "int;": "\u222b", - "intcal;": "\u22ba", - "integers;": "\u2124", - "intercal;": "\u22ba", - "intlarhk;": "\u2a17", - "intprod;": "\u2a3c", - "iocy;": "\u0451", - "iogon;": "\u012f", - "iopf;": "\U0001d55a", - "iota;": "\u03b9", - "iprod;": "\u2a3c", - "iquest": "\xbf", - "iquest;": "\xbf", - "iscr;": "\U0001d4be", - "isin;": "\u2208", - "isinE;": "\u22f9", - "isindot;": "\u22f5", - "isins;": "\u22f4", - "isinsv;": "\u22f3", - "isinv;": "\u2208", - "it;": "\u2062", - "itilde;": "\u0129", - "iukcy;": "\u0456", - "iuml": "\xef", - "iuml;": "\xef", - "jcirc;": "\u0135", - "jcy;": "\u0439", - "jfr;": "\U0001d527", - "jmath;": "\u0237", - "jopf;": "\U0001d55b", - "jscr;": "\U0001d4bf", - "jsercy;": "\u0458", - "jukcy;": "\u0454", - "kappa;": "\u03ba", - "kappav;": "\u03f0", - "kcedil;": "\u0137", - "kcy;": "\u043a", - "kfr;": "\U0001d528", - "kgreen;": "\u0138", - "khcy;": "\u0445", - "kjcy;": "\u045c", - "kopf;": "\U0001d55c", - "kscr;": "\U0001d4c0", - "lAarr;": "\u21da", - "lArr;": "\u21d0", - "lAtail;": "\u291b", - "lBarr;": "\u290e", - "lE;": "\u2266", - "lEg;": "\u2a8b", - "lHar;": "\u2962", - "lacute;": "\u013a", - "laemptyv;": "\u29b4", - "lagran;": "\u2112", - "lambda;": "\u03bb", - "lang;": "\u27e8", - "langd;": "\u2991", - "langle;": "\u27e8", - "lap;": "\u2a85", - "laquo": "\xab", - "laquo;": "\xab", - "larr;": "\u2190", - "larrb;": "\u21e4", - "larrbfs;": "\u291f", - "larrfs;": "\u291d", - "larrhk;": "\u21a9", - "larrlp;": "\u21ab", - "larrpl;": "\u2939", - "larrsim;": "\u2973", - "larrtl;": "\u21a2", - "lat;": "\u2aab", - "latail;": "\u2919", - "late;": "\u2aad", - "lates;": "\u2aad\ufe00", - "lbarr;": "\u290c", - "lbbrk;": "\u2772", - "lbrace;": "{", - "lbrack;": "[", - "lbrke;": "\u298b", - "lbrksld;": "\u298f", - "lbrkslu;": "\u298d", - "lcaron;": "\u013e", - "lcedil;": "\u013c", - "lceil;": "\u2308", - "lcub;": "{", - "lcy;": "\u043b", - "ldca;": "\u2936", - "ldquo;": "\u201c", - "ldquor;": "\u201e", - "ldrdhar;": "\u2967", - "ldrushar;": "\u294b", - "ldsh;": "\u21b2", - "le;": "\u2264", - "leftarrow;": "\u2190", - "leftarrowtail;": "\u21a2", - "leftharpoondown;": "\u21bd", - "leftharpoonup;": "\u21bc", - "leftleftarrows;": "\u21c7", - "leftrightarrow;": "\u2194", - "leftrightarrows;": "\u21c6", - "leftrightharpoons;": "\u21cb", - "leftrightsquigarrow;": "\u21ad", - "leftthreetimes;": "\u22cb", - "leg;": "\u22da", - "leq;": "\u2264", - "leqq;": "\u2266", - "leqslant;": "\u2a7d", - "les;": "\u2a7d", - "lescc;": "\u2aa8", - "lesdot;": "\u2a7f", - "lesdoto;": "\u2a81", - "lesdotor;": "\u2a83", - "lesg;": "\u22da\ufe00", - "lesges;": "\u2a93", - "lessapprox;": "\u2a85", - "lessdot;": "\u22d6", - "lesseqgtr;": "\u22da", - "lesseqqgtr;": "\u2a8b", - "lessgtr;": "\u2276", - "lesssim;": "\u2272", - "lfisht;": "\u297c", - "lfloor;": "\u230a", - "lfr;": "\U0001d529", - "lg;": "\u2276", - "lgE;": "\u2a91", - "lhard;": "\u21bd", - "lharu;": "\u21bc", - "lharul;": "\u296a", - "lhblk;": "\u2584", - "ljcy;": "\u0459", - "ll;": "\u226a", - "llarr;": "\u21c7", - "llcorner;": "\u231e", - "llhard;": "\u296b", - "lltri;": "\u25fa", - "lmidot;": "\u0140", - "lmoust;": "\u23b0", - "lmoustache;": "\u23b0", - "lnE;": "\u2268", - "lnap;": "\u2a89", - "lnapprox;": "\u2a89", - "lne;": "\u2a87", - "lneq;": "\u2a87", - "lneqq;": "\u2268", - "lnsim;": "\u22e6", - "loang;": "\u27ec", - "loarr;": "\u21fd", - "lobrk;": "\u27e6", - "longleftarrow;": "\u27f5", - "longleftrightarrow;": "\u27f7", - "longmapsto;": "\u27fc", - "longrightarrow;": "\u27f6", - "looparrowleft;": "\u21ab", - "looparrowright;": "\u21ac", - "lopar;": "\u2985", - "lopf;": "\U0001d55d", - "loplus;": "\u2a2d", - "lotimes;": "\u2a34", - "lowast;": "\u2217", - "lowbar;": "_", - "loz;": "\u25ca", - "lozenge;": "\u25ca", - "lozf;": "\u29eb", - "lpar;": "(", - "lparlt;": "\u2993", - "lrarr;": "\u21c6", - "lrcorner;": "\u231f", - "lrhar;": "\u21cb", - "lrhard;": "\u296d", - "lrm;": "\u200e", - "lrtri;": "\u22bf", - "lsaquo;": "\u2039", - "lscr;": "\U0001d4c1", - "lsh;": "\u21b0", - "lsim;": "\u2272", - "lsime;": "\u2a8d", - "lsimg;": "\u2a8f", - "lsqb;": "[", - "lsquo;": "\u2018", - "lsquor;": "\u201a", - "lstrok;": "\u0142", - "lt": "<", - "lt;": "<", - "ltcc;": "\u2aa6", - "ltcir;": "\u2a79", - "ltdot;": "\u22d6", - "lthree;": "\u22cb", - "ltimes;": "\u22c9", - "ltlarr;": "\u2976", - "ltquest;": "\u2a7b", - "ltrPar;": "\u2996", - "ltri;": "\u25c3", - "ltrie;": "\u22b4", - "ltrif;": "\u25c2", - "lurdshar;": "\u294a", - "luruhar;": "\u2966", - "lvertneqq;": "\u2268\ufe00", - "lvnE;": "\u2268\ufe00", - "mDDot;": "\u223a", - "macr": "\xaf", - "macr;": "\xaf", - "male;": "\u2642", - "malt;": "\u2720", - "maltese;": "\u2720", - "map;": "\u21a6", - "mapsto;": "\u21a6", - "mapstodown;": "\u21a7", - "mapstoleft;": "\u21a4", - "mapstoup;": "\u21a5", - "marker;": "\u25ae", - "mcomma;": "\u2a29", - "mcy;": "\u043c", - "mdash;": "\u2014", - "measuredangle;": "\u2221", - "mfr;": "\U0001d52a", - "mho;": "\u2127", - "micro": "\xb5", - "micro;": "\xb5", - "mid;": "\u2223", - "midast;": "*", - "midcir;": "\u2af0", - "middot": "\xb7", - "middot;": "\xb7", - "minus;": "\u2212", - "minusb;": "\u229f", - "minusd;": "\u2238", - "minusdu;": "\u2a2a", - "mlcp;": "\u2adb", - "mldr;": "\u2026", - "mnplus;": "\u2213", - "models;": "\u22a7", - "mopf;": "\U0001d55e", - "mp;": "\u2213", - "mscr;": "\U0001d4c2", - "mstpos;": "\u223e", - "mu;": "\u03bc", - "multimap;": "\u22b8", - "mumap;": "\u22b8", - "nGg;": "\u22d9\u0338", - "nGt;": "\u226b\u20d2", - "nGtv;": "\u226b\u0338", - "nLeftarrow;": "\u21cd", - "nLeftrightarrow;": "\u21ce", - "nLl;": "\u22d8\u0338", - "nLt;": "\u226a\u20d2", - "nLtv;": "\u226a\u0338", - "nRightarrow;": "\u21cf", - "nVDash;": "\u22af", - "nVdash;": "\u22ae", - "nabla;": "\u2207", - "nacute;": "\u0144", - "nang;": "\u2220\u20d2", - "nap;": "\u2249", - "napE;": "\u2a70\u0338", - "napid;": "\u224b\u0338", - "napos;": "\u0149", - "napprox;": "\u2249", - "natur;": "\u266e", - "natural;": "\u266e", - "naturals;": "\u2115", - "nbsp": "\xa0", - "nbsp;": "\xa0", - "nbump;": "\u224e\u0338", - "nbumpe;": "\u224f\u0338", - "ncap;": "\u2a43", - "ncaron;": "\u0148", - "ncedil;": "\u0146", - "ncong;": "\u2247", - "ncongdot;": "\u2a6d\u0338", - "ncup;": "\u2a42", - "ncy;": "\u043d", - "ndash;": "\u2013", - "ne;": "\u2260", - "neArr;": "\u21d7", - "nearhk;": "\u2924", - "nearr;": "\u2197", - "nearrow;": "\u2197", - "nedot;": "\u2250\u0338", - "nequiv;": "\u2262", - "nesear;": "\u2928", - "nesim;": "\u2242\u0338", - "nexist;": "\u2204", - "nexists;": "\u2204", - "nfr;": "\U0001d52b", - "ngE;": "\u2267\u0338", - "nge;": "\u2271", - "ngeq;": "\u2271", - "ngeqq;": "\u2267\u0338", - "ngeqslant;": "\u2a7e\u0338", - "nges;": "\u2a7e\u0338", - "ngsim;": "\u2275", - "ngt;": "\u226f", - "ngtr;": "\u226f", - "nhArr;": "\u21ce", - "nharr;": "\u21ae", - "nhpar;": "\u2af2", - "ni;": "\u220b", - "nis;": "\u22fc", - "nisd;": "\u22fa", - "niv;": "\u220b", - "njcy;": "\u045a", - "nlArr;": "\u21cd", - "nlE;": "\u2266\u0338", - "nlarr;": "\u219a", - "nldr;": "\u2025", - "nle;": "\u2270", - "nleftarrow;": "\u219a", - "nleftrightarrow;": "\u21ae", - "nleq;": "\u2270", - "nleqq;": "\u2266\u0338", - "nleqslant;": "\u2a7d\u0338", - "nles;": "\u2a7d\u0338", - "nless;": "\u226e", - "nlsim;": "\u2274", - "nlt;": "\u226e", - "nltri;": "\u22ea", - "nltrie;": "\u22ec", - "nmid;": "\u2224", - "nopf;": "\U0001d55f", - "not": "\xac", - "not;": "\xac", - "notin;": "\u2209", - "notinE;": "\u22f9\u0338", - "notindot;": "\u22f5\u0338", - "notinva;": "\u2209", - "notinvb;": "\u22f7", - "notinvc;": "\u22f6", - "notni;": "\u220c", - "notniva;": "\u220c", - "notnivb;": "\u22fe", - "notnivc;": "\u22fd", - "npar;": "\u2226", - "nparallel;": "\u2226", - "nparsl;": "\u2afd\u20e5", - "npart;": "\u2202\u0338", - "npolint;": "\u2a14", - "npr;": "\u2280", - "nprcue;": "\u22e0", - "npre;": "\u2aaf\u0338", - "nprec;": "\u2280", - "npreceq;": "\u2aaf\u0338", - "nrArr;": "\u21cf", - "nrarr;": "\u219b", - "nrarrc;": "\u2933\u0338", - "nrarrw;": "\u219d\u0338", - "nrightarrow;": "\u219b", - "nrtri;": "\u22eb", - "nrtrie;": "\u22ed", - "nsc;": "\u2281", - "nsccue;": "\u22e1", - "nsce;": "\u2ab0\u0338", - "nscr;": "\U0001d4c3", - "nshortmid;": "\u2224", - "nshortparallel;": "\u2226", - "nsim;": "\u2241", - "nsime;": "\u2244", - "nsimeq;": "\u2244", - "nsmid;": "\u2224", - "nspar;": "\u2226", - "nsqsube;": "\u22e2", - "nsqsupe;": "\u22e3", - "nsub;": "\u2284", - "nsubE;": "\u2ac5\u0338", - "nsube;": "\u2288", - "nsubset;": "\u2282\u20d2", - "nsubseteq;": "\u2288", - "nsubseteqq;": "\u2ac5\u0338", - "nsucc;": "\u2281", - "nsucceq;": "\u2ab0\u0338", - "nsup;": "\u2285", - "nsupE;": "\u2ac6\u0338", - "nsupe;": "\u2289", - "nsupset;": "\u2283\u20d2", - "nsupseteq;": "\u2289", - "nsupseteqq;": "\u2ac6\u0338", - "ntgl;": "\u2279", - "ntilde": "\xf1", - "ntilde;": "\xf1", - "ntlg;": "\u2278", - "ntriangleleft;": "\u22ea", - "ntrianglelefteq;": "\u22ec", - "ntriangleright;": "\u22eb", - "ntrianglerighteq;": "\u22ed", - "nu;": "\u03bd", - "num;": "#", - "numero;": "\u2116", - "numsp;": "\u2007", - "nvDash;": "\u22ad", - "nvHarr;": "\u2904", - "nvap;": "\u224d\u20d2", - "nvdash;": "\u22ac", - "nvge;": "\u2265\u20d2", - "nvgt;": ">\u20d2", - "nvinfin;": "\u29de", - "nvlArr;": "\u2902", - "nvle;": "\u2264\u20d2", - "nvlt;": "<\u20d2", - "nvltrie;": "\u22b4\u20d2", - "nvrArr;": "\u2903", - "nvrtrie;": "\u22b5\u20d2", - "nvsim;": "\u223c\u20d2", - "nwArr;": "\u21d6", - "nwarhk;": "\u2923", - "nwarr;": "\u2196", - "nwarrow;": "\u2196", - "nwnear;": "\u2927", - "oS;": "\u24c8", - "oacute": "\xf3", - "oacute;": "\xf3", - "oast;": "\u229b", - "ocir;": "\u229a", - "ocirc": "\xf4", - "ocirc;": "\xf4", - "ocy;": "\u043e", - "odash;": "\u229d", - "odblac;": "\u0151", - "odiv;": "\u2a38", - "odot;": "\u2299", - "odsold;": "\u29bc", - "oelig;": "\u0153", - "ofcir;": "\u29bf", - "ofr;": "\U0001d52c", - "ogon;": "\u02db", - "ograve": "\xf2", - "ograve;": "\xf2", - "ogt;": "\u29c1", - "ohbar;": "\u29b5", - "ohm;": "\u03a9", - "oint;": "\u222e", - "olarr;": "\u21ba", - "olcir;": "\u29be", - "olcross;": "\u29bb", - "oline;": "\u203e", - "olt;": "\u29c0", - "omacr;": "\u014d", - "omega;": "\u03c9", - "omicron;": "\u03bf", - "omid;": "\u29b6", - "ominus;": "\u2296", - "oopf;": "\U0001d560", - "opar;": "\u29b7", - "operp;": "\u29b9", - "oplus;": "\u2295", - "or;": "\u2228", - "orarr;": "\u21bb", - "ord;": "\u2a5d", - "order;": "\u2134", - "orderof;": "\u2134", - "ordf": "\xaa", - "ordf;": "\xaa", - "ordm": "\xba", - "ordm;": "\xba", - "origof;": "\u22b6", - "oror;": "\u2a56", - "orslope;": "\u2a57", - "orv;": "\u2a5b", - "oscr;": "\u2134", - "oslash": "\xf8", - "oslash;": "\xf8", - "osol;": "\u2298", - "otilde": "\xf5", - "otilde;": "\xf5", - "otimes;": "\u2297", - "otimesas;": "\u2a36", - "ouml": "\xf6", - "ouml;": "\xf6", - "ovbar;": "\u233d", - "par;": "\u2225", - "para": "\xb6", - "para;": "\xb6", - "parallel;": "\u2225", - "parsim;": "\u2af3", - "parsl;": "\u2afd", - "part;": "\u2202", - "pcy;": "\u043f", - "percnt;": "%", - "period;": ".", - "permil;": "\u2030", - "perp;": "\u22a5", - "pertenk;": "\u2031", - "pfr;": "\U0001d52d", - "phi;": "\u03c6", - "phiv;": "\u03d5", - "phmmat;": "\u2133", - "phone;": "\u260e", - "pi;": "\u03c0", - "pitchfork;": "\u22d4", - "piv;": "\u03d6", - "planck;": "\u210f", - "planckh;": "\u210e", - "plankv;": "\u210f", - "plus;": "+", - "plusacir;": "\u2a23", - "plusb;": "\u229e", - "pluscir;": "\u2a22", - "plusdo;": "\u2214", - "plusdu;": "\u2a25", - "pluse;": "\u2a72", - "plusmn": "\xb1", - "plusmn;": "\xb1", - "plussim;": "\u2a26", - "plustwo;": "\u2a27", - "pm;": "\xb1", - "pointint;": "\u2a15", - "popf;": "\U0001d561", - "pound": "\xa3", - "pound;": "\xa3", - "pr;": "\u227a", - "prE;": "\u2ab3", - "prap;": "\u2ab7", - "prcue;": "\u227c", - "pre;": "\u2aaf", - "prec;": "\u227a", - "precapprox;": "\u2ab7", - "preccurlyeq;": "\u227c", - "preceq;": "\u2aaf", - "precnapprox;": "\u2ab9", - "precneqq;": "\u2ab5", - "precnsim;": "\u22e8", - "precsim;": "\u227e", - "prime;": "\u2032", - "primes;": "\u2119", - "prnE;": "\u2ab5", - "prnap;": "\u2ab9", - "prnsim;": "\u22e8", - "prod;": "\u220f", - "profalar;": "\u232e", - "profline;": "\u2312", - "profsurf;": "\u2313", - "prop;": "\u221d", - "propto;": "\u221d", - "prsim;": "\u227e", - "prurel;": "\u22b0", - "pscr;": "\U0001d4c5", - "psi;": "\u03c8", - "puncsp;": "\u2008", - "qfr;": "\U0001d52e", - "qint;": "\u2a0c", - "qopf;": "\U0001d562", - "qprime;": "\u2057", - "qscr;": "\U0001d4c6", - "quaternions;": "\u210d", - "quatint;": "\u2a16", - "quest;": "?", - "questeq;": "\u225f", - "quot": "\"", - "quot;": "\"", - "rAarr;": "\u21db", - "rArr;": "\u21d2", - "rAtail;": "\u291c", - "rBarr;": "\u290f", - "rHar;": "\u2964", - "race;": "\u223d\u0331", - "racute;": "\u0155", - "radic;": "\u221a", - "raemptyv;": "\u29b3", - "rang;": "\u27e9", - "rangd;": "\u2992", - "range;": "\u29a5", - "rangle;": "\u27e9", - "raquo": "\xbb", - "raquo;": "\xbb", - "rarr;": "\u2192", - "rarrap;": "\u2975", - "rarrb;": "\u21e5", - "rarrbfs;": "\u2920", - "rarrc;": "\u2933", - "rarrfs;": "\u291e", - "rarrhk;": "\u21aa", - "rarrlp;": "\u21ac", - "rarrpl;": "\u2945", - "rarrsim;": "\u2974", - "rarrtl;": "\u21a3", - "rarrw;": "\u219d", - "ratail;": "\u291a", - "ratio;": "\u2236", - "rationals;": "\u211a", - "rbarr;": "\u290d", - "rbbrk;": "\u2773", - "rbrace;": "}", - "rbrack;": "]", - "rbrke;": "\u298c", - "rbrksld;": "\u298e", - "rbrkslu;": "\u2990", - "rcaron;": "\u0159", - "rcedil;": "\u0157", - "rceil;": "\u2309", - "rcub;": "}", - "rcy;": "\u0440", - "rdca;": "\u2937", - "rdldhar;": "\u2969", - "rdquo;": "\u201d", - "rdquor;": "\u201d", - "rdsh;": "\u21b3", - "real;": "\u211c", - "realine;": "\u211b", - "realpart;": "\u211c", - "reals;": "\u211d", - "rect;": "\u25ad", - "reg": "\xae", - "reg;": "\xae", - "rfisht;": "\u297d", - "rfloor;": "\u230b", - "rfr;": "\U0001d52f", - "rhard;": "\u21c1", - "rharu;": "\u21c0", - "rharul;": "\u296c", - "rho;": "\u03c1", - "rhov;": "\u03f1", - "rightarrow;": "\u2192", - "rightarrowtail;": "\u21a3", - "rightharpoondown;": "\u21c1", - "rightharpoonup;": "\u21c0", - "rightleftarrows;": "\u21c4", - "rightleftharpoons;": "\u21cc", - "rightrightarrows;": "\u21c9", - "rightsquigarrow;": "\u219d", - "rightthreetimes;": "\u22cc", - "ring;": "\u02da", - "risingdotseq;": "\u2253", - "rlarr;": "\u21c4", - "rlhar;": "\u21cc", - "rlm;": "\u200f", - "rmoust;": "\u23b1", - "rmoustache;": "\u23b1", - "rnmid;": "\u2aee", - "roang;": "\u27ed", - "roarr;": "\u21fe", - "robrk;": "\u27e7", - "ropar;": "\u2986", - "ropf;": "\U0001d563", - "roplus;": "\u2a2e", - "rotimes;": "\u2a35", - "rpar;": ")", - "rpargt;": "\u2994", - "rppolint;": "\u2a12", - "rrarr;": "\u21c9", - "rsaquo;": "\u203a", - "rscr;": "\U0001d4c7", - "rsh;": "\u21b1", - "rsqb;": "]", - "rsquo;": "\u2019", - "rsquor;": "\u2019", - "rthree;": "\u22cc", - "rtimes;": "\u22ca", - "rtri;": "\u25b9", - "rtrie;": "\u22b5", - "rtrif;": "\u25b8", - "rtriltri;": "\u29ce", - "ruluhar;": "\u2968", - "rx;": "\u211e", - "sacute;": "\u015b", - "sbquo;": "\u201a", - "sc;": "\u227b", - "scE;": "\u2ab4", - "scap;": "\u2ab8", - "scaron;": "\u0161", - "sccue;": "\u227d", - "sce;": "\u2ab0", - "scedil;": "\u015f", - "scirc;": "\u015d", - "scnE;": "\u2ab6", - "scnap;": "\u2aba", - "scnsim;": "\u22e9", - "scpolint;": "\u2a13", - "scsim;": "\u227f", - "scy;": "\u0441", - "sdot;": "\u22c5", - "sdotb;": "\u22a1", - "sdote;": "\u2a66", - "seArr;": "\u21d8", - "searhk;": "\u2925", - "searr;": "\u2198", - "searrow;": "\u2198", - "sect": "\xa7", - "sect;": "\xa7", - "semi;": ";", - "seswar;": "\u2929", - "setminus;": "\u2216", - "setmn;": "\u2216", - "sext;": "\u2736", - "sfr;": "\U0001d530", - "sfrown;": "\u2322", - "sharp;": "\u266f", - "shchcy;": "\u0449", - "shcy;": "\u0448", - "shortmid;": "\u2223", - "shortparallel;": "\u2225", - "shy": "\xad", - "shy;": "\xad", - "sigma;": "\u03c3", - "sigmaf;": "\u03c2", - "sigmav;": "\u03c2", - "sim;": "\u223c", - "simdot;": "\u2a6a", - "sime;": "\u2243", - "simeq;": "\u2243", - "simg;": "\u2a9e", - "simgE;": "\u2aa0", - "siml;": "\u2a9d", - "simlE;": "\u2a9f", - "simne;": "\u2246", - "simplus;": "\u2a24", - "simrarr;": "\u2972", - "slarr;": "\u2190", - "smallsetminus;": "\u2216", - "smashp;": "\u2a33", - "smeparsl;": "\u29e4", - "smid;": "\u2223", - "smile;": "\u2323", - "smt;": "\u2aaa", - "smte;": "\u2aac", - "smtes;": "\u2aac\ufe00", - "softcy;": "\u044c", - "sol;": "/", - "solb;": "\u29c4", - "solbar;": "\u233f", - "sopf;": "\U0001d564", - "spades;": "\u2660", - "spadesuit;": "\u2660", - "spar;": "\u2225", - "sqcap;": "\u2293", - "sqcaps;": "\u2293\ufe00", - "sqcup;": "\u2294", - "sqcups;": "\u2294\ufe00", - "sqsub;": "\u228f", - "sqsube;": "\u2291", - "sqsubset;": "\u228f", - "sqsubseteq;": "\u2291", - "sqsup;": "\u2290", - "sqsupe;": "\u2292", - "sqsupset;": "\u2290", - "sqsupseteq;": "\u2292", - "squ;": "\u25a1", - "square;": "\u25a1", - "squarf;": "\u25aa", - "squf;": "\u25aa", - "srarr;": "\u2192", - "sscr;": "\U0001d4c8", - "ssetmn;": "\u2216", - "ssmile;": "\u2323", - "sstarf;": "\u22c6", - "star;": "\u2606", - "starf;": "\u2605", - "straightepsilon;": "\u03f5", - "straightphi;": "\u03d5", - "strns;": "\xaf", - "sub;": "\u2282", - "subE;": "\u2ac5", - "subdot;": "\u2abd", - "sube;": "\u2286", - "subedot;": "\u2ac3", - "submult;": "\u2ac1", - "subnE;": "\u2acb", - "subne;": "\u228a", - "subplus;": "\u2abf", - "subrarr;": "\u2979", - "subset;": "\u2282", - "subseteq;": "\u2286", - "subseteqq;": "\u2ac5", - "subsetneq;": "\u228a", - "subsetneqq;": "\u2acb", - "subsim;": "\u2ac7", - "subsub;": "\u2ad5", - "subsup;": "\u2ad3", - "succ;": "\u227b", - "succapprox;": "\u2ab8", - "succcurlyeq;": "\u227d", - "succeq;": "\u2ab0", - "succnapprox;": "\u2aba", - "succneqq;": "\u2ab6", - "succnsim;": "\u22e9", - "succsim;": "\u227f", - "sum;": "\u2211", - "sung;": "\u266a", - "sup1": "\xb9", - "sup1;": "\xb9", - "sup2": "\xb2", - "sup2;": "\xb2", - "sup3": "\xb3", - "sup3;": "\xb3", - "sup;": "\u2283", - "supE;": "\u2ac6", - "supdot;": "\u2abe", - "supdsub;": "\u2ad8", - "supe;": "\u2287", - "supedot;": "\u2ac4", - "suphsol;": "\u27c9", - "suphsub;": "\u2ad7", - "suplarr;": "\u297b", - "supmult;": "\u2ac2", - "supnE;": "\u2acc", - "supne;": "\u228b", - "supplus;": "\u2ac0", - "supset;": "\u2283", - "supseteq;": "\u2287", - "supseteqq;": "\u2ac6", - "supsetneq;": "\u228b", - "supsetneqq;": "\u2acc", - "supsim;": "\u2ac8", - "supsub;": "\u2ad4", - "supsup;": "\u2ad6", - "swArr;": "\u21d9", - "swarhk;": "\u2926", - "swarr;": "\u2199", - "swarrow;": "\u2199", - "swnwar;": "\u292a", - "szlig": "\xdf", - "szlig;": "\xdf", - "target;": "\u2316", - "tau;": "\u03c4", - "tbrk;": "\u23b4", - "tcaron;": "\u0165", - "tcedil;": "\u0163", - "tcy;": "\u0442", - "tdot;": "\u20db", - "telrec;": "\u2315", - "tfr;": "\U0001d531", - "there4;": "\u2234", - "therefore;": "\u2234", - "theta;": "\u03b8", - "thetasym;": "\u03d1", - "thetav;": "\u03d1", - "thickapprox;": "\u2248", - "thicksim;": "\u223c", - "thinsp;": "\u2009", - "thkap;": "\u2248", - "thksim;": "\u223c", - "thorn": "\xfe", - "thorn;": "\xfe", - "tilde;": "\u02dc", - "times": "\xd7", - "times;": "\xd7", - "timesb;": "\u22a0", - "timesbar;": "\u2a31", - "timesd;": "\u2a30", - "tint;": "\u222d", - "toea;": "\u2928", - "top;": "\u22a4", - "topbot;": "\u2336", - "topcir;": "\u2af1", - "topf;": "\U0001d565", - "topfork;": "\u2ada", - "tosa;": "\u2929", - "tprime;": "\u2034", - "trade;": "\u2122", - "triangle;": "\u25b5", - "triangledown;": "\u25bf", - "triangleleft;": "\u25c3", - "trianglelefteq;": "\u22b4", - "triangleq;": "\u225c", - "triangleright;": "\u25b9", - "trianglerighteq;": "\u22b5", - "tridot;": "\u25ec", - "trie;": "\u225c", - "triminus;": "\u2a3a", - "triplus;": "\u2a39", - "trisb;": "\u29cd", - "tritime;": "\u2a3b", - "trpezium;": "\u23e2", - "tscr;": "\U0001d4c9", - "tscy;": "\u0446", - "tshcy;": "\u045b", - "tstrok;": "\u0167", - "twixt;": "\u226c", - "twoheadleftarrow;": "\u219e", - "twoheadrightarrow;": "\u21a0", - "uArr;": "\u21d1", - "uHar;": "\u2963", - "uacute": "\xfa", - "uacute;": "\xfa", - "uarr;": "\u2191", - "ubrcy;": "\u045e", - "ubreve;": "\u016d", - "ucirc": "\xfb", - "ucirc;": "\xfb", - "ucy;": "\u0443", - "udarr;": "\u21c5", - "udblac;": "\u0171", - "udhar;": "\u296e", - "ufisht;": "\u297e", - "ufr;": "\U0001d532", - "ugrave": "\xf9", - "ugrave;": "\xf9", - "uharl;": "\u21bf", - "uharr;": "\u21be", - "uhblk;": "\u2580", - "ulcorn;": "\u231c", - "ulcorner;": "\u231c", - "ulcrop;": "\u230f", - "ultri;": "\u25f8", - "umacr;": "\u016b", - "uml": "\xa8", - "uml;": "\xa8", - "uogon;": "\u0173", - "uopf;": "\U0001d566", - "uparrow;": "\u2191", - "updownarrow;": "\u2195", - "upharpoonleft;": "\u21bf", - "upharpoonright;": "\u21be", - "uplus;": "\u228e", - "upsi;": "\u03c5", - "upsih;": "\u03d2", - "upsilon;": "\u03c5", - "upuparrows;": "\u21c8", - "urcorn;": "\u231d", - "urcorner;": "\u231d", - "urcrop;": "\u230e", - "uring;": "\u016f", - "urtri;": "\u25f9", - "uscr;": "\U0001d4ca", - "utdot;": "\u22f0", - "utilde;": "\u0169", - "utri;": "\u25b5", - "utrif;": "\u25b4", - "uuarr;": "\u21c8", - "uuml": "\xfc", - "uuml;": "\xfc", - "uwangle;": "\u29a7", - "vArr;": "\u21d5", - "vBar;": "\u2ae8", - "vBarv;": "\u2ae9", - "vDash;": "\u22a8", - "vangrt;": "\u299c", - "varepsilon;": "\u03f5", - "varkappa;": "\u03f0", - "varnothing;": "\u2205", - "varphi;": "\u03d5", - "varpi;": "\u03d6", - "varpropto;": "\u221d", - "varr;": "\u2195", - "varrho;": "\u03f1", - "varsigma;": "\u03c2", - "varsubsetneq;": "\u228a\ufe00", - "varsubsetneqq;": "\u2acb\ufe00", - "varsupsetneq;": "\u228b\ufe00", - "varsupsetneqq;": "\u2acc\ufe00", - "vartheta;": "\u03d1", - "vartriangleleft;": "\u22b2", - "vartriangleright;": "\u22b3", - "vcy;": "\u0432", - "vdash;": "\u22a2", - "vee;": "\u2228", - "veebar;": "\u22bb", - "veeeq;": "\u225a", - "vellip;": "\u22ee", - "verbar;": "|", - "vert;": "|", - "vfr;": "\U0001d533", - "vltri;": "\u22b2", - "vnsub;": "\u2282\u20d2", - "vnsup;": "\u2283\u20d2", - "vopf;": "\U0001d567", - "vprop;": "\u221d", - "vrtri;": "\u22b3", - "vscr;": "\U0001d4cb", - "vsubnE;": "\u2acb\ufe00", - "vsubne;": "\u228a\ufe00", - "vsupnE;": "\u2acc\ufe00", - "vsupne;": "\u228b\ufe00", - "vzigzag;": "\u299a", - "wcirc;": "\u0175", - "wedbar;": "\u2a5f", - "wedge;": "\u2227", - "wedgeq;": "\u2259", - "weierp;": "\u2118", - "wfr;": "\U0001d534", - "wopf;": "\U0001d568", - "wp;": "\u2118", - "wr;": "\u2240", - "wreath;": "\u2240", - "wscr;": "\U0001d4cc", - "xcap;": "\u22c2", - "xcirc;": "\u25ef", - "xcup;": "\u22c3", - "xdtri;": "\u25bd", - "xfr;": "\U0001d535", - "xhArr;": "\u27fa", - "xharr;": "\u27f7", - "xi;": "\u03be", - "xlArr;": "\u27f8", - "xlarr;": "\u27f5", - "xmap;": "\u27fc", - "xnis;": "\u22fb", - "xodot;": "\u2a00", - "xopf;": "\U0001d569", - "xoplus;": "\u2a01", - "xotime;": "\u2a02", - "xrArr;": "\u27f9", - "xrarr;": "\u27f6", - "xscr;": "\U0001d4cd", - "xsqcup;": "\u2a06", - "xuplus;": "\u2a04", - "xutri;": "\u25b3", - "xvee;": "\u22c1", - "xwedge;": "\u22c0", - "yacute": "\xfd", - "yacute;": "\xfd", - "yacy;": "\u044f", - "ycirc;": "\u0177", - "ycy;": "\u044b", - "yen": "\xa5", - "yen;": "\xa5", - "yfr;": "\U0001d536", - "yicy;": "\u0457", - "yopf;": "\U0001d56a", - "yscr;": "\U0001d4ce", - "yucy;": "\u044e", - "yuml": "\xff", - "yuml;": "\xff", - "zacute;": "\u017a", - "zcaron;": "\u017e", - "zcy;": "\u0437", - "zdot;": "\u017c", - "zeetrf;": "\u2128", - "zeta;": "\u03b6", - "zfr;": "\U0001d537", - "zhcy;": "\u0436", - "zigrarr;": "\u21dd", - "zopf;": "\U0001d56b", - "zscr;": "\U0001d4cf", - "zwj;": "\u200d", - "zwnj;": "\u200c", -} - -replacementCharacters = { - 0x0: "\uFFFD", - 0x0d: "\u000D", - 0x80: "\u20AC", - 0x81: "\u0081", - 0x82: "\u201A", - 0x83: "\u0192", - 0x84: "\u201E", - 0x85: "\u2026", - 0x86: "\u2020", - 0x87: "\u2021", - 0x88: "\u02C6", - 0x89: "\u2030", - 0x8A: "\u0160", - 0x8B: "\u2039", - 0x8C: "\u0152", - 0x8D: "\u008D", - 0x8E: "\u017D", - 0x8F: "\u008F", - 0x90: "\u0090", - 0x91: "\u2018", - 0x92: "\u2019", - 0x93: "\u201C", - 0x94: "\u201D", - 0x95: "\u2022", - 0x96: "\u2013", - 0x97: "\u2014", - 0x98: "\u02DC", - 0x99: "\u2122", - 0x9A: "\u0161", - 0x9B: "\u203A", - 0x9C: "\u0153", - 0x9D: "\u009D", - 0x9E: "\u017E", - 0x9F: "\u0178", -} - -tokenTypes = { - "Doctype": 0, - "Characters": 1, - "SpaceCharacters": 2, - "StartTag": 3, - "EndTag": 4, - "EmptyTag": 5, - "Comment": 6, - "ParseError": 7 -} - -tagTokenTypes = frozenset([tokenTypes["StartTag"], tokenTypes["EndTag"], - tokenTypes["EmptyTag"]]) - - -prefixes = {v: k for k, v in namespaces.items()} -prefixes["http://www.w3.org/1998/Math/MathML"] = "math" - - -class DataLossWarning(UserWarning): - """Raised when the current tree is unable to represent the input data""" - pass - - -class _ReparseException(Exception): - pass diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/__init__.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py deleted file mode 100644 index 5ba926e..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import base - -from collections import OrderedDict - - -def _attr_key(attr): - """Return an appropriate key for an attribute for sorting - - Attributes have a namespace that can be either ``None`` or a string. We - can't compare the two because they're different types, so we convert - ``None`` to an empty string first. - - """ - return (attr[0][0] or ''), attr[0][1] - - -class Filter(base.Filter): - """Alphabetizes attributes for elements""" - def __iter__(self): - for token in base.Filter.__iter__(self): - if token["type"] in ("StartTag", "EmptyTag"): - attrs = OrderedDict() - for name, value in sorted(token["data"].items(), - key=_attr_key): - attrs[name] = value - token["data"] = attrs - yield token diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/base.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/base.py deleted file mode 100644 index c7dbaed..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/base.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - - -class Filter(object): - def __init__(self, source): - self.source = source - - def __iter__(self): - return iter(self.source) - - def __getattr__(self, name): - return getattr(self.source, name) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py deleted file mode 100644 index aefb5c8..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import base - - -class Filter(base.Filter): - """Injects ```` tag into head of document""" - def __init__(self, source, encoding): - """Creates a Filter - - :arg source: the source token stream - - :arg encoding: the encoding to set - - """ - base.Filter.__init__(self, source) - self.encoding = encoding - - def __iter__(self): - state = "pre_head" - meta_found = (self.encoding is None) - pending = [] - - for token in base.Filter.__iter__(self): - type = token["type"] - if type == "StartTag": - if token["name"].lower() == "head": - state = "in_head" - - elif type == "EmptyTag": - if token["name"].lower() == "meta": - # replace charset with actual encoding - has_http_equiv_content_type = False - for (namespace, name), value in token["data"].items(): - if namespace is not None: - continue - elif name.lower() == 'charset': - token["data"][(namespace, name)] = self.encoding - meta_found = True - break - elif name == 'http-equiv' and value.lower() == 'content-type': - has_http_equiv_content_type = True - else: - if has_http_equiv_content_type and (None, "content") in token["data"]: - token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding - meta_found = True - - elif token["name"].lower() == "head" and not meta_found: - # insert meta into empty head - yield {"type": "StartTag", "name": "head", - "data": token["data"]} - yield {"type": "EmptyTag", "name": "meta", - "data": {(None, "charset"): self.encoding}} - yield {"type": "EndTag", "name": "head"} - meta_found = True - continue - - elif type == "EndTag": - if token["name"].lower() == "head" and pending: - # insert meta into head (if necessary) and flush pending queue - yield pending.pop(0) - if not meta_found: - yield {"type": "EmptyTag", "name": "meta", - "data": {(None, "charset"): self.encoding}} - while pending: - yield pending.pop(0) - meta_found = True - state = "post_head" - - if state == "in_head": - pending.append(token) - else: - yield token diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/lint.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/lint.py deleted file mode 100644 index fcc07ee..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/lint.py +++ /dev/null @@ -1,93 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from pip._vendor.six import text_type - -from . import base -from ..constants import namespaces, voidElements - -from ..constants import spaceCharacters -spaceCharacters = "".join(spaceCharacters) - - -class Filter(base.Filter): - """Lints the token stream for errors - - If it finds any errors, it'll raise an ``AssertionError``. - - """ - def __init__(self, source, require_matching_tags=True): - """Creates a Filter - - :arg source: the source token stream - - :arg require_matching_tags: whether or not to require matching tags - - """ - super(Filter, self).__init__(source) - self.require_matching_tags = require_matching_tags - - def __iter__(self): - open_elements = [] - for token in base.Filter.__iter__(self): - type = token["type"] - if type in ("StartTag", "EmptyTag"): - namespace = token["namespace"] - name = token["name"] - assert namespace is None or isinstance(namespace, text_type) - assert namespace != "" - assert isinstance(name, text_type) - assert name != "" - assert isinstance(token["data"], dict) - if (not namespace or namespace == namespaces["html"]) and name in voidElements: - assert type == "EmptyTag" - else: - assert type == "StartTag" - if type == "StartTag" and self.require_matching_tags: - open_elements.append((namespace, name)) - for (namespace, name), value in token["data"].items(): - assert namespace is None or isinstance(namespace, text_type) - assert namespace != "" - assert isinstance(name, text_type) - assert name != "" - assert isinstance(value, text_type) - - elif type == "EndTag": - namespace = token["namespace"] - name = token["name"] - assert namespace is None or isinstance(namespace, text_type) - assert namespace != "" - assert isinstance(name, text_type) - assert name != "" - if (not namespace or namespace == namespaces["html"]) and name in voidElements: - assert False, "Void element reported as EndTag token: %(tag)s" % {"tag": name} - elif self.require_matching_tags: - start = open_elements.pop() - assert start == (namespace, name) - - elif type == "Comment": - data = token["data"] - assert isinstance(data, text_type) - - elif type in ("Characters", "SpaceCharacters"): - data = token["data"] - assert isinstance(data, text_type) - assert data != "" - if type == "SpaceCharacters": - assert data.strip(spaceCharacters) == "" - - elif type == "Doctype": - name = token["name"] - assert name is None or isinstance(name, text_type) - assert token["publicId"] is None or isinstance(name, text_type) - assert token["systemId"] is None or isinstance(name, text_type) - - elif type == "Entity": - assert isinstance(token["name"], text_type) - - elif type == "SerializerError": - assert isinstance(token["data"], text_type) - - else: - assert False, "Unknown token type: %(type)s" % {"type": type} - - yield token diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/optionaltags.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/optionaltags.py deleted file mode 100644 index 4a86501..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/optionaltags.py +++ /dev/null @@ -1,207 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import base - - -class Filter(base.Filter): - """Removes optional tags from the token stream""" - def slider(self): - previous1 = previous2 = None - for token in self.source: - if previous1 is not None: - yield previous2, previous1, token - previous2 = previous1 - previous1 = token - if previous1 is not None: - yield previous2, previous1, None - - def __iter__(self): - for previous, token, next in self.slider(): - type = token["type"] - if type == "StartTag": - if (token["data"] or - not self.is_optional_start(token["name"], previous, next)): - yield token - elif type == "EndTag": - if not self.is_optional_end(token["name"], next): - yield token - else: - yield token - - def is_optional_start(self, tagname, previous, next): - type = next and next["type"] or None - if tagname in 'html': - # An html element's start tag may be omitted if the first thing - # inside the html element is not a space character or a comment. - return type not in ("Comment", "SpaceCharacters") - elif tagname == 'head': - # A head element's start tag may be omitted if the first thing - # inside the head element is an element. - # XXX: we also omit the start tag if the head element is empty - if type in ("StartTag", "EmptyTag"): - return True - elif type == "EndTag": - return next["name"] == "head" - elif tagname == 'body': - # A body element's start tag may be omitted if the first thing - # inside the body element is not a space character or a comment, - # except if the first thing inside the body element is a script - # or style element and the node immediately preceding the body - # element is a head element whose end tag has been omitted. - if type in ("Comment", "SpaceCharacters"): - return False - elif type == "StartTag": - # XXX: we do not look at the preceding event, so we never omit - # the body element's start tag if it's followed by a script or - # a style element. - return next["name"] not in ('script', 'style') - else: - return True - elif tagname == 'colgroup': - # A colgroup element's start tag may be omitted if the first thing - # inside the colgroup element is a col element, and if the element - # is not immediately preceded by another colgroup element whose - # end tag has been omitted. - if type in ("StartTag", "EmptyTag"): - # XXX: we do not look at the preceding event, so instead we never - # omit the colgroup element's end tag when it is immediately - # followed by another colgroup element. See is_optional_end. - return next["name"] == "col" - else: - return False - elif tagname == 'tbody': - # A tbody element's start tag may be omitted if the first thing - # inside the tbody element is a tr element, and if the element is - # not immediately preceded by a tbody, thead, or tfoot element - # whose end tag has been omitted. - if type == "StartTag": - # omit the thead and tfoot elements' end tag when they are - # immediately followed by a tbody element. See is_optional_end. - if previous and previous['type'] == 'EndTag' and \ - previous['name'] in ('tbody', 'thead', 'tfoot'): - return False - return next["name"] == 'tr' - else: - return False - return False - - def is_optional_end(self, tagname, next): - type = next and next["type"] or None - if tagname in ('html', 'head', 'body'): - # An html element's end tag may be omitted if the html element - # is not immediately followed by a space character or a comment. - return type not in ("Comment", "SpaceCharacters") - elif tagname in ('li', 'optgroup', 'tr'): - # A li element's end tag may be omitted if the li element is - # immediately followed by another li element or if there is - # no more content in the parent element. - # An optgroup element's end tag may be omitted if the optgroup - # element is immediately followed by another optgroup element, - # or if there is no more content in the parent element. - # A tr element's end tag may be omitted if the tr element is - # immediately followed by another tr element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] == tagname - else: - return type == "EndTag" or type is None - elif tagname in ('dt', 'dd'): - # A dt element's end tag may be omitted if the dt element is - # immediately followed by another dt element or a dd element. - # A dd element's end tag may be omitted if the dd element is - # immediately followed by another dd element or a dt element, - # or if there is no more content in the parent element. - if type == "StartTag": - return next["name"] in ('dt', 'dd') - elif tagname == 'dd': - return type == "EndTag" or type is None - else: - return False - elif tagname == 'p': - # A p element's end tag may be omitted if the p element is - # immediately followed by an address, article, aside, - # blockquote, datagrid, dialog, dir, div, dl, fieldset, - # footer, form, h1, h2, h3, h4, h5, h6, header, hr, menu, - # nav, ol, p, pre, section, table, or ul, element, or if - # there is no more content in the parent element. - if type in ("StartTag", "EmptyTag"): - return next["name"] in ('address', 'article', 'aside', - 'blockquote', 'datagrid', 'dialog', - 'dir', 'div', 'dl', 'fieldset', 'footer', - 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', - 'header', 'hr', 'menu', 'nav', 'ol', - 'p', 'pre', 'section', 'table', 'ul') - else: - return type == "EndTag" or type is None - elif tagname == 'option': - # An option element's end tag may be omitted if the option - # element is immediately followed by another option element, - # or if it is immediately followed by an optgroup - # element, or if there is no more content in the parent - # element. - if type == "StartTag": - return next["name"] in ('option', 'optgroup') - else: - return type == "EndTag" or type is None - elif tagname in ('rt', 'rp'): - # An rt element's end tag may be omitted if the rt element is - # immediately followed by an rt or rp element, or if there is - # no more content in the parent element. - # An rp element's end tag may be omitted if the rp element is - # immediately followed by an rt or rp element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] in ('rt', 'rp') - else: - return type == "EndTag" or type is None - elif tagname == 'colgroup': - # A colgroup element's end tag may be omitted if the colgroup - # element is not immediately followed by a space character or - # a comment. - if type in ("Comment", "SpaceCharacters"): - return False - elif type == "StartTag": - # XXX: we also look for an immediately following colgroup - # element. See is_optional_start. - return next["name"] != 'colgroup' - else: - return True - elif tagname in ('thead', 'tbody'): - # A thead element's end tag may be omitted if the thead element - # is immediately followed by a tbody or tfoot element. - # A tbody element's end tag may be omitted if the tbody element - # is immediately followed by a tbody or tfoot element, or if - # there is no more content in the parent element. - # A tfoot element's end tag may be omitted if the tfoot element - # is immediately followed by a tbody element, or if there is no - # more content in the parent element. - # XXX: we never omit the end tag when the following element is - # a tbody. See is_optional_start. - if type == "StartTag": - return next["name"] in ['tbody', 'tfoot'] - elif tagname == 'tbody': - return type == "EndTag" or type is None - else: - return False - elif tagname == 'tfoot': - # A tfoot element's end tag may be omitted if the tfoot element - # is immediately followed by a tbody element, or if there is no - # more content in the parent element. - # XXX: we never omit the end tag when the following element is - # a tbody. See is_optional_start. - if type == "StartTag": - return next["name"] == 'tbody' - else: - return type == "EndTag" or type is None - elif tagname in ('td', 'th'): - # A td element's end tag may be omitted if the td element is - # immediately followed by a td or th element, or if there is - # no more content in the parent element. - # A th element's end tag may be omitted if the th element is - # immediately followed by a td or th element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] in ('td', 'th') - else: - return type == "EndTag" or type is None - return False diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/sanitizer.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/sanitizer.py deleted file mode 100644 index aa7431d..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/sanitizer.py +++ /dev/null @@ -1,916 +0,0 @@ -"""Deprecated from html5lib 1.1. - -See `here `_ for -information about its deprecation; `Bleach `_ -is recommended as a replacement. Please let us know in the aforementioned issue -if Bleach is unsuitable for your needs. - -""" -from __future__ import absolute_import, division, unicode_literals - -import re -import warnings -from xml.sax.saxutils import escape, unescape - -from pip._vendor.six.moves import urllib_parse as urlparse - -from . import base -from ..constants import namespaces, prefixes - -__all__ = ["Filter"] - - -_deprecation_msg = ( - "html5lib's sanitizer is deprecated; see " + - "https://github.com/html5lib/html5lib-python/issues/443 and please let " + - "us know if Bleach is unsuitable for your needs" -) - -warnings.warn(_deprecation_msg, DeprecationWarning) - -allowed_elements = frozenset(( - (namespaces['html'], 'a'), - (namespaces['html'], 'abbr'), - (namespaces['html'], 'acronym'), - (namespaces['html'], 'address'), - (namespaces['html'], 'area'), - (namespaces['html'], 'article'), - (namespaces['html'], 'aside'), - (namespaces['html'], 'audio'), - (namespaces['html'], 'b'), - (namespaces['html'], 'big'), - (namespaces['html'], 'blockquote'), - (namespaces['html'], 'br'), - (namespaces['html'], 'button'), - (namespaces['html'], 'canvas'), - (namespaces['html'], 'caption'), - (namespaces['html'], 'center'), - (namespaces['html'], 'cite'), - (namespaces['html'], 'code'), - (namespaces['html'], 'col'), - (namespaces['html'], 'colgroup'), - (namespaces['html'], 'command'), - (namespaces['html'], 'datagrid'), - (namespaces['html'], 'datalist'), - (namespaces['html'], 'dd'), - (namespaces['html'], 'del'), - (namespaces['html'], 'details'), - (namespaces['html'], 'dfn'), - (namespaces['html'], 'dialog'), - (namespaces['html'], 'dir'), - (namespaces['html'], 'div'), - (namespaces['html'], 'dl'), - (namespaces['html'], 'dt'), - (namespaces['html'], 'em'), - (namespaces['html'], 'event-source'), - (namespaces['html'], 'fieldset'), - (namespaces['html'], 'figcaption'), - (namespaces['html'], 'figure'), - (namespaces['html'], 'footer'), - (namespaces['html'], 'font'), - (namespaces['html'], 'form'), - (namespaces['html'], 'header'), - (namespaces['html'], 'h1'), - (namespaces['html'], 'h2'), - (namespaces['html'], 'h3'), - (namespaces['html'], 'h4'), - (namespaces['html'], 'h5'), - (namespaces['html'], 'h6'), - (namespaces['html'], 'hr'), - (namespaces['html'], 'i'), - (namespaces['html'], 'img'), - (namespaces['html'], 'input'), - (namespaces['html'], 'ins'), - (namespaces['html'], 'keygen'), - (namespaces['html'], 'kbd'), - (namespaces['html'], 'label'), - (namespaces['html'], 'legend'), - (namespaces['html'], 'li'), - (namespaces['html'], 'm'), - (namespaces['html'], 'map'), - (namespaces['html'], 'menu'), - (namespaces['html'], 'meter'), - (namespaces['html'], 'multicol'), - (namespaces['html'], 'nav'), - (namespaces['html'], 'nextid'), - (namespaces['html'], 'ol'), - (namespaces['html'], 'output'), - (namespaces['html'], 'optgroup'), - (namespaces['html'], 'option'), - (namespaces['html'], 'p'), - (namespaces['html'], 'pre'), - (namespaces['html'], 'progress'), - (namespaces['html'], 'q'), - (namespaces['html'], 's'), - (namespaces['html'], 'samp'), - (namespaces['html'], 'section'), - (namespaces['html'], 'select'), - (namespaces['html'], 'small'), - (namespaces['html'], 'sound'), - (namespaces['html'], 'source'), - (namespaces['html'], 'spacer'), - (namespaces['html'], 'span'), - (namespaces['html'], 'strike'), - (namespaces['html'], 'strong'), - (namespaces['html'], 'sub'), - (namespaces['html'], 'sup'), - (namespaces['html'], 'table'), - (namespaces['html'], 'tbody'), - (namespaces['html'], 'td'), - (namespaces['html'], 'textarea'), - (namespaces['html'], 'time'), - (namespaces['html'], 'tfoot'), - (namespaces['html'], 'th'), - (namespaces['html'], 'thead'), - (namespaces['html'], 'tr'), - (namespaces['html'], 'tt'), - (namespaces['html'], 'u'), - (namespaces['html'], 'ul'), - (namespaces['html'], 'var'), - (namespaces['html'], 'video'), - (namespaces['mathml'], 'maction'), - (namespaces['mathml'], 'math'), - (namespaces['mathml'], 'merror'), - (namespaces['mathml'], 'mfrac'), - (namespaces['mathml'], 'mi'), - (namespaces['mathml'], 'mmultiscripts'), - (namespaces['mathml'], 'mn'), - (namespaces['mathml'], 'mo'), - (namespaces['mathml'], 'mover'), - (namespaces['mathml'], 'mpadded'), - (namespaces['mathml'], 'mphantom'), - (namespaces['mathml'], 'mprescripts'), - (namespaces['mathml'], 'mroot'), - (namespaces['mathml'], 'mrow'), - (namespaces['mathml'], 'mspace'), - (namespaces['mathml'], 'msqrt'), - (namespaces['mathml'], 'mstyle'), - (namespaces['mathml'], 'msub'), - (namespaces['mathml'], 'msubsup'), - (namespaces['mathml'], 'msup'), - (namespaces['mathml'], 'mtable'), - (namespaces['mathml'], 'mtd'), - (namespaces['mathml'], 'mtext'), - (namespaces['mathml'], 'mtr'), - (namespaces['mathml'], 'munder'), - (namespaces['mathml'], 'munderover'), - (namespaces['mathml'], 'none'), - (namespaces['svg'], 'a'), - (namespaces['svg'], 'animate'), - (namespaces['svg'], 'animateColor'), - (namespaces['svg'], 'animateMotion'), - (namespaces['svg'], 'animateTransform'), - (namespaces['svg'], 'clipPath'), - (namespaces['svg'], 'circle'), - (namespaces['svg'], 'defs'), - (namespaces['svg'], 'desc'), - (namespaces['svg'], 'ellipse'), - (namespaces['svg'], 'font-face'), - (namespaces['svg'], 'font-face-name'), - (namespaces['svg'], 'font-face-src'), - (namespaces['svg'], 'g'), - (namespaces['svg'], 'glyph'), - (namespaces['svg'], 'hkern'), - (namespaces['svg'], 'linearGradient'), - (namespaces['svg'], 'line'), - (namespaces['svg'], 'marker'), - (namespaces['svg'], 'metadata'), - (namespaces['svg'], 'missing-glyph'), - (namespaces['svg'], 'mpath'), - (namespaces['svg'], 'path'), - (namespaces['svg'], 'polygon'), - (namespaces['svg'], 'polyline'), - (namespaces['svg'], 'radialGradient'), - (namespaces['svg'], 'rect'), - (namespaces['svg'], 'set'), - (namespaces['svg'], 'stop'), - (namespaces['svg'], 'svg'), - (namespaces['svg'], 'switch'), - (namespaces['svg'], 'text'), - (namespaces['svg'], 'title'), - (namespaces['svg'], 'tspan'), - (namespaces['svg'], 'use'), -)) - -allowed_attributes = frozenset(( - # HTML attributes - (None, 'abbr'), - (None, 'accept'), - (None, 'accept-charset'), - (None, 'accesskey'), - (None, 'action'), - (None, 'align'), - (None, 'alt'), - (None, 'autocomplete'), - (None, 'autofocus'), - (None, 'axis'), - (None, 'background'), - (None, 'balance'), - (None, 'bgcolor'), - (None, 'bgproperties'), - (None, 'border'), - (None, 'bordercolor'), - (None, 'bordercolordark'), - (None, 'bordercolorlight'), - (None, 'bottompadding'), - (None, 'cellpadding'), - (None, 'cellspacing'), - (None, 'ch'), - (None, 'challenge'), - (None, 'char'), - (None, 'charoff'), - (None, 'choff'), - (None, 'charset'), - (None, 'checked'), - (None, 'cite'), - (None, 'class'), - (None, 'clear'), - (None, 'color'), - (None, 'cols'), - (None, 'colspan'), - (None, 'compact'), - (None, 'contenteditable'), - (None, 'controls'), - (None, 'coords'), - (None, 'data'), - (None, 'datafld'), - (None, 'datapagesize'), - (None, 'datasrc'), - (None, 'datetime'), - (None, 'default'), - (None, 'delay'), - (None, 'dir'), - (None, 'disabled'), - (None, 'draggable'), - (None, 'dynsrc'), - (None, 'enctype'), - (None, 'end'), - (None, 'face'), - (None, 'for'), - (None, 'form'), - (None, 'frame'), - (None, 'galleryimg'), - (None, 'gutter'), - (None, 'headers'), - (None, 'height'), - (None, 'hidefocus'), - (None, 'hidden'), - (None, 'high'), - (None, 'href'), - (None, 'hreflang'), - (None, 'hspace'), - (None, 'icon'), - (None, 'id'), - (None, 'inputmode'), - (None, 'ismap'), - (None, 'keytype'), - (None, 'label'), - (None, 'leftspacing'), - (None, 'lang'), - (None, 'list'), - (None, 'longdesc'), - (None, 'loop'), - (None, 'loopcount'), - (None, 'loopend'), - (None, 'loopstart'), - (None, 'low'), - (None, 'lowsrc'), - (None, 'max'), - (None, 'maxlength'), - (None, 'media'), - (None, 'method'), - (None, 'min'), - (None, 'multiple'), - (None, 'name'), - (None, 'nohref'), - (None, 'noshade'), - (None, 'nowrap'), - (None, 'open'), - (None, 'optimum'), - (None, 'pattern'), - (None, 'ping'), - (None, 'point-size'), - (None, 'poster'), - (None, 'pqg'), - (None, 'preload'), - (None, 'prompt'), - (None, 'radiogroup'), - (None, 'readonly'), - (None, 'rel'), - (None, 'repeat-max'), - (None, 'repeat-min'), - (None, 'replace'), - (None, 'required'), - (None, 'rev'), - (None, 'rightspacing'), - (None, 'rows'), - (None, 'rowspan'), - (None, 'rules'), - (None, 'scope'), - (None, 'selected'), - (None, 'shape'), - (None, 'size'), - (None, 'span'), - (None, 'src'), - (None, 'start'), - (None, 'step'), - (None, 'style'), - (None, 'summary'), - (None, 'suppress'), - (None, 'tabindex'), - (None, 'target'), - (None, 'template'), - (None, 'title'), - (None, 'toppadding'), - (None, 'type'), - (None, 'unselectable'), - (None, 'usemap'), - (None, 'urn'), - (None, 'valign'), - (None, 'value'), - (None, 'variable'), - (None, 'volume'), - (None, 'vspace'), - (None, 'vrml'), - (None, 'width'), - (None, 'wrap'), - (namespaces['xml'], 'lang'), - # MathML attributes - (None, 'actiontype'), - (None, 'align'), - (None, 'columnalign'), - (None, 'columnalign'), - (None, 'columnalign'), - (None, 'columnlines'), - (None, 'columnspacing'), - (None, 'columnspan'), - (None, 'depth'), - (None, 'display'), - (None, 'displaystyle'), - (None, 'equalcolumns'), - (None, 'equalrows'), - (None, 'fence'), - (None, 'fontstyle'), - (None, 'fontweight'), - (None, 'frame'), - (None, 'height'), - (None, 'linethickness'), - (None, 'lspace'), - (None, 'mathbackground'), - (None, 'mathcolor'), - (None, 'mathvariant'), - (None, 'mathvariant'), - (None, 'maxsize'), - (None, 'minsize'), - (None, 'other'), - (None, 'rowalign'), - (None, 'rowalign'), - (None, 'rowalign'), - (None, 'rowlines'), - (None, 'rowspacing'), - (None, 'rowspan'), - (None, 'rspace'), - (None, 'scriptlevel'), - (None, 'selection'), - (None, 'separator'), - (None, 'stretchy'), - (None, 'width'), - (None, 'width'), - (namespaces['xlink'], 'href'), - (namespaces['xlink'], 'show'), - (namespaces['xlink'], 'type'), - # SVG attributes - (None, 'accent-height'), - (None, 'accumulate'), - (None, 'additive'), - (None, 'alphabetic'), - (None, 'arabic-form'), - (None, 'ascent'), - (None, 'attributeName'), - (None, 'attributeType'), - (None, 'baseProfile'), - (None, 'bbox'), - (None, 'begin'), - (None, 'by'), - (None, 'calcMode'), - (None, 'cap-height'), - (None, 'class'), - (None, 'clip-path'), - (None, 'color'), - (None, 'color-rendering'), - (None, 'content'), - (None, 'cx'), - (None, 'cy'), - (None, 'd'), - (None, 'dx'), - (None, 'dy'), - (None, 'descent'), - (None, 'display'), - (None, 'dur'), - (None, 'end'), - (None, 'fill'), - (None, 'fill-opacity'), - (None, 'fill-rule'), - (None, 'font-family'), - (None, 'font-size'), - (None, 'font-stretch'), - (None, 'font-style'), - (None, 'font-variant'), - (None, 'font-weight'), - (None, 'from'), - (None, 'fx'), - (None, 'fy'), - (None, 'g1'), - (None, 'g2'), - (None, 'glyph-name'), - (None, 'gradientUnits'), - (None, 'hanging'), - (None, 'height'), - (None, 'horiz-adv-x'), - (None, 'horiz-origin-x'), - (None, 'id'), - (None, 'ideographic'), - (None, 'k'), - (None, 'keyPoints'), - (None, 'keySplines'), - (None, 'keyTimes'), - (None, 'lang'), - (None, 'marker-end'), - (None, 'marker-mid'), - (None, 'marker-start'), - (None, 'markerHeight'), - (None, 'markerUnits'), - (None, 'markerWidth'), - (None, 'mathematical'), - (None, 'max'), - (None, 'min'), - (None, 'name'), - (None, 'offset'), - (None, 'opacity'), - (None, 'orient'), - (None, 'origin'), - (None, 'overline-position'), - (None, 'overline-thickness'), - (None, 'panose-1'), - (None, 'path'), - (None, 'pathLength'), - (None, 'points'), - (None, 'preserveAspectRatio'), - (None, 'r'), - (None, 'refX'), - (None, 'refY'), - (None, 'repeatCount'), - (None, 'repeatDur'), - (None, 'requiredExtensions'), - (None, 'requiredFeatures'), - (None, 'restart'), - (None, 'rotate'), - (None, 'rx'), - (None, 'ry'), - (None, 'slope'), - (None, 'stemh'), - (None, 'stemv'), - (None, 'stop-color'), - (None, 'stop-opacity'), - (None, 'strikethrough-position'), - (None, 'strikethrough-thickness'), - (None, 'stroke'), - (None, 'stroke-dasharray'), - (None, 'stroke-dashoffset'), - (None, 'stroke-linecap'), - (None, 'stroke-linejoin'), - (None, 'stroke-miterlimit'), - (None, 'stroke-opacity'), - (None, 'stroke-width'), - (None, 'systemLanguage'), - (None, 'target'), - (None, 'text-anchor'), - (None, 'to'), - (None, 'transform'), - (None, 'type'), - (None, 'u1'), - (None, 'u2'), - (None, 'underline-position'), - (None, 'underline-thickness'), - (None, 'unicode'), - (None, 'unicode-range'), - (None, 'units-per-em'), - (None, 'values'), - (None, 'version'), - (None, 'viewBox'), - (None, 'visibility'), - (None, 'width'), - (None, 'widths'), - (None, 'x'), - (None, 'x-height'), - (None, 'x1'), - (None, 'x2'), - (namespaces['xlink'], 'actuate'), - (namespaces['xlink'], 'arcrole'), - (namespaces['xlink'], 'href'), - (namespaces['xlink'], 'role'), - (namespaces['xlink'], 'show'), - (namespaces['xlink'], 'title'), - (namespaces['xlink'], 'type'), - (namespaces['xml'], 'base'), - (namespaces['xml'], 'lang'), - (namespaces['xml'], 'space'), - (None, 'y'), - (None, 'y1'), - (None, 'y2'), - (None, 'zoomAndPan'), -)) - -attr_val_is_uri = frozenset(( - (None, 'href'), - (None, 'src'), - (None, 'cite'), - (None, 'action'), - (None, 'longdesc'), - (None, 'poster'), - (None, 'background'), - (None, 'datasrc'), - (None, 'dynsrc'), - (None, 'lowsrc'), - (None, 'ping'), - (namespaces['xlink'], 'href'), - (namespaces['xml'], 'base'), -)) - -svg_attr_val_allows_ref = frozenset(( - (None, 'clip-path'), - (None, 'color-profile'), - (None, 'cursor'), - (None, 'fill'), - (None, 'filter'), - (None, 'marker'), - (None, 'marker-start'), - (None, 'marker-mid'), - (None, 'marker-end'), - (None, 'mask'), - (None, 'stroke'), -)) - -svg_allow_local_href = frozenset(( - (None, 'altGlyph'), - (None, 'animate'), - (None, 'animateColor'), - (None, 'animateMotion'), - (None, 'animateTransform'), - (None, 'cursor'), - (None, 'feImage'), - (None, 'filter'), - (None, 'linearGradient'), - (None, 'pattern'), - (None, 'radialGradient'), - (None, 'textpath'), - (None, 'tref'), - (None, 'set'), - (None, 'use') -)) - -allowed_css_properties = frozenset(( - 'azimuth', - 'background-color', - 'border-bottom-color', - 'border-collapse', - 'border-color', - 'border-left-color', - 'border-right-color', - 'border-top-color', - 'clear', - 'color', - 'cursor', - 'direction', - 'display', - 'elevation', - 'float', - 'font', - 'font-family', - 'font-size', - 'font-style', - 'font-variant', - 'font-weight', - 'height', - 'letter-spacing', - 'line-height', - 'overflow', - 'pause', - 'pause-after', - 'pause-before', - 'pitch', - 'pitch-range', - 'richness', - 'speak', - 'speak-header', - 'speak-numeral', - 'speak-punctuation', - 'speech-rate', - 'stress', - 'text-align', - 'text-decoration', - 'text-indent', - 'unicode-bidi', - 'vertical-align', - 'voice-family', - 'volume', - 'white-space', - 'width', -)) - -allowed_css_keywords = frozenset(( - 'auto', - 'aqua', - 'black', - 'block', - 'blue', - 'bold', - 'both', - 'bottom', - 'brown', - 'center', - 'collapse', - 'dashed', - 'dotted', - 'fuchsia', - 'gray', - 'green', - '!important', - 'italic', - 'left', - 'lime', - 'maroon', - 'medium', - 'none', - 'navy', - 'normal', - 'nowrap', - 'olive', - 'pointer', - 'purple', - 'red', - 'right', - 'solid', - 'silver', - 'teal', - 'top', - 'transparent', - 'underline', - 'white', - 'yellow', -)) - -allowed_svg_properties = frozenset(( - 'fill', - 'fill-opacity', - 'fill-rule', - 'stroke', - 'stroke-width', - 'stroke-linecap', - 'stroke-linejoin', - 'stroke-opacity', -)) - -allowed_protocols = frozenset(( - 'ed2k', - 'ftp', - 'http', - 'https', - 'irc', - 'mailto', - 'news', - 'gopher', - 'nntp', - 'telnet', - 'webcal', - 'xmpp', - 'callto', - 'feed', - 'urn', - 'aim', - 'rsync', - 'tag', - 'ssh', - 'sftp', - 'rtsp', - 'afs', - 'data', -)) - -allowed_content_types = frozenset(( - 'image/png', - 'image/jpeg', - 'image/gif', - 'image/webp', - 'image/bmp', - 'text/plain', -)) - - -data_content_type = re.compile(r''' - ^ - # Match a content type / - (?P[-a-zA-Z0-9.]+/[-a-zA-Z0-9.]+) - # Match any character set and encoding - (?:(?:;charset=(?:[-a-zA-Z0-9]+)(?:;(?:base64))?) - |(?:;(?:base64))?(?:;charset=(?:[-a-zA-Z0-9]+))?) - # Assume the rest is data - ,.* - $ - ''', - re.VERBOSE) - - -class Filter(base.Filter): - """Sanitizes token stream of XHTML+MathML+SVG and of inline style attributes""" - def __init__(self, - source, - allowed_elements=allowed_elements, - allowed_attributes=allowed_attributes, - allowed_css_properties=allowed_css_properties, - allowed_css_keywords=allowed_css_keywords, - allowed_svg_properties=allowed_svg_properties, - allowed_protocols=allowed_protocols, - allowed_content_types=allowed_content_types, - attr_val_is_uri=attr_val_is_uri, - svg_attr_val_allows_ref=svg_attr_val_allows_ref, - svg_allow_local_href=svg_allow_local_href): - """Creates a Filter - - :arg allowed_elements: set of elements to allow--everything else will - be escaped - - :arg allowed_attributes: set of attributes to allow in - elements--everything else will be stripped - - :arg allowed_css_properties: set of CSS properties to allow--everything - else will be stripped - - :arg allowed_css_keywords: set of CSS keywords to allow--everything - else will be stripped - - :arg allowed_svg_properties: set of SVG properties to allow--everything - else will be removed - - :arg allowed_protocols: set of allowed protocols for URIs - - :arg allowed_content_types: set of allowed content types for ``data`` URIs. - - :arg attr_val_is_uri: set of attributes that have URI values--values - that have a scheme not listed in ``allowed_protocols`` are removed - - :arg svg_attr_val_allows_ref: set of SVG attributes that can have - references - - :arg svg_allow_local_href: set of SVG elements that can have local - hrefs--these are removed - - """ - super(Filter, self).__init__(source) - - warnings.warn(_deprecation_msg, DeprecationWarning) - - self.allowed_elements = allowed_elements - self.allowed_attributes = allowed_attributes - self.allowed_css_properties = allowed_css_properties - self.allowed_css_keywords = allowed_css_keywords - self.allowed_svg_properties = allowed_svg_properties - self.allowed_protocols = allowed_protocols - self.allowed_content_types = allowed_content_types - self.attr_val_is_uri = attr_val_is_uri - self.svg_attr_val_allows_ref = svg_attr_val_allows_ref - self.svg_allow_local_href = svg_allow_local_href - - def __iter__(self): - for token in base.Filter.__iter__(self): - token = self.sanitize_token(token) - if token: - yield token - - # Sanitize the +html+, escaping all elements not in ALLOWED_ELEMENTS, and - # stripping out all attributes not in ALLOWED_ATTRIBUTES. Style attributes - # are parsed, and a restricted set, specified by ALLOWED_CSS_PROPERTIES and - # ALLOWED_CSS_KEYWORDS, are allowed through. attributes in ATTR_VAL_IS_URI - # are scanned, and only URI schemes specified in ALLOWED_PROTOCOLS are - # allowed. - # - # sanitize_html('') - # => <script> do_nasty_stuff() </script> - # sanitize_html('Click here for $100') - # => Click here for $100 - def sanitize_token(self, token): - - # accommodate filters which use token_type differently - token_type = token["type"] - if token_type in ("StartTag", "EndTag", "EmptyTag"): - name = token["name"] - namespace = token["namespace"] - if ((namespace, name) in self.allowed_elements or - (namespace is None and - (namespaces["html"], name) in self.allowed_elements)): - return self.allowed_token(token) - else: - return self.disallowed_token(token) - elif token_type == "Comment": - pass - else: - return token - - def allowed_token(self, token): - if "data" in token: - attrs = token["data"] - attr_names = set(attrs.keys()) - - # Remove forbidden attributes - for to_remove in (attr_names - self.allowed_attributes): - del token["data"][to_remove] - attr_names.remove(to_remove) - - # Remove attributes with disallowed URL values - for attr in (attr_names & self.attr_val_is_uri): - assert attr in attrs - # I don't have a clue where this regexp comes from or why it matches those - # characters, nor why we call unescape. I just know it's always been here. - # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all - # this will do is remove *more* than it otherwise would. - val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\\s]+", '', - unescape(attrs[attr])).lower() - # remove replacement characters from unescaped characters - val_unescaped = val_unescaped.replace("\ufffd", "") - try: - uri = urlparse.urlparse(val_unescaped) - except ValueError: - uri = None - del attrs[attr] - if uri and uri.scheme: - if uri.scheme not in self.allowed_protocols: - del attrs[attr] - if uri.scheme == 'data': - m = data_content_type.match(uri.path) - if not m: - del attrs[attr] - elif m.group('content_type') not in self.allowed_content_types: - del attrs[attr] - - for attr in self.svg_attr_val_allows_ref: - if attr in attrs: - attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', - ' ', - unescape(attrs[attr])) - if (token["name"] in self.svg_allow_local_href and - (namespaces['xlink'], 'href') in attrs and re.search(r'^\s*[^#\s].*', - attrs[(namespaces['xlink'], 'href')])): - del attrs[(namespaces['xlink'], 'href')] - if (None, 'style') in attrs: - attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) - token["data"] = attrs - return token - - def disallowed_token(self, token): - token_type = token["type"] - if token_type == "EndTag": - token["data"] = "" % token["name"] - elif token["data"]: - assert token_type in ("StartTag", "EmptyTag") - attrs = [] - for (ns, name), v in token["data"].items(): - attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) - token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) - else: - token["data"] = "<%s>" % token["name"] - if token.get("selfClosing"): - token["data"] = token["data"][:-1] + "/>" - - token["type"] = "Characters" - - del token["name"] - return token - - def sanitize_css(self, style): - # disallow urls - style = re.compile(r'url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) - - # gauntlet - if not re.match(r"""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): - return '' - if not re.match(r"^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): - return '' - - clean = [] - for prop, value in re.findall(r"([-\w]+)\s*:\s*([^:;]*)", style): - if not value: - continue - if prop.lower() in self.allowed_css_properties: - clean.append(prop + ': ' + value + ';') - elif prop.split('-')[0].lower() in ['background', 'border', 'margin', - 'padding']: - for keyword in value.split(): - if keyword not in self.allowed_css_keywords and \ - not re.match(r"^(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa - break - else: - clean.append(prop + ': ' + value + ';') - elif prop.lower() in self.allowed_svg_properties: - clean.append(prop + ': ' + value + ';') - - return ' '.join(clean) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/whitespace.py deleted file mode 100644 index 0d12584..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/whitespace.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import re - -from . import base -from ..constants import rcdataElements, spaceCharacters -spaceCharacters = "".join(spaceCharacters) - -SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) - - -class Filter(base.Filter): - """Collapses whitespace except in pre, textarea, and script elements""" - spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) - - def __iter__(self): - preserve = 0 - for token in base.Filter.__iter__(self): - type = token["type"] - if type == "StartTag" \ - and (preserve or token["name"] in self.spacePreserveElements): - preserve += 1 - - elif type == "EndTag" and preserve: - preserve -= 1 - - elif not preserve and type == "SpaceCharacters" and token["data"]: - # Test on token["data"] above to not introduce spaces where there were not - token["data"] = " " - - elif not preserve and type == "Characters": - token["data"] = collapse_spaces(token["data"]) - - yield token - - -def collapse_spaces(text): - return SPACES_REGEX.sub(' ', text) diff --git a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/html5parser.py b/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/html5parser.py deleted file mode 100644 index d06784f..0000000 --- a/backend/venv39/lib/python3.9/site-packages/pip/_vendor/html5lib/html5parser.py +++ /dev/null @@ -1,2795 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals -from pip._vendor.six import with_metaclass, viewkeys - -import types - -from . import _inputstream -from . import _tokenizer - -from . import treebuilders -from .treebuilders.base import Marker - -from . import _utils -from .constants import ( - spaceCharacters, asciiUpper2Lower, - specialElements, headingElements, cdataElements, rcdataElements, - tokenTypes, tagTokenTypes, - namespaces, - htmlIntegrationPointElements, mathmlTextIntegrationPointElements, - adjustForeignAttributes as adjustForeignAttributesMap, - adjustMathMLAttributes, adjustSVGAttributes, - E, - _ReparseException -) - - -def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): - """Parse an HTML document as a string or file-like object into a tree - - :arg doc: the document to parse as a string or file-like object - - :arg treebuilder: the treebuilder to use when parsing - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :returns: parsed tree - - Example: - - >>> from html5lib.html5parser import parse - >>> parse('

    This is a doc

    ') - - - """ - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parse(doc, **kwargs) - - -def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): - """Parse an HTML fragment as a string or file-like object into a tree - - :arg doc: the fragment to parse as a string or file-like object - - :arg container: the container context to parse the fragment in - - :arg treebuilder: the treebuilder to use when parsing - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :returns: parsed tree - - Example: - - >>> from html5lib.html5libparser import parseFragment - >>> parseFragment('this is a fragment') - - - """ - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parseFragment(doc, container=container, **kwargs) - - -def method_decorator_metaclass(function): - class Decorated(type): - def __new__(meta, classname, bases, classDict): - for attributeName, attribute in classDict.items(): - if isinstance(attribute, types.FunctionType): - attribute = function(attribute) - - classDict[attributeName] = attribute - return type.__new__(meta, classname, bases, classDict) - return Decorated - - -class HTMLParser(object): - """HTML parser - - Generates a tree structure from a stream of (possibly malformed) HTML. - - """ - - def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): - """ - :arg tree: a treebuilder class controlling the type of tree that will be - returned. Built in treebuilders can be accessed through - html5lib.treebuilders.getTreeBuilder(treeType) - - :arg strict: raise an exception when a parse error is encountered - - :arg namespaceHTMLElements: whether or not to namespace HTML elements - - :arg debug: whether or not to enable debug mode which logs things - - Example: - - >>> from html5lib.html5parser import HTMLParser - >>> parser = HTMLParser() # generates parser with etree builder - >>> parser = HTMLParser('lxml', strict=True) # generates parser with lxml builder which is strict - - """ - - # Raise an exception on the first error encountered - self.strict = strict - - if tree is None: - tree = treebuilders.getTreeBuilder("etree") - self.tree = tree(namespaceHTMLElements) - self.errors = [] - - self.phases = {name: cls(self, self.tree) for name, cls in - getPhases(debug).items()} - - def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): - - self.innerHTMLMode = innerHTML - self.container = container - self.scripting = scripting - self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) - self.reset() - - try: - self.mainLoop() - except _ReparseException: - self.reset() - self.mainLoop() - - def reset(self): - self.tree.reset() - self.firstStartTag = False - self.errors = [] - self.log = [] # only used with debug mode - # "quirks" / "limited quirks" / "no quirks" - self.compatMode = "no quirks" - - if self.innerHTMLMode: - self.innerHTML = self.container.lower() - - if self.innerHTML in cdataElements: - self.tokenizer.state = self.tokenizer.rcdataState - elif self.innerHTML in rcdataElements: - self.tokenizer.state = self.tokenizer.rawtextState - elif self.innerHTML == 'plaintext': - self.tokenizer.state = self.tokenizer.plaintextState - else: - # state already is data state - # self.tokenizer.state = self.tokenizer.dataState - pass - self.phase = self.phases["beforeHtml"] - self.phase.insertHtmlElement() - self.resetInsertionMode() - else: - self.innerHTML = False # pylint:disable=redefined-variable-type - self.phase = self.phases["initial"] - - self.lastPhase = None - - self.beforeRCDataPhase = None - - self.framesetOK = True - - @property - def documentEncoding(self): - """Name of the character encoding that was used to decode the input stream, or - :obj:`None` if that is not determined yet - - """ - if not hasattr(self, 'tokenizer'): - return None - return self.tokenizer.stream.charEncoding[0].name - - def isHTMLIntegrationPoint(self, element): - if (element.name == "annotation-xml" and - element.namespace == namespaces["mathml"]): - return ("encoding" in element.attributes and - element.attributes["encoding"].translate( - asciiUpper2Lower) in - ("text/html", "application/xhtml+xml")) - else: - return (element.namespace, element.name) in htmlIntegrationPointElements - - def isMathMLTextIntegrationPoint(self, element): - return (element.namespace, element.name) in mathmlTextIntegrationPointElements - - def mainLoop(self): - CharactersToken = tokenTypes["Characters"] - SpaceCharactersToken = tokenTypes["SpaceCharacters"] - StartTagToken = tokenTypes["StartTag"] - EndTagToken = tokenTypes["EndTag"] - CommentToken = tokenTypes["Comment"] - DoctypeToken = tokenTypes["Doctype"] - ParseErrorToken = tokenTypes["ParseError"] - - for token in self.tokenizer: - prev_token = None - new_token = token - while new_token is not None: - prev_token = new_token - currentNode = self.tree.openElements[-1] if self.tree.openElements else None - currentNodeNamespace = currentNode.namespace if currentNode else None - currentNodeName = currentNode.name if currentNode else None - - type = new_token["type"] - - if type == ParseErrorToken: - self.parseError(new_token["data"], new_token.get("datavars", {})) - new_token = None - else: - if (len(self.tree.openElements) == 0 or - currentNodeNamespace == self.tree.defaultNamespace or - (self.isMathMLTextIntegrationPoint(currentNode) and - ((type == StartTagToken and - token["name"] not in frozenset(["mglyph", "malignmark"])) or - type in (CharactersToken, SpaceCharactersToken))) or - (currentNodeNamespace == namespaces["mathml"] and - currentNodeName == "annotation-xml" and - type == StartTagToken and - token["name"] == "svg") or - (self.isHTMLIntegrationPoint(currentNode) and - type in (StartTagToken, CharactersToken, SpaceCharactersToken))): - phase = self.phase - else: - phase = self.phases["inForeignContent"] - - if type == CharactersToken: - new_token = phase.processCharacters(new_token) - elif type == SpaceCharactersToken: - new_token = phase.processSpaceCharacters(new_token) - elif type == StartTagToken: - new_token = phase.processStartTag(new_token) - elif type == EndTagToken: - new_token = phase.processEndTag(new_token) - elif type == CommentToken: - new_token = phase.processComment(new_token) - elif type == DoctypeToken: - new_token = phase.processDoctype(new_token) - - if (type == StartTagToken and prev_token["selfClosing"] and - not prev_token["selfClosingAcknowledged"]): - self.parseError("non-void-element-with-trailing-solidus", - {"name": prev_token["name"]}) - - # When the loop finishes it's EOF - reprocess = True - phases = [] - while reprocess: - phases.append(self.phase) - reprocess = self.phase.processEOF() - if reprocess: - assert self.phase not in phases - - def parse(self, stream, *args, **kwargs): - """Parse a HTML document into a well-formed tree - - :arg stream: a file-like object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element). - - :arg scripting: treat noscript elements as if JavaScript was turned on - - :returns: parsed tree - - Example: - - >>> from html5lib.html5parser import HTMLParser - >>> parser = HTMLParser() - >>> parser.parse('

    This is a doc

    ') - - - """ - self._parse(stream, False, None, *args, **kwargs) - return self.tree.getDocument() - - def parseFragment(self, stream, *args, **kwargs): - """Parse a HTML fragment into a well-formed tree fragment - - :arg container: name of the element we're setting the innerHTML - property if set to None, default to 'div' - - :arg stream: a file-like object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - - :arg scripting: treat noscript elements as if JavaScript was turned on - - :returns: parsed tree - - Example: - - >>> from html5lib.html5libparser import HTMLParser - >>> parser = HTMLParser() - >>> parser.parseFragment('this is a fragment') - - - """ - self._parse(stream, True, *args, **kwargs) - return self.tree.getFragment() - - def parseError(self, errorcode="XXX-undefined-error", datavars=None): - # XXX The idea is to make errorcode mandatory. - if datavars is None: - datavars = {} - self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) - if self.strict: - raise ParseError(E[errorcode] % datavars) - - def adjustMathMLAttributes(self, token): - adjust_attributes(token, adjustMathMLAttributes) - - def adjustSVGAttributes(self, token): - adjust_attributes(token, adjustSVGAttributes) - - def adjustForeignAttributes(self, token): - adjust_attributes(token, adjustForeignAttributesMap) - - def reparseTokenNormal(self, token): - # pylint:disable=unused-argument - self.parser.phase() - - def resetInsertionMode(self): - # The name of this method is mostly historical. (It's also used in the - # specification.) - last = False - newModes = { - "select": "inSelect", - "td": "inCell", - "th": "inCell", - "tr": "inRow", - "tbody": "inTableBody", - "thead": "inTableBody", - "tfoot": "inTableBody", - "caption": "inCaption", - "colgroup": "inColumnGroup", - "table": "inTable", - "head": "inBody", - "body": "inBody", - "frameset": "inFrameset", - "html": "beforeHead" - } - for node in self.tree.openElements[::-1]: - nodeName = node.name - new_phase = None - if node == self.tree.openElements[0]: - assert self.innerHTML - last = True - nodeName = self.innerHTML - # Check for conditions that should only happen in the innerHTML - # case - if nodeName in ("select", "colgroup", "head", "html"): - assert self.innerHTML - - if not last and node.namespace != self.tree.defaultNamespace: - continue - - if nodeName in newModes: - new_phase = self.phases[newModes[nodeName]] - break - elif last: - new_phase = self.phases["inBody"] - break - - self.phase = new_phase - - def parseRCDataRawtext(self, token, contentType): - # Generic RCDATA/RAWTEXT Parsing algorithm - assert contentType in ("RAWTEXT", "RCDATA") - - self.tree.insertElement(token) - - if contentType == "RAWTEXT": - self.tokenizer.state = self.tokenizer.rawtextState - else: - self.tokenizer.state = self.tokenizer.rcdataState - - self.originalPhase = self.phase - - self.phase = self.phases["text"] - - -@_utils.memoize -def getPhases(debug): - def log(function): - """Logger that records which phase processes each token""" - type_names = {value: key for key, value in tokenTypes.items()} - - def wrapped(self, *args, **kwargs): - if function.__name__.startswith("process") and len(args) > 0: - token = args[0] - info = {"type": type_names[token['type']]} - if token['type'] in tagTokenTypes: - info["name"] = token['name'] - - self.parser.log.append((self.parser.tokenizer.state.__name__, - self.parser.phase.__class__.__name__, - self.__class__.__name__, - function.__name__, - info)) - return function(self, *args, **kwargs) - else: - return function(self, *args, **kwargs) - return wrapped - - def getMetaclass(use_metaclass, metaclass_func): - if use_metaclass: - return method_decorator_metaclass(metaclass_func) - else: - return type - - # pylint:disable=unused-argument - class Phase(with_metaclass(getMetaclass(debug, log))): - """Base class for helper object that implements each phase of processing - """ - __slots__ = ("parser", "tree", "__startTagCache", "__endTagCache") - - def __init__(self, parser, tree): - self.parser = parser - self.tree = tree - self.__startTagCache = {} - self.__endTagCache = {} - - def processEOF(self): - raise NotImplementedError - - def processComment(self, token): - # For most phases the following is correct. Where it's not it will be - # overridden. - self.tree.insertComment(token, self.tree.openElements[-1]) - - def processDoctype(self, token): - self.parser.parseError("unexpected-doctype") - - def processCharacters(self, token): - self.tree.insertText(token["data"]) - - def processSpaceCharacters(self, token): - self.tree.insertText(token["data"]) - - def processStartTag(self, token): - # Note the caching is done here rather than BoundMethodDispatcher as doing it there - # requires a circular reference to the Phase, and this ends up with a significant - # (CPython 2.7, 3.8) GC cost when parsing many short inputs - name = token["name"] - # In Py2, using `in` is quicker in general than try/except KeyError - # In Py3, `in` is quicker when there are few cache hits (typically short inputs) - if name in self.__startTagCache: - func = self.__startTagCache[name] - else: - func = self.__startTagCache[name] = self.startTagHandler[name] - # bound the cache size in case we get loads of unknown tags - while len(self.__startTagCache) > len(self.startTagHandler) * 1.1: - # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 - self.__startTagCache.pop(next(iter(self.__startTagCache))) - return func(token) - - def startTagHtml(self, token): - if not self.parser.firstStartTag and token["name"] == "html": - self.parser.parseError("non-html-root") - # XXX Need a check here to see if the first start tag token emitted is - # this token... If it's not, invoke self.parser.parseError(). - for attr, value in token["data"].items(): - if attr not in self.tree.openElements[0].attributes: - self.tree.openElements[0].attributes[attr] = value - self.parser.firstStartTag = False - - def processEndTag(self, token): - # Note the caching is done here rather than BoundMethodDispatcher as doing it there - # requires a circular reference to the Phase, and this ends up with a significant - # (CPython 2.7, 3.8) GC cost when parsing many short inputs - name = token["name"] - # In Py2, using `in` is quicker in general than try/except KeyError - # In Py3, `in` is quicker when there are few cache hits (typically short inputs) - if name in self.__endTagCache: - func = self.__endTagCache[name] - else: - func = self.__endTagCache[name] = self.endTagHandler[name] - # bound the cache size in case we get loads of unknown tags - while len(self.__endTagCache) > len(self.endTagHandler) * 1.1: - # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 - self.__endTagCache.pop(next(iter(self.__endTagCache))) - return func(token) - - class InitialPhase(Phase): - __slots__ = tuple() - - def processSpaceCharacters(self, token): - pass - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processDoctype(self, token): - name = token["name"] - publicId = token["publicId"] - systemId = token["systemId"] - correct = token["correct"] - - if (name != "html" or publicId is not None or - systemId is not None and systemId != "about:legacy-compat"): - self.parser.parseError("unknown-doctype") - - if publicId is None: - publicId = "" - - self.tree.insertDoctype(token) - - if publicId != "": - publicId = publicId.translate(asciiUpper2Lower) - - if (not correct or token["name"] != "html" or - publicId.startswith( - ("+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//")) or - publicId in ("-//w3o//dtd w3 html strict 3.0//en//", - "-/w3c/dtd html 4.0 transitional/en", - "html") or - publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is None or - systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): - self.parser.compatMode = "quirks" - elif (publicId.startswith( - ("-//w3c//dtd xhtml 1.0 frameset//", - "-//w3c//dtd xhtml 1.0 transitional//")) or - publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is not None): - self.parser.compatMode = "limited quirks" - - self.parser.phase = self.parser.phases["beforeHtml"] - - def anythingElse(self): - self.parser.compatMode = "quirks" - self.parser.phase = self.parser.phases["beforeHtml"] - - def processCharacters(self, token): - self.parser.parseError("expected-doctype-but-got-chars") - self.anythingElse() - return token - - def processStartTag(self, token): - self.parser.parseError("expected-doctype-but-got-start-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEndTag(self, token): - self.parser.parseError("expected-doctype-but-got-end-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEOF(self): - self.parser.parseError("expected-doctype-but-got-eof") - self.anythingElse() - return True - - class BeforeHtmlPhase(Phase): - __slots__ = tuple() - - # helper methods - def insertHtmlElement(self): - self.tree.insertRoot(impliedTagToken("html", "StartTag")) - self.parser.phase = self.parser.phases["beforeHead"] - - # other - def processEOF(self): - self.insertHtmlElement() - return True - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.insertHtmlElement() - return token - - def processStartTag(self, token): - if token["name"] == "html": - self.parser.firstStartTag = True - self.insertHtmlElement() - return token - - def processEndTag(self, token): - if token["name"] not in ("head", "body", "html", "br"): - self.parser.parseError("unexpected-end-tag-before-html", - {"name": token["name"]}) - else: - self.insertHtmlElement() - return token - - class BeforeHeadPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.startTagHead(impliedTagToken("head", "StartTag")) - return True - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.tree.insertElement(token) - self.tree.headPointer = self.tree.openElements[-1] - self.parser.phase = self.parser.phases["inHead"] - - def startTagOther(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagImplyHead(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagOther(self, token): - self.parser.parseError("end-tag-after-implied-root", - {"name": token["name"]}) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - (("head", "body", "html", "br"), endTagImplyHead) - ]) - endTagHandler.default = endTagOther - - class InHeadPhase(Phase): - __slots__ = tuple() - - # the real thing - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.parser.parseError("two-heads-are-not-better-than-one") - - def startTagBaseLinkCommand(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - def startTagMeta(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - attributes = token["data"] - if self.parser.tokenizer.stream.charEncoding[1] == "tentative": - if "charset" in attributes: - self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) - elif ("content" in attributes and - "http-equiv" in attributes and - attributes["http-equiv"].lower() == "content-type"): - # Encoding it as UTF-8 here is a hack, as really we should pass - # the abstract Unicode string, and just use the - # ContentAttrParser on that, but using UTF-8 allows all chars - # to be encoded and as a ASCII-superset works. - data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) - parser = _inputstream.ContentAttrParser(data) - codec = parser.parse() - self.parser.tokenizer.stream.changeEncoding(codec) - - def startTagTitle(self, token): - self.parser.parseRCDataRawtext(token, "RCDATA") - - def startTagNoFramesStyle(self, token): - # Need to decide whether to implement the scripting-disabled case - self.parser.parseRCDataRawtext(token, "RAWTEXT") - - def startTagNoscript(self, token): - if self.parser.scripting: - self.parser.parseRCDataRawtext(token, "RAWTEXT") - else: - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inHeadNoscript"] - - def startTagScript(self, token): - self.tree.insertElement(token) - self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState - self.parser.originalPhase = self.parser.phase - self.parser.phase = self.parser.phases["text"] - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHead(self, token): - node = self.parser.tree.openElements.pop() - assert node.name == "head", "Expected head got %s" % node.name - self.parser.phase = self.parser.phases["afterHead"] - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.endTagHead(impliedTagToken("head")) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("title", startTagTitle), - (("noframes", "style"), startTagNoFramesStyle), - ("noscript", startTagNoscript), - ("script", startTagScript), - (("base", "basefont", "bgsound", "command", "link"), - startTagBaseLinkCommand), - ("meta", startTagMeta), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - ("head", endTagHead), - (("br", "html", "body"), endTagHtmlBodyBr) - ]) - endTagHandler.default = endTagOther - - class InHeadNoscriptPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.parser.parseError("eof-in-head-noscript") - self.anythingElse() - return True - - def processComment(self, token): - return self.parser.phases["inHead"].processComment(token) - - def processCharacters(self, token): - self.parser.parseError("char-in-head-noscript") - self.anythingElse() - return token - - def processSpaceCharacters(self, token): - return self.parser.phases["inHead"].processSpaceCharacters(token) - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagBaseLinkCommand(self, token): - return self.parser.phases["inHead"].processStartTag(token) - - def startTagHeadNoscript(self, token): - self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) - - def startTagOther(self, token): - self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) - self.anythingElse() - return token - - def endTagNoscript(self, token): - node = self.parser.tree.openElements.pop() - assert node.name == "noscript", "Expected noscript got %s" % node.name - self.parser.phase = self.parser.phases["inHead"] - - def endTagBr(self, token): - self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - # Caller must raise parse error first! - self.endTagNoscript(impliedTagToken("noscript")) - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - (("basefont", "bgsound", "link", "meta", "noframes", "style"), startTagBaseLinkCommand), - (("head", "noscript"), startTagHeadNoscript), - ]) - startTagHandler.default = startTagOther - - endTagHandler = _utils.MethodDispatcher([ - ("noscript", endTagNoscript), - ("br", endTagBr), - ]) - endTagHandler.default = endTagOther - - class AfterHeadPhase(Phase): - __slots__ = tuple() - - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagBody(self, token): - self.parser.framesetOK = False - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inBody"] - - def startTagFrameset(self, token): - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inFrameset"] - - def startTagFromHead(self, token): - self.parser.parseError("unexpected-start-tag-out-of-my-head", - {"name": token["name"]}) - self.tree.openElements.append(self.tree.headPointer) - self.parser.phases["inHead"].processStartTag(token) - for node in self.tree.openElements[::-1]: - if node.name == "head": - self.tree.openElements.remove(node) - break - - def startTagHead(self, token): - self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.tree.insertElement(impliedTagToken("body", "StartTag")) - self.parser.phase = self.parser.phases["inBody"] - self.parser.framesetOK = True - - startTagHandler = _utils.MethodDispatcher([ - ("html", startTagHtml), - ("body", startTagBody), - ("frameset", startTagFrameset), - (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", - "style", "title"), - startTagFromHead), - ("head", startTagHead) - ]) - startTagHandler.default = startTagOther - endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), - endTagHtmlBodyBr)]) - endTagHandler.default = endTagOther - - class InBodyPhase(Phase): - # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody - # the really-really-really-very crazy mode - __slots__ = ("processSpaceCharacters",) - - def __init__(self, *args, **kwargs): - super(InBodyPhase, self).__init__(*args, **kwargs) - # Set this to the default handler - self.processSpaceCharacters = self.processSpaceCharactersNonPre - - def isMatchingFormattingElement(self, node1, node2): - return (node1.name == node2.name and - node1.namespace == node2.namespace and - node1.attributes == node2.attributes) - - # helper - def addFormattingElement(self, token): - self.tree.insertElement(token) - element = self.tree.openElements[-1] - - matchingElements = [] - for node in self.tree.activeFormattingElements[::-1]: - if node is Marker: - break - elif self.isMatchingFormattingElement(node, element): - matchingElements.append(node) - - assert len(matchingElements) <= 3 - if len(matchingElements) == 3: - self.tree.activeFormattingElements.remove(matchingElements[-1]) - self.tree.activeFormattingElements.append(element) - - # the real deal - def processEOF(self): - allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", - "tfoot", "th", "thead", "tr", "body", - "html")) - for node in self.tree.openElements[::-1]: - if node.name not in allowed_elements: - self.parser.parseError("expected-closing-tag-but-got-eof") - break - # Stop parsing - - def processSpaceCharactersDropNewline(self, token): - # Sometimes (start of
    , , and